diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/core_mcpcia.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/core_mcpcia.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/core_mcpcia.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/core_mcpcia.h	2011-01-04 19:50:19.000000000 -0500
@@ -247,7 +247,7 @@
 #define vip	volatile int __force *
 #define vuip	volatile unsigned int __force *
 
-#ifdef MCPCIA_ONE_HAE_WINDOW
+#ifndef MCPCIA_ONE_HAE_WINDOW
 #define MCPCIA_FROB_MMIO						\
 	if (__mcpcia_is_mmio(hose)) {					\
 		set_hae(hose & 0xffffffff);				\
diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/core_t2.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/core_t2.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/core_t2.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/core_t2.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,9 @@
 #ifndef __ALPHA_T2__H__
 #define __ALPHA_T2__H__
 
+/* Fit everything into one 128MB HAE window. */
+#define T2_ONE_HAE_WINDOW 1
+
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <asm/compiler.h>
@@ -19,7 +22,7 @@
  *
  */
 
-#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 26 bits */
+#define T2_MEM_R1_MASK 0x07ffffff  /* Mem sparse region 1 mask is 27 bits */
 
 /* GAMMA-SABLE is a SABLE with EV5-based CPUs */
 /* All LYNX machines, EV4 or EV5, use the GAMMA bias also */
@@ -85,7 +88,9 @@
 #define T2_DIR			(IDENT_ADDR + GAMMA_BIAS + 0x38e0004a0UL)
 #define T2_ICE			(IDENT_ADDR + GAMMA_BIAS + 0x38e0004c0UL)
 
+#ifndef T2_ONE_HAE_WINDOW
 #define T2_HAE_ADDRESS		T2_HAE_1
+#endif
 
 /*  T2 CSRs are in the non-cachable primary IO space from 3.8000.0000 to
  3.8fff.ffff
@@ -429,13 +434,15 @@
  *
  */
 
+#ifdef T2_ONE_HAE_WINDOW
+#define t2_set_hae
+#else
 #define t2_set_hae { \
-	msb = addr  >> 27; \
+	unsigned long msb = addr >> 27; \
 	addr &= T2_MEM_R1_MASK; \
 	set_hae(msb); \
 }
-
-extern raw_spinlock_t t2_hae_lock;
+#endif
 
 /*
  * NOTE: take T2_DENSE_MEM off in each readX/writeX routine, since
@@ -446,28 +453,22 @@
 __EXTERN_INLINE u8 t2_readb(const volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long result, msb;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long result;
 
 	t2_set_hae;
 
 	result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 	return __kernel_extbl(result, addr & 3);
 }
 
 __EXTERN_INLINE u16 t2_readw(const volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long result, msb;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long result;
 
 	t2_set_hae;
 
 	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 	return __kernel_extwl(result, addr & 3);
 }
 
@@ -478,59 +479,47 @@
 __EXTERN_INLINE u32 t2_readl(const volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long result, msb;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long result;
 
 	t2_set_hae;
 
 	result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 	return result & 0xffffffffUL;
 }
 
 __EXTERN_INLINE u64 t2_readq(const volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long r0, r1, work, msb;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long r0, r1, work;
 
 	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	r0 = *(vuip)(work);
 	r1 = *(vuip)(work + (4 << 5));
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 	return r1 << 32 | r0;
 }
 
 __EXTERN_INLINE void t2_writeb(u8 b, volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long msb, w;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long w;
 
 	t2_set_hae;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void t2_writew(u16 b, volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long msb, w;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long w;
 
 	t2_set_hae;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 /*
@@ -540,29 +529,22 @@
 __EXTERN_INLINE void t2_writel(u32 b, volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long msb;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
 
 	t2_set_hae;
 
 	*(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void t2_writeq(u64 b, volatile void __iomem *xaddr)
 {
 	unsigned long addr = (unsigned long) xaddr - T2_DENSE_MEM;
-	unsigned long msb, work;
-	unsigned long flags;
-	raw_spin_lock_irqsave(&t2_hae_lock, flags);
+	unsigned long work;
 
 	t2_set_hae;
 
 	work = (addr << 5) + T2_SPARSE_MEM + 0x18;
 	*(vuip)work = b;
 	*(vuip)(work + (4 << 5)) = b >> 32;
-	raw_spin_unlock_irqrestore(&t2_hae_lock, flags);
 }
 
 __EXTERN_INLINE void __iomem *t2_ioportmap(unsigned long addr)
diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+#ifndef __ALPHA_IRQFLAGS_H
+#define __ALPHA_IRQFLAGS_H
+
+#include <asm/system.h>
+
+#define IPL_MIN		0
+#define IPL_SW0		1
+#define IPL_SW1		2
+#define IPL_DEV0	3
+#define IPL_DEV1	4
+#define IPL_TIMER	5
+#define IPL_PERF	6
+#define IPL_POWERFAIL	6
+#define IPL_MCHECK	7
+#define IPL_MAX		7
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+#undef IPL_MIN
+#define IPL_MIN		__min_ipl
+extern int __min_ipl;
+#endif
+
+#define getipl()		(rdps() & 7)
+#define setipl(ipl)		((void) swpipl(ipl))
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	return rdps();
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	setipl(IPL_MAX);
+	barrier();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = swpipl(IPL_MAX);
+	barrier();
+	return flags;
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	barrier();
+	setipl(IPL_MIN);
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	barrier();
+	setipl(flags);
+	barrier();
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags == IPL_MAX;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(getipl());
+}
+
+#endif /* __ALPHA_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,11 +1,6 @@
 #ifndef __ASM_ALPHA_PERF_EVENT_H
 #define __ASM_ALPHA_PERF_EVENT_H
 
-/* Alpha only supports software events through this interface. */
-extern void set_perf_event_pending(void);
-
-#define PERF_EVENT_INDEX_OFFSET 0
-
 #ifdef CONFIG_PERF_EVENTS
 extern void init_hw_perf_events(void);
 #else
diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -318,9 +318,7 @@
 }
 
 #define pte_offset_map(dir,addr)	pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir),(addr))
 #define pte_unmap(pte)			do { } while (0)
-#define pte_unmap_nested(pte)		do { } while (0)
 
 extern pgd_t swapper_pg_dir[1024];
 
diff -druN linux-libre-2.6.36-gnu/arch/alpha/include/asm/system.h linux-libre-2.6.37-gnu/arch/alpha/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/alpha/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -259,34 +259,6 @@
 __CALL_PAL_W1(wrusp, unsigned long);
 __CALL_PAL_W1(wrvptptr, unsigned long);
 
-#define IPL_MIN		0
-#define IPL_SW0		1
-#define IPL_SW1		2
-#define IPL_DEV0	3
-#define IPL_DEV1	4
-#define IPL_TIMER	5
-#define IPL_PERF	6
-#define IPL_POWERFAIL	6
-#define IPL_MCHECK	7
-#define IPL_MAX		7
-
-#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
-#undef IPL_MIN
-#define IPL_MIN		__min_ipl
-extern int __min_ipl;
-#endif
-
-#define getipl()		(rdps() & 7)
-#define setipl(ipl)		((void) swpipl(ipl))
-
-#define local_irq_disable()			do { setipl(IPL_MAX); barrier(); } while(0)
-#define local_irq_enable()			do { barrier(); setipl(IPL_MIN); } while(0)
-#define local_save_flags(flags)	((flags) = rdps())
-#define local_irq_save(flags)	do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
-#define local_irq_restore(flags)	do { barrier(); setipl(flags); barrier(); } while(0)
-
-#define irqs_disabled()	(getipl() == IPL_MAX)
-
 /*
  * TB routines..
  */
diff -druN linux-libre-2.6.36-gnu/arch/alpha/Kconfig linux-libre-2.6.37-gnu/arch/alpha/Kconfig
--- linux-libre-2.6.36-gnu/arch/alpha/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
 config ALPHA
 	bool
 	default y
@@ -9,6 +5,7 @@
 	select HAVE_IDE
 	select HAVE_OPROFILE
 	select HAVE_SYSCALL_WRAPPERS
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select HAVE_DMA_ATTRS
 	help
@@ -54,6 +51,9 @@
 	bool
 	default y
 
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/core_t2.c linux-libre-2.6.37-gnu/arch/alpha/kernel/core_t2.c
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/core_t2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/core_t2.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,8 +74,6 @@
 # define DBG(args)
 #endif
 
-DEFINE_RAW_SPINLOCK(t2_hae_lock);
-
 static volatile unsigned int t2_mcheck_any_expected;
 static volatile unsigned int t2_mcheck_last_taken;
 
@@ -406,6 +404,7 @@
 t2_init_arch(void)
 {
 	struct pci_controller *hose;
+	struct resource *hae_mem;
 	unsigned long temp;
 	unsigned int i;
 
@@ -433,7 +432,13 @@
 	 */
 	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
-	hose->mem_space = &iomem_resource;
+	hae_mem = alloc_resource();
+	hae_mem->start = 0;
+	hae_mem->end = T2_MEM_R1_MASK;
+	hae_mem->name = pci_hae0_name;
+	if (request_resource(&iomem_resource, hae_mem) < 0)
+		printk(KERN_ERR "Failed to request HAE_MEM\n");
+	hose->mem_space = hae_mem;
 	hose->index = 0;
 
 	hose->sparse_mem_base = T2_SPARSE_MEM - IDENT_ADDR;
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/machvec_impl.h linux-libre-2.6.37-gnu/arch/alpha/kernel/machvec_impl.h
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/machvec_impl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/machvec_impl.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,9 @@
 #ifdef MCPCIA_ONE_HAE_WINDOW
 #define MCPCIA_HAE_ADDRESS	(&alpha_mv.hae_cache)
 #endif
+#ifdef T2_ONE_HAE_WINDOW
+#define T2_HAE_ADDRESS		(&alpha_mv.hae_cache)
+#endif
 
 /* Only a few systems don't define IACK_SC, handling all interrupts through
    the SRM console.  But splitting out that one case from IO() below
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/pci_iommu.c linux-libre-2.6.37-gnu/arch/alpha/kernel/pci_iommu.c
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/pci_iommu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/pci_iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -223,7 +223,7 @@
  */
 static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
 {
-	dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
+	dma_addr_t dac_offset = alpha_mv.pci_dac_offset;
 	int ok = 1;
 
 	/* If this is not set, the machine doesn't support DAC at all.  */
@@ -756,7 +756,7 @@
 	spin_lock_irqsave(&arena->lock, flags);
 
 	for (end = sg + nents; sg < end; ++sg) {
-		dma64_addr_t addr;
+		dma_addr_t addr;
 		size_t size;
 		long npages, ofs;
 		dma_addr_t tend;
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/alpha/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -307,7 +307,7 @@
 			     new_raw_count) != prev_raw_count)
 		goto again;
 
-	delta = (new_raw_count  - (prev_raw_count & alpha_pmu->pmc_count_mask[idx])) + ovf;
+	delta = (new_raw_count - (prev_raw_count & alpha_pmu->pmc_count_mask[idx])) + ovf;
 
 	/* It is possible on very rare occasions that the PMC has overflowed
 	 * but the interrupt is yet to come.  Detect and fix this situation.
@@ -402,14 +402,13 @@
 		struct hw_perf_event *hwc = &pe->hw;
 		int idx = hwc->idx;
 
-		if (cpuc->current_idx[j] != PMC_NO_INDEX) {
-			cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
-			continue;
+		if (cpuc->current_idx[j] == PMC_NO_INDEX) {
+			alpha_perf_event_set_period(pe, hwc, idx);
+			cpuc->current_idx[j] = idx;
 		}
 
-		alpha_perf_event_set_period(pe, hwc, idx);
-		cpuc->current_idx[j] = idx;
-		cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
+		if (!(hwc->state & PERF_HES_STOPPED))
+			cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
 	}
 	cpuc->config = cpuc->event[0]->hw.config_base;
 }
@@ -420,12 +419,13 @@
  *  - this function is called from outside this module via the pmu struct
  *    returned from perf event initialisation.
  */
-static int alpha_pmu_enable(struct perf_event *event)
+static int alpha_pmu_add(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
 	int n0;
 	int ret;
-	unsigned long flags;
+	unsigned long irq_flags;
 
 	/*
 	 * The Sparc code has the IRQ disable first followed by the perf
@@ -435,8 +435,8 @@
 	 * nevertheless we disable the PMCs first to enable a potential
 	 * final PMI to occur before we disable interrupts.
 	 */
-	perf_disable();
-	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+	local_irq_save(irq_flags);
 
 	/* Default to error to be returned */
 	ret = -EAGAIN;
@@ -455,8 +455,12 @@
 		}
 	}
 
-	local_irq_restore(flags);
-	perf_enable();
+	hwc->state = PERF_HES_UPTODATE;
+	if (!(flags & PERF_EF_START))
+		hwc->state |= PERF_HES_STOPPED;
+
+	local_irq_restore(irq_flags);
+	perf_pmu_enable(event->pmu);
 
 	return ret;
 }
@@ -467,15 +471,15 @@
  *  - this function is called from outside this module via the pmu struct
  *    returned from perf event initialisation.
  */
-static void alpha_pmu_disable(struct perf_event *event)
+static void alpha_pmu_del(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
-	unsigned long flags;
+	unsigned long irq_flags;
 	int j;
 
-	perf_disable();
-	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+	local_irq_save(irq_flags);
 
 	for (j = 0; j < cpuc->n_events; j++) {
 		if (event == cpuc->event[j]) {
@@ -501,8 +505,8 @@
 		}
 	}
 
-	local_irq_restore(flags);
-	perf_enable();
+	local_irq_restore(irq_flags);
+	perf_pmu_enable(event->pmu);
 }
 
 
@@ -514,13 +518,44 @@
 }
 
 
-static void alpha_pmu_unthrottle(struct perf_event *event)
+static void alpha_pmu_stop(struct perf_event *event, int flags)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		cpuc->idx_mask &= ~(1UL<<hwc->idx);
+		hwc->state |= PERF_HES_STOPPED;
+	}
+
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		alpha_perf_event_update(event, hwc, hwc->idx, 0);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
+
+	if (cpuc->enabled)
+		wrperfmon(PERFMON_CMD_DISABLE, (1UL<<hwc->idx));
+}
+
+
+static void alpha_pmu_start(struct perf_event *event, int flags)
 {
 	struct hw_perf_event *hwc = &event->hw;
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
+	if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+		return;
+
+	if (flags & PERF_EF_RELOAD) {
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+		alpha_perf_event_set_period(event, hwc, hwc->idx);
+	}
+
+	hwc->state = 0;
+
 	cpuc->idx_mask |= 1UL<<hwc->idx;
-	wrperfmon(PERFMON_CMD_ENABLE, (1UL<<hwc->idx));
+	if (cpuc->enabled)
+		wrperfmon(PERFMON_CMD_ENABLE, (1UL<<hwc->idx));
 }
 
 
@@ -642,39 +677,36 @@
 	return 0;
 }
 
-static const struct pmu pmu = {
-	.enable		= alpha_pmu_enable,
-	.disable	= alpha_pmu_disable,
-	.read		= alpha_pmu_read,
-	.unthrottle	= alpha_pmu_unthrottle,
-};
-
-
 /*
  * Main entry point to initialise a HW performance event.
  */
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int alpha_pmu_event_init(struct perf_event *event)
 {
 	int err;
 
+	switch (event->attr.type) {
+	case PERF_TYPE_RAW:
+	case PERF_TYPE_HARDWARE:
+	case PERF_TYPE_HW_CACHE:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
 	if (!alpha_pmu)
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 
 	/* Do the real initialisation work. */
 	err = __hw_perf_event_init(event);
 
-	if (err)
-		return ERR_PTR(err);
-
-	return &pmu;
+	return err;
 }
 
-
-
 /*
  * Main entry point - enable HW performance counters.
  */
-void hw_perf_enable(void)
+static void alpha_pmu_enable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -700,7 +732,7 @@
  * Main entry point - disable HW performance counters.
  */
 
-void hw_perf_disable(void)
+static void alpha_pmu_disable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -713,6 +745,17 @@
 	wrperfmon(PERFMON_CMD_DISABLE, cpuc->idx_mask);
 }
 
+static struct pmu pmu = {
+	.pmu_enable	= alpha_pmu_enable,
+	.pmu_disable	= alpha_pmu_disable,
+	.event_init	= alpha_pmu_event_init,
+	.add		= alpha_pmu_add,
+	.del		= alpha_pmu_del,
+	.start		= alpha_pmu_start,
+	.stop		= alpha_pmu_stop,
+	.read		= alpha_pmu_read,
+};
+
 
 /*
  * Main entry point - don't know when this is called but it
@@ -766,7 +809,7 @@
 	wrperfmon(PERFMON_CMD_DISABLE, cpuc->idx_mask);
 
 	/* la_ptr is the counter that overflowed. */
-	if (unlikely(la_ptr >= perf_max_events)) {
+	if (unlikely(la_ptr >= alpha_pmu->num_pmcs)) {
 		/* This should never occur! */
 		irq_err_count++;
 		pr_warning("PMI: silly index %ld\n", la_ptr);
@@ -807,7 +850,7 @@
 			/* Interrupts coming too quickly; "throttle" the
 			 * counter, i.e., disable it for a little while.
 			 */
-			cpuc->idx_mask &= ~(1UL<<idx);
+			alpha_pmu_stop(event, 0);
 		}
 	}
 	wrperfmon(PERFMON_CMD_ENABLE, cpuc->idx_mask);
@@ -837,6 +880,7 @@
 
 	/* And set up PMU specification */
 	alpha_pmu = &ev67_pmu;
-	perf_max_events = alpha_pmu->num_pmcs;
+
+	perf_pmu_register(&pmu);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/alpha/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -269,7 +269,8 @@
 	user_disable_single_step(child);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long tmp;
 	size_t copied;
@@ -292,7 +293,7 @@
 	case PTRACE_PEEKUSR:
 		force_successful_syscall_return();
 		ret = get_reg(child, addr);
-		DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
+		DBG(DBG_MEM, ("peek $%lu->%#lx\n", addr, ret));
 		break;
 
 	/* When I and D space are separate, this will have to be fixed.  */
@@ -302,7 +303,7 @@
 		break;
 
 	case PTRACE_POKEUSR: /* write the specified register */
-		DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
+		DBG(DBG_MEM, ("poke $%lu<-%#lx\n", addr, data));
 		ret = put_reg(child, addr, data);
 		break;
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/alpha/kernel/time.c linux-libre-2.6.37-gnu/arch/alpha/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/alpha/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/alpha/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 #include <linux/init.h>
 #include <linux/bcd.h>
 #include <linux/profile.h>
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -83,25 +83,25 @@
 
 unsigned long est_cycle_freq;
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_IRQ_WORK
 
-DEFINE_PER_CPU(u8, perf_event_pending);
+DEFINE_PER_CPU(u8, irq_work_pending);
 
-#define set_perf_event_pending_flag()  __get_cpu_var(perf_event_pending) = 1
-#define test_perf_event_pending()      __get_cpu_var(perf_event_pending)
-#define clear_perf_event_pending()     __get_cpu_var(perf_event_pending) = 0
+#define set_irq_work_pending_flag()  __get_cpu_var(irq_work_pending) = 1
+#define test_irq_work_pending()      __get_cpu_var(irq_work_pending)
+#define clear_irq_work_pending()     __get_cpu_var(irq_work_pending) = 0
 
-void set_perf_event_pending(void)
+void set_irq_work_pending(void)
 {
-	set_perf_event_pending_flag();
+	set_irq_work_pending_flag();
 }
 
-#else  /* CONFIG_PERF_EVENTS */
+#else  /* CONFIG_IRQ_WORK */
 
-#define test_perf_event_pending()      0
-#define clear_perf_event_pending()
+#define test_irq_work_pending()      0
+#define clear_irq_work_pending()
 
-#endif /* CONFIG_PERF_EVENTS */
+#endif /* CONFIG_IRQ_WORK */
 
 
 static inline __u32 rpcc(void)
@@ -191,9 +191,9 @@
 
 	write_sequnlock(&xtime_lock);
 
-	if (test_perf_event_pending()) {
-		clear_perf_event_pending();
-		perf_event_do_pending();
+	if (test_irq_work_pending()) {
+		clear_irq_work_pending();
+		irq_work_run();
 	}
 
 #ifndef CONFIG_SMP
diff -druN linux-libre-2.6.36-gnu/arch/arm/boot/bootp/init.S linux-libre-2.6.37-gnu/arch/arm/boot/bootp/init.S
--- linux-libre-2.6.36-gnu/arch/arm/boot/bootp/init.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/boot/bootp/init.S	2011-01-04 19:50:19.000000000 -0500
@@ -73,6 +73,8 @@
 
 		.size	_start, . - _start
 
+		.align
+
 		.type	data,#object
 data:		.word	initrd_start		@ source initrd address
 		.word	initrd_phys		@ destination initrd address
diff -druN linux-libre-2.6.36-gnu/arch/arm/boot/compressed/head.S linux-libre-2.6.37-gnu/arch/arm/boot/compressed/head.S
--- linux-libre-2.6.36-gnu/arch/arm/boot/compressed/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/boot/compressed/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -125,9 +125,13 @@
  * sort out different calling conventions
  */
 		.align
+		.arm				@ Always enter in ARM state
 start:
 		.type	start,#function
-		.rept	8
+ THUMB(		adr	r12, BSYM(1f)	)
+ THUMB(		bx	r12		)
+ THUMB(		.rept	6		)
+ ARM(		.rept	8		)
 		mov	r0, r0
 		.endr
 
@@ -135,6 +139,7 @@
 		.word	0x016f2818		@ Magic numbers to help the loader
 		.word	start			@ absolute load/run zImage address
 		.word	_edata			@ zImage end address
+ THUMB(		.thumb			)
 1:		mov	r7, r1			@ save architecture ID
 		mov	r8, r2			@ save atags pointer
 
@@ -174,7 +179,8 @@
 		ldr	sp, [r0, #28]
 #ifdef CONFIG_AUTO_ZRELADDR
 		@ determine final kernel image address
-		and	r4, pc, #0xf8000000
+		mov	r4, pc
+		and	r4, r4, #0xf8000000
 		add	r4, r4, #TEXT_OFFSET
 #else
 		ldr	r4, =zreladdr
@@ -445,7 +451,8 @@
  */
 		mov	r1, #0x1e
 		orr	r1, r1, #3 << 10
-		mov	r2, pc, lsr #20
+		mov	r2, pc
+		mov	r2, r2, lsr #20
 		orr	r1, r1, r2, lsl #20
 		add	r0, r3, r2, lsl #2
 		str	r1, [r0], #4
@@ -1084,6 +1091,6 @@
 reloc_end:
 
 		.align
-		.section ".stack", "w"
+		.section ".stack", "aw", %nobits
 user_stack:	.space	4096
 user_stack_end:
diff -druN linux-libre-2.6.36-gnu/arch/arm/boot/compressed/vmlinux.lds.in linux-libre-2.6.37-gnu/arch/arm/boot/compressed/vmlinux.lds.in
--- linux-libre-2.6.36-gnu/arch/arm/boot/compressed/vmlinux.lds.in	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/boot/compressed/vmlinux.lds.in	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,7 @@
   .bss			: { *(.bss) }
   _end = .;
 
-  .stack (NOLOAD)	: { *(.stack) }
+  .stack		: { *(.stack) }
 
   .stab 0		: { *(.stab) }
   .stabstr 0		: { *(.stabstr) }
diff -druN linux-libre-2.6.36-gnu/arch/arm/boot/Makefile linux-libre-2.6.37-gnu/arch/arm/boot/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/boot/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/boot/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -70,12 +70,7 @@
 $(obj)/uImage: LOADADDR=$(ZRELADDR)
 endif
 
-ifeq ($(CONFIG_THUMB2_KERNEL),y)
-# Set bit 0 to 1 so that "mov pc, rx" switches to Thumb-2 mode
-$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/")
-else
 $(obj)/uImage: STARTADDR=$(LOADADDR)
-endif
 
 $(obj)/uImage:	$(obj)/zImage FORCE
 	$(call if_changed,uimage)
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/gic.c linux-libre-2.6.37-gnu/arch/arm/common/gic.c
--- linux-libre-2.6.36-gnu/arch/arm/common/gic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/gic.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,25 +67,11 @@
 
 /*
  * Routines to acknowledge, disable and enable interrupts
- *
- * Linux assumes that when we're done with an interrupt we need to
- * unmask it, in the same way we need to unmask an interrupt when
- * we first enable it.
- *
- * The GIC has a separate notion of "end of interrupt" to re-enable
- * an interrupt after handling, in order to support hardware
- * prioritisation.
- *
- * We can make the GIC behave in the way that Linux expects by making
- * our "acknowledge" routine disable the interrupt, then mark it as
- * complete.
  */
 static void gic_ack_irq(unsigned int irq)
 {
-	u32 mask = 1 << (irq % 32);
 
 	spin_lock(&irq_controller_lock);
-	writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
 	writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
 	spin_unlock(&irq_controller_lock);
 }
@@ -160,9 +146,15 @@
 	unsigned int shift = (irq % 4) * 8;
 	unsigned int cpu = cpumask_first(mask_val);
 	u32 val;
+	struct irq_desc *desc;
 
 	spin_lock(&irq_controller_lock);
-	irq_desc[irq].node = cpu;
+	desc = irq_to_desc(irq);
+	if (desc == NULL) {
+		spin_unlock(&irq_controller_lock);
+		return -EINVAL;
+	}
+	desc->node = cpu;
 	val = readl(reg) & ~(0xff << shift);
 	val |= 1 << (cpu + shift);
 	writel(val, reg);
@@ -224,7 +216,7 @@
 void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
 			  unsigned int irq_start)
 {
-	unsigned int max_irq, i;
+	unsigned int gic_irqs, irq_limit, i;
 	u32 cpumask = 1 << smp_processor_id();
 
 	if (gic_nr >= MAX_GIC_NR)
@@ -240,46 +232,49 @@
 
 	/*
 	 * Find out how many interrupts are supported.
-	 */
-	max_irq = readl(base + GIC_DIST_CTR) & 0x1f;
-	max_irq = (max_irq + 1) * 32;
-
-	/*
 	 * The GIC only supports up to 1020 interrupt sources.
-	 * Limit this to either the architected maximum, or the
-	 * platform maximum.
 	 */
-	if (max_irq > max(1020, NR_IRQS))
-		max_irq = max(1020, NR_IRQS);
+	gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f;
+	gic_irqs = (gic_irqs + 1) * 32;
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
 
 	/*
 	 * Set all global interrupts to be level triggered, active low.
 	 */
-	for (i = 32; i < max_irq; i += 16)
+	for (i = 32; i < gic_irqs; i += 16)
 		writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);
 
 	/*
 	 * Set all global interrupts to this CPU only.
 	 */
-	for (i = 32; i < max_irq; i += 4)
+	for (i = 32; i < gic_irqs; i += 4)
 		writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
 	/*
-	 * Set priority on all interrupts.
+	 * Set priority on all global interrupts.
 	 */
-	for (i = 0; i < max_irq; i += 4)
+	for (i = 32; i < gic_irqs; i += 4)
 		writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
 	/*
-	 * Disable all interrupts.
+	 * Disable all interrupts.  Leave the PPI and SGIs alone
+	 * as these enables are banked registers.
 	 */
-	for (i = 0; i < max_irq; i += 32)
+	for (i = 32; i < gic_irqs; i += 32)
 		writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
 	/*
+	 * Limit number of interrupts registered to the platform maximum
+	 */
+	irq_limit = gic_data[gic_nr].irq_offset + gic_irqs;
+	if (WARN_ON(irq_limit > NR_IRQS))
+		irq_limit = NR_IRQS;
+
+	/*
 	 * Setup the Linux IRQ subsystem.
 	 */
-	for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) {
+	for (i = irq_start; i < irq_limit; i++) {
 		set_irq_chip(i, &gic_chip);
 		set_irq_chip_data(i, &gic_data[gic_nr]);
 		set_irq_handler(i, handle_level_irq);
@@ -291,11 +286,30 @@
 
 void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
 {
+	void __iomem *dist_base;
+	int i;
+
 	if (gic_nr >= MAX_GIC_NR)
 		BUG();
 
+	dist_base = gic_data[gic_nr].dist_base;
+	BUG_ON(!dist_base);
+
 	gic_data[gic_nr].cpu_base = base;
 
+	/*
+	 * Deal with the banked PPI and SGI interrupts - disable all
+	 * PPI interrupts, ensure all SGI interrupts are enabled.
+	 */
+	writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
+	writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
+
+	/*
+	 * Set priority on PPI and SGI interrupts
+	 */
+	for (i = 0; i < 32; i += 4)
+		writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+
 	writel(0xf0, base + GIC_CPU_PRIMASK);
 	writel(1, base + GIC_CPU_CTRL);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/icst.c linux-libre-2.6.37-gnu/arch/arm/common/icst.c
--- linux-libre-2.6.36-gnu/arch/arm/common/icst.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/icst.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  *
  *  Support functions for calculating clocks/divisors for the ICST307
- *  clock generators.  See http://www.icst.com/ for more information
+ *  clock generators.  See http://www.idt.com/ for more information
  *  on these devices.
  *
  *  This is an almost identical implementation to the ICST525 clock generator.
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/it8152.c linux-libre-2.6.37-gnu/arch/arm/common/it8152.c
--- linux-libre-2.6.36-gnu/arch/arm/common/it8152.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/it8152.c	2011-01-04 19:50:19.000000000 -0500
@@ -352,3 +352,4 @@
 	return pci_scan_bus(nr, &it8152_ops, sys);
 }
 
+EXPORT_SYMBOL(dma_set_coherent_mask);
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/pl330.c linux-libre-2.6.37-gnu/arch/arm/common/pl330.c
--- linux-libre-2.6.36-gnu/arch/arm/common/pl330.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/pl330.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,8 +146,7 @@
 #define DESIGNER	0x41
 #define REVISION	0x0
 #define INTEG_CFG	0x0
-#define PERIPH_ID_VAL	((PART << 0) | (DESIGNER << 12) \
-			  | (REVISION << 20) | (INTEG_CFG << 24))
+#define PERIPH_ID_VAL	((PART << 0) | (DESIGNER << 12))
 
 #define PCELL_ID_VAL	0xb105f00d
 
@@ -1859,10 +1858,10 @@
 	regs = pi->base;
 
 	/* Check if we can handle this DMAC */
-	if (get_id(pi, PERIPH_ID) != PERIPH_ID_VAL
+	if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
 	   || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
 		dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
-			readl(regs + PERIPH_ID), readl(regs + PCELL_ID));
+			get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
 		return -EINVAL;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/sa1111.c linux-libre-2.6.37-gnu/arch/arm/common/sa1111.c
--- linux-libre-2.6.36-gnu/arch/arm/common/sa1111.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/sa1111.c	2011-01-04 19:50:19.000000000 -0500
@@ -678,7 +678,7 @@
  *	%-EBUSY		physical address already marked in-use.
  *	%0		successful.
  */
-static int
+static int __devinit
 __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
 	struct sa1111 *sachip;
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/scoop.c linux-libre-2.6.37-gnu/arch/arm/common/scoop.c
--- linux-libre-2.6.36-gnu/arch/arm/common/scoop.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/scoop.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,12 +44,12 @@
 {
 	struct scoop_dev *sdev = dev_get_drvdata(dev);
 
-	iowrite16(0x0100, sdev->base + SCOOP_MCR);  // 00
-	iowrite16(0x0000, sdev->base + SCOOP_CDR);  // 04
-	iowrite16(0x0000, sdev->base + SCOOP_CCR);  // 10
-	iowrite16(0x0000, sdev->base + SCOOP_IMR);  // 18
-	iowrite16(0x00FF, sdev->base + SCOOP_IRM);  // 14
-	iowrite16(0x0000, sdev->base + SCOOP_ISR);  // 1C
+	iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
+	iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
+	iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
+	iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
+	iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
+	iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
 	iowrite16(0x0000, sdev->base + SCOOP_IRM);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/common/uengine.c linux-libre-2.6.37-gnu/arch/arm/common/uengine.c
--- linux-libre-2.6.36-gnu/arch/arm/common/uengine.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/common/uengine.c	2011-01-04 19:50:19.000000000 -0500
@@ -312,16 +312,16 @@
 		b1 = (gpr_a[i] >> 8) & 0xff;
 		b0 = gpr_a[i] & 0xff;
 
-		// immed[@ai, (b1 << 8) | b0]
-		// 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII
+		/* immed[@ai, (b1 << 8) | b0] */
+		/* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */
 		ucode[offset++] = 0xf0;
 		ucode[offset++] = (b1 >> 4);
 		ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
 		ucode[offset++] = (b0 << 2);
 		ucode[offset++] = 0x80 | i;
 
-		// immed_w1[@ai, (b3 << 8) | b2]
-		// 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII
+		/* immed_w1[@ai, (b3 << 8) | b2] */
+		/* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */
 		ucode[offset++] = 0xf4;
 		ucode[offset++] = 0x40 | (b3 >> 4);
 		ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
@@ -340,16 +340,16 @@
 		b1 = (gpr_b[i] >> 8) & 0xff;
 		b0 = gpr_b[i] & 0xff;
 
-		// immed[@bi, (b1 << 8) | b0]
-		// 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV
+		/* immed[@bi, (b1 << 8) | b0] */
+		/* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */
 		ucode[offset++] = 0xf0;
 		ucode[offset++] = (b1 >> 4);
 		ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
 		ucode[offset++] = (i << 2) | 0x03;
 		ucode[offset++] = b0;
 
-		// immed_w1[@bi, (b3 << 8) | b2]
-		// 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV
+		/* immed_w1[@bi, (b3 << 8) | b2] */
+		/* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */
 		ucode[offset++] = 0xf4;
 		ucode[offset++] = 0x40 | (b3 >> 4);
 		ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
@@ -357,7 +357,7 @@
 		ucode[offset++] = b2;
 	}
 
-	// ctx_arb[kill]
+	/* ctx_arb[kill] */
 	ucode[offset++] = 0xe0;
 	ucode[offset++] = 0x00;
 	ucode[offset++] = 0x01;
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,341 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_AT91=y
+CONFIG_MACH_ONEARM=y
+CONFIG_ARCH_AT91RM9200DK=y
+CONFIG_MACH_AT91RM9200EK=y
+CONFIG_MACH_CSB337=y
+CONFIG_MACH_CSB637=y
+CONFIG_MACH_CARMEVA=y
+CONFIG_MACH_ATEB9200=y
+CONFIG_MACH_KB9200=y
+CONFIG_MACH_PICOTUX2XX=y
+CONFIG_MACH_KAFA=y
+CONFIG_MACH_ECBAT91=y
+CONFIG_MACH_YL9200=y
+CONFIG_MACH_CPUAT91=y
+CONFIG_MACH_ECO920=y
+CONFIG_MTD_AT91_DATAFLASH_CARD=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=100
+# CONFIG_ARM_THUMB is not set
+CONFIG_PCCARD=y
+CONFIG_AT91_CF=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_LEDS=y
+CONFIG_LEDS_CPU=y
+CONFIG_ZBOOT_ROM_TEXT=0x10000000
+CONFIG_ZBOOT_ROM_BSS=0x20040000
+CONFIG_KEXEC=y
+CONFIG_FPE_NWFPE=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_AFS_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_PLATFORM=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_LEGACY=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+CONFIG_PHYLIB=y
+CONFIG_DAVICOM_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_MICREL_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_ARM_AT91_ETHER=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_PPP=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_LEGACY_PTY_COUNT=32
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=y
+CONFIG_SPI_BITBANG=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HWMON=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_DS1621=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM73=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+CONFIG_SENSORS_PCF8591=m
+CONFIG_SENSORS_SMSC47B397=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83L785TS=m
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_AT91RM9200_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_S1D13XXX=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_DISPLAY_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_MINI_4x6=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_KEYSPAN=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_MCT_U232=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_MMC=y
+CONFIG_MMC_AT91=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PCF8563=y
+CONFIG_RTC_DRV_AT91RM9200=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_REISERFS_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=m
+CONFIG_TMPFS=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_CRAMFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_SMB_FS=m
+CONFIG_CIFS=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_SHA1=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200dk_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200dk_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200dk_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200dk_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,72 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91RM9200DK=y
-CONFIG_MACH_ECO920=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200ek_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200ek_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/at91rm9200ek_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/at91rm9200ek_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,73 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_AT91RM9200EK=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_S1D13XXX=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/at91sam9g20ek_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/at91sam9g20ek_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/at91sam9g20ek_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/at91sam9g20ek_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 CONFIG_ARCH_AT91=y
 CONFIG_ARCH_AT91SAM9G20=y
 CONFIG_MACH_AT91SAM9G20EK=y
+CONFIG_MACH_AT91SAM9G20EK_2MMC=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_AEABI=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/ateb9200_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/ateb9200_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/ateb9200_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/ateb9200_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,131 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ATEB9200=y
-CONFIG_PCCARD=m
-CONFIG_AT91_CF=m
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-# CONFIG_IPV6 is not set
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_TUN=m
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_GL620A=y
-CONFIG_USB_NET_PLUSB=y
-CONFIG_USB_NET_RNDIS_HOST=y
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_GPIO=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_USB_HID=m
-CONFIG_HID_PID=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DATAFAB=m
-CONFIG_USB_STORAGE_FREECOM=m
-CONFIG_USB_STORAGE_USBAT=m
-CONFIG_USB_STORAGE_SDDR09=m
-CONFIG_USB_STORAGE_SDDR55=m
-CONFIG_USB_STORAGE_JUMPSHOT=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=m
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_MMC=m
-CONFIG_MMC_DEBUG=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=m
-CONFIG_REISERFS_FS=m
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_NTFS_RW=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V4=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_UTF8=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRC16=m
-CONFIG_LIBCRC32C=m
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/carmeva_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/carmeva_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/carmeva_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/carmeva_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,47 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_HOTPLUG is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CARMEVA=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIO=m
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_MMC=m
-CONFIG_MMC_DEBUG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-# CONFIG_DNOTIFY is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/cpuat91_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/cpuat91_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/cpuat91_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/cpuat91_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,112 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CPUAT91=y
-CONFIG_AT91_TIMER_HZ=100
-# CONFIG_ARM_THUMB is not set
-CONFIG_PREEMPT=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_DS1307=y
-CONFIG_RTC_DRV_PCF8563=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_AUTOFS4_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_CRAMFS=y
-CONFIG_MINIX_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/csb337_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/csb337_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/csb337_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/csb337_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,104 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CSB337=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=y
-CONFIG_USB_SERIAL_KEYSPAN=y
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-CONFIG_USB_SERIAL_MCT_U232=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
-# CONFIG_RTC_INTF_SYSFS is not set
-CONFIG_RTC_DRV_DS1307=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/csb637_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/csb637_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/csb637_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/csb637_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,98 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_CSB637=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_SCSI=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_SERIAL=y
-CONFIG_USB_SERIAL_CONSOLE=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_FTDI_SIO=y
-CONFIG_USB_SERIAL_KEYSPAN=y
-CONFIG_USB_SERIAL_KEYSPAN_MPR=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
-CONFIG_USB_SERIAL_MCT_U232=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/da8xx_omapl_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/da8xx_omapl_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/da8xx_omapl_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/da8xx_omapl_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,8 @@
 CONFIG_ARCH_DAVINCI=y
 CONFIG_ARCH_DAVINCI_DA830=y
 CONFIG_ARCH_DAVINCI_DA850=y
+CONFIG_MACH_MITYOMAPL138=y
+CONFIG_MACH_OMAPL138_HAWKBOARD=y
 CONFIG_DAVINCI_RESET_CLOCKS=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -79,6 +81,7 @@
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DUMMY=y
 CONFIG_REGULATOR_TPS6507X=y
 CONFIG_FB=y
 CONFIG_FB_DA8XX=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/ecbat91_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/ecbat91_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/ecbat91_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/ecbat91_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,99 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ECBAT91=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_PREEMPT=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="rootfstype=reiserfs root=/dev/mmcblk0p1 console=ttyS0,115200n8 rootdelay=1"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IPV6 is not set
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_AFS_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_PRINTER=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_SHA1=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/kafa_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/kafa_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/kafa_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/kafa_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,61 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_KAFA=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PREEMPT=y
-CONFIG_LEDS=y
-CONFIG_LEDS_CPU=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20800000,10M root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_LEGACY_PTY_COUNT=32
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_HCTOSYS is not set
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_DES=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/kb9202_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/kb9202_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/kb9202_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/kb9202_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,127 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_KB9200=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x10000000
-CONFIG_ZBOOT_ROM_BSS=0x20040000
-CONFIG_CMDLINE="noinitrd root=/dev/mtdblock0 rootfstype=jffs2 mem=64M"
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SPI_ATTRS=m
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_AT91RM9200_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_FONT_MINI_4x6=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
-CONFIG_MMC=y
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_INOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/kirkwood_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/kirkwood_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/kirkwood_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/kirkwood_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_ESATA_SHEEVAPLUG=y
 CONFIG_MACH_GURUPLUG=y
+CONFIG_MACH_DOCKSTAR=y
 CONFIG_MACH_TS219=y
 CONFIG_MACH_TS41X=y
 CONFIG_MACH_OPENRD_BASE=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/mx27_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/mx27_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/mx27_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/mx27_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,14 @@
 CONFIG_MACH_MX27=y
 CONFIG_MACH_MX27ADS=y
 CONFIG_MACH_PCM038=y
+CONFIG_MACH_CPUIMX27=y
+CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2=y
+CONFIG_MACH_EUKREA_CPUIMX27_USEUART4=y
 CONFIG_MACH_MX27_3DS=y
+CONFIG_MACH_IMX27_VISSTRIM_M10=y
 CONFIG_MACH_IMX27LITE=y
+CONFIG_MACH_PCA100=y
+CONFIG_MACH_MXT_TD60=y
 CONFIG_MXC_IRQ_PRIOR=y
 CONFIG_MXC_PWM=y
 CONFIG_NO_HZ=y
@@ -76,7 +82,9 @@
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
 # CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
@@ -85,19 +93,20 @@
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_IMX=y
 CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
+CONFIG_SPI_IMX=y
 CONFIG_W1=y
 CONFIG_W1_MASTER_MXC=y
 CONFIG_W1_SLAVE_THERM=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_IMX=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=m
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_ULPI=y
 CONFIG_MMC=y
 CONFIG_MMC_MXC=y
 CONFIG_RTC_CLASS=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/mx31pdk_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/mx31pdk_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/mx31pdk_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/mx31pdk_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,44 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_MXC=y
-# CONFIG_MACH_MX31ADS is not set
-CONFIG_MACH_MX31_3DS=y
-CONFIG_AEABI=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_LRO is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FIRMWARE_IN_KERNEL is not set
-# CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_DEVKMEM is not set
-CONFIG_SERIAL_IMX=y
-CONFIG_SERIAL_IMX_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRC32 is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/mx3_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/mx3_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/mx3_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/mx3_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 CONFIG_MACH_ARMADILLO5X0=y
 CONFIG_MACH_MX35_3DS=y
 CONFIG_MACH_KZM_ARM11_01=y
+CONFIG_MACH_EUKREA_CPUIMX35=y
 CONFIG_MXC_IRQ_PRIOR=y
 CONFIG_MXC_PWM=y
 CONFIG_NO_HZ=y
@@ -108,7 +109,6 @@
 CONFIG_MMC_MXC=y
 CONFIG_DMADEVICES=y
 # CONFIG_DNOTIFY is not set
-CONFIG_INOTIFY=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_UBIFS_FS=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/mx51_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/mx51_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/mx51_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/mx51_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,8 @@
 CONFIG_ARCH_MXC=y
 CONFIG_ARCH_MX5=y
 CONFIG_MACH_MX51_BABBAGE=y
+CONFIG_MACH_MX51_3DS=y
+CONFIG_MACH_EUKREA_CPUIMX51=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
@@ -69,7 +71,6 @@
 CONFIG_NATIONAL_PHY=y
 CONFIG_STE10XP=y
 CONFIG_LSI_ET1011C_PHY=y
-CONFIG_FIXED_PHY=y
 CONFIG_MDIO_BITBANG=y
 CONFIG_MDIO_GPIO=y
 CONFIG_NET_ETHERNET=y
@@ -81,6 +82,7 @@
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_MOUSE_PS2=m
 CONFIG_MOUSE_PS2_ELANTECH=y
@@ -100,7 +102,6 @@
 CONFIG_I2C_ALGOPCA=m
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
@@ -117,13 +118,11 @@
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
-CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
-CONFIG_INOTIFY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
@@ -136,6 +135,7 @@
 CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -151,7 +151,6 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
@@ -159,7 +158,6 @@
 # CONFIG_ARM_UNWIND is not set
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_KEYS=y
 CONFIG_SECURITYFS=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/n8x0_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/n8x0_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/n8x0_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/n8x0_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,94 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_OMAP_RESET_CLOCKS=y
-# CONFIG_OMAP_MUX is not set
-# CONFIG_OMAP_MCBSP is not set
-CONFIG_OMAP_MBOX_FWK=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 console=ttyS2,115200n8 debug earlyprintk rootwait"
-CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_PM=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_ONENAND=y
-CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_ONENAND_OTP=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-# CONFIG_I2C_COMPAT is not set
-# CONFIG_I2C_HELPER_AUTO is not set
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_MENELAUS=y
-CONFIG_REGULATOR=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
-# CONFIG_MUSB_PIO_ONLY is not set
-CONFIG_USB_MUSB_DEBUG=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_ETH=m
-CONFIG_USB_ETH_EEM=y
-CONFIG_MMC=y
-CONFIG_MMC_OMAP=y
-CONFIG_EXT3_FS=y
-CONFIG_INOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/omap2plus_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/omap2plus_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/omap2plus_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/configs/omap2plus_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,293 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP2=y
+CONFIG_ARCH_OMAP3=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_MACH_OMAP_GENERIC=y
+CONFIG_ARCH_OMAP2420=y
+CONFIG_ARCH_OMAP2430=y
+CONFIG_ARCH_OMAP3430=y
+CONFIG_MACH_OMAP_H4=y
+CONFIG_MACH_OMAP_APOLLON=y
+CONFIG_MACH_OMAP_2430SDP=y
+CONFIG_MACH_OMAP3_BEAGLE=y
+CONFIG_MACH_DEVKIT8000=y
+CONFIG_MACH_OMAP_LDP=y
+CONFIG_MACH_OVERO=y
+CONFIG_MACH_OMAP3EVM=y
+CONFIG_MACH_OMAP3517EVM=y
+CONFIG_MACH_OMAP3_PANDORA=y
+CONFIG_MACH_OMAP3_TOUCHBOOK=y
+CONFIG_MACH_OMAP_3430SDP=y
+CONFIG_MACH_NOKIA_N8X0=y
+CONFIG_MACH_NOKIA_RX51=y
+CONFIG_MACH_OMAP_ZOOM2=y
+CONFIG_MACH_OMAP_ZOOM3=y
+CONFIG_MACH_CM_T35=y
+CONFIG_MACH_IGEP0020=y
+CONFIG_MACH_SBC3530=y
+CONFIG_MACH_OMAP_3630SDP=y
+CONFIG_MACH_OMAP_4430SDP=y
+CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_ERRATA_411920=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_LOCAL_TIMERS is not set
+CONFIG_AEABI=y
+CONFIG_LEDS=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
+CONFIG_KEXEC=y
+CONFIG_FPE_NWFPE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_CFG80211=m
+CONFIG_MAC80211=m
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_LEDS=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_OOPS=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_EEPROM_LEGACY=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_SMSC911X=y
+CONFIG_KS8851=y
+CONFIG_KS8851_MLL=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_DEBUG=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_TWL4030=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_TWL4030_PWRBUTTON=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_OMAP=y
+CONFIG_SPI=y
+CONFIG_SPI_OMAP24XX=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_TWL4030=y
+CONFIG_W1=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_WATCHDOG=y
+CONFIG_OMAP_WATCHDOG=y
+CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MENELAUS=y
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_POWER=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_TPS65023=y
+CONFIG_REGULATOR_TPS6507X=y
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+CONFIG_FB_OMAP_LCD_VGA=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_DISPLAY_SUPPORT=y
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_MUSB_OTG is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+CONFIG_USB_MUSB_DEBUG=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_ZERO=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_SDIO_UART=y
+CONFIG_MMC_OMAP=y
+CONFIG_MMC_OMAP_HS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TWL92330=y
+CONFIG_RTC_DRV_TWL4030=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RUBIN=y
+CONFIG_UBIFS_FS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_PROVE_LOCKING=y
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SECURITY=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/omap3_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/omap3_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/omap3_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/omap3_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,292 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_ARCH_OMAP3=y
-CONFIG_ARCH_OMAP4=y
-CONFIG_OMAP_RESET_CLOCKS=y
-CONFIG_OMAP_MUX_DEBUG=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_ARCH_OMAP2430=y
-CONFIG_ARCH_OMAP3430=y
-CONFIG_MACH_OMAP_H4=y
-CONFIG_MACH_OMAP_APOLLON=y
-CONFIG_MACH_OMAP_2430SDP=y
-CONFIG_MACH_OMAP3_BEAGLE=y
-CONFIG_MACH_DEVKIT8000=y
-CONFIG_MACH_OMAP_LDP=y
-CONFIG_MACH_OVERO=y
-CONFIG_MACH_OMAP3EVM=y
-CONFIG_MACH_OMAP3517EVM=y
-CONFIG_MACH_OMAP3_PANDORA=y
-CONFIG_MACH_OMAP3_TOUCHBOOK=y
-CONFIG_MACH_OMAP_3430SDP=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_MACH_NOKIA_RX51=y
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_MACH_OMAP_ZOOM3=y
-CONFIG_MACH_CM_T35=y
-CONFIG_MACH_IGEP0020=y
-CONFIG_MACH_SBC3530=y
-CONFIG_MACH_OMAP_3630SDP=y
-CONFIG_MACH_OMAP_4430SDP=y
-CONFIG_ARM_THUMBEE=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_AEABI=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyS2,115200"
-CONFIG_KEXEC=y
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_STAT_DETAILS=y
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
-CONFIG_PM_DEBUG=y
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=y
-CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-CONFIG_BT=y
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=y
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=y
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_LL=y
-CONFIG_BT_HCIBCM203X=y
-CONFIG_BT_HCIBPA10X=y
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
-CONFIG_MAC80211_RC_PID=y
-CONFIG_MAC80211_RC_DEFAULT_PID=y
-CONFIG_MAC80211_LEDS=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_CONNECTOR=y
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_OOPS=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_ONENAND=y
-CONFIG_MTD_ONENAND_VERIFY_WRITE=y
-CONFIG_MTD_ONENAND_OMAP2=y
-CONFIG_MTD_UBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_EEPROM_LEGACY=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_MD=y
-CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_SMC91X=y
-CONFIG_SMSC911X=y
-CONFIG_LIBERTAS=y
-CONFIG_LIBERTAS_USB=y
-CONFIG_LIBERTAS_SDIO=y
-CONFIG_LIBERTAS_DEBUG=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_INPUT_JOYDEV=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_KEYBOARD_GPIO=y
-CONFIG_KEYBOARD_TWL4030=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_TWL4030=y
-CONFIG_W1=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_WATCHDOG=y
-CONFIG_MENELAUS=y
-CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_TWL4030=y
-CONFIG_REGULATOR_TPS65023=y
-CONFIG_REGULATOR_TPS6507X=y
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_OMAP_LCD_VGA=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_LCD_PLATFORM=y
-CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
-CONFIG_FONTS=y
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_VERBOSE_PRINTK=y
-CONFIG_SND_DEBUG=y
-CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
-CONFIG_USB_MON=y
-CONFIG_USB_MUSB_HDRC=y
-CONFIG_USB_MUSB_OTG=y
-CONFIG_USB_GADGET_MUSB_HDRC=y
-CONFIG_USB_MUSB_DEBUG=y
-CONFIG_USB_WDM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
-CONFIG_USB_TEST=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
-CONFIG_USB_ZERO=m
-CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
-CONFIG_SDIO_UART=y
-CONFIG_MMC_OMAP=y
-CONFIG_MMC_OMAP_HS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_TWL92330=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_UBIFS_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_LOCK_STAT=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_LL=y
-CONFIG_SECURITY=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC7=y
-CONFIG_LIBCRC32C=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/omap_4430sdp_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/omap_4430sdp_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/omap_4430sdp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/omap_4430sdp_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,125 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_ELF_CORE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP4=y
-# CONFIG_ARCH_OMAP2PLUS_TYPICAL is not set
-# CONFIG_ARCH_OMAP2 is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_OMAP_MUX is not set
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_OMAP_DM_TIMER=y
-CONFIG_MACH_OMAP_4430SDP=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PL310_ERRATA_588369=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
-# CONFIG_LOCAL_TIMERS is not set
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M console=ttyS2,115200n8 initrd=0x81600000,20M ramdisk_size=20480"
-CONFIG_VFP=y
-CONFIG_NEON=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_FW_LOADER is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_KS8851=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
-CONFIG_SPI=y
-CONFIG_SPI_OMAP24XX=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_OMAP_WATCHDOG=y
-CONFIG_TWL4030_CORE=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_TWL4030=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_OMAP_HS=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_TWL4030=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_QUOTA=y
-CONFIG_QFMT_V2=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_PREEMPT is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_FTRACE is not set
-# CONFIG_ARM_UNWIND is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
-CONFIG_CRC_T10DIF=y
-CONFIG_LIBCRC32C=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/omap_generic_2420_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/omap_generic_2420_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/omap_generic_2420_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/omap_generic_2420_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,37 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-# CONFIG_OMAP_MUX is not set
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x10C08000
-CONFIG_ZBOOT_ROM_BSS=0x10200000
-CONFIG_FPE_NWFPE=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_INOTIFY=y
-CONFIG_ROMFS_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/onearm_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/onearm_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/onearm_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/onearm_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,80 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_ONEARM=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_LEDS=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp mem=64M"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_MMC=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_ROOT_NFS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/pcontrol_g20_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/pcontrol_g20_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/pcontrol_g20_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/configs/pcontrol_g20_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,175 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="/opt/arm-2010q1/bin/arm-none-linux-gnueabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91SAM9G20=y
+CONFIG_MACH_PCONTROL_G20=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyS0,115200 mem=128M mtdparts=atmel_nand:128k(bootstrap)ro,256k(uboot)ro,128k(env1)ro,128k(env2)ro,2M(linux),-(root) root=/dev/mmcblk0p1 rootwait rw"
+CONFIG_VFP=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHRAM=m
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_AT24=m
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=m
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MACVLAN=m
+CONFIG_TUN=m
+CONFIG_SMSC_PHY=m
+CONFIG_BROADCOM_PHY=m
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+CONFIG_SMSC911X=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_INPUT_POLLDEV=y
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=m
+CONFIG_KEYBOARD_MATRIX=m
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_INPUT_GPIO_ROTARY_ENCODER=m
+# CONFIG_SERIO is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_SERIAL_MAX3100=m
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_R3964=m
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_GPIO=m
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=m
+CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_W1=m
+CONFIG_W1_MASTER_GPIO=m
+CONFIG_W1_SLAVE_DS2431=m
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=m
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_USB_G_HID=m
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_ATMELMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AT91SAM9=y
+CONFIG_AUXDISPLAY=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_STAGING=y
+# CONFIG_STAGING_EXCLUDE_BUILD is not set
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/picotux200_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/picotux200_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/picotux200_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/picotux200_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,242 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=m
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-# CONFIG_KALLSYMS is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_MACH_PICOTUX2XX=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=m
-CONFIG_NET=y
-CONFIG_PACKET=m
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_DIAG=m
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_IPV6_MIP6=m
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=m
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
-CONFIG_FW_LOADER=m
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_EEPROM_LEGACY=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=m
-CONFIG_NETDEVICES=y
-CONFIG_TUN=m
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_DM9601=m
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_PPP=m
-CONFIG_PPP_FILTER=y
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-CONFIG_SLIP_MODE_SLIP6=y
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_GPIO=m
-CONFIG_HWMON=m
-CONFIG_SENSORS_ADM1021=m
-CONFIG_SENSORS_ADM1025=m
-CONFIG_SENSORS_ADM1026=m
-CONFIG_SENSORS_ADM1029=m
-CONFIG_SENSORS_ADM1031=m
-CONFIG_SENSORS_ADM9240=m
-CONFIG_SENSORS_DS1621=m
-CONFIG_SENSORS_GL518SM=m
-CONFIG_SENSORS_GL520SM=m
-CONFIG_SENSORS_IT87=m
-CONFIG_SENSORS_LM63=m
-CONFIG_SENSORS_LM75=m
-CONFIG_SENSORS_LM77=m
-CONFIG_SENSORS_LM78=m
-CONFIG_SENSORS_LM80=m
-CONFIG_SENSORS_LM83=m
-CONFIG_SENSORS_LM85=m
-CONFIG_SENSORS_LM87=m
-CONFIG_SENSORS_LM90=m
-CONFIG_SENSORS_LM92=m
-CONFIG_SENSORS_MAX1619=m
-CONFIG_SENSORS_PCF8591=m
-CONFIG_SENSORS_SMSC47B397=m
-CONFIG_SENSORS_W83781D=m
-CONFIG_SENSORS_W83791D=m
-CONFIG_SENSORS_W83792D=m
-CONFIG_SENSORS_W83793=m
-CONFIG_SENSORS_W83L785TS=m
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=m
-CONFIG_HID=m
-CONFIG_USB=m
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_OHCI_HCD=m
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_MMC=m
-CONFIG_MMC_AT91=m
-CONFIG_RTC_CLASS=m
-CONFIG_RTC_DRV_AT91RM9200=m
-CONFIG_EXT2_FS=m
-CONFIG_EXT3_FS=m
-# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_SUMMARY=y
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_NFS_FS=m
-CONFIG_SMB_FS=m
-CONFIG_CIFS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_AMIGA_PARTITION=y
-CONFIG_NLS_DEFAULT="utf-8"
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=m
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_LIBCRC32C=m
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/realview_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/realview_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/realview_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/realview_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,7 @@
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
 CONFIG_NETDEVICES=y
 CONFIG_SMSC_PHY=y
 CONFIG_NET_ETHERNET=y
@@ -51,10 +52,13 @@
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
@@ -69,7 +73,13 @@
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_CRAMFS=y
@@ -79,6 +89,7 @@
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/realview-smp_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/realview-smp_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/realview-smp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/realview-smp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -39,6 +39,7 @@
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
 CONFIG_NETDEVICES=y
 CONFIG_SMSC_PHY=y
 CONFIG_NET_ETHERNET=y
@@ -52,10 +53,13 @@
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
@@ -70,7 +74,13 @@
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_CRAMFS=y
@@ -80,6 +90,7 @@
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/s5p6440_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/s5p6440_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/s5p6440_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/s5p6440_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,65 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S5P6440=y
-CONFIG_S3C_BOOT_ERROR_RESET=y
-CONFIG_S3C_LOWLEVEL_UART_PORT=1
-CONFIG_MACH_SMDK6440=y
-CONFIG_CPU_32v6K=y
-CONFIG_AEABI=y
-CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
-CONFIG_FPE_NWFPE=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-CONFIG_SERIAL_SAMSUNG=y
-CONFIG_SERIAL_SAMSUNG_CONSOLE=y
-CONFIG_HW_RANDOM=y
-# CONFIG_HWMON is not set
-CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_INOTIFY=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-CONFIG_DEBUG_S3C_UART=1
-CONFIG_CRYPTO=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/s5p64x0_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/s5p64x0_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/s5p64x0_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/configs/s5p64x0_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,66 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_S5P64X0=y
+CONFIG_S3C_BOOT_ERROR_RESET=y
+CONFIG_S3C_LOWLEVEL_UART_PORT=1
+CONFIG_MACH_SMDK6440=y
+CONFIG_MACH_SMDK6450=y
+CONFIG_CPU_32v6K=y
+CONFIG_AEABI=y
+CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
+CONFIG_FPE_NWFPE=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+# CONFIG_MISC_DEVICES is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_NR_UARTS=3
+CONFIG_SERIAL_SAMSUNG=y
+CONFIG_SERIAL_SAMSUNG_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HWMON is not set
+CONFIG_DISPLAY_SUPPORT=y
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_INOTIFY=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_S3C_UART=1
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/u300_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/u300_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/u300_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/u300_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -28,26 +28,9 @@
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 # CONFIG_SUSPEND is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MISC_DEVICES is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -58,7 +41,6 @@
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
-CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
@@ -66,24 +48,10 @@
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-# CONFIG_SND_SPI is not set
-CONFIG_SND_SOC=y
 # CONFIG_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_HCTOSYS is not set
 CONFIG_RTC_DRV_COH901331=y
@@ -93,12 +61,11 @@
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
diff -druN linux-libre-2.6.36-gnu/arch/arm/configs/yl9200_defconfig linux-libre-2.6.37-gnu/arch/arm/configs/yl9200_defconfig
--- linux-libre-2.6.36-gnu/arch/arm/configs/yl9200_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/configs/yl9200_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,137 +0,0 @@
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91RM9200DK=y
-CONFIG_MACH_YL9200=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_JEDECPROBE=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=3
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_NETDEVICES=y
-CONFIG_PHYLIB=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_ARM_AT91_ETHER=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
-CONFIG_SPI_ATMEL=y
-CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_LOGO=y
-# CONFIG_LOGO_LINUX_MONO is not set
-# CONFIG_LOGO_LINUX_VGA16 is not set
-CONFIG_USB=y
-CONFIG_USB_DEBUG=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_M66592=y
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_AT91=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT3_FS=y
-CONFIG_REISERFS_FS=y
-CONFIG_INOTIFY=y
-CONFIG_ISO9660_FS=y
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=1
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_RUBIN=y
-CONFIG_CRAMFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_SLUB_DEBUG_ON=y
-CONFIG_DEBUG_KOBJECT=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/assembler.h linux-libre-2.6.37-gnu/arch/arm/include/asm/assembler.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/assembler.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/assembler.h	2011-01-04 19:50:19.000000000 -0500
@@ -154,16 +154,39 @@
 	.long	9999b,9001f;			\
 	.popsection
 
+#ifdef CONFIG_SMP
+#define ALT_SMP(instr...)					\
+9998:	instr
+#define ALT_UP(instr...)					\
+	.pushsection ".alt.smp.init", "a"			;\
+	.long	9998b						;\
+	instr							;\
+	.popsection
+#define ALT_UP_B(label)					\
+	.equ	up_b_offset, label - 9998b			;\
+	.pushsection ".alt.smp.init", "a"			;\
+	.long	9998b						;\
+	b	. + up_b_offset					;\
+	.popsection
+#else
+#define ALT_SMP(instr...)
+#define ALT_UP(instr...) instr
+#define ALT_UP_B(label) b label
+#endif
+
 /*
  * SMP data memory barrier
  */
 	.macro	smp_dmb
 #ifdef CONFIG_SMP
 #if __LINUX_ARM_ARCH__ >= 7
-	dmb
+	ALT_SMP(dmb)
 #elif __LINUX_ARM_ARCH__ == 6
-	mcr	p15, 0, r0, c7, c10, 5	@ dmb
+	ALT_SMP(mcr	p15, 0, r0, c7, c10, 5)	@ dmb
+#else
+#error Incompatible SMP platform
 #endif
+	ALT_UP(nop)
 #endif
 	.endm
 
@@ -215,7 +238,7 @@
 	@ Slightly optimised to avoid incrementing the pointer twice
 	usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
 	.if	\rept == 2
-	usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort
+	usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
 	.endif
 
 	add\cond \ptr, #\rept * \inc
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/cacheflush.h linux-libre-2.6.37-gnu/arch/arm/include/asm/cacheflush.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/cacheflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/cacheflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -137,10 +137,10 @@
 #endif
 
 /*
- * This flag is used to indicate that the page pointed to by a pte
- * is dirty and requires cleaning before returning it to the user.
+ * This flag is used to indicate that the page pointed to by a pte is clean
+ * and does not require cleaning before returning it to the user.
  */
-#define PG_dcache_dirty PG_arch_1
+#define PG_dcache_clean PG_arch_1
 
 /*
  *	MM Cache Management
@@ -156,6 +156,12 @@
  *	Please note that the implementation of these, and the required
  *	effects are cache-type (VIVT/VIPT/PIPT) specific.
  *
+ *	flush_icache_all()
+ *
+ *		Unconditionally clean and invalidate the entire icache.
+ *		Currently only needed for cache-v6.S and cache-v7.S, see
+ *		__flush_icache_all for the generic implementation.
+ *
  *	flush_kern_all()
  *
  *		Unconditionally clean and invalidate the entire cache.
@@ -206,6 +212,7 @@
  */
 
 struct cpu_cache_fns {
+	void (*flush_icache_all)(void);
 	void (*flush_kern_all)(void);
 	void (*flush_user_all)(void);
 	void (*flush_user_range)(unsigned long, unsigned long, unsigned int);
@@ -227,6 +234,7 @@
 
 extern struct cpu_cache_fns cpu_cache;
 
+#define __cpuc_flush_icache_all		cpu_cache.flush_icache_all
 #define __cpuc_flush_kern_all		cpu_cache.flush_kern_all
 #define __cpuc_flush_user_all		cpu_cache.flush_user_all
 #define __cpuc_flush_user_range		cpu_cache.flush_user_range
@@ -246,6 +254,7 @@
 
 #else
 
+#define __cpuc_flush_icache_all		__glue(_CACHE,_flush_icache_all)
 #define __cpuc_flush_kern_all		__glue(_CACHE,_flush_kern_cache_all)
 #define __cpuc_flush_user_all		__glue(_CACHE,_flush_user_cache_all)
 #define __cpuc_flush_user_range		__glue(_CACHE,_flush_user_cache_range)
@@ -253,6 +262,7 @@
 #define __cpuc_coherent_user_range	__glue(_CACHE,_coherent_user_range)
 #define __cpuc_flush_dcache_area	__glue(_CACHE,_flush_kern_dcache_area)
 
+extern void __cpuc_flush_icache_all(void);
 extern void __cpuc_flush_kern_all(void);
 extern void __cpuc_flush_user_all(void);
 extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
@@ -291,6 +301,37 @@
 /*
  * Convert calls to our calling convention.
  */
+
+/* Invalidate I-cache */
+#define __flush_icache_all_generic()					\
+	asm("mcr	p15, 0, %0, c7, c5, 0"				\
+	    : : "r" (0));
+
+/* Invalidate I-cache inner shareable */
+#define __flush_icache_all_v7_smp()					\
+	asm("mcr	p15, 0, %0, c7, c1, 0"				\
+	    : : "r" (0));
+
+/*
+ * Optimized __flush_icache_all for the common cases. Note that UP ARMv7
+ * will fall through to use __flush_icache_all_generic.
+ */
+#if (defined(CONFIG_CPU_V7) && defined(CONFIG_CPU_V6)) ||		\
+	defined(CONFIG_SMP_ON_UP)
+#define __flush_icache_preferred	__cpuc_flush_icache_all
+#elif __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
+#define __flush_icache_preferred	__flush_icache_all_v7_smp
+#elif __LINUX_ARM_ARCH__ == 6 && defined(CONFIG_ARM_ERRATA_411920)
+#define __flush_icache_preferred	__cpuc_flush_icache_all
+#else
+#define __flush_icache_preferred	__flush_icache_all_generic
+#endif
+
+static inline void __flush_icache_all(void)
+{
+	__flush_icache_preferred();
+}
+
 #define flush_cache_all()		__cpuc_flush_kern_all()
 
 static inline void vivt_flush_cache_mm(struct mm_struct *mm)
@@ -366,21 +407,6 @@
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __flush_icache_all(void)
-{
-#ifdef CONFIG_ARM_ERRATA_411920
-	extern void v6_icache_inval_all(void);
-	v6_icache_inval_all();
-#elif defined(CONFIG_SMP) && __LINUX_ARM_ARCH__ >= 7
-	asm("mcr	p15, 0, %0, c7, c1, 0	@ invalidate I-cache inner shareable\n"
-	    :
-	    : "r" (0));
-#else
-	asm("mcr	p15, 0, %0, c7, c5, 0	@ invalidate I-cache\n"
-	    :
-	    : "r" (0));
-#endif
-}
 static inline void flush_kernel_vmap_range(void *addr, int size)
 {
 	if ((cache_is_vivt() || cache_is_vipt_aliasing()))
@@ -405,9 +431,6 @@
 #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
 static inline void flush_kernel_dcache_page(struct page *page)
 {
-	/* highmem pages are always flushed upon kunmap already */
-	if ((cache_is_vivt() || cache_is_vipt_aliasing()) && !PageHighMem(page))
-		__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
 }
 
 #define flush_dcache_mmap_lock(mapping) \
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/cachetype.h linux-libre-2.6.37-gnu/arch/arm/include/asm/cachetype.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/cachetype.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/cachetype.h	2011-01-04 19:50:19.000000000 -0500
@@ -6,6 +6,7 @@
 #define CACHEID_VIPT_ALIASING		(1 << 2)
 #define CACHEID_VIPT			(CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
 #define CACHEID_ASID_TAGGED		(1 << 3)
+#define CACHEID_VIPT_I_ALIASING		(1 << 4)
 
 extern unsigned int cacheid;
 
@@ -14,15 +15,18 @@
 #define cache_is_vipt_nonaliasing()	cacheid_is(CACHEID_VIPT_NONALIASING)
 #define cache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_ALIASING)
 #define icache_is_vivt_asid_tagged()	cacheid_is(CACHEID_ASID_TAGGED)
+#define icache_is_vipt_aliasing()	cacheid_is(CACHEID_VIPT_I_ALIASING)
 
 /*
  * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
  * Mask out support which will never be present on newer CPUs.
  * - v6+ is never VIVT
- * - v7+ VIPT never aliases
+ * - v7+ VIPT never aliases on D-side
  */
 #if __LINUX_ARM_ARCH__ >= 7
-#define __CACHEID_ARCH_MIN	(CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED)
+#define __CACHEID_ARCH_MIN	(CACHEID_VIPT_NONALIASING |\
+				 CACHEID_ASID_TAGGED |\
+				 CACHEID_VIPT_I_ALIASING)
 #elif __LINUX_ARM_ARCH__ >= 6
 #define	__CACHEID_ARCH_MIN	(~CACHEID_VIVT)
 #else
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/elf.h linux-libre-2.6.37-gnu/arch/arm/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -127,4 +127,8 @@
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+extern int vectors_user_mapping(void);
+#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/ftrace.h linux-libre-2.6.37-gnu/arch/arm/include/asm/ftrace.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/ftrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/ftrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,12 +2,30 @@
 #define _ASM_ARM_FTRACE
 
 #ifdef CONFIG_FUNCTION_TRACER
-#define MCOUNT_ADDR		((long)(mcount))
+#define MCOUNT_ADDR		((unsigned long)(__gnu_mcount_nc))
 #define MCOUNT_INSN_SIZE	4 /* sizeof mcount call */
 
 #ifndef __ASSEMBLY__
 extern void mcount(void);
 extern void __gnu_mcount_nc(void);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+struct dyn_arch_ftrace {
+#ifdef CONFIG_OLD_MCOUNT
+	bool	old_mcount;
+#endif
+};
+
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	/* With Thumb-2, the recorded addresses have the lsb set */
+	return addr & ~1;
+}
+
+extern void ftrace_caller_old(void);
+extern void ftrace_call_old(void);
+#endif
+
 #endif
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/cache-l2x0.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/cache-l2x0.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/cache-l2x0.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/cache-l2x0.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,9 +21,6 @@
 #define __ASM_ARM_HARDWARE_L2X0_H
 
 #define L2X0_CACHE_ID			0x000
-#define   L2X0_CACHE_ID_PART_MASK	(0xf << 6)
-#define   L2X0_CACHE_ID_PART_L210	(1 << 6)
-#define   L2X0_CACHE_ID_PART_L310	(3 << 6)
 #define L2X0_CACHE_TYPE			0x004
 #define L2X0_CTRL			0x100
 #define L2X0_AUX_CTRL			0x104
@@ -53,6 +50,16 @@
 #define L2X0_LINE_DATA			0xF10
 #define L2X0_LINE_TAG			0xF30
 #define L2X0_DEBUG_CTRL			0xF40
+#define L2X0_PREFETCH_CTRL		0xF60
+#define L2X0_POWER_CTRL			0xF80
+#define   L2X0_DYNAMIC_CLK_GATING_EN	(1 << 1)
+#define   L2X0_STNDBY_MODE_EN		(1 << 0)
+
+/* Registers shifts and masks */
+#define L2X0_CACHE_ID_PART_MASK		(0xf << 6)
+#define L2X0_CACHE_ID_PART_L210		(1 << 6)
+#define L2X0_CACHE_ID_PART_L310		(3 << 6)
+#define L2X0_AUX_CTRL_WAY_SIZE_MASK	(0x3 << 17)
 
 #ifndef __ASSEMBLY__
 extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/coresight.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/coresight.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/coresight.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/coresight.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,18 +21,6 @@
 #define TRACER_RUNNING		BIT(TRACER_RUNNING_BIT)
 #define TRACER_CYCLE_ACC	BIT(TRACER_CYCLE_ACC_BIT)
 
-struct tracectx {
-	unsigned int	etb_bufsz;
-	void __iomem	*etb_regs;
-	void __iomem	*etm_regs;
-	unsigned long	flags;
-	int		ncmppairs;
-	int		etm_portsz;
-	struct device	*dev;
-	struct clk	*emu_clk;
-	struct mutex	mutex;
-};
-
 #define TRACER_TIMEOUT 10000
 
 #define etm_writel(t, v, x) \
@@ -112,10 +100,10 @@
 
 /* ETM status register, "ETM Architecture", 3.3.2 */
 #define ETMR_STATUS		(0x10)
-#define ETMST_OVERFLOW		(1 << 0)
-#define ETMST_PROGBIT		(1 << 1)
-#define ETMST_STARTSTOP		(1 << 2)
-#define ETMST_TRIGGER		(1 << 3)
+#define ETMST_OVERFLOW		BIT(0)
+#define ETMST_PROGBIT		BIT(1)
+#define ETMST_STARTSTOP		BIT(2)
+#define ETMST_TRIGGER		BIT(3)
 
 #define etm_progbit(t)		(etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
 #define etm_started(t)		(etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
@@ -123,7 +111,7 @@
 
 #define ETMR_TRACEENCTRL2	0x1c
 #define ETMR_TRACEENCTRL	0x24
-#define ETMTE_INCLEXCL		(1 << 24)
+#define ETMTE_INCLEXCL		BIT(24)
 #define ETMR_TRACEENEVT		0x20
 #define ETMCTRL_OPTS		(ETMCTRL_DO_CPRT | \
 				ETMCTRL_DATA_DO_ADDR | \
@@ -146,12 +134,12 @@
 #define ETBR_CTRL		0x20
 #define ETBR_FORMATTERCTRL	0x304
 #define ETBFF_ENFTC		1
-#define ETBFF_ENFCONT		(1 << 1)
-#define ETBFF_FONFLIN		(1 << 4)
-#define ETBFF_MANUAL_FLUSH	(1 << 6)
-#define ETBFF_TRIGIN		(1 << 8)
-#define ETBFF_TRIGEVT		(1 << 9)
-#define ETBFF_TRIGFL		(1 << 10)
+#define ETBFF_ENFCONT		BIT(1)
+#define ETBFF_FONFLIN		BIT(4)
+#define ETBFF_MANUAL_FLUSH	BIT(6)
+#define ETBFF_TRIGIN		BIT(8)
+#define ETBFF_TRIGEVT		BIT(9)
+#define ETBFF_TRIGFL		BIT(10)
 
 #define etb_writel(t, v, x) \
 	(__raw_writel((v), (t)->etb_regs + (x)))
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/icst.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/icst.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/icst.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/icst.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  *
  *  Support functions for calculating clocks/divisors for the ICST
- *  clock generators.  See http://www.icst.com/ for more information
+ *  clock generators.  See http://www.idt.com/ for more information
  *  on these devices.
  */
 #ifndef ASMARM_HARDWARE_ICST_H
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/it8152.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/it8152.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hardware/it8152.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hardware/it8152.h	2011-01-04 19:50:19.000000000 -0500
@@ -75,7 +75,8 @@
   IT8152_PD_IRQ(1)  USB (USBR)
   IT8152_PD_IRQ(0)  Audio controller (ACR)
  */
-#define IT8152_IRQ(x)   (IRQ_BOARD_END + (x))
+#define IT8152_IRQ(x)   (IRQ_BOARD_START + (x))
+#define IT8152_LAST_IRQ	(IRQ_BOARD_START + 40)
 
 /* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
 #define IT8152_LD_IRQ_COUNT     9
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/arm/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,9 +25,6 @@
 extern void *kmap_high_get(struct page *page);
 extern void kunmap_high(struct page *page);
 
-extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
-extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
-
 /*
  * The following functions are already defined by <linux/highmem.h>
  * when CONFIG_HIGHMEM is not set.
@@ -35,9 +32,9 @@
 #ifdef CONFIG_HIGHMEM
 extern void *kmap(struct page *page);
 extern void kunmap(struct page *page);
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
 extern struct page *kmap_atomic_to_page(const void *ptr);
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hw_breakpoint.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hw_breakpoint.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hw_breakpoint.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hw_breakpoint.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,133 @@
+#ifndef _ARM_HW_BREAKPOINT_H
+#define _ARM_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+
+struct task_struct;
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+struct arch_hw_breakpoint_ctrl {
+		u32 __reserved	: 9,
+		mismatch	: 1,
+				: 9,
+		len		: 8,
+		type		: 2,
+		privilege	: 2,
+		enabled		: 1;
+};
+
+struct arch_hw_breakpoint {
+	u32	address;
+	u32	trigger;
+	struct perf_event *suspended_wp;
+	struct arch_hw_breakpoint_ctrl ctrl;
+};
+
+static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
+{
+	return (ctrl.mismatch << 22) | (ctrl.len << 5) | (ctrl.type << 3) |
+		(ctrl.privilege << 1) | ctrl.enabled;
+}
+
+static inline void decode_ctrl_reg(u32 reg,
+				   struct arch_hw_breakpoint_ctrl *ctrl)
+{
+	ctrl->enabled	= reg & 0x1;
+	reg >>= 1;
+	ctrl->privilege	= reg & 0x3;
+	reg >>= 2;
+	ctrl->type	= reg & 0x3;
+	reg >>= 2;
+	ctrl->len	= reg & 0xff;
+	reg >>= 17;
+	ctrl->mismatch	= reg & 0x1;
+}
+
+/* Debug architecture numbers. */
+#define ARM_DEBUG_ARCH_RESERVED	0	/* In case of ptrace ABI updates. */
+#define ARM_DEBUG_ARCH_V6	1
+#define ARM_DEBUG_ARCH_V6_1	2
+#define ARM_DEBUG_ARCH_V7_ECP14	3
+#define ARM_DEBUG_ARCH_V7_MM	4
+
+/* Breakpoint */
+#define ARM_BREAKPOINT_EXECUTE	0
+
+/* Watchpoints */
+#define ARM_BREAKPOINT_LOAD	1
+#define ARM_BREAKPOINT_STORE	2
+
+/* Privilege Levels */
+#define ARM_BREAKPOINT_PRIV	1
+#define ARM_BREAKPOINT_USER	2
+
+/* Lengths */
+#define ARM_BREAKPOINT_LEN_1	0x1
+#define ARM_BREAKPOINT_LEN_2	0x3
+#define ARM_BREAKPOINT_LEN_4	0xf
+#define ARM_BREAKPOINT_LEN_8	0xff
+
+/* Limits */
+#define ARM_MAX_BRP		16
+#define ARM_MAX_WRP		16
+#define ARM_MAX_HBP_SLOTS	(ARM_MAX_BRP + ARM_MAX_WRP)
+
+/* DSCR method of entry bits. */
+#define ARM_DSCR_MOE(x)			((x >> 2) & 0xf)
+#define ARM_ENTRY_BREAKPOINT		0x1
+#define ARM_ENTRY_ASYNC_WATCHPOINT	0x2
+#define ARM_ENTRY_SYNC_WATCHPOINT	0xa
+
+/* DSCR monitor/halting bits. */
+#define ARM_DSCR_HDBGEN		(1 << 14)
+#define ARM_DSCR_MDBGEN		(1 << 15)
+
+/* opcode2 numbers for the co-processor instructions. */
+#define ARM_OP2_BVR		4
+#define ARM_OP2_BCR		5
+#define ARM_OP2_WVR		6
+#define ARM_OP2_WCR		7
+
+/* Base register numbers for the debug registers. */
+#define ARM_BASE_BVR		64
+#define ARM_BASE_BCR		80
+#define ARM_BASE_WVR		96
+#define ARM_BASE_WCR		112
+
+/* Accessor macros for the debug registers. */
+#define ARM_DBG_READ(M, OP2, VAL) do {\
+	asm volatile("mrc p14, 0, %0, c0," #M ", " #OP2 : "=r" (VAL));\
+} while (0)
+
+#define ARM_DBG_WRITE(M, OP2, VAL) do {\
+	asm volatile("mcr p14, 0, %0, c0," #M ", " #OP2 : : "r" (VAL));\
+} while (0)
+
+struct notifier_block;
+struct perf_event;
+struct pmu;
+
+extern struct pmu perf_ops_bp;
+extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+				  int *gen_len, int *gen_type);
+extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+					   unsigned long val, void *data);
+
+extern u8 arch_get_debug_arch(void);
+extern u8 arch_get_max_wp_len(void);
+extern void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+int hw_breakpoint_slots(int type);
+
+#else
+static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk) {}
+
+#endif	/* CONFIG_HAVE_HW_BREAKPOINT */
+#endif	/* __KERNEL__ */
+#endif	/* _ARM_HW_BREAKPOINT_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/hw_irq.h linux-libre-2.6.37-gnu/arch/arm/include/asm/hw_irq.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/hw_irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/hw_irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,4 +24,6 @@
 #define IRQF_PROBE	(1 << 1)
 #define IRQF_NOAUTOEN	(1 << 2)
 
+#define ARCH_IRQ_INIT_FLAGS	(IRQ_NOREQUEST | IRQ_NOPROBE)
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/arm/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,89 +1,8 @@
 #ifndef __ASM_ARM_IOCTLS_H
 #define __ASM_ARM_IOCTLS_H
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define TIOCGRS485      0x542E
-#define TIOCSRS485      0x542F
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT	0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/io.h linux-libre-2.6.37-gnu/arch/arm/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -294,6 +294,7 @@
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
 extern int valid_phys_addr_range(unsigned long addr, size_t size);
 extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+extern int devmem_is_allowed(unsigned long pfn);
 #endif
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/arm/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,66 +10,85 @@
  */
 #if __LINUX_ARM_ARCH__ >= 6
 
-#define raw_local_irq_save(x)					\
-	({							\
-	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
-	"cpsid	i"						\
-	: "=r" (x) : : "memory", "cc");				\
-	})
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+
+	asm volatile(
+		"	mrs	%0, cpsr	@ arch_local_irq_save\n"
+		"	cpsid	i"
+		: "=r" (flags) : : "memory", "cc");
+	return flags;
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile(
+		"	cpsie i			@ arch_local_irq_enable"
+		:
+		:
+		: "memory", "cc");
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile(
+		"	cpsid i			@ arch_local_irq_disable"
+		:
+		:
+		: "memory", "cc");
+}
 
-#define raw_local_irq_enable()  __asm__("cpsie i	@ __sti" : : : "memory", "cc")
-#define raw_local_irq_disable() __asm__("cpsid i	@ __cli" : : : "memory", "cc")
 #define local_fiq_enable()  __asm__("cpsie f	@ __stf" : : : "memory", "cc")
 #define local_fiq_disable() __asm__("cpsid f	@ __clf" : : : "memory", "cc")
-
 #else
 
 /*
  * Save the current interrupt enable state & disable IRQs
  */
-#define raw_local_irq_save(x)					\
-	({							\
-		unsigned long temp;				\
-		(void) (&temp == &x);				\
-	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_save\n"	\
-"	orr	%1, %0, #128\n"					\
-"	msr	cpsr_c, %1"					\
-	: "=r" (x), "=r" (temp)					\
-	:							\
-	: "memory", "cc");					\
-	})
-	
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags, temp;
+
+	asm volatile(
+		"	mrs	%0, cpsr	@ arch_local_irq_save\n"
+		"	orr	%1, %0, #128\n"
+		"	msr	cpsr_c, %1"
+		: "=r" (flags), "=r" (temp)
+		:
+		: "memory", "cc");
+	return flags;
+}
+
 /*
  * Enable IRQs
  */
-#define raw_local_irq_enable()					\
-	({							\
-		unsigned long temp;				\
-	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_enable\n"	\
-"	bic	%0, %0, #128\n"					\
-"	msr	cpsr_c, %0"					\
-	: "=r" (temp)						\
-	:							\
-	: "memory", "cc");					\
-	})
+static inline void arch_local_irq_enable(void)
+{
+	unsigned long temp;
+	asm volatile(
+		"	mrs	%0, cpsr	@ arch_local_irq_enable\n"
+		"	bic	%0, %0, #128\n"
+		"	msr	cpsr_c, %0"
+		: "=r" (temp)
+		:
+		: "memory", "cc");
+}
 
 /*
  * Disable IRQs
  */
-#define raw_local_irq_disable()					\
-	({							\
-		unsigned long temp;				\
-	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_irq_disable\n"	\
-"	orr	%0, %0, #128\n"					\
-"	msr	cpsr_c, %0"					\
-	: "=r" (temp)						\
-	:							\
-	: "memory", "cc");					\
-	})
+static inline void arch_local_irq_disable(void)
+{
+	unsigned long temp;
+	asm volatile(
+		"	mrs	%0, cpsr	@ arch_local_irq_disable\n"
+		"	orr	%0, %0, #128\n"
+		"	msr	cpsr_c, %0"
+		: "=r" (temp)
+		:
+		: "memory", "cc");
+}
 
 /*
  * Enable FIQs
@@ -106,27 +125,31 @@
 /*
  * Save the current interrupt enable state.
  */
-#define raw_local_save_flags(x)					\
-	({							\
-	__asm__ __volatile__(					\
-	"mrs	%0, cpsr		@ local_save_flags"	\
-	: "=r" (x) : : "memory", "cc");				\
-	})
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile(
+		"	mrs	%0, cpsr	@ local_save_flags"
+		: "=r" (flags) : : "memory", "cc");
+	return flags;
+}
 
 /*
  * restore saved IRQ & FIQ state
  */
-#define raw_local_irq_restore(x)				\
-	__asm__ __volatile__(					\
-	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
-	:							\
-	: "r" (x)						\
-	: "memory", "cc")
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile(
+		"	msr	cpsr_c, %0	@ local_irq_restore"
+		:
+		: "r" (flags)
+		: "memory", "cc");
+}
 
-#define raw_irqs_disabled_flags(flags)	\
-({					\
-	(int)((flags) & PSR_I_BIT);	\
-})
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags & PSR_I_BIT;
+}
 
 #endif
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/kgdb.h linux-libre-2.6.37-gnu/arch/arm/include/asm/kgdb.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/kgdb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/kgdb.h	2011-01-04 19:50:19.000000000 -0500
@@ -70,7 +70,8 @@
 #define _GP_REGS		16
 #define _FP_REGS		8
 #define _EXTRA_REGS		2
-#define DBG_MAX_REG_NUM		(_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+#define GDB_MAX_REGS		(_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+#define DBG_MAX_REG_NUM		(_GP_REGS + _FP_REGS + _EXTRA_REGS)
 
 #define KGDB_MAX_NO_CPUS	1
 #define BUFMAX			400
@@ -93,7 +94,7 @@
 #define _SPT			13
 #define _LR			14
 #define _PC			15
-#define _CPSR			(DBG_MAX_REG_NUM - 1)
+#define _CPSR			(GDB_MAX_REGS - 1)
 
 /*
  * So that we can denote the end of a frame for tracing,
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/mach/arch.h linux-libre-2.6.37-gnu/arch/arm/include/asm/mach/arch.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/mach/arch.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/mach/arch.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,18 +16,15 @@
 
 struct machine_desc {
 	/*
-	 * Note! The first four elements are used
+	 * Note! The first two elements are used
 	 * by assembler code in head.S, head-common.S
 	 */
 	unsigned int		nr;		/* architecture number	*/
-	unsigned int		nr_irqs;	/* number of IRQs */
-	unsigned int		phys_io;	/* start of physical io	*/
-	unsigned int		io_pg_offst;	/* byte offset for io 
-						 * page tabe entry	*/
-
 	const char		*name;		/* architecture name	*/
 	unsigned long		boot_params;	/* tagged list		*/
 
+	unsigned int		nr_irqs;	/* number of IRQs */
+
 	unsigned int		video_start;	/* start of video RAM	*/
 	unsigned int		video_end;	/* end of video RAM	*/
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/arm/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/memblock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,13 +1,6 @@
 #ifndef _ASM_ARM_MEMBLOCK_H
 #define _ASM_ARM_MEMBLOCK_H
 
-#ifdef CONFIG_MMU
-extern phys_addr_t lowmem_end_addr;
-#define MEMBLOCK_REAL_LIMIT	lowmem_end_addr
-#else
-#define MEMBLOCK_REAL_LIMIT	0
-#endif
-
 struct meminfo;
 struct machine_desc;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/mmu_context.h linux-libre-2.6.37-gnu/arch/arm/include/asm/mmu_context.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/mmu_context.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/mmu_context.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,6 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/proc-fns.h>
-#include <asm-generic/mm_hooks.h>
 
 void __check_kvm_seq(struct mm_struct *mm);
 
@@ -134,4 +133,32 @@
 #define deactivate_mm(tsk,mm)	do { } while (0)
 #define activate_mm(prev,next)	switch_mm(prev, next, NULL)
 
+/*
+ * We are inserting a "fake" vma for the user-accessible vector page so
+ * gdb and friends can get to it through ptrace and /proc/<pid>/mem.
+ * But we also want to remove it before the generic code gets to see it
+ * during process exit or the unmapping of it would  cause total havoc.
+ * (the macro is used as remove_vma() is static to mm/mmap.c)
+ */
+#define arch_exit_mmap(mm) \
+do { \
+	struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
+	if (high_vma) { \
+		BUG_ON(high_vma->vm_next);  /* it should be last */ \
+		if (high_vma->vm_prev) \
+			high_vma->vm_prev->vm_next = NULL; \
+		else \
+			mm->mmap = NULL; \
+		rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
+		mm->mmap_cache = NULL; \
+		mm->map_count--; \
+		remove_vma(high_vma); \
+	} \
+} while (0)
+
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+				 struct mm_struct *mm)
+{
+}
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/mmu.h linux-libre-2.6.37-gnu/arch/arm/include/asm/mmu.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/mmu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/mmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,10 @@
 
 #ifdef CONFIG_CPU_HAS_ASID
 #define ASID(mm)	((mm)->context.id & 255)
+
+/* init_mm.context.id_lock should be initialized. */
+#define INIT_MM_CONTEXT(name)                                                 \
+	.context.id_lock    = __SPIN_LOCK_UNLOCKED(name.context.id_lock),
 #else
 #define ASID(mm)	(0)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/module.h linux-libre-2.6.37-gnu/arch/arm/include/asm/module.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/module.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/module.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,20 +7,27 @@
 
 struct unwind_table;
 
-struct mod_arch_specific
-{
 #ifdef CONFIG_ARM_UNWIND
-	Elf_Shdr *unw_sec_init;
-	Elf_Shdr *unw_sec_devinit;
-	Elf_Shdr *unw_sec_core;
-	Elf_Shdr *sec_init_text;
-	Elf_Shdr *sec_devinit_text;
-	Elf_Shdr *sec_core_text;
-	struct unwind_table *unwind_init;
-	struct unwind_table *unwind_devinit;
-	struct unwind_table *unwind_core;
-#endif
+struct arm_unwind_mapping {
+	Elf_Shdr *unw_sec;
+	Elf_Shdr *sec_text;
+	struct unwind_table *unwind;
 };
+enum {
+	ARM_SEC_INIT,
+	ARM_SEC_DEVINIT,
+	ARM_SEC_CORE,
+	ARM_SEC_EXIT,
+	ARM_SEC_DEVEXIT,
+	ARM_SEC_MAX,
+};
+struct mod_arch_specific {
+	struct arm_unwind_mapping map[ARM_SEC_MAX];
+};
+#else
+struct mod_arch_specific {
+};
+#endif
 
 /*
  * Include the ARM architecture version.
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/outercache.h linux-libre-2.6.37-gnu/arch/arm/include/asm/outercache.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/outercache.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/outercache.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,9 @@
 	void (*inv_range)(unsigned long, unsigned long);
 	void (*clean_range)(unsigned long, unsigned long);
 	void (*flush_range)(unsigned long, unsigned long);
+	void (*flush_all)(void);
+	void (*inv_all)(void);
+	void (*disable)(void);
 #ifdef CONFIG_OUTER_CACHE_SYNC
 	void (*sync)(void);
 #endif
@@ -50,6 +53,24 @@
 		outer_cache.flush_range(start, end);
 }
 
+static inline void outer_flush_all(void)
+{
+	if (outer_cache.flush_all)
+		outer_cache.flush_all();
+}
+
+static inline void outer_inv_all(void)
+{
+	if (outer_cache.inv_all)
+		outer_cache.inv_all();
+}
+
+static inline void outer_disable(void)
+{
+	if (outer_cache.disable)
+		outer_cache.disable();
+}
+
 #else
 
 static inline void outer_inv_range(unsigned long start, unsigned long end)
@@ -58,6 +79,9 @@
 { }
 static inline void outer_flush_range(unsigned long start, unsigned long end)
 { }
+static inline void outer_flush_all(void) { }
+static inline void outer_inv_all(void) { }
+static inline void outer_disable(void) { }
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/arm/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,18 +12,6 @@
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/*
- * NOP: on *most* (read: all supported) ARM platforms, the performance
- * counter interrupts are regular interrupts and not an NMI. This
- * means that when we receive the interrupt we can call
- * perf_event_do_pending() that handles all of the work with
- * interrupts disabled.
- */
-static inline void
-set_perf_event_pending(void)
-{
-}
-
 /* ARM performance counters start from 1 (in the cp15 accesses) so use the
  * same indexes here for consistency. */
 #define PERF_EVENT_INDEX_OFFSET 1
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/arm/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -263,24 +263,37 @@
 #define pte_page(pte)		(pfn_to_page(pte_pfn(pte)))
 #define pte_offset_kernel(dir,addr)	(pmd_page_vaddr(*(dir)) + __pte_index(addr))
 
-#define pte_offset_map(dir,addr)	(__pte_map(dir, KM_PTE0) + __pte_index(addr))
-#define pte_offset_map_nested(dir,addr)	(__pte_map(dir, KM_PTE1) + __pte_index(addr))
-#define pte_unmap(pte)			__pte_unmap(pte, KM_PTE0)
-#define pte_unmap_nested(pte)		__pte_unmap(pte, KM_PTE1)
+#define pte_offset_map(dir,addr)	(__pte_map(dir) + __pte_index(addr))
+#define pte_unmap(pte)			__pte_unmap(pte)
 
 #ifndef CONFIG_HIGHPTE
-#define __pte_map(dir,km)	pmd_page_vaddr(*(dir))
-#define __pte_unmap(pte,km)	do { } while (0)
+#define __pte_map(dir)		pmd_page_vaddr(*(dir))
+#define __pte_unmap(pte)	do { } while (0)
 #else
-#define __pte_map(dir,km)	((pte_t *)kmap_atomic(pmd_page(*(dir)), km) + PTRS_PER_PTE)
-#define __pte_unmap(pte,km)	kunmap_atomic((pte - PTRS_PER_PTE), km)
+#define __pte_map(dir)		((pte_t *)kmap_atomic(pmd_page(*(dir))) + PTRS_PER_PTE)
+#define __pte_unmap(pte)	kunmap_atomic((pte - PTRS_PER_PTE))
 #endif
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
 
-#define set_pte_at(mm,addr,ptep,pteval) do { \
-	set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \
- } while (0)
+#if __LINUX_ARM_ARCH__ < 6
+static inline void __sync_icache_dcache(pte_t pteval)
+{
+}
+#else
+extern void __sync_icache_dcache(pte_t pteval);
+#endif
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval)
+{
+	if (addr >= TASK_SIZE)
+		set_pte_ext(ptep, pteval, 0);
+	else {
+		__sync_icache_dcache(pteval);
+		set_pte_ext(ptep, pteval, PTE_EXT_NG);
+	}
+}
 
 /*
  * The following only work if pte_present() is true.
@@ -290,8 +303,13 @@
 #define pte_write(pte)		(pte_val(pte) & L_PTE_WRITE)
 #define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)		(pte_val(pte) & L_PTE_EXEC)
 #define pte_special(pte)	(0)
 
+#define pte_present_user(pte) \
+	((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+	 (L_PTE_PRESENT | L_PTE_USER))
+
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
@@ -356,6 +374,9 @@
 
 #define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
 
+/* we don't need complex calculations here as the pmd is folded into the pgd */
+#define pmd_addr_end(addr,end)	(end)
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/processor.h linux-libre-2.6.37-gnu/arch/arm/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 
 #ifdef __KERNEL__
 
+#include <asm/hw_breakpoint.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
@@ -41,6 +42,9 @@
 struct debug_info {
 	int			nsaved;
 	struct debug_entry	bp[2];
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+	struct perf_event	*hbp[ARM_MAX_HBP_SLOTS];
+#endif
 };
 
 struct thread_struct {
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/arm/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -29,6 +29,8 @@
 #define PTRACE_SETCRUNCHREGS	26
 #define PTRACE_GETVFPREGS	27
 #define PTRACE_SETVFPREGS	28
+#define PTRACE_GETHBPREGS	29
+#define PTRACE_SETHBPREGS	30
 
 /*
  * PSR bits
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/seccomp.h linux-libre-2.6.37-gnu/arch/arm/include/asm/seccomp.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/seccomp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/seccomp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,11 @@
+#ifndef _ASM_ARM_SECCOMP_H
+#define _ASM_ARM_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+
+#endif /* _ASM_ARM_SECCOMP_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/sizes.h linux-libre-2.6.37-gnu/arch/arm/include/asm/sizes.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/sizes.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/sizes.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,9 +13,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-/* DO NOT EDIT!! - this file automatically generated
- *                 from .s file by awk -f s2h.awk
- */
 /*  Size definitions
  *  Copyright (C) ARM Limited 1998. All rights reserved.
  */
@@ -25,6 +22,9 @@
 
 /* handy sizes */
 #define SZ_16				0x00000010
+#define SZ_32				0x00000020
+#define SZ_64				0x00000040
+#define SZ_128				0x00000080
 #define SZ_256				0x00000100
 #define SZ_512				0x00000200
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/smp_mpidr.h linux-libre-2.6.37-gnu/arch/arm/include/asm/smp_mpidr.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/smp_mpidr.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/smp_mpidr.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,17 @@
+#ifndef ASMARM_SMP_MIDR_H
+#define ASMARM_SMP_MIDR_H
+
+#define hard_smp_processor_id()						\
+	({								\
+		unsigned int cpunum;					\
+		__asm__("\n"						\
+			"1:	mrc p15, 0, %0, c0, c0, 5\n"		\
+			"	.pushsection \".alt.smp.init\", \"a\"\n"\
+			"	.long	1b\n"				\
+			"	mov	%0, #0\n"			\
+			"	.popsection"				\
+			: "=r" (cpunum));				\
+		cpunum &= 0x0F;						\
+	})
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/smp_plat.h linux-libre-2.6.37-gnu/arch/arm/include/asm/smp_plat.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/smp_plat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/smp_plat.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,15 +7,40 @@
 
 #include <asm/cputype.h>
 
+/*
+ * Return true if we are running on a SMP platform
+ */
+static inline bool is_smp(void)
+{
+#ifndef CONFIG_SMP
+	return false;
+#elif defined(CONFIG_SMP_ON_UP)
+	extern unsigned int smp_on_up;
+	return !!smp_on_up;
+#else
+	return true;
+#endif
+}
+
 /* all SMP configurations have the extended CPUID registers */
 static inline int tlb_ops_need_broadcast(void)
 {
+	if (!is_smp())
+		return 0;
+
 	return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
 }
 
+#if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7
+#define cache_ops_need_broadcast()	0
+#else
 static inline int cache_ops_need_broadcast(void)
 {
+	if (!is_smp())
+		return 0;
+
 	return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1;
 }
+#endif
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/system.h linux-libre-2.6.37-gnu/arch/arm/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -85,6 +85,10 @@
 				       struct pt_regs *),
 		     int sig, int code, const char *name);
 
+void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
+				       struct pt_regs *),
+		     int sig, int code, const char *name);
+
 #define xchg(ptr,x) \
 	((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
@@ -146,6 +150,7 @@
 #define rmb()		dmb()
 #define wmb()		mb()
 #else
+#include <asm/memory.h>
 #define mb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
 #define rmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
 #define wmb()	do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
@@ -325,6 +330,8 @@
 extern void disable_hlt(void);
 extern void enable_hlt(void);
 
+void cpu_idle_wait(void);
+
 #include <asm-generic/cmpxchg-local.h>
 
 #if __LINUX_ARM_ARCH__ < 6
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/thread_info.h linux-libre-2.6.37-gnu/arch/arm/include/asm/thread_info.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/thread_info.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/thread_info.h	2011-01-04 19:50:19.000000000 -0500
@@ -144,6 +144,7 @@
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FREEZE		19
 #define TIF_RESTORE_SIGMASK	20
+#define TIF_SECCOMP		21
 
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
@@ -153,6 +154,7 @@
 #define _TIF_USING_IWMMXT	(1 << TIF_USING_IWMMXT)
 #define _TIF_FREEZE		(1 << TIF_FREEZE)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
+#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 
 /*
  * Change these and you break ASM code in entry-common.S
diff -druN linux-libre-2.6.36-gnu/arch/arm/include/asm/tlbflush.h linux-libre-2.6.37-gnu/arch/arm/include/asm/tlbflush.h
--- linux-libre-2.6.36-gnu/arch/arm/include/asm/tlbflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/include/asm/tlbflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -70,6 +70,10 @@
 #undef _TLB
 #undef MULTI_TLB
 
+#ifdef CONFIG_SMP_ON_UP
+#define MULTI_TLB 1
+#endif
+
 #define v3_tlb_flags	(TLB_V3_FULL | TLB_V3_PAGE)
 
 #ifdef CONFIG_CPU_TLB_V3
@@ -185,17 +189,23 @@
 # define v6wbi_always_flags	(-1UL)
 #endif
 
-#ifdef CONFIG_SMP
-#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \
+#define v7wbi_tlb_flags_smp	(TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \
 			 TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
-#else
-#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+#define v7wbi_tlb_flags_up	(TLB_WB | TLB_DCLEAN | TLB_BTB | \
 			 TLB_V6_U_FULL | TLB_V6_U_PAGE | TLB_V6_U_ASID)
-#endif
 
 #ifdef CONFIG_CPU_TLB_V7
-# define v7wbi_possible_flags	v7wbi_tlb_flags
-# define v7wbi_always_flags	v7wbi_tlb_flags
+
+# ifdef CONFIG_SMP_ON_UP
+#  define v7wbi_possible_flags	(v7wbi_tlb_flags_smp | v7wbi_tlb_flags_up)
+#  define v7wbi_always_flags	(v7wbi_tlb_flags_smp & v7wbi_tlb_flags_up)
+# elif defined(CONFIG_SMP)
+#  define v7wbi_possible_flags	v7wbi_tlb_flags_smp
+#  define v7wbi_always_flags	v7wbi_tlb_flags_smp
+# else
+#  define v7wbi_possible_flags	v7wbi_tlb_flags_up
+#  define v7wbi_always_flags	v7wbi_tlb_flags_up
+# endif
 # ifdef _TLB
 #  define MULTI_TLB 1
 # else
@@ -560,12 +570,20 @@
 #endif
 
 /*
- * if PG_dcache_dirty is set for the page, we need to ensure that any
+ * If PG_dcache_clean is not set for the page, we need to ensure that any
  * cache entries for the kernels virtual memory range are written
- * back to the page.
+ * back to the page. On ARMv6 and later, the cache coherency is handled via
+ * the set_pte_at() function.
  */
+#if __LINUX_ARM_ARCH__ < 6
 extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
 	pte_t *ptep);
+#else
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+				    unsigned long addr, pte_t *ptep)
+{
+}
+#endif
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/Kconfig linux-libre-2.6.37-gnu/arch/arm/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux Kernel Configuration"
-
 config ARM
 	bool
 	default y
@@ -13,19 +6,23 @@
 	select HAVE_MEMBLOCK
 	select RTC_LIB
 	select SYS_SUPPORTS_APM_EMULATION
-	select GENERIC_ATOMIC64 if (!CPU_32v6K)
+	select GENERIC_ATOMIC64 if (!CPU_32v6K || !AEABI)
 	select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
 	select HAVE_ARCH_KGDB
-	select HAVE_KPROBES if (!XIP_KERNEL)
+	select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL)
 	select HAVE_KRETPROBES if (HAVE_KPROBES)
 	select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
+	select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
+	select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_LZO
 	select HAVE_KERNEL_LZMA
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
 	select HAVE_REGS_AND_STACK_ACCESS_API
+	select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V7))
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -145,6 +142,9 @@
 	  and that the relevant menu configurations are displayed for
 	  it.
 
+config ARCH_HAS_CPU_IDLE_WAIT
+       def_bool y
+
 config GENERIC_HWEIGHT
 	bool
 	default y
@@ -510,6 +510,7 @@
 	select GENERIC_CLOCKEVENTS
 	select TICK_ONESHOT
 	select PLAT_PXA
+	select SPARSE_IRQ
 	help
 	  Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
@@ -565,6 +566,7 @@
 	select HAVE_CLK
 	select COMMON_CLKDEV
 	select ARCH_HAS_BARRIERS if CACHE_L2X0
+	select ARCH_HAS_CPUFREQ
 	help
 	  This enables support for NVIDIA Tegra based systems (Tegra APX,
 	  Tegra 6xx and Tegra 2 series).
@@ -587,6 +589,7 @@
 	select GENERIC_CLOCKEVENTS
 	select TICK_ONESHOT
 	select PLAT_PXA
+	select SPARSE_IRQ
 	help
 	  Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
 
@@ -643,7 +646,7 @@
 	select ARCH_HAS_CPUFREQ
 	select HAVE_CLK
 	select ARCH_USES_GETTIMEOFFSET
-	select HAVE_S3C2410_I2C
+	select HAVE_S3C2410_I2C if I2C
 	help
 	  Samsung S3C2410X CPU based systems, such as the Simtec Electronics
 	  BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
@@ -673,22 +676,23 @@
 	select S3C_DEV_NAND
 	select USB_ARCH_HAS_OHCI
 	select SAMSUNG_GPIOLIB_4BIT
-	select HAVE_S3C2410_I2C
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	help
 	  Samsung S3C64XX series based systems
 
-config ARCH_S5P6440
-	bool "Samsung S5P6440"
+config ARCH_S5P64X0
+	bool "Samsung S5P6440 S5P6450"
 	select CPU_V6
 	select GENERIC_GPIO
 	select HAVE_CLK
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	select ARCH_USES_GETTIMEOFFSET
-	select HAVE_S3C2410_I2C
-	select HAVE_S3C_RTC
+	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C_RTC if RTC_CLASS
 	help
-	  Samsung S5P6440 CPU based systems
+	  Samsung S5P64X0 CPU based systems, such as the Samsung SMDK6440,
+	  SMDK6450.
 
 config ARCH_S5P6442
 	bool "Samsung S5P6442"
@@ -696,7 +700,7 @@
 	select GENERIC_GPIO
 	select HAVE_CLK
 	select ARCH_USES_GETTIMEOFFSET
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	help
 	  Samsung S5P6442 CPU based systems
 
@@ -707,31 +711,37 @@
 	select CPU_V7
 	select ARM_L1_CACHE_SHIFT_6
 	select ARCH_USES_GETTIMEOFFSET
-	select HAVE_S3C2410_I2C
-	select HAVE_S3C_RTC
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C_RTC if RTC_CLASS
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	help
 	  Samsung S5PC100 series based systems
 
 config ARCH_S5PV210
 	bool "Samsung S5PV210/S5PC110"
 	select CPU_V7
+	select ARCH_SPARSEMEM_ENABLE
 	select GENERIC_GPIO
 	select HAVE_CLK
 	select ARM_L1_CACHE_SHIFT_6
+	select ARCH_HAS_CPUFREQ
 	select ARCH_USES_GETTIMEOFFSET
-	select HAVE_S3C2410_I2C
-	select HAVE_S3C_RTC
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C_RTC if RTC_CLASS
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	help
 	  Samsung S5PV210/S5PC110 series based systems
 
 config ARCH_S5PV310
 	bool "Samsung S5PV310/S5PC210"
 	select CPU_V7
+	select ARCH_SPARSEMEM_ENABLE
 	select GENERIC_GPIO
 	select HAVE_CLK
 	select GENERIC_CLOCKEVENTS
+	select HAVE_S3C_RTC if RTC_CLASS
+	select HAVE_S3C2410_I2C if I2C
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	help
 	  Samsung S5PV310 series based systems
 
@@ -747,6 +757,15 @@
 	  Support for the StrongARM based Digital DNARD machine, also known
 	  as "Shark" (<http://www.shark-linux.de/shark.html>).
 
+config ARCH_TCC_926
+	bool "Telechips TCC ARM926-based systems"
+	select CPU_ARM926T
+	select HAVE_CLK
+	select COMMON_CLKDEV
+	select GENERIC_CLOCKEVENTS
+	help
+	  Support for Telechips TCC ARM926-based systems.
+
 config ARCH_LH7A40X
 	bool "Sharp LH7A40X"
 	select CPU_ARM922T
@@ -812,7 +831,7 @@
 	select GENERIC_CLOCKEVENTS
 	select ARCH_HAS_HOLES_MEMORYMODEL
 	help
-	  Support for TI's OMAP platform (OMAP1 and OMAP2).
+	  Support for TI's OMAP platform (OMAP1/2/3/4).
 
 config PLAT_SPEAR
 	bool "ST SPEAr"
@@ -915,6 +934,8 @@
 
 source "arch/arm/plat-spear/Kconfig"
 
+source "arch/arm/plat-tcc/Kconfig"
+
 if ARCH_S3C2410
 source "arch/arm/mach-s3c2400/Kconfig"
 source "arch/arm/mach-s3c2410/Kconfig"
@@ -928,7 +949,7 @@
 source "arch/arm/mach-s3c64xx/Kconfig"
 endif
 
-source "arch/arm/mach-s5p6440/Kconfig"
+source "arch/arm/mach-s5p64x0/Kconfig"
 
 source "arch/arm/mach-s5p6442/Kconfig"
 
@@ -1002,7 +1023,7 @@
 
 config ARM_ERRATA_411920
 	bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
-	depends on CPU_V6 && !SMP
+	depends on CPU_V6
 	help
 	  Invalidation of the Instruction Cache operation can
 	  fail. This erratum is present in 1136 (before r1p4), 1156 and 1176.
@@ -1181,13 +1202,13 @@
 
 config SMP
 	bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\
-		 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 ||\
-		 ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4)
+	depends on EXPERIMENTAL
 	depends on GENERIC_CLOCKEVENTS
+	depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
+		 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 ||\
+		 ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4
 	select USE_GENERIC_SMP_HELPERS
-	select HAVE_ARM_SCU if ARCH_REALVIEW || ARCH_OMAP4 || ARCH_S5PV310 ||\
-		 ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4
+	select HAVE_ARM_SCU
 	help
 	  This enables support for systems with more than one CPU. If you have
 	  a system with only one CPU, like most personal computers, say N. If
@@ -1201,10 +1222,23 @@
 
 	  See also <file:Documentation/i386/IO-APIC.txt>,
 	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-	  <http://www.linuxdoc.org/docs.html#howto>.
+	  <http://tldp.org/HOWTO/SMP-HOWTO.html>.
 
 	  If you don't know what to do here, say N.
 
+config SMP_ON_UP
+	bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	depends on SMP && !XIP && !THUMB2_KERNEL
+	default y
+	help
+	  SMP kernels contain instructions which fail on non-SMP processors.
+	  Enabling this option allows the kernel to modify itself to make
+	  these instructions safe.  Disabling it allows about 1K of space
+	  savings.
+
+	  If you don't know what to do here, say Y.
+
 config HAVE_ARM_SCU
 	bool
 	depends on SMP
@@ -1255,12 +1289,9 @@
 
 config LOCAL_TIMERS
 	bool "Use local timer interrupts"
-	depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
-		REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
-		ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4)
+	depends on SMP
 	default y
-	select HAVE_ARM_TWD if ARCH_REALVIEW || ARCH_OMAP4 || ARCH_S5PV310 || \
-		ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS
+	select HAVE_ARM_TWD
 	help
 	  Enable support for local timers on SMP platforms, rather then the
 	  legacy IPI broadcast method.  Local timers allows the system
@@ -1271,7 +1302,7 @@
 
 config HZ
 	int
-	default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P6440 || \
+	default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
 		ARCH_S5P6442 || ARCH_S5PV210 || ARCH_S5PV310
 	default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
 	default AT91_TIMER_HZ if ARCH_AT91
@@ -1280,7 +1311,7 @@
 
 config THUMB2_KERNEL
 	bool "Compile the kernel in Thumb-2 mode"
-	depends on CPU_V7 && EXPERIMENTAL
+	depends on CPU_V7 && !CPU_V6 && EXPERIMENTAL
 	select AEABI
 	select ARM_ASM_UNIFIED
 	help
@@ -1477,6 +1508,20 @@
 	  However, if the CPU data cache is using a write-allocate mode,
 	  this option is unlikely to provide any performance gain.
 
+config SECCOMP
+	bool
+	prompt "Enable seccomp to safely compute untrusted bytecode"
+	---help---
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
 config CC_STACKPROTECTOR
 	bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
 	help
@@ -1623,6 +1668,12 @@
 
 source "drivers/cpufreq/Kconfig"
 
+config CPU_FREQ_IMX
+	tristate "CPUfreq driver for i.MX CPUs"
+	depends on ARCH_MXC && CPU_FREQ
+	help
+	  This enables the CPUfreq driver for i.MX CPUs.
+
 config CPU_FREQ_SA1100
 	bool
 
@@ -1708,7 +1759,7 @@
 
 config FPE_NWFPE
 	bool "NWFPE math emulation"
-	depends on !AEABI || OABI_COMPAT
+	depends on (!AEABI || OABI_COMPAT) && !THUMB2_KERNEL
 	---help---
 	  Say Y to include the NWFPE floating point emulator in the kernel.
 	  This is necessary to run most binaries. Linux does not currently
diff -druN linux-libre-2.6.36-gnu/arch/arm/Kconfig.debug linux-libre-2.6.37-gnu/arch/arm/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/arm/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,20 @@
 
 source "lib/Kconfig.debug"
 
+config STRICT_DEVMEM
+	bool "Filter access to /dev/mem"
+	depends on MMU
+	---help---
+	  If this option is disabled, you allow userspace (root) access to all
+	  of memory, including kernel and userspace memory. Accidental
+	  access to this is obviously disastrous, but specific access can
+	  be used by people debugging the kernel.
+
+	  If this option is switched on, the /dev/mem file only allows
+	  userspace access to memory mapped peripherals.
+
+          If in doubt, say Y.
+
 # RMK wants arm kernels compiled with frame pointers or stack unwinding.
 # If you know what you are doing and are willing to live without stack
 # traces, you can get a slightly smaller kernel by setting this option to
@@ -27,6 +41,11 @@
 	  the performance is not affected. Currently, this feature
 	  only works with EABI compilers. If unsure say Y.
 
+config OLD_MCOUNT
+	bool
+	depends on FUNCTION_TRACER && FRAME_POINTER
+	default y
+
 config DEBUG_USER
 	bool "Verbose user fault messages"
 	help
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/armksyms.c linux-libre-2.6.37-gnu/arch/arm/kernel/armksyms.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/armksyms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/armksyms.c	2011-01-04 19:50:19.000000000 -0500
@@ -165,6 +165,8 @@
 #endif
 
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_OLD_MCOUNT
 EXPORT_SYMBOL(mcount);
+#endif
 EXPORT_SYMBOL(__gnu_mcount_nc);
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/arm/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -102,8 +102,6 @@
   DEFINE(SIZEOF_MACHINE_DESC,	sizeof(struct machine_desc));
   DEFINE(MACHINFO_TYPE,		offsetof(struct machine_desc, nr));
   DEFINE(MACHINFO_NAME,		offsetof(struct machine_desc, name));
-  DEFINE(MACHINFO_PHYSIO,	offsetof(struct machine_desc, phys_io));
-  DEFINE(MACHINFO_PGOFFIO,	offsetof(struct machine_desc, io_pg_offst));
   BLANK();
   DEFINE(PROC_INFO_SZ,		sizeof(struct proc_info_list));
   DEFINE(PROCINFO_INITFUNC,	offsetof(struct proc_info_list, __cpu_flush));
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/debug.S linux-libre-2.6.37-gnu/arch/arm/kernel/debug.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/debug.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/debug.S	2011-01-04 19:50:19.000000000 -0500
@@ -22,11 +22,11 @@
 #if defined(CONFIG_DEBUG_ICEDCC)
 		@@ debug using ARM EmbeddedICE DCC channel
 
-#if defined(CONFIG_CPU_V6)
-
-		.macro	addruart, rx, tmp
+		.macro	addruart, rp, rv
 		.endm
 
+#if defined(CONFIG_CPU_V6)
+
 		.macro	senduart, rd, rx
 		mcr	p14, 0, \rd, c0, c5, 0
 		.endm
@@ -51,9 +51,6 @@
 
 #elif defined(CONFIG_CPU_V7)
 
-		.macro	addruart, rx, tmp
-		.endm
-
 		.macro	senduart, rd, rx
 		mcr	p14, 0, \rd, c0, c5, 0
 		.endm
@@ -71,9 +68,6 @@
 
 #elif defined(CONFIG_CPU_XSCALE)
 
-		.macro	addruart, rx, tmp
-		.endm
-
 		.macro	senduart, rd, rx
 		mcr	p14, 0, \rd, c8, c0, 0
 		.endm
@@ -98,9 +92,6 @@
 
 #else
 
-		.macro	addruart, rx, tmp
-		.endm
-
 		.macro	senduart, rd, rx
 		mcr	p14, 0, \rd, c1, c0, 0
 		.endm
@@ -130,6 +121,22 @@
 #include <mach/debug-macro.S>
 #endif	/* CONFIG_DEBUG_ICEDCC */
 
+#ifdef CONFIG_MMU
+		.macro	addruart_current, rx, tmp1, tmp2
+		addruart	\tmp1, \tmp2
+		mrc		p15, 0, \rx, c1, c0
+		tst		\rx, #1
+		moveq		\rx, \tmp1
+		movne		\rx, \tmp2
+		.endm
+
+#else /* !CONFIG_MMU */
+		.macro	addruart_current, rx, tmp1, tmp2
+		addruart	\rx, \tmp1
+		.endm
+
+#endif /* CONFIG_MMU */
+
 /*
  * Useful debugging routines
  */
@@ -164,7 +171,7 @@
 		.ltorg
 
 ENTRY(printascii)
-		addruart r3, r1
+		addruart_current r3, r1, r2
 		b	2f
 1:		waituart r2, r3
 		senduart r1, r3
@@ -180,7 +187,7 @@
 ENDPROC(printascii)
 
 ENTRY(printch)
-		addruart r3, r1
+		addruart_current r3, r1, r2
 		mov	r1, r0
 		mov	r0, #0
 		b	1b
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/entry-armv.S linux-libre-2.6.37-gnu/arch/arm/kernel/entry-armv.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/entry-armv.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/entry-armv.S	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,8 @@
 	 * this macro assumes that irqstat (r6) and base (r5) are
 	 * preserved from get_irqnr_and_base above
 	 */
-	test_for_ipi r0, r6, r5, lr
+	ALT_SMP(test_for_ipi r0, r6, r5, lr)
+	ALT_UP_B(9997f)
 	movne	r0, sp
 	adrne	lr, BSYM(1b)
 	bne	do_IPI
@@ -57,6 +58,7 @@
 	adrne	lr, BSYM(1b)
 	bne	do_local_timer
 #endif
+9997:
 #endif
 
 	.endm
@@ -909,7 +911,7 @@
 	 * A special ghost syscall is used for that (see traps.c).
 	 */
 	stmfd	sp!, {r7, lr}
-	ldr	r7, =1f			@ it's 20 bits
+	ldr	r7, 1f			@ it's 20 bits
 	swi	__ARM_NR_cmpxchg
 	ldmfd	sp!, {r7, pc}
 1:	.word	__ARM_NR_cmpxchg
@@ -965,11 +967,8 @@
 	beq	1b
 	rsbs	r0, r3, #0
 	/* beware -- each __kuser slot must be 8 instructions max */
-#ifdef CONFIG_SMP
-	b	__kuser_memory_barrier
-#else
-	usr_ret	lr
-#endif
+	ALT_SMP(b	__kuser_memory_barrier)
+	ALT_UP(usr_ret	lr)
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/entry-common.S linux-libre-2.6.37-gnu/arch/arm/kernel/entry-common.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/entry-common.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/entry-common.S	2011-01-04 19:50:19.000000000 -0500
@@ -29,6 +29,9 @@
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	bne	fast_work_pending
+#if defined(CONFIG_IRQSOFF_TRACER)
+	asm_trace_hardirqs_on
+#endif
 
 	/* perform architecture specific actions before user return */
 	arch_ret_to_user r1, lr
@@ -65,6 +68,9 @@
 	tst	r1, #_TIF_WORK_MASK
 	bne	work_pending
 no_work_pending:
+#if defined(CONFIG_IRQSOFF_TRACER)
+	asm_trace_hardirqs_on
+#endif
 	/* perform architecture specific actions before user return */
 	arch_ret_to_user r1, lr
 
@@ -129,30 +135,58 @@
  * clobber the ip register.  This is OK because the ARM calling convention
  * allows it to be clobbered in subroutines and doesn't use it to hold
  * parameters.)
+ *
+ * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0"
+ * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see
+ * arch/arm/kernel/ftrace.c).
  */
+
+#ifndef CONFIG_OLD_MCOUNT
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
+#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
+#endif
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(mcount)
+ENTRY(__gnu_mcount_nc)
+	mov	ip, lr
+	ldmia	sp!, {lr}
+	mov	pc, ip
+ENDPROC(__gnu_mcount_nc)
+
+ENTRY(ftrace_caller)
 	stmdb	sp!, {r0-r3, lr}
 	mov	r0, lr
 	sub	r0, r0, #MCOUNT_INSN_SIZE
+	ldr	r1, [sp, #20]
 
-	.globl mcount_call
-mcount_call:
+	.global	ftrace_call
+ftrace_call:
 	bl	ftrace_stub
-	ldr	lr, [fp, #-4]			@ restore lr
-	ldmia	sp!, {r0-r3, pc}
+	ldmia	sp!, {r0-r3, ip, lr}
+	mov	pc, ip
+ENDPROC(ftrace_caller)
 
-ENTRY(ftrace_caller)
+#ifdef CONFIG_OLD_MCOUNT
+ENTRY(mcount)
+	stmdb	sp!, {lr}
+	ldr	lr, [fp, #-4]
+	ldmia	sp!, {pc}
+ENDPROC(mcount)
+
+ENTRY(ftrace_caller_old)
 	stmdb	sp!, {r0-r3, lr}
 	ldr	r1, [fp, #-4]
 	mov	r0, lr
 	sub	r0, r0, #MCOUNT_INSN_SIZE
 
-	.globl ftrace_call
-ftrace_call:
+	.globl ftrace_call_old
+ftrace_call_old:
 	bl	ftrace_stub
 	ldr	lr, [fp, #-4]			@ restore lr
 	ldmia	sp!, {r0-r3, pc}
+ENDPROC(ftrace_caller_old)
+#endif
 
 #else
 
@@ -160,7 +194,7 @@
 	stmdb	sp!, {r0-r3, lr}
 	ldr	r0, =ftrace_trace_function
 	ldr	r2, [r0]
-	adr	r0, ftrace_stub
+	adr	r0, .Lftrace_stub
 	cmp	r0, r2
 	bne	gnu_trace
 	ldmia	sp!, {r0-r3, ip, lr}
@@ -170,11 +204,19 @@
 	ldr	r1, [sp, #20]			@ lr of instrumented routine
 	mov	r0, lr
 	sub	r0, r0, #MCOUNT_INSN_SIZE
-	mov	lr, pc
+	adr	lr, BSYM(1f)
 	mov	pc, r2
+1:
 	ldmia	sp!, {r0-r3, ip, lr}
 	mov	pc, ip
+ENDPROC(__gnu_mcount_nc)
 
+#ifdef CONFIG_OLD_MCOUNT
+/*
+ * This is under an ifdef in order to force link-time errors for people trying
+ * to build with !FRAME_POINTER with a GCC which doesn't use the new-style
+ * mcount.
+ */
 ENTRY(mcount)
 	stmdb	sp!, {r0-r3, lr}
 	ldr	r0, =ftrace_trace_function
@@ -193,12 +235,15 @@
 	mov	pc, r2
 	ldr	lr, [fp, #-4]			@ restore lr
 	ldmia	sp!, {r0-r3, pc}
+ENDPROC(mcount)
+#endif
 
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
-	.globl ftrace_stub
-ftrace_stub:
+ENTRY(ftrace_stub)
+.Lftrace_stub:
 	mov	pc, lr
+ENDPROC(ftrace_stub)
 
 #endif /* CONFIG_FUNCTION_TRACER */
 
@@ -295,7 +340,6 @@
 
 	get_thread_info tsk
 	adr	tbl, sys_call_table		@ load syscall table pointer
-	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
 
 #if defined(CONFIG_OABI_COMPAT)
 	/*
@@ -312,8 +356,20 @@
 	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
 #endif
 
+	ldr	r10, [tsk, #TI_FLAGS]		@ check for syscall tracing
 	stmdb	sp!, {r4, r5}			@ push fifth and sixth args
-	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
+
+#ifdef CONFIG_SECCOMP
+	tst	r10, #_TIF_SECCOMP
+	beq	1f
+	mov	r0, scno
+	bl	__secure_computing	
+	add	r0, sp, #S_R0 + S_OFF		@ pointer to regs
+	ldmia	r0, {r0 - r3}			@ have to reload r0 - r3
+1:
+#endif
+
+	tst	r10, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
 	bne	__sys_trace
 
 	cmp	scno, #NR_syscalls		@ check upper syscall limit
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/etm.c linux-libre-2.6.37-gnu/arch/arm/kernel/etm.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/etm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/etm.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,21 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shishkin");
 
+/*
+ * ETM tracer state
+ */
+struct tracectx {
+	unsigned int	etb_bufsz;
+	void __iomem	*etb_regs;
+	void __iomem	*etm_regs;
+	unsigned long	flags;
+	int		ncmppairs;
+	int		etm_portsz;
+	struct device	*dev;
+	struct clk	*emu_clk;
+	struct mutex	mutex;
+};
+
 static struct tracectx tracer;
 
 static inline bool trace_isrunning(struct tracectx *t)
@@ -314,6 +329,7 @@
 	.read = etb_read,
 	.open = etb_open,
 	.release = etb_release,
+	.llseek = no_llseek,
 };
 
 static struct miscdevice etb_miscdev = {
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/ftrace.c linux-libre-2.6.37-gnu/arch/arm/kernel/ftrace.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/ftrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/ftrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,102 +2,194 @@
  * Dynamic function tracing support.
  *
  * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com>
+ * Copyright (C) 2010 Rabin Vincent <rabin@rab.in>
  *
  * For licencing details, see COPYING.
  *
  * Defines low-level handling of mcount calls when the kernel
  * is compiled with the -pg flag. When using dynamic ftrace, the
- * mcount call-sites get patched lazily with NOP till they are
- * enabled. All code mutation routines here take effect atomically.
+ * mcount call-sites get patched with NOP till they are enabled.
+ * All code mutation routines here are called under stop_machine().
  */
 
 #include <linux/ftrace.h>
+#include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
 #include <asm/ftrace.h>
 
-#define PC_OFFSET      8
-#define BL_OPCODE      0xeb000000
-#define BL_OFFSET_MASK 0x00ffffff
+#ifdef CONFIG_THUMB2_KERNEL
+#define	NOP		0xeb04f85d	/* pop.w {lr} */
+#else
+#define	NOP		0xe8bd4000	/* pop {lr} */
+#endif
 
-static unsigned long bl_insn;
-static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */
+#ifdef CONFIG_OLD_MCOUNT
+#define OLD_MCOUNT_ADDR	((unsigned long) mcount)
+#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old)
 
-unsigned char *ftrace_nop_replace(void)
+#define	OLD_NOP		0xe1a00000	/* mov r0, r0 */
+
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 {
-	return (char *)&NOP;
+	return rec->arch.old_mcount ? OLD_NOP : NOP;
+}
+
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+	if (!rec->arch.old_mcount)
+		return addr;
+
+	if (addr == MCOUNT_ADDR)
+		addr = OLD_MCOUNT_ADDR;
+	else if (addr == FTRACE_ADDR)
+		addr = OLD_FTRACE_ADDR;
+
+	return addr;
+}
+#else
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
+{
+	return NOP;
+}
+
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+	return addr;
 }
+#endif
 
 /* construct a branch (BL) instruction to addr */
-unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr)
+#ifdef CONFIG_THUMB2_KERNEL
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
+	unsigned long s, j1, j2, i1, i2, imm10, imm11;
+	unsigned long first, second;
 	long offset;
 
-	offset = (long)addr - (long)(pc + PC_OFFSET);
+	offset = (long)addr - (long)(pc + 4);
+	if (offset < -16777216 || offset > 16777214) {
+		WARN_ON_ONCE(1);
+		return 0;
+	}
+
+	s	= (offset >> 24) & 0x1;
+	i1	= (offset >> 23) & 0x1;
+	i2	= (offset >> 22) & 0x1;
+	imm10	= (offset >> 12) & 0x3ff;
+	imm11	= (offset >>  1) & 0x7ff;
+
+	j1 = (!i1) ^ s;
+	j2 = (!i2) ^ s;
+
+	first = 0xf000 | (s << 10) | imm10;
+	second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11;
+
+	return (second << 16) | first;
+}
+#else
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
+{
+	long offset;
+
+	offset = (long)addr - (long)(pc + 8);
 	if (unlikely(offset < -33554432 || offset > 33554428)) {
 		/* Can't generate branches that far (from ARM ARM). Ftrace
 		 * doesn't generate branches outside of kernel text.
 		 */
 		WARN_ON_ONCE(1);
-		return NULL;
+		return 0;
 	}
-	offset = (offset >> 2) & BL_OFFSET_MASK;
-	bl_insn = BL_OPCODE | offset;
-	return (unsigned char *)&bl_insn;
-}
 
-int ftrace_modify_code(unsigned long pc, unsigned char *old_code,
-		       unsigned char *new_code)
-{
-	unsigned long err = 0, replaced = 0, old, new;
+	offset = (offset >> 2) & 0x00ffffff;
 
-	old = *(unsigned long *)old_code;
-	new = *(unsigned long *)new_code;
+	return 0xeb000000 | offset;
+}
+#endif
 
-	__asm__ __volatile__ (
-		"1:  ldr    %1, [%2]  \n"
-		"    cmp    %1, %4    \n"
-		"2:  streq  %3, [%2]  \n"
-		"    cmpne  %1, %3    \n"
-		"    movne  %0, #2    \n"
-		"3:\n"
+static int ftrace_modify_code(unsigned long pc, unsigned long old,
+			      unsigned long new)
+{
+	unsigned long replaced;
 
-		".pushsection .fixup, \"ax\"\n"
-		"4:  mov  %0, #1  \n"
-		"    b    3b      \n"
-		".popsection\n"
+	if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+		return -EFAULT;
 
-		".pushsection __ex_table, \"a\"\n"
-		"    .long 1b, 4b \n"
-		"    .long 2b, 4b \n"
-		".popsection\n"
+	if (replaced != old)
+		return -EINVAL;
 
-		: "=r"(err), "=r"(replaced)
-		: "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced)
-		: "memory");
+	if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
+		return -EPERM;
 
-	if (!err && (replaced == old))
-		flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
+	flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
 
-	return err;
+	return 0;
 }
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-	int ret;
 	unsigned long pc, old;
-	unsigned char *new;
+	unsigned long new;
+	int ret;
 
 	pc = (unsigned long)&ftrace_call;
 	memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
 	new = ftrace_call_replace(pc, (unsigned long)func);
-	ret = ftrace_modify_code(pc, (unsigned char *)&old, new);
+
+	ret = ftrace_modify_code(pc, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+	if (!ret) {
+		pc = (unsigned long)&ftrace_call_old;
+		memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
+		new = ftrace_call_replace(pc, (unsigned long)func);
+
+		ret = ftrace_modify_code(pc, old, new);
+	}
+#endif
+
+	return ret;
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned long new, old;
+	unsigned long ip = rec->ip;
+
+	old = ftrace_nop_replace(rec);
+	new = ftrace_call_replace(ip, adjust_address(rec, addr));
+
+	return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_nop(struct module *mod,
+		    struct dyn_ftrace *rec, unsigned long addr)
+{
+	unsigned long ip = rec->ip;
+	unsigned long old;
+	unsigned long new;
+	int ret;
+
+	old = ftrace_call_replace(ip, adjust_address(rec, addr));
+	new = ftrace_nop_replace(rec);
+	ret = ftrace_modify_code(ip, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+	if (ret == -EINVAL && addr == MCOUNT_ADDR) {
+		rec->arch.old_mcount = true;
+
+		old = ftrace_call_replace(ip, adjust_address(rec, addr));
+		new = ftrace_nop_replace(rec);
+		ret = ftrace_modify_code(ip, old, new);
+	}
+#endif
+
 	return ret;
 }
 
-/* run from ftrace_init with irqs disabled */
 int __init ftrace_dyn_arch_init(void *data)
 {
-	ftrace_mcount_set(data);
+	*(unsigned long *)data = 0;
+
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/head-common.S linux-libre-2.6.37-gnu/arch/arm/kernel/head-common.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/head-common.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/head-common.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,55 +15,6 @@
 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
 #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
 
-	.align	2
-	.type	__switch_data, %object
-__switch_data:
-	.long	__mmap_switched
-	.long	__data_loc			@ r4
-	.long	_data				@ r5
-	.long	__bss_start			@ r6
-	.long	_end				@ r7
-	.long	processor_id			@ r4
-	.long	__machine_arch_type		@ r5
-	.long	__atags_pointer			@ r6
-	.long	cr_alignment			@ r7
-	.long	init_thread_union + THREAD_START_SP @ sp
-
-/*
- * The following fragment of code is executed with the MMU on in MMU mode,
- * and uses absolute addresses; this is not position independent.
- *
- *  r0  = cp#15 control register
- *  r1  = machine ID
- *  r2  = atags pointer
- *  r9  = processor ID
- */
-__mmap_switched:
-	adr	r3, __switch_data + 4
-
-	ldmia	r3!, {r4, r5, r6, r7}
-	cmp	r4, r5				@ Copy data segment if needed
-1:	cmpne	r5, r6
-	ldrne	fp, [r4], #4
-	strne	fp, [r5], #4
-	bne	1b
-
-	mov	fp, #0				@ Clear BSS (and zero fp)
-1:	cmp	r6, r7
-	strcc	fp, [r6],#4
-	bcc	1b
-
- ARM(	ldmia	r3, {r4, r5, r6, r7, sp})
- THUMB(	ldmia	r3, {r4, r5, r6, r7}	)
- THUMB(	ldr	sp, [r3, #16]		)
-	str	r9, [r4]			@ Save processor ID
-	str	r1, [r5]			@ Save machine type
-	str	r2, [r6]			@ Save atags pointer
-	bic	r4, r0, #CR_A			@ Clear 'A' bit
-	stmia	r7, {r0, r4}			@ Save control register values
-	b	start_kernel
-ENDPROC(__mmap_switched)
-
 /*
  * Exception handling.  Something went wrong and we can't proceed.  We
  * ought to tell the user, but since we don't have any guarantee that
@@ -73,21 +24,7 @@
  * and hope for the best (useful if bootloader fails to pass a proper
  * machine ID for example).
  */
-__error_p:
-#ifdef CONFIG_DEBUG_LL
-	adr	r0, str_p1
-	bl	printascii
-	mov	r0, r9
-	bl	printhex8
-	adr	r0, str_p2
-	bl	printascii
-	b	__error
-str_p1:	.asciz	"\nError: unrecognized/unsupported processor variant (0x"
-str_p2:	.asciz	").\n"
-	.align
-#endif
-ENDPROC(__error_p)
-
+	__HEAD
 __error_a:
 #ifdef CONFIG_DEBUG_LL
 	mov	r4, r1				@ preserve machine ID
@@ -97,7 +34,7 @@
 	bl	printhex8
 	adr	r0, str_a2
 	bl	printascii
-	adr	r3, 4f
+	adr	r3, __lookup_machine_type_data
 	ldmia	r3, {r4, r5, r6}		@ get machine desc list
 	sub	r4, r3, r4			@ get offset between virt&phys
 	add	r5, r5, r4			@ convert virt addresses to
@@ -125,78 +62,6 @@
 	.align
 #endif
 
-__error:
-#ifdef CONFIG_ARCH_RPC
-/*
- * Turn the screen red on a error - RiscPC only.
- */
-	mov	r0, #0x02000000
-	mov	r3, #0x11
-	orr	r3, r3, r3, lsl #8
-	orr	r3, r3, r3, lsl #16
-	str	r3, [r0], #4
-	str	r3, [r0], #4
-	str	r3, [r0], #4
-	str	r3, [r0], #4
-#endif
-1:	mov	r0, r0
-	b	1b
-ENDPROC(__error)
-
-
-/*
- * Read processor ID register (CP#15, CR0), and look up in the linker-built
- * supported processor list.  Note that we can't use the absolute addresses
- * for the __proc_info lists since we aren't running with the MMU on
- * (and therefore, we are not in the correct address space).  We have to
- * calculate the offset.
- *
- *	r9 = cpuid
- * Returns:
- *	r3, r4, r6 corrupted
- *	r5 = proc_info pointer in physical address space
- *	r9 = cpuid (preserved)
- */
-__lookup_processor_type:
-	adr	r3, 3f
-	ldmia	r3, {r5 - r7}
-	add	r3, r3, #8
-	sub	r3, r3, r7			@ get offset between virt&phys
-	add	r5, r5, r3			@ convert virt addresses to
-	add	r6, r6, r3			@ physical address space
-1:	ldmia	r5, {r3, r4}			@ value, mask
-	and	r4, r4, r9			@ mask wanted bits
-	teq	r3, r4
-	beq	2f
-	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
-	cmp	r5, r6
-	blo	1b
-	mov	r5, #0				@ unknown processor
-2:	mov	pc, lr
-ENDPROC(__lookup_processor_type)
-
-/*
- * This provides a C-API version of the above function.
- */
-ENTRY(lookup_processor_type)
-	stmfd	sp!, {r4 - r7, r9, lr}
-	mov	r9, r0
-	bl	__lookup_processor_type
-	mov	r0, r5
-	ldmfd	sp!, {r4 - r7, r9, pc}
-ENDPROC(lookup_processor_type)
-
-/*
- * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
- * more information about the __proc_info and __arch_info structures.
- */
-	.align	2
-3:	.long	__proc_info_begin
-	.long	__proc_info_end
-4:	.long	.
-	.long	__arch_info_begin
-	.long	__arch_info_end
-
 /*
  * Lookup machine architecture in the linker-build list of architectures.
  * Note that we can't use the absolute addresses for the __arch_info
@@ -209,7 +74,7 @@
  *  r5 = mach_info pointer in physical address space
  */
 __lookup_machine_type:
-	adr	r3, 4b
+	adr	r3, __lookup_machine_type_data
 	ldmia	r3, {r4, r5, r6}
 	sub	r3, r3, r4			@ get offset between virt&phys
 	add	r5, r5, r3			@ convert virt addresses to
@@ -225,15 +90,16 @@
 ENDPROC(__lookup_machine_type)
 
 /*
- * This provides a C-API version of the above function.
+ * Look in arch/arm/kernel/arch.[ch] for information about the
+ * __arch_info structures.
  */
-ENTRY(lookup_machine_type)
-	stmfd	sp!, {r4 - r6, lr}
-	mov	r1, r0
-	bl	__lookup_machine_type
-	mov	r0, r5
-	ldmfd	sp!, {r4 - r6, pc}
-ENDPROC(lookup_machine_type)
+	.align	2
+	.type	__lookup_machine_type_data, %object
+__lookup_machine_type_data:
+	.long	.
+	.long	__arch_info_begin
+	.long	__arch_info_end
+	.size	__lookup_machine_type_data, . - __lookup_machine_type_data
 
 /* Determine validity of the r2 atags pointer.  The heuristic requires
  * that the pointer be aligned, in the first 16k of physical RAM and
@@ -265,3 +131,150 @@
 1:	mov	r2, #0
 	mov	pc, lr
 ENDPROC(__vet_atags)
+
+/*
+ * The following fragment of code is executed with the MMU on in MMU mode,
+ * and uses absolute addresses; this is not position independent.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r9  = processor ID
+ */
+	__INIT
+__mmap_switched:
+	adr	r3, __mmap_switched_data
+
+	ldmia	r3!, {r4, r5, r6, r7}
+	cmp	r4, r5				@ Copy data segment if needed
+1:	cmpne	r5, r6
+	ldrne	fp, [r4], #4
+	strne	fp, [r5], #4
+	bne	1b
+
+	mov	fp, #0				@ Clear BSS (and zero fp)
+1:	cmp	r6, r7
+	strcc	fp, [r6],#4
+	bcc	1b
+
+ ARM(	ldmia	r3, {r4, r5, r6, r7, sp})
+ THUMB(	ldmia	r3, {r4, r5, r6, r7}	)
+ THUMB(	ldr	sp, [r3, #16]		)
+	str	r9, [r4]			@ Save processor ID
+	str	r1, [r5]			@ Save machine type
+	str	r2, [r6]			@ Save atags pointer
+	bic	r4, r0, #CR_A			@ Clear 'A' bit
+	stmia	r7, {r0, r4}			@ Save control register values
+	b	start_kernel
+ENDPROC(__mmap_switched)
+
+	.align	2
+	.type	__mmap_switched_data, %object
+__mmap_switched_data:
+	.long	__data_loc			@ r4
+	.long	_sdata				@ r5
+	.long	__bss_start			@ r6
+	.long	_end				@ r7
+	.long	processor_id			@ r4
+	.long	__machine_arch_type		@ r5
+	.long	__atags_pointer			@ r6
+	.long	cr_alignment			@ r7
+	.long	init_thread_union + THREAD_START_SP @ sp
+	.size	__mmap_switched_data, . - __mmap_switched_data
+
+/*
+ * This provides a C-API version of __lookup_machine_type
+ */
+ENTRY(lookup_machine_type)
+	stmfd	sp!, {r4 - r6, lr}
+	mov	r1, r0
+	bl	__lookup_machine_type
+	mov	r0, r5
+	ldmfd	sp!, {r4 - r6, pc}
+ENDPROC(lookup_machine_type)
+
+/*
+ * This provides a C-API version of __lookup_processor_type
+ */
+ENTRY(lookup_processor_type)
+	stmfd	sp!, {r4 - r6, r9, lr}
+	mov	r9, r0
+	bl	__lookup_processor_type
+	mov	r0, r5
+	ldmfd	sp!, {r4 - r6, r9, pc}
+ENDPROC(lookup_processor_type)
+
+/*
+ * Read processor ID register (CP#15, CR0), and look up in the linker-built
+ * supported processor list.  Note that we can't use the absolute addresses
+ * for the __proc_info lists since we aren't running with the MMU on
+ * (and therefore, we are not in the correct address space).  We have to
+ * calculate the offset.
+ *
+ *	r9 = cpuid
+ * Returns:
+ *	r3, r4, r6 corrupted
+ *	r5 = proc_info pointer in physical address space
+ *	r9 = cpuid (preserved)
+ */
+	__CPUINIT
+__lookup_processor_type:
+	adr	r3, __lookup_processor_type_data
+	ldmia	r3, {r4 - r6}
+	sub	r3, r3, r4			@ get offset between virt&phys
+	add	r5, r5, r3			@ convert virt addresses to
+	add	r6, r6, r3			@ physical address space
+1:	ldmia	r5, {r3, r4}			@ value, mask
+	and	r4, r4, r9			@ mask wanted bits
+	teq	r3, r4
+	beq	2f
+	add	r5, r5, #PROC_INFO_SZ		@ sizeof(proc_info_list)
+	cmp	r5, r6
+	blo	1b
+	mov	r5, #0				@ unknown processor
+2:	mov	pc, lr
+ENDPROC(__lookup_processor_type)
+
+/*
+ * Look in <asm/procinfo.h> for information about the __proc_info structure.
+ */
+	.align	2
+	.type	__lookup_processor_type_data, %object
+__lookup_processor_type_data:
+	.long	.
+	.long	__proc_info_begin
+	.long	__proc_info_end
+	.size	__lookup_processor_type_data, . - __lookup_processor_type_data
+
+__error_p:
+#ifdef CONFIG_DEBUG_LL
+	adr	r0, str_p1
+	bl	printascii
+	mov	r0, r9
+	bl	printhex8
+	adr	r0, str_p2
+	bl	printascii
+	b	__error
+str_p1:	.asciz	"\nError: unrecognized/unsupported processor variant (0x"
+str_p2:	.asciz	").\n"
+	.align
+#endif
+ENDPROC(__error_p)
+
+__error:
+#ifdef CONFIG_ARCH_RPC
+/*
+ * Turn the screen red on a error - RiscPC only.
+ */
+	mov	r0, #0x02000000
+	mov	r3, #0x11
+	orr	r3, r3, r3, lsl #8
+	orr	r3, r3, r3, lsl #16
+	str	r3, [r0], #4
+	str	r3, [r0], #4
+	str	r3, [r0], #4
+	str	r3, [r0], #4
+#endif
+1:	mov	r0, r0
+	b	1b
+ENDPROC(__error)
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/head-nommu.S linux-libre-2.6.37-gnu/arch/arm/kernel/head-nommu.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/head-nommu.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/head-nommu.S	2011-01-04 19:50:19.000000000 -0500
@@ -48,8 +48,6 @@
 	movs	r8, r5				@ invalid machine (r5=0)?
 	beq	__error_a			@ yes, error 'a'
 
-	ldr	r13, __switch_data		@ address to jump to after
-						@ the initialization is done
 	adr	lr, BSYM(__after_proc_init)	@ return (PIC) address
  ARM(	add	pc, r10, #PROCINFO_INITFUNC	)
  THUMB(	add	r12, r10, #PROCINFO_INITFUNC	)
@@ -87,8 +85,7 @@
 	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
 #endif /* CONFIG_CPU_CP15 */
 
-	mov	r3, r13
-	mov	pc, r3				@ clear the BSS and jump
+	b	__mmap_switched			@ clear the BSS and jump
 						@ to start_kernel
 ENDPROC(__after_proc_init)
 	.ltorg
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/head.S linux-libre-2.6.37-gnu/arch/arm/kernel/head.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,10 @@
 #include <asm/thread_info.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_DEBUG_LL
+#include <mach/debug-macro.S>
+#endif
+
 #if (PHYS_OFFSET & 0x001fffff)
 #error "PHYS_OFFSET must be at an even 2MiB boundary!"
 #endif
@@ -81,11 +85,16 @@
 	mrc	p15, 0, r9, c0, c0		@ get processor id
 	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
 	movs	r10, r5				@ invalid processor (r5=0)?
+ THUMB( it	eq )		@ force fixup-able long branch encoding
 	beq	__error_p			@ yes, error 'p'
 	bl	__lookup_machine_type		@ r5=machinfo
 	movs	r8, r5				@ invalid machine (r5=0)?
+ THUMB( it	eq )		@ force fixup-able long branch encoding
 	beq	__error_a			@ yes, error 'a'
 	bl	__vet_atags
+#ifdef CONFIG_SMP_ON_UP
+	bl	__fixup_smp
+#endif
 	bl	__create_page_tables
 
 	/*
@@ -95,113 +104,15 @@
 	 * above.  On return, the CPU will be ready for the MMU to be
 	 * turned on, and r0 will hold the CPU control register value.
 	 */
-	ldr	r13, __switch_data		@ address to jump to after
+	ldr	r13, =__mmap_switched		@ address to jump to after
 						@ mmu has been enabled
-	adr	lr, BSYM(__enable_mmu)		@ return (PIC) address
+	adr	lr, BSYM(1f)			@ return (PIC) address
  ARM(	add	pc, r10, #PROCINFO_INITFUNC	)
  THUMB(	add	r12, r10, #PROCINFO_INITFUNC	)
  THUMB(	mov	pc, r12				)
+1:	b	__enable_mmu
 ENDPROC(stext)
-
-#if defined(CONFIG_SMP)
-ENTRY(secondary_startup)
-	/*
-	 * Common entry point for secondary CPUs.
-	 *
-	 * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
-	 * the processor type - there is no need to check the machine type
-	 * as it has already been validated by the primary processor.
-	 */
-	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
-	mrc	p15, 0, r9, c0, c0		@ get processor id
-	bl	__lookup_processor_type
-	movs	r10, r5				@ invalid processor?
-	moveq	r0, #'p'			@ yes, error 'p'
-	beq	__error
-
-	/*
-	 * Use the page tables supplied from  __cpu_up.
-	 */
-	adr	r4, __secondary_data
-	ldmia	r4, {r5, r7, r12}		@ address to jump to after
-	sub	r4, r4, r5			@ mmu has been enabled
-	ldr	r4, [r7, r4]			@ get secondary_data.pgdir
-	adr	lr, BSYM(__enable_mmu)		@ return address
-	mov	r13, r12			@ __secondary_switched address
- ARM(	add	pc, r10, #PROCINFO_INITFUNC	) @ initialise processor
-						  @ (return control reg)
- THUMB(	add	r12, r10, #PROCINFO_INITFUNC	)
- THUMB(	mov	pc, r12				)
-ENDPROC(secondary_startup)
-
-	/*
-	 * r6  = &secondary_data
-	 */
-ENTRY(__secondary_switched)
-	ldr	sp, [r7, #4]			@ get secondary_data.stack
-	mov	fp, #0
-	b	secondary_start_kernel
-ENDPROC(__secondary_switched)
-
-	.type	__secondary_data, %object
-__secondary_data:
-	.long	.
-	.long	secondary_data
-	.long	__secondary_switched
-#endif /* defined(CONFIG_SMP) */
-
-
-
-/*
- * Setup common bits before finally enabling the MMU.  Essentially
- * this is just loading the page table pointer and domain access
- * registers.
- */
-__enable_mmu:
-#ifdef CONFIG_ALIGNMENT_TRAP
-	orr	r0, r0, #CR_A
-#else
-	bic	r0, r0, #CR_A
-#endif
-#ifdef CONFIG_CPU_DCACHE_DISABLE
-	bic	r0, r0, #CR_C
-#endif
-#ifdef CONFIG_CPU_BPREDICT_DISABLE
-	bic	r0, r0, #CR_Z
-#endif
-#ifdef CONFIG_CPU_ICACHE_DISABLE
-	bic	r0, r0, #CR_I
-#endif
-	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
-		      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
-	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register
-	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
-	b	__turn_mmu_on
-ENDPROC(__enable_mmu)
-
-/*
- * Enable the MMU.  This completely changes the structure of the visible
- * memory space.  You will not be able to trace execution through this.
- * If you have an enquiry about this, *please* check the linux-arm-kernel
- * mailing list archives BEFORE sending another post to the list.
- *
- *  r0  = cp#15 control register
- *  r13 = *virtual* address to jump to upon completion
- *
- * other registers depend on the function called upon completion
- */
-	.align	5
-__turn_mmu_on:
-	mov	r0, r0
-	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
-	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
-	mov	r3, r3
-	mov	r3, r13
-	mov	pc, r3
-ENDPROC(__turn_mmu_on)
-
+	.ltorg
 
 /*
  * Setup the initial page tables.  We only setup the barest
@@ -213,7 +124,7 @@
  * r10 = procinfo
  *
  * Returns:
- *  r0, r3, r6, r7 corrupted
+ *  r0, r3, r5-r7 corrupted
  *  r4 = physical page table address
  */
 __create_page_tables:
@@ -235,20 +146,30 @@
 	ldr	r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
 
 	/*
-	 * Create identity mapping for first MB of kernel to
-	 * cater for the MMU enable.  This identity mapping
-	 * will be removed by paging_init().  We use our current program
-	 * counter to determine corresponding section base address.
+	 * Create identity mapping to cater for __enable_mmu.
+	 * This identity mapping will be removed by paging_init().
 	 */
-	mov	r6, pc
-	mov	r6, r6, lsr #20			@ start of kernel section
-	orr	r3, r7, r6, lsl #20		@ flags + kernel base
-	str	r3, [r4, r6, lsl #2]		@ identity mapping
+	adr	r0, __enable_mmu_loc
+	ldmia	r0, {r3, r5, r6}
+	sub	r0, r0, r3			@ virt->phys offset
+	add	r5, r5, r0			@ phys __enable_mmu
+	add	r6, r6, r0			@ phys __enable_mmu_end
+	mov	r5, r5, lsr #20
+	mov	r6, r6, lsr #20
+
+1:	orr	r3, r7, r5, lsl #20		@ flags + kernel base
+	str	r3, [r4, r5, lsl #2]		@ identity mapping
+	teq	r5, r6
+	addne	r5, r5, #1			@ next section
+	bne	1b
 
 	/*
 	 * Now setup the pagetables for our kernel direct
 	 * mapped region.
 	 */
+	mov	r3, pc
+	mov	r3, r3, lsr #20
+	orr	r3, r7, r3, lsl #20
 	add	r0, r4,  #(KERNEL_START & 0xff000000) >> 18
 	str	r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
 	ldr	r6, =(KERNEL_END - 1)
@@ -289,24 +210,35 @@
 	str	r6, [r0]
 
 #ifdef CONFIG_DEBUG_LL
-	ldr	r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+#ifndef CONFIG_DEBUG_ICEDCC
 	/*
 	 * Map in IO space for serial debugging.
 	 * This allows debug messages to be output
 	 * via a serial console before paging_init.
 	 */
-	ldr	r3, [r8, #MACHINFO_PGOFFIO]
+	addruart r7, r3
+
+	mov	r3, r3, lsr #20
+	mov	r3, r3, lsl #2
+
 	add	r0, r4, r3
 	rsb	r3, r3, #0x4000			@ PTRS_PER_PGD*sizeof(long)
 	cmp	r3, #0x0800			@ limit to 512MB
 	movhi	r3, #0x0800
 	add	r6, r0, r3
-	ldr	r3, [r8, #MACHINFO_PHYSIO]
-	orr	r3, r3, r7
+	mov	r3, r7, lsr #20
+	ldr	r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+	orr	r3, r7, r3, lsl #20
 1:	str	r3, [r0], #4
 	add	r3, r3, #1 << 20
 	teq	r0, r6
 	bne	1b
+
+#else /* CONFIG_DEBUG_ICEDCC */
+	/* we don't need any serial debugging mappings for ICEDCC */
+	ldr	r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+#endif /* !CONFIG_DEBUG_ICEDCC */
+
 #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
 	/*
 	 * If we're using the NetWinder or CATS, we also need to map
@@ -332,5 +264,173 @@
 	mov	pc, lr
 ENDPROC(__create_page_tables)
 	.ltorg
+	.align
+__enable_mmu_loc:
+	.long	.
+	.long	__enable_mmu
+	.long	__enable_mmu_end
+
+#if defined(CONFIG_SMP)
+	__CPUINIT
+ENTRY(secondary_startup)
+	/*
+	 * Common entry point for secondary CPUs.
+	 *
+	 * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
+	 * the processor type - there is no need to check the machine type
+	 * as it has already been validated by the primary processor.
+	 */
+	setmode	PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+	mrc	p15, 0, r9, c0, c0		@ get processor id
+	bl	__lookup_processor_type
+	movs	r10, r5				@ invalid processor?
+	moveq	r0, #'p'			@ yes, error 'p'
+ THUMB( it	eq )		@ force fixup-able long branch encoding
+	beq	__error_p
+
+	/*
+	 * Use the page tables supplied from  __cpu_up.
+	 */
+	adr	r4, __secondary_data
+	ldmia	r4, {r5, r7, r12}		@ address to jump to after
+	sub	r4, r4, r5			@ mmu has been enabled
+	ldr	r4, [r7, r4]			@ get secondary_data.pgdir
+	adr	lr, BSYM(__enable_mmu)		@ return address
+	mov	r13, r12			@ __secondary_switched address
+ ARM(	add	pc, r10, #PROCINFO_INITFUNC	) @ initialise processor
+						  @ (return control reg)
+ THUMB(	add	r12, r10, #PROCINFO_INITFUNC	)
+ THUMB(	mov	pc, r12				)
+ENDPROC(secondary_startup)
+
+	/*
+	 * r6  = &secondary_data
+	 */
+ENTRY(__secondary_switched)
+	ldr	sp, [r7, #4]			@ get secondary_data.stack
+	mov	fp, #0
+	b	secondary_start_kernel
+ENDPROC(__secondary_switched)
+
+	.align
+
+	.type	__secondary_data, %object
+__secondary_data:
+	.long	.
+	.long	secondary_data
+	.long	__secondary_switched
+#endif /* defined(CONFIG_SMP) */
+
+
+
+/*
+ * Setup common bits before finally enabling the MMU.  Essentially
+ * this is just loading the page table pointer and domain access
+ * registers.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r4  = page table pointer
+ *  r9  = processor ID
+ *  r13 = *virtual* address to jump to upon completion
+ */
+__enable_mmu:
+#ifdef CONFIG_ALIGNMENT_TRAP
+	orr	r0, r0, #CR_A
+#else
+	bic	r0, r0, #CR_A
+#endif
+#ifdef CONFIG_CPU_DCACHE_DISABLE
+	bic	r0, r0, #CR_C
+#endif
+#ifdef CONFIG_CPU_BPREDICT_DISABLE
+	bic	r0, r0, #CR_Z
+#endif
+#ifdef CONFIG_CPU_ICACHE_DISABLE
+	bic	r0, r0, #CR_I
+#endif
+	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
+		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
+		      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
+		      domain_val(DOMAIN_IO, DOMAIN_CLIENT))
+	mcr	p15, 0, r5, c3, c0, 0		@ load domain access register
+	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
+	b	__turn_mmu_on
+ENDPROC(__enable_mmu)
+
+/*
+ * Enable the MMU.  This completely changes the structure of the visible
+ * memory space.  You will not be able to trace execution through this.
+ * If you have an enquiry about this, *please* check the linux-arm-kernel
+ * mailing list archives BEFORE sending another post to the list.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r9  = processor ID
+ *  r13 = *virtual* address to jump to upon completion
+ *
+ * other registers depend on the function called upon completion
+ */
+	.align	5
+__turn_mmu_on:
+	mov	r0, r0
+	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
+	mrc	p15, 0, r3, c0, c0, 0		@ read id reg
+	mov	r3, r3
+	mov	r3, r13
+	mov	pc, r3
+__enable_mmu_end:
+ENDPROC(__turn_mmu_on)
+
+
+#ifdef CONFIG_SMP_ON_UP
+__fixup_smp:
+	mov	r7, #0x00070000
+	orr	r6, r7, #0xff000000	@ mask 0xff070000
+	orr	r7, r7, #0x41000000	@ val 0x41070000
+	and	r0, r9, r6
+	teq	r0, r7			@ ARM CPU and ARMv6/v7?
+	bne	__fixup_smp_on_up	@ no, assume UP
+
+	orr	r6, r6, #0x0000ff00
+	orr	r6, r6, #0x000000f0	@ mask 0xff07fff0
+	orr	r7, r7, #0x0000b000
+	orr	r7, r7, #0x00000020	@ val 0x4107b020
+	and	r0, r9, r6
+	teq	r0, r7			@ ARM 11MPCore?
+	moveq	pc, lr			@ yes, assume SMP
+
+	mrc	p15, 0, r0, c0, c0, 5	@ read MPIDR
+	tst	r0, #1 << 31
+	movne	pc, lr			@ bit 31 => SMP
+
+__fixup_smp_on_up:
+	adr	r0, 1f
+	ldmia	r0, {r3, r6, r7}
+	sub	r3, r0, r3
+	add	r6, r6, r3
+	add	r7, r7, r3
+2:	cmp	r6, r7
+	ldmia	r6!, {r0, r4}
+	strlo	r4, [r0, r3]
+	blo	2b
+	mov	pc, lr
+ENDPROC(__fixup_smp)
+
+	.align
+1:	.word	.
+	.word	__smpalt_begin
+	.word	__smpalt_end
+
+	.pushsection .data
+	.globl	smp_on_up
+smp_on_up:
+	ALT_SMP(.long	1)
+	ALT_UP(.long	0)
+	.popsection
+
+#endif
 
 #include "head-common.S"
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/hw_breakpoint.c linux-libre-2.6.37-gnu/arch/arm/kernel/hw_breakpoint.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/hw_breakpoint.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/hw_breakpoint.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,848 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2009, 2010 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ */
+#define pr_fmt(fmt) "hw-breakpoint: " fmt
+
+#include <linux/errno.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/current.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/kdebug.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+/* Breakpoint currently in use for each BRP. */
+static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
+
+/* Watchpoint currently in use for each WRP. */
+static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]);
+
+/* Number of BRP/WRP registers on this CPU. */
+static int core_num_brps;
+static int core_num_wrps;
+
+/* Debug architecture version. */
+static u8 debug_arch;
+
+/* Maximum supported watchpoint length. */
+static u8 max_watchpoint_len;
+
+/* Determine number of BRP registers available. */
+static int get_num_brps(void)
+{
+	u32 didr;
+	ARM_DBG_READ(c0, 0, didr);
+	return ((didr >> 24) & 0xf) + 1;
+}
+
+/* Determine number of WRP registers available. */
+static int get_num_wrps(void)
+{
+	/*
+	 * FIXME: When a watchpoint fires, the only way to work out which
+	 * watchpoint it was is by disassembling the faulting instruction
+	 * and working out the address of the memory access.
+	 *
+	 * Furthermore, we can only do this if the watchpoint was precise
+	 * since imprecise watchpoints prevent us from calculating register
+	 * based addresses.
+	 *
+	 * For the time being, we only report 1 watchpoint register so we
+	 * always know which watchpoint fired. In the future we can either
+	 * add a disassembler and address generation emulator, or we can
+	 * insert a check to see if the DFAR is set on watchpoint exception
+	 * entry [the ARM ARM states that the DFAR is UNKNOWN, but
+	 * experience shows that it is set on some implementations].
+	 */
+
+#if 0
+	u32 didr, wrps;
+	ARM_DBG_READ(c0, 0, didr);
+	return ((didr >> 28) & 0xf) + 1;
+#endif
+
+	return 1;
+}
+
+int hw_breakpoint_slots(int type)
+{
+	/*
+	 * We can be called early, so don't rely on
+	 * our static variables being initialised.
+	 */
+	switch (type) {
+	case TYPE_INST:
+		return get_num_brps();
+	case TYPE_DATA:
+		return get_num_wrps();
+	default:
+		pr_warning("unknown slot type: %d\n", type);
+		return 0;
+	}
+}
+
+/* Determine debug architecture. */
+static u8 get_debug_arch(void)
+{
+	u32 didr;
+
+	/* Do we implement the extended CPUID interface? */
+	if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
+		pr_warning("CPUID feature registers not supported. "
+				"Assuming v6 debug is present.\n");
+		return ARM_DEBUG_ARCH_V6;
+	}
+
+	ARM_DBG_READ(c0, 0, didr);
+	return (didr >> 16) & 0xf;
+}
+
+/* Does this core support mismatch breakpoints? */
+static int core_has_mismatch_bps(void)
+{
+	return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1;
+}
+
+u8 arch_get_debug_arch(void)
+{
+	return debug_arch;
+}
+
+#define READ_WB_REG_CASE(OP2, M, VAL)		\
+	case ((OP2 << 4) + M):			\
+		ARM_DBG_READ(c ## M, OP2, VAL); \
+		break
+
+#define WRITE_WB_REG_CASE(OP2, M, VAL)		\
+	case ((OP2 << 4) + M):			\
+		ARM_DBG_WRITE(c ## M, OP2, VAL);\
+		break
+
+#define GEN_READ_WB_REG_CASES(OP2, VAL)		\
+	READ_WB_REG_CASE(OP2, 0, VAL);		\
+	READ_WB_REG_CASE(OP2, 1, VAL);		\
+	READ_WB_REG_CASE(OP2, 2, VAL);		\
+	READ_WB_REG_CASE(OP2, 3, VAL);		\
+	READ_WB_REG_CASE(OP2, 4, VAL);		\
+	READ_WB_REG_CASE(OP2, 5, VAL);		\
+	READ_WB_REG_CASE(OP2, 6, VAL);		\
+	READ_WB_REG_CASE(OP2, 7, VAL);		\
+	READ_WB_REG_CASE(OP2, 8, VAL);		\
+	READ_WB_REG_CASE(OP2, 9, VAL);		\
+	READ_WB_REG_CASE(OP2, 10, VAL);		\
+	READ_WB_REG_CASE(OP2, 11, VAL);		\
+	READ_WB_REG_CASE(OP2, 12, VAL);		\
+	READ_WB_REG_CASE(OP2, 13, VAL);		\
+	READ_WB_REG_CASE(OP2, 14, VAL);		\
+	READ_WB_REG_CASE(OP2, 15, VAL)
+
+#define GEN_WRITE_WB_REG_CASES(OP2, VAL)	\
+	WRITE_WB_REG_CASE(OP2, 0, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 1, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 2, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 3, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 4, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 5, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 6, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 7, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 8, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 9, VAL);		\
+	WRITE_WB_REG_CASE(OP2, 10, VAL);	\
+	WRITE_WB_REG_CASE(OP2, 11, VAL);	\
+	WRITE_WB_REG_CASE(OP2, 12, VAL);	\
+	WRITE_WB_REG_CASE(OP2, 13, VAL);	\
+	WRITE_WB_REG_CASE(OP2, 14, VAL);	\
+	WRITE_WB_REG_CASE(OP2, 15, VAL)
+
+static u32 read_wb_reg(int n)
+{
+	u32 val = 0;
+
+	switch (n) {
+	GEN_READ_WB_REG_CASES(ARM_OP2_BVR, val);
+	GEN_READ_WB_REG_CASES(ARM_OP2_BCR, val);
+	GEN_READ_WB_REG_CASES(ARM_OP2_WVR, val);
+	GEN_READ_WB_REG_CASES(ARM_OP2_WCR, val);
+	default:
+		pr_warning("attempt to read from unknown breakpoint "
+				"register %d\n", n);
+	}
+
+	return val;
+}
+
+static void write_wb_reg(int n, u32 val)
+{
+	switch (n) {
+	GEN_WRITE_WB_REG_CASES(ARM_OP2_BVR, val);
+	GEN_WRITE_WB_REG_CASES(ARM_OP2_BCR, val);
+	GEN_WRITE_WB_REG_CASES(ARM_OP2_WVR, val);
+	GEN_WRITE_WB_REG_CASES(ARM_OP2_WCR, val);
+	default:
+		pr_warning("attempt to write to unknown breakpoint "
+				"register %d\n", n);
+	}
+	isb();
+}
+
+/*
+ * In order to access the breakpoint/watchpoint control registers,
+ * we must be running in debug monitor mode. Unfortunately, we can
+ * be put into halting debug mode at any time by an external debugger
+ * but there is nothing we can do to prevent that.
+ */
+static int enable_monitor_mode(void)
+{
+	u32 dscr;
+	int ret = 0;
+
+	ARM_DBG_READ(c1, 0, dscr);
+
+	/* Ensure that halting mode is disabled. */
+	if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled."
+				"Unable to access hardware resources.")) {
+		ret = -EPERM;
+		goto out;
+	}
+
+	/* Write to the corresponding DSCR. */
+	switch (debug_arch) {
+	case ARM_DEBUG_ARCH_V6:
+	case ARM_DEBUG_ARCH_V6_1:
+		ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
+		break;
+	case ARM_DEBUG_ARCH_V7_ECP14:
+		ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
+		break;
+	default:
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* Check that the write made it through. */
+	ARM_DBG_READ(c1, 0, dscr);
+	if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN),
+				"failed to enable monitor mode.")) {
+		ret = -EPERM;
+	}
+
+out:
+	return ret;
+}
+
+/*
+ * Check if 8-bit byte-address select is available.
+ * This clobbers WRP 0.
+ */
+static u8 get_max_wp_len(void)
+{
+	u32 ctrl_reg;
+	struct arch_hw_breakpoint_ctrl ctrl;
+	u8 size = 4;
+
+	if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14)
+		goto out;
+
+	if (enable_monitor_mode())
+		goto out;
+
+	memset(&ctrl, 0, sizeof(ctrl));
+	ctrl.len = ARM_BREAKPOINT_LEN_8;
+	ctrl_reg = encode_ctrl_reg(ctrl);
+
+	write_wb_reg(ARM_BASE_WVR, 0);
+	write_wb_reg(ARM_BASE_WCR, ctrl_reg);
+	if ((read_wb_reg(ARM_BASE_WCR) & ctrl_reg) == ctrl_reg)
+		size = 8;
+
+out:
+	return size;
+}
+
+u8 arch_get_max_wp_len(void)
+{
+	return max_watchpoint_len;
+}
+
+/*
+ * Handler for reactivating a suspended watchpoint when the single
+ * step `mismatch' breakpoint is triggered.
+ */
+static void wp_single_step_handler(struct perf_event *bp, int unused,
+				   struct perf_sample_data *data,
+				   struct pt_regs *regs)
+{
+	perf_event_enable(counter_arch_bp(bp)->suspended_wp);
+	unregister_hw_breakpoint(bp);
+}
+
+static int bp_is_single_step(struct perf_event *bp)
+{
+	return bp->overflow_handler == wp_single_step_handler;
+}
+
+/*
+ * Install a perf counter breakpoint.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	struct perf_event **slot, **slots;
+	int i, max_slots, ctrl_base, val_base, ret = 0;
+
+	/* Ensure that we are in monitor mode and halting mode is disabled. */
+	ret = enable_monitor_mode();
+	if (ret)
+		goto out;
+
+	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+		/* Breakpoint */
+		ctrl_base = ARM_BASE_BCR;
+		val_base = ARM_BASE_BVR;
+		slots = __get_cpu_var(bp_on_reg);
+		max_slots = core_num_brps - 1;
+
+		if (bp_is_single_step(bp)) {
+			info->ctrl.mismatch = 1;
+			i = max_slots;
+			slots[i] = bp;
+			goto setup;
+		}
+	} else {
+		/* Watchpoint */
+		ctrl_base = ARM_BASE_WCR;
+		val_base = ARM_BASE_WVR;
+		slots = __get_cpu_var(wp_on_reg);
+		max_slots = core_num_wrps;
+	}
+
+	for (i = 0; i < max_slots; ++i) {
+		slot = &slots[i];
+
+		if (!*slot) {
+			*slot = bp;
+			break;
+		}
+	}
+
+	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+setup:
+	/* Setup the address register. */
+	write_wb_reg(val_base + i, info->address);
+
+	/* Setup the control register. */
+	write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1);
+
+out:
+	return ret;
+}
+
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	struct perf_event **slot, **slots;
+	int i, max_slots, base;
+
+	if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+		/* Breakpoint */
+		base = ARM_BASE_BCR;
+		slots = __get_cpu_var(bp_on_reg);
+		max_slots = core_num_brps - 1;
+
+		if (bp_is_single_step(bp)) {
+			i = max_slots;
+			slots[i] = NULL;
+			goto reset;
+		}
+	} else {
+		/* Watchpoint */
+		base = ARM_BASE_WCR;
+		slots = __get_cpu_var(wp_on_reg);
+		max_slots = core_num_wrps;
+	}
+
+	/* Remove the breakpoint. */
+	for (i = 0; i < max_slots; ++i) {
+		slot = &slots[i];
+
+		if (*slot == bp) {
+			*slot = NULL;
+			break;
+		}
+	}
+
+	if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+		return;
+
+reset:
+	/* Reset the control register. */
+	write_wb_reg(base + i, 0);
+}
+
+static int get_hbp_len(u8 hbp_len)
+{
+	unsigned int len_in_bytes = 0;
+
+	switch (hbp_len) {
+	case ARM_BREAKPOINT_LEN_1:
+		len_in_bytes = 1;
+		break;
+	case ARM_BREAKPOINT_LEN_2:
+		len_in_bytes = 2;
+		break;
+	case ARM_BREAKPOINT_LEN_4:
+		len_in_bytes = 4;
+		break;
+	case ARM_BREAKPOINT_LEN_8:
+		len_in_bytes = 8;
+		break;
+	}
+
+	return len_in_bytes;
+}
+
+/*
+ * Check whether bp virtual address is in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct perf_event *bp)
+{
+	unsigned int len;
+	unsigned long va;
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+	va = info->address;
+	len = get_hbp_len(info->ctrl.len);
+
+	return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl.
+ * Hopefully this will disappear when ptrace can bypass the conversion
+ * to generic breakpoint descriptions.
+ */
+int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+			   int *gen_len, int *gen_type)
+{
+	/* Type */
+	switch (ctrl.type) {
+	case ARM_BREAKPOINT_EXECUTE:
+		*gen_type = HW_BREAKPOINT_X;
+		break;
+	case ARM_BREAKPOINT_LOAD:
+		*gen_type = HW_BREAKPOINT_R;
+		break;
+	case ARM_BREAKPOINT_STORE:
+		*gen_type = HW_BREAKPOINT_W;
+		break;
+	case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE:
+		*gen_type = HW_BREAKPOINT_RW;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Len */
+	switch (ctrl.len) {
+	case ARM_BREAKPOINT_LEN_1:
+		*gen_len = HW_BREAKPOINT_LEN_1;
+		break;
+	case ARM_BREAKPOINT_LEN_2:
+		*gen_len = HW_BREAKPOINT_LEN_2;
+		break;
+	case ARM_BREAKPOINT_LEN_4:
+		*gen_len = HW_BREAKPOINT_LEN_4;
+		break;
+	case ARM_BREAKPOINT_LEN_8:
+		*gen_len = HW_BREAKPOINT_LEN_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Construct an arch_hw_breakpoint from a perf_event.
+ */
+static int arch_build_bp_info(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+	/* Type */
+	switch (bp->attr.bp_type) {
+	case HW_BREAKPOINT_X:
+		info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
+		break;
+	case HW_BREAKPOINT_R:
+		info->ctrl.type = ARM_BREAKPOINT_LOAD;
+		break;
+	case HW_BREAKPOINT_W:
+		info->ctrl.type = ARM_BREAKPOINT_STORE;
+		break;
+	case HW_BREAKPOINT_RW:
+		info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Len */
+	switch (bp->attr.bp_len) {
+	case HW_BREAKPOINT_LEN_1:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_1;
+		break;
+	case HW_BREAKPOINT_LEN_2:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_2;
+		break;
+	case HW_BREAKPOINT_LEN_4:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+		break;
+	case HW_BREAKPOINT_LEN_8:
+		info->ctrl.len = ARM_BREAKPOINT_LEN_8;
+		if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE)
+			&& max_watchpoint_len >= 8)
+			break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Address */
+	info->address = bp->attr.bp_addr;
+
+	/* Privilege */
+	info->ctrl.privilege = ARM_BREAKPOINT_USER;
+	if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp))
+		info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
+
+	/* Enabled? */
+	info->ctrl.enabled = !bp->attr.disabled;
+
+	/* Mismatch */
+	info->ctrl.mismatch = 0;
+
+	return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings.
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp)
+{
+	struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+	int ret = 0;
+	u32 bytelen, max_len, offset, alignment_mask = 0x3;
+
+	/* Build the arch_hw_breakpoint. */
+	ret = arch_build_bp_info(bp);
+	if (ret)
+		goto out;
+
+	/* Check address alignment. */
+	if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+		alignment_mask = 0x7;
+	if (info->address & alignment_mask) {
+		/*
+		 * Try to fix the alignment. This may result in a length
+		 * that is too large, so we must check for that.
+		 */
+		bytelen = get_hbp_len(info->ctrl.len);
+		max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 :
+				max_watchpoint_len;
+
+		if (max_len >= 8)
+			offset = info->address & 0x7;
+		else
+			offset = info->address & 0x3;
+
+		if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) {
+			ret = -EFBIG;
+			goto out;
+		}
+
+		info->ctrl.len <<= offset;
+		info->address &= ~offset;
+
+		pr_debug("breakpoint alignment fixup: length = 0x%x, "
+			"address = 0x%x\n", info->ctrl.len, info->address);
+	}
+
+	/*
+	 * Currently we rely on an overflow handler to take
+	 * care of single-stepping the breakpoint when it fires.
+	 * In the case of userspace breakpoints on a core with V7 debug,
+	 * we can use the mismatch feature as a poor-man's hardware single-step.
+	 */
+	if (WARN_ONCE(!bp->overflow_handler &&
+		(arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()),
+			"overflow handler required but none found")) {
+		ret = -EINVAL;
+		goto out;
+	}
+out:
+	return ret;
+}
+
+static void update_mismatch_flag(int idx, int flag)
+{
+	struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]);
+	struct arch_hw_breakpoint *info;
+
+	if (bp == NULL)
+		return;
+
+	info = counter_arch_bp(bp);
+
+	/* Update the mismatch field to enter/exit `single-step' mode */
+	if (!bp->overflow_handler && info->ctrl.mismatch != flag) {
+		info->ctrl.mismatch = flag;
+		write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1);
+	}
+}
+
+static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+	int i;
+	struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg);
+	struct arch_hw_breakpoint *info;
+	struct perf_event_attr attr;
+
+	/* Without a disassembler, we can only handle 1 watchpoint. */
+	BUG_ON(core_num_wrps > 1);
+
+	hw_breakpoint_init(&attr);
+	attr.bp_addr	= regs->ARM_pc & ~0x3;
+	attr.bp_len	= HW_BREAKPOINT_LEN_4;
+	attr.bp_type	= HW_BREAKPOINT_X;
+
+	for (i = 0; i < core_num_wrps; ++i) {
+		rcu_read_lock();
+
+		if (slots[i] == NULL) {
+			rcu_read_unlock();
+			continue;
+		}
+
+		/*
+		 * The DFAR is an unknown value. Since we only allow a
+		 * single watchpoint, we can set the trigger to the lowest
+		 * possible faulting address.
+		 */
+		info = counter_arch_bp(slots[i]);
+		info->trigger = slots[i]->attr.bp_addr;
+		pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
+		perf_bp_event(slots[i], regs);
+
+		/*
+		 * If no overflow handler is present, insert a temporary
+		 * mismatch breakpoint so we can single-step over the
+		 * watchpoint trigger.
+		 */
+		if (!slots[i]->overflow_handler) {
+			bp = register_user_hw_breakpoint(&attr,
+							 wp_single_step_handler,
+							 current);
+			counter_arch_bp(bp)->suspended_wp = slots[i];
+			perf_event_disable(slots[i]);
+		}
+
+		rcu_read_unlock();
+	}
+}
+
+static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+	int i;
+	int mismatch;
+	u32 ctrl_reg, val, addr;
+	struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg);
+	struct arch_hw_breakpoint *info;
+	struct arch_hw_breakpoint_ctrl ctrl;
+
+	/* The exception entry code places the amended lr in the PC. */
+	addr = regs->ARM_pc;
+
+	for (i = 0; i < core_num_brps; ++i) {
+		rcu_read_lock();
+
+		bp = slots[i];
+
+		if (bp == NULL) {
+			rcu_read_unlock();
+			continue;
+		}
+
+		mismatch = 0;
+
+		/* Check if the breakpoint value matches. */
+		val = read_wb_reg(ARM_BASE_BVR + i);
+		if (val != (addr & ~0x3))
+			goto unlock;
+
+		/* Possible match, check the byte address select to confirm. */
+		ctrl_reg = read_wb_reg(ARM_BASE_BCR + i);
+		decode_ctrl_reg(ctrl_reg, &ctrl);
+		if ((1 << (addr & 0x3)) & ctrl.len) {
+			mismatch = 1;
+			info = counter_arch_bp(bp);
+			info->trigger = addr;
+		}
+
+unlock:
+		if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) {
+			pr_debug("breakpoint fired: address = 0x%x\n", addr);
+			perf_bp_event(bp, regs);
+		}
+
+		update_mismatch_flag(i, mismatch);
+		rcu_read_unlock();
+	}
+}
+
+/*
+ * Called from either the Data Abort Handler [watchpoint] or the
+ * Prefetch Abort Handler [breakpoint].
+ */
+static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
+				 struct pt_regs *regs)
+{
+	int ret = 1; /* Unhandled fault. */
+	u32 dscr;
+
+	/* We only handle watchpoints and hardware breakpoints. */
+	ARM_DBG_READ(c1, 0, dscr);
+
+	/* Perform perf callbacks. */
+	switch (ARM_DSCR_MOE(dscr)) {
+	case ARM_ENTRY_BREAKPOINT:
+		breakpoint_handler(addr, regs);
+		break;
+	case ARM_ENTRY_ASYNC_WATCHPOINT:
+		WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
+	case ARM_ENTRY_SYNC_WATCHPOINT:
+		watchpoint_handler(addr, regs);
+		break;
+	default:
+		goto out;
+	}
+
+	ret = 0;
+out:
+	return ret;
+}
+
+/*
+ * One-time initialisation.
+ */
+static void __init reset_ctrl_regs(void *unused)
+{
+	int i;
+
+	if (enable_monitor_mode())
+		return;
+
+	for (i = 0; i < core_num_brps; ++i) {
+		write_wb_reg(ARM_BASE_BCR + i, 0UL);
+		write_wb_reg(ARM_BASE_BVR + i, 0UL);
+	}
+
+	for (i = 0; i < core_num_wrps; ++i) {
+		write_wb_reg(ARM_BASE_WCR + i, 0UL);
+		write_wb_reg(ARM_BASE_WVR + i, 0UL);
+	}
+}
+
+static int __init arch_hw_breakpoint_init(void)
+{
+	int ret = 0;
+	u32 dscr;
+
+	debug_arch = get_debug_arch();
+
+	if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
+		pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* Determine how many BRPs/WRPs are available. */
+	core_num_brps = get_num_brps();
+	core_num_wrps = get_num_wrps();
+
+	pr_info("found %d breakpoint and %d watchpoint registers.\n",
+			core_num_brps, core_num_wrps);
+
+	if (core_has_mismatch_bps())
+		pr_info("1 breakpoint reserved for watchpoint single-step.\n");
+
+	ARM_DBG_READ(c1, 0, dscr);
+	if (dscr & ARM_DSCR_HDBGEN) {
+		pr_warning("halting debug mode enabled. Assuming maximum "
+				"watchpoint size of 4 bytes.");
+	} else {
+		/* Work out the maximum supported watchpoint length. */
+		max_watchpoint_len = get_max_wp_len();
+		pr_info("maximum watchpoint size is %u bytes.\n",
+				max_watchpoint_len);
+
+		/*
+		 * Reset the breakpoint resources. We assume that a halting
+		 * debugger will leave the world in a nice state for us.
+		 */
+		smp_call_function(reset_ctrl_regs, NULL, 1);
+		reset_ctrl_regs(NULL);
+	}
+
+	/* Register debug fault handler. */
+	hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+			"watchpoint debug exception");
+	hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+			"breakpoint debug exception");
+
+out:
+	return ret;
+}
+arch_initcall(arch_hw_breakpoint_init);
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+}
+
+/*
+ * Dummy function to register with die_notifier.
+ */
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+					unsigned long val, void *data)
+{
+	return NOTIFY_DONE;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/irq.c linux-libre-2.6.37-gnu/arch/arm/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,14 +154,6 @@
 
 void __init init_IRQ(void)
 {
-	struct irq_desc *desc;
-	int irq;
-
-	for (irq = 0; irq < nr_irqs; irq++) {
-		desc = irq_to_desc_alloc_node(irq, 0);
-		desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
-	}
-
 	init_arch_irq();
 }
 
@@ -169,7 +161,7 @@
 int __init arch_probe_nr_irqs(void)
 {
 	nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;
-	return 0;
+	return nr_irqs;
 }
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/kgdb.c linux-libre-2.6.37-gnu/arch/arm/kernel/kgdb.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/kgdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/kgdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 		return;
 
 	/* Initialize to zero */
-	for (regno = 0; regno < DBG_MAX_REG_NUM; regno++)
+	for (regno = 0; regno < GDB_MAX_REGS; regno++)
 		gdb_regs[regno] = 0;
 
 	/* Otherwise, we have only some registers from switch_to() */
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/machine_kexec.c linux-libre-2.6.37-gnu/arch/arm/kernel/machine_kexec.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/machine_kexec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/machine_kexec.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,7 +78,10 @@
 	local_fiq_disable();
 	setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
 	flush_cache_all();
+	outer_flush_all();
+	outer_disable();
 	cpu_proc_fin();
+	outer_inv_all();
 	flush_cache_all();
 	cpu_reset(reboot_code_buffer_phys);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/Makefile linux-libre-2.6.37-gnu/arch/arm/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -42,6 +42,7 @@
 obj-$(CONFIG_ARM_UNWIND)	+= unwind.o
 obj-$(CONFIG_HAVE_TCM)		+= tcm.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 
 obj-$(CONFIG_CRUNCH)		+= crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o		:= -Wa,-mcpu=ep9312
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/module.c linux-libre-2.6.37-gnu/arch/arm/kernel/module.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/module.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/module.c	2011-01-04 19:50:19.000000000 -0500
@@ -69,20 +69,31 @@
 {
 #ifdef CONFIG_ARM_UNWIND
 	Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+	struct arm_unwind_mapping *maps = mod->arch.map;
 
 	for (s = sechdrs; s < sechdrs_end; s++) {
-		if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
-			mod->arch.unw_sec_init = s;
-		else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
-			mod->arch.unw_sec_devinit = s;
-		else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
-			mod->arch.unw_sec_core = s;
-		else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
-			mod->arch.sec_init_text = s;
-		else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
-			mod->arch.sec_devinit_text = s;
-		else if (strcmp(".text", secstrings + s->sh_name) == 0)
-			mod->arch.sec_core_text = s;
+		char const *secname = secstrings + s->sh_name;
+
+		if (strcmp(".ARM.exidx.init.text", secname) == 0)
+			maps[ARM_SEC_INIT].unw_sec = s;
+		else if (strcmp(".ARM.exidx.devinit.text", secname) == 0)
+			maps[ARM_SEC_DEVINIT].unw_sec = s;
+		else if (strcmp(".ARM.exidx", secname) == 0)
+			maps[ARM_SEC_CORE].unw_sec = s;
+		else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
+			maps[ARM_SEC_EXIT].unw_sec = s;
+		else if (strcmp(".ARM.exidx.devexit.text", secname) == 0)
+			maps[ARM_SEC_DEVEXIT].unw_sec = s;
+		else if (strcmp(".init.text", secname) == 0)
+			maps[ARM_SEC_INIT].sec_text = s;
+		else if (strcmp(".devinit.text", secname) == 0)
+			maps[ARM_SEC_DEVINIT].sec_text = s;
+		else if (strcmp(".text", secname) == 0)
+			maps[ARM_SEC_CORE].sec_text = s;
+		else if (strcmp(".exit.text", secname) == 0)
+			maps[ARM_SEC_EXIT].sec_text = s;
+		else if (strcmp(".devexit.text", secname) == 0)
+			maps[ARM_SEC_DEVEXIT].sec_text = s;
 	}
 #endif
 	return 0;
@@ -292,31 +303,22 @@
 #ifdef CONFIG_ARM_UNWIND
 static void register_unwind_tables(struct module *mod)
 {
-	if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
-		mod->arch.unwind_init =
-			unwind_table_add(mod->arch.unw_sec_init->sh_addr,
-					 mod->arch.unw_sec_init->sh_size,
-					 mod->arch.sec_init_text->sh_addr,
-					 mod->arch.sec_init_text->sh_size);
-	if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
-		mod->arch.unwind_devinit =
-			unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
-					 mod->arch.unw_sec_devinit->sh_size,
-					 mod->arch.sec_devinit_text->sh_addr,
-					 mod->arch.sec_devinit_text->sh_size);
-	if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
-		mod->arch.unwind_core =
-			unwind_table_add(mod->arch.unw_sec_core->sh_addr,
-					 mod->arch.unw_sec_core->sh_size,
-					 mod->arch.sec_core_text->sh_addr,
-					 mod->arch.sec_core_text->sh_size);
+	int i;
+	for (i = 0; i < ARM_SEC_MAX; ++i) {
+		struct arm_unwind_mapping *map = &mod->arch.map[i];
+		if (map->unw_sec && map->sec_text)
+			map->unwind = unwind_table_add(map->unw_sec->sh_addr,
+						       map->unw_sec->sh_size,
+						       map->sec_text->sh_addr,
+						       map->sec_text->sh_size);
+	}
 }
 
 static void unregister_unwind_tables(struct module *mod)
 {
-	unwind_table_del(mod->arch.unwind_init);
-	unwind_table_del(mod->arch.unwind_devinit);
-	unwind_table_del(mod->arch.unwind_core);
+	int i = ARM_SEC_MAX;
+	while (--i >= 0)
+		unwind_table_del(mod->arch.map[i].unwind);
 }
 #else
 static inline void register_unwind_tables(struct module *mod) { }
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/arm/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -123,6 +123,12 @@
 }
 EXPORT_SYMBOL_GPL(armpmu_get_max_events);
 
+int perf_num_counters(void)
+{
+	return armpmu_get_max_events();
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
 #define HW_OP_UNSUPPORTED		0xFFFF
 
 #define C(_x) \
@@ -221,46 +227,56 @@
 }
 
 static void
-armpmu_disable(struct perf_event *event)
+armpmu_read(struct perf_event *event)
 {
-	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
 
-	WARN_ON(idx < 0);
-
-	clear_bit(idx, cpuc->active_mask);
-	armpmu->disable(hwc, idx);
-
-	barrier();
-
-	armpmu_event_update(event, hwc, idx);
-	cpuc->events[idx] = NULL;
-	clear_bit(idx, cpuc->used_mask);
+	/* Don't read disabled counters! */
+	if (hwc->idx < 0)
+		return;
 
-	perf_event_update_userpage(event);
+	armpmu_event_update(event, hwc, hwc->idx);
 }
 
 static void
-armpmu_read(struct perf_event *event)
+armpmu_stop(struct perf_event *event, int flags)
 {
 	struct hw_perf_event *hwc = &event->hw;
 
-	/* Don't read disabled counters! */
-	if (hwc->idx < 0)
+	if (!armpmu)
 		return;
 
-	armpmu_event_update(event, hwc, hwc->idx);
+	/*
+	 * ARM pmu always has to update the counter, so ignore
+	 * PERF_EF_UPDATE, see comments in armpmu_start().
+	 */
+	if (!(hwc->state & PERF_HES_STOPPED)) {
+		armpmu->disable(hwc, hwc->idx);
+		barrier(); /* why? */
+		armpmu_event_update(event, hwc, hwc->idx);
+		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	}
 }
 
 static void
-armpmu_unthrottle(struct perf_event *event)
+armpmu_start(struct perf_event *event, int flags)
 {
 	struct hw_perf_event *hwc = &event->hw;
 
+	if (!armpmu)
+		return;
+
+	/*
+	 * ARM pmu always has to reprogram the period, so ignore
+	 * PERF_EF_RELOAD, see the comment below.
+	 */
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+	hwc->state = 0;
 	/*
 	 * Set the period again. Some counters can't be stopped, so when we
-	 * were throttled we simply disabled the IRQ source and the counter
+	 * were stopped we simply disabled the IRQ source and the counter
 	 * may have been left counting. If we don't do this step then we may
 	 * get an interrupt too soon or *way* too late if the overflow has
 	 * happened since disabling.
@@ -269,14 +285,33 @@
 	armpmu->enable(hwc, hwc->idx);
 }
 
+static void
+armpmu_del(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+
+	WARN_ON(idx < 0);
+
+	clear_bit(idx, cpuc->active_mask);
+	armpmu_stop(event, PERF_EF_UPDATE);
+	cpuc->events[idx] = NULL;
+	clear_bit(idx, cpuc->used_mask);
+
+	perf_event_update_userpage(event);
+}
+
 static int
-armpmu_enable(struct perf_event *event)
+armpmu_add(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
 	int idx;
 	int err = 0;
 
+	perf_pmu_disable(event->pmu);
+
 	/* If we don't have a space for the counter then finish early. */
 	idx = armpmu->get_event_idx(cpuc, hwc);
 	if (idx < 0) {
@@ -293,25 +328,19 @@
 	cpuc->events[idx] = event;
 	set_bit(idx, cpuc->active_mask);
 
-	/* Set the period for the event. */
-	armpmu_event_set_period(event, hwc, idx);
-
-	/* Enable the event. */
-	armpmu->enable(hwc, idx);
+	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	if (flags & PERF_EF_START)
+		armpmu_start(event, PERF_EF_RELOAD);
 
 	/* Propagate our changes to the userspace mapping. */
 	perf_event_update_userpage(event);
 
 out:
+	perf_pmu_enable(event->pmu);
 	return err;
 }
 
-static struct pmu pmu = {
-	.enable	    = armpmu_enable,
-	.disable    = armpmu_disable,
-	.unthrottle = armpmu_unthrottle,
-	.read	    = armpmu_read,
-};
+static struct pmu pmu;
 
 static int
 validate_event(struct cpu_hw_events *cpuc,
@@ -491,20 +520,29 @@
 	return err;
 }
 
-const struct pmu *
-hw_perf_event_init(struct perf_event *event)
+static int armpmu_event_init(struct perf_event *event)
 {
 	int err = 0;
 
+	switch (event->attr.type) {
+	case PERF_TYPE_RAW:
+	case PERF_TYPE_HARDWARE:
+	case PERF_TYPE_HW_CACHE:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
 	if (!armpmu)
-		return ERR_PTR(-ENODEV);
+		return -ENODEV;
 
 	event->destroy = hw_perf_event_destroy;
 
 	if (!atomic_inc_not_zero(&active_events)) {
-		if (atomic_read(&active_events) > perf_max_events) {
+		if (atomic_read(&active_events) > armpmu->num_events) {
 			atomic_dec(&active_events);
-			return ERR_PTR(-ENOSPC);
+			return -ENOSPC;
 		}
 
 		mutex_lock(&pmu_reserve_mutex);
@@ -518,17 +556,16 @@
 	}
 
 	if (err)
-		return ERR_PTR(err);
+		return err;
 
 	err = __hw_perf_event_init(event);
 	if (err)
 		hw_perf_event_destroy(event);
 
-	return err ? ERR_PTR(err) : &pmu;
+	return err;
 }
 
-void
-hw_perf_enable(void)
+static void armpmu_enable(struct pmu *pmu)
 {
 	/* Enable all of the perf events on hardware. */
 	int idx;
@@ -549,13 +586,23 @@
 	armpmu->start();
 }
 
-void
-hw_perf_disable(void)
+static void armpmu_disable(struct pmu *pmu)
 {
 	if (armpmu)
 		armpmu->stop();
 }
 
+static struct pmu pmu = {
+	.pmu_enable	= armpmu_enable,
+	.pmu_disable	= armpmu_disable,
+	.event_init	= armpmu_event_init,
+	.add		= armpmu_add,
+	.del		= armpmu_del,
+	.start		= armpmu_start,
+	.stop		= armpmu_stop,
+	.read		= armpmu_read,
+};
+
 /*
  * ARMv6 Performance counter handling code.
  *
@@ -1045,7 +1092,7 @@
 	 * platforms that can have the PMU interrupts raised as an NMI, this
 	 * will not work.
 	 */
-	perf_event_do_pending();
+	irq_work_run();
 
 	return IRQ_HANDLED;
 }
@@ -1702,7 +1749,7 @@
 static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,
 					enum armv7_counters counter)
 {
-	int ret;
+	int ret = 0;
 
 	if (counter == ARMV7_CYCLE_COUNTER)
 		ret = pmnc & ARMV7_FLAG_C;
@@ -2021,7 +2068,7 @@
 	 * platforms that can have the PMU interrupts raised as an NMI, this
 	 * will not work.
 	 */
-	perf_event_do_pending();
+	irq_work_run();
 
 	return IRQ_HANDLED;
 }
@@ -2389,7 +2436,7 @@
 			armpmu->disable(hwc, idx);
 	}
 
-	perf_event_do_pending();
+	irq_work_run();
 
 	/*
 	 * Re-enable the PMU.
@@ -2716,7 +2763,7 @@
 			armpmu->disable(hwc, idx);
 	}
 
-	perf_event_do_pending();
+	irq_work_run();
 
 	/*
 	 * Re-enable the PMU.
@@ -2933,14 +2980,12 @@
 			armpmu = &armv6pmu;
 			memcpy(armpmu_perf_cache_map, armv6_perf_cache_map,
 					sizeof(armv6_perf_cache_map));
-			perf_max_events	= armv6pmu.num_events;
 			break;
 		case 0xB020:	/* ARM11mpcore */
 			armpmu = &armv6mpcore_pmu;
 			memcpy(armpmu_perf_cache_map,
 			       armv6mpcore_perf_cache_map,
 			       sizeof(armv6mpcore_perf_cache_map));
-			perf_max_events = armv6mpcore_pmu.num_events;
 			break;
 		case 0xC080:	/* Cortex-A8 */
 			armv7pmu.id = ARM_PERF_PMU_ID_CA8;
@@ -2952,7 +2997,6 @@
 			/* Reset PMNC and read the nb of CNTx counters
 			    supported */
 			armv7pmu.num_events = armv7_reset_read_pmnc();
-			perf_max_events = armv7pmu.num_events;
 			break;
 		case 0xC090:	/* Cortex-A9 */
 			armv7pmu.id = ARM_PERF_PMU_ID_CA9;
@@ -2964,7 +3008,6 @@
 			/* Reset PMNC and read the nb of CNTx counters
 			    supported */
 			armv7pmu.num_events = armv7_reset_read_pmnc();
-			perf_max_events = armv7pmu.num_events;
 			break;
 		}
 	/* Intel CPUs [xscale]. */
@@ -2975,13 +3018,11 @@
 			armpmu = &xscale1pmu;
 			memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
 					sizeof(xscale_perf_cache_map));
-			perf_max_events	= xscale1pmu.num_events;
 			break;
 		case 2:
 			armpmu = &xscale2pmu;
 			memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
 					sizeof(xscale_perf_cache_map));
-			perf_max_events	= xscale2pmu.num_events;
 			break;
 		}
 	}
@@ -2991,9 +3032,10 @@
 				arm_pmu_names[armpmu->id], armpmu->num_events);
 	} else {
 		pr_info("no hardware support available\n");
-		perf_max_events = -1;
 	}
 
+	perf_pmu_register(&pmu);
+
 	return 0;
 }
 arch_initcall(init_hw_perf_events);
@@ -3001,13 +3043,6 @@
 /*
  * Callchain handling code.
  */
-static inline void
-callchain_store(struct perf_callchain_entry *entry,
-		u64 ip)
-{
-	if (entry->nr < PERF_MAX_STACK_DEPTH)
-		entry->ip[entry->nr++] = ip;
-}
 
 /*
  * The registers we're interested in are at the end of the variable
@@ -3039,7 +3074,7 @@
 	if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail)))
 		return NULL;
 
-	callchain_store(entry, buftail.lr);
+	perf_callchain_store(entry, buftail.lr);
 
 	/*
 	 * Frame pointers should strictly progress back up the stack
@@ -3051,16 +3086,11 @@
 	return buftail.fp - 1;
 }
 
-static void
-perf_callchain_user(struct pt_regs *regs,
-		    struct perf_callchain_entry *entry)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
 	struct frame_tail *tail;
 
-	callchain_store(entry, PERF_CONTEXT_USER);
-
-	if (!user_mode(regs))
-		regs = task_pt_regs(current);
 
 	tail = (struct frame_tail *)regs->ARM_fp - 1;
 
@@ -3078,56 +3108,18 @@
 		void *data)
 {
 	struct perf_callchain_entry *entry = data;
-	callchain_store(entry, fr->pc);
+	perf_callchain_store(entry, fr->pc);
 	return 0;
 }
 
-static void
-perf_callchain_kernel(struct pt_regs *regs,
-		      struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
 	struct stackframe fr;
 
-	callchain_store(entry, PERF_CONTEXT_KERNEL);
 	fr.fp = regs->ARM_fp;
 	fr.sp = regs->ARM_sp;
 	fr.lr = regs->ARM_lr;
 	fr.pc = regs->ARM_pc;
 	walk_stackframe(&fr, callchain_trace, entry);
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs,
-		  struct perf_callchain_entry *entry)
-{
-	int is_user;
-
-	if (!regs)
-		return;
-
-	is_user = user_mode(regs);
-
-	if (!current || !current->pid)
-		return;
-
-	if (is_user && current->state != TASK_RUNNING)
-		return;
-
-	if (!is_user)
-		perf_callchain_kernel(regs, entry);
-
-	if (current->mm)
-		perf_callchain_user(regs, entry);
-}
-
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-
-struct perf_callchain_entry *
-perf_callchain(struct pt_regs *regs)
-{
-	struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
-
-	entry->nr = 0;
-	perf_do_callchain(regs, entry);
-	return entry;
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/process.c linux-libre-2.6.37-gnu/arch/arm/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,6 +29,7 @@
 #include <linux/utsname.h>
 #include <linux/uaccess.h>
 #include <linux/random.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/cacheflush.h>
 #include <asm/leds.h>
@@ -135,6 +136,25 @@
 void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
+ * pm_idle and update to new pm_idle value. Required while changing pm_idle
+ * handler on SMP systems.
+ *
+ * Caller must have changed pm_idle to the new value before the call. Old
+ * pm_idle value will not be used by any CPU after the return of this function.
+ */
+void cpu_idle_wait(void)
+{
+	smp_mb();
+	/* kick all the CPUs so that they exit out of pm_idle */
+	smp_call_function(do_nothing, NULL, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
 /*
  * This is our default idle handler.  We need to disable
@@ -317,6 +337,8 @@
 	struct thread_info *thread = current_thread_info();
 	struct task_struct *tsk = current;
 
+	flush_ptrace_hw_breakpoint(tsk);
+
 	memset(thread->used_cp, 0, sizeof(thread->used_cp));
 	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
 	memset(&thread->fpstate, 0, sizeof(union fp_state));
@@ -345,6 +367,8 @@
 	thread->cpu_context.sp = (unsigned long)childregs;
 	thread->cpu_context.pc = (unsigned long)ret_from_fork;
 
+	clear_ptrace_hw_breakpoint(p);
+
 	if (clone_flags & CLONE_SETTLS)
 		thread->tp_value = regs->ARM_r3;
 
@@ -458,3 +482,24 @@
 	unsigned long range_end = mm->brk + 0x02000000;
 	return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
 }
+
+/*
+ * The vectors page is always readable from user space for the
+ * atomic helpers and the signal restart code.  Let's declare a mapping
+ * for it so it is visible through ptrace and /proc/<pid>/mem.
+ */
+
+int vectors_user_mapping(void)
+{
+	struct mm_struct *mm = current->mm;
+	return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
+				       VM_READ | VM_EXEC |
+				       VM_MAYREAD | VM_MAYEXEC |
+				       VM_ALWAYSDUMP | VM_RESERVED,
+				       NULL);
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+	return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/arm/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/signal.h>
 #include <linux/uaccess.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -847,13 +849,241 @@
 }
 #endif
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+/*
+ * Convert a virtual register number into an index for a thread_info
+ * breakpoint array. Breakpoints are identified using positive numbers
+ * whilst watchpoints are negative. The registers are laid out as pairs
+ * of (address, control), each pair mapping to a unique hw_breakpoint struct.
+ * Register 0 is reserved for describing resource information.
+ */
+static int ptrace_hbp_num_to_idx(long num)
+{
+	if (num < 0)
+		num = (ARM_MAX_BRP << 1) - num;
+	return (num - 1) >> 1;
+}
+
+/*
+ * Returns the virtual register number for the address of the
+ * breakpoint at index idx.
+ */
+static long ptrace_hbp_idx_to_num(int idx)
+{
+	long mid = ARM_MAX_BRP << 1;
+	long num = (idx << 1) + 1;
+	return num > mid ? mid - num : num;
+}
+
+/*
+ * Handle hitting a HW-breakpoint.
+ */
+static void ptrace_hbptriggered(struct perf_event *bp, int unused,
+				     struct perf_sample_data *data,
+				     struct pt_regs *regs)
+{
+	struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
+	long num;
+	int i;
+	siginfo_t info;
+
+	for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
+		if (current->thread.debug.hbp[i] == bp)
+			break;
+
+	num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
+
+	info.si_signo	= SIGTRAP;
+	info.si_errno	= (int)num;
+	info.si_code	= TRAP_HWBKPT;
+	info.si_addr	= (void __user *)(bkpt->trigger);
+
+	force_sig_info(SIGTRAP, &info, current);
+}
+
+/*
+ * Set ptrace breakpoint pointers to zero for this task.
+ * This is required in order to prevent child processes from unregistering
+ * breakpoints held by their parent.
+ */
+void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+	memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp));
+}
+
+/*
+ * Unregister breakpoints from this task and reset the pointers in
+ * the thread_struct.
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+	int i;
+	struct thread_struct *t = &tsk->thread;
+
+	for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
+		if (t->debug.hbp[i]) {
+			unregister_hw_breakpoint(t->debug.hbp[i]);
+			t->debug.hbp[i] = NULL;
+		}
+	}
+}
+
+static u32 ptrace_get_hbp_resource_info(void)
+{
+	u8 num_brps, num_wrps, debug_arch, wp_len;
+	u32 reg = 0;
+
+	num_brps	= hw_breakpoint_slots(TYPE_INST);
+	num_wrps	= hw_breakpoint_slots(TYPE_DATA);
+	debug_arch	= arch_get_debug_arch();
+	wp_len		= arch_get_max_wp_len();
+
+	reg		|= debug_arch;
+	reg		<<= 8;
+	reg		|= wp_len;
+	reg		<<= 8;
+	reg		|= num_wrps;
+	reg		<<= 8;
+	reg		|= num_brps;
+
+	return reg;
+}
+
+static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
+{
+	struct perf_event_attr attr;
+
+	ptrace_breakpoint_init(&attr);
+
+	/* Initialise fields to sane defaults. */
+	attr.bp_addr	= 0;
+	attr.bp_len	= HW_BREAKPOINT_LEN_4;
+	attr.bp_type	= type;
+	attr.disabled	= 1;
+
+	return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk);
+}
+
+static int ptrace_gethbpregs(struct task_struct *tsk, long num,
+			     unsigned long  __user *data)
+{
+	u32 reg;
+	int idx, ret = 0;
+	struct perf_event *bp;
+	struct arch_hw_breakpoint_ctrl arch_ctrl;
+
+	if (num == 0) {
+		reg = ptrace_get_hbp_resource_info();
+	} else {
+		idx = ptrace_hbp_num_to_idx(num);
+		if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		bp = tsk->thread.debug.hbp[idx];
+		if (!bp) {
+			reg = 0;
+			goto put;
+		}
+
+		arch_ctrl = counter_arch_bp(bp)->ctrl;
+
+		/*
+		 * Fix up the len because we may have adjusted it
+		 * to compensate for an unaligned address.
+		 */
+		while (!(arch_ctrl.len & 0x1))
+			arch_ctrl.len >>= 1;
+
+		if (idx & 0x1)
+			reg = encode_ctrl_reg(arch_ctrl);
+		else
+			reg = bp->attr.bp_addr;
+	}
+
+put:
+	if (put_user(reg, data))
+		ret = -EFAULT;
+
+out:
+	return ret;
+}
+
+static int ptrace_sethbpregs(struct task_struct *tsk, long num,
+			     unsigned long __user *data)
+{
+	int idx, gen_len, gen_type, implied_type, ret = 0;
+	u32 user_val;
+	struct perf_event *bp;
+	struct arch_hw_breakpoint_ctrl ctrl;
+	struct perf_event_attr attr;
+
+	if (num == 0)
+		goto out;
+	else if (num < 0)
+		implied_type = HW_BREAKPOINT_RW;
+	else
+		implied_type = HW_BREAKPOINT_X;
+
+	idx = ptrace_hbp_num_to_idx(num);
+	if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (get_user(user_val, data)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	bp = tsk->thread.debug.hbp[idx];
+	if (!bp) {
+		bp = ptrace_hbp_create(tsk, implied_type);
+		if (IS_ERR(bp)) {
+			ret = PTR_ERR(bp);
+			goto out;
+		}
+		tsk->thread.debug.hbp[idx] = bp;
+	}
+
+	attr = bp->attr;
+
+	if (num & 0x1) {
+		/* Address */
+		attr.bp_addr	= user_val;
+	} else {
+		/* Control */
+		decode_ctrl_reg(user_val, &ctrl);
+		ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type);
+		if (ret)
+			goto out;
+
+		if ((gen_type & implied_type) != gen_type) {
+				ret = -EINVAL;
+				goto out;
+		}
+
+		attr.bp_len	= gen_len;
+		attr.bp_type	= gen_type;
+		attr.disabled	= !ctrl.enabled;
+	}
+
+	ret = modify_user_hw_breakpoint(bp, &attr);
+out:
+	return ret;
+}
+#endif
+
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 		case PTRACE_PEEKUSR:
-			ret = ptrace_read_user(child, addr, (unsigned long __user *)data);
+			ret = ptrace_read_user(child, addr, datap);
 			break;
 
 		case PTRACE_POKEUSR:
@@ -861,34 +1091,34 @@
 			break;
 
 		case PTRACE_GETREGS:
-			ret = ptrace_getregs(child, (void __user *)data);
+			ret = ptrace_getregs(child, datap);
 			break;
 
 		case PTRACE_SETREGS:
-			ret = ptrace_setregs(child, (void __user *)data);
+			ret = ptrace_setregs(child, datap);
 			break;
 
 		case PTRACE_GETFPREGS:
-			ret = ptrace_getfpregs(child, (void __user *)data);
+			ret = ptrace_getfpregs(child, datap);
 			break;
 		
 		case PTRACE_SETFPREGS:
-			ret = ptrace_setfpregs(child, (void __user *)data);
+			ret = ptrace_setfpregs(child, datap);
 			break;
 
 #ifdef CONFIG_IWMMXT
 		case PTRACE_GETWMMXREGS:
-			ret = ptrace_getwmmxregs(child, (void __user *)data);
+			ret = ptrace_getwmmxregs(child, datap);
 			break;
 
 		case PTRACE_SETWMMXREGS:
-			ret = ptrace_setwmmxregs(child, (void __user *)data);
+			ret = ptrace_setwmmxregs(child, datap);
 			break;
 #endif
 
 		case PTRACE_GET_THREAD_AREA:
 			ret = put_user(task_thread_info(child)->tp_value,
-				       (unsigned long __user *) data);
+				       datap);
 			break;
 
 		case PTRACE_SET_SYSCALL:
@@ -898,21 +1128,32 @@
 
 #ifdef CONFIG_CRUNCH
 		case PTRACE_GETCRUNCHREGS:
-			ret = ptrace_getcrunchregs(child, (void __user *)data);
+			ret = ptrace_getcrunchregs(child, datap);
 			break;
 
 		case PTRACE_SETCRUNCHREGS:
-			ret = ptrace_setcrunchregs(child, (void __user *)data);
+			ret = ptrace_setcrunchregs(child, datap);
 			break;
 #endif
 
 #ifdef CONFIG_VFP
 		case PTRACE_GETVFPREGS:
-			ret = ptrace_getvfpregs(child, (void __user *)data);
+			ret = ptrace_getvfpregs(child, datap);
 			break;
 
 		case PTRACE_SETVFPREGS:
-			ret = ptrace_setvfpregs(child, (void __user *)data);
+			ret = ptrace_setvfpregs(child, datap);
+			break;
+#endif
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+		case PTRACE_GETHBPREGS:
+			ret = ptrace_gethbpregs(child, addr,
+						(unsigned long __user *)data);
+			break;
+		case PTRACE_SETHBPREGS:
+			ret = ptrace_sethbpregs(child, addr,
+						(unsigned long __user *)data);
 			break;
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/relocate_kernel.S linux-libre-2.6.37-gnu/arch/arm/kernel/relocate_kernel.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/relocate_kernel.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/relocate_kernel.S	2011-01-04 19:50:19.000000000 -0500
@@ -59,6 +59,8 @@
 	ldr r2,kexec_boot_atags
 	mov pc,lr
 
+	.align
+
 	.globl kexec_start_address
 kexec_start_address:
 	.long	0x0
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/setup.c linux-libre-2.6.37-gnu/arch/arm/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,7 @@
 #include <asm/procinfo.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
+#include <asm/smp_plat.h>
 #include <asm/mach-types.h>
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
@@ -238,6 +239,35 @@
 	return cpu_arch;
 }
 
+static int cpu_has_aliasing_icache(unsigned int arch)
+{
+	int aliasing_icache;
+	unsigned int id_reg, num_sets, line_size;
+
+	/* arch specifies the register format */
+	switch (arch) {
+	case CPU_ARCH_ARMv7:
+		asm("mcr	p15, 2, %0, c0, c0, 0 @ set CSSELR"
+		    : /* No output operands */
+		    : "r" (1));
+		isb();
+		asm("mrc	p15, 1, %0, c0, c0, 0 @ read CCSIDR"
+		    : "=r" (id_reg));
+		line_size = 4 << ((id_reg & 0x7) + 2);
+		num_sets = ((id_reg >> 13) & 0x7fff) + 1;
+		aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
+		break;
+	case CPU_ARCH_ARMv6:
+		aliasing_icache = read_cpuid_cachetype() & (1 << 11);
+		break;
+	default:
+		/* I-cache aliases will be handled by D-cache aliasing code */
+		aliasing_icache = 0;
+	}
+
+	return aliasing_icache;
+}
+
 static void __init cacheid_init(void)
 {
 	unsigned int cachetype = read_cpuid_cachetype();
@@ -249,10 +279,15 @@
 			cacheid = CACHEID_VIPT_NONALIASING;
 			if ((cachetype & (3 << 14)) == 1 << 14)
 				cacheid |= CACHEID_ASID_TAGGED;
-		} else if (cachetype & (1 << 23))
+			else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
+				cacheid |= CACHEID_VIPT_I_ALIASING;
+		} else if (cachetype & (1 << 23)) {
 			cacheid = CACHEID_VIPT_ALIASING;
-		else
+		} else {
 			cacheid = CACHEID_VIPT_NONALIASING;
+			if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
+				cacheid |= CACHEID_VIPT_I_ALIASING;
+		}
 	} else {
 		cacheid = CACHEID_VIVT;
 	}
@@ -263,7 +298,7 @@
 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
 		cache_is_vivt() ? "VIVT" :
 		icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
-		cache_is_vipt_aliasing() ? "VIPT aliasing" :
+		icache_is_vipt_aliasing() ? "VIPT aliasing" :
 		cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
 }
 
@@ -490,7 +525,7 @@
 
 	kernel_code.start   = virt_to_phys(_text);
 	kernel_code.end     = virt_to_phys(_etext - 1);
-	kernel_data.start   = virt_to_phys(_data);
+	kernel_data.start   = virt_to_phys(_sdata);
 	kernel_data.end     = virt_to_phys(_end - 1);
 
 	for (i = 0; i < mi->nr_banks; i++) {
@@ -825,7 +860,8 @@
 	request_standard_resources(&meminfo, mdesc);
 
 #ifdef CONFIG_SMP
-	smp_init_cpus();
+	if (is_smp())
+		smp_init_cpus();
 #endif
 	reserve_crashkernel();
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/smp.c linux-libre-2.6.37-gnu/arch/arm/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
+#include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
 #include <asm/localtimer.h>
@@ -67,12 +68,47 @@
 	IPI_CPU_STOP,
 };
 
+static inline void identity_mapping_add(pgd_t *pgd, unsigned long start,
+	unsigned long end)
+{
+	unsigned long addr, prot;
+	pmd_t *pmd;
+
+	prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+	if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+		prot |= PMD_BIT4;
+
+	for (addr = start & PGDIR_MASK; addr < end;) {
+		pmd = pmd_offset(pgd + pgd_index(addr), addr);
+		pmd[0] = __pmd(addr | prot);
+		addr += SECTION_SIZE;
+		pmd[1] = __pmd(addr | prot);
+		addr += SECTION_SIZE;
+		flush_pmd_entry(pmd);
+		outer_clean_range(__pa(pmd), __pa(pmd + 1));
+	}
+}
+
+static inline void identity_mapping_del(pgd_t *pgd, unsigned long start,
+	unsigned long end)
+{
+	unsigned long addr;
+	pmd_t *pmd;
+
+	for (addr = start & PGDIR_MASK; addr < end; addr += PGDIR_SIZE) {
+		pmd = pmd_offset(pgd + pgd_index(addr), addr);
+		pmd[0] = __pmd(0);
+		pmd[1] = __pmd(0);
+		clean_pmd_entry(pmd);
+		outer_clean_range(__pa(pmd), __pa(pmd + 1));
+	}
+}
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
 	struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
 	struct task_struct *idle = ci->idle;
 	pgd_t *pgd;
-	pmd_t *pmd;
 	int ret;
 
 	/*
@@ -101,11 +137,16 @@
 	 * a 1:1 mapping for the physical address of the kernel.
 	 */
 	pgd = pgd_alloc(&init_mm);
-	pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET);
-	*pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
-		     PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
-	flush_pmd_entry(pmd);
-	outer_clean_range(__pa(pmd), __pa(pmd + 1));
+	if (!pgd)
+		return -ENOMEM;
+
+	if (PHYS_OFFSET != PAGE_OFFSET) {
+#ifndef CONFIG_HOTPLUG_CPU
+		identity_mapping_add(pgd, __pa(__init_begin), __pa(__init_end));
+#endif
+		identity_mapping_add(pgd, __pa(_stext), __pa(_etext));
+		identity_mapping_add(pgd, __pa(_sdata), __pa(_edata));
+	}
 
 	/*
 	 * We need to tell the secondary core where to find
@@ -143,8 +184,14 @@
 	secondary_data.stack = NULL;
 	secondary_data.pgdir = 0;
 
-	*pmd = __pmd(0);
-	clean_pmd_entry(pmd);
+	if (PHYS_OFFSET != PAGE_OFFSET) {
+#ifndef CONFIG_HOTPLUG_CPU
+		identity_mapping_del(pgd, __pa(__init_begin), __pa(__init_end));
+#endif
+		identity_mapping_del(pgd, __pa(_stext), __pa(_etext));
+		identity_mapping_del(pgd, __pa(_sdata), __pa(_edata));
+	}
+
 	pgd_free(&init_mm, pgd);
 
 	if (ret) {
@@ -263,7 +310,6 @@
 	 * All kernel threads share the same mm context; grab a
 	 * reference and switch to it.
 	 */
-	atomic_inc(&mm->mm_users);
 	atomic_inc(&mm->mm_count);
 	current->active_mm = mm;
 	cpumask_set_cpu(cpu, mm_cpumask(mm));
@@ -567,7 +613,8 @@
 {
 	cpumask_t mask = cpu_online_map;
 	cpu_clear(smp_processor_id(), mask);
-	send_ipi_message(&mask, IPI_CPU_STOP);
+	if (!cpus_empty(mask))
+		send_ipi_message(&mask, IPI_CPU_STOP);
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/stacktrace.c linux-libre-2.6.37-gnu/arch/arm/kernel/stacktrace.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/stacktrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/stacktrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
 
 	/* only go to a higher address on the stack */
 	low = frame->sp;
-	high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
+	high = ALIGN(low, THREAD_SIZE);
 
 	/* check current frame pointer is within bounds */
 	if (fp < (low + 12) || fp + 4 >= high)
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/traps.c linux-libre-2.6.37-gnu/arch/arm/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -53,10 +53,7 @@
 void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
 {
 #ifdef CONFIG_KALLSYMS
-	char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN];
-	sprint_symbol(sym1, where);
-	sprint_symbol(sym2, from);
-	printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2);
+	printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from);
 #else
 	printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/unwind.c linux-libre-2.6.37-gnu/arch/arm/kernel/unwind.c
--- linux-libre-2.6.36-gnu/arch/arm/kernel/unwind.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/unwind.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,6 +146,8 @@
 			    addr < table->end_addr) {
 				idx = search_index(addr, table->start,
 						   table->stop - 1);
+				/* Move-to-front to exploit common traces */
+				list_move(&table->list, &unwind_tables);
 				break;
 			}
 		}
@@ -277,7 +279,7 @@
 
 	/* only go to a higher address on the stack */
 	low = frame->sp;
-	high = ALIGN(low, THREAD_SIZE) + THREAD_SIZE;
+	high = ALIGN(low, THREAD_SIZE);
 
 	pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
 		 frame->pc, frame->lr, frame->sp);
diff -druN linux-libre-2.6.36-gnu/arch/arm/kernel/vmlinux.lds.S linux-libre-2.6.37-gnu/arch/arm/kernel/vmlinux.lds.S
--- linux-libre-2.6.36-gnu/arch/arm/kernel/vmlinux.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/kernel/vmlinux.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,6 +8,19 @@
 #include <asm/memory.h>
 #include <asm/page.h>
 	
+#define PROC_INFO							\
+	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
+	*(.proc.info.init)						\
+	VMLINUX_SYMBOL(__proc_info_end) = .;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define ARM_CPU_DISCARD(x)
+#define ARM_CPU_KEEP(x)		x
+#else
+#define ARM_CPU_DISCARD(x)	x
+#define ARM_CPU_KEEP(x)
+#endif
+
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -31,15 +44,18 @@
 			HEAD_TEXT
 			INIT_TEXT
 		_einittext = .;
-		__proc_info_begin = .;
-			*(.proc.info.init)
-		__proc_info_end = .;
+		ARM_CPU_DISCARD(PROC_INFO)
 		__arch_info_begin = .;
 			*(.arch.info.init)
 		__arch_info_end = .;
 		__tagtable_begin = .;
 			*(.taglist.init)
 		__tagtable_end = .;
+#ifdef CONFIG_SMP_ON_UP
+		__smpalt_begin = .;
+			*(.alt.smp.init)
+		__smpalt_end = .;
+#endif
 
 		INIT_SETUP(16)
 
@@ -68,10 +84,8 @@
 	/DISCARD/ : {
 		*(.ARM.exidx.exit.text)
 		*(.ARM.extab.exit.text)
-#ifndef CONFIG_HOTPLUG_CPU
-		*(.ARM.exidx.cpuexit.text)
-		*(.ARM.extab.cpuexit.text)
-#endif
+		ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
+		ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
 #ifndef CONFIG_HOTPLUG
 		*(.ARM.exidx.devexit.text)
 		*(.ARM.extab.devexit.text)
@@ -99,13 +113,13 @@
 			*(.rodata.*)
 			*(.glue_7)
 			*(.glue_7t)
+		. = ALIGN(4);
 		*(.got)			/* Global offset table		*/
+			ARM_CPU_KEEP(PROC_INFO)
 	}
 
 	RO_DATA(PAGE_SIZE)
 
-	_etext = .;			/* End of text and rodata section */
-
 #ifdef CONFIG_ARM_UNWIND
 	/*
 	 * Stack unwinding tables
@@ -123,6 +137,8 @@
 	}
 #endif
 
+	_etext = .;			/* End of text and rodata section */
+
 #ifdef CONFIG_XIP_KERNEL
 	__data_loc = ALIGN(4);		/* location in binary */
 	. = PAGE_OFFSET + TEXT_OFFSET;
@@ -237,6 +253,12 @@
 
 	/* Default discards */
 	DISCARDS
+
+#ifndef CONFIG_SMP_ON_UP
+	/DISCARD/ : {
+		*(.alt.smp.init)
+	}
+#endif
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/arm/lib/findbit.S linux-libre-2.6.37-gnu/arch/arm/lib/findbit.S
--- linux-libre-2.6.36-gnu/arch/arm/lib/findbit.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/lib/findbit.S	2011-01-04 19:50:19.000000000 -0500
@@ -174,8 +174,8 @@
  */
 .L_found:
 #if __LINUX_ARM_ARCH__ >= 5
-		rsb	r1, r3, #0
-		and	r3, r3, r1
+		rsb	r0, r3, #0
+		and	r3, r3, r0
 		clz	r3, r3
 		rsb	r3, r3, #31
 		add	r0, r2, r3
@@ -190,5 +190,7 @@
 		addeq	r2, r2, #1
 		mov	r0, r2
 #endif
+		cmp	r1, r0			@ Clamp to maxbit
+		movlo	r0, r1
 		mov	pc, lr
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/aaed2000.c linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/aaed2000.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/aaed2000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/aaed2000.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,8 +95,6 @@
 
 MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
 	/* Maintainer: Nicolas Bellido Y Ortega */
-	.phys_io	= PIO_BASE,
-	.io_pg_offst	= ((VIO_BASE) >> 18) & 0xfffc,
 	.map_io		= aaed2000_map_io,
 	.init_irq	= aaed2000_init_irq,
 	.timer		= &aaec2000_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,12 +10,10 @@
  */
 
 #include "hardware.h"
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x80000000		@ physical
-		movne	\rx, #io_p2v(0x80000000)	@ virtual
-		orr	\rx, \rx, #0x00000800
+		.macro	addruart, rp, rv
+		mov	\rp, 0x00000800
+		orr	\rv, \rp, #io_p2v(0x80000000)	@ virtual
+		orr	\rp, \rp, #0x80000000		@ physical
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-aaec2000/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-aaec2000/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END		(PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END		0xd0000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91rm9200_devices.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91rm9200_devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91rm9200_devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91rm9200_devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -1106,51 +1106,6 @@
 static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
 struct platform_device *atmel_default_console_device;	/* the serial console device */
 
-void __init __deprecated at91_init_serial(struct at91_uart_config *config)
-{
-	int i;
-
-	/* Fill in list of supported UARTs */
-	for (i = 0; i < config->nr_tty; i++) {
-		switch (config->tty_map[i]) {
-			case 0:
-				configure_usart0_pins(ATMEL_UART_CTS | ATMEL_UART_RTS);
-				at91_uarts[i] = &at91rm9200_uart0_device;
-				at91_clock_associate("usart0_clk", &at91rm9200_uart0_device.dev, "usart");
-				break;
-			case 1:
-				configure_usart1_pins(ATMEL_UART_CTS | ATMEL_UART_RTS | ATMEL_UART_DSR | ATMEL_UART_DTR | ATMEL_UART_DCD | ATMEL_UART_RI);
-				at91_uarts[i] = &at91rm9200_uart1_device;
-				at91_clock_associate("usart1_clk", &at91rm9200_uart1_device.dev, "usart");
-				break;
-			case 2:
-				configure_usart2_pins(0);
-				at91_uarts[i] = &at91rm9200_uart2_device;
-				at91_clock_associate("usart2_clk", &at91rm9200_uart2_device.dev, "usart");
-				break;
-			case 3:
-				configure_usart3_pins(0);
-				at91_uarts[i] = &at91rm9200_uart3_device;
-				at91_clock_associate("usart3_clk", &at91rm9200_uart3_device.dev, "usart");
-				break;
-			case 4:
-				configure_dbgu_pins();
-				at91_uarts[i] = &at91rm9200_dbgu_device;
-				at91_clock_associate("mck", &at91rm9200_dbgu_device.dev, "usart");
-				break;
-			default:
-				continue;
-		}
-		at91_uarts[i]->id = i;		/* update ID number to mapped ID */
-	}
-
-	/* Set serial console device */
-	if (config->console_tty < ATMEL_MAX_UART)
-		atmel_default_console_device = at91_uarts[config->console_tty];
-	if (!atmel_default_console_device)
-		printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
 	struct platform_device *pdev;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9260.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9260.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9260.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9260.c	2011-01-04 19:50:19.000000000 -0500
@@ -279,11 +279,6 @@
 	}
 };
 
-static void at91sam9260_reset(void)
-{
-	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9260_poweroff(void)
 {
 	at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -327,7 +322,7 @@
 	else
 		iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
 
-	at91_arch_reset = at91sam9260_reset;
+	at91_arch_reset = at91sam9_alt_reset;
 	pm_power_off = at91sam9260_poweroff;
 	at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
 			| (1 << AT91SAM9260_ID_IRQ2);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9261.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9261.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9261.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9261.c	2011-01-04 19:50:19.000000000 -0500
@@ -257,11 +257,6 @@
 	}
 };
 
-static void at91sam9261_reset(void)
-{
-	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9261_poweroff(void)
 {
 	at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -283,7 +278,7 @@
 		iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
 
 
-	at91_arch_reset = at91sam9261_reset;
+	at91_arch_reset = at91sam9_alt_reset;
 	pm_power_off = at91sam9261_poweroff;
 	at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
 			| (1 << AT91SAM9261_ID_IRQ2);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9263.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9263.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9263.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9263.c	2011-01-04 19:50:19.000000000 -0500
@@ -269,11 +269,6 @@
 	}
 };
 
-static void at91sam9263_reset(void)
-{
-	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9263_poweroff(void)
 {
 	at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -289,7 +284,7 @@
 	/* Map peripherals */
 	iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
 
-	at91_arch_reset = at91sam9263_reset;
+	at91_arch_reset = at91sam9_alt_reset;
 	pm_power_off = at91sam9263_poweroff;
 	at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9_alt_reset.S linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9_alt_reset.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9_alt_reset.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9_alt_reset.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+/*
+ * reset AT91SAM9G20 as per errata
+ *
+ * (C) BitBox Ltd 2010
+ *
+ * unless the SDRAM is cleanly shutdown before we hit the
+ * reset register it can be left driving the data bus and
+ * killing the chance of a subsequent boot from NAND
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+#include <mach/hardware.h>
+#include <mach/at91sam9_sdramc.h>
+#include <mach/at91_rstc.h>
+
+			.arm
+
+			.globl	at91sam9_alt_reset
+
+at91sam9_alt_reset:	mrc	p15, 0, r0, c1, c0, 0
+			orr	r0, r0, #CR_I
+			mcr	p15, 0, r0, c1, c0, 0		@ enable I-cache
+
+			ldr	r0, .at91_va_base_sdramc	@ preload constants
+			ldr	r1, .at91_va_base_rstc_cr
+
+			mov	r2, #1
+			mov	r3, #AT91_SDRAMC_LPCB_POWER_DOWN
+			ldr	r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST
+
+			.balign	32				@ align to cache line
+
+			str	r2, [r0, #AT91_SDRAMC_TR]	@ disable SDRAM access
+			str	r3, [r0, #AT91_SDRAMC_LPR]	@ power down SDRAM
+			str	r4, [r1]			@ reset processor
+
+			b	.
+
+.at91_va_base_sdramc:
+	.word AT91_VA_BASE_SYS + AT91_SDRAMC0
+.at91_va_base_rstc_cr:
+	.word AT91_VA_BASE_SYS + AT91_RSTC_CR
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9g45_devices.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9g45_devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9g45_devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9g45_devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
+#include <linux/atmel-mci.h>
 
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
@@ -25,6 +26,7 @@
 #include <mach/at91sam9g45_matrix.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at_hdmac.h>
+#include <mach/atmel-mci.h>
 
 #include "generic.h"
 
@@ -349,6 +351,169 @@
 #endif
 
 
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_MCI0,
+		.end	= AT91SAM9G45_BASE_MCI0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_MCI0,
+		.end	= AT91SAM9G45_ID_MCI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9g45_mmc0_device = {
+	.name		= "atmel_mci",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &mmc0_data,
+	},
+	.resource	= mmc0_resources,
+	.num_resources	= ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_MCI1,
+		.end	= AT91SAM9G45_BASE_MCI1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_MCI1,
+		.end	= AT91SAM9G45_ID_MCI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9g45_mmc1_device = {
+	.name		= "atmel_mci",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= DMA_BIT_MASK(32),
+				.platform_data		= &mmc1_data,
+	},
+	.resource	= mmc1_resources,
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+};
+
+/* Consider only one slot : slot 0 */
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+{
+
+	if (!data)
+		return;
+
+	/* Must have at least one usable slot */
+	if (!data->slot[0].bus_width)
+		return;
+
+#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
+	{
+	struct at_dma_slave	*atslave;
+	struct mci_dma_data	*alt_atslave;
+
+	alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
+	atslave = &alt_atslave->sdata;
+
+	/* DMA slave channel configuration */
+	atslave->dma_dev = &at_hdmac_device.dev;
+	atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT;
+	atslave->cfg = ATC_FIFOCFG_HALFFIFO
+			| ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
+	atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
+	if (mmc_id == 0)	/* MCI0 */
+		atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
+			      | ATC_DST_PER(AT_DMA_ID_MCI0);
+
+	else			/* MCI1 */
+		atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
+			      | ATC_DST_PER(AT_DMA_ID_MCI1);
+
+	data->dma_slave = alt_atslave;
+	}
+#endif
+
+
+	/* input/irq */
+	if (data->slot[0].detect_pin) {
+		at91_set_gpio_input(data->slot[0].detect_pin, 1);
+		at91_set_deglitch(data->slot[0].detect_pin, 1);
+	}
+	if (data->slot[0].wp_pin)
+		at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+	if (mmc_id == 0) {		/* MCI0 */
+
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA0, 0);
+
+		/* CMD */
+		at91_set_A_periph(AT91_PIN_PA1, 1);
+
+		/* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+		at91_set_A_periph(AT91_PIN_PA2, 1);
+		if (data->slot[0].bus_width == 4) {
+			at91_set_A_periph(AT91_PIN_PA3, 1);
+			at91_set_A_periph(AT91_PIN_PA4, 1);
+			at91_set_A_periph(AT91_PIN_PA5, 1);
+			if (data->slot[0].bus_width == 8) {
+				at91_set_A_periph(AT91_PIN_PA6, 1);
+				at91_set_A_periph(AT91_PIN_PA7, 1);
+				at91_set_A_periph(AT91_PIN_PA8, 1);
+				at91_set_A_periph(AT91_PIN_PA9, 1);
+			}
+		}
+
+		mmc0_data = *data;
+		at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
+		platform_device_register(&at91sam9g45_mmc0_device);
+
+	} else {			/* MCI1 */
+
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA31, 0);
+
+		/* CMD */
+		at91_set_A_periph(AT91_PIN_PA22, 1);
+
+		/* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+		at91_set_A_periph(AT91_PIN_PA23, 1);
+		if (data->slot[0].bus_width == 4) {
+			at91_set_A_periph(AT91_PIN_PA24, 1);
+			at91_set_A_periph(AT91_PIN_PA25, 1);
+			at91_set_A_periph(AT91_PIN_PA26, 1);
+			if (data->slot[0].bus_width == 8) {
+				at91_set_A_periph(AT91_PIN_PA27, 1);
+				at91_set_A_periph(AT91_PIN_PA28, 1);
+				at91_set_A_periph(AT91_PIN_PA29, 1);
+				at91_set_A_periph(AT91_PIN_PA30, 1);
+			}
+		}
+
+		mmc1_data = *data;
+		at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
+		platform_device_register(&at91sam9g45_mmc1_device);
+
+	}
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  NAND / SmartMedia
  * -------------------------------------------------------------------- */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9rl.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9rl.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/at91sam9rl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/at91sam9rl.c	2011-01-04 19:50:19.000000000 -0500
@@ -242,11 +242,6 @@
 	}
 };
 
-static void at91sam9rl_reset(void)
-{
-	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
 static void at91sam9rl_poweroff(void)
 {
 	at91_sys_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
@@ -281,7 +276,7 @@
 	/* Map SRAM */
 	iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
 
-	at91_arch_reset = at91sam9rl_reset;
+	at91_arch_reset = at91sam9_alt_reset;
 	pm_power_off = at91sam9rl_poweroff;
 	at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-1arm.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-1arm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-1arm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-1arm.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,24 +39,24 @@
 #include "generic.h"
 
 
-/*
- * Serial port configuration.
- *    0 .. 3 = USART0 .. USART3
- *    4      = DBGU
- */
-static struct at91_uart_config __initdata onearm_uart_config = {
-	.console_tty	= 0,				/* ttyS0 */
-	.nr_tty		= 3,
-	.tty_map	= { 4, 0, 1, -1, -1 },		/* ttyS0, ..., ttyS4 */
-};
-
 static void __init onearm_map_io(void)
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91rm9200_initialize(18432000, AT91RM9200_PQFP);
 
-	/* Setup the serial ports and console */
-	at91_init_serial(&onearm_uart_config);
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
 }
 
 static void __init onearm_init_irq(void)
@@ -92,8 +92,6 @@
 
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= onearm_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-afeb-9260v1.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-afeb-9260v1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-afeb-9260v1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-afeb-9260v1.c	2011-01-04 19:50:19.000000000 -0500
@@ -218,8 +218,6 @@
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
 	/* Maintainer: Sergey Lapin <slapin@ossfans.org> */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= afeb9260_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-at572d940hf_ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-at572d940hf_ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-at572d940hf_ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-at572d940hf_ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -216,7 +216,7 @@
 /*	.rdy_pin	= AT91_PIN_PC16, */
 	.enable_pin	= AT91_PIN_PA15,
 	.partition_info	= nand_partitions,
-#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
 	.bus_width_16	= 1,
 #else
 	.bus_width_16	= 0,
@@ -318,8 +318,6 @@
 
 MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB")
 	/* Maintainer: Atmel <costa.antonior@gmail.com> */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= eb_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cam60.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cam60.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cam60.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cam60.c	2011-01-04 19:50:19.000000000 -0500
@@ -198,8 +198,6 @@
 
 MACHINE_START(CAM60, "KwikByte CAM60")
 	/* Maintainer: KwikByte */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= cam60_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cap9adk.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cap9adk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cap9adk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cap9adk.c	2011-01-04 19:50:19.000000000 -0500
@@ -399,8 +399,6 @@
 
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
 	/* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= cap9adk_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-carmeva.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-carmeva.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-carmeva.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-carmeva.c	2011-01-04 19:50:19.000000000 -0500
@@ -162,8 +162,6 @@
 
 MACHINE_START(CARMEVA, "Carmeva")
 	/* Maintainer: Conitec Datasystems */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= carmeva_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cpu9krea.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cpu9krea.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cpu9krea.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cpu9krea.c	2011-01-04 19:50:19.000000000 -0500
@@ -375,8 +375,6 @@
 MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
 	/* Maintainer: Eric Benard - EUKREA Electromatique */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= cpu9krea_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cpuat91.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cpuat91.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-cpuat91.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-cpuat91.c	2011-01-04 19:50:19.000000000 -0500
@@ -175,8 +175,6 @@
 
 MACHINE_START(CPUAT91, "Eukrea")
 	/* Maintainer: Eric Benard - EUKREA Electromatique */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= cpuat91_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-csb337.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-csb337.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-csb337.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-csb337.c	2011-01-04 19:50:19.000000000 -0500
@@ -257,8 +257,6 @@
 
 MACHINE_START(CSB337, "Cogent CSB337")
 	/* Maintainer: Bill Gatliff */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= csb337_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-csb637.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-csb637.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-csb637.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-csb637.c	2011-01-04 19:50:19.000000000 -0500
@@ -138,8 +138,6 @@
 
 MACHINE_START(CSB637, "Cogent CSB637")
 	/* Maintainer: Bill Gatliff */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= csb637_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-dk.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-dk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-dk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-dk.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,235 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-dk.c
- *
- *  Copyright (C) 2005 SAN People
- *
- *  Epson S1D framebuffer glue code is:
- *     Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91rm9200_mc.h>
-
-#include "generic.h"
-
-
-static void __init dk_map_io(void)
-{
-	/* Initialize processor: 18.432 MHz crystal */
-	at91rm9200_initialize(18432000, AT91RM9200_BGA);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-static void __init dk_init_irq(void)
-{
-	at91rm9200_init_interrupts(NULL);
-}
-
-static struct at91_eth_data __initdata dk_eth_data = {
-	.phy_irq_pin	= AT91_PIN_PC4,
-	.is_rmii	= 1,
-};
-
-static struct at91_usbh_data __initdata dk_usbh_data = {
-	.ports		= 2,
-};
-
-static struct at91_udc_data __initdata dk_udc_data = {
-	.vbus_pin	= AT91_PIN_PD4,
-	.pullup_pin	= AT91_PIN_PD5,
-};
-
-static struct at91_cf_data __initdata dk_cf_data = {
-	.det_pin	= AT91_PIN_PB0,
-	.rst_pin	= AT91_PIN_PC5,
-	// .irq_pin	= ... not connected
-	// .vcc_pin	= ... always powered
-};
-
-static struct at91_mmc_data __initdata dk_mmc_data = {
-	.slot_b		= 0,
-	.wire4		= 1,
-};
-
-static struct spi_board_info dk_spi_devices[] = {
-	{	/* DataFlash chip */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 0,
-		.max_speed_hz	= 15 * 1000 * 1000,
-	},
-	{	/* UR6HCPS2-SP40 PS2-to-SPI adapter */
-		.modalias	= "ur6hcps2",
-		.chip_select	= 1,
-		.max_speed_hz	= 250 *  1000,
-	},
-	{	/* TLV1504 ADC, 4 channels, 10 bits; one is a temp sensor */
-		.modalias	= "tlv1504",
-		.chip_select	= 2,
-		.max_speed_hz	= 20 * 1000 * 1000,
-	},
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-	{	/* DataFlash card */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 3,
-		.max_speed_hz	= 15 * 1000 * 1000,
-	}
-#endif
-};
-
-static struct i2c_board_info __initdata dk_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("ics1523", 0x26),
-	},
-	{
-		I2C_BOARD_INFO("x9429", 0x28),
-	},
-	{
-		I2C_BOARD_INFO("24c1024", 0x50),
-	}
-};
-
-static struct mtd_partition __initdata dk_nand_partition[] = {
-	{
-		.name	= "NAND Partition 1",
-		.offset	= 0,
-		.size	= MTDPART_SIZ_FULL,
-	},
-};
-
-static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
-{
-	*num_partitions = ARRAY_SIZE(dk_nand_partition);
-	return dk_nand_partition;
-}
-
-static struct atmel_nand_data __initdata dk_nand_data = {
-	.ale		= 22,
-	.cle		= 21,
-	.det_pin	= AT91_PIN_PB1,
-	.rdy_pin	= AT91_PIN_PC2,
-	// .enable_pin	= ... not there
-	.partition_info	= nand_partitions,
-};
-
-#define DK_FLASH_BASE	AT91_CHIPSELECT_0
-#define DK_FLASH_SIZE	SZ_2M
-
-static struct physmap_flash_data dk_flash_data = {
-	.width		= 2,
-};
-
-static struct resource dk_flash_resource = {
-	.start		= DK_FLASH_BASE,
-	.end		= DK_FLASH_BASE + DK_FLASH_SIZE - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device dk_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-				.platform_data	= &dk_flash_data,
-			},
-	.resource	= &dk_flash_resource,
-	.num_resources	= 1,
-};
-
-static struct gpio_led dk_leds[] = {
-	{
-		.name			= "led0",
-		.gpio			= AT91_PIN_PB2,
-		.active_low		= 1,
-		.default_trigger	= "heartbeat",
-	}
-};
-
-static void __init dk_board_init(void)
-{
-	/* Serial */
-	at91_add_device_serial();
-	/* Ethernet */
-	at91_add_device_eth(&dk_eth_data);
-	/* USB Host */
-	at91_add_device_usbh(&dk_usbh_data);
-	/* USB Device */
-	at91_add_device_udc(&dk_udc_data);
-	at91_set_multi_drive(dk_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
-	/* Compact Flash */
-	at91_add_device_cf(&dk_cf_data);
-	/* I2C */
-	at91_add_device_i2c(dk_i2c_devices, ARRAY_SIZE(dk_i2c_devices));
-	/* SPI */
-	at91_add_device_spi(dk_spi_devices, ARRAY_SIZE(dk_spi_devices));
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-	/* DataFlash card */
-	at91_set_gpio_output(AT91_PIN_PB7, 0);
-#else
-	/* MMC */
-	at91_set_gpio_output(AT91_PIN_PB7, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(0, &dk_mmc_data);
-#endif
-	/* NAND */
-	at91_add_device_nand(&dk_nand_data);
-	/* NOR Flash */
-	platform_device_register(&dk_flash);
-	/* LEDs */
-	at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds));
-	/* VGA */
-//	dk_add_device_video();
-}
-
-MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
-	/* Maintainer: SAN People/Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
-	.boot_params	= AT91_SDRAM_BASE + 0x100,
-	.timer		= &at91rm9200_timer,
-	.map_io		= dk_map_io,
-	.init_irq	= dk_init_irq,
-	.init_machine	= dk_board_init,
-MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-eb9200.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-eb9200.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-eb9200.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-eb9200.c	2011-01-04 19:50:19.000000000 -0500
@@ -120,8 +120,6 @@
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= eb9200_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-ecbat91.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-ecbat91.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-ecbat91.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-ecbat91.c	2011-01-04 19:50:19.000000000 -0500
@@ -168,8 +168,6 @@
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
 	/* Maintainer: emQbit.com */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= ecb_at91map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-eco920.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-eco920.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-eco920.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-eco920.c	2011-01-04 19:50:19.000000000 -0500
@@ -148,8 +148,6 @@
 
 MACHINE_START(ECO920, "eco920")
 	/* Maintainer: Sascha Hauer */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= eco920_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-ek.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,201 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-ek.c
- *
- *  Copyright (C) 2005 SAN People
- *
- *  Epson S1D framebuffer glue code is:
- *     Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91rm9200_mc.h>
-
-#include "generic.h"
-
-
-static void __init ek_map_io(void)
-{
-	/* Initialize processor: 18.432 MHz crystal */
-	at91rm9200_initialize(18432000, AT91RM9200_BGA);
-
-	/* Setup the LEDs */
-	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
-	/* DBGU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-static void __init ek_init_irq(void)
-{
-	at91rm9200_init_interrupts(NULL);
-}
-
-static struct at91_eth_data __initdata ek_eth_data = {
-	.phy_irq_pin	= AT91_PIN_PC4,
-	.is_rmii	= 1,
-};
-
-static struct at91_usbh_data __initdata ek_usbh_data = {
-	.ports		= 2,
-};
-
-static struct at91_udc_data __initdata ek_udc_data = {
-	.vbus_pin	= AT91_PIN_PD4,
-	.pullup_pin	= AT91_PIN_PD5,
-};
-
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.det_pin	= AT91_PIN_PB27,
-	.slot_b		= 0,
-	.wire4		= 1,
-	.wp_pin		= AT91_PIN_PA17,
-};
-
-static struct spi_board_info ek_spi_devices[] = {
-	{	/* DataFlash chip */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 0,
-		.max_speed_hz	= 15 * 1000 * 1000,
-	},
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-	{	/* DataFlash card */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 3,
-		.max_speed_hz	= 15 * 1000 * 1000,
-	},
-#endif
-};
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("ics1523", 0x26),
-	},
-	{
-		I2C_BOARD_INFO("dac3550", 0x4d),
-	}
-};
-
-#define EK_FLASH_BASE	AT91_CHIPSELECT_0
-#define EK_FLASH_SIZE	SZ_2M
-
-static struct physmap_flash_data ek_flash_data = {
-	.width		= 2,
-};
-
-static struct resource ek_flash_resource = {
-	.start		= EK_FLASH_BASE,
-	.end		= EK_FLASH_BASE + EK_FLASH_SIZE - 1,
-	.flags		= IORESOURCE_MEM,
-};
-
-static struct platform_device ek_flash = {
-	.name		= "physmap-flash",
-	.id		= 0,
-	.dev		= {
-				.platform_data	= &ek_flash_data,
-			},
-	.resource	= &ek_flash_resource,
-	.num_resources	= 1,
-};
-
-static struct gpio_led ek_leds[] = {
-	{	/* "user led 1", DS2 */
-		.name			= "green",
-		.gpio			= AT91_PIN_PB0,
-		.active_low		= 1,
-		.default_trigger	= "mmc0",
-	},
-	{	/* "user led 2", DS4 */
-		.name			= "yellow",
-		.gpio			= AT91_PIN_PB1,
-		.active_low		= 1,
-		.default_trigger	= "heartbeat",
-	},
-	{	/* "user led 3", DS6 */
-		.name			= "red",
-		.gpio			= AT91_PIN_PB2,
-		.active_low		= 1,
-	}
-};
-
-static void __init ek_board_init(void)
-{
-	/* Serial */
-	at91_add_device_serial();
-	/* Ethernet */
-	at91_add_device_eth(&ek_eth_data);
-	/* USB Host */
-	at91_add_device_usbh(&ek_usbh_data);
-	/* USB Device */
-	at91_add_device_udc(&ek_udc_data);
-	at91_set_multi_drive(ek_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
-	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
-	/* SPI */
-	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-	/* DataFlash card */
-	at91_set_gpio_output(AT91_PIN_PB22, 0);
-#else
-	/* MMC */
-	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(0, &ek_mmc_data);
-#endif
-	/* NOR Flash */
-	platform_device_register(&ek_flash);
-	/* LEDs */
-	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
-	/* VGA */
-//	ek_add_device_video();
-}
-
-MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
-	/* Maintainer: SAN People/Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
-	.boot_params	= AT91_SDRAM_BASE + 0x100,
-	.timer		= &at91rm9200_timer,
-	.map_io		= ek_map_io,
-	.init_irq	= ek_init_irq,
-	.init_machine	= ek_board_init,
-MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-flexibity.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-flexibity.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-flexibity.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-flexibity.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,162 @@
+/*
+ * linux/arch/arm/mach-at91/board-flexibity.c
+ *
+ *  Copyright (C) 2010 Flexibity
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+
+#include "generic.h"
+
+static void __init flexibity_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91sam9260_initialize(18432000);
+
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init flexibity_init_irq(void)
+{
+	at91sam9260_init_interrupts(NULL);
+}
+
+/* USB Host port */
+static struct at91_usbh_data __initdata flexibity_usbh_data = {
+	.ports		= 2,
+};
+
+/* USB Device port */
+static struct at91_udc_data __initdata flexibity_udc_data = {
+	.vbus_pin	= AT91_PIN_PC5,
+	.pullup_pin	= 0,		/* pull-up driven by UDC */
+};
+
+/* SPI devices */
+static struct spi_board_info flexibity_spi_devices[] = {
+	{	/* DataFlash chip */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 1,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+};
+
+/* MCI (SD/MMC) */
+static struct at91_mmc_data __initdata flexibity_mmc_data = {
+	.slot_b		= 0,
+	.wire4		= 1,
+	.det_pin	= AT91_PIN_PC9,
+	.wp_pin		= AT91_PIN_PC4,
+};
+
+/* LEDs */
+static struct gpio_led flexibity_leds[] = {
+	{
+		.name			= "usb1:green",
+		.gpio			= AT91_PIN_PA12,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb1:red",
+		.gpio			= AT91_PIN_PA13,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb2:green",
+		.gpio			= AT91_PIN_PB26,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb2:red",
+		.gpio			= AT91_PIN_PB27,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb3:green",
+		.gpio			= AT91_PIN_PC8,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb3:red",
+		.gpio			= AT91_PIN_PC6,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb4:green",
+		.gpio			= AT91_PIN_PB4,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	},
+	{
+		.name			= "usb4:red",
+		.gpio			= AT91_PIN_PB5,
+		.active_low		= 1,
+		.default_trigger	= "default-on",
+	}
+};
+
+static void __init flexibity_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	at91_add_device_usbh(&flexibity_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&flexibity_udc_data);
+	/* SPI */
+	at91_add_device_spi(flexibity_spi_devices,
+		ARRAY_SIZE(flexibity_spi_devices));
+	/* MMC */
+	at91_add_device_mmc(0, &flexibity_mmc_data);
+	/* LEDs */
+	at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
+}
+
+MACHINE_START(FLEXIBITY, "Flexibity Connect")
+	/* Maintainer: Maxim Osipov */
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= flexibity_map_io,
+	.init_irq	= flexibity_init_irq,
+	.init_machine	= flexibity_board_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-kafa.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-kafa.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-kafa.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-kafa.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,17 +39,6 @@
 #include "generic.h"
 
 
-/*
- * Serial port configuration.
- *    0 .. 3 = USART0 .. USART3
- *    4      = DBGU
- */
-static struct at91_uart_config __initdata kafa_uart_config = {
-	.console_tty	= 0,				/* ttyS0 */
-	.nr_tty		= 2,
-	.tty_map	= { 4, 0, -1, -1, -1 }		/* ttyS0, ..., ttyS4 */
-};
-
 static void __init kafa_map_io(void)
 {
 	/* Initialize processor: 18.432 MHz crystal */
@@ -58,8 +47,14 @@
 	/* Set up the LEDs */
 	at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
 
-	/* Setup the serial ports and console */
-	at91_init_serial(&kafa_uart_config);
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+	at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
 }
 
 static void __init kafa_init_irq(void)
@@ -99,8 +94,6 @@
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
 	/* Maintainer: Sergei Sharonov */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= kafa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-kb9202.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-kb9202.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-kb9202.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-kb9202.c	2011-01-04 19:50:19.000000000 -0500
@@ -136,8 +136,6 @@
 
 MACHINE_START(KB9200, "KB920x")
 	/* Maintainer: KwikByte, Inc. */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= kb9202_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-neocore926.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-neocore926.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-neocore926.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-neocore926.c	2011-01-04 19:50:19.000000000 -0500
@@ -387,8 +387,6 @@
 
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
 	/* Maintainer: ADENEO */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= neocore926_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-pcontrol-g20.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-pcontrol-g20.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-pcontrol-g20.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-pcontrol-g20.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,230 @@
+/*
+ *  Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
+ *                     taskit GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * copied and adjusted from board-stamp9g20.c
+ * by Peter Gsellmann <pgsellmann@portner-elektronik.at>
+ */
+
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/w1-gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/board.h>
+#include <mach/at91sam9_smc.h>
+#include <mach/stamp9g20.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init pcontrol_g20_map_io(void)
+{
+	stamp9g20_map_io();
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+						| ATMEL_UART_RTS);
+
+	/* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485  X5 */
+	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+						| ATMEL_UART_RTS);
+
+	/* USART2 on ttyS3. (Rx, Tx)  9bit-Bus  Multidrop-mode  X4 */
+	at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
+}
+
+
+static void __init init_irq(void)
+{
+	at91sam9260_init_interrupts(NULL);
+}
+
+
+static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
+	.ncs_read_setup		= 16,
+	.nrd_setup		= 18,
+	.ncs_write_setup	= 16,
+	.nwe_setup		= 18,
+
+	.ncs_read_pulse		= 63,
+	.nrd_pulse		= 55,
+	.ncs_write_pulse	= 63,
+	.nwe_pulse		= 55,
+
+	.read_cycle		= 127,
+	.write_cycle		= 127,
+
+	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+			| AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+			| AT91_SMC_DBW_8 | AT91_SMC_PS_4
+			| AT91_SMC_TDFMODE,
+	.tdf_cycles		= 3,
+}, {
+	.ncs_read_setup		= 0,
+	.nrd_setup		= 0,
+	.ncs_write_setup	= 0,
+	.nwe_setup		= 1,
+
+	.ncs_read_pulse		= 8,
+	.nrd_pulse		= 8,
+	.ncs_write_pulse	= 5,
+	.nwe_pulse		= 4,
+
+	.read_cycle		= 8,
+	.write_cycle		= 7,
+
+	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+			| AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
+			| AT91_SMC_DBW_16 | AT91_SMC_PS_8
+			| AT91_SMC_TDFMODE,
+	.tdf_cycles		= 1,
+} };
+
+static void __init add_device_pcontrol(void)
+{
+	/* configure chip-select 4 (IO compatible to 8051  X4 ) */
+	sam9_smc_configure(4, &pcontrol_smc_config[0]);
+	/* configure chip-select 7 (FerroRAM 256KiBx16bit MR2A16A  D4 ) */
+	sam9_smc_configure(7, &pcontrol_smc_config[1]);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata usbh_data = {
+	.ports		= 2,
+};
+
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata pcontrol_g20_udc_data = {
+	.vbus_pin	= AT91_PIN_PA22,	/* Detect +5V bus voltage */
+	.pullup_pin	= AT91_PIN_PA4,		/* K-state, active low */
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata macb_data = {
+	.phy_irq_pin	= AT91_PIN_PA28,
+	.is_rmii	= 1,
+};
+
+
+/*
+ * I2C devices: eeprom and phy/switch
+ */
+static struct i2c_board_info __initdata pcontrol_g20_i2c_devices[] = {
+{		/* D7  address width=2, 8KiB */
+	I2C_BOARD_INFO("24c64", 0x50)
+}, {		/* D8  address width=1, 1 byte has 32 bits! */
+	I2C_BOARD_INFO("lan9303", 0x0a)
+}, };
+
+
+/*
+ * LEDs
+ */
+static struct gpio_led pcontrol_g20_leds[] = {
+	{
+		.name			= "LED1",	/* red  H5 */
+		.gpio			= AT91_PIN_PB18,
+		.active_low		= 1,
+		.default_trigger	= "none",	/* supervisor */
+	}, {
+		.name			= "LED2",	/* yellow  H7 */
+		.gpio			= AT91_PIN_PB19,
+		.active_low		= 1,
+		.default_trigger	= "mmc0",	/* SD-card activity */
+	}, {
+		.name			= "LED3",	/* green  H2 */
+		.gpio			= AT91_PIN_PB20,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",	/* blinky */
+	}, {
+		.name			= "LED4",	/* red  H3 */
+		.gpio			= AT91_PIN_PC6,
+		.active_low		= 1,
+		.default_trigger	= "none",	/* connection lost */
+	}, {
+		.name			= "LED5",	/* yellow  H6 */
+		.gpio			= AT91_PIN_PC7,
+		.active_low		= 1,
+		.default_trigger	= "none",	/* unsent data */
+	}, {
+		.name			= "LED6",	/* green  H1 */
+		.gpio			= AT91_PIN_PC9,
+		.active_low		= 1,
+		.default_trigger	= "none",	/* snafu */
+	}
+};
+
+
+/*
+ * SPI devices
+ */
+static struct spi_board_info pcontrol_g20_spi_devices[] = {
+	{
+		.modalias	= "spidev",	/* HMI port  X4 */
+		.chip_select	= 1,
+		.max_speed_hz	= 50 * 1000 * 1000,
+		.bus_num	= 0,
+	}, {
+		.modalias	= "spidev",	/* piggyback  A2 */
+		.chip_select	= 0,
+		.max_speed_hz	= 50 * 1000 * 1000,
+		.bus_num	= 1,
+	},
+};
+
+
+static void __init pcontrol_g20_board_init(void)
+{
+	stamp9g20_board_init();
+	at91_add_device_usbh(&usbh_data);
+	at91_add_device_eth(&macb_data);
+	at91_add_device_i2c(pcontrol_g20_i2c_devices,
+		ARRAY_SIZE(pcontrol_g20_i2c_devices));
+	add_device_pcontrol();
+	at91_add_device_spi(pcontrol_g20_spi_devices,
+		ARRAY_SIZE(pcontrol_g20_spi_devices));
+	at91_add_device_udc(&pcontrol_g20_udc_data);
+	at91_gpio_leds(pcontrol_g20_leds,
+		ARRAY_SIZE(pcontrol_g20_leds));
+	/* piggyback  A2 */
+	at91_set_gpio_output(AT91_PIN_PB31, 1);
+}
+
+
+MACHINE_START(PCONTROL_G20, "PControl G20")
+	/* Maintainer: pgsellmann@portner-elektronik.at */
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= pcontrol_g20_map_io,
+	.init_irq	= init_irq,
+	.init_machine	= pcontrol_g20_board_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-picotux200.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-picotux200.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-picotux200.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-picotux200.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,24 +43,21 @@
 #include "generic.h"
 
 
-/*
- * Serial port configuration.
- *    0 .. 3 = USART0 .. USART3
- *    4      = DBGU
- */
-static struct at91_uart_config __initdata picotux200_uart_config = {
-	.console_tty	= 0,				/* ttyS0 */
-	.nr_tty		= 2,
-	.tty_map	= { 4, 1, -1, -1, -1 }		/* ttyS0, ..., ttyS4 */
-};
-
 static void __init picotux200_map_io(void)
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91rm9200_initialize(18432000, AT91RM9200_BGA);
 
-	/* Setup the serial ports and console */
-	at91_init_serial(&picotux200_uart_config);
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			  | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			  | ATMEL_UART_RI);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
 }
 
 static void __init picotux200_init_irq(void)
@@ -77,11 +74,6 @@
 	.ports		= 1,
 };
 
-// static struct at91_udc_data __initdata picotux200_udc_data = {
-// 	.vbus_pin	= AT91_PIN_PD4,
-// 	.pullup_pin	= AT91_PIN_PD5,
-// };
-
 static struct at91_mmc_data __initdata picotux200_mmc_data = {
 	.det_pin	= AT91_PIN_PB27,
 	.slot_b		= 0,
@@ -89,21 +81,6 @@
 	.wp_pin		= AT91_PIN_PA17,
 };
 
-// static struct spi_board_info picotux200_spi_devices[] = {
-// 	{	/* DataFlash chip */
-// 		.modalias	= "mtd_dataflash",
-// 		.chip_select	= 0,
-// 		.max_speed_hz	= 15 * 1000 * 1000,
-// 	},
-// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-// 	{	/* DataFlash card */
-// 		.modalias	= "mtd_dataflash",
-// 		.chip_select	= 3,
-// 		.max_speed_hz	= 15 * 1000 * 1000,
-// 	},
-// #endif
-// };
-
 #define PICOTUX200_FLASH_BASE	AT91_CHIPSELECT_0
 #define PICOTUX200_FLASH_SIZE	SZ_4M
 
@@ -135,29 +112,17 @@
 	at91_add_device_eth(&picotux200_eth_data);
 	/* USB Host */
 	at91_add_device_usbh(&picotux200_usbh_data);
-	/* USB Device */
-	// at91_add_device_udc(&picotux200_udc_data);
-	// at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
 	/* I2C */
 	at91_add_device_i2c(NULL, 0);
-	/* SPI */
-	// at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-	/* DataFlash card */
-	at91_set_gpio_output(AT91_PIN_PB22, 0);
-#else
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
 	at91_add_device_mmc(0, &picotux200_mmc_data);
-#endif
 	/* NOR Flash */
 	platform_device_register(&picotux200_flash);
 }
 
 MACHINE_START(PICOTUX2XX, "picotux 200")
 	/* Maintainer: Kleinhenz Elektronik GmbH */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= picotux200_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-qil-a9260.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-qil-a9260.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-qil-a9260.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-qil-a9260.c	2011-01-04 19:50:19.000000000 -0500
@@ -268,8 +268,6 @@
 
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
 	/* Maintainer: calao-systems */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-rm9200dk.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-rm9200dk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-rm9200dk.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-rm9200dk.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,235 @@
+/*
+ * linux/arch/arm/mach-at91/board-rm9200dk.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *
+ *  Epson S1D framebuffer glue code is:
+ *     Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91rm9200_mc.h>
+
+#include "generic.h"
+
+
+static void __init dk_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init dk_init_irq(void)
+{
+	at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata dk_eth_data = {
+	.phy_irq_pin	= AT91_PIN_PC4,
+	.is_rmii	= 1,
+};
+
+static struct at91_usbh_data __initdata dk_usbh_data = {
+	.ports		= 2,
+};
+
+static struct at91_udc_data __initdata dk_udc_data = {
+	.vbus_pin	= AT91_PIN_PD4,
+	.pullup_pin	= AT91_PIN_PD5,
+};
+
+static struct at91_cf_data __initdata dk_cf_data = {
+	.det_pin	= AT91_PIN_PB0,
+	.rst_pin	= AT91_PIN_PC5,
+	// .irq_pin	= ... not connected
+	// .vcc_pin	= ... always powered
+};
+
+#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+static struct at91_mmc_data __initdata dk_mmc_data = {
+	.slot_b		= 0,
+	.wire4		= 1,
+};
+#endif
+
+static struct spi_board_info dk_spi_devices[] = {
+	{	/* DataFlash chip */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 0,
+		.max_speed_hz	= 15 * 1000 * 1000,
+	},
+	{	/* UR6HCPS2-SP40 PS2-to-SPI adapter */
+		.modalias	= "ur6hcps2",
+		.chip_select	= 1,
+		.max_speed_hz	= 250 *  1000,
+	},
+	{	/* TLV1504 ADC, 4 channels, 10 bits; one is a temp sensor */
+		.modalias	= "tlv1504",
+		.chip_select	= 2,
+		.max_speed_hz	= 20 * 1000 * 1000,
+	},
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	{	/* DataFlash card */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 3,
+		.max_speed_hz	= 15 * 1000 * 1000,
+	}
+#endif
+};
+
+static struct i2c_board_info __initdata dk_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("ics1523", 0x26),
+	},
+	{
+		I2C_BOARD_INFO("x9429", 0x28),
+	},
+	{
+		I2C_BOARD_INFO("24c1024", 0x50),
+	}
+};
+
+static struct mtd_partition __initdata dk_nand_partition[] = {
+	{
+		.name	= "NAND Partition 1",
+		.offset	= 0,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(dk_nand_partition);
+	return dk_nand_partition;
+}
+
+static struct atmel_nand_data __initdata dk_nand_data = {
+	.ale		= 22,
+	.cle		= 21,
+	.det_pin	= AT91_PIN_PB1,
+	.rdy_pin	= AT91_PIN_PC2,
+	// .enable_pin	= ... not there
+	.partition_info	= nand_partitions,
+};
+
+#define DK_FLASH_BASE	AT91_CHIPSELECT_0
+#define DK_FLASH_SIZE	SZ_2M
+
+static struct physmap_flash_data dk_flash_data = {
+	.width		= 2,
+};
+
+static struct resource dk_flash_resource = {
+	.start		= DK_FLASH_BASE,
+	.end		= DK_FLASH_BASE + DK_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device dk_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data	= &dk_flash_data,
+			},
+	.resource	= &dk_flash_resource,
+	.num_resources	= 1,
+};
+
+static struct gpio_led dk_leds[] = {
+	{
+		.name			= "led0",
+		.gpio			= AT91_PIN_PB2,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	}
+};
+
+static void __init dk_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* Ethernet */
+	at91_add_device_eth(&dk_eth_data);
+	/* USB Host */
+	at91_add_device_usbh(&dk_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&dk_udc_data);
+	at91_set_multi_drive(dk_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
+	/* Compact Flash */
+	at91_add_device_cf(&dk_cf_data);
+	/* I2C */
+	at91_add_device_i2c(dk_i2c_devices, ARRAY_SIZE(dk_i2c_devices));
+	/* SPI */
+	at91_add_device_spi(dk_spi_devices, ARRAY_SIZE(dk_spi_devices));
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	/* DataFlash card */
+	at91_set_gpio_output(AT91_PIN_PB7, 0);
+#else
+	/* MMC */
+	at91_set_gpio_output(AT91_PIN_PB7, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
+	at91_add_device_mmc(0, &dk_mmc_data);
+#endif
+	/* NAND */
+	at91_add_device_nand(&dk_nand_data);
+	/* NOR Flash */
+	platform_device_register(&dk_flash);
+	/* LEDs */
+	at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds));
+	/* VGA */
+//	dk_add_device_video();
+}
+
+MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
+	/* Maintainer: SAN People/Atmel */
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91rm9200_timer,
+	.map_io		= dk_map_io,
+	.init_irq	= dk_init_irq,
+	.init_machine	= dk_board_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-rm9200ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-rm9200ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-rm9200ek.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-rm9200ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,201 @@
+/*
+ * linux/arch/arm/mach-at91/board-rm9200ek.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *
+ *  Epson S1D framebuffer glue code is:
+ *     Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/at91rm9200_mc.h>
+
+#include "generic.h"
+
+
+static void __init ek_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+	/* Setup the LEDs */
+	at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+
+	/* DBGU on ttyS0. (Rx & Tx only) */
+	at91_register_uart(0, 0, 0);
+
+	/* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+			   | ATMEL_UART_RI);
+
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init ek_init_irq(void)
+{
+	at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata ek_eth_data = {
+	.phy_irq_pin	= AT91_PIN_PC4,
+	.is_rmii	= 1,
+};
+
+static struct at91_usbh_data __initdata ek_usbh_data = {
+	.ports		= 2,
+};
+
+static struct at91_udc_data __initdata ek_udc_data = {
+	.vbus_pin	= AT91_PIN_PD4,
+	.pullup_pin	= AT91_PIN_PD5,
+};
+
+#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+static struct at91_mmc_data __initdata ek_mmc_data = {
+	.det_pin	= AT91_PIN_PB27,
+	.slot_b		= 0,
+	.wire4		= 1,
+	.wp_pin		= AT91_PIN_PA17,
+};
+#endif
+
+static struct spi_board_info ek_spi_devices[] = {
+	{	/* DataFlash chip */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 0,
+		.max_speed_hz	= 15 * 1000 * 1000,
+	},
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	{	/* DataFlash card */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 3,
+		.max_speed_hz	= 15 * 1000 * 1000,
+	},
+#endif
+};
+
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("ics1523", 0x26),
+	},
+	{
+		I2C_BOARD_INFO("dac3550", 0x4d),
+	}
+};
+
+#define EK_FLASH_BASE	AT91_CHIPSELECT_0
+#define EK_FLASH_SIZE	SZ_2M
+
+static struct physmap_flash_data ek_flash_data = {
+	.width		= 2,
+};
+
+static struct resource ek_flash_resource = {
+	.start		= EK_FLASH_BASE,
+	.end		= EK_FLASH_BASE + EK_FLASH_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device ek_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data	= &ek_flash_data,
+			},
+	.resource	= &ek_flash_resource,
+	.num_resources	= 1,
+};
+
+static struct gpio_led ek_leds[] = {
+	{	/* "user led 1", DS2 */
+		.name			= "green",
+		.gpio			= AT91_PIN_PB0,
+		.active_low		= 1,
+		.default_trigger	= "mmc0",
+	},
+	{	/* "user led 2", DS4 */
+		.name			= "yellow",
+		.gpio			= AT91_PIN_PB1,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+	{	/* "user led 3", DS6 */
+		.name			= "red",
+		.gpio			= AT91_PIN_PB2,
+		.active_low		= 1,
+	}
+};
+
+static void __init ek_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* Ethernet */
+	at91_add_device_eth(&ek_eth_data);
+	/* USB Host */
+	at91_add_device_usbh(&ek_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&ek_udc_data);
+	at91_set_multi_drive(ek_udc_data.pullup_pin, 1);	/* pullup_pin is connected to reset */
+	/* I2C */
+	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+	/* SPI */
+	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	/* DataFlash card */
+	at91_set_gpio_output(AT91_PIN_PB22, 0);
+#else
+	/* MMC */
+	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
+	at91_add_device_mmc(0, &ek_mmc_data);
+#endif
+	/* NOR Flash */
+	platform_device_register(&ek_flash);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+	/* VGA */
+//	ek_add_device_video();
+}
+
+MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
+	/* Maintainer: SAN People/Atmel */
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91rm9200_timer,
+	.map_io		= ek_map_io,
+	.init_irq	= ek_init_irq,
+	.init_machine	= ek_board_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9260ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9260ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9260ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9260ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -356,8 +356,6 @@
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9261ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9261ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9261ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9261ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -623,8 +623,6 @@
 MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9263ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9263ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9263ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9263ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -454,8 +454,6 @@
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,329 +0,0 @@
-/*
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2008 Atmel
- *  Copyright (C) 2009 Rob Emanuele
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/at73c213.h>
-#include <linux/clk.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/consumer.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91sam9_smc.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init ek_map_io(void)
-{
-	/* Initialize processor: 18.432 MHz crystal */
-	at91sam9260_initialize(18432000);
-
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-			   | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-			   | ATMEL_UART_RI);
-
-	/* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-	at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-static void __init ek_init_irq(void)
-{
-	at91sam9260_init_interrupts(NULL);
-}
-
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
-	.ports		= 2,
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
-	.vbus_pin	= AT91_PIN_PC5,
-	.pullup_pin	= 0,		/* pull-up driven by UDC */
-};
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
-	{	/* DataFlash chip */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 1,
-		.max_speed_hz	= 15 * 1000 * 1000,
-		.bus_num	= 0,
-	},
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-	{	/* DataFlash card */
-		.modalias	= "mtd_dataflash",
-		.chip_select	= 0,
-		.max_speed_hz	= 15 * 1000 * 1000,
-		.bus_num	= 0,
-	},
-#endif
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct at91_eth_data __initdata ek_macb_data = {
-	.phy_irq_pin	= AT91_PIN_PB0,
-	.is_rmii	= 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
-	{
-		.name   = "Bootstrap",
-		.offset = 0,
-		.size   = 4 * SZ_1M,
-	},
-	{
-		.name	= "Partition 1",
-		.offset	= MTDPART_OFS_NXTBLK,
-		.size	= 60 * SZ_1M,
-	},
-	{
-		.name	= "Partition 2",
-		.offset	= MTDPART_OFS_NXTBLK,
-		.size	= MTDPART_SIZ_FULL,
-	},
-};
-
-static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
-{
-	*num_partitions = ARRAY_SIZE(ek_nand_partition);
-	return ek_nand_partition;
-}
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
-	.ale		= 21,
-	.cle		= 22,
-	.rdy_pin	= AT91_PIN_PC13,
-	.enable_pin	= AT91_PIN_PC14,
-	.partition_info	= nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-	.bus_width_16	= 1,
-#else
-	.bus_width_16	= 0,
-#endif
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
-	.ncs_read_setup		= 0,
-	.nrd_setup		= 2,
-	.ncs_write_setup	= 0,
-	.nwe_setup		= 2,
-
-	.ncs_read_pulse		= 4,
-	.nrd_pulse		= 4,
-	.ncs_write_pulse	= 4,
-	.nwe_pulse		= 4,
-
-	.read_cycle		= 7,
-	.write_cycle		= 7,
-
-	.mode			= AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-	.tdf_cycles		= 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
-	/* setup bus-width (8 or 16) */
-	if (ek_nand_data.bus_width_16)
-		ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
-	else
-		ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-	/* configure chip-select 3 (NAND) */
-	sam9_smc_configure(3, &ek_nand_smc_config);
-
-	at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- * wp_pin is not connected
- */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-static struct mci_platform_data __initdata ek_mmc_data = {
-	.slot[0] = {
-		.bus_width	= 4,
-		.detect_pin	= AT91_PIN_PC2,
-		.wp_pin		= -ENODEV,
-	},
-	.slot[1] = {
-		.bus_width	= 4,
-		.detect_pin	= AT91_PIN_PC9,
-		.wp_pin		= -ENODEV,
-	},
-
-};
-#else
-static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 1,	/* Only one slot so use slot B */
-	.wire4		= 1,
-	.det_pin	= AT91_PIN_PC9,
-};
-#endif
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
-	{	/* "bottom" led, green, userled1 to be defined */
-		.name			= "ds5",
-		.gpio			= AT91_PIN_PB8,
-		.active_low		= 1,
-		.default_trigger	= "none",
-	},
-	{	/* "power" led, yellow */
-		.name			= "ds1",
-		.gpio			= AT91_PIN_PB9,
-		.default_trigger	= "heartbeat",
-	}
-};
-
-#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
-static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
-	REGULATOR_SUPPLY("AVDD", "0-001b"),
-	REGULATOR_SUPPLY("HPVDD", "0-001b"),
-	REGULATOR_SUPPLY("DBVDD", "0-001b"),
-	REGULATOR_SUPPLY("DCVDD", "0-001b"),
-};
-
-static struct regulator_init_data ek_avdd_reg_init_data = {
-	.constraints	= {
-		.name	= "3V3",
-		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-	},
-	.consumer_supplies = ek_audio_consumer_supplies,
-	.num_consumer_supplies = ARRAY_SIZE(ek_audio_consumer_supplies),
-};
-
-static struct fixed_voltage_config ek_vdd_pdata = {
-	.supply_name	= "board-3V3",
-	.microvolts	= 3300000,
-	.gpio		= -EINVAL,
-	.enabled_at_boot = 0,
-	.init_data	= &ek_avdd_reg_init_data,
-};
-static struct platform_device ek_voltage_regulator = {
-	.name		= "reg-fixed-voltage",
-	.id		= -1,
-	.num_resources	= 0,
-	.dev		= {
-		.platform_data	= &ek_vdd_pdata,
-	},
-};
-static void __init ek_add_regulators(void)
-{
-	platform_device_register(&ek_voltage_regulator);
-}
-#else
-static void __init ek_add_regulators(void) {}
-#endif
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
-	{
-		I2C_BOARD_INFO("24c512", 0x50),
-	},
-};
-
-
-static void __init ek_board_init(void)
-{
-	/* Serial */
-	at91_add_device_serial();
-	/* USB Host */
-	at91_add_device_usbh(&ek_usbh_data);
-	/* USB Device */
-	at91_add_device_udc(&ek_udc_data);
-	/* SPI */
-	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
-	/* NAND */
-	ek_add_device_nand();
-	/* Ethernet */
-	at91_add_device_eth(&ek_macb_data);
-	/* Regulators */
-	ek_add_regulators();
-	/* MMC */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-	at91_add_device_mci(0, &ek_mmc_data);
-#else
-	at91_add_device_mmc(0, &ek_mmc_data);
-#endif
-	/* I2C */
-	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
-	/* LEDs */
-	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
-	/* PCK0 provides MCLK to the WM8731 */
-	at91_set_B_periph(AT91_PIN_PC1, 0);
-	/* SSC (for WM8731) */
-	at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
-}
-
-MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
-	/* Maintainer: Rob Emanuele */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
-	.boot_params	= AT91_SDRAM_BASE + 0x100,
-	.timer		= &at91sam926x_timer,
-	.map_io		= ek_map_io,
-	.init_irq	= ek_init_irq,
-	.init_machine	= ek_board_init,
-MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9g20ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9g20ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9g20ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9g20ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,18 @@
 #include "sam9_smc.h"
 #include "generic.h"
 
+/*
+ * board revision encoding
+ * bit 0:
+ * 	0 => 1 sd/mmc slot
+ * 	1 => 2 sd/mmc slots connectors (board from revision C)
+ */
+#define HAVE_2MMC	(1 << 0)
+static int inline ek_have_2mmc(void)
+{
+	return machine_is_at91sam9g20ek_2mmc() || (system_rev & HAVE_2MMC);
+}
+
 
 static void __init ek_map_io(void)
 {
@@ -94,7 +106,7 @@
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
 	{	/* DataFlash chip */
 		.modalias	= "mtd_dataflash",
 		.chip_select	= 1,
@@ -121,6 +133,13 @@
 	.is_rmii	= 1,
 };
 
+static void __init ek_add_device_macb(void)
+{
+	if (ek_have_2mmc())
+		ek_macb_data.phy_irq_pin = AT91_PIN_PB0;
+
+	at91_add_device_eth(&ek_macb_data);
+}
 
 /*
  * NAND flash
@@ -198,13 +217,36 @@
 
 /*
  * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
+ * wp_pin and vcc_pin are not connected
  */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata ek_mmc_data = {
+	.slot[1] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PC9,
+	},
+
+};
+#else
 static struct at91_mmc_data __initdata ek_mmc_data = {
-	.slot_b		= 1,
+	.slot_b		= 1,	/* Only one slot so use slot B */
 	.wire4		= 1,
+	.det_pin	= AT91_PIN_PC9,
 };
+#endif
 
+static void __init ek_add_device_mmc(void)
+{
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+	if (ek_have_2mmc()) {
+		ek_mmc_data.slot[0].bus_width = 4;
+		ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
+	}
+	at91_add_device_mci(0, &ek_mmc_data);
+#else
+	at91_add_device_mmc(0, &ek_mmc_data);
+#endif
+}
 
 /*
  * LEDs
@@ -223,6 +265,15 @@
 	}
 };
 
+static void __init ek_add_device_gpio_leds(void)
+{
+	if (ek_have_2mmc()) {
+		ek_leds[0].gpio = AT91_PIN_PB8;
+		ek_leds[1].gpio = AT91_PIN_PB9;
+	}
+
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+}
 
 /*
  * GPIO Buttons
@@ -336,15 +387,15 @@
 	/* NAND */
 	ek_add_device_nand();
 	/* Ethernet */
-	at91_add_device_eth(&ek_macb_data);
+	ek_add_device_macb();
 	/* Regulators */
 	ek_add_regulators();
 	/* MMC */
-	at91_add_device_mmc(0, &ek_mmc_data);
+	ek_add_device_mmc();
 	/* I2C */
 	at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
 	/* LEDs */
-	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+	ek_add_device_gpio_leds();
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* PCK0 provides MCLK to the WM8731 */
@@ -355,8 +406,15 @@
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= ek_map_io,
+	.init_irq	= ek_init_irq,
+	.init_machine	= ek_board_init,
+MACHINE_END
+
+MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+	/* Maintainer: Atmel */
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9-l9260.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9-l9260.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9-l9260.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9-l9260.c	2011-01-04 19:50:19.000000000 -0500
@@ -212,8 +212,6 @@
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
 	/* Maintainer: Olimex */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9m10g45ek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9m10g45ek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9m10g45ek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9m10g45ek.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,9 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/clk.h>
+#include <linux/atmel-mci.h>
 
+#include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
@@ -98,6 +100,25 @@
 
 
 /*
+ * MCI (SD/MMC)
+ */
+static struct mci_platform_data __initdata mci0_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PD10,
+	},
+};
+
+static struct mci_platform_data __initdata mci1_data = {
+	.slot[0] = {
+		.bus_width	= 4,
+		.detect_pin	= AT91_PIN_PD11,
+		.wp_pin		= AT91_PIN_PD29,
+	},
+};
+
+
+/*
  * MACB Ethernet device
  */
 static struct at91_eth_data __initdata ek_macb_data = {
@@ -135,7 +156,7 @@
 	.rdy_pin	= AT91_PIN_PC8,
 	.enable_pin	= AT91_PIN_PC14,
 	.partition_info	= nand_partitions,
-#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
 	.bus_width_16	= 1,
 #else
 	.bus_width_16	= 0,
@@ -380,6 +401,9 @@
 	at91_add_device_usba(&ek_usba_udc_data);
 	/* SPI */
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+	/* MMC */
+	at91_add_device_mci(0, &mci0_data);
+	at91_add_device_mci(1, &mci1_data);
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* NAND */
@@ -399,10 +423,8 @@
 	at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
 }
 
-MACHINE_START(AT91SAM9G45EKES, "Atmel AT91SAM9G45-EKES")
+MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9rlek.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9rlek.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-sam9rlek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-sam9rlek.c	2011-01-04 19:50:19.000000000 -0500
@@ -329,8 +329,6 @@
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
 	/* Maintainer: Atmel */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-snapper9260.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-snapper9260.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-snapper9260.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-snapper9260.c	2011-01-04 19:50:19.000000000 -0500
@@ -177,8 +177,6 @@
 }
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= snapper9260_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-stamp9g20.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-stamp9g20.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-stamp9g20.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-stamp9g20.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 #include "generic.h"
 
 
-static void __init portuxg20_map_io(void)
+void __init stamp9g20_map_io(void)
 {
 	/* Initialize processor: 18.432 MHz crystal */
 	at91sam9260_initialize(18432000);
@@ -40,6 +40,24 @@
 	/* DGBU on ttyS0. (Rx & Tx only) */
 	at91_register_uart(0, 0, 0);
 
+	/* set serial console to ttyS0 (ie, DBGU) */
+	at91_set_serial_console(0);
+}
+
+static void __init stamp9g20evb_map_io(void)
+{
+	stamp9g20_map_io();
+
+	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+						| ATMEL_UART_DTR | ATMEL_UART_DSR
+						| ATMEL_UART_DCD | ATMEL_UART_RI);
+}
+
+static void __init portuxg20_map_io(void)
+{
+	stamp9g20_map_io();
+
 	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
 	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
 						| ATMEL_UART_DTR | ATMEL_UART_DSR
@@ -56,26 +74,6 @@
 
 	/* USART5 on ttyS6. (Rx, Tx only) */
 	at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
-}
-
-static void __init stamp9g20_map_io(void)
-{
-	/* Initialize processor: 18.432 MHz crystal */
-	at91sam9260_initialize(18432000);
-
-	/* DGBU on ttyS0. (Rx & Tx only) */
-	at91_register_uart(0, 0, 0);
-
-	/* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-	at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-						| ATMEL_UART_DTR | ATMEL_UART_DSR
-						| ATMEL_UART_DCD | ATMEL_UART_RI);
-
-	/* set serial console to ttyS0 (ie, DBGU) */
-	at91_set_serial_console(0);
 }
 
 static void __init init_irq(void)
@@ -156,7 +154,7 @@
 	.pullup_pin	= 0,		/* pull-up driven by UDC */
 };
 
-static struct at91_udc_data __initdata stamp9g20_udc_data = {
+static struct at91_udc_data __initdata stamp9g20evb_udc_data = {
 	.vbus_pin	= AT91_PIN_PA22,
 	.pullup_pin	= 0,		/* pull-up driven by UDC */
 };
@@ -190,7 +188,7 @@
 	}
 };
 
-static struct gpio_led stamp9g20_leds[] = {
+static struct gpio_led stamp9g20evb_leds[] = {
 	{
 		.name			= "D8",
 		.gpio			= AT91_PIN_PB18,
@@ -250,7 +248,7 @@
 }
 
 
-static void __init generic_board_init(void)
+void __init stamp9g20_board_init(void)
 {
 	/* Serial */
 	at91_add_device_serial();
@@ -262,40 +260,44 @@
 #else
 	at91_add_device_mmc(0, &mmc_data);
 #endif
-	/* USB Host */
-	at91_add_device_usbh(&usbh_data);
-	/* Ethernet */
-	at91_add_device_eth(&macb_data);
-	/* I2C */
-	at91_add_device_i2c(NULL, 0);
 	/* W1 */
 	add_w1();
 }
 
 static void __init portuxg20_board_init(void)
 {
-	generic_board_init();
-	/* SPI */
-	at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
+	stamp9g20_board_init();
+	/* USB Host */
+	at91_add_device_usbh(&usbh_data);
 	/* USB Device */
 	at91_add_device_udc(&portuxg20_udc_data);
+	/* Ethernet */
+	at91_add_device_eth(&macb_data);
+	/* I2C */
+	at91_add_device_i2c(NULL, 0);
+	/* SPI */
+	at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
 	/* LEDs */
 	at91_gpio_leds(portuxg20_leds, ARRAY_SIZE(portuxg20_leds));
 }
 
-static void __init stamp9g20_board_init(void)
+static void __init stamp9g20evb_board_init(void)
 {
-	generic_board_init();
+	stamp9g20_board_init();
+	/* USB Host */
+	at91_add_device_usbh(&usbh_data);
 	/* USB Device */
-	at91_add_device_udc(&stamp9g20_udc_data);
+	at91_add_device_udc(&stamp9g20evb_udc_data);
+	/* Ethernet */
+	at91_add_device_eth(&macb_data);
+	/* I2C */
+	at91_add_device_i2c(NULL, 0);
 	/* LEDs */
-	at91_gpio_leds(stamp9g20_leds, ARRAY_SIZE(stamp9g20_leds));
+	at91_gpio_leds(stamp9g20evb_leds, ARRAY_SIZE(stamp9g20evb_leds));
 }
 
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
 	/* Maintainer: taskit GmbH */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= portuxg20_map_io,
@@ -305,11 +307,9 @@
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
 	/* Maintainer: taskit GmbH */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
-	.map_io		= stamp9g20_map_io,
+	.map_io		= stamp9g20evb_map_io,
 	.init_irq	= init_irq,
-	.init_machine	= stamp9g20_board_init,
+	.init_machine	= stamp9g20evb_board_init,
 MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-usb-a9260.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-usb-a9260.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-usb-a9260.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-usb-a9260.c	2011-01-04 19:50:19.000000000 -0500
@@ -228,8 +228,6 @@
 
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
 	/* Maintainer: calao-systems */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-usb-a9263.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-usb-a9263.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-usb-a9263.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-usb-a9263.c	2011-01-04 19:50:19.000000000 -0500
@@ -244,8 +244,6 @@
 
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
 	/* Maintainer: calao-systems */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91sam926x_timer,
 	.map_io		= ek_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-yl-9200.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-yl-9200.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/board-yl-9200.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/board-yl-9200.c	2011-01-04 19:50:19.000000000 -0500
@@ -387,7 +387,7 @@
  * EPSON S1D13806 FB (discontinued chip)
  * EPSON S1D13506 FB
  */
-#if defined(CONFIG_FB_S1D135XX) || defined(CONFIG_FB_S1D13XXX_MODULE)
+#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE)
 #include <video/s1d13xxxfb.h>
 
 
@@ -594,8 +594,6 @@
 
 MACHINE_START(YL9200, "uCdragon YL-9200")
 	/* Maintainer: S.Birtles */
-	.phys_io	= AT91_BASE_SYS,
-	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
 	.boot_params	= AT91_SDRAM_BASE + 0x100,
 	.timer		= &at91rm9200_timer,
 	.map_io		= yl9200_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -658,7 +658,7 @@
 	/* Now set uhpck values */
 	uhpck.parent = &utmi_clk;
 	uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
-	uhpck.rate_hz = utmi_clk.parent->rate_hz;
+	uhpck.rate_hz = utmi_clk.rate_hz;
 	uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/generic.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/generic.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/generic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/generic.h	2011-01-04 19:50:19.000000000 -0500
@@ -46,6 +46,9 @@
 extern void at91_irq_suspend(void);
 extern void at91_irq_resume(void);
 
+/* reset */
+extern void at91sam9_alt_reset(void);
+
  /* GPIO */
 #define AT91RM9200_PQFP		3	/* AT91RM9200 PQFP package has 3 banks */
 #define AT91RM9200_BGA		4	/* AT91RM9200 BGA package has 4 banks */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/at91_mci.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/at91_mci.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/at91_mci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/at91_mci.h	2011-01-04 19:50:19.000000000 -0500
@@ -74,6 +74,8 @@
 #define			AT91_MCI_TRTYP_BLOCK	(0 << 19)
 #define			AT91_MCI_TRTYP_MULTIPLE	(1 << 19)
 #define			AT91_MCI_TRTYP_STREAM	(2 << 19)
+#define			AT91_MCI_TRTYP_SDIO_BYTE	(4 << 19)
+#define			AT91_MCI_TRTYP_SDIO_BLOCK	(5 << 19)
 
 #define AT91_MCI_BLKR		0x18		/* Block Register */
 #define		AT91_MCI_BLKR_BCNT(n)	((0xffff & (n)) << 0)	/* Block count */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/at91x40.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/at91x40.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/at91x40.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/at91x40.h	2011-01-04 19:50:19.000000000 -0500
@@ -52,4 +52,10 @@
 #define AT91_DBGU_CIDR	(AT91_SF + 0)	/* CIDR in PS segment */
 #define AT91_DBGU_EXID	(AT91_SF + 4)	/* EXID in PS segment */
 
+/*
+ * Support defines for the simple Power Controller module.
+ */
+#define	AT91_PS_CR	(AT91_PS + 0)	/* PS Control register */
+#define	AT91_PS_CR_CPU	(1 << 0)	/* CPU clock disable bit */
+
 #endif /* AT91X40_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/board.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/board.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/board.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/board.h	2011-01-04 19:50:19.000000000 -0500
@@ -137,13 +137,7 @@
 extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
 extern void __init at91_set_serial_console(unsigned portnr);
 
-struct at91_uart_config {
-	unsigned short	console_tty;	/* tty number of serial console */
-	unsigned short	nr_tty;		/* number of serial tty's */
-	short		tty_map[];	/* map UART to tty number */
-};
 extern struct platform_device *atmel_default_console_device;
-extern void __init __deprecated at91_init_serial(struct at91_uart_config *config);
 
 struct atmel_uart_data {
 	short			use_dma_tx;	/* use transmit DMA? */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,9 @@
 #include <mach/hardware.h>
 #include <mach/at91_dbgu.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1						@ MMU enabled?
-	ldreq	\rx, =(AT91_BASE_SYS + AT91_DBGU)		@ System peripherals (phys address)
-	ldrne	\rx, =(AT91_VA_BASE_SYS	+ AT91_DBGU)		@ System peripherals (virt address)
+	.macro	addruart, rp, rv
+	ldr	\rp, =(AT91_BASE_SYS + AT91_DBGU)		@ System peripherals (phys address)
+	ldr	\rv, =(AT91_VA_BASE_SYS	+ AT91_DBGU)		@ System peripherals (virt address)
 	.endm
 
 	.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/stamp9g20.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/stamp9g20.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/stamp9g20.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/stamp9g20.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,7 @@
+#ifndef __MACH_STAMP9G20_H
+#define __MACH_STAMP9G20_H
+
+void stamp9g20_map_io(void);
+void stamp9g20_board_init(void);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/system.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/system.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/include/mach/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/include/mach/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,11 @@
 	 * Disable the processor clock.  The processor will be automatically
 	 * re-enabled by an interrupt or by a reset.
 	 */
+#ifdef AT91_PS
+	at91_sys_write(AT91_PS_CR, AT91_PS_CR_CPU);
+#else
 	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+#endif
 #ifndef CONFIG_CPU_ARM920T
 	/*
 	 * Set the processor (CP15) into 'Wait for Interrupt' mode.
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-at91/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 	select HAVE_AT91_USART3
 	select HAVE_AT91_USART4
 	select HAVE_AT91_USART5
+	select HAVE_NET_MACB
 
 config ARCH_AT91SAM9261
 	bool "AT91SAM9261"
@@ -51,6 +52,7 @@
 	select CPU_ARM926T
 	select GENERIC_CLOCKEVENTS
 	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
 
 config ARCH_AT91SAM9RL
 	bool "AT91SAM9RL"
@@ -66,6 +68,7 @@
 	select HAVE_AT91_USART3
 	select HAVE_AT91_USART4
 	select HAVE_AT91_USART5
+	select HAVE_NET_MACB
 
 config ARCH_AT91SAM9G45
 	bool "AT91SAM9G45"
@@ -73,6 +76,7 @@
 	select GENERIC_CLOCKEVENTS
 	select HAVE_AT91_USART3
 	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
 
 config ARCH_AT91CAP9
 	bool "AT91CAP9"
@@ -105,7 +109,7 @@
 	bool "Ajeco 1ARM Single Board Computer"
 	help
 	  Select this if you are using Ajeco's 1ARM Single Board Computer.
-	  <http://www.ajeco.fi/products.htm>
+	  <http://www.ajeco.fi/>
 
 config ARCH_AT91RM9200DK
 	bool "Atmel AT91RM9200-DK Development board"
@@ -137,7 +141,7 @@
 	bool "Conitec ARM&EVA"
 	help
 	  Select this if you are using Conitec's AT91RM9200-MCU-Module.
-	  <http://www.conitec.net/english/linuxboard.htm>
+	  <http://www.conitec.net/english/linuxboard.php>
 
 config MACH_ATEB9200
 	bool "Embest ATEB9200"
@@ -149,7 +153,7 @@
 	bool "KwikByte KB920x"
 	help
 	  Select this if you are using KwikByte's KB920x board.
-	  <http://kwikbyte.com/KB9202_description_new.htm>
+	  <http://www.kwikbyte.com/KB9202.html>
 
 config MACH_PICOTUX2XX
 	bool "picotux 200"
@@ -248,6 +252,12 @@
 	  Select this if you are using a Eukrea Electromatique's
 	  CPU9260 Board <http://www.eukrea.com/>
 
+config MACH_FLEXIBITY
+	bool "Flexibity Connect board"
+	help
+	  Select this if you are using Flexibity Connect board
+	  <http://www.flexibity.com>
+
 endif
 
 # ----------------------------------------------------------
@@ -338,6 +348,7 @@
 	  that embeds only one SD/MMC slot.
 
 config MACH_AT91SAM9G20EK_2MMC
+	depends on MACH_AT91SAM9G20EK
 	bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
 	select HAVE_NAND_ATMEL_BUSWIDTH_16
 	help
@@ -364,6 +375,12 @@
 	  evaluation board.
 	  <http://www.taskit.de/en/>
 
+config MACH_PCONTROL_G20
+	bool "PControl G20 CPU module"
+	help
+	  Select this if you are using taskit's Stamp9G20 CPU module on this
+	  carrier board, beeing the decentralized unit of a building automation
+	  system; featuring nvram, eth-switch, iso-rs485, display, io
 endif
 
 if (ARCH_AT91SAM9260 || ARCH_AT91SAM9G20)
@@ -383,8 +400,8 @@
 
 comment "AT91SAM9G45 Board Type"
 
-config MACH_AT91SAM9G45EKES
-	bool "Atmel AT91SAM9G45-EKES Evaluation Kit"
+config MACH_AT91SAM9M10G45EK
+	bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
 	select HAVE_NAND_ATMEL_BUSWIDTH_16
 	help
 	  Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-at91/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,12 @@
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G10)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G20)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G10)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9RL)	+= at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o at91sam9_alt_reset.o
+obj-$(CONFIG_ARCH_AT91SAM9G20)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
 obj-$(CONFIG_ARCH_AT91SAM9G45)	+= at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91CAP9)	+= at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT572D940HF)  += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
@@ -24,8 +24,8 @@
 
 # AT91RM9200 board-specific support
 obj-$(CONFIG_MACH_ONEARM)	+= board-1arm.o
-obj-$(CONFIG_ARCH_AT91RM9200DK)	+= board-dk.o
-obj-$(CONFIG_MACH_AT91RM9200EK)	+= board-ek.o
+obj-$(CONFIG_ARCH_AT91RM9200DK)	+= board-rm9200dk.o
+obj-$(CONFIG_MACH_AT91RM9200EK)	+= board-rm9200ek.o
 obj-$(CONFIG_MACH_CSB337)	+= board-csb337.o
 obj-$(CONFIG_MACH_CSB637)	+= board-csb637.o
 obj-$(CONFIG_MACH_CARMEVA)	+= board-carmeva.o
@@ -46,6 +46,7 @@
 obj-$(CONFIG_MACH_QIL_A9260)	+= board-qil-a9260.o
 obj-$(CONFIG_MACH_AFEB9260)	+= board-afeb-9260v1.o
 obj-$(CONFIG_MACH_CPU9260)	+= board-cpu9krea.o
+obj-$(CONFIG_MACH_FLEXIBITY)	+= board-flexibity.o
 
 # AT91SAM9261 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
@@ -61,16 +62,16 @@
 
 # AT91SAM9G20 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
-obj-$(CONFIG_MACH_AT91SAM9G20EK_2MMC) += board-sam9g20ek-2slot-mmc.o
 obj-$(CONFIG_MACH_CPU9G20)	+= board-cpu9krea.o
 obj-$(CONFIG_MACH_STAMP9G20)	+= board-stamp9g20.o
 obj-$(CONFIG_MACH_PORTUXG20)	+= board-stamp9g20.o
+obj-$(CONFIG_MACH_PCONTROL_G20)	+= board-pcontrol-g20.o board-stamp9g20.o
 
 # AT91SAM9260/AT91SAM9G20 board-specific support
 obj-$(CONFIG_MACH_SNAPPER_9260)	+= board-snapper9260.o
 
 # AT91SAM9G45 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
+obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 
 # AT91CAP9 board-specific support
 obj-$(CONFIG_MACH_AT91CAP9ADK)	+= board-cap9adk.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm.c linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -258,16 +258,23 @@
 			 * NOTE: the Wait-for-Interrupt instruction needs to be
 			 * in icache so no SDRAM accesses are needed until the
 			 * wakeup IRQ occurs and self-refresh is terminated.
+			 * For ARM 926 based chips, this requirement is weaker
+			 * as at91sam9 can access a RAM in self-refresh mode.
 			 */
-			asm("b 1f; .align 5; 1:");
-			asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
+			asm volatile (	"mov r0, #0\n\t"
+					"b 1f\n\t"
+					".align 5\n\t"
+					"1: mcr p15, 0, r0, c7, c10, 4\n\t"
+					: /* no output */
+					: /* no input */
+					: "r0");
 			saved_lpr = sdram_selfrefresh_enable();
-			asm("mcr p15, 0, r0, c7, c0, 4");	/* wait for interrupt */
+			wait_for_interrupt_enable();
 			sdram_selfrefresh_disable(saved_lpr);
 			break;
 
 		case PM_SUSPEND_ON:
-			asm("mcr p15, 0, r0, c7, c0, 4");	/* wait for interrupt */
+			cpu_do_idle();
 			break;
 
 		default:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm.h linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,8 @@
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)	at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()		asm volatile ("mcr p15, 0, %0, c7, c0, 4" \
+								: : "r" (0))
 
 #elif defined(CONFIG_ARCH_AT91CAP9)
 #include <mach/at91cap9_ddrsdr.h>
@@ -38,6 +40,7 @@
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)	at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()		cpu_do_idle()
 
 #elif defined(CONFIG_ARCH_AT91SAM9G45)
 #include <mach/at91sam9_ddrsdr.h>
@@ -74,6 +77,7 @@
 		at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); \
 		at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); \
 	} while (0)
+#define wait_for_interrupt_enable()		cpu_do_idle()
 
 #else
 #include <mach/at91sam9_sdramc.h>
@@ -98,5 +102,6 @@
 }
 
 #define sdram_selfrefresh_disable(saved_lpr)	at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr)
+#define wait_for_interrupt_enable()		cpu_do_idle()
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm_slowclock.S linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm_slowclock.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-at91/pm_slowclock.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-at91/pm_slowclock.S	2011-01-04 19:50:19.000000000 -0500
@@ -124,6 +124,7 @@
 	ldr	r5, .at91_va_base_ramc1
 
 	/* Drain write buffer */
+	mov	r0, #0
 	mcr	p15, 0, r0, c7, c10, 4
 
 #ifdef CONFIG_ARCH_AT91RM9200
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/arch.c linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/arch.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/arch.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/arch.c	2011-01-04 19:50:19.000000000 -0500
@@ -167,8 +167,6 @@
 
 MACHINE_START(BCMRING, "BCMRING")
 	/* Maintainer: Broadcom Corporation */
-	.phys_io = MM_IO_START,
-	.io_pg_offst = (MM_IO_BASE >> 18) & 0xfffc,
 	.fixup = bcmring_fixup,
 	.map_io = bcmring_map_io,
 	.init_irq = bcmring_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -691,7 +691,7 @@
 
 	memset(&gDMA, 0, sizeof(gDMA));
 
-	init_MUTEX_LOCKED(&gDMA.lock);
+	sema_init(&gDMA.lock, 0);
 	init_waitqueue_head(&gDMA.freeChannelQ);
 
 	/* Initialize the Hardware */
@@ -1574,7 +1574,7 @@
 {
 	memset(memMap, 0, sizeof(*memMap));
 
-	init_MUTEX(&memMap->lock);
+	sema_init(&memMap->lock, 1);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -22,4 +22,4 @@
  * 0xe0000000 to 0xefffffff. This gives us 256 MB of vm space and handles
  * larger physical memory designs better.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
+#define VMALLOC_END       0xf0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-bcmring/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-bcmring/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,21 +67,21 @@
 }
 
 static struct irq_chip bcmring_irq0_chip = {
-	.typename = "ARM-INTC0",
+	.name = "ARM-INTC0",
 	.ack = bcmring_mask_irq0,
 	.mask = bcmring_mask_irq0,	/* mask a specific interrupt, blocking its delivery. */
 	.unmask = bcmring_unmask_irq0,	/* unmaks an interrupt */
 };
 
 static struct irq_chip bcmring_irq1_chip = {
-	.typename = "ARM-INTC1",
+	.name = "ARM-INTC1",
 	.ack = bcmring_mask_irq1,
 	.mask = bcmring_mask_irq1,
 	.unmask = bcmring_unmask_irq1,
 };
 
 static struct irq_chip bcmring_irq2_chip = {
-	.typename = "ARM-SINTC",
+	.name = "ARM-SINTC",
 	.ack = bcmring_mask_irq2,
 	.mask = bcmring_mask_irq2,
 	.unmask = bcmring_unmask_irq2,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/autcpu12.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/autcpu12.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/autcpu12.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/autcpu12.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,8 +64,6 @@
 
 MACHINE_START(AUTCPU12, "autronix autcpu12")
 	/* Maintainer: Thomas Gleixner */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0020000,
 	.map_io		= autcpu12_map_io,
 	.init_irq	= clps711x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/cdb89712.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/cdb89712.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/cdb89712.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/cdb89712.c	2011-01-04 19:50:19.000000000 -0500
@@ -55,8 +55,6 @@
 
 MACHINE_START(CDB89712, "Cirrus-CDB89712")
 	/* Maintainer: Ray Lehtiniemi */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= cdb89712_map_io,
 	.init_irq	= clps711x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/ceiva.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/ceiva.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/ceiva.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/ceiva.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,8 +56,6 @@
 
 MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
 	/* Maintainer: Rob Scott */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= ceiva_map_io,
 	.init_irq	= clps711x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/clep7312.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/clep7312.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/clep7312.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/clep7312.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,8 +37,6 @@
 
 MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
 	/* Maintainer: Nobody */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.fixup		= fixup_clep7312,
 	.map_io		= clps711x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/edb7211-arch.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/edb7211-arch.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/edb7211-arch.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/edb7211-arch.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,8 +57,6 @@
 
 MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
 	/* Maintainer: Jon McClintock */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0020100,	/* 0xc0000000 - 0xc001ffff can be video RAM */
 	.fixup		= fixup_edb7211,
 	.map_io		= edb7211_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/fortunet.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/fortunet.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/fortunet.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/fortunet.c	2011-01-04 19:50:19.000000000 -0500
@@ -75,8 +75,6 @@
 
 MACHINE_START(FORTUNET, "ARM-FortuNet")
 	/* Maintainer: FortuNet Inc. */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000000,
 	.fixup		= fortunet_fixup,
 	.map_io		= clps711x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,16 +14,14 @@
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #CLPS7111_PHYS_BASE
-		movne	\rx, #CLPS7111_VIRT_BASE
+		.macro	addruart, rp, rv
 #ifndef CONFIG_DEBUG_CLPS711X_UART2
-		add	\rx, \rx, #0x0000	@ UART1
+		mov	\rp, #0x0000	@ UART1
 #else
-		add	\rx, \rx, #0x1000	@ UART2
+		mov	\rp, #0x1000	@ UART2
 #endif
+		orr	\rv, \rp, #CLPS7111_VIRT_BASE
+		orr	\rp, \rp, #CLPS7111_PHYS_BASE
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/p720t.c linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/p720t.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-clps711x/p720t.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-clps711x/p720t.c	2011-01-04 19:50:19.000000000 -0500
@@ -89,8 +89,6 @@
 
 MACHINE_START(P720T, "ARM-Prospector720T")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xff000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.fixup		= fixup_p720t,
 	.map_io		= p720t_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/cns3420vb.c linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/cns3420vb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/cns3420vb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/cns3420vb.c	2011-01-04 19:50:19.000000000 -0500
@@ -142,8 +142,6 @@
 }
 
 MACHINE_START(CNS3420VB, "Cavium Networks CNS3420 Validation Board")
-	.phys_io	= CNS3XXX_UART0_BASE,
-	.io_pg_offst	= (CNS3XXX_UART0_BASE_VIRT >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= cns3420_map_io,
 	.init_irq	= cns3xxx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,12 +10,10 @@
  * published by the Free Software Foundation.
  */
 
-		.macro	addruart,rx
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx,      #0x10000000
-		movne	\rx,      #0xf0000000	@ virtual base
-		orr	\rx, \rx, #0x00009000
+		.macro	addruart,rp,rv
+		mov	\rp, #0x00009000
+		orr	\rv, \rp, #0xf0000000	@ virtual base
+		orr	\rp, \rp, #0x10000000
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/pcie.c linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/pcie.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-cns3xxx/pcie.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-cns3xxx/pcie.c	2011-01-04 19:50:19.000000000 -0500
@@ -369,7 +369,7 @@
 {
 	int i;
 
-	hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS,
+	hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
 			"imprecise external abort");
 
 	for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/aemif.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/aemif.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/aemif.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/aemif.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,133 @@
+/*
+ * AEMIF support for DaVinci SoCs
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated. http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/time.h>
+
+#include <mach/aemif.h>
+
+/* Timing value configuration */
+
+#define TA(x)		((x) << 2)
+#define RHOLD(x)	((x) << 4)
+#define RSTROBE(x)	((x) << 7)
+#define RSETUP(x)	((x) << 13)
+#define WHOLD(x)	((x) << 17)
+#define WSTROBE(x)	((x) << 20)
+#define WSETUP(x)	((x) << 26)
+
+#define TA_MAX		0x3
+#define RHOLD_MAX	0x7
+#define RSTROBE_MAX	0x3f
+#define RSETUP_MAX	0xf
+#define WHOLD_MAX	0x7
+#define WSTROBE_MAX	0x3f
+#define WSETUP_MAX	0xf
+
+#define TIMING_MASK	(TA(TA_MAX) | \
+				RHOLD(RHOLD_MAX) | \
+				RSTROBE(RSTROBE_MAX) |	\
+				RSETUP(RSETUP_MAX) | \
+				WHOLD(WHOLD_MAX) | \
+				WSTROBE(WSTROBE_MAX) | \
+				WSETUP(WSETUP_MAX))
+
+/*
+ * aemif_calc_rate - calculate timing data.
+ * @wanted: The cycle time needed in nanoseconds.
+ * @clk: The input clock rate in kHz.
+ * @max: The maximum divider value that can be programmed.
+ *
+ * On success, returns the calculated timing value minus 1 for easy
+ * programming into AEMIF timing registers, else negative errno.
+ */
+static int aemif_calc_rate(int wanted, unsigned long clk, int max)
+{
+	int result;
+
+	result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
+
+	pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
+
+	/* It is generally OK to have a more relaxed timing than requested... */
+	if (result < 0)
+		result = 0;
+
+	/* ... But configuring tighter timings is not an option. */
+	else if (result > max)
+		result = -EINVAL;
+
+	return result;
+}
+
+/**
+ * davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
+ * @t: timing values to be progammed
+ * @base: The virtual base address of the AEMIF interface
+ * @cs: chip-select to program the timing values for
+ *
+ * This function programs the given timing values (in real clock) into the
+ * AEMIF registers taking the AEMIF clock into account.
+ *
+ * This function does not use any locking while programming the AEMIF
+ * because it is expected that there is only one user of a given
+ * chip-select.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+					void __iomem *base, unsigned cs)
+{
+	unsigned set, val;
+	unsigned ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
+	unsigned offset = A1CR_OFFSET + cs * 4;
+	struct clk *aemif_clk;
+	unsigned long clkrate;
+
+	if (!t)
+		return 0;	/* Nothing to do */
+
+	aemif_clk = clk_get(NULL, "aemif");
+	if (IS_ERR(aemif_clk))
+		return PTR_ERR(aemif_clk);
+
+	clkrate = clk_get_rate(aemif_clk);
+
+	clkrate /= 1000;	/* turn clock into kHz for ease of use */
+
+	ta	= aemif_calc_rate(t->ta, clkrate, TA_MAX);
+	rhold	= aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
+	rstrobe	= aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
+	rsetup	= aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
+	whold	= aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
+	wstrobe	= aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
+	wsetup	= aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
+
+	if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
+			whold < 0 || wstrobe < 0 || wsetup < 0) {
+		pr_err("%s: cannot get suitable timings\n", __func__);
+		return -EINVAL;
+	}
+
+	set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
+		WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
+
+	val = __raw_readl(base + offset);
+	val &= ~TIMING_MASK;
+	val |= set;
+	__raw_writel(val, base + offset);
+
+	return 0;
+}
+EXPORT_SYMBOL(davinci_aemif_setup_timing);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-da830-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-da830-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-da830-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-da830-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,10 +29,9 @@
 #include <mach/nand.h>
 #include <mach/da8xx.h>
 #include <mach/usb.h>
+#include <mach/aemif.h>
 
-#define DA830_EVM_PHY_MASK		0x0
-#define DA830_EVM_MDIO_FREQUENCY	2200000	/* PHY bus frequency */
-
+#define DA830_EVM_PHY_ID		""
 /*
  * USB1 VBUS is controlled by GPIO1[15], over-current is reported on GPIO2[4].
  */
@@ -360,6 +359,16 @@
 	.pattern	= da830_evm_nand_mirror_pattern
 };
 
+static struct davinci_aemif_timing da830_evm_nandflash_timing = {
+	.wsetup         = 24,
+	.wstrobe        = 21,
+	.whold          = 14,
+	.rsetup         = 19,
+	.rstrobe        = 50,
+	.rhold          = 0,
+	.ta             = 20,
+};
+
 static struct davinci_nand_pdata da830_evm_nand_pdata = {
 	.parts		= da830_evm_nand_partitions,
 	.nr_parts	= ARRAY_SIZE(da830_evm_nand_partitions),
@@ -368,6 +377,7 @@
 	.options	= NAND_USE_FLASH_BBT,
 	.bbt_td		= &da830_evm_nand_bbt_main_descr,
 	.bbt_md		= &da830_evm_nand_bbt_mirror_descr,
+	.timing         = &da830_evm_nandflash_timing,
 };
 
 static struct resource da830_evm_nand_resources[] = {
@@ -546,9 +556,8 @@
 
 	da830_evm_usb_init();
 
-	soc_info->emac_pdata->phy_mask = DA830_EVM_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = DA830_EVM_MDIO_FREQUENCY;
 	soc_info->emac_pdata->rmii_en = 1;
+	soc_info->emac_pdata->phy_id = DA830_EVM_PHY_ID;
 
 	ret = davinci_cfg_reg_list(da830_cpgmac_pins);
 	if (ret)
@@ -586,6 +595,9 @@
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static int __init da830_evm_console_init(void)
 {
+	if (!machine_is_davinci_da830_evm())
+		return 0;
+
 	return add_preferred_console("ttyS", 2, "115200");
 }
 console_initcall(da830_evm_console_init);
@@ -596,9 +608,7 @@
 	da830_init();
 }
 
-MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
-	.phys_io	= IO_PHYS,
-	.io_pg_offst	= (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137/AM17x EVM")
 	.boot_params	= (DA8XX_DDR_BASE + 0x100),
 	.map_io		= da830_evm_map_io,
 	.init_irq	= cp_intc_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-da850-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-da850-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-da850-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-da850-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,6 @@
 #include <linux/mtd/physmap.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6507x.h>
-#include <linux/mfd/tps6507x.h>
 #include <linux/input/tps6507x-ts.h>
 
 #include <asm/mach-types.h>
@@ -36,10 +35,9 @@
 #include <mach/da8xx.h>
 #include <mach/nand.h>
 #include <mach/mux.h>
+#include <mach/aemif.h>
 
-#define DA850_EVM_PHY_MASK		0x1
-#define DA850_EVM_MDIO_FREQUENCY	2200000 /* PHY bus frequency */
-
+#define DA850_EVM_PHY_ID		"0:00"
 #define DA850_LCD_PWR_PIN		GPIO_TO_PIN(2, 8)
 #define DA850_LCD_BL_PIN		GPIO_TO_PIN(2, 15)
 
@@ -110,7 +108,7 @@
  * to boot, using TI's tools to install the secondary boot loader
  * (UBL) and U-Boot.
  */
-struct mtd_partition da850_evm_nandflash_partition[] = {
+static struct mtd_partition da850_evm_nandflash_partition[] = {
 	{
 		.name		= "u-boot env",
 		.offset		= 0,
@@ -143,12 +141,23 @@
 	},
 };
 
+static struct davinci_aemif_timing da850_evm_nandflash_timing = {
+	.wsetup		= 24,
+	.wstrobe	= 21,
+	.whold		= 14,
+	.rsetup		= 19,
+	.rstrobe	= 50,
+	.rhold		= 0,
+	.ta		= 20,
+};
+
 static struct davinci_nand_pdata da850_evm_nandflash_data = {
 	.parts		= da850_evm_nandflash_partition,
 	.nr_parts	= ARRAY_SIZE(da850_evm_nandflash_partition),
 	.ecc_mode	= NAND_ECC_HW,
 	.ecc_bits	= 4,
 	.options	= NAND_USE_FLASH_BBT,
+	.timing		= &da850_evm_nandflash_timing,
 };
 
 static struct resource da850_evm_nandflash_resource[] = {
@@ -196,6 +205,30 @@
 	iounmap(aemif_addr);
 }
 
+static const short da850_evm_nand_pins[] = {
+	DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+	DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+	DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
+	DA850_NEMA_WE, DA850_NEMA_OE,
+	-1
+};
+
+static const short da850_evm_nor_pins[] = {
+	DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
+	DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
+	DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
+	DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
+	DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
+	DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
+	DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
+	DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
+	DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
+	DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
+	DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
+	DA850_EMA_A_22, DA850_EMA_A_23,
+	-1
+};
+
 static u32 ui_card_detected;
 
 #if defined(CONFIG_MMC_DAVINCI) || \
@@ -205,17 +238,17 @@
 #define HAS_MMC 0
 #endif
 
-static __init void da850_evm_setup_nor_nand(void)
+static inline void da850_evm_setup_nor_nand(void)
 {
 	int ret = 0;
 
 	if (ui_card_detected & !HAS_MMC) {
-		ret = davinci_cfg_reg_list(da850_nand_pins);
+		ret = davinci_cfg_reg_list(da850_evm_nand_pins);
 		if (ret)
 			pr_warning("da850_evm_init: nand mux setup failed: "
 					"%d\n", ret);
 
-		ret = davinci_cfg_reg_list(da850_nor_pins);
+		ret = davinci_cfg_reg_list(da850_evm_nor_pins);
 		if (ret)
 			pr_warning("da850_evm_init: nor mux setup failed: %d\n",
 				ret);
@@ -406,7 +439,7 @@
 /* TPS65070 voltage regulator support */
 
 /* 3.3V */
-struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc1_consumers[] = {
 	{
 		.supply = "usb0_vdda33",
 	},
@@ -416,7 +449,7 @@
 };
 
 /* 3.3V or 1.8V */
-struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc2_consumers[] = {
 	{
 		.supply = "dvdd3318_a",
 	},
@@ -429,14 +462,14 @@
 };
 
 /* 1.2V */
-struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
+static struct regulator_consumer_supply tps65070_dcdc3_consumers[] = {
 	{
 		.supply = "cvdd",
 	},
 };
 
 /* 1.8V LDO */
-struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo1_consumers[] = {
 	{
 		.supply = "sata_vddr",
 	},
@@ -452,7 +485,7 @@
 };
 
 /* 1.2V LDO */
-struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
+static struct regulator_consumer_supply tps65070_ldo2_consumers[] = {
 	{
 		.supply = "sata_vdd",
 	},
@@ -475,7 +508,7 @@
 	.defdcdc_default = true,
 };
 
-struct regulator_init_data tps65070_regulator_data[] = {
+static struct regulator_init_data tps65070_regulator_data[] = {
 	/* dcdc1 */
 	{
 		.constraints = {
@@ -576,6 +609,23 @@
 	-1
 };
 
+static const short da850_evm_mii_pins[] = {
+	DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+	DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+	DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+	DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+	DA850_MDIO_D,
+	-1
+};
+
+static const short da850_evm_rmii_pins[] = {
+	DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+	DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+	DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+	DA850_MDIO_D,
+	-1
+};
+
 static int __init da850_evm_config_emac(void)
 {
 	void __iomem *cfg_chip3_base;
@@ -593,12 +643,12 @@
 
 	if (rmii_en) {
 		val |= BIT(8);
-		ret = davinci_cfg_reg_list(da850_rmii_pins);
+		ret = davinci_cfg_reg_list(da850_evm_rmii_pins);
 		pr_info("EMAC: RMII PHY configured, MII PHY will not be"
 							" functional\n");
 	} else {
 		val &= ~BIT(8);
-		ret = davinci_cfg_reg_list(da850_cpgmac_pins);
+		ret = davinci_cfg_reg_list(da850_evm_mii_pins);
 		pr_info("EMAC: MII PHY configured, RMII PHY will not be"
 							" functional\n");
 	}
@@ -625,8 +675,7 @@
 	/* Enable/Disable MII MDIO clock */
 	gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, rmii_en);
 
-	soc_info->emac_pdata->phy_mask = DA850_EVM_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = DA850_EVM_MDIO_FREQUENCY;
+	soc_info->emac_pdata->phy_id = DA850_EVM_PHY_ID;
 
 	ret = da8xx_register_emac();
 	if (ret)
@@ -787,7 +836,7 @@
 	if (ret)
 		pr_warning("da850_evm_init: rtc setup failed: %d\n", ret);
 
-	ret = da850_register_cpufreq();
+	ret = da850_register_cpufreq("pll0_sysclk3");
 	if (ret)
 		pr_warning("da850_evm_init: cpufreq registration failed: %d\n",
 				ret);
@@ -806,6 +855,9 @@
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static int __init da850_evm_console_init(void)
 {
+	if (!machine_is_davinci_da850_evm())
+		return 0;
+
 	return add_preferred_console("ttyS", 2, "115200");
 }
 console_initcall(da850_evm_console_init);
@@ -816,9 +868,7 @@
 	da850_init();
 }
 
-MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
-	.phys_io	= IO_PHYS,
-	.io_pg_offst	= (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
+MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138/AM18x EVM")
 	.boot_params	= (DA8XX_DDR_BASE + 0x100),
 	.map_io		= da850_evm_map_io,
 	.init_irq	= cp_intc_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm355-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm355-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm355-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm355-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -351,8 +351,6 @@
 }
 
 MACHINE_START(DAVINCI_DM355_EVM, "DaVinci DM355 EVM")
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (0x80000100),
 	.map_io	      = dm355_evm_map_io,
 	.init_irq     = davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm355-leopard.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm355-leopard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm355-leopard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm355-leopard.c	2011-01-04 19:50:19.000000000 -0500
@@ -270,8 +270,6 @@
 }
 
 MACHINE_START(DM355_LEOPARD, "DaVinci DM355 leopard")
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (0x80000100),
 	.map_io	      = dm355_leopard_map_io,
 	.init_irq     = davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm365-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm365-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm365-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm365-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,9 +54,7 @@
 	return 0;
 }
 
-#define DM365_EVM_PHY_MASK		(0x2)
-#define DM365_EVM_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
-
+#define DM365_EVM_PHY_ID		"0:01"
 /*
  * A MAX-II CPLD is used for various board control functions.
  */
@@ -175,7 +173,9 @@
 	.context	= (void *)0x7f00,
 };
 
-static struct snd_platform_data dm365_evm_snd_data;
+static struct snd_platform_data dm365_evm_snd_data = {
+	.asp_chan_q = EVENTQ_3,
+};
 
 static struct i2c_board_info i2c_info[] = {
 	{
@@ -533,8 +533,7 @@
 
 		/* ... and ENET ... */
 		dm365evm_emac_configure();
-		soc_info->emac_pdata->phy_mask = DM365_EVM_PHY_MASK;
-		soc_info->emac_pdata->mdio_max_freq = DM365_EVM_MDIO_FREQUENCY;
+		soc_info->emac_pdata->phy_id = DM365_EVM_PHY_ID;
 		resets &= ~BIT(3);
 
 		/* ... and AIC33 */
@@ -613,8 +612,6 @@
 }
 
 MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM")
-	.phys_io	= IO_PHYS,
-	.io_pg_offst	= (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params	= (0x80000100),
 	.map_io		= dm365_evm_map_io,
 	.init_irq	= davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm644x-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm644x-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm644x-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm644x-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,10 +37,9 @@
 #include <mach/nand.h>
 #include <mach/mmc.h>
 #include <mach/usb.h>
+#include <mach/aemif.h>
 
-#define DM644X_EVM_PHY_MASK		(0x2)
-#define DM644X_EVM_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
-
+#define DM644X_EVM_PHY_ID		"0:01"
 #define LXT971_PHY_ID	(0x001378e2)
 #define LXT971_PHY_MASK	(0xfffffff0)
 
@@ -137,11 +136,22 @@
 	 */
 };
 
+static struct davinci_aemif_timing davinci_evm_nandflash_timing = {
+	.wsetup		= 20,
+	.wstrobe	= 40,
+	.whold		= 20,
+	.rsetup		= 10,
+	.rstrobe	= 40,
+	.rhold		= 10,
+	.ta		= 40,
+};
+
 static struct davinci_nand_pdata davinci_evm_nandflash_data = {
 	.parts		= davinci_evm_nandflash_partition,
 	.nr_parts	= ARRAY_SIZE(davinci_evm_nandflash_partition),
 	.ecc_mode	= NAND_ECC_HW,
 	.options	= NAND_USE_FLASH_BBT,
+	.timing		= &davinci_evm_nandflash_timing,
 };
 
 static struct resource davinci_evm_nandflash_resource[] = {
@@ -695,9 +705,7 @@
 	davinci_serial_init(&uart_config);
 	dm644x_init_asp(&dm644x_evm_snd_data);
 
-	soc_info->emac_pdata->phy_mask = DM644X_EVM_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = DM644X_EVM_MDIO_FREQUENCY;
-
+	soc_info->emac_pdata->phy_id = DM644X_EVM_PHY_ID;
 	/* Register the fixup for PHY on DaVinci */
 	phy_register_fixup_for_uid(LXT971_PHY_ID, LXT971_PHY_MASK,
 					davinci_phy_fixup);
@@ -706,8 +714,6 @@
 
 MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM")
 	/* Maintainer: MontaVista Software <source@mvista.com> */
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (DAVINCI_DDR_BASE + 0x100),
 	.map_io	      = davinci_evm_map_io,
 	.init_irq     = davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm646x-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm646x-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-dm646x-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-dm646x-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,6 +42,7 @@
 #include <mach/nand.h>
 #include <mach/clock.h>
 #include <mach/cdce949.h>
+#include <mach/aemif.h>
 
 #include "clock.h"
 
@@ -71,6 +72,16 @@
 	}
 };
 
+static struct davinci_aemif_timing dm6467tevm_nandflash_timing = {
+	.wsetup		= 29,
+	.wstrobe	= 24,
+	.whold		= 14,
+	.rsetup		= 19,
+	.rstrobe	= 33,
+	.rhold		= 0,
+	.ta		= 29,
+};
+
 static struct davinci_nand_pdata davinci_nand_data = {
 	.mask_cle 		= 0x80000,
 	.mask_ale 		= 0x40000,
@@ -718,9 +729,7 @@
 	.enabled_uarts = (1 << 0),
 };
 
-#define DM646X_EVM_PHY_MASK		(0x2)
-#define DM646X_EVM_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
-
+#define DM646X_EVM_PHY_ID		"0:01"
 /*
  * The following EDMA channels/slots are not being used by drivers (for
  * example: Timer, GPIO, UART events etc) on dm646x, hence they are being
@@ -763,6 +772,9 @@
 	dm646x_init_mcasp0(&dm646x_evm_snd_data[0]);
 	dm646x_init_mcasp1(&dm646x_evm_snd_data[1]);
 
+	if (machine_is_davinci_dm6467tevm())
+		davinci_nand_data.timing = &dm6467tevm_nandflash_timing;
+
 	platform_device_register(&davinci_nand_device);
 
 	dm646x_init_edma(dm646x_edma_rsv);
@@ -770,8 +782,7 @@
 	if (HAS_ATA)
 		davinci_init_ide();
 
-	soc_info->emac_pdata->phy_mask = DM646X_EVM_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = DM646X_EVM_MDIO_FREQUENCY;
+	soc_info->emac_pdata->phy_id = DM646X_EVM_PHY_ID;
 }
 
 #define DM646X_EVM_REF_FREQ		27000000
@@ -786,8 +797,6 @@
 }
 
 MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (0x80000100),
 	.map_io       = davinci_map_io,
 	.init_irq     = davinci_irq_init,
@@ -796,8 +805,6 @@
 MACHINE_END
 
 MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM")
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (0x80000100),
 	.map_io       = davinci_map_io,
 	.init_irq     = davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-mityomapl138.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-mityomapl138.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-mityomapl138.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-mityomapl138.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,422 @@
+/*
+ * Critical Link MityOMAP-L138 SoM
+ *
+ * Copyright (C) 2010 Critical Link LLC - http://www.criticallink.com
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/etherdevice.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/common.h>
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+#include <mach/nand.h>
+#include <mach/mux.h>
+
+#define MITYOMAPL138_PHY_ID		"0:03"
+
+#define FACTORY_CONFIG_MAGIC	0x012C0138
+#define FACTORY_CONFIG_VERSION	0x00010001
+
+/* Data Held in On-Board I2C device */
+struct factory_config {
+	u32	magic;
+	u32	version;
+	u8	mac[6];
+	u32	fpga_type;
+	u32	spare;
+	u32	serialnumber;
+	char	partnum[32];
+};
+
+static struct factory_config factory_config;
+
+static void read_factory_config(struct memory_accessor *a, void *context)
+{
+	int ret;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
+	if (ret != sizeof(struct factory_config)) {
+		pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
+				ret);
+		return;
+	}
+
+	if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
+		pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
+				factory_config.magic);
+		return;
+	}
+
+	if (factory_config.version != FACTORY_CONFIG_VERSION) {
+		pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
+				factory_config.version);
+		return;
+	}
+
+	pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
+	pr_info("MityOMAPL138: Part Number = %s\n", factory_config.partnum);
+	if (is_valid_ether_addr(factory_config.mac))
+		memcpy(soc_info->emac_pdata->mac_addr,
+			factory_config.mac, ETH_ALEN);
+	else
+		pr_warning("MityOMAPL138: Invalid MAC found "
+				"in factory config block\n");
+}
+
+static struct at24_platform_data mityomapl138_fd_chip = {
+	.byte_len	= 256,
+	.page_size	= 8,
+	.flags		= AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
+	.setup		= read_factory_config,
+	.context	= NULL,
+};
+
+static struct davinci_i2c_platform_data mityomap_i2c_0_pdata = {
+	.bus_freq	= 100,	/* kHz */
+	.bus_delay	= 0,	/* usec */
+};
+
+/* TPS65023 voltage regulator support */
+/* 1.2V Core */
+static struct regulator_consumer_supply tps65023_dcdc1_consumers[] = {
+	{
+		.supply = "cvdd",
+	},
+};
+
+/* 1.8V */
+static struct regulator_consumer_supply tps65023_dcdc2_consumers[] = {
+	{
+		.supply = "usb0_vdda18",
+	},
+	{
+		.supply = "usb1_vdda18",
+	},
+	{
+		.supply = "ddr_dvdd18",
+	},
+	{
+		.supply = "sata_vddr",
+	},
+};
+
+/* 1.2V */
+static struct regulator_consumer_supply tps65023_dcdc3_consumers[] = {
+	{
+		.supply = "sata_vdd",
+	},
+	{
+		.supply = "usb_cvdd",
+	},
+	{
+		.supply = "pll0_vdda",
+	},
+	{
+		.supply = "pll1_vdda",
+	},
+};
+
+/* 1.8V Aux LDO, not used */
+static struct regulator_consumer_supply tps65023_ldo1_consumers[] = {
+	{
+		.supply = "1.8v_aux",
+	},
+};
+
+/* FPGA VCC Aux (2.5 or 3.3) LDO */
+static struct regulator_consumer_supply tps65023_ldo2_consumers[] = {
+	{
+		.supply = "vccaux",
+	},
+};
+
+static struct regulator_init_data tps65023_regulator_data[] = {
+	/* dcdc1 */
+	{
+		.constraints = {
+			.min_uV = 1150000,
+			.max_uV = 1350000,
+			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+					  REGULATOR_CHANGE_STATUS,
+			.boot_on = 1,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1_consumers),
+		.consumer_supplies = tps65023_dcdc1_consumers,
+	},
+	/* dcdc2 */
+	{
+		.constraints = {
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+			.boot_on = 1,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc2_consumers),
+		.consumer_supplies = tps65023_dcdc2_consumers,
+	},
+	/* dcdc3 */
+	{
+		.constraints = {
+			.min_uV = 1200000,
+			.max_uV = 1200000,
+			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+			.boot_on = 1,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc3_consumers),
+		.consumer_supplies = tps65023_dcdc3_consumers,
+	},
+	/* ldo1 */
+	{
+		.constraints = {
+			.min_uV = 1800000,
+			.max_uV = 1800000,
+			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+			.boot_on = 1,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_ldo1_consumers),
+		.consumer_supplies = tps65023_ldo1_consumers,
+	},
+	/* ldo2 */
+	{
+		.constraints = {
+			.min_uV = 2500000,
+			.max_uV = 3300000,
+			.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+					  REGULATOR_CHANGE_STATUS,
+			.boot_on = 1,
+		},
+		.num_consumer_supplies = ARRAY_SIZE(tps65023_ldo2_consumers),
+		.consumer_supplies = tps65023_ldo2_consumers,
+	},
+};
+
+static struct i2c_board_info __initdata mityomap_tps65023_info[] = {
+	{
+		I2C_BOARD_INFO("tps65023", 0x48),
+		.platform_data = &tps65023_regulator_data[0],
+	},
+	{
+		I2C_BOARD_INFO("24c02", 0x50),
+		.platform_data = &mityomapl138_fd_chip,
+	},
+};
+
+static int __init pmic_tps65023_init(void)
+{
+	return i2c_register_board_info(1, mityomap_tps65023_info,
+					ARRAY_SIZE(mityomap_tps65023_info));
+}
+
+/*
+ * MityDSP-L138 includes a 256 MByte large-page NAND flash
+ * (128K blocks).
+ */
+static struct mtd_partition mityomapl138_nandflash_partition[] = {
+	{
+		.name		= "rootfs",
+		.offset		= 0,
+		.size		= SZ_128M,
+		.mask_flags	= 0, /* MTD_WRITEABLE, */
+	},
+	{
+		.name		= "homefs",
+		.offset		= MTDPART_OFS_APPEND,
+		.size		= MTDPART_SIZ_FULL,
+		.mask_flags	= 0,
+	},
+};
+
+static struct davinci_nand_pdata mityomapl138_nandflash_data = {
+	.parts		= mityomapl138_nandflash_partition,
+	.nr_parts	= ARRAY_SIZE(mityomapl138_nandflash_partition),
+	.ecc_mode	= NAND_ECC_HW,
+	.options	= NAND_USE_FLASH_BBT | NAND_BUSWIDTH_16,
+	.ecc_bits	= 1, /* 4 bit mode is not supported with 16 bit NAND */
+};
+
+static struct resource mityomapl138_nandflash_resource[] = {
+	{
+		.start	= DA8XX_AEMIF_CS3_BASE,
+		.end	= DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= DA8XX_AEMIF_CTL_BASE,
+		.end	= DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device mityomapl138_nandflash_device = {
+	.name		= "davinci_nand",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &mityomapl138_nandflash_data,
+	},
+	.num_resources	= ARRAY_SIZE(mityomapl138_nandflash_resource),
+	.resource	= mityomapl138_nandflash_resource,
+};
+
+static struct platform_device *mityomapl138_devices[] __initdata = {
+	&mityomapl138_nandflash_device,
+};
+
+static void __init mityomapl138_setup_nand(void)
+{
+	platform_add_devices(mityomapl138_devices,
+				 ARRAY_SIZE(mityomapl138_devices));
+}
+
+static struct davinci_uart_config mityomapl138_uart_config __initdata = {
+	.enabled_uarts = 0x7,
+};
+
+static const short mityomap_mii_pins[] = {
+	DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
+	DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
+	DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
+	DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
+	DA850_MDIO_D,
+	-1
+};
+
+static const short mityomap_rmii_pins[] = {
+	DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+	DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
+	DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
+	DA850_MDIO_D,
+	-1
+};
+
+static void __init mityomapl138_config_emac(void)
+{
+	void __iomem *cfg_chip3_base;
+	int ret;
+	u32 val;
+	struct davinci_soc_info *soc_info = &davinci_soc_info;
+
+	soc_info->emac_pdata->rmii_en = 0; /* hardcoded for now */
+
+	cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
+	val = __raw_readl(cfg_chip3_base);
+
+	if (soc_info->emac_pdata->rmii_en) {
+		val |= BIT(8);
+		ret = davinci_cfg_reg_list(mityomap_rmii_pins);
+		pr_info("RMII PHY configured\n");
+	} else {
+		val &= ~BIT(8);
+		ret = davinci_cfg_reg_list(mityomap_mii_pins);
+		pr_info("MII PHY configured\n");
+	}
+
+	if (ret) {
+		pr_warning("mii/rmii mux setup failed: %d\n", ret);
+		return;
+	}
+
+	/* configure the CFGCHIP3 register for RMII or MII */
+	__raw_writel(val, cfg_chip3_base);
+
+	soc_info->emac_pdata->phy_id = MITYOMAPL138_PHY_ID;
+
+	ret = da8xx_register_emac();
+	if (ret)
+		pr_warning("emac registration failed: %d\n", ret);
+}
+
+static struct davinci_pm_config da850_pm_pdata = {
+	.sleepcount = 128,
+};
+
+static struct platform_device da850_pm_device = {
+	.name	= "pm-davinci",
+	.dev = {
+		.platform_data  = &da850_pm_pdata,
+	},
+	.id	= -1,
+};
+
+static void __init mityomapl138_init(void)
+{
+	int ret;
+
+	/* for now, no special EDMA channels are reserved */
+	ret = da850_register_edma(NULL);
+	if (ret)
+		pr_warning("edma registration failed: %d\n", ret);
+
+	ret = da8xx_register_watchdog();
+	if (ret)
+		pr_warning("watchdog registration failed: %d\n", ret);
+
+	davinci_serial_init(&mityomapl138_uart_config);
+
+	ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata);
+	if (ret)
+		pr_warning("i2c0 registration failed: %d\n", ret);
+
+	ret = pmic_tps65023_init();
+	if (ret)
+		pr_warning("TPS65023 PMIC init failed: %d\n", ret);
+
+	mityomapl138_setup_nand();
+
+	mityomapl138_config_emac();
+
+	ret = da8xx_register_rtc();
+	if (ret)
+		pr_warning("rtc setup failed: %d\n", ret);
+
+	ret = da850_register_cpufreq("pll0_sysclk3");
+	if (ret)
+		pr_warning("cpufreq registration failed: %d\n", ret);
+
+	ret = da8xx_register_cpuidle();
+	if (ret)
+		pr_warning("cpuidle registration failed: %d\n", ret);
+
+	ret = da850_register_pm(&da850_pm_device);
+	if (ret)
+		pr_warning("da850_evm_init: suspend registration failed: %d\n",
+				ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init mityomapl138_console_init(void)
+{
+	if (!machine_is_mityomapl138())
+		return 0;
+
+	return add_preferred_console("ttyS", 1, "115200");
+}
+console_initcall(mityomapl138_console_init);
+#endif
+
+static void __init mityomapl138_map_io(void)
+{
+	da850_init();
+}
+
+MACHINE_START(MITYOMAPL138, "MityDSP-L138/MityARM-1808")
+	.boot_params	= (DA8XX_DDR_BASE + 0x100),
+	.map_io		= mityomapl138_map_io,
+	.init_irq	= cp_intc_init,
+	.timer		= &davinci_timer,
+	.init_machine	= mityomapl138_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-neuros-osd2.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-neuros-osd2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-neuros-osd2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-neuros-osd2.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,9 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/usb.h>
 
-#define NEUROS_OSD2_PHY_MASK		0x2
-#define NEUROS_OSD2_MDIO_FREQUENCY	2200000 /* PHY bus frequency */
-
+#define NEUROS_OSD2_PHY_ID		"0:01"
 #define LXT971_PHY_ID			0x001378e2
 #define LXT971_PHY_MASK			0xfffffff0
 
@@ -252,8 +250,7 @@
 	davinci_serial_init(&uart_config);
 	dm644x_init_asp(&dm644x_ntosd2_snd_data);
 
-	soc_info->emac_pdata->phy_mask = NEUROS_OSD2_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = NEUROS_OSD2_MDIO_FREQUENCY;
+	soc_info->emac_pdata->phy_id = NEUROS_OSD2_PHY_ID;
 
 	davinci_setup_usb(1000, 8);
 	/*
@@ -275,8 +272,6 @@
 
 MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
 	/* Maintainer: Neuros Technologies <neuros@groups.google.com> */
-	.phys_io	= IO_PHYS,
-	.io_pg_offst	= (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params	= (DAVINCI_DDR_BASE + 0x100),
 	.map_io		 = davinci_ntosd2_map_io,
 	.init_irq	= davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-omapl138-hawk.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-omapl138-hawk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-omapl138-hawk.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-omapl138-hawk.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,62 @@
+/*
+ * Hawkboard.org based on TI's OMAP-L138 Platform
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/cp_intc.h>
+#include <mach/da8xx.h>
+
+static struct davinci_uart_config omapl138_hawk_uart_config __initdata = {
+	.enabled_uarts = 0x7,
+};
+
+static __init void omapl138_hawk_init(void)
+{
+	int ret;
+
+	davinci_serial_init(&omapl138_hawk_uart_config);
+
+	ret = da8xx_register_watchdog();
+	if (ret)
+		pr_warning("omapl138_hawk_init: "
+			"watchdog registration failed: %d\n",
+			ret);
+}
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static int __init omapl138_hawk_console_init(void)
+{
+	if (!machine_is_omapl138_hawkboard())
+		return 0;
+
+	return add_preferred_console("ttyS", 2, "115200");
+}
+console_initcall(omapl138_hawk_console_init);
+#endif
+
+static void __init omapl138_hawk_map_io(void)
+{
+	da850_init();
+}
+
+MACHINE_START(OMAPL138_HAWKBOARD, "AM18x/OMAP-L138 Hawkboard")
+	.boot_params	= (DA8XX_DDR_BASE + 0x100),
+	.map_io		= omapl138_hawk_map_io,
+	.init_irq	= cp_intc_init,
+	.timer		= &davinci_timer,
+	.init_machine	= omapl138_hawk_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-sffsdr.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-sffsdr.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-sffsdr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-sffsdr.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,9 +42,7 @@
 #include <mach/mux.h>
 #include <mach/usb.h>
 
-#define SFFSDR_PHY_MASK		(0x2)
-#define SFFSDR_MDIO_FREQUENCY	(2200000) /* PHY bus frequency */
-
+#define SFFSDR_PHY_ID		"0:01"
 static struct mtd_partition davinci_sffsdr_nandflash_partition[] = {
 	/* U-Boot Environment: Block 0
 	 * UBL:                Block 1
@@ -143,8 +141,7 @@
 			     ARRAY_SIZE(davinci_sffsdr_devices));
 	sffsdr_init_i2c();
 	davinci_serial_init(&uart_config);
-	soc_info->emac_pdata->phy_mask = SFFSDR_PHY_MASK;
-	soc_info->emac_pdata->mdio_max_freq = SFFSDR_MDIO_FREQUENCY;
+	soc_info->emac_pdata->phy_id = SFFSDR_PHY_ID;
 	davinci_setup_usb(0, 0); /* We support only peripheral mode. */
 
 	/* mux VLYNQ pins */
@@ -154,8 +151,6 @@
 
 MACHINE_START(SFFSDR, "Lyrtech SFFSDR")
 	/* Maintainer: Hugo Villeneuve hugo.villeneuve@lyrtech.com */
-	.phys_io      = IO_PHYS,
-	.io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
 	.boot_params  = (DAVINCI_DDR_BASE + 0x100),
 	.map_io	      = davinci_sffsdr_map_io,
 	.init_irq     = davinci_irq_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-tnetv107x-evm.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-tnetv107x-evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/board-tnetv107x-evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/board-tnetv107x-evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,9 @@
 #include <linux/ratelimit.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
 
@@ -141,10 +144,63 @@
 	.enabled_uarts	= BIT(1),
 };
 
+static const uint32_t keymap[] = {
+	KEY(0, 0, KEY_NUMERIC_1),
+	KEY(0, 1, KEY_NUMERIC_2),
+	KEY(0, 2, KEY_NUMERIC_3),
+	KEY(0, 3, KEY_FN_F1),
+	KEY(0, 4, KEY_MENU),
+
+	KEY(1, 0, KEY_NUMERIC_4),
+	KEY(1, 1, KEY_NUMERIC_5),
+	KEY(1, 2, KEY_NUMERIC_6),
+	KEY(1, 3, KEY_UP),
+	KEY(1, 4, KEY_FN_F2),
+
+	KEY(2, 0, KEY_NUMERIC_7),
+	KEY(2, 1, KEY_NUMERIC_8),
+	KEY(2, 2, KEY_NUMERIC_9),
+	KEY(2, 3, KEY_LEFT),
+	KEY(2, 4, KEY_ENTER),
+
+	KEY(3, 0, KEY_NUMERIC_STAR),
+	KEY(3, 1, KEY_NUMERIC_0),
+	KEY(3, 2, KEY_NUMERIC_POUND),
+	KEY(3, 3, KEY_DOWN),
+	KEY(3, 4, KEY_RIGHT),
+
+	KEY(4, 0, KEY_FN_F3),
+	KEY(4, 1, KEY_FN_F4),
+	KEY(4, 2, KEY_MUTE),
+	KEY(4, 3, KEY_HOME),
+	KEY(4, 4, KEY_BACK),
+
+	KEY(5, 0, KEY_VOLUMEDOWN),
+	KEY(5, 1, KEY_VOLUMEUP),
+	KEY(5, 2, KEY_F1),
+	KEY(5, 3, KEY_F2),
+	KEY(5, 4, KEY_F3),
+};
+
+static const struct matrix_keymap_data keymap_data = {
+	.keymap		= keymap,
+	.keymap_size	= ARRAY_SIZE(keymap),
+};
+
+static struct matrix_keypad_platform_data keypad_config = {
+	.keymap_data	= &keymap_data,
+	.num_row_gpios	= 6,
+	.num_col_gpios	= 5,
+	.debounce_ms	= 0, /* minimum */
+	.active_low	= 0, /* pull up realization */
+	.no_autorepeat	= 0,
+};
+
 static struct tnetv107x_device_info evm_device_info __initconst = {
 	.serial_config		= &serial_config,
 	.mmc_config[1]		= &mmc_config,	/* controller 1 */
 	.nand_config[0]		= &nand_config,	/* chip select 0 */
+	.keypad_config		= &keypad_config,
 };
 
 static __init void tnetv107x_evm_board_init(void)
@@ -164,8 +220,6 @@
 #endif
 
 MACHINE_START(TNETV107X, "TNETV107X EVM")
-	.phys_io	= TNETV107X_IO_BASE,
-	.io_pg_offst	= (TNETV107X_IO_VIRT >> 18) & 0xfffc,
 	.boot_params	= (TNETV107X_DDR_BASE + 0x100),
 	.map_io		= tnetv107x_init,
 	.init_irq	= cp_intc_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -236,7 +236,7 @@
 		if (!davinci_psc_is_clk_active(ck->gpsc, ck->lpsc))
 			continue;
 
-		pr_info("Clocks: disable unused %s\n", ck->name);
+		pr_debug("Clocks: disable unused %s\n", ck->name);
 
 		davinci_psc_config(psc_domain(ck), ck->gpsc, ck->lpsc,
 				(ck->flags & PSC_SWRSTDISABLE) ?
@@ -287,6 +287,79 @@
 	return rate;
 }
 
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned v;
+	struct pll_data *pll;
+	unsigned long input;
+	unsigned ratio = 0;
+
+	/* If this is the PLL base clock, wrong function to call */
+	if (clk->pll_data)
+		return -EINVAL;
+
+	/* There must be a parent... */
+	if (WARN_ON(!clk->parent))
+		return -EINVAL;
+
+	/* ... the parent must be a PLL... */
+	if (WARN_ON(!clk->parent->pll_data))
+		return -EINVAL;
+
+	/* ... and this clock must have a divider. */
+	if (WARN_ON(!clk->div_reg))
+		return -EINVAL;
+
+	pll = clk->parent->pll_data;
+
+	input = clk->parent->rate;
+
+	/* If pre-PLL, source clock is before the multiplier and divider(s) */
+	if (clk->flags & PRE_PLL)
+		input = pll->input_rate;
+
+	if (input > rate) {
+		/*
+		 * Can afford to provide an output little higher than requested
+		 * only if maximum rate supported by hardware on this sysclk
+		 * is known.
+		 */
+		if (clk->maxrate) {
+			ratio = DIV_ROUND_CLOSEST(input, rate);
+			if (input / ratio > clk->maxrate)
+				ratio = 0;
+		}
+
+		if (ratio == 0)
+			ratio = DIV_ROUND_UP(input, rate);
+
+		ratio--;
+	}
+
+	if (ratio > PLLDIV_RATIO_MASK)
+		return -EINVAL;
+
+	do {
+		v = __raw_readl(pll->base + PLLSTAT);
+	} while (v & PLLSTAT_GOSTAT);
+
+	v = __raw_readl(pll->base + clk->div_reg);
+	v &= ~PLLDIV_RATIO_MASK;
+	v |= ratio | PLLDIV_EN;
+	__raw_writel(v, pll->base + clk->div_reg);
+
+	v = __raw_readl(pll->base + PLLCMD);
+	v |= PLLCMD_GOSET;
+	__raw_writel(v, pll->base + PLLCMD);
+
+	do {
+		v = __raw_readl(pll->base + PLLSTAT);
+	} while (v & PLLSTAT_GOSTAT);
+
+	return 0;
+}
+EXPORT_SYMBOL(davinci_set_sysclk_rate);
+
 static unsigned long clk_leafclk_recalc(struct clk *clk)
 {
 	if (WARN_ON(!clk->parent))
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/clock.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -70,6 +70,9 @@
 #include <linux/list.h>
 #include <asm/clkdev.h>
 
+#define PLLSTAT_GOSTAT	BIT(0)
+#define PLLCMD_GOSET	BIT(0)
+
 struct pll_data {
 	u32 phys_base;
 	void __iomem *base;
@@ -86,6 +89,7 @@
 	struct module		*owner;
 	const char		*name;
 	unsigned long		rate;
+	unsigned long		maxrate;	/* H/W supported max rate */
 	u8			usecount;
 	u8			lpsc;
 	u8			gpsc;
@@ -118,6 +122,7 @@
 int davinci_clk_init(struct clk_lookup *clocks);
 int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv,
 				unsigned int mult, unsigned int postdiv);
+int davinci_set_sysclk_rate(struct clk *clk, unsigned long rate);
 
 extern struct platform_device davinci_wdt_device;
 extern void davinci_watchdog_reset(struct platform_device *);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/cpufreq.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/cpufreq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/cpufreq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,8 @@
 struct davinci_cpufreq {
 	struct device *dev;
 	struct clk *armclk;
+	struct clk *asyncclk;
+	unsigned long asyncrate;
 };
 static struct davinci_cpufreq cpufreq;
 
@@ -104,15 +106,27 @@
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
 	/* if moving to higher frequency, up the voltage beforehand */
-	if (pdata->set_voltage && freqs.new > freqs.old)
-		pdata->set_voltage(idx);
+	if (pdata->set_voltage && freqs.new > freqs.old) {
+		ret = pdata->set_voltage(idx);
+		if (ret)
+			goto out;
+	}
 
 	ret = clk_set_rate(armclk, idx);
+	if (ret)
+		goto out;
+
+	if (cpufreq.asyncclk) {
+		ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
+		if (ret)
+			goto out;
+	}
 
 	/* if moving to lower freq, lower the voltage after lowering freq */
 	if (pdata->set_voltage && freqs.new < freqs.old)
 		pdata->set_voltage(idx);
 
+out:
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
 	return ret;
@@ -185,6 +199,7 @@
 static int __init davinci_cpufreq_probe(struct platform_device *pdev)
 {
 	struct davinci_cpufreq_config *pdata = pdev->dev.platform_data;
+	struct clk *asyncclk;
 
 	if (!pdata)
 		return -EINVAL;
@@ -199,6 +214,12 @@
 		return PTR_ERR(cpufreq.armclk);
 	}
 
+	asyncclk = clk_get(cpufreq.dev, "async");
+	if (!IS_ERR(asyncclk)) {
+		cpufreq.asyncclk = asyncclk;
+		cpufreq.asyncrate = clk_get_rate(asyncclk);
+	}
+
 	return cpufreq_register_driver(&davinci_driver);
 }
 
@@ -206,6 +227,9 @@
 {
 	clk_put(cpufreq.armclk);
 
+	if (cpufreq.asyncclk)
+		clk_put(cpufreq.asyncclk);
+
 	return cpufreq_unregister_driver(&davinci_driver);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/da850.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/da850.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/da850.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/da850.c	2011-01-04 19:50:19.000000000 -0500
@@ -86,6 +86,8 @@
 	.parent		= &pll0_clk,
 	.flags		= CLK_PLL,
 	.div_reg	= PLLDIV3,
+	.set_rate	= davinci_set_sysclk_rate,
+	.maxrate	= 100000000,
 };
 
 static struct clk pll0_sysclk4 = {
@@ -323,12 +325,19 @@
 	.gpsc		= 1,
 };
 
-static struct clk mmcsd_clk = {
-	.name		= "mmcsd",
+static struct clk mmcsd0_clk = {
+	.name		= "mmcsd0",
 	.parent		= &pll0_sysclk2,
 	.lpsc		= DA8XX_LPSC0_MMC_SD,
 };
 
+static struct clk mmcsd1_clk = {
+	.name		= "mmcsd1",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA850_LPSC1_MMC_SD1,
+	.gpsc		= 1,
+};
+
 static struct clk aemif_clk = {
 	.name		= "aemif",
 	.parent		= &pll0_sysclk3,
@@ -375,7 +384,8 @@
 	CLK("davinci_emac.1",	NULL,		&emac_clk),
 	CLK("davinci-mcasp.0",	NULL,		&mcasp_clk),
 	CLK("da8xx_lcdc.0",	NULL,		&lcdc_clk),
-	CLK("davinci_mmc.0",	NULL,		&mmcsd_clk),
+	CLK("davinci_mmc.0",	NULL,		&mmcsd0_clk),
+	CLK("davinci_mmc.1",	NULL,		&mmcsd1_clk),
 	CLK(NULL,		"aemif",	&aemif_clk),
 	CLK(NULL,		NULL,		NULL),
 };
@@ -572,15 +582,9 @@
 	DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
 	DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
 	DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
-	DA850_MDIO_D,
-	-1
-};
-
-const short da850_rmii_pins[] __initdata = {
-	DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
-	DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1,
-	DA850_RMII_RXER, DA850_RMII_MHZ_50_CLK, DA850_MDIO_CLK,
-	DA850_MDIO_D,
+	DA850_MDIO_D, DA850_RMII_TXD_0, DA850_RMII_TXD_1, DA850_RMII_TXEN,
+	DA850_RMII_CRS_DV, DA850_RMII_RXD_0, DA850_RMII_RXD_1, DA850_RMII_RXER,
+	DA850_RMII_MHZ_50_CLK,
 	-1
 };
 
@@ -607,27 +611,19 @@
 	-1
 };
 
-const short da850_nand_pins[] __initdata = {
-	DA850_EMA_D_7, DA850_EMA_D_6, DA850_EMA_D_5, DA850_EMA_D_4,
-	DA850_EMA_D_3, DA850_EMA_D_2, DA850_EMA_D_1, DA850_EMA_D_0,
-	DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
-	DA850_NEMA_WE, DA850_NEMA_OE,
-	-1
-};
-
-const short da850_nor_pins[] __initdata = {
+const short da850_emif25_pins[] __initdata = {
 	DA850_EMA_BA_1, DA850_EMA_CLK, DA850_EMA_WAIT_1, DA850_NEMA_CS_2,
-	DA850_NEMA_WE, DA850_NEMA_OE, DA850_EMA_D_0, DA850_EMA_D_1,
-	DA850_EMA_D_2, DA850_EMA_D_3, DA850_EMA_D_4, DA850_EMA_D_5,
-	DA850_EMA_D_6, DA850_EMA_D_7, DA850_EMA_D_8, DA850_EMA_D_9,
-	DA850_EMA_D_10, DA850_EMA_D_11, DA850_EMA_D_12, DA850_EMA_D_13,
-	DA850_EMA_D_14, DA850_EMA_D_15, DA850_EMA_A_0, DA850_EMA_A_1,
-	DA850_EMA_A_2, DA850_EMA_A_3, DA850_EMA_A_4, DA850_EMA_A_5,
-	DA850_EMA_A_6, DA850_EMA_A_7, DA850_EMA_A_8, DA850_EMA_A_9,
-	DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
-	DA850_EMA_A_14, DA850_EMA_A_15, DA850_EMA_A_16, DA850_EMA_A_17,
-	DA850_EMA_A_18, DA850_EMA_A_19, DA850_EMA_A_20, DA850_EMA_A_21,
-	DA850_EMA_A_22, DA850_EMA_A_23,
+	DA850_NEMA_CS_3, DA850_NEMA_CS_4, DA850_NEMA_WE, DA850_NEMA_OE,
+	DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
+	DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
+	DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
+	DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
+	DA850_EMA_A_0, DA850_EMA_A_1, DA850_EMA_A_2, DA850_EMA_A_3,
+	DA850_EMA_A_4, DA850_EMA_A_5, DA850_EMA_A_6, DA850_EMA_A_7,
+	DA850_EMA_A_8, DA850_EMA_A_9, DA850_EMA_A_10, DA850_EMA_A_11,
+	DA850_EMA_A_12, DA850_EMA_A_13, DA850_EMA_A_14, DA850_EMA_A_15,
+	DA850_EMA_A_16, DA850_EMA_A_17, DA850_EMA_A_18, DA850_EMA_A_19,
+	DA850_EMA_A_20, DA850_EMA_A_21, DA850_EMA_A_22, DA850_EMA_A_23,
 	-1
 };
 
@@ -851,7 +847,7 @@
 	.prediv		= 1,
 	.mult		= 25,
 	.postdiv	= 2,
-	.cvdd_min	= 1140000,
+	.cvdd_min	= 1200000,
 	.cvdd_max	= 1320000,
 };
 
@@ -860,7 +856,7 @@
 	.prediv		= 1,
 	.mult		= 25,
 	.postdiv	= 3,
-	.cvdd_min	= 1050000,
+	.cvdd_min	= 1100000,
 	.cvdd_max	= 1160000,
 };
 
@@ -869,7 +865,7 @@
 	.prediv		= 1,
 	.mult		= 20,
 	.postdiv	= 5,
-	.cvdd_min	= 950000,
+	.cvdd_min	= 1000000,
 	.cvdd_max	= 1050000,
 };
 
@@ -929,10 +925,16 @@
 	.dev = {
 		.platform_data	= &cpufreq_info,
 	},
+	.id = -1,
 };
 
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
 {
+	/* cpufreq driver can help keep an "async" clock constant */
+	if (async_clk)
+		clk_add_alias("async", da850_cpufreq_device.name,
+							async_clk, NULL);
+
 	return platform_device_register(&da850_cpufreq_device);
 }
 
@@ -983,7 +985,7 @@
 	return 0;
 }
 #else
-int __init da850_register_cpufreq(void)
+int __init da850_register_cpufreq(char *async_clk)
 {
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -213,7 +213,7 @@
 				IO_ADDRESS(DAVINCI_SYSTEM_MODULE_BASE + 0x7c);
 
 			/* Configure pull down control */
-			__raw_writel((__raw_readl(pupdctl1) & ~0x400),
+			__raw_writel((__raw_readl(pupdctl1) & ~0xfc0),
 					pupdctl1);
 
 			mmcsd1_resources[0].start = DM365_MMCSD1_BASE;
@@ -295,6 +295,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+struct platform_device davinci_pcm_device = {
+	.name		= "davinci-pcm-audio",
+	.id		= -1,
+};
+
+static void davinci_init_pcm(void)
+{
+	platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
 struct davinci_timer_instance davinci_timer_instance[2] = {
 	{
 		.base		= DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
+	davinci_init_pcm();
 	davinci_init_wdt();
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices-da8xx.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices-da8xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices-da8xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices-da8xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include "clock.h"
 
 #define DA8XX_TPCC_BASE			0x01c00000
+#define DA850_MMCSD1_BASE		0x01e1b000
 #define DA850_TPCC1_BASE		0x01e30000
 #define DA8XX_TPTC0_BASE		0x01c08000
 #define DA8XX_TPTC1_BASE		0x01c08400
@@ -41,7 +42,6 @@
 #define DA8XX_EMAC_CTRL_REG_OFFSET	0x3000
 #define DA8XX_EMAC_MOD_REG_OFFSET	0x2000
 #define DA8XX_EMAC_RAM_OFFSET		0x0000
-#define DA8XX_MDIO_REG_OFFSET		0x4000
 #define DA8XX_EMAC_CTRL_RAM_SIZE	SZ_8K
 
 void __iomem *da8xx_syscfg0_base;
@@ -351,7 +351,7 @@
 static struct resource da8xx_emac_resources[] = {
 	{
 		.start	= DA8XX_EMAC_CPPI_PORT_BASE,
-		.end	= DA8XX_EMAC_CPPI_PORT_BASE + 0x5000 - 1,
+		.end	= DA8XX_EMAC_CPPI_PORT_BASE + SZ_16K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -380,7 +380,6 @@
 	.ctrl_reg_offset	= DA8XX_EMAC_CTRL_REG_OFFSET,
 	.ctrl_mod_reg_offset	= DA8XX_EMAC_MOD_REG_OFFSET,
 	.ctrl_ram_offset	= DA8XX_EMAC_RAM_OFFSET,
-	.mdio_reg_offset	= DA8XX_MDIO_REG_OFFSET,
 	.ctrl_ram_size		= DA8XX_EMAC_CTRL_RAM_SIZE,
 	.version		= EMAC_VERSION_2,
 };
@@ -395,9 +394,34 @@
 	.resource	= da8xx_emac_resources,
 };
 
+static struct resource da8xx_mdio_resources[] = {
+	{
+		.start	= DA8XX_EMAC_MDIO_BASE,
+		.end	= DA8XX_EMAC_MDIO_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device da8xx_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(da8xx_mdio_resources),
+	.resource	= da8xx_mdio_resources,
+};
+
 int __init da8xx_register_emac(void)
 {
-	return platform_device_register(&da8xx_emac_device);
+	int ret;
+
+	ret = platform_device_register(&da8xx_mdio_device);
+	if (ret < 0)
+		return ret;
+	ret = platform_device_register(&da8xx_emac_device);
+	if (ret < 0)
+		return ret;
+	ret = clk_add_alias(NULL, dev_name(&da8xx_mdio_device.dev),
+			    NULL, &da8xx_emac_device.dev);
+	return ret;
 }
 
 static struct resource da830_mcasp1_resources[] = {
@@ -566,6 +590,44 @@
 	return platform_device_register(&da8xx_mmcsd0_device);
 }
 
+#ifdef CONFIG_ARCH_DAVINCI_DA850
+static struct resource da850_mmcsd1_resources[] = {
+	{		/* registers */
+		.start	= DA850_MMCSD1_BASE,
+		.end	= DA850_MMCSD1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{		/* interrupt */
+		.start	= IRQ_DA850_MMCSDINT0_1,
+		.end	= IRQ_DA850_MMCSDINT0_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{		/* DMA RX */
+		.start	= EDMA_CTLR_CHAN(1, 28),
+		.end	= EDMA_CTLR_CHAN(1, 28),
+		.flags	= IORESOURCE_DMA,
+	},
+	{		/* DMA TX */
+		.start	= EDMA_CTLR_CHAN(1, 29),
+		.end	= EDMA_CTLR_CHAN(1, 29),
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device da850_mmcsd1_device = {
+	.name		= "davinci_mmc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(da850_mmcsd1_resources),
+	.resource	= da850_mmcsd1_resources,
+};
+
+int __init da850_register_mmcsd1(struct davinci_mmc_config *config)
+{
+	da850_mmcsd1_device.dev.platform_data = config;
+	return platform_device_register(&da850_mmcsd1_device);
+}
+#endif
+
 static struct resource da8xx_rtc_resources[] = {
 	{
 		.start		= DA8XX_RTC_BASE,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices-tnetv107x.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices-tnetv107x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/devices-tnetv107x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/devices-tnetv107x.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,8 +31,10 @@
 #define TNETV107X_TPTC0_BASE			0x01c10000
 #define TNETV107X_TPTC1_BASE			0x01c10400
 #define TNETV107X_WDOG_BASE			0x08086700
+#define TNETV107X_TSC_BASE			0x08088500
 #define TNETV107X_SDIO0_BASE			0x08088700
 #define TNETV107X_SDIO1_BASE			0x08088800
+#define TNETV107X_KEYPAD_BASE			0x08088a00
 #define TNETV107X_ASYNC_EMIF_CNTRL_BASE		0x08200000
 #define TNETV107X_ASYNC_EMIF_DATA_CE0_BASE	0x30000000
 #define TNETV107X_ASYNC_EMIF_DATA_CE1_BASE	0x40000000
@@ -298,12 +300,55 @@
 	return platform_device_register(pdev);
 }
 
+static struct resource keypad_resources[] = {
+	{
+		.start	= TNETV107X_KEYPAD_BASE,
+		.end	= TNETV107X_KEYPAD_BASE + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_TNETV107X_KEYPAD,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "press",
+	},
+	{
+		.start	= IRQ_TNETV107X_KEYPAD_FREE,
+		.flags	= IORESOURCE_IRQ,
+		.name	= "release",
+	},
+};
+
+static struct platform_device keypad_device = {
+	.name		= "tnetv107x-keypad",
+	.num_resources	= ARRAY_SIZE(keypad_resources),
+	.resource	= keypad_resources,
+};
+
+static struct resource tsc_resources[] = {
+	{
+		.start	= TNETV107X_TSC_BASE,
+		.end	= TNETV107X_TSC_BASE + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_TNETV107X_TSC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tsc_device = {
+	.name		= "tnetv107x-ts",
+	.num_resources	= ARRAY_SIZE(tsc_resources),
+	.resource	= tsc_resources,
+};
+
 void __init tnetv107x_devices_init(struct tnetv107x_device_info *info)
 {
 	int i;
 
 	platform_device_register(&edma_device);
 	platform_device_register(&tnetv107x_wdt_device);
+	platform_device_register(&tsc_device);
 
 	if (info->serial_config)
 		davinci_serial_init(info->serial_config);
@@ -317,4 +362,9 @@
 	for (i = 0; i < 4; i++)
 		if (info->nand_config[i])
 			nand_init(i, info->nand_config[i]);
+
+	if (info->keypad_config) {
+		keypad_device.dev.platform_data = info->keypad_config;
+		platform_device_register(&keypad_device);
+	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm355.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm355.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm355.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm355.c	2011-01-04 19:50:19.000000000 -0500
@@ -359,8 +359,8 @@
 	CLK(NULL, "uart1", &uart1_clk),
 	CLK(NULL, "uart2", &uart2_clk),
 	CLK("i2c_davinci.1", NULL, &i2c_clk),
-	CLK("davinci-asp.0", NULL, &asp0_clk),
-	CLK("davinci-asp.1", NULL, &asp1_clk),
+	CLK("davinci-mcbsp.0", NULL, &asp0_clk),
+	CLK("davinci-mcbsp.1", NULL, &asp1_clk),
 	CLK("davinci_mmc.0", NULL, &mmcsd0_clk),
 	CLK("davinci_mmc.1", NULL, &mmcsd1_clk),
 	CLK("spi_davinci.0", NULL, &spi0_clk),
@@ -664,7 +664,7 @@
 };
 
 static struct platform_device dm355_asp1_device = {
-	.name		= "davinci-asp",
+	.name		= "davinci-mcbsp",
 	.id		= 1,
 	.num_resources	= ARRAY_SIZE(dm355_asp1_resources),
 	.resource	= dm355_asp1_resources,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm365.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm365.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm365.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm365.c	2011-01-04 19:50:19.000000000 -0500
@@ -459,7 +459,7 @@
 	CLK(NULL, "usb", &usb_clk),
 	CLK("davinci_emac.1", NULL, &emac_clk),
 	CLK("davinci_voicecodec", NULL, &voicecodec_clk),
-	CLK("davinci-asp.0", NULL, &asp0_clk),
+	CLK("davinci-mcbsp", NULL, &asp0_clk),
 	CLK(NULL, "rto", &rto_clk),
 	CLK(NULL, "mjcp", &mjcp_clk),
 	CLK(NULL, NULL, NULL),
@@ -691,7 +691,6 @@
 	.ctrl_reg_offset	= DM365_EMAC_CNTRL_OFFSET,
 	.ctrl_mod_reg_offset	= DM365_EMAC_CNTRL_MOD_OFFSET,
 	.ctrl_ram_offset	= DM365_EMAC_CNTRL_RAM_OFFSET,
-	.mdio_reg_offset	= DM365_EMAC_MDIO_OFFSET,
 	.ctrl_ram_size		= DM365_EMAC_CNTRL_RAM_SIZE,
 	.version		= EMAC_VERSION_2,
 };
@@ -699,7 +698,7 @@
 static struct resource dm365_emac_resources[] = {
 	{
 		.start	= DM365_EMAC_BASE,
-		.end	= DM365_EMAC_BASE + 0x47ff,
+		.end	= DM365_EMAC_BASE + SZ_16K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -734,6 +733,21 @@
 	.resource	= dm365_emac_resources,
 };
 
+static struct resource dm365_mdio_resources[] = {
+	{
+		.start	= DM365_EMAC_MDIO_BASE,
+		.end	= DM365_EMAC_MDIO_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device dm365_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(dm365_mdio_resources),
+	.resource	= dm365_mdio_resources,
+};
+
 static u8 dm365_default_priorities[DAVINCI_N_AINTC_IRQ] = {
 	[IRQ_VDINT0]			= 2,
 	[IRQ_VDINT1]			= 6,
@@ -908,8 +922,8 @@
 };
 
 static struct platform_device dm365_asp_device = {
-	.name		= "davinci-asp",
-	.id		= 0,
+	.name		= "davinci-mcbsp",
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(dm365_asp_resources),
 	.resource	= dm365_asp_resources,
 };
@@ -1219,7 +1233,12 @@
 
 	davinci_cfg_reg(DM365_INT_EDMA_CC);
 	platform_device_register(&dm365_edma_device);
+
+	platform_device_register(&dm365_mdio_device);
 	platform_device_register(&dm365_emac_device);
+	clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
+		      NULL, &dm365_emac_device.dev);
+
 	/* Add isif clock alias */
 	clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
 	platform_device_register(&dm365_vpss_device);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm644x.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm644x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm644x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm644x.c	2011-01-04 19:50:19.000000000 -0500
@@ -302,7 +302,7 @@
 	CLK("davinci_emac.1", NULL, &emac_clk),
 	CLK("i2c_davinci.1", NULL, &i2c_clk),
 	CLK("palm_bk3710", NULL, &ide_clk),
-	CLK("davinci-asp", NULL, &asp_clk),
+	CLK("davinci-mcbsp", NULL, &asp_clk),
 	CLK("davinci_mmc.0", NULL, &mmcsd_clk),
 	CLK(NULL, "spi", &spi_clk),
 	CLK(NULL, "gpio", &gpio_clk),
@@ -322,7 +322,6 @@
 	.ctrl_reg_offset	= DM644X_EMAC_CNTRL_OFFSET,
 	.ctrl_mod_reg_offset	= DM644X_EMAC_CNTRL_MOD_OFFSET,
 	.ctrl_ram_offset	= DM644X_EMAC_CNTRL_RAM_OFFSET,
-	.mdio_reg_offset	= DM644X_EMAC_MDIO_OFFSET,
 	.ctrl_ram_size		= DM644X_EMAC_CNTRL_RAM_SIZE,
 	.version		= EMAC_VERSION_1,
 };
@@ -330,7 +329,7 @@
 static struct resource dm644x_emac_resources[] = {
 	{
 		.start	= DM644X_EMAC_BASE,
-		.end	= DM644X_EMAC_BASE + 0x47ff,
+		.end	= DM644X_EMAC_BASE + SZ_16K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -350,6 +349,21 @@
        .resource	= dm644x_emac_resources,
 };
 
+static struct resource dm644x_mdio_resources[] = {
+	{
+		.start	= DM644X_EMAC_MDIO_BASE,
+		.end	= DM644X_EMAC_MDIO_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device dm644x_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(dm644x_mdio_resources),
+	.resource	= dm644x_mdio_resources,
+};
+
 /*
  * Device specific mux setup
  *
@@ -566,7 +580,7 @@
 };
 
 static struct platform_device dm644x_asp_device = {
-	.name		= "davinci-asp",
+	.name		= "davinci-mcbsp",
 	.id		= -1,
 	.num_resources	= ARRAY_SIZE(dm644x_asp_resources),
 	.resource	= dm644x_asp_resources,
@@ -776,7 +790,12 @@
 	clk_add_alias("master", dm644x_ccdc_dev.name, "vpss_master", NULL);
 	clk_add_alias("slave", dm644x_ccdc_dev.name, "vpss_slave", NULL);
 	platform_device_register(&dm644x_edma_device);
+
+	platform_device_register(&dm644x_mdio_device);
 	platform_device_register(&dm644x_emac_device);
+	clk_add_alias(NULL, dev_name(&dm644x_mdio_device.dev),
+		      NULL, &dm644x_emac_device.dev);
+
 	platform_device_register(&dm644x_vpss_device);
 	platform_device_register(&dm644x_ccdc_dev);
 	platform_device_register(&vpfe_capture_dev);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm646x.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm646x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dm646x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dm646x.c	2011-01-04 19:50:19.000000000 -0500
@@ -358,7 +358,6 @@
 	.ctrl_reg_offset	= DM646X_EMAC_CNTRL_OFFSET,
 	.ctrl_mod_reg_offset	= DM646X_EMAC_CNTRL_MOD_OFFSET,
 	.ctrl_ram_offset	= DM646X_EMAC_CNTRL_RAM_OFFSET,
-	.mdio_reg_offset	= DM646X_EMAC_MDIO_OFFSET,
 	.ctrl_ram_size		= DM646X_EMAC_CNTRL_RAM_SIZE,
 	.version		= EMAC_VERSION_2,
 };
@@ -366,7 +365,7 @@
 static struct resource dm646x_emac_resources[] = {
 	{
 		.start	= DM646X_EMAC_BASE,
-		.end	= DM646X_EMAC_BASE + 0x47ff,
+		.end	= DM646X_EMAC_BASE + SZ_16K - 1,
 		.flags	= IORESOURCE_MEM,
 	},
 	{
@@ -401,6 +400,21 @@
 	.resource	= dm646x_emac_resources,
 };
 
+static struct resource dm646x_mdio_resources[] = {
+	{
+		.start	= DM646X_EMAC_MDIO_BASE,
+		.end	= DM646X_EMAC_MDIO_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device dm646x_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(dm646x_mdio_resources),
+	.resource	= dm646x_mdio_resources,
+};
+
 /*
  * Device specific mux setup
  *
@@ -896,7 +910,11 @@
 	if (!cpu_is_davinci_dm646x())
 		return 0;
 
+	platform_device_register(&dm646x_mdio_device);
 	platform_device_register(&dm646x_emac_device);
+	clk_add_alias(NULL, dev_name(&dm646x_mdio_device.dev),
+		      NULL, &dm646x_emac_device.dev);
+
 	return 0;
 }
 postcore_initcall(dm646x_init_devices);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -354,10 +354,12 @@
 static irqreturn_t dma_irq_handler(int irq, void *data)
 {
 	int i;
-	unsigned ctlr;
+	int ctlr;
 	unsigned int cnt = 0;
 
 	ctlr = irq2ctlr(irq);
+	if (ctlr < 0)
+		return IRQ_NONE;
 
 	dev_dbg(data, "dma_irq_handler\n");
 
@@ -408,10 +410,12 @@
 static irqreturn_t dma_ccerr_handler(int irq, void *data)
 {
 	int i;
-	unsigned ctlr;
+	int ctlr;
 	unsigned int cnt = 0;
 
 	ctlr = irq2ctlr(irq);
+	if (ctlr < 0)
+		return IRQ_NONE;
 
 	dev_dbg(data, "dma_ccerr_handler\n");
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/aemif.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/aemif.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/aemif.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/aemif.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,36 @@
+/*
+ * TI DaVinci AEMIF support
+ *
+ * Copyright 2010 (C) Texas Instruments, Inc. http://www.ti.com/
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+#ifndef _MACH_DAVINCI_AEMIF_H
+#define _MACH_DAVINCI_AEMIF_H
+
+#define NRCSR_OFFSET		0x00
+#define AWCCR_OFFSET		0x04
+#define A1CR_OFFSET		0x10
+
+#define ACR_ASIZE_MASK		0x3
+#define ACR_EW_MASK		BIT(30)
+#define ACR_SS_MASK		BIT(31)
+
+/* All timings in nanoseconds */
+struct davinci_aemif_timing {
+	u8	wsetup;
+	u8	wstrobe;
+	u8	whold;
+
+	u8	rsetup;
+	u8	rstrobe;
+	u8	rhold;
+
+	u8	ta;
+};
+
+int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
+					void __iomem *base, unsigned cs);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/da8xx.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/da8xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/da8xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/da8xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -76,9 +76,10 @@
 int da8xx_register_emac(void);
 int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
 int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
+int da850_register_mmcsd1(struct davinci_mmc_config *config);
 void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
 int da8xx_register_rtc(void);
-int da850_register_cpufreq(void);
+int da850_register_cpufreq(char *async_clk);
 int da8xx_register_cpuidle(void);
 void __iomem * __init da8xx_get_mem_ctlr(void);
 int da850_register_pm(struct platform_device *pdev);
@@ -121,11 +122,9 @@
 extern const short da850_i2c0_pins[];
 extern const short da850_i2c1_pins[];
 extern const short da850_cpgmac_pins[];
-extern const short da850_rmii_pins[];
 extern const short da850_mcasp_pins[];
 extern const short da850_lcdcntl_pins[];
 extern const short da850_mmcsd0_pins[];
-extern const short da850_nand_pins[];
-extern const short da850_nor_pins[];
+extern const short da850_emif25_pins[];
 
 #endif /* __ASM_ARCH_DAVINCI_DA8XX_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -29,35 +29,39 @@
 davinci_uart_virt:	.word	0
 		.popsection
 
-		.macro addruart, rx, tmp
+		.macro addruart, rp, rv
 
 		/* Use davinci_uart_phys/virt if already configured */
-10:		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =__virt_to_phys(davinci_uart_phys)
-		ldrne	\rx, =davinci_uart_virt
-		ldr	\rx, [\rx]
-		cmp	\rx, #0			@ is port configured?
+10:		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		ldreq	\rp, =__virt_to_phys(davinci_uart_phys)
+		ldrne	\rp, =davinci_uart_phys
+		add	\rv, \rp, #4		@ davinci_uart_virt
+		ldr	\rp, [\rp, #0]
+		ldr	\rv, [\rv, #0]
+		cmp	\rp, #0			@ is port configured?
+		cmpne	\rv, #0
 		bne	99f			@ already configured
 
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
+		/* Check the debug UART address set in uncompress.h */
+		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
 
 		/* Copy uart phys address from decompressor uart info */
-		ldreq	\tmp, =__virt_to_phys(davinci_uart_phys)
-		ldrne	\tmp, =davinci_uart_phys
-		ldreq	\rx, =DAVINCI_UART_INFO
-		ldrne	\rx, =__phys_to_virt(DAVINCI_UART_INFO)
-		ldr	\rx, [\rx, #0]
-		str	\rx, [\tmp]
+		ldreq	\rv, =__virt_to_phys(davinci_uart_phys)
+		ldrne	\rv, =davinci_uart_phys
+		ldreq	\rp, =DAVINCI_UART_INFO
+		ldrne	\rp, =__phys_to_virt(DAVINCI_UART_INFO)
+		ldr	\rp, [\rp, #0]
+		str	\rp, [\rv]
 
 		/* Copy uart virt address from decompressor uart info */
-		ldreq	\tmp, =__virt_to_phys(davinci_uart_virt)
-		ldrne	\tmp, =davinci_uart_virt
-		ldreq	\rx, =DAVINCI_UART_INFO
-		ldrne	\rx, =__phys_to_virt(DAVINCI_UART_INFO)
-		ldr	\rx, [\rx, #4]
-		str	\rx, [\tmp]
+		ldreq	\rv, =__virt_to_phys(davinci_uart_virt)
+		ldrne	\rv, =davinci_uart_virt
+		ldreq	\rp, =DAVINCI_UART_INFO
+		ldrne	\rp, =__phys_to_virt(DAVINCI_UART_INFO)
+		ldr	\rp, [\rp, #4]
+		str	\rp, [\rv]
 
 		b	10b
 99:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm365.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm365.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm365.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm365.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,10 +21,10 @@
 #include <media/davinci/vpfe_capture.h>
 
 #define DM365_EMAC_BASE			(0x01D07000)
+#define DM365_EMAC_MDIO_BASE		(DM365_EMAC_BASE + 0x4000)
 #define DM365_EMAC_CNTRL_OFFSET		(0x0000)
 #define DM365_EMAC_CNTRL_MOD_OFFSET	(0x3000)
 #define DM365_EMAC_CNTRL_RAM_OFFSET	(0x1000)
-#define DM365_EMAC_MDIO_OFFSET		(0x4000)
 #define DM365_EMAC_CNTRL_RAM_SIZE	(0x2000)
 
 /* Base of key scan register bank */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm644x.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm644x.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm644x.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm644x.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,10 +28,10 @@
 #include <media/davinci/vpfe_capture.h>
 
 #define DM644X_EMAC_BASE		(0x01C80000)
+#define DM644X_EMAC_MDIO_BASE		(DM644X_EMAC_BASE + 0x4000)
 #define DM644X_EMAC_CNTRL_OFFSET	(0x0000)
 #define DM644X_EMAC_CNTRL_MOD_OFFSET	(0x1000)
 #define DM644X_EMAC_CNTRL_RAM_OFFSET	(0x2000)
-#define DM644X_EMAC_MDIO_OFFSET		(0x4000)
 #define DM644X_EMAC_CNTRL_RAM_SIZE	(0x2000)
 
 #define DM644X_ASYNC_EMIF_CONTROL_BASE	0x01E00000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm646x.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm646x.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/dm646x.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/dm646x.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,10 +19,10 @@
 #include <linux/davinci_emac.h>
 
 #define DM646X_EMAC_BASE		(0x01C80000)
+#define DM646X_EMAC_MDIO_BASE		(DM646X_EMAC_BASE + 0x4000)
 #define DM646X_EMAC_CNTRL_OFFSET	(0x0000)
 #define DM646X_EMAC_CNTRL_MOD_OFFSET	(0x1000)
 #define DM646X_EMAC_CNTRL_RAM_OFFSET	(0x2000)
-#define DM646X_EMAC_MDIO_OFFSET		(0x4000)
 #define DM646X_EMAC_CNTRL_RAM_SIZE	(0x2000)
 
 #define DM646X_ASYNC_EMIF_CONTROL_BASE	0x20008000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/nand.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/nand.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/nand.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/nand.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,9 +30,6 @@
 
 #include <linux/mtd/nand.h>
 
-#define NRCSR_OFFSET		0x00
-#define AWCCR_OFFSET		0x04
-#define A1CR_OFFSET		0x10
 #define NANDFCR_OFFSET		0x60
 #define NANDFSR_OFFSET		0x64
 #define NANDF1ECC_OFFSET	0x70
@@ -83,6 +80,9 @@
 	/* Main and mirror bbt descriptor overrides */
 	struct nand_bbt_descr	*bbt_td;
 	struct nand_bbt_descr	*bbt_md;
+
+	/* Access timings */
+	struct davinci_aemif_timing	*timing;
 };
 
 #endif	/* __ARCH_ARM_DAVINCI_NAND_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/psc.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/psc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/psc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/psc.h	2011-01-04 19:50:19.000000000 -0500
@@ -172,6 +172,7 @@
 #define DA8XX_LPSC1_UART2		13
 #define DA8XX_LPSC1_LCDC		16
 #define DA8XX_LPSC1_PWM			17
+#define DA850_LPSC1_MMC_SD1		18
 #define DA8XX_LPSC1_ECAP		20
 #define DA830_LPSC1_EQEP		21
 #define DA850_LPSC1_TPTC2		21
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/tnetv107x.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/tnetv107x.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/tnetv107x.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/tnetv107x.h	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,8 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/serial_8250.h>
+#include <linux/input/matrix_keypad.h>
+
 #include <mach/mmc.h>
 #include <mach/nand.h>
 #include <mach/serial.h>
@@ -41,6 +43,7 @@
 	struct davinci_uart_config	*serial_config;
 	struct davinci_mmc_config	*mmc_config[2];  /* 2 controllers */
 	struct davinci_nand_pdata	*nand_config[4]; /* 4 chipsels */
+	struct matrix_keypad_platform_data *keypad_config;
 };
 
 extern struct platform_device tnetv107x_wdt_device;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/uncompress.h linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/include/mach/uncompress.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/include/mach/uncompress.h	2011-01-04 19:50:19.000000000 -0500
@@ -88,6 +88,8 @@
 		/* DA8xx boards */
 		DEBUG_LL_DA8XX(davinci_da830_evm,	2);
 		DEBUG_LL_DA8XX(davinci_da850_evm,	2);
+		DEBUG_LL_DA8XX(mityomapl138,		1);
+		DEBUG_LL_DA8XX(omapl138_hawkboard,	2);
 
 		/* TNETV107x boards */
 		DEBUG_LL_TNETV107X(tnetv107x,		1);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-davinci/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,23 +20,23 @@
 	select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DM355
-        bool "DaVinci 355 based system"
+	bool "DaVinci 355 based system"
 	select AINTC
 	select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DM646x
-        bool "DaVinci 646x based system"
+	bool "DaVinci 646x based system"
 	select AINTC
 	select ARCH_DAVINCI_DMx
 
 config ARCH_DAVINCI_DA830
-        bool "DA830/OMAP-L137 based system"
+	bool "DA830/OMAP-L137/AM17x based system"
 	select CP_INTC
 	select ARCH_DAVINCI_DA8XX
 	select CPU_DCACHE_WRITETHROUGH # needed on silicon revs 1.0, 1.1
 
 config ARCH_DAVINCI_DA850
-	bool "DA850/OMAP-L138 based system"
+	bool "DA850/OMAP-L138/AM18x based system"
 	select CP_INTC
 	select ARCH_DAVINCI_DA8XX
 	select ARCH_HAS_CPUFREQ
@@ -115,21 +115,21 @@
 	  for development is a DM365 EVM
 
 config MACH_DAVINCI_DA830_EVM
-	bool "TI DA830/OMAP-L137 Reference Platform"
+	bool "TI DA830/OMAP-L137/AM17x Reference Platform"
 	default ARCH_DAVINCI_DA830
 	depends on ARCH_DAVINCI_DA830
 	select GPIO_PCF857X
 	help
-	  Say Y here to select the TI DA830/OMAP-L137 Evaluation Module.
+	  Say Y here to select the TI DA830/OMAP-L137/AM17x Evaluation Module.
 
 choice
-	prompt "Select DA830/OMAP-L137 UI board peripheral"
+	prompt "Select DA830/OMAP-L137/AM17x UI board peripheral"
 	depends on MACH_DAVINCI_DA830_EVM
 	help
-	  The presence of UI card on the DA830/OMAP-L137 EVM is detected
-	  automatically based on successful probe of the I2C based GPIO
-	  expander on that board. This option selected in this menu has
-	  an effect only in case of a successful UI card detection.
+	  The presence of UI card on the DA830/OMAP-L137/AM17x EVM is
+	  detected automatically based on successful probe of the I2C
+	  based GPIO expander on that board. This option selected in this
+	  menu has an effect only in case of a successful UI card detection.
 
 config DA830_UI_LCD
 	bool "LCD"
@@ -140,23 +140,23 @@
 config DA830_UI_NAND
 	bool "NAND flash"
 	help
-	  Say Y here to use the NAND flash.  Do not forget to setup
+	  Say Y here to use the NAND flash. Do not forget to setup
 	  the switch correctly.
 endchoice
 
 config MACH_DAVINCI_DA850_EVM
-	bool "TI DA850/OMAP-L138 Reference Platform"
+	bool "TI DA850/OMAP-L138/AM18x Reference Platform"
 	default ARCH_DAVINCI_DA850
 	depends on ARCH_DAVINCI_DA850
 	select GPIO_PCA953X
 	help
-	  Say Y here to select the TI DA850/OMAP-L138 Evaluation Module.
+	  Say Y here to select the TI DA850/OMAP-L138/AM18x Evaluation Module.
 
 choice
 	prompt "Select peripherals connected to expander on UI board"
 	depends on MACH_DAVINCI_DA850_EVM
 	help
-	  The presence of User Interface (UI) card on the DA850/OMAP-L138
+	  The presence of User Interface (UI) card on the DA850/OMAP-L138/AM18x
 	  EVM is detected automatically based on successful probe of the I2C
 	  based GPIO expander on that card. This option selected in this
 	  menu has an effect only in case of a successful UI card detection.
@@ -165,13 +165,13 @@
 	bool "No peripheral is enabled"
 	help
 	  Say Y if you do not want to enable any of the peripherals connected
-	  to TCA6416 expander on DA850/OMAP-L138 EVM UI card
+	  to TCA6416 expander on DA850/OMAP-L138/AM18x EVM UI card
 
 config DA850_UI_RMII
 	bool "RMII Ethernet PHY"
 	help
-	  Say Y if you want to use the RMII PHY on the DA850/OMAP-L138 EVM.
-	  This PHY is found on the UI daughter card that is supplied with
+	  Say Y if you want to use the RMII PHY on the DA850/OMAP-L138/AM18x
+	  EVM. This PHY is found on the UI daughter card that is supplied with
 	  the EVM.
 	  NOTE: Please take care while choosing this option, MII PHY will
 	  not be functional if RMII mode is selected.
@@ -185,6 +185,22 @@
 	help
 	  Say Y here to select the TI TNETV107X Evaluation Module.
 
+config MACH_MITYOMAPL138
+	bool "Critical Link MityDSP-L138/MityARM-1808 SoM"
+	depends on ARCH_DAVINCI_DA850
+	help
+	  Say Y here to select the Critical Link MityDSP-L138/MityARM-1808
+	  System on Module.  Information on this SoM may be found at
+	  http://www.mitydsp.com
+
+config MACH_OMAPL138_HAWKBOARD
+	bool "TI AM1808 / OMAPL-138 Hawkboard platform"
+	depends on ARCH_DAVINCI_DA850
+	help
+	  Say Y here to select the TI AM1808 / OMAPL-138 Hawkboard platform .
+	  Information of this board may be found at
+	  http://www.hawkboard.org/
+
 config DAVINCI_MUX
 	bool "DAVINCI multiplexing support"
 	depends on ARCH_DAVINCI
@@ -195,20 +211,20 @@
 	  say Y.
 
 config DAVINCI_MUX_DEBUG
-        bool "Multiplexing debug output"
-        depends on DAVINCI_MUX
-        help
-          Makes the multiplexing functions print out a lot of debug info.
-          This is useful if you want to find out the correct values of the
-          multiplexing registers.
+	bool "Multiplexing debug output"
+	depends on DAVINCI_MUX
+	help
+	  Makes the multiplexing functions print out a lot of debug info.
+	  This is useful if you want to find out the correct values of the
+	  multiplexing registers.
 
 config DAVINCI_MUX_WARNINGS
-        bool "Warn about pins the bootloader didn't set up"
-        depends on DAVINCI_MUX
-        help
-          Choose Y here to warn whenever driver initialization logic needs
-          to change the pin multiplexing setup.  When there are no warnings
-          printed, it's safe to deselect DAVINCI_MUX for your product.
+	bool "Warn about pins the bootloader didn't set up"
+	depends on DAVINCI_MUX
+	help
+	  Choose Y here to warn whenever driver initialization logic needs
+	  to change the pin multiplexing setup. When there are no warnings
+	  printed, it's safe to deselect DAVINCI_MUX for your product.
 
 config DAVINCI_RESET_CLOCKS
 	bool "Reset unused clocks during boot"
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-davinci/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
 
 # Common objects
 obj-y 			:= time.o clock.o serial.o io.o psc.o \
-			   gpio.o dma.o usb.o common.o sram.o
+			   gpio.o dma.o usb.o common.o sram.o aemif.o
 
 obj-$(CONFIG_DAVINCI_MUX)		+= mux.o
 
@@ -33,6 +33,8 @@
 obj-$(CONFIG_MACH_DAVINCI_DA830_EVM)	+= board-da830-evm.o
 obj-$(CONFIG_MACH_DAVINCI_DA850_EVM)	+= board-da850-evm.o
 obj-$(CONFIG_MACH_TNETV107X)		+= board-tnetv107x-evm.o
+obj-$(CONFIG_MACH_MITYOMAPL138)		+= board-mityomapl138.o
+obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD)	+= board-omapl138-hawk.o
 
 # Power Management
 obj-$(CONFIG_CPU_FREQ)			+= cpufreq.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-davinci/tnetv107x.c linux-libre-2.6.37-gnu/arch/arm/mach-davinci/tnetv107x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-davinci/tnetv107x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-davinci/tnetv107x.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,7 +104,7 @@
 };
 
 /* PSC control registers */
-static u32 psc_regs[] __initconst = { TNETV107X_PSC_BASE };
+static u32 psc_regs[] = { TNETV107X_PSC_BASE };
 
 /* Host map for interrupt controller */
 static u32 intc_host_map[] = { 0x01010000, 0x01010101, -1 };
@@ -581,7 +581,14 @@
 		.part_no	= 0xb8a1,
 		.manufacturer	= 0x017,
 		.cpu_id		= DAVINCI_CPU_ID_TNETV107X,
-		.name		= "tnetv107x rev1.0",
+		.name		= "tnetv107x rev 1.0",
+	},
+	{
+		.variant	= 0x1,
+		.part_no	= 0xb8a1,
+		.manufacturer	= 0x017,
+		.cpu_id		= DAVINCI_CPU_ID_TNETV107X,
+		.name		= "tnetv107x rev 1.1/1.2",
 	},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-dove/dove-db-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-dove/dove-db-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-dove/dove-db-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-dove/dove-db-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -94,8 +94,6 @@
 }
 
 MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
-	.phys_io	= DOVE_SB_REGS_PHYS_BASE,
-	.io_pg_offst	= ((DOVE_SB_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= dove_db_init,
 	.map_io		= dove_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-dove/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-dove/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-dove/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-dove/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,12 +8,11 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =DOVE_SB_REGS_PHYS_BASE
-	ldrne	\rx, =DOVE_SB_REGS_VIRT_BASE
-	orr	\rx, \rx, #0x00012000
+	.macro	addruart, rp, rv
+	ldr	\rp, =DOVE_SB_REGS_PHYS_BASE
+	ldr	\rv, =DOVE_SB_REGS_VIRT_BASE
+	orr	\rp, \rp, #0x00012000
+	orr	\rv, \rv, #0x00012000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/core.c linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -280,8 +280,6 @@
 
 MACHINE_START(EBSA110, "EBSA110")
 	/* Maintainer: Russell King */
-	.phys_io	= 0xe0000000,
-	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000400,
 	.reserve_lp0	= 1,
 	.reserve_lp2	= 1,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,10 @@
  *
 **/
 
-		.macro	addruart, rx, tmp
-		mov	\rx, #0xf0000000
-		orr	\rx, \rx, #0x00000be0
+		.macro	addruart, rp, rv
+		mov	\rp, #0xf0000000
+		orr	\rp, \rp, #0x00000be0
+		mov	\rp, \rv
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ebsa110/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ebsa110/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,4 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x1f000000)
+#define VMALLOC_END       0xdf000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/adssphere.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/adssphere.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/adssphere.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/adssphere.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,8 +33,6 @@
 
 MACHINE_START(ADSSPHERE, "ADS Sphere board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -358,8 +358,7 @@
 	int i, found = 0, __div = 0, __pdiv = 0;
 
 	/* Don't exceed the maximum rate */
-	max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4),
-		       clk_xtali.rate / 4);
+	max_rate = max3(clk_pll1.rate / 4, clk_pll2.rate / 4, clk_xtali.rate / 4);
 	rate = min(rate, max_rate);
 
 	/*
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/core.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -776,9 +776,15 @@
 	.resource	= ep93xx_i2s_resource,
 };
 
+static struct platform_device ep93xx_pcm_device = {
+	.name		= "ep93xx-pcm-audio",
+	.id		= -1,
+};
+
 void __init ep93xx_register_i2s(void)
 {
 	platform_device_register(&ep93xx_i2s_device);
+	platform_device_register(&ep93xx_pcm_device);
 }
 
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK	(EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@
 }
 EXPORT_SYMBOL(ep93xx_i2s_release);
 
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+	{
+		.start	= EP93XX_AAC_PHYS_BASE,
+		.end	= EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_AACINTR,
+		.end	= IRQ_EP93XX_AACINTR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_ac97_device = {
+	.name		= "ep93xx-ac97",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_ac97_resources),
+	.resource	= ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+	/*
+	 * Make sure that the AC97 pins are not used by I2S.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+	platform_device_register(&ep93xx_ac97_device);
+	platform_device_register(&ep93xx_pcm_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/edb93xx.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/edb93xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/edb93xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/edb93xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -124,8 +124,6 @@
 #ifdef CONFIG_MACH_EDB9301
 MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board")
 	/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -137,8 +135,6 @@
 #ifdef CONFIG_MACH_EDB9302
 MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
 	/* Maintainer: George Kashperko <george@chas.com.ua> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -150,8 +146,6 @@
 #ifdef CONFIG_MACH_EDB9302A
 MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -163,8 +157,6 @@
 #ifdef CONFIG_MACH_EDB9307
 MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
 	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -176,8 +168,6 @@
 #ifdef CONFIG_MACH_EDB9307A
 MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
 	/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -189,8 +179,6 @@
 #ifdef CONFIG_MACH_EDB9312
 MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
 	/* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -202,8 +190,6 @@
 #ifdef CONFIG_MACH_EDB9315
 MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -215,8 +201,6 @@
 #ifdef CONFIG_MACH_EDB9315A
 MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/gesbc9312.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/gesbc9312.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/gesbc9312.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/gesbc9312.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,8 +33,6 @@
 
 MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,11 @@
  */
 #include <mach/ep93xx-regs.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1				@ MMU enabled?
-		ldreq	\rx, =EP93XX_APB_PHYS_BASE	@ Physical base
-		ldrne	\rx, =EP93XX_APB_VIRT_BASE	@ virtual base
-		orr	\rx, \rx, #0x000c0000
+		.macro	addruart, rp, rv
+		ldr	\rp, =EP93XX_APB_PHYS_BASE	@ Physical base
+		ldr	\rv, =EP93XX_APB_VIRT_BASE	@ virtual base
+		orr	\rp, \rp, #0x000c0000
+		orr	\rv, \rv, #0x000c0000
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,13 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/dma.h
+/**
+ * DOC: EP93xx DMA M2P memory to peripheral and peripheral to memory engine
+ *
+ * The EP93xx DMA M2P subsystem handles DMA transfers between memory and
+ * peripherals. DMA M2P channels are available for audio, UARTs and IrDA.
+ * See chapter 10 of the EP93xx users guide for full details on the DMA M2P
+ * engine.
+ *
+ * See sound/soc/ep93xx/ep93xx-pcm.c for an example use of the DMA M2P code.
+ *
  */
 
 #ifndef __ASM_ARCH_DMA_H
@@ -8,12 +16,34 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
+/**
+ * struct ep93xx_dma_buffer - Information about a buffer to be transferred
+ * using the DMA M2P engine
+ *
+ * @list: Entry in DMA buffer list
+ * @bus_addr: Physical address of the buffer
+ * @size: Size of the buffer in bytes
+ */
 struct ep93xx_dma_buffer {
 	struct list_head	list;
 	u32			bus_addr;
 	u16			size;
 };
 
+/**
+ * struct ep93xx_dma_m2p_client - Information about a DMA M2P client
+ *
+ * @name: Unique name for this client
+ * @flags: Client flags
+ * @cookie: User data to pass to callback functions
+ * @buffer_started: Non NULL function to call when a transfer is started.
+ * 			The arguments are the user data cookie and the DMA
+ *			buffer which is starting.
+ * @buffer_finished: Non NULL function to call when a transfer is completed.
+ *			The arguments are the user data cookie, the DMA buffer
+ *			which has completed, and a boolean flag indicating if
+ *			the transfer had an error.
+ */
 struct ep93xx_dma_m2p_client {
 	char			*name;
 	u8			flags;
@@ -24,10 +54,11 @@
 					struct ep93xx_dma_buffer *buf,
 					int bytes, int error);
 
-	/* Internal to the DMA code.  */
+	/* private: Internal use only */
 	void			*channel;
 };
 
+/* DMA M2P ports */
 #define EP93XX_DMA_M2P_PORT_I2S1	0x00
 #define EP93XX_DMA_M2P_PORT_I2S2	0x01
 #define EP93XX_DMA_M2P_PORT_AAC1	0x02
@@ -39,18 +70,80 @@
 #define EP93XX_DMA_M2P_PORT_UART3	0x08
 #define EP93XX_DMA_M2P_PORT_IRDA	0x09
 #define EP93XX_DMA_M2P_PORT_MASK	0x0f
-#define EP93XX_DMA_M2P_TX		0x00
-#define EP93XX_DMA_M2P_RX		0x10
-#define EP93XX_DMA_M2P_ABORT_ON_ERROR	0x20
-#define EP93XX_DMA_M2P_IGNORE_ERROR	0x40
-#define EP93XX_DMA_M2P_ERROR_MASK	0x60
 
-int  ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
+/* DMA M2P client flags */
+#define EP93XX_DMA_M2P_TX		0x00	/* Memory to peripheral */
+#define EP93XX_DMA_M2P_RX		0x10	/* Peripheral to memory */
+
+/*
+ * DMA M2P client error handling flags. See the EP93xx users guide
+ * documentation on the DMA M2P CONTROL register for more details
+ */
+#define EP93XX_DMA_M2P_ABORT_ON_ERROR	0x20	/* Abort on peripheral error */
+#define EP93XX_DMA_M2P_IGNORE_ERROR	0x40	/* Ignore peripheral errors */
+#define EP93XX_DMA_M2P_ERROR_MASK	0x60	/* Mask of error bits */
+
+/**
+ * ep93xx_dma_m2p_client_register - Register a client with the DMA M2P
+ * subsystem
+ *
+ * @m2p: Client information to register
+ * returns 0 on success
+ *
+ * The DMA M2P subsystem allocates a channel and an interrupt line for the DMA
+ * client
+ */
+int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
+
+/**
+ * ep93xx_dma_m2p_client_unregister - Unregister a client from the DMA M2P
+ * subsystem
+ *
+ * @m2p: Client to unregister
+ *
+ * Any transfers currently in progress will be completed in hardware, but
+ * ignored in software.
+ */
 void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *m2p);
+
+/**
+ * ep93xx_dma_m2p_submit - Submit a DMA M2P transfer
+ *
+ * @m2p: DMA Client to submit the transfer on
+ * @buf: DMA Buffer to submit
+ *
+ * If the current or next transfer positions are free on the M2P client then
+ * the transfer is started immediately. If not, the transfer is added to the
+ * list of pending transfers. This function must not be called from the
+ * buffer_finished callback for an M2P channel.
+ *
+ */
 void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *m2p,
 			   struct ep93xx_dma_buffer *buf);
+
+/**
+ * ep93xx_dma_m2p_submit_recursive - Put a DMA transfer on the pending list
+ * for an M2P channel
+ *
+ * @m2p: DMA Client to submit the transfer on
+ * @buf: DMA Buffer to submit
+ *
+ * This function must only be called from the buffer_finished callback for an
+ * M2P channel. It is commonly used to add the next transfer in a chained list
+ * of DMA transfers.
+ */
 void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *m2p,
 				     struct ep93xx_dma_buffer *buf);
+
+/**
+ * ep93xx_dma_m2p_flush - Flush all pending transfers on a DMA M2P client
+ *
+ * @m2p: DMA client to flush transfers on
+ *
+ * Any transfers currently in progress will be completed in hardware, but
+ * ignored in software.
+ *
+ */
 void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *m2p);
 
 #endif /* __ASM_ARCH_DMA_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -105,6 +105,7 @@
 #define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
 
+#define EP93XX_AAC_PHYS_BASE		EP93XX_APB_PHYS(0x00080000)
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
 #define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/platform.h linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/platform.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/include/mach/platform.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/include/mach/platform.h	2011-01-04 19:50:19.000000000 -0500
@@ -61,6 +61,7 @@
 void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/micro9.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/micro9.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/micro9.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/micro9.c	2011-01-04 19:50:19.000000000 -0500
@@ -77,8 +77,6 @@
 #ifdef CONFIG_MACH_MICRO9H
 MACHINE_START(MICRO9, "Contec Micro9-High")
 	/* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -90,8 +88,6 @@
 #ifdef CONFIG_MACH_MICRO9M
 MACHINE_START(MICRO9M, "Contec Micro9-Mid")
 	/* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -103,8 +99,6 @@
 #ifdef CONFIG_MACH_MICRO9L
 MACHINE_START(MICRO9L, "Contec Micro9-Lite")
 	/* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
@@ -116,8 +110,6 @@
 #ifdef CONFIG_MACH_MICRO9S
 MACHINE_START(MICRO9S, "Contec Micro9-Slim")
 	/* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/simone.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/simone.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/simone.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/simone.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,12 +61,11 @@
 	ep93xx_register_fb(&simone_fb_info);
 	ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
 			    ARRAY_SIZE(simone_i2c_board_info));
+	ep93xx_register_ac97();
 }
 
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
 /* Maintainer: Ryan Mallon <ryan@bluewatersys.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/snappercl15.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/snappercl15.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/snappercl15.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/snappercl15.c	2011-01-04 19:50:19.000000000 -0500
@@ -163,8 +163,6 @@
 
 MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15")
 	/* Maintainer: Ryan Mallon <ryan@bluewatersys.com> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE0_PHYS_BASE + 0x100,
 	.map_io		= ep93xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/ts72xx.c linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/ts72xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ep93xx/ts72xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ep93xx/ts72xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -257,8 +257,6 @@
 
 MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= EP93XX_APB_PHYS_BASE,
-	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
 	.map_io		= ts72xx_map_io,
 	.init_irq	= ep93xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/cats-hw.c linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/cats-hw.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/cats-hw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/cats-hw.c	2011-01-04 19:50:19.000000000 -0500
@@ -86,8 +86,6 @@
 
 MACHINE_START(CATS, "Chalice-CATS")
 	/* Maintainer: Philip Blundell */
-	.phys_io	= DC21285_ARMCSR_BASE,
-	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.soft_reboot	= 1,
 	.fixup		= fixup_cats,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/ebsa285.c linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/ebsa285.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/ebsa285.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/ebsa285.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,8 +15,6 @@
 
 MACHINE_START(EBSA285, "EBSA285")
 	/* Maintainer: Russell King */
-	.phys_io	= DC21285_ARMCSR_BASE,
-	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.video_start	= 0x000a0000,
 	.video_end	= 0x000bffff,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,12 +15,10 @@
 
 #ifndef CONFIG_DEBUG_DC21285_PORT
 	/* For NetWinder debugging */
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x7c000000	@ physical
-		movne	\rx, #0xff000000	@ virtual
-		orr	\rx, \rx, #0x000003f8
+		.macro	addruart, rp, rv
+		mov	\rp, #0x000003f8
+		orr	\rv, \rp, #0x7c000000	@ physical
+		orr	\rp, \rp, #0xff000000	@ virtual
 		.endm
 
 #define UART_SHIFT	0
@@ -32,14 +30,14 @@
 		.equ	dc21285_high, ARMCSR_BASE & 0xff000000
 		.equ	dc21285_low,  ARMCSR_BASE & 0x00ffffff
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x42000000
-		movne	\rx, #dc21285_high
+		.macro	addruart, rp, rv
 		.if	dc21285_low
-		orrne	\rx, \rx, #dc21285_low
+		mov	\rp, #dc21285_low
+		.else
+		mov	\rp, #0
 		.endif
+		orr	\rv, \rp, #0x42000000
+		orr	\rp, \rp, #dc21285_high
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,4 +7,4 @@
  */
 
 
-#define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
+#define VMALLOC_END       0xf0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/netwinder-hw.c linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/netwinder-hw.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/netwinder-hw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/netwinder-hw.c	2011-01-04 19:50:19.000000000 -0500
@@ -648,8 +648,6 @@
 
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
 	/* Maintainer: Russell King/Rebel.com */
-	.phys_io	= DC21285_ARMCSR_BASE,
-	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.video_start	= 0x000a0000,
 	.video_end	= 0x000bffff,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/personal.c linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/personal.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-footbridge/personal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-footbridge/personal.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,8 +15,6 @@
 
 MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
 	/* Maintainer: Jamey Hicks / George France */
-	.phys_io	= DC21285_ARMCSR_BASE,
-	.io_pg_offst	= ((0xfe000000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= footbridge_map_io,
 	.init_irq	= footbridge_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-nas4220b.c linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-nas4220b.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-nas4220b.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-nas4220b.c	2011-01-04 19:50:19.000000000 -0500
@@ -101,8 +101,6 @@
 }
 
 MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")
-	.phys_io	= 0x7fffc000,
-	.io_pg_offst	= ((0xffffc000) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= gemini_map_io,
 	.init_irq	= gemini_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-rut1xx.c linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-rut1xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-rut1xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-rut1xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -85,8 +85,6 @@
 }
 
 MACHINE_START(RUT100, "Teltonika RUT100")
-	.phys_io	= 0x7fffc000,
-	.io_pg_offst	= ((0xffffc000) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= gemini_map_io,
 	.init_irq	= gemini_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-wbd111.c linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-wbd111.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-wbd111.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-wbd111.c	2011-01-04 19:50:19.000000000 -0500
@@ -133,8 +133,6 @@
 }
 
 MACHINE_START(WBD111, "Wiliboard WBD-111")
-	.phys_io	= 0x7fffc000,
-	.io_pg_offst	= ((0xffffc000) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= gemini_map_io,
 	.init_irq	= gemini_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-wbd222.c linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-wbd222.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-gemini/board-wbd222.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-gemini/board-wbd222.c	2011-01-04 19:50:19.000000000 -0500
@@ -133,8 +133,6 @@
 }
 
 MACHINE_START(WBD222, "Wiliboard WBD-222")
-	.phys_io	= 0x7fffc000,
-	.io_pg_offst	= ((0xffffc000) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= gemini_map_io,
 	.init_irq	= gemini_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-gemini/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-gemini/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-gemini/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-gemini/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,11 +11,9 @@
  */
 #include <mach/hardware.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =GEMINI_UART_BASE			@ physical
-	ldrne	\rx, =IO_ADDRESS(GEMINI_UART_BASE)	@ virtual
+	.macro	addruart, rp, rv
+	ldr	\rp, =GEMINI_UART_BASE			@ physical
+	ldr	\rv, =IO_ADDRESS(GEMINI_UART_BASE)	@ virtual
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-h720x/h7201-eval.c linux-libre-2.6.37-gnu/arch/arm/mach-h720x/h7201-eval.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-h720x/h7201-eval.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-h720x/h7201-eval.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,6 @@
 
 MACHINE_START(H7201, "Hynix GMS30C7201")
 	/* Maintainer: Robert Schwebel, Pengutronix */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0001000,
 	.map_io		= h720x_map_io,
 	.init_irq	= h720x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-h720x/h7202-eval.c linux-libre-2.6.37-gnu/arch/arm/mach-h720x/h7202-eval.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-h720x/h7202-eval.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-h720x/h7202-eval.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,8 +72,6 @@
 
 MACHINE_START(H7202, "Hynix HMS30C7202")
 	/* Maintainer: Robert Schwebel, Pengutronix */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x40000100,
 	.map_io		= h720x_map_io,
 	.init_irq	= h7202_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-h720x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-h720x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-h720x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-h720x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -16,12 +16,10 @@
 		.equ    io_virt, IO_VIRT
 		.equ    io_phys, IO_PHYS
 
-		.macro  addruart, rx, tmp
-		mrc     p15, 0, \rx, c1, c0
-		tst     \rx, #1  	       @ MMU enabled?
-		moveq   \rx, #io_phys	       @ physical base address
-		movne   \rx, #io_virt	       @ virtual address
-		add     \rx, \rx, #0x00020000   @ UART1
+		.macro  addruart, rp, rv
+		mov     \rp, #0x00020000	@ UART1
+		add     \rv, \rp, #io_virt	@ virtual address
+		add     \rp, \rp, #io_phys	@ physical base address
 		.endm
 
 		.macro  senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-h720x/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-h720x/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-h720x/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-h720x/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,6 @@
 #ifndef __ARCH_ARM_VMALLOC_H
 #define __ARCH_ARM_VMALLOC_H
 
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx1.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx1.c	2011-01-04 19:50:19.000000000 -0500
@@ -592,7 +592,7 @@
 	_REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
 	_REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
 	_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
-	_REGISTER_CLOCK("spi_imx.0", NULL, spi_clk)
+	_REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
 	_REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk)
 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
 	_REGISTER_CLOCK(NULL, "mshc", mshc_clk)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx21.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx21.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx21.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx21.c	2011-01-04 19:50:19.000000000 -0500
@@ -1172,9 +1172,9 @@
 	_REGISTER_CLOCK(NULL, "pwm", pwm_clk[0])
 	_REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0])
 	_REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1])
-	_REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0])
-	_REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1])
-	_REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
+	_REGISTER_CLOCK("imx21-cspi.0", NULL, cspi_clk[0])
+	_REGISTER_CLOCK("imx21-cspi.1", NULL, cspi_clk[1])
+	_REGISTER_CLOCK("imx21-cspi.2", NULL, cspi_clk[2])
 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
 	_REGISTER_CLOCK(NULL, "csi", csi_clk[0])
 	_REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx27.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx27.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/clock-imx27.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/clock-imx27.c	2011-01-04 19:50:19.000000000 -0500
@@ -594,27 +594,27 @@
 DEFINE_CLOCK(uart1_clk1,   0, PCCR1, 31, NULL, NULL, &ipg_clk);
 
 /* Clocks we cannot directly gate, but drivers need their rates */
-DEFINE_CLOCK(cspi1_clk,    0, 0,      0, NULL, &cspi1_clk1, &per2_clk);
-DEFINE_CLOCK(cspi2_clk,    1, 0,      0, NULL, &cspi2_clk1, &per2_clk);
-DEFINE_CLOCK(cspi3_clk,    2, 0,      0, NULL, &cspi13_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc1_clk,    0, 0,      0, NULL, &sdhc1_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc2_clk,    1, 0,      0, NULL, &sdhc2_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc3_clk,    2, 0,      0, NULL, &sdhc3_clk1, &per2_clk);
-DEFINE_CLOCK(pwm_clk,      0, 0,      0, NULL, &pwm_clk1, &per1_clk);
-DEFINE_CLOCK(gpt1_clk,     0, 0,      0, NULL, &gpt1_clk1, &per1_clk);
-DEFINE_CLOCK(gpt2_clk,     1, 0,      0, NULL, &gpt2_clk1, &per1_clk);
-DEFINE_CLOCK(gpt3_clk,     2, 0,      0, NULL, &gpt3_clk1, &per1_clk);
-DEFINE_CLOCK(gpt4_clk,     3, 0,      0, NULL, &gpt4_clk1, &per1_clk);
-DEFINE_CLOCK(gpt5_clk,     4, 0,      0, NULL, &gpt5_clk1, &per1_clk);
-DEFINE_CLOCK(gpt6_clk,     5, 0,      0, NULL, &gpt6_clk1, &per1_clk);
-DEFINE_CLOCK(uart1_clk,    0, 0,      0, NULL, &uart1_clk1, &per1_clk);
-DEFINE_CLOCK(uart2_clk,    1, 0,      0, NULL, &uart2_clk1, &per1_clk);
-DEFINE_CLOCK(uart3_clk,    2, 0,      0, NULL, &uart3_clk1, &per1_clk);
-DEFINE_CLOCK(uart4_clk,    3, 0,      0, NULL, &uart4_clk1, &per1_clk);
-DEFINE_CLOCK(uart5_clk,    4, 0,      0, NULL, &uart5_clk1, &per1_clk);
-DEFINE_CLOCK(uart6_clk,    5, 0,      0, NULL, &uart6_clk1, &per1_clk);
-DEFINE_CLOCK1(lcdc_clk,    0, 0,      0, parent, &lcdc_clk1, &per3_clk);
-DEFINE_CLOCK1(csi_clk,     0, 0,      0, parent, &csi_clk1, &per4_clk);
+DEFINE_CLOCK(cspi1_clk,    0, NULL,   0, NULL, &cspi1_clk1, &per2_clk);
+DEFINE_CLOCK(cspi2_clk,    1, NULL,   0, NULL, &cspi2_clk1, &per2_clk);
+DEFINE_CLOCK(cspi3_clk,    2, NULL,   0, NULL, &cspi13_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc1_clk,    0, NULL,   0, NULL, &sdhc1_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc2_clk,    1, NULL,   0, NULL, &sdhc2_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc3_clk,    2, NULL,   0, NULL, &sdhc3_clk1, &per2_clk);
+DEFINE_CLOCK(pwm_clk,      0, NULL,   0, NULL, &pwm_clk1, &per1_clk);
+DEFINE_CLOCK(gpt1_clk,     0, NULL,   0, NULL, &gpt1_clk1, &per1_clk);
+DEFINE_CLOCK(gpt2_clk,     1, NULL,   0, NULL, &gpt2_clk1, &per1_clk);
+DEFINE_CLOCK(gpt3_clk,     2, NULL,   0, NULL, &gpt3_clk1, &per1_clk);
+DEFINE_CLOCK(gpt4_clk,     3, NULL,   0, NULL, &gpt4_clk1, &per1_clk);
+DEFINE_CLOCK(gpt5_clk,     4, NULL,   0, NULL, &gpt5_clk1, &per1_clk);
+DEFINE_CLOCK(gpt6_clk,     5, NULL,   0, NULL, &gpt6_clk1, &per1_clk);
+DEFINE_CLOCK(uart1_clk,    0, NULL,   0, NULL, &uart1_clk1, &per1_clk);
+DEFINE_CLOCK(uart2_clk,    1, NULL,   0, NULL, &uart2_clk1, &per1_clk);
+DEFINE_CLOCK(uart3_clk,    2, NULL,   0, NULL, &uart3_clk1, &per1_clk);
+DEFINE_CLOCK(uart4_clk,    3, NULL,   0, NULL, &uart4_clk1, &per1_clk);
+DEFINE_CLOCK(uart5_clk,    4, NULL,   0, NULL, &uart5_clk1, &per1_clk);
+DEFINE_CLOCK(uart6_clk,    5, NULL,   0, NULL, &uart6_clk1, &per1_clk);
+DEFINE_CLOCK1(lcdc_clk,    0, NULL,   0, parent, &lcdc_clk1, &per3_clk);
+DEFINE_CLOCK1(csi_clk,     0, NULL,   0, parent, &csi_clk1, &per4_clk);
 
 #define _REGISTER_CLOCK(d, n, c) \
 	{ \
@@ -640,9 +640,9 @@
 	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
 	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
 	_REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk)
-	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+	_REGISTER_CLOCK("imx27-cspi.0", NULL, cspi1_clk)
+	_REGISTER_CLOCK("imx27-cspi.1", NULL, cspi2_clk)
+	_REGISTER_CLOCK("imx27-cspi.2", NULL, cspi3_clk)
 	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
 	_REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
 	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -314,27 +314,6 @@
 	},
 };
 
-#ifdef CONFIG_MACH_MX27
-static struct resource mxc_fec_resources[] = {
-	{
-		.start = MX27_FEC_BASE_ADDR,
-		.end = MX27_FEC_BASE_ADDR + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX27_INT_FEC,
-		.end = MX27_INT_FEC,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_fec_device = {
-	.name = "fec",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(mxc_fec_resources),
-	.resource = mxc_fec_resources,
-};
-#endif
-
 static struct resource mxc_pwm_resources[] = {
 	{
 		.start = MX2x_PWM_BASE_ADDR,
@@ -480,41 +459,6 @@
 };
 #endif
 
-#define DEFINE_IMX_SSI_DMARES(_name, ssin, suffix)			\
-	{								\
-		.name = _name,						\
-		.start = MX2x_DMA_REQ_SSI ## ssin ## _ ## suffix,	\
-		.end = MX2x_DMA_REQ_SSI ## ssin ## _ ## suffix,		\
-		.flags = IORESOURCE_DMA,				\
-	}
-
-#define DEFINE_IMX_SSI_DEVICE(n, ssin, baseaddr, irq)			\
-	static struct resource imx_ssi_resources ## n[] = {		\
-		{							\
-			.start = MX2x_SSI ## ssin ## _BASE_ADDR,	\
-			.end = MX2x_SSI ## ssin ## _BASE_ADDR + 0x6f,	\
-			.flags = IORESOURCE_MEM,			\
-		}, {							\
-			.start = MX2x_INT_SSI1,				\
-			.end = MX2x_INT_SSI1,				\
-			.flags = IORESOURCE_IRQ,			\
-		},							\
-		DEFINE_IMX_SSI_DMARES("tx0", ssin, TX0),		\
-		DEFINE_IMX_SSI_DMARES("rx0", ssin, RX0),		\
-		DEFINE_IMX_SSI_DMARES("tx1", ssin, TX1),		\
-		DEFINE_IMX_SSI_DMARES("rx1", ssin, RX1),		\
-	};								\
-									\
-	struct platform_device imx_ssi_device ## n = {			\
-		.name = "imx-ssi",					\
-		.id = n,						\
-		.num_resources = ARRAY_SIZE(imx_ssi_resources ## n),	\
-		.resource = imx_ssi_resources ## n,			\
-	}
-
-DEFINE_IMX_SSI_DEVICE(0, 1, MX2x_SSI1_BASE_ADDR, MX2x_INT_SSI1);
-DEFINE_IMX_SSI_DEVICE(1, 2, MX2x_SSI1_BASE_ADDR, MX2x_INT_SSI1);
-
 /* GPIO port description */
 #define DEFINE_MXC_GPIO_PORT_IRQ(SOC, n, _irq)				\
 	{								\
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 extern struct platform_device mxc_wdt;
 extern struct platform_device mxc_w1_master_device;
 extern struct platform_device mxc_fb_device;
-extern struct platform_device mxc_fec_device;
 extern struct platform_device mxc_pwm_device;
 extern struct platform_device mxc_sdhc_device0;
 extern struct platform_device mxc_sdhc_device1;
@@ -26,7 +25,5 @@
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
 extern struct platform_device mx21_usbhc_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_kpp_device;
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx1.h linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx1.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx1.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx1.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,10 +9,12 @@
 #include <mach/mx1.h>
 #include <mach/devices-common.h>
 
-#define imx1_add_i2c_imx(pdata)		\
-	imx_add_imx_i2c(0, MX1_I2C_BASE_ADDR, SZ_4K, MX1_INT_I2C, pdata)
+extern const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst;
+#define imx1_add_imx_i2c(pdata)		\
+	imx_add_imx_i2c(&imx1_imx_i2c_data, pdata)
 
-#define imx1_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_3irq(0, MX1_UART1_BASE_ADDR, 0xd0, MX1_INT_UART1RX, MX1_INT_UART1TX, MX1_INT_UART1RTS, pdata)
-#define imx1_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_3irq(0, MX1_UART2_BASE_ADDR, 0xd0, MX1_INT_UART2RX, MX1_INT_UART2TX, MX1_INT_UART2RTS, pdata)
+extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst;
+#define imx1_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata)
+#define imx1_add_imx_uart0(pdata)	imx1_add_imx_uart(0, pdata)
+#define imx1_add_imx_uart1(pdata)	imx1_add_imx_uart(1, pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx21.h linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx21.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx21.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx21.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,22 +9,28 @@
 #include <mach/mx21.h>
 #include <mach/devices-common.h>
 
-#define imx21_add_i2c_imx(pdata)	\
-	imx_add_imx_i2c(0, MX2x_I2C_BASE_ADDR, SZ_4K, MX2x_INT_I2C, pdata)
+extern const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst;
+#define imx21_add_imx_i2c(pdata)	\
+	imx_add_imx_i2c(&imx21_imx_i2c_data, pdata)
 
-#define imx21_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_1irq(0, MX21_UART1_BASE_ADDR, SZ_4K, MX21_INT_UART1, pdata)
-#define imx21_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_1irq(1, MX21_UART2_BASE_ADDR, SZ_4K, MX21_INT_UART2, pdata)
-#define imx21_add_imx_uart2(pdata)	\
-	imx_add_imx_uart_1irq(2, MX21_UART3_BASE_ADDR, SZ_4K, MX21_INT_UART3, pdata)
-#define imx21_add_imx_uart3(pdata)	\
-	imx_add_imx_uart_1irq(3, MX21_UART4_BASE_ADDR, SZ_4K, MX21_INT_UART4, pdata)
+extern const struct imx_imx_ssi_data imx21_imx_ssi_data[] __initconst;
+#define imx21_add_imx_ssi(id, pdata)	\
+	imx_add_imx_ssi(&imx21_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst;
+#define imx21_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx21_imx_uart_data[id], pdata)
+#define imx21_add_imx_uart0(pdata)	imx21_add_imx_uart(0, pdata)
+#define imx21_add_imx_uart1(pdata)	imx21_add_imx_uart(1, pdata)
+#define imx21_add_imx_uart2(pdata)	imx21_add_imx_uart(2, pdata)
+#define imx21_add_imx_uart3(pdata)	imx21_add_imx_uart(3, pdata)
 
+extern const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst;
 #define imx21_add_mxc_nand(pdata)	\
-	imx_add_mxc_nand_v1(MX21_NFC_BASE_ADDR, MX21_INT_NANDFC, pdata)
+	imx_add_mxc_nand(&imx21_mxc_nand_data, pdata)
 
-#define imx21_add_spi_imx0(pdata)	\
-	imx_add_spi_imx(0, MX21_CSPI1_BASE_ADDR, SZ_4K, MX21_INT_CSPI1, pdata)
-#define imx21_add_spi_imx1(pdata)	\
-	imx_add_spi_imx(1, MX21_CSPI2_BASE_ADDR, SZ_4K, MX21_INT_CSPI2, pdata)
+extern const struct imx_spi_imx_data imx21_cspi_data[] __initconst;
+#define imx21_add_cspi(id, pdata)	\
+	imx_add_spi_imx(&imx21_cspi_data[id], pdata)
+#define imx21_add_spi_imx0(pdata)	imx21_add_cspi(0, pdata)
+#define imx21_add_spi_imx1(pdata)	imx21_add_cspi(1, pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx27.h linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx27.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/devices-imx27.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/devices-imx27.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,30 +9,35 @@
 #include <mach/mx27.h>
 #include <mach/devices-common.h>
 
-#define imx27_add_i2c_imx0(pdata)	\
-	imx_add_imx_i2c(0, MX27_I2C1_BASE_ADDR, SZ_4K, MX27_INT_I2C1, pdata)
-#define imx27_add_i2c_imx1(pdata)	\
-	imx_add_imx_i2c(1, MX27_I2C2_BASE_ADDR, SZ_4K, MX27_INT_I2C2, pdata)
+extern const struct imx_fec_data imx27_fec_data __initconst;
+#define imx27_add_fec(pdata)	\
+	imx_add_fec(&imx27_fec_data, pdata)
 
-#define imx27_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_1irq(0, MX27_UART1_BASE_ADDR, SZ_4K, MX27_INT_UART1, pdata)
-#define imx27_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_1irq(1, MX27_UART2_BASE_ADDR, SZ_4K, MX27_INT_UART2, pdata)
-#define imx27_add_imx_uart2(pdata)	\
-	imx_add_imx_uart_1irq(2, MX27_UART3_BASE_ADDR, SZ_4K, MX27_INT_UART3, pdata)
-#define imx27_add_imx_uart3(pdata)	\
-	imx_add_imx_uart_1irq(3, MX27_UART4_BASE_ADDR, SZ_4K, MX27_INT_UART4, pdata)
-#define imx27_add_imx_uart4(pdata)	\
-	imx_add_imx_uart_1irq(4, MX27_UART5_BASE_ADDR, SZ_4K, MX27_INT_UART5, pdata)
-#define imx27_add_imx_uart5(pdata)	\
-	imx_add_imx_uart_1irq(5, MX27_UART6_BASE_ADDR, SZ_4K, MX27_INT_UART6, pdata)
+extern const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst;
+#define imx27_add_imx_i2c(id, pdata)	\
+	imx_add_imx_i2c(&imx27_imx_i2c_data[id], pdata)
+
+extern const struct imx_imx_ssi_data imx27_imx_ssi_data[] __initconst;
+#define imx27_add_imx_ssi(id, pdata)    \
+	imx_add_imx_ssi(&imx27_imx_ssi_data[id], pdata)
 
+extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst;
+#define imx27_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx27_imx_uart_data[id], pdata)
+#define imx27_add_imx_uart0(pdata)	imx27_add_imx_uart(0, pdata)
+#define imx27_add_imx_uart1(pdata)	imx27_add_imx_uart(1, pdata)
+#define imx27_add_imx_uart2(pdata)	imx27_add_imx_uart(2, pdata)
+#define imx27_add_imx_uart3(pdata)	imx27_add_imx_uart(3, pdata)
+#define imx27_add_imx_uart4(pdata)	imx27_add_imx_uart(4, pdata)
+#define imx27_add_imx_uart5(pdata)	imx27_add_imx_uart(5, pdata)
+
+extern const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst;
 #define imx27_add_mxc_nand(pdata)	\
-	imx_add_mxc_nand_v1(MX27_NFC_BASE_ADDR, MX27_INT_NANDFC, pdata)
+	imx_add_mxc_nand(&imx27_mxc_nand_data, pdata)
 
-#define imx27_add_spi_imx0(pdata)	\
-	imx_add_spi_imx(0, MX27_CSPI1_BASE_ADDR, SZ_4K, MX27_INT_CSPI1, pdata)
-#define imx27_add_spi_imx1(pdata)	\
-	imx_add_spi_imx(1, MX27_CSPI2_BASE_ADDR, SZ_4K, MX27_INT_CSPI2, pdata)
-#define imx27_add_spi_imx2(pdata)	\
-	imx_add_spi_imx(2, MX27_CSPI3_BASE_ADDR, SZ_4K, MX27_INT_CSPI3, pdata)
+extern const struct imx_spi_imx_data imx27_cspi_data[] __initconst;
+#define imx27_add_cspi(id, pdata)	\
+	imx_add_spi_imx(&imx27_cspi_data[id], pdata)
+#define imx27_add_spi_imx0(pdata)	imx27_add_cspi(0, pdata)
+#define imx27_add_spi_imx1(pdata)	imx27_add_cspi(1, pdata)
+#define imx27_add_spi_imx2(pdata)	imx27_add_cspi(2, pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,13 +36,12 @@
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/spi.h>
-#include <mach/ssi.h>
 #include <mach/audmux.h>
 
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int eukrea_mbimx27_pins[] = {
+static const int eukrea_mbimx27_pins[] __initconst = {
 	/* UART2 */
 	PE3_PF_UART2_CTS,
 	PE4_PF_UART2_RTS,
@@ -251,9 +250,6 @@
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
-	|| defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-
 #define ADS7846_PENDOWN (GPIO_PORTD | 25)
 
 static void ads7846_dev_init(void)
@@ -274,9 +270,7 @@
 	.get_pendown_state	= ads7846_get_pendown_state,
 	.keep_vref_on		= 1,
 };
-#endif
 
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
 static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
 	[0] = {
 		.modalias	= "ads7846",
@@ -295,7 +289,6 @@
 	.chipselect	= eukrea_mbimx27_spi_cs,
 	.num_chipselect = ARRAY_SIZE(eukrea_mbimx27_spi_cs),
 };
-#endif
 
 static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = {
 	{
@@ -311,7 +304,8 @@
 	.dat3_card_detect = 1,
 };
 
-struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata __initconst = {
 	.flags = IMX_SSI_DMA | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -357,7 +351,7 @@
 	i2c_register_board_info(0, eukrea_mbimx27_i2c_devices,
 				ARRAY_SIZE(eukrea_mbimx27_i2c_devices));
 
-	mxc_register_device(&imx_ssi_device0, &eukrea_mbimx27_ssi_pdata);
+	imx27_add_imx_ssi(0, &eukrea_mbimx27_ssi_pdata);
 
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) \
 	|| defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/include/mach/dma-v1.h linux-libre-2.6.37-gnu/arch/arm/mach-imx/include/mach/dma-v1.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/include/mach/dma-v1.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/include/mach/dma-v1.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,8 @@
 
 #define imx_has_dma_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
 
+#include <mach/dma.h>
+
 #define IMX_DMA_CHANNELS  16
 
 #define DMA_MODE_READ		0
@@ -96,12 +98,6 @@
 
 void imx_dma_free(int channel);
 
-enum imx_dma_prio {
-	DMA_PRIO_HIGH = 0,
-	DMA_PRIO_MEDIUM = 1,
-	DMA_PRIO_LOW = 2
-};
-
 int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio);
 
 #endif	/* __MACH_DMA_V1_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-imx/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -147,8 +147,8 @@
 	default MACH_EUKREA_MBIMX27_BASEBOARD
 
 config MACH_EUKREA_MBIMX27_BASEBOARD
-	prompt "Eukrea MBIMX27 development board"
-	bool
+	bool "Eukrea MBIMX27 development board"
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_SPI_IMX
 	help
@@ -164,6 +164,15 @@
 	  Include support for MX27PDK platform. This includes specific
 	  configurations for the board and its peripherals.
 
+config MACH_IMX27_VISSTRIM_M10
+	bool "Vista Silicon i.MX27 Visstrim_m10"
+	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_UART
+	help
+	  Include support for Visstrim_m10 platform and its different variants.
+	  This includes specific configurations for the board and its
+	  peripherals.
+
 config MACH_IMX27LITE
 	bool "LogicPD MX27 LITEKIT platform"
 	select IMX_HAVE_PLATFORM_IMX_UART
@@ -174,6 +183,7 @@
 config MACH_PCA100
 	bool "Phytec phyCARD-s (pca100)"
 	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_MXC_NAND
 	select IMX_HAVE_PLATFORM_SPI_IMX
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-cpuimx27.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-cpuimx27.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-cpuimx27.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-cpuimx27.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int eukrea_cpuimx27_pins[] = {
+static const int eukrea_cpuimx27_pins[] __initconst = {
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -157,7 +157,6 @@
 
 static struct platform_device *platform_devices[] __initdata = {
 	&eukrea_cpuimx27_nor_mtd_device,
-	&mxc_fec_device,
 	&mxc_wdt,
 	&mxc_w1_master_device,
 };
@@ -259,8 +258,9 @@
 	i2c_register_board_info(0, eukrea_cpuimx27_i2c_devices,
 				ARRAY_SIZE(eukrea_cpuimx27_i2c_devices));
 
-	imx27_add_i2c_imx0(&cpuimx27_i2c1_data);
+	imx27_add_imx_i2c(0, &cpuimx27_i2c1_data);
 
+	imx27_add_fec(NULL);
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
@@ -307,8 +307,6 @@
 };
 
 MACHINE_START(CPUIMX27, "EUKREA CPUIMX27")
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-imx27lite.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-imx27lite.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-imx27lite.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-imx27lite.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mx27lite_pins[] = {
+static const int mx27lite_pins[] __initconst = {
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -58,16 +58,12 @@
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct platform_device *platform_devices[] __initdata = {
-	&mxc_fec_device,
-};
-
 static void __init mx27lite_init(void)
 {
 	mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins),
 		"imx27lite");
 	imx27_add_imx_uart0(&uart_pdata);
-	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+	imx27_add_fec(NULL);
 }
 
 static void __init mx27lite_timer_init(void)
@@ -80,8 +76,6 @@
 };
 
 MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-imx27_visstrim_m10.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-imx27_visstrim_m10.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-imx27_visstrim_m10.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,261 @@
+/*
+ * mach-imx27_visstrim_m10.c
+ *
+ * Copyright 2010  Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Based on mach-pcm038.c, mach-pca100.c, mach-mx27ads.c and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/mmc.h>
+#include <mach/iomux.h>
+#include <mach/mxc_ehci.h>
+
+#include "devices-imx27.h"
+#include "devices.h"
+
+#define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
+#define SDHC1_IRQ IRQ_GPIOB(25)
+
+static const int visstrim_m10_pins[] __initconst = {
+	/* UART1 (console) */
+	PE12_PF_UART1_TXD,
+	PE13_PF_UART1_RXD,
+	PE14_PF_UART1_CTS,
+	PE15_PF_UART1_RTS,
+	/* FEC */
+	PD0_AIN_FEC_TXD0,
+	PD1_AIN_FEC_TXD1,
+	PD2_AIN_FEC_TXD2,
+	PD3_AIN_FEC_TXD3,
+	PD4_AOUT_FEC_RX_ER,
+	PD5_AOUT_FEC_RXD1,
+	PD6_AOUT_FEC_RXD2,
+	PD7_AOUT_FEC_RXD3,
+	PD8_AF_FEC_MDIO,
+	PD9_AIN_FEC_MDC,
+	PD10_AOUT_FEC_CRS,
+	PD11_AOUT_FEC_TX_CLK,
+	PD12_AOUT_FEC_RXD0,
+	PD13_AOUT_FEC_RX_DV,
+	PD14_AOUT_FEC_RX_CLK,
+	PD15_AOUT_FEC_COL,
+	PD16_AIN_FEC_TX_ER,
+	PF23_AIN_FEC_TX_EN,
+	/* SDHC1 */
+	PE18_PF_SD1_D0,
+	PE19_PF_SD1_D1,
+	PE20_PF_SD1_D2,
+	PE21_PF_SD1_D3,
+	PE22_PF_SD1_CMD,
+	PE23_PF_SD1_CLK,
+	/* Both I2Cs */
+	PD17_PF_I2C_DATA,
+	PD18_PF_I2C_CLK,
+	PC5_PF_I2C2_SDA,
+	PC6_PF_I2C2_SCL,
+	/* USB OTG */
+	OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT,
+	PC9_PF_USBOTG_DATA0,
+	PC11_PF_USBOTG_DATA1,
+	PC10_PF_USBOTG_DATA2,
+	PC13_PF_USBOTG_DATA3,
+	PC12_PF_USBOTG_DATA4,
+	PC7_PF_USBOTG_DATA5,
+	PC8_PF_USBOTG_DATA6,
+	PE25_PF_USBOTG_DATA7,
+	PE24_PF_USBOTG_CLK,
+	PE2_PF_USBOTG_DIR,
+	PE0_PF_USBOTG_NXT,
+	PE1_PF_USBOTG_STP,
+	PB23_PF_USB_PWR,
+	PB24_PF_USB_OC,
+};
+
+/* GPIOs used as events for applications */
+static struct gpio_keys_button visstrim_gpio_keys[] = {
+	{
+		.type	= EV_KEY,
+		.code	= KEY_RESTART,
+		.gpio	= (GPIO_PORTC + 15),
+		.desc	= "Default config",
+		.active_low = 0,
+		.wakeup = 1,
+	},
+	{
+		.type	= EV_KEY,
+		.code	= KEY_RECORD,
+		.gpio	= (GPIO_PORTF + 14),
+		.desc	= "Record",
+		.active_low = 0,
+		.wakeup = 1,
+	},
+	{
+		.type   = EV_KEY,
+		.code   = KEY_STOP,
+		.gpio   = (GPIO_PORTF + 13),
+		.desc   = "Stop",
+		.active_low = 0,
+		.wakeup = 1,
+	}
+};
+
+static struct gpio_keys_platform_data visstrim_gpio_keys_platform_data = {
+	.buttons	= visstrim_gpio_keys,
+	.nbuttons	= ARRAY_SIZE(visstrim_gpio_keys),
+};
+
+static struct platform_device visstrim_gpio_keys_device = {
+	.name	= "gpio-keys",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &visstrim_gpio_keys_platform_data,
+	},
+};
+
+/* Visstrim_SM10 has a microSD slot connected to sdhc1 */
+static int visstrim_m10_sdhc1_init(struct device *dev,
+		irq_handler_t detect_irq, void *data)
+{
+	int ret;
+
+	ret = request_irq(SDHC1_IRQ, detect_irq, IRQF_TRIGGER_FALLING,
+				"mmc-detect", data);
+	return ret;
+}
+
+static void visstrim_m10_sdhc1_exit(struct device *dev, void *data)
+{
+	free_irq(SDHC1_IRQ, data);
+}
+
+static struct imxmmc_platform_data visstrim_m10_sdhc_pdata = {
+	.init = visstrim_m10_sdhc1_init,
+	.exit = visstrim_m10_sdhc1_exit,
+};
+
+/* Visstrim_SM10 NOR flash */
+static struct physmap_flash_data visstrim_m10_flash_data = {
+	.width = 2,
+};
+
+static struct resource visstrim_m10_flash_resource = {
+	.start = 0xc0000000,
+	.end = 0xc0000000 + SZ_64M - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device visstrim_m10_nor_mtd_device = {
+	.name = "physmap-flash",
+	.id = 0,
+	.dev = {
+		.platform_data = &visstrim_m10_flash_data,
+	},
+	.num_resources = 1,
+	.resource = &visstrim_m10_flash_resource,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+	&visstrim_gpio_keys_device,
+	&visstrim_m10_nor_mtd_device,
+};
+
+/* Visstrim_M10 uses UART0 as console */
+static const struct imxuart_platform_data uart_pdata __initconst = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* I2C */
+static const struct imxi2c_platform_data visstrim_m10_i2c_data __initconst = {
+	.bitrate = 100000,
+};
+
+static struct pca953x_platform_data visstrim_m10_pca9555_pdata = {
+	.gpio_base = 240, /* After MX27 internal GPIOs */
+	.invert = 0,
+};
+
+static struct i2c_board_info visstrim_m10_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("pca9555", 0x20),
+		.platform_data = &visstrim_m10_pca9555_pdata,
+	},
+};
+
+/* USB OTG */
+static int otg_phy_init(struct platform_device *pdev)
+{
+	gpio_set_value(OTG_PHY_CS_GPIO, 0);
+	return 0;
+}
+
+static struct mxc_usbh_platform_data visstrim_m10_usbotg_pdata = {
+	.init = otg_phy_init,
+	.portsc	= MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+	.flags	= MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+static void __init visstrim_m10_board_init(void)
+{
+	int ret;
+
+	ret = mxc_gpio_setup_multiple_pins(visstrim_m10_pins,
+			ARRAY_SIZE(visstrim_m10_pins), "VISSTRIM_M10");
+	if (ret)
+		pr_err("Failed to setup pins (%d)\n", ret);
+
+	imx27_add_imx_uart0(&uart_pdata);
+
+	i2c_register_board_info(0, visstrim_m10_i2c_devices,
+				ARRAY_SIZE(visstrim_m10_i2c_devices));
+	imx27_add_imx_i2c(0, &visstrim_m10_i2c_data);
+	imx27_add_imx_i2c(1, &visstrim_m10_i2c_data);
+	mxc_register_device(&mxc_sdhc_device0, &visstrim_m10_sdhc_pdata);
+	mxc_register_device(&mxc_otg_host, &visstrim_m10_usbotg_pdata);
+	imx27_add_fec(NULL);
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init visstrim_m10_timer_init(void)
+{
+	mx27_clocks_init((unsigned long)25000000);
+}
+
+static struct sys_timer visstrim_m10_timer = {
+	.init	= visstrim_m10_timer_init,
+};
+
+MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
+	.boot_params    = MX27_PHYS_OFFSET + 0x100,
+	.map_io         = mx27_map_io,
+	.init_irq       = mx27_init_irq,
+	.init_machine   = visstrim_m10_board_init,
+	.timer          = &visstrim_m10_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx1ads.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx1ads.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx1ads.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx1ads.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 #include "devices-imx1.h"
 #include "devices.h"
 
-static int mx1ads_pins[] = {
+static const int mx1ads_pins[] __initconst = {
 	/* UART1 */
 	PC9_PF_UART1_CTS,
 	PC10_PF_UART1_RTS,
@@ -131,7 +131,7 @@
 	i2c_register_board_info(0, mx1ads_i2c_devices,
 				ARRAY_SIZE(mx1ads_i2c_devices));
 
-	imx1_add_i2c_imx(&mx1ads_i2c_data);
+	imx1_add_imx_i2c(&mx1ads_i2c_data);
 }
 
 static void __init mx1ads_timer_init(void)
@@ -145,8 +145,6 @@
 
 MACHINE_START(MX1ADS, "Freescale MX1ADS")
 	/* Maintainer: Sascha Hauer, Pengutronix */
-	.phys_io	= MX1_IO_BASE_ADDR,
-	.io_pg_offst	= (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params	= MX1_PHYS_OFFSET + 0x100,
 	.map_io		= mx1_map_io,
 	.init_irq	= mx1_init_irq,
@@ -155,8 +153,6 @@
 MACHINE_END
 
 MACHINE_START(MXLADS, "Freescale MXLADS")
-	.phys_io	= MX1_IO_BASE_ADDR,
-	.io_pg_offst	= (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params	= MX1_PHYS_OFFSET + 0x100,
 	.map_io		= mx1_map_io,
 	.init_irq	= mx1_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx21ads.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx21ads.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx21ads.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx21ads.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,7 +67,7 @@
 #define MX21ADS_IO_LED4_ON      0x4000
 #define MX21ADS_IO_LED3_ON      0x8000
 
-static unsigned int mx21ads_pins[] = {
+static const int mx21ads_pins[] __initconst = {
 
 	/* CS8900A */
 	(GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11),
@@ -314,8 +314,6 @@
 
 MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
 	/* maintainer: Freescale Semiconductor, Inc. */
-	.phys_io        = MX21_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX21_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX21_PHYS_OFFSET + 0x100,
 	.map_io         = mx21ads_map_io,
 	.init_irq       = mx21_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx27_3ds.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx27_3ds.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx27_3ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx27_3ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,17 +23,21 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/irq.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx27.h>
+#include <mach/mmc.h>
 
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mx27pdk_pins[] = {
+#define SD1_EN_GPIO (GPIO_PORTB + 25)
+
+static const int mx27pdk_pins[] __initconst = {
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -58,16 +62,20 @@
 	PD15_AOUT_FEC_COL,
 	PD16_AIN_FEC_TX_ER,
 	PF23_AIN_FEC_TX_EN,
+	/* SDHC1 */
+	PE18_PF_SD1_D0,
+	PE19_PF_SD1_D1,
+	PE20_PF_SD1_D2,
+	PE21_PF_SD1_D3,
+	PE22_PF_SD1_CMD,
+	PE23_PF_SD1_CLK,
+	SD1_EN_GPIO | GPIO_GPIO | GPIO_OUT,
 };
 
 static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct platform_device *platform_devices[] __initdata = {
-	&mxc_fec_device,
-};
-
 /*
  * Matrix keyboard
  */
@@ -89,13 +97,39 @@
 	.keymap_size	= ARRAY_SIZE(mx27_3ds_keymap),
 };
 
+static int mx27_3ds_sdhc1_init(struct device *dev, irq_handler_t detect_irq,
+				void *data)
+{
+	return request_irq(IRQ_GPIOB(26), detect_irq, IRQF_TRIGGER_FALLING |
+			IRQF_TRIGGER_RISING, "sdhc1-card-detect", data);
+}
+
+static void mx27_3ds_sdhc1_exit(struct device *dev, void *data)
+{
+	free_irq(IRQ_GPIOB(26), data);
+}
+
+static struct imxmmc_platform_data sdhc1_pdata = {
+	.init = mx27_3ds_sdhc1_init,
+	.exit = mx27_3ds_sdhc1_exit,
+};
+
+static void mx27_3ds_sdhc1_enable_level_translator(void)
+{
+	/* Turn on TXB0108 OE pin */
+	gpio_request(SD1_EN_GPIO, "sd1_enable");
+	gpio_direction_output(SD1_EN_GPIO, 1);
+}
+
 static void __init mx27pdk_init(void)
 {
 	mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
 		"mx27pdk");
+	mx27_3ds_sdhc1_enable_level_translator();
 	imx27_add_imx_uart0(&uart_pdata);
-	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+	imx27_add_fec(NULL);
 	mxc_register_device(&imx_kpp_device, &mx27_3ds_keymap_data);
+	mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
 }
 
 static void __init mx27pdk_timer_init(void)
@@ -109,8 +143,6 @@
 
 MACHINE_START(MX27_3DS, "Freescale MX27PDK")
 	/* maintainer: Freescale Semiconductor, Inc. */
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx27ads.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx27ads.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mx27ads.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mx27ads.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,7 +66,7 @@
 /* to determine the correct external crystal reference */
 #define CKIH_27MHZ_BIT_SET      (1 << 3)
 
-static unsigned int mx27ads_pins[] = {
+static const int mx27ads_pins[] __initconst = {
 	/* UART0 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -284,7 +284,6 @@
 
 static struct platform_device *platform_devices[] __initdata = {
 	&mx27ads_nor_mtd_device,
-	&mxc_fec_device,
 	&mxc_w1_master_device,
 };
 
@@ -308,11 +307,12 @@
 	/* only the i2c master 1 is used on this CPU card */
 	i2c_register_board_info(1, mx27ads_i2c_devices,
 				ARRAY_SIZE(mx27ads_i2c_devices));
-	imx27_add_i2c_imx1(&mx27ads_i2c1_data);
+	imx27_add_imx_i2c(1, &mx27ads_i2c1_data);
 	mxc_register_device(&mxc_fb_device, &mx27ads_fb_data);
 	mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
 	mxc_register_device(&mxc_sdhc_device1, &sdhc2_pdata);
 
+	imx27_add_fec(NULL);
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
@@ -347,8 +347,6 @@
 
 MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
 	/* maintainer: Freescale Semiconductor, Inc. */
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27ads_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mxt_td60.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mxt_td60.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-mxt_td60.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-mxt_td60.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mxt_td60_pins[] __initdata = {
+static const int mxt_td60_pins[] __initconst = {
 	/* UART0 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -231,10 +231,6 @@
 	.exit = mxt_td60_sdhc1_exit,
 };
 
-static struct platform_device *platform_devices[] __initdata = {
-	&mxc_fec_device,
-};
-
 static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
@@ -255,12 +251,11 @@
 	i2c_register_board_info(1, mxt_td60_i2c2_devices,
 				ARRAY_SIZE(mxt_td60_i2c2_devices));
 
-	imx27_add_i2c_imx0(&mxt_td60_i2c0_data);
-	imx27_add_i2c_imx1(&mxt_td60_i2c1_data);
+	imx27_add_imx_i2c(0, &mxt_td60_i2c0_data);
+	imx27_add_imx_i2c(1, &mxt_td60_i2c1_data);
 	mxc_register_device(&mxc_fb_device, &mxt_td60_fb_data);
 	mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
-
-	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+	imx27_add_fec(NULL);
 }
 
 static void __init mxt_td60_timer_init(void)
@@ -274,8 +269,6 @@
 
 MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
 	/* maintainer: Maxtrack Industrial */
-	.phys_io	= MX27_AIPI_BASE_ADDR,
-	.io_pg_offst	= ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params	= MX27_PHYS_OFFSET + 0x100,
 	.map_io		= mx27_map_io,
 	.init_irq	= mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-pca100.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-pca100.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-pca100.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-pca100.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,7 +38,6 @@
 #include <mach/iomux-mx27.h>
 #include <asm/mach/time.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 #include <mach/mxc_nand.h>
 #include <mach/irqs.h>
 #include <mach/mmc.h>
@@ -55,7 +54,7 @@
 #define SPI1_SS1 (GPIO_PORTD + 27)
 #define SD2_CD (GPIO_PORTC + 29)
 
-static int pca100_pins[] = {
+static const int pca100_pins[] __initconst = {
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -174,7 +173,6 @@
 
 static struct platform_device *platform_devices[] __initdata = {
 	&mxc_w1_master_device,
-	&mxc_fec_device,
 	&mxc_wdt,
 };
 
@@ -193,11 +191,9 @@
 		I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
 		.platform_data = &board_eeprom,
 	}, {
-		I2C_BOARD_INFO("rtc-pcf8563", 0x51),
-		.type = "pcf8563"
+		I2C_BOARD_INFO("pcf8563", 0x51),
 	}, {
 		I2C_BOARD_INFO("lm75", 0x4a),
-		.type = "lm75"
 	}
 };
 
@@ -252,7 +248,7 @@
 	msleep(2);
 }
 
-static struct imx_ssi_platform_data pca100_ssi_pdata = {
+static const struct imx_ssi_platform_data pca100_ssi_pdata __initconst = {
 	.ac97_reset		= pca100_ac97_cold_reset,
 	.ac97_warm_reset	= pca100_ac97_warm_reset,
 	.flags			= IMX_SSI_USE_AC97,
@@ -389,7 +385,7 @@
 	if (ret)
 		printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
 
-	mxc_register_device(&imx_ssi_device0, &pca100_ssi_pdata);
+	imx27_add_imx_ssi(0, &pca100_ssi_pdata);
 
 	imx27_add_imx_uart0(&uart_pdata);
 
@@ -401,7 +397,7 @@
 	i2c_register_board_info(1, pca100_i2c_devices,
 				ARRAY_SIZE(pca100_i2c_devices));
 
-	imx27_add_i2c_imx1(&pca100_i2c1_data);
+	imx27_add_imx_i2c(1, &pca100_i2c1_data);
 
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
 	mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN);
@@ -436,6 +432,7 @@
 
 	mxc_register_device(&mxc_fb_device, &pca100_fb_data);
 
+	imx27_add_fec(NULL);
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
@@ -449,8 +446,6 @@
 };
 
 MACHINE_START(PCA100, "phyCARD-i.MX27")
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-pcm038.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-pcm038.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-pcm038.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-pcm038.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int pcm038_pins[] = {
+static const int pcm038_pins[] __initconst = {
 	/* UART1 */
 	PE12_PF_UART1_TXD,
 	PE13_PF_UART1_RXD,
@@ -173,7 +173,6 @@
 static struct platform_device *platform_devices[] __initdata = {
 	&pcm038_nor_mtd_device,
 	&mxc_w1_master_device,
-	&mxc_fec_device,
 	&pcm038_sram_mtd_device,
 	&mxc_wdt,
 };
@@ -257,7 +256,7 @@
 	.consumer_supplies = cam_consumers,
 };
 
-struct mc13783_regulator_init_data pcm038_regulators[] = {
+static struct mc13783_regulator_init_data pcm038_regulators[] = {
 	{
 		.id = MC13783_REGU_VCAM,
 		.init_data = &cam_data,
@@ -309,7 +308,7 @@
 	i2c_register_board_info(1, pcm038_i2c_devices,
 				ARRAY_SIZE(pcm038_i2c_devices));
 
-	imx27_add_i2c_imx1(&pcm038_i2c1_data);
+	imx27_add_imx_i2c(1, &pcm038_i2c1_data);
 
 	/* PE18 for user-LED D40 */
 	mxc_gpio_mode(GPIO_PORTE | 18 | GPIO_GPIO | GPIO_OUT);
@@ -325,6 +324,7 @@
 
 	mxc_register_device(&mxc_usbh2, &usbh2_pdata);
 
+	imx27_add_fec(NULL);
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #ifdef CONFIG_MACH_PCM970_BASEBOARD
@@ -342,8 +342,6 @@
 };
 
 MACHINE_START(PCM038, "phyCORE-i.MX27")
-	.phys_io        = MX27_AIPI_BASE_ADDR,
-	.io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX27_PHYS_OFFSET + 0x100,
 	.map_io         = mx27_map_io,
 	.init_irq       = mx27_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-scb9328.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-scb9328.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/mach-scb9328.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/mach-scb9328.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,7 +95,7 @@
 	}
 };
 
-static int mxc_uart1_pins[] = {
+static const int mxc_uart1_pins[] = {
 	PC9_PF_UART1_CTS,
 	PC10_PF_UART1_RTS,
 	PC11_PF_UART1_TXD,
@@ -147,8 +147,6 @@
 
 MACHINE_START(SCB9328, "Synertronixx scb9328")
     /* Sascha Hauer */
-	.phys_io	= 0x00200000,
-	.io_pg_offst	= ((0xe0200000) >> 18) & 0xfffc,
 	.boot_params	= 0x08000100,
 	.map_io		= mx1_map_io,
 	.init_irq	= mx1_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-imx/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
 obj-$(CONFIG_MACH_MX27_3DS) += mach-mx27_3ds.o
 obj-$(CONFIG_MACH_IMX27LITE) += mach-imx27lite.o
+obj-$(CONFIG_MACH_IMX27_VISSTRIM_M10) += mach-imx27_visstrim_m10.o
 obj-$(CONFIG_MACH_CPUIMX27) += mach-cpuimx27.o
 obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
 obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-imx/pcm970-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-imx/pcm970-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-imx/pcm970-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-imx/pcm970-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,7 +31,7 @@
 
 #include "devices.h"
 
-static int pcm970_pins[] = {
+static const int pcm970_pins[] __initconst = {
 	/* SDHC */
 	PB4_PF_SD2_D0,
 	PB5_PF_SD2_D1,
@@ -200,7 +200,7 @@
 	},
 };
 
-struct sja1000_platform_data pcm970_sja1000_platform_data = {
+static struct sja1000_platform_data pcm970_sja1000_platform_data = {
 	.osc_freq	= 16000000,
 	.ocr		= OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL,
 	.cdr		= CDR_CBP,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-integrator/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-integrator/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-integrator/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-integrator/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,10 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x16000000	@ physical base address
-		movne	\rx, #0xf0000000	@ virtual base
-		addne	\rx, \rx, #0x16000000 >> 4
+		.macro	addruart, rp, rv
+		mov	\rp, #0x16000000	@ physical base address
+		mov	\rv, #0xf0000000	@ virtual base
+		add	\rv, \rv, #0x16000000 >> 4
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-integrator/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-integrator/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-integrator/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-integrator/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-integrator/integrator_ap.c linux-libre-2.6.37-gnu/arch/arm/mach-integrator/integrator_ap.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-integrator/integrator_ap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-integrator/integrator_ap.c	2011-01-04 19:50:19.000000000 -0500
@@ -500,8 +500,6 @@
 
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= 0x16000000,
-	.io_pg_offst	= ((0xf1600000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ap_map_io,
 	.reserve	= integrator_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-integrator/integrator_cp.c linux-libre-2.6.37-gnu/arch/arm/mach-integrator/integrator_cp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-integrator/integrator_cp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-integrator/integrator_cp.c	2011-01-04 19:50:19.000000000 -0500
@@ -599,8 +599,6 @@
 
 MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= 0x16000000,
-	.io_pg_offst	= ((0xf1600000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= intcp_map_io,
 	.reserve	= integrator_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,15 +11,13 @@
  * published by the Free Software Foundation.
  */
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1			@ mmu enabled?
-	moveq	\rx, #0xff000000	@ physical
-	orreq	\rx, \rx, #0x00d80000
-	movne	\rx, #0xfe000000	@ virtual
-	orrne	\rx, \rx, #0x00e80000
-	orr	\rx, \rx, #0x00002300
-	orr	\rx, \rx, #0x00000040
+	.macro	addruart, rp, rv
+	mov	\rp, #0x00002300
+	orr	\rp, \rp, #0x00000040
+	orr	\rv, \rp, #0xfe000000	@ virtual
+	orr	\rv, \rv, #0x00e80000
+	orr	\rp, \rp, #0xff000000	@ physical
+	orr	\rp, \rp, #0x00d80000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/iq81340mc.c linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/iq81340mc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/iq81340mc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/iq81340mc.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,8 +91,6 @@
 
 MACHINE_START(IQ81340MC, "Intel IQ81340MC")
 	/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
-	.phys_io        = IOP13XX_PMMR_PHYS_MEM_BASE,
-	.io_pg_offst    = (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
 	.boot_params    = 0x00000100,
 	.map_io         = iop13xx_map_io,
 	.init_irq       = iop13xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/iq81340sc.c linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/iq81340sc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/iq81340sc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/iq81340sc.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,8 +93,6 @@
 
 MACHINE_START(IQ81340SC, "Intel IQ81340SC")
 	/* Maintainer: Dan Williams <dan.j.williams@intel.com> */
-	.phys_io	= IOP13XX_PMMR_PHYS_MEM_BASE,
-	.io_pg_offst	= (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
 	.boot_params    = 0x00000100,
 	.map_io         = iop13xx_map_io,
 	.init_irq       = iop13xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/msi.c linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/msi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop13xx/msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop13xx/msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -164,10 +164,10 @@
 static struct irq_chip iop13xx_msi_chip = {
 	.name = "PCI-MSI",
 	.ack = iop13xx_msi_nop,
-	.enable = unmask_msi_irq,
-	.disable = mask_msi_irq,
-	.mask = mask_msi_irq,
-	.unmask = unmask_msi_irq,
+	.irq_enable = unmask_msi_irq,
+	.irq_disable = mask_msi_irq,
+	.irq_mask = mask_msi_irq,
+	.irq_unmask = unmask_msi_irq,
 };
 
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/em7210.c linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/em7210.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/em7210.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/em7210.c	2011-01-04 19:50:19.000000000 -0500
@@ -203,8 +203,6 @@
 }
 
 MACHINE_START(EM7210, "Lanner EM7210")
-	.phys_io	= IQ31244_UART,
-	.io_pg_offst	= ((IQ31244_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= em7210_map_io,
 	.init_irq	= iop32x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/glantank.c linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/glantank.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/glantank.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/glantank.c	2011-01-04 19:50:19.000000000 -0500
@@ -207,8 +207,6 @@
 
 MACHINE_START(GLANTANK, "GLAN Tank")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= GLANTANK_UART,
-	.io_pg_offst	= ((GLANTANK_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= glantank_map_io,
 	.init_irq	= iop32x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,10 @@
  * published by the Free Software Foundation.
  */
 
-		.macro	addruart, rx, tmp
-		mov	\rx, #0xfe000000	@ physical as well as virtual
-		orr	\rx, \rx, #0x00800000	@ location of the UART
+		.macro	addruart, rp, rv
+		mov	\rp, #0xfe000000	@ physical as well as virtual
+		orr	\rp, \rp, #0x00800000	@ location of the UART
+		mov	\rv, \rp
 		.endm
 
 #define UART_SHIFT	0
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/iq31244.c linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/iq31244.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/iq31244.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/iq31244.c	2011-01-04 19:50:19.000000000 -0500
@@ -313,8 +313,6 @@
 
 MACHINE_START(IQ31244, "Intel IQ31244")
 	/* Maintainer: Intel Corp. */
-	.phys_io	= IQ31244_UART,
-	.io_pg_offst	= ((IQ31244_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= iq31244_map_io,
 	.init_irq	= iop32x_init_irq,
@@ -329,8 +327,6 @@
  */
 MACHINE_START(EP80219, "Intel EP80219")
 	/* Maintainer: Intel Corp. */
-	.phys_io	= IQ31244_UART,
-	.io_pg_offst	= ((IQ31244_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= iq31244_map_io,
 	.init_irq	= iop32x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/iq80321.c linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/iq80321.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/iq80321.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/iq80321.c	2011-01-04 19:50:19.000000000 -0500
@@ -186,8 +186,6 @@
 
 MACHINE_START(IQ80321, "Intel IQ80321")
 	/* Maintainer: Intel Corp. */
-	.phys_io	= IQ80321_UART,
-	.io_pg_offst	= ((IQ80321_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= iq80321_map_io,
 	.init_irq	= iop32x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/n2100.c linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/n2100.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop32x/n2100.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop32x/n2100.c	2011-01-04 19:50:19.000000000 -0500
@@ -327,8 +327,6 @@
 
 MACHINE_START(N2100, "Thecus N2100")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= N2100_UART,
-	.io_pg_offst	= ((N2100_UART) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= n2100_map_io,
 	.init_irq	= iop32x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,13 +11,11 @@
  * published by the Free Software Foundation.
  */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ mmu enabled?
-		moveq	\rx, #0xff000000	@ physical
-		movne	\rx, #0xfe000000	@ virtual
-		orr	\rx, \rx, #0x00ff0000
-		orr	\rx, \rx, #0x0000f700
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00ff0000
+		orr	\rp, \rp, #0x0000f700
+		orr	\rv, #0xfe000000	@ virtual
+		orr	\rp, #0xff000000	@ physical
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/iq80331.c linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/iq80331.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/iq80331.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/iq80331.c	2011-01-04 19:50:19.000000000 -0500
@@ -141,8 +141,6 @@
 
 MACHINE_START(IQ80331, "Intel IQ80331")
 	/* Maintainer: Intel Corp. */
-	.phys_io	= 0xfefff000,
-	.io_pg_offst	= ((0xfffff000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= iop3xx_map_io,
 	.init_irq	= iop33x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/iq80332.c linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/iq80332.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-iop33x/iq80332.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-iop33x/iq80332.c	2011-01-04 19:50:19.000000000 -0500
@@ -141,8 +141,6 @@
 
 MACHINE_START(IQ80332, "Intel IQ80332")
 	/* Maintainer: Intel Corp. */
-	.phys_io	= 0xfefff000,
-	.io_pg_offst	= ((0xfffff000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= iop3xx_map_io,
 	.init_irq	= iop33x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/core.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -197,7 +197,7 @@
 	return offset / ticks_per_usec;
 }
 
-static int ixp2000_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t ixp2000_timer_interrupt(int irq, void *dev_id)
 {
 	/* clear timer 1 */
 	ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/enp2611.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/enp2611.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/enp2611.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/enp2611.c	2011-01-04 19:50:19.000000000 -0500
@@ -253,8 +253,6 @@
 
 MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
 	/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= enp2611_map_io,
 	.init_irq	= ixp2000_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,16 +11,14 @@
  *
 */
 
-		.macro  addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0xc0000000	@ Physical base
-		movne	\rx, #0xfe000000	@ virtual base
-		orrne	\rx, \rx, #0x00f00000
-		orr	\rx, \rx, #0x00030000
+		.macro  addruart, rp, rv
+		mov	\rp, #0x00030000
 #ifdef	__ARMEB__
-		orr	\rx, \rx, #0x00000003
+		orr	\rp, \rp, #0x00000003
 #endif
+		orr	\rv, \rp, #0xfe000000	@ virtual base
+		orr	\rv, \rv, #0x00f00000
+		orr	\rp, \rp, #0xc0000000	@ Physical base
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2400.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2400.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2400.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2400.c	2011-01-04 19:50:19.000000000 -0500
@@ -170,8 +170,6 @@
 
 MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ixdp2x00_map_io,
 	.init_irq	= ixdp2400_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2800.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2800.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2800.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2800.c	2011-01-04 19:50:19.000000000 -0500
@@ -285,8 +285,6 @@
 
 MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ixdp2x00_map_io,
 	.init_irq	= ixdp2800_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2x01.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2x01.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp2000/ixdp2x01.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp2000/ixdp2x01.c	2011-01-04 19:50:19.000000000 -0500
@@ -416,8 +416,6 @@
 #ifdef CONFIG_ARCH_IXDP2401
 MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ixdp2x01_map_io,
 	.init_irq	= ixdp2x01_init_irq,
@@ -429,8 +427,6 @@
 #ifdef CONFIG_ARCH_IXDP2801
 MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ixdp2x01_map_io,
 	.init_irq	= ixdp2x01_init_irq,
@@ -444,8 +440,6 @@
  */
 MACHINE_START(IXDP28X5, "Intel IXDP2805/2855 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP2000_UART_PHYS_BASE,
-	.io_pg_offst	= ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= ixdp2x01_map_io,
 	.init_irq	= ixdp2x01_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/espresso.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/espresso.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/espresso.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/espresso.c	2011-01-04 19:50:19.000000000 -0500
@@ -85,8 +85,6 @@
 
 MACHINE_START(ESPRESSO, "IP Fabrics Double Espresso")
 	/* Maintainer: Lennert Buytenhek */
-	.phys_io	= IXP23XX_PERIPHERAL_PHYS,
-	.io_pg_offst	= ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
 	.map_io		= ixp23xx_map_io,
 	.init_irq	= ixp23xx_init_irq,
 	.timer		= &ixp23xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -12,13 +12,12 @@
  */
 #include <mach/ixp23xx.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1				@ mmu enabled?
-		ldreq	\rx, =IXP23XX_PERIPHERAL_PHYS 	@ physical
-		ldrne	\rx, =IXP23XX_PERIPHERAL_VIRT	@ virtual
+		.macro	addruart, rp, rv
+		ldr	\rp, =IXP23XX_PERIPHERAL_PHYS 	@ physical
+		ldr	\rv, =IXP23XX_PERIPHERAL_VIRT	@ virtual
 #ifdef __ARMEB__
-		orr	\rx, \rx, #0x00000003
+		orr	\rp, \rp, #0x00000003
+		orr	\rv, \rv, #0x00000003
 #endif
 		.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/ixdp2351.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/ixdp2351.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/ixdp2351.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/ixdp2351.c	2011-01-04 19:50:19.000000000 -0500
@@ -328,8 +328,6 @@
 
 MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP23XX_PERIPHERAL_PHYS,
-	.io_pg_offst	= ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
 	.map_io		= ixdp2351_map_io,
 	.init_irq	= ixdp2351_init_irq,
 	.timer		= &ixp23xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/roadrunner.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/roadrunner.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp23xx/roadrunner.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp23xx/roadrunner.c	2011-01-04 19:50:19.000000000 -0500
@@ -171,8 +171,6 @@
 
 MACHINE_START(ROADRUNNER, "ADI Engineering RoadRunner Development Platform")
 	/* Maintainer: Deepak Saxena */
-	.phys_io	= IXP23XX_PERIPHERAL_PHYS,
-	.io_pg_offst	= ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
 	.map_io		= ixp23xx_map_io,
 	.init_irq	= ixp23xx_init_irq,
 	.timer		= &ixp23xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/avila-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/avila-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/avila-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/avila-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -164,8 +164,6 @@
 
 MACHINE_START(AVILA, "Gateworks Avila Network Platform")
 	/* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
@@ -181,8 +179,6 @@
 #ifdef CONFIG_MACH_LOFT
 MACHINE_START(LOFT, "Giant Shoulder Inc Loft board")
 	/* Maintainer: Tom Billman <kernel@giantshoulderinc.com> */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/common-pci.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/common-pci.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/common-pci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/common-pci.c	2011-01-04 19:50:19.000000000 -0500
@@ -513,4 +513,4 @@
 
 EXPORT_SYMBOL(ixp4xx_pci_read);
 EXPORT_SYMBOL(ixp4xx_pci_write);
-
+EXPORT_SYMBOL(dma_set_coherent_mask);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/coyote-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/coyote-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/coyote-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/coyote-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -109,8 +109,6 @@
 #ifdef CONFIG_ARCH_ADI_COYOTE
 MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
@@ -126,8 +124,6 @@
 #ifdef CONFIG_MACH_IXDPG425
 MACHINE_START(IXDPG425, "Intel IXDPG425")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/dsmg600-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/dsmg600-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/dsmg600-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/dsmg600-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -279,8 +279,6 @@
 
 MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/fsg-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/fsg-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/fsg-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/fsg-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -270,8 +270,6 @@
 
 MACHINE_START(FSG, "Freecom FSG-3")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/gateway7001-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/gateway7001-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/gateway7001-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/gateway7001-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -96,8 +96,6 @@
 #ifdef CONFIG_MACH_GATEWAY7001
 MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
 	/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/goramo_mlr.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/goramo_mlr.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/goramo_mlr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/goramo_mlr.c	2011-01-04 19:50:19.000000000 -0500
@@ -496,8 +496,6 @@
 
 MACHINE_START(GORAMO_MLR, "MultiLink")
 	/* Maintainer: Krzysztof Halasa */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/gtwx5715-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/gtwx5715-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/gtwx5715-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/gtwx5715-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -164,8 +164,6 @@
 
 MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
 	/* Maintainer: George Joseph */
-	.phys_io	= IXP4XX_UART2_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,16 +10,16 @@
  * published by the Free Software Foundation.
 */
 
-                .macro  addruart, rx, tmp
-                mrc     p15, 0, \rx, c1, c0
-                tst     \rx, #1                 @ MMU enabled?
-                moveq   \rx, #0xc8000000
-                movne   \rx, #0xff000000
-		orrne	\rx, \rx, #0x00b00000
+                .macro  addruart, rp, rv
 #ifdef __ARMEB__
-                add     \rx,\rx,#3              @ Uart regs are at off set of 3 if
-						@ byte writes used - Big Endian.
+                mov     \rp, #3         @ Uart regs are at off set of 3 if
+					@ byte writes used - Big Endian.
+#else
+		mov	\rp, #0
 #endif
+                orr     \rv, \rp, #0xff000000	@ virtual
+		orr	\rv, \rv, #0x00b00000
+                orr     \rp, \rp, #0xc8000000	@ physical
                 .endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/ixdp425-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/ixdp425-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/ixdp425-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/ixdp425-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -257,8 +257,6 @@
 #ifdef CONFIG_ARCH_IXDP425
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
@@ -270,8 +268,6 @@
 #ifdef CONFIG_MACH_IXDP465
 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
@@ -283,8 +279,6 @@
 #ifdef CONFIG_ARCH_PRPMC1100
 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
@@ -296,8 +290,6 @@
 #ifdef CONFIG_MACH_KIXRP435
 MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/nas100d-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/nas100d-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/nas100d-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/nas100d-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -314,8 +314,6 @@
 
 MACHINE_START(NAS100D, "Iomega NAS 100d")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/nslu2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/nslu2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/nslu2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/nslu2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -300,8 +300,6 @@
 
 MACHINE_START(NSLU2, "Linksys NSLU2")
 	/* Maintainer: www.nslu2-linux.org */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/vulcan-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/vulcan-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/vulcan-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/vulcan-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -236,8 +236,6 @@
 
 MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan")
 	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/wg302v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/wg302v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ixp4xx/wg302v2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ixp4xx/wg302v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -97,8 +97,6 @@
 #ifdef CONFIG_MACH_WG302V2
 MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
 	/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-	.phys_io	= IXP4XX_PERIPHERAL_BASE_PHYS,
-	.io_pg_offst	= ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
 	.map_io		= ixp4xx_map_io,
 	.init_irq	= ixp4xx_init_irq,
 	.timer		= &ixp4xx_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/common.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -854,10 +854,9 @@
 
 	kirkwood_pcie_id(&dev, &rev);
 
-	if ((dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
-					rev == MV88F6281_REV_A1)) ||
-	    (dev == MV88F6282_DEV_ID))
-		return 200000000;
+	if (dev == MV88F6281_DEV_ID || dev == MV88F6282_DEV_ID)
+		if (((readl(SAMPLE_AT_RESET) >> 21) & 1) == 0)
+			return 200000000;
 
 	return 166666667;
 }
@@ -903,10 +902,16 @@
 	},
 };
 
+static struct platform_device kirkwood_pcm_device = {
+	.name		= "kirkwood-pcm-audio",
+	.id		= -1,
+};
+
 void __init kirkwood_audio_init(void)
 {
 	kirkwood_clk_ctrl |= CGC_AUDIO;
 	platform_device_register(&kirkwood_i2s_device);
+	platform_device_register(&kirkwood_pcm_device);
 }
 
 /*****************************************************************************
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/d2net_v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/d2net_v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/d2net_v2-setup.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/d2net_v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,229 @@
+/*
+ * arch/arm/mach-kirkwood/d2net_v2-setup.c
+ *
+ * LaCie d2 Network Space v2 Board Setup
+ *
+ * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <mach/leds-ns2.h>
+#include "common.h"
+#include "mpp.h"
+#include "lacie_v2-common.h"
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data d2net_v2_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
+};
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+
+static struct mv_sata_platform_data d2net_v2_sata_data = {
+	.n_ports	= 2,
+};
+
+/*****************************************************************************
+ * GPIO keys
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_PUSH_BUTTON          34
+#define D2NET_V2_GPIO_POWER_SWITCH_ON      13
+#define D2NET_V2_GPIO_POWER_SWITCH_OFF     15
+
+#define D2NET_V2_SWITCH_POWER_ON           0x1
+#define D2NET_V2_SWITCH_POWER_OFF          0x2
+
+static struct gpio_keys_button d2net_v2_buttons[] = {
+	[0] = {
+		.type           = EV_SW,
+		.code           = D2NET_V2_SWITCH_POWER_ON,
+		.gpio           = D2NET_V2_GPIO_POWER_SWITCH_ON,
+		.desc           = "Back power switch (on|auto)",
+		.active_low     = 0,
+	},
+	[1] = {
+		.type           = EV_SW,
+		.code           = D2NET_V2_SWITCH_POWER_OFF,
+		.gpio           = D2NET_V2_GPIO_POWER_SWITCH_OFF,
+		.desc           = "Back power switch (auto|off)",
+		.active_low     = 0,
+	},
+	[2] = {
+		.code           = KEY_POWER,
+		.gpio           = D2NET_V2_GPIO_PUSH_BUTTON,
+		.desc           = "Front Push Button",
+		.active_low     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data d2net_v2_button_data = {
+	.buttons	= d2net_v2_buttons,
+	.nbuttons	= ARRAY_SIZE(d2net_v2_buttons),
+};
+
+static struct platform_device d2net_v2_gpio_buttons = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_button_data,
+	},
+};
+
+/*****************************************************************************
+ * GPIO LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_RED_LED		12
+
+static struct gpio_led d2net_v2_gpio_led_pins[] = {
+	{
+		.name	= "d2net_v2:red:fail",
+		.gpio	= D2NET_V2_GPIO_RED_LED,
+	},
+};
+
+static struct gpio_led_platform_data d2net_v2_gpio_leds_data = {
+	.num_leds	= ARRAY_SIZE(d2net_v2_gpio_led_pins),
+	.leds		= d2net_v2_gpio_led_pins,
+};
+
+static struct platform_device d2net_v2_gpio_leds = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_gpio_leds_data,
+	},
+};
+
+/*****************************************************************************
+ * Dual-GPIO CPLD LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_BLUE_LED_SLOW	29
+#define D2NET_V2_GPIO_BLUE_LED_CMD	30
+
+static struct ns2_led d2net_v2_led_pins[] = {
+	{
+		.name	= "d2net_v2:blue:sata",
+		.cmd	= D2NET_V2_GPIO_BLUE_LED_CMD,
+		.slow	= D2NET_V2_GPIO_BLUE_LED_SLOW,
+	},
+};
+
+static struct ns2_led_platform_data d2net_v2_leds_data = {
+	.num_leds	= ARRAY_SIZE(d2net_v2_led_pins),
+	.leds		= d2net_v2_led_pins,
+};
+
+static struct platform_device d2net_v2_leds = {
+	.name		= "leds-ns2",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_leds_data,
+	},
+};
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+static unsigned int d2net_v2_mpp_config[] __initdata = {
+	MPP0_SPI_SCn,
+	MPP1_SPI_MOSI,
+	MPP2_SPI_SCK,
+	MPP3_SPI_MISO,
+	MPP6_SYSRST_OUTn,
+	MPP7_GPO,		/* Request power-off */
+	MPP8_TW0_SDA,
+	MPP9_TW0_SCK,
+	MPP10_UART0_TXD,
+	MPP11_UART0_RXD,
+	MPP12_GPO,		/* Red led */
+	MPP13_GPIO,		/* Rear power switch (on|auto) */
+	MPP14_GPIO,		/* USB fuse */
+	MPP15_GPIO,		/* Rear power switch (auto|off) */
+	MPP16_GPIO,		/* SATA 0 power */
+	MPP21_SATA0_ACTn,
+	MPP24_GPIO,		/* USB mode select */
+	MPP26_GPIO,		/* USB device vbus */
+	MPP28_GPIO,		/* USB enable host vbus */
+	MPP29_GPIO,		/* Blue led (slow register) */
+	MPP30_GPIO,		/* Blue led (command register) */
+	MPP34_GPIO,		/* Power button (1 = Released, 0 = Pushed) */
+	MPP35_GPIO,		/* Inhibit power-off */
+	0
+};
+
+#define D2NET_V2_GPIO_POWER_OFF		7
+
+static void d2net_v2_power_off(void)
+{
+	gpio_set_value(D2NET_V2_GPIO_POWER_OFF, 1);
+}
+
+static void __init d2net_v2_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_init();
+	kirkwood_mpp_conf(d2net_v2_mpp_config);
+
+	lacie_v2_hdd_power_init(1);
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&d2net_v2_ge00_data);
+	kirkwood_sata_init(&d2net_v2_sata_data);
+	kirkwood_uart0_init();
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
+
+	platform_device_register(&d2net_v2_leds);
+	platform_device_register(&d2net_v2_gpio_leds);
+	platform_device_register(&d2net_v2_gpio_buttons);
+
+	if (gpio_request(D2NET_V2_GPIO_POWER_OFF, "power-off") == 0 &&
+	    gpio_direction_output(D2NET_V2_GPIO_POWER_OFF, 0) == 0)
+		pm_power_off = d2net_v2_power_off;
+	else
+		pr_err("d2net_v2: failed to configure power-off GPIO\n");
+}
+
+MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
+	.boot_params	= 0x00000100,
+	.init_machine	= d2net_v2_init,
+	.map_io		= kirkwood_map_io,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &kirkwood_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/db88f6281-bp-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/db88f6281-bp-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/db88f6281-bp-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/db88f6281-bp-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -97,8 +97,6 @@
 
 MACHINE_START(DB88F6281_BP, "Marvell DB-88F6281-BP Development Board")
 	/* Maintainer: Saeed Bishara <saeed@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= db88f6281_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/dockstar-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/dockstar-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/dockstar-setup.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/dockstar-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/mach-kirkwood/dockstar-setup.c
+ *
+ * Seagate FreeAgent DockStar Setup
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <plat/mvsdio.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mtd_partition dockstar_nand_parts[] = {
+	{
+		.name = "u-boot",
+		.offset = 0,
+		.size = SZ_1M
+	}, {
+		.name = "uImage",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = SZ_4M
+	}, {
+		.name = "root",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = MTDPART_SIZ_FULL
+	},
+};
+
+static struct mv643xx_eth_platform_data dockstar_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct gpio_led dockstar_led_pins[] = {
+	{
+		.name			= "dockstar:green:health",
+		.default_trigger	= "default-on",
+		.gpio			= 46,
+		.active_low		= 1,
+	},
+	{
+		.name			= "dockstar:orange:misc",
+		.default_trigger	= "none",
+		.gpio			= 47,
+		.active_low		= 1,
+	},
+};
+
+static struct gpio_led_platform_data dockstar_led_data = {
+	.leds		= dockstar_led_pins,
+	.num_leds	= ARRAY_SIZE(dockstar_led_pins),
+};
+
+static struct platform_device dockstar_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &dockstar_led_data,
+	}
+};
+
+static unsigned int dockstar_mpp_config[] __initdata = {
+	MPP29_GPIO,	/* USB Power Enable */
+	MPP46_GPIO,	/* LED green */
+	MPP47_GPIO,	/* LED orange */
+	0
+};
+
+static void __init dockstar_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_init();
+
+	/* setup gpio pin select */
+	kirkwood_mpp_conf(dockstar_mpp_config);
+
+	kirkwood_uart0_init();
+	kirkwood_nand_init(ARRAY_AND_SIZE(dockstar_nand_parts), 25);
+
+	if (gpio_request(29, "USB Power Enable") != 0 ||
+	    gpio_direction_output(29, 1) != 0)
+		printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
+	kirkwood_ehci_init();
+
+	kirkwood_ge00_init(&dockstar_ge00_data);
+
+	platform_device_register(&dockstar_leds);
+}
+
+MACHINE_START(DOCKSTAR, "Seagate FreeAgent DockStar")
+	.boot_params	= 0x00000100,
+	.init_machine	= dockstar_init,
+	.map_io		= kirkwood_map_io,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &kirkwood_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/guruplug-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/guruplug-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/guruplug-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/guruplug-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -121,8 +121,6 @@
 
 MACHINE_START(GURUPLUG, "Marvell GuruPlug Reference Board")
 	/* Maintainer: Siddarth Gore <gores@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= guruplug_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,12 +8,11 @@
 
 #include <mach/bridge-regs.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =KIRKWOOD_REGS_PHYS_BASE
-	ldrne	\rx, =KIRKWOOD_REGS_VIRT_BASE
-	orr	\rx, \rx, #0x00012000
+	.macro	addruart, rp, rv
+	ldr	\rp, =KIRKWOOD_REGS_PHYS_BASE
+	ldr	\rv, =KIRKWOOD_REGS_VIRT_BASE
+	orr	\rp, \rp, #0x00012000
+	orr	\rv, \rv, #0x00012000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,55 @@
+/*
+ * arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
+ *
+ * Platform data structure for netxbig LED driver
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_LEDS_NETXBIG_H
+#define __MACH_LEDS_NETXBIG_H
+
+struct netxbig_gpio_ext {
+	unsigned	*addr;
+	int		num_addr;
+	unsigned	*data;
+	int		num_data;
+	unsigned	enable;
+};
+
+enum netxbig_led_mode {
+	NETXBIG_LED_OFF,
+	NETXBIG_LED_ON,
+	NETXBIG_LED_SATA,
+	NETXBIG_LED_TIMER1,
+	NETXBIG_LED_TIMER2,
+	NETXBIG_LED_MODE_NUM,
+};
+
+#define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
+
+struct netxbig_led_timer {
+	unsigned long		delay_on;
+	unsigned long		delay_off;
+	enum netxbig_led_mode	mode;
+};
+
+struct netxbig_led {
+	const char	*name;
+	const char	*default_trigger;
+	int		mode_addr;
+	int		*mode_val;
+	int		bright_addr;
+};
+
+struct netxbig_led_platform_data {
+	struct netxbig_gpio_ext	*gpio_ext;
+	struct netxbig_led_timer *timer;
+	int			num_timer;
+	struct netxbig_led	*leds;
+	int			num_leds;
+};
+
+#endif /* __MACH_LEDS_NETXBIG_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -58,6 +58,12 @@
 	  QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
 	  devices.
 
+config MACH_DOCKSTAR
+	bool "Seagate FreeAgent DockStar"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Seagate FreeAgent DockStar.
+
 config MACH_OPENRD
         bool
 
@@ -100,6 +106,12 @@
 	  Say 'Y' here if you want your kernel to support the
 	  LaCie Network Space Max v2 NAS.
 
+config MACH_D2NET_V2
+	bool "LaCie d2 Network v2 NAS Board"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  LaCie d2 Network v2 NAS.
+
 config MACH_NET2BIG_V2
 	bool "LaCie 2Big Network v2 NAS Board"
 	help
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/lacie_v2-common.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/lacie_v2-common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/lacie_v2-common.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/lacie_v2-common.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,113 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/gpio.h>
+#include <asm/mach/time.h>
+#include <mach/kirkwood.h>
+#include <mach/irqs.h>
+#include <plat/time.h>
+#include "common.h"
+
+/*****************************************************************************
+ * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
+ ****************************************************************************/
+
+static struct mtd_partition lacie_v2_flash_parts[] = {
+	{
+		.name = "u-boot",
+		.size = MTDPART_SIZ_FULL,
+		.offset = 0,
+		.mask_flags = MTD_WRITEABLE, /* force read-only */
+	},
+};
+
+static const struct flash_platform_data lacie_v2_flash = {
+	.type		= "mx25l4005a",
+	.name		= "spi_flash",
+	.parts		= lacie_v2_flash_parts,
+	.nr_parts	= ARRAY_SIZE(lacie_v2_flash_parts),
+};
+
+static struct spi_board_info __initdata lacie_v2_spi_slave_info[] = {
+	{
+		.modalias	= "m25p80",
+		.platform_data	= &lacie_v2_flash,
+		.irq		= -1,
+		.max_speed_hz	= 20000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+	},
+};
+
+void __init lacie_v2_register_flash(void)
+{
+	spi_register_board_info(lacie_v2_spi_slave_info,
+				ARRAY_SIZE(lacie_v2_spi_slave_info));
+	kirkwood_spi_init();
+}
+
+/*****************************************************************************
+ * I2C devices
+ ****************************************************************************/
+
+static struct at24_platform_data at24c04 = {
+	.byte_len	= SZ_4K / 8,
+	.page_size	= 16,
+};
+
+/*
+ * i2c addr | chip         | description
+ * 0x50     | HT24LC04     | eeprom (512B)
+ */
+
+static struct i2c_board_info __initdata lacie_v2_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("24c04", 0x50),
+		.platform_data  = &at24c04,
+	}
+};
+
+void __init lacie_v2_register_i2c_devices(void)
+{
+	kirkwood_i2c_init();
+	i2c_register_board_info(0, lacie_v2_i2c_info,
+				ARRAY_SIZE(lacie_v2_i2c_info));
+}
+
+/*****************************************************************************
+ * Hard Disk power
+ ****************************************************************************/
+
+static int __initdata lacie_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
+
+void __init lacie_v2_hdd_power_init(int hdd_num)
+{
+	int i;
+	int err;
+
+	/* Power up all hard disks. */
+	for (i = 0; i < hdd_num; i++) {
+		err = gpio_request(lacie_v2_gpio_hdd_power[i], NULL);
+		if (err == 0) {
+			err = gpio_direction_output(
+					lacie_v2_gpio_hdd_power[i], 1);
+			/* Free the HDD power GPIOs. This allow user-space to
+			 * configure them via the gpiolib sysfs interface. */
+			gpio_free(lacie_v2_gpio_hdd_power[i]);
+		}
+		if (err)
+			pr_err("Failed to power up HDD%d\n", i + 1);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/lacie_v2-common.h linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/lacie_v2-common.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/lacie_v2-common.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/lacie_v2-common.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+#define __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+
+void lacie_v2_register_flash(void);
+void lacie_v2_register_i2c_devices(void);
+void lacie_v2_hdd_power_init(int hdd_num);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -7,14 +7,16 @@
 obj-$(CONFIG_MACH_SHEEVAPLUG)		+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG)	+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_GURUPLUG)		+= guruplug-setup.o
+obj-$(CONFIG_MACH_DOCKSTAR)		+= dockstar-setup.o
 obj-$(CONFIG_MACH_TS219)		+= ts219-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS41X)		+= ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD)		+= openrd-setup.o
-obj-$(CONFIG_MACH_NETSPACE_V2)		+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_INETSPACE_V2)		+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_NETSPACE_MAX_V2)	+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_NET2BIG_V2)		+= netxbig_v2-setup.o
-obj-$(CONFIG_MACH_NET5BIG_V2)		+= netxbig_v2-setup.o
+obj-$(CONFIG_MACH_NETSPACE_V2)		+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_INETSPACE_V2)		+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NETSPACE_MAX_V2)	+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_D2NET_V2)		+= d2net_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET2BIG_V2)		+= netxbig_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET5BIG_V2)		+= netxbig_v2-setup.o lacie_v2-common.o
 obj-$(CONFIG_MACH_T5325)		+= t5325-setup.o
 
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/mpp.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/mpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/mpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/mpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,7 +59,7 @@
 	}
 	printk("\n");
 
-	while (*mpp_list) {
+	for ( ; *mpp_list; mpp_list++) {
 		unsigned int num = MPP_NUM(*mpp_list);
 		unsigned int sel = MPP_SEL(*mpp_list);
 		int shift, gpio_mode;
@@ -88,8 +88,6 @@
 		if (sel != 0)
 			gpio_mode = 0;
 		orion_gpio_set_valid(num, gpio_mode);
-
-		mpp_list++;
 	}
 
 	printk(KERN_DEBUG "  final MPP regs:");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -163,8 +163,6 @@
 
 MACHINE_START(MV88F6281GTW_GE, "Marvell 88F6281 GTW GE Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= mv88f6281gtw_ge_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/netspace_v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/netspace_v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/netspace_v2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/netspace_v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,56 +24,20 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
+#include <linux/gpio-fan.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/leds-ns2.h>
-#include <plat/time.h>
 #include "common.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netspace_v2_flash_parts[] = {
-	{
-		.name = "u-boot",
-		.size = MTDPART_SIZ_FULL,
-		.offset = 0,
-		.mask_flags = MTD_WRITEABLE, /* force read-only */
-	},
-};
-
-static const struct flash_platform_data netspace_v2_flash = {
-	.type		= "mx25l4005a",
-	.name		= "spi_flash",
-	.parts		= netspace_v2_flash_parts,
-	.nr_parts	= ARRAY_SIZE(netspace_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netspace_v2_spi_slave_info[] = {
-	{
-		.modalias	= "m25p80",
-		.platform_data	= &netspace_v2_flash,
-		.irq		= -1,
-		.max_speed_hz	= 20000000,
-		.bus_num	= 0,
-		.chip_select	= 0,
-	},
-};
+#include "lacie_v2-common.h"
 
 /*****************************************************************************
  * Ethernet
@@ -84,27 +48,6 @@
 };
 
 /*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-	.byte_len	= SZ_4K / 8,
-	.page_size	= 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netspace_v2_i2c_info[] = {
-	{
-		I2C_BOARD_INFO("24c04", 0x50),
-		.platform_data  = &at24c04,
-	}
-};
-
-/*****************************************************************************
  * SATA
  ****************************************************************************/
 
@@ -112,35 +55,6 @@
 	.n_ports	= 2,
 };
 
-#define NETSPACE_V2_GPIO_SATA0_POWER	16
-#define NETSPACE_V2_GPIO_SATA1_POWER	17
-
-static void __init netspace_v2_sata_power_init(void)
-{
-	int err;
-
-	err = gpio_request(NETSPACE_V2_GPIO_SATA0_POWER, "SATA0 power");
-	if (err == 0) {
-		err = gpio_direction_output(NETSPACE_V2_GPIO_SATA0_POWER, 1);
-		if (err)
-			gpio_free(NETSPACE_V2_GPIO_SATA0_POWER);
-	}
-	if (err)
-		pr_err("netspace_v2: failed to setup SATA0 power\n");
-
-	if (machine_is_netspace_max_v2()) {
-		err = gpio_request(NETSPACE_V2_GPIO_SATA1_POWER, "SATA1 power");
-		if (err == 0) {
-			err = gpio_direction_output(
-					NETSPACE_V2_GPIO_SATA1_POWER, 1);
-			if (err)
-				gpio_free(NETSPACE_V2_GPIO_SATA1_POWER);
-		}
-		if (err)
-			pr_err("netspace_v2: failed to setup SATA1 power\n");
-	}
-}
-
 /*****************************************************************************
  * GPIO keys
  ****************************************************************************/
@@ -224,17 +138,43 @@
 };
 
 /*****************************************************************************
- * Timer
+ * GPIO fan
  ****************************************************************************/
 
-static void netspace_v2_timer_init(void)
-{
-	kirkwood_tclk = 166666667;
-	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
+/* Designed for fan 40x40x16: ADDA AD0412LB-D50 6000rpm@12v */
+static struct gpio_fan_speed netspace_max_v2_fan_speed[] = {
+	{    0,  0 },
+	{ 1500,	15 },
+	{ 1700,	14 },
+	{ 1800,	13 },
+	{ 2100,	12 },
+	{ 3100,	11 },
+	{ 3300,	10 },
+	{ 4300,	 9 },
+	{ 5500,	 8 },
+};
 
-struct sys_timer netspace_v2_timer = {
-	.init = netspace_v2_timer_init,
+static unsigned netspace_max_v2_fan_ctrl[] = { 22, 7, 33, 23 };
+
+static struct gpio_fan_alarm netspace_max_v2_fan_alarm = {
+	.gpio		= 25,
+	.active_low	= 1,
+};
+
+static struct gpio_fan_platform_data netspace_max_v2_fan_data = {
+	.num_ctrl	= ARRAY_SIZE(netspace_max_v2_fan_ctrl),
+	.ctrl		= netspace_max_v2_fan_ctrl,
+	.alarm		= &netspace_max_v2_fan_alarm,
+	.num_speed	= ARRAY_SIZE(netspace_max_v2_fan_speed),
+	.speed		= netspace_max_v2_fan_speed,
+};
+
+static struct platform_device netspace_max_v2_gpio_fan = {
+	.name	= "gpio-fan",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &netspace_max_v2_fan_data,
+	},
 };
 
 /*****************************************************************************
@@ -291,22 +231,23 @@
 	kirkwood_init();
 	kirkwood_mpp_conf(netspace_v2_mpp_config);
 
-	netspace_v2_sata_power_init();
+	if (machine_is_netspace_max_v2())
+		lacie_v2_hdd_power_init(2);
+	else
+		lacie_v2_hdd_power_init(1);
 
 	kirkwood_ehci_init();
 	kirkwood_ge00_init(&netspace_v2_ge00_data);
 	kirkwood_sata_init(&netspace_v2_sata_data);
 	kirkwood_uart0_init();
-	spi_register_board_info(netspace_v2_spi_slave_info,
-				ARRAY_SIZE(netspace_v2_spi_slave_info));
-	kirkwood_spi_init();
-	kirkwood_i2c_init();
-	i2c_register_board_info(0, netspace_v2_i2c_info,
-				ARRAY_SIZE(netspace_v2_i2c_info));
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
 
 	platform_device_register(&netspace_v2_leds);
 	platform_device_register(&netspace_v2_gpio_leds);
 	platform_device_register(&netspace_v2_gpio_buttons);
+	if (machine_is_netspace_max_v2())
+		platform_device_register(&netspace_max_v2_gpio_fan);
 
 	if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
 	    gpio_direction_output(NETSPACE_V2_GPIO_POWER_OFF, 0) == 0)
@@ -317,36 +258,30 @@
 
 #ifdef CONFIG_MACH_NETSPACE_V2
 MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &kirkwood_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_INETSPACE_V2
 MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &kirkwood_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_NETSPACE_MAX_V2
 MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &kirkwood_timer,
 MACHINE_END
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/netxbig_v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/netxbig_v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/netxbig_v2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/netxbig_v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,55 +23,19 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
-#include <plat/time.h>
+#include <mach/leds-netxbig.h>
 #include "common.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netxbig_v2_flash_parts[] = {
-	{
-		.name = "u-boot",
-		.size = MTDPART_SIZ_FULL,
-		.offset = 0,
-		.mask_flags = MTD_WRITEABLE, /* force read-only */
-	},
-};
-
-static const struct flash_platform_data netxbig_v2_flash = {
-	.type		= "mx25l4005a",
-	.name		= "spi_flash",
-	.parts		= netxbig_v2_flash_parts,
-	.nr_parts	= ARRAY_SIZE(netxbig_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netxbig_v2_spi_slave_info[] = {
-	{
-		.modalias	= "m25p80",
-		.platform_data	= &netxbig_v2_flash,
-		.irq		= -1,
-		.max_speed_hz	= 20000000,
-		.bus_num	= 0,
-		.chip_select	= 0,
-	},
-};
+#include "lacie_v2-common.h"
 
 /*****************************************************************************
  * Ethernet
@@ -86,27 +50,6 @@
 };
 
 /*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-	.byte_len	= SZ_4K / 8,
-	.page_size	= 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netxbig_v2_i2c_info[] = {
-	{
-		I2C_BOARD_INFO("24c04", 0x50),
-		.platform_data  = &at24c04,
-	}
-};
-
-/*****************************************************************************
  * SATA
  ****************************************************************************/
 
@@ -114,34 +57,6 @@
 	.n_ports	= 2,
 };
 
-static int __initdata netxbig_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
-
-static void __init netxbig_v2_sata_power_init(void)
-{
-	int i;
-	int err;
-	int hdd_nb;
-
-	if (machine_is_net2big_v2())
-		hdd_nb = 2;
-	else
-		hdd_nb = 5;
-
-	/* Power up all hard disks. */
-	for (i = 0; i < hdd_nb; i++) {
-		err = gpio_request(netxbig_v2_gpio_hdd_power[i], NULL);
-		if (err == 0) {
-			err = gpio_direction_output(
-					netxbig_v2_gpio_hdd_power[i], 1);
-			/* Free the HDD power GPIOs. This allow user-space to
-			 * configure them via the gpiolib sysfs interface. */
-			gpio_free(netxbig_v2_gpio_hdd_power[i]);
-		}
-		if (err)
-			pr_err("netxbig_v2: failed to power up HDD%d\n", i + 1);
-	}
-}
-
 /*****************************************************************************
  * GPIO keys
  ****************************************************************************/
@@ -190,7 +105,7 @@
 };
 
 /*****************************************************************************
- * GPIO LEDs
+ * GPIO extension LEDs
  ****************************************************************************/
 
 /*
@@ -200,19 +115,32 @@
  * - address register : bit [0-2] -> GPIO [47-49]
  * - data register    : bit [0-2] -> GPIO [44-46]
  * - enable register  : GPIO 29
- *
+ */
+
+static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 };
+static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 };
+
+static struct netxbig_gpio_ext netxbig_v2_gpio_ext = {
+	.addr		= netxbig_v2_gpio_ext_addr,
+	.num_addr	= ARRAY_SIZE(netxbig_v2_gpio_ext_addr),
+	.data		= netxbig_v2_gpio_ext_data,
+	.num_data	= ARRAY_SIZE(netxbig_v2_gpio_ext_data),
+	.enable		= 29,
+};
+
+/*
  * Address register selection:
  *
  * addr | register
  * ----------------------------
  *   0  | front LED
  *   1  | front LED brightness
- *   2  | HDD LED brightness
- *   3  | HDD1 LED
- *   4  | HDD2 LED
- *   5  | HDD3 LED
- *   6  | HDD4 LED
- *   7  | HDD5 LED
+ *   2  | SATA LED brightness
+ *   3  | SATA0 LED
+ *   4  | SATA1 LED
+ *   5  | SATA2 LED
+ *   6  | SATA3 LED
+ *   7  | SATA4 LED
  *
  * Data register configuration:
  *
@@ -233,30 +161,107 @@
  *   6  | blink blue on=1 sec and red on=1 sec
  *   7  | blink blue on=0.5 sec and blue off=2.5 sec
  *
- * data | HDD LED mode
+ * data | SATA LED mode
  * -------------------------------------------------
- *   0  | fix blue on
+ *   0  | fix off
  *   1  | SATA activity blink
  *   2  | fix red on
  *   3  | blink blue on=1 sec and blue off=1 sec
  *   4  | blink red on=1 sec and red off=1 sec
  *   5  | blink blue on=2.5 sec and red on=0.5 sec
  *   6  | blink blue on=1 sec and red on=1 sec
- *   7  | blink blue on=0.5 sec and blue off=2.5 sec
+ *   7  | fix blue on
  */
 
-/*****************************************************************************
- * Timer
- ****************************************************************************/
+static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 2,
+	[NETXBIG_LED_SATA]	= NETXBIG_LED_INVALID_MODE,
+	[NETXBIG_LED_TIMER1]	= 4,
+	[NETXBIG_LED_TIMER2]	= NETXBIG_LED_INVALID_MODE,
+};
 
-static void netxbig_v2_timer_init(void)
-{
-	kirkwood_tclk = 166666667;
-	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
+static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 1,
+	[NETXBIG_LED_SATA]	= NETXBIG_LED_INVALID_MODE,
+	[NETXBIG_LED_TIMER1]	= 3,
+	[NETXBIG_LED_TIMER2]	= 7,
+};
 
-struct sys_timer netxbig_v2_timer = {
-	.init = netxbig_v2_timer_init,
+static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 7,
+	[NETXBIG_LED_SATA]	= 1,
+	[NETXBIG_LED_TIMER1]	= 3,
+	[NETXBIG_LED_TIMER2]	= NETXBIG_LED_INVALID_MODE,
+};
+
+static struct netxbig_led_timer netxbig_v2_led_timer[] = {
+	[0] = {
+		.delay_on	= 500,
+		.delay_off	= 500,
+		.mode		= NETXBIG_LED_TIMER1,
+	},
+	[1] = {
+		.delay_on	= 500,
+		.delay_off	= 1000,
+		.mode		= NETXBIG_LED_TIMER2,
+	},
+};
+
+#define NETXBIG_LED(_name, maddr, mval, baddr)			\
+	{ .name		= _name,				\
+	  .mode_addr	= maddr,				\
+	  .mode_val	= mval,					\
+	  .bright_addr	= baddr }
+
+static struct netxbig_led net2big_v2_leds_ctrl[] = {
+	NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+	NETXBIG_LED("net2big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+	NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net2big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net2big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+};
+
+static struct netxbig_led_platform_data net2big_v2_leds_data = {
+	.gpio_ext	= &netxbig_v2_gpio_ext,
+	.timer		= netxbig_v2_led_timer,
+	.num_timer	= ARRAY_SIZE(netxbig_v2_led_timer),
+	.leds		= net2big_v2_leds_ctrl,
+	.num_leds	= ARRAY_SIZE(net2big_v2_leds_ctrl),
+};
+
+static struct netxbig_led net5big_v2_leds_ctrl[] = {
+	NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+	NETXBIG_LED("net5big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+	NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata2",  5, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata3",  6, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata5",  7, netxbig_v2_red_mled,       2),
+};
+
+static struct netxbig_led_platform_data net5big_v2_leds_data = {
+	.gpio_ext	= &netxbig_v2_gpio_ext,
+	.timer		= netxbig_v2_led_timer,
+	.num_timer	= ARRAY_SIZE(netxbig_v2_led_timer),
+	.leds		= net5big_v2_leds_ctrl,
+	.num_leds	= ARRAY_SIZE(net5big_v2_leds_ctrl),
+};
+
+static struct platform_device netxbig_v2_leds = {
+	.name		= "leds-netxbig",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &net2big_v2_leds_data,
+	},
 };
 
 /*****************************************************************************
@@ -284,18 +289,18 @@
 	MPP24_GPIO,		/* USB mode select */
 	MPP26_GPIO,		/* USB device vbus */
 	MPP28_GPIO,		/* USB enable host vbus */
-	MPP29_GPIO,		/* CPLD extension ALE */
+	MPP29_GPIO,		/* GPIO extension ALE */
 	MPP34_GPIO,		/* Rear Push button */
 	MPP35_GPIO,		/* Inhibit switch power-off */
 	MPP36_GPIO,		/* SATA HDD1 presence */
 	MPP37_GPIO,		/* SATA HDD2 presence */
 	MPP40_GPIO,		/* eSATA presence */
-	MPP44_GPIO,		/* CPLD extension (data 0) */
-	MPP45_GPIO,		/* CPLD extension (data 1) */
-	MPP46_GPIO,		/* CPLD extension (data 2) */
-	MPP47_GPIO,		/* CPLD extension (addr 0) */
-	MPP48_GPIO,		/* CPLD extension (addr 1) */
-	MPP49_GPIO,		/* CPLD extension (addr 2) */
+	MPP44_GPIO,		/* GPIO extension (data 0) */
+	MPP45_GPIO,		/* GPIO extension (data 1) */
+	MPP46_GPIO,		/* GPIO extension (data 2) */
+	MPP47_GPIO,		/* GPIO extension (addr 0) */
+	MPP48_GPIO,		/* GPIO extension (addr 1) */
+	MPP49_GPIO,		/* GPIO extension (addr 2) */
 	0
 };
 
@@ -324,7 +329,7 @@
 	MPP26_GE1_RXD2,
 	MPP27_GE1_RXD3,
 	MPP28_GPIO,		/* USB enable host vbus */
-	MPP29_GPIO,		/* CPLD extension ALE */
+	MPP29_GPIO,		/* GPIO extension ALE */
 	MPP30_GE1_RXCTL,
 	MPP31_GE1_RXCLK,
 	MPP32_GE1_TCLKOUT,
@@ -339,12 +344,12 @@
 	MPP41_GPIO,		/* SATA HDD3 power */
 	MPP42_GPIO,		/* SATA HDD4 power */
 	MPP43_GPIO,		/* SATA HDD5 power */
-	MPP44_GPIO,		/* CPLD extension (data 0) */
-	MPP45_GPIO,		/* CPLD extension (data 1) */
-	MPP46_GPIO,		/* CPLD extension (data 2) */
-	MPP47_GPIO,		/* CPLD extension (addr 0) */
-	MPP48_GPIO,		/* CPLD extension (addr 1) */
-	MPP49_GPIO,		/* CPLD extension (addr 2) */
+	MPP44_GPIO,		/* GPIO extension (data 0) */
+	MPP45_GPIO,		/* GPIO extension (data 1) */
+	MPP46_GPIO,		/* GPIO extension (data 2) */
+	MPP47_GPIO,		/* GPIO extension (addr 0) */
+	MPP48_GPIO,		/* GPIO extension (addr 1) */
+	MPP49_GPIO,		/* GPIO extension (addr 2) */
 	0
 };
 
@@ -366,7 +371,10 @@
 	else
 		kirkwood_mpp_conf(net5big_v2_mpp_config);
 
-	netxbig_v2_sata_power_init();
+	if (machine_is_net2big_v2())
+		lacie_v2_hdd_power_init(2);
+	else
+		lacie_v2_hdd_power_init(5);
 
 	kirkwood_ehci_init();
 	kirkwood_ge00_init(&netxbig_v2_ge00_data);
@@ -374,13 +382,12 @@
 		kirkwood_ge01_init(&netxbig_v2_ge01_data);
 	kirkwood_sata_init(&netxbig_v2_sata_data);
 	kirkwood_uart0_init();
-	spi_register_board_info(netxbig_v2_spi_slave_info,
-				ARRAY_SIZE(netxbig_v2_spi_slave_info));
-	kirkwood_spi_init();
-	kirkwood_i2c_init();
-	i2c_register_board_info(0, netxbig_v2_i2c_info,
-				ARRAY_SIZE(netxbig_v2_i2c_info));
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
 
+	if (machine_is_net5big_v2())
+		netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data;
+	platform_device_register(&netxbig_v2_leds);
 	platform_device_register(&netxbig_v2_gpio_buttons);
 
 	if (gpio_request(NETXBIG_V2_GPIO_POWER_OFF, "power-off") == 0 &&
@@ -392,24 +399,20 @@
 
 #ifdef CONFIG_MACH_NET2BIG_V2
 MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= netxbig_v2_init,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netxbig_v2_timer,
+	.timer		= &kirkwood_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_NET5BIG_V2
 MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= netxbig_v2_init,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netxbig_v2_timer,
+	.timer		= &kirkwood_timer,
 MACHINE_END
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/openrd-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/openrd-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/openrd-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/openrd-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
@@ -57,7 +58,22 @@
 };
 
 static unsigned int openrd_mpp_config[] __initdata = {
+	MPP12_SD_CLK,
+	MPP13_SD_CMD,
+	MPP14_SD_D0,
+	MPP15_SD_D1,
+	MPP16_SD_D2,
+	MPP17_SD_D3,
+	MPP28_GPIO,
 	MPP29_GPIO,
+	MPP34_GPIO,
+	0
+};
+
+/* Configure MPP for UART1 */
+static unsigned int openrd_uart1_mpp_config[] __initdata = {
+	MPP13_UART1_TXD,
+	MPP14_UART1_RXD,
 	0
 };
 
@@ -67,6 +83,68 @@
 	},
 };
 
+static int __initdata uart1;
+
+static int __init sd_uart_selection(char *str)
+{
+	uart1 = -EINVAL;
+
+	/* Default is SD. Change if required, for UART */
+	if (!str)
+		return 0;
+
+	if (!strncmp(str, "232", 3)) {
+		uart1 = 232;
+	} else if (!strncmp(str, "485", 3)) {
+		/* OpenRD-Base doesn't have RS485. Treat is as an
+		 * unknown argument & just have default setting -
+		 * which is SD */
+		if (machine_is_openrd_base()) {
+			uart1 = -ENODEV;
+			return 1;
+		}
+
+		uart1 = 485;
+	}
+	return 1;
+}
+/* Parse boot_command_line string kw_openrd_init_uart1=232/485 */
+__setup("kw_openrd_init_uart1=", sd_uart_selection);
+
+static int __init uart1_mpp_config(void)
+{
+	kirkwood_mpp_conf(openrd_uart1_mpp_config);
+
+	if (gpio_request(34, "SD_UART1_SEL")) {
+		printk(KERN_ERR "GPIO request failed for SD/UART1 selection"
+				", gpio: 34\n");
+		return -EIO;
+	}
+
+	if (gpio_request(28, "RS232_RS485_SEL")) {
+		printk(KERN_ERR "GPIO request failed for RS232/RS485 selection"
+				", gpio# 28\n");
+		gpio_free(34);
+		return -EIO;
+	}
+
+	/* Select UART1
+	 * Pin # 34: 0 => UART1, 1 => SD */
+	gpio_direction_output(34, 0);
+
+	/* Select RS232 OR RS485
+	 * Pin # 28: 0 => RS232, 1 => RS485 */
+	if (uart1 == 232)
+		gpio_direction_output(28, 0);
+	else
+		gpio_direction_output(28, 1);
+
+	gpio_free(34);
+	gpio_free(28);
+
+	return 0;
+}
+
 static void __init openrd_init(void)
 {
 	/*
@@ -90,7 +168,6 @@
 		kirkwood_ge01_init(&openrd_ge01_data);
 
 	kirkwood_sata_init(&openrd_sata_data);
-	kirkwood_sdio_init(&openrd_mvsdio_data);
 
 	kirkwood_i2c_init();
 
@@ -99,6 +176,28 @@
 			ARRAY_SIZE(i2c_board_info));
 		kirkwood_audio_init();
 	}
+
+	if (uart1 <= 0) {
+		if (uart1 < 0)
+			printk(KERN_ERR "Invalid kernel parameter to select "
+				"UART1. Defaulting to SD. ERROR CODE: %d\n",
+				uart1);
+
+		/* Select SD
+		 * Pin # 34: 0 => UART1, 1 => SD */
+		if (gpio_request(34, "SD_UART1_SEL")) {
+			printk(KERN_ERR "GPIO request failed for SD/UART1 "
+					"selection, gpio: 34\n");
+		} else {
+
+			gpio_direction_output(34, 1);
+			gpio_free(34);
+			kirkwood_sdio_init(&openrd_mvsdio_data);
+		}
+	} else {
+		if (!uart1_mpp_config())
+			kirkwood_uart1_init();
+	}
 }
 
 static int __init openrd_pci_init(void)
@@ -115,8 +214,6 @@
 #ifdef CONFIG_MACH_OPENRD_BASE
 MACHINE_START(OPENRD_BASE, "Marvell OpenRD Base Board")
 	/* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= openrd_init,
 	.map_io		= kirkwood_map_io,
@@ -128,8 +225,6 @@
 #ifdef CONFIG_MACH_OPENRD_CLIENT
 MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
 	/* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= openrd_init,
 	.map_io		= kirkwood_map_io,
@@ -141,8 +236,6 @@
 #ifdef CONFIG_MACH_OPENRD_ULTIMATE
 MACHINE_START(OPENRD_ULTIMATE, "Marvell OpenRD Ultimate Board")
 	/* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= openrd_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/rd88f6192-nas-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -79,8 +79,6 @@
 
 MACHINE_START(RD88F6192_NAS, "Marvell RD-88F6192-NAS Development Board")
 	/* Maintainer: Saeed Bishara <saeed@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f6192_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/rd88f6281-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/rd88f6281-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/rd88f6281-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/rd88f6281-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -115,8 +115,6 @@
 
 MACHINE_START(RD88F6281, "Marvell RD-88F6281 Reference Board")
 	/* Maintainer: Saeed Bishara <saeed@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f6281_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/sheevaplug-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/sheevaplug-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/sheevaplug-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/sheevaplug-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -131,8 +131,6 @@
 #ifdef CONFIG_MACH_SHEEVAPLUG
 MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board")
 	/* Maintainer: shadi Ammouri <shadi@marvell.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= sheevaplug_init,
 	.map_io		= kirkwood_map_io,
@@ -143,8 +141,6 @@
 
 #ifdef CONFIG_MACH_ESATA_SHEEVAPLUG
 MACHINE_START(ESATA_SHEEVAPLUG, "Marvell eSATA SheevaPlug Reference Board")
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= sheevaplug_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/t5325-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/t5325-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/t5325-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/t5325-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -184,8 +184,6 @@
 
 MACHINE_START(T5325, "HP t5325 Thin Client")
 	/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= hp_t5325_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/ts219-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/ts219-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/ts219-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/ts219-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -120,8 +120,6 @@
 
 MACHINE_START(TS219, "QNAP TS-119/TS-219")
 	/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= qnap_ts219_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/ts41x-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/ts41x-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-kirkwood/ts41x-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-kirkwood/ts41x-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,10 @@
 #include "mpp.h"
 #include "tsx1x-common.h"
 
+/* for the PCIe reset workaround */
+#include <plat/pcie.h>
+
+
 #define QNAP_TS41X_JUMPER_JP1	45
 
 static struct i2c_board_info __initdata qnap_ts41x_i2c_rtc = {
@@ -140,8 +144,16 @@
 
 static int __init ts41x_pci_init(void)
 {
-	if (machine_is_ts41x())
+	if (machine_is_ts41x()) {
+		/*
+		 * Without this explicit reset, the PCIe SATA controller
+		 * (Marvell 88sx7042/sata_mv) is known to stop working
+		 * after a few minutes.
+		 */
+		orion_pcie_reset((void __iomem *)PCIE_VIRT_BASE);
+
 		kirkwood_pcie_init(KW_PCIE0);
+	}
 
    return 0;
 }
@@ -149,8 +161,6 @@
 
 MACHINE_START(TS41X, "QNAP TS-41x")
 	/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
-	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= qnap_ts41x_init,
 	.map_io		= kirkwood_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-acs5k.c linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-acs5k.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-acs5k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-acs5k.c	2011-01-04 19:50:19.000000000 -0500
@@ -223,8 +223,6 @@
 
 MACHINE_START(ACS5K, "Brivo Systems LLC ACS-5000 Master board")
 	/* Maintainer: Simtec Electronics. */
-	.phys_io	= KS8695_IO_PA,
-	.io_pg_offst	= (KS8695_IO_VA >> 18) & 0xfffc,
 	.boot_params	= KS8695_SDRAM_PA + 0x100,
 	.map_io		= ks8695_map_io,
 	.init_irq	= ks8695_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-dsm320.c linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-dsm320.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-dsm320.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-dsm320.c	2011-01-04 19:50:19.000000000 -0500
@@ -121,8 +121,6 @@
 
 MACHINE_START(DSM320, "D-Link DSM-320 Wireless Media Player")
 	/* Maintainer: Simtec Electronics. */
-	.phys_io	= KS8695_IO_PA,
-	.io_pg_offst	= (KS8695_IO_VA >> 18) & 0xfffc,
 	.boot_params	= KS8695_SDRAM_PA + 0x100,
 	.map_io		= ks8695_map_io,
 	.init_irq	= ks8695_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-micrel.c linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-micrel.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/board-micrel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/board-micrel.c	2011-01-04 19:50:19.000000000 -0500
@@ -53,8 +53,6 @@
 
 MACHINE_START(KS8695, "KS8695 Centaur Development Board")
 	/* Maintainer: Micrel Semiconductor Inc. */
-	.phys_io	= KS8695_IO_PA,
-	.io_pg_offst	= (KS8695_IO_VA >> 18) & 0xfffc,
 	.boot_params	= KS8695_SDRAM_PA + 0x100,
 	.map_io		= ks8695_map_io,
 	.init_irq	= ks8695_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ks8695/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ks8695/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,9 @@
 #include <mach/hardware.h>
 #include <mach/regs-uart.h>
 
-	.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1				@ MMU enabled?
-		ldreq	\rx, =KS8695_UART_PA		@ physical base address
-		ldrne	\rx, =KS8695_UART_VA		@ virtual base address
+	.macro	addruart, rp, rv
+		ldr	\rp, =KS8695_UART_PA		@ physical base address
+		ldr	\rv, =KS8695_UART_VA		@ virtual base address
 	.endm
 
 	.macro	senduart, rd, rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-l7200/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-l7200/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-l7200/include/mach/debug-macro.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-l7200/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+/* arch/arm/mach-l7200/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 1994-1999 Russell King
+ *  Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+		.equ	io_virt, IO_BASE
+		.equ	io_phys, IO_START
+
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00044000	@ UART1
+@		mov	\rp, #0x00045000	@ UART2
+		add	\rv, \rp, #io_virt	@ virtual address
+		add	\rp, \rp, #io_phys	@ physical base address
+		.endm
+
+		.macro	senduart,rd,rx
+		str	\rd, [\rx, #0x0]	@ UARTDR
+		.endm
+
+		.macro	waituart,rd,rx
+1001:		ldr	\rd, [\rx, #0x18]	@ UARTFLG
+		tst	\rd, #1 << 5		@ UARTFLGUTXFF - 1 when full
+		bne	1001b
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:		ldr	\rd, [\rx, #0x18]	@ UARTFLG
+		tst	\rd, #1 << 3		@ UARTFLGUBUSY - 1 when busy
+		bne	1001b
+		.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/arch-kev7a400.c linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/arch-kev7a400.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/arch-kev7a400.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/arch-kev7a400.c	2011-01-04 19:50:19.000000000 -0500
@@ -111,8 +111,6 @@
 
 MACHINE_START (KEV7A400, "Sharp KEV7a400")
 	/* Maintainer: Marc Singer */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= kev7a400_map_io,
 	.init_irq	= lh7a400_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/arch-lpd7a40x.c linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/arch-lpd7a40x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/arch-lpd7a40x.c	2011-01-04 19:50:19.000000000 -0500
@@ -398,8 +398,6 @@
 
 MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
 	/* Maintainer: Marc Singer */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= lpd7a40x_map_io,
 	.init_irq	= lh7a400_init_irq,
@@ -413,8 +411,6 @@
 
 MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
 	/* Maintainer: Marc Singer */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= lpd7a40x_map_io,
 	.init_irq	= lh7a404_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-lh7a40x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-lh7a40x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,12 +14,10 @@
 	@ It is not known if this will be appropriate for every 40x
 	@ board.
 
-		.macro  addruart, rx, tmp
-		mrc     p15, 0, \rx, c1, c0
-		tst     \rx, #1                 @ MMU enabled?
-		mov     \rx, #0x00000700        @ offset from base
-		orreq   \rx, \rx, #0x80000000   @ physical base
-		orrne   \rx, \rx, #0xf8000000   @ virtual base
+		.macro  addruart, rp, rv
+		mov     \rp, #0x00000700        @ offset from base
+		orr     \rv, \rp, #0xf8000000   @ virtual base
+		orr     \rp, \rp, #0x80000000   @ physical base
 		.endm
 
 		.macro  senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-loki/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-loki/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-loki/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-loki/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,12 +8,11 @@
 
 #include <mach/loki.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =LOKI_REGS_PHYS_BASE
-	ldrne	\rx, =LOKI_REGS_VIRT_BASE
-	orr	\rx, \rx, #0x00012000
+	.macro	addruart, rp, rv
+	ldr	\rp, =LOKI_REGS_PHYS_BASE
+	ldr	\rv, =LOKI_REGS_VIRT_BASE
+	orr	\rp, \rp, #0x00012000
+	orr	\rv, \rv, #0x00012000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-loki/lb88rc8480-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-loki/lb88rc8480-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-loki/lb88rc8480-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-loki/lb88rc8480-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -90,8 +90,6 @@
 
 MACHINE_START(LB88RC8480, "Marvell LB88RC8480 Development Board")
 	/* Maintainer: Ke Wei <kewei@marvell.com> */
-	.phys_io	= LOKI_REGS_PHYS_BASE,
-	.io_pg_offst	= ((LOKI_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= lb88rc8480_init,
 	.map_io		= loki_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-lpc32xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-lpc32xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-lpc32xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-lpc32xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -20,11 +20,9 @@
  * Debug output is hardcoded to standard UART 5
 */
 
-	.macro	addruart,rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1				@ MMU enabled?
-	ldreq	\rx, =0x40090000
-	ldrne	\rx, =0xF4090000
+	.macro	addruart, rp, rv
+	ldreq	\rp, =0x40090000
+	ldrne	\rv, =0xF4090000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-lpc32xx/phy3250.c linux-libre-2.6.37-gnu/arch/arm/mach-lpc32xx/phy3250.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-lpc32xx/phy3250.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-lpc32xx/phy3250.c	2011-01-04 19:50:19.000000000 -0500
@@ -172,18 +172,12 @@
 }
 
 static struct pl022_config_chip spi0_chip_info = {
-	.lbm			= LOOPBACK_DISABLED,
 	.com_mode		= INTERRUPT_TRANSFER,
 	.iface			= SSP_INTERFACE_MOTOROLA_SPI,
 	.hierarchy		= SSP_MASTER,
 	.slave_tx_disable	= 0,
-	.endian_tx		= SSP_TX_LSB,
-	.endian_rx		= SSP_RX_LSB,
-	.data_size		= SSP_DATA_BITS_8,
 	.rx_lev_trig		= SSP_RX_4_OR_MORE_ELEM,
 	.tx_lev_trig		= SSP_TX_4_OR_MORE_EMPTY_LOC,
-	.clk_phase		= SSP_CLK_FIRST_EDGE,
-	.clk_pol		= SSP_CLK_POL_IDLE_LOW,
 	.ctrl_len		= SSP_BITS_8,
 	.wait_state		= SSP_MWIRE_WAIT_ZERO,
 	.duplex			= SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@@ -239,6 +233,7 @@
 			.max_speed_hz = 5000000,
 			.bus_num = 0,
 			.chip_select = 0,
+			.mode = SPI_MODE_0,
 			.platform_data = &eeprom,
 			.controller_data = &spi0_chip_info,
 		},
@@ -387,8 +382,6 @@
 
 MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
 	/* Maintainer: Kevin Wells, NXP Semiconductors */
-	.phys_io	= LPC32XX_UART5_BASE,
-	.io_pg_offst	= ((IO_ADDRESS(LPC32XX_UART5_BASE))>>18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= lpc32xx_map_io,
 	.init_irq	= lpc32xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/aspenite.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/aspenite.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/aspenite.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/aspenite.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -23,6 +24,9 @@
 #include <mach/mfp-pxa168.h>
 #include <mach/pxa168.h>
 #include <mach/gpio.h>
+#include <video/pxa168fb.h>
+#include <linux/input.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "common.h"
 
@@ -66,6 +70,43 @@
 	GPIO115_I2S_BCLK,
 	GPIO116_I2S_RXD,
 	GPIO117_I2S_TXD,
+
+	/* LCD */
+	GPIO56_LCD_FCLK_RD,
+	GPIO57_LCD_LCLK_A0,
+	GPIO58_LCD_PCLK_WR,
+	GPIO59_LCD_DENA_BIAS,
+	GPIO60_LCD_DD0,
+	GPIO61_LCD_DD1,
+	GPIO62_LCD_DD2,
+	GPIO63_LCD_DD3,
+	GPIO64_LCD_DD4,
+	GPIO65_LCD_DD5,
+	GPIO66_LCD_DD6,
+	GPIO67_LCD_DD7,
+	GPIO68_LCD_DD8,
+	GPIO69_LCD_DD9,
+	GPIO70_LCD_DD10,
+	GPIO71_LCD_DD11,
+	GPIO72_LCD_DD12,
+	GPIO73_LCD_DD13,
+	GPIO74_LCD_DD14,
+	GPIO75_LCD_DD15,
+	GPIO76_LCD_DD16,
+	GPIO77_LCD_DD17,
+	GPIO78_LCD_DD18,
+	GPIO79_LCD_DD19,
+	GPIO80_LCD_DD20,
+	GPIO81_LCD_DD21,
+	GPIO82_LCD_DD22,
+	GPIO83_LCD_DD23,
+
+	/* Keypad */
+	GPIO109_KP_MKIN1,
+	GPIO110_KP_MKIN0,
+	GPIO111_KP_MKOUT7,
+	GPIO112_KP_MKOUT6,
+	GPIO121_KP_MKIN4,
 };
 
 static struct smc91x_platdata smc91x_info = {
@@ -134,6 +175,51 @@
 	{ I2C_BOARD_INFO("wm8753", 0x1b), },
 };
 
+static struct fb_videomode video_modes[] = {
+	[0] = {
+		.pixclock	= 30120,
+		.refresh	= 60,
+		.xres		= 800,
+		.yres		= 480,
+		.hsync_len	= 1,
+		.left_margin	= 215,
+		.right_margin	= 40,
+		.vsync_len	= 1,
+		.upper_margin	= 34,
+		.lower_margin	= 10,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+	},
+};
+
+struct pxa168fb_mach_info aspenite_lcd_info = {
+	.id			= "Graphic Frame",
+	.modes			= video_modes,
+	.num_modes		= ARRAY_SIZE(video_modes),
+	.pix_fmt		= PIX_FMT_RGB565,
+	.io_pin_allocation_mode = PIN_MODE_DUMB_24,
+	.dumb_mode		= DUMB_MODE_RGB888,
+	.active			= 1,
+	.panel_rbswap		= 0,
+	.invert_pixclock	= 0,
+};
+
+static unsigned int aspenite_matrix_key_map[] = {
+	KEY(0, 6, KEY_UP),	/* SW 4 */
+	KEY(0, 7, KEY_DOWN),	/* SW 5 */
+	KEY(1, 6, KEY_LEFT),	/* SW 6 */
+	KEY(1, 7, KEY_RIGHT),	/* SW 7 */
+	KEY(4, 6, KEY_ENTER),	/* SW 8 */
+	KEY(4, 7, KEY_ESC),	/* SW 9 */
+};
+
+static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
+	.matrix_key_rows	= 5,
+	.matrix_key_cols	= 8,
+	.matrix_key_map		= aspenite_matrix_key_map,
+	.matrix_key_map_size	= ARRAY_SIZE(aspenite_matrix_key_map),
+	.debounce_interval	= 30,
+};
+
 static void __init common_init(void)
 {
 	mfp_config(ARRAY_AND_SIZE(common_pin_config));
@@ -143,24 +229,24 @@
 	pxa168_add_twsi(1, NULL, ARRAY_AND_SIZE(aspenite_i2c_info));
 	pxa168_add_ssp(1);
 	pxa168_add_nand(&aspenite_nand_info);
+	pxa168_add_fb(&aspenite_lcd_info);
+	pxa168_add_keypad(&aspenite_keypad_info);
 
 	/* off-chip devices */
 	platform_device_register(&smc91x_device);
 }
 
 MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
+	.nr_irqs	= IRQ_BOARD_START,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = common_init,
 MACHINE_END
 
 MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
+	.nr_irqs	= IRQ_BOARD_START,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
 	.init_machine   = common_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/avengers_lite.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/avengers_lite.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/avengers_lite.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/avengers_lite.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,8 +41,6 @@
 }
 
 MACHINE_START(AVENGERS_LITE, "PXA168 Avengers lite Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
 	.init_irq       = pxa168_init_irq,
 	.timer          = &pxa168_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/common.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,13 +10,20 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <mach/addr-map.h>
+#include <mach/cputype.h>
 
 #include "common.h"
 
+#define MMP_CHIPID	(AXI_VIRT_BASE + 0x82c00)
+
+unsigned int mmp_chip_id;
+EXPORT_SYMBOL(mmp_chip_id);
+
 static struct map_desc standard_io_desc[] __initdata = {
 	{
 		.pfn		= __phys_to_pfn(APB_PHYS_BASE),
@@ -34,4 +41,7 @@
 void __init mmp_map_io(void)
 {
 	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
+
+	/* this is early, initialize mmp_chip_id here */
+	mmp_chip_id = __raw_readl(MMP_CHIPID);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/flint.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/flint.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/flint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/flint.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/smc91x.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -25,6 +26,8 @@
 
 #include "common.h"
 
+#define FLINT_NR_IRQS	(IRQ_BOARD_START + 48)
+
 static unsigned long flint_pin_config[] __initdata = {
 	/* UART1 */
 	GPIO45_UART1_RXD,
@@ -113,9 +116,8 @@
 }
 
 MACHINE_START(FLINT, "Flint Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
+	.nr_irqs	= FLINT_NR_IRQS,
 	.init_irq       = mmp2_init_irq,
 	.timer          = &mmp2_timer,
 	.init_machine   = flint_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/cputype.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/cputype.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/cputype.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/cputype.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,36 +4,52 @@
 #include <asm/cputype.h>
 
 /*
- *  CPU   Stepping   OLD_ID       CPU_ID      CHIP_ID
+ *  CPU   Stepping   CPU_ID      CHIP_ID
  *
- * PXA168    A0    0x41159263   0x56158400   0x00A0A333
- * PXA910    Y0    0x41159262   0x56158000   0x00F0C910
- * MMP2	     Z0			0x560f5811
+ * PXA168    S0    0x56158400   0x0000C910
+ * PXA168    A0    0x56158400   0x00A0A168
+ * PXA910    Y1    0x56158400   0x00F2C920
+ * PXA910    A0    0x56158400   0x00F2C910
+ * PXA910    A1    0x56158400   0x00A0C910
+ * PXA920    Y0    0x56158400   0x00F2C920
+ * PXA920    A0    0x56158400   0x00A0C920
+ * PXA920    A1    0x56158400   0x00A1C920
+ * MMP2	     Z0	   0x560f5811   0x00F00410
+ * MMP2      Z1    0x560f5811   0x00E00410
+ * MMP2      A0    0x560f5811   0x00A0A610
  */
 
+extern unsigned int mmp_chip_id;
+
 #ifdef CONFIG_CPU_PXA168
-#  define __cpu_is_pxa168(id)	\
-	({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; })
+static inline int cpu_is_pxa168(void)
+{
+	return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+		((mmp_chip_id & 0xfff) == 0x168);
+}
 #else
-#  define __cpu_is_pxa168(id)	(0)
+#define cpu_is_pxa168()	(0)
 #endif
 
+/* cpu_is_pxa910() is shared on both pxa910 and pxa920 */
 #ifdef CONFIG_CPU_PXA910
-#  define __cpu_is_pxa910(id)	\
-	({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x80; })
+static inline int cpu_is_pxa910(void)
+{
+	return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+		(((mmp_chip_id & 0xfff) == 0x910) ||
+		 ((mmp_chip_id & 0xfff) == 0x920));
+}
 #else
-#  define __cpu_is_pxa910(id)	(0)
+#define cpu_is_pxa910()	(0)
 #endif
 
 #ifdef CONFIG_CPU_MMP2
-#  define __cpu_is_mmp2(id)	\
-	({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x58; })
+static inline int cpu_is_mmp2(void)
+{
+	return (((read_cpuid_id() >> 8) & 0xff) == 0x58);
+}
 #else
-#  define __cpu_is_mmp2(id)	(0)
+#define cpu_is_mmp2()	(0)
 #endif
 
-#define cpu_is_pxa168()		({ __cpu_is_pxa168(read_cpuid_id()); })
-#define cpu_is_pxa910()		({ __cpu_is_pxa910(read_cpuid_id()); })
-#define cpu_is_mmp2()		({ __cpu_is_mmp2(read_cpuid_id()); })
-
 #endif /* __ASM_MACH_CPUTYPE_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,11 @@
 
 #include <mach/addr-map.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1				@ MMU enabled?
-		ldreq	\rx, =APB_PHYS_BASE		@ physical
-		ldrne	\rx, =APB_VIRT_BASE		@ virtual
-		orr	\rx, \rx, #0x00017000
+		.macro	addruart, rp, rv
+		ldr	\rp, =APB_PHYS_BASE		@ physical
+		ldr	\rv, =APB_VIRT_BASE		@ virtual
+		orr	\rp, \rp, #0x00017000
+		orr	\rv, \rv, #0x00017000
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -222,10 +222,8 @@
 #define IRQ_GPIO_NUM			192
 #define IRQ_GPIO(x)			(IRQ_GPIO_START + (x))
 
-/* Board IRQ - 64 by default, increase if not enough */
 #define IRQ_BOARD_START			(IRQ_GPIO_START + IRQ_GPIO_NUM)
-#define IRQ_BOARD_END			(IRQ_BOARD_START + 64)
 
-#define NR_IRQS				(IRQ_BOARD_END)
+#define NR_IRQS				(IRQ_BOARD_START)
 
 #endif /* __ASM_MACH_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/mfp-pxa168.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/mfp-pxa168.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/mfp-pxa168.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/mfp-pxa168.h	2011-01-04 19:50:19.000000000 -0500
@@ -289,4 +289,11 @@
 #define GPIO86_PWM1_OUT		MFP_CFG(GPIO86, AF2)
 #define GPIO86_PWM2_OUT		MFP_CFG(GPIO86, AF3)
 
+/* Keypad */
+#define GPIO109_KP_MKIN1        MFP_CFG(GPIO109, AF7)
+#define GPIO110_KP_MKIN0        MFP_CFG(GPIO110, AF7)
+#define GPIO111_KP_MKOUT7       MFP_CFG(GPIO111, AF7)
+#define GPIO112_KP_MKOUT6       MFP_CFG(GPIO112, AF7)
+#define GPIO121_KP_MKIN4        MFP_CFG(GPIO121, AF7)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/pxa168.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/pxa168.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/pxa168.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/pxa168.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,11 +5,15 @@
 
 extern struct sys_timer pxa168_timer;
 extern void __init pxa168_init_irq(void);
+extern void pxa168_clear_keypad_wakeup(void);
 
 #include <linux/i2c.h>
 #include <mach/devices.h>
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
+#include <video/pxa168fb.h>
+#include <plat/pxa27x_keypad.h>
+#include <mach/cputype.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
@@ -25,6 +29,8 @@
 extern struct pxa_device_desc pxa168_device_ssp4;
 extern struct pxa_device_desc pxa168_device_ssp5;
 extern struct pxa_device_desc pxa168_device_nand;
+extern struct pxa_device_desc pxa168_device_fb;
+extern struct pxa_device_desc pxa168_device_keypad;
 
 static inline int pxa168_add_uart(int id)
 {
@@ -97,4 +103,18 @@
 {
 	return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
 }
+
+static inline int pxa168_add_fb(struct pxa168fb_mach_info *mi)
+{
+	return pxa_register_device(&pxa168_device_fb, mi, sizeof(*mi));
+}
+
+static inline int pxa168_add_keypad(struct pxa27x_keypad_platform_data *data)
+{
+	if (cpu_is_pxa168())
+		data->clear_wakeup_event = pxa168_clear_keypad_wakeup;
+
+	return pxa_register_device(&pxa168_device_keypad, data, sizeof(*data));
+}
+
 #endif /* __ASM_MACH_PXA168_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/regs-apmu.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/regs-apmu.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/regs-apmu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/regs-apmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -33,4 +33,16 @@
 #define APMU_FNRST_DIS	(1 << 1)
 #define APMU_AXIRST_DIS	(1 << 0)
 
+/* Wake Clear Register */
+#define APMU_WAKE_CLR	APMU_REG(0x07c)
+
+#define APMU_PXA168_KP_WAKE_CLR		(1 << 7)
+#define APMU_PXA168_CFI_WAKE_CLR	(1 << 6)
+#define APMU_PXA168_XD_WAKE_CLR		(1 << 5)
+#define APMU_PXA168_MSP_WAKE_CLR	(1 << 4)
+#define APMU_PXA168_SD4_WAKE_CLR	(1 << 3)
+#define APMU_PXA168_SD3_WAKE_CLR	(1 << 2)
+#define APMU_PXA168_SD2_WAKE_CLR	(1 << 1)
+#define APMU_PXA168_SD1_WAKE_CLR	(1 << 0)
+
 #endif /* __ASM_MACH_REGS_APMU_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/teton_bga.h linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/teton_bga.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/include/mach/teton_bga.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/include/mach/teton_bga.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,27 @@
+/*
+ *  linux/arch/arm/mach-mmp/include/mach/teton_bga.h
+ *
+ *  Support for the Marvell PXA168 Teton BGA Development Platform.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+#ifndef __ASM_MACH_TETON_BGA_H
+#define __ASM_MACH_TETON_BGA_H
+
+/* GPIOs */
+#define MMC_PWENA_GPIO		27
+#define USBHPENB_GPIO		55
+#define RTC_INT_GPIO		78
+#define LCD_VBLK_EN_GPIO	79
+#define LCD_DVDD_EN_GPIO	80
+#define RST_WIFI_GPIO		81
+#define CF_PWEN_GPIO		82
+#define USB_OC_GPIO		83
+#define PWM_GPIO		84
+#define USBHPENA_GPIO		85
+#define TS_INT_GPIO		86
+#define CIR_GPIO		108
+
+#endif /* __ASM_MACH_TETON_BGA_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/jasper.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/jasper.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/jasper.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/jasper.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,16 +18,18 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max8649.h>
 #include <linux/mfd/max8925.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/addr-map.h>
 #include <mach/mfp-mmp2.h>
 #include <mach/mmp2.h>
-#include <mach/irqs.h>
 
 #include "common.h"
 
+#define JASPER_NR_IRQS		(IRQ_BOARD_START + 48)
+
 static unsigned long jasper_pin_config[] __initdata = {
 	/* UART1 */
 	GPIO29_UART1_RXD,
@@ -134,9 +136,8 @@
 }
 
 MACHINE_START(MARVELL_JASPER, "Jasper Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
+	.nr_irqs	= JASPER_NR_IRQS,
 	.init_irq       = mmp2_init_irq,
 	.timer          = &mmp2_timer,
 	.init_machine   = jasper_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-mmp/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,13 @@
 	  PXA910-based development board. Since MMP2 is compatible to
 	  ARMv6 architecture.
 
+config MACH_TETON_BGA
+	bool "Marvell's PXA168 Teton BGA Development Board"
+	select CPU_PXA168
+	help
+	  Say 'Y' here if you want to support the Marvell PXA168-based
+	  Teton BGA Development Board.
+
 endmenu
 
 config CPU_PXA168
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-mmp/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -17,3 +17,4 @@
 obj-$(CONFIG_MACH_TTC_DKB)	+= ttc_dkb.o
 obj-$(CONFIG_MACH_FLINT)	+= flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
+obj-$(CONFIG_MACH_TETON_BGA)	+= teton_bga.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/mmp2.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/mmp2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/mmp2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/mmp2.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,7 +126,6 @@
 static APBC_CLK(twsi4, MMP2_TWSI4, 0, 26000000);
 static APBC_CLK(twsi5, MMP2_TWSI5, 0, 26000000);
 static APBC_CLK(twsi6, MMP2_TWSI6, 0, 26000000);
-static APBC_CLK(rtc, MMP2_RTC, 0, 32768);
 
 static APMU_CLK(nand, NAND, 0xbf, 100000000);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/pxa168.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/pxa168.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/pxa168.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/pxa168.c	2011-01-04 19:50:19.000000000 -0500
@@ -77,8 +77,10 @@
 static APBC_CLK(ssp3, PXA168_SSP3, 4, 0);
 static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
 static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
+static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
 
 static APMU_CLK(nand, NAND, 0x01db, 208000000);
+static APMU_CLK(lcd, LCD, 0x7f, 312000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
@@ -96,6 +98,8 @@
 	INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
 	INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
 	INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
+	INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
+	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -132,6 +136,16 @@
 	.init	= pxa168_timer_init,
 };
 
+void pxa168_clear_keypad_wakeup(void)
+{
+	uint32_t val;
+	uint32_t mask = APMU_PXA168_KP_WAKE_CLR;
+
+	/* wake event clear is needed in order to clear keypad interrupt */
+	val = __raw_readl(APMU_WAKE_CLR);
+	__raw_writel(val |  mask, APMU_WAKE_CLR);
+}
+
 /* on-chip devices */
 PXA168_DEVICE(uart1, "pxa2xx-uart", 0, UART1, 0xd4017000, 0x30, 21, 22);
 PXA168_DEVICE(uart2, "pxa2xx-uart", 1, UART2, 0xd4018000, 0x30, 23, 24);
@@ -147,3 +161,5 @@
 PXA168_DEVICE(ssp3, "pxa168-ssp", 2, SSP3, 0xd401f000, 0x40, 56, 57);
 PXA168_DEVICE(ssp4, "pxa168-ssp", 3, SSP4, 0xd4020000, 0x40, 58, 59);
 PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
+PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
+PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/tavorevb.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/tavorevb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/tavorevb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/tavorevb.c	2011-01-04 19:50:19.000000000 -0500
@@ -99,8 +99,6 @@
 }
 
 MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
 	.init_irq       = pxa910_init_irq,
 	.timer          = &pxa910_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/teton_bga.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/teton_bga.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/teton_bga.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/teton_bga.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,89 @@
+/*
+ *  linux/arch/arm/mach-mmp/teton_bga.c
+ *
+ *  Support for the Marvell PXA168 Teton BGA Development Platform.
+ *
+ *  Author: Mark F. Brown <mark.brown314@gmail.com>
+ *
+ *  This code is based on aspenite.c
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <plat/pxa27x_keypad.h>
+#include <linux/i2c.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/addr-map.h>
+#include <mach/mfp-pxa168.h>
+#include <mach/pxa168.h>
+#include <mach/teton_bga.h>
+
+#include "common.h"
+
+static unsigned long teton_bga_pin_config[] __initdata = {
+	/* UART1 */
+	GPIO107_UART1_TXD,
+	GPIO108_UART1_RXD,
+
+	/* Keypad */
+	GPIO109_KP_MKIN1,
+	GPIO110_KP_MKIN0,
+	GPIO111_KP_MKOUT7,
+	GPIO112_KP_MKOUT6,
+
+	/* I2C Bus */
+	GPIO105_CI2C_SDA,
+	GPIO106_CI2C_SCL,
+
+	/* RTC */
+	GPIO78_GPIO,
+};
+
+static unsigned int teton_bga_matrix_key_map[] = {
+	KEY(0, 6, KEY_ESC),
+	KEY(0, 7, KEY_ENTER),
+	KEY(1, 6, KEY_LEFT),
+	KEY(1, 7, KEY_RIGHT),
+};
+
+static struct pxa27x_keypad_platform_data teton_bga_keypad_info __initdata = {
+	.matrix_key_rows        = 2,
+	.matrix_key_cols        = 8,
+	.matrix_key_map         = teton_bga_matrix_key_map,
+	.matrix_key_map_size    = ARRAY_SIZE(teton_bga_matrix_key_map),
+	.debounce_interval      = 30,
+};
+
+static struct i2c_board_info teton_bga_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("ds1337", 0x68),
+		.irq = gpio_to_irq(RTC_INT_GPIO)
+	},
+};
+
+static void __init teton_bga_init(void)
+{
+	mfp_config(ARRAY_AND_SIZE(teton_bga_pin_config));
+
+	/* on-chip devices */
+	pxa168_add_uart(1);
+	pxa168_add_keypad(&teton_bga_keypad_info);
+	pxa168_add_twsi(0, NULL, ARRAY_AND_SIZE(teton_bga_i2c_info));
+}
+
+MACHINE_START(TETON_BGA, "PXA168-based Teton BGA Development Platform")
+	.map_io		= mmp_map_io,
+	.nr_irqs	= IRQ_BOARD_START,
+	.init_irq       = pxa168_init_irq,
+	.timer          = &pxa168_timer,
+	.init_machine   = teton_bga_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mmp/ttc_dkb.c linux-libre-2.6.37-gnu/arch/arm/mach-mmp/ttc_dkb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mmp/ttc_dkb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mmp/ttc_dkb.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/onenand.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -24,6 +25,8 @@
 
 #include "common.h"
 
+#define TTCDKB_NR_IRQS		(IRQ_BOARD_START + 24)
+
 static unsigned long ttc_dkb_pin_config[] __initdata = {
 	/* UART2 */
 	GPIO47_UART2_RXD,
@@ -122,9 +125,8 @@
 }
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
-	.phys_io        = APB_PHYS_BASE,
-	.io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
 	.map_io		= mmp_map_io,
+	.nr_irqs	= TTCDKB_NR_IRQS,
 	.init_irq       = pxa910_init_irq,
 	.timer          = &pxa910_timer,
 	.init_machine   = ttc_dkb_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-halibut.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-halibut.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-halibut.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-halibut.c	2011-01-04 19:50:19.000000000 -0500
@@ -83,7 +83,6 @@
 {
 	mi->nr_banks=1;
 	mi->bank[0].start = PHYS_OFFSET;
-	mi->bank[0].node = PHYS_TO_NID(PHYS_OFFSET);
 	mi->bank[0].size = (101*1024*1024);
 }
 
@@ -95,8 +94,6 @@
 
 MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= 0x10000100,
 	.fixup		= halibut_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-mahimahi.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-mahimahi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-mahimahi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-mahimahi.c	2011-01-04 19:50:19.000000000 -0500
@@ -75,8 +75,6 @@
 
 MACHINE_START(MAHIMAHI, "mahimahi")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= 0x20000100,
 	.fixup		= mahimahi_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm7x27.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm7x27.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm7x27.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm7x27.c	2011-01-04 19:50:19.000000000 -0500
@@ -131,8 +131,6 @@
 
 MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= PHYS_OFFSET + 0x100,
 	.map_io		= msm7x2x_map_io,
@@ -143,8 +141,6 @@
 
 MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= PHYS_OFFSET + 0x100,
 	.map_io		= msm7x2x_map_io,
@@ -155,8 +151,6 @@
 
 MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= PHYS_OFFSET + 0x100,
 	.map_io		= msm7x2x_map_io,
@@ -167,8 +161,6 @@
 
 MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= PHYS_OFFSET + 0x100,
 	.map_io		= msm7x2x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm7x30.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm7x30.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm7x30.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm7x30.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,27 +39,11 @@
 
 extern struct sys_timer msm_timer;
 
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-static struct msm_gpio uart2_config_data[] = {
-	{ GPIO_CFG(49, 2, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_RFR"},
-	{ GPIO_CFG(50, 2, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_CTS"},
-	{ GPIO_CFG(51, 2, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
-	{ GPIO_CFG(52, 2, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
-};
-
-static void msm7x30_init_uart2(void)
-{
-	msm_gpios_request_enable(uart2_config_data,
-			ARRAY_SIZE(uart2_config_data));
-
-}
-#endif
-
 static struct platform_device *devices[] __initdata = {
 #if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
         &msm_device_uart2,
 #endif
-
+	&msm_device_smd,
 };
 
 static void __init msm7x30_init_irq(void)
@@ -70,10 +54,6 @@
 static void __init msm7x30_init(void)
 {
 	platform_add_devices(devices, ARRAY_SIZE(devices));
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-	msm7x30_init_uart2();
-#endif
-
 }
 
 static void __init msm7x30_map_io(void)
@@ -84,8 +64,6 @@
 
 MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io  = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = msm7x30_map_io,
@@ -96,8 +74,6 @@
 
 MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io  = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = msm7x30_map_io,
@@ -108,8 +84,6 @@
 
 MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io  = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = msm7x30_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm8x60.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm8x60.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-msm8x60.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-msm8x60.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,100 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+void __iomem *gic_cpu_base_addr;
+
+unsigned long clk_get_max_axi_khz(void)
+{
+	return 0;
+}
+
+static void __init msm8x60_map_io(void)
+{
+	msm_map_msm8x60_io();
+}
+
+static void __init msm8x60_init_irq(void)
+{
+	unsigned int i;
+
+	gic_dist_init(0, MSM_QGIC_DIST_BASE, GIC_PPI_START);
+	gic_cpu_base_addr = (void *)MSM_QGIC_CPU_BASE;
+	gic_cpu_init(0, MSM_QGIC_CPU_BASE);
+
+	/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
+	writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+
+	/* RUMI does not adhere to GIC spec by enabling STIs by default.
+	 * Enable/clear is supposed to be RO for STIs, but is RW on RUMI.
+	 */
+	if (!machine_is_msm8x60_sim())
+		writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
+
+	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
+	 * as they are configured as level, which does not play nice with
+	 * handle_percpu_irq.
+	 */
+	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
+		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
+			set_irq_handler(i, handle_percpu_irq);
+	}
+}
+
+static void __init msm8x60_init(void)
+{
+}
+
+MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3")
+	.map_io = msm8x60_map_io,
+	.init_irq = msm8x60_init_irq,
+	.init_machine = msm8x60_init,
+	.timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
+	.map_io = msm8x60_map_io,
+	.init_irq = msm8x60_init_irq,
+	.init_machine = msm8x60_init,
+	.timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR")
+	.map_io = msm8x60_map_io,
+	.init_irq = msm8x60_init_irq,
+	.init_machine = msm8x60_init,
+	.timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA")
+	.map_io = msm8x60_map_io,
+	.init_irq = msm8x60_init_irq,
+	.init_machine = msm8x60_init,
+	.timer = &msm_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-qsd8x50.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-qsd8x50.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-qsd8x50.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-qsd8x50.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,20 +35,49 @@
 
 extern struct sys_timer msm_timer;
 
-static struct msm_gpio uart3_config_data[] = {
-	{ GPIO_CFG(86, 1, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
-	{ GPIO_CFG(87, 1, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
+static const resource_size_t qsd8x50_surf_smc91x_base __initdata = 0x70000300;
+static const unsigned        qsd8x50_surf_smc91x_gpio __initdata = 156;
+
+/* Leave smc91x resources empty here, as we'll fill them in
+ * at run-time: they vary from board to board, and the true
+ * configuration won't be known until boot.
+ */
+static struct resource smc91x_resources[] __initdata = {
+	[0] = {
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
-static struct platform_device *devices[] __initdata = {
-	&msm_device_uart3,
+static struct platform_device smc91x_device __initdata = {
+	.name           = "smc91x",
+	.id             = 0,
+	.num_resources  = ARRAY_SIZE(smc91x_resources),
+	.resource       = smc91x_resources,
 };
 
-static void msm8x50_init_uart3(void)
+static int __init msm_init_smc91x(void)
 {
-	msm_gpios_request_enable(uart3_config_data,
-				ARRAY_SIZE(uart3_config_data));
+	if (machine_is_qsd8x50_surf()) {
+		smc91x_resources[0].start = qsd8x50_surf_smc91x_base;
+		smc91x_resources[0].end   = qsd8x50_surf_smc91x_base + 0xff;
+		smc91x_resources[1].start =
+			gpio_to_irq(qsd8x50_surf_smc91x_gpio);
+		smc91x_resources[1].end   =
+			gpio_to_irq(qsd8x50_surf_smc91x_gpio);
+		platform_device_register(&smc91x_device);
+	}
+
+	return 0;
 }
+module_init(msm_init_smc91x);
+
+static struct platform_device *devices[] __initdata = {
+	&msm_device_uart3,
+	&msm_device_smd,
+};
 
 static void __init qsd8x50_map_io(void)
 {
@@ -64,14 +93,11 @@
 
 static void __init qsd8x50_init(void)
 {
-	msm8x50_init_uart3();
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io  = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = qsd8x50_map_io,
@@ -82,8 +108,6 @@
 
 MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io  = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = qsd8x50_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-sapphire.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-sapphire.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-sapphire.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-sapphire.c	2011-01-04 19:50:19.000000000 -0500
@@ -106,8 +106,6 @@
 MACHINE_START(SAPPHIRE, "sapphire")
 /* Maintainer: Brian Swetland <swetland@google.com> */
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io        = MSM_DEBUG_UART_PHYS,
-	.io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params    = PHYS_OFFSET + 0x100,
 	.fixup          = sapphire_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-trout.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-trout.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/board-trout.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/board-trout.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,8 +93,6 @@
 
 MACHINE_START(TROUT, "HTC Dream")
 #ifdef CONFIG_MSM_DEBUG_UART
-	.phys_io	= MSM_DEBUG_UART_PHYS,
-	.io_pg_offst	= ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
 	.boot_params	= 0x10000100,
 	.fixup		= trout_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/clock-dummy.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/clock-dummy.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/clock-dummy.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/clock-dummy.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,54 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+	return -ENOENT;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	return -ENOENT;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-msm7x30.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-msm7x30.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-msm7x30.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-msm7x30.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,11 @@
 	.resource	= resources_uart2,
 };
 
+struct platform_device msm_device_smd = {
+	.name   = "msm_smd",
+	.id     = -1,
+};
+
 struct clk msm_clocks_7x30[] = {
 	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
 	CLK_PCOM("adsp_clk",	ADSP_CLK,	NULL, 0),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-msm8x60-iommu.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-msm8x60-iommu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-msm8x60-iommu.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-msm8x60-iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,883 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+
+#include <mach/msm_iomap-8x60.h>
+#include <mach/irqs-8x60.h>
+#include <mach/iommu.h>
+
+static struct resource msm_iommu_jpegd_resources[] = {
+	{
+		.start = MSM_IOMMU_JPEGD_PHYS,
+		.end   = MSM_IOMMU_JPEGD_PHYS + MSM_IOMMU_JPEGD_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_JPEGD_CB_SC_SECURE_IRQ,
+		.end   = SMMU_JPEGD_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_vpe_resources[] = {
+	{
+		.start = MSM_IOMMU_VPE_PHYS,
+		.end   = MSM_IOMMU_VPE_PHYS + MSM_IOMMU_VPE_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_VPE_CB_SC_SECURE_IRQ,
+		.end   = SMMU_VPE_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_mdp0_resources[] = {
+	{
+		.start = MSM_IOMMU_MDP0_PHYS,
+		.end   = MSM_IOMMU_MDP0_PHYS + MSM_IOMMU_MDP0_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_MDP0_CB_SC_SECURE_IRQ,
+		.end   = SMMU_MDP0_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_mdp1_resources[] = {
+	{
+		.start = MSM_IOMMU_MDP1_PHYS,
+		.end   = MSM_IOMMU_MDP1_PHYS + MSM_IOMMU_MDP1_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_MDP1_CB_SC_SECURE_IRQ,
+		.end   = SMMU_MDP1_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_rot_resources[] = {
+	{
+		.start = MSM_IOMMU_ROT_PHYS,
+		.end   = MSM_IOMMU_ROT_PHYS + MSM_IOMMU_ROT_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_ROT_CB_SC_SECURE_IRQ,
+		.end   = SMMU_ROT_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_ijpeg_resources[] = {
+	{
+		.start = MSM_IOMMU_IJPEG_PHYS,
+		.end   = MSM_IOMMU_IJPEG_PHYS + MSM_IOMMU_IJPEG_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_IJPEG_CB_SC_SECURE_IRQ,
+		.end   = SMMU_IJPEG_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_vfe_resources[] = {
+	{
+		.start = MSM_IOMMU_VFE_PHYS,
+		.end   = MSM_IOMMU_VFE_PHYS + MSM_IOMMU_VFE_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_VFE_CB_SC_SECURE_IRQ,
+		.end   = SMMU_VFE_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_vcodec_a_resources[] = {
+	{
+		.start = MSM_IOMMU_VCODEC_A_PHYS,
+		.end   = MSM_IOMMU_VCODEC_A_PHYS + MSM_IOMMU_VCODEC_A_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
+		.end   = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_vcodec_b_resources[] = {
+	{
+		.start = MSM_IOMMU_VCODEC_B_PHYS,
+		.end   = MSM_IOMMU_VCODEC_B_PHYS + MSM_IOMMU_VCODEC_B_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
+		.end   = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_gfx3d_resources[] = {
+	{
+		.start = MSM_IOMMU_GFX3D_PHYS,
+		.end   = MSM_IOMMU_GFX3D_PHYS + MSM_IOMMU_GFX3D_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_GFX3D_CB_SC_SECURE_IRQ,
+		.end   = SMMU_GFX3D_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource msm_iommu_gfx2d0_resources[] = {
+	{
+		.start = MSM_IOMMU_GFX2D0_PHYS,
+		.end   = MSM_IOMMU_GFX2D0_PHYS + MSM_IOMMU_GFX2D0_SIZE - 1,
+		.name  = "physbase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "nonsecure_irq",
+		.start = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
+		.end   = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "secure_irq",
+		.start = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
+		.end   = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_root_iommu_dev = {
+	.name = "msm_iommu",
+	.id = -1,
+};
+
+static struct msm_iommu_dev jpegd_smmu = {
+	.name = "jpegd",
+	.clk_rate = -1
+};
+
+static struct msm_iommu_dev vpe_smmu = {
+	.name = "vpe"
+};
+
+static struct msm_iommu_dev mdp0_smmu = {
+	.name = "mdp0"
+};
+
+static struct msm_iommu_dev mdp1_smmu = {
+	.name = "mdp1"
+};
+
+static struct msm_iommu_dev rot_smmu = {
+	.name = "rot"
+};
+
+static struct msm_iommu_dev ijpeg_smmu = {
+	.name = "ijpeg"
+};
+
+static struct msm_iommu_dev vfe_smmu = {
+	.name = "vfe",
+	.clk_rate = -1
+};
+
+static struct msm_iommu_dev vcodec_a_smmu = {
+	.name = "vcodec_a"
+};
+
+static struct msm_iommu_dev vcodec_b_smmu = {
+	.name = "vcodec_b"
+};
+
+static struct msm_iommu_dev gfx3d_smmu = {
+	.name = "gfx3d",
+	.clk_rate = 27000000
+};
+
+static struct msm_iommu_dev gfx2d0_smmu = {
+	.name = "gfx2d0",
+	.clk_rate = 27000000
+};
+
+static struct platform_device msm_device_smmu_jpegd = {
+	.name = "msm_iommu",
+	.id = 0,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
+	.resource = msm_iommu_jpegd_resources,
+};
+
+static struct platform_device msm_device_smmu_vpe = {
+	.name = "msm_iommu",
+	.id = 1,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
+	.resource = msm_iommu_vpe_resources,
+};
+
+static struct platform_device msm_device_smmu_mdp0 = {
+	.name = "msm_iommu",
+	.id = 2,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
+	.resource = msm_iommu_mdp0_resources,
+};
+
+static struct platform_device msm_device_smmu_mdp1 = {
+	.name = "msm_iommu",
+	.id = 3,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
+	.resource = msm_iommu_mdp1_resources,
+};
+
+static struct platform_device msm_device_smmu_rot = {
+	.name = "msm_iommu",
+	.id = 4,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
+	.resource = msm_iommu_rot_resources,
+};
+
+static struct platform_device msm_device_smmu_ijpeg = {
+	.name = "msm_iommu",
+	.id = 5,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
+	.resource = msm_iommu_ijpeg_resources,
+};
+
+static struct platform_device msm_device_smmu_vfe = {
+	.name = "msm_iommu",
+	.id = 6,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
+	.resource = msm_iommu_vfe_resources,
+};
+
+static struct platform_device msm_device_smmu_vcodec_a = {
+	.name = "msm_iommu",
+	.id = 7,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
+	.resource = msm_iommu_vcodec_a_resources,
+};
+
+static struct platform_device msm_device_smmu_vcodec_b = {
+	.name = "msm_iommu",
+	.id = 8,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
+	.resource = msm_iommu_vcodec_b_resources,
+};
+
+static struct platform_device msm_device_smmu_gfx3d = {
+	.name = "msm_iommu",
+	.id = 9,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
+	.resource = msm_iommu_gfx3d_resources,
+};
+
+static struct platform_device msm_device_smmu_gfx2d0 = {
+	.name = "msm_iommu",
+	.id = 10,
+	.dev = {
+		.parent = &msm_root_iommu_dev.dev,
+	},
+	.num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
+	.resource = msm_iommu_gfx2d0_resources,
+};
+
+static struct msm_iommu_ctx_dev jpegd_src_ctx = {
+	.name = "jpegd_src",
+	.num = 0,
+	.mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev jpegd_dst_ctx = {
+	.name = "jpegd_dst",
+	.num = 1,
+	.mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev vpe_src_ctx = {
+	.name = "vpe_src",
+	.num = 0,
+	.mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev vpe_dst_ctx = {
+	.name = "vpe_dst",
+	.num = 1,
+	.mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_vg1_ctx = {
+	.name = "mdp_vg1",
+	.num = 0,
+	.mids = {0, 2, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_rgb1_ctx = {
+	.name = "mdp_rgb1",
+	.num = 1,
+	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_vg2_ctx = {
+	.name = "mdp_vg2",
+	.num = 0,
+	.mids = {0, 2, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_rgb2_ctx = {
+	.name = "mdp_rgb2",
+	.num = 1,
+	.mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
+};
+
+static struct msm_iommu_ctx_dev rot_src_ctx = {
+	.name = "rot_src",
+	.num = 0,
+	.mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev rot_dst_ctx = {
+	.name = "rot_dst",
+	.num = 1,
+	.mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev ijpeg_src_ctx = {
+	.name = "ijpeg_src",
+	.num = 0,
+	.mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev ijpeg_dst_ctx = {
+	.name = "ijpeg_dst",
+	.num = 1,
+	.mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev vfe_imgwr_ctx = {
+	.name = "vfe_imgwr",
+	.num = 0,
+	.mids = {2, 3, 4, 5, 6, 7, 8, -1}
+};
+
+static struct msm_iommu_ctx_dev vfe_misc_ctx = {
+	.name = "vfe_misc",
+	.num = 1,
+	.mids = {0, 1, 9, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_a_stream_ctx = {
+	.name = "vcodec_a_stream",
+	.num = 0,
+	.mids = {2, 5, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_a_mm1_ctx = {
+	.name = "vcodec_a_mm1",
+	.num = 1,
+	.mids = {0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_b_mm2_ctx = {
+	.name = "vcodec_b_mm2",
+	.num = 0,
+	.mids = {0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_rbpa_ctx = {
+	.name = "gfx3d_rbpa",
+	.num = 0,
+	.mids = {-1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_cpvgttc_ctx = {
+	.name = "gfx3d_cpvgttc",
+	.num = 1,
+	.mids = {0, 1, 2, 3, 4, 5, 6, 7, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_smmu_ctx = {
+	.name = "gfx3d_smmu",
+	.num = 2,
+	.mids = {8, 9, 10, 11, 12, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx2d0_pixv1_ctx = {
+	.name = "gfx2d0_pixv1_smmu",
+	.num = 0,
+	.mids = {0, 3, 4, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx2d0_texv3_ctx = {
+	.name = "gfx2d0_texv3_smmu",
+	.num = 1,
+	.mids = {1, 6, 7, -1}
+};
+
+static struct platform_device msm_device_jpegd_src_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 0,
+	.dev = {
+		.parent = &msm_device_smmu_jpegd.dev,
+	},
+};
+
+static struct platform_device msm_device_jpegd_dst_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 1,
+	.dev = {
+		.parent = &msm_device_smmu_jpegd.dev,
+	},
+};
+
+static struct platform_device msm_device_vpe_src_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 2,
+	.dev = {
+		.parent = &msm_device_smmu_vpe.dev,
+	},
+};
+
+static struct platform_device msm_device_vpe_dst_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 3,
+	.dev = {
+		.parent = &msm_device_smmu_vpe.dev,
+	},
+};
+
+static struct platform_device msm_device_mdp_vg1_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 4,
+	.dev = {
+		.parent = &msm_device_smmu_mdp0.dev,
+	},
+};
+
+static struct platform_device msm_device_mdp_rgb1_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 5,
+	.dev = {
+		.parent = &msm_device_smmu_mdp0.dev,
+	},
+};
+
+static struct platform_device msm_device_mdp_vg2_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 6,
+	.dev = {
+		.parent = &msm_device_smmu_mdp1.dev,
+	},
+};
+
+static struct platform_device msm_device_mdp_rgb2_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 7,
+	.dev = {
+		.parent = &msm_device_smmu_mdp1.dev,
+	},
+};
+
+static struct platform_device msm_device_rot_src_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 8,
+	.dev = {
+		.parent = &msm_device_smmu_rot.dev,
+	},
+};
+
+static struct platform_device msm_device_rot_dst_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 9,
+	.dev = {
+		.parent = &msm_device_smmu_rot.dev,
+	},
+};
+
+static struct platform_device msm_device_ijpeg_src_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 10,
+	.dev = {
+		.parent = &msm_device_smmu_ijpeg.dev,
+	},
+};
+
+static struct platform_device msm_device_ijpeg_dst_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 11,
+	.dev = {
+		.parent = &msm_device_smmu_ijpeg.dev,
+	},
+};
+
+static struct platform_device msm_device_vfe_imgwr_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 12,
+	.dev = {
+		.parent = &msm_device_smmu_vfe.dev,
+	},
+};
+
+static struct platform_device msm_device_vfe_misc_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 13,
+	.dev = {
+		.parent = &msm_device_smmu_vfe.dev,
+	},
+};
+
+static struct platform_device msm_device_vcodec_a_stream_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 14,
+	.dev = {
+		.parent = &msm_device_smmu_vcodec_a.dev,
+	},
+};
+
+static struct platform_device msm_device_vcodec_a_mm1_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 15,
+	.dev = {
+		.parent = &msm_device_smmu_vcodec_a.dev,
+	},
+};
+
+static struct platform_device msm_device_vcodec_b_mm2_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 16,
+	.dev = {
+		.parent = &msm_device_smmu_vcodec_b.dev,
+	},
+};
+
+static struct platform_device msm_device_gfx3d_rbpa_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 17,
+	.dev = {
+		.parent = &msm_device_smmu_gfx3d.dev,
+	},
+};
+
+static struct platform_device msm_device_gfx3d_cpvgttc_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 18,
+	.dev = {
+		.parent = &msm_device_smmu_gfx3d.dev,
+	},
+};
+
+static struct platform_device msm_device_gfx3d_smmu_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 19,
+	.dev = {
+		.parent = &msm_device_smmu_gfx3d.dev,
+	},
+};
+
+static struct platform_device msm_device_gfx2d0_pixv1_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 20,
+	.dev = {
+		.parent = &msm_device_smmu_gfx2d0.dev,
+	},
+};
+
+static struct platform_device msm_device_gfx2d0_texv3_ctx = {
+	.name = "msm_iommu_ctx",
+	.id = 21,
+	.dev = {
+		.parent = &msm_device_smmu_gfx2d0.dev,
+	},
+};
+
+static struct platform_device *msm_iommu_devs[] = {
+	&msm_device_smmu_jpegd,
+	&msm_device_smmu_vpe,
+	&msm_device_smmu_mdp0,
+	&msm_device_smmu_mdp1,
+	&msm_device_smmu_rot,
+	&msm_device_smmu_ijpeg,
+	&msm_device_smmu_vfe,
+	&msm_device_smmu_vcodec_a,
+	&msm_device_smmu_vcodec_b,
+	&msm_device_smmu_gfx3d,
+	&msm_device_smmu_gfx2d0,
+};
+
+static struct msm_iommu_dev *msm_iommu_data[] = {
+	&jpegd_smmu,
+	&vpe_smmu,
+	&mdp0_smmu,
+	&mdp1_smmu,
+	&rot_smmu,
+	&ijpeg_smmu,
+	&vfe_smmu,
+	&vcodec_a_smmu,
+	&vcodec_b_smmu,
+	&gfx3d_smmu,
+	&gfx2d0_smmu,
+};
+
+static struct platform_device *msm_iommu_ctx_devs[] = {
+	&msm_device_jpegd_src_ctx,
+	&msm_device_jpegd_dst_ctx,
+	&msm_device_vpe_src_ctx,
+	&msm_device_vpe_dst_ctx,
+	&msm_device_mdp_vg1_ctx,
+	&msm_device_mdp_rgb1_ctx,
+	&msm_device_mdp_vg2_ctx,
+	&msm_device_mdp_rgb2_ctx,
+	&msm_device_rot_src_ctx,
+	&msm_device_rot_dst_ctx,
+	&msm_device_ijpeg_src_ctx,
+	&msm_device_ijpeg_dst_ctx,
+	&msm_device_vfe_imgwr_ctx,
+	&msm_device_vfe_misc_ctx,
+	&msm_device_vcodec_a_stream_ctx,
+	&msm_device_vcodec_a_mm1_ctx,
+	&msm_device_vcodec_b_mm2_ctx,
+	&msm_device_gfx3d_rbpa_ctx,
+	&msm_device_gfx3d_cpvgttc_ctx,
+	&msm_device_gfx3d_smmu_ctx,
+	&msm_device_gfx2d0_pixv1_ctx,
+	&msm_device_gfx2d0_texv3_ctx,
+};
+
+static struct msm_iommu_ctx_dev *msm_iommu_ctx_data[] = {
+	&jpegd_src_ctx,
+	&jpegd_dst_ctx,
+	&vpe_src_ctx,
+	&vpe_dst_ctx,
+	&mdp_vg1_ctx,
+	&mdp_rgb1_ctx,
+	&mdp_vg2_ctx,
+	&mdp_rgb2_ctx,
+	&rot_src_ctx,
+	&rot_dst_ctx,
+	&ijpeg_src_ctx,
+	&ijpeg_dst_ctx,
+	&vfe_imgwr_ctx,
+	&vfe_misc_ctx,
+	&vcodec_a_stream_ctx,
+	&vcodec_a_mm1_ctx,
+	&vcodec_b_mm2_ctx,
+	&gfx3d_rbpa_ctx,
+	&gfx3d_cpvgttc_ctx,
+	&gfx3d_smmu_ctx,
+	&gfx2d0_pixv1_ctx,
+	&gfx2d0_texv3_ctx,
+};
+
+static int msm8x60_iommu_init(void)
+{
+	int ret, i;
+
+	ret = platform_device_register(&msm_root_iommu_dev);
+	if (ret != 0) {
+		pr_err("Failed to register root IOMMU device!\n");
+		goto failure;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); i++) {
+		ret = platform_device_add_data(msm_iommu_devs[i],
+					       msm_iommu_data[i],
+					       sizeof(struct msm_iommu_dev));
+		if (ret != 0) {
+			pr_err("platform_device_add_data failed, "
+			       "i = %d\n", i);
+			goto failure_unwind;
+		}
+
+		ret = platform_device_register(msm_iommu_devs[i]);
+
+		if (ret != 0) {
+			pr_err("platform_device_register smmu failed, "
+			       "i = %d\n", i);
+			goto failure_unwind;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++) {
+		ret = platform_device_add_data(msm_iommu_ctx_devs[i],
+					       msm_iommu_ctx_data[i],
+					       sizeof(*msm_iommu_ctx_devs[i]));
+		if (ret != 0) {
+			pr_err("platform_device_add_data smmu failed, "
+			       "i = %d\n", i);
+			goto failure_unwind2;
+		}
+
+		ret = platform_device_register(msm_iommu_ctx_devs[i]);
+		if (ret != 0) {
+			pr_err("platform_device_register ctx failed, "
+			       "i = %d\n", i);
+			goto failure_unwind2;
+		}
+	}
+	return 0;
+
+failure_unwind2:
+	while (--i >= 0)
+		platform_device_unregister(msm_iommu_ctx_devs[i]);
+failure_unwind:
+	while (--i >= 0)
+		platform_device_unregister(msm_iommu_devs[i]);
+
+	platform_device_unregister(&msm_root_iommu_dev);
+failure:
+	return ret;
+}
+
+static void msm8x60_iommu_exit(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++)
+		platform_device_unregister(msm_iommu_ctx_devs[i]);
+
+	for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); ++i)
+		platform_device_unregister(msm_iommu_devs[i]);
+
+	platform_device_unregister(&msm_root_iommu_dev);
+}
+
+subsys_initcall(msm8x60_iommu_init);
+module_exit(msm8x60_iommu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-qsd8x50.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-qsd8x50.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/devices-qsd8x50.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/devices-qsd8x50.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,6 +48,11 @@
 	.resource	= resources_uart3,
 };
 
+struct platform_device msm_device_smd = {
+	.name   = "msm_smd",
+	.id     = -1,
+};
+
 struct clk msm_clocks_8x50[] = {
 	CLK_PCOM("adm_clk",	ADM_CLK,	NULL, 0),
 	CLK_PCOM("ebi1_clk",	EBI1_CLK,	NULL, CLK_MIN),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/gpio.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -14,72 +14,363 @@
  *
  */
 
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/module.h>
-#include <mach/gpio.h>
-#include "proc_comm.h"
+#include "gpio_hw.h"
+#include "gpiomux.h"
 
-int gpio_tlmm_config(unsigned config, unsigned disable)
+#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
+
+#define MSM_GPIO_BANK(bank, first, last)				\
+	{								\
+		.regs = {						\
+			.out =         MSM_GPIO_OUT_##bank,		\
+			.in =          MSM_GPIO_IN_##bank,		\
+			.int_status =  MSM_GPIO_INT_STATUS_##bank,	\
+			.int_clear =   MSM_GPIO_INT_CLEAR_##bank,	\
+			.int_en =      MSM_GPIO_INT_EN_##bank,		\
+			.int_edge =    MSM_GPIO_INT_EDGE_##bank,	\
+			.int_pos =     MSM_GPIO_INT_POS_##bank,		\
+			.oe =          MSM_GPIO_OE_##bank,		\
+		},							\
+		.chip = {						\
+			.base = (first),				\
+			.ngpio = (last) - (first) + 1,			\
+			.get = msm_gpio_get,				\
+			.set = msm_gpio_set,				\
+			.direction_input = msm_gpio_direction_input,	\
+			.direction_output = msm_gpio_direction_output,	\
+			.to_irq = msm_gpio_to_irq,			\
+			.request = msm_gpio_request,			\
+			.free = msm_gpio_free,				\
+		}							\
+	}
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+struct msm_gpio_regs {
+	void __iomem *out;
+	void __iomem *in;
+	void __iomem *int_status;
+	void __iomem *int_clear;
+	void __iomem *int_en;
+	void __iomem *int_edge;
+	void __iomem *int_pos;
+	void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+	spinlock_t		lock;
+	struct gpio_chip	chip;
+	struct msm_gpio_regs	regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	unsigned                int_status_copy;
+#endif
+	unsigned int            both_edge_detect;
+	unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
+			  unsigned offset, unsigned on)
 {
-	return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
+	unsigned mask = BIT(offset);
+	unsigned val;
+
+	val = readl(msm_chip->regs.out);
+	if (on)
+		writel(val | mask, msm_chip->regs.out);
+	else
+		writel(val & ~mask, msm_chip->regs.out);
+	return 0;
 }
-EXPORT_SYMBOL(gpio_tlmm_config);
 
-int msm_gpios_enable(const struct msm_gpio *table, int size)
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
 {
-	int rc;
-	int i;
-	const struct msm_gpio *g;
-	for (i = 0; i < size; i++) {
-		g = table + i;
-		rc = gpio_tlmm_config(g->gpio_cfg, GPIO_ENABLE);
-		if (rc) {
-			pr_err("gpio_tlmm_config(0x%08x, GPIO_ENABLE)"
-			       " <%s> failed: %d\n",
-			       g->gpio_cfg, g->label ?: "?", rc);
-			pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
-			       GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
-			       GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
-			       GPIO_DRVSTR(g->gpio_cfg));
-			goto err;
-		}
-	}
+	int loop_limit = 100;
+	unsigned pol, val, val2, intstat;
+	do {
+		val = readl(msm_chip->regs.in);
+		pol = readl(msm_chip->regs.int_pos);
+		pol = (pol & ~msm_chip->both_edge_detect) |
+		      (~val & msm_chip->both_edge_detect);
+		writel(pol, msm_chip->regs.int_pos);
+		intstat = readl(msm_chip->regs.int_status);
+		val2 = readl(msm_chip->regs.in);
+		if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+			return;
+	} while (loop_limit-- > 0);
+	printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
+	       "failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
+					unsigned offset)
+{
+	unsigned bit = BIT(offset);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+	/* Save interrupts that already triggered before we loose them. */
+	/* Any interrupt that triggers between the read of int_status */
+	/* and the write to int_clear will still be lost though. */
+	msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+	msm_chip->int_status_copy &= ~bit;
+#endif
+	writel(bit, msm_chip->regs.int_clear);
+	msm_gpio_update_both_edge_detect(msm_chip);
 	return 0;
-err:
-	msm_gpios_disable(table, i);
-	return rc;
 }
-EXPORT_SYMBOL(msm_gpios_enable);
 
-void msm_gpios_disable(const struct msm_gpio *table, int size)
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	int rc;
-	int i;
-	const struct msm_gpio *g;
-	for (i = size-1; i >= 0; i--) {
-		g = table + i;
-		rc = gpio_tlmm_config(g->gpio_cfg, GPIO_DISABLE);
-		if (rc) {
-			pr_err("gpio_tlmm_config(0x%08x, GPIO_DISABLE)"
-			       " <%s> failed: %d\n",
-			       g->gpio_cfg, g->label ?: "?", rc);
-			pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
-			       GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
-			       GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
-			       GPIO_DRVSTR(g->gpio_cfg));
-		}
+	struct msm_gpio_chip *msm_chip;
+	unsigned long irq_flags;
+
+	msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
+}
+
+static int
+msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *msm_chip;
+	unsigned long irq_flags;
+
+	msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	msm_gpio_write(msm_chip, offset, value);
+	writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct msm_gpio_chip *msm_chip;
+
+	msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+	return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct msm_gpio_chip *msm_chip;
+	unsigned long irq_flags;
+
+	msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	msm_gpio_write(msm_chip, offset, value);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	return MSM_GPIO_TO_INT(chip->base + offset);
+}
+
+#ifdef CONFIG_MSM_GPIOMUX
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	msm_gpiomux_put(chip->base + offset);
+}
+#else
+#define msm_gpio_request NULL
+#define msm_gpio_free NULL
+#endif
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+#if defined(CONFIG_ARCH_MSM7X00A)
+	MSM_GPIO_BANK(0,   0,  15),
+	MSM_GPIO_BANK(1,  16,  42),
+	MSM_GPIO_BANK(2,  43,  67),
+	MSM_GPIO_BANK(3,  68,  94),
+	MSM_GPIO_BANK(4,  95, 106),
+	MSM_GPIO_BANK(5, 107, 121),
+#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
+	MSM_GPIO_BANK(0,   0,  15),
+	MSM_GPIO_BANK(1,  16,  42),
+	MSM_GPIO_BANK(2,  43,  67),
+	MSM_GPIO_BANK(3,  68,  94),
+	MSM_GPIO_BANK(4,  95, 106),
+	MSM_GPIO_BANK(5, 107, 132),
+#elif defined(CONFIG_ARCH_MSM7X30)
+	MSM_GPIO_BANK(0,   0,  15),
+	MSM_GPIO_BANK(1,  16,  43),
+	MSM_GPIO_BANK(2,  44,  67),
+	MSM_GPIO_BANK(3,  68,  94),
+	MSM_GPIO_BANK(4,  95, 106),
+	MSM_GPIO_BANK(5, 107, 133),
+	MSM_GPIO_BANK(6, 134, 150),
+	MSM_GPIO_BANK(7, 151, 181),
+#elif defined(CONFIG_ARCH_QSD8X50)
+	MSM_GPIO_BANK(0,   0,  15),
+	MSM_GPIO_BANK(1,  16,  42),
+	MSM_GPIO_BANK(2,  43,  67),
+	MSM_GPIO_BANK(3,  68,  94),
+	MSM_GPIO_BANK(4,  95, 103),
+	MSM_GPIO_BANK(5, 104, 121),
+	MSM_GPIO_BANK(6, 122, 152),
+	MSM_GPIO_BANK(7, 153, 164),
+#endif
+};
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	msm_gpio_clear_detect_status(msm_chip,
+				     irq - gpio_to_irq(msm_chip->chip.base));
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	/* level triggered interrupts are also latched */
+	if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+		msm_gpio_clear_detect_status(msm_chip, offset);
+	msm_chip->int_enable[0] &= ~BIT(offset);
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	/* level triggered interrupts are also latched */
+	if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+		msm_gpio_clear_detect_status(msm_chip, offset);
+	msm_chip->int_enable[0] |= BIT(offset);
+	writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+	if (on)
+		msm_chip->int_enable[1] |= BIT(offset);
+	else
+		msm_chip->int_enable[1] &= ~BIT(offset);
+
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
+}
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	unsigned long irq_flags;
+	struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+	unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+	unsigned val, mask = BIT(offset);
+
+	spin_lock_irqsave(&msm_chip->lock, irq_flags);
+	val = readl(msm_chip->regs.int_edge);
+	if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+		writel(val | mask, msm_chip->regs.int_edge);
+		irq_desc[irq].handle_irq = handle_edge_irq;
+	} else {
+		writel(val & ~mask, msm_chip->regs.int_edge);
+		irq_desc[irq].handle_irq = handle_level_irq;
 	}
+	if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+		msm_chip->both_edge_detect |= mask;
+		msm_gpio_update_both_edge_detect(msm_chip);
+	} else {
+		msm_chip->both_edge_detect &= ~mask;
+		val = readl(msm_chip->regs.int_pos);
+		if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+			writel(val | mask, msm_chip->regs.int_pos);
+		else
+			writel(val & ~mask, msm_chip->regs.int_pos);
+	}
+	spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+	return 0;
 }
-EXPORT_SYMBOL(msm_gpios_disable);
 
-int msm_gpios_request_enable(const struct msm_gpio *table, int size)
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-	int rc = msm_gpios_enable(table, size);
-	return rc;
+	int i, j, mask;
+	unsigned val;
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+		val = readl(msm_chip->regs.int_status);
+		val &= msm_chip->int_enable[0];
+		while (val) {
+			mask = val & -val;
+			j = fls(mask) - 1;
+			/* printk("%s %08x %08x bit %d gpio %d irq %d\n",
+				__func__, v, m, j, msm_chip->chip.start + j,
+				FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
+			val &= ~mask;
+			generic_handle_irq(FIRST_GPIO_IRQ +
+					   msm_chip->chip.base + j);
+		}
+	}
+	desc->chip->ack(irq);
 }
-EXPORT_SYMBOL(msm_gpios_request_enable);
 
-void msm_gpios_disable_free(const struct msm_gpio *table, int size)
+static struct irq_chip msm_gpio_irq_chip = {
+	.name      = "msmgpio",
+	.ack       = msm_gpio_irq_ack,
+	.mask      = msm_gpio_irq_mask,
+	.unmask    = msm_gpio_irq_unmask,
+	.set_wake  = msm_gpio_irq_set_wake,
+	.set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
 {
-	msm_gpios_disable(table, size);
+	int i, j = 0;
+
+	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+		if (i - FIRST_GPIO_IRQ >=
+			msm_gpio_chips[j].chip.base +
+			msm_gpio_chips[j].chip.ngpio)
+			j++;
+		set_irq_chip_data(i, &msm_gpio_chips[j]);
+		set_irq_chip(i, &msm_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		spin_lock_init(&msm_gpio_chips[i].lock);
+		writel(0, msm_gpio_chips[i].regs.int_en);
+		gpiochip_add(&msm_gpio_chips[i].chip);
+	}
+
+	set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+	set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+	set_irq_wake(INT_GPIO_GROUP1, 1);
+	set_irq_wake(INT_GPIO_GROUP2, 2);
+	return 0;
 }
-EXPORT_SYMBOL(msm_gpios_disable_free);
+
+postcore_initcall(msm_init_gpio);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpio_hw.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpio_hw.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpio_hw.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpio_hw.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,278 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#else
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X25) ||\
+    defined(CONFIG_ARCH_MSM7X27)
+
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0  */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16 */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43 */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68 */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
+
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0   */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16  */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43  */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68  */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 103-95  */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x10)  /* gpio 121-104 */
+#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0x14)  /* gpio 152-122 */
+#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x20)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x24)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x28)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x2C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x30)
+#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x50)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x54)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x58)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x5C)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0xB0)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0xB4)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0xB8)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0xBC)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xC0)
+#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xC4)
+#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0xD0)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0xD4)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0xD8)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0xDC)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xE0)
+#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xE4)
+#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xF0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xF4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xF8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xFC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0x100)
+#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0x104)
+#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x108)
+
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
+#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
+#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
+#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0xC8)
+#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
+#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0xCC)
+#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
+#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0xD0)
+#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
+#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xD4)
+#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
+#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xD8)
+#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
+#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xDC)
+#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
+#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0xE0)
+#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x234)
+
+#endif
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-7x30.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-7x30.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-7x30.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-7x30.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+	[49] = { /* UART2 RFR */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	},
+	[50] = { /* UART2 CTS */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	},
+	[51] = { /* UART2 RX */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	},
+	[52] = { /* UART2 TX */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+	},
+#endif
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-8x50.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-8x50.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-8x50.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-8x50.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,28 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+	[86] = { /* UART3 RX */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_1 | GPIOMUX_VALID,
+	},
+	[87] = { /* UART3 TX */
+		.suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+			     GPIOMUX_FUNC_1 | GPIOMUX_VALID,
+	},
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-8x60.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-8x60.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-8x60.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-8x60.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,19 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,96 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "gpiomux.h"
+
+static DEFINE_SPINLOCK(gpiomux_lock);
+
+int msm_gpiomux_write(unsigned gpio,
+		      gpiomux_config_t active,
+		      gpiomux_config_t suspended)
+{
+	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	unsigned long irq_flags;
+	gpiomux_config_t setting;
+
+	if (gpio >= GPIOMUX_NGPIOS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gpiomux_lock, irq_flags);
+
+	if (active & GPIOMUX_VALID)
+		cfg->active = active;
+
+	if (suspended & GPIOMUX_VALID)
+		cfg->suspended = suspended;
+
+	setting = cfg->ref ? active : suspended;
+	if (setting & GPIOMUX_VALID)
+		__msm_gpiomux_write(gpio, setting);
+
+	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+	return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_write);
+
+int msm_gpiomux_get(unsigned gpio)
+{
+	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	unsigned long irq_flags;
+
+	if (gpio >= GPIOMUX_NGPIOS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gpiomux_lock, irq_flags);
+	if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID)
+		__msm_gpiomux_write(gpio, cfg->active);
+	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+	return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_get);
+
+int msm_gpiomux_put(unsigned gpio)
+{
+	struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+	unsigned long irq_flags;
+
+	if (gpio >= GPIOMUX_NGPIOS)
+		return -EINVAL;
+
+	spin_lock_irqsave(&gpiomux_lock, irq_flags);
+	BUG_ON(cfg->ref == 0);
+	if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID)
+		__msm_gpiomux_write(gpio, cfg->suspended);
+	spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+	return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_put);
+
+static int __init gpiomux_init(void)
+{
+	unsigned n;
+
+	for (n = 0; n < GPIOMUX_NGPIOS; ++n) {
+		msm_gpiomux_configs[n].ref = 0;
+		if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID))
+			continue;
+		__msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended);
+	}
+	return 0;
+}
+postcore_initcall(gpiomux_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,114 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_H
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+
+#if defined(CONFIG_MSM_V2_TLMM)
+#include "gpiomux-v2.h"
+#else
+#include "gpiomux-v1.h"
+#endif
+
+/**
+ * struct msm_gpiomux_config: gpiomux settings for one gpio line.
+ *
+ * A complete gpiomux config is the bitwise-or of a drive-strength,
+ * function, and pull.  For functions other than GPIO, the OE
+ * is hard-wired according to the function.  For GPIO mode,
+ * OE is controlled by gpiolib.
+ *
+ * Available settings differ by target; see the gpiomux header
+ * specific to your target arch for available configurations.
+ *
+ * @active: The configuration to be installed when the line is
+ * active, or its reference count is > 0.
+ * @suspended: The configuration to be installed when the line
+ * is suspended, or its reference count is 0.
+ * @ref: The reference count of the line.  For internal use of
+ * the gpiomux framework only.
+ */
+struct msm_gpiomux_config {
+	gpiomux_config_t active;
+	gpiomux_config_t suspended;
+	unsigned         ref;
+};
+
+/**
+ * @GPIOMUX_VALID:	If set, the config field contains 'good data'.
+ *                      The absence of this bit will prevent the gpiomux
+ *			system from applying the configuration under all
+ *			circumstances.
+ */
+enum {
+	GPIOMUX_VALID	 = BIT(sizeof(gpiomux_config_t) * BITS_PER_BYTE - 1),
+	GPIOMUX_CTL_MASK = GPIOMUX_VALID,
+};
+
+#ifdef CONFIG_MSM_GPIOMUX
+
+/* Each architecture must provide its own instance of this table.
+ * To avoid having gpiomux manage any given gpio, one or both of
+ * the entries can avoid setting GPIOMUX_VALID - the absence
+ * of that flag will prevent the configuration from being applied
+ * during state transitions.
+ */
+extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
+
+/* Increment a gpio's reference count, possibly activating the line. */
+int __must_check msm_gpiomux_get(unsigned gpio);
+
+/* Decrement a gpio's reference count, possibly suspending the line. */
+int msm_gpiomux_put(unsigned gpio);
+
+/* Install a new configuration to the gpio line.  To avoid overwriting
+ * a configuration, leave the VALID bit out.
+ */
+int msm_gpiomux_write(unsigned gpio,
+		      gpiomux_config_t active,
+		      gpiomux_config_t suspended);
+
+/* Architecture-internal function for use by the framework only.
+ * This function can assume the following:
+ * - the gpio value has passed a bounds-check
+ * - the gpiomux spinlock has been obtained
+ *
+ * This function is not for public consumption.  External users
+ * should use msm_gpiomux_write.
+ */
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
+#else
+static inline int __must_check msm_gpiomux_get(unsigned gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_gpiomux_put(unsigned gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int msm_gpiomux_write(unsigned gpio,
+				    gpiomux_config_t active,
+				    gpiomux_config_t suspended)
+{
+	return -ENOSYS;
+}
+#endif
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v1.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v1.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v1.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,33 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/kernel.h>
+#include "gpiomux.h"
+#include "proc_comm.h"
+
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+{
+	unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) |
+				((gpio & 0x3ff) << 4);
+	unsigned tlmm_disable = 0;
+	int rc;
+
+	rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+			   &tlmm_config, &tlmm_disable);
+	if (rc)
+		pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n",
+		       __func__, rc, tlmm_config, tlmm_disable);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v1.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v1.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v1.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v1.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define GPIOMUX_NGPIOS 182
+#elif defined(CONFIG_ARCH_QSD8X50)
+#define GPIOMUX_NGPIOS 165
+#else
+#define GPIOMUX_NGPIOS 133
+#endif
+
+typedef u32 gpiomux_config_t;
+
+enum {
+	GPIOMUX_DRV_2MA  = 0UL << 17,
+	GPIOMUX_DRV_4MA  = 1UL << 17,
+	GPIOMUX_DRV_6MA  = 2UL << 17,
+	GPIOMUX_DRV_8MA  = 3UL << 17,
+	GPIOMUX_DRV_10MA = 4UL << 17,
+	GPIOMUX_DRV_12MA = 5UL << 17,
+	GPIOMUX_DRV_14MA = 6UL << 17,
+	GPIOMUX_DRV_16MA = 7UL << 17,
+};
+
+enum {
+	GPIOMUX_FUNC_GPIO = 0UL,
+	GPIOMUX_FUNC_1    = 1UL,
+	GPIOMUX_FUNC_2    = 2UL,
+	GPIOMUX_FUNC_3    = 3UL,
+	GPIOMUX_FUNC_4    = 4UL,
+	GPIOMUX_FUNC_5    = 5UL,
+	GPIOMUX_FUNC_6    = 6UL,
+	GPIOMUX_FUNC_7    = 7UL,
+	GPIOMUX_FUNC_8    = 8UL,
+	GPIOMUX_FUNC_9    = 9UL,
+	GPIOMUX_FUNC_A    = 10UL,
+	GPIOMUX_FUNC_B    = 11UL,
+	GPIOMUX_FUNC_C    = 12UL,
+	GPIOMUX_FUNC_D    = 13UL,
+	GPIOMUX_FUNC_E    = 14UL,
+	GPIOMUX_FUNC_F    = 15UL,
+};
+
+enum {
+	GPIOMUX_PULL_NONE   = 0UL << 15,
+	GPIOMUX_PULL_DOWN   = 1UL << 15,
+	GPIOMUX_PULL_KEEPER = 2UL << 15,
+	GPIOMUX_PULL_UP     = 3UL << 15,
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v2.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v2.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v2.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,25 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/io.h>
+#include <mach/msm_iomap.h>
+#include "gpiomux.h"
+
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+{
+	writel(val & ~GPIOMUX_CTL_MASK,
+	       MSM_TLMM_BASE + 0x1000 + (0x10 * gpio));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v2.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v2.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/gpiomux-v2.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/gpiomux-v2.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#ifndef __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
+
+#define GPIOMUX_NGPIOS 173
+
+typedef u16 gpiomux_config_t;
+
+enum {
+	GPIOMUX_DRV_2MA  = 0UL << 6,
+	GPIOMUX_DRV_4MA  = 1UL << 6,
+	GPIOMUX_DRV_6MA  = 2UL << 6,
+	GPIOMUX_DRV_8MA  = 3UL << 6,
+	GPIOMUX_DRV_10MA = 4UL << 6,
+	GPIOMUX_DRV_12MA = 5UL << 6,
+	GPIOMUX_DRV_14MA = 6UL << 6,
+	GPIOMUX_DRV_16MA = 7UL << 6,
+};
+
+enum {
+	GPIOMUX_FUNC_GPIO = 0UL  << 2,
+	GPIOMUX_FUNC_1    = 1UL  << 2,
+	GPIOMUX_FUNC_2    = 2UL  << 2,
+	GPIOMUX_FUNC_3    = 3UL  << 2,
+	GPIOMUX_FUNC_4    = 4UL  << 2,
+	GPIOMUX_FUNC_5    = 5UL  << 2,
+	GPIOMUX_FUNC_6    = 6UL  << 2,
+	GPIOMUX_FUNC_7    = 7UL  << 2,
+	GPIOMUX_FUNC_8    = 8UL  << 2,
+	GPIOMUX_FUNC_9    = 9UL  << 2,
+	GPIOMUX_FUNC_A    = 10UL << 2,
+	GPIOMUX_FUNC_B    = 11UL << 2,
+	GPIOMUX_FUNC_C    = 12UL << 2,
+	GPIOMUX_FUNC_D    = 13UL << 2,
+	GPIOMUX_FUNC_E    = 14UL << 2,
+	GPIOMUX_FUNC_F    = 15UL << 2,
+};
+
+enum {
+	GPIOMUX_PULL_NONE   = 0UL,
+	GPIOMUX_PULL_DOWN   = 1UL,
+	GPIOMUX_PULL_KEEPER = 2UL,
+	GPIOMUX_PULL_UP     = 3UL,
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/board.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/board.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/board.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/board.h	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,8 @@
 
 struct clk;
 
+extern struct sys_timer msm_timer;
+
 /* common init routines for use by arch/arm/mach-msm/board-*.c */
 
 void __init msm_add_devices(void);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -19,13 +19,10 @@
 #include <mach/hardware.h>
 #include <mach/msm_iomap.h>
 
-#ifdef CONFIG_MSM_DEBUG_UART
-	.macro	addruart, rx, tmp
-	@ see if the MMU is enabled and select appropriate base address
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1
-	ldreq	\rx, =MSM_DEBUG_UART_PHYS
-	ldrne	\rx, =MSM_DEBUG_UART_BASE
+#if defined(CONFIG_HAS_MSM_DEBUG_UART_PHYS) && !defined(CONFIG_MSM_DEBUG_UART_NONE)
+	.macro	addruart, rp, rv
+	ldr	\rp, =MSM_DEBUG_UART_PHYS
+	ldr	\rv, =MSM_DEBUG_UART_BASE
 	.endm
 
 	.macro	senduart,rd,rx
@@ -40,7 +37,9 @@
 	beq	1001b
 	.endm
 #else
-	.macro	addruart, rx, tmp
+	.macro  addruart, rp, rv
+	mov	\rv, #0xff000000
+	orr	\rv, \rv, #0x00f00000
 	.endm
 
 	.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,10 +32,18 @@
 	void *data;
 };
 
+#ifndef CONFIG_ARCH_MSM8X60
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
 void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
 int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
-
+#else
+static inline
+void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { }
+static inline
+void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) { }
+static inline
+int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) { return -EIO; }
+#endif
 
 
 #define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro-qgic.S linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro-qgic.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro-qgic.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,88 @@
+/*
+ * Low-level IRQ helper macros
+ *
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	ldr	\base, =gic_cpu_base_addr
+	ldr	\base, [\base]
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	/*
+	 * The interrupt numbering scheme is defined in the
+	 * interrupt controller spec.  To wit:
+	 *
+	 * Migrated the code from ARM MP port to be more consistant
+	 * with interrupt processing , the following still holds true
+	 * however, all interrupts are treated the same regardless of
+	 * if they are local IPI or PPI
+	 *
+	 * Interrupts 0-15 are IPI
+	 * 16-31 are PPI
+	 *   (16-18 are the timers)
+	 * 32-1020 are global
+	 * 1021-1022 are reserved
+	 * 1023 is "spurious" (no interrupt)
+	 *
+	 * A simple read from the controller will tell us the number of the
+	 * highest priority enabled interrupt.  We then just need to check
+	 * whether it is in the valid range for an IRQ (0-1020 inclusive).
+	 *
+	 * Base ARM code assumes that the local (private) peripheral interrupts
+	 * are not valid, we treat them differently, in that the privates are
+	 * handled like normal shared interrupts with the exception that only
+	 * one processor can register the interrupt and the handler must be
+	 * the same for all processors.
+	 */
+
+	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+	ldr  \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
+						   9-0 =int # */
+
+	bic     \irqnr, \irqstat, #0x1c00	@mask src
+	cmp     \irqnr, #15
+	ldr		\tmp, =1021
+	cmpcc	\irqnr, \irqnr
+	cmpne	\irqnr, \tmp
+	cmpcs	\irqnr, \irqnr
+
+	.endm
+
+	/* We assume that irqstat (the raw value of the IRQ acknowledge
+	 * register) is preserved from the macro above.
+	 * If there is an IPI, we immediately signal end of interrupt on the
+	 * controller, since this requires the original irqstat value which
+	 * we won't easily be able to recreate later.
+	 */
+	.macro test_for_ipi, irqnr, irqstat, base, tmp
+    bic \irqnr, \irqstat, #0x1c00
+    cmp \irqnr, #16
+    strcc   \irqstat, [\base, #GIC_CPU_EOI]
+    cmpcs   \irqnr, \irqnr
+	.endm
+
+	/* As above, this assumes that irqstat and base are preserved.. */
+
+	.macro test_for_ltirq, irqnr, irqstat, base, tmp
+    bic \irqnr, \irqstat, #0x1c00
+    mov     \tmp, #0
+    cmp \irqnr, #16
+    moveq   \tmp, #1
+    streq   \irqstat, [\base, #GIC_CPU_EOI]
+    cmp \tmp, #0
+	.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -1,38 +1,23 @@
-/* arch/arm/mach-msm7200/include/mach/entry-macro.S
- *
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
  *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
  */
 
-#include <mach/msm_iomap.h>
-
- 	.macro	disable_fiq
-	.endm
-
-	.macro	get_irqnr_preamble, base, tmp
-	@ enable imprecise aborts
-	cpsie	a
-	mov	\base, #MSM_VIC_BASE
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
-
-	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	@ 0xD0 has irq# or old irq# if the irq has been handled
-	@ 0xD4 has irq# or -1 if none pending *but* if you just
-	@ read 0xD4 you never get the first irq for some reason
-	ldr	\irqnr, [\base, #0xD0]
-	ldr	\irqnr, [\base, #0xD4]
-	cmp	\irqnr, #0xffffffff
-	.endm
+#if defined(CONFIG_ARM_GIC)
+#include <mach/entry-macro-qgic.S>
+#else
+#include <mach/entry-macro-vic.S>
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro-vic.S linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro-vic.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/entry-macro-vic.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/entry-macro-vic.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <mach/msm_iomap.h>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro	get_irqnr_preamble, base, tmp
+	@ enable imprecise aborts
+	cpsie	a
+	mov	\base, #MSM_VIC_BASE
+	.endm
+
+	.macro	arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	@ 0xD0 has irq# or old irq# if the irq has been handled
+	@ 0xD4 has irq# or -1 if none pending *but* if you just
+	@ read 0xD4 you never get the first irq for some reason
+	ldr	\irqnr, [\base, #0xD0]
+	ldr	\irqnr, [\base, #0xD4]
+	cmp	\irqnr, #0xffffffff
+	.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,127 +23,4 @@
 #define gpio_cansleep   __gpio_cansleep
 #define gpio_to_irq     __gpio_to_irq
 
-/**
- * struct msm_gpio - GPIO pin description
- * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
- * @label - textual label
- *
- * Usually, GPIO's are operated by sets.
- * This struct accumulate all GPIO information in single source
- * and facilitete group operations provided by msm_gpios_xxx()
- */
-struct msm_gpio {
-	u32 gpio_cfg;
-	const char *label;
-};
-
-/**
- * msm_gpios_request_enable() - request and enable set of GPIOs
- *
- * Request and configure set of GPIO's
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_request_enable(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_disable_free() - disable and free set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_disable_free(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_request() - request set of GPIOs
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_request(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_free() - free set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_free(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_enable() - enable set of GPIOs
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_enable(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_disable() - disable set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_disable(const struct msm_gpio *table, int size);
-
-/* GPIO TLMM (Top Level Multiplexing) Definitions */
-
-/* GPIO TLMM: Function -- GPIO specific */
-
-/* GPIO TLMM: Direction */
-enum {
-	GPIO_INPUT,
-	GPIO_OUTPUT,
-};
-
-/* GPIO TLMM: Pullup/Pulldown */
-enum {
-	GPIO_NO_PULL,
-	GPIO_PULL_DOWN,
-	GPIO_KEEPER,
-	GPIO_PULL_UP,
-};
-
-/* GPIO TLMM: Drive Strength */
-enum {
-	GPIO_2MA,
-	GPIO_4MA,
-	GPIO_6MA,
-	GPIO_8MA,
-	GPIO_10MA,
-	GPIO_12MA,
-	GPIO_14MA,
-	GPIO_16MA,
-};
-
-enum {
-	GPIO_ENABLE,
-	GPIO_DISABLE,
-};
-
-#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
-	((((gpio) & 0x3FF) << 4)        |	  \
-	 ((func) & 0xf)                  |	  \
-	 (((dir) & 0x1) << 14)           |	  \
-	 (((pull) & 0x3) << 15)          |	  \
-	 (((drvstr) & 0xF) << 17))
-
-/**
- * extract GPIO pin from bit-field used for gpio_tlmm_config
- */
-#define GPIO_PIN(gpio_cfg)    (((gpio_cfg) >>  4) & 0x3ff)
-#define GPIO_FUNC(gpio_cfg)   (((gpio_cfg) >>  0) & 0xf)
-#define GPIO_DIR(gpio_cfg)    (((gpio_cfg) >> 14) & 0x1)
-#define GPIO_PULL(gpio_cfg)   (((gpio_cfg) >> 15) & 0x3)
-#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
-
-int gpio_tlmm_config(unsigned config, unsigned disable);
-
 #endif /* __ASM_ARCH_MSM_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/io.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/io.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 
 void msm_map_qsd8x50_io(void);
 void msm_map_msm7x30_io(void);
+void msm_map_msm8x60_io(void);
 
 extern unsigned int msm_shared_ram_phys;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/iommu.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/iommu.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/iommu.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/iommu.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,103 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef MSM_IOMMU_H
+#define MSM_IOMMU_H
+
+#include <linux/interrupt.h>
+
+/* Maximum number of Machine IDs that we are allowing to be mapped to the same
+ * context bank. The number of MIDs mapped to the same CB does not affect
+ * performance, but there is a practical limit on how many distinct MIDs may
+ * be present. These mappings are typically determined at design time and are
+ * not expected to change at run time.
+ */
+#define MAX_NUM_MIDS	16
+
+/**
+ * struct msm_iommu_dev - a single IOMMU hardware instance
+ * name		Human-readable name given to this IOMMU HW instance
+ * clk_rate	Rate to set for this IOMMU's clock, if applicable to this
+ *		particular IOMMU. 0 means don't set a rate.
+ *		-1 means it is an AXI clock with no valid rate
+ *
+ */
+struct msm_iommu_dev {
+	const char *name;
+	int clk_rate;
+};
+
+/**
+ * struct msm_iommu_ctx_dev - an IOMMU context bank instance
+ * name		Human-readable name given to this context bank
+ * num		Index of this context bank within the hardware
+ * mids		List of Machine IDs that are to be mapped into this context
+ *		bank, terminated by -1. The MID is a set of signals on the
+ *		AXI bus that identifies the function associated with a specific
+ *		memory request. (See ARM spec).
+ */
+struct msm_iommu_ctx_dev {
+	const char *name;
+	int num;
+	int mids[MAX_NUM_MIDS];
+};
+
+
+/**
+ * struct msm_iommu_drvdata - A single IOMMU hardware instance
+ * @base:	IOMMU config port base address (VA)
+ * @irq:	Interrupt number
+  *
+ * A msm_iommu_drvdata holds the global driver data about a single piece
+ * of an IOMMU hardware instance.
+ */
+struct msm_iommu_drvdata {
+	void __iomem *base;
+	int irq;
+};
+
+/**
+ * struct msm_iommu_ctx_drvdata - an IOMMU context bank instance
+ * @num:		Hardware context number of this context
+ * @pdev:		Platform device associated wit this HW instance
+ * @attached_elm:	List element for domains to track which devices are
+ *			attached to them
+ *
+ * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
+ * within each IOMMU hardware instance
+ */
+struct msm_iommu_ctx_drvdata {
+	int num;
+	struct platform_device *pdev;
+	struct list_head attached_elm;
+};
+
+/*
+ * Look up an IOMMU context device by its context name. NULL if none found.
+ * Useful for testing and drivers that do not yet fully have IOMMU stuff in
+ * their platform devices.
+ */
+struct device *msm_iommu_get_ctx(const char *ctx_name);
+
+/*
+ * Interrupt handler for the IOMMU context fault interrupt. Hooking the
+ * interrupt is not supported in the API yet, but this will print an error
+ * message and dump useful IOMMU registers.
+ */
+irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1871 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_IOMMU_HW_8XXX_H
+#define __ARCH_ARM_MACH_MSM_IOMMU_HW_8XXX_H
+
+#define CTX_SHIFT 12
+
+#define GET_GLOBAL_REG(reg, base) (readl((base) + (reg)))
+#define GET_CTX_REG(reg, base, ctx) \
+				(readl((base) + (reg) + ((ctx) << CTX_SHIFT)))
+
+#define SET_GLOBAL_REG(reg, base, val)	writel((val), ((base) + (reg)))
+
+#define SET_CTX_REG(reg, base, ctx, val) \
+			writel((val), ((base) + (reg) + ((ctx) << CTX_SHIFT)))
+
+/* Wrappers for numbered registers */
+#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG(b, ((r) + (n << 2)), (v))
+#define GET_GLOBAL_REG_N(b, n, r)    GET_GLOBAL_REG(b, ((r) + (n << 2)))
+
+/* Field wrappers */
+#define GET_GLOBAL_FIELD(b, r, F)    GET_FIELD(((b) + (r)), F##_MASK, F##_SHIFT)
+#define GET_CONTEXT_FIELD(b, c, r, F)	\
+	GET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), F##_MASK, F##_SHIFT)
+
+#define SET_GLOBAL_FIELD(b, r, F, v) \
+	SET_FIELD(((b) + (r)), F##_MASK, F##_SHIFT, (v))
+#define SET_CONTEXT_FIELD(b, c, r, F, v)	\
+	SET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), F##_MASK, F##_SHIFT, (v))
+
+#define GET_FIELD(addr, mask, shift)  ((readl(addr) >> (shift)) & (mask))
+
+#define SET_FIELD(addr, mask, shift, v) \
+do { \
+	int t = readl(addr); \
+	writel((t & ~((mask) << (shift))) + (((v) & (mask)) << (shift)), addr);\
+} while (0)
+
+
+#define NUM_FL_PTE	4096
+#define NUM_SL_PTE	256
+
+/* First-level page table bits */
+#define FL_BASE_MASK		0xFFFFFC00
+#define FL_TYPE_TABLE		(1 << 0)
+#define FL_TYPE_SECT		(2 << 0)
+#define FL_SUPERSECTION		(1 << 18)
+#define FL_AP_WRITE		(1 << 10)
+#define FL_AP_READ		(1 << 11)
+#define FL_SHARED		(1 << 16)
+#define FL_OFFSET(va)		(((va) & 0xFFF00000) >> 20)
+
+/* Second-level page table bits */
+#define SL_BASE_MASK_LARGE	0xFFFF0000
+#define SL_BASE_MASK_SMALL	0xFFFFF000
+#define SL_TYPE_LARGE		(1 << 0)
+#define SL_TYPE_SMALL		(2 << 0)
+#define SL_AP0			(1 << 4)
+#define SL_AP1			(2 << 4)
+#define SL_SHARED		(1 << 10)
+#define SL_OFFSET(va)		(((va) & 0xFF000) >> 12)
+
+/* Global register setters / getters */
+#define SET_M2VCBR_N(b, N, v)	 SET_GLOBAL_REG_N(M2VCBR_N, N, (b), (v))
+#define SET_CBACR_N(b, N, v)	 SET_GLOBAL_REG_N(CBACR_N, N, (b), (v))
+#define SET_TLBRSW(b, v)	 SET_GLOBAL_REG(TLBRSW, (b), (v))
+#define SET_TLBTR0(b, v)	 SET_GLOBAL_REG(TLBTR0, (b), (v))
+#define SET_TLBTR1(b, v)	 SET_GLOBAL_REG(TLBTR1, (b), (v))
+#define SET_TLBTR2(b, v)	 SET_GLOBAL_REG(TLBTR2, (b), (v))
+#define SET_TESTBUSCR(b, v)	 SET_GLOBAL_REG(TESTBUSCR, (b), (v))
+#define SET_GLOBAL_TLBIALL(b, v) SET_GLOBAL_REG(GLOBAL_TLBIALL, (b), (v))
+#define SET_TLBIVMID(b, v)	 SET_GLOBAL_REG(TLBIVMID, (b), (v))
+#define SET_CR(b, v)		 SET_GLOBAL_REG(CR, (b), (v))
+#define SET_EAR(b, v)		 SET_GLOBAL_REG(EAR, (b), (v))
+#define SET_ESR(b, v)		 SET_GLOBAL_REG(ESR, (b), (v))
+#define SET_ESRRESTORE(b, v)	 SET_GLOBAL_REG(ESRRESTORE, (b), (v))
+#define SET_ESYNR0(b, v)	 SET_GLOBAL_REG(ESYNR0, (b), (v))
+#define SET_ESYNR1(b, v)	 SET_GLOBAL_REG(ESYNR1, (b), (v))
+#define SET_RPU_ACR(b, v)	 SET_GLOBAL_REG(RPU_ACR, (b), (v))
+
+#define GET_M2VCBR_N(b, N)	 GET_GLOBAL_REG_N(M2VCBR_N, N, (b))
+#define GET_CBACR_N(b, N)	 GET_GLOBAL_REG_N(CBACR_N, N, (b))
+#define GET_TLBTR0(b)		 GET_GLOBAL_REG(TLBTR0, (b))
+#define GET_TLBTR1(b)		 GET_GLOBAL_REG(TLBTR1, (b))
+#define GET_TLBTR2(b)		 GET_GLOBAL_REG(TLBTR2, (b))
+#define GET_TESTBUSCR(b)	 GET_GLOBAL_REG(TESTBUSCR, (b))
+#define GET_GLOBAL_TLBIALL(b)	 GET_GLOBAL_REG(GLOBAL_TLBIALL, (b))
+#define GET_TLBIVMID(b)		 GET_GLOBAL_REG(TLBIVMID, (b))
+#define GET_CR(b)		 GET_GLOBAL_REG(CR, (b))
+#define GET_EAR(b)		 GET_GLOBAL_REG(EAR, (b))
+#define GET_ESR(b)		 GET_GLOBAL_REG(ESR, (b))
+#define GET_ESRRESTORE(b)	 GET_GLOBAL_REG(ESRRESTORE, (b))
+#define GET_ESYNR0(b)		 GET_GLOBAL_REG(ESYNR0, (b))
+#define GET_ESYNR1(b)		 GET_GLOBAL_REG(ESYNR1, (b))
+#define GET_REV(b)		 GET_GLOBAL_REG(REV, (b))
+#define GET_IDR(b)		 GET_GLOBAL_REG(IDR, (b))
+#define GET_RPU_ACR(b)		 GET_GLOBAL_REG(RPU_ACR, (b))
+
+
+/* Context register setters/getters */
+#define SET_SCTLR(b, c, v)	 SET_CTX_REG(SCTLR, (b), (c), (v))
+#define SET_ACTLR(b, c, v)	 SET_CTX_REG(ACTLR, (b), (c), (v))
+#define SET_CONTEXTIDR(b, c, v)	 SET_CTX_REG(CONTEXTIDR, (b), (c), (v))
+#define SET_TTBR0(b, c, v)	 SET_CTX_REG(TTBR0, (b), (c), (v))
+#define SET_TTBR1(b, c, v)	 SET_CTX_REG(TTBR1, (b), (c), (v))
+#define SET_TTBCR(b, c, v)	 SET_CTX_REG(TTBCR, (b), (c), (v))
+#define SET_PAR(b, c, v)	 SET_CTX_REG(PAR, (b), (c), (v))
+#define SET_FSR(b, c, v)	 SET_CTX_REG(FSR, (b), (c), (v))
+#define SET_FSRRESTORE(b, c, v)	 SET_CTX_REG(FSRRESTORE, (b), (c), (v))
+#define SET_FAR(b, c, v)	 SET_CTX_REG(FAR, (b), (c), (v))
+#define SET_FSYNR0(b, c, v)	 SET_CTX_REG(FSYNR0, (b), (c), (v))
+#define SET_FSYNR1(b, c, v)	 SET_CTX_REG(FSYNR1, (b), (c), (v))
+#define SET_PRRR(b, c, v)	 SET_CTX_REG(PRRR, (b), (c), (v))
+#define SET_NMRR(b, c, v)	 SET_CTX_REG(NMRR, (b), (c), (v))
+#define SET_TLBLKCR(b, c, v)	 SET_CTX_REG(TLBLCKR, (b), (c), (v))
+#define SET_V2PSR(b, c, v)	 SET_CTX_REG(V2PSR, (b), (c), (v))
+#define SET_TLBFLPTER(b, c, v)	 SET_CTX_REG(TLBFLPTER, (b), (c), (v))
+#define SET_TLBSLPTER(b, c, v)	 SET_CTX_REG(TLBSLPTER, (b), (c), (v))
+#define SET_BFBCR(b, c, v)	 SET_CTX_REG(BFBCR, (b), (c), (v))
+#define SET_CTX_TLBIALL(b, c, v) SET_CTX_REG(CTX_TLBIALL, (b), (c), (v))
+#define SET_TLBIASID(b, c, v)	 SET_CTX_REG(TLBIASID, (b), (c), (v))
+#define SET_TLBIVA(b, c, v)	 SET_CTX_REG(TLBIVA, (b), (c), (v))
+#define SET_TLBIVAA(b, c, v)	 SET_CTX_REG(TLBIVAA, (b), (c), (v))
+#define SET_V2PPR(b, c, v)	 SET_CTX_REG(V2PPR, (b), (c), (v))
+#define SET_V2PPW(b, c, v)	 SET_CTX_REG(V2PPW, (b), (c), (v))
+#define SET_V2PUR(b, c, v)	 SET_CTX_REG(V2PUR, (b), (c), (v))
+#define SET_V2PUW(b, c, v)	 SET_CTX_REG(V2PUW, (b), (c), (v))
+#define SET_RESUME(b, c, v)	 SET_CTX_REG(RESUME, (b), (c), (v))
+
+#define GET_SCTLR(b, c)		 GET_CTX_REG(SCTLR, (b), (c))
+#define GET_ACTLR(b, c)		 GET_CTX_REG(ACTLR, (b), (c))
+#define GET_CONTEXTIDR(b, c)	 GET_CTX_REG(CONTEXTIDR, (b), (c))
+#define GET_TTBR0(b, c)		 GET_CTX_REG(TTBR0, (b), (c))
+#define GET_TTBR1(b, c)		 GET_CTX_REG(TTBR1, (b), (c))
+#define GET_TTBCR(b, c)		 GET_CTX_REG(TTBCR, (b), (c))
+#define GET_PAR(b, c)		 GET_CTX_REG(PAR, (b), (c))
+#define GET_FSR(b, c)		 GET_CTX_REG(FSR, (b), (c))
+#define GET_FSRRESTORE(b, c)	 GET_CTX_REG(FSRRESTORE, (b), (c))
+#define GET_FAR(b, c)		 GET_CTX_REG(FAR, (b), (c))
+#define GET_FSYNR0(b, c)	 GET_CTX_REG(FSYNR0, (b), (c))
+#define GET_FSYNR1(b, c)	 GET_CTX_REG(FSYNR1, (b), (c))
+#define GET_PRRR(b, c)		 GET_CTX_REG(PRRR, (b), (c))
+#define GET_NMRR(b, c)		 GET_CTX_REG(NMRR, (b), (c))
+#define GET_TLBLCKR(b, c)	 GET_CTX_REG(TLBLCKR, (b), (c))
+#define GET_V2PSR(b, c)		 GET_CTX_REG(V2PSR, (b), (c))
+#define GET_TLBFLPTER(b, c)	 GET_CTX_REG(TLBFLPTER, (b), (c))
+#define GET_TLBSLPTER(b, c)	 GET_CTX_REG(TLBSLPTER, (b), (c))
+#define GET_BFBCR(b, c)		 GET_CTX_REG(BFBCR, (b), (c))
+#define GET_CTX_TLBIALL(b, c)	 GET_CTX_REG(CTX_TLBIALL, (b), (c))
+#define GET_TLBIASID(b, c)	 GET_CTX_REG(TLBIASID, (b), (c))
+#define GET_TLBIVA(b, c)	 GET_CTX_REG(TLBIVA, (b), (c))
+#define GET_TLBIVAA(b, c)	 GET_CTX_REG(TLBIVAA, (b), (c))
+#define GET_V2PPR(b, c)		 GET_CTX_REG(V2PPR, (b), (c))
+#define GET_V2PPW(b, c)		 GET_CTX_REG(V2PPW, (b), (c))
+#define GET_V2PUR(b, c)		 GET_CTX_REG(V2PUR, (b), (c))
+#define GET_V2PUW(b, c)		 GET_CTX_REG(V2PUW, (b), (c))
+#define GET_RESUME(b, c)	 GET_CTX_REG(RESUME, (b), (c))
+
+
+/* Global field setters / getters */
+/* Global Field Setters: */
+/* CBACR_N */
+#define SET_RWVMID(b, n, v)   SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWVMID, v)
+#define SET_RWE(b, n, v)      SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWE, v)
+#define SET_RWGE(b, n, v)     SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWGE, v)
+#define SET_CBVMID(b, n, v)   SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), CBVMID, v)
+#define SET_IRPTNDX(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), IRPTNDX, v)
+
+
+/* M2VCBR_N */
+#define SET_VMID(b, n, v)     SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), VMID, v)
+#define SET_CBNDX(b, n, v)    SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), CBNDX, v)
+#define SET_BYPASSD(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BYPASSD, v)
+#define SET_BPRCOSH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCOSH, v)
+#define SET_BPRCISH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCISH, v)
+#define SET_BPRCNSH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCNSH, v)
+#define SET_BPSHCFG(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPSHCFG, v)
+#define SET_NSCFG(b, n, v)    SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), NSCFG, v)
+#define SET_BPMTCFG(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMTCFG, v)
+#define SET_BPMEMTYPE(b, n, v) \
+	SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMEMTYPE, v)
+
+
+/* CR */
+#define SET_RPUE(b, v)		 SET_GLOBAL_FIELD(b, CR, RPUE, v)
+#define SET_RPUERE(b, v)	 SET_GLOBAL_FIELD(b, CR, RPUERE, v)
+#define SET_RPUEIE(b, v)	 SET_GLOBAL_FIELD(b, CR, RPUEIE, v)
+#define SET_DCDEE(b, v)		 SET_GLOBAL_FIELD(b, CR, DCDEE, v)
+#define SET_CLIENTPD(b, v)       SET_GLOBAL_FIELD(b, CR, CLIENTPD, v)
+#define SET_STALLD(b, v)	 SET_GLOBAL_FIELD(b, CR, STALLD, v)
+#define SET_TLBLKCRWE(b, v)      SET_GLOBAL_FIELD(b, CR, TLBLKCRWE, v)
+#define SET_CR_TLBIALLCFG(b, v)  SET_GLOBAL_FIELD(b, CR, CR_TLBIALLCFG, v)
+#define SET_TLBIVMIDCFG(b, v)    SET_GLOBAL_FIELD(b, CR, TLBIVMIDCFG, v)
+#define SET_CR_HUME(b, v)        SET_GLOBAL_FIELD(b, CR, CR_HUME, v)
+
+
+/* ESR */
+#define SET_CFG(b, v)		 SET_GLOBAL_FIELD(b, ESR, CFG, v)
+#define SET_BYPASS(b, v)	 SET_GLOBAL_FIELD(b, ESR, BYPASS, v)
+#define SET_ESR_MULTI(b, v)      SET_GLOBAL_FIELD(b, ESR, ESR_MULTI, v)
+
+
+/* ESYNR0 */
+#define SET_ESYNR0_AMID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AMID, v)
+#define SET_ESYNR0_APID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_APID, v)
+#define SET_ESYNR0_ABID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ABID, v)
+#define SET_ESYNR0_AVMID(b, v)   SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AVMID, v)
+#define SET_ESYNR0_ATID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ATID, v)
+
+
+/* ESYNR1 */
+#define SET_ESYNR1_AMEMTYPE(b, v) \
+			SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AMEMTYPE, v)
+#define SET_ESYNR1_ASHARED(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASHARED, v)
+#define SET_ESYNR1_AINNERSHARED(b, v) \
+			SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINNERSHARED, v)
+#define SET_ESYNR1_APRIV(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APRIV, v)
+#define SET_ESYNR1_APROTNS(b, v) SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APROTNS, v)
+#define SET_ESYNR1_AINST(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINST, v)
+#define SET_ESYNR1_AWRITE(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AWRITE, v)
+#define SET_ESYNR1_ABURST(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ABURST, v)
+#define SET_ESYNR1_ALEN(b, v)    SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALEN, v)
+#define SET_ESYNR1_ASIZE(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASIZE, v)
+#define SET_ESYNR1_ALOCK(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALOCK, v)
+#define SET_ESYNR1_AOOO(b, v)    SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AOOO, v)
+#define SET_ESYNR1_AFULL(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AFULL, v)
+#define SET_ESYNR1_AC(b, v)      SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AC, v)
+#define SET_ESYNR1_DCD(b, v)     SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_DCD, v)
+
+
+/* TESTBUSCR */
+#define SET_TBE(b, v)		 SET_GLOBAL_FIELD(b, TESTBUSCR, TBE, v)
+#define SET_SPDMBE(b, v)	 SET_GLOBAL_FIELD(b, TESTBUSCR, SPDMBE, v)
+#define SET_WGSEL(b, v)		 SET_GLOBAL_FIELD(b, TESTBUSCR, WGSEL, v)
+#define SET_TBLSEL(b, v)	 SET_GLOBAL_FIELD(b, TESTBUSCR, TBLSEL, v)
+#define SET_TBHSEL(b, v)	 SET_GLOBAL_FIELD(b, TESTBUSCR, TBHSEL, v)
+#define SET_SPDM0SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM0SEL, v)
+#define SET_SPDM1SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM1SEL, v)
+#define SET_SPDM2SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM2SEL, v)
+#define SET_SPDM3SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM3SEL, v)
+
+
+/* TLBIVMID */
+#define SET_TLBIVMID_VMID(b, v)  SET_GLOBAL_FIELD(b, TLBIVMID, TLBIVMID_VMID, v)
+
+
+/* TLBRSW */
+#define SET_TLBRSW_INDEX(b, v)   SET_GLOBAL_FIELD(b, TLBRSW, TLBRSW_INDEX, v)
+#define SET_TLBBFBS(b, v)	 SET_GLOBAL_FIELD(b, TLBRSW, TLBBFBS, v)
+
+
+/* TLBTR0 */
+#define SET_PR(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, PR, v)
+#define SET_PW(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, PW, v)
+#define SET_UR(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, UR, v)
+#define SET_UW(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, UW, v)
+#define SET_XN(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, XN, v)
+#define SET_NSDESC(b, v)	 SET_GLOBAL_FIELD(b, TLBTR0, NSDESC, v)
+#define SET_ISH(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, ISH, v)
+#define SET_SH(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, SH, v)
+#define SET_MT(b, v)		 SET_GLOBAL_FIELD(b, TLBTR0, MT, v)
+#define SET_DPSIZR(b, v)	 SET_GLOBAL_FIELD(b, TLBTR0, DPSIZR, v)
+#define SET_DPSIZC(b, v)	 SET_GLOBAL_FIELD(b, TLBTR0, DPSIZC, v)
+
+
+/* TLBTR1 */
+#define SET_TLBTR1_VMID(b, v)    SET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_VMID, v)
+#define SET_TLBTR1_PA(b, v)      SET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_PA, v)
+
+
+/* TLBTR2 */
+#define SET_TLBTR2_ASID(b, v)    SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_ASID, v)
+#define SET_TLBTR2_V(b, v)       SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_V, v)
+#define SET_TLBTR2_NSTID(b, v)   SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NSTID, v)
+#define SET_TLBTR2_NV(b, v)      SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NV, v)
+#define SET_TLBTR2_VA(b, v)      SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_VA, v)
+
+
+/* Global Field Getters */
+/* CBACR_N */
+#define GET_RWVMID(b, n)	 GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWVMID)
+#define GET_RWE(b, n)		 GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWE)
+#define GET_RWGE(b, n)		 GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWGE)
+#define GET_CBVMID(b, n)	 GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), CBVMID)
+#define GET_IRPTNDX(b, n)	 GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), IRPTNDX)
+
+
+/* M2VCBR_N */
+#define GET_VMID(b, n)       GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), VMID)
+#define GET_CBNDX(b, n)      GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), CBNDX)
+#define GET_BYPASSD(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BYPASSD)
+#define GET_BPRCOSH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCOSH)
+#define GET_BPRCISH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCISH)
+#define GET_BPRCNSH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCNSH)
+#define GET_BPSHCFG(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPSHCFG)
+#define GET_NSCFG(b, n)      GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), NSCFG)
+#define GET_BPMTCFG(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMTCFG)
+#define GET_BPMEMTYPE(b, n)  GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMEMTYPE)
+
+
+/* CR */
+#define GET_RPUE(b)		 GET_GLOBAL_FIELD(b, CR, RPUE)
+#define GET_RPUERE(b)		 GET_GLOBAL_FIELD(b, CR, RPUERE)
+#define GET_RPUEIE(b)		 GET_GLOBAL_FIELD(b, CR, RPUEIE)
+#define GET_DCDEE(b)		 GET_GLOBAL_FIELD(b, CR, DCDEE)
+#define GET_CLIENTPD(b)		 GET_GLOBAL_FIELD(b, CR, CLIENTPD)
+#define GET_STALLD(b)		 GET_GLOBAL_FIELD(b, CR, STALLD)
+#define GET_TLBLKCRWE(b)	 GET_GLOBAL_FIELD(b, CR, TLBLKCRWE)
+#define GET_CR_TLBIALLCFG(b)	 GET_GLOBAL_FIELD(b, CR, CR_TLBIALLCFG)
+#define GET_TLBIVMIDCFG(b)	 GET_GLOBAL_FIELD(b, CR, TLBIVMIDCFG)
+#define GET_CR_HUME(b)		 GET_GLOBAL_FIELD(b, CR, CR_HUME)
+
+
+/* ESR */
+#define GET_CFG(b)		 GET_GLOBAL_FIELD(b, ESR, CFG)
+#define GET_BYPASS(b)		 GET_GLOBAL_FIELD(b, ESR, BYPASS)
+#define GET_ESR_MULTI(b)	 GET_GLOBAL_FIELD(b, ESR, ESR_MULTI)
+
+
+/* ESYNR0 */
+#define GET_ESYNR0_AMID(b)	 GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AMID)
+#define GET_ESYNR0_APID(b)	 GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_APID)
+#define GET_ESYNR0_ABID(b)	 GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ABID)
+#define GET_ESYNR0_AVMID(b)	 GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AVMID)
+#define GET_ESYNR0_ATID(b)	 GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ATID)
+
+
+/* ESYNR1 */
+#define GET_ESYNR1_AMEMTYPE(b)   GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AMEMTYPE)
+#define GET_ESYNR1_ASHARED(b)    GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASHARED)
+#define GET_ESYNR1_AINNERSHARED(b) \
+			GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINNERSHARED)
+#define GET_ESYNR1_APRIV(b)      GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APRIV)
+#define GET_ESYNR1_APROTNS(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APROTNS)
+#define GET_ESYNR1_AINST(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINST)
+#define GET_ESYNR1_AWRITE(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AWRITE)
+#define GET_ESYNR1_ABURST(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ABURST)
+#define GET_ESYNR1_ALEN(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALEN)
+#define GET_ESYNR1_ASIZE(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASIZE)
+#define GET_ESYNR1_ALOCK(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALOCK)
+#define GET_ESYNR1_AOOO(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AOOO)
+#define GET_ESYNR1_AFULL(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AFULL)
+#define GET_ESYNR1_AC(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AC)
+#define GET_ESYNR1_DCD(b)	 GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_DCD)
+
+
+/* IDR */
+#define GET_NM2VCBMT(b)		 GET_GLOBAL_FIELD(b, IDR, NM2VCBMT)
+#define GET_HTW(b)		 GET_GLOBAL_FIELD(b, IDR, HTW)
+#define GET_HUM(b)		 GET_GLOBAL_FIELD(b, IDR, HUM)
+#define GET_TLBSIZE(b)		 GET_GLOBAL_FIELD(b, IDR, TLBSIZE)
+#define GET_NCB(b)		 GET_GLOBAL_FIELD(b, IDR, NCB)
+#define GET_NIRPT(b)		 GET_GLOBAL_FIELD(b, IDR, NIRPT)
+
+
+/* REV */
+#define GET_MAJOR(b)		 GET_GLOBAL_FIELD(b, REV, MAJOR)
+#define GET_MINOR(b)		 GET_GLOBAL_FIELD(b, REV, MINOR)
+
+
+/* TESTBUSCR */
+#define GET_TBE(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, TBE)
+#define GET_SPDMBE(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDMBE)
+#define GET_WGSEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, WGSEL)
+#define GET_TBLSEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, TBLSEL)
+#define GET_TBHSEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, TBHSEL)
+#define GET_SPDM0SEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM0SEL)
+#define GET_SPDM1SEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM1SEL)
+#define GET_SPDM2SEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM2SEL)
+#define GET_SPDM3SEL(b)		 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM3SEL)
+
+
+/* TLBIVMID */
+#define GET_TLBIVMID_VMID(b)	 GET_GLOBAL_FIELD(b, TLBIVMID, TLBIVMID_VMID)
+
+
+/* TLBTR0 */
+#define GET_PR(b)		 GET_GLOBAL_FIELD(b, TLBTR0, PR)
+#define GET_PW(b)		 GET_GLOBAL_FIELD(b, TLBTR0, PW)
+#define GET_UR(b)		 GET_GLOBAL_FIELD(b, TLBTR0, UR)
+#define GET_UW(b)		 GET_GLOBAL_FIELD(b, TLBTR0, UW)
+#define GET_XN(b)		 GET_GLOBAL_FIELD(b, TLBTR0, XN)
+#define GET_NSDESC(b)		 GET_GLOBAL_FIELD(b, TLBTR0, NSDESC)
+#define GET_ISH(b)		 GET_GLOBAL_FIELD(b, TLBTR0, ISH)
+#define GET_SH(b)		 GET_GLOBAL_FIELD(b, TLBTR0, SH)
+#define GET_MT(b)		 GET_GLOBAL_FIELD(b, TLBTR0, MT)
+#define GET_DPSIZR(b)		 GET_GLOBAL_FIELD(b, TLBTR0, DPSIZR)
+#define GET_DPSIZC(b)		 GET_GLOBAL_FIELD(b, TLBTR0, DPSIZC)
+
+
+/* TLBTR1 */
+#define GET_TLBTR1_VMID(b)	 GET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_VMID)
+#define GET_TLBTR1_PA(b)	 GET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_PA)
+
+
+/* TLBTR2 */
+#define GET_TLBTR2_ASID(b)	 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_ASID)
+#define GET_TLBTR2_V(b)		 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_V)
+#define GET_TLBTR2_NSTID(b)	 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NSTID)
+#define GET_TLBTR2_NV(b)	 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NV)
+#define GET_TLBTR2_VA(b)	 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_VA)
+
+
+/* Context Register setters / getters */
+/* Context Register setters */
+/* ACTLR */
+#define SET_CFERE(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, CFERE, v)
+#define SET_CFEIE(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, CFEIE, v)
+#define SET_PTSHCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, PTSHCFG, v)
+#define SET_RCOSH(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, RCOSH, v)
+#define SET_RCISH(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, RCISH, v)
+#define SET_RCNSH(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, RCNSH, v)
+#define SET_PRIVCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, PRIVCFG, v)
+#define SET_DNA(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, DNA, v)
+#define SET_DNLV2PA(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, DNLV2PA, v)
+#define SET_TLBMCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, TLBMCFG, v)
+#define SET_CFCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, CFCFG, v)
+#define SET_TIPCF(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, TIPCF, v)
+#define SET_V2PCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, V2PCFG, v)
+#define SET_HUME(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, HUME, v)
+#define SET_PTMTCFG(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, PTMTCFG, v)
+#define SET_PTMEMTYPE(b, c, v)	 SET_CONTEXT_FIELD(b, c, ACTLR, PTMEMTYPE, v)
+
+
+/* BFBCR */
+#define SET_BFBDFE(b, c, v)	 SET_CONTEXT_FIELD(b, c, BFBCR, BFBDFE, v)
+#define SET_BFBSFE(b, c, v)	 SET_CONTEXT_FIELD(b, c, BFBCR, BFBSFE, v)
+#define SET_SFVS(b, c, v)	 SET_CONTEXT_FIELD(b, c, BFBCR, SFVS, v)
+#define SET_FLVIC(b, c, v)	 SET_CONTEXT_FIELD(b, c, BFBCR, FLVIC, v)
+#define SET_SLVIC(b, c, v)	 SET_CONTEXT_FIELD(b, c, BFBCR, SLVIC, v)
+
+
+/* CONTEXTIDR */
+#define SET_CONTEXTIDR_ASID(b, c, v)   \
+		SET_CONTEXT_FIELD(b, c, CONTEXTIDR, CONTEXTIDR_ASID, v)
+#define SET_CONTEXTIDR_PROCID(b, c, v) \
+		SET_CONTEXT_FIELD(b, c, CONTEXTIDR, PROCID, v)
+
+
+/* FSR */
+#define SET_TF(b, c, v)		 SET_CONTEXT_FIELD(b, c, FSR, TF, v)
+#define SET_AFF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, AFF, v)
+#define SET_APF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, APF, v)
+#define SET_TLBMF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, TLBMF, v)
+#define SET_HTWDEEF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, HTWDEEF, v)
+#define SET_HTWSEEF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, HTWSEEF, v)
+#define SET_MHF(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, MHF, v)
+#define SET_SL(b, c, v)		 SET_CONTEXT_FIELD(b, c, FSR, SL, v)
+#define SET_SS(b, c, v)		 SET_CONTEXT_FIELD(b, c, FSR, SS, v)
+#define SET_MULTI(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSR, MULTI, v)
+
+
+/* FSYNR0 */
+#define SET_AMID(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR0, AMID, v)
+#define SET_APID(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR0, APID, v)
+#define SET_ABID(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR0, ABID, v)
+#define SET_ATID(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR0, ATID, v)
+
+
+/* FSYNR1 */
+#define SET_AMEMTYPE(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, AMEMTYPE, v)
+#define SET_ASHARED(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, ASHARED, v)
+#define SET_AINNERSHARED(b, c, v)  \
+				SET_CONTEXT_FIELD(b, c, FSYNR1, AINNERSHARED, v)
+#define SET_APRIV(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, APRIV, v)
+#define SET_APROTNS(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, APROTNS, v)
+#define SET_AINST(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, AINST, v)
+#define SET_AWRITE(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, AWRITE, v)
+#define SET_ABURST(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, ABURST, v)
+#define SET_ALEN(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, ALEN, v)
+#define SET_FSYNR1_ASIZE(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, FSYNR1, FSYNR1_ASIZE, v)
+#define SET_ALOCK(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, ALOCK, v)
+#define SET_AFULL(b, c, v)	 SET_CONTEXT_FIELD(b, c, FSYNR1, AFULL, v)
+
+
+/* NMRR */
+#define SET_ICPC0(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC0, v)
+#define SET_ICPC1(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC1, v)
+#define SET_ICPC2(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC2, v)
+#define SET_ICPC3(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC3, v)
+#define SET_ICPC4(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC4, v)
+#define SET_ICPC5(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC5, v)
+#define SET_ICPC6(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC6, v)
+#define SET_ICPC7(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, ICPC7, v)
+#define SET_OCPC0(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC0, v)
+#define SET_OCPC1(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC1, v)
+#define SET_OCPC2(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC2, v)
+#define SET_OCPC3(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC3, v)
+#define SET_OCPC4(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC4, v)
+#define SET_OCPC5(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC5, v)
+#define SET_OCPC6(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC6, v)
+#define SET_OCPC7(b, c, v)	 SET_CONTEXT_FIELD(b, c, NMRR, OCPC7, v)
+
+
+/* PAR */
+#define SET_FAULT(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT, v)
+
+#define SET_FAULT_TF(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_TF, v)
+#define SET_FAULT_AFF(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_AFF, v)
+#define SET_FAULT_APF(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_APF, v)
+#define SET_FAULT_TLBMF(b, c, v) SET_CONTEXT_FIELD(b, c, PAR, FAULT_TLBMF, v)
+#define SET_FAULT_HTWDEEF(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWDEEF, v)
+#define SET_FAULT_HTWSEEF(b, c, v) \
+				SET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWSEEF, v)
+#define SET_FAULT_MHF(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_MHF, v)
+#define SET_FAULT_SL(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_SL, v)
+#define SET_FAULT_SS(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, FAULT_SS, v)
+
+#define SET_NOFAULT_SS(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_SS, v)
+#define SET_NOFAULT_MT(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_MT, v)
+#define SET_NOFAULT_SH(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_SH, v)
+#define SET_NOFAULT_NS(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_NS, v)
+#define SET_NOFAULT_NOS(b, c, v) SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_NOS, v)
+#define SET_NPFAULT_PA(b, c, v)	 SET_CONTEXT_FIELD(b, c, PAR, NPFAULT_PA, v)
+
+
+/* PRRR */
+#define SET_MTC0(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC0, v)
+#define SET_MTC1(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC1, v)
+#define SET_MTC2(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC2, v)
+#define SET_MTC3(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC3, v)
+#define SET_MTC4(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC4, v)
+#define SET_MTC5(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC5, v)
+#define SET_MTC6(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC6, v)
+#define SET_MTC7(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, MTC7, v)
+#define SET_SHDSH0(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, SHDSH0, v)
+#define SET_SHDSH1(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, SHDSH1, v)
+#define SET_SHNMSH0(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, SHNMSH0, v)
+#define SET_SHNMSH1(b, c, v)     SET_CONTEXT_FIELD(b, c, PRRR, SHNMSH1, v)
+#define SET_NOS0(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS0, v)
+#define SET_NOS1(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS1, v)
+#define SET_NOS2(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS2, v)
+#define SET_NOS3(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS3, v)
+#define SET_NOS4(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS4, v)
+#define SET_NOS5(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS5, v)
+#define SET_NOS6(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS6, v)
+#define SET_NOS7(b, c, v)	 SET_CONTEXT_FIELD(b, c, PRRR, NOS7, v)
+
+
+/* RESUME */
+#define SET_TNR(b, c, v)	 SET_CONTEXT_FIELD(b, c, RESUME, TNR, v)
+
+
+/* SCTLR */
+#define SET_M(b, c, v)		 SET_CONTEXT_FIELD(b, c, SCTLR, M, v)
+#define SET_TRE(b, c, v)	 SET_CONTEXT_FIELD(b, c, SCTLR, TRE, v)
+#define SET_AFE(b, c, v)	 SET_CONTEXT_FIELD(b, c, SCTLR, AFE, v)
+#define SET_HAF(b, c, v)	 SET_CONTEXT_FIELD(b, c, SCTLR, HAF, v)
+#define SET_BE(b, c, v)		 SET_CONTEXT_FIELD(b, c, SCTLR, BE, v)
+#define SET_AFFD(b, c, v)	 SET_CONTEXT_FIELD(b, c, SCTLR, AFFD, v)
+
+
+/* TLBLKCR */
+#define SET_LKE(b, c, v)	   SET_CONTEXT_FIELD(b, c, TLBLKCR, LKE, v)
+#define SET_TLBLKCR_TLBIALLCFG(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBLCKR_TLBIALLCFG, v)
+#define SET_TLBIASIDCFG(b, c, v) \
+			SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIASIDCFG, v)
+#define SET_TLBIVAACFG(b, c, v)	SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIVAACFG, v)
+#define SET_FLOOR(b, c, v)	SET_CONTEXT_FIELD(b, c, TLBLKCR, FLOOR, v)
+#define SET_VICTIM(b, c, v)	SET_CONTEXT_FIELD(b, c, TLBLKCR, VICTIM, v)
+
+
+/* TTBCR */
+#define SET_N(b, c, v)	         SET_CONTEXT_FIELD(b, c, TTBCR, N, v)
+#define SET_PD0(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBCR, PD0, v)
+#define SET_PD1(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBCR, PD1, v)
+
+
+/* TTBR0 */
+#define SET_TTBR0_IRGNH(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNH, v)
+#define SET_TTBR0_SH(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_SH, v)
+#define SET_TTBR0_ORGN(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_ORGN, v)
+#define SET_TTBR0_NOS(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_NOS, v)
+#define SET_TTBR0_IRGNL(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNL, v)
+#define SET_TTBR0_PA(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_PA, v)
+
+
+/* TTBR1 */
+#define SET_TTBR1_IRGNH(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNH, v)
+#define SET_TTBR1_SH(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_SH, v)
+#define SET_TTBR1_ORGN(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_ORGN, v)
+#define SET_TTBR1_NOS(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_NOS, v)
+#define SET_TTBR1_IRGNL(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNL, v)
+#define SET_TTBR1_PA(b, c, v)	 SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_PA, v)
+
+
+/* V2PSR */
+#define SET_HIT(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PSR, HIT, v)
+#define SET_INDEX(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PSR, INDEX, v)
+
+
+/* V2Pxx UW UR PW PR */
+#define SET_V2PUW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX, v)
+#define SET_V2PUW_VA(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA, v)
+
+#define SET_V2PUR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX, v)
+#define SET_V2PUR_VA(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA, v)
+
+#define SET_V2PPW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX, v)
+#define SET_V2PPW_VA(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA, v)
+
+#define SET_V2PPR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX, v)
+#define SET_V2PPR_VA(b, c, v)	 SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA, v)
+
+
+/* Context Register getters */
+/* ACTLR */
+#define GET_CFERE(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, CFERE)
+#define GET_CFEIE(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, CFEIE)
+#define GET_PTSHCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PTSHCFG)
+#define GET_RCOSH(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, RCOSH)
+#define GET_RCISH(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, RCISH)
+#define GET_RCNSH(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, RCNSH)
+#define GET_PRIVCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PRIVCFG)
+#define GET_DNA(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, DNA)
+#define GET_DNLV2PA(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, DNLV2PA)
+#define GET_TLBMCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, TLBMCFG)
+#define GET_CFCFG(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, CFCFG)
+#define GET_TIPCF(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, TIPCF)
+#define GET_V2PCFG(b, c)        GET_CONTEXT_FIELD(b, c, ACTLR, V2PCFG)
+#define GET_HUME(b, c)	        GET_CONTEXT_FIELD(b, c, ACTLR, HUME)
+#define GET_PTMTCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PTMTCFG)
+#define GET_PTMEMTYPE(b, c)     GET_CONTEXT_FIELD(b, c, ACTLR, PTMEMTYPE)
+
+/* BFBCR */
+#define GET_BFBDFE(b, c)	GET_CONTEXT_FIELD(b, c, BFBCR, BFBDFE)
+#define GET_BFBSFE(b, c)	GET_CONTEXT_FIELD(b, c, BFBCR, BFBSFE)
+#define GET_SFVS(b, c)		GET_CONTEXT_FIELD(b, c, BFBCR, SFVS)
+#define GET_FLVIC(b, c)		GET_CONTEXT_FIELD(b, c, BFBCR, FLVIC)
+#define GET_SLVIC(b, c)		GET_CONTEXT_FIELD(b, c, BFBCR, SLVIC)
+
+
+/* CONTEXTIDR */
+#define GET_CONTEXTIDR_ASID(b, c) \
+			GET_CONTEXT_FIELD(b, c, CONTEXTIDR, CONTEXTIDR_ASID)
+#define GET_CONTEXTIDR_PROCID(b, c) GET_CONTEXT_FIELD(b, c, CONTEXTIDR, PROCID)
+
+
+/* FSR */
+#define GET_TF(b, c)		GET_CONTEXT_FIELD(b, c, FSR, TF)
+#define GET_AFF(b, c)		GET_CONTEXT_FIELD(b, c, FSR, AFF)
+#define GET_APF(b, c)		GET_CONTEXT_FIELD(b, c, FSR, APF)
+#define GET_TLBMF(b, c)		GET_CONTEXT_FIELD(b, c, FSR, TLBMF)
+#define GET_HTWDEEF(b, c)	GET_CONTEXT_FIELD(b, c, FSR, HTWDEEF)
+#define GET_HTWSEEF(b, c)	GET_CONTEXT_FIELD(b, c, FSR, HTWSEEF)
+#define GET_MHF(b, c)		GET_CONTEXT_FIELD(b, c, FSR, MHF)
+#define GET_SL(b, c)		GET_CONTEXT_FIELD(b, c, FSR, SL)
+#define GET_SS(b, c)		GET_CONTEXT_FIELD(b, c, FSR, SS)
+#define GET_MULTI(b, c)		GET_CONTEXT_FIELD(b, c, FSR, MULTI)
+
+
+/* FSYNR0 */
+#define GET_AMID(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR0, AMID)
+#define GET_APID(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR0, APID)
+#define GET_ABID(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR0, ABID)
+#define GET_ATID(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR0, ATID)
+
+
+/* FSYNR1 */
+#define GET_AMEMTYPE(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, AMEMTYPE)
+#define GET_ASHARED(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, ASHARED)
+#define GET_AINNERSHARED(b, c)  GET_CONTEXT_FIELD(b, c, FSYNR1, AINNERSHARED)
+#define GET_APRIV(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR1, APRIV)
+#define GET_APROTNS(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, APROTNS)
+#define GET_AINST(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR1, AINST)
+#define GET_AWRITE(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, AWRITE)
+#define GET_ABURST(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, ABURST)
+#define GET_ALEN(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR1, ALEN)
+#define GET_FSYNR1_ASIZE(b, c)	GET_CONTEXT_FIELD(b, c, FSYNR1, FSYNR1_ASIZE)
+#define GET_ALOCK(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR1, ALOCK)
+#define GET_AFULL(b, c)		GET_CONTEXT_FIELD(b, c, FSYNR1, AFULL)
+
+
+/* NMRR */
+#define GET_ICPC0(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC0)
+#define GET_ICPC1(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC1)
+#define GET_ICPC2(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC2)
+#define GET_ICPC3(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC3)
+#define GET_ICPC4(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC4)
+#define GET_ICPC5(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC5)
+#define GET_ICPC6(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC6)
+#define GET_ICPC7(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, ICPC7)
+#define GET_OCPC0(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC0)
+#define GET_OCPC1(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC1)
+#define GET_OCPC2(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC2)
+#define GET_OCPC3(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC3)
+#define GET_OCPC4(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC4)
+#define GET_OCPC5(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC5)
+#define GET_OCPC6(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC6)
+#define GET_OCPC7(b, c)		GET_CONTEXT_FIELD(b, c, NMRR, OCPC7)
+
+
+/* PAR */
+#define GET_FAULT(b, c)		GET_CONTEXT_FIELD(b, c, PAR, FAULT)
+
+#define GET_FAULT_TF(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_TF)
+#define GET_FAULT_AFF(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_AFF)
+#define GET_FAULT_APF(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_APF)
+#define GET_FAULT_TLBMF(b, c)   GET_CONTEXT_FIELD(b, c, PAR, FAULT_TLBMF)
+#define GET_FAULT_HTWDEEF(b, c) GET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWDEEF)
+#define GET_FAULT_HTWSEEF(b, c) GET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWSEEF)
+#define GET_FAULT_MHF(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_MHF)
+#define GET_FAULT_SL(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_SL)
+#define GET_FAULT_SS(b, c)	GET_CONTEXT_FIELD(b, c, PAR, FAULT_SS)
+
+#define GET_NOFAULT_SS(b, c)	GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_SS)
+#define GET_NOFAULT_MT(b, c)	GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_MT)
+#define GET_NOFAULT_SH(b, c)	GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_SH)
+#define GET_NOFAULT_NS(b, c)	GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_NS)
+#define GET_NOFAULT_NOS(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_NOS)
+#define GET_NPFAULT_PA(b, c)	GET_CONTEXT_FIELD(b, c, PAR, PAR_NPFAULT_PA)
+
+
+/* PRRR */
+#define GET_MTC0(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC0)
+#define GET_MTC1(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC1)
+#define GET_MTC2(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC2)
+#define GET_MTC3(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC3)
+#define GET_MTC4(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC4)
+#define GET_MTC5(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC5)
+#define GET_MTC6(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC6)
+#define GET_MTC7(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, MTC7)
+#define GET_SHDSH0(b, c)	GET_CONTEXT_FIELD(b, c, PRRR, SHDSH0)
+#define GET_SHDSH1(b, c)	GET_CONTEXT_FIELD(b, c, PRRR, SHDSH1)
+#define GET_SHNMSH0(b, c)	GET_CONTEXT_FIELD(b, c, PRRR, SHNMSH0)
+#define GET_SHNMSH1(b, c)	GET_CONTEXT_FIELD(b, c, PRRR, SHNMSH1)
+#define GET_NOS0(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS0)
+#define GET_NOS1(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS1)
+#define GET_NOS2(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS2)
+#define GET_NOS3(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS3)
+#define GET_NOS4(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS4)
+#define GET_NOS5(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS5)
+#define GET_NOS6(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS6)
+#define GET_NOS7(b, c)		GET_CONTEXT_FIELD(b, c, PRRR, NOS7)
+
+
+/* RESUME */
+#define GET_TNR(b, c)		GET_CONTEXT_FIELD(b, c, RESUME, TNR)
+
+
+/* SCTLR */
+#define GET_M(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, M)
+#define GET_TRE(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, TRE)
+#define GET_AFE(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, AFE)
+#define GET_HAF(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, HAF)
+#define GET_BE(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, BE)
+#define GET_AFFD(b, c)		GET_CONTEXT_FIELD(b, c, SCTLR, AFFD)
+
+
+/* TLBLKCR */
+#define GET_LKE(b, c)		GET_CONTEXT_FIELD(b, c, TLBLKCR, LKE)
+#define GET_TLBLCKR_TLBIALLCFG(b, c) \
+			GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBLCKR_TLBIALLCFG)
+#define GET_TLBIASIDCFG(b, c)   GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIASIDCFG)
+#define GET_TLBIVAACFG(b, c)	GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIVAACFG)
+#define GET_FLOOR(b, c)		GET_CONTEXT_FIELD(b, c, TLBLKCR, FLOOR)
+#define GET_VICTIM(b, c)	GET_CONTEXT_FIELD(b, c, TLBLKCR, VICTIM)
+
+
+/* TTBCR */
+#define GET_N(b, c)		GET_CONTEXT_FIELD(b, c, TTBCR, N)
+#define GET_PD0(b, c)		GET_CONTEXT_FIELD(b, c, TTBCR, PD0)
+#define GET_PD1(b, c)		GET_CONTEXT_FIELD(b, c, TTBCR, PD1)
+
+
+/* TTBR0 */
+#define GET_TTBR0_IRGNH(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNH)
+#define GET_TTBR0_SH(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_SH)
+#define GET_TTBR0_ORGN(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_ORGN)
+#define GET_TTBR0_NOS(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_NOS)
+#define GET_TTBR0_IRGNL(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNL)
+#define GET_TTBR0_PA(b, c)	GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_PA)
+
+
+/* TTBR1 */
+#define GET_TTBR1_IRGNH(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNH)
+#define GET_TTBR1_SH(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_SH)
+#define GET_TTBR1_ORGN(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_ORGN)
+#define GET_TTBR1_NOS(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_NOS)
+#define GET_TTBR1_IRGNL(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNL)
+#define GET_TTBR1_PA(b, c)	GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_PA)
+
+
+/* V2PSR */
+#define GET_HIT(b, c)		GET_CONTEXT_FIELD(b, c, V2PSR, HIT)
+#define GET_INDEX(b, c)		GET_CONTEXT_FIELD(b, c, V2PSR, INDEX)
+
+
+/* V2Pxx UW UR PW PR */
+#define GET_V2PUW_INDEX(b, c)	GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX)
+#define GET_V2PUW_VA(b, c)	GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA)
+
+#define GET_V2PUR_INDEX(b, c)	GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX)
+#define GET_V2PUR_VA(b, c)	GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA)
+
+#define GET_V2PPW_INDEX(b, c)	GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX)
+#define GET_V2PPW_VA(b, c)	GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA)
+
+#define GET_V2PPR_INDEX(b, c)	GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX)
+#define GET_V2PPR_VA(b, c)	GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA)
+
+
+/* Global Registers */
+#define M2VCBR_N	(0xFF000)
+#define CBACR_N		(0xFF800)
+#define TLBRSW		(0xFFE00)
+#define TLBTR0		(0xFFE80)
+#define TLBTR1		(0xFFE84)
+#define TLBTR2		(0xFFE88)
+#define TESTBUSCR	(0xFFE8C)
+#define GLOBAL_TLBIALL	(0xFFF00)
+#define TLBIVMID	(0xFFF04)
+#define CR		(0xFFF80)
+#define EAR		(0xFFF84)
+#define ESR		(0xFFF88)
+#define ESRRESTORE	(0xFFF8C)
+#define ESYNR0		(0xFFF90)
+#define ESYNR1		(0xFFF94)
+#define REV		(0xFFFF4)
+#define IDR		(0xFFFF8)
+#define RPU_ACR		(0xFFFFC)
+
+
+/* Context Bank Registers */
+#define SCTLR		(0x000)
+#define ACTLR		(0x004)
+#define CONTEXTIDR	(0x008)
+#define TTBR0		(0x010)
+#define TTBR1		(0x014)
+#define TTBCR		(0x018)
+#define PAR		(0x01C)
+#define FSR		(0x020)
+#define FSRRESTORE	(0x024)
+#define FAR		(0x028)
+#define FSYNR0		(0x02C)
+#define FSYNR1		(0x030)
+#define PRRR		(0x034)
+#define NMRR		(0x038)
+#define TLBLCKR		(0x03C)
+#define V2PSR		(0x040)
+#define TLBFLPTER	(0x044)
+#define TLBSLPTER	(0x048)
+#define BFBCR		(0x04C)
+#define CTX_TLBIALL	(0x800)
+#define TLBIASID	(0x804)
+#define TLBIVA		(0x808)
+#define TLBIVAA		(0x80C)
+#define V2PPR		(0x810)
+#define V2PPW		(0x814)
+#define V2PUR		(0x818)
+#define V2PUW		(0x81C)
+#define RESUME		(0x820)
+
+
+/* Global Register Fields */
+/* CBACRn */
+#define RWVMID        (RWVMID_MASK       << RWVMID_SHIFT)
+#define RWE           (RWE_MASK          << RWE_SHIFT)
+#define RWGE          (RWGE_MASK         << RWGE_SHIFT)
+#define CBVMID        (CBVMID_MASK       << CBVMID_SHIFT)
+#define IRPTNDX       (IRPTNDX_MASK      << IRPTNDX_SHIFT)
+
+
+/* CR */
+#define RPUE          (RPUE_MASK          << RPUE_SHIFT)
+#define RPUERE        (RPUERE_MASK        << RPUERE_SHIFT)
+#define RPUEIE        (RPUEIE_MASK        << RPUEIE_SHIFT)
+#define DCDEE         (DCDEE_MASK         << DCDEE_SHIFT)
+#define CLIENTPD      (CLIENTPD_MASK      << CLIENTPD_SHIFT)
+#define STALLD        (STALLD_MASK        << STALLD_SHIFT)
+#define TLBLKCRWE     (TLBLKCRWE_MASK     << TLBLKCRWE_SHIFT)
+#define CR_TLBIALLCFG (CR_TLBIALLCFG_MASK << CR_TLBIALLCFG_SHIFT)
+#define TLBIVMIDCFG   (TLBIVMIDCFG_MASK   << TLBIVMIDCFG_SHIFT)
+#define CR_HUME       (CR_HUME_MASK       << CR_HUME_SHIFT)
+
+
+/* ESR */
+#define CFG           (CFG_MASK          << CFG_SHIFT)
+#define BYPASS        (BYPASS_MASK       << BYPASS_SHIFT)
+#define ESR_MULTI     (ESR_MULTI_MASK    << ESR_MULTI_SHIFT)
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID   (ESYNR0_AMID_MASK  << ESYNR0_AMID_SHIFT)
+#define ESYNR0_APID   (ESYNR0_APID_MASK  << ESYNR0_APID_SHIFT)
+#define ESYNR0_ABID   (ESYNR0_ABID_MASK  << ESYNR0_ABID_SHIFT)
+#define ESYNR0_AVMID  (ESYNR0_AVMID_MASK << ESYNR0_AVMID_SHIFT)
+#define ESYNR0_ATID   (ESYNR0_ATID_MASK  << ESYNR0_ATID_SHIFT)
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE      (ESYNR1_AMEMTYPE_MASK    << ESYNR1_AMEMTYPE_SHIFT)
+#define ESYNR1_ASHARED       (ESYNR1_ASHARED_MASK     << ESYNR1_ASHARED_SHIFT)
+#define ESYNR1_AINNERSHARED  (ESYNR1_AINNERSHARED_MASK<< \
+						ESYNR1_AINNERSHARED_SHIFT)
+#define ESYNR1_APRIV         (ESYNR1_APRIV_MASK       << ESYNR1_APRIV_SHIFT)
+#define ESYNR1_APROTNS       (ESYNR1_APROTNS_MASK     << ESYNR1_APROTNS_SHIFT)
+#define ESYNR1_AINST         (ESYNR1_AINST_MASK       << ESYNR1_AINST_SHIFT)
+#define ESYNR1_AWRITE        (ESYNR1_AWRITE_MASK      << ESYNR1_AWRITE_SHIFT)
+#define ESYNR1_ABURST        (ESYNR1_ABURST_MASK      << ESYNR1_ABURST_SHIFT)
+#define ESYNR1_ALEN          (ESYNR1_ALEN_MASK        << ESYNR1_ALEN_SHIFT)
+#define ESYNR1_ASIZE         (ESYNR1_ASIZE_MASK       << ESYNR1_ASIZE_SHIFT)
+#define ESYNR1_ALOCK         (ESYNR1_ALOCK_MASK       << ESYNR1_ALOCK_SHIFT)
+#define ESYNR1_AOOO          (ESYNR1_AOOO_MASK        << ESYNR1_AOOO_SHIFT)
+#define ESYNR1_AFULL         (ESYNR1_AFULL_MASK       << ESYNR1_AFULL_SHIFT)
+#define ESYNR1_AC            (ESYNR1_AC_MASK          << ESYNR1_AC_SHIFT)
+#define ESYNR1_DCD           (ESYNR1_DCD_MASK         << ESYNR1_DCD_SHIFT)
+
+
+/* IDR */
+#define NM2VCBMT      (NM2VCBMT_MASK     << NM2VCBMT_SHIFT)
+#define HTW           (HTW_MASK          << HTW_SHIFT)
+#define HUM           (HUM_MASK          << HUM_SHIFT)
+#define TLBSIZE       (TLBSIZE_MASK      << TLBSIZE_SHIFT)
+#define NCB           (NCB_MASK          << NCB_SHIFT)
+#define NIRPT         (NIRPT_MASK        << NIRPT_SHIFT)
+
+
+/* M2VCBRn */
+#define VMID          (VMID_MASK         << VMID_SHIFT)
+#define CBNDX         (CBNDX_MASK        << CBNDX_SHIFT)
+#define BYPASSD       (BYPASSD_MASK      << BYPASSD_SHIFT)
+#define BPRCOSH       (BPRCOSH_MASK      << BPRCOSH_SHIFT)
+#define BPRCISH       (BPRCISH_MASK      << BPRCISH_SHIFT)
+#define BPRCNSH       (BPRCNSH_MASK      << BPRCNSH_SHIFT)
+#define BPSHCFG       (BPSHCFG_MASK      << BPSHCFG_SHIFT)
+#define NSCFG         (NSCFG_MASK        << NSCFG_SHIFT)
+#define BPMTCFG       (BPMTCFG_MASK      << BPMTCFG_SHIFT)
+#define BPMEMTYPE     (BPMEMTYPE_MASK    << BPMEMTYPE_SHIFT)
+
+
+/* REV */
+#define IDR_MINOR     (MINOR_MASK        << MINOR_SHIFT)
+#define IDR_MAJOR     (MAJOR_MASK        << MAJOR_SHIFT)
+
+
+/* TESTBUSCR */
+#define TBE           (TBE_MASK          << TBE_SHIFT)
+#define SPDMBE        (SPDMBE_MASK       << SPDMBE_SHIFT)
+#define WGSEL         (WGSEL_MASK        << WGSEL_SHIFT)
+#define TBLSEL        (TBLSEL_MASK       << TBLSEL_SHIFT)
+#define TBHSEL        (TBHSEL_MASK       << TBHSEL_SHIFT)
+#define SPDM0SEL      (SPDM0SEL_MASK     << SPDM0SEL_SHIFT)
+#define SPDM1SEL      (SPDM1SEL_MASK     << SPDM1SEL_SHIFT)
+#define SPDM2SEL      (SPDM2SEL_MASK     << SPDM2SEL_SHIFT)
+#define SPDM3SEL      (SPDM3SEL_MASK     << SPDM3SEL_SHIFT)
+
+
+/* TLBIVMID */
+#define TLBIVMID_VMID (TLBIVMID_VMID_MASK << TLBIVMID_VMID_SHIFT)
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX  (TLBRSW_INDEX_MASK << TLBRSW_INDEX_SHIFT)
+#define TLBBFBS       (TLBBFBS_MASK      << TLBBFBS_SHIFT)
+
+
+/* TLBTR0 */
+#define PR            (PR_MASK           << PR_SHIFT)
+#define PW            (PW_MASK           << PW_SHIFT)
+#define UR            (UR_MASK           << UR_SHIFT)
+#define UW            (UW_MASK           << UW_SHIFT)
+#define XN            (XN_MASK           << XN_SHIFT)
+#define NSDESC        (NSDESC_MASK       << NSDESC_SHIFT)
+#define ISH           (ISH_MASK          << ISH_SHIFT)
+#define SH            (SH_MASK           << SH_SHIFT)
+#define MT            (MT_MASK           << MT_SHIFT)
+#define DPSIZR        (DPSIZR_MASK       << DPSIZR_SHIFT)
+#define DPSIZC        (DPSIZC_MASK       << DPSIZC_SHIFT)
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID   (TLBTR1_VMID_MASK  << TLBTR1_VMID_SHIFT)
+#define TLBTR1_PA     (TLBTR1_PA_MASK    << TLBTR1_PA_SHIFT)
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID   (TLBTR2_ASID_MASK  << TLBTR2_ASID_SHIFT)
+#define TLBTR2_V      (TLBTR2_V_MASK     << TLBTR2_V_SHIFT)
+#define TLBTR2_NSTID  (TLBTR2_NSTID_MASK << TLBTR2_NSTID_SHIFT)
+#define TLBTR2_NV     (TLBTR2_NV_MASK    << TLBTR2_NV_SHIFT)
+#define TLBTR2_VA     (TLBTR2_VA_MASK    << TLBTR2_VA_SHIFT)
+
+
+/* Context Register Fields */
+/* ACTLR */
+#define CFERE              (CFERE_MASK              << CFERE_SHIFT)
+#define CFEIE              (CFEIE_MASK              << CFEIE_SHIFT)
+#define PTSHCFG            (PTSHCFG_MASK            << PTSHCFG_SHIFT)
+#define RCOSH              (RCOSH_MASK              << RCOSH_SHIFT)
+#define RCISH              (RCISH_MASK              << RCISH_SHIFT)
+#define RCNSH              (RCNSH_MASK              << RCNSH_SHIFT)
+#define PRIVCFG            (PRIVCFG_MASK            << PRIVCFG_SHIFT)
+#define DNA                (DNA_MASK                << DNA_SHIFT)
+#define DNLV2PA            (DNLV2PA_MASK            << DNLV2PA_SHIFT)
+#define TLBMCFG            (TLBMCFG_MASK            << TLBMCFG_SHIFT)
+#define CFCFG              (CFCFG_MASK              << CFCFG_SHIFT)
+#define TIPCF              (TIPCF_MASK              << TIPCF_SHIFT)
+#define V2PCFG             (V2PCFG_MASK             << V2PCFG_SHIFT)
+#define HUME               (HUME_MASK               << HUME_SHIFT)
+#define PTMTCFG            (PTMTCFG_MASK            << PTMTCFG_SHIFT)
+#define PTMEMTYPE          (PTMEMTYPE_MASK          << PTMEMTYPE_SHIFT)
+
+
+/* BFBCR */
+#define BFBDFE             (BFBDFE_MASK             << BFBDFE_SHIFT)
+#define BFBSFE             (BFBSFE_MASK             << BFBSFE_SHIFT)
+#define SFVS               (SFVS_MASK               << SFVS_SHIFT)
+#define FLVIC              (FLVIC_MASK              << FLVIC_SHIFT)
+#define SLVIC              (SLVIC_MASK              << SLVIC_SHIFT)
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID    (CONTEXTIDR_ASID_MASK    << CONTEXTIDR_ASID_SHIFT)
+#define PROCID             (PROCID_MASK             << PROCID_SHIFT)
+
+
+/* FSR */
+#define TF                 (TF_MASK                 << TF_SHIFT)
+#define AFF                (AFF_MASK                << AFF_SHIFT)
+#define APF                (APF_MASK                << APF_SHIFT)
+#define TLBMF              (TLBMF_MASK              << TLBMF_SHIFT)
+#define HTWDEEF            (HTWDEEF_MASK            << HTWDEEF_SHIFT)
+#define HTWSEEF            (HTWSEEF_MASK            << HTWSEEF_SHIFT)
+#define MHF                (MHF_MASK                << MHF_SHIFT)
+#define SL                 (SL_MASK                 << SL_SHIFT)
+#define SS                 (SS_MASK                 << SS_SHIFT)
+#define MULTI              (MULTI_MASK              << MULTI_SHIFT)
+
+
+/* FSYNR0 */
+#define AMID               (AMID_MASK               << AMID_SHIFT)
+#define APID               (APID_MASK               << APID_SHIFT)
+#define ABID               (ABID_MASK               << ABID_SHIFT)
+#define ATID               (ATID_MASK               << ATID_SHIFT)
+
+
+/* FSYNR1 */
+#define AMEMTYPE           (AMEMTYPE_MASK           << AMEMTYPE_SHIFT)
+#define ASHARED            (ASHARED_MASK            << ASHARED_SHIFT)
+#define AINNERSHARED       (AINNERSHARED_MASK       << AINNERSHARED_SHIFT)
+#define APRIV              (APRIV_MASK              << APRIV_SHIFT)
+#define APROTNS            (APROTNS_MASK            << APROTNS_SHIFT)
+#define AINST              (AINST_MASK              << AINST_SHIFT)
+#define AWRITE             (AWRITE_MASK             << AWRITE_SHIFT)
+#define ABURST             (ABURST_MASK             << ABURST_SHIFT)
+#define ALEN               (ALEN_MASK               << ALEN_SHIFT)
+#define FSYNR1_ASIZE       (FSYNR1_ASIZE_MASK       << FSYNR1_ASIZE_SHIFT)
+#define ALOCK              (ALOCK_MASK              << ALOCK_SHIFT)
+#define AFULL              (AFULL_MASK              << AFULL_SHIFT)
+
+
+/* NMRR */
+#define ICPC0              (ICPC0_MASK              << ICPC0_SHIFT)
+#define ICPC1              (ICPC1_MASK              << ICPC1_SHIFT)
+#define ICPC2              (ICPC2_MASK              << ICPC2_SHIFT)
+#define ICPC3              (ICPC3_MASK              << ICPC3_SHIFT)
+#define ICPC4              (ICPC4_MASK              << ICPC4_SHIFT)
+#define ICPC5              (ICPC5_MASK              << ICPC5_SHIFT)
+#define ICPC6              (ICPC6_MASK              << ICPC6_SHIFT)
+#define ICPC7              (ICPC7_MASK              << ICPC7_SHIFT)
+#define OCPC0              (OCPC0_MASK              << OCPC0_SHIFT)
+#define OCPC1              (OCPC1_MASK              << OCPC1_SHIFT)
+#define OCPC2              (OCPC2_MASK              << OCPC2_SHIFT)
+#define OCPC3              (OCPC3_MASK              << OCPC3_SHIFT)
+#define OCPC4              (OCPC4_MASK              << OCPC4_SHIFT)
+#define OCPC5              (OCPC5_MASK              << OCPC5_SHIFT)
+#define OCPC6              (OCPC6_MASK              << OCPC6_SHIFT)
+#define OCPC7              (OCPC7_MASK              << OCPC7_SHIFT)
+
+
+/* PAR */
+#define FAULT              (FAULT_MASK              << FAULT_SHIFT)
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF           (FAULT_TF_MASK           << FAULT_TF_SHIFT)
+#define FAULT_AFF          (FAULT_AFF_MASK          << FAULT_AFF_SHIFT)
+#define FAULT_APF          (FAULT_APF_MASK          << FAULT_APF_SHIFT)
+#define FAULT_TLBMF        (FAULT_TLBMF_MASK        << FAULT_TLBMF_SHIFT)
+#define FAULT_HTWDEEF      (FAULT_HTWDEEF_MASK      << FAULT_HTWDEEF_SHIFT)
+#define FAULT_HTWSEEF      (FAULT_HTWSEEF_MASK      << FAULT_HTWSEEF_SHIFT)
+#define FAULT_MHF          (FAULT_MHF_MASK          << FAULT_MHF_SHIFT)
+#define FAULT_SL           (FAULT_SL_MASK           << FAULT_SL_SHIFT)
+#define FAULT_SS           (FAULT_SS_MASK           << FAULT_SS_SHIFT)
+
+/* If NO fault is present, the following fields are in effect */
+/* (FAULT remains as before) */
+#define PAR_NOFAULT_SS     (PAR_NOFAULT_SS_MASK     << PAR_NOFAULT_SS_SHIFT)
+#define PAR_NOFAULT_MT     (PAR_NOFAULT_MT_MASK     << PAR_NOFAULT_MT_SHIFT)
+#define PAR_NOFAULT_SH     (PAR_NOFAULT_SH_MASK     << PAR_NOFAULT_SH_SHIFT)
+#define PAR_NOFAULT_NS     (PAR_NOFAULT_NS_MASK     << PAR_NOFAULT_NS_SHIFT)
+#define PAR_NOFAULT_NOS    (PAR_NOFAULT_NOS_MASK    << PAR_NOFAULT_NOS_SHIFT)
+#define PAR_NPFAULT_PA     (PAR_NPFAULT_PA_MASK     << PAR_NPFAULT_PA_SHIFT)
+
+
+/* PRRR */
+#define MTC0               (MTC0_MASK               << MTC0_SHIFT)
+#define MTC1               (MTC1_MASK               << MTC1_SHIFT)
+#define MTC2               (MTC2_MASK               << MTC2_SHIFT)
+#define MTC3               (MTC3_MASK               << MTC3_SHIFT)
+#define MTC4               (MTC4_MASK               << MTC4_SHIFT)
+#define MTC5               (MTC5_MASK               << MTC5_SHIFT)
+#define MTC6               (MTC6_MASK               << MTC6_SHIFT)
+#define MTC7               (MTC7_MASK               << MTC7_SHIFT)
+#define SHDSH0             (SHDSH0_MASK             << SHDSH0_SHIFT)
+#define SHDSH1             (SHDSH1_MASK             << SHDSH1_SHIFT)
+#define SHNMSH0            (SHNMSH0_MASK            << SHNMSH0_SHIFT)
+#define SHNMSH1            (SHNMSH1_MASK            << SHNMSH1_SHIFT)
+#define NOS0               (NOS0_MASK               << NOS0_SHIFT)
+#define NOS1               (NOS1_MASK               << NOS1_SHIFT)
+#define NOS2               (NOS2_MASK               << NOS2_SHIFT)
+#define NOS3               (NOS3_MASK               << NOS3_SHIFT)
+#define NOS4               (NOS4_MASK               << NOS4_SHIFT)
+#define NOS5               (NOS5_MASK               << NOS5_SHIFT)
+#define NOS6               (NOS6_MASK               << NOS6_SHIFT)
+#define NOS7               (NOS7_MASK               << NOS7_SHIFT)
+
+
+/* RESUME */
+#define TNR                (TNR_MASK                << TNR_SHIFT)
+
+
+/* SCTLR */
+#define M                  (M_MASK                  << M_SHIFT)
+#define TRE                (TRE_MASK                << TRE_SHIFT)
+#define AFE                (AFE_MASK                << AFE_SHIFT)
+#define HAF                (HAF_MASK                << HAF_SHIFT)
+#define BE                 (BE_MASK                 << BE_SHIFT)
+#define AFFD               (AFFD_MASK               << AFFD_SHIFT)
+
+
+/* TLBIASID */
+#define TLBIASID_ASID      (TLBIASID_ASID_MASK      << TLBIASID_ASID_SHIFT)
+
+
+/* TLBIVA */
+#define TLBIVA_ASID        (TLBIVA_ASID_MASK        << TLBIVA_ASID_SHIFT)
+#define TLBIVA_VA          (TLBIVA_VA_MASK          << TLBIVA_VA_SHIFT)
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA         (TLBIVAA_VA_MASK         << TLBIVAA_VA_SHIFT)
+
+
+/* TLBLCKR */
+#define LKE                (LKE_MASK                << LKE_SHIFT)
+#define TLBLCKR_TLBIALLCFG (TLBLCKR_TLBIALLCFG_MASK<<TLBLCKR_TLBIALLCFG_SHIFT)
+#define TLBIASIDCFG        (TLBIASIDCFG_MASK        << TLBIASIDCFG_SHIFT)
+#define TLBIVAACFG         (TLBIVAACFG_MASK         << TLBIVAACFG_SHIFT)
+#define FLOOR              (FLOOR_MASK              << FLOOR_SHIFT)
+#define VICTIM             (VICTIM_MASK             << VICTIM_SHIFT)
+
+
+/* TTBCR */
+#define N                  (N_MASK                  << N_SHIFT)
+#define PD0                (PD0_MASK                << PD0_SHIFT)
+#define PD1                (PD1_MASK                << PD1_SHIFT)
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH        (TTBR0_IRGNH_MASK        << TTBR0_IRGNH_SHIFT)
+#define TTBR0_SH           (TTBR0_SH_MASK           << TTBR0_SH_SHIFT)
+#define TTBR0_ORGN         (TTBR0_ORGN_MASK         << TTBR0_ORGN_SHIFT)
+#define TTBR0_NOS          (TTBR0_NOS_MASK          << TTBR0_NOS_SHIFT)
+#define TTBR0_IRGNL        (TTBR0_IRGNL_MASK        << TTBR0_IRGNL_SHIFT)
+#define TTBR0_PA           (TTBR0_PA_MASK           << TTBR0_PA_SHIFT)
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH        (TTBR1_IRGNH_MASK        << TTBR1_IRGNH_SHIFT)
+#define TTBR1_SH           (TTBR1_SH_MASK           << TTBR1_SH_SHIFT)
+#define TTBR1_ORGN         (TTBR1_ORGN_MASK         << TTBR1_ORGN_SHIFT)
+#define TTBR1_NOS          (TTBR1_NOS_MASK          << TTBR1_NOS_SHIFT)
+#define TTBR1_IRGNL        (TTBR1_IRGNL_MASK        << TTBR1_IRGNL_SHIFT)
+#define TTBR1_PA           (TTBR1_PA_MASK           << TTBR1_PA_SHIFT)
+
+
+/* V2PSR */
+#define HIT                (HIT_MASK                << HIT_SHIFT)
+#define INDEX              (INDEX_MASK              << INDEX_SHIFT)
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX        (V2Pxx_INDEX_MASK        << V2Pxx_INDEX_SHIFT)
+#define V2Pxx_VA           (V2Pxx_VA_MASK           << V2Pxx_VA_SHIFT)
+
+
+/* Global Register Masks */
+/* CBACRn */
+#define RWVMID_MASK               0x1F
+#define RWE_MASK                  0x01
+#define RWGE_MASK                 0x01
+#define CBVMID_MASK               0x1F
+#define IRPTNDX_MASK              0xFF
+
+
+/* CR */
+#define RPUE_MASK                 0x01
+#define RPUERE_MASK               0x01
+#define RPUEIE_MASK               0x01
+#define DCDEE_MASK                0x01
+#define CLIENTPD_MASK             0x01
+#define STALLD_MASK               0x01
+#define TLBLKCRWE_MASK            0x01
+#define CR_TLBIALLCFG_MASK        0x01
+#define TLBIVMIDCFG_MASK          0x01
+#define CR_HUME_MASK              0x01
+
+
+/* ESR */
+#define CFG_MASK                  0x01
+#define BYPASS_MASK               0x01
+#define ESR_MULTI_MASK            0x01
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID_MASK          0xFF
+#define ESYNR0_APID_MASK          0x1F
+#define ESYNR0_ABID_MASK          0x07
+#define ESYNR0_AVMID_MASK         0x1F
+#define ESYNR0_ATID_MASK          0xFF
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE_MASK             0x07
+#define ESYNR1_ASHARED_MASK              0x01
+#define ESYNR1_AINNERSHARED_MASK         0x01
+#define ESYNR1_APRIV_MASK                0x01
+#define ESYNR1_APROTNS_MASK              0x01
+#define ESYNR1_AINST_MASK                0x01
+#define ESYNR1_AWRITE_MASK               0x01
+#define ESYNR1_ABURST_MASK               0x01
+#define ESYNR1_ALEN_MASK                 0x0F
+#define ESYNR1_ASIZE_MASK                0x01
+#define ESYNR1_ALOCK_MASK                0x03
+#define ESYNR1_AOOO_MASK                 0x01
+#define ESYNR1_AFULL_MASK                0x01
+#define ESYNR1_AC_MASK                   0x01
+#define ESYNR1_DCD_MASK                  0x01
+
+
+/* IDR */
+#define NM2VCBMT_MASK             0x1FF
+#define HTW_MASK                  0x01
+#define HUM_MASK                  0x01
+#define TLBSIZE_MASK              0x0F
+#define NCB_MASK                  0xFF
+#define NIRPT_MASK                0xFF
+
+
+/* M2VCBRn */
+#define VMID_MASK                 0x1F
+#define CBNDX_MASK                0xFF
+#define BYPASSD_MASK              0x01
+#define BPRCOSH_MASK              0x01
+#define BPRCISH_MASK              0x01
+#define BPRCNSH_MASK              0x01
+#define BPSHCFG_MASK              0x03
+#define NSCFG_MASK                0x03
+#define BPMTCFG_MASK              0x01
+#define BPMEMTYPE_MASK            0x07
+
+
+/* REV */
+#define MINOR_MASK                0x0F
+#define MAJOR_MASK                0x0F
+
+
+/* TESTBUSCR */
+#define TBE_MASK                  0x01
+#define SPDMBE_MASK               0x01
+#define WGSEL_MASK                0x03
+#define TBLSEL_MASK               0x03
+#define TBHSEL_MASK               0x03
+#define SPDM0SEL_MASK             0x0F
+#define SPDM1SEL_MASK             0x0F
+#define SPDM2SEL_MASK             0x0F
+#define SPDM3SEL_MASK             0x0F
+
+
+/* TLBIMID */
+#define TLBIVMID_VMID_MASK        0x1F
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX_MASK         0xFF
+#define TLBBFBS_MASK              0x03
+
+
+/* TLBTR0 */
+#define PR_MASK                   0x01
+#define PW_MASK                   0x01
+#define UR_MASK                   0x01
+#define UW_MASK                   0x01
+#define XN_MASK                   0x01
+#define NSDESC_MASK               0x01
+#define ISH_MASK                  0x01
+#define SH_MASK                   0x01
+#define MT_MASK                   0x07
+#define DPSIZR_MASK               0x07
+#define DPSIZC_MASK               0x07
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID_MASK          0x1F
+#define TLBTR1_PA_MASK            0x000FFFFF
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID_MASK          0xFF
+#define TLBTR2_V_MASK             0x01
+#define TLBTR2_NSTID_MASK         0x01
+#define TLBTR2_NV_MASK            0x01
+#define TLBTR2_VA_MASK            0x000FFFFF
+
+
+/* Global Register Shifts */
+/* CBACRn */
+#define RWVMID_SHIFT             0
+#define RWE_SHIFT                8
+#define RWGE_SHIFT               9
+#define CBVMID_SHIFT             16
+#define IRPTNDX_SHIFT            24
+
+
+/* CR */
+#define RPUE_SHIFT               0
+#define RPUERE_SHIFT             1
+#define RPUEIE_SHIFT             2
+#define DCDEE_SHIFT              3
+#define CLIENTPD_SHIFT           4
+#define STALLD_SHIFT             5
+#define TLBLKCRWE_SHIFT          6
+#define CR_TLBIALLCFG_SHIFT      7
+#define TLBIVMIDCFG_SHIFT        8
+#define CR_HUME_SHIFT            9
+
+
+/* ESR */
+#define CFG_SHIFT                0
+#define BYPASS_SHIFT             1
+#define ESR_MULTI_SHIFT          31
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID_SHIFT        0
+#define ESYNR0_APID_SHIFT        8
+#define ESYNR0_ABID_SHIFT        13
+#define ESYNR0_AVMID_SHIFT       16
+#define ESYNR0_ATID_SHIFT        24
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE_SHIFT           0
+#define ESYNR1_ASHARED_SHIFT            3
+#define ESYNR1_AINNERSHARED_SHIFT       4
+#define ESYNR1_APRIV_SHIFT              5
+#define ESYNR1_APROTNS_SHIFT            6
+#define ESYNR1_AINST_SHIFT              7
+#define ESYNR1_AWRITE_SHIFT             8
+#define ESYNR1_ABURST_SHIFT             10
+#define ESYNR1_ALEN_SHIFT               12
+#define ESYNR1_ASIZE_SHIFT              16
+#define ESYNR1_ALOCK_SHIFT              20
+#define ESYNR1_AOOO_SHIFT               22
+#define ESYNR1_AFULL_SHIFT              24
+#define ESYNR1_AC_SHIFT                 30
+#define ESYNR1_DCD_SHIFT                31
+
+
+/* IDR */
+#define NM2VCBMT_SHIFT           0
+#define HTW_SHIFT                9
+#define HUM_SHIFT                10
+#define TLBSIZE_SHIFT            12
+#define NCB_SHIFT                16
+#define NIRPT_SHIFT              24
+
+
+/* M2VCBRn */
+#define VMID_SHIFT               0
+#define CBNDX_SHIFT              8
+#define BYPASSD_SHIFT            16
+#define BPRCOSH_SHIFT            17
+#define BPRCISH_SHIFT            18
+#define BPRCNSH_SHIFT            19
+#define BPSHCFG_SHIFT            20
+#define NSCFG_SHIFT              22
+#define BPMTCFG_SHIFT            24
+#define BPMEMTYPE_SHIFT          25
+
+
+/* REV */
+#define MINOR_SHIFT              0
+#define MAJOR_SHIFT              4
+
+
+/* TESTBUSCR */
+#define TBE_SHIFT                0
+#define SPDMBE_SHIFT             1
+#define WGSEL_SHIFT              8
+#define TBLSEL_SHIFT             12
+#define TBHSEL_SHIFT             14
+#define SPDM0SEL_SHIFT           16
+#define SPDM1SEL_SHIFT           20
+#define SPDM2SEL_SHIFT           24
+#define SPDM3SEL_SHIFT           28
+
+
+/* TLBIMID */
+#define TLBIVMID_VMID_SHIFT      0
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX_SHIFT       0
+#define TLBBFBS_SHIFT            8
+
+
+/* TLBTR0 */
+#define PR_SHIFT                 0
+#define PW_SHIFT                 1
+#define UR_SHIFT                 2
+#define UW_SHIFT                 3
+#define XN_SHIFT                 4
+#define NSDESC_SHIFT             6
+#define ISH_SHIFT                7
+#define SH_SHIFT                 8
+#define MT_SHIFT                 9
+#define DPSIZR_SHIFT             16
+#define DPSIZC_SHIFT             20
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID_SHIFT        0
+#define TLBTR1_PA_SHIFT          12
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID_SHIFT        0
+#define TLBTR2_V_SHIFT           8
+#define TLBTR2_NSTID_SHIFT       9
+#define TLBTR2_NV_SHIFT          10
+#define TLBTR2_VA_SHIFT          12
+
+
+/* Context Register Masks */
+/* ACTLR */
+#define CFERE_MASK                       0x01
+#define CFEIE_MASK                       0x01
+#define PTSHCFG_MASK                     0x03
+#define RCOSH_MASK                       0x01
+#define RCISH_MASK                       0x01
+#define RCNSH_MASK                       0x01
+#define PRIVCFG_MASK                     0x03
+#define DNA_MASK                         0x01
+#define DNLV2PA_MASK                     0x01
+#define TLBMCFG_MASK                     0x03
+#define CFCFG_MASK                       0x01
+#define TIPCF_MASK                       0x01
+#define V2PCFG_MASK                      0x03
+#define HUME_MASK                        0x01
+#define PTMTCFG_MASK                     0x01
+#define PTMEMTYPE_MASK                   0x07
+
+
+/* BFBCR */
+#define BFBDFE_MASK                      0x01
+#define BFBSFE_MASK                      0x01
+#define SFVS_MASK                        0x01
+#define FLVIC_MASK                       0x0F
+#define SLVIC_MASK                       0x0F
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID_MASK             0xFF
+#define PROCID_MASK                      0x00FFFFFF
+
+
+/* FSR */
+#define TF_MASK                          0x01
+#define AFF_MASK                         0x01
+#define APF_MASK                         0x01
+#define TLBMF_MASK                       0x01
+#define HTWDEEF_MASK                     0x01
+#define HTWSEEF_MASK                     0x01
+#define MHF_MASK                         0x01
+#define SL_MASK                          0x01
+#define SS_MASK                          0x01
+#define MULTI_MASK                       0x01
+
+
+/* FSYNR0 */
+#define AMID_MASK                        0xFF
+#define APID_MASK                        0x1F
+#define ABID_MASK                        0x07
+#define ATID_MASK                        0xFF
+
+
+/* FSYNR1 */
+#define AMEMTYPE_MASK                    0x07
+#define ASHARED_MASK                     0x01
+#define AINNERSHARED_MASK                0x01
+#define APRIV_MASK                       0x01
+#define APROTNS_MASK                     0x01
+#define AINST_MASK                       0x01
+#define AWRITE_MASK                      0x01
+#define ABURST_MASK                      0x01
+#define ALEN_MASK                        0x0F
+#define FSYNR1_ASIZE_MASK                0x07
+#define ALOCK_MASK                       0x03
+#define AFULL_MASK                       0x01
+
+
+/* NMRR */
+#define ICPC0_MASK                       0x03
+#define ICPC1_MASK                       0x03
+#define ICPC2_MASK                       0x03
+#define ICPC3_MASK                       0x03
+#define ICPC4_MASK                       0x03
+#define ICPC5_MASK                       0x03
+#define ICPC6_MASK                       0x03
+#define ICPC7_MASK                       0x03
+#define OCPC0_MASK                       0x03
+#define OCPC1_MASK                       0x03
+#define OCPC2_MASK                       0x03
+#define OCPC3_MASK                       0x03
+#define OCPC4_MASK                       0x03
+#define OCPC5_MASK                       0x03
+#define OCPC6_MASK                       0x03
+#define OCPC7_MASK                       0x03
+
+
+/* PAR */
+#define FAULT_MASK                       0x01
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF_MASK                    0x01
+#define FAULT_AFF_MASK                   0x01
+#define FAULT_APF_MASK                   0x01
+#define FAULT_TLBMF_MASK                 0x01
+#define FAULT_HTWDEEF_MASK               0x01
+#define FAULT_HTWSEEF_MASK               0x01
+#define FAULT_MHF_MASK                   0x01
+#define FAULT_SL_MASK                    0x01
+#define FAULT_SS_MASK                    0x01
+
+/* If NO fault is present, the following
+ * fields are in effect
+ * (FAULT remains as before) */
+#define PAR_NOFAULT_SS_MASK              0x01
+#define PAR_NOFAULT_MT_MASK              0x07
+#define PAR_NOFAULT_SH_MASK              0x01
+#define PAR_NOFAULT_NS_MASK              0x01
+#define PAR_NOFAULT_NOS_MASK             0x01
+#define PAR_NPFAULT_PA_MASK              0x000FFFFF
+
+
+/* PRRR */
+#define MTC0_MASK                        0x03
+#define MTC1_MASK                        0x03
+#define MTC2_MASK                        0x03
+#define MTC3_MASK                        0x03
+#define MTC4_MASK                        0x03
+#define MTC5_MASK                        0x03
+#define MTC6_MASK                        0x03
+#define MTC7_MASK                        0x03
+#define SHDSH0_MASK                      0x01
+#define SHDSH1_MASK                      0x01
+#define SHNMSH0_MASK                     0x01
+#define SHNMSH1_MASK                     0x01
+#define NOS0_MASK                        0x01
+#define NOS1_MASK                        0x01
+#define NOS2_MASK                        0x01
+#define NOS3_MASK                        0x01
+#define NOS4_MASK                        0x01
+#define NOS5_MASK                        0x01
+#define NOS6_MASK                        0x01
+#define NOS7_MASK                        0x01
+
+
+/* RESUME */
+#define TNR_MASK                         0x01
+
+
+/* SCTLR */
+#define M_MASK                           0x01
+#define TRE_MASK                         0x01
+#define AFE_MASK                         0x01
+#define HAF_MASK                         0x01
+#define BE_MASK                          0x01
+#define AFFD_MASK                        0x01
+
+
+/* TLBIASID */
+#define TLBIASID_ASID_MASK               0xFF
+
+
+/* TLBIVA */
+#define TLBIVA_ASID_MASK                 0xFF
+#define TLBIVA_VA_MASK                   0x000FFFFF
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA_MASK                  0x000FFFFF
+
+
+/* TLBLCKR */
+#define LKE_MASK                         0x01
+#define TLBLCKR_TLBIALLCFG_MASK          0x01
+#define TLBIASIDCFG_MASK                 0x01
+#define TLBIVAACFG_MASK                  0x01
+#define FLOOR_MASK                       0xFF
+#define VICTIM_MASK                      0xFF
+
+
+/* TTBCR */
+#define N_MASK                           0x07
+#define PD0_MASK                         0x01
+#define PD1_MASK                         0x01
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH_MASK                 0x01
+#define TTBR0_SH_MASK                    0x01
+#define TTBR0_ORGN_MASK                  0x03
+#define TTBR0_NOS_MASK                   0x01
+#define TTBR0_IRGNL_MASK                 0x01
+#define TTBR0_PA_MASK                    0x0003FFFF
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH_MASK                 0x01
+#define TTBR1_SH_MASK                    0x01
+#define TTBR1_ORGN_MASK                  0x03
+#define TTBR1_NOS_MASK                   0x01
+#define TTBR1_IRGNL_MASK                 0x01
+#define TTBR1_PA_MASK                    0x0003FFFF
+
+
+/* V2PSR */
+#define HIT_MASK                         0x01
+#define INDEX_MASK                       0xFF
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX_MASK                 0xFF
+#define V2Pxx_VA_MASK                    0x000FFFFF
+
+
+/* Context Register Shifts */
+/* ACTLR */
+#define CFERE_SHIFT                    0
+#define CFEIE_SHIFT                    1
+#define PTSHCFG_SHIFT                  2
+#define RCOSH_SHIFT                    4
+#define RCISH_SHIFT                    5
+#define RCNSH_SHIFT                    6
+#define PRIVCFG_SHIFT                  8
+#define DNA_SHIFT                      10
+#define DNLV2PA_SHIFT                  11
+#define TLBMCFG_SHIFT                  12
+#define CFCFG_SHIFT                    14
+#define TIPCF_SHIFT                    15
+#define V2PCFG_SHIFT                   16
+#define HUME_SHIFT                     18
+#define PTMTCFG_SHIFT                  20
+#define PTMEMTYPE_SHIFT                21
+
+
+/* BFBCR */
+#define BFBDFE_SHIFT                   0
+#define BFBSFE_SHIFT                   1
+#define SFVS_SHIFT                     2
+#define FLVIC_SHIFT                    4
+#define SLVIC_SHIFT                    8
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID_SHIFT          0
+#define PROCID_SHIFT                   8
+
+
+/* FSR */
+#define TF_SHIFT                       1
+#define AFF_SHIFT                      2
+#define APF_SHIFT                      3
+#define TLBMF_SHIFT                    4
+#define HTWDEEF_SHIFT                  5
+#define HTWSEEF_SHIFT                  6
+#define MHF_SHIFT                      7
+#define SL_SHIFT                       16
+#define SS_SHIFT                       30
+#define MULTI_SHIFT                    31
+
+
+/* FSYNR0 */
+#define AMID_SHIFT                     0
+#define APID_SHIFT                     8
+#define ABID_SHIFT                     13
+#define ATID_SHIFT                     24
+
+
+/* FSYNR1 */
+#define AMEMTYPE_SHIFT                 0
+#define ASHARED_SHIFT                  3
+#define AINNERSHARED_SHIFT             4
+#define APRIV_SHIFT                    5
+#define APROTNS_SHIFT                  6
+#define AINST_SHIFT                    7
+#define AWRITE_SHIFT                   8
+#define ABURST_SHIFT                   10
+#define ALEN_SHIFT                     12
+#define FSYNR1_ASIZE_SHIFT             16
+#define ALOCK_SHIFT                    20
+#define AFULL_SHIFT                    24
+
+
+/* NMRR */
+#define ICPC0_SHIFT                    0
+#define ICPC1_SHIFT                    2
+#define ICPC2_SHIFT                    4
+#define ICPC3_SHIFT                    6
+#define ICPC4_SHIFT                    8
+#define ICPC5_SHIFT                    10
+#define ICPC6_SHIFT                    12
+#define ICPC7_SHIFT                    14
+#define OCPC0_SHIFT                    16
+#define OCPC1_SHIFT                    18
+#define OCPC2_SHIFT                    20
+#define OCPC3_SHIFT                    22
+#define OCPC4_SHIFT                    24
+#define OCPC5_SHIFT                    26
+#define OCPC6_SHIFT                    28
+#define OCPC7_SHIFT                    30
+
+
+/* PAR */
+#define FAULT_SHIFT                    0
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF_SHIFT                 1
+#define FAULT_AFF_SHIFT                2
+#define FAULT_APF_SHIFT                3
+#define FAULT_TLBMF_SHIFT              4
+#define FAULT_HTWDEEF_SHIFT            5
+#define FAULT_HTWSEEF_SHIFT            6
+#define FAULT_MHF_SHIFT                7
+#define FAULT_SL_SHIFT                 16
+#define FAULT_SS_SHIFT                 30
+
+/* If NO fault is present, the following
+ * fields are in effect
+ * (FAULT remains as before) */
+#define PAR_NOFAULT_SS_SHIFT           1
+#define PAR_NOFAULT_MT_SHIFT           4
+#define PAR_NOFAULT_SH_SHIFT           7
+#define PAR_NOFAULT_NS_SHIFT           9
+#define PAR_NOFAULT_NOS_SHIFT          10
+#define PAR_NPFAULT_PA_SHIFT           12
+
+
+/* PRRR */
+#define MTC0_SHIFT                     0
+#define MTC1_SHIFT                     2
+#define MTC2_SHIFT                     4
+#define MTC3_SHIFT                     6
+#define MTC4_SHIFT                     8
+#define MTC5_SHIFT                     10
+#define MTC6_SHIFT                     12
+#define MTC7_SHIFT                     14
+#define SHDSH0_SHIFT                   16
+#define SHDSH1_SHIFT                   17
+#define SHNMSH0_SHIFT                  18
+#define SHNMSH1_SHIFT                  19
+#define NOS0_SHIFT                     24
+#define NOS1_SHIFT                     25
+#define NOS2_SHIFT                     26
+#define NOS3_SHIFT                     27
+#define NOS4_SHIFT                     28
+#define NOS5_SHIFT                     29
+#define NOS6_SHIFT                     30
+#define NOS7_SHIFT                     31
+
+
+/* RESUME */
+#define TNR_SHIFT                      0
+
+
+/* SCTLR */
+#define M_SHIFT                        0
+#define TRE_SHIFT                      1
+#define AFE_SHIFT                      2
+#define HAF_SHIFT                      3
+#define BE_SHIFT                       4
+#define AFFD_SHIFT                     5
+
+
+/* TLBIASID */
+#define TLBIASID_ASID_SHIFT            0
+
+
+/* TLBIVA */
+#define TLBIVA_ASID_SHIFT              0
+#define TLBIVA_VA_SHIFT                12
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA_SHIFT               12
+
+
+/* TLBLCKR */
+#define LKE_SHIFT                      0
+#define TLBLCKR_TLBIALLCFG_SHIFT       1
+#define TLBIASIDCFG_SHIFT              2
+#define TLBIVAACFG_SHIFT               3
+#define FLOOR_SHIFT                    8
+#define VICTIM_SHIFT                   8
+
+
+/* TTBCR */
+#define N_SHIFT                        3
+#define PD0_SHIFT                      4
+#define PD1_SHIFT                      5
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH_SHIFT              0
+#define TTBR0_SH_SHIFT                 1
+#define TTBR0_ORGN_SHIFT               3
+#define TTBR0_NOS_SHIFT                5
+#define TTBR0_IRGNL_SHIFT              6
+#define TTBR0_PA_SHIFT                 14
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH_SHIFT              0
+#define TTBR1_SH_SHIFT                 1
+#define TTBR1_ORGN_SHIFT               3
+#define TTBR1_NOS_SHIFT                5
+#define TTBR1_IRGNL_SHIFT              6
+#define TTBR1_PA_SHIFT                 14
+
+
+/* V2PSR */
+#define HIT_SHIFT                      0
+#define INDEX_SHIFT                    8
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX_SHIFT              0
+#define V2Pxx_VA_SHIFT                 12
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/irqs-8x60.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/irqs-8x60.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/irqs-8x60.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/irqs-8x60.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,253 @@
+/* Copyright (c) 2010 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8X60_H
+#define __ASM_ARCH_MSM_IRQS_8X60_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/* 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_DEBUG_TIMER_EXP			(GIC_PPI_START + 0)
+#define INT_GP_TIMER_EXP			(GIC_PPI_START + 1)
+#define INT_GP_TIMER2_EXP			(GIC_PPI_START + 2)
+#define WDT0_ACCSCSSNBARK_INT			(GIC_PPI_START + 3)
+#define WDT1_ACCSCSSNBARK_INT			(GIC_PPI_START + 4)
+#define AVS_SVICINT				(GIC_PPI_START + 5)
+#define AVS_SVICINTSWDONE			(GIC_PPI_START + 6)
+#define CPU_DBGCPUXCOMMRXFULL			(GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMTXEMPTY			(GIC_PPI_START + 8)
+#define CPU_SICCPUXPERFMONIRPTREQ		(GIC_PPI_START + 9)
+#define SC_AVSCPUXDOWN				(GIC_PPI_START + 10)
+#define SC_AVSCPUXUP				(GIC_PPI_START + 11)
+#define SC_SICCPUXACGIRPTREQ			(GIC_PPI_START + 12)
+/* PPI 13 to 15 are unused */
+
+
+#define SC_SICMPUIRPTREQ			(GIC_SPI_START + 0)
+#define SC_SICL2IRPTREQ				(GIC_SPI_START + 1)
+#define SC_SICL2ACGIRPTREQ			(GIC_SPI_START + 2)
+#define NC					(GIC_SPI_START + 3)
+#define TLMM_SCSS_DIR_CONN_IRQ_0		(GIC_SPI_START + 4)
+#define TLMM_SCSS_DIR_CONN_IRQ_1		(GIC_SPI_START + 5)
+#define TLMM_SCSS_DIR_CONN_IRQ_2		(GIC_SPI_START + 6)
+#define TLMM_SCSS_DIR_CONN_IRQ_3		(GIC_SPI_START + 7)
+#define TLMM_SCSS_DIR_CONN_IRQ_4		(GIC_SPI_START + 8)
+#define TLMM_SCSS_DIR_CONN_IRQ_5		(GIC_SPI_START + 9)
+#define TLMM_SCSS_DIR_CONN_IRQ_6		(GIC_SPI_START + 10)
+#define TLMM_SCSS_DIR_CONN_IRQ_7		(GIC_SPI_START + 11)
+#define TLMM_SCSS_DIR_CONN_IRQ_8		(GIC_SPI_START + 12)
+#define TLMM_SCSS_DIR_CONN_IRQ_9		(GIC_SPI_START + 13)
+#define PM8058_SEC_IRQ_N			(GIC_SPI_START + 14)
+#define PM8901_SEC_IRQ_N			(GIC_SPI_START + 15)
+#define TLMM_SCSS_SUMMARY_IRQ			(GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ				(GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ				(GIC_SPI_START + 18)
+#define RPM_SCSS_CPU0_GP_HIGH_IRQ		(GIC_SPI_START + 19)
+#define RPM_SCSS_CPU0_GP_MEDIUM_IRQ		(GIC_SPI_START + 20)
+#define RPM_SCSS_CPU0_GP_LOW_IRQ		(GIC_SPI_START + 21)
+#define RPM_SCSS_CPU0_WAKE_UP_IRQ		(GIC_SPI_START + 22)
+#define RPM_SCSS_CPU1_GP_HIGH_IRQ		(GIC_SPI_START + 23)
+#define RPM_SCSS_CPU1_GP_MEDIUM_IRQ		(GIC_SPI_START + 24)
+#define RPM_SCSS_CPU1_GP_LOW_IRQ		(GIC_SPI_START + 25)
+#define RPM_SCSS_CPU1_WAKE_UP_IRQ		(GIC_SPI_START + 26)
+#define SSBI2_2_SC_CPU0_SECURE_INT		(GIC_SPI_START + 27)
+#define SSBI2_2_SC_CPU0_NON_SECURE_INT		(GIC_SPI_START + 28)
+#define SSBI2_1_SC_CPU0_SECURE_INT		(GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_INT		(GIC_SPI_START + 30)
+#define MSMC_SC_SEC_CE_IRQ			(GIC_SPI_START + 31)
+#define MSMC_SC_PRI_CE_IRQ			(GIC_SPI_START + 32)
+#define MARM_FIQ				(GIC_SPI_START + 33)
+#define MARM_IRQ				(GIC_SPI_START + 34)
+#define MARM_L2CC_IRQ				(GIC_SPI_START + 35)
+#define MARM_WDOG_EXPIRED			(GIC_SPI_START + 36)
+#define MARM_SCSS_GP_IRQ_0			(GIC_SPI_START + 37)
+#define MARM_SCSS_GP_IRQ_1			(GIC_SPI_START + 38)
+#define MARM_SCSS_GP_IRQ_2			(GIC_SPI_START + 39)
+#define MARM_SCSS_GP_IRQ_3			(GIC_SPI_START + 40)
+#define MARM_SCSS_GP_IRQ_4			(GIC_SPI_START + 41)
+#define MARM_SCSS_GP_IRQ_5			(GIC_SPI_START + 42)
+#define MARM_SCSS_GP_IRQ_6			(GIC_SPI_START + 43)
+#define MARM_SCSS_GP_IRQ_7			(GIC_SPI_START + 44)
+#define MARM_SCSS_GP_IRQ_8			(GIC_SPI_START + 45)
+#define MARM_SCSS_GP_IRQ_9			(GIC_SPI_START + 46)
+#define VPE_IRQ					(GIC_SPI_START + 47)
+#define VFE_IRQ					(GIC_SPI_START + 48)
+#define VCODEC_IRQ				(GIC_SPI_START + 49)
+#define TV_ENC_IRQ				(GIC_SPI_START + 50)
+#define SMMU_VPE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 51)
+#define SMMU_VPE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 52)
+#define SMMU_VFE_CB_SC_SECURE_IRQ		(GIC_SPI_START + 53)
+#define SMMU_VFE_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 54)
+#define SMMU_VCODEC_B_CB_SC_SECURE_IRQ		(GIC_SPI_START + 55)
+#define SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 56)
+#define SMMU_VCODEC_A_CB_SC_SECURE_IRQ		(GIC_SPI_START + 57)
+#define SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 58)
+#define SMMU_ROT_CB_SC_SECURE_IRQ		(GIC_SPI_START + 59)
+#define SMMU_ROT_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 60)
+#define SMMU_MDP1_CB_SC_SECURE_IRQ		(GIC_SPI_START + 61)
+#define SMMU_MDP1_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 62)
+#define SMMU_MDP0_CB_SC_SECURE_IRQ		(GIC_SPI_START + 63)
+#define SMMU_MDP0_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 64)
+#define SMMU_JPEGD_CB_SC_SECURE_IRQ		(GIC_SPI_START + 65)
+#define SMMU_JPEGD_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 66)
+#define SMMU_IJPEG_CB_SC_SECURE_IRQ		(GIC_SPI_START + 67)
+#define SMMU_IJPEG_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 68)
+#define SMMU_GFX3D_CB_SC_SECURE_IRQ		(GIC_SPI_START + 69)
+#define SMMU_GFX3D_CB_SC_NON_SECURE_IRQ		(GIC_SPI_START + 70)
+#define SMMU_GFX2D0_CB_SC_SECURE_IRQ		(GIC_SPI_START + 71)
+#define SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ	(GIC_SPI_START + 72)
+#define ROT_IRQ					(GIC_SPI_START + 73)
+#define MMSS_FABRIC_IRQ				(GIC_SPI_START + 74)
+#define MDP_IRQ					(GIC_SPI_START + 75)
+#define JPEGD_IRQ				(GIC_SPI_START + 76)
+#define JPEG_IRQ				(GIC_SPI_START + 77)
+#define MMSS_IMEM_IRQ				(GIC_SPI_START + 78)
+#define HDMI_IRQ				(GIC_SPI_START + 79)
+#define GFX3D_IRQ				(GIC_SPI_START + 80)
+#define GFX2D0_IRQ				(GIC_SPI_START + 81)
+#define DSI_IRQ					(GIC_SPI_START + 82)
+#define CSI_1_IRQ				(GIC_SPI_START + 83)
+#define CSI_0_IRQ				(GIC_SPI_START + 84)
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ		(GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ			(GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED			(GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ			(GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ		(GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ			(GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ				(GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ				(GIC_SPI_START + 92)
+#define FABRIC_APPS_IRQ				(GIC_SPI_START + 93)
+#define USB1_HS_BAM_IRQ				(GIC_SPI_START + 94)
+#define SDC4_BAM_IRQ				(GIC_SPI_START + 95)
+#define SDC3_BAM_IRQ				(GIC_SPI_START + 96)
+#define SDC2_BAM_IRQ				(GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ				(GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ				(GIC_SPI_START + 99)
+#define USB1_HS_IRQ				(GIC_SPI_START + 100)
+#define SDC4_IRQ_0				(GIC_SPI_START + 101)
+#define SDC3_IRQ_0				(GIC_SPI_START + 102)
+#define SDC2_IRQ_0				(GIC_SPI_START + 103)
+#define SDC1_IRQ_0				(GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ				(GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ			(GIC_SPI_START + 106)
+#define SPS_MTI_0				(GIC_SPI_START + 107)
+#define SPS_MTI_1				(GIC_SPI_START + 108)
+#define SPS_MTI_2				(GIC_SPI_START + 109)
+#define SPS_MTI_3				(GIC_SPI_START + 110)
+#define SPS_MTI_4				(GIC_SPI_START + 111)
+#define SPS_MTI_5				(GIC_SPI_START + 112)
+#define SPS_MTI_6				(GIC_SPI_START + 113)
+#define SPS_MTI_7				(GIC_SPI_START + 114)
+#define SPS_MTI_8				(GIC_SPI_START + 115)
+#define SPS_MTI_9				(GIC_SPI_START + 116)
+#define SPS_MTI_10				(GIC_SPI_START + 117)
+#define SPS_MTI_11				(GIC_SPI_START + 118)
+#define SPS_MTI_12				(GIC_SPI_START + 119)
+#define SPS_MTI_13				(GIC_SPI_START + 120)
+#define SPS_MTI_14				(GIC_SPI_START + 121)
+#define SPS_MTI_15				(GIC_SPI_START + 122)
+#define SPS_MTI_16				(GIC_SPI_START + 123)
+#define SPS_MTI_17				(GIC_SPI_START + 124)
+#define SPS_MTI_18				(GIC_SPI_START + 125)
+#define SPS_MTI_19				(GIC_SPI_START + 126)
+#define SPS_MTI_20				(GIC_SPI_START + 127)
+#define SPS_MTI_21				(GIC_SPI_START + 128)
+#define SPS_MTI_22				(GIC_SPI_START + 129)
+#define SPS_MTI_23				(GIC_SPI_START + 130)
+#define SPS_MTI_24				(GIC_SPI_START + 131)
+#define SPS_MTI_25				(GIC_SPI_START + 132)
+#define SPS_MTI_26				(GIC_SPI_START + 133)
+#define SPS_MTI_27				(GIC_SPI_START + 134)
+#define SPS_MTI_28				(GIC_SPI_START + 135)
+#define SPS_MTI_29				(GIC_SPI_START + 136)
+#define SPS_MTI_30				(GIC_SPI_START + 137)
+#define SPS_MTI_31				(GIC_SPI_START + 138)
+#define UXMC_EBI2_WR_ER_DONE_IRQ		(GIC_SPI_START + 139)
+#define UXMC_EBI2_OP_DONE_IRQ			(GIC_SPI_START + 140)
+#define USB2_IRQ				(GIC_SPI_START + 141)
+#define USB1_IRQ				(GIC_SPI_START + 142)
+#define TSSC_SSBI_IRQ				(GIC_SPI_START + 143)
+#define TSSC_SAMPLE_IRQ				(GIC_SPI_START + 144)
+#define TSSC_PENUP_IRQ				(GIC_SPI_START + 145)
+#define INT_UART1DM_IRQ				(GIC_SPI_START + 146)
+#define GSBI1_QUP_IRQ				(GIC_SPI_START + 147)
+#define INT_UART2DM_IRQ				(GIC_SPI_START + 148)
+#define GSBI2_QUP_IRQ				(GIC_SPI_START + 149)
+#define INT_UART3DM_IRQ				(GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ				(GIC_SPI_START + 151)
+#define INT_UART4DM_IRQ				(GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ				(GIC_SPI_START + 153)
+#define INT_UART5DM_IRQ				(GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ				(GIC_SPI_START + 155)
+#define INT_UART6DM_IRQ				(GIC_SPI_START + 156)
+#define GSBI6_QUP_IRQ				(GIC_SPI_START + 157)
+#define INT_UART7DM_IRQ				(GIC_SPI_START + 158)
+#define GSBI7_QUP_IRQ				(GIC_SPI_START + 159)
+#define INT_UART8DM_IRQ				(GIC_SPI_START + 160)
+#define GSBI8_QUP_IRQ				(GIC_SPI_START + 161)
+#define TSIF_TSPP_IRQ				(GIC_SPI_START + 162)
+#define TSIF_BAM_IRQ				(GIC_SPI_START + 163)
+#define TSIF2_IRQ				(GIC_SPI_START + 164)
+#define TSIF1_IRQ				(GIC_SPI_START + 165)
+#define INT_ADM1_MASTER				(GIC_SPI_START + 166)
+#define INT_ADM1_AARM				(GIC_SPI_START + 167)
+#define INT_ADM1_SD2				(GIC_SPI_START + 168)
+#define INT_ADM1_SD3				(GIC_SPI_START + 169)
+#define INT_ADM0_MASTER				(GIC_SPI_START + 170)
+#define INT_ADM0_AARM				(GIC_SPI_START + 171)
+#define INT_ADM0_SD2				(GIC_SPI_START + 172)
+#define INT_ADM0_SD3				(GIC_SPI_START + 173)
+#define CC_SCSS_WDT1CPU1BITEEXPIRED		(GIC_SPI_START + 174)
+#define CC_SCSS_WDT1CPU0BITEEXPIRED		(GIC_SPI_START + 175)
+#define CC_SCSS_WDT0CPU1BITEEXPIRED		(GIC_SPI_START + 176)
+#define CC_SCSS_WDT0CPU0BITEEXPIRED		(GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT			(GIC_SPI_START + 178)
+#define SSBI2_2_SC_CPU1_SECURE_INT		(GIC_SPI_START + 179)
+#define SSBI2_2_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 180)
+#define SSBI2_1_SC_CPU1_SECURE_INT		(GIC_SPI_START + 181)
+#define SSBI2_1_SC_CPU1_NON_SECURE_INT		(GIC_SPI_START + 182)
+#define XPU_SUMMARY_IRQ				(GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ		(GIC_SPI_START + 184)
+#define HSDDRX_SMICH0_IRQ			(GIC_SPI_START + 185)
+#define HSDDRX_EBI1_IRQ				(GIC_SPI_START + 186)
+#define SDC5_BAM_IRQ				(GIC_SPI_START + 187)
+#define SDC5_IRQ_0				(GIC_SPI_START + 188)
+#define INT_UART9DM_IRQ				(GIC_SPI_START + 189)
+#define GSBI9_QUP_IRQ				(GIC_SPI_START + 190)
+#define INT_UART10DM_IRQ			(GIC_SPI_START + 191)
+#define GSBI10_QUP_IRQ				(GIC_SPI_START + 192)
+#define INT_UART11DM_IRQ			(GIC_SPI_START + 193)
+#define GSBI11_QUP_IRQ				(GIC_SPI_START + 194)
+#define INT_UART12DM_IRQ			(GIC_SPI_START + 195)
+#define GSBI12_QUP_IRQ				(GIC_SPI_START + 196)
+/*SPI 197 to 216 arent used in 8x60*/
+#define SMPSS_SPARE_1				(GIC_SPI_START + 217)
+#define SMPSS_SPARE_2				(GIC_SPI_START + 218)
+#define SMPSS_SPARE_3				(GIC_SPI_START + 219)
+#define SMPSS_SPARE_4				(GIC_SPI_START + 220)
+#define SMPSS_SPARE_5				(GIC_SPI_START + 221)
+#define SMPSS_SPARE_6				(GIC_SPI_START + 222)
+#define SMPSS_SPARE_7				(GIC_SPI_START + 223)
+
+#define NR_GPIO_IRQS 173
+#define NR_MSM_IRQS 256
+#define NR_BOARD_IRQS 0
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,8 @@
 #elif defined(CONFIG_ARCH_QSD8X50)
 #include "irqs-8x50.h"
 #include "sirc.h"
+#elif defined(CONFIG_ARCH_MSM8X60)
+#include "irqs-8x60.h"
 #elif defined(CONFIG_ARCH_MSM_ARM11)
 #include "irqs-7x00.h"
 #else
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/memory.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/memory.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/memory.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/memory.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,8 @@
 #define PHYS_OFFSET		UL(0x20000000)
 #elif defined(CONFIG_ARCH_MSM7X30)
 #define PHYS_OFFSET		UL(0x00200000)
+#elif defined(CONFIG_ARCH_MSM8X60)
+#define PHYS_OFFSET		UL(0x40200000)
 #else
 #define PHYS_OFFSET		UL(0x10000000)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8X60_H
+#define __ASM_ARCH_MSM_IOMAP_8X60_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * MSM_VIC_BASE must be an value that can be loaded via a "mov"
+ * instruction, otherwise entry-macro.S will not compile.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM_QGIC_DIST_BASE	IOMEM(0xF0000000)
+#define MSM_QGIC_DIST_PHYS	0x02080000
+#define MSM_QGIC_DIST_SIZE	SZ_4K
+
+#define MSM_QGIC_CPU_BASE	IOMEM(0xF0001000)
+#define MSM_QGIC_CPU_PHYS	0x02081000
+#define MSM_QGIC_CPU_SIZE	SZ_4K
+
+#define MSM_ACC_BASE		IOMEM(0xF0002000)
+#define MSM_ACC_PHYS		0x02001000
+#define MSM_ACC_SIZE		SZ_4K
+
+#define MSM_GCC_BASE		IOMEM(0xF0003000)
+#define MSM_GCC_PHYS		0x02082000
+#define MSM_GCC_SIZE		SZ_4K
+
+#define MSM_TLMM_BASE		IOMEM(0xF0004000)
+#define MSM_TLMM_PHYS		0x00800000
+#define MSM_TLMM_SIZE		SZ_16K
+
+#define MSM_SHARED_RAM_BASE	IOMEM(0xF0100000)
+#define MSM_SHARED_RAM_SIZE	SZ_1M
+
+#define MSM_TMR_BASE		IOMEM(0xF0200000)
+#define MSM_TMR_PHYS		0x02000000
+#define MSM_TMR_SIZE		(SZ_1M)
+
+#define MSM_GPT_BASE		(MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE		(MSM_TMR_BASE + 0x24)
+
+#define MSM_IOMMU_JPEGD_PHYS	0x07300000
+#define MSM_IOMMU_JPEGD_SIZE	SZ_1M
+
+#define MSM_IOMMU_VPE_PHYS	0x07400000
+#define MSM_IOMMU_VPE_SIZE	SZ_1M
+
+#define MSM_IOMMU_MDP0_PHYS	0x07500000
+#define MSM_IOMMU_MDP0_SIZE	SZ_1M
+
+#define MSM_IOMMU_MDP1_PHYS	0x07600000
+#define MSM_IOMMU_MDP1_SIZE	SZ_1M
+
+#define MSM_IOMMU_ROT_PHYS	0x07700000
+#define MSM_IOMMU_ROT_SIZE	SZ_1M
+
+#define MSM_IOMMU_IJPEG_PHYS	0x07800000
+#define MSM_IOMMU_IJPEG_SIZE	SZ_1M
+
+#define MSM_IOMMU_VFE_PHYS	0x07900000
+#define MSM_IOMMU_VFE_SIZE	SZ_1M
+
+#define MSM_IOMMU_VCODEC_A_PHYS	0x07A00000
+#define MSM_IOMMU_VCODEC_A_SIZE	SZ_1M
+
+#define MSM_IOMMU_VCODEC_B_PHYS	0x07B00000
+#define MSM_IOMMU_VCODEC_B_SIZE	SZ_1M
+
+#define MSM_IOMMU_GFX3D_PHYS	0x07C00000
+#define MSM_IOMMU_GFX3D_SIZE	SZ_1M
+
+#define MSM_IOMMU_GFX2D0_PHYS	0x07D00000
+#define MSM_IOMMU_GFX2D0_SIZE	SZ_1M
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/msm_iomap.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/msm_iomap.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/msm_iomap.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/msm_iomap.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,8 +47,12 @@
 #include "msm_iomap-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
 #include "msm_iomap-8x50.h"
+#elif defined(CONFIG_ARCH_MSM8X60)
+#include "msm_iomap-8x60.h"
 #else
 #include "msm_iomap-7x00.h"
 #endif
 
+
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/smp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Code Aurora nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SMP_H
+#define __ASM_ARCH_MSM_SMP_H
+
+#include <asm/hardware/gic.h>
+
+static inline void smp_cross_call(const struct cpumask *mask)
+{
+	gic_raise_softirq(mask, 1);
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 #ifndef __ASM_ARCH_MSM_VMALLOC_H
 #define __ASM_ARCH_MSM_VMALLOC_H
 
-#define VMALLOC_END	  (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END	  0xd0000000UL
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/io.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/io.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/io.c	2011-01-04 19:50:19.000000000 -0500
@@ -100,6 +100,21 @@
 }
 #endif /* CONFIG_ARCH_QSD8X50 */
 
+#ifdef CONFIG_ARCH_MSM8X60
+static struct map_desc msm8x60_io_desc[] __initdata = {
+	MSM_DEVICE(QGIC_DIST),
+	MSM_DEVICE(QGIC_CPU),
+	MSM_DEVICE(TMR),
+	MSM_DEVICE(ACC),
+	MSM_DEVICE(GCC),
+};
+
+void __init msm_map_msm8x60_io(void)
+{
+	iotable_init(msm8x60_io_desc, ARRAY_SIZE(msm8x60_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8X60 */
+
 #ifdef CONFIG_ARCH_MSM7X30
 static struct map_desc msm7x30_io_desc[] __initdata = {
 	MSM_DEVICE(VIC),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/iommu.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/iommu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/iommu.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,597 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/iommu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sizes.h>
+
+#include <mach/iommu_hw-8xxx.h>
+#include <mach/iommu.h>
+
+DEFINE_SPINLOCK(msm_iommu_lock);
+
+struct msm_priv {
+	unsigned long *pgtable;
+	struct list_head list_attached;
+};
+
+static void __flush_iotlb(struct iommu_domain *domain)
+{
+	struct msm_priv *priv = domain->priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+
+#ifndef CONFIG_IOMMU_PGTABLES_L2
+	unsigned long *fl_table = priv->pgtable;
+	int i;
+
+	dmac_flush_range(fl_table, fl_table + SZ_16K);
+
+	for (i = 0; i < NUM_FL_PTE; i++)
+		if ((fl_table[i] & 0x03) == FL_TYPE_TABLE) {
+			void *sl_table = __va(fl_table[i] & FL_BASE_MASK);
+			dmac_flush_range(sl_table, sl_table + SZ_4K);
+		}
+#endif
+
+	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
+		if (!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent)
+			BUG();
+
+		iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+		SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
+	}
+}
+
+static void __reset_context(void __iomem *base, int ctx)
+{
+	SET_BPRCOSH(base, ctx, 0);
+	SET_BPRCISH(base, ctx, 0);
+	SET_BPRCNSH(base, ctx, 0);
+	SET_BPSHCFG(base, ctx, 0);
+	SET_BPMTCFG(base, ctx, 0);
+	SET_ACTLR(base, ctx, 0);
+	SET_SCTLR(base, ctx, 0);
+	SET_FSRRESTORE(base, ctx, 0);
+	SET_TTBR0(base, ctx, 0);
+	SET_TTBR1(base, ctx, 0);
+	SET_TTBCR(base, ctx, 0);
+	SET_BFBCR(base, ctx, 0);
+	SET_PAR(base, ctx, 0);
+	SET_FAR(base, ctx, 0);
+	SET_CTX_TLBIALL(base, ctx, 0);
+	SET_TLBFLPTER(base, ctx, 0);
+	SET_TLBSLPTER(base, ctx, 0);
+	SET_TLBLKCR(base, ctx, 0);
+	SET_PRRR(base, ctx, 0);
+	SET_NMRR(base, ctx, 0);
+	SET_CONTEXTIDR(base, ctx, 0);
+}
+
+static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
+{
+	__reset_context(base, ctx);
+
+	/* Set up HTW mode */
+	/* TLB miss configuration: perform HTW on miss */
+	SET_TLBMCFG(base, ctx, 0x3);
+
+	/* V2P configuration: HTW for access */
+	SET_V2PCFG(base, ctx, 0x3);
+
+	SET_TTBCR(base, ctx, 0);
+	SET_TTBR0_PA(base, ctx, (pgtable >> 14));
+
+	/* Invalidate the TLB for this context */
+	SET_CTX_TLBIALL(base, ctx, 0);
+
+	/* Set interrupt number to "secure" interrupt */
+	SET_IRPTNDX(base, ctx, 0);
+
+	/* Enable context fault interrupt */
+	SET_CFEIE(base, ctx, 1);
+
+	/* Stall access on a context fault and let the handler deal with it */
+	SET_CFCFG(base, ctx, 1);
+
+	/* Redirect all cacheable requests to L2 slave port. */
+	SET_RCISH(base, ctx, 1);
+	SET_RCOSH(base, ctx, 1);
+	SET_RCNSH(base, ctx, 1);
+
+	/* Turn on TEX Remap */
+	SET_TRE(base, ctx, 1);
+
+	/* Do not configure PRRR / NMRR on the IOMMU for now. We will assume
+	 * TEX class 0 for everything until attributes are properly worked out
+	 */
+	SET_PRRR(base, ctx, 0);
+	SET_NMRR(base, ctx, 0);
+
+	/* Turn on BFB prefetch */
+	SET_BFBDFE(base, ctx, 1);
+
+#ifdef CONFIG_IOMMU_PGTABLES_L2
+	/* Configure page tables as inner-cacheable and shareable to reduce
+	 * the TLB miss penalty.
+	 */
+	SET_TTBR0_SH(base, ctx, 1);
+	SET_TTBR1_SH(base, ctx, 1);
+
+	SET_TTBR0_NOS(base, ctx, 1);
+	SET_TTBR1_NOS(base, ctx, 1);
+
+	SET_TTBR0_IRGNH(base, ctx, 0); /* WB, WA */
+	SET_TTBR0_IRGNL(base, ctx, 1);
+
+	SET_TTBR1_IRGNH(base, ctx, 0); /* WB, WA */
+	SET_TTBR1_IRGNL(base, ctx, 1);
+
+	SET_TTBR0_ORGN(base, ctx, 1); /* WB, WA */
+	SET_TTBR1_ORGN(base, ctx, 1); /* WB, WA */
+#endif
+
+	/* Enable the MMU */
+	SET_M(base, ctx, 1);
+}
+
+static int msm_iommu_domain_init(struct iommu_domain *domain)
+{
+	struct msm_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+
+	if (!priv)
+		goto fail_nomem;
+
+	INIT_LIST_HEAD(&priv->list_attached);
+	priv->pgtable = (unsigned long *)__get_free_pages(GFP_KERNEL,
+							  get_order(SZ_16K));
+
+	if (!priv->pgtable)
+		goto fail_nomem;
+
+	memset(priv->pgtable, 0, SZ_16K);
+	domain->priv = priv;
+	return 0;
+
+fail_nomem:
+	kfree(priv);
+	return -ENOMEM;
+}
+
+static void msm_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct msm_priv *priv;
+	unsigned long flags;
+	unsigned long *fl_table;
+	int i;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+	priv = domain->priv;
+	domain->priv = NULL;
+
+	if (priv) {
+		fl_table = priv->pgtable;
+
+		for (i = 0; i < NUM_FL_PTE; i++)
+			if ((fl_table[i] & 0x03) == FL_TYPE_TABLE)
+				free_page((unsigned long) __va(((fl_table[i]) &
+								FL_BASE_MASK)));
+
+		free_pages((unsigned long)priv->pgtable, get_order(SZ_16K));
+		priv->pgtable = NULL;
+	}
+
+	kfree(priv);
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+}
+
+static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_ctx_dev *ctx_dev;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	struct msm_iommu_ctx_drvdata *tmp_drvdata;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+
+	priv = domain->priv;
+
+	if (!priv || !dev) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	iommu_drvdata = dev_get_drvdata(dev->parent);
+	ctx_drvdata = dev_get_drvdata(dev);
+	ctx_dev = dev->platform_data;
+
+	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
+		if (tmp_drvdata == ctx_drvdata) {
+			ret = -EBUSY;
+			goto fail;
+		}
+
+	__program_context(iommu_drvdata->base, ctx_dev->num,
+			  __pa(priv->pgtable));
+
+	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
+	__flush_iotlb(domain);
+
+fail:
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	return ret;
+}
+
+static void msm_iommu_detach_dev(struct iommu_domain *domain,
+				 struct device *dev)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_ctx_dev *ctx_dev;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+	priv = domain->priv;
+
+	if (!priv || !dev)
+		goto fail;
+
+	iommu_drvdata = dev_get_drvdata(dev->parent);
+	ctx_drvdata = dev_get_drvdata(dev);
+	ctx_dev = dev->platform_data;
+
+	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev)
+		goto fail;
+
+	__flush_iotlb(domain);
+	__reset_context(iommu_drvdata->base, ctx_dev->num);
+	list_del_init(&ctx_drvdata->attached_elm);
+
+fail:
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+}
+
+static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
+			 phys_addr_t pa, int order, int prot)
+{
+	struct msm_priv *priv;
+	unsigned long flags;
+	unsigned long *fl_table;
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long *sl_pte;
+	unsigned long sl_offset;
+	size_t len = 0x1000UL << order;
+	int ret = 0;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+	priv = domain->priv;
+
+	if (!priv) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_table = priv->pgtable;
+
+	if (len != SZ_16M && len != SZ_1M &&
+	    len != SZ_64K && len != SZ_4K) {
+		pr_debug("Bad size: %d\n", len);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (!fl_table) {
+		pr_debug("Null page table\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
+	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	if (len == SZ_16M) {
+		int i = 0;
+		for (i = 0; i < 16; i++)
+			*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
+				  FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
+				  FL_SHARED;
+	}
+
+	if (len == SZ_1M)
+		*fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
+						FL_TYPE_SECT | FL_SHARED;
+
+	/* Need a 2nd level table */
+	if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
+		unsigned long *sl;
+		sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
+							get_order(SZ_4K));
+
+		if (!sl) {
+			pr_debug("Could not allocate second level table\n");
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		memset(sl, 0, SZ_4K);
+		*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | FL_TYPE_TABLE);
+	}
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+	sl_offset = SL_OFFSET(va);
+	sl_pte = sl_table + sl_offset;
+
+
+	if (len == SZ_4K)
+		*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
+					  SL_SHARED | SL_TYPE_SMALL;
+
+	if (len == SZ_64K) {
+		int i;
+
+		for (i = 0; i < 16; i++)
+			*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
+					    SL_AP1 | SL_SHARED | SL_TYPE_LARGE;
+	}
+
+	__flush_iotlb(domain);
+fail:
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	return ret;
+}
+
+static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
+			    int order)
+{
+	struct msm_priv *priv;
+	unsigned long flags;
+	unsigned long *fl_table;
+	unsigned long *fl_pte;
+	unsigned long fl_offset;
+	unsigned long *sl_table;
+	unsigned long *sl_pte;
+	unsigned long sl_offset;
+	size_t len = 0x1000UL << order;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+
+	priv = domain->priv;
+
+	if (!priv) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	fl_table = priv->pgtable;
+
+	if (len != SZ_16M && len != SZ_1M &&
+	    len != SZ_64K && len != SZ_4K) {
+		pr_debug("Bad length: %d\n", len);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	if (!fl_table) {
+		pr_debug("Null page table\n");
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
+	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
+
+	if (*fl_pte == 0) {
+		pr_debug("First level PTE is 0\n");
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	/* Unmap supersection */
+	if (len == SZ_16M)
+		for (i = 0; i < 16; i++)
+			*(fl_pte+i) = 0;
+
+	if (len == SZ_1M)
+		*fl_pte = 0;
+
+	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+	sl_offset = SL_OFFSET(va);
+	sl_pte = sl_table + sl_offset;
+
+	if (len == SZ_64K) {
+		for (i = 0; i < 16; i++)
+			*(sl_pte+i) = 0;
+	}
+
+	if (len == SZ_4K)
+		*sl_pte = 0;
+
+	if (len == SZ_4K || len == SZ_64K) {
+		int used = 0;
+
+		for (i = 0; i < NUM_SL_PTE; i++)
+			if (sl_table[i])
+				used = 1;
+		if (!used) {
+			free_page((unsigned long)sl_table);
+			*fl_pte = 0;
+		}
+	}
+
+	__flush_iotlb(domain);
+fail:
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	return ret;
+}
+
+static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
+					  unsigned long va)
+{
+	struct msm_priv *priv;
+	struct msm_iommu_drvdata *iommu_drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata;
+	unsigned int par;
+	unsigned long flags;
+	void __iomem *base;
+	phys_addr_t ret = 0;
+	int ctx;
+
+	spin_lock_irqsave(&msm_iommu_lock, flags);
+
+	priv = domain->priv;
+	if (list_empty(&priv->list_attached))
+		goto fail;
+
+	ctx_drvdata = list_entry(priv->list_attached.next,
+				 struct msm_iommu_ctx_drvdata, attached_elm);
+	iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+
+	base = iommu_drvdata->base;
+	ctx = ctx_drvdata->num;
+
+	/* Invalidate context TLB */
+	SET_CTX_TLBIALL(base, ctx, 0);
+	SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
+
+	if (GET_FAULT(base, ctx))
+		goto fail;
+
+	par = GET_PAR(base, ctx);
+
+	/* We are dealing with a supersection */
+	if (GET_NOFAULT_SS(base, ctx))
+		ret = (par & 0xFF000000) | (va & 0x00FFFFFF);
+	else	/* Upper 20 bits from PAR, lower 12 from VA */
+		ret = (par & 0xFFFFF000) | (va & 0x00000FFF);
+
+fail:
+	spin_unlock_irqrestore(&msm_iommu_lock, flags);
+	return ret;
+}
+
+static int msm_iommu_domain_has_cap(struct iommu_domain *domain,
+				    unsigned long cap)
+{
+	return 0;
+}
+
+static void print_ctx_regs(void __iomem *base, int ctx)
+{
+	unsigned int fsr = GET_FSR(base, ctx);
+	pr_err("FAR    = %08x    PAR    = %08x\n",
+	       GET_FAR(base, ctx), GET_PAR(base, ctx));
+	pr_err("FSR    = %08x [%s%s%s%s%s%s%s%s%s%s]\n", fsr,
+			(fsr & 0x02) ? "TF " : "",
+			(fsr & 0x04) ? "AFF " : "",
+			(fsr & 0x08) ? "APF " : "",
+			(fsr & 0x10) ? "TLBMF " : "",
+			(fsr & 0x20) ? "HTWDEEF " : "",
+			(fsr & 0x40) ? "HTWSEEF " : "",
+			(fsr & 0x80) ? "MHF " : "",
+			(fsr & 0x10000) ? "SL " : "",
+			(fsr & 0x40000000) ? "SS " : "",
+			(fsr & 0x80000000) ? "MULTI " : "");
+
+	pr_err("FSYNR0 = %08x    FSYNR1 = %08x\n",
+	       GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+	pr_err("TTBR0  = %08x    TTBR1  = %08x\n",
+	       GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+	pr_err("SCTLR  = %08x    ACTLR  = %08x\n",
+	       GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+	pr_err("PRRR   = %08x    NMRR   = %08x\n",
+	       GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+}
+
+irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
+{
+	struct msm_iommu_drvdata *drvdata = dev_id;
+	void __iomem *base;
+	unsigned int fsr = 0;
+	int ncb = 0, i = 0;
+
+	spin_lock(&msm_iommu_lock);
+
+	if (!drvdata) {
+		pr_err("Invalid device ID in context interrupt handler\n");
+		goto fail;
+	}
+
+	base = drvdata->base;
+
+	pr_err("===== WOAH! =====\n");
+	pr_err("Unexpected IOMMU page fault!\n");
+	pr_err("base = %08x\n", (unsigned int) base);
+
+	ncb = GET_NCB(base)+1;
+	for (i = 0; i < ncb; i++) {
+		fsr = GET_FSR(base, i);
+		if (fsr) {
+			pr_err("Fault occurred in context %d.\n", i);
+			pr_err("Interesting registers:\n");
+			print_ctx_regs(base, i);
+			SET_FSR(base, i, 0x4000000F);
+		}
+	}
+fail:
+	spin_unlock(&msm_iommu_lock);
+	return 0;
+}
+
+static struct iommu_ops msm_iommu_ops = {
+	.domain_init = msm_iommu_domain_init,
+	.domain_destroy = msm_iommu_domain_destroy,
+	.attach_dev = msm_iommu_attach_dev,
+	.detach_dev = msm_iommu_detach_dev,
+	.map = msm_iommu_map,
+	.unmap = msm_iommu_unmap,
+	.iova_to_phys = msm_iommu_iova_to_phys,
+	.domain_has_cap = msm_iommu_domain_has_cap
+};
+
+static int msm_iommu_init(void)
+{
+	register_iommu(&msm_iommu_ops);
+	return 0;
+}
+
+subsys_initcall(msm_iommu_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/iommu_dev.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/iommu_dev.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/iommu_dev.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/iommu_dev.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,378 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/iommu.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <mach/iommu_hw-8xxx.h>
+#include <mach/iommu.h>
+
+struct iommu_ctx_iter_data {
+	/* input */
+	const char *name;
+
+	/* output */
+	struct device *dev;
+};
+
+static struct platform_device *msm_iommu_root_dev;
+
+static int each_iommu_ctx(struct device *dev, void *data)
+{
+	struct iommu_ctx_iter_data *res = data;
+	struct msm_iommu_ctx_dev *c = dev->platform_data;
+
+	if (!res || !c || !c->name || !res->name)
+		return -EINVAL;
+
+	if (!strcmp(res->name, c->name)) {
+		res->dev = dev;
+		return 1;
+	}
+	return 0;
+}
+
+static int each_iommu(struct device *dev, void *data)
+{
+	return device_for_each_child(dev, data, each_iommu_ctx);
+}
+
+struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+	struct iommu_ctx_iter_data r;
+	int found;
+
+	if (!msm_iommu_root_dev) {
+		pr_err("No root IOMMU device.\n");
+		goto fail;
+	}
+
+	r.name = ctx_name;
+	found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
+
+	if (!found) {
+		pr_err("Could not find context <%s>\n", ctx_name);
+		goto fail;
+	}
+
+	return r.dev;
+fail:
+	return NULL;
+}
+EXPORT_SYMBOL(msm_iommu_get_ctx);
+
+static void msm_iommu_reset(void __iomem *base)
+{
+	int ctx, ncb;
+
+	SET_RPUE(base, 0);
+	SET_RPUEIE(base, 0);
+	SET_ESRRESTORE(base, 0);
+	SET_TBE(base, 0);
+	SET_CR(base, 0);
+	SET_SPDMBE(base, 0);
+	SET_TESTBUSCR(base, 0);
+	SET_TLBRSW(base, 0);
+	SET_GLOBAL_TLBIALL(base, 0);
+	SET_RPU_ACR(base, 0);
+	SET_TLBLKCRWE(base, 1);
+	ncb = GET_NCB(base)+1;
+
+	for (ctx = 0; ctx < ncb; ctx++) {
+		SET_BPRCOSH(base, ctx, 0);
+		SET_BPRCISH(base, ctx, 0);
+		SET_BPRCNSH(base, ctx, 0);
+		SET_BPSHCFG(base, ctx, 0);
+		SET_BPMTCFG(base, ctx, 0);
+		SET_ACTLR(base, ctx, 0);
+		SET_SCTLR(base, ctx, 0);
+		SET_FSRRESTORE(base, ctx, 0);
+		SET_TTBR0(base, ctx, 0);
+		SET_TTBR1(base, ctx, 0);
+		SET_TTBCR(base, ctx, 0);
+		SET_BFBCR(base, ctx, 0);
+		SET_PAR(base, ctx, 0);
+		SET_FAR(base, ctx, 0);
+		SET_CTX_TLBIALL(base, ctx, 0);
+		SET_TLBFLPTER(base, ctx, 0);
+		SET_TLBSLPTER(base, ctx, 0);
+		SET_TLBLKCR(base, ctx, 0);
+		SET_PRRR(base, ctx, 0);
+		SET_NMRR(base, ctx, 0);
+		SET_CONTEXTIDR(base, ctx, 0);
+	}
+}
+
+static int msm_iommu_probe(struct platform_device *pdev)
+{
+	struct resource *r, *r2;
+	struct clk *iommu_clk;
+	struct msm_iommu_drvdata *drvdata;
+	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
+	void __iomem *regs_base;
+	resource_size_t	len;
+	int ret = 0, ncb, nm2v, irq;
+
+	if (pdev->id != -1) {
+		drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+
+		if (!drvdata) {
+			ret = -ENOMEM;
+			goto fail;
+		}
+
+		if (!iommu_dev) {
+			ret = -ENODEV;
+			goto fail;
+		}
+
+		if (iommu_dev->clk_rate != 0) {
+			iommu_clk = clk_get(&pdev->dev, "iommu_clk");
+
+			if (IS_ERR(iommu_clk)) {
+				ret = -ENODEV;
+				goto fail;
+			}
+
+			if (iommu_dev->clk_rate > 0) {
+				ret = clk_set_rate(iommu_clk,
+							iommu_dev->clk_rate);
+				if (ret) {
+					clk_put(iommu_clk);
+					goto fail;
+				}
+			}
+
+			ret = clk_enable(iommu_clk);
+			if (ret) {
+				clk_put(iommu_clk);
+				goto fail;
+			}
+			clk_put(iommu_clk);
+		}
+
+		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						 "physbase");
+		if (!r) {
+			ret = -ENODEV;
+			goto fail;
+		}
+
+		len = r->end - r->start + 1;
+
+		r2 = request_mem_region(r->start, len, r->name);
+		if (!r2) {
+			pr_err("Could not request memory region: "
+			"start=%p, len=%d\n", (void *) r->start, len);
+			ret = -EBUSY;
+			goto fail;
+		}
+
+		regs_base = ioremap(r2->start, len);
+
+		if (!regs_base) {
+			pr_err("Could not ioremap: start=%p, len=%d\n",
+				 (void *) r2->start, len);
+			ret = -EBUSY;
+			goto fail_mem;
+		}
+
+		irq = platform_get_irq_byname(pdev, "secure_irq");
+		if (irq < 0) {
+			ret = -ENODEV;
+			goto fail_io;
+		}
+
+		mb();
+
+		if (GET_IDR(regs_base) == 0) {
+			pr_err("Invalid IDR value detected\n");
+			ret = -ENODEV;
+			goto fail_io;
+		}
+
+		ret = request_irq(irq, msm_iommu_fault_handler, 0,
+				"msm_iommu_secure_irpt_handler", drvdata);
+		if (ret) {
+			pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
+			goto fail_io;
+		}
+
+		msm_iommu_reset(regs_base);
+		drvdata->base = regs_base;
+		drvdata->irq = irq;
+
+		nm2v = GET_NM2VCBMT((unsigned long) regs_base);
+		ncb = GET_NCB((unsigned long) regs_base);
+
+		pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
+			iommu_dev->name, regs_base, irq, ncb+1);
+
+		platform_set_drvdata(pdev, drvdata);
+	} else
+		msm_iommu_root_dev = pdev;
+
+	return 0;
+
+fail_io:
+	iounmap(regs_base);
+fail_mem:
+	release_mem_region(r->start, len);
+fail:
+	kfree(drvdata);
+	return ret;
+}
+
+static int msm_iommu_remove(struct platform_device *pdev)
+{
+	struct msm_iommu_drvdata *drv = NULL;
+
+	drv = platform_get_drvdata(pdev);
+	if (drv) {
+		memset(drv, 0, sizeof(struct msm_iommu_drvdata));
+		kfree(drv);
+		platform_set_drvdata(pdev, NULL);
+	}
+	return 0;
+}
+
+static int msm_iommu_ctx_probe(struct platform_device *pdev)
+{
+	struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
+	struct msm_iommu_drvdata *drvdata;
+	struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
+	int i, ret = 0;
+	if (!c || !pdev->dev.parent) {
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	drvdata = dev_get_drvdata(pdev->dev.parent);
+
+	if (!drvdata) {
+		ret = -ENODEV;
+		goto fail;
+	}
+
+	ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
+	if (!ctx_drvdata) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+	ctx_drvdata->num = c->num;
+	ctx_drvdata->pdev = pdev;
+
+	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
+	platform_set_drvdata(pdev, ctx_drvdata);
+
+	/* Program the M2V tables for this context */
+	for (i = 0; i < MAX_NUM_MIDS; i++) {
+		int mid = c->mids[i];
+		if (mid == -1)
+			break;
+
+		SET_M2VCBR_N(drvdata->base, mid, 0);
+		SET_CBACR_N(drvdata->base, c->num, 0);
+
+		/* Set VMID = MID */
+		SET_VMID(drvdata->base, mid, mid);
+
+		/* Set the context number for that MID to this context */
+		SET_CBNDX(drvdata->base, mid, c->num);
+
+		/* Set MID associated with this context bank */
+		SET_CBVMID(drvdata->base, c->num, mid);
+
+		/* Set security bit override to be Non-secure */
+		SET_NSCFG(drvdata->base, mid, 3);
+	}
+
+	pr_info("context device %s with bank index %d\n", c->name, c->num);
+
+	return 0;
+fail:
+	kfree(ctx_drvdata);
+	return ret;
+}
+
+static int msm_iommu_ctx_remove(struct platform_device *pdev)
+{
+	struct msm_iommu_ctx_drvdata *drv = NULL;
+	drv = platform_get_drvdata(pdev);
+	if (drv) {
+		memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
+		kfree(drv);
+		platform_set_drvdata(pdev, NULL);
+	}
+	return 0;
+}
+
+static struct platform_driver msm_iommu_driver = {
+	.driver = {
+		.name	= "msm_iommu",
+	},
+	.probe		= msm_iommu_probe,
+	.remove		= msm_iommu_remove,
+};
+
+static struct platform_driver msm_iommu_ctx_driver = {
+	.driver = {
+		.name	= "msm_iommu_ctx",
+	},
+	.probe		= msm_iommu_ctx_probe,
+	.remove		= msm_iommu_ctx_remove,
+};
+
+static int msm_iommu_driver_init(void)
+{
+	int ret;
+	ret = platform_driver_register(&msm_iommu_driver);
+	if (ret != 0) {
+		pr_err("Failed to register IOMMU driver\n");
+		goto error;
+	}
+
+	ret = platform_driver_register(&msm_iommu_ctx_driver);
+	if (ret != 0) {
+		pr_err("Failed to register IOMMU context driver\n");
+		goto error;
+	}
+
+error:
+	return ret;
+}
+
+static void msm_iommu_driver_exit(void)
+{
+	platform_driver_unregister(&msm_iommu_ctx_driver);
+	platform_driver_unregister(&msm_iommu_driver);
+}
+
+subsys_initcall(msm_iommu_driver_init);
+module_exit(msm_iommu_driver_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-msm/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -6,26 +6,45 @@
 
 config ARCH_MSM7X00A
 	bool "MSM7x00A / MSM7x01A"
+	select MACH_TROUT if !MACH_HALIBUT
 	select ARCH_MSM_ARM11
 	select MSM_SMD
 	select MSM_SMD_PKG3
 	select CPU_V6
+	select MSM_PROC_COMM
+	select HAS_MSM_DEBUG_UART_PHYS
 
 config ARCH_MSM7X30
 	bool "MSM7x30"
+	select MACH_MSM7X30_SURF # if !
 	select ARCH_MSM_SCORPION
 	select MSM_SMD
 	select MSM_VIC
 	select CPU_V7
-	select MSM_REMOTE_SPINLOCK_DEKKERS
+	select MSM_GPIOMUX
+	select MSM_PROC_COMM
+	select HAS_MSM_DEBUG_UART_PHYS
 
 config ARCH_QSD8X50
 	bool "QSD8X50"
+	select MACH_QSD8X50_SURF if !MACH_QSD8X50A_ST1_5
 	select ARCH_MSM_SCORPION
 	select MSM_SMD
 	select MSM_VIC
 	select CPU_V7
-	select MSM_REMOTE_SPINLOCK_LDREX
+	select MSM_GPIOMUX
+	select MSM_PROC_COMM
+	select HAS_MSM_DEBUG_UART_PHYS
+
+config ARCH_MSM8X60
+	bool "MSM8X60"
+	select MACH_MSM8X60_SURF if (!MACH_MSM8X60_RUMI3 && !MACH_MSM8X60_SIM \
+				  && !MACH_MSM8X60_FFA)
+	select ARM_GIC
+	select CPU_V7
+	select MSM_V2_TLMM
+	select MSM_GPIOMUX
+
 endchoice
 
 config MSM_SOC_REV_A
@@ -36,6 +55,9 @@
 config  ARCH_MSM_SCORPION
 	bool
 
+config HAS_MSM_DEBUG_UART_PHYS
+	bool
+
 config  MSM_VIC
 	bool
 
@@ -74,6 +96,30 @@
 	help
 	  Support for the Qualcomm ST1.5.
 
+config MACH_MSM8X60_RUMI3
+	depends on ARCH_MSM8X60
+	bool "MSM8x60 RUMI3"
+	help
+	  Support for the Qualcomm MSM8x60 RUMI3 emulator.
+
+config MACH_MSM8X60_SURF
+	depends on ARCH_MSM8X60
+	bool "MSM8x60 SURF"
+	help
+	  Support for the Qualcomm MSM8x60 SURF eval board.
+
+config MACH_MSM8X60_SIM
+	depends on ARCH_MSM8X60
+	bool "MSM8x60 Simulator"
+	help
+	  Support for the Qualcomm MSM8x60 simulator.
+
+config MACH_MSM8X60_FFA
+	depends on ARCH_MSM8X60
+	bool "MSM8x60 FFA"
+	help
+	  Support for the Qualcomm MSM8x60 FFA eval board.
+
 endmenu
 
 config MSM_DEBUG_UART
@@ -82,6 +128,7 @@
 	default 2 if MSM_DEBUG_UART2
 	default 3 if MSM_DEBUG_UART3
 
+if HAS_MSM_DEBUG_UART_PHYS
 choice
 	prompt "Debug UART"
 
@@ -99,11 +146,20 @@
 	config MSM_DEBUG_UART3
 		bool "UART3"
 endchoice
+endif
 
 config MSM_SMD_PKG3
 	bool
 
+config MSM_PROC_COMM
+	bool
+
 config MSM_SMD
 	bool
 
+config MSM_GPIOMUX
+	bool
+
+config MSM_V2_TLMM
+	bool
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/last_radio_log.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/last_radio_log.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/last_radio_log.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/last_radio_log.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,7 +48,8 @@
 }
 
 static struct file_operations last_radio_log_fops = {
-	.read = last_radio_log_read
+	.read = last_radio_log_read,
+	.llseek = default_llseek,
 };
 
 void msm_init_last_radio_log(struct module *owner)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-msm/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,16 +1,20 @@
-obj-y += proc_comm.o
-obj-y += io.o idle.o timer.o dma.o
-obj-y += vreg.o
+obj-y += io.o idle.o timer.o
+ifndef CONFIG_ARCH_MSM8X60
 obj-y += acpuclock-arm11.o
-obj-y += clock.o clock-pcom.o
-obj-y += gpio.o
+obj-y += dma.o
+endif
 
 ifdef CONFIG_MSM_VIC
 obj-y += irq-vic.o
 else
+ifndef CONFIG_ARCH_MSM8X60
 obj-y += irq.o
 endif
+endif
 
+obj-$(CONFIG_ARCH_MSM8X60) += clock-dummy.o iommu.o iommu_dev.o devices-msm8x60-iommu.o
+obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o clock-pcom.o vreg.o
+obj-$(CONFIG_MSM_PROC_COMM) += clock.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
@@ -19,4 +23,11 @@
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
+obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60.o
 
+obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
+ifndef CONFIG_MSM_V2_TLMM
+obj-y	+= gpio.o
+endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/smd_debug.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/smd_debug.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/smd_debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/smd_debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -212,6 +212,7 @@
 static const struct file_operations debug_ops = {
 	.read = debug_read,
 	.open = debug_open,
+	.llseek = default_llseek,
 };
 
 static void debug_create(const char *name, mode_t mode,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-msm/timer.c linux-libre-2.6.37-gnu/arch/arm/mach-msm/timer.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-msm/timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-msm/timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #ifndef MSM_DGT_BASE
 #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
 #endif
-#define MSM_DGT_SHIFT (5)
 
 #define TIMER_MATCH_VAL         0x0000
 #define TIMER_COUNT_VAL         0x0004
@@ -36,12 +35,28 @@
 #define TIMER_ENABLE_CLR_ON_MATCH_EN    2
 #define TIMER_ENABLE_EN                 1
 #define TIMER_CLEAR             0x000C
-
+#define DGT_CLK_CTL             0x0034
+enum {
+	DGT_CLK_CTL_DIV_1 = 0,
+	DGT_CLK_CTL_DIV_2 = 1,
+	DGT_CLK_CTL_DIV_3 = 2,
+	DGT_CLK_CTL_DIV_4 = 3,
+};
 #define CSR_PROTECTION          0x0020
 #define CSR_PROTECTION_EN               1
 
 #define GPT_HZ 32768
+
+#if defined(CONFIG_ARCH_QSD8X50)
+#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#elif defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60)
+#define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#else
 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+#define MSM_DGT_SHIFT (5)
+#endif
 
 struct msm_clock {
 	struct clock_event_device   clockevent;
@@ -122,7 +137,7 @@
 			.rating         = 200,
 			.read           = msm_gpt_read,
 			.mask           = CLOCKSOURCE_MASK(32),
-			.shift          = 24,
+			.shift          = 17,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
 		.irq = {
@@ -170,6 +185,10 @@
 	int i;
 	int res;
 
+#ifdef CONFIG_ARCH_MSM8X60
+	writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+#endif
+
 	for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
 		struct msm_clock *clock = &msm_clocks[i];
 		struct clock_event_device *ce = &clock->clockevent;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -145,8 +145,6 @@
 
 MACHINE_START(TERASTATION_WXL, "Buffalo Nas WXL")
 	/* Maintainer: Sebastien Requiem <sebastien@requiem.fr> */
-	.phys_io	= MV78XX0_REGS_PHYS_BASE,
-	.io_pg_offst	= ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= wxl_init,
 	.map_io		= mv78xx0_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/db78x00-bp-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/db78x00-bp-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/db78x00-bp-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/db78x00-bp-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,8 +93,6 @@
 
 MACHINE_START(DB78X00_BP, "Marvell DB-78x00-BP Development Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= MV78XX0_REGS_PHYS_BASE,
-	.io_pg_offst	= ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= db78x00_init,
 	.map_io		= mv78xx0_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,12 +8,11 @@
 
 #include <mach/mv78xx0.h>
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =MV78XX0_REGS_PHYS_BASE
-	ldrne	\rx, =MV78XX0_REGS_VIRT_BASE
-	orr	\rx, \rx, #0x00012000
+	.macro	addruart, rp, rv
+	ldr	\rp, =MV78XX0_REGS_PHYS_BASE
+	ldr	\rv, =MV78XX0_REGS_VIRT_BASE
+	orr	\rp, \rp, #0x00012000
+	orr	\rv, \rv, #0x00012000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/mpp.c linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/mpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/mpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/mpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,7 @@
 	}
 	printk("\n");
 
-	while (*mpp_list) {
+	for ( ; *mpp_list; mpp_list++) {
 		unsigned int num = MPP_NUM(*mpp_list);
 		unsigned int sel = MPP_SEL(*mpp_list);
 		int shift, gpio_mode;
@@ -83,8 +83,6 @@
 		if (sel != 0)
 			gpio_mode = 0;
 		orion_gpio_set_valid(num, gpio_mode);
-
-		mpp_list++;
 	}
 
 	printk(KERN_DEBUG "  final MPP regs:");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,8 +78,6 @@
 
 MACHINE_START(RD78X00_MASA, "Marvell RD-78x00-MASA Development Board")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= MV78XX0_REGS_PHYS_BASE,
-	.io_pg_offst	= ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd78x00_masa_init,
 	.map_io		= mv78xx0_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-mx25/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 	unsigned long rate = get_rate_mpll();
 
 	if (cctl & (1 << 14))
-		rate = (rate * 3) >> 1;
+		rate = (rate * 3) >> 2;
 
 	return rate / ((cctl >> 30) + 1);
 }
@@ -99,7 +99,7 @@
 	if (readl(CRM_BASE + 0x64) & (1 << per))
 		fref = get_rate_upll();
 	else
-		fref = get_rate_ipg(NULL);
+		fref = get_rate_ahb(NULL);
 
 	return fref / (val + 1);
 }
@@ -139,6 +139,16 @@
 	return get_rate_per(7);
 }
 
+static unsigned long get_rate_esdhc1(struct clk *clk)
+{
+	return get_rate_per(3);
+}
+
+static unsigned long get_rate_esdhc2(struct clk *clk)
+{
+	return get_rate_per(4);
+}
+
 static unsigned long get_rate_csi(struct clk *clk)
 {
 	return get_rate_per(0);
@@ -213,6 +223,12 @@
 DEFINE_CLOCK(cspi1_clk,  0, CCM_CGCR1,  5, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi2_clk,  0, CCM_CGCR1,  6, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi3_clk,  0, CCM_CGCR1,  7, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, get_rate_esdhc1,	 NULL, NULL);
+DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0,  3, get_rate_esdhc1,	 NULL,
+		&esdhc1_ahb_clk);
+DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2,	 NULL, NULL);
+DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0,  4, get_rate_esdhc2,	 NULL,
+		&esdhc2_ahb_clk);
 DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL,	 NULL, NULL);
 DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL,	 NULL, NULL);
 DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0,  7, NULL,	 NULL, &lcdc_ahb_clk);
@@ -238,10 +254,14 @@
 DEFINE_CLOCK(wdt_clk,    0, CCM_CGCR2, 19, get_rate_ipg, NULL,  NULL);
 DEFINE_CLOCK(ssi1_clk,  0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk);
 DEFINE_CLOCK(ssi2_clk,  1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk);
+DEFINE_CLOCK(esdhc1_clk,  0, CCM_CGCR1, 13, get_rate_esdhc1, NULL,
+		&esdhc1_per_clk);
+DEFINE_CLOCK(esdhc2_clk,  1, CCM_CGCR1, 14, get_rate_esdhc2, NULL,
+		&esdhc2_per_clk);
 DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL);
 DEFINE_CLOCK(csi_clk,    0, CCM_CGCR1,  4, get_rate_csi, NULL,  &csi_per_clk);
 DEFINE_CLOCK(can1_clk,	 0, CCM_CGCR1,  2, get_rate_ipg, NULL, NULL);
-DEFINE_CLOCK(can2_clk,	 0, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(can2_clk,	 1, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
 
 #define _REGISTER_CLOCK(d, n, c)	\
 	{				\
@@ -261,9 +281,9 @@
 	_REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
 	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
 	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
-	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+	_REGISTER_CLOCK("imx25-cspi.0", NULL, cspi1_clk)
+	_REGISTER_CLOCK("imx25-cspi.1", NULL, cspi2_clk)
+	_REGISTER_CLOCK("imx25-cspi.2", NULL, cspi3_clk)
 	_REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk)
 	_REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
 	_REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)
@@ -279,6 +299,8 @@
 	_REGISTER_CLOCK("imx-wdt.0", NULL, wdt_clk)
 	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
 	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
 	_REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
 	_REGISTER_CLOCK(NULL, "audmux", audmux_clk)
 	_REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -208,26 +208,6 @@
 	return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
 
-static struct resource mx25_fec_resources[] = {
-	{
-		.start	= MX25_FEC_BASE_ADDR,
-		.end	= MX25_FEC_BASE_ADDR + 0xfff,
-		.flags	= IORESOURCE_MEM,
-	},
-	{
-		.start	= MX25_INT_FEC,
-		.end	= MX25_INT_FEC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mx25_fec_device = {
-	.name	= "fec",
-	.id	= 0,
-	.num_resources	= ARRAY_SIZE(mx25_fec_resources),
-	.resource	= mx25_fec_resources,
-};
-
 static struct resource mx25_rtc_resources[] = {
 	{
 		.start	= MX25_DRYICE_BASE_ADDR,
@@ -305,44 +285,6 @@
 	.resource	= mx25_kpp_resources,
 };
 
-static struct resource imx_ssi_resources0[] = {
-	{
-		.start	= MX25_SSI1_BASE_ADDR,
-		.end	= MX25_SSI1_BASE_ADDR + 0x3fff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= MX25_INT_SSI1,
-		.end	= MX25_INT_SSI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct resource imx_ssi_resources1[] = {
-	{
-		.start	= MX25_SSI2_BASE_ADDR,
-		.end	= MX25_SSI2_BASE_ADDR + 0x3fff,
-		.flags	= IORESOURCE_MEM
-	}, {
-		.start	= MX25_INT_SSI2,
-		.end	= MX25_INT_SSI2,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device imx_ssi_device0 = {
-	.name = "imx-ssi",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(imx_ssi_resources0),
-	.resource = imx_ssi_resources0,
-};
-
-struct platform_device imx_ssi_device1 = {
-	.name = "imx-ssi",
-	.id = 1,
-	.num_resources = ARRAY_SIZE(imx_ssi_resources1),
-	.resource = imx_ssi_resources1,
-};
-
 static struct resource mx25_csi_resources[] = {
 	{
 		.start	= MX25_CSI_BASE_ADDR,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -6,11 +6,8 @@
 extern struct platform_device mxc_pwm_device2;
 extern struct platform_device mxc_pwm_device3;
 extern struct platform_device mxc_keypad_device;
-extern struct platform_device mx25_fec_device;
 extern struct platform_device mx25_rtc_device;
 extern struct platform_device mx25_fb_device;
 extern struct platform_device mxc_wdt;
 extern struct platform_device mx25_kpp_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device mx25_csi_device;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices-imx25.h linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices-imx25.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/devices-imx25.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/devices-imx25.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,35 +9,46 @@
 #include <mach/mx25.h>
 #include <mach/devices-common.h>
 
+extern const struct imx_fec_data imx25_fec_data __initconst;
+#define imx25_add_fec(pdata)	\
+	imx_add_fec(&imx25_fec_data, pdata)
+
 #define imx25_add_flexcan0(pdata)	\
 	imx_add_flexcan(0, MX25_CAN1_BASE_ADDR, SZ_16K, MX25_INT_CAN1, pdata)
 #define imx25_add_flexcan1(pdata)	\
 	imx_add_flexcan(1, MX25_CAN2_BASE_ADDR, SZ_16K, MX25_INT_CAN2, pdata)
 
-#define imx25_add_imx_i2c0(pdata)	\
-	imx_add_imx_i2c(0, MX25_I2C1_BASE_ADDR, SZ_16K, MX25_INT_I2C1, pdata)
-#define imx25_add_imx_i2c1(pdata)	\
-	imx_add_imx_i2c(1, MX25_I2C2_BASE_ADDR, SZ_16K, MX25_INT_I2C2, pdata)
-#define imx25_add_imx_i2c2(pdata)	\
-	imx_add_imx_i2c(2, MX25_I2C3_BASE_ADDR, SZ_16K, MX25_INT_I2C3, pdata)
+extern const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst;
+#define imx25_add_imx_i2c(id, pdata)	\
+	imx_add_imx_i2c(&imx25_imx_i2c_data[id], pdata)
+#define imx25_add_imx_i2c0(pdata)	imx25_add_imx_i2c(0, pdata)
+#define imx25_add_imx_i2c1(pdata)	imx25_add_imx_i2c(1, pdata)
+#define imx25_add_imx_i2c2(pdata)	imx25_add_imx_i2c(2, pdata)
 
-#define imx25_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_1irq(0, MX25_UART1_BASE_ADDR, SZ_16K, MX25_INT_UART1, pdata)
-#define imx25_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_1irq(1, MX25_UART2_BASE_ADDR, SZ_16K, MX25_INT_UART2, pdata)
-#define imx25_add_imx_uart2(pdata)	\
-	imx_add_imx_uart_1irq(2, MX25_UART3_BASE_ADDR, SZ_16K, MX25_INT_UART3, pdata)
-#define imx25_add_imx_uart3(pdata)	\
-	imx_add_imx_uart_1irq(3, MX25_UART4_BASE_ADDR, SZ_16K, MX25_INT_UART4, pdata)
-#define imx25_add_imx_uart4(pdata)	\
-	imx_add_imx_uart_1irq(4, MX25_UART5_BASE_ADDR, SZ_16K, MX25_INT_UART5, pdata)
+extern const struct imx_imx_ssi_data imx25_imx_ssi_data[] __initconst;
+#define imx25_add_imx_ssi(id, pdata)	\
+	imx_add_imx_ssi(&imx25_imx_ssi_data[id], pdata)
 
+extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst;
+#define imx25_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx25_imx_uart_data[id], pdata)
+#define imx25_add_imx_uart0(pdata)	imx25_add_imx_uart(0, pdata)
+#define imx25_add_imx_uart1(pdata)	imx25_add_imx_uart(1, pdata)
+#define imx25_add_imx_uart2(pdata)	imx25_add_imx_uart(2, pdata)
+#define imx25_add_imx_uart3(pdata)	imx25_add_imx_uart(3, pdata)
+#define imx25_add_imx_uart4(pdata)	imx25_add_imx_uart(4, pdata)
+
+extern const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst;
 #define imx25_add_mxc_nand(pdata)	\
-	imx_add_mxc_nand_v21(MX25_NFC_BASE_ADDR, MX25_INT_NANDFC, pdata)
+	imx_add_mxc_nand(&imx25_mxc_nand_data, pdata)
 
-#define imx25_add_spi_imx0(pdata)	\
-	imx_add_spi_imx(0, MX25_CSPI1_BASE_ADDR, SZ_16K, MX25_INT_CSPI1, pdata)
-#define imx25_add_spi_imx1(pdata)	\
-	imx_add_spi_imx(1, MX25_CSPI2_BASE_ADDR, SZ_16K, MX25_INT_CSPI2, pdata)
-#define imx25_add_spi_imx2(pdata)	\
-	imx_add_spi_imx(2, MX25_CSPI3_BASE_ADDR, SZ_16K, MX25_INT_CSPI3, pdata)
+extern const struct imx_spi_imx_data imx25_cspi_data[] __initconst;
+#define imx25_add_spi_imx(id, pdata)	\
+	imx_add_spi_imx(&imx25_cspi_data[id], pdata)
+#define imx25_add_spi_imx0(pdata)	imx25_add_spi_imx(0, pdata)
+#define imx25_add_spi_imx1(pdata)	imx25_add_spi_imx(1, pdata)
+#define imx25_add_spi_imx2(pdata)	imx25_add_spi_imx(2, pdata)
+
+extern const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst;
+#define imx25_add_esdhc(id, pdata)	\
+	imx_add_esdhc(&imx25_esdhc_data[id], pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,6 @@
 #include <mach/mx25.h>
 #include <mach/imx-uart.h>
 #include <mach/imxfb.h>
-#include <mach/ssi.h>
 #include <mach/audmux.h>
 
 #include "devices-imx25.h"
@@ -90,6 +89,9 @@
 	MX25_PAD_KPP_COL2__AUD5_TXC,
 	MX25_PAD_KPP_COL1__AUD5_RXD,
 	MX25_PAD_KPP_COL0__AUD5_TXD,
+	/* CAN */
+	MX25_PAD_GPIO_D__CAN2_RX,
+	MX25_PAD_GPIO_C__CAN2_TX,
 };
 
 #define GPIO_LED1	83
@@ -114,6 +116,38 @@
 		},
 		.bpp	= 16,
 		.pcr	= 0xCAD08B80,
+	}, {
+		.mode = {
+			.name		= "DVI-VGA",
+			.refresh	= 60,
+			.xres		= 640,
+			.yres		= 480,
+			.pixclock	= 32000,
+			.hsync_len	= 7,
+			.left_margin	= 100,
+			.right_margin	= 100,
+			.vsync_len	= 7,
+			.upper_margin	= 7,
+			.lower_margin	= 100,
+		},
+		.pcr		= 0xFA208B80,
+		.bpp		= 16,
+	}, {
+		.mode = {
+			.name		= "DVI-SVGA",
+			.refresh	= 60,
+			.xres		= 800,
+			.yres		= 600,
+			.pixclock	= 25000,
+			.hsync_len	= 7,
+			.left_margin	= 75,
+			.right_margin	= 75,
+			.vsync_len	= 7,
+			.upper_margin	= 7,
+			.lower_margin	= 75,
+		},
+		.pcr		= 0xFA208B80,
+		.bpp		= 16,
 	},
 };
 
@@ -205,7 +239,8 @@
 	},
 };
 
-struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 	.flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -239,7 +274,10 @@
 
 	imx25_add_imx_uart1(&uart_pdata);
 	mxc_register_device(&mx25_fb_device, &eukrea_mximxsd_fb_pdata);
-	mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+	imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
+
+	imx25_add_flexcan1(NULL);
+	imx25_add_esdhc(0, NULL);
 
 	gpio_request(GPIO_LED1, "LED1");
 	gpio_direction_output(GPIO_LED1, 1);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-mx25/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -6,12 +6,15 @@
 	bool "Support MX25PDK (3DS) Platform"
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_MXC_NAND
+	select IMX_HAVE_PLATFORM_ESDHC
 
 config MACH_EUKREA_CPUIMX25
 	bool "Support Eukrea CPUIMX25 Platform"
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_MXC_NAND
+	select IMX_HAVE_PLATFORM_FLEXCAN
+	select IMX_HAVE_PLATFORM_ESDHC
 	select MXC_ULPI if USB_ULPI
 
 choice
@@ -20,8 +23,8 @@
 	default MACH_EUKREA_MBIMXSD25_BASEBOARD
 
 config MACH_EUKREA_MBIMXSD25_BASEBOARD
-	prompt "Eukrea MBIMXSD development board"
-	bool
+	bool "Eukrea MBIMXSD development board"
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	help
 	  This adds board specific devices that can be found on Eukrea's
 	  MBIMXSD evaluation board.
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/mach-cpuimx25.c linux-libre-2.6.37-gnu/arch/arm/mach-mx25/mach-cpuimx25.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/mach-cpuimx25.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/mach-cpuimx25.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
-#include <linux/fec.h>
 #include <linux/platform_device.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
@@ -41,7 +40,6 @@
 #include <mach/mxc_nand.h>
 #include <mach/imxfb.h>
 #include <mach/mxc_ehci.h>
-#include <mach/ulpi.h>
 #include <mach/iomux-mx25.h>
 
 #include "devices-imx25.h"
@@ -67,7 +65,7 @@
 	MX25_PAD_I2C1_DAT__I2C1_DAT,
 };
 
-static struct fec_platform_data mx25_fec_pdata = {
+static const struct fec_platform_data mx25_fec_pdata __initconst = {
 	.phy	= PHY_INTERFACE_MODE_RMII,
 };
 
@@ -129,24 +127,19 @@
 	imx25_add_imx_uart0(&uart_pdata);
 	imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
 	mxc_register_device(&mx25_rtc_device, NULL);
-	mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+	imx25_add_fec(&mx25_fec_pdata);
 
 	i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
 				ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
 	imx25_add_imx_i2c0(&eukrea_cpuimx25_i2c0_data);
 
-#if defined(CONFIG_USB_ULPI)
-	if (otg_mode_host) {
-		otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
-				ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
+	if (otg_mode_host)
 		mxc_register_device(&mxc_otg, &otg_pdata);
-	}
-	mxc_register_device(&mxc_usbh2, &usbh2_pdata);
-#endif
-	if (!otg_mode_host)
+	else
 		mxc_register_device(&otg_udc_device, &otg_device_pdata);
 
+	mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+
 #ifdef CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD
 	eukrea_mbimxsd25_baseboard_init();
 #endif
@@ -163,8 +156,6 @@
 
 MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
 	/* Maintainer: Eukrea Electromatique */
-	.phys_io	= MX25_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX25_PHYS_OFFSET + 0x100,
 	.map_io         = mx25_map_io,
 	.init_irq       = mx25_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx25/mach-mx25_3ds.c linux-libre-2.6.37-gnu/arch/arm/mach-mx25/mach-mx25_3ds.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx25/mach-mx25_3ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx25/mach-mx25_3ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
-#include <linux/fec.h>
 #include <linux/platform_device.h>
 #include <linux/input/matrix_keypad.h>
 
@@ -97,9 +96,17 @@
 	MX25_PAD_KPP_COL1__KPP_COL1,
 	MX25_PAD_KPP_COL2__KPP_COL2,
 	MX25_PAD_KPP_COL3__KPP_COL3,
+
+	/* SD1 */
+	MX25_PAD_SD1_CMD__SD1_CMD,
+	MX25_PAD_SD1_CLK__SD1_CLK,
+	MX25_PAD_SD1_DATA0__SD1_DATA0,
+	MX25_PAD_SD1_DATA1__SD1_DATA1,
+	MX25_PAD_SD1_DATA2__SD1_DATA2,
+	MX25_PAD_SD1_DATA3__SD1_DATA3,
 };
 
-static struct fec_platform_data mx25_fec_pdata = {
+static const struct fec_platform_data mx25_fec_pdata __initconst = {
         .phy    = PHY_INTERFACE_MODE_RMII,
 };
 
@@ -192,8 +199,10 @@
 	mxc_register_device(&mxc_wdt, NULL);
 
 	mx25pdk_fec_reset();
-	mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+	imx25_add_fec(&mx25_fec_pdata);
 	mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data);
+
+	imx25_add_esdhc(0, NULL);
 }
 
 static void __init mx25pdk_timer_init(void)
@@ -207,8 +216,6 @@
 
 MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)")
 	/* Maintainer: Freescale Semiconductor, Inc. */
-	.phys_io	= MX25_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX25_PHYS_OFFSET + 0x100,
 	.map_io         = mx25_map_io,
 	.init_irq       = mx25_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/clock-imx31.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/clock-imx31.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/clock-imx31.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/clock-imx31.c	2011-01-04 19:50:19.000000000 -0500
@@ -477,7 +477,7 @@
 DEFINE_CLOCK(epit2_clk,   1, MXC_CCM_CGR0,  8, NULL, NULL, &perclk_clk);
 DEFINE_CLOCK(iim_clk,     0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(ata_clk,     0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk);
-DEFINE_CLOCK(sdma_clk1,   0, MXC_CCM_CGR0, 14, NULL, &sdma_clk1, &ahb_clk);
+DEFINE_CLOCK(sdma_clk1,   0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk);
 DEFINE_CLOCK(cspi3_clk,   2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(rng_clk,     0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(uart1_clk,   0, MXC_CCM_CGR0, 20, NULL, NULL, &perclk_clk);
@@ -525,9 +525,9 @@
 
 static struct clk_lookup lookups[] = {
 	_REGISTER_CLOCK(NULL, "emi", emi_clk)
-	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-	_REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+	_REGISTER_CLOCK("imx31-cspi.0", NULL, cspi1_clk)
+	_REGISTER_CLOCK("imx31-cspi.1", NULL, cspi2_clk)
+	_REGISTER_CLOCK("imx31-cspi.2", NULL, cspi3_clk)
 	_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
 	_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
 	_REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
@@ -564,7 +564,7 @@
 	_REGISTER_CLOCK(NULL, "ata", ata_clk)
 	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
 	_REGISTER_CLOCK(NULL, "rng", rng_clk)
-	_REGISTER_CLOCK(NULL, "sdma_ahb", sdma_clk1)
+	_REGISTER_CLOCK("imx-sdma", NULL, sdma_clk1)
 	_REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2)
 	_REGISTER_CLOCK(NULL, "mstick", mstick1_clk)
 	_REGISTER_CLOCK(NULL, "mstick", mstick2_clk)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/clock-imx35.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/clock-imx35.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/clock-imx35.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/clock-imx35.c	2011-01-04 19:50:19.000000000 -0500
@@ -364,8 +364,8 @@
 DEFINE_CLOCK(ect_clk,    0, CCM_CGR0, 14, get_rate_ipg, NULL);
 DEFINE_CLOCK(edio_clk,   0, CCM_CGR0, 16, NULL, NULL);
 DEFINE_CLOCK(emi_clk,    0, CCM_CGR0, 18, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg, NULL);
 DEFINE_CLOCK(esai_clk,   0, CCM_CGR0, 24, NULL, NULL);
 DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGR0, 26, get_rate_sdhc, NULL);
 DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGR0, 28, get_rate_sdhc, NULL);
@@ -451,17 +451,17 @@
 	_REGISTER_CLOCK(NULL, "ata", ata_clk)
 	_REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
 	_REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
-	_REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-	_REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
+	_REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk)
+	_REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk)
 	_REGISTER_CLOCK(NULL, "ect", ect_clk)
 	_REGISTER_CLOCK(NULL, "edio", edio_clk)
 	_REGISTER_CLOCK(NULL, "emi", emi_clk)
-	_REGISTER_CLOCK(NULL, "epit", epit1_clk)
-	_REGISTER_CLOCK(NULL, "epit", epit2_clk)
+	_REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk)
+	_REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk)
 	_REGISTER_CLOCK(NULL, "esai", esai_clk)
-	_REGISTER_CLOCK(NULL, "sdhc", esdhc1_clk)
-	_REGISTER_CLOCK(NULL, "sdhc", esdhc2_clk)
-	_REGISTER_CLOCK(NULL, "sdhc", esdhc3_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
 	_REGISTER_CLOCK("fec.0", NULL, fec_clk)
 	_REGISTER_CLOCK(NULL, "gpio", gpio1_clk)
 	_REGISTER_CLOCK(NULL, "gpio", gpio2_clk)
@@ -482,7 +482,7 @@
 	_REGISTER_CLOCK(NULL, "rtc", rtc_clk)
 	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
 	_REGISTER_CLOCK(NULL, "scc", scc_clk)
-	_REGISTER_CLOCK(NULL, "sdma", sdma_clk)
+	_REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
 	_REGISTER_CLOCK(NULL, "spba", spba_clk)
 	_REGISTER_CLOCK(NULL, "spdif", spdif_clk)
 	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
@@ -535,8 +535,16 @@
 	__raw_writel(cgr2, CCM_BASE + CCM_CGR2);
 	__raw_writel(cgr3, CCM_BASE + CCM_CGR3);
 
+	clk_enable(&iim_clk);
+	mx35_read_cpu_rev();
+
+#ifdef CONFIG_MXC_USE_EPIT
+	epit_timer_init(&epit1_clk,
+			MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1);
+#else
 	mxc_timer_init(&gpt_clk,
 			MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT);
+#endif
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,15 +25,15 @@
 };
 
 static struct mx3_cpu_type mx31_cpu_type[] __initdata = {
-	{ .srev = 0x00, .name = "i.MX31(L)", .v = "1.0",  .rev = CHIP_REV_1_0	},
-	{ .srev = 0x10, .name = "i.MX31",    .v = "1.1",  .rev = CHIP_REV_1_1	},
-	{ .srev = 0x11, .name = "i.MX31L",   .v = "1.1",  .rev = CHIP_REV_1_1	},
-	{ .srev = 0x12, .name = "i.MX31",    .v = "1.15", .rev = CHIP_REV_1_1	},
-	{ .srev = 0x13, .name = "i.MX31L",   .v = "1.15", .rev = CHIP_REV_1_1	},
-	{ .srev = 0x14, .name = "i.MX31",    .v = "1.2",  .rev = CHIP_REV_1_2	},
-	{ .srev = 0x15, .name = "i.MX31L",   .v = "1.2",  .rev = CHIP_REV_1_2	},
-	{ .srev = 0x28, .name = "i.MX31",    .v = "2.0",  .rev = CHIP_REV_2_0	},
-	{ .srev = 0x29, .name = "i.MX31L",   .v = "2.0",  .rev = CHIP_REV_2_0	},
+	{ .srev = 0x00, .name = "i.MX31(L)", .v = "1.0",  .rev = MX3x_CHIP_REV_1_0 },
+	{ .srev = 0x10, .name = "i.MX31",    .v = "1.1",  .rev = MX3x_CHIP_REV_1_1 },
+	{ .srev = 0x11, .name = "i.MX31L",   .v = "1.1",  .rev = MX3x_CHIP_REV_1_1 },
+	{ .srev = 0x12, .name = "i.MX31",    .v = "1.15", .rev = MX3x_CHIP_REV_1_1 },
+	{ .srev = 0x13, .name = "i.MX31L",   .v = "1.15", .rev = MX3x_CHIP_REV_1_1 },
+	{ .srev = 0x14, .name = "i.MX31",    .v = "1.2",  .rev = MX3x_CHIP_REV_1_2 },
+	{ .srev = 0x15, .name = "i.MX31L",   .v = "1.2",  .rev = MX3x_CHIP_REV_1_2 },
+	{ .srev = 0x28, .name = "i.MX31",    .v = "2.0",  .rev = MX3x_CHIP_REV_2_0 },
+	{ .srev = 0x29, .name = "i.MX31L",   .v = "2.0",  .rev = MX3x_CHIP_REV_2_0 },
 };
 
 void __init mx31_read_cpu_rev(void)
@@ -41,7 +41,7 @@
 	u32 i, srev;
 
 	/* read SREV register from IIM module */
-	srev = __raw_readl(IO_ADDRESS(IIM_BASE_ADDR + MXC_IIMSREV));
+	srev = __raw_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV));
 
 	for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
 		if (srev == mx31_cpu_type[i].srev) {
@@ -55,3 +55,30 @@
 
 	printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev);
 }
+
+unsigned int mx35_cpu_rev;
+EXPORT_SYMBOL(mx35_cpu_rev);
+
+void __init mx35_read_cpu_rev(void)
+{
+	u32 rev;
+	char *srev = "unknown";
+
+	rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV));
+	switch (rev) {
+	case 0x00:
+		mx35_cpu_rev = MX3x_CHIP_REV_1_0;
+		srev = "1.0";
+		break;
+	case 0x10:
+		mx35_cpu_rev = MX3x_CHIP_REV_2_0;
+		srev = "2.0";
+		break;
+	case 0x11:
+		mx35_cpu_rev = MX3x_CHIP_REV_2_1;
+		srev = "2.1";
+		break;
+	}
+
+	printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,24 +72,24 @@
 #ifdef CONFIG_ARCH_MX31
 static struct resource mxcsdhc0_resources[] = {
 	{
-		.start = MMC_SDHC1_BASE_ADDR,
-		.end = MMC_SDHC1_BASE_ADDR + SZ_16K - 1,
+		.start = MX31_MMC_SDHC1_BASE_ADDR,
+		.end = MX31_MMC_SDHC1_BASE_ADDR + SZ_16K - 1,
 		.flags = IORESOURCE_MEM,
 	}, {
-		.start = MXC_INT_MMC_SDHC1,
-		.end = MXC_INT_MMC_SDHC1,
+		.start = MX31_INT_MMC_SDHC1,
+		.end = MX31_INT_MMC_SDHC1,
 		.flags = IORESOURCE_IRQ,
 	},
 };
 
 static struct resource mxcsdhc1_resources[] = {
 	{
-		.start = MMC_SDHC2_BASE_ADDR,
-		.end = MMC_SDHC2_BASE_ADDR + SZ_16K - 1,
+		.start = MX31_MMC_SDHC2_BASE_ADDR,
+		.end = MX31_MMC_SDHC2_BASE_ADDR + SZ_16K - 1,
 		.flags = IORESOURCE_MEM,
 	}, {
-		.start = MXC_INT_MMC_SDHC2,
-		.end = MXC_INT_MMC_SDHC2,
+		.start = MX31_INT_MMC_SDHC2,
+		.end = MX31_INT_MMC_SDHC2,
 		.flags = IORESOURCE_IRQ,
 	},
 };
@@ -281,65 +281,6 @@
 	.num_resources = ARRAY_SIZE(mxc_usbh2_resources),
 };
 
-#if defined(CONFIG_ARCH_MX35)
-static struct resource mxc_fec_resources[] = {
-	{
-		.start	= MXC_FEC_BASE_ADDR,
-		.end	= MXC_FEC_BASE_ADDR + 0xfff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= MXC_INT_FEC,
-		.end	= MXC_INT_FEC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_fec_device = {
-	.name = "fec",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(mxc_fec_resources),
-	.resource = mxc_fec_resources,
-};
-#endif
-
-static struct resource imx_ssi_resources0[] = {
-	{
-		.start	= SSI1_BASE_ADDR,
-		.end	= SSI1_BASE_ADDR + 0xfff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= MX31_INT_SSI1,
-		.end	= MX31_INT_SSI1,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct resource imx_ssi_resources1[] = {
-	{
-		.start	= SSI2_BASE_ADDR,
-		.end	= SSI2_BASE_ADDR + 0xfff,
-		.flags	= IORESOURCE_MEM
-	}, {
-		.start	= MX31_INT_SSI2,
-		.end	= MX31_INT_SSI2,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device imx_ssi_device0 = {
-	.name = "imx-ssi",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(imx_ssi_resources0),
-	.resource = imx_ssi_resources0,
-};
-
-struct platform_device imx_ssi_device1 = {
-	.name = "imx-ssi",
-	.id = 1,
-	.num_resources = ARRAY_SIZE(imx_ssi_resources1),
-	.resource = imx_ssi_resources1,
-};
-
 static struct resource imx_wdt_resources[] = {
 	{
 		.flags = IORESOURCE_MEM,
@@ -410,10 +351,6 @@
 		mxc_usbh1_resources[0].end = MX35_OTG_BASE_ADDR + 0x5ff;
 		mxc_usbh1_resources[1].start = MXC_INT_USBHS;
 		mxc_usbh1_resources[1].end = MXC_INT_USBHS;
-		imx_ssi_resources0[1].start = MX35_INT_SSI1;
-		imx_ssi_resources0[1].end = MX35_INT_SSI1;
-		imx_ssi_resources1[1].start = MX35_INT_SSI2;
-		imx_ssi_resources1[1].end = MX35_INT_SSI2;
 		imx_wdt_resources[0].start = MX35_WDOG_BASE_ADDR;
 		imx_wdt_resources[0].end = MX35_WDOG_BASE_ADDR + 0x3fff;
 	}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,6 @@
 extern struct platform_device mx3_ipu;
 extern struct platform_device mx3_fb;
 extern struct platform_device mx3_camera;
-extern struct platform_device mxc_fec_device;
 extern struct platform_device mxcsdhc_device0;
 extern struct platform_device mxcsdhc_device1;
 extern struct platform_device mxc_otg_udc_device;
@@ -10,9 +9,6 @@
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_rnga_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_wdt_device0;
 extern struct platform_device imx_rtc_device0;
 extern struct platform_device imx_kpp_device;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices-imx31.h linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices-imx31.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices-imx31.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices-imx31.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,30 +9,33 @@
 #include <mach/mx31.h>
 #include <mach/devices-common.h>
 
-#define imx31_add_imx_i2c0(pdata)	\
-	imx_add_imx_i2c(0, MX31_I2C1_BASE_ADDR, SZ_4K, MX31_INT_I2C1, pdata)
-#define imx31_add_imx_i2c1(pdata)	\
-	imx_add_imx_i2c(1, MX31_I2C2_BASE_ADDR, SZ_4K, MX31_INT_I2C2, pdata)
-#define imx31_add_imx_i2c2(pdata)	\
-	imx_add_imx_i2c(2, MX31_I2C3_BASE_ADDR, SZ_4K, MX31_INT_I2C3, pdata)
+extern const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst;
+#define imx31_add_imx_i2c(id, pdata)	\
+	imx_add_imx_i2c(&imx31_imx_i2c_data[id], pdata)
+#define imx31_add_imx_i2c0(pdata)	imx31_add_imx_i2c(0, pdata)
+#define imx31_add_imx_i2c1(pdata)	imx31_add_imx_i2c(1, pdata)
+#define imx31_add_imx_i2c2(pdata)	imx31_add_imx_i2c(2, pdata)
 
-#define imx31_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_1irq(0, MX31_UART1_BASE_ADDR, SZ_16K, MX31_INT_UART1, pdata)
-#define imx31_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_1irq(1, MX31_UART2_BASE_ADDR, SZ_16K, MX31_INT_UART2, pdata)
-#define imx31_add_imx_uart2(pdata)	\
-	imx_add_imx_uart_1irq(2, MX31_UART3_BASE_ADDR, SZ_16K, MX31_INT_UART3, pdata)
-#define imx31_add_imx_uart3(pdata)	\
-	imx_add_imx_uart_1irq(3, MX31_UART4_BASE_ADDR, SZ_16K, MX31_INT_UART4, pdata)
-#define imx31_add_imx_uart4(pdata)	\
-	imx_add_imx_uart_1irq(4, MX31_UART5_BASE_ADDR, SZ_16K, MX31_INT_UART5, pdata)
+extern const struct imx_imx_ssi_data imx31_imx_ssi_data[] __initconst;
+#define imx31_add_imx_ssi(id, pdata)    \
+	imx_add_imx_ssi(&imx31_imx_ssi_data[id], pdata)
 
+extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst;
+#define imx31_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx31_imx_uart_data[id], pdata)
+#define imx31_add_imx_uart0(pdata)	imx31_add_imx_uart(0, pdata)
+#define imx31_add_imx_uart1(pdata)	imx31_add_imx_uart(1, pdata)
+#define imx31_add_imx_uart2(pdata)	imx31_add_imx_uart(2, pdata)
+#define imx31_add_imx_uart3(pdata)	imx31_add_imx_uart(3, pdata)
+#define imx31_add_imx_uart4(pdata)	imx31_add_imx_uart(4, pdata)
+
+extern const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst;
 #define imx31_add_mxc_nand(pdata)	\
-	imx_add_mxc_nand_v1(MX31_NFC_BASE_ADDR, MX31_INT_NANDFC, pdata)
+	imx_add_mxc_nand(&imx31_mxc_nand_data, pdata)
 
-#define imx31_add_spi_imx0(pdata)	\
-	imx_add_spi_imx(0, MX31_CSPI1_BASE_ADDR, SZ_4K, MX31_INT_CSPI1, pdata)
-#define imx31_add_spi_imx1(pdata)	\
-	imx_add_spi_imx(1, MX31_CSPI2_BASE_ADDR, SZ_4K, MX31_INT_CSPI2, pdata)
-#define imx31_add_spi_imx2(pdata)	\
-	imx_add_spi_imx(2, MX31_CSPI3_BASE_ADDR, SZ_4K, MX31_INT_CSPI3, pdata)
+extern const struct imx_spi_imx_data imx31_cspi_data[] __initconst;
+#define imx31_add_cspi(id, pdata)	\
+	imx_add_spi_imx(&imx31_cspi_data[id], pdata)
+#define imx31_add_spi_imx0(pdata)	imx31_add_cspi(0, pdata)
+#define imx31_add_spi_imx1(pdata)	imx31_add_cspi(1, pdata)
+#define imx31_add_spi_imx2(pdata)	imx31_add_cspi(2, pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices-imx35.h linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices-imx35.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/devices-imx35.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/devices-imx35.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,29 +9,43 @@
 #include <mach/mx35.h>
 #include <mach/devices-common.h>
 
+extern const struct imx_fec_data imx35_fec_data __initconst;
+#define imx35_add_fec(pdata)	\
+	imx_add_fec(&imx35_fec_data, pdata)
+
 #define imx35_add_flexcan0(pdata)	\
 	imx_add_flexcan(0, MX35_CAN1_BASE_ADDR, SZ_16K, MX35_INT_CAN1, pdata)
 #define imx35_add_flexcan1(pdata)	\
 	imx_add_flexcan(1, MX35_CAN2_BASE_ADDR, SZ_16K, MX35_INT_CAN2, pdata)
 
-#define imx35_add_imx_i2c0(pdata)	\
-	imx_add_imx_i2c(0, MX35_I2C1_BASE_ADDR, SZ_4K, MX35_INT_I2C1, pdata)
-#define imx35_add_imx_i2c1(pdata)	\
-	imx_add_imx_i2c(1, MX35_I2C2_BASE_ADDR, SZ_4K, MX35_INT_I2C2, pdata)
-#define imx35_add_imx_i2c2(pdata)	\
-	imx_add_imx_i2c(2, MX35_I2C3_BASE_ADDR, SZ_4K, MX35_INT_I2C3, pdata)
+extern const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst;
+#define imx35_add_imx_i2c(id, pdata)	\
+	imx_add_imx_i2c(&imx35_imx_i2c_data[id], pdata)
+#define imx35_add_imx_i2c0(pdata)	imx35_add_imx_i2c(0, pdata)
+#define imx35_add_imx_i2c1(pdata)	imx35_add_imx_i2c(1, pdata)
+#define imx35_add_imx_i2c2(pdata)	imx35_add_imx_i2c(2, pdata)
 
-#define imx35_add_imx_uart0(pdata)	\
-	imx_add_imx_uart_1irq(0, MX35_UART1_BASE_ADDR, SZ_16K, MX35_INT_UART1, pdata)
-#define imx35_add_imx_uart1(pdata)	\
-	imx_add_imx_uart_1irq(1, MX35_UART2_BASE_ADDR, SZ_16K, MX35_INT_UART2, pdata)
-#define imx35_add_imx_uart2(pdata)	\
-	imx_add_imx_uart_1irq(2, MX35_UART3_BASE_ADDR, SZ_16K, MX35_INT_UART3, pdata)
+extern const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst;
+#define imx35_add_imx_ssi(id, pdata)    \
+	imx_add_imx_ssi(&imx35_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst;
+#define imx35_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx35_imx_uart_data[id], pdata)
+#define imx35_add_imx_uart0(pdata)	imx35_add_imx_uart(0, pdata)
+#define imx35_add_imx_uart1(pdata)	imx35_add_imx_uart(1, pdata)
+#define imx35_add_imx_uart2(pdata)	imx35_add_imx_uart(2, pdata)
 
+extern const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst;
 #define imx35_add_mxc_nand(pdata)	\
-	imx_add_mxc_nand_v21(MX35_NFC_BASE_ADDR, MX35_INT_NANDFC, pdata)
+	imx_add_mxc_nand(&imx35_mxc_nand_data, pdata)
 
-#define imx35_add_spi_imx0(pdata)	\
-	imx_add_spi_imx(0, MX35_CSPI1_BASE_ADDR, SZ_4K, MX35_INT_CSPI1, pdata)
-#define imx35_add_spi_imx1(pdata)	\
-	imx_add_spi_imx(1, MX35_CSPI2_BASE_ADDR, SZ_4K, MX35_INT_CSPI2, pdata)
+extern const struct imx_spi_imx_data imx35_cspi_data[] __initconst;
+#define imx35_add_cspi(id, pdata)	\
+	imx_add_spi_imx(&imx35_cspi_data[id], pdata)
+#define imx35_add_spi_imx0(pdata)	imx35_add_cspi(0, pdata)
+#define imx35_add_spi_imx1(pdata)	imx35_add_cspi(1, pdata)
+
+extern const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst;
+#define imx35_add_esdhc(id, pdata)	\
+	imx_add_esdhc(&imx35_esdhc_data[id], pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,14 +43,13 @@
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
 
 static const struct fb_videomode fb_modedb[] = {
 	{
-		.name		= "CMO_QVGA",
+		.name		= "CMO-QVGA",
 		.refresh	= 60,
 		.xres		= 320,
 		.yres		= 240,
@@ -65,6 +64,40 @@
 		.vmode		= FB_VMODE_NONINTERLACED,
 		.flag		= 0,
 	},
+	{
+		.name		= "DVI-VGA",
+		.refresh	= 60,
+		.xres		= 640,
+		.yres		= 480,
+		.pixclock	= 32000,
+		.left_margin	= 100,
+		.right_margin	= 100,
+		.upper_margin	= 7,
+		.lower_margin	= 100,
+		.hsync_len	= 7,
+		.vsync_len	= 7,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
+				  FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	},
+	{
+		.name		= "DVI-SVGA",
+		.refresh	= 60,
+		.xres		= 800,
+		.yres		= 600,
+		.pixclock	= 25000,
+		.left_margin	= 75,
+		.right_margin	= 75,
+		.upper_margin	= 7,
+		.lower_margin	= 75,
+		.hsync_len	= 7,
+		.vsync_len	= 7,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
+				  FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+		.flag		= 0,
+	},
 };
 
 static struct ipu_platform_data mx3_ipu_data = {
@@ -73,7 +106,7 @@
 
 static struct mx3fb_platform_data mx3fb_pdata = {
 	.dma_dev	= &mx3_ipu.dev,
-	.name		= "CMO_QVGA",
+	.name		= "CMO-QVGA",
 	.mode		= fb_modedb,
 	.num_modes	= ARRAY_SIZE(fb_modedb),
 };
@@ -120,6 +153,16 @@
 	MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
 	MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
 	MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+	/* CAN2 */
+	MX35_PAD_TX5_RX0__CAN2_TXCAN,
+	MX35_PAD_TX4_RX1__CAN2_RXCAN,
+	/* SDCARD */
+	MX35_PAD_SD1_CMD__ESDHC1_CMD,
+	MX35_PAD_SD1_CLK__ESDHC1_CLK,
+	MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+	MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+	MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+	MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 };
 
 #define GPIO_LED1	(2 * 32 + 29)
@@ -206,7 +249,8 @@
 	},
 };
 
-struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
 	.flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -242,7 +286,10 @@
 	mxc_register_device(&mx3_ipu, &mx3_ipu_data);
 	mxc_register_device(&mx3_fb, &mx3fb_pdata);
 
-	mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+	imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
+
+	imx35_add_flexcan1(NULL);
+	imx35_add_esdhc(0, NULL);
 
 	gpio_request(GPIO_LED1, "LED1");
 	gpio_direction_output(GPIO_LED1, 1);
@@ -254,7 +301,7 @@
 
 	gpio_request(GPIO_LCDPWR, "LCDPWR");
 	gpio_direction_output(GPIO_LCDPWR, 1);
-	gpio_free(GPIO_SWITCH1);
+	gpio_free(GPIO_LCDPWR);
 
 	i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
 				ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-mx3/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
 	bool
 	select ARCH_MXC_IOMUX_V3
 	select ARCH_MXC_AUDMUX_V2
+	select HAVE_EPIT
 
 comment "MX3 platforms:"
 
@@ -16,6 +17,7 @@
 	bool "Support MX31ADS platforms"
 	select ARCH_MX31
 	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
 	default y
 	help
@@ -117,9 +119,11 @@
 	bool "Support Phytec pcm043 (i.MX35) platforms"
 	select ARCH_MX35
 	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_MXC_NAND
 	select IMX_HAVE_PLATFORM_FLEXCAN
+	select IMX_HAVE_PLATFORM_ESDHC
 	select MXC_ULPI if USB_ULPI
 	help
 	  Include support for Phytec pcm043 platform. This includes
@@ -139,7 +143,10 @@
 config MACH_MX35_3DS
 	bool "Support MX35PDK platform"
 	select ARCH_MX35
+	select MXC_DEBUG_BOARD
 	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_MXC_NAND
+	select IMX_HAVE_PLATFORM_ESDHC
 	default n
 	help
 	  Include support for MX35PDK platform. This includes specific
@@ -159,6 +166,8 @@
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_MXC_NAND
+	select IMX_HAVE_PLATFORM_FLEXCAN
+	select IMX_HAVE_PLATFORM_ESDHC
 	select MXC_ULPI if USB_ULPI
 	help
 	  Include support for Eukrea CPUIMX35 platform. This includes
@@ -170,8 +179,8 @@
 	default MACH_EUKREA_MBIMXSD35_BASEBOARD
 
 config MACH_EUKREA_MBIMXSD35_BASEBOARD
-	prompt "Eukrea MBIMXSD development board"
-	bool
+	bool "Eukrea MBIMXSD development board"
+	select IMX_HAVE_PLATFORM_IMX_SSI
 	help
 	  This adds board specific devices that can be found on Eukrea's
 	  MBIMXSD evaluation board.
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-armadillo5x0.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-armadillo5x0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-armadillo5x0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-armadillo5x0.c	2011-01-04 19:50:19.000000000 -0500
@@ -571,8 +571,6 @@
 
 MACHINE_START(ARMADILLO5X0, "Armadillo-500")
 	/* Maintainer: Alberto Panizzo  */
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params	= MX3x_PHYS_OFFSET + 0x100,
 	.map_io		= mx31_map_io,
 	.init_irq	= mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-cpuimx35.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-cpuimx35.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-cpuimx35.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-cpuimx35.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 #include <linux/fsl_devices.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,7 +44,6 @@
 #include <mach/iomux-mx35.h>
 #include <mach/mxc_nand.h>
 #include <mach/mxc_ehci.h>
-#include <mach/ulpi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
@@ -53,39 +53,16 @@
 };
 
 static const struct imxi2c_platform_data
-eukrea_cpuimx35_i2c0_data __initconst = {
-	.bitrate = 50000,
+		eukrea_cpuimx35_i2c0_data __initconst = {
+	.bitrate =		100000,
 };
 
-#define TSC2007_IRQGPIO		(2 * 32 + 2)
-static int ts_get_pendown_state(void)
-{
-	int val = 0;
-	gpio_free(TSC2007_IRQGPIO);
-	gpio_request(TSC2007_IRQGPIO, NULL);
-	gpio_direction_input(TSC2007_IRQGPIO);
-
-	val = gpio_get_value(TSC2007_IRQGPIO);
-
-	gpio_free(TSC2007_IRQGPIO);
-	gpio_request(TSC2007_IRQGPIO, NULL);
-
-	return val ? 0 : 1;
-}
-
-static int ts_init(void)
-{
-	gpio_request(TSC2007_IRQGPIO, NULL);
-	return 0;
-}
-
 static struct tsc2007_platform_data tsc2007_info = {
 	.model			= 2007,
 	.x_plate_ohms		= 180,
-	.get_pendown_state	= ts_get_pendown_state,
-	.init_platform_hw	= ts_init,
 };
 
+#define TSC2007_IRQGPIO		(2 * 32 + 2)
 static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
 	{
 		I2C_BOARD_INFO("pcf8563", 0x51),
@@ -98,7 +75,6 @@
 };
 
 static struct platform_device *devices[] __initdata = {
-	&mxc_fec_device,
 	&imx_wdt_device0,
 };
 
@@ -135,18 +111,18 @@
 };
 
 static const struct mxc_nand_platform_data
-eukrea_cpuimx35_nand_board_info __initconst = {
+		eukrea_cpuimx35_nand_board_info __initconst = {
 	.width		= 1,
 	.hw_ecc		= 1,
 	.flash_bbt	= 1,
 };
 
-static struct mxc_usbh_platform_data otg_pdata = {
+static struct mxc_usbh_platform_data __maybe_unused otg_pdata = {
 	.portsc	= MXC_EHCI_MODE_UTMI,
 	.flags	= MXC_EHCI_INTERFACE_DIFF_UNI,
 };
 
-static struct mxc_usbh_platform_data usbh1_pdata = {
+static struct mxc_usbh_platform_data __maybe_unused usbh1_pdata = {
 	.portsc	= MXC_EHCI_MODE_SERIAL,
 	.flags	= MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
 		  MXC_EHCI_IPPUE_DOWN,
@@ -155,6 +131,7 @@
 static struct fsl_usb2_platform_data otg_device_pdata = {
 	.operating_mode	= FSL_USB2_DR_DEVICE,
 	.phy_mode	= FSL_USB2_PHY_UTMI,
+	.workaround	= FLS_USB2_WORKAROUND_ENGCM09152,
 };
 
 static int otg_mode_host;
@@ -180,6 +157,7 @@
 	mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads,
 			ARRAY_SIZE(eukrea_cpuimx35_pads));
 
+	imx35_add_fec(NULL);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	imx35_add_imx_uart0(&uart_pdata);
@@ -189,18 +167,13 @@
 			ARRAY_SIZE(eukrea_cpuimx35_i2c_devices));
 	imx35_add_imx_i2c0(&eukrea_cpuimx35_i2c0_data);
 
-#if defined(CONFIG_USB_ULPI)
-	if (otg_mode_host) {
-		otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
-				ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
+	if (otg_mode_host)
 		mxc_register_device(&mxc_otg_host, &otg_pdata);
-	}
-	mxc_register_device(&mxc_usbh1, &usbh1_pdata);
-#endif
-	if (!otg_mode_host)
+	else
 		mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
 
+	mxc_register_device(&mxc_usbh1, &usbh1_pdata);
+
 #ifdef CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD
 	eukrea_mbimxsd35_baseboard_init();
 #endif
@@ -217,8 +190,6 @@
 
 MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
 	/* Maintainer: Eukrea Electromatique */
-	.phys_io	= MX35_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx35_map_io,
 	.init_irq       = mx35_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-kzm_arm11_01.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-kzm_arm11_01.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-kzm_arm11_01.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-kzm_arm11_01.c	2011-01-04 19:50:19.000000000 -0500
@@ -274,8 +274,6 @@
  * initialize __mach_desc_KZM_ARM11_01 data structure.
  */
 MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
-	.phys_io        = MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = kzm_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31_3ds.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31_3ds.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31_3ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31_3ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,39 +38,9 @@
 #include "devices-imx31.h"
 #include "devices.h"
 
-/* Definitions for components on the Debug board */
-
-/* Base address of CPLD controller on the Debug board */
-#define DEBUG_BASE_ADDRESS		CS5_IO_ADDRESS(MX3x_CS5_BASE_ADDR)
-
-/* LAN9217 ethernet base address */
-#define LAN9217_BASE_ADDR		MX3x_CS5_BASE_ADDR
-
-/* CPLD config and interrupt base address */
-#define CPLD_ADDR			(DEBUG_BASE_ADDRESS + 0x20000)
-
-/* status, interrupt */
-#define CPLD_INT_STATUS_REG		(CPLD_ADDR + 0x10)
-#define CPLD_INT_MASK_REG		(CPLD_ADDR + 0x38)
-#define CPLD_INT_RESET_REG		(CPLD_ADDR + 0x20)
-/* magic word for debug CPLD */
-#define CPLD_MAGIC_NUMBER1_REG		(CPLD_ADDR + 0x40)
-#define CPLD_MAGIC_NUMBER2_REG		(CPLD_ADDR + 0x48)
-/* CPLD code version */
-#define CPLD_CODE_VER_REG		(CPLD_ADDR + 0x50)
-/* magic word for debug CPLD */
-#define CPLD_MAGIC_NUMBER3_REG		(CPLD_ADDR + 0x58)
-
 /* CPLD IRQ line for external uart, external ethernet etc */
 #define EXPIO_PARENT_INT	IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
 
-#define MXC_EXP_IO_BASE		(MXC_BOARD_IRQ_START)
-#define MXC_IRQ_TO_EXPIO(irq)	((irq) - MXC_EXP_IO_BASE)
-
-#define EXPIO_INT_ENET		(MXC_EXP_IO_BASE + 0)
-
-#define MXC_MAX_EXP_IO_LINES	16
-
 /*
  * This file contains the board-specific initialization routines.
  */
@@ -272,7 +242,7 @@
 	imx31_add_imx_uart0(&uart_pdata);
 	imx31_add_mxc_nand(&mx31_3ds_nand_board_info);
 
-	imx31_add_spi_imx0(&spi1_pdata);
+	imx31_add_spi_imx1(&spi1_pdata);
 	spi_register_board_info(mx31_3ds_spi_devs,
 						ARRAY_SIZE(mx31_3ds_spi_devs));
 
@@ -281,9 +251,9 @@
 	mx31_3ds_usbotg_init();
 	mxc_register_device(&mxc_otg_udc_device, &usbotg_pdata);
 
-	if (!mxc_expio_init(CS5_BASE_ADDR, EXPIO_PARENT_INT))
-		printk(KERN_WARNING "Init of the debugboard failed, all "
-				    "devices on the board are unusable.\n");
+	if (mxc_expio_init(MX31_CS5_BASE_ADDR, EXPIO_PARENT_INT))
+		printk(KERN_WARNING "Init of the debug board failed, all "
+				    "devices on the debug board are unusable.\n");
 }
 
 static void __init mx31_3ds_timer_init(void)
@@ -301,8 +271,6 @@
  */
 MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
 	/* Maintainer: Freescale Semiconductor, Inc. */
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31_3ds_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31ads.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31ads.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31ads.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31ads.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,13 +22,13 @@
 #include <linux/i2c.h>
 #include <linux/irq.h>
 
-#include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/memory.h>
 #include <asm/mach/map.h>
 #include <mach/common.h>
+#include <mach/board-mx31ads.h>
 #include <mach/iomux-mx3.h>
 
 #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
@@ -40,10 +40,6 @@
 #include "devices-imx31.h"
 #include "devices.h"
 
-/* Base address of PBC controller */
-#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
-/* Offsets for the PBC Controller register */
-
 /* PBC Board interrupt status register */
 #define PBC_INTSTATUS           0x000016
 
@@ -67,7 +63,6 @@
 #define PBC_INTMASK_CLEAR_REG	(PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT	IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
-#define MXC_EXP_IO_BASE		(MXC_BOARD_IRQ_START)
 #define MXC_IRQ_TO_EXPIO(irq)	((irq) - MXC_EXP_IO_BASE)
 
 #define EXPIO_INT_XUART_INTA	(MXC_EXP_IO_BASE + 10)
@@ -517,7 +512,7 @@
 
 static void mxc_init_audio(void)
 {
-	mxc_register_device(&imx_ssi_device0, NULL);
+	imx31_add_imx_ssi(0, NULL);
 	mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
 }
 
@@ -574,8 +569,6 @@
  */
 MACHINE_START(MX31ADS, "Freescale MX31ADS")
 	/* Maintainer: Freescale Semiconductor, Inc. */
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31ads_map_io,
 	.init_irq       = mx31ads_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31lilly.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31lilly.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31lilly.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31lilly.c	2011-01-04 19:50:19.000000000 -0500
@@ -348,8 +348,6 @@
 };
 
 MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params	= MX3x_PHYS_OFFSET + 0x100,
 	.map_io		= mx31_map_io,
 	.init_irq	= mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31lite.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31lite.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31lite.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31lite.c	2011-01-04 19:50:19.000000000 -0500
@@ -282,8 +282,6 @@
 
 MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
 	/* Maintainer: Freescale Semiconductor, Inc. */
-	.phys_io        = MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31lite_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31moboard.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31moboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx31moboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx31moboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -560,8 +560,6 @@
 
 MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
 	/* Maintainer: Valentin Longchamp, EPFL Mobots group */
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx35_3ds.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx35_3ds.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-mx35_3ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-mx35_3ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Marc Kleine-Budde, Pengutronix
  *
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  *
@@ -27,6 +28,8 @@
 #include <linux/gpio.h>
 #include <linux/fsl_devices.h>
 
+#include <linux/mtd/physmap.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -35,16 +38,47 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
+#include <mach/irqs.h>
+#include <mach/3ds_debugboard.h>
+#include <mach/mxc_ehci.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
 
+#define EXPIO_PARENT_INT	(MXC_INTERNAL_IRQS + GPIO_PORTA + 1)
+
 static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
+static struct physmap_flash_data mx35pdk_flash_data = {
+	.width  = 2,
+};
+
+static struct resource mx35pdk_flash_resource = {
+	.start	= MX35_CS0_BASE_ADDR,
+	.end	= MX35_CS0_BASE_ADDR + SZ_64M - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device mx35pdk_flash = {
+	.name	= "physmap-flash",
+	.id	= 0,
+	.dev	= {
+		.platform_data  = &mx35pdk_flash_data,
+	},
+	.resource = &mx35pdk_flash_resource,
+	.num_resources = 1,
+};
+
+static const struct mxc_nand_platform_data mx35pdk_nand_board_info __initconst = {
+	.width = 1,
+	.hw_ecc = 1,
+	.flash_bbt = 1,
+};
+
 static struct platform_device *devices[] __initdata = {
-	&mxc_fec_device,
+	&mx35pdk_flash,
 };
 
 static struct pad_desc mx35pdk_pads[] = {
@@ -75,14 +109,31 @@
 	/* USBOTG */
 	MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR,
 	MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC,
+	/* USBH1 */
+	MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR,
+	MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC,
+	/* SDCARD */
+	MX35_PAD_SD1_CMD__ESDHC1_CMD,
+	MX35_PAD_SD1_CLK__ESDHC1_CLK,
+	MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+	MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+	MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+	MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 };
 
 /* OTG config */
-static struct fsl_usb2_platform_data usb_pdata = {
+static struct fsl_usb2_platform_data usb_otg_pdata = {
 	.operating_mode	= FSL_USB2_DR_DEVICE,
 	.phy_mode	= FSL_USB2_PHY_UTMI_WIDE,
 };
 
+/* USB HOST config */
+static struct mxc_usbh_platform_data usb_host_pdata = {
+	.portsc		= MXC_EHCI_MODE_SERIAL,
+	.flags		= MXC_EHCI_INTERFACE_SINGLE_UNI |
+			  MXC_EHCI_INTERNAL_PHY,
+};
+
 /*
  * Board specific initialization.
  */
@@ -90,11 +141,21 @@
 {
 	mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
 
+	imx35_add_fec(NULL);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	imx35_add_imx_uart0(&uart_pdata);
 
-	mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+	mxc_register_device(&mxc_otg_udc_device, &usb_otg_pdata);
+
+	mxc_register_device(&mxc_usbh1, &usb_host_pdata);
+
+	imx35_add_mxc_nand(&mx35pdk_nand_board_info);
+	imx35_add_esdhc(0, NULL);
+
+	if (mxc_expio_init(MX35_CS5_BASE_ADDR, EXPIO_PARENT_INT))
+		pr_warn("Init of the debugboard failed, all "
+				"devices on the debugboard are unusable.\n");
 }
 
 static void __init mx35pdk_timer_init(void)
@@ -108,8 +169,6 @@
 
 MACHINE_START(MX35_3DS, "Freescale MX35PDK")
 	/* Maintainer: Freescale Semiconductor, Inc */
-	.phys_io	= MX35_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx35_map_io,
 	.init_irq       = mx35_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm037.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm037.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm037.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm037.c	2011-01-04 19:50:19.000000000 -0500
@@ -311,7 +311,6 @@
 	.bus_id		= 0,		/* Must match with the camera ID */
 	.board_info	= &pcm037_i2c_camera[1],
 	.i2c_adapter_id	= 2,
-	.module_name	= "mt9v022",
 };
 
 static struct soc_camera_link iclink_mt9t031 = {
@@ -319,7 +318,6 @@
 	.power		= pcm037_camera_power,
 	.board_info	= &pcm037_i2c_camera[0],
 	.i2c_adapter_id	= 2,
-	.module_name	= "mt9t031",
 };
 
 static struct i2c_board_info pcm037_i2c_devices[] = {
@@ -680,8 +678,6 @@
 
 MACHINE_START(PCM037, "Phytec Phycore pcm037")
 	/* Maintainer: Pengutronix */
-	.phys_io	= MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst	= (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm037_eet.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm037_eet.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm037_eet.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm037_eet.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,13 @@
 
 #include <mach/common.h>
 #include <mach/iomux-mx3.h>
+#include <mach/spi.h>
 
 #include <asm/mach-types.h>
 
 #include "pcm037.h"
 #include "devices.h"
+#include "devices-imx31.h"
 
 static unsigned int pcm037_eet_pins[] = {
 	/* Reserve and hardwire GPIO 57 high - S6E63D6 chipselect */
@@ -58,14 +60,12 @@
 };
 
 /* Platform Data for MXC CSPI */
-#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
 static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)};
 
 static const struct spi_imx_master pcm037_spi1_pdata __initconst = {
 	.chipselect = pcm037_spi1_cs,
 	.num_chipselect = ARRAY_SIZE(pcm037_spi1_cs),
 };
-#endif
 
 /* GPIO-keys input device */
 static struct gpio_keys_button pcm037_gpio_keys[] = {
@@ -170,7 +170,7 @@
 	},
 };
 
-static int eet_init_devices(void)
+static int __init eet_init_devices(void)
 {
 	if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET)
 		return 0;
@@ -181,7 +181,7 @@
 	/* SPI */
 	spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
-	imx35_add_spi_imx0(&pcm037_spi1_pdata);
+	imx31_add_spi_imx0(&pcm037_spi1_pdata);
 #endif
 
 	platform_device_register(&pcm037_gpio_keys_device);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm043.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm043.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-pcm043.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-pcm043.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,6 @@
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
@@ -141,7 +140,6 @@
 
 static struct platform_device *devices[] __initdata = {
 	&pcm043_flash,
-	&mxc_fec_device,
 	&imx_wdt_device0,
 };
 
@@ -217,6 +215,13 @@
 	/* CAN2 */
 	MX35_PAD_TX5_RX0__CAN2_TXCAN,
 	MX35_PAD_TX4_RX1__CAN2_RXCAN,
+	/* esdhc */
+	MX35_PAD_SD1_CMD__ESDHC1_CMD,
+	MX35_PAD_SD1_CLK__ESDHC1_CLK,
+	MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+	MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+	MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+	MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 };
 
 #define AC97_GPIO_TXFS	(1 * 32 + 31)
@@ -293,7 +298,7 @@
 	mdelay(1);
 }
 
-static struct imx_ssi_platform_data pcm043_ssi_pdata = {
+static const struct imx_ssi_platform_data pcm043_ssi_pdata __initconst = {
 	.ac97_reset = pcm043_ac97_cold_reset,
 	.ac97_warm_reset = pcm043_ac97_warm_reset,
 	.flags = IMX_SSI_USE_AC97,
@@ -357,11 +362,12 @@
 			MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
 			MXC_AUDMUX_V2_PDCR_RXDSEL(3));
 
+	imx35_add_fec(NULL);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
 	imx35_add_imx_uart0(&uart_pdata);
 	imx35_add_mxc_nand(&pcm037_nand_board_info);
-	mxc_register_device(&imx_ssi_device0, &pcm043_ssi_pdata);
+	imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
 
 	imx35_add_imx_uart1(&uart_pdata);
 
@@ -389,6 +395,7 @@
 		mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
 
 	imx35_add_flexcan1(NULL);
+	imx35_add_esdhc(0, NULL);
 }
 
 static void __init pcm043_timer_init(void)
@@ -402,8 +409,6 @@
 
 MACHINE_START(PCM043, "Phytec Phycore pcm043")
 	/* Maintainer: Pengutronix */
-	.phys_io	= MX35_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx35_map_io,
 	.init_irq       = mx35_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-qong.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-qong.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mach-qong.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mach-qong.c	2011-01-04 19:50:19.000000000 -0500
@@ -270,8 +270,6 @@
 
 MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
 	/* Maintainer: DENX Software Engineering GmbH */
-	.phys_io        = MX31_AIPS1_BASE_ADDR,
-	.io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
 	.boot_params    = MX3x_PHYS_OFFSET + 0x100,
 	.map_io         = mx31_map_io,
 	.init_irq       = mx31_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-mx3/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,6 @@
 obj-y				:= mm.o devices.o cpu.o
 CFLAGS_mm.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
 CFLAGS_devices.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
-CFLAGS_cpu.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
 obj-$(CONFIG_ARCH_MX31)		+= clock-imx31.o iomux-imx31.o
 obj-$(CONFIG_ARCH_MX35)		+= clock-imx35.o
 obj-$(CONFIG_MACH_MX31ADS)	+= mach-mx31ads.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mm.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mm.c	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,24 @@
 static int mxc_init_l2x0(void)
 {
 	void __iomem *l2x0_base;
+	void __iomem *clkctl_base;
+/*
+ * First of all, we must repair broken chip settings. There are some
+ * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These
+ * misconfigured CPUs will run amok immediately when the L2 cache gets enabled.
+ * Workaraound is to setup the correct register setting prior enabling the
+ * L2 cache. This should not hurt already working CPUs, as they are using the
+ * same value
+ */
+#define L2_MEM_VAL 0x10
+
+	clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096);
+	if (clkctl_base != NULL) {
+		writel(0x00000515, clkctl_base + L2_MEM_VAL);
+		iounmap(clkctl_base);
+	} else {
+		pr_err("L2 cache: Cannot fix timing. Trying to continue without\n");
+	}
 
 	l2x0_base = ioremap(L2CC_BASE_ADDR, 4096);
 	if (IS_ERR(l2x0_base)) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mx31moboard-marxbot.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mx31moboard-marxbot.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mx31moboard-marxbot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mx31moboard-marxbot.c	2011-01-04 19:50:19.000000000 -0500
@@ -179,7 +179,6 @@
 	.reset		= marxbot_basecam_reset,
 	.board_info	= &marxbot_i2c_devices[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "mt9t031",
 };
 
 static struct platform_device marxbot_camera[] = {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mx31moboard-smartbot.c linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mx31moboard-smartbot.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx3/mx31moboard-smartbot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx3/mx31moboard-smartbot.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,6 @@
 	.reset		= smartbot_cam_reset,
 	.board_info	= &smartbot_i2c_devices[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "mt9t031",
 };
 
 static struct platform_device smartbot_camera[] = {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-cpuimx51.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-cpuimx51.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-cpuimx51.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-cpuimx51.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,9 +28,7 @@
 #include <mach/eukrea-baseboards.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
@@ -39,6 +37,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define CPUIMX51_USBH1_STP	(0*32 + 27)
@@ -109,7 +108,6 @@
 #endif
 
 static struct platform_device *devices[] __initdata = {
-	&mxc_fec_device,
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
 	&serial_device,
 #endif
@@ -148,11 +146,19 @@
 	MX51_PAD_USBH1_STP__USBH1_STP,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct mxc_nand_platform_data
+		eukrea_cpuimx51_nand_board_info __initconst = {
+	.width		= 1,
+	.hw_ecc		= 1,
+	.flash_bbt	= 1,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct imxi2c_platform_data eukrea_cpuimx51_i2c_data = {
+static const
+struct imxi2c_platform_data eukrea_cpuimx51_i2c_data __initconst = {
 	.bitrate = 100000,
 };
 
@@ -239,7 +245,9 @@
 	mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads,
 					ARRAY_SIZE(eukrea_cpuimx51_pads));
 
-	mxc_register_device(&mxc_uart_device0, &uart_pdata);
+	imx51_add_imx_uart(0, &uart_pdata);
+	imx51_add_mxc_nand(&eukrea_cpuimx51_nand_board_info);
+
 	gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq");
 	gpio_direction_input(CPUIMX51_QUARTA_GPIO);
 	gpio_free(CPUIMX51_QUARTA_GPIO);
@@ -253,9 +261,10 @@
 	gpio_direction_input(CPUIMX51_QUARTD_GPIO);
 	gpio_free(CPUIMX51_QUARTD_GPIO);
 
+	imx51_add_fec(NULL);
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 
-	mxc_register_device(&mxc_i2c_device1, &eukrea_cpuimx51_i2c_data);
+	imx51_add_imx_i2c(1, &eukrea_cpuimx51_i2c_data);
 	i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices,
 				ARRAY_SIZE(eukrea_cpuimx51_i2c_devices));
 
@@ -283,8 +292,6 @@
 
 MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
 	/* Maintainer: Eric BÃ©nard <eric@eukrea.com> */
-	.phys_io = MX51_AIPS1_BASE_ADDR,
-	.io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = mx51_map_io,
 	.init_irq = mx51_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-cpuimx51sd.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-cpuimx51sd.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-cpuimx51sd.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-cpuimx51sd.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,331 @@
+/*
+ *
+ * Copyright (C) 2010 Eric BÃ©nard <eric@eukrea.com>
+ *
+ * based on board-mx51_babbage.c which is
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/can/platform/mcp251x.h>
+
+#include <mach/eukrea-baseboards.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define USBH1_RST		(1*32 + 28)
+#define ETH_RST			(1*32 + 31)
+#define TSC2007_IRQGPIO		(2*32 + 12)
+#define CAN_IRQGPIO		(0*32 + 1)
+#define CAN_RST			(3*32 + 15)
+#define CAN_NCS			(3*32 + 24)
+#define CAN_RXOBF		(0*32 + 4)
+#define CAN_RX1BF		(0*32 + 6)
+#define CAN_TXORTS		(0*32 + 7)
+#define CAN_TX1RTS		(0*32 + 8)
+#define CAN_TX2RTS		(0*32 + 9)
+#define I2C_SCL			(3*32 + 16)
+#define I2C_SDA			(3*32 + 17)
+
+/* USB_CTRL_1 */
+#define MX51_USB_CTRL_1_OFFSET		0x10
+#define MX51_USB_CTRL_UH1_EXT_CLK_EN	(1 << 25)
+
+#define	MX51_USB_PLLDIV_12_MHZ		0x00
+#define	MX51_USB_PLL_DIV_19_2_MHZ	0x01
+#define	MX51_USB_PLL_DIV_24_MHZ		0x02
+
+#define CPUIMX51SD_GPIO_3_12 IOMUX_PAD(0x57C, 0x194, 3, 0x0, 0, \
+				MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
+
+static struct pad_desc eukrea_cpuimx51sd_pads[] = {
+	/* UART1 */
+	MX51_PAD_UART1_RXD__UART1_RXD,
+	MX51_PAD_UART1_TXD__UART1_TXD,
+	MX51_PAD_UART1_RTS__UART1_RTS,
+	MX51_PAD_UART1_CTS__UART1_CTS,
+
+	/* USB HOST1 */
+	MX51_PAD_USBH1_CLK__USBH1_CLK,
+	MX51_PAD_USBH1_DIR__USBH1_DIR,
+	MX51_PAD_USBH1_NXT__USBH1_NXT,
+	MX51_PAD_USBH1_DATA0__USBH1_DATA0,
+	MX51_PAD_USBH1_DATA1__USBH1_DATA1,
+	MX51_PAD_USBH1_DATA2__USBH1_DATA2,
+	MX51_PAD_USBH1_DATA3__USBH1_DATA3,
+	MX51_PAD_USBH1_DATA4__USBH1_DATA4,
+	MX51_PAD_USBH1_DATA5__USBH1_DATA5,
+	MX51_PAD_USBH1_DATA6__USBH1_DATA6,
+	MX51_PAD_USBH1_DATA7__USBH1_DATA7,
+	MX51_PAD_USBH1_STP__USBH1_STP,
+	MX51_PAD_EIM_CS3__GPIO_2_28,		/* PHY nRESET */
+
+	/* FEC */
+	MX51_PAD_EIM_DTACK__GPIO_2_31,		/* PHY nRESET */
+
+	/* HSI2C */
+	MX51_PAD_I2C1_CLK__GPIO_4_16,
+	MX51_PAD_I2C1_DAT__GPIO_4_17,
+
+	/* CAN */
+	MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
+	MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
+	MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
+	MX51_PAD_CSPI1_SS0__GPIO_4_24,		/* nCS */
+	MX51_PAD_CSI2_PIXCLK__GPIO_4_15,	/* nReset */
+	MX51_PAD_GPIO_1_1__GPIO_1_1,		/* IRQ */
+	MX51_PAD_GPIO_1_4__GPIO_1_4,		/* Control signals */
+	MX51_PAD_GPIO_1_6__GPIO_1_6,
+	MX51_PAD_GPIO_1_7__GPIO_1_7,
+	MX51_PAD_GPIO_1_8__GPIO_1_8,
+	MX51_PAD_GPIO_1_9__GPIO_1_9,
+
+	/* Touchscreen */
+	CPUIMX51SD_GPIO_3_12,			/* IRQ */
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static int ts_get_pendown_state(void)
+{
+	return gpio_get_value(TSC2007_IRQGPIO) ? 0 : 1;
+}
+
+static struct tsc2007_platform_data tsc2007_info = {
+	.model			= 2007,
+	.x_plate_ohms		= 180,
+	.get_pendown_state	= ts_get_pendown_state,
+};
+
+static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("pcf8563", 0x51),
+	}, {
+		I2C_BOARD_INFO("tsc2007", 0x49),
+		.type		= "tsc2007",
+		.platform_data	= &tsc2007_info,
+		.irq		= gpio_to_irq(TSC2007_IRQGPIO),
+	},
+};
+
+static const struct mxc_nand_platform_data
+		eukrea_cpuimx51sd_nand_board_info __initconst = {
+	.width		= 1,
+	.hw_ecc		= 1,
+	.flash_bbt	= 1,
+};
+
+/* This function is board specific as the bit mask for the plldiv will also
+be different for other Freescale SoCs, thus a common bitmask is not
+possible and cannot get place in /plat-mxc/ehci.c.*/
+static int initialize_otg_port(struct platform_device *pdev)
+{
+	u32 v;
+	void __iomem *usb_base;
+	void __iomem *usbother_base;
+
+	usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+	/* Set the PHY clock to 19.2MHz */
+	v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+	v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+	v |= MX51_USB_PLL_DIV_19_2_MHZ;
+	__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+	iounmap(usb_base);
+	return 0;
+}
+
+static int initialize_usbh1_port(struct platform_device *pdev)
+{
+	u32 v;
+	void __iomem *usb_base;
+	void __iomem *usbother_base;
+
+	usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+	/* The clock for the USBH1 ULPI port will come from the PHY. */
+	v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
+	__raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN,
+			usbother_base + MX51_USB_CTRL_1_OFFSET);
+	iounmap(usb_base);
+	return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+	.init		= initialize_otg_port,
+	.portsc	= MXC_EHCI_UTMI_16BIT,
+	.flags	= MXC_EHCI_INTERNAL_PHY,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+	.operating_mode	= FSL_USB2_DR_DEVICE,
+	.phy_mode	= FSL_USB2_PHY_UTMI_WIDE,
+};
+
+static struct mxc_usbh_platform_data usbh1_config = {
+	.init		= initialize_usbh1_port,
+	.portsc	= MXC_EHCI_MODE_ULPI,
+	.flags	= (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx51sd_otg_mode(char *options)
+{
+	if (!strcmp(options, "host"))
+		otg_mode_host = 1;
+	else if (!strcmp(options, "device"))
+		otg_mode_host = 0;
+	else
+		pr_info("otg_mode neither \"host\" nor \"device\". "
+			"Defaulting to device\n");
+	return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx51sd_otg_mode);
+
+static struct i2c_gpio_platform_data pdata = {
+	.sda_pin		= I2C_SDA,
+	.sda_is_open_drain	= 0,
+	.scl_pin		= I2C_SCL,
+	.scl_is_open_drain	= 0,
+	.udelay			= 2,
+};
+
+static struct platform_device hsi2c_gpio_device = {
+	.name			= "i2c-gpio",
+	.id			= 0,
+	.dev.platform_data	= &pdata,
+};
+
+static struct mcp251x_platform_data mcp251x_info = {
+	.oscillator_frequency = 24E6,
+};
+
+static struct spi_board_info cpuimx51sd_spi_device[] = {
+	{
+		.modalias        = "mcp2515",
+		.max_speed_hz    = 6500000,
+		.bus_num         = 0,
+		.mode		= SPI_MODE_0,
+		.chip_select     = 0,
+		.platform_data   = &mcp251x_info,
+		.irq             = gpio_to_irq(0 * 32 + 1)
+	},
+};
+
+static int cpuimx51sd_spi1_cs[] = {
+	CAN_NCS,
+};
+
+static const struct spi_imx_master cpuimx51sd_ecspi1_pdata __initconst = {
+	.chipselect	= cpuimx51sd_spi1_cs,
+	.num_chipselect	= ARRAY_SIZE(cpuimx51sd_spi1_cs),
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+	&hsi2c_gpio_device,
+};
+
+static void __init eukrea_cpuimx51sd_init(void)
+{
+	mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51sd_pads,
+					ARRAY_SIZE(eukrea_cpuimx51sd_pads));
+
+	imx51_add_imx_uart(0, &uart_pdata);
+	imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
+
+	gpio_request(ETH_RST, "eth_rst");
+	gpio_set_value(ETH_RST, 1);
+	imx51_add_fec(NULL);
+
+	gpio_request(CAN_IRQGPIO, "can_irq");
+	gpio_direction_input(CAN_IRQGPIO);
+	gpio_free(CAN_IRQGPIO);
+	gpio_request(CAN_NCS, "can_ncs");
+	gpio_direction_output(CAN_NCS, 1);
+	gpio_free(CAN_NCS);
+	gpio_request(CAN_RST, "can_rst");
+	gpio_direction_output(CAN_RST, 0);
+	msleep(20);
+	gpio_set_value(CAN_RST, 1);
+	imx51_add_ecspi(0, &cpuimx51sd_ecspi1_pdata);
+	spi_register_board_info(cpuimx51sd_spi_device,
+				ARRAY_SIZE(cpuimx51sd_spi_device));
+
+	gpio_request(TSC2007_IRQGPIO, "tsc2007_irq");
+	gpio_direction_input(TSC2007_IRQGPIO);
+	gpio_free(TSC2007_IRQGPIO);
+
+	i2c_register_board_info(0, eukrea_cpuimx51sd_i2c_devices,
+			ARRAY_SIZE(eukrea_cpuimx51sd_i2c_devices));
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+	if (otg_mode_host)
+		mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+	else {
+		initialize_otg_port(NULL);
+		mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata);
+	}
+
+	gpio_request(USBH1_RST, "usb_rst");
+	gpio_direction_output(USBH1_RST, 0);
+	msleep(20);
+	gpio_set_value(USBH1_RST, 1);
+	mxc_register_device(&mxc_usbh1_device, &usbh1_config);
+
+#ifdef CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD
+	eukrea_mbimxsd51_baseboard_init();
+#endif
+}
+
+static void __init eukrea_cpuimx51sd_timer_init(void)
+{
+	mx51_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer mxc_timer = {
+	.init	= eukrea_cpuimx51sd_timer_init,
+};
+
+MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD")
+	/* Maintainer: Eric BÃ©nard <eric@eukrea.com> */
+	.boot_params = PHYS_OFFSET + 0x100,
+	.map_io = mx51_map_io,
+	.init_irq = mx51_init_irq,
+	.init_machine = eukrea_cpuimx51sd_init,
+	.timer = &mxc_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_3ds.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_3ds.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_3ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_3ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/spi/spi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -21,12 +22,13 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx51.h>
-#include <mach/imx-uart.h>
 #include <mach/3ds_debugboard.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define EXPIO_PARENT_INT	(MXC_INTERNAL_IRQS + GPIO_PORTA + 6)
+#define MX51_3DS_ECSPI2_CS	(GPIO_PORTC + 28)
 
 static struct pad_desc mx51_3ds_pads[] = {
 	/* UART1 */
@@ -61,19 +63,25 @@
 	MX51_PAD_KEY_COL3__KEY_COL3,
 	MX51_PAD_KEY_COL4__KEY_COL4,
 	MX51_PAD_KEY_COL5__KEY_COL5,
+
+	/* eCSPI2 */
+	MX51_PAD_NANDF_RB2__ECSPI2_SCLK,
+	MX51_PAD_NANDF_RB3__ECSPI2_MISO,
+	MX51_PAD_NANDF_D15__ECSPI2_MOSI,
+	MX51_PAD_NANDF_D12__GPIO_3_28,
 };
 
 /* Serial ports */
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
 static inline void mxc_init_imx_uart(void)
 {
-	mxc_register_device(&mxc_uart_device0, &uart_pdata);
-	mxc_register_device(&mxc_uart_device1, &uart_pdata);
-	mxc_register_device(&mxc_uart_device2, &uart_pdata);
+	imx51_add_imx_uart(0, &uart_pdata);
+	imx51_add_imx_uart(1, &uart_pdata);
+	imx51_add_imx_uart(2, &uart_pdata);
 }
 #else /* !SERIAL_IMX */
 static inline void mxc_init_imx_uart(void)
@@ -127,6 +135,26 @@
 }
 #endif
 
+static int mx51_3ds_spi2_cs[] = {
+	MXC_SPI_CS(0),
+	MX51_3DS_ECSPI2_CS,
+};
+
+static const struct spi_imx_master mx51_3ds_ecspi2_pdata __initconst = {
+	.chipselect	= mx51_3ds_spi2_cs,
+	.num_chipselect	= ARRAY_SIZE(mx51_3ds_spi2_cs),
+};
+
+static struct spi_board_info mx51_3ds_spi_nor_device[] = {
+	{
+	 .modalias = "m25p80",
+	 .max_speed_hz = 25000000,	/* max spi clock (SCK) speed in HZ */
+	 .bus_num = 1,
+	 .chip_select = 1,
+	 .mode = SPI_MODE_0,
+	 .platform_data = NULL,},
+};
+
 /*
  * Board specific initialization.
  */
@@ -136,6 +164,10 @@
 					ARRAY_SIZE(mx51_3ds_pads));
 	mxc_init_imx_uart();
 
+	imx51_add_ecspi(1, &mx51_3ds_ecspi2_pdata);
+	spi_register_board_info(mx51_3ds_spi_nor_device,
+				ARRAY_SIZE(mx51_3ds_spi_nor_device));
+
 	if (mxc_expio_init(MX51_CS5_BASE_ADDR, EXPIO_PARENT_INT))
 		printk(KERN_WARNING "Init of the debugboard failed, all "
 				    "devices on the board are unusable.\n");
@@ -154,8 +186,6 @@
 
 MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
 	/* Maintainer: Freescale Semiconductor, Inc. */
-	.phys_io = MX51_AIPS1_BASE_ADDR,
-	.io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = mx51_map_io,
 	.init_irq = mx51_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_babbage.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_babbage.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_babbage.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_babbage.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
  *
  * The code contained herein is licensed under the GNU General Public
@@ -17,12 +17,13 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
+#include <linux/fec.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
@@ -31,11 +32,15 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
+#include "cpu_op-mx51.h"
 
 #define BABBAGE_USB_HUB_RESET	(0*32 + 7)	/* GPIO_1_7 */
 #define BABBAGE_USBH1_STP	(0*32 + 27)	/* GPIO_1_27 */
-#define BABBAGE_PHY_RESET (1*32 +5)	/* GPIO_2_5 */
+#define BABBAGE_PHY_RESET	(1*32 + 5)	/* GPIO_2_5 */
+#define BABBAGE_FEC_PHY_RESET	(1*32 + 14)	/* GPIO_2_14 */
+#define BABBAGE_POWER_KEY	(1*32 + 21)	/* GPIO_2_21 */
 
 /* USB_CTRL_1 */
 #define MX51_USB_CTRL_1_OFFSET			0x10
@@ -45,8 +50,19 @@
 #define	MX51_USB_PLL_DIV_19_2_MHZ	0x01
 #define	MX51_USB_PLL_DIV_24_MHZ	0x02
 
-static struct platform_device *devices[] __initdata = {
-	&mxc_fec_device,
+static struct gpio_keys_button babbage_buttons[] = {
+	{
+		.gpio		= BABBAGE_POWER_KEY,
+		.code		= BTN_0,
+		.desc		= "PWR",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+};
+
+static const struct gpio_keys_platform_data imx_button_data __initconst = {
+	.buttons	= babbage_buttons,
+	.nbuttons	= ARRAY_SIZE(babbage_buttons),
 };
 
 static struct pad_desc mx51babbage_pads[] = {
@@ -93,19 +109,57 @@
 
 	/* USB HUB reset line*/
 	MX51_PAD_GPIO_1_7__GPIO_1_7,
+
+	/* FEC */
+	MX51_PAD_EIM_EB2__FEC_MDIO,
+	MX51_PAD_EIM_EB3__FEC_RDAT1,
+	MX51_PAD_EIM_CS2__FEC_RDAT2,
+	MX51_PAD_EIM_CS3__FEC_RDAT3,
+	MX51_PAD_EIM_CS4__FEC_RX_ER,
+	MX51_PAD_EIM_CS5__FEC_CRS,
+	MX51_PAD_NANDF_RB2__FEC_COL,
+	MX51_PAD_NANDF_RB3__FEC_RXCLK,
+	MX51_PAD_NANDF_RB6__FEC_RDAT0,
+	MX51_PAD_NANDF_RB7__FEC_TDAT0,
+	MX51_PAD_NANDF_CS2__FEC_TX_ER,
+	MX51_PAD_NANDF_CS3__FEC_MDC,
+	MX51_PAD_NANDF_CS4__FEC_TDAT1,
+	MX51_PAD_NANDF_CS5__FEC_TDAT2,
+	MX51_PAD_NANDF_CS6__FEC_TDAT3,
+	MX51_PAD_NANDF_CS7__FEC_TX_EN,
+	MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK,
+
+	/* FEC PHY reset line */
+	MX51_PAD_EIM_A20__GPIO_2_14,
+
+	/* SD 1 */
+	MX51_PAD_SD1_CMD__SD1_CMD,
+	MX51_PAD_SD1_CLK__SD1_CLK,
+	MX51_PAD_SD1_DATA0__SD1_DATA0,
+	MX51_PAD_SD1_DATA1__SD1_DATA1,
+	MX51_PAD_SD1_DATA2__SD1_DATA2,
+	MX51_PAD_SD1_DATA3__SD1_DATA3,
+
+	/* SD 2 */
+	MX51_PAD_SD2_CMD__SD2_CMD,
+	MX51_PAD_SD2_CLK__SD2_CLK,
+	MX51_PAD_SD2_DATA0__SD2_DATA0,
+	MX51_PAD_SD2_DATA1__SD2_DATA1,
+	MX51_PAD_SD2_DATA2__SD2_DATA2,
+	MX51_PAD_SD2_DATA3__SD2_DATA3,
 };
 
 /* Serial ports */
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
 static inline void mxc_init_imx_uart(void)
 {
-	mxc_register_device(&mxc_uart_device0, &uart_pdata);
-	mxc_register_device(&mxc_uart_device1, &uart_pdata);
-	mxc_register_device(&mxc_uart_device2, &uart_pdata);
+	imx51_add_imx_uart(0, &uart_pdata);
+	imx51_add_imx_uart(1, &uart_pdata);
+	imx51_add_imx_uart(2, &uart_pdata);
 }
 #else /* !SERIAL_IMX */
 static inline void mxc_init_imx_uart(void)
@@ -113,7 +167,7 @@
 }
 #endif /* SERIAL_IMX */
 
-static struct imxi2c_platform_data babbage_i2c_data = {
+static const struct imxi2c_platform_data babbage_i2c_data __initconst = {
 	.bitrate = 100000,
 };
 
@@ -171,6 +225,22 @@
 	gpio_set_value(BABBAGE_USB_HUB_RESET, 1);
 }
 
+static inline void babbage_fec_reset(void)
+{
+	int ret;
+
+	/* reset FEC PHY */
+	ret = gpio_request(BABBAGE_FEC_PHY_RESET, "fec-phy-reset");
+	if (ret) {
+		printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
+		return;
+	}
+	gpio_direction_output(BABBAGE_FEC_PHY_RESET, 0);
+	gpio_set_value(BABBAGE_FEC_PHY_RESET, 0);
+	msleep(1);
+	gpio_set_value(BABBAGE_FEC_PHY_RESET, 1);
+}
+
 /* This function is board specific as the bit mask for the plldiv will also
 be different for other Freescale SoCs, thus a common bitmask is not
 possible and cannot get place in /plat-mxc/ehci.c.*/
@@ -178,7 +248,7 @@
 {
 	u32 v;
 	void __iomem *usb_base;
-	u32 usbother_base;
+	void __iomem *usbother_base;
 
 	usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
 	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
@@ -196,7 +266,7 @@
 {
 	u32 v;
 	void __iomem *usb_base;
-	u32 usbother_base;
+	void __iomem *usbother_base;
 
 	usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
 	usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
@@ -246,14 +316,24 @@
 static void __init mxc_board_init(void)
 {
 	struct pad_desc usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP;
+	struct pad_desc power_key = MX51_PAD_EIM_A27__GPIO_2_21;
 
+#if defined(CONFIG_CPU_FREQ_IMX)
+	get_cpu_op = mx51_get_cpu_op;
+#endif
 	mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
 					ARRAY_SIZE(mx51babbage_pads));
 	mxc_init_imx_uart();
-	platform_add_devices(devices, ARRAY_SIZE(devices));
+	babbage_fec_reset();
+	imx51_add_fec(NULL);
 
-	mxc_register_device(&mxc_i2c_device0, &babbage_i2c_data);
-	mxc_register_device(&mxc_i2c_device1, &babbage_i2c_data);
+	/* Set the PAD settings for the pwr key. */
+	power_key.pad_ctrl = MX51_GPIO_PAD_CTRL_2;
+	mxc_iomux_v3_setup_pad(&power_key);
+	imx51_add_gpio_keys(&imx_button_data);
+
+	imx51_add_imx_i2c(0, &babbage_i2c_data);
+	imx51_add_imx_i2c(1, &babbage_i2c_data);
 	mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data);
 
 	if (otg_mode_host)
@@ -268,6 +348,9 @@
 	/* setback USBH1_STP to be function */
 	mxc_iomux_v3_setup_pad(&usbh1stp);
 	babbage_usbhub_reset();
+
+	imx51_add_esdhc(0, NULL);
+	imx51_add_esdhc(1, NULL);
 }
 
 static void __init mx51_babbage_timer_init(void)
@@ -281,9 +364,7 @@
 
 MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
 	/* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
-	.phys_io = MX51_AIPS1_BASE_ADDR,
-	.io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
-	.boot_params = PHYS_OFFSET + 0x100,
+	.boot_params = MX51_PHYS_OFFSET + 0x100,
 	.map_io = mx51_map_io,
 	.init_irq = mx51_init_irq,
 	.init_machine = mxc_board_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_efikamx.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_efikamx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/board-mx51_efikamx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/board-mx51_efikamx.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Linaro Limited
+ *
+ * based on code from the following
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
+ * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define	MX51_USB_PLL_DIV_24_MHZ	0x01
+
+static struct pad_desc mx51efikamx_pads[] = {
+	/* UART1 */
+	MX51_PAD_UART1_RXD__UART1_RXD,
+	MX51_PAD_UART1_TXD__UART1_TXD,
+	MX51_PAD_UART1_RTS__UART1_RTS,
+	MX51_PAD_UART1_CTS__UART1_CTS,
+};
+
+/* Serial ports */
+#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+static const struct imxuart_platform_data uart_pdata = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mxc_init_imx_uart(void)
+{
+	imx51_add_imx_uart(0, &uart_pdata);
+	imx51_add_imx_uart(1, &uart_pdata);
+	imx51_add_imx_uart(2, &uart_pdata);
+}
+#else /* !SERIAL_IMX */
+static inline void mxc_init_imx_uart(void)
+{
+}
+#endif /* SERIAL_IMX */
+
+/* This function is board specific as the bit mask for the plldiv will also
+ * be different for other Freescale SoCs, thus a common bitmask is not
+ * possible and cannot get place in /plat-mxc/ehci.c.
+ */
+static int initialize_otg_port(struct platform_device *pdev)
+{
+	u32 v;
+	void __iomem *usb_base;
+	void __iomem *usbother_base;
+	usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+	usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET);
+
+	/* Set the PHY clock to 19.2MHz */
+	v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+	v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+	v |= MX51_USB_PLL_DIV_24_MHZ;
+	__raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+	iounmap(usb_base);
+	return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+	.init   = initialize_otg_port,
+	.portsc = MXC_EHCI_UTMI_16BIT,
+	.flags  = MXC_EHCI_INTERNAL_PHY,
+};
+
+static void __init mxc_board_init(void)
+{
+	mxc_iomux_v3_setup_multiple_pads(mx51efikamx_pads,
+					ARRAY_SIZE(mx51efikamx_pads));
+	mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+	mxc_init_imx_uart();
+}
+
+static void __init mx51_efikamx_timer_init(void)
+{
+	mx51_clocks_init(32768, 24000000, 22579200, 24576000);
+}
+
+static struct sys_timer mxc_timer = {
+	.init	= mx51_efikamx_timer_init,
+};
+
+MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
+	/* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
+	.boot_params = MX51_PHYS_OFFSET + 0x100,
+	.map_io = mx51_map_io,
+	.init_irq = mx51_init_irq,
+	.init_machine =  mxc_board_init,
+	.timer = &mxc_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/clock-mx51.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/clock-mx51.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/clock-mx51.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/clock-mx51.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,34 +41,66 @@
 
 #define MAX_DPLL_WAIT_TRIES	1000 /* 1000 * udelay(1) = 1ms */
 
-static int _clk_ccgr_enable(struct clk *clk)
+/* calculate best pre and post dividers to get the required divider */
+static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post,
+	u32 max_pre, u32 max_post)
 {
-	u32 reg;
+	if (div >= max_pre * max_post) {
+		*pre = max_pre;
+		*post = max_post;
+	} else if (div >= max_pre) {
+		u32 min_pre, temp_pre, old_err, err;
+		min_pre = DIV_ROUND_UP(div, max_post);
+		old_err = max_pre;
+		for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) {
+			err = div % temp_pre;
+			if (err == 0) {
+				*pre = temp_pre;
+				break;
+			}
+			err = temp_pre - err;
+			if (err < old_err) {
+				old_err = err;
+				*pre = temp_pre;
+			}
+		}
+		*post = DIV_ROUND_UP(div, *pre);
+	} else {
+		*pre = div;
+		*post = 1;
+	}
+}
+
+static void _clk_ccgr_setclk(struct clk *clk, unsigned mode)
+{
+	u32 reg = __raw_readl(clk->enable_reg);
+
+	reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
+	reg |= mode << clk->enable_shift;
 
-	reg = __raw_readl(clk->enable_reg);
-	reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift;
 	__raw_writel(reg, clk->enable_reg);
+}
 
+static int _clk_ccgr_enable(struct clk *clk)
+{
+	_clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON);
 	return 0;
 }
 
 static void _clk_ccgr_disable(struct clk *clk)
 {
-	u32 reg;
-	reg = __raw_readl(clk->enable_reg);
-	reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
-	__raw_writel(reg, clk->enable_reg);
+	_clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF);
+}
 
+static int _clk_ccgr_enable_inrun(struct clk *clk)
+{
+	_clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
+	return 0;
 }
 
 static void _clk_ccgr_disable_inwait(struct clk *clk)
 {
-	u32 reg;
-
-	reg = __raw_readl(clk->enable_reg);
-	reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
-	reg |= MXC_CCM_CCGRx_MOD_IDLE << clk->enable_shift;
-	__raw_writel(reg, clk->enable_reg);
+	_clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
 }
 
 /*
@@ -330,7 +362,7 @@
 	return 0;
 }
 
-static unsigned long clk_arm_get_rate(struct clk *clk)
+static unsigned long clk_cpu_get_rate(struct clk *clk)
 {
 	u32 cacrr, div;
 	unsigned long parent_rate;
@@ -342,6 +374,22 @@
 	return parent_rate / div;
 }
 
+static int clk_cpu_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 reg, cpu_podf;
+	unsigned long parent_rate;
+
+	parent_rate = clk_get_rate(clk->parent);
+	cpu_podf = parent_rate / rate - 1;
+	/* use post divider to change freq */
+	reg = __raw_readl(MXC_CCM_CACRR);
+	reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK;
+	reg |= cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET;
+	__raw_writel(reg, MXC_CCM_CACRR);
+
+	return 0;
+}
+
 static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent)
 {
 	u32 reg, mux;
@@ -542,60 +590,60 @@
 	return 0;
 }
 
-static unsigned long clk_uart_get_rate(struct clk *clk)
-{
-	u32 reg, prediv, podf;
-	unsigned long parent_rate;
-
-	parent_rate = clk_get_rate(clk->parent);
+#define clk_nfc_set_parent	NULL
 
-	reg = __raw_readl(MXC_CCM_CSCDR1);
-	prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
-		  MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1;
-	podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
-		MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1;
+static unsigned long clk_nfc_get_rate(struct clk *clk)
+{
+	unsigned long rate;
+	u32 reg, div;
 
-	return parent_rate / (prediv * podf);
+	reg = __raw_readl(MXC_CCM_CBCDR);
+	div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >>
+	       MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1;
+	rate = clk_get_rate(clk->parent) / div;
+	WARN_ON(rate == 0);
+	return rate;
 }
 
-static int _clk_uart_set_parent(struct clk *clk, struct clk *parent)
+static unsigned long clk_nfc_round_rate(struct clk *clk,
+						unsigned long rate)
 {
-	u32 reg, mux;
+	u32 div;
+	unsigned long parent_rate = clk_get_rate(clk->parent);
 
-	mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
-		       &lp_apm_clk);
-	reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK;
-	reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET;
-	__raw_writel(reg, MXC_CCM_CSCMR1);
+	if (!rate)
+		return -EINVAL;
 
-	return 0;
-}
+	div = parent_rate / rate;
 
-static unsigned long clk_usboh3_get_rate(struct clk *clk)
-{
-	u32 reg, prediv, podf;
-	unsigned long parent_rate;
+	if (parent_rate % rate)
+		div++;
 
-	parent_rate = clk_get_rate(clk->parent);
+	if (div > 8)
+		return -EINVAL;
 
-	reg = __raw_readl(MXC_CCM_CSCDR1);
-	prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >>
-		  MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1;
-	podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >>
-		MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1;
+	return parent_rate / div;
 
-	return parent_rate / (prediv * podf);
 }
 
-static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent)
+static int clk_nfc_set_rate(struct clk *clk, unsigned long rate)
 {
-	u32 reg, mux;
+	u32 reg, div;
 
-	mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
-		       &lp_apm_clk);
-	reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
-	reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
-	__raw_writel(reg, MXC_CCM_CSCMR1);
+	div = clk_get_rate(clk->parent) / rate;
+	if (div == 0)
+		div++;
+	if (((clk_get_rate(clk->parent) / div) != rate) || (div > 8))
+		return -EINVAL;
+
+	reg = __raw_readl(MXC_CCM_CBCDR);
+	reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK;
+	reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET;
+	__raw_writel(reg, MXC_CCM_CBCDR);
+
+	while (__raw_readl(MXC_CCM_CDHIPR) &
+			MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){
+	}
 
 	return 0;
 }
@@ -620,6 +668,17 @@
 	return ckih2_reference;
 }
 
+static unsigned long clk_emi_slow_get_rate(struct clk *clk)
+{
+	u32 reg, div;
+
+	reg = __raw_readl(MXC_CCM_CBCDR);
+	div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >>
+	       MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1;
+
+	return clk_get_rate(clk->parent) / div;
+}
+
 /* External high frequency clock */
 static struct clk ckih_clk = {
 	.get_rate = get_high_reference_clock_rate,
@@ -693,7 +752,8 @@
 
 static struct clk cpu_clk = {
 	.parent = &pll1_sw_clk,
-	.get_rate = clk_arm_get_rate,
+	.get_rate = clk_cpu_get_rate,
+	.set_rate = clk_cpu_set_rate,
 };
 
 static struct clk ahb_clk = {
@@ -715,18 +775,6 @@
 	.set_parent = _clk_ipg_per_set_parent,
 };
 
-static struct clk uart_root_clk = {
-	.parent = &pll2_sw_clk,
-	.get_rate = clk_uart_get_rate,
-	.set_parent = _clk_uart_set_parent,
-};
-
-static struct clk usboh3_clk = {
-	.parent = &pll2_sw_clk,
-	.get_rate = clk_usboh3_get_rate,
-	.set_parent = _clk_usboh3_set_parent,
-};
-
 static struct clk ahb_max_clk = {
 	.parent = &ahb_clk,
 	.enable_reg = MXC_CCM_CCGR0,
@@ -762,45 +810,183 @@
 	.id = 0,
 };
 
-#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s)	\
+static struct clk emi_slow_clk = {
+	.parent = &pll2_sw_clk,
+	.enable_reg = MXC_CCM_CCGR5,
+	.enable_shift = MXC_CCM_CCGRx_CG8_OFFSET,
+	.enable = _clk_ccgr_enable,
+	.disable = _clk_ccgr_disable_inwait,
+	.get_rate = clk_emi_slow_get_rate,
+};
+
+#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s)	\
 	static struct clk name = {			\
 		.id		= i,			\
 		.enable_reg	= er,			\
 		.enable_shift	= es,			\
-		.get_rate	= gr,			\
-		.set_rate	= sr,			\
+		.get_rate	= pfx##_get_rate,	\
+		.set_rate	= pfx##_set_rate,	\
+		.round_rate	= pfx##_round_rate,	\
+		.set_parent	= pfx##_set_parent,	\
 		.enable		= _clk_ccgr_enable,	\
 		.disable	= _clk_ccgr_disable,	\
 		.parent		= p,			\
 		.secondary	= s,			\
 	}
 
-/* DEFINE_CLOCK(name, id, enable_reg, enable_shift,
-   get_rate, set_rate, parent, secondary); */
+#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s)	\
+	static struct clk name = {			\
+		.id		= i,			\
+		.enable_reg	= er,			\
+		.enable_shift	= es,			\
+		.get_rate	= pfx##_get_rate,	\
+		.set_rate	= pfx##_set_rate,	\
+		.set_parent	= pfx##_set_parent,	\
+		.enable		= _clk_max_enable,	\
+		.disable	= _clk_max_disable,	\
+		.parent		= p,			\
+		.secondary	= s,			\
+	}
+
+#define CLK_GET_RATE(name, nr, bitsname)				\
+static unsigned long clk_##name##_get_rate(struct clk *clk)		\
+{									\
+	u32 reg, pred, podf;						\
+									\
+	reg = __raw_readl(MXC_CCM_CSCDR##nr);				\
+	pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK)	\
+		>> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET;	\
+	podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK)	\
+		>> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET;	\
+									\
+	return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent),		\
+			(pred + 1) * (podf + 1));			\
+}
+
+#define CLK_SET_PARENT(name, nr, bitsname)				\
+static int clk_##name##_set_parent(struct clk *clk, struct clk *parent)	\
+{									\
+	u32 reg, mux;							\
+									\
+	mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk,		\
+			&pll3_sw_clk, &lp_apm_clk);			\
+	reg = __raw_readl(MXC_CCM_CSCMR##nr) &				\
+		~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK;		\
+	reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET;	\
+	__raw_writel(reg, MXC_CCM_CSCMR##nr);				\
+									\
+	return 0;							\
+}
+
+#define CLK_SET_RATE(name, nr, bitsname)				\
+static int clk_##name##_set_rate(struct clk *clk, unsigned long rate)	\
+{									\
+	u32 reg, div, parent_rate;					\
+	u32 pre = 0, post = 0;						\
+									\
+	parent_rate = clk_get_rate(clk->parent);			\
+	div = parent_rate / rate;					\
+									\
+	if ((parent_rate / div) != rate)				\
+		return -EINVAL;						\
+									\
+	__calc_pre_post_dividers(div, &pre, &post,			\
+		(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >>	\
+		MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1,	\
+		(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >>	\
+		MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\
+									\
+	/* Set sdhc1 clock divider */					\
+	reg = __raw_readl(MXC_CCM_CSCDR##nr) &				\
+		~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK	\
+		| MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK);	\
+	reg |= (post - 1) <<						\
+		MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET;	\
+	reg |= (pre - 1) <<						\
+		MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET;	\
+	__raw_writel(reg, MXC_CCM_CSCDR##nr);				\
+									\
+	return 0;							\
+}
+
+/* UART */
+CLK_GET_RATE(uart, 1, UART)
+CLK_SET_PARENT(uart, 1, UART)
+
+static struct clk uart_root_clk = {
+	.parent = &pll2_sw_clk,
+	.get_rate = clk_uart_get_rate,
+	.set_parent = clk_uart_set_parent,
+};
+
+/* USBOH3 */
+CLK_GET_RATE(usboh3, 1, USBOH3)
+CLK_SET_PARENT(usboh3, 1, USBOH3)
+
+static struct clk usboh3_clk = {
+	.parent = &pll2_sw_clk,
+	.get_rate = clk_usboh3_get_rate,
+	.set_parent = clk_usboh3_set_parent,
+};
+
+/* eCSPI */
+CLK_GET_RATE(ecspi, 2, CSPI)
+CLK_SET_PARENT(ecspi, 1, CSPI)
+
+static struct clk ecspi_main_clk = {
+	.parent = &pll3_sw_clk,
+	.get_rate = clk_ecspi_get_rate,
+	.set_parent = clk_ecspi_set_parent,
+};
+
+/* eSDHC */
+CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1)
+CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+
+CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2)
+CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+
+#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s)		\
+	static struct clk name = {					\
+		.id		= i,					\
+		.enable_reg	= er,					\
+		.enable_shift	= es,					\
+		.get_rate	= gr,					\
+		.set_rate	= sr,					\
+		.enable		= e,					\
+		.disable	= d,					\
+		.parent		= p,					\
+		.secondary	= s,					\
+	}
+
+#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s)			\
+	DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s)
 
 /* Shared peripheral bus arbiter */
 DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET,
 	NULL,  NULL, &ipg_clk, NULL);
 
 /* UART */
-DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET,
-	NULL,  NULL, &uart_root_clk, NULL);
-DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET,
-	NULL,  NULL, &uart_root_clk, NULL);
-DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET,
-	NULL,  NULL, &uart_root_clk, NULL);
 DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET,
 	NULL,  NULL, &ipg_clk, &aips_tz1_clk);
 DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET,
 	NULL,  NULL, &ipg_clk, &aips_tz1_clk);
 DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET,
 	NULL,  NULL, &ipg_clk, &spba_clk);
+DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET,
+	NULL,  NULL, &uart_root_clk, &uart1_ipg_clk);
+DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET,
+	NULL,  NULL, &uart_root_clk, &uart2_ipg_clk);
+DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET,
+	NULL,  NULL, &uart_root_clk, &uart3_ipg_clk);
 
 /* GPT */
-DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
-	NULL,  NULL, &ipg_clk, NULL);
 DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET,
 	NULL,  NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
+	NULL,  NULL, &ipg_clk, &gpt_ipg_clk);
 
 /* I2C */
 DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
@@ -814,6 +1000,52 @@
 DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET,
 	NULL,  NULL, &ipg_clk, NULL);
 
+/* NFC */
+DEFINE_CLOCK_CCGR(nfc_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG10_OFFSET,
+	clk_nfc, &emi_slow_clk, NULL);
+
+/* SSI */
+DEFINE_CLOCK(ssi1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG8_OFFSET,
+	NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG9_OFFSET,
+	NULL, NULL, &pll3_sw_clk, &ssi1_ipg_clk);
+DEFINE_CLOCK(ssi2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG10_OFFSET,
+	NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG11_OFFSET,
+	NULL, NULL, &pll3_sw_clk, &ssi2_ipg_clk);
+
+/* eCSPI */
+DEFINE_CLOCK_FULL(ecspi1_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET,
+		NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable,
+		&ipg_clk, &spba_clk);
+DEFINE_CLOCK(ecspi1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG10_OFFSET,
+		NULL, NULL, &ecspi_main_clk, &ecspi1_ipg_clk);
+DEFINE_CLOCK_FULL(ecspi2_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG11_OFFSET,
+		NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable,
+		&ipg_clk, &aips_tz2_clk);
+DEFINE_CLOCK(ecspi2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG12_OFFSET,
+		NULL, NULL, &ecspi_main_clk, &ecspi2_ipg_clk);
+
+/* CSPI */
+DEFINE_CLOCK(cspi_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET,
+		NULL, NULL, &ipg_clk, &aips_tz2_clk);
+DEFINE_CLOCK(cspi_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG13_OFFSET,
+		NULL, NULL, &ipg_clk, &cspi_ipg_clk);
+
+/* SDMA */
+DEFINE_CLOCK(sdma_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG15_OFFSET,
+		NULL, NULL, &ahb_clk, NULL);
+
+/* eSDHC */
+DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET,
+	NULL,  NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET,
+	clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk);
+DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET,
+	NULL,  NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET,
+	clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk);
+
 #define _REGISTER_CLOCK(d, n, c) \
        { \
 		.dev_id = d, \
@@ -837,6 +1069,19 @@
 	_REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
 	_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
 	_REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk)
+	_REGISTER_CLOCK("mxc_nand", NULL, nfc_clk)
+	_REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+	_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+	_REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+	_REGISTER_CLOCK(NULL, "ckih", ckih_clk)
+	_REGISTER_CLOCK(NULL, "ckih2", ckih2_clk)
+	_REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk)
+	_REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
+	_REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
+	_REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+	_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+	_REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk)
 };
 
 static void clk_tree_init(void)
@@ -880,6 +1125,14 @@
 	/* set the usboh3_clk parent to pll2_sw_clk */
 	clk_set_parent(&usboh3_clk, &pll2_sw_clk);
 
+	/* Set SDHC parents to be PLL2 */
+	clk_set_parent(&esdhc1_clk, &pll2_sw_clk);
+	clk_set_parent(&esdhc2_clk, &pll2_sw_clk);
+
+	/* set SDHC root clock as 166.25MHZ*/
+	clk_set_rate(&esdhc1_clk, 166250000);
+	clk_set_rate(&esdhc2_clk, 166250000);
+
 	/* System timer */
 	mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR),
 		MX51_MXC_INT_GPT);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -70,6 +70,25 @@
 }
 EXPORT_SYMBOL(mx51_revision);
 
+#ifdef CONFIG_NEON
+
+/*
+ * All versions of the silicon before Rev. 3 have broken NEON implementations.
+ * Dependent on link order - so the assumption is that vfp_init is called
+ * before us.
+ */
+static int __init mx51_neon_fixup(void)
+{
+	if (mx51_revision() < MX51_CHIP_REV_3_0 && (elf_hwcap & HWCAP_NEON)) {
+		elf_hwcap &= ~HWCAP_NEON;
+		pr_info("Turning off NEON support, detected broken NEON implementation\n");
+	}
+	return 0;
+}
+
+late_initcall(mx51_neon_fixup);
+#endif
+
 static int __init post_cpu_init(void)
 {
 	unsigned int reg;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu_op-mx51.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu_op-mx51.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu_op-mx51.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu_op-mx51.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/types.h>
+#include <mach/hardware.h>
+#include <linux/kernel.h>
+
+static struct cpu_op mx51_cpu_op[] = {
+	{
+	.cpu_rate = 160000000,},
+	{
+	.cpu_rate = 800000000,},
+};
+
+struct cpu_op *mx51_get_cpu_op(int *op)
+{
+	*op = ARRAY_SIZE(mx51_cpu_op);
+	return mx51_cpu_op;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu_op-mx51.h linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu_op-mx51.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/cpu_op-mx51.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/cpu_op-mx51.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+extern struct cpu_op *mx51_get_cpu_op(int *op);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,120 +17,6 @@
 #include <mach/imx-uart.h>
 #include <mach/irqs.h>
 
-static struct resource uart0[] = {
-	{
-		.start = MX51_UART1_BASE_ADDR,
-		.end = MX51_UART1_BASE_ADDR + 0xfff,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX51_MXC_INT_UART1,
-		.end = MX51_MXC_INT_UART1,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_uart_device0 = {
-	.name = "imx-uart",
-	.id = 0,
-	.resource = uart0,
-	.num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
-	{
-		.start = MX51_UART2_BASE_ADDR,
-		.end = MX51_UART2_BASE_ADDR + 0xfff,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX51_MXC_INT_UART2,
-		.end = MX51_MXC_INT_UART2,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_uart_device1 = {
-	.name = "imx-uart",
-	.id = 1,
-	.resource = uart1,
-	.num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
-	{
-		.start = MX51_UART3_BASE_ADDR,
-		.end = MX51_UART3_BASE_ADDR + 0xfff,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX51_MXC_INT_UART3,
-		.end = MX51_MXC_INT_UART3,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_uart_device2 = {
-	.name = "imx-uart",
-	.id = 2,
-	.resource = uart2,
-	.num_resources = ARRAY_SIZE(uart2),
-};
-
-static struct resource mxc_fec_resources[] = {
-	{
-		.start	= MX51_MXC_FEC_BASE_ADDR,
-		.end	= MX51_MXC_FEC_BASE_ADDR + 0xfff,
-		.flags	= IORESOURCE_MEM,
-	}, {
-		.start	= MX51_MXC_INT_FEC,
-		.end	= MX51_MXC_INT_FEC,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_fec_device = {
-	.name = "fec",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(mxc_fec_resources),
-	.resource = mxc_fec_resources,
-};
-
-static struct resource mxc_i2c0_resources[] = {
-	{
-		.start = MX51_I2C1_BASE_ADDR,
-		.end = MX51_I2C1_BASE_ADDR + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX51_MXC_INT_I2C1,
-		.end = MX51_MXC_INT_I2C1,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_i2c_device0 = {
-	.name = "imx-i2c",
-	.id = 0,
-	.num_resources = ARRAY_SIZE(mxc_i2c0_resources),
-	.resource = mxc_i2c0_resources,
-};
-
-static struct resource mxc_i2c1_resources[] = {
-	{
-		.start = MX51_I2C2_BASE_ADDR,
-		.end = MX51_I2C2_BASE_ADDR + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	}, {
-		.start = MX51_MXC_INT_I2C2,
-		.end = MX51_MXC_INT_I2C2,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device mxc_i2c_device1 = {
-	.name = "imx-i2c",
-	.id = 1,
-	.num_resources = ARRAY_SIZE(mxc_i2c1_resources),
-	.resource = mxc_i2c1_resources,
-};
-
 static struct resource mxc_hsi2c_resources[] = {
 	{
 		.start = MX51_HSI2C_DMA_BASE_ADDR,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,12 +1,6 @@
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-extern struct platform_device mxc_fec_device;
 extern struct platform_device mxc_usbdr_host_device;
 extern struct platform_device mxc_usbh1_device;
 extern struct platform_device mxc_usbdr_udc_device;
 extern struct platform_device mxc_wdt;
-extern struct platform_device mxc_i2c_device0;
-extern struct platform_device mxc_i2c_device1;
 extern struct platform_device mxc_hsi2c_device;
 extern struct platform_device mxc_keypad_device;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices-imx51.h linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices-imx51.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/devices-imx51.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/devices-imx51.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <mach/mx51.h>
+#include <mach/devices-common.h>
+
+extern const struct imx_fec_data imx51_fec_data __initconst;
+#define imx51_add_fec(pdata)	\
+	imx_add_fec(&imx51_fec_data, pdata)
+
+#define imx51_add_gpio_keys(pdata) imx_add_gpio_keys(pdata)
+
+extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst;
+#define imx51_add_imx_i2c(id, pdata)	\
+	imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata)
+
+extern const struct imx_imx_ssi_data imx51_imx_ssi_data[] __initconst;
+#define imx51_add_imx_ssi(id, pdata)	\
+	imx_add_imx_ssi(&imx51_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst;
+#define imx51_add_imx_uart(id, pdata)	\
+	imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata)
+
+extern const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst;
+#define imx51_add_mxc_nand(pdata)	\
+	imx_add_mxc_nand(&imx51_mxc_nand_data, pdata)
+
+extern const struct imx_spi_imx_data imx51_cspi_data __initconst;
+#define imx51_add_cspi(pdata)	\
+	imx_add_spi_imx(&imx51_cspi_data, pdata)
+
+extern const struct imx_spi_imx_data imx51_ecspi_data[] __initconst;
+#define imx51_add_ecspi(id, pdata)	\
+	imx_add_spi_imx(&imx51_ecspi_data[id], pdata)
+
+extern const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst;
+#define imx51_add_esdhc(id, pdata)	\
+	imx_add_esdhc(&imx51_esdhc_data[id], pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 
 #include <asm/mach/arch.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define MBIMX51_TSC2007_GPIO	(2*32 + 30)
@@ -112,9 +113,25 @@
 	MX51_PAD_KEY_COL1__KEY_COL1,
 	MX51_PAD_KEY_COL2__KEY_COL2,
 	MX51_PAD_KEY_COL3__KEY_COL3,
+
+	/* SD 1 */
+	MX51_PAD_SD1_CMD__SD1_CMD,
+	MX51_PAD_SD1_CLK__SD1_CLK,
+	MX51_PAD_SD1_DATA0__SD1_DATA0,
+	MX51_PAD_SD1_DATA1__SD1_DATA1,
+	MX51_PAD_SD1_DATA2__SD1_DATA2,
+	MX51_PAD_SD1_DATA3__SD1_DATA3,
+
+	/* SD 2 */
+	MX51_PAD_SD2_CMD__SD2_CMD,
+	MX51_PAD_SD2_CLK__SD2_CLK,
+	MX51_PAD_SD2_DATA0__SD2_DATA0,
+	MX51_PAD_SD2_DATA1__SD2_DATA1,
+	MX51_PAD_SD2_DATA2__SD2_DATA2,
+	MX51_PAD_SD2_DATA3__SD2_DATA3,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
 	.flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -158,9 +175,11 @@
 
 static struct i2c_board_info mbimx51_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("tsc2007", 0x48),
+		I2C_BOARD_INFO("tsc2007", 0x49),
 		.irq  = MBIMX51_TSC2007_IRQ,
 		.platform_data = &tsc2007_data,
+	}, {
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
 	},
 };
 
@@ -172,8 +191,8 @@
 	mxc_iomux_v3_setup_multiple_pads(mbimx51_pads,
 					ARRAY_SIZE(mbimx51_pads));
 
-	mxc_register_device(&mxc_uart_device1, NULL);
-	mxc_register_device(&mxc_uart_device2, &uart_pdata);
+	imx51_add_imx_uart(1, NULL);
+	imx51_add_imx_uart(2, &uart_pdata);
 
 	gpio_request(MBIMX51_LED0, "LED0");
 	gpio_direction_output(MBIMX51_LED0, 1);
@@ -197,4 +216,7 @@
 	set_irq_type(MBIMX51_TSC2007_IRQ, IRQF_TRIGGER_FALLING);
 	i2c_register_board_info(1, mbimx51_i2c_devices,
 				ARRAY_SIZE(mbimx51_i2c_devices));
+
+	imx51_add_esdhc(0, NULL);
+	imx51_add_esdhc(1, NULL);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ *
+ * Based on pcm970-baseboard.c which is :
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/imx-uart.h>
+#include <mach/iomux-mx51.h>
+#include <mach/audmux.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define MBIMXSD_GPIO_3_31 IOMUX_PAD(0x554, 0x16C, 3, 0x0, 0, \
+				MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
+
+static struct pad_desc eukrea_mbimxsd_pads[] = {
+	/* LED */
+	MX51_PAD_NANDF_D10__GPIO_3_30,
+	/* SWITCH */
+	MBIMXSD_GPIO_3_31,
+	/* UART2 */
+	MX51_PAD_UART2_RXD__UART2_RXD,
+	MX51_PAD_UART2_TXD__UART2_TXD,
+	/* UART 3 */
+	MX51_PAD_UART3_RXD__UART3_RXD,
+	MX51_PAD_UART3_TXD__UART3_TXD,
+	MX51_PAD_KEY_COL4__UART3_RTS,
+	MX51_PAD_KEY_COL5__UART3_CTS,
+	/* SD */
+	MX51_PAD_SD1_CMD__SD1_CMD,
+	MX51_PAD_SD1_CLK__SD1_CLK,
+	MX51_PAD_SD1_DATA0__SD1_DATA0,
+	MX51_PAD_SD1_DATA1__SD1_DATA1,
+	MX51_PAD_SD1_DATA2__SD1_DATA2,
+	MX51_PAD_SD1_DATA3__SD1_DATA3,
+};
+
+#define GPIO_LED1	(2 * 32 + 30)
+#define GPIO_SWITCH1	(2 * 32 + 31)
+
+static struct gpio_led eukrea_mbimxsd_leds[] = {
+	{
+		.name			= "led1",
+		.default_trigger	= "heartbeat",
+		.active_low		= 1,
+		.gpio			= GPIO_LED1,
+	},
+};
+
+static struct gpio_led_platform_data eukrea_mbimxsd_led_info = {
+	.leds		= eukrea_mbimxsd_leds,
+	.num_leds	= ARRAY_SIZE(eukrea_mbimxsd_leds),
+};
+
+static struct platform_device eukrea_mbimxsd_leds_gpio = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &eukrea_mbimxsd_led_info,
+	},
+};
+
+static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
+	{
+		.gpio		= GPIO_SWITCH1,
+		.code		= BTN_0,
+		.desc		= "BP1",
+		.active_low	= 1,
+		.wakeup		= 1,
+	},
+};
+
+static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+	.buttons	= eukrea_mbimxsd_gpio_buttons,
+	.nbuttons	= ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
+};
+
+static struct platform_device eukrea_mbimxsd_button_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.num_resources	= 0,
+	.dev		= {
+		.platform_data	= &eukrea_mbimxsd_button_data,
+	}
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+	&eukrea_mbimxsd_leds_gpio,
+	&eukrea_mbimxsd_button_device,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+	.flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("tlv320aic23", 0x1a),
+	},
+};
+
+/*
+ * system init for baseboard usage. Will be called by cpuimx51sd init.
+ *
+ * Add platform devices present on this baseboard and init
+ * them from CPU side as far as required to use them later on
+ */
+void __init eukrea_mbimxsd51_baseboard_init(void)
+{
+	if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
+			ARRAY_SIZE(eukrea_mbimxsd_pads)))
+		printk(KERN_ERR "error setting mbimxsd pads !\n");
+
+	imx51_add_imx_uart(1, NULL);
+	imx51_add_imx_uart(2, &uart_pdata);
+
+	imx51_add_esdhc(0, NULL);
+
+	gpio_request(GPIO_LED1, "LED1");
+	gpio_direction_output(GPIO_LED1, 1);
+	gpio_free(GPIO_LED1);
+
+	gpio_request(GPIO_SWITCH1, "SWITCH1");
+	gpio_direction_input(GPIO_SWITCH1);
+	gpio_free(GPIO_SWITCH1);
+
+	i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
+				ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+
+	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-mx5/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,11 +5,16 @@
 	default y
 	select MXC_TZIC
 	select ARCH_MXC_IOMUX_V3
+	select ARCH_MXC_AUDMUX_V2
+	select ARCH_HAS_CPUFREQ
 
 comment "MX5 platforms:"
 
 config MACH_MX51_BABBAGE
 	bool "Support MX51 BABBAGE platforms"
+	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_ESDHC
 	help
 	  Include support for MX51 Babbage platform, also known as MX51EVK in
 	  u-boot. This includes specific configurations for the board and its
@@ -17,6 +22,8 @@
 
 config MACH_MX51_3DS
 	bool "Support MX51PDK (3DS)"
+	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_SPI_IMX
 	select MXC_DEBUG_BOARD
 	help
 	  Include support for MX51PDK (3DS) platform. This includes specific
@@ -24,6 +31,10 @@
 
 config MACH_EUKREA_CPUIMX51
 	bool "Support Eukrea CPUIMX51 module"
+	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_MXC_NAND
+	select IMX_HAVE_PLATFORM_SPI_IMX
 	help
 	  Include support for Eukrea CPUIMX51 platform. This includes
 	  specific configurations for the module and its peripherals.
@@ -36,10 +47,43 @@
 config MACH_EUKREA_MBIMX51_BASEBOARD
 	prompt "Eukrea MBIMX51 development board"
 	bool
+	select IMX_HAVE_PLATFORM_ESDHC
 	help
 	  This adds board specific devices that can be found on Eukrea's
 	  MBIMX51 evaluation board.
 
 endchoice
 
+config MACH_EUKREA_CPUIMX51SD
+	bool "Support Eukrea CPUIMX51SD module"
+	select IMX_HAVE_PLATFORM_IMX_I2C
+	select IMX_HAVE_PLATFORM_SPI_IMX
+	select IMX_HAVE_PLATFORM_IMX_UART
+	select IMX_HAVE_PLATFORM_MXC_NAND
+	help
+	  Include support for Eukrea CPUIMX51SD platform. This includes
+	  specific configurations for the module and its peripherals.
+
+choice
+	prompt "Baseboard"
+	depends on MACH_EUKREA_CPUIMX51SD
+	default MACH_EUKREA_MBIMXSD51_BASEBOARD
+
+config MACH_EUKREA_MBIMXSD51_BASEBOARD
+	prompt "Eukrea MBIMXSD development board"
+	bool
+	select IMX_HAVE_PLATFORM_ESDHC
+	help
+	  This adds board specific devices that can be found on Eukrea's
+	  MBIMXSD evaluation board.
+
+endchoice
+
+config MACH_MX51_EFIKAMX
+	bool "Support MX51 Genesi Efika MX nettop"
+	select IMX_HAVE_PLATFORM_IMX_UART
+	help
+	  Include support for Genesi Efika MX nettop. This includes specific
+	  configurations for the board and its peripherals.
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mx5/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-mx5/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-mx5/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mx5/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,11 @@
 # Object file lists.
 obj-y   := cpu.o mm.o clock-mx51.o devices.o
 
+obj-$(CONFIG_CPU_FREQ_IMX)    += cpu_op-mx51.o
 obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
 obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
 obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-mxc91231/magx-zn5.c linux-libre-2.6.37-gnu/arch/arm/mach-mxc91231/magx-zn5.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-mxc91231/magx-zn5.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-mxc91231/magx-zn5.c	2011-01-04 19:50:19.000000000 -0500
@@ -53,8 +53,6 @@
 };
 
 MACHINE_START(MAGX_ZN5, "Motorola Zn5")
-	.phys_io	= MXC91231_AIPS1_BASE_ADDR,
-	.io_pg_offst	= ((MXC91231_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
 	.boot_params	= MXC91231_PHYS_OFFSET + 0x100,
 	.map_io		= mxc91231_map_io,
 	.init_irq	= mxc91231_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-netx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-netx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-netx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-netx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -13,12 +13,10 @@
 
 #include "hardware.h"
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x00100000		@ physical
-		movne	\rx, #io_p2v(0x00100000)	@ virtual
-		orr	\rx, \rx, #0x00000a00
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00000a00
+		orr	\rv, \rp, #io_p2v(0x00100000)	@ virtual
+		orr	\rp, \rp, #0x00100000		@ physical
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-netx/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-netx/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-netx/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-netx/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,4 +16,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxdb500.c linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxdb500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxdb500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxdb500.c	2011-01-04 19:50:19.000000000 -0500
@@ -200,8 +200,6 @@
 }
 
 MACHINE_START(NXDB500, "Hilscher nxdb500")
-	.phys_io	= 0x00100000,
-	.io_pg_offst	= (io_p2v(0x00100000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= netx_map_io,
 	.init_irq	= netx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxdkn.c linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxdkn.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxdkn.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxdkn.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,8 +93,6 @@
 }
 
 MACHINE_START(NXDKN, "Hilscher nxdkn")
-	.phys_io	= 0x00100000,
-	.io_pg_offst	= (io_p2v(0x00100000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= netx_map_io,
 	.init_irq	= netx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxeb500hmi.c linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxeb500hmi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-netx/nxeb500hmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-netx/nxeb500hmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -177,8 +177,6 @@
 }
 
 MACHINE_START(NXEB500HMI, "Hilscher nxeb500hmi")
-	.phys_io	= 0x00100000,
-	.io_pg_offst	= (io_p2v(0x00100000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= netx_map_io,
 	.init_irq	= netx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-nomadik/board-nhk8815.c linux-libre-2.6.37-gnu/arch/arm/mach-nomadik/board-nhk8815.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-nomadik/board-nhk8815.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-nomadik/board-nhk8815.c	2011-01-04 19:50:19.000000000 -0500
@@ -276,8 +276,6 @@
 
 MACHINE_START(NOMADIK, "NHK8815")
 	/* Maintainer: ST MicroElectronics */
-	.phys_io	= NOMADIK_UART0_BASE,
-	.io_pg_offst	= (IO_ADDRESS(NOMADIK_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= cpu8815_map_io,
 	.init_irq	= cpu8815_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-nomadik/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-nomadik/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-nomadik/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-nomadik/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,13 +10,11 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x10000000	@ physical base address
-		movne	\rx, #0xf0000000	@ virtual base
-		add	\rx, \rx, #0x00100000
-		add	\rx, \rx, #0x000fb000
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00100000
+		add	\rp, \rp, #0x000fb000
+		add	\rv, \rp, #0xf0000000	@ virtual base
+		add	\rp, \rp, #0x10000000	@ physical base address
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ns9xxx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ns9xxx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ns9xxx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ns9xxx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -12,11 +12,9 @@
 
 #include <mach/regs-board-a9m9750dev.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, =NS9XXX_CSxSTAT_PHYS(0)
-		ldrne	\rx, =io_p2v(NS9XXX_CSxSTAT_PHYS(0))
+		.macro	addruart, rp, rv
+		ldr	\rp, =NS9XXX_CSxSTAT_PHYS(0)
+		ldr	\rv, =io_p2v(NS9XXX_CSxSTAT_PHYS(0))
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-nuc93x/mach-nuc932evb.c linux-libre-2.6.37-gnu/arch/arm/mach-nuc93x/mach-nuc932evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-nuc93x/mach-nuc932evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-nuc93x/mach-nuc932evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,8 +35,6 @@
 
 MACHINE_START(NUC932EVB, "NUC932EVB")
 	/* Maintainer: Wan ZongShun */
-	.phys_io	= NUC93X_PA_UART,
-	.io_pg_offst	= (((u32)NUC93X_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= 0,
 	.map_io		= nuc932evb_map_io,
 	.init_irq	= nuc93x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-ams-delta.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-ams-delta.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-ams-delta.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-ams-delta.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,9 +16,12 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/leds.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 
+#include <media/soc_camera.h>
+
 #include <asm/serial.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -32,6 +35,7 @@
 #include <plat/usb.h>
 #include <plat/board.h>
 #include <plat/common.h>
+#include <mach/camera.h>
 
 #include <mach/ams-delta-fiq.h>
 
@@ -213,10 +217,56 @@
 	.id	= -1
 };
 
+static struct i2c_board_info ams_delta_camera_board_info[] = {
+	{
+		I2C_BOARD_INFO("ov6650", 0x60),
+	},
+};
+
+#ifdef CONFIG_LEDS_TRIGGERS
+DEFINE_LED_TRIGGER(ams_delta_camera_led_trigger);
+
+static int ams_delta_camera_power(struct device *dev, int power)
+{
+	/*
+	 * turn on camera LED
+	 */
+	if (power)
+		led_trigger_event(ams_delta_camera_led_trigger, LED_FULL);
+	else
+		led_trigger_event(ams_delta_camera_led_trigger, LED_OFF);
+	return 0;
+}
+#else
+#define ams_delta_camera_power	NULL
+#endif
+
+static struct soc_camera_link __initdata ams_delta_iclink = {
+	.bus_id         = 0,	/* OMAP1 SoC camera bus */
+	.i2c_adapter_id = 1,
+	.board_info     = &ams_delta_camera_board_info[0],
+	.module_name    = "ov6650",
+	.power		= ams_delta_camera_power,
+};
+
+static struct platform_device ams_delta_camera_device = {
+	.name   = "soc-camera-pdrv",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &ams_delta_iclink,
+	},
+};
+
+static struct omap1_cam_platform_data ams_delta_camera_platform_data = {
+	.camexclk_khz	= 12000,	/* default 12MHz clock, no extra DPLL */
+	.lclk_khz_max	= 1334,		/* results in 5fps CIF, 10fps QCIF */
+};
+
 static struct platform_device *ams_delta_devices[] __initdata = {
 	&ams_delta_kp_device,
 	&ams_delta_lcd_device,
 	&ams_delta_led_device,
+	&ams_delta_camera_device,
 };
 
 static void __init ams_delta_init(void)
@@ -225,6 +275,20 @@
 	omap_cfg_reg(UART1_TX);
 	omap_cfg_reg(UART1_RTS);
 
+	/* parallel camera interface */
+	omap_cfg_reg(H19_1610_CAM_EXCLK);
+	omap_cfg_reg(J15_1610_CAM_LCLK);
+	omap_cfg_reg(L18_1610_CAM_VS);
+	omap_cfg_reg(L15_1610_CAM_HS);
+	omap_cfg_reg(L19_1610_CAM_D0);
+	omap_cfg_reg(K14_1610_CAM_D1);
+	omap_cfg_reg(K15_1610_CAM_D2);
+	omap_cfg_reg(K19_1610_CAM_D3);
+	omap_cfg_reg(K18_1610_CAM_D4);
+	omap_cfg_reg(J14_1610_CAM_D5);
+	omap_cfg_reg(J19_1610_CAM_D6);
+	omap_cfg_reg(J18_1610_CAM_D7);
+
 	iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
 
 	omap_board_config = ams_delta_config;
@@ -236,6 +300,11 @@
 	ams_delta_latch2_write(~0, 0);
 
 	omap1_usb_init(&ams_delta_usb_config);
+	omap1_set_camera_info(&ams_delta_camera_platform_data);
+#ifdef CONFIG_LEDS_TRIGGERS
+	led_trigger_register_simple("ams_delta_camera",
+			&ams_delta_camera_led_trigger);
+#endif
 	platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
 
 #ifdef CONFIG_AMS_DELTA_FIQ
@@ -297,8 +366,6 @@
 
 MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
 	/* Maintainer: Jonathan McDowell <noodles@earth.li> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= ams_delta_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-fsample.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-fsample.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-fsample.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-fsample.c	2011-01-04 19:50:19.000000000 -0500
@@ -386,8 +386,6 @@
 
 MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
 /* Maintainer: Brian Swetland <swetland@google.com> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_fsample_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-generic.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-generic.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -94,8 +94,6 @@
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
 	/* Maintainer: Tony Lindgren <tony@atomide.com> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_generic_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h2.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h2.c	2011-01-04 19:50:19.000000000 -0500
@@ -458,8 +458,6 @@
 
 MACHINE_START(OMAP_H2, "TI-H2")
 	/* Maintainer: Imre Deak <imre.deak@nokia.com> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= h2_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h2-mmc.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h2-mmc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h2-mmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h2-mmc.c	2011-01-04 19:50:19.000000000 -0500
@@ -58,8 +58,7 @@
 	.dma_mask			= 0xffffffff,
 	.slots[0]       = {
 		.set_power              = mmc_set_power,
-		.ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-					  MMC_VDD_32_33 | MMC_VDD_33_34,
+		.ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
 		.name                   = "mmcblk",
 	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h3.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h3.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h3.c	2011-01-04 19:50:19.000000000 -0500
@@ -446,8 +446,6 @@
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
 	/* Maintainer: Texas Instruments, Inc. */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= h3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h3-mmc.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h3-mmc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-h3-mmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-h3-mmc.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,8 +40,7 @@
 	.dma_mask			= 0xffffffff,
 	.slots[0]       = {
 		.set_power              = mmc_set_power,
-		.ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-					  MMC_VDD_32_33 | MMC_VDD_33_34,
+		.ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
 		.name                   = "mmcblk",
 	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-htcherald.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-htcherald.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-htcherald.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-htcherald.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,13 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/htcpld.h>
+#include <linux/leds.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -39,6 +46,7 @@
 #include <plat/board.h>
 #include <plat/keypad.h>
 #include <plat/usb.h>
+#include <plat/mmc.h>
 
 #include <mach/irqs.h>
 
@@ -52,13 +60,123 @@
 #define       OMAP_LCDC_CTRL_LCD_EN           (1 << 0)
 #define       OMAP_LCDC_STAT_DONE             (1 << 0)
 
-static struct omap_lcd_config htcherald_lcd_config __initdata = {
-	.ctrl_name	= "internal",
-};
+/* GPIO definitions for the power button and keyboard slide switch */
+#define HTCHERALD_GPIO_POWER 139
+#define HTCHERALD_GPIO_SLIDE 174
+#define HTCHERALD_GIRQ_BTNS 141
 
-static struct omap_board_config_kernel htcherald_config[] __initdata = {
-	{ OMAP_TAG_LCD, &htcherald_lcd_config },
-};
+/* GPIO definitions for the touchscreen */
+#define HTCHERALD_GPIO_TS 76
+
+/* HTCPLD definitions */
+
+/*
+ * CPLD Logic
+ *
+ * Chip 3 - 0x03
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * DPAD light          x x x x  x x x 1
+ * SoundDev            x x x x  1 x x x
+ * Screen white        1 x x x  x x x x
+ * MMC power on        x x x x  x 1 x x
+ * Happy times (n)     0 x x x  x 1 x x
+ *
+ * Chip 4 - 0x04
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Keyboard light      x x x x  x x x 1
+ * LCD Bright (4)      x x x x  x 1 1 x
+ * LCD Bright (3)      x x x x  x 0 1 x
+ * LCD Bright (2)      x x x x  x 1 0 x
+ * LCD Bright (1)      x x x x  x 0 0 x
+ * LCD Off             x x x x  0 x x x
+ * LCD image (fb)      1 x x x  x x x x
+ * LCD image (white)   0 x x x  x x x x
+ * Caps lock LED       x x 1 x  x x x x
+ *
+ * Chip 5 - 0x05
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Red (solid)         x x x x  x 1 x x
+ * Red (flash)         x x x x  x x 1 x
+ * Green (GSM flash)   x x x x  1 x x x
+ * Green (GSM solid)   x x x 1  x x x x
+ * Green (wifi flash)  x x 1 x  x x x x
+ * Blue (bt flash)     x 1 x x  x x x x
+ * DPAD Int Enable     1 x x x  x x x 0
+ *
+ * (Combinations of the above can be made for different colors.)
+ * The direction pad interrupt enable must be set each time the
+ * interrupt is handled.
+ *
+ * Chip 6 - 0x06
+ *
+ * Function            7 6 5 4  3 2 1 0
+ * ------------------------------------
+ * Vibrator            x x x x  1 x x x
+ * Alt LED             x x x 1  x x x x
+ * Screen white        1 x x x  x x x x
+ * Screen white        x x 1 x  x x x x
+ * Screen white        x 0 x x  x x x x
+ * Enable kbd dpad     x x x x  x x 0 x
+ * Happy Times         0 1 0 x  x x 0 x
+ */
+
+/*
+ * HTCPLD GPIO lines start 16 after OMAP_MAX_GPIO_LINES to account
+ * for the 16 MPUIO lines.
+ */
+#define HTCPLD_GPIO_START_OFFSET	(OMAP_MAX_GPIO_LINES + 16)
+#define HTCPLD_IRQ(chip, offset)	(OMAP_IRQ_END + 8 * (chip) + (offset))
+#define HTCPLD_BASE(chip, offset)	\
+	(HTCPLD_GPIO_START_OFFSET + 8 * (chip) + (offset))
+
+#define HTCPLD_GPIO_LED_DPAD		HTCPLD_BASE(0, 0)
+#define HTCPLD_GPIO_LED_KBD		HTCPLD_BASE(1, 0)
+#define HTCPLD_GPIO_LED_CAPS		HTCPLD_BASE(1, 5)
+#define HTCPLD_GPIO_LED_RED_FLASH	HTCPLD_BASE(2, 1)
+#define HTCPLD_GPIO_LED_RED_SOLID	HTCPLD_BASE(2, 2)
+#define HTCPLD_GPIO_LED_GREEN_FLASH	HTCPLD_BASE(2, 3)
+#define HTCPLD_GPIO_LED_GREEN_SOLID	HTCPLD_BASE(2, 4)
+#define HTCPLD_GPIO_LED_WIFI		HTCPLD_BASE(2, 5)
+#define HTCPLD_GPIO_LED_BT		HTCPLD_BASE(2, 6)
+#define HTCPLD_GPIO_LED_VIBRATE		HTCPLD_BASE(3, 3)
+#define HTCPLD_GPIO_LED_ALT		HTCPLD_BASE(3, 4)
+
+#define HTCPLD_GPIO_RIGHT_KBD		HTCPLD_BASE(6, 7)
+#define HTCPLD_GPIO_UP_KBD		HTCPLD_BASE(6, 6)
+#define HTCPLD_GPIO_LEFT_KBD		HTCPLD_BASE(6, 5)
+#define HTCPLD_GPIO_DOWN_KBD		HTCPLD_BASE(6, 4)
+
+#define HTCPLD_GPIO_RIGHT_DPAD		HTCPLD_BASE(7, 7)
+#define HTCPLD_GPIO_UP_DPAD		HTCPLD_BASE(7, 6)
+#define HTCPLD_GPIO_LEFT_DPAD		HTCPLD_BASE(7, 5)
+#define HTCPLD_GPIO_DOWN_DPAD		HTCPLD_BASE(7, 4)
+#define HTCPLD_GPIO_ENTER_DPAD		HTCPLD_BASE(7, 3)
+
+/*
+ * The htcpld chip requires a gpio write to a specific line
+ * to re-enable interrupts after one has occurred.
+ */
+#define HTCPLD_GPIO_INT_RESET_HI	HTCPLD_BASE(2, 7)
+#define HTCPLD_GPIO_INT_RESET_LO	HTCPLD_BASE(2, 0)
+
+/* Chip 5 */
+#define HTCPLD_IRQ_RIGHT_KBD		HTCPLD_IRQ(0, 7)
+#define HTCPLD_IRQ_UP_KBD		HTCPLD_IRQ(0, 6)
+#define HTCPLD_IRQ_LEFT_KBD		HTCPLD_IRQ(0, 5)
+#define HTCPLD_IRQ_DOWN_KBD		HTCPLD_IRQ(0, 4)
+
+/* Chip 6 */
+#define HTCPLD_IRQ_RIGHT_DPAD		HTCPLD_IRQ(1, 7)
+#define HTCPLD_IRQ_UP_DPAD		HTCPLD_IRQ(1, 6)
+#define HTCPLD_IRQ_LEFT_DPAD		HTCPLD_IRQ(1, 5)
+#define HTCPLD_IRQ_DOWN_DPAD		HTCPLD_IRQ(1, 4)
+#define HTCPLD_IRQ_ENTER_DPAD		HTCPLD_IRQ(1, 3)
 
 /* Keyboard definition */
 
@@ -140,6 +258,129 @@
 	.resource	= kp_resources,
 };
 
+/* GPIO buttons for keyboard slide and power button */
+static struct gpio_keys_button herald_gpio_keys_table[] = {
+	{BTN_0,  HTCHERALD_GPIO_POWER, 1, "POWER", EV_KEY, 1, 20},
+	{SW_LID, HTCHERALD_GPIO_SLIDE, 0, "SLIDE", EV_SW,  1, 20},
+
+	{KEY_LEFT,  HTCPLD_GPIO_LEFT_KBD,  1, "LEFT",  EV_KEY, 1, 20},
+	{KEY_RIGHT, HTCPLD_GPIO_RIGHT_KBD, 1, "RIGHT", EV_KEY, 1, 20},
+	{KEY_UP,    HTCPLD_GPIO_UP_KBD,    1, "UP",    EV_KEY, 1, 20},
+	{KEY_DOWN,  HTCPLD_GPIO_DOWN_KBD,  1, "DOWN",  EV_KEY, 1, 20},
+
+	{KEY_LEFT,  HTCPLD_GPIO_LEFT_DPAD,   1, "DLEFT",  EV_KEY, 1, 20},
+	{KEY_RIGHT, HTCPLD_GPIO_RIGHT_DPAD,  1, "DRIGHT", EV_KEY, 1, 20},
+	{KEY_UP,    HTCPLD_GPIO_UP_DPAD,     1, "DUP",    EV_KEY, 1, 20},
+	{KEY_DOWN,  HTCPLD_GPIO_DOWN_DPAD,   1, "DDOWN",  EV_KEY, 1, 20},
+	{KEY_ENTER, HTCPLD_GPIO_ENTER_DPAD,  1, "DENTER", EV_KEY, 1, 20},
+};
+
+static struct gpio_keys_platform_data herald_gpio_keys_data = {
+	.buttons	= herald_gpio_keys_table,
+	.nbuttons	= ARRAY_SIZE(herald_gpio_keys_table),
+	.rep		= 1,
+};
+
+static struct platform_device herald_gpiokeys_device = {
+	.name      = "gpio-keys",
+	.id		= -1,
+	.dev = {
+		.platform_data = &herald_gpio_keys_data,
+	},
+};
+
+/* LEDs for the Herald.  These connect to the HTCPLD GPIO device. */
+static struct gpio_led gpio_leds[] = {
+	{"dpad",        NULL, HTCPLD_GPIO_LED_DPAD,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"kbd",         NULL, HTCPLD_GPIO_LED_KBD,         0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"vibrate",     NULL, HTCPLD_GPIO_LED_VIBRATE,     0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"green_solid", NULL, HTCPLD_GPIO_LED_GREEN_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"green_flash", NULL, HTCPLD_GPIO_LED_GREEN_FLASH, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"red_solid",   "mmc0", HTCPLD_GPIO_LED_RED_SOLID, 0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"red_flash",   NULL, HTCPLD_GPIO_LED_RED_FLASH,   0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"wifi",        NULL, HTCPLD_GPIO_LED_WIFI,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"bt",          NULL, HTCPLD_GPIO_LED_BT,          0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"caps",        NULL, HTCPLD_GPIO_LED_CAPS,        0, 0, LEDS_GPIO_DEFSTATE_OFF},
+	{"alt",         NULL, HTCPLD_GPIO_LED_ALT,         0, 0, LEDS_GPIO_DEFSTATE_OFF},
+};
+
+static struct gpio_led_platform_data gpio_leds_data = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device gpio_leds_device = {
+	.name		= "leds-gpio",
+	.id		= 0,
+	.dev	= {
+		.platform_data	= &gpio_leds_data,
+	},
+};
+
+/* HTC PLD chips */
+
+static struct resource htcpld_resources[] = {
+	[0] = {
+		.start  = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+		.end    = OMAP_GPIO_IRQ(HTCHERALD_GIRQ_BTNS),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+struct htcpld_chip_platform_data htcpld_chips[] = {
+	[0] = {
+		.addr		= 0x03,
+		.reset		= 0x04,
+		.num_gpios	= 8,
+		.gpio_out_base	= HTCPLD_BASE(0, 0),
+		.gpio_in_base	= HTCPLD_BASE(4, 0),
+	},
+	[1] = {
+		.addr		= 0x04,
+		.reset		= 0x8e,
+		.num_gpios	= 8,
+		.gpio_out_base	= HTCPLD_BASE(1, 0),
+		.gpio_in_base	= HTCPLD_BASE(5, 0),
+	},
+	[2] = {
+		.addr		= 0x05,
+		.reset		= 0x80,
+		.num_gpios	= 8,
+		.gpio_out_base	= HTCPLD_BASE(2, 0),
+		.gpio_in_base	= HTCPLD_BASE(6, 0),
+		.irq_base	= HTCPLD_IRQ(0, 0),
+		.num_irqs	= 8,
+	},
+	[3] = {
+		.addr		= 0x06,
+		.reset		= 0x40,
+		.num_gpios	= 8,
+		.gpio_out_base	= HTCPLD_BASE(3, 0),
+		.gpio_in_base	= HTCPLD_BASE(7, 0),
+		.irq_base	= HTCPLD_IRQ(1, 0),
+		.num_irqs	= 8,
+	},
+};
+
+struct htcpld_core_platform_data htcpld_pfdata = {
+	.int_reset_gpio_hi = HTCPLD_GPIO_INT_RESET_HI,
+	.int_reset_gpio_lo = HTCPLD_GPIO_INT_RESET_LO,
+	.i2c_adapter_id	   = 1,
+
+	.chip		   = htcpld_chips,
+	.num_chip	   = ARRAY_SIZE(htcpld_chips),
+};
+
+static struct platform_device htcpld_device = {
+	.name		= "i2c-htcpld",
+	.id		= -1,
+	.resource	= htcpld_resources,
+	.num_resources	= ARRAY_SIZE(htcpld_resources),
+	.dev	= {
+		.platform_data	= &htcpld_pfdata,
+	},
+};
+
 /* USB Device */
 static struct omap_usb_config htcherald_usb_config __initdata = {
 	.otg = 0,
@@ -150,14 +391,71 @@
 };
 
 /* LCD Device resources */
+static struct omap_lcd_config htcherald_lcd_config __initdata = {
+	.ctrl_name	= "internal",
+};
+
+static struct omap_board_config_kernel htcherald_config[] __initdata = {
+	{ OMAP_TAG_LCD, &htcherald_lcd_config },
+};
+
 static struct platform_device lcd_device = {
 	.name           = "lcd_htcherald",
 	.id             = -1,
 };
 
+/* MMC Card */
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+static struct omap_mmc_platform_data htc_mmc1_data = {
+	.nr_slots                       = 1,
+	.switch_slot                    = NULL,
+	.slots[0]       = {
+		.ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
+		.name                   = "mmcblk",
+		.nomux                  = 1,
+		.wires                  = 4,
+		.switch_pin             = -1,
+	},
+};
+
+static struct omap_mmc_platform_data *htc_mmc_data[1];
+#endif
+
+
+/* Platform devices for the Herald */
 static struct platform_device *devices[] __initdata = {
 	&kp_device,
 	&lcd_device,
+	&htcpld_device,
+	&gpio_leds_device,
+	&herald_gpiokeys_device,
+};
+
+/*
+ * Touchscreen
+ */
+static const struct ads7846_platform_data htcherald_ts_platform_data = {
+	.model			= 7846,
+	.keep_vref_on		= 1,
+	.x_plate_ohms		= 496,
+	.gpio_pendown		= HTCHERALD_GPIO_TS,
+	.pressure_max		= 100000,
+	.pressure_min		= 5000,
+	.x_min			= 528,
+	.x_max			= 3760,
+	.y_min			= 624,
+	.y_max			= 3760,
+};
+
+static struct spi_board_info __initdata htcherald_spi_board_info[] = {
+	{
+		.modalias		= "ads7846",
+		.platform_data		= &htcherald_ts_platform_data,
+		.irq			= OMAP_GPIO_IRQ(HTCHERALD_GPIO_TS),
+		.max_speed_hz		= 2500000,
+		.bus_num		= 2,
+		.chip_select		= 1,
+	}
 };
 
 /*
@@ -278,6 +576,7 @@
 {
 	printk(KERN_INFO "HTC Herald init.\n");
 
+	/* Do board initialization before we register all the devices */
 	omap_gpio_init();
 
 	omap_board_config = htcherald_config;
@@ -288,6 +587,16 @@
 
 	htcherald_usb_enable();
 	omap1_usb_init(&htcherald_usb_config);
+
+	spi_register_board_info(htcherald_spi_board_info,
+		ARRAY_SIZE(htcherald_spi_board_info));
+
+	omap_register_i2c_bus(1, 100, NULL, 0);
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+	htc_mmc_data[0] = &htc_mmc1_data;
+	omap1_init_mmc(htc_mmc_data, 1);
+#endif
 }
 
 static void __init htcherald_init_irq(void)
@@ -300,8 +609,6 @@
 MACHINE_START(HERALD, "HTC Herald")
 	/* Maintainer: Cory Maccarrone <darkstar6262@gmail.com> */
 	/* Maintainer: wing-linux.sourceforge.net */
-	.phys_io        = 0xfff00000,
-	.io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params    = 0x10000100,
 	.map_io         = htcherald_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-innovator.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-innovator.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-innovator.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-innovator.c	2011-01-04 19:50:19.000000000 -0500
@@ -459,8 +459,6 @@
 
 MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
 	/* Maintainer: MontaVista Software, Inc. */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= innovator_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-nokia770.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-nokia770.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-nokia770.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-nokia770.c	2011-01-04 19:50:19.000000000 -0500
@@ -262,8 +262,6 @@
 }
 
 MACHINE_START(NOKIA770, "Nokia 770")
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_nokia770_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-osk.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-osk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-osk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-osk.c	2011-01-04 19:50:19.000000000 -0500
@@ -580,8 +580,6 @@
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
 	/* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= osk_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmte.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmte.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmte.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmte.c	2011-01-04 19:50:19.000000000 -0500
@@ -285,8 +285,6 @@
 }
 
 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_palmte_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmtt.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmtt.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmtt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmtt.c	2011-01-04 19:50:19.000000000 -0500
@@ -317,8 +317,6 @@
 }
 
 MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_palmtt_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmz71.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmz71.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-palmz71.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-palmz71.c	2011-01-04 19:50:19.000000000 -0500
@@ -338,8 +338,6 @@
 }
 
 MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_palmz71_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-perseus2.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-perseus2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-perseus2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-perseus2.c	2011-01-04 19:50:19.000000000 -0500
@@ -347,8 +347,6 @@
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
 	/* Maintainer: Kevin Hilman <kjh@hilman.org> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_perseus2_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-sx1.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-sx1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-sx1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-sx1.c	2011-01-04 19:50:19.000000000 -0500
@@ -419,8 +419,6 @@
 }
 
 MACHINE_START(SX1, "OMAP310 based Siemens SX1")
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= omap_sx1_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-sx1-mmc.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-sx1-mmc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-sx1-mmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-sx1-mmc.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,8 +44,7 @@
 	.nr_slots                       = 1,
 	.slots[0]       = {
 		.set_power              = mmc_set_power,
-		.ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
-					  MMC_VDD_32_33 | MMC_VDD_33_34,
+		.ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
 		.name                   = "mmcblk",
 	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-voiceblue.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-voiceblue.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/board-voiceblue.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/board-voiceblue.c	2011-01-04 19:50:19.000000000 -0500
@@ -283,8 +283,6 @@
 
 MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
 	/* Maintainer: Ladislav Michl <michl@2n.cz> */
-	.phys_io	= 0xfff00000,
-	.io_pg_offst	= ((0xfef00000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.map_io		= voiceblue_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -25,6 +26,7 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -191,10 +193,76 @@
 }
 #endif
 
+
+#define OMAP1_CAMERA_BASE	0xfffb6800
+#define OMAP1_CAMERA_IOSIZE	0x1c
+
+static struct resource omap1_camera_resources[] = {
+	[0] = {
+		.start	= OMAP1_CAMERA_BASE,
+		.end	= OMAP1_CAMERA_BASE + OMAP1_CAMERA_IOSIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= INT_CAMERA,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 omap1_camera_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device omap1_camera_device = {
+	.name		= "omap1-camera",
+	.id		= 0, /* This is used to put cameras on this interface */
+	.dev		= {
+		.dma_mask		= &omap1_camera_dma_mask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(omap1_camera_resources),
+	.resource	= omap1_camera_resources,
+};
+
+void __init omap1_camera_init(void *info)
+{
+	struct platform_device *dev = &omap1_camera_device;
+	int ret;
+
+	dev->dev.platform_data = info;
+
+	ret = platform_device_register(dev);
+	if (ret)
+		dev_err(&dev->dev, "unable to register device: %d\n", ret);
+}
+
+
 /*-------------------------------------------------------------------------*/
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+	.name	= "omap-pcm-audio",
+	.id	= -1,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+	platform_device_register(&omap_mcbsp1);
+	platform_device_register(&omap_mcbsp2);
+	if (!cpu_is_omap7xx())
+		platform_device_register(&omap_mcbsp3);
+	platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -227,8 +295,35 @@
 	omap_init_rtc();
 	omap_init_spi100k();
 	omap_init_sti();
+	omap_init_audio();
 
 	return 0;
 }
 arch_initcall(omap1_init_devices);
 
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= 0xfffeb000,
+		.end		= 0xfffeb07F,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_wdt_device = {
+	.name	   = "omap_wdt",
+	.id	     = -1,
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static int __init omap_init_wdt(void)
+{
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
+	return platform_device_register(&omap_wdt_device);
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/camera.h linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/camera.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/camera.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/camera.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,13 @@
+#ifndef __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+#include <media/omap1_camera.h>
+
+void omap1_camera_init(void *);
+
+static inline void omap1_set_camera_info(struct omap1_cam_platform_data *info)
+{
+	omap1_camera_init(info);
+}
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -28,56 +28,58 @@
 		 * the desired UART phys and virt addresses temporarily into
 		 * the omap_uart_phys and omap_uart_virt above.
 		 */
-		.macro	addruart, rx, tmp
+		.macro	addruart, rp, rv
 
 		/* Use omap_uart_phys/virt if already configured */
-9:		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =__virt_to_phys(omap_uart_phys)	@ physical base address
-		ldrne	\rx, =omap_uart_virt	@ virtual base
-		ldr	\rx, [\rx, #0]
-		cmp	\rx, #0			@ is port configured?
+9:		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		ldreq	\rp, =__virt_to_phys(omap_uart_phys)	@ MMU not enabled
+		ldrne	\rp, =omap_uart_phys	@ MMU enabled
+		add	\rv, \rp, #4		@ omap_uart_virt
+		ldr	\rp, [\rp, #0]
+		ldr	\rv, [\rv, #0]
+		cmp	\rp, #0			@ is port configured?
+		cmpne	\rv, #0
 		bne	99f			@ already configured
 
 		/* Check the debug UART configuration set in uncompress.h */
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =OMAP_UART_INFO
-		ldrne	\rx, =__phys_to_virt(OMAP_UART_INFO)
-		ldr	\rx, [\rx, #0]
+		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		ldreq	\rp, =OMAP_UART_INFO	@ MMU not enabled
+		ldrne	\rp, =__phys_to_virt(OMAP_UART_INFO)	@ MMU enabled
+		ldr	\rp, [\rp, #0]
 
 		/* Select the UART to use based on the UART1 scratchpad value */
-10:		cmp	\rx, #0			@ no port configured?
+10:		cmp	\rp, #0			@ no port configured?
 		beq	11f			@ if none, try to use UART1
-		cmp	\rx, #OMAP1UART1
+		cmp	\rp, #OMAP1UART1
 		beq	11f			@ configure OMAP1UART1
-		cmp	\rx, #OMAP1UART2
+		cmp	\rp, #OMAP1UART2
 		beq	12f			@ configure OMAP1UART2
-		cmp	\rx, #OMAP1UART3
+		cmp	\rp, #OMAP1UART3
 		beq	13f			@ configure OMAP2UART3
 
 		/* Configure the UART offset from the phys/virt base */
-11:		mov	\rx, #0x00fb0000	@ OMAP1UART1
+11:		mov	\rp, #0x00fb0000	@ OMAP1UART1
 		b	98f
-12:		mov	\rx, #0x00fb0000	@ OMAP1UART1
-		orr	\rx, \rx, #0x00000800	@ OMAP1UART2
+12:		mov	\rp, #0x00fb0000	@ OMAP1UART1
+		orr	\rp, \rp, #0x00000800	@ OMAP1UART2
 		b	98f
-13:		mov	\rx, #0x00fb0000	@ OMAP1UART1
-		orr	\rx, \rx, #0x00000800	@ OMAP1UART2
-		orr	\rx, \rx, #0x00009000	@ OMAP1UART3
+13:		mov	\rp, #0x00fb0000	@ OMAP1UART1
+		orr	\rp, \rp, #0x00000800	@ OMAP1UART2
+		orr	\rp, \rp, #0x00009000	@ OMAP1UART3
 
 		/* Store both phys and virt address for the uart */
-98:		add	\rx, \rx, #0xff000000	@ phys base
-		mrc	p15, 0, \tmp, c1, c0
-		tst	\tmp, #1		@ MMU enabled?
-		ldreq	\tmp, =__virt_to_phys(omap_uart_phys)
-		ldrne	\tmp, =omap_uart_phys
-		str	\rx, [\tmp, #0]
-		sub	\rx, \rx, #0xff000000	@ phys base
-		add	\rx, \rx, #0xfe000000	@ virt base
-		ldreq	\tmp, =__virt_to_phys(omap_uart_virt)
-		ldrne	\tmp, =omap_uart_virt
-		str	\rx, [\tmp, #0]
+98:		add	\rp, \rp, #0xff000000	@ phys base
+		mrc	p15, 0, \rv, c1, c0
+		tst	\rv, #1			@ MMU enabled?
+		ldreq	\rv, =__virt_to_phys(omap_uart_phys)	@ MMU not enabled
+		ldrne	\rv, =omap_uart_phys	@ MMU enabled
+		str	\rp, [\rv, #0]
+		sub	\rp, \rp, #0xff000000	@ phys base
+		add	\rp, \rp, #0xfe000000	@ virt base
+		add	\rv, \rv, #4		@ omap_uart_lsr
+		str	\rp, [\rv, #0]
 		b	9b
 99:
 		.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END	(PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END	0xd8000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-omap1/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -128,7 +128,7 @@
 	help
 	  Support for the Palm Tungsten|T PDA. To boot the kernel, you'll
 	  need a PalmOS compatible bootloader (Garux); check out
-	  http://www.hackndev.com/palm/tt/ for more information.
+	  http://garux.sourceforge.net/ for more information.
 	  Say Y here if you have this PDA model, say N otherwise.
 
 config MACH_SX1
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-omap1/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
 obj-$(CONFIG_OMAP_32K_TIMER)	+= timer32k.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o
 
 # DSP
 obj-$(CONFIG_OMAP_MBOX_FWK)	+= mailbox_mach.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap1/pm_bus.c linux-libre-2.6.37-gnu/arch/arm/mach-omap1/pm_bus.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap1/pm_bus.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap1/pm_bus.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,98 @@
+/*
+ * Runtime PM support code for OMAP1
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+static int omap1_pm_runtime_suspend(struct device *dev)
+{
+	struct clk *iclk, *fclk;
+	int ret = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	ret = pm_generic_runtime_suspend(dev);
+
+	fclk = clk_get(dev, "fck");
+	if (!IS_ERR(fclk)) {
+		clk_disable(fclk);
+		clk_put(fclk);
+	}
+
+	iclk = clk_get(dev, "ick");
+	if (!IS_ERR(iclk)) {
+		clk_disable(iclk);
+		clk_put(iclk);
+	}
+
+	return 0;
+};
+
+static int omap1_pm_runtime_resume(struct device *dev)
+{
+	int ret = 0;
+	struct clk *iclk, *fclk;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	iclk = clk_get(dev, "ick");
+	if (!IS_ERR(iclk)) {
+		clk_enable(iclk);
+		clk_put(iclk);
+	}
+
+	fclk = clk_get(dev, "fck");
+	if (!IS_ERR(fclk)) {
+		clk_enable(fclk);
+		clk_put(fclk);
+	}
+
+	return pm_generic_runtime_resume(dev);
+};
+
+static int __init omap1_pm_runtime_init(void)
+{
+	const struct dev_pm_ops *pm;
+	struct dev_pm_ops *omap_pm;
+
+	pm = platform_bus_get_pm_ops();
+	if (!pm) {
+		pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+	if (!omap_pm) {
+		pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	omap_pm->runtime_suspend = omap1_pm_runtime_suspend;
+	omap_pm->runtime_resume = omap1_pm_runtime_resume;
+
+	platform_bus_set_pm_ops(omap_pm);
+
+	return 0;
+}
+core_initcall(omap1_pm_runtime_init);
+#endif /* CONFIG_PM_RUNTIME */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-2430sdp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-2430sdp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-2430sdp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-2430sdp.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/mmc/host.h>
 #include <linux/delay.h>
 #include <linux/i2c/twl.h>
 #include <linux/err.h>
@@ -190,7 +191,7 @@
 static struct omap2_hsmmc_info mmc[] __initdata = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.ext_clock	= 1,
@@ -253,8 +254,6 @@
 
 MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
 	/* Maintainer: Syed Khasim - Texas Instruments Inc */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_2430sdp_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-3430sdp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-3430sdp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-3430sdp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-3430sdp.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -38,15 +39,14 @@
 #include <plat/gpmc.h>
 #include <plat/display.h>
 
-#include <plat/control.h>
 #include <plat/gpmc-smc91x.h>
 
-#include <mach/board-flash.h>
-
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-qimonda-hyb18m512160af-6.h"
 #include "hsmmc.h"
 #include "pm.h"
+#include "control.h"
 
 #define CONFIG_DISABLE_HFCLK 1
 
@@ -76,7 +76,7 @@
 	{1, 10000, 30000, 300000},
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_LEFT),
 	KEY(0, 1, KEY_RIGHT),
 	KEY(0, 2, KEY_A),
@@ -353,12 +353,12 @@
 		/* 8 bits (default) requires S6.3 == ON,
 		 * so the SIM card isn't used; else 4 bits.
 		 */
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 4,
 	},
 	{
 		.mmc		= 2,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 7,
 	},
 	{}	/* Terminator */
@@ -817,8 +817,6 @@
 
 MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
 	/* Maintainer: Syed Khasim - Texas Instruments Inc */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-3630sdp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-3630sdp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-3630sdp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-3630sdp.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,8 @@
 #include <plat/usb.h>
 
 #include <mach/board-zoom.h>
-#include <mach/board-flash.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
 
@@ -208,7 +208,6 @@
 static void __init omap_sdp_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
-	omap_serial_init();
 	zoom_peripherals_init();
 	board_smc91x_init();
 	board_flash_init(sdp_flash_partitions, chip_sel_sdp);
@@ -217,8 +216,6 @@
 }
 
 MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-4430sdp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-4430sdp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-4430sdp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-4430sdp.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 #include <linux/usb/otg.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c/twl.h>
+#include <linux/gpio_keys.h>
 #include <linux/regulator/machine.h>
 #include <linux/leds.h>
 
@@ -31,15 +32,18 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+
 #include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
 
 #define ETH_KS8851_IRQ			34
 #define ETH_KS8851_POWER_ON		48
 #define ETH_KS8851_QUART		138
+#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO	184
+#define OMAP4_SFH7741_ENABLE_GPIO		188
 
 static struct gpio_led sdp4430_gpio_leds[] = {
 	{
@@ -77,11 +81,47 @@
 
 };
 
+static struct gpio_keys_button sdp4430_gpio_keys[] = {
+	{
+		.desc			= "Proximity Sensor",
+		.type			= EV_SW,
+		.code			= SW_FRONT_PROXIMITY,
+		.gpio			= OMAP4_SFH7741_SENSOR_OUTPUT_GPIO,
+		.active_low		= 0,
+	}
+};
+
 static struct gpio_led_platform_data sdp4430_led_data = {
 	.leds	= sdp4430_gpio_leds,
 	.num_leds	= ARRAY_SIZE(sdp4430_gpio_leds),
 };
 
+static int omap_prox_activate(struct device *dev)
+{
+	gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1);
+	return 0;
+}
+
+static void omap_prox_deactivate(struct device *dev)
+{
+	gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0);
+}
+
+static struct gpio_keys_platform_data sdp4430_gpio_keys_data = {
+	.buttons	= sdp4430_gpio_keys,
+	.nbuttons	= ARRAY_SIZE(sdp4430_gpio_keys),
+	.enable		= omap_prox_activate,
+	.disable	= omap_prox_deactivate,
+};
+
+static struct platform_device sdp4430_gpio_keys_device = {
+	.name	= "gpio-keys",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &sdp4430_gpio_keys_data,
+	},
+};
+
 static struct platform_device sdp4430_leds_gpio = {
 	.name	= "leds-gpio",
 	.id	= -1,
@@ -161,6 +201,7 @@
 
 static struct platform_device *sdp4430_devices[] __initdata = {
 	&sdp4430_lcd_device,
+	&sdp4430_gpio_keys_device,
 	&sdp4430_leds_gpio,
 };
 
@@ -193,15 +234,16 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= -EINVAL,
 	},
 	{
 		.mmc		= 2,
-		.wires		= 8,
+		.caps		=  MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.nonremovable   = true,
+		.ocr_mask	= MMC_VDD_29_30,
 	},
 	{}	/* Terminator */
 };
@@ -227,16 +269,27 @@
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 
 	/* Setting MMC1 Card detect Irq */
-	if (pdev->id == 0)
+	if (pdev->id == 0) {
+		ret = twl6030_mmc_card_detect_config();
+		if (ret)
+			pr_err("Failed configuring MMC1 card detect\n");
 		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
 						MMCDETECT_INTR_OFFSET;
+		pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+	}
 	return ret;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 {
-	struct omap_mmc_platform_data *pdata = dev->platform_data;
+	struct omap_mmc_platform_data *pdata;
 
+	/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+	if (!dev) {
+		pr_err("Failed %s\n", __func__);
+		return;
+	}
+	pdata = dev->platform_data;
 	pdata->init =	omap4_twl6030_hsmmc_late_init;
 }
 
@@ -412,6 +465,11 @@
 		I2C_BOARD_INFO("tmp105", 0x48),
 	},
 };
+static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("hmc5843", 0x1e),
+	},
+};
 static int __init omap4_i2c_init(void)
 {
 	/*
@@ -423,14 +481,36 @@
 	omap_register_i2c_bus(2, 400, NULL, 0);
 	omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
 				ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
-	omap_register_i2c_bus(4, 400, NULL, 0);
+	omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo,
+				ARRAY_SIZE(sdp4430_i2c_4_boardinfo));
 	return 0;
 }
+
+static void __init omap_sfh7741prox_init(void)
+{
+	int  error;
+
+	error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741");
+	if (error < 0) {
+		pr_err("%s:failed to request GPIO %d, error %d\n",
+			__func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+		return;
+	}
+
+	error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0);
+	if (error < 0) {
+		pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",
+			 __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
+		gpio_free(OMAP4_SFH7741_ENABLE_GPIO);
+	}
+}
+
 static void __init omap_4430sdp_init(void)
 {
 	int status;
 
 	omap4_i2c_init();
+	omap_sfh7741prox_init();
 	platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices));
 	omap_serial_init();
 	omap4_twl6030_hsmmc_init(mmc);
@@ -458,8 +538,6 @@
 
 MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
 	/* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_4430sdp_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-am3517evm.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-am3517evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-am3517evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-am3517evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/i2c/pca953x.h>
@@ -32,25 +33,43 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/usb.h>
 #include <plat/display.h>
 
 #include "mux.h"
+#include "control.h"
 
-#define AM35XX_EVM_PHY_MASK		(0xF)
 #define AM35XX_EVM_MDIO_FREQUENCY	(1000000)
 
+static struct mdio_platform_data am3517_evm_mdio_pdata = {
+	.bus_freq	= AM35XX_EVM_MDIO_FREQUENCY,
+};
+
+static struct resource am3517_mdio_resources[] = {
+	{
+		.start  = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET,
+		.end    = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET +
+			  SZ_4K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device am3517_mdio_device = {
+	.name		= "davinci_mdio",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(am3517_mdio_resources),
+	.resource	= am3517_mdio_resources,
+	.dev.platform_data = &am3517_evm_mdio_pdata,
+};
+
 static struct emac_platform_data am3517_evm_emac_pdata = {
-	.phy_mask	= AM35XX_EVM_PHY_MASK,
-	.mdio_max_freq	= AM35XX_EVM_MDIO_FREQUENCY,
 	.rmii_en	= 1,
 };
 
 static struct resource am3517_emac_resources[] = {
 	{
 		.start  = AM35XX_IPSS_EMAC_BASE,
-		.end    = AM35XX_IPSS_EMAC_BASE + 0x3FFFF,
+		.end    = AM35XX_IPSS_EMAC_BASE + 0x2FFFF,
 		.flags  = IORESOURCE_MEM,
 	},
 	{
@@ -106,14 +125,13 @@
 	regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
 }
 
-void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
+static void am3517_evm_ethernet_init(struct emac_platform_data *pdata)
 {
 	unsigned int regval;
 
 	pdata->ctrl_reg_offset		= AM35XX_EMAC_CNTRL_OFFSET;
 	pdata->ctrl_mod_reg_offset	= AM35XX_EMAC_CNTRL_MOD_OFFSET;
 	pdata->ctrl_ram_offset		= AM35XX_EMAC_CNTRL_RAM_OFFSET;
-	pdata->mdio_reg_offset		= AM35XX_EMAC_MDIO_OFFSET;
 	pdata->ctrl_ram_size		= AM35XX_EMAC_CNTRL_RAM_SIZE;
 	pdata->version			= EMAC_VERSION_2;
 	pdata->hw_ram_addr		= AM35XX_EMAC_HW_RAM_ADDR;
@@ -121,6 +139,9 @@
 	pdata->interrupt_disable	= am3517_disable_ethernet_int;
 	am3517_emac_device.dev.platform_data	= pdata;
 	platform_device_register(&am3517_emac_device);
+	platform_device_register(&am3517_mdio_device);
+	clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev),
+		      NULL, &am3517_emac_device.dev);
 
 	regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
 	regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
@@ -139,7 +160,6 @@
 static struct i2c_board_info __initdata am3517evm_i2c1_boardinfo[] = {
 	{
 		I2C_BOARD_INFO("s35390a", 0x30),
-		.type		= "s35390a",
 	},
 };
 
@@ -347,7 +367,7 @@
 	.default_device	= &am3517_evm_lcd_device,
 };
 
-struct platform_device am3517_evm_dss_device = {
+static struct platform_device am3517_evm_dss_device = {
 	.name		= "omapdss",
 	.id		= -1,
 	.dev		= {
@@ -375,6 +395,31 @@
 	omap_gpio_init();
 }
 
+static struct omap_musb_board_data musb_board_data = {
+	.interface_type         = MUSB_INTERFACE_ULPI,
+	.mode                   = MUSB_OTG,
+	.power                  = 500,
+};
+
+static __init void am3517_evm_musb_init(void)
+{
+	u32 devconf2;
+
+	/*
+	 * Set up USB clock/mode in the DEVCONF2 register.
+	 */
+	devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
+
+	/* USB2.0 PHY reference clock is 13 MHz */
+	devconf2 &= ~(CONF2_REFFREQ | CONF2_OTGMODE | CONF2_PHY_GPIOMODE);
+	devconf2 |=  CONF2_REFFREQ_13MHZ | CONF2_SESENDEN | CONF2_VBDTCTEN
+			| CONF2_DATPOL;
+
+	omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
+
+	usb_musb_init(&musb_board_data);
+}
+
 static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
 	.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
 #if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
@@ -393,6 +438,8 @@
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* USB OTG DRVVBUS offset = 0x212 */
+	OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -459,11 +506,12 @@
 				ARRAY_SIZE(am3517evm_i2c1_boardinfo));
 	/*Ethernet*/
 	am3517_evm_ethernet_init(&am3517_evm_emac_pdata);
+
+	/* MUSB */
+	am3517_evm_musb_init();
 }
 
 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-apollon.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-apollon.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-apollon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-apollon.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,9 +39,9 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/gpmc.h>
-#include <plat/control.h>
 
 #include "mux.h"
+#include "control.h"
 
 /* LED & Switch macros */
 #define LED0_GPIO13		13
@@ -356,8 +356,6 @@
 
 MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
 	/* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_apollon_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-cm-t3517.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-cm-t3517.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-cm-t3517.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-cm-t3517.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,292 @@
+/*
+ * linux/arch/arm/mach-omap2/board-cm-t3517.c
+ *
+ * Support for the CompuLab CM-T3517 modules
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Author: Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/rtc-v3020.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/can/platform/ti_hecc.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/usb.h>
+#include <plat/nand.h>
+#include <plat/gpmc.h>
+
+#include <mach/am35xx.h>
+
+#include "mux.h"
+#include "control.h"
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static struct gpio_led cm_t3517_leds[] = {
+	[0] = {
+		.gpio			= 186,
+		.name			= "cm-t3517:green",
+		.default_trigger	= "heartbeat",
+		.active_low		= 0,
+	},
+};
+
+static struct gpio_led_platform_data cm_t3517_led_pdata = {
+	.num_leds	= ARRAY_SIZE(cm_t3517_leds),
+	.leds		= cm_t3517_leds,
+};
+
+static struct platform_device cm_t3517_led_device = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &cm_t3517_led_pdata,
+	},
+};
+
+static void __init cm_t3517_init_leds(void)
+{
+	platform_device_register(&cm_t3517_led_device);
+}
+#else
+static inline void cm_t3517_init_leds(void) {}
+#endif
+
+#if defined(CONFIG_CAN_TI_HECC) || defined(CONFIG_CAN_TI_HECC_MODULE)
+static struct resource cm_t3517_hecc_resources[] = {
+	{
+		.start	= AM35XX_IPSS_HECC_BASE,
+		.end	= AM35XX_IPSS_HECC_BASE + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_35XX_HECC0_IRQ,
+		.end	= INT_35XX_HECC0_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct ti_hecc_platform_data cm_t3517_hecc_pdata = {
+	.scc_hecc_offset	= AM35XX_HECC_SCC_HECC_OFFSET,
+	.scc_ram_offset		= AM35XX_HECC_SCC_RAM_OFFSET,
+	.hecc_ram_offset	= AM35XX_HECC_RAM_OFFSET,
+	.mbx_offset		= AM35XX_HECC_MBOX_OFFSET,
+	.int_line		= AM35XX_HECC_INT_LINE,
+	.version		= AM35XX_HECC_VERSION,
+};
+
+static struct platform_device cm_t3517_hecc_device = {
+	.name		= "ti_hecc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(cm_t3517_hecc_resources),
+	.resource	= cm_t3517_hecc_resources,
+	.dev		= {
+		.platform_data	= &cm_t3517_hecc_pdata,
+	},
+};
+
+static void cm_t3517_init_hecc(void)
+{
+	platform_device_register(&cm_t3517_hecc_device);
+}
+#else
+static inline void cm_t3517_init_hecc(void) {}
+#endif
+
+#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
+#define RTC_IO_GPIO		(153)
+#define RTC_WR_GPIO		(154)
+#define RTC_RD_GPIO		(160)
+#define RTC_CS_GPIO		(163)
+
+struct v3020_platform_data cm_t3517_v3020_pdata = {
+	.use_gpio	= 1,
+	.gpio_cs	= RTC_CS_GPIO,
+	.gpio_wr	= RTC_WR_GPIO,
+	.gpio_rd	= RTC_RD_GPIO,
+	.gpio_io	= RTC_IO_GPIO,
+};
+
+static struct platform_device cm_t3517_rtc_device = {
+	.name		= "v3020",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &cm_t3517_v3020_pdata,
+	}
+};
+
+static void __init cm_t3517_init_rtc(void)
+{
+	platform_device_register(&cm_t3517_rtc_device);
+}
+#else
+static inline void cm_t3517_init_rtc(void) {}
+#endif
+
+#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+#define HSUSB1_RESET_GPIO	(146)
+#define HSUSB2_RESET_GPIO	(147)
+#define USB_HUB_RESET_GPIO	(152)
+
+static struct ehci_hcd_omap_platform_data cm_t3517_ehci_pdata __initdata = {
+	.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+	.port_mode[1] = EHCI_HCD_OMAP_MODE_PHY,
+	.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+
+	.phy_reset  = true,
+	.reset_gpio_port[0]  = HSUSB1_RESET_GPIO,
+	.reset_gpio_port[1]  = HSUSB2_RESET_GPIO,
+	.reset_gpio_port[2]  = -EINVAL,
+};
+
+static int cm_t3517_init_usbh(void)
+{
+	int err;
+
+	err = gpio_request(USB_HUB_RESET_GPIO, "usb hub rst");
+	if (err) {
+		pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
+	} else {
+		gpio_direction_output(USB_HUB_RESET_GPIO, 0);
+		udelay(10);
+		gpio_set_value(USB_HUB_RESET_GPIO, 1);
+		msleep(1);
+	}
+
+	usb_ehci_init(&cm_t3517_ehci_pdata);
+
+	return 0;
+}
+#else
+static inline int cm_t3517_init_usbh(void)
+{
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+#define NAND_BLOCK_SIZE		SZ_128K
+
+static struct mtd_partition cm_t3517_nand_partitions[] = {
+	{
+		.name           = "xloader",
+		.offset         = 0,			/* Offset = 0x00000 */
+		.size           = 4 * NAND_BLOCK_SIZE,
+		.mask_flags     = MTD_WRITEABLE
+	},
+	{
+		.name           = "uboot",
+		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x80000 */
+		.size           = 15 * NAND_BLOCK_SIZE,
+	},
+	{
+		.name           = "uboot environment",
+		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x260000 */
+		.size           = 2 * NAND_BLOCK_SIZE,
+	},
+	{
+		.name           = "linux",
+		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x280000 */
+		.size           = 32 * NAND_BLOCK_SIZE,
+	},
+	{
+		.name           = "rootfs",
+		.offset         = MTDPART_OFS_APPEND,	/* Offset = 0x680000 */
+		.size           = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct omap_nand_platform_data cm_t3517_nand_data = {
+	.parts			= cm_t3517_nand_partitions,
+	.nr_parts		= ARRAY_SIZE(cm_t3517_nand_partitions),
+	.dma_channel		= -1,	/* disable DMA in OMAP NAND driver */
+	.cs			= 0,
+};
+
+static void __init cm_t3517_init_nand(void)
+{
+	if (gpmc_nand_init(&cm_t3517_nand_data) < 0)
+		pr_err("CM-T3517: NAND initialization failed\n");
+}
+#else
+static inline void cm_t3517_init_nand(void) {}
+#endif
+
+static struct omap_board_config_kernel cm_t3517_config[] __initdata = {
+};
+
+static void __init cm_t3517_init_irq(void)
+{
+	omap_board_config = cm_t3517_config;
+	omap_board_config_size = ARRAY_SIZE(cm_t3517_config);
+
+	omap2_init_common_hw(NULL, NULL);
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static struct omap_board_mux board_mux[] __initdata = {
+	/* GPIO186 - Green LED */
+	OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+	/* RTC GPIOs: IO, WR#, RD#, CS# */
+	OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+	OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+	OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+	OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
+	/* HSUSB1 RESET */
+	OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+	/* HSUSB2 RESET */
+	OMAP3_MUX(UART2_RX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+	/* CM-T3517 USB HUB nRESET */
+	OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+
+	{ .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static void __init cm_t3517_init(void)
+{
+	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+	omap_serial_init();
+	cm_t3517_init_leds();
+	cm_t3517_init_nand();
+	cm_t3517_init_rtc();
+	cm_t3517_init_usbh();
+	cm_t3517_init_hecc();
+}
+
+MACHINE_START(CM_T3517, "Compulab CM-T3517")
+	.boot_params	= 0x80000100,
+	.map_io		= omap3_map_io,
+	.reserve        = omap_reserve,
+	.init_irq	= cm_t3517_init_irq,
+	.init_machine	= cm_t3517_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-cm-t35.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-cm-t35.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-cm-t35.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-cm-t35.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 #include <linux/i2c/at24.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/tdo24m.h>
@@ -237,8 +238,6 @@
 	defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
 #include <linux/spi/ads7846.h>
 
-#include <plat/mcspi.h>
-
 static struct omap2_mcspi_device_config ads7846_mcspi_config = {
 	.turbo_mode	= 0,
 	.single_channel	= 1,	/* 0: slave, 1: master */
@@ -558,7 +557,7 @@
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
-static int cm_t35_keymap[] = {
+static uint32_t cm_t35_keymap[] = {
 	KEY(0, 0, KEY_A),	KEY(0, 1, KEY_B),	KEY(0, 2, KEY_LEFT),
 	KEY(1, 0, KEY_UP),	KEY(1, 1, KEY_ENTER),	KEY(1, 2, KEY_DOWN),
 	KEY(2, 0, KEY_RIGHT),	KEY(2, 1, KEY_C),	KEY(2, 2, KEY_D),
@@ -579,14 +578,14 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 
 	},
 	{
 		.mmc		= 2,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.transceiver	= 1,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
@@ -809,8 +808,6 @@
 }
 
 MACHINE_START(CM_T35, "Compulab CM-T35")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-devkit8000.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-devkit8000.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-devkit8000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-devkit8000.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
@@ -44,7 +45,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 #include <plat/display.h>
 
 #include <plat/mcspi.h>
@@ -58,6 +58,7 @@
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #define NAND_BLOCK_SIZE		SZ_128K
 
@@ -105,7 +106,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 29,
 	},
 	{}	/* Terminator */
@@ -198,7 +199,7 @@
 static struct regulator_consumer_supply devkit8000_vdda_dac_supply =
 	REGULATOR_SUPPLY("vdda_dac", "omapdss");
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_1),
 	KEY(1, 0, KEY_2),
 	KEY(2, 0, KEY_3),
@@ -241,9 +242,6 @@
 	mmc[0].gpio_cd = gpio + 0;
 	omap2_hsmmc_init(mmc);
 
-	/* link regulators to MMC adapters */
-	devkit8000_vmmc1_supply.dev = mmc[0].dev;
-
 	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
 	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
 
@@ -800,8 +798,6 @@
 }
 
 MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-flash.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-flash.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-flash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-flash.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,8 @@
 #include <plat/nand.h>
 #include <plat/onenand.h>
 #include <plat/tc.h>
-#include <mach/board-flash.h>
+
+#include "board-flash.h"
 
 #define REG_FPGA_REV			0x10
 #define REG_FPGA_DIP_SWITCH_INPUT2	0x60
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-flash.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-flash.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-flash.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-flash.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,30 @@
+/*
+ *  board-sdp.h
+ *
+ *  Information structures for SDP-specific board config data
+ *
+ *  Copyright (C) 2009 Nokia Corporation
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <plat/gpmc.h>
+
+#define PDC_NOR		1
+#define PDC_NAND	2
+#define PDC_ONENAND	3
+#define DBG_MPDB	4
+
+struct flash_partitions {
+	struct mtd_partition *parts;
+	int nr_parts;
+};
+
+extern void board_flash_init(struct flash_partitions [],
+				char chip_sel[][GPMC_CS_NUM]);
+extern void board_nand_init(struct mtd_partition *nand_parts,
+					u8 nr_parts, u8 cs);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-generic.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-generic.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,14 +48,24 @@
 
 static void __init omap_generic_map_io(void)
 {
-	omap2_set_globals_242x(); /* should be 242x, 243x, or 343x */
-	omap242x_map_common_io();
+	if (cpu_is_omap242x()) {
+		omap2_set_globals_242x();
+		omap242x_map_common_io();
+	} else if (cpu_is_omap243x()) {
+		omap2_set_globals_243x();
+		omap243x_map_common_io();
+	} else if (cpu_is_omap34xx()) {
+		omap2_set_globals_3xxx();
+		omap34xx_map_common_io();
+	} else if (cpu_is_omap44xx()) {
+		omap2_set_globals_443x();
+		omap44xx_map_common_io();
+	}
 }
 
+/* XXX This machine entry name should be updated */
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
 	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_generic_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-h4.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-h4.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-h4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-h4.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,7 +31,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <plat/control.h>
 #include <mach/gpio.h>
 #include <plat/usb.h>
 #include <plat/board.h>
@@ -42,6 +41,7 @@
 #include <plat/gpmc.h>
 
 #include "mux.h"
+#include "control.h"
 
 #define H4_FLASH_CS	0
 #define H4_SMC91X_CS	1
@@ -376,8 +376,6 @@
 
 MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
 	/* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_h4_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-igep0020.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-igep0020.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-igep0020.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-igep0020.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -38,12 +39,61 @@
 #define IGEP2_SMSC911X_CS       5
 #define IGEP2_SMSC911X_GPIO     176
 #define IGEP2_GPIO_USBH_NRESET  24
-#define IGEP2_GPIO_LED0_GREEN 	26
-#define IGEP2_GPIO_LED0_RED 	27
-#define IGEP2_GPIO_LED1_RED   	28
-#define IGEP2_GPIO_DVI_PUP	170
-#define IGEP2_GPIO_WIFI_NPD 	94
-#define IGEP2_GPIO_WIFI_NRESET 	95
+#define IGEP2_GPIO_LED0_GREEN   26
+#define IGEP2_GPIO_LED0_RED     27
+#define IGEP2_GPIO_LED1_RED     28
+#define IGEP2_GPIO_DVI_PUP      170
+
+#define IGEP2_RB_GPIO_WIFI_NPD     94
+#define IGEP2_RB_GPIO_WIFI_NRESET  95
+#define IGEP2_RB_GPIO_BT_NRESET    137
+#define IGEP2_RC_GPIO_WIFI_NPD     138
+#define IGEP2_RC_GPIO_WIFI_NRESET  139
+#define IGEP2_RC_GPIO_BT_NRESET    137
+
+/*
+ * IGEP2 Hardware Revision Table
+ *
+ *  --------------------------------------------------------------------------
+ * | Id. | Hw Rev.            | HW0 (28) | WIFI_NPD | WIFI_NRESET | BT_NRESET |
+ *  --------------------------------------------------------------------------
+ * |  0  | B                  |   high   |  gpio94  |   gpio95    |     -     |
+ * |  0  | B/C (B-compatible) |   high   |  gpio94  |   gpio95    |  gpio137  |
+ * |  1  | C                  |   low    |  gpio138 |   gpio139   |  gpio137  |
+ *  --------------------------------------------------------------------------
+ */
+
+#define IGEP2_BOARD_HWREV_B	0
+#define IGEP2_BOARD_HWREV_C	1
+
+static u8 hwrev;
+
+static void __init igep2_get_revision(void)
+{
+	u8 ret;
+
+	omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT);
+
+	if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_HW0_REV") == 0) &&
+	    (gpio_direction_input(IGEP2_GPIO_LED1_RED) == 0)) {
+		ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
+		if (ret == 0) {
+			pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
+			hwrev = IGEP2_BOARD_HWREV_C;
+		} else if (ret ==  1) {
+			pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
+			hwrev = IGEP2_BOARD_HWREV_B;
+		} else {
+			pr_err("IGEP2: Unknown Hardware Revision\n");
+			hwrev = -1;
+		}
+	} else {
+		pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n");
+		pr_err("IGEP2: Unknown Hardware Revision\n");
+	}
+
+	gpio_free(IGEP2_GPIO_LED1_RED);
+}
 
 #if defined(CONFIG_MTD_ONENAND_OMAP2) || \
 	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
@@ -107,7 +157,7 @@
 	},
 };
 
-void __init igep2_flash_init(void)
+static void __init igep2_flash_init(void)
 {
 	u8		cs = 0;
 	u8		onenandcs = GPMC_CS_NUM + 1;
@@ -141,7 +191,7 @@
 }
 
 #else
-void __init igep2_flash_init(void) {}
+static void __init igep2_flash_init(void) {}
 #endif
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
@@ -211,10 +261,6 @@
 	.supply		= "vmmc",
 };
 
-static struct regulator_consumer_supply igep2_vmmc2_supply = {
-	.supply		= "vmmc",
-};
-
 /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
 static struct regulator_init_data igep2_vmmc1 = {
 	.constraints = {
@@ -230,37 +276,95 @@
 	.consumer_supplies      = &igep2_vmmc1_supply,
 };
 
-/* VMMC2 for OMAP VDD_MMC2 (i/o) and MMC2 WIFI */
-static struct regulator_init_data igep2_vmmc2 = {
-	.constraints = {
-		.min_uV			= 1850000,
-		.max_uV			= 3150000,
-		.valid_modes_mask	= REGULATOR_MODE_NORMAL
-					| REGULATOR_MODE_STANDBY,
-		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
-					| REGULATOR_CHANGE_MODE
-					| REGULATOR_CHANGE_STATUS,
-	},
-	.num_consumer_supplies  = 1,
-	.consumer_supplies      = &igep2_vmmc2_supply,
-};
-
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 	},
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
 	{
 		.mmc		= 2,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 	},
+#endif
 	{}      /* Terminator */
 };
 
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep2_gpio_leds[] = {
+	[0] = {
+		.name			= "gpio-led:red:d0",
+		.gpio			= IGEP2_GPIO_LED0_RED,
+		.default_trigger	= "default-off"
+	},
+	[1] = {
+		.name			= "gpio-led:green:d0",
+		.gpio			= IGEP2_GPIO_LED0_GREEN,
+		.default_trigger	= "default-off",
+	},
+	[2] = {
+		.name			= "gpio-led:red:d1",
+		.gpio			= IGEP2_GPIO_LED1_RED,
+		.default_trigger	= "default-off",
+	},
+	[3] = {
+		.name			= "gpio-led:green:d1",
+		.default_trigger	= "heartbeat",
+		.gpio			= -EINVAL, /* gets replaced */
+	},
+};
+
+static struct gpio_led_platform_data igep2_led_pdata = {
+	.leds           = igep2_gpio_leds,
+	.num_leds       = ARRAY_SIZE(igep2_gpio_leds),
+};
+
+static struct platform_device igep2_led_device = {
+	 .name   = "leds-gpio",
+	 .id     = -1,
+	 .dev    = {
+		 .platform_data  =  &igep2_led_pdata,
+	},
+};
+
+static void __init igep2_leds_init(void)
+{
+	platform_device_register(&igep2_led_device);
+}
+
+#else
+static inline void igep2_leds_init(void)
+{
+	if ((gpio_request(IGEP2_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+	    (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
+		gpio_export(IGEP2_GPIO_LED0_RED, 0);
+		gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
+	} else
+		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+
+	if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+	    (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
+		gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
+		gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
+	} else
+		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+	if ((gpio_request(IGEP2_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+	    (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
+		gpio_export(IGEP2_GPIO_LED1_RED, 0);
+		gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
+	} else
+		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+
+}
+#endif
+
 static int igep2_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
@@ -268,20 +372,48 @@
 	mmc[0].gpio_cd = gpio + 0;
 	omap2_hsmmc_init(mmc);
 
-	/* link regulators to MMC adapters ... we "know" the
+	/*
+	 * link regulators to MMC adapters ... we "know" the
 	 * regulators will be set up only *after* we return.
-	*/
+	 */
 	igep2_vmmc1_supply.dev = mmc[0].dev;
-	igep2_vmmc2_supply.dev = mmc[1].dev;
+
+	/*
+	 * REVISIT: need ehci-omap hooks for external VBUS
+	 * power switch and overcurrent detect
+	 */
+	if ((gpio_request(gpio + 1, "GPIO_EHCI_NOC") < 0) ||
+	    (gpio_direction_input(gpio + 1) < 0))
+		pr_err("IGEP2: Could not obtain gpio for EHCI NOC");
+
+	/*
+	 * TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN
+	 * (out, active low)
+	 */
+	if ((gpio_request(gpio + TWL4030_GPIO_MAX, "GPIO_USBH_CPEN") < 0) ||
+	    (gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0) < 0))
+		pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
+
+	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+	if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+	    && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+		gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+		gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+	} else
+		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+	igep2_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
 
 	return 0;
 };
 
-static struct twl4030_gpio_platform_data igep2_gpio_data = {
+static struct twl4030_gpio_platform_data igep2_twl4030_gpio_pdata = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
-	.use_leds	= false,
+	.use_leds	= true,
 	.setup		= igep2_twl_gpio_setup,
 };
 
@@ -355,47 +487,6 @@
 		pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
 }
 
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led igep2_gpio_leds[] = {
-	{
-		.name = "led0:red",
-		.gpio = IGEP2_GPIO_LED0_RED,
-	},
-	{
-		.name = "led0:green",
-		.default_trigger = "heartbeat",
-		.gpio = IGEP2_GPIO_LED0_GREEN,
-	},
-	{
-		.name = "led1:red",
-		.gpio = IGEP2_GPIO_LED1_RED,
-	},
-};
-
-static struct gpio_led_platform_data igep2_led_pdata = {
-	.leds           = igep2_gpio_leds,
-	.num_leds       = ARRAY_SIZE(igep2_gpio_leds),
-};
-
-static struct platform_device igep2_led_device = {
-	 .name   = "leds-gpio",
-	 .id     = -1,
-	 .dev    = {
-		 .platform_data  =  &igep2_led_pdata,
-	},
-};
-
-static void __init igep2_init_led(void)
-{
-	platform_device_register(&igep2_led_device);
-}
-
-#else
-static inline void igep2_init_led(void) {}
-#endif
-
 static struct platform_device *igep2_devices[] __initdata = {
 	&igep2_dss_device,
 };
@@ -425,14 +516,13 @@
 	/* platform_data for children goes here */
 	.usb		= &igep2_usb_data,
 	.codec		= &igep2_codec_data,
-	.gpio		= &igep2_gpio_data,
+	.gpio		= &igep2_twl4030_gpio_pdata,
 	.vmmc1          = &igep2_vmmc1,
-	.vmmc2		= &igep2_vmmc2,
 	.vpll2		= &igep2_vpll2,
 
 };
 
-static struct i2c_board_info __initdata igep2_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata igep2_i2c1_boardinfo[] = {
 	{
 		I2C_BOARD_INFO("twl4030", 0x48),
 		.flags		= I2C_CLIENT_WAKE,
@@ -441,14 +531,29 @@
 	},
 };
 
-static int __init igep2_i2c_init(void)
+static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("eeprom", 0x50),
+	},
+};
+
+static void __init igep2_i2c_init(void)
 {
-	omap_register_i2c_bus(1, 2600, igep2_i2c_boardinfo,
-			ARRAY_SIZE(igep2_i2c_boardinfo));
-	/* Bus 3 is attached to the DVI port where devices like the pico DLP
-	 * projector don't work reliably with 400kHz */
-	omap_register_i2c_bus(3, 100, NULL, 0);
-	return 0;
+	int ret;
+
+	ret = omap_register_i2c_bus(1, 2600, igep2_i2c1_boardinfo,
+		ARRAY_SIZE(igep2_i2c1_boardinfo));
+	if (ret)
+		pr_warning("IGEP2: Could not register I2C1 bus (%d)\n", ret);
+
+	/*
+	 * Bus 3 is attached to the DVI port where devices like the pico DLP
+	 * projector don't work reliably with 400kHz
+	 */
+	ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
+		ARRAY_SIZE(igep2_i2c3_boardinfo));
+	if (ret)
+		pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
 }
 
 static struct omap_musb_board_data musb_board_data = {
@@ -476,9 +581,57 @@
 #define board_mux	NULL
 #endif
 
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep2_wlan_bt_init(void)
+{
+	unsigned npd, wreset, btreset;
+
+	/* GPIO's for WLAN-BT combo depends on hardware revision */
+	if (hwrev == IGEP2_BOARD_HWREV_B) {
+		npd = IGEP2_RB_GPIO_WIFI_NPD;
+		wreset = IGEP2_RB_GPIO_WIFI_NRESET;
+		btreset = IGEP2_RB_GPIO_BT_NRESET;
+	} else if (hwrev == IGEP2_BOARD_HWREV_C) {
+		npd = IGEP2_RC_GPIO_WIFI_NPD;
+		wreset = IGEP2_RC_GPIO_WIFI_NRESET;
+		btreset = IGEP2_RC_GPIO_BT_NRESET;
+	} else
+		return;
+
+	/* Set GPIO's for  WLAN-BT combo module */
+	if ((gpio_request(npd, "GPIO_WIFI_NPD") == 0) &&
+	    (gpio_direction_output(npd, 1) == 0)) {
+		gpio_export(npd, 0);
+	} else
+		pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+	if ((gpio_request(wreset, "GPIO_WIFI_NRESET") == 0) &&
+	    (gpio_direction_output(wreset, 1) == 0)) {
+		gpio_export(wreset, 0);
+		gpio_set_value(wreset, 0);
+		udelay(10);
+		gpio_set_value(wreset, 1);
+	} else
+		pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+	if ((gpio_request(btreset, "GPIO_BT_NRESET") == 0) &&
+	    (gpio_direction_output(btreset, 1) == 0)) {
+		gpio_export(btreset, 0);
+	} else
+		pr_warning("IGEP2: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+static inline void __init igep2_wlan_bt_init(void) { }
+#endif
+
 static void __init igep2_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+	/* Get IGEP2 hardware revision */
+	igep2_get_revision();
+	/* Register I2C busses and drivers */
 	igep2_i2c_init();
 	platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
 	omap_serial_init();
@@ -486,55 +639,19 @@
 	usb_ehci_init(&ehci_pdata);
 
 	igep2_flash_init();
-	igep2_init_led();
+	igep2_leds_init();
 	igep2_display_init();
 	igep2_init_smsc911x();
 
-	/* GPIO userspace leds */
-#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
-	if ((gpio_request(IGEP2_GPIO_LED0_RED, "led0:red") == 0) &&
-	    (gpio_direction_output(IGEP2_GPIO_LED0_RED, 1) == 0)) {
-		gpio_export(IGEP2_GPIO_LED0_RED, 0);
-		gpio_set_value(IGEP2_GPIO_LED0_RED, 0);
-	} else
-		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
-
-	if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "led0:green") == 0) &&
-	    (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 1) == 0)) {
-		gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
-		gpio_set_value(IGEP2_GPIO_LED0_GREEN, 0);
-	} else
-		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
-
-	if ((gpio_request(IGEP2_GPIO_LED1_RED, "led1:red") == 0) &&
-	    (gpio_direction_output(IGEP2_GPIO_LED1_RED, 1) == 0)) {
-		gpio_export(IGEP2_GPIO_LED1_RED, 0);
-		gpio_set_value(IGEP2_GPIO_LED1_RED, 0);
-	} else
-		pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
-#endif
-
-	/* GPIO W-LAN + Bluetooth combo module */
-	if ((gpio_request(IGEP2_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
-	    (gpio_direction_output(IGEP2_GPIO_WIFI_NPD, 1) == 0)) {
-		gpio_export(IGEP2_GPIO_WIFI_NPD, 0);
-/* 		gpio_set_value(IGEP2_GPIO_WIFI_NPD, 0); */
-	} else
-		pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NPD\n");
+	/*
+	 * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+	 * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+	 */
+	igep2_wlan_bt_init();
 
-	if ((gpio_request(IGEP2_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
-	    (gpio_direction_output(IGEP2_GPIO_WIFI_NRESET, 1) == 0)) {
-		gpio_export(IGEP2_GPIO_WIFI_NRESET, 0);
-		gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 0);
-		udelay(10);
-		gpio_set_value(IGEP2_GPIO_WIFI_NRESET, 1);
-	} else
-		pr_warning("IGEP v2: Could not obtain gpio GPIO_WIFI_NRESET\n");
 }
 
 MACHINE_START(IGEP0020, "IGEP v2 board")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-igep0030.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-igep0030.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-igep0030.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-igep0030.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2010 - ISEE 2007 SL
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc.h>
+#include <plat/usb.h>
+#include <plat/onenand.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "sdram-numonyx-m65kxxxxam.h"
+
+#define IGEP3_GPIO_LED0_GREEN	54
+#define IGEP3_GPIO_LED0_RED	53
+#define IGEP3_GPIO_LED1_RED	16
+
+#define IGEP3_GPIO_WIFI_NPD	138
+#define IGEP3_GPIO_WIFI_NRESET	139
+#define IGEP3_GPIO_BT_NRESET	137
+
+#define IGEP3_GPIO_USBH_NRESET  115
+
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+
+#define ONENAND_MAP             0x20000000
+
+/*
+ * x2 Flash built-in COMBO POP MEMORY
+ * Since the device is equipped with two DataRAMs, and two-plane NAND
+ * Flash memory array, these two component enables simultaneous program
+ * of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+ * while Plane2 has only odd blocks such as block1, block3, block5.
+ * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
+ */
+
+static struct mtd_partition igep3_onenand_partitions[] = {
+	{
+		.name           = "X-Loader",
+		.offset         = 0,
+		.size           = 2 * (64*(2*2048))
+	},
+	{
+		.name           = "U-Boot",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 6 * (64*(2*2048)),
+	},
+	{
+		.name           = "Environment",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 2 * (64*(2*2048)),
+	},
+	{
+		.name           = "Kernel",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = 12 * (64*(2*2048)),
+	},
+	{
+		.name           = "File System",
+		.offset         = MTDPART_OFS_APPEND,
+		.size           = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct omap_onenand_platform_data igep3_onenand_pdata = {
+	.parts = igep3_onenand_partitions,
+	.nr_parts = ARRAY_SIZE(igep3_onenand_partitions),
+	.onenand_setup = NULL,
+	.dma_channel	= -1,	/* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device igep3_onenand_device = {
+	.name		= "omap2-onenand",
+	.id		= -1,
+	.dev = {
+		.platform_data = &igep3_onenand_pdata,
+	},
+};
+
+void __init igep3_flash_init(void)
+{
+	u8 cs = 0;
+	u8 onenandcs = GPMC_CS_NUM + 1;
+
+	for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+		u32 ret;
+		ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+		/* Check if NAND/oneNAND is configured */
+		if ((ret & 0xC00) == 0x800)
+			/* NAND found */
+			pr_err("IGEP3: Unsupported NAND found\n");
+		else {
+			ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+			if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+				/* OneNAND found */
+				onenandcs = cs;
+		}
+	}
+
+	if (onenandcs > GPMC_CS_NUM) {
+		pr_err("IGEP3: Unable to find configuration in GPMC\n");
+		return;
+	}
+
+	igep3_onenand_pdata.cs = onenandcs;
+
+	if (platform_device_register(&igep3_onenand_device) < 0)
+		pr_err("IGEP3: Unable to register OneNAND device\n");
+}
+
+#else
+void __init igep3_flash_init(void) {}
+#endif
+
+static struct regulator_consumer_supply igep3_vmmc1_supply = {
+	.supply		= "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data igep3_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &igep3_vmmc1_supply,
+};
+
+static struct omap2_hsmmc_info mmc[] = {
+	[0] = {
+		.mmc		= 1,
+		.caps		= MMC_CAP_4_BIT_DATA,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+	},
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+	[1] = {
+		.mmc		= 2,
+		.caps		= MMC_CAP_4_BIT_DATA,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+	},
+#endif
+	{}      /* Terminator */
+};
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#include <linux/leds.h>
+
+static struct gpio_led igep3_gpio_leds[] = {
+	[0] = {
+		.name			= "gpio-led:red:d0",
+		.gpio			= IGEP3_GPIO_LED0_RED,
+		.default_trigger	= "default-off"
+	},
+	[1] = {
+		.name			= "gpio-led:green:d0",
+		.gpio			= IGEP3_GPIO_LED0_GREEN,
+		.default_trigger	= "default-off",
+	},
+	[2] = {
+		.name			= "gpio-led:red:d1",
+		.gpio			= IGEP3_GPIO_LED1_RED,
+		.default_trigger	= "default-off",
+	},
+	[3] = {
+		.name			= "gpio-led:green:d1",
+		.default_trigger	= "heartbeat",
+		.gpio			= -EINVAL, /* gets replaced */
+	},
+};
+
+static struct gpio_led_platform_data igep3_led_pdata = {
+	.leds           = igep3_gpio_leds,
+	.num_leds       = ARRAY_SIZE(igep3_gpio_leds),
+};
+
+static struct platform_device igep3_led_device = {
+	 .name   = "leds-gpio",
+	 .id     = -1,
+	 .dev    = {
+		 .platform_data = &igep3_led_pdata,
+	},
+};
+
+static void __init igep3_leds_init(void)
+{
+	platform_device_register(&igep3_led_device);
+}
+
+#else
+static inline void igep3_leds_init(void)
+{
+	if ((gpio_request(IGEP3_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
+	    (gpio_direction_output(IGEP3_GPIO_LED0_RED, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_LED0_RED, 0);
+		gpio_set_value(IGEP3_GPIO_LED0_RED, 1);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_RED\n");
+
+	if ((gpio_request(IGEP3_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
+	    (gpio_direction_output(IGEP3_GPIO_LED0_GREEN, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_LED0_GREEN, 0);
+		gpio_set_value(IGEP3_GPIO_LED0_GREEN, 1);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_GREEN\n");
+
+	if ((gpio_request(IGEP3_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
+		(gpio_direction_output(IGEP3_GPIO_LED1_RED, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_LED1_RED, 0);
+		gpio_set_value(IGEP3_GPIO_LED1_RED, 1);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_RED\n");
+}
+#endif
+
+static int igep3_twl4030_gpio_setup(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
+	mmc[0].gpio_cd = gpio + 0;
+	omap2_hsmmc_init(mmc);
+
+	/*
+	 * link regulators to MMC adapters ... we "know" the
+	 * regulators will be set up only *after* we return.
+	 */
+	igep3_vmmc1_supply.dev = mmc[0].dev;
+
+	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
+	if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
+	    && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
+		gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
+		gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_GREEN\n");
+#else
+	igep3_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+#endif
+
+	return 0;
+};
+
+static struct twl4030_gpio_platform_data igep3_twl4030_gpio_pdata = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.use_leds	= true,
+	.setup		= igep3_twl4030_gpio_setup,
+};
+
+static struct twl4030_usb_data igep3_twl4030_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
+static void __init igep3_init_irq(void)
+{
+	omap2_init_common_hw(m65kxxxxam_sdrc_params, m65kxxxxam_sdrc_params);
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static struct twl4030_platform_data igep3_twl4030_pdata = {
+	.irq_base	= TWL4030_IRQ_BASE,
+	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.usb		= &igep3_twl4030_usb_data,
+	.gpio		= &igep3_twl4030_gpio_pdata,
+	.vmmc1		= &igep3_vmmc1,
+};
+
+static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl4030", 0x48),
+		.flags		= I2C_CLIENT_WAKE,
+		.irq		= INT_34XX_SYS_NIRQ,
+		.platform_data	= &igep3_twl4030_pdata,
+	},
+};
+
+static int __init igep3_i2c_init(void)
+{
+	omap_register_i2c_bus(1, 2600, igep3_i2c_boardinfo,
+			ARRAY_SIZE(igep3_i2c_boardinfo));
+
+	return 0;
+}
+
+static struct omap_musb_board_data musb_board_data = {
+	.interface_type	= MUSB_INTERFACE_ULPI,
+	.mode		= MUSB_OTG,
+	.power		= 100,
+};
+
+#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+
+static void __init igep3_wifi_bt_init(void)
+{
+	/* Configure MUX values for W-LAN + Bluetooth GPIO's */
+	omap_mux_init_gpio(IGEP3_GPIO_WIFI_NPD, OMAP_PIN_OUTPUT);
+	omap_mux_init_gpio(IGEP3_GPIO_WIFI_NRESET, OMAP_PIN_OUTPUT);
+	omap_mux_init_gpio(IGEP3_GPIO_BT_NRESET, OMAP_PIN_OUTPUT);
+
+	/* Set GPIO's for  W-LAN + Bluetooth combo module */
+	if ((gpio_request(IGEP3_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
+	    (gpio_direction_output(IGEP3_GPIO_WIFI_NPD, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_WIFI_NPD, 0);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NPD\n");
+
+	if ((gpio_request(IGEP3_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
+	    (gpio_direction_output(IGEP3_GPIO_WIFI_NRESET, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_WIFI_NRESET, 0);
+		gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 0);
+		udelay(10);
+		gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 1);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NRESET\n");
+
+	if ((gpio_request(IGEP3_GPIO_BT_NRESET, "GPIO_BT_NRESET") == 0) &&
+	    (gpio_direction_output(IGEP3_GPIO_BT_NRESET, 1) == 0)) {
+		gpio_export(IGEP3_GPIO_BT_NRESET, 0);
+	} else
+		pr_warning("IGEP3: Could not obtain gpio GPIO_BT_NRESET\n");
+}
+#else
+void __init igep3_wifi_bt_init(void) {}
+#endif
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+	{ .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux	NULL
+#endif
+
+static void __init igep3_init(void)
+{
+	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+
+	/* Register I2C busses and drivers */
+	igep3_i2c_init();
+
+	omap_serial_init();
+	usb_musb_init(&musb_board_data);
+
+	igep3_flash_init();
+	igep3_leds_init();
+
+	/*
+	 * WLAN-BT combo module from MuRata wich has a Marvell WLAN
+	 * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
+	 */
+	igep3_wifi_bt_init();
+
+}
+
+MACHINE_START(IGEP0030, "IGEP OMAP3 module")
+	.boot_params	= 0x80000100,
+	.map_io		= omap3_map_io,
+	.init_irq	= igep3_init_irq,
+	.init_machine	= igep3_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-ldp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-ldp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-ldp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-ldp.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/io.h>
 #include <linux/smsc911x.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -41,11 +42,12 @@
 #include <mach/board-zoom.h>
 
 #include <asm/delay.h>
-#include <plat/control.h>
 #include <plat/usb.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "hsmmc.h"
+#include "control.h"
 
 #define LDP_SMSC911X_CS		1
 #define LDP_SMSC911X_GPIO	152
@@ -82,7 +84,7 @@
 	},
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_1),
 	KEY(1, 0, KEY_2),
 	KEY(2, 0, KEY_3),
@@ -362,7 +364,7 @@
 static struct omap2_hsmmc_info mmc[] __initdata = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 	},
@@ -442,8 +444,6 @@
 }
 
 MACHINE_START(OMAP_LDP, "OMAP LDP board")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-n8x0.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-n8x0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-n8x0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-n8x0.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/usb/musb.h>
+#include <sound/tlv320aic3x.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -383,15 +384,6 @@
 	omap_mmc_notify_cover_event(mmc_device, index, *openp);
 }
 
-void n8x0_mmc_slot1_cover_handler(void *arg, int closed_state)
-{
-	if (mmc_device == NULL)
-		return;
-
-	slot1_cover_open = !closed_state;
-	omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
-}
-
 static int n8x0_mmc_late_init(struct device *dev)
 {
 	int r, bit, *openp;
@@ -511,7 +503,7 @@
 
 static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
 
-void __init n8x0_mmc_init(void)
+static void __init n8x0_mmc_init(void)
 
 {
 	int err;
@@ -560,11 +552,6 @@
 void __init n8x0_mmc_init(void)
 {
 }
-
-void n8x0_mmc_slot1_cover_handler(void *arg, int state)
-{
-}
-
 #endif	/* CONFIG_MMC_OMAP */
 
 #ifdef CONFIG_MENELAUS
@@ -614,29 +601,35 @@
 	return 0;
 }
 
-static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] = {
+#else
+static int n8x0_menelaus_late_init(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+	.late_init = n8x0_menelaus_late_init,
+};
+
+static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = {
 	{
 		I2C_BOARD_INFO("menelaus", 0x72),
 		.irq = INT_24XX_SYS_NIRQ,
+		.platform_data = &n8x0_menelaus_platform_data,
 	},
 };
 
-static struct menelaus_platform_data n8x0_menelaus_platform_data = {
-	.late_init = n8x0_menelaus_late_init,
+static struct aic3x_pdata n810_aic33_data __initdata = {
+	.gpio_reset = 118,
 };
 
-static void __init n8x0_menelaus_init(void)
-{
-	n8x0_i2c_board_info_1[0].platform_data = &n8x0_menelaus_platform_data;
-	omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
-			      ARRAY_SIZE(n8x0_i2c_board_info_1));
-}
-
-#else
-static inline void __init n8x0_menelaus_init(void)
-{
-}
-#endif
+static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {
+	{
+		I2C_BOARD_INFO("tlv320aic3x", 0x18),
+		.platform_data = &n810_aic33_data,
+	},
+};
 
 static void __init n8x0_map_io(void)
 {
@@ -653,6 +646,11 @@
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+	/* I2S codec port pins for McBSP block */
+	OMAP2420_MUX(EAC_AC_SCLK, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+	OMAP2420_MUX(EAC_AC_FS, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+	OMAP2420_MUX(EAC_AC_DIN, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),
+	OMAP2420_MUX(EAC_AC_DOUT, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),
 	{ .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #else
@@ -665,17 +663,20 @@
 	/* FIXME: add n810 spi devices */
 	spi_register_board_info(n800_spi_board_info,
 				ARRAY_SIZE(n800_spi_board_info));
+	omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
+			      ARRAY_SIZE(n8x0_i2c_board_info_1));
+	omap_register_i2c_bus(2, 400, NULL, 0);
+	if (machine_is_nokia_n810())
+		i2c_register_board_info(2, n810_i2c_board_info_2,
+					ARRAY_SIZE(n810_i2c_board_info_2));
 
 	omap_serial_init();
-	n8x0_menelaus_init();
 	n8x0_onenand_init();
 	n8x0_mmc_init();
 	n8x0_usb_init();
 }
 
 MACHINE_START(NOKIA_N800, "Nokia N800")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= n8x0_map_io,
 	.reserve	= omap_reserve,
@@ -685,8 +686,6 @@
 MACHINE_END
 
 MACHINE_START(NOKIA_N810, "Nokia N810")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= n8x0_map_io,
 	.reserve	= omap_reserve,
@@ -696,8 +695,6 @@
 MACHINE_END
 
 MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= n8x0_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3beagle.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3beagle.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3beagle.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3beagle.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
@@ -43,13 +44,100 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #define NAND_BLOCK_SIZE		SZ_128K
 
+/*
+ * OMAP3 Beagle revision
+ * Run time detection of Beagle revision is done by reading GPIO.
+ * GPIO ID -
+ *	AXBX	= GPIO173, GPIO172, GPIO171: 1 1 1
+ *	C1_3	= GPIO173, GPIO172, GPIO171: 1 1 0
+ *	C4	= GPIO173, GPIO172, GPIO171: 1 0 1
+ *	XM	= GPIO173, GPIO172, GPIO171: 0 0 0
+ */
+enum {
+	OMAP3BEAGLE_BOARD_UNKN = 0,
+	OMAP3BEAGLE_BOARD_AXBX,
+	OMAP3BEAGLE_BOARD_C1_3,
+	OMAP3BEAGLE_BOARD_C4,
+	OMAP3BEAGLE_BOARD_XM,
+};
+
+static u8 omap3_beagle_version;
+
+static u8 omap3_beagle_get_rev(void)
+{
+	return omap3_beagle_version;
+}
+
+static void __init omap3_beagle_init_rev(void)
+{
+	int ret;
+	u16 beagle_rev = 0;
+
+	omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
+	omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
+
+	ret = gpio_request(171, "rev_id_0");
+	if (ret < 0)
+		goto fail0;
+
+	ret = gpio_request(172, "rev_id_1");
+	if (ret < 0)
+		goto fail1;
+
+	ret = gpio_request(173, "rev_id_2");
+	if (ret < 0)
+		goto fail2;
+
+	gpio_direction_input(171);
+	gpio_direction_input(172);
+	gpio_direction_input(173);
+
+	beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
+			| (gpio_get_value(173) << 2);
+
+	switch (beagle_rev) {
+	case 7:
+		printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n");
+		omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX;
+		break;
+	case 6:
+		printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n");
+		omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3;
+		break;
+	case 5:
+		printk(KERN_INFO "OMAP3 Beagle Rev: C4\n");
+		omap3_beagle_version = OMAP3BEAGLE_BOARD_C4;
+		break;
+	case 0:
+		printk(KERN_INFO "OMAP3 Beagle Rev: xM\n");
+		omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
+		break;
+	default:
+		printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
+		omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+	}
+
+	return;
+
+fail2:
+	gpio_free(172);
+fail1:
+	gpio_free(171);
+fail0:
+	printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+	omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+
+	return;
+}
+
 static struct mtd_partition omap3beagle_nand_partitions[] = {
 	/* All the partition sizes are listed in terms of NAND block size */
 	{
@@ -166,7 +254,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 29,
 	},
 	{}	/* Terminator */
@@ -185,7 +273,10 @@
 static int beagle_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
-	if (system_rev >= 0x20 && system_rev <= 0x34301000) {
+	if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
+		mmc[0].gpio_wp = -EINVAL;
+	} else if ((omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C1_3) ||
+		(omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_C4)) {
 		omap_mux_init_gpio(23, OMAP_PIN_INPUT);
 		mmc[0].gpio_wp = 23;
 	} else {
@@ -322,13 +413,19 @@
 	},
 };
 
+static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
+       {
+               I2C_BOARD_INFO("eeprom", 0x50),
+       },
+};
+
 static int __init omap3_beagle_i2c_init(void)
 {
 	omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
 			ARRAY_SIZE(beagle_i2c_boardinfo));
 	/* Bus 3 is attached to the DVI port where devices like the pico DLP
 	 * projector don't work reliably with 400kHz */
-	omap_register_i2c_bus(3, 100, NULL, 0);
+	omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
 	return 0;
 }
 
@@ -464,6 +561,7 @@
 static void __init omap3_beagle_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+	omap3_beagle_init_rev();
 	omap3_beagle_i2c_init();
 	platform_add_devices(omap3_beagle_devices,
 			ARRAY_SIZE(omap3_beagle_devices));
@@ -487,8 +585,6 @@
 
 MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
 	/* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3evm.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 #include <linux/smsc911x.h>
 
 #include <linux/regulator/machine.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -370,7 +371,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= 63,
 	},
@@ -446,7 +447,7 @@
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_LEFT),
 	KEY(0, 1, KEY_DOWN),
 	KEY(0, 2, KEY_ENTER),
@@ -584,7 +585,7 @@
 	return !gpio_get_value(OMAP3_EVM_TS_GPIO);
 }
 
-struct ads7846_platform_data ads7846_config = {
+static struct ads7846_platform_data ads7846_config = {
 	.x_max			= 0x0fff,
 	.y_max			= 0x0fff,
 	.x_plate_ohms		= 180,
@@ -603,7 +604,7 @@
 	.single_channel	= 1,	/* 0: slave, 1: master */
 };
 
-struct spi_board_info omap3evm_spi_board_info[] = {
+static struct spi_board_info omap3evm_spi_board_info[] = {
 	[0] = {
 		.modalias		= "ads7846",
 		.bus_num		= 1,
@@ -714,8 +715,6 @@
 
 MACHINE_START(OMAP3EVM, "OMAP3 EVM")
 	/* Maintainer: Syed Mohammed Khasim - Texas Instruments */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3logic.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3logic.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3logic.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3logic.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,241 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3logic.c
+ *
+ * Copyright (C) 2010 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Copyright (C) 2010 Logic Product Development, Inc.
+ * Peter Barada <peter.barada@logicpd.com>
+ *
+ * Modified from Beagle, EVM, and RX51
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "mux.h"
+#include "hsmmc.h"
+#include "timer-gp.h"
+#include "control.h"
+
+#include <plat/mux.h>
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/gpmc-smsc911x.h>
+#include <plat/gpmc.h>
+#include <plat/sdrc.h>
+
+#define OMAP3LOGIC_SMSC911X_CS			1
+
+#define OMAP3530_LV_SOM_MMC_GPIO_CD		110
+#define OMAP3530_LV_SOM_MMC_GPIO_WP		126
+#define OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ	152
+
+#define OMAP3_TORPEDO_MMC_GPIO_CD		127
+#define OMAP3_TORPEDO_SMSC911X_GPIO_IRQ		129
+
+static struct regulator_consumer_supply omap3logic_vmmc1_supply = {
+	.supply			= "vmmc",
+};
+
+/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
+static struct regulator_init_data omap3logic_vmmc1 = {
+	.constraints = {
+		.name			= "VMMC1",
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &omap3logic_vmmc1_supply,
+};
+
+static struct twl4030_gpio_platform_data omap3logic_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.use_leds	= true,
+	.pullups	= BIT(1),
+	.pulldowns	= BIT(2)  | BIT(6)  | BIT(7)  | BIT(8)
+			| BIT(13) | BIT(15) | BIT(16) | BIT(17),
+};
+
+static struct twl4030_platform_data omap3logic_twldata = {
+	.irq_base	= TWL4030_IRQ_BASE,
+	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.gpio		= &omap3logic_gpio_data,
+	.vmmc1		= &omap3logic_vmmc1,
+};
+
+static struct i2c_board_info __initdata omap3logic_i2c_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("twl4030", 0x48),
+		.flags = I2C_CLIENT_WAKE,
+		.irq = INT_34XX_SYS_NIRQ,
+		.platform_data = &omap3logic_twldata,
+	},
+};
+
+static int __init omap3logic_i2c_init(void)
+{
+	omap_register_i2c_bus(1, 2600, omap3logic_i2c_boardinfo,
+				ARRAY_SIZE(omap3logic_i2c_boardinfo));
+	return 0;
+}
+
+static struct omap2_hsmmc_info __initdata board_mmc_info[] = {
+	{
+		.name		= "external",
+		.mmc		= 1,
+		.caps		= MMC_CAP_4_BIT_DATA,
+		.gpio_cd	= -EINVAL,
+		.gpio_wp	= -EINVAL,
+	},
+	{}      /* Terminator */
+};
+
+static void __init board_mmc_init(void)
+{
+	if (machine_is_omap3530_lv_som()) {
+		/* OMAP3530 LV SOM board */
+		board_mmc_info[0].gpio_cd = OMAP3530_LV_SOM_MMC_GPIO_CD;
+		board_mmc_info[0].gpio_wp = OMAP3530_LV_SOM_MMC_GPIO_WP;
+		omap_mux_init_signal("gpio_110", OMAP_PIN_OUTPUT);
+		omap_mux_init_signal("gpio_126", OMAP_PIN_OUTPUT);
+	} else if (machine_is_omap3_torpedo()) {
+		/* OMAP3 Torpedo board */
+		board_mmc_info[0].gpio_cd = OMAP3_TORPEDO_MMC_GPIO_CD;
+		omap_mux_init_signal("gpio_127", OMAP_PIN_OUTPUT);
+	} else {
+		/* unsupported board */
+		printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+		return;
+	}
+
+	omap2_hsmmc_init(board_mmc_info);
+	/* link regulators to MMC adapters */
+	omap3logic_vmmc1_supply.dev = board_mmc_info[0].dev;
+}
+
+static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
+	.cs             = OMAP3LOGIC_SMSC911X_CS,
+	.gpio_irq       = -EINVAL,
+	.gpio_reset     = -EINVAL,
+	.flags          = IORESOURCE_IRQ_LOWLEVEL,
+};
+
+/* TODO/FIXME (comment by Peter Barada, LogicPD):
+ * Fix the PBIAS voltage for Torpedo MMC1 pins that
+ * are used for other needs (IRQs, etc).            */
+static void omap3torpedo_fix_pbias_voltage(void)
+{
+	u16 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE;
+	u32 reg;
+
+	if (machine_is_omap3_torpedo())
+	{
+		/* Set the bias for the pin */
+		reg = omap_ctrl_readl(control_pbias_offset);
+
+		reg &= ~OMAP343X_PBIASLITEPWRDNZ1;
+		omap_ctrl_writel(reg, control_pbias_offset);
+
+		/* 100ms delay required for PBIAS configuration */
+		msleep(100);
+
+		reg |= OMAP343X_PBIASLITEVMODE1;
+		reg |= OMAP343X_PBIASLITEPWRDNZ1;
+		omap_ctrl_writel(reg | 0x300, control_pbias_offset);
+	}
+}
+
+static inline void __init board_smsc911x_init(void)
+{
+	if (machine_is_omap3530_lv_som()) {
+		/* OMAP3530 LV SOM board */
+		board_smsc911x_data.gpio_irq =
+					OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ;
+		omap_mux_init_signal("gpio_152", OMAP_PIN_INPUT);
+	} else if (machine_is_omap3_torpedo()) {
+		/* OMAP3 Torpedo board */
+		board_smsc911x_data.gpio_irq = OMAP3_TORPEDO_SMSC911X_GPIO_IRQ;
+		omap_mux_init_signal("gpio_129", OMAP_PIN_INPUT);
+	} else {
+		/* unsupported board */
+		printk(KERN_ERR "%s(): unknown machine type\n", __func__);
+		return;
+	}
+
+	gpmc_smsc911x_init(&board_smsc911x_data);
+}
+
+static void __init omap3logic_init_irq(void)
+{
+	omap2_init_common_hw(NULL, NULL);
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+#ifdef CONFIG_OMAP_MUX
+static struct omap_board_mux board_mux[] __initdata = {
+	{ .reg_offset = OMAP_MUX_TERMINATOR },
+};
+#else
+#define board_mux       NULL
+#endif
+
+static void __init omap3logic_init(void)
+{
+	omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
+	omap3torpedo_fix_pbias_voltage();
+	omap3logic_i2c_init();
+	omap_serial_init();
+	board_mmc_init();
+	board_smsc911x_init();
+
+	/* Ensure SDRC pins are mux'd for self-refresh */
+	omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
+	omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
+}
+
+MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
+	.boot_params	= 0x80000100,
+	.map_io		= omap3_map_io,
+	.init_irq	= omap3logic_init_irq,
+	.init_machine	= omap3logic_init,
+	.timer		= &omap_timer,
+MACHINE_END
+
+MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
+	.boot_params	= 0x80000100,
+	.map_io		= omap3_map_io,
+	.init_irq	= omap3logic_init_irq,
+	.init_machine	= omap3logic_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3pandora.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3pandora.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3pandora.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3pandora.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,14 +25,16 @@
 #include <linux/spi/ads7846.h>
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/leds.h>
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/gpio_keys.h>
+#include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/regulator/fixed.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -276,14 +278,14 @@
 static struct omap2_hsmmc_info omap3pandora_mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= 126,
 		.ext_clock	= 0,
 	},
 	{
 		.mmc		= 2,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= 127,
 		.ext_clock	= 1,
@@ -291,7 +293,7 @@
 	},
 	{
 		.mmc		= 3,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.init_card	= pandora_wl1251_init_card,
@@ -344,6 +346,9 @@
 static struct regulator_consumer_supply pandora_vmmc2_supply =
 	REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
 
+static struct regulator_consumer_supply pandora_vmmc3_supply =
+	REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.2");
+
 static struct regulator_consumer_supply pandora_vdda_dac_supply =
 	REGULATOR_SUPPLY("vdda_dac", "omapdss");
 
@@ -488,6 +493,33 @@
 	.consumer_supplies	= &pandora_adac_supply,
 };
 
+/* Fixed regulator internal to Wifi module */
+static struct regulator_init_data pandora_vmmc3 = {
+	.constraints = {
+		.valid_ops_mask		= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &pandora_vmmc3_supply,
+};
+
+static struct fixed_voltage_config pandora_vwlan = {
+	.supply_name		= "vwlan",
+	.microvolts		= 1800000, /* 1.8V */
+	.gpio			= PANDORA_WIFI_NRESET_GPIO,
+	.startup_delay		= 50000, /* 50ms */
+	.enable_high		= 1,
+	.enabled_at_boot	= 0,
+	.init_data		= &pandora_vmmc3,
+};
+
+static struct platform_device pandora_vwlan_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev = {
+		.platform_data = &pandora_vwlan,
+	},
+};
+
 static struct twl4030_usb_data omap3pandora_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
@@ -501,6 +533,8 @@
 	.audio = &omap3pandora_audio_data,
 };
 
+static struct twl4030_bci_platform_data pandora_bci_data;
+
 static struct twl4030_platform_data omap3pandora_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
@@ -516,6 +550,7 @@
 	.vaux4		= &pandora_vaux4,
 	.vsim		= &pandora_vsim,
 	.keypad		= &pandora_kp_data,
+	.bci		= &pandora_bci_data,
 };
 
 static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
@@ -644,19 +679,8 @@
 	if (pandora_wl1251_pdata.irq < 0)
 		goto fail_irq;
 
-	ret = gpio_request(PANDORA_WIFI_NRESET_GPIO, "wl1251 nreset");
-	if (ret < 0)
-		goto fail_irq;
-
-	/* start powered so that it probes with MMC subsystem */
-	ret = gpio_direction_output(PANDORA_WIFI_NRESET_GPIO, 1);
-	if (ret < 0)
-		goto fail_nreset;
-
 	return;
 
-fail_nreset:
-	gpio_free(PANDORA_WIFI_NRESET_GPIO);
 fail_irq:
 	gpio_free(PANDORA_WIFI_IRQ_GPIO);
 fail:
@@ -668,6 +692,7 @@
 	&pandora_keys_gpio,
 	&pandora_dss_device,
 	&pandora_wl1251_data,
+	&pandora_vwlan_device,
 };
 
 static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
@@ -717,8 +742,6 @@
 }
 
 MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3stalker.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3stalker.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3stalker.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3stalker.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,6 +26,7 @@
 
 #include <linux/regulator/machine.h>
 #include <linux/i2c/twl.h>
+#include <linux/mmc/host.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -38,7 +39,6 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 #include <plat/display.h>
 
 #include <plat/mcspi.h>
@@ -52,6 +52,7 @@
 #include "sdram-micron-mt46h32m32lf-6.h"
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
 #define OMAP3STALKER_ETHR_START	0x2c000000
@@ -275,7 +276,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 	 .mmc		= 1,
-	 .wires		= 4,
+	 .caps		= MMC_CAP_4_BIT_DATA,
 	 .gpio_cd	= -EINVAL,
 	 .gpio_wp	= 23,
 	 },
@@ -389,7 +390,7 @@
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_LEFT),
 	KEY(0, 1, KEY_DOWN),
 	KEY(0, 2, KEY_ENTER),
@@ -564,7 +565,7 @@
 	.single_channel		= 1,	/* 0: slave, 1: master */
 };
 
-struct spi_board_info omap3stalker_spi_board_info[] = {
+static struct spi_board_info omap3stalker_spi_board_info[] = {
 	[0] = {
 	       .modalias	= "ads7846",
 	       .bus_num		= 1,
@@ -654,8 +655,6 @@
 
 MACHINE_START(SBC3530, "OMAP3 STALKER")
 	/* Maintainer: Jason Lam -lzg@ema-tech.com */
-	.phys_io		= 0x48000000,
-	.io_pg_offst		= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params		= 0x80000100,
 	.map_io			= omap3_map_io,
 	.init_irq		= omap3_stalker_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3touchbook.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3touchbook.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap3touchbook.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap3touchbook.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/mmc/host.h>
 
 #include <plat/mcspi.h>
 #include <linux/spi/spi.h>
@@ -47,10 +48,10 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/timer-gp.h>
 
 #include "mux.h"
 #include "hsmmc.h"
+#include "timer-gp.h"
 
 #include <asm/setup.h>
 
@@ -61,7 +62,7 @@
 #define TB_BL_PWM_TIMER		9
 #define TB_KILL_POWER_GPIO	168
 
-unsigned long touchbook_revision;
+static unsigned long touchbook_revision;
 
 static struct mtd_partition omap3touchbook_nand_partitions[] = {
 	/* All the partition sizes are listed in terms of NAND block size */
@@ -108,7 +109,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= 29,
 	},
 	{}	/* Terminator */
@@ -538,8 +539,6 @@
 
 MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
 	/* Maintainer: Gregoire Gentil - http://www.alwaysinnovating.com */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap4panda.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap4panda.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-omap4panda.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-omap4panda.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/leds.h>
 #include <linux/gpio.h>
 #include <linux/usb/otg.h>
 #include <linux/i2c/twl.h>
@@ -33,12 +34,45 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/control.h>
-#include <plat/timer-gp.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
+#include "timer-gp.h"
+
 #include "hsmmc.h"
+#include "control.h"
+
+#define GPIO_HUB_POWER		1
+#define GPIO_HUB_NRESET		62
+
+static struct gpio_led gpio_leds[] = {
+	{
+		.name			= "pandaboard::status1",
+		.default_trigger	= "heartbeat",
+		.gpio			= 7,
+	},
+	{
+		.name			= "pandaboard::status2",
+		.default_trigger	= "mmc0",
+		.gpio			= 8,
+	},
+};
 
+static struct gpio_led_platform_data gpio_led_info = {
+	.leds		= gpio_leds,
+	.num_leds	= ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &gpio_led_info,
+	},
+};
+
+static struct platform_device *panda_devices[] __initdata = {
+	&leds_gpio,
+};
 
 static void __init omap4_panda_init_irq(void)
 {
@@ -47,6 +81,56 @@
 	omap_gpio_init();
 }
 
+static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
+	.port_mode[0] = EHCI_HCD_OMAP_MODE_PHY,
+	.port_mode[1] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+	.port_mode[2] = EHCI_HCD_OMAP_MODE_UNKNOWN,
+	.phy_reset  = false,
+	.reset_gpio_port[0]  = -EINVAL,
+	.reset_gpio_port[1]  = -EINVAL,
+	.reset_gpio_port[2]  = -EINVAL
+};
+
+static void __init omap4_ehci_init(void)
+{
+	int ret;
+
+
+	/* disable the power to the usb hub prior to init */
+	ret = gpio_request(GPIO_HUB_POWER, "hub_power");
+	if (ret) {
+		pr_err("Cannot request GPIO %d\n", GPIO_HUB_POWER);
+		goto error1;
+	}
+	gpio_export(GPIO_HUB_POWER, 0);
+	gpio_direction_output(GPIO_HUB_POWER, 0);
+	gpio_set_value(GPIO_HUB_POWER, 0);
+
+	/* reset phy+hub */
+	ret = gpio_request(GPIO_HUB_NRESET, "hub_nreset");
+	if (ret) {
+		pr_err("Cannot request GPIO %d\n", GPIO_HUB_NRESET);
+		goto error2;
+	}
+	gpio_export(GPIO_HUB_NRESET, 0);
+	gpio_direction_output(GPIO_HUB_NRESET, 0);
+	gpio_set_value(GPIO_HUB_NRESET, 0);
+	gpio_set_value(GPIO_HUB_NRESET, 1);
+
+	usb_ehci_init(&ehci_pdata);
+
+	/* enable power to hub */
+	gpio_set_value(GPIO_HUB_POWER, 1);
+	return;
+
+error2:
+	gpio_free(GPIO_HUB_POWER);
+error1:
+	pr_err("Unable to initialize EHCI power/reset\n");
+	return;
+
+}
+
 static struct omap_musb_board_data musb_board_data = {
 	.interface_type		= MUSB_INTERFACE_UTMI,
 	.mode			= MUSB_PERIPHERAL,
@@ -56,7 +140,7 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_wp	= -EINVAL,
 	},
 	{}	/* Terminator */
@@ -67,10 +151,6 @@
 		.supply = "vmmc",
 		.dev_name = "mmci-omap-hs.0",
 	},
-	{
-		.supply = "vmmc",
-		.dev_name = "mmci-omap-hs.1",
-	},
 };
 
 static int omap4_twl6030_hsmmc_late_init(struct device *dev)
@@ -80,16 +160,32 @@
 				struct platform_device, dev);
 	struct omap_mmc_platform_data *pdata = dev->platform_data;
 
+	if (!pdata) {
+		dev_err(dev, "%s: NULL platform data\n", __func__);
+		return -EINVAL;
+	}
 	/* Setting MMC1 Card detect Irq */
-	if (pdev->id == 0)
-		pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE +
-						MMCDETECT_INTR_OFFSET;
+	if (pdev->id == 0) {
+		ret = twl6030_mmc_card_detect_config();
+		 if (ret)
+			dev_err(dev, "%s: Error card detect config(%d)\n",
+				__func__, ret);
+		 else
+			pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+	}
 	return ret;
 }
 
 static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
 {
-	struct omap_mmc_platform_data *pdata = dev->platform_data;
+	struct omap_mmc_platform_data *pdata;
+
+	/* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+	if (!dev) {
+		pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
+		return;
+	}
+	pdata = dev->platform_data;
 
 	pdata->init =	omap4_twl6030_hsmmc_late_init;
 }
@@ -156,7 +252,7 @@
 					| REGULATOR_CHANGE_MODE
 					| REGULATOR_CHANGE_STATUS,
 	},
-	.num_consumer_supplies  = 2,
+	.num_consumer_supplies  = 1,
 	.consumer_supplies      = omap4_panda_vmmc_supply,
 };
 
@@ -274,13 +370,13 @@
 }
 static void __init omap4_panda_init(void)
 {
-	int status;
-
 	omap4_panda_i2c_init();
+	platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices));
 	omap_serial_init();
 	omap4_twl6030_hsmmc_init(mmc);
 	/* OMAP4 Panda uses internal transceiver so register nop transceiver */
 	usb_nop_xceiv_register();
+	omap4_ehci_init();
 	/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
 	if (!cpu_is_omap44xx())
 		usb_musb_init(&musb_board_data);
@@ -294,8 +390,6 @@
 
 MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
 	/* Maintainer: David Anders - Texas Instruments Inc */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap4_panda_map_io,
 	.init_irq	= omap4_panda_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-overo.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-overo.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-overo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-overo.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -303,13 +304,13 @@
 static struct omap2_hsmmc_info mmc[] = {
 	{
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 	},
 	{
 		.mmc		= 2,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.transceiver	= true,
@@ -501,8 +502,6 @@
 }
 
 MACHINE_START(OVERO, "Gumstix Overo")
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51.c	2011-01-04 19:50:19.000000000 -0500
@@ -150,8 +150,6 @@
 
 MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
 	/* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
-	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= rx51_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-peripherals.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-peripherals.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-peripherals.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-peripherals.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,7 @@
 #include <linux/input.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
-#include <linux/spi/wl12xx.h>
+#include <linux/wl12xx.h>
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 #include <linux/clk.h>
@@ -23,6 +23,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/mmc/host.h>
+#include <sound/tlv320aic3x.h>
 
 #include <plat/mcspi.h>
 #include <plat/board.h>
@@ -32,6 +33,8 @@
 #include <plat/onenand.h>
 #include <plat/gpmc-smc91x.h>
 
+#include <mach/board-rx51.h>
+
 #include <sound/tlv320aic3x.h>
 #include <sound/tpa6130a2-plat.h>
 
@@ -104,6 +107,10 @@
 	},
 };
 
+static struct platform_device rx51_charger_device = {
+	.name = "isp1704_charger",
+};
+
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 
 #define RX51_GPIO_CAMERA_LENS_COVER	110
@@ -184,7 +191,7 @@
 }
 #endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
 
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	/*
 	 * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
 	 * connected to the ground" matrix state.
@@ -302,7 +309,7 @@
 	{
 		.name		= "external",
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.cover_only	= true,
 		.gpio_cd	= 160,
 		.gpio_wp	= -EINVAL,
@@ -311,7 +318,8 @@
 	{
 		.name		= "internal",
 		.mmc		= 2,
-		.wires		= 8, /* See also rx51_mmc2_remux */
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+						/* See also rx51_mmc2_remux */
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.nonremovable	= true,
@@ -689,7 +697,6 @@
 };
 
 
-
 static struct twl4030_platform_data rx51_twldata __initdata = {
 	.irq_base		= TWL4030_IRQ_BASE,
 	.irq_end		= TWL4030_IRQ_END,
@@ -710,10 +717,6 @@
 	.vio			= &rx51_vio,
 };
 
-static struct aic3x_pdata rx51_aic3x_data __initdata = {
-	.gpio_reset		= 60,
-};
-
 static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
 	.id			= TPA6130A2,
 	.power_gpio		= 98,
@@ -728,6 +731,17 @@
 	},
 };
 
+/* Audio setup data */
+static struct aic3x_setup_data rx51_aic34_setup = {
+	.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
+	.gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
+};
+
+static struct aic3x_pdata rx51_aic3x_data = {
+	.setup = &rx51_aic34_setup,
+	.gpio_reset = 60,
+};
+
 static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
 	{
 		I2C_BOARD_INFO("tlv320aic3x", 0x18),
@@ -909,5 +923,6 @@
 	spi_register_board_info(rx51_peripherals_spi_board_info,
 				ARRAY_SIZE(rx51_peripherals_spi_board_info));
 	omap2_hsmmc_init(mmc);
+	platform_device_register(&rx51_charger_device);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-sdram.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-sdram.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-sdram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-sdram.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 	u32 tWTR;
 };
 
-struct omap_sdrc_params rx51_sdrc_params[4];
+static struct omap_sdrc_params rx51_sdrc_params[4];
 
 static const struct sdram_timings rx51_timings[] = {
 	{
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-video.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-video.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-rx51-video.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-rx51-video.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,8 @@
 #include <plat/vram.h>
 #include <plat/mcspi.h>
 
+#include <mach/board-rx51.h>
+
 #include "mux.h"
 
 #define RX51_LCD_RESET_GPIO	90
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom2.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom2.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/i2c/twl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -23,6 +24,7 @@
 
 #include <mach/board-zoom.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 
@@ -34,41 +36,6 @@
 	omap_gpio_init();
 }
 
-/* REVISIT: These audio entries can be removed once MFD code is merged */
-#if 0
-
-static struct twl4030_madc_platform_data zoom2_madc_data = {
-	.irq_line	= 1,
-};
-
-static struct twl4030_codec_audio_data zoom2_audio_data = {
-	.audio_mclk = 26000000,
-};
-
-static struct twl4030_codec_data zoom2_codec_data = {
-	.audio_mclk = 26000000,
-	.audio = &zoom2_audio_data,
-};
-
-static struct twl4030_platform_data zoom2_twldata = {
-	.irq_base	= TWL4030_IRQ_BASE,
-	.irq_end	= TWL4030_IRQ_END,
-
-	/* platform_data for children goes here */
-	.bci		= &zoom2_bci_data,
-	.madc		= &zoom2_madc_data,
-	.usb		= &zoom2_usb_data,
-	.gpio		= &zoom2_gpio_data,
-	.keypad		= &zoom2_kp_twl4030_data,
-	.codec		= &zoom2_codec_data,
-	.vmmc1          = &zoom2_vmmc1,
-	.vmmc2          = &zoom2_vmmc2,
-	.vsim           = &zoom2_vsim,
-
-};
-
-#endif
-
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
 	/* WLAN IRQ - GPIO 162 */
@@ -141,8 +108,6 @@
 }
 
 MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
-	.phys_io	= ZOOM_UART_BASE,
-	.io_pg_offst	= (ZOOM_UART_VIRT >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom3.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom3.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom3.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,7 @@
 #include <plat/board.h>
 #include <plat/usb.h>
 
+#include "board-flash.h"
 #include "mux.h"
 #include "sdram-hynix-h8mbx00u0mer-0em.h"
 
@@ -123,8 +124,6 @@
 }
 
 MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
-	.phys_io	= ZOOM_UART_BASE,
-	.io_pg_offst	= (ZOOM_UART_VIRT >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap3_map_io,
 	.reserve	= omap_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom-debugboard.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom-debugboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom-debugboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom-debugboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,8 @@
 
 #include <plat/gpmc.h>
 
+#include <mach/board-zoom.h>
+
 #define ZOOM_SMSC911X_CS	7
 #define ZOOM_SMSC911X_GPIO	158
 #define ZOOM_QUADUART_CS	3
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom-peripherals.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom-peripherals.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/board-zoom-peripherals.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/board-zoom-peripherals.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,9 @@
 #include <linux/gpio.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/wl12xx.h>
+#include <linux/mmc/host.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -24,11 +27,16 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 
+#include <mach/board-zoom.h>
+
 #include "mux.h"
 #include "hsmmc.h"
 
+#define OMAP_ZOOM_WLAN_PMENA_GPIO	(101)
+#define OMAP_ZOOM_WLAN_IRQ_GPIO		(162)
+
 /* Zoom2 has Qwerty keyboard*/
-static int board_keymap[] = {
+static uint32_t board_keymap[] = {
 	KEY(0, 0, KEY_E),
 	KEY(0, 1, KEY_R),
 	KEY(0, 2, KEY_T),
@@ -106,6 +114,11 @@
 	.supply		= "vmmc",
 };
 
+static struct regulator_consumer_supply zoom_vmmc3_supply = {
+	.supply		= "vmmc",
+	.dev_name	= "mmci-omap-hs.2",
+};
+
 /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
 static struct regulator_init_data zoom_vmmc1 = {
 	.constraints = {
@@ -151,23 +164,63 @@
 	.consumer_supplies      = &zoom_vsim_supply,
 };
 
+static struct regulator_init_data zoom_vmmc3 = {
+	.constraints = {
+		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies = &zoom_vmmc3_supply,
+};
+
+static struct fixed_voltage_config zoom_vwlan = {
+	.supply_name		= "vwl1271",
+	.microvolts		= 1800000, /* 1.8V */
+	.gpio			= OMAP_ZOOM_WLAN_PMENA_GPIO,
+	.startup_delay		= 70000, /* 70msec */
+	.enable_high		= 1,
+	.enabled_at_boot	= 0,
+	.init_data		= &zoom_vmmc3,
+};
+
+static struct platform_device omap_vwlan_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &zoom_vwlan,
+	},
+};
+
+struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
+	.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
+	/* ZOOM ref clock is 26 MHz */
+	.board_ref_clock = 1,
+};
+
 static struct omap2_hsmmc_info mmc[] __initdata = {
 	{
 		.name		= "external",
 		.mmc		= 1,
-		.wires		= 4,
+		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_wp	= -EINVAL,
 		.power_saving	= true,
 	},
 	{
 		.name		= "internal",
 		.mmc		= 2,
-		.wires		= 8,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.nonremovable	= true,
 		.power_saving	= true,
 	},
+	{
+		.name		= "wl1271",
+		.mmc		= 3,
+		.caps		= MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
+		.gpio_wp	= -EINVAL,
+		.gpio_cd	= -EINVAL,
+		.nonremovable	= true,
+	},
 	{}      /* Terminator */
 };
 
@@ -188,6 +241,11 @@
 	return 0;
 }
 
+/* EXTMUTE callback function */
+void zoom2_set_hs_extmute(int mute)
+{
+	gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+}
 
 static int zoom_batt_table[] = {
 /* 0 C*/
@@ -257,6 +315,11 @@
 
 static int __init omap_i2c_init(void)
 {
+	if (machine_is_omap_zoom2()) {
+		zoom_audio_data.ramp_delay_value = 3;	/* 161 ms */
+		zoom_audio_data.hs_extmute = 1;
+		zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+	}
 	omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
 			ARRAY_SIZE(zoom_i2c_boardinfo));
 	omap_register_i2c_bus(2, 400, NULL, 0);
@@ -279,7 +342,12 @@
 
 void __init zoom_peripherals_init(void)
 {
+	if (wl12xx_set_platform_data(&omap_zoom_wlan_data))
+		pr_err("error setting wl12xx data\n");
+
 	omap_i2c_init();
+	platform_device_register(&omap_vwlan_device);
 	usb_musb_init(&musb_board_data);
 	enable_board_wakeup_source();
+	omap_serial_init();
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock2420_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock2420_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock2420_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock2420_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include "prm-regbits-24xx.h"
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define OMAP_CM_REGADDR                 OMAP2420_CM_REGADDR
 
@@ -89,6 +90,12 @@
 	.clkdm_name	= "wkup_clkdm",
 };
 
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+	.name		= "mcbsp_clks",
+	.ops		= &clkops_null,
+};
+
 /*
  * Analog domain root source clocks
  */
@@ -1135,14 +1142,34 @@
 	.recalc		= &followparent_recalc,
 };
 
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+	{ .div = 1, .val = 0, .flags = RATE_IN_24XX },
+	{ .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+	{ .div = 1, .val = 1, .flags = RATE_IN_24XX },
+	{ .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+	{ .parent = &func_96m_ck,  .rates = common_mcbsp_96m_rates },
+	{ .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
+	{ .parent = NULL }
+};
+
 static struct clk mcbsp1_fck = {
 	.name		= "mcbsp1_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_MCBSP1_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+	.clksel_mask	= OMAP2_MCBSP1_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp2_ick = {
@@ -1159,10 +1186,14 @@
 	.name		= "mcbsp2_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_MCBSP2_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP242X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+	.clksel_mask	= OMAP2_MCBSP2_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcspi1_ick = {
@@ -1721,6 +1752,9 @@
 	CLK(NULL,	"osc_ck",	&osc_ck,	CK_242X),
 	CLK(NULL,	"sys_ck",	&sys_ck,	CK_242X),
 	CLK(NULL,	"alt_ck",	&alt_ck,	CK_242X),
+	CLK("omap-mcbsp.1",	"pad_fck",	&mcbsp_clks,	CK_242X),
+	CLK("omap-mcbsp.2",	"pad_fck",	&mcbsp_clks,	CK_242X),
+	CLK(NULL,	"mcbsp_clks",	&mcbsp_clks,	CK_242X),
 	/* internal analog sources */
 	CLK(NULL,	"dpll_ck",	&dpll_ck,	CK_242X),
 	CLK(NULL,	"apll96_ck",	&apll96_ck,	CK_242X),
@@ -1728,6 +1762,8 @@
 	/* internal prcm root sources */
 	CLK(NULL,	"func_54m_ck",	&func_54m_ck,	CK_242X),
 	CLK(NULL,	"core_ck",	&core_ck,	CK_242X),
+	CLK("omap-mcbsp.1",	"prcm_fck",	&func_96m_ck,	CK_242X),
+	CLK("omap-mcbsp.2",	"prcm_fck",	&func_96m_ck,	CK_242X),
 	CLK(NULL,	"func_96m_ck",	&func_96m_ck,	CK_242X),
 	CLK(NULL,	"func_48m_ck",	&func_48m_ck,	CK_242X),
 	CLK(NULL,	"func_12m_ck",	&func_12m_ck,	CK_242X),
@@ -1838,7 +1874,7 @@
 	CLK(NULL,	"des_ick",	&des_ick,	CK_242X),
 	CLK("omap-sham",	"ick",	&sha_ick,	CK_242X),
 	CLK("omap_rng",	"ick",		&rng_ick,	CK_242X),
-	CLK(NULL,	"aes_ick",	&aes_ick,	CK_242X),
+	CLK("omap-aes",	"ick",	&aes_ick,	CK_242X),
 	CLK(NULL,	"pka_ick",	&pka_ick,	CK_242X),
 	CLK(NULL,	"usb_fck",	&usb_fck,	CK_242X),
 	CLK("musb_hdrc",	"fck",	&osc_ck,	CK_242X),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock2430_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock2430_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock2430_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock2430_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include "prm-regbits-24xx.h"
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define OMAP_CM_REGADDR			OMAP2430_CM_REGADDR
 
@@ -89,6 +90,12 @@
 	.clkdm_name	= "wkup_clkdm",
 };
 
+/* Optional external clock input for McBSP CLKS */
+static struct clk mcbsp_clks = {
+	.name		= "mcbsp_clks",
+	.ops		= &clkops_null,
+};
+
 /*
  * Analog domain root source clocks
  */
@@ -1123,14 +1130,34 @@
 	.recalc		= &followparent_recalc,
 };
 
+static const struct clksel_rate common_mcbsp_96m_rates[] = {
+	{ .div = 1, .val = 0, .flags = RATE_IN_24XX },
+	{ .div = 0 }
+};
+
+static const struct clksel_rate common_mcbsp_mcbsp_rates[] = {
+	{ .div = 1, .val = 1, .flags = RATE_IN_24XX },
+	{ .div = 0 }
+};
+
+static const struct clksel mcbsp_fck_clksel[] = {
+	{ .parent = &func_96m_ck,  .rates = common_mcbsp_96m_rates },
+	{ .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
+	{ .parent = NULL }
+};
+
 static struct clk mcbsp1_fck = {
 	.name		= "mcbsp1_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_MCBSP1_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+	.clksel_mask	= OMAP2_MCBSP1_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp2_ick = {
@@ -1147,10 +1174,14 @@
 	.name		= "mcbsp2_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
 	.enable_bit	= OMAP24XX_EN_MCBSP2_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP243X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+	.clksel_mask	= OMAP2_MCBSP2_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp3_ick = {
@@ -1167,10 +1198,14 @@
 	.name		= "mcbsp3_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
 	.enable_bit	= OMAP2430_EN_MCBSP3_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+	.clksel_mask	= OMAP2_MCBSP3_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp4_ick = {
@@ -1187,10 +1222,14 @@
 	.name		= "mcbsp4_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
 	.enable_bit	= OMAP2430_EN_MCBSP4_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+	.clksel_mask	= OMAP2_MCBSP4_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcbsp5_ick = {
@@ -1207,10 +1246,14 @@
 	.name		= "mcbsp5_fck",
 	.ops		= &clkops_omap2_dflt_wait,
 	.parent		= &func_96m_ck,
+	.init		= &omap2_init_clksel_parent,
 	.clkdm_name	= "core_l4_clkdm",
 	.enable_reg	= OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
 	.enable_bit	= OMAP2430_EN_MCBSP5_SHIFT,
-	.recalc		= &followparent_recalc,
+	.clksel_reg	= OMAP243X_CTRL_REGADDR(OMAP243X_CONTROL_DEVCONF1),
+	.clksel_mask	= OMAP2_MCBSP5_CLKS_MASK,
+	.clksel		= mcbsp_fck_clksel,
+	.recalc		= &omap2_clksel_recalc,
 };
 
 static struct clk mcspi1_ick = {
@@ -1808,6 +1851,12 @@
 	CLK(NULL,	"osc_ck",	&osc_ck,	CK_243X),
 	CLK(NULL,	"sys_ck",	&sys_ck,	CK_243X),
 	CLK(NULL,	"alt_ck",	&alt_ck,	CK_243X),
+	CLK("omap-mcbsp.1",	"pad_fck",	&mcbsp_clks,	CK_243X),
+	CLK("omap-mcbsp.2",	"pad_fck",	&mcbsp_clks,	CK_243X),
+	CLK("omap-mcbsp.3",	"pad_fck",	&mcbsp_clks,	CK_243X),
+	CLK("omap-mcbsp.4",	"pad_fck",	&mcbsp_clks,	CK_243X),
+	CLK("omap-mcbsp.5",	"pad_fck",	&mcbsp_clks,	CK_243X),
+	CLK(NULL,	"mcbsp_clks",	&mcbsp_clks,	CK_243X),
 	/* internal analog sources */
 	CLK(NULL,	"dpll_ck",	&dpll_ck,	CK_243X),
 	CLK(NULL,	"apll96_ck",	&apll96_ck,	CK_243X),
@@ -1815,6 +1864,11 @@
 	/* internal prcm root sources */
 	CLK(NULL,	"func_54m_ck",	&func_54m_ck,	CK_243X),
 	CLK(NULL,	"core_ck",	&core_ck,	CK_243X),
+	CLK("omap-mcbsp.1",	"prcm_fck",	&func_96m_ck,	CK_243X),
+	CLK("omap-mcbsp.2",	"prcm_fck",	&func_96m_ck,	CK_243X),
+	CLK("omap-mcbsp.3",	"prcm_fck",	&func_96m_ck,	CK_243X),
+	CLK("omap-mcbsp.4",	"prcm_fck",	&func_96m_ck,	CK_243X),
+	CLK("omap-mcbsp.5",	"prcm_fck",	&func_96m_ck,	CK_243X),
 	CLK(NULL,	"func_96m_ck",	&func_96m_ck,	CK_243X),
 	CLK(NULL,	"func_48m_ck",	&func_48m_ck,	CK_243X),
 	CLK(NULL,	"func_12m_ck",	&func_12m_ck,	CK_243X),
@@ -1926,7 +1980,7 @@
 	CLK(NULL,	"des_ick",	&des_ick,	CK_243X),
 	CLK("omap-sham",	"ick",	&sha_ick,	CK_243X),
 	CLK("omap_rng",	"ick",		&rng_ick,	CK_243X),
-	CLK(NULL,	"aes_ick",	&aes_ick,	CK_243X),
+	CLK("omap-aes",	"ick",	&aes_ick,	CK_243X),
 	CLK(NULL,	"pka_ick",	&pka_ick,	CK_243X),
 	CLK(NULL,	"usb_fck",	&usb_fck,	CK_243X),
 	CLK("musb_hdrc",	"ick",	&usbhs_ick,	CK_243X),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock3xxx_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock3xxx_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock3xxx_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock3xxx_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/list.h>
 
-#include <plat/control.h>
 #include <plat/clkdev_omap.h>
 
 #include "clock.h"
@@ -33,6 +32,7 @@
 #include "cm-regbits-34xx.h"
 #include "prm.h"
 #include "prm-regbits-34xx.h"
+#include "control.h"
 
 /*
  * clocks
@@ -2465,6 +2465,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk uart4_fck = {
+	.name		= "uart4_fck",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &per_48m_fck,
+	.enable_reg	= OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+	.enable_bit	= OMAP3630_EN_UART4_SHIFT,
+	.clkdm_name	= "per_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpt2_fck = {
 	.name		= "gpt2_fck",
 	.ops		= &clkops_omap2_dflt_wait,
@@ -2715,6 +2725,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk uart4_ick = {
+	.name		= "uart4_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &per_l4_ick,
+	.enable_reg	= OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+	.enable_bit	= OMAP3630_EN_UART4_SHIFT,
+	.clkdm_name	= "per_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpt9_ick = {
 	.name		= "gpt9_ick",
 	.ops		= &clkops_omap2_dflt_wait,
@@ -3188,6 +3208,11 @@
 	CLK(NULL,	"osc_sys_ck",	&osc_sys_ck,	CK_3XXX),
 	CLK(NULL,	"sys_ck",	&sys_ck,	CK_3XXX),
 	CLK(NULL,	"sys_altclk",	&sys_altclk,	CK_3XXX),
+	CLK("omap-mcbsp.1",	"pad_fck",	&mcbsp_clks,	CK_3XXX),
+	CLK("omap-mcbsp.2",	"pad_fck",	&mcbsp_clks,	CK_3XXX),
+	CLK("omap-mcbsp.3",	"pad_fck",	&mcbsp_clks,	CK_3XXX),
+	CLK("omap-mcbsp.4",	"pad_fck",	&mcbsp_clks,	CK_3XXX),
+	CLK("omap-mcbsp.5",	"pad_fck",	&mcbsp_clks,	CK_3XXX),
 	CLK(NULL,	"mcbsp_clks",	&mcbsp_clks,	CK_3XXX),
 	CLK(NULL,	"sys_clkout1",	&sys_clkout1,	CK_3XXX),
 	CLK(NULL,	"dpll1_ck",	&dpll1_ck,	CK_3XXX),
@@ -3253,6 +3278,8 @@
 	CLK(NULL,	"cpefuse_fck",	&cpefuse_fck,	CK_3430ES2 | CK_AM35XX),
 	CLK(NULL,	"ts_fck",	&ts_fck,	CK_3430ES2 | CK_AM35XX),
 	CLK(NULL,	"usbtll_fck",	&usbtll_fck,	CK_3430ES2 | CK_AM35XX),
+	CLK("omap-mcbsp.1",	"prcm_fck",	&core_96m_fck,	CK_3XXX),
+	CLK("omap-mcbsp.5",	"prcm_fck",	&core_96m_fck,	CK_3XXX),
 	CLK(NULL,	"core_96m_fck",	&core_96m_fck,	CK_3XXX),
 	CLK("mmci-omap-hs.2",	"fck",	&mmchs3_fck,	CK_3430ES2 | CK_AM35XX),
 	CLK("mmci-omap-hs.1",	"fck",	&mmchs2_fck,	CK_3XXX),
@@ -3288,7 +3315,7 @@
 	CLK(NULL,	"usbtll_ick",	&usbtll_ick,	CK_3430ES2 | CK_AM35XX),
 	CLK("mmci-omap-hs.2",	"ick",	&mmchs3_ick,	CK_3430ES2 | CK_AM35XX),
 	CLK(NULL,	"icr_ick",	&icr_ick,	CK_343X),
-	CLK(NULL,	"aes2_ick",	&aes2_ick,	CK_343X),
+	CLK("omap-aes",	"ick",	&aes2_ick,	CK_343X),
 	CLK("omap-sham",	"ick",	&sha12_ick,	CK_343X),
 	CLK(NULL,	"des2_ick",	&des2_ick,	CK_343X),
 	CLK("mmci-omap-hs.1",	"ick",	&mmchs2_ick,	CK_3XXX),
@@ -3346,9 +3373,13 @@
 	CLK(NULL,	"omap_32ksync_ick", &omap_32ksync_ick, CK_3XXX),
 	CLK(NULL,	"gpt12_ick",	&gpt12_ick,	CK_3XXX),
 	CLK(NULL,	"gpt1_ick",	&gpt1_ick,	CK_3XXX),
+	CLK("omap-mcbsp.2",	"prcm_fck",	&per_96m_fck,	CK_3XXX),
+	CLK("omap-mcbsp.3",	"prcm_fck",	&per_96m_fck,	CK_3XXX),
+	CLK("omap-mcbsp.4",	"prcm_fck",	&per_96m_fck,	CK_3XXX),
 	CLK(NULL,	"per_96m_fck",	&per_96m_fck,	CK_3XXX),
 	CLK(NULL,	"per_48m_fck",	&per_48m_fck,	CK_3XXX),
 	CLK(NULL,	"uart3_fck",	&uart3_fck,	CK_3XXX),
+	CLK(NULL,	"uart4_fck",	&uart4_fck,	CK_36XX),
 	CLK(NULL,	"gpt2_fck",	&gpt2_fck,	CK_3XXX),
 	CLK(NULL,	"gpt3_fck",	&gpt3_fck,	CK_3XXX),
 	CLK(NULL,	"gpt4_fck",	&gpt4_fck,	CK_3XXX),
@@ -3372,6 +3403,7 @@
 	CLK(NULL,	"gpio2_ick",	&gpio2_ick,	CK_3XXX),
 	CLK(NULL,	"wdt3_ick",	&wdt3_ick,	CK_3XXX),
 	CLK(NULL,	"uart3_ick",	&uart3_ick,	CK_3XXX),
+	CLK(NULL,	"uart4_ick",	&uart4_ick,	CK_36XX),
 	CLK(NULL,	"gpt9_ick",	&gpt9_ick,	CK_3XXX),
 	CLK(NULL,	"gpt8_ick",	&gpt8_ick,	CK_3XXX),
 	CLK(NULL,	"gpt7_ick",	&gpt7_ick,	CK_3XXX),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock44xx_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock44xx_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock44xx_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock44xx_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,13 +17,15 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * XXX Some of the ES1 clocks have been removed/changed; once support
+ * is added for discriminating clocks by ES level, these should be added back
+ * in.
  */
 
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/clk.h>
-
-#include <plat/control.h>
 #include <plat/clkdev_omap.h>
 
 #include "clock.h"
@@ -32,6 +34,7 @@
 #include "cm-regbits-44xx.h"
 #include "prm.h"
 #include "prm-regbits-44xx.h"
+#include "control.h"
 
 /* Root clocks */
 
@@ -175,21 +178,27 @@
 	.recalc		= &omap2_clksel_recalc,
 };
 
+static struct clk tie_low_clock_ck = {
+	.name		= "tie_low_clock_ck",
+	.rate		= 0,
+	.ops		= &clkops_null,
+};
+
 static struct clk utmi_phy_clkout_ck = {
 	.name		= "utmi_phy_clkout_ck",
-	.rate		= 12000000,
+	.rate		= 60000000,
 	.ops		= &clkops_null,
 };
 
 static struct clk xclk60mhsp1_ck = {
 	.name		= "xclk60mhsp1_ck",
-	.rate		= 12000000,
+	.rate		= 60000000,
 	.ops		= &clkops_null,
 };
 
 static struct clk xclk60mhsp2_ck = {
 	.name		= "xclk60mhsp2_ck",
-	.rate		= 12000000,
+	.rate		= 60000000,
 	.ops		= &clkops_null,
 };
 
@@ -201,39 +210,23 @@
 
 /* Module clocks and DPLL outputs */
 
-static const struct clksel_rate div2_1to2_rates[] = {
-	{ .div = 1, .val = 0, .flags = RATE_IN_4430 },
-	{ .div = 2, .val = 1, .flags = RATE_IN_4430 },
-	{ .div = 0 },
-};
-
-static const struct clksel dpll_sys_ref_clk_div[] = {
-	{ .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+static const struct clksel abe_dpll_bypass_clk_mux_sel[] = {
+	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
+	{ .parent = &sys_32k_ck, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
-static struct clk dpll_sys_ref_clk = {
-	.name		= "dpll_sys_ref_clk",
+static struct clk abe_dpll_bypass_clk_mux_ck = {
+	.name		= "abe_dpll_bypass_clk_mux_ck",
 	.parent		= &sys_clkin_ck,
-	.clksel		= dpll_sys_ref_clk_div,
-	.clksel_reg	= OMAP4430_CM_DPLL_SYS_REF_CLKSEL,
-	.clksel_mask	= OMAP4430_CLKSEL_0_0_MASK,
 	.ops		= &clkops_null,
-	.recalc		= &omap2_clksel_recalc,
-	.round_rate	= &omap2_clksel_round_rate,
-	.set_rate	= &omap2_clksel_set_rate,
-};
-
-static const struct clksel abe_dpll_refclk_mux_sel[] = {
-	{ .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
-	{ .parent = &sys_32k_ck, .rates = div_1_1_rates },
-	{ .parent = NULL },
+	.recalc		= &followparent_recalc,
 };
 
 static struct clk abe_dpll_refclk_mux_ck = {
 	.name		= "abe_dpll_refclk_mux_ck",
-	.parent		= &dpll_sys_ref_clk,
-	.clksel		= abe_dpll_refclk_mux_sel,
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP4430_CM_ABE_PLL_REF_CLKSEL,
 	.clksel_mask	= OMAP4430_CLKSEL_0_0_MASK,
@@ -244,7 +237,7 @@
 /* DPLL_ABE */
 static struct dpll_data dpll_abe_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_ABE,
-	.clk_bypass	= &sys_clkin_ck,
+	.clk_bypass	= &abe_dpll_bypass_clk_mux_ck,
 	.clk_ref	= &abe_dpll_refclk_mux_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_ABE,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
@@ -310,6 +303,12 @@
 	.set_rate	= &omap2_clksel_set_rate,
 };
 
+static const struct clksel_rate div2_1to2_rates[] = {
+	{ .div = 1, .val = 0, .flags = RATE_IN_4430 },
+	{ .div = 2, .val = 1, .flags = RATE_IN_4430 },
+	{ .div = 0 },
+};
+
 static const struct clksel aess_fclk_div[] = {
 	{ .parent = &abe_clk, .rates = div2_1to2_rates },
 	{ .parent = NULL },
@@ -380,14 +379,14 @@
 };
 
 static const struct clksel core_hsd_byp_clk_mux_sel[] = {
-	{ .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
 	{ .parent = &dpll_abe_m3_ck, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
 static struct clk core_hsd_byp_clk_mux_ck = {
 	.name		= "core_hsd_byp_clk_mux_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.clksel		= core_hsd_byp_clk_mux_sel,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP4430_CM_CLKSEL_DPLL_CORE,
@@ -400,7 +399,7 @@
 static struct dpll_data dpll_core_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_CORE,
 	.clk_bypass	= &core_hsd_byp_clk_mux_ck,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_CORE,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_CORE,
@@ -418,7 +417,7 @@
 
 static struct clk dpll_core_ck = {
 	.name		= "dpll_core_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_core_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_null,
@@ -596,14 +595,14 @@
 };
 
 static const struct clksel iva_hsd_byp_clk_mux_sel[] = {
-	{ .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
 	{ .parent = &div_iva_hs_clk, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
 static struct clk iva_hsd_byp_clk_mux_ck = {
 	.name		= "iva_hsd_byp_clk_mux_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.ops		= &clkops_null,
 	.recalc		= &followparent_recalc,
 };
@@ -612,7 +611,7 @@
 static struct dpll_data dpll_iva_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_IVA,
 	.clk_bypass	= &iva_hsd_byp_clk_mux_ck,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_IVA,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_IVA,
@@ -630,7 +629,7 @@
 
 static struct clk dpll_iva_ck = {
 	.name		= "dpll_iva_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_iva_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_omap3_noncore_dpll_ops,
@@ -672,7 +671,7 @@
 static struct dpll_data dpll_mpu_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_MPU,
 	.clk_bypass	= &div_mpu_hs_clk,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_MPU,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_MPU,
@@ -690,7 +689,7 @@
 
 static struct clk dpll_mpu_ck = {
 	.name		= "dpll_mpu_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_mpu_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_omap3_noncore_dpll_ops,
@@ -724,14 +723,14 @@
 };
 
 static const struct clksel per_hsd_byp_clk_mux_sel[] = {
-	{ .parent = &dpll_sys_ref_clk, .rates = div_1_0_rates },
+	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
 	{ .parent = &per_hs_clk_div_ck, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
 static struct clk per_hsd_byp_clk_mux_ck = {
 	.name		= "per_hsd_byp_clk_mux_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.clksel		= per_hsd_byp_clk_mux_sel,
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP4430_CM_CLKSEL_DPLL_PER,
@@ -744,7 +743,7 @@
 static struct dpll_data dpll_per_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_PER,
 	.clk_bypass	= &per_hsd_byp_clk_mux_ck,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_PER,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_PER,
@@ -762,7 +761,7 @@
 
 static struct clk dpll_per_ck = {
 	.name		= "dpll_per_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_per_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_omap3_noncore_dpll_ops,
@@ -858,8 +857,8 @@
 /* DPLL_UNIPRO */
 static struct dpll_data dpll_unipro_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_UNIPRO,
-	.clk_bypass	= &dpll_sys_ref_clk,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.clk_bypass	= &sys_clkin_ck,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_UNIPRO,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_UNIPRO,
@@ -877,7 +876,7 @@
 
 static struct clk dpll_unipro_ck = {
 	.name		= "dpll_unipro_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_unipro_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_omap3_noncore_dpll_ops,
@@ -914,7 +913,8 @@
 static struct dpll_data dpll_usb_dd = {
 	.mult_div1_reg	= OMAP4430_CM_CLKSEL_DPLL_USB,
 	.clk_bypass	= &usb_hs_clk_div_ck,
-	.clk_ref	= &dpll_sys_ref_clk,
+	.flags		= DPLL_J_TYPE | DPLL_NO_DCO_SEL,
+	.clk_ref	= &sys_clkin_ck,
 	.control_reg	= OMAP4430_CM_CLKMODE_DPLL_USB,
 	.modes		= (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
 	.autoidle_reg	= OMAP4430_CM_AUTOIDLE_DPLL_USB,
@@ -927,13 +927,12 @@
 	.max_multiplier	= OMAP4430_MAX_DPLL_MULT,
 	.max_divider	= OMAP4430_MAX_DPLL_DIV,
 	.min_divider	= 1,
-	.flags		= DPLL_J_TYPE | DPLL_NO_DCO_SEL
 };
 
 
 static struct clk dpll_usb_ck = {
 	.name		= "dpll_usb_ck",
-	.parent		= &dpll_sys_ref_clk,
+	.parent		= &sys_clkin_ck,
 	.dpll_data	= &dpll_usb_dd,
 	.init		= &omap2_init_dpll_parent,
 	.ops		= &clkops_omap3_noncore_dpll_ops,
@@ -1222,7 +1221,7 @@
 static const struct clksel pmd_stm_clock_mux_sel[] = {
 	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
 	{ .parent = &dpll_core_m6_ck, .rates = div_1_1_rates },
-	{ .parent = &dpll_per_m7_ck, .rates = div_1_2_rates },
+	{ .parent = &tie_low_clock_ck, .rates = div_1_2_rates },
 	{ .parent = NULL },
 };
 
@@ -1240,10 +1239,15 @@
 	.recalc		= &followparent_recalc,
 };
 
+static const struct clksel syc_clk_div_div[] = {
+	{ .parent = &sys_clkin_ck, .rates = div2_1to2_rates },
+	{ .parent = NULL },
+};
+
 static struct clk syc_clk_div_ck = {
 	.name		= "syc_clk_div_ck",
 	.parent		= &sys_clkin_ck,
-	.clksel		= dpll_sys_ref_clk_div,
+	.clksel		= syc_clk_div_div,
 	.clksel_reg	= OMAP4430_CM_ABE_DSS_SYS_CLKSEL,
 	.clksel_mask	= OMAP4430_CLKSEL_0_0_MASK,
 	.ops		= &clkops_null,
@@ -1284,13 +1288,13 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk cust_efuse_fck = {
-	.name		= "cust_efuse_fck",
+static struct clk bandgap_fclk = {
+	.name		= "bandgap_fclk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_cefuse_clkdm",
-	.parent		= &sys_clkin_ck,
+	.enable_reg	= OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.parent		= &sys_32k_ck,
 	.recalc		= &followparent_recalc,
 };
 
@@ -1344,6 +1348,56 @@
 	.clkdm_name	= "abe_clkdm",
 };
 
+static struct clk dsp_fck = {
+	.name		= "dsp_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_TESLA_TESLA_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "tesla_clkdm",
+	.parent		= &dpll_iva_m4_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dss_sys_clk = {
+	.name		= "dss_sys_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_DSS_DSS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT,
+	.clkdm_name	= "l3_dss_clkdm",
+	.parent		= &syc_clk_div_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dss_tv_clk = {
+	.name		= "dss_tv_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_DSS_DSS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_TV_CLK_SHIFT,
+	.clkdm_name	= "l3_dss_clkdm",
+	.parent		= &extalt_clkin_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dss_dss_clk = {
+	.name		= "dss_dss_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_DSS_DSS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DSSCLK_SHIFT,
+	.clkdm_name	= "l3_dss_clkdm",
+	.parent		= &dpll_per_m5_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dss_48mhz_clk = {
+	.name		= "dss_48mhz_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_DSS_DSS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT,
+	.clkdm_name	= "l3_dss_clkdm",
+	.parent		= &func_48mc_fclk,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk dss_fck = {
 	.name		= "dss_fck",
 	.ops		= &clkops_omap2_dflt,
@@ -1354,18 +1408,18 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk ducati_ick = {
-	.name		= "ducati_ick",
+static struct clk efuse_ctrl_cust_fck = {
+	.name		= "efuse_ctrl_cust_fck",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
-	.clkdm_name	= "ducati_clkdm",
-	.parent		= &ducati_clk_mux_ck,
+	.enable_reg	= OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_cefuse_clkdm",
+	.parent		= &sys_clkin_ck,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk emif1_ick = {
-	.name		= "emif1_ick",
+static struct clk emif1_fck = {
+	.name		= "emif1_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -1375,8 +1429,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk emif2_ick = {
-	.name		= "emif2_ick",
+static struct clk emif2_fck = {
+	.name		= "emif2_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -1407,42 +1461,24 @@
 	.clkdm_name	= "iss_clkdm",
 };
 
-static const struct clksel per_sgx_fclk_div[] = {
-	{ .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
-	{ .parent = NULL },
-};
-
-static struct clk per_sgx_fclk = {
-	.name		= "per_sgx_fclk",
-	.parent		= &dpll_per_m2x2_ck,
-	.clksel		= per_sgx_fclk_div,
-	.clksel_reg	= OMAP4430_CM_GFX_GFX_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_PER_192M_MASK,
-	.ops		= &clkops_null,
-	.recalc		= &omap2_clksel_recalc,
-	.round_rate	= &omap2_clksel_round_rate,
-	.set_rate	= &omap2_clksel_set_rate,
-};
-
-static const struct clksel sgx_clk_mux_sel[] = {
-	{ .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
-	{ .parent = &per_sgx_fclk, .rates = div_1_1_rates },
-	{ .parent = NULL },
+static struct clk fpka_fck = {
+	.name		= "fpka_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_secure_clkdm",
+	.parent		= &l4_div_ck,
+	.recalc		= &followparent_recalc,
 };
 
-/* Merged sgx_clk_mux into gfx */
-static struct clk gfx_fck = {
-	.name		= "gfx_fck",
-	.parent		= &dpll_core_m7_ck,
-	.clksel		= sgx_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_GFX_GFX_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_SGX_FCLK_MASK,
+static struct clk gpio1_dbclk = {
+	.name		= "gpio1_dbclk",
 	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_GFX_GFX_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l3_gfx_clkdm",
+	.enable_reg	= OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
 };
 
 static struct clk gpio1_ick = {
@@ -1455,6 +1491,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpio2_dbclk = {
+	.name		= "gpio2_dbclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_GPIO2_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpio2_ick = {
 	.name		= "gpio2_ick",
 	.ops		= &clkops_omap2_dflt,
@@ -1465,6 +1511,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpio3_dbclk = {
+	.name		= "gpio3_dbclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpio3_ick = {
 	.name		= "gpio3_ick",
 	.ops		= &clkops_omap2_dflt,
@@ -1475,6 +1531,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpio4_dbclk = {
+	.name		= "gpio4_dbclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_GPIO4_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpio4_ick = {
 	.name		= "gpio4_ick",
 	.ops		= &clkops_omap2_dflt,
@@ -1485,6 +1551,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpio5_dbclk = {
+	.name		= "gpio5_dbclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_GPIO5_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpio5_ick = {
 	.name		= "gpio5_ick",
 	.ops		= &clkops_omap2_dflt,
@@ -1495,6 +1571,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk gpio6_dbclk = {
+	.name		= "gpio6_dbclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_GPIO6_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpio6_ick = {
 	.name		= "gpio6_ick",
 	.ops		= &clkops_omap2_dflt,
@@ -1515,214 +1601,25 @@
 	.recalc		= &followparent_recalc,
 };
 
-static const struct clksel dmt1_clk_mux_sel[] = {
-	{ .parent = &sys_clkin_ck, .rates = div_1_0_rates },
-	{ .parent = &sys_32k_ck, .rates = div_1_1_rates },
-	{ .parent = NULL },
-};
-
-/*
- * Merged dmt1_clk_mux into gptimer1
- * gptimer1 renamed temporarily into gpt1 to match OMAP3 convention
- */
-static struct clk gpt1_fck = {
-	.name		= "gpt1_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_wkup_clkdm",
-};
-
-/*
- * Merged cm2_dm10_mux into gptimer10
- * gptimer10 renamed temporarily into gpt10 to match OMAP3 convention
- */
-static struct clk gpt10_fck = {
-	.name		= "gpt10_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm11_mux into gptimer11
- * gptimer11 renamed temporarily into gpt11 to match OMAP3 convention
- */
-static struct clk gpt11_fck = {
-	.name		= "gpt11_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm2_mux into gptimer2
- * gptimer2 renamed temporarily into gpt2 to match OMAP3 convention
- */
-static struct clk gpt2_fck = {
-	.name		= "gpt2_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm3_mux into gptimer3
- * gptimer3 renamed temporarily into gpt3 to match OMAP3 convention
- */
-static struct clk gpt3_fck = {
-	.name		= "gpt3_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
-};
-
-/*
- * Merged cm2_dm4_mux into gptimer4
- * gptimer4 renamed temporarily into gpt4 to match OMAP3 convention
- */
-static struct clk gpt4_fck = {
-	.name		= "gpt4_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
-};
-
-static const struct clksel timer5_sync_mux_sel[] = {
-	{ .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
-	{ .parent = &sys_32k_ck, .rates = div_1_1_rates },
+static const struct clksel sgx_clk_mux_sel[] = {
+	{ .parent = &dpll_core_m7_ck, .rates = div_1_0_rates },
+	{ .parent = &dpll_per_m7_ck, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
-/*
- * Merged timer5_sync_mux into gptimer5
- * gptimer5 renamed temporarily into gpt5 to match OMAP3 convention
- */
-static struct clk gpt5_fck = {
-	.name		= "gpt5_fck",
-	.parent		= &syc_clk_div_ck,
-	.clksel		= timer5_sync_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-};
-
-/*
- * Merged timer6_sync_mux into gptimer6
- * gptimer6 renamed temporarily into gpt6 to match OMAP3 convention
- */
-static struct clk gpt6_fck = {
-	.name		= "gpt6_fck",
-	.parent		= &syc_clk_div_ck,
-	.clksel		= timer5_sync_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-};
-
-/*
- * Merged timer7_sync_mux into gptimer7
- * gptimer7 renamed temporarily into gpt7 to match OMAP3 convention
- */
-static struct clk gpt7_fck = {
-	.name		= "gpt7_fck",
-	.parent		= &syc_clk_div_ck,
-	.clksel		= timer5_sync_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-};
-
-/*
- * Merged timer8_sync_mux into gptimer8
- * gptimer8 renamed temporarily into gpt8 to match OMAP3 convention
- */
-static struct clk gpt8_fck = {
-	.name		= "gpt8_fck",
-	.parent		= &syc_clk_div_ck,
-	.clksel		= timer5_sync_mux_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
-	.ops		= &clkops_omap2_dflt,
-	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-};
-
-/*
- * Merged cm2_dm9_mux into gptimer9
- * gptimer9 renamed temporarily into gpt9 to match OMAP3 convention
- */
-static struct clk gpt9_fck = {
-	.name		= "gpt9_fck",
-	.parent		= &sys_clkin_ck,
-	.clksel		= dmt1_clk_mux_sel,
+/* Merged sgx_clk_mux into gpu */
+static struct clk gpu_fck = {
+	.name		= "gpu_fck",
+	.parent		= &dpll_core_m7_ck,
+	.clksel		= sgx_clk_mux_sel,
 	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.clksel_reg	= OMAP4430_CM_GFX_GFX_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_SGX_FCLK_MASK,
 	.ops		= &clkops_omap2_dflt,
 	.recalc		= &omap2_clksel_recalc,
-	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+	.enable_reg	= OMAP4430_CM_GFX_GFX_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_per_clkdm",
+	.clkdm_name	= "l3_gfx_clkdm",
 };
 
 static struct clk hdq1w_fck = {
@@ -1735,11 +1632,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static const struct clksel hsi_fclk_div[] = {
+	{ .parent = &dpll_per_m2x2_ck, .rates = div3_1to4_rates },
+	{ .parent = NULL },
+};
+
 /* Merged hsi_fclk into hsi */
-static struct clk hsi_ick = {
-	.name		= "hsi_ick",
+static struct clk hsi_fck = {
+	.name		= "hsi_fck",
 	.parent		= &dpll_per_m2x2_ck,
-	.clksel		= per_sgx_fclk_div,
+	.clksel		= hsi_fclk_div,
 	.clksel_reg	= OMAP4430_CM_L3INIT_HSI_CLKCTRL,
 	.clksel_mask	= OMAP4430_CLKSEL_24_25_MASK,
 	.ops		= &clkops_omap2_dflt,
@@ -1791,6 +1693,26 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk ipu_fck = {
+	.name		= "ipu_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_DUCATI_DUCATI_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "ducati_clkdm",
+	.parent		= &ducati_clk_mux_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk iss_ctrlclk = {
+	.name		= "iss_ctrlclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_CAM_ISS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT,
+	.clkdm_name	= "iss_clkdm",
+	.parent		= &func_96m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk iss_fck = {
 	.name		= "iss_fck",
 	.ops		= &clkops_omap2_dflt,
@@ -1801,8 +1723,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk ivahd_ick = {
-	.name		= "ivahd_ick",
+static struct clk iva_fck = {
+	.name		= "iva_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_IVAHD_IVAHD_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -1811,8 +1733,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk keyboard_fck = {
-	.name		= "keyboard_fck",
+static struct clk kbd_fck = {
+	.name		= "kbd_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_WKUP_KEYBOARD_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
@@ -1821,8 +1743,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk l3_instr_interconnect_ick = {
-	.name		= "l3_instr_interconnect_ick",
+static struct clk l3_instr_ick = {
+	.name		= "l3_instr_ick",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -1831,8 +1753,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk l3_interconnect_3_ick = {
-	.name		= "l3_interconnect_3_ick",
+static struct clk l3_main_3_ick = {
+	.name		= "l3_main_3_ick",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_L3INSTR_L3_3_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -2005,6 +1927,16 @@
 	.clkdm_name	= "l4_per_clkdm",
 };
 
+static struct clk mcpdm_fck = {
+	.name		= "mcpdm_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_PDM_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &pad_clks_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk mcspi1_fck = {
 	.name		= "mcspi1_fck",
 	.ops		= &clkops_omap2_dflt,
@@ -2105,33 +2037,33 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk ocp_wp1_ick = {
-	.name		= "ocp_wp1_ick",
+static struct clk ocp2scp_usb_phy_phy_48m = {
+	.name		= "ocp2scp_usb_phy_phy_48m",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
-	.clkdm_name	= "l3_instr_clkdm",
-	.parent		= &l3_div_ck,
+	.enable_reg	= OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_PHY_48M_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &func_48m_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk pdm_fck = {
-	.name		= "pdm_fck",
+static struct clk ocp2scp_usb_phy_ick = {
+	.name		= "ocp2scp_usb_phy_ick",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM1_ABE_PDM_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-	.parent		= &pad_clks_ck,
+	.enable_reg	= OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &l4_div_ck,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk pkaeip29_fck = {
-	.name		= "pkaeip29_fck",
+static struct clk ocp_wp_noc_ick = {
+	.name		= "ocp_wp_noc_ick",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L4SEC_PKAEIP29_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_secure_clkdm",
-	.parent		= &l4_div_ck,
+	.enable_reg	= OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "l3_instr_clkdm",
+	.parent		= &l3_div_ck,
 	.recalc		= &followparent_recalc,
 };
 
@@ -2145,8 +2077,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk sha2md51_fck = {
-	.name		= "sha2md51_fck",
+static struct clk sha2md5_fck = {
+	.name		= "sha2md5_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
@@ -2155,8 +2087,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk sl2_ick = {
-	.name		= "sl2_ick",
+static struct clk sl2if_ick = {
+	.name		= "sl2if_ick",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_IVAHD_SL2_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
@@ -2165,6 +2097,46 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk slimbus1_fclk_1 = {
+	.name		= "slimbus1_fclk_1",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_FCLK1_SHIFT,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &func_24m_clk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk slimbus1_fclk_0 = {
+	.name		= "slimbus1_fclk_0",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_FCLK0_SHIFT,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &abe_24m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk slimbus1_fclk_2 = {
+	.name		= "slimbus1_fclk_2",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_FCLK2_SHIFT,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &pad_clks_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk slimbus1_slimbus_clk = {
+	.name		= "slimbus1_slimbus_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &slimbus_clk,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk slimbus1_fck = {
 	.name		= "slimbus1_fck",
 	.ops		= &clkops_omap2_dflt,
@@ -2175,6 +2147,36 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk slimbus2_fclk_1 = {
+	.name		= "slimbus2_fclk_1",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &per_abe_24m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk slimbus2_fclk_0 = {
+	.name		= "slimbus2_fclk_0",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &func_24mc_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk slimbus2_slimbus_clk = {
+	.name		= "slimbus2_slimbus_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT,
+	.clkdm_name	= "l4_per_clkdm",
+	.parent		= &pad_slimbus_core_clks_ck,
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk slimbus2_fck = {
 	.name		= "slimbus2_fck",
 	.ops		= &clkops_omap2_dflt,
@@ -2185,8 +2187,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk sr_core_fck = {
-	.name		= "sr_core_fck",
+static struct clk smartreflex_core_fck = {
+	.name		= "smartreflex_core_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
@@ -2195,8 +2197,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk sr_iva_fck = {
-	.name		= "sr_iva_fck",
+static struct clk smartreflex_iva_fck = {
+	.name		= "smartreflex_iva_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
@@ -2205,8 +2207,8 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk sr_mpu_fck = {
-	.name		= "sr_mpu_fck",
+static struct clk smartreflex_mpu_fck = {
+	.name		= "smartreflex_mpu_fck",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
@@ -2215,14 +2217,175 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk tesla_ick = {
-	.name		= "tesla_ick",
+/* Merged dmt1_clk_mux into timer1 */
+static struct clk timer1_fck = {
+	.name		= "timer1_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_TESLA_TESLA_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
-	.clkdm_name	= "tesla_clkdm",
-	.parent		= &dpll_iva_m4_ck,
-	.recalc		= &followparent_recalc,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_WKUP_TIMER1_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_wkup_clkdm",
+};
+
+/* Merged cm2_dm10_mux into timer10 */
+static struct clk timer10_fck = {
+	.name		= "timer10_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
+};
+
+/* Merged cm2_dm11_mux into timer11 */
+static struct clk timer11_fck = {
+	.name		= "timer11_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
+};
+
+/* Merged cm2_dm2_mux into timer2 */
+static struct clk timer2_fck = {
+	.name		= "timer2_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
+};
+
+/* Merged cm2_dm3_mux into timer3 */
+static struct clk timer3_fck = {
+	.name		= "timer3_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
+};
+
+/* Merged cm2_dm4_mux into timer4 */
+static struct clk timer4_fck = {
+	.name		= "timer4_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
+};
+
+static const struct clksel timer5_sync_mux_sel[] = {
+	{ .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
+	{ .parent = &sys_32k_ck, .rates = div_1_1_rates },
+	{ .parent = NULL },
+};
+
+/* Merged timer5_sync_mux into timer5 */
+static struct clk timer5_fck = {
+	.name		= "timer5_fck",
+	.parent		= &syc_clk_div_ck,
+	.clksel		= timer5_sync_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM1_ABE_TIMER5_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+};
+
+/* Merged timer6_sync_mux into timer6 */
+static struct clk timer6_fck = {
+	.name		= "timer6_fck",
+	.parent		= &syc_clk_div_ck,
+	.clksel		= timer5_sync_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM1_ABE_TIMER6_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+};
+
+/* Merged timer7_sync_mux into timer7 */
+static struct clk timer7_fck = {
+	.name		= "timer7_fck",
+	.parent		= &syc_clk_div_ck,
+	.clksel		= timer5_sync_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM1_ABE_TIMER7_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+};
+
+/* Merged timer8_sync_mux into timer8 */
+static struct clk timer8_fck = {
+	.name		= "timer8_fck",
+	.parent		= &syc_clk_div_ck,
+	.clksel		= timer5_sync_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM1_ABE_TIMER8_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+};
+
+/* Merged cm2_dm9_mux into timer9 */
+static struct clk timer9_fck = {
+	.name		= "timer9_fck",
+	.parent		= &sys_clkin_ck,
+	.clksel		= abe_dpll_bypass_clk_mux_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_MASK,
+	.ops		= &clkops_omap2_dflt,
+	.recalc		= &omap2_clksel_recalc,
+	.enable_reg	= OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_per_clkdm",
 };
 
 static struct clk uart1_fck = {
@@ -2265,105 +2428,148 @@
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk unipro1_fck = {
-	.name		= "unipro1_fck",
+static struct clk usb_host_fs_fck = {
+	.name		= "usb_host_fs_fck",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INIT_UNIPRO1_CLKCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
 	.clkdm_name	= "l3_init_clkdm",
-	.parent		= &func_96m_fclk,
+	.parent		= &func_48mc_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usb_host_fck = {
-	.name		= "usb_host_fck",
+static struct clk usb_host_hs_utmi_p3_clk = {
+	.name		= "usb_host_hs_utmi_p3_clk",
 	.ops		= &clkops_omap2_dflt,
 	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT,
 	.clkdm_name	= "l3_init_clkdm",
 	.parent		= &init_60m_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usb_host_fs_fck = {
-	.name		= "usb_host_fs_fck",
+static struct clk usb_host_hs_hsic60m_p1_clk = {
+	.name		= "usb_host_hs_hsic60m_p1_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT,
 	.clkdm_name	= "l3_init_clkdm",
-	.parent		= &func_48mc_fclk,
+	.parent		= &init_60m_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usb_otg_ick = {
-	.name		= "usb_otg_ick",
+static struct clk usb_host_hs_hsic60m_p2_clk = {
+	.name		= "usb_host_hs_hsic60m_p2_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT,
 	.clkdm_name	= "l3_init_clkdm",
-	.parent		= &l3_div_ck,
+	.parent		= &init_60m_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usb_tll_ick = {
-	.name		= "usb_tll_ick",
+static const struct clksel utmi_p1_gfclk_sel[] = {
+	{ .parent = &init_60m_fclk, .rates = div_1_0_rates },
+	{ .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+	{ .parent = NULL },
+};
+
+static struct clk utmi_p1_gfclk = {
+	.name		= "utmi_p1_gfclk",
+	.parent		= &init_60m_fclk,
+	.clksel		= utmi_p1_gfclk_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_UTMI_P1_MASK,
+	.ops		= &clkops_null,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p1_clk = {
+	.name		= "usb_host_hs_utmi_p1_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT,
 	.clkdm_name	= "l3_init_clkdm",
-	.parent		= &l4_div_ck,
+	.parent		= &utmi_p1_gfclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usbphyocp2scp_ick = {
-	.name		= "usbphyocp2scp_ick",
+static const struct clksel utmi_p2_gfclk_sel[] = {
+	{ .parent = &init_60m_fclk, .rates = div_1_0_rates },
+	{ .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+	{ .parent = NULL },
+};
+
+static struct clk utmi_p2_gfclk = {
+	.name		= "utmi_p2_gfclk",
+	.parent		= &init_60m_fclk,
+	.clksel		= utmi_p2_gfclk_sel,
+	.init		= &omap2_init_clksel_parent,
+	.clksel_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_UTMI_P2_MASK,
+	.ops		= &clkops_null,
+	.recalc		= &omap2_clksel_recalc,
+};
+
+static struct clk usb_host_hs_utmi_p2_clk = {
+	.name		= "usb_host_hs_utmi_p2_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT,
 	.clkdm_name	= "l3_init_clkdm",
-	.parent		= &l4_div_ck,
+	.parent		= &utmi_p2_gfclk,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk usim_fck = {
-	.name		= "usim_fck",
+static struct clk usb_host_hs_hsic480m_p1_clk = {
+	.name		= "usb_host_hs_hsic480m_p1_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_WKUP_USIM_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.parent		= &sys_32k_ck,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &dpll_usb_m2_ck,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk wdt2_fck = {
-	.name		= "wdt2_fck",
+static struct clk usb_host_hs_hsic480m_p2_clk = {
+	.name		= "usb_host_hs_hsic480m_p2_clk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM_WKUP_WDT2_CLKCTRL,
-	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "l4_wkup_clkdm",
-	.parent		= &sys_32k_ck,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &dpll_usb_m2_ck,
 	.recalc		= &followparent_recalc,
 };
 
-static struct clk wdt3_fck = {
-	.name		= "wdt3_fck",
+static struct clk usb_host_hs_func48mclk = {
+	.name		= "usb_host_hs_func48mclk",
 	.ops		= &clkops_omap2_dflt,
-	.enable_reg	= OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &func_48mc_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk usb_host_hs_fck = {
+	.name		= "usb_host_hs_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
 	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
-	.clkdm_name	= "abe_clkdm",
-	.parent		= &sys_32k_ck,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &init_60m_fclk,
 	.recalc		= &followparent_recalc,
 };
 
-/* Remaining optional clocks */
 static const struct clksel otg_60m_gfclk_sel[] = {
 	{ .parent = &utmi_phy_clkout_ck, .rates = div_1_0_rates },
 	{ .parent = &xclk60motg_ck, .rates = div_1_1_rates },
 	{ .parent = NULL },
 };
 
-static struct clk otg_60m_gfclk_ck = {
-	.name		= "otg_60m_gfclk_ck",
+static struct clk otg_60m_gfclk = {
+	.name		= "otg_60m_gfclk",
 	.parent		= &utmi_phy_clkout_ck,
 	.clksel		= otg_60m_gfclk_sel,
 	.init		= &omap2_init_clksel_parent,
@@ -2373,38 +2579,74 @@
 	.recalc		= &omap2_clksel_recalc,
 };
 
-static const struct clksel stm_clk_div_div[] = {
-	{ .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
-	{ .parent = NULL },
+static struct clk usb_otg_hs_xclk = {
+	.name		= "usb_otg_hs_xclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_XCLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &otg_60m_gfclk,
+	.recalc		= &followparent_recalc,
 };
 
-static struct clk stm_clk_div_ck = {
-	.name		= "stm_clk_div_ck",
-	.parent		= &pmd_stm_clock_mux_ck,
-	.clksel		= stm_clk_div_div,
-	.clksel_reg	= OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
-	.ops		= &clkops_null,
-	.recalc		= &omap2_clksel_recalc,
-	.round_rate	= &omap2_clksel_round_rate,
-	.set_rate	= &omap2_clksel_set_rate,
+static struct clk usb_otg_hs_ick = {
+	.name		= "usb_otg_hs_ick",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &l3_div_ck,
+	.recalc		= &followparent_recalc,
 };
 
-static const struct clksel trace_clk_div_div[] = {
-	{ .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
-	{ .parent = NULL },
+static struct clk usb_phy_cm_clk32k = {
+	.name		= "usb_phy_cm_clk32k",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_ALWON_USBPHY_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_CLK32K_SHIFT,
+	.clkdm_name	= "l4_ao_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
 };
 
-static struct clk trace_clk_div_ck = {
-	.name		= "trace_clk_div_ck",
-	.parent		= &pmd_trace_clk_mux_ck,
-	.clksel		= trace_clk_div_div,
-	.clksel_reg	= OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
-	.ops		= &clkops_null,
-	.recalc		= &omap2_clksel_recalc,
-	.round_rate	= &omap2_clksel_round_rate,
-	.set_rate	= &omap2_clksel_set_rate,
+static struct clk usb_tll_hs_usb_ch2_clk = {
+	.name		= "usb_tll_hs_usb_ch2_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &init_60m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch0_clk = {
+	.name		= "usb_tll_hs_usb_ch0_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &init_60m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_usb_ch1_clk = {
+	.name		= "usb_tll_hs_usb_ch1_clk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &init_60m_fclk,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk usb_tll_hs_ick = {
+	.name		= "usb_tll_hs_ick",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "l3_init_clkdm",
+	.parent		= &l4_div_ck,
+	.recalc		= &followparent_recalc,
 };
 
 static const struct clksel_rate div2_14to18_rates[] = {
@@ -2418,8 +2660,8 @@
 	{ .parent = NULL },
 };
 
-static struct clk usim_fclk = {
-	.name		= "usim_fclk",
+static struct clk usim_ck = {
+	.name		= "usim_ck",
 	.parent		= &dpll_per_m4_ck,
 	.clksel		= usim_fclk_div,
 	.clksel_reg	= OMAP4430_CM_WKUP_USIM_CLKCTRL,
@@ -2430,38 +2672,79 @@
 	.set_rate	= &omap2_clksel_set_rate,
 };
 
-static const struct clksel utmi_p1_gfclk_sel[] = {
-	{ .parent = &init_60m_fclk, .rates = div_1_0_rates },
-	{ .parent = &xclk60mhsp1_ck, .rates = div_1_1_rates },
+static struct clk usim_fclk = {
+	.name		= "usim_fclk",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_WKUP_USIM_CLKCTRL,
+	.enable_bit	= OMAP4430_OPTFCLKEN_FCLK_SHIFT,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.parent		= &usim_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk usim_fck = {
+	.name		= "usim_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_WKUP_USIM_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_HWCTRL,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk wd_timer2_fck = {
+	.name		= "wd_timer2_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "l4_wkup_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk wd_timer3_fck = {
+	.name		= "wd_timer3_fck",
+	.ops		= &clkops_omap2_dflt,
+	.enable_reg	= OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+	.enable_bit	= OMAP4430_MODULEMODE_SWCTRL,
+	.clkdm_name	= "abe_clkdm",
+	.parent		= &sys_32k_ck,
+	.recalc		= &followparent_recalc,
+};
+
+/* Remaining optional clocks */
+static const struct clksel stm_clk_div_div[] = {
+	{ .parent = &pmd_stm_clock_mux_ck, .rates = div3_1to4_rates },
 	{ .parent = NULL },
 };
 
-static struct clk utmi_p1_gfclk_ck = {
-	.name		= "utmi_p1_gfclk_ck",
-	.parent		= &init_60m_fclk,
-	.clksel		= utmi_p1_gfclk_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_UTMI_P1_MASK,
+static struct clk stm_clk_div_ck = {
+	.name		= "stm_clk_div_ck",
+	.parent		= &pmd_stm_clock_mux_ck,
+	.clksel		= stm_clk_div_div,
+	.clksel_reg	= OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_PMD_STM_CLK_MASK,
 	.ops		= &clkops_null,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate,
+	.set_rate	= &omap2_clksel_set_rate,
 };
 
-static const struct clksel utmi_p2_gfclk_sel[] = {
-	{ .parent = &init_60m_fclk, .rates = div_1_0_rates },
-	{ .parent = &xclk60mhsp2_ck, .rates = div_1_1_rates },
+static const struct clksel trace_clk_div_div[] = {
+	{ .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
 	{ .parent = NULL },
 };
 
-static struct clk utmi_p2_gfclk_ck = {
-	.name		= "utmi_p2_gfclk_ck",
-	.parent		= &init_60m_fclk,
-	.clksel		= utmi_p2_gfclk_sel,
-	.init		= &omap2_init_clksel_parent,
-	.clksel_reg	= OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-	.clksel_mask	= OMAP4430_CLKSEL_UTMI_P2_MASK,
+static struct clk trace_clk_div_ck = {
+	.name		= "trace_clk_div_ck",
+	.parent		= &pmd_trace_clk_mux_ck,
+	.clksel		= trace_clk_div_div,
+	.clksel_reg	= OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
+	.clksel_mask	= OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
 	.ops		= &clkops_null,
 	.recalc		= &omap2_clksel_recalc,
+	.round_rate	= &omap2_clksel_round_rate,
+	.set_rate	= &omap2_clksel_set_rate,
 };
 
 /*
@@ -2483,11 +2766,12 @@
 	CLK(NULL,	"virt_27000000_ck",		&virt_27000000_ck,	CK_443X),
 	CLK(NULL,	"virt_38400000_ck",		&virt_38400000_ck,	CK_443X),
 	CLK(NULL,	"sys_clkin_ck",			&sys_clkin_ck,	CK_443X),
+	CLK(NULL,	"tie_low_clock_ck",		&tie_low_clock_ck,	CK_443X),
 	CLK(NULL,	"utmi_phy_clkout_ck",		&utmi_phy_clkout_ck,	CK_443X),
 	CLK(NULL,	"xclk60mhsp1_ck",		&xclk60mhsp1_ck,	CK_443X),
 	CLK(NULL,	"xclk60mhsp2_ck",		&xclk60mhsp2_ck,	CK_443X),
 	CLK(NULL,	"xclk60motg_ck",		&xclk60motg_ck,	CK_443X),
-	CLK(NULL,	"dpll_sys_ref_clk",		&dpll_sys_ref_clk,	CK_443X),
+	CLK(NULL,	"abe_dpll_bypass_clk_mux_ck",	&abe_dpll_bypass_clk_mux_ck,	CK_443X),
 	CLK(NULL,	"abe_dpll_refclk_mux_ck",	&abe_dpll_refclk_mux_ck,	CK_443X),
 	CLK(NULL,	"dpll_abe_ck",			&dpll_abe_ck,	CK_443X),
 	CLK(NULL,	"dpll_abe_m2x2_ck",		&dpll_abe_m2x2_ck,	CK_443X),
@@ -2557,46 +2841,48 @@
 	CLK(NULL,	"aes1_fck",			&aes1_fck,	CK_443X),
 	CLK(NULL,	"aes2_fck",			&aes2_fck,	CK_443X),
 	CLK(NULL,	"aess_fck",			&aess_fck,	CK_443X),
-	CLK(NULL,	"cust_efuse_fck",		&cust_efuse_fck,	CK_443X),
+	CLK(NULL,	"bandgap_fclk",			&bandgap_fclk,	CK_443X),
 	CLK(NULL,	"des3des_fck",			&des3des_fck,	CK_443X),
 	CLK(NULL,	"dmic_sync_mux_ck",		&dmic_sync_mux_ck,	CK_443X),
 	CLK(NULL,	"dmic_fck",			&dmic_fck,	CK_443X),
+	CLK(NULL,	"dsp_fck",			&dsp_fck,	CK_443X),
+	CLK(NULL,	"dss_sys_clk",			&dss_sys_clk,	CK_443X),
+	CLK(NULL,	"dss_tv_clk",			&dss_tv_clk,	CK_443X),
+	CLK(NULL,	"dss_dss_clk",			&dss_dss_clk,	CK_443X),
+	CLK(NULL,	"dss_48mhz_clk",		&dss_48mhz_clk,	CK_443X),
 	CLK(NULL,	"dss_fck",			&dss_fck,	CK_443X),
-	CLK(NULL,	"ducati_ick",			&ducati_ick,	CK_443X),
-	CLK(NULL,	"emif1_ick",			&emif1_ick,	CK_443X),
-	CLK(NULL,	"emif2_ick",			&emif2_ick,	CK_443X),
+	CLK(NULL,	"efuse_ctrl_cust_fck",		&efuse_ctrl_cust_fck,	CK_443X),
+	CLK(NULL,	"emif1_fck",			&emif1_fck,	CK_443X),
+	CLK(NULL,	"emif2_fck",			&emif2_fck,	CK_443X),
 	CLK(NULL,	"fdif_fck",			&fdif_fck,	CK_443X),
-	CLK(NULL,	"per_sgx_fclk",			&per_sgx_fclk,	CK_443X),
-	CLK(NULL,	"gfx_fck",			&gfx_fck,	CK_443X),
+	CLK(NULL,	"fpka_fck",			&fpka_fck,	CK_443X),
+	CLK(NULL,	"gpio1_dbck",			&gpio1_dbclk,	CK_443X),
 	CLK(NULL,	"gpio1_ick",			&gpio1_ick,	CK_443X),
+	CLK(NULL,	"gpio2_dbck",			&gpio2_dbclk,	CK_443X),
 	CLK(NULL,	"gpio2_ick",			&gpio2_ick,	CK_443X),
+	CLK(NULL,	"gpio3_dbck",			&gpio3_dbclk,	CK_443X),
 	CLK(NULL,	"gpio3_ick",			&gpio3_ick,	CK_443X),
+	CLK(NULL,	"gpio4_dbck",			&gpio4_dbclk,	CK_443X),
 	CLK(NULL,	"gpio4_ick",			&gpio4_ick,	CK_443X),
+	CLK(NULL,	"gpio5_dbck",			&gpio5_dbclk,	CK_443X),
 	CLK(NULL,	"gpio5_ick",			&gpio5_ick,	CK_443X),
+	CLK(NULL,	"gpio6_dbck",			&gpio6_dbclk,	CK_443X),
 	CLK(NULL,	"gpio6_ick",			&gpio6_ick,	CK_443X),
 	CLK(NULL,	"gpmc_ick",			&gpmc_ick,	CK_443X),
-	CLK(NULL,	"gpt1_fck",			&gpt1_fck,	CK_443X),
-	CLK(NULL,	"gpt10_fck",			&gpt10_fck,	CK_443X),
-	CLK(NULL,	"gpt11_fck",			&gpt11_fck,	CK_443X),
-	CLK(NULL,	"gpt2_fck",			&gpt2_fck,	CK_443X),
-	CLK(NULL,	"gpt3_fck",			&gpt3_fck,	CK_443X),
-	CLK(NULL,	"gpt4_fck",			&gpt4_fck,	CK_443X),
-	CLK(NULL,	"gpt5_fck",			&gpt5_fck,	CK_443X),
-	CLK(NULL,	"gpt6_fck",			&gpt6_fck,	CK_443X),
-	CLK(NULL,	"gpt7_fck",			&gpt7_fck,	CK_443X),
-	CLK(NULL,	"gpt8_fck",			&gpt8_fck,	CK_443X),
-	CLK(NULL,	"gpt9_fck",			&gpt9_fck,	CK_443X),
+	CLK(NULL,	"gpu_fck",			&gpu_fck,	CK_443X),
 	CLK("omap2_hdq.0",	"fck",				&hdq1w_fck,	CK_443X),
-	CLK(NULL,	"hsi_ick",			&hsi_ick,	CK_443X),
+	CLK(NULL,	"hsi_fck",			&hsi_fck,	CK_443X),
 	CLK("i2c_omap.1",	"fck",				&i2c1_fck,	CK_443X),
 	CLK("i2c_omap.2",	"fck",				&i2c2_fck,	CK_443X),
 	CLK("i2c_omap.3",	"fck",				&i2c3_fck,	CK_443X),
 	CLK("i2c_omap.4",	"fck",				&i2c4_fck,	CK_443X),
+	CLK(NULL,	"ipu_fck",			&ipu_fck,	CK_443X),
+	CLK(NULL,	"iss_ctrlclk",			&iss_ctrlclk,	CK_443X),
 	CLK(NULL,	"iss_fck",			&iss_fck,	CK_443X),
-	CLK(NULL,	"ivahd_ick",			&ivahd_ick,	CK_443X),
-	CLK(NULL,	"keyboard_fck",			&keyboard_fck,	CK_443X),
-	CLK(NULL,	"l3_instr_interconnect_ick",	&l3_instr_interconnect_ick,	CK_443X),
-	CLK(NULL,	"l3_interconnect_3_ick",	&l3_interconnect_3_ick,	CK_443X),
+	CLK(NULL,	"iva_fck",			&iva_fck,	CK_443X),
+	CLK(NULL,	"kbd_fck",			&kbd_fck,	CK_443X),
+	CLK(NULL,	"l3_instr_ick",			&l3_instr_ick,	CK_443X),
+	CLK(NULL,	"l3_main_3_ick",		&l3_main_3_ick,	CK_443X),
 	CLK(NULL,	"mcasp_sync_mux_ck",		&mcasp_sync_mux_ck,	CK_443X),
 	CLK(NULL,	"mcasp_fck",			&mcasp_fck,	CK_443X),
 	CLK(NULL,	"mcbsp1_sync_mux_ck",		&mcbsp1_sync_mux_ck,	CK_443X),
@@ -2607,6 +2893,7 @@
 	CLK("omap-mcbsp.3",	"fck",				&mcbsp3_fck,	CK_443X),
 	CLK(NULL,	"mcbsp4_sync_mux_ck",		&mcbsp4_sync_mux_ck,	CK_443X),
 	CLK("omap-mcbsp.4",	"fck",				&mcbsp4_fck,	CK_443X),
+	CLK(NULL,	"mcpdm_fck",			&mcpdm_fck,	CK_443X),
 	CLK("omap2_mcspi.1",	"fck",				&mcspi1_fck,	CK_443X),
 	CLK("omap2_mcspi.2",	"fck",				&mcspi2_fck,	CK_443X),
 	CLK("omap2_mcspi.3",	"fck",				&mcspi3_fck,	CK_443X),
@@ -2616,43 +2903,66 @@
 	CLK("mmci-omap-hs.2",	"fck",				&mmc3_fck,	CK_443X),
 	CLK("mmci-omap-hs.3",	"fck",				&mmc4_fck,	CK_443X),
 	CLK("mmci-omap-hs.4",	"fck",				&mmc5_fck,	CK_443X),
-	CLK(NULL,	"ocp_wp1_ick",			&ocp_wp1_ick,	CK_443X),
-	CLK(NULL,	"pdm_fck",			&pdm_fck,	CK_443X),
-	CLK(NULL,	"pkaeip29_fck",			&pkaeip29_fck,	CK_443X),
+	CLK(NULL,	"ocp2scp_usb_phy_phy_48m",	&ocp2scp_usb_phy_phy_48m,	CK_443X),
+	CLK(NULL,	"ocp2scp_usb_phy_ick",		&ocp2scp_usb_phy_ick,	CK_443X),
+	CLK(NULL,	"ocp_wp_noc_ick",		&ocp_wp_noc_ick,	CK_443X),
 	CLK("omap_rng",	"ick",				&rng_ick,	CK_443X),
-	CLK(NULL,	"sha2md51_fck",			&sha2md51_fck,	CK_443X),
-	CLK(NULL,	"sl2_ick",			&sl2_ick,	CK_443X),
+	CLK(NULL,	"sha2md5_fck",			&sha2md5_fck,	CK_443X),
+	CLK(NULL,	"sl2if_ick",			&sl2if_ick,	CK_443X),
+	CLK(NULL,	"slimbus1_fclk_1",		&slimbus1_fclk_1,	CK_443X),
+	CLK(NULL,	"slimbus1_fclk_0",		&slimbus1_fclk_0,	CK_443X),
+	CLK(NULL,	"slimbus1_fclk_2",		&slimbus1_fclk_2,	CK_443X),
+	CLK(NULL,	"slimbus1_slimbus_clk",		&slimbus1_slimbus_clk,	CK_443X),
 	CLK(NULL,	"slimbus1_fck",			&slimbus1_fck,	CK_443X),
+	CLK(NULL,	"slimbus2_fclk_1",		&slimbus2_fclk_1,	CK_443X),
+	CLK(NULL,	"slimbus2_fclk_0",		&slimbus2_fclk_0,	CK_443X),
+	CLK(NULL,	"slimbus2_slimbus_clk",		&slimbus2_slimbus_clk,	CK_443X),
 	CLK(NULL,	"slimbus2_fck",			&slimbus2_fck,	CK_443X),
-	CLK(NULL,	"sr_core_fck",			&sr_core_fck,	CK_443X),
-	CLK(NULL,	"sr_iva_fck",			&sr_iva_fck,	CK_443X),
-	CLK(NULL,	"sr_mpu_fck",			&sr_mpu_fck,	CK_443X),
-	CLK(NULL,	"tesla_ick",			&tesla_ick,	CK_443X),
+	CLK(NULL,	"smartreflex_core_fck",		&smartreflex_core_fck,	CK_443X),
+	CLK(NULL,	"smartreflex_iva_fck",		&smartreflex_iva_fck,	CK_443X),
+	CLK(NULL,	"smartreflex_mpu_fck",		&smartreflex_mpu_fck,	CK_443X),
+	CLK(NULL,	"gpt1_fck",			&timer1_fck,	CK_443X),
+	CLK(NULL,	"gpt10_fck",			&timer10_fck,	CK_443X),
+	CLK(NULL,	"gpt11_fck",			&timer11_fck,	CK_443X),
+	CLK(NULL,	"gpt2_fck",			&timer2_fck,	CK_443X),
+	CLK(NULL,	"gpt3_fck",			&timer3_fck,	CK_443X),
+	CLK(NULL,	"gpt4_fck",			&timer4_fck,	CK_443X),
+	CLK(NULL,	"gpt5_fck",			&timer5_fck,	CK_443X),
+	CLK(NULL,	"gpt6_fck",			&timer6_fck,	CK_443X),
+	CLK(NULL,	"gpt7_fck",			&timer7_fck,	CK_443X),
+	CLK(NULL,	"gpt8_fck",			&timer8_fck,	CK_443X),
+	CLK(NULL,	"gpt9_fck",			&timer9_fck,	CK_443X),
 	CLK(NULL,	"uart1_fck",			&uart1_fck,	CK_443X),
 	CLK(NULL,	"uart2_fck",			&uart2_fck,	CK_443X),
 	CLK(NULL,	"uart3_fck",			&uart3_fck,	CK_443X),
 	CLK(NULL,	"uart4_fck",			&uart4_fck,	CK_443X),
-	CLK(NULL,	"unipro1_fck",			&unipro1_fck,	CK_443X),
-	CLK(NULL,	"usb_host_fck",			&usb_host_fck,	CK_443X),
 	CLK(NULL,	"usb_host_fs_fck",		&usb_host_fs_fck,	CK_443X),
-	CLK("musb_hdrc",	"ick",				&usb_otg_ick,	CK_443X),
-	CLK(NULL,	"usb_tll_ick",			&usb_tll_ick,	CK_443X),
-	CLK(NULL,	"usbphyocp2scp_ick",		&usbphyocp2scp_ick,	CK_443X),
+	CLK(NULL,	"usb_host_hs_utmi_p3_clk",	&usb_host_hs_utmi_p3_clk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_hsic60m_p1_clk",	&usb_host_hs_hsic60m_p1_clk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_hsic60m_p2_clk",	&usb_host_hs_hsic60m_p2_clk,	CK_443X),
+	CLK(NULL,	"utmi_p1_gfclk",		&utmi_p1_gfclk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_utmi_p1_clk",	&usb_host_hs_utmi_p1_clk,	CK_443X),
+	CLK(NULL,	"utmi_p2_gfclk",		&utmi_p2_gfclk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_utmi_p2_clk",	&usb_host_hs_utmi_p2_clk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_hsic480m_p1_clk",	&usb_host_hs_hsic480m_p1_clk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_hsic480m_p2_clk",	&usb_host_hs_hsic480m_p2_clk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_func48mclk",	&usb_host_hs_func48mclk,	CK_443X),
+	CLK(NULL,	"usb_host_hs_fck",		&usb_host_hs_fck,	CK_443X),
+	CLK(NULL,	"otg_60m_gfclk",		&otg_60m_gfclk,	CK_443X),
+	CLK(NULL,	"usb_otg_hs_xclk",		&usb_otg_hs_xclk,	CK_443X),
+	CLK("musb_hdrc",	"ick",				&usb_otg_hs_ick,	CK_443X),
+	CLK(NULL,	"usb_phy_cm_clk32k",		&usb_phy_cm_clk32k,	CK_443X),
+	CLK(NULL,	"usb_tll_hs_usb_ch2_clk",	&usb_tll_hs_usb_ch2_clk,	CK_443X),
+	CLK(NULL,	"usb_tll_hs_usb_ch0_clk",	&usb_tll_hs_usb_ch0_clk,	CK_443X),
+	CLK(NULL,	"usb_tll_hs_usb_ch1_clk",	&usb_tll_hs_usb_ch1_clk,	CK_443X),
+	CLK(NULL,	"usb_tll_hs_ick",		&usb_tll_hs_ick,	CK_443X),
+	CLK(NULL,	"usim_ck",			&usim_ck,	CK_443X),
+	CLK(NULL,	"usim_fclk",			&usim_fclk,	CK_443X),
 	CLK(NULL,	"usim_fck",			&usim_fck,	CK_443X),
-	CLK("omap_wdt",	"fck",				&wdt2_fck,	CK_443X),
-	CLK(NULL,	"wdt3_fck",			&wdt3_fck,	CK_443X),
-	CLK(NULL,	"otg_60m_gfclk_ck",		&otg_60m_gfclk_ck,	CK_443X),
+	CLK("omap_wdt",	"fck",				&wd_timer2_fck,	CK_443X),
+	CLK(NULL,	"wd_timer3_fck",		&wd_timer3_fck,	CK_443X),
 	CLK(NULL,	"stm_clk_div_ck",		&stm_clk_div_ck,	CK_443X),
 	CLK(NULL,	"trace_clk_div_ck",		&trace_clk_div_ck,	CK_443X),
-	CLK(NULL,	"usim_fclk",			&usim_fclk,	CK_443X),
-	CLK(NULL,	"utmi_p1_gfclk_ck",		&utmi_p1_gfclk_ck,	CK_443X),
-	CLK(NULL,	"utmi_p2_gfclk_ck",		&utmi_p2_gfclk_ck,	CK_443X),
-	CLK(NULL,	"gpio1_dbck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpio2_dbck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpio3_dbck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpio4_dbck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpio5_dbck",			&dummy_ck,	CK_443X),
-	CLK(NULL,	"gpio6_dbck",			&dummy_ck,	CK_443X),
 	CLK(NULL,	"gpmc_ck",			&dummy_ck,	CK_443X),
 	CLK(NULL,	"gpt1_ick",			&dummy_ck,	CK_443X),
 	CLK(NULL,	"gpt2_ick",			&dummy_ck,	CK_443X),
@@ -2669,19 +2979,19 @@
 	CLK("i2c_omap.2",	"ick",				&dummy_ck,	CK_443X),
 	CLK("i2c_omap.3",	"ick",				&dummy_ck,	CK_443X),
 	CLK("i2c_omap.4",	"ick",				&dummy_ck,	CK_443X),
+	CLK("mmci-omap-hs.0",	"ick",				&dummy_ck,	CK_443X),
+	CLK("mmci-omap-hs.1",	"ick",				&dummy_ck,	CK_443X),
+	CLK("mmci-omap-hs.2",	"ick",				&dummy_ck,	CK_443X),
+	CLK("mmci-omap-hs.3",	"ick",				&dummy_ck,	CK_443X),
+	CLK("mmci-omap-hs.4",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap-mcbsp.1",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap-mcbsp.2",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap-mcbsp.3",	"ick",				&dummy_ck,	CK_443X),
 	CLK("omap-mcbsp.4",	"ick",				&dummy_ck,	CK_443X),
-	CLK("omap2_mcspi.1",	"ick",			&dummy_ck,	CK_443X),
-	CLK("omap2_mcspi.2",	"ick",			&dummy_ck,	CK_443X),
-	CLK("omap2_mcspi.3",	"ick",			&dummy_ck,	CK_443X),
-	CLK("omap2_mcspi.4",	"ick",			&dummy_ck,	CK_443X),
-	CLK("mmci-omap-hs.0",	"ick",		&dummy_ck,	CK_443X),
-	CLK("mmci-omap-hs.1",	"ick",		&dummy_ck,	CK_443X),
-	CLK("mmci-omap-hs.2",	"ick",		&dummy_ck,	CK_443X),
-	CLK("mmci-omap-hs.3",	"ick",		&dummy_ck,	CK_443X),
-	CLK("mmci-omap-hs.4",	"ick",		&dummy_ck,	CK_443X),
+	CLK("omap2_mcspi.1",	"ick",				&dummy_ck,	CK_443X),
+	CLK("omap2_mcspi.2",	"ick",				&dummy_ck,	CK_443X),
+	CLK("omap2_mcspi.3",	"ick",				&dummy_ck,	CK_443X),
+	CLK("omap2_mcspi.4",	"ick",				&dummy_ck,	CK_443X),
 	CLK(NULL,	"uart1_ick",			&dummy_ck,	CK_443X),
 	CLK(NULL,	"uart2_ick",			&dummy_ck,	CK_443X),
 	CLK(NULL,	"uart3_ick",			&dummy_ck,	CK_443X),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -395,7 +395,7 @@
 	if ((regval32 & (1 << clk->enable_bit)) == v)
 		return;
 
-	printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
+	pr_debug("Disabling unused clock \"%s\"\n", clk->name);
 	if (cpu_is_omap34xx()) {
 		omap2_clk_enable(clk);
 		omap2_clk_disable(clk);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clockdomain.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clockdomain.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/clockdomain.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/clockdomain.c	2011-01-04 19:50:19.000000000 -0500
@@ -258,97 +258,6 @@
 
 }
 
-/**
- * _init_wkdep_usecount - initialize wkdep usecounts to match hardware
- * @clkdm: clockdomain to initialize wkdep usecounts
- *
- * Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
- * If a wakeup dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0.  Software should clear all
- * software wakeup dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0.  No return value.
- */
-static void _init_wkdep_usecount(struct clockdomain *clkdm)
-{
-	u32 v;
-	struct clkdm_dep *cd;
-
-	if (!clkdm->wkdep_srcs)
-		return;
-
-	for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
-		if (!omap_chip_is(cd->omap_chip))
-			continue;
-
-		if (!cd->clkdm && cd->clkdm_name)
-			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
-		if (!cd->clkdm) {
-			WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
-			     "found\n", clkdm->name, cd->clkdm_name);
-			continue;
-		}
-
-		v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
-					    PM_WKDEP,
-					    (1 << cd->clkdm->dep_bit));
-
-		if (v)
-			pr_debug("clockdomain: %s: wakeup dependency already "
-				 "set to wake up when %s wakes\n",
-				 clkdm->name, cd->clkdm->name);
-
-		atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
-	}
-}
-
-/**
- * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
- * @clkdm: clockdomain to initialize sleepdep usecounts
- *
- * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
- * If a sleep dependency is present in the hardware, the usecount will be
- * set to 1; otherwise, it will be set to 0.  Software should clear all
- * software sleep dependencies prior to calling this function if it wishes
- * to ensure that all usecounts start at 0.  No return value.
- */
-static void _init_sleepdep_usecount(struct clockdomain *clkdm)
-{
-	u32 v;
-	struct clkdm_dep *cd;
-
-	if (!cpu_is_omap34xx())
-		return;
-
-	if (!clkdm->sleepdep_srcs)
-		return;
-
-	for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
-		if (!omap_chip_is(cd->omap_chip))
-			continue;
-
-		if (!cd->clkdm && cd->clkdm_name)
-			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
-
-		if (!cd->clkdm) {
-			WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
-			     "not found\n", clkdm->name, cd->clkdm_name);
-			continue;
-		}
-
-		v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
-					    OMAP3430_CM_SLEEPDEP,
-					    (1 << cd->clkdm->dep_bit));
-
-		if (v)
-			pr_debug("clockdomain: %s: sleep dependency already "
-				 "set to prevent from idling until %s "
-				 "idles\n", clkdm->name, cd->clkdm->name);
-
-		atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
-	}
-};
-
 /* Public functions */
 
 /**
@@ -379,12 +288,17 @@
 			_autodep_lookup(autodep);
 
 	/*
-	 * Ensure that the *dep_usecount registers reflect the current
-	 * state of the PRCM.
+	 * Put all clockdomains into software-supervised mode; PM code
+	 * should later enable hardware-supervised mode as appropriate
 	 */
 	list_for_each_entry(clkdm, &clkdm_list, node) {
-		_init_wkdep_usecount(clkdm);
-		_init_sleepdep_usecount(clkdm);
+		if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+			omap2_clkdm_wakeup(clkdm);
+		else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
+			omap2_clkdm_deny_idle(clkdm);
+
+		clkdm_clear_all_wkdeps(clkdm);
+		clkdm_clear_all_sleepdeps(clkdm);
 	}
 }
 
@@ -592,6 +506,9 @@
 		if (!omap_chip_is(cd->omap_chip))
 			continue;
 
+		if (!cd->clkdm && cd->clkdm_name)
+			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
 		/* PRM accesses are slow, so minimize them */
 		mask |= 1 << cd->clkdm->dep_bit;
 		atomic_set(&cd->wkdep_usecount, 0);
@@ -752,6 +669,9 @@
 		if (!omap_chip_is(cd->omap_chip))
 			continue;
 
+		if (!cd->clkdm && cd->clkdm_name)
+			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
+
 		/* PRM accesses are slow, so minimize them */
 		mask |= 1 << cd->clkdm->dep_bit;
 		atomic_set(&cd->sleepdep_usecount, 0);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm44xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -195,6 +195,42 @@
 #define OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET		0x0088
 #define OMAP4430_CM1_ABE_WDT3_CLKCTRL			OMAP44XX_CM1_REGADDR(OMAP4430_CM1_ABE_MOD, 0x0088)
 
+/* CM1.RESTORE_CM1 register offsets */
+#define OMAP4_CM_CLKSEL_CORE_RESTORE_OFFSET		0x0000
+#define OMAP4430_CM_CLKSEL_CORE_RESTORE			OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_DIV_M2_DPLL_CORE_RESTORE_OFFSET	0x0004
+#define OMAP4430_CM_DIV_M2_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_DIV_M3_DPLL_CORE_RESTORE_OFFSET	0x0008
+#define OMAP4430_CM_DIV_M3_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_DIV_M4_DPLL_CORE_RESTORE_OFFSET	0x000c
+#define OMAP4430_CM_DIV_M4_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_DIV_M5_DPLL_CORE_RESTORE_OFFSET	0x0010
+#define OMAP4430_CM_DIV_M5_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_DIV_M6_DPLL_CORE_RESTORE_OFFSET	0x0014
+#define OMAP4430_CM_DIV_M6_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_DIV_M7_DPLL_CORE_RESTORE_OFFSET	0x0018
+#define OMAP4430_CM_DIV_M7_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_CLKSEL_DPLL_CORE_RESTORE_OFFSET	0x001c
+#define OMAP4430_CM_CLKSEL_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE_OFFSET	0x0020
+#define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE	OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE_OFFSET	0x0024
+#define OMAP4430_CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE	OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_CLKMODE_DPLL_CORE_RESTORE_OFFSET	0x0028
+#define OMAP4430_CM_CLKMODE_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG2_RESTORE_OFFSET	0x002c
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG2_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_SHADOW_FREQ_CONFIG1_RESTORE_OFFSET	0x0030
+#define OMAP4430_CM_SHADOW_FREQ_CONFIG1_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_AUTOIDLE_DPLL_CORE_RESTORE_OFFSET	0x0034
+#define OMAP4430_CM_AUTOIDLE_DPLL_CORE_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_MPU_CLKSTCTRL_RESTORE_OFFSET		0x0038
+#define OMAP4430_CM_MPU_CLKSTCTRL_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_CM1_PROFILING_CLKCTRL_RESTORE_OFFSET	0x003c
+#define OMAP4430_CM_CM1_PROFILING_CLKCTRL_RESTORE	OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_DYN_DEP_PRESCAL_RESTORE_OFFSET		0x0040
+#define OMAP4430_CM_DYN_DEP_PRESCAL_RESTORE		OMAP44XX_CM1_REGADDR(OMAP4430_CM1_RESTORE_MOD, 0x0040)
+
 /* CM2 */
 
 /* CM2.OCP_SOCKET_CM2 register offsets */
@@ -252,8 +288,6 @@
 #define OMAP4430_CM_SSC_DELTAMSTEP_DPLL_PER		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0068)
 #define OMAP4_CM_SSC_MODFREQDIV_DPLL_PER_OFFSET		0x006c
 #define OMAP4430_CM_SSC_MODFREQDIV_DPLL_PER		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x006c)
-#define OMAP4_CM_EMU_OVERRIDE_DPLL_PER_OFFSET		0x0070
-#define OMAP4430_CM_EMU_OVERRIDE_DPLL_PER		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0070)
 #define OMAP4_CM_CLKMODE_DPLL_USB_OFFSET		0x0080
 #define OMAP4430_CM_CLKMODE_DPLL_USB			OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CKGEN_MOD, 0x0080)
 #define OMAP4_CM_IDLEST_DPLL_USB_OFFSET			0x0084
@@ -296,6 +330,8 @@
 #define OMAP4430_CM_ALWON_SR_IVA_CLKCTRL		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0030)
 #define OMAP4_CM_ALWON_SR_CORE_CLKCTRL_OFFSET		0x0038
 #define OMAP4430_CM_ALWON_SR_CORE_CLKCTRL		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0038)
+#define OMAP4_CM_ALWON_USBPHY_CLKCTRL_OFFSET		0x0040
+#define OMAP4430_CM_ALWON_USBPHY_CLKCTRL		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_ALWAYS_ON_MOD, 0x0040)
 
 /* CM2.CORE_CM2 register offsets */
 #define OMAP4_CM_L3_1_CLKSTCTRL_OFFSET			0x0000
@@ -578,4 +614,54 @@
 #define OMAP4430_CM_CEFUSE_CLKSTCTRL			OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0000)
 #define OMAP4_CM_CEFUSE_CEFUSE_CLKCTRL_OFFSET		0x0020
 #define OMAP4430_CM_CEFUSE_CEFUSE_CLKCTRL		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_CEFUSE_MOD, 0x0020)
+
+/* CM2.RESTORE_CM2 register offsets */
+#define OMAP4_CM_L3_1_CLKSTCTRL_RESTORE_OFFSET		0x0000
+#define OMAP4430_CM_L3_1_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0000)
+#define OMAP4_CM_L3_2_CLKSTCTRL_RESTORE_OFFSET		0x0004
+#define OMAP4430_CM_L3_2_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0004)
+#define OMAP4_CM_L4CFG_CLKSTCTRL_RESTORE_OFFSET		0x0008
+#define OMAP4430_CM_L4CFG_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0008)
+#define OMAP4_CM_MEMIF_CLKSTCTRL_RESTORE_OFFSET		0x000c
+#define OMAP4430_CM_MEMIF_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x000c)
+#define OMAP4_CM_L4PER_CLKSTCTRL_RESTORE_OFFSET		0x0010
+#define OMAP4430_CM_L4PER_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0010)
+#define OMAP4_CM_L3INIT_CLKSTCTRL_RESTORE_OFFSET	0x0014
+#define OMAP4430_CM_L3INIT_CLKSTCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0014)
+#define OMAP4_CM_L3INSTR_L3_3_CLKCTRL_RESTORE_OFFSET	0x0018
+#define OMAP4430_CM_L3INSTR_L3_3_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0018)
+#define OMAP4_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE_OFFSET	0x001c
+#define OMAP4430_CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x001c)
+#define OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE_OFFSET	0x0020
+#define OMAP4430_CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0020)
+#define OMAP4_CM_CM2_PROFILING_CLKCTRL_RESTORE_OFFSET	0x0024
+#define OMAP4430_CM_CM2_PROFILING_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0024)
+#define OMAP4_CM_D2D_STATICDEP_RESTORE_OFFSET		0x0028
+#define OMAP4430_CM_D2D_STATICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0028)
+#define OMAP4_CM_L3_1_DYNAMICDEP_RESTORE_OFFSET		0x002c
+#define OMAP4430_CM_L3_1_DYNAMICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x002c)
+#define OMAP4_CM_L3_2_DYNAMICDEP_RESTORE_OFFSET		0x0030
+#define OMAP4430_CM_L3_2_DYNAMICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0030)
+#define OMAP4_CM_D2D_DYNAMICDEP_RESTORE_OFFSET		0x0034
+#define OMAP4430_CM_D2D_DYNAMICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0034)
+#define OMAP4_CM_L4CFG_DYNAMICDEP_RESTORE_OFFSET	0x0038
+#define OMAP4430_CM_L4CFG_DYNAMICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0038)
+#define OMAP4_CM_L4PER_DYNAMICDEP_RESTORE_OFFSET	0x003c
+#define OMAP4430_CM_L4PER_DYNAMICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x003c)
+#define OMAP4_CM_L4PER_GPIO2_CLKCTRL_RESTORE_OFFSET	0x0040
+#define OMAP4430_CM_L4PER_GPIO2_CLKCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0040)
+#define OMAP4_CM_L4PER_GPIO3_CLKCTRL_RESTORE_OFFSET	0x0044
+#define OMAP4430_CM_L4PER_GPIO3_CLKCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0044)
+#define OMAP4_CM_L4PER_GPIO4_CLKCTRL_RESTORE_OFFSET	0x0048
+#define OMAP4430_CM_L4PER_GPIO4_CLKCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0048)
+#define OMAP4_CM_L4PER_GPIO5_CLKCTRL_RESTORE_OFFSET	0x004c
+#define OMAP4430_CM_L4PER_GPIO5_CLKCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x004c)
+#define OMAP4_CM_L4PER_GPIO6_CLKCTRL_RESTORE_OFFSET	0x0050
+#define OMAP4430_CM_L4PER_GPIO6_CLKCTRL_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0050)
+#define OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE_OFFSET	0x0054
+#define OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0054)
+#define OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE_OFFSET	0x0058
+#define OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL_RESTORE	OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x0058)
+#define OMAP4_CM_SDMA_STATICDEP_RESTORE_OFFSET		0x005c
+#define OMAP4430_CM_SDMA_STATICDEP_RESTORE		OMAP44XX_CM2_REGADDR(OMAP4430_CM2_RESTORE_MOD, 0x005c)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm4xxx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm4xxx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm4xxx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm4xxx.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,6 @@
  *                 using separate functional clock
  *   0x3 disabled: Module is disabled and cannot be accessed
  *
- * TODO: Need to handle module accessible in idle state
  */
 int omap4_cm_wait_module_ready(void __iomem *clkctrl_reg)
 {
@@ -52,9 +51,11 @@
 	if (!clkctrl_reg)
 		return 0;
 
-	omap_test_timeout(((__raw_readl(clkctrl_reg) &
-			    OMAP4430_IDLEST_MASK) == 0),
-			  MAX_MODULE_READY_TIME, i);
+	omap_test_timeout((
+		((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) == 0) ||
+		 (((__raw_readl(clkctrl_reg) & OMAP4430_IDLEST_MASK) >>
+		  OMAP4430_IDLEST_SHIFT) == 0x2)),
+		MAX_MODULE_READY_TIME, i);
 
 	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm-regbits-34xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm-regbits-34xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm-regbits-34xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm-regbits-34xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -649,6 +649,8 @@
 #define OMAP3430_ST_MCBSP2_MASK				(1 << 0)
 
 /* CM_AUTOIDLE_PER */
+#define OMAP3630_AUTO_UART4_MASK			(1 << 18)
+#define OMAP3630_AUTO_UART4_SHIFT			18
 #define OMAP3430_AUTO_GPIO6_MASK			(1 << 17)
 #define OMAP3430_AUTO_GPIO6_SHIFT			17
 #define OMAP3430_AUTO_GPIO5_MASK			(1 << 16)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm-regbits-44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm-regbits-44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cm-regbits-44xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cm-regbits-44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 /*
  * OMAP44xx Clock Management register bits
  *
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul@pwsan.com)
  * Rajendra Nayak (rnayak@ti.com)
@@ -25,453 +25,459 @@
 #include "cm.h"
 
 
-/* Used by CM_L3_1_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/*
+ * Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP,
+ * CM_TESLA_DYNAMICDEP
+ */
 #define OMAP4430_ABE_DYNDEP_SHIFT				3
-#define OMAP4430_ABE_DYNDEP_MASK				BITFIELD(3, 3)
+#define OMAP4430_ABE_DYNDEP_MASK				(1 << 3)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_ABE_STATDEP_SHIFT				3
-#define OMAP4430_ABE_STATDEP_MASK				BITFIELD(3, 3)
+#define OMAP4430_ABE_STATDEP_MASK				(1 << 3)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_ALWONCORE_DYNDEP_SHIFT				16
-#define OMAP4430_ALWONCORE_DYNDEP_MASK				BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_DYNDEP_MASK				(1 << 16)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
 #define OMAP4430_ALWONCORE_STATDEP_SHIFT			16
-#define OMAP4430_ALWONCORE_STATDEP_MASK				BITFIELD(16, 16)
+#define OMAP4430_ALWONCORE_STATDEP_MASK				(1 << 16)
 
 /*
- * Used by CM_AUTOIDLE_DPLL_PER, CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB,
- * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
- * CM_AUTOIDLE_DPLL_DDRPHY, CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU
+ * Used by CM_AUTOIDLE_DPLL_ABE, CM_AUTOIDLE_DPLL_CORE,
+ * CM_AUTOIDLE_DPLL_CORE_RESTORE, CM_AUTOIDLE_DPLL_DDRPHY,
+ * CM_AUTOIDLE_DPLL_IVA, CM_AUTOIDLE_DPLL_MPU, CM_AUTOIDLE_DPLL_PER,
+ * CM_AUTOIDLE_DPLL_UNIPRO, CM_AUTOIDLE_DPLL_USB
  */
 #define OMAP4430_AUTO_DPLL_MODE_SHIFT				0
-#define OMAP4430_AUTO_DPLL_MODE_MASK				BITFIELD(0, 2)
+#define OMAP4430_AUTO_DPLL_MODE_MASK				(0x7 << 0)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_CEFUSE_DYNDEP_SHIFT				17
-#define OMAP4430_CEFUSE_DYNDEP_MASK				BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_DYNDEP_MASK				(1 << 17)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_TESLA_STATICDEP */
 #define OMAP4430_CEFUSE_STATDEP_SHIFT				17
-#define OMAP4430_CEFUSE_STATDEP_MASK				BITFIELD(17, 17)
+#define OMAP4430_CEFUSE_STATDEP_MASK				(1 << 17)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_SHIFT		13
-#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK			BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ABE_24M_GFCLK_MASK			(1 << 13)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_SHIFT		12
-#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK		BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ABE_ALWON_32K_CLK_MASK		(1 << 12)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_LP_CLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_ABE_LP_CLK_MASK			(1 << 9)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_SYSCLK_SHIFT			11
-#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK			BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ABE_SYSCLK_MASK			(1 << 11)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ABE_X2_CLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ABE_X2_CLK_MASK			(1 << 8)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_SHIFT		11
-#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK			BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_ASYNC_DLL_CLK_MASK			(1 << 11)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_SHIFT		12
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK		BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY1_CLK_MASK		(1 << 12)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_SHIFT		13
-#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK		BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_ASYNC_PHY2_CLK_MASK		(1 << 13)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK		BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CAM_PHY_CTRL_GCLK_MASK		(1 << 9)
+
+/* Used by CM_ALWON_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_SHIFT		12
+#define OMAP4430_CLKACTIVITY_CORE_ALWON_32K_GFCLK_MASK		(1 << 12)
 
 /* Used by CM_EMU_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK		BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CORE_DPLL_EMU_CLK_MASK		(1 << 9)
 
 /* Used by CM_CEFUSE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK		BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_CUST_EFUSE_SYS_CLK_MASK		(1 << 9)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DLL_CLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DLL_CLK_MASK			(1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT10_GFCLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DMT10_GFCLK_MASK			(1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT11_GFCLK_SHIFT			10
-#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DMT11_GFCLK_MASK			(1 << 10)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT2_GFCLK_SHIFT			11
-#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK			BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_DMT2_GFCLK_MASK			(1 << 11)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT3_GFCLK_SHIFT			12
-#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK			BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_DMT3_GFCLK_MASK			(1 << 12)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT4_GFCLK_SHIFT			13
-#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK			BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_DMT4_GFCLK_MASK			(1 << 13)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_DMT9_GFCLK_SHIFT			14
-#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK			BITFIELD(14, 14)
+#define OMAP4430_CLKACTIVITY_DMT9_GFCLK_MASK			(1 << 14)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_SHIFT		10
-#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK		BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DSS_ALWON_SYS_CLK_MASK		(1 << 10)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DSS_FCLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_DSS_FCLK_MASK			(1 << 9)
 
 /* Used by CM_DUCATI_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_DUCATI_GCLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK			BITFIELD(8, 8)
-
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_SHIFT		10
-#define OMAP4430_CLKACTIVITY_EMAC_50MHZ_CLK_MASK		BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_DUCATI_GCLK_MASK			(1 << 8)
 
 /* Used by CM_EMU_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_EMU_SYS_CLK_MASK			(1 << 8)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_FDIF_GFCLK_SHIFT			10
-#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FDIF_GFCLK_MASK			(1 << 10)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_SHIFT		15
-#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK		BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_FUNC_12M_GFCLK_MASK		(1 << 15)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_SHIFT		10
-#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK		BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_FUNC_24M_GFCLK_MASK		(1 << 10)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_SHIFT		11
-#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK		BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_HDMI_PHY_48MHZ_GFCLK_MASK		(1 << 11)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_SHIFT		20
-#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK		BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_480M_GFCLK_MASK		(1 << 20)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_SHIFT		26
-#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK			BITFIELD(26, 26)
+#define OMAP4430_CLKACTIVITY_HSIC_P1_GFCLK_MASK			(1 << 26)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_SHIFT		21
-#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK		BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_480M_GFCLK_MASK		(1 << 21)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_SHIFT		27
-#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK			BITFIELD(27, 27)
-
-/* Used by CM_L3INIT_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_SHIFT		31
-#define OMAP4430_CLKACTIVITY_INIT_32K_GFCLK_MASK		BITFIELD(31, 31)
+#define OMAP4430_CLKACTIVITY_HSIC_P2_GFCLK_MASK			(1 << 27)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_SHIFT		13
-#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK		BITFIELD(13, 13)
+#define OMAP4430_CLKACTIVITY_INIT_48MC_GFCLK_MASK		(1 << 13)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_SHIFT		12
-#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK		BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_INIT_48M_GFCLK_MASK		(1 << 12)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_SHIFT		28
-#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK		BITFIELD(28, 28)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P1_GFCLK_MASK		(1 << 28)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_SHIFT		29
-#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK		BITFIELD(29, 29)
+#define OMAP4430_CLKACTIVITY_INIT_60M_P2_GFCLK_MASK		(1 << 29)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_SHIFT		11
-#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK		BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_INIT_96M_GFCLK_MASK		(1 << 11)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_SHIFT		16
-#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK		BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_INIT_HSI_GFCLK_MASK		(1 << 16)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_SHIFT		17
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK		BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC1_GFCLK_MASK		(1 << 17)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_SHIFT		18
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK		BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC2_GFCLK_MASK		(1 << 18)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_SHIFT		19
-#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK		BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_INIT_HSMMC6_GFCLK_MASK		(1 << 19)
 
 /* Used by CM_CAM_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_ISS_GCLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_ISS_GCLK_MASK			(1 << 8)
 
 /* Used by CM_IVAHD_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK		BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_IVAHD_ROOT_CLK_MASK		(1 << 8)
 
-/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_SHIFT	14
-#define OMAP4430_CLKACTIVITY_L3INIT_DPLL_ALWON_CLK_MASK		BITFIELD(14, 14)
+/* Used by CM_D2D_CLKSTCTRL */
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_SHIFT		10
+#define OMAP4430_CLKACTIVITY_L3X2_D2D_GICLK_MASK		(1 << 10)
 
 /* Used by CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_1_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_1_GICLK_MASK			(1 << 8)
 
 /* Used by CM_L3_2_CLKSTCTRL, CM_L3_2_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_2_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_2_GICLK_MASK			(1 << 8)
 
 /* Used by CM_D2D_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_D2D_GICLK_MASK			(1 << 8)
 
 /* Used by CM_SDMA_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DMA_GICLK_MASK			(1 << 8)
 
 /* Used by CM_DSS_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_DSS_GICLK_MASK			(1 << 8)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_EMIF_GICLK_MASK			(1 << 8)
 
 /* Used by CM_GFX_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_GFX_GICLK_MASK			(1 << 8)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INIT_GICLK_MASK			(1 << 8)
 
 /* Used by CM_L3INSTR_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK		BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_INSTR_GICLK_MASK		(1 << 8)
 
 /* Used by CM_L4SEC_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK		BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L3_SECURE_GICLK_MASK		(1 << 8)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_AO_ICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_AO_ICLK_MASK			(1 << 8)
 
 /* Used by CM_CEFUSE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK		BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CEFUSE_GICLK_MASK		(1 << 8)
 
 /* Used by CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_CFG_GICLK_MASK			(1 << 8)
 
 /* Used by CM_D2D_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_D2D_GICLK_MASK			(1 << 9)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_INIT_GICLK_MASK			(1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_L4_PER_GICLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_L4_PER_GICLK_MASK			(1 << 8)
 
 /* Used by CM_L4SEC_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK		BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_L4_SECURE_GICLK_MASK		(1 << 9)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_SHIFT		12
-#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK			BITFIELD(12, 12)
+#define OMAP4430_CLKACTIVITY_L4_WKUP_GICLK_MASK			(1 << 12)
 
 /* Used by CM_MPU_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_MPU_DPLL_CLK_MASK			(1 << 8)
 
 /* Used by CM1_ABE_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_OCP_ABE_GICLK_MASK			(1 << 9)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_SHIFT		16
-#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK		BITFIELD(16, 16)
+#define OMAP4430_CLKACTIVITY_PER_24MC_GFCLK_MASK		(1 << 16)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_SHIFT		17
-#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK			BITFIELD(17, 17)
+#define OMAP4430_CLKACTIVITY_PER_32K_GFCLK_MASK			(1 << 17)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_SHIFT		18
-#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK			BITFIELD(18, 18)
+#define OMAP4430_CLKACTIVITY_PER_48M_GFCLK_MASK			(1 << 18)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_SHIFT		19
-#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK			BITFIELD(19, 19)
+#define OMAP4430_CLKACTIVITY_PER_96M_GFCLK_MASK			(1 << 19)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_SHIFT		25
-#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK		BITFIELD(25, 25)
-
-/* Used by CM_EMU_CLKSTCTRL */
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_SHIFT		10
-#define OMAP4430_CLKACTIVITY_PER_DPLL_EMU_CLK_MASK		BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PER_ABE_24M_GFCLK_MASK		(1 << 25)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_SHIFT		20
-#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK		BITFIELD(20, 20)
+#define OMAP4430_CLKACTIVITY_PER_MCASP2_GFCLK_MASK		(1 << 20)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_SHIFT		21
-#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK		BITFIELD(21, 21)
+#define OMAP4430_CLKACTIVITY_PER_MCASP3_GFCLK_MASK		(1 << 21)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_SHIFT		22
-#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK		BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_PER_MCBSP4_GFCLK_MASK		(1 << 22)
 
 /* Used by CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_SHIFT		24
-#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK			BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_PER_SYS_GFCLK_MASK			(1 << 24)
 
 /* Used by CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_SHIFT			10
-#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_PHY_ROOT_CLK_MASK			(1 << 10)
 
 /* Used by CM_GFX_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SGX_GFCLK_SHIFT			9
-#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SGX_GFCLK_MASK			(1 << 9)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_SHIFT		11
-#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK		BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_SR_CORE_SYSCLK_MASK		(1 << 11)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_SHIFT		10
-#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_SR_IVA_SYSCLK_MASK			(1 << 10)
 
 /* Used by CM_ALWON_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_SHIFT		9
-#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_CLKACTIVITY_SR_MPU_SYSCLK_MASK			(1 << 9)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_SYS_CLK_SHIFT			8
-#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_SYS_CLK_MASK			(1 << 8)
 
 /* Used by CM_TESLA_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_SHIFT		8
-#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK		BITFIELD(8, 8)
+#define OMAP4430_CLKACTIVITY_TESLA_ROOT_CLK_MASK		(1 << 8)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_SHIFT		22
-#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK			BITFIELD(22, 22)
+#define OMAP4430_CLKACTIVITY_TLL_CH0_GFCLK_MASK			(1 << 22)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_SHIFT		23
-#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK			BITFIELD(23, 23)
+#define OMAP4430_CLKACTIVITY_TLL_CH1_GFCLK_MASK			(1 << 23)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_SHIFT		24
-#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK			BITFIELD(24, 24)
+#define OMAP4430_CLKACTIVITY_TLL_CH2_GFCLK_MASK			(1 << 24)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_SHIFT		10
+#define OMAP4430_CLKACTIVITY_UNIPRO_DPLL_CLK_MASK		(1 << 10)
+
+/* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_SHIFT			14
+#define OMAP4430_CLKACTIVITY_USB_DPLL_CLK_MASK			(1 << 14)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_SHIFT		15
-#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK		BITFIELD(15, 15)
+#define OMAP4430_CLKACTIVITY_USB_DPLL_HS_CLK_MASK		(1 << 15)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_USIM_GFCLK_SHIFT			10
-#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_CLKACTIVITY_USIM_GFCLK_MASK			(1 << 10)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_SHIFT		30
-#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK			BITFIELD(30, 30)
+#define OMAP4430_CLKACTIVITY_UTMI_P3_GFCLK_MASK			(1 << 30)
 
 /* Used by CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE */
 #define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_SHIFT		25
-#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK		BITFIELD(25, 25)
+#define OMAP4430_CLKACTIVITY_UTMI_ROOT_GFCLK_MASK		(1 << 25)
 
 /* Used by CM_WKUP_CLKSTCTRL */
 #define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_SHIFT		11
-#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK		BITFIELD(11, 11)
+#define OMAP4430_CLKACTIVITY_WKUP_32K_GFCLK_MASK		(1 << 11)
 
 /*
- * Used by CM_WKUP_TIMER1_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
+ * Used by CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL,
+ * CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL,
+ * CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
  * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
  * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
  * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL, CM_L3INIT_MMC6_CLKCTRL,
- * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
- * CM1_ABE_TIMER8_CLKCTRL
+ * CM_WKUP_TIMER1_CLKCTRL
  */
 #define OMAP4430_CLKSEL_SHIFT					24
-#define OMAP4430_CLKSEL_MASK					BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_MASK					(1 << 24)
 
 /*
  * Renamed from CLKSEL Used by CM_ABE_DSS_SYS_CLKSEL, CM_ABE_PLL_REF_CLKSEL,
- * CM_DPLL_SYS_REF_CLKSEL, CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT,
- * CM_CLKSEL_USB_60MHZ
+ * CM_L4_WKUP_CLKSEL, CM_CLKSEL_DUCATI_ISS_ROOT, CM_CLKSEL_USB_60MHZ
  */
 #define OMAP4430_CLKSEL_0_0_SHIFT				0
-#define OMAP4430_CLKSEL_0_0_MASK				BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_0_0_MASK				(1 << 0)
 
 /* Renamed from CLKSEL Used by CM_BYPCLK_DPLL_IVA, CM_BYPCLK_DPLL_MPU */
 #define OMAP4430_CLKSEL_0_1_SHIFT				0
-#define OMAP4430_CLKSEL_0_1_MASK				BITFIELD(0, 1)
+#define OMAP4430_CLKSEL_0_1_MASK				(0x3 << 0)
 
 /* Renamed from CLKSEL Used by CM_L3INIT_HSI_CLKCTRL */
 #define OMAP4430_CLKSEL_24_25_SHIFT				24
-#define OMAP4430_CLKSEL_24_25_MASK				BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_24_25_MASK				(0x3 << 24)
 
 /* Used by CM_L3INIT_USB_OTG_CLKCTRL */
 #define OMAP4430_CLKSEL_60M_SHIFT				24
-#define OMAP4430_CLKSEL_60M_MASK				BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_60M_MASK				(1 << 24)
 
 /* Used by CM1_ABE_AESS_CLKCTRL */
 #define OMAP4430_CLKSEL_AESS_FCLK_SHIFT				24
-#define OMAP4430_CLKSEL_AESS_FCLK_MASK				BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_AESS_FCLK_MASK				(1 << 24)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_CORE_SHIFT				0
-#define OMAP4430_CLKSEL_CORE_MASK				BITFIELD(0, 0)
+#define OMAP4430_CLKSEL_CORE_MASK				(1 << 0)
 
-/* Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_CORE Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
 #define OMAP4430_CLKSEL_CORE_1_1_SHIFT				1
-#define OMAP4430_CLKSEL_CORE_1_1_MASK				BITFIELD(1, 1)
+#define OMAP4430_CLKSEL_CORE_1_1_MASK				(1 << 1)
 
 /* Used by CM_WKUP_USIM_CLKCTRL */
 #define OMAP4430_CLKSEL_DIV_SHIFT				24
-#define OMAP4430_CLKSEL_DIV_MASK				BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_DIV_MASK				(1 << 24)
 
 /* Used by CM_CAM_FDIF_CLKCTRL */
 #define OMAP4430_CLKSEL_FCLK_SHIFT				24
-#define OMAP4430_CLKSEL_FCLK_MASK				BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_FCLK_MASK				(0x3 << 24)
 
 /* Used by CM_L4PER_MCBSP4_CLKCTRL */
 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT			25
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK			BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_MASK			(1 << 25)
 
 /*
  * Renamed from CLKSEL_INTERNAL_SOURCE Used by CM1_ABE_DMIC_CLKCTRL,
@@ -479,836 +485,869 @@
  * CM1_ABE_MCBSP3_CLKCTRL
  */
 #define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_SHIFT	26
-#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK	BITFIELD(26, 27)
+#define OMAP4430_CLKSEL_INTERNAL_SOURCE_CM1_ABE_DMIC_MASK	(0x3 << 26)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_L3_SHIFT				4
-#define OMAP4430_CLKSEL_L3_MASK					BITFIELD(4, 4)
+#define OMAP4430_CLKSEL_L3_MASK					(1 << 4)
 
-/* Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2 */
+/*
+ * Renamed from CLKSEL_L3 Used by CM_SHADOW_FREQ_CONFIG2_RESTORE,
+ * CM_SHADOW_FREQ_CONFIG2
+ */
 #define OMAP4430_CLKSEL_L3_SHADOW_SHIFT				2
-#define OMAP4430_CLKSEL_L3_SHADOW_MASK				BITFIELD(2, 2)
+#define OMAP4430_CLKSEL_L3_SHADOW_MASK				(1 << 2)
 
-/* Used by CM_CLKSEL_CORE_RESTORE, CM_CLKSEL_CORE */
+/* Used by CM_CLKSEL_CORE, CM_CLKSEL_CORE_RESTORE */
 #define OMAP4430_CLKSEL_L4_SHIFT				8
-#define OMAP4430_CLKSEL_L4_MASK					BITFIELD(8, 8)
+#define OMAP4430_CLKSEL_L4_MASK					(1 << 8)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_CLKSEL_OPP_SHIFT				0
-#define OMAP4430_CLKSEL_OPP_MASK				BITFIELD(0, 1)
-
-/* Used by CM_GFX_GFX_CLKCTRL */
-#define OMAP4430_CLKSEL_PER_192M_SHIFT				25
-#define OMAP4430_CLKSEL_PER_192M_MASK				BITFIELD(25, 26)
+#define OMAP4430_CLKSEL_OPP_MASK				(0x3 << 0)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT			27
-#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK			BITFIELD(27, 29)
+#define OMAP4430_CLKSEL_PMD_STM_CLK_MASK			(0x7 << 27)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_CLKSEL_PMD_TRACE_CLK_SHIFT			24
-#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK			BITFIELD(24, 26)
+#define OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK			(0x7 << 24)
 
 /* Used by CM_GFX_GFX_CLKCTRL */
 #define OMAP4430_CLKSEL_SGX_FCLK_SHIFT				24
-#define OMAP4430_CLKSEL_SGX_FCLK_MASK				BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SGX_FCLK_MASK				(1 << 24)
 
 /*
  * Used by CM1_ABE_DMIC_CLKCTRL, CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL,
  * CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL
  */
 #define OMAP4430_CLKSEL_SOURCE_SHIFT				24
-#define OMAP4430_CLKSEL_SOURCE_MASK				BITFIELD(24, 25)
+#define OMAP4430_CLKSEL_SOURCE_MASK				(0x3 << 24)
 
 /* Renamed from CLKSEL_SOURCE Used by CM_L4PER_MCBSP4_CLKCTRL */
 #define OMAP4430_CLKSEL_SOURCE_24_24_SHIFT			24
-#define OMAP4430_CLKSEL_SOURCE_24_24_MASK			BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_SOURCE_24_24_MASK			(1 << 24)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_CLKSEL_UTMI_P1_SHIFT				24
-#define OMAP4430_CLKSEL_UTMI_P1_MASK				BITFIELD(24, 24)
+#define OMAP4430_CLKSEL_UTMI_P1_MASK				(1 << 24)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_CLKSEL_UTMI_P2_SHIFT				25
-#define OMAP4430_CLKSEL_UTMI_P2_MASK				BITFIELD(25, 25)
+#define OMAP4430_CLKSEL_UTMI_P2_MASK				(1 << 25)
 
 /*
- * Used by CM_WKUP_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_D2D_CLKSTCTRL,
- * CM_DUCATI_CLKSTCTRL, CM_L3INSTR_CLKSTCTRL, CM_L3_1_CLKSTCTRL,
- * CM_L3_2_CLKSTCTRL, CM_L4CFG_CLKSTCTRL, CM_MEMIF_CLKSTCTRL,
- * CM_SDMA_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_L4PER_CLKSTCTRL, CM_L4SEC_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL, CM_CAM_CLKSTCTRL, CM_CEFUSE_CLKSTCTRL,
- * CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3_1_CLKSTCTRL_RESTORE,
- * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL_RESTORE,
- * CM_L4PER_CLKSTCTRL_RESTORE, CM_MEMIF_CLKSTCTRL_RESTORE, CM_ALWON_CLKSTCTRL,
- * CM_IVAHD_CLKSTCTRL, CM_DSS_CLKSTCTRL, CM_MPU_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
- * CM1_ABE_CLKSTCTRL, CM_MPU_CLKSTCTRL_RESTORE
+ * Used by CM1_ABE_CLKSTCTRL, CM_ALWON_CLKSTCTRL, CM_CAM_CLKSTCTRL,
+ * CM_CEFUSE_CLKSTCTRL, CM_D2D_CLKSTCTRL, CM_DSS_CLKSTCTRL,
+ * CM_DUCATI_CLKSTCTRL, CM_EMU_CLKSTCTRL, CM_GFX_CLKSTCTRL, CM_IVAHD_CLKSTCTRL,
+ * CM_L3INIT_CLKSTCTRL, CM_L3INIT_CLKSTCTRL_RESTORE, CM_L3INSTR_CLKSTCTRL,
+ * CM_L3_1_CLKSTCTRL, CM_L3_1_CLKSTCTRL_RESTORE, CM_L3_2_CLKSTCTRL,
+ * CM_L3_2_CLKSTCTRL_RESTORE, CM_L4CFG_CLKSTCTRL, CM_L4CFG_CLKSTCTRL_RESTORE,
+ * CM_L4PER_CLKSTCTRL, CM_L4PER_CLKSTCTRL_RESTORE, CM_L4SEC_CLKSTCTRL,
+ * CM_MEMIF_CLKSTCTRL, CM_MEMIF_CLKSTCTRL_RESTORE, CM_MPU_CLKSTCTRL,
+ * CM_MPU_CLKSTCTRL_RESTORE, CM_SDMA_CLKSTCTRL, CM_TESLA_CLKSTCTRL,
+ * CM_WKUP_CLKSTCTRL
  */
 #define OMAP4430_CLKTRCTRL_SHIFT				0
-#define OMAP4430_CLKTRCTRL_MASK					BITFIELD(0, 1)
+#define OMAP4430_CLKTRCTRL_MASK					(0x3 << 0)
 
 /* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_CORE_DPLL_EMU_DIV_SHIFT			0
-#define OMAP4430_CORE_DPLL_EMU_DIV_MASK				BITFIELD(0, 6)
+#define OMAP4430_CORE_DPLL_EMU_DIV_MASK				(0x7f << 0)
 
 /* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_CORE_DPLL_EMU_MULT_SHIFT			8
-#define OMAP4430_CORE_DPLL_EMU_MULT_MASK			BITFIELD(8, 18)
+#define OMAP4430_CORE_DPLL_EMU_MULT_MASK			(0x7ff << 8)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_CUSTOM_SHIFT					6
+#define OMAP4430_CUSTOM_MASK					(0x3 << 6)
+
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_D2D_DYNDEP_SHIFT				18
-#define OMAP4430_D2D_DYNDEP_MASK				BITFIELD(18, 18)
+#define OMAP4430_D2D_DYNDEP_MASK				(1 << 18)
 
 /* Used by CM_MPU_STATICDEP */
 #define OMAP4430_D2D_STATDEP_SHIFT				18
-#define OMAP4430_D2D_STATDEP_MASK				BITFIELD(18, 18)
+#define OMAP4430_D2D_STATDEP_MASK				(1 << 18)
 
 /*
- * Used by CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
- * CM_SSC_DELTAMSTEP_DPLL_USB, CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE,
- * CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
- * CM_SSC_DELTAMSTEP_DPLL_DDRPHY, CM_SSC_DELTAMSTEP_DPLL_IVA,
- * CM_SSC_DELTAMSTEP_DPLL_MPU
+ * Used by CM_SSC_DELTAMSTEP_DPLL_ABE, CM_SSC_DELTAMSTEP_DPLL_CORE,
+ * CM_SSC_DELTAMSTEP_DPLL_CORE_RESTORE, CM_SSC_DELTAMSTEP_DPLL_DDRPHY,
+ * CM_SSC_DELTAMSTEP_DPLL_IVA, CM_SSC_DELTAMSTEP_DPLL_MPU,
+ * CM_SSC_DELTAMSTEP_DPLL_PER, CM_SSC_DELTAMSTEP_DPLL_UNIPRO,
+ * CM_SSC_DELTAMSTEP_DPLL_USB
  */
 #define OMAP4430_DELTAMSTEP_SHIFT				0
-#define OMAP4430_DELTAMSTEP_MASK				BITFIELD(0, 19)
+#define OMAP4430_DELTAMSTEP_MASK				(0xfffff << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DLL_OVERRIDE_SHIFT				2
-#define OMAP4430_DLL_OVERRIDE_MASK				BITFIELD(2, 2)
+#define OMAP4430_DLL_OVERRIDE_MASK				(1 << 2)
 
 /* Renamed from DLL_OVERRIDE Used by CM_DLL_CTRL */
 #define OMAP4430_DLL_OVERRIDE_0_0_SHIFT				0
-#define OMAP4430_DLL_OVERRIDE_0_0_MASK				BITFIELD(0, 0)
+#define OMAP4430_DLL_OVERRIDE_0_0_MASK				(1 << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DLL_RESET_SHIFT				3
-#define OMAP4430_DLL_RESET_MASK					BITFIELD(3, 3)
+#define OMAP4430_DLL_RESET_MASK					(1 << 3)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO, CM_CLKSEL_DPLL_USB,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
+ * CM_CLKSEL_DPLL_USB
  */
 #define OMAP4430_DPLL_BYP_CLKSEL_SHIFT				23
-#define OMAP4430_DPLL_BYP_CLKSEL_MASK				BITFIELD(23, 23)
+#define OMAP4430_DPLL_BYP_CLKSEL_MASK				(1 << 23)
 
 /* Used by CM_CLKDCOLDO_DPLL_USB */
 #define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_SHIFT			8
-#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK			BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKDCOLDO_GATE_CTRL_MASK			(1 << 8)
 
-/* Used by CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_CORE */
+/* Used by CM_CLKSEL_DPLL_CORE, CM_CLKSEL_DPLL_CORE_RESTORE */
 #define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_SHIFT			20
-#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK			BITFIELD(20, 20)
+#define OMAP4430_DPLL_CLKOUTHIF_CLKSEL_MASK			(1 << 20)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_DIV_SHIFT			0
-#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK			BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUTHIF_DIV_MASK			(0x1f << 0)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_SHIFT			5
-#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK			BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUTHIF_DIVCHACK_MASK			(1 << 5)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT			8
-#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK			BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_MASK			(1 << 8)
 
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
 #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_SHIFT			10
-#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK			BITFIELD(10, 10)
+#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK			(1 << 10)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_CLKOUT_DIV_SHIFT				0
-#define OMAP4430_DPLL_CLKOUT_DIV_MASK				BITFIELD(0, 4)
+#define OMAP4430_DPLL_CLKOUT_DIV_MASK				(0x1f << 0)
 
 /* Renamed from DPLL_CLKOUT_DIV Used by CM_DIV_M2_DPLL_USB */
 #define OMAP4430_DPLL_CLKOUT_DIV_0_6_SHIFT			0
-#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK			BITFIELD(0, 6)
+#define OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK			(0x7f << 0)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO,
- * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
- * CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_SHIFT			5
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK			BITFIELD(5, 5)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_MASK			(1 << 5)
 
 /* Renamed from DPLL_CLKOUT_DIVCHACK Used by CM_DIV_M2_DPLL_USB */
 #define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_SHIFT		7
-#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK		BITFIELD(7, 7)
+#define OMAP4430_DPLL_CLKOUT_DIVCHACK_M2_USB_MASK		(1 << 7)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
  */
 #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_SHIFT			8
-#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK			BITFIELD(8, 8)
+#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK			(1 << 8)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DPLL_CORE_DPLL_EN_SHIFT			8
-#define OMAP4430_DPLL_CORE_DPLL_EN_MASK				BITFIELD(8, 10)
+#define OMAP4430_DPLL_CORE_DPLL_EN_MASK				(0x7 << 8)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_DPLL_CORE_M2_DIV_SHIFT				11
-#define OMAP4430_DPLL_CORE_M2_DIV_MASK				BITFIELD(11, 15)
+#define OMAP4430_DPLL_CORE_M2_DIV_MASK				(0x1f << 11)
 
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
 #define OMAP4430_DPLL_CORE_M5_DIV_SHIFT				3
-#define OMAP4430_DPLL_CORE_M5_DIV_MASK				BITFIELD(3, 7)
-
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_SHIFT			1
-#define OMAP4430_DPLL_CORE_SYS_REF_CLKSEL_MASK			BITFIELD(1, 1)
+#define OMAP4430_DPLL_CORE_M5_DIV_MASK				(0x1f << 3)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_DIV_SHIFT					0
-#define OMAP4430_DPLL_DIV_MASK					BITFIELD(0, 6)
+#define OMAP4430_DPLL_DIV_MASK					(0x7f << 0)
 
 /* Renamed from DPLL_DIV Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_DIV_0_7_SHIFT				0
-#define OMAP4430_DPLL_DIV_0_7_MASK				BITFIELD(0, 7)
+#define OMAP4430_DPLL_DIV_0_7_MASK				(0xff << 0)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER
  */
 #define OMAP4430_DPLL_DRIFTGUARD_EN_SHIFT			8
-#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK			BITFIELD(8, 8)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_MASK			(1 << 8)
 
 /* Renamed from DPLL_DRIFTGUARD_EN Used by CM_CLKMODE_DPLL_UNIPRO */
 #define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_SHIFT			3
-#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK			BITFIELD(3, 3)
+#define OMAP4430_DPLL_DRIFTGUARD_EN_3_3_MASK			(1 << 3)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_EN_SHIFT					0
-#define OMAP4430_DPLL_EN_MASK					BITFIELD(0, 2)
+#define OMAP4430_DPLL_EN_MASK					(0x7 << 0)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_LPMODE_EN_SHIFT				10
-#define OMAP4430_DPLL_LPMODE_EN_MASK				BITFIELD(10, 10)
+#define OMAP4430_DPLL_LPMODE_EN_MASK				(1 << 10)
 
 /*
- * Used by CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO,
- * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
- * CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA, CM_CLKSEL_DPLL_MPU
+ * Used by CM_CLKSEL_DPLL_ABE, CM_CLKSEL_DPLL_CORE,
+ * CM_CLKSEL_DPLL_CORE_RESTORE, CM_CLKSEL_DPLL_DDRPHY, CM_CLKSEL_DPLL_IVA,
+ * CM_CLKSEL_DPLL_MPU, CM_CLKSEL_DPLL_PER, CM_CLKSEL_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_MULT_SHIFT				8
-#define OMAP4430_DPLL_MULT_MASK					BITFIELD(8, 18)
+#define OMAP4430_DPLL_MULT_MASK					(0x7ff << 8)
 
 /* Renamed from DPLL_MULT Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_MULT_USB_SHIFT				8
-#define OMAP4430_DPLL_MULT_USB_MASK				BITFIELD(8, 19)
+#define OMAP4430_DPLL_MULT_USB_MASK				(0xfff << 8)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO
  */
 #define OMAP4430_DPLL_REGM4XEN_SHIFT				11
-#define OMAP4430_DPLL_REGM4XEN_MASK				BITFIELD(11, 11)
+#define OMAP4430_DPLL_REGM4XEN_MASK				(1 << 11)
 
 /* Used by CM_CLKSEL_DPLL_USB */
 #define OMAP4430_DPLL_SD_DIV_SHIFT				24
-#define OMAP4430_DPLL_SD_DIV_MASK				BITFIELD(24, 31)
+#define OMAP4430_DPLL_SD_DIV_MASK				(0xff << 24)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_ACK_SHIFT				13
-#define OMAP4430_DPLL_SSC_ACK_MASK				BITFIELD(13, 13)
+#define OMAP4430_DPLL_SSC_ACK_MASK				(1 << 13)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_DOWNSPREAD_SHIFT			14
-#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK			BITFIELD(14, 14)
+#define OMAP4430_DPLL_SSC_DOWNSPREAD_MASK			(1 << 14)
 
 /*
- * Used by CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO, CM_CLKMODE_DPLL_USB,
- * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
- * CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA, CM_CLKMODE_DPLL_MPU
+ * Used by CM_CLKMODE_DPLL_ABE, CM_CLKMODE_DPLL_CORE,
+ * CM_CLKMODE_DPLL_CORE_RESTORE, CM_CLKMODE_DPLL_DDRPHY, CM_CLKMODE_DPLL_IVA,
+ * CM_CLKMODE_DPLL_MPU, CM_CLKMODE_DPLL_PER, CM_CLKMODE_DPLL_UNIPRO,
+ * CM_CLKMODE_DPLL_USB
  */
 #define OMAP4430_DPLL_SSC_EN_SHIFT				12
-#define OMAP4430_DPLL_SSC_EN_MASK				BITFIELD(12, 12)
+#define OMAP4430_DPLL_SSC_EN_MASK				(1 << 12)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_DSS_DYNDEP_SHIFT				8
-#define OMAP4430_DSS_DYNDEP_MASK				BITFIELD(8, 8)
+#define OMAP4430_DSS_DYNDEP_MASK				(1 << 8)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE
  */
 #define OMAP4430_DSS_STATDEP_SHIFT				8
-#define OMAP4430_DSS_STATDEP_MASK				BITFIELD(8, 8)
+#define OMAP4430_DSS_STATDEP_MASK				(1 << 8)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_DUCATI_DYNDEP_SHIFT				0
-#define OMAP4430_DUCATI_DYNDEP_MASK				BITFIELD(0, 0)
+#define OMAP4430_DUCATI_DYNDEP_MASK				(1 << 0)
 
-/* Used by CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP */
+/* Used by CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE */
 #define OMAP4430_DUCATI_STATDEP_SHIFT				0
-#define OMAP4430_DUCATI_STATDEP_MASK				BITFIELD(0, 0)
+#define OMAP4430_DUCATI_STATDEP_MASK				(1 << 0)
 
-/* Used by CM_SHADOW_FREQ_CONFIG1_RESTORE, CM_SHADOW_FREQ_CONFIG1 */
+/* Used by CM_SHADOW_FREQ_CONFIG1, CM_SHADOW_FREQ_CONFIG1_RESTORE */
 #define OMAP4430_FREQ_UPDATE_SHIFT				0
-#define OMAP4430_FREQ_UPDATE_MASK				BITFIELD(0, 0)
+#define OMAP4430_FREQ_UPDATE_MASK				(1 << 0)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_FUNC_SHIFT					16
+#define OMAP4430_FUNC_MASK					(0xfff << 16)
+
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_GFX_DYNDEP_SHIFT				10
-#define OMAP4430_GFX_DYNDEP_MASK				BITFIELD(10, 10)
+#define OMAP4430_GFX_DYNDEP_MASK				(1 << 10)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_GFX_STATDEP_SHIFT				10
-#define OMAP4430_GFX_STATDEP_MASK				BITFIELD(10, 10)
+#define OMAP4430_GFX_STATDEP_MASK				(1 << 10)
 
-/* Used by CM_SHADOW_FREQ_CONFIG2 */
+/* Used by CM_SHADOW_FREQ_CONFIG2, CM_SHADOW_FREQ_CONFIG2_RESTORE */
 #define OMAP4430_GPMC_FREQ_UPDATE_SHIFT				0
-#define OMAP4430_GPMC_FREQ_UPDATE_MASK				BITFIELD(0, 0)
+#define OMAP4430_GPMC_FREQ_UPDATE_MASK				(1 << 0)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_DIV_SHIFT			0
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK			BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK			(0x1f << 0)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_SHIFT		5
-#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK		BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT1_DIVCHACK_MASK		(1 << 5)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_SHIFT		8
-#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK		BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT1_GATE_CTRL_MASK		(1 << 8)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_SHIFT			12
-#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK			BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT1_PWDN_MASK			(1 << 12)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_DIV_SHIFT			0
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK			BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK			(0x1f << 0)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_SHIFT		5
-#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK		BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT2_DIVCHACK_MASK		(1 << 5)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_SHIFT		8
-#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK		BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT2_GATE_CTRL_MASK		(1 << 8)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_SHIFT			12
-#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK			BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT2_PWDN_MASK			(1 << 12)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_DIV_SHIFT			0
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK			BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK			(0x1f << 0)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_SHIFT		5
-#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK		BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT3_DIVCHACK_MASK		(1 << 5)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_SHIFT		8
-#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK		BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT3_GATE_CTRL_MASK		(1 << 8)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_SHIFT			12
-#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK			BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT3_PWDN_MASK			(1 << 12)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_DIV_SHIFT			0
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK			BITFIELD(0, 4)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK			(0x1f << 0)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_SHIFT		5
-#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK		BITFIELD(5, 5)
+#define OMAP4430_HSDIVIDER_CLKOUT4_DIVCHACK_MASK		(1 << 5)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_SHIFT		8
-#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK		BITFIELD(8, 8)
+#define OMAP4430_HSDIVIDER_CLKOUT4_GATE_CTRL_MASK		(1 << 8)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_SHIFT			12
-#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK			BITFIELD(12, 12)
+#define OMAP4430_HSDIVIDER_CLKOUT4_PWDN_MASK			(1 << 12)
 
 /*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
  * CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
  */
 #define OMAP4430_IDLEST_SHIFT					16
-#define OMAP4430_IDLEST_MASK					BITFIELD(16, 17)
+#define OMAP4430_IDLEST_MASK					(0x3 << 16)
 
-/* Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP */
+/*
+ * Used by CM_DUCATI_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_ISS_DYNDEP_SHIFT				9
-#define OMAP4430_ISS_DYNDEP_MASK				BITFIELD(9, 9)
+#define OMAP4430_ISS_DYNDEP_MASK				(1 << 9)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_ISS_STATDEP_SHIFT				9
-#define OMAP4430_ISS_STATDEP_MASK				BITFIELD(9, 9)
+#define OMAP4430_ISS_STATDEP_MASK				(1 << 9)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_TESLA_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_TESLA_DYNAMICDEP */
 #define OMAP4430_IVAHD_DYNDEP_SHIFT				2
-#define OMAP4430_IVAHD_DYNDEP_MASK				BITFIELD(2, 2)
+#define OMAP4430_IVAHD_DYNDEP_MASK				(1 << 2)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_DSS_STATICDEP, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_IVAHD_STATDEP_SHIFT				2
-#define OMAP4430_IVAHD_STATDEP_MASK				BITFIELD(2, 2)
+#define OMAP4430_IVAHD_STATDEP_MASK				(1 << 2)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP, CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_L3INIT_DYNDEP_SHIFT				7
-#define OMAP4430_L3INIT_DYNDEP_MASK				BITFIELD(7, 7)
+#define OMAP4430_L3INIT_DYNDEP_MASK				(1 << 7)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_MPU_STATICDEP, CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
+ * CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3INIT_STATDEP_SHIFT				7
-#define OMAP4430_L3INIT_STATDEP_MASK				BITFIELD(7, 7)
+#define OMAP4430_L3INIT_STATDEP_MASK				(1 << 7)
 
 /*
- * Used by CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_DSS_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_DSS_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_2_DYNAMICDEP,
+ * CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
  */
 #define OMAP4430_L3_1_DYNDEP_SHIFT				5
-#define OMAP4430_L3_1_DYNDEP_MASK				BITFIELD(5, 5)
+#define OMAP4430_L3_1_DYNDEP_MASK				(1 << 5)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3_1_STATDEP_SHIFT				5
-#define OMAP4430_L3_1_STATDEP_MASK				BITFIELD(5, 5)
+#define OMAP4430_L3_1_STATDEP_MASK				(1 << 5)
 
 /*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP, CM_SDMA_DYNAMICDEP,
- * CM_GFX_DYNAMICDEP, CM_L4SEC_DYNAMICDEP, CM_L3INIT_DYNAMICDEP,
- * CM_CAM_DYNAMICDEP, CM_IVAHD_DYNAMICDEP
+ * Used by CM_CAM_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE,
+ * CM_DUCATI_DYNAMICDEP, CM_EMU_DYNAMICDEP, CM_GFX_DYNAMICDEP,
+ * CM_IVAHD_DYNAMICDEP, CM_L3INIT_DYNAMICDEP, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4SEC_DYNAMICDEP, CM_SDMA_DYNAMICDEP
  */
 #define OMAP4430_L3_2_DYNDEP_SHIFT				6
-#define OMAP4430_L3_2_DYNDEP_MASK				BITFIELD(6, 6)
+#define OMAP4430_L3_2_DYNDEP_MASK				(1 << 6)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L3_2_STATDEP_SHIFT				6
-#define OMAP4430_L3_2_STATDEP_MASK				BITFIELD(6, 6)
+#define OMAP4430_L3_2_STATDEP_MASK				(1 << 6)
 
-/* Used by CM_L3_1_DYNAMICDEP */
+/* Used by CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4CFG_DYNDEP_SHIFT				12
-#define OMAP4430_L4CFG_DYNDEP_MASK				BITFIELD(12, 12)
+#define OMAP4430_L4CFG_DYNDEP_MASK				(1 << 12)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP,
- * CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_MPU_STATICDEP, CM_SDMA_STATICDEP,
+ * CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4CFG_STATDEP_SHIFT				12
-#define OMAP4430_L4CFG_STATDEP_MASK				BITFIELD(12, 12)
+#define OMAP4430_L4CFG_STATDEP_MASK				(1 << 12)
 
-/* Used by CM_L3_2_DYNAMICDEP */
+/* Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4PER_DYNDEP_SHIFT				13
-#define OMAP4430_L4PER_DYNDEP_MASK				BITFIELD(13, 13)
+#define OMAP4430_L4PER_DYNDEP_MASK				(1 << 13)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_SDMA_STATICDEP_RESTORE,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE, CM_DUCATI_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4PER_STATDEP_SHIFT				13
-#define OMAP4430_L4PER_STATDEP_MASK				BITFIELD(13, 13)
+#define OMAP4430_L4PER_STATDEP_MASK				(1 << 13)
 
-/* Used by CM_L3_2_DYNAMICDEP, CM_L4PER_DYNAMICDEP */
+/*
+ * Used by CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE
+ */
 #define OMAP4430_L4SEC_DYNDEP_SHIFT				14
-#define OMAP4430_L4SEC_DYNDEP_MASK				BITFIELD(14, 14)
+#define OMAP4430_L4SEC_DYNDEP_MASK				(1 << 14)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE
  */
 #define OMAP4430_L4SEC_STATDEP_SHIFT				14
-#define OMAP4430_L4SEC_STATDEP_MASK				BITFIELD(14, 14)
+#define OMAP4430_L4SEC_STATDEP_MASK				(1 << 14)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_L4WKUP_DYNDEP_SHIFT				15
-#define OMAP4430_L4WKUP_DYNDEP_MASK				BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_DYNDEP_MASK				(1 << 15)
 
 /*
- * Used by CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP, CM_L3INIT_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_DUCATI_STATICDEP, CM_L3INIT_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_L4WKUP_STATDEP_SHIFT				15
-#define OMAP4430_L4WKUP_STATDEP_MASK				BITFIELD(15, 15)
+#define OMAP4430_L4WKUP_STATDEP_MASK				(1 << 15)
 
 /*
- * Used by CM_D2D_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_MPU_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_L3_1_DYNAMICDEP,
+ * CM_L3_1_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP
  */
 #define OMAP4430_MEMIF_DYNDEP_SHIFT				4
-#define OMAP4430_MEMIF_DYNDEP_MASK				BITFIELD(4, 4)
+#define OMAP4430_MEMIF_DYNDEP_MASK				(1 << 4)
 
 /*
- * Used by CM_D2D_STATICDEP, CM_DUCATI_STATICDEP, CM_SDMA_STATICDEP,
- * CM_GFX_STATICDEP, CM_L4SEC_STATICDEP, CM_L3INIT_STATICDEP, CM_CAM_STATICDEP,
- * CM_SDMA_STATICDEP_RESTORE, CM_IVAHD_STATICDEP, CM_DSS_STATICDEP,
- * CM_MPU_STATICDEP, CM_TESLA_STATICDEP
+ * Used by CM_CAM_STATICDEP, CM_D2D_STATICDEP, CM_D2D_STATICDEP_RESTORE,
+ * CM_DSS_STATICDEP, CM_DUCATI_STATICDEP, CM_GFX_STATICDEP, CM_IVAHD_STATICDEP,
+ * CM_L3INIT_STATICDEP, CM_L4SEC_STATICDEP, CM_MPU_STATICDEP,
+ * CM_SDMA_STATICDEP, CM_SDMA_STATICDEP_RESTORE, CM_TESLA_STATICDEP
  */
 #define OMAP4430_MEMIF_STATDEP_SHIFT				4
-#define OMAP4430_MEMIF_STATDEP_MASK				BITFIELD(4, 4)
+#define OMAP4430_MEMIF_STATDEP_MASK				(1 << 4)
 
 /*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
  */
 #define OMAP4430_MODFREQDIV_EXPONENT_SHIFT			8
-#define OMAP4430_MODFREQDIV_EXPONENT_MASK			BITFIELD(8, 10)
+#define OMAP4430_MODFREQDIV_EXPONENT_MASK			(0x7 << 8)
 
 /*
- * Used by CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
- * CM_SSC_MODFREQDIV_DPLL_USB, CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE,
- * CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
- * CM_SSC_MODFREQDIV_DPLL_DDRPHY, CM_SSC_MODFREQDIV_DPLL_IVA,
- * CM_SSC_MODFREQDIV_DPLL_MPU
+ * Used by CM_SSC_MODFREQDIV_DPLL_ABE, CM_SSC_MODFREQDIV_DPLL_CORE,
+ * CM_SSC_MODFREQDIV_DPLL_CORE_RESTORE, CM_SSC_MODFREQDIV_DPLL_DDRPHY,
+ * CM_SSC_MODFREQDIV_DPLL_IVA, CM_SSC_MODFREQDIV_DPLL_MPU,
+ * CM_SSC_MODFREQDIV_DPLL_PER, CM_SSC_MODFREQDIV_DPLL_UNIPRO,
+ * CM_SSC_MODFREQDIV_DPLL_USB
  */
 #define OMAP4430_MODFREQDIV_MANTISSA_SHIFT			0
-#define OMAP4430_MODFREQDIV_MANTISSA_MASK			BITFIELD(0, 6)
+#define OMAP4430_MODFREQDIV_MANTISSA_MASK			(0x7f << 0)
 
 /*
- * Used by PRM_PRM_PROFILING_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL,
- * CM_WKUP_KEYBOARD_CLKCTRL, CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL,
- * CM_WKUP_SARRAM_CLKCTRL, CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL,
- * CM_WKUP_TIMER1_CLKCTRL, CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL,
- * CM_WKUP_WDT2_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_MODEM_ICR_CLKCTRL,
- * CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
- * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL,
- * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL,
- * CM_L3_2_L3_2_CLKCTRL, CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL,
- * CM_L4CFG_L4_CFG_CLKCTRL, CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL,
- * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
- * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
- * CM_MEMIF_EMIF_H2_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4PER_ADC_CLKCTRL, CM_L4PER_DMTIMER10_CLKCTRL,
- * CM_L4PER_DMTIMER11_CLKCTRL, CM_L4PER_DMTIMER2_CLKCTRL,
- * CM_L4PER_DMTIMER3_CLKCTRL, CM_L4PER_DMTIMER4_CLKCTRL,
- * CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL,
- * CM_L4PER_HECC2_CLKCTRL, CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL,
- * CM_L4PER_I2C3_CLKCTRL, CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL,
- * CM_L4PER_L4PER_CLKCTRL, CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL,
- * CM_L4PER_MCBSP4_CLKCTRL, CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL,
- * CM_L4PER_MCSPI3_CLKCTRL, CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL,
- * CM_L4PER_MMCSD3_CLKCTRL, CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL,
- * CM_L4PER_MSPROHG_CLKCTRL, CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL,
- * CM_L4PER_UART2_CLKCTRL, CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL,
- * CM_L4SEC_AES1_CLKCTRL, CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL,
- * CM_L4SEC_DES3DES_CLKCTRL, CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL,
- * CM_L4SEC_SHA2MD51_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+ * Used by CM1_ABE_AESS_CLKCTRL, CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL,
+ * CM1_ABE_MCASP_CLKCTRL, CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL,
+ * CM1_ABE_MCBSP3_CLKCTRL, CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL,
+ * CM1_ABE_TIMER5_CLKCTRL, CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL,
+ * CM1_ABE_TIMER8_CLKCTRL, CM1_ABE_WDT3_CLKCTRL, CM_ALWON_MDMINTC_CLKCTRL,
+ * CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL, CM_ALWON_SR_MPU_CLKCTRL,
+ * CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
+ * CM_CM1_PROFILING_CLKCTRL, CM_CM1_PROFILING_CLKCTRL_RESTORE,
+ * CM_CM2_PROFILING_CLKCTRL, CM_CM2_PROFILING_CLKCTRL_RESTORE,
+ * CM_D2D_MODEM_ICR_CLKCTRL, CM_D2D_SAD2D_CLKCTRL, CM_D2D_SAD2D_FW_CLKCTRL,
+ * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_DUCATI_DUCATI_CLKCTRL,
+ * CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL,
+ * CM_IVAHD_SL2_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
  * CM_L3INIT_USBPHYOCP2SCP_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL,
- * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
- * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_CEFUSE_CEFUSE_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE,
- * CM_L3INSTR_L3_3_CLKCTRL_RESTORE, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
- * CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
- * CM_ALWON_MDMINTC_CLKCTRL, CM_ALWON_SR_CORE_CLKCTRL, CM_ALWON_SR_IVA_CLKCTRL,
- * CM_ALWON_SR_MPU_CLKCTRL, CM_IVAHD_IVAHD_CLKCTRL, CM_IVAHD_SL2_CLKCTRL,
- * CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL, CM_CM2_PROFILING_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL,
- * CM1_ABE_DMIC_CLKCTRL, CM1_ABE_L4ABE_CLKCTRL, CM1_ABE_MCASP_CLKCTRL,
- * CM1_ABE_MCBSP1_CLKCTRL, CM1_ABE_MCBSP2_CLKCTRL, CM1_ABE_MCBSP3_CLKCTRL,
- * CM1_ABE_PDM_CLKCTRL, CM1_ABE_SLIMBUS_CLKCTRL, CM1_ABE_TIMER5_CLKCTRL,
- * CM1_ABE_TIMER6_CLKCTRL, CM1_ABE_TIMER7_CLKCTRL, CM1_ABE_TIMER8_CLKCTRL,
- * CM1_ABE_WDT3_CLKCTRL, CM_CM1_PROFILING_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_HOST_FS_CLKCTRL,
+ * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
+ * CM_L3INIT_USB_TLL_CLKCTRL_RESTORE, CM_L3INIT_XHPI_CLKCTRL,
+ * CM_L3INSTR_L3_3_CLKCTRL, CM_L3INSTR_L3_3_CLKCTRL_RESTORE,
+ * CM_L3INSTR_L3_INSTR_CLKCTRL, CM_L3INSTR_L3_INSTR_CLKCTRL_RESTORE,
+ * CM_L3INSTR_OCP_WP1_CLKCTRL, CM_L3INSTR_OCP_WP1_CLKCTRL_RESTORE,
+ * CM_L3_1_L3_1_CLKCTRL, CM_L3_2_GPMC_CLKCTRL, CM_L3_2_L3_2_CLKCTRL,
+ * CM_L3_2_OCMC_RAM_CLKCTRL, CM_L4CFG_HW_SEM_CLKCTRL, CM_L4CFG_L4_CFG_CLKCTRL,
+ * CM_L4CFG_MAILBOX_CLKCTRL, CM_L4CFG_SAR_ROM_CLKCTRL, CM_L4PER_ADC_CLKCTRL,
+ * CM_L4PER_DMTIMER10_CLKCTRL, CM_L4PER_DMTIMER11_CLKCTRL,
+ * CM_L4PER_DMTIMER2_CLKCTRL, CM_L4PER_DMTIMER3_CLKCTRL,
+ * CM_L4PER_DMTIMER4_CLKCTRL, CM_L4PER_DMTIMER9_CLKCTRL, CM_L4PER_ELM_CLKCTRL,
+ * CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE,
+ * CM_L4PER_HDQ1W_CLKCTRL, CM_L4PER_HECC1_CLKCTRL, CM_L4PER_HECC2_CLKCTRL,
+ * CM_L4PER_I2C1_CLKCTRL, CM_L4PER_I2C2_CLKCTRL, CM_L4PER_I2C3_CLKCTRL,
+ * CM_L4PER_I2C4_CLKCTRL, CM_L4PER_I2C5_CLKCTRL, CM_L4PER_L4PER_CLKCTRL,
+ * CM_L4PER_MCASP2_CLKCTRL, CM_L4PER_MCASP3_CLKCTRL, CM_L4PER_MCBSP4_CLKCTRL,
+ * CM_L4PER_MCSPI1_CLKCTRL, CM_L4PER_MCSPI2_CLKCTRL, CM_L4PER_MCSPI3_CLKCTRL,
+ * CM_L4PER_MCSPI4_CLKCTRL, CM_L4PER_MGATE_CLKCTRL, CM_L4PER_MMCSD3_CLKCTRL,
+ * CM_L4PER_MMCSD4_CLKCTRL, CM_L4PER_MMCSD5_CLKCTRL, CM_L4PER_MSPROHG_CLKCTRL,
+ * CM_L4PER_SLIMBUS2_CLKCTRL, CM_L4PER_UART1_CLKCTRL, CM_L4PER_UART2_CLKCTRL,
+ * CM_L4PER_UART3_CLKCTRL, CM_L4PER_UART4_CLKCTRL, CM_L4SEC_AES1_CLKCTRL,
+ * CM_L4SEC_AES2_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L4SEC_DES3DES_CLKCTRL,
+ * CM_L4SEC_PKAEIP29_CLKCTRL, CM_L4SEC_RNG_CLKCTRL, CM_L4SEC_SHA2MD51_CLKCTRL,
+ * CM_MEMIF_DMM_CLKCTRL, CM_MEMIF_EMIF_1_CLKCTRL, CM_MEMIF_EMIF_2_CLKCTRL,
+ * CM_MEMIF_EMIF_FW_CLKCTRL, CM_MEMIF_EMIF_H1_CLKCTRL,
+ * CM_MEMIF_EMIF_H2_CLKCTRL, CM_MPU_MPU_CLKCTRL, CM_SDMA_SDMA_CLKCTRL,
+ * CM_TESLA_TESLA_CLKCTRL, CM_WKUP_GPIO1_CLKCTRL, CM_WKUP_KEYBOARD_CLKCTRL,
+ * CM_WKUP_L4WKUP_CLKCTRL, CM_WKUP_RTC_CLKCTRL, CM_WKUP_SARRAM_CLKCTRL,
+ * CM_WKUP_SYNCTIMER_CLKCTRL, CM_WKUP_TIMER12_CLKCTRL, CM_WKUP_TIMER1_CLKCTRL,
+ * CM_WKUP_USIM_CLKCTRL, CM_WKUP_WDT1_CLKCTRL, CM_WKUP_WDT2_CLKCTRL
  */
 #define OMAP4430_MODULEMODE_SHIFT				0
-#define OMAP4430_MODULEMODE_MASK				BITFIELD(0, 1)
+#define OMAP4430_MODULEMODE_MASK				(0x3 << 0)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT			9
-#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_48MHZ_CLK_MASK			(1 << 9)
 
 /* Used by CM_WKUP_BANDGAP_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT			8
-#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK			BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_BGAP_32K_MASK			(1 << 8)
 
-/* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
-#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT				9
-#define OMAP4430_OPTFCLKEN_CLK32K_MASK				BITFIELD(9, 9)
+/* Used by CM_ALWON_USBPHY_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_CLK32K_SHIFT				8
+#define OMAP4430_OPTFCLKEN_CLK32K_MASK				(1 << 8)
 
 /* Used by CM_CAM_ISS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_CTRLCLK_MASK				(1 << 8)
 
 /*
- * Used by CM_WKUP_GPIO1_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL,
- * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL,
- * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO3_CLKCTRL_RESTORE, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
- * CM_L4PER_GPIO5_CLKCTRL_RESTORE, CM_L4PER_GPIO6_CLKCTRL_RESTORE
+ * Used by CM_L4PER_GPIO2_CLKCTRL, CM_L4PER_GPIO2_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO3_CLKCTRL, CM_L4PER_GPIO3_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO4_CLKCTRL, CM_L4PER_GPIO4_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO5_CLKCTRL, CM_L4PER_GPIO5_CLKCTRL_RESTORE,
+ * CM_L4PER_GPIO6_CLKCTRL, CM_L4PER_GPIO6_CLKCTRL_RESTORE, CM_WKUP_GPIO1_CLKCTRL
  */
 #define OMAP4430_OPTFCLKEN_DBCLK_SHIFT				8
-#define OMAP4430_OPTFCLKEN_DBCLK_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DBCLK_MASK				(1 << 8)
 
 /* Used by CM_MEMIF_DLL_CLKCTRL, CM_MEMIF_DLL_H_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_DLL_CLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DLL_CLK_MASK				(1 << 8)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_DSSCLK_SHIFT				8
-#define OMAP4430_OPTFCLKEN_DSSCLK_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_DSSCLK_MASK				(1 << 8)
+
+/* Used by CM_WKUP_USIM_CLKCTRL */
+#define OMAP4430_OPTFCLKEN_FCLK_SHIFT				8
+#define OMAP4430_OPTFCLKEN_FCLK_MASK				(1 << 8)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK0_SHIFT				8
-#define OMAP4430_OPTFCLKEN_FCLK0_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_FCLK0_MASK				(1 << 8)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK1_SHIFT				9
-#define OMAP4430_OPTFCLKEN_FCLK1_MASK				BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_FCLK1_MASK				(1 << 9)
 
 /* Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_FCLK2_SHIFT				10
-#define OMAP4430_OPTFCLKEN_FCLK2_MASK				BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_FCLK2_MASK				(1 << 10)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT			15
-#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK			BITFIELD(15, 15)
+#define OMAP4430_OPTFCLKEN_FUNC48MCLK_MASK			(1 << 15)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT		13
-#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK			BITFIELD(13, 13)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_MASK			(1 << 13)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT		14
-#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK			BITFIELD(14, 14)
+#define OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_MASK			(1 << 14)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT			11
-#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK			BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_MASK			(1 << 11)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT			12
-#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK			BITFIELD(12, 12)
+#define OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_MASK			(1 << 12)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PER24MC_GFCLK_MASK			(1 << 8)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT		9
-#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_MASK			(1 << 9)
 
 /* Used by CM_L3INIT_USBPHYOCP2SCP_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_PHY_48M_SHIFT			8
-#define OMAP4430_OPTFCLKEN_PHY_48M_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_PHY_48M_MASK				(1 << 8)
 
 /* Used by CM_L4PER_SLIMBUS2_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT			10
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_MASK			(1 << 10)
 
 /* Renamed from OPTFCLKEN_SLIMBUS_CLK Used by CM1_ABE_SLIMBUS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT		11
-#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK		BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_MASK		(1 << 11)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT			10
-#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK				BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_SYS_CLK_MASK				(1 << 10)
 
 /* Used by CM_DSS_DSS_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_TV_CLK_SHIFT				11
-#define OMAP4430_OPTFCLKEN_TV_CLK_MASK				BITFIELD(11, 11)
+#define OMAP4430_OPTFCLKEN_TV_CLK_MASK				(1 << 11)
 
 /* Used by CM_L3INIT_UNIPRO1_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_TXPHYCLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_TXPHYCLK_MASK			(1 << 8)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_USB_CH0_CLK_MASK			(1 << 8)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT			9
-#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_USB_CH1_CLK_MASK			(1 << 9)
 
 /* Used by CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT			10
-#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_USB_CH2_CLK_MASK			(1 << 10)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT			8
-#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK			BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_UTMI_P1_CLK_MASK			(1 << 8)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT			9
-#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK			BITFIELD(9, 9)
+#define OMAP4430_OPTFCLKEN_UTMI_P2_CLK_MASK			(1 << 9)
 
 /* Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE */
 #define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT			10
-#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK			BITFIELD(10, 10)
+#define OMAP4430_OPTFCLKEN_UTMI_P3_CLK_MASK			(1 << 10)
 
 /* Used by CM_L3INIT_USB_OTG_CLKCTRL */
 #define OMAP4430_OPTFCLKEN_XCLK_SHIFT				8
-#define OMAP4430_OPTFCLKEN_XCLK_MASK				BITFIELD(8, 8)
+#define OMAP4430_OPTFCLKEN_XCLK_MASK				(1 << 8)
 
-/* Used by CM_EMU_OVERRIDE_DPLL_PER, CM_EMU_OVERRIDE_DPLL_CORE */
+/* Used by CM_EMU_OVERRIDE_DPLL_CORE */
 #define OMAP4430_OVERRIDE_ENABLE_SHIFT				19
-#define OMAP4430_OVERRIDE_ENABLE_MASK				BITFIELD(19, 19)
+#define OMAP4430_OVERRIDE_ENABLE_MASK				(1 << 19)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_PAD_CLKS_GATE_SHIFT				8
-#define OMAP4430_PAD_CLKS_GATE_MASK				BITFIELD(8, 8)
+#define OMAP4430_PAD_CLKS_GATE_MASK				(1 << 8)
 
 /* Used by CM_CORE_DVFS_CURRENT, CM_IVA_DVFS_CURRENT */
 #define OMAP4430_PERF_CURRENT_SHIFT				0
-#define OMAP4430_PERF_CURRENT_MASK				BITFIELD(0, 7)
+#define OMAP4430_PERF_CURRENT_MASK				(0xff << 0)
 
 /*
  * Used by CM_CORE_DVFS_PERF1, CM_CORE_DVFS_PERF2, CM_CORE_DVFS_PERF3,
@@ -1316,159 +1355,173 @@
  * CM_IVA_DVFS_PERF_TESLA
  */
 #define OMAP4430_PERF_REQ_SHIFT					0
-#define OMAP4430_PERF_REQ_MASK					BITFIELD(0, 7)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_DIV_SHIFT				0
-#define OMAP4430_PER_DPLL_EMU_DIV_MASK				BITFIELD(0, 6)
-
-/* Used by CM_EMU_OVERRIDE_DPLL_PER */
-#define OMAP4430_PER_DPLL_EMU_MULT_SHIFT			8
-#define OMAP4430_PER_DPLL_EMU_MULT_MASK				BITFIELD(8, 18)
+#define OMAP4430_PERF_REQ_MASK					(0xff << 0)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE1_COMPLETED_SHIFT				0
-#define OMAP4430_PHASE1_COMPLETED_MASK				BITFIELD(0, 0)
+#define OMAP4430_PHASE1_COMPLETED_MASK				(1 << 0)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE2A_COMPLETED_SHIFT			1
-#define OMAP4430_PHASE2A_COMPLETED_MASK				BITFIELD(1, 1)
+#define OMAP4430_PHASE2A_COMPLETED_MASK				(1 << 1)
 
 /* Used by CM_RESTORE_ST */
 #define OMAP4430_PHASE2B_COMPLETED_SHIFT			2
-#define OMAP4430_PHASE2B_COMPLETED_MASK				BITFIELD(2, 2)
+#define OMAP4430_PHASE2B_COMPLETED_MASK				(1 << 2)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_PMD_STM_MUX_CTRL_SHIFT				20
-#define OMAP4430_PMD_STM_MUX_CTRL_MASK				BITFIELD(20, 21)
+#define OMAP4430_PMD_STM_MUX_CTRL_MASK				(0x3 << 20)
 
 /* Used by CM_EMU_DEBUGSS_CLKCTRL */
 #define OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT			22
-#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK			BITFIELD(22, 23)
+#define OMAP4430_PMD_TRACE_MUX_CTRL_MASK			(0x3 << 22)
 
-/* Used by CM_DYN_DEP_PRESCAL */
+/* Used by CM_DYN_DEP_PRESCAL, CM_DYN_DEP_PRESCAL_RESTORE */
 #define OMAP4430_PRESCAL_SHIFT					0
-#define OMAP4430_PRESCAL_MASK					BITFIELD(0, 5)
+#define OMAP4430_PRESCAL_MASK					(0x3f << 0)
 
-/* Used by REVISION_CM2, REVISION_CM1 */
-#define OMAP4430_REV_SHIFT					0
-#define OMAP4430_REV_MASK					BITFIELD(0, 7)
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_R_RTL_SHIFT					11
+#define OMAP4430_R_RTL_MASK					(0x1f << 11)
 
 /*
- * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL_RESTORE, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
+ * Used by CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_TLL_CLKCTRL, CM_L3INIT_USB_TLL_CLKCTRL_RESTORE
  */
 #define OMAP4430_SAR_MODE_SHIFT					4
-#define OMAP4430_SAR_MODE_MASK					BITFIELD(4, 4)
+#define OMAP4430_SAR_MODE_MASK					(1 << 4)
 
 /* Used by CM_SCALE_FCLK */
 #define OMAP4430_SCALE_FCLK_SHIFT				0
-#define OMAP4430_SCALE_FCLK_MASK				BITFIELD(0, 0)
+#define OMAP4430_SCALE_FCLK_MASK				(1 << 0)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_SCHEME_SHIFT					30
+#define OMAP4430_SCHEME_MASK					(0x3 << 30)
+
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_SDMA_DYNDEP_SHIFT				11
-#define OMAP4430_SDMA_DYNDEP_MASK				BITFIELD(11, 11)
+#define OMAP4430_SDMA_DYNDEP_MASK				(1 << 11)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_SDMA_STATDEP_SHIFT				11
-#define OMAP4430_SDMA_STATDEP_MASK				BITFIELD(11, 11)
+#define OMAP4430_SDMA_STATDEP_MASK				(1 << 11)
 
 /* Used by CM_CLKSEL_ABE */
 #define OMAP4430_SLIMBUS_CLK_GATE_SHIFT				10
-#define OMAP4430_SLIMBUS_CLK_GATE_MASK				BITFIELD(10, 10)
+#define OMAP4430_SLIMBUS_CLK_GATE_MASK				(1 << 10)
 
 /*
- * Used by CM_EMU_DEBUGSS_CLKCTRL, CM_D2D_SAD2D_CLKCTRL,
- * CM_DUCATI_DUCATI_CLKCTRL, CM_SDMA_SDMA_CLKCTRL, CM_GFX_GFX_CLKCTRL,
- * CM_L4SEC_CRYPTODMA_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
+ * Used by CM1_ABE_AESS_CLKCTRL, CM_CAM_FDIF_CLKCTRL, CM_CAM_ISS_CLKCTRL,
+ * CM_D2D_SAD2D_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
+ * CM_DUCATI_DUCATI_CLKCTRL, CM_EMU_DEBUGSS_CLKCTRL, CM_GFX_GFX_CLKCTRL,
+ * CM_IVAHD_IVAHD_CLKCTRL, CM_L3INIT_CCPTX_CLKCTRL, CM_L3INIT_EMAC_CLKCTRL,
  * CM_L3INIT_HSI_CLKCTRL, CM_L3INIT_MMC1_CLKCTRL, CM_L3INIT_MMC2_CLKCTRL,
  * CM_L3INIT_MMC6_CLKCTRL, CM_L3INIT_P1500_CLKCTRL, CM_L3INIT_PCIESS_CLKCTRL,
  * CM_L3INIT_SATA_CLKCTRL, CM_L3INIT_TPPSS_CLKCTRL, CM_L3INIT_UNIPRO1_CLKCTRL,
- * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_FS_CLKCTRL,
- * CM_L3INIT_USB_OTG_CLKCTRL, CM_L3INIT_XHPI_CLKCTRL, CM_CAM_FDIF_CLKCTRL,
- * CM_CAM_ISS_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
- * CM_IVAHD_IVAHD_CLKCTRL, CM_DSS_DEISS_CLKCTRL, CM_DSS_DSS_CLKCTRL,
- * CM_MPU_MPU_CLKCTRL, CM_TESLA_TESLA_CLKCTRL, CM1_ABE_AESS_CLKCTRL
+ * CM_L3INIT_USB_HOST_CLKCTRL, CM_L3INIT_USB_HOST_CLKCTRL_RESTORE,
+ * CM_L3INIT_USB_HOST_FS_CLKCTRL, CM_L3INIT_USB_OTG_CLKCTRL,
+ * CM_L3INIT_XHPI_CLKCTRL, CM_L4SEC_CRYPTODMA_CLKCTRL, CM_MPU_MPU_CLKCTRL,
+ * CM_SDMA_SDMA_CLKCTRL, CM_TESLA_TESLA_CLKCTRL
  */
 #define OMAP4430_STBYST_SHIFT					18
-#define OMAP4430_STBYST_MASK					BITFIELD(18, 18)
+#define OMAP4430_STBYST_MASK					(1 << 18)
 
 /*
- * Used by CM_IDLEST_DPLL_PER, CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB,
- * CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
- * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
  */
 #define OMAP4430_ST_DPLL_CLK_SHIFT				0
-#define OMAP4430_ST_DPLL_CLK_MASK				BITFIELD(0, 0)
+#define OMAP4430_ST_DPLL_CLK_MASK				(1 << 0)
 
 /* Used by CM_CLKDCOLDO_DPLL_USB */
 #define OMAP4430_ST_DPLL_CLKDCOLDO_SHIFT			9
-#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK				BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKDCOLDO_MASK				(1 << 9)
 
 /*
- * Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB, CM_DIV_M2_DPLL_CORE_RESTORE,
- * CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE, CM_DIV_M2_DPLL_DDRPHY,
- * CM_DIV_M2_DPLL_MPU
+ * Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_CORE,
+ * CM_DIV_M2_DPLL_CORE_RESTORE, CM_DIV_M2_DPLL_DDRPHY, CM_DIV_M2_DPLL_MPU,
+ * CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_USB
  */
 #define OMAP4430_ST_DPLL_CLKOUT_SHIFT				9
-#define OMAP4430_ST_DPLL_CLKOUT_MASK				BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUT_MASK				(1 << 9)
 
 /*
- * Used by CM_DIV_M3_DPLL_PER, CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_ABE,
- * CM_DIV_M3_DPLL_CORE
+ * Used by CM_DIV_M3_DPLL_ABE, CM_DIV_M3_DPLL_CORE,
+ * CM_DIV_M3_DPLL_CORE_RESTORE, CM_DIV_M3_DPLL_PER
  */
 #define OMAP4430_ST_DPLL_CLKOUTHIF_SHIFT			9
-#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK				BITFIELD(9, 9)
+#define OMAP4430_ST_DPLL_CLKOUTHIF_MASK				(1 << 9)
 
-/* Used by CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO, CM_DIV_M2_DPLL_ABE */
+/* Used by CM_DIV_M2_DPLL_ABE, CM_DIV_M2_DPLL_PER, CM_DIV_M2_DPLL_UNIPRO */
 #define OMAP4430_ST_DPLL_CLKOUTX2_SHIFT				11
-#define OMAP4430_ST_DPLL_CLKOUTX2_MASK				BITFIELD(11, 11)
+#define OMAP4430_ST_DPLL_CLKOUTX2_MASK				(1 << 11)
 
 /*
- * Used by CM_DIV_M4_DPLL_PER, CM_DIV_M4_DPLL_CORE_RESTORE,
- * CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA
+ * Used by CM_DIV_M4_DPLL_CORE, CM_DIV_M4_DPLL_CORE_RESTORE,
+ * CM_DIV_M4_DPLL_DDRPHY, CM_DIV_M4_DPLL_IVA, CM_DIV_M4_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT1_SHIFT			9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK			BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT1_MASK			(1 << 9)
 
 /*
- * Used by CM_DIV_M5_DPLL_PER, CM_DIV_M5_DPLL_CORE_RESTORE,
- * CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA
+ * Used by CM_DIV_M5_DPLL_CORE, CM_DIV_M5_DPLL_CORE_RESTORE,
+ * CM_DIV_M5_DPLL_DDRPHY, CM_DIV_M5_DPLL_IVA, CM_DIV_M5_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT2_SHIFT			9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK			BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT2_MASK			(1 << 9)
 
 /*
- * Used by CM_DIV_M6_DPLL_PER, CM_DIV_M6_DPLL_CORE_RESTORE,
- * CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_DDRPHY
+ * Used by CM_DIV_M6_DPLL_CORE, CM_DIV_M6_DPLL_CORE_RESTORE,
+ * CM_DIV_M6_DPLL_DDRPHY, CM_DIV_M6_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT3_SHIFT			9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK			BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT3_MASK			(1 << 9)
 
 /*
- * Used by CM_DIV_M7_DPLL_PER, CM_DIV_M7_DPLL_CORE_RESTORE,
- * CM_DIV_M7_DPLL_CORE
+ * Used by CM_DIV_M7_DPLL_CORE, CM_DIV_M7_DPLL_CORE_RESTORE,
+ * CM_DIV_M7_DPLL_PER
  */
 #define OMAP4430_ST_HSDIVIDER_CLKOUT4_SHIFT			9
-#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK			BITFIELD(9, 9)
+#define OMAP4430_ST_HSDIVIDER_CLKOUT4_MASK			(1 << 9)
+
+/*
+ * Used by CM_IDLEST_DPLL_ABE, CM_IDLEST_DPLL_CORE, CM_IDLEST_DPLL_DDRPHY,
+ * CM_IDLEST_DPLL_IVA, CM_IDLEST_DPLL_MPU, CM_IDLEST_DPLL_PER,
+ * CM_IDLEST_DPLL_UNIPRO, CM_IDLEST_DPLL_USB
+ */
+#define OMAP4430_ST_MN_BYPASS_SHIFT				8
+#define OMAP4430_ST_MN_BYPASS_MASK				(1 << 8)
 
 /* Used by CM_SYS_CLKSEL */
 #define OMAP4430_SYS_CLKSEL_SHIFT				0
-#define OMAP4430_SYS_CLKSEL_MASK				BITFIELD(0, 2)
+#define OMAP4430_SYS_CLKSEL_MASK				(0x7 << 0)
 
-/* Used by CM_L4CFG_DYNAMICDEP */
+/* Used by CM_L4CFG_DYNAMICDEP, CM_L4CFG_DYNAMICDEP_RESTORE */
 #define OMAP4430_TESLA_DYNDEP_SHIFT				1
-#define OMAP4430_TESLA_DYNDEP_MASK				BITFIELD(1, 1)
+#define OMAP4430_TESLA_DYNDEP_MASK				(1 << 1)
 
 /* Used by CM_DUCATI_STATICDEP, CM_MPU_STATICDEP */
 #define OMAP4430_TESLA_STATDEP_SHIFT				1
-#define OMAP4430_TESLA_STATDEP_MASK				BITFIELD(1, 1)
+#define OMAP4430_TESLA_STATDEP_MASK				(1 << 1)
 
 /*
- * Used by CM_EMU_DYNAMICDEP, CM_D2D_DYNAMICDEP, CM_DUCATI_DYNAMICDEP,
- * CM_L3_1_DYNAMICDEP, CM_L3_2_DYNAMICDEP, CM_L4CFG_DYNAMICDEP,
- * CM_L4PER_DYNAMICDEP, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
+ * Used by CM_D2D_DYNAMICDEP, CM_D2D_DYNAMICDEP_RESTORE, CM_DUCATI_DYNAMICDEP,
+ * CM_EMU_DYNAMICDEP, CM_L3_1_DYNAMICDEP, CM_L3_1_DYNAMICDEP_RESTORE,
+ * CM_L3_2_DYNAMICDEP, CM_L3_2_DYNAMICDEP_RESTORE, CM_L4CFG_DYNAMICDEP,
+ * CM_L4CFG_DYNAMICDEP_RESTORE, CM_L4PER_DYNAMICDEP,
+ * CM_L4PER_DYNAMICDEP_RESTORE, CM_MPU_DYNAMICDEP, CM_TESLA_DYNAMICDEP
  */
 #define OMAP4430_WINDOWSIZE_SHIFT				24
-#define OMAP4430_WINDOWSIZE_MASK				BITFIELD(24, 27)
+#define OMAP4430_WINDOWSIZE_MASK				(0xf << 24)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_X_MAJOR_SHIFT					8
+#define OMAP4430_X_MAJOR_MASK					(0x7 << 8)
+
+/* Used by REVISION_CM1, REVISION_CM2 */
+#define OMAP4430_Y_MINOR_SHIFT					0
+#define OMAP4430_Y_MINOR_MASK					(0x3f << 0)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/common.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/common.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/mach-omap2/common.c
+ *
+ * Code common to all OMAP2+ machines.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+#include <plat/mux.h>
+
+#include <plat/clock.h>
+
+#include "sdrc.h"
+#include "control.h"
+
+/* Global address base setup code */
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+
+static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
+{
+	omap2_set_globals_tap(omap2_globals);
+	omap2_set_globals_sdrc(omap2_globals);
+	omap2_set_globals_control(omap2_globals);
+	omap2_set_globals_prcm(omap2_globals);
+}
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct omap_globals omap242x_globals = {
+	.class	= OMAP242X_CLASS,
+	.tap	= OMAP2_L4_IO_ADDRESS(0x48014000),
+	.sdrc	= OMAP2420_SDRC_BASE,
+	.sms	= OMAP2420_SMS_BASE,
+	.ctrl	= OMAP242X_CTRL_BASE,
+	.prm	= OMAP2420_PRM_BASE,
+	.cm	= OMAP2420_CM_BASE,
+	.uart1_phys	= OMAP2_UART1_BASE,
+	.uart2_phys	= OMAP2_UART2_BASE,
+	.uart3_phys	= OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_242x(void)
+{
+	__omap2_set_globals(&omap242x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct omap_globals omap243x_globals = {
+	.class	= OMAP243X_CLASS,
+	.tap	= OMAP2_L4_IO_ADDRESS(0x4900a000),
+	.sdrc	= OMAP243X_SDRC_BASE,
+	.sms	= OMAP243X_SMS_BASE,
+	.ctrl	= OMAP243X_CTRL_BASE,
+	.prm	= OMAP2430_PRM_BASE,
+	.cm	= OMAP2430_CM_BASE,
+	.uart1_phys	= OMAP2_UART1_BASE,
+	.uart2_phys	= OMAP2_UART2_BASE,
+	.uart3_phys	= OMAP2_UART3_BASE,
+};
+
+void __init omap2_set_globals_243x(void)
+{
+	__omap2_set_globals(&omap243x_globals);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP3)
+
+static struct omap_globals omap3_globals = {
+	.class	= OMAP343X_CLASS,
+	.tap	= OMAP2_L4_IO_ADDRESS(0x4830A000),
+	.sdrc	= OMAP343X_SDRC_BASE,
+	.sms	= OMAP343X_SMS_BASE,
+	.ctrl	= OMAP343X_CTRL_BASE,
+	.prm	= OMAP3430_PRM_BASE,
+	.cm	= OMAP3430_CM_BASE,
+	.uart1_phys	= OMAP3_UART1_BASE,
+	.uart2_phys	= OMAP3_UART2_BASE,
+	.uart3_phys	= OMAP3_UART3_BASE,
+	.uart4_phys	= OMAP3_UART4_BASE,	/* Only on 3630 */
+};
+
+void __init omap2_set_globals_3xxx(void)
+{
+	__omap2_set_globals(&omap3_globals);
+}
+
+void __init omap3_map_io(void)
+{
+	omap2_set_globals_3xxx();
+	omap34xx_map_common_io();
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4)
+static struct omap_globals omap4_globals = {
+	.class	= OMAP443X_CLASS,
+	.tap	= OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
+	.ctrl	= OMAP443X_SCM_BASE,
+	.ctrl_pad	= OMAP443X_CTRL_BASE,
+	.prm	= OMAP4430_PRM_BASE,
+	.cm	= OMAP4430_CM_BASE,
+	.cm2	= OMAP4430_CM2_BASE,
+	.uart1_phys	= OMAP4_UART1_BASE,
+	.uart2_phys	= OMAP4_UART2_BASE,
+	.uart3_phys	= OMAP4_UART3_BASE,
+	.uart4_phys	= OMAP4_UART4_BASE,
+};
+
+void __init omap2_set_globals_443x(void)
+{
+	omap2_set_globals_tap(&omap4_globals);
+	omap2_set_globals_control(&omap4_globals);
+	omap2_set_globals_prcm(&omap4_globals);
+}
+#endif
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/control.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/control.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/control.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/control.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,15 +16,18 @@
 #include <linux/io.h>
 
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/sdrc.h>
+
 #include "cm-regbits-34xx.h"
 #include "prm-regbits-34xx.h"
 #include "cm.h"
 #include "prm.h"
 #include "sdrc.h"
+#include "pm.h"
+#include "control.h"
 
 static void __iomem *omap2_ctrl_base;
+static void __iomem *omap4_ctrl_pad_base;
 
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 struct omap3_scratchpad {
@@ -137,6 +140,7 @@
 #endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
 
 #define OMAP_CTRL_REGADDR(reg)		(omap2_ctrl_base + (reg))
+#define OMAP4_CTRL_PAD_REGADDR(reg)	(omap4_ctrl_pad_base + (reg))
 
 void __init omap2_set_globals_control(struct omap_globals *omap2_globals)
 {
@@ -145,6 +149,12 @@
 		omap2_ctrl_base = ioremap(omap2_globals->ctrl, SZ_4K);
 		WARN_ON(!omap2_ctrl_base);
 	}
+
+	/* Static mapping, never released */
+	if (omap2_globals->ctrl_pad) {
+		omap4_ctrl_pad_base = ioremap(omap2_globals->ctrl_pad, SZ_4K);
+		WARN_ON(!omap4_ctrl_pad_base);
+	}
 }
 
 void __iomem *omap_ctrl_base_get(void)
@@ -182,6 +192,23 @@
 	__raw_writel(val, OMAP_CTRL_REGADDR(offset));
 }
 
+/*
+ * On OMAP4 control pad are not addressable from control
+ * core base. So the common omap_ctrl_read/write APIs breaks
+ * Hence export separate APIs to manage the omap4 pad control
+ * registers. This APIs will work only for OMAP4
+ */
+
+u32 omap4_ctrl_pad_readl(u16 offset)
+{
+	return __raw_readl(OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
+void omap4_ctrl_pad_writel(u32 val, u16 offset)
+{
+	__raw_writel(val, OMAP4_CTRL_PAD_REGADDR(offset));
+}
+
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 /*
  * Clears the scratchpad contents in case of cold boot-
@@ -190,7 +217,7 @@
 void omap3_clear_scratchpad_contents(void)
 {
 	u32 max_offset = OMAP343X_SCRATCHPAD_ROM_OFFSET;
-	u32 *v_addr;
+	void __iomem *v_addr;
 	u32 offset = 0;
 	v_addr = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD_ROM);
 	if (prm_read_mod_reg(OMAP3430_GR_MOD, OMAP3_PRM_RSTST_OFFSET) &
@@ -206,7 +233,7 @@
 /* Populate the scratchpad structure with restore structure */
 void omap3_save_scratchpad_contents(void)
 {
-	void * __iomem scratchpad_address;
+	void  __iomem *scratchpad_address;
 	u32 arm_context_addr;
 	struct omap3_scratchpad scratchpad_contents;
 	struct omap3_scratchpad_prcm_block prcm_block_contents;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/control.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/control.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/control.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/control.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,368 @@
+/*
+ * arch/arm/mach-omap2/control.h
+ *
+ * OMAP2/3/4 System Control Module definitions
+ *
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008, 2010 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CONTROL_H
+#define __ARCH_ARM_MACH_OMAP2_CONTROL_H
+
+#include <mach/io.h>
+#include <mach/ctrl_module_core_44xx.h>
+#include <mach/ctrl_module_wkup_44xx.h>
+#include <mach/ctrl_module_pad_core_44xx.h>
+#include <mach/ctrl_module_pad_wkup_44xx.h>
+
+#ifndef __ASSEMBLY__
+#define OMAP242X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#else
+#define OMAP242X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)					\
+		OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#endif /* __ASSEMBLY__ */
+
+/*
+ * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
+ * OMAP24XX and OMAP34XX.
+ */
+
+/* Control submodule offsets */
+
+#define OMAP2_CONTROL_INTERFACE		0x000
+#define OMAP2_CONTROL_PADCONFS		0x030
+#define OMAP2_CONTROL_GENERAL		0x270
+#define OMAP343X_CONTROL_MEM_WKUP	0x600
+#define OMAP343X_CONTROL_PADCONFS_WKUP	0xa00
+#define OMAP343X_CONTROL_GENERAL_WKUP	0xa60
+
+/* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
+
+#define OMAP2_CONTROL_SYSCONFIG		(OMAP2_CONTROL_INTERFACE + 0x10)
+
+/* CONTROL_GENERAL register offsets common to OMAP2 & 3 */
+#define OMAP2_CONTROL_DEVCONF0		(OMAP2_CONTROL_GENERAL + 0x0004)
+#define OMAP2_CONTROL_MSUSPENDMUX_0	(OMAP2_CONTROL_GENERAL + 0x0020)
+#define OMAP2_CONTROL_MSUSPENDMUX_1	(OMAP2_CONTROL_GENERAL + 0x0024)
+#define OMAP2_CONTROL_MSUSPENDMUX_2	(OMAP2_CONTROL_GENERAL + 0x0028)
+#define OMAP2_CONTROL_MSUSPENDMUX_3	(OMAP2_CONTROL_GENERAL + 0x002c)
+#define OMAP2_CONTROL_MSUSPENDMUX_4	(OMAP2_CONTROL_GENERAL + 0x0030)
+#define OMAP2_CONTROL_MSUSPENDMUX_5	(OMAP2_CONTROL_GENERAL + 0x0034)
+#define OMAP2_CONTROL_SEC_CTRL		(OMAP2_CONTROL_GENERAL + 0x0040)
+#define OMAP2_CONTROL_RPUB_KEY_H_0	(OMAP2_CONTROL_GENERAL + 0x0090)
+#define OMAP2_CONTROL_RPUB_KEY_H_1	(OMAP2_CONTROL_GENERAL + 0x0094)
+#define OMAP2_CONTROL_RPUB_KEY_H_2	(OMAP2_CONTROL_GENERAL + 0x0098)
+#define OMAP2_CONTROL_RPUB_KEY_H_3	(OMAP2_CONTROL_GENERAL + 0x009c)
+
+/* 242x-only CONTROL_GENERAL register offsets */
+#define OMAP242X_CONTROL_DEVCONF	OMAP2_CONTROL_DEVCONF0 /* match TRM */
+#define OMAP242X_CONTROL_OCM_RAM_PERM	(OMAP2_CONTROL_GENERAL + 0x0068)
+
+/* 243x-only CONTROL_GENERAL register offsets */
+/* CONTROL_IVA2_BOOT{ADDR,MOD} are at the same place on 343x - noted below */
+#define OMAP243X_CONTROL_DEVCONF1	(OMAP2_CONTROL_GENERAL + 0x0078)
+#define OMAP243X_CONTROL_CSIRXFE	(OMAP2_CONTROL_GENERAL + 0x007c)
+#define OMAP243X_CONTROL_IVA2_BOOTADDR	(OMAP2_CONTROL_GENERAL + 0x0190)
+#define OMAP243X_CONTROL_IVA2_BOOTMOD	(OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP243X_CONTROL_IVA2_GEMCFG	(OMAP2_CONTROL_GENERAL + 0x0198)
+#define OMAP243X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x0230)
+
+/* 24xx-only CONTROL_GENERAL register offsets */
+#define OMAP24XX_CONTROL_DEBOBS		(OMAP2_CONTROL_GENERAL + 0x0000)
+#define OMAP24XX_CONTROL_EMU_SUPPORT	(OMAP2_CONTROL_GENERAL + 0x0008)
+#define OMAP24XX_CONTROL_SEC_TEST	(OMAP2_CONTROL_GENERAL + 0x0044)
+#define OMAP24XX_CONTROL_PSA_CTRL	(OMAP2_CONTROL_GENERAL + 0x0048)
+#define OMAP24XX_CONTROL_PSA_CMD	(OMAP2_CONTROL_GENERAL + 0x004c)
+#define OMAP24XX_CONTROL_PSA_VALUE	(OMAP2_CONTROL_GENERAL + 0x0050)
+#define OMAP24XX_CONTROL_SEC_EMU	(OMAP2_CONTROL_GENERAL + 0x0060)
+#define OMAP24XX_CONTROL_SEC_TAP	(OMAP2_CONTROL_GENERAL + 0x0064)
+#define OMAP24XX_CONTROL_OCM_PUB_RAM_ADD	(OMAP2_CONTROL_GENERAL + 0x006c)
+#define OMAP24XX_CONTROL_EXT_SEC_RAM_START_ADD	(OMAP2_CONTROL_GENERAL + 0x0070)
+#define OMAP24XX_CONTROL_EXT_SEC_RAM_STOP_ADD	(OMAP2_CONTROL_GENERAL + 0x0074)
+#define OMAP24XX_CONTROL_SEC_STATUS		(OMAP2_CONTROL_GENERAL + 0x0080)
+#define OMAP24XX_CONTROL_SEC_ERR_STATUS		(OMAP2_CONTROL_GENERAL + 0x0084)
+#define OMAP24XX_CONTROL_STATUS			(OMAP2_CONTROL_GENERAL + 0x0088)
+#define OMAP24XX_CONTROL_GENERAL_PURPOSE_STATUS	(OMAP2_CONTROL_GENERAL + 0x008c)
+#define OMAP24XX_CONTROL_RAND_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00a0)
+#define OMAP24XX_CONTROL_RAND_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00a4)
+#define OMAP24XX_CONTROL_RAND_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00a8)
+#define OMAP24XX_CONTROL_RAND_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00ac)
+#define OMAP24XX_CONTROL_CUST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00b0)
+#define OMAP24XX_CONTROL_CUST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00b4)
+#define OMAP24XX_CONTROL_TEST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00c0)
+#define OMAP24XX_CONTROL_TEST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00c4)
+#define OMAP24XX_CONTROL_TEST_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00c8)
+#define OMAP24XX_CONTROL_TEST_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00cc)
+#define OMAP24XX_CONTROL_TEST_KEY_4	(OMAP2_CONTROL_GENERAL + 0x00d0)
+#define OMAP24XX_CONTROL_TEST_KEY_5	(OMAP2_CONTROL_GENERAL + 0x00d4)
+#define OMAP24XX_CONTROL_TEST_KEY_6	(OMAP2_CONTROL_GENERAL + 0x00d8)
+#define OMAP24XX_CONTROL_TEST_KEY_7	(OMAP2_CONTROL_GENERAL + 0x00dc)
+#define OMAP24XX_CONTROL_TEST_KEY_8	(OMAP2_CONTROL_GENERAL + 0x00e0)
+#define OMAP24XX_CONTROL_TEST_KEY_9	(OMAP2_CONTROL_GENERAL + 0x00e4)
+
+#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0)
+
+/* 34xx-only CONTROL_GENERAL register offsets */
+#define OMAP343X_CONTROL_PADCONF_OFF	(OMAP2_CONTROL_GENERAL + 0x0000)
+#define OMAP343X_CONTROL_MEM_DFTRW0	(OMAP2_CONTROL_GENERAL + 0x0008)
+#define OMAP343X_CONTROL_MEM_DFTRW1	(OMAP2_CONTROL_GENERAL + 0x000c)
+#define OMAP343X_CONTROL_DEVCONF1	(OMAP2_CONTROL_GENERAL + 0x0068)
+#define OMAP343X_CONTROL_CSIRXFE		(OMAP2_CONTROL_GENERAL + 0x006c)
+#define OMAP343X_CONTROL_SEC_STATUS		(OMAP2_CONTROL_GENERAL + 0x0070)
+#define OMAP343X_CONTROL_SEC_ERR_STATUS		(OMAP2_CONTROL_GENERAL + 0x0074)
+#define OMAP343X_CONTROL_SEC_ERR_STATUS_DEBUG	(OMAP2_CONTROL_GENERAL + 0x0078)
+#define OMAP343X_CONTROL_STATUS			(OMAP2_CONTROL_GENERAL + 0x0080)
+#define OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS	(OMAP2_CONTROL_GENERAL + 0x0084)
+#define OMAP343X_CONTROL_RPUB_KEY_H_4	(OMAP2_CONTROL_GENERAL + 0x00a0)
+#define OMAP343X_CONTROL_RAND_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00a8)
+#define OMAP343X_CONTROL_RAND_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00ac)
+#define OMAP343X_CONTROL_RAND_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00b0)
+#define OMAP343X_CONTROL_RAND_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00b4)
+#define OMAP343X_CONTROL_TEST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00c8)
+#define OMAP343X_CONTROL_TEST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00cc)
+#define OMAP343X_CONTROL_TEST_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00d0)
+#define OMAP343X_CONTROL_TEST_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00d4)
+#define OMAP343X_CONTROL_TEST_KEY_4	(OMAP2_CONTROL_GENERAL + 0x00d8)
+#define OMAP343X_CONTROL_TEST_KEY_5	(OMAP2_CONTROL_GENERAL + 0x00dc)
+#define OMAP343X_CONTROL_TEST_KEY_6	(OMAP2_CONTROL_GENERAL + 0x00e0)
+#define OMAP343X_CONTROL_TEST_KEY_7	(OMAP2_CONTROL_GENERAL + 0x00e4)
+#define OMAP343X_CONTROL_TEST_KEY_8	(OMAP2_CONTROL_GENERAL + 0x00e8)
+#define OMAP343X_CONTROL_TEST_KEY_9	(OMAP2_CONTROL_GENERAL + 0x00ec)
+#define OMAP343X_CONTROL_TEST_KEY_10	(OMAP2_CONTROL_GENERAL + 0x00f0)
+#define OMAP343X_CONTROL_TEST_KEY_11	(OMAP2_CONTROL_GENERAL + 0x00f4)
+#define OMAP343X_CONTROL_TEST_KEY_12	(OMAP2_CONTROL_GENERAL + 0x00f8)
+#define OMAP343X_CONTROL_TEST_KEY_13	(OMAP2_CONTROL_GENERAL + 0x00fc)
+#define OMAP343X_CONTROL_IVA2_BOOTADDR	(OMAP2_CONTROL_GENERAL + 0x0190)
+#define OMAP343X_CONTROL_IVA2_BOOTMOD	(OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP343X_CONTROL_DEBOBS(i)	(OMAP2_CONTROL_GENERAL + 0x01B0 \
+					+ ((i) >> 1) * 4 + (!((i) & 1)) * 2)
+#define OMAP343X_CONTROL_PROG_IO0	(OMAP2_CONTROL_GENERAL + 0x01D4)
+#define OMAP343X_CONTROL_PROG_IO1	(OMAP2_CONTROL_GENERAL + 0x01D8)
+#define OMAP343X_CONTROL_DSS_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E0)
+#define OMAP343X_CONTROL_CORE_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E4)
+#define OMAP343X_CONTROL_PER_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E8)
+#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01EC)
+#define OMAP343X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x02B0)
+#define OMAP343X_CONTROL_TEMP_SENSOR	(OMAP2_CONTROL_GENERAL + 0x02B4)
+#define OMAP343X_CONTROL_SRAMLDO4	(OMAP2_CONTROL_GENERAL + 0x02B8)
+#define OMAP343X_CONTROL_SRAMLDO5	(OMAP2_CONTROL_GENERAL + 0x02C0)
+#define OMAP343X_CONTROL_CSI		(OMAP2_CONTROL_GENERAL + 0x02C4)
+
+/* AM35XX only CONTROL_GENERAL register offsets */
+#define AM35XX_CONTROL_MSUSPENDMUX_6    (OMAP2_CONTROL_GENERAL + 0x0038)
+#define AM35XX_CONTROL_DEVCONF2         (OMAP2_CONTROL_GENERAL + 0x0310)
+#define AM35XX_CONTROL_DEVCONF3         (OMAP2_CONTROL_GENERAL + 0x0314)
+#define AM35XX_CONTROL_CBA_PRIORITY     (OMAP2_CONTROL_GENERAL + 0x0320)
+#define AM35XX_CONTROL_LVL_INTR_CLEAR   (OMAP2_CONTROL_GENERAL + 0x0324)
+#define AM35XX_CONTROL_IP_SW_RESET      (OMAP2_CONTROL_GENERAL + 0x0328)
+#define AM35XX_CONTROL_IPSS_CLK_CTRL    (OMAP2_CONTROL_GENERAL + 0x032C)
+
+/* 34xx PADCONF register offsets */
+#define OMAP343X_PADCONF_ETK(i)		(OMAP2_CONTROL_PADCONFS + 0x5a8 + \
+						(i)*2)
+#define OMAP343X_PADCONF_ETK_CLK	OMAP343X_PADCONF_ETK(0)
+#define OMAP343X_PADCONF_ETK_CTL	OMAP343X_PADCONF_ETK(1)
+#define OMAP343X_PADCONF_ETK_D0		OMAP343X_PADCONF_ETK(2)
+#define OMAP343X_PADCONF_ETK_D1		OMAP343X_PADCONF_ETK(3)
+#define OMAP343X_PADCONF_ETK_D2		OMAP343X_PADCONF_ETK(4)
+#define OMAP343X_PADCONF_ETK_D3		OMAP343X_PADCONF_ETK(5)
+#define OMAP343X_PADCONF_ETK_D4		OMAP343X_PADCONF_ETK(6)
+#define OMAP343X_PADCONF_ETK_D5		OMAP343X_PADCONF_ETK(7)
+#define OMAP343X_PADCONF_ETK_D6		OMAP343X_PADCONF_ETK(8)
+#define OMAP343X_PADCONF_ETK_D7		OMAP343X_PADCONF_ETK(9)
+#define OMAP343X_PADCONF_ETK_D8		OMAP343X_PADCONF_ETK(10)
+#define OMAP343X_PADCONF_ETK_D9		OMAP343X_PADCONF_ETK(11)
+#define OMAP343X_PADCONF_ETK_D10	OMAP343X_PADCONF_ETK(12)
+#define OMAP343X_PADCONF_ETK_D11	OMAP343X_PADCONF_ETK(13)
+#define OMAP343X_PADCONF_ETK_D12	OMAP343X_PADCONF_ETK(14)
+#define OMAP343X_PADCONF_ETK_D13	OMAP343X_PADCONF_ETK(15)
+#define OMAP343X_PADCONF_ETK_D14	OMAP343X_PADCONF_ETK(16)
+#define OMAP343X_PADCONF_ETK_D15	OMAP343X_PADCONF_ETK(17)
+
+/* 34xx GENERAL_WKUP regist offsets */
+#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
+						0x008 + (i))
+#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
+#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C)
+#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010)
+#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
+#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
+
+/* 34xx D2D idle-related pins, handled by PM core */
+#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
+#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
+
+/*
+ * REVISIT: This list of registers is not comprehensive - there are more
+ * that should be added.
+ */
+
+/*
+ * Control module register bit defines - these should eventually go into
+ * their own regbits file.  Some of these will be complicated, depending
+ * on the device type (general-purpose, emulator, test, secure, bad, other)
+ * and the security mode (secure, non-secure, don't care)
+ */
+/* CONTROL_DEVCONF0 bits */
+#define OMAP2_MMCSDIO1ADPCLKISEL	(1 << 24) /* MMC1 loop back clock */
+#define OMAP24XX_USBSTANDBYCTRL		(1 << 15)
+#define OMAP2_MCBSP2_CLKS_MASK		(1 << 6)
+#define OMAP2_MCBSP1_FSR_MASK		(1 << 4)
+#define OMAP2_MCBSP1_CLKR_MASK		(1 << 3)
+#define OMAP2_MCBSP1_CLKS_MASK		(1 << 2)
+
+/* CONTROL_DEVCONF1 bits */
+#define OMAP243X_MMC1_ACTIVE_OVERWRITE	(1 << 31)
+#define OMAP2_MMCSDIO2ADPCLKISEL	(1 << 6) /* MMC2 loop back clock */
+#define OMAP2_MCBSP5_CLKS_MASK		(1 << 4) /* > 242x */
+#define OMAP2_MCBSP4_CLKS_MASK		(1 << 2) /* > 242x */
+#define OMAP2_MCBSP3_CLKS_MASK		(1 << 0) /* > 242x */
+
+/* CONTROL_STATUS bits */
+#define OMAP2_DEVICETYPE_MASK		(0x7 << 8)
+#define OMAP2_SYSBOOT_5_MASK		(1 << 5)
+#define OMAP2_SYSBOOT_4_MASK		(1 << 4)
+#define OMAP2_SYSBOOT_3_MASK		(1 << 3)
+#define OMAP2_SYSBOOT_2_MASK		(1 << 2)
+#define OMAP2_SYSBOOT_1_MASK		(1 << 1)
+#define OMAP2_SYSBOOT_0_MASK		(1 << 0)
+
+/* CONTROL_PBIAS_LITE bits */
+#define OMAP343X_PBIASLITESUPPLY_HIGH1	(1 << 15)
+#define OMAP343X_PBIASLITEVMODEERROR1	(1 << 11)
+#define OMAP343X_PBIASSPEEDCTRL1	(1 << 10)
+#define OMAP343X_PBIASLITEPWRDNZ1	(1 << 9)
+#define OMAP343X_PBIASLITEVMODE1	(1 << 8)
+#define OMAP343X_PBIASLITESUPPLY_HIGH0	(1 << 7)
+#define OMAP343X_PBIASLITEVMODEERROR0	(1 << 3)
+#define OMAP2_PBIASSPEEDCTRL0		(1 << 2)
+#define OMAP2_PBIASLITEPWRDNZ0		(1 << 1)
+#define OMAP2_PBIASLITEVMODE0		(1 << 0)
+
+/* CONTROL_PROG_IO1 bits */
+#define OMAP3630_PRG_SDMMC1_SPEEDCTRL	(1 << 20)
+
+/* CONTROL_IVA2_BOOTMOD bits */
+#define OMAP3_IVA2_BOOTMOD_SHIFT	0
+#define OMAP3_IVA2_BOOTMOD_MASK		(0xf << 0)
+#define OMAP3_IVA2_BOOTMOD_IDLE		(0x1 << 0)
+
+/* CONTROL_PADCONF_X bits */
+#define OMAP3_PADCONF_WAKEUPEVENT0	(1 << 15)
+#define OMAP3_PADCONF_WAKEUPENABLE0	(1 << 14)
+
+#define OMAP343X_SCRATCHPAD_ROM		(OMAP343X_CTRL_BASE + 0x860)
+#define OMAP343X_SCRATCHPAD		(OMAP343X_CTRL_BASE + 0x910)
+#define OMAP343X_SCRATCHPAD_ROM_OFFSET	0x19C
+
+/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */
+#define AM35XX_USBOTG_VBUSP_CLK_SHIFT   0
+#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT   1
+#define AM35XX_VPFE_VBUSP_CLK_SHIFT     2
+#define AM35XX_HECC_VBUSP_CLK_SHIFT     3
+#define AM35XX_USBOTG_FCLK_SHIFT        8
+#define AM35XX_CPGMAC_FCLK_SHIFT        9
+#define AM35XX_VPFE_FCLK_SHIFT          10
+
+/*AM35XX CONTROL_LVL_INTR_CLEAR bits*/
+#define AM35XX_CPGMAC_C0_MISC_PULSE_CLR	BIT(0)
+#define AM35XX_CPGMAC_C0_RX_PULSE_CLR	BIT(1)
+#define AM35XX_CPGMAC_C0_RX_THRESH_CLR	BIT(2)
+#define AM35XX_CPGMAC_C0_TX_PULSE_CLR	BIT(3)
+#define AM35XX_USBOTGSS_INT_CLR		BIT(4)
+#define AM35XX_VPFE_CCDC_VD0_INT_CLR	BIT(5)
+#define AM35XX_VPFE_CCDC_VD1_INT_CLR	BIT(6)
+#define AM35XX_VPFE_CCDC_VD2_INT_CLR	BIT(7)
+
+/*AM35XX CONTROL_IP_SW_RESET bits*/
+#define AM35XX_USBOTGSS_SW_RST		BIT(0)
+#define AM35XX_CPGMACSS_SW_RST		BIT(1)
+#define AM35XX_VPFE_VBUSP_SW_RST	BIT(2)
+#define AM35XX_HECC_SW_RST		BIT(3)
+#define AM35XX_VPFE_PCLK_SW_RST		BIT(4)
+
+/*
+ * CONTROL OMAP STATUS register to identify OMAP3 features
+ */
+#define OMAP3_CONTROL_OMAP_STATUS	0x044c
+
+#define OMAP3_SGX_SHIFT			13
+#define OMAP3_SGX_MASK			(3 << OMAP3_SGX_SHIFT)
+#define		FEAT_SGX_FULL		0
+#define		FEAT_SGX_HALF		1
+#define		FEAT_SGX_NONE		2
+
+#define OMAP3_IVA_SHIFT			12
+#define OMAP3_IVA_MASK			(1 << OMAP3_SGX_SHIFT)
+#define		FEAT_IVA		0
+#define		FEAT_IVA_NONE		1
+
+#define OMAP3_L2CACHE_SHIFT		10
+#define OMAP3_L2CACHE_MASK		(3 << OMAP3_L2CACHE_SHIFT)
+#define		FEAT_L2CACHE_NONE	0
+#define		FEAT_L2CACHE_64KB	1
+#define		FEAT_L2CACHE_128KB	2
+#define		FEAT_L2CACHE_256KB	3
+
+#define OMAP3_ISP_SHIFT			5
+#define OMAP3_ISP_MASK			(1 << OMAP3_ISP_SHIFT)
+#define		FEAT_ISP		0
+#define		FEAT_ISP_NONE		1
+
+#define OMAP3_NEON_SHIFT		4
+#define OMAP3_NEON_MASK			(1 << OMAP3_NEON_SHIFT)
+#define		FEAT_NEON		0
+#define		FEAT_NEON_NONE		1
+
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_ARCH_OMAP2PLUS
+extern void __iomem *omap_ctrl_base_get(void);
+extern u8 omap_ctrl_readb(u16 offset);
+extern u16 omap_ctrl_readw(u16 offset);
+extern u32 omap_ctrl_readl(u16 offset);
+extern u32 omap4_ctrl_pad_readl(u16 offset);
+extern void omap_ctrl_writeb(u8 val, u16 offset);
+extern void omap_ctrl_writew(u16 val, u16 offset);
+extern void omap_ctrl_writel(u32 val, u16 offset);
+extern void omap4_ctrl_pad_writel(u32 val, u16 offset);
+
+extern void omap3_save_scratchpad_contents(void);
+extern void omap3_clear_scratchpad_contents(void);
+extern u32 *get_restore_pointer(void);
+extern u32 *get_es3_restore_pointer(void);
+extern u32 omap3_arm_context[128];
+extern void omap3_control_save_context(void);
+extern void omap3_control_restore_context(void);
+
+#else
+#define omap_ctrl_base_get()		0
+#define omap_ctrl_readb(x)		0
+#define omap_ctrl_readw(x)		0
+#define omap_ctrl_readl(x)		0
+#define omap4_ctrl_pad_readl(x)		0
+#define omap_ctrl_writeb(x, y)		WARN_ON(1)
+#define omap_ctrl_writew(x, y)		WARN_ON(1)
+#define omap_ctrl_writel(x, y)		WARN_ON(1)
+#define omap4_ctrl_pad_writel(x, y)	WARN_ON(1)
+#endif
+#endif	/* __ASSEMBLY__ */
+
+#endif /* __ARCH_ARM_MACH_OMAP2_CONTROL_H */
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cpuidle34xx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cpuidle34xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/cpuidle34xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/cpuidle34xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,10 +29,10 @@
 #include <plat/irqs.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
-#include <plat/control.h>
 #include <plat/serial.h>
 
 #include "pm.h"
+#include "control.h"
 
 #ifdef CONFIG_CPU_IDLE
 
@@ -60,7 +60,8 @@
 
 struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
 struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *cam_pd;
 
 /*
  * The latencies/thresholds for various C states have
@@ -233,14 +234,60 @@
 			       struct cpuidle_state *state)
 {
 	struct cpuidle_state *new_state = next_valid_state(dev, state);
+	u32 core_next_state, per_next_state = 0, per_saved_state = 0;
+	u32 cam_state;
+	struct omap3_processor_cx *cx;
+	int ret;
 
 	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
 		BUG_ON(!dev->safe_state);
 		new_state = dev->safe_state;
+		goto select_state;
+	}
+
+	cx = cpuidle_get_statedata(state);
+	core_next_state = cx->core_state;
+
+	/*
+	 * FIXME: we currently manage device-specific idle states
+	 *        for PER and CORE in combination with CPU-specific
+	 *        idle states.  This is wrong, and device-specific
+	 *        idle managment needs to be separated out into 
+	 *        its own code.
+	 */
+
+	/*
+	 * Prevent idle completely if CAM is active.
+	 * CAM does not have wakeup capability in OMAP3.
+	 */
+	cam_state = pwrdm_read_pwrst(cam_pd);
+	if (cam_state == PWRDM_POWER_ON) {
+		new_state = dev->safe_state;
+		goto select_state;
 	}
 
+	/*
+	 * Prevent PER off if CORE is not in retention or off as this
+	 * would disable PER wakeups completely.
+	 */
+	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
+	if ((per_next_state == PWRDM_POWER_OFF) &&
+	    (core_next_state > PWRDM_POWER_RET))
+		per_next_state = PWRDM_POWER_RET;
+
+	/* Are we changing PER target state? */
+	if (per_next_state != per_saved_state)
+		pwrdm_set_next_pwrst(per_pd, per_next_state);
+
+select_state:
 	dev->last_state = new_state;
-	return omap3_enter_idle(dev, new_state);
+	ret = omap3_enter_idle(dev, new_state);
+
+	/* Restore original PER state if it was modified */
+	if (per_next_state != per_saved_state)
+		pwrdm_set_next_pwrst(per_pd, per_saved_state);
+
+	return ret;
 }
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -328,7 +375,8 @@
 			cpuidle_params_table[OMAP3_STATE_C2].threshold;
 	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_CHECK_BM;
 
 	/* C3 . MPU CSWR + Core inactive */
 	omap3_power_states[OMAP3_STATE_C3].valid =
@@ -426,6 +474,8 @@
 
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
 	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	cam_pd = pwrdm_lookup("cam_pwrdm");
 
 	omap_init_power_states();
 	cpuidle_register_driver(&omap3_idle_driver);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,12 +9,12 @@
  * (at your option) any later version.
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
@@ -22,14 +22,17 @@
 #include <asm/mach/map.h>
 #include <asm/pmu.h>
 
-#include <plat/control.h>
 #include <plat/tc.h>
 #include <plat/board.h>
+#include <plat/mcbsp.h>
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "mux.h"
+#include "control.h"
 
 #if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
@@ -235,6 +238,43 @@
 
 static inline void omap_init_sti(void) {}
 
+#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
+
+static struct platform_device omap_pcm = {
+	.name	= "omap-pcm-audio",
+	.id	= -1,
+};
+
+/*
+ * OMAP2420 has 2 McBSP ports
+ * OMAP2430 has 5 McBSP ports
+ * OMAP3 has 5 McBSP ports
+ * OMAP4 has 4 McBSP ports
+ */
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+OMAP_MCBSP_PLATFORM_DEVICE(4);
+OMAP_MCBSP_PLATFORM_DEVICE(5);
+
+static void omap_init_audio(void)
+{
+	platform_device_register(&omap_mcbsp1);
+	platform_device_register(&omap_mcbsp2);
+	if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
+		platform_device_register(&omap_mcbsp3);
+		platform_device_register(&omap_mcbsp4);
+	}
+	if (cpu_is_omap243x() || cpu_is_omap34xx())
+		platform_device_register(&omap_mcbsp5);
+
+	platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <plat/mcspi.h>
@@ -498,6 +538,76 @@
 static inline void omap_init_sham(void) { }
 #endif
 
+#if defined(CONFIG_CRYPTO_DEV_OMAP_AES) || defined(CONFIG_CRYPTO_DEV_OMAP_AES_MODULE)
+
+#ifdef CONFIG_ARCH_OMAP2
+static struct resource omap2_aes_resources[] = {
+	{
+		.start	= OMAP24XX_SEC_AES_BASE,
+		.end	= OMAP24XX_SEC_AES_BASE + 0x4C,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= OMAP24XX_DMA_AES_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= OMAP24XX_DMA_AES_RX,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+static int omap2_aes_resources_sz = ARRAY_SIZE(omap2_aes_resources);
+#else
+#define omap2_aes_resources		NULL
+#define omap2_aes_resources_sz		0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct resource omap3_aes_resources[] = {
+	{
+		.start	= OMAP34XX_SEC_AES_BASE,
+		.end	= OMAP34XX_SEC_AES_BASE + 0x4C,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= OMAP34XX_DMA_AES2_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	{
+		.start	= OMAP34XX_DMA_AES2_RX,
+		.flags	= IORESOURCE_DMA,
+	}
+};
+static int omap3_aes_resources_sz = ARRAY_SIZE(omap3_aes_resources);
+#else
+#define omap3_aes_resources		NULL
+#define omap3_aes_resources_sz		0
+#endif
+
+static struct platform_device aes_device = {
+	.name		= "omap-aes",
+	.id		= -1,
+};
+
+static void omap_init_aes(void)
+{
+	if (cpu_is_omap24xx()) {
+		aes_device.resource = omap2_aes_resources;
+		aes_device.num_resources = omap2_aes_resources_sz;
+	} else if (cpu_is_omap34xx()) {
+		aes_device.resource = omap3_aes_resources;
+		aes_device.num_resources = omap3_aes_resources_sz;
+	} else {
+		pr_err("%s: platform not supported\n", __func__);
+		return;
+	}
+	platform_device_register(&aes_device);
+}
+
+#else
+static inline void omap_init_aes(void) { }
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
@@ -624,7 +734,7 @@
 		omap_mux_init_signal("sdmmc_dat0", 0);
 		omap_mux_init_signal("sdmmc_dat_dir0", 0);
 		omap_mux_init_signal("sdmmc_cmd_dir", 0);
-		if (mmc_controller->slots[0].wires == 4) {
+		if (mmc_controller->slots[0].caps & MMC_CAP_4_BIT_DATA) {
 			omap_mux_init_signal("sdmmc_dat1", 0);
 			omap_mux_init_signal("sdmmc_dat2", 0);
 			omap_mux_init_signal("sdmmc_dat3", 0);
@@ -652,8 +762,8 @@
 				OMAP_PIN_INPUT_PULLUP);
 			omap_mux_init_signal("sdmmc1_dat0",
 				OMAP_PIN_INPUT_PULLUP);
-			if (mmc_controller->slots[0].wires == 4 ||
-				mmc_controller->slots[0].wires == 8) {
+			if (mmc_controller->slots[0].caps &
+				(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
 				omap_mux_init_signal("sdmmc1_dat1",
 					OMAP_PIN_INPUT_PULLUP);
 				omap_mux_init_signal("sdmmc1_dat2",
@@ -661,7 +771,8 @@
 				omap_mux_init_signal("sdmmc1_dat3",
 					OMAP_PIN_INPUT_PULLUP);
 			}
-			if (mmc_controller->slots[0].wires == 8) {
+			if (mmc_controller->slots[0].caps &
+						MMC_CAP_8_BIT_DATA) {
 				omap_mux_init_signal("sdmmc1_dat4",
 					OMAP_PIN_INPUT_PULLUP);
 				omap_mux_init_signal("sdmmc1_dat5",
@@ -685,8 +796,8 @@
 			 * For 8 wire configurations, Lines DAT4, 5, 6 and 7 need to be muxed
 			 * in the board-*.c files
 			 */
-			if (mmc_controller->slots[0].wires == 4 ||
-				mmc_controller->slots[0].wires == 8) {
+			if (mmc_controller->slots[0].caps &
+				(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
 				omap_mux_init_signal("sdmmc2_dat1",
 					OMAP_PIN_INPUT_PULLUP);
 				omap_mux_init_signal("sdmmc2_dat2",
@@ -694,7 +805,8 @@
 				omap_mux_init_signal("sdmmc2_dat3",
 					OMAP_PIN_INPUT_PULLUP);
 			}
-			if (mmc_controller->slots[0].wires == 8) {
+			if (mmc_controller->slots[0].caps &
+							MMC_CAP_8_BIT_DATA) {
 				omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
 					OMAP_PIN_INPUT_PULLUP);
 				omap_mux_init_signal("sdmmc2_dat5.sdmmc2_dat5",
@@ -745,13 +857,13 @@
 		case 3:
 			if (!cpu_is_omap44xx())
 				return;
-			base = OMAP4_MMC4_BASE + OMAP4_MMC_REG_OFFSET;
+			base = OMAP4_MMC4_BASE;
 			irq = OMAP44XX_IRQ_MMC4;
 			break;
 		case 4:
 			if (!cpu_is_omap44xx())
 				return;
-			base = OMAP4_MMC5_BASE + OMAP4_MMC_REG_OFFSET;
+			base = OMAP4_MMC5_BASE;
 			irq = OMAP44XX_IRQ_MMC5;
 			break;
 		default:
@@ -762,10 +874,8 @@
 			size = OMAP2420_MMC_SIZE;
 			name = "mmci-omap";
 		} else if (cpu_is_omap44xx()) {
-			if (i < 3) {
-				base += OMAP4_MMC_REG_OFFSET;
+			if (i < 3)
 				irq += OMAP44XX_IRQ_GIC_START;
-			}
 			size = OMAP4_HSMMC_SIZE;
 			name = "mmci-omap-hs";
 		} else {
@@ -841,12 +951,74 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Inorder to avoid any assumptions from bootloader regarding WDT
+ * settings, WDT module is reset during init. This enables the watchdog
+ * timer. Hence it is required to disable the watchdog after the WDT reset
+ * during init. Otherwise the system would reboot as per the default
+ * watchdog timer registers settings.
+ */
+#define OMAP_WDT_WPS	(0x34)
+#define OMAP_WDT_SPR	(0x48)
+
+static int omap2_disable_wdt(struct omap_hwmod *oh, void *unused)
+{
+	void __iomem *base;
+	int ret;
+
+	if (!oh) {
+		pr_err("%s: Could not look up wdtimer_hwmod\n", __func__);
+		return -EINVAL;
+	}
+
+	base = omap_hwmod_get_mpu_rt_va(oh);
+	if (!base) {
+		pr_err("%s: Could not get the base address for %s\n",
+				oh->name, __func__);
+		return -EINVAL;
+	}
+
+	/* Enable the clocks before accessing the WDT registers */
+	ret = omap_hwmod_enable(oh);
+	if (ret) {
+		pr_err("%s: Could not enable clocks for %s\n",
+				oh->name, __func__);
+		return ret;
+	}
+
+	/* sequence required to disable watchdog */
+	__raw_writel(0xAAAA, base + OMAP_WDT_SPR);
+	while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+		cpu_relax();
+
+	__raw_writel(0x5555, base + OMAP_WDT_SPR);
+	while (__raw_readl(base + OMAP_WDT_WPS) & 0x10)
+		cpu_relax();
+
+	ret = omap_hwmod_idle(oh);
+	if (ret)
+		pr_err("%s: Could not disable clocks for %s\n",
+				oh->name, __func__);
+
+	return ret;
+}
+
+static void __init omap_disable_wdt(void)
+{
+	if (cpu_class_is_omap2())
+		omap_hwmod_for_each_by_class("wd_timer",
+						omap2_disable_wdt, NULL);
+	return;
+}
+
 static int __init omap2_init_devices(void)
 {
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
+	omap_disable_wdt();
 	omap_hsmmc_reset();
+	omap_init_audio();
 	omap_init_camera();
 	omap_init_mbox();
 	omap_init_mcspi();
@@ -854,8 +1026,45 @@
 	omap_hdq_init();
 	omap_init_sti();
 	omap_init_sham();
+	omap_init_aes();
 	omap_init_vout();
 
 	return 0;
 }
 arch_initcall(omap2_init_devices);
+
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+struct omap_device_pm_latency omap_wdt_latency[] = {
+	[0] = {
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func   = omap_device_enable_hwmods,
+		.flags		 = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+static int __init omap_init_wdt(void)
+{
+	int id = -1;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+	char *oh_name = "wd_timer2";
+	char *dev_name = "omap_wdt";
+
+	if (!cpu_class_is_omap2())
+		return 0;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up wd_timer%d hwmod\n", id);
+		return -EINVAL;
+	}
+
+	od = omap_device_build(dev_name, id, oh, NULL, 0,
+				omap_wdt_latency,
+				ARRAY_SIZE(omap_wdt_latency), 0);
+	WARN(IS_ERR(od), "Cant build omap_device for %s:%s.\n",
+				dev_name, oh->name);
+	return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/dsp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/dsp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/dsp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/dsp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,85 @@
+/*
+ * TI's OMAP DSP platform device registration
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include "prm.h"
+#include "cm.h"
+#ifdef CONFIG_BRIDGE_DVFS
+#include <plat/omap-pm.h>
+#endif
+
+#include <plat/dsp.h>
+
+extern phys_addr_t omap_dsp_get_mempool_base(void);
+
+static struct platform_device *omap_dsp_pdev;
+
+static struct omap_dsp_platform_data omap_dsp_pdata __initdata = {
+#ifdef CONFIG_BRIDGE_DVFS
+	.dsp_set_min_opp = omap_pm_dsp_set_min_opp,
+	.dsp_get_opp = omap_pm_dsp_get_opp,
+	.cpu_set_freq = omap_pm_cpu_set_freq,
+	.cpu_get_freq = omap_pm_cpu_get_freq,
+#endif
+	.dsp_prm_read = prm_read_mod_reg,
+	.dsp_prm_write = prm_write_mod_reg,
+	.dsp_prm_rmw_bits = prm_rmw_mod_reg_bits,
+	.dsp_cm_read = cm_read_mod_reg,
+	.dsp_cm_write = cm_write_mod_reg,
+	.dsp_cm_rmw_bits = cm_rmw_mod_reg_bits,
+};
+
+static int __init omap_dsp_init(void)
+{
+	struct platform_device *pdev;
+	int err = -ENOMEM;
+	struct omap_dsp_platform_data *pdata = &omap_dsp_pdata;
+
+	pdata->phys_mempool_base = omap_dsp_get_mempool_base();
+
+	if (pdata->phys_mempool_base) {
+		pdata->phys_mempool_size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
+		pr_info("%s: %x bytes @ %x\n", __func__,
+			pdata->phys_mempool_size, pdata->phys_mempool_base);
+	}
+
+	pdev = platform_device_alloc("omap-dsp", -1);
+	if (!pdev)
+		goto err_out;
+
+	err = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+	if (err)
+		goto err_out;
+
+	err = platform_device_add(pdev);
+	if (err)
+		goto err_out;
+
+	omap_dsp_pdev = pdev;
+	return 0;
+
+err_out:
+	platform_device_put(pdev);
+	return err;
+}
+module_init(omap_dsp_init);
+
+static void __exit omap_dsp_exit(void)
+{
+	platform_device_unregister(omap_dsp_pdev);
+}
+module_exit(omap_dsp_exit);
+
+MODULE_AUTHOR("Hiroshi DOYU");
+MODULE_DESCRIPTION("TI's OMAP DSP platform device registration");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/gpmc-smsc911x.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/gpmc-smsc911x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/gpmc-smsc911x.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/gpmc-smsc911x.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,113 @@
+/*
+ * linux/arch/arm/mach-omap2/gpmc-smsc911x.c
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from linux/arch/arm/mach-omap2/gpmc-smc91x.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/smsc911x.h>
+
+#include <plat/board.h>
+#include <plat/gpmc.h>
+#include <plat/gpmc-smsc911x.h>
+
+static struct omap_smsc911x_platform_data *gpmc_cfg;
+
+static struct resource gpmc_smsc911x_resources[] = {
+	[0] = {
+		.flags		= IORESOURCE_MEM,
+	},
+	[1] = {
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct smsc911x_platform_config gpmc_smsc911x_config = {
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags		= SMSC911X_USE_16BIT,
+};
+
+static struct platform_device gpmc_smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(gpmc_smsc911x_resources),
+	.resource	= gpmc_smsc911x_resources,
+	.dev		= {
+		.platform_data = &gpmc_smsc911x_config,
+	},
+};
+
+/*
+ * Initialize smsc911x device connected to the GPMC. Note that we
+ * assume that pin multiplexing is done in the board-*.c file,
+ * or in the bootloader.
+ */
+void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
+{
+	unsigned long cs_mem_base;
+	int ret;
+
+	gpmc_cfg = board_data;
+
+	if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
+		printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+		return;
+	}
+
+	gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
+	gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
+
+	if (gpio_request(gpmc_cfg->gpio_irq, "smsc911x irq") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
+				gpmc_cfg->gpio_irq);
+		goto free1;
+	}
+
+	gpio_direction_input(gpmc_cfg->gpio_irq);
+	gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
+	gpmc_smsc911x_resources[1].flags |=
+					(gpmc_cfg->flags & IRQF_TRIGGER_MASK);
+
+	if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
+		ret = gpio_request(gpmc_cfg->gpio_reset, "smsc911x reset");
+		if (ret) {
+			printk(KERN_ERR "Failed to request GPIO%d for smsc911x reset\n",
+					gpmc_cfg->gpio_reset);
+			goto free2;
+		}
+
+		gpio_direction_output(gpmc_cfg->gpio_reset, 1);
+		gpio_set_value(gpmc_cfg->gpio_reset, 0);
+		msleep(100);
+		gpio_set_value(gpmc_cfg->gpio_reset, 1);
+	}
+
+	if (platform_device_register(&gpmc_smsc911x_device) < 0) {
+		printk(KERN_ERR "Unable to register smsc911x device\n");
+		gpio_free(gpmc_cfg->gpio_reset);
+		goto free2;
+	}
+
+	return;
+
+free2:
+	gpio_free(gpmc_cfg->gpio_irq);
+free1:
+	gpmc_cs_free(gpmc_cfg->cs);
+
+	printk(KERN_ERR "Could not initialize smsc911x\n");
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/hsmmc.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/hsmmc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/hsmmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/hsmmc.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,11 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <mach/hardware.h>
-#include <plat/control.h>
 #include <plat/mmc.h>
 #include <plat/omap-pm.h>
 
 #include "hsmmc.h"
+#include "control.h"
 
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
@@ -135,10 +135,11 @@
 	 *
 	 * FIXME handle VMMC1A as needed ...
 	 */
-	reg = omap_ctrl_readl(control_pbias_offset);
-	reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
-					OMAP4_USBC1_ICUSB_PWRDNZ);
-	omap_ctrl_writel(reg, control_pbias_offset);
+	reg = omap4_ctrl_pad_readl(control_pbias_offset);
+	reg &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+		OMAP4_MMC1_PWRDNZ_MASK |
+		OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+	omap4_ctrl_pad_writel(reg, control_pbias_offset);
 }
 
 static void omap4_hsmmc1_after_set_reg(struct device *dev, int slot,
@@ -147,30 +148,33 @@
 	u32 reg;
 
 	if (power_on) {
-		reg = omap_ctrl_readl(control_pbias_offset);
-		reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ;
+		reg = omap4_ctrl_pad_readl(control_pbias_offset);
+		reg |= OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK;
 		if ((1 << vdd) <= MMC_VDD_165_195)
-			reg &= ~OMAP4_MMC1_PBIASLITE_VMODE;
+			reg &= ~OMAP4_MMC1_PBIASLITE_VMODE_MASK;
 		else
-			reg |= OMAP4_MMC1_PBIASLITE_VMODE;
-		reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
-						OMAP4_USBC1_ICUSB_PWRDNZ);
-		omap_ctrl_writel(reg, control_pbias_offset);
+			reg |= OMAP4_MMC1_PBIASLITE_VMODE_MASK;
+		reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+			OMAP4_MMC1_PWRDNZ_MASK |
+			OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+		omap4_ctrl_pad_writel(reg, control_pbias_offset);
 		/* 4 microsec delay for comparator to generate an error*/
 		udelay(4);
-		reg = omap_ctrl_readl(control_pbias_offset);
-		if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR) {
+		reg = omap4_ctrl_pad_readl(control_pbias_offset);
+		if (reg & OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK) {
 			pr_err("Pbias Voltage is not same as LDO\n");
 			/* Caution : On VMODE_ERROR Power Down MMC IO */
-			reg &= ~(OMAP4_MMC1_PWRDNZ | OMAP4_USBC1_ICUSB_PWRDNZ);
-			omap_ctrl_writel(reg, control_pbias_offset);
+			reg &= ~(OMAP4_MMC1_PWRDNZ_MASK |
+				OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+			omap4_ctrl_pad_writel(reg, control_pbias_offset);
 		}
 	} else {
-		reg = omap_ctrl_readl(control_pbias_offset);
-		 reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ |
-			OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PWRDNZ |
-			OMAP4_USBC1_ICUSB_PWRDNZ);
-		omap_ctrl_writel(reg, control_pbias_offset);
+		reg = omap4_ctrl_pad_readl(control_pbias_offset);
+		reg |= (OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK |
+			OMAP4_MMC1_PWRDNZ_MASK |
+			OMAP4_MMC1_PBIASLITE_VMODE_MASK |
+			OMAP4_USBC1_ICUSB_PWRDNZ_MASK);
+		omap4_ctrl_pad_writel(reg, control_pbias_offset);
 	}
 }
 
@@ -218,17 +222,18 @@
 			control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1;
 		}
 	} else {
-		control_pbias_offset = OMAP44XX_CONTROL_PBIAS_LITE;
-		control_mmc1 = OMAP44XX_CONTROL_MMC1;
-		reg = omap_ctrl_readl(control_mmc1);
-		reg |= (OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0 |
-			OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1);
-		reg &= ~(OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2 |
-			OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3);
-		reg |= (OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL |
-			OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL |
-			OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL);
-		omap_ctrl_writel(reg, control_mmc1);
+		control_pbias_offset =
+			OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE;
+		control_mmc1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1;
+		reg = omap4_ctrl_pad_readl(control_mmc1);
+		reg |= (OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK |
+			OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK);
+		reg &= ~(OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK |
+			OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK);
+		reg |= (OMAP4_USBC1_DR0_SPEEDCTRL_MASK|
+			OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK |
+			OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK);
+		omap4_ctrl_pad_writel(reg, control_mmc1);
 	}
 
 	for (c = controllers; c->mmc; c++) {
@@ -258,9 +263,13 @@
 				"mmc%islot%i", c->mmc, 1);
 		mmc->slots[0].name = hc->name;
 		mmc->nr_slots = 1;
-		mmc->slots[0].wires = c->wires;
+		mmc->slots[0].caps = c->caps;
 		mmc->slots[0].internal_clock = !c->ext_clock;
 		mmc->dma_mask = 0xffffffff;
+		if (cpu_is_omap44xx())
+			mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
+		else
+			mmc->reg_offset = 0;
 
 		mmc->get_context_loss_count = hsmmc_get_context_loss;
 
@@ -298,6 +307,9 @@
 		else
 			mmc->slots[0].features |= HSMMC_HAS_PBIAS;
 
+		if (cpu_is_omap44xx() && (omap_rev() > OMAP4430_REV_ES1_0))
+			mmc->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
 		switch (c->mmc) {
 		case 1:
 			if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
@@ -316,16 +328,20 @@
 			}
 
 			/* Omap3630 HSMMC1 supports only 4-bit */
-			if (cpu_is_omap3630() && c->wires > 4) {
-				c->wires = 4;
-				mmc->slots[0].wires = c->wires;
+			if (cpu_is_omap3630() &&
+					(c->caps & MMC_CAP_8_BIT_DATA)) {
+				c->caps &= ~MMC_CAP_8_BIT_DATA;
+				c->caps |= MMC_CAP_4_BIT_DATA;
+				mmc->slots[0].caps = c->caps;
 			}
 			break;
 		case 2:
 			if (c->ext_clock)
 				c->transceiver = 1;
-			if (c->transceiver && c->wires > 4)
-				c->wires = 4;
+			if (c->transceiver && (c->caps & MMC_CAP_8_BIT_DATA)) {
+				c->caps &= ~MMC_CAP_8_BIT_DATA;
+				c->caps |= MMC_CAP_4_BIT_DATA;
+			}
 			/* FALLTHROUGH */
 		case 3:
 			if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/hsmmc.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/hsmmc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/hsmmc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/hsmmc.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,8 @@
 
 struct omap2_hsmmc_info {
 	u8	mmc;		/* controller 1/2/3 */
-	u8	wires;		/* 1/4/8 wires */
+	u32	caps;		/* 4/8 wires and any additional host
+				 * capabilities OR'd (ref. linux/mmc/host.h) */
 	bool	transceiver;	/* MMC-2 option */
 	bool	ext_clock;	/* use external pin for input clock */
 	bool	cover_only;	/* No card detect - just cover switch */
@@ -23,7 +24,7 @@
 	char	*name;		/* or NULL for default */
 	struct device *dev;	/* returned: pointer to mmc adapter */
 	int	ocr_mask;	/* temporary HACK */
-	/* Remux (pad configuation) when powering on/off */
+	/* Remux (pad configuration) when powering on/off */
 	void (*remux)(struct device *dev, int slot, int power_on);
 	/* init some special card */
 	void (*init_card)(struct mmc_card *card);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/id.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/id.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/id.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/id.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,11 +22,12 @@
 #include <asm/cputype.h>
 
 #include <plat/common.h>
-#include <plat/control.h>
 #include <plat/cpu.h>
 
 #include <mach/id.h>
 
+#include "control.h"
+
 static struct omap_chip_id omap_chip;
 static unsigned int omap_revision;
 
@@ -60,7 +61,7 @@
 	} else if (cpu_is_omap34xx()) {
 		val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
 	} else if (cpu_is_omap44xx()) {
-		val = omap_ctrl_readl(OMAP44XX_CONTROL_STATUS);
+		val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
 	} else {
 		pr_err("Cannot detect omap type!\n");
 		goto out;
@@ -298,7 +299,6 @@
 	u32 idcode;
 	u16 hawkeye;
 	u8 rev;
-	char *rev_name = "ES1.0";
 
 	/*
 	 * The IC rev detection is done with hawkeye and rev.
@@ -309,14 +309,39 @@
 	hawkeye = (idcode >> 12) & 0xffff;
 	rev = (idcode >> 28) & 0xff;
 
-	if ((hawkeye == 0xb852) && (rev == 0x0)) {
-		omap_revision = OMAP4430_REV_ES1_0;
-		omap_chip.oc |= CHIP_IS_OMAP4430ES1;
-		pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
-		return;
+	/*
+	 * Few initial ES2.0 samples IDCODE is same as ES1.0
+	 * Use ARM register to detect the correct ES version
+	 */
+	if (!rev) {
+		idcode = read_cpuid(CPUID_ID);
+		rev = (idcode & 0xf) - 1;
 	}
 
-	pr_err("Unknown OMAP4 CPU id\n");
+	switch (hawkeye) {
+	case 0xb852:
+		switch (rev) {
+		case 0:
+			omap_revision = OMAP4430_REV_ES1_0;
+			omap_chip.oc |= CHIP_IS_OMAP4430ES1;
+			break;
+		case 1:
+			omap_revision = OMAP4430_REV_ES2_0;
+			omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+			break;
+		default:
+			omap_revision = OMAP4430_REV_ES2_0;
+			omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+	}
+	break;
+	default:
+		/* Unknown default to latest silicon rev as default*/
+		omap_revision = OMAP4430_REV_ES2_0;
+		omap_chip.oc |= CHIP_IS_OMAP4430ES2;
+	}
+
+	pr_info("OMAP%04x ES%d.0\n",
+			omap_rev() >> 16, ((omap_rev() >> 12) & 0xf) + 1);
 }
 
 #define OMAP3_SHOW_FEATURE(feat)		\
@@ -361,30 +386,54 @@
 		strcpy(cpu_name, "OMAP3503");
 	}
 
-	switch (rev) {
-	case OMAP_REVBITS_00:
-		strcpy(cpu_rev, "1.0");
-		break;
-	case OMAP_REVBITS_01:
-		strcpy(cpu_rev, "1.1");
-		break;
-	case OMAP_REVBITS_02:
-		strcpy(cpu_rev, "1.2");
-		break;
-	case OMAP_REVBITS_10:
-		strcpy(cpu_rev, "2.0");
-		break;
-	case OMAP_REVBITS_20:
-		strcpy(cpu_rev, "2.1");
-		break;
-	case OMAP_REVBITS_30:
-		strcpy(cpu_rev, "3.0");
-		break;
-	case OMAP_REVBITS_40:
-	/* FALLTHROUGH */
-	default:
-		/* Use the latest known revision as default */
-		strcpy(cpu_rev, "3.1");
+	if (cpu_is_omap3630()) {
+		switch (rev) {
+		case OMAP_REVBITS_00:
+			strcpy(cpu_rev, "1.0");
+			break;
+		case OMAP_REVBITS_01:
+			strcpy(cpu_rev, "1.1");
+			break;
+		case OMAP_REVBITS_02:
+			/* FALLTHROUGH */
+		default:
+			/* Use the latest known revision as default */
+			strcpy(cpu_rev, "1.2");
+		}
+	} else if (cpu_is_omap3505() || cpu_is_omap3517()) {
+		switch (rev) {
+		case OMAP_REVBITS_00:
+			strcpy(cpu_rev, "1.0");
+			break;
+		case OMAP_REVBITS_01:
+			/* FALLTHROUGH */
+		default:
+			/* Use the latest known revision as default */
+			strcpy(cpu_rev, "1.1");
+		}
+	} else {
+		switch (rev) {
+		case OMAP_REVBITS_00:
+			strcpy(cpu_rev, "1.0");
+			break;
+		case OMAP_REVBITS_01:
+			strcpy(cpu_rev, "2.0");
+			break;
+		case OMAP_REVBITS_02:
+			strcpy(cpu_rev, "2.1");
+			break;
+		case OMAP_REVBITS_03:
+			strcpy(cpu_rev, "3.0");
+			break;
+		case OMAP_REVBITS_04:
+			strcpy(cpu_rev, "3.1");
+			break;
+		case OMAP_REVBITS_05:
+			/* FALLTHROUGH */
+		default:
+			/* Use the latest known revision as default */
+			strcpy(cpu_rev, "3.1.2");
+		}
 	}
 
 	/* Print verbose information */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-flash.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-flash.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-flash.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-flash.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,28 +0,0 @@
-/*
- *  board-sdp.h
- *
- *  Information structures for SDP-specific board config data
- *
- *  Copyright (C) 2009 Nokia Corporation
- *  Copyright (C) 2009 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <plat/gpmc.h>
-
-#define PDC_NOR		1
-#define PDC_NAND	2
-#define PDC_ONENAND	3
-#define DBG_MPDB	4
-
-struct flash_partitions {
-	struct mtd_partition *parts;
-	int nr_parts;
-};
-
-extern void board_flash_init(struct flash_partitions [],
-				char chip_sel[][GPMC_CS_NUM]);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-rx51.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-rx51.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-rx51.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-rx51.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,11 @@
+/*
+ * Defines for rx51 boards
+ */
+
+#ifndef _OMAP_BOARD_RX51_H
+#define _OMAP_BOARD_RX51_H
+
+extern void __init rx51_peripherals_init(void);
+extern void __init rx51_video_mem_init(void);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-zoom.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-zoom.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/board-zoom.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/board-zoom.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,11 +1,9 @@
 /*
  * Defines for zoom boards
  */
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
 #define ZOOM_NAND_CS    0
 
-extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO	153
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_core_44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,391 @@
+/*
+ * OMAP44xx CTRL_MODULE_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_CORE					0x4a002000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_CORE_IP_REVISION			0x0000
+#define OMAP4_CTRL_MODULE_CORE_IP_HWINFO			0x0004
+#define OMAP4_CTRL_MODULE_CORE_IP_SYSCONFIG			0x0010
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_0		0x0200
+#define OMAP4_CTRL_MODULE_CORE_ID_CODE				0x0204
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_1		0x0208
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_2		0x020c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_DIE_ID_3		0x0210
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_0		0x0214
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1		0x0218
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_USB_CONF		0x021c
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_VDD_WKUP		0x0228
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP		0x0260
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_0		0x0264
+#define OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_1		0x0268
+#define OMAP4_CTRL_MODULE_CORE_STATUS				0x02c4
+#define OMAP4_CTRL_MODULE_CORE_DEV_CONF				0x0300
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_IVA_VOLTAGE_CTRL		0x0314
+#define OMAP4_CTRL_MODULE_CORE_LDOVBB_MPU_VOLTAGE_CTRL		0x0318
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_IVA_VOLTAGE_CTRL		0x0320
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_MPU_VOLTAGE_CTRL		0x0324
+#define OMAP4_CTRL_MODULE_CORE_LDOSRAM_CORE_VOLTAGE_CTRL	0x0328
+#define OMAP4_CTRL_MODULE_CORE_TEMP_SENSOR			0x032c
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_0		0x0330
+#define OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_1		0x0334
+#define OMAP4_CTRL_MODULE_CORE_USBOTGHS_CONTROL			0x033c
+#define OMAP4_CTRL_MODULE_CORE_DSS_CONTROL			0x0340
+#define OMAP4_CTRL_MODULE_CORE_HWOBS_CONTROL			0x0350
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_FINAL_MUX_SEL		0x0400
+#define OMAP4_CTRL_MODULE_CORE_DEBOBS_MMR_MPU			0x0408
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL0		0x042c
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL1		0x0430
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL2		0x0434
+#define OMAP4_CTRL_MODULE_CORE_CONF_SDMA_REQ_SEL3		0x0438
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL0			0x0440
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL1			0x0444
+#define OMAP4_CTRL_MODULE_CORE_CONF_CLK_SEL2			0x0448
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_FREQLOCK_SEL		0x044c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_TINITZ_SEL		0x0450
+#define OMAP4_CTRL_MODULE_CORE_CONF_DPLL_PHASELOCK_SEL		0x0454
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_0		0x0480
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_1		0x0484
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_2		0x0488
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_3		0x048c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_4		0x0490
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_5		0x0494
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_6		0x0498
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_7		0x049c
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_8		0x04a0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_9		0x04a4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_10		0x04a8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_11		0x04ac
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_12		0x04b0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_13		0x04b4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_14		0x04b8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_15		0x04bc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_16		0x04c0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_17		0x04c4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_18		0x04c8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_19		0x04cc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_20		0x04d0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_21		0x04d4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_22		0x04d8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_23		0x04dc
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_24		0x04e0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_25		0x04e4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_26		0x04e8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_27		0x04ec
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_28		0x04f0
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_29		0x04f4
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_30		0x04f8
+#define OMAP4_CTRL_MODULE_CORE_CONF_DEBUG_SEL_TST_31		0x04fc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT			30
+#define OMAP4_IP_REV_SCHEME_MASK			(0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT				16
+#define OMAP4_IP_REV_FUNC_MASK				(0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT				11
+#define OMAP4_IP_REV_RTL_MASK				(0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT			8
+#define OMAP4_IP_REV_MAJOR_MASK				(0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT			6
+#define OMAP4_IP_REV_CUSTOM_MASK			(0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT			0
+#define OMAP4_IP_REV_MINOR_MASK				(0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT				0
+#define OMAP4_IP_HWINFO_MASK				(0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT		2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK		(0x3 << 2)
+
+/* STD_FUSE_DIE_ID_0 */
+#define OMAP4_STD_FUSE_DIE_ID_0_SHIFT			0
+#define OMAP4_STD_FUSE_DIE_ID_0_MASK			(0xffffffff << 0)
+
+/* ID_CODE */
+#define OMAP4_STD_FUSE_IDCODE_SHIFT			0
+#define OMAP4_STD_FUSE_IDCODE_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_1 */
+#define OMAP4_STD_FUSE_DIE_ID_1_SHIFT			0
+#define OMAP4_STD_FUSE_DIE_ID_1_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_2 */
+#define OMAP4_STD_FUSE_DIE_ID_2_SHIFT			0
+#define OMAP4_STD_FUSE_DIE_ID_2_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_DIE_ID_3 */
+#define OMAP4_STD_FUSE_DIE_ID_3_SHIFT			0
+#define OMAP4_STD_FUSE_DIE_ID_3_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_0 */
+#define OMAP4_STD_FUSE_PROD_ID_0_SHIFT			0
+#define OMAP4_STD_FUSE_PROD_ID_0_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_PROD_ID_1 */
+#define OMAP4_STD_FUSE_PROD_ID_1_SHIFT			0
+#define OMAP4_STD_FUSE_PROD_ID_1_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_USB_CONF */
+#define OMAP4_USB_PROD_ID_SHIFT				16
+#define OMAP4_USB_PROD_ID_MASK				(0xffff << 16)
+#define OMAP4_USB_VENDOR_ID_SHIFT			0
+#define OMAP4_USB_VENDOR_ID_MASK			(0xffff << 0)
+
+/* STD_FUSE_OPP_VDD_WKUP */
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_SHIFT		0
+#define OMAP4_STD_FUSE_OPP_VDD_WKUP_MASK		(0xffffffff << 0)
+
+/* STD_FUSE_OPP_BGAP */
+#define OMAP4_STD_FUSE_OPP_BGAP_SHIFT			0
+#define OMAP4_STD_FUSE_OPP_BGAP_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_0 */
+#define OMAP4_STD_FUSE_OPP_DPLL_0_SHIFT			0
+#define OMAP4_STD_FUSE_OPP_DPLL_0_MASK			(0xffffffff << 0)
+
+/* STD_FUSE_OPP_DPLL_1 */
+#define OMAP4_STD_FUSE_OPP_DPLL_1_SHIFT			0
+#define OMAP4_STD_FUSE_OPP_DPLL_1_MASK			(0xffffffff << 0)
+
+/* STATUS */
+#define OMAP4_ATTILA_CONF_SHIFT				11
+#define OMAP4_ATTILA_CONF_MASK				(0x3 << 11)
+#define OMAP4_DEVICE_TYPE_SHIFT				8
+#define OMAP4_DEVICE_TYPE_MASK				(0x7 << 8)
+#define OMAP4_SYS_BOOT_SHIFT				0
+#define OMAP4_SYS_BOOT_MASK				(0xff << 0)
+
+/* DEV_CONF */
+#define OMAP4_DEV_CONF_SHIFT				1
+#define OMAP4_DEV_CONF_MASK				(0x7fffffff << 1)
+#define OMAP4_USBPHY_PD_SHIFT				0
+#define OMAP4_USBPHY_PD_MASK				(1 << 0)
+
+/* LDOVBB_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_SHIFT		26
+#define OMAP4_LDOVBBIVA_RBB_MUX_CTRL_MASK		(1 << 26)
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_SHIFT		21
+#define OMAP4_LDOVBBIVA_RBB_VSET_IN_MASK		(0x1f << 21)
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_SHIFT		16
+#define OMAP4_LDOVBBIVA_RBB_VSET_OUT_MASK		(0x1f << 16)
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_SHIFT		10
+#define OMAP4_LDOVBBIVA_FBB_MUX_CTRL_MASK		(1 << 10)
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_SHIFT		5
+#define OMAP4_LDOVBBIVA_FBB_VSET_IN_MASK		(0x1f << 5)
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_SHIFT		0
+#define OMAP4_LDOVBBIVA_FBB_VSET_OUT_MASK		(0x1f << 0)
+
+/* LDOVBB_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_SHIFT		26
+#define OMAP4_LDOVBBMPU_RBB_MUX_CTRL_MASK		(1 << 26)
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_SHIFT		21
+#define OMAP4_LDOVBBMPU_RBB_VSET_IN_MASK		(0x1f << 21)
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_SHIFT		16
+#define OMAP4_LDOVBBMPU_RBB_VSET_OUT_MASK		(0x1f << 16)
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_SHIFT		10
+#define OMAP4_LDOVBBMPU_FBB_MUX_CTRL_MASK		(1 << 10)
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_SHIFT		5
+#define OMAP4_LDOVBBMPU_FBB_VSET_IN_MASK		(0x1f << 5)
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_SHIFT		0
+#define OMAP4_LDOVBBMPU_FBB_VSET_OUT_MASK		(0x1f << 0)
+
+/* LDOSRAM_IVA_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_SHIFT		26
+#define OMAP4_LDOSRAMIVA_RETMODE_MUX_CTRL_MASK		(1 << 26)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_SHIFT		21
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_IN_MASK		(0x1f << 21)
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_SHIFT		16
+#define OMAP4_LDOSRAMIVA_RETMODE_VSET_OUT_MASK		(0x1f << 16)
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_SHIFT		10
+#define OMAP4_LDOSRAMIVA_ACTMODE_MUX_CTRL_MASK		(1 << 10)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_SHIFT		5
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_IN_MASK		(0x1f << 5)
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_SHIFT		0
+#define OMAP4_LDOSRAMIVA_ACTMODE_VSET_OUT_MASK		(0x1f << 0)
+
+/* LDOSRAM_MPU_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_SHIFT		26
+#define OMAP4_LDOSRAMMPU_RETMODE_MUX_CTRL_MASK		(1 << 26)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_SHIFT		21
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_IN_MASK		(0x1f << 21)
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_SHIFT		16
+#define OMAP4_LDOSRAMMPU_RETMODE_VSET_OUT_MASK		(0x1f << 16)
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_SHIFT		10
+#define OMAP4_LDOSRAMMPU_ACTMODE_MUX_CTRL_MASK		(1 << 10)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_SHIFT		5
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_IN_MASK		(0x1f << 5)
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_SHIFT		0
+#define OMAP4_LDOSRAMMPU_ACTMODE_VSET_OUT_MASK		(0x1f << 0)
+
+/* LDOSRAM_CORE_VOLTAGE_CTRL */
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_SHIFT	26
+#define OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_MASK		(1 << 26)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_SHIFT		21
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_IN_MASK		(0x1f << 21)
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_SHIFT	16
+#define OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_MASK		(0x1f << 16)
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_SHIFT	10
+#define OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_MASK		(1 << 10)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_SHIFT		5
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_IN_MASK		(0x1f << 5)
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT	0
+#define OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_MASK		(0x1f << 0)
+
+/* TEMP_SENSOR */
+#define OMAP4_BGAP_TEMPSOFF_SHIFT			12
+#define OMAP4_BGAP_TEMPSOFF_MASK			(1 << 12)
+#define OMAP4_BGAP_TSHUT_SHIFT				11
+#define OMAP4_BGAP_TSHUT_MASK				(1 << 11)
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_SHIFT		10
+#define OMAP4_BGAP_TEMP_SENSOR_CONTCONV_MASK		(1 << 10)
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_SHIFT		9
+#define OMAP4_BGAP_TEMP_SENSOR_SOC_MASK			(1 << 9)
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_SHIFT		8
+#define OMAP4_BGAP_TEMP_SENSOR_EOCZ_MASK		(1 << 8)
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_SHIFT		0
+#define OMAP4_BGAP_TEMP_SENSOR_DTEMP_MASK		(0xff << 0)
+
+/* DPLL_NWELL_TRIM_0 */
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_SHIFT	29
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MUX_CTRL_MASK		(1 << 29)
+#define OMAP4_DPLL_ABE_NWELL_TRIM_SHIFT			24
+#define OMAP4_DPLL_ABE_NWELL_TRIM_MASK			(0x1f << 24)
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_SHIFT	23
+#define OMAP4_DPLL_PER_NWELL_TRIM_MUX_CTRL_MASK		(1 << 23)
+#define OMAP4_DPLL_PER_NWELL_TRIM_SHIFT			18
+#define OMAP4_DPLL_PER_NWELL_TRIM_MASK			(0x1f << 18)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_SHIFT	17
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MUX_CTRL_MASK	(1 << 17)
+#define OMAP4_DPLL_CORE_NWELL_TRIM_SHIFT		12
+#define OMAP4_DPLL_CORE_NWELL_TRIM_MASK			(0x1f << 12)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_SHIFT	11
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MUX_CTRL_MASK		(1 << 11)
+#define OMAP4_DPLL_IVA_NWELL_TRIM_SHIFT			6
+#define OMAP4_DPLL_IVA_NWELL_TRIM_MASK			(0x1f << 6)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_SHIFT	5
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MUX_CTRL_MASK		(1 << 5)
+#define OMAP4_DPLL_MPU_NWELL_TRIM_SHIFT			0
+#define OMAP4_DPLL_MPU_NWELL_TRIM_MASK			(0x1f << 0)
+
+/* DPLL_NWELL_TRIM_1 */
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_SHIFT	29
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MUX_CTRL_MASK	(1 << 29)
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_SHIFT		24
+#define OMAP4_DPLL_UNIPRO_NWELL_TRIM_MASK		(0x1f << 24)
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_SHIFT	23
+#define OMAP4_DPLL_USB_NWELL_TRIM_MUX_CTRL_MASK		(1 << 23)
+#define OMAP4_DPLL_USB_NWELL_TRIM_SHIFT			18
+#define OMAP4_DPLL_USB_NWELL_TRIM_MASK			(0x1f << 18)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_SHIFT	17
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MUX_CTRL_MASK	(1 << 17)
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_SHIFT		12
+#define OMAP4_DPLL_HDMI_NWELL_TRIM_MASK			(0x1f << 12)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_SHIFT	11
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MUX_CTRL_MASK	(1 << 11)
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_SHIFT		6
+#define OMAP4_DPLL_DSI2_NWELL_TRIM_MASK			(0x1f << 6)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_SHIFT	5
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MUX_CTRL_MASK	(1 << 5)
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_SHIFT		0
+#define OMAP4_DPLL_DSI1_NWELL_TRIM_MASK			(0x1f << 0)
+
+/* USBOTGHS_CONTROL */
+#define OMAP4_DISCHRGVBUS_SHIFT				8
+#define OMAP4_DISCHRGVBUS_MASK				(1 << 8)
+#define OMAP4_CHRGVBUS_SHIFT				7
+#define OMAP4_CHRGVBUS_MASK				(1 << 7)
+#define OMAP4_DRVVBUS_SHIFT				6
+#define OMAP4_DRVVBUS_MASK				(1 << 6)
+#define OMAP4_IDPULLUP_SHIFT				5
+#define OMAP4_IDPULLUP_MASK				(1 << 5)
+#define OMAP4_IDDIG_SHIFT				4
+#define OMAP4_IDDIG_MASK				(1 << 4)
+#define OMAP4_SESSEND_SHIFT				3
+#define OMAP4_SESSEND_MASK				(1 << 3)
+#define OMAP4_VBUSVALID_SHIFT				2
+#define OMAP4_VBUSVALID_MASK				(1 << 2)
+#define OMAP4_BVALID_SHIFT				1
+#define OMAP4_BVALID_MASK				(1 << 1)
+#define OMAP4_AVALID_SHIFT				0
+#define OMAP4_AVALID_MASK				(1 << 0)
+
+/* DSS_CONTROL */
+#define OMAP4_DSS_MUX6_SELECT_SHIFT			0
+#define OMAP4_DSS_MUX6_SELECT_MASK			(1 << 0)
+
+/* HWOBS_CONTROL */
+#define OMAP4_HWOBS_CLKDIV_SEL_SHIFT			3
+#define OMAP4_HWOBS_CLKDIV_SEL_MASK			(0x1f << 3)
+#define OMAP4_HWOBS_ALL_ZERO_MODE_SHIFT			2
+#define OMAP4_HWOBS_ALL_ZERO_MODE_MASK			(1 << 2)
+#define OMAP4_HWOBS_ALL_ONE_MODE_SHIFT			1
+#define OMAP4_HWOBS_ALL_ONE_MODE_MASK			(1 << 1)
+#define OMAP4_HWOBS_MACRO_ENABLE_SHIFT			0
+#define OMAP4_HWOBS_MACRO_ENABLE_MASK			(1 << 0)
+
+/* DEBOBS_FINAL_MUX_SEL */
+#define OMAP4_SELECT_SHIFT				0
+#define OMAP4_SELECT_MASK				(0xffffffff << 0)
+
+/* DEBOBS_MMR_MPU */
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_SHIFT		0
+#define OMAP4_SELECT_DEBOBS_MMR_MPU_MASK		(0xf << 0)
+
+/* CONF_SDMA_REQ_SEL0 */
+#define OMAP4_MULT_SHIFT				0
+#define OMAP4_MULT_MASK					(0x7f << 0)
+
+/* CONF_CLK_SEL0 */
+#define OMAP4_MULT_CONF_CLK_SEL0_SHIFT			0
+#define OMAP4_MULT_CONF_CLK_SEL0_MASK			(0x7 << 0)
+
+/* CONF_CLK_SEL1 */
+#define OMAP4_MULT_CONF_CLK_SEL1_SHIFT			0
+#define OMAP4_MULT_CONF_CLK_SEL1_MASK			(0x7 << 0)
+
+/* CONF_CLK_SEL2 */
+#define OMAP4_MULT_CONF_CLK_SEL2_SHIFT			0
+#define OMAP4_MULT_CONF_CLK_SEL2_MASK			(0x7 << 0)
+
+/* CONF_DPLL_FREQLOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_SHIFT		0
+#define OMAP4_MULT_CONF_DPLL_FREQLOCK_SEL_MASK		(0x7 << 0)
+
+/* CONF_DPLL_TINITZ_SEL */
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_SHIFT		0
+#define OMAP4_MULT_CONF_DPLL_TINITZ_SEL_MASK		(0x7 << 0)
+
+/* CONF_DPLL_PHASELOCK_SEL */
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_SHIFT	0
+#define OMAP4_MULT_CONF_DPLL_PHASELOCK_SEL_MASK		(0x7 << 0)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_MODE_SHIFT				0
+#define OMAP4_MODE_MASK					(0xf << 0)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_core_44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1409 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_CORE registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_CORE_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_CORE				0x4a100000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_REVISION			0x0000
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_HWINFO			0x0004
+#define OMAP4_CTRL_MODULE_PAD_CORE_IP_SYSCONFIG			0x0010
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_0	0x01d8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_1	0x01dc
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_2	0x01e0
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_3	0x01e4
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_4	0x01e8
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_5	0x01ec
+#define OMAP4_CTRL_MODULE_PAD_CORE_PADCONF_WAKEUPEVENT_6	0x01f0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_GLOBAL	0x05a0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PADCONF_MODE		0x05a4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_0	0x05a8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART1IO_PADCONF_1	0x05ac
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_0	0x05b0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART2IO_PADCONF_1	0x05b4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_0	0x05b8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_1	0x05bc
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SMART3IO_PADCONF_2	0x05c0
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USBB_HSIC		0x05c4
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_SLIMBUS		0x05c8
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_PBIASLITE		0x0600
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0		0x0604
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX		0x0608
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_AVDAC		0x060c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDMI_TX_PHY		0x0610
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC2			0x0614
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_DSIPHY		0x0618
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MCBSPLP		0x061c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB2PHYCORE		0x0620
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1		0x0624
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_MMC1			0x0628
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HSI			0x062c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_USB			0x0630
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_HDQ			0x0634
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_0		0x0638
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_1		0x063c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2		0x0640
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_3		0x0644
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_0		0x0648
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_1		0x064c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2		0x0650
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3		0x0654
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_BUS_HOLD		0x0658
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_C2C			0x065c
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_RW	0x0660
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R		0x0664
+#define OMAP4_CTRL_MODULE_PAD_CORE_CORE_CONTROL_SPARE_R_C0	0x0668
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1		0x0700
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2		0x0704
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_3		0x0708
+#define OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_4		0x070c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT				30
+#define OMAP4_IP_REV_SCHEME_MASK				(0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT					16
+#define OMAP4_IP_REV_FUNC_MASK					(0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT					11
+#define OMAP4_IP_REV_RTL_MASK					(0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT				8
+#define OMAP4_IP_REV_MAJOR_MASK					(0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT				6
+#define OMAP4_IP_REV_CUSTOM_MASK				(0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT				0
+#define OMAP4_IP_REV_MINOR_MASK					(0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT					0
+#define OMAP4_IP_HWINFO_MASK					(0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT			2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK			(0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_SHIFT		31
+#define OMAP4_GPMC_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_GPMC_NWP_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_SHIFT		29
+#define OMAP4_GPMC_NCS3_DUPLICATEWAKEUPEVENT_MASK		(1 << 29)
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_SHIFT		28
+#define OMAP4_GPMC_NCS2_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_SHIFT		27
+#define OMAP4_GPMC_NCS1_DUPLICATEWAKEUPEVENT_MASK		(1 << 27)
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_SHIFT		26
+#define OMAP4_GPMC_NCS0_DUPLICATEWAKEUPEVENT_MASK		(1 << 26)
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_SHIFT		25
+#define OMAP4_GPMC_A25_DUPLICATEWAKEUPEVENT_MASK		(1 << 25)
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_GPMC_A24_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_GPMC_A23_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_GPMC_A22_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_GPMC_A21_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_GPMC_A20_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_GPMC_A19_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_GPMC_A18_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_GPMC_A17_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_SHIFT		16
+#define OMAP4_GPMC_A16_DUPLICATEWAKEUPEVENT_MASK		(1 << 16)
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_GPMC_AD15_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_GPMC_AD14_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_GPMC_AD13_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_GPMC_AD12_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_GPMC_AD11_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_GPMC_AD10_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_GPMC_AD9_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_GPMC_AD8_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_GPMC_AD7_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_GPMC_AD6_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_GPMC_AD5_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_GPMC_AD4_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_SHIFT		3
+#define OMAP4_GPMC_AD3_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_GPMC_AD2_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_GPMC_AD1_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_GPMC_AD0_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_1 */
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_SHIFT		31
+#define OMAP4_CAM_STROBE_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_CAM_SHUTTER_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_SHIFT		29
+#define OMAP4_CSI22_DY1_DUPLICATEWAKEUPEVENT_MASK		(1 << 29)
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_SHIFT		28
+#define OMAP4_CSI22_DX1_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_SHIFT		27
+#define OMAP4_CSI22_DY0_DUPLICATEWAKEUPEVENT_MASK		(1 << 27)
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_SHIFT		26
+#define OMAP4_CSI22_DX0_DUPLICATEWAKEUPEVENT_MASK		(1 << 26)
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_SHIFT		25
+#define OMAP4_CSI21_DY4_DUPLICATEWAKEUPEVENT_MASK		(1 << 25)
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_CSI21_DX4_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_CSI21_DY3_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_CSI21_DX3_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_CSI21_DY2_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_CSI21_DX2_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_CSI21_DY1_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_CSI21_DX1_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_CSI21_DY0_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_SHIFT		16
+#define OMAP4_CSI21_DX0_DUPLICATEWAKEUPEVENT_MASK		(1 << 16)
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_HDMI_DDC_SDA_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_HDMI_DDC_SCL_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_HDMI_CEC_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_HDMI_HPD_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_C2C_DATA15_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_C2C_DATA14_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_C2C_DATA13_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_C2C_DATA12_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_C2C_DATA11_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_GPMC_WAIT1_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_GPMC_WAIT0_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_GPMC_NBE1_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_SHIFT		3
+#define OMAP4_GPMC_NBE0_CLE_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_GPMC_NWE_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_GPMC_NOE_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_GPMC_NADV_ALE_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_2 */
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_SHIFT	31
+#define OMAP4_ABE_MCBSP1_CLKX_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_ABE_MCBSP2_FSX_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_SHIFT		29
+#define OMAP4_ABE_MCBSP2_DX_DUPLICATEWAKEUPEVENT_MASK		(1 << 29)
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_SHIFT		28
+#define OMAP4_ABE_MCBSP2_DR_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_SHIFT	27
+#define OMAP4_ABE_MCBSP2_CLKX_DUPLICATEWAKEUPEVENT_MASK		(1 << 27)
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_SHIFT		26
+#define OMAP4_SDMMC1_DAT7_DUPLICATEWAKEUPEVENT_MASK		(1 << 26)
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_SHIFT		25
+#define OMAP4_SDMMC1_DAT6_DUPLICATEWAKEUPEVENT_MASK		(1 << 25)
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_SDMMC1_DAT5_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_SDMMC1_DAT4_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_SDMMC1_DAT3_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_SDMMC1_DAT2_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_SDMMC1_DAT1_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_SDMMC1_DAT0_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_SDMMC1_CMD_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_SDMMC1_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_SHIFT		16
+#define OMAP4_USBC1_ICUSB_DM_DUPLICATEWAKEUPEVENT_MASK		(1 << 16)
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_USBC1_ICUSB_DP_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT	14
+#define OMAP4_USBB1_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK	(1 << 14)
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT	13
+#define OMAP4_USBB1_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT	12
+#define OMAP4_USBB1_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK	(1 << 12)
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT	11
+#define OMAP4_USBB1_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK	(1 << 11)
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT	10
+#define OMAP4_USBB1_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK	(1 << 10)
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT	9
+#define OMAP4_USBB1_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK	(1 << 9)
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT	8
+#define OMAP4_USBB1_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK	(1 << 8)
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT	7
+#define OMAP4_USBB1_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK	(1 << 7)
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT	6
+#define OMAP4_USBB1_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK	(1 << 6)
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT	5
+#define OMAP4_USBB1_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK	(1 << 5)
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT	4
+#define OMAP4_USBB1_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK	(1 << 4)
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT	3
+#define OMAP4_USBB1_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK	(1 << 3)
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT	2
+#define OMAP4_USBB1_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK	(1 << 2)
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT	1
+#define OMAP4_USBB1_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK	(1 << 1)
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_SHIFT	0
+#define OMAP4_CAM_GLOBALRESET_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_3 */
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_SHIFT		31
+#define OMAP4_MCSPI1_CS3_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_MCSPI1_CS2_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_SHIFT		29
+#define OMAP4_MCSPI1_CS1_DUPLICATEWAKEUPEVENT_MASK		(1 << 29)
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_SHIFT		28
+#define OMAP4_MCSPI1_CS0_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_SHIFT		27
+#define OMAP4_MCSPI1_SIMO_DUPLICATEWAKEUPEVENT_MASK		(1 << 27)
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_SHIFT		26
+#define OMAP4_MCSPI1_SOMI_DUPLICATEWAKEUPEVENT_MASK		(1 << 26)
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_SHIFT		25
+#define OMAP4_MCSPI1_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 25)
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_I2C4_SDA_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_I2C4_SCL_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_I2C3_SDA_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_I2C3_SCL_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_I2C2_SDA_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_I2C2_SCL_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_I2C1_SDA_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_I2C1_SCL_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_SHIFT		16
+#define OMAP4_HDQ_SIO_DUPLICATEWAKEUPEVENT_MASK			(1 << 16)
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_UART2_TX_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_UART2_RX_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_UART2_RTS_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_UART2_CTS_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_ABE_DMIC_DIN3_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_ABE_DMIC_DIN2_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_ABE_DMIC_DIN1_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_ABE_DMIC_CLK1_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_ABE_CLKS_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_ABE_PDM_LB_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_ABE_PDM_FRAME_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_SHIFT	4
+#define OMAP4_ABE_PDM_DL_DATA_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_SHIFT	3
+#define OMAP4_ABE_PDM_UL_DATA_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_ABE_MCBSP1_FSX_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_ABE_MCBSP1_DX_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_ABE_MCBSP1_DR_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_4 */
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_SHIFT		31
+#define OMAP4_UNIPRO_TY0_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_UNIPRO_TX0_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_SHIFT	29
+#define OMAP4_USBB2_HSIC_STROBE_DUPLICATEWAKEUPEVENT_MASK	(1 << 29)
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_SHIFT	28
+#define OMAP4_USBB2_HSIC_DATA_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_SHIFT	27
+#define OMAP4_USBB2_ULPITLL_DAT7_DUPLICATEWAKEUPEVENT_MASK	(1 << 27)
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_SHIFT	26
+#define OMAP4_USBB2_ULPITLL_DAT6_DUPLICATEWAKEUPEVENT_MASK	(1 << 26)
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_SHIFT	25
+#define OMAP4_USBB2_ULPITLL_DAT5_DUPLICATEWAKEUPEVENT_MASK	(1 << 25)
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_SHIFT	24
+#define OMAP4_USBB2_ULPITLL_DAT4_DUPLICATEWAKEUPEVENT_MASK	(1 << 24)
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_SHIFT	23
+#define OMAP4_USBB2_ULPITLL_DAT3_DUPLICATEWAKEUPEVENT_MASK	(1 << 23)
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_SHIFT	22
+#define OMAP4_USBB2_ULPITLL_DAT2_DUPLICATEWAKEUPEVENT_MASK	(1 << 22)
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_SHIFT	21
+#define OMAP4_USBB2_ULPITLL_DAT1_DUPLICATEWAKEUPEVENT_MASK	(1 << 21)
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_SHIFT	20
+#define OMAP4_USBB2_ULPITLL_DAT0_DUPLICATEWAKEUPEVENT_MASK	(1 << 20)
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_SHIFT	19
+#define OMAP4_USBB2_ULPITLL_NXT_DUPLICATEWAKEUPEVENT_MASK	(1 << 19)
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_SHIFT	18
+#define OMAP4_USBB2_ULPITLL_DIR_DUPLICATEWAKEUPEVENT_MASK	(1 << 18)
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_SHIFT	17
+#define OMAP4_USBB2_ULPITLL_STP_DUPLICATEWAKEUPEVENT_MASK	(1 << 17)
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_SHIFT	16
+#define OMAP4_USBB2_ULPITLL_CLK_DUPLICATEWAKEUPEVENT_MASK	(1 << 16)
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_UART4_TX_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_UART4_RX_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_MCSPI4_CS0_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_MCSPI4_SOMI_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_MCSPI4_SIMO_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_MCSPI4_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_SDMMC5_DAT3_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_SDMMC5_DAT2_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_SDMMC5_DAT1_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_SDMMC5_DAT0_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_SDMMC5_CMD_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_SDMMC5_CLK_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_SHIFT		3
+#define OMAP4_UART3_TX_IRTX_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_UART3_RX_IRRX_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_UART3_RTS_SD_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_UART3_CTS_RCTX_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_5 */
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_SHIFT		31
+#define OMAP4_DPM_EMU11_DUPLICATEWAKEUPEVENT_MASK		(1 << 31)
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_SHIFT		30
+#define OMAP4_DPM_EMU10_DUPLICATEWAKEUPEVENT_MASK		(1 << 30)
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_SHIFT		29
+#define OMAP4_DPM_EMU9_DUPLICATEWAKEUPEVENT_MASK		(1 << 29)
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_SHIFT		28
+#define OMAP4_DPM_EMU8_DUPLICATEWAKEUPEVENT_MASK		(1 << 28)
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_SHIFT		27
+#define OMAP4_DPM_EMU7_DUPLICATEWAKEUPEVENT_MASK		(1 << 27)
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_SHIFT		26
+#define OMAP4_DPM_EMU6_DUPLICATEWAKEUPEVENT_MASK		(1 << 26)
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_SHIFT		25
+#define OMAP4_DPM_EMU5_DUPLICATEWAKEUPEVENT_MASK		(1 << 25)
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_DPM_EMU4_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_DPM_EMU3_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_DPM_EMU2_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_DPM_EMU1_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_DPM_EMU0_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_SYS_BOOT5_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_SYS_BOOT4_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_SYS_BOOT3_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_SHIFT		16
+#define OMAP4_SYS_BOOT2_DUPLICATEWAKEUPEVENT_MASK		(1 << 16)
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_SYS_BOOT1_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_SYS_BOOT0_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_SYS_NIRQ2_DUPLICATEWAKEUPEVENT_MASK		(1 << 13)
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_SYS_NIRQ1_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_FREF_CLK2_OUT_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_FREF_CLK1_OUT_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_UNIPRO_RY2_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_UNIPRO_RX2_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_UNIPRO_RY1_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_UNIPRO_RX1_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_UNIPRO_RY0_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_UNIPRO_RX0_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_SHIFT		3
+#define OMAP4_UNIPRO_TY2_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_UNIPRO_TX2_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_UNIPRO_TY1_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_UNIPRO_TX1_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* PADCONF_WAKEUPEVENT_6 */
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_DPM_EMU19_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_SHIFT		6
+#define OMAP4_DPM_EMU18_DUPLICATEWAKEUPEVENT_MASK		(1 << 6)
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_SHIFT		5
+#define OMAP4_DPM_EMU17_DUPLICATEWAKEUPEVENT_MASK		(1 << 5)
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_DPM_EMU16_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_SHIFT		3
+#define OMAP4_DPM_EMU15_DUPLICATEWAKEUPEVENT_MASK		(1 << 3)
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_DPM_EMU14_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_DPM_EMU13_DUPLICATEWAKEUPEVENT_MASK		(1 << 1)
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_SHIFT		0
+#define OMAP4_DPM_EMU12_DUPLICATEWAKEUPEVENT_MASK		(1 << 0)
+
+/* CONTROL_PADCONF_GLOBAL */
+#define OMAP4_FORCE_OFFMODE_EN_SHIFT				31
+#define OMAP4_FORCE_OFFMODE_EN_MASK				(1 << 31)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_BANK0_SHIFT				31
+#define OMAP4_VDDS_DV_BANK0_MASK				(1 << 31)
+#define OMAP4_VDDS_DV_BANK1_SHIFT				30
+#define OMAP4_VDDS_DV_BANK1_MASK				(1 << 30)
+#define OMAP4_VDDS_DV_BANK3_SHIFT				29
+#define OMAP4_VDDS_DV_BANK3_MASK				(1 << 29)
+#define OMAP4_VDDS_DV_BANK4_SHIFT				28
+#define OMAP4_VDDS_DV_BANK4_MASK				(1 << 28)
+#define OMAP4_VDDS_DV_BANK5_SHIFT				27
+#define OMAP4_VDDS_DV_BANK5_MASK				(1 << 27)
+#define OMAP4_VDDS_DV_BANK6_SHIFT				26
+#define OMAP4_VDDS_DV_BANK6_MASK				(1 << 26)
+#define OMAP4_VDDS_DV_C2C_SHIFT					25
+#define OMAP4_VDDS_DV_C2C_MASK					(1 << 25)
+#define OMAP4_VDDS_DV_CAM_SHIFT					24
+#define OMAP4_VDDS_DV_CAM_MASK					(1 << 24)
+#define OMAP4_VDDS_DV_GPMC_SHIFT				23
+#define OMAP4_VDDS_DV_GPMC_MASK					(1 << 23)
+#define OMAP4_VDDS_DV_SDMMC2_SHIFT				22
+#define OMAP4_VDDS_DV_SDMMC2_MASK				(1 << 22)
+
+/* CONTROL_SMART1IO_PADCONF_0 */
+#define OMAP4_ABE_DR0_SC_SHIFT					30
+#define OMAP4_ABE_DR0_SC_MASK					(0x3 << 30)
+#define OMAP4_CAM_DR0_SC_SHIFT					28
+#define OMAP4_CAM_DR0_SC_MASK					(0x3 << 28)
+#define OMAP4_FREF_DR2_SC_SHIFT					26
+#define OMAP4_FREF_DR2_SC_MASK					(0x3 << 26)
+#define OMAP4_FREF_DR3_SC_SHIFT					24
+#define OMAP4_FREF_DR3_SC_MASK					(0x3 << 24)
+#define OMAP4_GPIO_DR8_SC_SHIFT					22
+#define OMAP4_GPIO_DR8_SC_MASK					(0x3 << 22)
+#define OMAP4_GPIO_DR9_SC_SHIFT					20
+#define OMAP4_GPIO_DR9_SC_MASK					(0x3 << 20)
+#define OMAP4_GPMC_DR2_SC_SHIFT					18
+#define OMAP4_GPMC_DR2_SC_MASK					(0x3 << 18)
+#define OMAP4_GPMC_DR3_SC_SHIFT					16
+#define OMAP4_GPMC_DR3_SC_MASK					(0x3 << 16)
+#define OMAP4_GPMC_DR6_SC_SHIFT					14
+#define OMAP4_GPMC_DR6_SC_MASK					(0x3 << 14)
+#define OMAP4_HDMI_DR0_SC_SHIFT					12
+#define OMAP4_HDMI_DR0_SC_MASK					(0x3 << 12)
+#define OMAP4_MCSPI1_DR0_SC_SHIFT				10
+#define OMAP4_MCSPI1_DR0_SC_MASK				(0x3 << 10)
+#define OMAP4_UART1_DR0_SC_SHIFT				8
+#define OMAP4_UART1_DR0_SC_MASK					(0x3 << 8)
+#define OMAP4_UART3_DR0_SC_SHIFT				6
+#define OMAP4_UART3_DR0_SC_MASK					(0x3 << 6)
+#define OMAP4_UART3_DR1_SC_SHIFT				4
+#define OMAP4_UART3_DR1_SC_MASK					(0x3 << 4)
+#define OMAP4_UNIPRO_DR0_SC_SHIFT				2
+#define OMAP4_UNIPRO_DR0_SC_MASK				(0x3 << 2)
+#define OMAP4_UNIPRO_DR1_SC_SHIFT				0
+#define OMAP4_UNIPRO_DR1_SC_MASK				(0x3 << 0)
+
+/* CONTROL_SMART1IO_PADCONF_1 */
+#define OMAP4_ABE_DR0_LB_SHIFT					30
+#define OMAP4_ABE_DR0_LB_MASK					(0x3 << 30)
+#define OMAP4_CAM_DR0_LB_SHIFT					28
+#define OMAP4_CAM_DR0_LB_MASK					(0x3 << 28)
+#define OMAP4_FREF_DR2_LB_SHIFT					26
+#define OMAP4_FREF_DR2_LB_MASK					(0x3 << 26)
+#define OMAP4_FREF_DR3_LB_SHIFT					24
+#define OMAP4_FREF_DR3_LB_MASK					(0x3 << 24)
+#define OMAP4_GPIO_DR8_LB_SHIFT					22
+#define OMAP4_GPIO_DR8_LB_MASK					(0x3 << 22)
+#define OMAP4_GPIO_DR9_LB_SHIFT					20
+#define OMAP4_GPIO_DR9_LB_MASK					(0x3 << 20)
+#define OMAP4_GPMC_DR2_LB_SHIFT					18
+#define OMAP4_GPMC_DR2_LB_MASK					(0x3 << 18)
+#define OMAP4_GPMC_DR3_LB_SHIFT					16
+#define OMAP4_GPMC_DR3_LB_MASK					(0x3 << 16)
+#define OMAP4_GPMC_DR6_LB_SHIFT					14
+#define OMAP4_GPMC_DR6_LB_MASK					(0x3 << 14)
+#define OMAP4_HDMI_DR0_LB_SHIFT					12
+#define OMAP4_HDMI_DR0_LB_MASK					(0x3 << 12)
+#define OMAP4_MCSPI1_DR0_LB_SHIFT				10
+#define OMAP4_MCSPI1_DR0_LB_MASK				(0x3 << 10)
+#define OMAP4_UART1_DR0_LB_SHIFT				8
+#define OMAP4_UART1_DR0_LB_MASK					(0x3 << 8)
+#define OMAP4_UART3_DR0_LB_SHIFT				6
+#define OMAP4_UART3_DR0_LB_MASK					(0x3 << 6)
+#define OMAP4_UART3_DR1_LB_SHIFT				4
+#define OMAP4_UART3_DR1_LB_MASK					(0x3 << 4)
+#define OMAP4_UNIPRO_DR0_LB_SHIFT				2
+#define OMAP4_UNIPRO_DR0_LB_MASK				(0x3 << 2)
+#define OMAP4_UNIPRO_DR1_LB_SHIFT				0
+#define OMAP4_UNIPRO_DR1_LB_MASK				(0x3 << 0)
+
+/* CONTROL_SMART2IO_PADCONF_0 */
+#define OMAP4_C2C_DR0_LB_SHIFT					31
+#define OMAP4_C2C_DR0_LB_MASK					(1 << 31)
+#define OMAP4_DPM_DR1_LB_SHIFT					30
+#define OMAP4_DPM_DR1_LB_MASK					(1 << 30)
+#define OMAP4_DPM_DR2_LB_SHIFT					29
+#define OMAP4_DPM_DR2_LB_MASK					(1 << 29)
+#define OMAP4_DPM_DR3_LB_SHIFT					28
+#define OMAP4_DPM_DR3_LB_MASK					(1 << 28)
+#define OMAP4_GPIO_DR0_LB_SHIFT					27
+#define OMAP4_GPIO_DR0_LB_MASK					(1 << 27)
+#define OMAP4_GPIO_DR1_LB_SHIFT					26
+#define OMAP4_GPIO_DR1_LB_MASK					(1 << 26)
+#define OMAP4_GPIO_DR10_LB_SHIFT				25
+#define OMAP4_GPIO_DR10_LB_MASK					(1 << 25)
+#define OMAP4_GPIO_DR2_LB_SHIFT					24
+#define OMAP4_GPIO_DR2_LB_MASK					(1 << 24)
+#define OMAP4_GPMC_DR0_LB_SHIFT					23
+#define OMAP4_GPMC_DR0_LB_MASK					(1 << 23)
+#define OMAP4_GPMC_DR1_LB_SHIFT					22
+#define OMAP4_GPMC_DR1_LB_MASK					(1 << 22)
+#define OMAP4_GPMC_DR4_LB_SHIFT					21
+#define OMAP4_GPMC_DR4_LB_MASK					(1 << 21)
+#define OMAP4_GPMC_DR5_LB_SHIFT					20
+#define OMAP4_GPMC_DR5_LB_MASK					(1 << 20)
+#define OMAP4_GPMC_DR7_LB_SHIFT					19
+#define OMAP4_GPMC_DR7_LB_MASK					(1 << 19)
+#define OMAP4_HSI2_DR0_LB_SHIFT					18
+#define OMAP4_HSI2_DR0_LB_MASK					(1 << 18)
+#define OMAP4_HSI2_DR1_LB_SHIFT					17
+#define OMAP4_HSI2_DR1_LB_MASK					(1 << 17)
+#define OMAP4_HSI2_DR2_LB_SHIFT					16
+#define OMAP4_HSI2_DR2_LB_MASK					(1 << 16)
+#define OMAP4_KPD_DR0_LB_SHIFT					15
+#define OMAP4_KPD_DR0_LB_MASK					(1 << 15)
+#define OMAP4_KPD_DR1_LB_SHIFT					14
+#define OMAP4_KPD_DR1_LB_MASK					(1 << 14)
+#define OMAP4_PDM_DR0_LB_SHIFT					13
+#define OMAP4_PDM_DR0_LB_MASK					(1 << 13)
+#define OMAP4_SDMMC2_DR0_LB_SHIFT				12
+#define OMAP4_SDMMC2_DR0_LB_MASK				(1 << 12)
+#define OMAP4_SDMMC3_DR0_LB_SHIFT				11
+#define OMAP4_SDMMC3_DR0_LB_MASK				(1 << 11)
+#define OMAP4_SDMMC4_DR0_LB_SHIFT				10
+#define OMAP4_SDMMC4_DR0_LB_MASK				(1 << 10)
+#define OMAP4_SDMMC4_DR1_LB_SHIFT				9
+#define OMAP4_SDMMC4_DR1_LB_MASK				(1 << 9)
+#define OMAP4_SPI3_DR0_LB_SHIFT					8
+#define OMAP4_SPI3_DR0_LB_MASK					(1 << 8)
+#define OMAP4_SPI3_DR1_LB_SHIFT					7
+#define OMAP4_SPI3_DR1_LB_MASK					(1 << 7)
+#define OMAP4_UART3_DR2_LB_SHIFT				6
+#define OMAP4_UART3_DR2_LB_MASK					(1 << 6)
+#define OMAP4_UART3_DR3_LB_SHIFT				5
+#define OMAP4_UART3_DR3_LB_MASK					(1 << 5)
+#define OMAP4_UART3_DR4_LB_SHIFT				4
+#define OMAP4_UART3_DR4_LB_MASK					(1 << 4)
+#define OMAP4_UART3_DR5_LB_SHIFT				3
+#define OMAP4_UART3_DR5_LB_MASK					(1 << 3)
+#define OMAP4_USBA0_DR1_LB_SHIFT				2
+#define OMAP4_USBA0_DR1_LB_MASK					(1 << 2)
+#define OMAP4_USBA_DR2_LB_SHIFT					1
+#define OMAP4_USBA_DR2_LB_MASK					(1 << 1)
+
+/* CONTROL_SMART2IO_PADCONF_1 */
+#define OMAP4_USBB1_DR0_LB_SHIFT				31
+#define OMAP4_USBB1_DR0_LB_MASK					(1 << 31)
+#define OMAP4_USBB2_DR0_LB_SHIFT				30
+#define OMAP4_USBB2_DR0_LB_MASK					(1 << 30)
+#define OMAP4_USBA0_DR0_LB_SHIFT				29
+#define OMAP4_USBA0_DR0_LB_MASK					(1 << 29)
+
+/* CONTROL_SMART3IO_PADCONF_0 */
+#define OMAP4_DMIC_DR0_MB_SHIFT					30
+#define OMAP4_DMIC_DR0_MB_MASK					(0x3 << 30)
+#define OMAP4_GPIO_DR3_MB_SHIFT					28
+#define OMAP4_GPIO_DR3_MB_MASK					(0x3 << 28)
+#define OMAP4_GPIO_DR4_MB_SHIFT					26
+#define OMAP4_GPIO_DR4_MB_MASK					(0x3 << 26)
+#define OMAP4_GPIO_DR5_MB_SHIFT					24
+#define OMAP4_GPIO_DR5_MB_MASK					(0x3 << 24)
+#define OMAP4_GPIO_DR6_MB_SHIFT					22
+#define OMAP4_GPIO_DR6_MB_MASK					(0x3 << 22)
+#define OMAP4_HSI_DR1_MB_SHIFT					20
+#define OMAP4_HSI_DR1_MB_MASK					(0x3 << 20)
+#define OMAP4_HSI_DR2_MB_SHIFT					18
+#define OMAP4_HSI_DR2_MB_MASK					(0x3 << 18)
+#define OMAP4_HSI_DR3_MB_SHIFT					16
+#define OMAP4_HSI_DR3_MB_MASK					(0x3 << 16)
+#define OMAP4_MCBSP2_DR0_MB_SHIFT				14
+#define OMAP4_MCBSP2_DR0_MB_MASK				(0x3 << 14)
+#define OMAP4_MCSPI4_DR0_MB_SHIFT				12
+#define OMAP4_MCSPI4_DR0_MB_MASK				(0x3 << 12)
+#define OMAP4_MCSPI4_DR1_MB_SHIFT				10
+#define OMAP4_MCSPI4_DR1_MB_MASK				(0x3 << 10)
+#define OMAP4_SDMMC3_DR0_MB_SHIFT				8
+#define OMAP4_SDMMC3_DR0_MB_MASK				(0x3 << 8)
+#define OMAP4_SPI2_DR0_MB_SHIFT					0
+#define OMAP4_SPI2_DR0_MB_MASK					(0x3 << 0)
+
+/* CONTROL_SMART3IO_PADCONF_1 */
+#define OMAP4_SPI2_DR1_MB_SHIFT					30
+#define OMAP4_SPI2_DR1_MB_MASK					(0x3 << 30)
+#define OMAP4_SPI2_DR2_MB_SHIFT					28
+#define OMAP4_SPI2_DR2_MB_MASK					(0x3 << 28)
+#define OMAP4_UART2_DR0_MB_SHIFT				26
+#define OMAP4_UART2_DR0_MB_MASK					(0x3 << 26)
+#define OMAP4_UART2_DR1_MB_SHIFT				24
+#define OMAP4_UART2_DR1_MB_MASK					(0x3 << 24)
+#define OMAP4_UART4_DR0_MB_SHIFT				22
+#define OMAP4_UART4_DR0_MB_MASK					(0x3 << 22)
+#define OMAP4_HSI_DR0_MB_SHIFT					20
+#define OMAP4_HSI_DR0_MB_MASK					(0x3 << 20)
+
+/* CONTROL_SMART3IO_PADCONF_2 */
+#define OMAP4_DMIC_DR0_LB_SHIFT					31
+#define OMAP4_DMIC_DR0_LB_MASK					(1 << 31)
+#define OMAP4_GPIO_DR3_LB_SHIFT					30
+#define OMAP4_GPIO_DR3_LB_MASK					(1 << 30)
+#define OMAP4_GPIO_DR4_LB_SHIFT					29
+#define OMAP4_GPIO_DR4_LB_MASK					(1 << 29)
+#define OMAP4_GPIO_DR5_LB_SHIFT					28
+#define OMAP4_GPIO_DR5_LB_MASK					(1 << 28)
+#define OMAP4_GPIO_DR6_LB_SHIFT					27
+#define OMAP4_GPIO_DR6_LB_MASK					(1 << 27)
+#define OMAP4_HSI_DR1_LB_SHIFT					26
+#define OMAP4_HSI_DR1_LB_MASK					(1 << 26)
+#define OMAP4_HSI_DR2_LB_SHIFT					25
+#define OMAP4_HSI_DR2_LB_MASK					(1 << 25)
+#define OMAP4_HSI_DR3_LB_SHIFT					24
+#define OMAP4_HSI_DR3_LB_MASK					(1 << 24)
+#define OMAP4_MCBSP2_DR0_LB_SHIFT				23
+#define OMAP4_MCBSP2_DR0_LB_MASK				(1 << 23)
+#define OMAP4_MCSPI4_DR0_LB_SHIFT				22
+#define OMAP4_MCSPI4_DR0_LB_MASK				(1 << 22)
+#define OMAP4_MCSPI4_DR1_LB_SHIFT				21
+#define OMAP4_MCSPI4_DR1_LB_MASK				(1 << 21)
+#define OMAP4_SLIMBUS2_DR0_LB_SHIFT				18
+#define OMAP4_SLIMBUS2_DR0_LB_MASK				(1 << 18)
+#define OMAP4_SPI2_DR0_LB_SHIFT					16
+#define OMAP4_SPI2_DR0_LB_MASK					(1 << 16)
+#define OMAP4_SPI2_DR1_LB_SHIFT					15
+#define OMAP4_SPI2_DR1_LB_MASK					(1 << 15)
+#define OMAP4_SPI2_DR2_LB_SHIFT					14
+#define OMAP4_SPI2_DR2_LB_MASK					(1 << 14)
+#define OMAP4_UART2_DR0_LB_SHIFT				13
+#define OMAP4_UART2_DR0_LB_MASK					(1 << 13)
+#define OMAP4_UART2_DR1_LB_SHIFT				12
+#define OMAP4_UART2_DR1_LB_MASK					(1 << 12)
+#define OMAP4_UART4_DR0_LB_SHIFT				11
+#define OMAP4_UART4_DR0_LB_MASK					(1 << 11)
+#define OMAP4_HSI_DR0_LB_SHIFT					10
+#define OMAP4_HSI_DR0_LB_MASK					(1 << 10)
+
+/* CONTROL_USBB_HSIC */
+#define OMAP4_USBB2_DR1_SR_SHIFT				30
+#define OMAP4_USBB2_DR1_SR_MASK					(0x3 << 30)
+#define OMAP4_USBB2_DR1_I_SHIFT					27
+#define OMAP4_USBB2_DR1_I_MASK					(0x7 << 27)
+#define OMAP4_USBB1_DR1_SR_SHIFT				25
+#define OMAP4_USBB1_DR1_SR_MASK					(0x3 << 25)
+#define OMAP4_USBB1_DR1_I_SHIFT					22
+#define OMAP4_USBB1_DR1_I_MASK					(0x7 << 22)
+#define OMAP4_USBB1_HSIC_DATA_WD_SHIFT				20
+#define OMAP4_USBB1_HSIC_DATA_WD_MASK				(0x3 << 20)
+#define OMAP4_USBB1_HSIC_STROBE_WD_SHIFT			18
+#define OMAP4_USBB1_HSIC_STROBE_WD_MASK				(0x3 << 18)
+#define OMAP4_USBB2_HSIC_DATA_WD_SHIFT				16
+#define OMAP4_USBB2_HSIC_DATA_WD_MASK				(0x3 << 16)
+#define OMAP4_USBB2_HSIC_STROBE_WD_SHIFT			14
+#define OMAP4_USBB2_HSIC_STROBE_WD_MASK				(0x3 << 14)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT		13
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_ENABLE_MASK		(1 << 13)
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_SHIFT			11
+#define OMAP4_USBB1_HSIC_DATA_OFFMODE_WD_MASK			(0x3 << 11)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT		10
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK		(1 << 10)
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_SHIFT		8
+#define OMAP4_USBB1_HSIC_STROBE_OFFMODE_WD_MASK			(0x3 << 8)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_SHIFT		7
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_ENABLE_MASK		(1 << 7)
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_SHIFT			5
+#define OMAP4_USBB2_HSIC_DATA_OFFMODE_WD_MASK			(0x3 << 5)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_SHIFT		4
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_ENABLE_MASK		(1 << 4)
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_SHIFT		2
+#define OMAP4_USBB2_HSIC_STROBE_OFFMODE_WD_MASK			(0x3 << 2)
+
+/* CONTROL_SLIMBUS */
+#define OMAP4_SLIMBUS1_DR0_MB_SHIFT				30
+#define OMAP4_SLIMBUS1_DR0_MB_MASK				(0x3 << 30)
+#define OMAP4_SLIMBUS1_DR1_MB_SHIFT				28
+#define OMAP4_SLIMBUS1_DR1_MB_MASK				(0x3 << 28)
+#define OMAP4_SLIMBUS2_DR0_MB_SHIFT				26
+#define OMAP4_SLIMBUS2_DR0_MB_MASK				(0x3 << 26)
+#define OMAP4_SLIMBUS2_DR1_MB_SHIFT				24
+#define OMAP4_SLIMBUS2_DR1_MB_MASK				(0x3 << 24)
+#define OMAP4_SLIMBUS2_DR2_MB_SHIFT				22
+#define OMAP4_SLIMBUS2_DR2_MB_MASK				(0x3 << 22)
+#define OMAP4_SLIMBUS2_DR3_MB_SHIFT				20
+#define OMAP4_SLIMBUS2_DR3_MB_MASK				(0x3 << 20)
+#define OMAP4_SLIMBUS1_DR0_LB_SHIFT				19
+#define OMAP4_SLIMBUS1_DR0_LB_MASK				(1 << 19)
+#define OMAP4_SLIMBUS2_DR1_LB_SHIFT				18
+#define OMAP4_SLIMBUS2_DR1_LB_MASK				(1 << 18)
+
+/* CONTROL_PBIASLITE */
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_SHIFT			31
+#define OMAP4_USIM_PBIASLITE_HIZ_MODE_MASK			(1 << 31)
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_SHIFT		30
+#define OMAP4_USIM_PBIASLITE_SUPPLY_HI_OUT_MASK			(1 << 30)
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_SHIFT			29
+#define OMAP4_USIM_PBIASLITE_VMODE_ERROR_MASK			(1 << 29)
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_SHIFT			28
+#define OMAP4_USIM_PBIASLITE_PWRDNZ_MASK			(1 << 28)
+#define OMAP4_USIM_PBIASLITE_VMODE_SHIFT			27
+#define OMAP4_USIM_PBIASLITE_VMODE_MASK				(1 << 27)
+#define OMAP4_MMC1_PWRDNZ_SHIFT					26
+#define OMAP4_MMC1_PWRDNZ_MASK					(1 << 26)
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_SHIFT			25
+#define OMAP4_MMC1_PBIASLITE_HIZ_MODE_MASK			(1 << 25)
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_SHIFT		24
+#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT_MASK			(1 << 24)
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_SHIFT			23
+#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR_MASK			(1 << 23)
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_SHIFT			22
+#define OMAP4_MMC1_PBIASLITE_PWRDNZ_MASK			(1 << 22)
+#define OMAP4_MMC1_PBIASLITE_VMODE_SHIFT			21
+#define OMAP4_MMC1_PBIASLITE_VMODE_MASK				(1 << 21)
+#define OMAP4_USBC1_ICUSB_PWRDNZ_SHIFT				20
+#define OMAP4_USBC1_ICUSB_PWRDNZ_MASK				(1 << 20)
+
+/* CONTROL_I2C_0 */
+#define OMAP4_I2C4_SDA_GLFENB_SHIFT				31
+#define OMAP4_I2C4_SDA_GLFENB_MASK				(1 << 31)
+#define OMAP4_I2C4_SDA_LOAD_BITS_SHIFT				29
+#define OMAP4_I2C4_SDA_LOAD_BITS_MASK				(0x3 << 29)
+#define OMAP4_I2C4_SDA_PULLUPRESX_SHIFT				28
+#define OMAP4_I2C4_SDA_PULLUPRESX_MASK				(1 << 28)
+#define OMAP4_I2C3_SDA_GLFENB_SHIFT				27
+#define OMAP4_I2C3_SDA_GLFENB_MASK				(1 << 27)
+#define OMAP4_I2C3_SDA_LOAD_BITS_SHIFT				25
+#define OMAP4_I2C3_SDA_LOAD_BITS_MASK				(0x3 << 25)
+#define OMAP4_I2C3_SDA_PULLUPRESX_SHIFT				24
+#define OMAP4_I2C3_SDA_PULLUPRESX_MASK				(1 << 24)
+#define OMAP4_I2C2_SDA_GLFENB_SHIFT				23
+#define OMAP4_I2C2_SDA_GLFENB_MASK				(1 << 23)
+#define OMAP4_I2C2_SDA_LOAD_BITS_SHIFT				21
+#define OMAP4_I2C2_SDA_LOAD_BITS_MASK				(0x3 << 21)
+#define OMAP4_I2C2_SDA_PULLUPRESX_SHIFT				20
+#define OMAP4_I2C2_SDA_PULLUPRESX_MASK				(1 << 20)
+#define OMAP4_I2C1_SDA_GLFENB_SHIFT				19
+#define OMAP4_I2C1_SDA_GLFENB_MASK				(1 << 19)
+#define OMAP4_I2C1_SDA_LOAD_BITS_SHIFT				17
+#define OMAP4_I2C1_SDA_LOAD_BITS_MASK				(0x3 << 17)
+#define OMAP4_I2C1_SDA_PULLUPRESX_SHIFT				16
+#define OMAP4_I2C1_SDA_PULLUPRESX_MASK				(1 << 16)
+#define OMAP4_I2C4_SCL_GLFENB_SHIFT				15
+#define OMAP4_I2C4_SCL_GLFENB_MASK				(1 << 15)
+#define OMAP4_I2C4_SCL_LOAD_BITS_SHIFT				13
+#define OMAP4_I2C4_SCL_LOAD_BITS_MASK				(0x3 << 13)
+#define OMAP4_I2C4_SCL_PULLUPRESX_SHIFT				12
+#define OMAP4_I2C4_SCL_PULLUPRESX_MASK				(1 << 12)
+#define OMAP4_I2C3_SCL_GLFENB_SHIFT				11
+#define OMAP4_I2C3_SCL_GLFENB_MASK				(1 << 11)
+#define OMAP4_I2C3_SCL_LOAD_BITS_SHIFT				9
+#define OMAP4_I2C3_SCL_LOAD_BITS_MASK				(0x3 << 9)
+#define OMAP4_I2C3_SCL_PULLUPRESX_SHIFT				8
+#define OMAP4_I2C3_SCL_PULLUPRESX_MASK				(1 << 8)
+#define OMAP4_I2C2_SCL_GLFENB_SHIFT				7
+#define OMAP4_I2C2_SCL_GLFENB_MASK				(1 << 7)
+#define OMAP4_I2C2_SCL_LOAD_BITS_SHIFT				5
+#define OMAP4_I2C2_SCL_LOAD_BITS_MASK				(0x3 << 5)
+#define OMAP4_I2C2_SCL_PULLUPRESX_SHIFT				4
+#define OMAP4_I2C2_SCL_PULLUPRESX_MASK				(1 << 4)
+#define OMAP4_I2C1_SCL_GLFENB_SHIFT				3
+#define OMAP4_I2C1_SCL_GLFENB_MASK				(1 << 3)
+#define OMAP4_I2C1_SCL_LOAD_BITS_SHIFT				1
+#define OMAP4_I2C1_SCL_LOAD_BITS_MASK				(0x3 << 1)
+#define OMAP4_I2C1_SCL_PULLUPRESX_SHIFT				0
+#define OMAP4_I2C1_SCL_PULLUPRESX_MASK				(1 << 0)
+
+/* CONTROL_CAMERA_RX */
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_SHIFT			31
+#define OMAP4_CAMERARX_UNIPRO_CTRLCLKEN_MASK			(1 << 31)
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT			29
+#define OMAP4_CAMERARX_CSI22_LANEENABLE_MASK			(0x3 << 29)
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT			24
+#define OMAP4_CAMERARX_CSI21_LANEENABLE_MASK			(0x1f << 24)
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_SHIFT			22
+#define OMAP4_CAMERARX_UNIPRO_CAMMODE_MASK			(0x3 << 22)
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_SHIFT			21
+#define OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK			(1 << 21)
+#define OMAP4_CAMERARX_CSI22_CAMMODE_SHIFT			19
+#define OMAP4_CAMERARX_CSI22_CAMMODE_MASK			(0x3 << 19)
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_SHIFT			18
+#define OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK			(1 << 18)
+#define OMAP4_CAMERARX_CSI21_CAMMODE_SHIFT			16
+#define OMAP4_CAMERARX_CSI21_CAMMODE_MASK			(0x3 << 16)
+
+/* CONTROL_AVDAC */
+#define OMAP4_AVDAC_ACEN_SHIFT					31
+#define OMAP4_AVDAC_ACEN_MASK					(1 << 31)
+#define OMAP4_AVDAC_TVOUTBYPASS_SHIFT				30
+#define OMAP4_AVDAC_TVOUTBYPASS_MASK				(1 << 30)
+#define OMAP4_AVDAC_INPUTINV_SHIFT				29
+#define OMAP4_AVDAC_INPUTINV_MASK				(1 << 29)
+#define OMAP4_AVDAC_CTL_SHIFT					13
+#define OMAP4_AVDAC_CTL_MASK					(0xffff << 13)
+#define OMAP4_AVDAC_CTL_WR_ACK_SHIFT				12
+#define OMAP4_AVDAC_CTL_WR_ACK_MASK				(1 << 12)
+
+/* CONTROL_HDMI_TX_PHY */
+#define OMAP4_HDMITXPHY_PADORDER_SHIFT				31
+#define OMAP4_HDMITXPHY_PADORDER_MASK				(1 << 31)
+#define OMAP4_HDMITXPHY_TXVALID_SHIFT				30
+#define OMAP4_HDMITXPHY_TXVALID_MASK				(1 << 30)
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_SHIFT			29
+#define OMAP4_HDMITXPHY_ENBYPASSCLK_MASK			(1 << 29)
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_SHIFT			28
+#define OMAP4_HDMITXPHY_PD_PULLUPDET_MASK			(1 << 28)
+
+/* CONTROL_MMC2 */
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_SHIFT			31
+#define OMAP4_MMC2_FEEDBACK_CLK_SEL_MASK			(1 << 31)
+
+/* CONTROL_DSIPHY */
+#define OMAP4_DSI2_LANEENABLE_SHIFT				29
+#define OMAP4_DSI2_LANEENABLE_MASK				(0x7 << 29)
+#define OMAP4_DSI1_LANEENABLE_SHIFT				24
+#define OMAP4_DSI1_LANEENABLE_MASK				(0x1f << 24)
+#define OMAP4_DSI1_PIPD_SHIFT					19
+#define OMAP4_DSI1_PIPD_MASK					(0x1f << 19)
+#define OMAP4_DSI2_PIPD_SHIFT					14
+#define OMAP4_DSI2_PIPD_MASK					(0x1f << 14)
+
+/* CONTROL_MCBSPLP */
+#define OMAP4_ALBCTRLRX_FSX_SHIFT				31
+#define OMAP4_ALBCTRLRX_FSX_MASK				(1 << 31)
+#define OMAP4_ALBCTRLRX_CLKX_SHIFT				30
+#define OMAP4_ALBCTRLRX_CLKX_MASK				(1 << 30)
+#define OMAP4_ABE_MCBSP1_DR_EN_SHIFT				29
+#define OMAP4_ABE_MCBSP1_DR_EN_MASK				(1 << 29)
+
+/* CONTROL_USB2PHYCORE */
+#define OMAP4_USB2PHY_AUTORESUME_EN_SHIFT			31
+#define OMAP4_USB2PHY_AUTORESUME_EN_MASK			(1 << 31)
+#define OMAP4_USB2PHY_DISCHGDET_SHIFT				30
+#define OMAP4_USB2PHY_DISCHGDET_MASK				(1 << 30)
+#define OMAP4_USB2PHY_GPIOMODE_SHIFT				29
+#define OMAP4_USB2PHY_GPIOMODE_MASK				(1 << 29)
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_SHIFT			28
+#define OMAP4_USB2PHY_CHG_DET_EXT_CTL_MASK			(1 << 28)
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_SHIFT			27
+#define OMAP4_USB2PHY_RDM_PD_CHGDET_EN_MASK			(1 << 27)
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_SHIFT			26
+#define OMAP4_USB2PHY_RDP_PU_CHGDET_EN_MASK			(1 << 26)
+#define OMAP4_USB2PHY_CHG_VSRC_EN_SHIFT				25
+#define OMAP4_USB2PHY_CHG_VSRC_EN_MASK				(1 << 25)
+#define OMAP4_USB2PHY_CHG_ISINK_EN_SHIFT			24
+#define OMAP4_USB2PHY_CHG_ISINK_EN_MASK				(1 << 24)
+#define OMAP4_USB2PHY_CHG_DET_STATUS_SHIFT			21
+#define OMAP4_USB2PHY_CHG_DET_STATUS_MASK			(0x7 << 21)
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_SHIFT			20
+#define OMAP4_USB2PHY_CHG_DET_DM_COMP_MASK			(1 << 20)
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_SHIFT			19
+#define OMAP4_USB2PHY_CHG_DET_DP_COMP_MASK			(1 << 19)
+#define OMAP4_USB2PHY_DATADET_SHIFT				18
+#define OMAP4_USB2PHY_DATADET_MASK				(1 << 18)
+#define OMAP4_USB2PHY_SINKONDP_SHIFT				17
+#define OMAP4_USB2PHY_SINKONDP_MASK				(1 << 17)
+#define OMAP4_USB2PHY_SRCONDM_SHIFT				16
+#define OMAP4_USB2PHY_SRCONDM_MASK				(1 << 16)
+#define OMAP4_USB2PHY_RESTARTCHGDET_SHIFT			15
+#define OMAP4_USB2PHY_RESTARTCHGDET_MASK			(1 << 15)
+#define OMAP4_USB2PHY_CHGDETDONE_SHIFT				14
+#define OMAP4_USB2PHY_CHGDETDONE_MASK				(1 << 14)
+#define OMAP4_USB2PHY_CHGDETECTED_SHIFT				13
+#define OMAP4_USB2PHY_CHGDETECTED_MASK				(1 << 13)
+#define OMAP4_USB2PHY_MCPCPUEN_SHIFT				12
+#define OMAP4_USB2PHY_MCPCPUEN_MASK				(1 << 12)
+#define OMAP4_USB2PHY_MCPCMODEEN_SHIFT				11
+#define OMAP4_USB2PHY_MCPCMODEEN_MASK				(1 << 11)
+#define OMAP4_USB2PHY_RESETDONEMCLK_SHIFT			10
+#define OMAP4_USB2PHY_RESETDONEMCLK_MASK			(1 << 10)
+#define OMAP4_USB2PHY_UTMIRESETDONE_SHIFT			9
+#define OMAP4_USB2PHY_UTMIRESETDONE_MASK			(1 << 9)
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_SHIFT			8
+#define OMAP4_USB2PHY_TXBITSTUFFENABLE_MASK			(1 << 8)
+#define OMAP4_USB2PHY_DATAPOLARITYN_SHIFT			7
+#define OMAP4_USB2PHY_DATAPOLARITYN_MASK			(1 << 7)
+#define OMAP4_USBDPLL_FREQLOCK_SHIFT				6
+#define OMAP4_USBDPLL_FREQLOCK_MASK				(1 << 6)
+#define OMAP4_USB2PHY_RESETDONETCLK_SHIFT			5
+#define OMAP4_USB2PHY_RESETDONETCLK_MASK			(1 << 5)
+
+/* CONTROL_I2C_1 */
+#define OMAP4_HDMI_DDC_SDA_GLFENB_SHIFT				31
+#define OMAP4_HDMI_DDC_SDA_GLFENB_MASK				(1 << 31)
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_SHIFT			29
+#define OMAP4_HDMI_DDC_SDA_LOAD_BITS_MASK			(0x3 << 29)
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_SHIFT			28
+#define OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK			(1 << 28)
+#define OMAP4_HDMI_DDC_SCL_GLFENB_SHIFT				27
+#define OMAP4_HDMI_DDC_SCL_GLFENB_MASK				(1 << 27)
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_SHIFT			25
+#define OMAP4_HDMI_DDC_SCL_LOAD_BITS_MASK			(0x3 << 25)
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_SHIFT			24
+#define OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK			(1 << 24)
+#define OMAP4_HDMI_DDC_SDA_HSMODE_SHIFT				23
+#define OMAP4_HDMI_DDC_SDA_HSMODE_MASK				(1 << 23)
+#define OMAP4_HDMI_DDC_SDA_NMODE_SHIFT				22
+#define OMAP4_HDMI_DDC_SDA_NMODE_MASK				(1 << 22)
+#define OMAP4_HDMI_DDC_SCL_HSMODE_SHIFT				21
+#define OMAP4_HDMI_DDC_SCL_HSMODE_MASK				(1 << 21)
+#define OMAP4_HDMI_DDC_SCL_NMODE_SHIFT				20
+#define OMAP4_HDMI_DDC_SCL_NMODE_MASK				(1 << 20)
+
+/* CONTROL_MMC1 */
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_SHIFT			31
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP0_MASK			(1 << 31)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_SHIFT			30
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP1_MASK			(1 << 30)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_SHIFT			29
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP2_MASK			(1 << 29)
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_SHIFT			28
+#define OMAP4_SDMMC1_PUSTRENGTH_GRP3_MASK			(1 << 28)
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_SHIFT			27
+#define OMAP4_SDMMC1_DR0_SPEEDCTRL_MASK				(1 << 27)
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_SHIFT			26
+#define OMAP4_SDMMC1_DR1_SPEEDCTRL_MASK				(1 << 26)
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_SHIFT			25
+#define OMAP4_SDMMC1_DR2_SPEEDCTRL_MASK				(1 << 25)
+#define OMAP4_USBC1_DR0_SPEEDCTRL_SHIFT				24
+#define OMAP4_USBC1_DR0_SPEEDCTRL_MASK				(1 << 24)
+#define OMAP4_USB_FD_CDEN_SHIFT					23
+#define OMAP4_USB_FD_CDEN_MASK					(1 << 23)
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_SHIFT			22
+#define OMAP4_USBC1_ICUSB_DP_PDDIS_MASK				(1 << 22)
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_SHIFT			21
+#define OMAP4_USBC1_ICUSB_DM_PDDIS_MASK				(1 << 21)
+
+/* CONTROL_HSI */
+#define OMAP4_HSI1_CALLOOP_SEL_SHIFT				31
+#define OMAP4_HSI1_CALLOOP_SEL_MASK				(1 << 31)
+#define OMAP4_HSI1_CALMUX_SEL_SHIFT				30
+#define OMAP4_HSI1_CALMUX_SEL_MASK				(1 << 30)
+#define OMAP4_HSI2_CALLOOP_SEL_SHIFT				29
+#define OMAP4_HSI2_CALLOOP_SEL_MASK				(1 << 29)
+#define OMAP4_HSI2_CALMUX_SEL_SHIFT				28
+#define OMAP4_HSI2_CALMUX_SEL_MASK				(1 << 28)
+
+/* CONTROL_USB */
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_SHIFT		31
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT0_AUTO_EN_MASK		(1 << 31)
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_SHIFT		30
+#define OMAP4_CARKIT_USBA0_ULPIPHY_DAT1_AUTO_EN_MASK		(1 << 30)
+
+/* CONTROL_HDQ */
+#define OMAP4_HDQ_SIO_PWRDNZ_SHIFT				31
+#define OMAP4_HDQ_SIO_PWRDNZ_MASK				(1 << 31)
+
+/* CONTROL_LPDDR2IO1_0 */
+#define OMAP4_LPDDR2IO1_GR4_SR_SHIFT				30
+#define OMAP4_LPDDR2IO1_GR4_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR4_I_SHIFT				27
+#define OMAP4_LPDDR2IO1_GR4_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR4_WD_SHIFT				25
+#define OMAP4_LPDDR2IO1_GR4_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR3_SR_SHIFT				22
+#define OMAP4_LPDDR2IO1_GR3_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR3_I_SHIFT				19
+#define OMAP4_LPDDR2IO1_GR3_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR3_WD_SHIFT				17
+#define OMAP4_LPDDR2IO1_GR3_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR2_SR_SHIFT				14
+#define OMAP4_LPDDR2IO1_GR2_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR2_I_SHIFT				11
+#define OMAP4_LPDDR2IO1_GR2_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR2_WD_SHIFT				9
+#define OMAP4_LPDDR2IO1_GR2_WD_MASK				(0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR1_SR_SHIFT				6
+#define OMAP4_LPDDR2IO1_GR1_SR_MASK				(0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR1_I_SHIFT				3
+#define OMAP4_LPDDR2IO1_GR1_I_MASK				(0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR1_WD_SHIFT				1
+#define OMAP4_LPDDR2IO1_GR1_WD_MASK				(0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_1 */
+#define OMAP4_LPDDR2IO1_GR8_SR_SHIFT				30
+#define OMAP4_LPDDR2IO1_GR8_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR8_I_SHIFT				27
+#define OMAP4_LPDDR2IO1_GR8_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR8_WD_SHIFT				25
+#define OMAP4_LPDDR2IO1_GR8_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR7_SR_SHIFT				22
+#define OMAP4_LPDDR2IO1_GR7_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR7_I_SHIFT				19
+#define OMAP4_LPDDR2IO1_GR7_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR7_WD_SHIFT				17
+#define OMAP4_LPDDR2IO1_GR7_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR6_SR_SHIFT				14
+#define OMAP4_LPDDR2IO1_GR6_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR6_I_SHIFT				11
+#define OMAP4_LPDDR2IO1_GR6_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR6_WD_SHIFT				9
+#define OMAP4_LPDDR2IO1_GR6_WD_MASK				(0x3 << 9)
+#define OMAP4_LPDDR2IO1_GR5_SR_SHIFT				6
+#define OMAP4_LPDDR2IO1_GR5_SR_MASK				(0x3 << 6)
+#define OMAP4_LPDDR2IO1_GR5_I_SHIFT				3
+#define OMAP4_LPDDR2IO1_GR5_I_MASK				(0x7 << 3)
+#define OMAP4_LPDDR2IO1_GR5_WD_SHIFT				1
+#define OMAP4_LPDDR2IO1_GR5_WD_MASK				(0x3 << 1)
+
+/* CONTROL_LPDDR2IO1_2 */
+#define OMAP4_LPDDR2IO1_GR11_SR_SHIFT				30
+#define OMAP4_LPDDR2IO1_GR11_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO1_GR11_I_SHIFT				27
+#define OMAP4_LPDDR2IO1_GR11_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO1_GR11_WD_SHIFT				25
+#define OMAP4_LPDDR2IO1_GR11_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO1_GR10_SR_SHIFT				22
+#define OMAP4_LPDDR2IO1_GR10_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO1_GR10_I_SHIFT				19
+#define OMAP4_LPDDR2IO1_GR10_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO1_GR10_WD_SHIFT				17
+#define OMAP4_LPDDR2IO1_GR10_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO1_GR9_SR_SHIFT				14
+#define OMAP4_LPDDR2IO1_GR9_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO1_GR9_I_SHIFT				11
+#define OMAP4_LPDDR2IO1_GR9_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO1_GR9_WD_SHIFT				9
+#define OMAP4_LPDDR2IO1_GR9_WD_MASK				(0x3 << 9)
+
+/* CONTROL_LPDDR2IO1_3 */
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_SHIFT			31
+#define OMAP4_LPDDR21_VREF_CA_CCAP0_MASK			(1 << 31)
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_SHIFT			30
+#define OMAP4_LPDDR21_VREF_CA_CCAP1_MASK			(1 << 30)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_SHIFT			29
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP0_MASK			(1 << 29)
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_SHIFT			28
+#define OMAP4_LPDDR21_VREF_CA_INT_CCAP1_MASK			(1 << 28)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_SHIFT			27
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP0_MASK			(1 << 27)
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_SHIFT			26
+#define OMAP4_LPDDR21_VREF_CA_INT_TAP1_MASK			(1 << 26)
+#define OMAP4_LPDDR21_VREF_CA_TAP0_SHIFT			25
+#define OMAP4_LPDDR21_VREF_CA_TAP0_MASK				(1 << 25)
+#define OMAP4_LPDDR21_VREF_CA_TAP1_SHIFT			24
+#define OMAP4_LPDDR21_VREF_CA_TAP1_MASK				(1 << 24)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_SHIFT			23
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP0_MASK			(1 << 23)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_SHIFT			22
+#define OMAP4_LPDDR21_VREF_DQ0_INT_CCAP1_MASK			(1 << 22)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_SHIFT			21
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP0_MASK			(1 << 21)
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_SHIFT			20
+#define OMAP4_LPDDR21_VREF_DQ0_INT_TAP1_MASK			(1 << 20)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_SHIFT			19
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP0_MASK			(1 << 19)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_SHIFT			18
+#define OMAP4_LPDDR21_VREF_DQ1_INT_CCAP1_MASK			(1 << 18)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_SHIFT			17
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP0_MASK			(1 << 17)
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_SHIFT			16
+#define OMAP4_LPDDR21_VREF_DQ1_INT_TAP1_MASK			(1 << 16)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_SHIFT			15
+#define OMAP4_LPDDR21_VREF_DQ_CCAP0_MASK			(1 << 15)
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_SHIFT			14
+#define OMAP4_LPDDR21_VREF_DQ_CCAP1_MASK			(1 << 14)
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_SHIFT			13
+#define OMAP4_LPDDR21_VREF_DQ_TAP0_MASK				(1 << 13)
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_SHIFT			12
+#define OMAP4_LPDDR21_VREF_DQ_TAP1_MASK				(1 << 12)
+
+/* CONTROL_LPDDR2IO2_0 */
+#define OMAP4_LPDDR2IO2_GR4_SR_SHIFT				30
+#define OMAP4_LPDDR2IO2_GR4_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR4_I_SHIFT				27
+#define OMAP4_LPDDR2IO2_GR4_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR4_WD_SHIFT				25
+#define OMAP4_LPDDR2IO2_GR4_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR3_SR_SHIFT				22
+#define OMAP4_LPDDR2IO2_GR3_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR3_I_SHIFT				19
+#define OMAP4_LPDDR2IO2_GR3_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR3_WD_SHIFT				17
+#define OMAP4_LPDDR2IO2_GR3_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR2_SR_SHIFT				14
+#define OMAP4_LPDDR2IO2_GR2_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR2_I_SHIFT				11
+#define OMAP4_LPDDR2IO2_GR2_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR2_WD_SHIFT				9
+#define OMAP4_LPDDR2IO2_GR2_WD_MASK				(0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR1_SR_SHIFT				6
+#define OMAP4_LPDDR2IO2_GR1_SR_MASK				(0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR1_I_SHIFT				3
+#define OMAP4_LPDDR2IO2_GR1_I_MASK				(0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR1_WD_SHIFT				1
+#define OMAP4_LPDDR2IO2_GR1_WD_MASK				(0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_1 */
+#define OMAP4_LPDDR2IO2_GR8_SR_SHIFT				30
+#define OMAP4_LPDDR2IO2_GR8_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR8_I_SHIFT				27
+#define OMAP4_LPDDR2IO2_GR8_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR8_WD_SHIFT				25
+#define OMAP4_LPDDR2IO2_GR8_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR7_SR_SHIFT				22
+#define OMAP4_LPDDR2IO2_GR7_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR7_I_SHIFT				19
+#define OMAP4_LPDDR2IO2_GR7_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR7_WD_SHIFT				17
+#define OMAP4_LPDDR2IO2_GR7_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR6_SR_SHIFT				14
+#define OMAP4_LPDDR2IO2_GR6_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR6_I_SHIFT				11
+#define OMAP4_LPDDR2IO2_GR6_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR6_WD_SHIFT				9
+#define OMAP4_LPDDR2IO2_GR6_WD_MASK				(0x3 << 9)
+#define OMAP4_LPDDR2IO2_GR5_SR_SHIFT				6
+#define OMAP4_LPDDR2IO2_GR5_SR_MASK				(0x3 << 6)
+#define OMAP4_LPDDR2IO2_GR5_I_SHIFT				3
+#define OMAP4_LPDDR2IO2_GR5_I_MASK				(0x7 << 3)
+#define OMAP4_LPDDR2IO2_GR5_WD_SHIFT				1
+#define OMAP4_LPDDR2IO2_GR5_WD_MASK				(0x3 << 1)
+
+/* CONTROL_LPDDR2IO2_2 */
+#define OMAP4_LPDDR2IO2_GR11_SR_SHIFT				30
+#define OMAP4_LPDDR2IO2_GR11_SR_MASK				(0x3 << 30)
+#define OMAP4_LPDDR2IO2_GR11_I_SHIFT				27
+#define OMAP4_LPDDR2IO2_GR11_I_MASK				(0x7 << 27)
+#define OMAP4_LPDDR2IO2_GR11_WD_SHIFT				25
+#define OMAP4_LPDDR2IO2_GR11_WD_MASK				(0x3 << 25)
+#define OMAP4_LPDDR2IO2_GR10_SR_SHIFT				22
+#define OMAP4_LPDDR2IO2_GR10_SR_MASK				(0x3 << 22)
+#define OMAP4_LPDDR2IO2_GR10_I_SHIFT				19
+#define OMAP4_LPDDR2IO2_GR10_I_MASK				(0x7 << 19)
+#define OMAP4_LPDDR2IO2_GR10_WD_SHIFT				17
+#define OMAP4_LPDDR2IO2_GR10_WD_MASK				(0x3 << 17)
+#define OMAP4_LPDDR2IO2_GR9_SR_SHIFT				14
+#define OMAP4_LPDDR2IO2_GR9_SR_MASK				(0x3 << 14)
+#define OMAP4_LPDDR2IO2_GR9_I_SHIFT				11
+#define OMAP4_LPDDR2IO2_GR9_I_MASK				(0x7 << 11)
+#define OMAP4_LPDDR2IO2_GR9_WD_SHIFT				9
+#define OMAP4_LPDDR2IO2_GR9_WD_MASK				(0x3 << 9)
+
+/* CONTROL_LPDDR2IO2_3 */
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_SHIFT			31
+#define OMAP4_LPDDR22_VREF_CA_CCAP0_MASK			(1 << 31)
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_SHIFT			30
+#define OMAP4_LPDDR22_VREF_CA_CCAP1_MASK			(1 << 30)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_SHIFT			29
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP0_MASK			(1 << 29)
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_SHIFT			28
+#define OMAP4_LPDDR22_VREF_CA_INT_CCAP1_MASK			(1 << 28)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_SHIFT			27
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP0_MASK			(1 << 27)
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_SHIFT			26
+#define OMAP4_LPDDR22_VREF_CA_INT_TAP1_MASK			(1 << 26)
+#define OMAP4_LPDDR22_VREF_CA_TAP0_SHIFT			25
+#define OMAP4_LPDDR22_VREF_CA_TAP0_MASK				(1 << 25)
+#define OMAP4_LPDDR22_VREF_CA_TAP1_SHIFT			24
+#define OMAP4_LPDDR22_VREF_CA_TAP1_MASK				(1 << 24)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_SHIFT			23
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP0_MASK			(1 << 23)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_SHIFT			22
+#define OMAP4_LPDDR22_VREF_DQ0_INT_CCAP1_MASK			(1 << 22)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_SHIFT			21
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP0_MASK			(1 << 21)
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_SHIFT			20
+#define OMAP4_LPDDR22_VREF_DQ0_INT_TAP1_MASK			(1 << 20)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_SHIFT			19
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP0_MASK			(1 << 19)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_SHIFT			18
+#define OMAP4_LPDDR22_VREF_DQ1_INT_CCAP1_MASK			(1 << 18)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_SHIFT			17
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP0_MASK			(1 << 17)
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_SHIFT			16
+#define OMAP4_LPDDR22_VREF_DQ1_INT_TAP1_MASK			(1 << 16)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_SHIFT			15
+#define OMAP4_LPDDR22_VREF_DQ_CCAP0_MASK			(1 << 15)
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_SHIFT			14
+#define OMAP4_LPDDR22_VREF_DQ_CCAP1_MASK			(1 << 14)
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_SHIFT			13
+#define OMAP4_LPDDR22_VREF_DQ_TAP0_MASK				(1 << 13)
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_SHIFT			12
+#define OMAP4_LPDDR22_VREF_DQ_TAP1_MASK				(1 << 12)
+
+/* CONTROL_BUS_HOLD */
+#define OMAP4_ABE_DMIC_DIN3_EN_SHIFT				31
+#define OMAP4_ABE_DMIC_DIN3_EN_MASK				(1 << 31)
+#define OMAP4_MCSPI1_CS3_EN_SHIFT				30
+#define OMAP4_MCSPI1_CS3_EN_MASK				(1 << 30)
+
+/* CONTROL_C2C */
+#define OMAP4_MIRROR_MODE_EN_SHIFT				31
+#define OMAP4_MIRROR_MODE_EN_MASK				(1 << 31)
+#define OMAP4_C2C_SPARE_SHIFT					24
+#define OMAP4_C2C_SPARE_MASK					(0x7f << 24)
+
+/* CORE_CONTROL_SPARE_RW */
+#define OMAP4_CORE_CONTROL_SPARE_RW_SHIFT			0
+#define OMAP4_CORE_CONTROL_SPARE_RW_MASK			(0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R */
+#define OMAP4_CORE_CONTROL_SPARE_R_SHIFT			0
+#define OMAP4_CORE_CONTROL_SPARE_R_MASK				(0xffffffff << 0)
+
+/* CORE_CONTROL_SPARE_R_C0 */
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_SHIFT			31
+#define OMAP4_CORE_CONTROL_SPARE_R_C0_MASK			(1 << 31)
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_SHIFT			30
+#define OMAP4_CORE_CONTROL_SPARE_R_C1_MASK			(1 << 30)
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_SHIFT			29
+#define OMAP4_CORE_CONTROL_SPARE_R_C2_MASK			(1 << 29)
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_SHIFT			28
+#define OMAP4_CORE_CONTROL_SPARE_R_C3_MASK			(1 << 28)
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_SHIFT			27
+#define OMAP4_CORE_CONTROL_SPARE_R_C4_MASK			(1 << 27)
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_SHIFT			26
+#define OMAP4_CORE_CONTROL_SPARE_R_C5_MASK			(1 << 26)
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_SHIFT			25
+#define OMAP4_CORE_CONTROL_SPARE_R_C6_MASK			(1 << 25)
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_SHIFT			24
+#define OMAP4_CORE_CONTROL_SPARE_R_C7_MASK			(1 << 24)
+
+/* CONTROL_EFUSE_1 */
+#define OMAP4_AVDAC_TRIM_BYTE3_SHIFT				24
+#define OMAP4_AVDAC_TRIM_BYTE3_MASK				(0x7f << 24)
+#define OMAP4_AVDAC_TRIM_BYTE2_SHIFT				16
+#define OMAP4_AVDAC_TRIM_BYTE2_MASK				(0xff << 16)
+#define OMAP4_AVDAC_TRIM_BYTE1_SHIFT				8
+#define OMAP4_AVDAC_TRIM_BYTE1_MASK				(0xff << 8)
+#define OMAP4_AVDAC_TRIM_BYTE0_SHIFT				0
+#define OMAP4_AVDAC_TRIM_BYTE0_MASK				(0xff << 0)
+
+/* CONTROL_EFUSE_2 */
+#define OMAP4_EFUSE_SMART2TEST_P0_SHIFT				31
+#define OMAP4_EFUSE_SMART2TEST_P0_MASK				(1 << 31)
+#define OMAP4_EFUSE_SMART2TEST_P1_SHIFT				30
+#define OMAP4_EFUSE_SMART2TEST_P1_MASK				(1 << 30)
+#define OMAP4_EFUSE_SMART2TEST_P2_SHIFT				29
+#define OMAP4_EFUSE_SMART2TEST_P2_MASK				(1 << 29)
+#define OMAP4_EFUSE_SMART2TEST_P3_SHIFT				28
+#define OMAP4_EFUSE_SMART2TEST_P3_MASK				(1 << 28)
+#define OMAP4_EFUSE_SMART2TEST_N0_SHIFT				27
+#define OMAP4_EFUSE_SMART2TEST_N0_MASK				(1 << 27)
+#define OMAP4_EFUSE_SMART2TEST_N1_SHIFT				26
+#define OMAP4_EFUSE_SMART2TEST_N1_MASK				(1 << 26)
+#define OMAP4_EFUSE_SMART2TEST_N2_SHIFT				25
+#define OMAP4_EFUSE_SMART2TEST_N2_MASK				(1 << 25)
+#define OMAP4_EFUSE_SMART2TEST_N3_SHIFT				24
+#define OMAP4_EFUSE_SMART2TEST_N3_MASK				(1 << 24)
+#define OMAP4_LPDDR2_PTV_N1_SHIFT				23
+#define OMAP4_LPDDR2_PTV_N1_MASK				(1 << 23)
+#define OMAP4_LPDDR2_PTV_N2_SHIFT				22
+#define OMAP4_LPDDR2_PTV_N2_MASK				(1 << 22)
+#define OMAP4_LPDDR2_PTV_N3_SHIFT				21
+#define OMAP4_LPDDR2_PTV_N3_MASK				(1 << 21)
+#define OMAP4_LPDDR2_PTV_N4_SHIFT				20
+#define OMAP4_LPDDR2_PTV_N4_MASK				(1 << 20)
+#define OMAP4_LPDDR2_PTV_N5_SHIFT				19
+#define OMAP4_LPDDR2_PTV_N5_MASK				(1 << 19)
+#define OMAP4_LPDDR2_PTV_P1_SHIFT				18
+#define OMAP4_LPDDR2_PTV_P1_MASK				(1 << 18)
+#define OMAP4_LPDDR2_PTV_P2_SHIFT				17
+#define OMAP4_LPDDR2_PTV_P2_MASK				(1 << 17)
+#define OMAP4_LPDDR2_PTV_P3_SHIFT				16
+#define OMAP4_LPDDR2_PTV_P3_MASK				(1 << 16)
+#define OMAP4_LPDDR2_PTV_P4_SHIFT				15
+#define OMAP4_LPDDR2_PTV_P4_MASK				(1 << 15)
+#define OMAP4_LPDDR2_PTV_P5_SHIFT				14
+#define OMAP4_LPDDR2_PTV_P5_MASK				(1 << 14)
+
+/* CONTROL_EFUSE_3 */
+#define OMAP4_STD_FUSE_SPARE_1_SHIFT				24
+#define OMAP4_STD_FUSE_SPARE_1_MASK				(0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_2_SHIFT				16
+#define OMAP4_STD_FUSE_SPARE_2_MASK				(0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_3_SHIFT				8
+#define OMAP4_STD_FUSE_SPARE_3_MASK				(0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_4_SHIFT				0
+#define OMAP4_STD_FUSE_SPARE_4_MASK				(0xff << 0)
+
+/* CONTROL_EFUSE_4 */
+#define OMAP4_STD_FUSE_SPARE_5_SHIFT				24
+#define OMAP4_STD_FUSE_SPARE_5_MASK				(0xff << 24)
+#define OMAP4_STD_FUSE_SPARE_6_SHIFT				16
+#define OMAP4_STD_FUSE_SPARE_6_MASK				(0xff << 16)
+#define OMAP4_STD_FUSE_SPARE_7_SHIFT				8
+#define OMAP4_STD_FUSE_SPARE_7_MASK				(0xff << 8)
+#define OMAP4_STD_FUSE_SPARE_8_SHIFT				0
+#define OMAP4_STD_FUSE_SPARE_8_MASK				(0xff << 0)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_pad_wkup_44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,236 @@
+/*
+ * OMAP44xx CTRL_MODULE_PAD_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_PAD_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_PAD_WKUP					0x4a31e000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_REVISION				0x0000
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_HWINFO				0x0004
+#define OMAP4_CTRL_MODULE_PAD_WKUP_IP_SYSCONFIG				0x0010
+#define OMAP4_CTRL_MODULE_PAD_WKUP_PADCONF_WAKEUPEVENT_0		0x007c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_0	0x05a0
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SMART1NOPMIO_PADCONF_1	0x05a4
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_PADCONF_MODE			0x05a8
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_XTAL_OSCILLATOR		0x05ac
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_USIMIO			0x0600
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2			0x0604
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_JTAG				0x0608
+#define OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_SYS				0x060c
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_RW		0x0614
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R			0x0618
+#define OMAP4_CTRL_MODULE_PAD_WKUP_WKUP_CONTROL_SPARE_R_C0		0x061c
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT				30
+#define OMAP4_IP_REV_SCHEME_MASK				(0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT					16
+#define OMAP4_IP_REV_FUNC_MASK					(0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT					11
+#define OMAP4_IP_REV_RTL_MASK					(0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT				8
+#define OMAP4_IP_REV_MAJOR_MASK					(0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT				6
+#define OMAP4_IP_REV_CUSTOM_MASK				(0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT				0
+#define OMAP4_IP_REV_MINOR_MASK					(0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT					0
+#define OMAP4_IP_HWINFO_MASK					(0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT			2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK			(0x3 << 2)
+
+/* PADCONF_WAKEUPEVENT_0 */
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_SHIFT		24
+#define OMAP4_JTAG_TDO_DUPLICATEWAKEUPEVENT_MASK		(1 << 24)
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_SHIFT		23
+#define OMAP4_JTAG_TDI_DUPLICATEWAKEUPEVENT_MASK		(1 << 23)
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_SHIFT		22
+#define OMAP4_JTAG_TMS_TMSC_DUPLICATEWAKEUPEVENT_MASK		(1 << 22)
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_SHIFT		21
+#define OMAP4_JTAG_RTCK_DUPLICATEWAKEUPEVENT_MASK		(1 << 21)
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_SHIFT		20
+#define OMAP4_JTAG_TCK_DUPLICATEWAKEUPEVENT_MASK		(1 << 20)
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_SHIFT		19
+#define OMAP4_JTAG_NTRST_DUPLICATEWAKEUPEVENT_MASK		(1 << 19)
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_SHIFT		18
+#define OMAP4_SYS_BOOT7_DUPLICATEWAKEUPEVENT_MASK		(1 << 18)
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_SHIFT		17
+#define OMAP4_SYS_BOOT6_DUPLICATEWAKEUPEVENT_MASK		(1 << 17)
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_SHIFT	16
+#define OMAP4_SYS_PWRON_RESET_OUT_DUPLICATEWAKEUPEVENT_MASK	(1 << 16)
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_SHIFT		15
+#define OMAP4_SYS_PWR_REQ_DUPLICATEWAKEUPEVENT_MASK		(1 << 15)
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_SHIFT		14
+#define OMAP4_SYS_NRESWARM_DUPLICATEWAKEUPEVENT_MASK		(1 << 14)
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_SHIFT		13
+#define OMAP4_SYS_32K_DUPLICATEWAKEUPEVENT_MASK			(1 << 13)
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_SHIFT		12
+#define OMAP4_FREF_CLK4_OUT_DUPLICATEWAKEUPEVENT_MASK		(1 << 12)
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_SHIFT		11
+#define OMAP4_FREF_CLK4_REQ_DUPLICATEWAKEUPEVENT_MASK		(1 << 11)
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_SHIFT		10
+#define OMAP4_FREF_CLK3_OUT_DUPLICATEWAKEUPEVENT_MASK		(1 << 10)
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_SHIFT		9
+#define OMAP4_FREF_CLK3_REQ_DUPLICATEWAKEUPEVENT_MASK		(1 << 9)
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_SHIFT		8
+#define OMAP4_FREF_CLK0_OUT_DUPLICATEWAKEUPEVENT_MASK		(1 << 8)
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_SHIFT		7
+#define OMAP4_FREF_CLK_IOREQ_DUPLICATEWAKEUPEVENT_MASK		(1 << 7)
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_SHIFT			6
+#define OMAP4_SR_SDA_DUPLICATEWAKEUPEVENT_MASK			(1 << 6)
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_SHIFT			5
+#define OMAP4_SR_SCL_DUPLICATEWAKEUPEVENT_MASK			(1 << 5)
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_SHIFT		4
+#define OMAP4_SIM_PWRCTRL_DUPLICATEWAKEUPEVENT_MASK		(1 << 4)
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_SHIFT			3
+#define OMAP4_SIM_CD_DUPLICATEWAKEUPEVENT_MASK			(1 << 3)
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_SHIFT		2
+#define OMAP4_SIM_RESET_DUPLICATEWAKEUPEVENT_MASK		(1 << 2)
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_SHIFT		1
+#define OMAP4_SIM_CLK_DUPLICATEWAKEUPEVENT_MASK			(1 << 1)
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_SHIFT			0
+#define OMAP4_SIM_IO_DUPLICATEWAKEUPEVENT_MASK			(1 << 0)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_0 */
+#define OMAP4_FREF_DR0_SC_SHIFT					30
+#define OMAP4_FREF_DR0_SC_MASK					(0x3 << 30)
+#define OMAP4_FREF_DR1_SC_SHIFT					28
+#define OMAP4_FREF_DR1_SC_MASK					(0x3 << 28)
+#define OMAP4_FREF_DR4_SC_SHIFT					26
+#define OMAP4_FREF_DR4_SC_MASK					(0x3 << 26)
+#define OMAP4_FREF_DR5_SC_SHIFT					24
+#define OMAP4_FREF_DR5_SC_MASK					(0x3 << 24)
+#define OMAP4_FREF_DR6_SC_SHIFT					22
+#define OMAP4_FREF_DR6_SC_MASK					(0x3 << 22)
+#define OMAP4_FREF_DR7_SC_SHIFT					20
+#define OMAP4_FREF_DR7_SC_MASK					(0x3 << 20)
+#define OMAP4_GPIO_DR7_SC_SHIFT					18
+#define OMAP4_GPIO_DR7_SC_MASK					(0x3 << 18)
+#define OMAP4_DPM_DR0_SC_SHIFT					14
+#define OMAP4_DPM_DR0_SC_MASK					(0x3 << 14)
+#define OMAP4_SIM_DR0_SC_SHIFT					12
+#define OMAP4_SIM_DR0_SC_MASK					(0x3 << 12)
+
+/* CONTROL_SMART1NOPMIO_PADCONF_1 */
+#define OMAP4_FREF_DR0_LB_SHIFT					30
+#define OMAP4_FREF_DR0_LB_MASK					(0x3 << 30)
+#define OMAP4_FREF_DR1_LB_SHIFT					28
+#define OMAP4_FREF_DR1_LB_MASK					(0x3 << 28)
+#define OMAP4_FREF_DR4_LB_SHIFT					26
+#define OMAP4_FREF_DR4_LB_MASK					(0x3 << 26)
+#define OMAP4_FREF_DR5_LB_SHIFT					24
+#define OMAP4_FREF_DR5_LB_MASK					(0x3 << 24)
+#define OMAP4_FREF_DR6_LB_SHIFT					22
+#define OMAP4_FREF_DR6_LB_MASK					(0x3 << 22)
+#define OMAP4_FREF_DR7_LB_SHIFT					20
+#define OMAP4_FREF_DR7_LB_MASK					(0x3 << 20)
+#define OMAP4_GPIO_DR7_LB_SHIFT					18
+#define OMAP4_GPIO_DR7_LB_MASK					(0x3 << 18)
+#define OMAP4_DPM_DR0_LB_SHIFT					14
+#define OMAP4_DPM_DR0_LB_MASK					(0x3 << 14)
+#define OMAP4_SIM_DR0_LB_SHIFT					12
+#define OMAP4_SIM_DR0_LB_MASK					(0x3 << 12)
+
+/* CONTROL_PADCONF_MODE */
+#define OMAP4_VDDS_DV_FREF_SHIFT				31
+#define OMAP4_VDDS_DV_FREF_MASK					(1 << 31)
+#define OMAP4_VDDS_DV_BANK2_SHIFT				30
+#define OMAP4_VDDS_DV_BANK2_MASK				(1 << 30)
+
+/* CONTROL_XTAL_OSCILLATOR */
+#define OMAP4_OSCILLATOR_BOOST_SHIFT				31
+#define OMAP4_OSCILLATOR_BOOST_MASK				(1 << 31)
+#define OMAP4_OSCILLATOR_OS_OUT_SHIFT				30
+#define OMAP4_OSCILLATOR_OS_OUT_MASK				(1 << 30)
+
+/* CONTROL_USIMIO */
+#define OMAP4_PAD_USIM_CLK_LOW_SHIFT				31
+#define OMAP4_PAD_USIM_CLK_LOW_MASK				(1 << 31)
+#define OMAP4_PAD_USIM_RST_LOW_SHIFT				29
+#define OMAP4_PAD_USIM_RST_LOW_MASK				(1 << 29)
+#define OMAP4_USIM_PWRDNZ_SHIFT					28
+#define OMAP4_USIM_PWRDNZ_MASK					(1 << 28)
+
+/* CONTROL_I2C_2 */
+#define OMAP4_SR_SDA_GLFENB_SHIFT				31
+#define OMAP4_SR_SDA_GLFENB_MASK				(1 << 31)
+#define OMAP4_SR_SDA_LOAD_BITS_SHIFT				29
+#define OMAP4_SR_SDA_LOAD_BITS_MASK				(0x3 << 29)
+#define OMAP4_SR_SDA_PULLUPRESX_SHIFT				28
+#define OMAP4_SR_SDA_PULLUPRESX_MASK				(1 << 28)
+#define OMAP4_SR_SCL_GLFENB_SHIFT				27
+#define OMAP4_SR_SCL_GLFENB_MASK				(1 << 27)
+#define OMAP4_SR_SCL_LOAD_BITS_SHIFT				25
+#define OMAP4_SR_SCL_LOAD_BITS_MASK				(0x3 << 25)
+#define OMAP4_SR_SCL_PULLUPRESX_SHIFT				24
+#define OMAP4_SR_SCL_PULLUPRESX_MASK				(1 << 24)
+
+/* CONTROL_JTAG */
+#define OMAP4_JTAG_NTRST_EN_SHIFT				31
+#define OMAP4_JTAG_NTRST_EN_MASK				(1 << 31)
+#define OMAP4_JTAG_TCK_EN_SHIFT					30
+#define OMAP4_JTAG_TCK_EN_MASK					(1 << 30)
+#define OMAP4_JTAG_RTCK_EN_SHIFT				29
+#define OMAP4_JTAG_RTCK_EN_MASK					(1 << 29)
+#define OMAP4_JTAG_TDI_EN_SHIFT					28
+#define OMAP4_JTAG_TDI_EN_MASK					(1 << 28)
+#define OMAP4_JTAG_TDO_EN_SHIFT					27
+#define OMAP4_JTAG_TDO_EN_MASK					(1 << 27)
+
+/* CONTROL_SYS */
+#define OMAP4_SYS_NRESWARM_PIPU_SHIFT				31
+#define OMAP4_SYS_NRESWARM_PIPU_MASK				(1 << 31)
+
+/* WKUP_CONTROL_SPARE_RW */
+#define OMAP4_WKUP_CONTROL_SPARE_RW_SHIFT			0
+#define OMAP4_WKUP_CONTROL_SPARE_RW_MASK			(0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R */
+#define OMAP4_WKUP_CONTROL_SPARE_R_SHIFT			0
+#define OMAP4_WKUP_CONTROL_SPARE_R_MASK				(0xffffffff << 0)
+
+/* WKUP_CONTROL_SPARE_R_C0 */
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_SHIFT			31
+#define OMAP4_WKUP_CONTROL_SPARE_R_C0_MASK			(1 << 31)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_SHIFT			30
+#define OMAP4_WKUP_CONTROL_SPARE_R_C1_MASK			(1 << 30)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_SHIFT			29
+#define OMAP4_WKUP_CONTROL_SPARE_R_C2_MASK			(1 << 29)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_SHIFT			28
+#define OMAP4_WKUP_CONTROL_SPARE_R_C3_MASK			(1 << 28)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_SHIFT			27
+#define OMAP4_WKUP_CONTROL_SPARE_R_C4_MASK			(1 << 27)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_SHIFT			26
+#define OMAP4_WKUP_CONTROL_SPARE_R_C5_MASK			(1 << 26)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_SHIFT			25
+#define OMAP4_WKUP_CONTROL_SPARE_R_C6_MASK			(1 << 25)
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_SHIFT			24
+#define OMAP4_WKUP_CONTROL_SPARE_R_C7_MASK			(1 << 24)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/ctrl_module_wkup_44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,92 @@
+/*
+ * OMAP44xx CTRL_MODULE_WKUP registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_CTRL_MODULE_WKUP_44XX_H
+
+
+/* Base address */
+#define OMAP4_CTRL_MODULE_WKUP				0x4a30c000
+
+/* Registers offset */
+#define OMAP4_CTRL_MODULE_WKUP_IP_REVISION		0x0000
+#define OMAP4_CTRL_MODULE_WKUP_IP_HWINFO		0x0004
+#define OMAP4_CTRL_MODULE_WKUP_IP_SYSCONFIG		0x0010
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_0	0x0460
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_1	0x0464
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_2	0x0468
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_3	0x046c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_4	0x0470
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_5	0x0474
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_6	0x0478
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_7	0x047c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_8	0x0480
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_9	0x0484
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_10	0x0488
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_11	0x048c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_12	0x0490
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_13	0x0494
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_14	0x0498
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_15	0x049c
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_16	0x04a0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_17	0x04a4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_18	0x04a8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_19	0x04ac
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_20	0x04b0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_21	0x04b4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_22	0x04b8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_23	0x04bc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_24	0x04c0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_25	0x04c4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_26	0x04c8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_27	0x04cc
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_28	0x04d0
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_29	0x04d4
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_30	0x04d8
+#define OMAP4_CTRL_MODULE_WKUP_CONF_DEBUG_SEL_TST_31	0x04dc
+
+/* Registers shifts and masks */
+
+/* IP_REVISION */
+#define OMAP4_IP_REV_SCHEME_SHIFT		30
+#define OMAP4_IP_REV_SCHEME_MASK		(0x3 << 30)
+#define OMAP4_IP_REV_FUNC_SHIFT			16
+#define OMAP4_IP_REV_FUNC_MASK			(0xfff << 16)
+#define OMAP4_IP_REV_RTL_SHIFT			11
+#define OMAP4_IP_REV_RTL_MASK			(0x1f << 11)
+#define OMAP4_IP_REV_MAJOR_SHIFT		8
+#define OMAP4_IP_REV_MAJOR_MASK			(0x7 << 8)
+#define OMAP4_IP_REV_CUSTOM_SHIFT		6
+#define OMAP4_IP_REV_CUSTOM_MASK		(0x3 << 6)
+#define OMAP4_IP_REV_MINOR_SHIFT		0
+#define OMAP4_IP_REV_MINOR_MASK			(0x3f << 0)
+
+/* IP_HWINFO */
+#define OMAP4_IP_HWINFO_SHIFT			0
+#define OMAP4_IP_HWINFO_MASK			(0xffffffff << 0)
+
+/* IP_SYSCONFIG */
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_SHIFT	2
+#define OMAP4_IP_SYSCONFIG_IDLEMODE_MASK	(0x3 << 2)
+
+/* CONF_DEBUG_SEL_TST_0 */
+#define OMAP4_WKUP_MODE_SHIFT			0
+#define OMAP4_WKUP_MODE_MASK				(1 << 0)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -31,95 +31,94 @@
 		 * the desired UART phys and virt addresses temporarily into
 		 * the omap_uart_phys and omap_uart_virt above.
 		 */
-		.macro	addruart, rx, tmp
+		.macro	addruart, rp, rv
 
 		/* Use omap_uart_phys/virt if already configured */
-10:		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =__virt_to_phys(omap_uart_phys)	@ physical base address
-		ldrne	\rx, =omap_uart_virt	@ virtual base address
-		ldr	\rx, [\rx, #0]
-		cmp	\rx, #0			@ is port configured?
+10:		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		ldreq	\rp, =__virt_to_phys(omap_uart_phys)	@ MMU not enabled
+		ldrne	\rp, =omap_uart_phys	@ MMU enabled
+		add	\rv, \rp, #4		@ omap_uart_virt
+		ldr	\rp, [\rp, #0]
+		ldr	\rv, [\rv, #0]
+		cmp	\rp, #0			@ is port configured?
+		cmpne	\rv, #0
 		bne	99f			@ already configured
 
 		/* Check the debug UART configuration set in uncompress.h */
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =OMAP_UART_INFO
-		ldrne	\rx, =__phys_to_virt(OMAP_UART_INFO)
-		ldr	\rx, [\rx, #0]
+		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		ldreq	\rp, =OMAP_UART_INFO	@ MMU not enabled
+		ldrne	\rp, =__phys_to_virt(OMAP_UART_INFO)	@ MMU enabled
+		ldr	\rp, [\rp, #0]
 
 		/* Select the UART to use based on the UART1 scratchpad value */
-		cmp	\rx, #0			@ no port configured?
+		cmp	\rp, #0			@ no port configured?
 		beq	21f			@ if none, try to use UART1
-		cmp	\rx, #OMAP2UART1	@ OMAP2/3/4UART1
+		cmp	\rp, #OMAP2UART1	@ OMAP2/3/4UART1
 		beq	21f			@ configure OMAP2/3/4UART1
-		cmp	\rx, #OMAP2UART2	@ OMAP2/3/4UART2
+		cmp	\rp, #OMAP2UART2	@ OMAP2/3/4UART2
 		beq	22f			@ configure OMAP2/3/4UART2
-		cmp	\rx, #OMAP2UART3	@ only on 24xx
+		cmp	\rp, #OMAP2UART3	@ only on 24xx
 		beq	23f			@ configure OMAP2UART3
-		cmp	\rx, #OMAP3UART3	@ only on 34xx
+		cmp	\rp, #OMAP3UART3	@ only on 34xx
 		beq	33f			@ configure OMAP3UART3
-		cmp	\rx, #OMAP4UART3	@ only on 44xx
+		cmp	\rp, #OMAP4UART3	@ only on 44xx
 		beq	43f			@ configure OMAP4UART3
-		cmp	\rx, #OMAP3UART4	@ only on 36xx
+		cmp	\rp, #OMAP3UART4	@ only on 36xx
 		beq	34f			@ configure OMAP3UART4
-		cmp	\rx, #OMAP4UART4	@ only on 44xx
+		cmp	\rp, #OMAP4UART4	@ only on 44xx
 		beq	44f			@ configure OMAP4UART4
-		cmp	\rx, #ZOOM_UART		@ only on zoom2/3
+		cmp	\rp, #ZOOM_UART		@ only on zoom2/3
 		beq	95f			@ configure ZOOM_UART
 
 		/* Configure the UART offset from the phys/virt base */
-21:		mov	\rx, #UART_OFFSET(OMAP2_UART1_BASE)	@ omap2/3/4
+21:		mov	\rp, #UART_OFFSET(OMAP2_UART1_BASE)	@ omap2/3/4
 		b	98f
-22:		mov	\rx, #UART_OFFSET(OMAP2_UART2_BASE)	@ omap2/3/4
+22:		mov	\rp, #UART_OFFSET(OMAP2_UART2_BASE)	@ omap2/3/4
 		b	98f
-23:		mov	\rx, #UART_OFFSET(OMAP2_UART3_BASE)
+23:		mov	\rp, #UART_OFFSET(OMAP2_UART3_BASE)
 		b	98f
-33:		mov	\rx, #UART_OFFSET(OMAP3_UART1_BASE)
-		add	\rx, \rx, #0x00fb0000
-		add	\rx, \rx, #0x00006000		@ OMAP3_UART3_BASE
+33:		mov	\rp, #UART_OFFSET(OMAP3_UART1_BASE)
+		add	\rp, \rp, #0x00fb0000
+		add	\rp, \rp, #0x00006000		@ OMAP3_UART3_BASE
 		b	98f
-34:		mov	\rx, #UART_OFFSET(OMAP3_UART1_BASE)
-		add	\rx, \rx, #0x00fb0000
-		add	\rx, \rx, #0x00028000		@ OMAP3_UART4_BASE
+34:		mov	\rp, #UART_OFFSET(OMAP3_UART1_BASE)
+		add	\rp, \rp, #0x00fb0000
+		add	\rp, \rp, #0x00028000		@ OMAP3_UART4_BASE
 		b	98f
-43:		mov	\rx, #UART_OFFSET(OMAP4_UART3_BASE)
+43:		mov	\rp, #UART_OFFSET(OMAP4_UART3_BASE)
 		b	98f
-44:		mov	\rx, #UART_OFFSET(OMAP4_UART4_BASE)
+44:		mov	\rp, #UART_OFFSET(OMAP4_UART4_BASE)
 		b	98f
-95:		ldr	\rx, =ZOOM_UART_BASE
-		mrc	p15, 0, \tmp, c1, c0
-		tst	\tmp, #1		@ MMU enabled?
-		ldreq	\tmp, =__virt_to_phys(omap_uart_phys)
-		ldrne	\tmp, =omap_uart_phys
-		str	\rx, [\tmp, #0]
-		ldr	\rx, =ZOOM_UART_VIRT
-		ldreq	\tmp, =__virt_to_phys(omap_uart_virt)
-		ldrne	\tmp, =omap_uart_virt
-		str	\rx, [\tmp, #0]
-		mov	\rx, #(UART_LSR << ZOOM_PORT_SHIFT)
-		ldreq	\tmp, =__virt_to_phys(omap_uart_lsr)
-		ldrne	\tmp, =omap_uart_lsr
-		str	\rx, [\tmp, #0]
+95:		ldr	\rp, =ZOOM_UART_BASE
+		mrc	p15, 0, \rv, c1, c0
+		tst	\rv, #1			@ MMU enabled?
+		ldreq	\rv, =__virt_to_phys(omap_uart_phys)	@ MMU not enabled
+		ldrne	\rv, =omap_uart_phys	@ MMU enabled
+		str	\rp, [\rv, #0]
+		ldr	\rp, =ZOOM_UART_VIRT
+		add	\rv, \rv, #4		@ omap_uart_virt
+		str	\rp, [\rv, #0]
+		mov	\rp, #(UART_LSR << ZOOM_PORT_SHIFT)
+		add	\rv, \rv, #4		@ omap_uart_lsr
+		str	\rp, [\rv, #0]
 		b	10b
 
 		/* Store both phys and virt address for the uart */
-98:		add	\rx, \rx, #0x48000000	@ phys base
-		mrc	p15, 0, \tmp, c1, c0
-		tst	\tmp, #1		@ MMU enabled?
-		ldreq	\tmp, =__virt_to_phys(omap_uart_phys)
-		ldrne	\tmp, =omap_uart_phys
-		str	\rx, [\tmp, #0]
-		sub	\rx, \rx, #0x48000000	@ phys base
-		add	\rx, \rx, #0xfa000000	@ virt base
-		ldreq	\tmp, =__virt_to_phys(omap_uart_virt)
-		ldrne	\tmp, =omap_uart_virt
-		str	\rx, [\tmp, #0]
-		mov	\rx, #(UART_LSR << OMAP_PORT_SHIFT)
-		ldreq	\tmp, =__virt_to_phys(omap_uart_lsr)
-		ldrne	\tmp, =omap_uart_lsr
-		str	\rx, [\tmp, #0]
+98:		add	\rp, \rp, #0x48000000	@ phys base
+		mrc	p15, 0, \rv, c1, c0
+		tst	\rv, #1			@ MMU enabled?
+		ldreq	\rv, =__virt_to_phys(omap_uart_phys)	@ MMU not enabled
+		ldrne	\rv, =omap_uart_phys	@ MMU enabled
+		str	\rp, [\rv, #0]
+		sub	\rp, \rp, #0x48000000	@ phys base
+		add	\rp, \rp, #0xfa000000	@ virt base
+		add	\rv, \rv, #4		@ omap_uart_virt
+		str	\rp, [\rv, #0]
+		mov	\rp, #(UART_LSR << OMAP_PORT_SHIFT)
+		add	\rv, \rv, #4		@ omap_uart_lsr
+		str	\rp, [\rv, #0]
 
 		b	10b
 99:
@@ -131,9 +130,9 @@
 
 		.macro	busyuart,rd,rx
 1001:		mrc	p15, 0, \rd, c1, c0
-		tst	\rd, #1		@ MMU enabled?
-		ldreq	\rd, =__virt_to_phys(omap_uart_lsr)
-		ldrne	\rd, =omap_uart_lsr
+		tst	\rd, #1			@ MMU enabled?
+		ldreq	\rd, =__virt_to_phys(omap_uart_lsr)	@ MMU not enabled
+		ldrne	\rd, =omap_uart_lsr	@ MMU enabled
 		ldr	\rd, [\rd, #0]
 		ldrb	\rd, [\rx, \rd]
 		and	\rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END	  (PAGE_OFFSET + 0x38000000)
+#define VMALLOC_END	  0xf8000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/io.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/io.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/io.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,7 @@
 #include "clock2xxx.h"
 #include "clock3xxx.h"
 #include "clock44xx.h"
+#include "io.h"
 
 #include <plat/omap-pm.h>
 #include <plat/powerdomain.h>
@@ -296,7 +297,7 @@
 		return 0;
 
 	dpll3_m2_ck = clk_get(NULL, "dpll3_m2_ck");
-	if (!dpll3_m2_ck)
+	if (IS_ERR(dpll3_m2_ck))
 		return -EINVAL;
 
 	rate = clk_get_rate(dpll3_m2_ck);
@@ -323,6 +324,9 @@
 		omap2430_hwmod_init();
 	else if (cpu_is_omap34xx())
 		omap3xxx_hwmod_init();
+	else if (cpu_is_omap44xx())
+		omap44xx_hwmod_init();
+
 	/* The OPP tables have to be registered before a clk init */
 	omap_pm_if_early_init(mpu_opps, dsp_opps, l3_opps);
 
@@ -342,9 +346,7 @@
 #ifndef CONFIG_PM_RUNTIME
 	skip_setup_idle = 1;
 #endif
-	if (cpu_is_omap24xx() || cpu_is_omap34xx())   /* FIXME: OMAP4 */
-		omap_hwmod_late_init(skip_setup_idle);
-
+	omap_hwmod_late_init(skip_setup_idle);
 	if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
 		omap2_sdrc_init(sdrc_cs0, sdrc_cs1);
 		_omap2_init_reprogram_sdrc();
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/io.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/io.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/io.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,7 @@
+
+#ifndef __MACH_OMAP2_IO_H__
+#define __MACH_OMAP2_IO_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /*  __MACH_OMAP2_IO_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,7 +47,6 @@
 } __attribute__ ((aligned(4))) irq_banks[] = {
 	{
 		/* MPU INTC */
-		.base_reg	= 0,
 		.nr_irqs	= 96,
 	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-omap2/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,8 @@
 	select PM_RUNTIME
 	select VFP
 	select NEON if ARCH_OMAP3 || ARCH_OMAP4
-	select SERIAL_8250
-	select SERIAL_CORE_CONSOLE
-	select SERIAL_8250_CONSOLE
+	select SERIAL_OMAP
+	select SERIAL_OMAP_CONSOLE
 	select I2C
 	select I2C_OMAP
 	select MFD
@@ -35,7 +34,7 @@
 	default y
 	select CPU_V7
 	select USB_ARCH_HAS_EHCI
-	select ARM_L1_CACHE_SHIFT_6
+	select ARM_L1_CACHE_SHIFT_6 if !ARCH_OMAP4
 
 config ARCH_OMAP4
 	bool "TI OMAP4"
@@ -43,6 +42,8 @@
 	depends on ARCH_OMAP2PLUS
 	select CPU_V7
 	select ARM_GIC
+	select PL310_ERRATA_588369
+	select ARM_ERRATA_720789
 
 comment "OMAP Core Type"
 	depends on ARCH_OMAP2
@@ -99,20 +100,20 @@
 
 config MACH_OMAP_H4
 	bool "OMAP 2420 H4 board"
-	depends on ARCH_OMAP2
+	depends on ARCH_OMAP2420
 	default y
 	select OMAP_PACKAGE_ZAF
 	select OMAP_DEBUG_DEVICES
 
 config MACH_OMAP_APOLLON
 	bool "OMAP 2420 Apollon board"
-	depends on ARCH_OMAP2
+	depends on ARCH_OMAP2420
 	default y
 	select OMAP_PACKAGE_ZAC
 
 config MACH_OMAP_2430SDP
 	bool "OMAP 2430 SDP board"
-	depends on ARCH_OMAP2
+	depends on ARCH_OMAP2430
 	default y
 	select OMAP_PACKAGE_ZAC
 
@@ -135,6 +136,26 @@
 	default y
 	select OMAP_PACKAGE_CBB
 
+config MACH_OMAP3530_LV_SOM
+	bool "OMAP3 Logic 3530 LV SOM board"
+	depends on ARCH_OMAP3
+	select OMAP_PACKAGE_CBB
+	default y
+	help
+	 Support for the LogicPD OMAP3530 SOM Development kit
+	 for full description please see the products webpage at
+	 http://www.logicpd.com/products/development-kits/texas-instruments-zoom%E2%84%A2-omap35x-development-kit
+
+config MACH_OMAP3_TORPEDO
+	bool "OMAP3 Logic 35x Torpedo board"
+	depends on ARCH_OMAP3
+	select OMAP_PACKAGE_CBB
+	default y
+	help
+	 Support for the LogicPD OMAP35x Torpedo Development kit
+	 for full description please see the products webpage at
+	 http://www.logicpd.com/products/development-kits/zoom-omap35x-torpedo-development-kit
+
 config MACH_OVERO
 	bool "Gumstix Overo board"
 	depends on ARCH_OMAP3
@@ -200,12 +221,18 @@
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBB
+	select SERIAL_8250
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_8250_CONSOLE
 
 config MACH_OMAP_ZOOM3
 	bool "OMAP3630 Zoom3 board"
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBP
+	select SERIAL_8250
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_8250_CONSOLE
 
 config MACH_CM_T35
 	bool "CompuLab CM-T35 module"
@@ -214,11 +241,24 @@
 	select OMAP_PACKAGE_CUS
 	select OMAP_MUX
 
+config MACH_CM_T3517
+	bool "CompuLab CM-T3517 module"
+	depends on ARCH_OMAP3
+	default y
+	select OMAP_PACKAGE_CBB
+	select OMAP_MUX
+
 config MACH_IGEP0020
 	bool "IGEP v2 board"
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBB
+
+config MACH_IGEP0030
+	bool "IGEP OMAP3 module"
+	depends on ARCH_OMAP3
+	default y
+	select OMAP_PACKAGE_CBB
 
 config MACH_SBC3530
 	bool "OMAP3 SBC STALKER board"
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mailbox.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mailbox.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mailbox.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mailbox.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,7 +181,7 @@
 static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
 		omap_mbox_type_t irq)
 {
-	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	struct omap_mbox2_priv *p = mbox->priv;
 	u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 
 	l = mbox_read_reg(p->irqenable);
@@ -192,7 +192,7 @@
 static void omap2_mbox_disable_irq(struct omap_mbox *mbox,
 		omap_mbox_type_t irq)
 {
-	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	struct omap_mbox2_priv *p = mbox->priv;
 	u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 	l = mbox_read_reg(p->irqdisable);
 	l &= ~bit;
@@ -202,7 +202,7 @@
 static void omap2_mbox_ack_irq(struct omap_mbox *mbox,
 		omap_mbox_type_t irq)
 {
-	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	struct omap_mbox2_priv *p = mbox->priv;
 	u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 
 	mbox_write_reg(bit, p->irqstatus);
@@ -214,7 +214,7 @@
 static int omap2_mbox_is_irq(struct omap_mbox *mbox,
 		omap_mbox_type_t irq)
 {
-	struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+	struct omap_mbox2_priv *p = mbox->priv;
 	u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 	u32 enable = mbox_read_reg(p->irqenable);
 	u32 status = mbox_read_reg(p->irqstatus);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-omap2/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,9 +3,10 @@
 #
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o
+obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o \
+	 common.o
 
-omap-2-3-common				= irq.o sdrc.o
+omap-2-3-common				= irq.o sdrc.o prm2xxx_3xxx.o
 hwmod-common				= omap_hwmod.o \
 					  omap_hwmod_common_data.o
 prcm-common				= prcm.o powerdomain.o
@@ -15,7 +16,7 @@
 
 obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common)
-obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) prm44xx.o $(hwmod-common)
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
@@ -49,14 +50,18 @@
 # Power Management
 ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_ARCH_OMAP2)		+= pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o
-obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o
-obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o
+obj-$(CONFIG_ARCH_OMAP2)		+= sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP3)		+= pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP4)		+= pm44xx.o pm_bus.o
 obj-$(CONFIG_PM_DEBUG)			+= pm-debug.o
 
 AFLAGS_sleep24xx.o			:=-Wa,-march=armv6
 AFLAGS_sleep34xx.o			:=-Wa,-march=armv7-a
 
+ifeq ($(CONFIG_PM_VERBOSE),y)
+CFLAGS_pm_bus.o				+= -DDEBUG
+endif
+
 endif
 
 # PRCM
@@ -87,6 +92,7 @@
 obj-$(CONFIG_ARCH_OMAP2420)		+= omap_hwmod_2420_data.o
 obj-$(CONFIG_ARCH_OMAP2430)		+= omap_hwmod_2430_data.o
 obj-$(CONFIG_ARCH_OMAP3)		+= omap_hwmod_3xxx_data.o
+obj-$(CONFIG_ARCH_OMAP4)		+= omap_hwmod_44xx_data.o
 
 # EMU peripherals
 obj-$(CONFIG_OMAP3_EMU)			+= emu.o
@@ -102,6 +108,10 @@
 i2c-omap-$(CONFIG_I2C_OMAP)		:= i2c.o
 obj-y					+= $(i2c-omap-m) $(i2c-omap-y)
 
+ifneq ($(CONFIG_TIDSPBRIDGE),)
+obj-y					+= dsp.o
+endif
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)		+= board-generic.o
 obj-$(CONFIG_MACH_OMAP_H4)		+= board-h4.o
@@ -115,6 +125,10 @@
 obj-$(CONFIG_MACH_OMAP_LDP)		+= board-ldp.o \
 					   board-flash.o \
 					   hsmmc.o
+obj-$(CONFIG_MACH_OMAP3530_LV_SOM)      += board-omap3logic.o \
+					   hsmmc.o
+obj-$(CONFIG_MACH_OMAP3_TORPEDO)        += board-omap3logic.o \
+					   hsmmc.o
 obj-$(CONFIG_MACH_OVERO)		+= board-overo.o \
 					   hsmmc.o
 obj-$(CONFIG_MACH_OMAP3EVM)		+= board-omap3evm.o \
@@ -146,8 +160,11 @@
 					   hsmmc.o
 obj-$(CONFIG_MACH_CM_T35)		+= board-cm-t35.o \
 					   hsmmc.o
+obj-$(CONFIG_MACH_CM_T3517)		+= board-cm-t3517.o
 obj-$(CONFIG_MACH_IGEP0020)		+= board-igep0020.o \
 					   hsmmc.o
+obj-$(CONFIG_MACH_IGEP0030)		+= board-igep0030.o \
+					   hsmmc.o
 obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK)	+= board-omap3touchbook.o \
 					   hsmmc.o
 obj-$(CONFIG_MACH_OMAP_4430SDP)		+= board-4430sdp.o \
@@ -174,3 +191,6 @@
 
 smc91x-$(CONFIG_SMC91X)			:= gpmc-smc91x.o
 obj-y					+= $(smc91x-m) $(smc91x-y)
+
+smsc911x-$(CONFIG_SMSC911X)		:= gpmc-smsc911x.o
+obj-y					+= $(smsc911x-m) $(smsc911x-y)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mcbsp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mcbsp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mcbsp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mcbsp.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,29 +23,86 @@
 #include <plat/cpu.h>
 #include <plat/mcbsp.h>
 
-#include "mux.h"
+#include "control.h"
 
-static void omap2_mcbsp2_mux_setup(void)
+
+/* McBSP internal signal muxing functions */
+
+void omap2_mcbsp1_mux_clkr_src(u8 mux)
 {
-	omap_mux_init_signal("eac_ac_sclk.mcbsp2_clkx", OMAP_PULL_ENA);
-	omap_mux_init_signal("eac_ac_fs.mcbsp2_fsx", OMAP_PULL_ENA);
-	omap_mux_init_signal("eac_ac_din.mcbsp2_dr", OMAP_PULL_ENA);
-	omap_mux_init_signal("eac_ac_dout.mcbsp2_dx", OMAP_PULL_ENA);
-	omap_mux_init_gpio(117, OMAP_PULL_ENA);
-	/*
-	 * TODO: Need to add MUX settings for OMAP 2430 SDP
-	 */
+	u32 v;
+
+	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+	if (mux == CLKR_SRC_CLKR)
+		v &= ~OMAP2_MCBSP1_CLKR_MASK;
+	else if (mux == CLKR_SRC_CLKX)
+		v |= OMAP2_MCBSP1_CLKR_MASK;
+	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
 }
+EXPORT_SYMBOL(omap2_mcbsp1_mux_clkr_src);
 
-static void omap2_mcbsp_request(unsigned int id)
+void omap2_mcbsp1_mux_fsr_src(u8 mux)
 {
-	if (cpu_is_omap2420() && (id == OMAP_MCBSP2))
-		omap2_mcbsp2_mux_setup();
+	u32 v;
+
+	v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+	if (mux == FSR_SRC_FSR)
+		v &= ~OMAP2_MCBSP1_FSR_MASK;
+	else if (mux == FSR_SRC_FSX)
+		v |= OMAP2_MCBSP1_FSR_MASK;
+	omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
 }
+EXPORT_SYMBOL(omap2_mcbsp1_mux_fsr_src);
 
-static struct omap_mcbsp_ops omap2_mcbsp_ops = {
-	.request	= omap2_mcbsp_request,
-};
+/* McBSP CLKS source switching function */
+
+int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id)
+{
+	struct omap_mcbsp *mcbsp;
+	struct clk *fck_src;
+	char *fck_src_name;
+	int r;
+
+	if (!omap_mcbsp_check_valid_id(id)) {
+		pr_err("%s: Invalid id (%d)\n", __func__, id + 1);
+		return -EINVAL;
+	}
+	mcbsp = id_to_mcbsp_ptr(id);
+
+	if (fck_src_id == MCBSP_CLKS_PAD_SRC)
+		fck_src_name = "pad_fck";
+	else if (fck_src_id == MCBSP_CLKS_PRCM_SRC)
+		fck_src_name = "prcm_fck";
+	else
+		return -EINVAL;
+
+	fck_src = clk_get(mcbsp->dev, fck_src_name);
+	if (IS_ERR_OR_NULL(fck_src)) {
+		pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks",
+		       fck_src_name);
+		return -EINVAL;
+	}
+
+	clk_disable(mcbsp->fclk);
+
+	r = clk_set_parent(mcbsp->fclk, fck_src);
+	if (IS_ERR_VALUE(r)) {
+		pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n",
+		       "clks", fck_src_name);
+		clk_put(fck_src);
+		return -EINVAL;
+	}
+
+	clk_enable(mcbsp->fclk);
+
+	clk_put(fck_src);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_set_clks_src);
+
+
+/* Platform data */
 
 #ifdef CONFIG_ARCH_OMAP2420
 static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
@@ -55,7 +112,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP1_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base	= OMAP24XX_MCBSP2_BASE,
@@ -63,7 +119,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP2_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 };
 #define OMAP2420_MCBSP_PDATA_SZ		ARRAY_SIZE(omap2420_mcbsp_pdata)
@@ -82,7 +137,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP1_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base	= OMAP24XX_MCBSP2_BASE,
@@ -90,7 +144,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP2_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base	= OMAP2430_MCBSP3_BASE,
@@ -98,7 +151,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP3_TX,
 		.rx_irq		= INT_24XX_MCBSP3_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP3_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base	= OMAP2430_MCBSP4_BASE,
@@ -106,7 +158,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP4_TX,
 		.rx_irq		= INT_24XX_MCBSP4_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP4_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base	= OMAP2430_MCBSP5_BASE,
@@ -114,7 +165,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP5_TX,
 		.rx_irq		= INT_24XX_MCBSP5_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP5_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 	},
 };
 #define OMAP2430_MCBSP_PDATA_SZ		ARRAY_SIZE(omap2430_mcbsp_pdata)
@@ -133,7 +183,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP1_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	{
@@ -143,7 +192,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP2_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 		.buffer_size	= 0x500, /* The FIFO has 1024 + 256 locations */
 	},
 	{
@@ -153,7 +201,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP3_TX,
 		.rx_irq		= INT_24XX_MCBSP3_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP3_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	{
@@ -162,7 +209,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP4_TX,
 		.rx_irq		= INT_24XX_MCBSP4_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP4_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 	{
@@ -171,7 +217,6 @@
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP5_TX,
 		.rx_irq		= INT_24XX_MCBSP5_IRQ_RX,
 		.tx_irq		= INT_24XX_MCBSP5_IRQ_TX,
-		.ops		= &omap2_mcbsp_ops,
 		.buffer_size	= 0x80, /* The FIFO has 128 locations */
 	},
 };
@@ -189,28 +234,24 @@
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP1_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP1_TX,
 		.tx_irq         = OMAP44XX_IRQ_MCBSP1,
-		.ops            = &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base      = OMAP44XX_MCBSP2_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP2_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP2_TX,
 		.tx_irq         = OMAP44XX_IRQ_MCBSP2,
-		.ops            = &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base      = OMAP44XX_MCBSP3_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP3_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP3_TX,
 		.tx_irq         = OMAP44XX_IRQ_MCBSP3,
-		.ops            = &omap2_mcbsp_ops,
 	},
 	{
 		.phys_base      = OMAP44XX_MCBSP4_BASE,
 		.dma_rx_sync    = OMAP44XX_DMA_MCBSP4_RX,
 		.dma_tx_sync    = OMAP44XX_DMA_MCBSP4_TX,
 		.tx_irq         = OMAP44XX_IRQ_MCBSP4,
-		.ops            = &omap2_mcbsp_ops,
 	},
 };
 #define OMAP44XX_MCBSP_PDATA_SZ		ARRAY_SIZE(omap44xx_mcbsp_pdata)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux2420.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux2420.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux2420.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux2420.c	2011-01-04 19:50:19.000000000 -0500
@@ -507,7 +507,7 @@
  * Balls for 447-pin POP package
  */
 #ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2420_pop_ball[] = {
+static struct omap_ball __initdata omap2420_pop_ball[] = {
 	_OMAP2420_BALLENTRY(CAM_D0, "y4", NULL),
 	_OMAP2420_BALLENTRY(CAM_D1, "y3", NULL),
 	_OMAP2420_BALLENTRY(CAM_D2, "u7", NULL),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux2430.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux2430.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux2430.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux2430.c	2011-01-04 19:50:19.000000000 -0500
@@ -586,7 +586,7 @@
  * 447-pin s-PBGA Package, 0.00mm Ball Pitch (Bottom)
  */
 #ifdef CONFIG_DEBUG_FS
-struct omap_ball __initdata omap2430_pop_ball[] = {
+static struct omap_ball __initdata omap2430_pop_ball[] = {
 	_OMAP2430_BALLENTRY(CAM_D0, "t8", NULL),
 	_OMAP2430_BALLENTRY(CAM_D1, "t4", NULL),
 	_OMAP2430_BALLENTRY(CAM_D10, "r4", NULL),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux34xx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux34xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux34xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux34xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -931,7 +931,7 @@
  * Signals different on CUS package compared to superset
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_mux __initdata omap3_cus_subset[] = {
+static struct omap_mux __initdata omap3_cus_subset[] = {
 	_OMAP3_MUXENTRY(CAM_D10, 109,
 		"cam_d10", NULL, NULL, NULL,
 		"gpio_109", NULL, NULL, "safe_mode"),
@@ -1077,7 +1077,7 @@
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)		\
 		&& defined(CONFIG_OMAP_PACKAGE_CUS)
-struct omap_ball __initdata omap3_cus_ball[] = {
+static struct omap_ball __initdata omap3_cus_ball[] = {
 	_OMAP3_BALLENTRY(CAM_D0, "ab18", NULL),
 	_OMAP3_BALLENTRY(CAM_D1, "ac18", NULL),
 	_OMAP3_BALLENTRY(CAM_D10, "f21", NULL),
@@ -1269,7 +1269,7 @@
  * Signals different on CBB package comapared to superset
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_mux __initdata omap3_cbb_subset[] = {
+static struct omap_mux __initdata omap3_cbb_subset[] = {
 	_OMAP3_MUXENTRY(CAM_D10, 109,
 		"cam_d10", NULL, NULL, NULL,
 		"gpio_109", NULL, NULL, "safe_mode"),
@@ -1390,7 +1390,7 @@
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)		\
 		&& defined(CONFIG_OMAP_PACKAGE_CBB)
-struct omap_ball __initdata omap3_cbb_ball[] = {
+static struct omap_ball __initdata omap3_cbb_ball[] = {
 	_OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
 	_OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
 	_OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
@@ -1600,7 +1600,7 @@
  * Signals different on 36XX CBP package comapared to 34XX CBC package
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_OMAP_PACKAGE_CBP)
-struct omap_mux __initdata omap36xx_cbp_subset[] = {
+static struct omap_mux __initdata omap36xx_cbp_subset[] = {
 	_OMAP3_MUXENTRY(CAM_D0, 99,
 		"cam_d0", NULL, "csi2_dx2", NULL,
 		"gpio_99", NULL, NULL, "safe_mode"),
@@ -1818,7 +1818,7 @@
  */
 #if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)		\
 		&& defined (CONFIG_OMAP_PACKAGE_CBP)
-struct omap_ball __initdata omap36xx_cbp_ball[] = {
+static struct omap_ball __initdata omap36xx_cbp_ball[] = {
 	_OMAP3_BALLENTRY(CAM_D0, "ag17", NULL),
 	_OMAP3_BALLENTRY(CAM_D1, "ah17", NULL),
 	_OMAP3_BALLENTRY(CAM_D10, "b25", NULL),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,12 +23,11 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  */
-#include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -36,8 +35,7 @@
 
 #include <asm/system.h>
 
-#include <plat/control.h>
-
+#include "control.h"
 #include "mux.h"
 
 #define OMAP_MUX_BASE_OFFSET		0x30	/* Offset from CTRL_BASE */
@@ -87,7 +85,7 @@
 int __init omap_mux_init_gpio(int gpio, int val)
 {
 	struct omap_mux_entry *e;
-	struct omap_mux *gpio_mux;
+	struct omap_mux *gpio_mux = NULL;
 	u16 old_mode;
 	u16 mux_mode;
 	int found = 0;
@@ -127,17 +125,16 @@
 	return 0;
 }
 
-int __init omap_mux_init_signal(char *muxname, int val)
+int __init omap_mux_init_signal(const char *muxname, int val)
 {
 	struct omap_mux_entry *e;
-	char *m0_name = NULL, *mode_name = NULL;
-	int found = 0;
+	const char *mode_name;
+	int found = 0, mode0_len = 0;
 
 	mode_name = strchr(muxname, '.');
 	if (mode_name) {
-		*mode_name = '\0';
+		mode0_len = strlen(muxname) - strlen(mode_name);
 		mode_name++;
-		m0_name = muxname;
 	} else {
 		mode_name = muxname;
 	}
@@ -147,9 +144,11 @@
 		char *m0_entry = m->muxnames[0];
 		int i;
 
-		if (m0_name && strcmp(m0_name, m0_entry))
+		/* First check for full name in mode0.muxmode format */
+		if (mode0_len && strncmp(muxname, m0_entry, mode0_len))
 			continue;
 
+		/* Then check for muxmode only */
 		for (i = 0; i < OMAP_MUX_NR_MODES; i++) {
 			char *mode_cur = m->muxnames[i];
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/mux.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/mux.h	2011-01-04 19:50:19.000000000 -0500
@@ -120,7 +120,7 @@
  * @muxname:		Mux name in mode0_name.signal_name format
  * @val:		Options for the mux register value
  */
-int omap_mux_init_signal(char *muxname, int val);
+int omap_mux_init_signal(const char *muxname, int val);
 
 #else
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap4-common.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap4-common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap4-common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap4-common.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,13 @@
 }
 
 #ifdef CONFIG_CACHE_L2X0
+
+static void omap4_l2x0_disable(void)
+{
+	/* Disable PL310 L2 Cache controller */
+	omap_smc1(0x102, 0x0);
+}
+
 static int __init omap_l2_cache_init(void)
 {
 	/*
@@ -61,10 +68,20 @@
 	omap_smc1(0x102, 0x1);
 
 	/*
-	 * 32KB way size, 16-way associativity,
-	 * parity disabled
+	 * 16-way associativity, parity disabled
+	 * Way size - 32KB (es1.0)
+	 * Way size - 64KB (es2.0 +)
 	 */
-	l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+	if (omap_rev() == OMAP4430_REV_ES1_0)
+		l2x0_init(l2cache_base, 0x0e050000, 0xc0000fff);
+	else
+		l2x0_init(l2cache_base, 0x0e070000, 0xc0000fff);
+
+	/*
+	 * Override default outer_cache.disable with a OMAP4
+	 * specific one
+	*/
+	outer_cache.disable = omap4_l2x0_disable;
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_2420_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_2420_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_2420_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_2420_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,10 +15,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2420 hardware module integration data
@@ -33,6 +35,7 @@
 static struct omap_hwmod omap2420_iva_hwmod;
 static struct omap_hwmod omap2420_l3_main_hwmod;
 static struct omap_hwmod omap2420_l4_core_hwmod;
+static struct omap_hwmod omap2420_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -71,6 +74,9 @@
 };
 
 static struct omap_hwmod omap2420_l4_wkup_hwmod;
+static struct omap_hwmod omap2420_uart1_hwmod;
+static struct omap_hwmod omap2420_uart2_hwmod;
+static struct omap_hwmod omap2420_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART1_BASE,
+		.pa_end		= OMAP2_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap2420_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2420_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART2_BASE,
+		.pa_end		= OMAP2_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap2420_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2420_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART3_BASE,
+		.pa_end		= OMAP2_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap2420_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
 	&omap2420_l3_main__l4_core,
@@ -87,6 +147,9 @@
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
 	&omap2420_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
 };
 
 /* L4 CORE */
@@ -165,12 +228,206 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x48022000,
+		.pa_end		= 0x4802207f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
+	.master		= &omap2420_l4_wkup_hwmod,
+	.slave		= &omap2420_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2420_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap2420_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap2420_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
+	&omap2420_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2420_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap2420_wd_timer_hwmod_class,
+	.main_clk	= "mpu_wdt_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+		},
+	},
+	.slaves		= omap2420_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
+	&omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2420_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
+	&omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2420_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
+	&omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2420_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 2,
+			.module_bit = OMAP24XX_EN_UART3_SHIFT,
+			.idlest_reg_id = 2,
+			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
 static __initdata struct omap_hwmod *omap2420_hwmods[] = {
 	&omap2420_l3_main_hwmod,
 	&omap2420_l4_core_hwmod,
 	&omap2420_l4_wkup_hwmod,
 	&omap2420_mpu_hwmod,
 	&omap2420_iva_hwmod,
+	&omap2420_wd_timer2_hwmod,
+	&omap2420_uart1_hwmod,
+	&omap2420_uart2_hwmod,
+	&omap2420_uart3_hwmod,
 	NULL,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_2430_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_2430_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_2430_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_2430_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,10 +15,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2430 hardware module integration data
@@ -33,6 +35,7 @@
 static struct omap_hwmod omap2430_iva_hwmod;
 static struct omap_hwmod omap2430_l3_main_hwmod;
 static struct omap_hwmod omap2430_l4_core_hwmod;
+static struct omap_hwmod omap2430_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
@@ -71,6 +74,9 @@
 };
 
 static struct omap_hwmod omap2430_l4_wkup_hwmod;
+static struct omap_hwmod omap2430_uart1_hwmod;
+static struct omap_hwmod omap2430_uart2_hwmod;
+static struct omap_hwmod omap2430_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2430_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART1_BASE,
+		.pa_end		= OMAP2_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap2430_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2430_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART2_BASE,
+		.pa_end		= OMAP2_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap2430_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2430_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART3_BASE,
+		.pa_end		= OMAP2_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap2430_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
 	&omap2430_l3_main__l4_core,
@@ -104,6 +164,9 @@
 /* Slave interfaces on the L4_WKUP interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
 	&omap2430_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
 };
 
 /* Master interfaces on the L4_WKUP interconnect */
@@ -165,12 +228,206 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x49016000,
+		.pa_end		= 0x4901607f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+	.master		= &omap2430_l4_wkup_hwmod,
+	.slave		= &omap2430_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2430_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap2430_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_wd_timer_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap2430_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
+	&omap2430_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2430_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap2430_wd_timer_hwmod_class,
+	.main_clk	= "mpu_wdt_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+		},
+	},
+	.slaves		= omap2430_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
+	&omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2430_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
+	&omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2430_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
+	&omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2430_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 2,
+			.module_bit = OMAP24XX_EN_UART3_SHIFT,
+			.idlest_reg_id = 2,
+			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
 static __initdata struct omap_hwmod *omap2430_hwmods[] = {
 	&omap2430_l3_main_hwmod,
 	&omap2430_l4_core_hwmod,
 	&omap2430_l4_wkup_hwmod,
 	&omap2430_mpu_hwmod,
 	&omap2430_iva_hwmod,
+	&omap2430_wd_timer2_hwmod,
+	&omap2430_uart1_hwmod,
+	&omap2430_uart2_hwmod,
+	&omap2430_uart3_hwmod,
 	NULL,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,10 +17,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
 
 /*
  * OMAP3xxx hardware module integration data
@@ -36,6 +38,7 @@
 static struct omap_hwmod omap3xxx_l3_main_hwmod;
 static struct omap_hwmod omap3xxx_l4_core_hwmod;
 static struct omap_hwmod omap3xxx_l4_per_hwmod;
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -82,6 +85,10 @@
 };
 
 static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_uart1_hwmod;
+static struct omap_hwmod omap3xxx_uart2_hwmod;
+static struct omap_hwmod omap3xxx_uart3_hwmod;
+static struct omap_hwmod omap3xxx_uart4_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
@@ -90,6 +97,78 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART1_BASE,
+		.pa_end		= OMAP3_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap3xxx_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART2_BASE,
+		.pa_end		= OMAP3_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap3xxx_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART3_BASE,
+		.pa_end		= OMAP3_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
+	.master		= &omap3xxx_l4_per_hwmod,
+	.slave		= &omap3xxx_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap3xxx_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART4 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART4_BASE,
+		.pa_end		= OMAP3_UART4_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
+	.master		= &omap3xxx_l4_per_hwmod,
+	.slave		= &omap3xxx_uart4_hwmod,
+	.clk		= "uart4_ick",
+	.addr		= omap3xxx_uart4_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart4_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
 	&omap3xxx_l3_main__l4_core,
@@ -98,6 +177,8 @@
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
 	&omap3xxx_l4_core__l4_wkup,
+	&omap3_l4_core__uart1,
+	&omap3_l4_core__uart2,
 };
 
 /* L4 CORE */
@@ -119,6 +200,8 @@
 
 /* Master interfaces on the L4_PER interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
+	&omap3_l4_per__uart3,
+	&omap3_l4_per__uart4,
 };
 
 /* L4 PER */
@@ -197,6 +280,235 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x48314000,
+		.pa_end		= 0x4831407f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
+	.master		= &omap3xxx_l4_wkup_hwmod,
+	.slave		= &omap3xxx_wd_timer2_hwmod,
+	.clk		= "wdt2_ick",
+	.addr		= omap3xxx_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap3xxx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
+	&omap3xxx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap3xxx_wd_timer_hwmod_class,
+	.main_clk	= "wdt2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_WDT2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART common */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
+	&omap3_l4_core__uart1,
+};
+
+static struct omap_hwmod omap3xxx_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
+	&omap3_l4_core__uart2,
+};
+
+static struct omap_hwmod omap3xxx_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
+	&omap3_l4_per__uart3,
+};
+
+static struct omap_hwmod omap3xxx_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART4 */
+
+static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
+	{ .irq = INT_36XX_UART4_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP36XX_DMA_UART4_RX, },
+	{ .name = "tx",	.dma_req = OMAP36XX_DMA_UART4_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
+	&omap3_l4_per__uart4,
+};
+
+static struct omap_hwmod omap3xxx_uart4_hwmod = {
+	.name		= "uart4",
+	.mpu_irqs	= uart4_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart4_mpu_irqs),
+	.sdma_reqs	= uart4_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart4_sdma_reqs),
+	.main_clk	= "uart4_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3630_EN_UART4_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart4_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart4_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l3_main_hwmod,
 	&omap3xxx_l4_core_hwmod,
@@ -204,6 +516,11 @@
 	&omap3xxx_l4_wkup_hwmod,
 	&omap3xxx_mpu_hwmod,
 	&omap3xxx_iva_hwmod,
+	&omap3xxx_wd_timer2_hwmod,
+	&omap3xxx_uart1_hwmod,
+	&omap3xxx_uart2_hwmod,
+	&omap3xxx_uart3_hwmod,
+	&omap3xxx_uart4_hwmod,
 	NULL,
 };
 
@@ -211,5 +528,3 @@
 {
 	return omap_hwmod_init(omap3xxx_hwmods);
 }
-
-
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_44xx_data.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod_44xx_data.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod_44xx_data.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,850 @@
+/*
+ * Hardware modules present on the OMAP44xx chips
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Paul Walmsley
+ * Benoit Cousson
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/cpu.h>
+
+#include "omap_hwmod_common_data.h"
+
+#include "cm.h"
+#include "prm-regbits-44xx.h"
+
+/* Base offset for all OMAP4 interrupts external to MPUSS */
+#define OMAP44XX_IRQ_GIC_START	32
+
+/* Base offset for all OMAP4 dma requests */
+#define OMAP44XX_DMA_REQ_START  1
+
+/* Backward references (IPs with Bus Master capability) */
+static struct omap_hwmod omap44xx_dmm_hwmod;
+static struct omap_hwmod omap44xx_emif_fw_hwmod;
+static struct omap_hwmod omap44xx_l3_instr_hwmod;
+static struct omap_hwmod omap44xx_l3_main_1_hwmod;
+static struct omap_hwmod omap44xx_l3_main_2_hwmod;
+static struct omap_hwmod omap44xx_l3_main_3_hwmod;
+static struct omap_hwmod omap44xx_l4_abe_hwmod;
+static struct omap_hwmod omap44xx_l4_cfg_hwmod;
+static struct omap_hwmod omap44xx_l4_per_hwmod;
+static struct omap_hwmod omap44xx_l4_wkup_hwmod;
+static struct omap_hwmod omap44xx_mpu_hwmod;
+static struct omap_hwmod omap44xx_mpu_private_hwmod;
+
+/*
+ * Interconnects omap_hwmod structures
+ * hwmods that compose the global OMAP interconnect
+ */
+
+/*
+ * 'dmm' class
+ * instance(s): dmm
+ */
+static struct omap_hwmod_class omap44xx_dmm_hwmod_class = {
+	.name = "dmm",
+};
+
+/* dmm interface data */
+/* l3_main_1 -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
+	.master		= &omap44xx_l3_main_1_hwmod,
+	.slave		= &omap44xx_dmm_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = {
+	.master		= &omap44xx_mpu_hwmod,
+	.slave		= &omap44xx_dmm_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dmm slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
+	&omap44xx_l3_main_1__dmm,
+	&omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod_irq_info omap44xx_dmm_irqs[] = {
+	{ .irq = 113 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod omap44xx_dmm_hwmod = {
+	.name		= "dmm",
+	.class		= &omap44xx_dmm_hwmod_class,
+	.slaves		= omap44xx_dmm_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_dmm_slaves),
+	.mpu_irqs	= omap44xx_dmm_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_dmm_irqs),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'emif_fw' class
+ * instance(s): emif_fw
+ */
+static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
+	.name = "emif_fw",
+};
+
+/* emif_fw interface data */
+/* dmm -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
+	.master		= &omap44xx_dmm_hwmod,
+	.slave		= &omap44xx_emif_fw_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__emif_fw = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_emif_fw_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* emif_fw slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
+	&omap44xx_dmm__emif_fw,
+	&omap44xx_l4_cfg__emif_fw,
+};
+
+static struct omap_hwmod omap44xx_emif_fw_hwmod = {
+	.name		= "emif_fw",
+	.class		= &omap44xx_emif_fw_hwmod_class,
+	.slaves		= omap44xx_emif_fw_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_emif_fw_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l3' class
+ * instance(s): l3_instr, l3_main_1, l3_main_2, l3_main_3
+ */
+static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
+	.name = "l3",
+};
+
+/* l3_instr interface data */
+/* l3_main_3 -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = {
+	.master		= &omap44xx_l3_main_3_hwmod,
+	.slave		= &omap44xx_l3_instr_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_instr slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
+	&omap44xx_l3_main_3__l3_instr,
+};
+
+static struct omap_hwmod omap44xx_l3_instr_hwmod = {
+	.name		= "l3_instr",
+	.class		= &omap44xx_l3_hwmod_class,
+	.slaves		= omap44xx_l3_instr_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_instr_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_l3_main_1_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_l3_main_1_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
+	.master		= &omap44xx_mpu_hwmod,
+	.slave		= &omap44xx_l3_main_1_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
+	&omap44xx_l3_main_2__l3_main_1,
+	&omap44xx_l4_cfg__l3_main_1,
+	&omap44xx_mpu__l3_main_1,
+};
+
+static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
+	.name		= "l3_main_1",
+	.class		= &omap44xx_l3_hwmod_class,
+	.slaves		= omap44xx_l3_main_1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_1_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_2 interface data */
+/* l3_main_1 -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
+	.master		= &omap44xx_l3_main_1_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_l3_main_2_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
+	&omap44xx_l3_main_1__l3_main_2,
+	&omap44xx_l4_cfg__l3_main_2,
+};
+
+static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
+	.name		= "l3_main_2",
+	.class		= &omap44xx_l3_hwmod_class,
+	.slaves		= omap44xx_l3_main_2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l3_main_3 interface data */
+/* l3_main_1 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
+	.master		= &omap44xx_l3_main_1_hwmod,
+	.slave		= &omap44xx_l3_main_3_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_l3_main_3_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_l3_main_3_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
+	&omap44xx_l3_main_1__l3_main_3,
+	&omap44xx_l3_main_2__l3_main_3,
+	&omap44xx_l4_cfg__l3_main_3,
+};
+
+static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
+	.name		= "l3_main_3",
+	.class		= &omap44xx_l3_hwmod_class,
+	.slaves		= omap44xx_l3_main_3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l3_main_3_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_abe, l4_cfg, l4_per, l4_wkup
+ */
+static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
+	.name = "l4",
+};
+
+/* l4_abe interface data */
+/* l3_main_1 -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
+	.master		= &omap44xx_l3_main_1_hwmod,
+	.slave		= &omap44xx_l4_abe_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
+	.master		= &omap44xx_mpu_hwmod,
+	.slave		= &omap44xx_l4_abe_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_abe slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
+	&omap44xx_l3_main_1__l4_abe,
+	&omap44xx_mpu__l4_abe,
+};
+
+static struct omap_hwmod omap44xx_l4_abe_hwmod = {
+	.name		= "l4_abe",
+	.class		= &omap44xx_l4_hwmod_class,
+	.slaves		= omap44xx_l4_abe_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_abe_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_cfg interface data */
+/* l3_main_1 -> l4_cfg */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
+	.master		= &omap44xx_l3_main_1_hwmod,
+	.slave		= &omap44xx_l4_cfg_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
+	&omap44xx_l3_main_1__l4_cfg,
+};
+
+static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
+	.name		= "l4_cfg",
+	.class		= &omap44xx_l4_hwmod_class,
+	.slaves		= omap44xx_l4_cfg_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_cfg_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per interface data */
+/* l3_main_2 -> l4_per */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
+	.master		= &omap44xx_l3_main_2_hwmod,
+	.slave		= &omap44xx_l4_per_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
+	&omap44xx_l3_main_2__l4_per,
+};
+
+static struct omap_hwmod omap44xx_l4_per_hwmod = {
+	.name		= "l4_per",
+	.class		= &omap44xx_l4_hwmod_class,
+	.slaves		= omap44xx_l4_per_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_per_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_wkup interface data */
+/* l4_cfg -> l4_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
+	.master		= &omap44xx_l4_cfg_hwmod,
+	.slave		= &omap44xx_l4_wkup_hwmod,
+	.clk		= "l4_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
+	&omap44xx_l4_cfg__l4_wkup,
+};
+
+static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
+	.name		= "l4_wkup",
+	.class		= &omap44xx_l4_hwmod_class,
+	.slaves		= omap44xx_l4_wkup_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_l4_wkup_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu_bus' class
+ * instance(s): mpu_private
+ */
+static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
+	.name = "mpu_bus",
+};
+
+/* mpu_private interface data */
+/* mpu -> mpu_private */
+static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
+	.master		= &omap44xx_mpu_hwmod,
+	.slave		= &omap44xx_mpu_private_hwmod,
+	.clk		= "l3_div_ck",
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu_private slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
+	&omap44xx_mpu__mpu_private,
+};
+
+static struct omap_hwmod omap44xx_mpu_private_hwmod = {
+	.name		= "mpu_private",
+	.class		= &omap44xx_mpu_bus_hwmod_class,
+	.slaves		= omap44xx_mpu_private_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_mpu_private_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'mpu' class
+ * mpu sub-system
+ */
+
+static struct omap_hwmod_class omap44xx_mpu_hwmod_class = {
+	.name = "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
+	{ .name = "pl310", .irq = 0 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "cti0", .irq = 1 + OMAP44XX_IRQ_GIC_START },
+	{ .name = "cti1", .irq = 2 + OMAP44XX_IRQ_GIC_START },
+};
+
+/* mpu master ports */
+static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
+	&omap44xx_mpu__l3_main_1,
+	&omap44xx_mpu__l4_abe,
+	&omap44xx_mpu__dmm,
+};
+
+static struct omap_hwmod omap44xx_mpu_hwmod = {
+	.name		= "mpu",
+	.class		= &omap44xx_mpu_hwmod_class,
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= omap44xx_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_mpu_irqs),
+	.main_clk	= "dpll_mpu_m2_ck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL,
+		},
+	},
+	.masters	= omap44xx_mpu_masters,
+	.masters_cnt	= ARRAY_SIZE(omap44xx_mpu_masters),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+/*
+ * 'uart' class
+ * universal asynchronous receiver/transmitter (uart)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
+	.rev_offs	= 0x0050,
+	.sysc_offs	= 0x0054,
+	.syss_offs	= 0x0058,
+	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap44xx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod omap44xx_wd_timer2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
+	{ .irq = 80 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x4a314000,
+		.pa_end		= 0x4a31407f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
+	.name = "uart",
+	.sysc = &omap44xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod omap44xx_uart1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
+	{ .irq = 72 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
+	{
+		.pa_start	= 0x4806a000,
+		.pa_end		= 0x4806a0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart1_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart1_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart1_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
+	&omap44xx_l4_per__uart1,
+};
+
+static struct omap_hwmod omap44xx_uart1_hwmod = {
+	.name		= "uart1",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart1_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart1_irqs),
+	.sdma_reqs	= omap44xx_uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart1_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart2 */
+static struct omap_hwmod omap44xx_uart2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
+	{ .irq = 73 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
+	{
+		.pa_start	= 0x4806c000,
+		.pa_end		= 0x4806c0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_wd_timer2_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* wd_timer2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
+	&omap44xx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.mpu_irqs	= omap44xx_wd_timer2_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_irqs),
+	.main_clk	= "wd_timer2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* wd_timer3 */
+static struct omap_hwmod omap44xx_wd_timer3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
+	{ .irq = 36 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+	{
+		.pa_start	= 0x40130000,
+		.pa_end		= 0x4013007f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart2_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
+	&omap44xx_l4_per__uart2,
+};
+
+static struct omap_hwmod omap44xx_uart2_hwmod = {
+	.name		= "uart2",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart2_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart2_irqs),
+	.sdma_reqs	= omap44xx_uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart3 */
+static struct omap_hwmod omap44xx_uart3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
+	{ .irq = 74 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
+	{
+		.pa_start	= 0x48020000,
+		.pa_end		= 0x480200ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_abe -> wd_timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_wd_timer3_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_wd_timer3_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_addrs),
+	.user		= OCP_USER_MPU,
+};
+
+/* l4_abe -> wd_timer3 (dma) */
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+	{
+		.pa_start	= 0x49030000,
+		.pa_end		= 0x4903007f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart3_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart3_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart3_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
+	&omap44xx_l4_per__uart3,
+};
+
+static struct omap_hwmod omap44xx_uart3_hwmod = {
+	.name		= "uart3",
+	.class		= &omap44xx_uart_hwmod_class,
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= omap44xx_uart3_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart3_irqs),
+	.sdma_reqs	= omap44xx_uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart3_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart4 */
+static struct omap_hwmod omap44xx_uart4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
+	{ .irq = 70 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
+	{
+		.pa_start	= 0x4806e000,
+		.pa_end		= 0x4806e0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_wd_timer3_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_wd_timer3_dma_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_dma_addrs),
+	.user		= OCP_USER_SDMA,
+};
+
+/* wd_timer3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
+	&omap44xx_l4_abe__wd_timer3,
+	&omap44xx_l4_abe__wd_timer3_dma,
+};
+
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+	.name		= "wd_timer3",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.mpu_irqs	= omap44xx_wd_timer3_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_irqs),
+	.main_clk	= "wd_timer3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_wd_timer3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per -> uart4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart4_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart4_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart4_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
+	&omap44xx_l4_per__uart4,
+};
+
+static struct omap_hwmod omap44xx_uart4_hwmod = {
+	.name		= "uart4",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart4_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart4_irqs),
+	.sdma_reqs	= omap44xx_uart4_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart4_sdma_reqs),
+	.main_clk	= "uart4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart4_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart4_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
+	/* dmm class */
+	&omap44xx_dmm_hwmod,
+	/* emif_fw class */
+	&omap44xx_emif_fw_hwmod,
+	/* l3 class */
+	&omap44xx_l3_instr_hwmod,
+	&omap44xx_l3_main_1_hwmod,
+	&omap44xx_l3_main_2_hwmod,
+	&omap44xx_l3_main_3_hwmod,
+	/* l4 class */
+	&omap44xx_l4_abe_hwmod,
+	&omap44xx_l4_cfg_hwmod,
+	&omap44xx_l4_per_hwmod,
+	&omap44xx_l4_wkup_hwmod,
+	/* mpu_bus class */
+	&omap44xx_mpu_private_hwmod,
+
+	/* mpu class */
+	&omap44xx_mpu_hwmod,
+	/* wd_timer class */
+	&omap44xx_wd_timer2_hwmod,
+	&omap44xx_wd_timer3_hwmod,
+
+	/* uart class */
+	&omap44xx_uart1_hwmod,
+	&omap44xx_uart2_hwmod,
+	&omap44xx_uart3_hwmod,
+	&omap44xx_uart4_hwmod,
+	NULL,
+};
+
+int __init omap44xx_hwmod_init(void)
+{
+	return omap_hwmod_init(omap44xx_hwmods);
+}
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/omap_hwmod.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/omap_hwmod.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,10 +13,102 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * This code manages "OMAP modules" (on-chip devices) and their
- * integration with Linux device driver and bus code.
+ * Introduction
+ * ------------
+ * One way to view an OMAP SoC is as a collection of largely unrelated
+ * IP blocks connected by interconnects.  The IP blocks include
+ * devices such as ARM processors, audio serial interfaces, UARTs,
+ * etc.  Some of these devices, like the DSP, are created by TI;
+ * others, like the SGX, largely originate from external vendors.  In
+ * TI's documentation, on-chip devices are referred to as "OMAP
+ * modules."  Some of these IP blocks are identical across several
+ * OMAP versions.  Others are revised frequently.
  *
- * References:
+ * These OMAP modules are tied together by various interconnects.
+ * Most of the address and data flow between modules is via OCP-based
+ * interconnects such as the L3 and L4 buses; but there are other
+ * interconnects that distribute the hardware clock tree, handle idle
+ * and reset signaling, supply power, and connect the modules to
+ * various pads or balls on the OMAP package.
+ *
+ * OMAP hwmod provides a consistent way to describe the on-chip
+ * hardware blocks and their integration into the rest of the chip.
+ * This description can be automatically generated from the TI
+ * hardware database.  OMAP hwmod provides a standard, consistent API
+ * to reset, enable, idle, and disable these hardware blocks.  And
+ * hwmod provides a way for other core code, such as the Linux device
+ * code or the OMAP power management and address space mapping code,
+ * to query the hardware database.
+ *
+ * Using hwmod
+ * -----------
+ * Drivers won't call hwmod functions directly.  That is done by the
+ * omap_device code, and in rare occasions, by custom integration code
+ * in arch/arm/ *omap*.  The omap_device code includes functions to
+ * build a struct platform_device using omap_hwmod data, and that is
+ * currently how hwmod data is communicated to drivers and to the
+ * Linux driver model.  Most drivers will call omap_hwmod functions only
+ * indirectly, via pm_runtime*() functions.
+ *
+ * From a layering perspective, here is where the OMAP hwmod code
+ * fits into the kernel software stack:
+ *
+ *            +-------------------------------+
+ *            |      Device driver code       |
+ *            |      (e.g., drivers/)         |
+ *            +-------------------------------+
+ *            |      Linux driver model       |
+ *            |     (platform_device /        |
+ *            |  platform_driver data/code)   |
+ *            +-------------------------------+
+ *            | OMAP core-driver integration  |
+ *            |(arch/arm/mach-omap2/devices.c)|
+ *            +-------------------------------+
+ *            |      omap_device code         |
+ *            | (../plat-omap/omap_device.c)  |
+ *            +-------------------------------+
+ *   ---->    |    omap_hwmod code/data       |    <-----
+ *            | (../mach-omap2/omap_hwmod*)   |
+ *            +-------------------------------+
+ *            | OMAP clock/PRCM/register fns  |
+ *            | (__raw_{read,write}l, clk*)   |
+ *            +-------------------------------+
+ *
+ * Device drivers should not contain any OMAP-specific code or data in
+ * them.  They should only contain code to operate the IP block that
+ * the driver is responsible for.  This is because these IP blocks can
+ * also appear in other SoCs, either from TI (such as DaVinci) or from
+ * other manufacturers; and drivers should be reusable across other
+ * platforms.
+ *
+ * The OMAP hwmod code also will attempt to reset and idle all on-chip
+ * devices upon boot.  The goal here is for the kernel to be
+ * completely self-reliant and independent from bootloaders.  This is
+ * to ensure a repeatable configuration, both to ensure consistent
+ * runtime behavior, and to make it easier for others to reproduce
+ * bugs.
+ *
+ * OMAP module activity states
+ * ---------------------------
+ * The hwmod code considers modules to be in one of several activity
+ * states.  IP blocks start out in an UNKNOWN state, then once they
+ * are registered via the hwmod code, proceed to the REGISTERED state.
+ * Once their clock names are resolved to clock pointers, the module
+ * enters the CLKS_INITED state; and finally, once the module has been
+ * reset and the integration registers programmed, the INITIALIZED state
+ * is entered.  The hwmod code will then place the module into either
+ * the IDLE state to save power, or in the case of a critical system
+ * module, the ENABLED state.
+ *
+ * OMAP core integration code can then call omap_hwmod*() functions
+ * directly to move the module between the IDLE, ENABLED, and DISABLED
+ * states, as needed.  This is done during both the PM idle loop, and
+ * in the OMAP core integration code's implementation of the PM runtime
+ * functions.
+ *
+ * References
+ * ----------
+ * This is a partial list.
  * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
  * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
  * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
@@ -50,11 +142,13 @@
 #include <plat/powerdomain.h>
 #include <plat/clock.h>
 #include <plat/omap_hwmod.h>
+#include <plat/prcm.h>
 
 #include "cm.h"
+#include "prm.h"
 
-/* Maximum microseconds to wait for OMAP module to reset */
-#define MAX_MODULE_RESET_WAIT		10000
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT	10000
 
 /* Name of the OMAP hwmod for the MPU */
 #define MPU_INITIATOR_NAME		"mpu"
@@ -90,7 +184,7 @@
 
 	/* XXX ensure module interface clock is up */
 
-	oh->_sysc_cache = omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+	oh->_sysc_cache = omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
 
 	if (!(oh->class->sysc->sysc_flags & SYSC_NO_CACHE))
 		oh->_int_flags |= _HWMOD_SYSCONFIG_LOADED;
@@ -117,7 +211,7 @@
 
 	if (oh->_sysc_cache != v) {
 		oh->_sysc_cache = v;
-		omap_hwmod_writel(v, oh, oh->class->sysc->sysc_offs);
+		omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs);
 	}
 }
 
@@ -544,6 +638,36 @@
 	return 0;
 }
 
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+	struct omap_hwmod_opt_clk *oc;
+	int i;
+
+	pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
+
+	for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+		if (oc->_clk) {
+			pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
+				 oc->_clk->name);
+			clk_enable(oc->_clk);
+		}
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+	struct omap_hwmod_opt_clk *oc;
+	int i;
+
+	pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
+
+	for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+		if (oc->_clk) {
+			pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
+				 oc->_clk->name);
+			clk_disable(oc->_clk);
+		}
+}
+
 /**
  * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
  * @oh: struct omap_hwmod *
@@ -622,7 +746,7 @@
 }
 
 /**
- * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG
+ * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * If module is marked as SWSUP_SIDLE, force the module out of slave
@@ -630,7 +754,7 @@
  * as SWSUP_MSUSPEND, force the module out of master standby;
  * otherwise, configure it for smart-standby.  No return value.
  */
-static void _sysc_enable(struct omap_hwmod *oh)
+static void _enable_sysc(struct omap_hwmod *oh)
 {
 	u8 idlemode, sf;
 	u32 v;
@@ -653,14 +777,6 @@
 		_set_master_standbymode(oh, idlemode, &v);
 	}
 
-	if (sf & SYSC_HAS_AUTOIDLE) {
-		idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
-			0 : 1;
-		_set_module_autoidle(oh, idlemode, &v);
-	}
-
-	/* XXX OCP ENAWAKEUP bit? */
-
 	/*
 	 * XXX The clock framework should handle this, by
 	 * calling into this code.  But this must wait until the
@@ -671,10 +787,25 @@
 		_set_clockactivity(oh, oh->class->sysc->clockact, &v);
 
 	_write_sysconfig(v, oh);
+
+	/* If slave is in SMARTIDLE, also enable wakeup */
+	if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE))
+		_enable_wakeup(oh);
+
+	/*
+	 * Set the autoidle bit only after setting the smartidle bit
+	 * Setting this will not have any impact on the other modules.
+	 */
+	if (sf & SYSC_HAS_AUTOIDLE) {
+		idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ?
+			0 : 1;
+		_set_module_autoidle(oh, idlemode, &v);
+		_write_sysconfig(v, oh);
+	}
 }
 
 /**
- * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG
+ * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * If module is marked as SWSUP_SIDLE, force the module into slave
@@ -682,7 +813,7 @@
  * as SWSUP_MSUSPEND, force the module into master standby; otherwise,
  * configure it for smart-standby.  No return value.
  */
-static void _sysc_idle(struct omap_hwmod *oh)
+static void _idle_sysc(struct omap_hwmod *oh)
 {
 	u8 idlemode, sf;
 	u32 v;
@@ -709,13 +840,13 @@
 }
 
 /**
- * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG
+ * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG
  * @oh: struct omap_hwmod *
  *
  * Force the module into slave idle and master suspend. No return
  * value.
  */
-static void _sysc_shutdown(struct omap_hwmod *oh)
+static void _shutdown_sysc(struct omap_hwmod *oh)
 {
 	u32 v;
 	u8 sf;
@@ -767,10 +898,10 @@
  * @data: not used; pass NULL
  *
  * Called by omap_hwmod_late_init() (after omap2_clk_init()).
- * Resolves all clock names embedded in the hwmod.  Must be called
- * with omap_hwmod_mutex held.  Returns -EINVAL if the omap_hwmod
- * has not yet been registered or if the clocks have already been
- * initialized, 0 on success, or a non-zero error on failure.
+ * Resolves all clock names embedded in the hwmod.  Returns -EINVAL if
+ * the omap_hwmod has not yet been registered or if the clocks have
+ * already been initialized, 0 on success, or a non-zero error on
+ * failure.
  */
 static int _init_clocks(struct omap_hwmod *oh, void *data)
 {
@@ -834,56 +965,202 @@
 }
 
 /**
+ * _lookup_hardreset - return the register bit shift for this hwmod/reset line
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line in the context of this hwmod
+ *
+ * Return the bit position of the reset line that match the
+ * input name. Return -ENOENT if not found.
+ */
+static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	int i;
+
+	for (i = 0; i < oh->rst_lines_cnt; i++) {
+		const char *rst_line = oh->rst_lines[i].name;
+		if (!strcmp(rst_line, name)) {
+			u8 shift = oh->rst_lines[i].rst_shift;
+			pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n",
+				 oh->name, rst_line, shift);
+
+			return shift;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/**
+ * _assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	u8 shift;
+
+	if (!oh)
+		return -EINVAL;
+
+	shift = _lookup_hardreset(oh, name);
+	if (IS_ERR_VALUE(shift))
+		return shift;
+
+	if (cpu_is_omap24xx() || cpu_is_omap34xx())
+		return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
+						  shift);
+	else if (cpu_is_omap44xx())
+		return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg,
+						  shift);
+	else
+		return -EINVAL;
+}
+
+/**
+ * _deassert_hardreset - deassert the HW reset line of submodules contained
+ * in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.
+ */
+static int _deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	u8 shift;
+	int r;
+
+	if (!oh)
+		return -EINVAL;
+
+	shift = _lookup_hardreset(oh, name);
+	if (IS_ERR_VALUE(shift))
+		return shift;
+
+	if (cpu_is_omap24xx() || cpu_is_omap34xx())
+		r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
+						 shift);
+	else if (cpu_is_omap44xx())
+		r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg,
+						 shift);
+	else
+		return -EINVAL;
+
+	if (r == -EBUSY)
+		pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name);
+
+	return r;
+}
+
+/**
+ * _read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the state of the reset line.
+ */
+static int _read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	u8 shift;
+
+	if (!oh)
+		return -EINVAL;
+
+	shift = _lookup_hardreset(oh, name);
+	if (IS_ERR_VALUE(shift))
+		return shift;
+
+	if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+		return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
+						       shift);
+	} else if (cpu_is_omap44xx()) {
+		return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg,
+						       shift);
+	} else {
+		return -EINVAL;
+	}
+}
+
+/**
  * _reset - reset an omap_hwmod
  * @oh: struct omap_hwmod *
  *
  * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit.  hwmod must be
- * enabled for this to work.  Must be called with omap_hwmod_mutex
- * held.  Returns -EINVAL if the hwmod cannot be reset this way or if
- * the hwmod is in the wrong state, -ETIMEDOUT if the module did not
- * reset in time, or 0 upon success.
+ * enabled for this to work.  Returns -EINVAL if the hwmod cannot be
+ * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
+ * the module did not reset in time, or 0 upon success.
+ *
+ * In OMAP3 a specific SYSSTATUS register is used to get the reset status.
+ * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead
+ * use the SYSCONFIG softreset bit to provide the status.
+ *
+ * Note that some IP like McBSP does have a reset control but no reset status.
  */
 static int _reset(struct omap_hwmod *oh)
 {
-	u32 r, v;
+	u32 v;
 	int c = 0;
+	int ret = 0;
 
 	if (!oh->class->sysc ||
-	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET) ||
-	    (oh->class->sysc->sysc_flags & SYSS_MISSING))
+	    !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
 		return -EINVAL;
 
 	/* clocks must be on for this operation */
 	if (oh->_state != _HWMOD_STATE_ENABLED) {
-		WARN(1, "omap_hwmod: %s: reset can only be entered from "
-		     "enabled state\n", oh->name);
+		pr_warning("omap_hwmod: %s: reset can only be entered from "
+			   "enabled state\n", oh->name);
 		return -EINVAL;
 	}
 
+	/* For some modules, all optionnal clocks need to be enabled as well */
+	if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+		_enable_optional_clocks(oh);
+
 	pr_debug("omap_hwmod: %s: resetting\n", oh->name);
 
 	v = oh->_sysc_cache;
-	r = _set_softreset(oh, &v);
-	if (r)
-		return r;
+	ret = _set_softreset(oh, &v);
+	if (ret)
+		goto dis_opt_clks;
 	_write_sysconfig(v, oh);
 
-	omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) &
-			   SYSS_RESETDONE_MASK),
-			  MAX_MODULE_RESET_WAIT, c);
+	if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
+		omap_test_timeout((omap_hwmod_read(oh,
+						    oh->class->sysc->syss_offs)
+				   & SYSS_RESETDONE_MASK),
+				  MAX_MODULE_SOFTRESET_WAIT, c);
+	else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS)
+		omap_test_timeout(!(omap_hwmod_read(oh,
+						     oh->class->sysc->sysc_offs)
+				   & SYSC_TYPE2_SOFTRESET_MASK),
+				  MAX_MODULE_SOFTRESET_WAIT, c);
 
-	if (c == MAX_MODULE_RESET_WAIT)
-		WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n",
-		     oh->name, MAX_MODULE_RESET_WAIT);
+	if (c == MAX_MODULE_SOFTRESET_WAIT)
+		pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
+			   oh->name, MAX_MODULE_SOFTRESET_WAIT);
 	else
-		pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c);
+		pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
 
 	/*
 	 * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
 	 * _wait_target_ready() or _reset()
 	 */
 
-	return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0;
+	ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
+
+dis_opt_clks:
+	if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+		_disable_optional_clocks(oh);
+
+	return ret;
 }
 
 /**
@@ -891,9 +1168,11 @@
  * @oh: struct omap_hwmod *
  *
  * Enables an omap_hwmod @oh such that the MPU can access the hwmod's
- * register target.  Must be called with omap_hwmod_mutex held.
- * Returns -EINVAL if the hwmod is in the wrong state or passes along
- * the return value of _wait_target_ready().
+ * register target.  (This function has a full name --
+ * _omap_hwmod_enable() rather than simply _enable() -- because it is
+ * currently required by the pm34xx.c idle loop.)  Returns -EINVAL if
+ * the hwmod is in the wrong state or passes along the return value of
+ * _wait_target_ready().
  */
 int _omap_hwmod_enable(struct omap_hwmod *oh)
 {
@@ -909,6 +1188,15 @@
 
 	pr_debug("omap_hwmod: %s: enabling\n", oh->name);
 
+	/*
+	 * If an IP contains only one HW reset line, then de-assert it in order
+	 * to allow to enable the clocks. Otherwise the PRCM will return
+	 * Intransition status, and the init will failed.
+	 */
+	if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
+	     oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
+		_deassert_hardreset(oh, oh->rst_lines[0].name);
+
 	/* XXX mux balls */
 
 	_add_initiator_dep(oh, mpu_oh);
@@ -922,7 +1210,7 @@
 		if (oh->class->sysc) {
 			if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
 				_update_sysc_cache(oh);
-			_sysc_enable(oh);
+			_enable_sysc(oh);
 		}
 	} else {
 		pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
@@ -933,12 +1221,14 @@
 }
 
 /**
- * _idle - idle an omap_hwmod
+ * _omap_hwmod_idle - idle an omap_hwmod
  * @oh: struct omap_hwmod *
  *
  * Idles an omap_hwmod @oh.  This should be called once the hwmod has
- * no further work.  Returns -EINVAL if the hwmod is in the wrong
- * state or returns 0.
+ * no further work.  (This function has a full name --
+ * _omap_hwmod_idle() rather than simply _idle() -- because it is
+ * currently required by the pm34xx.c idle loop.)  Returns -EINVAL if
+ * the hwmod is in the wrong state or returns 0.
  */
 int _omap_hwmod_idle(struct omap_hwmod *oh)
 {
@@ -951,7 +1241,7 @@
 	pr_debug("omap_hwmod: %s: idling\n", oh->name);
 
 	if (oh->class->sysc)
-		_sysc_idle(oh);
+		_idle_sysc(oh);
 	_del_initiator_dep(oh, mpu_oh);
 	_disable_clocks(oh);
 
@@ -981,10 +1271,21 @@
 	pr_debug("omap_hwmod: %s: disabling\n", oh->name);
 
 	if (oh->class->sysc)
-		_sysc_shutdown(oh);
-	_del_initiator_dep(oh, mpu_oh);
-	/* XXX what about the other system initiators here? DMA, tesla, d2d */
-	_disable_clocks(oh);
+		_shutdown_sysc(oh);
+
+	/*
+	 * If an IP contains only one HW reset line, then assert it
+	 * before disabling the clocks and shutting down the IP.
+	 */
+	if (oh->rst_lines_cnt == 1)
+		_assert_hardreset(oh, oh->rst_lines[0].name);
+
+	/* clocks and deps are already disabled in idle */
+	if (oh->_state == _HWMOD_STATE_ENABLED) {
+		_del_initiator_dep(oh, mpu_oh);
+		/* XXX what about the other system initiators here? dma, dsp */
+		_disable_clocks(oh);
+	}
 	/* XXX Should this code also force-disable the optional clocks? */
 
 	/* XXX mux any associated balls to safe mode */
@@ -1000,11 +1301,10 @@
  * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1
  *
  * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register.  Must be called with omap_hwmod_mutex held.
- * @skip_setup_idle is intended to be used on a system that will not
- * call omap_hwmod_enable() to enable devices (e.g., a system without
- * PM runtime).  Returns -EINVAL if the hwmod is in the wrong state or
- * returns 0.
+ * OCP_SYSCONFIG register.  @skip_setup_idle is intended to be used on
+ * a system that will not call omap_hwmod_enable() to enable devices
+ * (e.g., a system without PM runtime).  Returns -EINVAL if the hwmod
+ * is in the wrong state or returns 0.
  */
 static int _setup(struct omap_hwmod *oh, void *data)
 {
@@ -1034,8 +1334,19 @@
 		}
 	}
 
+	mutex_init(&oh->_mutex);
 	oh->_state = _HWMOD_STATE_INITIALIZED;
 
+	/*
+	 * In the case of hwmod with hardreset that should not be
+	 * de-assert at boot time, we have to keep the module
+	 * initialized, because we cannot enable it properly with the
+	 * reset asserted. Exit without warning because that behavior is
+	 * expected.
+	 */
+	if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
+		return 0;
+
 	r = _omap_hwmod_enable(oh);
 	if (r) {
 		pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
@@ -1044,16 +1355,16 @@
 	}
 
 	if (!(oh->flags & HWMOD_INIT_NO_RESET)) {
+		_reset(oh);
+
 		/*
-		 * XXX Do the OCP_SYSCONFIG bits need to be
-		 * reprogrammed after a reset?  If not, then this can
-		 * be removed.  If they do, then probably the
-		 * _omap_hwmod_enable() function should be split to avoid the
-		 * rewrite of the OCP_SYSCONFIG register.
+		 * OCP_SYSCONFIG bits need to be reprogrammed after a softreset.
+		 * The _omap_hwmod_enable() function should be split to
+		 * avoid the rewrite of the OCP_SYSCONFIG register.
 		 */
 		if (oh->class->sysc) {
 			_update_sysc_cache(oh);
-			_sysc_enable(oh);
+			_enable_sysc(oh);
 		}
 	}
 
@@ -1067,14 +1378,20 @@
 
 /* Public functions */
 
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs)
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
 {
-	return __raw_readl(oh->_mpu_rt_va + reg_offs);
+	if (oh->flags & HWMOD_16BIT_REG)
+		return __raw_readw(oh->_mpu_rt_va + reg_offs);
+	else
+		return __raw_readl(oh->_mpu_rt_va + reg_offs);
 }
 
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs)
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
 {
-	__raw_writel(v, oh->_mpu_rt_va + reg_offs);
+	if (oh->flags & HWMOD_16BIT_REG)
+		__raw_writew(v, oh->_mpu_rt_va + reg_offs);
+	else
+		__raw_writel(v, oh->_mpu_rt_va + reg_offs);
 }
 
 /**
@@ -1309,7 +1626,7 @@
  * omap_hwmod_enable - enable an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Enable an omap_hwomd @oh.  Intended to be called by omap_device_enable().
+ * Enable an omap_hwmod @oh.  Intended to be called by omap_device_enable().
  * Returns -EINVAL on error or passes along the return value from _enable().
  */
 int omap_hwmod_enable(struct omap_hwmod *oh)
@@ -1319,9 +1636,9 @@
 	if (!oh)
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	r = _omap_hwmod_enable(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return r;
 }
@@ -1331,7 +1648,7 @@
  * omap_hwmod_idle - idle an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Idle an omap_hwomd @oh.  Intended to be called by omap_device_idle().
+ * Idle an omap_hwmod @oh.  Intended to be called by omap_device_idle().
  * Returns -EINVAL on error or passes along the return value from _idle().
  */
 int omap_hwmod_idle(struct omap_hwmod *oh)
@@ -1339,9 +1656,9 @@
 	if (!oh)
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_omap_hwmod_idle(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
@@ -1350,7 +1667,7 @@
  * omap_hwmod_shutdown - shutdown an omap_hwmod
  * @oh: struct omap_hwmod *
  *
- * Shutdown an omap_hwomd @oh.  Intended to be called by
+ * Shutdown an omap_hwmod @oh.  Intended to be called by
  * omap_device_shutdown().  Returns -EINVAL on error or passes along
  * the return value from _shutdown().
  */
@@ -1359,9 +1676,9 @@
 	if (!oh)
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_shutdown(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
@@ -1374,9 +1691,9 @@
  */
 int omap_hwmod_enable_clocks(struct omap_hwmod *oh)
 {
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_enable_clocks(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
@@ -1389,9 +1706,9 @@
  */
 int omap_hwmod_disable_clocks(struct omap_hwmod *oh)
 {
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_disable_clocks(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
@@ -1421,7 +1738,7 @@
 	 * Forces posted writes to complete on the OCP thread handling
 	 * register writes
 	 */
-	omap_hwmod_readl(oh, oh->class->sysc->sysc_offs);
+	omap_hwmod_read(oh, oh->class->sysc->sysc_offs);
 }
 
 /**
@@ -1430,20 +1747,18 @@
  *
  * Under some conditions, a driver may wish to reset the entire device.
  * Called from omap_device code.  Returns -EINVAL on error or passes along
- * the return value from _reset()/_enable().
+ * the return value from _reset().
  */
 int omap_hwmod_reset(struct omap_hwmod *oh)
 {
 	int r;
 
-	if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED))
+	if (!oh)
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	r = _reset(oh);
-	if (!r)
-		r = _omap_hwmod_enable(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return r;
 }
@@ -1468,7 +1783,7 @@
 {
 	int ret, i;
 
-	ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt;
+	ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt;
 
 	for (i = 0; i < oh->slaves_cnt; i++)
 		ret += oh->slaves[i]->addr_cnt;
@@ -1501,10 +1816,10 @@
 		r++;
 	}
 
-	for (i = 0; i < oh->sdma_chs_cnt; i++) {
-		(res + r)->name = (oh->sdma_chs + i)->name;
-		(res + r)->start = (oh->sdma_chs + i)->dma_ch;
-		(res + r)->end = (oh->sdma_chs + i)->dma_ch;
+	for (i = 0; i < oh->sdma_reqs_cnt; i++) {
+		(res + r)->name = (oh->sdma_reqs + i)->name;
+		(res + r)->start = (oh->sdma_reqs + i)->dma_req;
+		(res + r)->end = (oh->sdma_reqs + i)->dma_req;
 		(res + r)->flags = IORESOURCE_DMA;
 		r++;
 	}
@@ -1644,9 +1959,9 @@
 	    !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_enable_wakeup(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
@@ -1669,14 +1984,92 @@
 	    !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
 		return -EINVAL;
 
-	mutex_lock(&omap_hwmod_mutex);
+	mutex_lock(&oh->_mutex);
 	_disable_wakeup(oh);
-	mutex_unlock(&omap_hwmod_mutex);
+	mutex_unlock(&oh->_mutex);
 
 	return 0;
 }
 
 /**
+ * omap_hwmod_assert_hardreset - assert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to lookup and assert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.  Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _assert_hardreset().
+ */
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	int ret;
+
+	if (!oh)
+		return -EINVAL;
+
+	mutex_lock(&oh->_mutex);
+	ret = _assert_hardreset(oh, name);
+	mutex_unlock(&oh->_mutex);
+
+	return ret;
+}
+
+/**
+ * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules
+ * contained in the hwmod module.
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and deassert
+ *
+ * Some IP like dsp, ipu or iva contain processor that require
+ * an HW reset line to be assert / deassert in order to enable fully
+ * the IP.  Returns -EINVAL if @oh is null or if the operation is not
+ * yet supported on this OMAP; otherwise, passes along the return value
+ * from _deassert_hardreset().
+ */
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	int ret;
+
+	if (!oh)
+		return -EINVAL;
+
+	mutex_lock(&oh->_mutex);
+	ret = _deassert_hardreset(oh, name);
+	mutex_unlock(&oh->_mutex);
+
+	return ret;
+}
+
+/**
+ * omap_hwmod_read_hardreset - read the HW reset line state of submodules
+ * contained in the hwmod module
+ * @oh: struct omap_hwmod *
+ * @name: name of the reset line to look up and read
+ *
+ * Return the current state of the hwmod @oh's reset line named @name:
+ * returns -EINVAL upon parameter error or if this operation
+ * is unsupported on the current OMAP; otherwise, passes along the return
+ * value from _read_hardreset().
+ */
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name)
+{
+	int ret;
+
+	if (!oh)
+		return -EINVAL;
+
+	mutex_lock(&oh->_mutex);
+	ret = _read_hardreset(oh, name);
+	mutex_unlock(&oh->_mutex);
+
+	return ret;
+}
+
+
+/**
  * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname
  * @classname: struct omap_hwmod_class name to search for
  * @fn: callback function pointer to call for each hwmod in class @classname
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm24xx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm24xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm24xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm24xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/irq.h>
 #include <linux/time.h>
 #include <linux/gpio.h>
+#include <linux/console.h>
 
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
@@ -38,7 +39,6 @@
 #include <mach/irqs.h>
 #include <plat/clock.h>
 #include <plat/sram.h>
-#include <plat/control.h>
 #include <plat/dma.h>
 #include <plat/board.h>
 
@@ -48,10 +48,24 @@
 #include "cm-regbits-24xx.h"
 #include "sdrc.h"
 #include "pm.h"
+#include "control.h"
 
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
 
+#ifdef CONFIG_SUSPEND
+static suspend_state_t suspend_state = PM_SUSPEND_ON;
+static inline bool is_suspending(void)
+{
+	return (suspend_state != PM_SUSPEND_ON);
+}
+#else
+static inline bool is_suspending(void)
+{
+	return false;
+}
+#endif
+
 static void (*omap2_sram_idle)(void);
 static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
 				  void __iomem *sdrc_power);
@@ -118,6 +132,11 @@
 	if (omap_irq_pending())
 		goto no_sleep;
 
+	/* Block console output in case it is on one of the OMAP UARTs */
+	if (!is_suspending())
+		if (try_acquire_console_sem())
+			goto no_sleep;
+
 	omap_uart_prepare_idle(0);
 	omap_uart_prepare_idle(1);
 	omap_uart_prepare_idle(2);
@@ -131,6 +150,9 @@
 	omap_uart_resume_idle(1);
 	omap_uart_resume_idle(0);
 
+	if (!is_suspending())
+		release_console_sem();
+
 no_sleep:
 	if (omap2_pm_debug) {
 		unsigned long long tmp;
@@ -245,6 +267,8 @@
 {
 	if (omap2_fclks_active())
 		return 0;
+	if (!omap_uart_can_sleep())
+		return 0;
 	if (osc_ck->usecount > 1)
 		return 0;
 	if (omap_dma_running())
@@ -275,6 +299,12 @@
 	local_irq_enable();
 }
 
+static int omap2_pm_begin(suspend_state_t state)
+{
+	suspend_state = state;
+	return 0;
+}
+
 static int omap2_pm_prepare(void)
 {
 	/* We cannot sleep in idle until we have resumed */
@@ -324,10 +354,17 @@
 	enable_hlt();
 }
 
+static void omap2_pm_end(void)
+{
+	suspend_state = PM_SUSPEND_ON;
+}
+
 static struct platform_suspend_ops omap_pm_ops = {
+	.begin		= omap2_pm_begin,
 	.prepare	= omap2_pm_prepare,
 	.enter		= omap2_pm_enter,
 	.finish		= omap2_pm_finish,
+	.end		= omap2_pm_end,
 	.valid		= suspend_valid_only_mem,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm34xx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm34xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm34xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm34xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,17 +28,16 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/console.h>
 
 #include <plat/sram.h>
 #include <plat/clockdomain.h>
 #include <plat/powerdomain.h>
-#include <plat/control.h>
 #include <plat/serial.h>
 #include <plat/sdrc.h>
 #include <plat/prcm.h>
 #include <plat/gpmc.h>
 #include <plat/dma.h>
-#include <plat/dmtimer.h>
 
 #include <asm/tlbflush.h>
 
@@ -49,16 +48,25 @@
 #include "prm.h"
 #include "pm.h"
 #include "sdrc.h"
+#include "control.h"
 
-/* Scratchpad offsets */
-#define OMAP343X_TABLE_ADDRESS_OFFSET	   0x31
-#define OMAP343X_TABLE_VALUE_OFFSET	   0x30
-#define OMAP343X_CONTROL_REG_VALUE_OFFSET  0x32
+#ifdef CONFIG_SUSPEND
+static suspend_state_t suspend_state = PM_SUSPEND_ON;
+static inline bool is_suspending(void)
+{
+	return (suspend_state != PM_SUSPEND_ON);
+}
+#else
+static inline bool is_suspending(void)
+{
+	return false;
+}
+#endif
 
-u32 enable_off_mode;
-u32 sleep_while_idle;
-u32 wakeup_timer_seconds;
-u32 wakeup_timer_milliseconds;
+/* Scratchpad offsets */
+#define OMAP343X_TABLE_ADDRESS_OFFSET	   0xc4
+#define OMAP343X_TABLE_VALUE_OFFSET	   0xc0
+#define OMAP343X_CONTROL_REG_VALUE_OFFSET  0xc8
 
 struct power_state {
 	struct powerdomain *pwrdm;
@@ -316,7 +324,7 @@
 /* Function to restore the table entry that was modified for enabling MMU */
 static void restore_table_entry(void)
 {
-	u32 *scratchpad_address;
+	void __iomem *scratchpad_address;
 	u32 previous_value, control_reg_value;
 	u32 *address;
 
@@ -351,7 +359,6 @@
 	int core_next_state = PWRDM_POWER_ON;
 	int core_prev_state, per_prev_state;
 	u32 sdrc_pwr = 0;
-	int per_state_modified = 0;
 
 	if (!_omap_sram_idle)
 		return;
@@ -385,30 +392,29 @@
 	/* Enable IO-PAD and IO-CHAIN wakeups */
 	per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
 	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
-	if (omap3_has_io_wakeup() && \
-			(per_next_state < PWRDM_POWER_ON ||
-			core_next_state < PWRDM_POWER_ON)) {
+	if (omap3_has_io_wakeup() &&
+	    (per_next_state < PWRDM_POWER_ON ||
+	     core_next_state < PWRDM_POWER_ON)) {
 		prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
 		omap3_enable_io_chain();
 	}
 
+	/* Block console output in case it is on one of the OMAP UARTs */
+	if (!is_suspending())
+		if (per_next_state < PWRDM_POWER_ON ||
+		    core_next_state < PWRDM_POWER_ON)
+			if (try_acquire_console_sem())
+				goto console_still_active;
+
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		omap_uart_prepare_idle(2);
+		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(per_next_state);
-		if (per_next_state == PWRDM_POWER_OFF) {
-			if (core_next_state == PWRDM_POWER_ON) {
-				per_next_state = PWRDM_POWER_RET;
-				pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
-				per_state_modified = 1;
-			} else
+		if (per_next_state == PWRDM_POWER_OFF)
 				omap3_per_save_context();
-		}
 	}
 
-	if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
-		omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
-
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
 		omap_uart_prepare_idle(0);
@@ -475,10 +481,13 @@
 		if (per_prev_state == PWRDM_POWER_OFF)
 			omap3_per_restore_context();
 		omap_uart_resume_idle(2);
-		if (per_state_modified)
-			pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
+		omap_uart_resume_idle(3);
 	}
 
+	if (!is_suspending())
+		release_console_sem();
+
+console_still_active:
 	/* Disable IO-PAD and IO-CHAIN wakeup */
 	if (omap3_has_io_wakeup() &&
 	    (per_next_state < PWRDM_POWER_ON ||
@@ -501,51 +510,6 @@
 	return 1;
 }
 
-/* This sets pwrdm state (other than mpu & core. Currently only ON &
- * RET are supported. Function is assuming that clkdm doesn't have
- * hw_sup mode enabled. */
-int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
-{
-	u32 cur_state;
-	int sleep_switch = 0;
-	int ret = 0;
-
-	if (pwrdm == NULL || IS_ERR(pwrdm))
-		return -EINVAL;
-
-	while (!(pwrdm->pwrsts & (1 << state))) {
-		if (state == PWRDM_POWER_OFF)
-			return ret;
-		state--;
-	}
-
-	cur_state = pwrdm_read_next_pwrst(pwrdm);
-	if (cur_state == state)
-		return ret;
-
-	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
-		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
-		sleep_switch = 1;
-		pwrdm_wait_transition(pwrdm);
-	}
-
-	ret = pwrdm_set_next_pwrst(pwrdm, state);
-	if (ret) {
-		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
-		       pwrdm->name);
-		goto err;
-	}
-
-	if (sleep_switch) {
-		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
-		pwrdm_wait_transition(pwrdm);
-		pwrdm_state_switch(pwrdm);
-	}
-
-err:
-	return ret;
-}
-
 static void omap3_pm_idle(void)
 {
 	local_irq_disable();
@@ -565,25 +529,6 @@
 }
 
 #ifdef CONFIG_SUSPEND
-static suspend_state_t suspend_state;
-
-static void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
-{
-	u32 tick_rate, cycles;
-
-	if (!seconds && !milliseconds)
-		return;
-
-	tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
-	cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
-	omap_dm_timer_stop(gptimer_wakeup);
-	omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
-
-	pr_info("PM: Resume timer in %u.%03u secs"
-		" (%d ticks at %d ticks/sec.)\n",
-		seconds, milliseconds, cycles, tick_rate);
-}
-
 static int omap3_pm_prepare(void)
 {
 	disable_hlt();
@@ -604,7 +549,7 @@
 		pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
 	/* Set ones wanted by suspend */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
-		if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+		if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
 			goto restore;
 		if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
 			goto restore;
@@ -625,7 +570,7 @@
 			       pwrst->pwrdm->name, pwrst->next_state);
 			ret = -1;
 		}
-		set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+		omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
 	}
 	if (ret)
 		printk(KERN_ERR "Could not enter target state in pm_suspend\n");
@@ -756,6 +701,14 @@
 
 static void __init prcm_setup_regs(void)
 {
+	u32 omap3630_auto_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_AUTO_UART4_MASK : 0;
+	u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_EN_UART4_MASK : 0;
+	u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_GRPSEL_UART4_MASK : 0;
+
+
 	/* XXX Reset all wkdeps. This should be done when initializing
 	 * powerdomains */
 	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
@@ -842,6 +795,7 @@
 		CM_AUTOIDLE);
 
 	cm_write_mod_reg(
+		omap3630_auto_uart4_mask |
 		OMAP3430_AUTO_GPIO6_MASK |
 		OMAP3430_AUTO_GPIO5_MASK |
 		OMAP3430_AUTO_GPIO4_MASK |
@@ -918,14 +872,16 @@
 				OMAP3430_DSS_MOD, PM_WKEN);
 
 	/* Enable wakeups in PER */
-	prm_write_mod_reg(OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
+	prm_write_mod_reg(omap3630_en_uart4_mask |
+			  OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
 			  OMAP3430_EN_GPIO4_MASK | OMAP3430_EN_GPIO5_MASK |
 			  OMAP3430_EN_GPIO6_MASK | OMAP3430_EN_UART3_MASK |
 			  OMAP3430_EN_MCBSP2_MASK | OMAP3430_EN_MCBSP3_MASK |
 			  OMAP3430_EN_MCBSP4_MASK,
 			  OMAP3430_PER_MOD, PM_WKEN);
 	/* and allow them to wake up MPU */
-	prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2_MASK |
+	prm_write_mod_reg(omap3630_grpsel_uart4_mask |
+			  OMAP3430_GRPSEL_GPIO2_MASK |
 			  OMAP3430_GRPSEL_GPIO3_MASK |
 			  OMAP3430_GRPSEL_GPIO4_MASK |
 			  OMAP3430_GRPSEL_GPIO5_MASK |
@@ -974,7 +930,7 @@
 
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 		pwrst->next_state = state;
-		set_pwrdm_state(pwrst->pwrdm, state);
+		omap_set_pwrdm_state(pwrst->pwrdm, state);
 	}
 }
 
@@ -1019,7 +975,7 @@
 	if (pwrdm_has_hdwr_sar(pwrdm))
 		pwrdm_enable_hdwr_sar(pwrdm);
 
-	return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+	return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
 }
 
 /*
@@ -1029,9 +985,6 @@
  */
 static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
 {
-	clkdm_clear_all_wkdeps(clkdm);
-	clkdm_clear_all_sleepdeps(clkdm);
-
 	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
 		omap2_clkdm_allow_idle(clkdm);
 	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm_bus.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm_bus.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm_bus.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm_bus.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,85 @@
+/*
+ * Runtime PM support code for OMAP
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+
+#ifdef CONFIG_PM_RUNTIME
+int omap_pm_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int r, ret = 0;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	ret = pm_generic_runtime_suspend(dev);
+
+	if (!ret && dev->parent == &omap_device_parent) {
+		r = omap_device_idle(pdev);
+		WARN_ON(r);
+	}
+
+	return ret;
+};
+
+int omap_pm_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int r;
+
+	dev_dbg(dev, "%s\n", __func__);
+
+	if (dev->parent == &omap_device_parent) {
+		r = omap_device_enable(pdev);
+		WARN_ON(r);
+	}
+
+	return pm_generic_runtime_resume(dev);
+};
+#else
+#define omap_pm_runtime_suspend NULL
+#define omap_pm_runtime_resume NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static int __init omap_pm_runtime_init(void)
+{
+	const struct dev_pm_ops *pm;
+	struct dev_pm_ops *omap_pm;
+
+	pm = platform_bus_get_pm_ops();
+	if (!pm) {
+		pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
+	if (!omap_pm) {
+		pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	omap_pm->runtime_suspend = omap_pm_runtime_suspend;
+	omap_pm->runtime_resume = omap_pm_runtime_resume;
+
+	platform_bus_set_pm_ops(omap_pm);
+
+	return 0;
+}
+core_initcall(omap_pm_runtime_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,11 +18,15 @@
 #include <plat/omap_device.h>
 #include <plat/common.h>
 
+#include <plat/powerdomain.h>
+#include <plat/clockdomain.h>
+
 static struct omap_device_pm_latency *pm_lats;
 
 static struct device *mpu_dev;
-static struct device *dsp_dev;
+static struct device *iva_dev;
 static struct device *l3_dev;
+static struct device *dsp_dev;
 
 struct device *omap2_get_mpuss_device(void)
 {
@@ -30,10 +34,10 @@
 	return mpu_dev;
 }
 
-struct device *omap2_get_dsp_device(void)
+struct device *omap2_get_iva_device(void)
 {
-	WARN_ON_ONCE(!dsp_dev);
-	return dsp_dev;
+	WARN_ON_ONCE(!iva_dev);
+	return iva_dev;
 }
 
 struct device *omap2_get_l3_device(void)
@@ -42,6 +46,13 @@
 	return l3_dev;
 }
 
+struct device *omap4_get_dsp_device(void)
+{
+	WARN_ON_ONCE(!dsp_dev);
+	return dsp_dev;
+}
+EXPORT_SYMBOL(omap4_get_dsp_device);
+
 /* static int _init_omap_device(struct omap_hwmod *oh, void *user) */
 static int _init_omap_device(char *name, struct device **new_dev)
 {
@@ -69,8 +80,60 @@
 static void omap2_init_processor_devices(void)
 {
 	_init_omap_device("mpu", &mpu_dev);
-	_init_omap_device("iva", &dsp_dev);
-	_init_omap_device("l3_main", &l3_dev);
+	_init_omap_device("iva", &iva_dev);
+	if (cpu_is_omap44xx()) {
+		_init_omap_device("l3_main_1", &l3_dev);
+		_init_omap_device("dsp", &dsp_dev);
+	} else {
+		_init_omap_device("l3_main", &l3_dev);
+	}
+}
+
+/*
+ * This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled.
+ */
+int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+	u32 cur_state;
+	int sleep_switch = 0;
+	int ret = 0;
+
+	if (pwrdm == NULL || IS_ERR(pwrdm))
+		return -EINVAL;
+
+	while (!(pwrdm->pwrsts & (1 << state))) {
+		if (state == PWRDM_POWER_OFF)
+			return ret;
+		state--;
+	}
+
+	cur_state = pwrdm_read_next_pwrst(pwrdm);
+	if (cur_state == state)
+		return ret;
+
+	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+		sleep_switch = 1;
+		pwrdm_wait_transition(pwrdm);
+	}
+
+	ret = pwrdm_set_next_pwrst(pwrdm, state);
+	if (ret) {
+		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+		       pwrdm->name);
+		goto err;
+	}
+
+	if (sleep_switch) {
+		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+		pwrdm_wait_transition(pwrdm);
+		pwrdm_state_switch(pwrdm);
+	}
+
+err:
+	return ret;
 }
 
 static int __init omap2_common_pm_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm-debug.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm-debug.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm-debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm-debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,12 +31,17 @@
 #include <plat/board.h>
 #include <plat/powerdomain.h>
 #include <plat/clockdomain.h>
+#include <plat/dmtimer.h>
 
 #include "prm.h"
 #include "cm.h"
 #include "pm.h"
 
 int omap2_pm_debug;
+u32 enable_off_mode;
+u32 sleep_while_idle;
+u32 wakeup_timer_seconds;
+u32 wakeup_timer_milliseconds;
 
 #define DUMP_PRM_MOD_REG(mod, reg)    \
 	regs[reg_count].name = #mod "." #reg; \
@@ -156,13 +161,30 @@
 		printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
 }
 
+void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds)
+{
+	u32 tick_rate, cycles;
+
+	if (!seconds && !milliseconds)
+		return;
+
+	tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup));
+	cycles = tick_rate * seconds + tick_rate * milliseconds / 1000;
+	omap_dm_timer_stop(gptimer_wakeup);
+	omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles);
+
+	pr_info("PM: Resume timer in %u.%03u secs"
+		" (%d ticks at %d ticks/sec.)\n",
+		seconds, milliseconds, cycles, tick_rate);
+}
+
 #ifdef CONFIG_DEBUG_FS
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
 static void pm_dbg_regset_store(u32 *ptr);
 
-struct dentry *pm_dbg_dir;
+static struct dentry *pm_dbg_dir;
 
 static int pm_dbg_init_done;
 
@@ -494,8 +516,10 @@
 
 static int pwrdm_suspend_get(void *data, u64 *val)
 {
-	int ret;
-	ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
+	int ret = -EINVAL;
+
+	if (cpu_is_omap34xx())
+		ret = omap3_pm_get_suspend_state((struct powerdomain *)data);
 	*val = ret;
 
 	if (ret >= 0)
@@ -505,7 +529,10 @@
 
 static int pwrdm_suspend_set(void *data, u64 val)
 {
-	return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val);
+	if (cpu_is_omap34xx())
+		return omap3_pm_set_suspend_state(
+			(struct powerdomain *)data, (int)val);
+	return -EINVAL;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get,
@@ -553,8 +580,10 @@
 
 	*option = val;
 
-	if (option == &enable_off_mode)
-		omap3_pm_off_mode_enable(val);
+	if (option == &enable_off_mode) {
+		if (cpu_is_omap34xx())
+			omap3_pm_off_mode_enable(val);
+	}
 
 	return 0;
 }
@@ -609,6 +638,9 @@
 				   &sleep_while_idle, &pm_dbg_option_fops);
 	(void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d,
 				   &wakeup_timer_seconds, &pm_dbg_option_fops);
+	(void) debugfs_create_file("wakeup_timer_milliseconds",
+			S_IRUGO | S_IWUGO, d, &wakeup_timer_milliseconds,
+			&pm_dbg_option_fops);
 	pm_dbg_init_done = 1;
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/pm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/pm.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,14 +13,11 @@
 
 #include <plat/powerdomain.h>
 
-extern u32 enable_off_mode;
-extern u32 sleep_while_idle;
-
 extern void *omap3_secure_ram_storage;
 extern void omap3_pm_off_mode_enable(int);
 extern void omap_sram_idle(void);
 extern int omap3_can_sleep(void);
-extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
+extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 extern int omap3_idle_init(void);
 
 struct cpuidle_params {
@@ -48,10 +45,16 @@
 
 #ifdef CONFIG_PM_DEBUG
 extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds);
 extern int omap2_pm_debug;
+extern u32 enable_off_mode;
+extern u32 sleep_while_idle;
 #else
 #define omap2_pm_dump(mode, resume, us)		do {} while (0);
+#define omap2_pm_wakeup_on_timer(seconds, milliseconds)	do {} while (0);
 #define omap2_pm_debug				0
+#define enable_off_mode 0
+#define sleep_while_idle 0
 #endif
 
 #if defined(CONFIG_CPU_IDLE)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/powerdomains44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/powerdomains44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/powerdomains44xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/powerdomains44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -98,7 +98,7 @@
 	.prcm_offs	  = OMAP4430_PRM_DSS_MOD,
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
 	.pwrsts		  = PWRSTS_OFF_RET_ON,
-	.pwrsts_logic_ret = PWRSTS_OFF_RET,
+	.pwrsts_logic_ret = PWRSTS_OFF,
 	.banks		  = 1,
 	.pwrsts_mem_ret	= {
 		[0] = PWRDM_POWER_OFF,	/* dss_mem */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prcm.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prcm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prcm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prcm.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,13 +26,14 @@
 #include <plat/common.h>
 #include <plat/prcm.h>
 #include <plat/irqs.h>
-#include <plat/control.h>
 
 #include "clock.h"
 #include "clock2xxx.h"
 #include "cm.h"
 #include "prm.h"
 #include "prm-regbits-24xx.h"
+#include "prm-regbits-44xx.h"
+#include "control.h"
 
 static void __iomem *prm_base;
 static void __iomem *cm_base;
@@ -118,7 +119,7 @@
 	u32 wkup_pm_wken;
 };
 
-struct omap3_prcm_regs prcm_context;
+static struct omap3_prcm_regs prcm_context;
 
 u32 omap_prcm_get_reset_sources(void)
 {
@@ -161,8 +162,8 @@
 		prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
 						 OMAP2_RM_RSTCTRL);
 	if (cpu_is_omap44xx())
-		prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs,
-						 OMAP4_RM_RSTCTRL);
+		prm_set_mod_reg_bits(OMAP4430_RST_GLOBAL_WARM_SW_MASK,
+				     prcm_offs, OMAP4_RM_RSTCTRL);
 }
 
 static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg)
@@ -215,6 +216,30 @@
 	return v;
 }
 
+/* Read a PRM register, AND it, and shift the result down to bit 0 */
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask)
+{
+	u32 v;
+
+	v = __raw_readl(reg);
+	v &= mask;
+	v >>= __ffs(mask);
+
+	return v;
+}
+
+/* Read-modify-write a register in a PRM module. Caller must lock */
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg)
+{
+	u32 v;
+
+	v = __raw_readl(reg);
+	v &= ~mask;
+	v |= bits;
+	__raw_writel(v, reg);
+
+	return v;
+}
 /* Read a register in a CM module */
 u32 cm_read_mod_reg(s16 module, u16 idx)
 {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prcm-common.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prcm-common.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prcm-common.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prcm-common.h	2011-01-04 19:50:19.000000000 -0500
@@ -243,13 +243,14 @@
 #define OMAP24XX_EN_GPT1_MASK				(1 << 0)
 
 /* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
-#define OMAP24XX_ST_GPIOS_SHIFT				(1 << 2)
-#define OMAP24XX_ST_GPIOS_MASK				2
-#define OMAP24XX_ST_GPT1_SHIFT				(1 << 0)
-#define OMAP24XX_ST_GPT1_MASK				0
+#define OMAP24XX_ST_GPIOS_SHIFT				2
+#define OMAP24XX_ST_GPIOS_MASK				(1 << 2)
+#define OMAP24XX_ST_GPT1_SHIFT				0
+#define OMAP24XX_ST_GPT1_MASK				(1 << 0)
 
 /* CM_IDLEST_MDM and PM_WKST_MDM shared bits */
-#define OMAP2430_ST_MDM_SHIFT				(1 << 0)
+#define OMAP2430_ST_MDM_SHIFT				0
+#define OMAP2430_ST_MDM_MASK				(1 << 0)
 
 
 /* 3430 register bits shared between CM & PRM registers */
@@ -382,6 +383,9 @@
 #define OMAP3430_EN_MPU_SHIFT				1
 
 /* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER shared bits */
+
+#define OMAP3630_EN_UART4_MASK				(1 << 18)
+#define OMAP3630_EN_UART4_SHIFT				18
 #define OMAP3430_EN_GPIO6_MASK				(1 << 17)
 #define OMAP3430_EN_GPIO6_SHIFT				17
 #define OMAP3430_EN_GPIO5_MASK				(1 << 16)
@@ -422,6 +426,8 @@
 #define OMAP3430_EN_MCBSP2_SHIFT			0
 
 /* CM_IDLEST_PER, PM_WKST_PER shared bits */
+#define OMAP3630_ST_UART4_SHIFT				18
+#define OMAP3630_ST_UART4_MASK				(1 << 18)
 #define OMAP3430_ST_GPIO6_SHIFT				17
 #define OMAP3430_ST_GPIO6_MASK				(1 << 17)
 #define OMAP3430_ST_GPIO5_SHIFT				16
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm2xxx_3xxx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm2xxx_3xxx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm2xxx_3xxx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm2xxx_3xxx.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,110 @@
+/*
+ * OMAP2/3 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * BenoÃ®t Cousson
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "prm-regbits-34xx.h"
+
+/**
+ * omap2_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL if called while running on a non-OMAP2/3 chip.
+ */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+{
+	if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+		return -EINVAL;
+
+	return prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
+				       (1 << shift));
+}
+
+/**
+ * omap2_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * place the submodule into reset.  Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+{
+	u32 mask;
+
+	if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+		return -EINVAL;
+
+	mask = 1 << shift;
+	prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL);
+
+	return 0;
+}
+
+/**
+ * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning.  Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift)
+{
+	u32 mask;
+	int c;
+
+	if (!(cpu_is_omap24xx() || cpu_is_omap34xx()))
+		return -EINVAL;
+
+	mask = 1 << shift;
+
+	/* Check the current status to avoid de-asserting the line twice */
+	if (prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0)
+		return -EEXIST;
+
+	/* Clear the reset status by writing 1 to the status bit */
+	prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST);
+	/* de-assert the reset control line */
+	prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL);
+	/* wait the status to be set */
+	omap_test_timeout(prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST,
+						  mask),
+			  MAX_MODULE_HARDRESET_WAIT, c);
+
+	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm44xx.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm44xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm44xx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm44xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,116 @@
+/*
+ * OMAP4 PRM module functions
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ * Copyright (C) 2010 Nokia Corporation
+ * BenoÃ®t Cousson
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/prcm.h>
+
+#include "prm.h"
+#include "prm-regbits-44xx.h"
+
+/*
+ * Address offset (in bytes) between the reset control and the reset
+ * status registers: 4 bytes on OMAP4
+ */
+#define OMAP4_RST_CTRL_ST_OFFSET		4
+
+/**
+ * omap4_prm_is_hardreset_asserted - read the HW reset line state of
+ * submodules contained in the hwmod module
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to check
+ *
+ * Returns 1 if the (sub)module hardreset line is currently asserted,
+ * 0 if the (sub)module hardreset line is not currently asserted, or
+ * -EINVAL upon parameter error.
+ */
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift)
+{
+	if (!cpu_is_omap44xx() || !rstctrl_reg)
+		return -EINVAL;
+
+	return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift));
+}
+
+/**
+ * omap4_prm_assert_hardreset - assert the HW reset line of a submodule
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to assert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * place the submodule into reset.  Returns 0 upon success or -EINVAL
+ * upon an argument error.
+ */
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+	u32 mask;
+
+	if (!cpu_is_omap44xx() || !rstctrl_reg)
+		return -EINVAL;
+
+	mask = 1 << shift;
+	omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg);
+
+	return 0;
+}
+
+/**
+ * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait
+ * @rstctrl_reg: RM_RSTCTRL register address for this module
+ * @shift: register bit shift corresponding to the reset line to deassert
+ *
+ * Some IPs like dsp, ipu or iva contain processors that require an HW
+ * reset line to be asserted / deasserted in order to fully enable the
+ * IP.  These modules may have multiple hard-reset lines that reset
+ * different 'submodules' inside the IP block.  This function will
+ * take the submodule out of reset and wait until the PRCM indicates
+ * that the reset has completed before returning.  Returns 0 upon success or
+ * -EINVAL upon an argument error, -EEXIST if the submodule was already out
+ * of reset, or -EBUSY if the submodule did not exit reset promptly.
+ */
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift)
+{
+	u32 mask;
+	void __iomem *rstst_reg;
+	int c;
+
+	if (!cpu_is_omap44xx() || !rstctrl_reg)
+		return -EINVAL;
+
+	rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET;
+
+	mask = 1 << shift;
+
+	/* Check the current status to avoid de-asserting the line twice */
+	if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0)
+		return -EEXIST;
+
+	/* Clear the reset status by writing 1 to the status bit */
+	omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg);
+	/* de-assert the reset control line */
+	omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg);
+	/* wait the status to be set */
+	omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask),
+			  MAX_MODULE_HARDRESET_WAIT, c);
+
+	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
+}
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm44xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,14 +44,12 @@
 #define OMAP4430_PRM_IRQSTATUS_TESLA			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0030)
 #define OMAP4_PRM_IRQENABLE_TESLA_OFFSET		0x0038
 #define OMAP4430_PRM_IRQENABLE_TESLA			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0038)
-#define OMAP4_PRM_PRM_PROFILING_CLKCTRL_OFFSET		0x0040
-#define OMAP4430_PRM_PRM_PROFILING_CLKCTRL		OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
+#define OMAP4_CM_PRM_PROFILING_CLKCTRL_OFFSET		0x0040
+#define OMAP4430_CM_PRM_PROFILING_CLKCTRL		OMAP44XX_PRM_REGADDR(OMAP4430_PRM_OCP_SOCKET_MOD, 0x0040)
 
 /* PRM.CKGEN_PRM register offsets */
 #define OMAP4_CM_ABE_DSS_SYS_CLKSEL_OFFSET		0x0000
 #define OMAP4430_CM_ABE_DSS_SYS_CLKSEL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0000)
-#define OMAP4_CM_DPLL_SYS_REF_CLKSEL_OFFSET		0x0004
-#define OMAP4430_CM_DPLL_SYS_REF_CLKSEL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0004)
 #define OMAP4_CM_L4_WKUP_CLKSEL_OFFSET			0x0008
 #define OMAP4430_CM_L4_WKUP_CLKSEL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_CKGEN_MOD, 0x0008)
 #define OMAP4_CM_ABE_PLL_REF_CLKSEL_OFFSET		0x000c
@@ -686,8 +684,8 @@
 #define OMAP4430_PRM_LDO_ABB_IVA_SETUP			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00d8)
 #define OMAP4_PRM_LDO_ABB_IVA_CTRL_OFFSET		0x00dc
 #define OMAP4430_PRM_LDO_ABB_IVA_CTRL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00dc)
-#define OMAP4_PRM_LDO_BANDGAP_CTRL_OFFSET		0x00e0
-#define OMAP4430_PRM_LDO_BANDGAP_CTRL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
+#define OMAP4_PRM_LDO_BANDGAP_SETUP_OFFSET		0x00e0
+#define OMAP4430_PRM_LDO_BANDGAP_SETUP			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e0)
 #define OMAP4_PRM_DEVICE_OFF_CTRL_OFFSET		0x00e4
 #define OMAP4430_PRM_DEVICE_OFF_CTRL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00e4)
 #define OMAP4_PRM_PHASE1_CNDP_OFFSET			0x00e8
@@ -698,6 +696,8 @@
 #define OMAP4430_PRM_PHASE2B_CNDP			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f0)
 #define OMAP4_PRM_MODEM_IF_CTRL_OFFSET			0x00f4
 #define OMAP4430_PRM_MODEM_IF_CTRL			OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f4)
+#define OMAP4_PRM_VC_ERRST_OFFSET			0x00f8
+#define OMAP4430_PRM_VC_ERRST				OMAP44XX_PRM_REGADDR(OMAP4430_PRM_DEVICE_MOD, 0x00f8)
 
 /*
  * PRCM_MPU
@@ -715,6 +715,8 @@
 /* PRCM_MPU.DEVICE_PRM register offsets */
 #define OMAP4_PRCM_MPU_PRM_RSTST_OFFSET			0x0000
 #define OMAP4430_PRCM_MPU_PRM_RSTST			OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0000)
+#define OMAP4_PRCM_MPU_PRM_PSCON_COUNT_OFFSET		0x0004
+#define OMAP4430_PRCM_MPU_PRM_PSCON_COUNT		OMAP44XX_PRCM_MPU_REGADDR(OMAP4430_PRCM_MPU_DEVICE_PRM_MOD, 0x0004)
 
 /* PRCM_MPU.CPU0 register offsets */
 #define OMAP4_PM_CPU0_PWRSTCTRL_OFFSET			0x0000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  * OMAP2/3 Power/Reset Management (PRM) register definitions
  *
  * Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Nokia Corporation
  *
  * Written by Paul Walmsley
  *
@@ -246,6 +246,15 @@
 	return prm_rmw_mod_reg_bits(bits, 0x0, module, idx);
 }
 
+/* These omap2_ PRM functions apply to both OMAP2 and 3 */
+int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
+int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
+int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift);
+
+int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift);
+
 #endif
 
 /*
@@ -398,4 +407,11 @@
 #define OMAP_POWERSTATE_MASK				(0x3 << 0)
 
 
+/*
+ * MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP
+ * submodule to exit hardreset
+ */
+#define MAX_MODULE_HARDRESET_WAIT		10000
+
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm-regbits-34xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm-regbits-34xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm-regbits-34xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm-regbits-34xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -122,6 +122,7 @@
 #define OMAP3430_MEMRETSTATE_MASK			(1 << 8)
 
 /* PM_MPUGRPSEL_PER, PM_IVA2GRPSEL_PER shared bits */
+#define OMAP3630_GRPSEL_UART4_MASK			(1 << 18)
 #define OMAP3430_GRPSEL_GPIO6_MASK			(1 << 17)
 #define OMAP3430_GRPSEL_GPIO5_MASK			(1 << 16)
 #define OMAP3430_GRPSEL_GPIO4_MASK			(1 << 15)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm-regbits-44xx.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm-regbits-44xx.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/prm-regbits-44xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/prm-regbits-44xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 /*
  * OMAP44xx Power Management register bits
  *
- * Copyright (C) 2009 Texas Instruments, Inc.
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Paul Walmsley (paul@pwsan.com)
  * Rajendra Nayak (rnayak@ti.com)
@@ -30,587 +30,611 @@
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ABBOFF_ACT_EXPORT_SHIFT				1
-#define OMAP4430_ABBOFF_ACT_EXPORT_MASK					BITFIELD(1, 1)
+#define OMAP4430_ABBOFF_ACT_EXPORT_MASK					(1 << 1)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ABBOFF_SLEEP_EXPORT_SHIFT				2
-#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK				BITFIELD(2, 2)
+#define OMAP4430_ABBOFF_SLEEP_EXPORT_MASK				(1 << 2)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_ABB_IVA_DONE_EN_SHIFT					31
-#define OMAP4430_ABB_IVA_DONE_EN_MASK					BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_EN_MASK					(1 << 31)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_ABB_IVA_DONE_ST_SHIFT					31
-#define OMAP4430_ABB_IVA_DONE_ST_MASK					BITFIELD(31, 31)
+#define OMAP4430_ABB_IVA_DONE_ST_MASK					(1 << 31)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_ABB_MPU_DONE_EN_SHIFT					7
-#define OMAP4430_ABB_MPU_DONE_EN_MASK					BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_EN_MASK					(1 << 7)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_ABB_MPU_DONE_ST_SHIFT					7
-#define OMAP4430_ABB_MPU_DONE_ST_MASK					BITFIELD(7, 7)
+#define OMAP4430_ABB_MPU_DONE_ST_MASK					(1 << 7)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_ACTIVE_FBB_SEL_SHIFT					2
-#define OMAP4430_ACTIVE_FBB_SEL_MASK					BITFIELD(2, 2)
+#define OMAP4430_ACTIVE_FBB_SEL_MASK					(1 << 2)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_ACTIVE_RBB_SEL_SHIFT					1
-#define OMAP4430_ACTIVE_RBB_SEL_MASK					BITFIELD(1, 1)
+#define OMAP4430_ACTIVE_RBB_SEL_MASK					(1 << 1)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_AESSMEM_ONSTATE_SHIFT					16
-#define OMAP4430_AESSMEM_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_AESSMEM_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_AESSMEM_RETSTATE_SHIFT					8
-#define OMAP4430_AESSMEM_RETSTATE_MASK					BITFIELD(8, 8)
+#define OMAP4430_AESSMEM_RETSTATE_MASK					(1 << 8)
 
 /* Used by PM_ABE_PWRSTST */
 #define OMAP4430_AESSMEM_STATEST_SHIFT					4
-#define OMAP4430_AESSMEM_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_AESSMEM_STATEST_MASK					(0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_AIPOFF_SHIFT						8
-#define OMAP4430_AIPOFF_MASK						BITFIELD(8, 8)
+#define OMAP4430_AIPOFF_MASK						(1 << 8)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_CORE_L_SHIFT				0
-#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK				BITFIELD(0, 1)
+#define OMAP4430_AUTO_CTRL_VDD_CORE_L_MASK				(0x3 << 0)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_IVA_L_SHIFT				4
-#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK				BITFIELD(4, 5)
+#define OMAP4430_AUTO_CTRL_VDD_IVA_L_MASK				(0x3 << 4)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_AUTO_CTRL_VDD_MPU_L_SHIFT				2
-#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK				BITFIELD(2, 3)
+#define OMAP4430_AUTO_CTRL_VDD_MPU_L_MASK				(0x3 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_RA_ERR_SHIFT					25
+#define OMAP4430_BYPS_RA_ERR_MASK					(1 << 25)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_SA_ERR_SHIFT					24
+#define OMAP4430_BYPS_SA_ERR_MASK					(1 << 24)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_BYPS_TIMEOUT_ERR_SHIFT					26
+#define OMAP4430_BYPS_TIMEOUT_ERR_MASK					(1 << 26)
+
+/* Used by PRM_RSTST */
+#define OMAP4430_C2C_RST_SHIFT						10
+#define OMAP4430_C2C_RST_MASK						(1 << 10)
 
 /* Used by PM_CAM_PWRSTCTRL */
 #define OMAP4430_CAM_MEM_ONSTATE_SHIFT					16
-#define OMAP4430_CAM_MEM_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_CAM_MEM_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_CAM_PWRSTST */
 #define OMAP4430_CAM_MEM_STATEST_SHIFT					4
-#define OMAP4430_CAM_MEM_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_CAM_MEM_STATEST_MASK					(0x3 << 4)
 
 /* Used by PRM_CLKREQCTRL */
 #define OMAP4430_CLKREQ_COND_SHIFT					0
-#define OMAP4430_CLKREQ_COND_MASK					BITFIELD(0, 2)
+#define OMAP4430_CLKREQ_COND_MASK					(0x7 << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_CORE_L_SHIFT					0
-#define OMAP4430_CMDRA_VDD_CORE_L_MASK					BITFIELD(0, 7)
+#define OMAP4430_CMDRA_VDD_CORE_L_MASK					(0xff << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_IVA_L_SHIFT					8
-#define OMAP4430_CMDRA_VDD_IVA_L_MASK					BITFIELD(8, 15)
+#define OMAP4430_CMDRA_VDD_IVA_L_MASK					(0xff << 8)
 
 /* Used by PRM_VC_VAL_SMPS_RA_CMD */
 #define OMAP4430_CMDRA_VDD_MPU_L_SHIFT					16
-#define OMAP4430_CMDRA_VDD_MPU_L_MASK					BITFIELD(16, 23)
+#define OMAP4430_CMDRA_VDD_MPU_L_MASK					(0xff << 16)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_CORE_L_SHIFT					4
-#define OMAP4430_CMD_VDD_CORE_L_MASK					BITFIELD(4, 4)
+#define OMAP4430_CMD_VDD_CORE_L_MASK					(1 << 4)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_IVA_L_SHIFT					12
-#define OMAP4430_CMD_VDD_IVA_L_MASK					BITFIELD(12, 12)
+#define OMAP4430_CMD_VDD_IVA_L_MASK					(1 << 12)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_CMD_VDD_MPU_L_SHIFT					17
-#define OMAP4430_CMD_VDD_MPU_L_MASK					BITFIELD(17, 17)
+#define OMAP4430_CMD_VDD_MPU_L_MASK					(1 << 17)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OCMRAM_ONSTATE_SHIFT				18
-#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK				BITFIELD(18, 19)
+#define OMAP4430_CORE_OCMRAM_ONSTATE_MASK				(0x3 << 18)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OCMRAM_RETSTATE_SHIFT				9
-#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK				BITFIELD(9, 9)
+#define OMAP4430_CORE_OCMRAM_RETSTATE_MASK				(1 << 9)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_CORE_OCMRAM_STATEST_SHIFT				6
-#define OMAP4430_CORE_OCMRAM_STATEST_MASK				BITFIELD(6, 7)
+#define OMAP4430_CORE_OCMRAM_STATEST_MASK				(0x3 << 6)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OTHER_BANK_ONSTATE_SHIFT				16
-#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK				BITFIELD(16, 17)
+#define OMAP4430_CORE_OTHER_BANK_ONSTATE_MASK				(0x3 << 16)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_CORE_OTHER_BANK_RETSTATE_SHIFT				8
-#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK				BITFIELD(8, 8)
+#define OMAP4430_CORE_OTHER_BANK_RETSTATE_MASK				(1 << 8)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_CORE_OTHER_BANK_STATEST_SHIFT				4
-#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK				BITFIELD(4, 5)
+#define OMAP4430_CORE_OTHER_BANK_STATEST_MASK				(0x3 << 4)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_CUSTOM_SHIFT						6
+#define OMAP4430_CUSTOM_MASK						(0x3 << 6)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_DATA_SHIFT						16
-#define OMAP4430_DATA_MASK						BITFIELD(16, 23)
+#define OMAP4430_DATA_MASK						(0xff << 16)
 
 /* Used by PRM_DEVICE_OFF_CTRL */
 #define OMAP4430_DEVICE_OFF_ENABLE_SHIFT				0
-#define OMAP4430_DEVICE_OFF_ENABLE_MASK					BITFIELD(0, 0)
+#define OMAP4430_DEVICE_OFF_ENABLE_MASK					(1 << 0)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_DFILTEREN_SHIFT					6
-#define OMAP4430_DFILTEREN_MASK						BITFIELD(6, 6)
+#define OMAP4430_DFILTEREN_MASK						(1 << 6)
 
-/* Used by PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
+/*
+ * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
+ * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
+ */
+#define OMAP4430_DISABLE_RTA_EXPORT_SHIFT				0
+#define OMAP4430_DISABLE_RTA_EXPORT_MASK				(1 << 0)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
 #define OMAP4430_DPLL_ABE_RECAL_EN_SHIFT				4
-#define OMAP4430_DPLL_ABE_RECAL_EN_MASK					BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_EN_MASK					(1 << 4)
 
-/* Used by PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_DPLL_ABE_RECAL_ST_SHIFT				4
-#define OMAP4430_DPLL_ABE_RECAL_ST_MASK					BITFIELD(4, 4)
+#define OMAP4430_DPLL_ABE_RECAL_ST_MASK					(1 << 4)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_CORE_RECAL_EN_SHIFT				0
-#define OMAP4430_DPLL_CORE_RECAL_EN_MASK				BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_EN_MASK				(1 << 0)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_CORE_RECAL_ST_SHIFT				0
-#define OMAP4430_DPLL_CORE_RECAL_ST_MASK				BITFIELD(0, 0)
+#define OMAP4430_DPLL_CORE_RECAL_ST_MASK				(1 << 0)
 
 /* Used by PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_DDRPHY_RECAL_EN_SHIFT				6
-#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK				BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_EN_MASK				(1 << 6)
 
 /* Used by PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_DDRPHY_RECAL_ST_SHIFT				6
-#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK				BITFIELD(6, 6)
+#define OMAP4430_DPLL_DDRPHY_RECAL_ST_MASK				(1 << 6)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU, PRM_IRQENABLE_TESLA */
 #define OMAP4430_DPLL_IVA_RECAL_EN_SHIFT				2
-#define OMAP4430_DPLL_IVA_RECAL_EN_MASK					BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_EN_MASK					(1 << 2)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_DPLL_IVA_RECAL_ST_SHIFT				2
-#define OMAP4430_DPLL_IVA_RECAL_ST_MASK					BITFIELD(2, 2)
+#define OMAP4430_DPLL_IVA_RECAL_ST_MASK					(1 << 2)
 
 /* Used by PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_MPU_RECAL_EN_SHIFT				1
-#define OMAP4430_DPLL_MPU_RECAL_EN_MASK					BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_EN_MASK					(1 << 1)
 
 /* Used by PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_MPU_RECAL_ST_SHIFT				1
-#define OMAP4430_DPLL_MPU_RECAL_ST_MASK					BITFIELD(1, 1)
+#define OMAP4430_DPLL_MPU_RECAL_ST_MASK					(1 << 1)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_PER_RECAL_EN_SHIFT				3
-#define OMAP4430_DPLL_PER_RECAL_EN_MASK					BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_EN_MASK					(1 << 3)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_PER_RECAL_ST_SHIFT				3
-#define OMAP4430_DPLL_PER_RECAL_ST_MASK					BITFIELD(3, 3)
+#define OMAP4430_DPLL_PER_RECAL_ST_MASK					(1 << 3)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_DPLL_UNIPRO_RECAL_EN_SHIFT				7
-#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK				BITFIELD(7, 7)
+#define OMAP4430_DPLL_UNIPRO_RECAL_EN_MASK				(1 << 7)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_DPLL_UNIPRO_RECAL_ST_SHIFT				7
-#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK				BITFIELD(7, 7)
-
-/* Used by PRM_IRQENABLE_MPU */
-#define OMAP4430_DPLL_USB_RECAL_EN_SHIFT				5
-#define OMAP4430_DPLL_USB_RECAL_EN_MASK					BITFIELD(5, 5)
-
-/* Used by PRM_IRQSTATUS_MPU */
-#define OMAP4430_DPLL_USB_RECAL_ST_SHIFT				5
-#define OMAP4430_DPLL_USB_RECAL_ST_MASK					BITFIELD(5, 5)
+#define OMAP4430_DPLL_UNIPRO_RECAL_ST_MASK				(1 << 7)
 
 /* Used by PM_DSS_PWRSTCTRL */
 #define OMAP4430_DSS_MEM_ONSTATE_SHIFT					16
-#define OMAP4430_DSS_MEM_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_DSS_MEM_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_DSS_PWRSTCTRL */
 #define OMAP4430_DSS_MEM_RETSTATE_SHIFT					8
-#define OMAP4430_DSS_MEM_RETSTATE_MASK					BITFIELD(8, 8)
+#define OMAP4430_DSS_MEM_RETSTATE_MASK					(1 << 8)
 
 /* Used by PM_DSS_PWRSTST */
 #define OMAP4430_DSS_MEM_STATEST_SHIFT					4
-#define OMAP4430_DSS_MEM_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_DSS_MEM_STATEST_MASK					(0x3 << 4)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_L2RAM_ONSTATE_SHIFT				20
-#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK				BITFIELD(20, 21)
+#define OMAP4430_DUCATI_L2RAM_ONSTATE_MASK				(0x3 << 20)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_L2RAM_RETSTATE_SHIFT				10
-#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK				BITFIELD(10, 10)
+#define OMAP4430_DUCATI_L2RAM_RETSTATE_MASK				(1 << 10)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_DUCATI_L2RAM_STATEST_SHIFT				8
-#define OMAP4430_DUCATI_L2RAM_STATEST_MASK				BITFIELD(8, 9)
+#define OMAP4430_DUCATI_L2RAM_STATEST_MASK				(0x3 << 8)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_UNICACHE_ONSTATE_SHIFT				22
-#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK				BITFIELD(22, 23)
+#define OMAP4430_DUCATI_UNICACHE_ONSTATE_MASK				(0x3 << 22)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_DUCATI_UNICACHE_RETSTATE_SHIFT				11
-#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK				BITFIELD(11, 11)
+#define OMAP4430_DUCATI_UNICACHE_RETSTATE_MASK				(1 << 11)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_DUCATI_UNICACHE_STATEST_SHIFT				10
-#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK				BITFIELD(10, 11)
+#define OMAP4430_DUCATI_UNICACHE_STATEST_MASK				(0x3 << 10)
 
 /* Used by RM_MPU_RSTST */
 #define OMAP4430_EMULATION_RST_SHIFT					0
-#define OMAP4430_EMULATION_RST_MASK					BITFIELD(0, 0)
+#define OMAP4430_EMULATION_RST_MASK					(1 << 0)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_EMULATION_RST1ST_SHIFT					3
-#define OMAP4430_EMULATION_RST1ST_MASK					BITFIELD(3, 3)
+#define OMAP4430_EMULATION_RST1ST_MASK					(1 << 3)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_EMULATION_RST2ST_SHIFT					4
-#define OMAP4430_EMULATION_RST2ST_MASK					BITFIELD(4, 4)
+#define OMAP4430_EMULATION_RST2ST_MASK					(1 << 4)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_EMULATION_SEQ1_RST1ST_SHIFT				3
-#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK				BITFIELD(3, 3)
+#define OMAP4430_EMULATION_SEQ1_RST1ST_MASK				(1 << 3)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_EMULATION_SEQ2_RST2ST_SHIFT				4
-#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK				BITFIELD(4, 4)
+#define OMAP4430_EMULATION_SEQ2_RST2ST_MASK				(1 << 4)
 
 /* Used by PM_EMU_PWRSTCTRL */
 #define OMAP4430_EMU_BANK_ONSTATE_SHIFT					16
-#define OMAP4430_EMU_BANK_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_EMU_BANK_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_EMU_PWRSTST */
 #define OMAP4430_EMU_BANK_STATEST_SHIFT					4
-#define OMAP4430_EMU_BANK_STATEST_MASK					BITFIELD(4, 5)
-
-/*
- * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
- * PRM_LDO_SRAM_MPU_SETUP, PRM_SRAM_WKUP_SETUP
- */
-#define OMAP4430_ENABLE_RTA_EXPORT_SHIFT				0
-#define OMAP4430_ENABLE_RTA_EXPORT_MASK					BITFIELD(0, 0)
+#define OMAP4430_EMU_BANK_STATEST_MASK					(0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
-#define OMAP4430_ENFUNC1_SHIFT						3
-#define OMAP4430_ENFUNC1_MASK						BITFIELD(3, 3)
+#define OMAP4430_ENFUNC1_EXPORT_SHIFT					3
+#define OMAP4430_ENFUNC1_EXPORT_MASK					(1 << 3)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
-#define OMAP4430_ENFUNC3_SHIFT						5
-#define OMAP4430_ENFUNC3_MASK						BITFIELD(5, 5)
+#define OMAP4430_ENFUNC3_EXPORT_SHIFT					5
+#define OMAP4430_ENFUNC3_EXPORT_MASK					(1 << 5)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ENFUNC4_SHIFT						6
-#define OMAP4430_ENFUNC4_MASK						BITFIELD(6, 6)
+#define OMAP4430_ENFUNC4_MASK						(1 << 6)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_SETUP, PRM_LDO_SRAM_IVA_SETUP,
  * PRM_LDO_SRAM_MPU_SETUP
  */
 #define OMAP4430_ENFUNC5_SHIFT						7
-#define OMAP4430_ENFUNC5_MASK						BITFIELD(7, 7)
+#define OMAP4430_ENFUNC5_MASK						(1 << 7)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_ERRORGAIN_SHIFT					16
-#define OMAP4430_ERRORGAIN_MASK						BITFIELD(16, 23)
+#define OMAP4430_ERRORGAIN_MASK						(0xff << 16)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_ERROROFFSET_SHIFT					24
-#define OMAP4430_ERROROFFSET_MASK					BITFIELD(24, 31)
+#define OMAP4430_ERROROFFSET_MASK					(0xff << 24)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_EXTERNAL_WARM_RST_SHIFT				5
-#define OMAP4430_EXTERNAL_WARM_RST_MASK					BITFIELD(5, 5)
+#define OMAP4430_EXTERNAL_WARM_RST_MASK					(1 << 5)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_FORCEUPDATE_SHIFT					1
-#define OMAP4430_FORCEUPDATE_MASK					BITFIELD(1, 1)
+#define OMAP4430_FORCEUPDATE_MASK					(1 << 1)
 
 /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
 #define OMAP4430_FORCEUPDATEWAIT_SHIFT					8
-#define OMAP4430_FORCEUPDATEWAIT_MASK					BITFIELD(8, 31)
+#define OMAP4430_FORCEUPDATEWAIT_MASK					(0xffffff << 8)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_TESLA */
 #define OMAP4430_FORCEWKUP_EN_SHIFT					10
-#define OMAP4430_FORCEWKUP_EN_MASK					BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_EN_MASK					(1 << 10)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_TESLA */
 #define OMAP4430_FORCEWKUP_ST_SHIFT					10
-#define OMAP4430_FORCEWKUP_ST_MASK					BITFIELD(10, 10)
+#define OMAP4430_FORCEWKUP_ST_MASK					(1 << 10)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_FUNC_SHIFT						16
+#define OMAP4430_FUNC_MASK						(0xfff << 16)
 
 /* Used by PM_GFX_PWRSTCTRL */
 #define OMAP4430_GFX_MEM_ONSTATE_SHIFT					16
-#define OMAP4430_GFX_MEM_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_GFX_MEM_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_GFX_PWRSTST */
 #define OMAP4430_GFX_MEM_STATEST_SHIFT					4
-#define OMAP4430_GFX_MEM_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_GFX_MEM_STATEST_MASK					(0x3 << 4)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_GLOBAL_COLD_RST_SHIFT					0
-#define OMAP4430_GLOBAL_COLD_RST_MASK					BITFIELD(0, 0)
+#define OMAP4430_GLOBAL_COLD_RST_MASK					(1 << 0)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_GLOBAL_WARM_SW_RST_SHIFT				1
-#define OMAP4430_GLOBAL_WARM_SW_RST_MASK				BITFIELD(1, 1)
+#define OMAP4430_GLOBAL_WARM_SW_RST_MASK				(1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_GLOBAL_WUEN_SHIFT					16
-#define OMAP4430_GLOBAL_WUEN_MASK					BITFIELD(16, 16)
+#define OMAP4430_GLOBAL_WUEN_MASK					(1 << 16)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_HSMCODE_SHIFT						0
-#define OMAP4430_HSMCODE_MASK						BITFIELD(0, 2)
+#define OMAP4430_HSMCODE_MASK						(0x7 << 0)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_HSMODEEN_SHIFT						3
-#define OMAP4430_HSMODEEN_MASK						BITFIELD(3, 3)
+#define OMAP4430_HSMODEEN_MASK						(1 << 3)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_HSSCLH_SHIFT						16
-#define OMAP4430_HSSCLH_MASK						BITFIELD(16, 23)
+#define OMAP4430_HSSCLH_MASK						(0xff << 16)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_HSSCLL_SHIFT						24
-#define OMAP4430_HSSCLL_MASK						BITFIELD(24, 31)
+#define OMAP4430_HSSCLL_MASK						(0xff << 24)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_HWA_MEM_ONSTATE_SHIFT					16
-#define OMAP4430_HWA_MEM_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_HWA_MEM_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_HWA_MEM_RETSTATE_SHIFT					8
-#define OMAP4430_HWA_MEM_RETSTATE_MASK					BITFIELD(8, 8)
+#define OMAP4430_HWA_MEM_RETSTATE_MASK					(1 << 8)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_HWA_MEM_STATEST_SHIFT					4
-#define OMAP4430_HWA_MEM_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_HWA_MEM_STATEST_MASK					(0x3 << 4)
 
 /* Used by RM_MPU_RSTST */
 #define OMAP4430_ICECRUSHER_MPU_RST_SHIFT				1
-#define OMAP4430_ICECRUSHER_MPU_RST_MASK				BITFIELD(1, 1)
+#define OMAP4430_ICECRUSHER_MPU_RST_MASK				(1 << 1)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_ICECRUSHER_RST1ST_SHIFT				5
-#define OMAP4430_ICECRUSHER_RST1ST_MASK					BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_RST1ST_MASK					(1 << 5)
 
 /* Used by RM_DUCATI_RSTST */
 #define OMAP4430_ICECRUSHER_RST2ST_SHIFT				6
-#define OMAP4430_ICECRUSHER_RST2ST_MASK					BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_RST2ST_MASK					(1 << 6)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_ICECRUSHER_SEQ1_RST1ST_SHIFT				5
-#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK				BITFIELD(5, 5)
+#define OMAP4430_ICECRUSHER_SEQ1_RST1ST_MASK				(1 << 5)
 
 /* Used by RM_IVAHD_RSTST */
 #define OMAP4430_ICECRUSHER_SEQ2_RST2ST_SHIFT				6
-#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK				BITFIELD(6, 6)
+#define OMAP4430_ICECRUSHER_SEQ2_RST2ST_MASK				(1 << 6)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_ICEPICK_RST_SHIFT					9
-#define OMAP4430_ICEPICK_RST_MASK					BITFIELD(9, 9)
+#define OMAP4430_ICEPICK_RST_MASK					(1 << 9)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_INITVDD_SHIFT						2
-#define OMAP4430_INITVDD_MASK						BITFIELD(2, 2)
+#define OMAP4430_INITVDD_MASK						(1 << 2)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_INITVOLTAGE_SHIFT					8
-#define OMAP4430_INITVOLTAGE_MASK					BITFIELD(8, 15)
+#define OMAP4430_INITVOLTAGE_MASK					(0xff << 8)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_INTRANSITION_SHIFT					20
-#define OMAP4430_INTRANSITION_MASK					BITFIELD(20, 20)
+#define OMAP4430_INTRANSITION_MASK					(1 << 20)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_IO_EN_SHIFT						9
-#define OMAP4430_IO_EN_MASK						BITFIELD(9, 9)
+#define OMAP4430_IO_EN_MASK						(1 << 9)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_IO_ON_STATUS_SHIFT					5
-#define OMAP4430_IO_ON_STATUS_MASK					BITFIELD(5, 5)
+#define OMAP4430_IO_ON_STATUS_MASK					(1 << 5)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_IO_ST_SHIFT						9
-#define OMAP4430_IO_ST_MASK						BITFIELD(9, 9)
+#define OMAP4430_IO_ST_MASK						(1 << 9)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOCLK_OVERRIDE_SHIFT					0
-#define OMAP4430_ISOCLK_OVERRIDE_MASK					BITFIELD(0, 0)
+#define OMAP4430_ISOCLK_OVERRIDE_MASK					(1 << 0)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOCLK_STATUS_SHIFT					1
-#define OMAP4430_ISOCLK_STATUS_MASK					BITFIELD(1, 1)
+#define OMAP4430_ISOCLK_STATUS_MASK					(1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_ISOOVR_EXTEND_SHIFT					4
-#define OMAP4430_ISOOVR_EXTEND_MASK					BITFIELD(4, 4)
+#define OMAP4430_ISOOVR_EXTEND_MASK					(1 << 4)
 
 /* Used by PRM_IO_COUNT */
 #define OMAP4430_ISO_2_ON_TIME_SHIFT					0
-#define OMAP4430_ISO_2_ON_TIME_MASK					BITFIELD(0, 7)
+#define OMAP4430_ISO_2_ON_TIME_MASK					(0xff << 0)
 
 /* Used by PM_L3INIT_PWRSTCTRL */
 #define OMAP4430_L3INIT_BANK1_ONSTATE_SHIFT				16
-#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK				BITFIELD(16, 17)
+#define OMAP4430_L3INIT_BANK1_ONSTATE_MASK				(0x3 << 16)
 
 /* Used by PM_L3INIT_PWRSTCTRL */
 #define OMAP4430_L3INIT_BANK1_RETSTATE_SHIFT				8
-#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK				BITFIELD(8, 8)
+#define OMAP4430_L3INIT_BANK1_RETSTATE_MASK				(1 << 8)
 
 /* Used by PM_L3INIT_PWRSTST */
 #define OMAP4430_L3INIT_BANK1_STATEST_SHIFT				4
-#define OMAP4430_L3INIT_BANK1_STATEST_MASK				BITFIELD(4, 5)
+#define OMAP4430_L3INIT_BANK1_STATEST_MASK				(0x3 << 4)
 
 /*
- * Used by PM_CORE_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL,
- * PM_MPU_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL,
- * PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTST, PM_CORE_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
+ */
+#define OMAP4430_LASTPOWERSTATEENTERED_SHIFT				24
+#define OMAP4430_LASTPOWERSTATEENTERED_MASK				(0x3 << 24)
+
+/*
+ * Used by PM_ABE_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_LOGICRETSTATE_SHIFT					2
-#define OMAP4430_LOGICRETSTATE_MASK					BITFIELD(2, 2)
+#define OMAP4430_LOGICRETSTATE_MASK					(1 << 2)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_LOGICSTATEST_SHIFT					2
-#define OMAP4430_LOGICSTATEST_MASK					BITFIELD(2, 2)
+#define OMAP4430_LOGICSTATEST_MASK					(1 << 2)
 
 /*
- * Used by RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT,
- * RM_WKUP_L4WKUP_CONTEXT, RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT,
- * RM_WKUP_SYNCTIMER_CONTEXT, RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT,
- * RM_WKUP_USIM_CONTEXT, RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT,
- * RM_EMU_DEBUGSS_CONTEXT, RM_D2D_SAD2D_CONTEXT, RM_D2D_SAD2D_FW_CONTEXT,
- * RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
- * RM_L3INSTR_L3_INSTR_CONTEXT, RM_L3INSTR_OCP_WP1_CONTEXT,
- * RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT, RM_L3_2_OCMC_RAM_CONTEXT,
- * RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT, RM_MEMIF_DLL_CONTEXT,
- * RM_MEMIF_DLL_H_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT,
- * RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
- * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
- * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
- * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
- * RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
+ * Used by RM_ABE_AESS_CONTEXT, RM_ABE_DMIC_CONTEXT, RM_ABE_MCASP_CONTEXT,
  * RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT, RM_ABE_MCBSP3_CONTEXT,
  * RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT, RM_ABE_TIMER5_CONTEXT,
  * RM_ABE_TIMER6_CONTEXT, RM_ABE_TIMER7_CONTEXT, RM_ABE_TIMER8_CONTEXT,
- * RM_ABE_WDT3_CONTEXT, RM_GFX_GFX_CONTEXT, RM_MPU_MPU_CONTEXT,
- * RM_CEFUSE_CEFUSE_CONTEXT, RM_ALWON_MDMINTC_CONTEXT,
- * RM_ALWON_SR_CORE_CONTEXT, RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT,
- * RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT, RM_L4PER_ADC_CONTEXT,
- * RM_L4PER_DMTIMER10_CONTEXT, RM_L4PER_DMTIMER11_CONTEXT,
- * RM_L4PER_DMTIMER2_CONTEXT, RM_L4PER_DMTIMER3_CONTEXT,
- * RM_L4PER_DMTIMER4_CONTEXT, RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT,
- * RM_L4PER_HDQ1W_CONTEXT, RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
- * RM_L4PER_I2C2_CONTEXT, RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT,
- * RM_L4PER_I2C5_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT,
- * RM_L4PER_MCASP3_CONTEXT, RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT,
- * RM_L4PER_MCSPI2_CONTEXT, RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT,
- * RM_L4PER_MGATE_CONTEXT, RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT,
- * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_MSPROHG_CONTEXT,
- * RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT,
- * RM_TESLA_TESLA_CONTEXT, RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT
+ * RM_ABE_WDT3_CONTEXT, RM_ALWON_MDMINTC_CONTEXT, RM_ALWON_SR_CORE_CONTEXT,
+ * RM_ALWON_SR_IVA_CONTEXT, RM_ALWON_SR_MPU_CONTEXT, RM_CAM_FDIF_CONTEXT,
+ * RM_CAM_ISS_CONTEXT, RM_CEFUSE_CEFUSE_CONTEXT, RM_D2D_SAD2D_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT,
+ * RM_DUCATI_DUCATI_CONTEXT, RM_EMU_DEBUGSS_CONTEXT, RM_GFX_GFX_CONTEXT,
+ * RM_IVAHD_IVAHD_CONTEXT, RM_IVAHD_SL2_CONTEXT, RM_L3INIT_CCPTX_CONTEXT,
+ * RM_L3INIT_EMAC_CONTEXT, RM_L3INIT_P1500_CONTEXT, RM_L3INIT_PCIESS_CONTEXT,
+ * RM_L3INIT_SATA_CONTEXT, RM_L3INIT_TPPSS_CONTEXT, RM_L3INIT_UNIPRO1_CONTEXT,
+ * RM_L3INIT_USBPHYOCP2SCP_CONTEXT, RM_L3INIT_XHPI_CONTEXT,
+ * RM_L3INSTR_L3_3_CONTEXT, RM_L3INSTR_L3_INSTR_CONTEXT,
+ * RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_L3_2_CONTEXT,
+ * RM_L3_2_OCMC_RAM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT, RM_L4CFG_SAR_ROM_CONTEXT,
+ * RM_L4PER_ADC_CONTEXT, RM_L4PER_DMTIMER10_CONTEXT,
+ * RM_L4PER_DMTIMER11_CONTEXT, RM_L4PER_DMTIMER2_CONTEXT,
+ * RM_L4PER_DMTIMER3_CONTEXT, RM_L4PER_DMTIMER4_CONTEXT,
+ * RM_L4PER_DMTIMER9_CONTEXT, RM_L4PER_ELM_CONTEXT, RM_L4PER_HDQ1W_CONTEXT,
+ * RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT, RM_L4PER_I2C2_CONTEXT,
+ * RM_L4PER_I2C3_CONTEXT, RM_L4PER_I2C4_CONTEXT, RM_L4PER_I2C5_CONTEXT,
+ * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_MCASP2_CONTEXT, RM_L4PER_MCASP3_CONTEXT,
+ * RM_L4PER_MCBSP4_CONTEXT, RM_L4PER_MCSPI1_CONTEXT, RM_L4PER_MCSPI2_CONTEXT,
+ * RM_L4PER_MCSPI3_CONTEXT, RM_L4PER_MCSPI4_CONTEXT, RM_L4PER_MGATE_CONTEXT,
+ * RM_L4PER_MMCSD3_CONTEXT, RM_L4PER_MMCSD4_CONTEXT, RM_L4PER_MMCSD5_CONTEXT,
+ * RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT,
+ * RM_L4SEC_PKAEIP29_CONTEXT, RM_MEMIF_DLL_CONTEXT, RM_MEMIF_DLL_H_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MPU_MPU_CONTEXT, RM_TESLA_TESLA_CONTEXT,
+ * RM_WKUP_GPIO1_CONTEXT, RM_WKUP_KEYBOARD_CONTEXT, RM_WKUP_L4WKUP_CONTEXT,
+ * RM_WKUP_RTC_CONTEXT, RM_WKUP_SARRAM_CONTEXT, RM_WKUP_SYNCTIMER_CONTEXT,
+ * RM_WKUP_TIMER12_CONTEXT, RM_WKUP_TIMER1_CONTEXT, RM_WKUP_USIM_CONTEXT,
+ * RM_WKUP_WDT1_CONTEXT, RM_WKUP_WDT2_CONTEXT
  */
 #define OMAP4430_LOSTCONTEXT_DFF_SHIFT					0
-#define OMAP4430_LOSTCONTEXT_DFF_MASK					BITFIELD(0, 0)
+#define OMAP4430_LOSTCONTEXT_DFF_MASK					(1 << 0)
 
 /*
  * Used by RM_D2D_MODEM_ICR_CONTEXT, RM_D2D_SAD2D_CONTEXT,
- * RM_D2D_SAD2D_FW_CONTEXT, RM_DUCATI_DUCATI_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
+ * RM_D2D_SAD2D_FW_CONTEXT, RM_DSS_DSS_CONTEXT, RM_DUCATI_DUCATI_CONTEXT,
+ * RM_L3INIT_HSI_CONTEXT, RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT,
+ * RM_L3INIT_MMC6_CONTEXT, RM_L3INIT_USB_HOST_CONTEXT,
+ * RM_L3INIT_USB_HOST_FS_CONTEXT, RM_L3INIT_USB_OTG_CONTEXT,
+ * RM_L3INIT_USB_TLL_CONTEXT, RM_L3INSTR_L3_3_CONTEXT,
  * RM_L3INSTR_OCP_WP1_CONTEXT, RM_L3_1_L3_1_CONTEXT, RM_L3_2_GPMC_CONTEXT,
  * RM_L3_2_L3_2_CONTEXT, RM_L4CFG_HW_SEM_CONTEXT, RM_L4CFG_L4_CFG_CONTEXT,
- * RM_L4CFG_MAILBOX_CONTEXT, RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT,
- * RM_MEMIF_EMIF_2_CONTEXT, RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
- * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_L3INIT_HSI_CONTEXT,
- * RM_L3INIT_MMC1_CONTEXT, RM_L3INIT_MMC2_CONTEXT, RM_L3INIT_MMC6_CONTEXT,
- * RM_L3INIT_USB_HOST_CONTEXT, RM_L3INIT_USB_HOST_FS_CONTEXT,
- * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_USB_TLL_CONTEXT, RM_DSS_DSS_CONTEXT,
- * RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT, RM_L4PER_GPIO4_CONTEXT,
- * RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT, RM_L4PER_I2C1_CONTEXT,
- * RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT, RM_L4PER_UART2_CONTEXT,
- * RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT, RM_L4SEC_AES1_CONTEXT,
- * RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT, RM_L4SEC_DES3DES_CONTEXT,
- * RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT, RM_TESLA_TESLA_CONTEXT
+ * RM_L4CFG_MAILBOX_CONTEXT, RM_L4PER_GPIO2_CONTEXT, RM_L4PER_GPIO3_CONTEXT,
+ * RM_L4PER_GPIO4_CONTEXT, RM_L4PER_GPIO5_CONTEXT, RM_L4PER_GPIO6_CONTEXT,
+ * RM_L4PER_I2C1_CONTEXT, RM_L4PER_L4_PER_CONTEXT, RM_L4PER_UART1_CONTEXT,
+ * RM_L4PER_UART2_CONTEXT, RM_L4PER_UART3_CONTEXT, RM_L4PER_UART4_CONTEXT,
+ * RM_L4SEC_AES1_CONTEXT, RM_L4SEC_AES2_CONTEXT, RM_L4SEC_CRYPTODMA_CONTEXT,
+ * RM_L4SEC_DES3DES_CONTEXT, RM_L4SEC_RNG_CONTEXT, RM_L4SEC_SHA2MD51_CONTEXT,
+ * RM_MEMIF_DMM_CONTEXT, RM_MEMIF_EMIF_1_CONTEXT, RM_MEMIF_EMIF_2_CONTEXT,
+ * RM_MEMIF_EMIF_FW_CONTEXT, RM_MEMIF_EMIF_H1_CONTEXT,
+ * RM_MEMIF_EMIF_H2_CONTEXT, RM_SDMA_SDMA_CONTEXT, RM_TESLA_TESLA_CONTEXT
  */
 #define OMAP4430_LOSTCONTEXT_RFF_SHIFT					1
-#define OMAP4430_LOSTCONTEXT_RFF_MASK					BITFIELD(1, 1)
+#define OMAP4430_LOSTCONTEXT_RFF_MASK					(1 << 1)
 
 /* Used by RM_ABE_AESS_CONTEXT */
 #define OMAP4430_LOSTMEM_AESSMEM_SHIFT					8
-#define OMAP4430_LOSTMEM_AESSMEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_AESSMEM_MASK					(1 << 8)
 
 /* Used by RM_CAM_FDIF_CONTEXT, RM_CAM_ISS_CONTEXT */
 #define OMAP4430_LOSTMEM_CAM_MEM_SHIFT					8
-#define OMAP4430_LOSTMEM_CAM_MEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CAM_MEM_MASK					(1 << 8)
 
 /* Used by RM_L3INSTR_OCP_WP1_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_SHIFT				8
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_MASK				(1 << 8)
 
 /* Renamed from LOSTMEM_CORE_NRET_BANK Used by RM_MEMIF_DMM_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_SHIFT			9
-#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK			BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_CORE_NRET_BANK_9_9_MASK			(1 << 9)
 
 /* Used by RM_L3_2_OCMC_RAM_CONTEXT */
 #define OMAP4430_LOSTMEM_CORE_OCMRAM_SHIFT				8
-#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OCMRAM_MASK				(1 << 8)
 
 /*
  * Used by RM_D2D_MODEM_ICR_CONTEXT, RM_MEMIF_DMM_CONTEXT,
  * RM_SDMA_SDMA_CONTEXT
  */
 #define OMAP4430_LOSTMEM_CORE_OTHER_BANK_SHIFT				8
-#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_CORE_OTHER_BANK_MASK				(1 << 8)
 
 /* Used by RM_DSS_DEISS_CONTEXT, RM_DSS_DSS_CONTEXT */
 #define OMAP4430_LOSTMEM_DSS_MEM_SHIFT					8
-#define OMAP4430_LOSTMEM_DSS_MEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DSS_MEM_MASK					(1 << 8)
 
 /* Used by RM_DUCATI_DUCATI_CONTEXT */
 #define OMAP4430_LOSTMEM_DUCATI_L2RAM_SHIFT				9
-#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK				BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_DUCATI_L2RAM_MASK				(1 << 9)
 
 /* Used by RM_DUCATI_DUCATI_CONTEXT */
 #define OMAP4430_LOSTMEM_DUCATI_UNICACHE_SHIFT				8
-#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_DUCATI_UNICACHE_MASK				(1 << 8)
 
 /* Used by RM_EMU_DEBUGSS_CONTEXT */
 #define OMAP4430_LOSTMEM_EMU_BANK_SHIFT					8
-#define OMAP4430_LOSTMEM_EMU_BANK_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_EMU_BANK_MASK					(1 << 8)
 
 /* Used by RM_GFX_GFX_CONTEXT */
 #define OMAP4430_LOSTMEM_GFX_MEM_SHIFT					8
-#define OMAP4430_LOSTMEM_GFX_MEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_GFX_MEM_MASK					(1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_HWA_MEM_SHIFT					10
-#define OMAP4430_LOSTMEM_HWA_MEM_MASK					BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_HWA_MEM_MASK					(1 << 10)
 
 /*
  * Used by RM_L3INIT_CCPTX_CONTEXT, RM_L3INIT_EMAC_CONTEXT,
@@ -620,19 +644,19 @@
  * RM_L3INIT_USB_OTG_CONTEXT, RM_L3INIT_XHPI_CONTEXT
  */
 #define OMAP4430_LOSTMEM_L3INIT_BANK1_SHIFT				8
-#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_L3INIT_BANK1_MASK				(1 << 8)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_L1_SHIFT					8
-#define OMAP4430_LOSTMEM_MPU_L1_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_MPU_L1_MASK					(1 << 8)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_L2_SHIFT					9
-#define OMAP4430_LOSTMEM_MPU_L2_MASK					BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_MPU_L2_MASK					(1 << 9)
 
 /* Used by RM_MPU_MPU_CONTEXT */
 #define OMAP4430_LOSTMEM_MPU_RAM_SHIFT					10
-#define OMAP4430_LOSTMEM_MPU_RAM_MASK					BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_MPU_RAM_MASK					(1 << 10)
 
 /*
  * Used by RM_L4PER_HECC1_CONTEXT, RM_L4PER_HECC2_CONTEXT,
@@ -640,14 +664,14 @@
  * RM_L4PER_MMCSD5_CONTEXT, RM_L4PER_SLIMBUS2_CONTEXT, RM_L4SEC_PKAEIP29_CONTEXT
  */
 #define OMAP4430_LOSTMEM_NONRETAINED_BANK_SHIFT				8
-#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_NONRETAINED_BANK_MASK				(1 << 8)
 
 /*
  * Used by RM_ABE_DMIC_CONTEXT, RM_ABE_MCBSP1_CONTEXT, RM_ABE_MCBSP2_CONTEXT,
  * RM_ABE_MCBSP3_CONTEXT, RM_ABE_PDM_CONTEXT, RM_ABE_SLIMBUS_CONTEXT
  */
 #define OMAP4430_LOSTMEM_PERIHPMEM_SHIFT				8
-#define OMAP4430_LOSTMEM_PERIHPMEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_PERIHPMEM_MASK					(1 << 8)
 
 /*
  * Used by RM_L4PER_MSPROHG_CONTEXT, RM_L4PER_UART1_CONTEXT,
@@ -655,245 +679,237 @@
  * RM_L4SEC_CRYPTODMA_CONTEXT
  */
 #define OMAP4430_LOSTMEM_RETAINED_BANK_SHIFT				8
-#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK				BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_RETAINED_BANK_MASK				(1 << 8)
 
 /* Used by RM_IVAHD_SL2_CONTEXT */
 #define OMAP4430_LOSTMEM_SL2_MEM_SHIFT					8
-#define OMAP4430_LOSTMEM_SL2_MEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_SL2_MEM_MASK					(1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_TCM1_MEM_SHIFT					8
-#define OMAP4430_LOSTMEM_TCM1_MEM_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TCM1_MEM_MASK					(1 << 8)
 
 /* Used by RM_IVAHD_IVAHD_CONTEXT */
 #define OMAP4430_LOSTMEM_TCM2_MEM_SHIFT					9
-#define OMAP4430_LOSTMEM_TCM2_MEM_MASK					BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TCM2_MEM_MASK					(1 << 9)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_EDMA_SHIFT				10
-#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK				BITFIELD(10, 10)
+#define OMAP4430_LOSTMEM_TESLA_EDMA_MASK				(1 << 10)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_L1_SHIFT					8
-#define OMAP4430_LOSTMEM_TESLA_L1_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_TESLA_L1_MASK					(1 << 8)
 
 /* Used by RM_TESLA_TESLA_CONTEXT */
 #define OMAP4430_LOSTMEM_TESLA_L2_SHIFT					9
-#define OMAP4430_LOSTMEM_TESLA_L2_MASK					BITFIELD(9, 9)
+#define OMAP4430_LOSTMEM_TESLA_L2_MASK					(1 << 9)
 
 /* Used by RM_WKUP_SARRAM_CONTEXT */
 #define OMAP4430_LOSTMEM_WKUP_BANK_SHIFT				8
-#define OMAP4430_LOSTMEM_WKUP_BANK_MASK					BITFIELD(8, 8)
+#define OMAP4430_LOSTMEM_WKUP_BANK_MASK					(1 << 8)
 
 /*
- * Used by PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_L3INIT_PWRSTCTRL,
- * PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
- * PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_IVAHD_PWRSTCTRL,
+ * PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL, PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_LOWPOWERSTATECHANGE_SHIFT				4
-#define OMAP4430_LOWPOWERSTATECHANGE_MASK				BITFIELD(4, 4)
-
-/* Used by PM_CORE_PWRSTCTRL */
-#define OMAP4430_MEMORYCHANGE_SHIFT					3
-#define OMAP4430_MEMORYCHANGE_MASK					BITFIELD(3, 3)
+#define OMAP4430_LOWPOWERSTATECHANGE_MASK				(1 << 4)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_READY_SHIFT					1
-#define OMAP4430_MODEM_READY_MASK					BITFIELD(1, 1)
+#define OMAP4430_MODEM_READY_MASK					(1 << 1)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_SHUTDOWN_IRQ_SHIFT				9
-#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK				BITFIELD(9, 9)
+#define OMAP4430_MODEM_SHUTDOWN_IRQ_MASK				(1 << 9)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_SLEEP_ST_SHIFT					16
-#define OMAP4430_MODEM_SLEEP_ST_MASK					BITFIELD(16, 16)
+#define OMAP4430_MODEM_SLEEP_ST_MASK					(1 << 16)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_MODEM_WAKE_IRQ_SHIFT					8
-#define OMAP4430_MODEM_WAKE_IRQ_MASK					BITFIELD(8, 8)
+#define OMAP4430_MODEM_WAKE_IRQ_MASK					(1 << 8)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L1_ONSTATE_SHIFT					16
-#define OMAP4430_MPU_L1_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_MPU_L1_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L1_RETSTATE_SHIFT					8
-#define OMAP4430_MPU_L1_RETSTATE_MASK					BITFIELD(8, 8)
+#define OMAP4430_MPU_L1_RETSTATE_MASK					(1 << 8)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_L1_STATEST_SHIFT					4
-#define OMAP4430_MPU_L1_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_MPU_L1_STATEST_MASK					(0x3 << 4)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L2_ONSTATE_SHIFT					18
-#define OMAP4430_MPU_L2_ONSTATE_MASK					BITFIELD(18, 19)
+#define OMAP4430_MPU_L2_ONSTATE_MASK					(0x3 << 18)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_L2_RETSTATE_SHIFT					9
-#define OMAP4430_MPU_L2_RETSTATE_MASK					BITFIELD(9, 9)
+#define OMAP4430_MPU_L2_RETSTATE_MASK					(1 << 9)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_L2_STATEST_SHIFT					6
-#define OMAP4430_MPU_L2_STATEST_MASK					BITFIELD(6, 7)
+#define OMAP4430_MPU_L2_STATEST_MASK					(0x3 << 6)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_RAM_ONSTATE_SHIFT					20
-#define OMAP4430_MPU_RAM_ONSTATE_MASK					BITFIELD(20, 21)
+#define OMAP4430_MPU_RAM_ONSTATE_MASK					(0x3 << 20)
 
 /* Used by PM_MPU_PWRSTCTRL */
 #define OMAP4430_MPU_RAM_RETSTATE_SHIFT					10
-#define OMAP4430_MPU_RAM_RETSTATE_MASK					BITFIELD(10, 10)
+#define OMAP4430_MPU_RAM_RETSTATE_MASK					(1 << 10)
 
 /* Used by PM_MPU_PWRSTST */
 #define OMAP4430_MPU_RAM_STATEST_SHIFT					8
-#define OMAP4430_MPU_RAM_STATEST_MASK					BITFIELD(8, 9)
+#define OMAP4430_MPU_RAM_STATEST_MASK					(0x3 << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT				2
-#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK				BITFIELD(2, 2)
+#define OMAP4430_MPU_SECURITY_VIOL_RST_MASK				(1 << 2)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_MPU_WDT_RST_SHIFT					3
-#define OMAP4430_MPU_WDT_RST_MASK					BITFIELD(3, 3)
+#define OMAP4430_MPU_WDT_RST_MASK					(1 << 3)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_NONRETAINED_BANK_ONSTATE_SHIFT				18
-#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK				BITFIELD(18, 19)
+#define OMAP4430_NONRETAINED_BANK_ONSTATE_MASK				(0x3 << 18)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_NONRETAINED_BANK_RETSTATE_SHIFT			9
-#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK				BITFIELD(9, 9)
+#define OMAP4430_NONRETAINED_BANK_RETSTATE_MASK				(1 << 9)
 
 /* Used by PM_L4PER_PWRSTST */
 #define OMAP4430_NONRETAINED_BANK_STATEST_SHIFT				6
-#define OMAP4430_NONRETAINED_BANK_STATEST_MASK				BITFIELD(6, 7)
+#define OMAP4430_NONRETAINED_BANK_STATEST_MASK				(0x3 << 6)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_OCP_NRET_BANK_ONSTATE_SHIFT				24
-#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK				BITFIELD(24, 25)
+#define OMAP4430_OCP_NRET_BANK_ONSTATE_MASK				(0x3 << 24)
 
 /* Used by PM_CORE_PWRSTCTRL */
 #define OMAP4430_OCP_NRET_BANK_RETSTATE_SHIFT				12
-#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK				BITFIELD(12, 12)
+#define OMAP4430_OCP_NRET_BANK_RETSTATE_MASK				(1 << 12)
 
 /* Used by PM_CORE_PWRSTST */
 #define OMAP4430_OCP_NRET_BANK_STATEST_SHIFT				12
-#define OMAP4430_OCP_NRET_BANK_STATEST_MASK				BITFIELD(12, 13)
+#define OMAP4430_OCP_NRET_BANK_STATEST_MASK				(0x3 << 12)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_OFF_SHIFT						0
-#define OMAP4430_OFF_MASK						BITFIELD(0, 7)
-
-/* Used by PRM_LDO_BANDGAP_CTRL */
-#define OMAP4430_OFF_ENABLE_SHIFT					0
-#define OMAP4430_OFF_ENABLE_MASK					BITFIELD(0, 0)
+#define OMAP4430_OFF_MASK						(0xff << 0)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_ON_SHIFT						24
-#define OMAP4430_ON_MASK						BITFIELD(24, 31)
+#define OMAP4430_ON_MASK						(0xff << 24)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_ONLP_SHIFT						16
-#define OMAP4430_ONLP_MASK						BITFIELD(16, 23)
+#define OMAP4430_ONLP_MASK						(0xff << 16)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_OPP_CHANGE_SHIFT					2
-#define OMAP4430_OPP_CHANGE_MASK					BITFIELD(2, 2)
+#define OMAP4430_OPP_CHANGE_MASK					(1 << 2)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_OPP_SEL_SHIFT						0
-#define OMAP4430_OPP_SEL_MASK						BITFIELD(0, 1)
+#define OMAP4430_OPP_SEL_MASK						(0x3 << 0)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_PCHARGECNT_VALUE_SHIFT					0
-#define OMAP4430_PCHARGECNT_VALUE_MASK					BITFIELD(0, 5)
+#define OMAP4430_PCHARGECNT_VALUE_MASK					(0x3f << 0)
 
 /* Used by PRM_PSCON_COUNT */
 #define OMAP4430_PCHARGE_TIME_SHIFT					0
-#define OMAP4430_PCHARGE_TIME_MASK					BITFIELD(0, 7)
+#define OMAP4430_PCHARGE_TIME_MASK					(0xff << 0)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_PERIPHMEM_ONSTATE_SHIFT				20
-#define OMAP4430_PERIPHMEM_ONSTATE_MASK					BITFIELD(20, 21)
+#define OMAP4430_PERIPHMEM_ONSTATE_MASK					(0x3 << 20)
 
 /* Used by PM_ABE_PWRSTCTRL */
 #define OMAP4430_PERIPHMEM_RETSTATE_SHIFT				10
-#define OMAP4430_PERIPHMEM_RETSTATE_MASK				BITFIELD(10, 10)
+#define OMAP4430_PERIPHMEM_RETSTATE_MASK				(1 << 10)
 
 /* Used by PM_ABE_PWRSTST */
 #define OMAP4430_PERIPHMEM_STATEST_SHIFT				8
-#define OMAP4430_PERIPHMEM_STATEST_MASK					BITFIELD(8, 9)
+#define OMAP4430_PERIPHMEM_STATEST_MASK					(0x3 << 8)
 
 /* Used by PRM_PHASE1_CNDP */
 #define OMAP4430_PHASE1_CNDP_SHIFT					0
-#define OMAP4430_PHASE1_CNDP_MASK					BITFIELD(0, 31)
+#define OMAP4430_PHASE1_CNDP_MASK					(0xffffffff << 0)
 
 /* Used by PRM_PHASE2A_CNDP */
 #define OMAP4430_PHASE2A_CNDP_SHIFT					0
-#define OMAP4430_PHASE2A_CNDP_MASK					BITFIELD(0, 31)
+#define OMAP4430_PHASE2A_CNDP_MASK					(0xffffffff << 0)
 
 /* Used by PRM_PHASE2B_CNDP */
 #define OMAP4430_PHASE2B_CNDP_SHIFT					0
-#define OMAP4430_PHASE2B_CNDP_MASK					BITFIELD(0, 31)
+#define OMAP4430_PHASE2B_CNDP_MASK					(0xffffffff << 0)
 
 /* Used by PRM_PSCON_COUNT */
 #define OMAP4430_PONOUT_2_PGOODIN_TIME_SHIFT				8
-#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK				BITFIELD(8, 15)
+#define OMAP4430_PONOUT_2_PGOODIN_TIME_MASK				(0xff << 8)
 
 /*
- * Used by PM_EMU_PWRSTCTRL, PM_CORE_PWRSTCTRL, PM_CAM_PWRSTCTRL,
- * PM_L3INIT_PWRSTCTRL, PM_ABE_PWRSTCTRL, PM_GFX_PWRSTCTRL, PM_MPU_PWRSTCTRL,
- * PM_CEFUSE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
- * PM_TESLA_PWRSTCTRL, PM_IVAHD_PWRSTCTRL
+ * Used by PM_ABE_PWRSTCTRL, PM_CAM_PWRSTCTRL, PM_CEFUSE_PWRSTCTRL,
+ * PM_CORE_PWRSTCTRL, PM_DSS_PWRSTCTRL, PM_EMU_PWRSTCTRL, PM_GFX_PWRSTCTRL,
+ * PM_IVAHD_PWRSTCTRL, PM_L3INIT_PWRSTCTRL, PM_L4PER_PWRSTCTRL,
+ * PM_MPU_PWRSTCTRL, PM_TESLA_PWRSTCTRL
  */
 #define OMAP4430_POWERSTATE_SHIFT					0
-#define OMAP4430_POWERSTATE_MASK					BITFIELD(0, 1)
+#define OMAP4430_POWERSTATE_MASK					(0x3 << 0)
 
 /*
- * Used by PM_EMU_PWRSTST, PM_CORE_PWRSTST, PM_CAM_PWRSTST, PM_L3INIT_PWRSTST,
- * PM_ABE_PWRSTST, PM_GFX_PWRSTST, PM_MPU_PWRSTST, PM_CEFUSE_PWRSTST,
- * PM_DSS_PWRSTST, PM_L4PER_PWRSTST, PM_TESLA_PWRSTST, PM_IVAHD_PWRSTST
+ * Used by PM_ABE_PWRSTST, PM_CAM_PWRSTST, PM_CEFUSE_PWRSTST, PM_CORE_PWRSTST,
+ * PM_DSS_PWRSTST, PM_EMU_PWRSTST, PM_GFX_PWRSTST, PM_IVAHD_PWRSTST,
+ * PM_L3INIT_PWRSTST, PM_L4PER_PWRSTST, PM_MPU_PWRSTST, PM_TESLA_PWRSTST
  */
 #define OMAP4430_POWERSTATEST_SHIFT					0
-#define OMAP4430_POWERSTATEST_MASK					BITFIELD(0, 1)
+#define OMAP4430_POWERSTATEST_MASK					(0x3 << 0)
 
 /* Used by PRM_PWRREQCTRL */
 #define OMAP4430_PWRREQ_COND_SHIFT					0
-#define OMAP4430_PWRREQ_COND_MASK					BITFIELD(0, 1)
+#define OMAP4430_PWRREQ_COND_MASK					(0x3 << 0)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_CORE_L_SHIFT					3
-#define OMAP4430_RACEN_VDD_CORE_L_MASK					BITFIELD(3, 3)
+#define OMAP4430_RACEN_VDD_CORE_L_MASK					(1 << 3)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_IVA_L_SHIFT					11
-#define OMAP4430_RACEN_VDD_IVA_L_MASK					BITFIELD(11, 11)
+#define OMAP4430_RACEN_VDD_IVA_L_MASK					(1 << 11)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RACEN_VDD_MPU_L_SHIFT					20
-#define OMAP4430_RACEN_VDD_MPU_L_MASK					BITFIELD(20, 20)
+#define OMAP4430_RACEN_VDD_MPU_L_MASK					(1 << 20)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_CORE_L_SHIFT					2
-#define OMAP4430_RAC_VDD_CORE_L_MASK					BITFIELD(2, 2)
+#define OMAP4430_RAC_VDD_CORE_L_MASK					(1 << 2)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_IVA_L_SHIFT					10
-#define OMAP4430_RAC_VDD_IVA_L_MASK					BITFIELD(10, 10)
+#define OMAP4430_RAC_VDD_IVA_L_MASK					(1 << 10)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAC_VDD_MPU_L_SHIFT					19
-#define OMAP4430_RAC_VDD_MPU_L_MASK					BITFIELD(19, 19)
+#define OMAP4430_RAC_VDD_MPU_L_MASK					(1 << 19)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -901,7 +917,7 @@
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_DOWN_COUNT_SHIFT					16
-#define OMAP4430_RAMP_DOWN_COUNT_MASK					BITFIELD(16, 21)
+#define OMAP4430_RAMP_DOWN_COUNT_MASK					(0x3f << 16)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -909,7 +925,7 @@
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_DOWN_PRESCAL_SHIFT				24
-#define OMAP4430_RAMP_DOWN_PRESCAL_MASK					BITFIELD(24, 25)
+#define OMAP4430_RAMP_DOWN_PRESCAL_MASK					(0x3 << 24)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -917,7 +933,7 @@
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_UP_COUNT_SHIFT					0
-#define OMAP4430_RAMP_UP_COUNT_MASK					BITFIELD(0, 5)
+#define OMAP4430_RAMP_UP_COUNT_MASK					(0x3f << 0)
 
 /*
  * Used by PRM_VOLTSETUP_CORE_OFF, PRM_VOLTSETUP_CORE_RET_SLEEP,
@@ -925,1281 +941,1381 @@
  * PRM_VOLTSETUP_MPU_RET_SLEEP
  */
 #define OMAP4430_RAMP_UP_PRESCAL_SHIFT					8
-#define OMAP4430_RAMP_UP_PRESCAL_MASK					BITFIELD(8, 9)
+#define OMAP4430_RAMP_UP_PRESCAL_MASK					(0x3 << 8)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_CORE_L_SHIFT					1
-#define OMAP4430_RAV_VDD_CORE_L_MASK					BITFIELD(1, 1)
+#define OMAP4430_RAV_VDD_CORE_L_MASK					(1 << 1)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_IVA_L_SHIFT					9
-#define OMAP4430_RAV_VDD_IVA_L_MASK					BITFIELD(9, 9)
+#define OMAP4430_RAV_VDD_IVA_L_MASK					(1 << 9)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_RAV_VDD_MPU_L_SHIFT					18
-#define OMAP4430_RAV_VDD_MPU_L_MASK					BITFIELD(18, 18)
+#define OMAP4430_RAV_VDD_MPU_L_MASK					(1 << 18)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_REGADDR_SHIFT						8
-#define OMAP4430_REGADDR_MASK						BITFIELD(8, 15)
+#define OMAP4430_REGADDR_MASK						(0xff << 8)
 
 /*
  * Used by PRM_VC_VAL_CMD_VDD_CORE_L, PRM_VC_VAL_CMD_VDD_IVA_L,
  * PRM_VC_VAL_CMD_VDD_MPU_L
  */
 #define OMAP4430_RET_SHIFT						8
-#define OMAP4430_RET_MASK						BITFIELD(8, 15)
+#define OMAP4430_RET_MASK						(0xff << 8)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_RETAINED_BANK_ONSTATE_SHIFT				16
-#define OMAP4430_RETAINED_BANK_ONSTATE_MASK				BITFIELD(16, 17)
+#define OMAP4430_RETAINED_BANK_ONSTATE_MASK				(0x3 << 16)
 
 /* Used by PM_L4PER_PWRSTCTRL */
 #define OMAP4430_RETAINED_BANK_RETSTATE_SHIFT				8
-#define OMAP4430_RETAINED_BANK_RETSTATE_MASK				BITFIELD(8, 8)
+#define OMAP4430_RETAINED_BANK_RETSTATE_MASK				(1 << 8)
 
 /* Used by PM_L4PER_PWRSTST */
 #define OMAP4430_RETAINED_BANK_STATEST_SHIFT				4
-#define OMAP4430_RETAINED_BANK_STATEST_MASK				BITFIELD(4, 5)
+#define OMAP4430_RETAINED_BANK_STATEST_MASK				(0x3 << 4)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_RETMODE_ENABLE_SHIFT					0
-#define OMAP4430_RETMODE_ENABLE_MASK					BITFIELD(0, 0)
-
-/* Used by REVISION_PRM */
-#define OMAP4430_REV_SHIFT						0
-#define OMAP4430_REV_MASK						BITFIELD(0, 7)
+#define OMAP4430_RETMODE_ENABLE_MASK					(1 << 0)
 
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
 #define OMAP4430_RST1_SHIFT						0
-#define OMAP4430_RST1_MASK						BITFIELD(0, 0)
+#define OMAP4430_RST1_MASK						(1 << 0)
 
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
 #define OMAP4430_RST1ST_SHIFT						0
-#define OMAP4430_RST1ST_MASK						BITFIELD(0, 0)
+#define OMAP4430_RST1ST_MASK						(1 << 0)
 
-/* Used by RM_DUCATI_RSTCTRL, RM_TESLA_RSTCTRL, RM_IVAHD_RSTCTRL */
+/* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL, RM_TESLA_RSTCTRL */
 #define OMAP4430_RST2_SHIFT						1
-#define OMAP4430_RST2_MASK						BITFIELD(1, 1)
+#define OMAP4430_RST2_MASK						(1 << 1)
 
-/* Used by RM_DUCATI_RSTST, RM_TESLA_RSTST, RM_IVAHD_RSTST */
+/* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST, RM_TESLA_RSTST */
 #define OMAP4430_RST2ST_SHIFT						1
-#define OMAP4430_RST2ST_MASK						BITFIELD(1, 1)
+#define OMAP4430_RST2ST_MASK						(1 << 1)
 
 /* Used by RM_DUCATI_RSTCTRL, RM_IVAHD_RSTCTRL */
 #define OMAP4430_RST3_SHIFT						2
-#define OMAP4430_RST3_MASK						BITFIELD(2, 2)
+#define OMAP4430_RST3_MASK						(1 << 2)
 
 /* Used by RM_DUCATI_RSTST, RM_IVAHD_RSTST */
 #define OMAP4430_RST3ST_SHIFT						2
-#define OMAP4430_RST3ST_MASK						BITFIELD(2, 2)
+#define OMAP4430_RST3ST_MASK						(1 << 2)
 
 /* Used by PRM_RSTTIME */
 #define OMAP4430_RSTTIME1_SHIFT						0
-#define OMAP4430_RSTTIME1_MASK						BITFIELD(0, 9)
+#define OMAP4430_RSTTIME1_MASK						(0x3ff << 0)
 
 /* Used by PRM_RSTTIME */
 #define OMAP4430_RSTTIME2_SHIFT						10
-#define OMAP4430_RSTTIME2_MASK						BITFIELD(10, 14)
+#define OMAP4430_RSTTIME2_MASK						(0x1f << 10)
 
 /* Used by PRM_RSTCTRL */
 #define OMAP4430_RST_GLOBAL_COLD_SW_SHIFT				1
-#define OMAP4430_RST_GLOBAL_COLD_SW_MASK				BITFIELD(1, 1)
+#define OMAP4430_RST_GLOBAL_COLD_SW_MASK				(1 << 1)
 
 /* Used by PRM_RSTCTRL */
 #define OMAP4430_RST_GLOBAL_WARM_SW_SHIFT				0
-#define OMAP4430_RST_GLOBAL_WARM_SW_MASK				BITFIELD(0, 0)
+#define OMAP4430_RST_GLOBAL_WARM_SW_MASK				(1 << 0)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_R_RTL_SHIFT						11
+#define OMAP4430_R_RTL_MASK						(0x1f << 11)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_CORE_L_SHIFT					0
-#define OMAP4430_SA_VDD_CORE_L_MASK					BITFIELD(0, 0)
+#define OMAP4430_SA_VDD_CORE_L_MASK					(1 << 0)
 
 /* Renamed from SA_VDD_CORE_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_CORE_L_0_6_SHIFT				0
-#define OMAP4430_SA_VDD_CORE_L_0_6_MASK					BITFIELD(0, 6)
+#define OMAP4430_SA_VDD_CORE_L_0_6_MASK					(0x7f << 0)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_IVA_L_SHIFT					8
-#define OMAP4430_SA_VDD_IVA_L_MASK					BITFIELD(8, 8)
+#define OMAP4430_SA_VDD_IVA_L_MASK					(1 << 8)
 
 /* Renamed from SA_VDD_IVA_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_SHIFT			8
-#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK			BITFIELD(8, 14)
+#define OMAP4430_SA_VDD_IVA_L_PRM_VC_SMPS_SA_MASK			(0x7f << 8)
 
 /* Used by PRM_VC_CFG_CHANNEL */
 #define OMAP4430_SA_VDD_MPU_L_SHIFT					16
-#define OMAP4430_SA_VDD_MPU_L_MASK					BITFIELD(16, 16)
+#define OMAP4430_SA_VDD_MPU_L_MASK					(1 << 16)
 
 /* Renamed from SA_VDD_MPU_L Used by PRM_VC_SMPS_SA */
 #define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_SHIFT			16
-#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK			BITFIELD(16, 22)
+#define OMAP4430_SA_VDD_MPU_L_PRM_VC_SMPS_SA_MASK			(0x7f << 16)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_SCHEME_SHIFT						30
+#define OMAP4430_SCHEME_MASK						(0x3 << 30)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_SCLH_SHIFT						0
-#define OMAP4430_SCLH_MASK						BITFIELD(0, 7)
+#define OMAP4430_SCLH_MASK						(0xff << 0)
 
 /* Used by PRM_VC_CFG_I2C_CLK */
 #define OMAP4430_SCLL_SHIFT						8
-#define OMAP4430_SCLL_MASK						BITFIELD(8, 15)
+#define OMAP4430_SCLL_MASK						(0xff << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_SECURE_WDT_RST_SHIFT					4
-#define OMAP4430_SECURE_WDT_RST_MASK					BITFIELD(4, 4)
+#define OMAP4430_SECURE_WDT_RST_MASK					(1 << 4)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_SL2_MEM_ONSTATE_SHIFT					18
-#define OMAP4430_SL2_MEM_ONSTATE_MASK					BITFIELD(18, 19)
+#define OMAP4430_SL2_MEM_ONSTATE_MASK					(0x3 << 18)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_SL2_MEM_RETSTATE_SHIFT					9
-#define OMAP4430_SL2_MEM_RETSTATE_MASK					BITFIELD(9, 9)
+#define OMAP4430_SL2_MEM_RETSTATE_MASK					(1 << 9)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_SL2_MEM_STATEST_SHIFT					6
-#define OMAP4430_SL2_MEM_STATEST_MASK					BITFIELD(6, 7)
+#define OMAP4430_SL2_MEM_STATEST_MASK					(0x3 << 6)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_SLAVEADDR_SHIFT					0
-#define OMAP4430_SLAVEADDR_MASK						BITFIELD(0, 6)
+#define OMAP4430_SLAVEADDR_MASK						(0x7f << 0)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SLEEP_RBB_SEL_SHIFT					3
-#define OMAP4430_SLEEP_RBB_SEL_MASK					BITFIELD(3, 3)
+#define OMAP4430_SLEEP_RBB_SEL_MASK					(1 << 3)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_SLPCNT_VALUE_SHIFT					16
-#define OMAP4430_SLPCNT_VALUE_MASK					BITFIELD(16, 23)
+#define OMAP4430_SLPCNT_VALUE_MASK					(0xff << 16)
 
 /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
 #define OMAP4430_SMPSWAITTIMEMAX_SHIFT					8
-#define OMAP4430_SMPSWAITTIMEMAX_MASK					BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMAX_MASK					(0xffff << 8)
 
 /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
 #define OMAP4430_SMPSWAITTIMEMIN_SHIFT					8
-#define OMAP4430_SMPSWAITTIMEMIN_MASK					BITFIELD(8, 23)
+#define OMAP4430_SMPSWAITTIMEMIN_MASK					(0xffff << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_CORE_SHIFT					1
+#define OMAP4430_SMPS_RA_ERR_CORE_MASK					(1 << 1)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_IVA_SHIFT					9
+#define OMAP4430_SMPS_RA_ERR_IVA_MASK					(1 << 9)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_RA_ERR_MPU_SHIFT					17
+#define OMAP4430_SMPS_RA_ERR_MPU_MASK					(1 << 17)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_CORE_SHIFT					0
+#define OMAP4430_SMPS_SA_ERR_CORE_MASK					(1 << 0)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_IVA_SHIFT					8
+#define OMAP4430_SMPS_SA_ERR_IVA_MASK					(1 << 8)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_SA_ERR_MPU_SHIFT					16
+#define OMAP4430_SMPS_SA_ERR_MPU_MASK					(1 << 16)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_SHIFT				2
+#define OMAP4430_SMPS_TIMEOUT_ERR_CORE_MASK				(1 << 2)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_SHIFT				10
+#define OMAP4430_SMPS_TIMEOUT_ERR_IVA_MASK				(1 << 10)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_SHIFT				18
+#define OMAP4430_SMPS_TIMEOUT_ERR_MPU_MASK				(1 << 18)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SR2EN_SHIFT						0
-#define OMAP4430_SR2EN_MASK						BITFIELD(0, 0)
+#define OMAP4430_SR2EN_MASK						(1 << 0)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_SR2_IN_TRANSITION_SHIFT				6
-#define OMAP4430_SR2_IN_TRANSITION_MASK					BITFIELD(6, 6)
+#define OMAP4430_SR2_IN_TRANSITION_MASK					(1 << 6)
 
 /* Used by PRM_LDO_ABB_IVA_CTRL, PRM_LDO_ABB_MPU_CTRL */
 #define OMAP4430_SR2_STATUS_SHIFT					3
-#define OMAP4430_SR2_STATUS_MASK					BITFIELD(3, 4)
+#define OMAP4430_SR2_STATUS_MASK					(0x3 << 3)
 
 /* Used by PRM_LDO_ABB_IVA_SETUP, PRM_LDO_ABB_MPU_SETUP */
 #define OMAP4430_SR2_WTCNT_VALUE_SHIFT					8
-#define OMAP4430_SR2_WTCNT_VALUE_MASK					BITFIELD(8, 15)
+#define OMAP4430_SR2_WTCNT_VALUE_MASK					(0xff << 8)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_SRAMLDO_STATUS_SHIFT					8
-#define OMAP4430_SRAMLDO_STATUS_MASK					BITFIELD(8, 8)
+#define OMAP4430_SRAMLDO_STATUS_MASK					(1 << 8)
 
 /*
  * Used by PRM_LDO_SRAM_CORE_CTRL, PRM_LDO_SRAM_IVA_CTRL,
  * PRM_LDO_SRAM_MPU_CTRL
  */
 #define OMAP4430_SRAM_IN_TRANSITION_SHIFT				9
-#define OMAP4430_SRAM_IN_TRANSITION_MASK				BITFIELD(9, 9)
+#define OMAP4430_SRAM_IN_TRANSITION_MASK				(1 << 9)
 
 /* Used by PRM_VC_CFG_I2C_MODE */
 #define OMAP4430_SRMODEEN_SHIFT						4
-#define OMAP4430_SRMODEEN_MASK						BITFIELD(4, 4)
+#define OMAP4430_SRMODEEN_MASK						(1 << 4)
 
 /* Used by PRM_VOLTSETUP_WARMRESET */
 #define OMAP4430_STABLE_COUNT_SHIFT					0
-#define OMAP4430_STABLE_COUNT_MASK					BITFIELD(0, 5)
+#define OMAP4430_STABLE_COUNT_MASK					(0x3f << 0)
 
 /* Used by PRM_VOLTSETUP_WARMRESET */
 #define OMAP4430_STABLE_PRESCAL_SHIFT					8
-#define OMAP4430_STABLE_PRESCAL_MASK					BITFIELD(8, 9)
+#define OMAP4430_STABLE_PRESCAL_MASK					(0x3 << 8)
+
+/* Used by PRM_LDO_BANDGAP_SETUP */
+#define OMAP4430_STARTUP_COUNT_SHIFT					0
+#define OMAP4430_STARTUP_COUNT_MASK					(0xff << 0)
+
+/* Renamed from STARTUP_COUNT Used by PRM_SRAM_COUNT */
+#define OMAP4430_STARTUP_COUNT_24_31_SHIFT				24
+#define OMAP4430_STARTUP_COUNT_24_31_MASK				(0xff << 24)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM1_MEM_ONSTATE_SHIFT					20
-#define OMAP4430_TCM1_MEM_ONSTATE_MASK					BITFIELD(20, 21)
+#define OMAP4430_TCM1_MEM_ONSTATE_MASK					(0x3 << 20)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM1_MEM_RETSTATE_SHIFT				10
-#define OMAP4430_TCM1_MEM_RETSTATE_MASK					BITFIELD(10, 10)
+#define OMAP4430_TCM1_MEM_RETSTATE_MASK					(1 << 10)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_TCM1_MEM_STATEST_SHIFT					8
-#define OMAP4430_TCM1_MEM_STATEST_MASK					BITFIELD(8, 9)
+#define OMAP4430_TCM1_MEM_STATEST_MASK					(0x3 << 8)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM2_MEM_ONSTATE_SHIFT					22
-#define OMAP4430_TCM2_MEM_ONSTATE_MASK					BITFIELD(22, 23)
+#define OMAP4430_TCM2_MEM_ONSTATE_MASK					(0x3 << 22)
 
 /* Used by PM_IVAHD_PWRSTCTRL */
 #define OMAP4430_TCM2_MEM_RETSTATE_SHIFT				11
-#define OMAP4430_TCM2_MEM_RETSTATE_MASK					BITFIELD(11, 11)
+#define OMAP4430_TCM2_MEM_RETSTATE_MASK					(1 << 11)
 
 /* Used by PM_IVAHD_PWRSTST */
 #define OMAP4430_TCM2_MEM_STATEST_SHIFT					10
-#define OMAP4430_TCM2_MEM_STATEST_MASK					BITFIELD(10, 11)
+#define OMAP4430_TCM2_MEM_STATEST_MASK					(0x3 << 10)
 
 /* Used by RM_TESLA_RSTST */
 #define OMAP4430_TESLASS_EMU_RSTST_SHIFT				2
-#define OMAP4430_TESLASS_EMU_RSTST_MASK					BITFIELD(2, 2)
+#define OMAP4430_TESLASS_EMU_RSTST_MASK					(1 << 2)
 
 /* Used by RM_TESLA_RSTST */
 #define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_SHIFT				3
-#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK				BITFIELD(3, 3)
+#define OMAP4430_TESLA_DSP_EMU_REQ_RSTST_MASK				(1 << 3)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_EDMA_ONSTATE_SHIFT				20
-#define OMAP4430_TESLA_EDMA_ONSTATE_MASK				BITFIELD(20, 21)
+#define OMAP4430_TESLA_EDMA_ONSTATE_MASK				(0x3 << 20)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_EDMA_RETSTATE_SHIFT				10
-#define OMAP4430_TESLA_EDMA_RETSTATE_MASK				BITFIELD(10, 10)
+#define OMAP4430_TESLA_EDMA_RETSTATE_MASK				(1 << 10)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_EDMA_STATEST_SHIFT				8
-#define OMAP4430_TESLA_EDMA_STATEST_MASK				BITFIELD(8, 9)
+#define OMAP4430_TESLA_EDMA_STATEST_MASK				(0x3 << 8)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L1_ONSTATE_SHIFT					16
-#define OMAP4430_TESLA_L1_ONSTATE_MASK					BITFIELD(16, 17)
+#define OMAP4430_TESLA_L1_ONSTATE_MASK					(0x3 << 16)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L1_RETSTATE_SHIFT				8
-#define OMAP4430_TESLA_L1_RETSTATE_MASK					BITFIELD(8, 8)
+#define OMAP4430_TESLA_L1_RETSTATE_MASK					(1 << 8)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_L1_STATEST_SHIFT					4
-#define OMAP4430_TESLA_L1_STATEST_MASK					BITFIELD(4, 5)
+#define OMAP4430_TESLA_L1_STATEST_MASK					(0x3 << 4)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L2_ONSTATE_SHIFT					18
-#define OMAP4430_TESLA_L2_ONSTATE_MASK					BITFIELD(18, 19)
+#define OMAP4430_TESLA_L2_ONSTATE_MASK					(0x3 << 18)
 
 /* Used by PM_TESLA_PWRSTCTRL */
 #define OMAP4430_TESLA_L2_RETSTATE_SHIFT				9
-#define OMAP4430_TESLA_L2_RETSTATE_MASK					BITFIELD(9, 9)
+#define OMAP4430_TESLA_L2_RETSTATE_MASK					(1 << 9)
 
 /* Used by PM_TESLA_PWRSTST */
 #define OMAP4430_TESLA_L2_STATEST_SHIFT					6
-#define OMAP4430_TESLA_L2_STATEST_MASK					BITFIELD(6, 7)
+#define OMAP4430_TESLA_L2_STATEST_MASK					(0x3 << 6)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_TIMEOUT_SHIFT						0
-#define OMAP4430_TIMEOUT_MASK						BITFIELD(0, 15)
+#define OMAP4430_TIMEOUT_MASK						(0xffff << 0)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_TIMEOUTEN_SHIFT					3
-#define OMAP4430_TIMEOUTEN_MASK						BITFIELD(3, 3)
+#define OMAP4430_TIMEOUTEN_MASK						(1 << 3)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_TRANSITION_EN_SHIFT					8
-#define OMAP4430_TRANSITION_EN_MASK					BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_EN_MASK					(1 << 8)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_TRANSITION_ST_SHIFT					8
-#define OMAP4430_TRANSITION_ST_MASK					BITFIELD(8, 8)
+#define OMAP4430_TRANSITION_ST_MASK					(1 << 8)
 
 /* Used by PRM_VC_VAL_BYPASS */
 #define OMAP4430_VALID_SHIFT						24
-#define OMAP4430_VALID_MASK						BITFIELD(24, 24)
+#define OMAP4430_VALID_MASK						(1 << 24)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_BYPASSACK_EN_SHIFT					14
-#define OMAP4430_VC_BYPASSACK_EN_MASK					BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_EN_MASK					(1 << 14)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_BYPASSACK_ST_SHIFT					14
-#define OMAP4430_VC_BYPASSACK_ST_MASK					BITFIELD(14, 14)
+#define OMAP4430_VC_BYPASSACK_ST_MASK					(1 << 14)
+
+/* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
+#define OMAP4430_VC_CORE_VPACK_EN_SHIFT					22
+#define OMAP4430_VC_CORE_VPACK_EN_MASK					(1 << 22)
+
+/* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
+#define OMAP4430_VC_CORE_VPACK_ST_SHIFT					22
+#define OMAP4430_VC_CORE_VPACK_ST_MASK					(1 << 22)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_IVA_VPACK_EN_SHIFT					30
-#define OMAP4430_VC_IVA_VPACK_EN_MASK					BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_EN_MASK					(1 << 30)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_IVA_VPACK_ST_SHIFT					30
-#define OMAP4430_VC_IVA_VPACK_ST_MASK					BITFIELD(30, 30)
+#define OMAP4430_VC_IVA_VPACK_ST_MASK					(1 << 30)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VC_MPU_VPACK_EN_SHIFT					6
-#define OMAP4430_VC_MPU_VPACK_EN_MASK					BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_EN_MASK					(1 << 6)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VC_MPU_VPACK_ST_SHIFT					6
-#define OMAP4430_VC_MPU_VPACK_ST_MASK					BITFIELD(6, 6)
+#define OMAP4430_VC_MPU_VPACK_ST_MASK					(1 << 6)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_RAERR_EN_SHIFT					12
-#define OMAP4430_VC_RAERR_EN_MASK					BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_EN_MASK					(1 << 12)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_RAERR_ST_SHIFT					12
-#define OMAP4430_VC_RAERR_ST_MASK					BITFIELD(12, 12)
+#define OMAP4430_VC_RAERR_ST_MASK					(1 << 12)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_SAERR_EN_SHIFT					11
-#define OMAP4430_VC_SAERR_EN_MASK					BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_EN_MASK					(1 << 11)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_SAERR_ST_SHIFT					11
-#define OMAP4430_VC_SAERR_ST_MASK					BITFIELD(11, 11)
+#define OMAP4430_VC_SAERR_ST_MASK					(1 << 11)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VC_TOERR_EN_SHIFT					13
-#define OMAP4430_VC_TOERR_EN_MASK					BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_EN_MASK					(1 << 13)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VC_TOERR_ST_SHIFT					13
-#define OMAP4430_VC_TOERR_ST_MASK					BITFIELD(13, 13)
+#define OMAP4430_VC_TOERR_ST_MASK					(1 << 13)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_VDDMAX_SHIFT						24
-#define OMAP4430_VDDMAX_MASK						BITFIELD(24, 31)
+#define OMAP4430_VDDMAX_MASK						(0xff << 24)
 
 /* Used by PRM_VP_CORE_VLIMITTO, PRM_VP_IVA_VLIMITTO, PRM_VP_MPU_VLIMITTO */
 #define OMAP4430_VDDMIN_SHIFT						16
-#define OMAP4430_VDDMIN_MASK						BITFIELD(16, 23)
+#define OMAP4430_VDDMIN_MASK						(0xff << 16)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_CORE_I2C_DISABLE_SHIFT				12
-#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK				BITFIELD(12, 12)
+#define OMAP4430_VDD_CORE_I2C_DISABLE_MASK				(1 << 12)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_CORE_VOLT_MGR_RST_SHIFT				8
-#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK				BITFIELD(8, 8)
+#define OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK				(1 << 8)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_IVA_I2C_DISABLE_SHIFT				14
-#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK				BITFIELD(14, 14)
+#define OMAP4430_VDD_IVA_I2C_DISABLE_MASK				(1 << 14)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_IVA_PRESENCE_SHIFT					9
-#define OMAP4430_VDD_IVA_PRESENCE_MASK					BITFIELD(9, 9)
+#define OMAP4430_VDD_IVA_PRESENCE_MASK					(1 << 9)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_IVA_VOLT_MGR_RST_SHIFT				7
-#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK				BITFIELD(7, 7)
+#define OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK				(1 << 7)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_MPU_I2C_DISABLE_SHIFT				13
-#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK				BITFIELD(13, 13)
+#define OMAP4430_VDD_MPU_I2C_DISABLE_MASK				(1 << 13)
 
 /* Used by PRM_VOLTCTRL */
 #define OMAP4430_VDD_MPU_PRESENCE_SHIFT					8
-#define OMAP4430_VDD_MPU_PRESENCE_MASK					BITFIELD(8, 8)
+#define OMAP4430_VDD_MPU_PRESENCE_MASK					(1 << 8)
 
 /* Used by PRM_RSTST */
 #define OMAP4430_VDD_MPU_VOLT_MGR_RST_SHIFT				6
-#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK				BITFIELD(6, 6)
+#define OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK				(1 << 6)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_CORE_SHIFT					4
+#define OMAP4430_VFSM_RA_ERR_CORE_MASK					(1 << 4)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_IVA_SHIFT					12
+#define OMAP4430_VFSM_RA_ERR_IVA_MASK					(1 << 12)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_RA_ERR_MPU_SHIFT					20
+#define OMAP4430_VFSM_RA_ERR_MPU_MASK					(1 << 20)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_CORE_SHIFT					3
+#define OMAP4430_VFSM_SA_ERR_CORE_MASK					(1 << 3)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_IVA_SHIFT					11
+#define OMAP4430_VFSM_SA_ERR_IVA_MASK					(1 << 11)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_SA_ERR_MPU_SHIFT					19
+#define OMAP4430_VFSM_SA_ERR_MPU_MASK					(1 << 19)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_SHIFT				5
+#define OMAP4430_VFSM_TIMEOUT_ERR_CORE_MASK				(1 << 5)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_SHIFT				13
+#define OMAP4430_VFSM_TIMEOUT_ERR_IVA_MASK				(1 << 13)
+
+/* Used by PRM_VC_ERRST */
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_SHIFT				21
+#define OMAP4430_VFSM_TIMEOUT_ERR_MPU_MASK				(1 << 21)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_CORE_L_SHIFT					0
-#define OMAP4430_VOLRA_VDD_CORE_L_MASK					BITFIELD(0, 7)
+#define OMAP4430_VOLRA_VDD_CORE_L_MASK					(0xff << 0)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_IVA_L_SHIFT					8
-#define OMAP4430_VOLRA_VDD_IVA_L_MASK					BITFIELD(8, 15)
+#define OMAP4430_VOLRA_VDD_IVA_L_MASK					(0xff << 8)
 
 /* Used by PRM_VC_VAL_SMPS_RA_VOL */
 #define OMAP4430_VOLRA_VDD_MPU_L_SHIFT					16
-#define OMAP4430_VOLRA_VDD_MPU_L_MASK					BITFIELD(16, 23)
+#define OMAP4430_VOLRA_VDD_MPU_L_MASK					(0xff << 16)
 
 /* Used by PRM_VP_CORE_CONFIG, PRM_VP_IVA_CONFIG, PRM_VP_MPU_CONFIG */
 #define OMAP4430_VPENABLE_SHIFT						0
-#define OMAP4430_VPENABLE_MASK						BITFIELD(0, 0)
+#define OMAP4430_VPENABLE_MASK						(1 << 0)
 
 /* Used by PRM_VP_CORE_STATUS, PRM_VP_IVA_STATUS, PRM_VP_MPU_STATUS */
 #define OMAP4430_VPINIDLE_SHIFT						0
-#define OMAP4430_VPINIDLE_MASK						BITFIELD(0, 0)
+#define OMAP4430_VPINIDLE_MASK						(1 << 0)
 
 /* Used by PRM_VP_CORE_VOLTAGE, PRM_VP_IVA_VOLTAGE, PRM_VP_MPU_VOLTAGE */
 #define OMAP4430_VPVOLTAGE_SHIFT					0
-#define OMAP4430_VPVOLTAGE_MASK						BITFIELD(0, 7)
+#define OMAP4430_VPVOLTAGE_MASK						(0xff << 0)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_EQVALUE_EN_SHIFT				20
-#define OMAP4430_VP_CORE_EQVALUE_EN_MASK				BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_EN_MASK				(1 << 20)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_EQVALUE_ST_SHIFT				20
-#define OMAP4430_VP_CORE_EQVALUE_ST_MASK				BITFIELD(20, 20)
+#define OMAP4430_VP_CORE_EQVALUE_ST_MASK				(1 << 20)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_MAXVDD_EN_SHIFT				18
-#define OMAP4430_VP_CORE_MAXVDD_EN_MASK					BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_EN_MASK					(1 << 18)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_MAXVDD_ST_SHIFT				18
-#define OMAP4430_VP_CORE_MAXVDD_ST_MASK					BITFIELD(18, 18)
+#define OMAP4430_VP_CORE_MAXVDD_ST_MASK					(1 << 18)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_MINVDD_EN_SHIFT				17
-#define OMAP4430_VP_CORE_MINVDD_EN_MASK					BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_EN_MASK					(1 << 17)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_MINVDD_ST_SHIFT				17
-#define OMAP4430_VP_CORE_MINVDD_ST_MASK					BITFIELD(17, 17)
+#define OMAP4430_VP_CORE_MINVDD_ST_MASK					(1 << 17)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_NOSMPSACK_EN_SHIFT				19
-#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK				BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_EN_MASK				(1 << 19)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_NOSMPSACK_ST_SHIFT				19
-#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK				BITFIELD(19, 19)
+#define OMAP4430_VP_CORE_NOSMPSACK_ST_MASK				(1 << 19)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_SHIFT				16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK				BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_EN_MASK				(1 << 16)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_SHIFT				16
-#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK				BITFIELD(16, 16)
+#define OMAP4430_VP_CORE_OPPCHANGEDONE_ST_MASK				(1 << 16)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_CORE_TRANXDONE_EN_SHIFT				21
-#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK				BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_EN_MASK				(1 << 21)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_CORE_TRANXDONE_ST_SHIFT				21
-#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK				BITFIELD(21, 21)
+#define OMAP4430_VP_CORE_TRANXDONE_ST_MASK				(1 << 21)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_EQVALUE_EN_SHIFT				28
-#define OMAP4430_VP_IVA_EQVALUE_EN_MASK					BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_EN_MASK					(1 << 28)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_EQVALUE_ST_SHIFT				28
-#define OMAP4430_VP_IVA_EQVALUE_ST_MASK					BITFIELD(28, 28)
+#define OMAP4430_VP_IVA_EQVALUE_ST_MASK					(1 << 28)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_MAXVDD_EN_SHIFT					26
-#define OMAP4430_VP_IVA_MAXVDD_EN_MASK					BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_EN_MASK					(1 << 26)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_MAXVDD_ST_SHIFT					26
-#define OMAP4430_VP_IVA_MAXVDD_ST_MASK					BITFIELD(26, 26)
+#define OMAP4430_VP_IVA_MAXVDD_ST_MASK					(1 << 26)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_MINVDD_EN_SHIFT					25
-#define OMAP4430_VP_IVA_MINVDD_EN_MASK					BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_EN_MASK					(1 << 25)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_MINVDD_ST_SHIFT					25
-#define OMAP4430_VP_IVA_MINVDD_ST_MASK					BITFIELD(25, 25)
+#define OMAP4430_VP_IVA_MINVDD_ST_MASK					(1 << 25)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_NOSMPSACK_EN_SHIFT				27
-#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK				BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_EN_MASK				(1 << 27)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_NOSMPSACK_ST_SHIFT				27
-#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK				BITFIELD(27, 27)
+#define OMAP4430_VP_IVA_NOSMPSACK_ST_MASK				(1 << 27)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_SHIFT				24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK				BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_EN_MASK				(1 << 24)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_SHIFT				24
-#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK				BITFIELD(24, 24)
+#define OMAP4430_VP_IVA_OPPCHANGEDONE_ST_MASK				(1 << 24)
 
 /* Used by PRM_IRQENABLE_DUCATI, PRM_IRQENABLE_MPU */
 #define OMAP4430_VP_IVA_TRANXDONE_EN_SHIFT				29
-#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK				BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_EN_MASK				(1 << 29)
 
 /* Used by PRM_IRQSTATUS_DUCATI, PRM_IRQSTATUS_MPU */
 #define OMAP4430_VP_IVA_TRANXDONE_ST_SHIFT				29
-#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK				BITFIELD(29, 29)
+#define OMAP4430_VP_IVA_TRANXDONE_ST_MASK				(1 << 29)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_EQVALUE_EN_SHIFT				4
-#define OMAP4430_VP_MPU_EQVALUE_EN_MASK					BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_EN_MASK					(1 << 4)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_EQVALUE_ST_SHIFT				4
-#define OMAP4430_VP_MPU_EQVALUE_ST_MASK					BITFIELD(4, 4)
+#define OMAP4430_VP_MPU_EQVALUE_ST_MASK					(1 << 4)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_MAXVDD_EN_SHIFT					2
-#define OMAP4430_VP_MPU_MAXVDD_EN_MASK					BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_EN_MASK					(1 << 2)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_MAXVDD_ST_SHIFT					2
-#define OMAP4430_VP_MPU_MAXVDD_ST_MASK					BITFIELD(2, 2)
+#define OMAP4430_VP_MPU_MAXVDD_ST_MASK					(1 << 2)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_MINVDD_EN_SHIFT					1
-#define OMAP4430_VP_MPU_MINVDD_EN_MASK					BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_EN_MASK					(1 << 1)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_MINVDD_ST_SHIFT					1
-#define OMAP4430_VP_MPU_MINVDD_ST_MASK					BITFIELD(1, 1)
+#define OMAP4430_VP_MPU_MINVDD_ST_MASK					(1 << 1)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_NOSMPSACK_EN_SHIFT				3
-#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK				BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_EN_MASK				(1 << 3)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_NOSMPSACK_ST_SHIFT				3
-#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK				BITFIELD(3, 3)
+#define OMAP4430_VP_MPU_NOSMPSACK_ST_MASK				(1 << 3)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_SHIFT				0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK				BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_EN_MASK				(1 << 0)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_SHIFT				0
-#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK				BITFIELD(0, 0)
+#define OMAP4430_VP_MPU_OPPCHANGEDONE_ST_MASK				(1 << 0)
 
 /* Used by PRM_IRQENABLE_MPU_2 */
 #define OMAP4430_VP_MPU_TRANXDONE_EN_SHIFT				5
-#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK				BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_EN_MASK				(1 << 5)
 
 /* Used by PRM_IRQSTATUS_MPU_2 */
 #define OMAP4430_VP_MPU_TRANXDONE_ST_SHIFT				5
-#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK				BITFIELD(5, 5)
+#define OMAP4430_VP_MPU_TRANXDONE_ST_MASK				(1 << 5)
 
 /* Used by PRM_SRAM_COUNT */
 #define OMAP4430_VSETUPCNT_VALUE_SHIFT					8
-#define OMAP4430_VSETUPCNT_VALUE_MASK					BITFIELD(8, 15)
+#define OMAP4430_VSETUPCNT_VALUE_MASK					(0xff << 8)
 
 /* Used by PRM_VP_CORE_VSTEPMAX, PRM_VP_IVA_VSTEPMAX, PRM_VP_MPU_VSTEPMAX */
 #define OMAP4430_VSTEPMAX_SHIFT						0
-#define OMAP4430_VSTEPMAX_MASK						BITFIELD(0, 7)
+#define OMAP4430_VSTEPMAX_MASK						(0xff << 0)
 
 /* Used by PRM_VP_CORE_VSTEPMIN, PRM_VP_IVA_VSTEPMIN, PRM_VP_MPU_VSTEPMIN */
 #define OMAP4430_VSTEPMIN_SHIFT						0
-#define OMAP4430_VSTEPMIN_MASK						BITFIELD(0, 7)
+#define OMAP4430_VSTEPMIN_MASK						(0xff << 0)
 
 /* Used by PRM_MODEM_IF_CTRL */
 #define OMAP4430_WAKE_MODEM_SHIFT					0
-#define OMAP4430_WAKE_MODEM_MASK					BITFIELD(0, 0)
+#define OMAP4430_WAKE_MODEM_MASK					(1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DISPC_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DISPC_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DISPC_MPU_MASK					(1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_DISPC_SDMA_MASK				(1 << 3)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DISPC_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DISPC_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DMIC_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DMIC_DMA_TESLA_MASK				(1 << 6)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_DMIC_WKDEP */
 #define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_DMIC_IRQ_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_DMTIMER10_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER10_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER10_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_DMTIMER11_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER11_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_DMTIMER11_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER11_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER11_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_DMTIMER2_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER2_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER2_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_DMTIMER3_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER3_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_DMTIMER3_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER3_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER3_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_DMTIMER4_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER4_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_DMTIMER4_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER4_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER4_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_DMTIMER9_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_DMTIMER9_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_DMTIMER9_WKDEP */
 #define OMAP4430_WKUPDEP_DMTIMER9_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_DMTIMER9_MPU_MASK				(1 << 0)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_DUCATI_SHIFT				5
-#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK				BITFIELD(5, 5)
+#define OMAP4430_WKUPDEP_DSI1_DUCATI_MASK				(1 << 5)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_MPU_SHIFT					4
-#define OMAP4430_WKUPDEP_DSI1_MPU_MASK					BITFIELD(4, 4)
+#define OMAP4430_WKUPDEP_DSI1_MPU_MASK					(1 << 4)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK					BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_DSI1_SDMA_MASK					(1 << 7)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI1_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_DSI1_TESLA_MASK				(1 << 6)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_DUCATI_SHIFT				9
-#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK				BITFIELD(9, 9)
+#define OMAP4430_WKUPDEP_DSI2_DUCATI_MASK				(1 << 9)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_MPU_SHIFT					8
-#define OMAP4430_WKUPDEP_DSI2_MPU_MASK					BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_DSI2_MPU_MASK					(1 << 8)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_SDMA_SHIFT				11
-#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK					BITFIELD(11, 11)
+#define OMAP4430_WKUPDEP_DSI2_SDMA_MASK					(1 << 11)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_DSI2_TESLA_SHIFT				10
-#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK				BITFIELD(10, 10)
+#define OMAP4430_WKUPDEP_DSI2_TESLA_MASK				(1 << 10)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_SHIFT			1
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_WKUP_GPIO1_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO1_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_SHIFT			1
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_GPIO2_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO2_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_GPIO3_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_GPIO3_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO3_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_GPIO4_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_GPIO4_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO4_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_GPIO5_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_GPIO5_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO5_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_GPIO6_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_GPIO6_WKDEP */
 #define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_GPIO6_IRQ2_TESLA_MASK				(1 << 6)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIDMA_SDMA_SHIFT				19
-#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK				BITFIELD(19, 19)
+#define OMAP4430_WKUPDEP_HDMIDMA_SDMA_MASK				(1 << 19)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_SHIFT				13
-#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK				BITFIELD(13, 13)
+#define OMAP4430_WKUPDEP_HDMIIRQ_DUCATI_MASK				(1 << 13)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_MPU_SHIFT				12
-#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK				BITFIELD(12, 12)
+#define OMAP4430_WKUPDEP_HDMIIRQ_MPU_MASK				(1 << 12)
 
 /* Used by PM_DSS_DSS_WKDEP */
 #define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_SHIFT				14
-#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK				BITFIELD(14, 14)
+#define OMAP4430_WKUPDEP_HDMIIRQ_TESLA_MASK				(1 << 14)
 
 /* Used by PM_L4PER_HECC1_WKDEP */
 #define OMAP4430_WKUPDEP_HECC1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_HECC1_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC1_MPU_MASK					(1 << 0)
 
 /* Used by PM_L4PER_HECC2_WKDEP */
 #define OMAP4430_WKUPDEP_HECC2_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_HECC2_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HECC2_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_DSP_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_HSI_DSP_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_HSI_MCU_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_HSI_MCU_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_HSI_MCU_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C1_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_I2C1_WKDEP */
 #define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C1_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C2_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_I2C2_WKDEP */
 #define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C2_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C3_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_I2C3_WKDEP */
 #define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C3_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C4_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_I2C4_WKDEP */
 #define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C4_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_I2C5_WKDEP */
 #define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_I2C5_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_I2C5_WKDEP */
 #define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_I2C5_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_WKUP_KEYBOARD_WKDEP */
 #define OMAP4430_WKUPDEP_KEYBOARD_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_KEYBOARD_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP1_DMA_TESLA_MASK				(1 << 6)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_MCASP_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP1_IRQ_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP2_DMA_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCASP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP2_IRQ_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_MCASP3_DMA_TESLA_MASK				(1 << 6)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCASP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCASP3_IRQ_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP1_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP1_SDMA_MASK				(1 << 3)
 
 /* Used by PM_ABE_MCBSP1_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP1_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP1_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP2_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP2_SDMA_MASK				(1 << 3)
 
 /* Used by PM_ABE_MCBSP2_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP2_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP2_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP3_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP3_SDMA_MASK				(1 << 3)
 
 /* Used by PM_ABE_MCBSP3_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP3_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP3_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCBSP4_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCBSP4_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MCBSP4_WKDEP */
 #define OMAP4430_WKUPDEP_MCBSP4_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCBSP4_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI1_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI1_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MCSPI1_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI1_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MCSPI1_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MCSPI2_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI2_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCSPI2_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI2_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI2_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MCSPI3_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI3_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI3_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCSPI3_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI3_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI3_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MCSPI4_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI4_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MCSPI4_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MCSPI4_WKDEP */
 #define OMAP4430_WKUPDEP_MCSPI4_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MCSPI4_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC1_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_MMC1_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC1_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK					BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC1_SDMA_MASK					(1 << 3)
 
 /* Used by PM_L3INIT_MMC1_WKDEP */
 #define OMAP4430_WKUPDEP_MMC1_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC1_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC2_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_MMC2_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC2_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK					BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMC2_SDMA_MASK					(1 << 3)
 
 /* Used by PM_L3INIT_MMC2_WKDEP */
 #define OMAP4430_WKUPDEP_MMC2_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC2_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMC6_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_MMC6_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMC6_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_MMC6_WKDEP */
 #define OMAP4430_WKUPDEP_MMC6_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_MMC6_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD3_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD3_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MMCSD3_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD3_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD3_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD4_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD4_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MMCSD4_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD4_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD4_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_MMCSD5_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_MMCSD5_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_MMCSD5_WKDEP */
 #define OMAP4430_WKUPDEP_MMCSD5_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_MMCSD5_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L3INIT_PCIESS_WKDEP */
 #define OMAP4430_WKUPDEP_PCIESS_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PCIESS_MPU_MASK				(1 << 0)
 
 /* Used by PM_L3INIT_PCIESS_WKDEP */
 #define OMAP4430_WKUPDEP_PCIESS_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PCIESS_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_DMA_SDMA_SHIFT				7
-#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_PDM_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_DMA_TESLA_SHIFT				6
-#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK				BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_PDM_DMA_TESLA_MASK				(1 << 6)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_PDM_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_PDM_WKDEP */
 #define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_PDM_IRQ_TESLA_MASK				(1 << 2)
 
 /* Used by PM_WKUP_RTC_WKDEP */
 #define OMAP4430_WKUPDEP_RTC_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_RTC_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_RTC_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_SATA_WKDEP */
 #define OMAP4430_WKUPDEP_SATA_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_SATA_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SATA_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_SATA_WKDEP */
 #define OMAP4430_WKUPDEP_SATA_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_SATA_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SATA_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_SHIFT			7
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_SHIFT			6
-#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK			BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS1_DMA_TESLA_MASK			(1 << 6)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_SLIMBUS_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_SHIFT			2
-#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK			BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS1_IRQ_TESLA_MASK			(1 << 2)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_SHIFT			7
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK				BITFIELD(7, 7)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_SDMA_MASK				(1 << 7)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_SHIFT			6
-#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK			BITFIELD(6, 6)
+#define OMAP4430_WKUPDEP_SLIMBUS2_DMA_TESLA_MASK			(1 << 6)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_MPU_MASK				(1 << 0)
 
 /* Used by PM_L4PER_SLIMBUS2_WKDEP */
 #define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_SHIFT			2
-#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK			BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_SLIMBUS2_IRQ_TESLA_MASK			(1 << 2)
 
 /* Used by PM_ALWON_SR_CORE_WKDEP */
 #define OMAP4430_WKUPDEP_SR_CORE_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_CORE_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_ALWON_SR_CORE_WKDEP */
 #define OMAP4430_WKUPDEP_SR_CORE_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_CORE_MPU_MASK				(1 << 0)
 
 /* Used by PM_ALWON_SR_IVA_WKDEP */
 #define OMAP4430_WKUPDEP_SR_IVA_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_SR_IVA_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_ALWON_SR_IVA_WKDEP */
 #define OMAP4430_WKUPDEP_SR_IVA_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_IVA_MPU_MASK				(1 << 0)
 
 /* Used by PM_ALWON_SR_MPU_WKDEP */
 #define OMAP4430_WKUPDEP_SR_MPU_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_SR_MPU_MPU_MASK				(1 << 0)
 
 /* Used by PM_WKUP_TIMER12_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER12_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER12_MPU_MASK				(1 << 0)
 
 /* Used by PM_WKUP_TIMER1_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER1_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_TIMER5_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER5_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER5_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_TIMER5_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER5_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER5_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_TIMER6_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER6_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER6_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_TIMER6_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER6_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER6_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_TIMER7_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER7_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER7_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_TIMER7_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER7_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER7_TESLA_MASK				(1 << 2)
 
 /* Used by PM_ABE_TIMER8_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER8_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_TIMER8_MPU_MASK				(1 << 0)
 
 /* Used by PM_ABE_TIMER8_WKDEP */
 #define OMAP4430_WKUPDEP_TIMER8_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_TIMER8_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_UART1_WKDEP */
 #define OMAP4430_WKUPDEP_UART1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_UART1_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART1_MPU_MASK					(1 << 0)
 
 /* Used by PM_L4PER_UART1_WKDEP */
 #define OMAP4430_WKUPDEP_UART1_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_UART1_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART1_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_UART2_WKDEP */
 #define OMAP4430_WKUPDEP_UART2_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_UART2_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART2_MPU_MASK					(1 << 0)
 
 /* Used by PM_L4PER_UART2_WKDEP */
 #define OMAP4430_WKUPDEP_UART2_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_UART2_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART2_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UART3_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_UART3_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART3_MPU_MASK					(1 << 0)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_UART3_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART3_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L4PER_UART3_WKDEP */
 #define OMAP4430_WKUPDEP_UART3_TESLA_SHIFT				2
-#define OMAP4430_WKUPDEP_UART3_TESLA_MASK				BITFIELD(2, 2)
+#define OMAP4430_WKUPDEP_UART3_TESLA_MASK				(1 << 2)
 
 /* Used by PM_L4PER_UART4_WKDEP */
 #define OMAP4430_WKUPDEP_UART4_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_UART4_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UART4_MPU_MASK					(1 << 0)
 
 /* Used by PM_L4PER_UART4_WKDEP */
 #define OMAP4430_WKUPDEP_UART4_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_UART4_SDMA_MASK				BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_UART4_SDMA_MASK				(1 << 3)
 
 /* Used by PM_L3INIT_UNIPRO1_WKDEP */
 #define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_UNIPRO1_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_UNIPRO1_WKDEP */
 #define OMAP4430_WKUPDEP_UNIPRO1_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_UNIPRO1_MPU_MASK				(1 << 0)
 
 /* Used by PM_L3INIT_USB_HOST_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_SHIFT			1
-#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK			BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_DUCATI_MASK			(1 << 1)
 
 /* Used by PM_L3INIT_USB_HOST_FS_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_FS_MPU_MASK				(1 << 0)
 
 /* Used by PM_L3INIT_USB_HOST_WKDEP */
 #define OMAP4430_WKUPDEP_USB_HOST_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_HOST_MPU_MASK				(1 << 0)
 
 /* Used by PM_L3INIT_USB_OTG_WKDEP */
 #define OMAP4430_WKUPDEP_USB_OTG_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_OTG_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_USB_OTG_WKDEP */
 #define OMAP4430_WKUPDEP_USB_OTG_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_OTG_MPU_MASK				(1 << 0)
 
 /* Used by PM_L3INIT_USB_TLL_WKDEP */
 #define OMAP4430_WKUPDEP_USB_TLL_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_USB_TLL_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_L3INIT_USB_TLL_WKDEP */
 #define OMAP4430_WKUPDEP_USB_TLL_MPU_SHIFT				0
-#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK				BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USB_TLL_MPU_MASK				(1 << 0)
 
 /* Used by PM_WKUP_USIM_WKDEP */
 #define OMAP4430_WKUPDEP_USIM_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_USIM_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_USIM_MPU_MASK					(1 << 0)
 
 /* Used by PM_WKUP_USIM_WKDEP */
 #define OMAP4430_WKUPDEP_USIM_SDMA_SHIFT				3
-#define OMAP4430_WKUPDEP_USIM_SDMA_MASK					BITFIELD(3, 3)
+#define OMAP4430_WKUPDEP_USIM_SDMA_MASK					(1 << 3)
 
 /* Used by PM_WKUP_WDT2_WKDEP */
 #define OMAP4430_WKUPDEP_WDT2_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_WDT2_DUCATI_MASK				(1 << 1)
 
 /* Used by PM_WKUP_WDT2_WKDEP */
 #define OMAP4430_WKUPDEP_WDT2_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_WDT2_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT2_MPU_MASK					(1 << 0)
 
 /* Used by PM_ABE_WDT3_WKDEP */
 #define OMAP4430_WKUPDEP_WDT3_MPU_SHIFT					0
-#define OMAP4430_WKUPDEP_WDT3_MPU_MASK					BITFIELD(0, 0)
+#define OMAP4430_WKUPDEP_WDT3_MPU_MASK					(1 << 0)
 
 /* Used by PM_L3INIT_HSI_WKDEP */
 #define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_SHIFT				8
-#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK				BITFIELD(8, 8)
+#define OMAP4430_WKUPDEP_WGM_HSI_WAKE_MPU_MASK				(1 << 8)
 
 /* Used by PM_L3INIT_XHPI_WKDEP */
 #define OMAP4430_WKUPDEP_XHPI_DUCATI_SHIFT				1
-#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK				BITFIELD(1, 1)
+#define OMAP4430_WKUPDEP_XHPI_DUCATI_MASK				(1 << 1)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_WUCLK_CTRL_SHIFT					8
-#define OMAP4430_WUCLK_CTRL_MASK					BITFIELD(8, 8)
+#define OMAP4430_WUCLK_CTRL_MASK					(1 << 8)
 
 /* Used by PRM_IO_PMCTRL */
 #define OMAP4430_WUCLK_STATUS_SHIFT					9
-#define OMAP4430_WUCLK_STATUS_MASK					BITFIELD(9, 9)
+#define OMAP4430_WUCLK_STATUS_MASK					(1 << 9)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_X_MAJOR_SHIFT						8
+#define OMAP4430_X_MAJOR_MASK						(0x7 << 8)
+
+/* Used by REVISION_PRM */
+#define OMAP4430_Y_MINOR_SHIFT						0
+#define OMAP4430_Y_MINOR_MASK						(0x3f << 0)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/serial.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/serial.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,20 +19,32 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/serial_8250.h>
+#include <linux/pm_runtime.h>
+#include <linux/console.h>
+
+#ifdef CONFIG_SERIAL_OMAP
+#include <plat/omap-serial.h>
+#endif
 
 #include <plat/common.h>
 #include <plat/board.h>
 #include <plat/clock.h>
-#include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "prm.h"
 #include "pm.h"
+#include "cm.h"
 #include "prm-regbits-34xx.h"
+#include "control.h"
 
 #define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV	0x52
 #define UART_OMAP_WER		0x17	/* Wake-up enable register */
@@ -48,6 +60,8 @@
  */
 #define DEFAULT_TIMEOUT 0
 
+#define MAX_UART_HWMOD_NAME_LEN		16
+
 struct omap_uart_state {
 	int num;
 	int can_sleep;
@@ -58,14 +72,21 @@
 	void __iomem *wk_en;
 	u32 wk_mask;
 	u32 padconf;
+	u32 dma_enabled;
 
 	struct clk *ick;
 	struct clk *fck;
 	int clocked;
 
-	struct plat_serial8250_port *p;
+	int irq;
+	int regshift;
+	int irqflags;
+	void __iomem *membase;
+	resource_size_t mapbase;
+
 	struct list_head node;
-	struct platform_device pdev;
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
 
 	u32 errata;
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
@@ -83,75 +104,47 @@
 };
 
 static LIST_HEAD(uart_list);
+static u8 num_uarts;
 
-static struct plat_serial8250_port serial_platform_data0[] = {
-	{
-		.irq		= 72,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
+/*
+ * Since these idle/enable hooks are used in the idle path itself
+ * which has interrupts disabled, use the non-locking versions of
+ * the hwmod enable/disable functions.
+ */
+static int uart_idle_hwmod(struct omap_device *od)
+{
+	_omap_hwmod_idle(od->hwmods[0]);
 
-static struct plat_serial8250_port serial_platform_data1[] = {
-	{
-		.irq		= 73,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
+	return 0;
+}
 
-static struct plat_serial8250_port serial_platform_data2[] = {
-	{
-		.irq		= 74,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
+static int uart_enable_hwmod(struct omap_device *od)
+{
+	_omap_hwmod_enable(od->hwmods[0]);
 
-static struct plat_serial8250_port serial_platform_data3[] = {
+	return 0;
+}
+
+static struct omap_device_pm_latency omap_uart_latency[] = {
 	{
-		.irq		= 70,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
+		.deactivate_func = uart_idle_hwmod,
+		.activate_func	 = uart_enable_hwmod,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
 };
 
-void __init omap2_set_globals_uart(struct omap_globals *omap2_globals)
-{
-	serial_platform_data0[0].mapbase = omap2_globals->uart1_phys;
-	serial_platform_data1[0].mapbase = omap2_globals->uart2_phys;
-	serial_platform_data2[0].mapbase = omap2_globals->uart3_phys;
-	serial_platform_data3[0].mapbase = omap2_globals->uart4_phys;
-}
-
 static inline unsigned int __serial_read_reg(struct uart_port *up,
-					   int offset)
+					     int offset)
 {
 	offset <<= up->regshift;
 	return (unsigned int)__raw_readb(up->membase + offset);
 }
 
-static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+static inline unsigned int serial_read_reg(struct omap_uart_state *uart,
 					   int offset)
 {
-	offset <<= up->regshift;
-	return (unsigned int)__raw_readb(up->membase + offset);
+	offset <<= uart->regshift;
+	return (unsigned int)__raw_readb(uart->membase + offset);
 }
 
 static inline void __serial_write_reg(struct uart_port *up, int offset,
@@ -161,11 +154,11 @@
 	__raw_writeb(value, up->membase + offset);
 }
 
-static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
 				    int value)
 {
-	offset <<= p->regshift;
-	__raw_writeb(value, p->membase + offset);
+	offset <<= uart->regshift;
+	__raw_writeb(value, uart->membase + offset);
 }
 
 /*
@@ -173,14 +166,12 @@
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
+
 static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
-	struct plat_serial8250_port *p = uart->p;
-
-	serial_write_reg(p, UART_OMAP_MDR1, 0x07);
-	serial_write_reg(p, UART_OMAP_SCR, 0x08);
-	serial_write_reg(p, UART_OMAP_MDR1, 0x00);
-	serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
+	serial_write_reg(uart, UART_OMAP_MDR1, 0x07);
+	serial_write_reg(uart, UART_OMAP_SCR, 0x08);
+	serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
@@ -197,24 +188,23 @@
 static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
 		u8 fcr_val)
 {
-	struct plat_serial8250_port *p = uart->p;
 	u8 timeout = 255;
 
-	serial_write_reg(p, UART_OMAP_MDR1, mdr1_val);
+	serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
 	udelay(2);
-	serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
+	serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
 			UART_FCR_CLEAR_RCVR);
 	/*
 	 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
 	 * TX_FIFO_E bit is 1.
 	 */
-	while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) &
+	while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
 				(UART_LSR_THRE | UART_LSR_DR))) {
 		timeout--;
 		if (!timeout) {
 			/* Should *never* happen. we warn and carry on */
-			dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n",
-				serial_read_reg(p, UART_LSR));
+			dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
+			serial_read_reg(uart, UART_LSR));
 			break;
 		}
 		udelay(1);
@@ -224,23 +214,22 @@
 static void omap_uart_save_context(struct omap_uart_state *uart)
 {
 	u16 lcr = 0;
-	struct plat_serial8250_port *p = uart->p;
 
 	if (!enable_off_mode)
 		return;
 
-	lcr = serial_read_reg(p, UART_LCR);
-	serial_write_reg(p, UART_LCR, 0xBF);
-	uart->dll = serial_read_reg(p, UART_DLL);
-	uart->dlh = serial_read_reg(p, UART_DLM);
-	serial_write_reg(p, UART_LCR, lcr);
-	uart->ier = serial_read_reg(p, UART_IER);
-	uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
-	uart->scr = serial_read_reg(p, UART_OMAP_SCR);
-	uart->wer = serial_read_reg(p, UART_OMAP_WER);
-	serial_write_reg(p, UART_LCR, 0x80);
-	uart->mcr = serial_read_reg(p, UART_MCR);
-	serial_write_reg(p, UART_LCR, lcr);
+	lcr = serial_read_reg(uart, UART_LCR);
+	serial_write_reg(uart, UART_LCR, 0xBF);
+	uart->dll = serial_read_reg(uart, UART_DLL);
+	uart->dlh = serial_read_reg(uart, UART_DLM);
+	serial_write_reg(uart, UART_LCR, lcr);
+	uart->ier = serial_read_reg(uart, UART_IER);
+	uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC);
+	uart->scr = serial_read_reg(uart, UART_OMAP_SCR);
+	uart->wer = serial_read_reg(uart, UART_OMAP_WER);
+	serial_write_reg(uart, UART_LCR, 0x80);
+	uart->mcr = serial_read_reg(uart, UART_MCR);
+	serial_write_reg(uart, UART_LCR, lcr);
 
 	uart->context_valid = 1;
 }
@@ -248,7 +237,6 @@
 static void omap_uart_restore_context(struct omap_uart_state *uart)
 {
 	u16 efr = 0;
-	struct plat_serial8250_port *p = uart->p;
 
 	if (!enable_off_mode)
 		return;
@@ -261,29 +249,30 @@
 	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
 		omap_uart_mdr1_errataset(uart, 0x07, 0xA0);
 	else
-		serial_write_reg(p, UART_OMAP_MDR1, 0x7);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	efr = serial_read_reg(p, UART_EFR);
-	serial_write_reg(p, UART_EFR, UART_EFR_ECB);
-	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(p, UART_IER, 0x0);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	serial_write_reg(p, UART_DLL, uart->dll);
-	serial_write_reg(p, UART_DLM, uart->dlh);
-	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(p, UART_IER, uart->ier);
-	serial_write_reg(p, UART_LCR, 0x80);
-	serial_write_reg(p, UART_MCR, uart->mcr);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	serial_write_reg(p, UART_EFR, efr);
-	serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
-	serial_write_reg(p, UART_OMAP_SCR, uart->scr);
-	serial_write_reg(p, UART_OMAP_WER, uart->wer);
-	serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+		serial_write_reg(uart, UART_OMAP_MDR1, 0x7);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_read_reg(uart, UART_EFR);
+	serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
+	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(uart, UART_IER, 0x0);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(uart, UART_DLL, uart->dll);
+	serial_write_reg(uart, UART_DLM, uart->dlh);
+	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(uart, UART_IER, uart->ier);
+	serial_write_reg(uart, UART_LCR, 0x80);
+	serial_write_reg(uart, UART_MCR, uart->mcr);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(uart, UART_EFR, efr);
+	serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
+	serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
+	serial_write_reg(uart, UART_OMAP_WER, uart->wer);
+	serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
 	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
 		omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
 	else
-		serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+		/* UART 16x mode */
+		serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 #else
 static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
@@ -295,8 +284,7 @@
 	if (uart->clocked)
 		return;
 
-	clk_enable(uart->ick);
-	clk_enable(uart->fck);
+	omap_device_enable(uart->pdev);
 	uart->clocked = 1;
 	omap_uart_restore_context(uart);
 }
@@ -310,8 +298,7 @@
 
 	omap_uart_save_context(uart);
 	uart->clocked = 0;
-	clk_disable(uart->ick);
-	clk_disable(uart->fck);
+	omap_device_idle(uart->pdev);
 }
 
 static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
@@ -349,18 +336,24 @@
 }
 
 static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
-					  int enable)
+					       int enable)
 {
-	struct plat_serial8250_port *p = uart->p;
-	u16 sysc;
+	u8 idlemode;
 
-	sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
-	if (enable)
-		sysc |= 0x2 << 3;
-	else
-		sysc |= 0x1 << 3;
+	if (enable) {
+		/**
+		 * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
+		 * in Smartidle Mode When Configured for DMA Operations.
+		 */
+		if (uart->dma_enabled)
+			idlemode = HWMOD_IDLEMODE_FORCE;
+		else
+			idlemode = HWMOD_IDLEMODE_SMART;
+	} else {
+		idlemode = HWMOD_IDLEMODE_NO;
+	}
 
-	serial_write_reg(p, UART_OMAP_SYSC, sysc);
+	omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
 }
 
 static void omap_uart_block_sleep(struct omap_uart_state *uart)
@@ -377,7 +370,7 @@
 
 static void omap_uart_allow_sleep(struct omap_uart_state *uart)
 {
-	if (device_may_wakeup(&uart->pdev.dev))
+	if (device_may_wakeup(&uart->pdev->dev))
 		omap_uart_enable_wakeup(uart);
 	else
 		omap_uart_disable_wakeup(uart);
@@ -414,7 +407,7 @@
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
-		if (num == uart->num) {
+		if (num == uart->num && uart->can_sleep) {
 			omap_uart_enable_clocks(uart);
 
 			/* Check for IO pad wakeup */
@@ -472,6 +465,7 @@
  * UART will not idle or sleep for its timeout period.
  *
  **/
+/* static int first_interrupt; */
 static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
 {
 	struct omap_uart_state *uart = dev_id;
@@ -483,7 +477,6 @@
 
 static void omap_uart_idle_init(struct omap_uart_state *uart)
 {
-	struct plat_serial8250_port *p = uart->p;
 	int ret;
 
 	uart->can_sleep = 0;
@@ -495,7 +488,7 @@
 	omap_uart_smart_idle_enable(uart, 0);
 
 	if (cpu_is_omap34xx()) {
-		u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+		u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
 		u32 wk_mask = 0;
 		u32 padconf = 0;
 
@@ -514,19 +507,17 @@
 			wk_mask = OMAP3430_ST_UART3_MASK;
 			padconf = 0x19e;
 			break;
+		case 3:
+			wk_mask = OMAP3630_ST_UART4_MASK;
+			padconf = 0x0d2;
+			break;
 		}
 		uart->wk_mask = wk_mask;
 		uart->padconf = padconf;
 	} else if (cpu_is_omap24xx()) {
 		u32 wk_mask = 0;
+		u32 wk_en = PM_WKEN1, wk_st = PM_WKST1;
 
-		if (cpu_is_omap2430()) {
-			uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1);
-			uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1);
-		} else if (cpu_is_omap2420()) {
-			uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1);
-			uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1);
-		}
 		switch (uart->num) {
 		case 0:
 			wk_mask = OMAP24XX_ST_UART1_MASK;
@@ -535,10 +526,19 @@
 			wk_mask = OMAP24XX_ST_UART2_MASK;
 			break;
 		case 2:
+			wk_en = OMAP24XX_PM_WKEN2;
+			wk_st = OMAP24XX_PM_WKST2;
 			wk_mask = OMAP24XX_ST_UART3_MASK;
 			break;
 		}
 		uart->wk_mask = wk_mask;
+		if (cpu_is_omap2430()) {
+			uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, wk_en);
+			uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, wk_st);
+		} else if (cpu_is_omap2420()) {
+			uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, wk_en);
+			uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, wk_st);
+		}
 	} else {
 		uart->wk_en = NULL;
 		uart->wk_st = NULL;
@@ -546,9 +546,9 @@
 		uart->padconf = 0;
 	}
 
-	p->irqflags |= IRQF_SHARED;
-	ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
-			  "serial idle", (void *)uart);
+	uart->irqflags |= IRQF_SHARED;
+	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
+				   IRQF_SHARED, "serial idle", (void *)uart);
 	WARN_ON(ret);
 }
 
@@ -558,11 +558,17 @@
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
-		if (enable)
-			ret = request_irq(uart->p->irq, omap_uart_interrupt,
-				IRQF_SHARED, "serial idle", (void *)uart);
-		else
-			free_irq(uart->p->irq, (void *)uart);
+		if (enable) {
+			pm_runtime_put_sync(&uart->pdev->dev);
+			ret = request_threaded_irq(uart->irq, NULL,
+						   omap_uart_interrupt,
+						   IRQF_SHARED,
+						   "serial idle",
+						   (void *)uart);
+		} else {
+			pm_runtime_get_noresume(&uart->pdev->dev);
+			free_irq(uart->irq, (void *)uart);
+		}
 	}
 }
 
@@ -570,10 +576,9 @@
 				  struct device_attribute *attr,
 				  char *buf)
 {
-	struct platform_device *pdev = container_of(dev,
-					struct platform_device, dev);
-	struct omap_uart_state *uart = container_of(pdev,
-					struct omap_uart_state, pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *odev = to_omap_device(pdev);
+	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
 
 	return sprintf(buf, "%u\n", uart->timeout / HZ);
 }
@@ -582,10 +587,9 @@
 				   struct device_attribute *attr,
 				   const char *buf, size_t n)
 {
-	struct platform_device *pdev = container_of(dev,
-					struct platform_device, dev);
-	struct omap_uart_state *uart = container_of(pdev,
-					struct omap_uart_state, pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *odev = to_omap_device(pdev);
+	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
 	unsigned int value;
 
 	if (sscanf(buf, "%u", &value) != 1) {
@@ -608,48 +612,15 @@
 #define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
 #else
 static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+static void omap_uart_block_sleep(struct omap_uart_state *uart)
+{
+	/* Needed to enable UART clocks when built without CONFIG_PM */
+	omap_uart_enable_clocks(uart);
+}
 #define DEV_CREATE_FILE(dev, attr)
 #endif /* CONFIG_PM */
 
-static struct omap_uart_state omap_uart[] = {
-	{
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM,
-			.dev			= {
-				.platform_data	= serial_platform_data0,
-			},
-		},
-	}, {
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM1,
-			.dev			= {
-				.platform_data	= serial_platform_data1,
-			},
-		},
-	}, {
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM2,
-			.dev			= {
-				.platform_data	= serial_platform_data2,
-			},
-		},
-	},
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-	{
-		.pdev = {
-			.name			= "serial8250",
-			.id			= 3,
-			.dev			= {
-				.platform_data	= serial_platform_data3,
-			},
-		},
-	},
-#endif
-};
-
+#ifndef CONFIG_SERIAL_OMAP
 /*
  * Override the default 8250 read handler: mem_serial_in()
  * Empty RX fifo read causes an abort on omap3630 and omap4
@@ -682,71 +653,44 @@
 	}
 	__serial_write_reg(up, offset, value);
 }
+#endif
+
 void __init omap_serial_early_init(void)
 {
-	int i, nr_ports;
-	char name[16];
+	int i = 0;
 
-	if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-		nr_ports = 3;
-	else
-		nr_ports = ARRAY_SIZE(omap_uart);
+	do {
+		char oh_name[MAX_UART_HWMOD_NAME_LEN];
+		struct omap_hwmod *oh;
+		struct omap_uart_state *uart;
 
-	/*
-	 * Make sure the serial ports are muxed on at this point.
-	 * You have to mux them off in device drivers later on
-	 * if not needed.
-	 */
+		snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
+			 "uart%d", i + 1);
+		oh = omap_hwmod_lookup(oh_name);
+		if (!oh)
+			break;
 
-	for (i = 0; i < nr_ports; i++) {
-		struct omap_uart_state *uart = &omap_uart[i];
-		struct platform_device *pdev = &uart->pdev;
-		struct device *dev = &pdev->dev;
-		struct plat_serial8250_port *p = dev->platform_data;
+		uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
+		if (WARN_ON(!uart))
+			return;
+
+		uart->oh = oh;
+		uart->num = i++;
+		list_add_tail(&uart->node, &uart_list);
+		num_uarts++;
 
-		/* Don't map zero-based physical address */
-		if (p->mapbase == 0) {
-			dev_warn(dev, "no physical address for uart#%d,"
-				 " so skipping early_init...\n", i);
-			continue;
-		}
 		/*
-		 * Module 4KB + L4 interconnect 4KB
-		 * Static mapping, never released
+		 * NOTE: omap_hwmod_init() has not yet been called,
+		 *       so no hwmod functions will work yet.
 		 */
-		p->membase = ioremap(p->mapbase, SZ_8K);
-		if (!p->membase) {
-			dev_err(dev, "ioremap failed for uart%i\n", i + 1);
-			continue;
-		}
 
-		sprintf(name, "uart%d_ick", i + 1);
-		uart->ick = clk_get(NULL, name);
-		if (IS_ERR(uart->ick)) {
-			dev_err(dev, "Could not get uart%d_ick\n", i + 1);
-			uart->ick = NULL;
-		}
-
-		sprintf(name, "uart%d_fck", i+1);
-		uart->fck = clk_get(NULL, name);
-		if (IS_ERR(uart->fck)) {
-			dev_err(dev, "Could not get uart%d_fck\n", i + 1);
-			uart->fck = NULL;
-		}
-
-		/* FIXME: Remove this once the clkdev is ready */
-		if (!cpu_is_omap44xx()) {
-			if (!uart->ick || !uart->fck)
-				continue;
-		}
-
-		uart->num = i;
-		p->private_data = uart;
-		uart->p = p;
-
-		if (cpu_is_omap44xx())
-			p->irq += 32;
-	}
+		/*
+		 * During UART early init, device need to be probed
+		 * to determine SoC specific init before omap_device
+		 * is ready.  Therefore, don't allow idle here
+		 */
+		uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
+	} while (1);
 }
 
 /**
@@ -763,53 +707,139 @@
 void __init omap_serial_init_port(int port)
 {
 	struct omap_uart_state *uart;
-	struct platform_device *pdev;
-	struct device *dev;
-
-	BUG_ON(port < 0);
-	BUG_ON(port >= ARRAY_SIZE(omap_uart));
-
-	uart = &omap_uart[port];
-	pdev = &uart->pdev;
-	dev = &pdev->dev;
+	struct omap_hwmod *oh;
+	struct omap_device *od;
+	void *pdata = NULL;
+	u32 pdata_size = 0;
+	char *name;
+#ifndef CONFIG_SERIAL_OMAP
+	struct plat_serial8250_port ports[2] = {
+		{},
+		{.flags = 0},
+	};
+	struct plat_serial8250_port *p = &ports[0];
+#else
+	struct omap_uart_port_info omap_up;
+#endif
 
-	/* Don't proceed if there's no clocks available */
-	if (unlikely(!uart->ick || !uart->fck)) {
-		WARN(1, "%s: can't init uart%d, no clocks available\n",
-		     kobject_name(&dev->kobj), port);
+	if (WARN_ON(port < 0))
+		return;
+	if (WARN_ON(port >= num_uarts))
 		return;
-	}
-
-	omap_uart_enable_clocks(uart);
-
-	omap_uart_reset(uart);
-	omap_uart_idle_init(uart);
 
-	list_add_tail(&uart->node, &uart_list);
+	list_for_each_entry(uart, &uart_list, node)
+		if (port == uart->num)
+			break;
 
-	if (WARN_ON(platform_device_register(pdev)))
-		return;
+	oh = uart->oh;
+	uart->dma_enabled = 0;
+#ifndef CONFIG_SERIAL_OMAP
+	name = "serial8250";
 
-	if ((cpu_is_omap34xx() && uart->padconf) ||
-	    (uart->wk_en && uart->wk_mask)) {
-		device_init_wakeup(dev, true);
-		DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
-	}
+	/*
+	 * !! 8250 driver does not use standard IORESOURCE* It
+	 * has it's own custom pdata that can be taken from
+	 * the hwmod resource data.  But, this needs to be
+	 * done after the build.
+	 *
+	 * ?? does it have to be done before the register ??
+	 * YES, because platform_device_data_add() copies
+	 * pdata, it does not use a pointer.
+	 */
+	p->flags = UPF_BOOT_AUTOCONF;
+	p->iotype = UPIO_MEM;
+	p->regshift = 2;
+	p->uartclk = OMAP24XX_BASE_BAUD * 16;
+	p->irq = oh->mpu_irqs[0].irq;
+	p->mapbase = oh->slaves[0]->addr->pa_start;
+	p->membase = omap_hwmod_get_mpu_rt_va(oh);
+	p->irqflags = IRQF_SHARED;
+	p->private_data = uart;
 
 	/*
 	 * omap44xx: Never read empty UART fifo
 	 * omap3xxx: Never read empty UART fifo on UARTs
 	 * with IP rev >=0x52
 	 */
+	uart->regshift = p->regshift;
+	uart->membase = p->membase;
 	if (cpu_is_omap44xx())
 		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
-	else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
+	else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
 			>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
 		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
 
 	if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) {
-		uart->p->serial_in = serial_in_override;
-		uart->p->serial_out = serial_out_override;
+		p->serial_in = serial_in_override;
+		p->serial_out = serial_out_override;
+	}
+
+	pdata = &ports[0];
+	pdata_size = 2 * sizeof(struct plat_serial8250_port);
+#else
+
+	name = DRIVER_NAME;
+
+	omap_up.dma_enabled = uart->dma_enabled;
+	omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
+	omap_up.mapbase = oh->slaves[0]->addr->pa_start;
+	omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
+	omap_up.irqflags = IRQF_SHARED;
+	omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+	pdata = &omap_up;
+	pdata_size = sizeof(struct omap_uart_port_info);
+#endif
+
+	if (WARN_ON(!oh))
+		return;
+
+	od = omap_device_build(name, uart->num, oh, pdata, pdata_size,
+			       omap_uart_latency,
+			       ARRAY_SIZE(omap_uart_latency), false);
+	WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
+	     name, oh->name);
+
+	uart->irq = oh->mpu_irqs[0].irq;
+	uart->regshift = 2;
+	uart->mapbase = oh->slaves[0]->addr->pa_start;
+	uart->membase = omap_hwmod_get_mpu_rt_va(oh);
+	uart->pdev = &od->pdev;
+
+	oh->dev_attr = uart;
+
+	acquire_console_sem(); /* in case the earlycon is on the UART */
+
+	/*
+	 * Because of early UART probing, UART did not get idled
+	 * on init.  Now that omap_device is ready, ensure full idle
+	 * before doing omap_device_enable().
+	 */
+	omap_hwmod_idle(uart->oh);
+
+	omap_device_enable(uart->pdev);
+	omap_uart_idle_init(uart);
+	omap_uart_reset(uart);
+	omap_hwmod_enable_wakeup(uart->oh);
+	omap_device_idle(uart->pdev);
+
+	/*
+	 * Need to block sleep long enough for interrupt driven
+	 * driver to start.  Console driver is in polling mode
+	 * so device needs to be kept enabled while polling driver
+	 * is in use.
+	 */
+	if (uart->timeout)
+		uart->timeout = (30 * HZ);
+	omap_uart_block_sleep(uart);
+	uart->timeout = DEFAULT_TIMEOUT;
+
+	release_console_sem();
+
+	if ((cpu_is_omap34xx() && uart->padconf) ||
+	    (uart->wk_en && uart->wk_mask)) {
+		device_init_wakeup(&od->pdev.dev, true);
+		DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
 	}
 
 	/* Enable the MDR1 errata for OMAP3 */
@@ -826,13 +856,8 @@
  */
 void __init omap_serial_init(void)
 {
-	int i, nr_ports;
-
-	if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-		nr_ports = 3;
-	else
-		nr_ports = ARRAY_SIZE(omap_uart);
+	struct omap_uart_state *uart;
 
-	for (i = 0; i < nr_ports; i++)
-		omap_serial_init_port(i);
+	list_for_each_entry(uart, &uart_list, node)
+		omap_serial_init_port(uart->num);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/sleep34xx.S linux-libre-2.6.37-gnu/arch/arm/mach-omap2/sleep34xx.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/sleep34xx.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/sleep34xx.S	2011-01-04 19:50:19.000000000 -0500
@@ -27,11 +27,11 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <mach/io.h>
-#include <plat/control.h>
 
 #include "cm.h"
 #include "prm.h"
 #include "sdrc.h"
+#include "control.h"
 
 #define SDRC_SCRATCHPAD_SEM_V	0xfa00291c
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/sram34xx.S linux-libre-2.6.37-gnu/arch/arm/mach-omap2/sram34xx.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/sram34xx.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/sram34xx.S	2011-01-04 19:50:19.000000000 -0500
@@ -129,8 +129,11 @@
 	ldr	r4, [sp, #80]
 	str     r4, omap_sdrc_mr_1_val
 skip_cs1_params:
+	mrc	p15, 0, r8, c1, c0, 0	@ read ctrl register
+	bic	r10, r8, #0x800		@ clear Z-bit, disable branch prediction
+	mcr	p15, 0, r10, c1, c0, 0	@ write ctrl register
 	dsb				@ flush buffered writes to interconnect
-
+	isb				@ prevent speculative exec past here
 	cmp	r3, #1			@ if increasing SDRC clk rate,
 	bleq	configure_sdrc		@ program the SDRC regs early (for RFR)
 	cmp	r1, #SDRC_UNLOCK_DLL	@ set the intended DLL state
@@ -148,6 +151,7 @@
 	beq	return_to_sdram		@ return to SDRAM code, otherwise,
 	bl	configure_sdrc		@ reprogram SDRC regs now
 return_to_sdram:
+	mcr	p15, 0, r8, c1, c0, 0	@ restore ctrl register
 	isb				@ prevent speculative exec past here
 	mov 	r0, #0 			@ return value
 	ldmfd	sp!, {r1-r12, pc}	@ restore regs and return
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/timer-gp.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/timer-gp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/timer-gp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/timer-gp.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,8 @@
 #include <plat/dmtimer.h>
 #include <asm/localtimer.h>
 
+#include "timer-gp.h"
+
 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
 #define MAX_GPTIMER_ID		12
 
@@ -228,8 +230,10 @@
 static void __init omap2_gp_timer_init(void)
 {
 #ifdef CONFIG_LOCAL_TIMERS
-	twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
-	BUG_ON(!twd_base);
+	if (cpu_is_omap44xx()) {
+		twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256);
+		BUG_ON(!twd_base);
+	}
 #endif
 	omap_dm_timer_init();
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/timer-gp.h linux-libre-2.6.37-gnu/arch/arm/mach-omap2/timer-gp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/timer-gp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/timer-gp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+/*
+ * OMAP2/3 GPTIMER support.headers
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
+#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
+
+extern int __init omap2_gp_clockevent_set_gptimer(u8 id);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/usb-fs.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/usb-fs.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/usb-fs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/usb-fs.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,18 +29,18 @@
 
 #include <asm/irq.h>
 
-#include <plat/control.h>
 #include <plat/usb.h>
 #include <plat/board.h>
 
+#include "control.h"
+#include "mux.h"
+
 #define INT_USB_IRQ_GEN		INT_24XX_USB_IRQ_GEN
 #define INT_USB_IRQ_NISO	INT_24XX_USB_IRQ_NISO
 #define INT_USB_IRQ_ISO		INT_24XX_USB_IRQ_ISO
 #define INT_USB_IRQ_HGEN	INT_24XX_USB_IRQ_HGEN
 #define INT_USB_IRQ_OTG		INT_24XX_USB_IRQ_OTG
 
-#include "mux.h"
-
 #if defined(CONFIG_ARCH_OMAP2)
 
 #ifdef	CONFIG_USB_GADGET_OMAP
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-omap2/usb-musb.c linux-libre-2.6.37-gnu/arch/arm/mach-omap2/usb-musb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-omap2/usb-musb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-omap2/usb-musb.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
+#include <mach/am35xx.h>
 #include <plat/usb.h>
 
 #ifdef CONFIG_USB_MUSB_SOC
@@ -89,6 +90,9 @@
 {
 	if (cpu_is_omap243x()) {
 		musb_resources[0].start = OMAP243X_HS_BASE;
+	} else if (cpu_is_omap3517() || cpu_is_omap3505()) {
+		musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
+		musb_resources[1].start = INT_35XX_USBOTG_IRQ;
 	} else if (cpu_is_omap34xx()) {
 		musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
 	} else if (cpu_is_omap44xx()) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/d2net-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/d2net-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/d2net-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/d2net-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -336,8 +336,6 @@
 
 #ifdef CONFIG_MACH_D2NET
 MACHINE_START(D2NET, "LaCie d2 Network")
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= d2net_init,
 	.map_io		= orion5x_map_io,
@@ -349,8 +347,6 @@
 
 #ifdef CONFIG_MACH_BIGDISK
 MACHINE_START(BIGDISK, "LaCie Big Disk Network")
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= d2net_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/db88f5281-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/db88f5281-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/db88f5281-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/db88f5281-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -358,8 +358,6 @@
 
 MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
 	/* Maintainer: Tzachi Perelstein <tzachi@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.init_machine	= db88f5281_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/dns323-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/dns323-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/dns323-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/dns323-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -730,8 +730,6 @@
 /* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
 MACHINE_START(DNS323, "D-Link DNS-323")
 	/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= dns323_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/edmini_v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/edmini_v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/edmini_v2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/edmini_v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -251,8 +251,6 @@
 /* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
 MACHINE_START(EDMINI_V2, "LaCie Ethernet Disk mini V2")
 	/* Maintainer: Christopher Moore <moore@free.fr> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= edmini_v2_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,12 +10,11 @@
 
 #include <mach/orion5x.h>
 
-	.macro  addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =ORION5X_REGS_PHYS_BASE
-	ldrne	\rx, =ORION5X_REGS_VIRT_BASE
-	orr	\rx, \rx, #0x00012000
+	.macro  addruart, rp, rv
+	ldr	\rp, =ORION5X_REGS_PHYS_BASE
+	ldr	\rv, =ORION5X_REGS_VIRT_BASE
+	orr	\rp, \rp, #0x00012000
+	orr	\rv, \rv, #0x00012000
 	.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/kurobox_pro-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/kurobox_pro-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/kurobox_pro-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/kurobox_pro-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -379,8 +379,6 @@
 #ifdef CONFIG_MACH_KUROBOX_PRO
 MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
 	/* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= kurobox_pro_init,
 	.map_io		= orion5x_map_io,
@@ -393,8 +391,6 @@
 #ifdef CONFIG_MACH_LINKSTATION_PRO
 MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
 	/* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= kurobox_pro_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ls_hgl-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ls_hgl-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ls_hgl-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ls_hgl-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -265,8 +265,6 @@
 
 MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
 	/* Maintainer: Zhu Qingsen <zhuqs@cn.fujistu.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= ls_hgl_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/lsmini-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/lsmini-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/lsmini-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/lsmini-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -267,8 +267,6 @@
 #ifdef CONFIG_MACH_LINKSTATION_MINI
 MACHINE_START(LINKSTATION_MINI, "Buffalo Linkstation Mini")
 	/* Maintainer: Alexey Kopytko <alexey@kopytko.ru> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= lsmini_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mpp.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -127,7 +127,7 @@
 	/* Initialize gpiolib. */
 	orion_gpio_init();
 
-	while (mode->mpp >= 0) {
+	for ( ; mode->mpp >= 0; mode++) {
 		u32 *reg;
 		int num_type;
 		int shift;
@@ -160,8 +160,6 @@
 			orion_gpio_set_unused(mode->mpp);
 
 		orion_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
-
-		mode++;
 	}
 
 	writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mss2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mss2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mss2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mss2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -261,8 +261,6 @@
 
 MACHINE_START(MSS2, "Maxtor Shared Storage II")
 	/* Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= mss2_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mv2120-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mv2120-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/mv2120-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/mv2120-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -229,8 +229,6 @@
 /* Warning: HP uses a wrong mach-type (=526) in their bootloader */
 MACHINE_START(MV2120, "HP Media Vault mv2120")
 	/* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= mv2120_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/net2big-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/net2big-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/net2big-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/net2big-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -419,8 +419,6 @@
 
 /* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
 MACHINE_START(NET2BIG, "LaCie 2Big Network")
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= net2big_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -169,8 +169,6 @@
 
 MACHINE_START(RD88F5181L_FXO, "Marvell Orion-VoIP FXO Reference Design")
 	/* Maintainer: Nicolas Pitre <nico@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f5181l_fxo_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,8 +181,6 @@
 
 MACHINE_START(RD88F5181L_GE, "Marvell Orion-VoIP GE Reference Design")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f5181l_ge_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5182-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5182-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f5182-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f5182-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -305,8 +305,6 @@
 
 MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
 	/* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f5182_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -123,8 +123,6 @@
 
 MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= rd88f6183ap_ge_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/terastation_pro2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/terastation_pro2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/terastation_pro2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/terastation_pro2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -358,8 +358,6 @@
 
 MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
 	/* Maintainer:  Sylver Bruneau <sylver.bruneau@googlemail.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= tsp2_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts209-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts209-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts209-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts209-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -322,8 +322,6 @@
 
 MACHINE_START(TS209, "QNAP TS-109/TS-209")
 	/* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= qnap_ts209_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts409-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts409-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts409-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts409-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -311,8 +311,6 @@
 
 MACHINE_START(TS409, "QNAP TS-409")
 	/* Maintainer:  Sylver Bruneau <sylver.bruneau@gmail.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= qnap_ts409_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts78xx-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts78xx-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/ts78xx-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/ts78xx-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -239,7 +239,7 @@
 static struct resource ts78xx_ts_nand_resources = {
 	.start		= TS_NAND_DATA,
 	.end		= TS_NAND_DATA + 4,
-	.flags		= IORESOURCE_IO,
+	.flags		= IORESOURCE_MEM,
 };
 
 static struct platform_device ts78xx_ts_nand_device = {
@@ -550,8 +550,6 @@
 
 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
 	/* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= ts78xx_init,
 	.map_io		= ts78xx_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/wnr854t-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/wnr854t-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/wnr854t-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/wnr854t-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -172,8 +172,6 @@
 
 MACHINE_START(WNR854T, "Netgear WNR854T")
 	/* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= wnr854t_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/wrt350n-v2-setup.c linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/wrt350n-v2-setup.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-orion5x/wrt350n-v2-setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-orion5x/wrt350n-v2-setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -260,8 +260,6 @@
 
 MACHINE_START(WRT350N_V2, "Linksys WRT350N v2")
 	/* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-	.phys_io	= ORION5X_REGS_PHYS_BASE,
-	.io_pg_offst	= ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
 	.boot_params	= 0x00000100,
 	.init_machine	= wrt350n_v2_init,
 	.map_io		= orion5x_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/core.c linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -264,8 +264,6 @@
 
 MACHINE_START(PNX4008, "Philips PNX4008")
 	/* Maintainer: MontaVista Software Inc. */
-	.phys_io 		= 0x40090000,
-	.io_pg_offst 		= (0xf4090000 >> 18) & 0xfffc,
 	.boot_params		= 0x80000100,
 	.map_io 		= pnx4008_map_io,
 	.init_irq 		= pnx4008_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,10 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		mov	\rx, #0x00090000
-		addeq	\rx, \rx, #0x40000000
-		addne	\rx, \rx, #0xf4000000
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00090000
+		add	\rv, \rp, #0xf4000000	@ virtual
+		add	\rp, \rp, #0x40000000	@ physical
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pnx4008/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pnx4008/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,4 +17,4 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/balloon3.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/balloon3.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/balloon3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/balloon3.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,42 +68,6 @@
 
 	/* Reset, configured as GPIO wakeup source */
 	GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
-
-	/* LEDs */
-	GPIO9_GPIO,	/* NAND activity LED */
-	GPIO10_GPIO,	/* Heartbeat LED */
-
-	/* AC97 */
-	GPIO28_AC97_BITCLK,
-	GPIO29_AC97_SDATA_IN_0,
-	GPIO30_AC97_SDATA_OUT,
-	GPIO31_AC97_SYNC,
-	GPIO113_AC97_nRESET,
-	GPIO95_GPIO,
-
-	/* MMC */
-	GPIO32_MMC_CLK,
-	GPIO92_MMC_DAT_0,
-	GPIO109_MMC_DAT_1,
-	GPIO110_MMC_DAT_2,
-	GPIO111_MMC_DAT_3,
-	GPIO112_MMC_CMD,
-
-	/* USB Host */
-	GPIO88_USBH1_PWR,
-	GPIO89_USBH1_PEN,
-
-	/* PC Card */
-	GPIO48_nPOE,
-	GPIO49_nPWE,
-	GPIO50_nPIOR,
-	GPIO51_nPIOW,
-	GPIO85_nPCE_1,
-	GPIO54_nPCE_2,
-	GPIO79_PSKTSEL,
-	GPIO55_nPREG,
-	GPIO56_nPWAIT,
-	GPIO57_nIOIS16,
 };
 
 /******************************************************************************
@@ -132,6 +96,34 @@
 early_param("balloon3_features", parse_balloon3_features);
 
 /******************************************************************************
+ * Compact Flash slot
+ ******************************************************************************/
+#if	defined(CONFIG_PCMCIA_PXA2XX) || defined(CONFIG_PCMCIA_PXA2XX_MODULE)
+static unsigned long balloon3_cf_pin_config[] __initdata = {
+	GPIO48_nPOE,
+	GPIO49_nPWE,
+	GPIO50_nPIOR,
+	GPIO51_nPIOW,
+	GPIO85_nPCE_1,
+	GPIO54_nPCE_2,
+	GPIO79_PSKTSEL,
+	GPIO55_nPREG,
+	GPIO56_nPWAIT,
+	GPIO57_nIOIS16,
+};
+
+static void __init balloon3_cf_init(void)
+{
+	if (!balloon3_has(BALLOON3_FEATURE_CF))
+		return;
+
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_cf_pin_config));
+}
+#else
+static inline void balloon3_cf_init(void) {}
+#endif
+
+/******************************************************************************
  * NOR Flash
  ******************************************************************************/
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
@@ -179,6 +171,15 @@
  ******************************************************************************/
 #if	defined(CONFIG_TOUCHSCREEN_UCB1400) || \
 	defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE)
+static unsigned long balloon3_ac97_pin_config[] __initdata = {
+	GPIO28_AC97_BITCLK,
+	GPIO29_AC97_SDATA_IN_0,
+	GPIO30_AC97_SDATA_OUT,
+	GPIO31_AC97_SYNC,
+	GPIO113_AC97_nRESET,
+	GPIO95_GPIO,
+};
+
 static struct ucb1400_pdata vpac270_ucb1400_pdata = {
 	.irq		= IRQ_GPIO(BALLOON3_GPIO_CODEC_IRQ),
 };
@@ -197,6 +198,7 @@
 	if (!balloon3_has(BALLOON3_FEATURE_AUDIO))
 		return;
 
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_ac97_pin_config));
 	pxa_set_ac97_info(NULL);
 	platform_device_register(&balloon3_ucb1400_device);
 }
@@ -208,6 +210,11 @@
  * Framebuffer
  ******************************************************************************/
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static unsigned long balloon3_lcd_pin_config[] __initdata = {
+	GPIOxx_LCD_TFT_16BPP,
+	GPIO99_GPIO,
+};
+
 static struct pxafb_mode_info balloon3_lcd_modes[] = {
 	{
 		.pixclock		= 38000,
@@ -242,6 +249,8 @@
 	if (!balloon3_has(BALLOON3_FEATURE_TOPPOLY))
 		return;
 
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_lcd_pin_config));
+
 	ret = gpio_request(BALLOON3_GPIO_RUN_BACKLIGHT, "BKL-ON");
 	if (ret) {
 		pr_err("Requesting BKL-ON GPIO failed!\n");
@@ -271,6 +280,15 @@
  * SD/MMC card controller
  ******************************************************************************/
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
+static unsigned long balloon3_mmc_pin_config[] __initdata = {
+	GPIO32_MMC_CLK,
+	GPIO92_MMC_DAT_0,
+	GPIO109_MMC_DAT_1,
+	GPIO110_MMC_DAT_2,
+	GPIO111_MMC_DAT_3,
+	GPIO112_MMC_CMD,
+};
+
 static struct pxamci_platform_data balloon3_mci_platform_data = {
 	.ocr_mask		= MMC_VDD_32_33 | MMC_VDD_33_34,
 	.gpio_card_detect	= -1,
@@ -281,6 +299,7 @@
 
 static void __init balloon3_mmc_init(void)
 {
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_mmc_pin_config));
 	pxa_set_mci_info(&balloon3_mci_platform_data);
 }
 #else
@@ -339,6 +358,11 @@
  * USB Host
  ******************************************************************************/
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static unsigned long balloon3_uhc_pin_config[] __initdata = {
+	GPIO88_USBH1_PWR,
+	GPIO89_USBH1_PEN,
+};
+
 static struct pxaohci_platform_data balloon3_ohci_info = {
 	.port_mode	= PMM_PERPORT_MODE,
 	.flags		= ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
@@ -348,6 +372,7 @@
 {
 	if (!balloon3_has(BALLOON3_FEATURE_OHCI))
 		return;
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_uhc_pin_config));
 	pxa_set_ohci_info(&balloon3_ohci_info);
 }
 #else
@@ -358,6 +383,11 @@
  * LEDs
  ******************************************************************************/
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static unsigned long balloon3_led_pin_config[] __initdata = {
+	GPIO9_GPIO,	/* NAND activity LED */
+	GPIO10_GPIO,	/* Heartbeat LED */
+};
+
 struct gpio_led balloon3_gpio_leds[] = {
 	{
 		.name			= "balloon3:green:idle",
@@ -436,6 +466,7 @@
 
 static void __init balloon3_leds_init(void)
 {
+	pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_led_pin_config));
 	platform_device_register(&balloon3_leds);
 	platform_device_register(&balloon3_pcf_leds);
 }
@@ -757,6 +788,7 @@
 	balloon3_ts_init();
 	balloon3_udc_init();
 	balloon3_uhc_init();
+	balloon3_cf_init();
 }
 
 static struct map_desc balloon3_io_desc[] __initdata = {
@@ -776,9 +808,8 @@
 
 MACHINE_START(BALLOON3, "Balloon3")
 	/* Maintainer: Nick Bane. */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= balloon3_map_io,
+	.nr_irqs	= BALLOON3_NR_IRQS,
 	.init_irq	= balloon3_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= balloon3_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/capc7117.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/capc7117.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/capc7117.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/capc7117.c	2011-01-04 19:50:19.000000000 -0500
@@ -148,9 +148,7 @@
 
 MACHINE_START(CAPC7117,
 	      "Embedian CAPC-7117 evaluation kit based on the MXM-8x10 CoM")
-	.phys_io = 0x40000000,
 	.boot_params = 0xa0000100,
-	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io = pxa_map_io,
 	.init_irq = pxa3xx_init_irq,
 	.timer = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cm-x2xx.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cm-x2xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cm-x2xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cm-x2xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,9 @@
 extern void cmx255_init(void);
 extern void cmx270_init(void);
 
+/* reserve IRQs for IT8152 */
+#define CMX2XX_NR_IRQS		(IRQ_BOARD_START + 40)
+
 /* virtual addresses for statically mapped regions */
 #define CMX2XX_VIRT_BASE	(0xe8000000)
 #define CMX2XX_IT8152_VIRT	(CMX2XX_VIRT_BASE)
@@ -473,8 +476,6 @@
 
 static void __init cmx2xx_init_irq(void)
 {
-	pxa27x_init_irq();
-
 	if (cpu_is_pxa25x()) {
 		pxa25x_init_irq();
 		cmx2xx_pci_init_irq(CMX255_GPIO_IT8152_IRQ);
@@ -511,9 +512,8 @@
 
 MACHINE_START(ARMCORE, "Compulab CM-X2XX")
 	.boot_params	= 0xa0000100,
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= cmx2xx_map_io,
+	.nr_irqs	= CMX2XX_NR_IRQS,
 	.init_irq	= cmx2xx_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= cmx2xx_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cm-x300.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cm-x300.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cm-x300.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cm-x300.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
@@ -50,6 +51,7 @@
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 #include <mach/audio.h>
+#include <mach/pxa3xx-u2d.h>
 
 #include <asm/mach/map.h>
 
@@ -68,6 +70,8 @@
 #define GPIO97_RTC_RD		(97)
 #define GPIO98_RTC_IO		(98)
 
+#define GPIO_ULPI_PHY_RST	(127)
+
 static mfp_cfg_t cm_x3xx_mfp_cfg[] __initdata = {
 	/* LCD */
 	GPIO54_LCD_LDD_0,
@@ -472,6 +476,78 @@
 static inline void cm_x300_init_mmc(void) {}
 #endif
 
+#if defined(CONFIG_PXA310_ULPI)
+static struct clk *pout_clk;
+
+static int cm_x300_ulpi_phy_reset(void)
+{
+	int err;
+
+	/* reset the PHY */
+	err = gpio_request(GPIO_ULPI_PHY_RST, "ulpi reset");
+	if (err) {
+		pr_err("%s: failed to request ULPI reset GPIO: %d\n",
+		       __func__, err);
+		return err;
+	}
+
+	gpio_direction_output(GPIO_ULPI_PHY_RST, 0);
+	msleep(10);
+	gpio_set_value(GPIO_ULPI_PHY_RST, 1);
+	msleep(10);
+
+	gpio_free(GPIO_ULPI_PHY_RST);
+
+	return 0;
+}
+
+static inline int cm_x300_u2d_init(struct device *dev)
+{
+	int err = 0;
+
+	if (cpu_is_pxa310()) {
+		/* CLK_POUT is connected to the ULPI PHY */
+		pout_clk = clk_get(NULL, "CLK_POUT");
+		if (IS_ERR(pout_clk)) {
+			err = PTR_ERR(pout_clk);
+			pr_err("%s: failed to get CLK_POUT: %d\n",
+			       __func__, err);
+			return err;
+		}
+		clk_enable(pout_clk);
+
+		err = cm_x300_ulpi_phy_reset();
+		if (err) {
+			clk_disable(pout_clk);
+			clk_put(pout_clk);
+		}
+	}
+
+	return err;
+}
+
+static void cm_x300_u2d_exit(struct device *dev)
+{
+	if (cpu_is_pxa310()) {
+		clk_disable(pout_clk);
+		clk_put(pout_clk);
+	}
+}
+
+static struct pxa3xx_u2d_platform_data cm_x300_u2d_platform_data = {
+	.ulpi_mode	= ULPI_SER_6PIN,
+	.init		= cm_x300_u2d_init,
+	.exit		= cm_x300_u2d_exit,
+};
+
+static void cm_x300_init_u2d(void)
+{
+	pxa3xx_set_u2d_info(&cm_x300_u2d_platform_data);
+}
+#else
+static inline void cm_x300_init_u2d(void) {}
+#endif
+
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 static int cm_x300_ohci_init(struct device *dev)
 {
@@ -754,6 +830,7 @@
 	cm_x300_init_da9030();
 	cm_x300_init_dm9000();
 	cm_x300_init_lcd();
+	cm_x300_init_u2d();
 	cm_x300_init_ohci();
 	cm_x300_init_mmc();
 	cm_x300_init_nand();
@@ -779,9 +856,7 @@
 }
 
 MACHINE_START(CM_X300, "CM-X300 module")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa3xx_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa270.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa270.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa270.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa270.c	2011-01-04 19:50:19.000000000 -0500
@@ -207,8 +207,6 @@
 }
 
 MACHINE_START(COLIBRI, "Toradex Colibri PXA270")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= COLIBRI_SDRAM_BASE + 0x100,
 	.init_machine	= colibri_pxa270_init,
 	.map_io		= pxa_map_io,
@@ -217,8 +215,6 @@
 MACHINE_END
 
 MACHINE_START(INCOME, "Income s.r.o. SH-Dmaster PXA270 SBC")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.init_machine	= colibri_pxa270_income_init,
 	.map_io		= pxa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa300.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa300.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa300.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa300.c	2011-01-04 19:50:19.000000000 -0500
@@ -186,8 +186,6 @@
 }
 
 MACHINE_START(COLIBRI300, "Toradex Colibri PXA300")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= COLIBRI_SDRAM_BASE + 0x100,
 	.init_machine	= colibri_pxa300_init,
 	.map_io		= pxa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa320.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa320.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/colibri-pxa320.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/colibri-pxa320.c	2011-01-04 19:50:19.000000000 -0500
@@ -255,8 +255,6 @@
 }
 
 MACHINE_START(COLIBRI320, "Toradex Colibri PXA320")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= COLIBRI_SDRAM_BASE + 0x100,
 	.init_machine	= colibri_pxa320_init,
 	.map_io		= pxa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/corgi.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/corgi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/corgi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/corgi.c	2011-01-04 19:50:19.000000000 -0500
@@ -720,8 +720,6 @@
 
 #ifdef CONFIG_MACH_CORGI
 MACHINE_START(CORGI, "SHARP Corgi")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
@@ -732,8 +730,6 @@
 
 #ifdef CONFIG_MACH_SHEPHERD
 MACHINE_START(SHEPHERD, "SHARP Shepherd")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
@@ -744,8 +740,6 @@
 
 #ifdef CONFIG_MACH_HUSKY
 MACHINE_START(HUSKY, "SHARP Husky")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_corgi,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cpufreq-pxa3xx.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cpufreq-pxa3xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/cpufreq-pxa3xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/cpufreq-pxa3xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -159,7 +159,7 @@
 
 static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)
 {
-	return get_clk_frequency_khz(0);
+	return pxa3xx_get_clk_frequency_khz(0);
 }
 
 static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
@@ -212,7 +212,8 @@
 	policy->cpuinfo.min_freq = 104000;
 	policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
 	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
-	policy->cur = policy->min = policy->max = get_clk_frequency_khz(0);
+	policy->max = pxa3xx_get_clk_frequency_khz(0);
+	policy->cur = policy->min = policy->max;
 
 	if (cpu_is_pxa300() || cpu_is_pxa310())
 		ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs));
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/csb726.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/csb726.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/csb726.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/csb726.c	2011-01-04 19:50:19.000000000 -0500
@@ -272,9 +272,7 @@
 }
 
 MACHINE_START(CSB726, "Cogent CSB726")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io         = pxa_map_io,
 	.init_irq       = pxa27x_init_irq,
 	.init_machine   = csb726_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,11 +6,12 @@
 
 #include <asm/pmu.h>
 #include <mach/udc.h>
+#include <mach/pxa3xx-u2d.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
@@ -134,6 +135,33 @@
 	}
 };
 
+#ifdef CONFIG_PXA3xx
+static struct resource pxa3xx_u2d_resources[] = {
+	[0] = {
+		.start	= 0x54100000,
+		.end	= 0x54100fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_USB2,
+		.end	= IRQ_USB2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device pxa3xx_device_u2d = {
+	.name		= "pxa3xx-u2d",
+	.id		= -1,
+	.resource	= pxa3xx_u2d_resources,
+	.num_resources	= ARRAY_SIZE(pxa3xx_u2d_resources),
+};
+
+void __init pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info)
+{
+	pxa_register_device(&pxa3xx_device_u2d, info);
+}
+#endif /* CONFIG_PXA3xx */
+
 static struct resource pxafb_resources[] = {
 	[0] = {
 		.start	= 0x44000000,
@@ -354,6 +382,31 @@
 	.num_resources	= ARRAY_SIZE(pxai2s_resources),
 };
 
+struct platform_device pxa_device_asoc_ssp1 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+	.name		= "pxa-ssp-dai",
+	.id		= 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+	.name		= "pxa-pcm-audio",
+	.id		= -1,
+};
+
 static u64 pxaficp_dmamask = ~(u32)0;
 
 struct platform_device pxa_device_ficp = {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,7 @@
 extern struct platform_device pxa3xx_device_mci3;
 extern struct platform_device pxa25x_device_udc;
 extern struct platform_device pxa27x_device_udc;
+extern struct platform_device pxa3xx_device_u2d;
 extern struct platform_device pxa_device_fb;
 extern struct platform_device pxa_device_ffuart;
 extern struct platform_device pxa_device_btuart;
@@ -38,4 +39,10 @@
 
 extern struct platform_device pxa3xx_device_gcu;
 
+extern struct platform_device pxa_device_asoc_platform;
+extern struct platform_device pxa_device_asoc_ssp1;
+extern struct platform_device pxa_device_asoc_ssp2;
+extern struct platform_device pxa_device_asoc_ssp3;
+extern struct platform_device pxa_device_asoc_ssp4;
+
 void __init pxa_register_device(struct platform_device *dev, void *data);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/em-x270.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/em-x270.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/em-x270.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/em-x270.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
 #include <mach/mmc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/pxa2xx_spi.h>
@@ -1015,7 +1015,6 @@
 	.power		= em_x270_sensor_power,
 	.board_info	= &em_x270_i2c_cam_info[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "mt9m111",
 };
 
 static struct platform_device em_x270_camera = {
@@ -1301,8 +1300,6 @@
 
 MACHINE_START(EM_X270, "Compulab EM-X270")
 	.boot_params	= 0xa0000100,
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
 	.timer		= &pxa_timer,
@@ -1311,8 +1308,6 @@
 
 MACHINE_START(EXEDA, "Compulab eXeda")
 	.boot_params	= 0xa0000100,
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/eseries.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/eseries.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/eseries.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/eseries.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,6 +29,7 @@
 
 #include <mach/pxa25x.h>
 #include <mach/eseries-gpio.h>
+#include <mach/eseries-irq.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
 #include <mach/udc.h>
@@ -179,10 +180,9 @@
 
 MACHINE_START(E330, "Toshiba e330")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e330_init,
@@ -229,10 +229,9 @@
 
 MACHINE_START(E350, "Toshiba e350")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e350_init,
@@ -352,10 +351,9 @@
 
 MACHINE_START(E400, "Toshiba e400")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e400_init,
@@ -541,10 +539,9 @@
 
 MACHINE_START(E740, "Toshiba e740")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e740_init,
@@ -733,10 +730,9 @@
 
 MACHINE_START(E750, "Toshiba e750")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e750_init,
@@ -929,10 +925,9 @@
 
 MACHINE_START(E800, "Toshiba e800")
 	/* Maintainer: Ian Molton (spyro@f2s.com) */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ESERIES_NR_IRQS,
 	.init_irq	= pxa25x_init_irq,
 	.fixup		= eseries_fixup,
 	.init_machine	= e800_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/ezx.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/ezx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/ezx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/ezx.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,12 +32,14 @@
 #include <mach/ohci.h>
 #include <plat/i2c.h>
 #include <mach/hardware.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/camera.h>
 
 #include "devices.h"
 #include "generic.h"
 
+#define EZX_NR_IRQS			(IRQ_BOARD_START + 24)
+
 #define GPIO12_A780_FLIP_LID 		12
 #define GPIO15_A1200_FLIP_LID 		15
 #define GPIO15_A910_FLIP_LID 		15
@@ -753,7 +755,6 @@
 	.flags          = SOCAM_SENSOR_INVERT_PCLK,
 	.i2c_adapter_id = 0,
 	.board_info     = &a780_camera_i2c_board_info,
-	.module_name    = "mt9m111",
 	.power          = a780_camera_power,
 	.reset          = a780_camera_reset,
 };
@@ -796,10 +797,9 @@
 }
 
 MACHINE_START(EZX_A780, "Motorola EZX A780")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = a780_init,
@@ -862,10 +862,9 @@
 }
 
 MACHINE_START(EZX_E680, "Motorola EZX E680")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = e680_init,
@@ -928,10 +927,9 @@
 }
 
 MACHINE_START(EZX_A1200, "Motorola EZX A1200")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = a1200_init,
@@ -1025,7 +1023,6 @@
 	.bus_id         = 0,
 	.i2c_adapter_id = 0,
 	.board_info     = &a910_camera_i2c_board_info,
-	.module_name    = "mt9m111",
 	.power          = a910_camera_power,
 	.reset          = a910_camera_reset,
 };
@@ -1120,10 +1117,9 @@
 }
 
 MACHINE_START(EZX_A910, "Motorola EZX A910")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = a910_init,
@@ -1186,10 +1182,9 @@
 }
 
 MACHINE_START(EZX_E6, "Motorola EZX E6")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = e6_init,
@@ -1226,10 +1221,9 @@
 }
 
 MACHINE_START(EZX_E2, "Motorola EZX E2")
-	.phys_io        = 0x40000000,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= EZX_NR_IRQS,
 	.init_irq       = pxa27x_init_irq,
 	.timer          = &pxa_timer,
 	.init_machine   = e2_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/generic.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/generic.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,8 +66,7 @@
 		return pxa25x_get_clk_frequency_khz(info);
 	else if (cpu_is_pxa27x())
 		return pxa27x_get_clk_frequency_khz(info);
-	else
-		return pxa3xx_get_clk_frequency_khz(info);
+	return 0;
 }
 EXPORT_SYMBOL(get_clk_frequency_khz);
 
@@ -80,8 +79,7 @@
 		return pxa25x_get_memclk_frequency_10khz();
 	else if (cpu_is_pxa27x())
 		return pxa27x_get_memclk_frequency_10khz();
-	else
-		return pxa3xx_get_memclk_frequency_10khz();
+	return 0;
 }
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/generic.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/generic.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/generic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/generic.h	2011-01-04 19:50:19.000000000 -0500
@@ -54,11 +54,9 @@
 
 #ifdef CONFIG_PXA3xx
 extern unsigned pxa3xx_get_clk_frequency_khz(int);
-extern unsigned pxa3xx_get_memclk_frequency_10khz(void);
 extern void pxa3xx_clear_reset_status(unsigned int);
 #else
 #define pxa3xx_get_clk_frequency_khz(x)		(0)
-#define pxa3xx_get_memclk_frequency_10khz()	(0)
 static inline void pxa3xx_clear_reset_status(unsigned int mask) {}
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/gumstix.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/gumstix.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/gumstix.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/gumstix.c	2011-01-04 19:50:19.000000000 -0500
@@ -224,9 +224,7 @@
 }
 
 MACHINE_START(GUMSTIX, "Gumstix")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100, /* match u-boot bi_boot_params */
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/h5000.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/h5000.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/h5000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/h5000.c	2011-01-04 19:50:19.000000000 -0500
@@ -201,8 +201,6 @@
 }
 
 MACHINE_START(H5400, "HP iPAQ H5000")
-	.phys_io = 0x40000000,
-	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params = 0xa0000100,
 	.map_io = pxa_map_io,
 	.init_irq = pxa25x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/himalaya.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/himalaya.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/himalaya.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/himalaya.c	2011-01-04 19:50:19.000000000 -0500
@@ -159,8 +159,6 @@
 
 
 MACHINE_START(HIMALAYA, "HTC Himalaya")
-	.phys_io = 0x40000000,
-	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params = 0xa0000100,
 	.map_io = pxa_map_io,
 	.init_irq = pxa25x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/hx4700.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/hx4700.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/hx4700.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/hx4700.c	2011-01-04 19:50:19.000000000 -0500
@@ -870,10 +870,9 @@
 }
 
 MACHINE_START(H4700, "HP iPAQ HX4700")
-	.phys_io      = 0x40000000,
-	.io_pg_offst  = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params  = 0xa0000100,
 	.map_io       = pxa_map_io,
+	.nr_irqs      = HX4700_NR_IRQS,
 	.init_irq     = pxa27x_init_irq,
 	.init_machine = hx4700_init,
 	.timer        = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/icontrol.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/icontrol.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/icontrol.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/icontrol.c	2011-01-04 19:50:19.000000000 -0500
@@ -191,9 +191,7 @@
 }
 
 MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa3xx_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/idp.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/idp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/idp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/idp.c	2011-01-04 19:50:19.000000000 -0500
@@ -194,8 +194,6 @@
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
 	/* Maintainer: Vibren Technologies */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= idp_map_io,
 	.init_irq	= pxa25x_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/balloon3.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/balloon3.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/balloon3.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/balloon3.h	2011-01-04 19:50:19.000000000 -0500
@@ -174,6 +174,8 @@
 #define BALLOON3_CODEC_IRQ	IRQ_GPIO(BALLOON3_GPIO_CODEC_IRQ)
 #define BALLOON3_S0_CD_IRQ	IRQ_GPIO(BALLOON3_GPIO_S0_CD)
 
+#define BALLOON3_NR_IRQS	(IRQ_BOARD_START + 4)
+
 extern int balloon3_has(enum balloon3_features feature);
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -13,12 +13,10 @@
 
 #include "hardware.h"
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x40000000		@ physical
-		movne	\rx, #io_p2v(0x40000000)	@ virtual
-		orr	\rx, \rx, #0x00100000
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00100000
+		orr	\rv, \rp, #io_p2v(0x40000000)	@ virtual
+		orr	\rp, \rp, #0x40000000		@ physical
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/eseries-irq.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/eseries-irq.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/eseries-irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/eseries-irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,3 +25,4 @@
 #define TMIO_SD_IRQ     IRQ_TMIO(1)
 #define TMIO_USB_IRQ    IRQ_TMIO(2)
 
+#define ESERIES_NR_IRQS	(IRQ_BOARD_START + 16)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/hx4700.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/hx4700.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/hx4700.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/hx4700.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
 
 #define HX4700_ASIC3_GPIO_BASE	NR_BUILTIN_GPIO
 #define HX4700_EGPIO_BASE	(HX4700_ASIC3_GPIO_BASE + ASIC3_NUM_GPIOS)
+#define HX4700_NR_IRQS		(IRQ_BOARD_START + 70)
 
 /*
  * PXA GPIOs
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -117,48 +117,12 @@
 /*
  * The following interrupts are for board specific purposes. Since
  * the kernel can only run on one machine at a time, we can re-use
- * these.  There will be 16 IRQs by default.  If it is not enough,
- * IRQ_BOARD_END is allowed be customized for each board, but keep
- * the numbers within sensible limits and in descending order, so
- * when multiple config options are selected, the maximum will be
- * used.
+ * these.
+ * By default, no board IRQ is reserved. It should be finished in
+ * custom board since sparse IRQ is already enabled.
  */
 #define IRQ_BOARD_START		(PXA_GPIO_IRQ_BASE + PXA_GPIO_IRQ_NUM)
 
-#if defined(CONFIG_MACH_H4700)
-#define IRQ_BOARD_END		(IRQ_BOARD_START + 70)
-#elif defined(CONFIG_MACH_ZYLONITE)
-#define IRQ_BOARD_END		(IRQ_BOARD_START + 32)
-#elif defined(CONFIG_PXA_EZX)
-#define IRQ_BOARD_END		(IRQ_BOARD_START + 23)
-#else
-#define IRQ_BOARD_END		(IRQ_BOARD_START + 16)
-#endif
-
-/*
- * Figure out the MAX IRQ number.
- *
- * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
- * If we have an LoCoMo, the max IRQ is IRQ_LOCOMO_SPI_TEND+1
- * Otherwise, we have the standard IRQs only.
- */
-#ifdef CONFIG_SA1111
-#define NR_IRQS			(IRQ_BOARD_END + 55)
-#elif defined(CONFIG_PXA_HAVE_BOARD_IRQS)
-#define NR_IRQS			(IRQ_BOARD_END)
-#else
 #define NR_IRQS			(IRQ_BOARD_START)
-#endif
-
-/* add IT8152 IRQs beyond BOARD_END */
-#ifdef CONFIG_PCI_HOST_ITE8152
-#define IT8152_LAST_IRQ         (IRQ_BOARD_END + 40)
-
-#if NR_IRQS < (IT8152_LAST_IRQ+1)
-#undef NR_IRQS
-#define NR_IRQS (IT8152_LAST_IRQ+1)
-#endif
-
-#endif /* CONFIG_PCI_HOST_ITE8152 */
 
 #endif /* __ASM_MACH_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/littleton.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/littleton.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/littleton.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/littleton.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,4 +10,6 @@
 #define EXT0_GPIO_BASE	(NR_BUILTIN_GPIO)
 #define EXT0_GPIO(x)	(EXT0_GPIO_BASE + (x))
 
+#define LITTLETON_NR_IRQS	(IRQ_BOARD_START + 8)
+
 #endif /* __ASM_ARCH_LITTLETON_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/lpd270.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/lpd270.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/lpd270.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/lpd270.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,5 +38,6 @@
 #define LPD270_USBC_IRQ		LPD270_IRQ(2)
 #define LPD270_ETHERNET_IRQ	LPD270_IRQ(3)
 #define LPD270_AC97_IRQ		LPD270_IRQ(4)
+#define LPD270_NR_IRQS		(IRQ_BOARD_START + 5)
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/lubbock.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/lubbock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/lubbock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/lubbock.h	2011-01-04 19:50:19.000000000 -0500
@@ -45,6 +45,9 @@
 #define LUBBOCK_USB_DISC_IRQ	LUBBOCK_IRQ(6)  /* usb disconnect */
 #define LUBBOCK_LAST_IRQ	LUBBOCK_IRQ(6)
 
+#define LUBBOCK_SA1111_IRQ_BASE	(IRQ_BOARD_START + 16)
+#define LUBBOCK_NR_IRQS		(IRQ_BOARD_START + 16 + 55)
+
 #ifndef __ASSEMBLY__
 extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/magician.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/magician.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/magician.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/magician.h	2011-01-04 19:50:19.000000000 -0500
@@ -71,6 +71,8 @@
 #define IRQ_MAGICIAN_BT		(IRQ_BOARD_START + 2)
 #define IRQ_MAGICIAN_VBUS	(IRQ_BOARD_START + 3)
 
+#define MAGICIAN_NR_IRQS	(IRQ_BOARD_START + 8)
+
 /*
  * CPLD EGPIOs
  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/mainstone.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/mainstone.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/mainstone.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/mainstone.h	2011-01-04 19:50:19.000000000 -0500
@@ -134,4 +134,6 @@
 #define MAINSTONE_S1_STSCHG_IRQ	MAINSTONE_IRQ(14)
 #define MAINSTONE_S1_IRQ	MAINSTONE_IRQ(15)
 
+#define MAINSTONE_NR_IRQS	(IRQ_BOARD_START + 16)
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/mfp-pxa930.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/mfp-pxa930.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/mfp-pxa930.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/mfp-pxa930.h	2011-01-04 19:50:19.000000000 -0500
@@ -69,6 +69,7 @@
 #define nBE0_GPIO_60		MFP_CFG(nBE0, AF0)
 #define nBE1_GPIO_61		MFP_CFG(nBE1, AF0)
 #define RDY_GPIO_62		MFP_CFG(RDY, AF0)
+#define PMIC_INT_GPIO83		MFP_CFG_LPM(PMIC_INT, AF0, PULL_HIGH)
 
 /* Chip Select */
 #define DF_nCS0_nCS2		MFP_CFG_LPM(DF_nCS0, AF3, PULL_HIGH)
@@ -92,6 +93,9 @@
 #define GPIO63_CI2C_SCL		MFP_CFG_LPM(GPIO63, AF4, PULL_HIGH)
 #define GPIO64_CI2C_SDA		MFP_CFG_LPM(GPIO64, AF4, PULL_HIGH)
 
+#define GPIO73_CI2C_SCL		MFP_CFG_LPM(GPIO73, AF1, PULL_HIGH)
+#define GPIO74_CI2C_SDA		MFP_CFG_LPM(GPIO74, AF1, PULL_HIGH)
+
 #define GPIO77_CI2C_SCL		MFP_CFG_LPM(GPIO77, AF2, PULL_HIGH)
 #define GPIO78_CI2C_SDA		MFP_CFG_LPM(GPIO78, AF2, PULL_HIGH)
 
@@ -345,6 +349,9 @@
 #define GPIO69_UART1_CTS	MFP_CFG(GPIO69, AF2)
 #define GPIO70_UART1_RTS	MFP_CFG(GPIO70, AF2)
 
+#define GPIO53_UART1_TXD	MFP_CFG(GPIO53, AF2)
+#define GPIO54_UART1_RXD	MFP_CFG(GPIO54, AF2)
+
 /* UART2 - BTUART */
 #define GPIO91_UART2_RXD	MFP_CFG(GPIO91, AF1)
 #define GPIO92_UART2_TXD	MFP_CFG(GPIO92, AF1)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pcm027.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pcm027.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pcm027.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pcm027.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,8 @@
 #define PCM027_MMCDET_IRQ      PCM027_IRQ(2)
 #define PCM027_PM_5V_IRQ       PCM027_IRQ(3)
 
+#define PCM027_NR_IRQS		(IRQ_BOARD_START + 32)
+
 /* I2C RTC */
 #define PCM027_RTC_IRQ_GPIO	0
 #define PCM027_RTC_IRQ		IRQ_GPIO(PCM027_RTC_IRQ_GPIO)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/poodle.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/poodle.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/poodle.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/poodle.h	2011-01-04 19:50:19.000000000 -0500
@@ -85,6 +85,8 @@
 #define POODLE_LOCOMO_GPIO_232VCC_ON   LOCOMO_GPIO(12)
 #define POODLE_LOCOMO_GPIO_JK_B        LOCOMO_GPIO(13)
 
+#define POODLE_NR_IRQS		(IRQ_BOARD_START + 4)	/* 4 for LoCoMo */
+
 extern struct platform_device poodle_locomo_device;
 
 #endif /* __ASM_ARCH_POODLE_H  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pxa27x_keypad.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,59 +0,0 @@
-#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
-#define __ASM_ARCH_PXA27x_KEYPAD_H
-
-#include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
-
-#define MAX_MATRIX_KEY_ROWS	(8)
-#define MAX_MATRIX_KEY_COLS	(8)
-#define MATRIX_ROW_SHIFT	(3)
-#define MAX_DIRECT_KEY_NUM	(8)
-
-/* pxa3xx keypad platform specific parameters
- *
- * NOTE:
- * 1. direct_key_num indicates the number of keys in the direct keypad
- *    _plus_ the number of rotary-encoder sensor inputs,  this can be
- *    left as 0 if only rotary encoders are enabled,  the driver will
- *    automatically calculate this
- *
- * 2. direct_key_map is the key code map for the direct keys, if rotary
- *    encoder(s) are enabled, direct key 0/1(2/3) will be ignored
- *
- * 3. rotary can be either interpreted as a relative input event (e.g.
- *    REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT)
- *
- * 4. matrix key and direct key will use the same debounce_interval by
- *    default, which should be sufficient in most cases
- */
-struct pxa27x_keypad_platform_data {
-
-	/* code map for the matrix keys */
-	unsigned int	matrix_key_rows;
-	unsigned int	matrix_key_cols;
-	unsigned int	*matrix_key_map;
-	int		matrix_key_map_size;
-
-	/* direct keys */
-	int		direct_key_num;
-	unsigned int	direct_key_map[MAX_DIRECT_KEY_NUM];
-
-	/* rotary encoders 0 */
-	int		enable_rotary0;
-	int		rotary0_rel_code;
-	int		rotary0_up_key;
-	int		rotary0_down_key;
-
-	/* rotary encoders 1 */
-	int		enable_rotary1;
-	int		rotary1_rel_code;
-	int		rotary1_up_key;
-	int		rotary1_down_key;
-
-	/* key debounce interval */
-	unsigned int	debounce_interval;
-};
-
-extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
-
-#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/*
+ * PXA3xx U2D header
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PXA310_U2D__
+#define __PXA310_U2D__
+
+#include <linux/usb/ulpi.h>
+
+struct pxa3xx_u2d_platform_data {
+
+#define ULPI_SER_6PIN	(1 << 0)
+#define ULPI_SER_3PIN	(1 << 1)
+	unsigned int ulpi_mode;
+
+	int (*init)(struct device *);
+	void (*exit)(struct device *);
+};
+
+
+/* Start PXA3xx U2D host */
+int pxa3xx_u2d_start_hc(struct usb_bus *host);
+/* Stop PXA3xx U2D host */
+void pxa3xx_u2d_stop_hc(struct usb_bus *host);
+
+extern void pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info);
+
+#endif /* __PXA310_U2D__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/tosa.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/tosa.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/tosa.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/tosa.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 /* Jacket Scoop */
 #define TOSA_SCOOP_PHYS  	(PXA_CS5_PHYS + 0x00800000)
 
+#define TOSA_NR_IRQS		(IRQ_BOARD_START + TC6393XB_NR_IRQS)
 /*
  * SCOOP2 internal GPIOs
  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/zeus.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/zeus.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/zeus.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/zeus.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,8 @@
 #ifndef _MACH_ZEUS_H
 #define _MACH_ZEUS_H
 
+#define ZEUS_NR_IRQS		(IRQ_BOARD_START + 48)
+
 /* Physical addresses */
 #define ZEUS_FLASH_PHYS		PXA_CS0_PHYS
 #define ZEUS_ETH0_PHYS		PXA_CS1_PHYS
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/zylonite.h linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/zylonite.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/include/mach/zylonite.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/include/mach/zylonite.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,8 @@
 
 #define EXT_GPIO(x)		(128 + (x))
 
+#define ZYLONITE_NR_IRQS	(IRQ_BOARD_START + 32)
+
 /* the following variables are processor specific and initialized
  * by the corresponding zylonite_pxa3xx_init()
  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-pxa/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -8,19 +8,16 @@
 	bool "Intel DBPXA250 Development Platform (aka Lubbock)"
 	select PXA25x
 	select SA1111
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_MAINSTONE
 	bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
 	select PXA27x
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_ZYLONITE
 	bool
 	select PXA3xx
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_ZYLONITE300
 	bool "PXA3xx Development Platform (aka Zylonite) PXA300/310"
@@ -44,6 +41,10 @@
 	select PXA3xx
 	select CPU_PXA930
 
+config MACH_TAVOREVB3
+	bool "PXA95x Development Platform (aka TavorEVB III)"
+	select CPU_PXA950
+
 config MACH_SAAR
 	bool "PXA930 Handheld Platform (aka SAAR)"
 	select PXA3xx
@@ -61,7 +62,6 @@
 	select ISA
 	select I2C_GPIO
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 	select PXA_HAVE_ISA_IRQS
 	select ARCOM_PCMCIA
 
@@ -69,7 +69,6 @@
 	bool "Arcom/Eurotech ZEUS SBC"
 	select PXA27x
 	select ISA
-	select PXA_HAVE_BOARD_IRQS
 	select PXA_HAVE_ISA_IRQS
 	select ARCOM_PCMCIA
 
@@ -77,7 +76,6 @@
 	bool "Balloon 3 board"
 	select PXA27x
 	select IWMMXT
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_CSB726
 	bool "Enable Cogent CSB726 System On a Module"
@@ -140,13 +138,11 @@
 	bool "Intel Mote 2 Platform"
 	select PXA27x
 	select IWMMXT
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_STARGATE2
 	bool "Intel Stargate 2 Platform"
 	select PXA27x
 	select IWMMXT
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_XCEP
 	bool "Iskratel Electronics XCEP"
@@ -206,13 +202,11 @@
 	bool "LogicPD PXA270 Card Engine Development Platform"
 	select PXA27x
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_PCM027
 	bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
 	select PXA27x
 	select IWMMXT
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_PCM990_BASEBOARD
 	bool "PHYTEC PCM-990 development board"
@@ -247,7 +241,6 @@
 	depends on MACH_COLIBRI
 	select PXA27x
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_COLIBRI300
 	bool "Toradex Colibri PXA300/310"
@@ -274,7 +267,6 @@
 	select PXA27x
 	select IWMMXT
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_H5000
 	bool "HP iPAQ h5000"
@@ -289,7 +281,6 @@
 	select PXA27x
 	select IWMMXT
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_MIOA701
 	bool "Mitac Mio A701 Support"
@@ -307,7 +298,6 @@
 	select PXA27x
 	select IWMMXT
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_EZX_A780
 	bool "Motorola EZX A780"
@@ -478,7 +468,6 @@
 	depends on PXA_SHARPSL
 	select PXA25x
 	select SHARP_LOCOMO
-	select PXA_HAVE_BOARD_IRQS
 
 config MACH_CORGI
 	bool "Enable Sharp SL-C700 (Corgi) Support"
@@ -523,7 +512,6 @@
 	bool "Enable Sharp SL-6000x (Tosa) Support"
 	depends on PXA_SHARPSL
 	select PXA25x
-	select PXA_HAVE_BOARD_IRQS
 
 config TOSA_BT
 	tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
@@ -552,7 +540,7 @@
 config ARCH_PXA_ESERIES
 	bool "PXA based Toshiba e-series PDAs"
 	select PXA25x
-	select PXA_HAVE_BOARD_IRQS
+	select FB_W100
 
 config MACH_E330
 	bool "Toshiba e330"
@@ -606,7 +594,6 @@
 	bool "Zipit Z2 Handheld"
 	select PXA27x
 	select HAVE_PWM
-	select PXA_HAVE_BOARD_IRQS
 
 endmenu
 
@@ -643,6 +630,7 @@
 config CPU_PXA310
 	bool
 	select CPU_PXA300
+	select PXA310_ULPI if USB_ULPI
 	help
 	  PXA310 (codename Monahans-LV)
 
@@ -692,10 +680,10 @@
 	select HWMON
 	select SENSORS_MAX1111
 
-config PXA_HAVE_BOARD_IRQS
+config PXA_HAVE_ISA_IRQS
 	bool
 
-config PXA_HAVE_ISA_IRQS
+config PXA310_ULPI
 	bool
 
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/littleton.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/littleton.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/littleton.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/littleton.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/littleton.h>
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
@@ -437,10 +437,9 @@
 }
 
 MACHINE_START(LITTLETON, "Marvell Form Factor Development Platform (aka Littleton)")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= LITTLETON_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= littleton_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/lpd270.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/lpd270.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/lpd270.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/lpd270.c	2011-01-04 19:50:19.000000000 -0500
@@ -505,10 +505,9 @@
 
 MACHINE_START(LOGICPD_PXA270, "LogicPD PXA270 Card Engine")
 	/* Maintainer: Peter Barada */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= lpd270_map_io,
+	.nr_irqs	= LPD270_NR_IRQS,
 	.init_irq	= lpd270_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= lpd270_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/lubbock.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/lubbock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/lubbock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/lubbock.c	2011-01-04 19:50:19.000000000 -0500
@@ -229,7 +229,7 @@
 };
 
 static struct sa1111_platform_data sa1111_info = {
-	.irq_base	= IRQ_BOARD_END,
+	.irq_base	= LUBBOCK_SA1111_IRQ_BASE,
 };
 
 static struct platform_device sa1111_device = {
@@ -557,9 +557,8 @@
 
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
 	/* Maintainer: MontaVista Software Inc. */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= lubbock_map_io,
+	.nr_irqs	= LUBBOCK_NR_IRQS,
 	.init_irq	= lubbock_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= lubbock_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/magician.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/magician.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/magician.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/magician.c	2011-01-04 19:50:19.000000000 -0500
@@ -764,10 +764,9 @@
 
 
 MACHINE_START(MAGICIAN, "HTC Magician")
-	.phys_io = 0x40000000,
-	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params = 0xa0000100,
 	.map_io = pxa_map_io,
+	.nr_irqs = MAGICIAN_NR_IRQS,
 	.init_irq = pxa27x_init_irq,
 	.init_machine = magician_init,
 	.timer = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mainstone.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mainstone.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mainstone.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mainstone.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,7 +50,7 @@
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -624,10 +624,9 @@
 
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
 	/* Maintainer: MontaVista Software Inc. */
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,	/* BLOB boot parameter setting */
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= mainstone_map_io,
+	.nr_irqs	= MAINSTONE_NR_IRQS,
 	.init_irq	= mainstone_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= mainstone_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-pxa/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,7 @@
 # SoC-specific code
 obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
 obj-$(CONFIG_PXA27x)		+= mfp-pxa2xx.o pxa2xx.o pxa27x.o
-obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o
+obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
 obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
 obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
 obj-$(CONFIG_CPU_PXA930)	+= pxa930.o
@@ -32,6 +32,7 @@
 obj-$(CONFIG_MACH_ZYLONITE320)	+= zylonite.o zylonite_pxa320.o
 obj-$(CONFIG_MACH_LITTLETON)	+= littleton.o
 obj-$(CONFIG_MACH_TAVOREVB)	+= tavorevb.o
+obj-$(CONFIG_MACH_TAVOREVB3)	+= tavorevb3.o
 obj-$(CONFIG_MACH_SAAR)		+= saar.o
 
 # 3rd Party Dev Platforms
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mioa701.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mioa701.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mioa701.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mioa701.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,7 +45,7 @@
 
 #include <mach/pxa27x.h>
 #include <mach/regs-rtc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
@@ -711,7 +711,6 @@
 	.bus_id		= 0, /* Match id in pxa27x_device_camera in device.c */
 	.board_info	= &mioa701_i2c_devices[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "mt9m111",
 };
 
 struct i2c_pxa_platform_data i2c_pdata = {
@@ -819,8 +818,6 @@
 }
 
 MACHINE_START(MIOA701, "MIO A701")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= &pxa_map_io,
 	.init_irq	= &pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mp900.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mp900.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/mp900.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/mp900.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,9 +92,7 @@
 
 /* Maintainer - Michael Petchkovsky <mkpetch@internode.on.net> */
 MACHINE_START(NEC_MP900, "MobilePro900/C")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0220100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.timer		= &pxa_timer,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmld.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmld.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmld.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmld.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
 
@@ -343,8 +343,6 @@
 }
 
 MACHINE_START(PALMLD, "Palm LifeDrive")
-	.phys_io	= PALMLD_PHYS_IO_START,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= palmld_map_io,
 	.init_irq	= pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmt5.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmt5.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmt5.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmt5.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -202,8 +202,6 @@
 }
 
 MACHINE_START(PALMT5, "Palm Tungsten|T5")
-	.phys_io	= PALMT5_PHYS_IO_START,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
 	.reserve	= palmt5_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtc.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -412,9 +412,7 @@
 };
 
 MACHINE_START(PALMTC, "Palm Tungsten|C")
-	.phys_io	= 0x40000000,
 	.boot_params 	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmte2.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmte2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmte2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmte2.c	2011-01-04 19:50:19.000000000 -0500
@@ -373,8 +373,6 @@
 }
 
 MACHINE_START(PALMTE2, "Palm Tungsten|E2")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa25x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtreo.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtreo.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtreo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtreo.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/ohci.h>
 #include <mach/pxa2xx-regs.h>
@@ -441,8 +441,6 @@
 }
 
 MACHINE_START(TREO680, "Palm Treo 680")
-	.phys_io        = TREO_PHYS_IO_START,
-	.io_pg_offst    = io_p2v(0x40000000),
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
 	.reserve	= treo_reserve,
@@ -452,8 +450,6 @@
 MACHINE_END
 
 MACHINE_START(CENTRO, "Palm Centro 685")
-	.phys_io        = TREO_PHYS_IO_START,
-	.io_pg_offst    = io_p2v(0x40000000),
 	.boot_params    = 0xa0000100,
 	.map_io         = pxa_map_io,
 	.reserve	= treo_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtx.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmtx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmtx.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -241,7 +241,8 @@
 /******************************************************************************
  * NAND Flash
  ******************************************************************************/
-#if defined(CONFIG_MTD_NAND_GPIO) || defined(CONFIG_MTD_NAND_GPIO_MODULE)
+#if defined(CONFIG_MTD_NAND_PLATFORM) || \
+	defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
 static void palmtx_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
 				 unsigned int ctrl)
 {
@@ -363,8 +364,6 @@
 }
 
 MACHINE_START(PALMTX, "Palm T|X")
-	.phys_io	= PALMTX_PHYS_IO_START,
-	.io_pg_offst	= io_p2v(0x40000000),
 	.boot_params	= 0xa0000100,
 	.map_io		= palmtx_map_io,
 	.init_irq	= pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmz72.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmz72.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/palmz72.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/palmz72.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -279,8 +279,6 @@
 }
 
 MACHINE_START(PALMZ72, "Palm Zire72")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= io_p2v(0x40000000),
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pcm027.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pcm027.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pcm027.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pcm027.c	2011-01-04 19:50:19.000000000 -0500
@@ -259,9 +259,8 @@
 MACHINE_START(PCM027, "Phytec Messtechnik GmbH phyCORE-PXA270")
 	/* Maintainer: Pengutronix */
 	.boot_params	= 0xa0000100,
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pcm027_map_io,
+	.nr_irqs	= PCM027_NR_IRQS,
 	.init_irq	= pxa27x_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= pcm027_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pcm990-baseboard.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pcm990-baseboard.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pcm990-baseboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pcm990-baseboard.c	2011-01-04 19:50:19.000000000 -0500
@@ -453,7 +453,6 @@
 		.query_bus_param	= pcm990_camera_query_bus_param,
 		.set_bus_param		= pcm990_camera_set_bus_param,
 		.free_bus		= pcm990_camera_free_bus,
-		.module_name		= "mt9v022",
 	}, {
 		.bus_id			= 0, /* Must match with the camera ID */
 		.board_info		= &pcm990_camera_i2c[1],
@@ -461,7 +460,6 @@
 		.query_bus_param	= pcm990_camera_query_bus_param,
 		.set_bus_param		= pcm990_camera_set_bus_param,
 		.free_bus		= pcm990_camera_free_bus,
-		.module_name		= "mt9m001",
 	},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/poodle.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/poodle.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/poodle.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/poodle.c	2011-01-04 19:50:19.000000000 -0500
@@ -465,10 +465,9 @@
 }
 
 MACHINE_START(POODLE, "SHARP Poodle")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= fixup_poodle,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= POODLE_NR_IRQS,	/* 4 for LoCoMo */
 	.init_irq	= pxa25x_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= poodle_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa27x.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa27x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa27x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa27x.c	2011-01-04 19:50:19.000000000 -0500
@@ -385,6 +385,10 @@
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa3xx.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa3xx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa3xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa3xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -98,23 +98,6 @@
 	return CLK / 1000;
 }
 
-/*
- * Return the current static memory controller clock frequency
- * in units of 10kHz
- */
-unsigned int pxa3xx_get_memclk_frequency_10khz(void)
-{
-	unsigned long acsr;
-	unsigned int smcfs, clk = 0;
-
-	acsr = ACSR;
-
-	smcfs = (acsr >> 23) & 0x7;
-	clk = (acsr & ACCR_D0CS) ? RO_CLK : smcfs_mult[smcfs] * BASE_CLK;
-
-	return (clk / 10000);
-}
-
 void pxa3xx_clear_reset_status(unsigned int mask)
 {
 	/* RESET_STATUS_* has a 1:1 mapping with ARSR */
@@ -265,7 +248,7 @@
 	INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
 	INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
 	INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
-	INIT_CLKREG(&clk_pxa3xx_u2d, NULL, "U2DCLK"),
+	INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL),
 	INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
 	INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
 	INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
@@ -610,6 +593,11 @@
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_ssp4,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa3xx-ulpi.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa3xx-ulpi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa3xx-ulpi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa3xx-ulpi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,400 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa3xx-ulpi.c
+ *
+ * code specific to pxa3xx aka Monahans
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * 2010-13-07: Igor Grinberg <grinberg@compulab.co.il>
+ *             initial version: pxa310 USB Host mode support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-u2d.h>
+#include <mach/pxa3xx-u2d.h>
+
+struct pxa3xx_u2d_ulpi {
+	struct clk		*clk;
+	void __iomem		*mmio_base;
+
+	struct otg_transceiver	*otg;
+	unsigned int		ulpi_mode;
+};
+
+static struct pxa3xx_u2d_ulpi *u2d;
+
+static inline u32 u2d_readl(u32 reg)
+{
+	return __raw_readl(u2d->mmio_base + reg);
+}
+
+static inline void u2d_writel(u32 reg, u32 val)
+{
+	__raw_writel(val, u2d->mmio_base + reg);
+}
+
+#if defined(CONFIG_PXA310_ULPI)
+enum u2d_ulpi_phy_mode {
+	SYNCH		= 0,
+	CARKIT		= (1 << 0),
+	SER_3PIN	= (1 << 1),
+	SER_6PIN	= (1 << 2),
+	LOWPOWER	= (1 << 3),
+};
+
+static inline enum u2d_ulpi_phy_mode pxa310_ulpi_get_phymode(void)
+{
+	return (u2d_readl(U2DOTGUSR) >> 28) & 0xF;
+}
+
+static int pxa310_ulpi_poll(void)
+{
+	int timeout = 50000;
+
+	while (timeout--) {
+		if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
+			return 0;
+
+		cpu_relax();
+	}
+
+	pr_warning("%s: ULPI access timed out!\n", __func__);
+
+	return -ETIMEDOUT;
+}
+
+static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
+{
+	int err;
+
+	if (pxa310_ulpi_get_phymode() != SYNCH) {
+		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+		return -EBUSY;
+	}
+
+	u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << 16));
+	msleep(5);
+
+	err = pxa310_ulpi_poll();
+	if (err)
+		return err;
+
+	return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
+}
+
+static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+{
+	if (pxa310_ulpi_get_phymode() != SYNCH) {
+		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+		return -EBUSY;
+	}
+
+	u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << 16) | (val << 8));
+	msleep(5);
+
+	return pxa310_ulpi_poll();
+}
+
+struct otg_io_access_ops pxa310_ulpi_access_ops = {
+	.read	= pxa310_ulpi_read,
+	.write	= pxa310_ulpi_write,
+};
+
+static void pxa310_otg_transceiver_rtsm(void)
+{
+	u32 u2dotgcr;
+
+	/* put PHY to sync mode */
+	u2dotgcr = u2d_readl(U2DOTGCR);
+	u2dotgcr |=  U2DOTGCR_RTSM | U2DOTGCR_UTMID;
+	u2d_writel(U2DOTGCR, u2dotgcr);
+	msleep(10);
+
+	/* setup OTG sync mode */
+	u2dotgcr = u2d_readl(U2DOTGCR);
+	u2dotgcr |= U2DOTGCR_ULAF;
+	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+	u2d_writel(U2DOTGCR, u2dotgcr);
+}
+
+static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
+{
+	int err;
+
+	pxa310_otg_transceiver_rtsm();
+
+	err = otg_init(u2d->otg);
+	if (err) {
+		pr_err("OTG transceiver init failed");
+		return err;
+	}
+
+	err = otg_set_vbus(u2d->otg, 1);
+	if (err) {
+		pr_err("OTG transceiver VBUS set failed");
+		return err;
+	}
+
+	err = otg_set_host(u2d->otg, host);
+	if (err)
+		pr_err("OTG transceiver Host mode set failed");
+
+	return err;
+}
+
+static int pxa310_start_otg_hc(struct usb_bus *host)
+{
+	u32 u2dotgcr;
+	int err;
+
+	/* disable USB device controller */
+	u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
+	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
+	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
+
+	err = pxa310_start_otg_host_transcvr(host);
+	if (err)
+		return err;
+
+	/* set xceiver mode */
+	if (u2d->ulpi_mode & ULPI_IC_6PIN_SERIAL)
+		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
+	else if (u2d->ulpi_mode & ULPI_IC_3PIN_SERIAL)
+		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
+
+	/* start OTG host controller */
+	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
+	u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
+
+	return 0;
+}
+
+static void pxa310_stop_otg_hc(void)
+{
+	pxa310_otg_transceiver_rtsm();
+
+	otg_set_host(u2d->otg, NULL);
+	otg_set_vbus(u2d->otg, 0);
+	otg_shutdown(u2d->otg);
+}
+
+static void pxa310_u2d_setup_otg_hc(void)
+{
+	u32 u2dotgcr;
+
+	u2dotgcr = u2d_readl(U2DOTGCR);
+	u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
+	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+	u2d_writel(U2DOTGCR, u2dotgcr);
+	msleep(5);
+	u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
+	msleep(5);
+	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
+}
+
+static int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
+{
+	unsigned int ulpi_mode = ULPI_OTG_DRVVBUS;
+
+	if (pdata) {
+		if (pdata->ulpi_mode & ULPI_SER_6PIN)
+			ulpi_mode |= ULPI_IC_6PIN_SERIAL;
+		else if (pdata->ulpi_mode & ULPI_SER_3PIN)
+			ulpi_mode |= ULPI_IC_3PIN_SERIAL;
+	}
+
+	u2d->ulpi_mode = ulpi_mode;
+
+	u2d->otg = otg_ulpi_create(&pxa310_ulpi_access_ops, ulpi_mode);
+	if (!u2d->otg)
+		return -ENOMEM;
+
+	u2d->otg->io_priv = u2d->mmio_base;
+
+	return 0;
+}
+
+static void pxa310_otg_exit(void)
+{
+	kfree(u2d->otg);
+}
+#else
+static inline void pxa310_u2d_setup_otg_hc(void) {}
+static inline int pxa310_start_otg_hc(struct usb_bus *host)
+{
+	return 0;
+}
+static inline void pxa310_stop_otg_hc(void) {}
+static inline int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
+{
+	return 0;
+}
+static inline void pxa310_otg_exit(void) {}
+#endif /* CONFIG_PXA310_ULPI */
+
+int pxa3xx_u2d_start_hc(struct usb_bus *host)
+{
+	int err = 0;
+
+	/* In case the PXA3xx ULPI isn't used, do nothing. */
+	if (!u2d)
+		return 0;
+
+	clk_enable(u2d->clk);
+
+	if (cpu_is_pxa310()) {
+		pxa310_u2d_setup_otg_hc();
+		err = pxa310_start_otg_hc(host);
+	}
+
+	return err;
+}
+
+void pxa3xx_u2d_stop_hc(struct usb_bus *host)
+{
+	/* In case the PXA3xx ULPI isn't used, do nothing. */
+	if (!u2d)
+		return;
+
+	if (cpu_is_pxa310())
+		pxa310_stop_otg_hc();
+
+	clk_disable(u2d->clk);
+}
+
+static int pxa3xx_u2d_probe(struct platform_device *pdev)
+{
+	struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *r;
+	int err;
+
+	u2d = kzalloc(sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);
+	if (!u2d) {
+		dev_err(&pdev->dev, "failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	u2d->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(u2d->clk)) {
+		dev_err(&pdev->dev, "failed to get u2d clock\n");
+		err = PTR_ERR(u2d->clk);
+		goto err_free_mem;
+	}
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		dev_err(&pdev->dev, "no IO memory resource defined\n");
+		err = -ENODEV;
+		goto err_put_clk;
+	}
+
+        r = request_mem_region(r->start, resource_size(r), pdev->name);
+        if (!r) {
+                dev_err(&pdev->dev, "failed to request memory resource\n");
+                err = -EBUSY;
+                goto err_put_clk;
+        }
+
+	u2d->mmio_base = ioremap(r->start, resource_size(r));
+	if (!u2d->mmio_base) {
+		dev_err(&pdev->dev, "ioremap() failed\n");
+		err = -ENODEV;
+		goto err_free_res;
+	}
+
+	if (pdata->init) {
+		err = pdata->init(&pdev->dev);
+		if (err)
+			goto err_free_io;
+	}
+
+	/* Only PXA310 U2D has OTG functionality */
+	if (cpu_is_pxa310()) {
+		err = pxa310_otg_init(pdata);
+		if (err)
+			goto err_free_plat;
+	}
+
+	platform_set_drvdata(pdev, &u2d);
+
+	return 0;
+
+err_free_plat:
+	if (pdata->exit)
+		pdata->exit(&pdev->dev);
+err_free_io:
+	iounmap(u2d->mmio_base);
+err_free_res:
+	release_mem_region(r->start, resource_size(r));
+err_put_clk:
+	clk_put(u2d->clk);
+err_free_mem:
+	kfree(u2d);
+	return err;
+}
+
+static int pxa3xx_u2d_remove(struct platform_device *pdev)
+{
+	struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *r;
+
+	if (cpu_is_pxa310()) {
+		pxa310_stop_otg_hc();
+		pxa310_otg_exit();
+	}
+
+	if (pdata->exit)
+		pdata->exit(&pdev->dev);
+
+	platform_set_drvdata(pdev, NULL);
+	iounmap(u2d->mmio_base);
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, resource_size(r));
+
+	clk_put(u2d->clk);
+
+	kfree(u2d);
+
+	return 0;
+}
+
+static struct platform_driver pxa3xx_u2d_ulpi_driver = {
+        .driver		= {
+                .name   = "pxa3xx-u2d",
+		.owner	= THIS_MODULE,
+        },
+        .probe          = pxa3xx_u2d_probe,
+        .remove         = pxa3xx_u2d_remove,
+};
+
+static int pxa3xx_u2d_ulpi_init(void)
+{
+	return platform_driver_register(&pxa3xx_u2d_ulpi_driver);
+}
+module_init(pxa3xx_u2d_ulpi_init);
+
+static void __exit pxa3xx_u2d_ulpi_exit(void)
+{
+	platform_driver_unregister(&pxa3xx_u2d_ulpi_driver);
+}
+module_exit(pxa3xx_u2d_ulpi_exit);
+
+MODULE_DESCRIPTION("PXA3xx U2D ULPI driver");
+MODULE_AUTHOR("Igor Grinberg");
+MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa930.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa930.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/pxa930.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/pxa930.c	2011-01-04 19:50:19.000000000 -0500
@@ -192,7 +192,7 @@
 
 static int __init pxa930_init(void)
 {
-	if (cpu_is_pxa930() || cpu_is_pxa935()) {
+	if (cpu_is_pxa930() || cpu_is_pxa935() || cpu_is_pxa950()) {
 		mfp_init_base(io_p2v(MFPR_BASE));
 		mfp_init_addr(pxa930_mfp_addr_map);
 	}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/raumfeld.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/raumfeld.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/raumfeld.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/raumfeld.c	2011-01-04 19:50:19.000000000 -0500
@@ -1083,8 +1083,6 @@
 
 #ifdef CONFIG_MACH_RAUMFELD_RC
 MACHINE_START(RAUMFELD_RC, "Raumfeld Controller")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= RAUMFELD_SDRAM_BASE + 0x100,
 	.init_machine	= raumfeld_controller_init,
 	.map_io		= pxa_map_io,
@@ -1095,8 +1093,6 @@
 
 #ifdef CONFIG_MACH_RAUMFELD_CONNECTOR
 MACHINE_START(RAUMFELD_CONNECTOR, "Raumfeld Connector")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= RAUMFELD_SDRAM_BASE + 0x100,
 	.init_machine	= raumfeld_connector_init,
 	.map_io		= pxa_map_io,
@@ -1107,8 +1103,6 @@
 
 #ifdef CONFIG_MACH_RAUMFELD_SPEAKER
 MACHINE_START(RAUMFELD_SPEAKER, "Raumfeld Speaker")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= RAUMFELD_SDRAM_BASE + 0x100,
 	.init_machine	= raumfeld_speaker_init,
 	.map_io		= pxa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/saar.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/saar.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/saar.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/saar.c	2011-01-04 19:50:19.000000000 -0500
@@ -116,7 +116,7 @@
 	},
 };
 
-#if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULE)
+#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
 static uint16_t lcd_power_on[] = {
 	/* single frame */
 	SMART_CMD_NOOP,
@@ -596,9 +596,7 @@
 
 MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
 	/* Maintainer: Eric Miao <eric.miao@marvell.com> */
-	.phys_io        = 0x40000000,
 	.boot_params    = 0xa0000100,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io         = pxa_map_io,
 	.init_irq       = pxa3xx_init_irq,
 	.timer          = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/sleep.S linux-libre-2.6.37-gnu/arch/arm/mach-pxa/sleep.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/sleep.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/sleep.S	2011-01-04 19:50:19.000000000 -0500
@@ -353,8 +353,8 @@
 
 	@ Let us ensure we jump to resume_after_mmu only when the mcr above
 	@ actually took effect.  They call it the "cpwait" operation.
-	mrc	p15, 0, r1, c2, c0, 0		@ queue a dependency on CP15
-	sub	pc, r2, r1, lsr #32		@ jump to virtual addr
+	mrc	p15, 0, r0, c2, c0, 0		@ queue a dependency on CP15
+	sub	pc, r2, r0, lsr #32		@ jump to virtual addr
 	nop
 	nop
 	nop
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/spitz.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/spitz.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/spitz.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/spitz.c	2011-01-04 19:50:19.000000000 -0500
@@ -979,8 +979,6 @@
 
 #ifdef CONFIG_MACH_SPITZ
 MACHINE_START(SPITZ, "SHARP Spitz")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= spitz_fixup,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
@@ -991,8 +989,6 @@
 
 #ifdef CONFIG_MACH_BORZOI
 MACHINE_START(BORZOI, "SHARP Borzoi")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= spitz_fixup,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
@@ -1003,8 +999,6 @@
 
 #ifdef CONFIG_MACH_AKITA
 MACHINE_START(AKITA, "SHARP Akita")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup		= spitz_fixup,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/stargate2.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/stargate2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/stargate2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/stargate2.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,6 +56,8 @@
 #include "devices.h"
 #include "generic.h"
 
+#define STARGATE_NR_IRQS	(IRQ_BOARD_START + 8)
+
 /* Bluetooth */
 #define SG2_BT_RESET		81
 
@@ -996,8 +998,6 @@
 
 #ifdef CONFIG_MACH_INTELMOTE2
 MACHINE_START(INTELMOTE2, "IMOTE 2")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
 	.timer		= &pxa_timer,
@@ -1008,9 +1008,8 @@
 
 #ifdef CONFIG_MACH_STARGATE2
 MACHINE_START(STARGATE2, "Stargate 2")
-	.phys_io = 0x40000000,
-	.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io = pxa_map_io,
+	.nr_irqs = STARGATE_NR_IRQS,
 	.init_irq = pxa27x_init_irq,
 	.timer = &pxa_timer,
 	.init_machine = stargate2_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tavorevb3.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tavorevb3.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tavorevb3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tavorevb3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,135 @@
+/*
+ *  linux/arch/arm/mach-pxa/tavorevb3.c
+ *
+ *  Support for the Marvell EVB3 Development Platform.
+ *
+ *  Copyright:  (C) Copyright 2008-2010 Marvell International Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/mfd/88pm860x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pxa930.h>
+
+#include <plat/i2c.h>
+
+#include "devices.h"
+#include "generic.h"
+
+#define TAVOREVB3_NR_IRQS	(IRQ_BOARD_START + 24)
+
+static mfp_cfg_t evb3_mfp_cfg[] __initdata = {
+	/* UART */
+	GPIO53_UART1_TXD,
+	GPIO54_UART1_RXD,
+
+	/* PMIC */
+	PMIC_INT_GPIO83,
+};
+
+#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
+static struct pm860x_touch_pdata evb3_touch = {
+	.gpadc_prebias	= 1,
+	.slot_cycle	= 1,
+	.tsi_prebias	= 6,
+	.pen_prebias	= 16,
+	.pen_prechg	= 2,
+	.res_x		= 300,
+};
+
+static struct pm860x_backlight_pdata evb3_backlight[] = {
+	{
+		.id	= PM8606_ID_BACKLIGHT,
+		.iset	= PM8606_WLED_CURRENT(24),
+		.flags	= PM8606_BACKLIGHT1,
+	},
+	{},
+};
+
+static struct pm860x_led_pdata evb3_led[] = {
+	{
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED1_RED,
+	}, {
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED1_GREEN,
+	}, {
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED1_BLUE,
+	}, {
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED2_RED,
+	}, {
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED2_GREEN,
+	}, {
+		.id	= PM8606_ID_LED,
+		.iset	= PM8606_LED_CURRENT(12),
+		.flags	= PM8606_LED2_BLUE,
+	},
+};
+
+static struct pm860x_platform_data evb3_pm8607_info = {
+	.touch				= &evb3_touch,
+	.backlight			= &evb3_backlight[0],
+	.led				= &evb3_led[0],
+	.companion_addr			= 0x10,
+	.irq_mode			= 0,
+	.irq_base			= IRQ_BOARD_START,
+
+	.i2c_port			= GI2C_PORT,
+};
+
+static struct i2c_board_info evb3_i2c_info[] = {
+	{
+		.type		= "88PM860x",
+		.addr		= 0x34,
+		.platform_data	= &evb3_pm8607_info,
+		.irq		= gpio_to_irq(mfp_to_gpio(MFP_PIN_GPIO83)),
+	},
+};
+
+static void __init evb3_init_i2c(void)
+{
+	pxa_set_i2c_info(NULL);
+	i2c_register_board_info(0, ARRAY_AND_SIZE(evb3_i2c_info));
+}
+#else
+static inline void evb3_init_i2c(void) {}
+#endif
+
+static void __init evb3_init(void)
+{
+	/* initialize MFP configurations */
+	pxa3xx_mfp_config(ARRAY_AND_SIZE(evb3_mfp_cfg));
+
+	pxa_set_ffuart_info(NULL);
+
+	evb3_init_i2c();
+}
+
+MACHINE_START(TAVOREVB3, "PXA950 Evaluation Board (aka TavorEVB3)")
+	.boot_params	= 0xa0000100,
+	.map_io         = pxa_map_io,
+	.nr_irqs	= TAVOREVB3_NR_IRQS,
+	.init_irq       = pxa3xx_init_irq,
+	.timer          = &pxa_timer,
+	.init_machine   = evb3_init,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tavorevb.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tavorevb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tavorevb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tavorevb.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 
 #include <mach/pxa930.h>
 #include <mach/pxafb.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -489,9 +489,7 @@
 
 MACHINE_START(TAVOREVB, "PXA930 Evaluation Board (aka TavorEVB)")
 	/* Maintainer: Eric Miao <eric.miao@marvell.com> */
-	.phys_io        = 0x40000000,
 	.boot_params    = 0xa0000100,
-	.io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io         = pxa_map_io,
 	.init_irq       = pxa3xx_init_irq,
 	.timer          = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tosa.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tosa.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/tosa.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/tosa.c	2011-01-04 19:50:19.000000000 -0500
@@ -952,10 +952,9 @@
 }
 
 MACHINE_START(TOSA, "SHARP Tosa")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.fixup          = fixup_tosa,
 	.map_io         = pxa_map_io,
+	.nr_irqs	= TOSA_NR_IRQS,
 	.init_irq       = pxa25x_init_irq,
 	.init_machine   = tosa_init,
 	.timer          = &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/trizeps4.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/trizeps4.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/trizeps4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/trizeps4.c	2011-01-04 19:50:19.000000000 -0500
@@ -555,8 +555,6 @@
 
 MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
 	/* MAINTAINER("JÃ¼rgen Schindele") */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= TRIZEPS4_SDRAM_BASE + 0x100,
 	.init_machine	= trizeps4_init,
 	.map_io		= trizeps4_map_io,
@@ -566,8 +564,6 @@
 
 MACHINE_START(TRIZEPS4WL, "Keith und Koep Trizeps IV-WL module")
 	/* MAINTAINER("JÃ¼rgen Schindele") */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= TRIZEPS4_SDRAM_BASE + 0x100,
 	.init_machine	= trizeps4_init,
 	.map_io		= trizeps4_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/viper.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/viper.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/viper.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/viper.c	2011-01-04 19:50:19.000000000 -0500
@@ -992,8 +992,6 @@
 
 MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC")
 	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= viper_map_io,
 	.init_irq	= viper_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/vpac270.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/vpac270.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/vpac270.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/vpac270.c	2011-01-04 19:50:19.000000000 -0500
@@ -718,8 +718,6 @@
 }
 
 MACHINE_START(VPAC270, "Voipac PXA270")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/xcep.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/xcep.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/xcep.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/xcep.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,8 +181,6 @@
 }
 
 MACHINE_START(XCEP, "Iskratel XCEP")
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.boot_params	= 0xa0000100,
 	.init_machine	= xcep_init,
 	.map_io		= pxa_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/z2.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/z2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/z2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/z2.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,7 @@
 #include <mach/z2.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
 
 #include <plat/i2c.h>
@@ -703,9 +703,7 @@
 }
 
 MACHINE_START(ZIPIT2, "Zipit Z2")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
 	.init_irq	= pxa27x_init_irq,
 	.timer		= &pxa_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/zeus.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/zeus.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/zeus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/zeus.c	2011-01-04 19:50:19.000000000 -0500
@@ -900,10 +900,9 @@
 
 MACHINE_START(ARCOM_ZEUS, "Arcom/Eurotech ZEUS")
 	/* Maintainer: Marc Zyngier <maz@misterjones.org> */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= ((io_p2v(0x40000000) >> 18) & 0xfffc),
 	.boot_params	= 0xa0000100,
 	.map_io		= zeus_map_io,
+	.nr_irqs	= ZEUS_NR_IRQS,
 	.init_irq	= zeus_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= zeus_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-pxa/zylonite.c linux-libre-2.6.37-gnu/arch/arm/mach-pxa/zylonite.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-pxa/zylonite.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-pxa/zylonite.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,7 @@
 #include <mach/zylonite.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <plat/pxa3xx_nand.h>
 
 #include "devices.h"
@@ -45,6 +45,16 @@
 int lcd_id;
 int lcd_orientation;
 
+struct platform_device pxa_device_wm9713_audio = {
+	.name		= "wm9713-codec",
+	.id		= -1,
+};
+
+static void __init zylonite_init_wm9713_audio(void)
+{
+	platform_device_register(&pxa_device_wm9713_audio);
+}
+
 static struct resource smc91x_resources[] = {
 	[0] = {
 		.start	= ZYLONITE_ETH_PHYS + 0x300,
@@ -408,13 +418,13 @@
 	zylonite_init_nand();
 	zylonite_init_leds();
 	zylonite_init_ohci();
+	zylonite_init_wm9713_audio();
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
-	.phys_io	= 0x40000000,
 	.boot_params	= 0xa0000100,
-	.io_pg_offst	= (io_p2v(0x40000000) >> 18) & 0xfffc,
 	.map_io		= pxa_map_io,
+	.nr_irqs	= ZYLONITE_NR_IRQS,
 	.init_irq	= pxa3xx_init_irq,
 	.timer		= &pxa_timer,
 	.init_machine	= zylonite_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/core.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -259,6 +259,7 @@
 	.status		= realview_mmc_status,
 	.gpio_wp	= 17,
 	.gpio_cd	= 16,
+	.cd_invert	= true,
 };
 
 struct mmci_platform_data realview_mmc1_plat_data = {
@@ -266,6 +267,7 @@
 	.status		= realview_mmc_status,
 	.gpio_wp	= 19,
 	.gpio_cd	= 18,
+	.cd_invert	= true,
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/headsmp.S linux-libre-2.6.37-gnu/arch/arm/mach-realview/headsmp.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/headsmp.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/headsmp.S	2011-01-04 19:50:19.000000000 -0500
@@ -35,5 +35,6 @@
 	 */
 	b	secondary_startup
 
+	.align
 1:	.long	.
 	.long	pen_release
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-realview/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -33,12 +33,10 @@
 #error "Unknown RealView platform"
 #endif
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx,      #0x10000000
-		movne	\rx,      #0xfb000000	@ virtual base
-		orr	\rx, \rx, #DEBUG_LL_UART_OFFSET
+		.macro	addruart, rp, rv
+		mov	\rp, #DEBUG_LL_UART_OFFSET
+		orr	\rv, \rp, #0xfb000000	@ virtual base
+		orr	\rp, \rp, #0x10000000	@ physical base
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-realview/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/include/mach/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,16 +1,8 @@
 #ifndef ASMARM_ARCH_SMP_H
 #define ASMARM_ARCH_SMP_H
 
-
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()			\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x0F;				\
-	})
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_eb.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_eb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_eb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_eb.c	2011-01-04 19:50:19.000000000 -0500
@@ -486,8 +486,6 @@
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= REALVIEW_EB_UART0_BASE & SECTION_MASK,
-	.io_pg_offst	= (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.fixup		= realview_fixup,
 	.map_io		= realview_eb_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pb1176.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pb1176.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pb1176.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pb1176.c	2011-01-04 19:50:19.000000000 -0500
@@ -378,8 +378,6 @@
 
 MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= REALVIEW_PB1176_UART0_BASE & SECTION_MASK,
-	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.fixup		= realview_pb1176_fixup,
 	.map_io		= realview_pb1176_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pb11mp.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pb11mp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pb11mp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pb11mp.c	2011-01-04 19:50:19.000000000 -0500
@@ -381,8 +381,6 @@
 
 MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= REALVIEW_PB11MP_UART0_BASE & SECTION_MASK,
-	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.fixup		= realview_fixup,
 	.map_io		= realview_pb11mp_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pba8.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pba8.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pba8.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pba8.c	2011-01-04 19:50:19.000000000 -0500
@@ -331,8 +331,6 @@
 
 MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= REALVIEW_PBA8_UART0_BASE & SECTION_MASK,
-	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PBA8_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.fixup		= realview_fixup,
 	.map_io		= realview_pba8_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pbx.c linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pbx.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-realview/realview_pbx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-realview/realview_pbx.c	2011-01-04 19:50:19.000000000 -0500
@@ -417,8 +417,6 @@
 
 MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= REALVIEW_PBX_UART0_BASE & SECTION_MASK,
-	.io_pg_offst	= (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.fixup		= realview_pbx_fixup,
 	.map_io		= realview_pbx_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-rpc/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-rpc/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-rpc/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-rpc/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,13 +11,11 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x03000000
-		movne	\rx, #0xe0000000
-		orr	\rx, \rx, #0x00010000
-		orr	\rx, \rx, #0x00000fe0
+		.macro	addruart, rp, rv
+		mov	\rp, #0x00010000
+		orr	\rp, \rp, #0x00000fe0
+		orr	\rv, \rp, #0xe0000000	@ virtual
+		orr	\rp, \rp, #0x03000000	@ physical
 		.endm
 
 #define UART_SHIFT	2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-rpc/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-rpc/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-rpc/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-rpc/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,4 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
+#define VMALLOC_END       0xdc000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-rpc/riscpc.c linux-libre-2.6.37-gnu/arch/arm/mach-rpc/riscpc.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-rpc/riscpc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-rpc/riscpc.c	2011-01-04 19:50:19.000000000 -0500
@@ -218,8 +218,6 @@
 
 MACHINE_START(RISCPC, "Acorn-RiscPC")
 	/* Maintainer: Russell King */
-	.phys_io	= 0x03000000,
-	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x10000100,
 	.reserve_lp0	= 1,
 	.reserve_lp1	= 1,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/h1940-bluetooth.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/h1940-bluetooth.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/h1940-bluetooth.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/h1940-bluetooth.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,7 @@
 {
 	if (on) {
 		/* Power on the chip */
-		h1940_latch_control(0, H1940_LATCH_BLUETOOTH_POWER);
+		gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 1);
 		/* Reset the chip */
 		mdelay(10);
 
@@ -43,7 +43,7 @@
 		mdelay(10);
 		gpio_set_value(S3C2410_GPH(1), 0);
 		mdelay(10);
-		h1940_latch_control(H1940_LATCH_BLUETOOTH_POWER, 0);
+		gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
 	}
 }
 
@@ -64,19 +64,26 @@
 
 	ret = gpio_request(S3C2410_GPH(1), dev_name(&pdev->dev));
 	if (ret) {
-		dev_err(&pdev->dev, "could not get GPH1\n");\
+		dev_err(&pdev->dev, "could not get GPH1\n");
+		return ret;
+	}
+
+	ret = gpio_request(H1940_LATCH_BLUETOOTH_POWER, dev_name(&pdev->dev));
+	if (ret) {
+		gpio_free(S3C2410_GPH(1));
+		dev_err(&pdev->dev, "could not get BT_POWER\n");
 		return ret;
 	}
 
 	/* Configures BT serial port GPIOs */
 	s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0);
-	s3c_gpio_cfgpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
+	s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE);
 	s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT);
-	s3c_gpio_cfgpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
+	s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE);
 	s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0);
-	s3c_gpio_cfgpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
+	s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE);
 	s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0);
-	s3c_gpio_cfgpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
+	s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE);
 
 
 	rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -19,13 +19,12 @@
 #define S3C2410_UART1_OFF (0x4000)
 #define SHIFT_2440TXF (14-9)
 
-	.macro addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C24XX_PA_UART
-		ldrne	\rx, = S3C24XX_VA_UART
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C24XX_PA_UART
+		ldr	\rv, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,8 @@
 
 #ifdef CONFIG_CPU_S3C244X
 #define ARCH_NR_GPIOS	(32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)
+#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define ARCH_NR_GPIOS	(32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA)
 #else
 #define ARCH_NR_GPIOS	(256 + CONFIG_S3C24XX_GPIO_EXTRA)
 #endif
@@ -30,8 +32,10 @@
 #include <mach/gpio-nrs.h>
 #include <mach/gpio-fns.h>
 
-#ifdef CONFIG_CPU_S3C24XX
-#define S3C_GPIO_END	(S3C2410_GPIO_BANKJ + 32)
+#ifdef CONFIG_CPU_S3C244X
+#define S3C_GPIO_END	(S3C2410_GPJ(0) + 32)
+#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416)
+#define S3C_GPIO_END	(S3C2410_GPM(0) + 32)
 #else
-#define S3C_GPIO_END	(S3C2410_GPIO_BANKH + 32)
+#define S3C_GPIO_END	(S3C2410_GPH(0) + 32)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/h1940-latch.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/h1940-latch.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/h1940-latch.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/h1940-latch.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,51 +14,30 @@
 #ifndef __ASM_ARCH_H1940_LATCH_H
 #define __ASM_ARCH_H1940_LATCH_H
 
+#include <mach/gpio.h>
 
-#ifndef __ASSEMBLY__
-#define H1940_LATCH		((void __force __iomem *)0xF8000000)
-#else
-#define H1940_LATCH		0xF8000000
-#endif
-
-#define H1940_PA_LATCH		(S3C2410_CS2)
+#define H1940_LATCH_GPIO(x)		(S3C_GPIO_END + (x))
 
 /* SD layer latch */
 
-#define H1940_LATCH_SDQ1		(1<<16)
-#define H1940_LATCH_LCD_P1		(1<<17)
-#define H1940_LATCH_LCD_P2		(1<<18)
-#define H1940_LATCH_LCD_P3		(1<<19)
-#define H1940_LATCH_MAX1698_nSHUTDOWN	(1<<20)		/* LCD backlight */
-#define H1940_LATCH_LED_RED		(1<<21)
-#define H1940_LATCH_SDQ7		(1<<22)
-#define H1940_LATCH_USB_DP		(1<<23)
+#define H1940_LATCH_LCD_P0		H1940_LATCH_GPIO(0)
+#define H1940_LATCH_LCD_P1		H1940_LATCH_GPIO(1)
+#define H1940_LATCH_LCD_P2		H1940_LATCH_GPIO(2)
+#define H1940_LATCH_LCD_P3		H1940_LATCH_GPIO(3)
+#define H1940_LATCH_MAX1698_nSHUTDOWN	H1940_LATCH_GPIO(4)
+#define H1940_LATCH_LED_RED		H1940_LATCH_GPIO(5)
+#define H1940_LATCH_SDQ7		H1940_LATCH_GPIO(6)
+#define H1940_LATCH_USB_DP		H1940_LATCH_GPIO(7)
 
 /* CPU layer latch */
 
-#define H1940_LATCH_UDA_POWER		(1<<24)
-#define H1940_LATCH_AUDIO_POWER		(1<<25)
-#define H1940_LATCH_SM803_ENABLE	(1<<26)
-#define H1940_LATCH_LCD_P4		(1<<27)
-#define H1940_LATCH_CPUQ5		(1<<28)		/* untraced */
-#define H1940_LATCH_BLUETOOTH_POWER	(1<<29)		/* active high */
-#define H1940_LATCH_LED_GREEN		(1<<30)
-#define H1940_LATCH_LED_FLASH		(1<<31)
-
-/* default settings */
-
-#define H1940_LATCH_DEFAULT		\
-	H1940_LATCH_LCD_P4		| \
-	H1940_LATCH_SM803_ENABLE	| \
-	H1940_LATCH_SDQ1		| \
-	H1940_LATCH_LCD_P1		| \
-	H1940_LATCH_LCD_P2		| \
-	H1940_LATCH_LCD_P3		| \
-	H1940_LATCH_MAX1698_nSHUTDOWN   | \
-	H1940_LATCH_CPUQ5
-
-/* control functions */
-
-extern void h1940_latch_control(unsigned int clear, unsigned int set);
+#define H1940_LATCH_UDA_POWER		H1940_LATCH_GPIO(8)
+#define H1940_LATCH_AUDIO_POWER		H1940_LATCH_GPIO(9)
+#define H1940_LATCH_SM803_ENABLE	H1940_LATCH_GPIO(10)
+#define H1940_LATCH_LCD_P4		H1940_LATCH_GPIO(11)
+#define H1940_LATCH_SD_POWER		H1940_LATCH_GPIO(12)
+#define H1940_LATCH_BLUETOOTH_POWER	H1940_LATCH_GPIO(13)
+#define H1940_LATCH_LED_GREEN		H1940_LATCH_GPIO(14)
+#define H1940_LATCH_LED_FLASH		H1940_LATCH_GPIO(15)
 
 #endif /* __ASM_ARCH_H1940_LATCH_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -118,6 +118,8 @@
 #define S3C2443_SCLKCON_UARTCLK		(1<<8)
 #define S3C2443_SCLKCON_USBHOST		(1<<1)
 
+#define S3C2443_PWRCFG_SLEEP		(1<<15)
+
 #include <asm/div64.h>
 
 static inline unsigned int
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END	0xE0000000UL
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-amlm5900.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-amlm5900.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-amlm5900.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-amlm5900.c	2011-01-04 19:50:19.000000000 -0500
@@ -241,8 +241,6 @@
 }
 
 MACHINE_START(AML_M5900, "AML_M5900")
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= amlm5900_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-bast.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-bast.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-bast.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-bast.c	2011-01-04 19:50:19.000000000 -0500
@@ -664,8 +664,6 @@
 
 MACHINE_START(BAST, "Simtec-BAST")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= bast_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-h1940.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-h1940.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-h1940.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-h1940.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/pwm_backlight.h>
+#include <linux/i2c.h>
 #include <video/platform_lcd.h>
 
 #include <linux/mmc/host.h>
@@ -59,6 +60,14 @@
 #include <plat/mci.h>
 #include <plat/ts.h>
 
+#include <sound/uda1380.h>
+
+#define H1940_LATCH		((void __force __iomem *)0xF8000000)
+
+#define H1940_PA_LATCH		S3C2410_CS2
+
+#define H1940_LATCH_BIT(x)	(1 << ((x) + 16 - S3C_GPIO_END))
+
 static struct map_desc h1940_iodesc[] __initdata = {
 	[0] = {
 		.virtual	= (unsigned long)H1940_LATCH,
@@ -100,9 +109,9 @@
 
 /* Board control latch control */
 
-static unsigned int latch_state = H1940_LATCH_DEFAULT;
+static unsigned int latch_state;
 
-void h1940_latch_control(unsigned int clear, unsigned int set)
+static void h1940_latch_control(unsigned int clear, unsigned int set)
 {
 	unsigned long flags;
 
@@ -116,7 +125,42 @@
 	local_irq_restore(flags);
 }
 
-EXPORT_SYMBOL_GPL(h1940_latch_control);
+static inline int h1940_gpiolib_to_latch(int offset)
+{
+	return 1 << (offset + 16);
+}
+
+static void h1940_gpiolib_latch_set(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	int latch_bit = h1940_gpiolib_to_latch(offset);
+
+	h1940_latch_control(value ? 0 : latch_bit,
+		value ? latch_bit : 0);
+}
+
+static int h1940_gpiolib_latch_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	h1940_gpiolib_latch_set(chip, offset, value);
+	return 0;
+}
+
+static int h1940_gpiolib_latch_get(struct gpio_chip *chip,
+					unsigned offset)
+{
+	return (latch_state >> (offset + 16)) & 1;
+}
+
+struct gpio_chip h1940_latch_gpiochip = {
+	.base			= H1940_LATCH_GPIO(0),
+	.owner			= THIS_MODULE,
+	.label			= "H1940_LATCH",
+	.ngpio			= 16,
+	.direction_output	= h1940_gpiolib_latch_output,
+	.set			= h1940_gpiolib_latch_set,
+	.get			= h1940_gpiolib_latch_get,
+};
 
 static void h1940_udc_pullup(enum s3c2410_udc_cmd_e cmd)
 {
@@ -125,10 +169,10 @@
 	switch (cmd)
 	{
 		case S3C2410_UDC_P_ENABLE :
-			h1940_latch_control(0, H1940_LATCH_USB_DP);
+			gpio_set_value(H1940_LATCH_USB_DP, 1);
 			break;
 		case S3C2410_UDC_P_DISABLE :
-			h1940_latch_control(H1940_LATCH_USB_DP, 0);
+			gpio_set_value(H1940_LATCH_USB_DP, 0);
 			break;
 		case S3C2410_UDC_P_RESET :
 			break;
@@ -199,10 +243,25 @@
 	.id               = -1,
 };
 
+static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
+{
+	switch (power_mode) {
+	case MMC_POWER_OFF:
+		gpio_set_value(H1940_LATCH_SD_POWER, 0);
+		break;
+	case MMC_POWER_UP:
+	case MMC_POWER_ON:
+		gpio_set_value(H1940_LATCH_SD_POWER, 1);
+		break;
+	default:
+		break;
+	};
+}
+
 static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
 	.gpio_detect   = S3C2410_GPF(5),
 	.gpio_wprotect = S3C2410_GPH(8),
-	.set_power     = NULL,
+	.set_power     = h1940_set_mmc_power,
 	.ocr_avail     = MMC_VDD_32_33,
 };
 
@@ -213,15 +272,32 @@
 	gpio_direction_output(S3C2410_GPB(0), 0);
 	s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
 	s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
 
 	return 0;
 }
 
+static int h1940_backlight_notify(struct device *dev, int brightness)
+{
+	if (!brightness) {
+		gpio_direction_output(S3C2410_GPB(0), 1);
+		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+	} else {
+		gpio_direction_output(S3C2410_GPB(0), 0);
+		s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE);
+		s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);
+		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1);
+	}
+	return brightness;
+}
+
 static void h1940_backlight_exit(struct device *dev)
 {
 	gpio_direction_output(S3C2410_GPB(0), 1);
+	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
 }
 
+
 static struct platform_pwm_backlight_data backlight_data = {
 	.pwm_id         = 0,
 	.max_brightness = 100,
@@ -229,6 +305,7 @@
 	/* tcnt = 0x31 */
 	.pwm_period_ns  = 36296,
 	.init           = h1940_backlight_init,
+	.notify		= h1940_backlight_notify,
 	.exit           = h1940_backlight_exit,
 };
 
@@ -247,19 +324,37 @@
 	int value;
 
 	if (!power) {
-		/* set to 3ec */
-		gpio_direction_output(S3C2410_GPC(0), 0);
+		gpio_set_value(S3C2410_GPC(0), 0);
 		/* wait for 3ac */
 		do {
 			value = gpio_get_value(S3C2410_GPC(6));
 		} while (value);
-		/* set to 38c */
-		gpio_direction_output(S3C2410_GPC(5), 0);
+
+		gpio_set_value(H1940_LATCH_LCD_P2, 0);
+		gpio_set_value(H1940_LATCH_LCD_P3, 0);
+		gpio_set_value(H1940_LATCH_LCD_P4, 0);
+
+		gpio_direction_output(S3C2410_GPC(1), 0);
+		gpio_direction_output(S3C2410_GPC(4), 0);
+
+		gpio_set_value(H1940_LATCH_LCD_P1, 0);
+		gpio_set_value(H1940_LATCH_LCD_P0, 0);
+
+		gpio_set_value(S3C2410_GPC(5), 0);
+
 	} else {
-		/* Set to 3ac */
-		gpio_direction_output(S3C2410_GPC(5), 1);
-		/* Set to 3ad */
-		gpio_direction_output(S3C2410_GPC(0), 1);
+		gpio_set_value(H1940_LATCH_LCD_P0, 1);
+		gpio_set_value(H1940_LATCH_LCD_P1, 1);
+
+		s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2));
+
+		gpio_set_value(S3C2410_GPC(5), 1);
+		gpio_set_value(S3C2410_GPC(0), 1);
+
+		gpio_set_value(H1940_LATCH_LCD_P3, 1);
+		gpio_set_value(H1940_LATCH_LCD_P2, 1);
+		gpio_set_value(H1940_LATCH_LCD_P4, 1);
 	}
 }
 
@@ -273,12 +368,26 @@
 	.dev.platform_data      = &h1940_lcd_power_data,
 };
 
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power	= H1940_LATCH_UDA_POWER,
+	.gpio_reset	= S3C2410_GPA(12),
+	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info h1940_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x1a),
+		.platform_data = &uda1380_info,
+	},
+};
+
 static struct platform_device *h1940_devices[] __initdata = {
 	&s3c_device_ohci,
 	&s3c_device_lcd,
 	&s3c_device_wdt,
 	&s3c_device_i2c0,
 	&s3c_device_iis,
+	&s3c_device_pcm,
 	&s3c_device_usbgadget,
 	&h1940_device_leds,
 	&h1940_device_bluetooth,
@@ -303,6 +412,10 @@
 	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024);
 #endif
 	s3c_pm_init();
+
+	/* Add latch gpio chip, set latch initial value */
+	h1940_latch_control(0, 0);
+	WARN_ON(gpiochip_add(&h1940_latch_gpiochip));
 }
 
 /* H1940 and RX3715 need to reserve this for suspend */
@@ -340,18 +453,42 @@
 	writel(tmp, S3C2410_UPLLCON);
 
 	gpio_request(S3C2410_GPC(0), "LCD power");
+	gpio_request(S3C2410_GPC(1), "LCD power");
+	gpio_request(S3C2410_GPC(4), "LCD power");
 	gpio_request(S3C2410_GPC(5), "LCD power");
 	gpio_request(S3C2410_GPC(6), "LCD power");
-
+	gpio_request(H1940_LATCH_LCD_P0, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P1, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P2, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P3, "LCD power");
+	gpio_request(H1940_LATCH_LCD_P4, "LCD power");
+	gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power");
+	gpio_direction_output(S3C2410_GPC(0), 0);
+	gpio_direction_output(S3C2410_GPC(1), 0);
+	gpio_direction_output(S3C2410_GPC(4), 0);
+	gpio_direction_output(S3C2410_GPC(5), 0);
 	gpio_direction_input(S3C2410_GPC(6));
+	gpio_direction_output(H1940_LATCH_LCD_P0, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P1, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P2, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P3, 0);
+	gpio_direction_output(H1940_LATCH_LCD_P4, 0);
+	gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0);
+
+	gpio_request(H1940_LATCH_USB_DP, "USB pullup");
+	gpio_direction_output(H1940_LATCH_USB_DP, 0);
+
+	gpio_request(H1940_LATCH_SD_POWER, "SD power");
+	gpio_direction_output(H1940_LATCH_SD_POWER, 0);
 
 	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
+
+	i2c_register_board_info(0, h1940_i2c_devices,
+		ARRAY_SIZE(h1940_i2c_devices));
 }
 
 MACHINE_START(H1940, "IPAQ-H1940")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= h1940_map_io,
 	.reserve	= h1940_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-n30.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-n30.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-n30.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-n30.c	2011-01-04 19:50:19.000000000 -0500
@@ -605,8 +605,6 @@
 	/* Maintainer: Christer Weinigel <christer@weinigel.se>,
 				Ben Dooks <ben-linux@fluff.org>
 	*/
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.timer		= &s3c24xx_timer,
 	.init_machine	= n30_init,
@@ -617,8 +615,6 @@
 MACHINE_START(N35, "Acer-N35")
 	/* Maintainer: Christer Weinigel <christer@weinigel.se>
 	*/
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.timer		= &s3c24xx_timer,
 	.init_machine	= n30_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-otom.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-otom.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-otom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-otom.c	2011-01-04 19:50:19.000000000 -0500
@@ -116,8 +116,6 @@
 
 MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= otom11_map_io,
 	.init_machine	= otom11_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-qt2410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-qt2410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-qt2410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-qt2410.c	2011-01-04 19:50:19.000000000 -0500
@@ -362,8 +362,6 @@
 }
 
 MACHINE_START(QT2410, "QT2410")
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= qt2410_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-smdk2410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-smdk2410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-smdk2410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-smdk2410.c	2011-01-04 19:50:19.000000000 -0500
@@ -111,8 +111,6 @@
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
 				    * to SMDK2410 */
 	/* Maintainer: Jonas Dietsche */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= smdk2410_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-tct_hammer.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-tct_hammer.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-tct_hammer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-tct_hammer.c	2011-01-04 19:50:19.000000000 -0500
@@ -152,8 +152,6 @@
 }
 
 MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= tct_hammer_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-vr1000.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-vr1000.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2410/mach-vr1000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2410/mach-vr1000.c	2011-01-04 19:50:19.000000000 -0500
@@ -400,8 +400,6 @@
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= vr1000_map_io,
 	.init_machine	= vr1000_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 config CPU_S3C2412_ONLY
 	bool
 	depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
-		   !CPU_2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
+		   !CPU_S3C2416 && !CPU_S3C2440 && !CPU_S3C2442 && \
 		   !CPU_S3C2443 && CPU_S3C2412
 	default y if CPU_S3C2412
 
@@ -28,9 +28,16 @@
 
 config S3C2412_PM
 	bool
+	select S3C2412_PM_SLEEP
 	help
 	  Internal config node to apply S3C2412 power management
 
+config S3C2412_PM_SLEEP
+	bool
+	help
+	  Internal config node to apply sleep for S3C2412 power management.
+	  Can be selected by another SoCs with similar sleep procedure.
+
 # Note, the S3C2412 IOtiming support is in plat-s3c24xx
 
 config S3C2412_CPUFREQ
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-jive.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-jive.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-jive.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-jive.c	2011-01-04 19:50:19.000000000 -0500
@@ -675,8 +675,6 @@
 
 MACHINE_START(JIVE, "JIVE")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-smdk2413.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-smdk2413.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-smdk2413.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-smdk2413.c	2011-01-04 19:50:19.000000000 -0500
@@ -150,8 +150,6 @@
 
 MACHINE_START(S3C2413, "S3C2413")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.fixup		= smdk2413_fixup,
@@ -163,8 +161,6 @@
 
 MACHINE_START(SMDK2412, "SMDK2412")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.fixup		= smdk2413_fixup,
@@ -176,8 +172,6 @@
 
 MACHINE_START(SMDK2413, "SMDK2413")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.fixup		= smdk2413_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-vstms.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-vstms.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/mach-vstms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/mach-vstms.c	2011-01-04 19:50:19.000000000 -0500
@@ -156,8 +156,6 @@
 }
 
 MACHINE_START(VSTMS, "VSTMS")
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.fixup		= vstms_fixup,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,8 @@
 obj-$(CONFIG_CPU_S3C2412)	+= clock.o
 obj-$(CONFIG_CPU_S3C2412)	+= gpio.o
 obj-$(CONFIG_S3C2412_DMA)	+= dma.o
-obj-$(CONFIG_S3C2412_PM)	+= pm.o sleep.o
+obj-$(CONFIG_S3C2412_PM)	+= pm.o
+obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep.o
 obj-$(CONFIG_S3C2412_CPUFREQ)	+= cpu-freq.o
 
 # Machine support
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/s3c2412.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/s3c2412.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2412/s3c2412.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2412/s3c2412.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,7 @@
 #include <plat/clock.h>
 #include <plat/pm.h>
 #include <plat/pll.h>
+#include <plat/nand-core.h>
 
 #ifndef CONFIG_CPU_S3C2412_ONLY
 void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
@@ -92,7 +93,7 @@
 	/* rename devices that are s3c2412/s3c2413 specific */
 	s3c_device_sdi.name  = "s3c2412-sdi";
 	s3c_device_lcd.name  = "s3c2412-lcd";
-	s3c_device_nand.name = "s3c2412-nand";
+	s3c_nand_setname("s3c2412-nand");
 
 	/* alter IRQ of SDI controller */
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -168,12 +168,11 @@
 
 static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
 {
-	s3c2416_irq_demux(IRQ_S3C2443_UART3, 3);
+	s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
 }
 
 #define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
+#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
 
 static void s3c2416_irq_uart3_mask(unsigned int irqno)
 {
@@ -243,6 +242,8 @@
 
 static struct sysdev_driver s3c2416_irq_driver = {
 	.add		= s3c2416_irq_add,
+	.suspend	= s3c24xx_irq_suspend,
+	.resume		= s3c24xx_irq_resume,
 };
 
 static int __init s3c2416_irq_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -25,14 +25,24 @@
 	help
 	  Internal config node for S3C2416 DMA support
 
+config S3C2416_PM
+	bool
+	select S3C2412_PM_SLEEP
+	help
+	  Internal config node to apply S3C2416 power management
+
 menu "S3C2416 Machines"
 
 config MACH_SMDK2416
 	bool "SMDK2416"
 	select CPU_S3C2416
+	select MACH_SMDK
 	select S3C_DEV_FB
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC1
+	select S3C_DEV_NAND
+	select S3C_DEV_USB_HOST
+	select S3C2416_PM if PM
 	help
 	  Say Y here if you are using an SMDK2416
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/mach-smdk2416.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/mach-smdk2416.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/mach-smdk2416.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/mach-smdk2416.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,8 +195,6 @@
 
 MACHINE_START(SMDK2416, "SMDK2416")
 	/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,7 @@
 
 obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o clock.o
 obj-$(CONFIG_CPU_S3C2416)	+= irq.o
-
+obj-$(CONFIG_S3C2416_PM)	+= pm.o
 #obj-$(CONFIG_S3C2416_DMA)	+= dma.o
 
 # Machine support
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/pm.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/pm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,84 @@
+/* linux/arch/arm/mach-s3c2416/pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM support)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/regs-power.h>
+#include <mach/regs-s3c2443-clock.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+extern void s3c2412_sleep_enter(void);
+
+static void s3c2416_cpu_suspend(void)
+{
+	flush_cache_all();
+
+	/* enable wakeup sources regardless of battery state */
+	__raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG);
+
+	/* set the mode as sleep, 2BED represents "Go to BED" */
+	__raw_writel(0x2BED, S3C2443_PWRMODE);
+
+	s3c2412_sleep_enter();
+}
+
+static void s3c2416_pm_prepare(void)
+{
+	/*
+	 * write the magic value u-boot uses to check for resume into
+	 * the INFORM0 register, and ensure INFORM1 is set to the
+	 * correct address to resume from.
+	 */
+	__raw_writel(0x2BED, S3C2412_INFORM0);
+	__raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1);
+}
+
+static int s3c2416_pm_add(struct sys_device *sysdev)
+{
+	pm_cpu_prep = s3c2416_pm_prepare;
+	pm_cpu_sleep = s3c2416_cpu_suspend;
+
+	return 0;
+}
+
+static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+	return 0;
+}
+
+static int s3c2416_pm_resume(struct sys_device *dev)
+{
+	/* unset the return-from-sleep amd inform flags */
+	__raw_writel(0x0, S3C2443_PWRMODE);
+	__raw_writel(0x0, S3C2412_INFORM0);
+	__raw_writel(0x0, S3C2412_INFORM1);
+
+	return 0;
+}
+
+static struct sysdev_driver s3c2416_pm_driver = {
+	.add		= s3c2416_pm_add,
+	.suspend	= s3c2416_pm_suspend,
+	.resume		= s3c2416_pm_resume,
+};
+
+static __init int s3c2416_pm_init(void)
+{
+	return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver);
+}
+
+arch_initcall(s3c2416_pm_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/s3c2416.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/s3c2416.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2416/s3c2416.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2416/s3c2416.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,6 +56,7 @@
 
 #include <plat/iic-core.h>
 #include <plat/fb-core.h>
+#include <plat/nand-core.h>
 
 static struct map_desc s3c2416_iodesc[] __initdata = {
 	IODESC_ENT(WATCHDOG),
@@ -100,7 +101,7 @@
 {
 	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
 
-	s3c_device_nand.name = "s3c2416-nand";
+	s3c_nand_setname("s3c2412-nand");
 }
 
 /* s3c2416_map_io
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 
 config CPU_S3C2440
 	bool
-	depends on ARCH_S3C2410
 	select CPU_ARM920T
 	select S3C_GPIO_PULL_UP
 	select S3C2410_CLOCK
@@ -18,8 +17,8 @@
 
 config CPU_S3C2442
 	bool
-	depends on ARCH_S3C2410
 	select CPU_ARM920T
+	select S3C_GPIO_PULL_DOWN
 	select S3C2410_CLOCK
 	select S3C2410_GPIO
 	select S3C2410_PM if PM
@@ -30,7 +29,7 @@
 
 config CPU_S3C244X
 	bool
-	depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
+	depends on CPU_S3C2440 || CPU_S3C2442
 	help
 	  Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
 
@@ -72,7 +71,7 @@
 
 config S3C2440_DMA
 	bool
-	depends on ARCH_S3C2410 && CPU_S3C24405B
+	depends on CPU_S3C2440
 	help
 	  Support for S3C2440 specific DMA code5A
 
@@ -180,8 +179,10 @@
 	bool "MINI2440 development board"
 	select CPU_S3C2440
 	select EEPROM_AT24
+	select NEW_LEDS
+	select LEDS_CLASS
+	select LEDS_TRIGGER
 	select LEDS_TRIGGER_BACKLIGHT
-	select SND_S3C24XX_SOC_S3C24XX_UDA134X
 	select S3C_DEV_NAND
 	select S3C_DEV_USB_HOST
 	help
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-anubis.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-anubis.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-anubis.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-anubis.c	2011-01-04 19:50:19.000000000 -0500
@@ -498,8 +498,6 @@
 
 MACHINE_START(ANUBIS, "Simtec-Anubis")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= anubis_map_io,
 	.init_machine	= anubis_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-at2440evb.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-at2440evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-at2440evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-at2440evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *      and modifications by SBZ <sbz@spgui.org> and
  *      Weibing <http://weibing.blogbus.com>
  *
- * For product information, visit http://www.arm9e.com/
+ * For product information, visit http://www.arm.com/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -233,8 +233,6 @@
 
 
 MACHINE_START(AT2440EVB, "AT2440EVB")
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= at2440evb_map_io,
 	.init_machine	= at2440evb_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-gta02.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-gta02.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-gta02.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-gta02.c	2011-01-04 19:50:19.000000000 -0500
@@ -572,8 +572,6 @@
 
 MACHINE_START(NEO1973_GTA02, "GTA02")
 	/* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= gta02_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-mini2440.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-mini2440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-mini2440.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-mini2440.c	2011-01-04 19:50:19.000000000 -0500
@@ -691,8 +691,6 @@
 
 MACHINE_START(MINI2440, "MINI2440")
 	/* Maintainer: Michel Pollet <buserror@gmail.com> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= mini2440_map_io,
 	.init_machine	= mini2440_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-nexcoder.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-nexcoder.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-nexcoder.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-nexcoder.c	2011-01-04 19:50:19.000000000 -0500
@@ -151,8 +151,6 @@
 
 MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
 	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= nexcoder_map_io,
 	.init_machine	= nexcoder_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-osiris.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-osiris.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-osiris.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-osiris.c	2011-01-04 19:50:19.000000000 -0500
@@ -455,8 +455,6 @@
 
 MACHINE_START(OSIRIS, "Simtec-OSIRIS")
 	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= osiris_map_io,
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-rx1950.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-rx1950.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-rx1950.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-rx1950.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,8 +25,12 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/sysdev.h>
+#include <linux/pda_power.h>
 #include <linux/pwm_backlight.h>
 #include <linux/pwm.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -55,6 +59,8 @@
 #include <plat/irq.h>
 #include <plat/ts.h>
 
+#include <sound/uda1380.h>
+
 #define LCD_PWM_PERIOD 192960
 #define LCD_PWM_DUTY 127353
 
@@ -127,6 +133,193 @@
 
 };
 
+static int power_supply_init(struct device *dev)
+{
+	return gpio_request(S3C2410_GPF(2), "cable plugged");
+}
+
+static int rx1950_is_ac_online(void)
+{
+	return !gpio_get_value(S3C2410_GPF(2));
+}
+
+static void power_supply_exit(struct device *dev)
+{
+	gpio_free(S3C2410_GPF(2));
+}
+
+static char *rx1950_supplicants[] = {
+	"main-battery"
+};
+
+static struct pda_power_pdata power_supply_info = {
+	.init			= power_supply_init,
+	.is_ac_online		= rx1950_is_ac_online,
+	.exit			= power_supply_exit,
+	.supplied_to		= rx1950_supplicants,
+	.num_supplicants	= ARRAY_SIZE(rx1950_supplicants),
+};
+
+static struct resource power_supply_resources[] = {
+	[0] = {
+			.name	= "ac",
+			.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
+					  IORESOURCE_IRQ_HIGHEDGE,
+			.start	= IRQ_EINT2,
+			.end	= IRQ_EINT2,
+	},
+};
+
+static struct platform_device power_supply = {
+	.name			= "pda-power",
+	.id			= -1,
+	.dev			= {
+					.platform_data =
+						&power_supply_info,
+	},
+	.resource		= power_supply_resources,
+	.num_resources		= ARRAY_SIZE(power_supply_resources),
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
+	{ .volt = 4100, .cur = 156, .level = 100},
+	{ .volt = 4050, .cur = 156, .level = 95},
+	{ .volt = 4025, .cur = 141, .level = 90},
+	{ .volt = 3995, .cur = 144, .level = 85},
+	{ .volt = 3957, .cur = 162, .level = 80},
+	{ .volt = 3931, .cur = 147, .level = 75},
+	{ .volt = 3902, .cur = 147, .level = 70},
+	{ .volt = 3863, .cur = 153, .level = 65},
+	{ .volt = 3838, .cur = 150, .level = 60},
+	{ .volt = 3800, .cur = 153, .level = 55},
+	{ .volt = 3765, .cur = 153, .level = 50},
+	{ .volt = 3748, .cur = 172, .level = 45},
+	{ .volt = 3740, .cur = 153, .level = 40},
+	{ .volt = 3714, .cur = 175, .level = 35},
+	{ .volt = 3710, .cur = 156, .level = 30},
+	{ .volt = 3963, .cur = 156, .level = 25},
+	{ .volt = 3672, .cur = 178, .level = 20},
+	{ .volt = 3651, .cur = 178, .level = 15},
+	{ .volt = 3629, .cur = 178, .level = 10},
+	{ .volt = 3612, .cur = 162, .level = 5},
+	{ .volt = 3605, .cur = 162, .level = 0},
+};
+
+static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
+	{ .volt = 4200, .cur = 0, .level = 100},
+	{ .volt = 4190, .cur = 0, .level = 99},
+	{ .volt = 4178, .cur = 0, .level = 95},
+	{ .volt = 4110, .cur = 0, .level = 70},
+	{ .volt = 4076, .cur = 0, .level = 65},
+	{ .volt = 4046, .cur = 0, .level = 60},
+	{ .volt = 4021, .cur = 0, .level = 55},
+	{ .volt = 3999, .cur = 0, .level = 50},
+	{ .volt = 3982, .cur = 0, .level = 45},
+	{ .volt = 3965, .cur = 0, .level = 40},
+	{ .volt = 3957, .cur = 0, .level = 35},
+	{ .volt = 3948, .cur = 0, .level = 30},
+	{ .volt = 3936, .cur = 0, .level = 25},
+	{ .volt = 3927, .cur = 0, .level = 20},
+	{ .volt = 3906, .cur = 0, .level = 15},
+	{ .volt = 3880, .cur = 0, .level = 10},
+	{ .volt = 3829, .cur = 0, .level = 5},
+	{ .volt = 3820, .cur = 0, .level = 0},
+};
+
+int rx1950_bat_init(void)
+{
+	int ret;
+
+	ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
+	if (ret)
+		goto err_gpio1;
+	ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
+	if (ret)
+		goto err_gpio2;
+
+	return 0;
+
+err_gpio2:
+	gpio_free(S3C2410_GPJ(2));
+err_gpio1:
+	return ret;
+}
+
+void rx1950_bat_exit(void)
+{
+	gpio_free(S3C2410_GPJ(2));
+	gpio_free(S3C2410_GPJ(3));
+}
+
+void rx1950_enable_charger(void)
+{
+	gpio_direction_output(S3C2410_GPJ(2), 1);
+	gpio_direction_output(S3C2410_GPJ(3), 1);
+}
+
+void rx1950_disable_charger(void)
+{
+	gpio_direction_output(S3C2410_GPJ(2), 0);
+	gpio_direction_output(S3C2410_GPJ(3), 0);
+}
+
+static struct gpio_led rx1950_leds_desc[] = {
+	{
+		.name				= "Green",
+		.default_trigger	= "main-battery-charging-or-full",
+		.gpio				= S3C2410_GPA(6),
+	},
+	{
+		.name				= "Red",
+		.default_trigger	= "main-battery-full",
+		.gpio				= S3C2410_GPA(7),
+	},
+	{
+		.name				= "Blue",
+		.default_trigger	= "rx1950-acx-mem",
+		.gpio				= S3C2410_GPA(11),
+	},
+};
+
+static struct gpio_led_platform_data rx1950_leds_pdata = {
+	.num_leds	= ARRAY_SIZE(rx1950_leds_desc),
+	.leds		= rx1950_leds_desc,
+};
+
+static struct platform_device rx1950_leds = {
+	.name	= "leds-gpio",
+	.id		= -1,
+	.dev	= {
+				.platform_data = &rx1950_leds_pdata,
+	},
+};
+
+static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
+	.init = rx1950_bat_init,
+	.exit = rx1950_bat_exit,
+	.enable_charger = rx1950_enable_charger,
+	.disable_charger = rx1950_disable_charger,
+	.gpio_charge_finished = S3C2410_GPF(3),
+	.lut_noac = bat_lut_noac,
+	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
+	.lut_acin = bat_lut_acin,
+	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
+	.volt_channel = 0,
+	.current_channel = 1,
+	.volt_mult = 4235,
+	.current_mult = 2900,
+	.internal_impedance = 200,
+};
+
+static struct platform_device rx1950_battery = {
+	.name             = "s3c-adc-battery",
+	.id               = -1,
+	.dev = {
+		.parent = &s3c_device_adc.dev,
+		.platform_data = &rx1950_bat_cfg,
+	},
+};
+
 static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
 	.displays = &rx1950_display,
 	.num_displays = 1,
@@ -481,11 +674,17 @@
 	.dev.platform_data = &rx1950_gpio_keys_data,
 };
 
-static struct s3c2410_platform_i2c rx1950_i2c_data = {
-	.flags = 0,
-	.slave_addr = 0x42,
-	.frequency = 400 * 1000,
-	.sda_delay = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power	= S3C2410_GPJ(0),
+	.gpio_reset	= S3C2410_GPD(0),
+	.dac_clk	= UDA1380_DAC_CLK_SYSCLK,
+};
+
+static struct i2c_board_info rx1950_i2c_devices[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x1a),
+		.platform_data = &uda1380_info,
+	},
 };
 
 static struct platform_device *rx1950_devices[] __initdata = {
@@ -493,6 +692,7 @@
 	&s3c_device_wdt,
 	&s3c_device_i2c0,
 	&s3c_device_iis,
+	&s3c_device_pcm,
 	&s3c_device_usbgadget,
 	&s3c_device_rtc,
 	&s3c_device_nand,
@@ -503,6 +703,9 @@
 	&s3c_device_timer[1],
 	&rx1950_backlight,
 	&rx1950_device_gpiokeys,
+	&power_supply,
+	&rx1950_battery,
+	&rx1950_leds,
 };
 
 static struct clk *rx1950_clocks[] __initdata = {
@@ -538,7 +741,7 @@
 	s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
 	s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
 	s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
-	s3c_i2c0_set_platdata(&rx1950_i2c_data);
+	s3c_i2c0_set_platdata(NULL);
 	s3c_nand_set_platdata(&rx1950_nand_info);
 
 	/* Turn off suspend on both USB ports, and switch the
@@ -569,6 +772,9 @@
 	WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power"));
 
 	platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
+
+	i2c_register_board_info(0, rx1950_i2c_devices,
+		ARRAY_SIZE(rx1950_i2c_devices));
 }
 
 /* H1940 and RX3715 need to reserve this for suspend */
@@ -580,8 +786,6 @@
 
 MACHINE_START(RX1950, "HP iPAQ RX1950")
     /* Maintainers: Vasily Khoruzhick */
-    .phys_io = S3C2410_PA_UART,
-	.io_pg_offst = (((u32) S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params = S3C2410_SDRAM_PA + 0x100,
 	.map_io = rx1950_map_io,
 	.reserve	= rx1950_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-rx3715.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-rx3715.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-rx3715.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-rx3715.c	2011-01-04 19:50:19.000000000 -0500
@@ -218,8 +218,6 @@
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 	.map_io		= rx3715_map_io,
 	.reserve	= rx3715_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-smdk2440.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-smdk2440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/mach-smdk2440.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/mach-smdk2440.c	2011-01-04 19:50:19.000000000 -0500
@@ -175,8 +175,6 @@
 
 MACHINE_START(S3C2440, "SMDK2440")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c2440.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c2440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c2440.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c2440.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,9 +46,6 @@
 {
 	printk("S3C2440: Initialising architecture\n");
 
-	s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up;
-	s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up;
-
 	/* change irq for watchdog */
 
 	s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
@@ -58,3 +55,11 @@
 
 	return sysdev_register(&s3c2440_sysdev);
 }
+
+void __init s3c2440_map_io(void)
+{
+	s3c244x_map_io();
+
+	s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1up;
+	s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1up;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c2442.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c2442.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c2442.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c2442.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/mutex.h>
+#include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 
@@ -43,6 +44,11 @@
 
 #include <plat/clock.h>
 #include <plat/cpu.h>
+#include <plat/s3c244x.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
 
 /* S3C2442 extended clock support */
 
@@ -163,3 +169,11 @@
 
 	return sysdev_register(&s3c2442_sysdev);
 }
+
+void __init s3c2442_map_io(void)
+{
+	s3c244x_map_io();
+
+	s3c24xx_gpiocfg_default.set_pull = s3c_gpio_setpull_1down;
+	s3c24xx_gpiocfg_default.get_pull = s3c_gpio_getpull_1down;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c244x.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c244x.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2440/s3c244x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2440/s3c244x.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,7 @@
 #include <plat/cpu.h>
 #include <plat/pm.h>
 #include <plat/pll.h>
+#include <plat/nand-core.h>
 
 static struct map_desc s3c244x_iodesc[] __initdata = {
 	IODESC_ENT(CLKPWR),
@@ -68,7 +69,7 @@
 
 	s3c_device_sdi.name  = "s3c2440-sdi";
 	s3c_device_i2c0.name  = "s3c2440-i2c";
-	s3c_device_nand.name = "s3c2440-nand";
+	s3c_nand_setname("s3c2440-nand");
 	s3c_device_ts.name = "s3c2440-ts";
 	s3c_device_usbgadget.name = "s3c2440-usbgadget";
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -166,12 +166,11 @@
 
 static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
 {
-	s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);
+	s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
 }
 
 #define INTMSK_UART3	(1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
-#define SUBMSK_UART3	(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
-
+#define SUBMSK_UART3	(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
 
 static void s3c2443_irq_uart3_mask(unsigned int irqno)
 {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,7 @@
 config CPU_S3C2443
 	bool
 	depends on ARCH_S3C2410
+	select CPU_ARM920T
 	select S3C2443_DMA if S3C2410_DMA
 	select CPU_LLSERIAL_S3C2440
 	select SAMSUNG_CLKSRC
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/mach-smdk2443.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/mach-smdk2443.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/mach-smdk2443.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/mach-smdk2443.c	2011-01-04 19:50:19.000000000 -0500
@@ -132,8 +132,6 @@
 
 MACHINE_START(SMDK2443, "SMDK2443")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C2410_PA_UART,
-	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C2410_SDRAM_PA + 0x100,
 
 	.init_irq	= s3c24xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/s3c2443.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/s3c2443.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c2443/s3c2443.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c2443/s3c2443.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,7 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/fb-core.h>
+#include <plat/nand-core.h>
 
 static struct map_desc s3c2443_iodesc[] __initdata = {
 	IODESC_ENT(WATCHDOG),
@@ -62,7 +63,7 @@
 
 	s3c24xx_reset_hook = s3c2443_hard_reset;
 
-	s3c_device_nand.name = "s3c2412-nand";
+	s3c_nand_setname("s3c2412-nand");
 	s3c_fb_setname("s3c2443-fb");
 
 	/* change WDT IRQ number */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c24a0/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s3c24a0/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c24a0/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c24a0/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,13 +10,12 @@
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-	.macro addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C24XX_PA_UART
-		ldrne	\rx, = S3C24XX_VA_UART
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C24XX_PA_UART
+		ldr	\rv, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c24a0/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c24a0/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c24a0/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c24a0/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END	  (0xe0000000UL)
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/dev-audio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/dev-audio.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,44 +22,34 @@
 #include <plat/audio.h>
 #include <plat/gpio-cfg.h>
 
-#include <mach/gpio-bank-c.h>
-#include <mach/gpio-bank-d.h>
-#include <mach/gpio-bank-e.h>
-#include <mach/gpio-bank-h.h>
-
 static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
 {
+	unsigned int base;
+
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_I2S0_CLK);
-		s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_I2S0_CDCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_I2S0_LRCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_I2S0_DI);
-		s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_I2S0_D0);
+		base = S3C64XX_GPD(0);
 		break;
 	case 1:
-		s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_I2S1_CLK);
-		s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_I2S1_CDCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
-		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+		base = S3C64XX_GPE(0);
+		break;
 	default:
-		printk(KERN_DEBUG "Invalid I2S Controller number!");
+		printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 	}
 
+	s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3));
+
 	return 0;
 }
 
 static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev)
 {
-	s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
-	s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
-	s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
-	s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
-	s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
-	s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
-	s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+	s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
+	s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
+	s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
+	s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
 
 	return 0;
 }
@@ -168,26 +158,22 @@
 
 static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
 {
+	unsigned int base;
+
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
-		s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
-		s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
+		base = S3C64XX_GPD(0);
 		break;
 	case 1:
-		s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
-		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
-		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
-		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
+		base = S3C64XX_GPE(0);
 		break;
 	default:
-		printk(KERN_DEBUG "Invalid PCM Controller number!");
+		printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 	}
 
+	s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2));
 	return 0;
 }
 
@@ -261,24 +247,12 @@
 
 static int s3c64xx_ac97_cfg_gpd(struct platform_device *pdev)
 {
-	s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_AC97_BITCLK);
-	s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_AC97_nRESET);
-	s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_AC97_SYNC);
-	s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_AC97_SDI);
-	s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_AC97_SDO);
-
-	return 0;
+	return s3c_gpio_cfgpin_range(S3C64XX_GPD(0), 5, S3C_GPIO_SFN(4));
 }
 
 static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev)
 {
-	s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_AC97_BITCLK);
-	s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_AC97_nRESET);
-	s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_AC97_SYNC);
-	s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_AC97_SDI);
-	s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_AC97_SDO);
-
-	return 0;
+	return s3c_gpio_cfgpin_range(S3C64XX_GPE(0), 5, S3C_GPIO_SFN(4));
 }
 
 static struct resource s3c64xx_ac97_resource[] = {
@@ -333,3 +307,16 @@
 	else
 		s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 }
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/gpiolib.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/gpiolib.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/gpiolib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,11 +195,6 @@
 	.get_pull	= s3c_gpio_getpull_updown,
 };
 
-int s3c64xx_gpio2int_gpn(struct gpio_chip *chip, unsigned pin)
-{
-	return IRQ_EINT(0) + pin;
-}
-
 static struct s3c_gpio_chip gpio_2bit[] = {
 	{
 		.base	= S3C64XX_GPF_BASE,
@@ -227,12 +222,13 @@
 		},
 	}, {
 		.base	= S3C64XX_GPN_BASE,
+		.irq_base = IRQ_EINT(0),
 		.config	= &gpio_2bit_cfg_eint10,
 		.chip	= {
 			.base	= S3C64XX_GPN(0),
 			.ngpio	= S3C64XX_GPIO_N_NR,
 			.label	= "GPN",
-			.to_irq = s3c64xx_gpio2int_gpn,
+			.to_irq = samsung_gpiolib_to_irq,
 		},
 	}, {
 		.base	= S3C64XX_GPO_BASE,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -21,13 +21,12 @@
 	 * aligned and add in the offset when we load the value here.
 	 */
 
-	.macro addruart, rx, rtmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C_PA_UART
+		ldr	\rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END	0xE0000000UL
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -98,12 +98,33 @@
 	help
 	  Machine support for the A&W6410
 
+config MACH_MINI6410
+	bool "MINI6410"
+	select CPU_S3C6410
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC1
+	select S3C64XX_SETUP_SDHCI
+	select S3C_DEV_USB_HOST
+	select S3C_DEV_NAND
+	select S3C_DEV_FB
+	select S3C64XX_SETUP_FB_24BPP
+	select SAMSUNG_DEV_ADC
+	select SAMSUNG_DEV_TS
+	help
+	  Machine support for the FriendlyARM MINI6410
+
 config MACH_REAL6410
 	bool "REAL6410"
 	select CPU_S3C6410
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC1
 	select S3C64XX_SETUP_SDHCI
+	select S3C_DEV_FB
+	select S3C64XX_SETUP_FB_24BPP
+	select S3C_DEV_NAND
+	select SAMSUNG_DEV_ADC
+	select SAMSUNG_DEV_TS
+	select S3C_DEV_USB_HOST
 	help
 	  Machine support for the CoreWind REAL6410
 
@@ -122,7 +143,7 @@
 	select S3C_DEV_USB_HSOTG
 	select S3C_DEV_WDT
 	select SAMSUNG_DEV_KEYPAD
-	select HAVE_S3C2410_WATCHDOG
+	select HAVE_S3C2410_WATCHDOG if WATCHDOG
 	select S3C64XX_SETUP_SDHCI
 	select S3C64XX_SETUP_I2C1
 	select S3C64XX_SETUP_IDE
@@ -185,6 +206,7 @@
 	select REGULATOR_WM831X
 	select S3C24XX_GPIO_EXTRA64
 	select MFD_WM831X
+	select MFD_WM831X_I2C
 	help
 	  The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC
 	  daughtercard for the Samsung SMDK6410 reference platform.
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-anw6410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-anw6410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-anw6410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-anw6410.c	2011-01-04 19:50:19.000000000 -0500
@@ -233,8 +233,6 @@
 
 MACHINE_START(ANW6410, "A&W6410")
 	/* Maintainer: Kwangwoo Lee <kwangwoo.lee@gmail.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 
 	.init_irq	= s3c6410_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-hmt.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-hmt.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-hmt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-hmt.c	2011-01-04 19:50:19.000000000 -0500
@@ -265,8 +265,6 @@
 
 MACHINE_START(HMT, "Airgoo-HMT")
 	/* Maintainer: Peter Korsgaard <jacmet@sunsite.dk> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 	.init_irq	= s3c6410_init_irq,
 	.map_io		= hmt_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-mini6410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-mini6410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-mini6410.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-mini6410.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,357 @@
+/* linux/arch/arm/mach-s3c64xx/mach-mini6410.c
+ *
+ * Copyright 2010 Darius Augulis <augulis.darius@gmail.com>
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/dm9000.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-modem.h>
+#include <mach/regs-srom.h>
+#include <mach/s3c6410.h>
+
+#include <plat/adc.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/fb.h>
+#include <plat/nand.h>
+#include <plat/regs-serial.h>
+#include <plat/ts.h>
+
+#include <video/platform_lcd.h>
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
+#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
+
+static struct s3c2410_uartcfg mini6410_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport	= 0,
+		.flags	= 0,
+		.ucon	= UCON,
+		.ulcon	= ULCON,
+		.ufcon	= UFCON,
+	},
+	[1] = {
+		.hwport	= 1,
+		.flags	= 0,
+		.ucon	= UCON,
+		.ulcon	= ULCON,
+		.ufcon	= UFCON,
+	},
+	[2] = {
+		.hwport	= 2,
+		.flags	= 0,
+		.ucon	= UCON,
+		.ulcon	= ULCON,
+		.ufcon	= UFCON,
+	},
+	[3] = {
+		.hwport	= 3,
+		.flags	= 0,
+		.ucon	= UCON,
+		.ulcon	= ULCON,
+		.ufcon	= UFCON,
+	},
+};
+
+/* DM9000AEP 10/100 ethernet controller */
+
+static struct resource mini6410_dm9k_resource[] = {
+	[0] = {
+		.start	= S3C64XX_PA_XM0CSN1,
+		.end	= S3C64XX_PA_XM0CSN1 + 1,
+		.flags	= IORESOURCE_MEM
+	},
+	[1] = {
+		.start	= S3C64XX_PA_XM0CSN1 + 4,
+		.end	= S3C64XX_PA_XM0CSN1 + 5,
+		.flags	= IORESOURCE_MEM
+	},
+	[2] = {
+		.start	= S3C_EINT(7),
+		.end	= S3C_EINT(7),
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
+	}
+};
+
+static struct dm9000_plat_data mini6410_dm9k_pdata = {
+	.flags		= (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
+};
+
+static struct platform_device mini6410_device_eth = {
+	.name		= "dm9000",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(mini6410_dm9k_resource),
+	.resource	= mini6410_dm9k_resource,
+	.dev		= {
+		.platform_data	= &mini6410_dm9k_pdata,
+	},
+};
+
+static struct mtd_partition mini6410_nand_part[] = {
+	[0] = {
+		.name	= "uboot",
+		.size	= SZ_1M,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "kernel",
+		.size	= SZ_2M,
+		.offset	= SZ_1M,
+	},
+	[2] = {
+		.name	= "rootfs",
+		.size	= MTDPART_SIZ_FULL,
+		.offset	= SZ_1M + SZ_2M,
+	},
+};
+
+static struct s3c2410_nand_set mini6410_nand_sets[] = {
+	[0] = {
+		.name		= "nand",
+		.nr_chips	= 1,
+		.nr_partitions	= ARRAY_SIZE(mini6410_nand_part),
+		.partitions	= mini6410_nand_part,
+	},
+};
+
+static struct s3c2410_platform_nand mini6410_nand_info = {
+	.tacls		= 25,
+	.twrph0		= 55,
+	.twrph1		= 40,
+	.nr_sets	= ARRAY_SIZE(mini6410_nand_sets),
+	.sets		= mini6410_nand_sets,
+};
+
+static struct s3c_fb_pd_win mini6410_fb_win[] = {
+	{
+		.win_mode	= {	/* 4.3" 480x272 */
+			.left_margin	= 3,
+			.right_margin	= 2,
+			.upper_margin	= 1,
+			.lower_margin	= 1,
+			.hsync_len	= 40,
+			.vsync_len	= 1,
+			.xres		= 480,
+			.yres		= 272,
+		},
+		.max_bpp	= 32,
+		.default_bpp	= 16,
+	}, {
+		.win_mode	= {	/* 7.0" 800x480 */
+			.left_margin	= 8,
+			.right_margin	= 13,
+			.upper_margin	= 7,
+			.lower_margin	= 5,
+			.hsync_len	= 3,
+			.vsync_len	= 1,
+			.xres		= 800,
+			.yres		= 480,
+		},
+		.max_bpp	= 32,
+		.default_bpp	= 16,
+	},
+};
+
+static struct s3c_fb_platdata mini6410_lcd_pdata __initdata = {
+	.setup_gpio	= s3c64xx_fb_gpio_setup_24bpp,
+	.win[0]		= &mini6410_fb_win[0],
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+static void mini6410_lcd_power_set(struct plat_lcd_data *pd,
+				   unsigned int power)
+{
+	if (power)
+		gpio_direction_output(S3C64XX_GPE(0), 1);
+	else
+		gpio_direction_output(S3C64XX_GPE(0), 0);
+}
+
+static struct plat_lcd_data mini6410_lcd_power_data = {
+	.set_power	= mini6410_lcd_power_set,
+};
+
+static struct platform_device mini6410_lcd_powerdev = {
+	.name			= "platform-lcd",
+	.dev.parent		= &s3c_device_fb.dev,
+	.dev.platform_data	= &mini6410_lcd_power_data,
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+	.delay			= 10000,
+	.presc			= 49,
+	.oversampling_shift	= 2,
+};
+
+static struct platform_device *mini6410_devices[] __initdata = {
+	&mini6410_device_eth,
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc1,
+	&s3c_device_ohci,
+	&s3c_device_nand,
+	&s3c_device_fb,
+	&mini6410_lcd_powerdev,
+	&s3c_device_adc,
+	&s3c_device_ts,
+};
+
+static void __init mini6410_map_io(void)
+{
+	u32 tmp;
+
+	s3c64xx_init_io(NULL, 0);
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs));
+
+	/* set the LCD type */
+	tmp = __raw_readl(S3C64XX_SPCON);
+	tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+	tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+	__raw_writel(tmp, S3C64XX_SPCON);
+
+	/* remove the LCD bypass */
+	tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+	tmp &= ~MIFPCON_LCD_BYPASS;
+	__raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
+}
+
+/*
+ * mini6410_features string
+ *
+ * 0-9 LCD configuration
+ *
+ */
+static char mini6410_features_str[12] __initdata = "0";
+
+static int __init mini6410_features_setup(char *str)
+{
+	if (str)
+		strlcpy(mini6410_features_str, str,
+			sizeof(mini6410_features_str));
+	return 1;
+}
+
+__setup("mini6410=", mini6410_features_setup);
+
+#define FEATURE_SCREEN (1 << 0)
+
+struct mini6410_features_t {
+	int done;
+	int lcd_index;
+};
+
+static void mini6410_parse_features(
+		struct mini6410_features_t *features,
+		const char *features_str)
+{
+	const char *fp = features_str;
+
+	features->done = 0;
+	features->lcd_index = 0;
+
+	while (*fp) {
+		char f = *fp++;
+
+		switch (f) {
+		case '0'...'9':	/* tft screen */
+			if (features->done & FEATURE_SCREEN) {
+				printk(KERN_INFO "MINI6410: '%c' ignored, "
+					"screen type already set\n", f);
+			} else {
+				int li = f - '0';
+				if (li >= ARRAY_SIZE(mini6410_fb_win))
+					printk(KERN_INFO "MINI6410: '%c' out "
+						"of range LCD mode\n", f);
+				else {
+					features->lcd_index = li;
+				}
+			}
+			features->done |= FEATURE_SCREEN;
+			break;
+		}
+	}
+}
+
+static void __init mini6410_machine_init(void)
+{
+	u32 cs1;
+	struct mini6410_features_t features = { 0 };
+
+	printk(KERN_INFO "MINI6410: Option string mini6410=%s\n",
+			mini6410_features_str);
+
+	/* Parse the feature string */
+	mini6410_parse_features(&features, mini6410_features_str);
+
+	mini6410_lcd_pdata.win[0] = &mini6410_fb_win[features.lcd_index];
+
+	printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n",
+		mini6410_lcd_pdata.win[0]->win_mode.xres,
+		mini6410_lcd_pdata.win[0]->win_mode.yres);
+
+	s3c_nand_set_platdata(&mini6410_nand_info);
+	s3c_fb_set_platdata(&mini6410_lcd_pdata);
+	s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
+	/* configure nCS1 width to 16 bits */
+
+	cs1 = __raw_readl(S3C64XX_SROM_BW) &
+		~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
+	cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
+		(1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
+		(1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
+			S3C64XX_SROM_BW__NCS1__SHIFT;
+	__raw_writel(cs1, S3C64XX_SROM_BW);
+
+	/* set timing for nCS1 suitable for ethernet chip */
+
+	__raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
+		(6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
+		(4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
+		(1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
+		(13 << S3C64XX_SROM_BCX__TACC__SHIFT) |
+		(4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
+		(0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
+
+	gpio_request(S3C64XX_GPF(15), "LCD power");
+	gpio_request(S3C64XX_GPE(0), "LCD power");
+
+	platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));
+}
+
+MACHINE_START(MINI6410, "MINI6410")
+	/* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
+	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
+	.init_irq	= s3c6410_init_irq,
+	.map_io		= mini6410_map_io,
+	.init_machine	= mini6410_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-ncp.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-ncp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-ncp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-ncp.c	2011-01-04 19:50:19.000000000 -0500
@@ -97,8 +97,6 @@
 
 MACHINE_START(NCP, "NCP")
 	/* Maintainer: Samsung Electronics */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 	.init_irq	= s3c6410_init_irq,
 	.map_io		= ncp_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-real6410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-real6410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-real6410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-real6410.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,25 +12,41 @@
  *
 */
 
-#include <linux/kernel.h>
-#include <linux/types.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/init.h>
 #include <linux/dm9000.h>
-#include <linux/serial_core.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
 #include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+
 #include <mach/map.h>
-#include <mach/s3c6410.h>
+#include <mach/regs-fb.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-modem.h>
 #include <mach/regs-srom.h>
+#include <mach/s3c6410.h>
+
+#include <plat/adc.h>
 #include <plat/cpu.h>
 #include <plat/devs.h>
+#include <plat/fb.h>
+#include <plat/nand.h>
 #include <plat/regs-serial.h>
+#include <plat/ts.h>
 
-#define UCON (S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK)
+#include <video/platform_lcd.h>
+
+#define UCON S3C2410_UCON_DEFAULT
 #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB)
 #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE)
 
@@ -99,22 +115,192 @@
 	},
 };
 
+static struct s3c_fb_pd_win real6410_fb_win[] = {
+	{
+		.win_mode	= {	/* 4.3" 480x272 */
+			.left_margin	= 3,
+			.right_margin	= 2,
+			.upper_margin	= 1,
+			.lower_margin	= 1,
+			.hsync_len	= 40,
+			.vsync_len	= 1,
+			.xres		= 480,
+			.yres		= 272,
+		},
+		.max_bpp	= 32,
+		.default_bpp	= 16,
+	}, {
+		.win_mode	= {	/* 7.0" 800x480 */
+			.left_margin	= 8,
+			.right_margin	= 13,
+			.upper_margin	= 7,
+			.lower_margin	= 5,
+			.hsync_len	= 3,
+			.vsync_len	= 1,
+			.xres		= 800,
+			.yres		= 480,
+		},
+		.max_bpp	= 32,
+		.default_bpp	= 16,
+	},
+};
+
+static struct s3c_fb_platdata real6410_lcd_pdata __initdata = {
+	.setup_gpio	= s3c64xx_fb_gpio_setup_24bpp,
+	.win[0]		= &real6410_fb_win[0],
+	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+static struct mtd_partition real6410_nand_part[] = {
+	[0] = {
+		.name	= "uboot",
+		.size	= SZ_1M,
+		.offset	= 0,
+	},
+	[1] = {
+		.name	= "kernel",
+		.size	= SZ_2M,
+		.offset	= SZ_1M,
+	},
+	[2] = {
+		.name	= "rootfs",
+		.size	= MTDPART_SIZ_FULL,
+		.offset	= SZ_1M + SZ_2M,
+	},
+};
+
+static struct s3c2410_nand_set real6410_nand_sets[] = {
+	[0] = {
+		.name		= "nand",
+		.nr_chips	= 1,
+		.nr_partitions	= ARRAY_SIZE(real6410_nand_part),
+		.partitions	= real6410_nand_part,
+	},
+};
+
+static struct s3c2410_platform_nand real6410_nand_info = {
+	.tacls		= 25,
+	.twrph0		= 55,
+	.twrph1		= 40,
+	.nr_sets	= ARRAY_SIZE(real6410_nand_sets),
+	.sets		= real6410_nand_sets,
+};
+
 static struct platform_device *real6410_devices[] __initdata = {
 	&real6410_device_eth,
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc1,
+	&s3c_device_fb,
+	&s3c_device_nand,
+	&s3c_device_adc,
+	&s3c_device_ts,
+	&s3c_device_ohci,
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+	.delay			= 10000,
+	.presc			= 49,
+	.oversampling_shift	= 2,
 };
 
 static void __init real6410_map_io(void)
 {
+	u32 tmp;
+
 	s3c64xx_init_io(NULL, 0);
 	s3c24xx_init_clocks(12000000);
 	s3c24xx_init_uarts(real6410_uartcfgs, ARRAY_SIZE(real6410_uartcfgs));
+
+	/* set the LCD type */
+	tmp = __raw_readl(S3C64XX_SPCON);
+	tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK;
+	tmp |= S3C64XX_SPCON_LCD_SEL_RGB;
+	__raw_writel(tmp, S3C64XX_SPCON);
+
+	/* remove the LCD bypass */
+	tmp = __raw_readl(S3C64XX_MODEM_MIFPCON);
+	tmp &= ~MIFPCON_LCD_BYPASS;
+	__raw_writel(tmp, S3C64XX_MODEM_MIFPCON);
+}
+
+/*
+ * real6410_features string
+ *
+ * 0-9 LCD configuration
+ *
+ */
+static char real6410_features_str[12] __initdata = "0";
+
+static int __init real6410_features_setup(char *str)
+{
+	if (str)
+		strlcpy(real6410_features_str, str,
+			sizeof(real6410_features_str));
+	return 1;
+}
+
+__setup("real6410=", real6410_features_setup);
+
+#define FEATURE_SCREEN (1 << 0)
+
+struct real6410_features_t {
+	int done;
+	int lcd_index;
+};
+
+static void real6410_parse_features(
+		struct real6410_features_t *features,
+		const char *features_str)
+{
+	const char *fp = features_str;
+
+	features->done = 0;
+	features->lcd_index = 0;
+
+	while (*fp) {
+		char f = *fp++;
+
+		switch (f) {
+		case '0'...'9':	/* tft screen */
+			if (features->done & FEATURE_SCREEN) {
+				printk(KERN_INFO "REAL6410: '%c' ignored, "
+					"screen type already set\n", f);
+			} else {
+				int li = f - '0';
+				if (li >= ARRAY_SIZE(real6410_fb_win))
+					printk(KERN_INFO "REAL6410: '%c' out "
+						"of range LCD mode\n", f);
+				else {
+					features->lcd_index = li;
+				}
+			}
+			features->done |= FEATURE_SCREEN;
+			break;
+		}
+	}
 }
 
 static void __init real6410_machine_init(void)
 {
 	u32 cs1;
+	struct real6410_features_t features = { 0 };
+
+	printk(KERN_INFO "REAL6410: Option string real6410=%s\n",
+			real6410_features_str);
+
+	/* Parse the feature string */
+	real6410_parse_features(&features, real6410_features_str);
+
+	real6410_lcd_pdata.win[0] = &real6410_fb_win[features.lcd_index];
+
+	printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n",
+		real6410_lcd_pdata.win[0]->win_mode.xres,
+		real6410_lcd_pdata.win[0]->win_mode.yres);
+
+	s3c_fb_set_platdata(&real6410_lcd_pdata);
+	s3c_nand_set_platdata(&real6410_nand_info);
+	s3c24xx_ts_set_platdata(&s3c_ts_platform);
 
 	/* configure nCS1 width to 16 bits */
 
@@ -136,13 +322,13 @@
 		(4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
 		(0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
 
+	gpio_request(S3C64XX_GPF(15), "LCD power");
+
 	platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices));
 }
 
 MACHINE_START(REAL6410, "REAL6410")
 	/* Maintainer: Darius Augulis <augulis.darius@gmail.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 
 	.init_irq	= s3c6410_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq5.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq5.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq5.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq5.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq5_leds[] __initdata = {
+static struct gpio_led smartq5_leds[] = {
 	{
 		.name			= "smartq5:green",
 		.active_low		= 1,
@@ -146,8 +146,6 @@
 
 MACHINE_START(SMARTQ5, "SmartQ 5")
 	/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 	.init_irq	= s3c6410_init_irq,
 	.map_io		= smartq_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq7.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq7.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq7.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq7.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq7_leds[] __initdata = {
+static struct gpio_led smartq7_leds[] = {
 	{
 		.name			= "smartq7:red",
 		.active_low		= 1,
@@ -162,8 +162,6 @@
 
 MACHINE_START(SMARTQ7, "SmartQ 7")
 	/* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 	.init_irq	= s3c6410_init_irq,
 	.map_io		= smartq_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smartq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smartq.c	2011-01-04 19:50:19.000000000 -0500
@@ -136,7 +136,7 @@
 	.dev.platform_data	= &smartq_usb_otg_vbus_pdata,
 };
 
-static int __init smartq_bl_init(struct device *dev)
+static int smartq_bl_init(struct device *dev)
 {
     s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smdk6400.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smdk6400.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smdk6400.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smdk6400.c	2011-01-04 19:50:19.000000000 -0500
@@ -85,8 +85,6 @@
 
 MACHINE_START(SMDK6400, "SMDK6400")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 
 	.init_irq	= s3c6400_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smdk6410.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smdk6410.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/mach-smdk6410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/mach-smdk6410.c	2011-01-04 19:50:19.000000000 -0500
@@ -283,6 +283,7 @@
 	&s3c_device_fb,
 	&s3c_device_ohci,
 	&s3c_device_usb_hsotg,
+	&s3c_device_pcm,
 	&s3c64xx_device_iisv4,
 	&samsung_device_keypad,
 
@@ -704,8 +705,6 @@
 
 MACHINE_START(SMDK6410, "SMDK6410")
 	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S3C64XX_PA_SDRAM + 0x100,
 
 	.init_irq	= s3c6410_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -53,6 +53,7 @@
 obj-$(CONFIG_MACH_SMDK6400)	+= mach-smdk6400.o
 obj-$(CONFIG_MACH_SMDK6410)	+= mach-smdk6410.o
 obj-$(CONFIG_MACH_REAL6410)     += mach-real6410.o
+obj-$(CONFIG_MACH_MINI6410)     += mach-mini6410.o
 obj-$(CONFIG_MACH_NCP)		+= mach-ncp.o
 obj-$(CONFIG_MACH_HMT)		+= mach-hmt.o
 obj-$(CONFIG_MACH_SMARTQ)	+= mach-smartq.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-fb-24bpp.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-fb-24bpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-fb-24bpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-fb-24bpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,15 +23,6 @@
 
 extern void s3c64xx_fb_gpio_setup_24bpp(void)
 {
-	unsigned int gpio;
-
-	for (gpio = S3C64XX_GPI(0); gpio <= S3C64XX_GPI(15); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	for (gpio = S3C64XX_GPJ(0); gpio <= S3C64XX_GPJ(11); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPI(0), 16, S3C_GPIO_SFN(2));
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPJ(0), 12, S3C_GPIO_SFN(2));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-ide.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-ide.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-ide.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-ide.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,11 +17,11 @@
 #include <mach/map.h>
 #include <mach/regs-clock.h>
 #include <plat/gpio-cfg.h>
+#include <plat/ata.h>
 
 void s3c64xx_ide_setup_gpio(void)
 {
 	u32 reg;
-	u32 gpio = 0;
 
 	reg = readl(S3C_MEM_SYS_CFG) & (~0x3f);
 
@@ -32,15 +32,12 @@
 	s3c_gpio_cfgpin(S3C64XX_GPB(4), S3C_GPIO_SFN(4));
 
 	/* Set XhiDATA[15:0] pins as CF Data[15:0] */
-	for (gpio = S3C64XX_GPK(0); gpio <= S3C64XX_GPK(15); gpio++)
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(5));
+	s3c_gpio_cfgpin_range(S3C64XX_GPK(0), 16, S3C_GPIO_SFN(5));
 
 	/* Set XhiADDR[2:0] pins as CF ADDR[2:0] */
-	for (gpio = S3C64XX_GPL(0); gpio <= S3C64XX_GPL(2); gpio++)
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6));
+	s3c_gpio_cfgpin_range(S3C64XX_GPL(0), 3, S3C_GPIO_SFN(6));
 
 	/* Set Xhi ctrl pins as CF ctrl pins(IORDY, IOWR, IORD, CE[0:1]) */
 	s3c_gpio_cfgpin(S3C64XX_GPM(5), S3C_GPIO_SFN(1));
-	for (gpio = S3C64XX_GPM(0); gpio <= S3C64XX_GPM(4); gpio++)
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(6));
+	s3c_gpio_cfgpin_range(S3C64XX_GPM(0), 5, S3C_GPIO_SFN(6));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-keypad.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-keypad.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-keypad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-keypad.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,23 +12,13 @@
 
 #include <linux/gpio.h>
 #include <plat/gpio-cfg.h>
+#include <plat/keypad.h>
 
 void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
 {
-	unsigned int gpio;
-	unsigned int end;
-
 	/* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */
-	end = S3C64XX_GPK(8 + rows);
-	for (gpio = S3C64XX_GPK(8); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPK(8), 8 + rows, S3C_GPIO_SFN(3));
 
 	/* Set all the necessary GPL pins to special-function 3: KP_COL[x] */
-	end = S3C64XX_GPL(0 + cols);
-	for (gpio = S3C64XX_GPL(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPL(0), cols, S3C_GPIO_SFN(3));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s3c64xx/setup-sdhci-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,16 +24,9 @@
 void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S3C64XX_GPG(2 + width);
 
-	/* Set all the necessary GPG pins to special-function 0 */
-	for (gpio = S3C64XX_GPG(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	/* Set all the necessary GPG pins to special-function 2 */
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPG(0), 2 + width, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
@@ -44,16 +37,9 @@
 void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
-	unsigned int end;
 
-	end = S3C64XX_GPH(2 + width);
-
-	/* Set all the necessary GPG pins to special-function 0 */
-	for (gpio = S3C64XX_GPH(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	/* Set all the necessary GPH pins to special-function 2 */
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPH(0), 2 + width, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP);
@@ -63,20 +49,9 @@
 
 void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
 {
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S3C64XX_GPH(6 + width);
-
-	/* Set all the necessary GPH pins to special-function 1 */
-	for (gpio = S3C64XX_GPH(6); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	/* Set all the necessary GPH pins to special-function 3 */
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPH(6), width, S3C_GPIO_SFN(3));
 
-	/* Set all the necessary GPC pins to special-function 1 */
-	for (gpio = S3C64XX_GPC(4); gpio < S3C64XX_GPC(6); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	/* Set all the necessary GPC pins to special-function 3 */
+	s3c_gpio_cfgrange_nopull(S3C64XX_GPC(4), 2, S3C_GPIO_SFN(3));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/clock.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,846 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/clock.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Clock support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/sysdev.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/cpu-freq.h>
-#include <mach/regs-clock.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/clock-clksrc.h>
-#include <plat/s5p-clock.h>
-#include <plat/pll.h>
-#include <plat/s5p6440.h>
-
-/* APLL Mux output clock */
-static struct clksrc_clk clk_mout_apll = {
-	.clk    = {
-		.name           = "mout_apll",
-		.id             = -1,
-	},
-	.sources        = &clk_src_apll,
-	.reg_src        = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
-};
-
-static int s5p6440_epll_enable(struct clk *clk, int enable)
-{
-	unsigned int ctrlbit = clk->ctrlbit;
-	unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
-
-	if (enable)
-		__raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
-	else
-		__raw_writel(epll_con, S5P_EPLL_CON);
-
-	return 0;
-}
-
-static unsigned long s5p6440_epll_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-
-static u32 epll_div[][5] = {
-	{ 36000000,	0,	48, 1, 4 },
-	{ 48000000,	0,	32, 1, 3 },
-	{ 60000000,	0,	40, 1, 3 },
-	{ 72000000,	0,	48, 1, 3 },
-	{ 84000000,	0,	28, 1, 2 },
-	{ 96000000,	0,	32, 1, 2 },
-	{ 32768000,	45264,	43, 1, 4 },
-	{ 45158000,	6903,	30, 1, 3 },
-	{ 49152000,	50332,	32, 1, 3 },
-	{ 67738000,	10398,	45, 1, 3 },
-	{ 73728000,	9961,	49, 1, 3 }
-};
-
-static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-	unsigned int epll_con, epll_con_k;
-	unsigned int i;
-
-	if (clk->rate == rate)	/* Return if nothing changed */
-		return 0;
-
-	epll_con = __raw_readl(S5P_EPLL_CON);
-	epll_con_k = __raw_readl(S5P_EPLL_CON_K);
-
-	epll_con_k &= ~(PLL90XX_KDIV_MASK);
-	epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
-
-	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-		 if (epll_div[i][0] == rate) {
-			epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
-			epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
-				    (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
-				    (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
-			break;
-		}
-	}
-
-	if (i == ARRAY_SIZE(epll_div)) {
-		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
-		return -EINVAL;
-	}
-
-	__raw_writel(epll_con, S5P_EPLL_CON);
-	__raw_writel(epll_con_k, S5P_EPLL_CON_K);
-
-	clk->rate = rate;
-
-	return 0;
-}
-
-static struct clk_ops s5p6440_epll_ops = {
-	.get_rate = s5p6440_epll_get_rate,
-	.set_rate = s5p6440_epll_set_rate,
-};
-
-static struct clksrc_clk clk_mout_epll = {
-	.clk    = {
-		.name           = "mout_epll",
-		.id             = -1,
-	},
-	.sources        = &clk_src_epll,
-	.reg_src        = { .reg = S5P_CLK_SRC0, .shift = 2, .size = 1 },
-};
-
-static struct clksrc_clk clk_mout_mpll = {
-	.clk = {
-		.name           = "mout_mpll",
-		.id             = -1,
-	},
-	.sources        = &clk_src_mpll,
-	.reg_src        = { .reg = S5P_CLK_SRC0, .shift = 1, .size = 1 },
-};
-
-enum perf_level {
-	L0 = 532*1000,
-	L1 = 266*1000,
-	L2 = 133*1000,
-};
-
-static const u32 clock_table[][3] = {
-	/*{ARM_CLK, DIVarm, DIVhclk}*/
-	{L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P_CLKDIV0_HCLK_SHIFT)},
-	{L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P_CLKDIV0_HCLK_SHIFT)},
-	{L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P_CLKDIV0_HCLK_SHIFT)},
-};
-
-static unsigned long s5p6440_armclk_get_rate(struct clk *clk)
-{
-	unsigned long rate = clk_get_rate(clk->parent);
-	u32 clkdiv;
-
-	/* divisor mask starts at bit0, so no need to shift */
-	clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK;
-
-	return rate / (clkdiv + 1);
-}
-
-static unsigned long s5p6440_armclk_round_rate(struct clk *clk,
-						unsigned long rate)
-{
-	u32 iter;
-
-	for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
-		if (rate > clock_table[iter][0])
-			return clock_table[iter-1][0];
-	}
-
-	return clock_table[ARRAY_SIZE(clock_table) - 1][0];
-}
-
-static int s5p6440_armclk_set_rate(struct clk *clk, unsigned long rate)
-{
-	u32 round_tmp;
-	u32 iter;
-	u32 clk_div0_tmp;
-	u32 cur_rate = clk->ops->get_rate(clk);
-	unsigned long flags;
-
-	round_tmp = clk->ops->round_rate(clk, rate);
-	if (round_tmp == cur_rate)
-		return 0;
-
-
-	for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
-		if (round_tmp == clock_table[iter][0])
-			break;
-	}
-
-	if (iter >= ARRAY_SIZE(clock_table))
-		iter = ARRAY_SIZE(clock_table) - 1;
-
-	local_irq_save(flags);
-	if (cur_rate > round_tmp) {
-		/* Frequency Down */
-		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
-		clk_div0_tmp |= clock_table[iter][1];
-		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
-				~(S5P_CLKDIV0_HCLK_MASK);
-		clk_div0_tmp |= clock_table[iter][2];
-		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-
-	} else {
-		/* Frequency Up */
-		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
-				~(S5P_CLKDIV0_HCLK_MASK);
-		clk_div0_tmp |= clock_table[iter][2];
-		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
-		clk_div0_tmp |= clock_table[iter][1];
-		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-		}
-	local_irq_restore(flags);
-
-	clk->rate = clock_table[iter][0];
-
-	return 0;
-}
-
-static struct clk_ops s5p6440_clkarm_ops = {
-	.get_rate	= s5p6440_armclk_get_rate,
-	.set_rate	= s5p6440_armclk_set_rate,
-	.round_rate	= s5p6440_armclk_round_rate,
-};
-
-static struct clksrc_clk clk_armclk = {
-	.clk	= {
-		.name	= "armclk",
-		.id	= 1,
-		.parent	= &clk_mout_apll.clk,
-		.ops	= &s5p6440_clkarm_ops,
-	},
-	.reg_div	= { .reg = S5P_CLK_DIV0, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mpll = {
-	.clk	= {
-		.name	= "dout_mpll",
-		.id	= -1,
-		.parent	= &clk_mout_mpll.clk,
-	},
-	.reg_div	= { .reg = S5P_CLK_DIV0, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk clk_hclk = {
-	.clk	= {
-		.name	= "clk_hclk",
-		.id	= -1,
-		.parent	= &clk_armclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLK_DIV0, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_pclk = {
-	.clk	= {
-		.name	= "clk_pclk",
-		.id	= -1,
-		.parent	= &clk_hclk.clk,
-	},
-	.reg_div = { .reg = S5P_CLK_DIV0, .shift = 12, .size = 4 },
-};
-
-static struct clk *clkset_hclklow_list[] = {
-	&clk_mout_apll.clk,
-	&clk_mout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_hclklow = {
-	.sources	= clkset_hclklow_list,
-	.nr_sources	= ARRAY_SIZE(clkset_hclklow_list),
-};
-
-static struct clksrc_clk clk_hclk_low = {
-	.clk = {
-		.name	= "hclk_low",
-		.id	= -1,
-	},
-	.sources	= &clkset_hclklow,
-	.reg_src	= { .reg = S5P_SYS_OTHERS, .shift = 6, .size = 1 },
-	.reg_div	= { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_pclk_low = {
-	.clk	= {
-		.name	= "pclk_low",
-		.id	= -1,
-		.parent	= &clk_hclk_low.clk,
-	},
-	.reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 },
-};
-
-int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
-{
-	unsigned long flags;
-	u32 val;
-
-	/* can't rely on clock lock, this register has other usages */
-	local_irq_save(flags);
-
-	val = __raw_readl(S5P_OTHERS);
-	if (enable)
-		val |= S5P_OTHERS_USB_SIG_MASK;
-	else
-		val &= ~S5P_OTHERS_USB_SIG_MASK;
-
-	__raw_writel(val, S5P_OTHERS);
-
-	local_irq_restore(flags);
-
-	return 0;
-}
-
-static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
-}
-
-static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
-}
-
-static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
-}
-
-static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
-}
-
-static int s5p6440_sclk1_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_SCLK1, clk, enable);
-}
-
-static int s5p6440_mem_ctrl(struct clk *clk, int enable)
-{
-	return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable);
-}
-
-/*
- * The following clocks will be disabled during clock initialization. It is
- * recommended to keep the following clocks disabled until the driver requests
- * for enabling the clock.
- */
-static struct clk init_clocks_disable[] = {
-	{
-		.name		= "nand",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_mem_ctrl,
-		.ctrlbit	= S5P_CLKCON_MEM0_HCLK_NFCON,
-	}, {
-		.name		= "adc",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_TSADC,
-	}, {
-		.name		= "i2c",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_IIC0,
-	}, {
-		.name		= "i2s_v40",
-		.id		= 0,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_IIS2,
-	}, {
-		.name		= "spi",
-		.id		= 0,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_SPI0,
-	}, {
-		.name		= "spi",
-		.id		= 1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_SPI1,
-	}, {
-		.name		= "sclk_spi_48",
-		.id		= 0,
-		.parent		= &clk_48m,
-		.enable		= s5p6440_sclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_SCLK0_SPI0_48,
-	}, {
-		.name		= "sclk_spi_48",
-		.id		= 1,
-		.parent		= &clk_48m,
-		.enable		= s5p6440_sclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_SCLK0_SPI1_48,
-	}, {
-		.name		= "mmc_48m",
-		.id		= 0,
-		.parent		= &clk_48m,
-		.enable		= s5p6440_sclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_SCLK0_MMC0_48,
-	}, {
-		.name		= "mmc_48m",
-		.id		= 1,
-		.parent		= &clk_48m,
-		.enable		= s5p6440_sclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_SCLK0_MMC1_48,
-	}, {
-		.name		= "mmc_48m",
-		.id		= 2,
-		.parent		= &clk_48m,
-		.enable		= s5p6440_sclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_SCLK0_MMC2_48,
-	}, {
-		.name    	= "otg",
-		.id	   	= -1,
-		.parent		= &clk_hclk_low.clk,
-		.enable  	= s5p6440_hclk0_ctrl,
-		.ctrlbit 	= S5P_CLKCON_HCLK0_USB
-	}, {
-		.name    	= "post",
-		.id	   	= -1,
-		.parent		= &clk_hclk_low.clk,
-		.enable  	= s5p6440_hclk0_ctrl,
-		.ctrlbit 	= S5P_CLKCON_HCLK0_POST0
-	}, {
-		.name		= "lcd",
-		.id		= -1,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk1_ctrl,
-		.ctrlbit	= S5P_CLKCON_HCLK1_DISPCON,
-	}, {
-		.name		= "hsmmc",
-		.id		= 0,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC0,
-	}, {
-		.name		= "hsmmc",
-		.id		= 1,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC1,
-	}, {
-		.name		= "hsmmc",
-		.id		= 2,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= S5P_CLKCON_HCLK0_HSMMC2,
-	}, {
-		.name		= "rtc",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_RTC,
-	}, {
-		.name		= "watchdog",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_WDT,
-	}, {
-		.name		= "timers",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_PWM,
-	}, {
-		.name		= "hclk_fimgvg",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_hclk1_ctrl,
-		.ctrlbit	= (1 << 2),
-	}, {
-		.name		= "tsi",
-		.id		= -1,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk1_ctrl,
-		.ctrlbit	= (1 << 0),
-	}, {
-		.name		= "pclk_fimgvg",
-		.id		= -1,
-		.parent		= &clk_pclk.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 31),
-	}, {
-		.name		= "dmc0",
-		.id		= -1,
-		.parent		= &clk_pclk.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 30),
-	}, {
-		.name		= "etm",
-		.id		= -1,
-		.parent		= &clk_pclk.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 29),
-	}, {
-		.name		= "dsim",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 28),
-	}, {
-		.name		= "gps",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 25),
-	}, {
-		.name		= "pcm",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= (1 << 8),
-	}, {
-		.name		= "irom",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= (1 << 25),
-	}, {
-		.name		= "dma",
-		.id		= -1,
-		.parent		= &clk_hclk_low.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= (1 << 12),
-	}, {
-		.name		= "2d",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= (1 << 8),
-	},
-};
-
-/*
- * The following clocks will be enabled during clock initialization.
- */
-static struct clk init_clocks[] = {
-	{
-		.name		= "gpio",
-		.id		= -1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_GPIO,
-	}, {
-		.name		= "uart",
-		.id		= 0,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_UART0,
-	}, {
-		.name		= "uart",
-		.id		= 1,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_UART1,
-	}, {
-		.name		= "uart",
-		.id		= 2,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_UART2,
-	}, {
-		.name		= "uart",
-		.id		= 3,
-		.parent		= &clk_pclk_low.clk,
-		.enable		= s5p6440_pclk_ctrl,
-		.ctrlbit	= S5P_CLKCON_PCLK_UART3,
-	}, {
-		.name		= "mem",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= (1 << 21),
-	}, {
-		.name		= "intc",
-		.id		= -1,
-		.parent		= &clk_hclk.clk,
-		.enable		= s5p6440_hclk0_ctrl,
-		.ctrlbit	= (1 << 1),
-	},
-};
-
-static struct clk clk_iis_cd_v40 = {
-	.name		= "iis_cdclk_v40",
-	.id		= -1,
-};
-
-static struct clk clk_pcm_cd = {
-	.name		= "pcm_cdclk",
-	.id		= -1,
-};
-
-static struct clk *clkset_group1_list[] = {
-	&clk_mout_epll.clk,
-	&clk_dout_mpll.clk,
-	&clk_fin_epll,
-};
-
-static struct clksrc_sources clkset_group1 = {
-	.sources	= clkset_group1_list,
-	.nr_sources	= ARRAY_SIZE(clkset_group1_list),
-};
-
-static struct clk *clkset_uart_list[] = {
-	&clk_mout_epll.clk,
-	&clk_dout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_uart = {
-	.sources	= clkset_uart_list,
-	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
-};
-
-static struct clk *clkset_audio_list[] = {
-	&clk_mout_epll.clk,
-	&clk_dout_mpll.clk,
-	&clk_fin_epll,
-	&clk_iis_cd_v40,
-	&clk_pcm_cd,
-};
-
-static struct clksrc_sources clkset_audio = {
-	.sources	= clkset_audio_list,
-	.nr_sources	= ARRAY_SIZE(clkset_audio_list),
-};
-
-static struct clksrc_clk clksrcs[] = {
-	{
-		.clk	= {
-			.name		= "mmc_bus",
-			.id		= 0,
-			.ctrlbit        = S5P_CLKCON_SCLK0_MMC0,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "mmc_bus",
-			.id		= 1,
-			.ctrlbit        = S5P_CLKCON_SCLK0_MMC1,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "mmc_bus",
-			.id		= 2,
-			.ctrlbit        = S5P_CLKCON_SCLK0_MMC2,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "uclk1",
-			.id		= -1,
-			.ctrlbit        = S5P_CLKCON_SCLK0_UART,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_uart,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 },
-		.reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "spi_epll",
-			.id		= 0,
-			.ctrlbit        = S5P_CLKCON_SCLK0_SPI0,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "spi_epll",
-			.id		= 1,
-			.ctrlbit        = S5P_CLKCON_SCLK0_SPI1,
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_post",
-			.id		= -1,
-			.ctrlbit	= (1 << 10),
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC0, .shift = 26, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_dispcon",
-			.id		= -1,
-			.ctrlbit	= (1 << 1),
-			.enable		= s5p6440_sclk1_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_fimgvg",
-			.id		= -1,
-			.ctrlbit	= (1 << 2),
-			.enable		= s5p6440_sclk1_ctrl,
-		},
-		.sources = &clkset_group1,
-		.reg_src = { .reg = S5P_CLK_SRC1, .shift = 8, .size = 2 },
-		.reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_audio2",
-			.id		= -1,
-			.ctrlbit	= (1 << 11),
-			.enable		= s5p6440_sclk_ctrl,
-		},
-		.sources = &clkset_audio,
-		.reg_src = { .reg = S5P_CLK_SRC1, .shift = 0, .size = 3 },
-		.reg_div = { .reg = S5P_CLK_DIV2, .shift = 24, .size = 4 },
-	},
-};
-
-/* Clock initialisation code */
-static struct clksrc_clk *sysclks[] = {
-	&clk_mout_apll,
-	&clk_mout_epll,
-	&clk_mout_mpll,
-	&clk_dout_mpll,
-	&clk_armclk,
-	&clk_hclk,
-	&clk_pclk,
-	&clk_hclk_low,
-	&clk_pclk_low,
-};
-
-void __init_or_cpufreq s5p6440_setup_clocks(void)
-{
-	struct clk *xtal_clk;
-	unsigned long xtal;
-	unsigned long fclk;
-	unsigned long hclk;
-	unsigned long hclk_low;
-	unsigned long pclk;
-	unsigned long pclk_low;
-	unsigned long epll;
-	unsigned long apll;
-	unsigned long mpll;
-	unsigned int ptr;
-
-	/* Set S5P6440 functions for clk_fout_epll */
-	clk_fout_epll.enable = s5p6440_epll_enable;
-	clk_fout_epll.ops = &s5p6440_epll_ops;
-
-	clk_48m.enable = s5p6440_clk48m_ctrl;
-
-	xtal_clk = clk_get(NULL, "ext_xtal");
-	BUG_ON(IS_ERR(xtal_clk));
-
-	xtal = clk_get_rate(xtal_clk);
-	clk_put(xtal_clk);
-
-	epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON),
-				__raw_readl(S5P_EPLL_CON_K));
-	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
-	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502);
-
-	clk_fout_mpll.rate = mpll;
-	clk_fout_epll.rate = epll;
-	clk_fout_apll.rate = apll;
-
-	printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
-			" E=%ld.%ldMHz\n",
-			print_mhz(apll), print_mhz(mpll), print_mhz(epll));
-
-	fclk = clk_get_rate(&clk_armclk.clk);
-	hclk = clk_get_rate(&clk_hclk.clk);
-	pclk = clk_get_rate(&clk_pclk.clk);
-	hclk_low = clk_get_rate(&clk_hclk_low.clk);
-	pclk_low = clk_get_rate(&clk_pclk_low.clk);
-
-	printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
-			" PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
-			print_mhz(hclk), print_mhz(hclk_low),
-			print_mhz(pclk), print_mhz(pclk_low));
-
-	clk_f.rate = fclk;
-	clk_h.rate = hclk;
-	clk_p.rate = pclk;
-
-	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-		s3c_set_clksrc(&clksrcs[ptr], true);
-}
-
-static struct clk *clks[] __initdata = {
-	&clk_ext,
-	&clk_iis_cd_v40,
-	&clk_pcm_cd,
-};
-
-void __init s5p6440_register_clocks(void)
-{
-	struct clk *clkp;
-	int ret;
-	int ptr;
-
-	ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-	if (ret > 0)
-		printk(KERN_ERR "Failed to register %u clocks\n", ret);
-
-	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
-		s3c_register_clksrc(sysclks[ptr], 1);
-
-	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
-	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-	clkp = init_clocks_disable;
-	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
-		ret = s3c24xx_register_clock(clkp);
-		if (ret < 0) {
-			printk(KERN_ERR "Failed to register clock %s (%d)\n",
-			       clkp->name, ret);
-		}
-		(clkp->enable)(clkp, 0);
-	}
-
-	s3c_pwmclk_init();
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/cpu.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,117 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/cpu.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/sysdev.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/proc-fns.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-#include <asm/irq.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-clock.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/s5p6440.h>
-#include <plat/adc-core.h>
-
-static void s5p6440_idle(void)
-{
-	unsigned long val;
-
-	if (!need_resched()) {
-		val = __raw_readl(S5P_PWR_CFG);
-		val &= ~(0x3<<5);
-		val |= (0x1<<5);
-		__raw_writel(val, S5P_PWR_CFG);
-
-		cpu_do_idle();
-	}
-	local_irq_enable();
-}
-
-/* s5p6440_map_io
- *
- * register the standard cpu IO areas
-*/
-
-void __init s5p6440_map_io(void)
-{
-	/* initialize any device information early */
-	s3c_adc_setname("s3c64xx-adc");
-}
-
-void __init s5p6440_init_clocks(int xtal)
-{
-	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
-	s3c24xx_register_baseclocks(xtal);
-	s5p_register_clocks(xtal);
-	s5p6440_register_clocks();
-	s5p6440_setup_clocks();
-}
-
-void __init s5p6440_init_irq(void)
-{
-	/* S5P6440 supports only 2 VIC */
-	u32 vic[2];
-
-	/*
-	 * VIC0 is missing IRQ_VIC0[3, 4, 8, 10, (12-22)]
-	 * VIC1 is missing IRQ VIC1[1, 3, 4, 10, 11, 12, 14, 15, 22]
-	 */
-	vic[0] = 0xff800ae7;
-	vic[1] = 0xffbf23e5;
-
-	s5p_init_irq(vic, ARRAY_SIZE(vic));
-}
-
-struct sysdev_class s5p6440_sysclass = {
-	.name	= "s5p6440-core",
-};
-
-static struct sys_device s5p6440_sysdev = {
-	.cls	= &s5p6440_sysclass,
-};
-
-static int __init s5p6440_core_init(void)
-{
-	return sysdev_class_register(&s5p6440_sysclass);
-}
-
-core_initcall(s5p6440_core_init);
-
-int __init s5p6440_init(void)
-{
-	printk(KERN_INFO "S5P6440: Initializing architecture\n");
-
-	/* set idle function */
-	pm_idle = s5p6440_idle;
-
-	return sysdev_register(&s5p6440_sysdev);
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dev-audio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dev-audio.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,127 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/dev-audio.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-#include <mach/irqs.h>
-
-static int s5p6440_cfg_i2s(struct platform_device *pdev)
-{
-	/* configure GPIO for i2s port */
-	switch (pdev->id) {
-	case -1:
-		s3c_gpio_cfgpin(S5P6440_GPR(4), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(5), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(5));
-		break;
-
-	default:
-		printk(KERN_ERR "Invalid Device %d\n", pdev->id);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct s3c_audio_pdata s3c_i2s_pdata = {
-	.cfg_gpio = s5p6440_cfg_i2s,
-};
-
-static struct resource s5p6440_iis0_resource[] = {
-	[0] = {
-		.start = S5P6440_PA_I2S,
-		.end   = S5P6440_PA_I2S + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_I2S0_TX,
-		.end   = DMACH_I2S0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_I2S0_RX,
-		.end   = DMACH_I2S0_RX,
-		.flags = IORESOURCE_DMA,
-	},
-};
-
-struct platform_device s5p6440_device_iis = {
-	.name		  = "s3c64xx-iis-v4",
-	.id		  = -1,
-	.num_resources	  = ARRAY_SIZE(s5p6440_iis0_resource),
-	.resource	  = s5p6440_iis0_resource,
-	.dev = {
-		.platform_data = &s3c_i2s_pdata,
-	},
-};
-
-/* PCM Controller platform_devices */
-
-static int s5p6440_pcm_cfg_gpio(struct platform_device *pdev)
-{
-	switch (pdev->id) {
-	case 0:
-		s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(2));
-		break;
-
-	default:
-		printk(KERN_DEBUG "Invalid PCM Controller number!");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct s3c_audio_pdata s3c_pcm_pdata = {
-	.cfg_gpio = s5p6440_pcm_cfg_gpio,
-};
-
-static struct resource s5p6440_pcm0_resource[] = {
-	[0] = {
-		.start = S5P6440_PA_PCM,
-		.end   = S5P6440_PA_PCM + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_PCM0_TX,
-		.end   = DMACH_PCM0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_PCM0_RX,
-		.end   = DMACH_PCM0_RX,
-		.flags = IORESOURCE_DMA,
-	},
-};
-
-struct platform_device s5p6440_device_pcm = {
-	.name		  = "samsung-pcm",
-	.id		  = 0,
-	.num_resources	  = ARRAY_SIZE(s5p6440_pcm0_resource),
-	.resource	  = s5p6440_pcm0_resource,
-	.dev = {
-		.platform_data = &s3c_pcm_pdata,
-	},
-};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dev-spi.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dev-spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dev-spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dev-spi.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,176 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/dev-spi.c
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <mach/dma.h>
-#include <mach/map.h>
-#include <mach/irqs.h>
-#include <mach/spi-clocks.h>
-
-#include <plat/s3c64xx-spi.h>
-#include <plat/gpio-cfg.h>
-
-static char *spi_src_clks[] = {
-	[S5P6440_SPI_SRCCLK_PCLK] = "pclk",
-	[S5P6440_SPI_SRCCLK_SCLK] = "spi_epll",
-};
-
-/* SPI Controller platform_devices */
-
-/* Since we emulate multi-cs capability, we do not touch the CS.
- * The emulated CS is toggled by board specific mechanism, as it can
- * be either some immediate GPIO or some signal out of some other
- * chip in between ... or some yet another way.
- * We simply do not assume anything about CS.
- */
-static int s5p6440_spi_cfg_gpio(struct platform_device *pdev)
-{
-	switch (pdev->id) {
-	case 0:
-		s3c_gpio_cfgpin(S5P6440_GPC(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPC(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPC(2), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5P6440_GPC(0), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6440_GPC(1), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6440_GPC(2), S3C_GPIO_PULL_UP);
-		break;
-
-	case 1:
-		s3c_gpio_cfgpin(S5P6440_GPC(4), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPC(5), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6440_GPC(6), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5P6440_GPC(4), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6440_GPC(5), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6440_GPC(6), S3C_GPIO_PULL_UP);
-		break;
-
-	default:
-		dev_err(&pdev->dev, "Invalid SPI Controller number!");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static struct resource s5p6440_spi0_resource[] = {
-	[0] = {
-		.start = S5P6440_PA_SPI0,
-		.end   = S5P6440_PA_SPI0 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_SPI0_TX,
-		.end   = DMACH_SPI0_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_SPI0_RX,
-		.end   = DMACH_SPI0_RX,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = IRQ_SPI0,
-		.end   = IRQ_SPI0,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
-	.cfg_gpio = s5p6440_spi_cfg_gpio,
-	.fifo_lvl_mask = 0x1ff,
-	.rx_lvl_offset = 15,
-};
-
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-struct platform_device s5p6440_device_spi0 = {
-	.name		  = "s3c64xx-spi",
-	.id		  = 0,
-	.num_resources	  = ARRAY_SIZE(s5p6440_spi0_resource),
-	.resource	  = s5p6440_spi0_resource,
-	.dev = {
-		.dma_mask		= &spi_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-		.platform_data = &s5p6440_spi0_pdata,
-	},
-};
-
-static struct resource s5p6440_spi1_resource[] = {
-	[0] = {
-		.start = S5P6440_PA_SPI1,
-		.end   = S5P6440_PA_SPI1 + 0x100 - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start = DMACH_SPI1_TX,
-		.end   = DMACH_SPI1_TX,
-		.flags = IORESOURCE_DMA,
-	},
-	[2] = {
-		.start = DMACH_SPI1_RX,
-		.end   = DMACH_SPI1_RX,
-		.flags = IORESOURCE_DMA,
-	},
-	[3] = {
-		.start = IRQ_SPI1,
-		.end   = IRQ_SPI1,
-		.flags = IORESOURCE_IRQ,
-	},
-};
-
-static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
-	.cfg_gpio = s5p6440_spi_cfg_gpio,
-	.fifo_lvl_mask = 0x7f,
-	.rx_lvl_offset = 15,
-};
-
-struct platform_device s5p6440_device_spi1 = {
-	.name		  = "s3c64xx-spi",
-	.id		  = 1,
-	.num_resources	  = ARRAY_SIZE(s5p6440_spi1_resource),
-	.resource	  = s5p6440_spi1_resource,
-	.dev = {
-		.dma_mask		= &spi_dmamask,
-		.coherent_dma_mask	= DMA_BIT_MASK(32),
-		.platform_data = &s5p6440_spi1_pdata,
-	},
-};
-
-void __init s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
-{
-	struct s3c64xx_spi_info *pd;
-
-	/* Reject invalid configuration */
-	if (!num_cs || src_clk_nr < 0
-			|| src_clk_nr > S5P6440_SPI_SRCCLK_SCLK) {
-		printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
-		return;
-	}
-
-	switch (cntrlr) {
-	case 0:
-		pd = &s5p6440_spi0_pdata;
-		break;
-	case 1:
-		pd = &s5p6440_spi1_pdata;
-		break;
-	default:
-		printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
-							__func__, cntrlr);
-		return;
-	}
-
-	pd->num_cs = num_cs;
-	pd->src_clk_nr = src_clk_nr;
-	pd->src_clk_name = spi_src_clks[src_clk_nr];
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/dma.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-
-#include <plat/devs.h>
-#include <plat/irqs.h>
-
-#include <mach/map.h>
-#include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
-
-static u64 dma_dmamask = DMA_BIT_MASK(32);
-
-static struct resource s5p6440_pdma_resource[] = {
-	[0] = {
-		.start  = S5P6440_PA_PDMA,
-		.end    = S5P6440_PA_PDMA + SZ_4K,
-		.flags = IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= IRQ_DMA0,
-		.end	= IRQ_DMA0,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-static struct s3c_pl330_platdata s5p6440_pdma_pdata = {
-	.peri = {
-		[0] = DMACH_UART0_RX,
-		[1] = DMACH_UART0_TX,
-		[2] = DMACH_UART1_RX,
-		[3] = DMACH_UART1_TX,
-		[4] = DMACH_UART2_RX,
-		[5] = DMACH_UART2_TX,
-		[6] = DMACH_UART3_RX,
-		[7] = DMACH_UART3_TX,
-		[8] = DMACH_MAX,
-		[9] = DMACH_MAX,
-		[10] = DMACH_PCM0_TX,
-		[11] = DMACH_PCM0_RX,
-		[12] = DMACH_I2S0_TX,
-		[13] = DMACH_I2S0_RX,
-		[14] = DMACH_SPI0_TX,
-		[15] = DMACH_SPI0_RX,
-		[16] = DMACH_MAX,
-		[17] = DMACH_MAX,
-		[18] = DMACH_MAX,
-		[19] = DMACH_MAX,
-		[20] = DMACH_SPI1_TX,
-		[21] = DMACH_SPI1_RX,
-		[22] = DMACH_MAX,
-		[23] = DMACH_MAX,
-		[24] = DMACH_MAX,
-		[25] = DMACH_MAX,
-		[26] = DMACH_MAX,
-		[27] = DMACH_MAX,
-		[28] = DMACH_MAX,
-		[29] = DMACH_PWM,
-		[30] = DMACH_MAX,
-		[31] = DMACH_MAX,
-	},
-};
-
-static struct platform_device s5p6440_device_pdma = {
-	.name		= "s3c-pl330",
-	.id		= 1,
-	.num_resources	= ARRAY_SIZE(s5p6440_pdma_resource),
-	.resource	= s5p6440_pdma_resource,
-	.dev		= {
-		.dma_mask = &dma_dmamask,
-		.coherent_dma_mask = DMA_BIT_MASK(32),
-		.platform_data = &s5p6440_pdma_pdata,
-	},
-};
-
-static struct platform_device *s5p6440_dmacs[] __initdata = {
-	&s5p6440_device_pdma,
-};
-
-static int __init s5p6440_dma_init(void)
-{
-	platform_add_devices(s5p6440_dmacs, ARRAY_SIZE(s5p6440_dmacs));
-
-	return 0;
-}
-arch_initcall(s5p6440_dma_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/gpio.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,344 +0,0 @@
-/* arch/arm/mach-s5p6440/gpio.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- * 		http://www.samsung.com/
- *
- * S5P6440 - GPIOlib support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <mach/map.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/gpio-core.h>
-#include <plat/gpio-cfg.h>
-#include <plat/gpio-cfg-helpers.h>
-
-/* GPIO bank summary:
-*
-* Bank	GPIOs	Style	SlpCon	ExtInt Group
-* A	6	4Bit	Yes	1
-* B	7	4Bit	Yes	1
-* C	8	4Bit	Yes	2
-* F	2	2Bit	Yes	4 [1]
-* G	7	4Bit	Yes	5
-* H	10	4Bit[2]	Yes	6
-* I	16	2Bit	Yes	None
-* J	12	2Bit	Yes	None
-* N	16	2Bit	No	IRQ_EINT
-* P	8	2Bit	Yes	8
-* R	15	4Bit[2]	Yes	8
-*
-* [1] BANKF pins 14,15 do not form part of the external interrupt sources
-* [2] BANK has two control registers, GPxCON0 and GPxCON1
-*/
-
-static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
-					     unsigned int offset)
-{
-	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
-	void __iomem *base = ourchip->base;
-	void __iomem *regcon = base;
-	unsigned long con;
-	unsigned long flags;
-
-	switch (offset) {
-	case 6:
-		offset += 1;
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-		regcon -= 4;
-		break;
-	default:
-		offset -= 7;
-		break;
-	}
-
-	s3c_gpio_lock(ourchip, flags);
-
-	con = __raw_readl(regcon);
-	con &= ~(0xf << con_4bit_shift(offset));
-	__raw_writel(con, regcon);
-
-	s3c_gpio_unlock(ourchip, flags);
-
-	return 0;
-}
-
-static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
-					      unsigned int offset, int value)
-{
-	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
-	void __iomem *base = ourchip->base;
-	void __iomem *regcon = base;
-	unsigned long con;
-	unsigned long dat;
-	unsigned long flags;
-	unsigned con_offset  = offset;
-
-	switch (con_offset) {
-	case 6:
-		con_offset += 1;
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-		regcon -= 4;
-		break;
-	default:
-		con_offset -= 7;
-		break;
-	}
-
-	s3c_gpio_lock(ourchip, flags);
-
-	con = __raw_readl(regcon);
-	con &= ~(0xf << con_4bit_shift(con_offset));
-	con |= 0x1 << con_4bit_shift(con_offset);
-
-	dat = __raw_readl(base + GPIODAT_OFF);
-	if (value)
-		dat |= 1 << offset;
-	else
-		dat &= ~(1 << offset);
-
-	__raw_writel(con, regcon);
-	__raw_writel(dat, base + GPIODAT_OFF);
-
-	s3c_gpio_unlock(ourchip, flags);
-
-	return 0;
-}
-
-int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
-				   unsigned int off, unsigned int cfg)
-{
-	void __iomem *reg = chip->base;
-	unsigned int shift;
-	unsigned long flags;
-	u32 con;
-
-	switch (off) {
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-		shift = (off & 7) * 4;
-		reg -= 4;
-		break;
-	case 6:
-		shift = ((off + 1) & 7) * 4;
-		reg -= 4;
-	default:
-		shift = ((off + 1) & 7) * 4;
-		break;
-	}
-
-	if (s3c_gpio_is_cfg_special(cfg)) {
-		cfg &= 0xf;
-		cfg <<= shift;
-	}
-
-	s3c_gpio_lock(chip, flags);
-
-	con = __raw_readl(reg);
-	con &= ~(0xf << shift);
-	con |= cfg;
-	__raw_writel(con, reg);
-
-	s3c_gpio_unlock(chip, flags);
-
-	return 0;
-}
-
-static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
-	{
-		.cfg_eint	= 0,
-	}, {
-		.cfg_eint	= 7,
-	}, {
-		.cfg_eint	= 3,
-		.set_config	= s5p6440_gpio_setcfg_4bit_rbank,
-	}, {
-		.cfg_eint	= 0,
-		.set_config	= s3c_gpio_setcfg_s3c24xx,
-		.get_config	= s3c_gpio_getcfg_s3c24xx,
-	}, {
-		.cfg_eint	= 2,
-		.set_config	= s3c_gpio_setcfg_s3c24xx,
-		.get_config	= s3c_gpio_getcfg_s3c24xx,
-	}, {
-		.cfg_eint	= 3,
-		.set_config	= s3c_gpio_setcfg_s3c24xx,
-		.get_config	= s3c_gpio_getcfg_s3c24xx,
-	},
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
-	{
-		.base	= S5P6440_GPA_BASE,
-		.config	= &s5p6440_gpio_cfgs[1],
-		.chip	= {
-			.base	= S5P6440_GPA(0),
-			.ngpio	= S5P6440_GPIO_A_NR,
-			.label	= "GPA",
-		},
-	}, {
-		.base	= S5P6440_GPB_BASE,
-		.config	= &s5p6440_gpio_cfgs[1],
-		.chip	= {
-			.base	= S5P6440_GPB(0),
-			.ngpio	= S5P6440_GPIO_B_NR,
-			.label	= "GPB",
-		},
-	}, {
-		.base	= S5P6440_GPC_BASE,
-		.config	= &s5p6440_gpio_cfgs[1],
-		.chip	= {
-			.base	= S5P6440_GPC(0),
-			.ngpio	= S5P6440_GPIO_C_NR,
-			.label	= "GPC",
-		},
-	}, {
-		.base	= S5P6440_GPG_BASE,
-		.config	= &s5p6440_gpio_cfgs[1],
-		.chip	= {
-			.base	= S5P6440_GPG(0),
-			.ngpio	= S5P6440_GPIO_G_NR,
-			.label	= "GPG",
-		},
-	},
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
-	{
-		.base	= S5P6440_GPH_BASE + 0x4,
-		.config	= &s5p6440_gpio_cfgs[1],
-		.chip	= {
-			.base	= S5P6440_GPH(0),
-			.ngpio	= S5P6440_GPIO_H_NR,
-			.label	= "GPH",
-		},
-	},
-};
-
-static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
-	{
-		.base	= S5P6440_GPR_BASE + 0x4,
-		.config	= &s5p6440_gpio_cfgs[2],
-		.chip	= {
-			.base	= S5P6440_GPR(0),
-			.ngpio	= S5P6440_GPIO_R_NR,
-			.label	= "GPR",
-		},
-	},
-};
-
-static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
-	{
-		.base	= S5P6440_GPF_BASE,
-		.config	= &s5p6440_gpio_cfgs[5],
-		.chip	= {
-			.base	= S5P6440_GPF(0),
-			.ngpio	= S5P6440_GPIO_F_NR,
-			.label	= "GPF",
-		},
-	}, {
-		.base	= S5P6440_GPI_BASE,
-		.config	= &s5p6440_gpio_cfgs[3],
-		.chip	= {
-			.base	= S5P6440_GPI(0),
-			.ngpio	= S5P6440_GPIO_I_NR,
-			.label	= "GPI",
-		},
-	}, {
-		.base	= S5P6440_GPJ_BASE,
-		.config	= &s5p6440_gpio_cfgs[3],
-		.chip	= {
-			.base	= S5P6440_GPJ(0),
-			.ngpio	= S5P6440_GPIO_J_NR,
-			.label	= "GPJ",
-		},
-	}, {
-		.base	= S5P6440_GPN_BASE,
-		.config	= &s5p6440_gpio_cfgs[4],
-		.chip	= {
-			.base	= S5P6440_GPN(0),
-			.ngpio	= S5P6440_GPIO_N_NR,
-			.label	= "GPN",
-		},
-	}, {
-		.base	= S5P6440_GPP_BASE,
-		.config	= &s5p6440_gpio_cfgs[5],
-		.chip	= {
-			.base	= S5P6440_GPP(0),
-			.ngpio	= S5P6440_GPIO_P_NR,
-			.label	= "GPP",
-		},
-	},
-};
-
-void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
-{
-	for (; nr_chips > 0; nr_chips--, chipcfg++) {
-		if (!chipcfg->set_config)
-			chipcfg->set_config	= s3c_gpio_setcfg_s3c64xx_4bit;
-		if (!chipcfg->get_config)
-			chipcfg->get_config	= s3c_gpio_getcfg_s3c64xx_4bit;
-		if (!chipcfg->set_pull)
-			chipcfg->set_pull	= s3c_gpio_setpull_updown;
-		if (!chipcfg->get_pull)
-			chipcfg->get_pull	= s3c_gpio_getpull_updown;
-	}
-}
-
-static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
-						int nr_chips)
-{
-	for (; nr_chips > 0; nr_chips--, chip++) {
-		chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
-		chip->chip.direction_output =
-					s5p6440_gpiolib_rbank_4bit2_output;
-		s3c_gpiolib_add(chip);
-	}
-}
-
-static int __init s5p6440_gpiolib_init(void)
-{
-	struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
-	int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
-
-	s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
-				ARRAY_SIZE(s5p6440_gpio_cfgs));
-
-	for (; nr_chips > 0; nr_chips--, chips++)
-		s3c_gpiolib_add(chips);
-
-	samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
-				ARRAY_SIZE(s5p6440_gpio_4bit));
-
-	samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
-				ARRAY_SIZE(s5p6440_gpio_4bit2));
-
-	s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
-				ARRAY_SIZE(gpio_rbank_4bit2));
-
-	return 0;
-}
-arch_initcall(s5p6440_gpiolib_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/debug-macro.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,37 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/debug-macro.S
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* pull in the relevant register and map files. */
-
-#include <mach/map.h>
-#include <plat/regs-serial.h>
-
-	/* note, for the boot process to work we have to keep the UART
-	 * virtual address aligned to an 1MiB boundary for the L1
-	 * mapping the head code makes. We keep the UART virtual address
-	 * aligned and add in the offset when we load the value here.
-	 */
-
-	.macro addruart, rx, rtmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = S3C_VA_UART
-#if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
-#endif
-	.endm
-
-/* include the reset of the code which will do the work, we're only
- * compiling for a single cpu processor type so the default of s3c2440
- * will be fine with us.
- */
-
-#include <plat/debug-macro.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/dma.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __MACH_DMA_H
-#define __MACH_DMA_H
-
-/* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
-
-#endif /* __MACH_DMA_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/entry-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/entry-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/entry-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/entry-macro.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,16 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/entry-macro.S
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Low-level IRQ helper macros for the Samsung S5P6440
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <mach/map.h>
-#include <plat/irqs.h>
-
-#include <asm/entry-macro-vic2.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/gpio.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,80 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/gpio.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - GPIO lib support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H __FILE__
-
-#define gpio_get_value	__gpio_get_value
-#define gpio_set_value	__gpio_set_value
-#define gpio_cansleep	__gpio_cansleep
-#define gpio_to_irq	__gpio_to_irq
-
-/* GPIO bank sizes */
-#define S5P6440_GPIO_A_NR	(6)
-#define S5P6440_GPIO_B_NR	(7)
-#define S5P6440_GPIO_C_NR	(8)
-#define S5P6440_GPIO_F_NR	(2)
-#define S5P6440_GPIO_G_NR	(7)
-#define S5P6440_GPIO_H_NR	(10)
-#define S5P6440_GPIO_I_NR	(16)
-#define S5P6440_GPIO_J_NR	(12)
-#define S5P6440_GPIO_N_NR	(16)
-#define S5P6440_GPIO_P_NR	(8)
-#define S5P6440_GPIO_R_NR	(15)
-
-/* GPIO bank numbers */
-
-/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
- * space for debugging purposes so that any accidental
- * change from one gpio bank to another can be caught.
-*/
-#define S5P6440_GPIO_NEXT(__gpio) \
-	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
-
-enum s5p_gpio_number {
-	S5P6440_GPIO_A_START = 0,
-	S5P6440_GPIO_B_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_A),
-	S5P6440_GPIO_C_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_B),
-	S5P6440_GPIO_F_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_C),
-	S5P6440_GPIO_G_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_F),
-	S5P6440_GPIO_H_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_G),
-	S5P6440_GPIO_I_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_H),
-	S5P6440_GPIO_J_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_I),
-	S5P6440_GPIO_N_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_J),
-	S5P6440_GPIO_P_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_N),
-	S5P6440_GPIO_R_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_P),
-};
-
-/* S5P6440 GPIO number definitions. */
-#define S5P6440_GPA(_nr)	(S5P6440_GPIO_A_START + (_nr))
-#define S5P6440_GPB(_nr)	(S5P6440_GPIO_B_START + (_nr))
-#define S5P6440_GPC(_nr)	(S5P6440_GPIO_C_START + (_nr))
-#define S5P6440_GPF(_nr)	(S5P6440_GPIO_F_START + (_nr))
-#define S5P6440_GPG(_nr)	(S5P6440_GPIO_G_START + (_nr))
-#define S5P6440_GPH(_nr)	(S5P6440_GPIO_H_START + (_nr))
-#define S5P6440_GPI(_nr)	(S5P6440_GPIO_I_START + (_nr))
-#define S5P6440_GPJ(_nr)	(S5P6440_GPIO_J_START + (_nr))
-#define S5P6440_GPN(_nr)	(S5P6440_GPIO_N_START + (_nr))
-#define S5P6440_GPP(_nr)	(S5P6440_GPIO_P_START + (_nr))
-#define S5P6440_GPR(_nr)	(S5P6440_GPIO_R_START + (_nr))
-
-/* the end of the S5P6440 specific gpios */
-#define S5P6440_GPIO_END	(S5P6440_GPR(S5P6440_GPIO_R_NR) + 1)
-#define S3C_GPIO_END		S5P6440_GPIO_END
-
-/* define the number of gpios we need to the one after the GPR() range */
-#define ARCH_NR_GPIOS		(S5P6440_GPR(S5P6440_GPIO_R_NR) +	\
-				 CONFIG_SAMSUNG_GPIO_EXTRA + 1)
-
-#include <asm-generic/gpio.h>
-
-#endif /* __ASM_ARCH_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/hardware.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/hardware.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/hardware.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,18 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/hardware.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Hardware support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H __FILE__
-
-/* currently nothing here, placeholder */
-
-#endif /* __ASM_ARCH_HARDWARE_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/io.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/io.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/io.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s5p6440/include/mach/io.h
- *
- * Copyright 2008 Simtec Electronics
- *	Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S3C64XX based
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)		__typesafe_io(a)
-#define __mem_pci(a)	(a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/irqs.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,118 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/irqs.h
- *
- * Copyright 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - IRQ definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_S5P_IRQS_H
-#define __ASM_ARCH_S5P_IRQS_H __FILE__
-
-#include <plat/irqs.h>
-
-/* VIC0 */
-
-#define IRQ_EINT0_3		S5P_IRQ_VIC0(0)
-#define IRQ_EINT4_11		S5P_IRQ_VIC0(1)
-#define IRQ_RTC_TIC		S5P_IRQ_VIC0(2)
-#define IRQ_IIC1		S5P_IRQ_VIC0(5)
-#define IRQ_I2SV40		S5P_IRQ_VIC0(6)
-#define IRQ_GPS			S5P_IRQ_VIC0(7)
-#define IRQ_POST0		S5P_IRQ_VIC0(9)
-#define IRQ_2D			S5P_IRQ_VIC0(11)
-#define IRQ_TIMER0_VIC		S5P_IRQ_VIC0(23)
-#define IRQ_TIMER1_VIC		S5P_IRQ_VIC0(24)
-#define IRQ_TIMER2_VIC		S5P_IRQ_VIC0(25)
-#define IRQ_WDT			S5P_IRQ_VIC0(26)
-#define IRQ_TIMER3_VIC		S5P_IRQ_VIC0(27)
-#define IRQ_TIMER4_VIC		S5P_IRQ_VIC0(28)
-#define IRQ_DISPCON0		S5P_IRQ_VIC0(29)
-#define IRQ_DISPCON1		S5P_IRQ_VIC0(30)
-#define IRQ_DISPCON2		S5P_IRQ_VIC0(31)
-
-/* VIC1 */
-
-#define IRQ_EINT12_15		S5P_IRQ_VIC1(0)
-#define IRQ_PCM0		S5P_IRQ_VIC1(2)
-#define IRQ_UART0		S5P_IRQ_VIC1(5)
-#define IRQ_UART1		S5P_IRQ_VIC1(6)
-#define IRQ_UART2		S5P_IRQ_VIC1(7)
-#define IRQ_UART3		S5P_IRQ_VIC1(8)
-#define IRQ_DMA0		S5P_IRQ_VIC1(9)
-#define IRQ_NFC			S5P_IRQ_VIC1(13)
-#define IRQ_SPI0		S5P_IRQ_VIC1(16)
-#define IRQ_SPI1		S5P_IRQ_VIC1(17)
-#define IRQ_IIC			S5P_IRQ_VIC1(18)
-#define IRQ_DISPCON3		S5P_IRQ_VIC1(19)
-#define IRQ_FIMGVG		S5P_IRQ_VIC1(20)
-#define IRQ_EINT_GROUPS		S5P_IRQ_VIC1(21)
-#define IRQ_PMU			S5P_IRQ_VIC1(23)
-#define IRQ_HSMMC0		S5P_IRQ_VIC1(24)
-#define IRQ_HSMMC1		S5P_IRQ_VIC1(25)
-#define IRQ_HSMMC2		IRQ_SPI1	/* shared with SPI1 */
-#define IRQ_OTG			S5P_IRQ_VIC1(26)
-#define IRQ_DSI			S5P_IRQ_VIC1(27)
-#define IRQ_RTC_ALARM		S5P_IRQ_VIC1(28)
-#define IRQ_TSI			S5P_IRQ_VIC1(29)
-#define IRQ_PENDN		S5P_IRQ_VIC1(30)
-#define IRQ_TC			IRQ_PENDN
-#define IRQ_ADC			S5P_IRQ_VIC1(31)
-
-/*
- * Since the IRQ_EINT(x) are a linear mapping on s5p6440 we just defined
- * them as an IRQ_EINT(x) macro from S5P_IRQ_EINT_BASE which we place
- * after the pair of VICs.
- */
-
-#define S5P_IRQ_EINT_BASE	(S5P_IRQ_VIC1(31) + 6)
-
-#define S5P_EINT(x)		((x) + S5P_IRQ_EINT_BASE)
-
-#define S5P_EINT_BASE1		(S5P_IRQ_EINT_BASE)
-/*
- * S5P6440 has 0-15 external interrupts in group 0. Only these can be used
- * to wake up from sleep. If request is beyond this range, by mistake, a large
- * return value for an irq number should be indication of something amiss.
- */
-#define S5P_EINT_BASE2		(0xf0000000)
-
-/*
- * Next the external interrupt groups. These are similar to the IRQ_EINT(x)
- * that they are sourced from the GPIO pins but with a different scheme for
- * priority and source indication.
- *
- * The IRQ_EINT(x) can be thought of as 'group 0' of the available GPIO
- * interrupts, but for historical reasons they are kept apart from these
- * next interrupts.
- *
- * Use IRQ_EINT_GROUP(group, offset) to get the number for use in the
- * machine specific support files.
- */
-
-/* Actually, #6 and #7 are missing in the EINT_GROUP1 */
-#define IRQ_EINT_GROUP1_NR	(15)
-#define IRQ_EINT_GROUP2_NR	(8)
-#define IRQ_EINT_GROUP5_NR	(7)
-#define IRQ_EINT_GROUP6_NR	(10)
-/* Actually, #0, #1 and #2 are missing in the EINT_GROUP8 */
-#define IRQ_EINT_GROUP8_NR	(11)
-
-#define IRQ_EINT_GROUP_BASE	S5P_EINT(16)
-#define IRQ_EINT_GROUP1_BASE	(IRQ_EINT_GROUP_BASE + 0)
-#define IRQ_EINT_GROUP2_BASE	(IRQ_EINT_GROUP1_BASE + IRQ_EINT_GROUP1_NR)
-#define IRQ_EINT_GROUP5_BASE	(IRQ_EINT_GROUP2_BASE + IRQ_EINT_GROUP2_NR)
-#define IRQ_EINT_GROUP6_BASE	(IRQ_EINT_GROUP5_BASE + IRQ_EINT_GROUP5_NR)
-#define IRQ_EINT_GROUP8_BASE	(IRQ_EINT_GROUP6_BASE + IRQ_EINT_GROUP6_NR)
-
-#define IRQ_EINT_GROUP(grp, x)	(IRQ_EINT_GROUP##grp##_BASE + (x))
-
-/* Set the default NR_IRQS */
-
-#define NR_IRQS			(IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
-
-#endif /* __ASM_ARCH_S5P_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/map.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/map.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,86 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/map.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MAP_H
-#define __ASM_ARCH_MAP_H __FILE__
-
-#include <plat/map-base.h>
-#include <plat/map-s5p.h>
-
-#define S5P6440_PA_CHIPID	(0xE0000000)
-#define S5P_PA_CHIPID		S5P6440_PA_CHIPID
-
-#define S5P6440_PA_SYSCON	(0xE0100000)
-#define S5P6440_PA_CLK		(S5P6440_PA_SYSCON + 0x0)
-#define S5P_PA_SYSCON		S5P6440_PA_SYSCON
-
-#define S5P6440_PA_GPIO		(0xE0308000)
-#define S5P_PA_GPIO		S5P6440_PA_GPIO
-
-#define S5P6440_PA_VIC0		(0xE4000000)
-#define S5P_PA_VIC0		S5P6440_PA_VIC0
-
-#define S5P6440_PA_PDMA		0xE9000000
-
-#define S5P6440_PA_VIC1		(0xE4100000)
-#define S5P_PA_VIC1		S5P6440_PA_VIC1
-
-#define S5P6440_PA_TIMER	(0xEA000000)
-#define S5P_PA_TIMER		S5P6440_PA_TIMER
-
-#define S5P6440_PA_RTC		(0xEA100000)
-
-#define S5P6440_PA_WDT		(0xEA200000)
-#define S5P_PA_WDT		S5P6440_PA_WDT
-
-#define S5P6440_PA_UART		(0xEC000000)
-
-#define S5P_PA_UART0		(S5P6440_PA_UART + 0x0)
-#define S5P_PA_UART1		(S5P6440_PA_UART + 0x400)
-#define S5P_PA_UART2		(S5P6440_PA_UART + 0x800)
-#define S5P_PA_UART3		(S5P6440_PA_UART + 0xC00)
-
-#define S5P_SZ_UART		SZ_256
-
-#define S5P6440_PA_IIC0		(0xEC104000)
-#define S5P6440_PA_IIC1		(0xEC20F000)
-
-#define S5P6440_PA_SPI0		0xEC400000
-#define S5P6440_PA_SPI1		0xEC500000
-
-#define S5P6440_PA_HSOTG	(0xED100000)
-
-#define S5P6440_PA_HSMMC0	(0xED800000)
-#define S5P6440_PA_HSMMC1	(0xED900000)
-#define S5P6440_PA_HSMMC2	(0xEDA00000)
-
-#define S5P6440_PA_SDRAM	(0x20000000)
-#define S5P_PA_SDRAM		S5P6440_PA_SDRAM
-
-/* I2S */
-#define S5P6440_PA_I2S		0xF2000000
-
-/* PCM */
-#define S5P6440_PA_PCM		0xF2100000
-
-#define S5P6440_PA_ADC		(0xF3000000)
-
-/* compatibiltiy defines. */
-#define S3C_PA_UART		S5P6440_PA_UART
-#define S3C_PA_IIC		S5P6440_PA_IIC0
-#define S3C_PA_RTC		S5P6440_PA_RTC
-#define S3C_PA_IIC1		S5P6440_PA_IIC1
-#define S3C_PA_WDT		S5P6440_PA_WDT
-
-#define SAMSUNG_PA_ADC		S5P6440_PA_ADC
-
-#endif /* __ASM_ARCH_MAP_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/memory.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/memory.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/memory.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/memory.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/memory.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Memory definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#define PHYS_OFFSET     	UL(0x20000000)
-#define CONSISTENT_DMA_SIZE	SZ_8M
-
-#endif /* __ASM_ARCH_MEMORY_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/pwm-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/pwm-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/pwm-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/pwm-clock.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,70 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/pwm-clock.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *      Ben Dooks <ben@simtec.co.uk>
- *      http://armlinux.simtec.co.uk/
- *
- * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
- *
- * S5P6440 - pwm clock and timer support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_PWMCLK_H
-#define __ASM_ARCH_PWMCLK_H __FILE__
-
-/**
- * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
- * @tcfg: The timer TCFG1 register bits shifted down to 0.
- *
- * Return true if the given configuration from TCFG1 is a TCLK instead
- * any of the TDIV clocks.
- */
-static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
-{
-	return 0;
-}
-
-/**
- * tcfg_to_divisor() - convert tcfg1 setting to a divisor
- * @tcfg1: The tcfg1 setting, shifted down.
- *
- * Get the divisor value for the given tcfg1 setting. We assume the
- * caller has already checked to see if this is not a TCLK source.
- */
-static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
-{
-	return 1 << tcfg1;
-}
-
-/**
- * pwm_tdiv_has_div1() - does the tdiv setting have a /1
- *
- * Return true if we have a /1 in the tdiv setting.
- */
-static inline unsigned int pwm_tdiv_has_div1(void)
-{
-	return 1;
-}
-
-/**
- * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
- * @div: The divisor to calculate the bit information for.
- *
- * Turn a divisor into the necessary bit field for TCFG1.
- */
-static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
-{
-	return ilog2(div);
-}
-
-#define S3C_TCFG1_MUX_TCLK 0
-
-#endif /* __ASM_ARCH_PWMCLK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-clock.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,130 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-clock.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Clock register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_CLOCK_H
-#define __ASM_ARCH_REGS_CLOCK_H __FILE__
-
-#include <mach/map.h>
-
-#define S5P_CLKREG(x)		(S3C_VA_SYS + (x))
-
-#define S5P_APLL_LOCK		S5P_CLKREG(0x00)
-#define S5P_MPLL_LOCK		S5P_CLKREG(0x04)
-#define S5P_EPLL_LOCK		S5P_CLKREG(0x08)
-#define S5P_APLL_CON		S5P_CLKREG(0x0C)
-#define S5P_MPLL_CON		S5P_CLKREG(0x10)
-#define S5P_EPLL_CON		S5P_CLKREG(0x14)
-#define S5P_EPLL_CON_K		S5P_CLKREG(0x18)
-#define S5P_CLK_SRC0		S5P_CLKREG(0x1C)
-#define S5P_CLK_DIV0		S5P_CLKREG(0x20)
-#define S5P_CLK_DIV1		S5P_CLKREG(0x24)
-#define S5P_CLK_DIV2		S5P_CLKREG(0x28)
-#define S5P_CLK_OUT		S5P_CLKREG(0x2C)
-#define S5P_CLK_GATE_HCLK0	S5P_CLKREG(0x30)
-#define S5P_CLK_GATE_PCLK	S5P_CLKREG(0x34)
-#define S5P_CLK_GATE_SCLK0	S5P_CLKREG(0x38)
-#define S5P_CLK_GATE_MEM0	S5P_CLKREG(0x3C)
-#define S5P_CLK_DIV3		S5P_CLKREG(0x40)
-#define S5P_CLK_GATE_HCLK1	S5P_CLKREG(0x44)
-#define S5P_CLK_GATE_SCLK1	S5P_CLKREG(0x48)
-#define S5P_AHB_CON0           	S5P_CLKREG(0x100)
-#define S5P_CLK_SRC1           	S5P_CLKREG(0x10C)
-#define S5P_SWRESET		S5P_CLKREG(0x114)
-#define S5P_SYS_ID		S5P_CLKREG(0x118)
-#define S5P_SYS_OTHERS		S5P_CLKREG(0x11C)
-#define S5P_MEM_CFG_STAT	S5P_CLKREG(0x12C)
-#define S5P_PWR_CFG		S5P_CLKREG(0x804)
-#define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0x808)
-#define S5P_NORMAL_CFG		S5P_CLKREG(0x810)
-#define S5P_STOP_CFG		S5P_CLKREG(0x814)
-#define S5P_SLEEP_CFG		S5P_CLKREG(0x818)
-#define S5P_OSC_FREQ		S5P_CLKREG(0x820)
-#define S5P_OSC_STABLE		S5P_CLKREG(0x824)
-#define S5P_PWR_STABLE		S5P_CLKREG(0x828)
-#define S5P_MTC_STABLE		S5P_CLKREG(0x830)
-#define S5P_OTHERS		S5P_CLKREG(0x900)
-#define S5P_RST_STAT		S5P_CLKREG(0x904)
-#define S5P_WAKEUP_STAT		S5P_CLKREG(0x908)
-#define S5P_SLPEN		S5P_CLKREG(0x930)
-#define S5P_INFORM0		S5P_CLKREG(0xA00)
-#define S5P_INFORM1		S5P_CLKREG(0xA04)
-#define S5P_INFORM2		S5P_CLKREG(0xA08)
-#define S5P_INFORM3		S5P_CLKREG(0xA0C)
-
-/* CLKDIV0 */
-#define S5P_CLKDIV0_PCLK_MASK		(0xf << 12)
-#define S5P_CLKDIV0_PCLK_SHIFT		(12)
-#define S5P_CLKDIV0_HCLK_MASK		(0xf << 8)
-#define S5P_CLKDIV0_HCLK_SHIFT		(8)
-#define S5P_CLKDIV0_MPLL_MASK		(0x1 << 4)
-#define S5P_CLKDIV0_ARM_MASK		(0xf << 0)
-#define S5P_CLKDIV0_ARM_SHIFT		(0)
-
-/* CLKDIV3 */
-#define S5P_CLKDIV3_PCLK_LOW_MASK	(0xf << 12)
-#define S5P_CLKDIV3_PCLK_LOW_SHIFT	(12)
-#define S5P_CLKDIV3_HCLK_LOW_MASK	(0xf << 8)
-#define S5P_CLKDIV3_HCLK_LOW_SHIFT	(8)
-
-/* HCLK0 GATE Registers */
-#define S5P_CLKCON_HCLK0_USB		(1<<20)
-#define S5P_CLKCON_HCLK0_HSMMC2		(1<<19)
-#define S5P_CLKCON_HCLK0_HSMMC1		(1<<18)
-#define S5P_CLKCON_HCLK0_HSMMC0		(1<<17)
-#define S5P_CLKCON_HCLK0_POST0		(1<<5)
-
-/* HCLK1 GATE Registers */
-#define S5P_CLKCON_HCLK1_DISPCON	(1<<1)
-
-/* PCLK GATE Registers */
-#define S5P_CLKCON_PCLK_IIS2		(1<<26)
-#define S5P_CLKCON_PCLK_SPI1		(1<<22)
-#define S5P_CLKCON_PCLK_SPI0		(1<<21)
-#define S5P_CLKCON_PCLK_GPIO		(1<<18)
-#define S5P_CLKCON_PCLK_IIC0		(1<<17)
-#define S5P_CLKCON_PCLK_TSADC		(1<<12)
-#define S5P_CLKCON_PCLK_PWM		(1<<7)
-#define S5P_CLKCON_PCLK_RTC		(1<<6)
-#define S5P_CLKCON_PCLK_WDT		(1<<5)
-#define S5P_CLKCON_PCLK_UART3		(1<<4)
-#define S5P_CLKCON_PCLK_UART2		(1<<3)
-#define S5P_CLKCON_PCLK_UART1		(1<<2)
-#define S5P_CLKCON_PCLK_UART0		(1<<1)
-
-/* SCLK0 GATE Registers */
-#define S5P_CLKCON_SCLK0_MMC2_48	(1<<29)
-#define S5P_CLKCON_SCLK0_MMC1_48	(1<<28)
-#define S5P_CLKCON_SCLK0_MMC0_48	(1<<27)
-#define S5P_CLKCON_SCLK0_MMC2		(1<<26)
-#define S5P_CLKCON_SCLK0_MMC1		(1<<25)
-#define S5P_CLKCON_SCLK0_MMC0		(1<<24)
-#define S5P_CLKCON_SCLK0_SPI1_48 	(1<<23)
-#define S5P_CLKCON_SCLK0_SPI0_48 	(1<<22)
-#define S5P_CLKCON_SCLK0_SPI1		(1<<21)
-#define S5P_CLKCON_SCLK0_SPI0		(1<<20)
-#define S5P_CLKCON_SCLK0_UART		(1<<5)
-
-/* SCLK1 GATE Registers */
-
-/* MEM0 GATE Registers */
-#define S5P_CLKCON_MEM0_HCLK_NFCON	(1<<2)
-
-/*OTHERS Resgister */
-#define S5P_OTHERS_USB_SIG_MASK		(1<<16)
-#define S5P_OTHERS_HCLK_LOW_SEL_MPLL	(1<<6)
-
-/* Compatibility defines */
-#define ARM_CLK_DIV			S5P_CLK_DIV0
-#define ARM_DIV_RATIO_SHIFT		0
-#define ARM_DIV_MASK			(0xf << ARM_DIV_RATIO_SHIFT)
-
-#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-gpio.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,54 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-gpio.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - GPIO register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_REGS_GPIO_H
-#define __ASM_ARCH_REGS_GPIO_H __FILE__
-
-#include <mach/map.h>
-
-/* Base addresses for each of the banks */
-#define S5P6440_GPA_BASE		(S5P_VA_GPIO + 0x0000)
-#define S5P6440_GPB_BASE		(S5P_VA_GPIO + 0x0020)
-#define S5P6440_GPC_BASE		(S5P_VA_GPIO + 0x0040)
-#define S5P6440_GPF_BASE		(S5P_VA_GPIO + 0x00A0)
-#define S5P6440_GPG_BASE		(S5P_VA_GPIO + 0x00C0)
-#define S5P6440_GPH_BASE		(S5P_VA_GPIO + 0x00E0)
-#define S5P6440_GPI_BASE		(S5P_VA_GPIO + 0x0100)
-#define S5P6440_GPJ_BASE		(S5P_VA_GPIO + 0x0120)
-#define S5P6440_GPN_BASE		(S5P_VA_GPIO + 0x0830)
-#define S5P6440_GPP_BASE		(S5P_VA_GPIO + 0x0160)
-#define S5P6440_GPR_BASE		(S5P_VA_GPIO + 0x0290)
-#define S5P6440_EINT0CON0		(S5P_VA_GPIO + 0x900)
-#define S5P6440_EINT0FLTCON0		(S5P_VA_GPIO + 0x910)
-#define S5P6440_EINT0FLTCON1		(S5P_VA_GPIO + 0x914)
-#define S5P6440_EINT0MASK		(S5P_VA_GPIO + 0x920)
-#define S5P6440_EINT0PEND		(S5P_VA_GPIO + 0x924)
-
-/* for LCD */
-#define S5P6440_SPCON_LCD_SEL_RGB	(1 << 0)
-#define S5P6440_SPCON_LCD_SEL_MASK	(3 << 0)
-
-/* These set of macros are not really useful for the
- * GPF/GPI/GPJ/GPN/GPP,
- * useful for others set of GPIO's (4 bit)
- */
-#define S5P6440_GPIO_CONMASK(__gpio)	(0xf << ((__gpio) * 4))
-#define S5P6440_GPIO_INPUT(__gpio)	(0x0 << ((__gpio) * 4))
-#define S5P6440_GPIO_OUTPUT(__gpio)	(0x1 << ((__gpio) * 4))
-
-/* Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
- * */
-#define S5P6440_GPIO2_CONMASK(__gpio)	(0x3 << ((__gpio) * 2))
-#define S5P6440_GPIO2_INPUT(__gpio)	(0x0 << ((__gpio) * 2))
-#define S5P6440_GPIO2_OUTPUT(__gpio)	(0x1 << ((__gpio) * 2))
-
-#endif /* __ASM_ARCH_REGS_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-irq.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-irq.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/regs-irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/regs-irq.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-irq.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - IRQ register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_IRQ_H
-#define __ASM_ARCH_REGS_IRQ_H __FILE__
-
-#include <asm/hardware/vic.h>
-#include <mach/map.h>
-
-#endif /* __ASM_ARCH_REGS_IRQ_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/spi-clocks.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/spi-clocks.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/spi-clocks.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5P6440_PLAT_SPI_CLKS_H
-#define __S5P6440_PLAT_SPI_CLKS_H __FILE__
-
-#define S5P6440_SPI_SRCCLK_PCLK		0
-#define S5P6440_SPI_SRCCLK_SCLK		1
-
-#endif /* __S5P6440_PLAT_SPI_CLKS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/system.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/system.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/system.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,23 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/system.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - system support header
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H __FILE__
-
-#include <plat/system-reset.h>
-
-static void arch_idle(void)
-{
-	/* nothing here yet */
-}
-
-#endif /* __ASM_ARCH_SYSTEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/tick.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/tick.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/tick.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/tick.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/tick.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Timer tick support definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TICK_H
-#define __ASM_ARCH_TICK_H __FILE__
-
-static inline u32 s3c24xx_ostimer_pending(void)
-{
-	u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
-	return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
-}
-
-#define TICK_MAX	(0xffffffff)
-
-#endif /* __ASM_ARCH_TICK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/timex.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/timex.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/timex.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/timex.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,24 +0,0 @@
-/* arch/arm/mach-s3c64xx/include/mach/timex.h
- *
- * Copyright (c) 2003-2005 Simtec Electronics
- *	Ben Dooks <ben@simtec.co.uk>
- *
- * S3C6400 - time parameters
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
- * a variable is useless. It seems as long as we make our timers an
- * exact multiple of HZ, any value that makes a 1->1 correspondence
- * for the time conversion functions to/from jiffies is acceptable.
-*/
-
-#define CLOCK_TICK_RATE 12000000
-
-#endif /* __ASM_ARCH_TIMEX_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/uncompress.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/uncompress.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/uncompress.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/uncompress.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - uncompress code
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/map.h>
-#include <plat/uncompress.h>
-
-static void arch_detect_cpu(void)
-{
-	/* we do not need to do any cpu detection here at the moment. */
-}
-
-#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/include/mach/vmalloc.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,17 +0,0 @@
-/* arch/arm/mach-s5p6440/include/mach/vmalloc.h
- *
- * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * S3C6400 vmalloc definition
-*/
-
-#ifndef __ASM_ARCH_VMALLOC_H
-#define __ASM_ARCH_VMALLOC_H
-
-#define VMALLOC_END	0xE0000000UL
-
-#endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/init.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/init.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/init.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,52 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/init.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * S5P6440 - Init support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/s5p6440.h>
-#include <plat/regs-serial.h>
-
-static struct s3c24xx_uart_clksrc s5p6440_serial_clocks[] = {
-	[0] = {
-		.name		= "pclk_low",
-		.divisor	= 1,
-		.min_baud	= 0,
-		.max_baud	= 0,
-	},
-	[1] = {
-		.name		= "uclk1",
-		.divisor	= 1,
-		.min_baud	= 0,
-		.max_baud	= 0,
-	},
-};
-
-/* uart registration process */
-void __init s5p6440_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-	struct s3c2410_uartcfg *tcfg = cfg;
-	u32 ucnt;
-
-	for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
-		if (!tcfg->clocks) {
-			tcfg->clocks = s5p6440_serial_clocks;
-			tcfg->clocks_size = ARRAY_SIZE(s5p6440_serial_clocks);
-		}
-	}
-
-	s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Kconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,33 +0,0 @@
-# arch/arm/mach-s5p6440/Kconfig
-#
-# Copyright (c) 2009 Samsung Electronics Co., Ltd.
-#		http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-if ARCH_S5P6440
-
-config CPU_S5P6440
-	bool
-	select S3C_PL330_DMA
-	help
-	  Enable S5P6440 CPU support
-
-config S5P6440_SETUP_I2C1
-	bool
-	help
-	  Common setup code for i2c bus 1.
-
-config MACH_SMDK6440
-	bool "SMDK6440"
-	select CPU_S5P6440
-	select S3C_DEV_I2C1
-	select S3C_DEV_RTC
-	select S3C_DEV_WDT
-	select SAMSUNG_DEV_ADC
-	select SAMSUNG_DEV_TS
-	select S5P6440_SETUP_I2C1
-	help
-	  Machine support for the Samsung SMDK6440
-
-endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/mach-smdk6440.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/mach-smdk6440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/mach-smdk6440.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/mach-smdk6440.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,146 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/mach-smdk6440.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/clk.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <plat/regs-serial.h>
-
-#include <plat/s5p6440.h>
-#include <plat/clock.h>
-#include <mach/regs-clock.h>
-#include <plat/devs.h>
-#include <plat/cpu.h>
-#include <plat/iic.h>
-#include <plat/pll.h>
-#include <plat/adc.h>
-#include <plat/ts.h>
-
-#define SMDK6440_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
-				S3C2410_UCON_RXILEVEL |		\
-				S3C2410_UCON_TXIRQMODE |	\
-				S3C2410_UCON_RXIRQMODE |	\
-				S3C2410_UCON_RXFIFO_TOI |	\
-				S3C2443_UCON_RXERR_IRQEN)
-
-#define SMDK6440_ULCON_DEFAULT	S3C2410_LCON_CS8
-
-#define SMDK6440_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
-				S3C2440_UFCON_TXTRIG16 |	\
-				S3C2410_UFCON_RXTRIG8)
-
-static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
-	[0] = {
-		.hwport	     = 0,
-		.flags	     = 0,
-		.ucon	     = SMDK6440_UCON_DEFAULT,
-		.ulcon	     = SMDK6440_ULCON_DEFAULT,
-		.ufcon	     = SMDK6440_UFCON_DEFAULT,
-	},
-	[1] = {
-		.hwport	     = 1,
-		.flags	     = 0,
-		.ucon	     = SMDK6440_UCON_DEFAULT,
-		.ulcon	     = SMDK6440_ULCON_DEFAULT,
-		.ufcon	     = SMDK6440_UFCON_DEFAULT,
-	},
-	[2] = {
-		.hwport	     = 2,
-		.flags	     = 0,
-		.ucon	     = SMDK6440_UCON_DEFAULT,
-		.ulcon	     = SMDK6440_ULCON_DEFAULT,
-		.ufcon	     = SMDK6440_UFCON_DEFAULT,
-	},
-	[3] = {
-		.hwport	     = 3,
-		.flags	     = 0,
-		.ucon	     = SMDK6440_UCON_DEFAULT,
-		.ulcon	     = SMDK6440_ULCON_DEFAULT,
-		.ufcon	     = SMDK6440_UFCON_DEFAULT,
-	},
-};
-
-static struct platform_device *smdk6440_devices[] __initdata = {
-	&s5p6440_device_iis,
-	&s3c_device_adc,
-	&s3c_device_rtc,
-	&s3c_device_i2c0,
-	&s3c_device_i2c1,
-	&s3c_device_ts,
-	&s3c_device_wdt,
-};
-
-static struct i2c_board_info smdk6440_i2c_devs0[] __initdata = {
-	{ I2C_BOARD_INFO("24c08", 0x50), },
-};
-
-static struct i2c_board_info smdk6440_i2c_devs1[] __initdata = {
-	/* To be populated */
-};
-
-static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
-	.delay			= 10000,
-	.presc			= 49,
-	.oversampling_shift	= 2,
-};
-
-static void __init smdk6440_map_io(void)
-{
-	s5p_init_io(NULL, 0, S5P_SYS_ID);
-	s3c24xx_init_clocks(12000000);
-	s3c24xx_init_uarts(smdk6440_uartcfgs, ARRAY_SIZE(smdk6440_uartcfgs));
-}
-
-static void __init smdk6440_machine_init(void)
-{
-	s3c24xx_ts_set_platdata(&s3c_ts_platform);
-
-	/* I2C */
-	s3c_i2c0_set_platdata(NULL);
-	s3c_i2c1_set_platdata(NULL);
-	i2c_register_board_info(0, smdk6440_i2c_devs0,
-			ARRAY_SIZE(smdk6440_i2c_devs0));
-	i2c_register_board_info(1, smdk6440_i2c_devs1,
-			ARRAY_SIZE(smdk6440_i2c_devs1));
-
-	platform_add_devices(smdk6440_devices, ARRAY_SIZE(smdk6440_devices));
-}
-
-MACHINE_START(SMDK6440, "SMDK6440")
-	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
-	.boot_params	= S5P_PA_SDRAM + 0x100,
-
-	.init_irq	= s5p6440_init_irq,
-	.map_io		= smdk6440_map_io,
-	.init_machine	= smdk6440_machine_init,
-	.timer		= &s3c24xx_timer,
-MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,25 +0,0 @@
-# arch/arm/mach-s5p6440/Makefile
-#
-# Copyright (c) 2009 Samsung Electronics Co., Ltd.
-# 		http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-obj-y				:=
-obj-m				:=
-obj-n				:=
-obj-				:=
-
-# Core support for S5P6440 system
-
-obj-$(CONFIG_CPU_S5P6440)	+= cpu.o init.o clock.o gpio.o dma.o
-obj-$(CONFIG_CPU_S5P6440)	+= setup-i2c0.o
-
-# machine support
-
-obj-$(CONFIG_MACH_SMDK6440)	+= mach-smdk6440.o
-
-# device support
-obj-y				+= dev-audio.o
-obj-$(CONFIG_S3C64XX_DEV_SPI)	+= dev-spi.o
-obj-$(CONFIG_S5P6440_SETUP_I2C1)	+= setup-i2c1.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Makefile.boot linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Makefile.boot
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/Makefile.boot	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/Makefile.boot	1969-12-31 19:00:00.000000000 -0500
@@ -1,2 +0,0 @@
-   zreladdr-y	:= 0x20008000
-params_phys-y	:= 0x20000100
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/setup-i2c0.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/setup-i2c0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/setup-i2c0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/setup-i2c0.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,30 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/setup-i2c0.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * I2C0 GPIO configuration.
- *
- * Based on plat-s3c64xx/setup-i2c0.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-struct platform_device; /* don't need the contents */
-
-#include <linux/gpio.h>
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-
-void s3c_i2c0_cfg_gpio(struct platform_device *dev)
-{
-	s3c_gpio_cfgpin(S5P6440_GPB(5), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5P6440_GPB(5), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5P6440_GPB(6), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5P6440_GPB(6), S3C_GPIO_PULL_UP);
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/setup-i2c1.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/setup-i2c1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6440/setup-i2c1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6440/setup-i2c1.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,30 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/setup-i2c1.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
- *
- * I2C1 GPIO configuration.
- *
- * Based on plat-s3c64xx/setup-i2c0.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/gpio.h>
-
-struct platform_device; /* don't need the contents */
-
-#include <plat/gpio-cfg.h>
-#include <plat/iic.h>
-
-void s3c_i2c1_cfg_gpio(struct platform_device *dev)
-{
-	s3c_gpio_cfgpin(S5P6440_GPR(9), S3C_GPIO_SFN(6));
-	s3c_gpio_setpull(S5P6440_GPR(9), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5P6440_GPR(10), S3C_GPIO_SFN(6));
-	s3c_gpio_setpull(S5P6440_GPR(10), S3C_GPIO_PULL_UP);
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -192,6 +192,11 @@
 	.parent		= &clk_hclkd1,
 };
 
+int s5p6442_clk_ip0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable);
+}
+
 int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
@@ -335,6 +340,16 @@
 	clk_pclkd1.rate = pclkd1;
 }
 
+static struct clk init_clocks_disable[] = {
+	{
+		.name		= "pdma",
+		.id		= -1,
+		.parent		= &clk_pclkd1,
+		.enable		= s5p6442_clk_ip0_ctrl,
+		.ctrlbit	= (1 << 3),
+	},
+};
+
 static struct clk init_clocks[] = {
 	{
 		.name		= "systimer",
@@ -393,10 +408,23 @@
 
 void __init s5p6442_register_clocks(void)
 {
+	struct clk *clkptr;
+	int i, ret;
+
 	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
 
 	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
 	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
 
+	clkptr = init_clocks_disable;
+	for (i = 0; i < ARRAY_SIZE(init_clocks_disable); i++, clkptr++) {
+		ret = s3c24xx_register_clock(clkptr);
+		if (ret < 0) {
+			printk(KERN_ERR "Fail to register clock %s (%d)\n",
+					clkptr->name, ret);
+		} else
+			(clkptr->enable)(clkptr, 0);
+	}
+
 	s3c_pwmclk_init();
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s5p6442/cpu.c
  *
  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
+ *		http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -48,10 +48,30 @@
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S5P_VA_GPIO,
+		.pfn		= __phys_to_pfn(S5P6442_PA_GPIO),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC0,
+		.pfn		= __phys_to_pfn(S5P6442_PA_VIC0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC1,
+		.pfn		= __phys_to_pfn(S5P6442_PA_VIC1),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)VA_VIC2,
 		.pfn		= __phys_to_pfn(S5P6442_PA_VIC2),
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S3C_PA_UART),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
 	}
 };
 
@@ -63,10 +83,11 @@
 	local_irq_enable();
 }
 
-/* s5p6442_map_io
+/*
+ * s5p6442_map_io
  *
  * register the standard cpu IO areas
-*/
+ */
 
 void __init s5p6442_map_io(void)
 {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dev-audio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dev-audio.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,22 +21,16 @@
 
 static int s5p6442_cfg_i2s(struct platform_device *pdev)
 {
+	unsigned int base;
+
 	/* configure GPIO for i2s port */
 	switch (pdev->id) {
 	case 1:
-		s3c_gpio_cfgpin(S5P6442_GPC1(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC1(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC1(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC1(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC1(4), S3C_GPIO_SFN(2));
+		base = S5P6442_GPC1(0);
 		break;
 
 	case -1:
-		s3c_gpio_cfgpin(S5P6442_GPC0(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC0(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC0(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC0(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPC0(4), S3C_GPIO_SFN(2));
+		base = S5P6442_GPC0(0);
 		break;
 
 	default:
@@ -44,6 +38,7 @@
 		return -EINVAL;
 	}
 
+	s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2));
 	return 0;
 }
 
@@ -111,21 +106,15 @@
 
 static int s5p6442_pcm_cfg_gpio(struct platform_device *pdev)
 {
+	unsigned int base;
+
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S5P6442_GPC0(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC0(1), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC0(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC0(3), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC0(4), S3C_GPIO_SFN(3));
+		base = S5P6442_GPC0(0);
 		break;
 
 	case 1:
-		s3c_gpio_cfgpin(S5P6442_GPC1(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC1(1), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC1(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC1(3), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5P6442_GPC1(4), S3C_GPIO_SFN(3));
+		base = S5P6442_GPC1(0);
 		break;
 
 	default:
@@ -133,6 +122,7 @@
 		return -EINVAL;
 	}
 
+	s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3));
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dev-spi.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dev-spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dev-spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dev-spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,11 +38,9 @@
 	switch (pdev->id) {
 	case 0:
 		s3c_gpio_cfgpin(S5P6442_GPB(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPB(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5P6442_GPB(3), S3C_GPIO_SFN(2));
 		s3c_gpio_setpull(S5P6442_GPB(0), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6442_GPB(2), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5P6442_GPB(3), S3C_GPIO_PULL_UP);
+		s3c_gpio_cfgall_range(S5P6442_GPB(2), 2,
+				      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,7 +82,7 @@
 
 static struct platform_device s5p6442_device_pdma = {
 	.name		= "s3c-pl330",
-	.id		= 1,
+	.id		= -1,
 	.num_resources	= ARRAY_SIZE(s5p6442_pdma_resource),
 	.resource	= s5p6442_pdma_resource,
 	.dev		= {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,13 +15,12 @@
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-	.macro addruart, rx, rtmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = S3C_VA_UART
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C_PA_UART
+		ldr	\rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/map.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/map.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,16 +23,10 @@
 #define S5P_PA_SYSCON		S5P6442_PA_SYSCON
 
 #define S5P6442_PA_GPIO		(0xE0200000)
-#define S5P_PA_GPIO		S5P6442_PA_GPIO
 
 #define S5P6442_PA_VIC0		(0xE4000000)
-#define S5P_PA_VIC0		S5P6442_PA_VIC0
-
 #define S5P6442_PA_VIC1		(0xE4100000)
-#define S5P_PA_VIC1		S5P6442_PA_VIC1
-
 #define S5P6442_PA_VIC2		(0xE4200000)
-#define S5P_PA_VIC2		S5P6442_PA_VIC2
 
 #define S5P6442_PA_MDMA		0xE8000000
 #define S5P6442_PA_PDMA		0xE9000000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/regs-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/regs-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/regs-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/regs-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -46,6 +46,7 @@
 #define S5P_CLK_DIV5		S5P_CLKREG(0x314)
 #define S5P_CLK_DIV6		S5P_CLKREG(0x318)
 
+#define S5P_CLKGATE_IP0		S5P_CLKREG(0x460)
 #define S5P_CLKGATE_IP3		S5P_CLKREG(0x46C)
 
 /* CLK_OUT */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END	0xE0000000UL
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,6 @@
 
 config CPU_S5P6442
 	bool
-	select PLAT_S5P
 	select S3C_PL330_DMA
 	help
 	  Enable S5P6442 CPU support
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/mach-smdk6442.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/mach-smdk6442.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p6442/mach-smdk6442.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p6442/mach-smdk6442.c	2011-01-04 19:50:19.000000000 -0500
@@ -83,8 +83,6 @@
 
 MACHINE_START(SMDK6442, "SMDK6442")
 	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5p6442_init_irq,
 	.map_io		= smdk6442_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,235 @@
+/* linux/arch/arm/mach-s5p64x0/clock.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+
+struct clksrc_clk clk_mout_apll = {
+	.clk	= {
+		.name		= "mout_apll",
+		.id		= -1,
+	},
+	.sources	= &clk_src_apll,
+	.reg_src	= { .reg = S5P64X0_CLK_SRC0, .shift = 0, .size = 1 },
+};
+
+struct clksrc_clk clk_mout_mpll = {
+	.clk	= {
+		.name		= "mout_mpll",
+		.id		= -1,
+	},
+	.sources	= &clk_src_mpll,
+	.reg_src	= { .reg = S5P64X0_CLK_SRC0, .shift = 1, .size = 1 },
+};
+
+struct clksrc_clk clk_mout_epll = {
+	.clk	= {
+		.name		= "mout_epll",
+		.id		= -1,
+	},
+	.sources	= &clk_src_epll,
+	.reg_src	= { .reg = S5P64X0_CLK_SRC0, .shift = 2, .size = 1 },
+};
+
+enum perf_level {
+	L0 = 532*1000,
+	L1 = 266*1000,
+	L2 = 133*1000,
+};
+
+static const u32 clock_table[][3] = {
+	/*{ARM_CLK, DIVarm, DIVhclk}*/
+	{L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+	{L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+	{L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+};
+
+unsigned long s5p64x0_armclk_get_rate(struct clk *clk)
+{
+	unsigned long rate = clk_get_rate(clk->parent);
+	u32 clkdiv;
+
+	/* divisor mask starts at bit0, so no need to shift */
+	clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK;
+
+	return rate / (clkdiv + 1);
+}
+
+unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
+{
+	u32 iter;
+
+	for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
+		if (rate > clock_table[iter][0])
+			return clock_table[iter-1][0];
+	}
+
+	return clock_table[ARRAY_SIZE(clock_table) - 1][0];
+}
+
+int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 round_tmp;
+	u32 iter;
+	u32 clk_div0_tmp;
+	u32 cur_rate = clk->ops->get_rate(clk);
+	unsigned long flags;
+
+	round_tmp = clk->ops->round_rate(clk, rate);
+	if (round_tmp == cur_rate)
+		return 0;
+
+
+	for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
+		if (round_tmp == clock_table[iter][0])
+			break;
+	}
+
+	if (iter >= ARRAY_SIZE(clock_table))
+		iter = ARRAY_SIZE(clock_table) - 1;
+
+	local_irq_save(flags);
+	if (cur_rate > round_tmp) {
+		/* Frequency Down */
+		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
+		clk_div0_tmp |= clock_table[iter][1];
+		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
+				~(S5P64X0_CLKDIV0_HCLK_MASK);
+		clk_div0_tmp |= clock_table[iter][2];
+		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+
+	} else {
+		/* Frequency Up */
+		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
+				~(S5P64X0_CLKDIV0_HCLK_MASK);
+		clk_div0_tmp |= clock_table[iter][2];
+		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+		clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
+		clk_div0_tmp |= clock_table[iter][1];
+		__raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+	}
+	local_irq_restore(flags);
+
+	clk->rate = clock_table[iter][0];
+
+	return 0;
+}
+
+struct clk_ops s5p64x0_clkarm_ops = {
+	.get_rate	= s5p64x0_armclk_get_rate,
+	.set_rate	= s5p64x0_armclk_set_rate,
+	.round_rate	= s5p64x0_armclk_round_rate,
+};
+
+struct clksrc_clk clk_armclk = {
+	.clk	= {
+		.name		= "armclk",
+		.id		= 1,
+		.parent		= &clk_mout_apll.clk,
+		.ops		= &s5p64x0_clkarm_ops,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 0, .size = 4 },
+};
+
+struct clksrc_clk clk_dout_mpll = {
+	.clk	= {
+		.name		= "dout_mpll",
+		.id		= -1,
+		.parent		= &clk_mout_mpll.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 4, .size = 1 },
+};
+
+struct clk *clkset_hclk_low_list[] = {
+	&clk_mout_apll.clk,
+	&clk_mout_mpll.clk,
+};
+
+struct clksrc_sources clkset_hclk_low = {
+	.sources	= clkset_hclk_low_list,
+	.nr_sources	= ARRAY_SIZE(clkset_hclk_low_list),
+};
+
+int s5p64x0_pclk_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_PCLK, clk, enable);
+}
+
+int s5p64x0_hclk0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK0, clk, enable);
+}
+
+int s5p64x0_hclk1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK1, clk, enable);
+}
+
+int s5p64x0_sclk_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK0, clk, enable);
+}
+
+int s5p64x0_sclk1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK1, clk, enable);
+}
+
+int s5p64x0_mem_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P64X0_CLK_GATE_MEM0, clk, enable);
+}
+
+int s5p64x0_clk48m_ctrl(struct clk *clk, int enable)
+{
+	unsigned long flags;
+	u32 val;
+
+	/* can't rely on clock lock, this register has other usages */
+	local_irq_save(flags);
+
+	val = __raw_readl(S5P64X0_OTHERS);
+	if (enable)
+		val |= S5P64X0_OTHERS_USB_SIG_MASK;
+	else
+		val &= ~S5P64X0_OTHERS_USB_SIG_MASK;
+
+	__raw_writel(val, S5P64X0_OTHERS);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock-s5p6440.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock-s5p6440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock-s5p6440.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock-s5p6440.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,629 @@
+/* linux/arch/arm/mach-s5p64x0/clock-s5p6440.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P6440 - Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/s5p64x0-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6440.h>
+
+static u32 epll_div[][5] = {
+	{ 36000000,	0,	48, 1, 4 },
+	{ 48000000,	0,	32, 1, 3 },
+	{ 60000000,	0,	40, 1, 3 },
+	{ 72000000,	0,	48, 1, 3 },
+	{ 84000000,	0,	28, 1, 2 },
+	{ 96000000,	0,	32, 1, 2 },
+	{ 32768000,	45264,	43, 1, 4 },
+	{ 45158000,	6903,	30, 1, 3 },
+	{ 49152000,	50332,	32, 1, 3 },
+	{ 67738000,	10398,	45, 1, 3 },
+	{ 73728000,	9961,	49, 1, 3 }
+};
+
+static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int epll_con, epll_con_k;
+	unsigned int i;
+
+	if (clk->rate == rate)	/* Return if nothing changed */
+		return 0;
+
+	epll_con = __raw_readl(S5P64X0_EPLL_CON);
+	epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
+
+	epll_con_k &= ~(PLL90XX_KDIV_MASK);
+	epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		 if (epll_div[i][0] == rate) {
+			epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
+			epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
+				    (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
+				    (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(epll_con, S5P64X0_EPLL_CON);
+	__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+static struct clk_ops s5p6440_epll_ops = {
+	.get_rate = s5p_epll_get_rate,
+	.set_rate = s5p6440_epll_set_rate,
+};
+
+static struct clksrc_clk clk_hclk = {
+	.clk	= {
+		.name		= "clk_hclk",
+		.id		= -1,
+		.parent		= &clk_armclk.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk = {
+	.clk	= {
+		.name		= "clk_pclk",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
+};
+static struct clksrc_clk clk_hclk_low = {
+	.clk	= {
+		.name		= "clk_hclk_low",
+		.id		= -1,
+	},
+	.sources	= &clkset_hclk_low,
+	.reg_src	= { .reg = S5P64X0_SYS_OTHERS, .shift = 6, .size = 1 },
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_low = {
+	.clk	= {
+		.name		= "clk_pclk_low",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
+};
+
+/*
+ * The following clocks will be disabled during clock initialization. It is
+ * recommended to keep the following clocks disabled until the driver requests
+ * for enabling the clock.
+ */
+static struct clk init_clocks_disable[] = {
+	{
+		.name		= "nand",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_mem_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "post",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 5)
+	}, {
+		.name		= "2d",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "pdma",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "hsmmc",
+		.id		= 0,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "hsmmc",
+		.id		= 1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "hsmmc",
+		.id		= 2,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 19),
+	}, {
+		.name		= "otg",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 20)
+	}, {
+		.name		= "irom",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 25),
+	}, {
+		.name		= "lcd",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk1_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "hclk_fimgvg",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk1_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "tsi",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk1_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "watchdog",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "rtc",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "timers",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "pcm",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "adc",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "i2c",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "spi",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "spi",
+		.id		= 1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "gps",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 25),
+	}, {
+		.name		= "i2s_v40",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 26),
+	}, {
+		.name		= "dsim",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 28),
+	}, {
+		.name		= "etm",
+		.id		= -1,
+		.parent		= &clk_pclk.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 29),
+	}, {
+		.name		= "dmc0",
+		.id		= -1,
+		.parent		= &clk_pclk.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 30),
+	}, {
+		.name		= "pclk_fimgvg",
+		.id		= -1,
+		.parent		= &clk_pclk.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 31),
+	}, {
+		.name		= "sclk_spi_48",
+		.id		= 0,
+		.parent		= &clk_48m,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "sclk_spi_48",
+		.id		= 1,
+		.parent		= &clk_48m,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 23),
+	}, {
+		.name		= "mmc_48m",
+		.id		= 0,
+		.parent		= &clk_48m,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 27),
+	}, {
+		.name		= "mmc_48m",
+		.id		= 1,
+		.parent		= &clk_48m,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 28),
+	}, {
+		.name		= "mmc_48m",
+		.id		= 2,
+		.parent		= &clk_48m,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 29),
+	},
+};
+
+/*
+ * The following clocks will be enabled during clock initialization.
+ */
+static struct clk init_clocks[] = {
+	{
+		.name		= "intc",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "mem",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "uart",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "uart",
+		.id		= 1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "uart",
+		.id		= 2,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "uart",
+		.id		= 3,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "gpio",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 18),
+	},
+};
+
+static struct clk clk_iis_cd_v40 = {
+	.name		= "iis_cdclk_v40",
+	.id		= -1,
+};
+
+static struct clk clk_pcm_cd = {
+	.name		= "pcm_cdclk",
+	.id		= -1,
+};
+
+static struct clk *clkset_group1_list[] = {
+	&clk_mout_epll.clk,
+	&clk_dout_mpll.clk,
+	&clk_fin_epll,
+};
+
+static struct clksrc_sources clkset_group1 = {
+	.sources	= clkset_group1_list,
+	.nr_sources	= ARRAY_SIZE(clkset_group1_list),
+};
+
+static struct clk *clkset_uart_list[] = {
+	&clk_mout_epll.clk,
+	&clk_dout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_uart = {
+	.sources	= clkset_uart_list,
+	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
+};
+
+static struct clk *clkset_audio_list[] = {
+	&clk_mout_epll.clk,
+	&clk_dout_mpll.clk,
+	&clk_fin_epll,
+	&clk_iis_cd_v40,
+	&clk_pcm_cd,
+};
+
+static struct clksrc_sources clkset_audio = {
+	.sources	= clkset_audio_list,
+	.nr_sources	= ARRAY_SIZE(clkset_audio_list),
+};
+
+static struct clksrc_clk clksrcs[] = {
+	{
+		.clk	= {
+			.name		= "mmc_bus",
+			.id		= 0,
+			.ctrlbit	= (1 << 24),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "mmc_bus",
+			.id		= 1,
+			.ctrlbit	= (1 << 25),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "mmc_bus",
+			.id		= 2,
+			.ctrlbit	= (1 << 26),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "uclk1",
+			.id		= -1,
+			.ctrlbit	= (1 << 5),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_uart,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_spi",
+			.id		= 0,
+			.ctrlbit	= (1 << 20),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_spi",
+			.id		= 1,
+			.ctrlbit	= (1 << 21),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_post",
+			.id		= -1,
+			.ctrlbit	= (1 << 10),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_dispcon",
+			.id		= -1,
+			.ctrlbit	= (1 << 1),
+			.enable		= s5p64x0_sclk1_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimgvg",
+			.id		= -1,
+			.ctrlbit	= (1 << 2),
+			.enable		= s5p64x0_sclk1_ctrl,
+		},
+		.sources = &clkset_group1,
+		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_audio2",
+			.id		= -1,
+			.ctrlbit	= (1 << 11),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_audio,
+		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 },
+	},
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *sysclks[] = {
+	&clk_mout_apll,
+	&clk_mout_epll,
+	&clk_mout_mpll,
+	&clk_dout_mpll,
+	&clk_armclk,
+	&clk_hclk,
+	&clk_pclk,
+	&clk_hclk_low,
+	&clk_pclk_low,
+};
+
+void __init_or_cpufreq s5p6440_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+
+	unsigned long xtal;
+	unsigned long fclk;
+	unsigned long hclk;
+	unsigned long hclk_low;
+	unsigned long pclk;
+	unsigned long pclk_low;
+
+	unsigned long apll;
+	unsigned long mpll;
+	unsigned long epll;
+	unsigned int ptr;
+
+	/* Set S5P6440 functions for clk_fout_epll */
+
+	clk_fout_epll.enable = s5p_epll_enable;
+	clk_fout_epll.ops = &s5p6440_epll_ops;
+
+	clk_48m.enable = s5p64x0_clk48m_ctrl;
+
+	xtal_clk = clk_get(NULL, "ext_xtal");
+	BUG_ON(IS_ERR(xtal_clk));
+
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
+	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
+	epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
+				__raw_readl(S5P64X0_EPLL_CON_K));
+
+	clk_fout_apll.rate = apll;
+	clk_fout_mpll.rate = mpll;
+	clk_fout_epll.rate = epll;
+
+	printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
+			" E=%ld.%ldMHz\n",
+			print_mhz(apll), print_mhz(mpll), print_mhz(epll));
+
+	fclk = clk_get_rate(&clk_armclk.clk);
+	hclk = clk_get_rate(&clk_hclk.clk);
+	pclk = clk_get_rate(&clk_pclk.clk);
+	hclk_low = clk_get_rate(&clk_hclk_low.clk);
+	pclk_low = clk_get_rate(&clk_pclk_low.clk);
+
+	printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
+			" PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
+			print_mhz(hclk), print_mhz(hclk_low),
+			print_mhz(pclk), print_mhz(pclk_low));
+
+	clk_f.rate = fclk;
+	clk_h.rate = hclk;
+	clk_p.rate = pclk;
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+		s3c_set_clksrc(&clksrcs[ptr], true);
+}
+
+static struct clk *clks[] __initdata = {
+	&clk_ext,
+	&clk_iis_cd_v40,
+	&clk_pcm_cd,
+};
+
+void __init s5p6440_register_clocks(void)
+{
+	struct clk *clkp;
+	int ret;
+	int ptr;
+
+	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
+		s3c_register_clksrc(sysclks[ptr], 1);
+
+	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
+	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+	clkp = init_clocks_disable;
+	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+		ret = s3c24xx_register_clock(clkp);
+		if (ret < 0) {
+			printk(KERN_ERR "Failed to register clock %s (%d)\n",
+			       clkp->name, ret);
+		}
+		(clkp->enable)(clkp, 0);
+	}
+
+	s3c_pwmclk_init();
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock-s5p6450.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock-s5p6450.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/clock-s5p6450.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/clock-s5p6450.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,658 @@
+/* linux/arch/arm/mach-s5p64x0/clock-s5p6450.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P6450 - Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/s5p64x0-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6450.h>
+
+static struct clksrc_clk clk_mout_dpll = {
+	.clk	= {
+		.name		= "mout_dpll",
+		.id		= -1,
+	},
+	.sources	= &clk_src_dpll,
+	.reg_src	= { .reg = S5P64X0_CLK_SRC0, .shift = 5, .size = 1 },
+};
+
+static u32 epll_div[][5] = {
+	{ 133000000,	27307,	55, 2, 2 },
+	{ 100000000,	43691,	41, 2, 2 },
+	{ 480000000,	0,	80, 2, 0 },
+};
+
+static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int epll_con, epll_con_k;
+	unsigned int i;
+
+	if (clk->rate == rate)	/* Return if nothing changed */
+		return 0;
+
+	epll_con = __raw_readl(S5P64X0_EPLL_CON);
+	epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
+
+	epll_con_k &= ~(PLL90XX_KDIV_MASK);
+	epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		 if (epll_div[i][0] == rate) {
+			epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
+			epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
+				    (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
+				    (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(epll_con, S5P64X0_EPLL_CON);
+	__raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+static struct clk_ops s5p6450_epll_ops = {
+	.get_rate = s5p_epll_get_rate,
+	.set_rate = s5p6450_epll_set_rate,
+};
+
+static struct clksrc_clk clk_dout_epll = {
+	.clk	= {
+		.name		= "dout_epll",
+		.id		= -1,
+		.parent		= &clk_mout_epll.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV1, .shift = 24, .size = 4 },
+};
+
+static struct clksrc_clk clk_mout_hclk_sel = {
+	.clk	= {
+		.name		= "mout_hclk_sel",
+		.id		= -1,
+	},
+	.sources	= &clkset_hclk_low,
+	.reg_src	= { .reg = S5P64X0_OTHERS, .shift = 15, .size = 1 },
+};
+
+static struct clk *clkset_hclk_list[] = {
+	&clk_mout_hclk_sel.clk,
+	&clk_armclk.clk,
+};
+
+static struct clksrc_sources clkset_hclk = {
+	.sources	= clkset_hclk_list,
+	.nr_sources	= ARRAY_SIZE(clkset_hclk_list),
+};
+
+static struct clksrc_clk clk_hclk = {
+	.clk	= {
+		.name		= "clk_hclk",
+		.id		= -1,
+	},
+	.sources	= &clkset_hclk,
+	.reg_src	= { .reg = S5P64X0_OTHERS, .shift = 14, .size = 1 },
+	.reg_div	= { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk = {
+	.clk	= {
+		.name		= "clk_pclk",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+	},
+	.reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
+};
+static struct clksrc_clk clk_dout_pwm_ratio0 = {
+	.clk	= {
+		.name		= "clk_dout_pwm_ratio0",
+		.id		= -1,
+		.parent		= &clk_mout_hclk_sel.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_to_wdt_pwm = {
+	.clk	= {
+		.name		= "clk_pclk_to_wdt_pwm",
+		.id		= -1,
+		.parent		= &clk_dout_pwm_ratio0.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 20, .size = 4 },
+};
+
+static struct clksrc_clk clk_hclk_low = {
+	.clk	= {
+		.name		= "clk_hclk_low",
+		.id		= -1,
+	},
+	.sources	= &clkset_hclk_low,
+	.reg_src	= { .reg = S5P64X0_OTHERS, .shift = 6, .size = 1 },
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_low = {
+	.clk	= {
+		.name		= "clk_pclk_low",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+	},
+	.reg_div	= { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
+};
+
+/*
+ * The following clocks will be disabled during clock initialization. It is
+ * recommended to keep the following clocks disabled until the driver requests
+ * for enabling the clock.
+ */
+static struct clk init_clocks_disable[] = {
+	{
+		.name		= "usbhost",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "pdma",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "hsmmc",
+		.id		= 0,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "hsmmc",
+		.id		= 1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "hsmmc",
+		.id		= 2,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 19),
+	}, {
+		.name		= "usbotg",
+		.id		= -1,
+		.parent		= &clk_hclk_low.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 20),
+	}, {
+		.name		= "lcd",
+		.id		= -1,
+		.parent		= &clk_h,
+		.enable		= s5p64x0_hclk1_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "watchdog",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "adc",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "i2c",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "spi",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "spi",
+		.id		= 1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 22),
+	}, {
+		.name		= "iis",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 26),
+	}, {
+		.name		= "i2c",
+		.id		= 1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 27),
+	}, {
+		.name		= "dmc0",
+		.id		= -1,
+		.parent		= &clk_pclk.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 30),
+	}
+};
+
+/*
+ * The following clocks will be enabled during clock initialization.
+ */
+static struct clk init_clocks[] = {
+	{
+		.name		= "intc",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "mem",
+		.id		= -1,
+		.parent		= &clk_hclk.clk,
+		.enable		= s5p64x0_hclk0_ctrl,
+		.ctrlbit	= (1 << 21),
+	}, {
+		.name		= "uart",
+		.id		= 0,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "uart",
+		.id		= 1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "uart",
+		.id		= 2,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "uart",
+		.id		= 3,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "timers",
+		.id		= -1,
+		.parent		= &clk_pclk_to_wdt_pwm.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "gpio",
+		.id		= -1,
+		.parent		= &clk_pclk_low.clk,
+		.enable		= s5p64x0_pclk_ctrl,
+		.ctrlbit	= (1 << 18),
+	},
+};
+
+static struct clk *clkset_uart_list[] = {
+	&clk_dout_epll.clk,
+	&clk_dout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_uart = {
+	.sources	= clkset_uart_list,
+	.nr_sources	= ARRAY_SIZE(clkset_uart_list),
+};
+
+static struct clk *clkset_mali_list[] = {
+	&clk_mout_epll.clk,
+	&clk_mout_apll.clk,
+	&clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_mali = {
+	.sources	= clkset_mali_list,
+	.nr_sources	= ARRAY_SIZE(clkset_mali_list),
+};
+
+static struct clk *clkset_group2_list[] = {
+	&clk_dout_epll.clk,
+	&clk_dout_mpll.clk,
+	&clk_ext_xtal_mux,
+};
+
+static struct clksrc_sources clkset_group2 = {
+	.sources	= clkset_group2_list,
+	.nr_sources	= ARRAY_SIZE(clkset_group2_list),
+};
+
+static struct clk *clkset_dispcon_list[] = {
+	&clk_dout_epll.clk,
+	&clk_dout_mpll.clk,
+	&clk_ext_xtal_mux,
+	&clk_mout_dpll.clk,
+};
+
+static struct clksrc_sources clkset_dispcon = {
+	.sources	= clkset_dispcon_list,
+	.nr_sources	= ARRAY_SIZE(clkset_dispcon_list),
+};
+
+static struct clk *clkset_hsmmc44_list[] = {
+	&clk_dout_epll.clk,
+	&clk_dout_mpll.clk,
+	&clk_ext_xtal_mux,
+	&s5p_clk_27m,
+	&clk_48m,
+};
+
+static struct clksrc_sources clkset_hsmmc44 = {
+	.sources	= clkset_hsmmc44_list,
+	.nr_sources	= ARRAY_SIZE(clkset_hsmmc44_list),
+};
+
+static struct clk *clkset_sclk_audio0_list[] = {
+	[0] = &clk_dout_epll.clk,
+	[1] = &clk_dout_mpll.clk,
+	[2] = &clk_ext_xtal_mux,
+	[3] = NULL,
+	[4] = NULL,
+};
+
+static struct clksrc_sources clkset_sclk_audio0 = {
+	.sources	= clkset_sclk_audio0_list,
+	.nr_sources	= ARRAY_SIZE(clkset_sclk_audio0_list),
+};
+
+static struct clksrc_clk clk_sclk_audio0 = {
+	.clk		= {
+		.name		= "audio-bus",
+		.id		= -1,
+		.enable		= s5p64x0_sclk_ctrl,
+		.ctrlbit	= (1 << 8),
+		.parent		= &clk_dout_epll.clk,
+	},
+	.sources	= &clkset_sclk_audio0,
+	.reg_src	= { .reg = S5P64X0_CLK_SRC1, .shift = 10, .size = 3 },
+	.reg_div	= { .reg = S5P64X0_CLK_DIV2, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clksrcs[] = {
+	{
+		.clk	= {
+			.name		= "sclk_mmc",
+			.id		= 0,
+			.ctrlbit	= (1 << 24),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_mmc",
+			.id		= 1,
+			.ctrlbit	= (1 << 25),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_mmc",
+			.id		= 2,
+			.ctrlbit	= (1 << 26),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "uclk1",
+			.id		= -1,
+			.ctrlbit	= (1 << 5),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_uart,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_spi",
+			.id		= 0,
+			.ctrlbit	= (1 << 20),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_spi",
+			.id		= 1,
+			.ctrlbit	= (1 << 21),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_fimc",
+			.id		= -1,
+			.ctrlbit	= (1 << 10),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "aclk_mali",
+			.id		= -1,
+			.ctrlbit	= (1 << 2),
+			.enable		= s5p64x0_sclk1_ctrl,
+		},
+		.sources = &clkset_mali,
+		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_2d",
+			.id		= -1,
+			.ctrlbit	= (1 << 12),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_mali,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 30, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 20, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_usi",
+			.id		= -1,
+			.ctrlbit	= (1 << 7),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 10, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 16, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_camif",
+			.id		= -1,
+			.ctrlbit	= (1 << 6),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_group2,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 28, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 20, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_dispcon",
+			.id		= -1,
+			.ctrlbit	= (1 << 1),
+			.enable		= s5p64x0_sclk1_ctrl,
+		},
+		.sources = &clkset_dispcon,
+		.reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
+	}, {
+		.clk	= {
+			.name		= "sclk_hsmmc44",
+			.id		= -1,
+			.ctrlbit	= (1 << 30),
+			.enable		= s5p64x0_sclk_ctrl,
+		},
+		.sources = &clkset_hsmmc44,
+		.reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 6, .size = 3 },
+		.reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 28, .size = 4 },
+	},
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *sysclks[] = {
+	&clk_mout_apll,
+	&clk_mout_epll,
+	&clk_dout_epll,
+	&clk_mout_mpll,
+	&clk_dout_mpll,
+	&clk_armclk,
+	&clk_mout_hclk_sel,
+	&clk_dout_pwm_ratio0,
+	&clk_pclk_to_wdt_pwm,
+	&clk_hclk,
+	&clk_pclk,
+	&clk_hclk_low,
+	&clk_pclk_low,
+	&clk_sclk_audio0,
+};
+
+void __init_or_cpufreq s5p6450_setup_clocks(void)
+{
+	struct clk *xtal_clk;
+
+	unsigned long xtal;
+	unsigned long fclk;
+	unsigned long hclk;
+	unsigned long hclk_low;
+	unsigned long pclk;
+	unsigned long pclk_low;
+
+	unsigned long apll;
+	unsigned long mpll;
+	unsigned long epll;
+	unsigned long dpll;
+	unsigned int ptr;
+
+	/* Set S5P6450 functions for clk_fout_epll */
+
+	clk_fout_epll.enable = s5p_epll_enable;
+	clk_fout_epll.ops = &s5p6450_epll_ops;
+
+	clk_48m.enable = s5p64x0_clk48m_ctrl;
+
+	xtal_clk = clk_get(NULL, "ext_xtal");
+	BUG_ON(IS_ERR(xtal_clk));
+
+	xtal = clk_get_rate(xtal_clk);
+	clk_put(xtal_clk);
+
+	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
+	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
+	epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
+				__raw_readl(S5P64X0_EPLL_CON_K));
+	dpll = s5p_get_pll46xx(xtal, __raw_readl(S5P6450_DPLL_CON),
+				__raw_readl(S5P6450_DPLL_CON_K), pll_4650c);
+
+	clk_fout_apll.rate = apll;
+	clk_fout_mpll.rate = mpll;
+	clk_fout_epll.rate = epll;
+	clk_fout_dpll.rate = dpll;
+
+	printk(KERN_INFO "S5P6450: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
+			" E=%ld.%ldMHz, D=%ld.%ldMHz\n",
+			print_mhz(apll), print_mhz(mpll), print_mhz(epll),
+			print_mhz(dpll));
+
+	fclk = clk_get_rate(&clk_armclk.clk);
+	hclk = clk_get_rate(&clk_hclk.clk);
+	pclk = clk_get_rate(&clk_pclk.clk);
+	hclk_low = clk_get_rate(&clk_hclk_low.clk);
+	pclk_low = clk_get_rate(&clk_pclk_low.clk);
+
+	printk(KERN_INFO "S5P6450: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
+			" PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
+			print_mhz(hclk), print_mhz(hclk_low),
+			print_mhz(pclk), print_mhz(pclk_low));
+
+	clk_f.rate = fclk;
+	clk_h.rate = hclk;
+	clk_p.rate = pclk;
+
+	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+		s3c_set_clksrc(&clksrcs[ptr], true);
+}
+
+void __init s5p6450_register_clocks(void)
+{
+	struct clk *clkp;
+	int ret;
+	int ptr;
+
+	for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
+		s3c_register_clksrc(sysclks[ptr], 1);
+
+	s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
+	s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+	clkp = init_clocks_disable;
+	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+		ret = s3c24xx_register_clock(clkp);
+		if (ret < 0) {
+			printk(KERN_ERR "Failed to register clock %s (%d)\n",
+			       clkp->name, ret);
+		}
+		(clkp->enable)(clkp, 0);
+	}
+
+	s3c_pwmclk_init();
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/cpu.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,209 @@
+/* linux/arch/arm/mach-s5p64x0/cpu.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/regs-serial.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+#include <plat/adc-core.h>
+
+/* Initial IO mappings */
+
+static struct map_desc s5p64x0_iodesc[] __initdata = {
+	{
+		.virtual	= (unsigned long)S5P_VA_GPIO,
+		.pfn		= __phys_to_pfn(S5P64X0_PA_GPIO),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC0,
+		.pfn		= __phys_to_pfn(S5P64X0_PA_VIC0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC1,
+		.pfn		= __phys_to_pfn(S5P64X0_PA_VIC1),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	},
+};
+
+static struct map_desc s5p6440_iodesc[] __initdata = {
+	{
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S5P6440_PA_UART(0)),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+};
+
+static struct map_desc s5p6450_iodesc[] __initdata = {
+	{
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S5P6450_PA_UART(0)),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_UART + SZ_512K,
+		.pfn		= __phys_to_pfn(S5P6450_PA_UART(5)),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	},
+};
+
+static void s5p64x0_idle(void)
+{
+	unsigned long val;
+
+	if (!need_resched()) {
+		val = __raw_readl(S5P64X0_PWR_CFG);
+		val &= ~(0x3 << 5);
+		val |= (0x1 << 5);
+		__raw_writel(val, S5P64X0_PWR_CFG);
+
+		cpu_do_idle();
+	}
+	local_irq_enable();
+}
+
+/*
+ * s5p64x0_map_io
+ *
+ * register the standard CPU IO areas
+ */
+
+void __init s5p6440_map_io(void)
+{
+	/* initialize any device information early */
+	s3c_adc_setname("s3c64xx-adc");
+
+	iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc));
+	iotable_init(s5p6440_iodesc, ARRAY_SIZE(s5p6440_iodesc));
+}
+
+void __init s5p6450_map_io(void)
+{
+	/* initialize any device information early */
+	s3c_adc_setname("s3c64xx-adc");
+
+	iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc));
+	iotable_init(s5p6450_iodesc, ARRAY_SIZE(s5p6440_iodesc));
+}
+
+/*
+ * s5p64x0_init_clocks
+ *
+ * register and setup the CPU clocks
+ */
+
+void __init s5p6440_init_clocks(int xtal)
+{
+	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+	s3c24xx_register_baseclocks(xtal);
+	s5p_register_clocks(xtal);
+	s5p6440_register_clocks();
+	s5p6440_setup_clocks();
+}
+
+void __init s5p6450_init_clocks(int xtal)
+{
+	printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+	s3c24xx_register_baseclocks(xtal);
+	s5p_register_clocks(xtal);
+	s5p6450_register_clocks();
+	s5p6450_setup_clocks();
+}
+
+/*
+ * s5p64x0_init_irq
+ *
+ * register the CPU interrupts
+ */
+
+void __init s5p6440_init_irq(void)
+{
+	/* S5P6440 supports 2 VIC */
+	u32 vic[2];
+
+	/*
+	 * VIC0 is missing IRQ_VIC0[3, 4, 8, 10, (12-22)]
+	 * VIC1 is missing IRQ VIC1[1, 3, 4, 10, 11, 12, 14, 15, 22]
+	 */
+	vic[0] = 0xff800ae7;
+	vic[1] = 0xffbf23e5;
+
+	s5p_init_irq(vic, ARRAY_SIZE(vic));
+}
+
+void __init s5p6450_init_irq(void)
+{
+	/* S5P6450 supports only 2 VIC */
+	u32 vic[2];
+
+	/*
+	 * VIC0 is missing IRQ_VIC0[(13-15), (21-22)]
+	 * VIC1 is missing IRQ VIC1[12, 14, 23]
+	 */
+	vic[0] = 0xff9f1fff;
+	vic[1] = 0xff7fafff;
+
+	s5p_init_irq(vic, ARRAY_SIZE(vic));
+}
+
+struct sysdev_class s5p64x0_sysclass = {
+	.name	= "s5p64x0-core",
+};
+
+static struct sys_device s5p64x0_sysdev = {
+	.cls	= &s5p64x0_sysclass,
+};
+
+static int __init s5p64x0_core_init(void)
+{
+	return sysdev_class_register(&s5p64x0_sysclass);
+}
+core_initcall(s5p64x0_core_init);
+
+int __init s5p64x0_init(void)
+{
+	printk(KERN_INFO "S5P64X0(S5P6440/S5P6450): Initializing architecture\n");
+
+	/* set idle function */
+	pm_idle = s5p64x0_idle;
+
+	return sysdev_register(&s5p64x0_sysdev);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dev-audio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dev-audio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,152 @@
+/* linux/arch/arm/mach-s5p64x0/dev-audio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *	Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+static int s5p6440_cfg_i2s(struct platform_device *pdev)
+{
+	/* configure GPIO for i2s port */
+	switch (pdev->id) {
+	case -1:
+		s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5));
+		s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5));
+		break;
+
+	default:
+		printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int s5p6450_cfg_i2s(struct platform_device *pdev)
+{
+	/* configure GPIO for i2s port */
+	switch (pdev->id) {
+	case -1:
+		s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5));
+		s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5));
+		s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5));
+
+		break;
+
+	default:
+		printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct s3c_audio_pdata s5p6440_i2s_pdata = {
+	.cfg_gpio = s5p6440_cfg_i2s,
+};
+
+static struct s3c_audio_pdata s5p6450_i2s_pdata = {
+	.cfg_gpio = s5p6450_cfg_i2s,
+};
+
+static struct resource s5p64x0_iis0_resource[] = {
+	[0] = {
+		.start	= S5P64X0_PA_I2S,
+		.end	= S5P64X0_PA_I2S + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_I2S0_TX,
+		.end	= DMACH_I2S0_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[2] = {
+		.start	= DMACH_I2S0_RX,
+		.end	= DMACH_I2S0_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device s5p6440_device_iis = {
+	.name		= "s3c64xx-iis-v4",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5p64x0_iis0_resource),
+	.resource	= s5p64x0_iis0_resource,
+	.dev = {
+		.platform_data = &s5p6440_i2s_pdata,
+	},
+};
+
+struct platform_device s5p6450_device_iis0 = {
+	.name		= "s3c64xx-iis-v4",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5p64x0_iis0_resource),
+	.resource	= s5p64x0_iis0_resource,
+	.dev = {
+		.platform_data = &s5p6450_i2s_pdata,
+	},
+};
+
+/* PCM Controller platform_devices */
+
+static int s5p6440_pcm_cfg_gpio(struct platform_device *pdev)
+{
+	switch (pdev->id) {
+	case 0:
+		s3c_gpio_cfgpin_range(S5P6440_GPR(6), 3, S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(2));
+		break;
+
+	default:
+		printk(KERN_DEBUG "Invalid PCM Controller number!");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct s3c_audio_pdata s5p6440_pcm_pdata = {
+	.cfg_gpio = s5p6440_pcm_cfg_gpio,
+};
+
+static struct resource s5p6440_pcm0_resource[] = {
+	[0] = {
+		.start	= S5P64X0_PA_PCM,
+		.end	= S5P64X0_PA_PCM + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_PCM0_TX,
+		.end	= DMACH_PCM0_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[2] = {
+		.start	= DMACH_PCM0_RX,
+		.end	= DMACH_PCM0_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+struct platform_device s5p6440_device_pcm = {
+	.name		= "samsung-pcm",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(s5p6440_pcm0_resource),
+	.resource	= s5p6440_pcm0_resource,
+	.dev = {
+		.platform_data = &s5p6440_pcm_pdata,
+	},
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dev-spi.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dev-spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dev-spi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dev-spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,222 @@
+/* linux/arch/arm/mach-s5p64x0/dev-spi.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *	Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/regs-clock.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+
+static char *s5p64x0_spi_src_clks[] = {
+	[S5P64X0_SPI_SRCCLK_PCLK] = "pclk",
+	[S5P64X0_SPI_SRCCLK_SCLK] = "sclk_spi",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5p6440_spi_cfg_gpio(struct platform_device *pdev)
+{
+	unsigned int base;
+
+	switch (pdev->id) {
+	case 0:
+		base = S5P6440_GPC(0);
+		break;
+
+	case 1:
+		base = S5P6440_GPC(4);
+		break;
+
+	default:
+		dev_err(&pdev->dev, "Invalid SPI Controller number!");
+		return -EINVAL;
+	}
+
+	s3c_gpio_cfgall_range(base, 3,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+	return 0;
+}
+
+static int s5p6450_spi_cfg_gpio(struct platform_device *pdev)
+{
+	unsigned int base;
+
+	switch (pdev->id) {
+	case 0:
+		base = S5P6450_GPC(0);
+		break;
+
+	case 1:
+		base = S5P6450_GPC(4);
+		break;
+
+	default:
+		dev_err(&pdev->dev, "Invalid SPI Controller number!");
+		return -EINVAL;
+	}
+
+	s3c_gpio_cfgall_range(base, 3,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
+	return 0;
+}
+
+static struct resource s5p64x0_spi0_resource[] = {
+	[0] = {
+		.start	= S5P64X0_PA_SPI0,
+		.end	= S5P64X0_PA_SPI0 + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_SPI0_TX,
+		.end	= DMACH_SPI0_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[2] = {
+		.start	= DMACH_SPI0_RX,
+		.end	= DMACH_SPI0_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= IRQ_SPI0,
+		.end	= IRQ_SPI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
+	.cfg_gpio	= s5p6440_spi_cfg_gpio,
+	.fifo_lvl_mask	= 0x1ff,
+	.rx_lvl_offset	= 15,
+};
+
+static struct s3c64xx_spi_info s5p6450_spi0_pdata = {
+	.cfg_gpio	= s5p6450_spi_cfg_gpio,
+	.fifo_lvl_mask	= 0x1ff,
+	.rx_lvl_offset	= 15,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5p64x0_device_spi0 = {
+	.name		= "s3c64xx-spi",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(s5p64x0_spi0_resource),
+	.resource	= s5p64x0_spi0_resource,
+	.dev = {
+		.dma_mask		= &spi_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+static struct resource s5p64x0_spi1_resource[] = {
+	[0] = {
+		.start	= S5P64X0_PA_SPI1,
+		.end	= S5P64X0_PA_SPI1 + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_SPI1_TX,
+		.end	= DMACH_SPI1_TX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[2] = {
+		.start	= DMACH_SPI1_RX,
+		.end	= DMACH_SPI1_RX,
+		.flags	= IORESOURCE_DMA,
+	},
+	[3] = {
+		.start	= IRQ_SPI1,
+		.end	= IRQ_SPI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
+	.cfg_gpio	= s5p6440_spi_cfg_gpio,
+	.fifo_lvl_mask	= 0x7f,
+	.rx_lvl_offset	= 15,
+};
+
+static struct s3c64xx_spi_info s5p6450_spi1_pdata = {
+	.cfg_gpio	= s5p6450_spi_cfg_gpio,
+	.fifo_lvl_mask	= 0x7f,
+	.rx_lvl_offset	= 15,
+};
+
+struct platform_device s5p64x0_device_spi1 = {
+	.name		= "s3c64xx-spi",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(s5p64x0_spi1_resource),
+	.resource	= s5p64x0_spi1_resource,
+	.dev = {
+		.dma_mask		= &spi_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
+void __init s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+	unsigned int id;
+	struct s3c64xx_spi_info *pd;
+
+	id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
+
+	/* Reject invalid configuration */
+	if (!num_cs || src_clk_nr < 0
+			|| src_clk_nr > S5P64X0_SPI_SRCCLK_SCLK) {
+		printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+		return;
+	}
+
+	switch (cntrlr) {
+	case 0:
+		if (id == 0x50000)
+			pd = &s5p6450_spi0_pdata;
+		else
+			pd = &s5p6440_spi0_pdata;
+
+		s5p64x0_device_spi0.dev.platform_data = pd;
+		break;
+	case 1:
+		if (id == 0x50000)
+			pd = &s5p6450_spi1_pdata;
+		else
+			pd = &s5p6440_spi1_pdata;
+
+		s5p64x0_device_spi1.dev.platform_data = pd;
+		break;
+	default:
+		printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+							__func__, cntrlr);
+		return;
+	}
+
+	pd->num_cs = num_cs;
+	pd->src_clk_nr = src_clk_nr;
+	pd->src_clk_name = s5p64x0_spi_src_clks[src_clk_nr];
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/dma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,149 @@
+/* linux/arch/arm/mach-s5p64x0/dma.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *	Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/regs-clock.h>
+
+#include <plat/devs.h>
+#include <plat/s3c-pl330-pdata.h>
+
+static u64 dma_dmamask = DMA_BIT_MASK(32);
+
+static struct resource s5p64x0_pdma_resource[] = {
+	[0] = {
+		.start	= S5P64X0_PA_PDMA,
+		.end	= S5P64X0_PA_PDMA + SZ_4K,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_DMA0,
+		.end	= IRQ_DMA0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct s3c_pl330_platdata s5p6440_pdma_pdata = {
+	.peri = {
+		[0] = DMACH_UART0_RX,
+		[1] = DMACH_UART0_TX,
+		[2] = DMACH_UART1_RX,
+		[3] = DMACH_UART1_TX,
+		[4] = DMACH_UART2_RX,
+		[5] = DMACH_UART2_TX,
+		[6] = DMACH_UART3_RX,
+		[7] = DMACH_UART3_TX,
+		[8] = DMACH_MAX,
+		[9] = DMACH_MAX,
+		[10] = DMACH_PCM0_TX,
+		[11] = DMACH_PCM0_RX,
+		[12] = DMACH_I2S0_TX,
+		[13] = DMACH_I2S0_RX,
+		[14] = DMACH_SPI0_TX,
+		[15] = DMACH_SPI0_RX,
+		[16] = DMACH_MAX,
+		[17] = DMACH_MAX,
+		[18] = DMACH_MAX,
+		[19] = DMACH_MAX,
+		[20] = DMACH_SPI1_TX,
+		[21] = DMACH_SPI1_RX,
+		[22] = DMACH_MAX,
+		[23] = DMACH_MAX,
+		[24] = DMACH_MAX,
+		[25] = DMACH_MAX,
+		[26] = DMACH_MAX,
+		[27] = DMACH_MAX,
+		[28] = DMACH_MAX,
+		[29] = DMACH_PWM,
+		[30] = DMACH_MAX,
+		[31] = DMACH_MAX,
+	},
+};
+
+static struct s3c_pl330_platdata s5p6450_pdma_pdata = {
+	.peri = {
+		[0] = DMACH_UART0_RX,
+		[1] = DMACH_UART0_TX,
+		[2] = DMACH_UART1_RX,
+		[3] = DMACH_UART1_TX,
+		[4] = DMACH_UART2_RX,
+		[5] = DMACH_UART2_TX,
+		[6] = DMACH_UART3_RX,
+		[7] = DMACH_UART3_TX,
+		[8] = DMACH_UART4_RX,
+		[9] = DMACH_UART4_TX,
+		[10] = DMACH_PCM0_TX,
+		[11] = DMACH_PCM0_RX,
+		[12] = DMACH_I2S0_TX,
+		[13] = DMACH_I2S0_RX,
+		[14] = DMACH_SPI0_TX,
+		[15] = DMACH_SPI0_RX,
+		[16] = DMACH_PCM1_TX,
+		[17] = DMACH_PCM1_RX,
+		[18] = DMACH_PCM2_TX,
+		[19] = DMACH_PCM2_RX,
+		[20] = DMACH_SPI1_TX,
+		[21] = DMACH_SPI1_RX,
+		[22] = DMACH_USI_TX,
+		[23] = DMACH_USI_RX,
+		[24] = DMACH_MAX,
+		[25] = DMACH_I2S1_TX,
+		[26] = DMACH_I2S1_RX,
+		[27] = DMACH_I2S2_TX,
+		[28] = DMACH_I2S2_RX,
+		[29] = DMACH_PWM,
+		[30] = DMACH_UART5_RX,
+		[31] = DMACH_UART5_TX,
+	},
+};
+
+static struct platform_device s5p64x0_device_pdma = {
+	.name		= "s3c-pl330",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5p64x0_pdma_resource),
+	.resource	= s5p64x0_pdma_resource,
+	.dev		= {
+		.dma_mask = &dma_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static int __init s5p64x0_dma_init(void)
+{
+	unsigned int id;
+
+	id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
+
+	if (id == 0x50000)
+		s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
+	else
+		s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
+
+	platform_device_register(&s5p64x0_device_pdma);
+
+	return 0;
+}
+arch_initcall(s5p64x0_dma_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,342 @@
+/* linux/arch/arm/mach-s5p64x0/gpio.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - GPIOlib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+#include <mach/regs-gpio.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+/* To be implemented S5P6450 GPIO */
+
+/*
+ * S5P6440 GPIO bank summary:
+ *
+ * Bank	GPIOs	Style	SlpCon	ExtInt Group
+ * A	6	4Bit	Yes	1
+ * B	7	4Bit	Yes	1
+ * C	8	4Bit	Yes	2
+ * F	2	2Bit	Yes	4 [1]
+ * G	7	4Bit	Yes	5
+ * H	10	4Bit[2]	Yes	6
+ * I	16	2Bit	Yes	None
+ * J	12	2Bit	Yes	None
+ * N	16	2Bit	No	IRQ_EINT
+ * P	8	2Bit	Yes	8
+ * R	15	4Bit[2]	Yes	8
+ *
+ * [1] BANKF pins 14,15 do not form part of the external interrupt sources
+ * [2] BANK has two control registers, GPxCON0 and GPxCON1
+ */
+
+static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
+					     unsigned int offset)
+{
+	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+	void __iomem *base = ourchip->base;
+	void __iomem *regcon = base;
+	unsigned long con;
+	unsigned long flags;
+
+	switch (offset) {
+	case 6:
+		offset += 1;
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		regcon -= 4;
+		break;
+	default:
+		offset -= 7;
+		break;
+	}
+
+	s3c_gpio_lock(ourchip, flags);
+
+	con = __raw_readl(regcon);
+	con &= ~(0xf << con_4bit_shift(offset));
+	__raw_writel(con, regcon);
+
+	s3c_gpio_unlock(ourchip, flags);
+
+	return 0;
+}
+
+static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
+					      unsigned int offset, int value)
+{
+	struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
+	void __iomem *base = ourchip->base;
+	void __iomem *regcon = base;
+	unsigned long con;
+	unsigned long dat;
+	unsigned long flags;
+	unsigned con_offset  = offset;
+
+	switch (con_offset) {
+	case 6:
+		con_offset += 1;
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		regcon -= 4;
+		break;
+	default:
+		con_offset -= 7;
+		break;
+	}
+
+	s3c_gpio_lock(ourchip, flags);
+
+	con = __raw_readl(regcon);
+	con &= ~(0xf << con_4bit_shift(con_offset));
+	con |= 0x1 << con_4bit_shift(con_offset);
+
+	dat = __raw_readl(base + GPIODAT_OFF);
+	if (value)
+		dat |= 1 << offset;
+	else
+		dat &= ~(1 << offset);
+
+	__raw_writel(con, regcon);
+	__raw_writel(dat, base + GPIODAT_OFF);
+
+	s3c_gpio_unlock(ourchip, flags);
+
+	return 0;
+}
+
+int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
+				   unsigned int off, unsigned int cfg)
+{
+	void __iomem *reg = chip->base;
+	unsigned int shift;
+	u32 con;
+
+	switch (off) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+		shift = (off & 7) * 4;
+		reg -= 4;
+		break;
+	case 6:
+		shift = ((off + 1) & 7) * 4;
+		reg -= 4;
+	default:
+		shift = ((off + 1) & 7) * 4;
+		break;
+	}
+
+	if (s3c_gpio_is_cfg_special(cfg)) {
+		cfg &= 0xf;
+		cfg <<= shift;
+	}
+
+	con = __raw_readl(reg);
+	con &= ~(0xf << shift);
+	con |= cfg;
+	__raw_writel(con, reg);
+
+	return 0;
+}
+
+static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
+	{
+		.cfg_eint	= 0,
+	}, {
+		.cfg_eint	= 7,
+	}, {
+		.cfg_eint	= 3,
+		.set_config	= s5p64x0_gpio_setcfg_4bit_rbank,
+	}, {
+		.cfg_eint	= 0,
+		.set_config	= s3c_gpio_setcfg_s3c24xx,
+		.get_config	= s3c_gpio_getcfg_s3c24xx,
+	}, {
+		.cfg_eint	= 2,
+		.set_config	= s3c_gpio_setcfg_s3c24xx,
+		.get_config	= s3c_gpio_getcfg_s3c24xx,
+	}, {
+		.cfg_eint	= 3,
+		.set_config	= s3c_gpio_setcfg_s3c24xx,
+		.get_config	= s3c_gpio_getcfg_s3c24xx,
+	},
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
+	{
+		.base	= S5P6440_GPA_BASE,
+		.config	= &s5p64x0_gpio_cfgs[1],
+		.chip	= {
+			.base	= S5P6440_GPA(0),
+			.ngpio	= S5P6440_GPIO_A_NR,
+			.label	= "GPA",
+		},
+	}, {
+		.base	= S5P6440_GPB_BASE,
+		.config	= &s5p64x0_gpio_cfgs[1],
+		.chip	= {
+			.base	= S5P6440_GPB(0),
+			.ngpio	= S5P6440_GPIO_B_NR,
+			.label	= "GPB",
+		},
+	}, {
+		.base	= S5P6440_GPC_BASE,
+		.config	= &s5p64x0_gpio_cfgs[1],
+		.chip	= {
+			.base	= S5P6440_GPC(0),
+			.ngpio	= S5P6440_GPIO_C_NR,
+			.label	= "GPC",
+		},
+	}, {
+		.base	= S5P6440_GPG_BASE,
+		.config	= &s5p64x0_gpio_cfgs[1],
+		.chip	= {
+			.base	= S5P6440_GPG(0),
+			.ngpio	= S5P6440_GPIO_G_NR,
+			.label	= "GPG",
+		},
+	},
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
+	{
+		.base	= S5P6440_GPH_BASE + 0x4,
+		.config	= &s5p64x0_gpio_cfgs[1],
+		.chip	= {
+			.base	= S5P6440_GPH(0),
+			.ngpio	= S5P6440_GPIO_H_NR,
+			.label	= "GPH",
+		},
+	},
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
+	{
+		.base	= S5P6440_GPR_BASE + 0x4,
+		.config	= &s5p64x0_gpio_cfgs[2],
+		.chip	= {
+			.base	= S5P6440_GPR(0),
+			.ngpio	= S5P6440_GPIO_R_NR,
+			.label	= "GPR",
+		},
+	},
+};
+
+static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
+	{
+		.base	= S5P6440_GPF_BASE,
+		.config	= &s5p64x0_gpio_cfgs[5],
+		.chip	= {
+			.base	= S5P6440_GPF(0),
+			.ngpio	= S5P6440_GPIO_F_NR,
+			.label	= "GPF",
+		},
+	}, {
+		.base	= S5P6440_GPI_BASE,
+		.config	= &s5p64x0_gpio_cfgs[3],
+		.chip	= {
+			.base	= S5P6440_GPI(0),
+			.ngpio	= S5P6440_GPIO_I_NR,
+			.label	= "GPI",
+		},
+	}, {
+		.base	= S5P6440_GPJ_BASE,
+		.config	= &s5p64x0_gpio_cfgs[3],
+		.chip	= {
+			.base	= S5P6440_GPJ(0),
+			.ngpio	= S5P6440_GPIO_J_NR,
+			.label	= "GPJ",
+		},
+	}, {
+		.base	= S5P6440_GPN_BASE,
+		.config	= &s5p64x0_gpio_cfgs[4],
+		.chip	= {
+			.base	= S5P6440_GPN(0),
+			.ngpio	= S5P6440_GPIO_N_NR,
+			.label	= "GPN",
+		},
+	}, {
+		.base	= S5P6440_GPP_BASE,
+		.config	= &s5p64x0_gpio_cfgs[5],
+		.chip	= {
+			.base	= S5P6440_GPP(0),
+			.ngpio	= S5P6440_GPIO_P_NR,
+			.label	= "GPP",
+		},
+	},
+};
+
+void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
+{
+	for (; nr_chips > 0; nr_chips--, chipcfg++) {
+		if (!chipcfg->set_config)
+			chipcfg->set_config	= s3c_gpio_setcfg_s3c64xx_4bit;
+		if (!chipcfg->get_config)
+			chipcfg->get_config	= s3c_gpio_getcfg_s3c64xx_4bit;
+		if (!chipcfg->set_pull)
+			chipcfg->set_pull	= s3c_gpio_setpull_updown;
+		if (!chipcfg->get_pull)
+			chipcfg->get_pull	= s3c_gpio_getpull_updown;
+	}
+}
+
+static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
+						int nr_chips)
+{
+	for (; nr_chips > 0; nr_chips--, chip++) {
+		chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
+		chip->chip.direction_output =
+					s5p64x0_gpiolib_rbank_4bit2_output;
+		s3c_gpiolib_add(chip);
+	}
+}
+
+static int __init s5p6440_gpiolib_init(void)
+{
+	struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
+	int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
+
+	s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
+				ARRAY_SIZE(s5p64x0_gpio_cfgs));
+
+	for (; nr_chips > 0; nr_chips--, chips++)
+		s3c_gpiolib_add(chips);
+
+	samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit,
+				ARRAY_SIZE(s5p6440_gpio_4bit));
+
+	samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
+				ARRAY_SIZE(s5p6440_gpio_4bit2));
+
+	s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
+				ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
+
+	return 0;
+}
+arch_initcall(s5p6440_gpiolib_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/debug-macro.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,33 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/debug-macro.S
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* pull in the relevant register and map files. */
+
+#include <plat/map-base.h>
+#include <plat/map-s5p.h>
+
+#include <plat/regs-serial.h>
+
+	.macro addruart, rp, rv
+		mov	\rp, #0xE0000000
+		orr	\rp, \rp, #0x00100000
+		ldr	\rp, [\rp, #0x118 ]
+		and	\rp, \rp, #0xff000
+		teq	\rp, #0x50000		@@ S5P6450
+		ldreq	\rp, =0xEC800000
+		movne	\rp, #0xEC000000	@@ S5P6440
+		ldrne	\rv, = S3C_VA_UART
+#if CONFIG_DEBUG_S3C_UART != 0
+		add	\rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
+#endif
+	.endm
+
+#include <plat/debug-macro.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/dma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *	Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MACH_DMA_H
+#define __MACH_DMA_H
+
+/* This platform uses the common S3C DMA API driver for PL330 */
+#include <plat/s3c-dma-pl330.h>
+
+#endif /* __MACH_DMA_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/entry-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/entry-macro.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/entry-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Low-level IRQ helper macros for the Samsung S5P64X0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <mach/map.h>
+#include <plat/irqs.h>
+
+#include <asm/entry-macro-vic2.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/gpio.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,139 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/gpio.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - GPIO lib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H __FILE__
+
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+#define gpio_to_irq	__gpio_to_irq
+
+/* GPIO bank sizes */
+
+#define S5P6440_GPIO_A_NR	(6)
+#define S5P6440_GPIO_B_NR	(7)
+#define S5P6440_GPIO_C_NR	(8)
+#define S5P6440_GPIO_F_NR	(2)
+#define S5P6440_GPIO_G_NR	(7)
+#define S5P6440_GPIO_H_NR	(10)
+#define S5P6440_GPIO_I_NR	(16)
+#define S5P6440_GPIO_J_NR	(12)
+#define S5P6440_GPIO_N_NR	(16)
+#define S5P6440_GPIO_P_NR	(8)
+#define S5P6440_GPIO_R_NR	(15)
+
+#define S5P6450_GPIO_A_NR	(6)
+#define S5P6450_GPIO_B_NR	(7)
+#define S5P6450_GPIO_C_NR	(8)
+#define S5P6450_GPIO_D_NR	(8)
+#define S5P6450_GPIO_F_NR	(2)
+#define S5P6450_GPIO_G_NR	(14)
+#define S5P6450_GPIO_H_NR	(10)
+#define S5P6450_GPIO_I_NR	(16)
+#define S5P6450_GPIO_J_NR	(12)
+#define S5P6450_GPIO_K_NR	(5)
+#define S5P6450_GPIO_N_NR	(16)
+#define S5P6450_GPIO_P_NR	(11)
+#define S5P6450_GPIO_Q_NR	(14)
+#define S5P6450_GPIO_R_NR	(15)
+#define S5P6450_GPIO_S_NR	(8)
+
+/* GPIO bank numbers */
+
+/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
+ * space for debugging purposes so that any accidental
+ * change from one gpio bank to another can be caught.
+*/
+
+#define S5P64X0_GPIO_NEXT(__gpio) \
+	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+enum s5p6440_gpio_number {
+	S5P6440_GPIO_A_START	= 0,
+	S5P6440_GPIO_B_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_A),
+	S5P6440_GPIO_C_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_B),
+	S5P6440_GPIO_F_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_C),
+	S5P6440_GPIO_G_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_F),
+	S5P6440_GPIO_H_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_G),
+	S5P6440_GPIO_I_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_H),
+	S5P6440_GPIO_J_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_I),
+	S5P6440_GPIO_N_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_J),
+	S5P6440_GPIO_P_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_N),
+	S5P6440_GPIO_R_START	= S5P64X0_GPIO_NEXT(S5P6440_GPIO_P),
+};
+
+enum s5p6450_gpio_number {
+	S5P6450_GPIO_A_START	= 0,
+	S5P6450_GPIO_B_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_A),
+	S5P6450_GPIO_C_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_B),
+	S5P6450_GPIO_D_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_C),
+	S5P6450_GPIO_F_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_D),
+	S5P6450_GPIO_G_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_F),
+	S5P6450_GPIO_H_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_G),
+	S5P6450_GPIO_I_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_H),
+	S5P6450_GPIO_J_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_I),
+	S5P6450_GPIO_K_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_J),
+	S5P6450_GPIO_N_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_K),
+	S5P6450_GPIO_P_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_N),
+	S5P6450_GPIO_Q_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_P),
+	S5P6450_GPIO_R_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_Q),
+	S5P6450_GPIO_S_START	= S5P64X0_GPIO_NEXT(S5P6450_GPIO_R),
+};
+
+/* GPIO number definitions */
+
+#define S5P6440_GPA(_nr)	(S5P6440_GPIO_A_START + (_nr))
+#define S5P6440_GPB(_nr)	(S5P6440_GPIO_B_START + (_nr))
+#define S5P6440_GPC(_nr)	(S5P6440_GPIO_C_START + (_nr))
+#define S5P6440_GPF(_nr)	(S5P6440_GPIO_F_START + (_nr))
+#define S5P6440_GPG(_nr)	(S5P6440_GPIO_G_START + (_nr))
+#define S5P6440_GPH(_nr)	(S5P6440_GPIO_H_START + (_nr))
+#define S5P6440_GPI(_nr)	(S5P6440_GPIO_I_START + (_nr))
+#define S5P6440_GPJ(_nr)	(S5P6440_GPIO_J_START + (_nr))
+#define S5P6440_GPN(_nr)	(S5P6440_GPIO_N_START + (_nr))
+#define S5P6440_GPP(_nr)	(S5P6440_GPIO_P_START + (_nr))
+#define S5P6440_GPR(_nr)	(S5P6440_GPIO_R_START + (_nr))
+
+#define S5P6450_GPA(_nr)	(S5P6450_GPIO_A_START + (_nr))
+#define S5P6450_GPB(_nr)	(S5P6450_GPIO_B_START + (_nr))
+#define S5P6450_GPC(_nr)	(S5P6450_GPIO_C_START + (_nr))
+#define S5P6450_GPD(_nr)	(S5P6450_GPIO_D_START + (_nr))
+#define S5P6450_GPF(_nr)	(S5P6450_GPIO_F_START + (_nr))
+#define S5P6450_GPG(_nr)	(S5P6450_GPIO_G_START + (_nr))
+#define S5P6450_GPH(_nr)	(S5P6450_GPIO_H_START + (_nr))
+#define S5P6450_GPI(_nr)	(S5P6450_GPIO_I_START + (_nr))
+#define S5P6450_GPJ(_nr)	(S5P6450_GPIO_J_START + (_nr))
+#define S5P6450_GPK(_nr)	(S5P6450_GPIO_K_START + (_nr))
+#define S5P6450_GPN(_nr)	(S5P6450_GPIO_N_START + (_nr))
+#define S5P6450_GPP(_nr)	(S5P6450_GPIO_P_START + (_nr))
+#define S5P6450_GPQ(_nr)	(S5P6450_GPIO_Q_START + (_nr))
+#define S5P6450_GPR(_nr)	(S5P6450_GPIO_R_START + (_nr))
+#define S5P6450_GPS(_nr)	(S5P6450_GPIO_S_START + (_nr))
+
+/* the end of the S5P64X0 specific gpios */
+
+#define S5P6440_GPIO_END	(S5P6440_GPR(S5P6440_GPIO_R_NR) + 1)
+#define S5P6450_GPIO_END	(S5P6450_GPS(S5P6450_GPIO_S_NR) + 1)
+
+#define S5P64X0_GPIO_END	(S5P6440_GPIO_END > S5P6450_GPIO_END ?	\
+				 S5P6440_GPIO_END : S5P6450_GPIO_END)
+
+#define S3C_GPIO_END		S5P64X0_GPIO_END
+
+/* define the number of gpios we need to the one after the last GPIO range */
+
+#define ARCH_NR_GPIOS		(S5P64X0_GPIO_END + CONFIG_SAMSUNG_GPIO_EXTRA)
+
+#include <asm-generic/gpio.h>
+
+#endif /* __ASM_ARCH_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/hardware.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/hardware.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/hardware.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,18 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/hardware.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Hardware support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H __FILE__
+
+/* currently nothing here, placeholder */
+
+#endif /* __ASM_ARCH_HARDWARE_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/i2c.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/i2c.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/i2c.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/i2c.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/i2c.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 I2C configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+extern void s5p6440_i2c0_cfg_gpio(struct platform_device *dev);
+extern void s5p6440_i2c1_cfg_gpio(struct platform_device *dev);
+
+extern void s5p6450_i2c0_cfg_gpio(struct platform_device *dev);
+extern void s5p6450_i2c1_cfg_gpio(struct platform_device *dev);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/io.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/io.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/io.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/io.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright 2008 Simtec Electronics
+ *	Ben Dooks <ben-linux@fluff.org>
+ *
+ * Default IO routines for S5P64X0 based
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/* No current ISA/PCI bus support. */
+#define __io(a)		__typesafe_io(a)
+#define __mem_pci(a)	(a)
+
+#define IO_SPACE_LIMIT (0xFFFFFFFF)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/irqs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,142 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/irqs.h
+ *
+ * Copyright 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - IRQ definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H __FILE__
+
+#include <plat/irqs.h>
+
+/* VIC0 */
+
+#define IRQ_EINT0_3		S5P_IRQ_VIC0(0)
+#define IRQ_EINT4_11		S5P_IRQ_VIC0(1)
+#define IRQ_RTC_TIC		S5P_IRQ_VIC0(2)
+#define IRQ_IIS1		S5P_IRQ_VIC0(3)	/* for only S5P6450 */
+#define IRQ_IIS2		S5P_IRQ_VIC0(4)	/* for only S5P6450 */
+#define IRQ_IIC1		S5P_IRQ_VIC0(5)
+#define IRQ_I2SV40		S5P_IRQ_VIC0(6)
+#define IRQ_GPS			S5P_IRQ_VIC0(7)	/* for only S5P6450 */
+
+#define IRQ_2D			S5P_IRQ_VIC0(11)
+#define IRQ_TIMER0_VIC		S5P_IRQ_VIC0(23)
+#define IRQ_TIMER1_VIC		S5P_IRQ_VIC0(24)
+#define IRQ_TIMER2_VIC		S5P_IRQ_VIC0(25)
+#define IRQ_WDT			S5P_IRQ_VIC0(26)
+#define IRQ_TIMER3_VIC		S5P_IRQ_VIC0(27)
+#define IRQ_TIMER4_VIC		S5P_IRQ_VIC0(28)
+#define IRQ_DISPCON0		S5P_IRQ_VIC0(29)
+#define IRQ_DISPCON1		S5P_IRQ_VIC0(30)
+#define IRQ_DISPCON2		S5P_IRQ_VIC0(31)
+
+/* VIC1 */
+
+#define IRQ_EINT12_15		S5P_IRQ_VIC1(0)
+#define IRQ_PCM0		S5P_IRQ_VIC1(2)
+#define IRQ_PCM1		S5P_IRQ_VIC1(3)	/* for only S5P6450 */
+#define IRQ_PCM2		S5P_IRQ_VIC1(4)	/* for only S5P6450 */
+#define IRQ_UART0		S5P_IRQ_VIC1(5)
+#define IRQ_UART1		S5P_IRQ_VIC1(6)
+#define IRQ_UART2		S5P_IRQ_VIC1(7)
+#define IRQ_UART3		S5P_IRQ_VIC1(8)
+#define IRQ_DMA0		S5P_IRQ_VIC1(9)
+#define IRQ_UART4		S5P_IRQ_VIC1(10)	/* S5P6450 */
+#define IRQ_UART5		S5P_IRQ_VIC1(11)	/* S5P6450 */
+#define IRQ_NFC			S5P_IRQ_VIC1(13)
+#define IRQ_USI			S5P_IRQ_VIC1(15)	/* S5P6450 */
+#define IRQ_SPI0		S5P_IRQ_VIC1(16)
+#define IRQ_SPI1		S5P_IRQ_VIC1(17)
+#define IRQ_HSMMC2		S5P_IRQ_VIC1(17)	/* Shared */
+#define IRQ_IIC			S5P_IRQ_VIC1(18)
+#define IRQ_DISPCON3		S5P_IRQ_VIC1(19)
+#define IRQ_EINT_GROUPS		S5P_IRQ_VIC1(21)
+#define IRQ_PMU			S5P_IRQ_VIC1(23)	/* S5P6440 */
+#define IRQ_HSMMC0		S5P_IRQ_VIC1(24)
+#define IRQ_HSMMC1		S5P_IRQ_VIC1(25)
+#define IRQ_OTG			S5P_IRQ_VIC1(26)
+#define IRQ_DSI			S5P_IRQ_VIC1(27)
+#define IRQ_RTC_ALARM		S5P_IRQ_VIC1(28)
+#define IRQ_TSI			S5P_IRQ_VIC1(29)
+#define IRQ_PENDN		S5P_IRQ_VIC1(30)
+#define IRQ_TC			IRQ_PENDN
+#define IRQ_ADC			S5P_IRQ_VIC1(31)
+
+/* UART interrupts, S5P6450 has 5 UARTs */
+#define IRQ_S5P_UART_BASE4	(96)
+#define IRQ_S5P_UART_BASE5	(100)
+
+#define IRQ_S5P_UART_RX4	(IRQ_S5P_UART_BASE4 + UART_IRQ_RXD)
+#define IRQ_S5P_UART_TX4	(IRQ_S5P_UART_BASE4 + UART_IRQ_TXD)
+#define IRQ_S5P_UART_ERR4	(IRQ_S5P_UART_BASE4 + UART_IRQ_ERR)
+
+#define IRQ_S5P_UART_RX5	(IRQ_S5P_UART_BASE5 + UART_IRQ_RXD)
+#define IRQ_S5P_UART_TX5	(IRQ_S5P_UART_BASE5 + UART_IRQ_TXD)
+#define IRQ_S5P_UART_ERR5	(IRQ_S5P_UART_BASE5 + UART_IRQ_ERR)
+
+/* S3C compatibilty defines */
+#define IRQ_S3CUART_RX4		IRQ_S5P_UART_RX4
+#define IRQ_S3CUART_RX5		IRQ_S5P_UART_RX5
+
+/* S5P6450 EINT feature will be added */
+
+/*
+ * Since the IRQ_EINT(x) are a linear mapping on s5p6440 we just defined
+ * them as an IRQ_EINT(x) macro from S5P_IRQ_EINT_BASE which we place
+ * after the pair of VICs.
+ */
+
+#define S5P_IRQ_EINT_BASE	(S5P_IRQ_VIC1(31) + 6)
+
+#define S5P_EINT(x)		((x) + S5P_IRQ_EINT_BASE)
+
+#define S5P_EINT_BASE1		(S5P_IRQ_EINT_BASE)
+/*
+ * S5P6440 has 0-15 external interrupts in group 0. Only these can be used
+ * to wake up from sleep. If request is beyond this range, by mistake, a large
+ * return value for an irq number should be indication of something amiss.
+ */
+#define S5P_EINT_BASE2		(0xf0000000)
+
+/*
+ * Next the external interrupt groups. These are similar to the IRQ_EINT(x)
+ * that they are sourced from the GPIO pins but with a different scheme for
+ * priority and source indication.
+ *
+ * The IRQ_EINT(x) can be thought of as 'group 0' of the available GPIO
+ * interrupts, but for historical reasons they are kept apart from these
+ * next interrupts.
+ *
+ * Use IRQ_EINT_GROUP(group, offset) to get the number for use in the
+ * machine specific support files.
+ */
+
+/* Actually, #6 and #7 are missing in the EINT_GROUP1 */
+#define IRQ_EINT_GROUP1_NR	(15)
+#define IRQ_EINT_GROUP2_NR	(8)
+#define IRQ_EINT_GROUP5_NR	(7)
+#define IRQ_EINT_GROUP6_NR	(10)
+/* Actually, #0, #1 and #2 are missing in the EINT_GROUP8 */
+#define IRQ_EINT_GROUP8_NR	(11)
+
+#define IRQ_EINT_GROUP_BASE	S5P_EINT(16)
+#define IRQ_EINT_GROUP1_BASE	(IRQ_EINT_GROUP_BASE + 0)
+#define IRQ_EINT_GROUP2_BASE	(IRQ_EINT_GROUP1_BASE + IRQ_EINT_GROUP1_NR)
+#define IRQ_EINT_GROUP5_BASE	(IRQ_EINT_GROUP2_BASE + IRQ_EINT_GROUP2_NR)
+#define IRQ_EINT_GROUP6_BASE	(IRQ_EINT_GROUP5_BASE + IRQ_EINT_GROUP5_NR)
+#define IRQ_EINT_GROUP8_BASE	(IRQ_EINT_GROUP6_BASE + IRQ_EINT_GROUP6_NR)
+
+#define IRQ_EINT_GROUP(grp, x)	(IRQ_EINT_GROUP##grp##_BASE + (x))
+
+/* Set the default NR_IRQS */
+
+#define NR_IRQS			(IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
+
+#endif /* __ASM_ARCH_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/map.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/map.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,83 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/map.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H __FILE__
+
+#include <plat/map-base.h>
+#include <plat/map-s5p.h>
+
+#define S5P64X0_PA_SDRAM	(0x20000000)
+
+#define S5P64X0_PA_CHIPID	(0xE0000000)
+#define S5P_PA_CHIPID		S5P64X0_PA_CHIPID
+
+#define S5P64X0_PA_SYSCON	(0xE0100000)
+#define S5P_PA_SYSCON		S5P64X0_PA_SYSCON
+
+#define S5P64X0_PA_GPIO		(0xE0308000)
+
+#define S5P64X0_PA_VIC0		(0xE4000000)
+#define S5P64X0_PA_VIC1		(0xE4100000)
+
+#define S5P64X0_PA_PDMA		(0xE9000000)
+
+#define S5P64X0_PA_TIMER	(0xEA000000)
+#define S5P_PA_TIMER		S5P64X0_PA_TIMER
+
+#define S5P64X0_PA_RTC		(0xEA100000)
+
+#define S5P64X0_PA_WDT		(0xEA200000)
+
+#define S5P6440_PA_UART(x)	(0xEC000000 + ((x) * S3C_UART_OFFSET))
+#define S5P6450_PA_UART(x)	((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+
+#define S5P_PA_UART0		S5P6450_PA_UART(0)
+#define S5P_PA_UART1		S5P6450_PA_UART(1)
+#define S5P_PA_UART2		S5P6450_PA_UART(2)
+#define S5P_PA_UART3		S5P6450_PA_UART(3)
+#define S5P_PA_UART4		S5P6450_PA_UART(4)
+#define S5P_PA_UART5		S5P6450_PA_UART(5)
+
+#define S5P_SZ_UART		SZ_256
+
+#define S5P6440_PA_IIC0		(0xEC104000)
+#define S5P6440_PA_IIC1		(0xEC20F000)
+#define S5P6450_PA_IIC0		(0xEC100000)
+#define S5P6450_PA_IIC1		(0xEC200000)
+
+#define S5P64X0_PA_SPI0		(0xEC400000)
+#define S5P64X0_PA_SPI1		(0xEC500000)
+
+#define S5P64X0_PA_HSOTG	(0xED100000)
+
+#define S5P64X0_PA_HSMMC(x)	(0xED800000 + ((x) * 0x100000))
+
+#define S5P64X0_PA_I2S		(0xF2000000)
+
+#define S5P64X0_PA_PCM		(0xF2100000)
+
+#define S5P64X0_PA_ADC		(0xF3000000)
+
+/* compatibiltiy defines. */
+
+#define S3C_PA_HSMMC0		S5P64X0_PA_HSMMC(0)
+#define S3C_PA_HSMMC1		S5P64X0_PA_HSMMC(1)
+#define S3C_PA_HSMMC2		S5P64X0_PA_HSMMC(2)
+#define S3C_PA_IIC		S5P6440_PA_IIC0
+#define S3C_PA_IIC1		S5P6440_PA_IIC1
+#define S3C_PA_RTC		S5P64X0_PA_RTC
+#define S3C_PA_WDT		S5P64X0_PA_WDT
+
+#define SAMSUNG_PA_ADC		S5P64X0_PA_ADC
+
+#endif /* __ASM_ARCH_MAP_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/memory.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/memory.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/memory.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/memory.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,19 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/memory.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Memory definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H __FILE__
+
+#define PHYS_OFFSET		UL(0x20000000)
+#define CONSISTENT_DMA_SIZE	SZ_8M
+
+#endif /* __ASM_ARCH_MEMORY_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S5P64X0 - pwm clock and timer support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_PWMCLK_H
+#define __ASM_ARCH_PWMCLK_H __FILE__
+
+/**
+ * pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
+ * @tcfg: The timer TCFG1 register bits shifted down to 0.
+ *
+ * Return true if the given configuration from TCFG1 is a TCLK instead
+ * any of the TDIV clocks.
+ */
+static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
+{
+	return 0;
+}
+
+/**
+ * tcfg_to_divisor() - convert tcfg1 setting to a divisor
+ * @tcfg1: The tcfg1 setting, shifted down.
+ *
+ * Get the divisor value for the given tcfg1 setting. We assume the
+ * caller has already checked to see if this is not a TCLK source.
+ */
+static inline unsigned long tcfg_to_divisor(unsigned long tcfg1)
+{
+	return 1 << tcfg1;
+}
+
+/**
+ * pwm_tdiv_has_div1() - does the tdiv setting have a /1
+ *
+ * Return true if we have a /1 in the tdiv setting.
+ */
+static inline unsigned int pwm_tdiv_has_div1(void)
+{
+	return 1;
+}
+
+/**
+ * pwm_tdiv_div_bits() - calculate TCFG1 divisor value.
+ * @div: The divisor to calculate the bit information for.
+ *
+ * Turn a divisor into the necessary bit field for TCFG1.
+ */
+static inline unsigned long pwm_tdiv_div_bits(unsigned int div)
+{
+	return ilog2(div);
+}
+
+#define S3C_TCFG1_MUX_TCLK 0
+
+#endif /* __ASM_ARCH_PWMCLK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,65 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Clock register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_CLOCK_H
+#define __ASM_ARCH_REGS_CLOCK_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_CLKREG(x)			(S3C_VA_SYS + (x))
+
+#define S5P64X0_APLL_CON		S5P_CLKREG(0x0C)
+#define S5P64X0_MPLL_CON		S5P_CLKREG(0x10)
+#define S5P64X0_EPLL_CON		S5P_CLKREG(0x14)
+#define S5P64X0_EPLL_CON_K		S5P_CLKREG(0x18)
+
+#define S5P64X0_CLK_SRC0		S5P_CLKREG(0x1C)
+
+#define S5P64X0_CLK_DIV0		S5P_CLKREG(0x20)
+#define S5P64X0_CLK_DIV1		S5P_CLKREG(0x24)
+#define S5P64X0_CLK_DIV2		S5P_CLKREG(0x28)
+
+#define S5P64X0_CLK_GATE_HCLK0		S5P_CLKREG(0x30)
+#define S5P64X0_CLK_GATE_PCLK		S5P_CLKREG(0x34)
+#define S5P64X0_CLK_GATE_SCLK0		S5P_CLKREG(0x38)
+#define S5P64X0_CLK_GATE_MEM0		S5P_CLKREG(0x3C)
+
+#define S5P64X0_CLK_DIV3		S5P_CLKREG(0x40)
+
+#define S5P64X0_CLK_GATE_HCLK1		S5P_CLKREG(0x44)
+#define S5P64X0_CLK_GATE_SCLK1		S5P_CLKREG(0x48)
+
+#define S5P6450_DPLL_CON		S5P_CLKREG(0x50)
+#define S5P6450_DPLL_CON_K		S5P_CLKREG(0x54)
+
+#define S5P64X0_CLK_SRC1		S5P_CLKREG(0x10C)
+
+#define S5P64X0_SYS_ID			S5P_CLKREG(0x118)
+#define S5P64X0_SYS_OTHERS		S5P_CLKREG(0x11C)
+
+#define S5P64X0_PWR_CFG			S5P_CLKREG(0x804)
+#define S5P64X0_OTHERS			S5P_CLKREG(0x900)
+
+#define S5P64X0_CLKDIV0_HCLK_SHIFT	(8)
+#define S5P64X0_CLKDIV0_HCLK_MASK	(0xF << S5P64X0_CLKDIV0_HCLK_SHIFT)
+
+#define S5P64X0_OTHERS_USB_SIG_MASK	(1 << 16)
+
+/* Compatibility defines */
+
+#define ARM_CLK_DIV			S5P64X0_CLK_DIV0
+#define ARM_DIV_RATIO_SHIFT		0
+#define ARM_DIV_MASK			(0xF << ARM_DIV_RATIO_SHIFT)
+
+#define S5P_EPLL_CON			S5P64X0_EPLL_CON
+
+#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,62 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - GPIO register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+
+/* Will be implemented S5P6442 GPIOlib */
+
+/* Base addresses for each of the banks */
+
+#define S5P6440_GPA_BASE		(S5P_VA_GPIO + 0x0000)
+#define S5P6440_GPB_BASE		(S5P_VA_GPIO + 0x0020)
+#define S5P6440_GPC_BASE		(S5P_VA_GPIO + 0x0040)
+#define S5P6440_GPF_BASE		(S5P_VA_GPIO + 0x00A0)
+#define S5P6440_GPG_BASE		(S5P_VA_GPIO + 0x00C0)
+#define S5P6440_GPH_BASE		(S5P_VA_GPIO + 0x00E0)
+#define S5P6440_GPI_BASE		(S5P_VA_GPIO + 0x0100)
+#define S5P6440_GPJ_BASE		(S5P_VA_GPIO + 0x0120)
+#define S5P6440_GPN_BASE		(S5P_VA_GPIO + 0x0830)
+#define S5P6440_GPP_BASE		(S5P_VA_GPIO + 0x0160)
+#define S5P6440_GPR_BASE		(S5P_VA_GPIO + 0x0290)
+
+#define S5P6440_EINT0CON0		(S5P_VA_GPIO + 0x900)
+#define S5P6440_EINT0FLTCON0		(S5P_VA_GPIO + 0x910)
+#define S5P6440_EINT0FLTCON1		(S5P_VA_GPIO + 0x914)
+#define S5P6440_EINT0MASK		(S5P_VA_GPIO + 0x920)
+#define S5P6440_EINT0PEND		(S5P_VA_GPIO + 0x924)
+
+/* for LCD */
+
+#define S5P6440_SPCON_LCD_SEL_RGB	(1 << 0)
+#define S5P6440_SPCON_LCD_SEL_MASK	(3 << 0)
+
+/*
+ * These set of macros are not really useful for the
+ * GPF/GPI/GPJ/GPN/GPP, useful for others set of GPIO's (4 bit)
+ */
+
+#define S5P6440_GPIO_CONMASK(__gpio)	(0xf << ((__gpio) * 4))
+#define S5P6440_GPIO_INPUT(__gpio)	(0x0 << ((__gpio) * 4))
+#define S5P6440_GPIO_OUTPUT(__gpio)	(0x1 << ((__gpio) * 4))
+
+/*
+ * Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
+ */
+
+#define S5P6440_GPIO2_CONMASK(__gpio)	(0x3 << ((__gpio) * 2))
+#define S5P6440_GPIO2_INPUT(__gpio)	(0x0 << ((__gpio) * 2))
+#define S5P6440_GPIO2_OUTPUT(__gpio)	(0x1 << ((__gpio) * 2))
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-irq.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/regs-irq.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/regs-irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,19 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - IRQ register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_IRQ_H
+#define __ASM_ARCH_REGS_IRQ_H __FILE__
+
+#include <asm/hardware/vic.h>
+#include <mach/map.h>
+
+#endif /* __ASM_ARCH_REGS_IRQ_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,46 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Header file for s5p64x0 clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_CLOCK_H
+#define __ASM_ARCH_CLOCK_H __FILE__
+
+#include <linux/clk.h>
+
+extern struct clksrc_clk clk_mout_apll;
+extern struct clksrc_clk clk_mout_mpll;
+extern struct clksrc_clk clk_mout_epll;
+
+extern int s5p64x0_epll_enable(struct clk *clk, int enable);
+extern unsigned long s5p64x0_epll_get_rate(struct clk *clk);
+
+extern unsigned long s5p64x0_armclk_get_rate(struct clk *clk);
+extern unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate);
+extern int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate);
+
+extern struct clk_ops s5p64x0_clkarm_ops;
+
+extern struct clksrc_clk clk_armclk;
+extern struct clksrc_clk clk_dout_mpll;
+
+extern struct clk *clkset_hclk_low_list[];
+extern struct clksrc_sources clkset_hclk_low;
+
+extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_hclk0_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_hclk1_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_sclk_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_sclk1_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_mem_ctrl(struct clk *clk, int enable);
+
+extern int s5p64x0_clk48m_ctrl(struct clk *clk, int enable);
+
+#endif /* __ASM_ARCH_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *	Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_SPI_CLKS_H
+#define __ASM_ARCH_SPI_CLKS_H __FILE__
+
+#define S5P64X0_SPI_SRCCLK_PCLK		0
+#define S5P64X0_SPI_SRCCLK_SCLK		1
+
+#endif /* __ASM_ARCH_SPI_CLKS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/system.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/system.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/system.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/system.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - system support header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H __FILE__
+
+#include <plat/system-reset.h>
+
+static void arch_idle(void)
+{
+	/* nothing here yet */
+}
+
+#endif /* __ASM_ARCH_SYSTEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/tick.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/tick.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/tick.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/tick.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/tick.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *	http://armlinux.simtec.co.uk/
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S5P64X0 - Timer tick support definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_TICK_H
+#define __ASM_ARCH_TICK_H __FILE__
+
+static inline u32 s3c24xx_ostimer_pending(void)
+{
+	u32 pend = __raw_readl(VA_VIC0 + VIC_RAW_STATUS);
+	return pend & (1 << (IRQ_TIMER4_VIC - S5P_IRQ_VIC0(0)));
+}
+
+#define TICK_MAX	(0xffffffff)
+
+#endif /* __ASM_ARCH_TICK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/timex.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/timex.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/timex.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,27 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/timex.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S5P64X0 - time parameters
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/* CLOCK_TICK_RATE needs to be evaluatable by the cpp, so making it
+ * a variable is useless. It seems as long as we make our timers an
+ * exact multiple of HZ, any value that makes a 1->1 correspondence
+ * for the time conversion functions to/from jiffies is acceptable.
+*/
+
+#define CLOCK_TICK_RATE 12000000
+
+#endif /* __ASM_ARCH_TIMEX_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/uncompress.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/uncompress.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/uncompress.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,212 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/uncompress.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - uncompress code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <mach/map.h>
+
+/*
+ * cannot use commonly <plat/uncompress.h>
+ * because uart base of S5P6440 and S5P6450 is different
+ */
+
+typedef unsigned int upf_t;	/* cannot include linux/serial_core.h */
+
+/* uart setup */
+
+static unsigned int fifo_mask;
+static unsigned int fifo_max;
+
+/* forward declerations */
+
+static void arch_detect_cpu(void);
+
+/* defines for UART registers */
+
+#include <plat/regs-serial.h>
+#include <plat/regs-watchdog.h>
+
+/* working in physical space... */
+#undef S3C2410_WDOGREG
+#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
+
+/* how many bytes we allow into the FIFO at a time in FIFO mode */
+#define FIFO_MAX	 (14)
+
+static unsigned long uart_base;
+
+static __inline__ void get_uart_base(void)
+{
+	unsigned int chipid;
+
+	chipid = *(const volatile unsigned int __force *) 0xE0100118;
+
+	uart_base = S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT;
+
+	if ((chipid & 0xff000) == 0x50000)
+		uart_base += 0xEC800000;
+	else
+		uart_base += 0xEC000000;
+}
+
+static __inline__ void uart_wr(unsigned int reg, unsigned int val)
+{
+	volatile unsigned int *ptr;
+
+	get_uart_base();
+	ptr = (volatile unsigned int *)(reg + uart_base);
+	*ptr = val;
+}
+
+static __inline__ unsigned int uart_rd(unsigned int reg)
+{
+	volatile unsigned int *ptr;
+
+	get_uart_base();
+	ptr = (volatile unsigned int *)(reg + uart_base);
+	return *ptr;
+}
+
+/*
+ * we can deal with the case the UARTs are being run
+ * in FIFO mode, so that we don't hold up our execution
+ * waiting for tx to happen...
+ */
+
+static void putc(int ch)
+{
+	if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
+		int level;
+
+		while (1) {
+			level = uart_rd(S3C2410_UFSTAT);
+			level &= fifo_mask;
+
+			if (level < fifo_max)
+				break;
+		}
+
+	} else {
+		/* not using fifos */
+
+		while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
+			barrier();
+	}
+
+	/* write byte to transmission register */
+	uart_wr(S3C2410_UTXH, ch);
+}
+
+static inline void flush(void)
+{
+}
+
+#define __raw_writel(d, ad)			\
+	do {							\
+		*((volatile unsigned int __force *)(ad)) = (d); \
+	} while (0)
+
+/*
+ * CONFIG_S3C_BOOT_WATCHDOG
+ *
+ * Simple boot-time watchdog setup, to reboot the system if there is
+ * any problem with the boot process
+ */
+
+#ifdef CONFIG_S3C_BOOT_WATCHDOG
+
+#define WDOG_COUNT (0xff00)
+
+static inline void arch_decomp_wdog(void)
+{
+	__raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+}
+
+static void arch_decomp_wdog_start(void)
+{
+	__raw_writel(WDOG_COUNT, S3C2410_WTDAT);
+	__raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+	__raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
+}
+
+#else
+#define arch_decomp_wdog_start()
+#define arch_decomp_wdog()
+#endif
+
+#ifdef CONFIG_S3C_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+	putstr("\n\n");
+	putstr(x);
+	putstr("\n\n -- System resetting\n");
+
+	__raw_writel(0x4000, S3C2410_WTDAT);
+	__raw_writel(0x4000, S3C2410_WTCNT);
+	__raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+	while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
+#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
+static inline void arch_enable_uart_fifo(void)
+{
+	u32 fifocon = uart_rd(S3C2410_UFCON);
+
+	if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
+		fifocon |= S3C2410_UFCON_RESETBOTH;
+		uart_wr(S3C2410_UFCON, fifocon);
+
+		/* wait for fifo reset to complete */
+		while (1) {
+			fifocon = uart_rd(S3C2410_UFCON);
+			if (!(fifocon & S3C2410_UFCON_RESETBOTH))
+				break;
+		}
+	}
+}
+#else
+#define arch_enable_uart_fifo() do { } while(0)
+#endif
+
+static void arch_decomp_setup(void)
+{
+	/*
+	 * we may need to setup the uart(s) here if we are not running
+	 * on an BAST... the BAST will have left the uarts configured
+	 * after calling linux.
+	 */
+
+	arch_detect_cpu();
+	arch_decomp_wdog_start();
+
+	/*
+	 * Enable the UART FIFOs if they where not enabled and our
+	 * configuration says we should turn them on.
+	 */
+
+	arch_enable_uart_fifo();
+}
+
+
+
+static void arch_detect_cpu(void)
+{
+	/* we do not need to do any cpu detection here at the moment. */
+}
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/include/mach/vmalloc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C6400 vmalloc definition
+*/
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END	0xF6000000UL
+
+#endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/init.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/init.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/init.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,73 @@
+/* linux/arch/arm/mach-s5p64x0/init.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Init support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#include <mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+#include <plat/regs-serial.h>
+
+static struct s3c24xx_uart_clksrc s5p64x0_serial_clocks[] = {
+	[0] = {
+		.name		= "pclk_low",
+		.divisor	= 1,
+		.min_baud	= 0,
+		.max_baud	= 0,
+	},
+	[1] = {
+		.name		= "uclk1",
+		.divisor	= 1,
+		.min_baud	= 0,
+		.max_baud	= 0,
+	},
+};
+
+/* uart registration process */
+
+void __init s5p64x0_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	struct s3c2410_uartcfg *tcfg = cfg;
+	u32 ucnt;
+
+	for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
+		if (!tcfg->clocks) {
+			tcfg->clocks = s5p64x0_serial_clocks;
+			tcfg->clocks_size = ARRAY_SIZE(s5p64x0_serial_clocks);
+		}
+	}
+}
+
+void __init s5p6440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	int uart;
+
+	for (uart = 0; uart < no; uart++) {
+		s5p_uart_resources[uart].resources->start = S5P6440_PA_UART(uart);
+		s5p_uart_resources[uart].resources->end = S5P6440_PA_UART(uart) + S5P_SZ_UART;
+	}
+
+	s5p64x0_common_init_uarts(cfg, no);
+	s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
+}
+
+void __init s5p6450_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+	s5p64x0_common_init_uarts(cfg, no);
+	s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,55 @@
+# arch/arm/mach-s5p64x0/Kconfig
+#
+# Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+#		http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+if ARCH_S5P64X0
+
+config CPU_S5P6440
+	bool
+	select S3C_PL330_DMA
+	help
+	  Enable S5P6440 CPU support
+
+config CPU_S5P6450
+	bool
+	select S3C_PL330_DMA
+	help
+	  Enable S5P6450 CPU support
+
+config S5P64X0_SETUP_I2C1
+	bool
+	help
+	  Common setup code for i2c bus 1.
+
+# machine support
+
+config MACH_SMDK6440
+	bool "SMDK6440"
+	select CPU_S5P6440
+	select S3C_DEV_I2C1
+	select S3C_DEV_RTC
+	select S3C_DEV_WDT
+	select S3C64XX_DEV_SPI
+	select SAMSUNG_DEV_ADC
+	select SAMSUNG_DEV_TS
+	select S5P64X0_SETUP_I2C1
+	help
+	  Machine support for the Samsung SMDK6440
+
+config MACH_SMDK6450
+	bool "SMDK6450"
+	select CPU_S5P6450
+	select S3C_DEV_I2C1
+	select S3C_DEV_RTC
+	select S3C_DEV_WDT
+	select S3C64XX_DEV_SPI
+	select SAMSUNG_DEV_ADC
+	select SAMSUNG_DEV_TS
+	select S5P64X0_SETUP_I2C1
+	help
+	  Machine support for the Samsung SMDK6450
+
+endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/mach-smdk6440.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/mach-smdk6440.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/mach-smdk6440.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/mach-smdk6440.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,161 @@
+/* linux/arch/arm/mach-s5p64x0/mach-smdk6440.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/i2c.h>
+
+#include <plat/regs-serial.h>
+#include <plat/gpio-cfg.h>
+#include <plat/s5p6440.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+#include <plat/pll.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
+
+#define SMDK6440_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
+				S3C2410_UCON_RXILEVEL |		\
+				S3C2410_UCON_TXIRQMODE |	\
+				S3C2410_UCON_RXIRQMODE |	\
+				S3C2410_UCON_RXFIFO_TOI |	\
+				S3C2443_UCON_RXERR_IRQEN)
+
+#define SMDK6440_ULCON_DEFAULT	S3C2410_LCON_CS8
+
+#define SMDK6440_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
+				S3C2440_UFCON_TXTRIG16 |	\
+				S3C2410_UFCON_RXTRIG8)
+
+static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport		= 0,
+		.flags		= 0,
+		.ucon		= SMDK6440_UCON_DEFAULT,
+		.ulcon		= SMDK6440_ULCON_DEFAULT,
+		.ufcon		= SMDK6440_UFCON_DEFAULT,
+	},
+	[1] = {
+		.hwport		= 1,
+		.flags		= 0,
+		.ucon		= SMDK6440_UCON_DEFAULT,
+		.ulcon		= SMDK6440_ULCON_DEFAULT,
+		.ufcon		= SMDK6440_UFCON_DEFAULT,
+	},
+	[2] = {
+		.hwport		= 2,
+		.flags		= 0,
+		.ucon		= SMDK6440_UCON_DEFAULT,
+		.ulcon		= SMDK6440_ULCON_DEFAULT,
+		.ufcon		= SMDK6440_UFCON_DEFAULT,
+	},
+	[3] = {
+		.hwport		= 3,
+		.flags		= 0,
+		.ucon		= SMDK6440_UCON_DEFAULT,
+		.ulcon		= SMDK6440_ULCON_DEFAULT,
+		.ufcon		= SMDK6440_UFCON_DEFAULT,
+	},
+};
+
+static struct platform_device *smdk6440_devices[] __initdata = {
+	&s3c_device_adc,
+	&s3c_device_rtc,
+	&s3c_device_i2c0,
+	&s3c_device_i2c1,
+	&s3c_device_ts,
+	&s3c_device_wdt,
+	&s5p6440_device_iis,
+};
+
+static struct s3c2410_platform_i2c s5p6440_i2c0_data __initdata = {
+	.flags		= 0,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+	.cfg_gpio	= s5p6440_i2c0_cfg_gpio,
+};
+
+static struct s3c2410_platform_i2c s5p6440_i2c1_data __initdata = {
+	.flags		= 0,
+	.bus_num	= 1,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+	.cfg_gpio	= s5p6440_i2c1_cfg_gpio,
+};
+
+static struct i2c_board_info smdk6440_i2c_devs0[] __initdata = {
+	{ I2C_BOARD_INFO("24c08", 0x50), },
+};
+
+static struct i2c_board_info smdk6440_i2c_devs1[] __initdata = {
+	/* To be populated */
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+	.delay			= 10000,
+	.presc			= 49,
+	.oversampling_shift	= 2,
+};
+
+static void __init smdk6440_map_io(void)
+{
+	s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
+	s3c24xx_init_clocks(12000000);
+	s3c24xx_init_uarts(smdk6440_uartcfgs, ARRAY_SIZE(smdk6440_uartcfgs));
+}
+
+static void __init smdk6440_machine_init(void)
+{
+	s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
+	s3c_i2c0_set_platdata(&s5p6440_i2c0_data);
+	s3c_i2c1_set_platdata(&s5p6440_i2c1_data);
+	i2c_register_board_info(0, smdk6440_i2c_devs0,
+			ARRAY_SIZE(smdk6440_i2c_devs0));
+	i2c_register_board_info(1, smdk6440_i2c_devs1,
+			ARRAY_SIZE(smdk6440_i2c_devs1));
+
+	platform_add_devices(smdk6440_devices, ARRAY_SIZE(smdk6440_devices));
+}
+
+MACHINE_START(SMDK6440, "SMDK6440")
+	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+	.boot_params	= S5P64X0_PA_SDRAM + 0x100,
+
+	.init_irq	= s5p6440_init_irq,
+	.map_io		= smdk6440_map_io,
+	.init_machine	= smdk6440_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/mach-smdk6450.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/mach-smdk6450.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/mach-smdk6450.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/mach-smdk6450.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s5p64x0/mach-smdk6450.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/i2c.h>
+
+#include <plat/regs-serial.h>
+#include <plat/gpio-cfg.h>
+#include <plat/s5p6450.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+#include <plat/pll.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
+
+#define SMDK6450_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
+				S3C2410_UCON_RXILEVEL |		\
+				S3C2410_UCON_TXIRQMODE |	\
+				S3C2410_UCON_RXIRQMODE |	\
+				S3C2410_UCON_RXFIFO_TOI |	\
+				S3C2443_UCON_RXERR_IRQEN)
+
+#define SMDK6450_ULCON_DEFAULT	S3C2410_LCON_CS8
+
+#define SMDK6450_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
+				S3C2440_UFCON_TXTRIG16 |	\
+				S3C2410_UFCON_RXTRIG8)
+
+static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport		= 0,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+	[1] = {
+		.hwport		= 1,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+	[2] = {
+		.hwport		= 2,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+	[3] = {
+		.hwport		= 3,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 4
+	[4] = {
+		.hwport		= 4,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 5
+	[5] = {
+		.hwport		= 5,
+		.flags		= 0,
+		.ucon		= SMDK6450_UCON_DEFAULT,
+		.ulcon		= SMDK6450_ULCON_DEFAULT,
+		.ufcon		= SMDK6450_UFCON_DEFAULT,
+	},
+#endif
+};
+
+static struct platform_device *smdk6450_devices[] __initdata = {
+	&s3c_device_adc,
+	&s3c_device_rtc,
+	&s3c_device_i2c0,
+	&s3c_device_i2c1,
+	&s3c_device_ts,
+	&s3c_device_wdt,
+	&s5p6450_device_iis0,
+	/* s5p6450_device_spi0 will be added */
+};
+
+static struct s3c2410_platform_i2c s5p6450_i2c0_data __initdata = {
+	.flags		= 0,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+	.cfg_gpio	= s5p6450_i2c0_cfg_gpio,
+};
+
+static struct s3c2410_platform_i2c s5p6450_i2c1_data __initdata = {
+	.flags		= 0,
+	.bus_num	= 1,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+	.cfg_gpio	= s5p6450_i2c1_cfg_gpio,
+};
+
+static struct i2c_board_info smdk6450_i2c_devs0[] __initdata = {
+	{ I2C_BOARD_INFO("24c08", 0x50), },	/* Samsung KS24C080C EEPROM */
+};
+
+static struct i2c_board_info smdk6450_i2c_devs1[] __initdata = {
+	{ I2C_BOARD_INFO("24c128", 0x57), },/* Samsung S524AD0XD1 EEPROM */
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+	.delay			= 10000,
+	.presc			= 49,
+	.oversampling_shift	= 2,
+};
+
+static void __init smdk6450_map_io(void)
+{
+	s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
+	s3c24xx_init_clocks(19200000);
+	s3c24xx_init_uarts(smdk6450_uartcfgs, ARRAY_SIZE(smdk6450_uartcfgs));
+}
+
+static void __init smdk6450_machine_init(void)
+{
+	s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
+	s3c_i2c0_set_platdata(&s5p6450_i2c0_data);
+	s3c_i2c1_set_platdata(&s5p6450_i2c1_data);
+	i2c_register_board_info(0, smdk6450_i2c_devs0,
+			ARRAY_SIZE(smdk6450_i2c_devs0));
+	i2c_register_board_info(1, smdk6450_i2c_devs1,
+			ARRAY_SIZE(smdk6450_i2c_devs1));
+
+	platform_add_devices(smdk6450_devices, ARRAY_SIZE(smdk6450_devices));
+}
+
+MACHINE_START(SMDK6450, "SMDK6450")
+	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+	.boot_params	= S5P64X0_PA_SDRAM + 0x100,
+
+	.init_irq	= s5p6450_init_irq,
+	.map_io		= smdk6450_map_io,
+	.init_machine	= smdk6450_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,30 @@
+# arch/arm/mach-s5p64x0/Makefile
+#
+# Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+# 		http://www.samsung.com
+#
+# Licensed under GPLv2
+
+obj-y				:=
+obj-m				:=
+obj-n				:=
+obj-				:=
+
+# Core support for S5P64X0 system
+
+obj-$(CONFIG_ARCH_S5P64X0)	+= cpu.o init.o clock.o dma.o
+obj-$(CONFIG_ARCH_S5P64X0)	+= setup-i2c0.o
+obj-$(CONFIG_CPU_S5P6440)	+= clock-s5p6440.o gpio.o
+obj-$(CONFIG_CPU_S5P6450)	+= clock-s5p6450.o
+
+# machine support
+
+obj-$(CONFIG_MACH_SMDK6440)	+= mach-smdk6440.o
+obj-$(CONFIG_MACH_SMDK6450)	+= mach-smdk6450.o
+
+# device support
+
+obj-y				+= dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)	+= dev-spi.o
+
+obj-$(CONFIG_S5P64X0_SETUP_I2C1)	+= setup-i2c1.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Makefile.boot linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Makefile.boot
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/Makefile.boot	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/Makefile.boot	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2 @@
+   zreladdr-y	:= 0x20008000
+params_phys-y	:= 0x20000100
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/setup-i2c0.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/setup-i2c0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/setup-i2c0.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/setup-i2c0.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+/* linux/arch/arm/mach-s5p64x0/setup-i2c0.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * I2C0 GPIO configuration.
+ *
+ * Based on plat-s3c64x0/setup-i2c0.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
+
+#include <mach/i2c.h>
+
+void s5p6440_i2c0_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5P6440_GPB(5), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+}
+
+void s5p6450_i2c0_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5P6450_GPB(5), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+}
+
+void s3c_i2c0_cfg_gpio(struct platform_device *dev) { }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/setup-i2c1.c linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/setup-i2c1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5p64x0/setup-i2c1.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5p64x0/setup-i2c1.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+/* linux/arch/arm/mach-s5p64xx/setup-i2c1.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * I2C1 GPIO configuration.
+ *
+ * Based on plat-s3c64xx/setup-i2c0.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+
+struct platform_device; /* don't need the contents */
+
+#include <plat/gpio-cfg.h>
+#include <plat/iic.h>
+
+#include <mach/i2c.h>
+
+void s5p6440_i2c1_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5P6440_GPR(9), 2,
+			      S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP);
+}
+
+void s5p6450_i2c1_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5P6450_GPR(9), 2,
+			      S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP);
+}
+
+void s3c_i2c1_cfg_gpio(struct platform_device *dev) { }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -273,24 +273,6 @@
 	.reg_div = { .reg = S5P_CLK_DIV3, .shift = 28, .size = 4 },
 };
 
-static int s5pc100_epll_enable(struct clk *clk, int enable)
-{
-	unsigned int ctrlbit = clk->ctrlbit;
-	unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
-
-	if (enable)
-		__raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
-	else
-		__raw_writel(epll_con, S5P_EPLL_CON);
-
-	return 0;
-}
-
-static unsigned long s5pc100_epll_get_rate(struct clk *clk)
-{
-	return clk->rate;
-}
-
 static u32 epll_div[][4] = {
 	{ 32750000,	131, 3, 4 },
 	{ 32768000,	131, 3, 4 },
@@ -341,13 +323,16 @@
 
 	__raw_writel(epll_con, S5P_EPLL_CON);
 
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
 	clk->rate = rate;
 
 	return 0;
 }
 
 static struct clk_ops s5pc100_epll_ops = {
-	.get_rate = s5pc100_epll_get_rate,
+	.get_rate = s5p_epll_get_rate,
 	.set_rate = s5pc100_epll_set_rate,
 };
 
@@ -691,55 +676,55 @@
 	}, {
 		.name		= "iis",
 		.id		= 0,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 0),
 	}, {
 		.name		= "iis",
 		.id		= 1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 1),
 	}, {
 		.name		= "iis",
 		.id		= 2,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 2),
 	}, {
 		.name		= "ac97",
 		.id		= -1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
 		.name		= "pcm",
 		.id		= 0,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 4),
 	}, {
 		.name		= "pcm",
 		.id		= 1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 5),
 	}, {
 		.name		= "spdif",
 		.id		= -1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 6),
 	}, {
 		.name		= "adc",
 		.id		= -1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 7),
 	}, {
 		.name		= "keypad",
 		.id		= -1,
-		.parent		= &clk_div_d1_bus.clk,
+		.parent		= &clk_div_pclkd1.clk,
 		.enable		= s5pc100_d1_5_ctrl,
 		.ctrlbit	= (1 << 8),
 	}, {
@@ -848,6 +833,18 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_group3_list),
 };
 
+static struct clksrc_clk clk_sclk_audio0 = {
+	.clk	= {
+		.name		= "sclk_audio",
+		.id		= 0,
+		.ctrlbit	= (1 << 8),
+		.enable		= s5pc100_sclk1_ctrl,
+	},
+	.sources = &clk_src_group3,
+	.reg_src = { .reg = S5P_CLK_SRC3, .shift = 12, .size = 3 },
+	.reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 },
+};
+
 static struct clk *clk_src_group4_list[] = {
 	[0] = &clk_mout_epll.clk,
 	[1] = &clk_div_mpll.clk,
@@ -862,6 +859,18 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_group4_list),
 };
 
+static struct clksrc_clk clk_sclk_audio1 = {
+	.clk	= {
+		.name		= "sclk_audio",
+		.id		= 1,
+		.ctrlbit	= (1 << 9),
+		.enable		= s5pc100_sclk1_ctrl,
+	},
+	.sources = &clk_src_group4,
+	.reg_src = { .reg = S5P_CLK_SRC3, .shift = 16, .size = 3 },
+	.reg_div = { .reg = S5P_CLK_DIV4, .shift = 16, .size = 4 },
+};
+
 static struct clk *clk_src_group5_list[] = {
 	[0] = &clk_mout_epll.clk,
 	[1] = &clk_div_mpll.clk,
@@ -875,6 +884,18 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_group5_list),
 };
 
+static struct clksrc_clk clk_sclk_audio2 = {
+	.clk	= {
+		.name		= "sclk_audio",
+		.id		= 2,
+		.ctrlbit	= (1 << 10),
+		.enable		= s5pc100_sclk1_ctrl,
+	},
+	.sources = &clk_src_group5,
+	.reg_src = { .reg = S5P_CLK_SRC3, .shift = 20, .size = 3 },
+	.reg_div = { .reg = S5P_CLK_DIV4, .shift = 20, .size = 4 },
+};
+
 static struct clk *clk_src_group6_list[] = {
 	[0] = &s5p_clk_27m,
 	[1] = &clk_vclk54m,
@@ -944,6 +965,64 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_pwi_list),
 };
 
+static struct clk *clk_sclk_spdif_list[] = {
+	[0] = &clk_sclk_audio0.clk,
+	[1] = &clk_sclk_audio1.clk,
+	[2] = &clk_sclk_audio2.clk,
+};
+
+struct clksrc_sources clk_src_sclk_spdif = {
+	.sources	= clk_sclk_spdif_list,
+	.nr_sources	= ARRAY_SIZE(clk_sclk_spdif_list),
+};
+
+static int s5pc100_spdif_set_rate(struct clk *clk, unsigned long rate)
+{
+	struct clk *pclk;
+	int ret;
+
+	pclk = clk_get_parent(clk);
+	if (IS_ERR(pclk))
+		return -EINVAL;
+
+	ret = pclk->ops->set_rate(pclk, rate);
+	clk_put(pclk);
+
+	return ret;
+}
+
+static unsigned long s5pc100_spdif_get_rate(struct clk *clk)
+{
+	struct clk *pclk;
+	int rate;
+
+	pclk = clk_get_parent(clk);
+	if (IS_ERR(pclk))
+		return -EINVAL;
+
+	rate = pclk->ops->get_rate(clk);
+	clk_put(pclk);
+
+	return rate;
+}
+
+static struct clk_ops s5pc100_sclk_spdif_ops = {
+	.set_rate	= s5pc100_spdif_set_rate,
+	.get_rate	= s5pc100_spdif_get_rate,
+};
+
+static struct clksrc_clk clk_sclk_spdif = {
+	.clk	= {
+		.name		= "sclk_spdif",
+		.id		= -1,
+		.ctrlbit	= (1 << 11),
+		.enable		= s5pc100_sclk1_ctrl,
+		.ops		= &s5pc100_sclk_spdif_ops,
+	},
+	.sources = &clk_src_sclk_spdif,
+	.reg_src = { .reg = S5P_CLK_SRC3, .shift = 24, .size = 2 },
+};
+
 static struct clksrc_clk clksrcs[] = {
 	{
 		.clk	= {
@@ -1001,39 +1080,6 @@
 		.reg_src = { .reg = S5P_CLK_SRC2, .shift = 28, .size = 2 },
 	}, {
 		.clk	= {
-			.name		= "sclk_audio",
-			.id		= 0,
-			.ctrlbit	= (1 << 8),
-			.enable		= s5pc100_sclk1_ctrl,
-
-		},
-		.sources = &clk_src_group3,
-		.reg_src = { .reg = S5P_CLK_SRC3, .shift = 12, .size = 3 },
-		.reg_div = { .reg = S5P_CLK_DIV4, .shift = 12, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_audio",
-			.id		= 1,
-			.ctrlbit	= (1 << 9),
-			.enable		= s5pc100_sclk1_ctrl,
-
-		},
-		.sources = &clk_src_group4,
-		.reg_src = { .reg = S5P_CLK_SRC3, .shift = 16, .size = 3 },
-		.reg_div = { .reg = S5P_CLK_DIV4, .shift = 16, .size = 4 },
-	}, {
-		.clk	= {
-			.name		= "sclk_audio",
-			.id		= 2,
-			.ctrlbit	= (1 << 10),
-			.enable		= s5pc100_sclk1_ctrl,
-
-		},
-		.sources = &clk_src_group5,
-		.reg_src = { .reg = S5P_CLK_SRC3, .shift = 20, .size = 3 },
-		.reg_div = { .reg = S5P_CLK_DIV4, .shift = 20, .size = 4 },
-	}, {
-		.clk	= {
 			.name		= "sclk_lcd",
 			.id		= -1,
 			.ctrlbit	= (1 << 0),
@@ -1179,6 +1225,10 @@
 	&clk_div_pclkd1,
 	&clk_div_cam,
 	&clk_div_hdmi,
+	&clk_sclk_audio0,
+	&clk_sclk_audio1,
+	&clk_sclk_audio2,
+	&clk_sclk_spdif,
 };
 
 void __init_or_cpufreq s5pc100_setup_clocks(void)
@@ -1196,7 +1246,7 @@
 	unsigned int ptr;
 
 	/* Set S5PC100 functions for clk_fout_epll */
-	clk_fout_epll.enable = s5pc100_epll_enable;
+	clk_fout_epll.enable = s5p_epll_enable;
 	clk_fout_epll.ops = &s5pc100_epll_ops;
 
 	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,8 @@
 /* linux/arch/arm/mach-s5pc100/cpu.c
  *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
  * Copyright 2009 Samsung Electronics Co.
  *	Byungho Min <bhmin@samsung.com>
  *
@@ -57,11 +60,31 @@
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S5P_VA_GPIO,
+		.pfn		= __phys_to_pfn(S5PC100_PA_GPIO),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC0,
+		.pfn		= __phys_to_pfn(S5PC100_PA_VIC0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC1,
+		.pfn		= __phys_to_pfn(S5PC100_PA_VIC1),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)VA_VIC2,
-		.pfn		= __phys_to_pfn(S5P_PA_VIC2),
+		.pfn		= __phys_to_pfn(S5PC100_PA_VIC2),
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S3C_PA_UART),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)S5PC100_VA_OTHERS,
 		.pfn		= __phys_to_pfn(S5PC100_PA_OTHERS),
 		.length		= SZ_4K,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dev-audio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dev-audio.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,19 +24,11 @@
 	/* configure GPIO for i2s port */
 	switch (pdev->id) {
 	case 1:
-		s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(2));
 		break;
 
 	case 2:
-		s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(4));
+		s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(4));
 		break;
 
 	case -1: /* Dedicated pins */
@@ -144,19 +136,11 @@
 {
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5PC100_GPG3(1), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(5));
-		s3c_gpio_cfgpin(S5PC100_GPG3(4), S3C_GPIO_SFN(5));
+		s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(5));
 		break;
 
 	case 1:
-		s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(3));
+		s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(3));
 		break;
 
 	default:
@@ -231,13 +215,7 @@
 
 static int s5pc100_ac97_cfg_gpio(struct platform_device *pdev)
 {
-	s3c_gpio_cfgpin(S5PC100_GPC(0), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PC100_GPC(1), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PC100_GPC(2), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PC100_GPC(3), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PC100_GPC(4), S3C_GPIO_SFN(4));
-
-	return 0;
+	return s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(4));
 }
 
 static struct resource s5pc100_ac97_resource[] = {
@@ -285,3 +263,57 @@
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
+
+/* S/PDIF Controller platform_device */
+static int s5pc100_spdif_cfg_gpd(struct platform_device *pdev)
+{
+	s3c_gpio_cfgpin_range(S5PC100_GPD(5), 2, S3C_GPIO_SFN(3));
+
+	return 0;
+}
+
+static int s5pc100_spdif_cfg_gpg3(struct platform_device *pdev)
+{
+	s3c_gpio_cfgpin_range(S5PC100_GPG3(5), 2, S3C_GPIO_SFN(3));
+
+	return 0;
+}
+
+static struct resource s5pc100_spdif_resource[] = {
+	[0] = {
+		.start	= S5PC100_PA_SPDIF,
+		.end	= S5PC100_PA_SPDIF + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_SPDIF,
+		.end	= DMACH_SPDIF,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct s3c_audio_pdata s5p_spdif_pdata = {
+	.cfg_gpio = s5pc100_spdif_cfg_gpd,
+};
+
+static u64 s5pc100_spdif_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pc100_device_spdif = {
+	.name		= "samsung-spdif",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5pc100_spdif_resource),
+	.resource	= s5pc100_spdif_resource,
+	.dev = {
+		.platform_data = &s5p_spdif_pdata,
+		.dma_mask = &s5pc100_spdif_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+void __init s5pc100_spdif_setup_gpio(int gpio)
+{
+	if (gpio == S5PC100_SPDIF_GPD)
+		s5p_spdif_pdata.cfg_gpio = s5pc100_spdif_cfg_gpd;
+	else
+		s5p_spdif_pdata.cfg_gpio = s5pc100_spdif_cfg_gpg3;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dev-spi.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dev-spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dev-spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dev-spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,30 +38,20 @@
 {
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S5PC100_GPB(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPB(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPB(2), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5PC100_GPB(0), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPB(1), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPB(2), S3C_GPIO_PULL_UP);
+		s3c_gpio_cfgall_range(S5PC100_GPB(0), 3,
+				      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 		break;
 
 	case 1:
-		s3c_gpio_cfgpin(S5PC100_GPB(4), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPB(5), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PC100_GPB(6), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5PC100_GPB(4), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPB(5), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPB(6), S3C_GPIO_PULL_UP);
+		s3c_gpio_cfgall_range(S5PC100_GPB(4), 3,
+				      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 		break;
 
 	case 2:
 		s3c_gpio_cfgpin(S5PC100_GPG3(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPG3(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PC100_GPG3(3), S3C_GPIO_SFN(3));
 		s3c_gpio_setpull(S5PC100_GPG3(0), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPG3(2), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PC100_GPG3(3), S3C_GPIO_PULL_UP);
+		s3c_gpio_cfgall_range(S5PC100_GPB(2), 2,
+				      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,7 +81,7 @@
 
 static struct platform_device s5pc100_device_pdma0 = {
 	.name		= "s3c-pl330",
-	.id		= 1,
+	.id		= 0,
 	.num_resources	= ARRAY_SIZE(s5pc100_pdma0_resource),
 	.resource	= s5pc100_pdma0_resource,
 	.dev		= {
@@ -143,7 +143,7 @@
 
 static struct platform_device s5pc100_device_pdma1 = {
 	.name		= "s3c-pl330",
-	.id		= 2,
+	.id		= 1,
 	.num_resources	= ARRAY_SIZE(s5pc100_pdma1_resource),
 	.resource	= s5pc100_pdma1_resource,
 	.dev		= {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/gpiolib.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/gpiolib.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/gpiolib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,7 @@
-/*
- * arch/arm/plat-s5pc100/gpiolib.c
+/* linux/arch/arm/mach-s5pc100/gpiolib.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
  *
  *  Copyright 2009 Samsung Electronics Co
  *  Kyungmin Park <kyungmin.park@samsung.com>
@@ -61,30 +63,6 @@
  * L3	8	4Bit	None
  */
 
-static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
-	return S3C_IRQ_GPIO(chip->base + offset);
-}
-
-static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset)
-{
-	int base;
-
-	base = chip->base - S5PC100_GPH0(0);
-	if (base == 0)
-		return IRQ_EINT(offset);
-	base = chip->base - S5PC100_GPH1(0);
-	if (base == 0)
-		return IRQ_EINT(8 + offset);
-	base = chip->base - S5PC100_GPH2(0);
-	if (base == 0)
-		return IRQ_EINT(16 + offset);
-	base = chip->base - S5PC100_GPH3(0);
-	if (base == 0)
-		return IRQ_EINT(24 + offset);
-	return -EINVAL;
-}
-
 static struct s3c_gpio_cfg gpio_cfg = {
 	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
 	.set_pull	= s3c_gpio_setpull_updown,
@@ -104,209 +82,150 @@
 	.get_pull	= s3c_gpio_getpull_updown,
 };
 
+/*
+ * GPIO bank's base address given the index of the bank in the
+ * list of all gpio banks.
+ */
+#define S5PC100_BANK_BASE(bank_nr)	(S5P_VA_GPIO + ((bank_nr) * 0x20))
+
+/*
+ * Following are the gpio banks in S5PC100.
+ *
+ * The 'config' member when left to NULL, is initialized to the default
+ * structure gpio_cfg in the init function below.
+ *
+ * The 'base' member is also initialized in the init function below.
+ * Note: The initialization of 'base' member of s3c_gpio_chip structure
+ * uses the above macro and depends on the banks being listed in order here.
+ */
 static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
 	{
-		.base	= S5PC100_GPA0_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPA0(0),
 			.ngpio	= S5PC100_GPIO_A0_NR,
 			.label	= "GPA0",
 		},
 	}, {
-		.base	= S5PC100_GPA1_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPA1(0),
 			.ngpio	= S5PC100_GPIO_A1_NR,
 			.label	= "GPA1",
 		},
 	}, {
-		.base	= S5PC100_GPB_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPB(0),
 			.ngpio	= S5PC100_GPIO_B_NR,
 			.label	= "GPB",
 		},
 	}, {
-		.base	= S5PC100_GPC_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPC(0),
 			.ngpio	= S5PC100_GPIO_C_NR,
 			.label	= "GPC",
 		},
 	}, {
-		.base	= S5PC100_GPD_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPD(0),
 			.ngpio	= S5PC100_GPIO_D_NR,
 			.label	= "GPD",
 		},
 	}, {
-		.base	= S5PC100_GPE0_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPE0(0),
 			.ngpio	= S5PC100_GPIO_E0_NR,
 			.label	= "GPE0",
 		},
 	}, {
-		.base	= S5PC100_GPE1_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPE1(0),
 			.ngpio	= S5PC100_GPIO_E1_NR,
 			.label	= "GPE1",
 		},
 	}, {
-		.base	= S5PC100_GPF0_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPF0(0),
 			.ngpio	= S5PC100_GPIO_F0_NR,
 			.label	= "GPF0",
 		},
 	}, {
-		.base	= S5PC100_GPF1_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPF1(0),
 			.ngpio	= S5PC100_GPIO_F1_NR,
 			.label	= "GPF1",
 		},
 	}, {
-		.base	= S5PC100_GPF2_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPF2(0),
 			.ngpio	= S5PC100_GPIO_F2_NR,
 			.label	= "GPF2",
 		},
 	}, {
-		.base	= S5PC100_GPF3_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPF3(0),
 			.ngpio	= S5PC100_GPIO_F3_NR,
 			.label	= "GPF3",
 		},
 	}, {
-		.base	= S5PC100_GPG0_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPG0(0),
 			.ngpio	= S5PC100_GPIO_G0_NR,
 			.label	= "GPG0",
 		},
 	}, {
-		.base	= S5PC100_GPG1_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPG1(0),
 			.ngpio	= S5PC100_GPIO_G1_NR,
 			.label	= "GPG1",
 		},
 	}, {
-		.base	= S5PC100_GPG2_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPG2(0),
 			.ngpio	= S5PC100_GPIO_G2_NR,
 			.label	= "GPG2",
 		},
 	}, {
-		.base	= S5PC100_GPG3_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPG3(0),
 			.ngpio	= S5PC100_GPIO_G3_NR,
 			.label	= "GPG3",
 		},
 	}, {
-		.base	= S5PC100_GPH0_BASE,
-		.config	= &gpio_cfg_eint,
-		.chip	= {
-			.base	= S5PC100_GPH0(0),
-			.ngpio	= S5PC100_GPIO_H0_NR,
-			.label	= "GPH0",
-		},
-	}, {
-		.base	= S5PC100_GPH1_BASE,
-		.config	= &gpio_cfg_eint,
-		.chip	= {
-			.base	= S5PC100_GPH1(0),
-			.ngpio	= S5PC100_GPIO_H1_NR,
-			.label	= "GPH1",
-		},
-	}, {
-		.base	= S5PC100_GPH2_BASE,
-		.config	= &gpio_cfg_eint,
-		.chip	= {
-			.base	= S5PC100_GPH2(0),
-			.ngpio	= S5PC100_GPIO_H2_NR,
-			.label	= "GPH2",
-		},
-	}, {
-		.base	= S5PC100_GPH3_BASE,
-		.config	= &gpio_cfg_eint,
-		.chip	= {
-			.base	= S5PC100_GPH3(0),
-			.ngpio	= S5PC100_GPIO_H3_NR,
-			.label	= "GPH3",
-		},
-	}, {
-		.base	= S5PC100_GPI_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPI(0),
 			.ngpio	= S5PC100_GPIO_I_NR,
 			.label	= "GPI",
 		},
 	}, {
-		.base	= S5PC100_GPJ0_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPJ0(0),
 			.ngpio	= S5PC100_GPIO_J0_NR,
 			.label	= "GPJ0",
 		},
 	}, {
-		.base	= S5PC100_GPJ1_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPJ1(0),
 			.ngpio	= S5PC100_GPIO_J1_NR,
 			.label	= "GPJ1",
 		},
 	}, {
-		.base	= S5PC100_GPJ2_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPJ2(0),
 			.ngpio	= S5PC100_GPIO_J2_NR,
 			.label	= "GPJ2",
 		},
 	}, {
-		.base	= S5PC100_GPJ3_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPJ3(0),
 			.ngpio	= S5PC100_GPIO_J3_NR,
 			.label	= "GPJ3",
 		},
 	}, {
-		.base	= S5PC100_GPJ4_BASE,
-		.config	= &gpio_cfg,
 		.chip	= {
 			.base	= S5PC100_GPJ4(0),
 			.ngpio	= S5PC100_GPIO_J4_NR,
 			.label	= "GPJ4",
 		},
 	}, {
-		.base	= S5PC100_GPK0_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPK0(0),
@@ -314,7 +233,6 @@
 			.label	= "GPK0",
 		},
 	}, {
-		.base	= S5PC100_GPK1_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPK1(0),
@@ -322,7 +240,6 @@
 			.label	= "GPK1",
 		},
 	}, {
-		.base	= S5PC100_GPK2_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPK2(0),
@@ -330,7 +247,6 @@
 			.label	= "GPK2",
 		},
 	}, {
-		.base	= S5PC100_GPK3_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPK3(0),
@@ -338,7 +254,6 @@
 			.label	= "GPK3",
 		},
 	}, {
-		.base	= S5PC100_GPL0_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPL0(0),
@@ -346,7 +261,6 @@
 			.label	= "GPL0",
 		},
 	}, {
-		.base	= S5PC100_GPL1_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPL1(0),
@@ -354,7 +268,6 @@
 			.label	= "GPL1",
 		},
 	}, {
-		.base	= S5PC100_GPL2_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPL2(0),
@@ -362,7 +275,6 @@
 			.label	= "GPL2",
 		},
 	}, {
-		.base	= S5PC100_GPL3_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPL3(0),
@@ -370,56 +282,72 @@
 			.label	= "GPL3",
 		},
 	}, {
-		.base	= S5PC100_GPL4_BASE,
 		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PC100_GPL4(0),
 			.ngpio	= S5PC100_GPIO_L4_NR,
 			.label	= "GPL4",
 		},
+	}, {
+		.base	= (S5P_VA_GPIO + 0xC00),
+		.config	= &gpio_cfg_eint,
+		.irq_base = IRQ_EINT(0),
+		.chip	= {
+			.base	= S5PC100_GPH0(0),
+			.ngpio	= S5PC100_GPIO_H0_NR,
+			.label	= "GPH0",
+			.to_irq = samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO + 0xC20),
+		.config	= &gpio_cfg_eint,
+		.irq_base = IRQ_EINT(8),
+		.chip	= {
+			.base	= S5PC100_GPH1(0),
+			.ngpio	= S5PC100_GPIO_H1_NR,
+			.label	= "GPH1",
+			.to_irq = samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO + 0xC40),
+		.config	= &gpio_cfg_eint,
+		.irq_base = IRQ_EINT(16),
+		.chip	= {
+			.base	= S5PC100_GPH2(0),
+			.ngpio	= S5PC100_GPIO_H2_NR,
+			.label	= "GPH2",
+			.to_irq = samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO + 0xC60),
+		.config	= &gpio_cfg_eint,
+		.irq_base = IRQ_EINT(24),
+		.chip	= {
+			.base	= S5PC100_GPH3(0),
+			.ngpio	= S5PC100_GPIO_H3_NR,
+			.label	= "GPH3",
+			.to_irq = samsung_gpiolib_to_irq,
+		},
 	},
 };
 
-/* FIXME move from irq-gpio.c */
-extern struct irq_chip s5pc100_gpioint;
-extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc);
-
-static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip)
+static __init int s5pc100_gpiolib_init(void)
 {
-	/* Interrupt */
-	if (chip->config == &gpio_cfg) {
-		int i, irq;
-
-		chip->chip.to_irq = s5pc100_gpiolib_to_irq;
+	struct s3c_gpio_chip *chip = s5pc100_gpio_chips;
+	int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
+	int gpioint_group = 0;
+	int i;
 
-		for (i = 0;  i < chip->chip.ngpio; i++) {
-			irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i;
-			set_irq_chip(irq, &s5pc100_gpioint);
-			set_irq_data(irq, &chip->chip);
-			set_irq_handler(irq, handle_level_irq);
-			set_irq_flags(irq, IRQF_VALID);
+	for (i = 0; i < nr_chips; i++, chip++) {
+		if (chip->config == NULL) {
+			chip->config = &gpio_cfg;
+			chip->group = gpioint_group++;
 		}
-	} else if (chip->config == &gpio_cfg_eint) {
-		chip->chip.to_irq = s5pc100_gpiolib_to_eint;
+		if (chip->base == NULL)
+			chip->base = S5PC100_BANK_BASE(i);
 	}
-}
 
-static __init int s5pc100_gpiolib_init(void)
-{
-	struct s3c_gpio_chip *chip;
-	int nr_chips;
-
-	chip = s5pc100_gpio_chips;
-	nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
-
-	for (; nr_chips > 0; nr_chips--, chip++)
-		s5pc100_gpiolib_link(chip);
-
-	samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips,
-				       ARRAY_SIZE(s5pc100_gpio_chips));
-
-	/* Interrupt */
-	set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler);
+	samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -22,13 +22,12 @@
 	 * aligned and add in the offset when we load the value here.
 	 */
 
-	.macro addruart, rx, rtmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = S3C_VA_UART
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C_PA_UART
+		ldr	\rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -146,13 +146,6 @@
 /* define the number of gpios we need to the one after the MP04() range */
 #define ARCH_NR_GPIOS		(S5PC100_GPIO_END + 1)
 
-#define EINT_MODE		S3C_GPIO_SFN(0x2)
-
-#define EINT_GPIO_0(x)		S5PC100_GPH0(x)
-#define EINT_GPIO_1(x)		S5PC100_GPH1(x)
-#define EINT_GPIO_2(x)		S5PC100_GPH2(x)
-#define EINT_GPIO_3(x)		S5PC100_GPH3(x)
-
 #include <asm-generic/gpio.h>
 
 #endif /* __ASM_ARCH_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -48,8 +48,8 @@
 #define IRQ_SPI1		S5P_IRQ_VIC1(16)
 #define IRQ_SPI2		S5P_IRQ_VIC1(17)
 #define IRQ_IRDA		S5P_IRQ_VIC1(18)
-#define IRQ_CAN0		S5P_IRQ_VIC1(19)
-#define IRQ_CAN1		S5P_IRQ_VIC1(20)
+#define IRQ_IIC2		S5P_IRQ_VIC1(19)
+#define IRQ_IIC3		S5P_IRQ_VIC1(20)
 #define IRQ_HSIRX		S5P_IRQ_VIC1(21)
 #define IRQ_HSITX		S5P_IRQ_VIC1(22)
 #define IRQ_UHOST		S5P_IRQ_VIC1(23)
@@ -100,11 +100,12 @@
 #define S5P_EINT_BASE1		(S5P_IRQ_VIC0(0))
 #define S5P_EINT_BASE2		(IRQ_VIC_END + 1)
 
-#define S3C_IRQ_GPIO_BASE	(IRQ_EINT(31) + 1)
-#define S3C_IRQ_GPIO(x)		(S3C_IRQ_GPIO_BASE + (x))
+/* GPIO interrupt */
+#define S5P_GPIOINT_BASE	(IRQ_EINT(31) + 1)
+#define S5P_GPIOINT_GROUP_MAXNR	21
 
-/* Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs */
-#define NR_IRQS		(S3C_IRQ_GPIO(320) + 1)
+/* Set the default NR_IRQS */
+#define NR_IRQS			(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
 
 /* Compatibility */
 #define IRQ_LCD_FIFO		IRQ_LCD0
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/map.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/map.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,19 +44,16 @@
 #define S5PC100_PA_OTHERS	(0xE0200000)
 #define S5PC100_VA_OTHERS	(S3C_VA_SYS + 0x10000)
 
-#define S5P_PA_GPIO		(0xE0300000)
+#define S5PC100_PA_GPIO		(0xE0300000)
 #define S5PC1XX_VA_GPIO		S3C_ADDR(0x00500000)
 
 /* Interrupt */
-#define S5PC100_PA_VIC		(0xE4000000)
+#define S5PC100_PA_VIC0		(0xE4000000)
+#define S5PC100_PA_VIC1		(0xE4100000)
+#define S5PC100_PA_VIC2		(0xE4200000)
 #define S5PC100_VA_VIC		S3C_VA_IRQ
-#define S5PC100_PA_VIC_OFFSET	0x100000
 #define S5PC100_VA_VIC_OFFSET	0x10000
-#define S5PC1XX_PA_VIC(x)	(S5PC100_PA_VIC + ((x) * S5PC100_PA_VIC_OFFSET))
 #define S5PC1XX_VA_VIC(x)	(S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
-#define S5P_PA_VIC0		S5PC1XX_PA_VIC(0)
-#define S5P_PA_VIC1		S5PC1XX_PA_VIC(1)
-#define S5P_PA_VIC2		S5PC1XX_PA_VIC(2)
 
 
 #define S5PC100_PA_ONENAND	(0xE7100000)
@@ -113,6 +110,8 @@
 #define S5PC100_PA_PCM0		0xF2400000
 #define S5PC100_PA_PCM1		0xF2500000
 
+#define S5PC100_PA_SPDIF	0xF2600000
+
 #define S5PC100_PA_TSADC	(0xF3000000)
 
 /* KEYPAD */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/regs-gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/regs-gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/regs-gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/regs-gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,43 +11,6 @@
 
 #include <mach/map.h>
 
-/* S5PC100 */
-#define S5PC100_GPIO_BASE	S5P_VA_GPIO
-#define S5PC100_GPA0_BASE	(S5PC100_GPIO_BASE + 0x0000)
-#define S5PC100_GPA1_BASE	(S5PC100_GPIO_BASE + 0x0020)
-#define S5PC100_GPB_BASE	(S5PC100_GPIO_BASE + 0x0040)
-#define S5PC100_GPC_BASE	(S5PC100_GPIO_BASE + 0x0060)
-#define S5PC100_GPD_BASE	(S5PC100_GPIO_BASE + 0x0080)
-#define S5PC100_GPE0_BASE	(S5PC100_GPIO_BASE + 0x00A0)
-#define S5PC100_GPE1_BASE	(S5PC100_GPIO_BASE + 0x00C0)
-#define S5PC100_GPF0_BASE	(S5PC100_GPIO_BASE + 0x00E0)
-#define S5PC100_GPF1_BASE	(S5PC100_GPIO_BASE + 0x0100)
-#define S5PC100_GPF2_BASE	(S5PC100_GPIO_BASE + 0x0120)
-#define S5PC100_GPF3_BASE	(S5PC100_GPIO_BASE + 0x0140)
-#define S5PC100_GPG0_BASE	(S5PC100_GPIO_BASE + 0x0160)
-#define S5PC100_GPG1_BASE	(S5PC100_GPIO_BASE + 0x0180)
-#define S5PC100_GPG2_BASE	(S5PC100_GPIO_BASE + 0x01A0)
-#define S5PC100_GPG3_BASE	(S5PC100_GPIO_BASE + 0x01C0)
-#define S5PC100_GPH0_BASE	(S5PC100_GPIO_BASE + 0x0C00)
-#define S5PC100_GPH1_BASE	(S5PC100_GPIO_BASE + 0x0C20)
-#define S5PC100_GPH2_BASE	(S5PC100_GPIO_BASE + 0x0C40)
-#define S5PC100_GPH3_BASE	(S5PC100_GPIO_BASE + 0x0C60)
-#define S5PC100_GPI_BASE	(S5PC100_GPIO_BASE + 0x01E0)
-#define S5PC100_GPJ0_BASE	(S5PC100_GPIO_BASE + 0x0200)
-#define S5PC100_GPJ1_BASE	(S5PC100_GPIO_BASE + 0x0220)
-#define S5PC100_GPJ2_BASE	(S5PC100_GPIO_BASE + 0x0240)
-#define S5PC100_GPJ3_BASE	(S5PC100_GPIO_BASE + 0x0260)
-#define S5PC100_GPJ4_BASE	(S5PC100_GPIO_BASE + 0x0280)
-#define S5PC100_GPK0_BASE	(S5PC100_GPIO_BASE + 0x02A0)
-#define S5PC100_GPK1_BASE	(S5PC100_GPIO_BASE + 0x02C0)
-#define S5PC100_GPK2_BASE	(S5PC100_GPIO_BASE + 0x02E0)
-#define S5PC100_GPK3_BASE	(S5PC100_GPIO_BASE + 0x0300)
-#define S5PC100_GPL0_BASE	(S5PC100_GPIO_BASE + 0x0320)
-#define S5PC100_GPL1_BASE	(S5PC100_GPIO_BASE + 0x0340)
-#define S5PC100_GPL2_BASE	(S5PC100_GPIO_BASE + 0x0360)
-#define S5PC100_GPL3_BASE	(S5PC100_GPIO_BASE + 0x0380)
-#define S5PC100_GPL4_BASE	(S5PC100_GPIO_BASE + 0x03A0)
-
 #define S5PC100EINT30CON		(S5P_VA_GPIO + 0xE00)
 #define S5P_EINT_CON(x)			(S5PC100EINT30CON + ((x) * 0x4))
 
@@ -64,12 +27,12 @@
 
 #define eint_irq_to_bit(irq)		(1 << (EINT_OFFSET(irq) & 0x7))
 
-/* values for S5P_EXTINT0 */
-#define S5P_EXTINT_LOWLEV		(0x00)
-#define S5P_EXTINT_HILEV		(0x01)
-#define S5P_EXTINT_FALLEDGE		(0x02)
-#define S5P_EXTINT_RISEEDGE		(0x03)
-#define S5P_EXTINT_BOTHEDGE		(0x04)
+#define EINT_MODE		S3C_GPIO_SFN(0x2)
+
+#define EINT_GPIO_0(x)		S5PC100_GPH0(x)
+#define EINT_GPIO_1(x)		S5PC100_GPH1(x)
+#define EINT_GPIO_2(x)		S5PC100_GPH2(x)
+#define EINT_GPIO_3(x)		S5PC100_GPH3(x)
 
 #endif /* __ASM_MACH_S5PC100_REGS_GPIO_H */
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END	  (0xe0000000UL)
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/irq-gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/irq-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/irq-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/irq-gpio.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,266 +0,0 @@
-/*
- * arch/arm/mach-s5pc100/irq-gpio.c
- *
- * Copyright (C) 2009 Samsung Electronics
- *
- * S5PC100 - Interrupt handling for IRQ_GPIO${group}(x)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-
-#include <mach/map.h>
-#include <plat/gpio-cfg.h>
-
-#define S5P_GPIOREG(x)		(S5P_VA_GPIO + (x))
-
-#define CON_OFFSET			0x700
-#define MASK_OFFSET			0x900
-#define PEND_OFFSET			0xA00
-#define CON_OFFSET_2			0xE00
-#define MASK_OFFSET_2			0xF00
-#define PEND_OFFSET_2			0xF40
-
-#define GPIOINT_LEVEL_LOW		0x0
-#define GPIOINT_LEVEL_HIGH		0x1
-#define GPIOINT_EDGE_FALLING		0x2
-#define GPIOINT_EDGE_RISING		0x3
-#define GPIOINT_EDGE_BOTH		0x4
-
-static int group_to_con_offset(int group)
-{
-	return group << 2;
-}
-
-static int group_to_mask_offset(int group)
-{
-	return group << 2;
-}
-
-static int group_to_pend_offset(int group)
-{
-	return group << 2;
-}
-
-static int s5pc100_get_start(unsigned int group)
-{
-	switch (group) {
-	case 0: return S5PC100_GPIO_A0_START;
-	case 1: return S5PC100_GPIO_A1_START;
-	case 2: return S5PC100_GPIO_B_START;
-	case 3: return S5PC100_GPIO_C_START;
-	case 4: return S5PC100_GPIO_D_START;
-	case 5: return S5PC100_GPIO_E0_START;
-	case 6: return S5PC100_GPIO_E1_START;
-	case 7: return S5PC100_GPIO_F0_START;
-	case 8: return S5PC100_GPIO_F1_START;
-	case 9: return S5PC100_GPIO_F2_START;
-	case 10: return S5PC100_GPIO_F3_START;
-	case 11: return S5PC100_GPIO_G0_START;
-	case 12: return S5PC100_GPIO_G1_START;
-	case 13: return S5PC100_GPIO_G2_START;
-	case 14: return S5PC100_GPIO_G3_START;
-	case 15: return S5PC100_GPIO_I_START;
-	case 16: return S5PC100_GPIO_J0_START;
-	case 17: return S5PC100_GPIO_J1_START;
-	case 18: return S5PC100_GPIO_J2_START;
-	case 19: return S5PC100_GPIO_J3_START;
-	case 20: return S5PC100_GPIO_J4_START;
-	default:
-		BUG();
-	}
-
-	return -EINVAL;
-}
-
-static int s5pc100_get_group(unsigned int irq)
-{
-	irq -= S3C_IRQ_GPIO(0);
-
-	switch (irq) {
-	case S5PC100_GPIO_A0_START ... S5PC100_GPIO_A1_START - 1:
-		return 0;
-	case S5PC100_GPIO_A1_START ... S5PC100_GPIO_B_START - 1:
-		return 1;
-	case S5PC100_GPIO_B_START ... S5PC100_GPIO_C_START - 1:
-		return 2;
-	case S5PC100_GPIO_C_START ... S5PC100_GPIO_D_START - 1:
-		return 3;
-	case S5PC100_GPIO_D_START ... S5PC100_GPIO_E0_START - 1:
-		return 4;
-	case S5PC100_GPIO_E0_START ... S5PC100_GPIO_E1_START - 1:
-		return 5;
-	case S5PC100_GPIO_E1_START ... S5PC100_GPIO_F0_START - 1:
-		return 6;
-	case S5PC100_GPIO_F0_START ... S5PC100_GPIO_F1_START - 1:
-		return 7;
-	case S5PC100_GPIO_F1_START ... S5PC100_GPIO_F2_START - 1:
-		return 8;
-	case S5PC100_GPIO_F2_START ... S5PC100_GPIO_F3_START - 1:
-		return 9;
-	case S5PC100_GPIO_F3_START ... S5PC100_GPIO_G0_START - 1:
-		return 10;
-	case S5PC100_GPIO_G0_START ... S5PC100_GPIO_G1_START - 1:
-		return 11;
-	case S5PC100_GPIO_G1_START ... S5PC100_GPIO_G2_START - 1:
-		return 12;
-	case S5PC100_GPIO_G2_START ... S5PC100_GPIO_G3_START - 1:
-		return 13;
-	case S5PC100_GPIO_G3_START ... S5PC100_GPIO_H0_START - 1:
-		return 14;
-	case S5PC100_GPIO_I_START ... S5PC100_GPIO_J0_START - 1:
-		return 15;
-	case S5PC100_GPIO_J0_START ... S5PC100_GPIO_J1_START - 1:
-		return 16;
-	case S5PC100_GPIO_J1_START ... S5PC100_GPIO_J2_START - 1:
-		return 17;
-	case S5PC100_GPIO_J2_START ... S5PC100_GPIO_J3_START - 1:
-		return 18;
-	case S5PC100_GPIO_J3_START ... S5PC100_GPIO_J4_START - 1:
-		return 19;
-	case S5PC100_GPIO_J4_START ... S5PC100_GPIO_K0_START - 1:
-		return 20;
-	default:
-		BUG();
-	}
-
-	return -EINVAL;
-}
-
-static int s5pc100_get_offset(unsigned int irq)
-{
-	struct gpio_chip *chip = get_irq_data(irq);
-	return irq - S3C_IRQ_GPIO(chip->base);
-}
-
-static void s5pc100_gpioint_ack(unsigned int irq)
-{
-	int group, offset, pend_offset;
-	unsigned int value;
-
-	group = s5pc100_get_group(irq);
-	offset = s5pc100_get_offset(irq);
-	pend_offset = group_to_pend_offset(group);
-
-	value = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset);
-	value |= 1 << offset;
-	__raw_writel(value, S5P_GPIOREG(PEND_OFFSET) + pend_offset);
-}
-
-static void s5pc100_gpioint_mask(unsigned int irq)
-{
-	int group, offset, mask_offset;
-	unsigned int value;
-
-	group = s5pc100_get_group(irq);
-	offset = s5pc100_get_offset(irq);
-	mask_offset = group_to_mask_offset(group);
-
-	value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
-	value |= 1 << offset;
-	__raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset);
-}
-
-static void s5pc100_gpioint_unmask(unsigned int irq)
-{
-	int group, offset, mask_offset;
-	unsigned int value;
-
-	group = s5pc100_get_group(irq);
-	offset = s5pc100_get_offset(irq);
-	mask_offset = group_to_mask_offset(group);
-
-	value = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
-	value &= ~(1 << offset);
-	__raw_writel(value, S5P_GPIOREG(MASK_OFFSET) + mask_offset);
-}
-
-static void s5pc100_gpioint_mask_ack(unsigned int irq)
-{
-	s5pc100_gpioint_mask(irq);
-	s5pc100_gpioint_ack(irq);
-}
-
-static int s5pc100_gpioint_set_type(unsigned int irq, unsigned int type)
-{
-	int group, offset, con_offset;
-	unsigned int value;
-
-	group = s5pc100_get_group(irq);
-	offset = s5pc100_get_offset(irq);
-	con_offset = group_to_con_offset(group);
-
-	switch (type) {
-	case IRQ_TYPE_NONE:
-		printk(KERN_WARNING "No irq type\n");
-		return -EINVAL;
-	case IRQ_TYPE_EDGE_RISING:
-		type = GPIOINT_EDGE_RISING;
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		type = GPIOINT_EDGE_FALLING;
-		break;
-	case IRQ_TYPE_EDGE_BOTH:
-		type = GPIOINT_EDGE_BOTH;
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		type = GPIOINT_LEVEL_HIGH;
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		type = GPIOINT_LEVEL_LOW;
-		break;
-	default:
-		BUG();
-	}
-
-
-	value = __raw_readl(S5P_GPIOREG(CON_OFFSET) + con_offset);
-	value &= ~(0xf << (offset * 0x4));
-	value |= (type << (offset * 0x4));
-	__raw_writel(value, S5P_GPIOREG(CON_OFFSET) + con_offset);
-
-	return 0;
-}
-
-struct irq_chip s5pc100_gpioint = {
-	.name		= "GPIO",
-	.ack		= s5pc100_gpioint_ack,
-	.mask		= s5pc100_gpioint_mask,
-	.mask_ack	= s5pc100_gpioint_mask_ack,
-	.unmask		= s5pc100_gpioint_unmask,
-	.set_type	= s5pc100_gpioint_set_type,
-};
-
-void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc)
-{
-	int group, offset, pend_offset, mask_offset;
-	int real_irq, group_end;
-	unsigned int pend, mask;
-
-	group_end = 21;
-
-	for (group = 0; group < group_end; group++) {
-		pend_offset = group_to_pend_offset(group);
-		pend = __raw_readl(S5P_GPIOREG(PEND_OFFSET) + pend_offset);
-		if (!pend)
-			continue;
-
-		mask_offset = group_to_mask_offset(group);
-		mask = __raw_readl(S5P_GPIOREG(MASK_OFFSET) + mask_offset);
-		pend &= ~mask;
-
-		for (offset = 0; offset < 8; offset++) {
-			if (pend & (1 << offset)) {
-				real_irq = s5pc100_get_start(group) + offset;
-				generic_handle_irq(S3C_IRQ_GPIO(real_irq));
-			}
-		}
-	}
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,6 @@
 
 config CPU_S5PC100
 	bool
-	select PLAT_S5P
 	select S5P_EXT_INT
 	select S3C_PL330_DMA
 	help
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/mach-smdkc100.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/mach-smdkc100.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/mach-smdkc100.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/mach-smdkc100.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 #include <plat/adc.h>
 #include <plat/keypad.h>
 #include <plat/ts.h>
+#include <plat/audio.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define SMDKC100_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
@@ -196,6 +197,7 @@
 	&s5p_device_fimc0,
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
+	&s5pc100_device_spdif,
 };
 
 static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
@@ -226,6 +228,8 @@
 
 	samsung_keypad_set_platdata(&smdkc100_keypad_data);
 
+	s5pc100_spdif_setup_gpio(S5PC100_SPDIF_GPD);
+
 	/* LCD init */
 	gpio_request(S5PC100_GPD(0), "GPD");
 	gpio_request(S5PC100_GPH0(6), "GPH0");
@@ -235,8 +239,6 @@
 
 MACHINE_START(SMDKC100, "SMDKC100")
 	/* Maintainer: Byungho Min <bhmin@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pc100_init_irq,
 	.map_io		= smdkc100_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,7 @@
 
 # Core support for S5PC100 system
 
-obj-$(CONFIG_CPU_S5PC100)	+= cpu.o init.o clock.o gpiolib.o irq-gpio.o
+obj-$(CONFIG_CPU_S5PC100)	+= cpu.o init.o clock.o gpiolib.o
 obj-$(CONFIG_CPU_S5PC100)	+= setup-i2c0.o
 obj-$(CONFIG_CPU_S5PC100)	+= dma.o
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-fb-24bpp.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-fb-24bpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-fb-24bpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-fb-24bpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,27 +22,15 @@
 
 #define DISR_OFFSET	0x7008
 
-void s5pc100_fb_gpio_setup_24bpp(void)
+static void s5pc100_fb_setgpios(unsigned int base, unsigned int nr)
 {
-	unsigned int gpio = 0;
-
-	for (gpio = S5PC100_GPF0(0); gpio <= S5PC100_GPF0(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	for (gpio = S5PC100_GPF1(0); gpio <= S5PC100_GPF1(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
-
-	for (gpio = S5PC100_GPF2(0); gpio <= S5PC100_GPF2(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(2));
+}
 
-	for (gpio = S5PC100_GPF3(0); gpio <= S5PC100_GPF3(3); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+void s5pc100_fb_gpio_setup_24bpp(void)
+{
+	s5pc100_fb_setgpios(S5PC100_GPF0(0), 8);
+	s5pc100_fb_setgpios(S5PC100_GPF1(0), 8);
+	s5pc100_fb_setgpios(S5PC100_GPF2(0), 8);
+	s5pc100_fb_setgpios(S5PC100_GPF3(0), 4);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-i2c0.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-i2c0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-i2c0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-i2c0.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,8 +23,6 @@
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PC100_GPD(3), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PC100_GPD(3), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PC100_GPD(4), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PC100_GPD(4), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PC100_GPD(3), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-i2c1.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-i2c1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-i2c1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-i2c1.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,8 +23,6 @@
 
 void s3c_i2c1_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PC100_GPD(5), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PC100_GPD(5), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PC100_GPD(6), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PC100_GPD(6), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PC100_GPD(5), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-ide.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-ide.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-ide.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-ide.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,52 +17,39 @@
 #include <mach/regs-clock.h>
 #include <plat/gpio-cfg.h>
 
+static void s5pc100_ide_cfg_gpios(unsigned int base, unsigned int nr)
+{
+	s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(4));
+
+	for (; nr > 0; nr--, base++)
+		s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4);
+}
+
 void s5pc100_ide_setup_gpio(void)
 {
 	u32 reg;
-	u32 gpio = 0;
 
 	/* Independent CF interface, CF chip select configuration */
 	reg = readl(S5PC100_MEM_SYS_CFG) & (~0x3f);
 	writel(reg | MEM_SYS_CFG_EBI_FIX_PRI_CFCON, S5PC100_MEM_SYS_CFG);
 
 	/* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, CF_DMACK */
-	for (gpio = S5PC100_GPJ0(0); gpio <= S5PC100_GPJ0(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	s5pc100_ide_cfg_gpios(S5PC100_GPJ0(0), 8);
 
 	/*CF_Data[0 - 7] */
-	for (gpio = S5PC100_GPJ2(0); gpio <= S5PC100_GPJ2(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	s5pc100_ide_cfg_gpios(S5PC100_GPJ2(0), 8);
 
 	/* CF_Data[8 - 15] */
-	for (gpio = S5PC100_GPJ3(0); gpio <= S5PC100_GPJ3(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	s5pc100_ide_cfg_gpios(S5PC100_GPJ3(0), 8);
 
 	/* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */
-	for (gpio = S5PC100_GPJ4(0); gpio <= S5PC100_GPJ4(3); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	s5pc100_ide_cfg_gpios(S5PC100_GPJ4(0), 4);
 
 	/* EBI_OE, EBI_WE */
-	for (gpio = S5PC100_GPK0(6); gpio <= S5PC100_GPK0(7); gpio++)
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0));
+	s3c_gpio_cfgpin_range(S5PC100_GPK0(6), 2, S3C_GPIO_SFN(0));
 
 	/* CF_OE, CF_WE */
-	for (gpio = S5PC100_GPK1(6); gpio <= S5PC100_GPK1(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPK1(6), 8, S3C_GPIO_SFN(2));
 
 	/* CF_CD */
 	s3c_gpio_cfgpin(S5PC100_GPK3(5), S3C_GPIO_SFN(2));
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-keypad.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-keypad.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-keypad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-keypad.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,20 +15,9 @@
 
 void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
 {
-	unsigned int gpio;
-	unsigned int end;
-
 	/* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */
-	end = S5PC100_GPH3(rows);
-	for (gpio = S5PC100_GPH3(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPH3(0), rows, S3C_GPIO_SFN(3));
 
 	/* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */
-	end = S5PC100_GPH2(cols);
-	for (gpio = S5PC100_GPH2(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPH2(0), cols, S3C_GPIO_SFN(3));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-sdhci-gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-sdhci-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pc100/setup-sdhci-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pc100/setup-sdhci-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,8 +25,6 @@
 void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
-	unsigned int end;
 	unsigned int num;
 
 	num = width;
@@ -34,20 +32,11 @@
 	if (width == 8)
 		num = width - 2;
 
-	end = S5PC100_GPG0(2 + num);
-
 	/* Set all the necessary GPG0/GPG1 pins to special-function 0 */
-	for (gpio = S5PC100_GPG0(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPG0(0), 2 + num, S3C_GPIO_SFN(2));
 
-	if (width == 8) {
-		for (gpio = S5PC100_GPG1(0); gpio <= S5PC100_GPG1(1); gpio++) {
-			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		}
-	}
+	if (width == 8)
+		s3c_gpio_cfgrange_nopull(S5PC100_GPG1(0), 2, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP);
@@ -58,16 +47,9 @@
 void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S5PC100_GPG2(2 + width);
 
 	/* Set all the necessary GPG2 pins to special-function 2 */
-	for (gpio = S5PC100_GPG2(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPG2(0), 2 + width, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP);
@@ -78,16 +60,9 @@
 void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
-	unsigned int end;
-
-	end = S5PC100_GPG3(2 + width);
 
 	/* Set all the necessary GPG3 pins to special-function 2 */
-	for (gpio = S5PC100_GPG3(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PC100_GPG3(0), 2 + width, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,8 @@
 #include <plat/clock-clksrc.h>
 #include <plat/s5pv210.h>
 
+static unsigned long xtal;
+
 static struct clksrc_clk clk_mout_apll = {
 	.clk	= {
 		.name		= "mout_apll",
@@ -259,6 +261,36 @@
 	.reg_src	= { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 },
 };
 
+static struct clk *clkset_moutdmc0src_list[] = {
+	[0] = &clk_sclk_a2m.clk,
+	[1] = &clk_mout_mpll.clk,
+	[2] = NULL,
+	[3] = NULL,
+};
+
+static struct clksrc_sources clkset_moutdmc0src = {
+	.sources	= clkset_moutdmc0src_list,
+	.nr_sources	= ARRAY_SIZE(clkset_moutdmc0src_list),
+};
+
+static struct clksrc_clk clk_mout_dmc0 = {
+	.clk	= {
+		.name		= "mout_dmc0",
+		.id		= -1,
+	},
+	.sources	= &clkset_moutdmc0src,
+	.reg_src	= { .reg = S5P_CLK_SRC6, .shift = 24, .size = 2 },
+};
+
+static struct clksrc_clk clk_sclk_dmc0 = {
+	.clk	= {
+		.name		= "sclk_dmc0",
+		.id		= -1,
+		.parent		= &clk_mout_dmc0.clk,
+	},
+	.reg_div	= { .reg = S5P_CLK_DIV6, .shift = 28, .size = 4 },
+};
+
 static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk)
 {
 	return clk_get_rate(clk->parent) / 2;
@@ -268,8 +300,29 @@
 	.get_rate	= s5pv210_clk_imem_get_rate,
 };
 
+static unsigned long s5pv210_clk_fout_apll_get_rate(struct clk *clk)
+{
+	return s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
+}
+
+static struct clk_ops clk_fout_apll_ops = {
+	.get_rate	= s5pv210_clk_fout_apll_get_rate,
+};
+
 static struct clk init_clocks_disable[] = {
 	{
+		.name		= "pdma",
+		.id		= 0,
+		.parent		= &clk_hclk_psys.clk,
+		.enable		= s5pv210_clk_ip0_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "pdma",
+		.id		= 1,
+		.parent		= &clk_hclk_psys.clk,
+		.enable		= s5pv210_clk_ip0_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
 		.name		= "rot",
 		.id		= -1,
 		.parent		= &clk_hclk_dsys.clk,
@@ -431,6 +484,12 @@
 		.parent		= &clk_p,
 		.enable		= s5pv210_clk_ip3_ctrl,
 		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "spdif",
+		.id		= -1,
+		.parent		= &clk_p,
+		.enable		= s5pv210_clk_ip3_ctrl,
+		.ctrlbit	= (1 << 0),
 	},
 };
 
@@ -660,6 +719,53 @@
 	.nr_sources	= ARRAY_SIZE(clkset_sclk_spdif_list),
 };
 
+static int s5pv210_spdif_set_rate(struct clk *clk, unsigned long rate)
+{
+	struct clk *pclk;
+	int ret;
+
+	pclk = clk_get_parent(clk);
+	if (IS_ERR(pclk))
+		return -EINVAL;
+
+	ret = pclk->ops->set_rate(pclk, rate);
+	clk_put(pclk);
+
+	return ret;
+}
+
+static unsigned long s5pv210_spdif_get_rate(struct clk *clk)
+{
+	struct clk *pclk;
+	int rate;
+
+	pclk = clk_get_parent(clk);
+	if (IS_ERR(pclk))
+		return -EINVAL;
+
+	rate = pclk->ops->get_rate(clk);
+	clk_put(pclk);
+
+	return rate;
+}
+
+static struct clk_ops s5pv210_sclk_spdif_ops = {
+	.set_rate	= s5pv210_spdif_set_rate,
+	.get_rate	= s5pv210_spdif_get_rate,
+};
+
+static struct clksrc_clk clk_sclk_spdif = {
+	.clk		= {
+		.name		= "sclk_spdif",
+		.id		= -1,
+		.enable		= s5pv210_clk_mask0_ctrl,
+		.ctrlbit	= (1 << 27),
+		.ops		= &s5pv210_sclk_spdif_ops,
+	},
+	.sources = &clkset_sclk_spdif,
+	.reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 },
+};
+
 static struct clk *clkset_group2_list[] = {
 	[0] = &clk_ext_xtal_mux,
 	[1] = &clk_xusbxti,
@@ -744,15 +850,6 @@
 		.sources = &clkset_sclk_mixer,
 		.reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 },
 	}, {
-		.clk		= {
-			.name		= "sclk_spdif",
-			.id		= -1,
-			.enable		= s5pv210_clk_mask0_ctrl,
-			.ctrlbit	= (1 << 27),
-		},
-		.sources = &clkset_sclk_spdif,
-		.reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 },
-	}, {
 		.clk	= {
 			.name		= "sclk_fimc",
 			.id		= 0,
@@ -953,12 +1050,93 @@
 	&clk_sclk_dac,
 	&clk_sclk_pixel,
 	&clk_sclk_hdmi,
+	&clk_mout_dmc0,
+	&clk_sclk_dmc0,
+	&clk_sclk_audio0,
+	&clk_sclk_audio1,
+	&clk_sclk_audio2,
+	&clk_sclk_spdif,
+};
+
+static u32 epll_div[][6] = {
+	{  48000000, 0, 48, 3, 3, 0 },
+	{  96000000, 0, 48, 3, 2, 0 },
+	{ 144000000, 1, 72, 3, 2, 0 },
+	{ 192000000, 0, 48, 3, 1, 0 },
+	{ 288000000, 1, 72, 3, 1, 0 },
+	{  32750000, 1, 65, 3, 4, 35127 },
+	{  32768000, 1, 65, 3, 4, 35127 },
+	{  45158400, 0, 45, 3, 3, 10355 },
+	{  45000000, 0, 45, 3, 3, 10355 },
+	{  45158000, 0, 45, 3, 3, 10355 },
+	{  49125000, 0, 49, 3, 3, 9961 },
+	{  49152000, 0, 49, 3, 3, 9961 },
+	{  67737600, 1, 67, 3, 3, 48366 },
+	{  67738000, 1, 67, 3, 3, 48366 },
+	{  73800000, 1, 73, 3, 3, 47710 },
+	{  73728000, 1, 73, 3, 3, 47710 },
+	{  36000000, 1, 32, 3, 4, 0 },
+	{  60000000, 1, 60, 3, 3, 0 },
+	{  72000000, 1, 72, 3, 3, 0 },
+	{  80000000, 1, 80, 3, 3, 0 },
+	{  84000000, 0, 42, 3, 2, 0 },
+	{  50000000, 0, 50, 3, 3, 0 },
+};
+
+static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int epll_con, epll_con_k;
+	unsigned int i;
+
+	/* Return if nothing changed */
+	if (clk->rate == rate)
+		return 0;
+
+	epll_con = __raw_readl(S5P_EPLL_CON);
+	epll_con_k = __raw_readl(S5P_EPLL_CON1);
+
+	epll_con_k &= ~PLL46XX_KDIV_MASK;
+	epll_con &= ~(1 << 27 |
+			PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT |
+			PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT |
+			PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+
+	for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+		if (epll_div[i][0] == rate) {
+			epll_con_k |= epll_div[i][5] << 0;
+			epll_con |= (epll_div[i][1] << 27 |
+					epll_div[i][2] << PLL46XX_MDIV_SHIFT |
+					epll_div[i][3] << PLL46XX_PDIV_SHIFT |
+					epll_div[i][4] << PLL46XX_SDIV_SHIFT);
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(epll_div)) {
+		printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	__raw_writel(epll_con, S5P_EPLL_CON);
+	__raw_writel(epll_con_k, S5P_EPLL_CON1);
+
+	printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n",
+			clk->rate, rate);
+
+	clk->rate = rate;
+
+	return 0;
+}
+
+static struct clk_ops s5pv210_epll_ops = {
+	.set_rate = s5pv210_epll_set_rate,
+	.get_rate = s5p_epll_get_rate,
 };
 
 void __init_or_cpufreq s5pv210_setup_clocks(void)
 {
 	struct clk *xtal_clk;
-	unsigned long xtal;
 	unsigned long vpllsrc;
 	unsigned long armclk;
 	unsigned long hclk_msys;
@@ -974,6 +1152,10 @@
 	unsigned int ptr;
 	u32 clkdiv0, clkdiv1;
 
+	/* Set functions for clk_fout_epll */
+	clk_fout_epll.enable = s5p_epll_enable;
+	clk_fout_epll.ops = &s5pv210_epll_ops;
+
 	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
 
 	clkdiv0 = __raw_readl(S5P_CLK_DIV0);
@@ -992,11 +1174,12 @@
 
 	apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
 	mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
-	epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500);
+	epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON),
+				__raw_readl(S5P_EPLL_CON1), pll_4600);
 	vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
 	vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502);
 
-	clk_fout_apll.rate = apll;
+	clk_fout_apll.ops = &clk_fout_apll_ops;
 	clk_fout_mpll.rate = mpll;
 	clk_fout_epll.rate = epll;
 	clk_fout_vpll.rate = vpll;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s5pv210/cpu.c
  *
  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
+ *		http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -51,6 +51,21 @@
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S5P_VA_GPIO,
+		.pfn		= __phys_to_pfn(S5PV210_PA_GPIO),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC0,
+		.pfn		= __phys_to_pfn(S5PV210_PA_VIC0),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)VA_VIC1,
+		.pfn		= __phys_to_pfn(S5PV210_PA_VIC1),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)VA_VIC2,
 		.pfn		= __phys_to_pfn(S5PV210_PA_VIC2),
 		.length		= SZ_16K,
@@ -61,10 +76,30 @@
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S3C_PA_UART),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)S5P_VA_SROMC,
 		.pfn		= __phys_to_pfn(S5PV210_PA_SROMC),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_DMC0,
+		.pfn		= __phys_to_pfn(S5PV210_PA_DMC0),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_DMC1,
+		.pfn		= __phys_to_pfn(S5PV210_PA_DMC1),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_USB_HSPHY,
+		.pfn		=__phys_to_pfn(S5PV210_PA_HSPHY),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
 	}
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/cpufreq.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/cpufreq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/cpufreq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,484 @@
+/* linux/arch/arm/mach-s5pv210/cpufreq.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * CPU frequency scaling for S5PC110/S5PV210
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/cpufreq.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+static struct clk *cpu_clk;
+static struct clk *dmc0_clk;
+static struct clk *dmc1_clk;
+static struct cpufreq_freqs freqs;
+
+/* APLL M,P,S values for 1G/800Mhz */
+#define APLL_VAL_1000	((1 << 31) | (125 << 16) | (3 << 8) | 1)
+#define APLL_VAL_800	((1 << 31) | (100 << 16) | (3 << 8) | 1)
+
+/*
+ * DRAM configurations to calculate refresh counter for changing
+ * frequency of memory.
+ */
+struct dram_conf {
+	unsigned long freq;	/* HZ */
+	unsigned long refresh;	/* DRAM refresh counter * 1000 */
+};
+
+/* DRAM configuration (DMC0 and DMC1) */
+static struct dram_conf s5pv210_dram_conf[2];
+
+enum perf_level {
+	L0, L1, L2, L3, L4,
+};
+
+enum s5pv210_mem_type {
+	LPDDR	= 0x1,
+	LPDDR2	= 0x2,
+	DDR2	= 0x4,
+};
+
+enum s5pv210_dmc_port {
+	DMC0 = 0,
+	DMC1,
+};
+
+static struct cpufreq_frequency_table s5pv210_freq_table[] = {
+	{L0, 1000*1000},
+	{L1, 800*1000},
+	{L2, 400*1000},
+	{L3, 200*1000},
+	{L4, 100*1000},
+	{0, CPUFREQ_TABLE_END},
+};
+
+static u32 clkdiv_val[5][11] = {
+	/*
+	 * Clock divider value for following
+	 * { APLL, A2M, HCLK_MSYS, PCLK_MSYS,
+	 *   HCLK_DSYS, PCLK_DSYS, HCLK_PSYS, PCLK_PSYS,
+	 *   ONEDRAM, MFC, G3D }
+	 */
+
+	/* L0 : [1000/200/100][166/83][133/66][200/200] */
+	{0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L1 : [800/200/100][166/83][133/66][200/200] */
+	{0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L2 : [400/200/100][166/83][133/66][200/200] */
+	{1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L3 : [200/200/100][166/83][133/66][200/200] */
+	{3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0},
+
+	/* L4 : [100/100/100][83/83][66/66][100/100] */
+	{7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0},
+};
+
+/*
+ * This function set DRAM refresh counter
+ * accoriding to operating frequency of DRAM
+ * ch: DMC port number 0 or 1
+ * freq: Operating frequency of DRAM(KHz)
+ */
+static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
+{
+	unsigned long tmp, tmp1;
+	void __iomem *reg = NULL;
+
+	if (ch == DMC0)
+		reg = (S5P_VA_DMC0 + 0x30);
+	else if (ch == DMC1)
+		reg = (S5P_VA_DMC1 + 0x30);
+	else
+		printk(KERN_ERR "Cannot find DMC port\n");
+
+	/* Find current DRAM frequency */
+	tmp = s5pv210_dram_conf[ch].freq;
+
+	do_div(tmp, freq);
+
+	tmp1 = s5pv210_dram_conf[ch].refresh;
+
+	do_div(tmp1, tmp);
+
+	__raw_writel(tmp1, reg);
+}
+
+int s5pv210_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, s5pv210_freq_table);
+}
+
+unsigned int s5pv210_getspeed(unsigned int cpu)
+{
+	if (cpu)
+		return 0;
+
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int s5pv210_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
+{
+	unsigned long reg;
+	unsigned int index, priv_index;
+	unsigned int pll_changing = 0;
+	unsigned int bus_speed_changing = 0;
+
+	freqs.old = s5pv210_getspeed(0);
+
+	if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+					   target_freq, relation, &index))
+		return -EINVAL;
+
+	freqs.new = s5pv210_freq_table[index].frequency;
+	freqs.cpu = 0;
+
+	if (freqs.new == freqs.old)
+		return 0;
+
+	/* Finding current running level index */
+	if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
+					   freqs.old, relation, &priv_index))
+		return -EINVAL;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	if (freqs.new > freqs.old) {
+		/* Voltage up: will be implemented */
+	}
+
+	/* Check if there need to change PLL */
+	if ((index == L0) || (priv_index == L0))
+		pll_changing = 1;
+
+	/* Check if there need to change System bus clock */
+	if ((index == L4) || (priv_index == L4))
+		bus_speed_changing = 1;
+
+	if (bus_speed_changing) {
+		/*
+		 * Reconfigure DRAM refresh counter value for minimum
+		 * temporary clock while changing divider.
+		 * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287
+		 */
+		if (pll_changing)
+			s5pv210_set_refresh(DMC1, 83000);
+		else
+			s5pv210_set_refresh(DMC1, 100000);
+
+		s5pv210_set_refresh(DMC0, 83000);
+	}
+
+	/*
+	 * APLL should be changed in this level
+	 * APLL -> MPLL(for stable transition) -> APLL
+	 * Some clock source's clock API are not prepared.
+	 * Do not use clock API in below code.
+	 */
+	if (pll_changing) {
+		/*
+		 * 1. Temporary Change divider for MFC and G3D
+		 * SCLKA2M(200/1=200)->(200/4=50)Mhz
+		 */
+		reg = __raw_readl(S5P_CLK_DIV2);
+		reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+		reg |= (3 << S5P_CLKDIV2_G3D_SHIFT) |
+			(3 << S5P_CLKDIV2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_DIV2);
+
+		/* For MFC, G3D dividing */
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT0);
+		} while (reg & ((1 << 16) | (1 << 17)));
+
+		/*
+		 * 2. Change SCLKA2M(200Mhz)to SCLKMPLL in MFC_MUX, G3D MUX
+		 * (200/4=50)->(667/4=166)Mhz
+		 */
+		reg = __raw_readl(S5P_CLK_SRC2);
+		reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+		reg |= (1 << S5P_CLKSRC2_G3D_SHIFT) |
+			(1 << S5P_CLKSRC2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC2);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT1);
+		} while (reg & ((1 << 7) | (1 << 3)));
+
+		/*
+		 * 3. DMC1 refresh count for 133Mhz if (index == L4) is
+		 * true refresh counter is already programed in upper
+		 * code. 0x287@83Mhz
+		 */
+		if (!bus_speed_changing)
+			s5pv210_set_refresh(DMC1, 133000);
+
+		/* 4. SCLKAPLL -> SCLKMPLL */
+		reg = __raw_readl(S5P_CLK_SRC0);
+		reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+		reg |= (0x1 << S5P_CLKSRC0_MUX200_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC0);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT0);
+		} while (reg & (0x1 << 18));
+
+	}
+
+	/* Change divider */
+	reg = __raw_readl(S5P_CLK_DIV0);
+
+	reg &= ~(S5P_CLKDIV0_APLL_MASK | S5P_CLKDIV0_A2M_MASK |
+		S5P_CLKDIV0_HCLK200_MASK | S5P_CLKDIV0_PCLK100_MASK |
+		S5P_CLKDIV0_HCLK166_MASK | S5P_CLKDIV0_PCLK83_MASK |
+		S5P_CLKDIV0_HCLK133_MASK | S5P_CLKDIV0_PCLK66_MASK);
+
+	reg |= ((clkdiv_val[index][0] << S5P_CLKDIV0_APLL_SHIFT) |
+		(clkdiv_val[index][1] << S5P_CLKDIV0_A2M_SHIFT) |
+		(clkdiv_val[index][2] << S5P_CLKDIV0_HCLK200_SHIFT) |
+		(clkdiv_val[index][3] << S5P_CLKDIV0_PCLK100_SHIFT) |
+		(clkdiv_val[index][4] << S5P_CLKDIV0_HCLK166_SHIFT) |
+		(clkdiv_val[index][5] << S5P_CLKDIV0_PCLK83_SHIFT) |
+		(clkdiv_val[index][6] << S5P_CLKDIV0_HCLK133_SHIFT) |
+		(clkdiv_val[index][7] << S5P_CLKDIV0_PCLK66_SHIFT));
+
+	__raw_writel(reg, S5P_CLK_DIV0);
+
+	do {
+		reg = __raw_readl(S5P_CLKDIV_STAT0);
+	} while (reg & 0xff);
+
+	/* ARM MCS value changed */
+	reg = __raw_readl(S5P_ARM_MCS_CON);
+	reg &= ~0x3;
+	if (index >= L3)
+		reg |= 0x3;
+	else
+		reg |= 0x1;
+
+	__raw_writel(reg, S5P_ARM_MCS_CON);
+
+	if (pll_changing) {
+		/* 5. Set Lock time = 30us*24Mhz = 0x2cf */
+		__raw_writel(0x2cf, S5P_APLL_LOCK);
+
+		/*
+		 * 6. Turn on APLL
+		 * 6-1. Set PMS values
+		 * 6-2. Wait untile the PLL is locked
+		 */
+		if (index == L0)
+			__raw_writel(APLL_VAL_1000, S5P_APLL_CON);
+		else
+			__raw_writel(APLL_VAL_800, S5P_APLL_CON);
+
+		do {
+			reg = __raw_readl(S5P_APLL_CON);
+		} while (!(reg & (0x1 << 29)));
+
+		/*
+		 * 7. Change souce clock from SCLKMPLL(667Mhz)
+		 * to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX
+		 * (667/4=166)->(200/4=50)Mhz
+		 */
+		reg = __raw_readl(S5P_CLK_SRC2);
+		reg &= ~(S5P_CLKSRC2_G3D_MASK | S5P_CLKSRC2_MFC_MASK);
+		reg |= (0 << S5P_CLKSRC2_G3D_SHIFT) |
+			(0 << S5P_CLKSRC2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC2);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT1);
+		} while (reg & ((1 << 7) | (1 << 3)));
+
+		/*
+		 * 8. Change divider for MFC and G3D
+		 * (200/4=50)->(200/1=200)Mhz
+		 */
+		reg = __raw_readl(S5P_CLK_DIV2);
+		reg &= ~(S5P_CLKDIV2_G3D_MASK | S5P_CLKDIV2_MFC_MASK);
+		reg |= (clkdiv_val[index][10] << S5P_CLKDIV2_G3D_SHIFT) |
+			(clkdiv_val[index][9] << S5P_CLKDIV2_MFC_SHIFT);
+		__raw_writel(reg, S5P_CLK_DIV2);
+
+		/* For MFC, G3D dividing */
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT0);
+		} while (reg & ((1 << 16) | (1 << 17)));
+
+		/* 9. Change MPLL to APLL in MSYS_MUX */
+		reg = __raw_readl(S5P_CLK_SRC0);
+		reg &= ~(S5P_CLKSRC0_MUX200_MASK);
+		reg |= (0x0 << S5P_CLKSRC0_MUX200_SHIFT);
+		__raw_writel(reg, S5P_CLK_SRC0);
+
+		do {
+			reg = __raw_readl(S5P_CLKMUX_STAT0);
+		} while (reg & (0x1 << 18));
+
+		/*
+		 * 10. DMC1 refresh counter
+		 * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c
+		 * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618
+		 */
+		if (!bus_speed_changing)
+			s5pv210_set_refresh(DMC1, 200000);
+	}
+
+	/*
+	 * L4 level need to change memory bus speed, hence onedram clock divier
+	 * and memory refresh parameter should be changed
+	 */
+	if (bus_speed_changing) {
+		reg = __raw_readl(S5P_CLK_DIV6);
+		reg &= ~S5P_CLKDIV6_ONEDRAM_MASK;
+		reg |= (clkdiv_val[index][8] << S5P_CLKDIV6_ONEDRAM_SHIFT);
+		__raw_writel(reg, S5P_CLK_DIV6);
+
+		do {
+			reg = __raw_readl(S5P_CLKDIV_STAT1);
+		} while (reg & (1 << 15));
+
+		/* Reconfigure DRAM refresh counter value */
+		if (index != L4) {
+			/*
+			 * DMC0 : 166Mhz
+			 * DMC1 : 200Mhz
+			 */
+			s5pv210_set_refresh(DMC0, 166000);
+			s5pv210_set_refresh(DMC1, 200000);
+		} else {
+			/*
+			 * DMC0 : 83Mhz
+			 * DMC1 : 100Mhz
+			 */
+			s5pv210_set_refresh(DMC0, 83000);
+			s5pv210_set_refresh(DMC1, 100000);
+		}
+	}
+
+	if (freqs.new < freqs.old) {
+		/* Voltage down: will be implemented */
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	printk(KERN_DEBUG "Perf changed[L%d]\n", index);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5pv210_cpufreq_suspend(struct cpufreq_policy *policy,
+				   pm_message_t pmsg)
+{
+	return 0;
+}
+
+static int s5pv210_cpufreq_resume(struct cpufreq_policy *policy)
+{
+	return 0;
+}
+#endif
+
+static int check_mem_type(void __iomem *dmc_reg)
+{
+	unsigned long val;
+
+	val = __raw_readl(dmc_reg + 0x4);
+	val = (val & (0xf << 8));
+
+	return val >> 8;
+}
+
+static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned long mem_type;
+
+	cpu_clk = clk_get(NULL, "armclk");
+	if (IS_ERR(cpu_clk))
+		return PTR_ERR(cpu_clk);
+
+	dmc0_clk = clk_get(NULL, "sclk_dmc0");
+	if (IS_ERR(dmc0_clk)) {
+		clk_put(cpu_clk);
+		return PTR_ERR(dmc0_clk);
+	}
+
+	dmc1_clk = clk_get(NULL, "hclk_msys");
+	if (IS_ERR(dmc1_clk)) {
+		clk_put(dmc0_clk);
+		clk_put(cpu_clk);
+		return PTR_ERR(dmc1_clk);
+	}
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	/*
+	 * check_mem_type : This driver only support LPDDR & LPDDR2.
+	 * other memory type is not supported.
+	 */
+	mem_type = check_mem_type(S5P_VA_DMC0);
+
+	if ((mem_type != LPDDR) && (mem_type != LPDDR2)) {
+		printk(KERN_ERR "CPUFreq doesn't support this memory type\n");
+		return -EINVAL;
+	}
+
+	/* Find current refresh counter and frequency each DMC */
+	s5pv210_dram_conf[0].refresh = (__raw_readl(S5P_VA_DMC0 + 0x30) * 1000);
+	s5pv210_dram_conf[0].freq = clk_get_rate(dmc0_clk);
+
+	s5pv210_dram_conf[1].refresh = (__raw_readl(S5P_VA_DMC1 + 0x30) * 1000);
+	s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
+
+	policy->cur = policy->min = policy->max = s5pv210_getspeed(0);
+
+	cpufreq_frequency_table_get_attr(s5pv210_freq_table, policy->cpu);
+
+	policy->cpuinfo.transition_latency = 40000;
+
+	return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table);
+}
+
+static struct cpufreq_driver s5pv210_driver = {
+	.flags		= CPUFREQ_STICKY,
+	.verify		= s5pv210_verify_speed,
+	.target		= s5pv210_target,
+	.get		= s5pv210_getspeed,
+	.init		= s5pv210_cpu_init,
+	.name		= "s5pv210",
+#ifdef CONFIG_PM
+	.suspend	= s5pv210_cpufreq_suspend,
+	.resume		= s5pv210_cpufreq_resume,
+#endif
+};
+
+static int __init s5pv210_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&s5pv210_driver);
+}
+
+late_initcall(s5pv210_cpufreq_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-audio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-audio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-audio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-audio.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,29 +24,15 @@
 	/* configure GPIO for i2s port */
 	switch (pdev->id) {
 	case 1:
-		s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(2));
 		break;
 
 	case 2:
-		s3c_gpio_cfgpin(S5PV210_GPC1(0), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PV210_GPC1(1), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PV210_GPC1(2), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PV210_GPC1(3), S3C_GPIO_SFN(4));
-		s3c_gpio_cfgpin(S5PV210_GPC1(4), S3C_GPIO_SFN(4));
+		s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(4));
 		break;
 
 	case -1:
-		s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(5), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPI(6), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
 		break;
 
 	default:
@@ -151,25 +137,13 @@
 {
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S5PV210_GPI(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPI(1), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPI(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPI(3), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPI(4), S3C_GPIO_SFN(3));
+		s3c_gpio_cfgpin_range(S5PV210_GPI(0), 5, S3C_GPIO_SFN(3));
 		break;
 	case 1:
-		s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(3));
-		s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(3));
+		s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(3));
 		break;
 	case 2:
-		s3c_gpio_cfgpin(S5PV210_GPC1(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC1(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC1(2), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC1(3), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPC1(4), S3C_GPIO_SFN(2));
+		s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(2));
 		break;
 	default:
 		printk(KERN_DEBUG "Invalid PCM Controller number!");
@@ -271,13 +245,7 @@
 
 static int s5pv210_ac97_cfg_gpio(struct platform_device *pdev)
 {
-	s3c_gpio_cfgpin(S5PV210_GPC0(0), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PV210_GPC0(1), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PV210_GPC0(2), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PV210_GPC0(3), S3C_GPIO_SFN(4));
-	s3c_gpio_cfgpin(S5PV210_GPC0(4), S3C_GPIO_SFN(4));
-
-	return 0;
+	return s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(4));
 }
 
 static struct resource s5pv210_ac97_resource[] = {
@@ -325,3 +293,43 @@
 		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 };
+
+/* S/PDIF Controller platform_device */
+
+static int s5pv210_spdif_cfg_gpio(struct platform_device *pdev)
+{
+	s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 2, S3C_GPIO_SFN(3));
+
+	return 0;
+}
+
+static struct resource s5pv210_spdif_resource[] = {
+	[0] = {
+		.start	= S5PV210_PA_SPDIF,
+		.end	= S5PV210_PA_SPDIF + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= DMACH_SPDIF,
+		.end	= DMACH_SPDIF,
+		.flags	= IORESOURCE_DMA,
+	},
+};
+
+static struct s3c_audio_pdata samsung_spdif_pdata = {
+	.cfg_gpio = s5pv210_spdif_cfg_gpio,
+};
+
+static u64 s5pv210_spdif_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5pv210_device_spdif = {
+	.name		= "samsung-spdif",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5pv210_spdif_resource),
+	.resource	= s5pv210_spdif_resource,
+	.dev = {
+		.platform_data = &samsung_spdif_pdata,
+		.dma_mask = &s5pv210_spdif_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-onenand.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-onenand.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-onenand.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-onenand.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,55 +0,0 @@
-/*
- * linux/arch/arm/mach-s5pv210/dev-onenand.c
- *
- *  Copyright (c) 2008-2010 Samsung Electronics
- *  Kyungmin Park <kyungmin.park@samsung.com>
- *
- * S5PC110 series device definition for OneNAND devices
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/onenand.h>
-
-#include <mach/irqs.h>
-#include <mach/map.h>
-
-static struct resource s5pc110_onenand_resources[] = {
-	[0] = {
-		.start	= S5PC110_PA_ONENAND,
-		.end	= S5PC110_PA_ONENAND + SZ_128K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[1] = {
-		.start	= S5PC110_PA_ONENAND_DMA,
-		.end	= S5PC110_PA_ONENAND_DMA + SZ_8K - 1,
-		.flags	= IORESOURCE_MEM,
-	},
-	[2] = {
-		.start	= IRQ_ONENAND_AUDI,
-		.end	= IRQ_ONENAND_AUDI,
-		.flags	= IORESOURCE_IRQ,
-	},
-};
-
-struct platform_device s5pc110_device_onenand = {
-	.name		= "s5pc110-onenand",
-	.id		= -1,
-	.num_resources	= ARRAY_SIZE(s5pc110_onenand_resources),
-	.resource	= s5pc110_onenand_resources,
-};
-
-void s5pc110_onenand_set_platdata(struct onenand_platform_data *pdata)
-{
-	struct onenand_platform_data *pd;
-
-	pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
-	if (!pd)
-		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
-	s5pc110_device_onenand.dev.platform_data = pd;
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-spi.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dev-spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dev-spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,23 +35,15 @@
  */
 static int s5pv210_spi_cfg_gpio(struct platform_device *pdev)
 {
+	unsigned int base;
+
 	switch (pdev->id) {
 	case 0:
-		s3c_gpio_cfgpin(S5PV210_GPB(0), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPB(1), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPB(2), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PV210_GPB(1), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PV210_GPB(2), S3C_GPIO_PULL_UP);
+		base = S5PV210_GPB(0);
 		break;
 
 	case 1:
-		s3c_gpio_cfgpin(S5PV210_GPB(4), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPB(5), S3C_GPIO_SFN(2));
-		s3c_gpio_cfgpin(S5PV210_GPB(6), S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(S5PV210_GPB(4), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PV210_GPB(5), S3C_GPIO_PULL_UP);
-		s3c_gpio_setpull(S5PV210_GPB(6), S3C_GPIO_PULL_UP);
+		base = S5PV210_GPB(4);
 		break;
 
 	default:
@@ -59,6 +51,9 @@
 		return -EINVAL;
 	}
 
+	s3c_gpio_cfgall_range(base, 3,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,7 +82,7 @@
 
 static struct platform_device s5pv210_device_pdma0 = {
 	.name		= "s3c-pl330",
-	.id		= 1,
+	.id		= 0,
 	.num_resources	= ARRAY_SIZE(s5pv210_pdma0_resource),
 	.resource	= s5pv210_pdma0_resource,
 	.dev		= {
@@ -144,7 +144,7 @@
 
 static struct platform_device s5pv210_device_pdma1 = {
 	.name		= "s3c-pl330",
-	.id		= 2,
+	.id		= 1,
 	.num_resources	= ARRAY_SIZE(s5pv210_pdma1_resource),
 	.resource	= s5pv210_pdma1_resource,
 	.dev		= {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/gpiolib.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/gpiolib.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/gpiolib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -150,6 +150,7 @@
 			.label	= "GPG3",
 		},
 	}, {
+		.config	= &gpio_cfg_noint,
 		.chip	= {
 			.base	= S5PV210_GPI(0),
 			.ngpio	= S5PV210_GPIO_I_NR,
@@ -223,34 +224,42 @@
 	}, {
 		.base	= (S5P_VA_GPIO + 0xC00),
 		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(0),
 		.chip	= {
 			.base	= S5PV210_GPH0(0),
 			.ngpio	= S5PV210_GPIO_H0_NR,
 			.label	= "GPH0",
+			.to_irq = samsung_gpiolib_to_irq,
 		},
 	}, {
 		.base	= (S5P_VA_GPIO + 0xC20),
 		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(8),
 		.chip	= {
 			.base	= S5PV210_GPH1(0),
 			.ngpio	= S5PV210_GPIO_H1_NR,
 			.label	= "GPH1",
+			.to_irq = samsung_gpiolib_to_irq,
 		},
 	}, {
 		.base	= (S5P_VA_GPIO + 0xC40),
 		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(16),
 		.chip	= {
 			.base	= S5PV210_GPH2(0),
 			.ngpio	= S5PV210_GPIO_H2_NR,
 			.label	= "GPH2",
+			.to_irq = samsung_gpiolib_to_irq,
 		},
 	}, {
 		.base	= (S5P_VA_GPIO + 0xC60),
 		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(24),
 		.chip	= {
 			.base	= S5PV210_GPH3(0),
 			.ngpio	= S5PV210_GPIO_H3_NR,
 			.label	= "GPH3",
+			.to_irq = samsung_gpiolib_to_irq,
 		},
 	},
 };
@@ -259,11 +268,14 @@
 {
 	struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
 	int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
+	int gpioint_group = 0;
 	int i = 0;
 
 	for (i = 0; i < nr_chips; i++, chip++) {
-		if (chip->config == NULL)
+		if (chip->config == NULL) {
 			chip->config = &gpio_cfg;
+			chip->group = gpioint_group++;
+		}
 		if (chip->base == NULL)
 			chip->base = S5PV210_BANK_BASE(i);
 	}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -21,13 +21,12 @@
 	 * aligned and add in the offset when we load the value here.
 	 */
 
-	.macro addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = S3C_VA_UART
+	.macro addruart, rp, rv
+		ldr	\rp, = S3C_PA_UART
+		ldr	\rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,8 +55,8 @@
 #define IRQ_SPI1		S5P_IRQ_VIC1(16)
 #define IRQ_SPI2		S5P_IRQ_VIC1(17)
 #define IRQ_IRDA		S5P_IRQ_VIC1(18)
-#define IRQ_CAN0		S5P_IRQ_VIC1(19)
-#define IRQ_CAN1		S5P_IRQ_VIC1(20)
+#define IRQ_IIC2		S5P_IRQ_VIC1(19)
+#define IRQ_IIC3		S5P_IRQ_VIC1(20)
 #define IRQ_HSIRX		S5P_IRQ_VIC1(21)
 #define IRQ_HSITX		S5P_IRQ_VIC1(22)
 #define IRQ_UHOST		S5P_IRQ_VIC1(23)
@@ -109,7 +109,7 @@
 
 #define IRQ_IPC			S5P_IRQ_VIC3(0)
 #define IRQ_HOSTIF		S5P_IRQ_VIC3(1)
-#define IRQ_MMC3		S5P_IRQ_VIC3(2)
+#define IRQ_HSMMC3		S5P_IRQ_VIC3(2)
 #define IRQ_CEC			S5P_IRQ_VIC3(3)
 #define IRQ_TSI			S5P_IRQ_VIC3(4)
 #define IRQ_MDNIE0		S5P_IRQ_VIC3(5)
@@ -121,8 +121,12 @@
 #define S5P_EINT_BASE1		(S5P_IRQ_VIC0(0))
 #define S5P_EINT_BASE2		(IRQ_VIC_END + 1)
 
+/* GPIO interrupt */
+#define S5P_GPIOINT_BASE	(IRQ_EINT(31) + 1)
+#define S5P_GPIOINT_GROUP_MAXNR	22
+
 /* Set the default NR_IRQS */
-#define NR_IRQS			(IRQ_EINT(31) + 1)
+#define NR_IRQS			(IRQ_EINT(31) + S5P_GPIOINT_COUNT + 1)
 
 /* Compatibility */
 #define IRQ_LCD_FIFO		IRQ_LCD0
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/map.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/map.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,10 @@
 #include <plat/map-s5p.h>
 
 #define S5PC110_PA_ONENAND	(0xB0000000)
+#define S5P_PA_ONENAND		S5PC110_PA_ONENAND
+
 #define S5PC110_PA_ONENAND_DMA	(0xB0600000)
+#define S5P_PA_ONENAND_DMA	S5PC110_PA_ONENAND_DMA
 
 #define S5PV210_PA_CHIPID	(0xE0000000)
 #define S5P_PA_CHIPID		S5PV210_PA_CHIPID
@@ -26,7 +29,6 @@
 #define S5P_PA_SYSCON		S5PV210_PA_SYSCON
 
 #define S5PV210_PA_GPIO		(0xE0200000)
-#define S5P_PA_GPIO		S5PV210_PA_GPIO
 
 /* SPI */
 #define S5PV210_PA_SPI0		0xE1300000
@@ -55,6 +57,8 @@
 
 #define S5P_SZ_UART		SZ_256
 
+#define S3C_VA_UARTx(x)		(S3C_VA_UART + ((x) * S3C_UART_OFFSET))
+
 #define S5PV210_PA_SROMC	(0xE8000000)
 
 #define S5PV210_PA_CFCON	(0xE8200000)
@@ -71,21 +75,20 @@
 
 #define S5PV210_PA_HSMMC(x)	(0xEB000000 + ((x) * 0x100000))
 
-#define S5PV210_PA_VIC0		(0xF2000000)
-#define S5P_PA_VIC0		S5PV210_PA_VIC0
+#define S5PV210_PA_HSOTG	(0xEC000000)
+#define S5PV210_PA_HSPHY	(0xEC100000)
 
+#define S5PV210_PA_VIC0		(0xF2000000)
 #define S5PV210_PA_VIC1		(0xF2100000)
-#define S5P_PA_VIC1		S5PV210_PA_VIC1
-
 #define S5PV210_PA_VIC2		(0xF2200000)
-#define S5P_PA_VIC2		S5PV210_PA_VIC2
-
 #define S5PV210_PA_VIC3		(0xF2300000)
-#define S5P_PA_VIC3		S5PV210_PA_VIC3
 
 #define S5PV210_PA_SDRAM	(0x20000000)
 #define S5P_PA_SDRAM		S5PV210_PA_SDRAM
 
+/* S/PDIF */
+#define S5PV210_PA_SPDIF	0xE1100000
+
 /* I2S */
 #define S5PV210_PA_IIS0		0xEEE30000
 #define S5PV210_PA_IIS1		0xE2100000
@@ -101,6 +104,9 @@
 
 #define S5PV210_PA_ADC		(0xE1700000)
 
+#define S5PV210_PA_DMC0		(0xF0000000)
+#define S5PV210_PA_DMC1		(0xF1400000)
+
 /* compatibiltiy defines. */
 #define S3C_PA_UART		S5PV210_PA_UART
 #define S3C_PA_HSMMC0		S5PV210_PA_HSMMC(0)
@@ -113,6 +119,7 @@
 #define S3C_PA_FB		S5PV210_PA_FB
 #define S3C_PA_RTC		S5PV210_PA_RTC
 #define S3C_PA_WDT		S5PV210_PA_WATCHDOG
+#define S3C_PA_USB_HSOTG	S5PV210_PA_HSOTG
 #define S5P_PA_FIMC0		S5PV210_PA_FIMC0
 #define S5P_PA_FIMC1		S5PV210_PA_FIMC1
 #define S5P_PA_FIMC2		S5PV210_PA_FIMC2
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/pm-core.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/pm-core.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/pm-core.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/pm-core.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,43 @@
+/* linux/arch/arm/mach-s5pv210/include/mach/pm-core.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h,
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S5PV210 - PM core support for arch/arm/plat-s5p/pm.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+	/* nothing here yet */
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+	__raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK);
+	__raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK);
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+	/* nothing here yet */
+}
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+	/* nothing here yet */
+}
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+					   struct pm_uart_save *save)
+{
+	/* nothing here yet */
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #define S5P_APLL_CON		S5P_CLKREG(0x100)
 #define S5P_MPLL_CON		S5P_CLKREG(0x108)
 #define S5P_EPLL_CON		S5P_CLKREG(0x110)
+#define S5P_EPLL_CON1		S5P_CLKREG(0x114)
 #define S5P_VPLL_CON		S5P_CLKREG(0x120)
 
 #define S5P_CLK_SRC0		S5P_CLKREG(0x200)
@@ -67,11 +68,28 @@
 #define S5P_CLKGATE_BUS1	S5P_CLKREG(0x488)
 #define S5P_CLK_OUT		S5P_CLKREG(0x500)
 
+/* DIV/MUX STATUS */
+#define S5P_CLKDIV_STAT0	S5P_CLKREG(0x1000)
+#define S5P_CLKDIV_STAT1	S5P_CLKREG(0x1004)
+#define S5P_CLKMUX_STAT0	S5P_CLKREG(0x1100)
+#define S5P_CLKMUX_STAT1	S5P_CLKREG(0x1104)
+
 /* CLKSRC0 */
-#define S5P_CLKSRC0_MUX200_MASK		(0x1<<16)
+#define S5P_CLKSRC0_MUX200_SHIFT	(16)
+#define S5P_CLKSRC0_MUX200_MASK		(0x1 << S5P_CLKSRC0_MUX200_SHIFT)
 #define S5P_CLKSRC0_MUX166_MASK		(0x1<<20)
 #define S5P_CLKSRC0_MUX133_MASK		(0x1<<24)
 
+/* CLKSRC2 */
+#define S5P_CLKSRC2_G3D_SHIFT           (0)
+#define S5P_CLKSRC2_G3D_MASK            (0x3 << S5P_CLKSRC2_G3D_SHIFT)
+#define S5P_CLKSRC2_MFC_SHIFT           (4)
+#define S5P_CLKSRC2_MFC_MASK            (0x3 << S5P_CLKSRC2_MFC_SHIFT)
+
+/* CLKSRC6*/
+#define S5P_CLKSRC6_ONEDRAM_SHIFT       (24)
+#define S5P_CLKSRC6_ONEDRAM_MASK        (0x3 << S5P_CLKSRC6_ONEDRAM_SHIFT)
+
 /* CLKDIV0 */
 #define S5P_CLKDIV0_APLL_SHIFT		(0)
 #define S5P_CLKDIV0_APLL_MASK		(0x7 << S5P_CLKDIV0_APLL_SHIFT)
@@ -90,12 +108,24 @@
 #define S5P_CLKDIV0_PCLK66_SHIFT	(28)
 #define S5P_CLKDIV0_PCLK66_MASK		(0x7 << S5P_CLKDIV0_PCLK66_SHIFT)
 
+/* CLKDIV2 */
+#define S5P_CLKDIV2_G3D_SHIFT           (0)
+#define S5P_CLKDIV2_G3D_MASK            (0xF << S5P_CLKDIV2_G3D_SHIFT)
+#define S5P_CLKDIV2_MFC_SHIFT           (4)
+#define S5P_CLKDIV2_MFC_MASK            (0xF << S5P_CLKDIV2_MFC_SHIFT)
+
+/* CLKDIV6 */
+#define S5P_CLKDIV6_ONEDRAM_SHIFT       (28)
+#define S5P_CLKDIV6_ONEDRAM_MASK        (0xF << S5P_CLKDIV6_ONEDRAM_SHIFT)
+
 #define S5P_SWRESET		S5P_CLKREG(0x2000)
 
+#define S5P_ARM_MCS_CON		S5P_CLKREG(0x6100)
+
 /* Registers related to power management */
 #define S5P_PWR_CFG		S5P_CLKREG(0xC000)
 #define S5P_EINT_WAKEUP_MASK	S5P_CLKREG(0xC004)
-#define S5P_WAKEUP_MASK 	S5P_CLKREG(0xC008)
+#define S5P_WAKEUP_MASK		S5P_CLKREG(0xC008)
 #define S5P_PWR_MODE		S5P_CLKREG(0xC00C)
 #define S5P_NORMAL_CFG		S5P_CLKREG(0xC010)
 #define S5P_IDLE_CFG		S5P_CLKREG(0xC020)
@@ -159,8 +189,11 @@
 #define S5P_SLEEP_CFG_USBOSC_EN		(1 << 1)
 
 /* OTHERS Resgister */
+#define S5P_OTHERS_RET_IO		(1 << 31)
+#define S5P_OTHERS_RET_CF		(1 << 30)
+#define S5P_OTHERS_RET_MMC		(1 << 29)
+#define S5P_OTHERS_RET_UART		(1 << 28)
 #define S5P_OTHERS_USB_SIG_MASK		(1 << 16)
-#define S5P_OTHERS_MIPI_DPHY_EN		(1 << 28)
 
 /* MIPI */
 #define S5P_MIPI_DPHY_EN		(3)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -31,13 +31,6 @@
 
 #define eint_irq_to_bit(irq)		(1 << (EINT_OFFSET(irq) & 0x7))
 
-/* values for S5P_EXTINT0 */
-#define S5P_EXTINT_LOWLEV		(0x00)
-#define S5P_EXTINT_HILEV		(0x01)
-#define S5P_EXTINT_FALLEDGE		(0x02)
-#define S5P_EXTINT_RISEEDGE		(0x03)
-#define S5P_EXTINT_BOTHEDGE		(0x04)
-
 #define EINT_MODE		S3C_GPIO_SFN(0xf)
 
 #define EINT_GPIO_0(x)		S5PV210_GPH0(x)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-sys.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-sys.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/regs-sys.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/regs-sys.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,19 @@
+/* arch/arm/mach-s5pv210/include/mach/regs-sys.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5PV210 - System registers definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#define S5PV210_USB_PHY_CON	(S3C_VA_SYS + 0xE80C)
+#define S5PV210_USB_PHY0_EN	(1 << 0)
+#define S5PV210_USB_PHY1_EN	(1 << 1)
+
+/* compatibility defines for s3c-hsotg driver */
+#define S3C64XX_OTHERS		S5PV210_USB_PHY_CON
+#define S3C64XX_OTHERS_USBMASK	S5PV210_USB_PHY0_EN
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H __FILE__
 
-#define VMALLOC_END	(0xE0000000UL)
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,9 @@
 
 config CPU_S5PV210
 	bool
-	select PLAT_S5P
 	select S3C_PL330_DMA
 	select S5P_EXT_INT
+	select S5PV210_PM if PM
 	help
 	  Enable S5PV210 CPU support
 
@@ -53,17 +53,11 @@
 	help
 	  Common setup code for SDHCI gpio.
 
-config S5PC110_DEV_ONENAND
-	bool
-	help
-	  Compile in platform device definition for OneNAND1 controller
-
 menu "S5PC110 Machines"
 
 config MACH_AQUILA
 	bool "Aquila"
 	select CPU_S5PV210
-	select ARCH_SPARSEMEM_ENABLE
 	select S3C_DEV_FB
 	select S5P_DEV_FIMC0
 	select S5P_DEV_FIMC1
@@ -71,7 +65,7 @@
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC1
 	select S3C_DEV_HSMMC2
-	select S5PC110_DEV_ONENAND
+	select S5P_DEV_ONENAND
 	select S5PV210_SETUP_FB_24BPP
 	select S5PV210_SETUP_SDHCI
 	help
@@ -80,7 +74,7 @@
 config MACH_GONI
 	bool "GONI"
 	select CPU_S5PV210
-	select ARCH_SPARSEMEM_ENABLE
+	select S5P_GPIO_INT
 	select S3C_DEV_FB
 	select S5P_DEV_FIMC0
 	select S5P_DEV_FIMC1
@@ -88,8 +82,15 @@
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC1
 	select S3C_DEV_HSMMC2
-	select S5PC110_DEV_ONENAND
+	select S3C_DEV_I2C1
+	select S3C_DEV_I2C2
+	select S3C_DEV_USB_HSOTG
+	select S5P_DEV_ONENAND
+	select SAMSUNG_DEV_KEYPAD
 	select S5PV210_SETUP_FB_24BPP
+	select S5PV210_SETUP_I2C1
+	select S5PV210_SETUP_I2C2
+	select S5PV210_SETUP_KEYPAD
 	select S5PV210_SETUP_SDHCI
 	help
 	  Machine support for Samsung GONI board
@@ -98,7 +99,6 @@
 config MACH_SMDKC110
 	bool "SMDKC110"
 	select CPU_S5PV210
-	select ARCH_SPARSEMEM_ENABLE
 	select S3C_DEV_I2C1
 	select S3C_DEV_I2C2
 	select S3C_DEV_RTC
@@ -118,7 +118,6 @@
 config MACH_SMDKV210
 	bool "SMDKV210"
 	select CPU_S5PV210
-	select ARCH_SPARSEMEM_ENABLE
 	select S3C_DEV_HSMMC
 	select S3C_DEV_HSMMC1
 	select S3C_DEV_HSMMC2
@@ -139,6 +138,29 @@
 	help
 	  Machine support for Samsung SMDKV210
 
+config MACH_TORBRECK
+	bool "Torbreck"
+	select CPU_S5PV210
+	select ARCH_SPARSEMEM_ENABLE
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC1
+	select S3C_DEV_HSMMC2
+	select S3C_DEV_HSMMC3
+	select S3C_DEV_I2C1
+	select S3C_DEV_I2C2
+	select S3C_DEV_RTC
+	select S3C_DEV_WDT
+	select S5PV210_SETUP_I2C1
+	select S5PV210_SETUP_I2C2
+	select S5PV210_SETUP_SDHCI
+	help
+	  Machine support for aESOP Torbreck
+
 endmenu
 
+config S5PV210_PM
+	bool
+	help
+	  Power Management code common to S5PV210
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-aquila.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-aquila.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-aquila.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-aquila.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,8 @@
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/mfd/max8998.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/regulator/fixed.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
@@ -376,9 +378,128 @@
 static struct max8998_platform_data aquila_max8998_pdata = {
 	.num_regulators	= ARRAY_SIZE(aquila_regulators),
 	.regulators	= aquila_regulators,
+	.buck1_set1	= S5PV210_GPH0(3),
+	.buck1_set2	= S5PV210_GPH0(4),
+	.buck2_set3	= S5PV210_GPH0(5),
+	.buck1_max_voltage1 = 1200000,
+	.buck1_max_voltage2 = 1200000,
+	.buck2_max_voltage = 1200000,
 };
 #endif
 
+static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = {
+	{
+		.dev_name	= "5-001a",
+		.supply		= "DBVDD",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "AVDD2",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "CPVDD",
+	},
+};
+
+static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = {
+	{
+		.dev_name	= "5-001a",
+		.supply		= "SPKVDD1",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "SPKVDD2",
+	},
+};
+
+static struct regulator_init_data wm8994_fixed_voltage0_init_data = {
+	.constraints = {
+		.always_on = 1,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(wm8994_fixed_voltage0_supplies),
+	.consumer_supplies	= wm8994_fixed_voltage0_supplies,
+};
+
+static struct regulator_init_data wm8994_fixed_voltage1_init_data = {
+	.constraints = {
+		.always_on = 1,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(wm8994_fixed_voltage1_supplies),
+	.consumer_supplies	= wm8994_fixed_voltage1_supplies,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage0_config = {
+	.supply_name	= "VCC_1.8V_PDA",
+	.microvolts	= 1800000,
+	.gpio		= -EINVAL,
+	.init_data	= &wm8994_fixed_voltage0_init_data,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage1_config = {
+	.supply_name	= "V_BAT",
+	.microvolts	= 3700000,
+	.gpio		= -EINVAL,
+	.init_data	= &wm8994_fixed_voltage1_init_data,
+};
+
+static struct platform_device wm8994_fixed_voltage0 = {
+	.name		= "reg-fixed-voltage",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &wm8994_fixed_voltage0_config,
+	},
+};
+
+static struct platform_device wm8994_fixed_voltage1 = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &wm8994_fixed_voltage1_config,
+	},
+};
+
+static struct regulator_consumer_supply wm8994_avdd1_supply = {
+	.dev_name	= "5-001a",
+	.supply		= "AVDD1",
+};
+
+static struct regulator_consumer_supply wm8994_dcvdd_supply = {
+	.dev_name	= "5-001a",
+	.supply		= "DCVDD",
+};
+
+static struct regulator_init_data wm8994_ldo1_data = {
+	.constraints	= {
+		.name		= "AVDD1_3.0V",
+		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &wm8994_avdd1_supply,
+};
+
+static struct regulator_init_data wm8994_ldo2_data = {
+	.constraints	= {
+		.name		= "DCVDD_1.0V",
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &wm8994_dcvdd_supply,
+};
+
+static struct wm8994_pdata wm8994_platform_data = {
+	/* configure gpio1 function: 0x0001(Logic level input/output) */
+	.gpio_defaults[0] = 0x0001,
+	/* configure gpio3/4/5/7 function for AIF2 voice */
+	.gpio_defaults[2] = 0x8100,
+	.gpio_defaults[3] = 0x8100,
+	.gpio_defaults[4] = 0x8100,
+	.gpio_defaults[6] = 0x0100,
+	/* configure gpio8/9/10/11 function for AIF3 BT */
+	.gpio_defaults[7] = 0x8100,
+	.gpio_defaults[8] = 0x0100,
+	.gpio_defaults[9] = 0x0100,
+	.gpio_defaults[10] = 0x0100,
+	.ldo[0]	= { S5PV210_MP03(6), NULL, &wm8994_ldo1_data },	/* XM0FRNB_2 */
+	.ldo[1]	= { 0, NULL, &wm8994_ldo2_data },
+};
+
 /* GPIO I2C PMIC */
 #define AP_I2C_GPIO_PMIC_BUS_4	4
 static struct i2c_gpio_platform_data aquila_i2c_gpio_pmic_data = {
@@ -404,6 +525,29 @@
 #endif
 };
 
+/* GPIO I2C AP 1.8V */
+#define AP_I2C_GPIO_BUS_5	5
+static struct i2c_gpio_platform_data aquila_i2c_gpio5_data = {
+	.sda_pin	= S5PV210_MP05(3),	/* XM0ADDR_11 */
+	.scl_pin	= S5PV210_MP05(2),	/* XM0ADDR_10 */
+};
+
+static struct platform_device aquila_i2c_gpio5 = {
+	.name		= "i2c-gpio",
+	.id		= AP_I2C_GPIO_BUS_5,
+	.dev		= {
+		.platform_data	= &aquila_i2c_gpio5_data,
+	},
+};
+
+static struct i2c_board_info i2c_gpio5_devs[] __initdata = {
+	{
+		/* CS/ADDR = low 0x34 (FYI: high = 0x36) */
+		I2C_BOARD_INFO("wm8994", 0x1a),
+		.platform_data	= &wm8994_platform_data,
+	},
+};
+
 /* PMIC Power button */
 static struct gpio_keys_button aquila_gpio_keys_table[] = {
 	{
@@ -475,17 +619,43 @@
 
 static struct platform_device *aquila_devices[] __initdata = {
 	&aquila_i2c_gpio_pmic,
+	&aquila_i2c_gpio5,
 	&aquila_device_gpiokeys,
 	&s3c_device_fb,
-	&s5pc110_device_onenand,
+	&s5p_device_onenand,
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc1,
 	&s3c_device_hsmmc2,
 	&s5p_device_fimc0,
 	&s5p_device_fimc1,
 	&s5p_device_fimc2,
+	&s5pv210_device_iis0,
+	&wm8994_fixed_voltage0,
+	&wm8994_fixed_voltage1,
 };
 
+static void __init aquila_sound_init(void)
+{
+	unsigned int gpio;
+
+	/* CODEC_XTAL_EN
+	 *
+	 * The Aquila board have a oscillator which provide main clock
+	 * to WM8994 codec. The oscillator provide 24MHz clock to WM8994
+	 * clock. Set gpio setting of "CODEC_XTAL_EN" to enable a oscillator.
+	 * */
+	gpio = S5PV210_GPH3(2);		/* XEINT_26 */
+	gpio_request(gpio, "CODEC_XTAL_EN");
+	s3c_gpio_cfgpin(gpio, S3C_GPIO_OUTPUT);
+	s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+
+	/* Ths main clock of WM8994 codec uses the output of CLKOUT pin.
+	 * The CLKOUT[9:8] set to 0x3(XUSBXTI) of 0xE010E000(OTHERS)
+	 * because it needs 24MHz clock to operate WM8994 codec.
+	 */
+	__raw_writel(__raw_readl(S5P_OTHERS) | (0x3 << 8), S5P_OTHERS);
+}
+
 static void __init aquila_map_io(void)
 {
 	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -506,6 +676,11 @@
 	s3c_fimc_setname(1, "s5p-fimc");
 	s3c_fimc_setname(2, "s5p-fimc");
 
+	/* SOUND */
+	aquila_sound_init();
+	i2c_register_board_info(AP_I2C_GPIO_BUS_5, i2c_gpio5_devs,
+			ARRAY_SIZE(i2c_gpio5_devs));
+
 	/* FB */
 	s3c_fb_set_platdata(&aquila_lcd_pdata);
 
@@ -516,8 +691,6 @@
 	/* Maintainers:
 	   Marek Szyprowski <m.szyprowski@samsung.com>
 	   Kyungmin Park <kyungmin.park@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv210_init_irq,
 	.map_io		= aquila_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-goni.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-goni.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-goni.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-goni.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,13 @@
 #include <linux/fb.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
+#include <linux/i2c/qt602240_ts.h>
 #include <linux/mfd/max8998.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/regulator/fixed.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/lcd.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
@@ -35,7 +41,10 @@
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/fb.h>
+#include <plat/iic.h>
+#include <plat/keypad.h>
 #include <plat/sdhci.h>
+#include <plat/clock.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define GONI_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
@@ -87,13 +96,12 @@
 /* Frame Buffer */
 static struct s3c_fb_pd_win goni_fb_win0 = {
 	.win_mode = {
-		.pixclock = 1000000000000ULL / ((16+16+2+480)*(28+3+2+800)*55),
 		.left_margin	= 16,
 		.right_margin	= 16,
-		.upper_margin	= 3,
+		.upper_margin	= 2,
 		.lower_margin	= 28,
 		.hsync_len	= 2,
-		.vsync_len	= 2,
+		.vsync_len	= 1,
 		.xres		= 480,
 		.yres		= 800,
 		.refresh	= 55,
@@ -111,9 +119,160 @@
 	.setup_gpio	= s5pv210_fb_gpio_setup_24bpp,
 };
 
+static int lcd_power_on(struct lcd_device *ld, int enable)
+{
+	return 1;
+}
+
+static int reset_lcd(struct lcd_device *ld)
+{
+	static unsigned int first = 1;
+	int reset_gpio = -1;
+
+	reset_gpio = S5PV210_MP05(5);
+
+	if (first) {
+		gpio_request(reset_gpio, "MLCD_RST");
+		first = 0;
+	}
+
+	gpio_direction_output(reset_gpio, 1);
+	return 1;
+}
+
+static struct lcd_platform_data goni_lcd_platform_data = {
+	.reset			= reset_lcd,
+	.power_on		= lcd_power_on,
+	.lcd_enabled		= 0,
+	.reset_delay		= 120,	/* 120ms */
+	.power_on_delay		= 25,	/* 25ms */
+	.power_off_delay	= 200,	/* 200ms */
+};
+
+#define LCD_BUS_NUM	3
+static struct spi_board_info spi_board_info[] __initdata = {
+	{
+		.modalias	= "s6e63m0",
+		.platform_data	= &goni_lcd_platform_data,
+		.max_speed_hz	= 1200000,
+		.bus_num	= LCD_BUS_NUM,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_3,
+		.controller_data = (void *)S5PV210_MP01(1), /* DISPLAY_CS */
+	},
+};
+
+static struct spi_gpio_platform_data lcd_spi_gpio_data = {
+	.sck	= S5PV210_MP04(1), /* DISPLAY_CLK */
+	.mosi	= S5PV210_MP04(3), /* DISPLAY_SI */
+	.miso	= SPI_GPIO_NO_MISO,
+	.num_chipselect	= 1,
+};
+
+static struct platform_device goni_spi_gpio = {
+	.name	= "spi_gpio",
+	.id	= LCD_BUS_NUM,
+	.dev	= {
+		.parent		= &s3c_device_fb.dev,
+		.platform_data	= &lcd_spi_gpio_data,
+	},
+};
+
+/* KEYPAD */
+static uint32_t keymap[] __initdata = {
+	/* KEY(row, col, keycode) */
+	KEY(0, 1, KEY_MENU),		/* Send */
+	KEY(0, 2, KEY_BACK),		/* End */
+	KEY(1, 1, KEY_CONFIG),		/* Half shot */
+	KEY(1, 2, KEY_VOLUMEUP),
+	KEY(2, 1, KEY_CAMERA),		/* Full shot */
+	KEY(2, 2, KEY_VOLUMEDOWN),
+};
+
+static struct matrix_keymap_data keymap_data __initdata = {
+	.keymap		= keymap,
+	.keymap_size	= ARRAY_SIZE(keymap),
+};
+
+static struct samsung_keypad_platdata keypad_data __initdata = {
+	.keymap_data	= &keymap_data,
+	.rows		= 3,
+	.cols		= 3,
+};
+
+/* Radio */
+static struct i2c_board_info i2c1_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("si470x", 0x10),
+	},
+};
+
+static void __init goni_radio_init(void)
+{
+	int gpio;
+
+	gpio = S5PV210_GPJ2(4);			/* XMSMDATA_4 */
+	gpio_request(gpio, "FM_INT");
+	s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
+	i2c1_devs[0].irq = gpio_to_irq(gpio);
+
+	gpio = S5PV210_GPJ2(5);			/* XMSMDATA_5 */
+	gpio_request(gpio, "FM_RST");
+	gpio_direction_output(gpio, 1);
+}
+
+/* TSP */
+static struct qt602240_platform_data qt602240_platform_data = {
+	.x_line		= 17,
+	.y_line		= 11,
+	.x_size		= 800,
+	.y_size		= 480,
+	.blen		= 0x21,
+	.threshold	= 0x28,
+	.voltage	= 2800000,              /* 2.8V */
+	.orient		= QT602240_DIAGONAL,
+};
+
+static struct s3c2410_platform_i2c i2c2_data __initdata = {
+	.flags		= 0,
+	.bus_num	= 2,
+	.slave_addr	= 0x10,
+	.frequency	= 400 * 1000,
+	.sda_delay	= 100,
+};
+
+static struct i2c_board_info i2c2_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("qt602240_ts", 0x4a),
+		.platform_data = &qt602240_platform_data,
+	},
+};
+
+static void __init goni_tsp_init(void)
+{
+	int gpio;
+
+	gpio = S5PV210_GPJ1(3);		/* XMSMADDR_11 */
+	gpio_request(gpio, "TSP_LDO_ON");
+	gpio_direction_output(gpio, 1);
+	gpio_export(gpio, 0);
+
+	gpio = S5PV210_GPJ0(5);		/* XMSMADDR_5 */
+	gpio_request(gpio, "TSP_INT");
+
+	s5p_register_gpio_interrupt(gpio);
+	s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0xf));
+	s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+	i2c2_devs[0].irq = gpio_to_irq(gpio);
+}
+
 /* MAX8998 regulators */
 #if defined(CONFIG_REGULATOR_MAX8998) || defined(CONFIG_REGULATOR_MAX8998_MODULE)
 
+static struct regulator_consumer_supply goni_ldo5_consumers[] = {
+	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+};
+
 static struct regulator_init_data goni_ldo2_data = {
 	.constraints	= {
 		.name		= "VALIVE_1.1V",
@@ -153,6 +312,8 @@
 		.max_uV		= 2800000,
 		.apply_uV	= 1,
 	},
+	.num_consumer_supplies = ARRAY_SIZE(goni_ldo5_consumers),
+	.consumer_supplies = goni_ldo5_consumers,
 };
 
 static struct regulator_init_data goni_ldo6_data = {
@@ -357,9 +518,128 @@
 static struct max8998_platform_data goni_max8998_pdata = {
 	.num_regulators	= ARRAY_SIZE(goni_regulators),
 	.regulators	= goni_regulators,
+	.buck1_set1	= S5PV210_GPH0(3),
+	.buck1_set2	= S5PV210_GPH0(4),
+	.buck2_set3	= S5PV210_GPH0(5),
+	.buck1_max_voltage1 = 1200000,
+	.buck1_max_voltage2 = 1200000,
+	.buck2_max_voltage = 1200000,
 };
 #endif
 
+static struct regulator_consumer_supply wm8994_fixed_voltage0_supplies[] = {
+	{
+		.dev_name	= "5-001a",
+		.supply		= "DBVDD",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "AVDD2",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "CPVDD",
+	},
+};
+
+static struct regulator_consumer_supply wm8994_fixed_voltage1_supplies[] = {
+	{
+		.dev_name	= "5-001a",
+		.supply		= "SPKVDD1",
+	}, {
+		.dev_name	= "5-001a",
+		.supply		= "SPKVDD2",
+	},
+};
+
+static struct regulator_init_data wm8994_fixed_voltage0_init_data = {
+	.constraints = {
+		.always_on = 1,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(wm8994_fixed_voltage0_supplies),
+	.consumer_supplies	= wm8994_fixed_voltage0_supplies,
+};
+
+static struct regulator_init_data wm8994_fixed_voltage1_init_data = {
+	.constraints = {
+		.always_on = 1,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(wm8994_fixed_voltage1_supplies),
+	.consumer_supplies	= wm8994_fixed_voltage1_supplies,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage0_config = {
+	.supply_name	= "VCC_1.8V_PDA",
+	.microvolts	= 1800000,
+	.gpio		= -EINVAL,
+	.init_data	= &wm8994_fixed_voltage0_init_data,
+};
+
+static struct fixed_voltage_config wm8994_fixed_voltage1_config = {
+	.supply_name	= "V_BAT",
+	.microvolts	= 3700000,
+	.gpio		= -EINVAL,
+	.init_data	= &wm8994_fixed_voltage1_init_data,
+};
+
+static struct platform_device wm8994_fixed_voltage0 = {
+	.name		= "reg-fixed-voltage",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &wm8994_fixed_voltage0_config,
+	},
+};
+
+static struct platform_device wm8994_fixed_voltage1 = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev		= {
+		.platform_data	= &wm8994_fixed_voltage1_config,
+	},
+};
+
+static struct regulator_consumer_supply wm8994_avdd1_supply = {
+	.dev_name	= "5-001a",
+	.supply		= "AVDD1",
+};
+
+static struct regulator_consumer_supply wm8994_dcvdd_supply = {
+	.dev_name	= "5-001a",
+	.supply		= "DCVDD",
+};
+
+static struct regulator_init_data wm8994_ldo1_data = {
+	.constraints	= {
+		.name		= "AVDD1_3.0V",
+		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &wm8994_avdd1_supply,
+};
+
+static struct regulator_init_data wm8994_ldo2_data = {
+	.constraints	= {
+		.name		= "DCVDD_1.0V",
+	},
+	.num_consumer_supplies	= 1,
+	.consumer_supplies	= &wm8994_dcvdd_supply,
+};
+
+static struct wm8994_pdata wm8994_platform_data = {
+	/* configure gpio1 function: 0x0001(Logic level input/output) */
+	.gpio_defaults[0] = 0x0001,
+	/* configure gpio3/4/5/7 function for AIF2 voice */
+	.gpio_defaults[2] = 0x8100,
+	.gpio_defaults[3] = 0x8100,
+	.gpio_defaults[4] = 0x8100,
+	.gpio_defaults[6] = 0x0100,
+	/* configure gpio8/9/10/11 function for AIF3 BT */
+	.gpio_defaults[7] = 0x8100,
+	.gpio_defaults[8] = 0x0100,
+	.gpio_defaults[9] = 0x0100,
+	.gpio_defaults[10] = 0x0100,
+	.ldo[0]	= { S5PV210_MP03(6), NULL, &wm8994_ldo1_data },	/* XM0FRNB_2 */
+	.ldo[1]	= { 0, NULL, &wm8994_ldo2_data },
+};
+
 /* GPIO I2C PMIC */
 #define AP_I2C_GPIO_PMIC_BUS_4	4
 static struct i2c_gpio_platform_data goni_i2c_gpio_pmic_data = {
@@ -385,6 +665,29 @@
 #endif
 };
 
+/* GPIO I2C AP 1.8V */
+#define AP_I2C_GPIO_BUS_5	5
+static struct i2c_gpio_platform_data goni_i2c_gpio5_data = {
+	.sda_pin	= S5PV210_MP05(3),	/* XM0ADDR_11 */
+	.scl_pin	= S5PV210_MP05(2),	/* XM0ADDR_10 */
+};
+
+static struct platform_device goni_i2c_gpio5 = {
+	.name		= "i2c-gpio",
+	.id		= AP_I2C_GPIO_BUS_5,
+	.dev		= {
+		.platform_data	= &goni_i2c_gpio5_data,
+	},
+};
+
+static struct i2c_board_info i2c_gpio5_devs[] __initdata = {
+	{
+		/* CS/ADDR = low 0x34 (FYI: high = 0x36) */
+		I2C_BOARD_INFO("wm8994", 0x1a),
+		.platform_data	= &wm8994_platform_data,
+	},
+};
+
 /* PMIC Power button */
 static struct gpio_keys_button goni_gpio_keys_table[] = {
 	{
@@ -444,11 +747,37 @@
 	.ext_cd_gpio_invert	= 1,
 };
 
+static struct regulator_consumer_supply mmc2_supplies[] = {
+	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"),
+};
+
+static struct regulator_init_data mmc2_fixed_voltage_init_data = {
+	.constraints		= {
+		.name		= "V_TF_2.8V",
+		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(mmc2_supplies),
+	.consumer_supplies	= mmc2_supplies,
+};
+
+static struct fixed_voltage_config mmc2_fixed_voltage_config = {
+	.supply_name		= "EXT_FLASH_EN",
+	.microvolts		= 2800000,
+	.gpio			= GONI_EXT_FLASH_EN,
+	.enable_high		= true,
+	.init_data		= &mmc2_fixed_voltage_init_data,
+};
+
+static struct platform_device mmc2_fixed_voltage = {
+	.name		= "reg-fixed-voltage",
+	.id		= 2,
+	.dev		= {
+		.platform_data	= &mmc2_fixed_voltage_config,
+	},
+};
+
 static void goni_setup_sdhci(void)
 {
-	gpio_request(GONI_EXT_FLASH_EN, "FLASH_EN");
-	gpio_direction_output(GONI_EXT_FLASH_EN, 1);
-
 	s3c_sdhci0_set_platdata(&goni_hsmmc0_data);
 	s3c_sdhci1_set_platdata(&goni_hsmmc1_data);
 	s3c_sdhci2_set_platdata(&goni_hsmmc2_data);
@@ -456,8 +785,11 @@
 
 static struct platform_device *goni_devices[] __initdata = {
 	&s3c_device_fb,
-	&s5pc110_device_onenand,
+	&s5p_device_onenand,
+	&goni_spi_gpio,
 	&goni_i2c_gpio_pmic,
+	&goni_i2c_gpio5,
+	&mmc2_fixed_voltage,
 	&goni_device_gpiokeys,
 	&s5p_device_fimc0,
 	&s5p_device_fimc1,
@@ -465,8 +797,24 @@
 	&s3c_device_hsmmc0,
 	&s3c_device_hsmmc1,
 	&s3c_device_hsmmc2,
+	&s5pv210_device_iis0,
+	&s3c_device_usb_hsotg,
+	&samsung_device_keypad,
+	&s3c_device_i2c1,
+	&s3c_device_i2c2,
+	&wm8994_fixed_voltage0,
+	&wm8994_fixed_voltage1,
 };
 
+static void __init goni_sound_init(void)
+{
+	/* Ths main clock of WM8994 codec uses the output of CLKOUT pin.
+	 * The CLKOUT[9:8] set to 0x3(XUSBXTI) of 0xE010E000(OTHERS)
+	 * because it needs 24MHz clock to operate WM8994 codec.
+	 */
+	__raw_writel(__raw_readl(S5P_OTHERS) | (0x3 << 8), S5P_OTHERS);
+}
+
 static void __init goni_map_io(void)
 {
 	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -476,6 +824,20 @@
 
 static void __init goni_machine_init(void)
 {
+	/* Radio: call before I2C 1 registeration */
+	goni_radio_init();
+
+	/* I2C1 */
+	s3c_i2c1_set_platdata(NULL);
+	i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+
+	/* TSP: call before I2C 2 registeration */
+	goni_tsp_init();
+
+	/* I2C2 */
+	s3c_i2c2_set_platdata(&i2c2_data);
+	i2c_register_board_info(2, i2c2_devs, ARRAY_SIZE(i2c2_devs));
+
 	/* PMIC */
 	goni_pmic_init();
 	i2c_register_board_info(AP_I2C_GPIO_PMIC_BUS_4, i2c_gpio_pmic_devs,
@@ -483,16 +845,27 @@
 	/* SDHCI */
 	goni_setup_sdhci();
 
+	/* SOUND */
+	goni_sound_init();
+	i2c_register_board_info(AP_I2C_GPIO_BUS_5, i2c_gpio5_devs,
+			ARRAY_SIZE(i2c_gpio5_devs));
+
 	/* FB */
 	s3c_fb_set_platdata(&goni_lcd_pdata);
 
+	/* SPI */
+	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+	/* KEYPAD */
+	samsung_keypad_set_platdata(&keypad_data);
+
+	clk_xusbxti.rate = 24000000;
+
 	platform_add_devices(goni_devices, ARRAY_SIZE(goni_devices));
 }
 
 MACHINE_START(GONI, "GONI")
 	/* Maintainers: Kyungmin Park <kyungmin.park@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv210_init_irq,
 	.map_io		= goni_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-smdkc110.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-smdkc110.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-smdkc110.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-smdkc110.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/serial_core.h>
 #include <linux/i2c.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -28,6 +29,7 @@
 #include <plat/cpu.h>
 #include <plat/ata.h>
 #include <plat/iic.h>
+#include <plat/pm.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define SMDKC110_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
@@ -81,6 +83,7 @@
 static struct platform_device *smdkc110_devices[] __initdata = {
 	&s5pv210_device_iis0,
 	&s5pv210_device_ac97,
+	&s5pv210_device_spdif,
 	&s3c_device_cfcon,
 	&s3c_device_i2c0,
 	&s3c_device_i2c1,
@@ -110,6 +113,8 @@
 
 static void __init smdkc110_machine_init(void)
 {
+	s3c_pm_init();
+
 	s3c_i2c0_set_platdata(NULL);
 	s3c_i2c1_set_platdata(NULL);
 	s3c_i2c2_set_platdata(NULL);
@@ -127,8 +132,6 @@
 
 MACHINE_START(SMDKC110, "SMDKC110")
 	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv210_init_irq,
 	.map_io		= smdkc110_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-smdkv210.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-smdkv210.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-smdkv210.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-smdkv210.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/serial_core.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -31,6 +32,7 @@
 #include <plat/ata.h>
 #include <plat/iic.h>
 #include <plat/keypad.h>
+#include <plat/pm.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define SMDKV210_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
@@ -103,6 +105,7 @@
 static struct platform_device *smdkv210_devices[] __initdata = {
 	&s5pv210_device_iis0,
 	&s5pv210_device_ac97,
+	&s5pv210_device_spdif,
 	&s3c_device_adc,
 	&s3c_device_cfcon,
 	&s3c_device_hsmmc0,
@@ -145,6 +148,8 @@
 
 static void __init smdkv210_machine_init(void)
 {
+	s3c_pm_init();
+
 	samsung_keypad_set_platdata(&smdkv210_keypad_data);
 	s3c24xx_ts_set_platdata(&s3c_ts_platform);
 
@@ -165,8 +170,6 @@
 
 MACHINE_START(SMDKV210, "SMDKV210")
 	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv210_init_irq,
 	.map_io		= smdkv210_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-torbreck.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-torbreck.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/mach-torbreck.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/mach-torbreck.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,131 @@
+/* linux/arch/arm/mach-s5pv210/mach-torbreck.c
+ *
+ * Copyright (c) 2010 aESOP Community
+ *		http://www.aesop.or.kr/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/regs-serial.h>
+#include <plat/s5pv210.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define TORBRECK_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
+				 S3C2410_UCON_RXILEVEL |	\
+				 S3C2410_UCON_TXIRQMODE |	\
+				 S3C2410_UCON_RXIRQMODE |	\
+				 S3C2410_UCON_RXFIFO_TOI |	\
+				 S3C2443_UCON_RXERR_IRQEN)
+
+#define TORBRECK_ULCON_DEFAULT	S3C2410_LCON_CS8
+
+#define TORBRECK_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
+				 S5PV210_UFCON_TXTRIG4 |	\
+				 S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg torbreck_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport		= 0,
+		.flags		= 0,
+		.ucon		= TORBRECK_UCON_DEFAULT,
+		.ulcon		= TORBRECK_ULCON_DEFAULT,
+		.ufcon		= TORBRECK_UFCON_DEFAULT,
+	},
+	[1] = {
+		.hwport		= 1,
+		.flags		= 0,
+		.ucon		= TORBRECK_UCON_DEFAULT,
+		.ulcon		= TORBRECK_ULCON_DEFAULT,
+		.ufcon		= TORBRECK_UFCON_DEFAULT,
+	},
+	[2] = {
+		.hwport		= 2,
+		.flags		= 0,
+		.ucon		= TORBRECK_UCON_DEFAULT,
+		.ulcon		= TORBRECK_ULCON_DEFAULT,
+		.ufcon		= TORBRECK_UFCON_DEFAULT,
+	},
+	[3] = {
+		.hwport		= 3,
+		.flags		= 0,
+		.ucon		= TORBRECK_UCON_DEFAULT,
+		.ulcon		= TORBRECK_ULCON_DEFAULT,
+		.ufcon		= TORBRECK_UFCON_DEFAULT,
+	},
+};
+
+static struct platform_device *torbreck_devices[] __initdata = {
+	&s5pv210_device_iis0,
+	&s3c_device_cfcon,
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc1,
+	&s3c_device_hsmmc2,
+	&s3c_device_hsmmc3,
+	&s3c_device_i2c0,
+	&s3c_device_i2c1,
+	&s3c_device_i2c2,
+	&s3c_device_rtc,
+	&s3c_device_wdt,
+};
+
+static struct i2c_board_info torbreck_i2c_devs0[] __initdata = {
+	/* To Be Updated */
+};
+
+static struct i2c_board_info torbreck_i2c_devs1[] __initdata = {
+	/* To Be Updated */
+};
+
+static struct i2c_board_info torbreck_i2c_devs2[] __initdata = {
+	/* To Be Updated */
+};
+
+static void __init torbreck_map_io(void)
+{
+	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+	s3c24xx_init_clocks(24000000);
+	s3c24xx_init_uarts(torbreck_uartcfgs, ARRAY_SIZE(torbreck_uartcfgs));
+}
+
+static void __init torbreck_machine_init(void)
+{
+	s3c_i2c0_set_platdata(NULL);
+	s3c_i2c1_set_platdata(NULL);
+	s3c_i2c2_set_platdata(NULL);
+	i2c_register_board_info(0, torbreck_i2c_devs0,
+			ARRAY_SIZE(torbreck_i2c_devs0));
+	i2c_register_board_info(1, torbreck_i2c_devs1,
+			ARRAY_SIZE(torbreck_i2c_devs1));
+	i2c_register_board_info(2, torbreck_i2c_devs2,
+			ARRAY_SIZE(torbreck_i2c_devs2));
+
+	platform_add_devices(torbreck_devices, ARRAY_SIZE(torbreck_devices));
+}
+
+MACHINE_START(TORBRECK, "TORBRECK")
+	/* Maintainer: Hyunchul Ko <ghcstop@gmail.com> */
+	.boot_params	= S5P_PA_SDRAM + 0x100,
+	.init_irq	= s5pv210_init_irq,
+	.map_io		= torbreck_map_io,
+	.init_machine	= torbreck_machine_init,
+	.timer		= &s3c24xx_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,8 @@
 
 obj-$(CONFIG_CPU_S5PV210)	+= cpu.o init.o clock.o dma.o gpiolib.o
 obj-$(CONFIG_CPU_S5PV210)	+= setup-i2c0.o
+obj-$(CONFIG_S5PV210_PM)	+= pm.o sleep.o
+obj-$(CONFIG_CPU_FREQ)		+= cpufreq.o
 
 # machine support
 
@@ -21,12 +23,12 @@
 obj-$(CONFIG_MACH_SMDKV210)	+= mach-smdkv210.o
 obj-$(CONFIG_MACH_SMDKC110)	+= mach-smdkc110.o
 obj-$(CONFIG_MACH_GONI)		+= mach-goni.o
+obj-$(CONFIG_MACH_TORBRECK)	+= mach-torbreck.o
 
 # device support
 
 obj-y				+= dev-audio.o
 obj-$(CONFIG_S3C64XX_DEV_SPI)	+= dev-spi.o
-obj-$(CONFIG_S5PC110_DEV_ONENAND) += dev-onenand.o
 
 obj-$(CONFIG_S5PV210_SETUP_FB_24BPP)	+= setup-fb-24bpp.o
 obj-$(CONFIG_S5PV210_SETUP_I2C1) 	+= setup-i2c1.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/pm.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/pm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,166 @@
+/* linux/arch/arm/mach-s5pv210/pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV210 - Power Management support
+ *
+ * Based on arch/arm/mach-s3c2410/pm.c
+ * Copyright (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/io.h>
+
+#include <plat/cpu.h>
+#include <plat/pm.h>
+#include <plat/regs-timer.h>
+
+#include <mach/regs-irq.h>
+#include <mach/regs-clock.h>
+
+static struct sleep_save s5pv210_core_save[] = {
+	/* Clock source */
+	SAVE_ITEM(S5P_CLK_SRC0),
+	SAVE_ITEM(S5P_CLK_SRC1),
+	SAVE_ITEM(S5P_CLK_SRC2),
+	SAVE_ITEM(S5P_CLK_SRC3),
+	SAVE_ITEM(S5P_CLK_SRC4),
+	SAVE_ITEM(S5P_CLK_SRC5),
+	SAVE_ITEM(S5P_CLK_SRC6),
+
+	/* Clock source Mask */
+	SAVE_ITEM(S5P_CLK_SRC_MASK0),
+	SAVE_ITEM(S5P_CLK_SRC_MASK1),
+
+	/* Clock Divider */
+	SAVE_ITEM(S5P_CLK_DIV0),
+	SAVE_ITEM(S5P_CLK_DIV1),
+	SAVE_ITEM(S5P_CLK_DIV2),
+	SAVE_ITEM(S5P_CLK_DIV3),
+	SAVE_ITEM(S5P_CLK_DIV4),
+	SAVE_ITEM(S5P_CLK_DIV5),
+	SAVE_ITEM(S5P_CLK_DIV6),
+	SAVE_ITEM(S5P_CLK_DIV7),
+
+	/* Clock Main Gate */
+	SAVE_ITEM(S5P_CLKGATE_MAIN0),
+	SAVE_ITEM(S5P_CLKGATE_MAIN1),
+	SAVE_ITEM(S5P_CLKGATE_MAIN2),
+
+	/* Clock source Peri Gate */
+	SAVE_ITEM(S5P_CLKGATE_PERI0),
+	SAVE_ITEM(S5P_CLKGATE_PERI1),
+
+	/* Clock source SCLK Gate */
+	SAVE_ITEM(S5P_CLKGATE_SCLK0),
+	SAVE_ITEM(S5P_CLKGATE_SCLK1),
+
+	/* Clock IP Clock gate */
+	SAVE_ITEM(S5P_CLKGATE_IP0),
+	SAVE_ITEM(S5P_CLKGATE_IP1),
+	SAVE_ITEM(S5P_CLKGATE_IP2),
+	SAVE_ITEM(S5P_CLKGATE_IP3),
+	SAVE_ITEM(S5P_CLKGATE_IP4),
+
+	/* Clock Blcok and Bus gate */
+	SAVE_ITEM(S5P_CLKGATE_BLOCK),
+	SAVE_ITEM(S5P_CLKGATE_BUS0),
+
+	/* Clock ETC */
+	SAVE_ITEM(S5P_CLK_OUT),
+	SAVE_ITEM(S5P_MDNIE_SEL),
+
+	/* PWM Register */
+	SAVE_ITEM(S3C2410_TCFG0),
+	SAVE_ITEM(S3C2410_TCFG1),
+	SAVE_ITEM(S3C64XX_TINT_CSTAT),
+	SAVE_ITEM(S3C2410_TCON),
+	SAVE_ITEM(S3C2410_TCNTB(0)),
+	SAVE_ITEM(S3C2410_TCMPB(0)),
+	SAVE_ITEM(S3C2410_TCNTO(0)),
+};
+
+void s5pv210_cpu_suspend(void)
+{
+	unsigned long tmp;
+
+	/* issue the standby signal into the pm unit. Note, we
+	 * issue a write-buffer drain just in case */
+
+	tmp = 0;
+
+	asm("b 1f\n\t"
+	    ".align 5\n\t"
+	    "1:\n\t"
+	    "mcr p15, 0, %0, c7, c10, 5\n\t"
+	    "mcr p15, 0, %0, c7, c10, 4\n\t"
+	    "wfi" : : "r" (tmp));
+
+	/* we should never get past here */
+	panic("sleep resumed to originator?");
+}
+
+static void s5pv210_pm_prepare(void)
+{
+	unsigned int tmp;
+
+	/* ensure at least INFORM0 has the resume address */
+	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0);
+
+	tmp = __raw_readl(S5P_SLEEP_CFG);
+	tmp &= ~(S5P_SLEEP_CFG_OSC_EN | S5P_SLEEP_CFG_USBOSC_EN);
+	__raw_writel(tmp, S5P_SLEEP_CFG);
+
+	/* WFI for SLEEP mode configuration by SYSCON */
+	tmp = __raw_readl(S5P_PWR_CFG);
+	tmp &= S5P_CFG_WFI_CLEAN;
+	tmp |= S5P_CFG_WFI_SLEEP;
+	__raw_writel(tmp, S5P_PWR_CFG);
+
+	/* SYSCON interrupt handling disable */
+	tmp = __raw_readl(S5P_OTHERS);
+	tmp |= S5P_OTHER_SYSC_INTOFF;
+	__raw_writel(tmp, S5P_OTHERS);
+
+	s3c_pm_do_save(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
+}
+
+static int s5pv210_pm_add(struct sys_device *sysdev)
+{
+	pm_cpu_prep = s5pv210_pm_prepare;
+	pm_cpu_sleep = s5pv210_cpu_suspend;
+
+	return 0;
+}
+
+static int s5pv210_pm_resume(struct sys_device *dev)
+{
+	u32 tmp;
+
+	tmp = __raw_readl(S5P_OTHERS);
+	tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF |\
+		S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART);
+	__raw_writel(tmp , S5P_OTHERS);
+
+	s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
+
+	return 0;
+}
+
+static struct sysdev_driver s5pv210_pm_driver = {
+	.add		= s5pv210_pm_add,
+	.resume		= s5pv210_pm_resume,
+};
+
+static __init int s5pv210_pm_drvinit(void)
+{
+	return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver);
+}
+arch_initcall(s5pv210_pm_drvinit);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-fb-24bpp.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-fb-24bpp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-fb-24bpp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-fb-24bpp.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,33 +21,21 @@
 #include <mach/regs-clock.h>
 #include <plat/gpio-cfg.h>
 
-void s5pv210_fb_gpio_setup_24bpp(void)
+static void s5pv210_fb_cfg_gpios(unsigned int base, unsigned int nr)
 {
-	unsigned int gpio = 0;
-
-	for (gpio = S5PV210_GPF0(0); gpio <= S5PV210_GPF0(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(2));
 
-	for (gpio = S5PV210_GPF1(0); gpio <= S5PV210_GPF1(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	for (; nr > 0; nr--, base++)
+		s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4);
+}
 
-	for (gpio = S5PV210_GPF2(0); gpio <= S5PV210_GPF2(7); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
 
-	for (gpio = S5PV210_GPF3(0); gpio <= S5PV210_GPF3(3); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+void s5pv210_fb_gpio_setup_24bpp(void)
+{
+	s5pv210_fb_cfg_gpios(S5PV210_GPF0(0), 8);
+	s5pv210_fb_cfg_gpios(S5PV210_GPF1(0), 8);
+	s5pv210_fb_cfg_gpios(S5PV210_GPF2(0), 8);
+	s5pv210_fb_cfg_gpios(S5PV210_GPF3(0), 4);
 
 	/* Set DISPLAY_CONTROL register for Display path selection.
 	 *
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c0.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c0.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,8 +23,6 @@
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV210_GPD1(0), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(0), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV210_GPD1(1), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(1), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV210_GPD1(0), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c1.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c1.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,8 +23,6 @@
 
 void s3c_i2c1_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV210_GPD1(2), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(2), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV210_GPD1(3), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(3), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV210_GPD1(2), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c2.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-i2c2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-i2c2.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,8 +23,6 @@
 
 void s3c_i2c2_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV210_GPD1(4), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(4), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV210_GPD1(5), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV210_GPD1(5), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV210_GPD1(4), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-ide.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-ide.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-ide.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-ide.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,36 +15,25 @@
 
 #include <plat/gpio-cfg.h>
 
-void s5pv210_ide_setup_gpio(void)
+static void s5pv210_ide_cfg_gpios(unsigned int base, unsigned int nr)
 {
-	unsigned int gpio = 0;
+	s3c_gpio_cfgrange_nopull(base, nr, S3C_GPIO_SFN(4));
 
-	for (gpio = S5PV210_GPJ0(0); gpio <= S5PV210_GPJ0(7); gpio++) {
-		/* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST,
-			CF_DMACK */
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	for (; nr > 0; nr--, base++)
+		s5p_gpio_set_drvstr(base, S5P_GPIO_DRVSTR_LV4);
+}
 
-	for (gpio = S5PV210_GPJ2(0); gpio <= S5PV210_GPJ2(7); gpio++) {
-		/*CF_Data[0 - 7] */
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+void s5pv210_ide_setup_gpio(void)
+{
+	/* CF_Add[0 - 2], CF_IORDY, CF_INTRQ, CF_DMARQ, CF_DMARST, CF_DMACK */
+	s5pv210_ide_cfg_gpios(S5PV210_GPJ0(0), 8);
 
-	for (gpio = S5PV210_GPJ3(0); gpio <= S5PV210_GPJ3(7); gpio++) {
-		/* CF_Data[8 - 15] */
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	/* CF_Data[0 - 7] */
+	s5pv210_ide_cfg_gpios(S5PV210_GPJ2(0), 8);
 
-	for (gpio = S5PV210_GPJ4(0); gpio <= S5PV210_GPJ4(3); gpio++) {
-		/* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
-	}
+	/* CF_Data[8 - 15] */
+	s5pv210_ide_cfg_gpios(S5PV210_GPJ3(0), 8);
+
+	/* CF_CS0, CF_CS1, CF_IORD, CF_IOWR */
+	s5pv210_ide_cfg_gpios(S5PV210_GPJ4(0), 4);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-keypad.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-keypad.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-keypad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-keypad.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,19 +16,9 @@
 
 void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols)
 {
-	unsigned int gpio, end;
-
 	/* Set all the necessary GPH3 pins to special-function 3: KP_ROW[x] */
-	end = S5PV210_GPH3(rows);
-	for (gpio = S5PV210_GPH3(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPH3(0), rows, S3C_GPIO_SFN(3));
 
 	/* Set all the necessary GPH2 pins to special-function 3: KP_COL[x] */
-	end = S5PV210_GPH2(cols);
-	for (gpio = S5PV210_GPH2(0); gpio < end; gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPH2(0), cols, S3C_GPIO_SFN(3));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-sdhci-gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-sdhci-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/setup-sdhci-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/setup-sdhci-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,26 +26,17 @@
 void s5pv210_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
 
 	/* Set all the necessary GPG0/GPG1 pins to special-function 2 */
-	for (gpio = S5PV210_GPG0(0); gpio < S5PV210_GPG0(2); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG0(0), 2, S3C_GPIO_SFN(2));
+
 	switch (width) {
 	case 8:
 		/* GPG1[3:6] special-funtion 3 */
-		for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) {
-			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		}
+		s3c_gpio_cfgrange_nopull(S5PV210_GPG1(3), 4, S3C_GPIO_SFN(3));
 	case 4:
 		/* GPG0[3:6] special-funtion 2 */
-		for (gpio = S5PV210_GPG0(3); gpio <= S5PV210_GPG0(6); gpio++) {
-			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		}
+		s3c_gpio_cfgrange_nopull(S5PV210_GPG0(3), 4, S3C_GPIO_SFN(2));
 	default:
 		break;
 	}
@@ -59,19 +50,12 @@
 void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
 
 	/* Set all the necessary GPG1[0:1] pins to special-function 2 */
-	for (gpio = S5PV210_GPG1(0); gpio < S5PV210_GPG1(2); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG1(0), 2, S3C_GPIO_SFN(2));
 
 	/* Data pin GPG1[3:6] to special-function 2 */
-	for (gpio = S5PV210_GPG1(3); gpio <= S5PV210_GPG1(6); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG1(3), 4, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S5PV210_GPG1(2), S3C_GPIO_PULL_UP);
@@ -82,27 +66,17 @@
 void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
 
 	/* Set all the necessary GPG2[0:1] pins to special-function 2 */
-	for (gpio = S5PV210_GPG2(0); gpio < S5PV210_GPG2(2); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG2(0), 2, S3C_GPIO_SFN(2));
 
 	switch (width) {
 	case 8:
 		/* Data pin GPG3[3:6] to special-function 3 */
-		for (gpio = S5PV210_GPG3(3); gpio <= S5PV210_GPG3(6); gpio++) {
-			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
-			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		}
+		s3c_gpio_cfgrange_nopull(S5PV210_GPG3(3), 4, S3C_GPIO_SFN(3));
 	case 4:
 		/* Data pin GPG2[3:6] to special-function 2 */
-		for (gpio = S5PV210_GPG2(3); gpio <= S5PV210_GPG2(6); gpio++) {
-			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-		}
+		s3c_gpio_cfgrange_nopull(S5PV210_GPG2(3), 4, S3C_GPIO_SFN(2));
 	default:
 		break;
 	}
@@ -116,19 +90,12 @@
 void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
 {
 	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
-	unsigned int gpio;
 
-	/* Set all the necessary GPG3[0:2] pins to special-function 2 */
-	for (gpio = S5PV210_GPG3(0); gpio < S5PV210_GPG3(2); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	/* Set all the necessary GPG3[0:1] pins to special-function 2 */
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG3(0), 2, S3C_GPIO_SFN(2));
 
 	/* Data pin GPG3[3:6] to special-function 2 */
-	for (gpio = S5PV210_GPG3(3); gpio <= S5PV210_GPG3(6); gpio++) {
-		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
-		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
-	}
+	s3c_gpio_cfgrange_nopull(S5PV210_GPG3(3), 4, S3C_GPIO_SFN(2));
 
 	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
 		s3c_gpio_setpull(S5PV210_GPG3(2), S3C_GPIO_PULL_UP);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/sleep.S linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/sleep.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv210/sleep.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv210/sleep.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,170 @@
+/* linux/arch/arm/plat-s5p/sleep.S
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV210 power Manager (Suspend-To-RAM) support
+ * Based on S3C2410 sleep code by:
+ * 	Ben Dooks, (c) 2004 Simtec Electronics
+ *
+ * Based on PXA/SA1100 sleep code by:
+ *	Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ *	Cliff Brake, (c) 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+
+	.text
+
+	/* s3c_cpu_save
+	 *
+	 * entry:
+	 *	r0 = save address (virtual addr of s3c_sleep_save_phys)
+	*/
+
+ENTRY(s3c_cpu_save)
+
+	stmfd	sp!, { r3 - r12, lr }
+
+	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
+	mrc	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
+	mrc	p15, 0, r8, c2, c0, 2	@ Translation Table Control
+	mrc	p15, 0, r9, c1, c0, 0	@ Control register
+	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
+	mrc	p15, 0, r12, c10, c2, 0	@ Read PRRR
+	mrc	p15, 0, r3, c10, c2, 1	@ READ NMRR
+
+	stmia	r0, { r3 - r13 }
+
+	bl	s3c_pm_cb_flushcache
+
+	ldr	r0, =pm_cpu_sleep
+	ldr	r0, [ r0 ]
+	mov	pc, r0
+
+resume_with_mmu:
+	/*
+	 * After MMU is turned on, restore the previous MMU table.
+	 */
+	ldr	r9 , =(PAGE_OFFSET - PHYS_OFFSET)
+	add	r4, r4, r9
+	str	r12, [r4]
+
+	ldmfd	sp!, { r3 - r12, pc }
+
+	.ltorg
+
+	.data
+
+	.global	s3c_sleep_save_phys
+s3c_sleep_save_phys:
+	.word	0
+
+	/* sleep magic, to allow the bootloader to check for an valid
+	 * image to resume to. Must be the first word before the
+	 * s3c_cpu_resume entry.
+	*/
+
+	.word	0x2bedf00d
+
+	/* s3c_cpu_resume
+	 *
+	 * resume code entry for bootloader to call
+	 *
+	 * we must put this code here in the data segment as we have no
+	 * other way of restoring the stack pointer after sleep, and we
+	 * must not write to the code segment (code is read-only)
+	*/
+
+ENTRY(s3c_cpu_resume)
+	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+	msr	cpsr_c, r0
+
+	mov	r1, #0
+	mcr	p15, 0, r1, c8, c7, 0		@ invalidate TLBs
+	mcr	p15, 0, r1, c7, c5, 0		@ invalidate I Cache
+
+	ldr	r0, s3c_sleep_save_phys		@ address of restore block
+	ldmia	r0, { r3 - r13 }
+
+	mcr	p15, 0, r4, c13, c0, 0		@ FCSE/PID
+	mcr	p15, 0, r5, c3, c0, 0		@ Domain ID
+
+	mcr	p15, 0, r8, c2, c0, 2		@ Translation Table Control
+	mcr	p15, 0, r7, c2, c0, 1		@ Translation Table BASE1
+	mcr	p15, 0, r6, c2, c0, 0		@ Translation Table BASE0
+
+	mcr	p15, 0, r10, c1, c0, 1		@ Auxiliary control register
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c8, c7, 0		@ Invalidate I & D TLB
+
+	mov	r0, #0				@ restore copro access
+	mcr	p15, 0, r11, c1, c0, 2		@ Co-processor access
+	mcr 	p15, 0, r0, c7, c5, 4
+
+	mcr	p15, 0, r12, c10, c2, 0		@ write PRRR
+	mcr	p15, 0, r3, c10, c2, 1		@ write NMRR
+
+	/*
+	 * In Cortex-A8, when MMU is turned on, the pipeline is flushed.
+	 * And there are no valid entries in the MMU table at this point.
+	 * So before turning on the MMU, the MMU entry for the DRAM address
+	 * range is added. After the MMU is turned on, the other entries
+	 * in the MMU table will be restored.
+	*/
+
+	/* r6 = Translation Table BASE0 */
+	mov	r4, r6
+	mov	r4, r4, LSR #14
+	mov	r4, r4, LSL #14
+
+	/* Load address for adding to MMU table list */
+	ldr	r11, =0xE010F000		@ INFORM0 reg.
+	ldr	r10, [r11, #0]
+	mov	r10, r10, LSR #18
+	bic	r10, r10, #0x3
+	orr	r4, r4, r10
+
+	/* Calculate MMU table entry */
+	mov 	r10, r10, LSL #18
+	ldr	r5, =0x40E
+	orr	r10, r10, r5
+
+	/* Back up originally data */
+	ldr	r12, [r4]
+
+	/* Add calculated MMU table entry into MMU table list */
+	str	r10, [r4]
+
+	ldr	r2, =resume_with_mmu
+	mcr	p15, 0, r9, c1, c0, 0		@ turn on MMU, etc
+
+	nop
+	nop
+	nop
+	nop
+	nop					@ second-to-last before mmu
+
+	mov	pc, r2				@ go back to virtual address
+
+	.ltorg
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,16 +30,92 @@
 	.rate		= 27000000,
 };
 
+static struct clk clk_sclk_hdmiphy = {
+	.name		= "sclk_hdmiphy",
+	.id		= -1,
+};
+
+static struct clk clk_sclk_usbphy0 = {
+	.name		= "sclk_usbphy0",
+	.id		= -1,
+	.rate		= 27000000,
+};
+
+static struct clk clk_sclk_usbphy1 = {
+	.name		= "sclk_usbphy1",
+	.id		= -1,
+};
+
+static int s5pv310_clksrc_mask_top_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
+}
+
+static int s5pv310_clksrc_mask_cam_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_CAM, clk, enable);
+}
+
+static int s5pv310_clksrc_mask_lcd0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_LCD0, clk, enable);
+}
+
+static int s5pv310_clksrc_mask_lcd1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_LCD1, clk, enable);
+}
+
+static int s5pv310_clksrc_mask_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_FSYS, clk, enable);
+}
+
 static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable);
 }
 
+static int s5pv310_clksrc_mask_peril1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL1, clk, enable);
+}
+
+static int s5pv310_clk_ip_cam_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_CAM, clk, enable);
+}
+
+static int s5pv310_clk_ip_image_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_IMAGE, clk, enable);
+}
+
+static int s5pv310_clk_ip_lcd0_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_LCD0, clk, enable);
+}
+
+static int s5pv310_clk_ip_lcd1_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_LCD1, clk, enable);
+}
+
+static int s5pv310_clk_ip_fsys_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_FSYS, clk, enable);
+}
+
 static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
 }
 
+static int s5pv310_clk_ip_perir_ctrl(struct clk *clk, int enable)
+{
+	return s5p_gatectrl(S5P_CLKGATE_IP_PERIR, clk, enable);
+}
+
 /* Core list of CMU_CPU side */
 
 static struct clksrc_clk clk_mout_apll = {
@@ -79,7 +155,7 @@
 };
 
 static struct clk *clkset_moutcore_list[] = {
-	[0] = &clk_sclk_apll.clk,
+	[0] = &clk_mout_apll.clk,
 	[1] = &clk_mout_mpll.clk,
 };
 
@@ -150,24 +226,6 @@
 	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 },
 };
 
-static struct clksrc_clk clk_atclk = {
-	.clk	= {
-		.name		= "atclk",
-		.id		= -1,
-		.parent		= &clk_moutcore.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 16, .size = 3 },
-};
-
-static struct clksrc_clk clk_pclk_dbg = {
-	.clk	= {
-		.name		= "pclk_dbg",
-		.id		= -1,
-		.parent		= &clk_atclk.clk,
-	},
-	.reg_div	= { .reg = S5P_CLKDIV_CPU, .shift = 20, .size = 3 },
-};
-
 /* Core list of CMU_CORE side */
 
 static struct clk *clkset_corebus_list[] = {
@@ -241,7 +299,7 @@
 	[1] = &clk_sclk_apll.clk,
 };
 
-static struct clksrc_sources clkset_aclk_200 = {
+static struct clksrc_sources clkset_aclk = {
 	.sources	= clkset_aclk_top_list,
 	.nr_sources	= ARRAY_SIZE(clkset_aclk_top_list),
 };
@@ -251,52 +309,37 @@
 		.name		= "aclk_200",
 		.id		= -1,
 	},
-	.sources	= &clkset_aclk_200,
+	.sources	= &clkset_aclk,
 	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 },
 	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 },
 };
 
-static struct clksrc_sources clkset_aclk_100 = {
-	.sources	= clkset_aclk_top_list,
-	.nr_sources	= ARRAY_SIZE(clkset_aclk_top_list),
-};
-
 static struct clksrc_clk clk_aclk_100 = {
 	.clk	= {
 		.name		= "aclk_100",
 		.id		= -1,
 	},
-	.sources	= &clkset_aclk_100,
+	.sources	= &clkset_aclk,
 	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 },
 	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 },
 };
 
-static struct clksrc_sources clkset_aclk_160 = {
-	.sources	= clkset_aclk_top_list,
-	.nr_sources	= ARRAY_SIZE(clkset_aclk_top_list),
-};
-
 static struct clksrc_clk clk_aclk_160 = {
 	.clk	= {
 		.name		= "aclk_160",
 		.id		= -1,
 	},
-	.sources	= &clkset_aclk_160,
+	.sources	= &clkset_aclk,
 	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 },
 	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 },
 };
 
-static struct clksrc_sources clkset_aclk_133 = {
-	.sources	= clkset_aclk_top_list,
-	.nr_sources	= ARRAY_SIZE(clkset_aclk_top_list),
-};
-
 static struct clksrc_clk clk_aclk_133 = {
 	.clk	= {
 		.name		= "aclk_133",
 		.id		= -1,
 	},
-	.sources	= &clkset_aclk_133,
+	.sources	= &clkset_aclk,
 	.reg_src	= { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 },
 	.reg_div	= { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 },
 };
@@ -315,6 +358,8 @@
 	.clk	= {
 		.name		= "vpll_src",
 		.id		= -1,
+		.enable		= s5pv310_clksrc_mask_top_ctrl,
+		.ctrlbit	= (1 << 0),
 	},
 	.sources	= &clkset_vpllsrc,
 	.reg_src	= { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 },
@@ -346,7 +391,175 @@
 		.parent		= &clk_aclk_100.clk,
 		.enable		= s5pv310_clk_ip_peril_ctrl,
 		.ctrlbit	= (1<<24),
-	}
+	}, {
+		.name		= "csis",
+		.id		= 0,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 4),
+	}, {
+		.name		= "csis",
+		.id		= 1,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "fimc",
+		.id		= 0,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "fimc",
+		.id		= 1,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 1),
+	}, {
+		.name		= "fimc",
+		.id		= 2,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 2),
+	}, {
+		.name		= "fimc",
+		.id		= 3,
+		.enable		= s5pv310_clk_ip_cam_ctrl,
+		.ctrlbit	= (1 << 3),
+	}, {
+		.name		= "fimd",
+		.id		= 0,
+		.enable		= s5pv310_clk_ip_lcd0_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "fimd",
+		.id		= 1,
+		.enable		= s5pv310_clk_ip_lcd1_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "hsmmc",
+		.id		= 0,
+		.parent		= &clk_aclk_133.clk,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 5),
+	}, {
+		.name		= "hsmmc",
+		.id		= 1,
+		.parent		= &clk_aclk_133.clk,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "hsmmc",
+		.id		= 2,
+		.parent		= &clk_aclk_133.clk,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "hsmmc",
+		.id		= 3,
+		.parent		= &clk_aclk_133.clk,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "hsmmc",
+		.id		= 4,
+		.parent		= &clk_aclk_133.clk,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "sata",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 10),
+	}, {
+		.name		= "adc",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "rtc",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_perir_ctrl,
+		.ctrlbit	= (1 << 15),
+	}, {
+		.name		= "watchdog",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_perir_ctrl,
+		.ctrlbit	= (1 << 14),
+	}, {
+		.name		= "usbhost",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_fsys_ctrl ,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "otg",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_fsys_ctrl,
+		.ctrlbit	= (1 << 13),
+	}, {
+		.name		= "spi",
+		.id		= 0,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 16),
+	}, {
+		.name		= "spi",
+		.id		= 1,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 17),
+	}, {
+		.name		= "spi",
+		.id		= 2,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 18),
+	}, {
+		.name		= "fimg2d",
+		.id		= -1,
+		.enable		= s5pv310_clk_ip_image_ctrl,
+		.ctrlbit	= (1 << 0),
+	}, {
+		.name		= "i2c",
+		.id		= 0,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 6),
+	}, {
+		.name		= "i2c",
+		.id		= 1,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 7),
+	}, {
+		.name		= "i2c",
+		.id		= 2,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 8),
+	}, {
+		.name		= "i2c",
+		.id		= 3,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 9),
+	}, {
+		.name		= "i2c",
+		.id		= 4,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 10),
+	}, {
+		.name		= "i2c",
+		.id		= 5,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 11),
+	}, {
+		.name		= "i2c",
+		.id		= 6,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 12),
+	}, {
+		.name		= "i2c",
+		.id		= 7,
+		.parent		= &clk_aclk_100.clk,
+		.enable		= s5pv310_clk_ip_peril_ctrl,
+		.ctrlbit	= (1 << 13),
+	},
 };
 
 static struct clk init_clocks[] = {
@@ -387,6 +600,9 @@
 	[0] = &clk_ext_xtal_mux,
 	[1] = &clk_xusbxti,
 	[2] = &clk_sclk_hdmi27m,
+	[3] = &clk_sclk_usbphy0,
+	[4] = &clk_sclk_usbphy1,
+	[5] = &clk_sclk_hdmiphy,
 	[6] = &clk_mout_mpll.clk,
 	[7] = &clk_mout_epll.clk,
 	[8] = &clk_sclk_vpll.clk,
@@ -397,6 +613,104 @@
 	.nr_sources	= ARRAY_SIZE(clkset_group_list),
 };
 
+static struct clk *clkset_mout_g2d0_list[] = {
+	[0] = &clk_mout_mpll.clk,
+	[1] = &clk_sclk_apll.clk,
+};
+
+static struct clksrc_sources clkset_mout_g2d0 = {
+	.sources	= clkset_mout_g2d0_list,
+	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d0_list),
+};
+
+static struct clksrc_clk clk_mout_g2d0 = {
+	.clk	= {
+		.name		= "mout_g2d0",
+		.id		= -1,
+	},
+	.sources	= &clkset_mout_g2d0,
+	.reg_src	= { .reg = S5P_CLKSRC_IMAGE, .shift = 0, .size = 1 },
+};
+
+static struct clk *clkset_mout_g2d1_list[] = {
+	[0] = &clk_mout_epll.clk,
+	[1] = &clk_sclk_vpll.clk,
+};
+
+static struct clksrc_sources clkset_mout_g2d1 = {
+	.sources	= clkset_mout_g2d1_list,
+	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d1_list),
+};
+
+static struct clksrc_clk clk_mout_g2d1 = {
+	.clk	= {
+		.name		= "mout_g2d1",
+		.id		= -1,
+	},
+	.sources	= &clkset_mout_g2d1,
+	.reg_src	= { .reg = S5P_CLKSRC_IMAGE, .shift = 4, .size = 1 },
+};
+
+static struct clk *clkset_mout_g2d_list[] = {
+	[0] = &clk_mout_g2d0.clk,
+	[1] = &clk_mout_g2d1.clk,
+};
+
+static struct clksrc_sources clkset_mout_g2d = {
+	.sources	= clkset_mout_g2d_list,
+	.nr_sources	= ARRAY_SIZE(clkset_mout_g2d_list),
+};
+
+static struct clksrc_clk clk_dout_mmc0 = {
+	.clk		= {
+		.name		= "dout_mmc0",
+		.id		= -1,
+	},
+	.sources = &clkset_group,
+	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 0, .size = 4 },
+	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk clk_dout_mmc1 = {
+	.clk		= {
+		.name		= "dout_mmc1",
+		.id		= -1,
+	},
+	.sources = &clkset_group,
+	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 4, .size = 4 },
+	.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk clk_dout_mmc2 = {
+	.clk		= {
+		.name		= "dout_mmc2",
+		.id		= -1,
+	},
+	.sources = &clkset_group,
+	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 8, .size = 4 },
+	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 0, .size = 4 },
+};
+
+static struct clksrc_clk clk_dout_mmc3 = {
+	.clk		= {
+		.name		= "dout_mmc3",
+		.id		= -1,
+	},
+	.sources = &clkset_group,
+	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 12, .size = 4 },
+	.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk clk_dout_mmc4 = {
+	.clk		= {
+		.name		= "dout_mmc4",
+		.id		= -1,
+	},
+	.sources = &clkset_group,
+	.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 16, .size = 4 },
+	.reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 0, .size = 4 },
+};
+
 static struct clksrc_clk clksrcs[] = {
 	{
 		.clk	= {
@@ -448,7 +762,200 @@
 		.sources = &clkset_group,
 		.reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 },
 		.reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 },
-	},
+	}, {
+		.clk		= {
+			.name		= "sclk_csis",
+			.id		= 0,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 24, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 24, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_csis",
+			.id		= 1,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 28),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 28, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_cam",
+			.id		= 0,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 16, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_cam",
+			.id		= 1,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 20),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 20, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 20, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimc",
+			.id		= 0,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 0, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimc",
+			.id		= 1,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 4),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 4, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 4, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimc",
+			.id		= 2,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 8),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 8, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 8, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimc",
+			.id		= 3,
+			.enable		= s5pv310_clksrc_mask_cam_ctrl,
+			.ctrlbit	= (1 << 12),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_CAM, .shift = 12, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 12, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimd",
+			.id		= 0,
+			.enable		= s5pv310_clksrc_mask_lcd0_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_LCD0, .shift = 0, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_LCD0, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimd",
+			.id		= 1,
+			.enable		= s5pv310_clksrc_mask_lcd1_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_LCD1, .shift = 0, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_LCD1, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_sata",
+			.id		= -1,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &clkset_mout_corebus,
+		.reg_src = { .reg = S5P_CLKSRC_FSYS, .shift = 24, .size = 1 },
+		.reg_div = { .reg = S5P_CLKDIV_FSYS0, .shift = 20, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_spi",
+			.id		= 0,
+			.enable		= s5pv310_clksrc_mask_peril1_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 16, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_spi",
+			.id		= 1,
+			.enable		= s5pv310_clksrc_mask_peril1_ctrl,
+			.ctrlbit	= (1 << 20),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 20, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_PERIL1, .shift = 16, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_spi",
+			.id		= 2,
+			.enable		= s5pv310_clksrc_mask_peril1_ctrl,
+			.ctrlbit	= (1 << 24),
+		},
+		.sources = &clkset_group,
+		.reg_src = { .reg = S5P_CLKSRC_PERIL1, .shift = 24, .size = 4 },
+		.reg_div = { .reg = S5P_CLKDIV_PERIL2, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_fimg2d",
+			.id		= -1,
+		},
+		.sources = &clkset_mout_g2d,
+		.reg_src = { .reg = S5P_CLKSRC_IMAGE, .shift = 8, .size = 1 },
+		.reg_div = { .reg = S5P_CLKDIV_IMAGE, .shift = 0, .size = 4 },
+	}, {
+		.clk		= {
+			.name		= "sclk_mmc",
+			.id		= 0,
+			.parent		= &clk_dout_mmc0.clk,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 0),
+		},
+		.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 8, .size = 8 },
+	}, {
+		.clk		= {
+			.name		= "sclk_mmc",
+			.id		= 1,
+			.parent         = &clk_dout_mmc1.clk,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 4),
+		},
+		.reg_div = { .reg = S5P_CLKDIV_FSYS1, .shift = 24, .size = 8 },
+	}, {
+		.clk		= {
+			.name		= "sclk_mmc",
+			.id		= 2,
+			.parent         = &clk_dout_mmc2.clk,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 8),
+		},
+		.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 8, .size = 8 },
+	}, {
+		.clk		= {
+			.name		= "sclk_mmc",
+			.id		= 3,
+			.parent         = &clk_dout_mmc3.clk,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 12),
+		},
+		.reg_div = { .reg = S5P_CLKDIV_FSYS2, .shift = 24, .size = 8 },
+	}, {
+		.clk		= {
+			.name		= "sclk_mmc",
+			.id		= 4,
+			.parent         = &clk_dout_mmc4.clk,
+			.enable		= s5pv310_clksrc_mask_fsys_ctrl,
+			.ctrlbit	= (1 << 16),
+		},
+		.reg_div = { .reg = S5P_CLKDIV_FSYS3, .shift = 8, .size = 8 },
+	}
 };
 
 /* Clock initialization code */
@@ -464,8 +971,6 @@
 	&clk_aclk_cores,
 	&clk_aclk_corem1,
 	&clk_periphclk,
-	&clk_atclk,
-	&clk_pclk_dbg,
 	&clk_mout_corebus,
 	&clk_sclk_dmc,
 	&clk_aclk_cored,
@@ -478,6 +983,11 @@
 	&clk_aclk_100,
 	&clk_aclk_160,
 	&clk_aclk_133,
+	&clk_dout_mmc0,
+	&clk_dout_mmc1,
+	&clk_dout_mmc2,
+	&clk_dout_mmc3,
+	&clk_dout_mmc4,
 };
 
 void __init_or_cpufreq s5pv310_setup_clocks(void)
@@ -490,15 +1000,11 @@
 	unsigned long vpllsrc;
 	unsigned long xtal;
 	unsigned long armclk;
-	unsigned long aclk_corem0;
-	unsigned long aclk_cores;
-	unsigned long aclk_corem1;
-	unsigned long periphclk;
 	unsigned long sclk_dmc;
-	unsigned long aclk_cored;
-	unsigned long aclk_corep;
-	unsigned long aclk_acp;
-	unsigned long pclk_acp;
+	unsigned long aclk_200;
+	unsigned long aclk_100;
+	unsigned long aclk_160;
+	unsigned long aclk_133;
 	unsigned int ptr;
 
 	printk(KERN_DEBUG "%s: registering clocks\n", __func__);
@@ -529,26 +1035,21 @@
 			apll, mpll, epll, vpll);
 
 	armclk = clk_get_rate(&clk_armclk.clk);
-	aclk_corem0 = clk_get_rate(&clk_aclk_corem0.clk);
-	aclk_cores = clk_get_rate(&clk_aclk_cores.clk);
-	aclk_corem1 = clk_get_rate(&clk_aclk_corem1.clk);
-	periphclk = clk_get_rate(&clk_periphclk.clk);
 	sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk);
-	aclk_cored = clk_get_rate(&clk_aclk_cored.clk);
-	aclk_corep = clk_get_rate(&clk_aclk_corep.clk);
-	aclk_acp = clk_get_rate(&clk_aclk_acp.clk);
-	pclk_acp = clk_get_rate(&clk_pclk_acp.clk);
 
-	printk(KERN_INFO "S5PV310: ARMCLK=%ld, COREM0=%ld, CORES=%ld\n"
-			 "COREM1=%ld, PERI=%ld, DMC=%ld, CORED=%ld\n"
-			 "COREP=%ld, ACLK_ACP=%ld, PCLK_ACP=%ld",
-			armclk, aclk_corem0, aclk_cores, aclk_corem1,
-			periphclk, sclk_dmc, aclk_cored, aclk_corep,
-			aclk_acp, pclk_acp);
+	aclk_200 = clk_get_rate(&clk_aclk_200.clk);
+	aclk_100 = clk_get_rate(&clk_aclk_100.clk);
+	aclk_160 = clk_get_rate(&clk_aclk_160.clk);
+	aclk_133 = clk_get_rate(&clk_aclk_133.clk);
+
+	printk(KERN_INFO "S5PV310: ARMCLK=%ld, DMC=%ld, ACLK200=%ld\n"
+			 "ACLK100=%ld, ACLK160=%ld, ACLK133=%ld\n",
+			armclk, sclk_dmc, aclk_200,
+			aclk_100, aclk_160, aclk_133);
 
 	clk_f.rate = armclk;
 	clk_h.rate = sclk_dmc;
-	clk_p.rate = periphclk;
+	clk_p.rate = aclk_100;
 
 	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
 		s3c_set_clksrc(&clksrcs[ptr], true);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,10 +15,12 @@
 #include <asm/mach/irq.h>
 
 #include <asm/proc-fns.h>
+#include <asm/hardware/cache-l2x0.h>
 
 #include <plat/cpu.h>
 #include <plat/clock.h>
 #include <plat/s5pv310.h>
+#include <plat/sdhci.h>
 
 #include <mach/regs-irq.h>
 
@@ -31,9 +33,14 @@
 /* Initial IO mappings */
 static struct map_desc s5pv310_iodesc[] __initdata = {
 	{
-		.virtual	= (unsigned long)S5P_VA_COREPERI_BASE,
-		.pfn		= __phys_to_pfn(S5PV310_PA_COREPERI),
-		.length		= SZ_8K,
+		.virtual	= (unsigned long)S5P_VA_SYSRAM,
+		.pfn		= __phys_to_pfn(S5PV310_PA_SYSRAM),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_CMU,
+		.pfn		= __phys_to_pfn(S5PV310_PA_CMU),
+		.length		= SZ_128K,
 		.type		= MT_DEVICE,
 	}, {
 		.virtual	= (unsigned long)S5P_VA_COMBINER_BASE,
@@ -41,19 +48,39 @@
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	}, {
+		.virtual	= (unsigned long)S5P_VA_COREPERI_BASE,
+		.pfn		= __phys_to_pfn(S5PV310_PA_COREPERI),
+		.length		= SZ_8K,
+		.type		= MT_DEVICE,
+	}, {
 		.virtual	= (unsigned long)S5P_VA_L2CC,
 		.pfn		= __phys_to_pfn(S5PV310_PA_L2CC),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= (unsigned long)S5P_VA_SYSRAM,
-		.pfn		= __phys_to_pfn(S5PV310_PA_SYSRAM),
+		.virtual	= (unsigned long)S5P_VA_GPIO1,
+		.pfn		= __phys_to_pfn(S5PV310_PA_GPIO1),
 		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= (unsigned long)S5P_VA_CMU,
-		.pfn		= __phys_to_pfn(S5PV310_PA_CMU),
-		.length		= SZ_128K,
+		.virtual	= (unsigned long)S5P_VA_GPIO2,
+		.pfn		= __phys_to_pfn(S5PV310_PA_GPIO2),
+		.length		= SZ_4K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_GPIO3,
+		.pfn		= __phys_to_pfn(S5PV310_PA_GPIO3),
+		.length		= SZ_256,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S3C_VA_UART,
+		.pfn		= __phys_to_pfn(S3C_PA_UART),
+		.length		= SZ_512K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)S5P_VA_SROMC,
+		.pfn		= __phys_to_pfn(S5PV310_PA_SROMC),
+		.length		= SZ_4K,
 		.type		= MT_DEVICE,
 	},
 };
@@ -73,6 +100,12 @@
 void __init s5pv310_map_io(void)
 {
 	iotable_init(s5pv310_iodesc, ARRAY_SIZE(s5pv310_iodesc));
+
+	/* initialize device information early */
+	s5pv310_default_sdhci0();
+	s5pv310_default_sdhci1();
+	s5pv310_default_sdhci2();
+	s5pv310_default_sdhci3();
 }
 
 void __init s5pv310_init_clocks(int xtal)
@@ -121,6 +154,28 @@
 
 core_initcall(s5pv310_core_init);
 
+#ifdef CONFIG_CACHE_L2X0
+static int __init s5pv310_l2x0_cache_init(void)
+{
+	/* TAG, Data Latency Control: 2cycle */
+	__raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+	__raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+
+	/* L2X0 Prefetch Control */
+	__raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+
+	/* L2X0 Power Control */
+	__raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
+		     S5P_VA_L2CC + L2X0_POWER_CTRL);
+
+	l2x0_init(S5P_VA_L2CC, 0x7C070001, 0xC200ffff);
+
+	return 0;
+}
+
+early_initcall(s5pv310_l2x0_cache_init);
+#endif
+
 int __init s5pv310_init(void)
 {
 	printk(KERN_INFO "S5PV310: Initializing architecture\n");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/gpiolib.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/gpiolib.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/gpiolib.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,304 @@
+/* linux/arch/arm/mach-s5pv310/gpiolib.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV310 - GPIOlib support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+#include <plat/gpio-cfg-helpers.h>
+
+static struct s3c_gpio_cfg gpio_cfg = {
+	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
+	.set_pull	= s3c_gpio_setpull_updown,
+	.get_pull	= s3c_gpio_getpull_updown,
+};
+
+static struct s3c_gpio_cfg gpio_cfg_noint = {
+	.set_config	= s3c_gpio_setcfg_s3c64xx_4bit,
+	.set_pull	= s3c_gpio_setpull_updown,
+	.get_pull	= s3c_gpio_getpull_updown,
+};
+
+/*
+ * Following are the gpio banks in v310.
+ *
+ * The 'config' member when left to NULL, is initialized to the default
+ * structure gpio_cfg in the init function below.
+ *
+ * The 'base' member is also initialized in the init function below.
+ * Note: The initialization of 'base' member of s3c_gpio_chip structure
+ * uses the above macro and depends on the banks being listed in order here.
+ */
+static struct s3c_gpio_chip s5pv310_gpio_part1_4bit[] = {
+	{
+		.chip	= {
+			.base	= S5PV310_GPA0(0),
+			.ngpio	= S5PV310_GPIO_A0_NR,
+			.label	= "GPA0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPA1(0),
+			.ngpio	= S5PV310_GPIO_A1_NR,
+			.label	= "GPA1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPB(0),
+			.ngpio	= S5PV310_GPIO_B_NR,
+			.label	= "GPB",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPC0(0),
+			.ngpio	= S5PV310_GPIO_C0_NR,
+			.label	= "GPC0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPC1(0),
+			.ngpio	= S5PV310_GPIO_C1_NR,
+			.label	= "GPC1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPD0(0),
+			.ngpio	= S5PV310_GPIO_D0_NR,
+			.label	= "GPD0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPD1(0),
+			.ngpio	= S5PV310_GPIO_D1_NR,
+			.label	= "GPD1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPE0(0),
+			.ngpio	= S5PV310_GPIO_E0_NR,
+			.label	= "GPE0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPE1(0),
+			.ngpio	= S5PV310_GPIO_E1_NR,
+			.label	= "GPE1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPE2(0),
+			.ngpio	= S5PV310_GPIO_E2_NR,
+			.label	= "GPE2",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPE3(0),
+			.ngpio	= S5PV310_GPIO_E3_NR,
+			.label	= "GPE3",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPE4(0),
+			.ngpio	= S5PV310_GPIO_E4_NR,
+			.label	= "GPE4",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPF0(0),
+			.ngpio	= S5PV310_GPIO_F0_NR,
+			.label	= "GPF0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPF1(0),
+			.ngpio	= S5PV310_GPIO_F1_NR,
+			.label	= "GPF1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPF2(0),
+			.ngpio	= S5PV310_GPIO_F2_NR,
+			.label	= "GPF2",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPF3(0),
+			.ngpio	= S5PV310_GPIO_F3_NR,
+			.label	= "GPF3",
+		},
+	},
+};
+
+static struct s3c_gpio_chip s5pv310_gpio_part2_4bit[] = {
+	{
+		.chip	= {
+			.base	= S5PV310_GPJ0(0),
+			.ngpio	= S5PV310_GPIO_J0_NR,
+			.label	= "GPJ0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPJ1(0),
+			.ngpio	= S5PV310_GPIO_J1_NR,
+			.label	= "GPJ1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPK0(0),
+			.ngpio	= S5PV310_GPIO_K0_NR,
+			.label	= "GPK0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPK1(0),
+			.ngpio	= S5PV310_GPIO_K1_NR,
+			.label	= "GPK1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPK2(0),
+			.ngpio	= S5PV310_GPIO_K2_NR,
+			.label	= "GPK2",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPK3(0),
+			.ngpio	= S5PV310_GPIO_K3_NR,
+			.label	= "GPK3",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPL0(0),
+			.ngpio	= S5PV310_GPIO_L0_NR,
+			.label	= "GPL0",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPL1(0),
+			.ngpio	= S5PV310_GPIO_L1_NR,
+			.label	= "GPL1",
+		},
+	}, {
+		.chip	= {
+			.base	= S5PV310_GPL2(0),
+			.ngpio	= S5PV310_GPIO_L2_NR,
+			.label	= "GPL2",
+		},
+	}, {
+		.base	= (S5P_VA_GPIO2 + 0xC00),
+		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(0),
+		.chip	= {
+			.base	= S5PV310_GPX0(0),
+			.ngpio	= S5PV310_GPIO_X0_NR,
+			.label	= "GPX0",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO2 + 0xC20),
+		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(8),
+		.chip	= {
+			.base	= S5PV310_GPX1(0),
+			.ngpio	= S5PV310_GPIO_X1_NR,
+			.label	= "GPX1",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO2 + 0xC40),
+		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(16),
+		.chip	= {
+			.base	= S5PV310_GPX2(0),
+			.ngpio	= S5PV310_GPIO_X2_NR,
+			.label	= "GPX2",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	}, {
+		.base	= (S5P_VA_GPIO2 + 0xC60),
+		.config	= &gpio_cfg_noint,
+		.irq_base = IRQ_EINT(24),
+		.chip	= {
+			.base	= S5PV310_GPX3(0),
+			.ngpio	= S5PV310_GPIO_X3_NR,
+			.label	= "GPX3",
+			.to_irq	= samsung_gpiolib_to_irq,
+		},
+	},
+};
+
+static struct s3c_gpio_chip s5pv310_gpio_part3_4bit[] = {
+	{
+		.chip	= {
+			.base	= S5PV310_GPZ(0),
+			.ngpio	= S5PV310_GPIO_Z_NR,
+			.label	= "GPZ",
+		},
+	},
+};
+
+static __init int s5pv310_gpiolib_init(void)
+{
+	struct s3c_gpio_chip *chip;
+	int i;
+	int nr_chips;
+
+	/* GPIO part 1 */
+
+	chip = s5pv310_gpio_part1_4bit;
+	nr_chips = ARRAY_SIZE(s5pv310_gpio_part1_4bit);
+
+	for (i = 0; i < nr_chips; i++, chip++) {
+		if (chip->config == NULL)
+			chip->config = &gpio_cfg;
+		if (chip->base == NULL)
+			chip->base = S5P_VA_GPIO1 + (i) * 0x20;
+	}
+
+	samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part1_4bit, nr_chips);
+
+	/* GPIO part 2 */
+
+	chip = s5pv310_gpio_part2_4bit;
+	nr_chips = ARRAY_SIZE(s5pv310_gpio_part2_4bit);
+
+	for (i = 0; i < nr_chips; i++, chip++) {
+		if (chip->config == NULL)
+			chip->config = &gpio_cfg;
+		if (chip->base == NULL)
+			chip->base = S5P_VA_GPIO2 + (i) * 0x20;
+	}
+
+	samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part2_4bit, nr_chips);
+
+	/* GPIO part 3 */
+
+	chip = s5pv310_gpio_part3_4bit;
+	nr_chips = ARRAY_SIZE(s5pv310_gpio_part3_4bit);
+
+	for (i = 0; i < nr_chips; i++, chip++) {
+		if (chip->config == NULL)
+			chip->config = &gpio_cfg;
+		if (chip->base == NULL)
+			chip->base = S5P_VA_GPIO3 + (i) * 0x20;
+	}
+
+	samsung_gpiolib_add_4bit_chips(s5pv310_gpio_part3_4bit, nr_chips);
+
+	return 0;
+}
+core_initcall(s5pv310_gpiolib_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/hotplug.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/hotplug.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/hotplug.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/hotplug.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,144 @@
+/* linux arch/arm/mach-s5pv310/hotplug.c
+ *
+ *  Cloned from linux/arch/arm/mach-realview/hotplug.c
+ *
+ *  Copyright (C) 2002 ARM Ltd.
+ *  All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+#include <asm/cacheflush.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void cpu_enter_lowpower(void)
+{
+	unsigned int v;
+
+	flush_cache_all();
+	asm volatile(
+	"	mcr	p15, 0, %1, c7, c5, 0\n"
+	"	mcr	p15, 0, %1, c7, c10, 4\n"
+	/*
+	 * Turn off coherency
+	 */
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	bic	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	"	mrc	p15, 0, %0, c1, c0, 0\n"
+	"	bic	%0, %0, #0x04\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	  : "=&r" (v)
+	  : "r" (0)
+	  : "cc");
+}
+
+static inline void cpu_leave_lowpower(void)
+{
+	unsigned int v;
+
+	asm volatile(
+	"mrc	p15, 0, %0, c1, c0, 0\n"
+	"	orr	%0, %0, #0x04\n"
+	"	mcr	p15, 0, %0, c1, c0, 0\n"
+	"	mrc	p15, 0, %0, c1, c0, 1\n"
+	"	orr	%0, %0, #0x20\n"
+	"	mcr	p15, 0, %0, c1, c0, 1\n"
+	  : "=&r" (v)
+	  :
+	  : "cc");
+}
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+	/*
+	 * there is no power-control hardware on this platform, so all
+	 * we can do is put the core into WFI; this is safe as the calling
+	 * code will have already disabled interrupts
+	 */
+	for (;;) {
+		/*
+		 * here's the WFI
+		 */
+		asm(".word	0xe320f003\n"
+		    :
+		    :
+		    : "memory", "cc");
+
+		if (pen_release == cpu) {
+			/*
+			 * OK, proper wakeup, we're done
+			 */
+			break;
+		}
+
+		/*
+		 * getting here, means that we have come out of WFI without
+		 * having been woken up - this shouldn't happen
+		 *
+		 * The trouble is, letting people know about this is not really
+		 * possible, since we are currently running incoherently, and
+		 * therefore cannot safely call printk() or anything else
+		 */
+#ifdef DEBUG
+		printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu);
+#endif
+	}
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+	unsigned int this_cpu = hard_smp_processor_id();
+
+	if (cpu != this_cpu) {
+		printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+			   this_cpu, cpu);
+		BUG();
+	}
+#endif
+
+	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+	complete(&cpu_killed);
+
+	/*
+	 * we're ready for shutdown now, so do it
+	 */
+	cpu_enter_lowpower();
+	platform_do_lowpower(cpu);
+
+	/*
+	 * bring this CPU back into the world of cache
+	 * coherency, and then restore interrupts
+	 */
+	cpu_leave_lowpower();
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+	return cpu == 0 ? -EPERM : 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -20,13 +20,12 @@
 	 * aligned and add in the offset when we load the value here.
 	 */
 
-	.macro addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1
-		ldreq	\rx, = S3C_PA_UART
-		ldrne	\rx, = S3C_VA_UART
+	.macro addruart, rp, rv
+		ldreq	\rp, = S3C_PA_UART
+		ldrne	\rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-		add	\rx, \rx, #(0x10000 * CONFIG_DEBUG_S3C_UART)
+		add	\rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
+		add	\rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  *		http://www.samsung.com/
  *
- * S5PV210 - IRQ definitions
+ * S5PV310 - IRQ definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -60,6 +60,9 @@
 #define IRQ_TIMER3_VIC		COMBINER_IRQ(22, 3)
 #define IRQ_TIMER4_VIC		COMBINER_IRQ(22, 4)
 
+#define IRQ_RTC_ALARM		COMBINER_IRQ(23, 0)
+#define IRQ_RTC_TIC		COMBINER_IRQ(23, 1)
+
 #define IRQ_UART0		COMBINER_IRQ(26, 0)
 #define IRQ_UART1		COMBINER_IRQ(26, 1)
 #define IRQ_UART2		COMBINER_IRQ(26, 2)
@@ -67,11 +70,46 @@
 #define IRQ_UART4		COMBINER_IRQ(26, 4)
 
 #define IRQ_IIC			COMBINER_IRQ(27, 0)
+#define IRQ_IIC1		COMBINER_IRQ(27, 1)
+#define IRQ_IIC2		COMBINER_IRQ(27, 2)
+#define IRQ_IIC3		COMBINER_IRQ(27, 3)
+#define IRQ_IIC4		COMBINER_IRQ(27, 4)
+#define IRQ_IIC5		COMBINER_IRQ(27, 5)
+#define IRQ_IIC6		COMBINER_IRQ(27, 6)
+#define IRQ_IIC7		COMBINER_IRQ(27, 7)
 
-/* Set the default NR_IRQS */
+#define IRQ_HSMMC0		COMBINER_IRQ(29, 0)
+#define IRQ_HSMMC1		COMBINER_IRQ(29, 1)
+#define IRQ_HSMMC2		COMBINER_IRQ(29, 2)
+#define IRQ_HSMMC3		COMBINER_IRQ(29, 3)
 
-#define NR_IRQS			COMBINER_IRQ(MAX_COMBINER_NR, 0)
+#define IRQ_ONENAND_AUDI	COMBINER_IRQ(34, 0)
 
-#define MAX_COMBINER_NR		39
+#define IRQ_EINT4		COMBINER_IRQ(37, 0)
+#define IRQ_EINT5		COMBINER_IRQ(37, 1)
+#define IRQ_EINT6		COMBINER_IRQ(37, 2)
+#define IRQ_EINT7		COMBINER_IRQ(37, 3)
+#define IRQ_EINT8		COMBINER_IRQ(38, 0)
+
+#define IRQ_EINT9		COMBINER_IRQ(38, 1)
+#define IRQ_EINT10		COMBINER_IRQ(38, 2)
+#define IRQ_EINT11		COMBINER_IRQ(38, 3)
+#define IRQ_EINT12		COMBINER_IRQ(38, 4)
+#define IRQ_EINT13		COMBINER_IRQ(38, 5)
+#define IRQ_EINT14		COMBINER_IRQ(38, 6)
+#define IRQ_EINT15		COMBINER_IRQ(38, 7)
+
+#define IRQ_EINT16_31		COMBINER_IRQ(39, 0)
+
+#define MAX_COMBINER_NR		40
+
+#define S5P_IRQ_EINT_BASE	COMBINER_IRQ(MAX_COMBINER_NR, 0)
+
+#define S5P_EINT_BASE1		(S5P_IRQ_EINT_BASE + 0)
+#define S5P_EINT_BASE2		(S5P_IRQ_EINT_BASE + 16)
+
+/* Set the default NR_IRQS */
+
+#define NR_IRQS			(S5P_IRQ_EINT_BASE + 32)
 
 #endif /* __ASM_ARCH_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/map.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/map.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/map.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/map.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,15 +25,24 @@
 
 #define S5PV310_PA_SYSRAM		(0x02025000)
 
+#define S5PV310_PA_SROM_BANK(x)		(0x04000000 + ((x) * 0x01000000))
+
+#define S5PC210_PA_ONENAND		(0x0C000000)
+#define S5P_PA_ONENAND			S5PC210_PA_ONENAND
+
+#define S5PC210_PA_ONENAND_DMA		(0x0C600000)
+#define S5P_PA_ONENAND_DMA		S5PC210_PA_ONENAND_DMA
+
 #define S5PV310_PA_CHIPID		(0x10000000)
 #define S5P_PA_CHIPID			S5PV310_PA_CHIPID
 
-#define S5PV310_PA_SYSCON		(0x10020000)
+#define S5PV310_PA_SYSCON		(0x10010000)
 #define S5P_PA_SYSCON			S5PV310_PA_SYSCON
 
 #define S5PV310_PA_CMU			(0x10030000)
 
 #define S5PV310_PA_WATCHDOG		(0x10060000)
+#define S5PV310_PA_RTC			(0x10070000)
 
 #define S5PV310_PA_COMBINER		(0x10448000)
 
@@ -46,10 +55,11 @@
 #define S5PV310_PA_GPIO1		(0x11400000)
 #define S5PV310_PA_GPIO2		(0x11000000)
 #define S5PV310_PA_GPIO3		(0x03860000)
-#define S5P_PA_GPIO			S5PV310_PA_GPIO1
 
 #define S5PV310_PA_HSMMC(x)		(0x12510000 + ((x) * 0x10000))
 
+#define S5PV310_PA_SROMC		(0x12570000)
+
 #define S5PV310_PA_UART			(0x13800000)
 
 #define S5P_PA_UART(x)			(S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))
@@ -61,7 +71,7 @@
 
 #define S5P_SZ_UART			SZ_256
 
-#define S5PV310_PA_IIC0			(0x13860000)
+#define S5PV310_PA_IIC(x)		(0x13860000 + ((x) * 0x10000))
 
 #define S5PV310_PA_TIMER		(0x139D0000)
 #define S5P_PA_TIMER			S5PV310_PA_TIMER
@@ -75,7 +85,15 @@
 #define S3C_PA_HSMMC1			S5PV310_PA_HSMMC(1)
 #define S3C_PA_HSMMC2			S5PV310_PA_HSMMC(2)
 #define S3C_PA_HSMMC3			S5PV310_PA_HSMMC(3)
-#define S3C_PA_IIC			S5PV310_PA_IIC0
+#define S3C_PA_IIC			S5PV310_PA_IIC(0)
+#define S3C_PA_IIC1			S5PV310_PA_IIC(1)
+#define S3C_PA_IIC2			S5PV310_PA_IIC(2)
+#define S3C_PA_IIC3			S5PV310_PA_IIC(3)
+#define S3C_PA_IIC4			S5PV310_PA_IIC(4)
+#define S3C_PA_IIC5			S5PV310_PA_IIC(5)
+#define S3C_PA_IIC6			S5PV310_PA_IIC(6)
+#define S3C_PA_IIC7			S5PV310_PA_IIC(7)
+#define S3C_PA_RTC			S5PV310_PA_RTC
 #define S3C_PA_WDT			S5PV310_PA_WATCHDOG
 
 #endif /* __ASM_ARCH_MAP_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-clock.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,11 +26,23 @@
 
 #define S5P_CLKSRC_TOP0			S5P_CLKREG(0x0C210)
 #define S5P_CLKSRC_TOP1			S5P_CLKREG(0x0C214)
-
+#define S5P_CLKSRC_CAM			S5P_CLKREG(0x0C220)
+#define S5P_CLKSRC_IMAGE		S5P_CLKREG(0x0C230)
+#define S5P_CLKSRC_LCD0			S5P_CLKREG(0x0C234)
+#define S5P_CLKSRC_LCD1			S5P_CLKREG(0x0C238)
+#define S5P_CLKSRC_FSYS			S5P_CLKREG(0x0C240)
 #define S5P_CLKSRC_PERIL0		S5P_CLKREG(0x0C250)
+#define S5P_CLKSRC_PERIL1		S5P_CLKREG(0x0C254)
 
 #define S5P_CLKDIV_TOP			S5P_CLKREG(0x0C510)
-
+#define S5P_CLKDIV_CAM			S5P_CLKREG(0x0C520)
+#define S5P_CLKDIV_IMAGE		S5P_CLKREG(0x0C530)
+#define S5P_CLKDIV_LCD0			S5P_CLKREG(0x0C534)
+#define S5P_CLKDIV_LCD1			S5P_CLKREG(0x0C538)
+#define S5P_CLKDIV_FSYS0		S5P_CLKREG(0x0C540)
+#define S5P_CLKDIV_FSYS1		S5P_CLKREG(0x0C544)
+#define S5P_CLKDIV_FSYS2		S5P_CLKREG(0x0C548)
+#define S5P_CLKDIV_FSYS3		S5P_CLKREG(0x0C54C)
 #define S5P_CLKDIV_PERIL0		S5P_CLKREG(0x0C550)
 #define S5P_CLKDIV_PERIL1		S5P_CLKREG(0x0C554)
 #define S5P_CLKDIV_PERIL2		S5P_CLKREG(0x0C558)
@@ -38,9 +50,21 @@
 #define S5P_CLKDIV_PERIL4		S5P_CLKREG(0x0C560)
 #define S5P_CLKDIV_PERIL5		S5P_CLKREG(0x0C564)
 
+#define S5P_CLKSRC_MASK_TOP		S5P_CLKREG(0x0C310)
+#define S5P_CLKSRC_MASK_CAM		S5P_CLKREG(0x0C320)
+#define S5P_CLKSRC_MASK_LCD0		S5P_CLKREG(0x0C334)
+#define S5P_CLKSRC_MASK_LCD1		S5P_CLKREG(0x0C338)
+#define S5P_CLKSRC_MASK_FSYS		S5P_CLKREG(0x0C340)
 #define S5P_CLKSRC_MASK_PERIL0		S5P_CLKREG(0x0C350)
+#define S5P_CLKSRC_MASK_PERIL1		S5P_CLKREG(0x0C354)
 
+#define S5P_CLKGATE_IP_CAM		S5P_CLKREG(0x0C920)
+#define S5P_CLKGATE_IP_IMAGE		S5P_CLKREG(0x0C930)
+#define S5P_CLKGATE_IP_LCD0		S5P_CLKREG(0x0C934)
+#define S5P_CLKGATE_IP_LCD1		S5P_CLKREG(0x0C938)
+#define S5P_CLKGATE_IP_FSYS		S5P_CLKREG(0x0C940)
 #define S5P_CLKGATE_IP_PERIL		S5P_CLKREG(0x0C950)
+#define S5P_CLKGATE_IP_PERIR		S5P_CLKREG(0x0C960)
 
 #define S5P_CLKSRC_CORE			S5P_CLKREG(0x10200)
 #define S5P_CLKDIV_CORE0		S5P_CLKREG(0x10500)
@@ -60,4 +84,8 @@
 
 #define S5P_CLKGATE_SCLKCPU		S5P_CLKREG(0x14800)
 
+/* Compatibility defines */
+
+#define S5P_EPLL_CON			S5P_EPLL_CON0
+
 #endif /* __ASM_ARCH_REGS_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-gpio.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,42 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/regs-gpio.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV310 - GPIO (including EINT) register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_GPIO_H
+#define __ASM_ARCH_REGS_GPIO_H __FILE__
+
+#include <mach/map.h>
+#include <mach/irqs.h>
+
+#define S5PV310_EINT40CON		(S5P_VA_GPIO2 + 0xE00)
+#define S5P_EINT_CON(x)			(S5PV310_EINT40CON + ((x) * 0x4))
+
+#define S5PV310_EINT40FLTCON0		(S5P_VA_GPIO2 + 0xE80)
+#define S5P_EINT_FLTCON(x)		(S5PV310_EINT40FLTCON0 + ((x) * 0x4))
+
+#define S5PV310_EINT40MASK		(S5P_VA_GPIO2 + 0xF00)
+#define S5P_EINT_MASK(x)		(S5PV310_EINT40MASK + ((x) * 0x4))
+
+#define S5PV310_EINT40PEND		(S5P_VA_GPIO2 + 0xF40)
+#define S5P_EINT_PEND(x)		(S5PV310_EINT40PEND + ((x) * 0x4))
+
+#define EINT_REG_NR(x)			(EINT_OFFSET(x) >> 3)
+
+#define eint_irq_to_bit(irq)		(1 << (EINT_OFFSET(irq) & 0x7))
+
+#define EINT_MODE			S3C_GPIO_SFN(0xf)
+
+#define EINT_GPIO_0(x)			S5PV310_GPX0(x)
+#define EINT_GPIO_1(x)			S5PV310_GPX1(x)
+#define EINT_GPIO_2(x)			S5PV310_GPX2(x)
+#define EINT_GPIO_3(x)			S5PV310_GPX3(x)
+
+#endif /* __ASM_ARCH_REGS_GPIO_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-srom.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-srom.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/regs-srom.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/regs-srom.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,50 @@
+/* linux/arch/arm/mach-s5pv310/include/mach/regs-srom.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV310 - SROMC register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_SROM_H
+#define __ASM_ARCH_REGS_SROM_H __FILE__
+
+#include <mach/map.h>
+
+#define S5PV310_SROMREG(x)	(S5P_VA_SROMC + (x))
+
+#define S5PV310_SROM_BW		S5PV310_SROMREG(0x0)
+#define S5PV310_SROM_BC0	S5PV310_SROMREG(0x4)
+#define S5PV310_SROM_BC1	S5PV310_SROMREG(0x8)
+#define S5PV310_SROM_BC2	S5PV310_SROMREG(0xc)
+#define S5PV310_SROM_BC3	S5PV310_SROMREG(0x10)
+
+/* one register BW holds 4 x 4-bit packed settings for NCS0 - NCS3 */
+
+#define S5PV310_SROM_BW__DATAWIDTH__SHIFT	0
+#define S5PV310_SROM_BW__ADDRMODE__SHIFT	1
+#define S5PV310_SROM_BW__WAITENABLE__SHIFT	2
+#define S5PV310_SROM_BW__BYTEENABLE__SHIFT	3
+
+#define S5PV310_SROM_BW__CS_MASK		0xf
+
+#define S5PV310_SROM_BW__NCS0__SHIFT		0
+#define S5PV310_SROM_BW__NCS1__SHIFT		4
+#define S5PV310_SROM_BW__NCS2__SHIFT		8
+#define S5PV310_SROM_BW__NCS3__SHIFT		12
+
+/* applies to same to BCS0 - BCS3 */
+
+#define S5PV310_SROM_BCX__PMC__SHIFT		0
+#define S5PV310_SROM_BCX__TACP__SHIFT		4
+#define S5PV310_SROM_BCX__TCAH__SHIFT		8
+#define S5PV310_SROM_BCX__TCOH__SHIFT		12
+#define S5PV310_SROM_BCX__TACC__SHIFT		16
+#define S5PV310_SROM_BCX__TCOS__SHIFT		24
+#define S5PV310_SROM_BCX__TACS__SHIFT		28
+
+#endif /* __ASM_ARCH_REGS_SROM_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,17 +7,10 @@
 #define ASM_ARCH_SMP_H __FILE__
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 extern void __iomem *gic_cpu_base_addr;
 
-#define hard_smp_processor_id()			\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x03;				\
-	})
-
 /*
  * We use IRQ1 as the IPI
  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H __FILE__
 
-#define VMALLOC_END	(0xF0000000UL)
+#define VMALLOC_END	0xF6000000UL
 
 #endif /* __ASM_ARCH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/irq-combiner.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/irq-combiner.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/irq-combiner.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/irq-combiner.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,11 +66,7 @@
 	if (status == 0)
 		goto out;
 
-	for (combiner_irq = 0; combiner_irq < 32; combiner_irq++) {
-		if (status & 0x1)
-			break;
-		status >>= 1;
-	}
+	combiner_irq = __ffs(status);
 
 	cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
 	if (unlikely(cascade_irq >= NR_IRQS))
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/irq-eint.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/irq-eint.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/irq-eint.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/irq-eint.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,228 @@
+/* linux/arch/arm/mach-s5pv310/irq-eint.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5PV310 - IRQ EINT support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/sysdev.h>
+#include <linux/gpio.h>
+
+#include <plat/pm.h>
+#include <plat/cpu.h>
+#include <plat/gpio-cfg.h>
+
+#include <mach/regs-gpio.h>
+
+static DEFINE_SPINLOCK(eint_lock);
+
+static unsigned int eint0_15_data[16];
+
+static unsigned int s5pv310_get_irq_nr(unsigned int number)
+{
+	u32 ret = 0;
+
+	switch (number) {
+	case 0 ... 3:
+		ret = (number + IRQ_EINT0);
+		break;
+	case 4 ... 7:
+		ret = (number + (IRQ_EINT4 - 4));
+		break;
+	case 8 ... 15:
+		ret = (number + (IRQ_EINT8 - 8));
+		break;
+	default:
+		printk(KERN_ERR "number available : %d\n", number);
+	}
+
+	return ret;
+}
+
+static inline void s5pv310_irq_eint_mask(unsigned int irq)
+{
+	u32 mask;
+
+	spin_lock(&eint_lock);
+	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
+	mask |= eint_irq_to_bit(irq);
+	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+	spin_unlock(&eint_lock);
+}
+
+static void s5pv310_irq_eint_unmask(unsigned int irq)
+{
+	u32 mask;
+
+	spin_lock(&eint_lock);
+	mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(irq)));
+	mask &= ~(eint_irq_to_bit(irq));
+	__raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(irq)));
+	spin_unlock(&eint_lock);
+}
+
+static inline void s5pv310_irq_eint_ack(unsigned int irq)
+{
+	__raw_writel(eint_irq_to_bit(irq), S5P_EINT_PEND(EINT_REG_NR(irq)));
+}
+
+static void s5pv310_irq_eint_maskack(unsigned int irq)
+{
+	s5pv310_irq_eint_mask(irq);
+	s5pv310_irq_eint_ack(irq);
+}
+
+static int s5pv310_irq_eint_set_type(unsigned int irq, unsigned int type)
+{
+	int offs = EINT_OFFSET(irq);
+	int shift;
+	u32 ctrl, mask;
+	u32 newvalue = 0;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		newvalue = S5P_IRQ_TYPE_EDGE_RISING;
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
+		break;
+
+	case IRQ_TYPE_EDGE_BOTH:
+		newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
+		break;
+
+	default:
+		printk(KERN_ERR "No such irq type %d", type);
+		return -EINVAL;
+	}
+
+	shift = (offs & 0x7) * 4;
+	mask = 0x7 << shift;
+
+	spin_lock(&eint_lock);
+	ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(irq)));
+	ctrl &= ~mask;
+	ctrl |= newvalue << shift;
+	__raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(irq)));
+	spin_unlock(&eint_lock);
+
+	switch (offs) {
+	case 0 ... 7:
+		s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
+		break;
+	case 8 ... 15:
+		s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
+		break;
+	case 16 ... 23:
+		s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
+		break;
+	case 24 ... 31:
+		s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
+		break;
+	default:
+		printk(KERN_ERR "No such irq number %d", offs);
+	}
+
+	return 0;
+}
+
+static struct irq_chip s5pv310_irq_eint = {
+	.name		= "s5pv310-eint",
+	.mask		= s5pv310_irq_eint_mask,
+	.unmask		= s5pv310_irq_eint_unmask,
+	.mask_ack	= s5pv310_irq_eint_maskack,
+	.ack		= s5pv310_irq_eint_ack,
+	.set_type	= s5pv310_irq_eint_set_type,
+#ifdef CONFIG_PM
+	.set_wake	= s3c_irqext_wake,
+#endif
+};
+
+/* s5pv310_irq_demux_eint
+ *
+ * This function demuxes the IRQ from from EINTs 16 to 31.
+ * It is designed to be inlined into the specific handler
+ * s5p_irq_demux_eintX_Y.
+ *
+ * Each EINT pend/mask registers handle eight of them.
+ */
+static inline void s5pv310_irq_demux_eint(unsigned int start)
+{
+	unsigned int irq;
+
+	u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
+	u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
+
+	status &= ~mask;
+	status &= 0xff;
+
+	while (status) {
+		irq = fls(status) - 1;
+		generic_handle_irq(irq + start);
+		status &= ~(1 << irq);
+	}
+}
+
+static void s5pv310_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
+{
+	s5pv310_irq_demux_eint(IRQ_EINT(16));
+	s5pv310_irq_demux_eint(IRQ_EINT(24));
+}
+
+static void s5pv310_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
+{
+	u32 *irq_data = get_irq_data(irq);
+	struct irq_chip *chip = get_irq_chip(irq);
+
+	chip->mask(irq);
+
+	if (chip->ack)
+		chip->ack(irq);
+
+	generic_handle_irq(*irq_data);
+
+	chip->unmask(irq);
+}
+
+int __init s5pv310_init_irq_eint(void)
+{
+	int irq;
+
+	for (irq = 0 ; irq <= 31 ; irq++) {
+		set_irq_chip(IRQ_EINT(irq), &s5pv310_irq_eint);
+		set_irq_handler(IRQ_EINT(irq), handle_level_irq);
+		set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
+	}
+
+	set_irq_chained_handler(IRQ_EINT16_31, s5pv310_irq_demux_eint16_31);
+
+	for (irq = 0 ; irq <= 15 ; irq++) {
+		eint0_15_data[irq] = IRQ_EINT(irq);
+
+		set_irq_data(s5pv310_get_irq_nr(irq), &eint0_15_data[irq]);
+		set_irq_chained_handler(s5pv310_get_irq_nr(irq),
+					s5pv310_irq_eint0_15);
+	}
+
+	return 0;
+}
+
+arch_initcall(s5pv310_init_irq_eint);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,6 @@
 
 config CPU_S5PV310
 	bool
-	select PLAT_S5P
 	help
 	  Enable S5PV310 CPU support
 
@@ -25,21 +24,105 @@
 	help
 	  Common setup code for i2c bus 2.
 
+config S5PV310_SETUP_I2C3
+	bool
+	help
+	  Common setup code for i2c bus 3.
+
+config S5PV310_SETUP_I2C4
+	bool
+	help
+	  Common setup code for i2c bus 4.
+
+config S5PV310_SETUP_I2C5
+	bool
+	help
+	  Common setup code for i2c bus 5.
+
+config S5PV310_SETUP_I2C6
+	bool
+	help
+	  Common setup code for i2c bus 6.
+
+config S5PV310_SETUP_I2C7
+	bool
+	help
+	  Common setup code for i2c bus 7.
+
+config S5PV310_SETUP_SDHCI
+	bool
+	select S5PV310_SETUP_SDHCI_GPIO
+	help
+	  Internal helper functions for S5PV310 based SDHCI systems.
+
+config S5PV310_SETUP_SDHCI_GPIO
+	bool
+	help
+	  Common setup code for SDHCI gpio.
+
 # machine support
 
-config MACH_SMDKV310
-	bool "SMDKV310"
+menu "S5PC210 Machines"
+
+config MACH_SMDKC210
+	bool "SMDKC210"
 	select CPU_S5PV310
-	select ARCH_SPARSEMEM_ENABLE
+	select S3C_DEV_RTC
+	select S3C_DEV_WDT
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC1
+	select S3C_DEV_HSMMC2
+	select S3C_DEV_HSMMC3
+	select S5PV310_SETUP_SDHCI
 	help
-	  Machine support for Samsung SMDKV310
+	  Machine support for Samsung SMDKC210
+	  S5PC210(MCP) is one of package option of S5PV310
 
 config MACH_UNIVERSAL_C210
 	bool "Mobile UNIVERSAL_C210 Board"
 	select CPU_S5PV310
-	select ARCH_SPARSEMEM_ENABLE
+	select S5P_DEV_ONENAND
+	select S3C_DEV_I2C1
+	select S5PV310_SETUP_I2C1
 	help
 	  Machine support for Samsung Mobile Universal S5PC210 Reference
 	  Board. S5PC210(MCP) is one of package option of S5PV310
 
+endmenu
+
+menu "S5PV310 Machines"
+
+config MACH_SMDKV310
+	bool "SMDKV310"
+	select CPU_S5PV310
+	select S3C_DEV_RTC
+	select S3C_DEV_WDT
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC1
+	select S3C_DEV_HSMMC2
+	select S3C_DEV_HSMMC3
+	select S5PV310_SETUP_SDHCI
+	help
+	  Machine support for Samsung SMDKV310
+
+endmenu
+
+comment "Configuration for HSMMC bus width"
+
+menu "Use 8-bit bus width"
+
+config S5PV310_SDHCI_CH0_8BIT
+	bool "Channel 0 with 8-bit bus"
+	help
+	  Support HSMMC Channel 0 8-bit bus.
+	  If selected, Channel 1 is disabled.
+
+config S5PV310_SDHCI_CH2_8BIT
+	bool "Channel 2 with 8-bit bus"
+	help
+	  Support HSMMC Channel 2 8-bit bus.
+	  If selected, Channel 3 is disabled.
+
+endmenu
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-smdkc210.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-smdkc210.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-smdkc210.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-smdkc210.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,202 @@
+/* linux/arch/arm/mach-s5pv310/mach-smdkc210.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/serial_core.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <linux/io.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/s5pv310.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/sdhci.h>
+
+#include <mach/map.h>
+#include <mach/regs-srom.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define SMDKC210_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
+				 S3C2410_UCON_RXILEVEL |	\
+				 S3C2410_UCON_TXIRQMODE |	\
+				 S3C2410_UCON_RXIRQMODE |	\
+				 S3C2410_UCON_RXFIFO_TOI |	\
+				 S3C2443_UCON_RXERR_IRQEN)
+
+#define SMDKC210_ULCON_DEFAULT	S3C2410_LCON_CS8
+
+#define SMDKC210_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
+				 S5PV210_UFCON_TXTRIG4 |	\
+				 S5PV210_UFCON_RXTRIG4)
+
+static struct s3c2410_uartcfg smdkc210_uartcfgs[] __initdata = {
+	[0] = {
+		.hwport		= 0,
+		.flags		= 0,
+		.ucon		= SMDKC210_UCON_DEFAULT,
+		.ulcon		= SMDKC210_ULCON_DEFAULT,
+		.ufcon		= SMDKC210_UFCON_DEFAULT,
+	},
+	[1] = {
+		.hwport		= 1,
+		.flags		= 0,
+		.ucon		= SMDKC210_UCON_DEFAULT,
+		.ulcon		= SMDKC210_ULCON_DEFAULT,
+		.ufcon		= SMDKC210_UFCON_DEFAULT,
+	},
+	[2] = {
+		.hwport		= 2,
+		.flags		= 0,
+		.ucon		= SMDKC210_UCON_DEFAULT,
+		.ulcon		= SMDKC210_ULCON_DEFAULT,
+		.ufcon		= SMDKC210_UFCON_DEFAULT,
+	},
+	[3] = {
+		.hwport		= 3,
+		.flags		= 0,
+		.ucon		= SMDKC210_UCON_DEFAULT,
+		.ulcon		= SMDKC210_ULCON_DEFAULT,
+		.ufcon		= SMDKC210_UFCON_DEFAULT,
+	},
+};
+
+static struct s3c_sdhci_platdata smdkc210_hsmmc0_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK0(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+#ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT
+	.max_width		= 8,
+	.host_caps		= MMC_CAP_8_BIT_DATA,
+#endif
+};
+
+static struct s3c_sdhci_platdata smdkc210_hsmmc1_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK0(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct s3c_sdhci_platdata smdkc210_hsmmc2_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK2(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+#ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT
+	.max_width		= 8,
+	.host_caps		= MMC_CAP_8_BIT_DATA,
+#endif
+};
+
+static struct s3c_sdhci_platdata smdkc210_hsmmc3_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK2(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct resource smdkc210_smsc911x_resources[] = {
+	[0] = {
+		.start	= S5PV310_PA_SROM_BANK(1),
+		.end	= S5PV310_PA_SROM_BANK(1) + SZ_64K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_EINT(5),
+		.end	= IRQ_EINT(5),
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+	},
+};
+
+static struct smsc911x_platform_config smsc9215_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.mac		= {0x00, 0x80, 0x00, 0x23, 0x45, 0x67},
+};
+
+static struct platform_device smdkc210_smsc911x = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smdkc210_smsc911x_resources),
+	.resource	= smdkc210_smsc911x_resources,
+	.dev		= {
+		.platform_data	= &smsc9215_config,
+	},
+};
+
+static struct platform_device *smdkc210_devices[] __initdata = {
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc1,
+	&s3c_device_hsmmc2,
+	&s3c_device_hsmmc3,
+	&s3c_device_rtc,
+	&s3c_device_wdt,
+	&smdkc210_smsc911x,
+};
+
+static void __init smdkc210_smsc911x_init(void)
+{
+	u32 cs1;
+
+	/* configure nCS1 width to 16 bits */
+	cs1 = __raw_readl(S5PV310_SROM_BW) &
+		    ~(S5PV310_SROM_BW__CS_MASK <<
+				    S5PV310_SROM_BW__NCS1__SHIFT);
+	cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) |
+		(1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) |
+		(1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) <<
+		S5PV310_SROM_BW__NCS1__SHIFT;
+	__raw_writel(cs1, S5PV310_SROM_BW);
+
+	/* set timing for nCS1 suitable for ethernet chip */
+	__raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) |
+		     (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) |
+		     (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) |
+		     (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1);
+}
+
+static void __init smdkc210_map_io(void)
+{
+	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+	s3c24xx_init_clocks(24000000);
+	s3c24xx_init_uarts(smdkc210_uartcfgs, ARRAY_SIZE(smdkc210_uartcfgs));
+}
+
+static void __init smdkc210_machine_init(void)
+{
+	smdkc210_smsc911x_init();
+
+	s3c_sdhci0_set_platdata(&smdkc210_hsmmc0_pdata);
+	s3c_sdhci1_set_platdata(&smdkc210_hsmmc1_pdata);
+	s3c_sdhci2_set_platdata(&smdkc210_hsmmc2_pdata);
+	s3c_sdhci3_set_platdata(&smdkc210_hsmmc3_pdata);
+
+	platform_add_devices(smdkc210_devices, ARRAY_SIZE(smdkc210_devices));
+}
+
+MACHINE_START(SMDKC210, "SMDKC210")
+	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+	.boot_params	= S5P_PA_SDRAM + 0x100,
+	.init_irq	= s5pv310_init_irq,
+	.map_io		= smdkc210_map_io,
+	.init_machine	= smdkc210_machine_init,
+	.timer		= &s5pv310_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-smdkv310.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-smdkv310.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-smdkv310.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-smdkv310.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,16 +9,23 @@
 */
 
 #include <linux/serial_core.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <linux/io.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
-#include <asm/hardware/cache-l2x0.h>
 
 #include <plat/regs-serial.h>
 #include <plat/s5pv310.h>
 #include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/sdhci.h>
 
 #include <mach/map.h>
+#include <mach/regs-srom.h>
 
 /* Following are default values for UCON, ULCON and UFCON UART registers */
 #define SMDKV310_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
@@ -65,6 +72,107 @@
 	},
 };
 
+static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK0(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+#ifdef CONFIG_S5PV310_SDHCI_CH0_8BIT
+	.max_width		= 8,
+	.host_caps		= MMC_CAP_8_BIT_DATA,
+#endif
+};
+
+static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK0(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK2(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+#ifdef CONFIG_S5PV310_SDHCI_CH2_8BIT
+	.max_width		= 8,
+	.host_caps		= MMC_CAP_8_BIT_DATA,
+#endif
+};
+
+static struct s3c_sdhci_platdata smdkv310_hsmmc3_pdata __initdata = {
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.ext_cd_gpio		= S5PV310_GPK2(2),
+	.ext_cd_gpio_invert	= 1,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct resource smdkv310_smsc911x_resources[] = {
+	[0] = {
+		.start	= S5PV310_PA_SROM_BANK(1),
+		.end	= S5PV310_PA_SROM_BANK(1) + SZ_64K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_EINT(5),
+		.end	= IRQ_EINT(5),
+		.flags	= IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+	},
+};
+
+static struct smsc911x_platform_config smsc9215_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+	.flags		= SMSC911X_USE_16BIT | SMSC911X_FORCE_INTERNAL_PHY,
+	.phy_interface	= PHY_INTERFACE_MODE_MII,
+	.mac		= {0x00, 0x80, 0x00, 0x23, 0x45, 0x67},
+};
+
+static struct platform_device smdkv310_smsc911x = {
+	.name		= "smsc911x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smdkv310_smsc911x_resources),
+	.resource	= smdkv310_smsc911x_resources,
+	.dev		= {
+		.platform_data	= &smsc9215_config,
+	},
+};
+
+static struct platform_device *smdkv310_devices[] __initdata = {
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc1,
+	&s3c_device_hsmmc2,
+	&s3c_device_hsmmc3,
+	&s3c_device_rtc,
+	&s3c_device_wdt,
+	&smdkv310_smsc911x,
+};
+
+static void __init smdkv310_smsc911x_init(void)
+{
+	u32 cs1;
+
+	/* configure nCS1 width to 16 bits */
+	cs1 = __raw_readl(S5PV310_SROM_BW) &
+		    ~(S5PV310_SROM_BW__CS_MASK <<
+				    S5PV310_SROM_BW__NCS1__SHIFT);
+	cs1 |= ((1 << S5PV310_SROM_BW__DATAWIDTH__SHIFT) |
+		(1 << S5PV310_SROM_BW__WAITENABLE__SHIFT) |
+		(1 << S5PV310_SROM_BW__BYTEENABLE__SHIFT)) <<
+		S5PV310_SROM_BW__NCS1__SHIFT;
+	__raw_writel(cs1, S5PV310_SROM_BW);
+
+	/* set timing for nCS1 suitable for ethernet chip */
+	__raw_writel((0x1 << S5PV310_SROM_BCX__PMC__SHIFT) |
+		     (0x9 << S5PV310_SROM_BCX__TACP__SHIFT) |
+		     (0xc << S5PV310_SROM_BCX__TCAH__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TCOH__SHIFT) |
+		     (0x6 << S5PV310_SROM_BCX__TACC__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TCOS__SHIFT) |
+		     (0x1 << S5PV310_SROM_BCX__TACS__SHIFT), S5PV310_SROM_BC1);
+}
+
 static void __init smdkv310_map_io(void)
 {
 	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -74,16 +182,19 @@
 
 static void __init smdkv310_machine_init(void)
 {
-#ifdef CONFIG_CACHE_L2X0
-	l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff);
-#endif
+	smdkv310_smsc911x_init();
+
+	s3c_sdhci0_set_platdata(&smdkv310_hsmmc0_pdata);
+	s3c_sdhci1_set_platdata(&smdkv310_hsmmc1_pdata);
+	s3c_sdhci2_set_platdata(&smdkv310_hsmmc2_pdata);
+	s3c_sdhci3_set_platdata(&smdkv310_hsmmc3_pdata);
+
+	platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices));
 }
 
 MACHINE_START(SMDKV310, "SMDKV310")
 	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
 	/* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv310_init_irq,
 	.map_io		= smdkv310_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-universal_c210.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-universal_c210.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/mach-universal_c210.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/mach-universal_c210.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,15 +7,20 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
-#include <asm/hardware/cache-l2x0.h>
 
 #include <plat/regs-serial.h>
 #include <plat/s5pv310.h>
 #include <plat/cpu.h>
+#include <plat/devs.h>
 
 #include <mach/map.h>
 
@@ -60,6 +65,72 @@
 	},
 };
 
+static struct gpio_keys_button universal_gpio_keys_tables[] = {
+	{
+		.code			= KEY_VOLUMEUP,
+		.gpio			= S5PV310_GPX2(0),	/* XEINT16 */
+		.desc			= "gpio-keys: KEY_VOLUMEUP",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_VOLUMEDOWN,
+		.gpio			= S5PV310_GPX2(1),	/* XEINT17 */
+		.desc			= "gpio-keys: KEY_VOLUMEDOWN",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_CONFIG,
+		.gpio			= S5PV310_GPX2(2),	/* XEINT18 */
+		.desc			= "gpio-keys: KEY_CONFIG",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_CAMERA,
+		.gpio			= S5PV310_GPX2(3),	/* XEINT19 */
+		.desc			= "gpio-keys: KEY_CAMERA",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_OK,
+		.gpio			= S5PV310_GPX3(5),	/* XEINT29 */
+		.desc			= "gpio-keys: KEY_OK",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data universal_gpio_keys_data = {
+	.buttons	= universal_gpio_keys_tables,
+	.nbuttons	= ARRAY_SIZE(universal_gpio_keys_tables),
+};
+
+static struct platform_device universal_gpio_keys = {
+	.name			= "gpio-keys",
+	.dev			= {
+		.platform_data	= &universal_gpio_keys_data,
+	},
+};
+
+/* I2C0 */
+static struct i2c_board_info i2c0_devs[] __initdata = {
+	/* Camera, To be updated */
+};
+
+/* I2C1 */
+static struct i2c_board_info i2c1_devs[] __initdata = {
+	/* Gyro, To be updated */
+};
+
+static struct platform_device *universal_devices[] __initdata = {
+	&universal_gpio_keys,
+	&s5p_device_onenand,
+};
+
 static void __init universal_map_io(void)
 {
 	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
@@ -69,15 +140,15 @@
 
 static void __init universal_machine_init(void)
 {
-#ifdef CONFIG_CACHE_L2X0
-	l2x0_init(S5P_VA_L2CC, 1 << 28, 0xffffffff);
-#endif
+	i2c_register_board_info(0, i2c0_devs, ARRAY_SIZE(i2c0_devs));
+	i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+
+	/* Last */
+	platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices));
 }
 
 MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
 	/* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
-	.phys_io	= S3C_PA_UART & 0xfff00000,
-	.io_pg_offst	= (((u32)S3C_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= S5P_PA_SDRAM + 0x100,
 	.init_irq	= s5pv310_init_irq,
 	.map_io		= universal_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -13,7 +13,7 @@
 # Core support for S5PV310 system
 
 obj-$(CONFIG_CPU_S5PV310)	+= cpu.o init.o clock.o irq-combiner.o
-obj-$(CONFIG_CPU_S5PV310)	+= setup-i2c0.o time.o
+obj-$(CONFIG_CPU_S5PV310)	+= setup-i2c0.o time.o gpiolib.o irq-eint.o
 
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
 obj-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
@@ -21,6 +21,7 @@
 
 # machine support
 
+obj-$(CONFIG_MACH_SMDKC210)	+= mach-smdkc210.o
 obj-$(CONFIG_MACH_SMDKV310)	+= mach-smdkv310.o
 obj-$(CONFIG_MACH_UNIVERSAL_C210)	+= mach-universal_c210.o
 
@@ -28,3 +29,10 @@
 
 obj-$(CONFIG_S5PV310_SETUP_I2C1)	+= setup-i2c1.o
 obj-$(CONFIG_S5PV310_SETUP_I2C2)	+= setup-i2c2.o
+obj-$(CONFIG_S5PV310_SETUP_I2C3)	+= setup-i2c3.o
+obj-$(CONFIG_S5PV310_SETUP_I2C4)	+= setup-i2c4.o
+obj-$(CONFIG_S5PV310_SETUP_I2C5)	+= setup-i2c5.o
+obj-$(CONFIG_S5PV310_SETUP_I2C6)	+= setup-i2c6.o
+obj-$(CONFIG_S5PV310_SETUP_I2C7)	+= setup-i2c7.o
+obj-$(CONFIG_S5PV310_SETUP_SDHCI)	+= setup-sdhci.o
+obj-$(CONFIG_S5PV310_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c0.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c0.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c0.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,6 @@
 
 void s3c_i2c0_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV310_GPD1(0), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV310_GPD1(0), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV310_GPD1(1), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV310_GPD1(1), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV310_GPD1(0), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c1.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c1.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c1.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,8 +18,6 @@
 
 void s3c_i2c1_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV310_GPD1(2), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV310_GPD1(2), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV310_GPD1(3), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S5PV310_GPD1(3), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV310_GPD1(2), 2,
+			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c2.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c2.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c2.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,8 +18,6 @@
 
 void s3c_i2c2_cfg_gpio(struct platform_device *dev)
 {
-	s3c_gpio_cfgpin(S5PV310_GPA0(6), S3C_GPIO_SFN(3));
-	s3c_gpio_setpull(S5PV310_GPA0(6), S3C_GPIO_PULL_UP);
-	s3c_gpio_cfgpin(S5PV310_GPA0(7), S3C_GPIO_SFN(3));
-	s3c_gpio_setpull(S5PV310_GPA0(7), S3C_GPIO_PULL_UP);
+	s3c_gpio_cfgall_range(S5PV310_GPA0(6), 2,
+			      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c3.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c3.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-s5pv310/setup-i2c3.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * I2C3 GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct platform_device; /* don't need the contents */
+
+#include <linux/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c3_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5PV310_GPA1(2), 2,
+			      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c4.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c4.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c4.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c4.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-s5pv310/setup-i2c4.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * I2C4 GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct platform_device; /* don't need the contents */
+
+#include <linux/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c4_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5PV310_GPB(2), 2,
+			      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c5.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c5.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c5.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c5.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-s5pv310/setup-i2c5.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * I2C5 GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct platform_device; /* don't need the contents */
+
+#include <linux/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c5_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5PV310_GPB(6), 2,
+			      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c6.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c6.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c6.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c6.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-s5pv310/setup-i2c6.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * I2C6 GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct platform_device; /* don't need the contents */
+
+#include <linux/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c6_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5PV310_GPC1(3), 2,
+			      S3C_GPIO_SFN(4), S3C_GPIO_PULL_UP);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c7.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c7.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-i2c7.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-i2c7.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-s5pv310/setup-i2c7.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *
+ * I2C7 GPIO configuration.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct platform_device; /* don't need the contents */
+
+#include <linux/gpio.h>
+#include <plat/iic.h>
+#include <plat/gpio-cfg.h>
+
+void s3c_i2c7_cfg_gpio(struct platform_device *dev)
+{
+	s3c_gpio_cfgall_range(S5PV310_GPD0(2), 2,
+			      S3C_GPIO_SFN(3), S3C_GPIO_PULL_UP);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-sdhci.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-sdhci.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-sdhci.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-sdhci.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,69 @@
+/* linux/arch/arm/mach-s5pv310/setup-sdhci.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5PV310 - Helper functions for settign up SDHCI device(s) (HSMMC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include <plat/regs-sdhci.h>
+
+/* clock sources for the mmc bus clock, order as for the ctrl2[5..4] */
+
+char *s5pv310_hsmmc_clksrcs[4] = {
+	[0] = NULL,
+	[1] = NULL,
+	[2] = "sclk_mmc",	/* mmc_bus */
+	[3] = NULL,
+};
+
+void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev, void __iomem *r,
+				  struct mmc_ios *ios, struct mmc_card *card)
+{
+	u32 ctrl2, ctrl3;
+
+	/* don't need to alter anything acording to card-type */
+
+	ctrl2 = readl(r + S3C_SDHCI_CONTROL2);
+
+	/* select base clock source to HCLK */
+
+	ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+
+	/*
+	 * clear async mode, enable conflict mask, rx feedback ctrl, SD
+	 * clk hold and no use debounce count
+	 */
+
+	ctrl2 |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
+		  S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
+		  S3C_SDHCI_CTRL2_ENFBCLKRX |
+		  S3C_SDHCI_CTRL2_DFCNT_NONE |
+		  S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
+
+	/* Tx and Rx feedback clock delay control */
+
+	if (ios->clock < 25 * 1000000)
+		ctrl3 = (S3C_SDHCI_CTRL3_FCSEL3 |
+			 S3C_SDHCI_CTRL3_FCSEL2 |
+			 S3C_SDHCI_CTRL3_FCSEL1 |
+			 S3C_SDHCI_CTRL3_FCSEL0);
+	else
+		ctrl3 = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
+
+	writel(ctrl2, r + S3C_SDHCI_CONTROL2);
+	writel(ctrl3, r + S3C_SDHCI_CONTROL3);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-sdhci-gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-sdhci-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-s5pv310/setup-sdhci-gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-s5pv310/setup-sdhci-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,152 @@
+/* linux/arch/arm/mach-s5pv310/setup-sdhci-gpio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5PV310 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/regs-sdhci.h>
+#include <plat/sdhci.h>
+
+void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width)
+{
+	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
+	unsigned int gpio;
+
+	/* Set all the necessary GPK0[0:1] pins to special-function 2 */
+	for (gpio = S5PV310_GPK0(0); gpio < S5PV310_GPK0(2); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	switch (width) {
+	case 8:
+		for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) {
+			/* Data pin GPK1[3:6] to special-funtion 3 */
+			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+			s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+		}
+	case 4:
+		for (gpio = S5PV310_GPK0(3); gpio <= S5PV310_GPK0(6); gpio++) {
+			/* Data pin GPK0[3:6] to special-funtion 2 */
+			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+			s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+		}
+	default:
+		break;
+	}
+
+	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
+		s3c_gpio_cfgpin(S5PV310_GPK0(2), S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(S5PV310_GPK0(2), S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+}
+
+void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width)
+{
+	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
+	unsigned int gpio;
+
+	/* Set all the necessary GPK1[0:1] pins to special-function 2 */
+	for (gpio = S5PV310_GPK1(0); gpio < S5PV310_GPK1(2); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	for (gpio = S5PV310_GPK1(3); gpio <= S5PV310_GPK1(6); gpio++) {
+		/* Data pin GPK1[3:6] to special-function 2 */
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
+		s3c_gpio_cfgpin(S5PV310_GPK1(2), S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(S5PV310_GPK1(2), S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+}
+
+void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width)
+{
+	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
+	unsigned int gpio;
+
+	/* Set all the necessary GPK2[0:1] pins to special-function 2 */
+	for (gpio = S5PV310_GPK2(0); gpio < S5PV310_GPK2(2); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	switch (width) {
+	case 8:
+		for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) {
+			/* Data pin GPK3[3:6] to special-function 3 */
+			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3));
+			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+			s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+		}
+	case 4:
+		for (gpio = S5PV310_GPK2(3); gpio <= S5PV310_GPK2(6); gpio++) {
+			/* Data pin GPK2[3:6] to special-function 2 */
+			s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+			s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+			s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+		}
+	default:
+		break;
+	}
+
+	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
+		s3c_gpio_cfgpin(S5PV310_GPK2(2), S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(S5PV310_GPK2(2), S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+}
+
+void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *dev, int width)
+{
+	struct s3c_sdhci_platdata *pdata = dev->dev.platform_data;
+	unsigned int gpio;
+
+	/* Set all the necessary GPK3[0:1] pins to special-function 2 */
+	for (gpio = S5PV310_GPK3(0); gpio < S5PV310_GPK3(2); gpio++) {
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	for (gpio = S5PV310_GPK3(3); gpio <= S5PV310_GPK3(6); gpio++) {
+		/* Data pin GPK3[3:6] to special-function 2 */
+		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+
+	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
+		s3c_gpio_cfgpin(S5PV310_GPK3(2), S3C_GPIO_SFN(2));
+		s3c_gpio_setpull(S5PV310_GPK3(2), S3C_GPIO_PULL_UP);
+		s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/assabet.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/assabet.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/assabet.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/assabet.c	2011-01-04 19:50:19.000000000 -0500
@@ -447,8 +447,6 @@
 
 
 MACHINE_START(ASSABET, "Intel-Assabet")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.fixup		= fixup_assabet,
 	.map_io		= assabet_map_io,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/badge4.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/badge4.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/badge4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/badge4.c	2011-01-04 19:50:19.000000000 -0500
@@ -302,8 +302,6 @@
 }
 
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= badge4_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/cerf.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/cerf.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/cerf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/cerf.c	2011-01-04 19:50:19.000000000 -0500
@@ -135,8 +135,6 @@
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
 	/* Maintainer: support@intrinsyc.com */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= cerf_map_io,
 	.init_irq	= cerf_init_irq,
 	.timer		= &sa1100_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/collie.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/collie.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/collie.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/collie.c	2011-01-04 19:50:19.000000000 -0500
@@ -379,8 +379,6 @@
 }
 
 MACHINE_START(COLLIE, "Sharp-Collie")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= collie_map_io,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/cpu-sa1100.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/cpu-sa1100.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/cpu-sa1100.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/cpu-sa1100.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,7 +13,7 @@
  * This software has been developed while working on the LART
  * computing board (http://www.lartmaker.nl/), which is
  * sponsored by the Mobile Multi-media Communications
- * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
+ * (http://www.mobimedia.org/) and Ubiquitous Communications
  * (http://www.ubicom.tudelft.nl/) projects.
  *
  * The authors can be reached at:
@@ -184,16 +184,15 @@
 {
 	unsigned int cur = sa11x0_getspeed(0);
 	unsigned int new_ppcr;
-
 	struct cpufreq_freqs freqs;
+
+	new_ppcr = sa11x0_freq_to_ppcr(target_freq);
 	switch(relation){
 	case CPUFREQ_RELATION_L:
-		new_ppcr = sa11x0_freq_to_ppcr(target_freq);
 		if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max)
 			new_ppcr--;
 		break;
 	case CPUFREQ_RELATION_H:
-		new_ppcr = sa11x0_freq_to_ppcr(target_freq);
 		if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) &&
 		    (sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min))
 			new_ppcr--;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/h3100.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/h3100.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/h3100.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/h3100.c	2011-01-04 19:50:19.000000000 -0500
@@ -84,8 +84,6 @@
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= h3100_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/h3600.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/h3600.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/h3600.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/h3600.c	2011-01-04 19:50:19.000000000 -0500
@@ -125,8 +125,6 @@
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= h3600_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/hackkit.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/hackkit.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/hackkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/hackkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,8 +195,6 @@
  */
 
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= hackkit_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -12,33 +12,37 @@
 */
 #include <mach/hardware.h>
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x80000000	@ physical base address
-		movne	\rx, #0xf8000000	@ virtual address
+		.macro	addruart, rp, rv
+		mrc	p15, 0, \rp, c1, c0
+		tst	\rp, #1			@ MMU enabled?
+		moveq	\rp, #0x80000000	@ physical base address
+		movne	\rp, #0xf8000000	@ virtual address
 
 		@ We probe for the active serial port here, coherently with
 		@ the comment in arch/arm/mach-sa1100/include/mach/uncompress.h.
 		@ We assume r1 can be clobbered.
 
 		@ see if Ser3 is active
-		add	\rx, \rx, #0x00050000
-		ldr	r1, [\rx, #UTCR3]
-		tst	r1, #UTCR3_TXE
+		add	\rp, \rp, #0x00050000
+		ldr	\rv, [\rp, #UTCR3]
+		tst	\rv, #UTCR3_TXE
 
 		@ if Ser3 is inactive, then try Ser1
-		addeq	\rx, \rx, #(0x00010000 - 0x00050000)
-		ldreq	r1, [\rx, #UTCR3]
-		tsteq	r1, #UTCR3_TXE
+		addeq	\rp, \rp, #(0x00010000 - 0x00050000)
+		ldreq	\rv, [\rp, #UTCR3]
+		tsteq	\rv, #UTCR3_TXE
 
 		@ if Ser1 is inactive, then try Ser2
-		addeq	\rx, \rx, #(0x00030000 - 0x00010000)
-		ldreq	r1, [\rx, #UTCR3]
-		tsteq	r1, #UTCR3_TXE
+		addeq	\rp, \rp, #(0x00030000 - 0x00010000)
+		ldreq	\rv, [\rp, #UTCR3]
+		tsteq	\rv, #UTCR3_TXE
+
+		@ clear top bits, and generate both phys and virt addresses
+		lsl	\rp, \rp, #8
+		lsr	\rp, \rp, #8
+		orr	\rv, \rp, #0xf8000000	@ virtual
+		orr	\rp, \rp, #0x80000000	@ physical
 
-		@ if all ports are inactive, then there is nothing we can do
-		moveq	pc, lr
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/jornada720.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/jornada720.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/jornada720.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/jornada720.c	2011-01-04 19:50:19.000000000 -0500
@@ -364,8 +364,6 @@
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
 	/* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= jornada720_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -90,8 +90,8 @@
 	# FIXME: select CPU_FREQ_SA11x0
 	help
 	  Say Y here if you want to build a kernel for the HP Jornada 720
-	  handheld computer.  See <http://www.hp.com/jornada/products/720>
-	  for details.
+	  handheld computer.  See 
+	  <http://h10025.www1.hp.com/ewfrf/wc/product?product=61677&cc=us&lc=en&dlc=en&product=61677#> 
 
 config SA1100_JORNADA720_SSP
 	bool "HP Jornada 720 Extended SSP driver"
@@ -145,7 +145,7 @@
 	  FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
 	  PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
 	  like CL4 in additional it has a PCMCIA-Slot. For more information
-	  visit <http://www.my-siemens.com/> or <http://www.siemens.ch/>.
+	  visit <http://www.usa.siemens.com/> or <http://www.siemens.ch/>.
 
 config SA1100_SSP
 	tristate "Generic PIO SSP"
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/lart.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/lart.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/lart.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/lart.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,8 +61,6 @@
 }
 
 MACHINE_START(LART, "LART")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= lart_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/pleb.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/pleb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/pleb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/pleb.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,8 +146,6 @@
 }
 
 MACHINE_START(PLEB, "PLEB")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.map_io		= pleb_map_io,
 	.init_irq	= sa1100_init_irq,
 	.timer		= &sa1100_timer,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/shannon.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/shannon.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/shannon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/shannon.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,8 +82,6 @@
 }
 
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= shannon_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/simpad.c linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/simpad.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-sa1100/simpad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-sa1100/simpad.c	2011-01-04 19:50:19.000000000 -0500
@@ -228,8 +228,6 @@
 
 MACHINE_START(SIMPAD, "Simpad")
 	/* Maintainer: Holger Freyther */
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf8000000) >> 18) & 0xfffc,
 	.boot_params	= 0xc0000100,
 	.map_io		= simpad_map_io,
 	.init_irq	= sa1100_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shark/core.c linux-libre-2.6.37-gnu/arch/arm/mach-shark/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shark/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shark/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -152,8 +152,6 @@
 
 MACHINE_START(SHARK, "Shark")
 	/* Maintainer: Alexander Schulz */
-	.phys_io	= 0x40000000,
-	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x08003000,
 	.map_io		= shark_map_io,
 	.init_irq	= shark_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shark/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-shark/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-shark/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shark/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,10 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mov	\rx, #0xe0000000
-		orr	\rx, \rx, #0x000003f8
+		.macro	addruart, rp, rv
+		mov	\rp, #0xe0000000
+		orr	\rp, \rp, #0x000003f8
+		mov	\rv, \rp
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shark/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-shark/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-shark/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shark/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,4 @@
 /*
  * arch/arm/mach-shark/include/mach/vmalloc.h
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-ap4evb.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-ap4evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-ap4evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-ap4evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-#include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
@@ -44,6 +43,10 @@
 #include <linux/input/sh_keysc.h>
 #include <linux/usb/r8a66597.h>
 
+#include <media/sh_mobile_ceu.h>
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+
 #include <sound/sh_fsi.h>
 
 #include <video/sh_mobile_hdmi.h>
@@ -160,11 +163,13 @@
 		.name		= "loader",
 		.offset		= 0x00000000,
 		.size		= 512 * 1024,
+		.mask_flags	= MTD_WRITEABLE,
 	},
 	{
 		.name		= "bootenv",
 		.offset		= MTDPART_OFS_APPEND,
 		.size		= 512 * 1024,
+		.mask_flags	= MTD_WRITEABLE,
 	},
 	{
 		.name		= "kernel_ro",
@@ -235,10 +240,22 @@
 	},
 };
 
+/*
+ * The card detect pin of the top SD/MMC slot (CN7) is active low and is
+ * connected to GPIO A22 of SH7372 (GPIO_PORT41).
+ */
+static int slot_cn7_get_cd(struct platform_device *pdev)
+{
+	if (gpio_is_valid(GPIO_PORT41))
+		return !gpio_get_value(GPIO_PORT41);
+	else
+		return -ENXIO;
+}
+
 /* SH_MMCIF */
 static struct resource sh_mmcif_resources[] = {
 	[0] = {
-		.name	= "SH_MMCIF",
+		.name	= "MMCIF",
 		.start	= 0xE6BD0000,
 		.end	= 0xE6BD00FF,
 		.flags	= IORESOURCE_MEM,
@@ -261,6 +278,7 @@
 	.caps		= MMC_CAP_4_BIT_DATA |
 			  MMC_CAP_8_BIT_DATA |
 			  MMC_CAP_NEEDS_POLL,
+	.get_cd		= slot_cn7_get_cd,
 };
 
 static struct platform_device sh_mmcif_device = {
@@ -310,6 +328,8 @@
 	.dma_slave_rx	= SHDMA_SLAVE_SDHI1_RX,
 	.tmio_ocr_mask	= MMC_VDD_165_195,
 	.tmio_flags	= TMIO_MMC_WRPROTECT_DISABLE,
+	.tmio_caps	= MMC_CAP_NEEDS_POLL,
+	.get_cd		= slot_cn7_get_cd,
 };
 
 static struct resource sdhi1_resources[] = {
@@ -375,10 +395,40 @@
 	.resource	= usb1_host_resources,
 };
 
+const static struct fb_videomode ap4evb_lcdc_modes[] = {
+	{
+#ifdef CONFIG_AP4EVB_QHD
+		.name		= "R63302(QHD)",
+		.xres		= 544,
+		.yres		= 961,
+		.left_margin	= 72,
+		.right_margin	= 600,
+		.hsync_len	= 16,
+		.upper_margin	= 8,
+		.lower_margin	= 8,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+#else
+		.name		= "WVGA Panel",
+		.xres		= 800,
+		.yres		= 480,
+		.left_margin	= 220,
+		.right_margin	= 110,
+		.hsync_len	= 70,
+		.upper_margin	= 20,
+		.lower_margin	= 5,
+		.vsync_len	= 5,
+		.sync		= 0,
+#endif
+	},
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.bpp = 16,
+		.lcd_cfg = ap4evb_lcdc_modes,
+		.num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
 	}
 };
 
@@ -517,26 +567,130 @@
 
 /* FSI */
 #define IRQ_FSI		evt2irq(0x1840)
-#define FSIACKCR	0xE6150018
-static void fsiackcr_init(struct clk *clk)
+static int __fsi_set_rate(struct clk *clk, long rate, int enable)
 {
-	u32 status = __raw_readl(clk->enable_reg);
+	int ret = 0;
 
-	/* use external clock */
-	status &= ~0x000000ff;
-	status |= 0x00000080;
-	__raw_writel(status, clk->enable_reg);
+	if (rate <= 0)
+		return ret;
+
+	if (enable) {
+		ret = clk_set_rate(clk, rate);
+		if (0 == ret)
+			ret = clk_enable(clk);
+	} else {
+		clk_disable(clk);
+	}
+
+	return ret;
 }
 
-static struct clk_ops fsiackcr_clk_ops = {
-	.init = fsiackcr_init,
-};
+static int __fsi_set_round_rate(struct clk *clk, long rate, int enable)
+{
+	return __fsi_set_rate(clk, clk_round_rate(clk, rate), enable);
+}
 
-static struct clk fsiackcr_clk = {
-	.ops		= &fsiackcr_clk_ops,
-	.enable_reg	= (void __iomem *)FSIACKCR,
-	.rate		= 0, /* unknown */
-};
+static int fsi_ak4642_set_rate(struct device *dev, int rate, int enable)
+{
+	struct clk *fsia_ick;
+	struct clk *fsiack;
+	int ret = -EIO;
+
+	fsia_ick = clk_get(dev, "icka");
+	if (IS_ERR(fsia_ick))
+		return PTR_ERR(fsia_ick);
+
+	/*
+	 * FSIACK is connected to AK4642,
+	 * and use external clock pin from it.
+	 * it is parent of fsia_ick now.
+	 */
+	fsiack = clk_get_parent(fsia_ick);
+	if (!fsiack)
+		goto fsia_ick_out;
+
+	/*
+	 * we get 1/1 divided clock by setting same rate to fsiack and fsia_ick
+	 *
+	 ** FIXME **
+	 * Because the freq_table of external clk (fsiack) are all 0,
+	 * the return value of clk_round_rate became 0.
+	 * So, it use __fsi_set_rate here.
+	 */
+	ret = __fsi_set_rate(fsiack, rate, enable);
+	if (ret < 0)
+		goto fsiack_out;
+
+	ret = __fsi_set_round_rate(fsia_ick, rate, enable);
+	if ((ret < 0) && enable)
+		__fsi_set_round_rate(fsiack, rate, 0); /* disable FSI ACK */
+
+fsiack_out:
+	clk_put(fsiack);
+
+fsia_ick_out:
+	clk_put(fsia_ick);
+
+	return 0;
+}
+
+static int fsi_hdmi_set_rate(struct device *dev, int rate, int enable)
+{
+	struct clk *fsib_clk;
+	struct clk *fdiv_clk = &sh7372_fsidivb_clk;
+	long fsib_rate = 0;
+	long fdiv_rate = 0;
+	int ackmd_bpfmd;
+	int ret;
+
+	switch (rate) {
+	case 44100:
+		fsib_rate	= rate * 256;
+		ackmd_bpfmd	= SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+		break;
+	case 48000:
+		fsib_rate	= 85428000; /* around 48kHz x 256 x 7 */
+		fdiv_rate	= rate * 256;
+		ackmd_bpfmd	= SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+		break;
+	default:
+		pr_err("unsupported rate in FSI2 port B\n");
+		return -EINVAL;
+	}
+
+	/* FSI B setting */
+	fsib_clk = clk_get(dev, "ickb");
+	if (IS_ERR(fsib_clk))
+		return -EIO;
+
+	ret = __fsi_set_round_rate(fsib_clk, fsib_rate, enable);
+	clk_put(fsib_clk);
+	if (ret < 0)
+		return ret;
+
+	/* FSI DIV setting */
+	ret = __fsi_set_round_rate(fdiv_clk, fdiv_rate, enable);
+	if (ret < 0) {
+		/* disable FSI B */
+		if (enable)
+			__fsi_set_round_rate(fsib_clk, fsib_rate, 0);
+		return ret;
+	}
+
+	return ackmd_bpfmd;
+}
+
+static int fsi_set_rate(struct device *dev, int is_porta, int rate, int enable)
+{
+	int ret;
+
+	if (is_porta)
+		ret = fsi_ak4642_set_rate(dev, rate, enable);
+	else
+		ret = fsi_hdmi_set_rate(dev, rate, enable);
+
+	return ret;
+}
 
 static struct sh_fsi_platform_info fsi_info = {
 	.porta_flags = SH_FSI_BRS_INV |
@@ -544,6 +698,12 @@
 		       SH_FSI_IN_SLAVE_MODE |
 		       SH_FSI_OFMT(PCM) |
 		       SH_FSI_IFMT(PCM),
+
+	.portb_flags = SH_FSI_BRS_INV |
+		       SH_FSI_BRM_INV |
+		       SH_FSI_LRS_INV |
+		       SH_FSI_OFMT(SPDIF),
+	.set_rate = fsi_set_rate,
 };
 
 static struct resource fsi_resources[] = {
@@ -577,26 +737,6 @@
 		.interface_type = RGB24,
 		.clock_divider = 1,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_cfg = {
-			.name = "HDMI",
-			/* So far only 720p is supported */
-			.xres = 1280,
-			.yres = 720,
-			/*
-			 * If left and right margins are not multiples of 8,
-			 * LDHAJR will be adjusted accordingly by the LCDC
-			 * driver. Until we start using EDID, these values
-			 * might have to be adjusted for different monitors.
-			 */
-			.left_margin = 200,
-			.right_margin = 88,
-			.hsync_len = 48,
-			.upper_margin = 20,
-			.lower_margin = 5,
-			.vsync_len = 5,
-			.pixclock = 13468,
-			.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
-		},
 	}
 };
 
@@ -608,7 +748,7 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= intcs_evt2irq(0x17a0),
+		.start	= intcs_evt2irq(0x1780),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -627,6 +767,7 @@
 static struct sh_mobile_hdmi_info hdmi_info = {
 	.lcd_chan = &sh_mobile_lcdc1_info.ch[0],
 	.lcd_dev = &lcdc1_device.dev,
+	.flags = HDMI_SND_SRC_SPDIF,
 };
 
 static struct resource hdmi_resources[] = {
@@ -689,6 +830,95 @@
 	},
 };
 
+static struct i2c_board_info imx074_info = {
+	I2C_BOARD_INFO("imx074", 0x1a),
+};
+
+struct soc_camera_link imx074_link = {
+	.bus_id		= 0,
+	.board_info	= &imx074_info,
+	.i2c_adapter_id	= 0,
+	.module_name	= "imx074",
+};
+
+static struct platform_device ap4evb_camera = {
+	.name   = "soc-camera-pdrv",
+	.id     = 0,
+	.dev    = {
+		.platform_data = &imx074_link,
+	},
+};
+
+static struct sh_csi2_client_config csi2_clients[] = {
+	{
+		.phy		= SH_CSI2_PHY_MAIN,
+		.lanes		= 3,
+		.channel	= 0,
+		.pdev		= &ap4evb_camera,
+	},
+};
+
+static struct sh_csi2_pdata csi2_info = {
+	.type		= SH_CSI2C,
+	.clients	= csi2_clients,
+	.num_clients	= ARRAY_SIZE(csi2_clients),
+	.flags		= SH_CSI2_ECC | SH_CSI2_CRC,
+};
+
+static struct resource csi2_resources[] = {
+	[0] = {
+		.name	= "CSI2",
+		.start	= 0xffc90000,
+		.end	= 0xffc90fff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x17a0),
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device csi2_device = {
+	.name   = "sh-mobile-csi2",
+	.id     = 0,
+	.num_resources	= ARRAY_SIZE(csi2_resources),
+	.resource	= csi2_resources,
+	.dev    = {
+		.platform_data = &csi2_info,
+	},
+};
+
+static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
+	.flags = SH_CEU_FLAG_USE_8BIT_BUS,
+	.csi2_dev = &csi2_device.dev,
+};
+
+static struct resource ceu_resources[] = {
+	[0] = {
+		.name	= "CEU",
+		.start	= 0xfe910000,
+		.end	= 0xfe91009f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0x880),
+		.flags  = IORESOURCE_IRQ,
+	},
+	[2] = {
+		/* place holder for contiguous memory */
+	},
+};
+
+static struct platform_device ceu_device = {
+	.name		= "sh_mobile_ceu",
+	.id             = 0, /* "ceu0" clock */
+	.num_resources	= ARRAY_SIZE(ceu_resources),
+	.resource	= ceu_resources,
+	.dev	= {
+		.platform_data	= &sh_mobile_ceu_info,
+	},
+};
+
 static struct platform_device *ap4evb_devices[] __initdata = {
 	&leds_device,
 	&nor_flash_device,
@@ -701,6 +931,9 @@
 	&lcdc1_device,
 	&lcdc_device,
 	&hdmi_device,
+	&csi2_device,
+	&ceu_device,
+	&ap4evb_camera,
 };
 
 static int __init hdmi_init_pm_clock(void)
@@ -715,30 +948,35 @@
 		goto out;
 	}
 
-	ret = clk_set_parent(&pllc2_clk, &dv_clki_div2_clk);
+	ret = clk_set_parent(&sh7372_pllc2_clk, &sh7372_dv_clki_div2_clk);
 	if (ret < 0) {
-		pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, pllc2_clk.usecount);
+		pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, sh7372_pllc2_clk.usecount);
 		goto out;
 	}
 
-	pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&pllc2_clk));
+	pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&sh7372_pllc2_clk));
 
-	rate = clk_round_rate(&pllc2_clk, 594000000);
+	rate = clk_round_rate(&sh7372_pllc2_clk, 594000000);
 	if (rate < 0) {
 		pr_err("Cannot get suitable rate: %ld\n", rate);
 		ret = rate;
 		goto out;
 	}
 
-	ret = clk_set_rate(&pllc2_clk, rate);
+	ret = clk_set_rate(&sh7372_pllc2_clk, rate);
 	if (ret < 0) {
 		pr_err("Cannot set rate %ld: %d\n", rate, ret);
 		goto out;
 	}
 
+	ret = clk_enable(&sh7372_pllc2_clk);
+	if (ret < 0) {
+		pr_err("Cannot enable pllc2 clock\n");
+		goto out;
+	}
 	pr_debug("PLLC2 set frequency %lu\n", rate);
 
-	ret = clk_set_parent(hdmi_ick, &pllc2_clk);
+	ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
 	if (ret < 0) {
 		pr_err("Cannot set HDMI parent: %d\n", ret);
 		goto out;
@@ -752,11 +990,32 @@
 
 device_initcall(hdmi_init_pm_clock);
 
+static int __init fsi_init_pm_clock(void)
+{
+	struct clk *fsia_ick;
+	int ret;
+
+	fsia_ick = clk_get(&fsi_device.dev, "icka");
+	if (IS_ERR(fsia_ick)) {
+		ret = PTR_ERR(fsia_ick);
+		pr_err("Cannot get FSI ICK: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk);
+	if (ret < 0)
+		pr_err("Cannot set FSI-A parent: %d\n", ret);
+
+	clk_put(fsia_ick);
+
+	return ret;
+}
+device_initcall(fsi_init_pm_clock);
+
 /*
  * FIXME !!
  *
  * gpio_no_direction
- * gpio_pull_up
  * are quick_hack.
  *
  * current gpio frame work doesn't have
@@ -768,49 +1027,37 @@
 	__raw_writeb(0x00, addr);
 }
 
-static void __init gpio_pull_up(u32 addr)
-{
-	u8 data = __raw_readb(addr);
-
-	data &= 0x0F;
-	data |= 0xC0;
-	__raw_writeb(data, addr);
-}
-
 /* TouchScreen */
+#ifdef CONFIG_AP4EVB_QHD
+# define GPIO_TSC_IRQ	GPIO_FN_IRQ28_123
+# define GPIO_TSC_PORT	GPIO_PORT123
+#else /* WVGA */
+# define GPIO_TSC_IRQ	GPIO_FN_IRQ7_40
+# define GPIO_TSC_PORT	GPIO_PORT40
+#endif
+
 #define IRQ28	evt2irq(0x3380) /* IRQ28A */
 #define IRQ7	evt2irq(0x02e0) /* IRQ7A */
 static int ts_get_pendown_state(void)
 {
-	int val1, val2;
+	int val;
 
-	gpio_free(GPIO_FN_IRQ28_123);
-	gpio_free(GPIO_FN_IRQ7_40);
+	gpio_free(GPIO_TSC_IRQ);
 
-	gpio_request(GPIO_PORT123, NULL);
-	gpio_request(GPIO_PORT40, NULL);
+	gpio_request(GPIO_TSC_PORT, NULL);
 
-	gpio_direction_input(GPIO_PORT123);
-	gpio_direction_input(GPIO_PORT40);
+	gpio_direction_input(GPIO_TSC_PORT);
 
-	val1 = gpio_get_value(GPIO_PORT123);
-	val2 = gpio_get_value(GPIO_PORT40);
+	val = gpio_get_value(GPIO_TSC_PORT);
 
-	gpio_request(GPIO_FN_IRQ28_123, NULL);	/* for QHD */
-	gpio_request(GPIO_FN_IRQ7_40, NULL);	/* for WVGA */
+	gpio_request(GPIO_TSC_IRQ, NULL);
 
-	return val1 ^ val2;
+	return !val;
 }
 
-#define PORT40CR	0xE6051028
-#define PORT123CR	0xE605007B
 static int ts_init(void)
 {
-	gpio_request(GPIO_FN_IRQ28_123, NULL);	/* for QHD */
-	gpio_request(GPIO_FN_IRQ7_40, NULL);	/* for WVGA */
-
-	gpio_pull_up(PORT40CR);
-	gpio_pull_up(PORT123CR);
+	gpio_request(GPIO_TSC_IRQ, NULL);
 
 	return 0;
 }
@@ -865,6 +1112,7 @@
 
 #define GPIO_PORT9CR	0xE6051009
 #define GPIO_PORT10CR	0xE605100A
+#define USCCR1		0xE6058144
 static void __init ap4evb_init(void)
 {
 	u32 srcr4;
@@ -935,7 +1183,7 @@
 	/* setup USB phy */
 	__raw_writew(0x8a0a, 0xE6058130);	/* USBCR2 */
 
-	/* enable FSI2 */
+	/* enable FSI2 port A (ak4643) */
 	gpio_request(GPIO_FN_FSIAIBT,	NULL);
 	gpio_request(GPIO_FN_FSIAILR,	NULL);
 	gpio_request(GPIO_FN_FSIAISLD,	NULL);
@@ -948,6 +1196,14 @@
 	gpio_no_direction(GPIO_PORT9CR);  /* FSIAOBT needs no direction */
 	gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
 
+	/* card detect pin for MMC slot (CN7) */
+	gpio_request(GPIO_PORT41, NULL);
+	gpio_direction_input(GPIO_PORT41);
+
+	/* setup FSI2 port B (HDMI) */
+	gpio_request(GPIO_FN_FSIBCK, NULL);
+	__raw_writew(__raw_readw(USCCR1) & ~(1 << 6), USCCR1); /* use SPDIF */
+
 	/* set SPU2 clock to 119.6 MHz */
 	clk = clk_get(NULL, "spu_clk");
 	if (!IS_ERR(clk)) {
@@ -955,14 +1211,6 @@
 		clk_put(clk);
 	}
 
-	/* change parent of FSI A */
-	clk = clk_get(NULL, "fsia_clk");
-	if (!IS_ERR(clk)) {
-		clk_register(&fsiackcr_clk);
-		clk_set_parent(clk, &fsiackcr_clk);
-		clk_put(clk);
-	}
-
 	/*
 	 * set irq priority, to avoid sound chopping
 	 * when NFS rootfs is used
@@ -977,8 +1225,10 @@
 				ARRAY_SIZE(i2c1_devices));
 
 #ifdef CONFIG_AP4EVB_QHD
+
 	/*
-	 * QHD
+	 * For QHD Panel (MIPI-DSI, CONFIG_AP4EVB_QHD=y) and
+	 * IRQ28 for Touch Panel, set dip switches S3, S43 as OFF, ON.
 	 */
 
 	/* enable KEYSC */
@@ -1004,17 +1254,6 @@
 	lcdc_info.ch[0].interface_type		= RGB24;
 	lcdc_info.ch[0].clock_divider		= 1;
 	lcdc_info.ch[0].flags			= LCDC_FLAGS_DWPOL;
-	lcdc_info.ch[0].lcd_cfg.name		= "R63302(QHD)";
-	lcdc_info.ch[0].lcd_cfg.xres		= 544;
-	lcdc_info.ch[0].lcd_cfg.yres		= 961;
-	lcdc_info.ch[0].lcd_cfg.left_margin	= 72;
-	lcdc_info.ch[0].lcd_cfg.right_margin	= 600;
-	lcdc_info.ch[0].lcd_cfg.hsync_len	= 16;
-	lcdc_info.ch[0].lcd_cfg.upper_margin	= 8;
-	lcdc_info.ch[0].lcd_cfg.lower_margin	= 8;
-	lcdc_info.ch[0].lcd_cfg.vsync_len	= 2;
-	lcdc_info.ch[0].lcd_cfg.sync		= FB_SYNC_VERT_HIGH_ACT |
-						  FB_SYNC_HOR_HIGH_ACT;
 	lcdc_info.ch[0].lcd_size_cfg.width	= 44;
 	lcdc_info.ch[0].lcd_size_cfg.height	= 79;
 
@@ -1022,8 +1261,10 @@
 
 #else
 	/*
-	 * WVGA
+	 * For WVGA Panel (18-bit RGB, CONFIG_AP4EVB_WVGA=y) and
+	 * IRQ7 for Touch Panel, set dip switches S3, S43 to ON, OFF.
 	 */
+
 	gpio_request(GPIO_FN_LCDD17,   NULL);
 	gpio_request(GPIO_FN_LCDD16,   NULL);
 	gpio_request(GPIO_FN_LCDD15,   NULL);
@@ -1055,16 +1296,6 @@
 	lcdc_info.ch[0].interface_type		= RGB18;
 	lcdc_info.ch[0].clock_divider		= 2;
 	lcdc_info.ch[0].flags			= 0;
-	lcdc_info.ch[0].lcd_cfg.name		= "WVGA Panel";
-	lcdc_info.ch[0].lcd_cfg.xres		= 800;
-	lcdc_info.ch[0].lcd_cfg.yres		= 480;
-	lcdc_info.ch[0].lcd_cfg.left_margin	= 220;
-	lcdc_info.ch[0].lcd_cfg.right_margin	= 110;
-	lcdc_info.ch[0].lcd_cfg.hsync_len	= 70;
-	lcdc_info.ch[0].lcd_cfg.upper_margin	= 20;
-	lcdc_info.ch[0].lcd_cfg.lower_margin	= 5;
-	lcdc_info.ch[0].lcd_cfg.vsync_len	= 5;
-	lcdc_info.ch[0].lcd_cfg.sync		= 0;
 	lcdc_info.ch[0].lcd_size_cfg.width	= 152;
 	lcdc_info.ch[0].lcd_size_cfg.height	= 91;
 
@@ -1075,6 +1306,23 @@
 	i2c_register_board_info(0, &tsc_device, 1);
 #endif /* CONFIG_AP4EVB_QHD */
 
+	/* CEU */
+
+	/*
+	 * TODO: reserve memory for V4L2 DMA buffers, when a suitable API
+	 * becomes available
+	 */
+
+	/* MIPI-CSI stuff */
+	gpio_request(GPIO_FN_VIO_CKO, NULL);
+
+	clk = clk_get(NULL, "vck1_clk");
+	if (!IS_ERR(clk)) {
+		clk_set_rate(clk, clk_round_rate(clk, 13000000));
+		clk_enable(clk);
+		clk_put(clk);
+	}
+
 	sh7372_add_standard_devices();
 
 	/* HDMI */
@@ -1097,7 +1345,7 @@
 	shmobile_timer.init();
 
 	/* External clock source */
-	clk_set_rate(&dv_clki_clk, 27000000);
+	clk_set_rate(&sh7372_dv_clki_clk, 27000000);
 }
 
 static struct sys_timer ap4evb_timer = {
@@ -1105,8 +1353,6 @@
 };
 
 MACHINE_START(AP4EVB, "ap4evb")
-	.phys_io	= 0xe6000000,
-	.io_pg_offst	= ((0xe6000000) >> 18) & 0xfffc,
 	.map_io		= ap4evb_map_io,
 	.init_irq	= sh7372_init_irq,
 	.init_machine	= ap4evb_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-g3evm.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-g3evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-g3evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-g3evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -365,8 +365,6 @@
 };
 
 MACHINE_START(G3EVM, "g3evm")
-	.phys_io	= 0xe6000000,
-	.io_pg_offst	= ((0xe6000000) >> 18) & 0xfffc,
 	.map_io		= g3evm_map_io,
 	.init_irq	= sh7367_init_irq,
 	.init_machine	= g3evm_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-g4evm.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-g4evm.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/board-g4evm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/board-g4evm.c	2011-01-04 19:50:19.000000000 -0500
@@ -392,8 +392,6 @@
 };
 
 MACHINE_START(G4EVM, "g4evm")
-	.phys_io	= 0xe6000000,
-	.io_pg_offst	= ((0xe6000000) >> 18) & 0xfffc,
 	.map_io		= g4evm_map_io,
 	.init_irq	= sh7377_init_irq,
 	.init_machine	= g4evm_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7367.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7367.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7367.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7367.c	2011-01-04 19:50:19.000000000 -0500
@@ -321,7 +321,7 @@
 	CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */
 	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */
 	CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */
-	CLKDEV_CON_ID("cmt1", &mstp_clks[SYMSTP229]), /* CMT10 */
+	CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[SYMSTP229]), /* CMT10 */
 	CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */
 	CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */
 	CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7372.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7372.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7372.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7372.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,8 +50,11 @@
 #define SMSTPCR3	0xe615013c
 #define SMSTPCR4	0xe6150140
 
+#define FSIDIVA		0xFE1F8000
+#define FSIDIVB		0xFE1F8008
+
 /* Platforms must set frequency on their DV_CLKI pin */
-struct clk dv_clki_clk = {
+struct clk sh7372_dv_clki_clk = {
 };
 
 /* Fixed 32 KHz root clock from EXTALR pin */
@@ -86,9 +89,9 @@
 };
 
 /* Divide dv_clki by two */
-struct clk dv_clki_div2_clk = {
+struct clk sh7372_dv_clki_div2_clk = {
 	.ops		= &div2_clk_ops,
-	.parent		= &dv_clki_clk,
+	.parent		= &sh7372_dv_clki_clk,
 };
 
 /* Divide extal1 by two */
@@ -150,7 +153,7 @@
 static struct clk *pllc2_parent[] = {
 	[0] = &extal1_div2_clk,
 	[1] = &extal2_div2_clk,
-	[2] = &dv_clki_div2_clk,
+	[2] = &sh7372_dv_clki_div2_clk,
 };
 
 /* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */
@@ -217,8 +220,7 @@
 	__raw_writel(__raw_readl(PLLC2CR) & ~0x80000000, PLLC2CR);
 }
 
-static int pllc2_set_rate(struct clk *clk,
-			  unsigned long rate, int algo_id)
+static int pllc2_set_rate(struct clk *clk, unsigned long rate)
 {
 	unsigned long value;
 	int idx;
@@ -227,21 +229,13 @@
 	if (idx < 0)
 		return idx;
 
-	if (rate == clk->parent->rate) {
-		pllc2_disable(clk);
-		return 0;
-	}
+	if (rate == clk->parent->rate)
+		return -EINVAL;
 
 	value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
 
-	if (value & 0x80000000)
-		pllc2_disable(clk);
-
 	__raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
 
-	if (value & 0x80000000)
-		return pllc2_enable(clk);
-
 	return 0;
 }
 
@@ -284,27 +278,37 @@
 	.set_parent	= pllc2_set_parent,
 };
 
-struct clk pllc2_clk = {
+struct clk sh7372_pllc2_clk = {
 	.ops		= &pllc2_clk_ops,
 	.parent		= &extal1_div2_clk,
 	.freq_table	= pllc2_freq_table,
+	.nr_freqs	= ARRAY_SIZE(pllc2_freq_table) - 1,
 	.parent_table	= pllc2_parent,
 	.parent_num	= ARRAY_SIZE(pllc2_parent),
 };
 
+/* External input clock (pin name: FSIACK/FSIBCK ) */
+struct clk sh7372_fsiack_clk = {
+};
+
+struct clk sh7372_fsibck_clk = {
+};
+
 static struct clk *main_clks[] = {
-	&dv_clki_clk,
+	&sh7372_dv_clki_clk,
 	&r_clk,
 	&sh7372_extal1_clk,
 	&sh7372_extal2_clk,
-	&dv_clki_div2_clk,
+	&sh7372_dv_clki_div2_clk,
 	&extal1_div2_clk,
 	&extal2_div2_clk,
 	&extal2_div4_clk,
 	&pllc0_clk,
 	&pllc1_clk,
 	&pllc1_div2_clk,
-	&pllc2_clk,
+	&sh7372_pllc2_clk,
+	&sh7372_fsiack_clk,
+	&sh7372_fsibck_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -357,7 +361,7 @@
 };
 
 enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
-       DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
+       DIV6_SUB, DIV6_SPU,
        DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
        DIV6_NR };
 
@@ -367,8 +371,6 @@
 	[DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
 	[DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0),
 	[DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0),
-	[DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0),
-	[DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0),
 	[DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0),
 	[DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
 	[DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
@@ -377,24 +379,129 @@
 	[DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
 };
 
-enum { DIV6_HDMI, DIV6_REPARENT_NR };
+enum { DIV6_HDMI, DIV6_FSIA, DIV6_FSIB, DIV6_REPARENT_NR };
 
 /* Indices are important - they are the actual src selecting values */
 static struct clk *hdmi_parent[] = {
 	[0] = &pllc1_div2_clk,
-	[1] = &pllc2_clk,
-	[2] = &dv_clki_clk,
+	[1] = &sh7372_pllc2_clk,
+	[2] = &sh7372_dv_clki_clk,
 	[3] = NULL,	/* pllc2_div4 not implemented yet */
 };
 
+static struct clk *fsiackcr_parent[] = {
+	[0] = &pllc1_div2_clk,
+	[1] = &sh7372_pllc2_clk,
+	[2] = &sh7372_fsiack_clk, /* external input for FSI A */
+	[3] = NULL,	/* setting prohibited */
+};
+
+static struct clk *fsibckcr_parent[] = {
+	[0] = &pllc1_div2_clk,
+	[1] = &sh7372_pllc2_clk,
+	[2] = &sh7372_fsibck_clk, /* external input for FSI B */
+	[3] = NULL,	/* setting prohibited */
+};
+
 static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
 	[DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0,
 				      hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
+	[DIV6_FSIA] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIACKCR, 0,
+				      fsiackcr_parent, ARRAY_SIZE(fsiackcr_parent), 6, 2),
+	[DIV6_FSIB] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIBCKCR, 0,
+				      fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
+};
+
+/* FSI DIV */
+static unsigned long fsidiv_recalc(struct clk *clk)
+{
+	unsigned long value;
+
+	value = __raw_readl(clk->mapping->base);
+
+	if ((value & 0x3) != 0x3)
+		return 0;
+
+	value >>= 16;
+	if (value < 2)
+		return 0;
+
+	return clk->parent->rate / value;
+}
+
+static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
+{
+	return clk_rate_div_range_round(clk, 2, 0xffff, rate);
+}
+
+static void fsidiv_disable(struct clk *clk)
+{
+	__raw_writel(0, clk->mapping->base);
+}
+
+static int fsidiv_enable(struct clk *clk)
+{
+	unsigned long value;
+
+	value  = __raw_readl(clk->mapping->base) >> 16;
+	if (value < 2)
+		return -EIO;
+
+	__raw_writel((value << 16) | 0x3, clk->mapping->base);
+
+	return 0;
+}
+
+static int fsidiv_set_rate(struct clk *clk, unsigned long rate)
+{
+	int idx;
+
+	idx = (clk->parent->rate / rate) & 0xffff;
+	if (idx < 2)
+		return -EINVAL;
+
+	__raw_writel(idx << 16, clk->mapping->base);
+	return 0;
+}
+
+static struct clk_ops fsidiv_clk_ops = {
+	.recalc		= fsidiv_recalc,
+	.round_rate	= fsidiv_round_rate,
+	.set_rate	= fsidiv_set_rate,
+	.enable		= fsidiv_enable,
+	.disable	= fsidiv_disable,
+};
+
+static struct clk_mapping sh7372_fsidiva_clk_mapping = {
+	.phys	= FSIDIVA,
+	.len	= 8,
+};
+
+struct clk sh7372_fsidiva_clk = {
+	.ops		= &fsidiv_clk_ops,
+	.parent		= &div6_reparent_clks[DIV6_FSIA], /* late install */
+	.mapping	= &sh7372_fsidiva_clk_mapping,
+};
+
+static struct clk_mapping sh7372_fsidivb_clk_mapping = {
+	.phys	= FSIDIVB,
+	.len	= 8,
+};
+
+struct clk sh7372_fsidivb_clk = {
+	.ops		= &fsidiv_clk_ops,
+	.parent		= &div6_reparent_clks[DIV6_FSIB],  /* late install */
+	.mapping	= &sh7372_fsidivb_clk_mapping,
+};
+
+static struct clk *late_main_clks[] = {
+	&sh7372_fsidiva_clk,
+	&sh7372_fsidivb_clk,
 };
 
 enum { MSTP001,
        MSTP131, MSTP130,
-       MSTP129, MSTP128, MSTP127, MSTP126,
+       MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
        MSTP118, MSTP117, MSTP116,
        MSTP106, MSTP101, MSTP100,
        MSTP223,
@@ -414,6 +521,7 @@
 	[MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */
 	[MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */
 	[MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */
+	[MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */
 	[MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */
 	[MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
 	[MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
@@ -429,7 +537,7 @@
 	[MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
 	[MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
 	[MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
-	[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSIA */
+	[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
 	[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
 	[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
 	[MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
@@ -445,10 +553,11 @@
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+#define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
 	/* main clocks */
-	CLKDEV_CON_ID("dv_clki_div2_clk", &dv_clki_div2_clk),
+	CLKDEV_CON_ID("dv_clki_div2_clk", &sh7372_dv_clki_div2_clk),
 	CLKDEV_CON_ID("r_clk", &r_clk),
 	CLKDEV_CON_ID("extal1", &sh7372_extal1_clk),
 	CLKDEV_CON_ID("extal2", &sh7372_extal2_clk),
@@ -458,7 +567,7 @@
 	CLKDEV_CON_ID("pllc0_clk", &pllc0_clk),
 	CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
 	CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
-	CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
+	CLKDEV_CON_ID("pllc2_clk", &sh7372_pllc2_clk),
 
 	/* DIV4 clocks */
 	CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
@@ -483,8 +592,6 @@
 	CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
 	CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
 	CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
-	CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]),
-	CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]),
 	CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
 	CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
 	CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
@@ -501,6 +608,8 @@
 	CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */
 	CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */
 	CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */
+	CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */
+	CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */
 	CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
 	CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */
 	CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
@@ -516,11 +625,11 @@
 	CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
 	CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
 	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
-	CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
+	CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
 	CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
 	CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
-	CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */
-	CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */
+	CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
+	CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
 	CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
 	CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
@@ -531,7 +640,10 @@
 	CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
 	CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
 	CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
-	{.con_id = "ick", .dev_id = "sh-mobile-hdmi", .clk = &div6_reparent_clks[DIV6_HDMI]},
+
+	CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
+	CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]),
+	CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]),
 };
 
 void __init sh7372_clock_init(void)
@@ -548,11 +660,14 @@
 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
 	if (!ret)
-		ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_NR);
+		ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
 
 	if (!ret)
 		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
+	for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+		ret = clk_register(late_main_clks[k]);
+
 	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
 	if (!ret)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7377.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7377.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/clock-sh7377.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/clock-sh7377.c	2011-01-04 19:50:19.000000000 -0500
@@ -333,7 +333,7 @@
 	CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
 	CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
 	CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
-	CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
+	CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
 	CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */
 	CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
 	CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/entry-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/entry-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/entry-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/entry-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2010 Magnus Damm
  * Copyright (C) 2008 Renesas Solutions Corp.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -14,24 +15,45 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
-#include <mach/hardware.h>
 #include <mach/irqs.h>
 
+#define INTCA_BASE	0xe6980000
+#define INTFLGA_OFFS	0x00000018 /* accept pending interrupt */
+#define INTEVTA_OFFS	0x00000020 /* vector number of accepted interrupt */
+#define INTLVLA_OFFS	0x00000030 /* priority level of accepted interrupt */
+#define INTLVLB_OFFS	0x00000034 /* previous priority level */
+
 	.macro  disable_fiq
 	.endm
 
 	.macro  get_irqnr_preamble, base, tmp
-	ldr     \base, =INTFLGA
+	ldr     \base, =INTCA_BASE
 	.endm
 
 	.macro  arch_ret_to_user, tmp1, tmp2
 	.endm
 
 	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-	ldr     \irqnr, [\base]
+	/* The single INTFLGA read access below results in the following:
+	 *
+	 * 1. INTLVLB is updated with old priority value from INTLVLA
+	 * 2. Highest priority interrupt is accepted
+	 * 3. INTLVLA is updated to contain priority of accepted interrupt
+	 * 4. Accepted interrupt vector is stored in INTFLGA and INTEVTA
+	 */
+	ldr     \irqnr, [\base, #INTFLGA_OFFS]
+
+	/* Restore INTLVLA with the value saved in INTLVLB.
+	 * This is required to support interrupt priorities properly.
+	 */
+	ldrb	\tmp, [\base, #INTLVLB_OFFS]
+	strb    \tmp, [\base, #INTLVLA_OFFS]
+
+	/* Handle invalid vector number case */
 	cmp	\irqnr, #0
 	beq	1000f
-	/* intevt to irq number */
+
+	/* Convert vector to irq number, same as the evt2irq() macro */
 	lsr	\irqnr, \irqnr, #0x5
 	subs	\irqnr, \irqnr, #16
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,12 +35,12 @@
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-	return -ENOSYS;
+	return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-	return -EINVAL;
+	return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/sh7372.h linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/sh7372.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/sh7372.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/sh7372.h	2011-01-04 19:50:19.000000000 -0500
@@ -457,8 +457,14 @@
 	SHDMA_SLAVE_SDHI2_TX,
 };
 
-extern struct clk dv_clki_clk;
-extern struct clk dv_clki_div2_clk;
-extern struct clk pllc2_clk;
+extern struct clk sh7372_extal1_clk;
+extern struct clk sh7372_extal2_clk;
+extern struct clk sh7372_dv_clki_clk;
+extern struct clk sh7372_dv_clki_div2_clk;
+extern struct clk sh7372_pllc2_clk;
+extern struct clk sh7372_fsiack_clk;
+extern struct clk sh7372_fsibck_clk;
+extern struct clk sh7372_fsidiva_clk;
+extern struct clk sh7372_fsidivb_clk;
 
 #endif /* __ASM_SH7372_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,6 @@
 #define __ASM_MACH_VMALLOC_H
 
 /* Vmalloc at ... - 0xe5ffffff */
-#define VMALLOC_END 0xe6000000
+#define VMALLOC_END 0xe6000000UL
 
 #endif /* __ASM_MACH_VMALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/intc-sh7372.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/intc-sh7372.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/intc-sh7372.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/intc-sh7372.c	2011-01-04 19:50:19.000000000 -0500
@@ -98,7 +98,7 @@
 	INTC_VECT(IRQ14A, 0x03c0), INTC_VECT(IRQ15A, 0x03e0),
 	INTC_VECT(IRQ16A, 0x3200), INTC_VECT(IRQ17A, 0x3220),
 	INTC_VECT(IRQ18A, 0x3240), INTC_VECT(IRQ19A, 0x3260),
-	INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ31A, 0x32a0),
+	INTC_VECT(IRQ20A, 0x3280), INTC_VECT(IRQ21A, 0x32a0),
 	INTC_VECT(IRQ22A, 0x32c0), INTC_VECT(IRQ23A, 0x32e0),
 	INTC_VECT(IRQ24A, 0x3300), INTC_VECT(IRQ25A, 0x3320),
 	INTC_VECT(IRQ26A, 0x3340), INTC_VECT(IRQ27A, 0x3360),
@@ -369,9 +369,13 @@
 	INTCS,
 
 	/* interrupt sources INTCS */
+
+	/* IRQ0S - IRQ31S */
 	VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3,
 	RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3,
 	CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2,
+	/* MFI */
+	/* BBIF2 */
 	VPU,
 	TSIF1,
 	_3DG_SGX530,
@@ -379,13 +383,17 @@
 	IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
 	IPMMU_IPMMUR, IPMMU_IPMMUR2,
 	RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR,
+	/* KEYSC */
+	/* TTI20 */
 	MSIOF,
 	IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0,
 	TMU_TUNI0, TMU_TUNI1, TMU_TUNI2,
 	CMT0,
 	TSIF0,
+	/* CMT2 */
 	LMB,
 	CTI,
+	/* RWDT0 */
 	ICB,
 	JPU_JPEG,
 	LCDC,
@@ -397,11 +405,17 @@
 	CSIRX,
 	DSITX_DSITX0,
 	DSITX_DSITX1,
+	/* SPU2 */
+	/* FSI */
+	/* FMSI */
+	/* HDMI */
 	TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2,
 	CMT4,
 	DSITX1_DSITX1_0,
 	DSITX1_DSITX1_1,
+	/* MFIS2 */
 	CPORTS2R,
+	/* CEC */
 	JPU6E,
 
 	/* interrupt groups INTCS */
@@ -410,12 +424,15 @@
 };
 
 static struct intc_vect intcs_vectors[] = {
+	/* IRQ0S - IRQ31S */
 	INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720),
 	INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760),
 	INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820),
 	INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860),
 	INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0),
 	INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0),
+	/* MFI */
+	/* BBIF2 */
 	INTCS_VECT(VPU, 0x980),
 	INTCS_VECT(TSIF1, 0x9a0),
 	INTCS_VECT(_3DG_SGX530, 0x9e0),
@@ -425,14 +442,19 @@
 	INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20),
 	INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0),
 	INTCS_VECT(RTDMAC_2_DADERR, 0xbc0),
+	/* KEYSC */
+	/* TTI20 */
+	INTCS_VECT(MSIOF, 0x0d20),
 	INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20),
 	INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60),
 	INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0),
 	INTCS_VECT(TMU_TUNI2, 0xec0),
 	INTCS_VECT(CMT0, 0xf00),
 	INTCS_VECT(TSIF0, 0xf20),
+	/* CMT2 */
 	INTCS_VECT(LMB, 0xf60),
 	INTCS_VECT(CTI, 0x400),
+	/* RWDT0 */
 	INTCS_VECT(ICB, 0x480),
 	INTCS_VECT(JPU_JPEG, 0x560),
 	INTCS_VECT(LCDC, 0x580),
@@ -446,12 +468,18 @@
 	INTCS_VECT(CSIRX, 0x17a0),
 	INTCS_VECT(DSITX_DSITX0, 0x17c0),
 	INTCS_VECT(DSITX_DSITX1, 0x17e0),
+	/* SPU2 */
+	/* FSI */
+	/* FMSI */
+	/* HDMI */
 	INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920),
 	INTCS_VECT(TMU1_TUNI2, 0x1940),
 	INTCS_VECT(CMT4, 0x1980),
 	INTCS_VECT(DSITX1_DSITX1_0, 0x19a0),
 	INTCS_VECT(DSITX1_DSITX1_1, 0x19c0),
+	/* MFIS2 */
 	INTCS_VECT(CPORTS2R, 0x1a20),
+	/* CEC */
 	INTCS_VECT(JPU6E, 0x1a80),
 
 	INTC_VECT(INTCS, 0xf80),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -116,4 +116,6 @@
 config SH_CLK_CPG
 	bool
 
+source "drivers/sh/Kconfig"
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/pfc-sh7372.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/pfc-sh7372.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/pfc-sh7372.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/pfc-sh7372.c	2011-01-04 19:50:19.000000000 -0500
@@ -166,12 +166,12 @@
 	MSIOF2_TSYNC_MARK,	MSIOF2_TSCK_MARK,	MSIOF2_RXD_MARK,
 	MSIOF2_TXD_MARK,
 
-	/* MSIOF3 */
+	/* BBIF1 */
 	BBIF1_RXD_MARK,		BBIF1_TSYNC_MARK,	BBIF1_TSCK_MARK,
 	BBIF1_TXD_MARK,		BBIF1_RSCK_MARK,	BBIF1_RSYNC_MARK,
 	BBIF1_FLOW_MARK,	BB_RX_FLOW_N_MARK,
 
-	/* MSIOF4 */
+	/* BBIF2 */
 	BBIF2_TSCK1_MARK,	BBIF2_TSYNC1_MARK,
 	BBIF2_TXD1_MARK,	BBIF2_RXD_MARK,
 
@@ -976,12 +976,12 @@
 	GPIO_FN(MSIOF2_TSYNC),	GPIO_FN(MSIOF2_TSCK),	GPIO_FN(MSIOF2_RXD),
 	GPIO_FN(MSIOF2_TXD),
 
-	/* MSIOF3 */
+	/* BBIF1 */
 	GPIO_FN(BBIF1_RXD),	GPIO_FN(BBIF1_TSYNC),	GPIO_FN(BBIF1_TSCK),
 	GPIO_FN(BBIF1_TXD),	GPIO_FN(BBIF1_RSCK),	GPIO_FN(BBIF1_RSYNC),
 	GPIO_FN(BBIF1_FLOW),	GPIO_FN(BB_RX_FLOW_N),
 
-	/* MSIOF4 */
+	/* BBIF2 */
 	GPIO_FN(BBIF2_TSCK1),	GPIO_FN(BBIF2_TSYNC1),
 	GPIO_FN(BBIF2_TXD1),	GPIO_FN(BBIF2_RXD),
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7367.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7367.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7367.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7367.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,7 +154,6 @@
 	.name = "CMT10",
 	.channel_offset = 0x10,
 	.timer_bit = 0,
-	.clk = "r_clk",
 	.clockevent_rating = 125,
 	.clocksource_rating = 125,
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7372.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7372.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7372.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7372.c	2011-01-04 19:50:19.000000000 -0500
@@ -158,7 +158,6 @@
 	.name = "CMT10",
 	.channel_offset = 0x10,
 	.timer_bit = 0,
-	.clk = "cmt1",
 	.clockevent_rating = 125,
 	.clocksource_rating = 125,
 };
@@ -186,6 +185,67 @@
 	.num_resources	= ARRAY_SIZE(cmt10_resources),
 };
 
+/* TMU */
+static struct sh_timer_config tmu00_platform_data = {
+	.name = "TMU00",
+	.channel_offset = 0x4,
+	.timer_bit = 0,
+	.clockevent_rating = 200,
+};
+
+static struct resource tmu00_resources[] = {
+	[0] = {
+		.name	= "TMU00",
+		.start	= 0xfff60008,
+		.end	= 0xfff60013,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0xe80), /* TMU_TUNI0 */
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu00_device = {
+	.name		= "sh_tmu",
+	.id		= 0,
+	.dev = {
+		.platform_data	= &tmu00_platform_data,
+	},
+	.resource	= tmu00_resources,
+	.num_resources	= ARRAY_SIZE(tmu00_resources),
+};
+
+static struct sh_timer_config tmu01_platform_data = {
+	.name = "TMU01",
+	.channel_offset = 0x10,
+	.timer_bit = 1,
+	.clocksource_rating = 200,
+};
+
+static struct resource tmu01_resources[] = {
+	[0] = {
+		.name	= "TMU01",
+		.start	= 0xfff60014,
+		.end	= 0xfff6001f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= intcs_evt2irq(0xea0), /* TMU_TUNI1 */
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tmu01_device = {
+	.name		= "sh_tmu",
+	.id		= 1,
+	.dev = {
+		.platform_data	= &tmu01_platform_data,
+	},
+	.resource	= tmu01_resources,
+	.num_resources	= ARRAY_SIZE(tmu01_resources),
+};
+
 /* I2C */
 static struct resource iic0_resources[] = {
 	[0] = {
@@ -419,14 +479,14 @@
 	},
 	{
 		/* DMA error IRQ */
-		.start	= 246,
-		.end	= 246,
+		.start	= evt2irq(0x20c0),
+		.end	= evt2irq(0x20c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-5 */
-		.start	= 240,
-		.end	= 245,
+		.start	= evt2irq(0x2000),
+		.end	= evt2irq(0x20a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -447,14 +507,14 @@
 	},
 	{
 		/* DMA error IRQ */
-		.start	= 254,
-		.end	= 254,
+		.start	= evt2irq(0x21c0),
+		.end	= evt2irq(0x21c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-5 */
-		.start	= 248,
-		.end	= 253,
+		.start	= evt2irq(0x2100),
+		.end	= evt2irq(0x21a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -475,14 +535,14 @@
 	},
 	{
 		/* DMA error IRQ */
-		.start	= 262,
-		.end	= 262,
+		.start	= evt2irq(0x22c0),
+		.end	= evt2irq(0x22c0),
 		.flags	= IORESOURCE_IRQ,
 	},
 	{
 		/* IRQ for channels 0-5 */
-		.start	= 256,
-		.end	= 261,
+		.start	= evt2irq(0x2200),
+		.end	= evt2irq(0x22a0),
 		.flags	= IORESOURCE_IRQ,
 	},
 };
@@ -526,6 +586,11 @@
 	&scif5_device,
 	&scif6_device,
 	&cmt10_device,
+	&tmu00_device,
+	&tmu01_device,
+};
+
+static struct platform_device *sh7372_late_devices[] __initdata = {
 	&iic0_device,
 	&iic1_device,
 	&dma0_device,
@@ -537,6 +602,9 @@
 {
 	platform_add_devices(sh7372_early_devices,
 			    ARRAY_SIZE(sh7372_early_devices));
+
+	platform_add_devices(sh7372_late_devices,
+			    ARRAY_SIZE(sh7372_late_devices));
 }
 
 void __init sh7372_add_early_devices(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7377.c linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7377.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-shmobile/setup-sh7377.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-shmobile/setup-sh7377.c	2011-01-04 19:50:19.000000000 -0500
@@ -172,7 +172,6 @@
 	.name = "CMT10",
 	.channel_offset = 0x10,
 	.timer_bit = 0,
-	.clk = "r_clk",
 	.clockevent_rating = 125,
 	.clocksource_rating = 125,
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-stmp378x/stmp378x_devb.c linux-libre-2.6.37-gnu/arch/arm/mach-stmp378x/stmp378x_devb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-stmp378x/stmp378x_devb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-stmp378x/stmp378x_devb.c	2011-01-04 19:50:19.000000000 -0500
@@ -324,8 +324,6 @@
 }
 
 MACHINE_START(STMP378X, "STMP378X")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x40000100,
 	.map_io		= stmp378x_map_io,
 	.init_irq	= stmp378x_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-stmp37xx/stmp37xx_devb.c linux-libre-2.6.37-gnu/arch/arm/mach-stmp37xx/stmp37xx_devb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-stmp37xx/stmp37xx_devb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-stmp37xx/stmp37xx_devb.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,8 +91,6 @@
 }
 
 MACHINE_START(STMP37XX, "STMP37XX")
-	.phys_io	= 0x80000000,
-	.io_pg_offst	= ((0xf0000000) >> 18) & 0xfffc,
 	.boot_params	= 0x40000100,
 	.map_io		= stmp37xx_map_io,
 	.init_irq	= stmp37xx_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/board-tcc8000-sdk.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/board-tcc8000-sdk.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/board-tcc8000-sdk.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/board-tcc8000-sdk.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/clock.h>
+
+#include "common.h"
+
+#define XI_FREQUENCY	12000000
+#define XTI_FREQUENCY	32768
+
+#ifdef CONFIG_MTD_NAND_TCC
+/* NAND */
+static struct tcc_nand_platform_data tcc8k_sdk_nand_data = {
+	.width = 1,
+	.hw_ecc = 0,
+};
+#endif
+
+static void __init tcc8k_init(void)
+{
+#ifdef CONFIG_MTD_NAND_TCC
+	tcc_nand_device.dev.platform_data = &tcc8k_sdk_nand_data;
+	platform_device_register(&tcc_nand_device);
+#endif
+}
+
+static void __init tcc8k_init_timer(void)
+{
+	tcc_clocks_init(XI_FREQUENCY, XTI_FREQUENCY);
+}
+
+static struct sys_timer tcc8k_timer = {
+	.init	= tcc8k_init_timer,
+};
+
+static void __init tcc8k_map_io(void)
+{
+	tcc8k_map_common_io();
+}
+
+MACHINE_START(TCC8000_SDK, "Telechips TCC8000-SDK Demo Board")
+	.boot_params	= PHYS_OFFSET + 0x00000100,
+	.map_io		= tcc8k_map_io,
+	.init_irq	= tcc8k_init_irq,
+	.init_machine	= tcc8k_init,
+	.timer		= &tcc8k_timer,
+MACHINE_END
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/clock.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,567 @@
+/*
+ * Lowlevel clock handling for Telechips TCC8xxx SoCs
+ *
+ * Copyright (C) 2010 by Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/clock.h>
+#include <mach/irqs.h>
+#include <mach/tcc8k-regs.h>
+
+#include "common.h"
+
+#define BCLKCTR0	(CKC_BASE + BCLKCTR0_OFFS)
+#define BCLKCTR1	(CKC_BASE + BCLKCTR1_OFFS)
+
+#define ACLKREF		(CKC_BASE + ACLKREF_OFFS)
+#define ACLKUART0	(CKC_BASE + ACLKUART0_OFFS)
+#define ACLKUART1	(CKC_BASE + ACLKUART1_OFFS)
+#define ACLKUART2	(CKC_BASE + ACLKUART2_OFFS)
+#define ACLKUART3	(CKC_BASE + ACLKUART3_OFFS)
+#define ACLKUART4	(CKC_BASE + ACLKUART4_OFFS)
+#define ACLKI2C		(CKC_BASE + ACLKI2C_OFFS)
+#define ACLKADC		(CKC_BASE + ACLKADC_OFFS)
+#define ACLKUSBH	(CKC_BASE + ACLKUSBH_OFFS)
+#define ACLKLCD		(CKC_BASE + ACLKLCD_OFFS)
+#define ACLKSDH0	(CKC_BASE + ACLKSDH0_OFFS)
+#define ACLKSDH1	(CKC_BASE + ACLKSDH1_OFFS)
+#define ACLKSPI0	(CKC_BASE + ACLKSPI0_OFFS)
+#define ACLKSPI1	(CKC_BASE + ACLKSPI1_OFFS)
+#define ACLKSPDIF	(CKC_BASE + ACLKSPDIF_OFFS)
+#define ACLKC3DEC	(CKC_BASE + ACLKC3DEC_OFFS)
+#define ACLKCAN0	(CKC_BASE + ACLKCAN0_OFFS)
+#define ACLKCAN1	(CKC_BASE + ACLKCAN1_OFFS)
+#define ACLKGSB0	(CKC_BASE + ACLKGSB0_OFFS)
+#define ACLKGSB1	(CKC_BASE + ACLKGSB1_OFFS)
+#define ACLKGSB2	(CKC_BASE + ACLKGSB2_OFFS)
+#define ACLKGSB3	(CKC_BASE + ACLKGSB3_OFFS)
+#define ACLKUSBH	(CKC_BASE + ACLKUSBH_OFFS)
+#define ACLKTCT		(CKC_BASE + ACLKTCT_OFFS)
+#define ACLKTCX		(CKC_BASE + ACLKTCX_OFFS)
+#define ACLKTCZ		(CKC_BASE + ACLKTCZ_OFFS)
+
+/* Crystal frequencies */
+static unsigned long xi_rate, xti_rate;
+
+static void __iomem *pll_cfg_addr(int pll)
+{
+	switch (pll) {
+	case 0: return (CKC_BASE + PLL0CFG_OFFS);
+	case 1: return (CKC_BASE + PLL1CFG_OFFS);
+	case 2: return (CKC_BASE + PLL2CFG_OFFS);
+	default:
+		BUG();
+	}
+}
+
+static int pll_enable(int pll, int enable)
+{
+	u32 reg;
+	void __iomem *addr = pll_cfg_addr(pll);
+
+	reg = __raw_readl(addr);
+	if (enable)
+		reg &= ~PLLxCFG_PD;
+	else
+		reg |= PLLxCFG_PD;
+
+	__raw_writel(reg, addr);
+	return 0;
+}
+
+static int xi_enable(int enable)
+{
+	u32 reg;
+
+	reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS);
+	if (enable)
+		reg |= CLKCTRL_XE;
+	else
+		reg &= ~CLKCTRL_XE;
+
+	__raw_writel(reg, CKC_BASE + CLKCTRL_OFFS);
+	return 0;
+}
+
+static int root_clk_enable(enum root_clks src)
+{
+	switch (src) {
+	case CLK_SRC_PLL0: return pll_enable(0, 1);
+	case CLK_SRC_PLL1: return pll_enable(1, 1);
+	case CLK_SRC_PLL2: return pll_enable(2, 1);
+	case CLK_SRC_XI: return xi_enable(1);
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+static int root_clk_disable(enum root_clks root_src)
+{
+	switch (root_src) {
+	case CLK_SRC_PLL0: return pll_enable(0, 0);
+	case CLK_SRC_PLL1: return pll_enable(1, 0);
+	case CLK_SRC_PLL2: return pll_enable(2, 0);
+	case CLK_SRC_XI: return xi_enable(0);
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+static int enable_clk(struct clk *clk)
+{
+	u32 reg;
+
+	if (clk->root_id != CLK_SRC_NOROOT)
+		return root_clk_enable(clk->root_id);
+
+	if (clk->aclkreg) {
+		reg = __raw_readl(clk->aclkreg);
+		reg |= ACLK_EN;
+		__raw_writel(reg, clk->aclkreg);
+	}
+	if (clk->bclkctr) {
+		reg = __raw_readl(clk->bclkctr);
+		reg |= 1 << clk->bclk_shift;
+		__raw_writel(reg, clk->bclkctr);
+	}
+	return 0;
+}
+
+static void disable_clk(struct clk *clk)
+{
+	u32 reg;
+
+	if (clk->root_id != CLK_SRC_NOROOT) {
+		root_clk_disable(clk->root_id);
+		return;
+	}
+
+	if (clk->bclkctr) {
+		reg = __raw_readl(clk->bclkctr);
+		reg &= ~(1 << clk->bclk_shift);
+		__raw_writel(reg, clk->bclkctr);
+	}
+	if (clk->aclkreg) {
+		reg = __raw_readl(clk->aclkreg);
+		reg &= ~ACLK_EN;
+		__raw_writel(reg, clk->aclkreg);
+	}
+}
+
+static unsigned long get_rate_pll(int pll)
+{
+	u32 reg;
+	unsigned long s, m, p;
+	void __iomem *addr = pll_cfg_addr(pll);
+
+	reg = __raw_readl(addr);
+	s = (reg >> 16) & 0x07;
+	m = (reg >> 8) & 0xff;
+	p = reg & 0x3f;
+
+	return (m * xi_rate) / (p * (1 << s));
+}
+
+static unsigned long get_rate_pll_div(int pll)
+{
+	u32 reg;
+	unsigned long div = 0;
+	void __iomem *addr;
+
+	switch (pll) {
+	case 0:
+		addr = CKC_BASE + CLKDIVC0_OFFS;
+		reg = __raw_readl(addr);
+		if (reg & CLKDIVC0_P0E)
+			div = (reg >> 24) & 0x3f;
+		break;
+	case 1:
+		addr = CKC_BASE + CLKDIVC0_OFFS;
+		reg = __raw_readl(addr);
+		if (reg & CLKDIVC0_P1E)
+			div = (reg >> 16) & 0x3f;
+		break;
+	case 2:
+		addr = CKC_BASE + CLKDIVC1_OFFS;
+		reg = __raw_readl(addr);
+		if (reg & CLKDIVC1_P2E)
+			div = __raw_readl(addr) & 0x3f;
+		break;
+	}
+	return get_rate_pll(pll) / (div + 1);
+}
+
+static unsigned long get_rate_xi_div(void)
+{
+	unsigned long div = 0;
+	u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS);
+
+	if (reg & CLKDIVC0_XE)
+		div = (reg >> 8) & 0x3f;
+
+	return xi_rate / (div + 1);
+}
+
+static unsigned long get_rate_xti_div(void)
+{
+	unsigned long div = 0;
+	u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS);
+
+	if (reg & CLKDIVC0_XTE)
+		div = reg & 0x3f;
+
+	return xti_rate / (div + 1);
+}
+
+static unsigned long root_clk_get_rate(enum root_clks src)
+{
+	switch (src) {
+	case CLK_SRC_PLL0: return get_rate_pll(0);
+	case CLK_SRC_PLL1: return get_rate_pll(1);
+	case CLK_SRC_PLL2: return get_rate_pll(2);
+	case CLK_SRC_PLL0DIV: return get_rate_pll_div(0);
+	case CLK_SRC_PLL1DIV: return get_rate_pll_div(1);
+	case CLK_SRC_PLL2DIV: return get_rate_pll_div(2);
+	case CLK_SRC_XI: return xi_rate;
+	case CLK_SRC_XTI: return xti_rate;
+	case CLK_SRC_XIDIV: return get_rate_xi_div();
+	case CLK_SRC_XTIDIV: return get_rate_xti_div();
+	default: return 0;
+	}
+}
+
+static unsigned long aclk_get_rate(struct clk *clk)
+{
+	u32 reg;
+	unsigned long div;
+	unsigned int src;
+
+	reg = __raw_readl(clk->aclkreg);
+	div = reg & 0x0fff;
+	src = (reg >> ACLK_SEL_SHIFT) & CLK_SRC_MASK;
+	return root_clk_get_rate(src) / (div + 1);
+}
+
+static unsigned long aclk_best_div(struct clk *clk, unsigned long rate)
+{
+	unsigned long div, src, freq, r1, r2;
+
+	src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+	src &= CLK_SRC_MASK;
+	freq = root_clk_get_rate(src);
+	div = freq / rate + 1;
+	r1 = freq / div;
+	r2 = freq / (div + 1);
+	if (r2 >= rate)
+		return div + 1;
+	if ((rate - r2) < (r1 - rate))
+		return div + 1;
+
+	return div;
+}
+
+static unsigned long aclk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned int src;
+
+	src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+	src &= CLK_SRC_MASK;
+
+	return root_clk_get_rate(src) / aclk_best_div(clk, rate);
+}
+
+static int aclk_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 reg;
+
+	reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK;
+	reg |= aclk_best_div(clk, rate);
+	return 0;
+}
+
+static unsigned long get_rate_sys(struct clk *clk)
+{
+	unsigned int src;
+
+	src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK;
+		return root_clk_get_rate(src);
+}
+
+static unsigned long get_rate_bus(struct clk *clk)
+{
+	unsigned int div;
+
+	div = (__raw_readl(CKC_BASE + CLKCTRL_OFFS) >> 4) & 0xff;
+	return get_rate_sys(clk) / (div + 1);
+}
+
+static unsigned long get_rate_cpu(struct clk *clk)
+{
+	unsigned int reg, div, fsys, fbus;
+
+	fbus = get_rate_bus(clk);
+	reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS);
+	if (reg & (1 << 29))
+		return fbus;
+	fsys = get_rate_sys(clk);
+	div = (reg >> 16) & 0x0f;
+	return fbus + ((fsys - fbus) * (div + 1)) / 16;
+}
+
+static unsigned long get_rate_root(struct clk *clk)
+{
+	return root_clk_get_rate(clk->root_id);
+}
+
+static int aclk_set_parent(struct clk *clock, struct clk *parent)
+{
+	u32 reg;
+
+	if (clock->parent == parent)
+		return 0;
+
+	clock->parent = parent;
+
+	if (!parent)
+		return 0;
+
+	if (parent->root_id == CLK_SRC_NOROOT)
+		return 0;
+	reg = __raw_readl(clock->aclkreg);
+	reg &= ~ACLK_SEL_MASK;
+	reg |= (parent->root_id << ACLK_SEL_SHIFT) & ACLK_SEL_MASK;
+	__raw_writel(reg, clock->aclkreg);
+
+	return 0;
+}
+
+#define DEFINE_ROOT_CLOCK(name, ri, p)	\
+	static struct clk name = {		\
+		.root_id = ri,			\
+		.get_rate = get_rate_root,			\
+		.enable = enable_clk,		\
+		.disable = disable_clk,		\
+		.parent = p,			\
+	};
+
+#define DEFINE_SPECIAL_CLOCK(name, gr, p)	\
+	static struct clk name = {		\
+		.root_id = CLK_SRC_NOROOT,	\
+		.get_rate = gr,			\
+		.parent = p,			\
+	};
+
+#define DEFINE_ACLOCK(name, bc, bs, ar)		\
+	static struct clk name = {		\
+		.root_id = CLK_SRC_NOROOT,	\
+		.bclkctr = bc,			\
+		.bclk_shift = bs,		\
+		.aclkreg = ar,			\
+		.get_rate = aclk_get_rate,	\
+		.set_rate = aclk_set_rate,	\
+		.round_rate = aclk_round_rate,	\
+		.enable = enable_clk,		\
+		.disable = disable_clk,		\
+		.set_parent = aclk_set_parent,	\
+	};
+
+#define DEFINE_BCLOCK(name, bc, bs, gr, p)	\
+	static struct clk name = {		\
+		.root_id = CLK_SRC_NOROOT,	\
+		.bclkctr = bc,			\
+		.bclk_shift = bs,		\
+		.get_rate = gr,			\
+		.enable = enable_clk,		\
+		.disable = disable_clk,		\
+		.parent = p,			\
+	};
+
+DEFINE_ROOT_CLOCK(xi, CLK_SRC_XI, NULL)
+DEFINE_ROOT_CLOCK(xti, CLK_SRC_XTI, NULL)
+DEFINE_ROOT_CLOCK(xidiv, CLK_SRC_XIDIV, &xi)
+DEFINE_ROOT_CLOCK(xtidiv, CLK_SRC_XTIDIV, &xti)
+DEFINE_ROOT_CLOCK(pll0, CLK_SRC_PLL0, &xi)
+DEFINE_ROOT_CLOCK(pll1, CLK_SRC_PLL1, &xi)
+DEFINE_ROOT_CLOCK(pll2, CLK_SRC_PLL2, &xi)
+DEFINE_ROOT_CLOCK(pll0div, CLK_SRC_PLL0DIV, &pll0)
+DEFINE_ROOT_CLOCK(pll1div, CLK_SRC_PLL1DIV, &pll1)
+DEFINE_ROOT_CLOCK(pll2div, CLK_SRC_PLL2DIV, &pll2)
+
+/* The following 3 clocks are special and are initialized explicitly later */
+DEFINE_SPECIAL_CLOCK(sys, get_rate_sys, NULL)
+DEFINE_SPECIAL_CLOCK(bus, get_rate_bus, &sys)
+DEFINE_SPECIAL_CLOCK(cpu, get_rate_cpu, &sys)
+
+DEFINE_ACLOCK(tct, NULL, 0, ACLKTCT)
+DEFINE_ACLOCK(tcx, NULL, 0, ACLKTCX)
+DEFINE_ACLOCK(tcz, NULL, 0, ACLKTCZ)
+DEFINE_ACLOCK(ref, NULL, 0, ACLKREF)
+DEFINE_ACLOCK(uart0, BCLKCTR0, 5, ACLKUART0)
+DEFINE_ACLOCK(uart1, BCLKCTR0, 23, ACLKUART1)
+DEFINE_ACLOCK(uart2, BCLKCTR0, 6, ACLKUART2)
+DEFINE_ACLOCK(uart3, BCLKCTR0, 8, ACLKUART3)
+DEFINE_ACLOCK(uart4, BCLKCTR1, 6, ACLKUART4)
+DEFINE_ACLOCK(i2c, BCLKCTR0, 7, ACLKI2C)
+DEFINE_ACLOCK(adc, BCLKCTR0, 10, ACLKADC)
+DEFINE_ACLOCK(usbh0, BCLKCTR0, 11, ACLKUSBH)
+DEFINE_ACLOCK(lcd, BCLKCTR0, 13, ACLKLCD)
+DEFINE_ACLOCK(sd0, BCLKCTR0, 17, ACLKSDH0)
+DEFINE_ACLOCK(sd1, BCLKCTR1, 5, ACLKSDH1)
+DEFINE_ACLOCK(spi0, BCLKCTR0, 24, ACLKSPI0)
+DEFINE_ACLOCK(spi1, BCLKCTR0, 30, ACLKSPI1)
+DEFINE_ACLOCK(spdif, BCLKCTR1, 2, ACLKSPDIF)
+DEFINE_ACLOCK(c3dec, BCLKCTR1, 9, ACLKC3DEC)
+DEFINE_ACLOCK(can0, BCLKCTR1, 10, ACLKCAN0)
+DEFINE_ACLOCK(can1, BCLKCTR1, 11, ACLKCAN1)
+DEFINE_ACLOCK(gsb0, BCLKCTR1, 13, ACLKGSB0)
+DEFINE_ACLOCK(gsb1, BCLKCTR1, 14, ACLKGSB1)
+DEFINE_ACLOCK(gsb2, BCLKCTR1, 15, ACLKGSB2)
+DEFINE_ACLOCK(gsb3, BCLKCTR1, 16, ACLKGSB3)
+DEFINE_ACLOCK(usbh1, BCLKCTR1, 20, ACLKUSBH)
+
+DEFINE_BCLOCK(dai0, BCLKCTR0, 0, NULL, NULL)
+DEFINE_BCLOCK(pic, BCLKCTR0, 1, NULL, NULL)
+DEFINE_BCLOCK(tc, BCLKCTR0, 2, NULL, NULL)
+DEFINE_BCLOCK(gpio, BCLKCTR0, 3, NULL, NULL)
+DEFINE_BCLOCK(usbd, BCLKCTR0, 4, NULL, NULL)
+DEFINE_BCLOCK(ecc, BCLKCTR0, 9, NULL, NULL)
+DEFINE_BCLOCK(gdma0, BCLKCTR0, 12, NULL, NULL)
+DEFINE_BCLOCK(rtc, BCLKCTR0, 15, NULL, NULL)
+DEFINE_BCLOCK(nfc, BCLKCTR0, 16, NULL, NULL)
+DEFINE_BCLOCK(g2d, BCLKCTR0, 18, NULL, NULL)
+DEFINE_BCLOCK(gdma1, BCLKCTR0, 22, NULL, NULL)
+DEFINE_BCLOCK(mscl, BCLKCTR0, 25, NULL, NULL)
+DEFINE_BCLOCK(bdma, BCLKCTR1, 0, NULL, NULL)
+DEFINE_BCLOCK(adma0, BCLKCTR1, 1, NULL, NULL)
+DEFINE_BCLOCK(scfg, BCLKCTR1, 3, NULL, NULL)
+DEFINE_BCLOCK(cid, BCLKCTR1, 4, NULL, NULL)
+DEFINE_BCLOCK(dai1, BCLKCTR1, 7, NULL, NULL)
+DEFINE_BCLOCK(adma1, BCLKCTR1, 8, NULL, NULL)
+DEFINE_BCLOCK(gps, BCLKCTR1, 12, NULL, NULL)
+DEFINE_BCLOCK(gdma2, BCLKCTR1, 17, NULL, NULL)
+DEFINE_BCLOCK(gdma3, BCLKCTR1, 18, NULL, NULL)
+DEFINE_BCLOCK(ddrc, BCLKCTR1, 19, NULL, NULL)
+
+#define _REGISTER_CLOCK(d, n, c) \
+	{ \
+		.dev_id = d, \
+		.con_id = n, \
+		.clk = &c, \
+	},
+
+static struct clk_lookup lookups[] = {
+	_REGISTER_CLOCK(NULL, "bus", bus)
+	_REGISTER_CLOCK(NULL, "cpu", cpu)
+	_REGISTER_CLOCK(NULL, "tct", tct)
+	_REGISTER_CLOCK(NULL, "tcx", tcx)
+	_REGISTER_CLOCK(NULL, "tcz", tcz)
+	_REGISTER_CLOCK(NULL, "ref", ref)
+	_REGISTER_CLOCK(NULL, "dai0", dai0)
+	_REGISTER_CLOCK(NULL, "pic", pic)
+	_REGISTER_CLOCK(NULL, "tc", tc)
+	_REGISTER_CLOCK(NULL, "gpio", gpio)
+	_REGISTER_CLOCK(NULL, "usbd", usbd)
+	_REGISTER_CLOCK("tcc-uart.0", NULL, uart0)
+	_REGISTER_CLOCK("tcc-uart.2", NULL, uart2)
+	_REGISTER_CLOCK("tcc-i2c", NULL, i2c)
+	_REGISTER_CLOCK("tcc-uart.3", NULL, uart3)
+	_REGISTER_CLOCK(NULL, "ecc", ecc)
+	_REGISTER_CLOCK(NULL, "adc", adc)
+	_REGISTER_CLOCK("tcc-usbh.0", "usb", usbh0)
+	_REGISTER_CLOCK(NULL, "gdma0", gdma0)
+	_REGISTER_CLOCK(NULL, "lcd", lcd)
+	_REGISTER_CLOCK(NULL, "rtc", rtc)
+	_REGISTER_CLOCK(NULL, "nfc", nfc)
+	_REGISTER_CLOCK("tcc-mmc.0", NULL, sd0)
+	_REGISTER_CLOCK(NULL, "g2d", g2d)
+	_REGISTER_CLOCK(NULL, "gdma1", gdma1)
+	_REGISTER_CLOCK("tcc-uart.1", NULL, uart1)
+	_REGISTER_CLOCK("tcc-spi.0", NULL, spi0)
+	_REGISTER_CLOCK(NULL, "mscl", mscl)
+	_REGISTER_CLOCK("tcc-spi.1", NULL, spi1)
+	_REGISTER_CLOCK(NULL, "bdma", bdma)
+	_REGISTER_CLOCK(NULL, "adma0", adma0)
+	_REGISTER_CLOCK(NULL, "spdif", spdif)
+	_REGISTER_CLOCK(NULL, "scfg", scfg)
+	_REGISTER_CLOCK(NULL, "cid", cid)
+	_REGISTER_CLOCK("tcc-mmc.1", NULL, sd1)
+	_REGISTER_CLOCK("tcc-uart.4", NULL, uart4)
+	_REGISTER_CLOCK(NULL, "dai1", dai1)
+	_REGISTER_CLOCK(NULL, "adma1", adma1)
+	_REGISTER_CLOCK(NULL, "c3dec", c3dec)
+	_REGISTER_CLOCK("tcc-can.0", NULL, can0)
+	_REGISTER_CLOCK("tcc-can.1", NULL, can1)
+	_REGISTER_CLOCK(NULL, "gps", gps)
+	_REGISTER_CLOCK("tcc-gsb.0", NULL, gsb0)
+	_REGISTER_CLOCK("tcc-gsb.1", NULL, gsb1)
+	_REGISTER_CLOCK("tcc-gsb.2", NULL, gsb2)
+	_REGISTER_CLOCK("tcc-gsb.3", NULL, gsb3)
+	_REGISTER_CLOCK(NULL, "gdma2", gdma2)
+	_REGISTER_CLOCK(NULL, "gdma3", gdma3)
+	_REGISTER_CLOCK(NULL, "ddrc", ddrc)
+	_REGISTER_CLOCK("tcc-usbh.1", "usb", usbh1)
+};
+
+static struct clk *root_clk_by_index(enum root_clks src)
+{
+	switch (src) {
+	case CLK_SRC_PLL0: return &pll0;
+	case CLK_SRC_PLL1: return &pll1;
+	case CLK_SRC_PLL2: return &pll2;
+	case CLK_SRC_PLL0DIV: return &pll0div;
+	case CLK_SRC_PLL1DIV: return &pll1div;
+	case CLK_SRC_PLL2DIV: return &pll2div;
+	case CLK_SRC_XI: return &xi;
+	case CLK_SRC_XTI: return &xti;
+	case CLK_SRC_XIDIV: return &xidiv;
+	case CLK_SRC_XTIDIV: return &xtidiv;
+	default: return NULL;
+	}
+}
+
+static void find_aclk_parent(struct clk *clk)
+{
+	unsigned int src;
+	struct clk *clock;
+
+	if (!clk->aclkreg)
+		return;
+
+	src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+	src &= CLK_SRC_MASK;
+
+	clock = root_clk_by_index(src);
+	if (!clock)
+		return;
+
+	clk->parent = clock;
+	clk->set_parent = aclk_set_parent;
+}
+
+void __init tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq)
+{
+	int i;
+
+	xi_rate = xi_freq;
+	xti_rate = xti_freq;
+
+	/* fixup parents and add the clock */
+	for (i = 0; i < ARRAY_SIZE(lookups); i++) {
+		find_aclk_parent(lookups[i].clk);
+		clkdev_add(&lookups[i]);
+	}
+	tcc8k_timer_init(&tcz, (void __iomem *)TIMER_BASE, INT_TC32);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/common.h linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/common.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/common.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/common.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,15 @@
+#ifndef MACH_TCC8K_COMMON_H
+#define MACH_TCC8K_COMMON_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device tcc_nand_device;
+
+struct clk;
+
+extern void tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq);
+extern void tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq);
+extern void tcc8k_init_irq(void);
+extern void tcc8k_map_common_io(void);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/devices.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/devices.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/arm/mach-tcc8k/devices.c
+ *
+ * Copyright (C) Telechips, Inc.
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of GPL v2.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static u64 tcc8k_dmamask = DMA_BIT_MASK(32);
+
+#ifdef CONFIG_MTD_NAND_TCC
+/* NAND controller */
+static struct resource tcc_nand_resources[] = {
+	{
+		.start	= (resource_size_t)NFC_BASE,
+		.end	= (resource_size_t)NFC_BASE + 0x7f,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= INT_NFC,
+		.end	= INT_NFC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device tcc_nand_device = {
+	.name = "tcc_nand",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(tcc_nand_resources),
+	.resource = tcc_nand_resources,
+};
+#endif
+
+#ifdef CONFIG_MMC_TCC8K
+/* MMC controller */
+static struct resource tcc8k_mmc0_resource[] = {
+	{
+		.start = INT_SD0,
+		.end   = INT_SD0,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource tcc8k_mmc1_resource[] = {
+	{
+		.start = INT_SD1,
+		.end   = INT_SD1,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device tcc8k_mmc0_device = {
+	.name		= "tcc-mmc",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(tcc8k_mmc0_resource),
+	.resource	= tcc8k_mmc0_resource,
+	.dev		= {
+		.dma_mask		= &tcc8k_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	}
+};
+
+struct platform_device tcc8k_mmc1_device = {
+	.name		= "tcc-mmc",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(tcc8k_mmc1_resource),
+	.resource	= tcc8k_mmc1_resource,
+	.dev		= {
+		.dma_mask		= &tcc8k_dmamask,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	}
+};
+
+static inline void tcc8k_init_mmc(void)
+{
+	u32 reg = __raw_readl(GPIOPS_BASE + GPIOPS_FS1_OFFS);
+
+	reg |= GPIOPS_FS1_SDH0_BITS | GPIOPS_FS1_SDH1_BITS;
+	__raw_writel(reg, GPIOPS_BASE + GPIOPS_FS1_OFFS);
+
+	platform_device_register(&tcc8k_mmc0_device);
+	platform_device_register(&tcc8k_mmc1_device);
+}
+#else
+static inline void tcc8k_init_mmc(void) { }
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD
+static int tcc8k_ohci_init(struct device *dev)
+{
+	u32 reg;
+
+	/* Use GPIO PK19 as VBUS control output */
+	reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS0_OFFS);
+	reg &= ~(1 << 19);
+	__raw_writel(reg, GPIOPK_BASE + GPIOPK_FS0_OFFS);
+	reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS1_OFFS);
+	reg &= ~(1 << 19);
+	__raw_writel(reg, GPIOPK_BASE + GPIOPK_FS1_OFFS);
+
+	reg = __raw_readl(GPIOPK_BASE + GPIOPK_DOE_OFFS);
+	reg |= (1 << 19);
+	__raw_writel(reg, GPIOPK_BASE + GPIOPK_DOE_OFFS);
+	/* Turn on VBUS */
+	reg = __raw_readl(GPIOPK_BASE + GPIOPK_DAT_OFFS);
+	reg |= (1 << 19);
+	__raw_writel(reg, GPIOPK_BASE + GPIOPK_DAT_OFFS);
+
+	return 0;
+}
+
+static struct resource tcc8k_ohci0_resources[] = {
+	[0] = {
+		.start = (resource_size_t)USBH0_BASE,
+		.end   = (resource_size_t)USBH0_BASE + 0x5c,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = INT_USBH0,
+		.end   = INT_USBH0,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct resource tcc8k_ohci1_resources[] = {
+	[0] = {
+		.start = (resource_size_t)USBH1_BASE,
+		.end   = (resource_size_t)USBH1_BASE + 0x5c,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = INT_USBH1,
+		.end   = INT_USBH1,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct tccohci_platform_data tcc8k_ohci0_platform_data = {
+	.controller	= 0,
+	.port_mode	= PMM_PERPORT_MODE,
+	.init		= tcc8k_ohci_init,
+};
+
+static struct tccohci_platform_data tcc8k_ohci1_platform_data = {
+	.controller	= 1,
+	.port_mode	= PMM_PERPORT_MODE,
+	.init		= tcc8k_ohci_init,
+};
+
+static struct platform_device ohci0_device = {
+	.name = "tcc-ohci",
+	.id = 0,
+	.dev = {
+		.dma_mask = &tcc8k_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &tcc8k_ohci0_platform_data,
+	},
+	.num_resources  = ARRAY_SIZE(tcc8k_ohci0_resources),
+	.resource       = tcc8k_ohci0_resources,
+};
+
+static struct platform_device ohci1_device = {
+	.name = "tcc-ohci",
+	.id = 1,
+	.dev = {
+		.dma_mask = &tcc8k_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+		.platform_data = &tcc8k_ohci1_platform_data,
+	},
+	.num_resources  = ARRAY_SIZE(tcc8k_ohci1_resources),
+	.resource       = tcc8k_ohci1_resources,
+};
+
+static void __init tcc8k_init_usbhost(void)
+{
+	platform_device_register(&ohci0_device);
+	platform_device_register(&ohci1_device);
+}
+#else
+static void __init tcc8k_init_usbhost(void) { }
+#endif
+
+/* USB device controller*/
+#ifdef CONFIG_USB_GADGET_TCC8K
+static struct resource udc_resources[] = {
+	[0] = {
+		.start = INT_USBD,
+		.end   = INT_USBD,
+		.flags = IORESOURCE_IRQ,
+	},
+	[1] = {
+		.start = INT_UDMA,
+		.end   = INT_UDMA,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device tcc8k_udc_device = {
+	.name = "tcc-udc",
+	.id = 0,
+	.resource = udc_resources,
+	.num_resources = ARRAY_SIZE(udc_resources),
+	.dev = {
+		 .dma_mask = &tcc8k_dmamask,
+		 .coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+};
+
+static void __init tcc8k_init_usb_gadget(void)
+{
+	platform_device_register(&tcc8k_udc_device);
+}
+#else
+static void __init tcc8k_init_usb_gadget(void) { }
+#endif	/* CONFIG_USB_GADGET_TCC83X */
+
+static int __init tcc8k_init_devices(void)
+{
+	tcc8k_init_mmc();
+	tcc8k_init_usbhost();
+	tcc8k_init_usb_gadget();
+	return 0;
+}
+
+arch_initcall(tcc8k_init_devices);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/io.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/io.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/io.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/io.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,62 @@
+/*
+ * linux/arch/arm/mach-tcc8k/io.c
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * derived from TCC83xx io.c
+ * Copyright (C) Telechips, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/tcc8k-regs.h>
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc tcc8k_io_desc[] __initdata = {
+	{
+		.virtual	= (unsigned long)CS1_BASE_VIRT,
+		.pfn		= __phys_to_pfn(CS1_BASE),
+		.length		= CS1_SIZE,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)AHB_PERI_BASE_VIRT,
+		.pfn		= __phys_to_pfn(AHB_PERI_BASE),
+		.length		= AHB_PERI_SIZE,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)APB0_PERI_BASE_VIRT,
+		.pfn		= __phys_to_pfn(APB0_PERI_BASE),
+		.length		= APB0_PERI_SIZE,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)APB1_PERI_BASE_VIRT,
+		.pfn		= __phys_to_pfn(APB1_PERI_BASE),
+		.length		= APB1_PERI_SIZE,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= (unsigned long)EXT_MEM_CTRL_BASE_VIRT,
+		.pfn		= __phys_to_pfn(EXT_MEM_CTRL_BASE),
+		.length		= EXT_MEM_CTRL_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+
+/*
+ * Maps common IO regions for tcc8k.
+ *
+ */
+void __init tcc8k_map_common_io(void)
+{
+	iotable_init(tcc8k_io_desc, ARRAY_SIZE(tcc8k_io_desc));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/irq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) Telechips, Inc.
+ * Copyright (C) 2009-2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU GPL version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+/* Disable IRQ */
+static void tcc8000_mask_ack_irq0(unsigned int irq)
+{
+	PIC0_IEN &= ~(1 << irq);
+	PIC0_CREQ |=  (1 << irq);
+}
+
+static void tcc8000_mask_ack_irq1(unsigned int irq)
+{
+	PIC1_IEN &= ~(1 << (irq - 32));
+	PIC1_CREQ |= (1 << (irq - 32));
+}
+
+static void tcc8000_mask_irq0(unsigned int irq)
+{
+	PIC0_IEN &= ~(1 << irq);
+}
+
+static void tcc8000_mask_irq1(unsigned int irq)
+{
+	PIC1_IEN &= ~(1 << (irq - 32));
+}
+
+static void tcc8000_ack_irq0(unsigned int irq)
+{
+	PIC0_CREQ |=  (1 << irq);
+}
+
+static void tcc8000_ack_irq1(unsigned int irq)
+{
+	PIC1_CREQ |= (1 << (irq - 32));
+}
+
+/* Enable IRQ */
+static void tcc8000_unmask_irq0(unsigned int irq)
+{
+	PIC0_IEN |= (1 << irq);
+	PIC0_INTOEN |= (1 << irq);
+}
+
+static void tcc8000_unmask_irq1(unsigned int irq)
+{
+	PIC1_IEN |= (1 << (irq - 32));
+	PIC1_INTOEN |= (1 << (irq - 32));
+}
+
+static struct irq_chip tcc8000_irq_chip0 = {
+	.name		= "tcc_irq0",
+	.mask		= tcc8000_mask_irq0,
+	.ack		= tcc8000_ack_irq0,
+	.mask_ack	= tcc8000_mask_ack_irq0,
+	.unmask		= tcc8000_unmask_irq0,
+};
+
+static struct irq_chip tcc8000_irq_chip1 = {
+	.name		= "tcc_irq1",
+	.mask		= tcc8000_mask_irq1,
+	.ack		= tcc8000_ack_irq1,
+	.mask_ack	= tcc8000_mask_ack_irq1,
+	.unmask		= tcc8000_unmask_irq1,
+};
+
+void __init tcc8k_init_irq(void)
+{
+	int irqno;
+
+	/* Mask and clear all interrupts */
+	PIC0_IEN = 0x00000000;
+	PIC0_CREQ = 0xffffffff;
+	PIC1_IEN = 0x00000000;
+	PIC1_CREQ = 0xffffffff;
+
+	PIC0_MEN0 = 0x00000003;
+	PIC1_MEN1 = 0x00000003;
+	PIC1_MEN = 0x00000003;
+
+	/* let all IRQs be level triggered */
+	PIC0_TMODE = 0xffffffff;
+	PIC1_TMODE = 0xffffffff;
+	/* all IRQs are IRQs (not FIQs) */
+	PIC0_IRQSEL = 0xffffffff;
+	PIC1_IRQSEL = 0xffffffff;
+
+	for (irqno = 0; irqno < NR_IRQS; irqno++) {
+		if (irqno < 32)
+			set_irq_chip(irqno, &tcc8000_irq_chip0);
+		else
+			set_irq_chip(irqno, &tcc8000_irq_chip1);
+		set_irq_handler(irqno, handle_level_irq);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,11 @@
+if ARCH_TCC8K
+
+comment "TCC8000 systems:"
+
+config MACH_TCC8000_SDK
+	bool "Telechips TCC8000-SDK development kit"
+	default y
+	help
+	  Support for the Telechips TCC8000-SDK board.
+
+endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,9 @@
+#
+# Makefile for TCC8K boards and common files.
+#
+
+# Common support
+obj-y += clock.o irq.o time.o io.o devices.o
+
+# Board specific support
+obj-$(CONFIG_MACH_TCC8000_SDK) += board-tcc8000-sdk.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Makefile.boot linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Makefile.boot
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/Makefile.boot	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/Makefile.boot	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,3 @@
+   zreladdr-y		:= 0x20008000
+params_phys-y		:= 0x20000100
+initrd_phys-y		:= 0x20800000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/time.c linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/time.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tcc8k/time.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tcc8k/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,149 @@
+/*
+ * TCC8000 system timer setup
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL version 2.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach/time.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static void __iomem *timer_base;
+
+static cycle_t tcc_get_cycles(struct clocksource *cs)
+{
+	return __raw_readl(timer_base + TC32MCNT_OFFS);
+}
+
+static struct clocksource clocksource_tcc = {
+	.name		= "tcc_tc32",
+	.rating		= 200,
+	.read		= tcc_get_cycles,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 28,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int tcc_set_next_event(unsigned long evt,
+			      struct clock_event_device *unused)
+{
+	unsigned long reg = __raw_readl(timer_base + TC32MCNT_OFFS);
+
+	__raw_writel(reg + evt, timer_base + TC32CMP0_OFFS);
+	return 0;
+}
+
+static void tcc_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt)
+{
+	unsigned long tc32irq;
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_ONESHOT:
+		tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
+		tc32irq |= TC32IRQ_IRQEN0;
+		__raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+		tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
+		tc32irq &= ~TC32IRQ_IRQEN0;
+		__raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static irqreturn_t tcc8k_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+
+	/* Acknowledge TC32 interrupt by reading TC32IRQ */
+	__raw_readl(timer_base + TC32IRQ_OFFS);
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct clock_event_device clockevent_tcc = {
+	.name		= "tcc_timer1",
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_mode	= tcc_set_mode,
+	.set_next_event	= tcc_set_next_event,
+	.rating		= 200,
+};
+
+static struct irqaction tcc8k_timer_irq = {
+	.name		= "TC32_timer",
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
+	.handler	= tcc8k_timer_interrupt,
+	.dev_id		= &clockevent_tcc,
+};
+
+static int __init tcc_clockevent_init(struct clk *clock)
+{
+	unsigned int c = clk_get_rate(clock);
+
+	clocksource_tcc.mult = clocksource_hz2mult(c,
+					clocksource_tcc.shift);
+	clocksource_register(&clocksource_tcc);
+
+	clockevent_tcc.mult = div_sc(c, NSEC_PER_SEC,
+					clockevent_tcc.shift);
+	clockevent_tcc.max_delta_ns =
+			clockevent_delta2ns(0xfffffffe, &clockevent_tcc);
+	clockevent_tcc.min_delta_ns =
+			clockevent_delta2ns(0xff, &clockevent_tcc);
+
+	clockevent_tcc.cpumask = cpumask_of(0);
+
+	clockevents_register_device(&clockevent_tcc);
+
+	return 0;
+}
+
+void __init tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq)
+{
+	u32 reg;
+
+	timer_base = base;
+	tcc8k_timer_irq.irq = irq;
+
+	/* Enable clocks */
+	clk_enable(clock);
+
+	/* Initialize 32-bit timer */
+	reg = __raw_readl(timer_base + TC32EN_OFFS);
+	reg &= ~TC32EN_ENABLE; /* Disable timer */
+	__raw_writel(reg, timer_base + TC32EN_OFFS);
+	/* Free running timer, counting from 0 to 0xffffffff */
+	__raw_writel(0, timer_base + TC32EN_OFFS);
+	__raw_writel(0, timer_base + TC32LDV_OFFS);
+	reg = __raw_readl(timer_base + TC32IRQ_OFFS);
+	reg |= TC32IRQ_IRQEN0; /* irq at match with CMP0 */
+	__raw_writel(reg, timer_base + TC32IRQ_OFFS);
+
+	__raw_writel(TC32EN_ENABLE, timer_base + TC32EN_OFFS);
+
+	tcc_clockevent_init(clock);
+	setup_irq(irq, &tcc8k_timer_irq);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 void __init tegra_map_common_io(void);
 void __init tegra_init_irq(void);
 void __init tegra_init_clock(void);
+int __init tegra_pcie_init(bool init_port0, bool init_port1);
 
 extern struct sys_timer tegra_timer;
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board-harmony.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board-harmony.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board-harmony.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board-harmony.c	2011-01-04 19:50:19.000000000 -0500
@@ -115,8 +115,6 @@
 
 MACHINE_START(HARMONY, "harmony")
 	.boot_params  = 0x00000100,
-	.phys_io        = IO_APB_PHYS,
-	.io_pg_offst    = ((IO_APB_VIRT) >> 18) & 0xfffc,
 	.fixup		= tegra_harmony_fixup,
 	.init_irq       = tegra_init_irq,
 	.init_machine   = tegra_harmony_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board-harmony-pcie.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board-harmony-pcie.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/board-harmony-pcie.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/board-harmony-pcie.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,57 @@
+/*
+ * arch/arm/mach-tegra/board-harmony-pcie.c
+ *
+ * Copyright (C) 2010 CompuLab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/pinmux.h>
+#include "board.h"
+
+#ifdef CONFIG_TEGRA_PCI
+
+static int __init harmony_pcie_init(void)
+{
+	int err;
+
+	if (!machine_is_harmony())
+		return 0;
+
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_NORMAL);
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_NORMAL);
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
+
+	err = tegra_pcie_init(true, true);
+	if (err)
+		goto err_pcie;
+
+	return 0;
+
+err_pcie:
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_TRISTATE);
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
+	tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
+
+	return err;
+}
+
+subsys_initcall(harmony_pcie_init);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,13 +24,80 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
+#include <linux/regulator/consumer.h>
 #include <asm/clkdev.h>
 
 #include "clock.h"
+#include "board.h"
+#include "fuse.h"
 
 static LIST_HEAD(clocks);
 
 static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(dvfs_lock);
+
+static int clk_is_dvfs(struct clk *c)
+{
+	return (c->dvfs != NULL);
+};
+
+static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
+{
+	struct dvfs_table *t;
+
+	if (d->table == NULL)
+		return -ENODEV;
+
+	for (t = d->table; t->rate != 0; t++) {
+		if (rate <= t->rate) {
+			if (!d->reg)
+				return 0;
+
+			return regulator_set_voltage(d->reg,
+				t->millivolts * 1000,
+				d->max_millivolts * 1000);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static void dvfs_init(struct clk *c)
+{
+	int process_id;
+	int i;
+	struct dvfs_table *table;
+
+	process_id = c->dvfs->cpu ? tegra_core_process_id() :
+		tegra_cpu_process_id();
+
+	for (i = 0; i < c->dvfs->process_id_table_length; i++)
+		if (process_id == c->dvfs->process_id_table[i].process_id)
+			c->dvfs->table = c->dvfs->process_id_table[i].table;
+
+	if (c->dvfs->table == NULL) {
+		pr_err("Failed to find dvfs table for clock %s process %d\n",
+			c->name, process_id);
+		return;
+	}
+
+	c->dvfs->max_millivolts = 0;
+	for (table = c->dvfs->table; table->rate != 0; table++)
+		if (c->dvfs->max_millivolts < table->millivolts)
+			c->dvfs->max_millivolts = table->millivolts;
+
+	c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
+
+	if (IS_ERR(c->dvfs->reg)) {
+		pr_err("Failed to get regulator %s for clock %s\n",
+			c->dvfs->reg_id, c->name);
+		c->dvfs->reg = NULL;
+		return;
+	}
+
+	if (c->refcnt > 0)
+		dvfs_set_rate(c->dvfs, c->rate);
+}
 
 struct clk *tegra_get_clock_by_name(const char *name)
 {
@@ -48,14 +115,31 @@
 	return ret;
 }
 
+static void clk_recalculate_rate(struct clk *c)
+{
+	u64 rate;
+
+	if (!c->parent)
+		return;
+
+	rate = c->parent->rate;
+
+	if (c->mul != 0 && c->div != 0) {
+		rate = rate * c->mul;
+		do_div(rate, c->div);
+	}
+
+	if (rate > c->max_rate)
+		pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
+			c->name, rate, c->max_rate);
+
+	c->rate = rate;
+}
+
 int clk_reparent(struct clk *c, struct clk *parent)
 {
 	pr_debug("%s: %s\n", __func__, c->name);
-	if (c->refcnt && c->parent)
-		clk_disable_locked(c->parent);
 	c->parent = parent;
-	if (c->refcnt && c->parent)
-		clk_enable_locked(c->parent);
 	list_del(&c->sibling);
 	list_add_tail(&c->sibling, &parent->children);
 	return 0;
@@ -67,8 +151,7 @@
 	pr_debug("%s: %s\n", __func__, c->name);
 	list_for_each_entry(clkp, &c->children, sibling) {
 		pr_debug("   %s\n", clkp->name);
-		if (clkp->ops->recalculate_rate)
-			clkp->ops->recalculate_rate(clkp);
+		clk_recalculate_rate(clkp);
 		propagate_rate(clkp);
 	}
 }
@@ -77,6 +160,8 @@
 {
 	unsigned long flags;
 
+	pr_debug("%s: %s\n", __func__, c->name);
+
 	spin_lock_irqsave(&clock_lock, flags);
 
 	INIT_LIST_HEAD(&c->children);
@@ -85,6 +170,8 @@
 	if (c->ops && c->ops->init)
 		c->ops->init(c);
 
+	clk_recalculate_rate(c);
+
 	list_add(&c->node, &clocks);
 
 	if (c->parent)
@@ -122,13 +209,38 @@
 	return 0;
 }
 
+int clk_enable_cansleep(struct clk *c)
+{
+	int ret;
+	unsigned long flags;
+
+	mutex_lock(&dvfs_lock);
+
+	if (clk_is_dvfs(c) && c->refcnt > 0)
+		dvfs_set_rate(c->dvfs, c->rate);
+
+	spin_lock_irqsave(&clock_lock, flags);
+	ret = clk_enable_locked(c);
+	spin_unlock_irqrestore(&clock_lock, flags);
+
+	mutex_unlock(&dvfs_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable_cansleep);
+
 int clk_enable(struct clk *c)
 {
 	int ret;
 	unsigned long flags;
+
+	if (clk_is_dvfs(c))
+		BUG();
+
 	spin_lock_irqsave(&clock_lock, flags);
 	ret = clk_enable_locked(c);
 	spin_unlock_irqrestore(&clock_lock, flags);
+
 	return ret;
 }
 EXPORT_SYMBOL(clk_enable);
@@ -152,9 +264,30 @@
 	c->refcnt--;
 }
 
+void clk_disable_cansleep(struct clk *c)
+{
+	unsigned long flags;
+
+	mutex_lock(&dvfs_lock);
+
+	spin_lock_irqsave(&clock_lock, flags);
+	clk_disable_locked(c);
+	spin_unlock_irqrestore(&clock_lock, flags);
+
+	if (clk_is_dvfs(c) && c->refcnt == 0)
+		dvfs_set_rate(c->dvfs, c->rate);
+
+	mutex_unlock(&dvfs_lock);
+}
+EXPORT_SYMBOL(clk_disable_cansleep);
+
 void clk_disable(struct clk *c)
 {
 	unsigned long flags;
+
+	if (clk_is_dvfs(c))
+		BUG();
+
 	spin_lock_irqsave(&clock_lock, flags);
 	clk_disable_locked(c);
 	spin_unlock_irqrestore(&clock_lock, flags);
@@ -175,6 +308,8 @@
 	if (ret)
 		return ret;
 
+	clk_recalculate_rate(c);
+
 	propagate_rate(c);
 
 	return 0;
@@ -197,22 +332,69 @@
 }
 EXPORT_SYMBOL(clk_get_parent);
 
-int clk_set_rate(struct clk *c, unsigned long rate)
+int clk_set_rate_locked(struct clk *c, unsigned long rate)
+{
+	int ret;
+
+	if (rate > c->max_rate)
+		rate = c->max_rate;
+
+	if (!c->ops || !c->ops->set_rate)
+		return -ENOSYS;
+
+	ret = c->ops->set_rate(c, rate);
+
+	if (ret)
+		return ret;
+
+	clk_recalculate_rate(c);
+
+	propagate_rate(c);
+
+	return 0;
+}
+
+int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
 {
 	int ret = 0;
 	unsigned long flags;
 
+	pr_debug("%s: %s\n", __func__, c->name);
+
+	mutex_lock(&dvfs_lock);
+
+	if (rate > c->rate)
+		ret = dvfs_set_rate(c->dvfs, rate);
+	if (ret)
+		goto out;
+
 	spin_lock_irqsave(&clock_lock, flags);
+	ret = clk_set_rate_locked(c, rate);
+	spin_unlock_irqrestore(&clock_lock, flags);
 
-	pr_debug("%s: %s\n", __func__, c->name);
+	if (ret)
+		goto out;
 
-	if (c->ops && c->ops->set_rate)
-		ret = c->ops->set_rate(c, rate);
-	else
-		ret = -ENOSYS;
+	ret = dvfs_set_rate(c->dvfs, rate);
 
-	propagate_rate(c);
+out:
+	mutex_unlock(&dvfs_lock);
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate_cansleep);
+
+int clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long flags;
 
+	pr_debug("%s: %s\n", __func__, c->name);
+
+	if (clk_is_dvfs(c))
+		BUG();
+
+	spin_lock_irqsave(&clock_lock, flags);
+	ret = clk_set_rate_locked(c, rate);
 	spin_unlock_irqrestore(&clock_lock, flags);
 
 	return ret;
@@ -235,6 +417,20 @@
 }
 EXPORT_SYMBOL(clk_get_rate);
 
+long clk_round_rate(struct clk *c, unsigned long rate)
+{
+	pr_debug("%s: %s\n", __func__, c->name);
+
+	if (!c->ops || !c->ops->round_rate)
+		return -ENOSYS;
+
+	if (rate > c->max_rate)
+		rate = c->max_rate;
+
+	return c->ops->round_rate(c, rate);
+}
+EXPORT_SYMBOL(clk_round_rate);
+
 static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table)
 {
 	struct clk *c;
@@ -308,13 +504,28 @@
 }
 EXPORT_SYMBOL(tegra_periph_reset_assert);
 
-int __init tegra_init_clock(void)
+void __init tegra_init_clock(void)
 {
 	tegra2_init_clocks();
+}
+
+int __init tegra_init_dvfs(void)
+{
+	struct clk *c, *safe;
+
+	mutex_lock(&dvfs_lock);
+
+	list_for_each_entry_safe(c, safe, &clocks, node)
+		if (c->dvfs)
+			dvfs_init(c);
+
+	mutex_unlock(&dvfs_lock);
 
 	return 0;
 }
 
+late_initcall(tegra_init_dvfs);
+
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *clk_debugfs_root;
 
@@ -324,7 +535,7 @@
 	struct clk *child;
 	struct clk *safe;
 	const char *state = "uninit";
-	char div[5] = {0};
+	char div[8] = {0};
 
 	if (c->state == ON)
 		state = "on";
@@ -332,16 +543,26 @@
 		state = "off";
 
 	if (c->mul != 0 && c->div != 0) {
-		BUG_ON(c->mul > 2);
-		if (c->mul > c->div)
-			snprintf(div, sizeof(div), "x%d", c->mul / c->div);
-		else
+		if (c->mul > c->div) {
+			int mul = c->mul / c->div;
+			int mul2 = (c->mul * 10 / c->div) % 10;
+			int mul3 = (c->mul * 10) % c->div;
+			if (mul2 == 0 && mul3 == 0)
+				snprintf(div, sizeof(div), "x%d", mul);
+			else if (mul3 == 0)
+				snprintf(div, sizeof(div), "x%d.%d", mul, mul2);
+			else
+				snprintf(div, sizeof(div), "x%d.%d..", mul, mul2);
+		} else {
 			snprintf(div, sizeof(div), "%d%s", c->div / c->mul,
 				(c->div % c->mul) ? ".5" : "");
+		}
 	}
 
-	seq_printf(s, "%*s%-*s %-6s %-3d %-5s %-10lu\n",
-		level * 3 + 1, c->set ? "" : "*",
+	seq_printf(s, "%*s%c%c%-*s %-6s %-3d %-8s %-10lu\n",
+		level * 3 + 1, "",
+		c->rate > c->max_rate ? '!' : ' ',
+		!c->set ? '*' : ' ',
 		30 - level * 3, c->name,
 		state, c->refcnt, div, c->rate);
 	list_for_each_entry_safe(child, safe, &c->children, sibling) {
@@ -353,8 +574,8 @@
 {
 	struct clk *c;
 	unsigned long flags;
-	seq_printf(s, " clock                          state  ref div   rate      \n");
-	seq_printf(s, "-----------------------------------------------------------\n");
+	seq_printf(s, "   clock                          state  ref div      rate\n");
+	seq_printf(s, "--------------------------------------------------------------\n");
 	spin_lock_irqsave(&clock_lock, flags);
 	list_for_each_entry(c, &clocks, node)
 		if (c->parent == NULL)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/clock.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/clock.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,18 +27,43 @@
 #define DIV_U71			(1 << 1)
 #define DIV_U71_FIXED		(1 << 2)
 #define DIV_2			(1 << 3)
-#define PLL_FIXED		(1 << 4)
-#define PLL_HAS_CPCON		(1 << 5)
-#define MUX			(1 << 6)
-#define PLLD			(1 << 7)
-#define PERIPH_NO_RESET		(1 << 8)
-#define PERIPH_NO_ENB		(1 << 9)
-#define PERIPH_EMC_ENB		(1 << 10)
-#define PERIPH_MANUAL_RESET	(1 << 11)
-#define PLL_ALT_MISC_REG	(1 << 12)
+#define DIV_U16			(1 << 4)
+#define PLL_FIXED		(1 << 5)
+#define PLL_HAS_CPCON		(1 << 6)
+#define MUX			(1 << 7)
+#define PLLD			(1 << 8)
+#define PERIPH_NO_RESET		(1 << 9)
+#define PERIPH_NO_ENB		(1 << 10)
+#define PERIPH_EMC_ENB		(1 << 11)
+#define PERIPH_MANUAL_RESET	(1 << 12)
+#define PLL_ALT_MISC_REG	(1 << 13)
+#define PLLU			(1 << 14)
 #define ENABLE_ON_INIT		(1 << 28)
 
 struct clk;
+struct regulator;
+
+struct dvfs_table {
+	unsigned long rate;
+	int millivolts;
+};
+
+struct dvfs_process_id_table {
+	int process_id;
+	struct dvfs_table *table;
+};
+
+
+struct dvfs {
+	struct regulator *reg;
+	struct dvfs_table *table;
+	int max_millivolts;
+
+	int process_id_table_length;
+	const char *reg_id;
+	bool cpu;
+	struct dvfs_process_id_table process_id_table[];
+};
 
 struct clk_mux_sel {
 	struct clk	*input;
@@ -58,12 +83,9 @@
 	void		(*init)(struct clk *);
 	int		(*enable)(struct clk *);
 	void		(*disable)(struct clk *);
-	void		(*recalc)(struct clk *);
 	int		(*set_parent)(struct clk *, struct clk *);
 	int		(*set_rate)(struct clk *, unsigned long);
-	unsigned long	(*get_rate)(struct clk *);
 	long		(*round_rate)(struct clk *, unsigned long);
-	unsigned long	(*recalculate_rate)(struct clk *);
 };
 
 enum clk_state {
@@ -85,6 +107,7 @@
 	struct clk			*parent;
 	struct clk_lookup		lookup;
 	unsigned long			rate;
+	unsigned long			max_rate;
 	u32				flags;
 	u32				refcnt;
 	const char			*name;
@@ -103,10 +126,6 @@
 	unsigned long			cf_max;
 	unsigned long			vco_min;
 	unsigned long			vco_max;
-	u32				m;
-	u32				n;
-	u32				p;
-	u32				cpcon;
 	const struct clk_pll_table	*pll_table;
 
 	/* DIV */
@@ -117,6 +136,12 @@
 	const struct clk_mux_sel	*inputs;
 	u32				sel;
 	u32				reg_mask;
+
+	/* Virtual cpu clock */
+	struct clk			*main;
+	struct clk			*backup;
+
+	struct dvfs			*dvfs;
 };
 
 
@@ -141,6 +166,7 @@
 void clk_disable_locked(struct clk *c);
 int clk_enable_locked(struct clk *c);
 int clk_set_parent_locked(struct clk *c, struct clk *parent);
+int clk_set_rate_locked(struct clk *c, unsigned long rate);
 int clk_reparent(struct clk *c, struct clk *parent);
 void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/common.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/common.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,13 +19,17 @@
 
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
 
 #include <asm/hardware/cache-l2x0.h>
 
 #include <mach/iomap.h>
+#include <mach/dma.h>
 
 #include "board.h"
 #include "clock.h"
+#include "fuse.h"
 
 static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
 	/* name		parent		rate		enabled */
@@ -35,8 +39,8 @@
 	{ "pll_p_out2",	"pll_p",	48000000,	true },
 	{ "pll_p_out3",	"pll_p",	72000000,	true },
 	{ "pll_p_out4",	"pll_p",	108000000,	true },
-	{ "sys",	"pll_p_out4",	108000000,	true },
-	{ "hclk",	"sys",		108000000,	true },
+	{ "sclk",	"pll_p_out4",	108000000,	true },
+	{ "hclk",	"sclk",		108000000,	true },
 	{ "pclk",	"hclk",		54000000,	true },
 	{ NULL,		NULL,		0,		0},
 };
@@ -51,11 +55,16 @@
 
 	l2x0_init(p, 0x6C080001, 0x8200c3fe);
 #endif
+
 }
 
 void __init tegra_common_init(void)
 {
+	tegra_init_fuse();
 	tegra_init_clock();
 	tegra_clk_init_from_table(common_clk_init_table);
 	tegra_init_cache();
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+	tegra_dma_init();
+#endif
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/cpu-tegra.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/cpu-tegra.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/cpu-tegra.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/cpu-tegra.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,185 @@
+/*
+ * arch/arm/mach-tegra/cpu-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *	Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#include <mach/hardware.h>
+#include <mach/clk.h>
+
+/* Frequency table index must be sequential starting at 0 */
+static struct cpufreq_frequency_table freq_table[] = {
+	{ 0, 312000 },
+	{ 1, 456000 },
+	{ 2, 608000 },
+	{ 3, 760000 },
+	{ 4, 816000 },
+	{ 5, 912000 },
+	{ 6, 1000000 },
+	{ 7, CPUFREQ_TABLE_END },
+};
+
+#define NUM_CPUS	2
+
+static struct clk *cpu_clk;
+
+static unsigned long target_cpu_speed[NUM_CPUS];
+
+int tegra_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+unsigned int tegra_getspeed(unsigned int cpu)
+{
+	unsigned long rate;
+
+	if (cpu >= NUM_CPUS)
+		return 0;
+
+	rate = clk_get_rate(cpu_clk) / 1000;
+	return rate;
+}
+
+static int tegra_update_cpu_speed(void)
+{
+	int i;
+	unsigned long rate = 0;
+	int ret = 0;
+	struct cpufreq_freqs freqs;
+
+	for_each_online_cpu(i)
+		rate = max(rate, target_cpu_speed[i]);
+
+	freqs.old = tegra_getspeed(0);
+	freqs.new = rate;
+
+	if (freqs.old == freqs.new)
+		return ret;
+
+	for_each_online_cpu(freqs.cpu)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_CPU_FREQ_DEBUG
+	printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
+	       freqs.old, freqs.new);
+#endif
+
+	ret = clk_set_rate_cansleep(cpu_clk, freqs.new * 1000);
+	if (ret) {
+		pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
+			freqs.new);
+		return ret;
+	}
+
+	for_each_online_cpu(freqs.cpu)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static int tegra_target(struct cpufreq_policy *policy,
+		       unsigned int target_freq,
+		       unsigned int relation)
+{
+	int idx;
+	unsigned int freq;
+
+	cpufreq_frequency_table_target(policy, freq_table, target_freq,
+		relation, &idx);
+
+	freq = freq_table[idx].frequency;
+
+	target_cpu_speed[policy->cpu] = freq;
+
+	return tegra_update_cpu_speed();
+}
+
+static int tegra_cpu_init(struct cpufreq_policy *policy)
+{
+	if (policy->cpu >= NUM_CPUS)
+		return -EINVAL;
+
+	cpu_clk = clk_get_sys(NULL, "cpu");
+	if (IS_ERR(cpu_clk))
+		return PTR_ERR(cpu_clk);
+
+	cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+	policy->cur = tegra_getspeed(policy->cpu);
+	target_cpu_speed[policy->cpu] = policy->cur;
+
+	/* FIXME: what's the actual transition time? */
+	policy->cpuinfo.transition_latency = 300 * 1000;
+
+	policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+	cpumask_copy(policy->related_cpus, cpu_possible_mask);
+
+	return 0;
+}
+
+static int tegra_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	clk_put(cpu_clk);
+	return 0;
+}
+
+static struct freq_attr *tegra_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver tegra_cpufreq_driver = {
+	.verify		= tegra_verify_speed,
+	.target		= tegra_target,
+	.get		= tegra_getspeed,
+	.init		= tegra_cpu_init,
+	.exit		= tegra_cpu_exit,
+	.name		= "tegra",
+	.attr		= tegra_cpufreq_attr,
+};
+
+static int __init tegra_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&tegra_cpufreq_driver);
+}
+
+static void __exit tegra_cpufreq_exit(void)
+{
+        cpufreq_unregister_driver(&tegra_cpufreq_driver);
+}
+
+
+MODULE_AUTHOR("Colin Cross <ccross@android.com>");
+MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
+MODULE_LICENSE("GPL");
+module_init(tegra_cpufreq_init);
+module_exit(tegra_cpufreq_exit);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/dma.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/dma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,752 @@
+/*
+ * arch/arm/mach-tegra/dma.c
+ *
+ * System DMA driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+
+#define APB_DMA_GEN				0x000
+#define GEN_ENABLE				(1<<31)
+
+#define APB_DMA_CNTRL				0x010
+
+#define APB_DMA_IRQ_MASK			0x01c
+
+#define APB_DMA_IRQ_MASK_SET			0x020
+
+#define APB_DMA_CHAN_CSR			0x000
+#define CSR_ENB					(1<<31)
+#define CSR_IE_EOC				(1<<30)
+#define CSR_HOLD				(1<<29)
+#define CSR_DIR					(1<<28)
+#define CSR_ONCE				(1<<27)
+#define CSR_FLOW				(1<<21)
+#define CSR_REQ_SEL_SHIFT			16
+#define CSR_REQ_SEL_MASK			(0x1F<<CSR_REQ_SEL_SHIFT)
+#define CSR_REQ_SEL_INVALID			(31<<CSR_REQ_SEL_SHIFT)
+#define CSR_WCOUNT_SHIFT			2
+#define CSR_WCOUNT_MASK				0xFFFC
+
+#define APB_DMA_CHAN_STA				0x004
+#define STA_BUSY				(1<<31)
+#define STA_ISE_EOC				(1<<30)
+#define STA_HALT				(1<<29)
+#define STA_PING_PONG				(1<<28)
+#define STA_COUNT_SHIFT				2
+#define STA_COUNT_MASK				0xFFFC
+
+#define APB_DMA_CHAN_AHB_PTR				0x010
+
+#define APB_DMA_CHAN_AHB_SEQ				0x014
+#define AHB_SEQ_INTR_ENB			(1<<31)
+#define AHB_SEQ_BUS_WIDTH_SHIFT			28
+#define AHB_SEQ_BUS_WIDTH_MASK			(0x7<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_8			(0<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_16			(1<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_32			(2<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_64			(3<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_BUS_WIDTH_128			(4<<AHB_SEQ_BUS_WIDTH_SHIFT)
+#define AHB_SEQ_DATA_SWAP			(1<<27)
+#define AHB_SEQ_BURST_MASK			(0x7<<24)
+#define AHB_SEQ_BURST_1				(4<<24)
+#define AHB_SEQ_BURST_4				(5<<24)
+#define AHB_SEQ_BURST_8				(6<<24)
+#define AHB_SEQ_DBL_BUF				(1<<19)
+#define AHB_SEQ_WRAP_SHIFT			16
+#define AHB_SEQ_WRAP_MASK			(0x7<<AHB_SEQ_WRAP_SHIFT)
+
+#define APB_DMA_CHAN_APB_PTR				0x018
+
+#define APB_DMA_CHAN_APB_SEQ				0x01c
+#define APB_SEQ_BUS_WIDTH_SHIFT			28
+#define APB_SEQ_BUS_WIDTH_MASK			(0x7<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_8			(0<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_16			(1<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_32			(2<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_64			(3<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_BUS_WIDTH_128			(4<<APB_SEQ_BUS_WIDTH_SHIFT)
+#define APB_SEQ_DATA_SWAP			(1<<27)
+#define APB_SEQ_WRAP_SHIFT			16
+#define APB_SEQ_WRAP_MASK			(0x7<<APB_SEQ_WRAP_SHIFT)
+
+#define TEGRA_SYSTEM_DMA_CH_NR			16
+#define TEGRA_SYSTEM_DMA_AVP_CH_NUM		4
+#define TEGRA_SYSTEM_DMA_CH_MIN			0
+#define TEGRA_SYSTEM_DMA_CH_MAX	\
+	(TEGRA_SYSTEM_DMA_CH_NR - TEGRA_SYSTEM_DMA_AVP_CH_NUM - 1)
+
+#define NV_DMA_MAX_TRASFER_SIZE 0x10000
+
+const unsigned int ahb_addr_wrap_table[8] = {
+	0, 32, 64, 128, 256, 512, 1024, 2048
+};
+
+const unsigned int apb_addr_wrap_table[8] = {0, 1, 2, 4, 8, 16, 32, 64};
+
+const unsigned int bus_width_table[5] = {8, 16, 32, 64, 128};
+
+#define TEGRA_DMA_NAME_SIZE 16
+struct tegra_dma_channel {
+	struct list_head	list;
+	int			id;
+	spinlock_t		lock;
+	char			name[TEGRA_DMA_NAME_SIZE];
+	void  __iomem		*addr;
+	int			mode;
+	int			irq;
+
+	/* Register shadow */
+	u32			csr;
+	u32			ahb_seq;
+	u32			ahb_ptr;
+	u32			apb_seq;
+	u32			apb_ptr;
+};
+
+#define  NV_DMA_MAX_CHANNELS  32
+
+static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
+static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req);
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req);
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch);
+static void tegra_dma_stop(struct tegra_dma_channel *ch);
+
+void tegra_dma_flush(struct tegra_dma_channel *ch)
+{
+}
+EXPORT_SYMBOL(tegra_dma_flush);
+
+void tegra_dma_dequeue(struct tegra_dma_channel *ch)
+{
+	struct tegra_dma_req *req;
+
+	req = list_entry(ch->list.next, typeof(*req), node);
+
+	tegra_dma_dequeue_req(ch, req);
+	return;
+}
+
+void tegra_dma_stop(struct tegra_dma_channel *ch)
+{
+	unsigned int csr;
+	unsigned int status;
+
+	csr = ch->csr;
+	csr &= ~CSR_IE_EOC;
+	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+	csr &= ~CSR_ENB;
+	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+	status = readl(ch->addr + APB_DMA_CHAN_STA);
+	if (status & STA_ISE_EOC)
+		writel(status, ch->addr + APB_DMA_CHAN_STA);
+}
+
+int tegra_dma_cancel(struct tegra_dma_channel *ch)
+{
+	unsigned int csr;
+	unsigned long irq_flags;
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	while (!list_empty(&ch->list))
+		list_del(ch->list.next);
+
+	csr = ch->csr;
+	csr &= ~CSR_REQ_SEL_MASK;
+	csr |= CSR_REQ_SEL_INVALID;
+
+	/* Set the enable as that is not shadowed */
+	csr |= CSR_ENB;
+	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+	tegra_dma_stop(ch);
+
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+	return 0;
+}
+
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *_req)
+{
+	unsigned int csr;
+	unsigned int status;
+	struct tegra_dma_req *req = NULL;
+	int found = 0;
+	unsigned long irq_flags;
+	int to_transfer;
+	int req_transfer_count;
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	list_for_each_entry(req, &ch->list, node) {
+		if (req == _req) {
+			list_del(&req->node);
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		spin_unlock_irqrestore(&ch->lock, irq_flags);
+		return 0;
+	}
+
+	/* STOP the DMA and get the transfer count.
+	 * Getting the transfer count is tricky.
+	 *  - Change the source selector to invalid to stop the DMA from
+	 *    FIFO to memory.
+	 *  - Read the status register to know the number of pending
+	 *    bytes to be transfered.
+	 *  - Finally stop or program the DMA to the next buffer in the
+	 *    list.
+	 */
+	csr = ch->csr;
+	csr &= ~CSR_REQ_SEL_MASK;
+	csr |= CSR_REQ_SEL_INVALID;
+
+	/* Set the enable as that is not shadowed */
+	csr |= CSR_ENB;
+	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+	/* Get the transfer count */
+	status = readl(ch->addr + APB_DMA_CHAN_STA);
+	to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
+	req_transfer_count = (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+	req_transfer_count += 1;
+	to_transfer += 1;
+
+	req->bytes_transferred = req_transfer_count;
+
+	if (status & STA_BUSY)
+		req->bytes_transferred -= to_transfer;
+
+	/* In continous transfer mode, DMA only tracks the count of the
+	 * half DMA buffer. So, if the DMA already finished half the DMA
+	 * then add the half buffer to the completed count.
+	 *
+	 *	FIXME: There can be a race here. What if the req to
+	 *	dequue happens at the same time as the DMA just moved to
+	 *	the new buffer and SW didn't yet received the interrupt?
+	 */
+	if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
+		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+			req->bytes_transferred += req_transfer_count;
+
+	req->bytes_transferred *= 4;
+
+	tegra_dma_stop(ch);
+	if (!list_empty(&ch->list)) {
+		/* if the list is not empty, queue the next request */
+		struct tegra_dma_req *next_req;
+		next_req = list_entry(ch->list.next,
+			typeof(*next_req), node);
+		tegra_dma_update_hw(ch, next_req);
+	}
+	req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
+
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+	/* Callback should be called without any lock */
+	req->complete(req);
+	return 0;
+}
+EXPORT_SYMBOL(tegra_dma_dequeue_req);
+
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch)
+{
+	unsigned long irq_flags;
+	bool is_empty;
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	if (list_empty(&ch->list))
+		is_empty = true;
+	else
+		is_empty = false;
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+	return is_empty;
+}
+EXPORT_SYMBOL(tegra_dma_is_empty);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *_req)
+{
+	unsigned long irq_flags;
+	struct tegra_dma_req *req;
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+	list_for_each_entry(req, &ch->list, node) {
+		if (req == _req) {
+			spin_unlock_irqrestore(&ch->lock, irq_flags);
+			return true;
+		}
+	}
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+	return false;
+}
+EXPORT_SYMBOL(tegra_dma_is_req_inflight);
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req)
+{
+	unsigned long irq_flags;
+	int start_dma = 0;
+
+	if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
+		req->source_addr & 0x3 || req->dest_addr & 0x3) {
+		pr_err("Invalid DMA request for channel %d\n", ch->id);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&ch->lock, irq_flags);
+
+	req->bytes_transferred = 0;
+	req->status = 0;
+	req->buffer_status = 0;
+	if (list_empty(&ch->list))
+		start_dma = 1;
+
+	list_add_tail(&req->node, &ch->list);
+
+	if (start_dma)
+		tegra_dma_update_hw(ch, req);
+
+	spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(tegra_dma_enqueue_req);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
+{
+	int channel;
+	struct tegra_dma_channel *ch;
+
+	/* first channel is the shared channel */
+	if (mode & TEGRA_DMA_SHARED) {
+		channel = TEGRA_SYSTEM_DMA_CH_MIN;
+	} else {
+		channel = find_first_zero_bit(channel_usage,
+			ARRAY_SIZE(dma_channels));
+		if (channel >= ARRAY_SIZE(dma_channels))
+			return NULL;
+	}
+	__set_bit(channel, channel_usage);
+	ch = &dma_channels[channel];
+	ch->mode = mode;
+	return ch;
+}
+EXPORT_SYMBOL(tegra_dma_allocate_channel);
+
+void tegra_dma_free_channel(struct tegra_dma_channel *ch)
+{
+	if (ch->mode & TEGRA_DMA_SHARED)
+		return;
+	tegra_dma_cancel(ch);
+	__clear_bit(ch->id, channel_usage);
+}
+EXPORT_SYMBOL(tegra_dma_free_channel);
+
+static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req)
+{
+	if (req->to_memory) {
+		ch->apb_ptr = req->source_addr;
+		ch->ahb_ptr = req->dest_addr;
+	} else {
+		ch->apb_ptr = req->dest_addr;
+		ch->ahb_ptr = req->source_addr;
+	}
+	writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+	writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+	req->status = TEGRA_DMA_REQ_INFLIGHT;
+	return;
+}
+
+static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req)
+{
+	int ahb_addr_wrap;
+	int apb_addr_wrap;
+	int ahb_bus_width;
+	int apb_bus_width;
+	int index;
+	unsigned long csr;
+
+
+	ch->csr |= CSR_FLOW;
+	ch->csr &= ~CSR_REQ_SEL_MASK;
+	ch->csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
+	ch->ahb_seq &= ~AHB_SEQ_BURST_MASK;
+	ch->ahb_seq |= AHB_SEQ_BURST_1;
+
+	/* One shot mode is always single buffered,
+	 * continuous mode is always double buffered
+	 * */
+	if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
+		ch->csr |= CSR_ONCE;
+		ch->ahb_seq &= ~AHB_SEQ_DBL_BUF;
+		ch->csr &= ~CSR_WCOUNT_MASK;
+		ch->csr |= ((req->size>>2) - 1) << CSR_WCOUNT_SHIFT;
+	} else {
+		ch->csr &= ~CSR_ONCE;
+		ch->ahb_seq |= AHB_SEQ_DBL_BUF;
+
+		/* In double buffered mode, we set the size to half the
+		 * requested size and interrupt when half the buffer
+		 * is full */
+		ch->csr &= ~CSR_WCOUNT_MASK;
+		ch->csr |= ((req->size>>3) - 1) << CSR_WCOUNT_SHIFT;
+	}
+
+	if (req->to_memory) {
+		ch->csr &= ~CSR_DIR;
+		ch->apb_ptr = req->source_addr;
+		ch->ahb_ptr = req->dest_addr;
+
+		apb_addr_wrap = req->source_wrap;
+		ahb_addr_wrap = req->dest_wrap;
+		apb_bus_width = req->source_bus_width;
+		ahb_bus_width = req->dest_bus_width;
+
+	} else {
+		ch->csr |= CSR_DIR;
+		ch->apb_ptr = req->dest_addr;
+		ch->ahb_ptr = req->source_addr;
+
+		apb_addr_wrap = req->dest_wrap;
+		ahb_addr_wrap = req->source_wrap;
+		apb_bus_width = req->dest_bus_width;
+		ahb_bus_width = req->source_bus_width;
+	}
+
+	apb_addr_wrap >>= 2;
+	ahb_addr_wrap >>= 2;
+
+	/* set address wrap for APB size */
+	index = 0;
+	do  {
+		if (apb_addr_wrap_table[index] == apb_addr_wrap)
+			break;
+		index++;
+	} while (index < ARRAY_SIZE(apb_addr_wrap_table));
+	BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
+	ch->apb_seq &= ~APB_SEQ_WRAP_MASK;
+	ch->apb_seq |= index << APB_SEQ_WRAP_SHIFT;
+
+	/* set address wrap for AHB size */
+	index = 0;
+	do  {
+		if (ahb_addr_wrap_table[index] == ahb_addr_wrap)
+			break;
+		index++;
+	} while (index < ARRAY_SIZE(ahb_addr_wrap_table));
+	BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
+	ch->ahb_seq &= ~AHB_SEQ_WRAP_MASK;
+	ch->ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
+
+	for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+		if (bus_width_table[index] == ahb_bus_width)
+			break;
+	}
+	BUG_ON(index == ARRAY_SIZE(bus_width_table));
+	ch->ahb_seq &= ~AHB_SEQ_BUS_WIDTH_MASK;
+	ch->ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
+
+	for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
+		if (bus_width_table[index] == apb_bus_width)
+			break;
+	}
+	BUG_ON(index == ARRAY_SIZE(bus_width_table));
+	ch->apb_seq &= ~APB_SEQ_BUS_WIDTH_MASK;
+	ch->apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
+
+	ch->csr |= CSR_IE_EOC;
+
+	/* update hw registers with the shadow */
+	writel(ch->csr, ch->addr + APB_DMA_CHAN_CSR);
+	writel(ch->apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
+	writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
+	writel(ch->ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
+	writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
+
+	csr = ch->csr | CSR_ENB;
+	writel(csr, ch->addr + APB_DMA_CHAN_CSR);
+
+	req->status = TEGRA_DMA_REQ_INFLIGHT;
+}
+
+static void tegra_dma_init_hw(struct tegra_dma_channel *ch)
+{
+	/* One shot with an interrupt to CPU after transfer */
+	ch->csr = CSR_ONCE | CSR_IE_EOC;
+	ch->ahb_seq = AHB_SEQ_BUS_WIDTH_32 | AHB_SEQ_INTR_ENB;
+	ch->apb_seq = APB_SEQ_BUS_WIDTH_32 | 1 << APB_SEQ_WRAP_SHIFT;
+}
+
+static void handle_oneshot_dma(struct tegra_dma_channel *ch)
+{
+	struct tegra_dma_req *req;
+
+	spin_lock(&ch->lock);
+	if (list_empty(&ch->list)) {
+		spin_unlock(&ch->lock);
+		return;
+	}
+
+	req = list_entry(ch->list.next, typeof(*req), node);
+	if (req) {
+		int bytes_transferred;
+
+		bytes_transferred =
+			(ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+		bytes_transferred += 1;
+		bytes_transferred <<= 2;
+
+		list_del(&req->node);
+		req->bytes_transferred = bytes_transferred;
+		req->status = TEGRA_DMA_REQ_SUCCESS;
+
+		spin_unlock(&ch->lock);
+		/* Callback should be called without any lock */
+		pr_debug("%s: transferred %d bytes\n", __func__,
+			req->bytes_transferred);
+		req->complete(req);
+		spin_lock(&ch->lock);
+	}
+
+	if (!list_empty(&ch->list)) {
+		req = list_entry(ch->list.next, typeof(*req), node);
+		/* the complete function we just called may have enqueued
+		   another req, in which case dma has already started */
+		if (req->status != TEGRA_DMA_REQ_INFLIGHT)
+			tegra_dma_update_hw(ch, req);
+	}
+	spin_unlock(&ch->lock);
+}
+
+static void handle_continuous_dma(struct tegra_dma_channel *ch)
+{
+	struct tegra_dma_req *req;
+
+	spin_lock(&ch->lock);
+	if (list_empty(&ch->list)) {
+		spin_unlock(&ch->lock);
+		return;
+	}
+
+	req = list_entry(ch->list.next, typeof(*req), node);
+	if (req) {
+		if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
+			/* Load the next request into the hardware, if available
+			 * */
+			if (!list_is_last(&req->node, &ch->list)) {
+				struct tegra_dma_req *next_req;
+
+				next_req = list_entry(req->node.next,
+					typeof(*next_req), node);
+				tegra_dma_update_hw_partial(ch, next_req);
+			}
+			req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
+			req->status = TEGRA_DMA_REQ_SUCCESS;
+			/* DMA lock is NOT held when callback is called */
+			spin_unlock(&ch->lock);
+			if (likely(req->threshold))
+				req->threshold(req);
+			return;
+
+		} else if (req->buffer_status ==
+			TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) {
+			/* Callback when the buffer is completely full (i.e on
+			 * the second  interrupt */
+			int bytes_transferred;
+
+			bytes_transferred =
+				(ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
+			bytes_transferred += 1;
+			bytes_transferred <<= 3;
+
+			req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
+			req->bytes_transferred = bytes_transferred;
+			req->status = TEGRA_DMA_REQ_SUCCESS;
+			list_del(&req->node);
+
+			/* DMA lock is NOT held when callbak is called */
+			spin_unlock(&ch->lock);
+			req->complete(req);
+			return;
+
+		} else {
+			BUG();
+		}
+	}
+	spin_unlock(&ch->lock);
+}
+
+static irqreturn_t dma_isr(int irq, void *data)
+{
+	struct tegra_dma_channel *ch = data;
+	unsigned long status;
+
+	status = readl(ch->addr + APB_DMA_CHAN_STA);
+	if (status & STA_ISE_EOC)
+		writel(status, ch->addr + APB_DMA_CHAN_STA);
+	else {
+		pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id);
+		return IRQ_HANDLED;
+	}
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t dma_thread_fn(int irq, void *data)
+{
+	struct tegra_dma_channel *ch = data;
+
+	if (ch->mode & TEGRA_DMA_MODE_ONESHOT)
+		handle_oneshot_dma(ch);
+	else
+		handle_continuous_dma(ch);
+
+
+	return IRQ_HANDLED;
+}
+
+int __init tegra_dma_init(void)
+{
+	int ret = 0;
+	int i;
+	unsigned int irq;
+	void __iomem *addr;
+
+	addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+	writel(GEN_ENABLE, addr + APB_DMA_GEN);
+	writel(0, addr + APB_DMA_CNTRL);
+	writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
+	       addr + APB_DMA_IRQ_MASK_SET);
+
+	memset(channel_usage, 0, sizeof(channel_usage));
+	memset(dma_channels, 0, sizeof(dma_channels));
+
+	/* Reserve all the channels we are not supposed to touch */
+	for (i = 0; i < TEGRA_SYSTEM_DMA_CH_MIN; i++)
+		__set_bit(i, channel_usage);
+
+	for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+		struct tegra_dma_channel *ch = &dma_channels[i];
+
+		__clear_bit(i, channel_usage);
+
+		ch->id = i;
+		snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
+
+		ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+			TEGRA_APB_DMA_CH0_SIZE * i);
+
+		spin_lock_init(&ch->lock);
+		INIT_LIST_HEAD(&ch->list);
+		tegra_dma_init_hw(ch);
+
+		irq = INT_APB_DMA_CH0 + i;
+		ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
+			dma_channels[i].name, ch);
+		if (ret) {
+			pr_err("Failed to register IRQ %d for DMA %d\n",
+				irq, i);
+			goto fail;
+		}
+		ch->irq = irq;
+	}
+	/* mark the shared channel allocated */
+	__set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
+
+	for (i = TEGRA_SYSTEM_DMA_CH_MAX+1; i < NV_DMA_MAX_CHANNELS; i++)
+		__set_bit(i, channel_usage);
+
+	return ret;
+fail:
+	writel(0, addr + APB_DMA_GEN);
+	for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
+		struct tegra_dma_channel *ch = &dma_channels[i];
+		if (ch->irq)
+			free_irq(ch->irq, ch);
+	}
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
+
+void tegra_dma_suspend(void)
+{
+	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+	u32 *ctx = apb_dma;
+	int i;
+
+	*ctx++ = readl(addr + APB_DMA_GEN);
+	*ctx++ = readl(addr + APB_DMA_CNTRL);
+	*ctx++ = readl(addr + APB_DMA_IRQ_MASK);
+
+	for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+		addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+				  TEGRA_APB_DMA_CH0_SIZE * i);
+
+		*ctx++ = readl(addr + APB_DMA_CHAN_CSR);
+		*ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR);
+		*ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ);
+		*ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR);
+		*ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ);
+	}
+}
+
+void tegra_dma_resume(void)
+{
+	void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+	u32 *ctx = apb_dma;
+	int i;
+
+	writel(*ctx++, addr + APB_DMA_GEN);
+	writel(*ctx++, addr + APB_DMA_CNTRL);
+	writel(*ctx++, addr + APB_DMA_IRQ_MASK);
+
+	for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) {
+		addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE +
+				  TEGRA_APB_DMA_CH0_SIZE * i);
+
+		writel(*ctx++, addr + APB_DMA_CHAN_CSR);
+		writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR);
+		writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ);
+		writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR);
+		writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ);
+	}
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/fuse.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/fuse.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/fuse.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/fuse.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "fuse.h"
+
+#define FUSE_UID_LOW		0x108
+#define FUSE_UID_HIGH		0x10c
+#define FUSE_SKU_INFO		0x110
+#define FUSE_SPARE_BIT		0x200
+
+static inline u32 fuse_readl(unsigned long offset)
+{
+	return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+static inline void fuse_writel(u32 value, unsigned long offset)
+{
+	writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+}
+
+void tegra_init_fuse(void)
+{
+	u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+	reg |= 1 << 28;
+	writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
+
+	pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
+		tegra_sku_id(), tegra_cpu_process_id(),
+		tegra_core_process_id());
+}
+
+unsigned long long tegra_chip_uid(void)
+{
+	unsigned long long lo, hi;
+
+	lo = fuse_readl(FUSE_UID_LOW);
+	hi = fuse_readl(FUSE_UID_HIGH);
+	return (hi << 32ull) | lo;
+}
+
+int tegra_sku_id(void)
+{
+	int sku_id;
+	u32 reg = fuse_readl(FUSE_SKU_INFO);
+	sku_id = reg & 0xFF;
+	return sku_id;
+}
+
+int tegra_cpu_process_id(void)
+{
+	int cpu_process_id;
+	u32 reg = fuse_readl(FUSE_SPARE_BIT);
+	cpu_process_id = (reg >> 6) & 3;
+	return cpu_process_id;
+}
+
+int tegra_core_process_id(void)
+{
+	int core_process_id;
+	u32 reg = fuse_readl(FUSE_SPARE_BIT);
+	core_process_id = (reg >> 12) & 3;
+	return core_process_id;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/fuse.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/fuse.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/fuse.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/fuse.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,24 @@
+/*
+ * arch/arm/mach-tegra/fuse.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+unsigned long long tegra_chip_uid(void);
+int tegra_sku_id(void);
+int tegra_cpu_process_id(void);
+int tegra_core_process_id(void);
+void tegra_init_fuse(void);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/gpio.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 
 #include <linux/io.h>
 #include <linux/gpio.h>
@@ -60,6 +61,13 @@
 	int bank;
 	int irq;
 	spinlock_t lvl_lock[4];
+#ifdef CONFIG_PM
+	u32 cnf[4];
+	u32 out[4];
+	u32 oe[4];
+	u32 int_enb[4];
+	u32 int_lvl[4];
+#endif
 };
 
 
@@ -131,7 +139,7 @@
 	.direction_output	= tegra_gpio_direction_output,
 	.set			= tegra_gpio_set,
 	.base			= 0,
-	.ngpio			= ARCH_NR_GPIOS,
+	.ngpio			= TEGRA_NR_GPIOS,
 };
 
 static void tegra_gpio_irq_ack(unsigned int irq)
@@ -244,6 +252,76 @@
 
 }
 
+#ifdef CONFIG_PM
+void tegra_gpio_resume(void)
+{
+	unsigned long flags;
+	int b, p, i;
+
+	local_irq_save(flags);
+
+	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+			unsigned int gpio = (b<<5) | (p<<3);
+			__raw_writel(bank->cnf[p], GPIO_CNF(gpio));
+			__raw_writel(bank->out[p], GPIO_OUT(gpio));
+			__raw_writel(bank->oe[p], GPIO_OE(gpio));
+			__raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
+			__raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
+		}
+	}
+
+	local_irq_restore(flags);
+
+	for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+		struct irq_desc *desc = irq_to_desc(i);
+		if (!desc || (desc->status & IRQ_WAKEUP))
+			continue;
+		enable_irq(i);
+	}
+}
+
+void tegra_gpio_suspend(void)
+{
+	unsigned long flags;
+	int b, p, i;
+
+	for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
+		struct irq_desc *desc = irq_to_desc(i);
+		if (!desc)
+			continue;
+		if (desc->status & IRQ_WAKEUP) {
+			int gpio = i - INT_GPIO_BASE;
+			pr_debug("gpio %d.%d is wakeup\n", gpio/8, gpio&7);
+			continue;
+		}
+		disable_irq(i);
+	}
+
+	local_irq_save(flags);
+	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
+		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+
+		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
+			unsigned int gpio = (b<<5) | (p<<3);
+			bank->cnf[p] = __raw_readl(GPIO_CNF(gpio));
+			bank->out[p] = __raw_readl(GPIO_OUT(gpio));
+			bank->oe[p] = __raw_readl(GPIO_OE(gpio));
+			bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
+			bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
+		}
+	}
+	local_irq_restore(flags);
+}
+
+static int tegra_gpio_wake_enable(unsigned int irq, unsigned int enable)
+{
+	struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
+	return set_irq_wake(bank->irq, enable);
+}
+#endif
 
 static struct irq_chip tegra_gpio_irq_chip = {
 	.name		= "GPIO",
@@ -251,6 +329,9 @@
 	.mask		= tegra_gpio_irq_mask,
 	.unmask		= tegra_gpio_irq_unmask,
 	.set_type	= tegra_gpio_irq_set_type,
+#ifdef CONFIG_PM
+	.set_wake	= tegra_gpio_wake_enable,
+#endif
 };
 
 
@@ -274,7 +355,7 @@
 
 	gpiochip_add(&tegra_gpio_chip);
 
-	for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + ARCH_NR_GPIOS); i++) {
+	for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
 		bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
 
 		lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
@@ -312,15 +393,16 @@
 	for (i = 0; i < 7; i++) {
 		for (j = 0; j < 4; j++) {
 			int gpio = tegra_gpio_compose(i, j, 0);
-			seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
-			       i, j,
-			       __raw_readl(GPIO_CNF(gpio)),
-			       __raw_readl(GPIO_OE(gpio)),
-			       __raw_readl(GPIO_OUT(gpio)),
-			       __raw_readl(GPIO_IN(gpio)),
-			       __raw_readl(GPIO_INT_STA(gpio)),
-			       __raw_readl(GPIO_INT_ENB(gpio)),
-			       __raw_readl(GPIO_INT_LVL(gpio)));
+			seq_printf(s,
+				"%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+				i, j,
+				__raw_readl(GPIO_CNF(gpio)),
+				__raw_readl(GPIO_OE(gpio)),
+				__raw_readl(GPIO_OUT(gpio)),
+				__raw_readl(GPIO_IN(gpio)),
+				__raw_readl(GPIO_INT_STA(gpio)),
+				__raw_readl(GPIO_INT_ENB(gpio)),
+				__raw_readl(GPIO_INT_LVL(gpio)));
 		}
 	}
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/clk.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/clk.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/clk.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/clk.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,4 +23,9 @@
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 
+int clk_enable_cansleep(struct clk *clk);
+void clk_disable_cansleep(struct clk *clk);
+int clk_set_rate_cansleep(struct clk *clk, unsigned long rate);
+int clk_set_parent_cansleep(struct clk *clk, struct clk *parent);
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -20,24 +20,28 @@
 
 #include <mach/io.h>
 
-	.macro  addruart,rx, tmp
-        mrc     p15, 0, \rx, c1, c0
-        tst     \rx, #1                 @ MMU enabled?
-        ldreq   \rx, =IO_APB_PHYS       @ physical
-        ldrne   \rx, =IO_APB_VIRT        @ virtual
+	.macro  addruart, rp, rv
+        ldr     \rp, =IO_APB_PHYS       @ physical
+        ldr     \rv, =IO_APB_VIRT        @ virtual
 #if defined(CONFIG_TEGRA_DEBUG_UART_NONE)
 #error "A debug UART must be selected in the kernel config to use DEBUG_LL"
 #elif defined(CONFIG_TEGRA_DEBUG_UARTA)
-        orr     \rx, \rx, #0x6000
+        orr     \rp, \rp, #0x6000
+        orr     \rv, \rv, #0x6000
 #elif defined(CONFIG_TEGRA_DEBUG_UARTB)
-	ldr	\tmp, =0x6040
-        orr     \rx, \rx, \tmp
+        orr     \rp, \rp, #0x6000
+	orr	\rp, \rp, #0x40
+        orr     \rv, \rv, #0x6000
+	orr	\rv, \rv, #0x40
 #elif defined(CONFIG_TEGRA_DEBUG_UARTC)
-        orr     \rx, \rx, #0x6200
+        orr     \rp, \rp, #0x6200
+        orr     \rv, \rv, #0x6200
 #elif defined(CONFIG_TEGRA_DEBUG_UARTD)
-        orr     \rx, \rx, #0x6300
+        orr     \rp, \rp, #0x6300
+        orr     \rv, \rv, #0x6300
 #elif defined(CONFIG_TEGRA_DEBUG_UARTE)
-        orr     \rx, \rx, #0x6400
+        orr     \rp, \rp, #0x6400
+        orr     \rv, \rv, #0x6400
 #endif
 	.endm
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/dma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/mach-tegra/include/mach/dma.h
+ *
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __MACH_TEGRA_DMA_H
+#define __MACH_TEGRA_DMA_H
+
+#include <linux/list.h>
+
+#if defined(CONFIG_TEGRA_SYSTEM_DMA)
+
+struct tegra_dma_req;
+struct tegra_dma_channel;
+
+#define TEGRA_DMA_REQ_SEL_CNTR			0
+#define TEGRA_DMA_REQ_SEL_I2S_2			1
+#define TEGRA_DMA_REQ_SEL_I2S_1			2
+#define TEGRA_DMA_REQ_SEL_SPD_I			3
+#define TEGRA_DMA_REQ_SEL_UI_I			4
+#define TEGRA_DMA_REQ_SEL_MIPI			5
+#define TEGRA_DMA_REQ_SEL_I2S2_2		6
+#define TEGRA_DMA_REQ_SEL_I2S2_1		7
+#define TEGRA_DMA_REQ_SEL_UARTA			8
+#define TEGRA_DMA_REQ_SEL_UARTB			9
+#define TEGRA_DMA_REQ_SEL_UARTC			10
+#define TEGRA_DMA_REQ_SEL_SPI			11
+#define TEGRA_DMA_REQ_SEL_AC97			12
+#define TEGRA_DMA_REQ_SEL_ACMODEM		13
+#define TEGRA_DMA_REQ_SEL_SL4B			14
+#define TEGRA_DMA_REQ_SEL_SL2B1			15
+#define TEGRA_DMA_REQ_SEL_SL2B2			16
+#define TEGRA_DMA_REQ_SEL_SL2B3			17
+#define TEGRA_DMA_REQ_SEL_SL2B4			18
+#define TEGRA_DMA_REQ_SEL_UARTD			19
+#define TEGRA_DMA_REQ_SEL_UARTE			20
+#define TEGRA_DMA_REQ_SEL_I2C			21
+#define TEGRA_DMA_REQ_SEL_I2C2			22
+#define TEGRA_DMA_REQ_SEL_I2C3			23
+#define TEGRA_DMA_REQ_SEL_DVC_I2C		24
+#define TEGRA_DMA_REQ_SEL_OWR			25
+#define TEGRA_DMA_REQ_SEL_INVALID		31
+
+enum tegra_dma_mode {
+	TEGRA_DMA_SHARED = 1,
+	TEGRA_DMA_MODE_CONTINOUS = 2,
+	TEGRA_DMA_MODE_ONESHOT = 4,
+};
+
+enum tegra_dma_req_error {
+	TEGRA_DMA_REQ_SUCCESS = 0,
+	TEGRA_DMA_REQ_ERROR_ABORTED,
+	TEGRA_DMA_REQ_INFLIGHT,
+};
+
+enum tegra_dma_req_buff_status {
+	TEGRA_DMA_REQ_BUF_STATUS_EMPTY = 0,
+	TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL,
+	TEGRA_DMA_REQ_BUF_STATUS_FULL,
+};
+
+struct tegra_dma_req {
+	struct list_head node;
+	unsigned int modid;
+	int instance;
+
+	/* Called when the req is complete and from the DMA ISR context.
+	 * When this is called the req structure is no longer queued by
+	 * the DMA channel.
+	 *
+	 * State of the DMA depends on the number of req it has. If there are
+	 * no DMA requests queued up, then it will STOP the DMA. It there are
+	 * more requests in the DMA, then it will queue the next request.
+	 */
+	void (*complete)(struct tegra_dma_req *req);
+
+	/*  This is a called from the DMA ISR context when the DMA is still in
+	 *  progress and is actively filling same buffer.
+	 *
+	 *  In case of continous mode receive, this threshold is 1/2 the buffer
+	 *  size. In other cases, this will not even be called as there is no
+	 *  hardware support for it.
+	 *
+	 * In the case of continous mode receive, if there is next req already
+	 * queued, DMA programs the HW to use that req when this req is
+	 * completed. If there is no "next req" queued, then DMA ISR doesn't do
+	 * anything before calling this callback.
+	 *
+	 *	This is mainly used by the cases, where the clients has queued
+	 *	only one req and want to get some sort of DMA threshold
+	 *	callback to program the next buffer.
+	 *
+	 */
+	void (*threshold)(struct tegra_dma_req *req);
+
+	/* 1 to copy to memory.
+	 * 0 to copy from the memory to device FIFO */
+	int to_memory;
+
+	void *virt_addr;
+
+	unsigned long source_addr;
+	unsigned long dest_addr;
+	unsigned long dest_wrap;
+	unsigned long source_wrap;
+	unsigned long source_bus_width;
+	unsigned long dest_bus_width;
+	unsigned long req_sel;
+	unsigned int size;
+
+	/* Updated by the DMA driver on the conpletion of the request. */
+	int bytes_transferred;
+	int status;
+
+	/* DMA completion tracking information */
+	int buffer_status;
+
+	/* Client specific data */
+	void *dev;
+};
+
+int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req);
+int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req);
+void tegra_dma_dequeue(struct tegra_dma_channel *ch);
+void tegra_dma_flush(struct tegra_dma_channel *ch);
+
+bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch,
+	struct tegra_dma_req *req);
+bool tegra_dma_is_empty(struct tegra_dma_channel *ch);
+
+struct tegra_dma_channel *tegra_dma_allocate_channel(int mode);
+void tegra_dma_free_channel(struct tegra_dma_channel *ch);
+
+int __init tegra_dma_init(void);
+
+#endif
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/gpio.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -22,7 +22,7 @@
 
 #include <mach/irqs.h>
 
-#define ARCH_NR_GPIOS		INT_GPIO_NR
+#define TEGRA_NR_GPIOS		INT_GPIO_NR
 
 #include <asm-generic/gpio.h>
 
@@ -35,7 +35,7 @@
 
 static inline int gpio_to_irq(unsigned int gpio)
 {
-	if (gpio < ARCH_NR_GPIOS)
+	if (gpio < TEGRA_NR_GPIOS)
 		return INT_GPIO_BASE + gpio;
 	return -EINVAL;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/hardware.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/hardware.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/hardware.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,4 +21,8 @@
 #ifndef __MACH_TEGRA_HARDWARE_H
 #define __MACH_TEGRA_HARDWARE_H
 
+#define PCIBIOS_MIN_IO			0x1000
+#define PCIBIOS_MIN_MEM			0
+#define pcibios_assign_all_busses()	1
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/io.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/io.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,7 @@
 #ifndef __MACH_TEGRA_IO_H
 #define __MACH_TEGRA_IO_H
 
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
 
 /* On TEGRA, many peripherals are very closely packed in
  * two 256MB io windows (that actually only use about 64KB
@@ -33,6 +33,10 @@
  *
  */
 
+#define IO_IRAM_PHYS	0x40000000
+#define IO_IRAM_VIRT	0xFE400000
+#define IO_IRAM_SIZE	SZ_256K
+
 #define IO_CPU_PHYS     0x50040000
 #define IO_CPU_VIRT     0xFE000000
 #define IO_CPU_SIZE	SZ_16K
@@ -55,6 +59,8 @@
 		IO_TO_VIRT_XLATE((n), IO_APB_PHYS, IO_APB_VIRT) :	\
 	IO_TO_VIRT_BETWEEN((n), IO_CPU_PHYS, IO_CPU_SIZE) ?		\
 		IO_TO_VIRT_XLATE((n), IO_CPU_PHYS, IO_CPU_VIRT) :	\
+	IO_TO_VIRT_BETWEEN((n), IO_IRAM_PHYS, IO_IRAM_SIZE) ?		\
+		IO_TO_VIRT_XLATE((n), IO_IRAM_PHYS, IO_IRAM_VIRT) :	\
 	0)
 
 #ifndef __ASSEMBLER__
@@ -67,10 +73,20 @@
 
 #define IO_ADDRESS(n) ((void __iomem *) IO_TO_VIRT(n))
 
+#ifdef CONFIG_TEGRA_PCI
+extern void __iomem *tegra_pcie_io_base;
+
+static inline void __iomem *__io(unsigned long addr)
+{
+	return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
+}
+#else
 static inline void __iomem *__io(unsigned long addr)
 {
 	return (void __iomem *)addr;
 }
+#endif
+
 #define __io(a)         __io(a)
 #define __mem_pci(a)    (a)
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/iomap.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/iomap.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/iomap.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/iomap.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,9 +23,15 @@
 
 #include <asm/sizes.h>
 
+#define TEGRA_IRAM_BASE			0x40000000
+#define TEGRA_IRAM_SIZE			SZ_256K
+
 #define TEGRA_ARM_PERIF_BASE		0x50040000
 #define TEGRA_ARM_PERIF_SIZE		SZ_8K
 
+#define TEGRA_ARM_PL310_BASE		0x50043000
+#define TEGRA_ARM_PL310_SIZE		SZ_4K
+
 #define TEGRA_ARM_INT_DIST_BASE		0x50041000
 #define TEGRA_ARM_INT_DIST_SIZE		SZ_4K
 
@@ -68,7 +74,22 @@
 #define TEGRA_FLOW_CTRL_BASE		0x60007000
 #define TEGRA_FLOW_CTRL_SIZE		20
 
-#define TEGRA_STATMON_BASE		0x6000C4000
+#define TEGRA_AHB_DMA_BASE		0x60008000
+#define TEGRA_AHB_DMA_SIZE		SZ_4K
+
+#define TEGRA_AHB_DMA_CH0_BASE		0x60009000
+#define TEGRA_AHB_DMA_CH0_SIZE		32
+
+#define TEGRA_APB_DMA_BASE		0x6000A000
+#define TEGRA_APB_DMA_SIZE		SZ_4K
+
+#define TEGRA_APB_DMA_CH0_BASE		0x6000B000
+#define TEGRA_APB_DMA_CH0_SIZE		32
+
+#define TEGRA_AHB_GIZMO_BASE		0x6000C004
+#define TEGRA_AHB_GIZMO_SIZE		0x10C
+
+#define TEGRA_STATMON_BASE		0x6000C400
 #define TEGRA_STATMON_SIZE		SZ_1K
 
 #define TEGRA_GPIO_BASE			0x6000D000
@@ -137,7 +158,7 @@
 #define TEGRA_I2C3_BASE			0x7000C500
 #define TEGRA_I2C3_SIZE			SZ_256
 
-#define TEGRA_OWR_BASE			0x7000D000
+#define TEGRA_OWR_BASE			0x7000C600
 #define TEGRA_OWR_SIZE			80
 
 #define TEGRA_DVC_BASE			0x7000D000
@@ -182,12 +203,12 @@
 #define TEGRA_USB_BASE			0xC5000000
 #define TEGRA_USB_SIZE			SZ_16K
 
-#define TEGRA_USB1_BASE			0xC5004000
-#define TEGRA_USB1_SIZE			SZ_16K
-
-#define TEGRA_USB2_BASE			0xC5008000
+#define TEGRA_USB2_BASE			0xC5004000
 #define TEGRA_USB2_SIZE			SZ_16K
 
+#define TEGRA_USB3_BASE			0xC5008000
+#define TEGRA_USB3_SIZE			SZ_16K
+
 #define TEGRA_SDMMC1_BASE		0xC8000000
 #define TEGRA_SDMMC1_SIZE		SZ_512
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 
 #define IRQ_LOCALTIMER                  29
 
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
 /* Primary Interrupt Controller */
 #define INT_PRI_BASE			(INT_GIC_BASE + 32)
 #define INT_TMR1			(INT_PRI_BASE + 0)
@@ -169,5 +170,6 @@
 #define INT_GPIO_NR			(28 * 8)
 
 #define NR_IRQS				(INT_GPIO_BASE + INT_GPIO_NR)
+#endif
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/legacy_irq.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/legacy_irq.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/legacy_irq.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/legacy_irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-tegra/include/mach/legacy_irq.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
+
+void tegra_legacy_mask_irq(unsigned int irq);
+void tegra_legacy_unmask_irq(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+void tegra_legacy_force_irq_set(unsigned int irq);
+void tegra_legacy_force_irq_clr(unsigned int irq);
+int tegra_legacy_force_irq_status(unsigned int irq);
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
+unsigned long tegra_legacy_vfiq(int nr);
+unsigned long tegra_legacy_class(int nr);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/pinmux.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/pinmux.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/pinmux.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/pinmux.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,126 +17,11 @@
 #ifndef __MACH_TEGRA_PINMUX_H
 #define __MACH_TEGRA_PINMUX_H
 
-enum tegra_pingroup {
-	TEGRA_PINGROUP_ATA = 0,
-	TEGRA_PINGROUP_ATB,
-	TEGRA_PINGROUP_ATC,
-	TEGRA_PINGROUP_ATD,
-	TEGRA_PINGROUP_ATE,
-	TEGRA_PINGROUP_CDEV1,
-	TEGRA_PINGROUP_CDEV2,
-	TEGRA_PINGROUP_CRTP,
-	TEGRA_PINGROUP_CSUS,
-	TEGRA_PINGROUP_DAP1,
-	TEGRA_PINGROUP_DAP2,
-	TEGRA_PINGROUP_DAP3,
-	TEGRA_PINGROUP_DAP4,
-	TEGRA_PINGROUP_DDC,
-	TEGRA_PINGROUP_DTA,
-	TEGRA_PINGROUP_DTB,
-	TEGRA_PINGROUP_DTC,
-	TEGRA_PINGROUP_DTD,
-	TEGRA_PINGROUP_DTE,
-	TEGRA_PINGROUP_DTF,
-	TEGRA_PINGROUP_GMA,
-	TEGRA_PINGROUP_GMB,
-	TEGRA_PINGROUP_GMC,
-	TEGRA_PINGROUP_GMD,
-	TEGRA_PINGROUP_GME,
-	TEGRA_PINGROUP_GPU,
-	TEGRA_PINGROUP_GPU7,
-	TEGRA_PINGROUP_GPV,
-	TEGRA_PINGROUP_HDINT,
-	TEGRA_PINGROUP_I2CP,
-	TEGRA_PINGROUP_IRRX,
-	TEGRA_PINGROUP_IRTX,
-	TEGRA_PINGROUP_KBCA,
-	TEGRA_PINGROUP_KBCB,
-	TEGRA_PINGROUP_KBCC,
-	TEGRA_PINGROUP_KBCD,
-	TEGRA_PINGROUP_KBCE,
-	TEGRA_PINGROUP_KBCF,
-	TEGRA_PINGROUP_LCSN,
-	TEGRA_PINGROUP_LD0,
-	TEGRA_PINGROUP_LD1,
-	TEGRA_PINGROUP_LD10,
-	TEGRA_PINGROUP_LD11,
-	TEGRA_PINGROUP_LD12,
-	TEGRA_PINGROUP_LD13,
-	TEGRA_PINGROUP_LD14,
-	TEGRA_PINGROUP_LD15,
-	TEGRA_PINGROUP_LD16,
-	TEGRA_PINGROUP_LD17,
-	TEGRA_PINGROUP_LD2,
-	TEGRA_PINGROUP_LD3,
-	TEGRA_PINGROUP_LD4,
-	TEGRA_PINGROUP_LD5,
-	TEGRA_PINGROUP_LD6,
-	TEGRA_PINGROUP_LD7,
-	TEGRA_PINGROUP_LD8,
-	TEGRA_PINGROUP_LD9,
-	TEGRA_PINGROUP_LDC,
-	TEGRA_PINGROUP_LDI,
-	TEGRA_PINGROUP_LHP0,
-	TEGRA_PINGROUP_LHP1,
-	TEGRA_PINGROUP_LHP2,
-	TEGRA_PINGROUP_LHS,
-	TEGRA_PINGROUP_LM0,
-	TEGRA_PINGROUP_LM1,
-	TEGRA_PINGROUP_LPP,
-	TEGRA_PINGROUP_LPW0,
-	TEGRA_PINGROUP_LPW1,
-	TEGRA_PINGROUP_LPW2,
-	TEGRA_PINGROUP_LSC0,
-	TEGRA_PINGROUP_LSC1,
-	TEGRA_PINGROUP_LSCK,
-	TEGRA_PINGROUP_LSDA,
-	TEGRA_PINGROUP_LSDI,
-	TEGRA_PINGROUP_LSPI,
-	TEGRA_PINGROUP_LVP0,
-	TEGRA_PINGROUP_LVP1,
-	TEGRA_PINGROUP_LVS,
-	TEGRA_PINGROUP_OWC,
-	TEGRA_PINGROUP_PMC,
-	TEGRA_PINGROUP_PTA,
-	TEGRA_PINGROUP_RM,
-	TEGRA_PINGROUP_SDB,
-	TEGRA_PINGROUP_SDC,
-	TEGRA_PINGROUP_SDD,
-	TEGRA_PINGROUP_SDIO1,
-	TEGRA_PINGROUP_SLXA,
-	TEGRA_PINGROUP_SLXC,
-	TEGRA_PINGROUP_SLXD,
-	TEGRA_PINGROUP_SLXK,
-	TEGRA_PINGROUP_SPDI,
-	TEGRA_PINGROUP_SPDO,
-	TEGRA_PINGROUP_SPIA,
-	TEGRA_PINGROUP_SPIB,
-	TEGRA_PINGROUP_SPIC,
-	TEGRA_PINGROUP_SPID,
-	TEGRA_PINGROUP_SPIE,
-	TEGRA_PINGROUP_SPIF,
-	TEGRA_PINGROUP_SPIG,
-	TEGRA_PINGROUP_SPIH,
-	TEGRA_PINGROUP_UAA,
-	TEGRA_PINGROUP_UAB,
-	TEGRA_PINGROUP_UAC,
-	TEGRA_PINGROUP_UAD,
-	TEGRA_PINGROUP_UCA,
-	TEGRA_PINGROUP_UCB,
-	TEGRA_PINGROUP_UDA,
-	/* these pin groups only have pullup and pull down control */
-	TEGRA_PINGROUP_CK32,
-	TEGRA_PINGROUP_DDRC,
-	TEGRA_PINGROUP_PMCA,
-	TEGRA_PINGROUP_PMCB,
-	TEGRA_PINGROUP_PMCC,
-	TEGRA_PINGROUP_PMCD,
-	TEGRA_PINGROUP_PMCE,
-	TEGRA_PINGROUP_XM2C,
-	TEGRA_PINGROUP_XM2D,
-	TEGRA_MAX_PINGROUP,
-};
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#include "pinmux-t2.h"
+#else
+#error "Undefined Tegra architecture"
+#endif
 
 enum tegra_mux_func {
 	TEGRA_MUX_RSVD = 0x8000,
@@ -205,6 +90,7 @@
 	TEGRA_MUX_VI,
 	TEGRA_MUX_VI_SENSOR_CLK,
 	TEGRA_MUX_XIO,
+	TEGRA_MUX_SAFE,
 	TEGRA_MAX_MUX,
 };
 
@@ -219,6 +105,18 @@
 	TEGRA_TRI_TRISTATE = 1,
 };
 
+enum tegra_vddio {
+	TEGRA_VDDIO_BB = 0,
+	TEGRA_VDDIO_LCD,
+	TEGRA_VDDIO_VI,
+	TEGRA_VDDIO_UART,
+	TEGRA_VDDIO_DDR,
+	TEGRA_VDDIO_NAND,
+	TEGRA_VDDIO_SYS,
+	TEGRA_VDDIO_AUDIO,
+	TEGRA_VDDIO_SD,
+};
+
 struct tegra_pingroup_config {
 	enum tegra_pingroup	pingroup;
 	enum tegra_mux_func	func;
@@ -270,38 +168,6 @@
 	TEGRA_MAX_PULL,
 };
 
-enum tegra_drive_pingroup {
-	TEGRA_DRIVE_PINGROUP_AO1 = 0,
-	TEGRA_DRIVE_PINGROUP_AO2,
-	TEGRA_DRIVE_PINGROUP_AT1,
-	TEGRA_DRIVE_PINGROUP_AT2,
-	TEGRA_DRIVE_PINGROUP_CDEV1,
-	TEGRA_DRIVE_PINGROUP_CDEV2,
-	TEGRA_DRIVE_PINGROUP_CSUS,
-	TEGRA_DRIVE_PINGROUP_DAP1,
-	TEGRA_DRIVE_PINGROUP_DAP2,
-	TEGRA_DRIVE_PINGROUP_DAP3,
-	TEGRA_DRIVE_PINGROUP_DAP4,
-	TEGRA_DRIVE_PINGROUP_DBG,
-	TEGRA_DRIVE_PINGROUP_LCD1,
-	TEGRA_DRIVE_PINGROUP_LCD2,
-	TEGRA_DRIVE_PINGROUP_SDMMC2,
-	TEGRA_DRIVE_PINGROUP_SDMMC3,
-	TEGRA_DRIVE_PINGROUP_SPI,
-	TEGRA_DRIVE_PINGROUP_UAA,
-	TEGRA_DRIVE_PINGROUP_UAB,
-	TEGRA_DRIVE_PINGROUP_UART2,
-	TEGRA_DRIVE_PINGROUP_UART3,
-	TEGRA_DRIVE_PINGROUP_VI1,
-	TEGRA_DRIVE_PINGROUP_VI2,
-	TEGRA_DRIVE_PINGROUP_XM2A,
-	TEGRA_DRIVE_PINGROUP_XM2C,
-	TEGRA_DRIVE_PINGROUP_XM2D,
-	TEGRA_DRIVE_PINGROUP_XM2CLK,
-	TEGRA_DRIVE_PINGROUP_MEMCOMP,
-	TEGRA_MAX_DRIVE_PINGROUP,
-};
-
 enum tegra_drive {
 	TEGRA_DRIVE_DIV_8 = 0,
 	TEGRA_DRIVE_DIV_4,
@@ -331,18 +197,44 @@
 	enum tegra_slew slew_falling;
 };
 
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func);
-int tegra_pinmux_set_tristate(enum tegra_pingroup pg, enum tegra_tristate tristate);
-int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg, enum tegra_pullupdown pupd);
+struct tegra_drive_pingroup_desc {
+	const char *name;
+	s16 reg;
+};
 
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
-	enum tegra_mux_func func, enum tegra_pullupdown pupd,
+struct tegra_pingroup_desc {
+	const char *name;
+	int funcs[4];
+	int func_safe;
+	int vddio;
+	s16 tri_reg; 	/* offset into the TRISTATE_REG_* register bank */
+	s16 mux_reg;	/* offset into the PIN_MUX_CTL_* register bank */
+	s16 pupd_reg;	/* offset into the PULL_UPDOWN_REG_* register bank */
+	s8 tri_bit; 	/* offset into the TRISTATE_REG_* register bit */
+	s8 mux_bit;	/* offset into the PIN_MUX_CTL_* register bit */
+	s8 pupd_bit;	/* offset into the PULL_UPDOWN_REG_* register bit */
+};
+
+extern const struct tegra_pingroup_desc tegra_soc_pingroups[];
+extern const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[];
+
+int tegra_pinmux_set_tristate(enum tegra_pingroup pg,
 	enum tegra_tristate tristate);
+int tegra_pinmux_set_pullupdown(enum tegra_pingroup pg,
+	enum tegra_pullupdown pupd);
 
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len);
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config,
+	int len);
 
 void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
 	int len);
-
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+	int len);
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+	int len);
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+	int len, enum tegra_tristate tristate);
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+	int len, enum tegra_pullupdown pupd);
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/pinmux-t2.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/pinmux-t2.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/pinmux-t2.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/pinmux-t2.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,174 @@
+/*
+ * linux/arch/arm/mach-tegra/include/mach/pinmux-t2.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_PINMUX_T2_H
+#define __MACH_TEGRA_PINMUX_T2_H
+
+enum tegra_pingroup {
+	TEGRA_PINGROUP_ATA = 0,
+	TEGRA_PINGROUP_ATB,
+	TEGRA_PINGROUP_ATC,
+	TEGRA_PINGROUP_ATD,
+	TEGRA_PINGROUP_ATE,
+	TEGRA_PINGROUP_CDEV1,
+	TEGRA_PINGROUP_CDEV2,
+	TEGRA_PINGROUP_CRTP,
+	TEGRA_PINGROUP_CSUS,
+	TEGRA_PINGROUP_DAP1,
+	TEGRA_PINGROUP_DAP2,
+	TEGRA_PINGROUP_DAP3,
+	TEGRA_PINGROUP_DAP4,
+	TEGRA_PINGROUP_DDC,
+	TEGRA_PINGROUP_DTA,
+	TEGRA_PINGROUP_DTB,
+	TEGRA_PINGROUP_DTC,
+	TEGRA_PINGROUP_DTD,
+	TEGRA_PINGROUP_DTE,
+	TEGRA_PINGROUP_DTF,
+	TEGRA_PINGROUP_GMA,
+	TEGRA_PINGROUP_GMB,
+	TEGRA_PINGROUP_GMC,
+	TEGRA_PINGROUP_GMD,
+	TEGRA_PINGROUP_GME,
+	TEGRA_PINGROUP_GPU,
+	TEGRA_PINGROUP_GPU7,
+	TEGRA_PINGROUP_GPV,
+	TEGRA_PINGROUP_HDINT,
+	TEGRA_PINGROUP_I2CP,
+	TEGRA_PINGROUP_IRRX,
+	TEGRA_PINGROUP_IRTX,
+	TEGRA_PINGROUP_KBCA,
+	TEGRA_PINGROUP_KBCB,
+	TEGRA_PINGROUP_KBCC,
+	TEGRA_PINGROUP_KBCD,
+	TEGRA_PINGROUP_KBCE,
+	TEGRA_PINGROUP_KBCF,
+	TEGRA_PINGROUP_LCSN,
+	TEGRA_PINGROUP_LD0,
+	TEGRA_PINGROUP_LD1,
+	TEGRA_PINGROUP_LD10,
+	TEGRA_PINGROUP_LD11,
+	TEGRA_PINGROUP_LD12,
+	TEGRA_PINGROUP_LD13,
+	TEGRA_PINGROUP_LD14,
+	TEGRA_PINGROUP_LD15,
+	TEGRA_PINGROUP_LD16,
+	TEGRA_PINGROUP_LD17,
+	TEGRA_PINGROUP_LD2,
+	TEGRA_PINGROUP_LD3,
+	TEGRA_PINGROUP_LD4,
+	TEGRA_PINGROUP_LD5,
+	TEGRA_PINGROUP_LD6,
+	TEGRA_PINGROUP_LD7,
+	TEGRA_PINGROUP_LD8,
+	TEGRA_PINGROUP_LD9,
+	TEGRA_PINGROUP_LDC,
+	TEGRA_PINGROUP_LDI,
+	TEGRA_PINGROUP_LHP0,
+	TEGRA_PINGROUP_LHP1,
+	TEGRA_PINGROUP_LHP2,
+	TEGRA_PINGROUP_LHS,
+	TEGRA_PINGROUP_LM0,
+	TEGRA_PINGROUP_LM1,
+	TEGRA_PINGROUP_LPP,
+	TEGRA_PINGROUP_LPW0,
+	TEGRA_PINGROUP_LPW1,
+	TEGRA_PINGROUP_LPW2,
+	TEGRA_PINGROUP_LSC0,
+	TEGRA_PINGROUP_LSC1,
+	TEGRA_PINGROUP_LSCK,
+	TEGRA_PINGROUP_LSDA,
+	TEGRA_PINGROUP_LSDI,
+	TEGRA_PINGROUP_LSPI,
+	TEGRA_PINGROUP_LVP0,
+	TEGRA_PINGROUP_LVP1,
+	TEGRA_PINGROUP_LVS,
+	TEGRA_PINGROUP_OWC,
+	TEGRA_PINGROUP_PMC,
+	TEGRA_PINGROUP_PTA,
+	TEGRA_PINGROUP_RM,
+	TEGRA_PINGROUP_SDB,
+	TEGRA_PINGROUP_SDC,
+	TEGRA_PINGROUP_SDD,
+	TEGRA_PINGROUP_SDIO1,
+	TEGRA_PINGROUP_SLXA,
+	TEGRA_PINGROUP_SLXC,
+	TEGRA_PINGROUP_SLXD,
+	TEGRA_PINGROUP_SLXK,
+	TEGRA_PINGROUP_SPDI,
+	TEGRA_PINGROUP_SPDO,
+	TEGRA_PINGROUP_SPIA,
+	TEGRA_PINGROUP_SPIB,
+	TEGRA_PINGROUP_SPIC,
+	TEGRA_PINGROUP_SPID,
+	TEGRA_PINGROUP_SPIE,
+	TEGRA_PINGROUP_SPIF,
+	TEGRA_PINGROUP_SPIG,
+	TEGRA_PINGROUP_SPIH,
+	TEGRA_PINGROUP_UAA,
+	TEGRA_PINGROUP_UAB,
+	TEGRA_PINGROUP_UAC,
+	TEGRA_PINGROUP_UAD,
+	TEGRA_PINGROUP_UCA,
+	TEGRA_PINGROUP_UCB,
+	TEGRA_PINGROUP_UDA,
+	/* these pin groups only have pullup and pull down control */
+	TEGRA_PINGROUP_CK32,
+	TEGRA_PINGROUP_DDRC,
+	TEGRA_PINGROUP_PMCA,
+	TEGRA_PINGROUP_PMCB,
+	TEGRA_PINGROUP_PMCC,
+	TEGRA_PINGROUP_PMCD,
+	TEGRA_PINGROUP_PMCE,
+	TEGRA_PINGROUP_XM2C,
+	TEGRA_PINGROUP_XM2D,
+	TEGRA_MAX_PINGROUP,
+};
+
+enum tegra_drive_pingroup {
+	TEGRA_DRIVE_PINGROUP_AO1 = 0,
+	TEGRA_DRIVE_PINGROUP_AO2,
+	TEGRA_DRIVE_PINGROUP_AT1,
+	TEGRA_DRIVE_PINGROUP_AT2,
+	TEGRA_DRIVE_PINGROUP_CDEV1,
+	TEGRA_DRIVE_PINGROUP_CDEV2,
+	TEGRA_DRIVE_PINGROUP_CSUS,
+	TEGRA_DRIVE_PINGROUP_DAP1,
+	TEGRA_DRIVE_PINGROUP_DAP2,
+	TEGRA_DRIVE_PINGROUP_DAP3,
+	TEGRA_DRIVE_PINGROUP_DAP4,
+	TEGRA_DRIVE_PINGROUP_DBG,
+	TEGRA_DRIVE_PINGROUP_LCD1,
+	TEGRA_DRIVE_PINGROUP_LCD2,
+	TEGRA_DRIVE_PINGROUP_SDMMC2,
+	TEGRA_DRIVE_PINGROUP_SDMMC3,
+	TEGRA_DRIVE_PINGROUP_SPI,
+	TEGRA_DRIVE_PINGROUP_UAA,
+	TEGRA_DRIVE_PINGROUP_UAB,
+	TEGRA_DRIVE_PINGROUP_UART2,
+	TEGRA_DRIVE_PINGROUP_UART3,
+	TEGRA_DRIVE_PINGROUP_VI1,
+	TEGRA_DRIVE_PINGROUP_VI2,
+	TEGRA_DRIVE_PINGROUP_XM2A,
+	TEGRA_DRIVE_PINGROUP_XM2C,
+	TEGRA_DRIVE_PINGROUP_XM2D,
+	TEGRA_DRIVE_PINGROUP_XM2CLK,
+	TEGRA_DRIVE_PINGROUP_MEMCOMP,
+	TEGRA_MAX_DRIVE_PINGROUP,
+};
+
+#endif
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/include/mach/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,16 +1,8 @@
 #ifndef ASMARM_ARCH_SMP_H
 #define ASMARM_ARCH_SMP_H
 
-
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()			\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x0F;				\
-	})
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/io.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/io.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/io.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,6 +49,12 @@
 		.length = IO_CPU_SIZE,
 		.type = MT_DEVICE,
 	},
+	{
+		.virtual = IO_IRAM_VIRT,
+		.pfn = __phys_to_pfn(IO_IRAM_PHYS),
+		.length = IO_IRAM_SIZE,
+		.type = MT_DEVICE,
+	},
 };
 
 void __init tegra_map_common_io(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/irq.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,8 @@
  * Author:
  *	Colin Cross <ccross@google.com>
  *
+ * Copyright (C) 2010, NVIDIA Corporation
+ *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
@@ -27,8 +29,143 @@
 
 #include "board.h"
 
+#define INT_SYS_NR	(INT_GPIO_BASE - INT_PRI_BASE)
+#define INT_SYS_SZ	(INT_SEC_BASE - INT_PRI_BASE)
+#define PPI_NR		((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
+
+#define APBDMA_IRQ_STA_CPU  0x14
+#define APBDMA_IRQ_MASK_SET 0x20
+#define APBDMA_IRQ_MASK_CLR 0x24
+
+#define ICTLR_CPU_IER		0x20
+#define ICTLR_CPU_IER_SET	0x24
+#define ICTLR_CPU_IER_CLR	0x28
+#define ICTLR_CPU_IEP_CLASS	0x2c
+#define ICTLR_COP_IER		0x30
+#define ICTLR_COP_IER_SET	0x34
+#define ICTLR_COP_IER_CLR	0x38
+#define ICTLR_COP_IEP_CLASS	0x3c
+
+static void (*gic_mask_irq)(unsigned int irq);
+static void (*gic_unmask_irq)(unsigned int irq);
+
+#define irq_to_ictlr(irq) (((irq)-32) >> 5)
+static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
+#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr)*0x100)
+
+static void tegra_mask(unsigned int irq)
+{
+	void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+	gic_mask_irq(irq);
+	writel(1<<(irq&31), addr+ICTLR_CPU_IER_CLR);
+}
+
+static void tegra_unmask(unsigned int irq)
+{
+	void __iomem *addr = ictlr_to_virt(irq_to_ictlr(irq));
+	gic_unmask_irq(irq);
+	writel(1<<(irq&31), addr+ICTLR_CPU_IER_SET);
+}
+
+#ifdef CONFIG_PM
+
+static int tegra_set_wake(unsigned int irq, unsigned int on)
+{
+	return 0;
+}
+#endif
+
+static struct irq_chip tegra_irq = {
+	.name		= "PPI",
+	.mask		= tegra_mask,
+	.unmask		= tegra_unmask,
+#ifdef CONFIG_PM
+	.set_wake	= tegra_set_wake,
+#endif
+};
+
 void __init tegra_init_irq(void)
 {
+	struct irq_chip *gic;
+	unsigned int i;
+
+	for (i = 0; i < PPI_NR; i++) {
+		writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
+		writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
+	}
+
 	gic_dist_init(0, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), 29);
 	gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
+
+	gic = get_irq_chip(29);
+	gic_unmask_irq = gic->unmask;
+	gic_mask_irq = gic->mask;
+	tegra_irq.ack = gic->ack;
+#ifdef CONFIG_SMP
+	tegra_irq.set_affinity = gic->set_affinity;
+#endif
+
+	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+		set_irq_chip(i, &tegra_irq);
+		set_irq_handler(i, handle_level_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+}
+
+#ifdef CONFIG_PM
+static u32 cop_ier[PPI_NR];
+static u32 cpu_ier[PPI_NR];
+static u32 cpu_iep[PPI_NR];
+
+void tegra_irq_suspend(void)
+{
+	unsigned long flags;
+	int i;
+
+	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+		struct irq_desc *desc = irq_to_desc(i);
+		if (!desc)
+			continue;
+		if (desc->status & IRQ_WAKEUP) {
+			pr_debug("irq %d is wakeup\n", i);
+			continue;
+		}
+		disable_irq(i);
+	}
+
+	local_irq_save(flags);
+	for (i = 0; i < PPI_NR; i++) {
+		void __iomem *ictlr = ictlr_to_virt(i);
+		cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
+		cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
+		cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
+		writel(~0, ictlr + ICTLR_COP_IER_CLR);
+	}
+	local_irq_restore(flags);
+}
+
+void tegra_irq_resume(void)
+{
+	unsigned long flags;
+	int i;
+
+	local_irq_save(flags);
+	for (i = 0; i < PPI_NR; i++) {
+		void __iomem *ictlr = ictlr_to_virt(i);
+		writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
+		writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
+		writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
+		writel(0, ictlr + ICTLR_COP_IEP_CLASS);
+		writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
+		writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
+	}
+	local_irq_restore(flags);
+
+	for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
+		struct irq_desc *desc = irq_to_desc(i);
+		if (!desc || (desc->status & IRQ_WAKEUP))
+			continue;
+		enable_irq(i);
+	}
 }
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-tegra/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,10 @@
 
 endchoice
 
+config TEGRA_PCI
+	bool "PCI Express support"
+	select PCI
+
 comment "Tegra board type"
 
 config MACH_HARMONY
@@ -47,4 +51,11 @@
 
 endchoice
 
+config TEGRA_SYSTEM_DMA
+	bool "Enable system DMA driver for NVIDIA Tegra SoCs"
+	default y
+	help
+	  Adds system DMA functionality for NVIDIA Tegra SoCs, used by
+	  several Tegra device drivers
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/legacy_irq.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/legacy_irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/legacy_irq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/legacy_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,114 @@
+/*
+ * arch/arm/mach-tegra/legacy_irq.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <mach/iomap.h>
+#include <mach/legacy_irq.h>
+
+#define ICTLR_CPU_IER		0x20
+#define ICTLR_CPU_IER_SET	0x24
+#define ICTLR_CPU_IER_CLR	0x28
+#define ICTLR_CPU_IEP_CLASS	0x2C
+#define ICTLR_CPU_IEP_VFIQ	0x08
+#define ICTLR_CPU_IEP_FIR	0x14
+#define ICTLR_CPU_IEP_FIR_SET	0x18
+#define ICTLR_CPU_IEP_FIR_CLR	0x1c
+
+static void __iomem *ictlr_reg_base[] = {
+	IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
+	IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
+	IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
+	IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+};
+
+/* When going into deep sleep, the CPU is powered down, taking the GIC with it
+   In order to wake, the wake interrupts need to be enabled in the legacy
+   interrupt controller. */
+void tegra_legacy_unmask_irq(unsigned int irq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	writel(1 << (irq & 31), base + ICTLR_CPU_IER_SET);
+}
+
+void tegra_legacy_mask_irq(unsigned int irq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	writel(1 << (irq & 31), base + ICTLR_CPU_IER_CLR);
+}
+
+void tegra_legacy_force_irq_set(unsigned int irq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_SET);
+}
+
+void tegra_legacy_force_irq_clr(unsigned int irq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_CLR);
+}
+
+int tegra_legacy_force_irq_status(unsigned int irq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	return !!(readl(base + ICTLR_CPU_IEP_FIR) & (1 << (irq & 31)));
+}
+
+void tegra_legacy_select_fiq(unsigned int irq, bool fiq)
+{
+	void __iomem *base;
+	pr_debug("%s: %d\n", __func__, irq);
+
+	irq -= 32;
+	base = ictlr_reg_base[irq>>5];
+	writel(fiq << (irq & 31), base + ICTLR_CPU_IEP_CLASS);
+}
+
+unsigned long tegra_legacy_vfiq(int nr)
+{
+	void __iomem *base;
+	base = ictlr_reg_base[nr];
+	return readl(base + ICTLR_CPU_IEP_VFIQ);
+}
+
+unsigned long tegra_legacy_class(int nr)
+{
+	void __iomem *base;
+	base = ictlr_reg_base[nr];
+	return readl(base + ICTLR_CPU_IEP_CLASS);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-tegra/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,14 +1,21 @@
 obj-y                                   += common.o
 obj-y                                   += io.o
-obj-y                                   += irq.o
+obj-y                                   += irq.o legacy_irq.o
 obj-y                                   += clock.o
 obj-y                                   += timer.o
 obj-y                                   += gpio.o
 obj-y                                   += pinmux.o
+obj-y					+= fuse.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += clock.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_clocks.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)         += tegra2_dvfs.o
+obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= pinmux-t2-tables.o
 obj-$(CONFIG_SMP)                       += platsmp.o localtimer.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)		+= dma.o
+obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
+obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
 
 obj-${CONFIG_MACH_HARMONY}              += board-harmony.o
 obj-${CONFIG_MACH_HARMONY}              += board-harmony-pinmux.o
+obj-${CONFIG_MACH_HARMONY}              += board-harmony-pcie.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pcie.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pcie.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pcie.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pcie.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,915 @@
+/*
+ * arch/arm/mach-tegra/pci.c
+ *
+ * PCIe host controller driver for TEGRA(2) SOCs
+ *
+ * Copyright (c) 2010, CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on NVIDIA PCIe driver
+ * Copyright (c) 2008-2009, NVIDIA Corporation.
+ *
+ * Bits taken from arch/arm/mach-dove/pcie.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <asm/sizes.h>
+#include <asm/mach/pci.h>
+
+#include <mach/pinmux.h>
+#include <mach/iomap.h>
+#include <mach/clk.h>
+
+/* register definitions */
+#define AFI_OFFSET	0x3800
+#define PADS_OFFSET	0x3000
+#define RP0_OFFSET	0x0000
+#define RP1_OFFSET	0x1000
+
+#define AFI_AXI_BAR0_SZ	0x00
+#define AFI_AXI_BAR1_SZ	0x04
+#define AFI_AXI_BAR2_SZ	0x08
+#define AFI_AXI_BAR3_SZ	0x0c
+#define AFI_AXI_BAR4_SZ	0x10
+#define AFI_AXI_BAR5_SZ	0x14
+
+#define AFI_AXI_BAR0_START	0x18
+#define AFI_AXI_BAR1_START	0x1c
+#define AFI_AXI_BAR2_START	0x20
+#define AFI_AXI_BAR3_START	0x24
+#define AFI_AXI_BAR4_START	0x28
+#define AFI_AXI_BAR5_START	0x2c
+
+#define AFI_FPCI_BAR0	0x30
+#define AFI_FPCI_BAR1	0x34
+#define AFI_FPCI_BAR2	0x38
+#define AFI_FPCI_BAR3	0x3c
+#define AFI_FPCI_BAR4	0x40
+#define AFI_FPCI_BAR5	0x44
+
+#define AFI_CACHE_BAR0_SZ	0x48
+#define AFI_CACHE_BAR0_ST	0x4c
+#define AFI_CACHE_BAR1_SZ	0x50
+#define AFI_CACHE_BAR1_ST	0x54
+
+#define AFI_MSI_BAR_SZ		0x60
+#define AFI_MSI_FPCI_BAR_ST	0x64
+#define AFI_MSI_AXI_BAR_ST	0x68
+
+#define AFI_CONFIGURATION		0xac
+#define  AFI_CONFIGURATION_EN_FPCI	(1 << 0)
+
+#define AFI_FPCI_ERROR_MASKS	0xb0
+
+#define AFI_INTR_MASK		0xb4
+#define  AFI_INTR_MASK_INT_MASK	(1 << 0)
+#define  AFI_INTR_MASK_MSI_MASK	(1 << 8)
+
+#define AFI_INTR_CODE		0xb8
+#define  AFI_INTR_CODE_MASK	0xf
+#define  AFI_INTR_MASTER_ABORT	4
+#define  AFI_INTR_LEGACY	6
+
+#define AFI_INTR_SIGNATURE	0xbc
+#define AFI_SM_INTR_ENABLE	0xc4
+
+#define AFI_AFI_INTR_ENABLE		0xc8
+#define  AFI_INTR_EN_INI_SLVERR		(1 << 0)
+#define  AFI_INTR_EN_INI_DECERR		(1 << 1)
+#define  AFI_INTR_EN_TGT_SLVERR		(1 << 2)
+#define  AFI_INTR_EN_TGT_DECERR		(1 << 3)
+#define  AFI_INTR_EN_TGT_WRERR		(1 << 4)
+#define  AFI_INTR_EN_DFPCI_DECERR	(1 << 5)
+#define  AFI_INTR_EN_AXI_DECERR		(1 << 6)
+#define  AFI_INTR_EN_FPCI_TIMEOUT	(1 << 7)
+
+#define AFI_PCIE_CONFIG					0x0f8
+#define  AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE		(1 << 1)
+#define  AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE		(1 << 2)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK	(0xf << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE	(0x0 << 20)
+#define  AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL	(0x1 << 20)
+
+#define AFI_FUSE			0x104
+#define  AFI_FUSE_PCIE_T0_GEN2_DIS	(1 << 2)
+
+#define AFI_PEX0_CTRL			0x110
+#define AFI_PEX1_CTRL			0x118
+#define  AFI_PEX_CTRL_RST		(1 << 0)
+#define  AFI_PEX_CTRL_REFCLK_EN		(1 << 3)
+
+#define RP_VEND_XP	0x00000F00
+#define  RP_VEND_XP_DL_UP	(1 << 30)
+
+#define RP_LINK_CONTROL_STATUS			0x00000090
+#define  RP_LINK_CONTROL_STATUS_LINKSTAT_MASK	0x3fff0000
+
+#define PADS_CTL_SEL		0x0000009C
+
+#define PADS_CTL		0x000000A0
+#define  PADS_CTL_IDDQ_1L	(1 << 0)
+#define  PADS_CTL_TX_DATA_EN_1L	(1 << 6)
+#define  PADS_CTL_RX_DATA_EN_1L	(1 << 10)
+
+#define PADS_PLL_CTL				0x000000B8
+#define  PADS_PLL_CTL_RST_B4SM			(1 << 1)
+#define  PADS_PLL_CTL_LOCKDET			(1 << 8)
+#define  PADS_PLL_CTL_REFCLK_MASK		(0x3 << 16)
+#define  PADS_PLL_CTL_REFCLK_INTERNAL_CML	(0 << 16)
+#define  PADS_PLL_CTL_REFCLK_INTERNAL_CMOS	(1 << 16)
+#define  PADS_PLL_CTL_REFCLK_EXTERNAL		(2 << 16)
+#define  PADS_PLL_CTL_TXCLKREF_MASK		(0x1 << 20)
+#define  PADS_PLL_CTL_TXCLKREF_DIV10		(0 << 20)
+#define  PADS_PLL_CTL_TXCLKREF_DIV5		(1 << 20)
+
+/* PMC access is required for PCIE xclk (un)clamping */
+#define PMC_SCRATCH42		0x144
+#define PMC_SCRATCH42_PCX_CLAMP	(1 << 0)
+
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+#define pmc_writel(value, reg) \
+	__raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+	__raw_readl((u32)reg_pmc_base + (reg))
+
+/*
+ * Tegra2 defines 1GB in the AXI address map for PCIe.
+ *
+ * That address space is split into different regions, with sizes and
+ * offsets as follows:
+ *
+ * 0x80000000 - 0x80003fff - PCI controller registers
+ * 0x80004000 - 0x80103fff - PCI configuration space
+ * 0x80104000 - 0x80203fff - PCI extended configuration space
+ * 0x80203fff - 0x803fffff - unused
+ * 0x80400000 - 0x8040ffff - downstream IO
+ * 0x80410000 - 0x8fffffff - unused
+ * 0x90000000 - 0x9fffffff - non-prefetchable memory
+ * 0xa0000000 - 0xbfffffff - prefetchable memory
+ */
+#define TEGRA_PCIE_BASE		0x80000000
+
+#define PCIE_REGS_SZ		SZ_16K
+#define PCIE_CFG_OFF		PCIE_REGS_SZ
+#define PCIE_CFG_SZ		SZ_1M
+#define PCIE_EXT_CFG_OFF	(PCIE_CFG_SZ + PCIE_CFG_OFF)
+#define PCIE_EXT_CFG_SZ		SZ_1M
+#define PCIE_IOMAP_SZ		(PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
+
+#define MMIO_BASE		(TEGRA_PCIE_BASE + SZ_4M)
+#define MMIO_SIZE		SZ_64K
+#define MEM_BASE_0		(TEGRA_PCIE_BASE + SZ_256M)
+#define MEM_SIZE_0		SZ_128M
+#define MEM_BASE_1		(MEM_BASE_0 + MEM_SIZE_0)
+#define MEM_SIZE_1		SZ_128M
+#define PREFETCH_MEM_BASE_0	(MEM_BASE_1 + MEM_SIZE_1)
+#define PREFETCH_MEM_SIZE_0	SZ_128M
+#define PREFETCH_MEM_BASE_1	(PREFETCH_MEM_BASE_0 + PREFETCH_MEM_SIZE_0)
+#define PREFETCH_MEM_SIZE_1	SZ_128M
+
+#define  PCIE_CONF_BUS(b)	((b) << 16)
+#define  PCIE_CONF_DEV(d)	((d) << 11)
+#define  PCIE_CONF_FUNC(f)	((f) << 8)
+#define  PCIE_CONF_REG(r)	\
+	(((r) & ~0x3) | (((r) < 256) ? PCIE_CFG_OFF : PCIE_EXT_CFG_OFF))
+
+struct tegra_pcie_port {
+	int			index;
+	u8			root_bus_nr;
+	void __iomem		*base;
+
+	bool			link_up;
+
+	char			io_space_name[16];
+	char			mem_space_name[16];
+	char			prefetch_space_name[20];
+	struct resource		res[3];
+};
+
+struct tegra_pcie_info {
+	struct tegra_pcie_port	port[2];
+	int			num_ports;
+
+	void __iomem		*regs;
+	struct resource		res_mmio;
+
+	struct clk		*pex_clk;
+	struct clk		*afi_clk;
+	struct clk		*pcie_xclk;
+	struct clk		*pll_e;
+};
+
+static struct tegra_pcie_info tegra_pcie = {
+	.res_mmio = {
+		.name = "PCI IO",
+		.start = MMIO_BASE,
+		.end = MMIO_BASE + MMIO_SIZE - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+void __iomem *tegra_pcie_io_base;
+EXPORT_SYMBOL(tegra_pcie_io_base);
+
+static inline void afi_writel(u32 value, unsigned long offset)
+{
+	writel(value, offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 afi_readl(unsigned long offset)
+{
+	return readl(offset + AFI_OFFSET + tegra_pcie.regs);
+}
+
+static inline void pads_writel(u32 value, unsigned long offset)
+{
+	writel(value, offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static inline u32 pads_readl(unsigned long offset)
+{
+	return readl(offset + PADS_OFFSET + tegra_pcie.regs);
+}
+
+static struct tegra_pcie_port *bus_to_port(int bus)
+{
+	int i;
+
+	for (i = tegra_pcie.num_ports - 1; i >= 0; i--) {
+		int rbus = tegra_pcie.port[i].root_bus_nr;
+		if (rbus != -1 && rbus == bus)
+			break;
+	}
+
+	return i >= 0 ? tegra_pcie.port + i : NULL;
+}
+
+static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 *val)
+{
+	struct tegra_pcie_port *pp = bus_to_port(bus->number);
+	void __iomem *addr;
+
+	if (pp) {
+		if (devfn != 0) {
+			*val = 0xffffffff;
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		}
+
+		addr = pp->base + (where & ~0x3);
+	} else {
+		addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+					  PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+					  PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+					  PCIE_CONF_REG(where));
+	}
+
+	*val = readl(addr);
+
+	if (size == 1)
+		*val = (*val >> (8 * (where & 3))) & 0xff;
+	else if (size == 2)
+		*val = (*val >> (8 * (where & 3))) & 0xffff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+				 int where, int size, u32 val)
+{
+	struct tegra_pcie_port *pp = bus_to_port(bus->number);
+	void __iomem *addr;
+
+	u32 mask;
+	u32 tmp;
+
+	if (pp) {
+		if (devfn != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		addr = pp->base + (where & ~0x3);
+	} else {
+		addr = tegra_pcie.regs + (PCIE_CONF_BUS(bus->number) +
+					  PCIE_CONF_DEV(PCI_SLOT(devfn)) +
+					  PCIE_CONF_FUNC(PCI_FUNC(devfn)) +
+					  PCIE_CONF_REG(where));
+	}
+
+	if (size == 4) {
+		writel(val, addr);
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	if (size == 2)
+		mask = ~(0xffff << ((where & 0x3) * 8));
+	else if (size == 1)
+		mask = ~(0xff << ((where & 0x3) * 8));
+	else
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	tmp = readl(addr) & mask;
+	tmp |= val << ((where & 0x3) * 8);
+	writel(tmp, addr);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops tegra_pcie_ops = {
+	.read	= tegra_pcie_read_conf,
+	.write	= tegra_pcie_write_conf,
+};
+
+static void __devinit tegra_pcie_fixup_bridge(struct pci_dev *dev)
+{
+	u16 reg;
+
+	if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
+		pci_read_config_word(dev, PCI_COMMAND, &reg);
+		reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
+		pci_write_config_word(dev, PCI_COMMAND, reg);
+	}
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
+
+/* Tegra PCIE root complex wrongly reports device class */
+static void __devinit tegra_pcie_fixup_class(struct pci_dev *dev)
+{
+	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
+
+/* Tegra PCIE requires relaxed ordering */
+static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
+{
+	u16 val16;
+	int pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+
+	if (pos <= 0) {
+		dev_err(&dev->dev, "skipping relaxed ordering fixup\n");
+		return;
+	}
+
+	pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &val16);
+	val16 |= PCI_EXP_DEVCTL_RELAX_EN;
+	pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, val16);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
+
+static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+	struct tegra_pcie_port *pp;
+
+	if (nr >= tegra_pcie.num_ports)
+		return 0;
+
+	pp = tegra_pcie.port + nr;
+	pp->root_bus_nr = sys->busnr;
+
+	/*
+	 * IORESOURCE_IO
+	 */
+	snprintf(pp->io_space_name, sizeof(pp->io_space_name),
+		 "PCIe %d I/O", pp->index);
+	pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
+	pp->res[0].name = pp->io_space_name;
+	if (pp->index == 0) {
+		pp->res[0].start = PCIBIOS_MIN_IO;
+		pp->res[0].end = pp->res[0].start + SZ_32K - 1;
+	} else {
+		pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
+		pp->res[0].end = IO_SPACE_LIMIT;
+	}
+	pp->res[0].flags = IORESOURCE_IO;
+	if (request_resource(&ioport_resource, &pp->res[0]))
+		panic("Request PCIe IO resource failed\n");
+	sys->resource[0] = &pp->res[0];
+
+	/*
+	 * IORESOURCE_MEM
+	 */
+	snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
+		 "PCIe %d MEM", pp->index);
+	pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
+	pp->res[1].name = pp->mem_space_name;
+	if (pp->index == 0) {
+		pp->res[1].start = MEM_BASE_0;
+		pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+	} else {
+		pp->res[1].start = MEM_BASE_1;
+		pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+	}
+	pp->res[1].flags = IORESOURCE_MEM;
+	if (request_resource(&iomem_resource, &pp->res[1]))
+		panic("Request PCIe Memory resource failed\n");
+	sys->resource[1] = &pp->res[1];
+
+	/*
+	 * IORESOURCE_MEM | IORESOURCE_PREFETCH
+	 */
+	snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
+		 "PCIe %d PREFETCH MEM", pp->index);
+	pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
+	pp->res[2].name = pp->prefetch_space_name;
+	if (pp->index == 0) {
+		pp->res[2].start = PREFETCH_MEM_BASE_0;
+		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+	} else {
+		pp->res[2].start = PREFETCH_MEM_BASE_1;
+		pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+	}
+	pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+	if (request_resource(&iomem_resource, &pp->res[2]))
+		panic("Request PCIe Prefetch Memory resource failed\n");
+	sys->resource[2] = &pp->res[2];
+
+	return 1;
+}
+
+static int tegra_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return INT_PCIE_INTR;
+}
+
+static struct pci_bus __init *tegra_pcie_scan_bus(int nr,
+						  struct pci_sys_data *sys)
+{
+	struct tegra_pcie_port *pp;
+
+	if (nr >= tegra_pcie.num_ports)
+		return 0;
+
+	pp = tegra_pcie.port + nr;
+	pp->root_bus_nr = sys->busnr;
+
+	return pci_scan_bus(sys->busnr, &tegra_pcie_ops, sys);
+}
+
+static struct hw_pci tegra_pcie_hw __initdata = {
+	.nr_controllers	= 2,
+	.setup		= tegra_pcie_setup,
+	.scan		= tegra_pcie_scan_bus,
+	.swizzle	= pci_std_swizzle,
+	.map_irq	= tegra_pcie_map_irq,
+};
+
+
+static irqreturn_t tegra_pcie_isr(int irq, void *arg)
+{
+	const char *err_msg[] = {
+		"Unknown",
+		"AXI slave error",
+		"AXI decode error",
+		"Target abort",
+		"Master abort",
+		"Invalid write",
+		"Response decoding error",
+		"AXI response decoding error",
+		"Transcation timeout",
+	};
+
+	u32 code, signature;
+
+	code = afi_readl(AFI_INTR_CODE) & AFI_INTR_CODE_MASK;
+	signature = afi_readl(AFI_INTR_SIGNATURE);
+	afi_writel(0, AFI_INTR_CODE);
+
+	if (code == AFI_INTR_LEGACY)
+		return IRQ_NONE;
+
+	if (code >= ARRAY_SIZE(err_msg))
+		code = 0;
+
+	/*
+	 * do not pollute kernel log with master abort reports since they
+	 * happen a lot during enumeration
+	 */
+	if (code == AFI_INTR_MASTER_ABORT)
+		pr_debug("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+	else
+		pr_err("PCIE: %s, signature: %08x\n", err_msg[code], signature);
+
+	return IRQ_HANDLED;
+}
+
+static void tegra_pcie_setup_translations(void)
+{
+	u32 fpci_bar;
+	u32 size;
+	u32 axi_address;
+
+	/* Bar 0: config Bar */
+	fpci_bar = ((u32)0xfdff << 16);
+	size = PCIE_CFG_SZ;
+	axi_address = TEGRA_PCIE_BASE + PCIE_CFG_OFF;
+	afi_writel(axi_address, AFI_AXI_BAR0_START);
+	afi_writel(size >> 12, AFI_AXI_BAR0_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR0);
+
+	/* Bar 1: extended config Bar */
+	fpci_bar = ((u32)0xfe1 << 20);
+	size = PCIE_EXT_CFG_SZ;
+	axi_address = TEGRA_PCIE_BASE + PCIE_EXT_CFG_OFF;
+	afi_writel(axi_address, AFI_AXI_BAR1_START);
+	afi_writel(size >> 12, AFI_AXI_BAR1_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR1);
+
+	/* Bar 2: downstream IO bar */
+	fpci_bar = ((__u32)0xfdfc << 16);
+	size = MMIO_SIZE;
+	axi_address = MMIO_BASE;
+	afi_writel(axi_address, AFI_AXI_BAR2_START);
+	afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR2);
+
+	/* Bar 3: prefetchable memory BAR */
+	fpci_bar = (((PREFETCH_MEM_BASE_0 >> 12) & 0x0fffffff) << 4) | 0x1;
+	size =  PREFETCH_MEM_SIZE_0 +  PREFETCH_MEM_SIZE_1;
+	axi_address = PREFETCH_MEM_BASE_0;
+	afi_writel(axi_address, AFI_AXI_BAR3_START);
+	afi_writel(size >> 12, AFI_AXI_BAR3_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR3);
+
+	/* Bar 4: non prefetchable memory BAR */
+	fpci_bar = (((MEM_BASE_0 >> 12)	& 0x0FFFFFFF) << 4) | 0x1;
+	size = MEM_SIZE_0 + MEM_SIZE_1;
+	axi_address = MEM_BASE_0;
+	afi_writel(axi_address, AFI_AXI_BAR4_START);
+	afi_writel(size >> 12, AFI_AXI_BAR4_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR4);
+
+	/* Bar 5: NULL out the remaining BAR as it is not used */
+	fpci_bar = 0;
+	size = 0;
+	axi_address = 0;
+	afi_writel(axi_address, AFI_AXI_BAR5_START);
+	afi_writel(size >> 12, AFI_AXI_BAR5_SZ);
+	afi_writel(fpci_bar, AFI_FPCI_BAR5);
+
+	/* map all upstream transactions as uncached */
+	afi_writel(PHYS_OFFSET, AFI_CACHE_BAR0_ST);
+	afi_writel(0, AFI_CACHE_BAR0_SZ);
+	afi_writel(0, AFI_CACHE_BAR1_ST);
+	afi_writel(0, AFI_CACHE_BAR1_SZ);
+
+	/* No MSI */
+	afi_writel(0, AFI_MSI_FPCI_BAR_ST);
+	afi_writel(0, AFI_MSI_BAR_SZ);
+	afi_writel(0, AFI_MSI_AXI_BAR_ST);
+	afi_writel(0, AFI_MSI_BAR_SZ);
+}
+
+static void tegra_pcie_enable_controller(void)
+{
+	u32 val, reg;
+	int i;
+
+	/* Enable slot clock and pulse the reset signals */
+	for (i = 0, reg = AFI_PEX0_CTRL; i < 2; i++, reg += 0x8) {
+		val = afi_readl(reg) |  AFI_PEX_CTRL_REFCLK_EN;
+		afi_writel(val, reg);
+		val &= ~AFI_PEX_CTRL_RST;
+		afi_writel(val, reg);
+
+		val = afi_readl(reg) | AFI_PEX_CTRL_RST;
+		afi_writel(val, reg);
+	}
+
+	/* Enable dual controller and both ports */
+	val = afi_readl(AFI_PCIE_CONFIG);
+	val &= ~(AFI_PCIE_CONFIG_PCIEC0_DISABLE_DEVICE |
+		 AFI_PCIE_CONFIG_PCIEC1_DISABLE_DEVICE |
+		 AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK);
+	val |= AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL;
+	afi_writel(val, AFI_PCIE_CONFIG);
+
+	val = afi_readl(AFI_FUSE) & ~AFI_FUSE_PCIE_T0_GEN2_DIS;
+	afi_writel(val, AFI_FUSE);
+
+	/* Initialze internal PHY, enable up to 16 PCIE lanes */
+	pads_writel(0x0, PADS_CTL_SEL);
+
+	/* override IDDQ to 1 on all 4 lanes */
+	val = pads_readl(PADS_CTL) | PADS_CTL_IDDQ_1L;
+	pads_writel(val, PADS_CTL);
+
+	/*
+	 * set up PHY PLL inputs select PLLE output as refclock,
+	 * set TX ref sel to div10 (not div5)
+	 */
+	val = pads_readl(PADS_PLL_CTL);
+	val &= ~(PADS_PLL_CTL_REFCLK_MASK | PADS_PLL_CTL_TXCLKREF_MASK);
+	val |= (PADS_PLL_CTL_REFCLK_INTERNAL_CML | PADS_PLL_CTL_TXCLKREF_DIV10);
+	pads_writel(val, PADS_PLL_CTL);
+
+	/* take PLL out of reset  */
+	val = pads_readl(PADS_PLL_CTL) | PADS_PLL_CTL_RST_B4SM;
+	pads_writel(val, PADS_PLL_CTL);
+
+	/*
+	 * Hack, set the clock voltage to the DEFAULT provided by hw folks.
+	 * This doesn't exist in the documentation
+	 */
+	pads_writel(0xfa5cfa5c, 0xc8);
+
+	/* Wait for the PLL to lock */
+	do {
+		val = pads_readl(PADS_PLL_CTL);
+	} while (!(val & PADS_PLL_CTL_LOCKDET));
+
+	/* turn off IDDQ override */
+	val = pads_readl(PADS_CTL) & ~PADS_CTL_IDDQ_1L;
+	pads_writel(val, PADS_CTL);
+
+	/* enable TX/RX data */
+	val = pads_readl(PADS_CTL);
+	val |= (PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L);
+	pads_writel(val, PADS_CTL);
+
+	/* Take the PCIe interface module out of reset */
+	tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+
+	/* Finally enable PCIe */
+	val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
+	afi_writel(val, AFI_CONFIGURATION);
+
+	val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
+	       AFI_INTR_EN_TGT_SLVERR | AFI_INTR_EN_TGT_DECERR |
+	       AFI_INTR_EN_TGT_WRERR | AFI_INTR_EN_DFPCI_DECERR);
+	afi_writel(val, AFI_AFI_INTR_ENABLE);
+	afi_writel(0xffffffff, AFI_SM_INTR_ENABLE);
+
+	/* FIXME: No MSI for now, only INT */
+	afi_writel(AFI_INTR_MASK_INT_MASK, AFI_INTR_MASK);
+
+	/* Disable all execptions */
+	afi_writel(0, AFI_FPCI_ERROR_MASKS);
+
+	return;
+}
+
+static void tegra_pcie_xclk_clamp(bool clamp)
+{
+	u32 reg;
+
+	reg = pmc_readl(PMC_SCRATCH42) & ~PMC_SCRATCH42_PCX_CLAMP;
+
+	if (clamp)
+		reg |= PMC_SCRATCH42_PCX_CLAMP;
+
+	pmc_writel(reg, PMC_SCRATCH42);
+}
+
+static int tegra_pcie_power_on(void)
+{
+	tegra_pcie_xclk_clamp(true);
+	tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+	tegra_pcie_xclk_clamp(false);
+
+	clk_enable(tegra_pcie.afi_clk);
+	clk_enable(tegra_pcie.pex_clk);
+	return clk_enable(tegra_pcie.pll_e);
+}
+
+static void tegra_pcie_power_off(void)
+{
+	tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
+	tegra_periph_reset_assert(tegra_pcie.afi_clk);
+	tegra_periph_reset_assert(tegra_pcie.pex_clk);
+
+	tegra_pcie_xclk_clamp(true);
+}
+
+static int tegra_pcie_clocks_get(void)
+{
+	int err;
+
+	tegra_pcie.pex_clk = clk_get(NULL, "pex");
+	if (IS_ERR(tegra_pcie.pex_clk))
+		return PTR_ERR(tegra_pcie.pex_clk);
+
+	tegra_pcie.afi_clk = clk_get(NULL, "afi");
+	if (IS_ERR(tegra_pcie.afi_clk)) {
+		err = PTR_ERR(tegra_pcie.afi_clk);
+		goto err_afi_clk;
+	}
+
+	tegra_pcie.pcie_xclk = clk_get(NULL, "pcie_xclk");
+	if (IS_ERR(tegra_pcie.pcie_xclk)) {
+		err =  PTR_ERR(tegra_pcie.pcie_xclk);
+		goto err_pcie_xclk;
+	}
+
+	tegra_pcie.pll_e = clk_get_sys(NULL, "pll_e");
+	if (IS_ERR(tegra_pcie.pll_e)) {
+		err = PTR_ERR(tegra_pcie.pll_e);
+		goto err_pll_e;
+	}
+
+	return 0;
+
+err_pll_e:
+	clk_put(tegra_pcie.pcie_xclk);
+err_pcie_xclk:
+	clk_put(tegra_pcie.afi_clk);
+err_afi_clk:
+	clk_put(tegra_pcie.pex_clk);
+
+	return err;
+}
+
+static void tegra_pcie_clocks_put(void)
+{
+	clk_put(tegra_pcie.pll_e);
+	clk_put(tegra_pcie.pcie_xclk);
+	clk_put(tegra_pcie.afi_clk);
+	clk_put(tegra_pcie.pex_clk);
+}
+
+static int __init tegra_pcie_get_resources(void)
+{
+	struct resource *res_mmio = &tegra_pcie.res_mmio;
+	int err;
+
+	err = tegra_pcie_clocks_get();
+	if (err) {
+		pr_err("PCIE: failed to get clocks: %d\n", err);
+		return err;
+	}
+
+	err = tegra_pcie_power_on();
+	if (err) {
+		pr_err("PCIE: failed to power up: %d\n", err);
+		goto err_pwr_on;
+	}
+
+	tegra_pcie.regs = ioremap_nocache(TEGRA_PCIE_BASE, PCIE_IOMAP_SZ);
+	if (tegra_pcie.regs == NULL) {
+		pr_err("PCIE: Failed to map PCI/AFI registers\n");
+		err = -ENOMEM;
+		goto err_map_reg;
+	}
+
+	err = request_resource(&iomem_resource, res_mmio);
+	if (err) {
+		pr_err("PCIE: Failed to request resources: %d\n", err);
+		goto err_req_io;
+	}
+
+	tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
+					     resource_size(res_mmio));
+	if (tegra_pcie_io_base == NULL) {
+		pr_err("PCIE: Failed to map IO\n");
+		err = -ENOMEM;
+		goto err_map_io;
+	}
+
+	err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
+			  IRQF_SHARED, "PCIE", &tegra_pcie);
+	if (err) {
+		pr_err("PCIE: Failed to register IRQ: %d\n", err);
+		goto err_irq;
+	}
+	set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
+
+	return 0;
+
+err_irq:
+	iounmap(tegra_pcie_io_base);
+err_map_io:
+	release_resource(&tegra_pcie.res_mmio);
+err_req_io:
+	iounmap(tegra_pcie.regs);
+err_map_reg:
+	tegra_pcie_power_off();
+err_pwr_on:
+	tegra_pcie_clocks_put();
+
+	return err;
+}
+
+/*
+ * FIXME: If there are no PCIe cards attached, then calling this function
+ * can result in the increase of the bootup time as there are big timeout
+ * loops.
+ */
+#define TEGRA_PCIE_LINKUP_TIMEOUT	200	/* up to 1.2 seconds */
+static bool tegra_pcie_check_link(struct tegra_pcie_port *pp, int idx,
+				  u32 reset_reg)
+{
+	u32 reg;
+	int retries = 3;
+	int timeout;
+
+	do {
+		timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+		while (timeout) {
+			reg = readl(pp->base + RP_VEND_XP);
+
+			if (reg & RP_VEND_XP_DL_UP)
+				break;
+
+			mdelay(1);
+			timeout--;
+		}
+
+		if (!timeout)  {
+			pr_err("PCIE: port %d: link down, retrying\n", idx);
+			goto retry;
+		}
+
+		timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
+		while (timeout) {
+			reg = readl(pp->base + RP_LINK_CONTROL_STATUS);
+
+			if (reg & 0x20000000)
+				return true;
+
+			mdelay(1);
+			timeout--;
+		}
+
+retry:
+		/* Pulse the PEX reset */
+		reg = afi_readl(reset_reg) | AFI_PEX_CTRL_RST;
+		afi_writel(reg, reset_reg);
+		mdelay(1);
+		reg = afi_readl(reset_reg) & ~AFI_PEX_CTRL_RST;
+		afi_writel(reg, reset_reg);
+
+		retries--;
+	} while (retries);
+
+	return false;
+}
+
+static void __init tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
+{
+	struct tegra_pcie_port *pp;
+
+	pp = tegra_pcie.port + tegra_pcie.num_ports;
+
+	pp->index = -1;
+	pp->base = tegra_pcie.regs + offset;
+	pp->link_up = tegra_pcie_check_link(pp, index, reset_reg);
+
+	if (!pp->link_up) {
+		pp->base = NULL;
+		printk(KERN_INFO "PCIE: port %d: link down, ignoring\n", index);
+		return;
+	}
+
+	tegra_pcie.num_ports++;
+	pp->index = index;
+	pp->root_bus_nr = -1;
+	memset(pp->res, 0, sizeof(pp->res));
+}
+
+int __init tegra_pcie_init(bool init_port0, bool init_port1)
+{
+	int err;
+
+	if (!(init_port0 || init_port1))
+		return -ENODEV;
+
+	err = tegra_pcie_get_resources();
+	if (err)
+		return err;
+
+	tegra_pcie_enable_controller();
+
+	/* setup the AFI address translations */
+	tegra_pcie_setup_translations();
+
+	if (init_port0)
+		tegra_pcie_add_port(0, RP0_OFFSET, AFI_PEX0_CTRL);
+
+	if (init_port1)
+		tegra_pcie_add_port(1, RP1_OFFSET, AFI_PEX1_CTRL);
+
+	pci_common_init(&tegra_pcie_hw);
+
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pinmux.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pinmux.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pinmux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pinmux.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,8 @@
  *
  */
 
-
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
@@ -23,21 +24,6 @@
 #include <mach/iomap.h>
 #include <mach/pinmux.h>
 
-
-#define TEGRA_TRI_STATE(x)	(0x14 + (4 * (x)))
-#define TEGRA_PP_MUX_CTL(x)	(0x80 + (4 * (x)))
-#define TEGRA_PP_PU_PD(x)	(0xa0 + (4 * (x)))
-
-#define REG_A 0
-#define REG_B 1
-#define REG_C 2
-#define REG_D 3
-#define REG_E 4
-#define REG_F 5
-#define REG_G 6
-
-#define REG_N -1
-
 #define HSM_EN(reg)	(((reg) >> 2) & 0x1)
 #define SCHMT_EN(reg)	(((reg) >> 3) & 0x1)
 #define LPMD(reg)	(((reg) >> 4) & 0x3)
@@ -46,154 +32,8 @@
 #define SLWR(reg)	(((reg) >> 28) & 0x3)
 #define SLWF(reg)	(((reg) >> 30) & 0x3)
 
-struct tegra_pingroup_desc {
-	const char *name;
-	int funcs[4];
-	s8 tri_reg; 	/* offset into the TRISTATE_REG_* register bank */
-	s8 tri_bit; 	/* offset into the TRISTATE_REG_* register bit */
-	s8 mux_reg;	/* offset into the PIN_MUX_CTL_* register bank */
-	s8 mux_bit;	/* offset into the PIN_MUX_CTL_* register bit */
-	s8 pupd_reg;	/* offset into the PULL_UPDOWN_REG_* register bank */
-	s8 pupd_bit;	/* offset into the PULL_UPDOWN_REG_* register bit */
-};
-
-#define PINGROUP(pg_name, f0, f1, f2, f3,			\
-		 tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)	\
-	[TEGRA_PINGROUP_ ## pg_name] = {			\
-		.name = #pg_name,				\
-		.funcs = {					\
-			TEGRA_MUX_ ## f0,			\
-			TEGRA_MUX_ ## f1,			\
-			TEGRA_MUX_ ## f2,			\
-			TEGRA_MUX_ ## f3,			\
-		},						\
-		.tri_reg = REG_ ## tri_r,			\
-		.tri_bit = tri_b,				\
-		.mux_reg = REG_ ## mux_r,			\
-		.mux_bit = mux_b,				\
-		.pupd_reg = REG_ ## pupd_r,			\
-		.pupd_bit = pupd_b,				\
-	}
-
-static const struct tegra_pingroup_desc pingroups[TEGRA_MAX_PINGROUP] = {
-	PINGROUP(ATA,   IDE,       NAND,      GMI,       RSVD,          A, 0,  A, 24, A, 0),
-	PINGROUP(ATB,   IDE,       NAND,      GMI,       SDIO4,         A, 1,  A, 16, A, 2),
-	PINGROUP(ATC,   IDE,       NAND,      GMI,       SDIO4,         A, 2,  A, 22, A, 4),
-	PINGROUP(ATD,   IDE,       NAND,      GMI,       SDIO4,         A, 3,  A, 20, A, 6),
-	PINGROUP(ATE,   IDE,       NAND,      GMI,       RSVD,          B, 25, A, 12, A, 8),
-	PINGROUP(CDEV1, OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    A, 4,  C, 2,  C, 0),
-	PINGROUP(CDEV2, OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     A, 5,  C, 4,  C, 2),
-	PINGROUP(CRTP,  CRT,       RSVD,      RSVD,      RSVD,          D, 14, G, 20, B, 24),
-	PINGROUP(CSUS,  PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, A, 6,  C, 6,  D, 24),
-	PINGROUP(DAP1,  DAP1,      RSVD,      GMI,       SDIO2,         A, 7,  C, 20, A, 10),
-	PINGROUP(DAP2,  DAP2,      TWC,       RSVD,      GMI,           A, 8,  C, 22, A, 12),
-	PINGROUP(DAP3,  DAP3,      RSVD,      RSVD,      RSVD,          A, 9,  C, 24, A, 14),
-	PINGROUP(DAP4,  DAP4,      RSVD,      GMI,       RSVD,          A, 10, C, 26, A, 16),
-	PINGROUP(DDC,   I2C2,      RSVD,      RSVD,      RSVD,          B, 31, C, 0,  E, 28),
-	PINGROUP(DTA,   RSVD,      SDIO2,     VI,        RSVD,          A, 11, B, 20, A, 18),
-	PINGROUP(DTB,   RSVD,      RSVD,      VI,        SPI1,          A, 12, B, 22, A, 20),
-	PINGROUP(DTC,   RSVD,      RSVD,      VI,        RSVD,          A, 13, B, 26, A, 22),
-	PINGROUP(DTD,   RSVD,      SDIO2,     VI,        RSVD,          A, 14, B, 28, A, 24),
-	PINGROUP(DTE,   RSVD,      RSVD,      VI,        SPI1,          A, 15, B, 30, A, 26),
-	PINGROUP(DTF,   I2C3,      RSVD,      VI,        RSVD,          D, 12, G, 30, A, 28),
-	PINGROUP(GMA,   UARTE,     SPI3,      GMI,       SDIO4,         A, 28, B, 0,  E, 20),
-	PINGROUP(GMB,   IDE,       NAND,      GMI,       GMI_INT,       B, 29, C, 28, E, 22),
-	PINGROUP(GMC,   UARTD,     SPI4,      GMI,       SFLASH,        A, 29, B, 2,  E, 24),
-	PINGROUP(GMD,   RSVD,      NAND,      GMI,       SFLASH,        B, 30, C, 30, E, 26),
-	PINGROUP(GME,   RSVD,      DAP5,      GMI,       SDIO4,         B, 0,  D, 0,  C, 24),
-	PINGROUP(GPU,   PWM,       UARTA,     GMI,       RSVD,          A, 16, D, 4,  B, 20),
-	PINGROUP(GPU7,  RTCK,      RSVD,      RSVD,      RSVD,          D, 11, G, 28, B, 6),
-	PINGROUP(GPV,   PCIE,      RSVD,      RSVD,      RSVD,          A, 17, D, 2,  A, 30),
-	PINGROUP(HDINT, HDMI,      RSVD,      RSVD,      RSVD,          C, 23, B, 4,  D, 22),
-	PINGROUP(I2CP,  I2C,       RSVD,      RSVD,      RSVD,          A, 18, C, 8,  B, 2),
-	PINGROUP(IRRX,  UARTA,     UARTB,     GMI,       SPI4,          A, 20, C, 18, C, 22),
-	PINGROUP(IRTX,  UARTA,     UARTB,     GMI,       SPI4,          A, 19, C, 16, C, 20),
-	PINGROUP(KBCA,  KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, A, 22, C, 10, B, 8),
-	PINGROUP(KBCB,  KBC,       NAND,      SDIO2,     MIO,           A, 21, C, 12, B, 10),
-	PINGROUP(KBCC,  KBC,       NAND,      TRACE,     EMC_TEST1_DLL, B, 26, C, 14, B, 12),
-	PINGROUP(KBCD,  KBC,       NAND,      SDIO2,     MIO,           D, 10, G, 26, B, 14),
-	PINGROUP(KBCE,  KBC,       NAND,      OWR,       RSVD,          A, 26, A, 28, E, 2),
-	PINGROUP(KBCF,  KBC,       NAND,      TRACE,     MIO,           A, 27, A, 26, E, 0),
-	PINGROUP(LCSN,  DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          C, 31, E, 12, D, 20),
-	PINGROUP(LD0,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 0,  F, 0,  D, 12),
-	PINGROUP(LD1,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 1,  F, 2,  D, 12),
-	PINGROUP(LD10,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 10, F, 20, D, 12),
-	PINGROUP(LD11,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 11, F, 22, D, 12),
-	PINGROUP(LD12,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 12, F, 24, D, 12),
-	PINGROUP(LD13,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 13, F, 26, D, 12),
-	PINGROUP(LD14,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 14, F, 28, D, 12),
-	PINGROUP(LD15,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 15, F, 30, D, 12),
-	PINGROUP(LD16,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 16, G, 0,  D, 12),
-	PINGROUP(LD17,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 17, G, 2,  D, 12),
-	PINGROUP(LD2,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 2,  F, 4,  D, 12),
-	PINGROUP(LD3,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 3,  F, 6,  D, 12),
-	PINGROUP(LD4,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 4,  F, 8,  D, 12),
-	PINGROUP(LD5,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 5,  F, 10, D, 12),
-	PINGROUP(LD6,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 6,  F, 12, D, 12),
-	PINGROUP(LD7,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 7,  F, 14, D, 12),
-	PINGROUP(LD8,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 8,  F, 16, D, 12),
-	PINGROUP(LD9,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 9,  F, 18, D, 12),
-	PINGROUP(LDC,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 30, E, 14, D, 20),
-	PINGROUP(LDI,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 6,  G, 16, D, 18),
-	PINGROUP(LHP0,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 18, G, 10, D, 16),
-	PINGROUP(LHP1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 19, G, 4,  D, 14),
-	PINGROUP(LHP2,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 20, G, 6,  D, 14),
-	PINGROUP(LHS,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          D, 7,  E, 22, D, 22),
-	PINGROUP(LM0,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          C, 24, E, 26, D, 22),
-	PINGROUP(LM1,   DISPLAYA,  DISPLAYB,  RSVD,      CRT,           C, 25, E, 28, D, 22),
-	PINGROUP(LPP,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 8,  G, 14, D, 18),
-	PINGROUP(LPW0,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 3,  E, 0,  D, 20),
-	PINGROUP(LPW1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          D, 4,  E, 2,  D, 20),
-	PINGROUP(LPW2,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 5,  E, 4,  D, 20),
-	PINGROUP(LSC0,  DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 27, E, 18, D, 22),
-	PINGROUP(LSC1,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          C, 28, E, 20, D, 20),
-	PINGROUP(LSCK,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          C, 29, E, 16, D, 20),
-	PINGROUP(LSDA,  DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          D, 1,  E, 8,  D, 20),
-	PINGROUP(LSDI,  DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          D, 2,  E, 6,  D, 20),
-	PINGROUP(LSPI,  DISPLAYA,  DISPLAYB,  XIO,       HDMI,          D, 0,  E, 10, D, 22),
-	PINGROUP(LVP0,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 21, E, 30, D, 22),
-	PINGROUP(LVP1,  DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          C, 22, G, 8,  D, 16),
-	PINGROUP(LVS,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          C, 26, E, 24, D, 22),
-	PINGROUP(OWC,   OWR,       RSVD,      RSVD,      RSVD,          A, 31, B, 8,  E, 30),
-	PINGROUP(PMC,   PWR_ON,    PWR_INTR,  RSVD,      RSVD,          A, 23, G, 18, N, -1),
-	PINGROUP(PTA,   I2C2,      HDMI,      GMI,       RSVD,          A, 24, G, 22, B, 4),
-	PINGROUP(RM,    I2C,       RSVD,      RSVD,      RSVD,          A, 25, A, 14, B, 0),
-	PINGROUP(SDB,   UARTA,     PWM,       SDIO3,     SPI2,          D, 15, D, 10, N, -1),
-	PINGROUP(SDC,   PWM,       TWC,       SDIO3,     SPI3,          B, 1,  D, 12, D, 28),
-	PINGROUP(SDD,   UARTA,     PWM,       SDIO3,     SPI3,          B, 2,  D, 14, D, 30),
-	PINGROUP(SDIO1, SDIO1,     RSVD,      UARTE,     UARTA,         A, 30, A, 30, E, 18),
-	PINGROUP(SLXA,  PCIE,      SPI4,      SDIO3,     SPI2,          B, 3,  B, 6,  B, 22),
-	PINGROUP(SLXC,  SPDIF,     SPI4,      SDIO3,     SPI2,          B, 5,  B, 10, B, 26),
-	PINGROUP(SLXD,  SPDIF,     SPI4,      SDIO3,     SPI2,          B, 6,  B, 12, B, 28),
-	PINGROUP(SLXK,  PCIE,      SPI4,      SDIO3,     SPI2,          B, 7,  B, 14, B, 30),
-	PINGROUP(SPDI,  SPDIF,     RSVD,      I2C,       SDIO2,         B, 8,  D, 8,  B, 16),
-	PINGROUP(SPDO,  SPDIF,     RSVD,      I2C,       SDIO2,         B, 9,  D, 6,  B, 18),
-	PINGROUP(SPIA,  SPI1,      SPI2,      SPI3,      GMI,           B, 10, D, 30, C, 4),
-	PINGROUP(SPIB,  SPI1,      SPI2,      SPI3,      GMI,           B, 11, D, 28, C, 6),
-	PINGROUP(SPIC,  SPI1,      SPI2,      SPI3,      GMI,           B, 12, D, 26, C, 8),
-	PINGROUP(SPID,  SPI2,      SPI1,      SPI2_ALT,  GMI,           B, 13, D, 24, C, 10),
-	PINGROUP(SPIE,  SPI2,      SPI1,      SPI2_ALT,  GMI,           B, 14, D, 22, C, 12),
-	PINGROUP(SPIF,  SPI3,      SPI1,      SPI2,      RSVD,          B, 15, D, 20, C, 14),
-	PINGROUP(SPIG,  SPI3,      SPI2,      SPI2_ALT,  I2C,           B, 16, D, 18, C, 16),
-	PINGROUP(SPIH,  SPI3,      SPI2,      SPI2_ALT,  I2C,           B, 17, D, 16, C, 18),
-	PINGROUP(UAA,   SPI3,      MIPI_HS,   UARTA,     ULPI,          B, 18, A, 0,  D, 0),
-	PINGROUP(UAB,   SPI2,      MIPI_HS,   UARTA,     ULPI,          B, 19, A, 2,  D, 2),
-	PINGROUP(UAC,   OWR,       RSVD,      RSVD,      RSVD,          B, 20, A, 4,  D, 4),
-	PINGROUP(UAD,   IRDA,      SPDIF,     UARTA,     SPI4,          B, 21, A, 6,  D, 6),
-	PINGROUP(UCA,   UARTC,     RSVD,      GMI,       RSVD,          B, 22, B, 16, D, 8),
-	PINGROUP(UCB,   UARTC,     PWM,       GMI,       RSVD,          B, 23, B, 18, D, 10),
-	PINGROUP(UDA,   SPI1,      RSVD,      UARTD,     ULPI,          D, 13, A, 8,  E, 16),
-	/* these pin groups only have pullup and pull down control */
-	PINGROUP(CK32,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 14),
-	PINGROUP(DDRC,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  D, 26),
-	PINGROUP(PMCA,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 4),
-	PINGROUP(PMCB,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 6),
-	PINGROUP(PMCC,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 8),
-	PINGROUP(PMCD,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 10),
-	PINGROUP(PMCE,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  E, 12),
-	PINGROUP(XM2C,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  C, 30),
-	PINGROUP(XM2D,  RSVD,      RSVD,      RSVD,      RSVD,          N, -1,  N, -1,  C, 28),
-};
+static const struct tegra_pingroup_desc *const pingroups = tegra_soc_pingroups;
+static const struct tegra_drive_pingroup_desc *const drive_pingroups = tegra_soc_drive_pingroups;
 
 static char *tegra_mux_names[TEGRA_MAX_MUX] = {
 	[TEGRA_MUX_AHB_CLK] = "AHB_CLK",
@@ -256,48 +96,7 @@
 	[TEGRA_MUX_VI] = "VI",
 	[TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
 	[TEGRA_MUX_XIO] = "XIO",
-};
-
-struct tegra_drive_pingroup_desc {
-	const char *name;
-	s16 reg;
-};
-
-#define DRIVE_PINGROUP(pg_name, r)				\
-	[TEGRA_DRIVE_PINGROUP_ ## pg_name] = {			\
-		.name = #pg_name,				\
-		.reg = r					\
-	}
-
-static const struct tegra_drive_pingroup_desc drive_pingroups[TEGRA_MAX_PINGROUP] = {
-	DRIVE_PINGROUP(AO1,		0x868),
-	DRIVE_PINGROUP(AO2,		0x86c),
-	DRIVE_PINGROUP(AT1,		0x870),
-	DRIVE_PINGROUP(AT2,		0x874),
-	DRIVE_PINGROUP(CDEV1,		0x878),
-	DRIVE_PINGROUP(CDEV2,		0x87c),
-	DRIVE_PINGROUP(CSUS,		0x880),
-	DRIVE_PINGROUP(DAP1,		0x884),
-	DRIVE_PINGROUP(DAP2,		0x888),
-	DRIVE_PINGROUP(DAP3,		0x88c),
-	DRIVE_PINGROUP(DAP4,		0x890),
-	DRIVE_PINGROUP(DBG,		0x894),
-	DRIVE_PINGROUP(LCD1,		0x898),
-	DRIVE_PINGROUP(LCD2,		0x89c),
-	DRIVE_PINGROUP(SDMMC2,	0x8a0),
-	DRIVE_PINGROUP(SDMMC3,	0x8a4),
-	DRIVE_PINGROUP(SPI,		0x8a8),
-	DRIVE_PINGROUP(UAA,		0x8ac),
-	DRIVE_PINGROUP(UAB,		0x8b0),
-	DRIVE_PINGROUP(UART2,		0x8b4),
-	DRIVE_PINGROUP(UART3,		0x8b8),
-	DRIVE_PINGROUP(VI1,		0x8bc),
-	DRIVE_PINGROUP(VI2,		0x8c0),
-	DRIVE_PINGROUP(XM2A,		0x8c4),
-	DRIVE_PINGROUP(XM2C,		0x8c8),
-	DRIVE_PINGROUP(XM2D,		0x8cc),
-	DRIVE_PINGROUP(XM2CLK,	0x8d0),
-	DRIVE_PINGROUP(MEMCOMP,	0x8d4),
+	[TEGRA_MUX_SAFE] = "<safe>",
 };
 
 static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
@@ -381,22 +180,27 @@
 	writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
 }
 
-int tegra_pinmux_set_func(enum tegra_pingroup pg, enum tegra_mux_func func)
+static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
 {
 	int mux = -1;
 	int i;
 	unsigned long reg;
 	unsigned long flags;
+	enum tegra_pingroup pg = config->pingroup;
+	enum tegra_mux_func func = config->func;
 
 	if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
 		return -ERANGE;
 
-	if (pingroups[pg].mux_reg == REG_N)
+	if (pingroups[pg].mux_reg < 0)
 		return -EINVAL;
 
 	if (func < 0)
 		return -ERANGE;
 
+	if (func == TEGRA_MUX_SAFE)
+		func = pingroups[pg].func_safe;
+
 	if (func & TEGRA_MUX_RSVD) {
 		mux = func & 0x3;
 	} else {
@@ -413,10 +217,10 @@
 
 	spin_lock_irqsave(&mux_lock, flags);
 
-	reg = pg_readl(TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+	reg = pg_readl(pingroups[pg].mux_reg);
 	reg &= ~(0x3 << pingroups[pg].mux_bit);
 	reg |= mux << pingroups[pg].mux_bit;
-	pg_writel(reg, TEGRA_PP_MUX_CTL(pingroups[pg].mux_reg));
+	pg_writel(reg, pingroups[pg].mux_reg);
 
 	spin_unlock_irqrestore(&mux_lock, flags);
 
@@ -432,16 +236,16 @@
 	if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
 		return -ERANGE;
 
-	if (pingroups[pg].tri_reg == REG_N)
+	if (pingroups[pg].tri_reg < 0)
 		return -EINVAL;
 
 	spin_lock_irqsave(&mux_lock, flags);
 
-	reg = pg_readl(TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+	reg = pg_readl(pingroups[pg].tri_reg);
 	reg &= ~(0x1 << pingroups[pg].tri_bit);
 	if (tristate)
 		reg |= 1 << pingroups[pg].tri_bit;
-	pg_writel(reg, TEGRA_TRI_STATE(pingroups[pg].tri_reg));
+	pg_writel(reg, pingroups[pg].tri_reg);
 
 	spin_unlock_irqrestore(&mux_lock, flags);
 
@@ -457,7 +261,7 @@
 	if (pg < 0 || pg >=  TEGRA_MAX_PINGROUP)
 		return -ERANGE;
 
-	if (pingroups[pg].pupd_reg == REG_N)
+	if (pingroups[pg].pupd_reg < 0)
 		return -EINVAL;
 
 	if (pupd != TEGRA_PUPD_NORMAL &&
@@ -468,38 +272,39 @@
 
 	spin_lock_irqsave(&mux_lock, flags);
 
-	reg = pg_readl(TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+	reg = pg_readl(pingroups[pg].pupd_reg);
 	reg &= ~(0x3 << pingroups[pg].pupd_bit);
 	reg |= pupd << pingroups[pg].pupd_bit;
-	pg_writel(reg, TEGRA_PP_PU_PD(pingroups[pg].pupd_reg));
+	pg_writel(reg, pingroups[pg].pupd_reg);
 
 	spin_unlock_irqrestore(&mux_lock, flags);
 
 	return 0;
 }
 
-void tegra_pinmux_config_pingroup(enum tegra_pingroup pingroup,
-				 enum tegra_mux_func func,
-				 enum tegra_pullupdown pupd,
-				 enum tegra_tristate tristate)
+static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
 {
+	enum tegra_pingroup pingroup = config->pingroup;
+	enum tegra_mux_func func     = config->func;
+	enum tegra_pullupdown pupd   = config->pupd;
+	enum tegra_tristate tristate = config->tristate;
 	int err;
 
-	if (pingroups[pingroup].mux_reg != REG_N) {
-		err = tegra_pinmux_set_func(pingroup, func);
+	if (pingroups[pingroup].mux_reg >= 0) {
+		err = tegra_pinmux_set_func(config);
 		if (err < 0)
 			pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
 			       pingroup_name(pingroup), func_name(func), err);
 	}
 
-	if (pingroups[pingroup].pupd_reg != REG_N) {
+	if (pingroups[pingroup].pupd_reg >= 0) {
 		err = tegra_pinmux_set_pullupdown(pingroup, pupd);
 		if (err < 0)
 			pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
 			       pingroup_name(pingroup), pupd_name(pupd), err);
 	}
 
-	if (pingroups[pingroup].tri_reg != REG_N) {
+	if (pingroups[pingroup].tri_reg >= 0) {
 		err = tegra_pinmux_set_tristate(pingroup, tristate);
 		if (err < 0)
 			pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
@@ -507,17 +312,12 @@
 	}
 }
 
-
-
-void tegra_pinmux_config_table(struct tegra_pingroup_config *config, int len)
+void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
 {
 	int i;
 
 	for (i = 0; i < len; i++)
-		tegra_pinmux_config_pingroup(config[i].pingroup,
-					     config[i].func,
-					     config[i].pupd,
-					     config[i].tristate);
+		tegra_pinmux_config_pingroup(&config[i]);
 }
 
 static const char *drive_pinmux_name(enum tegra_drive_pingroup pg)
@@ -784,6 +584,86 @@
 						     config[i].slew_falling);
 }
 
+void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
+	int len)
+{
+	int i;
+	struct tegra_pingroup_config c;
+
+	for (i = 0; i < len; i++) {
+		int err;
+		c = config[i];
+		if (c.pingroup < 0 || c.pingroup >= TEGRA_MAX_PINGROUP) {
+			WARN_ON(1);
+			continue;
+		}
+		c.func = pingroups[c.pingroup].func_safe;
+		err = tegra_pinmux_set_func(&c);
+		if (err < 0)
+			pr_err("%s: tegra_pinmux_set_func returned %d setting "
+			       "%s to %s\n", __func__, err,
+			       pingroup_name(c.pingroup), func_name(c.func));
+	}
+}
+
+void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
+	int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		int err;
+		if (config[i].pingroup < 0 ||
+		    config[i].pingroup >= TEGRA_MAX_PINGROUP) {
+			WARN_ON(1);
+			continue;
+		}
+		err = tegra_pinmux_set_func(&config[i]);
+		if (err < 0)
+			pr_err("%s: tegra_pinmux_set_func returned %d setting "
+			       "%s to %s\n", __func__, err,
+			       pingroup_name(config[i].pingroup),
+			       func_name(config[i].func));
+	}
+}
+
+void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
+	int len, enum tegra_tristate tristate)
+{
+	int i;
+	int err;
+	enum tegra_pingroup pingroup;
+
+	for (i = 0; i < len; i++) {
+		pingroup = config[i].pingroup;
+		if (pingroups[pingroup].tri_reg >= 0) {
+			err = tegra_pinmux_set_tristate(pingroup, tristate);
+			if (err < 0)
+				pr_err("pinmux: can't set pingroup %s tristate"
+					" to %s: %d\n",	pingroup_name(pingroup),
+					tri_name(tristate), err);
+		}
+	}
+}
+
+void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
+	int len, enum tegra_pullupdown pupd)
+{
+	int i;
+	int err;
+	enum tegra_pingroup pingroup;
+
+	for (i = 0; i < len; i++) {
+		pingroup = config[i].pingroup;
+		if (pingroups[pingroup].pupd_reg >= 0) {
+			err = tegra_pinmux_set_pullupdown(pingroup, pupd);
+			if (err < 0)
+				pr_err("pinmux: can't set pingroup %s pullupdown"
+					" to %s: %d\n",	pingroup_name(pingroup),
+					pupd_name(pupd), err);
+		}
+	}
+}
 
 #ifdef	CONFIG_DEBUG_FS
 
@@ -812,11 +692,11 @@
 		len = strlen(pingroups[i].name);
 		dbg_pad_field(s, 5 - len);
 
-		if (pingroups[i].mux_reg == REG_N) {
+		if (pingroups[i].mux_reg < 0) {
 			seq_printf(s, "TEGRA_MUX_NONE");
 			len = strlen("NONE");
 		} else {
-			mux = (pg_readl(TEGRA_PP_MUX_CTL(pingroups[i].mux_reg)) >>
+			mux = (pg_readl(pingroups[i].mux_reg) >>
 			       pingroups[i].mux_bit) & 0x3;
 			if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
 				seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
@@ -829,21 +709,21 @@
 		}
 		dbg_pad_field(s, 13-len);
 
-		if (pingroups[i].mux_reg == REG_N) {
+		if (pingroups[i].pupd_reg < 0) {
 			seq_printf(s, "TEGRA_PUPD_NORMAL");
 			len = strlen("NORMAL");
 		} else {
-			pupd = (pg_readl(TEGRA_PP_PU_PD(pingroups[i].pupd_reg)) >>
+			pupd = (pg_readl(pingroups[i].pupd_reg) >>
 				pingroups[i].pupd_bit) & 0x3;
 			seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
 			len = strlen(pupd_name(pupd));
 		}
 		dbg_pad_field(s, 9 - len);
 
-		if (pingroups[i].tri_reg == REG_N) {
+		if (pingroups[i].tri_reg < 0) {
 			seq_printf(s, "TEGRA_TRI_NORMAL");
 		} else {
-			tri = (pg_readl(TEGRA_TRI_STATE(pingroups[i].tri_reg)) >>
+			tri = (pg_readl(pingroups[i].tri_reg) >>
 			       pingroups[i].tri_bit) & 0x1;
 
 			seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pinmux-t2-tables.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pinmux-t2-tables.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/pinmux-t2-tables.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/pinmux-t2-tables.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,260 @@
+/*
+ * linux/arch/arm/mach-tegra/pinmux-t2-tables.c
+ *
+ * Common pinmux configurations for Tegra 2 SoCs
+ *
+ * Copyright (C) 2010 NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <mach/iomap.h>
+#include <mach/pinmux.h>
+
+#define DRIVE_PINGROUP(pg_name, r)				\
+	[TEGRA_DRIVE_PINGROUP_ ## pg_name] = {			\
+		.name = #pg_name,				\
+		.reg = r					\
+	}
+
+const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
+	DRIVE_PINGROUP(AO1,		0x868),
+	DRIVE_PINGROUP(AO2,		0x86c),
+	DRIVE_PINGROUP(AT1,		0x870),
+	DRIVE_PINGROUP(AT2,		0x874),
+	DRIVE_PINGROUP(CDEV1,		0x878),
+	DRIVE_PINGROUP(CDEV2,		0x87c),
+	DRIVE_PINGROUP(CSUS,		0x880),
+	DRIVE_PINGROUP(DAP1,		0x884),
+	DRIVE_PINGROUP(DAP2,		0x888),
+	DRIVE_PINGROUP(DAP3,		0x88c),
+	DRIVE_PINGROUP(DAP4,		0x890),
+	DRIVE_PINGROUP(DBG,		0x894),
+	DRIVE_PINGROUP(LCD1,		0x898),
+	DRIVE_PINGROUP(LCD2,		0x89c),
+	DRIVE_PINGROUP(SDMMC2,		0x8a0),
+	DRIVE_PINGROUP(SDMMC3,		0x8a4),
+	DRIVE_PINGROUP(SPI,		0x8a8),
+	DRIVE_PINGROUP(UAA,		0x8ac),
+	DRIVE_PINGROUP(UAB,		0x8b0),
+	DRIVE_PINGROUP(UART2,		0x8b4),
+	DRIVE_PINGROUP(UART3,		0x8b8),
+	DRIVE_PINGROUP(VI1,		0x8bc),
+	DRIVE_PINGROUP(VI2,		0x8c0),
+	DRIVE_PINGROUP(XM2A,		0x8c4),
+	DRIVE_PINGROUP(XM2C,		0x8c8),
+	DRIVE_PINGROUP(XM2D,		0x8cc),
+	DRIVE_PINGROUP(XM2CLK,		0x8d0),
+	DRIVE_PINGROUP(MEMCOMP,		0x8d4),
+};
+
+#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe,		\
+		 tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b)	\
+	[TEGRA_PINGROUP_ ## pg_name] = {			\
+		.name = #pg_name,				\
+		.vddio = TEGRA_VDDIO_ ## vdd,			\
+		.funcs = {					\
+			TEGRA_MUX_ ## f0,			\
+			TEGRA_MUX_ ## f1,			\
+			TEGRA_MUX_ ## f2,			\
+			TEGRA_MUX_ ## f3,			\
+		},						\
+		.func_safe = TEGRA_MUX_ ## f_safe,		\
+		.tri_reg = tri_r,				\
+		.tri_bit = tri_b,				\
+		.mux_reg = mux_r,				\
+		.mux_bit = mux_b,				\
+		.pupd_reg = pupd_r,				\
+		.pupd_bit = pupd_b,				\
+	}
+
+const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
+	PINGROUP(ATA,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x14, 0,  0x80, 24, 0xA0, 0),
+	PINGROUP(ATB,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 1,  0x80, 16, 0xA0, 2),
+	PINGROUP(ATC,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 2,  0x80, 22, 0xA0, 4),
+	PINGROUP(ATD,   NAND,  IDE,       NAND,      GMI,       SDIO4,         IDE,       0x14, 3,  0x80, 20, 0xA0, 6),
+	PINGROUP(ATE,   NAND,  IDE,       NAND,      GMI,       RSVD,          IDE,       0x18, 25, 0x80, 12, 0xA0, 8),
+	PINGROUP(CDEV1, AUDIO, OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC,    OSC,       0x14, 4,  0x88, 2,  0xA8, 0),
+	PINGROUP(CDEV2, AUDIO, OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4,     OSC,       0x14, 5,  0x88, 4,  0xA8, 2),
+	PINGROUP(CRTP,  LCD,   CRT,       RSVD,      RSVD,      RSVD,          RSVD,      0x20, 14, 0x98, 20, 0xA4, 24),
+	PINGROUP(CSUS,  VI,    PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6,  0x88, 6,  0xAC, 24),
+	PINGROUP(DAP1,  AUDIO, DAP1,      RSVD,      GMI,       SDIO2,         DAP1,      0x14, 7,  0x88, 20, 0xA0, 10),
+	PINGROUP(DAP2,  AUDIO, DAP2,      TWC,       RSVD,      GMI,           DAP2,      0x14, 8,  0x88, 22, 0xA0, 12),
+	PINGROUP(DAP3,  BB,    DAP3,      RSVD,      RSVD,      RSVD,          DAP3,      0x14, 9,  0x88, 24, 0xA0, 14),
+	PINGROUP(DAP4,  UART,  DAP4,      RSVD,      GMI,       RSVD,          DAP4,      0x14, 10, 0x88, 26, 0xA0, 16),
+	PINGROUP(DDC,   LCD,   I2C2,      RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 31, 0x88, 0,  0xB0, 28),
+	PINGROUP(DTA,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD4,     0x14, 11, 0x84, 20, 0xA0, 18),
+	PINGROUP(DTB,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 12, 0x84, 22, 0xA0, 20),
+	PINGROUP(DTC,   VI,    RSVD,      RSVD,      VI,        RSVD,          RSVD1,     0x14, 13, 0x84, 26, 0xA0, 22),
+	PINGROUP(DTD,   VI,    RSVD,      SDIO2,     VI,        RSVD,          RSVD1,     0x14, 14, 0x84, 28, 0xA0, 24),
+	PINGROUP(DTE,   VI,    RSVD,      RSVD,      VI,        SPI1,          RSVD1,     0x14, 15, 0x84, 30, 0xA0, 26),
+	PINGROUP(DTF,   VI,    I2C3,      RSVD,      VI,        RSVD,          RSVD4,     0x20, 12, 0x98, 30, 0xA0, 28),
+	PINGROUP(GMA,   NAND,  UARTE,     SPI3,      GMI,       SDIO4,         SPI3,      0x14, 28, 0x84, 0,  0xB0, 20),
+	PINGROUP(GMB,   NAND,  IDE,       NAND,      GMI,       GMI_INT,       GMI,       0x18, 29, 0x88, 28, 0xB0, 22),
+	PINGROUP(GMC,   NAND,  UARTD,     SPI4,      GMI,       SFLASH,        SPI4,      0x14, 29, 0x84, 2,  0xB0, 24),
+	PINGROUP(GMD,   NAND,  RSVD,      NAND,      GMI,       SFLASH,        GMI,       0x18, 30, 0x88, 30, 0xB0, 26),
+	PINGROUP(GME,   NAND,  RSVD,      DAP5,      GMI,       SDIO4,         GMI,       0x18, 0,  0x8C, 0,  0xA8, 24),
+	PINGROUP(GPU,   UART,  PWM,       UARTA,     GMI,       RSVD,          RSVD4,     0x14, 16, 0x8C, 4,  0xA4, 20),
+	PINGROUP(GPU7,  SYS,   RTCK,      RSVD,      RSVD,      RSVD,          RTCK,      0x20, 11, 0x98, 28, 0xA4, 6),
+	PINGROUP(GPV,   SD,    PCIE,      RSVD,      RSVD,      RSVD,          PCIE,      0x14, 17, 0x8C, 2,  0xA0, 30),
+	PINGROUP(HDINT, LCD,   HDMI,      RSVD,      RSVD,      RSVD,          HDMI,      0x1C, 23, 0x84, 4,  0xAC, 22),
+	PINGROUP(I2CP,  SYS,   I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 18, 0x88, 8,  0xA4, 2),
+	PINGROUP(IRRX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 20, 0x88, 18, 0xA8, 22),
+	PINGROUP(IRTX,  UART,  UARTA,     UARTB,     GMI,       SPI4,          UARTB,     0x14, 19, 0x88, 16, 0xA8, 20),
+	PINGROUP(KBCA,  SYS,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL, KBC,       0x14, 22, 0x88, 10, 0xA4, 8),
+	PINGROUP(KBCB,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x14, 21, 0x88, 12, 0xA4, 10),
+	PINGROUP(KBCC,  SYS,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL, KBC,       0x18, 26, 0x88, 14, 0xA4, 12),
+	PINGROUP(KBCD,  SYS,   KBC,       NAND,      SDIO2,     MIO,           KBC,       0x20, 10, 0x98, 26, 0xA4, 14),
+	PINGROUP(KBCE,  SYS,   KBC,       NAND,      OWR,       RSVD,          KBC,       0x14, 26, 0x80, 28, 0xB0, 2),
+	PINGROUP(KBCF,  SYS,   KBC,       NAND,      TRACE,     MIO,           KBC,       0x14, 27, 0x80, 26, 0xB0, 0),
+	PINGROUP(LCSN,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 31, 0x90, 12, 0xAC, 20),
+	PINGROUP(LD0,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 0,  0x94, 0,  0xAC, 12),
+	PINGROUP(LD1,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 1,  0x94, 2,  0xAC, 12),
+	PINGROUP(LD10,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 10, 0x94, 20, 0xAC, 12),
+	PINGROUP(LD11,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 11, 0x94, 22, 0xAC, 12),
+	PINGROUP(LD12,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 12, 0x94, 24, 0xAC, 12),
+	PINGROUP(LD13,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 13, 0x94, 26, 0xAC, 12),
+	PINGROUP(LD14,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 14, 0x94, 28, 0xAC, 12),
+	PINGROUP(LD15,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 15, 0x94, 30, 0xAC, 12),
+	PINGROUP(LD16,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 16, 0x98, 0,  0xAC, 12),
+	PINGROUP(LD17,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 17, 0x98, 2,  0xAC, 12),
+	PINGROUP(LD2,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 2,  0x94, 4,  0xAC, 12),
+	PINGROUP(LD3,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 3,  0x94, 6,  0xAC, 12),
+	PINGROUP(LD4,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 4,  0x94, 8,  0xAC, 12),
+	PINGROUP(LD5,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 5,  0x94, 10, 0xAC, 12),
+	PINGROUP(LD6,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 6,  0x94, 12, 0xAC, 12),
+	PINGROUP(LD7,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 7,  0x94, 14, 0xAC, 12),
+	PINGROUP(LD8,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 8,  0x94, 16, 0xAC, 12),
+	PINGROUP(LD9,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 9,  0x94, 18, 0xAC, 12),
+	PINGROUP(LDC,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 30, 0x90, 14, 0xAC, 20),
+	PINGROUP(LDI,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 6,  0x98, 16, 0xAC, 18),
+	PINGROUP(LHP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 18, 0x98, 10, 0xAC, 16),
+	PINGROUP(LHP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 19, 0x98, 4,  0xAC, 14),
+	PINGROUP(LHP2,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 20, 0x98, 6,  0xAC, 14),
+	PINGROUP(LHS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x20, 7,  0x90, 22, 0xAC, 22),
+	PINGROUP(LM0,   LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          RSVD4,     0x1C, 24, 0x90, 26, 0xAC, 22),
+	PINGROUP(LM1,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      CRT,           RSVD3,     0x1C, 25, 0x90, 28, 0xAC, 22),
+	PINGROUP(LPP,   LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 8,  0x98, 14, 0xAC, 18),
+	PINGROUP(LPW0,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 3,  0x90, 0,  0xAC, 20),
+	PINGROUP(LPW1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x20, 4,  0x90, 2,  0xAC, 20),
+	PINGROUP(LPW2,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 5,  0x90, 4,  0xAC, 20),
+	PINGROUP(LSC0,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 27, 0x90, 18, 0xAC, 22),
+	PINGROUP(LSC1,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 28, 0x90, 20, 0xAC, 20),
+	PINGROUP(LSCK,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x1C, 29, 0x90, 16, 0xAC, 20),
+	PINGROUP(LSDA,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      HDMI,          DISPLAYA,  0x20, 1,  0x90, 8,  0xAC, 20),
+	PINGROUP(LSDI,  LCD,   DISPLAYA,  DISPLAYB,  SPI3,      RSVD,          DISPLAYA,  0x20, 2,  0x90, 6,  0xAC, 20),
+	PINGROUP(LSPI,  LCD,   DISPLAYA,  DISPLAYB,  XIO,       HDMI,          DISPLAYA,  0x20, 0,  0x90, 10, 0xAC, 22),
+	PINGROUP(LVP0,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 21, 0x90, 30, 0xAC, 22),
+	PINGROUP(LVP1,  LCD,   DISPLAYA,  DISPLAYB,  RSVD,      RSVD,          RSVD4,     0x1C, 22, 0x98, 8,  0xAC, 16),
+	PINGROUP(LVS,   LCD,   DISPLAYA,  DISPLAYB,  XIO,       RSVD,          RSVD4,     0x1C, 26, 0x90, 24, 0xAC, 22),
+	PINGROUP(OWC,   SYS,   OWR,       RSVD,      RSVD,      RSVD,          OWR,       0x14, 31, 0x84, 8,  0xB0, 30),
+	PINGROUP(PMC,   SYS,   PWR_ON,    PWR_INTR,  RSVD,      RSVD,          PWR_ON,    0x14, 23, 0x98, 18, -1,   -1),
+	PINGROUP(PTA,   NAND,  I2C2,      HDMI,      GMI,       RSVD,          RSVD4,     0x14, 24, 0x98, 22, 0xA4, 4),
+	PINGROUP(RM,    UART,  I2C,       RSVD,      RSVD,      RSVD,          RSVD4,     0x14, 25, 0x80, 14, 0xA4, 0),
+	PINGROUP(SDB,   SD,    UARTA,     PWM,       SDIO3,     SPI2,          PWM,       0x20, 15, 0x8C, 10, -1,   -1),
+	PINGROUP(SDC,   SD,    PWM,       TWC,       SDIO3,     SPI3,          TWC,       0x18, 1,  0x8C, 12, 0xAC, 28),
+	PINGROUP(SDD,   SD,    UARTA,     PWM,       SDIO3,     SPI3,          PWM,       0x18, 2,  0x8C, 14, 0xAC, 30),
+	PINGROUP(SDIO1, BB,    SDIO1,     RSVD,      UARTE,     UARTA,         RSVD2,     0x14, 30, 0x80, 30, 0xB0, 18),
+	PINGROUP(SLXA,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 3,  0x84, 6,  0xA4, 22),
+	PINGROUP(SLXC,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 5,  0x84, 10, 0xA4, 26),
+	PINGROUP(SLXD,  SD,    SPDIF,     SPI4,      SDIO3,     SPI2,          SPI4,      0x18, 6,  0x84, 12, 0xA4, 28),
+	PINGROUP(SLXK,  SD,    PCIE,      SPI4,      SDIO3,     SPI2,          PCIE,      0x18, 7,  0x84, 14, 0xA4, 30),
+	PINGROUP(SPDI,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 8,  0x8C, 8,  0xA4, 16),
+	PINGROUP(SPDO,  AUDIO, SPDIF,     RSVD,      I2C,       SDIO2,         RSVD2,     0x18, 9,  0x8C, 6,  0xA4, 18),
+	PINGROUP(SPIA,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 10, 0x8C, 30, 0xA8, 4),
+	PINGROUP(SPIB,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 11, 0x8C, 28, 0xA8, 6),
+	PINGROUP(SPIC,  AUDIO, SPI1,      SPI2,      SPI3,      GMI,           GMI,       0x18, 12, 0x8C, 26, 0xA8, 8),
+	PINGROUP(SPID,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 13, 0x8C, 24, 0xA8, 10),
+	PINGROUP(SPIE,  AUDIO, SPI2,      SPI1,      SPI2_ALT,  GMI,           GMI,       0x18, 14, 0x8C, 22, 0xA8, 12),
+	PINGROUP(SPIF,  AUDIO, SPI3,      SPI1,      SPI2,      RSVD,          RSVD4,     0x18, 15, 0x8C, 20, 0xA8, 14),
+	PINGROUP(SPIG,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 16, 0x8C, 18, 0xA8, 16),
+	PINGROUP(SPIH,  AUDIO, SPI3,      SPI2,      SPI2_ALT,  I2C,           SPI2_ALT,  0x18, 17, 0x8C, 16, 0xA8, 18),
+	PINGROUP(UAA,   BB,    SPI3,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 18, 0x80, 0,  0xAC, 0),
+	PINGROUP(UAB,   BB,    SPI2,      MIPI_HS,   UARTA,     ULPI,          MIPI_HS,   0x18, 19, 0x80, 2,  0xAC, 2),
+	PINGROUP(UAC,   BB,    OWR,       RSVD,      RSVD,      RSVD,          RSVD4,     0x18, 20, 0x80, 4,  0xAC, 4),
+	PINGROUP(UAD,   UART,  IRDA,      SPDIF,     UARTA,     SPI4,          SPDIF,     0x18, 21, 0x80, 6,  0xAC, 6),
+	PINGROUP(UCA,   UART,  UARTC,     RSVD,      GMI,       RSVD,          RSVD4,     0x18, 22, 0x84, 16, 0xAC, 8),
+	PINGROUP(UCB,   UART,  UARTC,     PWM,       GMI,       RSVD,          RSVD4,     0x18, 23, 0x84, 18, 0xAC, 10),
+	PINGROUP(UDA,   BB,    SPI1,      RSVD,      UARTD,     ULPI,          RSVD2,     0x20, 13, 0x80, 8,  0xB0, 16),
+	/* these pin groups only have pullup and pull down control */
+	PINGROUP(CK32,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 14),
+	PINGROUP(DDRC,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xAC, 26),
+	PINGROUP(PMCA,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 4),
+	PINGROUP(PMCB,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 6),
+	PINGROUP(PMCC,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 8),
+	PINGROUP(PMCD,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 10),
+	PINGROUP(PMCE,  SYS,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xB0, 12),
+	PINGROUP(XM2C,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 30),
+	PINGROUP(XM2D,  DDR,   RSVD,      RSVD,      RSVD,      RSVD,          RSVD,      -1,   -1, -1,   -1, 0xA8, 28),
+};
+
+#ifdef CONFIG_PM
+#define TRISTATE_REG_A         0x14
+#define TRISTATE_REG_NUM       4
+#define PIN_MUX_CTL_REG_A      0x80
+#define PIN_MUX_CTL_REG_NUM    8
+#define PULLUPDOWN_REG_A       0xa0
+#define PULLUPDOWN_REG_NUM     5
+
+static u32 pinmux_reg[TRISTATE_REG_NUM + PIN_MUX_CTL_REG_NUM +
+		     PULLUPDOWN_REG_NUM];
+
+static inline unsigned long pg_readl(unsigned long offset)
+{
+	return readl(IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+static inline void pg_writel(unsigned long value, unsigned long offset)
+{
+	writel(value, IO_TO_VIRT(TEGRA_APB_MISC_BASE + offset));
+}
+
+void tegra_pinmux_suspend(void)
+{
+	unsigned int i;
+	u32 *ctx = pinmux_reg;
+
+	for (i = 0; i < TRISTATE_REG_NUM; i++)
+		*ctx++ = pg_readl(TRISTATE_REG_A + i*4);
+
+	for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+		*ctx++ = pg_readl(PIN_MUX_CTL_REG_A + i*4);
+
+	for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+		*ctx++ = pg_readl(PULLUPDOWN_REG_A + i*4);
+}
+
+void tegra_pinmux_resume(void)
+{
+	unsigned int i;
+	u32 *ctx = pinmux_reg;
+
+	for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
+		pg_writel(*ctx++, PIN_MUX_CTL_REG_A + i*4);
+
+	for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
+		pg_writel(*ctx++, PULLUPDOWN_REG_A + i*4);
+
+	for (i = 0; i < TRISTATE_REG_NUM; i++)
+		pg_writel(*ctx++, TRISTATE_REG_A + i*4);
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_clocks.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_clocks.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_clocks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_clocks.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,14 +30,21 @@
 #include <mach/iomap.h>
 
 #include "clock.h"
+#include "fuse.h"
+#include "tegra2_dvfs.h"
 
 #define RST_DEVICES			0x004
 #define RST_DEVICES_SET			0x300
 #define RST_DEVICES_CLR			0x304
+#define RST_DEVICES_NUM			3
 
 #define CLK_OUT_ENB			0x010
 #define CLK_OUT_ENB_SET			0x320
 #define CLK_OUT_ENB_CLR			0x324
+#define CLK_OUT_ENB_NUM			3
+
+#define CLK_MASK_ARM			0x44
+#define MISC_CLK_ENB			0x48
 
 #define OSC_CTRL			0x50
 #define OSC_CTRL_OSC_FREQ_MASK		(3<<30)
@@ -45,6 +52,7 @@
 #define OSC_CTRL_OSC_FREQ_19_2MHZ	(1<<30)
 #define OSC_CTRL_OSC_FREQ_12MHZ		(2<<30)
 #define OSC_CTRL_OSC_FREQ_26MHZ		(3<<30)
+#define OSC_CTRL_MASK			0x3f2
 
 #define OSC_FREQ_DET			0x58
 #define OSC_FREQ_DET_TRIG		(1<<31)
@@ -53,10 +61,17 @@
 #define OSC_FREQ_DET_BUSY		(1<<31)
 #define OSC_FREQ_DET_CNT_MASK		0xFFFF
 
+#define PERIPH_CLK_SOURCE_I2S1		0x100
+#define PERIPH_CLK_SOURCE_EMC		0x19c
+#define PERIPH_CLK_SOURCE_OSC		0x1fc
+#define PERIPH_CLK_SOURCE_NUM \
+	((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
 #define PERIPH_CLK_SOURCE_MASK		(3<<30)
 #define PERIPH_CLK_SOURCE_SHIFT		30
 #define PERIPH_CLK_SOURCE_ENABLE	(1<<28)
-#define PERIPH_CLK_SOURCE_DIV_MASK	0xFF
+#define PERIPH_CLK_SOURCE_DIVU71_MASK	0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK	0xFFFF
 #define PERIPH_CLK_SOURCE_DIV_SHIFT	0
 
 #define PLL_BASE			0x0
@@ -79,8 +94,9 @@
 #define PLL_OUT_RESET_DISABLE		(1<<0)
 
 #define PLL_MISC(c)			(((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
+#define PLL_MISC_LOCK_ENABLE(c)		(((c)->flags & PLLU) ? (1<<22) : (1<<18))
+
 #define PLL_MISC_DCCON_SHIFT		20
-#define PLL_MISC_LOCK_ENABLE		(1<<18)
 #define PLL_MISC_CPCON_SHIFT		8
 #define PLL_MISC_CPCON_MASK		(0xF<<PLL_MISC_CPCON_SHIFT)
 #define PLL_MISC_LFCON_SHIFT		4
@@ -88,10 +104,14 @@
 #define PLL_MISC_VCOCON_SHIFT		0
 #define PLL_MISC_VCOCON_MASK		(0xF<<PLL_MISC_VCOCON_SHIFT)
 
+#define PLLU_BASE_POST_DIV		(1<<20)
+
 #define PLLD_MISC_CLKENABLE		(1<<30)
 #define PLLD_MISC_DIV_RST		(1<<23)
 #define PLLD_MISC_DCCON_SHIFT		12
 
+#define PLLE_MISC_READY			(1 << 15)
+
 #define PERIPH_CLK_TO_ENB_REG(c)	((c->clk_num / 32) * 4)
 #define PERIPH_CLK_TO_ENB_SET_REG(c)	((c->clk_num / 32) * 8)
 #define PERIPH_CLK_TO_ENB_BIT(c)	(1 << (c->clk_num % 32))
@@ -143,30 +163,37 @@
 	}
 }
 
-static int clk_div71_get_divider(struct clk *c, unsigned long rate)
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate)
 {
-	unsigned long divider_u71;
+	s64 divider_u71 = parent_rate * 2;
+	divider_u71 += rate - 1;
+	do_div(divider_u71, rate);
 
-	divider_u71 = DIV_ROUND_UP(c->rate * 2, rate);
+	if (divider_u71 - 2 < 0)
+		return 0;
 
-	if (divider_u71 - 2 > 255 || divider_u71 - 2 < 0)
+	if (divider_u71 - 2 > 255)
 		return -EINVAL;
 
 	return divider_u71 - 2;
 }
 
-static unsigned long tegra2_clk_recalculate_rate(struct clk *c)
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
 {
-	unsigned long rate;
-	rate = c->parent->rate;
+	s64 divider_u16;
 
-	if (c->mul != 0 && c->div != 0)
-		c->rate = rate * c->mul / c->div;
-	else
-		c->rate = rate;
-	return c->rate;
-}
+	divider_u16 = parent_rate;
+	divider_u16 += rate - 1;
+	do_div(divider_u16, rate);
+
+	if (divider_u16 - 1 < 0)
+		return 0;
 
+	if (divider_u16 - 1 > 255)
+		return -EINVAL;
+
+	return divider_u16 - 1;
+}
 
 /* clk_m functions */
 static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c)
@@ -244,7 +271,6 @@
 	}
 	BUG_ON(sel->input == NULL);
 	c->parent = sel->input;
-	tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_super_clk_enable(struct clk *c)
@@ -266,6 +292,7 @@
 	u32 val;
 	const struct clk_mux_sel *sel;
 	int shift;
+
 	val = clk_readl(c->reg + SUPER_CLK_MUX);;
 	BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
 		((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
@@ -273,11 +300,18 @@
 		SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
 	for (sel = c->inputs; sel->input != NULL; sel++) {
 		if (sel->input == p) {
-			clk_reparent(c, p);
 			val &= ~(SUPER_SOURCE_MASK << shift);
 			val |= sel->value << shift;
+
+			if (c->refcnt)
+				clk_enable_locked(p);
+
 			clk_writel(val, c->reg);
-			c->rate = c->parent->rate;
+
+			if (c->refcnt && c->parent)
+				clk_disable_locked(c->parent);
+
+			clk_reparent(c, p);
 			return 0;
 		}
 	}
@@ -289,7 +323,61 @@
 	.enable			= tegra2_super_clk_enable,
 	.disable		= tegra2_super_clk_disable,
 	.set_parent		= tegra2_super_clk_set_parent,
-	.recalculate_rate	= tegra2_clk_recalculate_rate,
+};
+
+/* virtual cpu clock functions */
+/* some clocks can not be stopped (cpu, memory bus) while the SoC is running.
+   To change the frequency of these clocks, the parent pll may need to be
+   reprogrammed, so the clock must be moved off the pll, the pll reprogrammed,
+   and then the clock moved back to the pll.  To hide this sequence, a virtual
+   clock handles it.
+ */
+static void tegra2_cpu_clk_init(struct clk *c)
+{
+}
+
+static int tegra2_cpu_clk_enable(struct clk *c)
+{
+	return 0;
+}
+
+static void tegra2_cpu_clk_disable(struct clk *c)
+{
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	/* oops - don't disable the CPU clock! */
+	BUG();
+}
+
+static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	int ret;
+	ret = clk_set_parent_locked(c->parent, c->backup);
+	if (ret) {
+		pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
+		return ret;
+	}
+
+	ret = clk_set_rate_locked(c->main, rate);
+	if (ret) {
+		pr_err("Failed to change cpu pll to %lu\n", rate);
+		return ret;
+	}
+
+	ret = clk_set_parent_locked(c->parent, c->main);
+	if (ret) {
+		pr_err("Failed to switch cpu to clock %s\n", c->main->name);
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct clk_ops tegra_cpu_ops = {
+	.init     = tegra2_cpu_clk_init,
+	.enable   = tegra2_cpu_clk_enable,
+	.disable  = tegra2_cpu_clk_disable,
+	.set_rate = tegra2_cpu_clk_set_rate,
 };
 
 /* bus clock functions */
@@ -299,7 +387,6 @@
 	c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON;
 	c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1;
 	c->mul = 1;
-	tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_bus_clk_enable(struct clk *c)
@@ -340,27 +427,15 @@
 	.enable			= tegra2_bus_clk_enable,
 	.disable		= tegra2_bus_clk_disable,
 	.set_rate		= tegra2_bus_clk_set_rate,
-	.recalculate_rate	= tegra2_clk_recalculate_rate,
 };
 
 /* PLL Functions */
-static unsigned long tegra2_pll_clk_recalculate_rate(struct clk *c)
-{
-	u64 rate;
-	rate = c->parent->rate;
-	rate *= c->n;
-	do_div(rate, c->m);
-	if (c->p == 2)
-		rate >>= 1;
-	c->rate = rate;
-	return c->rate;
-}
-
 static int tegra2_pll_clk_wait_for_lock(struct clk *c)
 {
 	ktime_t before;
 
 	before = ktime_get();
+
 	while (!(clk_readl(c->reg + PLL_BASE) & PLL_BASE_LOCK)) {
 		if (ktime_us_delta(ktime_get(), before) > 5000) {
 			pr_err("Timed out waiting for lock bit on pll %s",
@@ -380,24 +455,19 @@
 
 	if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
 		pr_warning("Clock %s has unknown fixed frequency\n", c->name);
-		c->n = 1;
-		c->m = 0;
-		c->p = 1;
+		c->mul = 1;
+		c->div = 1;
 	} else if (val & PLL_BASE_BYPASS) {
-		c->n = 1;
-		c->m = 1;
-		c->p = 1;
+		c->mul = 1;
+		c->div = 1;
 	} else {
-		c->n = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
-		c->m = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
-		c->p = (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
+		c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+		c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+		if (c->flags & PLLU)
+			c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+		else
+			c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1;
 	}
-
-	val = clk_readl(c->reg + PLL_MISC(c));
-	if (c->flags & PLL_HAS_CPCON)
-		c->cpcon = (val & PLL_MISC_CPCON_MASK) >> PLL_MISC_CPCON_SHIFT;
-
-	tegra2_pll_clk_recalculate_rate(c);
 }
 
 static int tegra2_pll_clk_enable(struct clk *c)
@@ -411,7 +481,7 @@
 	clk_writel(val, c->reg + PLL_BASE);
 
 	val = clk_readl(c->reg + PLL_MISC(c));
-	val |= PLL_MISC_LOCK_ENABLE;
+	val |= PLL_MISC_LOCK_ENABLE(c);
 	clk_writel(val, c->reg + PLL_MISC(c));
 
 	tegra2_pll_clk_wait_for_lock(c);
@@ -441,33 +511,36 @@
 	input_rate = c->parent->rate;
 	for (sel = c->pll_table; sel->input_rate != 0; sel++) {
 		if (sel->input_rate == input_rate && sel->output_rate == rate) {
-			c->n = sel->n;
-			c->m = sel->m;
-			c->p = sel->p;
-			c->cpcon = sel->cpcon;
+			c->mul = sel->n;
+			c->div = sel->m * sel->p;
 
 			val = clk_readl(c->reg + PLL_BASE);
 			if (c->flags & PLL_FIXED)
 				val |= PLL_BASE_OVERRIDE;
 			val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK |
 				 PLL_BASE_DIVM_MASK);
-			val |= (c->m << PLL_BASE_DIVM_SHIFT) |
-				(c->n << PLL_BASE_DIVN_SHIFT);
-			BUG_ON(c->p > 2);
-			if (c->p == 2)
-				val |= 1 << PLL_BASE_DIVP_SHIFT;
+			val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+				(sel->n << PLL_BASE_DIVN_SHIFT);
+			BUG_ON(sel->p < 1 || sel->p > 2);
+			if (c->flags & PLLU) {
+				if (sel->p == 1)
+					val |= PLLU_BASE_POST_DIV;
+			} else {
+				if (sel->p == 2)
+					val |= 1 << PLL_BASE_DIVP_SHIFT;
+			}
 			clk_writel(val, c->reg + PLL_BASE);
 
 			if (c->flags & PLL_HAS_CPCON) {
-				val = c->cpcon << PLL_MISC_CPCON_SHIFT;
-				val |= PLL_MISC_LOCK_ENABLE;
+				val = clk_readl(c->reg + PLL_MISC(c));
+				val &= ~PLL_MISC_CPCON_MASK;
+				val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
 				clk_writel(val, c->reg + PLL_MISC(c));
 			}
 
 			if (c->state == ON)
 				tegra2_pll_clk_enable(c);
 
-			c->rate = rate;
 			return 0;
 		}
 	}
@@ -479,7 +552,46 @@
 	.enable			= tegra2_pll_clk_enable,
 	.disable		= tegra2_pll_clk_disable,
 	.set_rate		= tegra2_pll_clk_set_rate,
-	.recalculate_rate	= tegra2_pll_clk_recalculate_rate,
+};
+
+static void tegra2_pllx_clk_init(struct clk *c)
+{
+	tegra2_pll_clk_init(c);
+
+	if (tegra_sku_id() == 7)
+		c->max_rate = 750000000;
+}
+
+static struct clk_ops tegra_pllx_ops = {
+	.init     = tegra2_pllx_clk_init,
+	.enable   = tegra2_pll_clk_enable,
+	.disable  = tegra2_pll_clk_disable,
+	.set_rate = tegra2_pll_clk_set_rate,
+};
+
+static int tegra2_plle_clk_enable(struct clk *c)
+{
+	u32 val;
+
+	pr_debug("%s on clock %s\n", __func__, c->name);
+
+	mdelay(1);
+
+	val = clk_readl(c->reg + PLL_BASE);
+	if (!(val & PLLE_MISC_READY))
+		return -EBUSY;
+
+	val = clk_readl(c->reg + PLL_BASE);
+	val |= PLL_BASE_ENABLE | PLL_BASE_BYPASS;
+	clk_writel(val, c->reg + PLL_BASE);
+
+	return 0;
+}
+
+static struct clk_ops tegra_plle_ops = {
+	.init       = tegra2_pll_clk_init,
+	.enable     = tegra2_plle_clk_enable,
+	.set_rate   = tegra2_pll_clk_set_rate,
 };
 
 /* Clock divider ops */
@@ -503,8 +615,6 @@
 		c->div = 1;
 		c->mul = 1;
 	}
-
-	tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_pll_div_clk_enable(struct clk *c)
@@ -565,7 +675,7 @@
 	int divider_u71;
 	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 	if (c->flags & DIV_U71) {
-		divider_u71 = clk_div71_get_divider(c->parent, rate);
+		divider_u71 = clk_div71_get_divider(c->parent->rate, rate);
 		if (divider_u71 >= 0) {
 			val = clk_readl(c->reg);
 			new_val = val >> c->reg_shift;
@@ -580,25 +690,37 @@
 			clk_writel(val, c->reg);
 			c->div = divider_u71 + 2;
 			c->mul = 2;
-			tegra2_clk_recalculate_rate(c);
 			return 0;
 		}
 	} else if (c->flags & DIV_2) {
-		if (c->parent->rate == rate * 2) {
-			c->rate = rate;
+		if (c->parent->rate == rate * 2)
 			return 0;
-		}
 	}
 	return -EINVAL;
 }
 
+static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	int divider;
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(c->parent->rate, rate);
+		if (divider < 0)
+			return divider;
+		return c->parent->rate * 2 / (divider + 2);
+	} else if (c->flags & DIV_2) {
+		return c->parent->rate / 2;
+	}
+	return -EINVAL;
+}
 
 static struct clk_ops tegra_pll_div_ops = {
 	.init			= tegra2_pll_div_clk_init,
 	.enable			= tegra2_pll_div_clk_enable,
 	.disable		= tegra2_pll_div_clk_disable,
 	.set_rate		= tegra2_pll_div_clk_set_rate,
-	.recalculate_rate	= tegra2_clk_recalculate_rate,
+	.round_rate		= tegra2_pll_div_clk_round_rate,
 };
 
 /* Periph clk ops */
@@ -621,9 +743,13 @@
 	}
 
 	if (c->flags & DIV_U71) {
-		u32 divu71 = val & PERIPH_CLK_SOURCE_DIV_MASK;
+		u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
 		c->div = divu71 + 2;
 		c->mul = 2;
+	} else if (c->flags & DIV_U16) {
+		u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+		c->div = divu16 + 1;
+		c->mul = 1;
 	} else {
 		c->div = 1;
 		c->mul = 1;
@@ -637,7 +763,6 @@
 		if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
 				PERIPH_CLK_TO_ENB_BIT(c))
 			c->state = OFF;
-	tegra2_clk_recalculate_rate(c);
 }
 
 static int tegra2_periph_clk_enable(struct clk *c)
@@ -692,12 +817,19 @@
 	pr_debug("%s: %s %s\n", __func__, c->name, p->name);
 	for (sel = c->inputs; sel->input != NULL; sel++) {
 		if (sel->input == p) {
-			clk_reparent(c, p);
 			val = clk_readl(c->reg);
 			val &= ~PERIPH_CLK_SOURCE_MASK;
 			val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
+
+			if (c->refcnt)
+				clk_enable_locked(p);
+
 			clk_writel(val, c->reg);
-			c->rate = c->parent->rate;
+
+			if (c->refcnt && c->parent)
+				clk_disable_locked(c->parent);
+
+			clk_reparent(c, p);
 			return 0;
 		}
 	}
@@ -708,20 +840,55 @@
 static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
 {
 	u32 val;
-	int divider_u71;
+	int divider;
 	pr_debug("%s: %lu\n", __func__, rate);
 	if (c->flags & DIV_U71) {
-		divider_u71 = clk_div71_get_divider(c->parent, rate);
-		if (divider_u71 >= 0) {
+		divider = clk_div71_get_divider(c->parent->rate, rate);
+		if (divider >= 0) {
 			val = clk_readl(c->reg);
-			val &= ~PERIPH_CLK_SOURCE_DIV_MASK;
-			val |= divider_u71;
+			val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+			val |= divider;
 			clk_writel(val, c->reg);
-			c->div = divider_u71 + 2;
+			c->div = divider + 2;
 			c->mul = 2;
-			tegra2_clk_recalculate_rate(c);
 			return 0;
 		}
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(c->parent->rate, rate);
+		if (divider >= 0) {
+			val = clk_readl(c->reg);
+			val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+			val |= divider;
+			clk_writel(val, c->reg);
+			c->div = divider + 1;
+			c->mul = 1;
+			return 0;
+		}
+	} else if (c->parent->rate <= rate) {
+		c->div = 1;
+		c->mul = 1;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static long tegra2_periph_clk_round_rate(struct clk *c,
+	unsigned long rate)
+{
+	int divider;
+	pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+	if (c->flags & DIV_U71) {
+		divider = clk_div71_get_divider(c->parent->rate, rate);
+		if (divider < 0)
+			return divider;
+
+		return c->parent->rate * 2 / (divider + 2);
+	} else if (c->flags & DIV_U16) {
+		divider = clk_div16_get_divider(c->parent->rate, rate);
+		if (divider < 0)
+			return divider;
+		return c->parent->rate / (divider + 1);
 	}
 	return -EINVAL;
 }
@@ -732,7 +899,7 @@
 	.disable		= &tegra2_periph_clk_disable,
 	.set_parent		= &tegra2_periph_clk_set_parent,
 	.set_rate		= &tegra2_periph_clk_set_rate,
-	.recalculate_rate	= &tegra2_clk_recalculate_rate,
+	.round_rate		= &tegra2_periph_clk_round_rate,
 };
 
 /* Clock doubler ops */
@@ -744,21 +911,108 @@
 	if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
 			PERIPH_CLK_TO_ENB_BIT(c)))
 		c->state = OFF;
-	tegra2_clk_recalculate_rate(c);
 };
 
+static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+	if (rate != 2 * c->parent->rate)
+		return -EINVAL;
+	c->mul = 2;
+	c->div = 1;
+	return 0;
+}
+
 static struct clk_ops tegra_clk_double_ops = {
 	.init			= &tegra2_clk_double_init,
 	.enable			= &tegra2_periph_clk_enable,
 	.disable		= &tegra2_periph_clk_disable,
-	.recalculate_rate	= &tegra2_clk_recalculate_rate,
+	.set_rate		= &tegra2_clk_double_set_rate,
+};
+
+static void tegra2_audio_sync_clk_init(struct clk *c)
+{
+	int source;
+	const struct clk_mux_sel *sel;
+	u32 val = clk_readl(c->reg);
+	c->state = (val & (1<<4)) ? OFF : ON;
+	source = val & 0xf;
+	for (sel = c->inputs; sel->input != NULL; sel++)
+		if (sel->value == source)
+			break;
+	BUG_ON(sel->input == NULL);
+	c->parent = sel->input;
+}
+
+static int tegra2_audio_sync_clk_enable(struct clk *c)
+{
+	clk_writel(0, c->reg);
+	return 0;
+}
+
+static void tegra2_audio_sync_clk_disable(struct clk *c)
+{
+	clk_writel(1, c->reg);
+}
+
+static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+	u32 val;
+	const struct clk_mux_sel *sel;
+	for (sel = c->inputs; sel->input != NULL; sel++) {
+		if (sel->input == p) {
+			val = clk_readl(c->reg);
+			val &= ~0xf;
+			val |= sel->value;
+
+			if (c->refcnt)
+				clk_enable_locked(p);
+
+			clk_writel(val, c->reg);
+
+			if (c->refcnt && c->parent)
+				clk_disable_locked(c->parent);
+
+			clk_reparent(c, p);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate)
+{
+	unsigned long parent_rate;
+	if (!c->parent) {
+		pr_err("%s: clock has no parent\n", __func__);
+		return -EINVAL;
+	}
+	parent_rate = c->parent->rate;
+	if (rate != parent_rate) {
+		pr_err("%s: %s/%ld differs from parent %s/%ld\n",
+			__func__,
+			c->name, rate,
+			c->parent->name, parent_rate);
+		return -EINVAL;
+	}
+	c->rate = parent_rate;
+	return 0;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+	.init       = tegra2_audio_sync_clk_init,
+	.enable     = tegra2_audio_sync_clk_enable,
+	.disable    = tegra2_audio_sync_clk_disable,
+	.set_rate   = tegra2_audio_sync_clk_set_rate,
+	.set_parent = tegra2_audio_sync_clk_set_parent,
 };
 
 /* Clock definitions */
 static struct clk tegra_clk_32k = {
 	.name = "clk_32k",
-	.rate = 32678,
+	.rate = 32768,
 	.ops  = NULL,
+	.max_rate = 32768,
 };
 
 static struct clk_pll_table tegra_pll_s_table[] = {
@@ -782,6 +1036,7 @@
 	.vco_min   = 12000000,
 	.vco_max   = 26000000,
 	.pll_table = tegra_pll_s_table,
+	.max_rate  = 26000000,
 };
 
 static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -797,6 +1052,7 @@
 	.reg       = 0x1fc,
 	.reg_mask  = (1<<28),
 	.reg_shift = 28,
+	.max_rate  = 26000000,
 };
 
 static struct clk_pll_table tegra_pll_c_table[] = {
@@ -816,6 +1072,7 @@
 	.vco_min   = 20000000,
 	.vco_max   = 1400000000,
 	.pll_table = tegra_pll_c_table,
+	.max_rate  = 600000000,
 };
 
 static struct clk tegra_pll_c_out1 = {
@@ -825,9 +1082,18 @@
 	.parent    = &tegra_pll_c,
 	.reg       = 0x84,
 	.reg_shift = 0,
+	.max_rate  = 600000000,
 };
 
 static struct clk_pll_table tegra_pll_m_table[] = {
+	{ 12000000, 666000000, 666, 12, 1, 8},
+	{ 13000000, 666000000, 666, 13, 1, 8},
+	{ 19200000, 666000000, 555, 16, 1, 8},
+	{ 26000000, 666000000, 666, 26, 1, 8},
+	{ 12000000, 600000000, 600, 12, 1, 8},
+	{ 13000000, 600000000, 600, 13, 1, 8},
+	{ 19200000, 600000000, 375, 12, 1, 6},
+	{ 26000000, 600000000, 600, 26, 1, 8},
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
@@ -844,6 +1110,7 @@
 	.vco_min   = 20000000,
 	.vco_max   = 1200000000,
 	.pll_table = tegra_pll_m_table,
+	.max_rate  = 800000000,
 };
 
 static struct clk tegra_pll_m_out1 = {
@@ -853,6 +1120,7 @@
 	.parent    = &tegra_pll_m,
 	.reg       = 0x94,
 	.reg_shift = 0,
+	.max_rate  = 600000000,
 };
 
 static struct clk_pll_table tegra_pll_p_table[] = {
@@ -880,6 +1148,7 @@
 	.vco_min   = 20000000,
 	.vco_max   = 1400000000,
 	.pll_table = tegra_pll_p_table,
+	.max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out1 = {
@@ -889,6 +1158,7 @@
 	.parent    = &tegra_pll_p,
 	.reg       = 0xa4,
 	.reg_shift = 0,
+	.max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out2 = {
@@ -898,6 +1168,7 @@
 	.parent    = &tegra_pll_p,
 	.reg       = 0xa4,
 	.reg_shift = 16,
+	.max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out3 = {
@@ -907,6 +1178,7 @@
 	.parent    = &tegra_pll_p,
 	.reg       = 0xa8,
 	.reg_shift = 0,
+	.max_rate  = 432000000,
 };
 
 static struct clk tegra_pll_p_out4 = {
@@ -916,6 +1188,7 @@
 	.parent    = &tegra_pll_p,
 	.reg       = 0xa8,
 	.reg_shift = 16,
+	.max_rate  = 432000000,
 };
 
 static struct clk_pll_table tegra_pll_a_table[] = {
@@ -923,6 +1196,7 @@
 	{ 28800000, 73728000, 64, 25, 1, 1},
 	{ 28800000, 11289600, 49, 25, 1, 1},
 	{ 28800000, 12288000, 64, 25, 1, 1},
+	{ 28800000, 24000000,  5,  6, 1, 1},
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
@@ -939,6 +1213,7 @@
 	.vco_min   = 20000000,
 	.vco_max   = 1400000000,
 	.pll_table = tegra_pll_a_table,
+	.max_rate  = 56448000,
 };
 
 static struct clk tegra_pll_a_out0 = {
@@ -948,6 +1223,7 @@
 	.parent    = &tegra_pll_a,
 	.reg       = 0xb4,
 	.reg_shift = 0,
+	.max_rate  = 56448000,
 };
 
 static struct clk_pll_table tegra_pll_d_table[] = {
@@ -971,6 +1247,7 @@
 	.vco_min   = 40000000,
 	.vco_max   = 1000000000,
 	.pll_table = tegra_pll_d_table,
+	.max_rate  = 1000000000,
 };
 
 static struct clk tegra_pll_d_out0 = {
@@ -978,19 +1255,20 @@
 	.ops       = &tegra_pll_div_ops,
 	.flags     = DIV_2 | PLLD,
 	.parent    = &tegra_pll_d,
+	.max_rate  = 500000000,
 };
 
 static struct clk_pll_table tegra_pll_u_table[] = {
-	{ 12000000, 480000000, 960, 12, 1, 0},
-	{ 13000000, 480000000, 960, 13, 1, 0},
-	{ 19200000, 480000000, 200, 4,  1, 0},
-	{ 26000000, 480000000, 960, 26, 1, 0},
+	{ 12000000, 480000000, 960, 12, 2, 0},
+	{ 13000000, 480000000, 960, 13, 2, 0},
+	{ 19200000, 480000000, 200, 4,  2, 0},
+	{ 26000000, 480000000, 960, 26, 2, 0},
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
 static struct clk tegra_pll_u = {
 	.name      = "pll_u",
-	.flags     = 0,
+	.flags     = PLLU,
 	.ops       = &tegra_pll_ops,
 	.reg       = 0xc0,
 	.input_min = 2000000,
@@ -1001,24 +1279,59 @@
 	.vco_min   = 480000000,
 	.vco_max   = 960000000,
 	.pll_table = tegra_pll_u_table,
+	.max_rate  = 480000000,
 };
 
 static struct clk_pll_table tegra_pll_x_table[] = {
+	/* 1 GHz */
 	{ 12000000, 1000000000, 1000, 12, 1, 12},
 	{ 13000000, 1000000000, 1000, 13, 1, 12},
 	{ 19200000, 1000000000, 625,  12, 1, 8},
 	{ 26000000, 1000000000, 1000, 26, 1, 12},
-	{ 12000000, 750000000,  750,  12, 1, 12},
-	{ 13000000, 750000000,  750,  13, 1, 12},
-	{ 19200000, 750000000,  625,  16, 1, 8},
-	{ 26000000, 750000000,  750,  26, 1, 12},
+
+	/* 912 MHz */
+	{ 12000000, 912000000,  912,  12, 1, 12},
+	{ 13000000, 912000000,  912,  13, 1, 12},
+	{ 19200000, 912000000,  760,  16, 1, 8},
+	{ 26000000, 912000000,  912,  26, 1, 12},
+
+	/* 816 MHz */
+	{ 12000000, 816000000,  816,  12, 1, 12},
+	{ 13000000, 816000000,  816,  13, 1, 12},
+	{ 19200000, 816000000,  680,  16, 1, 8},
+	{ 26000000, 816000000,  816,  26, 1, 12},
+
+	/* 760 MHz */
+	{ 12000000, 760000000,  760,  12, 1, 12},
+	{ 13000000, 760000000,  760,  13, 1, 12},
+	{ 19200000, 760000000,  950,  24, 1, 8},
+	{ 26000000, 760000000,  760,  26, 1, 12},
+
+	/* 608 MHz */
+	{ 12000000, 608000000,  760,  12, 1, 12},
+	{ 13000000, 608000000,  760,  13, 1, 12},
+	{ 19200000, 608000000,  380,  12, 1, 8},
+	{ 26000000, 608000000,  760,  26, 1, 12},
+
+	/* 456 MHz */
+	{ 12000000, 456000000,  456,  12, 1, 12},
+	{ 13000000, 456000000,  456,  13, 1, 12},
+	{ 19200000, 456000000,  380,  16, 1, 8},
+	{ 26000000, 456000000,  456,  26, 1, 12},
+
+	/* 312 MHz */
+	{ 12000000, 312000000,  312,  12, 1, 12},
+	{ 13000000, 312000000,  312,  13, 1, 12},
+	{ 19200000, 312000000,  260,  16, 1, 8},
+	{ 26000000, 312000000,  312,  26, 1, 12},
+
 	{ 0, 0, 0, 0, 0, 0 },
 };
 
 static struct clk tegra_pll_x = {
 	.name      = "pll_x",
 	.flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
-	.ops       = &tegra_pll_ops,
+	.ops       = &tegra_pllx_ops,
 	.reg       = 0xe0,
 	.input_min = 2000000,
 	.input_max = 31000000,
@@ -1028,6 +1341,24 @@
 	.vco_min   = 20000000,
 	.vco_max   = 1200000000,
 	.pll_table = tegra_pll_x_table,
+	.max_rate  = 1000000000,
+};
+
+static struct clk_pll_table tegra_pll_e_table[] = {
+	{ 12000000, 100000000,  200,  24, 1, 0 },
+	{ 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+	.name      = "pll_e",
+	.flags	   = PLL_ALT_MISC_REG,
+	.ops       = &tegra_plle_ops,
+	.input_min = 12000000,
+	.input_max = 12000000,
+	.max_rate  = 100000000,
+	.parent    = &tegra_clk_m,
+	.reg       = 0xe8,
+	.pll_table = tegra_pll_e_table,
 };
 
 static struct clk tegra_clk_d = {
@@ -1038,19 +1369,77 @@
 	.reg       = 0x34,
 	.reg_shift = 12,
 	.parent    = &tegra_clk_m,
+	.max_rate  = 52000000,
+};
+
+/* initialized before peripheral clocks */
+static struct clk_mux_sel mux_audio_sync_clk[8+1];
+static const struct audio_sources {
+	const char *name;
+	int value;
+} mux_audio_sync_clk_sources[] = {
+	{ .name = "spdif_in", .value = 0 },
+	{ .name = "i2s1", .value = 1 },
+	{ .name = "i2s2", .value = 2 },
+	{ .name = "pll_a_out0", .value = 4 },
+#if 0 /* FIXME: not implemented */
+	{ .name = "ac97", .value = 3 },
+	{ .name = "ext_audio_clk2", .value = 5 },
+	{ .name = "ext_audio_clk1", .value = 6 },
+	{ .name = "ext_vimclk", .value = 7 },
+#endif
+	{ 0, 0 }
+};
+
+static struct clk tegra_clk_audio = {
+	.name      = "audio",
+	.inputs    = mux_audio_sync_clk,
+	.reg       = 0x38,
+	.max_rate  = 24000000,
+	.ops       = &tegra_audio_sync_clk_ops
 };
 
-/* FIXME: need tegra_audio
 static struct clk tegra_clk_audio_2x = {
-	.name      = "clk_d",
+	.name      = "audio_2x",
 	.flags     = PERIPH_NO_RESET,
+	.max_rate  = 48000000,
 	.ops       = &tegra_clk_double_ops,
 	.clk_num   = 89,
 	.reg       = 0x34,
 	.reg_shift = 8,
-	.parent    = &tegra_audio,
+	.parent    = &tegra_clk_audio,
+};
+
+struct clk_lookup tegra_audio_clk_lookups[] = {
+	{ .con_id = "audio", .clk = &tegra_clk_audio },
+	{ .con_id = "audio_2x", .clk = &tegra_clk_audio_2x }
+};
+
+/* This is called after peripheral clocks are initialized, as the
+ * audio_sync clock depends on some of the peripheral clocks.
+ */
+
+static void init_audio_sync_clock_mux(void)
+{
+	int i;
+	struct clk_mux_sel *sel = mux_audio_sync_clk;
+	const struct audio_sources *src = mux_audio_sync_clk_sources;
+	struct clk_lookup *lookup;
+
+	for (i = 0; src->name; i++, sel++, src++) {
+		sel->input = tegra_get_clock_by_name(src->name);
+		if (!sel->input)
+			pr_err("%s: could not find clk %s\n", __func__,
+				src->name);
+		sel->value = src->value;
+	}
+
+	lookup = tegra_audio_clk_lookups;
+	for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) {
+		clk_init(lookup->clk);
+		clkdev_add(lookup);
+	}
 }
-*/
 
 static struct clk_mux_sel mux_cclk[] = {
 	{ .input = &tegra_clk_m,	.value = 0},
@@ -1077,27 +1466,40 @@
 	{ 0, 0},
 };
 
-static struct clk tegra_clk_cpu = {
-	.name	= "cpu",
+static struct clk tegra_clk_cclk = {
+	.name	= "cclk",
 	.inputs	= mux_cclk,
 	.reg	= 0x20,
 	.ops	= &tegra_super_ops,
+	.max_rate = 1000000000,
 };
 
-static struct clk tegra_clk_sys = {
-	.name	= "sys",
+static struct clk tegra_clk_sclk = {
+	.name	= "sclk",
 	.inputs	= mux_sclk,
 	.reg	= 0x28,
 	.ops	= &tegra_super_ops,
+	.max_rate = 600000000,
+};
+
+static struct clk tegra_clk_virtual_cpu = {
+	.name      = "cpu",
+	.parent    = &tegra_clk_cclk,
+	.main      = &tegra_pll_x,
+	.backup    = &tegra_clk_m,
+	.ops       = &tegra_cpu_ops,
+	.max_rate  = 1000000000,
+	.dvfs      = &tegra_dvfs_virtual_cpu_dvfs,
 };
 
 static struct clk tegra_clk_hclk = {
 	.name		= "hclk",
 	.flags		= DIV_BUS,
-	.parent		= &tegra_clk_sys,
+	.parent		= &tegra_clk_sclk,
 	.reg		= 0x30,
 	.reg_shift	= 4,
 	.ops		= &tegra_bus_ops,
+	.max_rate       = 240000000,
 };
 
 static struct clk tegra_clk_pclk = {
@@ -1107,6 +1509,7 @@
 	.reg		= 0x30,
 	.reg_shift	= 0,
 	.ops		= &tegra_bus_ops,
+	.max_rate       = 108000000,
 };
 
 static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
@@ -1133,10 +1536,9 @@
 	{ 0, 0},
 };
 
-static struct clk_mux_sel mux_plla_audio_pllp_clkm[] = {
-	{.input = &tegra_pll_a, .value = 0},
-	/* FIXME: no mux defined for tegra_audio
-	{.input = &tegra_audio, .value = 1},*/
+static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = {
+	{.input = &tegra_pll_a_out0, .value = 0},
+	{.input = &tegra_clk_audio_2x, .value = 1},
 	{.input = &tegra_pll_p, .value = 2},
 	{.input = &tegra_clk_m, .value = 3},
 	{ 0, 0},
@@ -1153,8 +1555,7 @@
 static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = {
 	{.input = &tegra_pll_p,     .value = 0},
 	{.input = &tegra_pll_c,     .value = 1},
-	/* FIXME: no mux defined for tegra_audio
-	{.input = &tegra_audio,     .value = 2},*/
+	{.input = &tegra_clk_audio,     .value = 2},
 	{.input = &tegra_clk_m,     .value = 3},
 	{.input = &tegra_clk_32k,   .value = 4},
 	{ 0, 0},
@@ -1187,7 +1588,7 @@
 	{ 0, 0},
 };
 
-#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _inputs, _flags) \
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
 	{						\
 		.name      = _name,			\
 		.lookup    = {				\
@@ -1199,72 +1600,79 @@
 		.reg       = _reg,			\
 		.inputs    = _inputs,			\
 		.flags     = _flags,			\
+		.max_rate  = _max,			\
 	}
 
 struct clk tegra_periph_clks[] = {
-	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	mux_clk_32k,			PERIPH_NO_RESET),
-	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	mux_clk_m,			0),
-	PERIPH_CLK("i2s1",	"i2s.0",		NULL,	11,	0x100,	mux_plla_audio_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2s2",	"i2s.1",		NULL,	18,	0x104,	mux_plla_audio_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("rtc",	"rtc-tegra",		NULL,	4,	0,	32768,     mux_clk_32k,			PERIPH_NO_RESET),
+	PERIPH_CLK("timer",	"timer",		NULL,	5,	0,	26000000,  mux_clk_m,			0),
+	PERIPH_CLK("i2s1",	"i2s.0",		NULL,	11,	0x100,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("i2s2",	"i2s.1",		NULL,	18,	0x104,	26000000,  mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
 	/* FIXME: spdif has 2 clocks but 1 enable */
-	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	mux_plla_audio_pllp_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	mux_pllp_pllc_pllm,		MUX | DIV_U71),
-	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
-	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("ide",	"ide",			NULL,	25,	0x144,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("ndflash",	"tegra_nand",		NULL,	13,	0x160,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("spdif_out",	"spdif_out",		NULL,	10,	0x108,	100000000, mux_pllaout0_audio2x_pllp_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("spdif_in",	"spdif_in",		NULL,	10,	0x10c,	100000000, mux_pllp_pllc_pllm,		MUX | DIV_U71),
+	PERIPH_CLK("pwm",	"pwm",			NULL,	17,	0x110,	432000000, mux_pllp_pllc_audio_clkm_clk32,	MUX | DIV_U71),
+	PERIPH_CLK("spi",	"spi",			NULL,	43,	0x114,	40000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("xio",	"xio",			NULL,	45,	0x120,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("twc",	"twc",			NULL,	16,	0x12c,	150000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sbc1",	"spi_tegra.0",		NULL,	41,	0x134,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sbc2",	"spi_tegra.1",		NULL,	44,	0x118,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sbc3",	"spi_tegra.2",		NULL,	46,	0x11c,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sbc4",	"spi_tegra.3",		NULL,	68,	0x1b4,	160000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("ide",	"ide",			NULL,	25,	0x144,	100000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("ndflash",	"tegra_nand",		NULL,	13,	0x160,	164000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
 	/* FIXME: vfir shares an enable with uartb */
-	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x160,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("vde",	"vde",			NULL,	61,	0x1c8,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("vfir",	"vfir",			NULL,	7,	0x168,	72000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("sdmmc1",	"sdhci-tegra.0",	NULL,	14,	0x150,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc2",	"sdhci-tegra.1",	NULL,	9,	0x154,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc3",	"sdhci-tegra.2",	NULL,	69,	0x1bc,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("sdmmc4",	"sdhci-tegra.3",	NULL,	15,	0x160,	52000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("vde",	"vde",			NULL,	61,	0x1c8,	250000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("csite",	"csite",		NULL,	73,	0x1d4,	144000000, mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* max rate ??? */
 	/* FIXME: what is la? */
-	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("owr",	"owr",			NULL,	71,	0x1cc,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("dvc",	"tegra-i2c.3",		NULL,	47,	0x128,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("i2c1_i2c",	"tegra-i2c.0",		"i2c",	0,	0,	mux_pllp_out3,			0),
-	PERIPH_CLK("i2c2_i2c",	"tegra-i2c.1",		"i2c",	0,	0,	mux_pllp_out3,			0),
-	PERIPH_CLK("i2c3_i2c",	"tegra-i2c.2",		"i2c",	0,	0,	mux_pllp_out3,			0),
-	PERIPH_CLK("dvc_i2c",	"tegra-i2c.3",		"i2c",	0,	0,	mux_pllp_out3,			0),
-	PERIPH_CLK("uarta",	"uart.0",		NULL,	6,	0x178,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("uartb",	"uart.1",		NULL,	7,	0x17c,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("uartc",	"uart.2",		NULL,	55,	0x1a0,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("uartd",	"uart.3",		NULL,	65,	0x1c0,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("uarte",	"uart.4",		NULL,	66,	0x1c4,	mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET),
-	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
+	PERIPH_CLK("la",	"la",			NULL,	76,	0x1f8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("owr",	"tegra_w1",		NULL,	71,	0x1cc,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71),
+	PERIPH_CLK("nor",	"nor",			NULL,	42,	0x1d0,	92000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("mipi",	"mipi",			NULL,	50,	0x174,	60000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U71), /* scales with voltage */
+	PERIPH_CLK("i2c1",	"tegra-i2c.0",		NULL,	12,	0x124,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
+	PERIPH_CLK("i2c2",	"tegra-i2c.1",		NULL,	54,	0x198,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
+	PERIPH_CLK("i2c3",	"tegra-i2c.2",		NULL,	67,	0x1b8,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
+	PERIPH_CLK("dvc",	"tegra-i2c.3",		NULL,	47,	0x128,	26000000,  mux_pllp_pllc_pllm_clkm,	MUX | DIV_U16),
+	PERIPH_CLK("i2c1_i2c",	"tegra-i2c.0",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
+	PERIPH_CLK("i2c2_i2c",	"tegra-i2c.1",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
+	PERIPH_CLK("i2c3_i2c",	"tegra-i2c.2",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
+	PERIPH_CLK("dvc_i2c",	"tegra-i2c.3",		"i2c",	0,	0,	72000000,  mux_pllp_out3,			0),
+	PERIPH_CLK("uarta",	"uart.0",		NULL,	6,	0x178,	216000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartb",	"uart.1",		NULL,	7,	0x17c,	216000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartc",	"uart.2",		NULL,	55,	0x1a0,	216000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uartd",	"uart.3",		NULL,	65,	0x1c0,	216000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("uarte",	"uart.4",		NULL,	66,	0x1c4,	216000000, mux_pllp_pllc_pllm_clkm,	MUX),
+	PERIPH_CLK("3d",	"3d",			NULL,	24,	0x158,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
+	PERIPH_CLK("2d",	"2d",			NULL,	21,	0x15c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
 	/* FIXME: vi and vi_sensor share an enable */
-	PERIPH_CLK("vi",	"vi",			NULL,	20,	0x148,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
-	PERIPH_CLK("vi_sensor",	"vi_sensor",		NULL,	20,	0x1a8,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
-	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
-	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
-	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	mux_pllm_pllc_pllp_plla,	MUX | DIV_U71),
+	PERIPH_CLK("vi",	"vi",			NULL,	20,	0x148,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("vi_sensor",	"vi_sensor",		NULL,	20,	0x1a8,	150000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
+	PERIPH_CLK("epp",	"epp",			NULL,	19,	0x16c,	300000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("mpe",	"mpe",			NULL,	60,	0x170,	250000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("host1x",	"host1x",		NULL,	28,	0x180,	166000000, mux_pllm_pllc_pllp_plla,	MUX | DIV_U71), /* scales with voltage and process_id */
 	/* FIXME: cve and tvo share an enable	*/
-	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("disp1",	"tegrafb.0",		NULL,	27,	0x138,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("disp2",	"tegrafb.1",		NULL,	26,	0x13c,	mux_pllp_plld_pllc_clkm,	MUX | DIV_U71),
-	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	mux_clk_m,			0),
-	PERIPH_CLK("usb2",	"usb.1",		NULL,	58,	0,	mux_clk_m,			0),
-	PERIPH_CLK("usb3",	"usb.2",		NULL,	59,	0,	mux_clk_m,			0),
-	PERIPH_CLK("emc",	"emc",			NULL,	57,	0x19c,	mux_pllm_pllc_pllp_clkm,	MUX | DIV_U71 | PERIPH_EMC_ENB),
-	PERIPH_CLK("dsi",	"dsi",			NULL,	48,	0,	mux_plld,			0),
+	PERIPH_CLK("cve",	"cve",			NULL,	49,	0x140,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("tvo",	"tvo",			NULL,	49,	0x188,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("hdmi",	"hdmi",			NULL,	51,	0x18c,	148500000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("tvdac",	"tvdac",		NULL,	53,	0x194,	250000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* requires min voltage */
+	PERIPH_CLK("disp1",	"tegrafb.0",		NULL,	27,	0x138,	190000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("disp2",	"tegrafb.1",		NULL,	26,	0x13c,	190000000, mux_pllp_plld_pllc_clkm,	MUX | DIV_U71), /* scales with voltage and process_id */
+	PERIPH_CLK("usbd",	"fsl-tegra-udc",	NULL,	22,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("usb2",	"tegra-ehci.1",		NULL,	58,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("usb3",	"tegra-ehci.2",		NULL,	59,	0,	480000000, mux_clk_m,			0), /* requires min voltage */
+	PERIPH_CLK("emc",	"emc",			NULL,	57,	0x19c,	800000000, mux_pllm_pllc_pllp_clkm,	MUX | DIV_U71 | PERIPH_EMC_ENB),
+	PERIPH_CLK("dsi",	"dsi",			NULL,	48,	0,	500000000, mux_plld,			0), /* scales with voltage */
+	PERIPH_CLK("csi",	"csi",			NULL,	52,	0,	72000000,  mux_pllp_out3,		0),
+	PERIPH_CLK("isp",	"isp",			NULL,	23,	0,	150000000, mux_clk_m,			0), /* same frequency as VI */
+	PERIPH_CLK("csus",	"csus",			NULL,	92,	0,	150000000, mux_clk_m,			PERIPH_NO_RESET),
+	PERIPH_CLK("pex",       NULL,			"pex",  70,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
+	PERIPH_CLK("afi",       NULL,			"afi",  72,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
+	PERIPH_CLK("pcie_xclk", NULL,		  "pcie_xclk",  74,     0,	26000000,  mux_clk_m,			PERIPH_MANUAL_RESET),
 };
 
 #define CLK_DUPLICATE(_name, _dev, _con)		\
@@ -1286,6 +1694,9 @@
 	CLK_DUPLICATE("uartc",	"tegra_uart.2",	NULL),
 	CLK_DUPLICATE("uartd",	"tegra_uart.3",	NULL),
 	CLK_DUPLICATE("uarte",	"tegra_uart.4",	NULL),
+	CLK_DUPLICATE("host1x", "tegrafb.0", "host1x"),
+	CLK_DUPLICATE("host1x", "tegrafb.1", "host1x"),
+	CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
 };
 
 #define CLK(dev, con, ck)	\
@@ -1315,11 +1726,13 @@
 	CLK(NULL,	"pll_d_out0",	&tegra_pll_d_out0),
 	CLK(NULL,	"pll_u",	&tegra_pll_u),
 	CLK(NULL,	"pll_x",	&tegra_pll_x),
-	CLK(NULL,	"cpu",		&tegra_clk_cpu),
-	CLK(NULL,	"sys",		&tegra_clk_sys),
+	CLK(NULL,	"pll_e",	&tegra_pll_e),
+	CLK(NULL,	"cclk",		&tegra_clk_cclk),
+	CLK(NULL,	"sclk",		&tegra_clk_sclk),
 	CLK(NULL,	"hclk",		&tegra_clk_hclk),
 	CLK(NULL,	"pclk",		&tegra_clk_pclk),
 	CLK(NULL,	"clk_d",	&tegra_clk_d),
+	CLK(NULL,	"cpu",		&tegra_clk_virtual_cpu),
 };
 
 void __init tegra2_init_clocks(void)
@@ -1356,4 +1769,75 @@
 				cd->name);
 		}
 	}
+
+	init_audio_sync_clock_mux();
 }
+
+#ifdef CONFIG_PM
+static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
+			   PERIPH_CLK_SOURCE_NUM + 3];
+
+void tegra_clk_suspend(void)
+{
+	unsigned long off, i;
+	u32 *ctx = clk_rst_suspend;
+
+	*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+
+	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+			off += 4) {
+		if (off == PERIPH_CLK_SOURCE_EMC)
+			continue;
+		*ctx++ = clk_readl(off);
+	}
+
+	off = RST_DEVICES;
+	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+		*ctx++ = clk_readl(off);
+
+	off = CLK_OUT_ENB;
+	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+		*ctx++ = clk_readl(off);
+
+	*ctx++ = clk_readl(MISC_CLK_ENB);
+	*ctx++ = clk_readl(CLK_MASK_ARM);
+}
+
+void tegra_clk_resume(void)
+{
+	unsigned long off, i;
+	const u32 *ctx = clk_rst_suspend;
+	u32 val;
+
+	val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
+	val |= *ctx++;
+	clk_writel(val, OSC_CTRL);
+
+	/* enable all clocks before configuring clock sources */
+	clk_writel(0xbffffff9ul, CLK_OUT_ENB);
+	clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
+	clk_writel(0x77f01bfful, CLK_OUT_ENB + 8);
+	wmb();
+
+	for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
+			off += 4) {
+		if (off == PERIPH_CLK_SOURCE_EMC)
+			continue;
+		clk_writel(*ctx++, off);
+	}
+	wmb();
+
+	off = RST_DEVICES;
+	for (i = 0; i < RST_DEVICES_NUM; i++, off += 4)
+		clk_writel(*ctx++, off);
+	wmb();
+
+	off = CLK_OUT_ENB;
+	for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4)
+		clk_writel(*ctx++, off);
+	wmb();
+
+	clk_writel(*ctx++, MISC_CLK_ENB);
+	clk_writel(*ctx++, CLK_MASK_ARM);
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_dvfs.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_dvfs.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_dvfs.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_dvfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include "clock.h"
+#include "tegra2_dvfs.h"
+
+static struct dvfs_table virtual_cpu_process_0[] = {
+	{314000000,  750},
+	{456000000,  825},
+	{608000000,  900},
+	{760000000,  975},
+	{817000000,  1000},
+	{912000000,  1050},
+	{1000000000, 1100},
+	{0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_1[] = {
+	{314000000,  750},
+	{456000000,  825},
+	{618000000,  900},
+	{770000000,  975},
+	{827000000,  1000},
+	{922000000,  1050},
+	{1000000000, 1100},
+	{0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_2[] = {
+	{494000000,  750},
+	{675000000,  825},
+	{817000000,  875},
+	{922000000,  925},
+	{1000000000, 975},
+	{0, 0},
+};
+
+static struct dvfs_table virtual_cpu_process_3[] = {
+	{730000000,  750},
+	{760000000,  775},
+	{845000000,  800},
+	{1000000000, 875},
+	{0, 0},
+};
+
+struct dvfs tegra_dvfs_virtual_cpu_dvfs = {
+	.reg_id = "vdd_cpu",
+	.process_id_table = {
+		{
+			.process_id = 0,
+			.table = virtual_cpu_process_0,
+		},
+		{
+			.process_id = 1,
+			.table = virtual_cpu_process_1,
+		},
+		{
+			.process_id = 2,
+			.table = virtual_cpu_process_2,
+		},
+		{
+			.process_id = 3,
+			.table = virtual_cpu_process_3,
+		},
+	},
+	.process_id_table_length = 4,
+	.cpu = 1,
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_dvfs.h linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_dvfs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/tegra2_dvfs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/tegra2_dvfs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-tegra/tegra2_dvfs.h
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ *	Colin Cross <ccross@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-tegra/timer.c linux-libre-2.6.37-gnu/arch/arm/mach-tegra/timer.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-tegra/timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-tegra/timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #include <linux/cnt32_to_63.h>
 
 #include <asm/mach/time.h>
-#include <asm/mach/time.h>
 #include <asm/localtimer.h>
 
 #include <mach/iomap.h>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-u300/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,7 +66,7 @@
  *  AMBA bus
  *  |
  *  +- CPU
- *  +- NANDIF NAND Flash interface
+ *  +- FSMC NANDIF NAND Flash interface
  *  +- SEMI Shared Memory interface
  *  +- ISP Image Signal Processor (U335 only)
  *  +- CDS (U335 only)
@@ -726,7 +726,7 @@
 };
 
 static struct clk nandif_clk = {
-	.name       = "NANDIF",
+	.name       = "FSMC",
 	.parent	    = &amba_clk,
 	.hw_ctrld   = false,
 	.reset	    = true,
@@ -1259,7 +1259,7 @@
 	/* Connected directly to the AMBA bus */
 	DEF_LOOKUP("amba",      &amba_clk),
 	DEF_LOOKUP("cpu",       &cpu_clk),
-	DEF_LOOKUP("fsmc",      &nandif_clk),
+	DEF_LOOKUP("fsmc-nand", &nandif_clk),
 	DEF_LOOKUP("semi",      &semi_clk),
 #ifdef CONFIG_MACH_U300_BS335
 	DEF_LOOKUP("isp",       &isp_clk),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/core.c linux-libre-2.6.37-gnu/arch/arm/mach-u300/core.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,8 @@
 #include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/err.h>
-#include <mach/coh901318.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/fsmc.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -30,6 +31,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
+#include <mach/coh901318.h>
 #include <mach/hardware.h>
 #include <mach/syscon.h>
 #include <mach/dma_channels.h>
@@ -285,6 +287,13 @@
  */
 static struct resource fsmc_resources[] = {
 	{
+		.name  = "nand_data",
+		.start = U300_NAND_CS0_PHYS_BASE,
+		.end   = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name  = "fsmc_regs",
 		.start = U300_NAND_IF_PHYS_BASE,
 		.end   = U300_NAND_IF_PHYS_BASE + SZ_4K - 1,
 		.flags = IORESOURCE_MEM,
@@ -1429,11 +1438,39 @@
 	.resource = rtc_resources,
 };
 
-static struct platform_device fsmc_device = {
-	.name = "nandif",
+static struct mtd_partition u300_partitions[] = {
+	{
+		.name = "bootrecords",
+		.offset = 0,
+		.size = SZ_128K,
+	},
+	{
+		.name = "free",
+		.offset = SZ_128K,
+		.size = 8064 * SZ_1K,
+	},
+	{
+		.name = "platform",
+		.offset = 8192 * SZ_1K,
+		.size = 253952 * SZ_1K,
+	},
+};
+
+static struct fsmc_nand_platform_data nand_platform_data = {
+	.partitions = u300_partitions,
+	.nr_partitions = ARRAY_SIZE(u300_partitions),
+	.options = NAND_SKIP_BBTSCAN,
+	.width = FSMC_NAND_BW8,
+};
+
+static struct platform_device nand_device = {
+	.name = "fsmc-nand",
 	.id = -1,
-	.num_resources = ARRAY_SIZE(fsmc_resources),
 	.resource = fsmc_resources,
+	.num_resources = ARRAY_SIZE(fsmc_resources),
+	.dev = {
+		.platform_data = &nand_platform_data,
+	},
 };
 
 static struct platform_device ave_device = {
@@ -1465,7 +1502,7 @@
 	&keypad_device,
 	&rtc_device,
 	&gpio_device,
-	&fsmc_device,
+	&nand_device,
 	&wdog_device,
 	&ave_device
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/dummyspichip.c linux-libre-2.6.37-gnu/arch/arm/mach-u300/dummyspichip.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/dummyspichip.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/dummyspichip.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,6 @@
 	 * struct, this is just used here to alter the behaviour of the chip
 	 * in order to perform tests.
 	 */
-	struct pl022_config_chip *chip_info = spi->controller_data;
 	int status;
 	u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD,
 			0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05,
@@ -72,7 +71,7 @@
 	 * Force chip to 8 bit mode
 	 * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
 	 */
-	chip_info->data_size = SSP_DATA_BITS_8;
+	spi->bits_per_word = 8;
 	/* You should NOT DO THIS EITHER */
 	spi->master->setup(spi);
 
@@ -159,7 +158,7 @@
 	 * Force chip to 16 bit mode
 	 * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
 	 */
-	chip_info->data_size = SSP_DATA_BITS_16;
+	spi->bits_per_word = 16;
 	/* You should NOT DO THIS EITHER */
 	spi->master->setup(spi);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-u300/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,13 +10,12 @@
  */
 #include <mach/hardware.h>
 
-	.macro	addruart, rx, tmp
+	.macro	addruart, rp, rv
 	/* If we move the address using MMU, use this. */
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1			@ MMU enabled?
-	ldreq	\rx,	  = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
-	ldrne	\rx,	  = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
-	orr	\rx, \rx, #0x00003000
+	ldr	\rp,	  = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
+	ldr	\rv,	  = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
+	orr	\rp, \rp, #0x00003000
+	orr	\rv, \rv, #0x00003000
 	.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/include/mach/u300-regs.h linux-libre-2.6.37-gnu/arch/arm/mach-u300/include/mach/u300-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/include/mach/u300-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/include/mach/u300-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,11 +20,9 @@
 
 /* NAND Flash CS0 */
 #define U300_NAND_CS0_PHYS_BASE		0x80000000
-#define U300_NAND_CS0_VIRT_BASE		0xff040000
 
 /* NFIF */
 #define U300_NAND_IF_PHYS_BASE		0x9f800000
-#define U300_NAND_IF_VIRT_BASE		0xff030000
 
 /* AHB Peripherals */
 #define U300_AHB_PER_PHYS_BASE		0xa0000000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/spi.c linux-libre-2.6.37-gnu/arch/arm/mach-u300/spi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,6 @@
 }
 
 struct pl022_config_chip dummy_chip_info = {
-	/* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */
-	.lbm = LOOPBACK_ENABLED,
 	/*
 	 * available POLLING_TRANSFER and INTERRUPT_TRANSFER,
 	 * DMA_TRANSFER does not work
@@ -42,14 +40,8 @@
 	.hierarchy = SSP_MASTER,
 	/* 0 = drive TX even as slave, 1 = do not drive TX as slave */
 	.slave_tx_disable = 0,
-	/* LSB first */
-	.endian_tx = SSP_TX_LSB,
-	.endian_rx = SSP_RX_LSB,
-	.data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */
 	.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
 	.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
-	.clk_phase = SSP_CLK_SECOND_EDGE,
-	.clk_pol = SSP_CLK_POL_IDLE_LOW,
 	.ctrl_len = SSP_BITS_12,
 	.wait_state = SSP_MWIRE_WAIT_ZERO,
 	.duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@@ -75,7 +67,7 @@
 		.bus_num        = 0, /* Only one bus on this chip */
 		.chip_select    = 0,
 		/* Means SPI_CS_HIGH, change if e.g low CS */
-		.mode           = 0,
+		.mode           = SPI_MODE_1 | SPI_LOOP,
 	},
 #endif
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-u300/u300.c linux-libre-2.6.37-gnu/arch/arm/mach-u300/u300.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-u300/u300.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-u300/u300.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,8 +61,6 @@
 
 MACHINE_START(U300, MACH_U300_STRING)
 	/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
-	.phys_io	= U300_AHB_PER_PHYS_BASE,
-	.io_pg_offst	= ((U300_AHB_PER_VIRT_BASE) >> 18) & 0xfffc,
 	.boot_params	= BOOT_PARAMS_OFFSET,
 	.map_io		= u300_map_io,
 	.reserve	= u300_reserve,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,18 +18,22 @@
 #include <linux/amba/pl022.h>
 #include <linux/spi/spi.h>
 #include <linux/mfd/ab8500.h>
+#include <linux/input/matrix_keypad.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
 #include <plat/pincfg.h>
 #include <plat/i2c.h>
+#include <plat/ske.h>
 
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
+#include <mach/irqs.h>
 
 #include "pins-db8500.h"
+#include "board-mop500.h"
 
 static pin_cfg_t mop500_pins[] = {
 	/* SSP0 */
@@ -47,6 +51,24 @@
 	GPIO11_I2C2_SCL,
 	GPIO229_I2C3_SDA,
 	GPIO230_I2C3_SCL,
+
+	/* SKE keypad */
+	GPIO153_KP_I7,
+	GPIO154_KP_I6,
+	GPIO155_KP_I5,
+	GPIO156_KP_I4,
+	GPIO157_KP_O7,
+	GPIO158_KP_O6,
+	GPIO159_KP_O5,
+	GPIO160_KP_O4,
+	GPIO161_KP_I3,
+	GPIO162_KP_I2,
+	GPIO163_KP_I1,
+	GPIO164_KP_I0,
+	GPIO165_KP_O3,
+	GPIO166_KP_O2,
+	GPIO167_KP_O1,
+	GPIO168_KP_O0,
 };
 
 static void ab4500_spi_cs_control(u32 command)
@@ -55,19 +77,13 @@
 }
 
 struct pl022_config_chip ab4500_chip_info = {
-	.lbm = LOOPBACK_DISABLED,
 	.com_mode = INTERRUPT_TRANSFER,
 	.iface = SSP_INTERFACE_MOTOROLA_SPI,
 	/* we can act as master only */
 	.hierarchy = SSP_MASTER,
 	.slave_tx_disable = 0,
-	.endian_rx = SSP_RX_MSB,
-	.endian_tx = SSP_TX_MSB,
-	.data_size = SSP_DATA_BITS_24,
 	.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
 	.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
-	.clk_phase = SSP_CLK_SECOND_EDGE,
-	.clk_pol = SSP_CLK_POL_IDLE_HIGH,
 	.cs_control = ab4500_spi_cs_control,
 };
 
@@ -75,15 +91,33 @@
 	.irq_base	= MOP500_AB8500_IRQ_BASE,
 };
 
-static struct spi_board_info u8500_spi_devices[] = {
+static struct resource ab8500_resources[] = {
+	[0] = {
+		.start = IRQ_AB8500,
+		.end = IRQ_AB8500,
+		.flags = IORESOURCE_IRQ
+	}
+};
+
+struct platform_device ab8500_device = {
+	.name = "ab8500-i2c",
+	.id = 0,
+	.dev = {
+		.platform_data = &ab8500_platdata,
+	},
+	.num_resources = 1,
+	.resource = ab8500_resources,
+};
+
+static struct spi_board_info ab8500_spi_devices[] = {
 	{
-		.modalias = "ab8500",
+		.modalias = "ab8500-spi",
 		.controller_data = &ab4500_chip_info,
 		.platform_data = &ab8500_platdata,
 		.max_speed_hz = 12000000,
 		.bus_num = 0,
 		.chip_select = 0,
-		.mode = SPI_MODE_0,
+		.mode = SPI_MODE_3,
 		.irq = IRQ_DB8500_AB8500,
 	},
 };
@@ -134,12 +168,120 @@
 	&u8500_ssp0_device,
 };
 
+static const unsigned int ux500_keymap[] = {
+	KEY(2, 5, KEY_END),
+	KEY(4, 1, KEY_POWER),
+	KEY(3, 5, KEY_VOLUMEDOWN),
+	KEY(1, 3, KEY_3),
+	KEY(5, 2, KEY_RIGHT),
+	KEY(5, 0, KEY_9),
+
+	KEY(0, 5, KEY_MENU),
+	KEY(7, 6, KEY_ENTER),
+	KEY(4, 5, KEY_0),
+	KEY(6, 7, KEY_2),
+	KEY(3, 4, KEY_UP),
+	KEY(3, 3, KEY_DOWN),
+
+	KEY(6, 4, KEY_SEND),
+	KEY(6, 2, KEY_BACK),
+	KEY(4, 2, KEY_VOLUMEUP),
+	KEY(5, 5, KEY_1),
+	KEY(4, 3, KEY_LEFT),
+	KEY(3, 2, KEY_7),
+};
+
+static const struct matrix_keymap_data ux500_keymap_data = {
+	.keymap         = ux500_keymap,
+	.keymap_size    = ARRAY_SIZE(ux500_keymap),
+};
+
+/*
+ * Nomadik SKE keypad
+ */
+#define ROW_PIN_I0      164
+#define ROW_PIN_I1      163
+#define ROW_PIN_I2      162
+#define ROW_PIN_I3      161
+#define ROW_PIN_I4      156
+#define ROW_PIN_I5      155
+#define ROW_PIN_I6      154
+#define ROW_PIN_I7      153
+#define COL_PIN_O0      168
+#define COL_PIN_O1      167
+#define COL_PIN_O2      166
+#define COL_PIN_O3      165
+#define COL_PIN_O4      160
+#define COL_PIN_O5      159
+#define COL_PIN_O6      158
+#define COL_PIN_O7      157
+
+#define SKE_KPD_MAX_ROWS        8
+#define SKE_KPD_MAX_COLS        8
+
+static int ske_kp_rows[] = {
+	ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
+	ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
+};
+
+/*
+ * ske_set_gpio_row: request and set gpio rows
+ */
+static int ske_set_gpio_row(int gpio)
+{
+	int ret;
+
+	ret = gpio_request(gpio, "ske-kp");
+	if (ret < 0) {
+		pr_err("ske_set_gpio_row: gpio request failed\n");
+		return ret;
+	}
+
+	ret = gpio_direction_output(gpio, 1);
+	if (ret < 0) {
+		pr_err("ske_set_gpio_row: gpio direction failed\n");
+		gpio_free(gpio);
+	}
+
+	return ret;
+}
+
+/*
+ * ske_kp_init - enable the gpio configuration
+ */
+static int ske_kp_init(void)
+{
+	int ret, i;
+
+	for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
+		ret = ske_set_gpio_row(ske_kp_rows[i]);
+		if (ret < 0) {
+			pr_err("ske_kp_init: failed init\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static struct ske_keypad_platform_data ske_keypad_board = {
+	.init           = ske_kp_init,
+	.keymap_data    = &ux500_keymap_data,
+	.no_autorepeat  = true,
+	.krow           = SKE_KPD_MAX_ROWS,     /* 8x8 matrix */
+	.kcol           = SKE_KPD_MAX_COLS,
+	.debounce_ms    = 40,                   /* in millsecs */
+};
+
+
+
 /* add any platform devices here - TODO */
 static struct platform_device *platform_devs[] __initdata = {
 	&u8500_i2c0_device,
 	&ux500_i2c1_device,
 	&ux500_i2c2_device,
 	&ux500_i2c3_device,
+	&ux500_ske_keypad_device,
 };
 
 static void __init u8500_init_machine(void)
@@ -154,6 +296,7 @@
 	ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
 	ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
 	ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
+	ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
 
 	u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
 
@@ -163,14 +306,18 @@
 
 	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-	spi_register_board_info(u8500_spi_devices,
-			ARRAY_SIZE(u8500_spi_devices));
+	mop500_sdi_init();
+
+	/* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */
+	if (cpu_is_u8500ed() || cpu_is_u8500v10())
+		spi_register_board_info(ab8500_spi_devices,
+			ARRAY_SIZE(ab8500_spi_devices));
+	else /* If HW is v.1.1 or later use I2C to access AB8500 */
+		platform_device_register(&ab8500_device);
 }
 
 MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
 	/* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */
-	.phys_io	= U8500_UART2_BASE,
-	.io_pg_offst	= (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x100,
 	.map_io		= u8500_map_io,
 	.init_irq	= ux500_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __BOARD_MOP500_H
+#define __BOARD_MOP500_H
+
+extern void mop500_sdi_init(void);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500-regulators.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500-regulators.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500-regulators.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500-regulators.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * MOP500 board specific initialization for regulators
+ */
+#include <linux/kernel.h>
+#include <linux/regulator/machine.h>
+
+/* supplies to the display/camera */
+static struct regulator_init_data ab8500_vaux1_regulator = {
+	.constraints = {
+		.name = "V-DISPLAY",
+		.min_uV = 2500000,
+		.max_uV = 2900000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+					REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supplies to the on-board eMMC */
+static struct regulator_init_data ab8500_vaux2_regulator = {
+	.constraints = {
+		.name = "V-eMMC1",
+		.min_uV = 1100000,
+		.max_uV = 3300000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+					REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for VAUX3, supplies to SDcard slots */
+static struct regulator_init_data ab8500_vaux3_regulator = {
+	.constraints = {
+		.name = "V-MMC-SD",
+		.min_uV = 1100000,
+		.max_uV = 3300000,
+		.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+					REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for tvout, gpadc, TVOUT LDO */
+static struct regulator_init_data ab8500_vtvout_init = {
+	.constraints = {
+		.name = "V-TVOUT",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for ab8500-vaudio, VAUDIO LDO */
+static struct regulator_init_data ab8500_vaudio_init = {
+	.constraints = {
+		.name = "V-AUD",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for v-anamic1 VAMic1-LDO */
+static struct regulator_init_data ab8500_vamic1_init = {
+	.constraints = {
+		.name = "V-AMIC1",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+static struct regulator_init_data ab8500_vamic2_init = {
+	.constraints = {
+		.name = "V-AMIC2",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for v-dmic, VDMIC LDO */
+static struct regulator_init_data ab8500_vdmic_init = {
+	.constraints = {
+		.name = "V-DMIC",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for v-intcore12, VINTCORE12 LDO */
+static struct regulator_init_data ab8500_vintcore_init = {
+	.constraints = {
+		.name = "V-INTCORE",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
+/* supply for U8500 CSI/DSI, VANA LDO */
+static struct regulator_init_data ab8500_vana_init = {
+	.constraints = {
+		.name = "V-CSI/DSI",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+	},
+};
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500-sdi.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500-sdi.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-mop500-sdi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-mop500-sdi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Hanumath Prasad <hanumath.prasad@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+
+#include <plat/pincfg.h>
+#include <mach/devices.h>
+#include <mach/hardware.h>
+
+#include "pins-db8500.h"
+#include "board-mop500.h"
+
+static pin_cfg_t mop500_sdi_pins[] = {
+	/* SDI4 (on-board eMMC) */
+	GPIO197_MC4_DAT3,
+	GPIO198_MC4_DAT2,
+	GPIO199_MC4_DAT1,
+	GPIO200_MC4_DAT0,
+	GPIO201_MC4_CMD,
+	GPIO202_MC4_FBCLK,
+	GPIO203_MC4_CLK,
+	GPIO204_MC4_DAT7,
+	GPIO205_MC4_DAT6,
+	GPIO206_MC4_DAT5,
+	GPIO207_MC4_DAT4,
+};
+
+static pin_cfg_t mop500_sdi2_pins[] = {
+	/* SDI2 (POP eMMC) */
+	GPIO128_MC2_CLK,
+	GPIO129_MC2_CMD,
+	GPIO130_MC2_FBCLK,
+	GPIO131_MC2_DAT0,
+	GPIO132_MC2_DAT1,
+	GPIO133_MC2_DAT2,
+	GPIO134_MC2_DAT3,
+	GPIO135_MC2_DAT4,
+	GPIO136_MC2_DAT5,
+	GPIO137_MC2_DAT6,
+	GPIO138_MC2_DAT7,
+};
+
+/*
+ * SDI 2 (POP eMMC, not on DB8500ed)
+ */
+
+static struct mmci_platform_data mop500_sdi2_data = {
+	.ocr_mask	= MMC_VDD_165_195,
+	.f_max		= 100000000,
+	.capabilities	= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+	.gpio_cd	= -1,
+	.gpio_wp	= -1,
+};
+
+/*
+ * SDI 4 (on-board eMMC)
+ */
+
+static struct mmci_platform_data mop500_sdi4_data = {
+	.ocr_mask	= MMC_VDD_29_30,
+	.f_max		= 100000000,
+	.capabilities	= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA |
+			  MMC_CAP_MMC_HIGHSPEED,
+	.gpio_cd	= -1,
+	.gpio_wp	= -1,
+};
+
+void mop500_sdi_init(void)
+{
+	nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins));
+
+	u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data;
+	u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data;
+
+	if (!cpu_is_u8500ed()) {
+		nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins));
+		amba_device_register(&u8500_sdi2_device, &iomem_resource);
+	}
+
+	/* On-board eMMC */
+	amba_device_register(&u8500_sdi4_device, &iomem_resource);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-u5500.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-u5500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/board-u5500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/board-u5500.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,8 +31,6 @@
 }
 
 MACHINE_START(U8500, "ST-Ericsson U5500 Platform")
-	.phys_io	= UX500_UART0_BASE,
-	.io_pg_offst	= (IO_ADDRESS(UX500_UART0_BASE) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= u5500_map_io,
 	.init_irq	= ux500_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/clock.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -477,6 +477,7 @@
 	CLK(sdi5,	"sdi5",		NULL),
 	CLK(uart2,	"uart2",	NULL),
 	CLK(ske,	"ske",		NULL),
+	CLK(ske,	"nmk-ske-keypad",	NULL),
 	CLK(sdi2,	"sdi2",		NULL),
 	CLK(i2c0,	"nmk-i2c.0",	NULL),
 	CLK(fsmc,	"fsmc",		NULL),
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 #include <linux/io.h>
 #include <linux/clk.h>
 
+#include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
@@ -71,6 +72,46 @@
 }
 
 #ifdef CONFIG_CACHE_L2X0
+static inline void ux500_cache_wait(void __iomem *reg, unsigned long mask)
+{
+	/* wait for the operation to complete */
+	while (readl_relaxed(reg) & mask)
+		;
+}
+
+static inline void ux500_cache_sync(void)
+{
+	void __iomem *base = __io_address(UX500_L2CC_BASE);
+	writel_relaxed(0, base + L2X0_CACHE_SYNC);
+	ux500_cache_wait(base + L2X0_CACHE_SYNC, 1);
+}
+
+/*
+ * The L2 cache cannot be turned off in the non-secure world.
+ * Dummy until a secure service is in place.
+ */
+static void ux500_l2x0_disable(void)
+{
+}
+
+/*
+ * This is only called when doing a kexec, just after turning off the L2
+ * and L1 cache, and it is surrounded by a spinlock in the generic version.
+ * However, we're not really turning off the L2 cache right now and the
+ * PL310 does not support exclusive accesses (used to implement the spinlock).
+ * So, the invalidation needs to be done without the spinlock.
+ */
+static void ux500_l2x0_inv_all(void)
+{
+	void __iomem *l2x0_base = __io_address(UX500_L2CC_BASE);
+	uint32_t l2x0_way_mask = (1<<16) - 1;	/* Bitmask of active ways */
+
+	/* invalidate all ways */
+	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
+	ux500_cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
+	ux500_cache_sync();
+}
+
 static int ux500_l2x0_init(void)
 {
 	void __iomem *l2x0_base;
@@ -80,6 +121,10 @@
 	/* 64KB way size, 8 way associativity, force WA */
 	l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
 
+	/* Override invalidate function */
+	outer_cache.disable = ux500_l2x0_disable;
+	outer_cache.inv_all = ux500_l2x0_inv_all;
+
 	return 0;
 }
 early_initcall(ux500_l2x0_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu-db5500.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu-db5500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu-db5500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu-db5500.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <mach/hardware.h>
 #include <mach/devices.h>
 #include <mach/setup.h>
+#include <mach/irqs.h>
 
 static struct map_desc u5500_io_desc[] __initdata = {
 	__IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
@@ -24,6 +25,90 @@
 	__IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
 };
 
+static struct resource mbox0_resources[] = {
+	{
+		.name = "mbox_peer",
+		.start = U5500_MBOX0_PEER_START,
+		.end = U5500_MBOX0_PEER_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_local",
+		.start = U5500_MBOX0_LOCAL_START,
+		.end = U5500_MBOX0_LOCAL_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_irq",
+		.start = MBOX_PAIR0_VIRT_IRQ,
+		.end = MBOX_PAIR0_VIRT_IRQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct resource mbox1_resources[] = {
+	{
+		.name = "mbox_peer",
+		.start = U5500_MBOX1_PEER_START,
+		.end = U5500_MBOX1_PEER_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_local",
+		.start = U5500_MBOX1_LOCAL_START,
+		.end = U5500_MBOX1_LOCAL_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_irq",
+		.start = MBOX_PAIR1_VIRT_IRQ,
+		.end = MBOX_PAIR1_VIRT_IRQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct resource mbox2_resources[] = {
+	{
+		.name = "mbox_peer",
+		.start = U5500_MBOX2_PEER_START,
+		.end = U5500_MBOX2_PEER_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_local",
+		.start = U5500_MBOX2_LOCAL_START,
+		.end = U5500_MBOX2_LOCAL_END,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "mbox_irq",
+		.start = MBOX_PAIR2_VIRT_IRQ,
+		.end = MBOX_PAIR2_VIRT_IRQ,
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device mbox0_device = {
+	.id = 0,
+	.name = "mbox",
+	.resource = mbox0_resources,
+	.num_resources = ARRAY_SIZE(mbox0_resources),
+};
+
+static struct platform_device mbox1_device = {
+	.id = 1,
+	.name = "mbox",
+	.resource = mbox1_resources,
+	.num_resources = ARRAY_SIZE(mbox1_resources),
+};
+
+static struct platform_device mbox2_device = {
+	.id = 2,
+	.name = "mbox",
+	.resource = mbox2_resources,
+	.num_resources = ARRAY_SIZE(mbox2_resources),
+};
+
 static struct platform_device *u5500_platform_devs[] __initdata = {
 	&u5500_gpio_devs[0],
 	&u5500_gpio_devs[1],
@@ -33,6 +118,9 @@
 	&u5500_gpio_devs[5],
 	&u5500_gpio_devs[6],
 	&u5500_gpio_devs[7],
+	&mbox0_device,
+	&mbox1_device,
+	&mbox2_device,
 };
 
 void __init u5500_map_io(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu-db8500.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu-db8500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/cpu-db8500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/cpu-db8500.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,10 +38,12 @@
 /* minimum static i/o mapping required to boot U8500 platforms */
 static struct map_desc u8500_io_desc[] __initdata = {
 	__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
+	__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
 	__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+	__MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
 };
 
 static struct map_desc u8500ed_io_desc[] __initdata = {
@@ -53,6 +55,69 @@
 	__IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
 };
 
+/*
+ * Functions to differentiate between later ASICs
+ * We look into the end of the ROM to locate the hardcoded ASIC ID.
+ * This is only needed to differentiate between minor revisions and
+ * process variants of an ASIC, the major revisions are encoded in
+ * the cpuid.
+ */
+#define U8500_ASIC_ID_LOC_ED_V1	(U8500_BOOT_ROM_BASE + 0x1FFF4)
+#define U8500_ASIC_ID_LOC_V2	(U8500_BOOT_ROM_BASE + 0x1DBF4)
+#define U8500_ASIC_REV_ED	0x01
+#define U8500_ASIC_REV_V10	0xA0
+#define U8500_ASIC_REV_V11	0xA1
+#define U8500_ASIC_REV_V20	0xB0
+
+/**
+ * struct db8500_asic_id - fields of the ASIC ID
+ * @process: the manufacturing process, 0x40 is 40 nm
+ *  0x00 is "standard"
+ * @partnumber: hithereto 0x8500 for DB8500
+ * @revision: version code in the series
+ * This field definion is not formally defined but makes
+ * sense.
+ */
+struct db8500_asic_id {
+	u8 process;
+	u16 partnumber;
+	u8 revision;
+};
+
+/* This isn't going to change at runtime */
+static struct db8500_asic_id db8500_id;
+
+static void __init get_db8500_asic_id(void)
+{
+	u32 asicid;
+
+	if (cpu_is_u8500v1() || cpu_is_u8500ed())
+		asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1));
+	else if (cpu_is_u8500v2())
+		asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2));
+	else
+		BUG();
+
+	db8500_id.process = (asicid >> 24);
+	db8500_id.partnumber = (asicid >> 16) & 0xFFFFU;
+	db8500_id.revision = asicid & 0xFFU;
+}
+
+bool cpu_is_u8500v10(void)
+{
+	return (db8500_id.revision == U8500_ASIC_REV_V10);
+}
+
+bool cpu_is_u8500v11(void)
+{
+	return (db8500_id.revision == U8500_ASIC_REV_V11);
+}
+
+bool cpu_is_u8500v20(void)
+{
+	return (db8500_id.revision == U8500_ASIC_REV_V20);
+}
+
 void __init u8500_map_io(void)
 {
 	ux500_map_io();
@@ -63,6 +128,9 @@
 		iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc));
 	else
 		iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc));
+
+	/* Read out the ASIC ID as early as we can */
+	get_db8500_asic_id();
 }
 
 /*
@@ -70,6 +138,20 @@
  */
 void __init u8500_init_devices(void)
 {
+	/* Display some ASIC boilerplate */
+	pr_info("DB8500: process: %02x, revision ID: 0x%02x\n",
+		db8500_id.process, db8500_id.revision);
+	if (cpu_is_u8500ed())
+		pr_info("DB8500: Early Drop (ED)\n");
+	else if (cpu_is_u8500v10())
+		pr_info("DB8500: version 1.0\n");
+	else if (cpu_is_u8500v11())
+		pr_info("DB8500: version 1.1\n");
+	else if (cpu_is_u8500v20())
+		pr_info("DB8500: version 2.0\n");
+	else
+		pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
+
 	ux500_init_devices();
 
 	if (cpu_is_u8500ed())
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/devices-db8500.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/devices-db8500.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/devices-db8500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/devices-db8500.c	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,82 @@
 	.num_resources	= ARRAY_SIZE(u8500_i2c4_resources),
 };
 
+/*
+ * SD/MMC
+ */
+
+struct amba_device u8500_sdi0_device = {
+	.dev		= {
+		.init_name = "sdi0",
+	},
+	.res		= {
+		.start	= U8500_SDI0_BASE,
+		.end	= U8500_SDI0_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC0, NO_IRQ},
+};
+
+struct amba_device u8500_sdi1_device = {
+	.dev		= {
+		.init_name = "sdi1",
+	},
+	.res		= {
+		.start	= U8500_SDI1_BASE,
+		.end	= U8500_SDI1_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC1, NO_IRQ},
+};
+
+struct amba_device u8500_sdi2_device = {
+	.dev		= {
+		.init_name = "sdi2",
+	},
+	.res		= {
+		.start	= U8500_SDI2_BASE,
+		.end	= U8500_SDI2_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC2, NO_IRQ},
+};
+
+struct amba_device u8500_sdi3_device = {
+	.dev		= {
+		.init_name = "sdi3",
+	},
+	.res		= {
+		.start	= U8500_SDI3_BASE,
+		.end	= U8500_SDI3_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC3, NO_IRQ},
+};
+
+struct amba_device u8500_sdi4_device = {
+	.dev		= {
+		.init_name = "sdi4",
+	},
+	.res		= {
+		.start	= U8500_SDI4_BASE,
+		.end	= U8500_SDI4_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC4, NO_IRQ},
+};
+
+struct amba_device u8500_sdi5_device = {
+	.dev		= {
+		.init_name = "sdi5",
+	},
+	.res		= {
+		.start	= U8500_SDI5_BASE,
+		.end	= U8500_SDI5_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	.irq		= {IRQ_DB8500_SDMMC5, NO_IRQ},
+};
+
 static struct resource dma40_resources[] = {
 	[0] = {
 		.start = U8500_DMA_BASE,
@@ -132,35 +208,25 @@
 
 /* Default configuration for physcial memcpy */
 struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
-	.channel_type = (STEDMA40_CHANNEL_IN_PHY_MODE |
-			 STEDMA40_LOW_PRIORITY_CHANNEL |
-			 STEDMA40_PCHAN_BASIC_MODE),
+	.mode = STEDMA40_MODE_PHYSICAL,
 	.dir = STEDMA40_MEM_TO_MEM,
 
-	.src_info.endianess = STEDMA40_LITTLE_ENDIAN,
 	.src_info.data_width = STEDMA40_BYTE_WIDTH,
 	.src_info.psize = STEDMA40_PSIZE_PHY_1,
 	.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
 
-	.dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
 	.dst_info.data_width = STEDMA40_BYTE_WIDTH,
 	.dst_info.psize = STEDMA40_PSIZE_PHY_1,
 	.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
 };
 /* Default configuration for logical memcpy */
 struct stedma40_chan_cfg dma40_memcpy_conf_log = {
-	.channel_type = (STEDMA40_CHANNEL_IN_LOG_MODE |
-			 STEDMA40_LOW_PRIORITY_CHANNEL |
-			 STEDMA40_LCHAN_SRC_LOG_DST_LOG |
-			 STEDMA40_NO_TIM_FOR_LINK),
 	.dir = STEDMA40_MEM_TO_MEM,
 
-	.src_info.endianess = STEDMA40_LITTLE_ENDIAN,
 	.src_info.data_width = STEDMA40_BYTE_WIDTH,
 	.src_info.psize = STEDMA40_PSIZE_LOG_1,
 	.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
 
-	.dst_info.endianess = STEDMA40_LITTLE_ENDIAN,
 	.dst_info.data_width = STEDMA40_BYTE_WIDTH,
 	.dst_info.psize = STEDMA40_PSIZE_LOG_1,
 	.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
@@ -170,30 +236,29 @@
  * Mapping between destination event lines and physical device address.
  * The event line is tied to a device and therefor the address is constant.
  */
-static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV];
 
 /* Mapping between source event lines and physical device address */
-static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV];
 
 /* Reserved event lines for memcpy only */
 static int dma40_memcpy_event[] = {
-	STEDMA40_MEMCPY_TX_0,
-	STEDMA40_MEMCPY_TX_1,
-	STEDMA40_MEMCPY_TX_2,
-	STEDMA40_MEMCPY_TX_3,
-	STEDMA40_MEMCPY_TX_4,
-	STEDMA40_MEMCPY_TX_5,
+	DB8500_DMA_MEMCPY_TX_0,
+	DB8500_DMA_MEMCPY_TX_1,
+	DB8500_DMA_MEMCPY_TX_2,
+	DB8500_DMA_MEMCPY_TX_3,
+	DB8500_DMA_MEMCPY_TX_4,
+	DB8500_DMA_MEMCPY_TX_5,
 };
 
 static struct stedma40_platform_data dma40_plat_data = {
-	.dev_len = STEDMA40_NR_DEV,
+	.dev_len = DB8500_DMA_NR_DEV,
 	.dev_rx = dma40_rx_map,
 	.dev_tx = dma40_tx_map,
 	.memcpy = dma40_memcpy_event,
 	.memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
 	.memcpy_conf_phy = &dma40_memcpy_conf_phy,
 	.memcpy_conf_log = &dma40_memcpy_conf_log,
-	.llis_per_log = 8,
 	.disabled_channels = {-1},
 };
 
@@ -216,3 +281,23 @@
 	dma40_resources[1].start = U8500_DMA_LCPA_BASE_ED;
 	dma40_resources[1].end = U8500_DMA_LCPA_BASE_ED + 2 * SZ_1K - 1;
 }
+
+struct resource keypad_resources[] = {
+	[0] = {
+		.start = U8500_SKE_BASE,
+		.end = U8500_SKE_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_DB8500_KB,
+		.end = IRQ_DB8500_KB,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device ux500_ske_keypad_device = {
+	.name = "nmk-ske-keypad",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(keypad_resources),
+	.resource = keypad_resources,
+};
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/hotplug.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/hotplug.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/hotplug.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/hotplug.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *	Based on ARM realview platform
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+#include <asm/cacheflush.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+	flush_cache_all();
+
+	/* we put the platform to just WFI */
+	for (;;) {
+		__asm__ __volatile__("dsb\n\t" "wfi\n\t"
+				: : : "memory");
+		if (pen_release == cpu) {
+			/*
+			 * OK, proper wakeup, we're done
+			 */
+			break;
+		}
+	}
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+	unsigned int this_cpu = hard_smp_processor_id();
+
+	if (cpu != this_cpu) {
+		printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+			   this_cpu, cpu);
+		BUG();
+	}
+#endif
+
+	printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+	complete(&cpu_killed);
+
+	/* directly enter low power state, skipping secure registers */
+	platform_do_lowpower(cpu);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+	return cpu == 0 ? -EPERM : 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/db5500-regs.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/db5500-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/db5500-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/db5500-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -100,4 +100,18 @@
 #define U5500_GPIOBANK6_BASE	(U5500_GPIO4_BASE + 0x80)
 #define U5500_GPIOBANK7_BASE	(U5500_GPIO4_BASE + 0x100)
 
+#define U5500_MBOX_BASE		(U5500_MODEM_BASE + 0xFFD1000)
+#define U5500_MBOX0_PEER_START	(U5500_MBOX_BASE + 0x40)
+#define U5500_MBOX0_PEER_END	(U5500_MBOX_BASE + 0x5F)
+#define U5500_MBOX0_LOCAL_START	(U5500_MBOX_BASE + 0x60)
+#define U5500_MBOX0_LOCAL_END	(U5500_MBOX_BASE + 0x7F)
+#define U5500_MBOX1_PEER_START	(U5500_MBOX_BASE + 0x80)
+#define U5500_MBOX1_PEER_END	(U5500_MBOX_BASE + 0x9F)
+#define U5500_MBOX1_LOCAL_START	(U5500_MBOX_BASE + 0xA0)
+#define U5500_MBOX1_LOCAL_END	(U5500_MBOX_BASE + 0xBF)
+#define U5500_MBOX2_PEER_START	(U5500_MBOX_BASE + 0x00)
+#define U5500_MBOX2_PEER_END	(U5500_MBOX_BASE + 0x1F)
+#define U5500_MBOX2_LOCAL_START	(U5500_MBOX_BASE + 0x20)
+#define U5500_MBOX2_LOCAL_END	(U5500_MBOX_BASE + 0x3F)
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/db8500-regs.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/db8500-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/db8500-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/db8500-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,6 @@
 #define U8500_ICN_BASE		0x81000000
 
 #define U8500_BOOT_ROM_BASE	0x90000000
-/* ASIC ID is at 0xff4 offset within this region */
-#define U8500_ASIC_ID_BASE	0x9001F000
 
 #define U8500_PER6_BASE		0xa03c0000
 #define U8500_PER5_BASE		0xa03e0000
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -18,11 +18,9 @@
 #define UX500_UART(n)	__UX500_UART(n)
 #define UART_BASE	UX500_UART(CONFIG_UX500_DEBUG_UART)
 
-	.macro	addruart, rx, tmp
-	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1					@ MMU enabled?
-	ldreq	\rx, =UART_BASE				@ no, physical address
-	ldrne	\rx, =IO_ADDRESS(UART_BASE)		@ yes, virtual address
+	.macro	addruart, rp, rv
+	ldr	\rp, =UART_BASE				@ no, physical address
+	ldr	\rv, =IO_ADDRESS(UART_BASE)		@ yes, virtual address
 	.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/devices.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/devices.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/devices.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/devices.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,6 +26,14 @@
 extern struct platform_device u8500_i2c0_device;
 extern struct platform_device u8500_i2c4_device;
 extern struct platform_device u8500_dma40_device;
+extern struct platform_device ux500_ske_keypad_device;
+
+extern struct amba_device u8500_sdi0_device;
+extern struct amba_device u8500_sdi1_device;
+extern struct amba_device u8500_sdi2_device;
+extern struct amba_device u8500_sdi3_device;
+extern struct amba_device u8500_sdi4_device;
+extern struct amba_device u8500_sdi5_device;
 
 void dma40_u8500ed_fixup(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/hardware.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/hardware.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/hardware.h	2011-01-04 19:50:19.000000000 -0500
@@ -104,16 +104,35 @@
 #endif
 }
 
+#define CPUID_DB8500ED	0x410fc090
+#define CPUID_DB8500V1	0x411fc091
+#define CPUID_DB8500V2	0x412fc091
+
 static inline bool cpu_is_u8500ed(void)
 {
-	return cpu_is_u8500() && (read_cpuid_id() & 15) == 0;
+	return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED);
 }
 
 static inline bool cpu_is_u8500v1(void)
 {
-	return cpu_is_u8500() && (read_cpuid_id() & 15) == 1;
+	return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1);
 }
 
+static inline bool cpu_is_u8500v2(void)
+{
+	return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2);
+}
+
+#ifdef CONFIG_UX500_SOC_DB8500
+bool cpu_is_u8500v10(void);
+bool cpu_is_u8500v11(void);
+bool cpu_is_u8500v20(void);
+#else
+static inline bool cpu_is_u8500v10(void) { return false; }
+static inline bool cpu_is_u8500v11(void) { return false; }
+static inline bool cpu_is_u8500v20(void) { return false; }
+#endif
+
 static inline bool cpu_is_u5500(void)
 {
 #ifdef CONFIG_UX500_SOC_DB5500
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/irqs-db5500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/irqs-db5500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/irqs-db5500.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/irqs-db5500.h	2011-01-04 19:50:19.000000000 -0500
@@ -61,6 +61,7 @@
 #define IRQ_DB5500_SDMMC0		(IRQ_SHPI_START + 60)
 #define IRQ_DB5500_HSEM			(IRQ_SHPI_START + 61)
 #define IRQ_DB5500_SBAG			(IRQ_SHPI_START + 63)
+#define IRQ_DB5500_MODEM		(IRQ_SHPI_START + 65)
 #define IRQ_DB5500_SPI1			(IRQ_SHPI_START + 96)
 #define IRQ_DB5500_MSP2			(IRQ_SHPI_START + 98)
 #define IRQ_DB5500_SRPTIMER		(IRQ_SHPI_START + 101)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,8 @@
 #define IRQ_HSIR_CH1_OVRRUN	(IRQ_SHPI_START + 33)
 #define IRQ_HSIR_CH2_OVRRUN	(IRQ_SHPI_START + 34)
 #define IRQ_HSIR_CH3_OVRRUN	(IRQ_SHPI_START + 35)
-#define IRQ_AB4500		(IRQ_SHPI_START + 40)
+#define IRQ_AB8500		(IRQ_SHPI_START + 40)
+#define IRQ_PRCMU               (IRQ_SHPI_START + 47)
 #define IRQ_DISP		(IRQ_SHPI_START + 48)
 #define IRQ_SiPI3		(IRQ_SHPI_START + 49)
 #define IRQ_I2C4		(IRQ_SHPI_START + 51)
@@ -83,6 +84,19 @@
 #include <mach/irqs-board-mop500.h>
 #endif
 
-#define NR_IRQS				IRQ_BOARD_END
+/*
+ * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
+#define IRQ_MODEM_EVENTS_NBR 72
+#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+
+#define NR_IRQS				IRQ_MODEM_EVENTS_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/mbox.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/mbox.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/mbox.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/mbox.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __INC_STE_MBOX_H
+#define __INC_STE_MBOX_H
+
+#define MBOX_BUF_SIZE 16
+#define MBOX_NAME_SIZE 8
+
+/**
+  * mbox_recv_cb_t - Definition of the mailbox callback.
+  * @mbox_msg:	The mailbox message.
+  * @priv:	The clients private data as specified in the call to mbox_setup.
+  *
+  * This function will be called upon reception of new mailbox messages.
+  */
+typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
+
+/**
+  * struct mbox - Mailbox instance struct
+  * @list:		Linked list head.
+  * @pdev:		Pointer to device struct.
+  * @cb:		Callback function. Will be called
+  *			when new data is received.
+  * @client_data:	Clients private data. Will be sent back
+  *			in the callback function.
+  * @virtbase_peer:	Virtual address for outgoing mailbox.
+  * @virtbase_local:	Virtual address for incoming mailbox.
+  * @buffer:		Then internal queue for outgoing messages.
+  * @name:		Name of this mailbox.
+  * @buffer_available:	Completion variable to achieve "blocking send".
+  *			This variable will be signaled when there is
+  *			internal buffer space available.
+  * @client_blocked:	To keep track if any client is currently
+  *			blocked.
+  * @lock:		Spinlock to protect this mailbox instance.
+  * @write_index:	Index in internal buffer to write to.
+  * @read_index:	Index in internal buffer to read from.
+  * @allocated:		Indicates whether this particular mailbox
+  *			id has been allocated by someone.
+  */
+struct mbox {
+	struct list_head list;
+	struct platform_device *pdev;
+	mbox_recv_cb_t *cb;
+	void *client_data;
+	void __iomem *virtbase_peer;
+	void __iomem *virtbase_local;
+	u32 buffer[MBOX_BUF_SIZE];
+	char name[MBOX_NAME_SIZE];
+	struct completion buffer_available;
+	u8 client_blocked;
+	spinlock_t lock;
+	u8 write_index;
+	u8 read_index;
+	bool allocated;
+};
+
+/**
+  * mbox_setup - Set up a mailbox and return its instance.
+  * @mbox_id:	The ID number of the mailbox. 0 or 1 for modem CPU,
+  *		2 for modem DSP.
+  * @mbox_cb:	Pointer to the callback function to be called when a new message
+  *		is received.
+  * @priv:	Client user data which will be returned in the callback.
+  *
+  * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
+  */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
+
+/**
+  * mbox_send - Send a mailbox message.
+  * @mbox:	Mailbox instance (returned by mbox_setup)
+  * @mbox_msg:	The mailbox message to send.
+  * @block:	Specifies whether this call will block until send is possible,
+  *		or return an error if the mailbox buffer is full.
+  *
+  * Returns 0 on success or a negative error code on error. -ENOMEM indicates
+  * that the internal buffer is full and you have to try again later (or
+  * specify "block" in order to block until send is possible).
+  */
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
+
+#endif /*INC_STE_MBOX_H*/
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/prcmu.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/prcmu.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/prcmu.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/prcmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MACH_PRCMU_H
+#define __MACH_PRCMU_H
+
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#endif /* __MACH_PRCMU_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/prcmu-regs.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/prcmu-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/prcmu-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/prcmu-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+#ifndef __MACH_PRCMU_REGS_H
+#define __MACH_PRCMU_REGS_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_BASE		IO_ADDRESS(U8500_PRCMU_BASE)
+
+#define PRCM_ARM_PLLDIVPS	(_PRCMU_BASE + 0x118)
+#define PRCM_ARM_CHGCLKREQ	(_PRCMU_BASE + 0x114)
+#define PRCM_PLLARM_ENABLE	(_PRCMU_BASE + 0x98)
+#define PRCM_ARMCLKFIX_MGT	(_PRCMU_BASE + 0x0)
+#define PRCM_A9_RESETN_CLR	(_PRCMU_BASE + 0x1f4)
+#define PRCM_A9_RESETN_SET	(_PRCMU_BASE + 0x1f0)
+#define PRCM_ARM_LS_CLAMP	(_PRCMU_BASE + 0x30c)
+#define PRCM_SRAM_A9		(_PRCMU_BASE + 0x308)
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCMU_IOCR              (_PRCMU_BASE + 0x310)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL	(_PRCMU_BASE + 0x0fc)
+#define PRCM_MBOX_CPU_SET	(_PRCMU_BASE + 0x100)
+#define PRCM_MBOX_CPU_CLR	(_PRCMU_BASE + 0x104)
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ	(_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_ACK	(_PRCMU_BASE + 0x32c)
+#define PRCM_ARMITMSK31TO0	(_PRCMU_BASE + 0x11c)
+#define PRCM_ARMITMSK63TO32	(_PRCMU_BASE + 0x120)
+#define PRCM_ARMITMSK95TO64	(_PRCMU_BASE + 0x124)
+#define PRCM_ARMITMSK127TO96	(_PRCMU_BASE + 0x128)
+#define PRCM_POWER_STATE_VAL	(_PRCMU_BASE + 0x25C)
+#define PRCM_ARMITVAL31TO0	(_PRCMU_BASE + 0x260)
+#define PRCM_ARMITVAL63TO32	(_PRCMU_BASE + 0x264)
+#define PRCM_ARMITVAL95TO64	(_PRCMU_BASE + 0x268)
+#define PRCM_ARMITVAL127TO96	(_PRCMU_BASE + 0x26C)
+
+#define PRCM_HOSTACCESS_REQ	(_PRCMU_BASE + 0x334)
+#define ARM_WAKEUP_MODEM	0x1
+
+#define PRCM_ARM_IT1_CLEAR	(_PRCMU_BASE + 0x48C)
+#define PRCM_ARM_IT1_VAL	(_PRCMU_BASE + 0x494)
+#define PRCM_HOLD_EVT		(_PRCMU_BASE + 0x174)
+
+#define PRCM_ITSTATUS0		(_PRCMU_BASE + 0x148)
+#define PRCM_ITSTATUS1		(_PRCMU_BASE + 0x150)
+#define PRCM_ITSTATUS2		(_PRCMU_BASE + 0x158)
+#define PRCM_ITSTATUS3		(_PRCMU_BASE + 0x160)
+#define PRCM_ITSTATUS4		(_PRCMU_BASE + 0x168)
+#define PRCM_ITSTATUS5		(_PRCMU_BASE + 0x484)
+#define PRCM_ITCLEAR5		(_PRCMU_BASE + 0x488)
+#define PRCM_ARMIT_MASKXP70_IT	(_PRCMU_BASE + 0x1018)
+
+/* System reset register */
+#define PRCM_APE_SOFTRST	(_PRCMU_BASE + 0x228)
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
+#define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
+#define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
+#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + 0x044)
+#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + 0x064)
+#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + 0x058)
+#define PRCM_TVCLK_MGT             (_PRCMU_BASE + 0x07c)
+#define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
+#define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
+#define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
+#define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET            (_PRCMU_BASE + 0x410)
+#define PRCM_SRAM_LS_SLEEP         (_PRCMU_BASE + 0x304)
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET       (_PRCMU_BASE + 0x254)
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET          (_PRCMU_BASE + 0x324)
+
+#endif /* __MACH_PRCMU__REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/setup.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/setup.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/setup.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/setup.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,4 +38,11 @@
 	.type		= MT_DEVICE,		\
 }
 
+#define __MEM_DEV_DESC(x, sz)	{		\
+	.virtual	= IO_ADDRESS(x),	\
+	.pfn		= __phys_to_pfn(x),	\
+	.length		= sz,			\
+	.type		= MT_MEMORY,		\
+}
+
 #endif /*  __ASM_ARCH_SETUP_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/include/mach/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,18 +10,11 @@
 #define ASMARM_ARCH_SMP_H
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 /* This is required to wakeup the secondary core */
 extern void u8500_secondary_startup(void);
 
-#define hard_smp_processor_id()				\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x0F;				\
-	})
-
 /*
  * We use IRQ1 as the IPI
  */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/Kconfig linux-libre-2.6.37-gnu/arch/arm/mach-ux500/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -21,9 +21,7 @@
 	bool "U8500 Development platform"
 	select UX500_SOC_DB8500
 	help
-	  Include support for mop500 development platform
-	  based on U8500 architecture. The platform is based
-	  on early drop silicon version of 8500.
+	  Include support for the mop500 development platform.
 
 config MACH_U5500
 	bool "U5500 Development platform"
@@ -39,4 +37,18 @@
 	  Choose the UART on which kernel low-level debug messages should be
 	  output.
 
+config U5500_MODEM_IRQ
+	bool "Modem IRQ support"
+	depends on MACH_U5500
+	default y
+	help
+	  Add support for handling IRQ:s from modem side
+
+config U5500_MBOX
+	bool "Mailbox support"
+	depends on MACH_U5500 && U5500_MODEM_IRQ
+	default y
+	help
+	  Add support for U5500 mailbox communication with modem side
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/Makefile linux-libre-2.6.37-gnu/arch/arm/mach-ux500/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,8 +4,12 @@
 
 obj-y				:= clock.o cpu.o devices.o
 obj-$(CONFIG_UX500_SOC_DB5500)	+= cpu-db5500.o devices-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500_MOP)	+= board-mop500.o
+obj-$(CONFIG_UX500_SOC_DB8500)	+= cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_MACH_U8500_MOP)	+= board-mop500.o board-mop500-sdi.o
 obj-$(CONFIG_MACH_U5500)	+= board-u5500.o
 obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS)	+= localtimer.o
+obj-$(CONFIG_REGULATOR_AB8500)	+= board-mop500-regulators.o
+obj-$(CONFIG_U5500_MODEM_IRQ)	+= modem_irq.o
+obj-$(CONFIG_U5500_MBOX)	+= mbox.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/mbox.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/mbox.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/mbox.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/mbox.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/*
+ * Mailbox nomenclature:
+ *
+ *       APE           MODEM
+ *           mbox pairX
+ *   ..........................
+ *   .                       .
+ *   .           peer        .
+ *   .     send  ----        .
+ *   .      -->  |  |        .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .                       .
+ *   .           local       .
+ *   .     rec   ----        .
+ *   .           |  | <--    .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .........................
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/completion.h>
+#include <mach/mbox.h>
+
+#define MBOX_NAME "mbox"
+
+#define MBOX_FIFO_DATA        0x000
+#define MBOX_FIFO_ADD         0x004
+#define MBOX_FIFO_REMOVE      0x008
+#define MBOX_FIFO_THRES_FREE  0x00C
+#define MBOX_FIFO_THRES_OCCUP 0x010
+#define MBOX_FIFO_STATUS      0x014
+
+#define MBOX_DISABLE_IRQ 0x4
+#define MBOX_ENABLE_IRQ  0x0
+#define MBOX_LATCH 1
+
+/* Global list of all mailboxes */
+static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
+
+static struct mbox *get_mbox_with_id(u8 id)
+{
+	u8 i;
+	struct list_head *pos = &mboxs;
+	for (i = 0; i <= id; i++)
+		pos = pos->next;
+
+	return (struct mbox *) list_entry(pos, struct mbox, list);
+}
+
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
+{
+	int res = 0;
+
+	spin_lock(&mbox->lock);
+
+	dev_dbg(&(mbox->pdev->dev),
+		"About to buffer 0x%X to mailbox 0x%X."
+		" ri = %d, wi = %d\n",
+		mbox_msg, (u32)mbox, mbox->read_index,
+		mbox->write_index);
+
+	/* Check if write buffer is full */
+	while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
+		if (!block) {
+			dev_dbg(&(mbox->pdev->dev),
+			"Buffer full in non-blocking call! "
+			"Returning -ENOMEM!\n");
+			res = -ENOMEM;
+			goto exit;
+		}
+		spin_unlock(&mbox->lock);
+		dev_dbg(&(mbox->pdev->dev),
+			"Buffer full in blocking call! Sleeping...\n");
+		mbox->client_blocked = 1;
+		wait_for_completion(&mbox->buffer_available);
+		dev_dbg(&(mbox->pdev->dev),
+			"Blocking send was woken up! Trying again...\n");
+		spin_lock(&mbox->lock);
+	}
+
+	mbox->buffer[mbox->write_index] = mbox_msg;
+	mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
+
+	/*
+	 * Indicate that we want an IRQ as soon as there is a slot
+	 * in the FIFO
+	 */
+	writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+exit:
+	spin_unlock(&mbox->lock);
+	return res;
+}
+EXPORT_SYMBOL(mbox_send);
+
+#if defined(CONFIG_DEBUG_FS)
+/*
+ * Expected input: <value> <nbr sends>
+ * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
+ */
+static ssize_t mbox_write_fifo(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf,
+			       size_t count)
+{
+	unsigned long mbox_mess;
+	unsigned long nbr_sends;
+	unsigned long i;
+	char int_buf[16];
+	char *token;
+	char *val;
+
+	struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+	strncpy((char *) &int_buf, buf, sizeof(int_buf));
+	token = (char *) &int_buf;
+
+	/* Parse message */
+	val = strsep(&token, " ");
+	if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
+		mbox_mess = 0xDEADBEEF;
+
+	val = strsep(&token, " ");
+	if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
+		nbr_sends = 1;
+
+	dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
+		mbox_mess, nbr_sends, (u32) mbox);
+
+	for (i = 0; i < nbr_sends; i++)
+		mbox_send(mbox, mbox_mess, true);
+
+	return count;
+}
+
+static ssize_t mbox_read_fifo(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	int mbox_value;
+	struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+	if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
+		return sprintf(buf, "Mailbox is empty\n");
+
+	mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+	writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+	return sprintf(buf, "0x%X\n", mbox_value);
+}
+
+static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
+
+static int mbox_show(struct seq_file *s, void *data)
+{
+	struct list_head *pos;
+	u8 mbox_index = 0;
+
+	list_for_each(pos, &mboxs) {
+		struct mbox *m =
+			(struct mbox *) list_entry(pos, struct mbox, list);
+		if (m == NULL) {
+			seq_printf(s,
+				   "Unable to retrieve mailbox %d\n",
+				   mbox_index);
+			continue;
+		}
+
+		spin_lock(&m->lock);
+		if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
+			seq_printf(s, "MAILBOX %d not setup or corrupt\n",
+				   mbox_index);
+			spin_unlock(&m->lock);
+			continue;
+		}
+
+		seq_printf(s,
+		"===========================\n"
+		" MAILBOX %d\n"
+		" PEER MAILBOX DUMP\n"
+		"---------------------------\n"
+		"FIFO:                 0x%X (%d)\n"
+		"Free     Threshold:   0x%.2X (%d)\n"
+		"Occupied Threshold:   0x%.2X (%d)\n"
+		"Status:               0x%.2X (%d)\n"
+		"   Free spaces  (ot):    %d (%d)\n"
+		"   Occup spaces (ot):    %d (%d)\n"
+		"===========================\n"
+		" LOCAL MAILBOX DUMP\n"
+		"---------------------------\n"
+		"FIFO:                 0x%.X (%d)\n"
+		"Free     Threshold:   0x%.2X (%d)\n"
+		"Occupied Threshold:   0x%.2X (%d)\n"
+		"Status:               0x%.2X (%d)\n"
+		"   Free spaces  (ot):    %d (%d)\n"
+		"   Occup spaces (ot):    %d (%d)\n"
+		"===========================\n"
+		"write_index: %d\n"
+		"read_index : %d\n"
+		"===========================\n"
+		"\n",
+		mbox_index,
+		readl(m->virtbase_peer + MBOX_FIFO_DATA),
+		readl(m->virtbase_peer + MBOX_FIFO_DATA),
+		readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+		readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+		readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+		readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+		readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+		readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
+		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
+		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
+		(readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
+		readl(m->virtbase_local + MBOX_FIFO_DATA),
+		readl(m->virtbase_local + MBOX_FIFO_DATA),
+		readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+		readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+		readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+		readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+		readl(m->virtbase_local + MBOX_FIFO_STATUS),
+		readl(m->virtbase_local + MBOX_FIFO_STATUS),
+		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
+		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
+		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
+		(readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
+		m->write_index, m->read_index);
+		mbox_index++;
+		spin_unlock(&m->lock);
+	}
+
+	return 0;
+}
+
+static int mbox_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mbox_show, NULL);
+}
+
+static const struct file_operations mbox_operations = {
+	.owner = THIS_MODULE,
+	.open = mbox_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+#endif
+
+static irqreturn_t mbox_irq(int irq, void *arg)
+{
+	u32 mbox_value;
+	int nbr_occup;
+	int nbr_free;
+	struct mbox *mbox = (struct mbox *) arg;
+
+	spin_lock(&mbox->lock);
+
+	dev_dbg(&(mbox->pdev->dev),
+		"mbox IRQ [%d] received. ri = %d, wi = %d\n",
+		irq, mbox->read_index, mbox->write_index);
+
+	/*
+	 * Check if we have any outgoing messages, and if there is space for
+	 * them in the FIFO.
+	 */
+	if (mbox->read_index != mbox->write_index) {
+		/*
+		 * Check by reading FREE for LOCAL since that indicates
+		 * OCCUP for PEER
+		 */
+		nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
+			    >> 4) & 0x7;
+		dev_dbg(&(mbox->pdev->dev),
+			"Status indicates %d empty spaces in the FIFO!\n",
+			nbr_free);
+
+		while ((nbr_free > 0) &&
+		       (mbox->read_index != mbox->write_index)) {
+			/* Write the message and latch it into the FIFO */
+			writel(mbox->buffer[mbox->read_index],
+			       (mbox->virtbase_peer + MBOX_FIFO_DATA));
+			writel(MBOX_LATCH,
+			       (mbox->virtbase_peer + MBOX_FIFO_ADD));
+			dev_dbg(&(mbox->pdev->dev),
+				"Wrote message 0x%X to addr 0x%X\n",
+				mbox->buffer[mbox->read_index],
+				(u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
+
+			nbr_free--;
+			mbox->read_index =
+				(mbox->read_index + 1) % MBOX_BUF_SIZE;
+		}
+
+		/*
+		 * Check if we still want IRQ:s when there is free
+		 * space to send
+		 */
+		if (mbox->read_index != mbox->write_index) {
+			dev_dbg(&(mbox->pdev->dev),
+				"Still have messages to send, but FIFO full. "
+				"Request IRQ again!\n");
+			writel(MBOX_ENABLE_IRQ,
+			       mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+		} else {
+			dev_dbg(&(mbox->pdev->dev),
+				"No more messages to send. "
+				"Do not request IRQ again!\n");
+			writel(MBOX_DISABLE_IRQ,
+			       mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+		}
+
+		/*
+		 * Check if we can signal any blocked clients that it is OK to
+		 * start buffering again
+		 */
+		if (mbox->client_blocked &&
+		    (((mbox->write_index + 1) % MBOX_BUF_SIZE)
+		     != mbox->read_index)) {
+			dev_dbg(&(mbox->pdev->dev),
+				"Waking up blocked client\n");
+			complete(&mbox->buffer_available);
+			mbox->client_blocked = 0;
+		}
+	}
+
+	/* Check if we have any incoming messages */
+	nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
+	if (nbr_occup == 0)
+		goto exit;
+
+	if (mbox->cb == NULL) {
+		dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
+			"leaving %d incoming messages in fifo!\n", nbr_occup);
+		goto exit;
+	}
+
+	/* Read and acknowledge the message */
+	mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+	writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+	/* Notify consumer of new mailbox message */
+	dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
+		mbox_value);
+	mbox->cb(mbox_value, mbox->client_data);
+
+exit:
+	dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
+		mbox->read_index, mbox->write_index);
+	spin_unlock(&mbox->lock);
+
+	return IRQ_HANDLED;
+}
+
+/* Setup is executed once for each mbox pair */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
+{
+	struct resource *resource;
+	int irq;
+	int res;
+	struct mbox *mbox;
+
+	mbox = get_mbox_with_id(mbox_id);
+	if (mbox == NULL) {
+		dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
+			mbox_id);
+		goto exit;
+	}
+
+	/*
+	 * Check if mailbox has been allocated to someone else,
+	 * otherwise allocate it
+	 */
+	if (mbox->allocated) {
+		dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
+			mbox_id);
+		mbox = NULL;
+		goto exit;
+	}
+	mbox->allocated = true;
+
+	dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
+		mbox_id, (u32)mbox);
+
+	mbox->client_data = priv;
+	mbox->cb = mbox_cb;
+
+	/* Get addr for peer mailbox and ioremap it */
+	resource = platform_get_resource_byname(mbox->pdev,
+						IORESOURCE_MEM,
+						"mbox_peer");
+	if (resource == NULL) {
+		dev_err(&(mbox->pdev->dev),
+			"Unable to retrieve mbox peer resource\n");
+		mbox = NULL;
+		goto exit;
+	}
+	dev_dbg(&(mbox->pdev->dev),
+		"Resource name: %s start: 0x%X, end: 0x%X\n",
+		resource->name, resource->start, resource->end);
+	mbox->virtbase_peer =
+		ioremap(resource->start, resource->end - resource->start);
+	if (!mbox->virtbase_peer) {
+		dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
+		mbox = NULL;
+		goto exit;
+	}
+	dev_dbg(&(mbox->pdev->dev),
+		"ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
+		resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+	/* Get addr for local mailbox and ioremap it */
+	resource = platform_get_resource_byname(mbox->pdev,
+						IORESOURCE_MEM,
+						"mbox_local");
+	if (resource == NULL) {
+		dev_err(&(mbox->pdev->dev),
+			"Unable to retrieve mbox local resource\n");
+		mbox = NULL;
+		goto exit;
+	}
+	dev_dbg(&(mbox->pdev->dev),
+		"Resource name: %s start: 0x%X, end: 0x%X\n",
+		resource->name, resource->start, resource->end);
+	mbox->virtbase_local =
+		ioremap(resource->start, resource->end - resource->start);
+	if (!mbox->virtbase_local) {
+		dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
+		mbox = NULL;
+		goto exit;
+	}
+	dev_dbg(&(mbox->pdev->dev),
+		"ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
+		resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+	init_completion(&mbox->buffer_available);
+	mbox->client_blocked = 0;
+
+	/* Get IRQ for mailbox and allocate it */
+	irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
+	if (irq < 0) {
+		dev_err(&(mbox->pdev->dev),
+			"Unable to retrieve mbox irq resource\n");
+		mbox = NULL;
+		goto exit;
+	}
+
+	dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
+	res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
+	if (res < 0) {
+		dev_err(&(mbox->pdev->dev),
+			"Unable to allocate mbox irq %d\n", irq);
+		mbox = NULL;
+		goto exit;
+	}
+
+	/* Set up mailbox to not launch IRQ on free space in mailbox */
+	writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+	/*
+	 * Set up mailbox to launch IRQ on new message if we have
+	 * a callback set. If not, do not raise IRQ, but keep message
+	 * in FIFO for manual retrieval
+	 */
+	if (mbox_cb != NULL)
+		writel(MBOX_ENABLE_IRQ,
+		       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+	else
+		writel(MBOX_DISABLE_IRQ,
+		       mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+
+#if defined(CONFIG_DEBUG_FS)
+	res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
+	if (res != 0)
+		dev_warn(&(mbox->pdev->dev),
+			 "Unable to create mbox sysfs entry");
+
+	(void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
+				   NULL, &mbox_operations);
+#endif
+
+	dev_info(&(mbox->pdev->dev),
+		 "Mailbox driver with index %d initated!\n", mbox_id);
+
+exit:
+	return mbox;
+}
+EXPORT_SYMBOL(mbox_setup);
+
+
+int __init mbox_probe(struct platform_device *pdev)
+{
+	struct mbox local_mbox;
+	struct mbox *mbox;
+	int res = 0;
+	dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
+
+	memset(&local_mbox, 0x0, sizeof(struct mbox));
+
+	/* Associate our mbox data with the platform device */
+	res = platform_device_add_data(pdev,
+				       (void *) &local_mbox,
+				       sizeof(struct mbox));
+	if (res != 0) {
+		dev_err(&(pdev->dev),
+			"Unable to allocate driver platform data!\n");
+		goto exit;
+	}
+
+	mbox = (struct mbox *) pdev->dev.platform_data;
+	mbox->pdev = pdev;
+	mbox->write_index = 0;
+	mbox->read_index = 0;
+
+	INIT_LIST_HEAD(&(mbox->list));
+	list_add_tail(&(mbox->list), &mboxs);
+
+	sprintf(mbox->name, "%s", MBOX_NAME);
+	spin_lock_init(&mbox->lock);
+
+	dev_info(&(pdev->dev), "Mailbox driver loaded\n");
+
+exit:
+	return res;
+}
+
+static struct platform_driver mbox_driver = {
+	.driver = {
+		.name = MBOX_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init mbox_init(void)
+{
+	return platform_driver_probe(&mbox_driver, mbox_probe);
+}
+
+module_init(mbox_init);
+
+void __exit mbox_exit(void)
+{
+	platform_driver_unregister(&mbox_driver);
+}
+
+module_exit(mbox_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MBOX driver");
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/modem_irq.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/modem_irq.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/modem_irq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/modem_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
+#define MODEM_INTCON_SIZE 0xFFF
+
+#define DEST_IRQ41_OFFSET 0x2A4
+#define DEST_IRQ43_OFFSET 0x2AC
+#define DEST_IRQ45_OFFSET 0x2B4
+
+#define PRIO_IRQ41_OFFSET 0x6A4
+#define PRIO_IRQ43_OFFSET 0x6AC
+#define PRIO_IRQ45_OFFSET 0x6B4
+
+#define ALLOW_IRQ_OFFSET 0x104
+
+#define MODEM_INTCON_CPU_NBR 0x1
+#define MODEM_INTCON_PRIO_HIGH 0x0
+
+#define MODEM_INTCON_ALLOW_IRQ41 0x0200
+#define MODEM_INTCON_ALLOW_IRQ43 0x0800
+#define MODEM_INTCON_ALLOW_IRQ45 0x2000
+
+#define MODEM_IRQ_REG_OFFSET 0x4
+
+struct modem_irq {
+	void __iomem *modem_intcon_base;
+};
+
+
+static void setup_modem_intcon(void __iomem *modem_intcon_base)
+{
+	/* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
+	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
+	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
+	writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
+
+	/* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
+	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
+	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
+	writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
+
+	/* IC_ALLOW_ARRAY - IRQ enable */
+	writel(MODEM_INTCON_ALLOW_IRQ41 |
+		   MODEM_INTCON_ALLOW_IRQ43 |
+		   MODEM_INTCON_ALLOW_IRQ45,
+		   modem_intcon_base + ALLOW_IRQ_OFFSET);
+}
+
+static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
+{
+	int real_irq;
+	int virt_irq;
+	struct modem_irq *mi = (struct modem_irq *)data;
+
+	/* Read modem side IRQ number from modem IRQ controller */
+	real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
+	virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
+
+	pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
+		 "which will be 0x%X (%d) which translates to "
+		 "virtual IRQ 0x%X (%d)!\n",
+		   (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
+		   real_irq,
+		   real_irq & 0xFF,
+		   real_irq & 0xFF,
+		   virt_irq,
+		   virt_irq);
+
+	if (virt_irq != 0)
+		generic_handle_irq(virt_irq);
+
+	pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
+
+	return IRQ_HANDLED;
+}
+
+static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
+{
+	set_irq_chip(irq, modem_irq_chip);
+	set_irq_handler(irq, handle_simple_irq);
+	set_irq_flags(irq, IRQF_VALID);
+
+	pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
+}
+
+static int modem_irq_init(void)
+{
+	int err;
+	static struct irq_chip  modem_irq_chip;
+	struct modem_irq *mi;
+
+	pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
+		   IRQ_DB5500_MODEM);
+
+	mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
+	if (!mi) {
+		pr_err("modem_irq: Could not allocate device\n");
+		return -ENOMEM;
+	}
+
+	mi->modem_intcon_base =
+		ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
+	pr_debug("modem_irq: ioremapped modem_intcon_base from "
+		 "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
+		 (u32)mi->modem_intcon_base);
+
+	setup_modem_intcon(mi->modem_intcon_base);
+
+	modem_irq_chip = dummy_irq_chip;
+	modem_irq_chip.name = "modem_irq";
+
+	/* Create the virtual IRQ:s needed */
+	create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
+	create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
+	create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
+
+	err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
+				   modem_cpu_irq_handler, IRQF_ONESHOT,
+				   "modem_irq", mi);
+	if (err)
+		pr_err("modem_irq: Could not register IRQ %d\n",
+		       IRQ_DB5500_MODEM);
+
+	return 0;
+}
+
+arch_initcall(modem_irq_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/pins-db5500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/pins-db5500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/pins-db5500.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/pins-db5500.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_DB5500_PINS_H
+#define __MACH_DB5500_PINS_H
+
+#define GPIO0_GPIO		PIN_CFG(0, GPIO)
+#define GPIO0_SM_CS3n		PIN_CFG(0, ALT_A)
+
+#define GPIO1_GPIO		PIN_CFG(1, GPIO)
+#define GPIO1_SM_A3		PIN_CFG(1, ALT_A)
+
+#define GPIO2_GPIO		PIN_CFG(2, GPIO)
+#define GPIO2_SM_A4		PIN_CFG(2, ALT_A)
+#define GPIO2_SM_AVD		PIN_CFG(2, ALT_B)
+
+#define GPIO3_GPIO		PIN_CFG(3, GPIO)
+#define GPIO3_I2C1_SCL		PIN_CFG(3, ALT_A)
+
+#define GPIO4_GPIO		PIN_CFG(4, GPIO)
+#define GPIO4_I2C1_SDA		PIN_CFG(4, ALT_A)
+
+#define GPIO5_GPIO		PIN_CFG(5, GPIO)
+#define GPIO5_MC0_DAT0		PIN_CFG(5, ALT_A)
+#define GPIO5_SM_ADQ8		PIN_CFG(5, ALT_B)
+
+#define GPIO6_GPIO		PIN_CFG(6, GPIO)
+#define GPIO6_MC0_DAT1		PIN_CFG(6, ALT_A)
+#define GPIO6_SM_ADQ0		PIN_CFG(6, ALT_B)
+
+#define GPIO7_GPIO		PIN_CFG(7, GPIO)
+#define GPIO7_MC0_DAT2		PIN_CFG(7, ALT_A)
+#define GPIO7_SM_ADQ9		PIN_CFG(7, ALT_B)
+
+#define GPIO8_GPIO		PIN_CFG(8, GPIO)
+#define GPIO8_MC0_DAT3		PIN_CFG(8, ALT_A)
+#define GPIO8_SM_ADQ1		PIN_CFG(8, ALT_B)
+
+#define GPIO9_GPIO		PIN_CFG(9, GPIO)
+#define GPIO9_MC0_DAT4		PIN_CFG(9, ALT_A)
+#define GPIO9_SM_ADQ10		PIN_CFG(9, ALT_B)
+
+#define GPIO10_GPIO		PIN_CFG(10, GPIO)
+#define GPIO10_MC0_DAT5		PIN_CFG(10, ALT_A)
+#define GPIO10_SM_ADQ2		PIN_CFG(10, ALT_B)
+
+#define GPIO11_GPIO		PIN_CFG(11, GPIO)
+#define GPIO11_MC0_DAT6		PIN_CFG(11, ALT_A)
+#define GPIO11_SM_ADQ11		PIN_CFG(11, ALT_B)
+
+#define GPIO12_GPIO		PIN_CFG(12, GPIO)
+#define GPIO12_MC0_DAT7		PIN_CFG(12, ALT_A)
+#define GPIO12_SM_ADQ3		PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO		PIN_CFG(13, GPIO)
+#define GPIO13_MC0_CMD		PIN_CFG(13, ALT_A)
+#define GPIO13_SM_BUSY0n	PIN_CFG(13, ALT_B)
+#define GPIO13_SM_WAIT0n	PIN_CFG(13, ALT_C)
+
+#define GPIO14_GPIO		PIN_CFG(14, GPIO)
+#define GPIO14_MC0_CLK		PIN_CFG(14, ALT_A)
+#define GPIO14_SM_CS1n		PIN_CFG(14, ALT_B)
+#define GPIO14_SM_CKO		PIN_CFG(14, ALT_C)
+
+#define GPIO15_GPIO		PIN_CFG(15, GPIO)
+#define GPIO15_SM_A5		PIN_CFG(15, ALT_A)
+#define GPIO15_SM_CLE		PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO		PIN_CFG(16, GPIO)
+#define GPIO16_MC2_CMD		PIN_CFG(16, ALT_A)
+#define GPIO16_SM_OEn		PIN_CFG(16, ALT_B)
+
+#define GPIO17_GPIO		PIN_CFG(17, GPIO)
+#define GPIO17_MC2_CLK		PIN_CFG(17, ALT_A)
+#define GPIO17_SM_WEn		PIN_CFG(17, ALT_B)
+
+#define GPIO18_GPIO		PIN_CFG(18, GPIO)
+#define GPIO18_SM_A6		PIN_CFG(18, ALT_A)
+#define GPIO18_SM_ALE		PIN_CFG(18, ALT_B)
+#define GPIO18_SM_AVDn		PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO		PIN_CFG(19, GPIO)
+#define GPIO19_MC2_DAT1		PIN_CFG(19, ALT_A)
+#define GPIO19_SM_ADQ4		PIN_CFG(19, ALT_B)
+
+#define GPIO20_GPIO		PIN_CFG(20, GPIO)
+#define GPIO20_MC2_DAT3		PIN_CFG(20, ALT_A)
+#define GPIO20_SM_ADQ5		PIN_CFG(20, ALT_B)
+
+#define GPIO21_GPIO		PIN_CFG(21, GPIO)
+#define GPIO21_MC2_DAT5		PIN_CFG(21, ALT_A)
+#define GPIO21_SM_ADQ6		PIN_CFG(21, ALT_B)
+
+#define GPIO22_GPIO		PIN_CFG(22, GPIO)
+#define GPIO22_MC2_DAT7		PIN_CFG(22, ALT_A)
+#define GPIO22_SM_ADQ7		PIN_CFG(22, ALT_B)
+
+#define GPIO23_GPIO		PIN_CFG(23, GPIO)
+#define GPIO23_MC2_DAT0		PIN_CFG(23, ALT_A)
+#define GPIO23_SM_ADQ12		PIN_CFG(23, ALT_B)
+#define GPIO23_MC0_DAT1		PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO		PIN_CFG(24, GPIO)
+#define GPIO24_MC2_DAT2		PIN_CFG(24, ALT_A)
+#define GPIO24_SM_ADQ13		PIN_CFG(24, ALT_B)
+#define GPIO24_MC0_DAT3		PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO		PIN_CFG(25, GPIO)
+#define GPIO25_MC2_DAT4		PIN_CFG(25, ALT_A)
+#define GPIO25_SM_ADQ14		PIN_CFG(25, ALT_B)
+#define GPIO25_MC0_CMD		PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO		PIN_CFG(26, GPIO)
+#define GPIO26_MC2_DAT6		PIN_CFG(26, ALT_A)
+#define GPIO26_SM_ADQ15		PIN_CFG(26, ALT_B)
+
+#define GPIO27_GPIO		PIN_CFG(27, GPIO)
+#define GPIO27_SM_CS0n		PIN_CFG(27, ALT_A)
+#define GPIO27_SM_PS0n		PIN_CFG(27, ALT_B)
+
+#define GPIO28_GPIO		PIN_CFG(28, GPIO)
+#define GPIO28_U0_TXD		PIN_CFG(28, ALT_A)
+#define GPIO28_SM_A0		PIN_CFG(28, ALT_B)
+
+#define GPIO29_GPIO		PIN_CFG(29, GPIO)
+#define GPIO29_U0_RXD		PIN_CFG(29, ALT_A)
+#define GPIO29_SM_A1		PIN_CFG(29, ALT_B)
+#define GPIO29_PWM_0		PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO		PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5		PIN_CFG(30, ALT_A)
+#define GPIO30_SM_A2		PIN_CFG(30, ALT_B)
+#define GPIO30_PWM_1		PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO		PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT7		PIN_CFG(31, ALT_A)
+#define GPIO31_SM_CS2n		PIN_CFG(31, ALT_B)
+#define GPIO31_PWM_2		PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO		PIN_CFG(32, GPIO)
+#define GPIO32_MSP0_TCK		PIN_CFG(32, ALT_A)
+#define GPIO32_ACCI2S0_SCK	PIN_CFG(32, ALT_B)
+
+#define GPIO33_GPIO		PIN_CFG(33, GPIO)
+#define GPIO33_MSP0_TFS		PIN_CFG(33, ALT_A)
+#define GPIO33_ACCI2S0_WS	PIN_CFG(33, ALT_B)
+
+#define GPIO34_GPIO		PIN_CFG(34, GPIO)
+#define GPIO34_MSP0_TXD		PIN_CFG(34, ALT_A)
+#define GPIO34_ACCI2S0_DLD	PIN_CFG(34, ALT_B)
+
+#define GPIO35_GPIO		PIN_CFG(35, GPIO)
+#define GPIO35_MSP0_RXD		PIN_CFG(35, ALT_A)
+#define GPIO35_ACCI2S0_ULD	PIN_CFG(35, ALT_B)
+
+#define GPIO64_GPIO		PIN_CFG(64, GPIO)
+#define GPIO64_USB_DAT0		PIN_CFG(64, ALT_A)
+#define GPIO64_U0_TXD		PIN_CFG(64, ALT_B)
+
+#define GPIO65_GPIO		PIN_CFG(65, GPIO)
+#define GPIO65_USB_DAT1		PIN_CFG(65, ALT_A)
+#define GPIO65_U0_RXD		PIN_CFG(65, ALT_B)
+
+#define GPIO66_GPIO		PIN_CFG(66, GPIO)
+#define GPIO66_USB_DAT2		PIN_CFG(66, ALT_A)
+
+#define GPIO67_GPIO		PIN_CFG(67, GPIO)
+#define GPIO67_USB_DAT3		PIN_CFG(67, ALT_A)
+
+#define GPIO68_GPIO		PIN_CFG(68, GPIO)
+#define GPIO68_USB_DAT4		PIN_CFG(68, ALT_A)
+
+#define GPIO69_GPIO		PIN_CFG(69, GPIO)
+#define GPIO69_USB_DAT5		PIN_CFG(69, ALT_A)
+
+#define GPIO70_GPIO		PIN_CFG(70, GPIO)
+#define GPIO70_USB_DAT6		PIN_CFG(70, ALT_A)
+
+#define GPIO71_GPIO		PIN_CFG(71, GPIO)
+#define GPIO71_USB_DAT7		PIN_CFG(71, ALT_A)
+
+#define GPIO72_GPIO		PIN_CFG(72, GPIO)
+#define GPIO72_USB_STP		PIN_CFG(72, ALT_A)
+
+#define GPIO73_GPIO		PIN_CFG(73, GPIO)
+#define GPIO73_USB_DIR		PIN_CFG(73, ALT_A)
+
+#define GPIO74_GPIO		PIN_CFG(74, GPIO)
+#define GPIO74_USB_NXT		PIN_CFG(74, ALT_A)
+
+#define GPIO75_GPIO		PIN_CFG(75, GPIO)
+#define GPIO75_USB_XCLK		PIN_CFG(75, ALT_A)
+
+#define GPIO76_GPIO		PIN_CFG(76, GPIO)
+
+#define GPIO77_GPIO		PIN_CFG(77, GPIO)
+#define GPIO77_ACCTX_ON		PIN_CFG(77, ALT_A)
+
+#define GPIO78_GPIO		PIN_CFG(78, GPIO)
+#define GPIO78_IRQn		PIN_CFG(78, ALT_A)
+
+#define GPIO79_GPIO		PIN_CFG(79, GPIO)
+#define GPIO79_ACCSIM_Clk	PIN_CFG(79, ALT_A)
+
+#define GPIO80_GPIO		PIN_CFG(80, GPIO)
+#define GPIO80_ACCSIM_Da	PIN_CFG(80, ALT_A)
+
+#define GPIO81_GPIO		PIN_CFG(81, GPIO)
+#define GPIO81_ACCSIM_Reset	PIN_CFG(81, ALT_A)
+
+#define GPIO82_GPIO		PIN_CFG(82, GPIO)
+#define GPIO82_ACCSIM_DDir	PIN_CFG(82, ALT_A)
+
+#define GPIO96_GPIO		PIN_CFG(96, GPIO)
+#define GPIO96_MSP1_TCK		PIN_CFG(96, ALT_A)
+#define GPIO96_PRCMU_DEBUG3	PIN_CFG(96, ALT_B)
+#define GPIO96_PRCMU_DEBUG7	PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO		PIN_CFG(97, GPIO)
+#define GPIO97_MSP1_TFS		PIN_CFG(97, ALT_A)
+#define GPIO97_PRCMU_DEBUG2	PIN_CFG(97, ALT_B)
+#define GPIO97_PRCMU_DEBUG6	PIN_CFG(97, ALT_C)
+
+#define GPIO98_GPIO		PIN_CFG(98, GPIO)
+#define GPIO98_MSP1_TXD		PIN_CFG(98, ALT_A)
+#define GPIO98_PRCMU_DEBUG1	PIN_CFG(98, ALT_B)
+#define GPIO98_PRCMU_DEBUG5	PIN_CFG(98, ALT_C)
+
+#define GPIO99_GPIO		PIN_CFG(99, GPIO)
+#define GPIO99_MSP1_RXD		PIN_CFG(99, ALT_A)
+#define GPIO99_PRCMU_DEBUG0	PIN_CFG(99, ALT_B)
+#define GPIO99_PRCMU_DEBUG4	PIN_CFG(99, ALT_C)
+
+#define GPIO100_GPIO		PIN_CFG(100, GPIO)
+#define GPIO100_I2C0_SCL	PIN_CFG(100, ALT_A)
+
+#define GPIO101_GPIO		PIN_CFG(101, GPIO)
+#define GPIO101_I2C0_SDA	PIN_CFG(101, ALT_A)
+
+#define GPIO128_GPIO		PIN_CFG(128, GPIO)
+#define GPIO128_KP_I0		PIN_CFG(128, ALT_A)
+#define GPIO128_BUSMON_D0	PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO		PIN_CFG(129, GPIO)
+#define GPIO129_KP_O0		PIN_CFG(129, ALT_A)
+#define GPIO129_BUSMON_D1	PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO		PIN_CFG(130, GPIO)
+#define GPIO130_KP_I1		PIN_CFG(130, ALT_A)
+#define GPIO130_BUSMON_D2	PIN_CFG(130, ALT_B)
+
+#define GPIO131_GPIO		PIN_CFG(131, GPIO)
+#define GPIO131_KP_O1		PIN_CFG(131, ALT_A)
+#define GPIO131_BUSMON_D3	PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO		PIN_CFG(132, GPIO)
+#define GPIO132_KP_I2		PIN_CFG(132, ALT_A)
+#define GPIO132_ETM_D15		PIN_CFG(132, ALT_B)
+#define GPIO132_STMAPE_CLK	PIN_CFG(132, ALT_C)
+
+#define GPIO133_GPIO		PIN_CFG(133, GPIO)
+#define GPIO133_KP_O2		PIN_CFG(133, ALT_A)
+#define GPIO133_ETM_D14		PIN_CFG(133, ALT_B)
+#define GPIO133_U0_RXD		PIN_CFG(133, ALT_C)
+
+#define GPIO134_GPIO		PIN_CFG(134, GPIO)
+#define GPIO134_KP_I3		PIN_CFG(134, ALT_A)
+#define GPIO134_ETM_D13		PIN_CFG(134, ALT_B)
+#define GPIO134_STMAPE_DAT0	PIN_CFG(134, ALT_C)
+
+#define GPIO135_GPIO		PIN_CFG(135, GPIO)
+#define GPIO135_KP_O3		PIN_CFG(135, ALT_A)
+#define GPIO135_ETM_D12		PIN_CFG(135, ALT_B)
+#define GPIO135_STMAPE_DAT1	PIN_CFG(135, ALT_C)
+
+#define GPIO136_GPIO		PIN_CFG(136, GPIO)
+#define GPIO136_KP_I4		PIN_CFG(136, ALT_A)
+#define GPIO136_ETM_D11		PIN_CFG(136, ALT_B)
+#define GPIO136_STMAPE_DAT2	PIN_CFG(136, ALT_C)
+
+#define GPIO137_GPIO		PIN_CFG(137, GPIO)
+#define GPIO137_KP_O4		PIN_CFG(137, ALT_A)
+#define GPIO137_ETM_D10		PIN_CFG(137, ALT_B)
+#define GPIO137_STMAPE_DAT3	PIN_CFG(137, ALT_C)
+
+#define GPIO138_GPIO		PIN_CFG(138, GPIO)
+#define GPIO138_KP_I5		PIN_CFG(138, ALT_A)
+#define GPIO138_ETM_D9		PIN_CFG(138, ALT_B)
+#define GPIO138_U0_TXD		PIN_CFG(138, ALT_C)
+
+#define GPIO139_GPIO		PIN_CFG(139, GPIO)
+#define GPIO139_KP_O5		PIN_CFG(139, ALT_A)
+#define GPIO139_ETM_D8		PIN_CFG(139, ALT_B)
+#define GPIO139_BUSMON_D11	PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO		PIN_CFG(140, GPIO)
+#define GPIO140_KP_I6		PIN_CFG(140, ALT_A)
+#define GPIO140_ETM_D7		PIN_CFG(140, ALT_B)
+#define GPIO140_STMAPE_CLK	PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO		PIN_CFG(141, GPIO)
+#define GPIO141_KP_O6		PIN_CFG(141, ALT_A)
+#define GPIO141_ETM_D6		PIN_CFG(141, ALT_B)
+#define GPIO141_U0_RXD		PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO		PIN_CFG(142, GPIO)
+#define GPIO142_KP_I7		PIN_CFG(142, ALT_A)
+#define GPIO142_ETM_D5		PIN_CFG(142, ALT_B)
+#define GPIO142_STMAPE_DAT0	PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO		PIN_CFG(143, GPIO)
+#define GPIO143_KP_O7		PIN_CFG(143, ALT_A)
+#define GPIO143_ETM_D4		PIN_CFG(143, ALT_B)
+#define GPIO143_STMAPE_DAT1	PIN_CFG(143, ALT_C)
+
+#define GPIO144_GPIO		PIN_CFG(144, GPIO)
+#define GPIO144_I2C3_SCL	PIN_CFG(144, ALT_A)
+#define GPIO144_ETM_D3		PIN_CFG(144, ALT_B)
+#define GPIO144_STMAPE_DAT2	PIN_CFG(144, ALT_C)
+
+#define GPIO145_GPIO		PIN_CFG(145, GPIO)
+#define GPIO145_I2C3_SDA	PIN_CFG(145, ALT_A)
+#define GPIO145_ETM_D2		PIN_CFG(145, ALT_B)
+#define GPIO145_STMAPE_DAT3	PIN_CFG(145, ALT_C)
+
+#define GPIO146_GPIO		PIN_CFG(146, GPIO)
+#define GPIO146_PWM_0		PIN_CFG(146, ALT_A)
+#define GPIO146_ETM_D1		PIN_CFG(146, ALT_B)
+
+#define GPIO147_GPIO		PIN_CFG(147, GPIO)
+#define GPIO147_PWM_1		PIN_CFG(147, ALT_A)
+#define GPIO147_ETM_D0		PIN_CFG(147, ALT_B)
+
+#define GPIO148_GPIO		PIN_CFG(148, GPIO)
+#define GPIO148_PWM_2		PIN_CFG(148, ALT_A)
+#define GPIO148_ETM_CLK		PIN_CFG(148, ALT_B)
+
+#define GPIO160_GPIO		PIN_CFG(160, GPIO)
+#define GPIO160_CLKOUT_REQn	PIN_CFG(160, ALT_A)
+
+#define GPIO161_GPIO		PIN_CFG(161, GPIO)
+#define GPIO161_CLKOUT_0	PIN_CFG(161, ALT_A)
+
+#define GPIO162_GPIO		PIN_CFG(162, GPIO)
+#define GPIO162_CLKOUT_1	PIN_CFG(162, ALT_A)
+
+#define GPIO163_GPIO		PIN_CFG(163, GPIO)
+
+#define GPIO164_GPIO		PIN_CFG(164, GPIO)
+#define GPIO164_GPS_START	PIN_CFG(164, ALT_A)
+
+#define GPIO165_GPIO		PIN_CFG(165, GPIO)
+#define GPIO165_SPI1_CS2n	PIN_CFG(165, ALT_A)
+#define GPIO165_U3_RXD		PIN_CFG(165, ALT_B)
+#define GPIO165_BUSMON_D20	PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO		PIN_CFG(166, GPIO)
+#define GPIO166_SPI1_CS1n	PIN_CFG(166, ALT_A)
+#define GPIO166_U3_TXD		PIN_CFG(166, ALT_B)
+#define GPIO166_BUSMON_D21	PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO		PIN_CFG(167, GPIO)
+#define GPIO167_SPI1_CS0n	PIN_CFG(167, ALT_A)
+#define GPIO167_U3_RTSn		PIN_CFG(167, ALT_B)
+#define GPIO167_BUSMON_D22	PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO		PIN_CFG(168, GPIO)
+#define GPIO168_SPI1_RXD	PIN_CFG(168, ALT_A)
+#define GPIO168_U3_CTSn		PIN_CFG(168, ALT_B)
+#define GPIO168_BUSMON_D23	PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO		PIN_CFG(169, GPIO)
+#define GPIO169_SPI1_TXD	PIN_CFG(169, ALT_A)
+#define GPIO169_DDR_RC		PIN_CFG(169, ALT_B)
+#define GPIO169_BUSMON_D24	PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO		PIN_CFG(170, GPIO)
+#define GPIO170_SPI1_CLK	PIN_CFG(170, ALT_A)
+
+#define GPIO171_GPIO		PIN_CFG(171, GPIO)
+#define GPIO171_MC3_DAT0	PIN_CFG(171, ALT_A)
+#define GPIO171_SPI3_RXD	PIN_CFG(171, ALT_B)
+#define GPIO171_BUSMON_D25	PIN_CFG(171, ALT_C)
+
+#define GPIO172_GPIO		PIN_CFG(172, GPIO)
+#define GPIO172_MC3_DAT1	PIN_CFG(172, ALT_A)
+#define GPIO172_SPI3_CS1n	PIN_CFG(172, ALT_B)
+#define GPIO172_BUSMON_D26	PIN_CFG(172, ALT_C)
+
+#define GPIO173_GPIO		PIN_CFG(173, GPIO)
+#define GPIO173_MC3_DAT2	PIN_CFG(173, ALT_A)
+#define GPIO173_SPI3_CS2n	PIN_CFG(173, ALT_B)
+#define GPIO173_BUSMON_D27	PIN_CFG(173, ALT_C)
+
+#define GPIO174_GPIO		PIN_CFG(174, GPIO)
+#define GPIO174_MC3_DAT3	PIN_CFG(174, ALT_A)
+#define GPIO174_SPI3_CS0n	PIN_CFG(174, ALT_B)
+#define GPIO174_BUSMON_D28	PIN_CFG(174, ALT_C)
+
+#define GPIO175_GPIO		PIN_CFG(175, GPIO)
+#define GPIO175_MC3_CMD		PIN_CFG(175, ALT_A)
+#define GPIO175_SPI3_TXD	PIN_CFG(175, ALT_B)
+#define GPIO175_BUSMON_D29	PIN_CFG(175, ALT_C)
+
+#define GPIO176_GPIO		PIN_CFG(176, GPIO)
+#define GPIO176_MC3_CLK		PIN_CFG(176, ALT_A)
+#define GPIO176_SPI3_CLK	PIN_CFG(176, ALT_B)
+
+#define GPIO177_GPIO		PIN_CFG(177, GPIO)
+#define GPIO177_U2_RXD		PIN_CFG(177, ALT_A)
+#define GPIO177_I2C3_SCL	PIN_CFG(177, ALT_B)
+#define GPIO177_BUSMON_D30	PIN_CFG(177, ALT_C)
+
+#define GPIO178_GPIO		PIN_CFG(178, GPIO)
+#define GPIO178_U2_TXD		PIN_CFG(178, ALT_A)
+#define GPIO178_I2C3_SDA	PIN_CFG(178, ALT_B)
+#define GPIO178_BUSMON_D31	PIN_CFG(178, ALT_C)
+
+#define GPIO179_GPIO		PIN_CFG(179, GPIO)
+#define GPIO179_U2_CTSn		PIN_CFG(179, ALT_A)
+#define GPIO179_U3_RXD		PIN_CFG(179, ALT_B)
+#define GPIO179_BUSMON_D32	PIN_CFG(179, ALT_C)
+
+#define GPIO180_GPIO		PIN_CFG(180, GPIO)
+#define GPIO180_U2_RTSn		PIN_CFG(180, ALT_A)
+#define GPIO180_U3_TXD		PIN_CFG(180, ALT_B)
+#define GPIO180_BUSMON_D33	PIN_CFG(180, ALT_C)
+
+#define GPIO185_GPIO		PIN_CFG(185, GPIO)
+#define GPIO185_SPI3_CS2n	PIN_CFG(185, ALT_A)
+#define GPIO185_MC4_DAT0	PIN_CFG(185, ALT_B)
+
+#define GPIO186_GPIO		PIN_CFG(186, GPIO)
+#define GPIO186_SPI3_CS1n	PIN_CFG(186, ALT_A)
+#define GPIO186_MC4_DAT1	PIN_CFG(186, ALT_B)
+
+#define GPIO187_GPIO		PIN_CFG(187, GPIO)
+#define GPIO187_SPI3_CS0n	PIN_CFG(187, ALT_A)
+#define GPIO187_MC4_DAT2	PIN_CFG(187, ALT_B)
+
+#define GPIO188_GPIO		PIN_CFG(188, GPIO)
+#define GPIO188_SPI3_RXD	PIN_CFG(188, ALT_A)
+#define GPIO188_MC4_DAT3	PIN_CFG(188, ALT_B)
+
+#define GPIO189_GPIO		PIN_CFG(189, GPIO)
+#define GPIO189_SPI3_TXD	PIN_CFG(189, ALT_A)
+#define GPIO189_MC4_CMD		PIN_CFG(189, ALT_B)
+
+#define GPIO190_GPIO		PIN_CFG(190, GPIO)
+#define GPIO190_SPI3_CLK	PIN_CFG(190, ALT_A)
+#define GPIO190_MC4_CLK		PIN_CFG(190, ALT_B)
+
+#define GPIO191_GPIO		PIN_CFG(191, GPIO)
+#define GPIO191_MC1_DAT0	PIN_CFG(191, ALT_A)
+#define GPIO191_MC4_DAT4	PIN_CFG(191, ALT_B)
+#define GPIO191_STMAPE_DAT0	PIN_CFG(191, ALT_C)
+
+#define GPIO192_GPIO		PIN_CFG(192, GPIO)
+#define GPIO192_MC1_DAT1	PIN_CFG(192, ALT_A)
+#define GPIO192_MC4_DAT5	PIN_CFG(192, ALT_B)
+#define GPIO192_STMAPE_DAT1	PIN_CFG(192, ALT_C)
+
+#define GPIO193_GPIO		PIN_CFG(193, GPIO)
+#define GPIO193_MC1_DAT2	PIN_CFG(193, ALT_A)
+#define GPIO193_MC4_DAT6	PIN_CFG(193, ALT_B)
+#define GPIO193_STMAPE_DAT2	PIN_CFG(193, ALT_C)
+
+#define GPIO194_GPIO		PIN_CFG(194, GPIO)
+#define GPIO194_MC1_DAT3	PIN_CFG(194, ALT_A)
+#define GPIO194_MC4_DAT7	PIN_CFG(194, ALT_B)
+#define GPIO194_STMAPE_DAT3	PIN_CFG(194, ALT_C)
+
+#define GPIO195_GPIO		PIN_CFG(195, GPIO)
+#define GPIO195_MC1_CLK		PIN_CFG(195, ALT_A)
+#define GPIO195_STMAPE_CLK	PIN_CFG(195, ALT_B)
+#define GPIO195_BUSMON_CLK	PIN_CFG(195, ALT_C)
+
+#define GPIO196_GPIO		PIN_CFG(196, GPIO)
+#define GPIO196_MC1_CMD		PIN_CFG(196, ALT_A)
+#define GPIO196_U0_RXD		PIN_CFG(196, ALT_B)
+#define GPIO196_BUSMON_D38	PIN_CFG(196, ALT_C)
+
+#define GPIO197_GPIO		PIN_CFG(197, GPIO)
+#define GPIO197_MC1_CMDDIR	PIN_CFG(197, ALT_A)
+#define GPIO197_BUSMON_D39	PIN_CFG(197, ALT_B)
+
+#define GPIO198_GPIO		PIN_CFG(198, GPIO)
+#define GPIO198_MC1_FBCLK	PIN_CFG(198, ALT_A)
+
+#define GPIO199_GPIO		PIN_CFG(199, GPIO)
+#define GPIO199_MC1_DAT0DIR	PIN_CFG(199, ALT_A)
+#define GPIO199_BUSMON_D40	PIN_CFG(199, ALT_B)
+
+#define GPIO200_GPIO		PIN_CFG(200, GPIO)
+#define GPIO200_U1_TXD		PIN_CFG(200, ALT_A)
+#define GPIO200_ACCU0_RTSn	PIN_CFG(200, ALT_B)
+
+#define GPIO201_GPIO		PIN_CFG(201, GPIO)
+#define GPIO201_U1_RXD		PIN_CFG(201, ALT_A)
+#define GPIO201_ACCU0_CTSn	PIN_CFG(201, ALT_B)
+
+#define GPIO202_GPIO		PIN_CFG(202, GPIO)
+#define GPIO202_U1_CTSn		PIN_CFG(202, ALT_A)
+#define GPIO202_ACCU0_RXD	PIN_CFG(202, ALT_B)
+
+#define GPIO203_GPIO		PIN_CFG(203, GPIO)
+#define GPIO203_U1_RTSn		PIN_CFG(203, ALT_A)
+#define GPIO203_ACCU0_TXD	PIN_CFG(203, ALT_B)
+
+#define GPIO204_GPIO		PIN_CFG(204, GPIO)
+#define GPIO204_SPI0_CS2n	PIN_CFG(204, ALT_A)
+#define GPIO204_ACCGPIO_000	PIN_CFG(204, ALT_B)
+#define GPIO204_LCD_VSI1	PIN_CFG(204, ALT_C)
+
+#define GPIO205_GPIO		PIN_CFG(205, GPIO)
+#define GPIO205_SPI0_CS1n	PIN_CFG(205, ALT_A)
+#define GPIO205_ACCGPIO_001	PIN_CFG(205, ALT_B)
+#define GPIO205_LCD_D3		PIN_CFG(205, ALT_C)
+
+#define GPIO206_GPIO		PIN_CFG(206, GPIO)
+#define GPIO206_SPI0_CS0n	PIN_CFG(206, ALT_A)
+#define GPIO206_ACCGPIO_002	PIN_CFG(206, ALT_B)
+#define GPIO206_LCD_D2		PIN_CFG(206, ALT_C)
+
+#define GPIO207_GPIO		PIN_CFG(207, GPIO)
+#define GPIO207_SPI0_RXD	PIN_CFG(207, ALT_A)
+#define GPIO207_ACCGPIO_003	PIN_CFG(207, ALT_B)
+#define GPIO207_LCD_D1		PIN_CFG(207, ALT_C)
+
+#define GPIO208_GPIO		PIN_CFG(208, GPIO)
+#define GPIO208_SPI0_TXD	PIN_CFG(208, ALT_A)
+#define GPIO208_ACCGPIO_004	PIN_CFG(208, ALT_B)
+#define GPIO208_LCD_D0		PIN_CFG(208, ALT_C)
+
+#define GPIO209_GPIO		PIN_CFG(209, GPIO)
+#define GPIO209_SPI0_CLK	PIN_CFG(209, ALT_A)
+#define GPIO209_ACCGPIO_005	PIN_CFG(209, ALT_B)
+#define GPIO209_LCD_CLK		PIN_CFG(209, ALT_C)
+
+#define GPIO210_GPIO		PIN_CFG(210, GPIO)
+#define GPIO210_LCD_VSO		PIN_CFG(210, ALT_A)
+#define GPIO210_PRCMU_PWRCTRL1	PIN_CFG(210, ALT_B)
+
+#define GPIO211_GPIO		PIN_CFG(211, GPIO)
+#define GPIO211_LCD_VSI0	PIN_CFG(211, ALT_A)
+#define GPIO211_PRCMU_PWRCTRL2	PIN_CFG(211, ALT_B)
+
+#define GPIO212_GPIO		PIN_CFG(212, GPIO)
+#define GPIO212_SPI2_CS2n	PIN_CFG(212, ALT_A)
+#define GPIO212_LCD_HSO		PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO		PIN_CFG(213, GPIO)
+#define GPIO213_SPI2_CS1n	PIN_CFG(213, ALT_A)
+#define GPIO213_LCD_DE		PIN_CFG(213, ALT_B)
+#define GPIO213_BUSMON_D16	PIN_CFG(213, ALT_C)
+
+#define GPIO214_GPIO		PIN_CFG(214, GPIO)
+#define GPIO214_SPI2_CS0n	PIN_CFG(214, ALT_A)
+#define GPIO214_LCD_D7		PIN_CFG(214, ALT_B)
+#define GPIO214_BUSMON_D17	PIN_CFG(214, ALT_C)
+
+#define GPIO215_GPIO		PIN_CFG(215, GPIO)
+#define GPIO215_SPI2_RXD	PIN_CFG(215, ALT_A)
+#define GPIO215_LCD_D6		PIN_CFG(215, ALT_B)
+#define GPIO215_BUSMON_D18	PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO		PIN_CFG(216, GPIO)
+#define GPIO216_SPI2_CLK	PIN_CFG(216, ALT_A)
+#define GPIO216_LCD_D5		PIN_CFG(216, ALT_B)
+
+#define GPIO217_GPIO		PIN_CFG(217, GPIO)
+#define GPIO217_SPI2_TXD	PIN_CFG(217, ALT_A)
+#define GPIO217_LCD_D4		PIN_CFG(217, ALT_B)
+#define GPIO217_BUSMON_D19	PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO		PIN_CFG(218, GPIO)
+#define GPIO218_I2C2_SCL	PIN_CFG(218, ALT_A)
+#define GPIO218_LCD_VSO		PIN_CFG(218, ALT_B)
+
+#define GPIO219_GPIO		PIN_CFG(219, GPIO)
+#define GPIO219_I2C2_SDA	PIN_CFG(219, ALT_A)
+#define GPIO219_LCD_D3		PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO		PIN_CFG(220, GPIO)
+#define GPIO220_MSP2_TCK	PIN_CFG(220, ALT_A)
+#define GPIO220_LCD_D2		PIN_CFG(220, ALT_B)
+
+#define GPIO221_GPIO		PIN_CFG(221, GPIO)
+#define GPIO221_MSP2_TFS	PIN_CFG(221, ALT_A)
+#define GPIO221_LCD_D1		PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO		PIN_CFG(222, GPIO)
+#define GPIO222_MSP2_TXD	PIN_CFG(222, ALT_A)
+#define GPIO222_LCD_D0		PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO		PIN_CFG(223, GPIO)
+#define GPIO223_MSP2_RXD	PIN_CFG(223, ALT_A)
+#define GPIO223_LCD_CLK		PIN_CFG(223, ALT_B)
+
+#define GPIO224_GPIO		PIN_CFG(224, GPIO)
+#define GPIO224_PRCMU_PWRCTRL0	PIN_CFG(224, ALT_A)
+#define GPIO224_LCD_VSI1	PIN_CFG(224, ALT_B)
+
+#define GPIO225_GPIO		PIN_CFG(225, GPIO)
+#define GPIO225_PRCMU_PWRCTRL1	PIN_CFG(225, ALT_A)
+#define GPIO225_IRDA_RXD	PIN_CFG(225, ALT_B)
+
+#define GPIO226_GPIO		PIN_CFG(226, GPIO)
+#define GPIO226_PRCMU_PWRCTRL2	PIN_CFG(226, ALT_A)
+#define GPIO226_IRRC_DAT	PIN_CFG(226, ALT_B)
+
+#define GPIO227_GPIO		PIN_CFG(227, GPIO)
+#define GPIO227_IRRC_DAT	PIN_CFG(227, ALT_A)
+#define GPIO227_IRDA_TXD	PIN_CFG(227, ALT_B)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/pins-db8500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/pins-db8500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/pins-db8500.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/pins-db8500.h	2011-01-04 19:50:19.000000000 -0500
@@ -96,57 +96,57 @@
 #define GPIO17_SLIM0_CLK	PIN_CFG(17, ALT_C)
 
 #define GPIO18_GPIO		PIN_CFG(18, GPIO)
-#define GPIO18_MC0_CMDDIR	PIN_CFG(18, ALT_A)
+#define GPIO18_MC0_CMDDIR	PIN_CFG_PULL(18, ALT_A, UP)
 #define GPIO18_U2_RXD		PIN_CFG(18, ALT_B)
 #define GPIO18_MS_IEP		PIN_CFG(18, ALT_C)
 
 #define GPIO19_GPIO		PIN_CFG(19, GPIO)
-#define GPIO19_MC0_DAT0DIR	PIN_CFG(19, ALT_A)
+#define GPIO19_MC0_DAT0DIR	PIN_CFG_PULL(19, ALT_A, UP)
 #define GPIO19_U2_TXD		PIN_CFG(19, ALT_B)
 #define GPIO19_MS_DAT0DIR	PIN_CFG(19, ALT_C)
 
 #define GPIO20_GPIO		PIN_CFG(20, GPIO)
-#define GPIO20_MC0_DAT2DIR	PIN_CFG(20, ALT_A)
+#define GPIO20_MC0_DAT2DIR	PIN_CFG_PULL(20, ALT_A, UP)
 #define GPIO20_UARTMOD_TXD	PIN_CFG(20, ALT_B)
 #define GPIO20_IP_TRIGOUT	PIN_CFG(20, ALT_C)
 
 #define GPIO21_GPIO		PIN_CFG(21, GPIO)
-#define GPIO21_MC0_DAT31DIR	PIN_CFG(21, ALT_A)
+#define GPIO21_MC0_DAT31DIR	PIN_CFG_PULL(21, ALT_A, UP)
 #define GPIO21_MSP0_SCK		PIN_CFG(21, ALT_B)
 #define GPIO21_MS_DAT31DIR	PIN_CFG(21, ALT_C)
 
 #define GPIO22_GPIO		PIN_CFG(22, GPIO)
-#define GPIO22_MC0_FBCLK	PIN_CFG(22, ALT_A)
+#define GPIO22_MC0_FBCLK	PIN_CFG_PULL(22, ALT_A, UP)
 #define GPIO22_UARTMOD_RXD	PIN_CFG(22, ALT_B)
 #define GPIO22_MS_FBCLK		PIN_CFG(22, ALT_C)
 
 #define GPIO23_GPIO		PIN_CFG(23, GPIO)
-#define GPIO23_MC0_CLK		PIN_CFG(23, ALT_A)
+#define GPIO23_MC0_CLK		PIN_CFG_PULL(23, ALT_A, UP)
 #define GPIO23_STMMOD_CLK	PIN_CFG(23, ALT_B)
 #define GPIO23_MS_CLK		PIN_CFG(23, ALT_C)
 
 #define GPIO24_GPIO		PIN_CFG(24, GPIO)
-#define GPIO24_MC0_CMD		PIN_CFG(24, ALT_A)
+#define GPIO24_MC0_CMD		PIN_CFG_PULL(24, ALT_A, UP)
 #define GPIO24_UARTMOD_RXD	PIN_CFG(24, ALT_B)
 #define GPIO24_MS_BS		PIN_CFG(24, ALT_C)
 
 #define GPIO25_GPIO		PIN_CFG(25, GPIO)
-#define GPIO25_MC0_DAT0		PIN_CFG(25, ALT_A)
+#define GPIO25_MC0_DAT0		PIN_CFG_PULL(25, ALT_A, UP)
 #define GPIO25_STMMOD_DAT0	PIN_CFG(25, ALT_B)
 #define GPIO25_MS_DAT0		PIN_CFG(25, ALT_C)
 
 #define GPIO26_GPIO		PIN_CFG(26, GPIO)
-#define GPIO26_MC0_DAT1		PIN_CFG(26, ALT_A)
+#define GPIO26_MC0_DAT1		PIN_CFG_PULL(26, ALT_A, UP)
 #define GPIO26_STMMOD_DAT1	PIN_CFG(26, ALT_B)
 #define GPIO26_MS_DAT1		PIN_CFG(26, ALT_C)
 
 #define GPIO27_GPIO		PIN_CFG(27, GPIO)
-#define GPIO27_MC0_DAT2		PIN_CFG(27, ALT_A)
+#define GPIO27_MC0_DAT2		PIN_CFG_PULL(27, ALT_A, UP)
 #define GPIO27_STMMOD_DAT2	PIN_CFG(27, ALT_B)
 #define GPIO27_MS_DAT2		PIN_CFG(27, ALT_C)
 
 #define GPIO28_GPIO		PIN_CFG(28, GPIO)
-#define GPIO28_MC0_DAT3		PIN_CFG(28, ALT_A)
+#define GPIO28_MC0_DAT3		PIN_CFG_PULL(28, ALT_A, UP)
 #define GPIO28_STMMOD_DAT3	PIN_CFG(28, ALT_B)
 #define GPIO28_MS_DAT3		PIN_CFG(28, ALT_C)
 
@@ -357,48 +357,48 @@
 #define GPIO97_MC5_DAT7		PIN_CFG(97, ALT_C)
 
 #define GPIO128_GPIO		PIN_CFG(128, GPIO)
-#define GPIO128_MC2_CLK		PIN_CFG(128, ALT_A)
+#define GPIO128_MC2_CLK		PIN_CFG_PULL(128, ALT_A, UP)
 #define GPIO128_SM_CKO		PIN_CFG(128, ALT_B)
 
 #define GPIO129_GPIO		PIN_CFG(129, GPIO)
-#define GPIO129_MC2_CMD		PIN_CFG(129, ALT_A)
+#define GPIO129_MC2_CMD		PIN_CFG_PULL(129, ALT_A, UP)
 #define GPIO129_SM_WAIT0n	PIN_CFG(129, ALT_B)
 
 #define GPIO130_GPIO		PIN_CFG(130, GPIO)
-#define GPIO130_MC2_FBCLK	PIN_CFG(130, ALT_A)
+#define GPIO130_MC2_FBCLK	PIN_CFG_PULL(130, ALT_A, UP)
 #define GPIO130_SM_FBCLK	PIN_CFG(130, ALT_B)
 #define GPIO130_MC2_RSTN	PIN_CFG(130, ALT_C)
 
 #define GPIO131_GPIO		PIN_CFG(131, GPIO)
-#define GPIO131_MC2_DAT0	PIN_CFG(131, ALT_A)
+#define GPIO131_MC2_DAT0	PIN_CFG_PULL(131, ALT_A, UP)
 #define GPIO131_SM_ADQ8		PIN_CFG(131, ALT_B)
 
 #define GPIO132_GPIO		PIN_CFG(132, GPIO)
-#define GPIO132_MC2_DAT1	PIN_CFG(132, ALT_A)
+#define GPIO132_MC2_DAT1	PIN_CFG_PULL(132, ALT_A, UP)
 #define GPIO132_SM_ADQ9		PIN_CFG(132, ALT_B)
 
 #define GPIO133_GPIO		PIN_CFG(133, GPIO)
-#define GPIO133_MC2_DAT2	PIN_CFG(133, ALT_A)
+#define GPIO133_MC2_DAT2	PIN_CFG_PULL(133, ALT_A, UP)
 #define GPIO133_SM_ADQ10	PIN_CFG(133, ALT_B)
 
 #define GPIO134_GPIO		PIN_CFG(134, GPIO)
-#define GPIO134_MC2_DAT3	PIN_CFG(134, ALT_A)
+#define GPIO134_MC2_DAT3	PIN_CFG_PULL(134, ALT_A, UP)
 #define GPIO134_SM_ADQ11	PIN_CFG(134, ALT_B)
 
 #define GPIO135_GPIO		PIN_CFG(135, GPIO)
-#define GPIO135_MC2_DAT4	PIN_CFG(135, ALT_A)
+#define GPIO135_MC2_DAT4	PIN_CFG_PULL(135, ALT_A, UP)
 #define GPIO135_SM_ADQ12	PIN_CFG(135, ALT_B)
 
 #define GPIO136_GPIO		PIN_CFG(136, GPIO)
-#define GPIO136_MC2_DAT5	PIN_CFG(136, ALT_A)
+#define GPIO136_MC2_DAT5	PIN_CFG_PULL(136, ALT_A, UP)
 #define GPIO136_SM_ADQ13	PIN_CFG(136, ALT_B)
 
 #define GPIO137_GPIO		PIN_CFG(137, GPIO)
-#define GPIO137_MC2_DAT6	PIN_CFG(137, ALT_A)
+#define GPIO137_MC2_DAT6	PIN_CFG_PULL(137, ALT_A, UP)
 #define GPIO137_SM_ADQ14	PIN_CFG(137, ALT_B)
 
 #define GPIO138_GPIO		PIN_CFG(138, GPIO)
-#define GPIO138_MC2_DAT7	PIN_CFG(138, ALT_A)
+#define GPIO138_MC2_DAT7	PIN_CFG_PULL(138, ALT_A, UP)
 #define GPIO138_SM_ADQ15	PIN_CFG(138, ALT_B)
 
 #define GPIO139_GPIO		PIN_CFG(139, GPIO)
@@ -459,82 +459,82 @@
 #define GPIO152_KP_O9		PIN_CFG(152, ALT_C)
 
 #define GPIO153_GPIO		PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7		PIN_CFG(153, ALT_A)
+#define GPIO153_KP_I7		PIN_CFG_PULL(153, ALT_A, DOWN)
 #define GPIO153_LCD_D24		PIN_CFG(153, ALT_B)
 #define GPIO153_U2_RXD		PIN_CFG(153, ALT_C)
 
 #define GPIO154_GPIO		PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6		PIN_CFG(154, ALT_A)
+#define GPIO154_KP_I6		PIN_CFG_PULL(154, ALT_A, DOWN)
 #define GPIO154_LCD_D25		PIN_CFG(154, ALT_B)
 #define GPIO154_U2_TXD		PIN_CFG(154, ALT_C)
 
 #define GPIO155_GPIO		PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5		PIN_CFG(155, ALT_A)
+#define GPIO155_KP_I5		PIN_CFG_PULL(155, ALT_A, DOWN)
 #define GPIO155_LCD_D26		PIN_CFG(155, ALT_B)
 #define GPIO155_STMAPE_CLK	PIN_CFG(155, ALT_C)
 
 #define GPIO156_GPIO		PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4		PIN_CFG(156, ALT_A)
+#define GPIO156_KP_I4		PIN_CFG_PULL(156, ALT_A, DOWN)
 #define GPIO156_LCD_D27		PIN_CFG(156, ALT_B)
 #define GPIO156_STMAPE_DAT3	PIN_CFG(156, ALT_C)
 
 #define GPIO157_GPIO		PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7		PIN_CFG(157, ALT_A)
+#define GPIO157_KP_O7		PIN_CFG_PULL(157, ALT_A, UP)
 #define GPIO157_LCD_D28		PIN_CFG(157, ALT_B)
 #define GPIO157_STMAPE_DAT2	PIN_CFG(157, ALT_C)
 
 #define GPIO158_GPIO		PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6		PIN_CFG(158, ALT_A)
+#define GPIO158_KP_O6		PIN_CFG_PULL(158, ALT_A, UP)
 #define GPIO158_LCD_D29		PIN_CFG(158, ALT_B)
 #define GPIO158_STMAPE_DAT1	PIN_CFG(158, ALT_C)
 
 #define GPIO159_GPIO		PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5		PIN_CFG(159, ALT_A)
+#define GPIO159_KP_O5		PIN_CFG_PULL(159, ALT_A, UP)
 #define GPIO159_LCD_D30		PIN_CFG(159, ALT_B)
 #define GPIO159_STMAPE_DAT0	PIN_CFG(159, ALT_C)
 
 #define GPIO160_GPIO		PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4		PIN_CFG(160, ALT_A)
+#define GPIO160_KP_O4		PIN_CFG_PULL(160, ALT_A, UP)
 #define GPIO160_LCD_D31		PIN_CFG(160, ALT_B)
 #define GPIO160_NONE		PIN_CFG(160, ALT_C)
 
 #define GPIO161_GPIO		PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3		PIN_CFG(161, ALT_A)
+#define GPIO161_KP_I3		PIN_CFG_PULL(161, ALT_A, DOWN)
 #define GPIO161_LCD_D32		PIN_CFG(161, ALT_B)
 #define GPIO161_UARTMOD_RXD	PIN_CFG(161, ALT_C)
 
 #define GPIO162_GPIO		PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2		PIN_CFG(162, ALT_A)
+#define GPIO162_KP_I2		PIN_CFG_PULL(162, ALT_A, DOWN)
 #define GPIO162_LCD_D33		PIN_CFG(162, ALT_B)
 #define GPIO162_UARTMOD_TXD	PIN_CFG(162, ALT_C)
 
 #define GPIO163_GPIO		PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1		PIN_CFG(163, ALT_A)
+#define GPIO163_KP_I1		PIN_CFG_PULL(163, ALT_A, DOWN)
 #define GPIO163_LCD_D34		PIN_CFG(163, ALT_B)
 #define GPIO163_STMMOD_CLK	PIN_CFG(163, ALT_C)
 
 #define GPIO164_GPIO		PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0		PIN_CFG(164, ALT_A)
+#define GPIO164_KP_I0		PIN_CFG_PULL(164, ALT_A, UP)
 #define GPIO164_LCD_D35		PIN_CFG(164, ALT_B)
 #define GPIO164_STMMOD_DAT3	PIN_CFG(164, ALT_C)
 
 #define GPIO165_GPIO		PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3		PIN_CFG(165, ALT_A)
+#define GPIO165_KP_O3		PIN_CFG_PULL(165, ALT_A, UP)
 #define GPIO165_LCD_D36		PIN_CFG(165, ALT_B)
 #define GPIO165_STMMOD_DAT2	PIN_CFG(165, ALT_C)
 
 #define GPIO166_GPIO		PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2		PIN_CFG(166, ALT_A)
+#define GPIO166_KP_O2		PIN_CFG_PULL(166, ALT_A, UP)
 #define GPIO166_LCD_D37		PIN_CFG(166, ALT_B)
 #define GPIO166_STMMOD_DAT1	PIN_CFG(166, ALT_C)
 
 #define GPIO167_GPIO		PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1		PIN_CFG(167, ALT_A)
+#define GPIO167_KP_O1		PIN_CFG_PULL(167, ALT_A, UP)
 #define GPIO167_LCD_D38		PIN_CFG(167, ALT_B)
 #define GPIO167_STMMOD_DAT0	PIN_CFG(167, ALT_C)
 
 #define GPIO168_GPIO		PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0		PIN_CFG(168, ALT_A)
+#define GPIO168_KP_O0		PIN_CFG_PULL(168, ALT_A, UP)
 #define GPIO168_LCD_D39		PIN_CFG(168, ALT_B)
 #define GPIO168_NONE		PIN_CFG(168, ALT_C)
 
@@ -569,39 +569,39 @@
 #define GPIO196_MSP2_RXD	PIN_CFG(196, ALT_A)
 
 #define GPIO197_GPIO		PIN_CFG(197, GPIO)
-#define GPIO197_MC4_DAT3	PIN_CFG(197, ALT_A)
+#define GPIO197_MC4_DAT3	PIN_CFG_PULL(197, ALT_A, UP)
 
 #define GPIO198_GPIO		PIN_CFG(198, GPIO)
-#define GPIO198_MC4_DAT2	PIN_CFG(198, ALT_A)
+#define GPIO198_MC4_DAT2	PIN_CFG_PULL(198, ALT_A, UP)
 
 #define GPIO199_GPIO		PIN_CFG(199, GPIO)
-#define GPIO199_MC4_DAT1	PIN_CFG(199, ALT_A)
+#define GPIO199_MC4_DAT1	PIN_CFG_PULL(199, ALT_A, UP)
 
 #define GPIO200_GPIO		PIN_CFG(200, GPIO)
-#define GPIO200_MC4_DAT0	PIN_CFG(200, ALT_A)
+#define GPIO200_MC4_DAT0	PIN_CFG_PULL(200, ALT_A, UP)
 
 #define GPIO201_GPIO		PIN_CFG(201, GPIO)
-#define GPIO201_MC4_CMD		PIN_CFG(201, ALT_A)
+#define GPIO201_MC4_CMD		PIN_CFG_PULL(201, ALT_A, UP)
 
 #define GPIO202_GPIO		PIN_CFG(202, GPIO)
-#define GPIO202_MC4_FBCLK	PIN_CFG(202, ALT_A)
+#define GPIO202_MC4_FBCLK	PIN_CFG_PULL(202, ALT_A, UP)
 #define GPIO202_PWL		PIN_CFG(202, ALT_B)
 #define GPIO202_MC4_RSTN	PIN_CFG(202, ALT_C)
 
 #define GPIO203_GPIO		PIN_CFG(203, GPIO)
-#define GPIO203_MC4_CLK		PIN_CFG(203, ALT_A)
+#define GPIO203_MC4_CLK		PIN_CFG_PULL(203, ALT_A, UP)
 
 #define GPIO204_GPIO		PIN_CFG(204, GPIO)
-#define GPIO204_MC4_DAT7	PIN_CFG(204, ALT_A)
+#define GPIO204_MC4_DAT7	PIN_CFG_PULL(204, ALT_A, UP)
 
 #define GPIO205_GPIO		PIN_CFG(205, GPIO)
-#define GPIO205_MC4_DAT6	PIN_CFG(205, ALT_A)
+#define GPIO205_MC4_DAT6	PIN_CFG_PULL(205, ALT_A, UP)
 
 #define GPIO206_GPIO		PIN_CFG(206, GPIO)
-#define GPIO206_MC4_DAT5	PIN_CFG(206, ALT_A)
+#define GPIO206_MC4_DAT5	PIN_CFG_PULL(206, ALT_A, UP)
 
 #define GPIO207_GPIO		PIN_CFG(207, GPIO)
-#define GPIO207_MC4_DAT4	PIN_CFG(207, ALT_A)
+#define GPIO207_MC4_DAT4	PIN_CFG_PULL(207, ALT_A, UP)
 
 #define GPIO208_GPIO		PIN_CFG(208, GPIO)
 #define GPIO208_MC1_CLK		PIN_CFG(208, ALT_A)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/platsmp.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/platsmp.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/platsmp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/platsmp.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,6 +78,8 @@
 	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
 	outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1);
 
+	smp_cross_call(cpumask_of(cpu));
+
 	timeout = jiffies + (1 * HZ);
 	while (time_before(jiffies, timeout)) {
 		if (pen_release == -1)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/prcmu.c linux-libre-2.6.37-gnu/arch/arm/mach-ux500/prcmu.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/prcmu.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/prcmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) ST Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCMU driver.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+
+#include <mach/hardware.h>
+#include <mach/prcmu-regs.h>
+
+#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE)
+
+#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44)
+#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4)
+
+#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
+#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
+#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
+#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
+
+#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
+#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
+
+#define I2C_WRITE(slave) ((slave) << 1)
+#define I2C_READ(slave) (((slave) << 1) | BIT(0))
+#define I2C_STOP_EN BIT(3)
+
+enum ack_mb5_status {
+	I2C_WR_OK = 0x01,
+	I2C_RD_OK = 0x02,
+};
+
+#define MBOX_BIT BIT
+#define NUM_MBOX 8
+
+static struct {
+	struct mutex lock;
+	struct completion work;
+	bool failed;
+	struct {
+		u8 status;
+		u8 value;
+	} ack;
+} mb5_transfer;
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:	The I2C slave address.
+ * @reg:	The (start) register address.
+ * @value:	The read out value(s).
+ * @size:	The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+	int r;
+
+	if (size != 1)
+		return -EINVAL;
+
+	r = mutex_lock_interruptible(&mb5_transfer.lock);
+	if (r)
+		return r;
+
+	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+		cpu_relax();
+
+	writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
+	writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+	writeb(reg, REQ_MB5_I2C_REG);
+
+	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+	if (!wait_for_completion_timeout(&mb5_transfer.work,
+			msecs_to_jiffies(500))) {
+		pr_err("prcmu: prcmu_abb_read timed out.\n");
+		r = -EIO;
+		goto unlock_and_return;
+	}
+	r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+	if (!r)
+		*value = mb5_transfer.ack.value;
+
+unlock_and_return:
+	mutex_unlock(&mb5_transfer.lock);
+	return r;
+}
+EXPORT_SYMBOL(prcmu_abb_read);
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:	The I2C slave address.
+ * @reg:	The (start) register address.
+ * @value:	The value(s) to write.
+ * @size:	The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+	int r;
+
+	if (size != 1)
+		return -EINVAL;
+
+	r = mutex_lock_interruptible(&mb5_transfer.lock);
+	if (r)
+		return r;
+
+
+	while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+		cpu_relax();
+
+	writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
+	writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+	writeb(reg, REQ_MB5_I2C_REG);
+	writeb(*value, REQ_MB5_I2C_VAL);
+
+	writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+	if (!wait_for_completion_timeout(&mb5_transfer.work,
+			msecs_to_jiffies(500))) {
+		pr_err("prcmu: prcmu_abb_write timed out.\n");
+		r = -EIO;
+		goto unlock_and_return;
+	}
+	r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+
+unlock_and_return:
+	mutex_unlock(&mb5_transfer.lock);
+	return r;
+}
+EXPORT_SYMBOL(prcmu_abb_write);
+
+static void read_mailbox_0(void)
+{
+	writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_1(void)
+{
+	writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_2(void)
+{
+	writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_3(void)
+{
+	writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_4(void)
+{
+	writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_5(void)
+{
+	mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
+	mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
+	complete(&mb5_transfer.work);
+	writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_6(void)
+{
+	writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_7(void)
+{
+	writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+}
+
+static void (* const read_mailbox[NUM_MBOX])(void) = {
+	read_mailbox_0,
+	read_mailbox_1,
+	read_mailbox_2,
+	read_mailbox_3,
+	read_mailbox_4,
+	read_mailbox_5,
+	read_mailbox_6,
+	read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+	u32 bits;
+	u8 n;
+
+	bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
+	if (unlikely(!bits))
+		return IRQ_NONE;
+
+	for (n = 0; bits; n++) {
+		if (bits & MBOX_BIT(n)) {
+			bits -= MBOX_BIT(n);
+			read_mailbox[n]();
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int __init prcmu_init(void)
+{
+	mutex_init(&mb5_transfer.lock);
+	init_completion(&mb5_transfer.work);
+
+	/* Clean up the mailbox interrupts after pre-kernel code. */
+	writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
+
+	return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL);
+}
+
+arch_initcall(prcmu_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/ste-dma40-db5500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/ste-dma40-db5500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/ste-dma40-db5500.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/ste-dma40-db5500.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * DB5500-SoC-specific configuration for DMA40
+ */
+
+#ifndef STE_DMA40_DB5500_H
+#define STE_DMA40_DB5500_H
+
+#define DB5500_DMA_NR_DEV 64
+
+enum dma_src_dev_type {
+	DB5500_DMA_DEV0_SPI0_RX = 0,
+	DB5500_DMA_DEV1_SPI1_RX = 1,
+	DB5500_DMA_DEV2_SPI2_RX = 2,
+	DB5500_DMA_DEV3_SPI3_RX = 3,
+	DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
+	DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
+	DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
+	DB5500_DMA_DEV7_IRDA_RFS = 7,
+	DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
+	DB5500_DMA_DEV9_MSP0_RX = 9,
+	DB5500_DMA_DEV10_MSP1_RX = 10,
+	DB5500_DMA_DEV11_MSP2_RX = 11,
+	DB5500_DMA_DEV12_UART0_RX = 12,
+	DB5500_DMA_DEV13_UART1_RX = 13,
+	DB5500_DMA_DEV14_UART2_RX = 14,
+	DB5500_DMA_DEV15_UART3_RX = 15,
+	DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
+	DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
+	DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
+	DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
+	DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
+	DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
+	DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
+	DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
+	DB5500_DMA_DEV24_SDMMC0_RX = 24,
+	DB5500_DMA_DEV25_SDMMC1_RX = 25,
+	DB5500_DMA_DEV26_SDMMC2_RX = 26,
+	DB5500_DMA_DEV27_SDMMC3_RX = 27,
+	DB5500_DMA_DEV28_SDMMC4_RX = 28,
+	/* 29 - 32 not used */
+	DB5500_DMA_DEV33_SDMMC0_RX = 33,
+	DB5500_DMA_DEV34_SDMMC1_RX = 34,
+	DB5500_DMA_DEV35_SDMMC2_RX = 35,
+	DB5500_DMA_DEV36_SDMMC3_RX = 36,
+	DB5500_DMA_DEV37_SDMMC4_RX = 37,
+	DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
+	DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
+	DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
+	DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
+	DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
+	DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
+	DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
+	DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
+	/* 46 not used */
+	DB5500_DMA_DEV47_MCDE_RX = 47,
+	DB5500_DMA_DEV48_CRYPTO1_RX = 48,
+	/* 49, 50 not used */
+	DB5500_DMA_DEV49_I2C1_RX = 51,
+	DB5500_DMA_DEV50_I2C3_RX = 52,
+	DB5500_DMA_DEV51_I2C2_RX = 53,
+	/* 54 - 60 not used */
+	DB5500_DMA_DEV61_CRYPTO0_RX = 61,
+	/* 62, 63 not used */
+};
+
+enum dma_dest_dev_type {
+	DB5500_DMA_DEV0_SPI0_TX = 0,
+	DB5500_DMA_DEV1_SPI1_TX = 1,
+	DB5500_DMA_DEV2_SPI2_TX = 2,
+	DB5500_DMA_DEV3_SPI3_TX = 3,
+	DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
+	DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
+	DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
+	DB5500_DMA_DEV7_IRRC_TX = 7,
+	DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
+	DB5500_DMA_DEV9_MSP0_TX = 9,
+	DB5500_DMA_DEV10_MSP1_TX = 10,
+	DB5500_DMA_DEV11_MSP2_TX = 11,
+	DB5500_DMA_DEV12_UART0_TX = 12,
+	DB5500_DMA_DEV13_UART1_TX = 13,
+	DB5500_DMA_DEV14_UART2_TX = 14,
+	DB5500_DMA_DEV15_UART3_TX = 15,
+	DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
+	DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
+	DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
+	DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
+	DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
+	DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
+	DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
+	DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
+	DB5500_DMA_DEV24_SDMMC0_TX = 24,
+	DB5500_DMA_DEV25_SDMMC1_TX = 25,
+	DB5500_DMA_DEV26_SDMMC2_TX = 26,
+	DB5500_DMA_DEV27_SDMMC3_TX = 27,
+	DB5500_DMA_DEV28_SDMMC4_TX = 28,
+	/* 29 - 31 not used */
+	DB5500_DMA_DEV32_FSMC_TX = 32,
+	DB5500_DMA_DEV33_SDMMC0_TX = 33,
+	DB5500_DMA_DEV34_SDMMC1_TX = 34,
+	DB5500_DMA_DEV35_SDMMC2_TX = 35,
+	DB5500_DMA_DEV36_SDMMC3_TX = 36,
+	DB5500_DMA_DEV37_SDMMC4_TX = 37,
+	DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
+	DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
+	DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
+	DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
+	DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
+	DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
+	DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
+	DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
+	/* 46 not used */
+	DB5500_DMA_DEV47_STM_TX = 47,
+	DB5500_DMA_DEV48_CRYPTO1_TX = 48,
+	DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
+	DB5500_DMA_DEV50_HASH1_TX = 50,
+	DB5500_DMA_DEV51_I2C1_TX = 51,
+	DB5500_DMA_DEV52_I2C3_TX = 52,
+	DB5500_DMA_DEV53_I2C2_TX = 53,
+	/* 54, 55 not used */
+	DB5500_DMA_MEMCPY_TX_1 = 56,
+	DB5500_DMA_MEMCPY_TX_2 = 57,
+	DB5500_DMA_MEMCPY_TX_3 = 58,
+	DB5500_DMA_MEMCPY_TX_4 = 59,
+	DB5500_DMA_MEMCPY_TX_5 = 60,
+	DB5500_DMA_DEV61_CRYPTO0_TX = 61,
+	DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
+	DB5500_DMA_DEV63_HASH0_TX = 63,
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-ux500/ste-dma40-db8500.h linux-libre-2.6.37-gnu/arch/arm/mach-ux500/ste-dma40-db8500.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-ux500/ste-dma40-db8500.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-ux500/ste-dma40-db8500.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,145 +10,135 @@
 #ifndef STE_DMA40_DB8500_H
 #define STE_DMA40_DB8500_H
 
-#define STEDMA40_NR_DEV 64
+#define DB8500_DMA_NR_DEV 64
 
 enum dma_src_dev_type {
-	STEDMA40_DEV_SPI0_RX = 0,
-	STEDMA40_DEV_SD_MMC0_RX = 1,
-	STEDMA40_DEV_SD_MMC1_RX = 2,
-	STEDMA40_DEV_SD_MMC2_RX = 3,
-	STEDMA40_DEV_I2C1_RX = 4,
-	STEDMA40_DEV_I2C3_RX = 5,
-	STEDMA40_DEV_I2C2_RX = 6,
-	STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */
-	STEDMA40_DEV_SSP0_RX = 8,
-	STEDMA40_DEV_SSP1_RX = 9,
-	STEDMA40_DEV_MCDE_RX = 10,
-	STEDMA40_DEV_UART2_RX = 11,
-	STEDMA40_DEV_UART1_RX = 12,
-	STEDMA40_DEV_UART0_RX = 13,
-	STEDMA40_DEV_MSP2_RX = 14,
-	STEDMA40_DEV_I2C0_RX = 15,
-	STEDMA40_DEV_USB_OTG_IEP_8 = 16,
-	STEDMA40_DEV_USB_OTG_IEP_1_9 = 17,
-	STEDMA40_DEV_USB_OTG_IEP_2_10 = 18,
-	STEDMA40_DEV_USB_OTG_IEP_3_11 = 19,
-	STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
-	STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
-	STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
-	STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
-	STEDMA40_DEV_SRC_SXA0_RX_TX = 24,
-	STEDMA40_DEV_SRC_SXA1_RX_TX = 25,
-	STEDMA40_DEV_SRC_SXA2_RX_TX = 26,
-	STEDMA40_DEV_SRC_SXA3_RX_TX = 27,
-	STEDMA40_DEV_SD_MM2_RX = 28,
-	STEDMA40_DEV_SD_MM0_RX = 29,
-	STEDMA40_DEV_MSP1_RX = 30,
-	/*
-	 * This channel is either SlimBus or MSP,
-	 * never both at the same time.
-	 */
-	STEDMA40_SLIM0_CH0_RX = 31,
-	STEDMA40_DEV_MSP0_RX = 31,
-	STEDMA40_DEV_SD_MM1_RX = 32,
-	STEDMA40_DEV_SPI2_RX = 33,
-	STEDMA40_DEV_I2C3_RX2 = 34,
-	STEDMA40_DEV_SPI1_RX = 35,
-	STEDMA40_DEV_USB_OTG_IEP_4_12 = 36,
-	STEDMA40_DEV_USB_OTG_IEP_5_13 = 37,
-	STEDMA40_DEV_USB_OTG_IEP_6_14 = 38,
-	STEDMA40_DEV_USB_OTG_IEP_7_15 = 39,
-	STEDMA40_DEV_SPI3_RX = 40,
-	STEDMA40_DEV_SD_MM3_RX = 41,
-	STEDMA40_DEV_SD_MM4_RX = 42,
-	STEDMA40_DEV_SD_MM5_RX = 43,
-	STEDMA40_DEV_SRC_SXA4_RX_TX = 44,
-	STEDMA40_DEV_SRC_SXA5_RX_TX = 45,
-	STEDMA40_DEV_SRC_SXA6_RX_TX = 46,
-	STEDMA40_DEV_SRC_SXA7_RX_TX = 47,
-	STEDMA40_DEV_CAC1_RX = 48,
-	/* RX channels 49 and 50 are unused */
-	STEDMA40_DEV_MSHC_RX = 51,
-	STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52,
-	STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53,
-	STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54,
-	STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55,
-	/* RX channels 56 thru 60 are unused */
-	STEDMA40_DEV_CAC0_RX = 61,
-	/* RX channels 62 and 63 are unused */
+	DB8500_DMA_DEV0_SPI0_RX = 0,
+	DB8500_DMA_DEV1_SD_MMC0_RX = 1,
+	DB8500_DMA_DEV2_SD_MMC1_RX = 2,
+	DB8500_DMA_DEV3_SD_MMC2_RX = 3,
+	DB8500_DMA_DEV4_I2C1_RX = 4,
+	DB8500_DMA_DEV5_I2C3_RX = 5,
+	DB8500_DMA_DEV6_I2C2_RX = 6,
+	DB8500_DMA_DEV7_I2C4_RX = 7, /* Only on V1 and later */
+	DB8500_DMA_DEV8_SSP0_RX = 8,
+	DB8500_DMA_DEV9_SSP1_RX = 9,
+	DB8500_DMA_DEV10_MCDE_RX = 10,
+	DB8500_DMA_DEV11_UART2_RX = 11,
+	DB8500_DMA_DEV12_UART1_RX = 12,
+	DB8500_DMA_DEV13_UART0_RX = 13,
+	DB8500_DMA_DEV14_MSP2_RX = 14,
+	DB8500_DMA_DEV15_I2C0_RX = 15,
+	DB8500_DMA_DEV16_USB_OTG_IEP_7_15 = 16,
+	DB8500_DMA_DEV17_USB_OTG_IEP_6_14 = 17,
+	DB8500_DMA_DEV18_USB_OTG_IEP_5_13 = 18,
+	DB8500_DMA_DEV19_USB_OTG_IEP_4_12 = 19,
+	DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
+	DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
+	DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
+	DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
+	DB8500_DMA_DEV24_SRC_SXA0_RX_TX = 24,
+	DB8500_DMA_DEV25_SRC_SXA1_RX_TX = 25,
+	DB8500_DMA_DEV26_SRC_SXA2_RX_TX = 26,
+	DB8500_DMA_DEV27_SRC_SXA3_RX_TX = 27,
+	DB8500_DMA_DEV28_SD_MM2_RX = 28,
+	DB8500_DMA_DEV29_SD_MM0_RX = 29,
+	DB8500_DMA_DEV30_MSP1_RX = 30,
+	/* On DB8500v2, MSP3 RX replaces MSP1 RX */
+	DB8500_DMA_DEV30_MSP3_RX = 30,
+	DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX = 31,
+	DB8500_DMA_DEV32_SD_MM1_RX = 32,
+	DB8500_DMA_DEV33_SPI2_RX = 33,
+	DB8500_DMA_DEV34_I2C3_RX2 = 34,
+	DB8500_DMA_DEV35_SPI1_RX = 35,
+	DB8500_DMA_DEV36_USB_OTG_IEP_3_11 = 36,
+	DB8500_DMA_DEV37_USB_OTG_IEP_2_10 = 37,
+	DB8500_DMA_DEV38_USB_OTG_IEP_1_9 = 38,
+	DB8500_DMA_DEV39_USB_OTG_IEP_8 = 39,
+	DB8500_DMA_DEV40_SPI3_RX = 40,
+	DB8500_DMA_DEV41_SD_MM3_RX = 41,
+	DB8500_DMA_DEV42_SD_MM4_RX = 42,
+	DB8500_DMA_DEV43_SD_MM5_RX = 43,
+	DB8500_DMA_DEV44_SRC_SXA4_RX_TX = 44,
+	DB8500_DMA_DEV45_SRC_SXA5_RX_TX = 45,
+	DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX = 46,
+	DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX = 47,
+	DB8500_DMA_DEV48_CAC1_RX = 48,
+	/* 49, 50 and 51 are not used */
+	DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4 = 52,
+	DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5 = 53,
+	DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6 = 54,
+	DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7 = 55,
+	/* 56, 57, 58, 59 and 60 are not used */
+	DB8500_DMA_DEV61_CAC0_RX = 61,
+	/* 62 and 63 are not used */
 };
 
 enum dma_dest_dev_type {
-	STEDMA40_DEV_SPI0_TX = 0,
-	STEDMA40_DEV_SD_MMC0_TX = 1,
-	STEDMA40_DEV_SD_MMC1_TX = 2,
-	STEDMA40_DEV_SD_MMC2_TX = 3,
-	STEDMA40_DEV_I2C1_TX = 4,
-	STEDMA40_DEV_I2C3_TX = 5,
-	STEDMA40_DEV_I2C2_TX = 6,
-	STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */
-	STEDMA40_DEV_SSP0_TX = 8,
-	STEDMA40_DEV_SSP1_TX = 9,
-	/* TX channel 10 is unused */
-	STEDMA40_DEV_UART2_TX = 11,
-	STEDMA40_DEV_UART1_TX = 12,
-	STEDMA40_DEV_UART0_TX= 13,
-	STEDMA40_DEV_MSP2_TX = 14,
-	STEDMA40_DEV_I2C0_TX = 15,
-	STEDMA40_DEV_USB_OTG_OEP_8 = 16,
-	STEDMA40_DEV_USB_OTG_OEP_1_9 = 17,
-	STEDMA40_DEV_USB_OTG_OEP_2_10= 18,
-	STEDMA40_DEV_USB_OTG_OEP_3_11 = 19,
-	STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
-	STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
-	STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
-	STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
-	STEDMA40_DEV_DST_SXA0_RX_TX = 24,
-	STEDMA40_DEV_DST_SXA1_RX_TX = 25,
-	STEDMA40_DEV_DST_SXA2_RX_TX = 26,
-	STEDMA40_DEV_DST_SXA3_RX_TX = 27,
-	STEDMA40_DEV_SD_MM2_TX = 28,
-	STEDMA40_DEV_SD_MM0_TX = 29,
-	STEDMA40_DEV_MSP1_TX = 30,
-	/*
-	 * This channel is either SlimBus or MSP,
-	 * never both at the same time.
-	 */
-	STEDMA40_SLIM0_CH0_TX = 31,
-	STEDMA40_DEV_MSP0_TX = 31,
-	STEDMA40_DEV_SD_MM1_TX = 32,
-	STEDMA40_DEV_SPI2_TX = 33,
-	/* Secondary I2C3 channel */
-	STEDMA40_DEV_I2C3_TX2 = 34,
-	STEDMA40_DEV_SPI1_TX = 35,
-	STEDMA40_DEV_USB_OTG_OEP_4_12 = 36,
-	STEDMA40_DEV_USB_OTG_OEP_5_13 = 37,
-	STEDMA40_DEV_USB_OTG_OEP_6_14 = 38,
-	STEDMA40_DEV_USB_OTG_OEP_7_15 = 39,
-	STEDMA40_DEV_SPI3_TX = 40,
-	STEDMA40_DEV_SD_MM3_TX = 41,
-	STEDMA40_DEV_SD_MM4_TX = 42,
-	STEDMA40_DEV_SD_MM5_TX = 43,
-	STEDMA40_DEV_DST_SXA4_RX_TX = 44,
-	STEDMA40_DEV_DST_SXA5_RX_TX = 45,
-	STEDMA40_DEV_DST_SXA6_RX_TX = 46,
-	STEDMA40_DEV_DST_SXA7_RX_TX = 47,
-	STEDMA40_DEV_CAC1_TX = 48,
-	STEDMA40_DEV_CAC1_TX_HAC1_TX = 49,
-	STEDMA40_DEV_HAC1_TX = 50,
-	STEDMA40_MEMCPY_TX_0 = 51,
-	STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52,
-	STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53,
-	STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54,
-	STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55,
-	STEDMA40_MEMCPY_TX_1 = 56,
-	STEDMA40_MEMCPY_TX_2 = 57,
-	STEDMA40_MEMCPY_TX_3 = 58,
-	STEDMA40_MEMCPY_TX_4 = 59,
-	STEDMA40_MEMCPY_TX_5 = 60,
-	STEDMA40_DEV_CAC0_TX = 61,
-	STEDMA40_DEV_CAC0_TX_HAC0_TX = 62,
-	STEDMA40_DEV_HAC0_TX = 63,
+	DB8500_DMA_DEV0_SPI0_TX = 0,
+	DB8500_DMA_DEV1_SD_MMC0_TX = 1,
+	DB8500_DMA_DEV2_SD_MMC1_TX = 2,
+	DB8500_DMA_DEV3_SD_MMC2_TX = 3,
+	DB8500_DMA_DEV4_I2C1_TX = 4,
+	DB8500_DMA_DEV5_I2C3_TX = 5,
+	DB8500_DMA_DEV6_I2C2_TX = 6,
+	DB8500_DMA_DEV7_I2C4_TX = 7, /* Only on V1 and later */
+	DB8500_DMA_DEV8_SSP0_TX = 8,
+	DB8500_DMA_DEV9_SSP1_TX = 9,
+	/* 10 is not used*/
+	DB8500_DMA_DEV11_UART2_TX = 11,
+	DB8500_DMA_DEV12_UART1_TX = 12,
+	DB8500_DMA_DEV13_UART0_TX = 13,
+	DB8500_DMA_DEV14_MSP2_TX = 14,
+	DB8500_DMA_DEV15_I2C0_TX = 15,
+	DB8500_DMA_DEV16_USB_OTG_OEP_7_15 = 16,
+	DB8500_DMA_DEV17_USB_OTG_OEP_6_14 = 17,
+	DB8500_DMA_DEV18_USB_OTG_OEP_5_13 = 18,
+	DB8500_DMA_DEV19_USB_OTG_OEP_4_12 = 19,
+	DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
+	DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
+	DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
+	DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
+	DB8500_DMA_DEV24_DST_SXA0_RX_TX = 24,
+	DB8500_DMA_DEV25_DST_SXA1_RX_TX = 25,
+	DB8500_DMA_DEV26_DST_SXA2_RX_TX = 26,
+	DB8500_DMA_DEV27_DST_SXA3_RX_TX = 27,
+	DB8500_DMA_DEV28_SD_MM2_TX = 28,
+	DB8500_DMA_DEV29_SD_MM0_TX = 29,
+	DB8500_DMA_DEV30_MSP1_TX = 30,
+	DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX = 31,
+	DB8500_DMA_DEV32_SD_MM1_TX = 32,
+	DB8500_DMA_DEV33_SPI2_TX = 33,
+	DB8500_DMA_DEV34_I2C3_TX2 = 34,
+	DB8500_DMA_DEV35_SPI1_TX = 35,
+	DB8500_DMA_DEV36_USB_OTG_OEP_3_11 = 36,
+	DB8500_DMA_DEV37_USB_OTG_OEP_2_10 = 37,
+	DB8500_DMA_DEV38_USB_OTG_OEP_1_9 = 38,
+	DB8500_DMA_DEV39_USB_OTG_OEP_8 = 39,
+	DB8500_DMA_DEV40_SPI3_TX = 40,
+	DB8500_DMA_DEV41_SD_MM3_TX = 41,
+	DB8500_DMA_DEV42_SD_MM4_TX = 42,
+	DB8500_DMA_DEV43_SD_MM5_TX = 43,
+	DB8500_DMA_DEV44_DST_SXA4_RX_TX = 44,
+	DB8500_DMA_DEV45_DST_SXA5_RX_TX = 45,
+	DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX = 46,
+	DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX = 47,
+	DB8500_DMA_DEV48_CAC1_TX  = 48,
+	DB8500_DMA_DEV49_CAC1_TX_HAC1_TX = 49,
+	DB8500_DMA_DEV50_HAC1_TX = 50,
+	DB8500_DMA_MEMCPY_TX_0 = 51,
+	DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4 = 52,
+	DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5 = 53,
+	DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6 = 54,
+	DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7 = 55,
+	DB8500_DMA_MEMCPY_TX_1 = 56,
+	DB8500_DMA_MEMCPY_TX_2 = 57,
+	DB8500_DMA_MEMCPY_TX_3 = 58,
+	DB8500_DMA_MEMCPY_TX_4 = 59,
+	DB8500_DMA_MEMCPY_TX_5 = 60,
+	DB8500_DMA_DEV61_CAC0_TX = 61,
+	DB8500_DMA_DEV62_CAC0_TX_HAC0_TX = 62,
+	DB8500_DMA_DEV63_HAC0_TX = 63,
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-versatile/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-versatile/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-versatile/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-versatile/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -11,13 +11,11 @@
  *
 */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx,      #0x10000000
-		movne	\rx,      #0xf1000000	@ virtual base
-		orr	\rx, \rx, #0x001F0000
-		orr	\rx, \rx, #0x00001000
+		.macro	addruart, rp, rv
+		mov	\rp,      #0x001F0000
+		orr	\rp, \rp, #0x00001000
+		orr	\rv, \rp, #0xf1000000	@ virtual base
+		orr	\rp, \rp,  #0x10000000	@ physical base
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-versatile/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/mach-versatile/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-versatile/include/mach/vmalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-versatile/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,4 +18,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END		(PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END		0xd8000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-versatile/versatile_ab.c linux-libre-2.6.37-gnu/arch/arm/mach-versatile/versatile_ab.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-versatile/versatile_ab.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-versatile/versatile_ab.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,8 +35,6 @@
 
 MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= 0x101f1000,
-	.io_pg_offst	= ((0xf11f1000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= versatile_map_io,
 	.init_irq	= versatile_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-versatile/versatile_pb.c linux-libre-2.6.37-gnu/arch/arm/mach-versatile/versatile_pb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-versatile/versatile_pb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-versatile/versatile_pb.c	2011-01-04 19:50:19.000000000 -0500
@@ -108,8 +108,6 @@
 
 MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
 	/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-	.phys_io	= 0x101f1000,
-	.io_pg_offst	= ((0xf11f1000) >> 18) & 0xfffc,
 	.boot_params	= 0x00000100,
 	.map_io		= versatile_map_io,
 	.init_irq	= versatile_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/ct-ca9x4.c linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/ct-ca9x4.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/ct-ca9x4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/ct-ca9x4.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,9 @@
 
 static void __init ct_ca9x4_map_io(void)
 {
+#ifdef CONFIG_LOCAL_TIMERS
 	twd_base = MMIO_P2V(A9_MPCORE_TWD);
+#endif
 	v2m_map_io(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
 }
 
@@ -245,8 +247,6 @@
 }
 
 MACHINE_START(VEXPRESS, "ARM-Versatile Express CA9x4")
-	.phys_io	= V2M_UART0 & SECTION_MASK,
-	.io_pg_offst	= (__MMIO_P2V(V2M_UART0) >> 18) & 0xfffc,
 	.boot_params	= PHYS_OFFSET + 0x00000100,
 	.map_io		= ct_ca9x4_map_io,
 	.init_irq	= ct_ca9x4_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/headsmp.S linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/headsmp.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/headsmp.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/headsmp.S	2011-01-04 19:50:19.000000000 -0500
@@ -35,5 +35,6 @@
 	 */
 	b	secondary_startup
 
+	.align
 1:	.long	.
 	.long	pen_release
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -12,12 +12,10 @@
 
 #define DEBUG_LL_UART_OFFSET	0x00009000
 
-		.macro	addruart,rx,tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx,      #0x10000000
-		movne	\rx,      #0xf8000000	@ virtual base
-		orr	\rx, \rx, #DEBUG_LL_UART_OFFSET
+		.macro	addruart,rp,rv
+		mov	\rp, #DEBUG_LL_UART_OFFSET
+		orr	\rv, \rp, #0xf8000000	@ virtual base
+		orr	\rp, \rp, #0x10000000	@ physical base
 		.endm
 
 #include <asm/hardware/debug-pl01x.S>
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/include/mach/smp.h linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/include/mach/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/mach-vexpress/include/mach/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-vexpress/include/mach/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,14 +2,7 @@
 #define __MACH_SMP_H
 
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()				\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x0F;				\
-	})
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc910evb.c linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc910evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc910evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc910evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,8 +34,6 @@
 
 MACHINE_START(W90P910EVB, "W90P910EVB")
 	/* Maintainer: Wan ZongShun */
-	.phys_io	= W90X900_PA_UART,
-	.io_pg_offst	= (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= 0,
 	.map_io		= nuc910evb_map_io,
 	.init_irq	= nuc900_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc950evb.c linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc950evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc950evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc950evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,8 +37,6 @@
 
 MACHINE_START(W90P950EVB, "W90P950EVB")
 	/* Maintainer: Wan ZongShun */
-	.phys_io	= W90X900_PA_UART,
-	.io_pg_offst	= (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= 0,
 	.map_io		= nuc950evb_map_io,
 	.init_irq	= nuc900_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc960evb.c linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc960evb.c
--- linux-libre-2.6.36-gnu/arch/arm/mach-w90x900/mach-nuc960evb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mach-w90x900/mach-nuc960evb.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,8 +34,6 @@
 
 MACHINE_START(W90N960EVB, "W90N960EVB")
 	/* Maintainer: Wan ZongShun */
-	.phys_io	= W90X900_PA_UART,
-	.io_pg_offst	= (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
 	.boot_params	= 0,
 	.map_io		= nuc960evb_map_io,
 	.init_irq	= nuc900_init_irq,
diff -druN linux-libre-2.6.36-gnu/arch/arm/Makefile linux-libre-2.6.37-gnu/arch/arm/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -173,7 +173,7 @@
 machine-$(CONFIG_ARCH_S3C2410)		:= s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443
 machine-$(CONFIG_ARCH_S3C24A0)		:= s3c24a0
 machine-$(CONFIG_ARCH_S3C64XX)		:= s3c64xx
-machine-$(CONFIG_ARCH_S5P6440)		:= s5p6440
+machine-$(CONFIG_ARCH_S5P64X0)		:= s5p64x0
 machine-$(CONFIG_ARCH_S5P6442)		:= s5p6442
 machine-$(CONFIG_ARCH_S5PC100)		:= s5pc100
 machine-$(CONFIG_ARCH_S5PV210)		:= s5pv210
@@ -183,6 +183,7 @@
 machine-$(CONFIG_ARCH_SHMOBILE) 	:= shmobile
 machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
 machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
+machine-$(CONFIG_ARCH_TCC8K)		:= tcc8k
 machine-$(CONFIG_ARCH_TEGRA)		:= tegra
 machine-$(CONFIG_ARCH_U300)		:= u300
 machine-$(CONFIG_ARCH_U8500)		:= ux500
@@ -202,6 +203,7 @@
 plat-$(CONFIG_ARCH_OMAP)	:= omap
 plat-$(CONFIG_ARCH_S3C64XX)	:= samsung
 plat-$(CONFIG_ARCH_STMP3XXX)	:= stmp3xxx
+plat-$(CONFIG_ARCH_TCC_926)	:= tcc
 plat-$(CONFIG_PLAT_IOP)		:= iop
 plat-$(CONFIG_PLAT_NOMADIK)	:= nomadik
 plat-$(CONFIG_PLAT_ORION)	:= orion
@@ -245,13 +247,14 @@
 FASTFPE_OBJ	:=$(FASTFPE)/
 endif
 
-# If we have a machine-specific directory, then include it in the build.
-core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
-core-y				+= $(machdirs) $(platdirs)
 core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
 core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
 core-$(CONFIG_VFP)		+= arch/arm/vfp/
 
+# If we have a machine-specific directory, then include it in the build.
+core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y				+= $(machdirs) $(platdirs)
+
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 
 libs-y				:= arch/arm/lib/ $(libs-y)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-fa.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-fa.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-fa.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-fa.S	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,17 @@
 #define CACHE_DLIMIT	(CACHE_DSIZE * 2)
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(fa_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(fa_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular address
@@ -233,6 +244,7 @@
 
 	.type	fa_cache_fns, #object
 ENTRY(fa_cache_fns)
+	.long	fa_flush_icache_all
 	.long	fa_flush_kern_cache_all
 	.long	fa_flush_user_cache_all
 	.long	fa_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-feroceon-l2.c linux-libre-2.6.37-gnu/arch/arm/mm/cache-feroceon-l2.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-feroceon-l2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-feroceon-l2.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,13 +13,9 @@
  */
 
 #include <linux/init.h>
+#include <linux/highmem.h>
 #include <asm/cacheflush.h>
-#include <asm/kmap_types.h>
-#include <asm/fixmap.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
 #include <plat/cache-feroceon-l2.h>
-#include "mm.h"
 
 /*
  * Low-level cache maintenance operations.
@@ -39,27 +35,30 @@
  * between which we don't want to be preempted.
  */
 
-static inline unsigned long l2_start_va(unsigned long paddr)
+static inline unsigned long l2_get_va(unsigned long paddr)
 {
 #ifdef CONFIG_HIGHMEM
 	/*
-	 * Let's do our own fixmap stuff in a minimal way here.
 	 * Because range ops can't be done on physical addresses,
 	 * we simply install a virtual mapping for it only for the
 	 * TLB lookup to occur, hence no need to flush the untouched
-	 * memory mapping.  This is protected with the disabling of
-	 * interrupts by the caller.
+	 * memory mapping afterwards (note: a cache flush may happen
+	 * in some circumstances depending on the path taken in kunmap_atomic).
 	 */
-	unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
-	unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-	set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
-	local_flush_tlb_kernel_page(vaddr);
-	return vaddr + (paddr & ~PAGE_MASK);
+	void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
+	return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
 #else
 	return __phys_to_virt(paddr);
 #endif
 }
 
+static inline void l2_put_va(unsigned long vaddr)
+{
+#ifdef CONFIG_HIGHMEM
+	kunmap_atomic((void *)vaddr);
+#endif
+}
+
 static inline void l2_clean_pa(unsigned long addr)
 {
 	__asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
@@ -76,13 +75,14 @@
 	 */
 	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
-	raw_local_irq_save(flags);
-	va_start = l2_start_va(start);
+	va_start = l2_get_va(start);
 	va_end = va_start + (end - start);
+	raw_local_irq_save(flags);
 	__asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
 		"mcr p15, 1, %1, c15, c9, 5"
 		: : "r" (va_start), "r" (va_end));
 	raw_local_irq_restore(flags);
+	l2_put_va(va_start);
 }
 
 static inline void l2_clean_inv_pa(unsigned long addr)
@@ -106,13 +106,14 @@
 	 */
 	BUG_ON((start ^ end) >> PAGE_SHIFT);
 
-	raw_local_irq_save(flags);
-	va_start = l2_start_va(start);
+	va_start = l2_get_va(start);
 	va_end = va_start + (end - start);
+	raw_local_irq_save(flags);
 	__asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
 		"mcr p15, 1, %1, c15, c11, 5"
 		: : "r" (va_start), "r" (va_end));
 	raw_local_irq_restore(flags);
+	l2_put_va(va_start);
 }
 
 static inline void l2_inv_all(void)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-l2x0.c linux-libre-2.6.37-gnu/arch/arm/mm/cache-l2x0.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-l2x0.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-l2x0.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,14 +28,24 @@
 static void __iomem *l2x0_base;
 static DEFINE_SPINLOCK(l2x0_lock);
 static uint32_t l2x0_way_mask;	/* Bitmask of active ways */
+static uint32_t l2x0_size;
 
-static inline void cache_wait(void __iomem *reg, unsigned long mask)
+static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
 {
-	/* wait for the operation to complete */
+	/* wait for cache operation by line or way to complete */
 	while (readl_relaxed(reg) & mask)
 		;
 }
 
+#ifdef CONFIG_CACHE_PL310
+static inline void cache_wait(void __iomem *reg, unsigned long mask)
+{
+	/* cache operations by line are atomic on PL310 */
+}
+#else
+#define cache_wait	cache_wait_way
+#endif
+
 static inline void cache_sync(void)
 {
 	void __iomem *base = l2x0_base;
@@ -103,14 +113,40 @@
 	spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
-static inline void l2x0_inv_all(void)
+static void l2x0_flush_all(void)
+{
+	unsigned long flags;
+
+	/* clean all ways */
+	spin_lock_irqsave(&l2x0_lock, flags);
+	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY);
+	cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask);
+	cache_sync();
+	spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static void l2x0_clean_all(void)
+{
+	unsigned long flags;
+
+	/* clean all ways */
+	spin_lock_irqsave(&l2x0_lock, flags);
+	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY);
+	cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask);
+	cache_sync();
+	spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
+static void l2x0_inv_all(void)
 {
 	unsigned long flags;
 
 	/* invalidate all ways */
 	spin_lock_irqsave(&l2x0_lock, flags);
+	/* Invalidating when L2 is enabled is a nono */
+	BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1);
 	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
-	cache_wait(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
+	cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
 	cache_sync();
 	spin_unlock_irqrestore(&l2x0_lock, flags);
 }
@@ -159,6 +195,11 @@
 	void __iomem *base = l2x0_base;
 	unsigned long flags;
 
+	if ((end - start) >= l2x0_size) {
+		l2x0_clean_all();
+		return;
+	}
+
 	spin_lock_irqsave(&l2x0_lock, flags);
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
@@ -184,6 +225,11 @@
 	void __iomem *base = l2x0_base;
 	unsigned long flags;
 
+	if ((end - start) >= l2x0_size) {
+		l2x0_flush_all();
+		return;
+	}
+
 	spin_lock_irqsave(&l2x0_lock, flags);
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
@@ -206,10 +252,20 @@
 	spin_unlock_irqrestore(&l2x0_lock, flags);
 }
 
+static void l2x0_disable(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&l2x0_lock, flags);
+	writel(0, l2x0_base + L2X0_CTRL);
+	spin_unlock_irqrestore(&l2x0_lock, flags);
+}
+
 void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
 {
 	__u32 aux;
 	__u32 cache_id;
+	__u32 way_size = 0;
 	int ways;
 	const char *type;
 
@@ -244,6 +300,13 @@
 	l2x0_way_mask = (1 << ways) - 1;
 
 	/*
+	 * L2 cache Size =  Way size * Number of ways
+	 */
+	way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
+	way_size = 1 << (way_size + 3);
+	l2x0_size = ways * way_size * SZ_1K;
+
+	/*
 	 * Check if l2x0 controller is already enabled.
 	 * If you are booting from non-secure mode
 	 * accessing the below registers will fault.
@@ -263,8 +326,11 @@
 	outer_cache.clean_range = l2x0_clean_range;
 	outer_cache.flush_range = l2x0_flush_range;
 	outer_cache.sync = l2x0_cache_sync;
+	outer_cache.flush_all = l2x0_flush_all;
+	outer_cache.inv_all = l2x0_inv_all;
+	outer_cache.disable = l2x0_disable;
 
 	printk(KERN_INFO "%s cache controller enabled\n", type);
-	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
-			 ways, cache_id, aux);
+	printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
+			ways, cache_id, aux, l2x0_size);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v3.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v3.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v3.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v3.S	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,15 @@
 #include "proc-macros.S"
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(v3_flush_icache_all)
+	mov	pc, lr
+ENDPROC(v3_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -122,6 +131,7 @@
 
 	.type	v3_cache_fns, #object
 ENTRY(v3_cache_fns)
+	.long	v3_flush_icache_all
 	.long	v3_flush_kern_cache_all
 	.long	v3_flush_user_cache_all
 	.long	v3_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4.S	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,15 @@
 #include "proc-macros.S"
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(v4_flush_icache_all)
+	mov	pc, lr
+ENDPROC(v4_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -134,6 +143,7 @@
 
 	.type	v4_cache_fns, #object
 ENTRY(v4_cache_fns)
+	.long	v4_flush_icache_all
 	.long	v4_flush_kern_cache_all
 	.long	v4_flush_user_cache_all
 	.long	v4_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4wb.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4wb.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4wb.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4wb.S	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,17 @@
 	.text
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(v4wb_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(v4wb_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular address
@@ -244,6 +255,7 @@
 
 	.type	v4wb_cache_fns, #object
 ENTRY(v4wb_cache_fns)
+	.long	v4wb_flush_icache_all
 	.long	v4wb_flush_kern_cache_all
 	.long	v4wb_flush_user_cache_all
 	.long	v4wb_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4wt.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4wt.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v4wt.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v4wt.S	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,17 @@
 #define CACHE_DLIMIT	16384
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(v4wt_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(v4wt_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -188,6 +199,7 @@
 
 	.type	v4wt_cache_fns, #object
 ENTRY(v4wt_cache_fns)
+	.long	v4wt_flush_icache_all
 	.long	v4wt_flush_kern_cache_all
 	.long	v4wt_flush_user_cache_all
 	.long	v4wt_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v6.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v6.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v6.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v6.S	2011-01-04 19:50:19.000000000 -0500
@@ -21,18 +21,22 @@
 #define D_CACHE_LINE_SIZE	32
 #define BTB_FLUSH_SIZE		8
 
-#ifdef CONFIG_ARM_ERRATA_411920
 /*
- * Invalidate the entire I cache (this code is a workaround for the ARM1136
- * erratum 411920 - Invalidate Instruction Cache operation can fail. This
- * erratum is present in 1136, 1156 and 1176. It does not affect the MPCore.
+ *	v6_flush_icache_all()
  *
- * Registers:
- *   r0 - set to 0
- *   r1 - corrupted
+ *	Flush the whole I-cache.
+ *
+ *	ARM1136 erratum 411920 - Invalidate Instruction Cache operation can fail.
+ *	This erratum is present in 1136, 1156 and 1176. It does not affect the
+ *	MPCore.
+ *
+ *	Registers:
+ *	r0 - set to 0
+ *	r1 - corrupted
  */
-ENTRY(v6_icache_inval_all)
+ENTRY(v6_flush_icache_all)
 	mov	r0, #0
+#ifdef CONFIG_ARM_ERRATA_411920
 	mrs	r1, cpsr
 	cpsid	ifa				@ disable interrupts
 	mcr	p15, 0, r0, c7, c5, 0		@ invalidate entire I-cache
@@ -43,8 +47,11 @@
 	.rept	11				@ ARM Ltd recommends at least
 	nop					@ 11 NOPs
 	.endr
-	mov	pc, lr
+#else
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I-cache
 #endif
+	mov	pc, lr
+ENDPROC(v6_flush_icache_all)
 
 /*
  *	v6_flush_cache_all()
@@ -60,7 +67,7 @@
 #ifndef CONFIG_ARM_ERRATA_411920
 	mcr	p15, 0, r0, c7, c5, 0		@ I+BTB cache invalidate
 #else
-	b	v6_icache_inval_all
+	b	v6_flush_icache_all
 #endif
 #else
 	mcr	p15, 0, r0, c7, c15, 0		@ Cache clean+invalidate
@@ -138,7 +145,7 @@
 #ifndef CONFIG_ARM_ERRATA_411920
 	mcr	p15, 0, r0, c7, c5, 0		@ I+BTB cache invalidate
 #else
-	b	v6_icache_inval_all
+	b	v6_flush_icache_all
 #endif
 #else
 	mcr	p15, 0, r0, c7, c5, 6		@ invalidate BTB
@@ -196,6 +203,10 @@
  *	- end     - virtual end address of region
  */
 v6_dma_inv_range:
+#ifdef CONFIG_DMA_CACHE_RWFO
+	ldrb	r2, [r0]			@ read for ownership
+	strb	r2, [r0]			@ write for ownership
+#endif
 	tst	r0, #D_CACHE_LINE_SIZE - 1
 	bic	r0, r0, #D_CACHE_LINE_SIZE - 1
 #ifdef HARVARD_CACHE
@@ -204,6 +215,10 @@
 	mcrne	p15, 0, r0, c7, c11, 1		@ clean unified line
 #endif
 	tst	r1, #D_CACHE_LINE_SIZE - 1
+#ifdef CONFIG_DMA_CACHE_RWFO
+	ldrneb	r2, [r1, #-1]			@ read for ownership
+	strneb	r2, [r1, #-1]			@ write for ownership
+#endif
 	bic	r1, r1, #D_CACHE_LINE_SIZE - 1
 #ifdef HARVARD_CACHE
 	mcrne	p15, 0, r1, c7, c14, 1		@ clean & invalidate D line
@@ -211,10 +226,6 @@
 	mcrne	p15, 0, r1, c7, c15, 1		@ clean & invalidate unified line
 #endif
 1:
-#ifdef CONFIG_DMA_CACHE_RWFO
-	ldr	r2, [r0]			@ read for ownership
-	str	r2, [r0]			@ write for ownership
-#endif
 #ifdef HARVARD_CACHE
 	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D line
 #else
@@ -222,6 +233,10 @@
 #endif
 	add	r0, r0, #D_CACHE_LINE_SIZE
 	cmp	r0, r1
+#ifdef CONFIG_DMA_CACHE_RWFO
+	ldrlo	r2, [r0]			@ read for ownership
+	strlo	r2, [r0]			@ write for ownership
+#endif
 	blo	1b
 	mov	r0, #0
 	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
@@ -256,12 +271,12 @@
  *	- end     - virtual end address of region
  */
 ENTRY(v6_dma_flush_range)
-	bic	r0, r0, #D_CACHE_LINE_SIZE - 1
-1:
 #ifdef CONFIG_DMA_CACHE_RWFO
-	ldr	r2, [r0]			@ read for ownership
-	str	r2, [r0]			@ write for ownership
+	ldrb	r2, [r0]		@ read for ownership
+	strb	r2, [r0]		@ write for ownership
 #endif
+	bic	r0, r0, #D_CACHE_LINE_SIZE - 1
+1:
 #ifdef HARVARD_CACHE
 	mcr	p15, 0, r0, c7, c14, 1		@ clean & invalidate D line
 #else
@@ -269,6 +284,10 @@
 #endif
 	add	r0, r0, #D_CACHE_LINE_SIZE
 	cmp	r0, r1
+#ifdef CONFIG_DMA_CACHE_RWFO
+	ldrlob	r2, [r0]			@ read for ownership
+	strlob	r2, [r0]			@ write for ownership
+#endif
 	blo	1b
 	mov	r0, #0
 	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
@@ -312,6 +331,7 @@
 
 	.type	v6_cache_fns, #object
 ENTRY(v6_cache_fns)
+	.long	v6_flush_icache_all
 	.long	v6_flush_kern_cache_all
 	.long	v6_flush_user_cache_all
 	.long	v6_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-v7.S linux-libre-2.6.37-gnu/arch/arm/mm/cache-v7.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-v7.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-v7.S	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,21 @@
 #include "proc-macros.S"
 
 /*
+ *	v7_flush_icache_all()
+ *
+ *	Flush the whole I-cache.
+ *
+ *	Registers:
+ *	r0 - set to 0
+ */
+ENTRY(v7_flush_icache_all)
+	mov	r0, #0
+	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)		@ invalidate I-cache inner shareable
+	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)		@ I+BTB cache invalidate
+	mov	pc, lr
+ENDPROC(v7_flush_icache_all)
+
+/*
  *	v7_flush_dcache_all()
  *
  *	Flush the whole D-cache.
@@ -91,11 +106,8 @@
  THUMB(	stmfd	sp!, {r4-r7, r9-r11, lr}	)
 	bl	v7_flush_dcache_all
 	mov	r0, #0
-#ifdef CONFIG_SMP
-	mcr	p15, 0, r0, c7, c1, 0		@ invalidate I-cache inner shareable
-#else
-	mcr	p15, 0, r0, c7, c5, 0		@ I+BTB cache invalidate
-#endif
+	ALT_SMP(mcr	p15, 0, r0, c7, c1, 0)	@ invalidate I-cache inner shareable
+	ALT_UP(mcr	p15, 0, r0, c7, c5, 0)	@ I+BTB cache invalidate
  ARM(	ldmfd	sp!, {r4-r5, r7, r9-r11, lr}	)
  THUMB(	ldmfd	sp!, {r4-r7, r9-r11, lr}	)
 	mov	pc, lr
@@ -161,21 +173,25 @@
  UNWIND(.fnstart		)
 	dcache_line_size r2, r3
 	sub	r3, r2, #1
-	bic	r0, r0, r3
+	bic	r12, r0, r3
 1:
- USER(	mcr	p15, 0, r0, c7, c11, 1	)	@ clean D line to the point of unification
+ USER(	mcr	p15, 0, r12, c7, c11, 1	)	@ clean D line to the point of unification
+	add	r12, r12, r2
+	cmp	r12, r1
+	blo	1b
 	dsb
- USER(	mcr	p15, 0, r0, c7, c5, 1	)	@ invalidate I line
-	add	r0, r0, r2
+	icache_line_size r2, r3
+	sub	r3, r2, #1
+	bic	r12, r0, r3
 2:
-	cmp	r0, r1
-	blo	1b
+ USER(	mcr	p15, 0, r12, c7, c5, 1	)	@ invalidate I line
+	add	r12, r12, r2
+	cmp	r12, r1
+	blo	2b
+3:
 	mov	r0, #0
-#ifdef CONFIG_SMP
-	mcr	p15, 0, r0, c7, c1, 6		@ invalidate BTB Inner Shareable
-#else
-	mcr	p15, 0, r0, c7, c5, 6		@ invalidate BTB
-#endif
+	ALT_SMP(mcr	p15, 0, r0, c7, c1, 6)	@ invalidate BTB Inner Shareable
+	ALT_UP(mcr	p15, 0, r0, c7, c5, 6)	@ invalidate BTB
 	dsb
 	isb
 	mov	pc, lr
@@ -185,10 +201,10 @@
  * isn't mapped, just try the next page.
  */
 9001:
-	mov	r0, r0, lsr #12
-	mov	r0, r0, lsl #12
-	add	r0, r0, #4096
-	b	2b
+	mov	r12, r12, lsr #12
+	mov	r12, r12, lsl #12
+	add	r12, r12, #4096
+	b	3b
  UNWIND(.fnend		)
 ENDPROC(v7_coherent_kern_range)
 ENDPROC(v7_coherent_user_range)
@@ -309,6 +325,7 @@
 
 	.type	v7_cache_fns, #object
 ENTRY(v7_cache_fns)
+	.long	v7_flush_icache_all
 	.long	v7_flush_kern_cache_all
 	.long	v7_flush_user_cache_all
 	.long	v7_flush_user_cache_range
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/cache-xsc3l2.c linux-libre-2.6.37-gnu/arch/arm/mm/cache-xsc3l2.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/cache-xsc3l2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/cache-xsc3l2.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,14 +17,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 #include <linux/init.h>
+#include <linux/highmem.h>
 #include <asm/system.h>
 #include <asm/cputype.h>
 #include <asm/cacheflush.h>
-#include <asm/kmap_types.h>
-#include <asm/fixmap.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include "mm.h"
 
 #define CR_L2	(1 << 26)
 
@@ -71,16 +67,15 @@
 	dsb();
 }
 
+static inline void l2_unmap_va(unsigned long va)
+{
 #ifdef CONFIG_HIGHMEM
-#define l2_map_save_flags(x)		raw_local_save_flags(x)
-#define l2_map_restore_flags(x)		raw_local_irq_restore(x)
-#else
-#define l2_map_save_flags(x)		((x) = 0)
-#define l2_map_restore_flags(x)		((void)(x))
+	if (va != -1)
+		kunmap_atomic((void *)va);
 #endif
+}
 
-static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
-				      unsigned long flags)
+static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
 {
 #ifdef CONFIG_HIGHMEM
 	unsigned long va = prev_va & PAGE_MASK;
@@ -89,17 +84,10 @@
 		/*
 		 * Switching to a new page.  Because cache ops are
 		 * using virtual addresses only, we must put a mapping
-		 * in place for it.  We also enable interrupts for a
-		 * short while and disable them again to protect this
-		 * mapping.
+		 * in place for it.
 		 */
-		unsigned long idx;
-		raw_local_irq_restore(flags);
-		idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
-		va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-		raw_local_irq_restore(flags | PSR_I_BIT);
-		set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
-		local_flush_tlb_kernel_page(va);
+		l2_unmap_va(prev_va);
+		va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
 	}
 	return va + (pa_offset >> (32 - PAGE_SHIFT));
 #else
@@ -109,7 +97,7 @@
 
 static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
 {
-	unsigned long vaddr, flags;
+	unsigned long vaddr;
 
 	if (start == 0 && end == -1ul) {
 		xsc3_l2_inv_all();
@@ -117,13 +105,12 @@
 	}
 
 	vaddr = -1;  /* to force the first mapping */
-	l2_map_save_flags(flags);
 
 	/*
 	 * Clean and invalidate partial first cache line.
 	 */
 	if (start & (CACHE_LINE_SIZE - 1)) {
-		vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
+		vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 		start = (start | (CACHE_LINE_SIZE - 1)) + 1;
@@ -133,7 +120,7 @@
 	 * Invalidate all full cache lines between 'start' and 'end'.
 	 */
 	while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
-		vaddr = l2_map_va(start, vaddr, flags);
+		vaddr = l2_map_va(start, vaddr);
 		xsc3_l2_inv_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
@@ -142,31 +129,30 @@
 	 * Clean and invalidate partial last cache line.
 	 */
 	if (start < end) {
-		vaddr = l2_map_va(start, vaddr, flags);
+		vaddr = l2_map_va(start, vaddr);
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 	}
 
-	l2_map_restore_flags(flags);
+	l2_unmap_va(vaddr);
 
 	dsb();
 }
 
 static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
 {
-	unsigned long vaddr, flags;
+	unsigned long vaddr;
 
 	vaddr = -1;  /* to force the first mapping */
-	l2_map_save_flags(flags);
 
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
-		vaddr = l2_map_va(start, vaddr, flags);
+		vaddr = l2_map_va(start, vaddr);
 		xsc3_l2_clean_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
 
-	l2_map_restore_flags(flags);
+	l2_unmap_va(vaddr);
 
 	dsb();
 }
@@ -193,7 +179,7 @@
 
 static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
 {
-	unsigned long vaddr, flags;
+	unsigned long vaddr;
 
 	if (start == 0 && end == -1ul) {
 		xsc3_l2_flush_all();
@@ -201,17 +187,16 @@
 	}
 
 	vaddr = -1;  /* to force the first mapping */
-	l2_map_save_flags(flags);
 
 	start &= ~(CACHE_LINE_SIZE - 1);
 	while (start < end) {
-		vaddr = l2_map_va(start, vaddr, flags);
+		vaddr = l2_map_va(start, vaddr);
 		xsc3_l2_clean_mva(vaddr);
 		xsc3_l2_inv_mva(vaddr);
 		start += CACHE_LINE_SIZE;
 	}
 
-	l2_map_restore_flags(flags);
+	l2_unmap_va(vaddr);
 
 	dsb();
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/copypage-v4mc.c linux-libre-2.6.37-gnu/arch/arm/mm/copypage-v4mc.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/copypage-v4mc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/copypage-v4mc.c	2011-01-04 19:50:19.000000000 -0500
@@ -73,7 +73,7 @@
 {
 	void *kto = kmap_atomic(to, KM_USER1);
 
-	if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+	if (!test_and_set_bit(PG_dcache_clean, &from->flags))
 		__flush_dcache_page(page_mapping(from), from);
 
 	spin_lock(&minicache_lock);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/copypage-v6.c linux-libre-2.6.37-gnu/arch/arm/mm/copypage-v6.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/copypage-v6.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/copypage-v6.c	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 	unsigned int offset = CACHE_COLOUR(vaddr);
 	unsigned long kfrom, kto;
 
-	if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+	if (!test_and_set_bit(PG_dcache_clean, &from->flags))
 		__flush_dcache_page(page_mapping(from), from);
 
 	/* FIXME: not highmem safe */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/copypage-xscale.c linux-libre-2.6.37-gnu/arch/arm/mm/copypage-xscale.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/copypage-xscale.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/copypage-xscale.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,7 +95,7 @@
 {
 	void *kto = kmap_atomic(to, KM_USER1);
 
-	if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+	if (!test_and_set_bit(PG_dcache_clean, &from->flags))
 		__flush_dcache_page(page_mapping(from), from);
 
 	spin_lock(&minicache_lock);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/dma-mapping.c linux-libre-2.6.37-gnu/arch/arm/mm/dma-mapping.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/dma-mapping.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/dma-mapping.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/highmem.h>
 
 #include <asm/memory.h>
 #include <asm/highmem.h>
@@ -198,7 +199,7 @@
 	 * fragmentation of the DMA space, and also prevents allocations
 	 * smaller than a section from crossing a section boundary.
 	 */
-	bit = fls(size - 1) + 1;
+	bit = fls(size - 1);
 	if (bit > SECTION_SHIFT)
 		bit = SECTION_SHIFT;
 	align = 1 << bit;
@@ -480,10 +481,10 @@
 				op(vaddr, len, dir);
 				kunmap_high(page);
 			} else if (cache_is_vipt()) {
-				pte_t saved_pte;
-				vaddr = kmap_high_l1_vipt(page, &saved_pte);
+				/* unmapped pages might still be cached */
+				vaddr = kmap_atomic(page);
 				op(vaddr + offset, len, dir);
-				kunmap_high_l1_vipt(page, saved_pte);
+				kunmap_atomic(vaddr);
 			}
 		} else {
 			vaddr = page_address(page) + offset;
@@ -523,6 +524,12 @@
 		outer_inv_range(paddr, paddr + size);
 
 	dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+
+	/*
+	 * Mark the D-cache clean for this page to avoid extra flushing.
+	 */
+	if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
+		set_bit(PG_dcache_clean, &page->flags);
 }
 EXPORT_SYMBOL(___dma_page_dev_to_cpu);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/fault-armv.c linux-libre-2.6.37-gnu/arch/arm/mm/fault-armv.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/fault-armv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/fault-armv.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 
 static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
+#if __LINUX_ARM_ARCH__ < 6
 /*
  * We take the easy way out of this problem - we make the
  * PTE uncacheable.  However, we leave the write buffer on.
@@ -65,6 +66,30 @@
 	return ret;
 }
 
+#if USE_SPLIT_PTLOCKS
+/*
+ * If we are using split PTE locks, then we need to take the page
+ * lock here.  Otherwise we are using shared mm->page_table_lock
+ * which is already locked, thus cannot take it.
+ */
+static inline void do_pte_lock(spinlock_t *ptl)
+{
+	/*
+	 * Use nested version here to indicate that we are already
+	 * holding one similar spinlock.
+	 */
+	spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
+}
+
+static inline void do_pte_unlock(spinlock_t *ptl)
+{
+	spin_unlock(ptl);
+}
+#else /* !USE_SPLIT_PTLOCKS */
+static inline void do_pte_lock(spinlock_t *ptl) {}
+static inline void do_pte_unlock(spinlock_t *ptl) {}
+#endif /* USE_SPLIT_PTLOCKS */
+
 static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
 	unsigned long pfn)
 {
@@ -88,13 +113,13 @@
 	 * open-code the spin-locking.
 	 */
 	ptl = pte_lockptr(vma->vm_mm, pmd);
-	pte = pte_offset_map_nested(pmd, address);
-	spin_lock(ptl);
+	pte = pte_offset_map(pmd, address);
+	do_pte_lock(ptl);
 
 	ret = do_adjust_pte(vma, address, pfn, pte);
 
-	spin_unlock(ptl);
-	pte_unmap_nested(pte);
+	do_pte_unlock(ptl);
+	pte_unmap(pte);
 
 	return ret;
 }
@@ -141,7 +166,7 @@
  * a page table, or changing an existing PTE.  Basically, there are two
  * things that we need to take care of:
  *
- *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *  1. If PG_dcache_clean is not set for the page, we need to ensure
  *     that any cache entries for the kernels virtual memory
  *     range are written back to the page.
  *  2. If we have multiple shared mappings of the same space in
@@ -168,10 +193,8 @@
 		return;
 
 	mapping = page_mapping(page);
-#ifndef CONFIG_SMP
-	if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+	if (!test_and_set_bit(PG_dcache_clean, &page->flags))
 		__flush_dcache_page(mapping, page);
-#endif
 	if (mapping) {
 		if (cache_is_vivt())
 			make_coherent(mapping, vma, addr, ptep, pfn);
@@ -179,6 +202,7 @@
 			__flush_icache_all();
 	}
 }
+#endif	/* __LINUX_ARM_ARCH__ < 6 */
 
 /*
  * Check whether the write buffer has physical address aliasing
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/fault.c linux-libre-2.6.37-gnu/arch/arm/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -581,6 +581,19 @@
 	{ do_bad,		SIGBUS,  0,		"unknown 31"			   },
 };
 
+void __init
+hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+		 int sig, int code, const char *name)
+{
+	if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
+		BUG();
+
+	ifsr_info[nr].fn   = fn;
+	ifsr_info[nr].sig  = sig;
+	ifsr_info[nr].code = code;
+	ifsr_info[nr].name = name;
+}
+
 asmlinkage void __exception
 do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 {
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/flush.c linux-libre-2.6.37-gnu/arch/arm/mm/flush.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/flush.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/flush.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
+#include <linux/highmem.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
@@ -17,6 +18,7 @@
 #include <asm/smp_plat.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
+#include <asm/smp_plat.h>
 
 #include "mm.h"
 
@@ -39,6 +41,18 @@
 	    : "cc");
 }
 
+static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
+{
+	unsigned long colour = CACHE_COLOUR(vaddr);
+	unsigned long offset = vaddr & (PAGE_SIZE - 1);
+	unsigned long to;
+
+	set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
+	to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
+	flush_tlb_kernel_page(to);
+	flush_icache_range(to, to + len);
+}
+
 void flush_cache_mm(struct mm_struct *mm)
 {
 	if (cache_is_vivt()) {
@@ -89,16 +103,16 @@
 	if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
 		__flush_icache_all();
 }
+
 #else
-#define flush_pfn_alias(pfn,vaddr)	do { } while (0)
+#define flush_pfn_alias(pfn,vaddr)		do { } while (0)
+#define flush_icache_alias(pfn,vaddr,len)	do { } while (0)
 #endif
 
-#ifdef CONFIG_SMP
 static void flush_ptrace_access_other(void *args)
 {
 	__flush_icache_all();
 }
-#endif
 
 static
 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
@@ -118,15 +132,16 @@
 		return;
 	}
 
-	/* VIPT non-aliasing cache */
+	/* VIPT non-aliasing D-cache */
 	if (vma->vm_flags & VM_EXEC) {
 		unsigned long addr = (unsigned long)kaddr;
-		__cpuc_coherent_kern_range(addr, addr + len);
-#ifdef CONFIG_SMP
+		if (icache_is_vipt_aliasing())
+			flush_icache_alias(page_to_pfn(page), uaddr, len);
+		else
+			__cpuc_coherent_kern_range(addr, addr + len);
 		if (cache_ops_need_broadcast())
 			smp_call_function(flush_ptrace_access_other,
 					  NULL, 1);
-#endif
 	}
 }
 
@@ -166,10 +181,10 @@
 			__cpuc_flush_dcache_area(addr, PAGE_SIZE);
 			kunmap_high(page);
 		} else if (cache_is_vipt()) {
-			pte_t saved_pte;
-			addr = kmap_high_l1_vipt(page, &saved_pte);
+			/* unmapped pages might still be cached */
+			addr = kmap_atomic(page);
 			__cpuc_flush_dcache_area(addr, PAGE_SIZE);
-			kunmap_high_l1_vipt(page, saved_pte);
+			kunmap_atomic(addr);
 		}
 	}
 
@@ -215,6 +230,36 @@
 	flush_dcache_mmap_unlock(mapping);
 }
 
+#if __LINUX_ARM_ARCH__ >= 6
+void __sync_icache_dcache(pte_t pteval)
+{
+	unsigned long pfn;
+	struct page *page;
+	struct address_space *mapping;
+
+	if (!pte_present_user(pteval))
+		return;
+	if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
+		/* only flush non-aliasing VIPT caches for exec mappings */
+		return;
+	pfn = pte_pfn(pteval);
+	if (!pfn_valid(pfn))
+		return;
+
+	page = pfn_to_page(pfn);
+	if (cache_is_vipt_aliasing())
+		mapping = page_mapping(page);
+	else
+		mapping = NULL;
+
+	if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+		__flush_dcache_page(mapping, page);
+	/* pte_exec() already checked above for non-aliasing VIPT cache */
+	if (cache_is_vipt_nonaliasing() || pte_exec(pteval))
+		__flush_icache_all();
+}
+#endif
+
 /*
  * Ensure cache coherency between kernel mapping and userspace mapping
  * of this page.
@@ -246,17 +291,16 @@
 
 	mapping = page_mapping(page);
 
-#ifndef CONFIG_SMP
-	if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
-		set_bit(PG_dcache_dirty, &page->flags);
-	else
-#endif
-	{
+	if (!cache_ops_need_broadcast() &&
+	    mapping && !mapping_mapped(mapping))
+		clear_bit(PG_dcache_clean, &page->flags);
+	else {
 		__flush_dcache_page(mapping, page);
 		if (mapping && cache_is_vivt())
 			__flush_dcache_aliases(mapping, page);
 		else if (mapping)
 			__flush_icache_all();
+		set_bit(PG_dcache_clean, &page->flags);
 	}
 }
 EXPORT_SYMBOL(flush_dcache_page);
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/highmem.c linux-libre-2.6.37-gnu/arch/arm/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,18 +36,17 @@
 }
 EXPORT_SYMBOL(kunmap);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
 	unsigned int idx;
 	unsigned long vaddr;
 	void *kmap;
+	int type;
 
 	pagefault_disable();
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic(type);
-
 #ifdef CONFIG_DEBUG_HIGHMEM
 	/*
 	 * There is no cache coherency issue when non VIVT, so force the
@@ -61,6 +60,8 @@
 	if (kmap)
 		return kmap;
 
+	type = kmap_atomic_idx_push();
+
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -80,14 +81,17 @@
 
 	return (void *)vaddr;
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
+	int idx, type;
 
 	if (kvaddr >= (void *)FIXADDR_START) {
+		type = kmap_atomic_idx();
+		idx = type + KM_TYPE_NR * smp_processor_id();
+
 		if (cache_is_vivt())
 			__cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -97,21 +101,23 @@
 #else
 		(void) idx;  /* to kill a warning */
 #endif
+		kmap_atomic_idx_pop();
 	} else if (vaddr >= PKMAP_ADDR(0) && vaddr < PKMAP_ADDR(LAST_PKMAP)) {
 		/* this address was obtained through kmap_high_get() */
 		kunmap_high(pte_page(pkmap_page_table[PKMAP_NR(vaddr)]));
 	}
 	pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-	unsigned int idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	pagefault_disable();
 
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -134,90 +140,3 @@
 	pte = TOP_PTE(vaddr);
 	return pte_page(*pte);
 }
-
-#ifdef CONFIG_CPU_CACHE_VIPT
-
-#include <linux/percpu.h>
-
-/*
- * The VIVT cache of a highmem page is always flushed before the page
- * is unmapped. Hence unmapped highmem pages need no cache maintenance
- * in that case.
- *
- * However unmapped pages may still be cached with a VIPT cache, and
- * it is not possible to perform cache maintenance on them using physical
- * addresses unfortunately.  So we have no choice but to set up a temporary
- * virtual mapping for that purpose.
- *
- * Yet this VIPT cache maintenance may be triggered from DMA support
- * functions which are possibly called from interrupt context. As we don't
- * want to keep interrupt disabled all the time when such maintenance is
- * taking place, we therefore allow for some reentrancy by preserving and
- * restoring the previous fixmap entry before the interrupted context is
- * resumed.  If the reentrancy depth is 0 then there is no need to restore
- * the previous fixmap, and leaving the current one in place allow it to
- * be reused the next time without a TLB flush (common with DMA).
- */
-
-static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
-
-void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
-{
-	unsigned int idx, cpu;
-	int *depth;
-	unsigned long vaddr, flags;
-	pte_t pte, *ptep;
-
-	if (!in_interrupt())
-		preempt_disable();
-
-	cpu = smp_processor_id();
-	depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
-
-	idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
-	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-	ptep = TOP_PTE(vaddr);
-	pte = mk_pte(page, kmap_prot);
-
-	raw_local_irq_save(flags);
-	(*depth)++;
-	if (pte_val(*ptep) == pte_val(pte)) {
-		*saved_pte = pte;
-	} else {
-		*saved_pte = *ptep;
-		set_pte_ext(ptep, pte, 0);
-		local_flush_tlb_kernel_page(vaddr);
-	}
-	raw_local_irq_restore(flags);
-
-	return (void *)vaddr;
-}
-
-void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte)
-{
-	unsigned int idx, cpu = smp_processor_id();
-	int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
-	unsigned long vaddr, flags;
-	pte_t pte, *ptep;
-
-	idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
-	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-	ptep = TOP_PTE(vaddr);
-	pte = mk_pte(page, kmap_prot);
-
-	BUG_ON(pte_val(*ptep) != pte_val(pte));
-	BUG_ON(*depth <= 0);
-
-	raw_local_irq_save(flags);
-	(*depth)--;
-	if (*depth != 0 && pte_val(pte) != pte_val(saved_pte)) {
-		set_pte_ext(ptep, saved_pte, 0);
-		local_flush_tlb_kernel_page(vaddr);
-	}
-	raw_local_irq_restore(flags);
-
-	if (!in_interrupt())
-		preempt_enable();
-}
-
-#endif  /* CONFIG_CPU_CACHE_VIPT */
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/init.c linux-libre-2.6.37-gnu/arch/arm/mm/init.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
+#include <linux/sort.h>
 
 #include <asm/mach-types.h>
 #include <asm/sections.h>
@@ -121,9 +122,10 @@
 	printk("%d pages swap cached\n", cached);
 }
 
-static void __init find_limits(struct meminfo *mi,
-	unsigned long *min, unsigned long *max_low, unsigned long *max_high)
+static void __init find_limits(unsigned long *min, unsigned long *max_low,
+	unsigned long *max_high)
 {
+	struct meminfo *mi = &meminfo;
 	int i;
 
 	*min = -1UL;
@@ -147,13 +149,13 @@
 	}
 }
 
-static void __init arm_bootmem_init(struct meminfo *mi,
-	unsigned long start_pfn, unsigned long end_pfn)
+static void __init arm_bootmem_init(unsigned long start_pfn,
+	unsigned long end_pfn)
 {
+	struct memblock_region *reg;
 	unsigned int boot_pages;
 	phys_addr_t bitmap;
 	pg_data_t *pgdat;
-	int i;
 
 	/*
 	 * Allocate the bootmem bitmap page.  This must be in a region
@@ -171,30 +173,39 @@
 	pgdat = NODE_DATA(0);
 	init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
 
-	for_each_bank(i, mi) {
-		struct membank *bank = &mi->bank[i];
-		if (!bank->highmem)
-			free_bootmem(bank_phys_start(bank), bank_phys_size(bank));
+	/* Free the lowmem regions from memblock into bootmem. */
+	for_each_memblock(memory, reg) {
+		unsigned long start = memblock_region_memory_base_pfn(reg);
+		unsigned long end = memblock_region_memory_end_pfn(reg);
+
+		if (end >= end_pfn)
+			end = end_pfn;
+		if (start >= end)
+			break;
+
+		free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT);
 	}
 
-	/*
-	 * Reserve the memblock reserved regions in bootmem.
-	 */
-	for (i = 0; i < memblock.reserved.cnt; i++) {
-		phys_addr_t start = memblock_start_pfn(&memblock.reserved, i);
-		if (start >= start_pfn &&
-		    memblock_end_pfn(&memblock.reserved, i) <= end_pfn)
-			reserve_bootmem_node(pgdat, __pfn_to_phys(start),
-				memblock_size_bytes(&memblock.reserved, i),
-				BOOTMEM_DEFAULT);
+	/* Reserve the lowmem memblock reserved regions in bootmem. */
+	for_each_memblock(reserved, reg) {
+		unsigned long start = memblock_region_reserved_base_pfn(reg);
+		unsigned long end = memblock_region_reserved_end_pfn(reg);
+
+		if (end >= end_pfn)
+			end = end_pfn;
+		if (start >= end)
+			break;
+
+		reserve_bootmem(__pfn_to_phys(start),
+			        (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT);
 	}
 }
 
-static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min,
-	unsigned long max_low, unsigned long max_high)
+static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
+	unsigned long max_high)
 {
 	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
-	int i;
+	struct memblock_region *reg;
 
 	/*
 	 * initialise the zones.
@@ -216,13 +227,20 @@
 	 *  holes = node_size - sum(bank_sizes)
 	 */
 	memcpy(zhole_size, zone_size, sizeof(zhole_size));
-	for_each_bank(i, mi) {
-		int idx = 0;
+	for_each_memblock(memory, reg) {
+		unsigned long start = memblock_region_memory_base_pfn(reg);
+		unsigned long end = memblock_region_memory_end_pfn(reg);
+
+		if (start < max_low) {
+			unsigned long low_end = min(end, max_low);
+			zhole_size[0] -= low_end - start;
+		}
 #ifdef CONFIG_HIGHMEM
-		if (mi->bank[i].highmem)
-			idx = ZONE_HIGHMEM;
+		if (end > max_low) {
+			unsigned long high_start = max(start, max_low);
+			zhole_size[ZONE_HIGHMEM] -= end - high_start;
+		}
 #endif
-		zhole_size[idx] -= bank_pfn_size(&mi->bank[i]);
 	}
 
 	/*
@@ -237,20 +255,7 @@
 #ifndef CONFIG_SPARSEMEM
 int pfn_valid(unsigned long pfn)
 {
-	struct memblock_region *mem = &memblock.memory;
-	unsigned int left = 0, right = mem->cnt;
-
-	do {
-		unsigned int mid = (right + left) / 2;
-
-		if (pfn < memblock_start_pfn(mem, mid))
-			right = mid;
-		else if (pfn >= memblock_end_pfn(mem, mid))
-			left = mid + 1;
-		else
-			return 1;
-	} while (left < right);
-	return 0;
+	return memblock_is_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
 
@@ -260,24 +265,34 @@
 #else
 static void arm_memory_present(void)
 {
-	int i;
-	for (i = 0; i < memblock.memory.cnt; i++)
-		memory_present(0, memblock_start_pfn(&memblock.memory, i),
-				  memblock_end_pfn(&memblock.memory, i));
+	struct memblock_region *reg;
+
+	for_each_memblock(memory, reg)
+		memory_present(0, memblock_region_memory_base_pfn(reg),
+			       memblock_region_memory_end_pfn(reg));
 }
 #endif
 
+static int __init meminfo_cmp(const void *_a, const void *_b)
+{
+	const struct membank *a = _a, *b = _b;
+	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
+	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
 void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 {
 	int i;
 
+	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
+
 	memblock_init();
 	for (i = 0; i < mi->nr_banks; i++)
 		memblock_add(mi->bank[i].start, mi->bank[i].size);
 
 	/* Register the kernel text, kernel data and initrd with memblock. */
 #ifdef CONFIG_XIP_KERNEL
-	memblock_reserve(__pa(_data), _end - _data);
+	memblock_reserve(__pa(_sdata), _end - _sdata);
 #else
 	memblock_reserve(__pa(_stext), _end - _stext);
 #endif
@@ -303,14 +318,13 @@
 
 void __init bootmem_init(void)
 {
-	struct meminfo *mi = &meminfo;
 	unsigned long min, max_low, max_high;
 
 	max_low = max_high = 0;
 
-	find_limits(mi, &min, &max_low, &max_high);
+	find_limits(&min, &max_low, &max_high);
 
-	arm_bootmem_init(mi, min, max_low);
+	arm_bootmem_init(min, max_low);
 
 	/*
 	 * Sparsemem tries to allocate bootmem in memory_present(),
@@ -328,7 +342,7 @@
 	 * the sparse mem_map arrays initialized by sparse_init()
 	 * for memmap_init_zone(), otherwise all PFNs are invalid.
 	 */
-	arm_bootmem_free(mi, min, max_low, max_high);
+	arm_bootmem_free(min, max_low, max_high);
 
 	high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
 
@@ -422,6 +436,56 @@
 	}
 }
 
+static void __init free_highpages(void)
+{
+#ifdef CONFIG_HIGHMEM
+	unsigned long max_low = max_low_pfn + PHYS_PFN_OFFSET;
+	struct memblock_region *mem, *res;
+
+	/* set highmem page free */
+	for_each_memblock(memory, mem) {
+		unsigned long start = memblock_region_memory_base_pfn(mem);
+		unsigned long end = memblock_region_memory_end_pfn(mem);
+
+		/* Ignore complete lowmem entries */
+		if (end <= max_low)
+			continue;
+
+		/* Truncate partial highmem entries */
+		if (start < max_low)
+			start = max_low;
+
+		/* Find and exclude any reserved regions */
+		for_each_memblock(reserved, res) {
+			unsigned long res_start, res_end;
+
+			res_start = memblock_region_reserved_base_pfn(res);
+			res_end = memblock_region_reserved_end_pfn(res);
+
+			if (res_end < start)
+				continue;
+			if (res_start < start)
+				res_start = start;
+			if (res_start > end)
+				res_start = end;
+			if (res_end > end)
+				res_end = end;
+			if (res_start != start)
+				totalhigh_pages += free_area(start, res_start,
+							     NULL);
+			start = res_end;
+			if (start == end)
+				break;
+		}
+
+		/* And now free anything which remains */
+		if (start < end)
+			totalhigh_pages += free_area(start, end, NULL);
+	}
+	totalram_pages += totalhigh_pages;
+#endif
+}
+
 /*
  * mem_init() marks the free areas in the mem_map and tells us how much
  * memory is free.  This is done after various parts of the system have
@@ -430,6 +494,7 @@
 void __init mem_init(void)
 {
 	unsigned long reserved_pages, free_pages;
+	struct memblock_region *reg;
 	int i;
 #ifdef CONFIG_HAVE_TCM
 	/* These pointers are filled in on TCM detection */
@@ -450,16 +515,7 @@
 				    __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
 #endif
 
-#ifdef CONFIG_HIGHMEM
-	/* set highmem page free */
-	for_each_bank (i, &meminfo) {
-		unsigned long start = bank_pfn_start(&meminfo.bank[i]);
-		unsigned long end = bank_pfn_end(&meminfo.bank[i]);
-		if (start >= max_low_pfn + PHYS_PFN_OFFSET)
-			totalhigh_pages += free_area(start, end, NULL);
-	}
-	totalram_pages += totalhigh_pages;
-#endif
+	free_highpages();
 
 	reserved_pages = free_pages = 0;
 
@@ -489,9 +545,11 @@
 	 */
 	printk(KERN_INFO "Memory:");
 	num_physpages = 0;
-	for (i = 0; i < meminfo.nr_banks; i++) {
-		num_physpages += bank_pfn_size(&meminfo.bank[i]);
-		printk(" %ldMB", bank_phys_size(&meminfo.bank[i]) >> 20);
+	for_each_memblock(memory, reg) {
+		unsigned long pages = memblock_region_memory_end_pfn(reg) -
+			memblock_region_memory_base_pfn(reg);
+		num_physpages += pages;
+		printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
 	}
 	printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
 
@@ -545,7 +603,7 @@
 
 			MLK_ROUNDUP(__init_begin, __init_end),
 			MLK_ROUNDUP(_text, _etext),
-			MLK_ROUNDUP(_data, _edata));
+			MLK_ROUNDUP(_sdata, _edata));
 
 #undef MLK
 #undef MLM
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/ioremap.c linux-libre-2.6.37-gnu/arch/arm/mm/ioremap.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/ioremap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/ioremap.c	2011-01-04 19:50:19.000000000 -0500
@@ -206,8 +206,8 @@
 	 */
 	if (pfn_valid(pfn)) {
 		printk(KERN_WARNING "BUG: Your driver calls ioremap() on system memory.  This leads\n"
-		       KERN_WARNING "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
-		       KERN_WARNING "will fail in the next kernel release.  Please fix your driver.\n");
+		       "to architecturally unpredictable behaviour on ARMv6+, and ioremap()\n"
+		       "will fail in the next kernel release.  Please fix your driver.\n");
 		WARN_ON(1);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/Kconfig linux-libre-2.6.37-gnu/arch/arm/mm/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/mm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -779,6 +779,14 @@
 	help
 	  This option enables the L2x0 PrimeCell.
 
+config CACHE_PL310
+	bool
+	depends on CACHE_L2X0
+	default y if CPU_V7 && !CPU_V6
+	help
+	  This option enables optimisations for the PL310 cache
+	  controller.
+
 config CACHE_TAUROS2
 	bool "Enable the Tauros2 L2 cache controller"
 	depends on (ARCH_DOVE || ARCH_MMP)
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/mmap.c linux-libre-2.6.37-gnu/arch/arm/mm/mmap.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/mmap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/mmap.c	2011-01-04 19:50:19.000000000 -0500
@@ -144,3 +144,25 @@
 {
 	return !(pfn + (size >> PAGE_SHIFT) > 0x00100000);
 }
+
+#ifdef CONFIG_STRICT_DEVMEM
+
+#include <linux/ioport.h>
+
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain
+ * address is valid. The argument is a physical page number.
+ * We mimic x86 here by disallowing access to system RAM as well as
+ * device-exclusive MMIO regions. This effectively disable read()/write()
+ * on /dev/mem.
+ */
+int devmem_is_allowed(unsigned long pfn)
+{
+	if (iomem_is_exclusive(pfn << PAGE_SHIFT))
+		return 0;
+	if (!page_is_ram(pfn))
+		return 1;
+	return 0;
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/mmu.c linux-libre-2.6.37-gnu/arch/arm/mm/mmu.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,6 @@
 #include <linux/mman.h>
 #include <linux/nodemask.h>
 #include <linux/memblock.h>
-#include <linux/sort.h>
 #include <linux/fs.h>
 
 #include <asm/cputype.h>
@@ -265,17 +264,17 @@
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_DTCM] = {
-		.prot_pte	= L_PTE_PRESENT | L_PTE_YOUNG |
-		                  L_PTE_DIRTY | L_PTE_WRITE,
-		.prot_l1	= PMD_TYPE_TABLE,
-		.prot_sect	= PMD_TYPE_SECT | PMD_SECT_XN,
-		.domain		= DOMAIN_KERNEL,
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_WRITE,
+		.prot_l1   = PMD_TYPE_TABLE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
+		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_ITCM] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_USER | L_PTE_EXEC,
+				L_PTE_WRITE | L_PTE_EXEC,
 		.prot_l1   = PMD_TYPE_TABLE,
-		.domain    = DOMAIN_IO,
+		.domain    = DOMAIN_KERNEL,
 	},
 };
 
@@ -310,9 +309,8 @@
 			cachepolicy = CPOLICY_WRITEBACK;
 		ecc_mask = 0;
 	}
-#ifdef CONFIG_SMP
-	cachepolicy = CPOLICY_WRITEALLOC;
-#endif
+	if (is_smp())
+		cachepolicy = CPOLICY_WRITEALLOC;
 
 	/*
 	 * Strip out features not present on earlier architectures.
@@ -406,13 +404,11 @@
 	cp = &cache_policies[cachepolicy];
 	vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
 
-#ifndef CONFIG_SMP
 	/*
 	 * Only use write-through for non-SMP systems
 	 */
-	if (cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
+	if (!is_smp() && cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
 		vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte;
-#endif
 
 	/*
 	 * Enable CPU-specific coherency if supported.
@@ -436,22 +432,23 @@
 		mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 		mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 
-#ifdef CONFIG_SMP
-		/*
-		 * Mark memory with the "shared" attribute for SMP systems
-		 */
-		user_pgprot |= L_PTE_SHARED;
-		kern_pgprot |= L_PTE_SHARED;
-		vecs_pgprot |= L_PTE_SHARED;
-		mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S;
-		mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED;
-		mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
-		mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED;
-		mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
-		mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
-		mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
-		mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
-#endif
+		if (is_smp()) {
+			/*
+			 * Mark memory with the "shared" attribute
+			 * for SMP systems
+			 */
+			user_pgprot |= L_PTE_SHARED;
+			kern_pgprot |= L_PTE_SHARED;
+			vecs_pgprot |= L_PTE_SHARED;
+			mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S;
+			mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED;
+			mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
+			mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED;
+			mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
+			mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
+			mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
+		}
 	}
 
 	/*
@@ -747,13 +744,14 @@
 }
 early_param("vmalloc", early_vmalloc);
 
-phys_addr_t lowmem_end_addr;
+static phys_addr_t lowmem_limit __initdata = 0;
 
 static void __init sanity_check_meminfo(void)
 {
 	int i, j, highmem = 0;
 
-	lowmem_end_addr = __pa(vmalloc_min - 1) + 1;
+	lowmem_limit = __pa(vmalloc_min - 1) + 1;
+	memblock_set_current_limit(lowmem_limit);
 
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
@@ -829,8 +827,7 @@
 			 * rather difficult.
 			 */
 			reason = "with VIPT aliasing cache";
-#ifdef CONFIG_SMP
-		} else if (tlb_ops_need_broadcast()) {
+		} else if (is_smp() && tlb_ops_need_broadcast()) {
 			/*
 			 * kmap_high needs to occasionally flush TLB entries,
 			 * however, if the TLB entries need to be broadcast
@@ -840,7 +837,6 @@
 			 *   (must not be called with irqs off)
 			 */
 			reason = "without hardware TLB ops broadcasting";
-#endif
 		}
 		if (reason) {
 			printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n",
@@ -856,6 +852,7 @@
 static inline void prepare_page_table(void)
 {
 	unsigned long addr;
+	phys_addr_t end;
 
 	/*
 	 * Clear out all the mappings below the kernel image.
@@ -871,10 +868,17 @@
 		pmd_clear(pmd_off_k(addr));
 
 	/*
+	 * Find the end of the first block of lowmem.
+	 */
+	end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
+	if (end >= lowmem_limit)
+		end = lowmem_limit;
+
+	/*
 	 * Clear out all the kernel space mappings, except for the first
 	 * memory bank, up to the end of the vmalloc region.
 	 */
-	for (addr = __phys_to_virt(bank_phys_end(&meminfo.bank[0]));
+	for (addr = __phys_to_virt(end);
 	     addr < VMALLOC_END; addr += PGDIR_SIZE)
 		pmd_clear(pmd_off_k(addr));
 }
@@ -991,37 +995,28 @@
 #endif
 }
 
-static inline void map_memory_bank(struct membank *bank)
-{
-	struct map_desc map;
-
-	map.pfn = bank_pfn_start(bank);
-	map.virtual = __phys_to_virt(bank_phys_start(bank));
-	map.length = bank_phys_size(bank);
-	map.type = MT_MEMORY;
-
-	create_mapping(&map);
-}
-
 static void __init map_lowmem(void)
 {
-	struct meminfo *mi = &meminfo;
-	int i;
+	struct memblock_region *reg;
 
 	/* Map all the lowmem memory banks. */
-	for (i = 0; i < mi->nr_banks; i++) {
-		struct membank *bank = &mi->bank[i];
+	for_each_memblock(memory, reg) {
+		phys_addr_t start = reg->base;
+		phys_addr_t end = start + reg->size;
+		struct map_desc map;
 
-		if (!bank->highmem)
-			map_memory_bank(bank);
-	}
-}
+		if (end > lowmem_limit)
+			end = lowmem_limit;
+		if (start >= end)
+			break;
 
-static int __init meminfo_cmp(const void *_a, const void *_b)
-{
-	const struct membank *a = _a, *b = _b;
-	long cmp = bank_pfn_start(a) - bank_pfn_start(b);
-	return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+		map.pfn = __phys_to_pfn(start);
+		map.virtual = __phys_to_virt(start);
+		map.length = end - start;
+		map.type = MT_MEMORY;
+
+		create_mapping(&map);
+	}
 }
 
 /*
@@ -1032,8 +1027,6 @@
 {
 	void *zero_page;
 
-	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
-
 	build_mem_type_table();
 	sanity_check_meminfo();
 	prepare_page_table();
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/pgd.c linux-libre-2.6.37-gnu/arch/arm/mm/pgd.c
--- linux-libre-2.6.36-gnu/arch/arm/mm/pgd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/pgd.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,9 +57,9 @@
 			goto no_pte;
 
 		init_pmd = pmd_offset(init_pgd, 0);
-		init_pte = pte_offset_map_nested(init_pmd, 0);
+		init_pte = pte_offset_map(init_pmd, 0);
 		set_pte_ext(new_pte, *init_pte, 0);
-		pte_unmap_nested(init_pte);
+		pte_unmap(init_pte);
 		pte_unmap(new_pte);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1020e.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1020e.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1020e.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1020e.S	2011-01-04 19:50:19.000000000 -0500
@@ -119,6 +119,20 @@
 /* ================================= CACHE ================================ */
 
 	.align	5
+
+/*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm1020e_flush_icache_all)
+#ifndef CONFIG_CPU_ICACHE_DISABLE
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+#endif
+	mov	pc, lr
+ENDPROC(arm1020e_flush_icache_all)
+
 /*
  *	flush_user_cache_all()
  *
@@ -337,6 +351,7 @@
 ENDPROC(arm1020e_dma_unmap_area)
 
 ENTRY(arm1020e_cache_fns)
+	.long	arm1020e_flush_icache_all
 	.long	arm1020e_flush_kern_cache_all
 	.long	arm1020e_flush_user_cache_all
 	.long	arm1020e_flush_user_cache_range
@@ -412,7 +427,7 @@
 #endif /* CONFIG_MMU */
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm1020e_setup, #function
 __arm1020e_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1020.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1020.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1020.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1020.S	2011-01-04 19:50:19.000000000 -0500
@@ -119,6 +119,20 @@
 /* ================================= CACHE ================================ */
 
 	.align	5
+
+/*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm1020_flush_icache_all)
+#ifndef CONFIG_CPU_ICACHE_DISABLE
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+#endif
+	mov	pc, lr
+ENDPROC(arm1020_flush_icache_all)
+
 /*
  *	flush_user_cache_all()
  *
@@ -351,6 +365,7 @@
 ENDPROC(arm1020_dma_unmap_area)
 
 ENTRY(arm1020_cache_fns)
+	.long	arm1020_flush_icache_all
 	.long	arm1020_flush_kern_cache_all
 	.long	arm1020_flush_user_cache_all
 	.long	arm1020_flush_user_cache_range
@@ -430,7 +445,7 @@
 #endif /* CONFIG_MMU */
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm1020_setup, #function
 __arm1020_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1022.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1022.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1022.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1022.S	2011-01-04 19:50:19.000000000 -0500
@@ -108,6 +108,20 @@
 /* ================================= CACHE ================================ */
 
 	.align	5
+
+/*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm1022_flush_icache_all)
+#ifndef CONFIG_CPU_ICACHE_DISABLE
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+#endif
+	mov	pc, lr
+ENDPROC(arm1022_flush_icache_all)
+
 /*
  *	flush_user_cache_all()
  *
@@ -326,6 +340,7 @@
 ENDPROC(arm1022_dma_unmap_area)
 
 ENTRY(arm1022_cache_fns)
+	.long	arm1022_flush_icache_all
 	.long	arm1022_flush_kern_cache_all
 	.long	arm1022_flush_user_cache_all
 	.long	arm1022_flush_user_cache_range
@@ -394,7 +409,7 @@
 #endif /* CONFIG_MMU */
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm1022_setup, #function
 __arm1022_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1026.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1026.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm1026.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm1026.S	2011-01-04 19:50:19.000000000 -0500
@@ -108,6 +108,20 @@
 /* ================================= CACHE ================================ */
 
 	.align	5
+
+/*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm1026_flush_icache_all)
+#ifndef CONFIG_CPU_ICACHE_DISABLE
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+#endif
+	mov	pc, lr
+ENDPROC(arm1026_flush_icache_all)
+
 /*
  *	flush_user_cache_all()
  *
@@ -320,6 +334,7 @@
 ENDPROC(arm1026_dma_unmap_area)
 
 ENTRY(arm1026_cache_fns)
+	.long	arm1026_flush_icache_all
 	.long	arm1026_flush_kern_cache_all
 	.long	arm1026_flush_user_cache_all
 	.long	arm1026_flush_user_cache_range
@@ -384,7 +399,7 @@
 	mov	pc, lr
 
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm1026_setup, #function
 __arm1026_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm6_7.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm6_7.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm6_7.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm6_7.S	2011-01-04 19:50:19.000000000 -0500
@@ -238,7 +238,7 @@
 		mcr	p15, 0, r1, c1, c0, 0		@ turn off MMU etc
 		mov	pc, r0
 
-		__INIT
+		__CPUINIT
 
 		.type	__arm6_setup, #function
 __arm6_setup:	mov	r0, #0
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm720.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm720.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm720.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm720.S	2011-01-04 19:50:19.000000000 -0500
@@ -113,7 +113,7 @@
 		mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
 		mov	pc, r0
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm710_setup, #function
 __arm710_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm740.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm740.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm740.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm740.S	2011-01-04 19:50:19.000000000 -0500
@@ -55,7 +55,7 @@
 	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
 	mov	pc, r0
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm740_setup, #function
 __arm740_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm7tdmi.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm7tdmi.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm7tdmi.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm7tdmi.S	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 ENTRY(cpu_arm7tdmi_reset)
 		mov	pc, r0
 
-		__INIT
+		__CPUINIT
 
 		.type	__arm7tdmi_setup, #function
 __arm7tdmi_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm920.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm920.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm920.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm920.S	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,17 @@
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm920_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm920_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -305,6 +316,7 @@
 ENDPROC(arm920_dma_unmap_area)
 
 ENTRY(arm920_cache_fns)
+	.long	arm920_flush_icache_all
 	.long	arm920_flush_kern_cache_all
 	.long	arm920_flush_user_cache_all
 	.long	arm920_flush_user_cache_range
@@ -375,7 +387,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm920_setup, #function
 __arm920_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm922.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm922.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm922.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm922.S	2011-01-04 19:50:19.000000000 -0500
@@ -112,6 +112,17 @@
 #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm922_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm922_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular
@@ -307,6 +318,7 @@
 ENDPROC(arm922_dma_unmap_area)
 
 ENTRY(arm922_cache_fns)
+	.long	arm922_flush_icache_all
 	.long	arm922_flush_kern_cache_all
 	.long	arm922_flush_user_cache_all
 	.long	arm922_flush_user_cache_range
@@ -379,7 +391,7 @@
 #endif /* CONFIG_MMU */
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm922_setup, #function
 __arm922_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm925.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm925.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm925.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm925.S	2011-01-04 19:50:19.000000000 -0500
@@ -145,6 +145,17 @@
 	mov	pc, lr
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm925_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm925_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular
@@ -362,6 +373,7 @@
 ENDPROC(arm925_dma_unmap_area)
 
 ENTRY(arm925_cache_fns)
+	.long	arm925_flush_icache_all
 	.long	arm925_flush_kern_cache_all
 	.long	arm925_flush_user_cache_all
 	.long	arm925_flush_user_cache_range
@@ -428,7 +440,7 @@
 #endif /* CONFIG_MMU */
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm925_setup, #function
 __arm925_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm926.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm926.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm926.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm926.S	2011-01-04 19:50:19.000000000 -0500
@@ -111,6 +111,17 @@
 	mov	pc, lr
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm926_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm926_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular
@@ -325,6 +336,7 @@
 ENDPROC(arm926_dma_unmap_area)
 
 ENTRY(arm926_cache_fns)
+	.long	arm926_flush_icache_all
 	.long	arm926_flush_kern_cache_all
 	.long	arm926_flush_user_cache_all
 	.long	arm926_flush_user_cache_range
@@ -389,7 +401,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm926_setup, #function
 __arm926_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm940.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm940.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm940.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm940.S	2011-01-04 19:50:19.000000000 -0500
@@ -68,6 +68,17 @@
 	mov	pc, lr
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm940_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm940_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  */
 ENTRY(arm940_flush_user_cache_all)
@@ -254,6 +265,7 @@
 ENDPROC(arm940_dma_unmap_area)
 
 ENTRY(arm940_cache_fns)
+	.long	arm940_flush_icache_all
 	.long	arm940_flush_kern_cache_all
 	.long	arm940_flush_user_cache_all
 	.long	arm940_flush_user_cache_range
@@ -264,7 +276,7 @@
 	.long	arm940_dma_unmap_area
 	.long	arm940_dma_flush_range
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm940_setup, #function
 __arm940_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm946.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm946.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm946.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm946.S	2011-01-04 19:50:19.000000000 -0500
@@ -75,6 +75,17 @@
 	mov	pc, lr
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(arm946_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(arm946_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  */
 ENTRY(arm946_flush_user_cache_all)
@@ -296,6 +307,7 @@
 ENDPROC(arm946_dma_unmap_area)
 
 ENTRY(arm946_cache_fns)
+	.long	arm946_flush_icache_all
 	.long	arm946_flush_kern_cache_all
 	.long	arm946_flush_user_cache_all
 	.long	arm946_flush_user_cache_range
@@ -317,7 +329,7 @@
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__arm946_setup, #function
 __arm946_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm9tdmi.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm9tdmi.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-arm9tdmi.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-arm9tdmi.S	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 ENTRY(cpu_arm9tdmi_reset)
 		mov	pc, r0
 
-		__INIT
+		__CPUINIT
 
 		.type	__arm9tdmi_setup, #function
 __arm9tdmi_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-fa526.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-fa526.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-fa526.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-fa526.S	2011-01-04 19:50:19.000000000 -0500
@@ -134,7 +134,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__fa526_setup, #function
 __fa526_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-feroceon.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-feroceon.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-feroceon.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-feroceon.S	2011-01-04 19:50:19.000000000 -0500
@@ -124,6 +124,17 @@
 	mov	pc, lr
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(feroceon_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(feroceon_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Clean and invalidate all cache entries in a particular
@@ -401,6 +412,7 @@
 ENDPROC(feroceon_dma_unmap_area)
 
 ENTRY(feroceon_cache_fns)
+	.long	feroceon_flush_icache_all
 	.long	feroceon_flush_kern_cache_all
 	.long	feroceon_flush_user_cache_all
 	.long	feroceon_flush_user_cache_range
@@ -412,6 +424,7 @@
 	.long	feroceon_dma_flush_range
 
 ENTRY(feroceon_range_cache_fns)
+	.long	feroceon_flush_icache_all
 	.long	feroceon_flush_kern_cache_all
 	.long	feroceon_flush_user_cache_all
 	.long	feroceon_flush_user_cache_range
@@ -494,7 +507,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__feroceon_setup, #function
 __feroceon_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-macros.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-macros.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-macros.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-macros.S	2011-01-04 19:50:19.000000000 -0500
@@ -61,17 +61,27 @@
 	.endm
 
 /*
- * cache_line_size - get the cache line size from the CSIDR register
- * (available on ARMv7+). It assumes that the CSSR register was configured
- * to access the L1 data cache CSIDR.
+ * dcache_line_size - get the minimum D-cache line size from the CTR register
+ * on ARMv7.
  */
 	.macro	dcache_line_size, reg, tmp
-	mrc	p15, 1, \tmp, c0, c0, 0		@ read CSIDR
-	and	\tmp, \tmp, #7			@ cache line size encoding
-	mov	\reg, #16			@ size offset
+	mrc	p15, 0, \tmp, c0, c0, 1		@ read ctr
+	lsr	\tmp, \tmp, #16
+	and	\tmp, \tmp, #0xf		@ cache line size encoding
+	mov	\reg, #4			@ bytes per word
 	mov	\reg, \reg, lsl \tmp		@ actual cache line size
 	.endm
 
+/*
+ * icache_line_size - get the minimum I-cache line size from the CTR register
+ * on ARMv7.
+ */
+	.macro	icache_line_size, reg, tmp
+	mrc	p15, 0, \tmp, c0, c0, 1		@ read ctr
+	and	\tmp, \tmp, #0xf		@ cache line size encoding
+	mov	\reg, #4			@ bytes per word
+	mov	\reg, \reg, lsl \tmp		@ actual cache line size
+	.endm
 
 /*
  * Sanity check the PTE configuration for the code below - which makes
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-mohawk.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-mohawk.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-mohawk.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-mohawk.S	2011-01-04 19:50:19.000000000 -0500
@@ -338,7 +338,7 @@
 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__mohawk_setup, #function
 __mohawk_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-sa1100.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-sa1100.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-sa1100.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-sa1100.S	2011-01-04 19:50:19.000000000 -0500
@@ -169,7 +169,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__sa1100_setup, #function
 __sa1100_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-sa110.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-sa110.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-sa110.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-sa110.S	2011-01-04 19:50:19.000000000 -0500
@@ -156,7 +156,7 @@
 #endif
 	mov	pc, lr
 
-	__INIT
+	__CPUINIT
 
 	.type	__sa110_setup, #function
 __sa110_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-v6.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-v6.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-v6.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-v6.S	2011-01-04 19:50:19.000000000 -0500
@@ -30,13 +30,10 @@
 #define TTB_RGN_WT	(2 << 3)
 #define TTB_RGN_WB	(3 << 3)
 
-#ifndef CONFIG_SMP
-#define TTB_FLAGS	TTB_RGN_WBWA
-#define PMD_FLAGS	PMD_SECT_WB
-#else
-#define TTB_FLAGS	TTB_RGN_WBWA|TTB_S
-#define PMD_FLAGS	PMD_SECT_WBWA|PMD_SECT_S
-#endif
+#define TTB_FLAGS_UP	TTB_RGN_WBWA
+#define PMD_FLAGS_UP	PMD_SECT_WB
+#define TTB_FLAGS_SMP	TTB_RGN_WBWA|TTB_S
+#define PMD_FLAGS_SMP	PMD_SECT_WBWA|PMD_SECT_S
 
 ENTRY(cpu_v6_proc_init)
 	mov	pc, lr
@@ -97,7 +94,8 @@
 #ifdef CONFIG_MMU
 	mov	r2, #0
 	ldr	r1, [r1, #MM_CONTEXT_ID]	@ get mm->context.id
-	orr	r0, r0, #TTB_FLAGS
+	ALT_SMP(orr	r0, r0, #TTB_FLAGS_SMP)
+	ALT_UP(orr	r0, r0, #TTB_FLAGS_UP)
 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
 	mcr	p15, 0, r2, c7, c10, 4		@ drain write buffer
 	mcr	p15, 0, r0, c2, c0, 0		@ set TTB 0
@@ -137,7 +135,7 @@
 
 	.align
 
-	__INIT
+	__CPUINIT
 
 /*
  *	__v6_setup
@@ -156,9 +154,11 @@
  */
 __v6_setup:
 #ifdef CONFIG_SMP
-	mrc	p15, 0, r0, c1, c0, 1		@ Enable SMP/nAMP mode
+	ALT_SMP(mrc	p15, 0, r0, c1, c0, 1)	@ Enable SMP/nAMP mode
+	ALT_UP(nop)
 	orr	r0, r0, #0x20
-	mcr	p15, 0, r0, c1, c0, 1
+	ALT_SMP(mcr	p15, 0, r0, c1, c0, 1)
+	ALT_UP(nop)
 #endif
 
 	mov	r0, #0
@@ -169,7 +169,8 @@
 #ifdef CONFIG_MMU
 	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
 	mcr	p15, 0, r0, c2, c0, 2		@ TTB control register
-	orr	r4, r4, #TTB_FLAGS
+	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
+	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
 	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
 #endif /* CONFIG_MMU */
 	adr	r5, v6_crval
@@ -192,6 +193,8 @@
 v6_crval:
 	crval	clear=0x01e0fb7f, mmuset=0x00c0387d, ucset=0x00c0187c
 
+	__INITDATA
+
 	.type	v6_processor_functions, #object
 ENTRY(v6_processor_functions)
 	.word	v6_early_abort
@@ -205,6 +208,8 @@
 	.word	cpu_v6_set_pte_ext
 	.size	v6_processor_functions, . - v6_processor_functions
 
+	.section ".rodata"
+
 	.type	cpu_arch_name, #object
 cpu_arch_name:
 	.asciz	"armv6"
@@ -225,10 +230,16 @@
 __v6_proc_info:
 	.long	0x0007b000
 	.long	0x0007f000
-	.long   PMD_TYPE_SECT | \
+	ALT_SMP(.long \
+		PMD_TYPE_SECT | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ | \
-		PMD_FLAGS
+		PMD_FLAGS_SMP)
+	ALT_UP(.long \
+		PMD_TYPE_SECT | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ | \
+		PMD_FLAGS_UP)
 	.long   PMD_TYPE_SECT | \
 		PMD_SECT_XN | \
 		PMD_SECT_AP_WRITE | \
@@ -249,10 +260,16 @@
 __pj4_v6_proc_info:
 	.long	0x560f5810
 	.long	0xff0ffff0
-	.long   PMD_TYPE_SECT | \
+	ALT_SMP(.long \
+		PMD_TYPE_SECT | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ | \
-		PMD_FLAGS
+		PMD_FLAGS_SMP)
+	ALT_UP(.long \
+		PMD_TYPE_SECT | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ | \
+		PMD_FLAGS_UP)
 	.long   PMD_TYPE_SECT | \
 		PMD_SECT_XN | \
 		PMD_SECT_AP_WRITE | \
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-v7.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-v7.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-v7.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-v7.S	2011-01-04 19:50:19.000000000 -0500
@@ -30,15 +30,13 @@
 #define TTB_IRGN_WT	((1 << 0) | (0 << 6))
 #define TTB_IRGN_WB	((1 << 0) | (1 << 6))
 
-#ifndef CONFIG_SMP
 /* PTWs cacheable, inner WB not shareable, outer WB not shareable */
-#define TTB_FLAGS	TTB_IRGN_WB|TTB_RGN_OC_WB
-#define PMD_FLAGS	PMD_SECT_WB
-#else
+#define TTB_FLAGS_UP	TTB_IRGN_WB|TTB_RGN_OC_WB
+#define PMD_FLAGS_UP	PMD_SECT_WB
+
 /* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
-#define TTB_FLAGS	TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
-#define PMD_FLAGS	PMD_SECT_WBWA|PMD_SECT_S
-#endif
+#define TTB_FLAGS_SMP	TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
+#define PMD_FLAGS_SMP	PMD_SECT_WBWA|PMD_SECT_S
 
 ENTRY(cpu_v7_proc_init)
 	mov	pc, lr
@@ -105,7 +103,8 @@
 #ifdef CONFIG_MMU
 	mov	r2, #0
 	ldr	r1, [r1, #MM_CONTEXT_ID]	@ get mm->context.id
-	orr	r0, r0, #TTB_FLAGS
+	ALT_SMP(orr	r0, r0, #TTB_FLAGS_SMP)
+	ALT_UP(orr	r0, r0, #TTB_FLAGS_UP)
 #ifdef CONFIG_ARM_ERRATA_430973
 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
 #endif
@@ -169,7 +168,7 @@
 	.ascii	"ARMv7 Processor"
 	.align
 
-	__INIT
+	__CPUINIT
 
 /*
  *	__v7_setup
@@ -188,7 +187,8 @@
  */
 __v7_ca9mp_setup:
 #ifdef CONFIG_SMP
-	mrc	p15, 0, r0, c1, c0, 1
+	ALT_SMP(mrc	p15, 0, r0, c1, c0, 1)
+	ALT_UP(mov	r0, #(1 << 6))		@ fake it for UP
 	tst	r0, #(1 << 6)			@ SMP/nAMP mode enabled?
 	orreq	r0, r0, #(1 << 6) | (1 << 0)	@ Enable SMP/nAMP mode and
 	mcreq	p15, 0, r0, c1, c0, 1		@ TLB ops broadcasting
@@ -270,7 +270,8 @@
 #ifdef CONFIG_MMU
 	mcr	p15, 0, r10, c8, c7, 0		@ invalidate I + D TLBs
 	mcr	p15, 0, r10, c2, c0, 2		@ TTB control register
-	orr	r4, r4, #TTB_FLAGS
+	ALT_SMP(orr	r4, r4, #TTB_FLAGS_SMP)
+	ALT_UP(orr	r4, r4, #TTB_FLAGS_UP)
 	mcr	p15, 0, r4, c2, c0, 1		@ load TTB1
 	mov	r10, #0x1f			@ domains 0, 1 = manager
 	mcr	p15, 0, r10, c3, c0, 0		@ load domain access register
@@ -332,6 +333,8 @@
 __v7_setup_stack:
 	.space	4 * 11				@ 11 registers
 
+	__INITDATA
+
 	.type	v7_processor_functions, #object
 ENTRY(v7_processor_functions)
 	.word	v7_early_abort
@@ -345,6 +348,8 @@
 	.word	cpu_v7_set_pte_ext
 	.size	v7_processor_functions, . - v7_processor_functions
 
+	.section ".rodata"
+
 	.type	cpu_arch_name, #object
 cpu_arch_name:
 	.asciz	"armv7"
@@ -362,15 +367,21 @@
 __v7_ca9mp_proc_info:
 	.long	0x410fc090		@ Required ID value
 	.long	0xff0ffff0		@ Mask for ID
-	.long   PMD_TYPE_SECT | \
+	ALT_SMP(.long \
+		PMD_TYPE_SECT | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ | \
-		PMD_FLAGS
+		PMD_FLAGS_SMP)
+	ALT_UP(.long \
+		PMD_TYPE_SECT | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ | \
+		PMD_FLAGS_UP)
 	.long   PMD_TYPE_SECT | \
 		PMD_SECT_XN | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ
-	b	__v7_ca9mp_setup
+	W(b)	__v7_ca9mp_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
 	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
@@ -388,15 +399,21 @@
 __v7_proc_info:
 	.long	0x000f0000		@ Required ID value
 	.long	0x000f0000		@ Mask for ID
-	.long   PMD_TYPE_SECT | \
+	ALT_SMP(.long \
+		PMD_TYPE_SECT | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ | \
-		PMD_FLAGS
+		PMD_FLAGS_SMP)
+	ALT_UP(.long \
+		PMD_TYPE_SECT | \
+		PMD_SECT_AP_WRITE | \
+		PMD_SECT_AP_READ | \
+		PMD_FLAGS_UP)
 	.long   PMD_TYPE_SECT | \
 		PMD_SECT_XN | \
 		PMD_SECT_AP_WRITE | \
 		PMD_SECT_AP_READ
-	b	__v7_setup
+	W(b)	__v7_setup
 	.long	cpu_arch_name
 	.long	cpu_elf_name
 	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-xsc3.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-xsc3.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-xsc3.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-xsc3.S	2011-01-04 19:50:19.000000000 -0500
@@ -141,6 +141,17 @@
 /* ================================= CACHE ================================ */
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(xsc3_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(xsc3_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -325,6 +336,7 @@
 ENDPROC(xsc3_dma_unmap_area)
 
 ENTRY(xsc3_cache_fns)
+	.long	xsc3_flush_icache_all
 	.long	xsc3_flush_kern_cache_all
 	.long	xsc3_flush_user_cache_all
 	.long	xsc3_flush_user_cache_range
@@ -404,7 +416,7 @@
 
 	.align
 
-	__INIT
+	__CPUINIT
 
 	.type	__xsc3_setup, #function
 __xsc3_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/proc-xscale.S linux-libre-2.6.37-gnu/arch/arm/mm/proc-xscale.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/proc-xscale.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/proc-xscale.S	2011-01-04 19:50:19.000000000 -0500
@@ -181,6 +181,17 @@
 /* ================================= CACHE ================================ */
 
 /*
+ *	flush_icache_all()
+ *
+ *	Unconditionally clean and invalidate the entire icache.
+ */
+ENTRY(xscale_flush_icache_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mov	pc, lr
+ENDPROC(xscale_flush_icache_all)
+
+/*
  *	flush_user_cache_all()
  *
  *	Invalidate all cache entries in a particular address
@@ -397,6 +408,7 @@
 ENDPROC(xscale_dma_unmap_area)
 
 ENTRY(xscale_cache_fns)
+	.long	xscale_flush_icache_all
 	.long	xscale_flush_kern_cache_all
 	.long	xscale_flush_user_cache_all
 	.long	xscale_flush_user_cache_range
@@ -506,7 +518,7 @@
 
 	.align
 
-	__INIT
+	__CPUINIT
 
 	.type	__xscale_setup, #function
 __xscale_setup:
diff -druN linux-libre-2.6.36-gnu/arch/arm/mm/tlb-v7.S linux-libre-2.6.37-gnu/arch/arm/mm/tlb-v7.S
--- linux-libre-2.6.36-gnu/arch/arm/mm/tlb-v7.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/mm/tlb-v7.S	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/tlbflush.h>
@@ -41,20 +42,15 @@
 	orr	r0, r3, r0, lsl #PAGE_SHIFT	@ Create initial MVA
 	mov	r1, r1, lsl #PAGE_SHIFT
 1:
-#ifdef CONFIG_SMP
-	mcr	p15, 0, r0, c8, c3, 1		@ TLB invalidate U MVA (shareable) 
-#else
-	mcr	p15, 0, r0, c8, c7, 1		@ TLB invalidate U MVA
-#endif
+	ALT_SMP(mcr	p15, 0, r0, c8, c3, 1)	@ TLB invalidate U MVA (shareable)
+	ALT_UP(mcr	p15, 0, r0, c8, c7, 1)	@ TLB invalidate U MVA
+
 	add	r0, r0, #PAGE_SZ
 	cmp	r0, r1
 	blo	1b
 	mov	ip, #0
-#ifdef CONFIG_SMP
-	mcr	p15, 0, ip, c7, c1, 6		@ flush BTAC/BTB Inner Shareable
-#else
-	mcr	p15, 0, ip, c7, c5, 6		@ flush BTAC/BTB
-#endif
+	ALT_SMP(mcr	p15, 0, ip, c7, c1, 6)	@ flush BTAC/BTB Inner Shareable
+	ALT_UP(mcr	p15, 0, ip, c7, c5, 6)	@ flush BTAC/BTB
 	dsb
 	mov	pc, lr
 ENDPROC(v7wbi_flush_user_tlb_range)
@@ -74,20 +70,14 @@
 	mov	r0, r0, lsl #PAGE_SHIFT
 	mov	r1, r1, lsl #PAGE_SHIFT
 1:
-#ifdef CONFIG_SMP
-	mcr	p15, 0, r0, c8, c3, 1		@ TLB invalidate U MVA (shareable)
-#else
-	mcr	p15, 0, r0, c8, c7, 1		@ TLB invalidate U MVA
-#endif
+	ALT_SMP(mcr	p15, 0, r0, c8, c3, 1)	@ TLB invalidate U MVA (shareable)
+	ALT_UP(mcr	p15, 0, r0, c8, c7, 1)	@ TLB invalidate U MVA
 	add	r0, r0, #PAGE_SZ
 	cmp	r0, r1
 	blo	1b
 	mov	r2, #0
-#ifdef CONFIG_SMP
-	mcr	p15, 0, r2, c7, c1, 6		@ flush BTAC/BTB Inner Shareable
-#else
-	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
-#endif
+	ALT_SMP(mcr	p15, 0, r2, c7, c1, 6)	@ flush BTAC/BTB Inner Shareable
+	ALT_UP(mcr	p15, 0, r2, c7, c5, 6)	@ flush BTAC/BTB
 	dsb
 	isb
 	mov	pc, lr
@@ -99,5 +89,6 @@
 ENTRY(v7wbi_tlb_fns)
 	.long	v7wbi_flush_user_tlb_range
 	.long	v7wbi_flush_kern_tlb_range
-	.long	v7wbi_tlb_flags
+	ALT_SMP(.long	v7wbi_tlb_flags_smp)
+	ALT_UP(.long	v7wbi_tlb_flags_up)
 	.size	v7wbi_tlb_fns, . - v7wbi_tlb_fns
diff -druN linux-libre-2.6.36-gnu/arch/arm/nwfpe/milieu.h linux-libre-2.6.37-gnu/arch/arm/nwfpe/milieu.h
--- linux-libre-2.6.36-gnu/arch/arm/nwfpe/milieu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/nwfpe/milieu.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,8 +12,8 @@
 of this code was written as part of a project to build a fixed-point vector
 processor in collaboration with the University of California at Berkeley,
 overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
 
 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff -druN linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat.c linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat.c
--- linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,8 +11,8 @@
 of this code was written as part of a project to build a fixed-point vector
 processor in collaboration with the University of California at Berkeley,
 overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
-is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
 
 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff -druN linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat.h linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat.h
--- linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,8 +12,8 @@
 of this code was written as part of a project to build a fixed-point vector
 processor in collaboration with the University of California at Berkeley,
 overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
 
 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff -druN linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat-macros linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat-macros
--- linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat-macros	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat-macros	2011-01-04 19:50:19.000000000 -0500
@@ -12,8 +12,8 @@
 of this code was written as part of a project to build a fixed-point vector
 processor in collaboration with the University of California at Berkeley,
 overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
-is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
 
 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff -druN linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat-specialize linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat-specialize
--- linux-libre-2.6.36-gnu/arch/arm/nwfpe/softfloat-specialize	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/nwfpe/softfloat-specialize	2011-01-04 19:50:19.000000000 -0500
@@ -12,8 +12,8 @@
 of this code was written as part of a project to build a fixed-point vector
 processor in collaboration with the University of California at Berkeley,
 overseen by Profs. Nelson Morgan and John Wawrzynek.  More information
-is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
-arithmetic/softfloat.html'.
+is available through the Web page
+http://www.jhauser.us/arithmetic/SoftFloat-2b/SoftFloat-source.txt
 
 THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
 has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
diff -druN linux-libre-2.6.36-gnu/arch/arm/oprofile/common.c linux-libre-2.6.37-gnu/arch/arm/oprofile/common.c
--- linux-libre-2.6.36-gnu/arch/arm/oprofile/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/oprofile/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,139 +25,10 @@
 #include <asm/ptrace.h>
 
 #ifdef CONFIG_HW_PERF_EVENTS
-/*
- * Per performance monitor configuration as set via oprofilefs.
- */
-struct op_counter_config {
-	unsigned long count;
-	unsigned long enabled;
-	unsigned long event;
-	unsigned long unit_mask;
-	unsigned long kernel;
-	unsigned long user;
-	struct perf_event_attr attr;
-};
-
-static int op_arm_enabled;
-static DEFINE_MUTEX(op_arm_mutex);
-
-static struct op_counter_config *counter_config;
-static struct perf_event **perf_events[nr_cpumask_bits];
-static int perf_num_counters;
-
-/*
- * Overflow callback for oprofile.
- */
-static void op_overflow_handler(struct perf_event *event, int unused,
-			struct perf_sample_data *data, struct pt_regs *regs)
-{
-	int id;
-	u32 cpu = smp_processor_id();
-
-	for (id = 0; id < perf_num_counters; ++id)
-		if (perf_events[cpu][id] == event)
-			break;
-
-	if (id != perf_num_counters)
-		oprofile_add_sample(regs, id);
-	else
-		pr_warning("oprofile: ignoring spurious overflow "
-				"on cpu %u\n", cpu);
-}
-
-/*
- * Called by op_arm_setup to create perf attributes to mirror the oprofile
- * settings in counter_config. Attributes are created as `pinned' events and
- * so are permanently scheduled on the PMU.
- */
-static void op_perf_setup(void)
-{
-	int i;
-	u32 size = sizeof(struct perf_event_attr);
-	struct perf_event_attr *attr;
-
-	for (i = 0; i < perf_num_counters; ++i) {
-		attr = &counter_config[i].attr;
-		memset(attr, 0, size);
-		attr->type		= PERF_TYPE_RAW;
-		attr->size		= size;
-		attr->config		= counter_config[i].event;
-		attr->sample_period	= counter_config[i].count;
-		attr->pinned		= 1;
-	}
-}
-
-static int op_create_counter(int cpu, int event)
-{
-	int ret = 0;
-	struct perf_event *pevent;
-
-	if (!counter_config[event].enabled || (perf_events[cpu][event] != NULL))
-		return ret;
-
-	pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
-						  cpu, -1,
-						  op_overflow_handler);
-
-	if (IS_ERR(pevent)) {
-		ret = PTR_ERR(pevent);
-	} else if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
-		perf_event_release_kernel(pevent);
-		pr_warning("oprofile: failed to enable event %d "
-				"on CPU %d\n", event, cpu);
-		ret = -EBUSY;
-	} else {
-		perf_events[cpu][event] = pevent;
-	}
-
-	return ret;
-}
-
-static void op_destroy_counter(int cpu, int event)
-{
-	struct perf_event *pevent = perf_events[cpu][event];
-
-	if (pevent) {
-		perf_event_release_kernel(pevent);
-		perf_events[cpu][event] = NULL;
-	}
-}
-
-/*
- * Called by op_arm_start to create active perf events based on the
- * perviously configured attributes.
- */
-static int op_perf_start(void)
-{
-	int cpu, event, ret = 0;
-
-	for_each_online_cpu(cpu) {
-		for (event = 0; event < perf_num_counters; ++event) {
-			ret = op_create_counter(cpu, event);
-			if (ret)
-				goto out;
-		}
-	}
-
-out:
-	return ret;
-}
-
-/*
- * Called by op_arm_stop at the end of a profiling run.
- */
-static void op_perf_stop(void)
+char *op_name_from_perf_id(void)
 {
-	int cpu, event;
-
-	for_each_online_cpu(cpu)
-		for (event = 0; event < perf_num_counters; ++event)
-			op_destroy_counter(cpu, event);
-}
-
+	enum arm_perf_pmu_ids id = armpmu_get_pmu_id();
 
-static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
-{
 	switch (id) {
 	case ARM_PERF_PMU_ID_XSCALE1:
 		return "arm/xscale1";
@@ -176,116 +47,6 @@
 	}
 }
 
-static int op_arm_create_files(struct super_block *sb, struct dentry *root)
-{
-	unsigned int i;
-
-	for (i = 0; i < perf_num_counters; i++) {
-		struct dentry *dir;
-		char buf[4];
-
-		snprintf(buf, sizeof buf, "%d", i);
-		dir = oprofilefs_mkdir(sb, root, buf);
-		oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
-		oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
-		oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
-		oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
-		oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
-		oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
-	}
-
-	return 0;
-}
-
-static int op_arm_setup(void)
-{
-	spin_lock(&oprofilefs_lock);
-	op_perf_setup();
-	spin_unlock(&oprofilefs_lock);
-	return 0;
-}
-
-static int op_arm_start(void)
-{
-	int ret = -EBUSY;
-
-	mutex_lock(&op_arm_mutex);
-	if (!op_arm_enabled) {
-		ret = 0;
-		op_perf_start();
-		op_arm_enabled = 1;
-	}
-	mutex_unlock(&op_arm_mutex);
-	return ret;
-}
-
-static void op_arm_stop(void)
-{
-	mutex_lock(&op_arm_mutex);
-	if (op_arm_enabled)
-		op_perf_stop();
-	op_arm_enabled = 0;
-	mutex_unlock(&op_arm_mutex);
-}
-
-#ifdef CONFIG_PM
-static int op_arm_suspend(struct platform_device *dev, pm_message_t state)
-{
-	mutex_lock(&op_arm_mutex);
-	if (op_arm_enabled)
-		op_perf_stop();
-	mutex_unlock(&op_arm_mutex);
-	return 0;
-}
-
-static int op_arm_resume(struct platform_device *dev)
-{
-	mutex_lock(&op_arm_mutex);
-	if (op_arm_enabled && op_perf_start())
-		op_arm_enabled = 0;
-	mutex_unlock(&op_arm_mutex);
-	return 0;
-}
-
-static struct platform_driver oprofile_driver = {
-	.driver		= {
-		.name		= "arm-oprofile",
-	},
-	.resume		= op_arm_resume,
-	.suspend	= op_arm_suspend,
-};
-
-static struct platform_device *oprofile_pdev;
-
-static int __init init_driverfs(void)
-{
-	int ret;
-
-	ret = platform_driver_register(&oprofile_driver);
-	if (ret)
-		goto out;
-
-	oprofile_pdev =	platform_device_register_simple(
-				oprofile_driver.driver.name, 0, NULL, 0);
-	if (IS_ERR(oprofile_pdev)) {
-		ret = PTR_ERR(oprofile_pdev);
-		platform_driver_unregister(&oprofile_driver);
-	}
-
-out:
-	return ret;
-}
-
-static void  exit_driverfs(void)
-{
-	platform_device_unregister(oprofile_pdev);
-	platform_driver_unregister(&oprofile_driver);
-}
-#else
-static int __init init_driverfs(void) { return 0; }
-#define exit_driverfs() do { } while (0)
-#endif /* CONFIG_PM */
-
 static int report_trace(struct stackframe *frame, void *d)
 {
 	unsigned int *depth = d;
@@ -350,74 +111,14 @@
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-	int cpu, ret = 0;
-
-	perf_num_counters = armpmu_get_max_events();
-
-	counter_config = kcalloc(perf_num_counters,
-			sizeof(struct op_counter_config), GFP_KERNEL);
-
-	if (!counter_config) {
-		pr_info("oprofile: failed to allocate %d "
-				"counters\n", perf_num_counters);
-		return -ENOMEM;
-	}
-
-	ret = init_driverfs();
-	if (ret) {
-		kfree(counter_config);
-		counter_config = NULL;
-		return ret;
-	}
-
-	for_each_possible_cpu(cpu) {
-		perf_events[cpu] = kcalloc(perf_num_counters,
-				sizeof(struct perf_event *), GFP_KERNEL);
-		if (!perf_events[cpu]) {
-			pr_info("oprofile: failed to allocate %d perf events "
-					"for cpu %d\n", perf_num_counters, cpu);
-			while (--cpu >= 0)
-				kfree(perf_events[cpu]);
-			return -ENOMEM;
-		}
-	}
-
 	ops->backtrace		= arm_backtrace;
-	ops->create_files	= op_arm_create_files;
-	ops->setup		= op_arm_setup;
-	ops->start		= op_arm_start;
-	ops->stop		= op_arm_stop;
-	ops->shutdown		= op_arm_stop;
-	ops->cpu_type		= op_name_from_perf_id(armpmu_get_pmu_id());
 
-	if (!ops->cpu_type)
-		ret = -ENODEV;
-	else
-		pr_info("oprofile: using %s\n", ops->cpu_type);
-
-	return ret;
+	return oprofile_perf_init(ops);
 }
 
-void oprofile_arch_exit(void)
+void __exit oprofile_arch_exit(void)
 {
-	int cpu, id;
-	struct perf_event *event;
-
-	if (*perf_events) {
-		for_each_possible_cpu(cpu) {
-			for (id = 0; id < perf_num_counters; ++id) {
-				event = perf_events[cpu][id];
-				if (event != NULL)
-					perf_event_release_kernel(event);
-			}
-			kfree(perf_events[cpu]);
-		}
-	}
-
-	if (counter_config) {
-		kfree(counter_config);
-		exit_driverfs();
-	}
+	oprofile_perf_exit();
 }
 #else
 int __init oprofile_arch_init(struct oprofile_operations *ops)
@@ -425,5 +126,5 @@
 	pr_info("oprofile: hardware counters not available\n");
 	return -ENODEV;
 }
-void oprofile_arch_exit(void) {}
+void __exit oprofile_arch_exit(void) {}
 #endif /* CONFIG_HW_PERF_EVENTS */
diff -druN linux-libre-2.6.36-gnu/arch/arm/oprofile/Makefile linux-libre-2.6.37-gnu/arch/arm/oprofile/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/oprofile/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/oprofile/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,4 +6,8 @@
 		oprofilefs.o oprofile_stats.o \
 		timer_int.o )
 
+ifeq ($(CONFIG_HW_PERF_EVENTS),y)
+DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
+endif
+
 oprofile-y				:= $(DRIVER_OBJS) common.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-iop/time.c linux-libre-2.6.37-gnu/arch/arm/plat-iop/time.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-iop/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-iop/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/time.h>
 #include <linux/init.h>
 #include <linux/timex.h>
+#include <linux/sched.h>
 #include <linux/io.h>
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
@@ -36,7 +37,7 @@
 /*
  * IOP clocksource (free-running timer 1).
  */
-static cycle_t iop_clocksource_read(struct clocksource *unused)
+static cycle_t notrace iop_clocksource_read(struct clocksource *unused)
 {
 	return 0xffffffffu - read_tcr1();
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/audmux-v2.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/audmux-v2.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/audmux-v2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/audmux-v2.c	2011-01-04 19:50:19.000000000 -0500
@@ -137,6 +137,7 @@
 static const struct file_operations audmux_debugfs_fops = {
 	.open = audmux_open_file,
 	.read = audmux_read_file,
+	.llseek = default_llseek,
 };
 
 static void audmux_debugfs_init(void)
@@ -186,7 +187,13 @@
 static int mxc_audmux_v2_init(void)
 {
 	int ret;
-
+#if defined(CONFIG_ARCH_MX5)
+	if (cpu_is_mx51()) {
+		audmux_base = MX51_IO_ADDRESS(MX51_AUDMUX_BASE_ADDR);
+		ret = 0;
+		return ret;
+	}
+#endif
 #if defined(CONFIG_ARCH_MX3)
 	if (cpu_is_mx31())
 		audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/cpufreq.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/cpufreq.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/cpufreq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * A driver for the Freescale Semiconductor i.MXC CPUfreq module.
+ * The CPUFREQ driver is for controling CPU frequency. It allows you to change
+ * the CPU clock speed on the fly.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+
+#define CLK32_FREQ	32768
+#define NANOSECOND	(1000 * 1000 * 1000)
+
+struct cpu_op *(*get_cpu_op)(int *op);
+
+static int cpu_freq_khz_min;
+static int cpu_freq_khz_max;
+
+static struct clk *cpu_clk;
+static struct cpufreq_frequency_table *imx_freq_table;
+
+static int cpu_op_nr;
+static struct cpu_op *cpu_op_tbl;
+
+static int set_cpu_freq(int freq)
+{
+	int ret = 0;
+	int org_cpu_rate;
+
+	org_cpu_rate = clk_get_rate(cpu_clk);
+	if (org_cpu_rate == freq)
+		return ret;
+
+	ret = clk_set_rate(cpu_clk, freq);
+	if (ret != 0) {
+		printk(KERN_DEBUG "cannot set CPU clock rate\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int mxc_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	return cpufreq_frequency_table_verify(policy, imx_freq_table);
+}
+
+static unsigned int mxc_get_speed(unsigned int cpu)
+{
+	if (cpu)
+		return 0;
+
+	return clk_get_rate(cpu_clk) / 1000;
+}
+
+static int mxc_set_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	int freq_Hz;
+	int ret = 0;
+	unsigned int index;
+
+	cpufreq_frequency_table_target(policy, imx_freq_table,
+			target_freq, relation, &index);
+	freq_Hz = imx_freq_table[index].frequency * 1000;
+
+	freqs.old = clk_get_rate(cpu_clk) / 1000;
+	freqs.new = freq_Hz / 1000;
+	freqs.cpu = 0;
+	freqs.flags = 0;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	ret = set_cpu_freq(freq_Hz);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return ret;
+}
+
+static int __init mxc_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+	int i;
+
+	printk(KERN_INFO "i.MXC CPU frequency driver\n");
+
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	if (!get_cpu_op)
+		return -EINVAL;
+
+	cpu_clk = clk_get(NULL, "cpu_clk");
+	if (IS_ERR(cpu_clk)) {
+		printk(KERN_ERR "%s: failed to get cpu clock\n", __func__);
+		return PTR_ERR(cpu_clk);
+	}
+
+	cpu_op_tbl = get_cpu_op(&cpu_op_nr);
+
+	cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000;
+	cpu_freq_khz_max = cpu_op_tbl[0].cpu_rate / 1000;
+
+	imx_freq_table = kmalloc(
+		sizeof(struct cpufreq_frequency_table) * (cpu_op_nr + 1),
+			GFP_KERNEL);
+	if (!imx_freq_table) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	for (i = 0; i < cpu_op_nr; i++) {
+		imx_freq_table[i].index = i;
+		imx_freq_table[i].frequency = cpu_op_tbl[i].cpu_rate / 1000;
+
+		if ((cpu_op_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min)
+			cpu_freq_khz_min = cpu_op_tbl[i].cpu_rate / 1000;
+
+		if ((cpu_op_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max)
+			cpu_freq_khz_max = cpu_op_tbl[i].cpu_rate / 1000;
+	}
+
+	imx_freq_table[i].index = i;
+	imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	policy->cur = clk_get_rate(cpu_clk) / 1000;
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
+	policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
+
+	/* Manual states, that PLL stabilizes in two CLK32 periods */
+	policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
+
+	if (ret < 0) {
+		printk(KERN_ERR "%s: failed to register i.MXC CPUfreq \
+				with error code %d\n", __func__, ret);
+		goto err;
+	}
+
+	cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu);
+	return 0;
+err:
+	kfree(imx_freq_table);
+err1:
+	clk_put(cpu_clk);
+	return ret;
+}
+
+static int mxc_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+
+	set_cpu_freq(cpu_freq_khz_max * 1000);
+	clk_put(cpu_clk);
+	kfree(imx_freq_table);
+	return 0;
+}
+
+static struct cpufreq_driver mxc_driver = {
+	.flags = CPUFREQ_STICKY,
+	.verify = mxc_verify_speed,
+	.target = mxc_set_target,
+	.get = mxc_get_speed,
+	.init = mxc_cpufreq_init,
+	.exit = mxc_cpufreq_exit,
+	.name = "imx",
+};
+
+static int __devinit mxc_cpufreq_driver_init(void)
+{
+	return cpufreq_register_driver(&mxc_driver);
+}
+
+static void mxc_cpufreq_driver_exit(void)
+{
+	cpufreq_unregister_driver(&mxc_driver);
+}
+
+module_init(mxc_cpufreq_driver_init);
+module_exit(mxc_cpufreq_driver_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor Inc. Yong Shen <yong.shen@linaro.org>");
+MODULE_DESCRIPTION("CPUfreq driver for i.MX");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,24 @@
+config IMX_HAVE_PLATFORM_ESDHC
+	bool
+
+config IMX_HAVE_PLATFORM_FEC
+	bool
+	default y if ARCH_MX25 || SOC_IMX27 || ARCH_MX35 || ARCH_MX51
+
 config IMX_HAVE_PLATFORM_FLEXCAN
-	select HAVE_CAN_FLEXCAN
+	select HAVE_CAN_FLEXCAN if CAN
 	bool
 
+config IMX_HAVE_PLATFORM_GPIO_KEYS
+	bool
+	default y if ARCH_MX51
+	
 config IMX_HAVE_PLATFORM_IMX_I2C
 	bool
 
+config IMX_HAVE_PLATFORM_IMX_SSI
+	bool
+
 config IMX_HAVE_PLATFORM_IMX_UART
 	bool
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,10 @@
-ifdef CONFIG_CAN_FLEXCAN
-# the ifdef can be removed once the flexcan driver has been merged
-obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) +=  platform-flexcan.o
-endif
+obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o
+obj-y += platform-imx-dma.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-esdhc.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-esdhc.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-esdhc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-esdhc.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <mach/esdhc.h>
+
+#define imx_esdhc_imx_data_entry_single(soc, _id, hwid) \
+	{								\
+		.id = _id,						\
+		.iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR,	\
+		.irq = soc ## _INT_ESDHC ## hwid,			\
+	}
+
+#define imx_esdhc_imx_data_entry(soc, id, hwid)	\
+	[id] = imx_esdhc_imx_data_entry_single(soc, id, hwid)
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst = {
+#define imx25_esdhc_data_entry(_id, _hwid)				\
+	imx_esdhc_imx_data_entry(MX25, _id, _hwid)
+	imx25_esdhc_data_entry(0, 1),
+	imx25_esdhc_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst = {
+#define imx35_esdhc_data_entry(_id, _hwid)                           \
+	imx_esdhc_imx_data_entry(MX35, _id, _hwid)
+	imx35_esdhc_data_entry(0, 1),
+	imx35_esdhc_data_entry(1, 2),
+	imx35_esdhc_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst = {
+#define imx51_esdhc_data_entry(_id, _hwid)				\
+	imx_esdhc_imx_data_entry(MX51, _id, _hwid)
+	imx51_esdhc_data_entry(0, 1),
+	imx51_esdhc_data_entry(1, 2),
+	imx51_esdhc_data_entry(2, 3),
+	imx51_esdhc_data_entry(3, 4),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_esdhc(
+		const struct imx_esdhc_imx_data *data,
+		const struct esdhc_platform_data *pdata)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + SZ_16K - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+
+	return imx_add_platform_device("sdhci-esdhc-imx", data->id, res,
+			ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-fec.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-fec.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-fec.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-fec.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <asm/sizes.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_fec_data_entry_single(soc)					\
+	{								\
+		.iobase = soc ## _FEC_BASE_ADDR,			\
+		.irq = soc ## _INT_FEC,					\
+	}
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_fec_data imx25_fec_data __initconst =
+	imx_fec_data_entry_single(MX25);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_fec_data imx27_fec_data __initconst =
+	imx_fec_data_entry_single(MX27);
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_fec_data imx35_fec_data __initconst =
+	imx_fec_data_entry_single(MX35);
+#endif
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_fec_data imx51_fec_data __initconst =
+	imx_fec_data_entry_single(MX51);
+#endif
+
+struct platform_device *__init imx_add_fec(
+		const struct imx_fec_data *data,
+		const struct fec_platform_data *pdata)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + SZ_4K,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+
+	return imx_add_platform_device("fec", 0 /* -1? */,
+			res, ARRAY_SIZE(res),
+			pdata, sizeof(*pdata));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-gpio_keys.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-gpio_keys.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-gpio_keys.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-gpio_keys.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+#include <asm/sizes.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+struct platform_device *__init imx_add_gpio_keys(
+		const struct gpio_keys_platform_data *pdata)
+{
+	return imx_add_platform_device("gpio-keys", -1, NULL,
+		 0, pdata, sizeof(*pdata));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-dma.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-dma.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-dma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <mach/sdma.h>
+
+struct imx_imx_sdma_data {
+	resource_size_t iobase;
+	resource_size_t irq;
+	struct sdma_platform_data pdata;
+};
+
+#define imx_imx_sdma_data_entry_single(soc, _sdma_version, _cpu_name, _to_version)\
+	{								\
+		.iobase = soc ## _SDMA ## _BASE_ADDR,			\
+		.irq = soc ## _INT_SDMA,				\
+		.pdata = {						\
+			.sdma_version = _sdma_version,			\
+			.cpu_name = _cpu_name,				\
+			.to_version = _to_version,			\
+		},							\
+	}
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_sdma_data imx25_imx_sdma_data __initconst =
+	imx_imx_sdma_data_entry_single(MX25, 1, "imx25", 0);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_ARCH_MX31
+struct imx_imx_sdma_data imx31_imx_sdma_data __initdata =
+	imx_imx_sdma_data_entry_single(MX31, 1, "imx31", 0);
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+struct imx_imx_sdma_data imx35_imx_sdma_data __initdata =
+	imx_imx_sdma_data_entry_single(MX35, 2, "imx35", 0);
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_sdma_data imx51_imx_sdma_data __initconst =
+	imx_imx_sdma_data_entry_single(MX51, 2, "imx51", 0);
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+static struct platform_device __init __maybe_unused *imx_add_imx_sdma(
+		const struct imx_imx_sdma_data *data)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + SZ_4K - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+
+	return imx_add_platform_device("imx-sdma", -1,
+			res, ARRAY_SIZE(res),
+			&data->pdata, sizeof(data->pdata));
+}
+
+static struct platform_device __init __maybe_unused *imx_add_imx_dma(void)
+{
+	return imx_add_platform_device("imx-dma", -1, NULL, 0, NULL, 0);
+}
+
+static int __init imxXX_add_imx_dma(void)
+{
+	struct platform_device *ret;
+
+#if defined(CONFIG_SOC_IMX21) || defined(CONFIG_SOC_IMX27)
+	if (cpu_is_mx21() || cpu_is_mx27())
+		ret = imx_add_imx_dma();
+	else
+#endif
+
+#if defined(CONFIG_ARCH_MX25)
+	if (cpu_is_mx25())
+		ret = imx_add_imx_sdma(&imx25_imx_sdma_data);
+	else
+#endif
+
+#if defined(CONFIG_ARCH_MX31)
+	if (cpu_is_mx31()) {
+		imx31_imx_sdma_data.pdata.to_version = mx31_revision() >> 4;
+		ret = imx_add_imx_sdma(&imx31_imx_sdma_data);
+	} else
+#endif
+
+#if defined(CONFIG_ARCH_MX35)
+	if (cpu_is_mx35()) {
+		imx35_imx_sdma_data.pdata.to_version = mx35_revision() >> 4;
+		ret = imx_add_imx_sdma(&imx35_imx_sdma_data);
+	} else
+#endif
+
+#if defined(CONFIG_ARCH_MX51)
+	if (cpu_is_mx51())
+		ret = imx_add_imx_sdma(&imx51_imx_sdma_data);
+	else
+#endif
+		ret = ERR_PTR(-ENODEV);
+
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+
+	return 0;
+}
+arch_initcall(imxXX_add_imx_dma);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-i2c.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-i2c.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,24 +6,95 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_imx_i2c(int id,
-		resource_size_t iobase, resource_size_t iosize, int irq,
+#define imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size)		\
+	{								\
+		.id = _id,						\
+		.iobase = soc ## _I2C ## _hwid ## _BASE_ADDR,		\
+		.iosize = _size,					\
+		.irq = soc ## _INT_I2C ## _hwid,			\
+	}
+
+#define imx_imx_i2c_data_entry(soc, _id, _hwid, _size)			\
+	[_id] = imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size)
+
+#ifdef CONFIG_SOC_IMX1
+const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst =
+	imx_imx_i2c_data_entry_single(MX1, 0, , SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX1 */
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst =
+	imx_imx_i2c_data_entry_single(MX21, 0, , SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst = {
+#define imx25_imx_i2c_data_entry(_id, _hwid)				\
+	imx_imx_i2c_data_entry(MX25, _id, _hwid, SZ_16K)
+	imx25_imx_i2c_data_entry(0, 1),
+	imx25_imx_i2c_data_entry(1, 2),
+	imx25_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst = {
+#define imx27_imx_i2c_data_entry(_id, _hwid)				\
+	imx_imx_i2c_data_entry(MX27, _id, _hwid, SZ_4K)
+	imx27_imx_i2c_data_entry(0, 1),
+	imx27_imx_i2c_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst = {
+#define imx31_imx_i2c_data_entry(_id, _hwid)				\
+	imx_imx_i2c_data_entry(MX31, _id, _hwid, SZ_4K)
+	imx31_imx_i2c_data_entry(0, 1),
+	imx31_imx_i2c_data_entry(1, 2),
+	imx31_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = {
+#define imx35_imx_i2c_data_entry(_id, _hwid)				\
+	imx_imx_i2c_data_entry(MX35, _id, _hwid, SZ_4K)
+	imx35_imx_i2c_data_entry(0, 1),
+	imx35_imx_i2c_data_entry(1, 2),
+	imx35_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = {
+#define imx51_imx_i2c_data_entry(_id, _hwid)				\
+	imx_imx_i2c_data_entry(MX51, _id, _hwid, SZ_4K)
+	imx51_imx_i2c_data_entry(0, 1),
+	imx51_imx_i2c_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_i2c(
+		const struct imx_imx_i2c_data *data,
 		const struct imxi2c_platform_data *pdata)
 {
 	struct resource res[] = {
 		{
-			.start = iobase,
-			.end = iobase + iosize - 1,
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
 		}, {
-			.start = irq,
-			.end = irq,
+			.start = data->irq,
+			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
 		},
 	};
 
-	return imx_add_platform_device("imx-i2c", id, res, ARRAY_SIZE(res),
+	return imx_add_platform_device("imx-i2c", data->id,
+			res, ARRAY_SIZE(res),
 			pdata, sizeof(*pdata));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-ssi.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-ssi.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-ssi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-ssi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_imx_ssi_data_entry(soc, _id, _hwid, _size)			\
+	[_id] = {							\
+		.id = _id,						\
+		.iobase = soc ## _SSI ## _hwid ## _BASE_ADDR,		\
+		.iosize = _size,					\
+		.irq = soc ## _INT_SSI ## _hwid,			\
+		.dmatx0 = soc ## _DMA_REQ_SSI ## _hwid ## _TX0,		\
+		.dmarx0 = soc ## _DMA_REQ_SSI ## _hwid ## _RX0,		\
+		.dmatx1 = soc ## _DMA_REQ_SSI ## _hwid ## _TX1,		\
+		.dmarx1 = soc ## _DMA_REQ_SSI ## _hwid ## _RX1,		\
+	}
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_ssi_data imx21_imx_ssi_data[] __initconst = {
+#define imx21_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX21, _id, _hwid, SZ_4K)
+	imx21_imx_ssi_data_entry(0, 1),
+	imx21_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_ssi_data imx25_imx_ssi_data[] __initconst = {
+#define imx25_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX25, _id, _hwid, SZ_4K)
+	imx25_imx_ssi_data_entry(0, 1),
+	imx25_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_ssi_data imx27_imx_ssi_data[] __initconst = {
+#define imx27_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX27, _id, _hwid, SZ_4K)
+	imx27_imx_ssi_data_entry(0, 1),
+	imx27_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_ssi_data imx31_imx_ssi_data[] __initconst = {
+#define imx31_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX31, _id, _hwid, SZ_4K)
+	imx31_imx_ssi_data_entry(0, 1),
+	imx31_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst = {
+#define imx35_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX35, _id, _hwid, SZ_4K)
+	imx35_imx_ssi_data_entry(0, 1),
+	imx35_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_ssi_data imx51_imx_ssi_data[] __initconst = {
+#define imx51_imx_ssi_data_entry(_id, _hwid)				\
+	imx_imx_ssi_data_entry(MX51, _id, _hwid, SZ_4K)
+	imx51_imx_ssi_data_entry(0, 1),
+	imx51_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_ssi(
+		const struct imx_imx_ssi_data *data,
+		const struct imx_ssi_platform_data *pdata)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+#define DMARES(_name) {							\
+	.name = #_name,							\
+	.start = data->dma ## _name,					\
+	.end = data->dma ## _name,					\
+	.flags = IORESOURCE_DMA,					\
+}
+		DMARES(tx0),
+		DMARES(rx0),
+		DMARES(tx1),
+		DMARES(rx1),
+	};
+
+	return imx_add_platform_device("imx-ssi", data->id,
+			res, ARRAY_SIZE(res),
+			pdata, sizeof(*pdata));
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-uart.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-uart.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-imx-uart.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-imx-uart.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,55 +6,148 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_imx_uart_3irq(int id,
-		resource_size_t iobase, resource_size_t iosize,
-		resource_size_t irqrx, resource_size_t irqtx,
-		resource_size_t irqrts,
+#define imx_imx_uart_3irq_data_entry(soc, _id, _hwid, _size)		\
+	[_id] = {							\
+		.id = _id,						\
+		.iobase = soc ## _UART ## _hwid ## _BASE_ADDR,		\
+		.iosize = _size,					\
+		.irqrx = soc ## _INT_UART ## _hwid ## RX,		\
+		.irqtx = soc ## _INT_UART ## _hwid ## TX,		\
+		.irqrts = soc ## _INT_UART ## _hwid ## RTS,		\
+	}
+
+#define imx_imx_uart_1irq_data_entry(soc, _id, _hwid, _size)		\
+	[_id] = {							\
+		.id = _id,						\
+		.iobase = soc ## _UART ## _hwid ## _BASE_ADDR,		\
+		.iosize = _size,					\
+		.irq = soc ## _INT_UART ## _hwid,			\
+	}
+
+#ifdef CONFIG_SOC_IMX1
+const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst = {
+#define imx1_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_3irq_data_entry(MX1, _id, _hwid, 0xd0)
+	imx1_imx_uart_data_entry(0, 1),
+	imx1_imx_uart_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX1 */
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst = {
+#define imx21_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX21, _id, _hwid, SZ_4K)
+	imx21_imx_uart_data_entry(0, 1),
+	imx21_imx_uart_data_entry(1, 2),
+	imx21_imx_uart_data_entry(2, 3),
+	imx21_imx_uart_data_entry(3, 4),
+};
+#endif
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst = {
+#define imx25_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX25, _id, _hwid, SZ_16K)
+	imx25_imx_uart_data_entry(0, 1),
+	imx25_imx_uart_data_entry(1, 2),
+	imx25_imx_uart_data_entry(2, 3),
+	imx25_imx_uart_data_entry(3, 4),
+	imx25_imx_uart_data_entry(4, 5),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst = {
+#define imx27_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX27, _id, _hwid, SZ_4K)
+	imx27_imx_uart_data_entry(0, 1),
+	imx27_imx_uart_data_entry(1, 2),
+	imx27_imx_uart_data_entry(2, 3),
+	imx27_imx_uart_data_entry(3, 4),
+	imx27_imx_uart_data_entry(4, 5),
+	imx27_imx_uart_data_entry(5, 6),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst = {
+#define imx31_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX31, _id, _hwid, SZ_4K)
+	imx31_imx_uart_data_entry(0, 1),
+	imx31_imx_uart_data_entry(1, 2),
+	imx31_imx_uart_data_entry(2, 3),
+	imx31_imx_uart_data_entry(3, 4),
+	imx31_imx_uart_data_entry(4, 5),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst = {
+#define imx35_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX31, _id, _hwid, SZ_16K)
+	imx35_imx_uart_data_entry(0, 1),
+	imx35_imx_uart_data_entry(1, 2),
+	imx35_imx_uart_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst = {
+#define imx51_imx_uart_data_entry(_id, _hwid)				\
+	imx_imx_uart_1irq_data_entry(MX51, _id, _hwid, SZ_4K)
+	imx51_imx_uart_data_entry(0, 1),
+	imx51_imx_uart_data_entry(1, 2),
+	imx51_imx_uart_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_uart_3irq(
+		const struct imx_imx_uart_3irq_data *data,
 		const struct imxuart_platform_data *pdata)
 {
 	struct resource res[] = {
 		{
-			.start = iobase,
-			.end = iobase + iosize - 1,
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
 		}, {
-			.start = irqrx,
-			.end = irqrx,
+			.start = data->irqrx,
+			.end = data->irqrx,
 			.flags = IORESOURCE_IRQ,
 		}, {
-			.start = irqtx,
-			.end = irqtx,
+			.start = data->irqtx,
+			.end = data->irqtx,
 			.flags = IORESOURCE_IRQ,
 		}, {
-			.start = irqrts,
-			.end = irqrx,
+			.start = data->irqrts,
+			.end = data->irqrx,
 			.flags = IORESOURCE_IRQ,
 		},
 	};
 
-	return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
-			pdata, sizeof(*pdata));
+	return imx_add_platform_device("imx-uart", data->id, res,
+			ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
 
-struct platform_device *__init imx_add_imx_uart_1irq(int id,
-		resource_size_t iobase, resource_size_t iosize,
-		resource_size_t irq,
+struct platform_device *__init imx_add_imx_uart_1irq(
+		const struct imx_imx_uart_1irq_data *data,
 		const struct imxuart_platform_data *pdata)
 {
 	struct resource res[] = {
 		{
-			.start = iobase,
-			.end = iobase + iosize - 1,
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
 		}, {
-			.start = irq,
-			.end = irq,
+			.start = data->irq,
+			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
 		},
 	};
 
-	return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
+	return imx_add_platform_device("imx-uart", data->id, res, ARRAY_SIZE(res),
 			pdata, sizeof(*pdata));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-mxc_nand.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-mxc_nand.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-mxc_nand.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-mxc_nand.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,38 +7,77 @@
  * Free Software Foundation.
  */
 #include <asm/sizes.h>
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-static struct platform_device *__init imx_add_mxc_nand(resource_size_t iobase,
-		int irq, const struct mxc_nand_platform_data *pdata,
-		resource_size_t iosize)
+#define imx_mxc_nand_data_entry_single(soc, _size)			\
+	{								\
+		.iobase = soc ## _NFC_BASE_ADDR,			\
+		.iosize = _size,					\
+		.irq = soc ## _INT_NFC					\
+	}
+
+#define imx_mxc_nandv3_data_entry_single(soc, _size)			\
+	{								\
+		.id = -1,						\
+		.iobase = soc ## _NFC_BASE_ADDR,			\
+		.iosize = _size,					\
+		.axibase = soc ## _NFC_AXI_BASE_ADDR,			\
+		.irq = soc ## _INT_NFC					\
+	}
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst =
+	imx_mxc_nand_data_entry_single(MX21, SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst =
+	imx_mxc_nand_data_entry_single(MX25, SZ_8K);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst =
+	imx_mxc_nand_data_entry_single(MX27, SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst =
+	imx_mxc_nand_data_entry_single(MX31, SZ_4K);
+#endif
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst =
+	imx_mxc_nand_data_entry_single(MX35, SZ_8K);
+#endif
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst =
+	imx_mxc_nandv3_data_entry_single(MX51, SZ_16K);
+#endif
+
+struct platform_device *__init imx_add_mxc_nand(
+		const struct imx_mxc_nand_data *data,
+		const struct mxc_nand_platform_data *pdata)
 {
-	static int id = 0;
-	
+	/* AXI has to come first, that's how the mxc_nand driver expect it */
 	struct resource res[] = {
 		{
-			.start = iobase,
-			.end = iobase + iosize - 1,
+			.start = data->axibase,
+			.end = data->axibase + SZ_16K - 1,
 			.flags = IORESOURCE_MEM,
 		}, {
-			.start = irq,
-			.end = irq,
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
 		},
 	};
-
-	return imx_add_platform_device("mxc_nand", id++, res, ARRAY_SIZE(res),
+	return imx_add_platform_device("mxc_nand", data->id,
+			res + !data->axibase,
+			ARRAY_SIZE(res) - !data->axibase,
 			pdata, sizeof(*pdata));
 }
-
-struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
-		int irq, const struct mxc_nand_platform_data *pdata)
-{
-	return imx_add_mxc_nand(iobase, irq, pdata, SZ_4K);
-}
-
-struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
-		int irq, const struct mxc_nand_platform_data *pdata)
-{
-	return imx_add_mxc_nand(iobase, irq, pdata, SZ_8K);
-}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-spi_imx.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-spi_imx.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/devices/platform-spi_imx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/devices/platform-spi_imx.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,25 +6,97 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
-#include <asm/sizes.h>
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_spi_imx(int id,
-		resource_size_t iobase, resource_size_t iosize, int irq,
+#define imx_spi_imx_data_entry_single(soc, type, _devid, _id, hwid, _size) \
+	{								\
+		.devid = _devid,					\
+		.id = _id,						\
+		.iobase = soc ## _ ## type ## hwid ## _BASE_ADDR,	\
+		.iosize = _size,					\
+		.irq = soc ## _INT_ ## type ## hwid,			\
+	}
+
+#define imx_spi_imx_data_entry(soc, type, devid, id, hwid, size)	\
+	[id] = imx_spi_imx_data_entry_single(soc, type, devid, id, hwid, size)
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_spi_imx_data imx21_cspi_data[] __initconst = {
+#define imx21_cspi_data_entry(_id, _hwid)                            \
+	imx_spi_imx_data_entry(MX21, CSPI, "imx21-cspi", _id, _hwid, SZ_4K)
+	imx21_cspi_data_entry(0, 1),
+	imx21_cspi_data_entry(1, 2),
+};
+#endif
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_spi_imx_data imx25_cspi_data[] __initconst = {
+#define imx25_cspi_data_entry(_id, _hwid)				\
+	imx_spi_imx_data_entry(MX25, CSPI, "imx25-cspi", _id, _hwid, SZ_16K)
+	imx25_cspi_data_entry(0, 1),
+	imx25_cspi_data_entry(1, 2),
+	imx25_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_spi_imx_data imx27_cspi_data[] __initconst = {
+#define imx27_cspi_data_entry(_id, _hwid)				\
+	imx_spi_imx_data_entry(MX27, CSPI, "imx27-cspi", _id, _hwid, SZ_4K)
+	imx27_cspi_data_entry(0, 1),
+	imx27_cspi_data_entry(1, 2),
+	imx27_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_spi_imx_data imx31_cspi_data[] __initconst = {
+#define imx31_cspi_data_entry(_id, _hwid)				\
+	imx_spi_imx_data_entry(MX31, CSPI, "imx31-cspi", _id, _hwid, SZ_4K)
+	imx31_cspi_data_entry(0, 1),
+	imx31_cspi_data_entry(1, 2),
+	imx31_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_spi_imx_data imx35_cspi_data[] __initconst = {
+#define imx35_cspi_data_entry(_id, _hwid)                           \
+	imx_spi_imx_data_entry(MX35, CSPI, "imx35-cspi", _id, _hwid, SZ_4K)
+	imx35_cspi_data_entry(0, 1),
+	imx35_cspi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_spi_imx_data imx51_cspi_data __initconst =
+	imx_spi_imx_data_entry_single(MX51, CSPI, "imx51-cspi", 0, , SZ_4K);
+
+const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
+#define imx51_ecspi_data_entry(_id, _hwid)				\
+	imx_spi_imx_data_entry(MX51, ECSPI, "imx51-ecspi", _id, _hwid, SZ_4K)
+	imx51_ecspi_data_entry(0, 1),
+	imx51_ecspi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_spi_imx(
+		const struct imx_spi_imx_data *data,
 		const struct spi_imx_master *pdata)
 {
 	struct resource res[] = {
 		{
-			.start = iobase,
-			.end = iobase + iosize - 1,
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
 			.flags = IORESOURCE_MEM,
 		}, {
-			.start = irq,
-			.end = irq,
+			.start = data->irq,
+			.end = data->irq,
 			.flags = IORESOURCE_IRQ,
 		},
 	};
 
-	return imx_add_platform_device("spi_imx", id, res, ARRAY_SIZE(res),
-			pdata, sizeof(*pdata));
+	return imx_add_platform_device(data->devid, data->id,
+			res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/ehci.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/ehci.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/ehci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/ehci.c	2011-01-04 19:50:19.000000000 -0500
@@ -249,8 +249,8 @@
 #ifdef CONFIG_ARCH_MX51
 	if (cpu_is_mx51()) {
 		void __iomem *usb_base;
-		u32 usbotg_base;
-		u32 usbother_base;
+		void __iomem *usbotg_base;
+		void __iomem *usbother_base;
 		int ret = 0;
 
 		usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/epit.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/epit.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/epit.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/epit.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,242 @@
+/*
+ *  linux/arch/arm/plat-mxc/epit.c
+ *
+ *  Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#define EPITCR		0x00
+#define EPITSR		0x04
+#define EPITLR		0x08
+#define EPITCMPR	0x0c
+#define EPITCNR		0x10
+
+#define EPITCR_EN			(1 << 0)
+#define EPITCR_ENMOD			(1 << 1)
+#define EPITCR_OCIEN			(1 << 2)
+#define EPITCR_RLD			(1 << 3)
+#define EPITCR_PRESC(x)			(((x) & 0xfff) << 4)
+#define EPITCR_SWR			(1 << 16)
+#define EPITCR_IOVW			(1 << 17)
+#define EPITCR_DBGEN			(1 << 18)
+#define EPITCR_WAITEN			(1 << 19)
+#define EPITCR_RES			(1 << 20)
+#define EPITCR_STOPEN			(1 << 21)
+#define EPITCR_OM_DISCON		(0 << 22)
+#define EPITCR_OM_TOGGLE		(1 << 22)
+#define EPITCR_OM_CLEAR			(2 << 22)
+#define EPITCR_OM_SET			(3 << 22)
+#define EPITCR_CLKSRC_OFF		(0 << 24)
+#define EPITCR_CLKSRC_PERIPHERAL	(1 << 24)
+#define EPITCR_CLKSRC_REF_HIGH		(1 << 24)
+#define EPITCR_CLKSRC_REF_LOW		(3 << 24)
+
+#define EPITSR_OCIF			(1 << 0)
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+
+static struct clock_event_device clockevent_epit;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
+
+static void __iomem *timer_base;
+
+static inline void epit_irq_disable(void)
+{
+	u32 val;
+
+	val = __raw_readl(timer_base + EPITCR);
+	val &= ~EPITCR_OCIEN;
+	__raw_writel(val, timer_base + EPITCR);
+}
+
+static inline void epit_irq_enable(void)
+{
+	u32 val;
+
+	val = __raw_readl(timer_base + EPITCR);
+	val |= EPITCR_OCIEN;
+	__raw_writel(val, timer_base + EPITCR);
+}
+
+static void epit_irq_acknowledge(void)
+{
+	__raw_writel(EPITSR_OCIF, timer_base + EPITSR);
+}
+
+static cycle_t epit_read(struct clocksource *cs)
+{
+	return 0 - __raw_readl(timer_base + EPITCNR);
+}
+
+static struct clocksource clocksource_epit = {
+	.name		= "epit",
+	.rating		= 200,
+	.read		= epit_read,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 20,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init epit_clocksource_init(struct clk *timer_clk)
+{
+	unsigned int c = clk_get_rate(timer_clk);
+
+	clocksource_epit.mult = clocksource_hz2mult(c,
+					clocksource_epit.shift);
+	clocksource_register(&clocksource_epit);
+
+	return 0;
+}
+
+/* clock event */
+
+static int epit_set_next_event(unsigned long evt,
+			      struct clock_event_device *unused)
+{
+	unsigned long tcmp;
+
+	tcmp = __raw_readl(timer_base + EPITCNR);
+
+	__raw_writel(tcmp - evt, timer_base + EPITCMPR);
+
+	return 0;
+}
+
+static void epit_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt)
+{
+	unsigned long flags;
+
+	/*
+	 * The timer interrupt generation is disabled at least
+	 * for enough time to call epit_set_next_event()
+	 */
+	local_irq_save(flags);
+
+	/* Disable interrupt in GPT module */
+	epit_irq_disable();
+
+	if (mode != clockevent_mode) {
+		/* Set event time into far-far future */
+
+		/* Clear pending interrupt */
+		epit_irq_acknowledge();
+	}
+
+	/* Remember timer mode */
+	clockevent_mode = mode;
+	local_irq_restore(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		printk(KERN_ERR "epit_set_mode: Periodic mode is not "
+				"supported for i.MX EPIT\n");
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+	/*
+	 * Do not put overhead of interrupt enable/disable into
+	 * epit_set_next_event(), the core has about 4 minutes
+	 * to call epit_set_next_event() or shutdown clock after
+	 * mode switching
+	 */
+		local_irq_save(flags);
+		epit_irq_enable();
+		local_irq_restore(flags);
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_RESUME:
+		/* Left event sources disabled, no more interrupts appear */
+		break;
+	}
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &clockevent_epit;
+
+	epit_irq_acknowledge();
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction epit_timer_irq = {
+	.name		= "i.MX EPIT Timer Tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= epit_timer_interrupt,
+};
+
+static struct clock_event_device clockevent_epit = {
+	.name		= "epit",
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.set_mode	= epit_set_mode,
+	.set_next_event	= epit_set_next_event,
+	.rating		= 200,
+};
+
+static int __init epit_clockevent_init(struct clk *timer_clk)
+{
+	unsigned int c = clk_get_rate(timer_clk);
+
+	clockevent_epit.mult = div_sc(c, NSEC_PER_SEC,
+					clockevent_epit.shift);
+	clockevent_epit.max_delta_ns =
+			clockevent_delta2ns(0xfffffffe, &clockevent_epit);
+	clockevent_epit.min_delta_ns =
+			clockevent_delta2ns(0x800, &clockevent_epit);
+
+	clockevent_epit.cpumask = cpumask_of(0);
+
+	clockevents_register_device(&clockevent_epit);
+
+	return 0;
+}
+
+void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
+{
+	clk_enable(timer_clk);
+
+	timer_base = base;
+
+	/*
+	 * Initialise to a known state (all timers off, and timing reset)
+	 */
+	__raw_writel(0x0, timer_base + EPITCR);
+
+	__raw_writel(0xffffffff, timer_base + EPITLR);
+	__raw_writel(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
+			timer_base + EPITCR);
+
+	/* init and register the timer to the framework */
+	epit_clocksource_init(timer_clk);
+	epit_clockevent_init(timer_clk);
+
+	/* Make irqs happen */
+	setup_irq(irq, &epit_timer_irq);
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/gpio.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
@@ -201,11 +202,42 @@
 	}
 }
 
+/*
+ * Set interrupt number "irq" in the GPIO as a wake-up source.
+ * While system is running, all registered GPIO interrupts need to have
+ * wake-up enabled. When system is suspended, only selected GPIO interrupts
+ * need to have wake-up enabled.
+ * @param  irq          interrupt source number
+ * @param  enable       enable as wake-up if equal to non-zero
+ * @return       This function returns 0 on success.
+ */
+static int gpio_set_wake_irq(u32 irq, u32 enable)
+{
+	u32 gpio = irq_to_gpio(irq);
+	u32 gpio_idx = gpio & 0x1F;
+	struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
+
+	if (enable) {
+		if (port->irq_high && (gpio_idx >= 16))
+			enable_irq_wake(port->irq_high);
+		else
+			enable_irq_wake(port->irq);
+	} else {
+		if (port->irq_high && (gpio_idx >= 16))
+			disable_irq_wake(port->irq_high);
+		else
+			disable_irq_wake(port->irq);
+	}
+
+	return 0;
+}
+
 static struct irq_chip gpio_irq_chip = {
 	.ack = gpio_ack_irq,
 	.mask = gpio_mask_irq,
 	.unmask = gpio_unmask_irq,
 	.set_type = gpio_set_irq_type,
+	.set_wake = gpio_set_wake_irq,
 };
 
 static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
@@ -235,7 +267,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&port->lock, flags);
-	l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
+	l = (__raw_readl(reg) & (~(1 << offset))) | (!!value << offset);
 	__raw_writel(l, reg);
 	spin_unlock_irqrestore(&port->lock, flags);
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/board-mx31ads.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/board-mx31ads.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/board-mx31ads.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/board-mx31ads.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+
+#include <mach/hardware.h>
+
+/*
+ * These symbols are used by drivers/net/cs89x0.c.
+ * This is ugly as hell, but we have to provide them until
+ * someone fixed the driver.
+ */
+
+/* Base address of PBC controller */
+#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
+/* Offsets for the PBC Controller register */
+
+/* Ethernet Controller IO base address */
+#define PBC_CS8900A_IOBASE      0x020000
+
+#define MXC_EXP_IO_BASE		(MXC_BOARD_IRQ_START)
+
+#define EXPIO_INT_ENET_INT	(MXC_EXP_IO_BASE + 8)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/common.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/common.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/common.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/common.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 extern void mx35_init_irq(void);
 extern void mx51_init_irq(void);
 extern void mxc91231_init_irq(void);
+extern void epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq);
 extern void mxc_timer_init(struct clk *timer_clk, void __iomem *, int);
 extern int mx1_clocks_init(unsigned long fref);
 extern int mx21_clocks_init(unsigned long lref, unsigned long fref);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -62,11 +62,9 @@
 #define UART_PADDR	MXC91231_UART2_BASE_ADDR
 #define UART_VADDR	MXC91231_IO_ADDRESS(MXC91231_UART2_BASE_ADDR)
 #endif
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		ldreq	\rx, =UART_PADDR	@ physical
-		ldrne	\rx, =UART_VADDR	@ virtual
+		.macro	addruart, rp, rv
+		ldr	\rp, =UART_PADDR	@ physical
+		ldr	\rv, =UART_VADDR	@ virtual
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/devices-common.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/devices-common.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/devices-common.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/devices-common.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,47 +14,109 @@
 		const struct resource *res, unsigned int num_resources,
 		const void *data, size_t size_data);
 
-#if defined (CONFIG_CAN_FLEXCAN) || defined (CONFIG_CAN_FLEXCAN_MODULE)
+#include <linux/fec.h>
+struct imx_fec_data {
+	resource_size_t iobase;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_fec(
+		const struct imx_fec_data *data,
+		const struct fec_platform_data *pdata);
+
 #include <linux/can/platform/flexcan.h>
 struct platform_device *__init imx_add_flexcan(int id,
 		resource_size_t iobase, resource_size_t iosize,
 		resource_size_t irq,
 		const struct flexcan_platform_data *pdata);
-#else
-/* the ifdef can be removed once the flexcan driver has been merged */
-struct flexcan_platform_data;
-static inline struct platform_device *__init imx_add_flexcan(int id,
-		resource_size_t iobase, resource_size_t iosize,
-		resource_size_t irq,
-		const struct flexcan_platform_data *pdata)
-{
-	return NULL;
-}
-#endif
+
+#include <linux/gpio_keys.h>
+struct platform_device *__init imx_add_gpio_keys(
+		const struct gpio_keys_platform_data *pdata);
 
 #include <mach/i2c.h>
-struct platform_device *__init imx_add_imx_i2c(int id,
-		resource_size_t iobase, resource_size_t iosize, int irq,
+struct imx_imx_i2c_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx_i2c(
+		const struct imx_imx_i2c_data *data,
 		const struct imxi2c_platform_data *pdata);
 
+#include <mach/ssi.h>
+struct imx_imx_ssi_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irq;
+	resource_size_t dmatx0;
+	resource_size_t dmarx0;
+	resource_size_t dmatx1;
+	resource_size_t dmarx1;
+};
+struct platform_device *__init imx_add_imx_ssi(
+		const struct imx_imx_ssi_data *data,
+		const struct imx_ssi_platform_data *pdata);
+
 #include <mach/imx-uart.h>
-struct platform_device *__init imx_add_imx_uart_3irq(int id,
-		resource_size_t iobase, resource_size_t iosize,
-		resource_size_t irqrx, resource_size_t irqtx,
-		resource_size_t irqrts,
+struct imx_imx_uart_3irq_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irqrx;
+	resource_size_t irqtx;
+	resource_size_t irqrts;
+};
+struct platform_device *__init imx_add_imx_uart_3irq(
+		const struct imx_imx_uart_3irq_data *data,
 		const struct imxuart_platform_data *pdata);
-struct platform_device *__init imx_add_imx_uart_1irq(int id,
-		resource_size_t iobase, resource_size_t iosize,
-		resource_size_t irq,
+
+struct imx_imx_uart_1irq_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx_uart_1irq(
+		const struct imx_imx_uart_1irq_data *data,
 		const struct imxuart_platform_data *pdata);
 
 #include <mach/mxc_nand.h>
-struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
-		int irq, const struct mxc_nand_platform_data *pdata);
-struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
-		int irq, const struct mxc_nand_platform_data *pdata);
+struct imx_mxc_nand_data {
+	/*
+	 * id is traditionally 0, but -1 is more appropriate.  We use -1 for new
+	 * machines but don't change existing devices as the nand device usually
+	 * appears in the kernel command line to pass its partitioning.
+	 */
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t axibase;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_mxc_nand(
+		const struct imx_mxc_nand_data *data,
+		const struct mxc_nand_platform_data *pdata);
 
 #include <mach/spi.h>
-struct platform_device *__init imx_add_spi_imx(int id,
-		resource_size_t iobase, resource_size_t iosize, int irq,
+struct imx_spi_imx_data {
+	const char *devid;
+	int id;
+	resource_size_t iobase;
+	resource_size_t iosize;
+	int irq;
+};
+struct platform_device *__init imx_add_spi_imx(
+		const struct imx_spi_imx_data *data,
 		const struct spi_imx_master *pdata);
+
+#include <mach/esdhc.h>
+struct imx_esdhc_imx_data {
+	int id;
+	resource_size_t iobase;
+	resource_size_t irq;
+};
+struct platform_device *__init imx_add_esdhc(
+		const struct imx_esdhc_imx_data *data,
+		const struct esdhc_platform_data *pdata);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/dma.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/dma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_DMA_H__
+#define __ASM_ARCH_MXC_DMA_H__
+
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+
+/*
+ * This enumerates peripheral types. Used for SDMA.
+ */
+enum sdma_peripheral_type {
+	IMX_DMATYPE_SSI,	/* MCU domain SSI */
+	IMX_DMATYPE_SSI_SP,	/* Shared SSI */
+	IMX_DMATYPE_MMC,	/* MMC */
+	IMX_DMATYPE_SDHC,	/* SDHC */
+	IMX_DMATYPE_UART,	/* MCU domain UART */
+	IMX_DMATYPE_UART_SP,	/* Shared UART */
+	IMX_DMATYPE_FIRI,	/* FIRI */
+	IMX_DMATYPE_CSPI,	/* MCU domain CSPI */
+	IMX_DMATYPE_CSPI_SP,	/* Shared CSPI */
+	IMX_DMATYPE_SIM,	/* SIM */
+	IMX_DMATYPE_ATA,	/* ATA */
+	IMX_DMATYPE_CCM,	/* CCM */
+	IMX_DMATYPE_EXT,	/* External peripheral */
+	IMX_DMATYPE_MSHC,	/* Memory Stick Host Controller */
+	IMX_DMATYPE_MSHC_SP,	/* Shared Memory Stick Host Controller */
+	IMX_DMATYPE_DSP,	/* DSP */
+	IMX_DMATYPE_MEMORY,	/* Memory */
+	IMX_DMATYPE_FIFO_MEMORY,/* FIFO type Memory */
+	IMX_DMATYPE_SPDIF,	/* SPDIF */
+	IMX_DMATYPE_IPU_MEMORY,	/* IPU Memory */
+	IMX_DMATYPE_ASRC,	/* ASRC */
+	IMX_DMATYPE_ESAI,	/* ESAI */
+};
+
+enum imx_dma_prio {
+	DMA_PRIO_HIGH = 0,
+	DMA_PRIO_MEDIUM = 1,
+	DMA_PRIO_LOW = 2
+};
+
+struct imx_dma_data {
+	int dma_request; /* DMA request line */
+	enum sdma_peripheral_type peripheral_type;
+	int priority;
+};
+
+static inline int imx_dma_is_ipu(struct dma_chan *chan)
+{
+	return !strcmp(dev_name(chan->device->dev), "ipu-core");
+}
+
+static inline int imx_dma_is_general_purpose(struct dma_chan *chan)
+{
+	return !strcmp(dev_name(chan->device->dev), "imx-sdma") ||
+		!strcmp(dev_name(chan->device->dev), "imx-dma");
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/esdhc.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/esdhc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/esdhc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/esdhc.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010 Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef __ASM_ARCH_IMX_ESDHC_H
+#define __ASM_ARCH_IMX_ESDHC_H
+
+struct esdhc_platform_data {
+	unsigned int wp_gpio;	/* write protect pin */
+};
+#endif /* __ASM_ARCH_IMX_ESDHC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/eukrea-baseboards.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,19 +28,22 @@
  * its own devices, it calls baseboard's init function.
  * TODO: Add your own baseboard init function and call it from
  * inside eukrea_cpuimx25_init() eukrea_cpuimx27_init()
- * eukrea_cpuimx35_init() or eukrea_cpuimx51_init().
+ * eukrea_cpuimx35_init() eukrea_cpuimx51_init()
+ * or eukrea_cpuimx51sd_init().
  *
  * This example here is for the development board. Refer
  * mach-mx25/eukrea_mbimxsd-baseboard.c for cpuimx25
  * mach-imx/eukrea_mbimx27-baseboard.c for cpuimx27
  * mach-mx3/eukrea_mbimxsd-baseboard.c for cpuimx35
  * mach-mx5/eukrea_mbimx51-baseboard.c for cpuimx51
+ * mach-mx5/eukrea_mbimxsd-baseboard.c for cpuimx51sd
  */
 
 extern void eukrea_mbimxsd25_baseboard_init(void);
 extern void eukrea_mbimx27_baseboard_init(void);
 extern void eukrea_mbimxsd35_baseboard_init(void);
 extern void eukrea_mbimx51_baseboard_init(void);
+extern void eukrea_mbimxsd51_baseboard_init(void);
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/iomux-mx51.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/iomux-mx51.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/iomux-mx51.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/iomux-mx51.h	2011-01-04 19:50:19.000000000 -0500
@@ -45,6 +45,20 @@
 				PAD_CTL_PKE | PAD_CTL_HYS)
 #define MX51_GPIO_PAD_CTRL		(PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \
 				PAD_CTL_SRE_FAST)
+#define MX51_GPIO_PAD_CTRL_2	(PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \
+					PAD_CTL_PUS_100K_UP)
+#define MX51_ECSPI_PAD_CTRL	(PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \
+				PAD_CTL_SRE_FAST)
+#define MX51_SDHCI_PAD_CTRL	(PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \
+				PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_SRE_FAST | \
+				PAD_CTL_DVS)
+
+#define MX51_PAD_CTRL_1	(PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \
+					PAD_CTL_PUE | PAD_CTL_PKE | PAD_CTL_HYS)
+#define MX51_PAD_CTRL_2	(PAD_CTL_HYS | PAD_CTL_PKE)
+#define MX51_PAD_CTRL_3	(PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
+#define MX51_PAD_CTRL_4	(PAD_CTL_DVS | PAD_CTL_HYS | PAD_CTL_PKE)
+#define MX51_PAD_CTRL_5	(PAD_CTL_DVS | PAD_CTL_DSE_HIGH)
 
 /*
  * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode>
@@ -106,14 +120,20 @@
 #define MX51_PAD_EIM_EB0__EIM_EB0               IOMUX_PAD(0x460, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_EB1__EIM_EB1               IOMUX_PAD(0x464, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_EB2__GPIO_2_22             IOMUX_PAD(0x468, 0x0d4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB2__FEC_MDIO		IOMUX_PAD(0x468, 0x0d4, 3, 0x0,   0, MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
 #define MX51_PAD_EIM_EB3__GPIO_2_23             IOMUX_PAD(0x46c, 0x0d8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB3__FEC_RDAT1		IOMUX_PAD(0x46c, 0x0d8, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_OE__GPIO_2_24              IOMUX_PAD(0x470, 0x0dc, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS0__GPIO_2_25             IOMUX_PAD(0x474, 0x0e0, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS1__GPIO_2_26             IOMUX_PAD(0x478, 0x0e4, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS2__GPIO_2_27             IOMUX_PAD(0x47c, 0x0e8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS2__FEC_RDAT2		IOMUX_PAD(0x47c, 0x0e8, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS3__GPIO_2_28             IOMUX_PAD(0x480, 0x0ec, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS3__FEC_RDAT3		IOMUX_PAD(0x480, 0x0ec, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS4__GPIO_2_29             IOMUX_PAD(0x484, 0x0f0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS4__FEC_RX_ER		IOMUX_PAD(0x484, 0x0f0, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS5__GPIO_2_30             IOMUX_PAD(0x488, 0x0f4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS5__FEC_CRS		IOMUX_PAD(0x488, 0x0f4, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_DTACK__GPIO_2_31           IOMUX_PAD(0x48c, 0x0f8, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_LBA__GPIO_3_1              IOMUX_PAD(0x494, 0x0FC, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CRE__GPIO_3_2              IOMUX_PAD(0x4A0, 0x100, 1, 0x0,   0, NO_PAD_CTRL)
@@ -126,18 +146,32 @@
 #define MX51_PAD_NANDF_RB0__GPIO_3_8            IOMUX_PAD(0x4F8, 0x11C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__GPIO_3_9            IOMUX_PAD(0x4FC, 0x120, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__GPIO_3_10           IOMUX_PAD(0x500, 0x124, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__ECSPI2_SCLK         IOMUX_PAD(0x500, 0x124, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__FEC_COL		IOMUX_PAD(0x500, 0x124, 1, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_NANDF_RB3__GPIO_3_11           IOMUX_PAD(0x504, 0x128, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__ECSPI2_MISO         IOMUX_PAD(0x504, 0x128, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__FEC_RXCLK		IOMUX_PAD(0x504, 0x128, 1, 0x0,   0, MX51_PAD_CTRL_2)
+#define MX51_PAD_NANDF_RB6__FEC_RDAT0		IOMUX_PAD(0x5DC, 0x134, 1, 0x0,   0, MX51_PAD_CTRL_4)
+#define MX51_PAD_NANDF_RB7__FEC_TDAT0		IOMUX_PAD(0x5E0, 0x138, 1, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_GPIO_NAND__GPIO_3_12           IOMUX_PAD(0x514, 0x12C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS0__GPIO_3_16           IOMUX_PAD(0x518, 0x130, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS1__GPIO_3_17           IOMUX_PAD(0x51C, 0x134, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS2__GPIO_3_18           IOMUX_PAD(0x520, 0x138, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS2__FEC_TX_ER		IOMUX_PAD(0x520, 0x138, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS3__GPIO_3_19           IOMUX_PAD(0x524, 0x13C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS3__FEC_MDC		IOMUX_PAD(0x524, 0x13C, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS4__GPIO_3_20           IOMUX_PAD(0x528, 0x140, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS4__FEC_TDAT1		IOMUX_PAD(0x528, 0x140, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS5__GPIO_3_21           IOMUX_PAD(0x52C, 0x144, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS5__FEC_TDAT2		IOMUX_PAD(0x52C, 0x144, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS6__GPIO_3_22           IOMUX_PAD(0x530, 0x148, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS6__FEC_TDAT3		IOMUX_PAD(0x530, 0x148, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS7__GPIO_3_23           IOMUX_PAD(0x534, 0x14C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS7__FEC_TX_EN		IOMUX_PAD(0x534, 0x14C, 1, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_RDY_INT__GPIO_3_24       IOMUX_PAD(0x538, 0x150, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK	IOMUX_PAD(0x538, 0x150, 1, 0x0,   0, MX51_PAD_CTRL_4)
 #define MX51_PAD_NANDF_D15__GPIO_3_25           IOMUX_PAD(0x53C, 0x154, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D15__ECSPI2_MOSI         IOMUX_PAD(0x53C, 0x154, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_NANDF_D14__GPIO_3_26           IOMUX_PAD(0x540, 0x158, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_D13__GPIO_3_27           IOMUX_PAD(0x544, 0x15C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_D12__GPIO_3_28           IOMUX_PAD(0x548, 0x160, 3, 0x0,   0, NO_PAD_CTRL)
@@ -185,15 +219,25 @@
 #define MX51_PAD_I2C1_CLK__HSI2C_CLK		IOMUX_PAD(0x5E8, 0x1F8, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_I2C1_DAT__GPIO_4_17            IOMUX_PAD(0x5EC, 0x1FC, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_I2C1_DAT__HSI2C_DAT		IOMUX_PAD(0x5EC, 0x1FC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_TXD__AUD3_BB_TXD       IOMUX_PAD(0x5F0, 0x200, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_TXD__GPIO_4_18         IOMUX_PAD(0x5F0, 0x200, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_RXD__AUD3_BB_RXD       IOMUX_PAD(0x5F4, 0x204, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_RXD__GPIO_4_19         IOMUX_PAD(0x5F4, 0x204, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_CK__AUD3_BB_CK         IOMUX_PAD(0x5F8, 0x208, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_CK__GPIO_4_20          IOMUX_PAD(0x5F8, 0x208, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_FS__AUD3_BB_FS         IOMUX_PAD(0x5FC, 0x20C, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_FS__GPIO_4_21          IOMUX_PAD(0x5FC, 0x20C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI        IOMUX_PAD(0x600, 0x210, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_MOSI__GPIO_4_22          IOMUX_PAD(0x600, 0x210, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MISO__ECSPI1_MISO        IOMUX_PAD(0x604, 0x214, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_MISO__GPIO_4_23          IOMUX_PAD(0x604, 0x214, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS0__ECSPI1_SS0          IOMUX_PAD(0x608, 0x218, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SS0__GPIO_4_24           IOMUX_PAD(0x608, 0x218, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS1__ECSPI1_SS1          IOMUX_PAD(0x60C, 0x21C, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SS1__GPIO_4_25           IOMUX_PAD(0x60C, 0x21C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_RDY__ECSPI1_RDY          IOMUX_PAD(0x610, 0x220, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_RDY__GPIO_4_26           IOMUX_PAD(0x610, 0x220, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK        IOMUX_PAD(0x614, 0x224, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SCLK__GPIO_4_27          IOMUX_PAD(0x614, 0x224, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_UART1_RXD__UART1_RXD           IOMUX_PAD(0x618, 0x228, 0, 0x9e4, 0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
 #define MX51_PAD_UART1_TXD__UART1_TXD           IOMUX_PAD(0x61C, 0x22C, 0, 0x0,   0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
@@ -236,14 +280,14 @@
 #define MX51_PAD_USBH1_DATA6__USBH1_DATA6       IOMUX_PAD(0x6A0, 0x2A0, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
 #define MX51_PAD_USBH1_DATA7__USBH1_DATA7       IOMUX_PAD(0x6A4, 0x2A4, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
 #define MX51_PAD_DI1_PIN11__GPIO_3_0            IOMUX_PAD(0x6A8, 0x2A8, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN12__GPIO_3_1            IOMUX_PAD(0x6AC, 0x2AC, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN13__GPIO_3_2            IOMUX_PAD(0x6B0, 0x2B0, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_D0_CS__GPIO_3_3            IOMUX_PAD(0x6B4, 0x2B4, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_D1_CS__GPIO_3_4            IOMUX_PAD(0x6B8, 0x2B8, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_DIN__GPIO_3_5       IOMUX_PAD(0x6BC, 0x2BC, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_DIO__GPIO_3_6       IOMUX_PAD(0x6C0, 0x2C0, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_CLK__GPIO_3_7       IOMUX_PAD(0x6C4, 0x2C4, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_RS__GPIO_3_8        IOMUX_PAD(0x6C8, 0x2C8, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN12__GPIO_3_1            IOMUX_PAD(0x6AC, 0x2AC, 4, 0x978, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN13__GPIO_3_2            IOMUX_PAD(0x6B0, 0x2B0, 4, 0x97c, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D0_CS__GPIO_3_3            IOMUX_PAD(0x6B4, 0x2B4, 4, 0x980, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D1_CS__GPIO_3_4            IOMUX_PAD(0x6B8, 0x2B8, 4, 0x984, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIN__GPIO_3_5       IOMUX_PAD(0x6BC, 0x2BC, 4, 0x988, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIO__GPIO_3_6       IOMUX_PAD(0x6C0, 0x2C0, 4, 0x98c, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_CLK__GPIO_3_7       IOMUX_PAD(0x6C4, 0x2C4, 4, 0x990, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_RS__GPIO_3_8        IOMUX_PAD(0x6C8, 0x2C8, 4, 0x994, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT0__DISP1_DAT0         IOMUX_PAD(0x6CC, 0x2CC, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT1__DISP1_DAT1         IOMUX_PAD(0x6D0, 0x2D0, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT2__DISP1_DAT2         IOMUX_PAD(0x6D4, 0x2D4, 0, 0x0,   0, NO_PAD_CTRL)
@@ -294,32 +338,50 @@
 #define MX51_PAD_DISP2_DAT13__DISP2_DAT13       IOMUX_PAD(0x790, 0x388, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT14__DISP2_DAT14       IOMUX_PAD(0x794, 0x38C, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT15__DISP2_DAT15       IOMUX_PAD(0x798, 0x390, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CMD__SD1_CMD               IOMUX_PAD(0x79C, 0x394, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CLK__SD1_CLK               IOMUX_PAD(0x7A0, 0x398, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA0__SD1_DATA0           IOMUX_PAD(0x7A4, 0x39C, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA1__SD1_DATA1           IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA2__SD1_DATA2           IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA3__SD1_DATA3           IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_0__GPIO_1_0		IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_1__GPIO_1_1		IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CMD__SD2_CMD               IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CLK__SD2_CLK               IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA0__SD2_DATA0           IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA1__SD2_DATA1           IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA2__SD2_DATA2           IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA3__SD2_DATA3           IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_2__GPIO_1_2		IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CMD__SD1_CMD		IOMUX_PAD(0x79C, 0x394, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_CMD__AUD5_RXFS             IOMUX_PAD(0x79C, 0x394, 1, 0x8e0, 1, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CLK__SD1_CLK		IOMUX_PAD(0x7A0, 0x398, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD1_CLK__AUD5_RXC              IOMUX_PAD(0x7A0, 0x398, 1, 0x8dc, 1, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA0__SD1_DATA0		IOMUX_PAD(0x7A4, 0x39C, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA0__AUD5_TXD            IOMUX_PAD(0x7A4, 0x39C, 1, 0x8d8, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__SD1_DATA1		IOMUX_PAD(0x7A8, 0x3A0, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__AUD5_RXD            IOMUX_PAD(0x7A8, 0x3A0, 1, 0x8d4, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__SD1_DATA2		IOMUX_PAD(0x7AC, 0x3A4, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__AUD5_TXC            IOMUX_PAD(0x7AC, 0x3A4, 1, 0x8e4, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__SD1_DATA3		IOMUX_PAD(0x7B0, 0x3A8, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__AUD5_TXFS           IOMUX_PAD(0x7B0, 0x3A8, 1, 0x8e8, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD2_CMD__SD2_CMD		IOMUX_PAD(0x7BC, 0x3B4, IOMUX_CONFIG_SION, 0x0, 1, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_CLK__SD2_CLK		IOMUX_PAD(0x7C0, 0x3B8, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD2_DATA0__SD2_DATA0		IOMUX_PAD(0x7C4, 0x3BC, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__SD2_DATA1		IOMUX_PAD(0x7C8, 0x3C0, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__SD2_DATA2		IOMUX_PAD(0x7CC, 0x3C4, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA3__SD2_DATA3		IOMUX_PAD(0x7D0, 0x3C8, IOMUX_CONFIG_SION, 0x0, 0, \
+							MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_GPIO_1_0__GPIO_1_0		IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_1__GPIO_1_1		IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_2__GPIO_1_2		IOMUX_PAD(0x7D4, 0x3CC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_2__I2C2_SCL		IOMUX_PAD(0x7D4, 0x3CC, (2 | IOMUX_CONFIG_SION), \
 							0x9b8,   3, MX51_I2C_PAD_CTRL)
-#define MX51_PAD_GPIO_1_3__GPIO_1_3		IOMUX_PAD(0x7D8, 0x3D0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_3__GPIO_1_3		IOMUX_PAD(0x7D8, 0x3D0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_3__I2C2_SDA		IOMUX_PAD(0x7D8, 0x3D0, (2 | IOMUX_CONFIG_SION), \
 							0x9bc,   3, MX51_I2C_PAD_CTRL)
 #define MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ	IOMUX_PAD(0x7FC, 0x3D4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_4__GPIO_1_4		IOMUX_PAD(0x804, 0x3D8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_5__GPIO_1_5		IOMUX_PAD(0x808, 0x3DC, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_6__GPIO_1_6		IOMUX_PAD(0x80C, 0x3E0, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_7__GPIO_1_7		IOMUX_PAD(0x810, 0x3E4, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_8__GPIO_1_8		IOMUX_PAD(0x814, 0x3E8, 0, 0x0,   1, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_9__GPIO_1_9		IOMUX_PAD(0x818, 0x3EC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_4__GPIO_1_4		IOMUX_PAD(0x804, 0x3D8, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_5__GPIO_1_5		IOMUX_PAD(0x808, 0x3DC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_6__GPIO_1_6		IOMUX_PAD(0x80C, 0x3E0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_7__GPIO_1_7		IOMUX_PAD(0x810, 0x3E4, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_8__GPIO_1_8		IOMUX_PAD(0x814, 0x3E8, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_9__GPIO_1_9		IOMUX_PAD(0x818, 0x3EC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 
 #endif /* __MACH_IOMUX_MX51_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/iram.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/iram.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/iram.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/iram.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/errno.h>
+
+#ifdef CONFIG_IRAM_ALLOC
+
+int __init iram_init(unsigned long base, unsigned long size);
+void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr);
+void iram_free(unsigned long dma_addr, unsigned int size);
+
+#else
+
+static inline int __init iram_init(unsigned long base, unsigned long size)
+{
+	return -ENOMEM;
+}
+
+static inline void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr)
+{
+	return NULL;
+}
+
+static inline void iram_free(unsigned long base, unsigned long size) {}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx21.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx21.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx21.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx21.h	2011-01-04 19:50:19.000000000 -0500
@@ -120,7 +120,7 @@
 #define MX21_INT_GPT1		26
 #define MX21_INT_WDOG		27
 #define MX21_INT_PCMCIA		28
-#define MX21_INT_NANDFC		29
+#define MX21_INT_NFC		29
 #define MX21_INT_BMI		30
 #define MX21_INT_CSI		31
 #define MX21_INT_DMACH0		32
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx25.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx25.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx25.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx25.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,8 +50,11 @@
 #define MX25_SSI1_BASE_ADDR		0x50034000
 #define MX25_NFC_BASE_ADDR		0xbb000000
 #define MX25_DRYICE_BASE_ADDR		0x53ffc000
+#define MX25_ESDHC1_BASE_ADDR		0x53fb4000
+#define MX25_ESDHC2_BASE_ADDR		0x53fb8000
 #define MX25_LCDC_BASE_ADDR		0x53fbc000
 #define MX25_KPP_BASE_ADDR		0x43fa8000
+#define MX25_SDMA_BASE_ADDR		0x53fd4000
 #define MX25_OTG_BASE_ADDR		0x53ff4000
 #define MX25_CSI_BASE_ADDR		0x53ff8000
 
@@ -59,6 +62,8 @@
 #define MX25_INT_I2C1		3
 #define MX25_INT_I2C2		4
 #define MX25_INT_UART4		5
+#define MX25_INT_ESDHC2		8
+#define MX25_INT_ESDHC1		9
 #define MX25_INT_I2C3		10
 #define MX25_INT_SSI2		11
 #define MX25_INT_SSI1		12
@@ -69,7 +74,8 @@
 #define MX25_INT_KPP		24
 #define MX25_INT_DRYICE		25
 #define MX25_INT_UART2		32
-#define MX25_INT_NANDFC		33
+#define MX25_INT_NFC		33
+#define MX25_INT_SDMA		34
 #define MX25_INT_LCDC		39
 #define MX25_INT_UART5		40
 #define MX25_INT_CAN1		43
@@ -77,4 +83,13 @@
 #define MX25_INT_UART1		45
 #define MX25_INT_FEC		57
 
+#define MX25_DMA_REQ_SSI2_RX1	22
+#define MX25_DMA_REQ_SSI2_TX1	23
+#define MX25_DMA_REQ_SSI2_RX0	24
+#define MX25_DMA_REQ_SSI2_TX0	25
+#define MX25_DMA_REQ_SSI1_RX1	26
+#define MX25_DMA_REQ_SSI1_TX1	27
+#define MX25_DMA_REQ_SSI1_RX0	28
+#define MX25_DMA_REQ_SSI1_TX0	29
+
 #endif /* ifndef __MACH_MX25_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx27.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx27.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx27.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx27.h	2011-01-04 19:50:19.000000000 -0500
@@ -167,7 +167,7 @@
 #define MX27_INT_GPT1		26
 #define MX27_INT_WDOG		27
 #define MX27_INT_PCMCIA		28
-#define MX27_INT_NANDFC		29
+#define MX27_INT_NFC		29
 #define MX27_INT_ATA		30
 #define MX27_INT_CSI		31
 #define MX27_INT_DMACH0		32
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx31.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx31.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx31.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx31.h	2011-01-04 19:50:19.000000000 -0500
@@ -168,7 +168,7 @@
 #define MX31_INT_POWER_FAIL	30
 #define MX31_INT_CCM_DVFS	31
 #define MX31_INT_UART2		32
-#define MX31_INT_NANDFC		33
+#define MX31_INT_NFC		33
 #define MX31_INT_SDMA		34
 #define MX31_INT_USB1		35
 #define MX31_INT_USB2		36
@@ -197,6 +197,15 @@
 #define MX31_INT_EXT_WDOG	62
 #define MX31_INT_EXT_TV		63
 
+#define MX31_DMA_REQ_SSI2_RX1	22
+#define MX31_DMA_REQ_SSI2_TX1	23
+#define MX31_DMA_REQ_SSI2_RX0	24
+#define MX31_DMA_REQ_SSI2_TX0	25
+#define MX31_DMA_REQ_SSI1_RX1	26
+#define MX31_DMA_REQ_SSI1_TX1	27
+#define MX31_DMA_REQ_SSI1_RX0	28
+#define MX31_DMA_REQ_SSI1_TX0	29
+
 #define MX31_PROD_SIGNATURE		0x1	/* For MX31 */
 
 /* silicon revisions specific to i.MX31 */
@@ -231,7 +240,6 @@
 #define MPEG4_ENC_BASE_ADDR MX31_MPEG4_ENC_BASE_ADDR
 #define MXC_INT_MPEG4_ENCODER MX31_INT_MPEG4_ENCODER
 #define MXC_INT_FIRI MX31_INT_FIRI
-#define MXC_INT_MMC_SDHC1 MX31_INT_MMC_SDHC1
 #define MXC_INT_MBX MX31_INT_MBX
 #define MXC_INT_CSPI3 MX31_INT_CSPI3
 #define MXC_INT_SIM2 MX31_INT_SIM2
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx35.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx35.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx35.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx35.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,6 @@
 #ifndef __MACH_MX35_H__
 #define __MACH_MX35_H__
+
 /*
  * IRAM
  */
@@ -52,6 +53,9 @@
 #define MX35_GPIO3_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xa4000)
 #define MX35_SCC_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xac000)
 #define MX35_RNGA_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xb0000)
+#define MX35_ESDHC1_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xb4000)
+#define MX35_ESDHC2_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xb8000)
+#define MX35_ESDHC3_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xbc000)
 #define MX35_IPU_CTRL_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xc0000)
 #define MX35_AUDMUX_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xc4000)
 #define MX35_GPIO1_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xcc000)
@@ -63,6 +67,8 @@
 #define MX35_CAN1_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xe4000)
 #define MX35_CAN2_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xe8000)
 #define MX35_RTIC_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xec000)
+#define MX35_IIM_BASE_ADDR			(MX35_AIPS2_BASE_ADDR + 0xf0000)
+
 #define MX35_OTG_BASE_ADDR		0x53ff4000
 
 #define MX35_ROMP_BASE_ADDR		0x60000000
@@ -122,9 +128,9 @@
 #define MX35_INT_I2C3		3
 #define MX35_INT_I2C2		4
 #define MX35_INT_RTIC		6
-#define MX35_INT_MMC_SDHC1	7
-#define MX35_INT_MMC_SDHC2	8
-#define MX35_INT_MMC_SDHC3	9
+#define MX35_INT_ESDHC1		7
+#define MX35_INT_ESDHC2		8
+#define MX35_INT_ESDHC3		9
 #define MX35_INT_I2C1		10
 #define MX35_INT_SSI1		11
 #define MX35_INT_SSI2		12
@@ -145,7 +151,7 @@
 #define MX35_INT_GPT		29
 #define MX35_INT_POWER_FAIL	30
 #define MX35_INT_UART2		32
-#define MX35_INT_NANDFC		33
+#define MX35_INT_NFC		33
 #define MX35_INT_SDMA		34
 #define MX35_INT_USBHS		35
 #define MX35_INT_USBOTG		37
@@ -173,30 +179,24 @@
 #define MX35_INT_EXT_WDOG	62
 #define MX35_INT_EXT_TV		63
 
-#define MX35_PROD_SIGNATURE		0x1	/* For MX31 */
+#define MX35_DMA_REQ_SSI2_RX1   22
+#define MX35_DMA_REQ_SSI2_TX1   23
+#define MX35_DMA_REQ_SSI2_RX0   24
+#define MX35_DMA_REQ_SSI2_TX0   25
+#define MX35_DMA_REQ_SSI1_RX1   26
+#define MX35_DMA_REQ_SSI1_TX1   27
+#define MX35_DMA_REQ_SSI1_RX0   28
+#define MX35_DMA_REQ_SSI1_TX0   29
 
-/* silicon revisions specific to i.MX31 */
-#define MX35_CHIP_REV_1_0		0x10
-#define MX35_CHIP_REV_1_1		0x11
-#define MX35_CHIP_REV_1_2		0x12
-#define MX35_CHIP_REV_1_3		0x13
-#define MX35_CHIP_REV_2_0		0x20
-#define MX35_CHIP_REV_2_1		0x21
-#define MX35_CHIP_REV_2_2		0x22
-#define MX35_CHIP_REV_2_3		0x23
-#define MX35_CHIP_REV_3_0		0x30
-#define MX35_CHIP_REV_3_1		0x31
-#define MX35_CHIP_REV_3_2		0x32
+#define MX35_PROD_SIGNATURE		0x1	/* For MX31 */
 
-#define MX35_SYSTEM_REV_MIN		MX35_CHIP_REV_1_0
+#define MX35_SYSTEM_REV_MIN		MX3x_CHIP_REV_1_0
 #define MX35_SYSTEM_REV_NUM		3
 
 #ifdef IMX_NEEDS_DEPRECATED_SYMBOLS
 /* these should go away */
 #define MXC_FEC_BASE_ADDR MX35_FEC_BASE_ADDR
 #define MXC_INT_OWIRE MX35_INT_OWIRE
-#define MXC_INT_MMC_SDHC2 MX35_INT_MMC_SDHC2
-#define MXC_INT_MMC_SDHC3 MX35_INT_MMC_SDHC3
 #define MXC_INT_GPU2D MX35_INT_GPU2D
 #define MXC_INT_ASRC MX35_INT_ASRC
 #define MXC_INT_USBHS MX35_INT_USBHS
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx3x.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx3x.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx3x.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx3x.h	2011-01-04 19:50:19.000000000 -0500
@@ -240,7 +240,7 @@
 
 #define MX3x_PROD_SIGNATURE		0x1	/* For MX31 */
 
-/* silicon revisions specific to i.MX31 */
+/* silicon revisions specific to i.MX31 and i.MX35 */
 #define MX3x_CHIP_REV_1_0		0x10
 #define MX3x_CHIP_REV_1_1		0x11
 #define MX3x_CHIP_REV_1_2		0x12
@@ -267,6 +267,14 @@
 {
 	return mx31_cpu_rev;
 }
+
+extern unsigned int mx35_cpu_rev;
+extern void mx35_read_cpu_rev(void);
+
+static inline int mx35_revision(void)
+{
+	return mx35_cpu_rev;
+}
 #endif
 
 #ifdef IMX_NEEDS_DEPRECATED_SYMBOLS
@@ -389,19 +397,6 @@
 #define MXC_INT_EXT_WDOG MX3x_INT_EXT_WDOG
 #define MXC_INT_EXT_TV MX3x_INT_EXT_TV
 #define PROD_SIGNATURE MX3x_PROD_SIGNATURE
-#define CHIP_REV_1_0 MX3x_CHIP_REV_1_0
-#define CHIP_REV_1_1 MX3x_CHIP_REV_1_1
-#define CHIP_REV_1_2 MX3x_CHIP_REV_1_2
-#define CHIP_REV_1_3 MX3x_CHIP_REV_1_3
-#define CHIP_REV_2_0 MX3x_CHIP_REV_2_0
-#define CHIP_REV_2_1 MX3x_CHIP_REV_2_1
-#define CHIP_REV_2_2 MX3x_CHIP_REV_2_2
-#define CHIP_REV_2_3 MX3x_CHIP_REV_2_3
-#define CHIP_REV_3_0 MX3x_CHIP_REV_3_0
-#define CHIP_REV_3_1 MX3x_CHIP_REV_3_1
-#define CHIP_REV_3_2 MX3x_CHIP_REV_3_2
-#define SYSTEM_REV_MIN MX3x_SYSTEM_REV_MIN
-#define SYSTEM_REV_NUM MX3x_SYSTEM_REV_NUM
 #endif
 
 #endif /* ifndef __MACH_MX3x_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx51.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx51.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mx51.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mx51.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
-#ifndef __ASM_ARCH_MXC_MX51_H__
-#define __ASM_ARCH_MXC_MX51_H__
+#ifndef __MACH_MX51_H__
+#define __MACH_MX51_H__
 
 /*
  * MX51 memory map:
@@ -7,24 +7,23 @@
  *
  * Virt		Phys		Size	What
  * ---------------------------------------------------------------------------
- * FA3E0000	1FFE0000	128K	IRAM (SCCv2 RAM)
+ * fa3e0000	1ffe0000	128K	IRAM (SCCv2 RAM)
  *         	30000000	256M	GPU
  *         	40000000	512M	IPU
- * FA200000	60000000	1M	DEBUG
- * FB100000	70000000	1M	SPBA 0
- * FB000000	73F00000	1M	AIPS 1
- * FB200000	83F00000	1M	AIPS 2
- *		8FFFC000	16K	TZIC (interrupt controller)
+ * fa200000	60000000	1M	DEBUG
+ * fb100000	70000000	1M	SPBA 0
+ * fb000000	73f00000	1M	AIPS 1
+ * fb200000	83f00000	1M	AIPS 2
+ *		8fffc000	16K	TZIC (interrupt controller)
  *         	90000000	256M	CSD0 SDRAM/DDR
- *         	A0000000	256M	CSD1 SDRAM/DDR
- *         	B0000000	128M	CS0 Flash
- *         	B8000000	128M	CS1 Flash
- *         	C0000000	128M	CS2 Flash
- *         	C8000000	64M	CS3 Flash
- *         	CC000000	32M	CS4 SRAM
- *         	CE000000	32M	CS5 SRAM
- *		CFFF0000	64K	NFC (NAND Flash AXI)
- *
+ *         	a0000000	256M	CSD1 SDRAM/DDR
+ *         	b0000000	128M	CS0 Flash
+ *         	b8000000	128M	CS1 Flash
+ *         	c0000000	128M	CS2 Flash
+ *         	c8000000	64M	CS3 Flash
+ *         	cc000000	32M	CS4 SRAM
+ *         	ce000000	32M	CS5 SRAM
+ *		cfff0000	64K	NFC (NAND Flash AXI)
  */
 
 /*
@@ -36,65 +35,151 @@
 /*
  * IRAM
  */
-#define MX51_IRAM_BASE_ADDR		0x1FFE0000	/* internal ram */
-#define MX51_IRAM_BASE_ADDR_VIRT	0xFA3E0000
+#define MX51_IRAM_BASE_ADDR		0x1ffe0000	/* internal ram */
+#define MX51_IRAM_BASE_ADDR_VIRT	0xfa3e0000
 #define MX51_IRAM_PARTITIONS		16
-#define MX51_IRAM_PARTITIONS_TO1	12
 #define MX51_IRAM_SIZE		(MX51_IRAM_PARTITIONS * SZ_8K)	/* 128KB */
 
+#define MX51_GPU_BASE_ADDR		0x20000000
+#define MX51_GPU_CTRL_BASE_ADDR		0x30000000
+#define MX51_IPU_CTRL_BASE_ADDR		0x40000000
+
+#define MX51_DEBUG_BASE_ADDR		0x60000000
+#define MX51_DEBUG_BASE_ADDR_VIRT	0xfa200000
+#define MX51_DEBUG_SIZE			SZ_1M
+
+#define MX51_ETB_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x01000)
+#define MX51_ETM_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x02000)
+#define MX51_TPIU_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x03000)
+#define MX51_CTI0_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x04000)
+#define MX51_CTI1_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x05000)
+#define MX51_CTI2_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x06000)
+#define MX51_CTI3_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x07000)
+#define MX51_CORTEX_DBG_BASE_ADDR	(MX51_DEBUG_BASE_ADDR + 0x08000)
+
 /*
- * NFC
+ * SPBA global module enabled #0
  */
-#define MX51_NFC_AXI_BASE_ADDR		0xCFFF0000	/* NAND flash AXI */
-#define MX51_NFC_AXI_SIZE		SZ_64K
+#define MX51_SPBA0_BASE_ADDR		0x70000000
+#define MX51_SPBA0_BASE_ADDR_VIRT	0xfb100000
+#define MX51_SPBA0_SIZE			SZ_1M
+
+#define MX51_ESDHC1_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x04000)
+#define MX51_ESDHC2_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x08000)
+#define MX51_UART3_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x0c000)
+#define MX51_ECSPI1_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x10000)
+#define MX51_SSI2_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x14000)
+#define MX51_ESDHC3_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x20000)
+#define MX51_ESDHC4_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x24000)
+#define MX51_SPDIF_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x28000)
+#define MX51_ATA_DMA_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x30000)
+#define MX51_SLIM_DMA_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x34000)
+#define MX51_HSI2C_DMA_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x38000)
+#define MX51_SPBA_CTRL_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x3c000)
 
 /*
- * Graphics Memory of GPU
+ * AIPS 1
  */
-#define MX51_GPU_BASE_ADDR		0x20000000
-#define MX51_GPU2D_BASE_ADDR		0xD0000000
+#define MX51_AIPS1_BASE_ADDR		0x73f00000
+#define MX51_AIPS1_BASE_ADDR_VIRT	0xfb000000
+#define MX51_AIPS1_SIZE			SZ_1M
 
-#define MX51_TZIC_BASE_ADDR_TO1		0x8FFFC000
-#define MX51_TZIC_BASE_ADDR		0xE0000000
+#define MX51_OTG_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x80000)
+#define MX51_GPIO1_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x84000)
+#define MX51_GPIO2_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x88000)
+#define MX51_GPIO3_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x8c000)
+#define MX51_GPIO4_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x90000)
+#define MX51_KPP_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x94000)
+#define MX51_WDOG_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x98000)
+#define MX51_WDOG2_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0x9c000)
+#define MX51_GPT1_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xa0000)
+#define MX51_SRTC_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xa4000)
+#define MX51_IOMUXC_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xa8000)
+#define MX51_EPIT1_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xac000)
+#define MX51_EPIT2_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xb0000)
+#define MX51_PWM1_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xb4000)
+#define MX51_PWM2_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xb8000)
+#define MX51_UART1_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xbc000)
+#define MX51_UART2_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xc0000)
+#define MX51_SRC_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xd0000)
+#define MX51_CCM_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xd4000)
+#define MX51_GPC_BASE_ADDR		(MX51_AIPS1_BASE_ADDR + 0xd8000)
 
-#define MX51_DEBUG_BASE_ADDR		0x60000000
-#define MX51_DEBUG_BASE_ADDR_VIRT	0xFA200000
-#define MX51_DEBUG_SIZE			SZ_1M
-#define MX51_ETB_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00001000)
-#define MX51_ETM_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00002000)
-#define MX51_TPIU_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00003000)
-#define MX51_CTI0_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00004000)
-#define MX51_CTI1_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00005000)
-#define MX51_CTI2_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00006000)
-#define MX51_CTI3_BASE_ADDR		(MX51_DEBUG_BASE_ADDR + 0x00007000)
-#define MX51_CORTEX_DBG_BASE_ADDR	(MX51_DEBUG_BASE_ADDR + 0x00008000)
+/*
+ * AIPS 2
+ */
+#define MX51_AIPS2_BASE_ADDR		0x83f00000
+#define MX51_AIPS2_BASE_ADDR_VIRT	0xfb200000
+#define MX51_AIPS2_SIZE			SZ_1M
+
+#define MX51_PLL1_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x80000)
+#define MX51_PLL2_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x84000)
+#define MX51_PLL3_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x88000)
+#define MX51_AHBMAX_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x94000)
+#define MX51_IIM_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x98000)
+#define MX51_CSU_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0x9c000)
+#define MX51_ARM_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xa0000)
+#define MX51_OWIRE_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xa4000)
+#define MX51_FIRI_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xa8000)
+#define MX51_ECSPI2_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xac000)
+#define MX51_SDMA_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xb0000)
+#define MX51_SCC_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xb4000)
+#define MX51_ROMCP_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xb8000)
+#define MX51_RTIC_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xbc000)
+#define MX51_CSPI_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xc0000)
+#define MX51_I2C2_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xc4000)
+#define MX51_I2C1_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xc8000)
+#define MX51_SSI1_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xcc000)
+#define MX51_AUDMUX_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xd0000)
+#define MX51_M4IF_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xd8000)
+#define MX51_ESDCTL_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xd9000)
+#define MX51_WEIM_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xda000)
+#define MX51_NFC_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xdb000)
+#define MX51_EMI_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xdbf00)
+#define MX51_MIPI_HSC_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xdc000)
+#define MX51_ATA_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xe0000)
+#define MX51_SIM_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xe4000)
+#define MX51_SSI3BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xe8000)
+#define MX51_FEC_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xec000)
+#define MX51_TVE_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xf0000)
+#define MX51_VPU_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xf4000)
+#define MX51_SAHARA_BASE_ADDR		(MX51_AIPS2_BASE_ADDR + 0xf8000)
+
+#define MX51_CSD0_BASE_ADDR		0x90000000
+#define MX51_CSD1_BASE_ADDR		0xa0000000
+#define MX51_CS0_BASE_ADDR		0xb0000000
+#define MX51_CS1_BASE_ADDR		0xb8000000
+#define MX51_CS2_BASE_ADDR		0xc0000000
+#define MX51_CS3_BASE_ADDR		0xc8000000
+#define MX51_CS4_BASE_ADDR		0xcc000000
+#define MX51_CS5_BASE_ADDR		0xce000000
 
 /*
- * SPBA global module enabled #0
+ * NFC
  */
-#define MX51_SPBA0_BASE_ADDR 		0x70000000
-#define MX51_SPBA0_BASE_ADDR_VIRT	0xFB100000
-#define MX51_SPBA0_SIZE			SZ_1M
+#define MX51_NFC_AXI_BASE_ADDR		0xcfff0000	/* NAND flash AXI */
+#define MX51_NFC_AXI_SIZE		SZ_64K
 
-#define MX51_MMC_SDHC1_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x00004000)
-#define MX51_MMC_SDHC2_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x00008000)
-#define MX51_UART3_BASE_ADDR 		(MX51_SPBA0_BASE_ADDR + 0x0000C000)
-#define MX51_CSPI1_BASE_ADDR 		(MX51_SPBA0_BASE_ADDR + 0x00010000)
-#define MX51_SSI2_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x00014000)
-#define MX51_MMC_SDHC3_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x00020000)
-#define MX51_MMC_SDHC4_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x00024000)
-#define MX51_SPDIF_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x00028000)
-#define MX51_ATA_DMA_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x00030000)
-#define MX51_SLIM_DMA_BASE_ADDR		(MX51_SPBA0_BASE_ADDR + 0x00034000)
-#define MX51_HSI2C_DMA_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x00038000)
-#define MX51_SPBA_CTRL_BASE_ADDR	(MX51_SPBA0_BASE_ADDR + 0x0003C000)
+#define MX51_GPU2D_BASE_ADDR		0xd0000000
+#define MX51_TZIC_BASE_ADDR		0xe0000000
+
+#define MX51_IO_ADDRESS(x) (						\
+	IMX_IO_ADDRESS(x, MX51_IRAM) ?:					\
+	IMX_IO_ADDRESS(x, MX51_DEBUG) ?:				\
+	IMX_IO_ADDRESS(x, MX51_SPBA0) ?:				\
+	IMX_IO_ADDRESS(x, MX51_AIPS1) ?:				\
+	IMX_IO_ADDRESS(x, MX51_AIPS2))
+
+/* This is currently used in <mach/debug-macro.S>, but should go away */
+#define MX51_AIPS1_IO_ADDRESS(x)  \
+	(((x) - MX51_AIPS1_BASE_ADDR) + MX51_AIPS1_BASE_ADDR_VIRT)
 
 /*
  * defines for SPBA modules
  */
 #define MX51_SPBA_SDHC1	0x04
 #define MX51_SPBA_SDHC2	0x08
-#define MX51_SPBA_UART3	0x0C
+#define MX51_SPBA_UART3	0x0c
 #define MX51_SPBA_CSPI1	0x10
 #define MX51_SPBA_SSI2	0x14
 #define MX51_SPBA_SDHC3	0x20
@@ -103,35 +188,7 @@
 #define MX51_SPBA_ATA	0x30
 #define MX51_SPBA_SLIM	0x34
 #define MX51_SPBA_HSI2C	0x38
-#define MX51_SPBA_CTRL	0x3C
-
-/*
- * AIPS 1
- */
-#define MX51_AIPS1_BASE_ADDR 	0x73F00000
-#define MX51_AIPS1_BASE_ADDR_VIRT	0xFB000000
-#define MX51_AIPS1_SIZE		SZ_1M
-
-#define MX51_OTG_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00080000)
-#define MX51_GPIO1_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00084000)
-#define MX51_GPIO2_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00088000)
-#define MX51_GPIO3_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x0008C000)
-#define MX51_GPIO4_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00090000)
-#define MX51_KPP_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00094000)
-#define MX51_WDOG_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x00098000)
-#define MX51_WDOG2_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x0009C000)
-#define MX51_GPT1_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000A0000)
-#define MX51_SRTC_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000A4000)
-#define MX51_IOMUXC_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000A8000)
-#define MX51_EPIT1_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000AC000)
-#define MX51_EPIT2_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000B0000)
-#define MX51_PWM1_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000B4000)
-#define MX51_PWM2_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000B8000)
-#define MX51_UART1_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000BC000)
-#define MX51_UART2_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000C0000)
-#define MX51_SRC_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000D0000)
-#define MX51_CCM_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000D4000)
-#define MX51_GPC_BASE_ADDR	(MX51_AIPS1_BASE_ADDR + 0x000D8000)
+#define MX51_SPBA_CTRL	0x3c
 
 /*
  * Defines for modules using static and dynamic DMA channels
@@ -164,282 +221,186 @@
 #define MX51_MXC_DMA_CHANNEL_ATA_TX	MXC_DMA_DYNAMIC_CHANNEL
 #define MX51_MXC_DMA_CHANNEL_MEMORY	MXC_DMA_DYNAMIC_CHANNEL
 
-/*
- * AIPS 2
- */
-#define MX51_AIPS2_BASE_ADDR		0x83F00000
-#define MX51_AIPS2_BASE_ADDR_VIRT	0xFB200000
-#define MX51_AIPS2_SIZE			SZ_1M
-
-#define MX51_PLL1_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x00080000)
-#define MX51_PLL2_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x00084000)
-#define MX51_PLL3_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x00088000)
-#define MX51_AHBMAX_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x00094000)
-#define MX51_IIM_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x00098000)
-#define MX51_CSU_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x0009C000)
-#define MX51_ARM_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000A0000)
-#define MX51_OWIRE_BASE_ADDR 	(MX51_AIPS2_BASE_ADDR + 0x000A4000)
-#define MX51_FIRI_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000A8000)
-#define MX51_CSPI2_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000AC000)
-#define MX51_SDMA_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000B0000)
-#define MX51_SCC_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000B4000)
-#define MX51_ROMCP_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000B8000)
-#define MX51_RTIC_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000BC000)
-#define MX51_CSPI3_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000C0000)
-#define MX51_I2C2_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000C4000)
-#define MX51_I2C1_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000C8000)
-#define MX51_SSI1_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000CC000)
-#define MX51_AUDMUX_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000D0000)
-#define MX51_M4IF_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000D8000)
-#define MX51_ESDCTL_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000D9000)
-#define MX51_WEIM_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000DA000)
-#define MX51_NFC_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000DB000)
-#define MX51_EMI_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000DBF00)
-#define MX51_MIPI_HSC_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000DC000)
-#define MX51_ATA_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000E0000)
-#define MX51_SIM_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000E4000)
-#define MX51_SSI3BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000E8000)
-#define MX51_MXC_FEC_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000EC000)
-#define MX51_TVE_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000F0000)
-#define MX51_VPU_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000F4000)
-#define MX51_SAHARA_BASE_ADDR	(MX51_AIPS2_BASE_ADDR + 0x000F8000)
-
-/*
- * Memory regions and CS
- */
-#define MX51_GPU_CTRL_BASE_ADDR		0x30000000
-#define MX51_IPU_CTRL_BASE_ADDR		0x40000000
-#define MX51_CSD0_BASE_ADDR		0x90000000
-#define MX51_CSD1_BASE_ADDR		0xA0000000
-#define MX51_CS0_BASE_ADDR		0xB0000000
-#define MX51_CS1_BASE_ADDR		0xB8000000
-#define MX51_CS2_BASE_ADDR		0xC0000000
-#define MX51_CS3_BASE_ADDR		0xC8000000
-#define MX51_CS4_BASE_ADDR		0xCC000000
-#define MX51_CS5_BASE_ADDR		0xCE000000
-
-/* Does given address belongs to the specified memory region? */
-#define ADDRESS_IN_REGION(addr, start, size)			\
-	(((addr) >= (start)) && ((addr) < (start)+(size)))
-
-/* Does given address belongs to the specified named `module'? */
-#define MX51_IS_MODULE(addr, module)			       \
-	ADDRESS_IN_REGION(addr, MX51_ ## module ## _BASE_ADDR, \
-				MX51_ ## module ## _SIZE)
-/*
- * This macro defines the physical to virtual address mapping for all the
- * peripheral modules. It is used by passing in the physical address as x
- * and returning the virtual address. If the physical address is not mapped,
- * it returns 0xDEADBEEF
- */
-
-#define MX51_IO_ADDRESS(x)					\
-	(void __iomem *)					\
-	(MX51_IS_MODULE(x, IRAM) ? MX51_IRAM_IO_ADDRESS(x) :	\
-	MX51_IS_MODULE(x, DEBUG) ? MX51_DEBUG_IO_ADDRESS(x) :	\
-	MX51_IS_MODULE(x, SPBA0) ? MX51_SPBA0_IO_ADDRESS(x) :	\
-	MX51_IS_MODULE(x, AIPS1) ? MX51_AIPS1_IO_ADDRESS(x) :	\
-	MX51_IS_MODULE(x, AIPS2) ? MX51_AIPS2_IO_ADDRESS(x) : \
-	0xDEADBEEF)
-
-/*
- * define the address mapping macros: in physical address order
- */
-#define MX51_IRAM_IO_ADDRESS(x)  \
-	(((x) - MX51_IRAM_BASE_ADDR) + MX51_IRAM_BASE_ADDR_VIRT)
-
-#define MX51_DEBUG_IO_ADDRESS(x)  \
-	(((x) - MX51_DEBUG_BASE_ADDR) + MX51_DEBUG_BASE_ADDR_VIRT)
-
-#define MX51_SPBA0_IO_ADDRESS(x)  \
-	(((x) - MX51_SPBA0_BASE_ADDR) + MX51_SPBA0_BASE_ADDR_VIRT)
-
-#define MX51_AIPS1_IO_ADDRESS(x)  \
-	(((x) - MX51_AIPS1_BASE_ADDR) + MX51_AIPS1_BASE_ADDR_VIRT)
-
-#define MX51_AIPS2_IO_ADDRESS(x)  \
-	(((x) - MX51_AIPS2_BASE_ADDR) + MX51_AIPS2_BASE_ADDR_VIRT)
-
 #define MX51_IS_MEM_DEVICE_NONSHARED(x)		0
 
 /*
  * DMA request assignments
  */
-#define MX51_DMA_REQ_SSI3_TX1	47
-#define MX51_DMA_REQ_SSI3_RX1	46
-#define MX51_DMA_REQ_SPDIF	45
-#define MX51_DMA_REQ_UART3_TX	44
-#define MX51_DMA_REQ_UART3_RX	43
-#define MX51_DMA_REQ_SLIM_B_TX	42
-#define MX51_DMA_REQ_SDHC4	41
-#define MX51_DMA_REQ_SDHC3	40
-#define MX51_DMA_REQ_CSPI_TX	39
-#define MX51_DMA_REQ_CSPI_RX	38
-#define MX51_DMA_REQ_SSI3_TX2	37
-#define MX51_DMA_REQ_IPU	36
-#define MX51_DMA_REQ_SSI3_RX2	35
-#define MX51_DMA_REQ_EPIT2	34
-#define MX51_DMA_REQ_CTI2_1	33
-#define MX51_DMA_REQ_EMI_WR	32
-#define MX51_DMA_REQ_CTI2_0	31
-#define MX51_DMA_REQ_EMI_RD	30
-#define MX51_DMA_REQ_SSI1_TX1	29
-#define MX51_DMA_REQ_SSI1_RX1	28
-#define MX51_DMA_REQ_SSI1_TX2	27
-#define MX51_DMA_REQ_SSI1_RX2	26
-#define MX51_DMA_REQ_SSI2_TX1	25
-#define MX51_DMA_REQ_SSI2_RX1	24
-#define MX51_DMA_REQ_SSI2_TX2	23
-#define MX51_DMA_REQ_SSI2_RX2	22
-#define MX51_DMA_REQ_SDHC2	21
-#define MX51_DMA_REQ_SDHC1	20
-#define MX51_DMA_REQ_UART1_TX	19
-#define MX51_DMA_REQ_UART1_RX	18
-#define MX51_DMA_REQ_UART2_TX	17
-#define MX51_DMA_REQ_UART2_RX	16
-#define MX51_DMA_REQ_GPU	15
-#define MX51_DMA_REQ_EXTREQ1	14
-#define MX51_DMA_REQ_FIRI_TX	13
-#define MX51_DMA_REQ_FIRI_RX	12
-#define MX51_DMA_REQ_HS_I2C_RX	11
-#define MX51_DMA_REQ_HS_I2C_TX	10
-#define MX51_DMA_REQ_CSPI2_TX	9
-#define MX51_DMA_REQ_CSPI2_RX	8
-#define MX51_DMA_REQ_CSPI1_TX	7
-#define MX51_DMA_REQ_CSPI1_RX	6
-#define MX51_DMA_REQ_SLIM_B	5
-#define MX51_DMA_REQ_ATA_TX_END	4
-#define MX51_DMA_REQ_ATA_TX	3
-#define MX51_DMA_REQ_ATA_RX	2
-#define MX51_DMA_REQ_GPC	1
-#define MX51_DMA_REQ_VPU	0
+#define MX51_DMA_REQ_VPU		0
+#define MX51_DMA_REQ_GPC		1
+#define MX51_DMA_REQ_ATA_RX		2
+#define MX51_DMA_REQ_ATA_TX		3
+#define MX51_DMA_REQ_ATA_TX_END		4
+#define MX51_DMA_REQ_SLIM_B		5
+#define MX51_DMA_REQ_CSPI1_RX		6
+#define MX51_DMA_REQ_CSPI1_TX		7
+#define MX51_DMA_REQ_CSPI2_RX		8
+#define MX51_DMA_REQ_CSPI2_TX		9
+#define MX51_DMA_REQ_HS_I2C_TX		10
+#define MX51_DMA_REQ_HS_I2C_RX		11
+#define MX51_DMA_REQ_FIRI_RX		12
+#define MX51_DMA_REQ_FIRI_TX		13
+#define MX51_DMA_REQ_EXTREQ1		14
+#define MX51_DMA_REQ_GPU		15
+#define MX51_DMA_REQ_UART2_RX		16
+#define MX51_DMA_REQ_UART2_TX		17
+#define MX51_DMA_REQ_UART1_RX		18
+#define MX51_DMA_REQ_UART1_TX		19
+#define MX51_DMA_REQ_SDHC1		20
+#define MX51_DMA_REQ_SDHC2		21
+#define MX51_DMA_REQ_SSI2_RX1		22
+#define MX51_DMA_REQ_SSI2_TX1		23
+#define MX51_DMA_REQ_SSI2_RX0		24
+#define MX51_DMA_REQ_SSI2_TX0		25
+#define MX51_DMA_REQ_SSI1_RX1		26
+#define MX51_DMA_REQ_SSI1_TX1		27
+#define MX51_DMA_REQ_SSI1_RX0		28
+#define MX51_DMA_REQ_SSI1_TX0		29
+#define MX51_DMA_REQ_EMI_RD		30
+#define MX51_DMA_REQ_CTI2_0		31
+#define MX51_DMA_REQ_EMI_WR		32
+#define MX51_DMA_REQ_CTI2_1		33
+#define MX51_DMA_REQ_EPIT2		34
+#define MX51_DMA_REQ_SSI3_RX2		35
+#define MX51_DMA_REQ_IPU		36
+#define MX51_DMA_REQ_SSI3_TX2		37
+#define MX51_DMA_REQ_CSPI_RX		38
+#define MX51_DMA_REQ_CSPI_TX		39
+#define MX51_DMA_REQ_SDHC3		40
+#define MX51_DMA_REQ_SDHC4		41
+#define MX51_DMA_REQ_SLIM_B_TX		42
+#define MX51_DMA_REQ_UART3_RX		43
+#define MX51_DMA_REQ_UART3_TX		44
+#define MX51_DMA_REQ_SPDIF		45
+#define MX51_DMA_REQ_SSI3_RX1		46
+#define MX51_DMA_REQ_SSI3_TX1		47
 
 /*
  * Interrupt numbers
  */
-#define MX51_MXC_INT_BASE	0
-#define MX51_MXC_INT_RESV0	0
-#define MX51_MXC_INT_MMC_SDHC1	1
-#define MX51_MXC_INT_MMC_SDHC2	2
-#define MX51_MXC_INT_MMC_SDHC3	3
-#define MX51_MXC_INT_MMC_SDHC4	4
-#define MX51_MXC_INT_RESV5	5
-#define MX51_MXC_INT_SDMA	6
-#define MX51_MXC_INT_IOMUX	7
-#define MX51_MXC_INT_NFC	8
-#define MX51_MXC_INT_VPU	9
-#define MX51_MXC_INT_IPU_ERR	10
-#define MX51_MXC_INT_IPU_SYN	11
-#define MX51_MXC_INT_GPU	12
-#define MX51_MXC_INT_RESV13	13
-#define MX51_MXC_INT_USB_H1	14
-#define MX51_MXC_INT_EMI	15
-#define MX51_MXC_INT_USB_H2	16
-#define MX51_MXC_INT_USB_H3	17
-#define MX51_MXC_INT_USB_OTG	18
-#define MX51_MXC_INT_SAHARA_H0	19
-#define MX51_MXC_INT_SAHARA_H1	20
-#define MX51_MXC_INT_SCC_SMN	21
-#define MX51_MXC_INT_SCC_STZ	22
-#define MX51_MXC_INT_SCC_SCM	23
-#define MX51_MXC_INT_SRTC_NTZ	24
-#define MX51_MXC_INT_SRTC_TZ	25
-#define MX51_MXC_INT_RTIC	26
-#define MX51_MXC_INT_CSU	27
-#define MX51_MXC_INT_SLIM_B	28
-#define MX51_MXC_INT_SSI1	29
-#define MX51_MXC_INT_SSI2	30
-#define MX51_MXC_INT_UART1	31
-#define MX51_MXC_INT_UART2	32
-#define MX51_MXC_INT_UART3	33
-#define MX51_MXC_INT_RESV34	34
-#define MX51_MXC_INT_RESV35	35
-#define MX51_MXC_INT_CSPI1	36
-#define MX51_MXC_INT_CSPI2	37
-#define MX51_MXC_INT_CSPI	38
-#define MX51_MXC_INT_GPT	39
-#define MX51_MXC_INT_EPIT1	40
-#define MX51_MXC_INT_EPIT2	41
-#define MX51_MXC_INT_GPIO1_INT7	42
-#define MX51_MXC_INT_GPIO1_INT6	43
-#define MX51_MXC_INT_GPIO1_INT5	44
-#define MX51_MXC_INT_GPIO1_INT4	45
-#define MX51_MXC_INT_GPIO1_INT3	46
-#define MX51_MXC_INT_GPIO1_INT2	47
-#define MX51_MXC_INT_GPIO1_INT1	48
-#define MX51_MXC_INT_GPIO1_INT0	49
-#define MX51_MXC_INT_GPIO1_LOW	50
-#define MX51_MXC_INT_GPIO1_HIGH	51
-#define MX51_MXC_INT_GPIO2_LOW	52
-#define MX51_MXC_INT_GPIO2_HIGH	53
-#define MX51_MXC_INT_GPIO3_LOW	54
-#define MX51_MXC_INT_GPIO3_HIGH	55
-#define MX51_MXC_INT_GPIO4_LOW	56
-#define MX51_MXC_INT_GPIO4_HIGH	57
-#define MX51_MXC_INT_WDOG1	58
-#define MX51_MXC_INT_WDOG2	59
-#define MX51_MXC_INT_KPP	60
-#define MX51_MXC_INT_PWM1	61
-#define MX51_MXC_INT_I2C1	62
-#define MX51_MXC_INT_I2C2	63
-#define MX51_MXC_INT_HS_I2C	64
-#define MX51_MXC_INT_RESV65	65
-#define MX51_MXC_INT_RESV66	66
-#define MX51_MXC_INT_SIM_IPB	67
-#define MX51_MXC_INT_SIM_DAT	68
-#define MX51_MXC_INT_IIM	69
-#define MX51_MXC_INT_ATA	70
-#define MX51_MXC_INT_CCM1	71
-#define MX51_MXC_INT_CCM2	72
-#define MX51_MXC_INT_GPC1	73
-#define MX51_MXC_INT_GPC2	74
-#define MX51_MXC_INT_SRC	75
-#define MX51_MXC_INT_NM		76
-#define MX51_MXC_INT_PMU	77
-#define MX51_MXC_INT_CTI_IRQ	78
-#define MX51_MXC_INT_CTI1_TG0	79
-#define MX51_MXC_INT_CTI1_TG1	80
-#define MX51_MXC_INT_MCG_ERR	81
-#define MX51_MXC_INT_MCG_TMR	82
-#define MX51_MXC_INT_MCG_FUNC	83
-#define MX51_MXC_INT_GPU2_IRQ	84
-#define MX51_MXC_INT_GPU2_BUSY	85
-#define MX51_MXC_INT_RESV86	86
-#define MX51_MXC_INT_FEC	87
-#define MX51_MXC_INT_OWIRE	88
-#define MX51_MXC_INT_CTI1_TG2	89
-#define MX51_MXC_INT_SJC	90
-#define MX51_MXC_INT_SPDIF	91
-#define MX51_MXC_INT_TVE	92
-#define MX51_MXC_INT_FIRI	93
-#define MX51_MXC_INT_PWM2	94
-#define MX51_MXC_INT_SLIM_EXP	95
-#define MX51_MXC_INT_SSI3	96
-#define MX51_MXC_INT_EMI_BOOT	97
-#define MX51_MXC_INT_CTI1_TG3	98
-#define MX51_MXC_INT_SMC_RX	99
-#define MX51_MXC_INT_VPU_IDLE	100
-#define MX51_MXC_INT_EMI_NFC	101
-#define MX51_MXC_INT_GPU_IDLE	102
+#define MX51_MXC_INT_BASE		0
+#define MX51_MXC_INT_RESV0		0
+#define MX51_INT_ESDHC1			1
+#define MX51_INT_ESDHC2			2
+#define MX51_INT_ESDHC3			3
+#define MX51_INT_ESDHC4			4
+#define MX51_MXC_INT_RESV5		5
+#define MX51_INT_SDMA			6
+#define MX51_MXC_INT_IOMUX		7
+#define MX51_INT_NFC			8
+#define MX51_MXC_INT_VPU		9
+#define MX51_MXC_INT_IPU_ERR		10
+#define MX51_MXC_INT_IPU_SYN		11
+#define MX51_MXC_INT_GPU		12
+#define MX51_MXC_INT_RESV13		13
+#define MX51_MXC_INT_USB_H1		14
+#define MX51_MXC_INT_EMI		15
+#define MX51_MXC_INT_USB_H2		16
+#define MX51_MXC_INT_USB_H3		17
+#define MX51_MXC_INT_USB_OTG		18
+#define MX51_MXC_INT_SAHARA_H0		19
+#define MX51_MXC_INT_SAHARA_H1		20
+#define MX51_MXC_INT_SCC_SMN		21
+#define MX51_MXC_INT_SCC_STZ		22
+#define MX51_MXC_INT_SCC_SCM		23
+#define MX51_MXC_INT_SRTC_NTZ		24
+#define MX51_MXC_INT_SRTC_TZ		25
+#define MX51_MXC_INT_RTIC		26
+#define MX51_MXC_INT_CSU		27
+#define MX51_MXC_INT_SLIM_B		28
+#define MX51_INT_SSI1			29
+#define MX51_INT_SSI2			30
+#define MX51_INT_UART1			31
+#define MX51_INT_UART2			32
+#define MX51_INT_UART3			33
+#define MX51_MXC_INT_RESV34		34
+#define MX51_MXC_INT_RESV35		35
+#define MX51_INT_ECSPI1			36
+#define MX51_INT_ECSPI2			37
+#define MX51_INT_CSPI			38
+#define MX51_MXC_INT_GPT		39
+#define MX51_MXC_INT_EPIT1		40
+#define MX51_MXC_INT_EPIT2		41
+#define MX51_MXC_INT_GPIO1_INT7		42
+#define MX51_MXC_INT_GPIO1_INT6		43
+#define MX51_MXC_INT_GPIO1_INT5		44
+#define MX51_MXC_INT_GPIO1_INT4		45
+#define MX51_MXC_INT_GPIO1_INT3		46
+#define MX51_MXC_INT_GPIO1_INT2		47
+#define MX51_MXC_INT_GPIO1_INT1		48
+#define MX51_MXC_INT_GPIO1_INT0		49
+#define MX51_MXC_INT_GPIO1_LOW		50
+#define MX51_MXC_INT_GPIO1_HIGH		51
+#define MX51_MXC_INT_GPIO2_LOW		52
+#define MX51_MXC_INT_GPIO2_HIGH		53
+#define MX51_MXC_INT_GPIO3_LOW		54
+#define MX51_MXC_INT_GPIO3_HIGH		55
+#define MX51_MXC_INT_GPIO4_LOW		56
+#define MX51_MXC_INT_GPIO4_HIGH		57
+#define MX51_MXC_INT_WDOG1		58
+#define MX51_MXC_INT_WDOG2		59
+#define MX51_MXC_INT_KPP		60
+#define MX51_MXC_INT_PWM1		61
+#define MX51_INT_I2C1			62
+#define MX51_INT_I2C2			63
+#define MX51_MXC_INT_HS_I2C		64
+#define MX51_MXC_INT_RESV65		65
+#define MX51_MXC_INT_RESV66		66
+#define MX51_MXC_INT_SIM_IPB		67
+#define MX51_MXC_INT_SIM_DAT		68
+#define MX51_MXC_INT_IIM		69
+#define MX51_MXC_INT_ATA		70
+#define MX51_MXC_INT_CCM1		71
+#define MX51_MXC_INT_CCM2		72
+#define MX51_MXC_INT_GPC1		73
+#define MX51_MXC_INT_GPC2		74
+#define MX51_MXC_INT_SRC		75
+#define MX51_MXC_INT_NM			76
+#define MX51_MXC_INT_PMU		77
+#define MX51_MXC_INT_CTI_IRQ		78
+#define MX51_MXC_INT_CTI1_TG0		79
+#define MX51_MXC_INT_CTI1_TG1		80
+#define MX51_MXC_INT_MCG_ERR		81
+#define MX51_MXC_INT_MCG_TMR		82
+#define MX51_MXC_INT_MCG_FUNC		83
+#define MX51_MXC_INT_GPU2_IRQ		84
+#define MX51_MXC_INT_GPU2_BUSY		85
+#define MX51_MXC_INT_RESV86		86
+#define MX51_INT_FEC			87
+#define MX51_MXC_INT_OWIRE		88
+#define MX51_MXC_INT_CTI1_TG2		89
+#define MX51_MXC_INT_SJC		90
+#define MX51_MXC_INT_SPDIF		91
+#define MX51_MXC_INT_TVE		92
+#define MX51_MXC_INT_FIRI		93
+#define MX51_MXC_INT_PWM2		94
+#define MX51_MXC_INT_SLIM_EXP		95
+#define MX51_MXC_INT_SSI3		96
+#define MX51_MXC_INT_EMI_BOOT		97
+#define MX51_MXC_INT_CTI1_TG3		98
+#define MX51_MXC_INT_SMC_RX		99
+#define MX51_MXC_INT_VPU_IDLE		100
+#define MX51_MXC_INT_EMI_NFC		101
+#define MX51_MXC_INT_GPU_IDLE		102
 
 /* silicon revisions specific to i.MX51 */
-#define MX51_CHIP_REV_1_0	0x10
-#define MX51_CHIP_REV_1_1	0x11
-#define MX51_CHIP_REV_1_2	0x12
-#define MX51_CHIP_REV_1_3	0x13
-#define MX51_CHIP_REV_2_0	0x20
-#define MX51_CHIP_REV_2_1	0x21
-#define MX51_CHIP_REV_2_2	0x22
-#define MX51_CHIP_REV_2_3	0x23
-#define MX51_CHIP_REV_3_0	0x30
-#define MX51_CHIP_REV_3_1	0x31
-#define MX51_CHIP_REV_3_2	0x32
-
-/* Mandatory defines used globally */
+#define MX51_CHIP_REV_1_0		0x10
+#define MX51_CHIP_REV_1_1		0x11
+#define MX51_CHIP_REV_1_2		0x12
+#define MX51_CHIP_REV_1_3		0x13
+#define MX51_CHIP_REV_2_0		0x20
+#define MX51_CHIP_REV_2_1		0x21
+#define MX51_CHIP_REV_2_2		0x22
+#define MX51_CHIP_REV_2_3		0x23
+#define MX51_CHIP_REV_3_0		0x30
+#define MX51_CHIP_REV_3_1		0x31
+#define MX51_CHIP_REV_3_2		0x32
 
 #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
-
 extern int mx51_revision(void);
 #endif
 
-#endif	/*  __ASM_ARCH_MXC_MX51_H__ */
+/* tape-out 1 defines */
+#define MX51_TZIC_BASE_ADDR_TO1		0x8fffc000
+
+#endif	/* ifndef __MACH_MX51_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mxc.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mxc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/mxc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/mxc.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved.
  * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
  *
  * This program is free software; you can redistribute it and/or
@@ -20,6 +20,8 @@
 #ifndef __ASM_ARCH_MXC_H__
 #define __ASM_ARCH_MXC_H__
 
+#include <linux/types.h>
+
 #ifndef __ASM_ARCH_MXC_HARDWARE_H__
 #error "Do not include directly."
 #endif
@@ -133,6 +135,15 @@
 # define cpu_is_mxc91231()	(0)
 #endif
 
+#ifndef __ASSEMBLY__
+
+struct cpu_op {
+	u32 cpu_rate;
+};
+
+extern struct cpu_op *(*get_cpu_op)(int *op);
+#endif
+
 #if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2)
 /* These are deprecated, use mx[23][157]_setup_weimcs instead. */
 #define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10))
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/sdma.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/sdma.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/sdma.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/sdma.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,17 @@
+#ifndef __MACH_MXC_SDMA_H__
+#define __MACH_MXC_SDMA_H__
+
+/**
+ * struct sdma_platform_data - platform specific data for SDMA engine
+ *
+ * @sdma_version	The version of this SDMA engine
+ * @cpu_name		used to generate the firmware name
+ * @to_version		CPU Tape out version
+ */
+struct sdma_platform_data {
+	int sdma_version;
+	char *cpu_name;
+	int to_version;
+};
+
+#endif /* __MACH_MXC_SDMA_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/system.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/system.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *  Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,8 +28,34 @@
 		mxc91231_prepare_idle();
 	}
 #endif
-
-	cpu_do_idle();
+	/* fix i.MX31 errata TLSbo65953 and i.MX35 errata ENGcm09472 */
+	if (cpu_is_mx31() || cpu_is_mx35()) {
+		unsigned long reg = 0;
+		__asm__ __volatile__(
+			/* disable I and D cache */
+			"mrc p15, 0, %0, c1, c0, 0\n"
+			"bic %0, %0, #0x00001000\n"
+			"bic %0, %0, #0x00000004\n"
+			"mcr p15, 0, %0, c1, c0, 0\n"
+			/* invalidate I cache */
+			"mov %0, #0\n"
+			"mcr p15, 0, %0, c7, c5, 0\n"
+			/* clear and invalidate D cache */
+			"mov %0, #0\n"
+			"mcr p15, 0, %0, c7, c14, 0\n"
+			/* WFI */
+			"mov %0, #0\n"
+			"mcr p15, 0, %0, c7, c0, 4\n"
+			"nop\n" "nop\n" "nop\n" "nop\n"
+			"nop\n" "nop\n" "nop\n"
+			/* enable I and D cache */
+			"mrc p15, 0, %0, c1, c0, 0\n"
+			"orr %0, %0, #0x00001000\n"
+			"orr %0, %0, #0x00000004\n"
+			"mcr p15, 0, %0, c1, c0, 0\n"
+			: "=r" (reg));
+	} else
+		cpu_do_idle();
 }
 
 void arch_reset(char mode, const char *cmd);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/uncompress.h linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/include/mach/uncompress.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/include/mach/uncompress.h	2011-01-04 19:50:19.000000000 -0500
@@ -99,6 +99,7 @@
 		uart_base = MX3X_UART2_BASE_ADDR;
 		break;
 	case MACH_TYPE_MX51_BABBAGE:
+	case MACH_TYPE_EUKREA_CPUIMX51SD:
 		uart_base = MX51_UART1_BASE_ADDR;
 		break;
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/iram_alloc.c linux-libre-2.6.37-gnu/arch/arm/plat-mxc/iram_alloc.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/iram_alloc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/iram_alloc.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+#include <mach/iram.h>
+
+static unsigned long iram_phys_base;
+static void __iomem *iram_virt_base;
+static struct gen_pool *iram_pool;
+
+static inline void __iomem *iram_phys_to_virt(unsigned long p)
+{
+	return iram_virt_base + (p - iram_phys_base);
+}
+
+void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr)
+{
+	if (!iram_pool)
+		return NULL;
+
+	*dma_addr = gen_pool_alloc(iram_pool, size);
+	pr_debug("iram alloc - %dB@0x%lX\n", size, *dma_addr);
+	if (!*dma_addr)
+		return NULL;
+	return iram_phys_to_virt(*dma_addr);
+}
+EXPORT_SYMBOL(iram_alloc);
+
+void iram_free(unsigned long addr, unsigned int size)
+{
+	if (!iram_pool)
+		return;
+
+	gen_pool_free(iram_pool, addr, size);
+}
+EXPORT_SYMBOL(iram_free);
+
+int __init iram_init(unsigned long base, unsigned long size)
+{
+	iram_phys_base = base;
+
+	iram_pool = gen_pool_create(PAGE_SHIFT, -1);
+	if (!iram_pool)
+		return -ENOMEM;
+
+	gen_pool_add(iram_pool, base, size, -1);
+	iram_virt_base = ioremap(iram_phys_base, size);
+	if (!iram_virt_base)
+		return -EIO;
+
+	pr_debug("i.MX IRAM pool: %ld KB@0x%p\n", size / 1024, iram_virt_base);
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-mxc/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -92,6 +92,18 @@
 	  data/address de-multiplexing and decode, signal level shift,
 	  interrupt control and various board functions.
 
+config HAVE_EPIT
+	bool
+
+config MXC_USE_EPIT
+	bool "Use EPIT instead of GPT"
+	depends on HAVE_EPIT
+	help
+	  Use EPIT as the system timer on systems that have it. Normally you
+	  don't have a reason to do so as the EPIT has the same features and
+	  uses the same clocks as the GPT. Anyway, on some systems the GPT
+	  may be in use for other purposes.
+
 config MXC_ULPI
 	bool
 
@@ -110,4 +122,8 @@
 config ARCH_MXC_AUDMUX_V2
 	bool
 
+config IRAM_ALLOC
+	bool
+	select GENERIC_ALLOCATOR
+
 endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-mxc/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-mxc/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-mxc/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-mxc/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -10,12 +10,15 @@
 
 obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
 obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
+obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
 obj-$(CONFIG_MXC_PWM)  += pwm.o
 obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
+obj-$(CONFIG_MXC_USE_EPIT) += epit.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
+obj-$(CONFIG_CPU_FREQ_IMX)    += cpufreq.o
 ifdef CONFIG_SND_IMX_SOC
 obj-y += ssi-fiq.o
 obj-y += ssi-fiq-ksym.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/gpio.c linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -102,6 +102,22 @@
 	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
 }
 
+static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset, int val)
+{
+	if (val)
+		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
+	else
+		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
+				  unsigned offset, int val)
+{
+	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+	__nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
 static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
 			     pin_cfg_t cfg)
 {
@@ -118,20 +134,29 @@
 		[3] /* illegal */	= "??"
 	};
 	static const char *slpmnames[] = {
-		[NMK_GPIO_SLPM_INPUT]		= "input",
-		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change",
+		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
+		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
 	};
 
 	int pin = PIN_NUM(cfg);
 	int pull = PIN_PULL(cfg);
 	int af = PIN_ALT(cfg);
 	int slpm = PIN_SLPM(cfg);
+	int output = PIN_DIR(cfg);
+	int val = PIN_VAL(cfg);
 
-	dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s\n",
-		pin, afnames[af], pullnames[pull], slpmnames[slpm]);
+	dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n",
+		pin, afnames[af], pullnames[pull], slpmnames[slpm],
+		output ? "output " : "input",
+		output ? (val ? "high" : "low") : "");
+
+	if (output)
+		__nmk_gpio_make_output(nmk_chip, offset, val);
+	else {
+		__nmk_gpio_make_input(nmk_chip, offset);
+		__nmk_gpio_set_pull(nmk_chip, offset, pull);
+	}
 
-	__nmk_gpio_make_input(nmk_chip, offset);
-	__nmk_gpio_set_pull(nmk_chip, offset, pull);
 	__nmk_gpio_set_slpm(nmk_chip, offset, slpm);
 	__nmk_gpio_set_mode(nmk_chip, offset, af);
 }
@@ -200,6 +225,10 @@
  * changed to an input (with pullup/down enabled) in sleep and deep sleep.  If
  * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
  * configured even when in sleep and deep sleep.
+ *
+ * On DB8500v2 onwards, this setting loses the previous meaning and instead
+ * indicates if wakeup detection is enabled on the pin.  Note that
+ * enable_irq_wake() will automatically enable wakeup detection.
  */
 int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
 {
@@ -367,7 +396,27 @@
 
 static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
 {
-	return nmk_gpio_irq_modify(irq, WAKE, on);
+	struct nmk_gpio_chip *nmk_chip;
+	unsigned long flags;
+	int gpio;
+
+	gpio = NOMADIK_IRQ_TO_GPIO(irq);
+	nmk_chip = get_irq_chip_data(irq);
+	if (!nmk_chip)
+		return -EINVAL;
+
+	spin_lock_irqsave(&nmk_chip->lock, flags);
+#ifdef CONFIG_ARCH_U8500
+	if (cpu_is_u8500v2()) {
+		__nmk_gpio_set_slpm(nmk_chip, gpio,
+				    on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+				       : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+	}
+#endif
+	__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+	spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+	return 0;
 }
 
 static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
@@ -495,12 +544,8 @@
 {
 	struct nmk_gpio_chip *nmk_chip =
 		container_of(chip, struct nmk_gpio_chip, chip);
-	u32 bit = 1 << offset;
 
-	if (val)
-		writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
-	else
-		writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+	__nmk_gpio_set_output(nmk_chip, offset, val);
 }
 
 static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
@@ -509,8 +554,7 @@
 	struct nmk_gpio_chip *nmk_chip =
 		container_of(chip, struct nmk_gpio_chip, chip);
 
-	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
-	nmk_gpio_set_output(chip, offset, val);
+	__nmk_gpio_make_output(nmk_chip, offset, val);
 
 	return 0;
 }
@@ -534,7 +578,7 @@
 	.can_sleep		= 0,
 };
 
-static int __init nmk_gpio_probe(struct platform_device *dev)
+static int __devinit nmk_gpio_probe(struct platform_device *dev)
 {
 	struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
 	struct nmk_gpio_chip *nmk_chip;
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/gpio.h linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/gpio.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,9 @@
 /* Sleep mode */
 enum nmk_gpio_slpm {
 	NMK_GPIO_SLPM_INPUT,
+	NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
 	NMK_GPIO_SLPM_NOCHANGE,
+	NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
 };
 
 extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/pincfg.h linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/pincfg.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/pincfg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/pincfg.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,12 +19,16 @@
  *	bit  9..10 - Alternate Function Selection
  *	bit 11..12 - Pull up/down state
  *	bit     13 - Sleep mode behaviour
+ *	bit     14 - (sleep mode) Direction
+ *	bit     15 - (sleep mode) Value (if output)
  *
  * to facilitate the definition, the following macros are provided
  *
  * PIN_CFG_DEFAULT - default config (0):
  *		     pull up/down = disabled
- *		     sleep mode = input
+ *		     sleep mode = input/wakeup
+ *		     (sleep mode) direction = input
+ *		     (sleep mode) value = low
  *
  * PIN_CFG	   - default config with alternate function
  * PIN_CFG_PULL	   - default config with alternate function and pull up/down
@@ -53,8 +57,36 @@
 #define PIN_SLPM_SHIFT		13
 #define PIN_SLPM_MASK		(0x1 << PIN_SLPM_SHIFT)
 #define PIN_SLPM(x)		(((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
-#define PIN_SLPM_INPUT		(NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
+#define PIN_SLPM_MAKE_INPUT	(NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
 #define PIN_SLPM_NOCHANGE	(NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
+/* These two replace the above in DB8500v2+ */
+#define PIN_SLPM_WAKEUP_ENABLE	(NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_WAKEUP_DISABLE	(NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+
+#define PIN_DIR_SHIFT		14
+#define PIN_DIR_MASK		(0x1 << PIN_DIR_SHIFT)
+#define PIN_DIR(x)		(((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT)
+#define PIN_DIR_INPUT		(0 << PIN_DIR_SHIFT)
+#define PIN_DIR_OUTPUT		(1 << PIN_DIR_SHIFT)
+
+#define PIN_VAL_SHIFT		15
+#define PIN_VAL_MASK		(0x1 << PIN_VAL_SHIFT)
+#define PIN_VAL(x)		(((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT)
+#define PIN_VAL_LOW		(0 << PIN_VAL_SHIFT)
+#define PIN_VAL_HIGH		(1 << PIN_VAL_SHIFT)
+
+/* Shortcuts.  Use these instead of separate DIR and VAL.  */
+#define PIN_INPUT		PIN_DIR_INPUT
+#define PIN_OUTPUT_LOW		(PIN_DIR_OUTPUT | PIN_VAL_LOW)
+#define PIN_OUTPUT_HIGH		(PIN_DIR_OUTPUT | PIN_VAL_HIGH)
+
+/*
+ * These are the same as the ones above, but should make more sense to the
+ * reader when seen along with a setting a pin to AF mode.
+ */
+#define PIN_SLPM_INPUT		PIN_INPUT
+#define PIN_SLPM_OUTPUT_LOW	PIN_OUTPUT_LOW
+#define PIN_SLPM_OUTPUT_HIGH	PIN_OUTPUT_HIGH
 
 #define PIN_CFG_DEFAULT		(PIN_PULL_NONE | PIN_SLPM_INPUT)
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/ske.h linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/ske.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/ske.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/ske.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
+ *
+ * ux500 Scroll key and Keypad Encoder (SKE) header
+ */
+
+#ifndef __SKE_H
+#define __SKE_H
+
+#include <linux/input/matrix_keypad.h>
+
+/* register definitions for SKE peripheral */
+#define SKE_CR		0x00
+#define SKE_VAL0	0x04
+#define SKE_VAL1	0x08
+#define SKE_DBCR	0x0C
+#define SKE_IMSC	0x10
+#define SKE_RIS		0x14
+#define SKE_MIS		0x18
+#define SKE_ICR		0x1C
+
+/*
+ * Keypad module
+ */
+
+/**
+ * struct keypad_platform_data - structure for platform specific data
+ * @init:	pointer to keypad init function
+ * @exit:	pointer to keypad deinitialisation function
+ * @keymap_data: matrix scan code table for keycodes
+ * @krow:	maximum number of rows
+ * @kcol:	maximum number of columns
+ * @debounce_ms: platform specific debounce time
+ * @no_autorepeat: flag for auto repetition
+ * @wakeup_enable: allow waking up the system
+ */
+struct ske_keypad_platform_data {
+	int (*init)(void);
+	int (*exit)(void);
+	const struct matrix_keymap_data *keymap_data;
+	u8 krow;
+	u8 kcol;
+	u8 debounce_ms;
+	bool no_autorepeat;
+	bool wakeup_enable;
+};
+#endif	/*__SKE_KPD_H*/
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/ste_dma40.h linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/ste_dma40.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/include/plat/ste_dma40.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/include/plat/ste_dma40.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,8 @@
 /*
- * arch/arm/plat-nomadik/include/plat/ste_dma40.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
  */
 
 
@@ -14,43 +12,25 @@
 #include <linux/dmaengine.h>
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
-#include <linux/dmaengine.h>
 
 /* dev types for memcpy */
 #define STEDMA40_DEV_DST_MEMORY (-1)
 #define	STEDMA40_DEV_SRC_MEMORY (-1)
 
-/*
- * Description of bitfields of channel_type variable is available in
- * the info structure.
- */
-
-/* Priority */
-#define STEDMA40_INFO_PRIO_TYPE_POS 2
-#define STEDMA40_HIGH_PRIORITY_CHANNEL (0x1 << STEDMA40_INFO_PRIO_TYPE_POS)
-#define STEDMA40_LOW_PRIORITY_CHANNEL (0x2 << STEDMA40_INFO_PRIO_TYPE_POS)
-
-/* Mode  */
-#define STEDMA40_INFO_CH_MODE_TYPE_POS 6
-#define STEDMA40_CHANNEL_IN_PHY_MODE (0x1 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_LOG_MODE (0x2 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-#define STEDMA40_CHANNEL_IN_OPER_MODE (0x3 << STEDMA40_INFO_CH_MODE_TYPE_POS)
-
-/* Mode options */
-#define STEDMA40_INFO_CH_MODE_OPT_POS 8
-#define STEDMA40_PCHAN_BASIC_MODE (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_MODULO_MODE (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_PCHAN_DOUBLE_DST_MODE (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_PHY_DST_LOG (0x1 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_PHS (0x2 << STEDMA40_INFO_CH_MODE_OPT_POS)
-#define STEDMA40_LCHAN_SRC_LOG_DST_LOG (0x3 << STEDMA40_INFO_CH_MODE_OPT_POS)
-
-/* Interrupt */
-#define STEDMA40_INFO_TIM_POS 10
-#define STEDMA40_NO_TIM_FOR_LINK (0x0 << STEDMA40_INFO_TIM_POS)
-#define STEDMA40_TIM_FOR_LINK (0x1 << STEDMA40_INFO_TIM_POS)
+enum stedma40_mode {
+	STEDMA40_MODE_LOGICAL = 0,
+	STEDMA40_MODE_PHYSICAL,
+	STEDMA40_MODE_OPERATION,
+};
 
-/* End of channel_type configuration */
+enum stedma40_mode_opt {
+	STEDMA40_PCHAN_BASIC_MODE = 0,
+	STEDMA40_LCHAN_SRC_LOG_DST_LOG = 0,
+	STEDMA40_PCHAN_MODULO_MODE,
+	STEDMA40_PCHAN_DOUBLE_DST_MODE,
+	STEDMA40_LCHAN_SRC_PHY_DST_LOG,
+	STEDMA40_LCHAN_SRC_LOG_DST_PHY,
+};
 
 #define STEDMA40_ESIZE_8_BIT  0x0
 #define STEDMA40_ESIZE_16_BIT 0x1
@@ -73,16 +53,14 @@
 #define STEDMA40_PSIZE_LOG_8  STEDMA40_PSIZE_PHY_8
 #define STEDMA40_PSIZE_LOG_16 STEDMA40_PSIZE_PHY_16
 
+/* Maximum number of possible physical channels */
+#define STEDMA40_MAX_PHYS 32
+
 enum stedma40_flow_ctrl {
 	STEDMA40_NO_FLOW_CTRL,
 	STEDMA40_FLOW_CTRL,
 };
 
-enum stedma40_endianess {
-	STEDMA40_LITTLE_ENDIAN,
-	STEDMA40_BIG_ENDIAN
-};
-
 enum stedma40_periph_data_width {
 	STEDMA40_BYTE_WIDTH = STEDMA40_ESIZE_8_BIT,
 	STEDMA40_HALFWORD_WIDTH = STEDMA40_ESIZE_16_BIT,
@@ -90,15 +68,8 @@
 	STEDMA40_DOUBLEWORD_WIDTH = STEDMA40_ESIZE_64_BIT
 };
 
-struct stedma40_half_channel_info {
-	enum stedma40_endianess endianess;
-	enum stedma40_periph_data_width data_width;
-	int psize;
-	enum stedma40_flow_ctrl flow_ctrl;
-};
-
 enum stedma40_xfer_dir {
-	STEDMA40_MEM_TO_MEM,
+	STEDMA40_MEM_TO_MEM = 1,
 	STEDMA40_MEM_TO_PERIPH,
 	STEDMA40_PERIPH_TO_MEM,
 	STEDMA40_PERIPH_TO_PERIPH
@@ -106,18 +77,31 @@
 
 
 /**
+ * struct stedma40_chan_cfg - dst/src channel configuration
+ *
+ * @big_endian: true if the src/dst should be read as big endian
+ * @data_width: Data width of the src/dst hardware
+ * @p_size: Burst size
+ * @flow_ctrl: Flow control on/off.
+ */
+struct stedma40_half_channel_info {
+	bool big_endian;
+	enum stedma40_periph_data_width data_width;
+	int psize;
+	enum stedma40_flow_ctrl flow_ctrl;
+};
+
+/**
  * struct stedma40_chan_cfg - Structure to be filled by client drivers.
  *
  * @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH
- * @channel_type: priority, mode, mode options and interrupt configuration.
+ * @high_priority: true if high-priority
+ * @mode: channel mode: physical, logical, or operation
+ * @mode_opt: options for the chosen channel mode
  * @src_dev_type: Src device type
  * @dst_dev_type: Dst device type
  * @src_info: Parameters for dst half channel
  * @dst_info: Parameters for dst half channel
- * @pre_transfer_data: Data to be passed on to the pre_transfer() function.
- * @pre_transfer: Callback used if needed before preparation of transfer.
- * Only called if device is set. size of bytes to transfer
- * (in case of multiple element transfer size is size of the first element).
  *
  *
  * This structure has to be filled by the client drivers.
@@ -126,15 +110,13 @@
  */
 struct stedma40_chan_cfg {
 	enum stedma40_xfer_dir			 dir;
-	unsigned int				 channel_type;
+	bool					 high_priority;
+	enum stedma40_mode			 mode;
+	enum stedma40_mode_opt			 mode_opt;
 	int					 src_dev_type;
 	int					 dst_dev_type;
 	struct stedma40_half_channel_info	 src_info;
 	struct stedma40_half_channel_info	 dst_info;
-	void					*pre_transfer_data;
-	int (*pre_transfer)			(struct dma_chan *chan,
-						 void *data,
-						 int size);
 };
 
 /**
@@ -147,7 +129,6 @@
  * @memcpy_len: length of memcpy
  * @memcpy_conf_phy: default configuration of physical channel memcpy
  * @memcpy_conf_log: default configuration of logical channel memcpy
- * @llis_per_log: number of max linked list items per logical channel
  * @disabled_channels: A vector, ending with -1, that marks physical channels
  * that are for different reasons not available for the driver.
  */
@@ -159,23 +140,10 @@
 	u32				 memcpy_len;
 	struct stedma40_chan_cfg	*memcpy_conf_phy;
 	struct stedma40_chan_cfg	*memcpy_conf_log;
-	unsigned int			 llis_per_log;
-	int				 disabled_channels[8];
+	int				 disabled_channels[STEDMA40_MAX_PHYS];
 };
 
-/**
- * setdma40_set_psize() - Used for changing the package size of an
- * already configured dma channel.
- *
- * @chan: dmaengine handle
- * @src_psize: new package side for src. (STEDMA40_PSIZE*)
- * @src_psize: new package side for dst. (STEDMA40_PSIZE*)
- *
- * returns 0 on ok, otherwise negative error number.
- */
-int stedma40_set_psize(struct dma_chan *chan,
-		       int src_psize,
-		       int dst_psize);
+#ifdef CONFIG_STE_DMA40
 
 /**
  * stedma40_filter() - Provides stedma40_chan_cfg to the
@@ -238,4 +206,21 @@
 						  direction, flags);
 }
 
+#else
+static inline bool stedma40_filter(struct dma_chan *chan, void *data)
+{
+	return false;
+}
+
+static inline struct
+dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan,
+					    dma_addr_t addr,
+					    unsigned int size,
+					    enum dma_data_direction direction,
+					    unsigned long flags)
+{
+	return NULL;
+}
+#endif
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/timer.c linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/timer.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-nomadik/timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-nomadik/timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2008 STMicroelectronics
  * Copyright (C) 2010 Alessandro Rubini
+ * Copyright (C) 2010 Linus Walleij for ST-Ericsson
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2, as
@@ -16,11 +17,13 @@
 #include <linux/clk.h>
 #include <linux/jiffies.h>
 #include <linux/err.h>
+#include <linux/cnt32_to_63.h>
+#include <linux/timer.h>
 #include <asm/mach/time.h>
 
 #include <plat/mtu.h>
 
-void __iomem *mtu_base; /* ssigned by machine code */
+void __iomem *mtu_base; /* Assigned by machine code */
 
 /*
  * Kernel assumes that sched_clock can be called early
@@ -48,16 +51,82 @@
 /*
  * Override the global weak sched_clock symbol with this
  * local implementation which uses the clocksource to get some
- * better resolution when scheduling the kernel. We accept that
- * this wraps around for now, since it is just a relative time
- * stamp. (Inspired by OMAP implementation.)
+ * better resolution when scheduling the kernel.
+ *
+ * Because the hardware timer period may be quite short
+ * (32.3 secs on the 133 MHz MTU timer selection on ux500)
+ * and because cnt32_to_63() needs to be called at least once per
+ * half period to work properly, a kernel keepwarm() timer is set up
+ * to ensure this requirement is always met.
+ *
+ * Also the sched_clock timer will wrap around at some point,
+ * here we set it to run continously for a year.
  */
+#define SCHED_CLOCK_MIN_WRAP 3600*24*365
+static struct timer_list cnt32_to_63_keepwarm_timer;
+static u32 sched_mult;
+static u32 sched_shift;
+
 unsigned long long notrace sched_clock(void)
 {
-	return clocksource_cyc2ns(nmdk_clksrc.read(
-				  &nmdk_clksrc),
-				  nmdk_clksrc.mult,
-				  nmdk_clksrc.shift);
+	u64 cycles;
+
+	if (unlikely(!mtu_base))
+		return 0;
+
+	cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0)));
+	/*
+	 * sched_mult is guaranteed to be even so will
+	 * shift out bit 63
+	 */
+	return (cycles * sched_mult) >> sched_shift;
+}
+
+/* Just kick sched_clock every so often */
+static void cnt32_to_63_keepwarm(unsigned long data)
+{
+	mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data));
+	(void) sched_clock();
+}
+
+/*
+ * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm
+ * once in half a 32bit timer wrap interval.
+ */
+static void __init nmdk_sched_clock_init(unsigned long rate)
+{
+	u32 v;
+	unsigned long delta;
+	u64 days;
+
+	/* Find the apropriate mult and shift factors */
+	clocks_calc_mult_shift(&sched_mult, &sched_shift,
+			       rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP);
+	/* We need to multiply by an even number to get rid of bit 63 */
+	if (sched_mult & 1)
+		sched_mult++;
+
+	/* Let's see what we get, take max counter and scale it */
+	days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift;
+	do_div(days, NSEC_PER_SEC);
+	do_div(days, (3600*24));
+
+	pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n",
+		(64 - sched_shift), rate, (unsigned long) days);
+
+	/*
+	 * Program a timer to kick us at half 32bit wraparound
+	 * Formula: seconds per wrap = (2^32) / f
+	 */
+	v = 0xFFFFFFFFUL / rate;
+	/* We want half of the wrap time to keep cnt32_to_63 warm */
+	v /= 2;
+	pr_debug("sched_clock: prescaled timer rate: %lu Hz, "
+		 "initialize keepwarm timer every %d seconds\n", rate, v);
+	/* Convert seconds to jiffies */
+	delta = msecs_to_jiffies(v*1000);
+	setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta);
+	mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta));
 }
 
 /* Clockevent device: use one-shot mode */
@@ -161,13 +230,15 @@
 	writel(0, mtu_base + MTU_BGLR(0));
 	writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
 
-	/* Now the scheduling clock is ready */
+	/* Now the clock source is ready */
 	nmdk_clksrc.read = nmdk_read_timer;
 
 	if (clocksource_register(&nmdk_clksrc))
 		pr_err("timer: failed to initialize clock source %s\n",
 		       nmdk_clksrc.name);
 
+	nmdk_sched_clock_init(rate);
+
 	/* Timer 1 is used for events */
 
 	clockevents_calc_mult_shift(&nmdk_clkevt, rate, MTU_MIN_RANGE);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/clock.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 
 	spin_lock_irqsave(&clockfw_lock, flags);
 	if (clk->usecount == 0) {
-		printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
+		pr_err("Trying disable clock %s with 0 usecount\n",
 		       clk->name);
 		WARN_ON(1);
 		goto out;
@@ -397,6 +397,7 @@
 	struct clk *ck;
 	unsigned long flags;
 
+	pr_info("clock: disabling unused clocks to save power\n");
 	list_for_each_entry(ck, &clocks, node) {
 		if (ck->ops == &clkops_null)
 			continue;
@@ -418,7 +419,7 @@
 int __init clk_init(struct clk_functions * custom_clocks)
 {
 	if (!custom_clocks) {
-		printk(KERN_ERR "No custom clock functions registered\n");
+		pr_err("No custom clock functions registered\n");
 		BUG();
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/common.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/common.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,38 +11,16 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/omapfb.h>
 
-#include <mach/hardware.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-
 #include <plat/common.h>
 #include <plat/board.h>
-#include <plat/control.h>
-#include <plat/mux.h>
-#include <plat/fpga.h>
-#include <plat/serial.h>
 #include <plat/vram.h>
+#include <plat/dsp.h>
 
-#include <plat/clock.h>
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-# include "../mach-omap2/sdrc.h"
-#endif
 
 #define NO_LENGTH_CHECK 0xffffffff
 
@@ -87,271 +65,5 @@
 {
 	omapfb_reserve_sdram_memblock();
 	omap_vram_reserve_sdram_memblock();
+	omap_dsp_reserve_sdram_memblock();
 }
-
-/*
- * 32KHz clocksource ... always available, on pretty most chips except
- * OMAP 730 and 1510.  Other timers could be used as clocksources, with
- * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
- * but systems won't necessarily want to spend resources that way.
- */
-
-#define OMAP16XX_TIMER_32K_SYNCHRONIZED		0xfffbc410
-
-#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
-
-#include <linux/clocksource.h>
-
-/*
- * offset_32k holds the init time counter value. It is then subtracted
- * from every counter read to achieve a counter that counts time from the
- * kernel boot (needed for sched_clock()).
- */
-static u32 offset_32k __read_mostly;
-
-#ifdef CONFIG_ARCH_OMAP16XX
-static cycle_t omap16xx_32k_read(struct clocksource *cs)
-{
-	return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
-}
-#else
-#define omap16xx_32k_read	NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2420
-static cycle_t omap2420_32k_read(struct clocksource *cs)
-{
-	return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2420_32k_read	NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-static cycle_t omap2430_32k_read(struct clocksource *cs)
-{
-	return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap2430_32k_read	NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP3
-static cycle_t omap34xx_32k_read(struct clocksource *cs)
-{
-	return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap34xx_32k_read	NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-static cycle_t omap44xx_32k_read(struct clocksource *cs)
-{
-	return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
-}
-#else
-#define omap44xx_32k_read	NULL
-#endif
-
-/*
- * Kernel assumes that sched_clock can be called early but may not have
- * things ready yet.
- */
-static cycle_t omap_32k_read_dummy(struct clocksource *cs)
-{
-	return 0;
-}
-
-static struct clocksource clocksource_32k = {
-	.name		= "32k_counter",
-	.rating		= 250,
-	.read		= omap_32k_read_dummy,
-	.mask		= CLOCKSOURCE_MASK(32),
-	.shift		= 10,
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
- * Returns current time from boot in nsecs. It's OK for this to wrap
- * around for now, as it's just a relative time stamp.
- */
-unsigned long long sched_clock(void)
-{
-	return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
-				  clocksource_32k.mult, clocksource_32k.shift);
-}
-
-/**
- * read_persistent_clock -  Return time from a persistent clock.
- *
- * Reads the time from a source which isn't disabled during PM, the
- * 32k sync timer.  Convert the cycles elapsed since last read into
- * nsecs and adds to a monotonically increasing timespec.
- */
-static struct timespec persistent_ts;
-static cycles_t cycles, last_cycles;
-void read_persistent_clock(struct timespec *ts)
-{
-	unsigned long long nsecs;
-	cycles_t delta;
-	struct timespec *tsp = &persistent_ts;
-
-	last_cycles = cycles;
-	cycles = clocksource_32k.read(&clocksource_32k);
-	delta = cycles - last_cycles;
-
-	nsecs = clocksource_cyc2ns(delta,
-				   clocksource_32k.mult, clocksource_32k.shift);
-
-	timespec_add_ns(tsp, nsecs);
-	*ts = *tsp;
-}
-
-static int __init omap_init_clocksource_32k(void)
-{
-	static char err[] __initdata = KERN_ERR
-			"%s: can't register clocksource!\n";
-
-	if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
-		struct clk *sync_32k_ick;
-
-		if (cpu_is_omap16xx())
-			clocksource_32k.read = omap16xx_32k_read;
-		else if (cpu_is_omap2420())
-			clocksource_32k.read = omap2420_32k_read;
-		else if (cpu_is_omap2430())
-			clocksource_32k.read = omap2430_32k_read;
-		else if (cpu_is_omap34xx())
-			clocksource_32k.read = omap34xx_32k_read;
-		else if (cpu_is_omap44xx())
-			clocksource_32k.read = omap44xx_32k_read;
-		else
-			return -ENODEV;
-
-		sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
-		if (sync_32k_ick)
-			clk_enable(sync_32k_ick);
-
-		clocksource_32k.mult = clocksource_hz2mult(32768,
-					    clocksource_32k.shift);
-
-		offset_32k = clocksource_32k.read(&clocksource_32k);
-
-		if (clocksource_register(&clocksource_32k))
-			printk(err, clocksource_32k.name);
-	}
-	return 0;
-}
-arch_initcall(omap_init_clocksource_32k);
-
-#endif	/* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
-
-/* Global address base setup code */
-
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-
-static void __init __omap2_set_globals(struct omap_globals *omap2_globals)
-{
-	omap2_set_globals_tap(omap2_globals);
-	omap2_set_globals_sdrc(omap2_globals);
-	omap2_set_globals_control(omap2_globals);
-	omap2_set_globals_prcm(omap2_globals);
-	omap2_set_globals_uart(omap2_globals);
-}
-
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2420)
-
-static struct omap_globals omap242x_globals = {
-	.class	= OMAP242X_CLASS,
-	.tap	= OMAP2_L4_IO_ADDRESS(0x48014000),
-	.sdrc	= OMAP2420_SDRC_BASE,
-	.sms	= OMAP2420_SMS_BASE,
-	.ctrl	= OMAP2420_CTRL_BASE,
-	.prm	= OMAP2420_PRM_BASE,
-	.cm	= OMAP2420_CM_BASE,
-	.uart1_phys	= OMAP2_UART1_BASE,
-	.uart2_phys	= OMAP2_UART2_BASE,
-	.uart3_phys	= OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_242x(void)
-{
-	__omap2_set_globals(&omap242x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP2430)
-
-static struct omap_globals omap243x_globals = {
-	.class	= OMAP243X_CLASS,
-	.tap	= OMAP2_L4_IO_ADDRESS(0x4900a000),
-	.sdrc	= OMAP243X_SDRC_BASE,
-	.sms	= OMAP243X_SMS_BASE,
-	.ctrl	= OMAP243X_CTRL_BASE,
-	.prm	= OMAP2430_PRM_BASE,
-	.cm	= OMAP2430_CM_BASE,
-	.uart1_phys	= OMAP2_UART1_BASE,
-	.uart2_phys	= OMAP2_UART2_BASE,
-	.uart3_phys	= OMAP2_UART3_BASE,
-};
-
-void __init omap2_set_globals_243x(void)
-{
-	__omap2_set_globals(&omap243x_globals);
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP3)
-
-static struct omap_globals omap3_globals = {
-	.class	= OMAP343X_CLASS,
-	.tap	= OMAP2_L4_IO_ADDRESS(0x4830A000),
-	.sdrc	= OMAP343X_SDRC_BASE,
-	.sms	= OMAP343X_SMS_BASE,
-	.ctrl	= OMAP343X_CTRL_BASE,
-	.prm	= OMAP3430_PRM_BASE,
-	.cm	= OMAP3430_CM_BASE,
-	.uart1_phys	= OMAP3_UART1_BASE,
-	.uart2_phys	= OMAP3_UART2_BASE,
-	.uart3_phys	= OMAP3_UART3_BASE,
-	.uart4_phys	= OMAP3_UART4_BASE,	/* Only on 3630 */
-};
-
-void __init omap2_set_globals_3xxx(void)
-{
-	__omap2_set_globals(&omap3_globals);
-}
-
-void __init omap3_map_io(void)
-{
-	omap2_set_globals_3xxx();
-	omap34xx_map_common_io();
-}
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4)
-static struct omap_globals omap4_globals = {
-	.class	= OMAP443X_CLASS,
-	.tap	= OMAP2_L4_IO_ADDRESS(OMAP443X_SCM_BASE),
-	.ctrl	= OMAP443X_CTRL_BASE,
-	.prm	= OMAP4430_PRM_BASE,
-	.cm	= OMAP4430_CM_BASE,
-	.cm2	= OMAP4430_CM2_BASE,
-	.uart1_phys	= OMAP4_UART1_BASE,
-	.uart2_phys	= OMAP4_UART2_BASE,
-	.uart3_phys	= OMAP4_UART3_BASE,
-	.uart4_phys	= OMAP4_UART4_BASE,
-};
-
-void __init omap2_set_globals_443x(void)
-{
-	omap2_set_globals_tap(&omap4_globals);
-	omap2_set_globals_control(&omap4_globals);
-	omap2_set_globals_prcm(&omap4_globals);
-	omap2_set_globals_uart(&omap4_globals);
-}
-#endif
-
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/counter_32k.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/counter_32k.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/counter_32k.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/counter_32k.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,184 @@
+/*
+ * OMAP 32ksynctimer/counter_32k-related code
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Copyright (C) 2010 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * NOTE: This timer is not the same timer as the old OMAP1 MPU timer.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <plat/common.h>
+#include <plat/board.h>
+
+#include <plat/clock.h>
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510.  Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#define OMAP16XX_TIMER_32K_SYNCHRONIZED		0xfffbc410
+
+#if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
+
+#include <linux/clocksource.h>
+
+/*
+ * offset_32k holds the init time counter value. It is then subtracted
+ * from every counter read to achieve a counter that counts time from the
+ * kernel boot (needed for sched_clock()).
+ */
+static u32 offset_32k __read_mostly;
+
+#ifdef CONFIG_ARCH_OMAP16XX
+static cycle_t omap16xx_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k;
+}
+#else
+#define omap16xx_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2420
+static cycle_t omap2420_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2420_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static cycle_t omap2430_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap2430_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static cycle_t omap34xx_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap34xx_32k_read	NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+static cycle_t omap44xx_32k_read(struct clocksource *cs)
+{
+	return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k;
+}
+#else
+#define omap44xx_32k_read	NULL
+#endif
+
+/*
+ * Kernel assumes that sched_clock can be called early but may not have
+ * things ready yet.
+ */
+static cycle_t omap_32k_read_dummy(struct clocksource *cs)
+{
+	return 0;
+}
+
+static struct clocksource clocksource_32k = {
+	.name		= "32k_counter",
+	.rating		= 250,
+	.read		= omap_32k_read_dummy,
+	.mask		= CLOCKSOURCE_MASK(32),
+	.shift		= 10,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+	return clocksource_cyc2ns(clocksource_32k.read(&clocksource_32k),
+				  clocksource_32k.mult, clocksource_32k.shift);
+}
+
+/**
+ * read_persistent_clock -  Return time from a persistent clock.
+ *
+ * Reads the time from a source which isn't disabled during PM, the
+ * 32k sync timer.  Convert the cycles elapsed since last read into
+ * nsecs and adds to a monotonically increasing timespec.
+ */
+static struct timespec persistent_ts;
+static cycles_t cycles, last_cycles;
+void read_persistent_clock(struct timespec *ts)
+{
+	unsigned long long nsecs;
+	cycles_t delta;
+	struct timespec *tsp = &persistent_ts;
+
+	last_cycles = cycles;
+	cycles = clocksource_32k.read(&clocksource_32k);
+	delta = cycles - last_cycles;
+
+	nsecs = clocksource_cyc2ns(delta,
+				   clocksource_32k.mult, clocksource_32k.shift);
+
+	timespec_add_ns(tsp, nsecs);
+	*ts = *tsp;
+}
+
+static int __init omap_init_clocksource_32k(void)
+{
+	static char err[] __initdata = KERN_ERR
+			"%s: can't register clocksource!\n";
+
+	if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
+		struct clk *sync_32k_ick;
+
+		if (cpu_is_omap16xx())
+			clocksource_32k.read = omap16xx_32k_read;
+		else if (cpu_is_omap2420())
+			clocksource_32k.read = omap2420_32k_read;
+		else if (cpu_is_omap2430())
+			clocksource_32k.read = omap2430_32k_read;
+		else if (cpu_is_omap34xx())
+			clocksource_32k.read = omap34xx_32k_read;
+		else if (cpu_is_omap44xx())
+			clocksource_32k.read = omap44xx_32k_read;
+		else
+			return -ENODEV;
+
+		sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
+		if (!IS_ERR(sync_32k_ick))
+			clk_enable(sync_32k_ick);
+
+		clocksource_32k.mult = clocksource_hz2mult(32768,
+					    clocksource_32k.shift);
+
+		offset_32k = clocksource_32k.read(&clocksource_32k);
+
+		if (clocksource_register(&clocksource_32k))
+			printk(err, clocksource_32k.name);
+	}
+	return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif	/* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/cpu-omap.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/cpu-omap.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/cpu-omap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/cpu-omap.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,7 @@
 
 /* TODO: Add support for SDRAM timing changes */
 
-int omap_verify_speed(struct cpufreq_policy *policy)
+static int omap_verify_speed(struct cpufreq_policy *policy)
 {
 	if (freq_table)
 		return cpufreq_frequency_table_verify(policy, freq_table);
@@ -58,7 +58,7 @@
 	return 0;
 }
 
-unsigned int omap_getspeed(unsigned int cpu)
+static unsigned int omap_getspeed(unsigned int cpu)
 {
 	unsigned long rate;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/devices.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/devices.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,13 +15,13 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/memblock.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
 #include <plat/tc.h>
-#include <plat/control.h>
 #include <plat/board.h>
 #include <plat/mmc.h>
 #include <mach/gpio.h>
@@ -272,6 +272,37 @@
 static inline void omap_init_wdt(void) {}
 #endif
 
+#if defined(CONFIG_TIDSPBRIDGE) || defined(CONFIG_TIDSPBRIDGE_MODULE)
+
+static phys_addr_t omap_dsp_phys_mempool_base;
+
+void __init omap_dsp_reserve_sdram_memblock(void)
+{
+	phys_addr_t size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
+	phys_addr_t paddr;
+
+	if (!size)
+		return;
+
+	paddr = memblock_alloc(size, SZ_1M);
+	if (!paddr) {
+		pr_err("%s: failed to reserve %x bytes\n",
+				__func__, size);
+		return;
+	}
+	memblock_free(paddr, size);
+	memblock_remove(paddr, size);
+
+	omap_dsp_phys_mempool_base = paddr;
+}
+
+phys_addr_t omap_dsp_get_mempool_base(void)
+{
+	return omap_dsp_phys_mempool_base;
+}
+EXPORT_SYMBOL(omap_dsp_get_mempool_base);
+#endif
+
 /*
  * This gets called after board-specific INIT_MACHINE, and initializes most
  * on-chip peripherals accessible on this board (except for few like USB):
@@ -300,7 +331,6 @@
 	omap_init_rng();
 	omap_init_mcpdm();
 	omap_init_uwire();
-	omap_init_wdt();
 	return 0;
 }
 arch_initcall(omap_init_devices);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/dma.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/dma.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #include <asm/system.h>
 #include <mach/hardware.h>
@@ -996,11 +997,17 @@
 	l = dma_read(CCR(lch));
 
 	/*
-	 * Errata: On ES2.0 BUFFERING disable must be set.
-	 * This will always fail on ES1.0
+	 * Errata: Inter Frame DMA buffering issue (All OMAP2420 and
+	 * OMAP2430ES1.0): DMA will wrongly buffer elements if packing and
+	 * bursting is enabled. This might result in data gets stalled in
+	 * FIFO at the end of the block.
+	 * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
+	 * guarantee no data will stay in the DMA FIFO in case inter frame
+	 * buffering occurs.
 	 */
-	if (cpu_is_omap24xx())
-		l |= OMAP_DMA_CCR_EN;
+	if (cpu_is_omap2420() ||
+	    (cpu_is_omap2430() && (omap_type() == OMAP2430_REV_ES1_0)))
+		l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
 
 	l |= OMAP_DMA_CCR_EN;
 	dma_write(l, CCR(lch));
@@ -1018,8 +1025,39 @@
 		dma_write(0, CICR(lch));
 
 	l = dma_read(CCR(lch));
-	l &= ~OMAP_DMA_CCR_EN;
-	dma_write(l, CCR(lch));
+	/* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+	if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+		int i = 0;
+		u32 sys_cf;
+
+		/* Configure No-Standby */
+		l = dma_read(OCP_SYSCONFIG);
+		sys_cf = l;
+		l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+		l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+		dma_write(l , OCP_SYSCONFIG);
+
+		l = dma_read(CCR(lch));
+		l &= ~OMAP_DMA_CCR_EN;
+		dma_write(l, CCR(lch));
+
+		/* Wait for sDMA FIFO drain */
+		l = dma_read(CCR(lch));
+		while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+					OMAP_DMA_CCR_WR_ACTIVE))) {
+			udelay(5);
+			i++;
+			l = dma_read(CCR(lch));
+		}
+		if (i >= 100)
+			printk(KERN_ERR "DMA drain did not complete on "
+					"lch %d\n", lch);
+		/* Restore OCP_SYSCONFIG */
+		dma_write(sys_cf, OCP_SYSCONFIG);
+	} else {
+		l &= ~OMAP_DMA_CCR_EN;
+		dma_write(l, CCR(lch));
+	}
 
 	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
 		int next_lch, cur_lch = lch;
@@ -1945,6 +1983,8 @@
 
 	dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR(ch));
 	dma_write(1 << ch, IRQSTATUS_L0);
+	/* read back the register to flush the write */
+	dma_read(IRQSTATUS_L0);
 
 	/* If the ch is not chained then chain_id will be -1 */
 	if (dma_chan[ch].chain_id != -1) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/dmtimer.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/dmtimer.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/dmtimer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/dmtimer.c	2011-01-04 19:50:19.000000000 -0500
@@ -581,7 +581,7 @@
 	 * When the functional clock disappears, too quick writes seem
 	 * to cause an abort. XXX Is this still necessary?
 	 */
-	__delay(150000);
+	__delay(300000);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/fb.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/fb.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/fb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/fb.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,8 @@
 #include <plat/board.h>
 #include <plat/sram.h>
 
+#include "fb.h"
+
 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
 
 static struct omapfb_platform_data omapfb_config;
@@ -94,7 +96,7 @@
  * Get the region_idx`th region from board config/ATAG and convert it to
  * our internal format.
  */
-static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+static int __init get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
 {
 	const struct omap_fbmem_config	*conf;
 	u32				paddr;
@@ -126,7 +128,7 @@
 	 * type = 0 && paddr = 0, a default don't care case maps to
 	 * the SDRAM type.
 	 */
-	if (rg->type || (!rg->type && !rg->paddr))
+	if (rg->type || !rg->paddr)
 		return 0;
 	if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
 		rg->type = mem_type;
@@ -173,11 +175,7 @@
 
 static int valid_sdram(unsigned long addr, unsigned long size)
 {
-	struct memblock_property res;
-
-	res.base = addr;
-	res.size = size;
-	return !memblock_find(&res) && res.base == addr && res.size == size;
+	return memblock_is_region_memory(addr, size);
 }
 
 static int reserve_sdram(unsigned long addr, unsigned long size)
@@ -262,7 +260,7 @@
  * this point, since the driver built as a module would have problem with
  * freeing / reallocating the regions.
  */
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
 				  unsigned long sram_vstart,
 				  unsigned long sram_size,
 				  unsigned long pstart_avail,
@@ -336,7 +334,7 @@
 	omapfb_config.ctrl_platform_data = data;
 }
 
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
 {
 	const struct omap_lcd_config *conf;
 
@@ -381,7 +379,7 @@
 	omapfb_config = *data;
 }
 
-static inline int omap_init_fb(void)
+static int __init omap_init_fb(void)
 {
 	return platform_device_register(&omap_fb_device);
 }
@@ -392,7 +390,7 @@
 {
 }
 
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
 				  unsigned long sram_vstart,
 				  unsigned long sram_size,
 				  unsigned long start_avail,
@@ -411,7 +409,7 @@
 {
 }
 
-unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+unsigned long __init omapfb_reserve_sram(unsigned long sram_pstart,
 				  unsigned long sram_vstart,
 				  unsigned long sram_size,
 				  unsigned long start_avail,
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/fb.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/fb.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/fb.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/fb.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,10 @@
+#ifndef __PLAT_OMAP_FB_H__
+#define __PLAT_OMAP_FB_H__
+
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+					 unsigned long sram_vstart,
+					 unsigned long sram_size,
+					 unsigned long pstart_avail,
+					 unsigned long size_avail);
+
+#endif /* __PLAT_OMAP_FB_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/gpio.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -2084,9 +2084,10 @@
 
 	for (i = min; i < gpio_bank_count; i++) {
 		struct gpio_bank *bank = &gpio_bank[i];
-		u32 l1, l2;
+		u32 l1 = 0, l2 = 0;
+		int j;
 
-		if (bank->dbck_enable_mask)
+		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 			clk_disable(bank->dbck);
 
 		if (power_state > PWRDM_POWER_OFF)
@@ -2151,9 +2152,10 @@
 		min = 1;
 	for (i = min; i < gpio_bank_count; i++) {
 		struct gpio_bank *bank = &gpio_bank[i];
-		u32 l, gen, gen0, gen1;
+		u32 l = 0, gen, gen0, gen1;
+		int j;
 
-		if (bank->dbck_enable_mask)
+		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 			clk_enable(bank->dbck);
 
 		if (!workaround_enabled)
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/common.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/common.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/common.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/common.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 	unsigned long   sdrc;           /* SDRAM Controller */
 	unsigned long   sms;            /* SDRAM Memory Scheduler */
 	unsigned long   ctrl;           /* System Control Module */
+	unsigned long   ctrl_pad;	/* PAD Control Module */
 	unsigned long   prm;            /* Power and Reset Management */
 	unsigned long   cm;             /* Clock Management */
 	unsigned long   cm2;
@@ -66,7 +67,6 @@
 void omap2_set_globals_sdrc(struct omap_globals *);
 void omap2_set_globals_control(struct omap_globals *);
 void omap2_set_globals_prcm(struct omap_globals *);
-void omap2_set_globals_uart(struct omap_globals *);
 
 void omap3_map_io(void);
 
@@ -91,7 +91,8 @@
 })
 
 extern struct device *omap2_get_mpuss_device(void);
-extern struct device *omap2_get_dsp_device(void);
+extern struct device *omap2_get_iva_device(void);
 extern struct device *omap2_get_l3_device(void);
+extern struct device *omap4_get_dsp_device(void);
 
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/control.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/control.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/control.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/control.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,381 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/control.h
- *
- * OMAP2/3/4 System Control Module definitions
- *
- * Copyright (C) 2007-2009 Texas Instruments, Inc.
- * Copyright (C) 2007-2008 Nokia Corporation
- *
- * Written by Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_CONTROL_H
-#define __ASM_ARCH_CONTROL_H
-
-#include <mach/io.h>
-
-#ifndef __ASSEMBLY__
-#define OMAP242X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
-#else
-#define OMAP242X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
-#define OMAP243X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
-#define OMAP343X_CTRL_REGADDR(reg)					\
-		OMAP2_L4_IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
-#endif /* __ASSEMBLY__ */
-
-/*
- * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
- * OMAP24XX and OMAP34XX.
- */
-
-/* Control submodule offsets */
-
-#define OMAP2_CONTROL_INTERFACE		0x000
-#define OMAP2_CONTROL_PADCONFS		0x030
-#define OMAP2_CONTROL_GENERAL		0x270
-#define OMAP343X_CONTROL_MEM_WKUP	0x600
-#define OMAP343X_CONTROL_PADCONFS_WKUP	0xa00
-#define OMAP343X_CONTROL_GENERAL_WKUP	0xa60
-
-/* Control register offsets - read/write with omap_ctrl_{read,write}{bwl}() */
-
-#define OMAP2_CONTROL_SYSCONFIG		(OMAP2_CONTROL_INTERFACE + 0x10)
-
-/* CONTROL_GENERAL register offsets common to OMAP2 & 3 */
-#define OMAP2_CONTROL_DEVCONF0		(OMAP2_CONTROL_GENERAL + 0x0004)
-#define OMAP2_CONTROL_MSUSPENDMUX_0	(OMAP2_CONTROL_GENERAL + 0x0020)
-#define OMAP2_CONTROL_MSUSPENDMUX_1	(OMAP2_CONTROL_GENERAL + 0x0024)
-#define OMAP2_CONTROL_MSUSPENDMUX_2	(OMAP2_CONTROL_GENERAL + 0x0028)
-#define OMAP2_CONTROL_MSUSPENDMUX_3	(OMAP2_CONTROL_GENERAL + 0x002c)
-#define OMAP2_CONTROL_MSUSPENDMUX_4	(OMAP2_CONTROL_GENERAL + 0x0030)
-#define OMAP2_CONTROL_MSUSPENDMUX_5	(OMAP2_CONTROL_GENERAL + 0x0034)
-#define OMAP2_CONTROL_SEC_CTRL		(OMAP2_CONTROL_GENERAL + 0x0040)
-#define OMAP2_CONTROL_RPUB_KEY_H_0	(OMAP2_CONTROL_GENERAL + 0x0090)
-#define OMAP2_CONTROL_RPUB_KEY_H_1	(OMAP2_CONTROL_GENERAL + 0x0094)
-#define OMAP2_CONTROL_RPUB_KEY_H_2	(OMAP2_CONTROL_GENERAL + 0x0098)
-#define OMAP2_CONTROL_RPUB_KEY_H_3	(OMAP2_CONTROL_GENERAL + 0x009c)
-
-/* 242x-only CONTROL_GENERAL register offsets */
-#define OMAP242X_CONTROL_DEVCONF	OMAP2_CONTROL_DEVCONF0 /* match TRM */
-#define OMAP242X_CONTROL_OCM_RAM_PERM	(OMAP2_CONTROL_GENERAL + 0x0068)
-
-/* 243x-only CONTROL_GENERAL register offsets */
-/* CONTROL_IVA2_BOOT{ADDR,MOD} are at the same place on 343x - noted below */
-#define OMAP243X_CONTROL_DEVCONF1	(OMAP2_CONTROL_GENERAL + 0x0078)
-#define OMAP243X_CONTROL_CSIRXFE	(OMAP2_CONTROL_GENERAL + 0x007c)
-#define OMAP243X_CONTROL_IVA2_BOOTADDR	(OMAP2_CONTROL_GENERAL + 0x0190)
-#define OMAP243X_CONTROL_IVA2_BOOTMOD	(OMAP2_CONTROL_GENERAL + 0x0194)
-#define OMAP243X_CONTROL_IVA2_GEMCFG	(OMAP2_CONTROL_GENERAL + 0x0198)
-#define OMAP243X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x0230)
-
-/* 24xx-only CONTROL_GENERAL register offsets */
-#define OMAP24XX_CONTROL_DEBOBS		(OMAP2_CONTROL_GENERAL + 0x0000)
-#define OMAP24XX_CONTROL_EMU_SUPPORT	(OMAP2_CONTROL_GENERAL + 0x0008)
-#define OMAP24XX_CONTROL_SEC_TEST	(OMAP2_CONTROL_GENERAL + 0x0044)
-#define OMAP24XX_CONTROL_PSA_CTRL	(OMAP2_CONTROL_GENERAL + 0x0048)
-#define OMAP24XX_CONTROL_PSA_CMD	(OMAP2_CONTROL_GENERAL + 0x004c)
-#define OMAP24XX_CONTROL_PSA_VALUE	(OMAP2_CONTROL_GENERAL + 0x0050)
-#define OMAP24XX_CONTROL_SEC_EMU	(OMAP2_CONTROL_GENERAL + 0x0060)
-#define OMAP24XX_CONTROL_SEC_TAP	(OMAP2_CONTROL_GENERAL + 0x0064)
-#define OMAP24XX_CONTROL_OCM_PUB_RAM_ADD	(OMAP2_CONTROL_GENERAL + 0x006c)
-#define OMAP24XX_CONTROL_EXT_SEC_RAM_START_ADD	(OMAP2_CONTROL_GENERAL + 0x0070)
-#define OMAP24XX_CONTROL_EXT_SEC_RAM_STOP_ADD	(OMAP2_CONTROL_GENERAL + 0x0074)
-#define OMAP24XX_CONTROL_SEC_STATUS		(OMAP2_CONTROL_GENERAL + 0x0080)
-#define OMAP24XX_CONTROL_SEC_ERR_STATUS		(OMAP2_CONTROL_GENERAL + 0x0084)
-#define OMAP24XX_CONTROL_STATUS			(OMAP2_CONTROL_GENERAL + 0x0088)
-#define OMAP24XX_CONTROL_GENERAL_PURPOSE_STATUS	(OMAP2_CONTROL_GENERAL + 0x008c)
-#define OMAP24XX_CONTROL_RAND_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00a0)
-#define OMAP24XX_CONTROL_RAND_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00a4)
-#define OMAP24XX_CONTROL_RAND_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00a8)
-#define OMAP24XX_CONTROL_RAND_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00ac)
-#define OMAP24XX_CONTROL_CUST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00b0)
-#define OMAP24XX_CONTROL_CUST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00b4)
-#define OMAP24XX_CONTROL_TEST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00c0)
-#define OMAP24XX_CONTROL_TEST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00c4)
-#define OMAP24XX_CONTROL_TEST_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00c8)
-#define OMAP24XX_CONTROL_TEST_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00cc)
-#define OMAP24XX_CONTROL_TEST_KEY_4	(OMAP2_CONTROL_GENERAL + 0x00d0)
-#define OMAP24XX_CONTROL_TEST_KEY_5	(OMAP2_CONTROL_GENERAL + 0x00d4)
-#define OMAP24XX_CONTROL_TEST_KEY_6	(OMAP2_CONTROL_GENERAL + 0x00d8)
-#define OMAP24XX_CONTROL_TEST_KEY_7	(OMAP2_CONTROL_GENERAL + 0x00dc)
-#define OMAP24XX_CONTROL_TEST_KEY_8	(OMAP2_CONTROL_GENERAL + 0x00e0)
-#define OMAP24XX_CONTROL_TEST_KEY_9	(OMAP2_CONTROL_GENERAL + 0x00e4)
-
-#define OMAP343X_CONTROL_PADCONF_SYSNIRQ (OMAP2_CONTROL_INTERFACE + 0x01b0)
-
-/* 34xx-only CONTROL_GENERAL register offsets */
-#define OMAP343X_CONTROL_PADCONF_OFF	(OMAP2_CONTROL_GENERAL + 0x0000)
-#define OMAP343X_CONTROL_MEM_DFTRW0	(OMAP2_CONTROL_GENERAL + 0x0008)
-#define OMAP343X_CONTROL_MEM_DFTRW1	(OMAP2_CONTROL_GENERAL + 0x000c)
-#define OMAP343X_CONTROL_DEVCONF1	(OMAP2_CONTROL_GENERAL + 0x0068)
-#define OMAP343X_CONTROL_CSIRXFE		(OMAP2_CONTROL_GENERAL + 0x006c)
-#define OMAP343X_CONTROL_SEC_STATUS		(OMAP2_CONTROL_GENERAL + 0x0070)
-#define OMAP343X_CONTROL_SEC_ERR_STATUS		(OMAP2_CONTROL_GENERAL + 0x0074)
-#define OMAP343X_CONTROL_SEC_ERR_STATUS_DEBUG	(OMAP2_CONTROL_GENERAL + 0x0078)
-#define OMAP343X_CONTROL_STATUS			(OMAP2_CONTROL_GENERAL + 0x0080)
-#define OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS	(OMAP2_CONTROL_GENERAL + 0x0084)
-#define OMAP343X_CONTROL_RPUB_KEY_H_4	(OMAP2_CONTROL_GENERAL + 0x00a0)
-#define OMAP343X_CONTROL_RAND_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00a8)
-#define OMAP343X_CONTROL_RAND_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00ac)
-#define OMAP343X_CONTROL_RAND_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00b0)
-#define OMAP343X_CONTROL_RAND_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00b4)
-#define OMAP343X_CONTROL_TEST_KEY_0	(OMAP2_CONTROL_GENERAL + 0x00c8)
-#define OMAP343X_CONTROL_TEST_KEY_1	(OMAP2_CONTROL_GENERAL + 0x00cc)
-#define OMAP343X_CONTROL_TEST_KEY_2	(OMAP2_CONTROL_GENERAL + 0x00d0)
-#define OMAP343X_CONTROL_TEST_KEY_3	(OMAP2_CONTROL_GENERAL + 0x00d4)
-#define OMAP343X_CONTROL_TEST_KEY_4	(OMAP2_CONTROL_GENERAL + 0x00d8)
-#define OMAP343X_CONTROL_TEST_KEY_5	(OMAP2_CONTROL_GENERAL + 0x00dc)
-#define OMAP343X_CONTROL_TEST_KEY_6	(OMAP2_CONTROL_GENERAL + 0x00e0)
-#define OMAP343X_CONTROL_TEST_KEY_7	(OMAP2_CONTROL_GENERAL + 0x00e4)
-#define OMAP343X_CONTROL_TEST_KEY_8	(OMAP2_CONTROL_GENERAL + 0x00e8)
-#define OMAP343X_CONTROL_TEST_KEY_9	(OMAP2_CONTROL_GENERAL + 0x00ec)
-#define OMAP343X_CONTROL_TEST_KEY_10	(OMAP2_CONTROL_GENERAL + 0x00f0)
-#define OMAP343X_CONTROL_TEST_KEY_11	(OMAP2_CONTROL_GENERAL + 0x00f4)
-#define OMAP343X_CONTROL_TEST_KEY_12	(OMAP2_CONTROL_GENERAL + 0x00f8)
-#define OMAP343X_CONTROL_TEST_KEY_13	(OMAP2_CONTROL_GENERAL + 0x00fc)
-#define OMAP343X_CONTROL_IVA2_BOOTADDR	(OMAP2_CONTROL_GENERAL + 0x0190)
-#define OMAP343X_CONTROL_IVA2_BOOTMOD	(OMAP2_CONTROL_GENERAL + 0x0194)
-#define OMAP343X_CONTROL_DEBOBS(i)	(OMAP2_CONTROL_GENERAL + 0x01B0 \
-					+ ((i) >> 1) * 4 + (!((i) & 1)) * 2)
-#define OMAP343X_CONTROL_PROG_IO0	(OMAP2_CONTROL_GENERAL + 0x01D4)
-#define OMAP343X_CONTROL_PROG_IO1	(OMAP2_CONTROL_GENERAL + 0x01D8)
-#define OMAP343X_CONTROL_DSS_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E0)
-#define OMAP343X_CONTROL_CORE_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E4)
-#define OMAP343X_CONTROL_PER_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01E8)
-#define OMAP343X_CONTROL_USBHOST_DPLL_SPREADING	(OMAP2_CONTROL_GENERAL + 0x01EC)
-#define OMAP343X_CONTROL_PBIAS_LITE	(OMAP2_CONTROL_GENERAL + 0x02B0)
-#define OMAP343X_CONTROL_TEMP_SENSOR	(OMAP2_CONTROL_GENERAL + 0x02B4)
-#define OMAP343X_CONTROL_SRAMLDO4	(OMAP2_CONTROL_GENERAL + 0x02B8)
-#define OMAP343X_CONTROL_SRAMLDO5	(OMAP2_CONTROL_GENERAL + 0x02C0)
-#define OMAP343X_CONTROL_CSI		(OMAP2_CONTROL_GENERAL + 0x02C4)
-
-/* AM35XX only CONTROL_GENERAL register offsets */
-#define AM35XX_CONTROL_MSUSPENDMUX_6    (OMAP2_CONTROL_GENERAL + 0x0038)
-#define AM35XX_CONTROL_DEVCONF2         (OMAP2_CONTROL_GENERAL + 0x0310)
-#define AM35XX_CONTROL_DEVCONF3         (OMAP2_CONTROL_GENERAL + 0x0314)
-#define AM35XX_CONTROL_CBA_PRIORITY     (OMAP2_CONTROL_GENERAL + 0x0320)
-#define AM35XX_CONTROL_LVL_INTR_CLEAR   (OMAP2_CONTROL_GENERAL + 0x0324)
-#define AM35XX_CONTROL_IP_SW_RESET      (OMAP2_CONTROL_GENERAL + 0x0328)
-#define AM35XX_CONTROL_IPSS_CLK_CTRL    (OMAP2_CONTROL_GENERAL + 0x032C)
-
-/* 34xx PADCONF register offsets */
-#define OMAP343X_PADCONF_ETK(i)		(OMAP2_CONTROL_PADCONFS + 0x5a8 + \
-						(i)*2)
-#define OMAP343X_PADCONF_ETK_CLK	OMAP343X_PADCONF_ETK(0)
-#define OMAP343X_PADCONF_ETK_CTL	OMAP343X_PADCONF_ETK(1)
-#define OMAP343X_PADCONF_ETK_D0		OMAP343X_PADCONF_ETK(2)
-#define OMAP343X_PADCONF_ETK_D1		OMAP343X_PADCONF_ETK(3)
-#define OMAP343X_PADCONF_ETK_D2		OMAP343X_PADCONF_ETK(4)
-#define OMAP343X_PADCONF_ETK_D3		OMAP343X_PADCONF_ETK(5)
-#define OMAP343X_PADCONF_ETK_D4		OMAP343X_PADCONF_ETK(6)
-#define OMAP343X_PADCONF_ETK_D5		OMAP343X_PADCONF_ETK(7)
-#define OMAP343X_PADCONF_ETK_D6		OMAP343X_PADCONF_ETK(8)
-#define OMAP343X_PADCONF_ETK_D7		OMAP343X_PADCONF_ETK(9)
-#define OMAP343X_PADCONF_ETK_D8		OMAP343X_PADCONF_ETK(10)
-#define OMAP343X_PADCONF_ETK_D9		OMAP343X_PADCONF_ETK(11)
-#define OMAP343X_PADCONF_ETK_D10	OMAP343X_PADCONF_ETK(12)
-#define OMAP343X_PADCONF_ETK_D11	OMAP343X_PADCONF_ETK(13)
-#define OMAP343X_PADCONF_ETK_D12	OMAP343X_PADCONF_ETK(14)
-#define OMAP343X_PADCONF_ETK_D13	OMAP343X_PADCONF_ETK(15)
-#define OMAP343X_PADCONF_ETK_D14	OMAP343X_PADCONF_ETK(16)
-#define OMAP343X_PADCONF_ETK_D15	OMAP343X_PADCONF_ETK(17)
-
-/* 34xx GENERAL_WKUP regist offsets */
-#define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
-						0x008 + (i))
-#define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
-#define OMAP343X_CONTROL_WKUP_DEBOBS1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x00C)
-#define OMAP343X_CONTROL_WKUP_DEBOBS2 (OMAP343X_CONTROL_GENERAL_WKUP + 0x010)
-#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
-#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
-
-/* 34xx D2D idle-related pins, handled by PM core */
-#define OMAP3_PADCONF_SAD2D_MSTANDBY   0x250
-#define OMAP3_PADCONF_SAD2D_IDLEACK    0x254
-
-/* 44xx control status register offset */
-#define OMAP44XX_CONTROL_STATUS		0x2c4
-
-/* 44xx-only CONTROL_GENERAL register offsets */
-#define OMAP44XX_CONTROL_MMC1			0x628
-#define OMAP44XX_CONTROL_PBIAS_LITE		0x600
-/*
- * REVISIT: This list of registers is not comprehensive - there are more
- * that should be added.
- */
-
-/*
- * Control module register bit defines - these should eventually go into
- * their own regbits file.  Some of these will be complicated, depending
- * on the device type (general-purpose, emulator, test, secure, bad, other)
- * and the security mode (secure, non-secure, don't care)
- */
-/* CONTROL_DEVCONF0 bits */
-#define OMAP2_MMCSDIO1ADPCLKISEL	(1 << 24) /* MMC1 loop back clock */
-#define OMAP24XX_USBSTANDBYCTRL		(1 << 15)
-#define OMAP2_MCBSP2_CLKS_MASK		(1 << 6)
-#define OMAP2_MCBSP1_CLKS_MASK		(1 << 2)
-
-/* CONTROL_DEVCONF1 bits */
-#define OMAP243X_MMC1_ACTIVE_OVERWRITE	(1 << 31)
-#define OMAP2_MMCSDIO2ADPCLKISEL	(1 << 6) /* MMC2 loop back clock */
-#define OMAP2_MCBSP5_CLKS_MASK		(1 << 4) /* > 242x */
-#define OMAP2_MCBSP4_CLKS_MASK		(1 << 2) /* > 242x */
-#define OMAP2_MCBSP3_CLKS_MASK		(1 << 0) /* > 242x */
-
-/* CONTROL_STATUS bits */
-#define OMAP2_DEVICETYPE_MASK		(0x7 << 8)
-#define OMAP2_SYSBOOT_5_MASK		(1 << 5)
-#define OMAP2_SYSBOOT_4_MASK		(1 << 4)
-#define OMAP2_SYSBOOT_3_MASK		(1 << 3)
-#define OMAP2_SYSBOOT_2_MASK		(1 << 2)
-#define OMAP2_SYSBOOT_1_MASK		(1 << 1)
-#define OMAP2_SYSBOOT_0_MASK		(1 << 0)
-
-/* CONTROL_PBIAS_LITE bits */
-#define OMAP343X_PBIASLITESUPPLY_HIGH1	(1 << 15)
-#define OMAP343X_PBIASLITEVMODEERROR1	(1 << 11)
-#define OMAP343X_PBIASSPEEDCTRL1	(1 << 10)
-#define OMAP343X_PBIASLITEPWRDNZ1	(1 << 9)
-#define OMAP343X_PBIASLITEVMODE1	(1 << 8)
-#define OMAP343X_PBIASLITESUPPLY_HIGH0	(1 << 7)
-#define OMAP343X_PBIASLITEVMODEERROR0	(1 << 3)
-#define OMAP2_PBIASSPEEDCTRL0		(1 << 2)
-#define OMAP2_PBIASLITEPWRDNZ0		(1 << 1)
-#define OMAP2_PBIASLITEVMODE0		(1 << 0)
-
-/* CONTROL_PBIAS_LITE bits for OMAP4 */
-#define OMAP4_MMC1_PWRDNZ			(1 << 26)
-#define OMAP4_MMC1_PBIASLITE_HIZ_MODE		(1 << 25)
-#define OMAP4_MMC1_PBIASLITE_SUPPLY_HI_OUT	(1 << 24)
-#define OMAP4_MMC1_PBIASLITE_VMODE_ERROR	(1 << 23)
-#define OMAP4_MMC1_PBIASLITE_PWRDNZ		(1 << 22)
-#define OMAP4_MMC1_PBIASLITE_VMODE		(1 << 21)
-#define OMAP4_USBC1_ICUSB_PWRDNZ		(1 << 20)
-
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP0	(1 << 31)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP1	(1 << 30)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP2	(1 << 29)
-#define OMAP4_CONTROL_SDMMC1_PUSTRENGTHGRP3	(1 << 28)
-#define OMAP4_CONTROL_SDMMC1_DR0_SPEEDCTRL	(1 << 27)
-#define OMAP4_CONTROL_SDMMC1_DR1_SPEEDCTRL	(1 << 26)
-#define OMAP4_CONTROL_SDMMC1_DR2_SPEEDCTRL	(1 << 25)
-
-/* CONTROL_PROG_IO1 bits */
-#define OMAP3630_PRG_SDMMC1_SPEEDCTRL	(1 << 20)
-
-/* CONTROL_IVA2_BOOTMOD bits */
-#define OMAP3_IVA2_BOOTMOD_SHIFT	0
-#define OMAP3_IVA2_BOOTMOD_MASK		(0xf << 0)
-#define OMAP3_IVA2_BOOTMOD_IDLE		(0x1 << 0)
-
-/* CONTROL_PADCONF_X bits */
-#define OMAP3_PADCONF_WAKEUPEVENT0	(1 << 15)
-#define OMAP3_PADCONF_WAKEUPENABLE0	(1 << 14)
-
-#define OMAP343X_SCRATCHPAD_ROM		(OMAP343X_CTRL_BASE + 0x860)
-#define OMAP343X_SCRATCHPAD		(OMAP343X_CTRL_BASE + 0x910)
-#define OMAP343X_SCRATCHPAD_ROM_OFFSET	0x19C
-
-/* AM35XX_CONTROL_IPSS_CLK_CTRL bits */
-#define AM35XX_USBOTG_VBUSP_CLK_SHIFT   0
-#define AM35XX_CPGMAC_VBUSP_CLK_SHIFT   1
-#define AM35XX_VPFE_VBUSP_CLK_SHIFT     2
-#define AM35XX_HECC_VBUSP_CLK_SHIFT     3
-#define AM35XX_USBOTG_FCLK_SHIFT        8
-#define AM35XX_CPGMAC_FCLK_SHIFT        9
-#define AM35XX_VPFE_FCLK_SHIFT          10
-
-/*AM35XX CONTROL_LVL_INTR_CLEAR bits*/
-#define AM35XX_CPGMAC_C0_MISC_PULSE_CLR	BIT(0)
-#define AM35XX_CPGMAC_C0_RX_PULSE_CLR	BIT(1)
-#define AM35XX_CPGMAC_C0_RX_THRESH_CLR	BIT(2)
-#define AM35XX_CPGMAC_C0_TX_PULSE_CLR	BIT(3)
-#define AM35XX_USBOTGSS_INT_CLR		BIT(4)
-#define AM35XX_VPFE_CCDC_VD0_INT_CLR	BIT(5)
-#define AM35XX_VPFE_CCDC_VD1_INT_CLR	BIT(6)
-#define AM35XX_VPFE_CCDC_VD2_INT_CLR	BIT(7)
-
-/*AM35XX CONTROL_IP_SW_RESET bits*/
-#define AM35XX_USBOTGSS_SW_RST		BIT(0)
-#define AM35XX_CPGMACSS_SW_RST		BIT(1)
-#define AM35XX_VPFE_VBUSP_SW_RST	BIT(2)
-#define AM35XX_HECC_SW_RST		BIT(3)
-#define AM35XX_VPFE_PCLK_SW_RST		BIT(4)
-
-/*
- * CONTROL OMAP STATUS register to identify OMAP3 features
- */
-#define OMAP3_CONTROL_OMAP_STATUS	0x044c
-
-#define OMAP3_SGX_SHIFT			13
-#define OMAP3_SGX_MASK			(3 << OMAP3_SGX_SHIFT)
-#define		FEAT_SGX_FULL		0
-#define		FEAT_SGX_HALF		1
-#define		FEAT_SGX_NONE		2
-
-#define OMAP3_IVA_SHIFT			12
-#define OMAP3_IVA_MASK			(1 << OMAP3_SGX_SHIFT)
-#define		FEAT_IVA		0
-#define		FEAT_IVA_NONE		1
-
-#define OMAP3_L2CACHE_SHIFT		10
-#define OMAP3_L2CACHE_MASK		(3 << OMAP3_L2CACHE_SHIFT)
-#define		FEAT_L2CACHE_NONE	0
-#define		FEAT_L2CACHE_64KB	1
-#define		FEAT_L2CACHE_128KB	2
-#define		FEAT_L2CACHE_256KB	3
-
-#define OMAP3_ISP_SHIFT			5
-#define OMAP3_ISP_MASK			(1<< OMAP3_ISP_SHIFT)
-#define		FEAT_ISP		0
-#define		FEAT_ISP_NONE		1
-
-#define OMAP3_NEON_SHIFT		4
-#define OMAP3_NEON_MASK			(1<< OMAP3_NEON_SHIFT)
-#define		FEAT_NEON		0
-#define		FEAT_NEON_NONE		1
-
-
-#ifndef __ASSEMBLY__
-#ifdef CONFIG_ARCH_OMAP2PLUS
-extern void __iomem *omap_ctrl_base_get(void);
-extern u8 omap_ctrl_readb(u16 offset);
-extern u16 omap_ctrl_readw(u16 offset);
-extern u32 omap_ctrl_readl(u16 offset);
-extern void omap_ctrl_writeb(u8 val, u16 offset);
-extern void omap_ctrl_writew(u16 val, u16 offset);
-extern void omap_ctrl_writel(u32 val, u16 offset);
-
-extern void omap3_save_scratchpad_contents(void);
-extern void omap3_clear_scratchpad_contents(void);
-extern u32 *get_restore_pointer(void);
-extern u32 *get_es3_restore_pointer(void);
-extern u32 omap3_arm_context[128];
-extern void omap3_control_save_context(void);
-extern void omap3_control_restore_context(void);
-
-#else
-#define omap_ctrl_base_get()		0
-#define omap_ctrl_readb(x)		0
-#define omap_ctrl_readw(x)		0
-#define omap_ctrl_readl(x)		0
-#define omap_ctrl_writeb(x, y)		WARN_ON(1)
-#define omap_ctrl_writew(x, y)		WARN_ON(1)
-#define omap_ctrl_writel(x, y)		WARN_ON(1)
-#endif
-#endif	/* __ASSEMBLY__ */
-
-#endif /* __ASM_ARCH_CONTROL_H */
-
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/cpu.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/cpu.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -68,10 +68,9 @@
 #define OMAP_REVBITS_00		0x00
 #define OMAP_REVBITS_01		0x01
 #define OMAP_REVBITS_02		0x02
-#define OMAP_REVBITS_10		0x10
-#define OMAP_REVBITS_20		0x20
-#define OMAP_REVBITS_30		0x30
-#define OMAP_REVBITS_40		0x40
+#define OMAP_REVBITS_03		0x03
+#define OMAP_REVBITS_04		0x04
+#define OMAP_REVBITS_05		0x05
 
 /*
  * Get the CPU revision for OMAP devices
@@ -363,23 +362,24 @@
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS		0x24200024
-#define OMAP2420_REV_ES1_0	0x24200024
-#define OMAP2420_REV_ES2_0	0x24201024
+#define OMAP2420_REV_ES1_0	OMAP242X_CLASS
+#define OMAP2420_REV_ES2_0	(OMAP242X_CLASS | (OMAP_REVBITS_01 << 8))
 
 #define OMAP243X_CLASS		0x24300024
-#define OMAP2430_REV_ES1_0	0x24300024
+#define OMAP2430_REV_ES1_0	OMAP243X_CLASS
 
 #define OMAP343X_CLASS		0x34300034
-#define OMAP3430_REV_ES1_0	0x34300034
-#define OMAP3430_REV_ES2_0	0x34301034
-#define OMAP3430_REV_ES2_1	0x34302034
-#define OMAP3430_REV_ES3_0	0x34303034
-#define OMAP3430_REV_ES3_1	0x34304034
-#define OMAP3430_REV_ES3_1_2	0x34305034
+#define OMAP3430_REV_ES1_0	OMAP343X_CLASS
+#define OMAP3430_REV_ES2_0	(OMAP343X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3430_REV_ES2_1	(OMAP343X_CLASS | (OMAP_REVBITS_02 << 8))
+#define OMAP3430_REV_ES3_0	(OMAP343X_CLASS | (OMAP_REVBITS_03 << 8))
+#define OMAP3430_REV_ES3_1	(OMAP343X_CLASS | (OMAP_REVBITS_04 << 8))
+#define OMAP3430_REV_ES3_1_2	(OMAP343X_CLASS | (OMAP_REVBITS_05 << 8))
 
-#define OMAP3630_REV_ES1_0	0x36300034
-#define OMAP3630_REV_ES1_1	0x36300134
-#define OMAP3630_REV_ES1_2	0x36300234
+#define OMAP363X_CLASS		0x36300034
+#define OMAP3630_REV_ES1_0	OMAP363X_CLASS
+#define OMAP3630_REV_ES1_1	(OMAP363X_CLASS | (OMAP_REVBITS_01 << 8))
+#define OMAP3630_REV_ES1_2	(OMAP363X_CLASS | (OMAP_REVBITS_02 << 8))
 
 #define OMAP35XX_CLASS		0x35000034
 #define OMAP3503_REV(v)		(OMAP35XX_CLASS | (0x3503 << 16) | (v << 8))
@@ -390,7 +390,8 @@
 #define OMAP3517_REV(v)		(OMAP35XX_CLASS | (0x3517 << 16) | (v << 8))
 
 #define OMAP443X_CLASS		0x44300044
-#define OMAP4430_REV_ES1_0	0x44300044
+#define OMAP4430_REV_ES1_0	OMAP443X_CLASS
+#define OMAP4430_REV_ES2_0	0x44301044
 
 /*
  * omap_chip bits
@@ -417,10 +418,12 @@
 #define CHIP_IS_OMAP4430ES1		(1 << 8)
 #define CHIP_IS_OMAP3630ES1_1           (1 << 9)
 #define CHIP_IS_OMAP3630ES1_2           (1 << 10)
+#define CHIP_IS_OMAP4430ES2		(1 << 11)
 
 #define CHIP_IS_OMAP24XX		(CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
 
-#define CHIP_IS_OMAP4430		(CHIP_IS_OMAP4430ES1)
+#define CHIP_IS_OMAP4430		(CHIP_IS_OMAP4430ES1 | \
+						 CHIP_IS_OMAP4430ES2)
 
 /*
  * "GE" here represents "greater than or equal to" in terms of ES
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/display.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/display.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/display.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/display.h	2011-01-04 19:50:19.000000000 -0500
@@ -81,37 +81,6 @@
 	OMAP_DSS_COLOR_ARGB32	= 1 << 11, /* ARGB32 */
 	OMAP_DSS_COLOR_RGBA32	= 1 << 12, /* RGBA32 */
 	OMAP_DSS_COLOR_RGBX32	= 1 << 13, /* RGBx32 */
-
-	OMAP_DSS_COLOR_GFX_OMAP2 =
-		OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
-		OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
-		OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
-		OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
-
-	OMAP_DSS_COLOR_VID_OMAP2 =
-		OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-		OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
-		OMAP_DSS_COLOR_UYVY,
-
-	OMAP_DSS_COLOR_GFX_OMAP3 =
-		OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
-		OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
-		OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
-		OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-		OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
-		OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
-
-	OMAP_DSS_COLOR_VID1_OMAP3 =
-		OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
-		OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
-		OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
-
-	OMAP_DSS_COLOR_VID2_OMAP3 =
-		OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
-		OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
-		OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
-		OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
-		OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
 enum omap_lcd_display_type {
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dma.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dma.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -319,6 +319,8 @@
 #define OMAP34XX_DMA_USIM_TX		79	/* S_DMA_78 */
 #define OMAP34XX_DMA_USIM_RX		80	/* S_DMA_79 */
 
+#define OMAP36XX_DMA_UART4_TX		81	/* S_DMA_80 */
+#define OMAP36XX_DMA_UART4_RX		82	/* S_DMA_81 */
 /*----------------------------------------------------------------------------*/
 
 #define OMAP1_DMA_TOUT_IRQ		(1 << 0)
@@ -335,6 +337,10 @@
 #define OMAP2_DMA_MISALIGNED_ERR_IRQ	(1 << 11)
 
 #define OMAP_DMA_CCR_EN			(1 << 7)
+#define OMAP_DMA_CCR_RD_ACTIVE		(1 << 9)
+#define OMAP_DMA_CCR_WR_ACTIVE		(1 << 10)
+#define OMAP_DMA_CCR_SEL_SRC_DST_SYNC	(1 << 24)
+#define OMAP_DMA_CCR_BUFFERING_DISABLE	(1 << 25)
 
 #define OMAP_DMA_DATA_TYPE_S8		0x00
 #define OMAP_DMA_DATA_TYPE_S16		0x01
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dmtimer.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dmtimer.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dmtimer.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dmtimer.h	2011-01-04 19:50:19.000000000 -0500
@@ -45,6 +45,8 @@
 #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE	0x02
 
 struct omap_dm_timer;
+extern struct omap_dm_timer *gptimer_wakeup;
+extern struct sys_timer omap_timer;
 struct clk;
 
 int omap_dm_timer_init(void);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dsp.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dsp.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/dsp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/dsp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,31 @@
+#ifndef __OMAP_DSP_H__
+#define __OMAP_DSP_H__
+
+#include <linux/types.h>
+
+struct omap_dsp_platform_data {
+	void (*dsp_set_min_opp) (u8 opp_id);
+	u8 (*dsp_get_opp) (void);
+	void (*cpu_set_freq) (unsigned long f);
+	unsigned long (*cpu_get_freq) (void);
+	unsigned long mpu_speed[6];
+
+	/* functions to write and read PRCM registers */
+	void (*dsp_prm_write)(u32, s16 , u16);
+	u32 (*dsp_prm_read)(s16 , u16);
+	u32 (*dsp_prm_rmw_bits)(u32, u32, s16, s16);
+	void (*dsp_cm_write)(u32, s16 , u16);
+	u32 (*dsp_cm_read)(s16 , u16);
+	u32 (*dsp_cm_rmw_bits)(u32, u32, s16, s16);
+
+	phys_addr_t phys_mempool_base;
+	phys_addr_t phys_mempool_size;
+};
+
+#if defined(CONFIG_TIDSPBRIDGE) || defined(CONFIG_TIDSPBRIDGE_MODULE)
+extern void omap_dsp_reserve_sdram_memblock(void);
+#else
+static inline void omap_dsp_reserve_sdram_memblock(void) { }
+#endif
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
+ *
+ * Copyright (C) 2009 Li-Pro.Net
+ * Stephan Linz <linz@li-pro.net>
+ *
+ * Modified from arch/arm/plat-omap/include/plat/gpmc-smc91x.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPMC_SMSC911X_H__
+
+struct omap_smsc911x_platform_data {
+	int	cs;
+	int	gpio_irq;
+	int	gpio_reset;
+	u32	flags;
+};
+
+#if defined(CONFIG_SMSC911X) || \
+	defined(CONFIG_SMSC911X_MODULE)
+
+extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
+
+#else
+
+static inline void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d)
+{
+}
+
+#endif
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/i2c.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/i2c.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/i2c.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/i2c.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,8 @@
  * 02110-1301 USA
  *
  */
+#ifndef __ASM__ARCH_OMAP_I2C_H
+#define __ASM__ARCH_OMAP_I2C_H
 
 #include <linux/i2c.h>
 
@@ -36,3 +38,5 @@
 
 void __init omap1_i2c_mux_pins(int bus_id);
 void __init omap2_i2c_mux_pins(int bus_id);
+
+#endif /* __ASM__ARCH_OMAP_I2C_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/irqs.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -345,6 +345,8 @@
 #define INT_34XX_MMC3_IRQ	94
 #define INT_34XX_GPT12_IRQ	95
 
+#define INT_36XX_UART4_IRQ	80
+
 #define INT_35XX_HECC0_IRQ		24
 #define INT_35XX_HECC1_IRQ		28
 #define INT_35XX_EMAC_C0_RXTHRESH_IRQ	67
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/mcbsp.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/mcbsp.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/mcbsp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/mcbsp.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,13 @@
 #include <mach/hardware.h>
 #include <plat/clock.h>
 
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)		\
+static struct platform_device omap_mcbsp##port_nr = {	\
+	.name	= "omap-mcbsp-dai",			\
+	.id	= OMAP_MCBSP##port_nr,			\
+}
+
 #define OMAP7XX_MCBSP1_BASE	0xfffb1000
 #define OMAP7XX_MCBSP2_BASE	0xfffb1800
 
@@ -312,6 +319,18 @@
 #define RFSREN			0x0002
 #define RSYNCERREN		0x0001
 
+/* CLKR signal muxing options */
+#define CLKR_SRC_CLKR		0
+#define CLKR_SRC_CLKX		1
+
+/* FSR signal muxing options */
+#define FSR_SRC_FSR		0
+#define FSR_SRC_FSX		1
+
+/* McBSP functional clock sources */
+#define MCBSP_CLKS_PRCM_SRC	0
+#define MCBSP_CLKS_PAD_SRC	1
+
 /* we don't do multichannel for now */
 struct omap_mcbsp_reg_cfg {
 	u16 spcr2;
@@ -398,6 +417,7 @@
 struct omap_mcbsp_ops {
 	void (*request)(unsigned int);
 	void (*free)(unsigned int);
+	int (*set_clks_src)(u8, u8);
 };
 
 struct omap_mcbsp_platform_data {
@@ -464,6 +484,9 @@
 extern struct omap_mcbsp **mcbsp_ptr;
 extern int omap_mcbsp_count, omap_mcbsp_cache_size;
 
+#define omap_mcbsp_check_valid_id(id)	(id < omap_mcbsp_count)
+#define id_to_mcbsp_ptr(id)		mcbsp_ptr[id];
+
 int omap_mcbsp_init(void);
 void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
 					int size);
@@ -502,6 +525,8 @@
 int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
 
 
+/* McBSP functional clock source changing function */
+extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id);
 /* SPI specific API */
 void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg);
 
@@ -510,6 +535,10 @@
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
 int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
 
+/* McBSP signal muxing API */
+void omap2_mcbsp1_mux_clkr_src(u8 mux);
+void omap2_mcbsp1_mux_fsr_src(u8 mux);
+
 #ifdef CONFIG_ARCH_OMAP3
 /* Sidetone specific API */
 int omap_st_set_chgain(unsigned int id, int channel, s16 chgain);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/mmc.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/mmc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/mmc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/mmc.h	2011-01-04 19:50:19.000000000 -0500
@@ -71,12 +71,17 @@
 
 	u64 dma_mask;
 
+	/* Register offset deviation */
+	u16 reg_offset;
+
 	struct omap_mmc_slot_data {
 
-		/* 4 wire signaling is optional, and is used for SD/SDIO/HSMMC;
-		 * 8 wire signaling is also optional, and is used with HSMMC
+		/*
+		 * 4/8 wires and any additional host capabilities
+		 * need to OR'd all capabilities (ref. linux/mmc/host.h)
 		 */
-		u8 wires;
+		u8  wires;	/* Used for the MMC driver on omap1 and 2420 */
+		u32 caps;	/* Used for the MMC driver on 2430 and later */
 
 		/*
 		 * nomux means "standard" muxing is wrong on this board, and
@@ -104,6 +109,7 @@
 
 		/* we can put the features above into this variable */
 #define HSMMC_HAS_PBIAS		(1 << 0)
+#define HSMMC_HAS_UPDATED_RESET	(1 << 1)
 		unsigned features;
 
 		int switch_pin;			/* gpio (card detect) */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap24xx.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap24xx.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap24xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap24xx.h	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,7 @@
 #define OMAP24XX_IC_BASE	(L4_24XX_BASE + 0xfe000)
 #define OMAP24XX_IVA_INTC_BASE	0x40000000
 
-#define OMAP2420_CTRL_BASE	L4_24XX_BASE
+#define OMAP242X_CTRL_BASE	L4_24XX_BASE
 #define OMAP2420_32KSYNCT_BASE	(L4_24XX_BASE + 0x4000)
 #define OMAP2420_PRCM_BASE	(L4_24XX_BASE + 0x8000)
 #define OMAP2420_CM_BASE	(L4_24XX_BASE + 0x8000)
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap4-keypad.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap4-keypad.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap4-keypad.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap4-keypad.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,14 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
+
+#include <linux/input/matrix_keypad.h>
+
+struct omap4_keypad_platform_data {
+	const struct matrix_keymap_data *keymap_data;
+
+	u8 rows;
+	u8 cols;
+};
+
+extern int omap4_keyboard_init(struct omap4_keypad_platform_data *);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap_device.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap_device.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap_device.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap_device.h	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,8 @@
 
 #include <plat/omap_hwmod.h>
 
+extern struct device omap_device_parent;
+
 /* omap_device._state values */
 #define OMAP_DEVICE_STATE_UNKNOWN	0
 #define OMAP_DEVICE_STATE_ENABLED	1
@@ -62,7 +64,6 @@
  *
  */
 struct omap_device {
-	u32                             magic;
 	struct platform_device		pdev;
 	struct omap_hwmod		**hwmods;
 	struct omap_device_pm_latency	*pm_lats;
@@ -82,7 +83,6 @@
 
 /* Core code interface */
 
-bool omap_device_is_valid(struct omap_device *od);
 int omap_device_count_resources(struct omap_device *od);
 int omap_device_fill_resources(struct omap_device *od, struct resource *res);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap_hwmod.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap_hwmod.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap_hwmod.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap_hwmod.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,19 +14,16 @@
  *
  * These headers and macros are used to define OMAP on-chip module
  * data and their integration with other OMAP modules and Linux.
- *
- * References:
- * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064)
- * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090)
- * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108)
- * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140)
- * - Open Core Protocol Specification 2.2
+ * Copious documentation and references can also be found in the
+ * omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this
+ * writing).
  *
  * To do:
  * - add interconnect error log structures
  * - add pinmuxing
  * - init_conn_id_bit (CONNID_BIT_VECTOR)
  * - implement default hwmod SMS/SDRC flags?
+ * - remove unused fields
  *
  */
 #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H
@@ -35,6 +32,7 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/ioport.h>
+#include <linux/mutex.h>
 #include <plat/cpu.h>
 
 struct omap_device;
@@ -96,7 +94,7 @@
 /**
  * struct omap_hwmod_dma_info - DMA channels used by the hwmod
  * @name: name of the DMA channel (module local name)
- * @dma_ch: DMA channel ID
+ * @dma_req: DMA request ID
  *
  * @name should be something short, e.g., "tx" or "rx".  It is for use
  * by platform_get_resource_byname().  It is defined locally to the
@@ -104,7 +102,20 @@
  */
 struct omap_hwmod_dma_info {
 	const char	*name;
-	u16		dma_ch;
+	u16		dma_req;
+};
+
+/**
+ * struct omap_hwmod_rst_info - IPs reset lines use by hwmod
+ * @name: name of the reset line (module local name)
+ * @rst_shift: Offset of the reset bit
+ *
+ * @name should be something short, e.g., "cpu0" or "rst". It is defined
+ * locally to the hwmod.
+ */
+struct omap_hwmod_rst_info {
+	const char	*name;
+	u8		rst_shift;
 };
 
 /**
@@ -237,8 +248,9 @@
 #define SYSC_HAS_CLOCKACTIVITY	(1 << 4)
 #define SYSC_HAS_SIDLEMODE	(1 << 5)
 #define SYSC_HAS_MIDLEMODE	(1 << 6)
-#define SYSS_MISSING		(1 << 7)
+#define SYSS_HAS_RESET_STATUS	(1 << 7)
 #define SYSC_NO_CACHE		(1 << 8)  /* XXX SW flag, belongs elsewhere */
+#define SYSC_HAS_RESET_STATUS	(1 << 9)
 
 /* omap_hwmod_sysconfig.clockact flags */
 #define CLOCKACT_TEST_BOTH	0x0
@@ -327,10 +339,12 @@
 /**
  * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data
  * @clkctrl_reg: PRCM address of the clock control register
+ * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM
  * @submodule_wkdep_bit: bit shift of the WKDEP range
  */
 struct omap_hwmod_omap4_prcm {
 	void __iomem	*clkctrl_reg;
+	void __iomem	*rstctrl_reg;
 	u8		submodule_wkdep_bit;
 };
 
@@ -352,6 +366,11 @@
  * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
  * HWMOD_NO_IDLEST : this module does not have idle status - this is the case
  *     only for few initiator modules on OMAP2 & 3.
+ * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset.
+ *     This is needed for devices like DSS that require optional clocks enabled
+ *     in order to complete the reset. Optional clocks will be disabled
+ *     again after the reset.
+ * HWMOD_16BIT_REG: Module has 16bit registers
  */
 #define HWMOD_SWSUP_SIDLE			(1 << 0)
 #define HWMOD_SWSUP_MSTANDBY			(1 << 1)
@@ -360,6 +379,8 @@
 #define HWMOD_NO_OCP_AUTOIDLE			(1 << 4)
 #define HWMOD_SET_DEFAULT_CLOCKACT		(1 << 5)
 #define HWMOD_NO_IDLEST				(1 << 6)
+#define HWMOD_CONTROL_OPT_CLKS_IN_RESET		(1 << 7)
+#define HWMOD_16BIT_REG				(1 << 8)
 
 /*
  * omap_hwmod._int_flags definitions
@@ -410,7 +431,7 @@
  * @class: struct omap_hwmod_class * to the class of this hwmod
  * @od: struct omap_device currently associated with this hwmod (internal use)
  * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt)
- * @sdma_chs: ptr to an array of SDMA channel IDs (see also sdma_chs_cnt)
+ * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt)
  * @prcm: PRCM data pertaining to this hwmod
  * @main_clk: main clock: OMAP clock name
  * @_clk: pointer to the main struct clk (filled in at runtime)
@@ -424,7 +445,7 @@
  * @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6)
  * @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift
  * @mpu_irqs_cnt: number of @mpu_irqs
- * @sdma_chs_cnt: number of @sdma_chs
+ * @sdma_reqs_cnt: number of @sdma_reqs
  * @opt_clks_cnt: number of @opt_clks
  * @master_cnt: number of @master entries
  * @slaves_cnt: number of @slave entries
@@ -433,6 +454,7 @@
  * @_state: internal-use hwmod state
  * @flags: hwmod flags (documented below)
  * @omap_chip: OMAP chips this hwmod is present on
+ * @_mutex: mutex serializing operations on this hwmod
  * @node: list node for hwmod list (internal use)
  *
  * @main_clk refers to this module's "main clock," which for our
@@ -448,7 +470,8 @@
 	struct omap_hwmod_class		*class;
 	struct omap_device		*od;
 	struct omap_hwmod_irq_info	*mpu_irqs;
-	struct omap_hwmod_dma_info	*sdma_chs;
+	struct omap_hwmod_dma_info	*sdma_reqs;
+	struct omap_hwmod_rst_info	*rst_lines;
 	union {
 		struct omap_hwmod_omap2_prcm omap2;
 		struct omap_hwmod_omap4_prcm omap4;
@@ -461,6 +484,7 @@
 	void				*dev_attr;
 	u32				_sysc_cache;
 	void __iomem			*_mpu_rt_va;
+	struct mutex			_mutex;
 	struct list_head		node;
 	u16				flags;
 	u8				_mpu_port_index;
@@ -468,7 +492,8 @@
 	u8				msuspendmux_shift;
 	u8				response_lat;
 	u8				mpu_irqs_cnt;
-	u8				sdma_chs_cnt;
+	u8				sdma_reqs_cnt;
+	u8				rst_lines_cnt;
 	u8				opt_clks_cnt;
 	u8				masters_cnt;
 	u8				slaves_cnt;
@@ -492,6 +517,10 @@
 int _omap_hwmod_idle(struct omap_hwmod *oh);
 int omap_hwmod_shutdown(struct omap_hwmod *oh);
 
+int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name);
+int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name);
+
 int omap_hwmod_enable_clocks(struct omap_hwmod *oh);
 int omap_hwmod_disable_clocks(struct omap_hwmod *oh);
 
@@ -500,8 +529,8 @@
 int omap_hwmod_reset(struct omap_hwmod *oh);
 void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
-void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs);
-u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs);
+void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs);
+u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs);
 
 int omap_hwmod_count_resources(struct omap_hwmod *oh);
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);
@@ -534,5 +563,6 @@
 extern int omap2420_hwmod_init(void);
 extern int omap2430_hwmod_init(void);
 extern int omap3xxx_hwmod_init(void);
+extern int omap44xx_hwmod_init(void);
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap-serial.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap-serial.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/omap-serial.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/omap-serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,128 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *	Govindraj R	<govindraj.raja@ti.com>
+ *	Thara Gopinath	<thara@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __OMAP_SERIAL_H__
+#define __OMAP_SERIAL_H__
+
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <plat/mux.h>
+
+#define DRIVER_NAME	"omap-hsuart"
+
+/*
+ * Use tty device name as ttyO, [O -> OMAP]
+ * in bootargs we specify as console=ttyO0 if uart1
+ * is used as console uart.
+ */
+#define OMAP_SERIAL_NAME	"ttyO"
+
+#define OMAP_MDR1_DISABLE	0x07
+#define OMAP_MDR1_MODE13X	0x03
+#define OMAP_MDR1_MODE16X	0x00
+#define OMAP_MODE13X_SPEED	230400
+
+/*
+ * LCR = 0XBF: Switch to Configuration Mode B.
+ * In configuration mode b allow access
+ * to EFR,DLL,DLH.
+ * Reference OMAP TRM Chapter 17
+ * Section: 1.4.3 Mode Selection
+ */
+#define OMAP_UART_LCR_CONF_MDB	0XBF
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP	0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX		0x04
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX		0x04
+
+#define OMAP_UART_SYSC_RESET	0X07
+#define OMAP_UART_TCR_TRIG	0X0F
+#define OMAP_UART_SW_CLR	0XF0
+#define OMAP_UART_FIFO_CLR	0X06
+
+#define OMAP_UART_DMA_CH_FREE	-1
+
+#define RX_TIMEOUT		(3 * HZ)
+#define OMAP_MAX_HSUART_PORTS	4
+
+#define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
+
+struct omap_uart_port_info {
+	bool			dma_enabled;	/* To specify DMA Mode */
+	unsigned int		uartclk;	/* UART clock rate */
+	void __iomem		*membase;	/* ioremap cookie or NULL */
+	resource_size_t		mapbase;	/* resource base */
+	unsigned long		irqflags;	/* request_irq flags */
+	upf_t			flags;		/* UPF_* flags */
+};
+
+struct uart_omap_dma {
+	u8			uart_dma_tx;
+	u8			uart_dma_rx;
+	int			rx_dma_channel;
+	int			tx_dma_channel;
+	dma_addr_t		rx_buf_dma_phys;
+	dma_addr_t		tx_buf_dma_phys;
+	unsigned int		uart_base;
+	/*
+	 * Buffer for rx dma.It is not required for tx because the buffer
+	 * comes from port structure.
+	 */
+	unsigned char		*rx_buf;
+	unsigned int		prev_rx_dma_pos;
+	int			tx_buf_size;
+	int			tx_dma_used;
+	int			rx_dma_used;
+	spinlock_t		tx_lock;
+	spinlock_t		rx_lock;
+	/* timer to poll activity on rx dma */
+	struct timer_list	rx_timer;
+	int			rx_buf_size;
+	int			rx_timeout;
+};
+
+struct uart_omap_port {
+	struct uart_port	port;
+	struct uart_omap_dma	uart_dma;
+	struct platform_device	*pdev;
+
+	unsigned char		ier;
+	unsigned char		lcr;
+	unsigned char		mcr;
+	unsigned char		fcr;
+	unsigned char		efr;
+
+	int			use_dma;
+	/*
+	 * Some bits in registers are cleared on a read, so they must
+	 * be saved whenever the register is read but the bits will not
+	 * be immediately processed.
+	 */
+	unsigned int		lsr_break_flag;
+	unsigned char		msr_saved_flags;
+	char			name[20];
+	unsigned long		port_activity;
+};
+
+#endif /* __OMAP_SERIAL_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/powerdomain.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/powerdomain.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/powerdomain.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/powerdomain.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 
 /* Powerdomain allowable state bitfields */
 #define PWRSTS_ON		(1 << PWRDM_POWER_ON)
+#define PWRSTS_OFF		(1 << PWRDM_POWER_OFF)
 #define PWRSTS_OFF_ON		((1 << PWRDM_POWER_OFF) | \
 				 (1 << PWRDM_POWER_ON))
 
@@ -161,5 +162,6 @@
 int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
 int pwrdm_pre_transition(void);
 int pwrdm_post_transition(void);
+int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/prcm.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/prcm.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/prcm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/prcm.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,8 @@
 void prm_write_mod_reg(u32 val, s16 module, u16 idx);
 u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
 u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask);
+u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask);
+u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg);
 u32 cm_read_mod_reg(s16 module, u16 idx);
 void cm_write_mod_reg(u32 val, s16 module, u16 idx);
 u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/sdrc.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/sdrc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/sdrc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/sdrc.h	2011-01-04 19:50:19.000000000 -0500
@@ -147,6 +147,7 @@
 };
 
 extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
+struct omap_sdrc_params *rx51_get_sdram_timings(void);
 
 u32 omap2xxx_sdrc_dll_is_unlocked(void);
 u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/smp.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/smp.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #define OMAP_ARCH_SMP_H
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 /* Needed for secondary core boot */
 extern void omap_secondary_startup(void);
@@ -33,15 +34,4 @@
 	gic_raise_softirq(mask, 1);
 }
 
-/*
- * Read MPIDR: Multiprocessor affinity register
- */
-#define hard_smp_processor_id()			\
-	({						\
-		unsigned int cpunum;			\
-		__asm__("mrc p15, 0, %0, c0, c0, 5"	\
-			: "=r" (cpunum));		\
-		cpunum &= 0x0F;				\
-	})
-
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/sram.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/sram.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/sram.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/sram.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,6 @@
 #ifndef __ARCH_ARM_OMAP_SRAM_H
 #define __ARCH_ARM_OMAP_SRAM_H
 
-extern int __init omap_sram_init(void);
 extern void * omap_sram_push(void * start, unsigned long size);
 extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/timer-gp.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/timer-gp.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/timer-gp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/timer-gp.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,17 +0,0 @@
-/*
- * OMAP2/3 GPTIMER support.headers
- *
- * Copyright (C) 2009 Nokia Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
-#define __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_TIMER_GP_H
-
-int __init omap2_gp_clockevent_set_gptimer(u8 id);
-
-#endif
-
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/uncompress.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/uncompress.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/uncompress.h	2011-01-04 19:50:19.000000000 -0500
@@ -139,10 +139,14 @@
 		DEBUG_LL_OMAP2(1, omap3evm);
 		DEBUG_LL_OMAP3(1, omap_3430sdp);
 		DEBUG_LL_OMAP3(1, omap_3630sdp);
+		DEBUG_LL_OMAP3(1, omap3530_lv_som);
+		DEBUG_LL_OMAP3(1, omap3_torpedo);
 
 		/* omap3 based boards using UART3 */
 		DEBUG_LL_OMAP3(3, cm_t35);
+		DEBUG_LL_OMAP3(3, cm_t3517);
 		DEBUG_LL_OMAP3(3, igep0020);
+		DEBUG_LL_OMAP3(3, igep0030);
 		DEBUG_LL_OMAP3(3, nokia_rx51);
 		DEBUG_LL_OMAP3(3, omap3517evm);
 		DEBUG_LL_OMAP3(3, omap3_beagle);
@@ -153,6 +157,7 @@
 
 		/* omap4 based boards using UART3 */
 		DEBUG_LL_OMAP4(3, omap_4430sdp);
+		DEBUG_LL_OMAP4(3, omap4_panda);
 
 		/* zoom2/3 external uart */
 		DEBUG_LL_ZOOM(omap_zoom2);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/usb.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/usb.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/usb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/usb.h	2011-01-04 19:50:19.000000000 -0500
@@ -105,7 +105,7 @@
 #if defined(CONFIG_ARCH_OMAP_OTG) || defined(CONFIG_ARCH_OMAP_OTG_MODULE)
 void omap2_usbfs_init(struct omap_usb_config *pdata);
 #else
-static inline omap2_usbfs_init(struct omap_usb_config *pdata)
+static inline void omap2_usbfs_init(struct omap_usb_config *pdata)
 {
 }
 #endif
@@ -218,6 +218,27 @@
 #	define	USBT2TLL5PI		(1 << 17)
 #	define	USB0PUENACTLOI		(1 << 16)
 #	define	USBSTANDBYCTRL		(1 << 15)
+/* AM35x */
+/* USB 2.0 PHY Control */
+#define CONF2_PHY_GPIOMODE	(1 << 23)
+#define CONF2_OTGMODE		(3 << 14)
+#define CONF2_NO_OVERRIDE	(0 << 14)
+#define CONF2_FORCE_HOST	(1 << 14)
+#define CONF2_FORCE_DEVICE	(2 << 14)
+#define CONF2_FORCE_HOST_VBUS_LOW (3 << 14)
+#define CONF2_SESENDEN		(1 << 13)
+#define CONF2_VBDTCTEN		(1 << 12)
+#define CONF2_REFFREQ_24MHZ	(2 << 8)
+#define CONF2_REFFREQ_26MHZ	(7 << 8)
+#define CONF2_REFFREQ_13MHZ	(6 << 8)
+#define CONF2_REFFREQ		(0xf << 8)
+#define CONF2_PHYCLKGD		(1 << 7)
+#define CONF2_VBUSSENSE		(1 << 6)
+#define CONF2_PHY_PLLON		(1 << 5)
+#define CONF2_RESET		(1 << 4)
+#define CONF2_PHYPWRDN		(1 << 3)
+#define CONF2_OTGPWRDN		(1 << 2)
+#define CONF2_DATPOL		(1 << 1)
 
 #if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_USB)
 u32 omap1_usb0_init(unsigned nwires, unsigned is_device);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/vrfb.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/vrfb.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/include/plat/vrfb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/include/plat/vrfb.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 	bool yuv_mode;
 };
 
+#ifdef CONFIG_OMAP2_VRFB
 extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
 extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
 extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
@@ -47,4 +48,19 @@
 extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
 extern void omap_vrfb_restore_context(void);
 
+#else
+static inline int omap_vrfb_request_ctx(struct vrfb *vrfb) { return 0; }
+static inline void omap_vrfb_release_ctx(struct vrfb *vrfb) {}
+static inline void omap_vrfb_adjust_size(u16 *width, u16 *height,
+		u8 bytespp) {}
+static inline u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
+		{ return 0; }
+static inline u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
+		{ return 0; }
+static inline void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
+		u16 width, u16 height, unsigned bytespp, bool yuv_mode) {}
+static inline int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
+		{ return 0; }
+static inline void omap_vrfb_restore_context(void) {}
+#endif
 #endif /* __VRFB_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/iommu-debug.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/iommu-debug.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/iommu-debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/iommu-debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -328,12 +328,14 @@
 		.open = debug_open_generic,				\
 		.read = debug_read_##name,				\
 		.write = debug_write_##name,				\
+		.llseek = generic_file_llseek,				\
 	};
 
 #define DEBUG_FOPS_RO(name)						\
 	static const struct file_operations debug_##name##_fops = {	\
 		.open = debug_open_generic,				\
 		.read = debug_read_##name,				\
+		.llseek = generic_file_llseek,				\
 	};
 
 DEBUG_FOPS_RO(ver);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-omap/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,7 @@
 	bool "TI OMAP2/3/4"
 	select COMMON_CLKDEV
 	help
-	  "Systems based on omap24xx, omap34xx or omap44xx"
+	  "Systems based on OMAP2, OMAP3 or OMAP4"
 
 endchoice
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-omap/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
-	 usb.o fb.o io.o
+	 usb.o fb.o io.o counter_32k.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -31,4 +31,4 @@
 # OMAP mailbox framework
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
-obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
\ No newline at end of file
+obj-$(CONFIG_OMAP_PM_NOOP) += omap-pm-noop.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/mcbsp.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/mcbsp.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/mcbsp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/mcbsp.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,7 @@
 struct omap_mcbsp **mcbsp_ptr;
 int omap_mcbsp_count, omap_mcbsp_cache_size;
 
-void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 {
 	if (cpu_class_is_omap1()) {
 		((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val;
@@ -47,7 +47,7 @@
 	}
 }
 
-int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
+static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
 {
 	if (cpu_class_is_omap1()) {
 		return !from_cache ? __raw_readw(mcbsp->io_base + reg) :
@@ -62,12 +62,12 @@
 }
 
 #ifdef CONFIG_ARCH_OMAP3
-void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
+static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
 {
 	__raw_writel(val, mcbsp->st_data->io_base_st + reg);
 }
 
-int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
+static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
 {
 	return __raw_readl(mcbsp->st_data->io_base_st + reg);
 }
@@ -80,9 +80,6 @@
 #define MCBSP_READ_CACHE(mcbsp, reg) \
 		omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1)
 
-#define omap_mcbsp_check_valid_id(id)	(id < omap_mcbsp_count)
-#define id_to_mcbsp_ptr(id)		mcbsp_ptr[id];
-
 #define MCBSP_ST_READ(mcbsp, reg) \
 			omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg)
 #define MCBSP_ST_WRITE(mcbsp, reg, val) \
@@ -878,7 +875,7 @@
 void omap_mcbsp_start(unsigned int id, int tx, int rx)
 {
 	struct omap_mcbsp *mcbsp;
-	int idle;
+	int enable_srg = 0;
 	u16 w;
 
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -893,10 +890,13 @@
 	mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7;
 	mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7;
 
-	idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
-			MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
+	/* Only enable SRG, if McBSP is master */
+	w = MCBSP_READ_CACHE(mcbsp, PCR0);
+	if (w & (FSXM | FSRM | CLKXM | CLKRM))
+		enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) |
+				MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1);
 
-	if (idle) {
+	if (enable_srg) {
 		/* Start the sample generator */
 		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
 		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6));
@@ -919,7 +919,7 @@
 	 */
 	udelay(500);
 
-	if (idle) {
+	if (enable_srg) {
 		/* Start frame sync */
 		w = MCBSP_READ_CACHE(mcbsp, SPCR2);
 		MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
@@ -1645,7 +1645,7 @@
 	.attrs = (struct attribute **)sidetone_attrs,
 };
 
-int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
+static int __devinit omap_st_add(struct omap_mcbsp *mcbsp)
 {
 	struct omap_mcbsp_platform_data *pdata = mcbsp->pdata;
 	struct omap_mcbsp_st_data *st_data;
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/omap_device.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/omap_device.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/omap_device.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/omap_device.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,6 +82,7 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/clk.h>
 
 #include <plat/omap_device.h>
 #include <plat/omap_hwmod.h>
@@ -90,12 +91,6 @@
 #define USE_WAKEUP_LAT			0
 #define IGNORE_WAKEUP_LAT		1
 
-/*
- * OMAP_DEVICE_MAGIC: used to determine whether a struct omap_device
- * obtained via container_of() is in fact a struct omap_device
- */
-#define OMAP_DEVICE_MAGIC		 0xf00dcafe
-
 /* Private functions */
 
 /**
@@ -243,6 +238,44 @@
 	return container_of(pdev, struct omap_device, pdev);
 }
 
+/**
+ * _add_optional_clock_alias - Add clock alias for hwmod optional clocks
+ * @od: struct omap_device *od
+ *
+ * For every optional clock present per hwmod per omap_device, this function
+ * adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role>
+ * if an entry is already present in it with the form <dev-id=NULL, con-id=role>
+ *
+ * The function is called from inside omap_device_build_ss(), after
+ * omap_device_register.
+ *
+ * This allows drivers to get a pointer to its optional clocks based on its role
+ * by calling clk_get(<dev*>, <role>).
+ *
+ * No return value.
+ */
+static void _add_optional_clock_alias(struct omap_device *od,
+				      struct omap_hwmod *oh)
+{
+	int i;
+
+	for (i = 0; i < oh->opt_clks_cnt; i++) {
+		struct omap_hwmod_opt_clk *oc;
+		int r;
+
+		oc = &oh->opt_clks[i];
+
+		if (!oc->_clk)
+			continue;
+
+		r = clk_add_alias(oc->role, dev_name(&od->pdev.dev),
+				  (char *)oc->clk, &od->pdev.dev);
+		if (r)
+			pr_err("omap_device: %s: clk_add_alias for %s failed\n",
+			       dev_name(&od->pdev.dev), oc->role);
+	}
+}
+
 
 /* Public functions for use by core code */
 
@@ -257,12 +290,11 @@
  */
 int omap_device_count_resources(struct omap_device *od)
 {
-	struct omap_hwmod *oh;
 	int c = 0;
 	int i;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		c += omap_hwmod_count_resources(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		c += omap_hwmod_count_resources(od->hwmods[i]);
 
 	pr_debug("omap_device: %s: counted %d total resources across %d "
 		 "hwmods\n", od->pdev.name, c, od->hwmods_cnt);
@@ -289,12 +321,11 @@
  */
 int omap_device_fill_resources(struct omap_device *od, struct resource *res)
 {
-	struct omap_hwmod *oh;
 	int c = 0;
 	int i, r;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++) {
-		r = omap_hwmod_fill_resources(oh, res);
+	for (i = 0; i < od->hwmods_cnt; i++) {
+		r = omap_hwmod_fill_resources(od->hwmods[i], res);
 		res += r;
 		c += r;
 	}
@@ -414,15 +445,15 @@
 	od->pm_lats = pm_lats;
 	od->pm_lats_cnt = pm_lats_cnt;
 
-	od->magic = OMAP_DEVICE_MAGIC;
-
 	if (is_early_device)
 		ret = omap_early_device_register(od);
 	else
 		ret = omap_device_register(od);
 
-	for (i = 0; i < oh_cnt; i++)
+	for (i = 0; i < oh_cnt; i++) {
 		hwmods[i]->od = od;
+		_add_optional_clock_alias(od, hwmods[i]);
+	}
 
 	if (ret)
 		goto odbs_exit4;
@@ -473,6 +504,7 @@
 {
 	pr_debug("omap_device: %s: registering\n", od->pdev.name);
 
+	od->pdev.dev.parent = &omap_device_parent;
 	return platform_device_register(&od->pdev);
 }
 
@@ -566,7 +598,6 @@
 {
 	int ret, i;
 	struct omap_device *od;
-	struct omap_hwmod *oh;
 
 	od = _find_by_pdev(pdev);
 
@@ -579,8 +610,8 @@
 
 	ret = _omap_device_deactivate(od, IGNORE_WAKEUP_LAT);
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		omap_hwmod_shutdown(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		omap_hwmod_shutdown(od->hwmods[i]);
 
 	od->_state = OMAP_DEVICE_STATE_SHUTDOWN;
 
@@ -627,18 +658,6 @@
 }
 
 /**
- * omap_device_is_valid - Check if pointer is a valid omap_device
- * @od: struct omap_device *
- *
- * Return whether struct omap_device pointer @od points to a valid
- * omap_device.
- */
-bool omap_device_is_valid(struct omap_device *od)
-{
-	return (od && od->magic == OMAP_DEVICE_MAGIC);
-}
-
-/**
  * omap_device_get_pwrdm - return the powerdomain * associated with @od
  * @od: struct omap_device *
  *
@@ -692,11 +711,10 @@
  */
 int omap_device_enable_hwmods(struct omap_device *od)
 {
-	struct omap_hwmod *oh;
 	int i;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		omap_hwmod_enable(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		omap_hwmod_enable(od->hwmods[i]);
 
 	/* XXX pass along return value here? */
 	return 0;
@@ -710,11 +728,10 @@
  */
 int omap_device_idle_hwmods(struct omap_device *od)
 {
-	struct omap_hwmod *oh;
 	int i;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		omap_hwmod_idle(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		omap_hwmod_idle(od->hwmods[i]);
 
 	/* XXX pass along return value here? */
 	return 0;
@@ -729,11 +746,10 @@
  */
 int omap_device_disable_clocks(struct omap_device *od)
 {
-	struct omap_hwmod *oh;
 	int i;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		omap_hwmod_disable_clocks(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		omap_hwmod_disable_clocks(od->hwmods[i]);
 
 	/* XXX pass along return value here? */
 	return 0;
@@ -748,12 +764,22 @@
  */
 int omap_device_enable_clocks(struct omap_device *od)
 {
-	struct omap_hwmod *oh;
 	int i;
 
-	for (i = 0, oh = *od->hwmods; i < od->hwmods_cnt; i++, oh++)
-		omap_hwmod_enable_clocks(oh);
+	for (i = 0; i < od->hwmods_cnt; i++)
+		omap_hwmod_enable_clocks(od->hwmods[i]);
 
 	/* XXX pass along return value here? */
 	return 0;
 }
+
+struct device omap_device_parent = {
+	.init_name	= "omap",
+	.parent         = &platform_bus,
+};
+
+static int __init omap_device_init(void)
+{
+	return device_register(&omap_device_parent);
+}
+core_initcall(omap_device_init);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/sram.c linux-libre-2.6.37-gnu/arch/arm/plat-omap/sram.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/sram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/sram.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/omapfb.h>
 
 #include <asm/tlb.h>
 #include <asm/cacheflush.h>
@@ -30,8 +31,8 @@
 #include <plat/cpu.h>
 #include <plat/vram.h>
 
-#include <plat/control.h>
-
+#include "sram.h"
+#include "fb.h"
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 # include "../mach-omap2/prm.h"
 # include "../mach-omap2/cm.h"
@@ -53,7 +54,7 @@
 #define OMAP4_SRAM_PUB_PA	(OMAP4_SRAM_PA + 0x4000)
 #define OMAP4_SRAM_PUB_VA	(OMAP4_SRAM_VA + 0x4000)
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2PLUS)
 #define SRAM_BOOTLOADER_SZ	0x00
 #else
 #define SRAM_BOOTLOADER_SZ	0x80
@@ -68,7 +69,6 @@
 #define OMAP34XX_VA_WRITEPERM0		OMAP2_L3_IO_ADDRESS(0x68012858)
 #define OMAP34XX_VA_ADDR_MATCH2		OMAP2_L3_IO_ADDRESS(0x68012880)
 #define OMAP34XX_VA_SMS_RG_ATT0		OMAP2_L3_IO_ADDRESS(0x6C000048)
-#define OMAP34XX_VA_CONTROL_STAT	OMAP2_L4_IO_ADDRESS(0x480022F0)
 
 #define GP_DEVICE		0x300
 
@@ -79,12 +79,6 @@
 static unsigned long omap_sram_size;
 static unsigned long omap_sram_ceil;
 
-extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
-					 unsigned long sram_vstart,
-					 unsigned long sram_size,
-					 unsigned long pstart_avail,
-					 unsigned long size_avail);
-
 /*
  * Depending on the target RAMFS firewall setup, the public usable amount of
  * SRAM varies.  The default accessible size for all device types is 2k. A GP
@@ -93,16 +87,7 @@
  */
 static int is_sram_locked(void)
 {
-	int type = 0;
-
-	if (cpu_is_omap44xx())
-		/* Not yet supported */
-		return 0;
-
-	if (cpu_is_omap242x())
-		type = omap_rev() & OMAP2_DEVICETYPE_MASK;
-
-	if (type == GP_DEVICE) {
+	if (OMAP2_DEVICE_TYPE_GP == omap_type()) {
 		/* RAMFW: R/W access to all initiators for all qualifier sets */
 		if (cpu_is_omap242x()) {
 			__raw_writel(0xFF, OMAP24XX_VA_REQINFOPERM0); /* all q-vects */
@@ -127,7 +112,7 @@
  * to secure SRAM will hang the system. Also the SRAM is not
  * yet mapped at this point.
  */
-void __init omap_detect_sram(void)
+static void __init omap_detect_sram(void)
 {
 	unsigned long reserved;
 
@@ -181,7 +166,7 @@
 		     cpu_is_omap1710())
 			omap_sram_size = 0x4000;	/* 16K */
 		else if (cpu_is_omap1611())
-			omap_sram_size = 0x3e800;	/* 250K */
+			omap_sram_size = SZ_256K;
 		else {
 			printk(KERN_ERR "Could not detect SRAM size\n");
 			omap_sram_size = 0x4000;
@@ -213,7 +198,7 @@
 /*
  * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
  */
-void __init omap_map_sram(void)
+static void __init omap_map_sram(void)
 {
 	unsigned long base;
 
@@ -330,7 +315,7 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2420
-int __init omap242x_sram_init(void)
+static int __init omap242x_sram_init(void)
 {
 	_omap2_sram_ddr_init = omap_sram_push(omap242x_sram_ddr_init,
 					omap242x_sram_ddr_init_sz);
@@ -351,7 +336,7 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP2430
-int __init omap243x_sram_init(void)
+static int __init omap243x_sram_init(void)
 {
 	_omap2_sram_ddr_init = omap_sram_push(omap243x_sram_ddr_init,
 					omap243x_sram_ddr_init_sz);
@@ -407,7 +392,7 @@
 }
 #endif /* CONFIG_PM */
 
-int __init omap34xx_sram_init(void)
+static int __init omap34xx_sram_init(void)
 {
 	_omap3_sram_configure_core_dpll =
 		omap_sram_push(omap3_sram_configure_core_dpll,
@@ -423,7 +408,7 @@
 #endif
 
 #ifdef CONFIG_ARCH_OMAP4
-int __init omap44xx_sram_init(void)
+static int __init omap44xx_sram_init(void)
 {
 	printk(KERN_ERR "FIXME: %s not implemented\n", __func__);
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-omap/sram.h linux-libre-2.6.37-gnu/arch/arm/plat-omap/sram.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-omap/sram.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-omap/sram.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,6 @@
+#ifndef __PLAT_OMAP_SRAM_H__
+#define __PLAT_OMAP_SRAM_H__
+
+extern int __init omap_sram_init(void);
+
+#endif /* __PLAT_OMAP_SRAM_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-orion/include/plat/pcie.h linux-libre-2.6.37-gnu/arch/arm/plat-orion/include/plat/pcie.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-orion/include/plat/pcie.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-orion/include/plat/pcie.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,12 +11,15 @@
 #ifndef __PLAT_PCIE_H
 #define __PLAT_PCIE_H
 
+struct pci_bus;
+
 u32 orion_pcie_dev_id(void __iomem *base);
 u32 orion_pcie_rev(void __iomem *base);
 int orion_pcie_link_up(void __iomem *base);
 int orion_pcie_x4_mode(void __iomem *base);
 int orion_pcie_get_local_bus_nr(void __iomem *base);
 void orion_pcie_set_local_bus_nr(void __iomem *base, int nr);
+void orion_pcie_reset(void __iomem *base);
 void orion_pcie_setup(void __iomem *base,
 		      struct mbus_dram_target_info *dram);
 int orion_pcie_rd_conf(void __iomem *base, struct pci_bus *bus,
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-orion/pcie.c linux-libre-2.6.37-gnu/arch/arm/plat-orion/pcie.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-orion/pcie.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-orion/pcie.c	2011-01-04 19:50:19.000000000 -0500
@@ -182,11 +182,6 @@
 	u32 mask;
 
 	/*
-	 * soft reset PCIe unit
-	 */
-	orion_pcie_reset(base);
-
-	/*
 	 * Point PCIe unit MBUS decode windows to DRAM space.
 	 */
 	orion_pcie_setup_wins(base, dram);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,69 @@
+#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
+#define __ASM_ARCH_PXA27x_KEYPAD_H
+
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+
+#define MAX_MATRIX_KEY_ROWS	(8)
+#define MAX_MATRIX_KEY_COLS	(8)
+#define MATRIX_ROW_SHIFT	(3)
+#define MAX_DIRECT_KEY_NUM	(8)
+
+/* pxa3xx keypad platform specific parameters
+ *
+ * NOTE:
+ * 1. direct_key_num indicates the number of keys in the direct keypad
+ *    _plus_ the number of rotary-encoder sensor inputs,  this can be
+ *    left as 0 if only rotary encoders are enabled,  the driver will
+ *    automatically calculate this
+ *
+ * 2. direct_key_map is the key code map for the direct keys, if rotary
+ *    encoder(s) are enabled, direct key 0/1(2/3) will be ignored
+ *
+ * 3. rotary can be either interpreted as a relative input event (e.g.
+ *    REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT)
+ *
+ * 4. matrix key and direct key will use the same debounce_interval by
+ *    default, which should be sufficient in most cases
+ *
+ * pxa168 keypad platform specific parameter
+ *
+ * NOTE:
+ * clear_wakeup_event callback is a workaround required to clear the
+ * keypad interrupt. The keypad wake must be cleared in addition to
+ * reading the MI/DI bits in the KPC register.
+ */
+struct pxa27x_keypad_platform_data {
+
+	/* code map for the matrix keys */
+	unsigned int	matrix_key_rows;
+	unsigned int	matrix_key_cols;
+	unsigned int	*matrix_key_map;
+	int		matrix_key_map_size;
+
+	/* direct keys */
+	int		direct_key_num;
+	unsigned int	direct_key_map[MAX_DIRECT_KEY_NUM];
+
+	/* rotary encoders 0 */
+	int		enable_rotary0;
+	int		rotary0_rel_code;
+	int		rotary0_up_key;
+	int		rotary0_down_key;
+
+	/* rotary encoders 1 */
+	int		enable_rotary1;
+	int		rotary1_rel_code;
+	int		rotary1_up_key;
+	int		rotary1_down_key;
+
+	/* key debounce interval */
+	unsigned int	debounce_interval;
+
+	/* clear wakeup event requirement for pxa168 */
+	void		(*clear_wakeup_event)(void);
+};
+
+extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
+
+#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,15 +30,15 @@
 };
 
 struct pxa3xx_nand_flash {
-	const struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
-	const struct pxa3xx_nand_cmdset *cmdset;
+	uint32_t	chip_id;
+	unsigned int	page_per_block; /* Pages per block (PG_PER_BLK) */
+	unsigned int	page_size;	/* Page size in bytes (PAGE_SZ) */
+	unsigned int	flash_width;	/* Width of Flash memory (DWIDTH_M) */
+	unsigned int	dfc_width;	/* Width of flash controller(DWIDTH_C) */
+	unsigned int	num_blocks;	/* Number of physical blocks in Flash */
 
-	uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
-	uint32_t page_size;	/* Page size in bytes (PAGE_SZ) */
-	uint32_t flash_width;	/* Width of Flash memory (DWIDTH_M) */
-	uint32_t dfc_width;	/* Width of flash controller(DWIDTH_C) */
-	uint32_t num_blocks;	/* Number of physical blocks in Flash */
-	uint32_t chip_id;
+	struct pxa3xx_nand_cmdset *cmdset;	/* NAND command set */
+	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
 };
 
 struct pxa3xx_nand_platform_data {
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/sdhci.h linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/sdhci.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-pxa/include/plat/sdhci.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-pxa/include/plat/sdhci.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/* linux/arch/arm/plat-pxa/include/plat/sdhci.h
+ *
+ * Copyright 2010 Marvell
+ *	Zhangfei Gao <zhangfei.gao@marvell.com>
+ *
+ * PXA Platform - SDHCI platform data definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PLAT_PXA_SDHCI_H
+#define __PLAT_PXA_SDHCI_H
+
+/* pxa specific flag */
+/* Require clock free running */
+#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
+
+/* Board design supports 8-bit data on SD/SDIO BUS */
+#define PXA_FLAG_SD_8_BIT_CAPABLE_SLOT (1<<2)
+
+/*
+ * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
+ * @max_speed: the maximum speed supported
+ * @quirks: quirks of specific device
+ * @flags: flags for platform requirement
+ */
+struct sdhci_pxa_platdata {
+	unsigned int	max_speed;
+	unsigned int	quirks;
+	unsigned int	flags;
+};
+
+#endif /* __PLAT_PXA_SDHCI_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/common-smdk.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/common-smdk.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/common-smdk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/common-smdk.c	2011-01-04 19:50:19.000000000 -0500
@@ -147,7 +147,7 @@
 	[7] = {
 		.name	= "S3C2410 flash partition 7",
 		.offset = SZ_1M * 48,
-		.size	= SZ_16M,
+		.size	= MTDPART_SIZ_FULL,
 	}
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/cpu.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,7 @@
 	{
 		.idcode		= 0x32440000,
 		.idmask		= 0xffffffff,
-		.map_io		= s3c244x_map_io,
+		.map_io		= s3c2440_map_io,
 		.init_clocks	= s3c244x_init_clocks,
 		.init_uarts	= s3c244x_init_uarts,
 		.init		= s3c2440_init,
@@ -97,7 +97,7 @@
 	{
 		.idcode		= 0x32440001,
 		.idmask		= 0xffffffff,
-		.map_io		= s3c244x_map_io,
+		.map_io		= s3c2440_map_io,
 		.init_clocks	= s3c244x_init_clocks,
 		.init_uarts	= s3c244x_init_uarts,
 		.init		= s3c2440_init,
@@ -106,7 +106,7 @@
 	{
 		.idcode		= 0x32440aaa,
 		.idmask		= 0xffffffff,
-		.map_io		= s3c244x_map_io,
+		.map_io		= s3c2442_map_io,
 		.init_clocks	= s3c244x_init_clocks,
 		.init_uarts	= s3c244x_init_uarts,
 		.init		= s3c2442_init,
@@ -115,7 +115,7 @@
 	{
 		.idcode		= 0x32440aab,
 		.idmask		= 0xffffffff,
-		.map_io		= s3c244x_map_io,
+		.map_io		= s3c2442_map_io,
 		.init_clocks	= s3c244x_init_clocks,
 		.init_uarts	= s3c244x_init_uarts,
 		.init		= s3c2442_init,
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/devs.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/devs.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/devs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/devs.c	2011-01-04 19:50:19.000000000 -0500
@@ -247,7 +247,7 @@
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 
 struct platform_device s3c_device_iis = {
-	.name		  = "s3c2410-iis",
+	.name		  = "s3c24xx-iis",
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_iis_resource),
 	.resource	  = s3c_iis_resource,
@@ -259,6 +259,21 @@
 
 EXPORT_SYMBOL(s3c_device_iis);
 
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
 /* RTC */
 
 static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@
 	},
 };
 
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
 struct platform_device s3c_device_ac97 = {
 	.name		  = "s3c-ac97",
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_ac97_resource),
 	.resource	  = s3c_ac97_resource,
 	.dev              = {
-		.dma_mask = &s3c_device_ac97_dmamask,
+		.dma_mask = &s3c_device_audio_dmamask,
 		.coherent_dma_mask = 0xffffffffUL
 	}
 };
 
 EXPORT_SYMBOL(s3c_device_ac97);
 
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+	.name		  = "s3c2412-iis",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
 #endif // CONFIG_CPU_S32440
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/gpiolib.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/gpiolib.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/gpiolib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,11 +74,6 @@
 	return -EINVAL;
 }
 
-static int s3c24xx_gpiolib_bankg_toirq(struct gpio_chip *chip, unsigned offset)
-{
-	return IRQ_EINT8 + offset;
-}
-
 static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = {
 	.set_config	= s3c_gpio_setcfg_s3c24xx_a,
 	.get_config	= s3c_gpio_getcfg_s3c24xx_a,
@@ -157,12 +152,13 @@
 	[6] = {
 		.base	= S3C2410_GPGCON,
 		.pm	= __gpio_pm(&s3c_gpio_pm_2bit),
+		.irq_base = IRQ_EINT8,
 		.chip	= {
 			.base			= S3C2410_GPG(0),
 			.owner			= THIS_MODULE,
 			.label			= "GPIOG",
 			.ngpio			= 16,
-			.to_irq			= s3c24xx_gpiolib_bankg_toirq,
+			.to_irq			= samsung_gpiolib_to_irq,
 		},
 	}, {
 		.base	= S3C2410_GPHCON,
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/include/plat/s3c244x.h linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/include/plat/s3c244x.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/include/plat/s3c244x.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/include/plat/s3c244x.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,17 +21,22 @@
 #else
 #define s3c244x_init_clocks NULL
 #define s3c244x_init_uarts NULL
-#define s3c244x_map_io NULL
 #endif
 
 #ifdef CONFIG_CPU_S3C2440
 extern  int s3c2440_init(void);
+
+extern void s3c2440_map_io(void);
 #else
 #define s3c2440_init NULL
+#define s3c2440_map_io NULL
 #endif
 
 #ifdef CONFIG_CPU_S3C2442
 extern  int s3c2442_init(void);
+
+extern void s3c2442_map_io(void);
 #else
 #define s3c2442_init NULL
+#define s3c2442_map_io NULL
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
 	default y
 	select NO_IOPORT
 	select ARCH_REQUIRE_GPIOLIB
-	select S3C_DEVICE_NAND
+	select S3C_DEV_NAND
 	select S3C_GPIO_CFG_S3C24XX
 	help
 	  Base platform code for any Samsung S3C24XX device
@@ -69,6 +69,7 @@
 	int
 	default 128 if S3C24XX_GPIO_EXTRA128
 	default 64 if S3C24XX_GPIO_EXTRA64
+	default 16 if ARCH_H1940
 	default 0
 
 config S3C24XX_GPIO_EXTRA64
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus0-gpe11_12_13.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,8 +29,8 @@
 	} else {
 		s3c_gpio_cfgpin(S3C2410_GPE(13), S3C2410_GPIO_INPUT);
 		s3c_gpio_cfgpin(S3C2410_GPE(11), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPE(11), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPE(12), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPE(13), S3C_GPIO_PULL_NONE);
 	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpd8_9_10.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,8 +31,8 @@
 	} else {
 		s3c_gpio_cfgpin(S3C2410_GPD(8), S3C2410_GPIO_INPUT);
 		s3c_gpio_cfgpin(S3C2410_GPD(9), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPD(10), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE);
 	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s3c24xx/spi-bus1-gpg5_6_7.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,8 +29,8 @@
 	} else {
 		s3c_gpio_cfgpin(S3C2410_GPG(7), S3C2410_GPIO_INPUT);
 		s3c_gpio_cfgpin(S3C2410_GPG(5), S3C2410_GPIO_INPUT);
-		s3c_gpio_cfgpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
-		s3c_gpio_cfgpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPG(5), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE);
+		s3c_gpio_setpull(S3C2410_GPG(7), S3C_GPIO_PULL_NONE);
 	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/clock.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,8 @@
 #include <linux/io.h>
 #include <asm/div64.h>
 
+#include <mach/regs-clock.h>
+
 #include <plat/clock.h>
 #include <plat/clock-clksrc.h>
 #include <plat/s5p-clock.h>
@@ -74,19 +76,18 @@
 	.ctrlbit	= (1 << 31),
 };
 
-/* VPLL clock output */
-struct clk clk_fout_vpll = {
-	.name		= "fout_vpll",
+/* DPLL clock output */
+struct clk clk_fout_dpll = {
+	.name		= "fout_dpll",
 	.id		= -1,
 	.ctrlbit	= (1 << 31),
 };
 
-/* ARM clock */
-struct clk clk_arm = {
-	.name		= "armclk",
+/* VPLL clock output */
+struct clk clk_fout_vpll = {
+	.name		= "fout_vpll",
 	.id		= -1,
-	.rate		= 0,
-	.ctrlbit	= 0,
+	.ctrlbit	= (1 << 31),
 };
 
 /* Possible clock sources for APLL Mux */
@@ -122,6 +123,17 @@
 	.nr_sources	= ARRAY_SIZE(clk_src_epll_list),
 };
 
+/* Possible clock sources for DPLL Mux */
+static struct clk *clk_src_dpll_list[] = {
+	[0] = &clk_fin_dpll,
+	[1] = &clk_fout_dpll,
+};
+
+struct clksrc_sources clk_src_dpll = {
+	.sources	= clk_src_dpll_list,
+	.nr_sources	= ARRAY_SIZE(clk_src_dpll_list),
+};
+
 struct clk clk_vpll = {
 	.name		= "vpll",
 	.id		= -1,
@@ -138,6 +150,24 @@
 	return 0;
 }
 
+int s5p_epll_enable(struct clk *clk, int enable)
+{
+	unsigned int ctrlbit = clk->ctrlbit;
+	unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
+
+	if (enable)
+		__raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
+	else
+		__raw_writel(epll_con, S5P_EPLL_CON);
+
+	return 0;
+}
+
+unsigned long s5p_epll_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+
 static struct clk *s5p_clks[] __initdata = {
 	&clk_ext_xtal_mux,
 	&clk_48m,
@@ -145,8 +175,8 @@
 	&clk_fout_apll,
 	&clk_fout_mpll,
 	&clk_fout_epll,
+	&clk_fout_dpll,
 	&clk_fout_vpll,
-	&clk_arm,
 	&clk_vpll,
 	&clk_xusbxti,
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/cpu.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/cpu.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <plat/cpu.h>
 #include <plat/s5p6440.h>
 #include <plat/s5p6442.h>
+#include <plat/s5p6450.h>
 #include <plat/s5pc100.h>
 #include <plat/s5pv210.h>
 #include <plat/s5pv310.h>
@@ -27,6 +28,7 @@
 
 static const char name_s5p6440[] = "S5P6440";
 static const char name_s5p6442[] = "S5P6442";
+static const char name_s5p6450[] = "S5P6450";
 static const char name_s5pc100[] = "S5PC100";
 static const char name_s5pv210[] = "S5PV210/S5PC110";
 static const char name_s5pv310[] = "S5PV310";
@@ -38,7 +40,7 @@
 		.map_io		= s5p6440_map_io,
 		.init_clocks	= s5p6440_init_clocks,
 		.init_uarts	= s5p6440_init_uarts,
-		.init		= s5p6440_init,
+		.init		= s5p64x0_init,
 		.name		= name_s5p6440,
 	}, {
 		.idcode		= 0x36442000,
@@ -49,6 +51,14 @@
 		.init		= s5p6442_init,
 		.name		= name_s5p6442,
 	}, {
+		.idcode		= 0x36450000,
+		.idmask		= 0xffffff00,
+		.map_io		= s5p6450_map_io,
+		.init_clocks	= s5p6450_init_clocks,
+		.init_uarts	= s5p6450_init_uarts,
+		.init		= s5p64x0_init,
+		.name		= name_s5p6450,
+	}, {
 		.idcode		= 0x43100000,
 		.idmask		= 0xfffff000,
 		.map_io		= s5pc100_map_io,
@@ -89,33 +99,11 @@
 		.length		= SZ_64K,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= (unsigned long)S3C_VA_UART,
-		.pfn		= __phys_to_pfn(S3C_PA_UART),
-		.length		= SZ_512K,
-		.type		= MT_DEVICE,
-#ifdef CONFIG_ARM_VIC
-	}, {
-		.virtual	= (unsigned long)VA_VIC0,
-		.pfn		= __phys_to_pfn(S5P_PA_VIC0),
-		.length		= SZ_16K,
-		.type		= MT_DEVICE,
-	}, {
-		.virtual	= (unsigned long)VA_VIC1,
-		.pfn		= __phys_to_pfn(S5P_PA_VIC1),
-		.length		= SZ_16K,
-		.type		= MT_DEVICE,
-#endif
-	}, {
 		.virtual	= (unsigned long)S3C_VA_TIMER,
 		.pfn		= __phys_to_pfn(S5P_PA_TIMER),
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
 	}, {
-		.virtual	= (unsigned long)S5P_VA_GPIO,
-		.pfn		= __phys_to_pfn(S5P_PA_GPIO),
-		.length		= SZ_4K,
-		.type		= MT_DEVICE,
-	}, {
 		.virtual	= (unsigned long)S3C_VA_WATCHDOG,
 		.pfn		= __phys_to_pfn(S3C_PA_WDT),
 		.length		= SZ_4K,
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/dev-onenand.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/dev-onenand.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/dev-onenand.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/dev-onenand.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,57 @@
+/* linux/arch/arm/plat-s5p/dev-onenand.c
+ *
+ * Copyright 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ *  Copyright (c) 2008-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * S5P series device definition for OneNAND devices
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+static struct resource s5p_onenand_resources[] = {
+	[0] = {
+		.start	= S5P_PA_ONENAND,
+		.end	= S5P_PA_ONENAND + SZ_128K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= S5P_PA_ONENAND_DMA,
+		.end	= S5P_PA_ONENAND_DMA + SZ_8K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= IRQ_ONENAND_AUDI,
+		.end	= IRQ_ONENAND_AUDI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s5p_device_onenand = {
+	.name		= "s5pc110-onenand",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(s5p_onenand_resources),
+	.resource	= s5p_onenand_resources,
+};
+
+void s5p_onenand_set_platdata(struct onenand_platform_data *pdata)
+{
+	struct onenand_platform_data *pd;
+
+	pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
+	if (!pd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	s5p_device_onenand.dev.platform_data = pd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/dev-uart.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/dev-uart.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/dev-uart.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/dev-uart.c	2011-01-04 19:50:19.000000000 -0500
@@ -119,6 +119,56 @@
 #endif
 };
 
+static struct resource s5p_uart4_resource[] = {
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 4
+	[0] = {
+		.start	= S5P_PA_UART4,
+		.end	= S5P_PA_UART4 + S5P_SZ_UART,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_S5P_UART_RX4,
+		.end	= IRQ_S5P_UART_RX4,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= IRQ_S5P_UART_TX4,
+		.end	= IRQ_S5P_UART_TX4,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= IRQ_S5P_UART_ERR4,
+		.end	= IRQ_S5P_UART_ERR4,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
+static struct resource s5p_uart5_resource[] = {
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 5
+	[0] = {
+		.start	= S5P_PA_UART5,
+		.end	= S5P_PA_UART5 + S5P_SZ_UART,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_S5P_UART_RX5,
+		.end	= IRQ_S5P_UART_RX5,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[2] = {
+		.start	= IRQ_S5P_UART_TX5,
+		.end	= IRQ_S5P_UART_TX5,
+		.flags	= IORESOURCE_IRQ,
+	},
+	[3] = {
+		.start	= IRQ_S5P_UART_ERR5,
+		.end	= IRQ_S5P_UART_ERR5,
+		.flags	= IORESOURCE_IRQ,
+	},
+#endif
+};
+
 struct s3c24xx_uart_resources s5p_uart_resources[] __initdata = {
 	[0] = {
 		.resources	= s5p_uart0_resource,
@@ -136,4 +186,12 @@
 		.resources	= s5p_uart3_resource,
 		.nr_resources	= ARRAY_SIZE(s5p_uart3_resource),
 	},
+	[4] = {
+		.resources	= s5p_uart4_resource,
+		.nr_resources	= ARRAY_SIZE(s5p_uart4_resource),
+	},
+	[5] = {
+		.resources	= s5p_uart5_resource,
+		.nr_resources	= ARRAY_SIZE(s5p_uart5_resource),
+	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/irqs.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/irqs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -94,4 +94,22 @@
 						((irq) - S5P_EINT_BASE1) : \
 						((irq) + 16 - S5P_EINT_BASE2))
 
+#define IRQ_EINT_BIT(x)		EINT_OFFSET(x)
+
+/* Typically only a few gpio chips require gpio interrupt support.
+   To avoid memory waste irq descriptors are allocated only for
+   S5P_GPIOINT_GROUP_COUNT chips, each with total number of
+   S5P_GPIOINT_GROUP_SIZE pins/irqs. Each GPIOINT group can be assiged
+   to any gpio chip with the s5p_register_gpio_interrupt() function */
+#define S5P_GPIOINT_GROUP_COUNT 4
+#define S5P_GPIOINT_GROUP_SIZE	8
+#define S5P_GPIOINT_COUNT	(S5P_GPIOINT_GROUP_COUNT * S5P_GPIOINT_GROUP_SIZE)
+
+/* IRQ types common for all s5p platforms */
+#define S5P_IRQ_TYPE_LEVEL_LOW		(0x00)
+#define S5P_IRQ_TYPE_LEVEL_HIGH		(0x01)
+#define S5P_IRQ_TYPE_EDGE_FALLING	(0x02)
+#define S5P_IRQ_TYPE_EDGE_RISING	(0x03)
+#define S5P_IRQ_TYPE_EDGE_BOTH		(0x04)
+
 #endif /* __ASM_PLAT_S5P_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/map-s5p.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/map-s5p.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/map-s5p.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/map-s5p.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,24 +13,38 @@
 #ifndef __ASM_PLAT_MAP_S5P_H
 #define __ASM_PLAT_MAP_S5P_H __FILE__
 
-#define S5P_VA_CHIPID		S3C_ADDR(0x00700000)
-#define S5P_VA_GPIO		S3C_ADDR(0x00500000)
-#define S5P_VA_SYSTIMER		S3C_ADDR(0x01200000)
-#define S5P_VA_SROMC		S3C_ADDR(0x01100000)
-#define S5P_VA_SYSRAM		S3C_ADDR(0x01180000)
+#define S5P_VA_CHIPID		S3C_ADDR(0x02000000)
+#define S5P_VA_CMU		S3C_ADDR(0x02100000)
+#define S5P_VA_GPIO		S3C_ADDR(0x02200000)
+#define S5P_VA_GPIO1		S5P_VA_GPIO
+#define S5P_VA_GPIO2		S3C_ADDR(0x02240000)
+#define S5P_VA_GPIO3		S3C_ADDR(0x02280000)
 
-#define S5P_VA_COMBINER_BASE	S3C_ADDR(0x00600000)
+#define S5P_VA_SYSRAM		S3C_ADDR(0x02400000)
+#define S5P_VA_DMC0		S3C_ADDR(0x02440000)
+#define S5P_VA_DMC1		S3C_ADDR(0x02480000)
+#define S5P_VA_SROMC		S3C_ADDR(0x024C0000)
+
+#define S5P_VA_SYSTIMER		S3C_ADDR(0x02500000)
+#define S5P_VA_L2CC		S3C_ADDR(0x02600000)
+
+#define S5P_VA_COMBINER_BASE	S3C_ADDR(0x02700000)
 #define S5P_VA_COMBINER(x)	(S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10)
 
-#define S5P_VA_COREPERI_BASE	S3C_ADDR(0x00800000)
+#define S5P_VA_COREPERI_BASE	S3C_ADDR(0x02800000)
 #define S5P_VA_COREPERI(x)	(S5P_VA_COREPERI_BASE + (x))
 #define S5P_VA_SCU		S5P_VA_COREPERI(0x0)
 #define S5P_VA_GIC_CPU		S5P_VA_COREPERI(0x100)
 #define S5P_VA_TWD		S5P_VA_COREPERI(0x600)
 #define S5P_VA_GIC_DIST		S5P_VA_COREPERI(0x1000)
 
-#define S5P_VA_L2CC		S3C_ADDR(0x00900000)
-#define S5P_VA_CMU		S3C_ADDR(0x00920000)
+#define S3C_VA_USB_HSPHY	S3C_ADDR(0x02900000)
+
+#define VA_VIC(x)		(S3C_VA_IRQ + ((x) * 0x10000))
+#define VA_VIC0			VA_VIC(0)
+#define VA_VIC1			VA_VIC(1)
+#define VA_VIC2			VA_VIC(2)
+#define VA_VIC3			VA_VIC(3)
 
 #define S5P_VA_UART(x)		(S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 #define S5P_VA_UART0		S5P_VA_UART(0)
@@ -42,10 +56,4 @@
 #define S3C_UART_OFFSET		(0x400)
 #endif
 
-#define VA_VIC(x)		(S3C_VA_IRQ + ((x) * 0x10000))
-#define VA_VIC0			VA_VIC(0)
-#define VA_VIC1			VA_VIC(1)
-#define VA_VIC2			VA_VIC(2)
-#define VA_VIC3			VA_VIC(3)
-
 #endif /* __ASM_PLAT_MAP_S5P_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/pll.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/pll.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/pll.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 }
 
 #define PLL46XX_KDIV_MASK	(0xFFFF)
+#define PLL4650C_KDIV_MASK	(0xFFF)
 #define PLL46XX_MDIV_MASK	(0x1FF)
 #define PLL46XX_PDIV_MASK	(0x3F)
 #define PLL46XX_SDIV_MASK	(0x7)
@@ -57,6 +58,7 @@
 enum pll46xx_type_t {
 	pll_4600,
 	pll_4650,
+	pll_4650c,
 };
 
 static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
@@ -72,6 +74,11 @@
 	sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
 	kdiv = pll_con1 & PLL46XX_KDIV_MASK;
 
+	if (pll_type == pll_4650c)
+		kdiv = pll_con1 & PLL4650C_KDIV_MASK;
+	else
+		kdiv = pll_con1 & PLL46XX_KDIV_MASK;
+
 	tmp = baseclk;
 
 	if (pll_type == pll_4600) {
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p6440.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p6440.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p6440.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p6440.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,24 +12,23 @@
 
  /* Common init code for S5P6440 related SoCs */
 
-extern void s5p6440_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 extern void s5p6440_register_clocks(void);
 extern void s5p6440_setup_clocks(void);
 
 #ifdef CONFIG_CPU_S5P6440
 
-extern  int s5p6440_init(void);
+extern  int s5p64x0_init(void);
 extern void s5p6440_init_irq(void);
 extern void s5p6440_map_io(void);
 extern void s5p6440_init_clocks(int xtal);
 
-#define s5p6440_init_uarts s5p6440_common_init_uarts
+extern void s5p6440_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
 #else
 #define s5p6440_init_clocks NULL
 #define s5p6440_init_uarts NULL
 #define s5p6440_map_io NULL
-#define s5p6440_init NULL
+#define s5p64x0_init NULL
 #endif
 
 /* S5P6440 timer */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p6450.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p6450.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p6450.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p6450.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,36 @@
+/* arch/arm/plat-s5p/include/plat/s5p6450.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Header file for s5p6450 cpu support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* Common init code for S5P6450 related SoCs */
+
+extern void s5p6450_register_clocks(void);
+extern void s5p6450_setup_clocks(void);
+
+#ifdef CONFIG_CPU_S5P6450
+
+extern  int s5p64x0_init(void);
+extern void s5p6450_init_irq(void);
+extern void s5p6450_map_io(void);
+extern void s5p6450_init_clocks(int xtal);
+
+extern void s5p6450_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+#else
+#define s5p6450_init_clocks NULL
+#define s5p6450_init_uarts NULL
+#define s5p6450_map_io NULL
+#define s5p64x0_init NULL
+#endif
+
+/* S5P6450 timer */
+
+extern struct sys_timer s5p6450_timer;
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p-clock.h linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p-clock.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/include/plat/s5p-clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/include/plat/s5p-clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /* linux/arch/arm/plat-s5p/include/plat/s5p-clock.h
  *
- * Copyright 2009 Samsung Electronics Co., Ltd.
- *		http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
  *
  * Header file for s5p clock support
  *
@@ -20,6 +20,7 @@
 #define clk_fin_apll clk_ext_xtal_mux
 #define clk_fin_mpll clk_ext_xtal_mux
 #define clk_fin_epll clk_ext_xtal_mux
+#define clk_fin_dpll clk_ext_xtal_mux
 #define clk_fin_vpll clk_ext_xtal_mux
 #define clk_fin_hpll clk_ext_xtal_mux
 
@@ -30,6 +31,7 @@
 extern struct clk clk_fout_apll;
 extern struct clk clk_fout_mpll;
 extern struct clk clk_fout_epll;
+extern struct clk clk_fout_dpll;
 extern struct clk clk_fout_vpll;
 extern struct clk clk_arm;
 extern struct clk clk_vpll;
@@ -37,8 +39,12 @@
 extern struct clksrc_sources clk_src_apll;
 extern struct clksrc_sources clk_src_mpll;
 extern struct clksrc_sources clk_src_epll;
+extern struct clksrc_sources clk_src_dpll;
 
-extern int s5p6440_clk48m_ctrl(struct clk *clk, int enable);
 extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
 
+/* Common EPLL operations for S5P platform */
+extern int s5p_epll_enable(struct clk *clk, int enable);
+extern unsigned long s5p_epll_get_rate(struct clk *clk);
+
 #endif /* __ASM_PLAT_S5P_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-eint.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-eint.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-eint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-eint.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,23 +67,23 @@
 
 	switch (type) {
 	case IRQ_TYPE_EDGE_RISING:
-		newvalue = S5P_EXTINT_RISEEDGE;
+		newvalue = S5P_IRQ_TYPE_EDGE_RISING;
 		break;
 
 	case IRQ_TYPE_EDGE_FALLING:
-		newvalue = S5P_EXTINT_FALLEDGE;
+		newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
 		break;
 
 	case IRQ_TYPE_EDGE_BOTH:
-		newvalue = S5P_EXTINT_BOTHEDGE;
+		newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
 		break;
 
 	case IRQ_TYPE_LEVEL_LOW:
-		newvalue = S5P_EXTINT_LOWLEV;
+		newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
 		break;
 
 	case IRQ_TYPE_LEVEL_HIGH:
-		newvalue = S5P_EXTINT_HILEV;
+		newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-gpioint.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-gpioint.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-gpioint.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-gpioint.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,237 @@
+/* linux/arch/arm/plat-s5p/irq-gpioint.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <mach/map.h>
+#include <plat/gpio-core.h>
+#include <plat/gpio-cfg.h>
+
+#define S5P_GPIOREG(x)			(S5P_VA_GPIO + (x))
+
+#define GPIOINT_CON_OFFSET		0x700
+#define GPIOINT_MASK_OFFSET		0x900
+#define GPIOINT_PEND_OFFSET		0xA00
+
+static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
+
+static int s5p_gpioint_get_group(unsigned int irq)
+{
+	struct gpio_chip *chip = get_irq_data(irq);
+	struct s3c_gpio_chip *s3c_chip = container_of(chip,
+			struct s3c_gpio_chip, chip);
+	int group;
+
+	for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++)
+		if (s3c_chip == irq_chips[group])
+			break;
+
+	return group;
+}
+
+static int s5p_gpioint_get_offset(unsigned int irq)
+{
+	struct gpio_chip *chip = get_irq_data(irq);
+	struct s3c_gpio_chip *s3c_chip = container_of(chip,
+			struct s3c_gpio_chip, chip);
+
+	return irq - s3c_chip->irq_base;
+}
+
+static void s5p_gpioint_ack(unsigned int irq)
+{
+	int group, offset, pend_offset;
+	unsigned int value;
+
+	group = s5p_gpioint_get_group(irq);
+	offset = s5p_gpioint_get_offset(irq);
+	pend_offset = group << 2;
+
+	value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
+	value |= 1 << offset;
+	__raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
+}
+
+static void s5p_gpioint_mask(unsigned int irq)
+{
+	int group, offset, mask_offset;
+	unsigned int value;
+
+	group = s5p_gpioint_get_group(irq);
+	offset = s5p_gpioint_get_offset(irq);
+	mask_offset = group << 2;
+
+	value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+	value |= 1 << offset;
+	__raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+}
+
+static void s5p_gpioint_unmask(unsigned int irq)
+{
+	int group, offset, mask_offset;
+	unsigned int value;
+
+	group = s5p_gpioint_get_group(irq);
+	offset = s5p_gpioint_get_offset(irq);
+	mask_offset = group << 2;
+
+	value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+	value &= ~(1 << offset);
+	__raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset);
+}
+
+static void s5p_gpioint_mask_ack(unsigned int irq)
+{
+	s5p_gpioint_mask(irq);
+	s5p_gpioint_ack(irq);
+}
+
+static int s5p_gpioint_set_type(unsigned int irq, unsigned int type)
+{
+	int group, offset, con_offset;
+	unsigned int value;
+
+	group = s5p_gpioint_get_group(irq);
+	offset = s5p_gpioint_get_offset(irq);
+	con_offset = group << 2;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		type = S5P_IRQ_TYPE_EDGE_RISING;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		type = S5P_IRQ_TYPE_EDGE_FALLING;
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		type = S5P_IRQ_TYPE_EDGE_BOTH;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		type = S5P_IRQ_TYPE_LEVEL_HIGH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		type = S5P_IRQ_TYPE_LEVEL_LOW;
+		break;
+	case IRQ_TYPE_NONE:
+	default:
+		printk(KERN_WARNING "No irq type\n");
+		return -EINVAL;
+	}
+
+	value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset);
+	value &= ~(0x7 << (offset * 0x4));
+	value |= (type << (offset * 0x4));
+	__raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset);
+
+	return 0;
+}
+
+struct irq_chip s5p_gpioint = {
+	.name		= "s5p_gpioint",
+	.ack		= s5p_gpioint_ack,
+	.mask		= s5p_gpioint_mask,
+	.mask_ack	= s5p_gpioint_mask_ack,
+	.unmask		= s5p_gpioint_unmask,
+	.set_type	= s5p_gpioint_set_type,
+};
+
+static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int group, offset, pend_offset, mask_offset;
+	int real_irq;
+	unsigned int pend, mask;
+
+	for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) {
+		pend_offset = group << 2;
+		pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) +
+				pend_offset);
+		if (!pend)
+			continue;
+
+		mask_offset = group << 2;
+		mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) +
+				mask_offset);
+		pend &= ~mask;
+
+		for (offset = 0; offset < 8; offset++) {
+			if (pend & (1 << offset)) {
+				struct s3c_gpio_chip *chip = irq_chips[group];
+				if (chip) {
+					real_irq = chip->irq_base + offset;
+					generic_handle_irq(real_irq);
+				}
+			}
+		}
+	}
+}
+
+static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
+{
+	static int used_gpioint_groups = 0;
+	static bool handler_registered = 0;
+	int irq, group = chip->group;
+	int i;
+
+	if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
+		return -ENOMEM;
+
+	chip->irq_base = S5P_GPIOINT_BASE +
+			 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
+	used_gpioint_groups++;
+
+	if (!handler_registered) {
+		set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
+		handler_registered = 1;
+	}
+
+	irq_chips[group] = chip;
+	for (i = 0; i < chip->chip.ngpio; i++) {
+		irq = chip->irq_base + i;
+		set_irq_chip(irq, &s5p_gpioint);
+		set_irq_data(irq, &chip->chip);
+		set_irq_handler(irq, handle_level_irq);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+	return 0;
+}
+
+int __init s5p_register_gpio_interrupt(int pin)
+{
+	struct s3c_gpio_chip *my_chip = s3c_gpiolib_getchip(pin);
+	int offset, group;
+	int ret;
+
+	if (!my_chip)
+		return -EINVAL;
+
+	offset = pin - my_chip->chip.base;
+	group = my_chip->group;
+
+	/* check if the group has been already registered */
+	if (my_chip->irq_base)
+		return my_chip->irq_base + offset;
+
+	/* register gpio group */
+	ret = s5p_gpioint_add(my_chip);
+	if (ret == 0) {
+		my_chip->chip.to_irq = samsung_gpiolib_to_irq;
+		printk(KERN_INFO "Registered interrupt support for gpio group %d.\n",
+		       group);
+		return my_chip->irq_base + offset;
+	}
+	return ret;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-pm.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-pm.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/irq-pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/irq-pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,93 @@
+/* linux/arch/arm/plat-s5p/irq-pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Based on arch/arm/plat-s3c24xx/irq-pm.c,
+ * Copyright (c) 2003,2004 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *	http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+
+#include <plat/cpu.h>
+#include <plat/irqs.h>
+#include <plat/pm.h>
+#include <mach/map.h>
+
+#include <mach/regs-gpio.h>
+#include <mach/regs-irq.h>
+
+/* state for IRQs over sleep */
+
+/* default is to allow for EINT0..EINT31, and IRQ_RTC_TIC, IRQ_RTC_ALARM,
+ * as wakeup sources
+ *
+ * set bit to 1 in allow bitfield to enable the wakeup settings on it
+*/
+
+unsigned long s3c_irqwake_intallow	= 0x00000006L;
+unsigned long s3c_irqwake_eintallow	= 0xffffffffL;
+
+int s3c_irq_wake(unsigned int irqno, unsigned int state)
+{
+	unsigned long irqbit;
+
+	switch (irqno) {
+	case IRQ_RTC_TIC:
+	case IRQ_RTC_ALARM:
+		irqbit = 1 << (irqno + 1 - IRQ_RTC_ALARM);
+		if (!state)
+			s3c_irqwake_intmask |= irqbit;
+		else
+			s3c_irqwake_intmask &= ~irqbit;
+		break;
+	default:
+		return -ENOENT;
+	}
+	return 0;
+}
+
+static struct sleep_save eint_save[] = {
+	SAVE_ITEM(S5P_EINT_CON(0)),
+	SAVE_ITEM(S5P_EINT_CON(1)),
+	SAVE_ITEM(S5P_EINT_CON(2)),
+	SAVE_ITEM(S5P_EINT_CON(3)),
+
+	SAVE_ITEM(S5P_EINT_FLTCON(0)),
+	SAVE_ITEM(S5P_EINT_FLTCON(1)),
+	SAVE_ITEM(S5P_EINT_FLTCON(2)),
+	SAVE_ITEM(S5P_EINT_FLTCON(3)),
+	SAVE_ITEM(S5P_EINT_FLTCON(4)),
+	SAVE_ITEM(S5P_EINT_FLTCON(5)),
+	SAVE_ITEM(S5P_EINT_FLTCON(6)),
+	SAVE_ITEM(S5P_EINT_FLTCON(7)),
+
+	SAVE_ITEM(S5P_EINT_MASK(0)),
+	SAVE_ITEM(S5P_EINT_MASK(1)),
+	SAVE_ITEM(S5P_EINT_MASK(2)),
+	SAVE_ITEM(S5P_EINT_MASK(3)),
+};
+
+int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+	s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save));
+
+	return 0;
+}
+
+int s3c24xx_irq_resume(struct sys_device *dev)
+{
+	s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save));
+
+	return 0;
+}
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-s5p/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
 
 config PLAT_S5P
 	bool
-	depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310)
+	depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310)
 	default y
 	select ARM_VIC if !ARCH_S5PV310
 	select ARM_GIC if ARCH_S5PV310
@@ -30,7 +30,12 @@
 	bool
 	help
 	  Use the external interrupts (other than GPIO interrupts.)
-	  Note: Do not choose this for S5P6440.
+	  Note: Do not choose this for S5P6440 and S5P6450.
+
+config S5P_GPIO_INT
+	bool
+	help
+	  Common code for the GPIO interrupts (other than external interrupts.)
 
 config S5P_DEV_FIMC0
 	bool
@@ -46,3 +51,8 @@
 	bool
 	help
 	  Compile in platform device definitions for FIMC controller 2
+
+config S5P_DEV_ONENAND
+	bool
+	help
+	  Compile in platform device definition for OneNAND controller
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-s5p/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -18,9 +18,13 @@
 obj-y				+= clock.o
 obj-y				+= irq.o
 obj-$(CONFIG_S5P_EXT_INT)	+= irq-eint.o
+obj-$(CONFIG_S5P_GPIO_INT)	+= irq-gpioint.o
+obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_PM)		+= irq-pm.o
 
 # devices
 
 obj-$(CONFIG_S5P_DEV_FIMC0)	+= dev-fimc0.o
 obj-$(CONFIG_S5P_DEV_FIMC1)	+= dev-fimc1.o
 obj-$(CONFIG_S5P_DEV_FIMC2)	+= dev-fimc2.o
+obj-$(CONFIG_S5P_DEV_ONENAND)	+= dev-onenand.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-s5p/pm.c linux-libre-2.6.37-gnu/arch/arm/plat-s5p/pm.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-s5p/pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-s5p/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,52 @@
+/* linux/arch/arm/plat-s5p/pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P Power Manager (Suspend-To-RAM) support
+ *
+ * Based on arch/arm/plat-s3c24xx/pm.c
+ * Copyright (c) 2004,2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/suspend.h>
+#include <plat/pm.h>
+
+#define PFX "s5p pm: "
+
+/* s3c_pm_check_resume_pin
+ *
+ * check to see if the pin is configured correctly for sleep mode, and
+ * make any necessary adjustments if it is not
+*/
+
+static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
+{
+	/* nothing here yet */
+}
+
+/* s3c_pm_configure_extint
+ *
+ * configure all external interrupt pins
+*/
+
+void s3c_pm_configure_extint(void)
+{
+	/* nothing here yet */
+}
+
+void s3c_pm_restore_core(void)
+{
+	/* nothing here yet */
+}
+
+void s3c_pm_save_core(void)
+{
+	/* nothing here yet */
+}
+
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc1.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc1.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc1.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc1.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,7 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc1 = {
@@ -59,17 +60,20 @@
 {
 	struct s3c_sdhci_platdata *set = &s3c_hsmmc1_def_platdata;
 
-	set->max_width = pd->max_width;
 	set->cd_type = pd->cd_type;
 	set->ext_cd_init = pd->ext_cd_init;
 	set->ext_cd_cleanup = pd->ext_cd_cleanup;
 	set->ext_cd_gpio = pd->ext_cd_gpio;
 	set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
 
+	if (pd->max_width)
+		set->max_width = pd->max_width;
 	if (pd->cfg_gpio)
 		set->cfg_gpio = pd->cfg_gpio;
 	if (pd->cfg_card)
 		set->cfg_card = pd->cfg_card;
 	if (pd->host_caps)
-		set->host_caps = pd->host_caps;
+		set->host_caps |= pd->host_caps;
+	if (pd->clk_type)
+		set->clk_type = pd->clk_type;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc2.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc2.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc2.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,6 +42,7 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc2 = {
@@ -60,17 +61,20 @@
 {
 	struct s3c_sdhci_platdata *set = &s3c_hsmmc2_def_platdata;
 
-	set->max_width = pd->max_width;
 	set->cd_type = pd->cd_type;
 	set->ext_cd_init = pd->ext_cd_init;
 	set->ext_cd_cleanup = pd->ext_cd_cleanup;
 	set->ext_cd_gpio = pd->ext_cd_gpio;
 	set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
 
+	if (pd->max_width)
+		set->max_width = pd->max_width;
 	if (pd->cfg_gpio)
 		set->cfg_gpio = pd->cfg_gpio;
 	if (pd->cfg_card)
 		set->cfg_card = pd->cfg_card;
 	if (pd->host_caps)
-		set->host_caps = pd->host_caps;
+		set->host_caps |= pd->host_caps;
+	if (pd->clk_type)
+		set->clk_type = pd->clk_type;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc3.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc3.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc3.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,8 +33,8 @@
 		.flags	= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start	= IRQ_MMC3,
-		.end	= IRQ_MMC3,
+		.start	= IRQ_HSMMC3,
+		.end	= IRQ_HSMMC3,
 		.flags	= IORESOURCE_IRQ,
 	}
 };
@@ -45,6 +45,7 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc3 = {
@@ -63,15 +64,20 @@
 {
 	struct s3c_sdhci_platdata *set = &s3c_hsmmc3_def_platdata;
 
-	set->max_width = pd->max_width;
 	set->cd_type = pd->cd_type;
 	set->ext_cd_init = pd->ext_cd_init;
 	set->ext_cd_cleanup = pd->ext_cd_cleanup;
 	set->ext_cd_gpio = pd->ext_cd_gpio;
 	set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
 
+	if (pd->max_width)
+		set->max_width = pd->max_width;
 	if (pd->cfg_gpio)
 		set->cfg_gpio = pd->cfg_gpio;
 	if (pd->cfg_card)
 		set->cfg_card = pd->cfg_card;
+	if (pd->host_caps)
+		set->host_caps |= pd->host_caps;
+	if (pd->clk_type)
+		set->clk_type = pd->clk_type;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-hsmmc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-hsmmc.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,7 @@
 	.max_width	= 4,
 	.host_caps	= (MMC_CAP_4_BIT_DATA |
 			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
+	.clk_type	= S3C_SDHCI_CLK_DIV_INTERNAL,
 };
 
 struct platform_device s3c_device_hsmmc0 = {
@@ -59,17 +60,20 @@
 {
 	struct s3c_sdhci_platdata *set = &s3c_hsmmc0_def_platdata;
 
-	set->max_width = pd->max_width;
 	set->cd_type = pd->cd_type;
 	set->ext_cd_init = pd->ext_cd_init;
 	set->ext_cd_cleanup = pd->ext_cd_cleanup;
 	set->ext_cd_gpio = pd->ext_cd_gpio;
 	set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert;
 
+	if (pd->max_width)
+		set->max_width = pd->max_width;
 	if (pd->cfg_gpio)
 		set->cfg_gpio = pd->cfg_gpio;
 	if (pd->cfg_card)
 		set->cfg_card = pd->cfg_card;
 	if (pd->host_caps)
-		set->host_caps = pd->host_caps;
+		set->host_caps |= pd->host_caps;
+	if (pd->clk_type)
+		set->clk_type = pd->clk_type;
 }
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c2.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c2.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c2.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,8 +32,8 @@
 		.flags = IORESOURCE_MEM,
 	},
 	[1] = {
-		.start = IRQ_CAN0,
-		.end   = IRQ_CAN0,
+		.start = IRQ_IIC2,
+		.end   = IRQ_IIC2,
 		.flags = IORESOURCE_IRQ,
 	},
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c3.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c3.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-samsung/dev-i2c3.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P series device definition for i2c device 3
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+	[0] = {
+		.start	= S3C_PA_IIC3,
+		.end	= S3C_PA_IIC3 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_IIC3,
+		.end	= IRQ_IIC3,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_i2c3 = {
+	.name		= "s3c2440-i2c",
+	.id		= 3,
+	.num_resources	= ARRAY_SIZE(s3c_i2c_resource),
+	.resource	= s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data3 __initdata = {
+	.flags		= 0,
+	.bus_num	= 3,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+};
+
+void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+	struct s3c2410_platform_i2c *npd;
+
+	if (!pd)
+		pd = &default_i2c_data3;
+
+	npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+	if (!npd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	else if (!npd->cfg_gpio)
+		npd->cfg_gpio = s3c_i2c3_cfg_gpio;
+
+	s3c_device_i2c3.dev.platform_data = npd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c4.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c4.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c4.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c4.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-samsung/dev-i2c4.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P series device definition for i2c device 3
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+	[0] = {
+		.start	= S3C_PA_IIC4,
+		.end	= S3C_PA_IIC4 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_IIC4,
+		.end	= IRQ_IIC4,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_i2c4 = {
+	.name		= "s3c2440-i2c",
+	.id		= 4,
+	.num_resources	= ARRAY_SIZE(s3c_i2c_resource),
+	.resource	= s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data4 __initdata = {
+	.flags		= 0,
+	.bus_num	= 4,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+};
+
+void __init s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+	struct s3c2410_platform_i2c *npd;
+
+	if (!pd)
+		pd = &default_i2c_data4;
+
+	npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+	if (!npd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	else if (!npd->cfg_gpio)
+		npd->cfg_gpio = s3c_i2c4_cfg_gpio;
+
+	s3c_device_i2c4.dev.platform_data = npd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c5.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c5.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c5.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c5.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-samsung/dev-i2c3.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P series device definition for i2c device 3
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+	[0] = {
+		.start	= S3C_PA_IIC5,
+		.end	= S3C_PA_IIC5 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_IIC5,
+		.end	= IRQ_IIC5,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_i2c5 = {
+	.name		= "s3c2440-i2c",
+	.id		= 5,
+	.num_resources	= ARRAY_SIZE(s3c_i2c_resource),
+	.resource	= s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data5 __initdata = {
+	.flags		= 0,
+	.bus_num	= 5,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+};
+
+void __init s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+	struct s3c2410_platform_i2c *npd;
+
+	if (!pd)
+		pd = &default_i2c_data5;
+
+	npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+	if (!npd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	else if (!npd->cfg_gpio)
+		npd->cfg_gpio = s3c_i2c5_cfg_gpio;
+
+	s3c_device_i2c5.dev.platform_data = npd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c6.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c6.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c6.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c6.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-samsung/dev-i2c6.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P series device definition for i2c device 6
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+	[0] = {
+		.start	= S3C_PA_IIC6,
+		.end	= S3C_PA_IIC6 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_IIC6,
+		.end	= IRQ_IIC6,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_i2c6 = {
+	.name		= "s3c2440-i2c",
+	.id		= 6,
+	.num_resources	= ARRAY_SIZE(s3c_i2c_resource),
+	.resource	= s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data6 __initdata = {
+	.flags		= 0,
+	.bus_num	= 6,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+};
+
+void __init s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+	struct s3c2410_platform_i2c *npd;
+
+	if (!pd)
+		pd = &default_i2c_data6;
+
+	npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+	if (!npd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	else if (!npd->cfg_gpio)
+		npd->cfg_gpio = s3c_i2c6_cfg_gpio;
+
+	s3c_device_i2c6.dev.platform_data = npd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c7.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c7.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/dev-i2c7.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/dev-i2c7.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/* linux/arch/arm/plat-samsung/dev-i2c7.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S5P series device definition for i2c device 7
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+
+static struct resource s3c_i2c_resource[] = {
+	[0] = {
+		.start	= S3C_PA_IIC7,
+		.end	= S3C_PA_IIC7 + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= IRQ_IIC7,
+		.end	= IRQ_IIC7,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device s3c_device_i2c7 = {
+	.name		= "s3c2440-i2c",
+	.id		= 7,
+	.num_resources	= ARRAY_SIZE(s3c_i2c_resource),
+	.resource	= s3c_i2c_resource,
+};
+
+static struct s3c2410_platform_i2c default_i2c_data7 __initdata = {
+	.flags		= 0,
+	.bus_num	= 7,
+	.slave_addr	= 0x10,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
+};
+
+void __init s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *pd)
+{
+	struct s3c2410_platform_i2c *npd;
+
+	if (!pd)
+		pd = &default_i2c_data7;
+
+	npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
+	if (!npd)
+		printk(KERN_ERR "%s: no memory for platform data\n", __func__);
+	else if (!npd->cfg_gpio)
+		npd->cfg_gpio = s3c_i2c7_cfg_gpio;
+
+	s3c_device_i2c7.dev.platform_data = npd;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/gpio.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -157,3 +157,11 @@
 	if (ret >= 0)
 		s3c_gpiolib_track(chip);
 }
+
+int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+	struct s3c_gpio_chip *s3c_chip = container_of(chip,
+			struct s3c_gpio_chip, chip);
+
+	return s3c_chip->irq_base + offset;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/gpio-config.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/gpio-config.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/gpio-config.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/gpio-config.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,37 @@
 }
 EXPORT_SYMBOL(s3c_gpio_cfgpin);
 
+int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr,
+			  unsigned int cfg)
+{
+	int ret;
+
+	for (; nr > 0; nr--, start++) {
+		ret = s3c_gpio_cfgpin(start, cfg);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range);
+
+int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr,
+			  unsigned int cfg, s3c_gpio_pull_t pull)
+{
+	int ret;
+
+	for (; nr > 0; nr--, start++) {
+		s3c_gpio_setpull(start, pull);
+		ret = s3c_gpio_cfgpin(start, cfg);
+		if (ret != 0)
+			return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range);
+
 unsigned s3c_gpio_getcfg(unsigned int pin)
 {
 	struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
@@ -80,6 +111,25 @@
 }
 EXPORT_SYMBOL(s3c_gpio_setpull);
 
+s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin)
+{
+	struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);
+	unsigned long flags;
+	int offset;
+	u32 pup = 0;
+
+	if (chip) {
+		offset = pin - chip->chip.base;
+
+		s3c_gpio_lock(chip, flags);
+		pup = s3c_gpio_do_getpull(chip, offset);
+		s3c_gpio_unlock(chip, flags);
+	}
+
+	return (__force s3c_gpio_pull_t)pup;
+}
+EXPORT_SYMBOL(s3c_gpio_getpull);
+
 #ifdef CONFIG_S3C_GPIO_CFG_S3C24XX
 int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip,
 			      unsigned int off, unsigned int cfg)
@@ -230,18 +280,17 @@
 }
 #endif
 
-#ifdef CONFIG_S3C_GPIO_PULL_UP
-int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
-			 unsigned int off, s3c_gpio_pull_t pull)
+#if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN)
+static int s3c_gpio_setpull_1(struct s3c_gpio_chip *chip,
+			 unsigned int off, s3c_gpio_pull_t pull,
+			 s3c_gpio_pull_t updown)
 {
 	void __iomem *reg = chip->base + 0x08;
 	u32 pup = __raw_readl(reg);
 
-	pup = __raw_readl(reg);
-
-	if (pup == S3C_GPIO_PULL_UP)
+	if (pull == updown)
 		pup &= ~(1 << off);
-	else if (pup == S3C_GPIO_PULL_NONE)
+	else if (pull == S3C_GPIO_PULL_NONE)
 		pup |= (1 << off);
 	else
 		return -EINVAL;
@@ -250,17 +299,45 @@
 	return 0;
 }
 
-s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
-				     unsigned int off)
+static s3c_gpio_pull_t s3c_gpio_getpull_1(struct s3c_gpio_chip *chip,
+				     unsigned int off, s3c_gpio_pull_t updown)
 {
 	void __iomem *reg = chip->base + 0x08;
 	u32 pup = __raw_readl(reg);
 
 	pup &= (1 << off);
-	return pup ? S3C_GPIO_PULL_NONE : S3C_GPIO_PULL_UP;
+	return pup ? S3C_GPIO_PULL_NONE : updown;
+}
+#endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */
+
+#ifdef CONFIG_S3C_GPIO_PULL_UP
+s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip,
+				     unsigned int off)
+{
+	return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP);
+}
+
+int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip,
+			 unsigned int off, s3c_gpio_pull_t pull)
+{
+	return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP);
 }
 #endif /* CONFIG_S3C_GPIO_PULL_UP */
 
+#ifdef CONFIG_S3C_GPIO_PULL_DOWN
+s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip,
+				     unsigned int off)
+{
+	return s3c_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN);
+}
+
+int s3c_gpio_setpull_1down(struct s3c_gpio_chip *chip,
+			 unsigned int off, s3c_gpio_pull_t pull)
+{
+	return s3c_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
+}
+#endif /* CONFIG_S3C_GPIO_PULL_DOWN */
+
 #ifdef CONFIG_S5P_GPIO_DRVSTR
 s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
 {
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/adc.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/adc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/adc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/adc.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /* arch/arm/plat-samsung/include/plat/adc.h
  *
  * Copyright (c) 2008 Simtec Electronics
- *	http://armlinux.simnte.co.uk/
+ *	http://armlinux.simtec.co.uk/	
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C ADC driver information
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/audio.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/audio.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/audio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/audio.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,15 @@
 #define S3C64XX_AC97_GPE  1
 extern void s3c64xx_ac97_setup_gpio(int);
 
+/*
+ * The machine init code calls s5p*_spdif_setup_gpio with
+ * one of these defines in order to select appropriate bank
+ * of GPIO for S/PDIF pins
+ */
+#define S5PC100_SPDIF_GPD  0
+#define S5PC100_SPDIF_GPG3 1
+extern void s5pc100_spdif_setup_gpio(int);
+
 /**
  * struct s3c_audio_pdata - common platform data for audio device drivers
  * @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/cpu.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/cpu.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 extern struct sysdev_class s3c2443_sysclass;
 extern struct sysdev_class s3c6410_sysclass;
 extern struct sysdev_class s3c64xx_sysclass;
-extern struct sysdev_class s5p6440_sysclass;
+extern struct sysdev_class s5p64x0_sysclass;
 extern struct sysdev_class s5p6442_sysclass;
 extern struct sysdev_class s5pv210_sysclass;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/devs.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/devs.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/devs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/devs.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,8 @@
 extern struct platform_device s3c64xx_device_spi0;
 extern struct platform_device s3c64xx_device_spi1;
 
+extern struct platform_device s3c_device_pcm;
+
 extern struct platform_device s3c64xx_device_pcm0;
 extern struct platform_device s3c64xx_device_pcm1;
 
@@ -46,6 +48,11 @@
 extern struct platform_device s3c_device_i2c0;
 extern struct platform_device s3c_device_i2c1;
 extern struct platform_device s3c_device_i2c2;
+extern struct platform_device s3c_device_i2c3;
+extern struct platform_device s3c_device_i2c4;
+extern struct platform_device s3c_device_i2c5;
+extern struct platform_device s3c_device_i2c6;
+extern struct platform_device s3c_device_i2c7;
 extern struct platform_device s3c_device_rtc;
 extern struct platform_device s3c_device_adc;
 extern struct platform_device s3c_device_sdi;
@@ -67,13 +74,15 @@
 extern struct platform_device s5pv210_device_spi1;
 extern struct platform_device s5p6440_device_spi0;
 extern struct platform_device s5p6440_device_spi1;
+extern struct platform_device s5p6450_device_spi0;
+extern struct platform_device s5p6450_device_spi1;
 
 extern struct platform_device s3c_device_hwmon;
 
 extern struct platform_device s3c_device_nand;
 extern struct platform_device s3c_device_onenand;
 extern struct platform_device s3c64xx_device_onenand1;
-extern struct platform_device s5pc110_device_onenand;
+extern struct platform_device s5p_device_onenand;
 
 extern struct platform_device s3c_device_usbgadget;
 extern struct platform_device s3c_device_usb_hsotg;
@@ -85,6 +94,7 @@
 extern struct platform_device s5pv210_device_iis0;
 extern struct platform_device s5pv210_device_iis1;
 extern struct platform_device s5pv210_device_iis2;
+extern struct platform_device s5pv210_device_spdif;
 
 extern struct platform_device s5p6442_device_pcm0;
 extern struct platform_device s5p6442_device_pcm1;
@@ -95,12 +105,16 @@
 extern struct platform_device s5p6440_device_pcm;
 extern struct platform_device s5p6440_device_iis;
 
+extern struct platform_device s5p6450_device_iis0;
+extern struct platform_device s5p6450_device_pcm0;
+
 extern struct platform_device s5pc100_device_ac97;
 extern struct platform_device s5pc100_device_pcm0;
 extern struct platform_device s5pc100_device_pcm1;
 extern struct platform_device s5pc100_device_iis0;
 extern struct platform_device s5pc100_device_iis1;
 extern struct platform_device s5pc100_device_iis2;
+extern struct platform_device s5pc100_device_spdif;
 
 extern struct platform_device samsung_device_keypad;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg.h	2011-01-04 19:50:19.000000000 -0500
@@ -108,6 +108,19 @@
  */
 extern unsigned s3c_gpio_getcfg(unsigned int pin);
 
+/**
+ * s3c_gpio_cfgpin_range() - Change the GPIO function for configuring pin range
+ * @start: The pin number to start at
+ * @nr: The number of pins to configure from @start.
+ * @cfg: The configuration for the pin's function
+ *
+ * Call s3c_gpio_cfgpin() for the @nr pins starting at @start.
+ *
+ * @sa s3c_gpio_cfgpin.
+ */
+extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr,
+				 unsigned int cfg);
+
 /* Define values for the pull-{up,down} available for each gpio pin.
  *
  * These values control the state of the weak pull-{up,down} resistors
@@ -140,6 +153,31 @@
 */
 extern s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin);
 
+/* configure `all` aspects of an gpio */
+
+/**
+ * s3c_gpio_cfgall_range() - configure range of gpio functtion and pull.
+ * @start: The gpio number to start at.
+ * @nr: The number of gpio to configure from @start.
+ * @cfg: The configuration to use
+ * @pull: The pull setting to use.
+ *
+ * Run s3c_gpio_cfgpin() and s3c_gpio_setpull() over the gpio range starting
+ * @gpio and running for @size.
+ *
+ * @sa s3c_gpio_cfgpin
+ * @sa s3c_gpio_setpull
+ * @sa s3c_gpio_cfgpin_range
+ */
+extern int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr,
+				 unsigned int cfg, s3c_gpio_pull_t pull);
+
+static inline int s3c_gpio_cfgrange_nopull(unsigned int pin, unsigned int size,
+					   unsigned int cfg)
+{
+	return s3c_gpio_cfgall_range(pin, size, cfg, S3C_GPIO_PULL_NONE);
+}
+
 /* Define values for the drvstr available for each gpio pin.
  *
  * These values control the value of the output signal driver strength,
@@ -169,4 +207,22 @@
 */
 extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr);
 
+/**
+ * s5p_register_gpio_interrupt() - register interrupt support for a gpio group
+ * @pin: The pin number from the group to be registered
+ *
+ * This function registers gpio interrupt support for the group that the
+ * specified pin belongs to.
+ *
+ * The total number of gpio pins is quite large ob s5p series. Registering
+ * irq support for all of them would be a resource waste. Because of that the
+ * interrupt support for standard gpio pins is registered dynamically.
+ *
+ * It will return the irq number of the interrupt that has been registered
+ * or -ENOMEM if no more gpio interrupts can be registered. It is allowed
+ * to call this function more than once for the same gpio group (the group
+ * will be registered only once).
+ */
+extern int s5p_register_gpio_interrupt(int pin);
+
 #endif /* __PLAT_GPIO_CFG_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-cfg-helpers.h	2011-01-04 19:50:19.000000000 -0500
@@ -42,6 +42,12 @@
 	return (chip->config->set_pull)(chip, off, pull);
 }
 
+static inline s3c_gpio_pull_t s3c_gpio_do_getpull(struct s3c_gpio_chip *chip,
+						  unsigned int off)
+{
+	return chip->config->get_pull(chip, off);
+}
+
 /**
  * s3c_gpio_setcfg_s3c24xx - S3C24XX style GPIO configuration.
  * @chip: The gpio chip that is being configured.
@@ -204,6 +210,17 @@
 					    unsigned int off);
 
 /**
+ * s3c_gpio_getpull_1down() - Get configuration for choice of down or none
+ * @chip: The gpio chip that the GPIO pin belongs to
+ * @off: The offset to the pin to get the configuration of.
+ *
+ * This helper function reads the state of the pull-down resistor for the
+ * given GPIO in the same case as s3c_gpio_setpull_1down.
+*/
+extern s3c_gpio_pull_t s3c_gpio_getpull_1down(struct s3c_gpio_chip *chip,
+					    unsigned int off);
+
+/**
  * s3c_gpio_setpull_s3c2443() - Pull configuration for s3c2443.
  * @chip: The gpio chip that is being configured.
  * @off: The offset for the GPIO being configured.
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-core.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-core.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/gpio-core.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/gpio-core.h	2011-01-04 19:50:19.000000000 -0500
@@ -43,6 +43,8 @@
  * struct s3c_gpio_chip - wrapper for specific implementation of gpio
  * @chip: The chip structure to be exported via gpiolib.
  * @base: The base pointer to the gpio configuration registers.
+ * @group: The group register number for gpio interrupt support.
+ * @irq_base: The base irq number.
  * @config: special function and pull-resistor control information.
  * @lock: Lock for exclusive access to this gpio bank.
  * @pm_save: Save information for suspend/resume support.
@@ -63,6 +65,8 @@
 	struct s3c_gpio_cfg	*config;
 	struct s3c_gpio_pm	*pm;
 	void __iomem		*base;
+	int			irq_base;
+	int			group;
 	spinlock_t		 lock;
 #ifdef CONFIG_PM
 	u32			pm_save[4];
@@ -118,6 +122,17 @@
 extern void samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip);
 extern void samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip);
 
+
+/**
+ * samsung_gpiolib_to_irq - convert gpio pin to irq number
+ * @chip: The gpio chip that the pin belongs to.
+ * @offset: The offset of the pin in the chip.
+ *
+ * This helper returns the irq number calculated from the chip->irq_base and
+ * the provided offset.
+ */
+extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset);
+
 /* exported for core SoC support to change */
 extern struct s3c_gpio_cfg s3c24xx_gpiocfg_default;
 
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/iic.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/iic.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/iic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/iic.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,10 +55,20 @@
 extern void s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *i2c);
 extern void s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *i2c);
 extern void s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *i2c);
+extern void s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *i2c);
 
 /* defined by architecture to configure gpio */
 extern void s3c_i2c0_cfg_gpio(struct platform_device *dev);
 extern void s3c_i2c1_cfg_gpio(struct platform_device *dev);
 extern void s3c_i2c2_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c3_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c4_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c5_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c6_cfg_gpio(struct platform_device *dev);
+extern void s3c_i2c7_cfg_gpio(struct platform_device *dev);
 
 #endif /* __ASM_ARCH_IIC_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/map-base.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/map-base.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/map-base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/map-base.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,7 @@
 #ifndef __ASM_PLAT_MAP_H
 #define __ASM_PLAT_MAP_H __FILE__
 
-/* Fit all our registers in at 0xF4000000 upwards, trying to use as
+/* Fit all our registers in at 0xF6000000 upwards, trying to use as
  * little of the VA space as possible so vmalloc and friends have a
  * better chance of getting memory.
  *
@@ -22,7 +22,7 @@
  * an single MOVS instruction (ie, only 8 bits of set data)
  */
 
-#define S3C_ADDR_BASE	(0xF4000000)
+#define S3C_ADDR_BASE	0xF6000000
 
 #ifndef __ASSEMBLY__
 #define S3C_ADDR(x)	((void __iomem __force *)S3C_ADDR_BASE + (x))
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/nand-core.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/nand-core.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/nand-core.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/nand-core.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,28 @@
+/* arch/arm/plat-samsung/include/plat/nand-core.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * S3C -  Nand Controller core functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_NAND_CORE_H
+#define __ASM_ARCH_NAND_CORE_H __FILE__
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c_nand_setname(char *name)
+{
+#ifdef CONFIG_S3C_DEV_NAND
+	s3c_device_nand.name = name;
+#endif
+}
+
+#endif /* __ASM_ARCH_NAND_CORE_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,8 @@
  * struct s3c64xx_spi_info - SPI Controller defining structure
  * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
  * @src_clk_name: Platform name of the corresponding clock.
+ * @clk_from_cmu: If the SPI clock/prescalar control block is present
+ *     by the platform's clock-management-unit and not in SPI controller.
  * @num_cs: Number of CS this controller emulates.
  * @cfg_gpio: Configure pins for this SPI controller.
  * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
@@ -41,6 +43,7 @@
 struct s3c64xx_spi_info {
 	int src_clk_nr;
 	char *src_clk_name;
+	bool clk_from_cmu;
 
 	int num_cs;
 
@@ -65,7 +68,7 @@
 extern void s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pv210_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
-extern void s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 
 #endif /* __S3C64XX_PLAT_SPI_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,12 @@
 	DMACH_UART2_TX,
 	DMACH_UART3_RX,
 	DMACH_UART3_TX,
+	DMACH_UART4_RX,
+	DMACH_UART4_TX,
+	DMACH_UART5_RX,
+	DMACH_UART5_TX,
+	DMACH_USI_RX,
+	DMACH_USI_TX,
 	DMACH_IRDA,
 	DMACH_I2S0_RX,
 	DMACH_I2S0_TX,
@@ -64,6 +70,20 @@
 	DMACH_MSM_REQ2,
 	DMACH_MSM_REQ1,
 	DMACH_MSM_REQ0,
+	DMACH_SLIMBUS0_RX,
+	DMACH_SLIMBUS0_TX,
+	DMACH_SLIMBUS0AUX_RX,
+	DMACH_SLIMBUS0AUX_TX,
+	DMACH_SLIMBUS1_RX,
+	DMACH_SLIMBUS1_TX,
+	DMACH_SLIMBUS2_RX,
+	DMACH_SLIMBUS2_TX,
+	DMACH_SLIMBUS3_RX,
+	DMACH_SLIMBUS3_TX,
+	DMACH_SLIMBUS4_RX,
+	DMACH_SLIMBUS4_TX,
+	DMACH_SLIMBUS5_RX,
+	DMACH_SLIMBUS5_TX,
 	/* END Marker, also used to denote a reserved channel */
 	DMACH_MAX,
 };
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/sdhci.h linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/sdhci.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/include/plat/sdhci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/include/plat/sdhci.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,11 +28,17 @@
 	S3C_SDHCI_CD_PERMANENT,	/* no CD line, card permanently wired to host */
 };
 
+enum clk_types {
+	S3C_SDHCI_CLK_DIV_INTERNAL,	/* use mmc internal clock divider */
+	S3C_SDHCI_CLK_DIV_EXTERNAL,	/* use external clock divider */
+};
+
 /**
  * struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
  * @max_width: The maximum number of data bits supported.
  * @host_caps: Standard MMC host capabilities bit field.
  * @cd_type: Type of Card Detection method (see cd_types enum above)
+ * @clk_type: Type of clock divider method (see clk_types enum above)
  * @ext_cd_init: Initialize external card detect subsystem. Called on
  *		 sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL.
  *		 notify_func argument is a callback to the sdhci-s3c driver
@@ -59,6 +65,7 @@
 	unsigned int	max_width;
 	unsigned int	host_caps;
 	enum cd_types	cd_type;
+	enum clk_types	clk_type;
 
 	char		**clocks;	/* set of clock sources */
 
@@ -110,6 +117,10 @@
 extern void s5pv210_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
 extern void s5pv210_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
 extern void s5pv210_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
+extern void s5pv310_setup_sdhci0_cfg_gpio(struct platform_device *, int w);
+extern void s5pv310_setup_sdhci1_cfg_gpio(struct platform_device *, int w);
+extern void s5pv310_setup_sdhci2_cfg_gpio(struct platform_device *, int w);
+extern void s5pv310_setup_sdhci3_cfg_gpio(struct platform_device *, int w);
 
 /* S3C64XX SDHCI setup */
 
@@ -288,4 +299,57 @@
 
 #endif /* CONFIG_S5PV210_SETUP_SDHCI */
 
+/* S5PV310 SDHCI setup */
+#ifdef CONFIG_S5PV310_SETUP_SDHCI
+extern char *s5pv310_hsmmc_clksrcs[4];
+
+extern void s5pv310_setup_sdhci_cfg_card(struct platform_device *dev,
+					   void __iomem *r,
+					   struct mmc_ios *ios,
+					   struct mmc_card *card);
+
+static inline void s5pv310_default_sdhci0(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC
+	s3c_hsmmc0_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
+	s3c_hsmmc0_def_platdata.cfg_gpio = s5pv310_setup_sdhci0_cfg_gpio;
+	s3c_hsmmc0_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+#endif
+}
+
+static inline void s5pv310_default_sdhci1(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC1
+	s3c_hsmmc1_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
+	s3c_hsmmc1_def_platdata.cfg_gpio = s5pv310_setup_sdhci1_cfg_gpio;
+	s3c_hsmmc1_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+#endif
+}
+
+static inline void s5pv310_default_sdhci2(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC2
+	s3c_hsmmc2_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
+	s3c_hsmmc2_def_platdata.cfg_gpio = s5pv310_setup_sdhci2_cfg_gpio;
+	s3c_hsmmc2_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+#endif
+}
+
+static inline void s5pv310_default_sdhci3(void)
+{
+#ifdef CONFIG_S3C_DEV_HSMMC3
+	s3c_hsmmc3_def_platdata.clocks = s5pv310_hsmmc_clksrcs;
+	s3c_hsmmc3_def_platdata.cfg_gpio = s5pv310_setup_sdhci3_cfg_gpio;
+	s3c_hsmmc3_def_platdata.cfg_card = s5pv310_setup_sdhci_cfg_card;
+#endif
+}
+
+#else
+static inline void s5pv310_default_sdhci0(void) { }
+static inline void s5pv310_default_sdhci1(void) { }
+static inline void s5pv310_default_sdhci2(void) { }
+static inline void s5pv310_default_sdhci3(void) { }
+
+#endif /* CONFIG_S5PV310_SETUP_SDHCI */
+
 #endif /* __PLAT_S3C_SDHCI_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-samsung/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -180,6 +180,31 @@
 	help
 	  Compile in platform device definitions for I2C channel 2
 
+config S3C_DEV_I2C3
+	bool
+	help
+	  Compile in platform device definition for I2C controller 3
+
+config S3C_DEV_I2C4
+	bool
+	help
+	  Compile in platform device definition for I2C controller 4
+
+config S3C_DEV_I2C5
+	bool
+	help
+	  Compile in platform device definition for I2C controller 5
+
+config S3C_DEV_I2C6
+	bool
+	help
+	  Compile in platform device definition for I2C controller 6
+
+config S3C_DEV_I2C7
+	bool
+	help
+	  Compile in platform device definition for I2C controller 7
+
 config S3C_DEV_FB
 	bool
 	help
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-samsung/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,11 @@
 obj-y				+= dev-i2c0.o
 obj-$(CONFIG_S3C_DEV_I2C1)	+= dev-i2c1.o
 obj-$(CONFIG_S3C_DEV_I2C2)	+= dev-i2c2.o
+obj-$(CONFIG_S3C_DEV_I2C3)	+= dev-i2c3.o
+obj-$(CONFIG_S3C_DEV_I2C4)	+= dev-i2c4.o
+obj-$(CONFIG_S3C_DEV_I2C5)	+= dev-i2c5.o
+obj-$(CONFIG_S3C_DEV_I2C6)	+= dev-i2c6.o
+obj-$(CONFIG_S3C_DEV_I2C7)	+= dev-i2c7.o
 obj-$(CONFIG_S3C_DEV_FB)	+= dev-fb.o
 obj-y				+= dev-uart.o
 obj-$(CONFIG_S3C_DEV_USB_HOST)	+= dev-usb.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/pm-gpio.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/pm-gpio.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/pm-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/pm-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -192,7 +192,7 @@
 	.resume = s3c_gpio_pm_2bit_resume,
 };
 
-#ifdef CONFIG_ARCH_S3C64XX
+#if defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_PLAT_S5P)
 static void s3c_gpio_pm_4bit_save(struct s3c_gpio_chip *chip)
 {
 	chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON);
@@ -302,7 +302,7 @@
 	.save	= s3c_gpio_pm_4bit_save,
 	.resume = s3c_gpio_pm_4bit_resume,
 };
-#endif /* CONFIG_ARCH_S3C64XX */
+#endif /* CONFIG_ARCH_S3C64XX || CONFIG_PLAT_S5P */
 
 /**
  * s3c_pm_save_gpio() - save gpio chip data for suspend
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-samsung/s3c-pl330.c linux-libre-2.6.37-gnu/arch/arm/plat-samsung/s3c-pl330.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-samsung/s3c-pl330.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-samsung/s3c-pl330.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,8 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 
 #include <asm/hardware/pl330.h>
 
@@ -27,6 +29,7 @@
  * @node: To attach to the global list of DMACs.
  * @pi: PL330 configuration info for the DMAC.
  * @kmcache: Pool to quickly allocate xfers for all channels in the dmac.
+ * @clk: Pointer of DMAC operation clock.
  */
 struct s3c_pl330_dmac {
 	unsigned		busy_chan;
@@ -34,6 +37,7 @@
 	struct list_head	node;
 	struct pl330_info	*pi;
 	struct kmem_cache	*kmcache;
+	struct clk		*clk;
 };
 
 /**
@@ -1072,16 +1076,25 @@
 	if (ret)
 		goto probe_err4;
 
-	ret = pl330_add(pl330_info);
-	if (ret)
-		goto probe_err5;
-
 	/* Allocate a new DMAC */
 	s3c_pl330_dmac = kmalloc(sizeof(*s3c_pl330_dmac), GFP_KERNEL);
 	if (!s3c_pl330_dmac) {
 		ret = -ENOMEM;
+		goto probe_err5;
+	}
+
+	/* Get operation clock and enable it */
+	s3c_pl330_dmac->clk = clk_get(&pdev->dev, "pdma");
+	if (IS_ERR(s3c_pl330_dmac->clk)) {
+		dev_err(&pdev->dev, "Cannot get operation clock.\n");
+		ret = -EINVAL;
 		goto probe_err6;
 	}
+	clk_enable(s3c_pl330_dmac->clk);
+
+	ret = pl330_add(pl330_info);
+	if (ret)
+		goto probe_err7;
 
 	/* Hook the info */
 	s3c_pl330_dmac->pi = pl330_info;
@@ -1094,7 +1107,7 @@
 
 	if (!s3c_pl330_dmac->kmcache) {
 		ret = -ENOMEM;
-		goto probe_err7;
+		goto probe_err8;
 	}
 
 	/* Get the list of peripherals */
@@ -1120,10 +1133,13 @@
 
 	return 0;
 
+probe_err8:
+	pl330_del(pl330_info);
 probe_err7:
-	kfree(s3c_pl330_dmac);
+	clk_disable(s3c_pl330_dmac->clk);
+	clk_put(s3c_pl330_dmac->clk);
 probe_err6:
-	pl330_del(pl330_info);
+	kfree(s3c_pl330_dmac);
 probe_err5:
 	free_irq(irq, pl330_info);
 probe_err4:
@@ -1188,6 +1204,10 @@
 		}
 	}
 
+	/* Disable operation clock */
+	clk_disable(dmac->clk);
+	clk_put(dmac->clk);
+
 	/* Remove the DMAC */
 	list_del(&dmac->node);
 	kfree(dmac);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-spear/include/plat/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/plat-spear/include/plat/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/plat-spear/include/plat/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-spear/include/plat/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,9 @@
 #include <linux/amba/serial.h>
 #include <mach/spear.h>
 
-		.macro	addruart, rx
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1					@ MMU enabled?
-		moveq	\rx, #SPEAR_DBG_UART_BASE		@ Physical base
-		movne	\rx, #VA_SPEAR_DBG_UART_BASE		@ Virtual base
+		.macro	addruart, rp, rv
+		mov	\rp, #SPEAR_DBG_UART_BASE		@ Physical base
+		mov	\rv, #VA_SPEAR_DBG_UART_BASE		@ Virtual base
 		.endm
 
 		.macro	senduart, rd, rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -16,13 +16,10 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-		.macro	addruart, rx, tmp
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #0x80000000	@ physical base address
-		addeq	\rx, \rx, #0x00070000
-		movne	\rx, #0xf0000000	@ virtual base
-		addne	\rx, \rx, #0x00070000
+		.macro	addruart, rp, rv
+		mov	\rp,      #0x00070000
+		add	\rv, \rp, #0xf0000000	@ virtual base
+		add	\rp, \rp, #0x80000000	@ physical base
 		.endm
 
 		.macro	senduart,rd,rx
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/clock.c linux-libre-2.6.37-gnu/arch/arm/plat-tcc/clock.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/clock.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,179 @@
+/*
+ * Clock framework for Telechips SoCs
+ * Based on arch/arm/plat-mxc/clock.c
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2010 Hans J. Koch, hjk@linutronix.de
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#include <mach/clock.h>
+#include <mach/hardware.h>
+
+static DEFINE_MUTEX(clocks_mutex);
+
+/*-------------------------------------------------------------------------
+ * Standard clock functions defined in include/linux/clk.h
+ *-------------------------------------------------------------------------*/
+
+static void __clk_disable(struct clk *clk)
+{
+	BUG_ON(clk->refcount == 0);
+
+	if (!(--clk->refcount) && clk->disable) {
+		/* Unconditionally disable the clock in hardware */
+		clk->disable(clk);
+		/* recursively disable parents */
+		if (clk->parent)
+			__clk_disable(clk->parent);
+	}
+}
+
+static int __clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (clk->refcount++ == 0 && clk->enable) {
+		if (clk->parent)
+			ret = __clk_enable(clk->parent);
+		if (ret)
+			return ret;
+		else
+			return clk->enable(clk);
+	}
+
+	return 0;
+}
+
+/* This function increments the reference count on the clock and enables the
+ * clock if not already enabled. The parent clock tree is recursively enabled
+ */
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!clk)
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	ret = __clk_enable(clk);
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/* This function decrements the reference count on the clock and disables
+ * the clock when reference count is 0. The parent clock tree is
+ * recursively disabled
+ */
+void clk_disable(struct clk *clk)
+{
+	if (!clk)
+		return;
+
+	mutex_lock(&clocks_mutex);
+	__clk_disable(clk);
+	mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+/* Retrieve the *current* clock rate. If the clock itself
+ * does not provide a special calculation routine, ask
+ * its parent and so on, until one is able to return
+ * a valid clock rate
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (!clk)
+		return 0UL;
+
+	if (clk->get_rate)
+		return clk->get_rate(clk);
+
+	return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/* Round the requested clock rate to the nearest supported
+ * rate that is less than or equal to the requested rate.
+ * This is dependent on the clock's current parent.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (!clk)
+		return 0;
+	if (!clk->round_rate)
+		return 0;
+
+	return clk->round_rate(clk, rate);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/* Set the clock to the requested clock rate. The rate must
+ * match a supported rate exactly based on what clk_round_rate returns
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EINVAL;
+
+	if (!clk)
+		return ret;
+	if (!clk->set_rate || !rate)
+		return ret;
+
+	mutex_lock(&clocks_mutex);
+	ret = clk->set_rate(clk, rate);
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/* Set the clock's parent to another clock source */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk *old;
+	int ret = -EINVAL;
+
+	if (!clk)
+		return ret;
+	if (!clk->set_parent || !parent)
+		return ret;
+
+	mutex_lock(&clocks_mutex);
+	old = clk->parent;
+	if (clk->refcount)
+		__clk_enable(parent);
+	ret = clk->set_parent(clk, parent);
+	if (ret)
+		old = parent;
+	if (clk->refcount)
+		__clk_disable(old);
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/* Retrieve the clock's parent clock source */
+struct clk *clk_get_parent(struct clk *clk)
+{
+	if (!clk)
+		return NULL;
+
+	return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/clkdev.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/clkdev.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/clkdev.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/clkdev.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/clock.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/clock.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+/*
+ * Low level clock header file for Telechips TCC architecture
+ * (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the GPL v2.
+ */
+
+#ifndef __ASM_ARCH_TCC_CLOCK_H__
+#define __ASM_ARCH_TCC_CLOCK_H__
+
+#ifndef __ASSEMBLY__
+
+struct clk {
+	struct clk *parent;
+	/* id number of a root clock, 0 for normal clocks */
+	int root_id;
+	/* Reference count of clock enable/disable */
+	int refcount;
+	/* Address of associated BCLKCTRx register. Must be set. */
+	void __iomem *bclkctr;
+	/* Bit position for BCLKCTRx. Must be set. */
+	int bclk_shift;
+	/* Address of ACLKxxx register, if any. */
+	void __iomem *aclkreg;
+	/* get the current clock rate (always a fresh value) */
+	unsigned long (*get_rate) (struct clk *);
+	/* Function ptr to set the clock to a new rate. The rate must match a
+	   supported rate returned from round_rate. Leave blank if clock is not
+	   programmable */
+	int (*set_rate) (struct clk *, unsigned long);
+	/* Function ptr to round the requested clock rate to the nearest
+	   supported rate that is less than or equal to the requested rate. */
+	unsigned long (*round_rate) (struct clk *, unsigned long);
+	/* Function ptr to enable the clock. Leave blank if clock can not
+	   be gated. */
+	int (*enable) (struct clk *);
+	/* Function ptr to disable the clock. Leave blank if clock can not
+	   be gated. */
+	void (*disable) (struct clk *);
+	/* Function ptr to set the parent clock of the clock. */
+	int (*set_parent) (struct clk *, struct clk *);
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_ARCH_MXC_CLOCK_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/debug-macro.S linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/debug-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/debug-macro.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/debug-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1994-1999 Russell King
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+		.macro	addruart, rp, rv
+		moveq	\rp, #0x90000000	@ physical base address
+		movne	\rv, #0xF1000000	@ virtual base
+		orr	\rp, \rp, #0x00007000	@ UART0
+		orr	\rv, \rv, #0x00007000	@ UART0
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx, #0x44]
+		.endm
+
+		.macro	waituart,rd,rx
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:
+		ldr \rd, [\rx, #0x14]
+		tst \rd, #0x20
+
+		beq 1001b
+		.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/entry-macro.S linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/entry-macro.S
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/entry-macro.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/entry-macro.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+/*
+ * include/asm-arm/arch-tcc83x/entry-macro.S
+ *
+ * Author : <linux@telechips.com>
+ * Created: June 10, 2008
+ * Description: Low-level IRQ helper macros for Telechips-based platforms
+ *
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+		ldr	\base, =0xF2003000 @ base address of PIC registers
+
+		@@ read MREQ register of PIC0
+
+		mov	\irqnr, #0
+		ldr	\irqstat, [\base, #0x00000014 ]	@ lower 32 interrupts
+		cmp	\irqstat, #0
+		bne	1001f
+
+		@@ read MREQ register of PIC1
+
+		ldr	\irqstat, [\base, #0x00000094]	@ upper 32 interrupts
+		cmp	\irqstat, #0
+		beq	1002f
+		mov	\irqnr, #0x20
+
+1001:
+		movs	\tmp, \irqstat, lsl #16
+		movne	\irqstat, \tmp
+		addeq	\irqnr, \irqnr, #16
+
+		movs	\tmp, \irqstat, lsl #8
+		movne	\irqstat, \tmp
+		addeq	\irqnr, \irqnr, #8
+
+		movs	\tmp, \irqstat, lsl #4
+		movne	\irqstat, \tmp
+		addeq	\irqnr, \irqnr, #4
+
+		movs	\tmp, \irqstat, lsl #2
+		movne	\irqstat, \tmp
+		addeq	\irqnr, \irqnr, #2
+
+		movs	\tmp, \irqstat, lsl #1
+		addeq	\irqnr, \irqnr, #1
+		orrs	\base, \base, #1
+1002:
+		@@ exit here, Z flag unset if IRQ
+
+	.endm
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/hardware.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/hardware.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/hardware.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,43 @@
+/*
+ * Author: RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
+ * Reorganized for Linux-2.6 by Tony Lindgren <tony@atomide.com>
+ *                          and Dirk Behme <dirk.behme@de.bosch.com>
+ * Rewritten by:    <linux@telechips.com>
+ * Description: Hardware definitions for TCC8300 processors and boards
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Modifications for mainline (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU Pulic License version 2.
+ */
+
+#ifndef __ASM_ARCH_TCC_HARDWARE_H
+#define __ASM_ARCH_TCC_HARDWARE_H
+
+#include <asm/sizes.h>
+#ifndef __ASSEMBLER__
+#include <asm/types.h>
+#endif
+#include <mach/io.h>
+
+/*
+ * ----------------------------------------------------------------------------
+ * Clocks
+ * ----------------------------------------------------------------------------
+ */
+#define CLKGEN_REG_BASE		0xfffece00
+#define ARM_CKCTL		(CLKGEN_REG_BASE + 0x0)
+#define ARM_IDLECT1		(CLKGEN_REG_BASE + 0x4)
+#define ARM_IDLECT2		(CLKGEN_REG_BASE + 0x8)
+#define ARM_EWUPCT		(CLKGEN_REG_BASE + 0xC)
+#define ARM_RSTCT1		(CLKGEN_REG_BASE + 0x10)
+#define ARM_RSTCT2		(CLKGEN_REG_BASE + 0x14)
+#define ARM_SYSST		(CLKGEN_REG_BASE + 0x18)
+#define ARM_IDLECT3		(CLKGEN_REG_BASE + 0x24)
+
+/* DPLL control registers */
+#define DPLL_CTL		0xfffecf00
+
+#endif	/* __ASM_ARCH_TCC_HARDWARE_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/io.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/io.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/io.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+/*
+ * IO definitions for TCC8000 processors and boards
+ *
+ * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU Public License version 2.
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)			__typesafe_io(a)
+#define __mem_pci(a)		(a)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/irqs.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/irqs.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/irqs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/irqs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,83 @@
+/*
+ * IRQ definitions for TCC8xxx
+ *
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#ifndef __ASM_ARCH_TCC_IRQS_H
+#define __ASM_ARCH_TCC_IRQS_H
+
+#define NR_IRQS 64
+
+/* PIC0 interrupts */
+#define INT_ADMA1	0
+#define INT_BDMA	1
+#define INT_ADMA0	2
+#define INT_GDMA1	3
+#define INT_I2S0RX	4
+#define INT_I2S0TX	5
+#define INT_TC		6
+#define INT_UART0	7
+#define INT_USBD	8
+#define INT_SPI0TX	9
+#define INT_UDMA	10
+#define INT_LIRQ	11
+#define INT_GDMA2	12
+#define INT_GDMA0	13
+#define INT_TC32	14
+#define INT_LCD		15
+#define INT_ADC		16
+#define INT_I2C		17
+#define INT_RTCP	18
+#define INT_RTCA	19
+#define INT_NFC		20
+#define INT_SD0		21
+#define INT_GSB0	22
+#define INT_PK		23
+#define INT_USBH0	24
+#define INT_USBH1	25
+#define INT_G2D		26
+#define INT_ECC		27
+#define INT_SPI0RX	28
+#define INT_UART1	29
+#define INT_MSCL	30
+#define INT_GSB1	31
+/* PIC1 interrupts */
+#define INT_E0		32
+#define INT_E1		33
+#define INT_E2		34
+#define INT_E3		35
+#define INT_E4		36
+#define INT_E5		37
+#define INT_E6		38
+#define INT_E7		39
+#define INT_UART2	40
+#define INT_UART3	41
+#define INT_SPI1TX	42
+#define INT_SPI1RX	43
+#define INT_GSB2	44
+#define INT_SPDIF	45
+#define INT_CDIF	46
+#define INT_VBON	47
+#define INT_VBOFF	48
+#define INT_SD1		49
+#define INT_UART4	50
+#define INT_GDMA3	51
+#define INT_I2S1RX	52
+#define INT_I2S1TX	53
+#define INT_CAN0	54
+#define INT_CAN1	55
+#define INT_GSB3	56
+#define INT_KRST	57
+#define INT_UNUSED	58
+#define INT_SD0D3	59
+#define INT_SD1D3	60
+#define INT_GPS0	61
+#define INT_GPS1	62
+#define INT_GPS2	63
+
+#endif  /* ASM_ARCH_TCC_IRQS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/memory.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/memory.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/memory.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/memory.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET		UL(0x20000000)
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/system.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/system.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/system.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,31 @@
+/*
+ * Author: <linux@telechips.com>
+ * Created: June 10, 2008
+ * Description: LINUX SYSTEM FUNCTIONS for TCC83x
+ *
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+#include <linux/clk.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+extern void plat_tcc_reboot(void);
+
+static inline void arch_idle(void)
+{
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	plat_tcc_reboot();
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/tcc8k-regs.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/tcc8k-regs.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/tcc8k-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/tcc8k-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,807 @@
+/*
+ * Telechips TCC8000 register definitions
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPLv2.
+ */
+
+#ifndef TCC8K_REGS_H
+#define TCC8K_REGS_H
+
+#include <linux/types.h>
+
+#define EXT_SDRAM_BASE		0x20000000
+#define INT_SRAM_BASE		0x30000000
+#define INT_SRAM_SIZE		SZ_32K
+#define CS0_BASE		0x40000000
+#define CS1_BASE		0x50000000
+#define CS1_SIZE		SZ_64K
+#define CS2_BASE		0x60000000
+#define CS3_BASE		0x70000000
+#define AHB_PERI_BASE		0x80000000
+#define AHB_PERI_SIZE		SZ_64K
+#define APB0_PERI_BASE		0x90000000
+#define APB0_PERI_SIZE		SZ_128K
+#define APB1_PERI_BASE		0x98000000
+#define APB1_PERI_SIZE		SZ_128K
+#define DATA_TCM_BASE		0xa0000000
+#define DATA_TCM_SIZE		SZ_8K
+#define EXT_MEM_CTRL_BASE	0xf0000000
+#define EXT_MEM_CTRL_SIZE	SZ_4K
+
+#define CS1_BASE_VIRT		(void __iomem *)0xf7000000
+#define AHB_PERI_BASE_VIRT	(void __iomem *)0xf4000000
+#define APB0_PERI_BASE_VIRT	(void __iomem *)0xf1000000
+#define APB1_PERI_BASE_VIRT	(void __iomem *)0xf2000000
+#define EXT_MEM_CTRL_BASE_VIRT	(void __iomem *)0xf3000000
+#define INT_SRAM_BASE_VIRT	(void __iomem *)0xf5000000
+#define DATA_TCM_BASE_VIRT	(void __iomem *)0xf6000000
+
+#define __REG(x)     (*((volatile u32 *)(x)))
+
+/* USB Device Controller Registers */
+#define UDC_BASE	(AHB_PERI_BASE_VIRT + 0x8000)
+#define UDC_BASE_PHYS	(AHB_PERI_BASE + 0x8000)
+
+#define UDC_IR_OFFS		0x00
+#define UDC_EIR_OFFS		0x04
+#define UDC_EIER_OFFS		0x08
+#define UDC_FAR_OFFS		0x0c
+#define UDC_FNR_OFFS		0x10
+#define UDC_EDR_OFFS		0x14
+#define UDC_RT_OFFS		0x18
+#define UDC_SSR_OFFS		0x1c
+#define UDC_SCR_OFFS		0x20
+#define UDC_EP0SR_OFFS		0x24
+#define UDC_EP0CR_OFFS		0x28
+
+#define UDC_ESR_OFFS		0x2c
+#define UDC_ECR_OFFS		0x30
+#define UDC_BRCR_OFFS		0x34
+#define UDC_BWCR_OFFS		0x38
+#define UDC_MPR_OFFS		0x3c
+#define UDC_DCR_OFFS		0x40
+#define UDC_DTCR_OFFS		0x44
+#define UDC_DFCR_OFFS		0x48
+#define UDC_DTTCR1_OFFS		0x4c
+#define UDC_DTTCR2_OFFS		0x50
+#define UDC_ESR2_OFFS		0x54
+
+#define UDC_SCR2_OFFS		0x58
+#define UDC_EP0BUF_OFFS		0x60
+#define UDC_EP1BUF_OFFS		0x64
+#define UDC_EP2BUF_OFFS		0x68
+#define UDC_EP3BUF_OFFS		0x6c
+#define UDC_PLICR_OFFS		0xa0
+#define UDC_PCR_OFFS		0xa4
+
+#define UDC_UPCR0_OFFS		0xc8
+#define UDC_UPCR1_OFFS		0xcc
+#define UDC_UPCR2_OFFS		0xd0
+#define UDC_UPCR3_OFFS		0xd4
+
+/* Bits in UDC_EIR */
+#define UDC_EIR_EP0I		(1 << 0)
+#define UDC_EIR_EP1I		(1 << 1)
+#define UDC_EIR_EP2I		(1 << 2)
+#define UDC_EIR_EP3I		(1 << 3)
+#define UDC_EIR_EPI_MASK	0x0f
+
+/* Bits in UDC_EIER */
+#define UDC_EIER_EP0IE		(1 << 0)
+#define UDC_EIER_EP1IE		(1 << 1)
+#define UDC_EIER_EP2IE		(1 << 2)
+#define UDC_EIER_EP3IE		(1 << 3)
+
+/* Bits in UDC_FNR */
+#define UDC_FNR_FN_MASK		0x7ff
+#define UDC_FNR_SM		(1 << 13)
+#define UDC_FNR_FTL		(1 << 14)
+
+/* Bits in UDC_SSR */
+#define UDC_SSR_HFRES		(1 << 0)
+#define UDC_SSR_HFSUSP		(1 << 1)
+#define UDC_SSR_HFRM		(1 << 2)
+#define UDC_SSR_SDE		(1 << 3)
+#define UDC_SSR_HSP		(1 << 4)
+#define UDC_SSR_DM		(1 << 5)
+#define UDC_SSR_DP		(1 << 6)
+#define UDC_SSR_TBM		(1 << 7)
+#define UDC_SSR_VBON		(1 << 8)
+#define UDC_SSR_VBOFF		(1 << 9)
+#define UDC_SSR_EOERR		(1 << 10)
+#define UDC_SSR_DCERR		(1 << 11)
+#define UDC_SSR_TCERR		(1 << 12)
+#define UDC_SSR_BSERR		(1 << 13)
+#define UDC_SSR_TMERR		(1 << 14)
+#define UDC_SSR_BAERR		(1 << 15)
+
+/* Bits in UDC_SCR */
+#define UDC_SCR_HRESE		(1 << 0)
+#define UDC_SCR_HSSPE		(1 << 1)
+#define UDC_SCR_RRDE		(1 << 5)
+#define UDC_SCR_SPDEN		(1 << 6)
+#define UDC_SCR_DIEN		(1 << 12)
+
+/* Bits in UDC_EP0SR */
+#define UDC_EP0SR_RSR		(1 << 0)
+#define UDC_EP0SR_TST		(1 << 1)
+#define UDC_EP0SR_SHT		(1 << 4)
+#define UDC_EP0SR_LWO		(1 << 6)
+
+/* Bits in UDC_EP0CR */
+#define UDC_EP0CR_ESS		(1 << 1)
+
+/* Bits in UDC_ESR */
+#define UDC_ESR_RPS		(1 << 0)
+#define UDC_ESR_TPS		(1 << 1)
+#define UDC_ESR_LWO		(1 << 4)
+#define UDC_ESR_FFS		(1 << 6)
+
+/* Bits in UDC_ECR */
+#define UDC_ECR_ESS		(1 << 1)
+#define UDC_ECR_CDP		(1 << 2)
+
+#define UDC_ECR_FLUSH		(1 << 6)
+#define UDC_ECR_DUEN		(1 << 7)
+
+/* Bits in UDC_UPCR0 */
+#define UDC_UPCR0_VBD		(1 << 1)
+#define UDC_UPCR0_VBDS		(1 << 6)
+#define UDC_UPCR0_RCD_12	(0x0 << 9)
+#define UDC_UPCR0_RCD_24	(0x1 << 9)
+#define UDC_UPCR0_RCD_48	(0x2 << 9)
+#define UDC_UPCR0_RCS_EXT	(0x1 << 11)
+#define UDC_UPCR0_RCS_XTAL	(0x0 << 11)
+
+/* Bits in UDC_UPCR1 */
+#define UDC_UPCR1_CDT(x)	((x) << 0)
+#define UDC_UPCR1_OTGT(x)	((x) << 3)
+#define UDC_UPCR1_SQRXT(x)	((x) << 8)
+#define UDC_UPCR1_TXFSLST(x)	((x) << 12)
+
+/* Bits in UDC_UPCR2 */
+#define UDC_UPCR2_TP		(1 << 0)
+#define UDC_UPCR2_TXRT(x)	((x) << 2)
+#define UDC_UPCR2_TXVRT(x)	((x) << 5)
+#define UDC_UPCR2_OPMODE(x)	((x) << 9)
+#define UDC_UPCR2_XCVRSEL(x)	((x) << 12)
+#define UDC_UPCR2_TM		(1 << 14)
+
+/* USB Host Controller registers */
+#define USBH0_BASE	(AHB_PERI_BASE_VIRT + 0xb000)
+#define USBH1_BASE	(AHB_PERI_BASE_VIRT + 0xb800)
+
+#define OHCI_INT_ENABLE_OFFS	0x10
+
+#define RH_DESCRIPTOR_A_OFFS	0x48
+#define RH_DESCRIPTOR_B_OFFS	0x4c
+
+#define USBHTCFG0_OFFS		0x100
+#define USBHHCFG0_OFFS		0x104
+#define USBHHCFG1_OFFS		0x104
+
+/* DMA controller registers */
+#define DMAC0_BASE	(AHB_PERI_BASE + 0x4000)
+#define DMAC1_BASE	(AHB_PERI_BASE + 0xa000)
+#define DMAC2_BASE	(AHB_PERI_BASE + 0x4800)
+#define DMAC3_BASE	(AHB_PERI_BASE + 0xa800)
+
+#define DMAC_CH_OFFSET(ch)	(ch * 0x30)
+
+#define ST_SADR_OFFS		0x00
+#define SPARAM_OFFS		0x04
+#define C_SADR_OFFS		0x0c
+#define ST_DADR_OFFS		0x10
+#define DPARAM_OFFS		0x14
+#define C_DADR_OFFS		0x1c
+#define HCOUNT_OFFS		0x20
+#define CHCTRL_OFFS		0x24
+#define RPTCTRL_OFFS		0x28
+#define EXTREQ_A_OFFS		0x2c
+
+/* Bits in CHCTRL register */
+#define CHCTRL_EN		(1 << 0)
+
+#define CHCTRL_IEN		(1 << 2)
+#define CHCTRL_FLAG		(1 << 3)
+#define CHCTRL_WSIZE8		(0 << 4)
+#define CHCTRL_WSIZE16		(1 << 4)
+#define CHCTRL_WSIZE32		(2 << 4)
+
+#define CHCTRL_BSIZE1		(0 << 6)
+#define CHCTRL_BSIZE2		(1 << 6)
+#define CHCTRL_BSIZE4		(2 << 6)
+#define CHCTRL_BSIZE8		(3 << 6)
+
+#define CHCTRL_TYPE_SINGLE_E	(0 << 8)
+#define CHCTRL_TYPE_HW		(1 << 8)
+#define CHCTRL_TYPE_SW		(2 << 8)
+#define CHCTRL_TYPE_SINGLE_L	(3 << 8)
+
+#define CHCTRL_BST		(1 << 10)
+
+/* Use DMA controller 0, channel 2 for USB */
+#define USB_DMA_BASE		(DMAC0_BASE + DMAC_CH_OFFSET(2))
+
+/* NAND flash controller registers */
+#define NFC_BASE	(AHB_PERI_BASE_VIRT + 0xd000)
+#define NFC_BASE_PHYS	(AHB_PERI_BASE + 0xd000)
+
+#define NFC_CMD_OFFS		0x00
+#define NFC_LADDR_OFFS		0x04
+#define NFC_BADDR_OFFS		0x08
+#define NFC_SADDR_OFFS		0x0c
+#define NFC_WDATA_OFFS		0x10
+#define NFC_LDATA_OFFS		0x20
+#define NFC_SDATA_OFFS		0x40
+#define NFC_CTRL_OFFS		0x50
+#define NFC_PSTART_OFFS		0x54
+#define NFC_RSTART_OFFS		0x58
+#define NFC_DSIZE_OFFS		0x5c
+#define NFC_IREQ_OFFS		0x60
+#define NFC_RST_OFFS		0x64
+#define NFC_CTRL1_OFFS		0x68
+#define NFC_MDATA_OFFS		0x70
+
+#define NFC_WDATA_PHYS_ADDR	(NFC_BASE_PHYS + NFC_WDATA_OFFS)
+
+/* Bits in NFC_CTRL */
+#define NFC_CTRL_BHLD_MASK	(0xf << 0)
+#define NFC_CTRL_BPW_MASK	(0xf << 4)
+#define NFC_CTRL_BSTP_MASK	(0xf << 8)
+#define NFC_CTRL_CADDR_MASK	(0x7 << 12)
+#define NFC_CTRL_CADDR_1	(0x0 << 12)
+#define NFC_CTRL_CADDR_2	(0x1 << 12)
+#define NFC_CTRL_CADDR_3	(0x2 << 12)
+#define NFC_CTRL_CADDR_4	(0x3 << 12)
+#define NFC_CTRL_CADDR_5	(0x4 << 12)
+#define NFC_CTRL_MSK		(1 << 15)
+#define NFC_CTRL_PSIZE256	(0 << 16)
+#define NFC_CTRL_PSIZE512	(1 << 16)
+#define NFC_CTRL_PSIZE1024	(2 << 16)
+#define NFC_CTRL_PSIZE2048	(3 << 16)
+#define NFC_CTRL_PSIZE4096	(4 << 16)
+#define NFC_CTRL_PSIZE_MASK	(7 << 16)
+#define NFC_CTRL_BSIZE1		(0 << 19)
+#define NFC_CTRL_BSIZE2		(1 << 19)
+#define NFC_CTRL_BSIZE4		(2 << 19)
+#define NFC_CTRL_BSIZE8		(3 << 19)
+#define NFC_CTRL_BSIZE_MASK	(3 << 19)
+#define NFC_CTRL_RDY		(1 << 21)
+#define NFC_CTRL_CS0SEL		(1 << 22)
+#define NFC_CTRL_CS1SEL		(1 << 23)
+#define NFC_CTRL_CS2SEL		(1 << 24)
+#define NFC_CTRL_CS3SEL		(1 << 25)
+#define NFC_CTRL_CSMASK		(0xf << 22)
+#define NFC_CTRL_BW		(1 << 26)
+#define NFC_CTRL_FS		(1 << 27)
+#define NFC_CTRL_DEN		(1 << 28)
+#define NFC_CTRL_READ_IEN	(1 << 29)
+#define NFC_CTRL_PROG_IEN	(1 << 30)
+#define NFC_CTRL_RDY_IEN	(1 << 31)
+
+/* Bits in NFC_IREQ */
+#define NFC_IREQ_IRQ0		(1 << 0)
+#define NFC_IREQ_IRQ1		(1 << 1)
+#define NFC_IREQ_IRQ2		(1 << 2)
+
+#define NFC_IREQ_FLAG0		(1 << 4)
+#define NFC_IREQ_FLAG1		(1 << 5)
+#define NFC_IREQ_FLAG2		(1 << 6)
+
+/* MMC controller registers */
+#define MMC0_BASE	(AHB_PERI_BASE_VIRT + 0xe000)
+#define MMC1_BASE	(AHB_PERI_BASE_VIRT + 0xe800)
+
+/* UART base addresses */
+
+#define UART0_BASE	(APB0_PERI_BASE_VIRT + 0x07000)
+#define UART0_BASE_PHYS	(APB0_PERI_BASE + 0x07000)
+#define UART1_BASE	(APB0_PERI_BASE_VIRT + 0x08000)
+#define UART1_BASE_PHYS	(APB0_PERI_BASE + 0x08000)
+#define UART2_BASE	(APB0_PERI_BASE_VIRT + 0x09000)
+#define UART2_BASE_PHYS	(APB0_PERI_BASE + 0x09000)
+#define UART3_BASE	(APB0_PERI_BASE_VIRT + 0x0a000)
+#define UART3_BASE_PHYS	(APB0_PERI_BASE + 0x0a000)
+#define UART4_BASE	(APB0_PERI_BASE_VIRT + 0x15000)
+#define UART4_BASE_PHYS	(APB0_PERI_BASE + 0x15000)
+
+#define UART_BASE	UART0_BASE
+#define UART_BASE_PHYS	UART0_BASE_PHYS
+
+/* ECC controller */
+#define ECC_CTR_BASE	(APB0_PERI_BASE_VIRT + 0xd000)
+
+#define ECC_CTRL_OFFS		0x00
+#define ECC_BASE_OFFS		0x04
+#define ECC_MASK_OFFS		0x08
+#define ECC_CLEAR_OFFS		0x0c
+#define ECC4_0_OFFS		0x10
+#define ECC4_1_OFFS		0x14
+
+#define ECC_EADDR0_OFFS		0x50
+
+#define ECC_ERRNUM_OFFS		0x90
+#define ECC_IREQ_OFFS		0x94
+
+/* Bits in ECC_CTRL */
+#define ECC_CTRL_ECC4_DIEN	(1 << 28)
+#define ECC_CTRL_ECC8_DIEN	(1 << 29)
+#define ECC_CTRL_ECC12_DIEN	(1 << 30)
+#define ECC_CTRL_ECC_DISABLE	0x0
+#define ECC_CTRL_ECC_SLC_ENC	0x8
+#define ECC_CTRL_ECC_SLC_DEC	0x9
+#define ECC_CTRL_ECC4_ENC	0xa
+#define ECC_CTRL_ECC4_DEC	0xb
+#define ECC_CTRL_ECC8_ENC	0xc
+#define ECC_CTRL_ECC8_DEC	0xd
+#define ECC_CTRL_ECC12_ENC	0xe
+#define ECC_CTRL_ECC12_DEC	0xf
+
+/* Bits in ECC_IREQ */
+#define ECC_IREQ_E4DI		(1 << 4)
+
+#define ECC_IREQ_E4DF		(1 << 20)
+#define ECC_IREQ_E4EF		(1 << 21)
+
+/* Interrupt controller */
+
+#define PIC0_BASE	(APB1_PERI_BASE_VIRT + 0x3000)
+#define PIC0_BASE_PHYS	(APB1_PERI_BASE + 0x3000)
+
+#define PIC0_IEN_OFFS		0x00
+#define PIC0_CREQ_OFFS		0x04
+#define PIC0_IREQ_OFFS		0x08
+#define PIC0_IRQSEL_OFFS	0x0c
+#define PIC0_SRC_OFFS		0x10
+#define PIC0_MREQ_OFFS		0x14
+#define PIC0_TSTREQ_OFFS	0x18
+#define PIC0_POL_OFFS		0x1c
+#define PIC0_IRQ_OFFS		0x20
+#define PIC0_FIQ_OFFS		0x24
+#define PIC0_MIRQ_OFFS		0x28
+#define PIC0_MFIQ_OFFS		0x2c
+#define PIC0_TMODE_OFFS		0x30
+#define PIC0_SYNC_OFFS		0x34
+#define PIC0_WKUP_OFFS		0x38
+#define PIC0_TMODEA_OFFS	0x3c
+#define PIC0_INTOEN_OFFS	0x40
+#define PIC0_MEN0_OFFS		0x44
+#define PIC0_MEN_OFFS		0x48
+
+#define PIC0_IEN		__REG(PIC0_BASE + PIC0_IEN_OFFS)
+#define PIC0_IEN_PHYS		__REG(PIC0_BASE_PHYS + PIC0_IEN_OFFS)
+#define PIC0_CREQ		__REG(PIC0_BASE + PIC0_CREQ_OFFS)
+#define PIC0_CREQ_PHYS		__REG(PIC0_BASE_PHYS + PIC0_CREQ_OFFS)
+#define PIC0_IREQ		__REG(PIC0_BASE + PIC0_IREQ_OFFS)
+#define PIC0_IRQSEL		__REG(PIC0_BASE + PIC0_IRQSEL_OFFS)
+#define PIC0_IRQSEL_PHYS	__REG(PIC0_BASE_PHYS + PIC0_IRQSEL_OFFS)
+#define PIC0_SRC		__REG(PIC0_BASE + PIC0_SRC_OFFS)
+#define PIC0_MREQ		__REG(PIC0_BASE + PIC0_MREQ_OFFS)
+#define PIC0_TSTREQ		__REG(PIC0_BASE + PIC0_TSTREQ_OFFS)
+#define PIC0_POL		__REG(PIC0_BASE + PIC0_POL_OFFS)
+#define PIC0_IRQ		__REG(PIC0_BASE + PIC0_IRQ_OFFS)
+#define PIC0_FIQ		__REG(PIC0_BASE + PIC0_FIQ_OFFS)
+#define PIC0_MIRQ		__REG(PIC0_BASE + PIC0_MIRQ_OFFS)
+#define PIC0_MFIQ		__REG(PIC0_BASE + PIC0_MFIQ_OFFS)
+#define PIC0_TMODE		__REG(PIC0_BASE + PIC0_TMODE_OFFS)
+#define PIC0_TMODE_PHYS		__REG(PIC0_BASE_PHYS + PIC0_TMODE_OFFS)
+#define PIC0_SYNC		__REG(PIC0_BASE + PIC0_SYNC_OFFS)
+#define PIC0_WKUP		__REG(PIC0_BASE + PIC0_WKUP_OFFS)
+#define PIC0_TMODEA		__REG(PIC0_BASE + PIC0_TMODEA_OFFS)
+#define PIC0_INTOEN		__REG(PIC0_BASE + PIC0_INTOEN_OFFS)
+#define PIC0_MEN0		__REG(PIC0_BASE + PIC0_MEN0_OFFS)
+#define PIC0_MEN		__REG(PIC0_BASE + PIC0_MEN_OFFS)
+
+#define PIC1_BASE	(APB1_PERI_BASE_VIRT + 0x3080)
+
+#define PIC1_IEN_OFFS		0x00
+#define PIC1_CREQ_OFFS		0x04
+#define PIC1_IREQ_OFFS		0x08
+#define PIC1_IRQSEL_OFFS	0x0c
+#define PIC1_SRC_OFFS		0x10
+#define PIC1_MREQ_OFFS		0x14
+#define PIC1_TSTREQ_OFFS	0x18
+#define PIC1_POL_OFFS		0x1c
+#define PIC1_IRQ_OFFS		0x20
+#define PIC1_FIQ_OFFS		0x24
+#define PIC1_MIRQ_OFFS		0x28
+#define PIC1_MFIQ_OFFS		0x2c
+#define PIC1_TMODE_OFFS		0x30
+#define PIC1_SYNC_OFFS		0x34
+#define PIC1_WKUP_OFFS		0x38
+#define PIC1_TMODEA_OFFS	0x3c
+#define PIC1_INTOEN_OFFS	0x40
+#define PIC1_MEN1_OFFS		0x44
+#define PIC1_MEN_OFFS		0x48
+
+#define PIC1_IEN	__REG(PIC1_BASE + PIC1_IEN_OFFS)
+#define PIC1_CREQ	__REG(PIC1_BASE + PIC1_CREQ_OFFS)
+#define PIC1_IREQ	__REG(PIC1_BASE + PIC1_IREQ_OFFS)
+#define PIC1_IRQSEL	__REG(PIC1_BASE + PIC1_IRQSEL_OFFS)
+#define PIC1_SRC	__REG(PIC1_BASE + PIC1_SRC_OFFS)
+#define PIC1_MREQ	__REG(PIC1_BASE + PIC1_MREQ_OFFS)
+#define PIC1_TSTREQ	__REG(PIC1_BASE + PIC1_TSTREQ_OFFS)
+#define PIC1_POL	__REG(PIC1_BASE + PIC1_POL_OFFS)
+#define PIC1_IRQ	__REG(PIC1_BASE + PIC1_IRQ_OFFS)
+#define PIC1_FIQ	__REG(PIC1_BASE + PIC1_FIQ_OFFS)
+#define PIC1_MIRQ	__REG(PIC1_BASE + PIC1_MIRQ_OFFS)
+#define PIC1_MFIQ	__REG(PIC1_BASE + PIC1_MFIQ_OFFS)
+#define PIC1_TMODE	__REG(PIC1_BASE + PIC1_TMODE_OFFS)
+#define PIC1_SYNC	__REG(PIC1_BASE + PIC1_SYNC_OFFS)
+#define PIC1_WKUP	__REG(PIC1_BASE + PIC1_WKUP_OFFS)
+#define PIC1_TMODEA	__REG(PIC1_BASE + PIC1_TMODEA_OFFS)
+#define PIC1_INTOEN	__REG(PIC1_BASE + PIC1_INTOEN_OFFS)
+#define PIC1_MEN1	__REG(PIC1_BASE + PIC1_MEN1_OFFS)
+#define PIC1_MEN	__REG(PIC1_BASE + PIC1_MEN_OFFS)
+
+/* Timer registers */
+#define TIMER_BASE		(APB1_PERI_BASE_VIRT + 0x4000)
+#define TIMER_BASE_PHYS		(APB1_PERI_BASE + 0x4000)
+
+#define TWDCFG_OFFS		0x70
+
+#define TC32EN_OFFS		0x80
+#define TC32LDV_OFFS		0x84
+#define TC32CMP0_OFFS		0x88
+#define TC32CMP1_OFFS		0x8c
+#define TC32PCNT_OFFS		0x90
+#define TC32MCNT_OFFS		0x94
+#define TC32IRQ_OFFS		0x98
+
+/* Bits in TC32EN */
+#define TC32EN_PRESCALE_MASK	0x00ffffff
+#define TC32EN_ENABLE		(1 << 24)
+#define TC32EN_LOADZERO		(1 << 25)
+#define TC32EN_STOPMODE		(1 << 26)
+#define TC32EN_LDM0		(1 << 28)
+#define TC32EN_LDM1		(1 << 29)
+
+/* Bits in TC32IRQ */
+#define TC32IRQ_MSTAT_MASK	0x0000001f
+#define TC32IRQ_RSTAT_MASK	(0x1f << 8)
+#define TC32IRQ_IRQEN0		(1 << 16)
+#define TC32IRQ_IRQEN1		(1 << 17)
+#define TC32IRQ_IRQEN2		(1 << 18)
+#define TC32IRQ_IRQEN3		(1 << 19)
+#define TC32IRQ_IRQEN4		(1 << 20)
+#define TC32IRQ_RSYNC		(1 << 30)
+#define TC32IRQ_IRQCLR		(1 << 31)
+
+/* GPIO registers */
+#define GPIOPD_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPD_DAT_OFFS		0x00
+#define GPIOPD_DOE_OFFS		0x04
+#define GPIOPD_FS0_OFFS		0x08
+#define GPIOPD_FS1_OFFS		0x0c
+#define GPIOPD_FS2_OFFS		0x10
+#define GPIOPD_RPU_OFFS		0x30
+#define GPIOPD_RPD_OFFS		0x34
+#define GPIOPD_DV0_OFFS		0x38
+#define GPIOPD_DV1_OFFS		0x3c
+
+#define GPIOPS_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPS_DAT_OFFS		0x40
+#define GPIOPS_DOE_OFFS		0x44
+#define GPIOPS_FS0_OFFS		0x48
+#define GPIOPS_FS1_OFFS		0x4c
+#define GPIOPS_FS2_OFFS		0x50
+#define GPIOPS_FS3_OFFS		0x54
+#define GPIOPS_RPU_OFFS		0x70
+#define GPIOPS_RPD_OFFS		0x74
+#define GPIOPS_DV0_OFFS		0x78
+#define GPIOPS_DV1_OFFS		0x7c
+
+#define GPIOPS_FS1_SDH0_BITS	0x000000ff
+#define GPIOPS_FS1_SDH1_BITS	0x0000ff00
+
+#define GPIOPU_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPU_DAT_OFFS		0x80
+#define GPIOPU_DOE_OFFS		0x84
+#define GPIOPU_FS0_OFFS		0x88
+#define GPIOPU_FS1_OFFS		0x8c
+#define GPIOPU_FS2_OFFS		0x90
+#define GPIOPU_RPU_OFFS		0xb0
+#define GPIOPU_RPD_OFFS		0xb4
+#define GPIOPU_DV0_OFFS		0xb8
+#define GPIOPU_DV1_OFFS		0xbc
+
+#define GPIOPU_FS0_TXD0		(1 << 0)
+#define GPIOPU_FS0_RXD0		(1 << 1)
+#define GPIOPU_FS0_CTS0		(1 << 2)
+#define GPIOPU_FS0_RTS0		(1 << 3)
+#define GPIOPU_FS0_TXD1		(1 << 4)
+#define GPIOPU_FS0_RXD1		(1 << 5)
+#define GPIOPU_FS0_CTS1		(1 << 6)
+#define GPIOPU_FS0_RTS1		(1 << 7)
+#define GPIOPU_FS0_TXD2		(1 << 8)
+#define GPIOPU_FS0_RXD2		(1 << 9)
+#define GPIOPU_FS0_CTS2		(1 << 10)
+#define GPIOPU_FS0_RTS2		(1 << 11)
+#define GPIOPU_FS0_TXD3		(1 << 12)
+#define GPIOPU_FS0_RXD3		(1 << 13)
+#define GPIOPU_FS0_CTS3		(1 << 14)
+#define GPIOPU_FS0_RTS3		(1 << 15)
+#define GPIOPU_FS0_TXD4		(1 << 16)
+#define GPIOPU_FS0_RXD4		(1 << 17)
+#define GPIOPU_FS0_CTS4		(1 << 18)
+#define GPIOPU_FS0_RTS4		(1 << 19)
+
+#define GPIOFC_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOFC_DAT_OFFS		0xc0
+#define GPIOFC_DOE_OFFS		0xc4
+#define GPIOFC_FS0_OFFS		0xc8
+#define GPIOFC_FS1_OFFS		0xcc
+#define GPIOFC_FS2_OFFS		0xd0
+#define GPIOFC_FS3_OFFS		0xd4
+#define GPIOFC_RPU_OFFS		0xf0
+#define GPIOFC_RPD_OFFS		0xf4
+#define GPIOFC_DV0_OFFS		0xf8
+#define GPIOFC_DV1_OFFS		0xfc
+
+#define GPIOFD_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOFD_DAT_OFFS		0x100
+#define GPIOFD_DOE_OFFS		0x104
+#define GPIOFD_FS0_OFFS		0x108
+#define GPIOFD_FS1_OFFS		0x10c
+#define GPIOFD_FS2_OFFS		0x110
+#define GPIOFD_RPU_OFFS		0x130
+#define GPIOFD_RPD_OFFS		0x134
+#define GPIOFD_DV0_OFFS		0x138
+#define GPIOFD_DV1_OFFS		0x13c
+
+#define GPIOLC_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOLC_DAT_OFFS		0x140
+#define GPIOLC_DOE_OFFS		0x144
+#define GPIOLC_FS0_OFFS		0x148
+#define GPIOLC_FS1_OFFS		0x14c
+#define GPIOLC_RPU_OFFS		0x170
+#define GPIOLC_RPD_OFFS		0x174
+#define GPIOLC_DV0_OFFS		0x178
+#define GPIOLC_DV1_OFFS		0x17c
+
+#define GPIOLD_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOLD_DAT_OFFS		0x180
+#define GPIOLD_DOE_OFFS		0x184
+#define GPIOLD_FS0_OFFS		0x188
+#define GPIOLD_FS1_OFFS		0x18c
+#define GPIOLD_FS2_OFFS		0x190
+#define GPIOLD_RPU_OFFS		0x1b0
+#define GPIOLD_RPD_OFFS		0x1b4
+#define GPIOLD_DV0_OFFS		0x1b8
+#define GPIOLD_DV1_OFFS		0x1bc
+
+#define GPIOAD_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOAD_DAT_OFFS		0x1c0
+#define GPIOAD_DOE_OFFS		0x1c4
+#define GPIOAD_FS0_OFFS		0x1c8
+#define GPIOAD_RPU_OFFS		0x1f0
+#define GPIOAD_RPD_OFFS		0x1f4
+#define GPIOAD_DV0_OFFS		0x1f8
+#define GPIOAD_DV1_OFFS		0x1fc
+
+#define GPIOXC_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOXC_DAT_OFFS		0x200
+#define GPIOXC_DOE_OFFS		0x204
+#define GPIOXC_FS0_OFFS		0x208
+#define GPIOXC_RPU_OFFS		0x230
+#define GPIOXC_RPD_OFFS		0x234
+#define GPIOXC_DV0_OFFS		0x238
+#define GPIOXC_DV1_OFFS		0x23c
+
+#define GPIOXC_FS0		__REG(GPIOXC_BASE + GPIOXC_FS0_OFFS)
+
+#define GPIOXC_FS0_CS0		(1 << 26)
+#define GPIOXC_FS0_CS1		(1 << 27)
+
+#define GPIOXD_BASE		(APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOXD_DAT_OFFS		0x240
+#define GPIOXD_FS0_OFFS		0x248
+#define GPIOXD_RPU_OFFS		0x270
+#define GPIOXD_RPD_OFFS		0x274
+#define GPIOXD_DV0_OFFS		0x278
+#define GPIOXD_DV1_OFFS		0x27c
+
+#define GPIOPK_BASE		(APB1_PERI_BASE_VIRT + 0x1c000)
+
+#define GPIOPK_RST_OFFS		0x008
+#define GPIOPK_DAT_OFFS		0x100
+#define GPIOPK_DOE_OFFS		0x104
+#define GPIOPK_FS0_OFFS		0x108
+#define GPIOPK_FS1_OFFS		0x10c
+#define GPIOPK_FS2_OFFS		0x110
+#define GPIOPK_IRQST_OFFS	0x210
+#define GPIOPK_IRQEN_OFFS	0x214
+#define GPIOPK_IRQPOL_OFFS	0x218
+#define GPIOPK_IRQTM0_OFFS	0x21c
+#define GPIOPK_IRQTM1_OFFS	0x220
+#define GPIOPK_CTL_OFFS		0x22c
+
+#define PMGPIO_BASE		(APB1_PERI_BASE_VIRT + 0x10000)
+#define BACKUP_RAM_BASE		PMGPIO_BASE
+
+#define PMGPIO_DAT_OFFS		0x800
+#define PMGPIO_DOE_OFFS		0x804
+#define PMGPIO_FS0_OFFS		0x808
+#define PMGPIO_RPU_OFFS		0x810
+#define PMGPIO_RPD_OFFS		0x814
+#define PMGPIO_DV0_OFFS		0x818
+#define PMGPIO_DV1_OFFS		0x81c
+#define PMGPIO_EE0_OFFS		0x820
+#define PMGPIO_EE1_OFFS		0x824
+#define PMGPIO_CTL_OFFS		0x828
+#define PMGPIO_DI_OFFS		0x82c
+#define PMGPIO_STR_OFFS		0x830
+#define PMGPIO_STF_OFFS		0x834
+#define PMGPIO_POL_OFFS		0x838
+#define PMGPIO_APB_OFFS		0x800
+
+/* Clock controller registers */
+#define CKC_BASE	((void __iomem *)(APB1_PERI_BASE_VIRT + 0x6000))
+
+#define CLKCTRL_OFFS		0x00
+#define PLL0CFG_OFFS		0x04
+#define PLL1CFG_OFFS		0x08
+#define CLKDIVC0_OFFS		0x0c
+
+#define BCLKCTR0_OFFS		0x14
+#define SWRESET0_OFFS		0x18
+
+#define BCLKCTR1_OFFS		0x60
+#define SWRESET1_OFFS		0x64
+#define PWDCTL_OFFS		0x68
+#define PLL2CFG_OFFS		0x6c
+#define CLKDIVC1_OFFS		0x70
+
+#define ACLKREF_OFFS		0x80
+#define ACLKI2C_OFFS		0x84
+#define ACLKSPI0_OFFS		0x88
+#define ACLKSPI1_OFFS		0x8c
+#define ACLKUART0_OFFS		0x90
+#define ACLKUART1_OFFS		0x94
+#define ACLKUART2_OFFS		0x98
+#define ACLKUART3_OFFS		0x9c
+#define ACLKUART4_OFFS		0xa0
+#define ACLKTCT_OFFS		0xa4
+#define ACLKTCX_OFFS		0xa8
+#define ACLKTCZ_OFFS		0xac
+#define ACLKADC_OFFS		0xb0
+#define ACLKDAI0_OFFS		0xb4
+#define ACLKDAI1_OFFS		0xb8
+#define ACLKLCD_OFFS		0xbc
+#define ACLKSPDIF_OFFS		0xc0
+#define ACLKUSBH_OFFS		0xc4
+#define ACLKSDH0_OFFS		0xc8
+#define ACLKSDH1_OFFS		0xcc
+#define ACLKC3DEC_OFFS		0xd0
+#define ACLKEXT_OFFS		0xd4
+#define ACLKCAN0_OFFS		0xd8
+#define ACLKCAN1_OFFS		0xdc
+#define ACLKGSB0_OFFS		0xe0
+#define ACLKGSB1_OFFS		0xe4
+#define ACLKGSB2_OFFS		0xe8
+#define ACLKGSB3_OFFS		0xec
+
+#define PLLxCFG_PD		(1 << 31)
+
+/* CLKCTRL bits */
+#define CLKCTRL_XE		(1 << 31)
+
+/* CLKDIVCx bits */
+#define CLKDIVC0_XTE		(1 << 7)
+#define CLKDIVC0_XE		(1 << 15)
+#define CLKDIVC0_P1E		(1 << 23)
+#define CLKDIVC0_P0E		(1 << 31)
+
+#define CLKDIVC1_P2E		(1 << 7)
+
+/* BCLKCTR0 clock bits */
+#define BCLKCTR0_USBD		(1 << 4)
+#define BCLKCTR0_ECC		(1 << 9)
+#define BCLKCTR0_USBH0		(1 << 11)
+#define BCLKCTR0_NFC		(1 << 16)
+
+/* BCLKCTR1 clock bits */
+#define BCLKCTR1_USBH1		(1 << 20)
+
+/* SWRESET0 bits */
+#define SWRESET0_USBD		(1 << 4)
+#define SWRESET0_USBH0		(1 << 11)
+
+/* SWRESET1 bits */
+#define SWRESET1_USBH1		(1 << 20)
+
+/* System clock sources.
+ * Note: These are the clock sources that serve as parents for
+ * all other clocks. They have no parents themselves.
+ *
+ * These values are used for struct clk->root_id. All clocks
+ * that are not system clock sources have this value set to
+ * CLK_SRC_NOROOT.
+ * The values for system clocks start with CLK_SRC_PLL0 == 0
+ * because this gives us exactly the values needed for the lower
+ * 4 bits of ACLK_* registers. Therefore, CLK_SRC_NOROOT is
+ * defined as -1 to not disturb the order.
+ */
+enum root_clks {
+	CLK_SRC_NOROOT = -1,
+	CLK_SRC_PLL0 = 0,
+	CLK_SRC_PLL1,
+	CLK_SRC_PLL0DIV,
+	CLK_SRC_PLL1DIV,
+	CLK_SRC_XI,
+	CLK_SRC_XIDIV,
+	CLK_SRC_XTI,
+	CLK_SRC_XTIDIV,
+	CLK_SRC_PLL2,
+	CLK_SRC_PLL2DIV,
+	CLK_SRC_PK0,
+	CLK_SRC_PK1,
+	CLK_SRC_PK2,
+	CLK_SRC_PK3,
+	CLK_SRC_PK4,
+	CLK_SRC_48MHZ
+};
+
+#define CLK_SRC_MASK		0xf
+
+/* Bits in ACLK* registers */
+#define ACLK_EN		(1 << 28)
+#define ACLK_SEL_SHIFT		24
+#define ACLK_SEL_MASK		0x0f000000
+#define ACLK_DIV_MASK		0x00000fff
+
+/* System configuration registers */
+
+#define SCFG_BASE		(APB1_PERI_BASE_VIRT + 0x13000)
+
+#define	BMI_OFFS		0x00
+#define AHBCON0_OFFS		0x04
+#define APBPWE_OFFS		0x08
+#define DTCMWAIT_OFFS		0x0c
+#define ECCSEL_OFFS		0x10
+#define AHBCON1_OFFS		0x14
+#define SDHCFG_OFFS		0x18
+#define REMAP_OFFS		0x20
+#define LCDSIAE_OFFS		0x24
+#define XMCCFG_OFFS		0xe0
+#define IMCCFG_OFFS		0xe4
+
+/* Values for ECCSEL */
+#define ECCSEL_EXTMEM		0x0
+#define ECCSEL_DTCM		0x1
+#define ECCSEL_INT_SRAM		0x2
+#define ECCSEL_AHB		0x3
+
+/* Bits in XMCCFG */
+#define XMCCFG_NFCE		(1 << 1)
+#define XMCCFG_FDXD		(1 << 2)
+
+/* External memory controller registers */
+
+#define EMC_BASE		EXT_MEM_CTRL_BASE
+
+#define SDCFG_OFFS		0x00
+#define SDFSM_OFFS		0x04
+#define MCFG_OFFS		0x08
+
+#define CSCFG0_OFFS		0x10
+#define CSCFG1_OFFS		0x14
+#define CSCFG2_OFFS		0x18
+#define CSCFG3_OFFS		0x1c
+
+#define MCFG_SDEN		(1 << 4)
+
+#endif /* TCC8K_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/timex.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/timex.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/timex.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,5 @@
+/*
+ * A definition needed by arch core code.
+ *
+ */
+#define CLOCK_TICK_RATE		(HZ * 100000UL)
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/uncompress.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/uncompress.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/uncompress.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/uncompress.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * This file is licensed under the terms of the GPL version 2.
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/types.h>
+
+#include <mach/tcc8k-regs.h>
+
+unsigned int system_rev;
+
+#define ID_MASK			0x7fff
+
+static void putc(int c)
+{
+	u32 *uart_lsr = (u32 *)(UART_BASE_PHYS + (UART_LSR << 2));
+	u32 *uart_tx = (u32 *)(UART_BASE_PHYS + (UART_TX << 2));
+
+	while (!(*uart_lsr & UART_LSR_THRE))
+		barrier();
+	*uart_tx = c;
+}
+
+static inline void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/vmalloc.h linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/vmalloc.h
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/include/mach/vmalloc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/include/mach/vmalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,10 @@
+/*
+ * Author: <linux@telechips.com>
+ * Created: June 10, 2008
+ *
+ * Copyright (C) 2000 Russell King.
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+#define VMALLOC_END	0xf0000000UL
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/Kconfig linux-libre-2.6.37-gnu/arch/arm/plat-tcc/Kconfig
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+if ARCH_TCC_926
+
+menu "Telechips ARM926-based CPUs"
+
+choice
+	prompt "Telechips CPU type:"
+	default ARCH_TCC8K
+
+config ARCH_TCC8K
+	bool TCC8000
+	select USB_ARCH_HAS_OHCI
+	help
+	  Support for Telechips TCC8000 systems
+
+endchoice
+
+source "arch/arm/mach-tcc8k/Kconfig"
+
+endmenu
+endif
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/Makefile linux-libre-2.6.37-gnu/arch/arm/plat-tcc/Makefile
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,3 @@
+# "Telechips Platform Common Modules"
+
+obj-y := clock.o system.o
diff -druN linux-libre-2.6.36-gnu/arch/arm/plat-tcc/system.c linux-libre-2.6.37-gnu/arch/arm/plat-tcc/system.c
--- linux-libre-2.6.36-gnu/arch/arm/plat-tcc/system.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/arm/plat-tcc/system.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,25 @@
+/*
+ * System functions for Telechips TCCxxxx SoCs
+ *
+ * Copyright (C) Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#include <linux/io.h>
+
+#include <mach/tcc8k-regs.h>
+
+/* System reboot */
+void plat_tcc_reboot(void)
+{
+	/* Make sure clocks are on */
+	__raw_writel(0xffffffff, CKC_BASE + BCLKCTR0_OFFS);
+
+	/* Enable watchdog reset */
+	__raw_writel(0x49, TIMER_BASE + TWDCFG_OFFS);
+	/* Wait for reset */
+	while(1)
+		;
+}
diff -druN linux-libre-2.6.36-gnu/arch/arm/tools/mach-types linux-libre-2.6.37-gnu/arch/arm/tools/mach-types
--- linux-libre-2.6.36-gnu/arch/arm/tools/mach-types	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/tools/mach-types	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Thu Sep 9 22:43:01 2010
+# Last update: Sun Dec 12 23:24:27 2010
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -2321,7 +2321,7 @@
 u380			MACH_U380		U380			2333
 oamp3_hualu		MACH_HUALU_BOARD	HUALU_BOARD		2334
 npcmx50			MACH_NPCMX50		NPCMX50			2335
-mx51_lange51		MACH_MX51_LANGE51	MX51_LANGE51		2336
+mx51_efikamx		MACH_MX51_EFIKAMX	MX51_EFIKAMX		2336
 mx51_lange52		MACH_MX51_LANGE52	MX51_LANGE52		2337
 riom			MACH_RIOM		RIOM			2338
 comcas			MACH_COMCAS		COMCAS			2339
@@ -2355,7 +2355,7 @@
 csb732			MACH_CSB732		CSB732			2367
 u8500			MACH_U8500		U8500			2368
 huqiu			MACH_HUQIU		HUQIU			2369
-mx51_kunlun		MACH_MX51_KUNLUN	MX51_KUNLUN		2370
+mx51_efikasb		MACH_MX51_EFIKASB	MX51_EFIKASB		2370
 pmt1g			MACH_PMT1G		PMT1G			2371
 htcelf			MACH_HTCELF		HTCELF			2372
 armadillo420		MACH_ARMADILLO420	ARMADILLO420		2373
@@ -2971,7 +2971,7 @@
 wasabi			MACH_WASABI		WASABI			2986
 vivow			MACH_VIVOW		VIVOW			2987
 mx50_rdp		MACH_MX50_RDP		MX50_RDP		2988
-universal		MACH_UNIVERSAL		UNIVERSAL		2989
+universal_c210		MACH_UNIVERSAL_C210	UNIVERSAL_C210		2989
 real6410		MACH_REAL6410		REAL6410		2990
 spx_sakura		MACH_SPX_SAKURA		SPX_SAKURA		2991
 ij3k_2440		MACH_IJ3K_2440		IJ3K_2440		2992
@@ -3044,3 +3044,178 @@
 msm8x60_qrdc		MACH_MSM8X60_QRDC	MSM8X60_QRDC		3060
 spear900		MACH_SPEAR900		SPEAR900		3061
 pcontrol_g20		MACH_PCONTROL_G20	PCONTROL_G20		3062
+rdstor			MACH_RDSTOR		RDSTOR			3063
+usdloader		MACH_USDLOADER		USDLOADER		3064
+tsoploader		MACH_TSOPLOADER		TSOPLOADER		3065
+kronos			MACH_KRONOS		KRONOS			3066
+ffcore			MACH_FFCORE		FFCORE			3067
+mone			MACH_MONE		MONE			3068
+unit2s			MACH_UNIT2S		UNIT2S			3069
+acer_a5			MACH_ACER_A5		ACER_A5			3070
+etherpro_isp		MACH_ETHERPRO_ISP	ETHERPRO_ISP		3071
+stretchs7000		MACH_STRETCHS7000	STRETCHS7000		3072
+p87_smartsim		MACH_P87_SMARTSIM	P87_SMARTSIM		3073
+tulip			MACH_TULIP		TULIP			3074
+sunflower		MACH_SUNFLOWER		SUNFLOWER		3075
+rib			MACH_RIB		RIB			3076
+clod			MACH_CLOD		CLOD			3077
+rump			MACH_RUMP		RUMP			3078
+tenderloin		MACH_TENDERLOIN		TENDERLOIN		3079
+shortloin		MACH_SHORTLOIN		SHORTLOIN		3080
+crespo			MACH_CRESPO		CRESPO			3081
+antares			MACH_ANTARES		ANTARES			3082
+wb40n			MACH_WB40N		WB40N			3083
+herring			MACH_HERRING		HERRING			3084
+naxy400			MACH_NAXY400		NAXY400			3085
+naxy1200		MACH_NAXY1200		NAXY1200		3086
+vpr200			MACH_VPR200		VPR200			3087
+bug20			MACH_BUG20		BUG20			3088
+goflexnet		MACH_GOFLEXNET		GOFLEXNET		3089
+torbreck		MACH_TORBRECK		TORBRECK		3090
+saarb_mg1		MACH_SAARB_MG1		SAARB_MG1		3091
+callisto		MACH_CALLISTO		CALLISTO		3092
+multhsu			MACH_MULTHSU		MULTHSU			3093
+saluda			MACH_SALUDA		SALUDA			3094
+pemp_omap3_apollo	MACH_PEMP_OMAP3_APOLLO	PEMP_OMAP3_APOLLO	3095
+vc0718			MACH_VC0718		VC0718			3096
+mvblx			MACH_MVBLX		MVBLX			3097
+inhand_apeiron		MACH_INHAND_APEIRON	INHAND_APEIRON		3098
+inhand_fury		MACH_INHAND_FURY	INHAND_FURY		3099
+inhand_siren		MACH_INHAND_SIREN	INHAND_SIREN		3100
+hdnvp			MACH_HDNVP		HDNVP			3101
+softwinner		MACH_SOFTWINNER		SOFTWINNER		3102
+prima2_evb		MACH_PRIMA2_EVB		PRIMA2_EVB		3103
+nas6210			MACH_NAS6210		NAS6210			3104
+unisdev			MACH_UNISDEV		UNISDEV			3105
+sbca11			MACH_SBCA11		SBCA11			3106
+saga			MACH_SAGA		SAGA			3107
+ns_k330			MACH_NS_K330		NS_K330			3108
+tanna			MACH_TANNA		TANNA			3109
+imate8502		MACH_IMATE8502		IMATE8502		3110
+aspen			MACH_ASPEN		ASPEN			3111
+daintree_cwac		MACH_DAINTREE_CWAC	DAINTREE_CWAC		3112
+zmx25			MACH_ZMX25		ZMX25			3113
+maple1			MACH_MAPLE1		MAPLE1			3114
+qsd8x72_surf		MACH_QSD8X72_SURF	QSD8X72_SURF		3115
+qsd8x72_ffa		MACH_QSD8X72_FFA	QSD8X72_FFA		3116
+abilene			MACH_ABILENE		ABILENE			3117
+eigen_ttr		MACH_EIGEN_TTR		EIGEN_TTR		3118
+iomega_ix2_200		MACH_IOMEGA_IX2_200	IOMEGA_IX2_200		3119
+coretec_vcx7400		MACH_CORETEC_VCX7400	CORETEC_VCX7400		3120
+santiago		MACH_SANTIAGO		SANTIAGO		3121
+mx257sol		MACH_MX257SOL		MX257SOL		3122
+strasbourg		MACH_STRASBOURG		STRASBOURG		3123
+msm8x60_fluid		MACH_MSM8X60_FLUID	MSM8X60_FLUID		3124
+smartqv5		MACH_SMARTQV5		SMARTQV5		3125
+smartqv3		MACH_SMARTQV3		SMARTQV3		3126
+smartqv7		MACH_SMARTQV7		SMARTQV7		3127
+paz00			MACH_PAZ00		PAZ00			3128
+acmenetusfoxg20		MACH_ACMENETUSFOXG20	ACMENETUSFOXG20		3129
+htcwillow		MACH_HTCWILLOW		HTCWILLOW		3130
+fwbd_0404		MACH_FWBD_0404		FWBD_0404		3131
+hdgu			MACH_HDGU		HDGU			3132
+pyramid			MACH_PYRAMID		PYRAMID			3133
+epiphan			MACH_EPIPHAN		EPIPHAN			3134
+omap_bender		MACH_OMAP_BENDER	OMAP_BENDER		3135
+gurnard			MACH_GURNARD		GURNARD			3136
+gtl_it5100		MACH_GTL_IT5100		GTL_IT5100		3137
+bcm2708			MACH_BCM2708		BCM2708			3138
+mx51_ggc		MACH_MX51_GGC		MX51_GGC		3139
+sharespace		MACH_SHARESPACE		SHARESPACE		3140
+haba_knx_explorer	MACH_HABA_KNX_EXPLORER	HABA_KNX_EXPLORER	3141
+simtec_kirkmod		MACH_SIMTEC_KIRKMOD	SIMTEC_KIRKMOD		3142
+crux			MACH_CRUX		CRUX			3143
+mx51_bravo		MACH_MX51_BRAVO		MX51_BRAVO		3144
+charon			MACH_CHARON		CHARON			3145
+picocom3		MACH_PICOCOM3		PICOCOM3		3146
+picocom4		MACH_PICOCOM4		PICOCOM4		3147
+serrano			MACH_SERRANO		SERRANO			3148
+doubleshot		MACH_DOUBLESHOT		DOUBLESHOT		3149
+evsy			MACH_EVSY		EVSY			3150
+huashan			MACH_HUASHAN		HUASHAN			3151
+lausanne		MACH_LAUSANNE		LAUSANNE		3152
+emerald			MACH_EMERALD		EMERALD			3153
+tqma35			MACH_TQMA35		TQMA35			3154
+marvel			MACH_MARVEL		MARVEL			3155
+manuae			MACH_MANUAE		MANUAE			3156
+chacha			MACH_CHACHA		CHACHA			3157
+lemon			MACH_LEMON		LEMON			3158
+csc			MACH_CSC		CSC			3159
+gira_knxip_router	MACH_GIRA_KNXIP_ROUTER	GIRA_KNXIP_ROUTER	3160
+t20			MACH_T20		T20			3161
+hdmini			MACH_HDMINI		HDMINI			3162
+sciphone_g2		MACH_SCIPHONE_G2	SCIPHONE_G2		3163
+express			MACH_EXPRESS		EXPRESS			3164
+express_kt		MACH_EXPRESS_KT		EXPRESS_KT		3165
+maximasp		MACH_MAXIMASP		MAXIMASP		3166
+nitrogen_imx51		MACH_NITROGEN_IMX51	NITROGEN_IMX51		3167
+nitrogen_imx53		MACH_NITROGEN_IMX53	NITROGEN_IMX53		3168
+sunfire			MACH_SUNFIRE		SUNFIRE			3169
+arowana			MACH_AROWANA		AROWANA			3170
+tegra_daytona		MACH_TEGRA_DAYTONA	TEGRA_DAYTONA		3171
+tegra_swordfish		MACH_TEGRA_SWORDFISH	TEGRA_SWORDFISH		3172
+edison			MACH_EDISON		EDISON			3173
+svp8500v1		MACH_SVP8500V1		SVP8500V1		3174
+svp8500v2		MACH_SVP8500V2		SVP8500V2		3175
+svp5500			MACH_SVP5500		SVP5500			3176
+b5500			MACH_B5500		B5500			3177
+s5500			MACH_S5500		S5500			3178
+icon			MACH_ICON		ICON			3179
+elephant		MACH_ELEPHANT		ELEPHANT		3180
+msm8x60_fusion		MACH_MSM8X60_FUSION	MSM8X60_FUSION		3181
+shooter			MACH_SHOOTER		SHOOTER			3182
+spade_lte		MACH_SPADE_LTE		SPADE_LTE		3183
+philhwani		MACH_PHILHWANI		PHILHWANI		3184
+gsncomm			MACH_GSNCOMM		GSNCOMM			3185
+strasbourg_a2		MACH_STRASBOURG_A2	STRASBOURG_A2		3186
+mmm			MACH_MMM		MMM			3187
+davinci_dm365_bv	MACH_DAVINCI_DM365_BV	DAVINCI_DM365_BV	3188
+ag5evm			MACH_AG5EVM		AG5EVM			3189
+sc575plc		MACH_SC575PLC		SC575PLC		3190
+sc575hmi		MACH_SC575IPC		SC575IPC		3191
+omap3_tdm3730		MACH_OMAP3_TDM3730	OMAP3_TDM3730		3192
+g7			MACH_G7			G7			3193
+top9000_eval		MACH_TOP9000_EVAL	TOP9000_EVAL		3194
+top9000_su		MACH_TOP9000_SU		TOP9000_SU		3195
+utm300			MACH_UTM300		UTM300			3196
+tsunagi			MACH_TSUNAGI		TSUNAGI			3197
+ts75xx			MACH_TS75XX		TS75XX			3198
+msm8x60_fusn_ffa	MACH_MSM8X60_FUSN_FFA	MSM8X60_FUSN_FFA	3199
+ts47xx			MACH_TS47XX		TS47XX			3200
+da850_k5		MACH_DA850_K5		DA850_K5		3201
+ax502			MACH_AX502		AX502			3202
+igep0032		MACH_IGEP0032		IGEP0032		3203
+antero			MACH_ANTERO		ANTERO			3204
+synergy			MACH_SYNERGY		SYNERGY			3205
+ics_if_voip		MACH_ICS_IF_VOIP	ICS_IF_VOIP		3206
+wlf_cragg_6410		MACH_WLF_CRAGG_6410	WLF_CRAGG_6410		3207
+punica			MACH_PUNICA		PUNICA			3208
+sbc_nt250		MACH_SBC_NT250		SBC_NT250		3209
+mx27_wmultra		MACH_MX27_WMULTRA	MX27_WMULTRA		3210
+mackerel		MACH_MACKEREL		MACKEREL		3211
+fa9x27			MACH_FA9X27		FA9X27			3213
+ns2816tb		MACH_NS2816TB		NS2816TB		3214
+ns2816_ntpad		MACH_NS2816_NTPAD	NS2816_NTPAD		3215
+ns2816_ntnb		MACH_NS2816_NTNB	NS2816_NTNB		3216
+kaen			MACH_KAEN		KAEN			3217
+nv1000			MACH_NV1000		NV1000			3218
+nuc950ts		MACH_NUC950TS		NUC950TS		3219
+nokia_rm680		MACH_NOKIA_RM680	NOKIA_RM680		3220
+ast2200			MACH_AST2200		AST2200			3221
+lead			MACH_LEAD		LEAD			3222
+unino1			MACH_UNINO1		UNINO1			3223
+greeco			MACH_GREECO		GREECO			3224
+verdi			MACH_VERDI		VERDI			3225
+dm6446_adbox		MACH_DM6446_ADBOX	DM6446_ADBOX		3226
+quad_salsa		MACH_QUAD_SALSA		QUAD_SALSA		3227
+abb_gma_1_1		MACH_ABB_GMA_1_1	ABB_GMA_1_1		3228
+svcid			MACH_SVCID		SVCID			3229
+msm8960_sim		MACH_MSM8960_SIM	MSM8960_SIM		3230
+msm8960_rumi3		MACH_MSM8960_RUMI3	MSM8960_RUMI3		3231
+icon_g			MACH_ICON_G		ICON_G			3232
+mb3			MACH_MB3		MB3			3233
+gsia18s			MACH_GSIA18S		GSIA18S			3234
+pivicc			MACH_PIVICC		PIVICC			3235
+pcm048			MACH_PCM048		PCM048			3236
+dds			MACH_DDS		DDS			3237
+chalten_xa1		MACH_CHALTEN_XA1	CHALTEN_XA1		3238
diff -druN linux-libre-2.6.36-gnu/arch/arm/vfp/vfphw.S linux-libre-2.6.37-gnu/arch/arm/vfp/vfphw.S
--- linux-libre-2.6.36-gnu/arch/arm/vfp/vfphw.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/arm/vfp/vfphw.S	2011-01-04 19:50:19.000000000 -0500
@@ -206,6 +206,7 @@
 	mov	pc, lr
 ENDPROC(vfp_save_state)
 
+	.align
 last_VFP_context_address:
 	.word	last_VFP_context
 
diff -druN linux-libre-2.6.36-gnu/arch/avr32/boards/mimc200/fram.c linux-libre-2.6.37-gnu/arch/avr32/boards/mimc200/fram.c
--- linux-libre-2.6.36-gnu/arch/avr32/boards/mimc200/fram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/boards/mimc200/fram.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,7 @@
 static const struct file_operations fram_fops = {
 	.owner			= THIS_MODULE,
 	.mmap			= fram_mmap,
+	.llseek			= noop_llseek,
 };
 
 #define FRAM_MINOR	0
diff -druN linux-libre-2.6.36-gnu/arch/avr32/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/avr32/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/avr32/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,90 +1,6 @@
 #ifndef __ASM_AVR32_IOCTLS_H
 #define __ASM_AVR32_IOCTLS_H
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define TIOCGRS485      0x542E
-#define TIOCSRS485      0x542F
-
-#define FIONCLEX	0x5450
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
-#define FIOQSIZE	0x5460
-
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* __ASM_AVR32_IOCTLS_H */
diff -druN linux-libre-2.6.36-gnu/arch/avr32/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/avr32/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/avr32/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,16 +8,14 @@
 #ifndef __ASM_AVR32_IRQFLAGS_H
 #define __ASM_AVR32_IRQFLAGS_H
 
+#include <linux/types.h>
 #include <asm/sysreg.h>
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
 	return sysreg_read(SR);
 }
 
-#define raw_local_save_flags(x)					\
-	do { (x) = __raw_local_save_flags(); } while (0)
-
 /*
  * This will restore ALL status register flags, not only the interrupt
  * mask flag.
@@ -25,44 +23,39 @@
  * The empty asm statement informs the compiler of this fact while
  * also serving as a barrier.
  */
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
 	sysreg_write(SR, flags);
 	asm volatile("" : : : "memory", "cc");
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
 	asm volatile("ssrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
 	asm volatile("csrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
 	return (flags & SYSREG_BIT(GM)) != 0;
 }
 
-static inline int raw_irqs_disabled(void)
+static inline bool arch_irqs_disabled(void)
 {
-	unsigned long flags = __raw_local_save_flags();
-
-	return raw_irqs_disabled_flags(flags);
+	return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-	unsigned long flags = __raw_local_save_flags();
+	unsigned long flags = arch_local_save_flags();
 
-	raw_local_irq_disable();
+	arch_local_irq_disable();
 
 	return flags;
 }
 
-#define raw_local_irq_save(flags)				\
-	do { (flags) = __raw_local_irq_save(); } while (0)
-
 #endif /* __ASM_AVR32_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/avr32/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/avr32/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/avr32/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -319,9 +319,7 @@
 #define pte_offset_kernel(dir, address)					\
 	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte)		do { } while (0)
-#define pte_unmap_nested(pte)	do { } while (0)
 
 struct vm_area_struct;
 extern void update_mmu_cache(struct vm_area_struct * vma,
diff -druN linux-libre-2.6.36-gnu/arch/avr32/Kconfig linux-libre-2.6.37-gnu/arch/avr32/Kconfig
--- linux-libre-2.6.36-gnu/arch/avr32/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux Kernel Configuration"
-
 config AVR32
 	def_bool y
 	# With EMBEDDED=n, we get lots of stuff automatically selected
@@ -90,6 +83,7 @@
 	select ARCH_REQUIRE_GPIOLIB
 	select GENERIC_ALLOCATOR
 	select HAVE_FB_ATMEL
+	select HAVE_NET_MACB
 
 #
 # CPU types
@@ -145,7 +139,7 @@
 	  will cover even the most exceptional need of memory bandwidth. Together with the onboard
 	  video decoder the board is ready for video processing.
 
-	  For more information see: http://www.miromico.com/hammerhead
+	  For more information see: http://www.miromico.ch/index.php/hammerhead.html 
 
 config BOARD_FAVR_32
 	bool "Favr-32 LCD-board"
diff -druN linux-libre-2.6.36-gnu/arch/avr32/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/avr32/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/avr32/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/avr32/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,9 +146,11 @@
 	return ret;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	void __user *datap = (void __user *) data;
 
 	switch (request) {
 	/* Read the word at location addr in the child process */
@@ -158,8 +160,7 @@
 		break;
 
 	case PTRACE_PEEKUSR:
-		ret = ptrace_read_user(child, addr,
-				       (unsigned long __user *)data);
+		ret = ptrace_read_user(child, addr, datap);
 		break;
 
 	/* Write the word in data at location addr */
@@ -173,11 +174,11 @@
 		break;
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs(child, (void __user *)data);
+		ret = ptrace_getregs(child, datap);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs(child, (const void __user *)data);
+		ret = ptrace_setregs(child, datap);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF518F-EZBRD_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF518F-EZBRD_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF518F-EZBRD_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF518F-EZBRD_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -114,7 +115,6 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF526-EZBRD_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF526-EZBRD_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF526-EZBRD_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF526-EZBRD_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -152,7 +153,6 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-AD7160-EVAL_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,105 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_AIO is not set
+CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_PREEMPT=y
+CONFIG_BF527=y
+CONFIG_BF_REV_0_2=y
+CONFIG_IRQ_TWI=7
+CONFIG_IRQ_PORTH_INTA=7
+CONFIG_IRQ_PORTH_INTB=7
+CONFIG_BFIN527_AD7160EVAL=y
+CONFIG_BF527_SPORT0_PORTF=y
+CONFIG_BF527_UART1_PORTG=y
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="bootargs=root=/dev/mtdblock0 rw clkin_hz=24000000 earlyprintk=serial,uart0,57600 console=tty0 console=ttyBF0,57600"
+CONFIG_CLKIN_HZ=24000000
+CONFIG_HZ_300=y
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+CONFIG_IP_CHECKSUM_L1=y
+CONFIG_SYSCALL_TAB_L1=y
+CONFIG_CPLB_SWITCH_TAB_L1=y
+CONFIG_BFIN_GPTIMERS=y
+CONFIG_C_CDPRIO=y
+CONFIG_BANK_1=0x5554
+CONFIG_BANK_3=0xFFC0
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_NET=y
+CONFIG_UNIX=y
+# CONFIG_WIRELESS is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_AD7160=y
+CONFIG_TOUCHSCREEN_AD7160_FW=y
+# CONFIG_SERIO is not set
+# CONFIG_BFIN_DMA_INTERFACE is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_BFIN_OTP is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=400
+CONFIG_SPI=y
+CONFIG_SPI_BFIN=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_BLACKFIN_VGA16 is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_G_SERIAL=y
+CONFIG_MMC=y
+CONFIG_MMC_SPI=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-EZKIT_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-EZKIT_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-EZKIT_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-EZKIT_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF527=y
 CONFIG_BF_REV_0_1=y
@@ -37,6 +38,7 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -173,6 +175,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-EZKIT-V2_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-EZKIT-V2_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-EZKIT-V2_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF527=y
 CONFIG_BF_REV_0_2=y
@@ -38,6 +39,7 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -181,6 +183,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-TLL6527M_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-TLL6527M_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF527-TLL6527M_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF527-TLL6527M_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,179 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCALVERSION="DEV_0-1_pre2010"
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_FUTEX is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_AIO is not set
+CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_BF527=y
+CONFIG_BF_REV_0_2=y
+CONFIG_BFIN527_TLL6527M=y
+CONFIG_BF527_UART1_PORTG=y
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+CONFIG_BOOT_LOAD=0x400000
+# CONFIG_CYCLES_CLOCKSOURCE is not set
+# CONFIG_SCHEDULE_L1 is not set
+# CONFIG_MEMSET_L1 is not set
+# CONFIG_MEMCPY_L1 is not set
+# CONFIG_SYS_BFIN_SPINLOCK_L1 is not set
+CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
+CONFIG_BFIN_GPTIMERS=y
+CONFIG_DMA_UNCACHED_2M=y
+CONFIG_C_CDPRIO=y
+CONFIG_BANK_0=0xFFC2
+CONFIG_BANK_1=0xFFC2
+CONFIG_BANK_2=0xFFC2
+CONFIG_BANK_3=0xFFC2
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_IRDA=m
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRTTY_SIR=m
+CONFIG_BFIN_SIR=m
+CONFIG_BFIN_SIR0=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_GPIO_ADDR=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=m
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_BFIN_MAC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_AD7879=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_AD714X=y
+CONFIG_INPUT_ADXL34X=y
+# CONFIG_SERIO is not set
+CONFIG_BFIN_PPI=m
+CONFIG_BFIN_SIMPLE_TIMER=m
+CONFIG_BFIN_SPORT=m
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_BFIN_JTAG_COMM=m
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+CONFIG_I2C_BLACKFIN_TWI=y
+CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_BFIN_WDT=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_BLACKFIN_CAM=m
+CONFIG_OV9655=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_6x11=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_BLACKFIN_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=m
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_BFIN=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_UTF8=m
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_MMRS=y
+CONFIG_DEBUG_HWERR=y
+CONFIG_EXACT_HWERR=y
+CONFIG_DEBUG_DOUBLEFAULT=y
+CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CPLB_INFO=y
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC7=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF533-EZKIT_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF533-EZKIT_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF533-EZKIT_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF533-EZKIT_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BFIN533_EZKIT=y
 CONFIG_TIMER0=11
@@ -107,6 +108,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF533-STAMP_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF533-STAMP_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF533-STAMP_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF533-STAMP_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_TIMER0=11
 CONFIG_HIGH_RES_TIMERS=y
@@ -121,6 +122,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF537-STAMP_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF537-STAMP_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF537-STAMP_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF537-STAMP_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,9 +20,9 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF537=y
-CONFIG_IRQ_ERROR=11
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_NOMMU_INITIAL_TRIM_EXCESS=0
 CONFIG_BFIN_GPTIMERS=m
@@ -133,6 +133,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF538-EZKIT_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF538-EZKIT_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF538-EZKIT_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF538-EZKIT_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF538=y
 CONFIG_IRQ_TIMER0=12
@@ -31,6 +32,7 @@
 CONFIG_BANK_3=0x99B2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -129,6 +131,5 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF548-EZKIT_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF548-EZKIT_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF548-EZKIT_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF548-EZKIT_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 CONFIG_EBIU_FCTLVAL=0x6
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -62,7 +63,7 @@
 CONFIG_IRTTY_SIR=m
 CONFIG_BFIN_SIR=m
 CONFIG_BFIN_SIR3=y
-CONFIG_LIB80211=m
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
@@ -92,6 +93,7 @@
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 CONFIG_INPUT_FF_MEMLESS=m
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF561-ACVILON_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF561-ACVILON_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF561-ACVILON_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF561-ACVILON_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 # CONFIG_EVENTFD is not set
 # CONFIG_AIO is not set
 CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_LBDAF is not set
@@ -44,6 +45,7 @@
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -71,6 +73,7 @@
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -147,5 +150,4 @@
 CONFIG_DEBUG_MMRS=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BF561-EZKIT_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BF561-EZKIT_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BF561-EZKIT_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BF561-EZKIT_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 CONFIG_BANK_3=0xAAC2
 CONFIG_BINFMT_FLAT=y
 CONFIG_BINFMT_ZFLAT=y
+CONFIG_PM=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/BlackStamp_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/BlackStamp_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/BlackStamp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/BlackStamp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 CONFIG_IP_PNP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -63,6 +64,7 @@
 CONFIG_SMC91X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
@@ -104,5 +106,4 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF527_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF527_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF527_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF527_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -50,6 +50,7 @@
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -70,9 +71,9 @@
 CONFIG_NETDEVICES=y
 CONFIG_NET_ETHERNET=y
 CONFIG_BFIN_MAC=y
-CONFIG_BFIN_MAC_RMII=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -124,7 +125,6 @@
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF533_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF533_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF533_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF533_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -47,6 +48,7 @@
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -72,7 +74,6 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=y
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF537E_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF537E_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF537E_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF537E_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -48,6 +48,7 @@
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -65,6 +66,7 @@
 CONFIG_BFIN_MAC=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -99,7 +101,6 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF537U_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF537U_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF537U_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF537U_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,7 @@
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -59,6 +60,7 @@
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -90,7 +92,6 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF548_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF548_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF548_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF548_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -49,6 +49,7 @@
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
@@ -71,6 +72,7 @@
 CONFIG_SMSC911X=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 CONFIG_INPUT_EVBUG=m
@@ -167,7 +169,6 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF561_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF561_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/CM-BF561_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/CM-BF561_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -48,6 +48,7 @@
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -67,6 +68,7 @@
 CONFIG_SMSC911X=m
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -99,7 +101,6 @@
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=m
 CONFIG_CRC_ITU_T=y
 CONFIG_CRC7=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/H8606_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/H8606_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/H8606_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/H8606_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 CONFIG_IRCOMM=m
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -50,6 +51,7 @@
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -84,4 +86,3 @@
 CONFIG_NLS=m
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/IP0X_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/IP0X_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/IP0X_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/IP0X_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,7 @@
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
 CONFIG_IP_NF_MANGLE=y
+# CONFIG_WIRELESS is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
@@ -60,6 +61,7 @@
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
@@ -89,5 +91,4 @@
 CONFIG_NLS_ISO8859_1=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRC_CCITT=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/PNAV-10_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/PNAV-10_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/PNAV-10_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/PNAV-10_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 # CONFIG_LBDAF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BF537=y
 CONFIG_IRQ_TIMER0=12
@@ -107,7 +108,6 @@
 # CONFIG_DEBUG_HUNT_FOR_ZERO is not set
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 # CONFIG_ACCESS_CHECK is not set
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/SRV1_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/SRV1_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/SRV1_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/SRV1_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 CONFIG_IRCOMM=m
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRTTY_SIR=m
+# CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -51,6 +52,7 @@
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_KEYBOARD is not set
@@ -85,4 +87,3 @@
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/TCM-BF518_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/TCM-BF518_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/TCM-BF518_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/TCM-BF518_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -128,7 +128,6 @@
 CONFIG_DEBUG_BFIN_HWTRACE_COMPRESSION_ONE=y
 CONFIG_EARLY_PRINTK=y
 CONFIG_CPLB_INFO=y
-CONFIG_SECURITY=y
 CONFIG_CRYPTO=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRC_CCITT=m
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/configs/TCM-BF537_defconfig linux-libre-2.6.37-gnu/arch/blackfin/configs/TCM-BF537_defconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/configs/TCM-BF537_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/configs/TCM-BF537_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
@@ -57,6 +58,7 @@
 CONFIG_BFIN_MAC=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin5xx_spi.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin5xx_spi.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin5xx_spi.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin5xx_spi.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,26 +11,17 @@
 
 #define MIN_SPI_BAUD_VAL	2
 
-#define SPI_READ              0
-#define SPI_WRITE             1
-
-#define SPI_CTRL_OFF            0x0
-#define SPI_FLAG_OFF            0x4
-#define SPI_STAT_OFF            0x8
-#define SPI_TXBUFF_OFF          0xc
-#define SPI_RXBUFF_OFF          0x10
-#define SPI_BAUD_OFF            0x14
-#define SPI_SHAW_OFF            0x18
-
-
 #define BIT_CTL_ENABLE      0x4000
 #define BIT_CTL_OPENDRAIN   0x2000
 #define BIT_CTL_MASTER      0x1000
-#define BIT_CTL_POLAR       0x0800
-#define BIT_CTL_PHASE       0x0400
-#define BIT_CTL_BITORDER    0x0200
+#define BIT_CTL_CPOL        0x0800
+#define BIT_CTL_CPHA        0x0400
+#define BIT_CTL_LSBF        0x0200
 #define BIT_CTL_WORDSIZE    0x0100
-#define BIT_CTL_MISOENABLE  0x0020
+#define BIT_CTL_EMISO       0x0020
+#define BIT_CTL_PSSE        0x0010
+#define BIT_CTL_GM          0x0008
+#define BIT_CTL_SZ          0x0004
 #define BIT_CTL_RXMOD       0x0000
 #define BIT_CTL_TXMOD       0x0001
 #define BIT_CTL_TIMOD_DMA_TX 0x0003
@@ -50,61 +41,28 @@
 #define BIT_STU_SENDOVER    0x0001
 #define BIT_STU_RECVFULL    0x0020
 
-#define CFG_SPI_ENABLE      1
-#define CFG_SPI_DISABLE     0
-
-#define CFG_SPI_OUTENABLE   1
-#define CFG_SPI_OUTDISABLE  0
-
-#define CFG_SPI_ACTLOW      1
-#define CFG_SPI_ACTHIGH     0
-
-#define CFG_SPI_PHASESTART  1
-#define CFG_SPI_PHASEMID    0
-
-#define CFG_SPI_MASTER      1
-#define CFG_SPI_SLAVE       0
-
-#define CFG_SPI_SENELAST    0
-#define CFG_SPI_SENDZERO    1
-
-#define CFG_SPI_RCVFLUSH    1
-#define CFG_SPI_RCVDISCARD  0
-
-#define CFG_SPI_LSBFIRST    1
-#define CFG_SPI_MSBFIRST    0
-
-#define CFG_SPI_WORDSIZE16  1
-#define CFG_SPI_WORDSIZE8   0
-
-#define CFG_SPI_MISOENABLE   1
-#define CFG_SPI_MISODISABLE  0
-
-#define CFG_SPI_READ      0x00
-#define CFG_SPI_WRITE     0x01
-#define CFG_SPI_DMAREAD   0x02
-#define CFG_SPI_DMAWRITE  0x03
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
 
-#define CFG_SPI_CSCLEARALL  0
-#define CFG_SPI_CHIPSEL1    1
-#define CFG_SPI_CHIPSEL2    2
-#define CFG_SPI_CHIPSEL3    3
-#define CFG_SPI_CHIPSEL4    4
-#define CFG_SPI_CHIPSEL5    5
-#define CFG_SPI_CHIPSEL6    6
-#define CFG_SPI_CHIPSEL7    7
+/*
+ * bfin spi registers layout
+ */
+struct bfin_spi_regs {
+	__BFP(ctl);
+	__BFP(flg);
+	__BFP(stat);
+	__BFP(tdbr);
+	__BFP(rdbr);
+	__BFP(baud);
+	__BFP(shadow);
+};
 
-#define CFG_SPI_CS1VALUE    1
-#define CFG_SPI_CS2VALUE    2
-#define CFG_SPI_CS3VALUE    3
-#define CFG_SPI_CS4VALUE    4
-#define CFG_SPI_CS5VALUE    5
-#define CFG_SPI_CS6VALUE    6
-#define CFG_SPI_CS7VALUE    7
+#undef __BFP
 
-#define CMD_SPI_SET_BAUDRATE  2
-#define CMD_SPI_GET_SYSTEMCLOCK   25
-#define CMD_SPI_SET_WRITECONTINUOUS     26
+#define MAX_CTRL_CS          8  /* cs in spi controller */
 
 /* device.platform_data for SSP controller devices */
 struct bfin5xx_spi_master {
@@ -120,9 +78,7 @@
 	u16 ctl_reg;
 	u8 enable_dma;
 	u8 bits_per_word;
-	u8 cs_change_per_word;
 	u16 cs_chg_udelay; /* Some devices require 16-bit delays */
-	u32 cs_gpio;
 	/* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */
 	u16 idle_tx_val;
 	u8 pio_interrupt; /* Enable spi data irq */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_can.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_can.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_can.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_can.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,7 @@
 };
 
 struct bfin_can_channel_regs {
+	/* data[0,2,4,6] -> data{0,1,2,3} while data[1,3,5,7] is padding */
 	u16 data[8];
 	__BFP(dlc);
 	__BFP(tsv);
@@ -83,16 +84,18 @@
 	__BFP(gif);           /* offset 0x9c */
 	__BFP(control);       /* offset 0xa0 */
 	__BFP(intr);          /* offset 0xa4 */
-	u32 __pad3[1];
+	__BFP(version);       /* offset 0xa8 */
 	__BFP(mbtd);          /* offset 0xac */
 	__BFP(ewr);           /* offset 0xb0 */
 	__BFP(esr);           /* offset 0xb4 */
-	u32 __pad4[2];
+	u32 __pad3[2];
 	__BFP(ucreg);         /* offset 0xc0 */
 	__BFP(uccnt);         /* offset 0xc4 */
 	__BFP(ucrc);          /* offset 0xc8 */
 	__BFP(uccnf);         /* offset 0xcc */
-	u32 __pad5[12];
+	u32 __pad4[1];
+	__BFP(version2);      /* offset 0xd4 */
+	u32 __pad5[10];
 
 	/*
 	 * channel(mailbox) mask and message registers
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_ppi.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_ppi.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_ppi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_ppi.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,53 @@
+/*
+ * bfin_ppi.h - interface to Blackfin PPIs
+ *
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_PPI_H__
+#define __ASM_BFIN_PPI_H__
+
+#include <linux/types.h>
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin ppi registers layout
+ */
+struct bfin_ppi_regs {
+	__BFP(control);
+	__BFP(status);
+	__BFP(count);
+	__BFP(delay);
+	__BFP(frame);
+};
+
+/*
+ * bfin eppi registers layout
+ */
+struct bfin_eppi_regs {
+	__BFP(status);
+	__BFP(hcount);
+	__BFP(hdelay);
+	__BFP(vcount);
+	__BFP(vdelay);
+	__BFP(frame);
+	__BFP(line);
+	__BFP(clkdiv);
+	u32 control;
+	u32 fs1w_hbl;
+	u32 fs1p_avpl;
+	u32 fs2w_lvb;
+	u32 fs2p_lavf;
+	u32 clip;
+};
+
+#undef __BFP
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_twi.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_twi.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/bfin_twi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/bfin_twi.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,45 @@
+/*
+ * bfin_twi.h - interface to Blackfin TWIs
+ *
+ * Copyright 2005-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_TWI_H__
+#define __ASM_BFIN_TWI_H__
+
+#include <linux/types.h>
+
+/*
+ * All Blackfin system MMRs are padded to 32bits even if the register
+ * itself is only 16bits.  So use a helper macro to streamline this.
+ */
+#define __BFP(m) u16 m; u16 __pad_##m
+
+/*
+ * bfin twi registers layout
+ */
+struct bfin_twi_regs {
+	__BFP(clkdiv);
+	__BFP(control);
+	__BFP(slave_ctl);
+	__BFP(slave_stat);
+	__BFP(slave_addr);
+	__BFP(master_ctl);
+	__BFP(master_stat);
+	__BFP(master_addr);
+	__BFP(int_stat);
+	__BFP(int_mask);
+	__BFP(fifo_ctl);
+	__BFP(fifo_stat);
+	u32 __pad[20];
+	__BFP(xmt_data8);
+	__BFP(xmt_data16);
+	__BFP(rcv_data8);
+	__BFP(rcv_data16);
+};
+
+#undef __BFP
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/cachectl.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/cachectl.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/cachectl.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/cachectl.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+/*
+ * based on the mips/cachectl.h
+ *
+ * Copyright 2010 Analog Devices Inc.
+ * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef	_ASM_CACHECTL
+#define	_ASM_CACHECTL
+
+/*
+ * Options for cacheflush system call
+ */
+#define	ICACHE	(1<<0)		/* flush instruction cache        */
+#define	DCACHE	(1<<1)		/* writeback and flush data cache */
+#define	BCACHE	(ICACHE|DCACHE)	/* flush both caches              */
+
+#endif	/* _ASM_CACHECTL */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/cdef_LPBlackfin.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/cdef_LPBlackfin.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/cdef_LPBlackfin.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/cdef_LPBlackfin.h	2011-01-04 19:50:19.000000000 -0500
@@ -172,16 +172,19 @@
 #define bfin_write_ICPLB_DATA14(val)         bfin_write32(ICPLB_DATA14,val)
 #define bfin_read_ICPLB_DATA15()             bfin_read32(ICPLB_DATA15)
 #define bfin_write_ICPLB_DATA15(val)         bfin_write32(ICPLB_DATA15,val)
-#define bfin_read_ITEST_COMMAND()            bfin_read32(ITEST_COMMAND)
 #define bfin_write_ITEST_COMMAND(val)        bfin_write32(ITEST_COMMAND,val)
 #if 0
 #define ITEST_INDEX            0xFFE01304   /* Instruction Test Index Register */
 #endif
-#define bfin_read_ITEST_DATA0()              bfin_read32(ITEST_DATA0)
 #define bfin_write_ITEST_DATA0(val)          bfin_write32(ITEST_DATA0,val)
-#define bfin_read_ITEST_DATA1()              bfin_read32(ITEST_DATA1)
 #define bfin_write_ITEST_DATA1(val)          bfin_write32(ITEST_DATA1,val)
 
+#if !ANOMALY_05000481
+#define bfin_read_ITEST_COMMAND()            bfin_read32(ITEST_COMMAND)
+#define bfin_read_ITEST_DATA0()              bfin_read32(ITEST_DATA0)
+#define bfin_read_ITEST_DATA1()              bfin_read32(ITEST_DATA1)
+#endif
+
 /* Event/Interrupt Registers*/
 
 #define bfin_read_EVT0()                     bfin_read32(EVT0)
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/entry.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/entry.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/entry.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/entry.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,14 +15,6 @@
 #define	LFLUSH_I_AND_D	0x00000808
 #define	LSIGTRAP	5
 
-/* process bits for task_struct.flags */
-#define	PF_TRACESYS_OFF	3
-#define	PF_TRACESYS_BIT	5
-#define	PF_PTRACED_OFF	3
-#define	PF_PTRACED_BIT	4
-#define	PF_DTRACE_OFF	1
-#define	PF_DTRACE_BIT	5
-
 /*
  * NOTE!  The single-stepping code assumes that all interrupt handlers
  * start by saving SYSCFG on the stack with their first instruction.
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/ipipe.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/ipipe.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/ipipe.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/ipipe.h	2011-01-04 19:50:19.000000000 -0500
@@ -49,7 +49,7 @@
 #define prepare_arch_switch(next)		\
 do {						\
 	ipipe_schedule_notify(current, next);	\
-	local_irq_disable_hw();			\
+	hard_local_irq_disable();			\
 } while (0)
 
 #define task_hijacked(p)						\
@@ -57,7 +57,7 @@
 		int __x__ = __ipipe_root_domain_p;			\
 		__clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
 		if (__x__)						\
-			local_irq_enable_hw();				\
+			hard_local_irq_enable();				\
 		!__x__;							\
 	})
 
@@ -167,7 +167,7 @@
 #define __ipipe_run_isr(ipd, irq)					\
 	do {								\
 		if (!__ipipe_pipeline_head_p(ipd))			\
-			local_irq_enable_hw();				\
+			hard_local_irq_enable();				\
 		if (ipd == ipipe_root_domain) {				\
 			if (unlikely(ipipe_virtual_irq_p(irq))) {	\
 				irq_enter();				\
@@ -183,7 +183,7 @@
 			__ipipe_run_irqtail();				\
 			__set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
 		}							\
-		local_irq_disable_hw();					\
+		hard_local_irq_disable();					\
 	} while (0)
 
 #define __ipipe_syscall_watched_p(p, sc)	\
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,6 +8,8 @@
 #ifndef __ASM_BFIN_IRQFLAGS_H__
 #define __ASM_BFIN_IRQFLAGS_H__
 
+#include <mach/blackfin.h>
+
 #ifdef CONFIG_SMP
 # include <asm/pda.h>
 # include <asm/processor.h>
@@ -31,54 +33,108 @@
 	return flags;
 }
 
-#ifdef CONFIG_IPIPE
-
-#include <linux/compiler.h>
-#include <linux/ipipe_base.h>
-#include <linux/ipipe_trace.h>
-
 #ifdef CONFIG_DEBUG_HWERR
 # define bfin_no_irqs 0x3f
 #else
 # define bfin_no_irqs 0x1f
 #endif
 
-#define raw_local_irq_disable()				\
-	do {						\
-		ipipe_check_context(ipipe_root_domain);	\
-		__ipipe_stall_root();			\
-		barrier();				\
-	} while (0)
+/*****************************************************************************/
+/*
+ * Hard, untraced CPU interrupt flag manipulation and access.
+ */
+static inline void __hard_local_irq_disable(void)
+{
+	bfin_cli();
+}
 
-#define raw_local_irq_enable()				\
-	do {						\
-		barrier();				\
-		ipipe_check_context(ipipe_root_domain);	\
-		__ipipe_unstall_root();			\
-	} while (0)
+static inline void __hard_local_irq_enable(void)
+{
+	bfin_sti(bfin_irq_flags);
+}
 
-#define raw_local_save_flags_ptr(x)					\
-	do {								\
-		*(x) = __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags; \
-	} while (0)
+static inline unsigned long hard_local_save_flags(void)
+{
+	return bfin_read_IMASK();
+}
 
-#define raw_local_save_flags(x)		raw_local_save_flags_ptr(&(x))
+static inline unsigned long __hard_local_irq_save(void)
+{
+	unsigned long flags;
+	flags = bfin_cli();
+#ifdef CONFIG_DEBUG_HWERR
+	bfin_sti(0x3f);
+#endif
+	return flags;
+}
 
-#define raw_irqs_disabled_flags(x)	((x) == bfin_no_irqs)
+static inline int hard_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & ~0x3f) == 0;
+}
 
-#define raw_local_irq_save_ptr(x)					\
-	do {								\
-		*(x) = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags; \
-		barrier();						\
-	} while (0)
+static inline int hard_irqs_disabled(void)
+{
+	unsigned long flags = hard_local_save_flags();
+	return hard_irqs_disabled_flags(flags);
+}
 
-#define raw_local_irq_save(x)				\
-	do {						\
-		ipipe_check_context(ipipe_root_domain);	\
-		raw_local_irq_save_ptr(&(x));		\
-	} while (0)
+static inline void __hard_local_irq_restore(unsigned long flags)
+{
+	if (!hard_irqs_disabled_flags(flags))
+		__hard_local_irq_enable();
+}
 
-static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
+/*****************************************************************************/
+/*
+ * Interrupt pipe handling.
+ */
+#ifdef CONFIG_IPIPE
+
+#include <linux/compiler.h>
+#include <linux/ipipe_base.h>
+#include <linux/ipipe_trace.h>
+
+/*
+ * Interrupt pipe interface to linux/irqflags.h.
+ */
+static inline void arch_local_irq_disable(void)
+{
+	ipipe_check_context(ipipe_root_domain);
+	__ipipe_stall_root();
+	barrier();
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	barrier();
+	ipipe_check_context(ipipe_root_domain);
+	__ipipe_unstall_root();
+}
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	return __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags;
+}
+
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags == bfin_no_irqs;
+}
+
+static inline void arch_local_irq_save_ptr(unsigned long *_flags)
+{
+	x = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags;
+	barrier();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	ipipe_check_context(ipipe_root_domain);
+	return __hard_local_irq_save();
+}
+
+static inline unsigned long arch_mangle_irq_bits(int virt, unsigned long real)
 {
 	/*
 	 * Merge virtual and real interrupt mask bits into a single
@@ -87,130 +143,79 @@
 	return (real & ~(1 << 31)) | ((virt != 0) << 31);
 }
 
-static inline int raw_demangle_irq_bits(unsigned long *x)
+static inline int arch_demangle_irq_bits(unsigned long *x)
 {
 	int virt = (*x & (1 << 31)) != 0;
 	*x &= ~(1L << 31);
 	return virt;
 }
 
-static inline void local_irq_disable_hw_notrace(void)
+/*
+ * Interface to various arch routines that may be traced.
+ */
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+static inline void hard_local_irq_disable(void)
 {
-	bfin_cli();
+	if (!hard_irqs_disabled()) {
+		__hard_local_irq_disable();
+		ipipe_trace_begin(0x80000000);
+	}
 }
 
-static inline void local_irq_enable_hw_notrace(void)
+static inline void hard_local_irq_enable(void)
 {
-	bfin_sti(bfin_irq_flags);
+	if (hard_irqs_disabled()) {
+		ipipe_trace_end(0x80000000);
+		__hard_local_irq_enable();
+	}
 }
 
-#define local_save_flags_hw(flags)			\
-	do {						\
-		(flags) = bfin_read_IMASK();		\
-	} while (0)
-
-#define irqs_disabled_flags_hw(flags) (((flags) & ~0x3f) == 0)
-
-#define irqs_disabled_hw()			\
-	({					\
-	unsigned long flags;			\
-	local_save_flags_hw(flags);		\
-	irqs_disabled_flags_hw(flags);		\
-	})
-
-static inline void local_irq_save_ptr_hw(unsigned long *flags)
+static inline unsigned long hard_local_irq_save(void)
 {
-	*flags = bfin_cli();
-#ifdef CONFIG_DEBUG_HWERR
-	bfin_sti(0x3f);
-#endif
+	unsigned long flags = hard_local_save_flags();
+	if (!hard_irqs_disabled_flags(flags)) {
+		__hard_local_irq_disable();
+		ipipe_trace_begin(0x80000001);
+	}
+	return flags;
 }
 
-#define local_irq_save_hw_notrace(flags)		\
-	do {						\
-		local_irq_save_ptr_hw(&(flags));	\
-	} while (0)
-
-static inline void local_irq_restore_hw_notrace(unsigned long flags)
+static inline void hard_local_irq_restore(unsigned long flags)
 {
-	if (!irqs_disabled_flags_hw(flags))
-		local_irq_enable_hw_notrace();
+	if (!hard_irqs_disabled_flags(flags)) {
+		ipipe_trace_end(0x80000001);
+		__hard_local_irq_enable();
+	}
 }
 
-#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
-# define local_irq_disable_hw()				\
-	do {						\
-		if (!irqs_disabled_hw()) {		\
-			local_irq_disable_hw_notrace();	\
-			ipipe_trace_begin(0x80000000);	\
-		}					\
-	} while (0)
-# define local_irq_enable_hw()				\
-	do {						\
-		if (irqs_disabled_hw()) {		\
-			ipipe_trace_end(0x80000000);	\
-			local_irq_enable_hw_notrace();	\
-		}					\
-	} while (0)
-# define local_irq_save_hw(flags)			\
-	do {						\
-		local_save_flags_hw(flags);		\
-		if (!irqs_disabled_flags_hw(flags)) {	\
-			local_irq_disable_hw_notrace();	\
-			ipipe_trace_begin(0x80000001);	\
-		}					\
-	} while (0)
-# define local_irq_restore_hw(flags)			\
-	do {						\
-		if (!irqs_disabled_flags_hw(flags)) {	\
-			ipipe_trace_end(0x80000001);	\
-			local_irq_enable_hw_notrace();	\
-		}					\
-	} while (0)
 #else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
-# define local_irq_disable_hw()		local_irq_disable_hw_notrace()
-# define local_irq_enable_hw()		local_irq_enable_hw_notrace()
-# define local_irq_save_hw(flags)	local_irq_save_hw_notrace(flags)
-# define local_irq_restore_hw(flags)	local_irq_restore_hw_notrace(flags)
+# define hard_local_irq_disable()	__hard_local_irq_disable()
+# define hard_local_irq_enable()	__hard_local_irq_enable()
+# define hard_local_irq_save()		__hard_local_irq_save()
+# define hard_local_irq_restore(flags)	__hard_local_irq_restore(flags)
 #endif /* !CONFIG_IPIPE_TRACE_IRQSOFF */
 
 #else /* CONFIG_IPIPE */
 
-static inline void raw_local_irq_disable(void)
-{
-	bfin_cli();
-}
-static inline void raw_local_irq_enable(void)
-{
-	bfin_sti(bfin_irq_flags);
-}
-
-#define raw_local_save_flags(flags) do { (flags) = bfin_read_IMASK(); } while (0)
-
-#define raw_irqs_disabled_flags(flags) (((flags) & ~0x3f) == 0)
+/*
+ * Direct interface to linux/irqflags.h.
+ */
+#define arch_local_save_flags()		hard_local_save_flags()
+#define arch_local_irq_save(flags)	__hard_local_irq_save()
+#define arch_local_irq_restore(flags)	__hard_local_irq_restore(flags)
+#define arch_local_irq_enable()		__hard_local_irq_enable()
+#define arch_local_irq_disable()	__hard_local_irq_disable()
+#define arch_irqs_disabled_flags(flags)	hard_irqs_disabled_flags(flags)
+#define arch_irqs_disabled()		hard_irqs_disabled()
 
-static inline unsigned long __raw_local_irq_save(void)
-{
-	unsigned long flags = bfin_cli();
-#ifdef CONFIG_DEBUG_HWERR
-	bfin_sti(0x3f);
-#endif
-	return flags;
-}
-#define raw_local_irq_save(flags) do { (flags) = __raw_local_irq_save(); } while (0)
+/*
+ * Interface to various arch routines that may be traced.
+ */
+#define hard_local_irq_save()		__hard_local_irq_save()
+#define hard_local_irq_restore(flags)	__hard_local_irq_restore(flags)
+#define hard_local_irq_enable()		__hard_local_irq_enable()
+#define hard_local_irq_disable()	__hard_local_irq_disable()
 
-#define local_irq_save_hw(flags)	raw_local_irq_save(flags)
-#define local_irq_restore_hw(flags)	raw_local_irq_restore(flags)
-#define local_irq_enable_hw()		raw_local_irq_enable()
-#define local_irq_disable_hw()		raw_local_irq_disable()
-#define irqs_disabled_hw()		irqs_disabled()
 
 #endif /* !CONFIG_IPIPE */
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
-	if (!raw_irqs_disabled_flags(flags))
-		raw_local_irq_enable();
-}
-
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/Kbuild linux-libre-2.6.37-gnu/arch/blackfin/include/asm/Kbuild
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,5 @@
 include include/asm-generic/Kbuild.asm
 
 header-y += bfin_sport.h
+header-y += cachectl.h
 header-y += fixed_code.h
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/mmu_context.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/mmu_context.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/mmu_context.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/mmu_context.h	2011-01-04 19:50:19.000000000 -0500
@@ -97,8 +97,8 @@
 }
 
 #ifdef CONFIG_IPIPE
-#define lock_mm_switch(flags)	local_irq_save_hw_cond(flags)
-#define unlock_mm_switch(flags)	local_irq_restore_hw_cond(flags)
+#define lock_mm_switch(flags)	flags = hard_local_irq_save_cond()
+#define unlock_mm_switch(flags)	hard_local_irq_restore_cond(flags)
 #else
 #define lock_mm_switch(flags)	do { (void)(flags); } while (0)
 #define unlock_mm_switch(flags)	do { (void)(flags); } while (0)
@@ -205,9 +205,9 @@
 }
 
 #define ipipe_mm_switch_protect(flags)		\
-	local_irq_save_hw_cond(flags)
+	flags = hard_local_irq_save_cond()
 
 #define ipipe_mm_switch_unprotect(flags)	\
-	local_irq_restore_hw_cond(flags)
+	hard_local_irq_restore_cond(flags)
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -113,6 +113,9 @@
 /* common code demands this function */
 #define ptrace_disable(child) user_disable_single_step(child)
 
+extern int is_user_addr_valid(struct task_struct *child,
+			      unsigned long start, unsigned long len);
+
 /*
  * Get the address of the live pt_regs for the specified task.
  * These are saved onto the top kernel stack when the process
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/serial.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/serial.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/serial.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,2 +1 @@
 #include <asm-generic/serial.h>
-#define SERIAL_EXTRA_IRQ_FLAGS IRQF_TRIGGER_HIGH
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/system.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -117,7 +117,7 @@
 	unsigned long tmp = 0;
 	unsigned long flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	switch (size) {
 	case 1:
@@ -139,7 +139,7 @@
 			 : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
 		break;
 	}
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 	return tmp;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/include/asm/unistd.h linux-libre-2.6.37-gnu/arch/blackfin/include/asm/unistd.h
--- linux-libre-2.6.36-gnu/arch/blackfin/include/asm/unistd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/include/asm/unistd.h	2011-01-04 19:50:19.000000000 -0500
@@ -392,8 +392,9 @@
 #define __NR_fanotify_init	371
 #define __NR_fanotify_mark	372
 #define __NR_prlimit64		373
+#define __NR_cacheflush		374
 
-#define __NR_syscall		374
+#define __NR_syscall		375
 #define NR_syscalls		__NR_syscall
 
 /* Old optional stuff no one actually uses */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/Kconfig linux-libre-2.6.37-gnu/arch/blackfin/Kconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Blackfin Kernel Configuration"
-
 config SYMBOL_PREFIX
 	string
 	default "_"
@@ -300,7 +293,7 @@
 
 config BF_REV_0_2
 	bool "0.2"
-	depends on (BF52x || BF537 || BF536 || BF534 || (BF54x && !BF54xM))
+	depends on (BF51x || BF52x || BF537 || BF536 || BF534 || (BF54x && !BF54xM))
 
 config BF_REV_0_3
 	bool "0.3"
@@ -356,7 +349,7 @@
 
 config MEM_MT48LC32M16A2TG_75
 	bool
-	depends on (BFIN527_EZKIT || BFIN527_EZKIT_V2 || BFIN532_IP0X || BLACKSTAMP)
+	depends on (BFIN527_EZKIT || BFIN527_EZKIT_V2 || BFIN532_IP0X || BLACKSTAMP || BFIN527_AD7160EVAL)
 	default y
 
 config MEM_MT48H32M16LFCJ_75
@@ -426,6 +419,7 @@
 	default "25000000" # most people use this
 	default "27000000" if BFIN533_EZKIT
 	default "30000000" if BFIN561_EZKIT
+	default "24000000" if BFIN527_AD7160EVAL
 	help
 	  The frequency of CLKIN crystal oscillator on the board in Hz.
 	  Warning: This value should match the crystal on the board. Otherwise,
@@ -463,6 +457,7 @@
 	default "20" if (BFIN537_BLUETECHNIX_CM_E || BFIN537_BLUETECHNIX_CM_U || BFIN527_BLUETECHNIX_CM || BFIN561_BLUETECHNIX_CM)
 	default "20" if BFIN561_EZKIT
 	default "16" if (H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD || BFIN518F_EZBRD)
+	default "25" if BFIN527_AD7160EVAL
 	help
 	  This controls the frequency of the on-chip PLL. This can be between 1 and 64.
 	  PLL Frequency = (Crystal Frequency) * (this setting)
@@ -926,6 +921,12 @@
 
 endchoice
 
+# Common code uses "ROMKERNEL" or "XIP_KERNEL", so define both
+config XIP_KERNEL
+	bool
+	default y
+	depends on ROMKERNEL
+
 source "mm/Kconfig"
 
 config BFIN_GPTIMERS
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/Kconfig.debug linux-libre-2.6.37-gnu/arch/blackfin/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/blackfin/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -102,17 +102,6 @@
 
 endchoice
 
-config DEBUG_ICACHE_CHECK
-	bool "Check Instruction cache coherency"
-	depends on DEBUG_KERNEL
-	depends on DEBUG_HWERR
-	help
-	  Say Y here if you are getting weird unexplained errors. This will
-	  ensure that icache is what SDRAM says it should be by doing a
-	  byte wise comparison between SDRAM and instruction cache. This
-	  also relocates the irq_panic() function to L1 memory, (which is
-	  un-cached).
-
 config DEBUG_HUNT_FOR_ZERO
 	bool "Catch NULL pointer reads/writes"
 	default y
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/bfin_gpio.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/bfin_gpio.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/bfin_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/bfin_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * GPIO Abstraction Layer
  *
- * Copyright 2006-2009 Analog Devices Inc.
+ * Copyright 2006-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later
  */
@@ -215,82 +215,91 @@
 }
 
 #ifdef BF537_FAMILY
-static struct {
-	unsigned short res;
-	unsigned short offset;
-} port_mux_lut[] = {
-	{.res = P_PPI0_D13, .offset = 11},
-	{.res = P_PPI0_D14, .offset = 11},
-	{.res = P_PPI0_D15, .offset = 11},
-	{.res = P_SPORT1_TFS, .offset = 11},
-	{.res = P_SPORT1_TSCLK, .offset = 11},
-	{.res = P_SPORT1_DTPRI, .offset = 11},
-	{.res = P_PPI0_D10, .offset = 10},
-	{.res = P_PPI0_D11, .offset = 10},
-	{.res = P_PPI0_D12, .offset = 10},
-	{.res = P_SPORT1_RSCLK, .offset = 10},
-	{.res = P_SPORT1_RFS, .offset = 10},
-	{.res = P_SPORT1_DRPRI, .offset = 10},
-	{.res = P_PPI0_D8, .offset = 9},
-	{.res = P_PPI0_D9, .offset = 9},
-	{.res = P_SPORT1_DRSEC, .offset = 9},
-	{.res = P_SPORT1_DTSEC, .offset = 9},
-	{.res = P_TMR2, .offset = 8},
-	{.res = P_PPI0_FS3, .offset = 8},
-	{.res = P_TMR3, .offset = 7},
-	{.res = P_SPI0_SSEL4, .offset = 7},
-	{.res = P_TMR4, .offset = 6},
-	{.res = P_SPI0_SSEL5, .offset = 6},
-	{.res = P_TMR5, .offset = 5},
-	{.res = P_SPI0_SSEL6, .offset = 5},
-	{.res = P_UART1_RX, .offset = 4},
-	{.res = P_UART1_TX, .offset = 4},
-	{.res = P_TMR6, .offset = 4},
-	{.res = P_TMR7, .offset = 4},
-	{.res = P_UART0_RX, .offset = 3},
-	{.res = P_UART0_TX, .offset = 3},
-	{.res = P_DMAR0, .offset = 3},
-	{.res = P_DMAR1, .offset = 3},
-	{.res = P_SPORT0_DTSEC, .offset = 1},
-	{.res = P_SPORT0_DRSEC, .offset = 1},
-	{.res = P_CAN0_RX, .offset = 1},
-	{.res = P_CAN0_TX, .offset = 1},
-	{.res = P_SPI0_SSEL7, .offset = 1},
-	{.res = P_SPORT0_TFS, .offset = 0},
-	{.res = P_SPORT0_DTPRI, .offset = 0},
-	{.res = P_SPI0_SSEL2, .offset = 0},
-	{.res = P_SPI0_SSEL3, .offset = 0},
+static const s8 port_mux[] = {
+	[GPIO_PF0] = 3,
+	[GPIO_PF1] = 3,
+	[GPIO_PF2] = 4,
+	[GPIO_PF3] = 4,
+	[GPIO_PF4] = 5,
+	[GPIO_PF5] = 6,
+	[GPIO_PF6] = 7,
+	[GPIO_PF7] = 8,
+	[GPIO_PF8 ... GPIO_PF15] = -1,
+	[GPIO_PG0 ... GPIO_PG7] = -1,
+	[GPIO_PG8] = 9,
+	[GPIO_PG9] = 9,
+	[GPIO_PG10] = 10,
+	[GPIO_PG11] = 10,
+	[GPIO_PG12] = 10,
+	[GPIO_PG13] = 11,
+	[GPIO_PG14] = 11,
+	[GPIO_PG15] = 11,
+	[GPIO_PH0 ... GPIO_PH15] = -1,
+	[PORT_PJ0 ... PORT_PJ3] = -1,
+	[PORT_PJ4] = 1,
+	[PORT_PJ5] = 1,
+	[PORT_PJ6 ... PORT_PJ9] = -1,
+	[PORT_PJ10] = 0,
+	[PORT_PJ11] = 0,
 };
 
-static void portmux_setup(unsigned short per)
+static int portmux_group_check(unsigned short per)
 {
-	u16 y, offset, muxreg;
+	u16 ident = P_IDENT(per);
 	u16 function = P_FUNCT2MUX(per);
+	s8 offset = port_mux[ident];
+	u16 m, pmux, pfunc;
 
-	for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) {
-		if (port_mux_lut[y].res == per) {
-
-			/* SET PORTMUX REG */
-
-			offset = port_mux_lut[y].offset;
-			muxreg = bfin_read_PORT_MUX();
+	if (offset < 0)
+		return 0;
 
-			if (offset != 1)
-				muxreg &= ~(1 << offset);
-			else
-				muxreg &= ~(3 << 1);
+	pmux = bfin_read_PORT_MUX();
+	for (m = 0; m < ARRAY_SIZE(port_mux); ++m) {
+		if (m == ident)
+			continue;
+		if (port_mux[m] != offset)
+			continue;
+		if (!is_reserved(peri, m, 1))
+			continue;
 
-			muxreg |= (function << offset);
-			bfin_write_PORT_MUX(muxreg);
+		if (offset == 1)
+			pfunc = (pmux >> offset) & 3;
+		else
+			pfunc = (pmux >> offset) & 1;
+		if (pfunc != function) {
+			pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n",
+				ident, function, m, pfunc);
+			return -EINVAL;
 		}
 	}
+
+	return 0;
+}
+
+static void portmux_setup(unsigned short per)
+{
+	u16 ident = P_IDENT(per);
+	u16 function = P_FUNCT2MUX(per);
+	s8 offset = port_mux[ident];
+	u16 pmux;
+
+	if (offset == -1)
+		return;
+
+	pmux = bfin_read_PORT_MUX();
+	if (offset != 1)
+		pmux &= ~(1 << offset);
+	else
+		pmux &= ~(3 << 1);
+	pmux |= (function << offset);
+	bfin_write_PORT_MUX(pmux);
 }
 #elif defined(CONFIG_BF54x)
 inline void portmux_setup(unsigned short per)
 {
-	u32 pmux;
 	u16 ident = P_IDENT(per);
 	u16 function = P_FUNCT2MUX(per);
+	u32 pmux;
 
 	pmux = gpio_array[gpio_bank(ident)]->port_mux;
 
@@ -302,20 +311,54 @@
 
 inline u16 get_portmux(unsigned short per)
 {
-	u32 pmux;
 	u16 ident = P_IDENT(per);
-
-	pmux = gpio_array[gpio_bank(ident)]->port_mux;
-
+	u32 pmux = gpio_array[gpio_bank(ident)]->port_mux;
 	return (pmux >> (2 * gpio_sub_n(ident)) & 0x3);
 }
+static int portmux_group_check(unsigned short per)
+{
+	return 0;
+}
 #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
+static int portmux_group_check(unsigned short per)
+{
+	u16 ident = P_IDENT(per);
+	u16 function = P_FUNCT2MUX(per);
+	u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
+	u16 pin, gpiopin, pfunc;
+
+	for (pin = 0; pin < GPIO_BANKSIZE; ++pin) {
+		if (offset != pmux_offset[gpio_bank(ident)][pin])
+			continue;
+
+		gpiopin = gpio_bank(ident) * GPIO_BANKSIZE + pin;
+		if (gpiopin == ident)
+			continue;
+		if (!is_reserved(peri, gpiopin, 1))
+			continue;
+
+		pfunc = *port_mux[gpio_bank(ident)];
+		pfunc = (pfunc >> offset) & 3;
+		if (pfunc != function) {
+			pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n",
+				ident, function, gpiopin, pfunc);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 inline void portmux_setup(unsigned short per)
 {
-	u16 pmux, ident = P_IDENT(per), function = P_FUNCT2MUX(per);
+	u16 ident = P_IDENT(per);
+	u16 function = P_FUNCT2MUX(per);
 	u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
+	u16 pmux;
 
 	pmux = *port_mux[gpio_bank(ident)];
+	if  (((pmux >> offset) & 3) == function)
+		return;
 	pmux &= ~(3 << offset);
 	pmux |= (function & 3) << offset;
 	*port_mux[gpio_bank(ident)] = pmux;
@@ -323,6 +366,10 @@
 }
 #else
 # define portmux_setup(...)  do { } while (0)
+static int portmux_group_check(unsigned short per)
+{
+	return 0;
+}
 #endif
 
 #ifndef CONFIG_BF54x
@@ -349,13 +396,13 @@
 void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
 	unsigned long flags; \
-	local_irq_save_hw(flags); \
+	flags = hard_local_irq_save(); \
 	if (arg) \
 		gpio_array[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
 	else \
 		gpio_array[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
 	AWA_DUMMY_READ(name); \
-	local_irq_restore_hw(flags); \
+	hard_local_irq_restore(flags); \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
 
@@ -371,14 +418,14 @@
 { \
 	unsigned long flags; \
 	if (ANOMALY_05000311 || ANOMALY_05000323) \
-		local_irq_save_hw(flags); \
+		flags = hard_local_irq_save(); \
 	if (arg) \
 		gpio_array[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
 	else \
 		gpio_array[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
 	if (ANOMALY_05000311 || ANOMALY_05000323) { \
 		AWA_DUMMY_READ(name); \
-		local_irq_restore_hw(flags); \
+		hard_local_irq_restore(flags); \
 	} \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
@@ -391,11 +438,11 @@
 {
 	unsigned long flags;
 	if (ANOMALY_05000311 || ANOMALY_05000323)
-		local_irq_save_hw(flags);
+		flags = hard_local_irq_save();
 	gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
 	if (ANOMALY_05000311 || ANOMALY_05000323) {
 		AWA_DUMMY_READ(toggle);
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 	}
 }
 EXPORT_SYMBOL(set_gpio_toggle);
@@ -408,11 +455,11 @@
 { \
 	unsigned long flags; \
 	if (ANOMALY_05000311 || ANOMALY_05000323) \
-		local_irq_save_hw(flags); \
+		flags = hard_local_irq_save(); \
 	gpio_array[gpio_bank(gpio)]->name = arg; \
 	if (ANOMALY_05000311 || ANOMALY_05000323) { \
 		AWA_DUMMY_READ(name); \
-		local_irq_restore_hw(flags); \
+		hard_local_irq_restore(flags); \
 	} \
 } \
 EXPORT_SYMBOL(set_gpiop_ ## name);
@@ -433,11 +480,11 @@
 	unsigned long flags; \
 	unsigned short ret; \
 	if (ANOMALY_05000311 || ANOMALY_05000323) \
-		local_irq_save_hw(flags); \
+		flags = hard_local_irq_save(); \
 	ret = 0x01 & (gpio_array[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \
 	if (ANOMALY_05000311 || ANOMALY_05000323) { \
 		AWA_DUMMY_READ(name); \
-		local_irq_restore_hw(flags); \
+		hard_local_irq_restore(flags); \
 	} \
 	return ret; \
 } \
@@ -460,11 +507,11 @@
 	unsigned long flags; \
 	unsigned short ret; \
 	if (ANOMALY_05000311 || ANOMALY_05000323) \
-		local_irq_save_hw(flags); \
+		flags = hard_local_irq_save(); \
 	ret = (gpio_array[gpio_bank(gpio)]->name); \
 	if (ANOMALY_05000311 || ANOMALY_05000323) { \
 		AWA_DUMMY_READ(name); \
-		local_irq_restore_hw(flags); \
+		hard_local_irq_restore(flags); \
 	} \
 	return ret; \
 } \
@@ -525,14 +572,14 @@
 	if (check_gpio(gpio) < 0)
 		return -EINVAL;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	if (ctrl)
 		reserve(wakeup, gpio);
 	else
 		unreserve(wakeup, gpio);
 
 	set_gpio_maskb(gpio, ctrl);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return 0;
 }
@@ -690,7 +737,7 @@
 
 	BUG_ON(ident >= MAX_RESOURCES);
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	/* If a pin can be muxed as either GPIO or peripheral, make
 	 * sure it is not already a GPIO pin when we request it.
@@ -701,7 +748,7 @@
 		printk(KERN_ERR
 		       "%s: Peripheral %d is already reserved as GPIO by %s !\n",
 		       __func__, ident, get_label(ident));
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return -EBUSY;
 	}
 
@@ -730,18 +777,22 @@
 			printk(KERN_ERR
 			       "%s: Peripheral %d function %d is already reserved by %s !\n",
 			       __func__, ident, P_FUNCT2MUX(per), get_label(ident));
-			local_irq_restore_hw(flags);
+			hard_local_irq_restore(flags);
 			return -EBUSY;
 		}
 	}
 
+	if (unlikely(portmux_group_check(per))) {
+		hard_local_irq_restore(flags);
+		return -EBUSY;
+	}
  anyway:
 	reserve(peri, ident);
 
 	portmux_setup(per);
 	port_setup(ident, PERIPHERAL_USAGE);
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 	set_label(ident, label);
 
 	return 0;
@@ -780,10 +831,10 @@
 	if (!(per & P_DEFINED))
 		return;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (unlikely(!is_reserved(peri, ident, 0))) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return;
 	}
 
@@ -794,7 +845,7 @@
 
 	set_label(ident, "free");
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(peripheral_free);
 
@@ -828,7 +879,7 @@
 	if (check_gpio(gpio) < 0)
 		return -EINVAL;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	/*
 	 * Allow that the identical GPIO can
@@ -837,7 +888,7 @@
 	 */
 
 	if (cmp_label(gpio, label) == 0) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return 0;
 	}
 
@@ -846,7 +897,7 @@
 			dump_stack();
 		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
 		       gpio, get_label(gpio));
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return -EBUSY;
 	}
 	if (unlikely(is_reserved(peri, gpio, 1))) {
@@ -855,7 +906,7 @@
 		printk(KERN_ERR
 		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
 		       gpio, get_label(gpio));
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return -EBUSY;
 	}
 	if (unlikely(is_reserved(gpio_irq, gpio, 1))) {
@@ -871,7 +922,7 @@
 	reserve(gpio, gpio);
 	set_label(gpio, label);
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	port_setup(gpio, GPIO_USAGE);
 
@@ -888,13 +939,13 @@
 
 	might_sleep();
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (unlikely(!is_reserved(gpio, gpio, 0))) {
 		if (system_state == SYSTEM_BOOTING)
 			dump_stack();
 		gpio_error(gpio);
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return;
 	}
 
@@ -902,7 +953,7 @@
 
 	set_label(gpio, "free");
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(bfin_gpio_free);
 
@@ -913,7 +964,7 @@
 {
 	unsigned long flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	/*
 	 * Allow that the identical GPIO can
@@ -922,19 +973,19 @@
 	 */
 
 	if (cmp_label(gpio, label) == 0) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return 0;
 	}
 
 	if (unlikely(is_reserved(special_gpio, gpio, 1))) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
 		       gpio, get_label(gpio));
 
 		return -EBUSY;
 	}
 	if (unlikely(is_reserved(peri, gpio, 1))) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		printk(KERN_ERR
 		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
 		       gpio, get_label(gpio));
@@ -946,7 +997,7 @@
 	reserve(peri, gpio);
 
 	set_label(gpio, label);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 	port_setup(gpio, GPIO_USAGE);
 
 	return 0;
@@ -959,18 +1010,18 @@
 
 	might_sleep();
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (unlikely(!is_reserved(special_gpio, gpio, 0))) {
 		gpio_error(gpio);
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return;
 	}
 
 	unreserve(special_gpio, gpio);
 	unreserve(peri, gpio);
 	set_label(gpio, "free");
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(bfin_special_gpio_free);
 #endif
@@ -983,7 +1034,7 @@
 	if (check_gpio(gpio) < 0)
 		return -EINVAL;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (unlikely(is_reserved(peri, gpio, 1))) {
 		if (system_state == SYSTEM_BOOTING)
@@ -991,7 +1042,7 @@
 		printk(KERN_ERR
 		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
 		       gpio, get_label(gpio));
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return -EBUSY;
 	}
 	if (unlikely(is_reserved(gpio, gpio, 1)))
@@ -1002,7 +1053,7 @@
 	reserve(gpio_irq, gpio);
 	set_label(gpio, label);
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	port_setup(gpio, GPIO_USAGE);
 
@@ -1016,13 +1067,13 @@
 	if (check_gpio(gpio) < 0)
 		return;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (unlikely(!is_reserved(gpio_irq, gpio, 0))) {
 		if (system_state == SYSTEM_BOOTING)
 			dump_stack();
 		gpio_error(gpio);
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return;
 	}
 
@@ -1030,7 +1081,7 @@
 
 	set_label(gpio, "free");
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 static inline void __bfin_gpio_direction_input(unsigned gpio)
@@ -1052,10 +1103,10 @@
 		return -EINVAL;
 	}
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	__bfin_gpio_direction_input(gpio);
 	AWA_DUMMY_READ(inen);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return 0;
 }
@@ -1070,9 +1121,9 @@
 	port_setup(gpio, GPIO_USAGE);
 
 #ifdef CONFIG_BF54x
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	__bfin_gpio_direction_input(gpio);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 #endif
 }
 
@@ -1094,7 +1145,7 @@
 		return -EINVAL;
 	}
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
 	gpio_set_value(gpio, value);
@@ -1105,7 +1156,7 @@
 #endif
 
 	AWA_DUMMY_READ(dir);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return 0;
 }
@@ -1120,11 +1171,11 @@
 
 	if (unlikely(get_gpio_edge(gpio))) {
 		int ret;
-		local_irq_save_hw(flags);
+		flags = hard_local_irq_save();
 		set_gpio_edge(gpio, 0);
 		ret = get_gpio_data(gpio);
 		set_gpio_edge(gpio, 1);
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return ret;
 	} else
 		return get_gpio_data(gpio);
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/cplb-mpu/cplbmgr.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/cplb-mpu/cplbmgr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/cplb-mpu/cplbmgr.c	2011-01-04 19:50:19.000000000 -0500
@@ -318,7 +318,7 @@
 
 	nr_cplb_flush[cpu]++;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	_disable_icplb();
 	for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
 		icplb_tbl[cpu][i].data = 0;
@@ -332,7 +332,7 @@
 		bfin_write32(DCPLB_DATA0 + i * 4, 0);
 	}
 	_enable_dcplb();
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 }
 
@@ -348,7 +348,7 @@
 		return;
 	}
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	current_rwx_mask[cpu] = masks;
 
 	if (L2_LENGTH && addr >= L2_START && addr < L2_START + L2_LENGTH) {
@@ -373,5 +373,5 @@
 		addr += PAGE_SIZE;
 	}
 	_enable_dcplb();
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/ipipe.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/ipipe.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/ipipe.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/ipipe.c	2011-01-04 19:50:19.000000000 -0500
@@ -219,10 +219,10 @@
 
 	ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (!__ipipe_root_domain_p) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		return 1;
 	}
 
@@ -230,7 +230,7 @@
 	if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
 		__ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return -ret;
 }
@@ -239,14 +239,14 @@
 {
 	unsigned long flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	return flags;
 }
 
 void ipipe_critical_exit(unsigned long flags)
 {
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 static void __ipipe_no_irqtail(void)
@@ -279,9 +279,9 @@
 		return -EINVAL;
 #endif
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	__ipipe_handle_irq(irq, NULL);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return 1;
 }
@@ -293,7 +293,7 @@
 
 	BUG_ON(irqs_disabled());
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (irq_tail_hook)
 		irq_tail_hook();
@@ -303,7 +303,7 @@
 	if (ipipe_root_cpudom_var(irqpend_himask) != 0)
 		__ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 void ___ipipe_sync_pipeline(unsigned long syncmask)
@@ -344,10 +344,10 @@
 {
 	unsigned long *p, flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	p = &__ipipe_root_status;
 	__set_bit(IPIPE_STALL_FLAG, p);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_stall_root);
 
@@ -356,10 +356,10 @@
 	unsigned long *p, flags;
 	int x;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	p = &__ipipe_root_status;
 	x = __test_and_set_bit(IPIPE_STALL_FLAG, p);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return x;
 }
@@ -371,10 +371,10 @@
 	unsigned long flags;
 	int x;
 
-	local_irq_save_hw_smp(flags);
+	flags = hard_local_irq_save_smp();
 	p = &__ipipe_root_status;
 	x = test_bit(IPIPE_STALL_FLAG, p);
-	local_irq_restore_hw_smp(flags);
+	hard_local_irq_restore_smp(flags);
 
 	return x;
 }
@@ -384,10 +384,10 @@
 {
 	unsigned long *p, flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	p = &__ipipe_root_status;
 	__set_bit(IPIPE_SYNCDEFER_FLAG, p);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_lock_root);
 
@@ -395,9 +395,9 @@
 {
 	unsigned long *p, flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	p = &__ipipe_root_status;
 	__clear_bit(IPIPE_SYNCDEFER_FLAG, p);
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_unlock_root);
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/kgdb.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/kgdb.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/kgdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/kgdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -320,7 +320,7 @@
 	}
 }
 
-void kgdb_disable_hw_debug(struct pt_regs *regs)
+static void bfin_disable_hw_debug(struct pt_regs *regs)
 {
 	/* Disable hardware debugging while we are in kgdb */
 	bfin_write_WPIACTL(0);
@@ -406,6 +406,7 @@
 #endif
 	.set_hw_breakpoint = bfin_set_hw_break,
 	.remove_hw_breakpoint = bfin_remove_hw_break,
+	.disable_hw_break = bfin_disable_hw_debug,
 	.remove_all_hw_break = bfin_remove_all_hw_break,
 	.correct_hw_break = bfin_correct_hw_break,
 };
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/kgdb_test.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/kgdb_test.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/kgdb_test.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/kgdb_test.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,6 +88,7 @@
 	.owner = THIS_MODULE,
 	.read  = kgdb_test_proc_read,
 	.write = kgdb_test_proc_write,
+	.llseek = noop_llseek,
 };
 
 static int __init kgdbtest_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/process.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/smp_lock.h>
 #include <linux/unistd.h>
 #include <linux/user.h>
 #include <linux/uaccess.h>
@@ -65,11 +64,11 @@
 #ifdef CONFIG_IPIPE
 	ipipe_suspend_domain();
 #endif
-	local_irq_disable_hw();
+	hard_local_irq_disable();
 	if (!need_resched())
 		idle_with_irq_disabled();
 
-	local_irq_enable_hw();
+	hard_local_irq_enable();
 }
 
 /*
@@ -493,6 +492,11 @@
 		return 1;
 #endif
 
+#ifndef CONFIG_EXCEPTION_L1_SCRATCH
+	if (in_mem_const(addr, size, (unsigned long)l1_stack_base, l1_stack_len))
+		return 1;
+#endif
+
 	aret = in_async(addr, size);
 	if (aret < 2)
 		return aret;
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 #include <asm/fixed_code.h>
 #include <asm/cacheflush.h>
 #include <asm/mem_map.h>
+#include <asm/mmu_context.h>
 
 /*
  * does not yet catch signals sent when the child dies.
@@ -37,12 +38,13 @@
  * Get contents of register REGNO in task TASK.
  */
 static inline long
-get_reg(struct task_struct *task, long regno, unsigned long __user *datap)
+get_reg(struct task_struct *task, unsigned long regno,
+	unsigned long __user *datap)
 {
 	long tmp;
 	struct pt_regs *regs = task_pt_regs(task);
 
-	if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+	if (regno & 3 || regno > PT_LAST_PSEUDO)
 		return -EIO;
 
 	switch (regno) {
@@ -73,11 +75,11 @@
  * Write contents of register REGNO in task TASK.
  */
 static inline int
-put_reg(struct task_struct *task, long regno, unsigned long data)
+put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 {
 	struct pt_regs *regs = task_pt_regs(task);
 
-	if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0)
+	if (regno & 3 || regno > PT_LAST_PSEUDO)
 		return -EIO;
 
 	switch (regno) {
@@ -113,8 +115,8 @@
 /*
  * check that an address falls within the bounds of the target process's memory mappings
  */
-static inline int is_user_addr_valid(struct task_struct *child,
-				     unsigned long start, unsigned long len)
+int
+is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len)
 {
 	struct vm_area_struct *vma;
 	struct sram_list_struct *sraml;
@@ -135,6 +137,13 @@
 	if (start >= FIXED_CODE_START && start + len < FIXED_CODE_END)
 		return 0;
 
+#ifdef CONFIG_APP_STACK_L1
+	if (child->mm->context.l1_stack_save)
+		if (start >= (unsigned long)l1_stack_base &&
+			start + len < (unsigned long)l1_stack_base + l1_stack_len)
+			return 0;
+#endif
+
 	return -EIO;
 }
 
@@ -232,7 +241,8 @@
 	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
 	unsigned long __user *datap = (unsigned long __user *)data;
@@ -360,14 +370,14 @@
 		return copy_regset_to_user(child, &user_bfin_native_view,
 					   REGSET_GENERAL,
 					   0, sizeof(struct pt_regs),
-					   (void __user *)data);
+					   datap);
 
 	case PTRACE_SETREGS:
 		pr_debug("ptrace: PTRACE_SETREGS\n");
 		return copy_regset_from_user(child, &user_bfin_native_view,
 					     REGSET_GENERAL,
 					     0, sizeof(struct pt_regs),
-					     (const void __user *)data);
+					     datap);
 
 	case_default:
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/sys_bfin.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/sys_bfin.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/sys_bfin.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/sys_bfin.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,8 @@
 
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
+#include <asm/cachectl.h>
+#include <asm/ptrace.h>
 
 asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
 {
@@ -70,3 +72,16 @@
 
 	return ret;
 }
+
+SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, int, op)
+{
+	if (is_user_addr_valid(current, addr, len) != 0)
+		return -EINVAL;
+
+	if (op & DCACHE)
+		blackfin_dcache_flush_range(addr, addr + len);
+	if (op & ICACHE)
+		blackfin_icache_flush_range(addr, addr + len);
+
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/kernel/trace.c linux-libre-2.6.37-gnu/arch/blackfin/kernel/trace.c
--- linux-libre-2.6.36-gnu/arch/blackfin/kernel/trace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/kernel/trace.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/kallsyms.h>
 #include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/boards/ezbrd.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/boards/ezbrd.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/boards/ezbrd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/boards/ezbrd.c	2011-01-04 19:50:19.000000000 -0500
@@ -87,13 +87,55 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = {
+	P_MII0_ETxD0,
+	P_MII0_ETxD1,
+	P_MII0_ETxEN,
+	P_MII0_ERxD0,
+	P_MII0_ERxD1,
+	P_MII0_TxCLK,
+	P_MII0_PHYINT,
+	P_MII0_CRS,
+	P_MII0_MDC,
+	P_MII0_MDIO,
+	0
+};
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+	{
+		.addr = 2,
+		.irq = IRQ_MAC_PHYINT,
+	},
+	{
+		.addr = 3,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 3,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 
 #if defined(CONFIG_NET_DSA_KSZ8893M) || defined(CONFIG_NET_DSA_KSZ8893M_MODULE)
@@ -312,7 +354,7 @@
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* SPI (0) */
 static struct bfin5xx_spi_master bfin_spi0_info = {
-	.num_chipselect = 5,
+	.num_chipselect = 6,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
 };
@@ -347,7 +389,7 @@
 
 /* SPI (1) */
 static struct bfin5xx_spi_master bfin_spi1_info = {
-	.num_chipselect = 5,
+	.num_chipselect = 6,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
@@ -525,6 +567,14 @@
 #endif
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+	.name = "bfin-i2s",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
 #if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
 static struct resource bfin_twi0_resource[] = {
 	[0] = {
@@ -559,6 +609,11 @@
 		.irq = IRQ_PF8,
 	},
 #endif
+#if defined(CONFIG_SND_SOC_SSM2602) || defined(CONFIG_SND_SOC_SSM2602_MODULE)
+	{
+		I2C_BOARD_INFO("ssm2602", 0x1b),
+	},
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -736,6 +791,10 @@
 	&i2c_bfin_twi_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+	&bfin_i2s,
+#endif
+
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 #ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
 	&bfin_sport0_uart_device,
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/boards/tcm-bf518.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/boards/tcm-bf518.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/boards/tcm-bf518.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/boards/tcm-bf518.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,13 +81,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
@@ -291,7 +313,7 @@
 
 /* SPI (1) */
 static struct bfin5xx_spi_master bfin_spi1_info = {
-	.num_chipselect = 5,
+	.num_chipselect = 6,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -262,14 +262,14 @@
 #define bfin_write_SPORT0_TX(val)		bfin_write32(SPORT0_TX, val)
 #define bfin_read_SPORT0_RX()			bfin_read32(SPORT0_RX)
 #define bfin_write_SPORT0_RX(val)		bfin_write32(SPORT0_RX, val)
-#define bfin_read_SPORT0_TX32()			bfin_read32(SPORT0_TX32)
-#define bfin_write_SPORT0_TX32(val)		bfin_write32(SPORT0_TX32, val)
-#define bfin_read_SPORT0_RX32()			bfin_read32(SPORT0_RX32)
-#define bfin_write_SPORT0_RX32(val)		bfin_write32(SPORT0_RX32, val)
-#define bfin_read_SPORT0_TX16()			bfin_read16(SPORT0_TX16)
-#define bfin_write_SPORT0_TX16(val)		bfin_write16(SPORT0_TX16, val)
-#define bfin_read_SPORT0_RX16()			bfin_read16(SPORT0_RX16)
-#define bfin_write_SPORT0_RX16(val)		bfin_write16(SPORT0_RX16, val)
+#define bfin_read_SPORT0_TX32()			bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val)		bfin_write32(SPORT0_TX, val)
+#define bfin_read_SPORT0_RX32()			bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val)		bfin_write32(SPORT0_RX, val)
+#define bfin_read_SPORT0_TX16()			bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val)		bfin_write16(SPORT0_TX, val)
+#define bfin_read_SPORT0_RX16()			bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val)		bfin_write16(SPORT0_RX, val)
 #define bfin_read_SPORT0_RCR1()			bfin_read16(SPORT0_RCR1)
 #define bfin_write_SPORT0_RCR1(val)		bfin_write16(SPORT0_RCR1, val)
 #define bfin_read_SPORT0_RCR2()			bfin_read16(SPORT0_RCR2)
@@ -317,14 +317,14 @@
 #define bfin_write_SPORT1_TX(val)		bfin_write32(SPORT1_TX, val)
 #define bfin_read_SPORT1_RX()			bfin_read32(SPORT1_RX)
 #define bfin_write_SPORT1_RX(val)		bfin_write32(SPORT1_RX, val)
-#define bfin_read_SPORT1_TX32()			bfin_read32(SPORT1_TX32)
-#define bfin_write_SPORT1_TX32(val)		bfin_write32(SPORT1_TX32, val)
-#define bfin_read_SPORT1_RX32()			bfin_read32(SPORT1_RX32)
-#define bfin_write_SPORT1_RX32(val)		bfin_write32(SPORT1_RX32, val)
-#define bfin_read_SPORT1_TX16()			bfin_read16(SPORT1_TX16)
-#define bfin_write_SPORT1_TX16(val)		bfin_write16(SPORT1_TX16, val)
-#define bfin_read_SPORT1_RX16()			bfin_read16(SPORT1_RX16)
-#define bfin_write_SPORT1_RX16(val)		bfin_write16(SPORT1_RX16, val)
+#define bfin_read_SPORT1_TX32()			bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val)		bfin_write32(SPORT1_TX, val)
+#define bfin_read_SPORT1_RX32()			bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val)		bfin_write32(SPORT1_RX, val)
+#define bfin_read_SPORT1_TX16()			bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val)		bfin_write16(SPORT1_TX, val)
+#define bfin_read_SPORT1_RX16()			bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val)		bfin_write16(SPORT1_RX, val)
 #define bfin_read_SPORT1_RCR1()			bfin_read16(SPORT1_RCR1)
 #define bfin_write_SPORT1_RCR1(val)		bfin_write16(SPORT1_RCR1, val)
 #define bfin_read_SPORT1_RCR2()			bfin_read16(SPORT1_RCR2)
@@ -1058,54 +1058,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF52X_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -748,51 +748,6 @@
 #define FFE			0x20		/* Force Framing Error On Transmit	*/
 
 
-/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  ****************************/
-/* SPI_CTL Masks																	*/
-#define	TIMOD		0x0003		/* Transfer Initiate Mode							*/
-#define RDBR_CORE	0x0000		/* 		RDBR Read Initiates, IRQ When RDBR Full		*/
-#define	TDBR_CORE	0x0001		/* 		TDBR Write Initiates, IRQ When TDBR Empty	*/
-#define RDBR_DMA	0x0002		/* 		DMA Read, DMA Until FIFO Empty				*/
-#define TDBR_DMA	0x0003		/* 		DMA Write, DMA Until FIFO Full				*/
-#define SZ			0x0004		/* Send Zero (When TDBR Empty, Send Zero/Last*)		*/
-#define GM			0x0008		/* Get More (When RDBR Full, Overwrite/Discard*)	*/
-#define PSSE		0x0010		/* Slave-Select Input Enable						*/
-#define EMISO		0x0020		/* Enable MISO As Output							*/
-#define SIZE		0x0100		/* Size of Words (16/8* Bits)						*/
-#define LSBF		0x0200		/* LSB First										*/
-#define CPHA		0x0400		/* Clock Phase										*/
-#define CPOL		0x0800		/* Clock Polarity									*/
-#define MSTR		0x1000		/* Master/Slave*									*/
-#define WOM			0x2000		/* Write Open Drain Master							*/
-#define SPE			0x4000		/* SPI Enable										*/
-
-/* SPI_FLG Masks																	*/
-#define FLS1		0x0002		/* Enables SPI_FLOUT1 as SPI Slave-Select Output	*/
-#define FLS2		0x0004		/* Enables SPI_FLOUT2 as SPI Slave-Select Output	*/
-#define FLS3		0x0008		/* Enables SPI_FLOUT3 as SPI Slave-Select Output	*/
-#define FLS4		0x0010		/* Enables SPI_FLOUT4 as SPI Slave-Select Output	*/
-#define FLS5		0x0020		/* Enables SPI_FLOUT5 as SPI Slave-Select Output	*/
-#define FLS6		0x0040		/* Enables SPI_FLOUT6 as SPI Slave-Select Output	*/
-#define FLS7		0x0080		/* Enables SPI_FLOUT7 as SPI Slave-Select Output	*/
-#define FLG1		0xFDFF		/* Activates SPI_FLOUT1 							*/
-#define FLG2		0xFBFF		/* Activates SPI_FLOUT2								*/
-#define FLG3		0xF7FF		/* Activates SPI_FLOUT3								*/
-#define FLG4		0xEFFF		/* Activates SPI_FLOUT4								*/
-#define FLG5		0xDFFF		/* Activates SPI_FLOUT5								*/
-#define FLG6		0xBFFF		/* Activates SPI_FLOUT6								*/
-#define FLG7		0x7FFF		/* Activates SPI_FLOUT7								*/
-
-/* SPI_STAT Masks																				*/
-#define SPIF		0x0001		/* SPI Finished (Single-Word Transfer Complete)					*/
-#define MODF		0x0002		/* Mode Fault Error (Another Device Tried To Become Master)		*/
-#define TXE			0x0004		/* Transmission Error (Data Sent With No New Data In TDBR)		*/
-#define TXS			0x0008		/* SPI_TDBR Data Buffer Status (Full/Empty*)					*/
-#define RBSY		0x0010		/* Receive Error (Data Received With RDBR Full)					*/
-#define RXS			0x0020		/* SPI_RDBR Data Buffer Status (Full/Empty*)					*/
-#define TXCOL		0x0040		/* Transmit Collision Error (Corrupt Data May Have Been Sent)	*/
-
-
 /*  ****************  GENERAL PURPOSE TIMER MASKS  **********************/
 /* TIMER_ENABLE Masks													*/
 #define TIMEN0			0x0001		/* Enable Timer 0					*/
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf518/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf518/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ad7160eval.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ad7160eval.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ad7160eval.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ad7160eval.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,870 @@
+/*
+ * Copyright 2004-20010 Analog Devices Inc.
+ *                2005 National ICT Australia (NICTA)
+ *                      Aidan Williams <aidan@nicta.com.au>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "ADI BF527-AD7160EVAL";
+
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+	[0] = {
+		.start	= 0xffc03800,
+		.end	= 0xffc03cff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* general IRQ */
+		.start	= IRQ_USB_INT0,
+		.end	= IRQ_USB_INT0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+	[2] = {	/* DMA IRQ */
+		.start	= IRQ_USB_DMA,
+		.end	= IRQ_USB_DMA,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 8,
+	.dma_channels	= 8,
+	.gpio_vrsel	= GPIO_PG13,
+	/* Some custom boards need to be active low, just set it to "0"
+	 * if it is the case.
+	 */
+	.gpio_vrsel_active	= 1,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	.mode		= MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+	.mode		= MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.config		= &musb_config,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+	.name		= "musb_hdrc",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= &musb_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &musb_plat,
+	},
+	.num_resources	= ARRAY_SIZE(musb_resources),
+	.resource	= musb_resources,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_RA158Z) || defined(CONFIG_FB_BFIN_RA158Z_MODULE)
+static struct resource bf52x_ra158z_resources[] = {
+	{
+		.start = IRQ_PPI_ERROR,
+		.end = IRQ_PPI_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf52x_ra158z_device = {
+	.name		= "bfin-ra158z",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bf52x_ra158z_resources),
+	.resource	= bf52x_ra158z_resources,
+};
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition ad7160eval_partitions[] = {
+	{
+		.name       = "bootloader(nor)",
+		.size       = 0x40000,
+		.offset     = 0,
+	}, {
+		.name       = "linux kernel(nor)",
+		.size       = 0x1C0000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "file system(nor)",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data ad7160eval_flash_data = {
+	.width      = 2,
+	.parts      = ad7160eval_partitions,
+	.nr_parts   = ARRAY_SIZE(ad7160eval_partitions),
+};
+
+static struct resource ad7160eval_flash_resource = {
+	.start = 0x20000000,
+	.end   = 0x203fffff,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ad7160eval_flash_device = {
+	.name          = "physmap-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &ad7160eval_flash_data,
+	},
+	.num_resources = 1,
+	.resource      = &ad7160eval_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+static struct mtd_partition partition_info[] = {
+	{
+		.name = "linux kernel(nand)",
+		.offset = 0,
+		.size = 4 * 1024 * 1024,
+	},
+	{
+		.name = "file system(nand)",
+		.offset = MTDPART_OFS_APPEND,
+		.size = MTDPART_SIZ_FULL,
+	},
+};
+
+static struct bf5xx_nand_platform bf5xx_nand_platform = {
+	.data_width = NFC_NWIDTH_8,
+	.partitions = partition_info,
+	.nr_partitions = ARRAY_SIZE(partition_info),
+	.rd_dly = 3,
+	.wr_dly = 3,
+};
+
+static struct resource bf5xx_nand_resources[] = {
+	{
+		.start = NFC_CTL,
+		.end = NFC_DATA_RD + 2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = CH_NFC,
+		.end = CH_NFC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bf5xx_nand_device = {
+	.name = "bf5xx-nand",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bf5xx_nand_resources),
+	.resource = bf5xx_nand_resources,
+	.dev = {
+		.platform_data = &bf5xx_nand_platform,
+	},
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
+static struct platform_device bfin_mii_bus = {
+	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
+};
+
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
+};
+#endif
+
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader(spi)",
+		.size = 0x00040000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	}, {
+		.name = "linux kernel(spi)",
+		.size = MTDPART_SIZ_FULL,
+		.offset = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+static struct bfin5xx_spi_chip  mmc_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+	.name = "bfin-i2s",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+	.name = "bfin-tdm",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
+	{
+		.modalias = "ad183x",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 4,
+		.controller_data = &ad1836_spi_chip_info,
+	},
+#endif
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+	{
+		.modalias = "mmc_spi",
+		.max_speed_hz = 30000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = GPIO_PH3 + MAX_CTRL_CS,
+		.controller_data = &mmc_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &spidev_chip_info,
+	},
+#endif
+};
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+	.num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+	[0] = {
+		.start = SPI0_REGBASE,
+		.end   = SPI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+		},
+	[1] = {
+		.start = CH_SPI,
+		.end   = CH_SPI,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.start = IRQ_SPI,
+		.end   = IRQ_SPI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_spi0_device = {
+	.name = "bfin-spi",
+	.id = 0, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi0_resource),
+	.resource = bfin_spi0_resource,
+	.dev = {
+		.platform_data = &bfin_spi0_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
+	{
+		.start = UART0_THR,
+		.end = UART0_GCTL+2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART0_RX,
+		.end = IRQ_UART0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_UART0_ERROR,
+		.end = IRQ_UART0_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART0_TX,
+		.end = CH_UART0_TX,
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = CH_UART0_RX,
+		.end = CH_UART0_RX,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+	P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+	.name = "bfin-uart",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_uart0_resources),
+	.resource = bfin_uart0_resources,
+	.dev = {
+		.platform_data = &bfin_uart0_peripherals, /* Passed to driver */
+	},
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+	{
+		.start = UART1_THR,
+		.end = UART1_GCTL+2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART1_RX,
+		.end = IRQ_UART1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_UART1_ERROR,
+		.end = IRQ_UART1_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART1_TX,
+		.end = CH_UART1_TX,
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = CH_UART1_RX,
+		.end = CH_UART1_RX,
+		.flags = IORESOURCE_DMA,
+	},
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	{	/* CTS pin */
+		.start = GPIO_PF9,
+		.end = GPIO_PF9,
+		.flags = IORESOURCE_IO,
+	},
+	{	/* RTS pin */
+		.start = GPIO_PF10,
+		.end = GPIO_PF10,
+		.flags = IORESOURCE_IO,
+	},
+#endif
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+	P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart1_resources),
+	.resource = bfin_uart1_resources,
+	.dev = {
+		.platform_data = &bfin_uart1_peripherals, /* Passed to driver */
+	},
+};
+#endif
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+static struct resource bfin_sir0_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART0_RX,
+		.end = IRQ_UART0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART0_RX,
+		.end = CH_UART0_RX+1,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device bfin_sir0_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir0_resources),
+	.resource = bfin_sir0_resources,
+};
+#endif
+#ifdef CONFIG_BFIN_SIR1
+static struct resource bfin_sir1_resources[] = {
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART1_RX,
+		.end = IRQ_UART1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART1_RX,
+		.end = CH_UART1_RX+1,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device bfin_sir1_device = {
+	.name = "bfin_sir",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_sir1_resources),
+	.resource = bfin_sir1_resources,
+};
+#endif
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7160) || defined(CONFIG_TOUCHSCREEN_AD7160_MODULE)
+#include <linux/input/ad7160.h>
+static const struct ad7160_platform_data bfin_ad7160_ts_info = {
+	.sensor_x_res = 854,
+	.sensor_y_res = 480,
+	.pressure = 100,
+	.filter_coef = 3,
+	.coord_pref = AD7160_ORIG_TOP_LEFT,
+	.first_touch_window = 5,
+	.move_window = 3,
+	.event_cabs = AD7160_EMIT_ABS_MT_TRACKING_ID |
+			AD7160_EMIT_ABS_MT_PRESSURE |
+			AD7160_TRACKING_ID_ASCENDING,
+	.finger_act_ctrl = 0x64,
+	.haptic_effect1_ctrl = AD7160_HAPTIC_SLOT_A(60) |
+				AD7160_HAPTIC_SLOT_A_LVL_HIGH |
+				AD7160_HAPTIC_SLOT_B(60) |
+				AD7160_HAPTIC_SLOT_B_LVL_LOW,
+
+	.haptic_effect2_ctrl = AD7160_HAPTIC_SLOT_A(20) |
+				AD7160_HAPTIC_SLOT_A_LVL_HIGH |
+				AD7160_HAPTIC_SLOT_B(80) |
+				AD7160_HAPTIC_SLOT_B_LVL_LOW |
+				AD7160_HAPTIC_SLOT_C(120) |
+				AD7160_HAPTIC_SLOT_C_LVL_HIGH |
+				AD7160_HAPTIC_SLOT_D(30) |
+				AD7160_HAPTIC_SLOT_D_LVL_LOW,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI,
+		.end   = IRQ_TWI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+#endif
+
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_TOUCHSCREEN_AD7160) || defined(CONFIG_TOUCHSCREEN_AD7160_MODULE)
+	{
+		I2C_BOARD_INFO("ad7160", 0x33),
+		.irq = IRQ_PH1,
+		.platform_data = (void *)&bfin_ad7160_ts_info,
+	},
+#endif
+};
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+	{
+		.start = SPORT0_TCR1,
+		.end = SPORT0_MRCS3+4,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_SPORT0_RX,
+		.end = IRQ_SPORT0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_SPORT0_ERROR,
+		.end = IRQ_SPORT0_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+	P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+	P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+	.resource = bfin_sport0_uart_resources,
+	.dev = {
+		.platform_data = &bfin_sport0_peripherals, /* Passed to driver */
+	},
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+	{
+		.start = SPORT1_TCR1,
+		.end = SPORT1_MRCS3+4,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_SPORT1_RX,
+		.end = IRQ_SPORT1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_SPORT1_ERROR,
+		.end = IRQ_SPORT1_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+	P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+	P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+	.resource = bfin_sport1_uart_resources,
+	.dev = {
+		.platform_data = &bfin_sport1_peripherals, /* Passed to driver */
+	},
+};
+#endif
+#endif
+
+#if defined(CONFIG_INPUT_BFIN_ROTARY) || defined(CONFIG_INPUT_BFIN_ROTARY_MODULE)
+#include <asm/bfin_rotary.h>
+
+static struct bfin_rotary_platform_data bfin_rotary_data = {
+	/*.rotary_up_key     = KEY_UP,*/
+	/*.rotary_down_key   = KEY_DOWN,*/
+	.rotary_rel_code   = REL_WHEEL,
+	.rotary_button_key = KEY_ENTER,
+	.debounce	   = 10,	/* 0..17 */
+	.mode		   = ROT_QUAD_ENC | ROT_DEBE,
+};
+
+static struct resource bfin_rotary_resources[] = {
+	{
+		.start = IRQ_CNT,
+		.end = IRQ_CNT,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_rotary_device = {
+	.name		= "bfin-rotary",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bfin_rotary_resources),
+	.resource	= bfin_rotary_resources,
+	.dev		= {
+		.platform_data = &bfin_rotary_data,
+	},
+};
+#endif
+
+static const unsigned int cclk_vlev_datasheet[] = {
+	VRPAIR(VLEV_100, 400000000),
+	VRPAIR(VLEV_105, 426000000),
+	VRPAIR(VLEV_110, 500000000),
+	VRPAIR(VLEV_115, 533000000),
+	VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+	.tuple_tab = cclk_vlev_datasheet,
+	.tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+	.vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+	.name = "bfin dpmc",
+	.dev = {
+		.platform_data = &bfin_dmpc_vreg_data,
+	},
+};
+
+static struct platform_device *stamp_devices[] __initdata = {
+
+	&bfin_dpmc,
+
+#if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
+	&bf5xx_nand_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+	&musb_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mii_bus,
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	&bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	&bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_FB_BFIN_RA158Z) || defined(CONFIG_FB_BFIN_RA158Z_MODULE)
+	&bf52x_ra158z_device,
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+	&bfin_sir0_device,
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	&bfin_sir1_device,
+#endif
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+	&bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+	&bfin_sport1_uart_device,
+#endif
+#endif
+
+#if defined(CONFIG_INPUT_BFIN_ROTARY) || defined(CONFIG_INPUT_BFIN_ROTARY_MODULE)
+	&bfin_rotary_device,
+#endif
+
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+	&ad7160eval_flash_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+	&bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+	&bfin_tdm,
+#endif
+};
+
+static int __init ad7160eval_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+	i2c_register_board_info(0, bfin_i2c_board_info,
+				ARRAY_SIZE(bfin_i2c_board_info));
+	platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+	return 0;
+}
+
+arch_initcall(ad7160eval_init);
+
+static struct platform_device *ad7160eval_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	&bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	&bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+	&bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+	&bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+	printk(KERN_INFO "register early platform devices\n");
+	early_platform_add_devices(ad7160eval_early_devices,
+		ARRAY_SIZE(ad7160eval_early_devices));
+}
+
+void native_machine_restart(char *cmd)
+{
+	/* workaround reboot hang when booting from SPI */
+	if ((bfin_read_SYSCR() & 0x7) == 0x3)
+		bfin_reset_boot_spi_cs(P_DEFAULT_BOOT_SPI_CS);
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+	/* the MAC is stored in OTP memory page 0xDF */
+	u32 ret;
+	u64 otp_mac;
+	u32 (*otp_read)(u32 page, u32 flags, u64 *page_content) = (void *)0xEF00001A;
+
+	ret = otp_read(0xDF, 0x00, &otp_mac);
+	if (!(ret & 0x1)) {
+		char *otp_mac_p = (char *)&otp_mac;
+		for (ret = 0; ret < 6; ++ret)
+			addr[ret] = otp_mac_p[5 - ret];
+	}
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/cm_bf527.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/cm_bf527.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/cm_bf527.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/cm_bf527.c	2011-01-04 19:50:19.000000000 -0500
@@ -273,13 +273,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
@@ -342,8 +364,8 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -420,13 +442,13 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ezbrd.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ezbrd.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ezbrd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ezbrd.c	2011-01-04 19:50:19.000000000 -0500
@@ -137,8 +137,12 @@
 #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
 static struct mtd_partition partition_info[] = {
 	{
-		.name = "linux kernel(nand)",
+		.name = "bootloader(nand)",
 		.offset = 0,
+		.size = 0x40000,
+	}, {
+		.name = "linux kernel(nand)",
+		.offset = MTDPART_OFS_APPEND,
 		.size = 4 * 1024 * 1024,
 	},
 	{
@@ -189,13 +193,35 @@
 
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ezkit.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ezkit.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/ezkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/ezkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -222,8 +222,12 @@
 #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
 static struct mtd_partition partition_info[] = {
 	{
-		.name = "linux kernel(nand)",
+		.name = "bootloader(nand)",
 		.offset = 0,
+		.size = 0x40000,
+	}, {
+		.name = "linux kernel(nand)",
+		.offset = MTDPART_OFS_APPEND,
 		.size = 4 * 1024 * 1024,
 	},
 	{
@@ -362,13 +366,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
@@ -431,8 +457,8 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -547,13 +573,13 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -883,7 +909,7 @@
 };
 
 	/*
-	 *  ADP5520/5501 Multifuction Device Init Data
+	 *  ADP5520/5501 Multifunction Device Init Data
 	 */
 
 static struct adp5520_platform_data adp5520_pdev_data = {
@@ -929,6 +955,11 @@
 		I2C_BOARD_INFO("ssm2602", 0x1b),
 	},
 #endif
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("ad5252", 0x2f),
+	},
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/Kconfig linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/Kconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -24,4 +24,14 @@
 	help
 	  BF526-EZBRD/EZKIT Lite board support.
 
+config BFIN527_AD7160EVAL
+	bool "BF527-AD7160-EVAL"
+	help
+	  BF527-AD7160-EVAL board support.
+
+config BFIN527_TLL6527M
+	bool "The Learning Labs TLL6527M"
+	help
+	  TLL6527M V1.0 platform support
+
 endchoice
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/Makefile linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/Makefile
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,3 +6,5 @@
 obj-$(CONFIG_BFIN527_EZKIT_V2)         += ezkit.o
 obj-$(CONFIG_BFIN527_BLUETECHNIX_CM)   += cm_bf527.o
 obj-$(CONFIG_BFIN526_EZBRD)            += ezbrd.o
+obj-$(CONFIG_BFIN527_AD7160EVAL)       += ad7160eval.o
+obj-$(CONFIG_BFIN527_TLL6527M)         += tll6527m.o
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/tll6527m.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/tll6527m.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/boards/tll6527m.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/boards/tll6527m.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1008 @@
+/* File:	arch/blackfin/mach-bf527/boards/tll6527m.c
+ * Based on:	arch/blackfin/mach-bf527/boards/ezkit.c
+ * Author:	Ashish Gupta
+ *
+ * Copyright: 2010 - The Learning Labs Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/musb.h>
+#include <linux/leds.h>
+#include <linux/input.h>
+#include <asm/dma.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/reboot.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+#include <asm/dpmc.h>
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879) \
+	|| defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+#include <linux/spi/ad7879.h>
+#define LCD_BACKLIGHT_GPIO 0x40
+/* TLL6527M uses TLL7UIQ35 / ADI LCD EZ Extender. AD7879 AUX GPIO is used for
+ * LCD Backlight Enable
+ */
+#endif
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+const char bfin_board_name[] = "TLL6527M";
+/*
+ *  Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct resource musb_resources[] = {
+	[0] = {
+		.start	= 0xffc03800,
+		.end	= 0xffc03cff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {	/* general IRQ */
+		.start	= IRQ_USB_INT0,
+		.end	= IRQ_USB_INT0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+	[2] = {	/* DMA IRQ */
+		.start	= IRQ_USB_DMA,
+		.end	= IRQ_USB_DMA,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+	},
+};
+
+static struct musb_hdrc_config musb_config = {
+	.multipoint	= 0,
+	.dyn_fifo	= 0,
+	.soft_con	= 1,
+	.dma		= 1,
+	.num_eps	= 8,
+	.dma_channels	= 8,
+	/*.gpio_vrsel	= GPIO_PG13,*/
+	/* Some custom boards need to be active low, just set it to "0"
+	 * if it is the case.
+	 */
+	.gpio_vrsel_active	= 1,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#if defined(CONFIG_USB_MUSB_OTG)
+	.mode		= MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+	.mode		= MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+	.mode		= MUSB_PERIPHERAL,
+#endif
+	.config		= &musb_config,
+};
+
+static u64 musb_dmamask = ~(u32)0;
+
+static struct platform_device musb_device = {
+	.name		= "musb_hdrc",
+	.id		= 0,
+	.dev = {
+		.dma_mask		= &musb_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+		.platform_data		= &musb_plat,
+	},
+	.num_resources	= ARRAY_SIZE(musb_resources),
+	.resource	= musb_resources,
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+#include <asm/bfin-lq035q1.h>
+
+static struct bfin_lq035q1fb_disp_info bfin_lq035q1_data = {
+	.mode = LQ035_NORM | LQ035_RGB | LQ035_RL | LQ035_TB,
+	.ppi_mode = USE_RGB565_16_BIT_PPI,
+	.use_bl = 1,
+	.gpio_bl = LCD_BACKLIGHT_GPIO,
+};
+
+static struct resource bfin_lq035q1_resources[] = {
+	{
+		.start = IRQ_PPI_ERROR,
+		.end = IRQ_PPI_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_lq035q1_device = {
+	.name		= "bfin-lq035q1",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(bfin_lq035q1_resources),
+	.resource	= bfin_lq035q1_resources,
+	.dev		= {
+		.platform_data = &bfin_lq035q1_data,
+	},
+};
+#endif
+
+#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
+static struct mtd_partition tll6527m_partitions[] = {
+	{
+		.name       = "bootloader(nor)",
+		.size       = 0xA0000,
+		.offset     = 0,
+	}, {
+		.name       = "linux kernel(nor)",
+		.size       = 0xD00000,
+		.offset     = MTDPART_OFS_APPEND,
+	}, {
+		.name       = "file system(nor)",
+		.size       = MTDPART_SIZ_FULL,
+		.offset     = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct physmap_flash_data tll6527m_flash_data = {
+	.width      = 2,
+	.parts      = tll6527m_partitions,
+	.nr_parts   = ARRAY_SIZE(tll6527m_partitions),
+};
+
+static unsigned tll6527m_flash_gpios[] = { GPIO_PG11, GPIO_PH11, GPIO_PH12 };
+
+static struct resource tll6527m_flash_resource[] = {
+	{
+		.name  = "cfi_probe",
+		.start = 0x20000000,
+		.end   = 0x201fffff,
+		.flags = IORESOURCE_MEM,
+	}, {
+		.start = (unsigned long)tll6527m_flash_gpios,
+		.end   = ARRAY_SIZE(tll6527m_flash_gpios),
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device tll6527m_flash_device = {
+	.name          = "gpio-addr-flash",
+	.id            = 0,
+	.dev = {
+		.platform_data = &tll6527m_flash_data,
+	},
+	.num_resources = ARRAY_SIZE(tll6527m_flash_resource),
+	.resource      = tll6527m_flash_resource,
+};
+#endif
+
+#if defined(CONFIG_GPIO_DECODER) || defined(CONFIG_GPIO_DECODER_MODULE)
+/* An SN74LVC138A 3:8 decoder chip has been used to generate 7 augmented
+ * outputs used as SPI CS lines for all SPI SLAVE devices on TLL6527v1-0.
+ * EXP_GPIO_SPISEL_BASE is the base number for the expanded outputs being
+ * used as SPI CS lines, this should be > MAX_BLACKFIN_GPIOS
+ */
+#include <linux/gpio-decoder.h>
+#define EXP_GPIO_SPISEL_BASE 0x64
+static unsigned gpio_addr_inputs[] = {
+	GPIO_PG1, GPIO_PH9, GPIO_PH10
+};
+
+static struct gpio_decoder_platfrom_data spi_decoded_cs = {
+	.base		= EXP_GPIO_SPISEL_BASE,
+	.input_addrs	= gpio_addr_inputs,
+	.nr_input_addrs = ARRAY_SIZE(gpio_addr_inputs),
+	.default_output	= 0,
+/*	.default_output = (1 << ARRAY_SIZE(gpio_addr_inputs)) - 1 */
+};
+
+static struct platform_device spi_decoded_gpio = {
+	.name	= "gpio-decoder",
+	.id	= 0,
+	.dev	= {
+		.platform_data = &spi_decoded_cs,
+	},
+};
+
+#else
+#define EXP_GPIO_SPISEL_BASE 0x0
+
+#endif
+
+#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
+#include <linux/input/adxl34x.h>
+static const struct adxl34x_platform_data adxl345_info = {
+	.x_axis_offset = 0,
+	.y_axis_offset = 0,
+	.z_axis_offset = 0,
+	.tap_threshold = 0x31,
+	.tap_duration = 0x10,
+	.tap_latency = 0x60,
+	.tap_window = 0xF0,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 5,
+	.inactivity_threshold = 2,
+	.inactivity_time = 2,
+	.free_fall_threshold = 0x7,
+	.free_fall_time = 0x20,
+	.data_rate = 0x8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,		/* EV_REL */
+	.ev_code_y = ABS_Y,		/* EV_REL */
+	.ev_code_z = ABS_Z,		/* EV_REL */
+
+	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY x,y,z */
+
+/*	.ev_code_ff = KEY_F,*/		/* EV_KEY */
+	.ev_code_act_inactivity = KEY_A,	/* EV_KEY */
+	.use_int2 = 1,
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = ADXL_FIFO_STREAM,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+	.name = "rtc-bfin",
+	.id   = -1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
+static struct platform_device bfin_mii_bus = {
+	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
+};
+
+static struct platform_device bfin_mac_device = {
+	.name = "bfin_mac",
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
+};
+#endif
+
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+	{
+		.name = "bootloader(spi)",
+		.size = 0x00040000,
+		.offset = 0,
+		.mask_flags = MTD_CAP_ROM
+	}, {
+		.name = "linux kernel(spi)",
+		.size = MTDPART_SIZ_FULL,
+		.offset = MTDPART_OFS_APPEND,
+	}
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+	.name = "m25p80",
+	.parts = bfin_spi_flash_partitions,
+	.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+	.type = "m25p16",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_BFIN_SPI_ADC) \
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+/*
+ * tll6527m V1.0 does not support native spi slave selects
+ * hence DMA mode will not be useful since the ADC needs
+ * CS to toggle for each sample and cs_change_per_word
+ * seems to be removed from spi_bfin5xx.c
+ */
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+static struct bfin5xx_spi_chip  mmc_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879) \
+	|| defined(CONFIG_TOUCHSCREEN_AD7879_MODULE)
+static const struct ad7879_platform_data bfin_ad7879_ts_info = {
+	.model			= 7879,	/* Model = AD7879 */
+	.x_plate_ohms		= 620,	/* 620 Ohm from the touch datasheet */
+	.pressure_max		= 10000,
+	.pressure_min		= 0,
+	.first_conversion_delay = 3,
+				/* wait 512us before do a first conversion */
+	.acquisition_time	= 1,	/* 4us acquisition time per sample */
+	.median			= 2,	/* do 8 measurements */
+	.averaging		= 1,
+				/* take the average of 4 middle samples */
+	.pen_down_acc_interval	= 255,	/* 9.4 ms */
+	.gpio_export		= 1,	/* configure AUX as GPIO output*/
+	.gpio_base		= LCD_BACKLIGHT_GPIO,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) \
+	|| defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
+static struct bfin5xx_spi_chip spi_ad7879_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+static struct bfin5xx_spi_chip spidev_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+	.name = "bfin-i2s",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+static struct bfin5xx_spi_chip lq035q1_spi_chip_info = {
+	.enable_dma	= 0,
+	.bits_per_word	= 8,
+};
+#endif
+
+#if defined(CONFIG_GPIO_MCP23S08) || defined(CONFIG_GPIO_MCP23S08_MODULE)
+static struct bfin5xx_spi_chip spi_mcp23s08_sys_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+
+static struct bfin5xx_spi_chip spi_mcp23s08_usr_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+
+#include <linux/spi/mcp23s08.h>
+static const struct mcp23s08_platform_data bfin_mcp23s08_sys_gpio_info = {
+	.chip[0].is_present = true,
+	.base = 0x30,
+};
+static const struct mcp23s08_platform_data bfin_mcp23s08_usr_gpio_info = {
+	.chip[2].is_present = true,
+	.base = 0x38,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+	|| defined(CONFIG_MTD_M25P80_MODULE)
+	{
+		/* the modalias must be the same as spi device driver name */
+		.modalias = "m25p80", /* Name of spi_driver for this device */
+		.max_speed_hz = 25000000,
+				/* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x04 + MAX_CTRL_CS,
+		/* Can be connected to TLL6527M GPIO connector */
+		/* Either SPI_ADC or M25P80 FLASH can be installed at a time */
+		.platform_data = &bfin_spi_flash_data,
+		.controller_data = &spi_flash_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_BFIN_SPI_ADC)
+	|| defined(CONFIG_BFIN_SPI_ADC_MODULE)
+	{
+		.modalias = "bfin_spi_adc",
+				/* Name of spi_driver for this device */
+		.max_speed_hz = 10000000,
+				/* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x04 + MAX_CTRL_CS,
+		 /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_adc_chip_info,
+		.mode = SPI_MODE_0,
+	},
+#endif
+
+#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
+	{
+		.modalias = "mmc_spi",
+/*
+ * TLL6527M V1.0 does not support SD Card at SPI Clock > 10 MHz due to
+ * SPI buffer limitations
+ */
+		.max_speed_hz = 10000000,
+					/* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x05 + MAX_CTRL_CS,
+		.controller_data = &mmc_spi_chip_info,
+		.mode = SPI_MODE_0,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) \
+	|| defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
+	{
+		.modalias = "ad7879",
+		.platform_data = &bfin_ad7879_ts_info,
+		.irq = IRQ_PH14,
+		.max_speed_hz = 5000000,
+					/* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x07 + MAX_CTRL_CS,
+		.controller_data = &spi_ad7879_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+	{
+		.modalias = "spidev",
+		.max_speed_hz = 10000000,
+		/* TLL6527Mv1-0 supports max spi clock (SCK) speed = 10 MHz */
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x03 + MAX_CTRL_CS,
+		.mode = SPI_CPHA | SPI_CPOL,
+		.controller_data = &spidev_chip_info,
+	},
+#endif
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	{
+		.modalias = "bfin-lq035q1-spi",
+		.max_speed_hz = 20000000,
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x06 + MAX_CTRL_CS,
+		.controller_data = &lq035q1_spi_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
+#if defined(CONFIG_GPIO_MCP23S08) || defined(CONFIG_GPIO_MCP23S08_MODULE)
+	{
+		.modalias = "mcp23s08",
+		.platform_data = &bfin_mcp23s08_sys_gpio_info,
+		.max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x01 + MAX_CTRL_CS,
+		.controller_data = &spi_mcp23s08_sys_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+	{
+		.modalias = "mcp23s08",
+		.platform_data = &bfin_mcp23s08_usr_gpio_info,
+		.max_speed_hz = 5000000, /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = EXP_GPIO_SPISEL_BASE + 0x02 + MAX_CTRL_CS,
+		.controller_data = &spi_mcp23s08_usr_chip_info,
+		.mode = SPI_CPHA | SPI_CPOL,
+	},
+#endif
+};
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* SPI controller data */
+static struct bfin5xx_spi_master bfin_spi0_info = {
+	.num_chipselect = EXP_GPIO_SPISEL_BASE + 8 + MAX_CTRL_CS,
+	/* EXP_GPIO_SPISEL_BASE will be > MAX_BLACKFIN_GPIOS */
+	.enable_dma = 1,  /* master has the ability to do dma transfer */
+	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
+};
+
+/* SPI (0) */
+static struct resource bfin_spi0_resource[] = {
+	[0] = {
+		.start = SPI0_REGBASE,
+		.end   = SPI0_REGBASE + 0xFF,
+		.flags = IORESOURCE_MEM,
+		},
+	[1] = {
+		.start = CH_SPI,
+		.end   = CH_SPI,
+		.flags = IORESOURCE_DMA,
+	},
+	[2] = {
+		.start = IRQ_SPI,
+		.end   = IRQ_SPI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_spi0_device = {
+	.name = "bfin-spi",
+	.id = 0, /* Bus number */
+	.num_resources = ARRAY_SIZE(bfin_spi0_resource),
+	.resource = bfin_spi0_resource,
+	.dev = {
+		.platform_data = &bfin_spi0_info, /* Passed to driver */
+	},
+};
+#endif  /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+static struct resource bfin_uart0_resources[] = {
+	{
+		.start = UART0_THR,
+		.end = UART0_GCTL+2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART0_RX,
+		.end = IRQ_UART0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_UART0_ERROR,
+		.end = IRQ_UART0_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART0_TX,
+		.end = CH_UART0_TX,
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = CH_UART0_RX,
+		.end = CH_UART0_RX,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+unsigned short bfin_uart0_peripherals[] = {
+	P_UART0_TX, P_UART0_RX, 0
+};
+
+static struct platform_device bfin_uart0_device = {
+	.name = "bfin-uart",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_uart0_resources),
+	.resource = bfin_uart0_resources,
+	.dev = {
+		.platform_data = &bfin_uart0_peripherals,
+					/* Passed to driver */
+	},
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+static struct resource bfin_uart1_resources[] = {
+	{
+		.start = UART1_THR,
+		.end = UART1_GCTL+2,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART1_RX,
+		.end = IRQ_UART1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_UART1_ERROR,
+		.end = IRQ_UART1_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART1_TX,
+		.end = CH_UART1_TX,
+		.flags = IORESOURCE_DMA,
+	},
+	{
+		.start = CH_UART1_RX,
+		.end = CH_UART1_RX,
+		.flags = IORESOURCE_DMA,
+	},
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	{	/* CTS pin */
+		.start = GPIO_PF9,
+		.end = GPIO_PF9,
+		.flags = IORESOURCE_IO,
+	},
+	{	/* RTS pin */
+		.start = GPIO_PF10,
+		.end = GPIO_PF10,
+		.flags = IORESOURCE_IO,
+	},
+#endif
+};
+
+unsigned short bfin_uart1_peripherals[] = {
+	P_UART1_TX, P_UART1_RX, 0
+};
+
+static struct platform_device bfin_uart1_device = {
+	.name = "bfin-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_uart1_resources),
+	.resource = bfin_uart1_resources,
+	.dev = {
+		.platform_data = &bfin_uart1_peripherals,
+						/* Passed to driver */
+	},
+};
+#endif
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+static struct resource bfin_sir0_resources[] = {
+	{
+		.start = 0xFFC00400,
+		.end = 0xFFC004FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART0_RX,
+		.end = IRQ_UART0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART0_RX,
+		.end = CH_UART0_RX+1,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device bfin_sir0_device = {
+	.name = "bfin_sir",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sir0_resources),
+	.resource = bfin_sir0_resources,
+};
+#endif
+#ifdef CONFIG_BFIN_SIR1
+static struct resource bfin_sir1_resources[] = {
+	{
+		.start = 0xFFC02000,
+		.end = 0xFFC020FF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_UART1_RX,
+		.end = IRQ_UART1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = CH_UART1_RX,
+		.end = CH_UART1_RX+1,
+		.flags = IORESOURCE_DMA,
+	},
+};
+
+static struct platform_device bfin_sir1_device = {
+	.name = "bfin_sir",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_sir1_resources),
+	.resource = bfin_sir1_resources,
+};
+#endif
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct resource bfin_twi0_resource[] = {
+	[0] = {
+		.start = TWI0_REGBASE,
+		.end   = TWI0_REGBASE,
+		.flags = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start = IRQ_TWI,
+		.end   = IRQ_TWI,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device i2c_bfin_twi_device = {
+	.name = "i2c-bfin-twi",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_twi0_resource),
+	.resource = bfin_twi0_resource,
+};
+#endif
+
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
+	},
+#endif
+
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+	{
+		I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7879_I2C) \
+	|| defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("ad7879", 0x2C),
+		.irq = IRQ_PH14,
+		.platform_data = (void *)&bfin_ad7879_ts_info,
+	},
+#endif
+#if defined(CONFIG_SND_SOC_SSM2602) || defined(CONFIG_SND_SOC_SSM2602_MODULE)
+	{
+		I2C_BOARD_INFO("ssm2602", 0x1b),
+	},
+#endif
+	{
+		I2C_BOARD_INFO("adm1192", 0x2e),
+	},
+
+	{
+		I2C_BOARD_INFO("ltc3576", 0x09),
+	},
+#if defined(CONFIG_INPUT_ADXL34X_I2C) \
+	|| defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("adxl34x", 0x53),
+		.irq = IRQ_PH13,
+		.platform_data = (void *)&adxl345_info,
+	},
+#endif
+};
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) \
+	|| defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+static struct resource bfin_sport0_uart_resources[] = {
+	{
+		.start = SPORT0_TCR1,
+		.end = SPORT0_MRCS3+4,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_SPORT0_RX,
+		.end = IRQ_SPORT0_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_SPORT0_ERROR,
+		.end = IRQ_SPORT0_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+unsigned short bfin_sport0_peripherals[] = {
+	P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+	P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0
+};
+
+static struct platform_device bfin_sport0_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 0,
+	.num_resources = ARRAY_SIZE(bfin_sport0_uart_resources),
+	.resource = bfin_sport0_uart_resources,
+	.dev = {
+		.platform_data = &bfin_sport0_peripherals,
+		/* Passed to driver */
+	},
+};
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+static struct resource bfin_sport1_uart_resources[] = {
+	{
+		.start = SPORT1_TCR1,
+		.end = SPORT1_MRCS3+4,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_SPORT1_RX,
+		.end = IRQ_SPORT1_RX+1,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_SPORT1_ERROR,
+		.end = IRQ_SPORT1_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+unsigned short bfin_sport1_peripherals[] = {
+	P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+	P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+	.name = "bfin-sport-uart",
+	.id = 1,
+	.num_resources = ARRAY_SIZE(bfin_sport1_uart_resources),
+	.resource = bfin_sport1_uart_resources,
+	.dev = {
+		.platform_data = &bfin_sport1_peripherals,
+		/* Passed to driver */
+	},
+};
+#endif
+#endif
+
+static const unsigned int cclk_vlev_datasheet[] = {
+	VRPAIR(VLEV_100, 400000000),
+	VRPAIR(VLEV_105, 426000000),
+	VRPAIR(VLEV_110, 500000000),
+	VRPAIR(VLEV_115, 533000000),
+	VRPAIR(VLEV_120, 600000000),
+};
+
+static struct bfin_dpmc_platform_data bfin_dmpc_vreg_data = {
+	.tuple_tab = cclk_vlev_datasheet,
+	.tabsize = ARRAY_SIZE(cclk_vlev_datasheet),
+	.vr_settling_time = 25 /* us */,
+};
+
+static struct platform_device bfin_dpmc = {
+	.name = "bfin dpmc",
+	.dev = {
+		.platform_data = &bfin_dmpc_vreg_data,
+	},
+};
+
+static struct platform_device *tll6527m_devices[] __initdata = {
+
+	&bfin_dpmc,
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+	&rtc_device,
+#endif
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+	&musb_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+	&bfin_mii_bus,
+	&bfin_mac_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+	&bfin_spi0_device,
+#endif
+
+#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
+	&bfin_lq035q1_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	&bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	&bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_BFIN_SIR) || defined(CONFIG_BFIN_SIR_MODULE)
+#ifdef CONFIG_BFIN_SIR0
+	&bfin_sir0_device,
+#endif
+#ifdef CONFIG_BFIN_SIR1
+	&bfin_sir1_device,
+#endif
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+	&i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) \
+	|| defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+	&bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+	&bfin_sport1_uart_device,
+#endif
+#endif
+
+#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
+	&tll6527m_flash_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+	&bfin_i2s,
+#endif
+
+#if defined(CONFIG_GPIO_DECODER) || defined(CONFIG_GPIO_DECODER_MODULE)
+	&spi_decoded_gpio,
+#endif
+};
+
+static int __init tll6527m_init(void)
+{
+	printk(KERN_INFO "%s(): registering device resources\n", __func__);
+	i2c_register_board_info(0, bfin_i2c_board_info,
+				ARRAY_SIZE(bfin_i2c_board_info));
+	platform_add_devices(tll6527m_devices, ARRAY_SIZE(tll6527m_devices));
+	spi_register_board_info(bfin_spi_board_info,
+				ARRAY_SIZE(bfin_spi_board_info));
+	return 0;
+}
+
+arch_initcall(tll6527m_init);
+
+static struct platform_device *tll6527m_early_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+#ifdef CONFIG_SERIAL_BFIN_UART0
+	&bfin_uart0_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+	&bfin_uart1_device,
+#endif
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT_CONSOLE)
+#ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
+	&bfin_sport0_uart_device,
+#endif
+#ifdef CONFIG_SERIAL_BFIN_SPORT1_UART
+	&bfin_sport1_uart_device,
+#endif
+#endif
+};
+
+void __init native_machine_early_platform_add_devices(void)
+{
+	printk(KERN_INFO "register early platform devices\n");
+	early_platform_add_devices(tll6527m_early_devices,
+		ARRAY_SIZE(tll6527m_early_devices));
+}
+
+void native_machine_restart(char *cmd)
+{
+	/* workaround reboot hang when booting from SPI */
+	if ((bfin_read_SYSCR() & 0x7) == 0x3)
+		bfin_reset_boot_spi_cs(P_DEFAULT_BOOT_SPI_CS);
+}
+
+void bfin_get_ether_addr(char *addr)
+{
+	/* the MAC is stored in OTP memory page 0xDF */
+	u32 ret;
+	u64 otp_mac;
+	u32 (*otp_read)(u32 page, u32 flags,
+			u64 *page_content) = (void *)0xEF00001A;
+
+	ret = otp_read(0xDF, 0x00, &otp_mac);
+	if (!(ret & 0x1)) {
+		char *otp_mac_p = (char *)&otp_mac;
+		for (ret = 0; ret < 6; ++ret)
+			addr[ret] = otp_mac_p[5 - ret];
+	}
+}
+EXPORT_SYMBOL(bfin_get_ether_addr);
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -279,14 +279,14 @@
 #define bfin_write_SPORT0_TX(val)		bfin_write32(SPORT0_TX, val)
 #define bfin_read_SPORT0_RX()			bfin_read32(SPORT0_RX)
 #define bfin_write_SPORT0_RX(val)		bfin_write32(SPORT0_RX, val)
-#define bfin_read_SPORT0_TX32()			bfin_read32(SPORT0_TX32)
-#define bfin_write_SPORT0_TX32(val)		bfin_write32(SPORT0_TX32, val)
-#define bfin_read_SPORT0_RX32()			bfin_read32(SPORT0_RX32)
-#define bfin_write_SPORT0_RX32(val)		bfin_write32(SPORT0_RX32, val)
-#define bfin_read_SPORT0_TX16()			bfin_read16(SPORT0_TX16)
-#define bfin_write_SPORT0_TX16(val)		bfin_write16(SPORT0_TX16, val)
-#define bfin_read_SPORT0_RX16()			bfin_read16(SPORT0_RX16)
-#define bfin_write_SPORT0_RX16(val)		bfin_write16(SPORT0_RX16, val)
+#define bfin_read_SPORT0_TX32()			bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val)		bfin_write32(SPORT0_TX, val)
+#define bfin_read_SPORT0_RX32()			bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val)		bfin_write32(SPORT0_RX, val)
+#define bfin_read_SPORT0_TX16()			bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val)		bfin_write16(SPORT0_TX, val)
+#define bfin_read_SPORT0_RX16()			bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val)		bfin_write16(SPORT0_RX, val)
 #define bfin_read_SPORT0_RCR1()			bfin_read16(SPORT0_RCR1)
 #define bfin_write_SPORT0_RCR1(val)		bfin_write16(SPORT0_RCR1, val)
 #define bfin_read_SPORT0_RCR2()			bfin_read16(SPORT0_RCR2)
@@ -334,14 +334,14 @@
 #define bfin_write_SPORT1_TX(val)		bfin_write32(SPORT1_TX, val)
 #define bfin_read_SPORT1_RX()			bfin_read32(SPORT1_RX)
 #define bfin_write_SPORT1_RX(val)		bfin_write32(SPORT1_RX, val)
-#define bfin_read_SPORT1_TX32()			bfin_read32(SPORT1_TX32)
-#define bfin_write_SPORT1_TX32(val)		bfin_write32(SPORT1_TX32, val)
-#define bfin_read_SPORT1_RX32()			bfin_read32(SPORT1_RX32)
-#define bfin_write_SPORT1_RX32(val)		bfin_write32(SPORT1_RX32, val)
-#define bfin_read_SPORT1_TX16()			bfin_read16(SPORT1_TX16)
-#define bfin_write_SPORT1_TX16(val)		bfin_write16(SPORT1_TX16, val)
-#define bfin_read_SPORT1_RX16()			bfin_read16(SPORT1_RX16)
-#define bfin_write_SPORT1_RX16(val)		bfin_write16(SPORT1_RX16, val)
+#define bfin_read_SPORT1_TX32()			bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val)		bfin_write32(SPORT1_TX, val)
+#define bfin_read_SPORT1_RX32()			bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val)		bfin_write32(SPORT1_RX, val)
+#define bfin_read_SPORT1_TX16()			bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val)		bfin_write16(SPORT1_TX, val)
+#define bfin_read_SPORT1_RX16()			bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val)		bfin_write16(SPORT1_RX, val)
 #define bfin_read_SPORT1_RCR1()			bfin_read16(SPORT1_RCR1)
 #define bfin_write_SPORT1_RCR1(val)		bfin_write16(SPORT1_RCR1, val)
 #define bfin_read_SPORT1_RCR2()			bfin_read16(SPORT1_RCR2)
@@ -1110,54 +1110,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF52X_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -749,51 +749,6 @@
 #define FFE			0x20		/* Force Framing Error On Transmit	*/
 
 
-/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  ****************************/
-/* SPI_CTL Masks																	*/
-#define	TIMOD		0x0003		/* Transfer Initiate Mode							*/
-#define RDBR_CORE	0x0000		/* 		RDBR Read Initiates, IRQ When RDBR Full		*/
-#define	TDBR_CORE	0x0001		/* 		TDBR Write Initiates, IRQ When TDBR Empty	*/
-#define RDBR_DMA	0x0002		/* 		DMA Read, DMA Until FIFO Empty				*/
-#define TDBR_DMA	0x0003		/* 		DMA Write, DMA Until FIFO Full				*/
-#define SZ			0x0004		/* Send Zero (When TDBR Empty, Send Zero/Last*)		*/
-#define GM			0x0008		/* Get More (When RDBR Full, Overwrite/Discard*)	*/
-#define PSSE		0x0010		/* Slave-Select Input Enable						*/
-#define EMISO		0x0020		/* Enable MISO As Output							*/
-#define SIZE		0x0100		/* Size of Words (16/8* Bits)						*/
-#define LSBF		0x0200		/* LSB First										*/
-#define CPHA		0x0400		/* Clock Phase										*/
-#define CPOL		0x0800		/* Clock Polarity									*/
-#define MSTR		0x1000		/* Master/Slave*									*/
-#define WOM			0x2000		/* Write Open Drain Master							*/
-#define SPE			0x4000		/* SPI Enable										*/
-
-/* SPI_FLG Masks																	*/
-#define FLS1		0x0002		/* Enables SPI_FLOUT1 as SPI Slave-Select Output	*/
-#define FLS2		0x0004		/* Enables SPI_FLOUT2 as SPI Slave-Select Output	*/
-#define FLS3		0x0008		/* Enables SPI_FLOUT3 as SPI Slave-Select Output	*/
-#define FLS4		0x0010		/* Enables SPI_FLOUT4 as SPI Slave-Select Output	*/
-#define FLS5		0x0020		/* Enables SPI_FLOUT5 as SPI Slave-Select Output	*/
-#define FLS6		0x0040		/* Enables SPI_FLOUT6 as SPI Slave-Select Output	*/
-#define FLS7		0x0080		/* Enables SPI_FLOUT7 as SPI Slave-Select Output	*/
-#define FLG1		0xFDFF		/* Activates SPI_FLOUT1 							*/
-#define FLG2		0xFBFF		/* Activates SPI_FLOUT2								*/
-#define FLG3		0xF7FF		/* Activates SPI_FLOUT3								*/
-#define FLG4		0xEFFF		/* Activates SPI_FLOUT4								*/
-#define FLG5		0xDFFF		/* Activates SPI_FLOUT5								*/
-#define FLG6		0xBFFF		/* Activates SPI_FLOUT6								*/
-#define FLG7		0x7FFF		/* Activates SPI_FLOUT7								*/
-
-/* SPI_STAT Masks																				*/
-#define SPIF		0x0001		/* SPI Finished (Single-Word Transfer Complete)					*/
-#define MODF		0x0002		/* Mode Fault Error (Another Device Tried To Become Master)		*/
-#define TXE			0x0004		/* Transmission Error (Data Sent With No New Data In TDBR)		*/
-#define TXS			0x0008		/* SPI_TDBR Data Buffer Status (Full/Empty*)					*/
-#define RBSY		0x0010		/* Receive Error (Data Received With RDBR Full)					*/
-#define RXS			0x0020		/* SPI_RDBR Data Buffer Status (Full/Empty*)					*/
-#define TXCOL		0x0040		/* Transmit Collision Error (Corrupt Data May Have Been Sent)	*/
-
-
 /*  ****************  GENERAL PURPOSE TIMER MASKS  **********************/
 /* TIMER_ENABLE Masks													*/
 #define TIMEN0			0x0001		/* Enable Timer 0					*/
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf527/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf527/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/blackstamp.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/blackstamp.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/blackstamp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/blackstamp.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -367,8 +368,8 @@
 #include <linux/i2c-gpio.h>
 
 static struct i2c_gpio_platform_data i2c_gpio_data = {
-	.sda_pin		= 8,
-	.scl_pin		= 9,
+	.sda_pin		= GPIO_PF8,
+	.scl_pin		= GPIO_PF9,
 	.sda_is_open_drain	= 0,
 	.scl_is_open_drain	= 0,
 	.udelay			= 40,
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/cm_bf533.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/cm_bf533.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/cm_bf533.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/cm_bf533.c	2011-01-04 19:50:19.000000000 -0500
@@ -71,7 +71,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -110,12 +110,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -400,7 +400,7 @@
 	}, {
 		.start = IRQ_PF4,
 		.end = IRQ_PF4,
-		.flags = IORESOURCE_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/ezkit.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/ezkit.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/ezkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/ezkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -222,7 +222,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -261,12 +261,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -422,8 +422,8 @@
 #include <linux/i2c-gpio.h>
 
 static struct i2c_gpio_platform_data i2c_gpio_data = {
-	.sda_pin		= 1,
-	.scl_pin		= 0,
+	.sda_pin		= GPIO_PF1,
+	.scl_pin		= GPIO_PF0,
 	.sda_is_open_drain	= 0,
 	.scl_is_open_drain	= 0,
 	.udelay			= 40,
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/H8606.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/H8606.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/H8606.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/H8606.c	2011-01-04 19:50:19.000000000 -0500
@@ -171,7 +171,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -206,12 +206,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 16,
 		.bus_num = 1,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -347,6 +347,7 @@
 		.membase = (void *)0x20200000,
 		.mapbase = 0x20200000,
 		.irq = IRQ_PF8,
+		.irqflags = IRQF_TRIGGER_HIGH,
 		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
 		.iotype = UPIO_MEM,
 		.regshift = 1,
@@ -355,6 +356,7 @@
 		.membase = (void *)0x20200010,
 		.mapbase = 0x20200010,
 		.irq = IRQ_PF8,
+		.irqflags = IRQF_TRIGGER_HIGH,
 		.flags = UPF_BOOT_AUTOCONF | UART_CONFIG_TYPE,
 		.iotype = UPIO_MEM,
 		.regshift = 1,
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/ip0x.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/ip0x.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/ip0x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/ip0x.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,7 @@
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -231,7 +232,7 @@
 	},{
 		.start = IRQ_PF11,
 		.end   = IRQ_PF11,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/stamp.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/stamp.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/boards/stamp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/boards/stamp.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -184,7 +185,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -251,13 +252,15 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
+		.platform_data = "ad1836", /* only includes chip name for the moment */
 		.controller_data = &ad1836_spi_chip_info,
+		.mode = SPI_MODE_3,
 	},
 #endif
 
@@ -494,8 +497,8 @@
 #include <linux/i2c-gpio.h>
 
 static struct i2c_gpio_platform_data i2c_gpio_data = {
-	.sda_pin		= 2,
-	.scl_pin		= 3,
+	.sda_pin		= GPIO_PF2,
+	.scl_pin		= GPIO_PF3,
 	.sda_is_open_drain	= 0,
 	.scl_is_open_drain	= 0,
 	.udelay			= 40,
@@ -533,6 +536,11 @@
 		I2C_BOARD_INFO("bfin-adv7393", 0x2B),
 	},
 #endif
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("ad5252", 0x2f),
+	},
+#endif
 };
 
 static const unsigned int cclk_vlev_datasheet[] =
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/cdefBF532.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/cdefBF532.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/cdefBF532.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/cdefBF532.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,11 +7,6 @@
 #ifndef _CDEF_BF532_H
 #define _CDEF_BF532_H
 
-#include <asm/blackfin.h>
-
-/*include all Core registers and bit definitions*/
-#include "defBF532.h"
-
 /*include core specific register pointer definitions*/
 #include <asm/cdef_LPBlackfin.h>
 
@@ -655,90 +650,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-#if ANOMALY_05000311
-#define BFIN_WRITE_FIO_FLAG(name) \
-static inline void bfin_write_FIO_FLAG_##name(unsigned short val) \
-{ \
-	unsigned long flags; \
-	local_irq_save_hw(flags); \
-	bfin_write16(FIO_FLAG_##name, val); \
-	bfin_read_CHIPID(); \
-	local_irq_restore_hw(flags); \
-}
-BFIN_WRITE_FIO_FLAG(D)
-BFIN_WRITE_FIO_FLAG(C)
-BFIN_WRITE_FIO_FLAG(S)
-BFIN_WRITE_FIO_FLAG(T)
-
-#define BFIN_READ_FIO_FLAG(name) \
-static inline u16 bfin_read_FIO_FLAG_##name(void) \
-{ \
-	unsigned long flags; \
-	u16 ret; \
-	local_irq_save_hw(flags); \
-	ret = bfin_read16(FIO_FLAG_##name); \
-	bfin_read_CHIPID(); \
-	local_irq_restore_hw(flags); \
-	return ret; \
-}
-BFIN_READ_FIO_FLAG(D)
-BFIN_READ_FIO_FLAG(C)
-BFIN_READ_FIO_FLAG(S)
-BFIN_READ_FIO_FLAG(T)
-
-#else
-#define bfin_write_FIO_FLAG_D(val)           bfin_write16(FIO_FLAG_D, val)
-#define bfin_write_FIO_FLAG_C(val)           bfin_write16(FIO_FLAG_C, val)
-#define bfin_write_FIO_FLAG_S(val)           bfin_write16(FIO_FLAG_S, val)
-#define bfin_write_FIO_FLAG_T(val)           bfin_write16(FIO_FLAG_T, val)
-#define bfin_read_FIO_FLAG_T()               bfin_read16(FIO_FLAG_T)
-#define bfin_read_FIO_FLAG_C()               bfin_read16(FIO_FLAG_C)
-#define bfin_read_FIO_FLAG_S()               bfin_read16(FIO_FLAG_S)
-#define bfin_read_FIO_FLAG_D()               bfin_read16(FIO_FLAG_D)
-#endif
-
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr = bfin_read32(SIC_IWR);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR, iwr);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr = bfin_read32(SIC_IWR);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR, iwr);
-	local_irq_restore_hw(flags);
-}
-
 #endif				/* _CDEF_BF532_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/defBF532.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/defBF532.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/defBF532.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/defBF532.h	2011-01-04 19:50:19.000000000 -0500
@@ -681,76 +681,6 @@
 #define PF14_P        14
 #define PF15_P        15
 
-/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  **************** */
-
-/* SPI_CTL Masks */
-#define TIMOD                  0x00000003	/* Transfer initiation mode and interrupt generation */
-#define RDBR_CORE	0x0000		/* 		RDBR Read Initiates, IRQ When RDBR Full		*/
-#define	TDBR_CORE	0x0001		/* 		TDBR Write Initiates, IRQ When TDBR Empty	*/
-#define RDBR_DMA	0x0002		/* 		DMA Read, DMA Until FIFO Empty				*/
-#define TDBR_DMA	0x0003		/* 		DMA Write, DMA Until FIFO Full				*/
-#define SZ                     0x00000004	/* Send Zero (=0) or last (=1) word when TDBR empty. */
-#define GM                     0x00000008	/* When RDBR full, get more (=1) data or discard (=0) incoming Data */
-#define PSSE                   0x00000010	/* Enable (=1) Slave-Select input for Master. */
-#define EMISO                  0x00000020	/* Enable (=1) MISO pin as an output. */
-#define SIZE                   0x00000100	/* Word length (0 => 8 bits, 1 => 16 bits) */
-#define LSBF                   0x00000200	/* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
-#define CPHA                   0x00000400	/* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
-#define CPOL                   0x00000800	/* Clock polarity (0 => active-high, 1 => active-low) */
-#define MSTR                   0x00001000	/* Configures SPI as master (=1) or slave (=0) */
-#define WOM                    0x00002000	/* Open drain (=1) data output enable (for MOSI and MISO) */
-#define SPE                    0x00004000	/* SPI module enable (=1), disable (=0) */
-
-/* SPI_FLG Masks */
-#define FLS1                   0x00000002	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
-#define FLS2                   0x00000004	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLS3                   0x00000008	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
-#define FLS4                   0x00000010	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
-#define FLS5                   0x00000020	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
-#define FLS6                   0x00000040	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
-#define FLS7                   0x00000080	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
-#define FLG1                   0x00000200	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
-#define FLG2                   0x00000400	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLG3                   0x00000800	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
-#define FLG4                   0x00001000	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
-#define FLG5                   0x00002000	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
-#define FLG6                   0x00004000	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
-#define FLG7                   0x00008000	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
-
-/* SPI_FLG Bit Positions */
-#define FLS1_P                 0x00000001	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
-#define FLS2_P                 0x00000002	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLS3_P                 0x00000003	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
-#define FLS4_P                 0x00000004	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
-#define FLS5_P                 0x00000005	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
-#define FLS6_P                 0x00000006	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
-#define FLS7_P                 0x00000007	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
-#define FLG1_P                 0x00000009	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
-#define FLG2_P                 0x0000000A	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLG3_P                 0x0000000B	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
-#define FLG4_P                 0x0000000C	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
-#define FLG5_P                 0x0000000D	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
-#define FLG6_P                 0x0000000E	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
-#define FLG7_P                 0x0000000F	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
-
-/* SPI_STAT Masks */
-#define SPIF                   0x00000001	/* Set (=1) when SPI single-word transfer complete */
-#define MODF                   0x00000002	/* Set (=1) in a master device when some other device tries to become master */
-#define TXE                    0x00000004	/* Set (=1) when transmission occurs with no new data in SPI_TDBR */
-#define TXS                    0x00000008	/* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
-#define RBSY                   0x00000010	/* Set (=1) when data is received with RDBR full */
-#define RXS                    0x00000020	/* SPI_RDBR Data Buffer Status (0=Empty, 1=Full)  */
-#define TXCOL                  0x00000040	/* When set (=1), corrupt data may have been transmitted  */
-
-/* SPIx_FLG Masks																	*/
-#define FLG1E	0xFDFF		/* Activates SPI_FLOUT1 							*/
-#define FLG2E	0xFBFF		/* Activates SPI_FLOUT2								*/
-#define FLG3E	0xF7FF		/* Activates SPI_FLOUT3								*/
-#define FLG4E	0xEFFF		/* Activates SPI_FLOUT4								*/
-#define FLG5E	0xDFFF		/* Activates SPI_FLOUT5								*/
-#define FLG6E	0xBFFF		/* Activates SPI_FLOUT6								*/
-#define FLG7E	0x7FFF		/* Activates SPI_FLOUT7								*/
-
 /* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS  ************* */
 
 /* AMGCTL Masks */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/fio_flag.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/fio_flag.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/fio_flag.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/fio_flag.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_FIO_FLAG_H
+#define _MACH_FIO_FLAG_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+#if ANOMALY_05000311
+#define BFIN_WRITE_FIO_FLAG(name) \
+static inline void bfin_write_FIO_FLAG_##name(unsigned short val) \
+{ \
+	unsigned long flags; \
+	flags = hard_local_irq_save(); \
+	bfin_write16(FIO_FLAG_##name, val); \
+	bfin_read_CHIPID(); \
+	hard_local_irq_restore(flags); \
+}
+BFIN_WRITE_FIO_FLAG(D)
+BFIN_WRITE_FIO_FLAG(C)
+BFIN_WRITE_FIO_FLAG(S)
+BFIN_WRITE_FIO_FLAG(T)
+
+#define BFIN_READ_FIO_FLAG(name) \
+static inline u16 bfin_read_FIO_FLAG_##name(void) \
+{ \
+	unsigned long flags; \
+	u16 ret; \
+	flags = hard_local_irq_save(); \
+	ret = bfin_read16(FIO_FLAG_##name); \
+	bfin_read_CHIPID(); \
+	hard_local_irq_restore(flags); \
+	return ret; \
+}
+BFIN_READ_FIO_FLAG(D)
+BFIN_READ_FIO_FLAG(C)
+BFIN_READ_FIO_FLAG(S)
+BFIN_READ_FIO_FLAG(T)
+
+#else
+#define bfin_write_FIO_FLAG_D(val)           bfin_write16(FIO_FLAG_D, val)
+#define bfin_write_FIO_FLAG_C(val)           bfin_write16(FIO_FLAG_C, val)
+#define bfin_write_FIO_FLAG_S(val)           bfin_write16(FIO_FLAG_S, val)
+#define bfin_write_FIO_FLAG_T(val)           bfin_write16(FIO_FLAG_T, val)
+#define bfin_read_FIO_FLAG_T()               bfin_read16(FIO_FLAG_T)
+#define bfin_read_FIO_FLAG_C()               bfin_read16(FIO_FLAG_C)
+#define bfin_read_FIO_FLAG_S()               bfin_read16(FIO_FLAG_S)
+#define bfin_read_FIO_FLAG_D()               bfin_read16(FIO_FLAG_D)
+#endif
+
+#endif /* _MACH_FIO_FLAG_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf533/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf533/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/cm_bf537e.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/cm_bf537e.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/cm_bf537e.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/cm_bf537e.c	2011-01-04 19:50:19.000000000 -0500
@@ -73,7 +73,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -112,12 +112,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -229,7 +229,7 @@
 	}, {
 		.start = IRQ_PG15,
 		.end = IRQ_PG15,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
@@ -597,13 +597,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/cm_bf537u.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/cm_bf537u.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/cm_bf537u.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/cm_bf537u.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,7 +74,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -113,12 +113,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -230,7 +230,7 @@
 	}, {
 		.start = IRQ_PG15,
 		.end = IRQ_PG15,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
@@ -562,13 +562,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/minotaur.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/minotaur.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/minotaur.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/minotaur.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,13 +68,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/pnav10.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/pnav10.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/pnav10.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/pnav10.c	2011-01-04 19:50:19.000000000 -0500
@@ -99,13 +99,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_RMII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_RMII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
@@ -175,8 +197,8 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -238,13 +260,13 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/stamp.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/stamp.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/stamp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/stamp.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,12 +35,10 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
-#ifdef CONFIG_REGULATOR_ADP_SWITCH
-#include <linux/regulator/adp_switch.h>
-#endif
-#ifdef CONFIG_REGULATOR_AD5398
-#include <linux/regulator/ad5398.h>
+#ifdef CONFIG_REGULATOR_FIXED_VOLTAGE
+#include <linux/regulator/fixed.h>
 #endif
+#include <linux/regulator/machine.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/userspace-consumer.h>
 
@@ -264,7 +262,7 @@
 	}, {
 		.start = IRQ_PF3,
 		.end = IRQ_PF3,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
@@ -329,13 +327,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = PHY_POLL, /* IRQ_MAC_PHYINT */
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
@@ -418,7 +438,7 @@
 static struct resource bfin_plat_nand_resources = {
 	.start = 0x20212000,
 	.end   = 0x20212000 + (1 << MAX(BFIN_NAND_PLAT_CLE, BFIN_NAND_PLAT_ALE)),
-	.flags = IORESOURCE_IO,
+	.flags = IORESOURCE_MEM,
 };
 
 static struct platform_device bfin_async_nand_device = {
@@ -545,6 +565,14 @@
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_ADAV80X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_ADAV80X_MODULE)
+static struct bfin5xx_spi_chip adav801_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_INPUT_AD714X_SPI) || defined(CONFIG_INPUT_AD714X_SPI_MODULE)
 #include <linux/input/ad714x.h>
 static struct bfin5xx_spi_chip ad7147_spi_chip_info = {
@@ -693,6 +721,65 @@
 };
 #endif
 
+#if defined(CONFIG_AD7314) || defined(CONFIG_AD7314_MODULE)
+static struct bfin5xx_spi_chip ad7314_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD7816) || defined(CONFIG_AD7816_MODULE)
+static unsigned short ad7816_platform_data[] = {
+	GPIO_PF4, /* rdwr_pin */
+	GPIO_PF5, /* convert_pin */
+	GPIO_PF7, /* busy_pin */
+	0,
+};
+
+static struct bfin5xx_spi_chip ad7816_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_ADT7310) || defined(CONFIG_ADT7310_MODULE)
+static unsigned long adt7310_platform_data[3] = {
+/* INT bound temperature alarm event. line 1 */
+	IRQ_PG4, IRQF_TRIGGER_LOW,
+/* CT bound temperature alarm event irq_flags. line 0 */
+	IRQF_TRIGGER_LOW,
+};
+
+static struct bfin5xx_spi_chip adt7310_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_AD7298) || defined(CONFIG_AD7298_MODULE)
+static unsigned short ad7298_platform_data[] = {
+	GPIO_PF7, /* busy_pin */
+	0,
+};
+
+static struct bfin5xx_spi_chip ad7298_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_ADT7316_SPI) || defined(CONFIG_ADT7316_SPI_MODULE)
+static unsigned long adt7316_spi_data[2] = {
+	IRQF_TRIGGER_LOW, /* interrupt flags */
+	GPIO_PF7, /* ldac_pin, 0 means DAC/LDAC registers control DAC update */
+};
+
+static struct bfin5xx_spi_chip adt7316_spi_chip_info = {
+	.enable_dma = 0,
+	.bits_per_word = 8,
+};
+#endif
+
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
 #define MMC_SPI_CARD_DETECT_INT IRQ_PF5
 
@@ -824,14 +911,12 @@
 static struct bfin5xx_spi_chip enc28j60_spi_chip_info = {
 	.enable_dma	= 1,
 	.bits_per_word	= 8,
-	.cs_gpio = GPIO_PF10,
 };
 #endif
 
 #if defined(CONFIG_ADF702X) || defined(CONFIG_ADF702X_MODULE)
 static struct bfin5xx_spi_chip adf7021_spi_chip_info = {
 	.bits_per_word = 16,
-	.cs_gpio = GPIO_PF10,
 };
 
 #include <linux/spi/adf702x.h>
@@ -938,6 +1023,13 @@
 };
 #endif
 
+#if defined(CONFIG_AD7476) || defined(CONFIG_AD7476_MODULE)
+static struct bfin5xx_spi_chip spi_ad7476_chip_info = {
+	.enable_dma = 0,         /* use dma transfer with this chip*/
+	.bits_per_word = 8,
+};
+#endif
+
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
 #if defined(CONFIG_MTD_M25P80) \
 	|| defined(CONFIG_MTD_M25P80_MODULE)
@@ -982,7 +1074,7 @@
 		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = 4,/* CONFIG_SND_BLACKFIN_SPI_PFBIT */
+		.chip_select = 4,
 		.platform_data = "ad1836", /* only includes chip name for the moment */
 		.controller_data = &ad1836_spi_chip_info,
 		.mode = SPI_MODE_3,
@@ -1000,6 +1092,17 @@
 	},
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_ADAV80X) || defined(CONFIG_SND_BF5XX_SOC_ADAV80X_MODULE)
+	{
+		.modalias = "adav80x",
+		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1,
+		.controller_data = &adav801_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
 #if defined(CONFIG_INPUT_AD714X_SPI) || defined(CONFIG_INPUT_AD714X_SPI_MODULE)
 	{
 		.modalias = "ad714x_captouch",
@@ -1018,6 +1121,7 @@
 		.modalias = "ad2s90",
 		.bus_num = 0,
 		.chip_select = 3,            /* change it for your board */
+		.mode = SPI_MODE_3,
 		.platform_data = NULL,
 		.controller_data = &ad2s90_spi_chip_info,
 	},
@@ -1044,6 +1148,67 @@
 	},
 #endif
 
+#if defined(CONFIG_AD7314) || defined(CONFIG_AD7314_MODULE)
+	{
+		.modalias = "ad7314",
+		.max_speed_hz = 1000000,
+		.bus_num = 0,
+		.chip_select = 4,            /* CS, change it for your board */
+		.controller_data = &ad7314_spi_chip_info,
+		.mode = SPI_MODE_1,
+	},
+#endif
+
+#if defined(CONFIG_AD7816) || defined(CONFIG_AD7816_MODULE)
+	{
+		.modalias = "ad7818",
+		.max_speed_hz = 1000000,
+		.bus_num = 0,
+		.chip_select = 4,            /* CS, change it for your board */
+		.platform_data = ad7816_platform_data,
+		.controller_data = &ad7816_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_ADT7310) || defined(CONFIG_ADT7310_MODULE)
+	{
+		.modalias = "adt7310",
+		.max_speed_hz = 1000000,
+		.irq = IRQ_PG5,		/* CT alarm event. Line 0 */
+		.bus_num = 0,
+		.chip_select = 4,	/* CS, change it for your board */
+		.platform_data = adt7310_platform_data,
+		.controller_data = &adt7310_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_AD7298) || defined(CONFIG_AD7298_MODULE)
+	{
+		.modalias = "ad7298",
+		.max_speed_hz = 1000000,
+		.bus_num = 0,
+		.chip_select = 4,            /* CS, change it for your board */
+		.platform_data = ad7298_platform_data,
+		.controller_data = &ad7298_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
+#if defined(CONFIG_ADT7316_SPI) || defined(CONFIG_ADT7316_SPI_MODULE)
+	{
+		.modalias = "adt7316",
+		.max_speed_hz = 1000000,
+		.irq = IRQ_PG5,		/* interrupt line */
+		.bus_num = 0,
+		.chip_select = 4,	/* CS, change it for your board */
+		.platform_data = adt7316_spi_data,
+		.controller_data = &adt7316_spi_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
 	{
 		.modalias = "mmc_spi",
@@ -1103,7 +1268,7 @@
 		.max_speed_hz = 20000000,     /* max spi clock (SCK) speed in HZ */
 		.irq = IRQ_PF6,
 		.bus_num = 0,
-		.chip_select = 0,	/* GPIO controlled SSEL */
+		.chip_select = GPIO_PF10 + MAX_CTRL_CS,	/* GPIO controlled SSEL */
 		.controller_data = &enc28j60_spi_chip_info,
 		.mode = SPI_MODE_0,
 	},
@@ -1125,7 +1290,7 @@
 		.modalias = "adf702x",
 		.max_speed_hz = 16000000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = 0,	/* GPIO controlled SSEL */
+		.chip_select = GPIO_PF10 + MAX_CTRL_CS,	/* GPIO controlled SSEL */
 		.controller_data = &adf7021_spi_chip_info,
 		.platform_data = &adf7021_platform_data,
 		.mode = SPI_MODE_0,
@@ -1143,12 +1308,239 @@
 		.mode = SPI_MODE_0,
 	},
 #endif
+#if defined(CONFIG_AD7476) \
+	|| defined(CONFIG_AD7476_MODULE)
+	{
+		.modalias = "ad7476", /* Name of spi_driver for this device */
+		.max_speed_hz = 6250000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0, /* Framework bus number */
+		.chip_select = 1, /* Framework chip select. */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.controller_data = &spi_ad7476_chip_info,
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_ADE7753) \
+	|| defined(CONFIG_ADE7753_MODULE)
+	{
+		.modalias = "ade7753",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_1,
+	},
+#endif
+#if defined(CONFIG_ADE7754) \
+	|| defined(CONFIG_ADE7754_MODULE)
+	{
+		.modalias = "ade7754",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_1,
+	},
+#endif
+#if defined(CONFIG_ADE7758) \
+	|| defined(CONFIG_ADE7758_MODULE)
+	{
+		.modalias = "ade7758",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_1,
+	},
+#endif
+#if defined(CONFIG_ADE7759) \
+	|| defined(CONFIG_ADE7759_MODULE)
+	{
+		.modalias = "ade7759",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_1,
+	},
+#endif
+#if defined(CONFIG_ADE7854_SPI) \
+	|| defined(CONFIG_ADE7854_SPI_MODULE)
+	{
+		.modalias = "ade7854",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_ADIS16060) \
+	|| defined(CONFIG_ADIS16060_MODULE)
+	{
+		.modalias = "adis16060_r",
+		.max_speed_hz = 2900000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = MAX_CTRL_CS + 1, /* CS for read, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_0,
+	},
+	{
+		.modalias = "adis16060_w",
+		.max_speed_hz = 2900000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 2, /* CS for write, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_1,
+	},
+#endif
+#if defined(CONFIG_ADIS16130) \
+	|| defined(CONFIG_ADIS16130_MODULE)
+	{
+		.modalias = "adis16130",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS for read, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_ADIS16201) \
+	|| defined(CONFIG_ADIS16201_MODULE)
+	{
+		.modalias = "adis16201",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16203) \
+	|| defined(CONFIG_ADIS16203_MODULE)
+	{
+		.modalias = "adis16203",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16204) \
+	|| defined(CONFIG_ADIS16204_MODULE)
+	{
+		.modalias = "adis16204",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16209) \
+	|| defined(CONFIG_ADIS16209_MODULE)
+	{
+		.modalias = "adis16209",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16220) \
+	|| defined(CONFIG_ADIS16220_MODULE)
+	{
+		.modalias = "adis16220",
+		.max_speed_hz = 2000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16240) \
+	|| defined(CONFIG_ADIS16240_MODULE)
+	{
+		.modalias = "adis16240",
+		.max_speed_hz = 1500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16260) \
+	|| defined(CONFIG_ADIS16260_MODULE)
+	{
+		.modalias = "adis16260",
+		.max_speed_hz = 1500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16261) \
+	|| defined(CONFIG_ADIS16261_MODULE)
+	{
+		.modalias = "adis16261",
+		.max_speed_hz = 2500000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+	},
+#endif
+#if defined(CONFIG_ADIS16300) \
+	|| defined(CONFIG_ADIS16300_MODULE)
+	{
+		.modalias = "adis16300",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16350) \
+	|| defined(CONFIG_ADIS16350_MODULE)
+	{
+		.modalias = "adis16364",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 5, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+		.irq = IRQ_PF4,
+	},
+#endif
+#if defined(CONFIG_ADIS16400) \
+	|| defined(CONFIG_ADIS16400_MODULE)
+	{
+		.modalias = "adis16400",
+		.max_speed_hz = 1000000,     /* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = 1, /* CS, change it for your board */
+		.platform_data = NULL, /* No spi_driver specific config */
+		.mode = SPI_MODE_3,
+	},
+#endif
 };
 
 #if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
 /* SPI controller data */
 static struct bfin5xx_spi_master bfin_spi0_info = {
-	.num_chipselect = 8,
+	.num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
 };
@@ -1645,7 +2037,7 @@
 };
 
 	/*
-	 *  ADP5520/5501 Multifuction Device Init Data
+	 *  ADP5520/5501 Multifunction Device Init Data
 	 */
 
 static struct adp5520_platform_data adp5520_pdev_data = {
@@ -1773,12 +2165,6 @@
 	.consumer_supplies     = &ad5398_consumer,
 };
 
-static struct ad5398_platform_data ad5398_i2c_platform_data = {
-	.current_bits = 10,
-	.current_offset = 4,
-	.regulator_data = &ad5398_regulator_data,
-};
-
 #if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
 	defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
 static struct platform_device ad5398_virt_consumer_device = {
@@ -1811,7 +2197,34 @@
 #endif
 #endif
 
+#if defined(CONFIG_ADT7410) || defined(CONFIG_ADT7410_MODULE)
+/* INT bound temperature alarm event. line 1 */
+static unsigned long adt7410_platform_data[2] = {
+	IRQ_PG4, IRQF_TRIGGER_LOW,
+};
+#endif
+
+#if defined(CONFIG_ADT7316_I2C) || defined(CONFIG_ADT7316_I2C_MODULE)
+/* INT bound temperature alarm event. line 1 */
+static unsigned long adt7316_i2c_data[2] = {
+	IRQF_TRIGGER_LOW, /* interrupt flags */
+	GPIO_PF4, /* ldac_pin, 0 means DAC/LDAC registers control DAC update */
+};
+#endif
+
 static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_SND_BF5XX_SOC_AD193X) || defined(CONFIG_SND_BF5XX_SOC_AD193X_MODULE)
+	{
+		I2C_BOARD_INFO("ad1937", 0x04),
+	},
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_ADAV80X) || defined(CONFIG_SND_BF5XX_SOC_ADAV80X_MODULE)
+	{
+		I2C_BOARD_INFO("adav803", 0x10),
+	},
+#endif
+
 #if defined(CONFIG_INPUT_AD714X_I2C) || defined(CONFIG_INPUT_AD714X_I2C_MODULE)
 	{
 		I2C_BOARD_INFO("ad7142_captouch", 0x2C),
@@ -1843,12 +2256,7 @@
 	{
 		I2C_BOARD_INFO("ad7414", 0x9),
 		.irq = IRQ_PG5,
-		/*
-		 * platform_data pointer is borrwoed by the driver to
-		 * store custimer defined IRQ ALART level mode.
-		 * only IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW are valid.
-		 */
-		.platform_data = (void *)IRQF_TRIGGER_LOW,
+		.irq_flags = IRQF_TRIGGER_LOW,
 	},
 #endif
 
@@ -1856,12 +2264,56 @@
 	{
 		I2C_BOARD_INFO("ad7417", 0xb),
 		.irq = IRQ_PG5,
-		/*
-		 * platform_data pointer is borrwoed by the driver to
-		 * store custimer defined IRQ ALART level mode.
-		 * only IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW are valid.
-		 */
-		.platform_data = (void *)IRQF_TRIGGER_LOW,
+		.irq_flags = IRQF_TRIGGER_LOW,
+		.platform_data = (void *)GPIO_PF4,
+	},
+#endif
+
+#if defined(CONFIG_ADE7854_I2C) || defined(CONFIG_ADE7854_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("ade7854", 0x38),
+	},
+#endif
+
+#if defined(CONFIG_ADT75) || defined(CONFIG_ADT75_MODULE)
+	{
+		I2C_BOARD_INFO("adt75", 0x9),
+		.irq = IRQ_PG5,
+		.irq_flags = IRQF_TRIGGER_LOW,
+	},
+#endif
+
+#if defined(CONFIG_ADT7408) || defined(CONFIG_ADT7408_MODULE)
+	{
+		I2C_BOARD_INFO("adt7408", 0x18),
+		.irq = IRQ_PG5,
+		.irq_flags = IRQF_TRIGGER_LOW,
+	},
+#endif
+
+#if defined(CONFIG_ADT7410) || defined(CONFIG_ADT7410_MODULE)
+	{
+		I2C_BOARD_INFO("adt7410", 0x48),
+		/* CT critical temperature event. line 0 */
+		.irq = IRQ_PG5,
+		.irq_flags = IRQF_TRIGGER_LOW,
+		.platform_data = (void *)&adt7410_platform_data,
+	},
+#endif
+
+#if defined(CONFIG_AD7291) || defined(CONFIG_AD7291_MODULE)
+	{
+		I2C_BOARD_INFO("ad7291", 0x20),
+		.irq = IRQ_PG5,
+		.irq_flags = IRQF_TRIGGER_LOW,
+	},
+#endif
+
+#if defined(CONFIG_ADT7316_I2C) || defined(CONFIG_ADT7316_I2C_MODULE)
+	{
+		I2C_BOARD_INFO("adt7316", 0x48),
+		.irq = IRQ_PG6,
+		.platform_data = (void *)&adt7316_i2c_data,
 	},
 #endif
 
@@ -1917,7 +2369,7 @@
 #endif
 #if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
 	{
-		I2C_BOARD_INFO("bf537-lq035-ad5280", 0x2C),
+		I2C_BOARD_INFO("bf537-lq035-ad5280", 0x2F),
 	},
 #endif
 #if defined(CONFIG_BACKLIGHT_ADP8870) || defined(CONFIG_BACKLIGHT_ADP8870_MODULE)
@@ -1954,7 +2406,7 @@
 #if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
 	{
 		I2C_BOARD_INFO("ad5398", 0xC),
-		.platform_data = (void *)&ad5398_i2c_platform_data,
+		.platform_data = (void *)&ad5398_regulator_data,
 	},
 #endif
 #if defined(CONFIG_BACKLIGHT_ADP8860) || defined(CONFIG_BACKLIGHT_ADP8860_MODULE)
@@ -1963,6 +2415,16 @@
 		.platform_data = (void *)&adp8860_pdata,
 	},
 #endif
+#if defined(CONFIG_SND_SOC_ADAU1373) || defined(CONFIG_SND_SOC_ADAU1373_MODULE)
+	{
+		I2C_BOARD_INFO("adau1373", 0x1A),
+	},
+#endif
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("ad5252", 0x2e),
+	},
+#endif
 };
 
 #if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -2147,50 +2609,38 @@
 };
 #endif
 
-#if defined(CONFIG_REGULATOR_ADP_SWITCH) || defined(CONFIG_REGULATOR_ADP_SWITCH_MODULE)
-#define REGULATOR_ADP122        "adp122"
-#define REGULATOR_ADP150        "adp150"
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
+#define REGULATOR_ADP122	"adp122"
+#define REGULATOR_ADP122_UV	2500000
 
 static struct regulator_consumer_supply adp122_consumers = {
 		.supply = REGULATOR_ADP122,
 };
 
-static struct regulator_consumer_supply adp150_consumers = {
-		.supply = REGULATOR_ADP150,
-};
-
-static struct regulator_init_data adp_switch_regulator_data[] = {
-	{
-		.constraints = {
-			.name = REGULATOR_ADP122,
-			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-			.min_uA = 0,
-			.max_uA = 300000,
-		},
-		.num_consumer_supplies = 1,	/* only 1 */
-		.consumer_supplies     = &adp122_consumers,
-		.driver_data	       = (void *)GPIO_PF2, /* gpio port only */
-	},
-	{
-		.constraints = {
-			.name = REGULATOR_ADP150,
-			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
-			.min_uA = 0,
-			.max_uA = 150000,
-		},
-		.num_consumer_supplies = 1,	/* only 1 */
-		.consumer_supplies     = &adp150_consumers,
-		.driver_data	       = (void *)GPIO_PF3, /* gpio port only */
+static struct regulator_init_data adp_switch_regulator_data = {
+	.constraints = {
+		.name = REGULATOR_ADP122,
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+		.min_uV = REGULATOR_ADP122_UV,
+		.max_uV = REGULATOR_ADP122_UV,
+		.min_uA = 0,
+		.max_uA = 300000,
 	},
+	.num_consumer_supplies = 1,	/* only 1 */
+	.consumer_supplies     = &adp122_consumers,
 };
 
-static struct adp_switch_platform_data adp_switch_pdata = {
-	.regulator_num = ARRAY_SIZE(adp_switch_regulator_data),
-	.regulator_data = adp_switch_regulator_data,
+static struct fixed_voltage_config adp_switch_pdata = {
+	.supply_name = REGULATOR_ADP122,
+	.microvolts = REGULATOR_ADP122_UV,
+	.gpio = GPIO_PF2,
+	.enable_high = 1,
+	.enabled_at_boot = 0,
+	.init_data = &adp_switch_regulator_data,
 };
 
 static struct platform_device adp_switch_device = {
-	.name = "adp_switch",
+	.name = "reg-fixed-voltage",
 	.id = 0,
 	.dev = {
 		.platform_data = &adp_switch_pdata,
@@ -2216,27 +2666,26 @@
 		.platform_data = &adp122_userspace_comsumer_data,
 	},
 };
+#endif
+#endif
 
-static struct regulator_bulk_data adp150_bulk_data = {
-	.supply = REGULATOR_ADP150,
-};
+#if defined(CONFIG_IIO_GPIO_TRIGGER) || \
+	defined(CONFIG_IIO_GPIO_TRIGGER_MODULE)
 
-static struct regulator_userspace_consumer_data adp150_userspace_comsumer_data = {
-	.name = REGULATOR_ADP150,
-	.num_supplies = 1,
-	.supplies = &adp150_bulk_data,
+static struct resource iio_gpio_trigger_resources[] = {
+	[0] = {
+		.start  = IRQ_PF5,
+		.end    = IRQ_PF5,
+		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+	},
 };
 
-static struct platform_device adp150_userspace_consumer_device = {
-	.name = "reg-userspace-consumer",
-	.id = 1,
-	.dev = {
-		.platform_data = &adp150_userspace_comsumer_data,
-	},
+static struct platform_device iio_gpio_trigger = {
+	.name = "iio_gpio_trigger",
+	.num_resources = ARRAY_SIZE(iio_gpio_trigger_resources),
+	.resource = iio_gpio_trigger_resources,
 };
 #endif
-#endif
-
 
 static struct platform_device *stamp_devices[] __initdata = {
 
@@ -2369,14 +2818,18 @@
 #endif
 #endif
 
-#if defined(CONFIG_REGULATOR_ADP_SWITCH) || defined(CONFIG_REGULATOR_ADP_SWITCH_MODULE)
+#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
 	&adp_switch_device,
 #if defined(CONFIG_REGULATOR_USERSPACE_CONSUMER) || \
 	defined(CONFIG_REGULATOR_USERSPACE_CONSUMER_MODULE)
 	&adp122_userspace_consumer_device,
-	&adp150_userspace_consumer_device,
 #endif
 #endif
+
+#if defined(CONFIG_IIO_GPIO_TRIGGER) || \
+	defined(CONFIG_IIO_GPIO_TRIGGER_MODULE)
+	&iio_gpio_trigger,
+#endif
 };
 
 static int __init stamp_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/tcm_bf537.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/tcm_bf537.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/boards/tcm_bf537.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/boards/tcm_bf537.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,7 +74,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -113,12 +113,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -230,7 +230,7 @@
 	}, {
 		.start = IRQ_PG15,
 		.end = IRQ_PG15,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
@@ -564,13 +564,35 @@
 #endif
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+#include <linux/bfin_mac.h>
+static const unsigned short bfin_mac_peripherals[] = P_MII0;
+
+static struct bfin_phydev_platform_data bfin_phydev_data[] = {
+	{
+		.addr = 1,
+		.irq = IRQ_MAC_PHYINT,
+	},
+};
+
+static struct bfin_mii_bus_platform_data bfin_mii_bus_data = {
+	.phydev_number = 1,
+	.phydev_data = bfin_phydev_data,
+	.phy_mode = PHY_INTERFACE_MODE_MII,
+	.mac_peripherals = bfin_mac_peripherals,
+};
+
 static struct platform_device bfin_mii_bus = {
 	.name = "bfin_mii_bus",
+	.dev = {
+		.platform_data = &bfin_mii_bus_data,
+	}
 };
 
 static struct platform_device bfin_mac_device = {
 	.name = "bfin_mac",
-	.dev.platform_data = &bfin_mii_bus,
+	.dev = {
+		.platform_data = &bfin_mii_bus,
+	}
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/cdefBF534.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/cdefBF534.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/cdefBF534.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/cdefBF534.h	2011-01-04 19:50:19.000000000 -0500
@@ -1750,48 +1750,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr = bfin_read32(SIC_IWR);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR, iwr);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr = bfin_read32(SIC_IWR);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR, iwr);
-	local_irq_restore_hw(flags);
-}
-
 #endif				/* _CDEF_BF534_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/defBF534.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/defBF534.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/defBF534.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/defBF534.h	2011-01-04 19:50:19.000000000 -0500
@@ -1071,50 +1071,6 @@
 #define FPE			0x10	/* Force Parity Error On Transmit       */
 #define FFE			0x20	/* Force Framing Error On Transmit      */
 
-/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  ****************************/
-/* SPI_CTL Masks																	*/
-#define	TIMOD		0x0003	/* Transfer Initiate Mode                                                       */
-#define RDBR_CORE	0x0000	/*              RDBR Read Initiates, IRQ When RDBR Full         */
-#define	TDBR_CORE	0x0001	/*              TDBR Write Initiates, IRQ When TDBR Empty       */
-#define RDBR_DMA	0x0002	/*              DMA Read, DMA Until FIFO Empty                          */
-#define TDBR_DMA	0x0003	/*              DMA Write, DMA Until FIFO Full                          */
-#define SZ			0x0004	/* Send Zero (When TDBR Empty, Send Zero/Last*)         */
-#define GM			0x0008	/* Get More (When RDBR Full, Overwrite/Discard*)        */
-#define PSSE		0x0010	/* Slave-Select Input Enable                                            */
-#define EMISO		0x0020	/* Enable MISO As Output                                                        */
-#define SIZE		0x0100	/* Size of Words (16/8* Bits)                                           */
-#define LSBF		0x0200	/* LSB First                                                                            */
-#define CPHA		0x0400	/* Clock Phase                                                                          */
-#define CPOL		0x0800	/* Clock Polarity                                                                       */
-#define MSTR		0x1000	/* Master/Slave*                                                                        */
-#define WOM			0x2000	/* Write Open Drain Master                                                      */
-#define SPE			0x4000	/* SPI Enable                                                                           */
-
-/* SPI_FLG Masks																	*/
-#define FLS1		0x0002	/* Enables SPI_FLOUT1 as SPI Slave-Select Output        */
-#define FLS2		0x0004	/* Enables SPI_FLOUT2 as SPI Slave-Select Output        */
-#define FLS3		0x0008	/* Enables SPI_FLOUT3 as SPI Slave-Select Output        */
-#define FLS4		0x0010	/* Enables SPI_FLOUT4 as SPI Slave-Select Output        */
-#define FLS5		0x0020	/* Enables SPI_FLOUT5 as SPI Slave-Select Output        */
-#define FLS6		0x0040	/* Enables SPI_FLOUT6 as SPI Slave-Select Output        */
-#define FLS7		0x0080	/* Enables SPI_FLOUT7 as SPI Slave-Select Output        */
-#define FLG1		0xFDFF	/* Activates SPI_FLOUT1                                                         */
-#define FLG2		0xFBFF	/* Activates SPI_FLOUT2                                                         */
-#define FLG3		0xF7FF	/* Activates SPI_FLOUT3                                                         */
-#define FLG4		0xEFFF	/* Activates SPI_FLOUT4                                                         */
-#define FLG5		0xDFFF	/* Activates SPI_FLOUT5                                                         */
-#define FLG6		0xBFFF	/* Activates SPI_FLOUT6                                                         */
-#define FLG7		0x7FFF	/* Activates SPI_FLOUT7                                                         */
-
-/* SPI_STAT Masks																				*/
-#define SPIF		0x0001	/* SPI Finished (Single-Word Transfer Complete)                                 */
-#define MODF		0x0002	/* Mode Fault Error (Another Device Tried To Become Master)             */
-#define TXE			0x0004	/* Transmission Error (Data Sent With No New Data In TDBR)              */
-#define TXS			0x0008	/* SPI_TDBR Data Buffer Status (Full/Empty*)                                    */
-#define RBSY		0x0010	/* Receive Error (Data Received With RDBR Full)                                 */
-#define RXS			0x0020	/* SPI_RDBR Data Buffer Status (Full/Empty*)                                    */
-#define TXCOL		0x0040	/* Transmit Collision Error (Corrupt Data May Have Been Sent)   */
-
 /*  ****************  GENERAL PURPOSE TIMER MASKS  **********************/
 /* TIMER_ENABLE Masks													*/
 #define TIMEN0			0x0001	/* Enable Timer 0                                       */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr = bfin_read32(SIC_IWR);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR, iwr);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/Kconfig linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/Kconfig
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf537/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf537/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -14,8 +14,8 @@
 	int "IRQ_DMA_ERROR Generic"
 	default 7
 config IRQ_ERROR
-	int "IRQ_ERROR: CAN MAC SPORT0 SPORT1 SPI UART0 UART1"
-	default 7
+	int "IRQ_ERROR: PPI CAN MAC SPORT0 SPORT1 SPI UART0 UART1"
+	default 11
 config IRQ_RTC
 	int "IRQ_RTC"
 	default 8
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/boards/ezkit.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/boards/ezkit.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/boards/ezkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/boards/ezkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -695,7 +695,7 @@
 };
 
 static struct bfin5xx_spi_master bf538_spi_master_info1 = {
-	.num_chipselect = 8,
+	.num_chipselect = 2,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
@@ -711,7 +711,7 @@
 };
 
 static struct bfin5xx_spi_master bf538_spi_master_info2 = {
-	.num_chipselect = 8,
+	.num_chipselect = 2,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI2_SCK, P_SPI2_MISO, P_SPI2_MOSI, 0},
 };
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/cdefBF538.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/cdefBF538.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/cdefBF538.h	2011-01-04 19:50:19.000000000 -0500
@@ -2027,54 +2027,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/defBF539.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/defBF539.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/defBF539.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/defBF539.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 /* System Interrupt Controller (0xFFC00100 - 0xFFC001FF) */
 #define	SWRST			0xFFC00100  /* Software	Reset Register (16-bit) */
 #define	SYSCR			0xFFC00104  /* System Configuration registe */
+#define	SIC_RVECT		0xFFC00108
 #define	SIC_IMASK0		0xFFC0010C  /* Interrupt Mask Register */
 #define	SIC_IAR0		0xFFC00110  /* Interrupt Assignment Register 0 */
 #define	SIC_IAR1		0xFFC00114  /* Interrupt Assignment Register 1 */
@@ -1894,78 +1895,6 @@
 #define	PE14_P	0xE
 #define	PE15_P	0xF
 
-
-/* ***********	SERIAL PERIPHERAL INTERFACE (SPI) MASKS	 **************** */
-/* SPIx_CTL Masks */
-#define	TIMOD		0x0003		/* Transfer Initiate Mode */
-#define	RDBR_CORE	0x0000		/*		RDBR Read Initiates, IRQ When RDBR Full */
-#define	TDBR_CORE	0x0001		/*		TDBR Write Initiates, IRQ When TDBR Empty */
-#define	RDBR_DMA	0x0002		/*		DMA Read, DMA Until FIFO Empty */
-#define	TDBR_DMA	0x0003		/*		DMA Write, DMA Until FIFO Full */
-#define	SZ			0x0004		/* Send	Zero (When TDBR	Empty, Send Zero/Last*) */
-#define	GM			0x0008		/* Get More (When RDBR Full, Overwrite/Discard*) */
-#define	PSSE		0x0010		/* Slave-Select	Input Enable */
-#define	EMISO		0x0020		/* Enable MISO As Output */
-#define	SIZE		0x0100		/* Size	of Words (16/8*	Bits) */
-#define	LSBF		0x0200		/* LSB First			 */
-#define	CPHA		0x0400		/* Clock Phase			 */
-#define	CPOL		0x0800		/* Clock Polarity		 */
-#define	MSTR		0x1000		/* Master/Slave*		 */
-#define	WOM			0x2000		/* Write Open Drain Master */
-#define	SPE			0x4000		/* SPI Enable			 */
-
-/* SPIx_FLG Masks */
-#define	FLS1	0x0002	/* Enables (=1)	SPI_FLOUT1 as flag output for SPI Slave-select */
-#define	FLS2	0x0004	/* Enables (=1)	SPI_FLOUT2 as flag output for SPI Slave-select */
-#define	FLS3	0x0008	/* Enables (=1)	SPI_FLOUT3 as flag output for SPI Slave-select */
-#define	FLS4	0x0010	/* Enables (=1)	SPI_FLOUT4 as flag output for SPI Slave-select */
-#define	FLS5	0x0020	/* Enables (=1)	SPI_FLOUT5 as flag output for SPI Slave-select */
-#define	FLS6	0x0040	/* Enables (=1)	SPI_FLOUT6 as flag output for SPI Slave-select */
-#define	FLS7	0x0080	/* Enables (=1)	SPI_FLOUT7 as flag output for SPI Slave-select */
-
-#define	FLG1	0x0200	/* Activates (=0) SPI_FLOUT1 as	flag output for	SPI Slave-select  */
-#define	FLG2	0x0400	/* Activates (=0) SPI_FLOUT2 as	flag output for	SPI Slave-select */
-#define	FLG3	0x0800	/* Activates (=0) SPI_FLOUT3 as	flag output for	SPI Slave-select  */
-#define	FLG4	0x1000	/* Activates (=0) SPI_FLOUT4 as	flag output for	SPI Slave-select  */
-#define	FLG5	0x2000	/* Activates (=0) SPI_FLOUT5 as	flag output for	SPI Slave-select  */
-#define	FLG6	0x4000	/* Activates (=0) SPI_FLOUT6 as	flag output for	SPI Slave-select  */
-#define	FLG7	0x8000	/* Activates (=0) SPI_FLOUT7 as	flag output for	SPI Slave-select */
-
-/* SPIx_FLG Bit	Positions */
-#define	FLS1_P	0x0001	/* Enables (=1)	SPI_FLOUT1 as flag output for SPI Slave-select */
-#define	FLS2_P	0x0002	/* Enables (=1)	SPI_FLOUT2 as flag output for SPI Slave-select */
-#define	FLS3_P	0x0003	/* Enables (=1)	SPI_FLOUT3 as flag output for SPI Slave-select */
-#define	FLS4_P	0x0004	/* Enables (=1)	SPI_FLOUT4 as flag output for SPI Slave-select */
-#define	FLS5_P	0x0005	/* Enables (=1)	SPI_FLOUT5 as flag output for SPI Slave-select */
-#define	FLS6_P	0x0006	/* Enables (=1)	SPI_FLOUT6 as flag output for SPI Slave-select */
-#define	FLS7_P	0x0007	/* Enables (=1)	SPI_FLOUT7 as flag output for SPI Slave-select */
-#define	FLG1_P	0x0009	/* Activates (=0) SPI_FLOUT1 as	flag output for	SPI Slave-select  */
-#define	FLG2_P	0x000A	/* Activates (=0) SPI_FLOUT2 as	flag output for	SPI Slave-select */
-#define	FLG3_P	0x000B	/* Activates (=0) SPI_FLOUT3 as	flag output for	SPI Slave-select  */
-#define	FLG4_P	0x000C	/* Activates (=0) SPI_FLOUT4 as	flag output for	SPI Slave-select  */
-#define	FLG5_P	0x000D	/* Activates (=0) SPI_FLOUT5 as	flag output for	SPI Slave-select  */
-#define	FLG6_P	0x000E	/* Activates (=0) SPI_FLOUT6 as	flag output for	SPI Slave-select  */
-#define	FLG7_P	0x000F	/* Activates (=0) SPI_FLOUT7 as	flag output for	SPI Slave-select */
-
-/* SPIx_STAT Masks */
-#define	SPIF	0x0001	/* Set (=1) when SPI single-word transfer complete */
-#define	MODF	0x0002	/* Set (=1) in a master	device when some other device tries to become master */
-#define	TXE		0x0004	/* Set (=1) when transmission occurs with no new data in SPI_TDBR */
-#define	TXS		0x0008	/* SPI_TDBR Data Buffer	Status (0=Empty, 1=Full) */
-#define	RBSY	0x0010	/* Set (=1) when data is received with RDBR full */
-#define	RXS		0x0020	/* SPI_RDBR Data Buffer	Status (0=Empty, 1=Full)  */
-#define	TXCOL	0x0040	/* When	set (=1), corrupt data may have	been transmitted  */
-
-/* SPIx_FLG Masks										 */
-#define	FLG1E	0xFDFF		/* Activates SPI_FLOUT1	 */
-#define	FLG2E	0xFBFF		/* Activates SPI_FLOUT2	 */
-#define	FLG3E	0xF7FF		/* Activates SPI_FLOUT3	 */
-#define	FLG4E	0xEFFF		/* Activates SPI_FLOUT4	 */
-#define	FLG5E	0xDFFF		/* Activates SPI_FLOUT5	 */
-#define	FLG6E	0xBFFF		/* Activates SPI_FLOUT6	 */
-#define	FLG7E	0x7FFF		/* Activates SPI_FLOUT7	 */
-
-
 /* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS	************* */
 /* EBIU_AMGCTL Masks */
 #define	AMCKEN		0x0001	/* Enable CLKOUT */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf538/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf538/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/boards/cm_bf548.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/boards/cm_bf548.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/boards/cm_bf548.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/boards/cm_bf548.c	2011-01-04 19:50:19.000000000 -0500
@@ -753,6 +753,44 @@
 };
 #endif
 
+#if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
+unsigned short bfin_can_peripherals[] = {
+	P_CAN0_RX, P_CAN0_TX, 0
+};
+
+static struct resource bfin_can_resources[] = {
+	{
+		.start = 0xFFC02A00,
+		.end = 0xFFC02FFF,
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.start = IRQ_CAN0_RX,
+		.end = IRQ_CAN0_RX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_CAN0_TX,
+		.end = IRQ_CAN0_TX,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start = IRQ_CAN0_ERROR,
+		.end = IRQ_CAN0_ERROR,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device bfin_can_device = {
+	.name = "bfin_can",
+	.num_resources = ARRAY_SIZE(bfin_can_resources),
+	.resource = bfin_can_resources,
+	.dev = {
+		.platform_data = &bfin_can_peripherals, /* Passed to driver */
+	},
+};
+#endif
+
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 static struct mtd_partition para_partitions[] = {
 	{
@@ -928,7 +966,7 @@
 
 /* SPI controller data */
 static struct bfin5xx_spi_master bf54x_spi_master_info0 = {
-	.num_chipselect = 3,
+	.num_chipselect = 4,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
 };
@@ -944,7 +982,7 @@
 };
 
 static struct bfin5xx_spi_master bf54x_spi_master_info1 = {
-	.num_chipselect = 3,
+	.num_chipselect = 4,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
@@ -1152,6 +1190,11 @@
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&para_flash_device,
 #endif
+
+#if defined(CONFIG_CAN_BFIN) || defined(CONFIG_CAN_BFIN_MODULE)
+	&bfin_can_device,
+#endif
+
 };
 
 static int __init cm_bf548_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/boards/ezkit.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/boards/ezkit.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/boards/ezkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/boards/ezkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -837,8 +837,12 @@
 #if defined(CONFIG_MTD_NAND_BF5XX) || defined(CONFIG_MTD_NAND_BF5XX_MODULE)
 static struct mtd_partition partition_info[] = {
 	{
-		.name = "linux kernel(nand)",
+		.name = "bootloader(nand)",
 		.offset = 0,
+		.size = 0x80000,
+	}, {
+		.name = "linux kernel(nand)",
+		.offset = MTDPART_OFS_APPEND,
 		.size = 4 * 1024 * 1024,
 	},
 	{
@@ -901,7 +905,7 @@
 static struct mtd_partition ezkit_partitions[] = {
 	{
 		.name       = "bootloader(nor)",
-		.size       = 0x40000,
+		.size       = 0x80000,
 		.offset     = 0,
 	}, {
 		.name       = "linux kernel(nor)",
@@ -943,7 +947,7 @@
 static struct mtd_partition bfin_spi_flash_partitions[] = {
 	{
 		.name = "bootloader(spi)",
-		.size = 0x00040000,
+		.size = 0x00080000,
 		.offset = 0,
 		.mask_flags = MTD_CAP_ROM
 	}, {
@@ -966,8 +970,8 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -1023,13 +1027,13 @@
 		.mode = SPI_MODE_3,
 	},
 #endif
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 1,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -1107,7 +1111,7 @@
 
 /* SPI controller data */
 static struct bfin5xx_spi_master bf54x_spi_master_info0 = {
-	.num_chipselect = 3,
+	.num_chipselect = 4,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
 };
@@ -1123,7 +1127,7 @@
 };
 
 static struct bfin5xx_spi_master bf54x_spi_master_info1 = {
-	.num_chipselect = 3,
+	.num_chipselect = 4,
 	.enable_dma = 1,  /* master has the ability to do dma transfer */
 	.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
 };
@@ -1206,6 +1210,11 @@
 		.platform_data = (void *)&adxl34x_info,
 	},
 #endif
+#if defined(CONFIG_BFIN_TWI_LCD) || defined(CONFIG_BFIN_TWI_LCD_MODULE)
+	{
+		I2C_BOARD_INFO("ad5252", 0x2f),
+	},
+#endif
 };
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/dma.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/dma.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -63,6 +63,7 @@
 		break;
 	case CH_SPORT1_TX:
 		ret_irq = IRQ_SPORT1_TX;
+		break;
 	case CH_SPI0:
 		ret_irq = IRQ_SPI0;
 		break;
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,8 @@
 
 /* SIC Registers */
 
+#define bfin_read_SIC_RVECT()		bfin_read32(SIC_RVECT)
+#define bfin_write_SIC_RVECT(val)	bfin_write32(SIC_RVECT, val)
 #define bfin_read_SIC_IMASK0()		bfin_read32(SIC_IMASK0)
 #define bfin_write_SIC_IMASK0(val)	bfin_write32(SIC_IMASK0, val)
 #define bfin_read_SIC_IMASK1()		bfin_read32(SIC_IMASK1)
@@ -2648,61 +2650,5 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1, iwr2;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	iwr2 = bfin_read32(SIC_IWR2);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-	bfin_write32(SIC_IWR2, 0);
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	bfin_write32(SIC_IWR2, iwr2);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1, iwr2;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SIC_IWR0);
-	iwr1 = bfin_read32(SIC_IWR1);
-	iwr2 = bfin_read32(SIC_IWR2);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-	bfin_write32(SIC_IWR1, 0);
-	bfin_write32(SIC_IWR2, 0);
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SIC_IWR0, iwr0);
-	bfin_write32(SIC_IWR1, iwr1);
-	bfin_write32(SIC_IWR2, iwr2);
-	local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF54X_H */
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 
 /* SIC Registers */
 
+#define                        SIC_RVECT  0xffc00108
 #define                       SIC_IMASK0  0xffc0010c   /* System Interrupt Mask Register 0 */
 #define                       SIC_IMASK1  0xffc00110   /* System Interrupt Mask Register 1 */
 #define                       SIC_IMASK2  0xffc00114   /* System Interrupt Mask Register 2 */
@@ -2061,56 +2062,6 @@
 #define                  LOW_EVEN  0xff0000   /* Lower Limit for Even Bytes (Luma) */
 #define                 HIGH_EVEN  0xff000000 /* Upper Limit for Even Bytes (Luma) */
 
-/* Bit masks for SPIx_BAUD */
-
-#define                  SPI_BAUD  0xffff     /* Baud Rate */
-
-/* Bit masks for SPIx_CTL */
-
-#define                       SPE  0x4000     /* SPI Enable */
-#define                       WOM  0x2000     /* Write Open Drain Master */
-#define                      MSTR  0x1000     /* Master Mode */
-#define                      CPOL  0x800      /* Clock Polarity */
-#define                      CPHA  0x400      /* Clock Phase */
-#define                      LSBF  0x200      /* LSB First */
-#define                      SIZE  0x100      /* Size of Words */
-#define                     EMISO  0x20       /* Enable MISO Output */
-#define                      PSSE  0x10       /* Slave-Select Enable */
-#define                        GM  0x8        /* Get More Data */
-#define                        SZ  0x4        /* Send Zero */
-#define                     TIMOD  0x3        /* Transfer Initiation Mode */
-
-/* Bit masks for SPIx_FLG */
-
-#define                      FLS1  0x2        /* Slave Select Enable 1 */
-#define                      FLS2  0x4        /* Slave Select Enable 2 */
-#define                      FLS3  0x8        /* Slave Select Enable 3 */
-#define                      FLG1  0x200      /* Slave Select Value 1 */
-#define                      FLG2  0x400      /* Slave Select Value 2 */
-#define                      FLG3  0x800      /* Slave Select Value 3 */
-
-/* Bit masks for SPIx_STAT */
-
-#define                     TXCOL  0x40       /* Transmit Collision Error */
-#define                       RXS  0x20       /* RDBR Data Buffer Status */
-#define                      RBSY  0x10       /* Receive Error */
-#define                       TXS  0x8        /* TDBR Data Buffer Status */
-#define                       TXE  0x4        /* Transmission Error */
-#define                      MODF  0x2        /* Mode Fault Error */
-#define                      SPIF  0x1        /* SPI Finished */
-
-/* Bit masks for SPIx_TDBR */
-
-#define                      TDBR  0xffff     /* Transmit Data Buffer */
-
-/* Bit masks for SPIx_RDBR */
-
-#define                      RDBR  0xffff     /* Receive Data Buffer */
-
-/* Bit masks for SPIx_SHADOW */
-
-#define                    SHADOW  0xffff     /* RDBR Shadow */
-
 /* ************************************************ */
 /* The TWI bit masks fields are from the ADSP-BF538 */
 /* and they have not been verified as the final     */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf548/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf548/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1, iwr2;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	iwr2 = bfin_read32(SIC_IWR2);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+	bfin_write32(SIC_IWR2, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	bfin_write32(SIC_IWR2, iwr2);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1, iwr2;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SIC_IWR0);
+	iwr1 = bfin_read32(SIC_IWR1);
+	iwr2 = bfin_read32(SIC_IWR2);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+	bfin_write32(SIC_IWR1, 0);
+	bfin_write32(SIC_IWR2, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SIC_IWR0, iwr0);
+	bfin_write32(SIC_IWR1, iwr1);
+	bfin_write32(SIC_IWR2, iwr2);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/acvilon.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/acvilon.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/acvilon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/acvilon.c	2011-01-04 19:50:19.000000000 -0500
@@ -302,7 +302,7 @@
 static struct resource bfin_plat_nand_resources = {
 	.start = 0x24000000,
 	.end = 0x24000000 + (1 << MAX(BFIN_NAND_PLAT_CLE, BFIN_NAND_PLAT_ALE)),
-	.flags = IORESOURCE_IO,
+	.flags = IORESOURCE_MEM,
 };
 
 static struct platform_device bfin_async_nand_device = {
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/cm_bf561.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/cm_bf561.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/cm_bf561.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/cm_bf561.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -111,12 +111,12 @@
 	},
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) || defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
 		.controller_data = &ad1836_spi_chip_info,
 	},
 #endif
@@ -278,7 +278,7 @@
 	}, {
 		.start = IRQ_PF47,
 		.end = IRQ_PF47,
-		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/ezkit.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/ezkit.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/boards/ezkit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/boards/ezkit.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/spi/spi.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
@@ -74,7 +75,7 @@
 	}, {
 		.start = IRQ_PF8,
 		.end = IRQ_PF8,
-		.flags = IORESOURCE_IRQ,
+		.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
 	},
 };
 
@@ -274,8 +275,8 @@
 };
 #endif
 
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
 	.enable_dma = 0,
 	.bits_per_word = 16,
@@ -328,14 +329,16 @@
 #endif
 
 static struct spi_board_info bfin_spi_board_info[] __initdata = {
-#if defined(CONFIG_SND_BLACKFIN_AD183X) \
-	|| defined(CONFIG_SND_BLACKFIN_AD183X_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) \
+	|| defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
 	{
-		.modalias = "ad1836",
+		.modalias = "ad183x",
 		.max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
 		.bus_num = 0,
-		.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+		.chip_select = 4,
+		.platform_data = "ad1836", /* only includes chip name for the moment */
 		.controller_data = &ad1836_spi_chip_info,
+		.mode = SPI_MODE_3,
 	},
 #endif
 #if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
@@ -377,8 +380,8 @@
 #include <linux/i2c-gpio.h>
 
 static struct i2c_gpio_platform_data i2c_gpio_data = {
-	.sda_pin		= 1,
-	.scl_pin		= 0,
+	.sda_pin		= GPIO_PF1,
+	.scl_pin		= GPIO_PF0,
 	.sda_is_open_drain	= 0,
 	.scl_is_open_drain	= 0,
 	.udelay			= 40,
@@ -420,6 +423,30 @@
 	},
 };
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+static struct platform_device bfin_i2s = {
+	.name = "bfin-i2s",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+static struct platform_device bfin_tdm = {
+	.name = "bfin-tdm",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+static struct platform_device bfin_ac97 = {
+	.name = "bfin-ac97",
+	.id = CONFIG_SND_BF5XX_SPORT_NUM,
+	/* TODO: add platform data here */
+};
+#endif
+
 static struct platform_device *ezkit_devices[] __initdata = {
 
 	&bfin_dpmc,
@@ -467,6 +494,18 @@
 #if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
 	&ezkit_flash_device,
 #endif
+
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+	&bfin_i2s,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+	&bfin_tdm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+	&bfin_ac97,
+#endif
 };
 
 static int __init ezkit_init(void)
@@ -484,6 +523,17 @@
 	SSYNC();
 #endif
 
+#if defined(CONFIG_SND_BF5XX_SOC_AD183X) || defined(CONFIG_SND_BF5XX_SOC_AD183X_MODULE)
+	bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 15));
+	bfin_write_FIO0_FLAG_S(1 << 15);
+	SSYNC();
+	/*
+	 * This initialization lasts for approximately 4500 MCLKs.
+	 * MCLK = 12.288MHz
+	 */
+	udelay(400);
+#endif
+
 	spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/coreb.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/coreb.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/coreb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/coreb.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,9 +18,9 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 
-#define CMD_COREB_START		2
-#define CMD_COREB_STOP		3
-#define CMD_COREB_RESET		4
+#define CMD_COREB_START		_IO('b', 0)
+#define CMD_COREB_STOP		_IO('b', 1)
+#define CMD_COREB_RESET		_IO('b', 2)
 
 static long
 coreb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -29,10 +29,10 @@
 
 	switch (cmd) {
 	case CMD_COREB_START:
-		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
+		bfin_write_SYSCR(bfin_read_SYSCR() & ~0x0020);
 		break;
 	case CMD_COREB_STOP:
-		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
+		bfin_write_SYSCR(bfin_read_SYSCR() | 0x0020);
 		bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
 		break;
 	case CMD_COREB_RESET:
@@ -51,6 +51,7 @@
 static const struct file_operations coreb_fops = {
 	.owner          = THIS_MODULE,
 	.unlocked_ioctl = coreb_ioctl,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice coreb_dev = {
@@ -73,3 +74,4 @@
 
 MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
 MODULE_DESCRIPTION("BF561 Core B Support");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/blackfin.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/blackfin.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/blackfin.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/blackfin.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,29 +24,16 @@
 #define bfin_read_FIO_INEN() bfin_read_FIO0_INEN()
 #define bfin_write_FIO_INEN(val) bfin_write_FIO0_INEN(val)
 
-#define SIC_IWR0 SICA_IWR0
-#define SIC_IWR1 SICA_IWR1
-#define SIC_IAR0 SICA_IAR0
-#define bfin_write_SIC_IMASK0 bfin_write_SICA_IMASK0
-#define bfin_write_SIC_IMASK1 bfin_write_SICA_IMASK1
-#define bfin_write_SIC_IWR0   bfin_write_SICA_IWR0
-#define bfin_write_SIC_IWR1   bfin_write_SICA_IWR1
-
-#define bfin_read_SIC_IMASK0 bfin_read_SICA_IMASK0
-#define bfin_read_SIC_IMASK1 bfin_read_SICA_IMASK1
-#define bfin_read_SIC_IWR0   bfin_read_SICA_IWR0
-#define bfin_read_SIC_IWR1   bfin_read_SICA_IWR1
-#define bfin_read_SIC_ISR0   bfin_read_SICA_ISR0
-#define bfin_read_SIC_ISR1   bfin_read_SICA_ISR1
-
-#define bfin_read_SIC_IMASK(x)		bfin_read32(SICA_IMASK0 + (x << 2))
-#define bfin_write_SIC_IMASK(x, val)	bfin_write32((SICA_IMASK0 + (x << 2)), val)
-#define bfin_read_SICB_IMASK(x)		bfin_read32(SICB_IMASK0 + (x << 2))
-#define bfin_write_SICB_IMASK(x, val)	bfin_write32((SICB_IMASK0 + (x << 2)), val)
-#define bfin_read_SIC_ISR(x)		bfin_read32(SICA_ISR0 + (x << 2))
-#define bfin_write_SIC_ISR(x, val)	bfin_write32((SICA_ISR0 + (x << 2)), val)
-#define bfin_read_SICB_ISR(x)		bfin_read32(SICB_ISR0 + (x << 2))
-#define bfin_write_SICB_ISR(x, val)	bfin_write32((SICB_ISR0 + (x << 2)), val)
+/* Weird muxer funcs which pick SIC regs from IMASK base */
+#define __SIC_MUX(base, x)		((base) + ((x) << 2))
+#define bfin_read_SIC_IMASK(x)		bfin_read32(__SIC_MUX(SIC_IMASK0, x))
+#define bfin_write_SIC_IMASK(x, val)	bfin_write32(__SIC_MUX(SIC_IMASK0, x), val)
+#define bfin_read_SICB_IMASK(x)		bfin_read32(__SIC_MUX(SICB_IMASK0, x))
+#define bfin_write_SICB_IMASK(x, val)	bfin_write32(__SIC_MUX(SICB_IMASK0, x), val)
+#define bfin_read_SIC_ISR(x)		bfin_read32(__SIC_MUX(SIC_ISR0, x))
+#define bfin_write_SIC_ISR(x, val)	bfin_write32(__SIC_MUX(SIC_ISR0, x), val)
+#define bfin_read_SICB_ISR(x)		bfin_read32(__SIC_MUX(SICB_ISR0, x))
+#define bfin_write_SICB_ISR(x, val)	bfin_write32(__SIC_MUX(SICB_ISR0, x), val)
 
 #define BFIN_UART_NR_PORTS      1
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/cdefBF561.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/cdefBF561.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/cdefBF561.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,49 +30,41 @@
 #define bfin_write_PLL_LOCKCNT(val)          bfin_write16(PLL_LOCKCNT,val)
 #define bfin_read_CHIPID()                   bfin_read32(CHIPID)
 
-/* For MMR's that are reserved on Core B, set up defines to better integrate with other ports */
-#define bfin_read_SWRST()                    bfin_read_SICA_SWRST()
-#define bfin_write_SWRST(val)                bfin_write_SICA_SWRST(val)
-#define bfin_read_SYSCR()                    bfin_read_SICA_SYSCR()
-#define bfin_write_SYSCR(val)                bfin_write_SICA_SYSCR(val)
-
 /* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
-#define bfin_read_SICA_SWRST()               bfin_read16(SICA_SWRST)
-#define bfin_write_SICA_SWRST(val)           bfin_write16(SICA_SWRST,val)
-#define bfin_read_SICA_SYSCR()               bfin_read16(SICA_SYSCR)
-#define bfin_write_SICA_SYSCR(val)           bfin_write16(SICA_SYSCR,val)
-#define bfin_read_SICA_RVECT()               bfin_read16(SICA_RVECT)
-#define bfin_write_SICA_RVECT(val)           bfin_write16(SICA_RVECT,val)
-#define bfin_read_SICA_IMASK()               bfin_read32(SICA_IMASK)
-#define bfin_write_SICA_IMASK(val)           bfin_write32(SICA_IMASK,val)
-#define bfin_read_SICA_IMASK0()              bfin_read32(SICA_IMASK0)
-#define bfin_write_SICA_IMASK0(val)          bfin_write32(SICA_IMASK0,val)
-#define bfin_read_SICA_IMASK1()              bfin_read32(SICA_IMASK1)
-#define bfin_write_SICA_IMASK1(val)          bfin_write32(SICA_IMASK1,val)
-#define bfin_read_SICA_IAR0()                bfin_read32(SICA_IAR0)
-#define bfin_write_SICA_IAR0(val)            bfin_write32(SICA_IAR0,val)
-#define bfin_read_SICA_IAR1()                bfin_read32(SICA_IAR1)
-#define bfin_write_SICA_IAR1(val)            bfin_write32(SICA_IAR1,val)
-#define bfin_read_SICA_IAR2()                bfin_read32(SICA_IAR2)
-#define bfin_write_SICA_IAR2(val)            bfin_write32(SICA_IAR2,val)
-#define bfin_read_SICA_IAR3()                bfin_read32(SICA_IAR3)
-#define bfin_write_SICA_IAR3(val)            bfin_write32(SICA_IAR3,val)
-#define bfin_read_SICA_IAR4()                bfin_read32(SICA_IAR4)
-#define bfin_write_SICA_IAR4(val)            bfin_write32(SICA_IAR4,val)
-#define bfin_read_SICA_IAR5()                bfin_read32(SICA_IAR5)
-#define bfin_write_SICA_IAR5(val)            bfin_write32(SICA_IAR5,val)
-#define bfin_read_SICA_IAR6()                bfin_read32(SICA_IAR6)
-#define bfin_write_SICA_IAR6(val)            bfin_write32(SICA_IAR6,val)
-#define bfin_read_SICA_IAR7()                bfin_read32(SICA_IAR7)
-#define bfin_write_SICA_IAR7(val)            bfin_write32(SICA_IAR7,val)
-#define bfin_read_SICA_ISR0()                bfin_read32(SICA_ISR0)
-#define bfin_write_SICA_ISR0(val)            bfin_write32(SICA_ISR0,val)
-#define bfin_read_SICA_ISR1()                bfin_read32(SICA_ISR1)
-#define bfin_write_SICA_ISR1(val)            bfin_write32(SICA_ISR1,val)
-#define bfin_read_SICA_IWR0()                bfin_read32(SICA_IWR0)
-#define bfin_write_SICA_IWR0(val)            bfin_write32(SICA_IWR0,val)
-#define bfin_read_SICA_IWR1()                bfin_read32(SICA_IWR1)
-#define bfin_write_SICA_IWR1(val)            bfin_write32(SICA_IWR1,val)
+#define bfin_read_SWRST()                    bfin_read16(SWRST)
+#define bfin_write_SWRST(val)                bfin_write16(SWRST,val)
+#define bfin_read_SYSCR()                    bfin_read16(SYSCR)
+#define bfin_write_SYSCR(val)                bfin_write16(SYSCR,val)
+#define bfin_read_SIC_RVECT()                bfin_read16(SIC_RVECT)
+#define bfin_write_SIC_RVECT(val)            bfin_write16(SIC_RVECT,val)
+#define bfin_read_SIC_IMASK0()               bfin_read32(SIC_IMASK0)
+#define bfin_write_SIC_IMASK0(val)           bfin_write32(SIC_IMASK0,val)
+#define bfin_read_SIC_IMASK1()               bfin_read32(SIC_IMASK1)
+#define bfin_write_SIC_IMASK1(val)           bfin_write32(SIC_IMASK1,val)
+#define bfin_read_SIC_IAR0()                 bfin_read32(SIC_IAR0)
+#define bfin_write_SIC_IAR0(val)             bfin_write32(SIC_IAR0,val)
+#define bfin_read_SIC_IAR1()                 bfin_read32(SIC_IAR1)
+#define bfin_write_SIC_IAR1(val)             bfin_write32(SIC_IAR1,val)
+#define bfin_read_SIC_IAR2()                 bfin_read32(SIC_IAR2)
+#define bfin_write_SIC_IAR2(val)             bfin_write32(SIC_IAR2,val)
+#define bfin_read_SIC_IAR3()                 bfin_read32(SIC_IAR3)
+#define bfin_write_SIC_IAR3(val)             bfin_write32(SIC_IAR3,val)
+#define bfin_read_SIC_IAR4()                 bfin_read32(SIC_IAR4)
+#define bfin_write_SIC_IAR4(val)             bfin_write32(SIC_IAR4,val)
+#define bfin_read_SIC_IAR5()                 bfin_read32(SIC_IAR5)
+#define bfin_write_SIC_IAR5(val)             bfin_write32(SIC_IAR5,val)
+#define bfin_read_SIC_IAR6()                 bfin_read32(SIC_IAR6)
+#define bfin_write_SIC_IAR6(val)             bfin_write32(SIC_IAR6,val)
+#define bfin_read_SIC_IAR7()                 bfin_read32(SIC_IAR7)
+#define bfin_write_SIC_IAR7(val)             bfin_write32(SIC_IAR7,val)
+#define bfin_read_SIC_ISR0()                 bfin_read32(SIC_ISR0)
+#define bfin_write_SIC_ISR0(val)             bfin_write32(SIC_ISR0,val)
+#define bfin_read_SIC_ISR1()                 bfin_read32(SIC_ISR1)
+#define bfin_write_SIC_ISR1(val)             bfin_write32(SIC_ISR1,val)
+#define bfin_read_SIC_IWR0()                 bfin_read32(SIC_IWR0)
+#define bfin_write_SIC_IWR0(val)             bfin_write32(SIC_IWR0,val)
+#define bfin_read_SIC_IWR1()                 bfin_read32(SIC_IWR1)
+#define bfin_write_SIC_IWR1(val)             bfin_write32(SIC_IWR1,val)
 
 /* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
 #define bfin_read_SICB_SWRST()               bfin_read16(SICB_SWRST)
@@ -1534,54 +1526,4 @@
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_PLL_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SICA_IWR0);
-	iwr1 = bfin_read32(SICA_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
-	bfin_write32(SICA_IWR1, 0);
-
-	bfin_write16(PLL_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SICA_IWR0, iwr0);
-	bfin_write32(SICA_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-	unsigned long flags, iwr0, iwr1;
-
-	if (val == bfin_read_VR_CTL())
-		return;
-
-	local_irq_save_hw(flags);
-	/* Enable the PLL Wakeup bit in SIC IWR */
-	iwr0 = bfin_read32(SICA_IWR0);
-	iwr1 = bfin_read32(SICA_IWR1);
-	/* Only allow PPL Wakeup) */
-	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
-	bfin_write32(SICA_IWR1, 0);
-
-	bfin_write16(VR_CTL, val);
-	SSYNC();
-	asm("IDLE;");
-
-	bfin_write32(SICA_IWR0, iwr0);
-	bfin_write32(SICA_IWR1, iwr1);
-	local_irq_restore_hw(flags);
-}
-
 #endif				/* _CDEF_BF561_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/defBF561.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/defBF561.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/defBF561.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/defBF561.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,32 +28,29 @@
 #define CHIPID                 0xFFC00014       /* Chip ID Register */
 
 /* For MMR's that are reserved on Core B, set up defines to better integrate with other ports */
-#define SWRST                   SICA_SWRST
-#define SYSCR                   SICA_SYSCR
 #define DOUBLE_FAULT            (DOUBLE_FAULT_B|DOUBLE_FAULT_A)
 #define RESET_DOUBLE            (SWRST_DBL_FAULT_B|SWRST_DBL_FAULT_A)
 #define RESET_WDOG              (SWRST_WDT_B|SWRST_WDT_A)
 #define RESET_SOFTWARE          (SWRST_OCCURRED)
 
 /* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
-#define SICA_SWRST              0xFFC00100	/* Software Reset register */
-#define SICA_SYSCR              0xFFC00104	/* System Reset Configuration register */
-#define SICA_RVECT              0xFFC00108	/* SIC Reset Vector Address Register */
-#define SICA_IMASK              0xFFC0010C	/* SIC Interrupt Mask register 0 - hack to fix old tests */
-#define SICA_IMASK0             0xFFC0010C	/* SIC Interrupt Mask register 0 */
-#define SICA_IMASK1             0xFFC00110	/* SIC Interrupt Mask register 1 */
-#define SICA_IAR0               0xFFC00124	/* SIC Interrupt Assignment Register 0 */
-#define SICA_IAR1               0xFFC00128	/* SIC Interrupt Assignment Register 1 */
-#define SICA_IAR2               0xFFC0012C	/* SIC Interrupt Assignment Register 2 */
-#define SICA_IAR3               0xFFC00130	/* SIC Interrupt Assignment Register 3 */
-#define SICA_IAR4               0xFFC00134	/* SIC Interrupt Assignment Register 4 */
-#define SICA_IAR5               0xFFC00138	/* SIC Interrupt Assignment Register 5 */
-#define SICA_IAR6               0xFFC0013C	/* SIC Interrupt Assignment Register 6 */
-#define SICA_IAR7               0xFFC00140	/* SIC Interrupt Assignment Register 7 */
-#define SICA_ISR0               0xFFC00114	/* SIC Interrupt Status register 0 */
-#define SICA_ISR1               0xFFC00118	/* SIC Interrupt Status register 1 */
-#define SICA_IWR0               0xFFC0011C	/* SIC Interrupt Wakeup-Enable register 0 */
-#define SICA_IWR1               0xFFC00120	/* SIC Interrupt Wakeup-Enable register 1 */
+#define SWRST                   0xFFC00100	/* Software Reset register */
+#define SYSCR                   0xFFC00104	/* System Reset Configuration register */
+#define SIC_RVECT               0xFFC00108	/* SIC Reset Vector Address Register */
+#define SIC_IMASK0              0xFFC0010C	/* SIC Interrupt Mask register 0 */
+#define SIC_IMASK1              0xFFC00110	/* SIC Interrupt Mask register 1 */
+#define SIC_IAR0                0xFFC00124	/* SIC Interrupt Assignment Register 0 */
+#define SIC_IAR1                0xFFC00128	/* SIC Interrupt Assignment Register 1 */
+#define SIC_IAR2                0xFFC0012C	/* SIC Interrupt Assignment Register 2 */
+#define SIC_IAR3                0xFFC00130	/* SIC Interrupt Assignment Register 3 */
+#define SIC_IAR4                0xFFC00134	/* SIC Interrupt Assignment Register 4 */
+#define SIC_IAR5                0xFFC00138	/* SIC Interrupt Assignment Register 5 */
+#define SIC_IAR6                0xFFC0013C	/* SIC Interrupt Assignment Register 6 */
+#define SIC_IAR7                0xFFC00140	/* SIC Interrupt Assignment Register 7 */
+#define SIC_ISR0                0xFFC00114	/* SIC Interrupt Status register 0 */
+#define SIC_ISR1                0xFFC00118	/* SIC Interrupt Status register 1 */
+#define SIC_IWR0                0xFFC0011C	/* SIC Interrupt Wakeup-Enable register 0 */
+#define SIC_IWR1                0xFFC00120	/* SIC Interrupt Wakeup-Enable register 1 */
 
 /* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
 #define SICB_SWRST              0xFFC01100	/* reserved */
@@ -1271,63 +1268,6 @@
 #define PF14_P        14
 #define PF15_P        15
 
-/* ***********  SERIAL PERIPHERAL INTERFACE (SPI) MASKS  **************** */
-
-/* SPI_CTL Masks */
-#define TIMOD                  0x00000003	/* Transfer initiation mode and interrupt generation */
-#define SZ                     0x00000004	/* Send Zero (=0) or last (=1) word when TDBR empty. */
-#define GM                     0x00000008	/* When RDBR full, get more (=1) data or discard (=0) incoming Data */
-#define PSSE                   0x00000010	/* Enable (=1) Slave-Select input for Master. */
-#define EMISO                  0x00000020	/* Enable (=1) MISO pin as an output. */
-#define SIZE                   0x00000100	/* Word length (0 => 8 bits, 1 => 16 bits) */
-#define LSBF                   0x00000200	/* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
-#define CPHA                   0x00000400	/* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
-#define CPOL                   0x00000800	/* Clock polarity (0 => active-high, 1 => active-low) */
-#define MSTR                   0x00001000	/* Configures SPI as master (=1) or slave (=0) */
-#define WOM                    0x00002000	/* Open drain (=1) data output enable (for MOSI and MISO) */
-#define SPE                    0x00004000	/* SPI module enable (=1), disable (=0) */
-
-/* SPI_FLG Masks */
-#define FLS1                   0x00000002	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
-#define FLS2                   0x00000004	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLS3                   0x00000008	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
-#define FLS4                   0x00000010	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
-#define FLS5                   0x00000020	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
-#define FLS6                   0x00000040	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
-#define FLS7                   0x00000080	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
-#define FLG1                   0x00000200	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
-#define FLG2                   0x00000400	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLG3                   0x00000800	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
-#define FLG4                   0x00001000	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
-#define FLG5                   0x00002000	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
-#define FLG6                   0x00004000	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
-#define FLG7                   0x00008000	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
-
-/* SPI_FLG Bit Positions */
-#define FLS1_P                 0x00000001	/* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
-#define FLS2_P                 0x00000002	/* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLS3_P                 0x00000003	/* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
-#define FLS4_P                 0x00000004	/* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
-#define FLS5_P                 0x00000005	/* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
-#define FLS6_P                 0x00000006	/* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
-#define FLS7_P                 0x00000007	/* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
-#define FLG1_P                 0x00000009	/* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select  */
-#define FLG2_P                 0x0000000A	/* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
-#define FLG3_P                 0x0000000B	/* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select  */
-#define FLG4_P                 0x0000000C	/* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select  */
-#define FLG5_P                 0x0000000D	/* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select  */
-#define FLG6_P                 0x0000000E	/* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select  */
-#define FLG7_P                 0x0000000F	/* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
-
-/* SPI_STAT Masks */
-#define SPIF                   0x00000001	/* Set (=1) when SPI single-word transfer complete */
-#define MODF                   0x00000002	/* Set (=1) in a master device when some other device tries to become master */
-#define TXE                    0x00000004	/* Set (=1) when transmission occurs with no new data in SPI_TDBR */
-#define TXS                    0x00000008	/* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
-#define RBSY                   0x00000010	/* Set (=1) when data is received with RDBR full */
-#define RXS                    0x00000020	/* SPI_RDBR Data Buffer Status (0=Empty, 1=Full)  */
-#define TXCOL                  0x00000040	/* When set (=1), corrupt data may have been transmitted  */
-
 /* *********************  ASYNCHRONOUS MEMORY CONTROLLER MASKS  ************* */
 
 /* AMGCTL Masks */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/pll.h linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/pll.h
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/include/mach/pll.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/include/mach/pll.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2005-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_PLL_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SICA_IWR0);
+	iwr1 = bfin_read32(SICA_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+	bfin_write32(SICA_IWR1, 0);
+
+	bfin_write16(PLL_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SICA_IWR0, iwr0);
+	bfin_write32(SICA_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+	unsigned long flags, iwr0, iwr1;
+
+	if (val == bfin_read_VR_CTL())
+		return;
+
+	flags = hard_local_irq_save();
+	/* Enable the PLL Wakeup bit in SIC IWR */
+	iwr0 = bfin_read32(SICA_IWR0);
+	iwr1 = bfin_read32(SICA_IWR1);
+	/* Only allow PPL Wakeup) */
+	bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+	bfin_write32(SICA_IWR1, 0);
+
+	bfin_write16(VR_CTL, val);
+	SSYNC();
+	asm("IDLE;");
+
+	bfin_write32(SICA_IWR0, iwr0);
+	bfin_write32(SICA_IWR1, iwr1);
+	hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/ints-priority.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/ints-priority.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/ints-priority.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/ints-priority.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,7 +13,7 @@
 void __init program_IAR(void)
 {
 	/* Program the IAR0 Register with the configured priority */
-	bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+	bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
 			     ((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) |
 			     ((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) |
 			     ((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) |
@@ -22,7 +22,7 @@
 			     ((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
 			     ((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS));
 
-	bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
+	bfin_write_SIC_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
 			     ((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) |
 			     ((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) |
 			     ((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) |
@@ -31,7 +31,7 @@
 			     ((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) |
 			     ((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS));
 
-	bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
+	bfin_write_SIC_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
 			     ((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) |
 			     ((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) |
 			     ((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) |
@@ -40,7 +40,7 @@
 			     ((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) |
 			     ((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS));
 
-	bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
+	bfin_write_SIC_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
 			     ((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) |
 			     ((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) |
 			     ((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) |
@@ -49,7 +49,7 @@
 			     ((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) |
 			     ((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS));
 
-	bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
+	bfin_write_SIC_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
 			     ((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) |
 			     ((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) |
 			     ((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
@@ -58,7 +58,7 @@
 			     ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
 			     ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS));
 
-	bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
+	bfin_write_SIC_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
 			     ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
 			     ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
 			     ((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
@@ -67,7 +67,7 @@
 			     ((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) |
 			     ((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS));
 
-	bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
+	bfin_write_SIC_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
 			     ((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) |
 			     ((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) |
 			     ((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) |
@@ -76,7 +76,7 @@
 			     ((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) |
 			     ((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS));
 
-	bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
+	bfin_write_SIC_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
 			     ((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) |
 			     ((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) |
 			     ((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) |
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/smp.c linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/smp.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-bf561/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-bf561/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,19 +52,19 @@
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
 	/* Clone setup for peripheral interrupt sources from CoreA. */
-	bfin_write_SICB_IMASK0(bfin_read_SICA_IMASK0());
-	bfin_write_SICB_IMASK1(bfin_read_SICA_IMASK1());
+	bfin_write_SICB_IMASK0(bfin_read_SIC_IMASK0());
+	bfin_write_SICB_IMASK1(bfin_read_SIC_IMASK1());
 	SSYNC();
 
 	/* Clone setup for IARs from CoreA. */
-	bfin_write_SICB_IAR0(bfin_read_SICA_IAR0());
-	bfin_write_SICB_IAR1(bfin_read_SICA_IAR1());
-	bfin_write_SICB_IAR2(bfin_read_SICA_IAR2());
-	bfin_write_SICB_IAR3(bfin_read_SICA_IAR3());
-	bfin_write_SICB_IAR4(bfin_read_SICA_IAR4());
-	bfin_write_SICB_IAR5(bfin_read_SICA_IAR5());
-	bfin_write_SICB_IAR6(bfin_read_SICA_IAR6());
-	bfin_write_SICB_IAR7(bfin_read_SICA_IAR7());
+	bfin_write_SICB_IAR0(bfin_read_SIC_IAR0());
+	bfin_write_SICB_IAR1(bfin_read_SIC_IAR1());
+	bfin_write_SICB_IAR2(bfin_read_SIC_IAR2());
+	bfin_write_SICB_IAR3(bfin_read_SIC_IAR3());
+	bfin_write_SICB_IAR4(bfin_read_SIC_IAR4());
+	bfin_write_SICB_IAR5(bfin_read_SIC_IAR5());
+	bfin_write_SICB_IAR6(bfin_read_SIC_IAR6());
+	bfin_write_SICB_IAR7(bfin_read_SIC_IAR7());
 	bfin_write_SICB_IWR0(IWR_DISABLE_ALL);
 	bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
 	SSYNC();
@@ -86,12 +86,12 @@
 
 	spin_lock(&boot_lock);
 
-	if ((bfin_read_SICA_SYSCR() & COREB_SRAM_INIT) == 0) {
+	if ((bfin_read_SIC_SYSCR() & COREB_SRAM_INIT) == 0) {
 		/* CoreB already running, sending ipi to wakeup it */
 		platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
 	} else {
 		/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
-		bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~COREB_SRAM_INIT);
+		bfin_write_SIC_SYSCR(bfin_read_SIC_SYSCR() & ~COREB_SRAM_INIT);
 		SSYNC();
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/cpufreq.c linux-libre-2.6.37-gnu/arch/blackfin/mach-common/cpufreq.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/cpufreq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -134,7 +134,7 @@
 
 		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 		if (cpu == CPUFREQ_CPU) {
-			local_irq_save_hw(flags);
+			flags = hard_local_irq_save();
 			plldiv = (bfin_read_PLL_DIV() & SSEL) |
 						dpm_state_table[index].csel;
 			bfin_write_PLL_DIV(plldiv);
@@ -155,7 +155,7 @@
 				loops_per_jiffy = cpufreq_scale(lpj_ref,
 						lpj_ref_freq, freqs.new);
 			}
-			local_irq_restore_hw(flags);
+			hard_local_irq_restore(flags);
 		}
 		/* TODO: just test case for cycles clock source, remove later */
 		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/dpmc_modes.S linux-libre-2.6.37-gnu/arch/blackfin/mach-common/dpmc_modes.S
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/dpmc_modes.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/dpmc_modes.S	2011-01-04 19:50:19.000000000 -0500
@@ -292,13 +292,7 @@
 #ifdef SIC_IMASK
 	PM_SYS_PUSH(SIC_IMASK)
 #endif
-#ifdef SICA_IMASK0
-	PM_SYS_PUSH(SICA_IMASK0)
-#endif
-#ifdef SICA_IMASK1
-	PM_SYS_PUSH(SICA_IMASK1)
-#endif
-#ifdef SIC_IAR2
+#ifdef SIC_IAR0
 	PM_SYS_PUSH(SIC_IAR0)
 	PM_SYS_PUSH(SIC_IAR1)
 	PM_SYS_PUSH(SIC_IAR2)
@@ -321,17 +315,6 @@
 	PM_SYS_PUSH(SIC_IAR11)
 #endif
 
-#ifdef SICA_IAR0
-	PM_SYS_PUSH(SICA_IAR0)
-	PM_SYS_PUSH(SICA_IAR1)
-	PM_SYS_PUSH(SICA_IAR2)
-	PM_SYS_PUSH(SICA_IAR3)
-	PM_SYS_PUSH(SICA_IAR4)
-	PM_SYS_PUSH(SICA_IAR5)
-	PM_SYS_PUSH(SICA_IAR6)
-	PM_SYS_PUSH(SICA_IAR7)
-#endif
-
 #ifdef SIC_IWR
 	PM_SYS_PUSH(SIC_IWR)
 #endif
@@ -344,12 +327,6 @@
 #ifdef SIC_IWR2
 	PM_SYS_PUSH(SIC_IWR2)
 #endif
-#ifdef SICA_IWR0
-	PM_SYS_PUSH(SICA_IWR0)
-#endif
-#ifdef SICA_IWR1
-	PM_SYS_PUSH(SICA_IWR1)
-#endif
 
 #ifdef PINT0_ASSIGN
 	PM_SYS_PUSH(PINT0_MASK_SET)
@@ -750,12 +727,6 @@
 	PM_SYS_POP(PINT0_MASK_SET)
 #endif
 
-#ifdef SICA_IWR1
-	PM_SYS_POP(SICA_IWR1)
-#endif
-#ifdef SICA_IWR0
-	PM_SYS_POP(SICA_IWR0)
-#endif
 #ifdef SIC_IWR2
 	PM_SYS_POP(SIC_IWR2)
 #endif
@@ -769,17 +740,6 @@
 	PM_SYS_POP(SIC_IWR)
 #endif
 
-#ifdef SICA_IAR0
-	PM_SYS_POP(SICA_IAR7)
-	PM_SYS_POP(SICA_IAR6)
-	PM_SYS_POP(SICA_IAR5)
-	PM_SYS_POP(SICA_IAR4)
-	PM_SYS_POP(SICA_IAR3)
-	PM_SYS_POP(SICA_IAR2)
-	PM_SYS_POP(SICA_IAR1)
-	PM_SYS_POP(SICA_IAR0)
-#endif
-
 #ifdef SIC_IAR8
 	PM_SYS_POP(SIC_IAR11)
 	PM_SYS_POP(SIC_IAR10)
@@ -797,17 +757,11 @@
 #ifdef SIC_IAR3
 	PM_SYS_POP(SIC_IAR3)
 #endif
-#ifdef SIC_IAR2
+#ifdef SIC_IAR0
 	PM_SYS_POP(SIC_IAR2)
 	PM_SYS_POP(SIC_IAR1)
 	PM_SYS_POP(SIC_IAR0)
 #endif
-#ifdef SICA_IMASK1
-	PM_SYS_POP(SICA_IMASK1)
-#endif
-#ifdef SICA_IMASK0
-	PM_SYS_POP(SICA_IMASK0)
-#endif
 #ifdef SIC_IMASK
 	PM_SYS_POP(SIC_IMASK)
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/entry.S linux-libre-2.6.37-gnu/arch/blackfin/mach-common/entry.S
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -889,6 +889,66 @@
 	rts;
 ENDPROC(_ret_from_exception)
 
+#if defined(CONFIG_PREEMPT)
+
+ENTRY(_up_to_irq14)
+#if ANOMALY_05000281 || ANOMALY_05000461
+	r0.l = lo(SAFE_USER_INSTRUCTION);
+	r0.h = hi(SAFE_USER_INSTRUCTION);
+	reti = r0;
+#endif
+
+#ifdef CONFIG_DEBUG_HWERR
+	/* enable irq14 & hwerr interrupt, until we transition to _evt_evt14 */
+	r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#else
+	/* Only enable irq14 interrupt, until we transition to _evt_evt14 */
+	r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+#endif
+	sti r0;
+
+	p0.l = lo(EVT14);
+	p0.h = hi(EVT14);
+	p1.l = _evt_up_evt14;
+	p1.h = _evt_up_evt14;
+	[p0] = p1;
+	csync;
+
+	raise 14;
+1:
+	jump 1b;
+ENDPROC(_up_to_irq14)
+
+ENTRY(_evt_up_evt14)
+#ifdef CONFIG_DEBUG_HWERR
+	r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+	sti r0;
+#else
+	cli r0;
+#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+	[--sp] = rets;
+	sp += -12;
+	call _trace_hardirqs_off;
+	sp += 12;
+	rets = [sp++];
+#endif
+	[--sp] = RETI;
+	SP += 4;
+
+	/* restore normal evt14 */
+	p0.l = lo(EVT14);
+	p0.h = hi(EVT14);
+	p1.l = _evt_evt14;
+	p1.h = _evt_evt14;
+	[p0] = p1;
+	csync;
+
+	rts;
+ENDPROC(_evt_up_evt14)
+
+#endif
+
 #ifdef CONFIG_IPIPE
 
 _resume_kernel_from_int:
@@ -902,8 +962,54 @@
 	( r7:4, p5:3 ) = [sp++];
 	rets = [sp++];
 	rts
+#elif defined(CONFIG_PREEMPT)
+
+_resume_kernel_from_int:
+	/* check preempt_count */
+	r7 = sp;
+	r4.l = lo(ALIGN_PAGE_MASK);
+	r4.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r4;
+	p5 = r7;
+	r7 = [p5 + TI_PREEMPT];
+	cc = r7 == 0x0;
+	if !cc jump .Lreturn_to_kernel;
+.Lneed_schedule:
+	r7 = [p5 + TI_FLAGS];
+	r4.l = lo(_TIF_WORK_MASK);
+	r4.h = hi(_TIF_WORK_MASK);
+	r7 =  r7 & r4;
+	cc = BITTST(r7, TIF_NEED_RESCHED);
+	if !cc jump .Lreturn_to_kernel;
+	/*
+	 * let schedule done at level 15, otherwise sheduled process will run
+	 * at high level and block low level interrupt
+	 */
+	r6 = reti;  /* save reti */
+	r5.l = .Lkernel_schedule;
+	r5.h = .Lkernel_schedule;
+	reti = r5;
+	rti;
+.Lkernel_schedule:
+	[--sp] = rets;
+	sp += -12;
+	pseudo_long_call _preempt_schedule_irq, p4;
+	sp += 12;
+	rets = [sp++];
+
+	[--sp] = rets;
+	sp += -12;
+	/* up to irq14 so that reti after restore_all can return to irq15(kernel) */
+	pseudo_long_call _up_to_irq14, p4;
+	sp += 12;
+	rets = [sp++];
+
+	reti = r6; /* restore reti so that origin process can return to interrupted point */
+
+	jump .Lneed_schedule;
 #else
-#define _resume_kernel_from_int	 2f
+
+#define _resume_kernel_from_int	.Lreturn_to_kernel
 #endif
 
 ENTRY(_return_from_int)
@@ -913,7 +1019,7 @@
 	p2.h = hi(ILAT);
 	r0 = [p2];
 	cc = bittst (r0, EVT_IVG15_P);
-	if cc jump 2f;
+	if cc jump .Lreturn_to_kernel;
 
 	/* if not return to user mode, get out */
 	p2.l = lo(IPEND);
@@ -945,7 +1051,7 @@
 	STI r0;
 	raise 15;	/* raise evt15 to do signal or reschedule */
 	rti;
-2:
+.Lreturn_to_kernel:
 	rts;
 ENDPROC(_return_from_int)
 
@@ -1631,6 +1737,7 @@
 	.long _sys_fanotify_init
 	.long _sys_fanotify_mark
 	.long _sys_prlimit64
+	.long _sys_cacheflush
 
 	.rept NR_syscalls-(.-_sys_call_table)/4
 	.long _sys_ni_syscall
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/interrupt.S linux-libre-2.6.37-gnu/arch/blackfin/mach-common/interrupt.S
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/interrupt.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/interrupt.S	2011-01-04 19:50:19.000000000 -0500
@@ -116,7 +116,24 @@
 	cc = r0 == 0;
 	if cc jump .Lcommon_restore_context;
 #else /* CONFIG_IPIPE */
+
+#ifdef CONFIG_PREEMPT
+	r7 = sp;
+	r4.l = lo(ALIGN_PAGE_MASK);
+	r4.h = hi(ALIGN_PAGE_MASK);
+	r7 = r7 & r4;
+	p5 = r7;
+	r7 = [p5 + TI_PREEMPT]; /* get preempt count */
+	r7 += 1;                /* increment it */
+	[p5 + TI_PREEMPT] = r7;
+#endif
 	pseudo_long_call _do_irq, p2;
+
+#ifdef CONFIG_PREEMPT
+	r7 += -1;
+	[p5 + TI_PREEMPT] = r7; /* restore preempt count */
+#endif
+
 	SP += 12;
 #endif /* CONFIG_IPIPE */
 	pseudo_long_call _return_from_int, p2;
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/ints-priority.c linux-libre-2.6.37-gnu/arch/blackfin/mach-common/ints-priority.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/ints-priority.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/ints-priority.c	2011-01-04 19:50:19.000000000 -0500
@@ -132,8 +132,8 @@
 static void bfin_core_mask_irq(unsigned int irq)
 {
 	bfin_irq_flags &= ~(1 << irq);
-	if (!irqs_disabled_hw())
-		local_irq_enable_hw();
+	if (!hard_irqs_disabled())
+		hard_local_irq_enable();
 }
 
 static void bfin_core_unmask_irq(unsigned int irq)
@@ -148,8 +148,8 @@
 	 * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
 	 * what we need.
 	 */
-	if (!irqs_disabled_hw())
-		local_irq_enable_hw();
+	if (!hard_irqs_disabled())
+		hard_local_irq_enable();
 	return;
 }
 
@@ -158,12 +158,12 @@
 	unsigned long flags;
 
 #ifdef CONFIG_BF53x
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
 			     ~(1 << SIC_SYSIRQ(irq)));
 #else
 	unsigned mask_bank, mask_bit;
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	mask_bank = SIC_SYSIRQ(irq) / 32;
 	mask_bit = SIC_SYSIRQ(irq) % 32;
 	bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
@@ -173,7 +173,7 @@
 			     ~(1 << mask_bit));
 #endif
 #endif
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 #ifdef CONFIG_SMP
@@ -186,12 +186,12 @@
 	unsigned long flags;
 
 #ifdef CONFIG_BF53x
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
 			     (1 << SIC_SYSIRQ(irq)));
 #else
 	unsigned mask_bank, mask_bit;
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	mask_bank = SIC_SYSIRQ(irq) / 32;
 	mask_bit = SIC_SYSIRQ(irq) % 32;
 #ifdef CONFIG_SMP
@@ -207,7 +207,7 @@
 			(1 << mask_bit));
 #endif
 #endif
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 #ifdef CONFIG_SMP
@@ -264,7 +264,7 @@
 	break;
 	}
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	if (state) {
 		bfin_sic_iwr[bank] |= (1 << bit);
@@ -275,7 +275,7 @@
 		vr_wakeup  &= ~wakeup;
 	}
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 
 	return 0;
 }
@@ -511,7 +511,7 @@
 	int i, irq = 0;
 	u32 status = bfin_read_EMAC_SYSTAT();
 
-	for (i = 0; i < (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++)
+	for (i = 0; i <= (IRQ_MAC_STMDONE - IRQ_MAC_PHYINT); i++)
 		if (status & (1L << i)) {
 			irq = IRQ_MAC_PHYINT + i;
 			break;
@@ -529,8 +529,9 @@
 	} else
 		printk(KERN_ERR
 		       "%s : %s : LINE %d :\nIRQ ?: MAC ERROR"
-		       " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
-		       __func__, __FILE__, __LINE__);
+		       " INTERRUPT ASSERTED BUT NO SOURCE FOUND"
+		       "(EMAC_SYSTAT=0x%X)\n",
+		       __func__, __FILE__, __LINE__, status);
 }
 #endif
 
@@ -1298,7 +1299,7 @@
 	} else {
 		struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
 		struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(SIC_ISR0) || defined(SICA_ISR0)
+#if defined(SIC_ISR0)
 		unsigned long sic_status[3];
 
 		if (smp_processor_id()) {
@@ -1378,7 +1379,7 @@
 	if (likely(vec == EVT_IVTMR_P))
 		irq = IRQ_CORETMR;
 	else {
-#if defined(SIC_ISR0) || defined(SICA_ISR0)
+#if defined(SIC_ISR0)
 		unsigned long sic_status[3];
 
 		sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/irqpanic.c linux-libre-2.6.37-gnu/arch/blackfin/mach-common/irqpanic.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/irqpanic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/irqpanic.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,106 +0,0 @@
-/*
- * panic kernel with dump information
- *
- * Copyright 2005-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <asm/blackfin.h>
-
-#define L1_ICACHE_START 0xffa10000
-#define L1_ICACHE_END   0xffa13fff
-
-/*
- * irq_panic - calls panic with string setup
- */
-__attribute__ ((l1_text))
-asmlinkage void irq_panic(int reason, struct pt_regs *regs)
-{
-	unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
-	unsigned short i, j, die;
-	unsigned int bad[10][6];
-
-	/* check entire cache for coherency
-	 * Since printk is in cacheable memory,
-	 * don't call it until you have checked everything
-	*/
-
-	die = 0;
-	i = 0;
-
-	/* check icache */
-
-	for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
-
-		/* Grab various address bits for the itest_cmd fields                      */
-		cmd = (((ca & 0x3000) << 4) |	/* ca[13:12] for SBNK[1:0]             */
-		       ((ca & 0x0c00) << 16) |	/* ca[11:10] for WAYSEL[1:0]           */
-		       ((ca & 0x3f8)) |	/* ca[09:03] for SET[4:0] and DW[1:0]  */
-		       0);	/* Access Tag, Read access             */
-
-		SSYNC();
-		bfin_write_ITEST_COMMAND(cmd);
-		SSYNC();
-		tag = bfin_read_ITEST_DATA0();
-		SSYNC();
-
-		/* if tag is marked as valid, check it */
-		if (tag & 1) {
-			/* The icache is arranged in 4 groups of 64-bits */
-			for (j = 0; j < 32; j += 8) {
-				cmd = ((((ca + j) & 0x3000) << 4) |	/* ca[13:12] for SBNK[1:0]             */
-				       (((ca + j) & 0x0c00) << 16) |	/* ca[11:10] for WAYSEL[1:0]           */
-				       (((ca + j) & 0x3f8)) |	/* ca[09:03] for SET[4:0] and DW[1:0]  */
-				       4);	/* Access Data, Read access             */
-
-				SSYNC();
-				bfin_write_ITEST_COMMAND(cmd);
-				SSYNC();
-
-				cache_hi = bfin_read_ITEST_DATA1();
-				cache_lo = bfin_read_ITEST_DATA0();
-
-				pa = ((unsigned int *)((tag & 0xffffcc00) |
-						       ((ca + j) & ~(0xffffcc00))));
-
-				/*
-				 * Debugging this, enable
-				 *
-				 * printk("addr: %08x %08x%08x | %08x%08x\n",
-				 *  ((unsigned int *)((tag & 0xffffcc00)  | ((ca+j) & ~(0xffffcc00)))),
-				 *   cache_hi, cache_lo, *(pa+1), *pa);
-				 */
-
-				if (cache_hi != *(pa + 1) || cache_lo != *pa) {
-					/* Since icache is not working, stay out of it, by not printing */
-					die = 1;
-					bad[i][0] = (ca + j);
-					bad[i][1] = cache_hi;
-					bad[i][2] = cache_lo;
-					bad[i][3] = ((tag & 0xffffcc00) |
-					     	((ca + j) & ~(0xffffcc00)));
-					bad[i][4] = *(pa + 1);
-					bad[i][5] = *(pa);
-					i++;
-				}
-			}
-		}
-	}
-	if (die) {
-		printk(KERN_EMERG "icache coherency error\n");
-		for (j = 0; j <= i; j++) {
-			printk(KERN_EMERG
-			    "cache address   : %08x  cache value : %08x%08x\n",
-			     bad[j][0], bad[j][1], bad[j][2]);
-			printk(KERN_EMERG
-			    "physical address: %08x  SDRAM value : %08x%08x\n",
-			     bad[j][3], bad[j][4], bad[j][5]);
-		}
-		panic("icache coherency error");
-	} else
-		printk(KERN_EMERG "icache checked, and OK\n");
-}
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/Makefile linux-libre-2.6.37-gnu/arch/blackfin/mach-common/Makefile
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,4 +11,3 @@
 obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
 obj-$(CONFIG_SMP)         += smp.o
 obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
-obj-$(CONFIG_DEBUG_ICACHE_CHECK) += irqpanic.o
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mach-common/pm.c linux-libre-2.6.37-gnu/arch/blackfin/mach-common/pm.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mach-common/pm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mach-common/pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 {
 	unsigned long flags;
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 	bfin_pm_standby_setup();
 
 #ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
@@ -56,7 +56,7 @@
 	bfin_write_SIC_IWR(IWR_DISABLE_ALL);
 #endif
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 }
 
 int bf53x_suspend_l1_mem(unsigned char *memptr)
@@ -149,12 +149,12 @@
 	wakeup |= GPWE;
 #endif
 
-	local_irq_save_hw(flags);
+	flags = hard_local_irq_save();
 
 	ret = blackfin_dma_suspend();
 
 	if (ret) {
-		local_irq_restore_hw(flags);
+		hard_local_irq_restore(flags);
 		kfree(memptr);
 		return ret;
 	}
@@ -178,7 +178,7 @@
 	bfin_gpio_pm_hibernate_restore();
 	blackfin_dma_resume();
 
-	local_irq_restore_hw(flags);
+	hard_local_irq_restore(flags);
 	kfree(memptr);
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/Makefile linux-libre-2.6.37-gnu/arch/blackfin/Makefile
--- linux-libre-2.6.36-gnu/arch/blackfin/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -101,9 +101,8 @@
 KBUILD_AFLAGS += -mcpu=$(cpu-y)-$(rev-y)
 
 # - we utilize the silicon rev from the toolchain, so move it over to the checkflags
-# - the l1_text attribute is Blackfin specific, so fake it out as used to kill warnings
 CHECKFLAGS_SILICON = $(shell echo "" | $(CPP) $(KBUILD_CFLAGS) -dD - 2>/dev/null | awk '$$2 == "__SILICON_REVISION__" { print $$3 }')
-CHECKFLAGS += -D__SILICON_REVISION__=$(CHECKFLAGS_SILICON) -Dl1_text=__used__
+CHECKFLAGS += -D__SILICON_REVISION__=$(CHECKFLAGS_SILICON) -D__bfin__
 
 head-y   := arch/$(ARCH)/kernel/init_task.o
 
diff -druN linux-libre-2.6.36-gnu/arch/blackfin/mm/init.c linux-libre-2.6.37-gnu/arch/blackfin/mm/init.c
--- linux-libre-2.6.36-gnu/arch/blackfin/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/blackfin/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -158,5 +158,8 @@
 	free_init_pages("unused kernel memory",
 			(unsigned long)(&__init_begin),
 			(unsigned long)(&__init_end));
+
+	if (memory_start == (unsigned long)(&__init_end))
+		memory_start = (unsigned long)(&__init_begin);
 #endif
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/ds1302.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/ds1302.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/ds1302.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/ds1302.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,7 @@
 #include <linux/module.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/bcd.h>
 #include <linux/capability.h>
 
@@ -34,6 +34,7 @@
 
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
+static DEFINE_MUTEX(ds1302_mutex);
 static const char ds1302_name[] = "ds1302";
 
 /* The DS1302 might be connected to different bits on different products. 
@@ -357,9 +358,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ds1302_mutex);
 	ret = rtc_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ds1302_mutex);
 
 	return ret;
 }
@@ -387,6 +388,7 @@
 static const struct file_operations rtc_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl = rtc_unlocked_ioctl,
+	.llseek		= noop_llseek,
 }; 
 
 /* Probe for the chip by writing something to its RAM and try reading it back. */
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/gpio.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/gpio.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -745,6 +745,7 @@
 	.write          = gpio_write,
 	.open           = gpio_open,
 	.release        = gpio_release,
+	.llseek		= noop_llseek,
 };
 
 static void ioif_watcher(const unsigned int gpio_in_available,
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/i2c.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/i2c.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -617,6 +617,7 @@
 	.unlocked_ioctl	= i2c_ioctl,
 	.open		= i2c_open,
 	.release	= i2c_release,
+	.llseek		= noop_llseek,
 };
 
 int __init
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/pcf8563.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/pcf8563.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/pcf8563.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/pcf8563.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/bcd.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -49,6 +48,7 @@
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
 #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
 
+static DEFINE_MUTEX(pcf8563_mutex);
 static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
 
 static const unsigned char days_in_month[] =
@@ -64,6 +64,7 @@
 static const struct file_operations pcf8563_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = pcf8563_unlocked_ioctl,
+	.llseek		= noop_llseek,
 };
 
 unsigned char
@@ -343,9 +344,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&pcf8563_mutex);
 	return pcf8563_ioctl(filp, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&pcf8563_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/sync_serial.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/sync_serial.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/drivers/sync_serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/drivers/sync_serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/timer.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
@@ -149,6 +149,7 @@
 };
 
 
+static DEFINE_MUTEX(sync_serial_mutex);
 static int etrax_sync_serial_init(void);
 static void initialize_port(int portnbr);
 static inline int sync_data_avail(struct sync_port *port);
@@ -250,7 +251,8 @@
 	.poll		= sync_serial_poll,
 	.unlocked_ioctl	= sync_serial_ioctl,
 	.open		= sync_serial_open,
-	.release	= sync_serial_release
+	.release	= sync_serial_release,
+	.llseek		= noop_llseek,
 };
 
 static int __init etrax_sync_serial_init(void)
@@ -445,7 +447,7 @@
 	int mode;
 	int err = -EBUSY;
 
-	lock_kernel();
+	mutex_lock(&sync_serial_mutex);
 	DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));
 
 	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) {
@@ -626,7 +628,7 @@
 	ret = 0;
 	
 out:
-	unlock_kernel();
+	mutex_unlock(&sync_serial_mutex);
 	return ret;
 }
 
@@ -961,9 +963,9 @@
 {
 	long ret;
 
-	lock_kernel();
+	mutex_lock(&sync_serial_mutex);
 	ret = sync_serial_ioctl_unlocked(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&sync_serial_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v10/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/cris/arch-v10/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v10/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v10/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,9 +76,11 @@
  * (in user space) where the result of the ptrace call is written (instead of
  * being returned).
  */
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	unsigned int regno = addr >> 2;
 	unsigned long __user *datap = (unsigned long __user *)data;
 
 	switch (request) {
@@ -93,10 +95,10 @@
 			unsigned long tmp;
 
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+			if ((addr & 3) || regno > PT_MAX)
 				break;
 
-			tmp = get_reg(child, addr >> 2);
+			tmp = get_reg(child, regno);
 			ret = put_user(tmp, datap);
 			break;
 		}
@@ -110,19 +112,17 @@
  		/* Write the word at location address in the USER area. */
 		case PTRACE_POKEUSR:
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+			if ((addr & 3) || regno > PT_MAX)
 				break;
 
-			addr >>= 2;
-
-			if (addr == PT_DCCR) {
+			if (regno == PT_DCCR) {
 				/* don't allow the tracing process to change stuff like
 				 * interrupt enable, kernel/user bit, dma enables etc.
 				 */
 				data &= DCCR_MASK;
 				data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
 			}
-			if (put_reg(child, addr, data))
+			if (put_reg(child, regno, data))
 				break;
 			ret = 0;
 			break;
@@ -141,7 +141,7 @@
 					break;
 				}
 				
-				data += sizeof(long);
+				datap++;
 			}
 
 			break;
@@ -165,7 +165,7 @@
 				}
 				
 				put_reg(child, i, tmp);
-				data += sizeof(long);
+				datap++;
 			}
 			
 			break;
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/cryptocop.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/cryptocop.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/cryptocop.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/cryptocop.c	2011-01-04 19:50:19.000000000 -0500
@@ -281,7 +281,8 @@
 	.owner		= THIS_MODULE,
 	.open		= cryptocop_open,
 	.release	= cryptocop_release,
-	.unlocked_ioctl = cryptocop_ioctl
+	.unlocked_ioctl = cryptocop_ioctl,
+	.llseek		= noop_llseek,
 };
 
 
@@ -3139,9 +3140,9 @@
        struct inode *inode = file->f_path.dentry->d_inode;
        long ret;
 
-       lock_kernel();
+       mutex_lock(&cryptocop_mutex);
        ret = cryptocop_ioctl_unlocked(inode, filp, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&cryptocop_mutex);
 
        return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/i2c.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/i2c.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -698,6 +698,7 @@
 	.unlocked_ioctl = i2c_ioctl,
 	.open		= i2c_open,
 	.release	= i2c_release,
+	.llseek		= noop_llseek,
 };
 
 static int __init i2c_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/mach-a3/gpio.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/mach-a3/gpio.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/mach-a3/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/mach-a3/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/etraxgpio.h>
 #include <hwregs/reg_map.h>
@@ -66,6 +66,7 @@
 #define DP(x)
 #endif
 
+static DEFINE_MUTEX(gpio_mutex);
 static char gpio_name[] = "etrax gpio";
 
 #ifdef CONFIG_ETRAX_VIRTUAL_GPIO
@@ -391,7 +392,7 @@
 	if (!priv)
 		return -ENOMEM;
 
-	lock_kernel();
+	mutex_lock(&gpio_mutex);
 	memset(priv, 0, sizeof(*priv));
 
 	priv->minor = p;
@@ -414,7 +415,7 @@
 		spin_unlock_irq(&gpio_lock);
 	}
 
-	unlock_kernel();
+	mutex_unlock(&gpio_mutex);
 	return 0;
 }
 
@@ -667,9 +668,9 @@
 {
        long ret;
 
-       lock_kernel();
+       mutex_lock(&gpio_mutex);
        ret = gpio_ioctl_unlocked(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&gpio_mutex);
 
        return ret;
 }
@@ -893,6 +894,7 @@
 	.write		= gpio_write,
 	.open		= gpio_open,
 	.release	= gpio_release,
+	.llseek		= noop_llseek,
 };
 
 #ifdef CONFIG_ETRAX_VIRTUAL_GPIO
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/mach-fs/gpio.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/mach-fs/gpio.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/mach-fs/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/mach-fs/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,7 +22,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/etraxgpio.h>
 #include <hwregs/reg_map.h>
@@ -64,6 +64,7 @@
 #define DP(x)
 #endif
 
+static DEFINE_MUTEX(gpio_mutex);
 static char gpio_name[] = "etrax gpio";
 
 #if 0
@@ -429,7 +430,7 @@
 	if (!priv)
 		return -ENOMEM;
 
-	lock_kernel();
+	mutex_lock(&gpio_mutex);
 	memset(priv, 0, sizeof(*priv));
 
 	priv->minor = p;
@@ -450,7 +451,7 @@
 	alarmlist = priv;
 	spin_unlock_irq(&alarm_lock);
 
-	unlock_kernel();
+	mutex_unlock(&gpio_mutex);
 	return 0;
 }
 
@@ -708,9 +709,9 @@
 {
        long ret;
 
-       lock_kernel();
+       mutex_lock(&gpio_mutex);
        ret = gpio_ioctl_unlocked(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&gpio_mutex);
 
        return ret;
 }
@@ -870,6 +871,7 @@
 	.write		= gpio_write,
 	.open		= gpio_open,
 	.release	= gpio_release,
+	.llseek		= noop_llseek,
 };
 
 #ifdef CONFIG_ETRAX_VIRTUAL_GPIO
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/pcf8563.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/pcf8563.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/pcf8563.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/pcf8563.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
 #include <linux/mutex.h>
@@ -45,6 +44,7 @@
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
 #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
 
+static DEFINE_MUTEX(pcf8563_mutex);
 static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
 
 static const unsigned char days_in_month[] =
@@ -60,6 +60,7 @@
 static const struct file_operations pcf8563_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl = pcf8563_unlocked_ioctl,
+	.llseek		= noop_llseek,
 };
 
 unsigned char
@@ -339,9 +340,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&pcf8563_mutex);
 	return pcf8563_ioctl(filp, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&pcf8563_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/sync_serial.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/sync_serial.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/drivers/sync_serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/drivers/sync_serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,7 +13,7 @@
 #include <linux/errno.h>
 #include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
 #include <linux/init.h>
@@ -145,6 +145,7 @@
 	spinlock_t lock;
 } sync_port;
 
+static DEFINE_MUTEX(sync_serial_mutex);
 static int etrax_sync_serial_init(void);
 static void initialize_port(int portnbr);
 static inline int sync_data_avail(struct sync_port *port);
@@ -247,7 +248,8 @@
 	.poll		= sync_serial_poll,
 	.unlocked_ioctl	= sync_serial_ioctl,
 	.open		= sync_serial_open,
-	.release	= sync_serial_release
+	.release	= sync_serial_release,
+	.llseek		= noop_llseek,
 };
 
 static int __init etrax_sync_serial_init(void)
@@ -434,7 +436,7 @@
 	reg_dma_rw_cfg cfg = {.en = regk_dma_yes};
 	reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes};
 
-	lock_kernel();
+	mutex_lock(&sync_serial_mutex);
 	DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));
 
 	if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
@@ -583,7 +585,7 @@
 	port->busy++;
 	ret = 0;
 out:
-	unlock_kernel();
+	mutex_unlock(&sync_serial_mutex);
 	return ret;
 }
 
@@ -966,9 +968,9 @@
 {
        long ret;
 
-       lock_kernel();
+       mutex_lock(&sync_serial_mutex);
        ret = sync_serial_ioctl_unlocked(file, cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&sync_serial_mutex);
 
        return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/cris/arch-v32/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/cris/arch-v32/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/cris/arch-v32/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/arch-v32/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,9 +126,11 @@
 }
 
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	unsigned int regno = addr >> 2;
 	unsigned long __user *datap = (unsigned long __user *)data;
 
 	switch (request) {
@@ -163,10 +165,10 @@
 			unsigned long tmp;
 
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+			if ((addr & 3) || regno > PT_MAX)
 				break;
 
-			tmp = get_reg(child, addr >> 2);
+			tmp = get_reg(child, regno);
 			ret = put_user(tmp, datap);
 			break;
 		}
@@ -180,19 +182,17 @@
 		/* Write the word at location address in the USER area. */
 		case PTRACE_POKEUSR:
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+			if ((addr & 3) || regno > PT_MAX)
 				break;
 
-			addr >>= 2;
-
-			if (addr == PT_CCS) {
+			if (regno == PT_CCS) {
 				/* don't allow the tracing process to change stuff like
 				 * interrupt enable, kernel/user bit, dma enables etc.
 				 */
 				data &= CCS_MASK;
 				data |= get_reg(child, PT_CCS) & ~CCS_MASK;
 			}
-			if (put_reg(child, addr, data))
+			if (put_reg(child, regno, data))
 				break;
 			ret = 0;
 			break;
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/arch-v10/arch/irqflags.h linux-libre-2.6.37-gnu/arch/cris/include/arch-v10/arch/irqflags.h
--- linux-libre-2.6.36-gnu/arch/cris/include/arch-v10/arch/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/cris/include/arch-v10/arch/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,45 @@
+#ifndef __ASM_CRIS_ARCH_IRQFLAGS_H
+#define __ASM_CRIS_ARCH_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("move $ccr,%0" : "=rm" (flags) : : "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile("di" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile("ei" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("move %0,$ccr" : : "rm" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return !(flags & (1 << 5));
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASM_CRIS_ARCH_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/arch-v10/arch/system.h linux-libre-2.6.37-gnu/arch/cris/include/arch-v10/arch/system.h
--- linux-libre-2.6.36-gnu/arch/cris/include/arch-v10/arch/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/include/arch-v10/arch/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,20 +44,4 @@
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
-/* interrupt control.. */
-#define local_save_flags(x)	__asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory");
-#define local_irq_restore(x) 	__asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory");
-#define local_irq_disable() 	__asm__ __volatile__ ( "di" : : :"memory");
-#define local_irq_enable()	__asm__ __volatile__ ( "ei" : : :"memory");
-
-#define irqs_disabled()			\
-({					\
-	unsigned long flags;		\
-	local_save_flags(flags);	\
-	!(flags & (1<<5));		\
-})
-
-/* For spinlocks etc */
-#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory");
-
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/arch-v32/arch/irqflags.h linux-libre-2.6.37-gnu/arch/cris/include/arch-v32/arch/irqflags.h
--- linux-libre-2.6.36-gnu/arch/cris/include/arch-v32/arch/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/cris/include/arch-v32/arch/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,46 @@
+#ifndef __ASM_CRIS_ARCH_IRQFLAGS_H
+#define __ASM_CRIS_ARCH_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <arch/ptrace.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("move $ccs,%0" : "=rm" (flags) : : "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile("di" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile("ei" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("move %0,$ccs" : : "rm" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return !(flags & (1 << I_CCS_BITNR));
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASM_CRIS_ARCH_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/arch-v32/arch/system.h linux-libre-2.6.37-gnu/arch/cris/include/arch-v32/arch/system.h
--- linux-libre-2.6.36-gnu/arch/cris/include/arch-v32/arch/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/include/arch-v32/arch/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,26 +44,4 @@
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
-/* Used for interrupt control. */
-#define local_save_flags(x) \
-	__asm__ __volatile__ ("move $ccs, %0" : "=rm" (x) : : "memory");
-
-#define local_irq_restore(x) \
-	__asm__ __volatile__ ("move %0, $ccs" : : "rm" (x) : "memory");
-
-#define local_irq_disable()  __asm__ __volatile__ ("di" : : : "memory");
-#define local_irq_enable()   __asm__ __volatile__ ("ei" : : : "memory");
-
-#define irqs_disabled()		\
-({				\
-	unsigned long flags;	\
-				\
-	local_save_flags(flags);\
-	!(flags & (1 << I_CCS_BITNR));	\
-})
-
-/* Used for spinlocks, etc. */
-#define local_irq_save(x) \
-	__asm__ __volatile__ ("move $ccs, %0\n\tdi" : "=rm" (x) : : "memory");
-
 #endif /* _ASM_CRIS_ARCH_SYSTEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/cris/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/cris/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,93 +1,11 @@
 #ifndef __ARCH_CRIS_IOCTLS_H__
 #define __ARCH_CRIS_IOCTLS_H__
 
-/* verbatim copy of asm-i386/ioctls.h */
-
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
 #define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
-#define FIOQSIZE	0x5460
-
 #define TIOCSERSETRS485	0x5461  /* enable rs-485 (deprecated) */
 #define TIOCSERWRRS485	0x5462  /* write rs-485 */
 #define TIOCSRS485	0x5463  /* enable rs-485 */
-#define TIOCGRS485	0x542E  /* get rs-485 */
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/cris/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/cris/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/cris/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+#include <arch/irqflags.h>
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/cris/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/cris/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -248,10 +248,8 @@
 	((pte_t *) pmd_page_vaddr(*(dir)) +  __pte_offset(address))
 #define pte_offset_map(dir, address) \
 	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #define pte_pfn(x)		((unsigned long)(__va((x).pte)) >> PAGE_SHIFT)
 #define pfn_pte(pfn, prot)	__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 
diff -druN linux-libre-2.6.36-gnu/arch/cris/include/asm/system.h linux-libre-2.6.37-gnu/arch/cris/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/cris/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,7 @@
 #ifndef __ASM_CRIS_SYSTEM_H
 #define __ASM_CRIS_SYSTEM_H
 
+#include <linux/irqflags.h>
 #include <arch/system.h>
 
 /* the switch_to macro calls resume, an asm function in entry.S which does the actual
diff -druN linux-libre-2.6.36-gnu/arch/cris/Kconfig linux-libre-2.6.37-gnu/arch/cris/Kconfig
--- linux-libre-2.6.36-gnu/arch/cris/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see the Configure script.
-#
-
-mainmenu "Linux/CRIS Kernel Configuration"
-
 config MMU
 	bool
 	default y
diff -druN linux-libre-2.6.36-gnu/arch/cris/kernel/profile.c linux-libre-2.6.37-gnu/arch/cris/kernel/profile.c
--- linux-libre-2.6.36-gnu/arch/cris/kernel/profile.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/cris/kernel/profile.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,6 +59,7 @@
 static const struct file_operations cris_proc_profile_operations = {
 	.read		= read_cris_profile,
 	.write		= write_cris_profile,
+	.llseek		= default_llseek,
 };
 
 static int __init init_cris_profile(void)
diff -druN linux-libre-2.6.36-gnu/arch/frv/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/frv/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/frv/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -112,12 +112,11 @@
 	(void *) damlr;										  \
 })
 
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *kmap_atomic_primary(struct page *page, enum km_type type)
 {
 	unsigned long paddr;
 
 	pagefault_disable();
-	debug_kmap_atomic(type);
 	paddr = page_to_phys(page);
 
 	switch (type) {
@@ -125,14 +124,6 @@
         case 1:		return __kmap_atomic_primary(1, paddr, 3);
         case 2:		return __kmap_atomic_primary(2, paddr, 4);
         case 3:		return __kmap_atomic_primary(3, paddr, 5);
-        case 4:		return __kmap_atomic_primary(4, paddr, 6);
-        case 5:		return __kmap_atomic_primary(5, paddr, 7);
-        case 6:		return __kmap_atomic_primary(6, paddr, 8);
-        case 7:		return __kmap_atomic_primary(7, paddr, 9);
-        case 8:		return __kmap_atomic_primary(8, paddr, 10);
-
-	case 9 ... 9 + NR_TLB_LINES - 1:
-		return __kmap_atomic_secondary(type - 9, paddr);
 
 	default:
 		BUG();
@@ -152,22 +143,13 @@
 	asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory");	\
 } while(0)
 
-static inline void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+static inline void kunmap_atomic_primary(void *kvaddr, enum km_type type)
 {
 	switch (type) {
         case 0:		__kunmap_atomic_primary(0, 2);	break;
         case 1:		__kunmap_atomic_primary(1, 3);	break;
         case 2:		__kunmap_atomic_primary(2, 4);	break;
         case 3:		__kunmap_atomic_primary(3, 5);	break;
-        case 4:		__kunmap_atomic_primary(4, 6);	break;
-        case 5:		__kunmap_atomic_primary(5, 7);	break;
-        case 6:		__kunmap_atomic_primary(6, 8);	break;
-        case 7:		__kunmap_atomic_primary(7, 9);	break;
-        case 8:		__kunmap_atomic_primary(8, 10);	break;
-
-	case 9 ... 9 + NR_TLB_LINES - 1:
-		__kunmap_atomic_secondary(type - 9, kvaddr);
-		break;
 
 	default:
 		BUG();
@@ -175,6 +157,9 @@
 	pagefault_enable();
 }
 
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/frv/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/frv/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/frv/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,88 +1,10 @@
 #ifndef __ASM_IOCTLS_H__
 #define __ASM_IOCTLS_H__
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* __ASM_IOCTLS_H__ */
 
diff -druN linux-libre-2.6.36-gnu/arch/frv/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/frv/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/frv/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/frv/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,158 @@
+/* FR-V interrupt handling
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+/*
+ * interrupt flag manipulation
+ * - use virtual interrupt management since touching the PSR is slow
+ *   - ICC2.Z: T if interrupts virtually disabled
+ *   - ICC2.C: F if interrupts really disabled
+ * - if Z==1 upon interrupt:
+ *   - C is set to 0
+ *   - interrupts are really disabled
+ *   - entry.S returns immediately
+ * - uses TIHI (TRAP if Z==0 && C==0) #2 to really reenable interrupts
+ *   - if taken, the trap:
+ *     - sets ICC2.C
+ *     - enables interrupts
+ */
+static inline void arch_local_irq_disable(void)
+{
+	/* set Z flag, but don't change the C flag */
+	asm volatile("	andcc	gr0,gr0,gr0,icc2	\n"
+		     :
+		     :
+		     : "memory", "icc2"
+		     );
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	/* clear Z flag and then test the C flag */
+	asm volatile("  oricc	gr0,#1,gr0,icc2		\n"
+		     "	tihi	icc2,gr0,#2		\n"
+		     :
+		     :
+		     : "memory", "icc2"
+		     );
+}
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+
+	asm volatile("movsg ccr,%0"
+		     : "=r"(flags)
+		     :
+		     : "memory");
+
+	/* shift ICC2.Z to bit 0 */
+	flags >>= 26;
+
+	/* make flags 1 if interrupts disabled, 0 otherwise */
+	return flags & 1UL;
+
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	/* load the Z flag by turning 1 if disabled into 0 if disabled
+	 * and thus setting the Z flag but not the C flag */
+	asm volatile("  xoricc	%0,#1,gr0,icc2		\n"
+		     /* then trap if Z=0 and C=0 */
+		     "	tihi	icc2,gr0,#2		\n"
+		     :
+		     : "r"(flags)
+		     : "memory", "icc2"
+		     );
+
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+/*
+ * real interrupt flag manipulation
+ */
+#define __arch_local_irq_disable()			\
+do {							\
+	unsigned long psr;				\
+	asm volatile("	movsg	psr,%0		\n"	\
+		     "	andi	%0,%2,%0	\n"	\
+		     "	ori	%0,%1,%0	\n"	\
+		     "	movgs	%0,psr		\n"	\
+		     : "=r"(psr)			\
+		     : "i" (PSR_PIL_14), "i" (~PSR_PIL)	\
+		     : "memory");			\
+} while (0)
+
+#define __arch_local_irq_enable()			\
+do {							\
+	unsigned long psr;				\
+	asm volatile("	movsg	psr,%0		\n"	\
+		     "	andi	%0,%1,%0	\n"	\
+		     "	movgs	%0,psr		\n"	\
+		     : "=r"(psr)			\
+		     : "i" (~PSR_PIL)			\
+		     : "memory");			\
+} while (0)
+
+#define __arch_local_save_flags(flags)		\
+do {						\
+	typecheck(unsigned long, flags);	\
+	asm("movsg psr,%0"			\
+	    : "=r"(flags)			\
+	    :					\
+	    : "memory");			\
+} while (0)
+
+#define	__arch_local_irq_save(flags)			\
+do {							\
+	unsigned long npsr;				\
+	typecheck(unsigned long, flags);		\
+	asm volatile("	movsg	psr,%0		\n"	\
+		     "	andi	%0,%3,%1	\n"	\
+		     "	ori	%1,%2,%1	\n"	\
+		     "	movgs	%1,psr		\n"	\
+		     : "=r"(flags), "=r"(npsr)		\
+		     : "i" (PSR_PIL_14), "i" (~PSR_PIL)	\
+		     : "memory");			\
+} while (0)
+
+#define	__arch_local_irq_restore(flags)			\
+do {							\
+	typecheck(unsigned long, flags);		\
+	asm volatile("	movgs	%0,psr		\n"	\
+		     :					\
+		     : "r" (flags)			\
+		     : "memory");			\
+} while (0)
+
+#define __arch_irqs_disabled()			\
+	((__get_PSR() & PSR_PIL) >= PSR_PIL_14)
+
+#endif /* _ASM_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/frv/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/frv/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/frv/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -451,17 +451,12 @@
 
 #if defined(CONFIG_HIGHPTE)
 #define pte_offset_map(dir, address) \
-	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
-#define pte_offset_map_nested(dir, address) \
-	((pte_t *)kmap_atomic(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+	((pte_t *)kmap_atomic(pmd_page(*(dir))) + pte_index(address))
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) \
 	((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/frv/include/asm/system.h linux-libre-2.6.37-gnu/arch/frv/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/frv/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -37,142 +37,6 @@
 } while(0)
 
 /*
- * interrupt flag manipulation
- * - use virtual interrupt management since touching the PSR is slow
- *   - ICC2.Z: T if interrupts virtually disabled
- *   - ICC2.C: F if interrupts really disabled
- * - if Z==1 upon interrupt:
- *   - C is set to 0
- *   - interrupts are really disabled
- *   - entry.S returns immediately
- * - uses TIHI (TRAP if Z==0 && C==0) #2 to really reenable interrupts
- *   - if taken, the trap:
- *     - sets ICC2.C
- *     - enables interrupts
- */
-#define local_irq_disable()					\
-do {								\
-	/* set Z flag, but don't change the C flag */		\
-	asm volatile("	andcc	gr0,gr0,gr0,icc2	\n"	\
-		     :						\
-		     :						\
-		     : "memory", "icc2"				\
-		     );						\
-} while(0)
-
-#define local_irq_enable()					\
-do {								\
-	/* clear Z flag and then test the C flag */		\
-	asm volatile("  oricc	gr0,#1,gr0,icc2		\n"	\
-		     "	tihi	icc2,gr0,#2		\n"	\
-		     :						\
-		     :						\
-		     : "memory", "icc2"				\
-		     );						\
-} while(0)
-
-#define local_save_flags(flags)					\
-do {								\
-	typecheck(unsigned long, flags);			\
-	asm volatile("movsg ccr,%0"				\
-		     : "=r"(flags)				\
-		     :						\
-		     : "memory");				\
-								\
-	/* shift ICC2.Z to bit 0 */				\
-	flags >>= 26;						\
-								\
-	/* make flags 1 if interrupts disabled, 0 otherwise */	\
-	flags &= 1UL;						\
-} while(0)
-
-#define irqs_disabled() \
-	({unsigned long flags; local_save_flags(flags); !!flags; })
-
-#define	local_irq_save(flags)			\
-do {						\
-	typecheck(unsigned long, flags);	\
-	local_save_flags(flags);		\
-	local_irq_disable();			\
-} while(0)
-
-#define	local_irq_restore(flags)					\
-do {									\
-	typecheck(unsigned long, flags);				\
-									\
-	/* load the Z flag by turning 1 if disabled into 0 if disabled	\
-	 * and thus setting the Z flag but not the C flag */		\
-	asm volatile("  xoricc	%0,#1,gr0,icc2		\n"		\
-		     /* then test Z=0 and C=0 */			\
-		     "	tihi	icc2,gr0,#2		\n"		\
-		     :							\
-		     : "r"(flags)					\
-		     : "memory", "icc2"					\
-		     );							\
-									\
-} while(0)
-
-/*
- * real interrupt flag manipulation
- */
-#define __local_irq_disable()				\
-do {							\
-	unsigned long psr;				\
-	asm volatile("	movsg	psr,%0		\n"	\
-		     "	andi	%0,%2,%0	\n"	\
-		     "	ori	%0,%1,%0	\n"	\
-		     "	movgs	%0,psr		\n"	\
-		     : "=r"(psr)			\
-		     : "i" (PSR_PIL_14), "i" (~PSR_PIL)	\
-		     : "memory");			\
-} while(0)
-
-#define __local_irq_enable()				\
-do {							\
-	unsigned long psr;				\
-	asm volatile("	movsg	psr,%0		\n"	\
-		     "	andi	%0,%1,%0	\n"	\
-		     "	movgs	%0,psr		\n"	\
-		     : "=r"(psr)			\
-		     : "i" (~PSR_PIL)			\
-		     : "memory");			\
-} while(0)
-
-#define __local_save_flags(flags)		\
-do {						\
-	typecheck(unsigned long, flags);	\
-	asm("movsg psr,%0"			\
-	    : "=r"(flags)			\
-	    :					\
-	    : "memory");			\
-} while(0)
-
-#define	__local_irq_save(flags)				\
-do {							\
-	unsigned long npsr;				\
-	typecheck(unsigned long, flags);		\
-	asm volatile("	movsg	psr,%0		\n"	\
-		     "	andi	%0,%3,%1	\n"	\
-		     "	ori	%1,%2,%1	\n"	\
-		     "	movgs	%1,psr		\n"	\
-		     : "=r"(flags), "=r"(npsr)		\
-		     : "i" (PSR_PIL_14), "i" (~PSR_PIL)	\
-		     : "memory");			\
-} while(0)
-
-#define	__local_irq_restore(flags)			\
-do {							\
-	typecheck(unsigned long, flags);		\
-	asm volatile("	movgs	%0,psr		\n"	\
-		     :					\
-		     : "r" (flags)			\
-		     : "memory");			\
-} while(0)
-
-#define __irqs_disabled() \
-	((__get_PSR() & PSR_PIL) >= PSR_PIL_14)
-
-/*
  * Force strict CPU ordering.
  */
 #define nop()			asm volatile ("nop"::)
diff -druN linux-libre-2.6.36-gnu/arch/frv/Kconfig linux-libre-2.6.37-gnu/arch/frv/Kconfig
--- linux-libre-2.6.36-gnu/arch/frv/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,12 +1,9 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
 config FRV
 	bool
 	default y
 	select HAVE_IDE
 	select HAVE_ARCH_TRACEHOOK
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 
 config ZONE_DMA
@@ -60,8 +57,6 @@
 	int
 	default 1000
 
-mainmenu "Fujitsu FR-V Kernel Configuration"
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
diff -druN linux-libre-2.6.36-gnu/arch/frv/kernel/process.c linux-libre-2.6.37-gnu/arch/frv/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/frv/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff -druN linux-libre-2.6.36-gnu/arch/frv/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/frv/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/frv/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -254,23 +254,26 @@
 	user_disable_single_step(child);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long tmp;
 	int ret;
+	int regno = addr >> 2;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR: {
 		tmp = 0;
 		ret = -EIO;
-		if ((addr & 3) || addr < 0)
+		if (addr & 3)
 			break;
 
 		ret = 0;
-		switch (addr >> 2) {
+		switch (regno) {
 		case 0 ... PT__END - 1:
-			tmp = get_reg(child, addr >> 2);
+			tmp = get_reg(child, regno);
 			break;
 
 		case PT__END + 0:
@@ -299,23 +302,18 @@
 		}
 
 		if (ret == 0)
-			ret = put_user(tmp, (unsigned long *) data);
+			ret = put_user(tmp, datap);
 		break;
 	}
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 		ret = -EIO;
-		if ((addr & 3) || addr < 0)
+		if (addr & 3)
 			break;
 
-		ret = 0;
-		switch (addr >> 2) {
+		switch (regno) {
 		case 0 ... PT__END - 1:
-			ret = put_reg(child, addr >> 2, data);
-			break;
-
-		default:
-			ret = -EIO;
+			ret = put_reg(child, regno, data);
 			break;
 		}
 		break;
@@ -324,25 +322,25 @@
 		return copy_regset_to_user(child, &user_frv_native_view,
 					   REGSET_GENERAL,
 					   0, sizeof(child->thread.user->i),
-					   (void __user *)data);
+					   datap);
 
 	case PTRACE_SETREGS:	/* Set all integer regs in the child. */
 		return copy_regset_from_user(child, &user_frv_native_view,
 					     REGSET_GENERAL,
 					     0, sizeof(child->thread.user->i),
-					     (const void __user *)data);
+					     datap);
 
 	case PTRACE_GETFPREGS:	/* Get the child FP/Media state. */
 		return copy_regset_to_user(child, &user_frv_native_view,
 					   REGSET_FPMEDIA,
 					   0, sizeof(child->thread.user->f),
-					   (void __user *)data);
+					   datap);
 
 	case PTRACE_SETFPREGS:	/* Set the child FP/Media state. */
 		return copy_regset_from_user(child, &user_frv_native_view,
 					     REGSET_FPMEDIA,
 					     0, sizeof(child->thread.user->f),
-					     (const void __user *)data);
+					     datap);
 
 	default:
 		ret = ptrace_request(child, request, addr, data);
diff -druN linux-libre-2.6.36-gnu/arch/frv/lib/Makefile linux-libre-2.6.37-gnu/arch/frv/lib/Makefile
--- linux-libre-2.6.36-gnu/arch/frv/lib/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/lib/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -5,4 +5,4 @@
 lib-y := \
 	__ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \
 	checksum.o memcpy.o memset.o atomic-ops.o atomic64-ops.o \
-	outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o perf_event.o
+	outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o
diff -druN linux-libre-2.6.36-gnu/arch/frv/lib/perf_event.c linux-libre-2.6.37-gnu/arch/frv/lib/perf_event.c
--- linux-libre-2.6.36-gnu/arch/frv/lib/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/lib/perf_event.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,19 +0,0 @@
-/* Performance event handling
- *
- * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#include <linux/perf_event.h>
-
-/*
- * mark the performance event as pending
- */
-void set_perf_event_pending(void)
-{
-}
diff -druN linux-libre-2.6.36-gnu/arch/frv/mb93090-mb00/pci-dma.c linux-libre-2.6.37-gnu/arch/frv/mb93090-mb00/pci-dma.c
--- linux-libre-2.6.36-gnu/arch/frv/mb93090-mb00/pci-dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/mb93090-mb00/pci-dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,14 +61,14 @@
 	dampr2 = __get_DAMPR(2);
 
 	for (i = 0; i < nents; i++) {
-		vaddr = kmap_atomic(sg_page(&sg[i]), __KM_CACHE);
+		vaddr = kmap_atomic_primary(sg_page(&sg[i]), __KM_CACHE);
 
 		frv_dcache_writeback((unsigned long) vaddr,
 				     (unsigned long) vaddr + PAGE_SIZE);
 
 	}
 
-	kunmap_atomic(vaddr, __KM_CACHE);
+	kunmap_atomic_primary(vaddr, __KM_CACHE);
 	if (dampr2) {
 		__set_DAMPR(2, dampr2);
 		__set_IAMPR(2, dampr2);
diff -druN linux-libre-2.6.36-gnu/arch/frv/mm/cache-page.c linux-libre-2.6.37-gnu/arch/frv/mm/cache-page.c
--- linux-libre-2.6.36-gnu/arch/frv/mm/cache-page.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/mm/cache-page.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,11 +26,11 @@
 
 	dampr2 = __get_DAMPR(2);
 
-	vaddr = kmap_atomic(page, __KM_CACHE);
+	vaddr = kmap_atomic_primary(page, __KM_CACHE);
 
 	frv_dcache_writeback((unsigned long) vaddr, (unsigned long) vaddr + PAGE_SIZE);
 
-	kunmap_atomic(vaddr, __KM_CACHE);
+	kunmap_atomic_primary(vaddr, __KM_CACHE);
 
 	if (dampr2) {
 		__set_DAMPR(2, dampr2);
@@ -54,12 +54,12 @@
 
 	dampr2 = __get_DAMPR(2);
 
-	vaddr = kmap_atomic(page, __KM_CACHE);
+	vaddr = kmap_atomic_primary(page, __KM_CACHE);
 
 	start = (start & ~PAGE_MASK) | (unsigned long) vaddr;
 	frv_cache_wback_inv(start, start + len);
 
-	kunmap_atomic(vaddr, __KM_CACHE);
+	kunmap_atomic_primary(vaddr, __KM_CACHE);
 
 	if (dampr2) {
 		__set_DAMPR(2, dampr2);
diff -druN linux-libre-2.6.36-gnu/arch/frv/mm/highmem.c linux-libre-2.6.37-gnu/arch/frv/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/frv/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/frv/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,3 +36,54 @@
 {
 	return virt_to_page(ptr);
 }
+
+void *__kmap_atomic(struct page *page)
+{
+	unsigned long paddr;
+	int type;
+
+	pagefault_disable();
+	type = kmap_atomic_idx_push();
+	paddr = page_to_phys(page);
+
+	switch (type) {
+	/*
+	 * The first 4 primary maps are reserved for architecture code
+	 */
+	case 0:		return __kmap_atomic_primary(4, paddr, 6);
+	case 1:		return __kmap_atomic_primary(5, paddr, 7);
+	case 2:		return __kmap_atomic_primary(6, paddr, 8);
+	case 3:		return __kmap_atomic_primary(7, paddr, 9);
+	case 4:		return __kmap_atomic_primary(8, paddr, 10);
+
+	case 5 ... 5 + NR_TLB_LINES - 1:
+		return __kmap_atomic_secondary(type - 5, paddr);
+
+	default:
+		BUG();
+		return NULL;
+	}
+}
+EXPORT_SYMBOL(__kmap_atomic);
+
+void __kunmap_atomic(void *kvaddr)
+{
+	int type = kmap_atomic_idx();
+	switch (type) {
+	case 0:		__kunmap_atomic_primary(4, 6);	break;
+	case 1:		__kunmap_atomic_primary(5, 7);	break;
+	case 2:		__kunmap_atomic_primary(6, 8);	break;
+	case 3:		__kunmap_atomic_primary(7, 9);	break;
+	case 4:		__kunmap_atomic_primary(8, 10);	break;
+
+	case 5 ... 5 + NR_TLB_LINES - 1:
+		__kunmap_atomic_secondary(type - 5, kvaddr);
+		break;
+
+	default:
+		BUG();
+	}
+	kmap_atomic_idx_pop();
+	pagefault_enable();
+}
+EXPORT_SYMBOL(__kunmap_atomic);
diff -druN linux-libre-2.6.36-gnu/arch/h8300/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/h8300/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/h8300/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,87 +1,8 @@
 #ifndef __ARCH_H8300_IOCTLS_H__
 #define __ARCH_H8300_IOCTLS_H__
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* __ARCH_H8300_IOCTLS_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/h8300/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/h8300/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/h8300/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/h8300/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,43 @@
+#ifndef _H8300_IRQFLAGS_H
+#define _H8300_IRQFLAGS_H
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile ("stc ccr,%w0" : "=r" (flags));
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile ("orc  #0x80,ccr" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile ("andc #0x7f,ccr" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile ("ldc %w0,ccr" : : "r" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & 0x80) == 0x80;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _H8300_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/h8300/include/asm/system.h linux-libre-2.6.37-gnu/arch/h8300/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/h8300/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,7 @@
 #define _H8300_SYSTEM_H
 
 #include <linux/linkage.h>
+#include <linux/irqflags.h>
 
 struct pt_regs;
 
@@ -51,31 +52,8 @@
   (last) = _last; 					    \
 }
 
-#define __sti() asm volatile ("andc #0x7f,ccr")
-#define __cli() asm volatile ("orc  #0x80,ccr")
-
-#define __save_flags(x) \
-       asm volatile ("stc ccr,%w0":"=r" (x))
-
-#define __restore_flags(x) \
-       asm volatile ("ldc %w0,ccr": :"r" (x))
-
-#define	irqs_disabled()			\
-({					\
-	unsigned char flags;		\
-	__save_flags(flags);	        \
-	((flags & 0x80) == 0x80);	\
-})
-
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
-/* For spinlocks etc */
-#define local_irq_disable()	__cli()
-#define local_irq_enable()      __sti()
-#define local_irq_save(x)	({ __save_flags(x); local_irq_disable(); })
-#define local_irq_restore(x)	__restore_flags(x)
-#define local_save_flags(x)     __save_flags(x)
-
 /*
  * Force strict CPU ordering.
  * Not really required on H8...
diff -druN linux-libre-2.6.36-gnu/arch/h8300/Kconfig linux-libre-2.6.37-gnu/arch/h8300/Kconfig
--- linux-libre-2.6.36-gnu/arch/h8300/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "uClinux/h8300 (w/o MMU) Kernel Configuration"
-
 config H8300
 	bool
 	default y
diff -druN linux-libre-2.6.36-gnu/arch/h8300/Kconfig.cpu linux-libre-2.6.37-gnu/arch/h8300/Kconfig.cpu
--- linux-libre-2.6.36-gnu/arch/h8300/Kconfig.cpu	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/Kconfig.cpu	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,7 @@
 	help
 	  AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
 	  More Information. (Japanese Only)
-	  <http://akizukidensi.com/catalog/h8.html>
+	  <http://akizukidenshi.com/catalog/default.aspx>
 	  AE-3068/69 Evaluation Board Support
 	  More Information.
 	  <http://www.microtronique.com/ae3069lan.htm>
@@ -36,7 +36,7 @@
 	help
 	  GDB Simulator Support
 	  More Information.
-	  arch/h8300/Doc/simulator.txt
+	  <http://sourceware.org/sid/>
 
 config H8S_GENERIC
 	bool "H8S Generic"
@@ -50,14 +50,14 @@
 	  Renesas EDOSK-2674 Evaluation Board Support
 	  More Information.
 	  <http://www.azpower.com/H8-uClinux/index.html>
- 	  <http://www.eu.renesas.com/tools/edk/support/edosk2674.html>
+ 	  <http://www.renesas.eu/products/tools/introductory_evaluation_tools/evaluation_development_os_kits/edosk2674r/edosk2674r_software_tools_root.jsp>
 
 config H8S_SIM
 	bool "H8S Simulator"
 	help
 	  GDB Simulator Support
 	  More Information.
-	  arch/h8300/Doc/simulator.txt
+	  <http://sourceware.org/sid/>
 
 endchoice
 
diff -druN linux-libre-2.6.36-gnu/arch/h8300/kernel/process.c linux-libre-2.6.37-gnu/arch/h8300/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/h8300/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff -druN linux-libre-2.6.36-gnu/arch/h8300/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/h8300/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/h8300/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,27 +50,29 @@
 	user_disable_single_step(child);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	int regno = addr >> 2;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp = 0;
 			
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+			if ((addr & 3) || addr >= sizeof(struct user)) {
 				ret = -EIO;
 				break ;
 			}
 			
 		        ret = 0;  /* Default return condition */
-			addr = addr >> 2; /* temporary hack. */
 
-			if (addr < H8300_REGS_NO)
-				tmp = h8300_get_reg(child, addr);
+			if (regno < H8300_REGS_NO)
+				tmp = h8300_get_reg(child, regno);
 			else {
-				switch(addr) {
+				switch (regno) {
 				case 49:
 					tmp = child->mm->start_code;
 					break ;
@@ -88,24 +90,23 @@
 				}
 			}
 			if (!ret)
-				ret = put_user(tmp,(unsigned long *) data);
+				ret = put_user(tmp, datap);
 			break ;
 		}
 
       /* when I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+			if ((addr & 3) || addr >= sizeof(struct user)) {
 				ret = -EIO;
 				break ;
 			}
-			addr = addr >> 2; /* temporary hack. */
 			    
-			if (addr == PT_ORIG_ER0) {
+			if (regno == PT_ORIG_ER0) {
 				ret = -EIO;
 				break ;
 			}
-			if (addr < H8300_REGS_NO) {
-				ret = h8300_put_reg(child, addr, data);
+			if (regno < H8300_REGS_NO) {
+				ret = h8300_put_reg(child, regno, data);
 				break ;
 			}
 			ret = -EIO;
@@ -116,11 +117,11 @@
 			unsigned long tmp;
 			for (i = 0; i < H8300_REGS_NO; i++) {
 			    tmp = h8300_get_reg(child, i);
-			    if (put_user(tmp, (unsigned long *) data)) {
+			    if (put_user(tmp, datap)) {
 				ret = -EFAULT;
 				break;
 			    }
-			    data += sizeof(long);
+			    datap++;
 			}
 			ret = 0;
 			break;
@@ -130,12 +131,12 @@
 			int i;
 			unsigned long tmp;
 			for (i = 0; i < H8300_REGS_NO; i++) {
-			    if (get_user(tmp, (unsigned long *) data)) {
+			    if (get_user(tmp, datap)) {
 				ret = -EFAULT;
 				break;
 			    }
 			    h8300_put_reg(child, i, tmp);
-			    data += sizeof(long);
+			    datap++;
 			}
 			ret = 0;
 			break;
diff -druN linux-libre-2.6.36-gnu/arch/h8300/README linux-libre-2.6.37-gnu/arch/h8300/README
--- linux-libre-2.6.36-gnu/arch/h8300/README	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/h8300/README	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 
 4.EDOSK2674
   see http://www.eu.renesas.com/products/mpumcu/tool/edk/support/edosk2674.html
+      http://www.uclinux.org/pub/uClinux/ports/h8/HITACHI-EDOSK2674-HOWTO
       http://www.azpower.com/H8-uClinux/
 
 * Toolchain Version
diff -druN linux-libre-2.6.36-gnu/arch/ia64/hp/sim/simscsi.c linux-libre-2.6.37-gnu/arch/ia64/hp/sim/simscsi.c
--- linux-libre-2.6.36-gnu/arch/ia64/hp/sim/simscsi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/hp/sim/simscsi.c	2011-01-04 19:50:19.000000000 -0500
@@ -202,7 +202,7 @@
 }
 
 static int
-simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
+simscsi_queuecommand_lck (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
 	unsigned int target_id = sc->device->id;
 	char fname[MAX_ROOT_LEN+16];
@@ -326,6 +326,8 @@
 	return 0;
 }
 
+static DEF_SCSI_QCMD(simscsi_queuecommand)
+
 static int
 simscsi_host_reset (struct scsi_cmnd *sc)
 {
diff -druN linux-libre-2.6.36-gnu/arch/ia64/hp/sim/simserial.c linux-libre-2.6.37-gnu/arch/ia64/hp/sim/simserial.c
--- linux-libre-2.6.36-gnu/arch/ia64/hp/sim/simserial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/hp/sim/simserial.c	2011-01-04 19:50:19.000000000 -0500
@@ -395,7 +395,7 @@
 {
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+	    (cmd != TIOCMIWAIT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
@@ -433,16 +433,6 @@
 		case TIOCMIWAIT:
 			printk(KERN_INFO "rs_ioctl: TIOCMIWAIT: called\n");
 			return 0;
-		/*
-		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-		 * Return: write counters to the user passed counter struct
-		 * NB: both 1->0 and 0->1 transitions are counted except for
-		 *     RI where only 0->1 is counted.
-		 */
-		case TIOCGICOUNT:
-			printk(KERN_INFO "rs_ioctl: TIOCGICOUNT called\n");
-			return 0;
-
 		case TIOCSERGWILD:
 		case TIOCSERSWILD:
 			/* "setserial -W" is called in Debian boot */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/compat.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/compat.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/compat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/compat.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,208 +0,0 @@
-#ifndef _ASM_IA64_COMPAT_H
-#define _ASM_IA64_COMPAT_H
-/*
- * Architecture specific compatibility types
- */
-#include <linux/types.h>
-
-#define COMPAT_USER_HZ		100
-#define COMPAT_UTS_MACHINE	"i686\0\0\0"
-
-typedef u32		compat_size_t;
-typedef s32		compat_ssize_t;
-typedef s32		compat_time_t;
-typedef s32		compat_clock_t;
-typedef s32		compat_key_t;
-typedef s32		compat_pid_t;
-typedef u16		__compat_uid_t;
-typedef u16		__compat_gid_t;
-typedef u32		__compat_uid32_t;
-typedef u32		__compat_gid32_t;
-typedef u16		compat_mode_t;
-typedef u32		compat_ino_t;
-typedef u16		compat_dev_t;
-typedef s32		compat_off_t;
-typedef s64		compat_loff_t;
-typedef u16		compat_nlink_t;
-typedef u16		compat_ipc_pid_t;
-typedef s32		compat_daddr_t;
-typedef u32		compat_caddr_t;
-typedef __kernel_fsid_t	compat_fsid_t;
-typedef s32		compat_timer_t;
-
-typedef s32		compat_int_t;
-typedef s32		compat_long_t;
-typedef s64 __attribute__((aligned(4))) compat_s64;
-typedef u32		compat_uint_t;
-typedef u32		compat_ulong_t;
-typedef u64 __attribute__((aligned(4))) compat_u64;
-
-struct compat_timespec {
-	compat_time_t	tv_sec;
-	s32		tv_nsec;
-};
-
-struct compat_timeval {
-	compat_time_t	tv_sec;
-	s32		tv_usec;
-};
-
-struct compat_stat {
-	compat_dev_t	st_dev;
-	u16		__pad1;
-	compat_ino_t	st_ino;
-	compat_mode_t	st_mode;
-	compat_nlink_t	st_nlink;
-	__compat_uid_t	st_uid;
-	__compat_gid_t	st_gid;
-	compat_dev_t	st_rdev;
-	u16		__pad2;
-	u32		st_size;
-	u32		st_blksize;
-	u32		st_blocks;
-	u32		st_atime;
-	u32		st_atime_nsec;
-	u32		st_mtime;
-	u32		st_mtime_nsec;
-	u32		st_ctime;
-	u32		st_ctime_nsec;
-	u32		__unused4;
-	u32		__unused5;
-};
-
-struct compat_flock {
-	short		l_type;
-	short		l_whence;
-	compat_off_t	l_start;
-	compat_off_t	l_len;
-	compat_pid_t	l_pid;
-};
-
-#define F_GETLK64	12
-#define F_SETLK64	13
-#define F_SETLKW64	14
-
-/*
- * IA32 uses 4 byte alignment for 64 bit quantities,
- * so we need to pack this structure.
- */
-struct compat_flock64 {
-	short		l_type;
-	short		l_whence;
-	compat_loff_t	l_start;
-	compat_loff_t	l_len;
-	compat_pid_t	l_pid;
-} __attribute__((packed));
-
-struct compat_statfs {
-	int		f_type;
-	int		f_bsize;
-	int		f_blocks;
-	int		f_bfree;
-	int		f_bavail;
-	int		f_files;
-	int		f_ffree;
-	compat_fsid_t	f_fsid;
-	int		f_namelen;	/* SunOS ignores this field. */
-	int		f_frsize;
-	int		f_spare[5];
-};
-
-#define COMPAT_RLIM_OLD_INFINITY       0x7fffffff
-#define COMPAT_RLIM_INFINITY           0xffffffff
-
-typedef u32		compat_old_sigset_t;	/* at least 32 bits */
-
-#define _COMPAT_NSIG		64
-#define _COMPAT_NSIG_BPW	32
-
-typedef u32		compat_sigset_word;
-
-#define COMPAT_OFF_T_MAX	0x7fffffff
-#define COMPAT_LOFF_T_MAX	0x7fffffffffffffffL
-
-struct compat_ipc64_perm {
-	compat_key_t key;
-	__compat_uid32_t uid;
-	__compat_gid32_t gid;
-	__compat_uid32_t cuid;
-	__compat_gid32_t cgid;
-	unsigned short mode;
-	unsigned short __pad1;
-	unsigned short seq;
-	unsigned short __pad2;
-	compat_ulong_t unused1;
-	compat_ulong_t unused2;
-};
-
-struct compat_semid64_ds {
-	struct compat_ipc64_perm sem_perm;
-	compat_time_t  sem_otime;
-	compat_ulong_t __unused1;
-	compat_time_t  sem_ctime;
-	compat_ulong_t __unused2;
-	compat_ulong_t sem_nsems;
-	compat_ulong_t __unused3;
-	compat_ulong_t __unused4;
-};
-
-struct compat_msqid64_ds {
-	struct compat_ipc64_perm msg_perm;
-	compat_time_t  msg_stime;
-	compat_ulong_t __unused1;
-	compat_time_t  msg_rtime;
-	compat_ulong_t __unused2;
-	compat_time_t  msg_ctime;
-	compat_ulong_t __unused3;
-	compat_ulong_t msg_cbytes;
-	compat_ulong_t msg_qnum;
-	compat_ulong_t msg_qbytes;
-	compat_pid_t   msg_lspid;
-	compat_pid_t   msg_lrpid;
-	compat_ulong_t __unused4;
-	compat_ulong_t __unused5;
-};
-
-struct compat_shmid64_ds {
-	struct compat_ipc64_perm shm_perm;
-	compat_size_t  shm_segsz;
-	compat_time_t  shm_atime;
-	compat_ulong_t __unused1;
-	compat_time_t  shm_dtime;
-	compat_ulong_t __unused2;
-	compat_time_t  shm_ctime;
-	compat_ulong_t __unused3;
-	compat_pid_t   shm_cpid;
-	compat_pid_t   shm_lpid;
-	compat_ulong_t shm_nattch;
-	compat_ulong_t __unused4;
-	compat_ulong_t __unused5;
-};
-
-/*
- * A pointer passed in from user mode. This should not be used for syscall parameters,
- * just declare them as pointers because the syscall entry code will have appropriately
- * converted them already.
- */
-typedef	u32		compat_uptr_t;
-
-static inline void __user *
-compat_ptr (compat_uptr_t uptr)
-{
-	return (void __user *) (unsigned long) uptr;
-}
-
-static inline compat_uptr_t
-ptr_to_compat(void __user *uptr)
-{
-	return (u32)(unsigned long)uptr;
-}
-
-static __inline__ void __user *
-arch_compat_alloc_user_space (long len)
-{
-	struct pt_regs *regs = task_pt_regs(current);
-	return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len);
-}
-
-#endif /* _ASM_IA64_COMPAT_H */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/cputime.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/cputime.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/cputime.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/cputime.h	2011-01-04 19:50:19.000000000 -0500
@@ -56,10 +56,10 @@
 #define jiffies64_to_cputime64(__jif)	((__jif) * (NSEC_PER_SEC / HZ))
 
 /*
- * Convert cputime <-> milliseconds
+ * Convert cputime <-> microseconds
  */
-#define cputime_to_msecs(__ct)		((__ct) / NSEC_PER_MSEC)
-#define msecs_to_cputime(__msecs)	((__msecs) * NSEC_PER_MSEC)
+#define cputime_to_usecs(__ct)		((__ct) / NSEC_PER_USEC)
+#define usecs_to_cputime(__usecs)	((__usecs) * NSEC_PER_USEC)
 
 /*
  * Convert cputime <-> seconds
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/hardirq.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/hardirq.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/hardirq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/hardirq.h	2011-01-04 19:50:19.000000000 -0500
@@ -6,12 +6,6 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-
-#include <linux/threads.h>
-#include <linux/irq.h>
-
-#include <asm/processor.h>
-
 /*
  * No irq_cpustat_t for IA-64.  The data is held in the per-CPU data structure.
  */
@@ -20,6 +14,11 @@
 
 #define local_softirq_pending()		(local_cpu_data->softirq_pending)
 
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+#include <asm/processor.h>
+
 extern void __iomem *ipi_base_addr;
 
 void ack_bad_irq(unsigned int irq);
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,93 +1,6 @@
 #ifndef _ASM_IA64_IOCTLS_H
 #define _ASM_IA64_IOCTLS_H
 
-/*
- * Based on <asm-i386/ioctls.h>
- *
- * Modified 1998, 1999, 2002
- *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
-#define FIOQSIZE	0x5460
-
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* _ASM_IA64_IOCTLS_H */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/iommu_table.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/iommu_table.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/iommu_table.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/iommu_table.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,6 @@
+#ifndef _ASM_IA64_IOMMU_TABLE_H
+#define _ASM_IA64_IOMMU_TABLE_H
+
+#define IOMMU_INIT_POST(_detect)
+
+#endif /* _ASM_IA64_IOMMU_TABLE_H */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,94 @@
+/*
+ * IRQ flags defines.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
+ */
+
+#ifndef _ASM_IA64_IRQFLAGS_H
+#define _ASM_IA64_IRQFLAGS_H
+
+#ifdef CONFIG_IA64_DEBUG_IRQ
+extern unsigned long last_cli_ip;
+static inline void arch_maybe_save_ip(unsigned long flags)
+{
+	if (flags & IA64_PSR_I)
+		last_cli_ip = ia64_getreg(_IA64_REG_IP);
+}
+#else
+#define arch_maybe_save_ip(flags) do {} while (0)
+#endif
+
+/*
+ * - clearing psr.i is implicitly serialized (visible by next insn)
+ * - setting psr.i requires data serialization
+ * - we need a stop-bit before reading PSR because we sometimes
+ *   write a floating-point register right before reading the PSR
+ *   and that writes to PSR.mfl
+ */
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	ia64_stop();
+#ifdef CONFIG_PARAVIRT
+	return ia64_get_psr_i();
+#else
+	return ia64_getreg(_IA64_REG_PSR);
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+
+	ia64_stop();
+	ia64_rsm(IA64_PSR_I);
+	arch_maybe_save_ip(flags);
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#ifdef CONFIG_IA64_DEBUG_IRQ
+	arch_local_irq_save();
+#else
+	ia64_stop();
+	ia64_rsm(IA64_PSR_I);
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	ia64_stop();
+	ia64_ssm(IA64_PSR_I);
+	ia64_srlz_d();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+#ifdef CONFIG_IA64_DEBUG_IRQ
+	unsigned long old_psr = arch_local_save_flags();
+#endif
+	ia64_intrin_local_irq_restore(flags & IA64_PSR_I);
+	arch_maybe_save_ip(old_psr & ~flags);
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & IA64_PSR_I) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+static inline void arch_safe_halt(void)
+{
+	ia64_pal_halt_light();	/* PAL_HALT_LIGHT */
+}
+
+
+#endif /* _ASM_IA64_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -406,9 +406,7 @@
 #define pte_index(addr)	 	(((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
 #define pte_offset_kernel(dir,addr)	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir,addr)	pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr)	pte_offset_map(dir, addr)
 #define pte_unmap(pte)			do { } while (0)
-#define pte_unmap_nested(pte)		do { } while (0)
 
 /* atomic versions of the some PTE manipulations: */
 
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/siginfo.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/siginfo.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/siginfo.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/siginfo.h	2011-01-04 19:50:19.000000000 -0500
@@ -62,6 +62,7 @@
 			int _imm;		/* immediate value for "break" */
 			unsigned int _flags;	/* see below */
 			unsigned long _isr;	/* isr */
+			short _addr_lsb;	/* lsb of faulting address */
 		} _sigfault;
 
 		/* SIGPOLL */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/include/asm/system.h linux-libre-2.6.37-gnu/arch/ia64/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/ia64/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -107,87 +107,11 @@
  */
 #define set_mb(var, value)	do { (var) = (value); mb(); } while (0)
 
-#define safe_halt()         ia64_pal_halt_light()    /* PAL_HALT_LIGHT */
-
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
  * that none of the previous instructions in the same group are
  * affected by the rsm/ssm.
  */
-/* For spinlocks etc */
-
-/*
- * - clearing psr.i is implicitly serialized (visible by next insn)
- * - setting psr.i requires data serialization
- * - we need a stop-bit before reading PSR because we sometimes
- *   write a floating-point register right before reading the PSR
- *   and that writes to PSR.mfl
- */
-#ifdef CONFIG_PARAVIRT
-#define __local_save_flags()	ia64_get_psr_i()
-#else
-#define __local_save_flags()	ia64_getreg(_IA64_REG_PSR)
-#endif
-
-#define __local_irq_save(x)			\
-do {						\
-	ia64_stop();				\
-	(x) = __local_save_flags();		\
-	ia64_stop();				\
-	ia64_rsm(IA64_PSR_I);			\
-} while (0)
-
-#define __local_irq_disable()			\
-do {						\
-	ia64_stop();				\
-	ia64_rsm(IA64_PSR_I);			\
-} while (0)
-
-#define __local_irq_restore(x)	ia64_intrin_local_irq_restore((x) & IA64_PSR_I)
-
-#ifdef CONFIG_IA64_DEBUG_IRQ
-
-  extern unsigned long last_cli_ip;
-
-# define __save_ip()		last_cli_ip = ia64_getreg(_IA64_REG_IP)
-
-# define local_irq_save(x)					\
-do {								\
-	unsigned long __psr;					\
-								\
-	__local_irq_save(__psr);				\
-	if (__psr & IA64_PSR_I)					\
-		__save_ip();					\
-	(x) = __psr;						\
-} while (0)
-
-# define local_irq_disable()	do { unsigned long __x; local_irq_save(__x); } while (0)
-
-# define local_irq_restore(x)					\
-do {								\
-	unsigned long __old_psr, __psr = (x);			\
-								\
-	local_save_flags(__old_psr);				\
-	__local_irq_restore(__psr);				\
-	if ((__old_psr & IA64_PSR_I) && !(__psr & IA64_PSR_I))	\
-		__save_ip();					\
-} while (0)
-
-#else /* !CONFIG_IA64_DEBUG_IRQ */
-# define local_irq_save(x)	__local_irq_save(x)
-# define local_irq_disable()	__local_irq_disable()
-# define local_irq_restore(x)	__local_irq_restore(x)
-#endif /* !CONFIG_IA64_DEBUG_IRQ */
-
-#define local_irq_enable()	({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); })
-#define local_save_flags(flags)	({ ia64_stop(); (flags) = __local_save_flags(); })
-
-#define irqs_disabled()				\
-({						\
-	unsigned long __ia64_id_flags;		\
-	local_save_flags(__ia64_id_flags);	\
-	(__ia64_id_flags & IA64_PSR_I) == 0;	\
-})
 
 #ifdef __KERNEL__
 
@@ -272,10 +196,6 @@
 
 void default_idle(void);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_system_vtime(struct task_struct *);
-#endif
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/Kconfig linux-libre-2.6.37-gnu/arch/ia64/Kconfig
--- linux-libre-2.6.36-gnu/arch/ia64/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "IA-64 Linux Kernel Configuration"
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -53,6 +46,9 @@
 	bool
 	default y
 
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool y
+
 config NEED_DMA_MAP_STATE
 	def_bool y
 
@@ -62,6 +58,9 @@
 config SWIOTLB
        bool
 
+config STACKTRACE_SUPPORT
+	def_bool y
+
 config GENERIC_LOCKBREAK
 	def_bool n
 
@@ -683,8 +682,10 @@
 # Use the generic interrupt handling code in kernel/irq/:
 #
 config GENERIC_HARDIRQS
-	bool
-	default y
+	def_bool y
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+	def_bool y
 
 config GENERIC_IRQ_PROBE
 	bool
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/cyclone.c linux-libre-2.6.37-gnu/arch/ia64/kernel/cyclone.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/cyclone.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/cyclone.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,13 +59,13 @@
 		return -ENODEV;
 	}
 	base = readq(reg);
+	iounmap(reg);
 	if(!base){
 		printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
 				" value.\n");
 		use_cyclone = 0;
 		return -ENODEV;
 	}
-	iounmap(reg);
 
 	/* setup PMCC */
 	offset = (base + CYCLONE_PMCC_OFFSET);
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/iosapic.c linux-libre-2.6.37-gnu/arch/ia64/kernel/iosapic.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/iosapic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/iosapic.c	2011-01-04 19:50:19.000000000 -0500
@@ -108,10 +108,6 @@
 #define DBG(fmt...)
 #endif
 
-#define NR_PREALLOCATE_RTE_ENTRIES \
-	(PAGE_SIZE / sizeof(struct iosapic_rte_info))
-#define RTE_PREALLOCATED	(1)
-
 static DEFINE_SPINLOCK(iosapic_lock);
 
 /*
@@ -136,7 +132,6 @@
 	struct list_head rte_list;	/* RTEs sharing the same vector */
 	char		rte_index;	/* IOSAPIC RTE index */
 	int		refcnt;		/* reference counter */
-	unsigned int	flags;		/* flags */
 	struct iosapic	*iosapic;
 } ____cacheline_aligned;
 
@@ -155,9 +150,6 @@
 
 static unsigned char pcat_compat __devinitdata;	/* 8259 compatibility flag */
 
-static int iosapic_kmalloc_ok;
-static LIST_HEAD(free_rte_list);
-
 static inline void
 iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
 {
@@ -394,7 +386,7 @@
 }
 
 static void
-iosapic_end_level_irq (unsigned int irq)
+iosapic_unmask_level_irq (unsigned int irq)
 {
 	ia64_vector vec = irq_to_vector(irq);
 	struct iosapic_rte_info *rte;
@@ -404,7 +396,8 @@
 	if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
 		do_unmask_irq = 1;
 		mask_irq(irq);
-	}
+	} else
+		unmask_irq(irq);
 
 	list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
 		iosapic_eoi(rte->iosapic->addr, vec);
@@ -427,9 +420,8 @@
 	.enable =	iosapic_enable_level_irq,
 	.disable =	iosapic_disable_level_irq,
 	.ack =		iosapic_ack_level_irq,
-	.end =		iosapic_end_level_irq,
 	.mask =		mask_irq,
-	.unmask =	unmask_irq,
+	.unmask =	iosapic_unmask_level_irq,
 	.set_affinity =	iosapic_set_affinity
 };
 
@@ -552,37 +544,6 @@
 	}
 }
 
-static struct iosapic_rte_info * __init_refok iosapic_alloc_rte (void)
-{
-	int i;
-	struct iosapic_rte_info *rte;
-	int preallocated = 0;
-
-	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
-		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
-				    NR_PREALLOCATE_RTE_ENTRIES);
-		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
-			list_add(&rte->rte_list, &free_rte_list);
-	}
-
-	if (!list_empty(&free_rte_list)) {
-		rte = list_entry(free_rte_list.next, struct iosapic_rte_info,
-				 rte_list);
-		list_del(&rte->rte_list);
-		preallocated++;
-	} else {
-		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
-		if (!rte)
-			return NULL;
-	}
-
-	memset(rte, 0, sizeof(struct iosapic_rte_info));
-	if (preallocated)
-		rte->flags |= RTE_PREALLOCATED;
-
-	return rte;
-}
-
 static inline int irq_is_shared (int irq)
 {
 	return (iosapic_intr_info[irq].count > 1);
@@ -615,7 +576,7 @@
 
 	rte = find_rte(irq, gsi);
 	if (!rte) {
-		rte = iosapic_alloc_rte();
+		rte = kzalloc(sizeof (*rte), GFP_ATOMIC);
 		if (!rte) {
 			printk(KERN_WARNING "%s: cannot allocate memory\n",
 			       __func__);
@@ -658,6 +619,10 @@
 			       idesc->chip->name, irq_type->name);
 		idesc->chip = irq_type;
 	}
+	if (trigger == IOSAPIC_EDGE)
+		__set_irq_handler_unlocked(irq, handle_edge_irq);
+	else
+		__set_irq_handler_unlocked(irq, handle_level_irq);
 	return 0;
 }
 
@@ -1161,10 +1126,3 @@
 	return;
 }
 #endif
-
-static int __init iosapic_enable_kmalloc (void)
-{
-	iosapic_kmalloc_ok = 1;
-	return 0;
-}
-core_initcall (iosapic_enable_kmalloc);
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/irq_ia64.c linux-libre-2.6.37-gnu/arch/ia64/kernel/irq_ia64.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/irq_ia64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/irq_ia64.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/bitops.h>
 #include <linux/irq.h>
 #include <linux/ratelimit.h>
+#include <linux/acpi.h>
 
 #include <asm/delay.h>
 #include <asm/intrinsics.h>
@@ -635,6 +636,7 @@
 	desc->chip = &irq_type_ia64_lsapic;
 	if (action)
 		setup_irq(irq, action);
+	set_irq_handler(irq, handle_percpu_irq);
 }
 
 void __init
@@ -650,6 +652,9 @@
 void __init
 init_IRQ (void)
 {
+#ifdef CONFIG_ACPI
+	acpi_boot_init();
+#endif
 	ia64_register_ipi();
 	register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
 #ifdef CONFIG_SMP
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/Makefile linux-libre-2.6.37-gnu/arch/ia64/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,7 @@
 obj-$(CONFIG_PCI_MSI)		+= msi_ia64.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
 obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
+obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirtentry.o \
 				   paravirt_patch.o
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/mca.c linux-libre-2.6.37-gnu/arch/ia64/kernel/mca.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/mca.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/mca.c	2011-01-04 19:50:19.000000000 -0500
@@ -2055,25 +2055,6 @@
 
 	IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __func__);
 
-	/*
-	 *  Configure the CMCI/P vector and handler. Interrupts for CMC are
-	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
-	 */
-	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
-	register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
-	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP */
-
-	/* Setup the MCA rendezvous interrupt vector */
-	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
-
-	/* Setup the MCA wakeup interrupt vector */
-	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
-
-#ifdef CONFIG_ACPI
-	/* Setup the CPEI/P handler */
-	register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
-#endif
-
 	/* Initialize the areas set aside by the OS to buffer the
 	 * platform/processor error states for MCA/INIT/CMC
 	 * handling.
@@ -2103,6 +2084,25 @@
 	if (!mca_init)
 		return 0;
 
+	/*
+	 *  Configure the CMCI/P vector and handler. Interrupts for CMC are
+	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
+	 */
+	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
+	register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
+	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP */
+
+	/* Setup the MCA rendezvous interrupt vector */
+	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
+
+	/* Setup the MCA wakeup interrupt vector */
+	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
+
+#ifdef CONFIG_ACPI
+	/* Setup the CPEI/P handler */
+	register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
+#endif
+
 	register_hotcpu_notifier(&mca_cpu_notifier);
 
 	/* Setup the CMCI/P vector and handler */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/msi_ia64.c linux-libre-2.6.37-gnu/arch/ia64/kernel/msi_ia64.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/msi_ia64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/msi_ia64.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,8 +104,8 @@
  */
 static struct irq_chip ia64_msi_chip = {
 	.name		= "PCI-MSI",
-	.mask		= mask_msi_irq,
-	.unmask		= unmask_msi_irq,
+	.irq_mask	= mask_msi_irq,
+	.irq_unmask	= unmask_msi_irq,
 	.ack		= ia64_ack_msi_irq,
 #ifdef CONFIG_SMP
 	.set_affinity	= ia64_set_msi_irq_affinity,
@@ -160,8 +160,8 @@
 
 static struct irq_chip dmar_msi_type = {
 	.name = "DMAR_MSI",
-	.unmask = dmar_msi_unmask,
-	.mask = dmar_msi_mask,
+	.irq_unmask = dmar_msi_unmask,
+	.irq_mask = dmar_msi_mask,
 	.ack = ia64_ack_msi_irq,
 #ifdef CONFIG_SMP
 	.set_affinity = dmar_msi_set_affinity,
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/palinfo.c linux-libre-2.6.37-gnu/arch/ia64/kernel/palinfo.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/palinfo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/palinfo.c	2011-01-04 19:50:19.000000000 -0500
@@ -434,7 +434,7 @@
 	unsigned long phys_stacked;
 	pal_hints_u_t hints;
 	unsigned long iregs, dregs;
-	char *info_type[]={
+	static const char * const info_type[] = {
 		"Implemented AR(s)",
 		"AR(s) with read side-effects",
 		"Implemented CR(s)",
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/perfmon.c linux-libre-2.6.37-gnu/arch/ia64/kernel/perfmon.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/perfmon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/perfmon.c	2011-01-04 19:50:19.000000000 -0500
@@ -618,16 +618,15 @@
 }
 
 
-static int
-pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data,
-	     struct vfsmount *mnt)
+static struct dentry *
+pfmfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
 {
-	return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt);
+	return mount_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC);
 }
 
 static struct file_system_type pfm_fs_type = {
 	.name     = "pfmfs",
-	.get_sb   = pfmfs_get_sb,
+	.mount    = pfmfs_mount,
 	.kill_sb  = kill_anon_super,
 };
 
@@ -1573,7 +1572,7 @@
 		return -EINVAL;
 	}
 
-	ctx = (pfm_context_t *)filp->private_data;
+	ctx = filp->private_data;
 	if (ctx == NULL) {
 		printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", task_pid_nr(current));
 		return -EINVAL;
@@ -1673,7 +1672,7 @@
 		return 0;
 	}
 
-	ctx = (pfm_context_t *)filp->private_data;
+	ctx = filp->private_data;
 	if (ctx == NULL) {
 		printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", task_pid_nr(current));
 		return 0;
@@ -1733,7 +1732,7 @@
 		return -EBADF;
 	}
 
-	ctx = (pfm_context_t *)filp->private_data;
+	ctx = filp->private_data;
 	if (ctx == NULL) {
 		printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", task_pid_nr(current));
 		return -EBADF;
@@ -1841,7 +1840,7 @@
 		return -EBADF;
 	}
 
-	ctx = (pfm_context_t *)filp->private_data;
+	ctx = filp->private_data;
 	if (ctx == NULL) {
 		printk(KERN_ERR "perfmon: pfm_flush: NULL ctx [%d]\n", task_pid_nr(current));
 		return -EBADF;
@@ -1984,7 +1983,7 @@
 		return -EBADF;
 	}
 	
-	ctx = (pfm_context_t *)filp->private_data;
+	ctx = filp->private_data;
 	if (ctx == NULL) {
 		printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", task_pid_nr(current));
 		return -EBADF;
@@ -4907,7 +4906,7 @@
 		goto error_args;
 	}
 
-	ctx = (pfm_context_t *)file->private_data;
+	ctx = file->private_data;
 	if (unlikely(ctx == NULL)) {
 		DPRINT(("no context for fd %d\n", fd));
 		goto error_args;
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/ia64/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -1177,7 +1177,8 @@
 }
 
 long
-arch_ptrace (struct task_struct *child, long request, long addr, long data)
+arch_ptrace (struct task_struct *child, long request,
+	     unsigned long addr, unsigned long data)
 {
 	switch (request) {
 	case PTRACE_PEEKTEXT:
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/salinfo.c linux-libre-2.6.37-gnu/arch/ia64/kernel/salinfo.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/salinfo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/salinfo.c	2011-01-04 19:50:19.000000000 -0500
@@ -354,6 +354,7 @@
 static const struct file_operations salinfo_event_fops = {
 	.open  = salinfo_event_open,
 	.read  = salinfo_event_read,
+	.llseek = noop_llseek,
 };
 
 static int
@@ -571,6 +572,7 @@
 	.release = salinfo_log_release,
 	.read    = salinfo_log_read,
 	.write   = salinfo_log_write,
+	.llseek  = default_llseek,
 };
 
 static int __cpuinit
@@ -642,7 +644,7 @@
 	for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
 		data = salinfo_data + i;
 		data->type = i;
-		init_MUTEX(&data->mutex);
+		sema_init(&data->mutex, 1);
 		dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
 		if (!dir)
 			continue;
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/setup.c linux-libre-2.6.37-gnu/arch/ia64/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -594,10 +594,6 @@
 	cpu_init();	/* initialize the bootstrap CPU */
 	mmu_context_init();	/* initialize context_id bitmap */
 
-#ifdef CONFIG_ACPI
-	acpi_boot_init();
-#endif
-
 	paravirt_banner();
 	paravirt_arch_setup_console(cmdline_p);
 
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/stacktrace.c linux-libre-2.6.37-gnu/arch/ia64/kernel/stacktrace.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/stacktrace.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/stacktrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,39 @@
+/*
+ * arch/ia64/kernel/stacktrace.c
+ *
+ * Stack trace management functions
+ *
+ */
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/module.h>
+
+static void
+ia64_do_save_stack(struct unw_frame_info *info, void *arg)
+{
+	struct stack_trace *trace = arg;
+	unsigned long ip;
+	int skip = trace->skip;
+
+	trace->nr_entries = 0;
+	do {
+		unw_get_ip(info, &ip);
+		if (ip == 0)
+			break;
+		if (skip == 0) {
+			trace->entries[trace->nr_entries++] = ip;
+			if (trace->nr_entries == trace->max_entries)
+				break;
+		} else
+			skip--;
+	} while (unw_unwind(info) >= 0);
+}
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+	unw_init_running(ia64_do_save_stack, trace);
+}
+EXPORT_SYMBOL(save_stack_trace);
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kernel/unwind.c linux-libre-2.6.37-gnu/arch/ia64/kernel/unwind.c
--- linux-libre-2.6.36-gnu/arch/ia64/kernel/unwind.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kernel/unwind.c	2011-01-04 19:50:19.000000000 -0500
@@ -1204,10 +1204,10 @@
 static inline unw_hash_index_t
 hash (unsigned long ip)
 {
-#	define hashmagic	0x9e3779b97f4a7c16UL	/* based on (sqrt(5)/2-1)*2^64 */
+	/* magic number = ((sqrt(5)-1)/2)*2^64 */
+	static const unsigned long hashmagic = 0x9e3779b97f4a7c16UL;
 
-	return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE);
-#undef hashmagic
+	return (ip >> 4) * hashmagic >> (64 - UNW_LOG_HASH_SIZE);
 }
 
 static inline long
@@ -1531,7 +1531,7 @@
 	struct unw_labeled_state *ls, *next;
 	unsigned long ip = info->ip;
 	struct unw_state_record sr;
-	struct unw_table *table;
+	struct unw_table *table, *prev;
 	struct unw_reg_info *r;
 	struct unw_insn insn;
 	u8 *dp, *desc_end;
@@ -1560,11 +1560,26 @@
 
 	STAT(parse_start = ia64_get_itc());
 
+	prev = NULL;
 	for (table = unw.tables; table; table = table->next) {
 		if (ip >= table->start && ip < table->end) {
+			/*
+			 * Leave the kernel unwind table at the very front,
+			 * lest moving it breaks some assumption elsewhere.
+			 * Otherwise, move the matching table to the second
+			 * position in the list so that traversals can benefit
+			 * from commonality in backtrace paths.
+			 */
+			if (prev && prev != unw.tables) {
+				/* unw is safe - we're already spinlocked */
+				prev->next = table->next;
+				table->next = unw.tables->next;
+				unw.tables->next = table;
+			}
 			e = lookup(table, ip - table->segment_base);
 			break;
 		}
+		prev = table;
 	}
 	if (!e) {
 		/* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */
diff -druN linux-libre-2.6.36-gnu/arch/ia64/kvm/lapic.h linux-libre-2.6.37-gnu/arch/ia64/kvm/lapic.h
--- linux-libre-2.6.36-gnu/arch/ia64/kvm/lapic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/kvm/lapic.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,5 +25,6 @@
 int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
 int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
 #define kvm_apic_present(x) (true)
+#define kvm_lapic_enabled(x) (true)
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/ia64/sn/kernel/msi_sn.c linux-libre-2.6.37-gnu/arch/ia64/sn/kernel/msi_sn.c
--- linux-libre-2.6.36-gnu/arch/ia64/sn/kernel/msi_sn.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/sn/kernel/msi_sn.c	2011-01-04 19:50:19.000000000 -0500
@@ -228,8 +228,8 @@
 
 static struct irq_chip sn_msi_chip = {
 	.name		= "PCI-MSI",
-	.mask		= mask_msi_irq,
-	.unmask		= unmask_msi_irq,
+	.irq_mask	= mask_msi_irq,
+	.irq_unmask	= unmask_msi_irq,
 	.ack		= sn_ack_msi_irq,
 #ifdef CONFIG_SMP
 	.set_affinity	= sn_set_msi_irq_affinity,
diff -druN linux-libre-2.6.36-gnu/arch/ia64/sn/kernel/sn2/sn_hwperf.c linux-libre-2.6.37-gnu/arch/ia64/sn/kernel/sn2/sn_hwperf.c
--- linux-libre-2.6.36-gnu/arch/ia64/sn/kernel/sn2/sn_hwperf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/sn/kernel/sn2/sn_hwperf.c	2011-01-04 19:50:19.000000000 -0500
@@ -860,6 +860,7 @@
 
 static const struct file_operations sn_hwperf_fops = {
 	.unlocked_ioctl = sn_hwperf_ioctl,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice sn_hwperf_dev = {
diff -druN linux-libre-2.6.36-gnu/arch/ia64/xen/xen_pv_ops.c linux-libre-2.6.37-gnu/arch/ia64/xen/xen_pv_ops.c
--- linux-libre-2.6.36-gnu/arch/ia64/xen/xen_pv_ops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/ia64/xen/xen_pv_ops.c	2011-01-04 19:50:19.000000000 -0500
@@ -1136,7 +1136,6 @@
 static void __init
 xen_patch_branch(unsigned long tag, unsigned long type)
 {
-	const unsigned long nelem =
-		sizeof(xen_branch_target) / sizeof(xen_branch_target[0]);
-	__paravirt_patch_apply_branch(tag, type, xen_branch_target, nelem);
+	__paravirt_patch_apply_branch(tag, type, xen_branch_target,
+					ARRAY_SIZE(xen_branch_target));
 }
diff -druN linux-libre-2.6.36-gnu/arch/Kconfig linux-libre-2.6.37-gnu/arch/Kconfig
--- linux-libre-2.6.36-gnu/arch/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -42,6 +42,20 @@
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+config JUMP_LABEL
+       bool "Optimize trace point call sites"
+       depends on HAVE_ARCH_JUMP_LABEL
+       help
+         If it is detected that the compiler has support for "asm goto",
+	 the kernel will compile trace point locations with just a
+	 nop instruction. When trace points are enabled, the nop will
+	 be converted to a jump to the trace function. This technique
+	 lowers overhead and stress on the branch prediction of the
+	 processor.
+
+	 On i386, options added to the compiler flags may increase
+	 the size of the kernel slightly.
+
 config OPTPROBES
 	def_bool y
 	depends on KPROBES && HAVE_OPTPROBES
@@ -158,4 +172,7 @@
 	  subsystem.  Also has support for calculating CPU cycle events
 	  to determine how many clock cycles in a given period.
 
+config HAVE_ARCH_JUMP_LABEL
+	bool
+
 source "kernel/gcov/Kconfig"
diff -druN linux-libre-2.6.36-gnu/arch/m32r/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/m32r/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/m32r/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,87 +1,6 @@
 #ifndef __ARCH_M32R_IOCTLS_H__
 #define __ARCH_M32R_IOCTLS_H__
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
-#define FIOQSIZE	0x5460
-
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* __ARCH_M32R_IOCTLS_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/m32r/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/m32r/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/m32r/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m32r/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,104 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#ifndef _ASM_M32R_IRQFLAGS_H
+#define _ASM_M32R_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("mvfc %0,psw" : "=r"(flags));
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
+	asm volatile (
+		"clrpsw #0x40 -> nop"
+		: : : "memory");
+#else
+	unsigned long tmpreg0, tmpreg1;
+	asm volatile (
+		"ld24	%0, #0	; Use 32-bit insn.			\n\t"
+		"mvfc	%1, psw	; No interrupt can be accepted here.	\n\t"
+		"mvtc	%0, psw						\n\t"
+		"and3	%0, %1, #0xffbf					\n\t"
+		"mvtc	%0, psw						\n\t"
+		: "=&r" (tmpreg0), "=&r" (tmpreg1)
+		:
+		: "cbit", "memory");
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
+	asm volatile (
+		"setpsw #0x40 -> nop"
+		: : : "memory");
+#else
+	unsigned long tmpreg;
+	asm volatile (
+		"mvfc	%0, psw;		\n\t"
+		"or3	%0, %0, #0x0040;	\n\t"
+		"mvtc	%0, psw;		\n\t"
+		: "=&r" (tmpreg)
+		:
+		: "cbit", "memory");
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+
+#if !(defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_M32104))
+	asm volatile (
+		"mvfc	%0, psw;	\n\t"
+		"clrpsw	#0x40 -> nop;	\n\t"
+		: "=r" (flags)
+		:
+		: "memory");
+#else
+	unsigned long tmpreg;
+	asm volatile (
+		"ld24	%1, #0		\n\t"
+		"mvfc	%0, psw		\n\t"
+		"mvtc	%1, psw		\n\t"
+		"and3	%1, %0, #0xffbf	\n\t"
+		"mvtc	%1, psw		\n\t"
+		: "=r" (flags), "=&r" (tmpreg)
+		:
+		: "cbit", "memory");
+#endif
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("mvtc %0,psw"
+		     :
+		     : "r" (flags)
+		     : "cbit", "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return !(flags & 0x40);
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _ASM_M32R_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/m32r/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/m32r/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/m32r/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -332,9 +332,7 @@
 	((pte_t *)pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address)	\
 	((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address)	pte_offset_map(dir, address)
 #define pte_unmap(pte)		do { } while (0)
-#define pte_unmap_nested(pte)	do { } while (0)
 
 /* Encode and de-code a swap entry */
 #define __swp_type(x)			(((x).val >> 2) & 0x1f)
diff -druN linux-libre-2.6.36-gnu/arch/m32r/include/asm/system.h linux-libre-2.6.37-gnu/arch/m32r/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/m32r/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
  */
 
 #include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <asm/assembler.h>
 
 #ifdef __KERNEL__
@@ -54,71 +55,6 @@
 	); \
 } while(0)
 
-/* Interrupt Control */
-#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
-#define local_irq_enable() \
-	__asm__ __volatile__ ("setpsw #0x40 -> nop": : :"memory")
-#define local_irq_disable() \
-	__asm__ __volatile__ ("clrpsw #0x40 -> nop": : :"memory")
-#else	/* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-static inline void local_irq_enable(void)
-{
-	unsigned long tmpreg;
-	__asm__ __volatile__(
-		"mvfc	%0, psw;		\n\t"
-		"or3	%0, %0, #0x0040;	\n\t"
-		"mvtc	%0, psw;		\n\t"
-	: "=&r" (tmpreg) : : "cbit", "memory");
-}
-
-static inline void local_irq_disable(void)
-{
-	unsigned long tmpreg0, tmpreg1;
-	__asm__ __volatile__(
-		"ld24	%0, #0	; Use 32-bit insn. \n\t"
-		"mvfc	%1, psw	; No interrupt can be accepted here. \n\t"
-		"mvtc	%0, psw	\n\t"
-		"and3	%0, %1, #0xffbf	\n\t"
-		"mvtc	%0, psw	\n\t"
-	: "=&r" (tmpreg0), "=&r" (tmpreg1) : : "cbit", "memory");
-}
-#endif	/* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-
-#define local_save_flags(x) \
-	__asm__ __volatile__("mvfc %0,psw" : "=r"(x) : /* no input */)
-
-#define local_irq_restore(x) \
-	__asm__ __volatile__("mvtc %0,psw" : /* no outputs */ \
-		: "r" (x) : "cbit", "memory")
-
-#if !(defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_M32104))
-#define local_irq_save(x)				\
-	__asm__ __volatile__(				\
-  		"mvfc	%0, psw;		\n\t"	\
-	  	"clrpsw	#0x40 -> nop;		\n\t"	\
-  		: "=r" (x) : /* no input */ : "memory")
-#else	/* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-#define local_irq_save(x) 				\
-	({						\
-		unsigned long tmpreg;			\
-		__asm__ __volatile__( 			\
-			"ld24	%1, #0 \n\t" 		\
-			"mvfc	%0, psw \n\t"		\
-			"mvtc	%1, psw \n\t"		\
-			"and3	%1, %0, #0xffbf \n\t"	\
-			"mvtc	%1, psw \n\t" 		\
-			: "=r" (x), "=&r" (tmpreg)	\
-			: : "cbit", "memory");		\
-	})
-#endif	/* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-
-#define irqs_disabled()					\
-	({						\
-		unsigned long flags;			\
-		local_save_flags(flags);		\
-		!(flags & 0x40);			\
-	})
-
 #define nop()	__asm__ __volatile__ ("nop" : : )
 
 #define xchg(ptr, x)							\
diff -druN linux-libre-2.6.36-gnu/arch/m32r/Kconfig linux-libre-2.6.37-gnu/arch/m32r/Kconfig
--- linux-libre-2.6.36-gnu/arch/m32r/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux/M32R Kernel Configuration"
-
 config M32R
 	bool
 	default y
@@ -315,7 +308,7 @@
 	  Management" code will be disabled if you say Y here.
 
 	  See also the SMP-HOWTO available at
-	  <http://www.linuxdoc.org/docs.html#howto>.
+	  <http://tldp.org/HOWTO/SMP-HOWTO.html>.
 
 	  If you don't know what to do here, say N.
 
diff -druN linux-libre-2.6.36-gnu/arch/m32r/kernel/irq.c linux-libre-2.6.37-gnu/arch/m32r/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/m32r/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,7 +51,7 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %14s", irq_desc[i].chip->name);
 		seq_printf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
diff -druN linux-libre-2.6.36-gnu/arch/m32r/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/m32r/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/m32r/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -622,9 +622,11 @@
 }
 
 long
-arch_ptrace(struct task_struct *child, long request, long addr, long data)
+arch_ptrace(struct task_struct *child, long request,
+	    unsigned long addr, unsigned long data)
 {
 	int ret;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 	/*
@@ -639,8 +641,7 @@
 	 * read the word at location addr in the USER area.
 	 */
 	case PTRACE_PEEKUSR:
-		ret = ptrace_read_user(child, addr,
-				       (unsigned long __user *)data);
+		ret = ptrace_read_user(child, addr, datap);
 		break;
 
 	/*
@@ -661,11 +662,11 @@
 		break;
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs(child, (void __user *)data);
+		ret = ptrace_getregs(child, datap);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs(child, (void __user *)data);
+		ret = ptrace_setregs(child, datap);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/m32104ut/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/m32104ut/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/m32104ut/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/m32104ut/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,7 @@
 
 static struct irq_chip m32104ut_irq_type =
 {
-	.typename = "M32104UT-IRQ",
+	.name = "M32104UT-IRQ",
 	.startup = startup_m32104ut_irq,
 	.shutdown = shutdown_m32104ut_irq,
 	.enable = enable_m32104ut_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/m32700ut/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/m32700ut/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/m32700ut/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/m32700ut/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -71,7 +71,7 @@
 
 static struct irq_chip m32700ut_irq_type =
 {
-	.typename = "M32700UT-IRQ",
+	.name = "M32700UT-IRQ",
 	.startup = startup_m32700ut_irq,
 	.shutdown = shutdown_m32700ut_irq,
 	.enable = enable_m32700ut_irq,
@@ -148,7 +148,7 @@
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-	.typename = "M32700UT-PLD-IRQ",
+	.name = "M32700UT-PLD-IRQ",
 	.startup = startup_m32700ut_pld_irq,
 	.shutdown = shutdown_m32700ut_pld_irq,
 	.enable = enable_m32700ut_pld_irq,
@@ -217,7 +217,7 @@
 
 static struct irq_chip m32700ut_lanpld_irq_type =
 {
-	.typename = "M32700UT-PLD-LAN-IRQ",
+	.name = "M32700UT-PLD-LAN-IRQ",
 	.startup = startup_m32700ut_lanpld_irq,
 	.shutdown = shutdown_m32700ut_lanpld_irq,
 	.enable = enable_m32700ut_lanpld_irq,
@@ -286,7 +286,7 @@
 
 static struct irq_chip m32700ut_lcdpld_irq_type =
 {
-	.typename = "M32700UT-PLD-LCD-IRQ",
+	.name = "M32700UT-PLD-LCD-IRQ",
 	.startup = startup_m32700ut_lcdpld_irq,
 	.shutdown = shutdown_m32700ut_lcdpld_irq,
 	.enable = enable_m32700ut_lcdpld_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,7 @@
 
 static struct irq_chip mappi_irq_type =
 {
-	.typename = "MAPPI-IRQ",
+	.name = "MAPPI-IRQ",
 	.startup = startup_mappi_irq,
 	.shutdown = shutdown_mappi_irq,
 	.enable = enable_mappi_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi2/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi2/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi2/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi2/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 
 static struct irq_chip mappi2_irq_type =
 {
-	.typename = "MAPPI2-IRQ",
+	.name = "MAPPI2-IRQ",
 	.startup = startup_mappi2_irq,
 	.shutdown = shutdown_mappi2_irq,
 	.enable = enable_mappi2_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi3/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi3/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/mappi3/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/mappi3/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 
 static struct irq_chip mappi3_irq_type =
 {
-	.typename = "MAPPI3-IRQ",
+	.name = "MAPPI3-IRQ",
 	.startup = startup_mappi3_irq,
 	.shutdown = shutdown_mappi3_irq,
 	.enable = enable_mappi3_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/oaks32r/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/oaks32r/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/oaks32r/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/oaks32r/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -63,7 +63,7 @@
 
 static struct irq_chip oaks32r_irq_type =
 {
-	.typename = "OAKS32R-IRQ",
+	.name = "OAKS32R-IRQ",
 	.startup = startup_oaks32r_irq,
 	.shutdown = shutdown_oaks32r_irq,
 	.enable = enable_oaks32r_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/opsput/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/opsput/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/opsput/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/opsput/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 
 static struct irq_chip opsput_irq_type =
 {
-	.typename = "OPSPUT-IRQ",
+	.name = "OPSPUT-IRQ",
 	.startup = startup_opsput_irq,
 	.shutdown = shutdown_opsput_irq,
 	.enable = enable_opsput_irq,
@@ -149,7 +149,7 @@
 
 static struct irq_chip opsput_pld_irq_type =
 {
-	.typename = "OPSPUT-PLD-IRQ",
+	.name = "OPSPUT-PLD-IRQ",
 	.startup = startup_opsput_pld_irq,
 	.shutdown = shutdown_opsput_pld_irq,
 	.enable = enable_opsput_pld_irq,
@@ -218,7 +218,7 @@
 
 static struct irq_chip opsput_lanpld_irq_type =
 {
-	.typename = "OPSPUT-PLD-LAN-IRQ",
+	.name = "OPSPUT-PLD-LAN-IRQ",
 	.startup = startup_opsput_lanpld_irq,
 	.shutdown = shutdown_opsput_lanpld_irq,
 	.enable = enable_opsput_lanpld_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m32r/platforms/usrv/setup.c linux-libre-2.6.37-gnu/arch/m32r/platforms/usrv/setup.c
--- linux-libre-2.6.36-gnu/arch/m32r/platforms/usrv/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m32r/platforms/usrv/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -63,7 +63,7 @@
 
 static struct irq_chip mappi_irq_type =
 {
-	.typename = "M32700-IRQ",
+	.name = "M32700-IRQ",
 	.startup = startup_mappi_irq,
 	.shutdown = shutdown_mappi_irq,
 	.enable = enable_mappi_irq,
@@ -136,7 +136,7 @@
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-	.typename = "USRV-PLD-IRQ",
+	.name = "USRV-PLD-IRQ",
 	.startup = startup_m32700ut_pld_irq,
 	.shutdown = shutdown_m32700ut_pld_irq,
 	.enable = enable_m32700ut_pld_irq,
diff -druN linux-libre-2.6.36-gnu/arch/m68k/bvme6000/rtc.c linux-libre-2.6.37-gnu/arch/m68k/bvme6000/rtc.c
--- linux-libre-2.6.36-gnu/arch/m68k/bvme6000/rtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/bvme6000/rtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -155,6 +155,7 @@
 	.unlocked_ioctl	= rtc_ioctl,
 	.open		= rtc_open,
 	.release	= rtc_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice rtc_dev = {
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/amigahw.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/amigahw.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/amigahw.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/amigahw.h	2011-01-04 19:50:19.000000000 -0500
@@ -102,7 +102,6 @@
     AMIGAHW_DECLARE(ALICE_NTSC);	/* NTSC Alice (8374) */
     AMIGAHW_DECLARE(MAGIC_REKICK);	/* A3000 Magic Hard Rekick */
     AMIGAHW_DECLARE(PCMCIA);		/* PCMCIA Slot */
-    AMIGAHW_DECLARE(GG2_ISA);		/* GG2 Zorro2ISA Bridge */
     AMIGAHW_DECLARE(ZORRO);		/* Zorro AutoConfig */
     AMIGAHW_DECLARE(ZORRO3);		/* Zorro III */
 };
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,211 @@
-#ifdef __uClinux__
-#include "atomic_no.h"
+#ifndef __ARCH_M68K_ATOMIC__
+#define __ARCH_M68K_ATOMIC__
+
+#include <linux/types.h>
+#include <asm/system.h>
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+/*
+ * We do not have SMP m68k systems, so we don't have to deal with that.
+ */
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#define atomic_read(v)		(*(volatile int *)&(v)->counter)
+#define atomic_set(v, i)	(((v)->counter) = i)
+
+/*
+ * The ColdFire parts cannot do some immediate to memory operations,
+ * so for them we do not specify the "i" asm constraint.
+ */
+#ifdef CONFIG_COLDFIRE
+#define	ASM_DI	"d"
 #else
-#include "atomic_mm.h"
+#define	ASM_DI	"di"
 #endif
 
+static inline void atomic_add(int i, atomic_t *v)
+{
+	__asm__ __volatile__("addl %1,%0" : "+m" (*v) : ASM_DI (i));
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+	__asm__ __volatile__("subl %1,%0" : "+m" (*v) : ASM_DI (i));
+}
+
+static inline void atomic_inc(atomic_t *v)
+{
+	__asm__ __volatile__("addql #1,%0" : "+m" (*v));
+}
+
+static inline void atomic_dec(atomic_t *v)
+{
+	__asm__ __volatile__("subql #1,%0" : "+m" (*v));
+}
+
+static inline int atomic_dec_and_test(atomic_t *v)
+{
+	char c;
+	__asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
+	return c != 0;
+}
+
+static inline int atomic_inc_and_test(atomic_t *v)
+{
+	char c;
+	__asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
+	return c != 0;
+}
+
+#ifdef CONFIG_RMW_INSNS
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+	int t, tmp;
+
+	__asm__ __volatile__(
+			"1:	movel %2,%1\n"
+			"	addl %3,%1\n"
+			"	casl %2,%1,%0\n"
+			"	jne 1b"
+			: "+m" (*v), "=&d" (t), "=&d" (tmp)
+			: "g" (i), "2" (atomic_read(v)));
+	return t;
+}
+
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+	int t, tmp;
+
+	__asm__ __volatile__(
+			"1:	movel %2,%1\n"
+			"	subl %3,%1\n"
+			"	casl %2,%1,%0\n"
+			"	jne 1b"
+			: "+m" (*v), "=&d" (t), "=&d" (tmp)
+			: "g" (i), "2" (atomic_read(v)));
+	return t;
+}
+
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#else /* !CONFIG_RMW_INSNS */
+
+static inline int atomic_add_return(int i, atomic_t * v)
+{
+	unsigned long flags;
+	int t;
+
+	local_irq_save(flags);
+	t = atomic_read(v);
+	t += i;
+	atomic_set(v, t);
+	local_irq_restore(flags);
+
+	return t;
+}
+
+static inline int atomic_sub_return(int i, atomic_t * v)
+{
+	unsigned long flags;
+	int t;
+
+	local_irq_save(flags);
+	t = atomic_read(v);
+	t -= i;
+	atomic_set(v, t);
+	local_irq_restore(flags);
+
+	return t;
+}
+
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+	unsigned long flags;
+	int prev;
+
+	local_irq_save(flags);
+	prev = atomic_read(v);
+	if (prev == old)
+		atomic_set(v, new);
+	local_irq_restore(flags);
+	return prev;
+}
+
+static inline int atomic_xchg(atomic_t *v, int new)
+{
+	unsigned long flags;
+	int prev;
+
+	local_irq_save(flags);
+	prev = atomic_read(v);
+	atomic_set(v, new);
+	local_irq_restore(flags);
+	return prev;
+}
+
+#endif /* !CONFIG_RMW_INSNS */
+
+#define atomic_dec_return(v)	atomic_sub_return(1, (v))
+#define atomic_inc_return(v)	atomic_add_return(1, (v))
+
+static inline int atomic_sub_and_test(int i, atomic_t *v)
+{
+	char c;
+	__asm__ __volatile__("subl %2,%1; seq %0"
+			     : "=d" (c), "+m" (*v)
+			     : ASM_DI (i));
+	return c != 0;
+}
+
+static inline int atomic_add_negative(int i, atomic_t *v)
+{
+	char c;
+	__asm__ __volatile__("addl %2,%1; smi %0"
+			     : "=d" (c), "+m" (*v)
+			     : "id" (i));
+	return c != 0;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
+{
+	__asm__ __volatile__("andl %1,%0" : "+m" (*v) : "id" (~(mask)));
+}
+
+static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
+{
+	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
+}
+
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+	int c, old;
+	c = atomic_read(v);
+	for (;;) {
+		if (unlikely(c == (u)))
+			break;
+		old = atomic_cmpxchg((v), c, c + (a));
+		if (likely(old == c))
+			break;
+		c = old;
+	}
+	return c != (u);
+}
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
+#include <asm-generic/atomic-long.h>
 #include <asm-generic/atomic64.h>
+#endif /* __ARCH_M68K_ATOMIC __ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic_mm.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,200 +0,0 @@
-#ifndef __ARCH_M68K_ATOMIC__
-#define __ARCH_M68K_ATOMIC__
-
-#include <linux/types.h>
-#include <asm/system.h>
-
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-/*
- * We do not have SMP m68k systems, so we don't have to deal with that.
- */
-
-#define ATOMIC_INIT(i)	{ (i) }
-
-#define atomic_read(v)		(*(volatile int *)&(v)->counter)
-#define atomic_set(v, i)	(((v)->counter) = i)
-
-static inline void atomic_add(int i, atomic_t *v)
-{
-	__asm__ __volatile__("addl %1,%0" : "+m" (*v) : "id" (i));
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-	__asm__ __volatile__("subl %1,%0" : "+m" (*v) : "id" (i));
-}
-
-static inline void atomic_inc(atomic_t *v)
-{
-	__asm__ __volatile__("addql #1,%0" : "+m" (*v));
-}
-
-static inline void atomic_dec(atomic_t *v)
-{
-	__asm__ __volatile__("subql #1,%0" : "+m" (*v));
-}
-
-static inline int atomic_dec_and_test(atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
-	return c != 0;
-}
-
-static inline int atomic_inc_and_test(atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
-	return c != 0;
-}
-
-#ifdef CONFIG_RMW_INSNS
-
-static inline int atomic_add_return(int i, atomic_t *v)
-{
-	int t, tmp;
-
-	__asm__ __volatile__(
-			"1:	movel %2,%1\n"
-			"	addl %3,%1\n"
-			"	casl %2,%1,%0\n"
-			"	jne 1b"
-			: "+m" (*v), "=&d" (t), "=&d" (tmp)
-			: "g" (i), "2" (atomic_read(v)));
-	return t;
-}
-
-static inline int atomic_sub_return(int i, atomic_t *v)
-{
-	int t, tmp;
-
-	__asm__ __volatile__(
-			"1:	movel %2,%1\n"
-			"	subl %3,%1\n"
-			"	casl %2,%1,%0\n"
-			"	jne 1b"
-			: "+m" (*v), "=&d" (t), "=&d" (tmp)
-			: "g" (i), "2" (atomic_read(v)));
-	return t;
-}
-
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-
-#else /* !CONFIG_RMW_INSNS */
-
-static inline int atomic_add_return(int i, atomic_t * v)
-{
-	unsigned long flags;
-	int t;
-
-	local_irq_save(flags);
-	t = atomic_read(v);
-	t += i;
-	atomic_set(v, t);
-	local_irq_restore(flags);
-
-	return t;
-}
-
-static inline int atomic_sub_return(int i, atomic_t * v)
-{
-	unsigned long flags;
-	int t;
-
-	local_irq_save(flags);
-	t = atomic_read(v);
-	t -= i;
-	atomic_set(v, t);
-	local_irq_restore(flags);
-
-	return t;
-}
-
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-	unsigned long flags;
-	int prev;
-
-	local_irq_save(flags);
-	prev = atomic_read(v);
-	if (prev == old)
-		atomic_set(v, new);
-	local_irq_restore(flags);
-	return prev;
-}
-
-static inline int atomic_xchg(atomic_t *v, int new)
-{
-	unsigned long flags;
-	int prev;
-
-	local_irq_save(flags);
-	prev = atomic_read(v);
-	atomic_set(v, new);
-	local_irq_restore(flags);
-	return prev;
-}
-
-#endif /* !CONFIG_RMW_INSNS */
-
-#define atomic_dec_return(v)	atomic_sub_return(1, (v))
-#define atomic_inc_return(v)	atomic_add_return(1, (v))
-
-static inline int atomic_sub_and_test(int i, atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("subl %2,%1; seq %0"
-			     : "=d" (c), "+m" (*v)
-			     : "id" (i));
-	return c != 0;
-}
-
-static inline int atomic_add_negative(int i, atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("addl %2,%1; smi %0"
-			     : "=d" (c), "+m" (*v)
-			     : "id" (i));
-	return c != 0;
-}
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
-{
-	__asm__ __volatile__("andl %1,%0" : "+m" (*v) : "id" (~(mask)));
-}
-
-static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
-{
-	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
-}
-
-static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
-{
-	int c, old;
-	c = atomic_read(v);
-	for (;;) {
-		if (unlikely(c == (u)))
-			break;
-		old = atomic_cmpxchg((v), c, c + (a));
-		if (likely(old == c))
-			break;
-		c = old;
-	}
-	return c != (u);
-}
-
-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-
-/* Atomic operations are already serializing */
-#define smp_mb__before_atomic_dec()	barrier()
-#define smp_mb__after_atomic_dec()	barrier()
-#define smp_mb__before_atomic_inc()	barrier()
-#define smp_mb__after_atomic_inc()	barrier()
-
-#include <asm-generic/atomic-long.h>
-#endif /* __ARCH_M68K_ATOMIC __ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/atomic_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/atomic_no.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,155 +0,0 @@
-#ifndef __ARCH_M68KNOMMU_ATOMIC__
-#define __ARCH_M68KNOMMU_ATOMIC__
-
-#include <linux/types.h>
-#include <asm/system.h>
-
-/*
- * Atomic operations that C can't guarantee us.  Useful for
- * resource counting etc..
- */
-
-/*
- * We do not have SMP m68k systems, so we don't have to deal with that.
- */
-
-#define ATOMIC_INIT(i)	{ (i) }
-
-#define atomic_read(v)		(*(volatile int *)&(v)->counter)
-#define atomic_set(v, i)	(((v)->counter) = i)
-
-static __inline__ void atomic_add(int i, atomic_t *v)
-{
-#ifdef CONFIG_COLDFIRE
-	__asm__ __volatile__("addl %1,%0" : "+m" (*v) : "d" (i));
-#else
-	__asm__ __volatile__("addl %1,%0" : "+m" (*v) : "di" (i));
-#endif
-}
-
-static __inline__ void atomic_sub(int i, atomic_t *v)
-{
-#ifdef CONFIG_COLDFIRE
-	__asm__ __volatile__("subl %1,%0" : "+m" (*v) : "d" (i));
-#else
-	__asm__ __volatile__("subl %1,%0" : "+m" (*v) : "di" (i));
-#endif
-}
-
-static __inline__ int atomic_sub_and_test(int i, atomic_t * v)
-{
-	char c;
-#ifdef CONFIG_COLDFIRE
-	__asm__ __volatile__("subl %2,%1; seq %0"
-			     : "=d" (c), "+m" (*v)
-			     : "d" (i));
-#else
-	__asm__ __volatile__("subl %2,%1; seq %0"
-			     : "=d" (c), "+m" (*v)
-			     : "di" (i));
-#endif
-	return c != 0;
-}
-
-static __inline__ void atomic_inc(volatile atomic_t *v)
-{
-	__asm__ __volatile__("addql #1,%0" : "+m" (*v));
-}
-
-/*
- * atomic_inc_and_test - increment and test
- * @v: pointer of type atomic_t
- *
- * Atomically increments @v by 1
- * and returns true if the result is zero, or false for all
- * other cases.
- */
-
-static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("addql #1,%1; seq %0" : "=d" (c), "+m" (*v));
-	return c != 0;
-}
-
-static __inline__ void atomic_dec(volatile atomic_t *v)
-{
-	__asm__ __volatile__("subql #1,%0" : "+m" (*v));
-}
-
-static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
-{
-	char c;
-	__asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "+m" (*v));
-	return c != 0;
-}
-
-static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *v)
-{
-	__asm__ __volatile__("andl %1,%0" : "+m" (*v) : "id" (~(mask)));
-}
-
-static __inline__ void atomic_set_mask(unsigned long mask, unsigned long *v)
-{
-	__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
-}
-
-/* Atomic operations are already serializing */
-#define smp_mb__before_atomic_dec()    barrier()
-#define smp_mb__after_atomic_dec() barrier()
-#define smp_mb__before_atomic_inc()    barrier()
-#define smp_mb__after_atomic_inc() barrier()
-
-static inline int atomic_add_return(int i, atomic_t * v)
-{
-	unsigned long temp, flags;
-
-	local_irq_save(flags);
-	temp = *(long *)v;
-	temp += i;
-	*(long *)v = temp;
-	local_irq_restore(flags);
-
-	return temp;
-}
-
-#define atomic_add_negative(a, v)	(atomic_add_return((a), (v)) < 0)
-
-static inline int atomic_sub_return(int i, atomic_t * v)
-{
-	unsigned long temp, flags;
-
-	local_irq_save(flags);
-	temp = *(long *)v;
-	temp -= i;
-	*(long *)v = temp;
-	local_irq_restore(flags);
-
-	return temp;
-}
-
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-
-static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
-{
-	int c, old;
-	c = atomic_read(v);
-	for (;;) {
-		if (unlikely(c == (u)))
-			break;
-		old = atomic_cmpxchg((v), c, c + (a));
-		if (likely(old == c))
-			break;
-		c = old;
-	}
-	return c != (u);
-}
-
-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-
-#define atomic_dec_return(v) atomic_sub_return(1,(v))
-#define atomic_inc_return(v) atomic_add_return(1,(v))
-
-#include <asm-generic/atomic-long.h>
-#endif /* __ARCH_M68KNOMMU_ATOMIC __ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/cacheflush_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/cacheflush_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/cacheflush_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/cacheflush_no.h	2011-01-04 19:50:19.000000000 -0500
@@ -29,7 +29,7 @@
 
 static inline void __flush_cache_all(void)
 {
-#ifdef CONFIG_M5407
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
 	/*
 	 *	Use cpushl to push and invalidate all cache lines.
 	 *	Gas doesn't seem to know how to generate the ColdFire
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/coldfire.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/coldfire.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/coldfire.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/coldfire.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,9 @@
  */
 #define	MCF_MBAR	0x10000000
 #define	MCF_MBAR2	0x80000000
-#if defined(CONFIG_M520x)
+#if defined(CONFIG_M548x)
+#define	MCF_IPSBAR	MCF_MBAR
+#elif defined(CONFIG_M520x)
 #define	MCF_IPSBAR	0xFC000000
 #else
 #define	MCF_IPSBAR	0x40000000
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/entry_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/entry_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/entry_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/entry_mm.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,9 @@
 
 #include <asm/setup.h>
 #include <asm/page.h>
+#ifdef __ASSEMBLY__
+#include <asm/thread_info.h>
+#endif
 
 /*
  * Stack layout in 'ret_from_exception':
@@ -47,14 +50,6 @@
 
 LFLUSH_I_AND_D = 0x00000808
 
-/* process bits for task_struct.ptrace */
-PT_TRACESYS_OFF = 3
-PT_TRACESYS_BIT = 1
-PT_PTRACED_OFF = 3
-PT_PTRACED_BIT = 0
-PT_DTRACE_OFF = 3
-PT_DTRACE_BIT = 2
-
 #define SAVE_ALL_INT save_all_int
 #define SAVE_ALL_SYS save_all_sys
 #define RESTORE_ALL restore_all
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/entry_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/entry_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/entry_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/entry_no.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,20 +28,10 @@
  *			M68K		  COLDFIRE
  */
 
-#define ALLOWINT 0xf8ff
+#define ALLOWINT (~0x700)
 
 #ifdef __ASSEMBLY__
 
-/* process bits for task_struct.flags */
-PF_TRACESYS_OFF = 3
-PF_TRACESYS_BIT = 5
-PF_PTRACED_OFF = 3
-PF_PTRACED_BIT = 4
-PF_DTRACE_OFF = 1
-PF_DTRACE_BIT = 5
-
-LENOSYS = 38
-
 #define SWITCH_STACK_SIZE (6*4+4)	/* Includes return address */
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/gpio.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/gpio.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -36,7 +36,8 @@
  */
 #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
     defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
-    defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
+    defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+    defined(CONFIG_M532x) || defined(CONFIG_M548x)
 
 /* These parts have GPIO organized by 8 bit ports */
 
@@ -136,6 +137,8 @@
 #endif
 	else
 		return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+	return 0;
 #endif
 }
 
@@ -173,6 +176,8 @@
 #endif
 	else
 		return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
+#else
+	return 0;
 #endif
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,86 +1,8 @@
 #ifndef __ARCH_M68K_IOCTLS_H__
 #define __ARCH_M68K_IOCTLS_H__
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* __ARCH_M68K_IOCTLS_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/io_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/io_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/io_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/io_mm.h	2011-01-04 19:50:19.000000000 -0500
@@ -49,23 +49,6 @@
 #define MULTI_ISA 0
 #endif /* Q40 */
 
-/* GG-II Zorro to ISA bridge */
-#ifdef CONFIG_GG2
-
-extern unsigned long gg2_isa_base;
-#define GG2_ISA_IO_B(ioaddr) (gg2_isa_base+1+((unsigned long)(ioaddr)*4))
-#define GG2_ISA_IO_W(ioaddr) (gg2_isa_base+  ((unsigned long)(ioaddr)*4))
-#define GG2_ISA_MEM_B(madr)  (gg2_isa_base+1+(((unsigned long)(madr)*4) & 0xfffff))
-#define GG2_ISA_MEM_W(madr)  (gg2_isa_base+  (((unsigned long)(madr)*4) & 0xfffff))
-
-#ifndef MULTI_ISA
-#define MULTI_ISA 0
-#else
-#undef MULTI_ISA
-#define MULTI_ISA 1
-#endif
-#endif /* GG2 */
-
 #ifdef CONFIG_AMIGA_PCMCIA
 #include <asm/amigayle.h>
 
@@ -89,8 +72,7 @@
 #endif
 
 #define ISA_TYPE_Q40 (1)
-#define ISA_TYPE_GG2 (2)
-#define ISA_TYPE_AG  (3)
+#define ISA_TYPE_AG  (2)
 
 #if defined(CONFIG_Q40) && !defined(MULTI_ISA)
 #define ISA_TYPE ISA_TYPE_Q40
@@ -100,10 +82,6 @@
 #define ISA_TYPE ISA_TYPE_AG
 #define ISA_SEX  1
 #endif
-#if defined(CONFIG_GG2) && !defined(MULTI_ISA)
-#define ISA_TYPE ISA_TYPE_GG2
-#define ISA_SEX  0
-#endif
 
 #ifdef MULTI_ISA
 extern int isa_type;
@@ -125,9 +103,6 @@
 #ifdef CONFIG_Q40
     case ISA_TYPE_Q40: return (u8 __iomem *)Q40_ISA_IO_B(addr);
 #endif
-#ifdef CONFIG_GG2
-    case ISA_TYPE_GG2: return (u8 __iomem *)GG2_ISA_IO_B(addr);
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
     case ISA_TYPE_AG: return (u8 __iomem *)AG_ISA_IO_B(addr);
 #endif
@@ -141,9 +116,6 @@
 #ifdef CONFIG_Q40
     case ISA_TYPE_Q40: return (u16 __iomem *)Q40_ISA_IO_W(addr);
 #endif
-#ifdef CONFIG_GG2
-    case ISA_TYPE_GG2: return (u16 __iomem *)GG2_ISA_IO_W(addr);
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
     case ISA_TYPE_AG: return (u16 __iomem *)AG_ISA_IO_W(addr);
 #endif
@@ -167,9 +139,6 @@
 #ifdef CONFIG_Q40
     case ISA_TYPE_Q40: return (u8 __iomem *)Q40_ISA_MEM_B(addr);
 #endif
-#ifdef CONFIG_GG2
-    case ISA_TYPE_GG2: return (u8 __iomem *)GG2_ISA_MEM_B(addr);
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
     case ISA_TYPE_AG: return (u8 __iomem *)addr;
 #endif
@@ -183,9 +152,6 @@
 #ifdef CONFIG_Q40
     case ISA_TYPE_Q40: return (u16 __iomem *)Q40_ISA_MEM_W(addr);
 #endif
-#ifdef CONFIG_GG2
-    case ISA_TYPE_GG2: return (u16 __iomem *)GG2_ISA_MEM_W(addr);
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
     case ISA_TYPE_AG: return (u16 __iomem *)addr;
 #endif
@@ -217,9 +183,6 @@
 #ifdef CONFIG_Q40
     case ISA_TYPE_Q40: isa_outb(0,0x80); break;
 #endif
-#ifdef CONFIG_GG2
-    case ISA_TYPE_GG2: break;
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
     case ISA_TYPE_AG: break;
 #endif
@@ -287,9 +250,13 @@
 #define outb(val,port)     ((void)0)
 #define outb_p(val,port)   ((void)0)
 #define inw(port)          0xffff
+#define inw_p(port)        0xffff
 #define outw(val,port)     ((void)0)
+#define outw_p(val,port)   ((void)0)
 #define inl(port)          0xffffffffUL
+#define inl_p(port)        0xffffffffUL
 #define outl(val,port)     ((void)0)
+#define outl_p(val,port)   ((void)0)
 
 #define insb(port,buf,nr)  ((void)0)
 #define outsb(port,buf,nr) ((void)0)
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,78 @@
+#ifndef _M68K_IRQFLAGS_H
+#define _M68K_IRQFLAGS_H
+
+#include <linux/types.h>
+#ifdef CONFIG_MMU
+#include <linux/hardirq.h>
+#endif
+#include <linux/preempt.h>
+#include <asm/thread_info.h>
+#include <asm/entry.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile ("movew %%sr,%0" : "=d" (flags) : : "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#ifdef CONFIG_COLDFIRE
+	asm volatile (
+		"move	%/sr,%%d0	\n\t"
+		"ori.l	#0x0700,%%d0	\n\t"
+		"move	%%d0,%/sr	\n"
+		: /* no outputs */
+		:
+		: "cc", "%d0", "memory");
+#else
+	asm volatile ("oriw  #0x0700,%%sr" : : : "memory");
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+#if defined(CONFIG_COLDFIRE)
+	asm volatile (
+		"move	%/sr,%%d0	\n\t"
+		"andi.l	#0xf8ff,%%d0	\n\t"
+		"move	%%d0,%/sr	\n"
+		: /* no outputs */
+		:
+		: "cc", "%d0", "memory");
+#else
+# if defined(CONFIG_MMU)
+	if (MACH_IS_Q40 || !hardirq_count())
+# endif
+		asm volatile (
+			"andiw %0,%%sr"
+			:
+			: "i" (ALLOWINT)
+			: "memory");
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile ("movew %0,%%sr" : : "d" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & ~ALLOWINT) != 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _M68K_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/m548xgpt.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/m548xgpt.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/m548xgpt.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/m548xgpt.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,88 @@
+/*
+ * File:	m548xgpt.h
+ * Purpose:	Register and bit definitions for the MCF548X
+ *
+ * Notes:
+ *
+ */
+
+#ifndef m548xgpt_h
+#define m548xgpt_h
+
+/*********************************************************************
+*
+* General Purpose Timers (GPT)
+*
+*********************************************************************/
+
+/* Register read/write macros */
+#define MCF_GPT_GMS0       0x000800
+#define MCF_GPT_GCIR0      0x000804
+#define MCF_GPT_GPWM0      0x000808
+#define MCF_GPT_GSR0       0x00080C
+#define MCF_GPT_GMS1       0x000810
+#define MCF_GPT_GCIR1      0x000814
+#define MCF_GPT_GPWM1      0x000818
+#define MCF_GPT_GSR1       0x00081C
+#define MCF_GPT_GMS2       0x000820
+#define MCF_GPT_GCIR2      0x000824
+#define MCF_GPT_GPWM2      0x000828
+#define MCF_GPT_GSR2       0x00082C
+#define MCF_GPT_GMS3       0x000830
+#define MCF_GPT_GCIR3      0x000834
+#define MCF_GPT_GPWM3      0x000838
+#define MCF_GPT_GSR3       0x00083C
+#define MCF_GPT_GMS(x)     (0x000800+((x)*0x010))
+#define MCF_GPT_GCIR(x)    (0x000804+((x)*0x010))
+#define MCF_GPT_GPWM(x)    (0x000808+((x)*0x010))
+#define MCF_GPT_GSR(x)     (0x00080C+((x)*0x010))
+
+/* Bit definitions and macros for MCF_GPT_GMS */
+#define MCF_GPT_GMS_TMS(x)         (((x)&0x00000007)<<0)
+#define MCF_GPT_GMS_GPIO(x)        (((x)&0x00000003)<<4)
+#define MCF_GPT_GMS_IEN            (0x00000100)
+#define MCF_GPT_GMS_OD             (0x00000200)
+#define MCF_GPT_GMS_SC             (0x00000400)
+#define MCF_GPT_GMS_CE             (0x00001000)
+#define MCF_GPT_GMS_WDEN           (0x00008000)
+#define MCF_GPT_GMS_ICT(x)         (((x)&0x00000003)<<16)
+#define MCF_GPT_GMS_OCT(x)         (((x)&0x00000003)<<20)
+#define MCF_GPT_GMS_OCPW(x)        (((x)&0x000000FF)<<24)
+#define MCF_GPT_GMS_OCT_FRCLOW     (0x00000000)
+#define MCF_GPT_GMS_OCT_PULSEHI    (0x00100000)
+#define MCF_GPT_GMS_OCT_PULSELO    (0x00200000)
+#define MCF_GPT_GMS_OCT_TOGGLE     (0x00300000)
+#define MCF_GPT_GMS_ICT_ANY        (0x00000000)
+#define MCF_GPT_GMS_ICT_RISE       (0x00010000)
+#define MCF_GPT_GMS_ICT_FALL       (0x00020000)
+#define MCF_GPT_GMS_ICT_PULSE      (0x00030000)
+#define MCF_GPT_GMS_GPIO_INPUT     (0x00000000)
+#define MCF_GPT_GMS_GPIO_OUTLO     (0x00000020)
+#define MCF_GPT_GMS_GPIO_OUTHI     (0x00000030)
+#define MCF_GPT_GMS_TMS_DISABLE    (0x00000000)
+#define MCF_GPT_GMS_TMS_INCAPT     (0x00000001)
+#define MCF_GPT_GMS_TMS_OUTCAPT    (0x00000002)
+#define MCF_GPT_GMS_TMS_PWM        (0x00000003)
+#define MCF_GPT_GMS_TMS_GPIO       (0x00000004)
+
+/* Bit definitions and macros for MCF_GPT_GCIR */
+#define MCF_GPT_GCIR_CNT(x)        (((x)&0x0000FFFF)<<0)
+#define MCF_GPT_GCIR_PRE(x)        (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GPWM */
+#define MCF_GPT_GPWM_LOAD          (0x00000001)
+#define MCF_GPT_GPWM_PWMOP         (0x00000100)
+#define MCF_GPT_GPWM_WIDTH(x)      (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_GPT_GSR */
+#define MCF_GPT_GSR_CAPT           (0x00000001)
+#define MCF_GPT_GSR_COMP           (0x00000002)
+#define MCF_GPT_GSR_PWMP           (0x00000004)
+#define MCF_GPT_GSR_TEXP           (0x00000008)
+#define MCF_GPT_GSR_PIN            (0x00000100)
+#define MCF_GPT_GSR_OVF(x)         (((x)&0x00000007)<<12)
+#define MCF_GPT_GSR_CAPTURE(x)     (((x)&0x0000FFFF)<<16)
+
+/********************************************************************/
+
+#endif /* m548xgpt_h */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/m548xsim.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/m548xsim.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/m548xsim.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/m548xsim.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,55 @@
+/*
+ *	m548xsim.h -- ColdFire 547x/548x System Integration Unit support.
+ */
+
+#ifndef	m548xsim_h
+#define m548xsim_h
+
+#define MCFINT_VECBASE      64
+
+/*
+ *      Interrupt Controller Registers
+ */
+#define MCFICM_INTC0		0x0700		/* Base for Interrupt Ctrl 0 */
+#define MCFINTC_IPRH		0x00		/* Interrupt pending 32-63 */
+#define MCFINTC_IPRL		0x04		/* Interrupt pending 1-31 */
+#define MCFINTC_IMRH		0x08		/* Interrupt mask 32-63 */
+#define MCFINTC_IMRL		0x0c		/* Interrupt mask 1-31 */
+#define MCFINTC_INTFRCH		0x10		/* Interrupt force 32-63 */
+#define MCFINTC_INTFRCL		0x14		/* Interrupt force 1-31 */
+#define MCFINTC_IRLR		0x18		/* */
+#define MCFINTC_IACKL		0x19		/* */
+#define MCFINTC_ICR0		0x40		/* Base ICR register */
+
+/*
+ *	Define system peripheral IRQ usage.
+ */
+#define MCF_IRQ_TIMER		(64 + 54)	/* Slice Timer 0 */
+#define MCF_IRQ_PROFILER	(64 + 53)	/* Slice Timer 1 */
+
+/*
+ *	Generic GPIO support
+ */
+#define MCFGPIO_PIN_MAX		0	/* I am too lazy to count */
+#define MCFGPIO_IRQ_MAX		-1
+#define MCFGPIO_IRQ_VECBASE	-1
+
+/*
+ *	Some PSC related definitions
+ */
+#define MCF_PAR_PSC(x)		(0x000A4F-((x)&0x3))
+#define MCF_PAR_SDA		(0x0008)
+#define MCF_PAR_SCL		(0x0004)
+#define MCF_PAR_PSC_TXD		(0x04)
+#define MCF_PAR_PSC_RXD		(0x08)
+#define MCF_PAR_PSC_RTS(x)	(((x)&0x03)<<4)
+#define MCF_PAR_PSC_CTS(x)	(((x)&0x03)<<6)
+#define MCF_PAR_PSC_CTS_GPIO	(0x00)
+#define MCF_PAR_PSC_CTS_BCLK	(0x80)
+#define MCF_PAR_PSC_CTS_CTS	(0xC0)
+#define MCF_PAR_PSC_RTS_GPIO    (0x00)
+#define MCF_PAR_PSC_RTS_FSYNC	(0x20)
+#define MCF_PAR_PSC_RTS_RTS	(0x30)
+#define MCF_PAR_PSC_CANRX	(0x40)
+
+#endif	/* m548xsim_h */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,45 @@
-#ifdef __uClinux__
-#include "machdep_no.h"
-#else
-#include "machdep_mm.h"
-#endif
+#ifndef _M68K_MACHDEP_H
+#define _M68K_MACHDEP_H
+
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+
+struct pt_regs;
+struct mktime;
+struct rtc_time;
+struct rtc_pll_info;
+struct buffer_head;
+
+extern void (*mach_sched_init) (irq_handler_t handler);
+/* machine dependent irq functions */
+extern void (*mach_init_IRQ) (void);
+extern void (*mach_get_model) (char *model);
+extern void (*mach_get_hardware_list) (struct seq_file *m);
+/* machine dependent timer functions */
+extern unsigned long (*mach_gettimeoffset)(void);
+extern int (*mach_hwclk)(int, struct rtc_time*);
+extern unsigned int (*mach_get_ss)(void);
+extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
+extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
+extern int (*mach_set_clock_mmss)(unsigned long);
+extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
+			    int *min, int *sec);
+extern void (*mach_reset)( void );
+extern void (*mach_halt)( void );
+extern void (*mach_power_off)( void );
+extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
+extern void (*mach_hd_setup)(char *, int *);
+extern long mach_max_dma_address;
+extern void (*mach_heartbeat) (int);
+extern void (*mach_l2_flush) (int);
+extern void (*mach_beep) (unsigned int, unsigned int);
+
+/* Hardware clock functions */
+extern void hw_timer_init(void);
+extern unsigned long hw_timer_offset(void);
+extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
+
+extern void config_BSP(char *command, int len);
+extern void do_IRQ(int irq, struct pt_regs *fp);
+
+#endif /* _M68K_MACHDEP_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep_mm.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,35 +0,0 @@
-#ifndef _M68K_MACHDEP_H
-#define _M68K_MACHDEP_H
-
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-
-struct pt_regs;
-struct mktime;
-struct rtc_time;
-struct rtc_pll_info;
-struct buffer_head;
-
-extern void (*mach_sched_init) (irq_handler_t handler);
-/* machine dependent irq functions */
-extern void (*mach_init_IRQ) (void);
-extern void (*mach_get_model) (char *model);
-extern void (*mach_get_hardware_list) (struct seq_file *m);
-/* machine dependent timer functions */
-extern unsigned long (*mach_gettimeoffset)(void);
-extern int (*mach_hwclk)(int, struct rtc_time*);
-extern unsigned int (*mach_get_ss)(void);
-extern int (*mach_get_rtc_pll)(struct rtc_pll_info *);
-extern int (*mach_set_rtc_pll)(struct rtc_pll_info *);
-extern int (*mach_set_clock_mmss)(unsigned long);
-extern void (*mach_reset)( void );
-extern void (*mach_halt)( void );
-extern void (*mach_power_off)( void );
-extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
-extern void (*mach_hd_setup)(char *, int *);
-extern long mach_max_dma_address;
-extern void (*mach_heartbeat) (int);
-extern void (*mach_l2_flush) (int);
-extern void (*mach_beep) (unsigned int, unsigned int);
-
-#endif /* _M68K_MACHDEP_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/machdep_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/machdep_no.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,26 +0,0 @@
-#ifndef _M68KNOMMU_MACHDEP_H
-#define _M68KNOMMU_MACHDEP_H
-
-#include <linux/interrupt.h>
-
-/* Hardware clock functions */
-extern void hw_timer_init(void);
-extern unsigned long hw_timer_offset(void);
-
-extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
-
-/* Machine dependent time handling */
-extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour,
-			   int *min, int *sec);
-extern int (*mach_set_clock_mmss)(unsigned long);
-
-/* machine dependent power off functions */
-extern void (*mach_reset)( void );
-extern void (*mach_halt)( void );
-extern void (*mach_power_off)( void );
-
-extern void config_BSP(char *command, int len);
-
-extern void do_IRQ(int irq, struct pt_regs *fp);
-
-#endif /* _M68KNOMMU_MACHDEP_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfcache.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfcache.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfcache.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfcache.h	2011-01-04 19:50:19.000000000 -0500
@@ -107,7 +107,7 @@
 .endm
 #endif /* CONFIG_M532x */
 
-#if defined(CONFIG_M5407)
+#if defined(CONFIG_M5407) || defined(CONFIG_M548x)
 /*
  *	Version 4 cores have a true harvard style separate instruction
  *	and data cache. Invalidate and enable cache, also enable write
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfsim.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfsim.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfsim.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfsim.h	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,8 @@
 #elif defined(CONFIG_M5407)
 #include <asm/m5407sim.h>
 #include <asm/mcfintc.h>
+#elif defined(CONFIG_M548x)
+#include <asm/m548xsim.h>
 #endif
 
 /****************************************************************************/
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfslt.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfslt.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfslt.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfslt.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,44 @@
+/****************************************************************************/
+
+/*
+ *	mcfslt.h -- ColdFire internal Slice (SLT) timer support defines.
+ *
+ *	(C) Copyright 2004, Greg Ungerer (gerg@snapgear.com)
+ *	(C) Copyright 2009, Philippe De Muyter (phdm@macqel.be)
+ */
+
+/****************************************************************************/
+#ifndef mcfslt_h
+#define mcfslt_h
+/****************************************************************************/
+
+/*
+ *	Get address specific defines for the 547x.
+ */
+#define MCFSLT_TIMER0		0x900	/* Base address of TIMER0 */
+#define MCFSLT_TIMER1		0x910	/* Base address of TIMER1 */
+
+
+/*
+ *	Define the SLT timer register set addresses.
+ */
+#define MCFSLT_STCNT		0x00	/* Terminal count */
+#define MCFSLT_SCR		0x04	/* Control */
+#define MCFSLT_SCNT		0x08	/* Current count */
+#define MCFSLT_SSR		0x0C	/* Status */
+
+/*
+ *	Bit definitions for the SCR control register.
+ */
+#define MCFSLT_SCR_RUN		0x04000000	/* Run mode (continuous) */
+#define MCFSLT_SCR_IEN		0x02000000	/* Interrupt enable */
+#define MCFSLT_SCR_TEN		0x01000000	/* Timer enable */
+
+/*
+ *	Bit definitions for the SSR status register.
+ */
+#define MCFSLT_SSR_BE		0x02000000	/* Bus error condition */
+#define MCFSLT_SSR_TE		0x01000000	/* Timeout condition */
+
+/****************************************************************************/
+#endif	/* mcfslt_h */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfuart.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfuart.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/mcfuart.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/mcfuart.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,11 @@
 #define MCFUART_BASE1		0xfc060000	/* Base address of UART1 */
 #define MCFUART_BASE2		0xfc064000	/* Base address of UART2 */
 #define MCFUART_BASE3		0xfc068000	/* Base address of UART3 */
+#elif defined(CONFIG_M548x)
+#define MCFUART_BASE1		0x8600		/* on M548x */
+#define MCFUART_BASE2		0x8700		/* on M548x */
+#define MCFUART_BASE3		0x8800		/* on M548x */
+#define MCFUART_BASE4		0x8900		/* on M548x */
 #endif
 
 
@@ -212,7 +217,9 @@
 #define	MCFUART_URF_RXS		0xc0		/* Receiver status */
 #endif
 
-#if defined(CONFIG_M5272)
+#if defined(CONFIG_M548x)
+#define MCFUART_TXFIFOSIZE	512
+#elif defined(CONFIG_M5272)
 #define MCFUART_TXFIFOSIZE	25
 #else
 #define MCFUART_TXFIFOSIZE	1
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/motorola_pgtable.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/motorola_pgtable.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/motorola_pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/motorola_pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -221,9 +221,7 @@
 }
 
 #define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-#define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address)
 #define pte_unmap(pte)		((void)0)
-#define pte_unmap_nested(pte)	((void)0)
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/page.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/page.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/page.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/page.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,49 @@
-#ifdef __uClinux__
-#include "page_no.h"
+#ifndef _M68K_PAGE_H
+#define _M68K_PAGE_H
+
+#include <linux/const.h>
+#include <asm/setup.h>
+#include <asm/page_offset.h>
+
+/* PAGE_SHIFT determines the page size */
+#ifndef CONFIG_SUN3
+#define PAGE_SHIFT	(12)
 #else
+#define PAGE_SHIFT	(13)
+#endif
+#define PAGE_SIZE	(_AC(1, UL) << PAGE_SHIFT)
+#define PAGE_MASK	(~(PAGE_SIZE-1))
+#define PAGE_OFFSET	(PAGE_OFFSET_RAW)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd[16]; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct page *pgtable_t;
+
+#define pte_val(x)	((x).pte)
+#define pmd_val(x)	((&x)->pmd[0])
+#define pgd_val(x)	((x).pgd)
+#define pgprot_val(x)	((x).pgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __pmd(x)	((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+
+#endif /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_MMU
 #include "page_mm.h"
+#else
+#include "page_no.h"
 #endif
+
+#include <asm-generic/getorder.h>
+
+#endif /* _M68K_PAGE_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/page_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/page_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/page_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/page_mm.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,29 +1,9 @@
-#ifndef _M68K_PAGE_H
-#define _M68K_PAGE_H
-
-#include <linux/const.h>
-
-/* PAGE_SHIFT determines the page size */
-#ifndef CONFIG_SUN3
-#define PAGE_SHIFT	(12)
-#else
-#define PAGE_SHIFT	(13)
-#endif
-#define PAGE_SIZE	(_AC(1, UL) << PAGE_SHIFT)
-#define PAGE_MASK	(~(PAGE_SIZE-1))
-
-#include <asm/setup.h>
-
-#if PAGE_SHIFT < 13
-#define THREAD_SIZE (8192)
-#else
-#define THREAD_SIZE PAGE_SIZE
-#endif
+#ifndef _M68K_PAGE_MM_H
+#define _M68K_PAGE_MM_H
 
 #ifndef __ASSEMBLY__
 
 #include <linux/compiler.h>
-
 #include <asm/module.h>
 
 #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
@@ -84,33 +64,6 @@
 		flush_dcache_page(page);	\
 	} while (0)
 
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd[16]; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-typedef struct page *pgtable_t;
-
-#define pte_val(x)	((x).pte)
-#define pmd_val(x)	((&x)->pmd[0])
-#define pgd_val(x)	((x).pgd)
-#define pgprot_val(x)	((x).pgprot)
-
-#define __pte(x)	((pte_t) { (x) } )
-#define __pmd(x)	((pmd_t) { (x) } )
-#define __pgd(x)	((pgd_t) { (x) } )
-#define __pgprot(x)	((pgprot_t) { (x) } )
-
-#endif /* !__ASSEMBLY__ */
-
-#include <asm/page_offset.h>
-
-#define PAGE_OFFSET		(PAGE_OFFSET_RAW)
-
-#ifndef __ASSEMBLY__
-
 extern unsigned long m68k_memoffset;
 
 #ifndef CONFIG_SUN3
@@ -127,7 +80,7 @@
 		: "0" (vaddr), "i" (m68k_fixup_memoffset));
 	return paddr;
 }
-#define __pa(vaddr)	___pa((void *)(vaddr))
+#define __pa(vaddr)	___pa((void *)(long)(vaddr))
 static inline void *__va(unsigned long paddr)
 {
 	void *vaddr;
@@ -223,6 +176,4 @@
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-#include <asm-generic/getorder.h>
-
-#endif /* _M68K_PAGE_H */
+#endif /* _M68K_PAGE_MM_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/page_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/page_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/page_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/page_no.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,18 +1,11 @@
-#ifndef _M68KNOMMU_PAGE_H
-#define _M68KNOMMU_PAGE_H
-
-#include <linux/const.h>
-
-/* PAGE_SHIFT determines the page size */
-
-#define PAGE_SHIFT	(12)
-#define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK	(~(PAGE_SIZE-1))
-
-#include <asm/setup.h>
+#ifndef _M68K_PAGE_NO_H
+#define _M68K_PAGE_NO_H
 
 #ifndef __ASSEMBLY__
  
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
 #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
 #define free_user_page(page, addr)	free_page(addr)
 
@@ -26,36 +19,6 @@
 	alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
 #define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
 
-/*
- * These are used to make use of C type-checking..
- */
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd[16]; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-typedef struct page *pgtable_t;
-
-#define pte_val(x)	((x).pte)
-#define pmd_val(x)	((&x)->pmd[0])
-#define pgd_val(x)	((x).pgd)
-#define pgprot_val(x)	((x).pgprot)
-
-#define __pte(x)	((pte_t) { (x) } )
-#define __pmd(x)	((pmd_t) { (x) } )
-#define __pgd(x)	((pgd_t) { (x) } )
-#define __pgprot(x)	((pgprot_t) { (x) } )
-
-extern unsigned long memory_start;
-extern unsigned long memory_end;
-
-#endif /* !__ASSEMBLY__ */
-
-#include <asm/page_offset.h>
-
-#define PAGE_OFFSET		(PAGE_OFFSET_RAW)
-
-#ifndef __ASSEMBLY__
-
 #define __pa(vaddr)		((unsigned long)(vaddr))
 #define __va(paddr)		((void *)(paddr))
 
@@ -74,6 +37,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#include <asm-generic/getorder.h>
-
-#endif /* _M68KNOMMU_PAGE_H */
+#endif /* _M68K_PAGE_NO_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/string.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/string.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/string.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/string.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,133 @@
-#ifdef __uClinux__
-#include "string_no.h"
+#ifndef _M68K_STRING_H_
+#define _M68K_STRING_H_
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+static inline size_t __kernel_strlen(const char *s)
+{
+	const char *sc;
+
+	for (sc = s; *sc++; )
+		;
+	return sc - s - 1;
+}
+
+static inline char *__kernel_strcpy(char *dest, const char *src)
+{
+	char *xdest = dest;
+
+	asm volatile ("\n"
+		"1:	move.b	(%1)+,(%0)+\n"
+		"	jne	1b"
+		: "+a" (dest), "+a" (src)
+		: : "memory");
+	return xdest;
+}
+
+#ifndef __IN_STRING_C
+
+#define __HAVE_ARCH_STRLEN
+#define strlen(s)	(__builtin_constant_p(s) ?	\
+			 __builtin_strlen(s) :		\
+			 __kernel_strlen(s))
+
+#define __HAVE_ARCH_STRNLEN
+static inline size_t strnlen(const char *s, size_t count)
+{
+	const char *sc = s;
+
+	asm volatile ("\n"
+		"1:     subq.l  #1,%1\n"
+		"       jcs     2f\n"
+		"       tst.b   (%0)+\n"
+		"       jne     1b\n"
+		"       subq.l  #1,%0\n"
+		"2:"
+		: "+a" (sc), "+d" (count));
+	return sc - s;
+}
+
+#define __HAVE_ARCH_STRCPY
+#if __GNUC__ >= 4
+#define strcpy(d, s)	(__builtin_constant_p(s) &&	\
+			 __builtin_strlen(s) <= 32 ?	\
+			 __builtin_strcpy(d, s) :	\
+			 __kernel_strcpy(d, s))
 #else
-#include "string_mm.h"
+#define strcpy(d, s)	__kernel_strcpy(d, s)
+#endif
+
+#define __HAVE_ARCH_STRNCPY
+static inline char *strncpy(char *dest, const char *src, size_t n)
+{
+	char *xdest = dest;
+
+	asm volatile ("\n"
+		"	jra	2f\n"
+		"1:	move.b	(%1),(%0)+\n"
+		"	jeq	2f\n"
+		"	addq.l	#1,%1\n"
+		"2:	subq.l	#1,%2\n"
+		"	jcc	1b\n"
+		: "+a" (dest), "+a" (src), "+d" (n)
+		: : "memory");
+	return xdest;
+}
+
+#define __HAVE_ARCH_STRCAT
+#define strcat(d, s)	({			\
+	char *__d = (d);			\
+	strcpy(__d + strlen(__d), (s));		\
+})
+
+#define __HAVE_ARCH_STRCHR
+static inline char *strchr(const char *s, int c)
+{
+	char sc, ch = c;
+
+	for (; (sc = *s++) != ch; ) {
+		if (!sc)
+			return NULL;
+	}
+	return (char *)s - 1;
+}
+
+#ifndef CONFIG_COLDFIRE
+#define __HAVE_ARCH_STRCMP
+static inline int strcmp(const char *cs, const char *ct)
+{
+	char res;
+
+	asm ("\n"
+		"1:	move.b	(%0)+,%2\n"	/* get *cs */
+		"	cmp.b	(%1)+,%2\n"	/* compare a byte */
+		"	jne	2f\n"		/* not equal, break out */
+		"	tst.b	%2\n"		/* at end of cs? */
+		"	jne	1b\n"		/* no, keep going */
+		"	jra	3f\n"		/* strings are equal */
+		"2:	sub.b	-(%1),%2\n"	/* *cs - *ct */
+		"3:"
+		: "+a" (cs), "+a" (ct), "=d" (res));
+	return res;
+}
+
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, __kernel_size_t);
+#define memcmp(d, s, n) __builtin_memcmp(d, s, n)
+#endif /* CONFIG_COLDFIRE */
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, __kernel_size_t);
+#define memset(d, c, n) __builtin_memset(d, c, n)
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *, const void *, __kernel_size_t);
+#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
+
 #endif
+
+#endif /* _M68K_STRING_H_ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/string_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/string_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/string_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/string_mm.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,131 +0,0 @@
-#ifndef _M68K_STRING_H_
-#define _M68K_STRING_H_
-
-#include <linux/types.h>
-#include <linux/compiler.h>
-
-static inline size_t __kernel_strlen(const char *s)
-{
-	const char *sc;
-
-	for (sc = s; *sc++; )
-		;
-	return sc - s - 1;
-}
-
-static inline char *__kernel_strcpy(char *dest, const char *src)
-{
-	char *xdest = dest;
-
-	asm volatile ("\n"
-		"1:	move.b	(%1)+,(%0)+\n"
-		"	jne	1b"
-		: "+a" (dest), "+a" (src)
-		: : "memory");
-	return xdest;
-}
-
-#ifndef __IN_STRING_C
-
-#define __HAVE_ARCH_STRLEN
-#define strlen(s)	(__builtin_constant_p(s) ?	\
-			 __builtin_strlen(s) :		\
-			 __kernel_strlen(s))
-
-#define __HAVE_ARCH_STRNLEN
-static inline size_t strnlen(const char *s, size_t count)
-{
-	const char *sc = s;
-
-	asm volatile ("\n"
-		"1:     subq.l  #1,%1\n"
-		"       jcs     2f\n"
-		"       tst.b   (%0)+\n"
-		"       jne     1b\n"
-		"       subq.l  #1,%0\n"
-		"2:"
-		: "+a" (sc), "+d" (count));
-	return sc - s;
-}
-
-#define __HAVE_ARCH_STRCPY
-#if __GNUC__ >= 4
-#define strcpy(d, s)	(__builtin_constant_p(s) &&	\
-			 __builtin_strlen(s) <= 32 ?	\
-			 __builtin_strcpy(d, s) :	\
-			 __kernel_strcpy(d, s))
-#else
-#define strcpy(d, s)	__kernel_strcpy(d, s)
-#endif
-
-#define __HAVE_ARCH_STRNCPY
-static inline char *strncpy(char *dest, const char *src, size_t n)
-{
-	char *xdest = dest;
-
-	asm volatile ("\n"
-		"	jra	2f\n"
-		"1:	move.b	(%1),(%0)+\n"
-		"	jeq	2f\n"
-		"	addq.l	#1,%1\n"
-		"2:	subq.l	#1,%2\n"
-		"	jcc	1b\n"
-		: "+a" (dest), "+a" (src), "+d" (n)
-		: : "memory");
-	return xdest;
-}
-
-#define __HAVE_ARCH_STRCAT
-#define strcat(d, s)	({			\
-	char *__d = (d);			\
-	strcpy(__d + strlen(__d), (s));		\
-})
-
-#define __HAVE_ARCH_STRCHR
-static inline char *strchr(const char *s, int c)
-{
-	char sc, ch = c;
-
-	for (; (sc = *s++) != ch; ) {
-		if (!sc)
-			return NULL;
-	}
-	return (char *)s - 1;
-}
-
-#define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char *cs, const char *ct)
-{
-	char res;
-
-	asm ("\n"
-		"1:	move.b	(%0)+,%2\n"	/* get *cs */
-		"	cmp.b	(%1)+,%2\n"	/* compare a byte */
-		"	jne	2f\n"		/* not equal, break out */
-		"	tst.b	%2\n"		/* at end of cs? */
-		"	jne	1b\n"		/* no, keep going */
-		"	jra	3f\n"		/* strings are equal */
-		"2:	sub.b	-(%1),%2\n"	/* *cs - *ct */
-		"3:"
-		: "+a" (cs), "+a" (ct), "=d" (res));
-	return res;
-}
-
-#define __HAVE_ARCH_MEMSET
-extern void *memset(void *, int, __kernel_size_t);
-#define memset(d, c, n) __builtin_memset(d, c, n)
-
-#define __HAVE_ARCH_MEMCPY
-extern void *memcpy(void *, const void *, __kernel_size_t);
-#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
-
-#define __HAVE_ARCH_MEMMOVE
-extern void *memmove(void *, const void *, __kernel_size_t);
-
-#define __HAVE_ARCH_MEMCMP
-extern int memcmp(const void *, const void *, __kernel_size_t);
-#define memcmp(d, s, n) __builtin_memcmp(d, s, n)
-
-#endif
-
-#endif /* _M68K_STRING_H_ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/string_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/string_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/string_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/string_no.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,126 +0,0 @@
-#ifndef _M68KNOMMU_STRING_H_
-#define _M68KNOMMU_STRING_H_
-
-#ifdef __KERNEL__ /* only set these up for kernel code */
-
-#include <asm/setup.h>
-#include <asm/page.h>
-
-#define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
-{
-  char *xdest = dest;
-
-  __asm__ __volatile__
-       ("1:\tmoveb %1@+,%0@+\n\t"
-        "jne 1b"
-	: "=a" (dest), "=a" (src)
-        : "0" (dest), "1" (src) : "memory");
-  return xdest;
-}
-
-#define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char *dest, const char *src, size_t n)
-{
-  char *xdest = dest;
-
-  if (n == 0)
-    return xdest;
-
-  __asm__ __volatile__
-       ("1:\tmoveb %1@+,%0@+\n\t"
-	"jeq 2f\n\t"
-        "subql #1,%2\n\t"
-        "jne 1b\n\t"
-        "2:"
-        : "=a" (dest), "=a" (src), "=d" (n)
-        : "0" (dest), "1" (src), "2" (n)
-        : "memory");
-  return xdest;
-}
-
-
-#ifndef CONFIG_COLDFIRE
-
-#define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
-{
-  char __res;
-
-  __asm__
-       ("1:\tmoveb %0@+,%2\n\t" /* get *cs */
-        "cmpb %1@+,%2\n\t"      /* compare a byte */
-        "jne  2f\n\t"           /* not equal, break out */
-        "tstb %2\n\t"           /* at end of cs? */
-        "jne  1b\n\t"           /* no, keep going */
-        "jra  3f\n\t"		/* strings are equal */
-        "2:\tsubb %1@-,%2\n\t"  /* *cs - *ct */
-        "3:"
-        : "=a" (cs), "=a" (ct), "=d" (__res)
-        : "0" (cs), "1" (ct));
-
-  return __res;
-}
-
-#define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-  char __res;
-
-  if (!count)
-    return 0;
-  __asm__
-       ("1:\tmovb %0@+,%3\n\t"          /* get *cs */
-        "cmpb   %1@+,%3\n\t"            /* compare a byte */
-        "jne    3f\n\t"                 /* not equal, break out */
-        "tstb   %3\n\t"                 /* at end of cs? */
-        "jeq    4f\n\t"                 /* yes, all done */
-        "subql  #1,%2\n\t"              /* no, adjust count */
-        "jne    1b\n\t"                 /* more to do, keep going */
-        "2:\tmoveq #0,%3\n\t"           /* strings are equal */
-        "jra    4f\n\t"
-        "3:\tsubb %1@-,%3\n\t"          /* *cs - *ct */
-        "4:"
-        : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res)
-        : "0" (cs), "1" (ct), "2" (count));
-  return __res;
-}
-
-#endif /* CONFIG_COLDFIRE */
-
-#define __HAVE_ARCH_MEMSET
-extern void * memset(void * s, int c, size_t count);
-
-#define __HAVE_ARCH_MEMCPY
-extern void * memcpy(void *d, const void *s, size_t count);
-
-#else /* KERNEL */
-
-/*
- *	let user libraries deal with these,
- *	IMHO the kernel has no place defining these functions for user apps
- */
-
-#define __HAVE_ARCH_STRCPY 1
-#define __HAVE_ARCH_STRNCPY 1
-#define __HAVE_ARCH_STRCAT 1
-#define __HAVE_ARCH_STRNCAT 1
-#define __HAVE_ARCH_STRCMP 1
-#define __HAVE_ARCH_STRNCMP 1
-#define __HAVE_ARCH_STRNICMP 1
-#define __HAVE_ARCH_STRCHR 1
-#define __HAVE_ARCH_STRRCHR 1
-#define __HAVE_ARCH_STRSTR 1
-#define __HAVE_ARCH_STRLEN 1
-#define __HAVE_ARCH_STRNLEN 1
-#define __HAVE_ARCH_MEMSET 1
-#define __HAVE_ARCH_MEMCPY 1
-#define __HAVE_ARCH_MEMMOVE 1
-#define __HAVE_ARCH_MEMSCAN 1
-#define __HAVE_ARCH_MEMCMP 1
-#define __HAVE_ARCH_MEMCHR 1
-#define __HAVE_ARCH_STRTOK 1
-
-#endif /* KERNEL */
-
-#endif /* _M68K_STRING_H_ */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/sun3_pgtable.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/sun3_pgtable.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/sun3_pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/sun3_pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -219,9 +219,7 @@
 #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address))
 /* FIXME: should we bother with kmap() here? */
 #define pte_offset_map(pmd, address) ((pte_t *)kmap(pmd_page(*pmd)) + pte_index(address))
-#define pte_offset_map_nested(pmd, address) pte_offset_map(pmd, address)
 #define pte_unmap(pte) kunmap(pte)
-#define pte_unmap_nested(pte) kunmap(pte)
 
 /* Macros to (de)construct the fake PTEs representing swap pages. */
 #define __swp_type(x)		((x).val & 0x7F)
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/system_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/system_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/system_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/system_mm.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,7 @@
 
 #include <linux/linkage.h>
 #include <linux/kernel.h>
+#include <linux/irqflags.h>
 #include <asm/segment.h>
 #include <asm/entry.h>
 
@@ -62,30 +63,6 @@
 #define smp_wmb()	barrier()
 #define smp_read_barrier_depends()	((void)0)
 
-/* interrupt control.. */
-#if 0
-#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
-#else
-#include <linux/hardirq.h>
-#define local_irq_enable() ({							\
-	if (MACH_IS_Q40 || !hardirq_count())					\
-		asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory");	\
-})
-#endif
-#define local_irq_disable() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
-#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory")
-#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
-
-static inline int irqs_disabled(void)
-{
-	unsigned long flags;
-	local_save_flags(flags);
-	return flags & ~ALLOWINT;
-}
-
-/* For spinlocks etc */
-#define local_irq_save(x)	({ local_save_flags(x); local_irq_disable(); })
-
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 struct __xchg_dummy { unsigned long a[100]; };
@@ -205,9 +182,7 @@
 	((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\
 			(unsigned long)(n), sizeof(*(ptr))))
 
-#ifndef CONFIG_SMP
 #include <asm-generic/cmpxchg.h>
-#endif
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/system_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/system_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/system_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/system_no.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,7 @@
 #define _M68KNOMMU_SYSTEM_H
 
 #include <linux/linkage.h>
+#include <linux/irqflags.h>
 #include <asm/segment.h>
 #include <asm/entry.h>
 
@@ -46,54 +47,6 @@
   (last) = _last;						\
 }
 
-#ifdef CONFIG_COLDFIRE
-#define local_irq_enable() __asm__ __volatile__ (		\
-	"move %/sr,%%d0\n\t"					\
-	"andi.l #0xf8ff,%%d0\n\t"				\
-	"move %%d0,%/sr\n"					\
-	: /* no outputs */					\
-	:							\
-        : "cc", "%d0", "memory")
-#define local_irq_disable() __asm__ __volatile__ (		\
-	"move %/sr,%%d0\n\t"					\
-	"ori.l #0x0700,%%d0\n\t"				\
-	"move %%d0,%/sr\n"					\
-	: /* no outputs */					\
-	:							\
-	: "cc", "%d0", "memory")
-/* For spinlocks etc */
-#define local_irq_save(x) __asm__ __volatile__ (		\
-	"movew %%sr,%0\n\t"					\
-	"movew #0x0700,%%d0\n\t"				\
-	"or.l  %0,%%d0\n\t"					\
-	"movew %%d0,%/sr"					\
-	: "=d" (x)						\
-	:							\
-	: "cc", "%d0", "memory")
-#else
-
-/* portable version */ /* FIXME - see entry.h*/
-#define ALLOWINT 0xf8ff
-
-#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
-#define local_irq_disable() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
-#endif
-
-#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory")
-#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
-
-/* For spinlocks etc */
-#ifndef local_irq_save
-#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0)
-#endif
-
-#define	irqs_disabled()			\
-({					\
-	unsigned long flags;		\
-	local_save_flags(flags);	\
-	((flags & 0x0700) == 0x0700);	\
-})
-
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
 /*
@@ -106,17 +59,10 @@
 #define wmb()  asm volatile (""   : : :"memory")
 #define set_mb(var, value)	({ (var) = (value); wmb(); })
 
-#ifdef CONFIG_SMP
-#define smp_mb()	mb()
-#define smp_rmb()	rmb()
-#define smp_wmb()	wmb()
-#define smp_read_barrier_depends()	read_barrier_depends()
-#else
 #define smp_mb()	barrier()
 #define smp_rmb()	barrier()
 #define smp_wmb()	barrier()
 #define smp_read_barrier_depends()	do { } while(0)
-#endif
 
 #define read_barrier_depends()  ((void)0)
 
@@ -199,19 +145,9 @@
 			(unsigned long)(n), sizeof(*(ptr))))
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
 
-#ifndef CONFIG_SMP
 #include <asm-generic/cmpxchg.h>
-#endif
 
 #define arch_align_stack(x) (x)
 
 
-static inline int irqs_disabled_flags(unsigned long flags)
-{
-	if (flags & 0x0700)
-		return 0;
-	else
-		return 1;
-}
-
 #endif /* _M68KNOMMU_SYSTEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,108 @@
-#ifdef __uClinux__
-#include "thread_info_no.h"
+#ifndef _ASM_M68K_THREAD_INFO_H
+#define _ASM_M68K_THREAD_INFO_H
+
+#include <asm/types.h>
+#include <asm/page.h>
+
+/*
+ * On machines with 4k pages we default to an 8k thread size, though we
+ * allow a 4k with config option. Any other machine page size then
+ * the thread size must match the page size (which is 8k and larger here).
+ */
+#if PAGE_SHIFT < 13
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE	4096
 #else
-#include "thread_info_mm.h"
+#define THREAD_SIZE	8192
+#endif
+#else
+#define THREAD_SIZE	PAGE_SIZE
+#endif
+#define THREAD_SIZE_ORDER	((THREAD_SIZE / PAGE_SIZE) - 1)
+
+#ifndef __ASSEMBLY__
+
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	unsigned long		flags;
+	struct exec_domain	*exec_domain;	/* execution domain */
+	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
+	__u32			cpu;		/* should always be 0 on m68k */
+	unsigned long		tp_value;	/* thread pointer */
+	struct restart_block    restart_block;
+};
+#endif /* __ASSEMBLY__ */
+
+#define PREEMPT_ACTIVE		0x4000000
+
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	.task		= &tsk,			\
+	.exec_domain	= &default_exec_domain,	\
+	.preempt_count	= INIT_PREEMPT_COUNT,	\
+	.restart_block = {			\
+		.fn = do_no_restart_syscall,	\
+	},					\
+}
+
+#define init_stack		(init_thread_union.stack)
+
+#ifdef CONFIG_MMU
+
+#ifndef __ASSEMBLY__
+#include <asm/current.h>
 #endif
+
+#ifdef ASM_OFFSETS_C
+#define task_thread_info(tsk)	((struct thread_info *) NULL)
+#else
+#include <asm/asm-offsets.h>
+#define task_thread_info(tsk)	((struct thread_info *)((char *)tsk+TASK_TINFO))
+#endif
+
+#define init_thread_info	(init_task.thread.info)
+#define task_stack_page(tsk)	((tsk)->stack)
+#define current_thread_info()	task_thread_info(current)
+
+#define __HAVE_THREAD_FUNCTIONS
+
+#define setup_thread_stack(p, org) ({			\
+	*(struct task_struct **)(p)->stack = (p);	\
+	task_thread_info(p)->task = (p);		\
+})
+
+#define end_of_stack(p)		((unsigned long *)(p)->stack + 1)
+
+#else /* !CONFIG_MMU */
+
+#ifndef __ASSEMBLY__
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+	struct thread_info *ti;
+	__asm__(
+		"move.l %%sp, %0 \n\t"
+		"and.l  %1, %0"
+		: "=&d"(ti)
+		: "di" (~(THREAD_SIZE-1))
+		);
+	return ti;
+}
+#endif
+
+#define init_thread_info	(init_thread_union.thread_info)
+
+#endif /* CONFIG_MMU */
+
+/* entry.S relies on these definitions!
+ * bits 0-7 are tested at every exception exit
+ * bits 8-15 are also tested at syscall exit
+ */
+#define TIF_SIGPENDING		6	/* signal pending */
+#define TIF_NEED_RESCHED	7	/* rescheduling necessary */
+#define TIF_DELAYED_TRACE	14	/* single step a syscall */
+#define TIF_SYSCALL_TRACE	15	/* syscall trace active */
+#define TIF_MEMDIE		16	/* is terminating due to OOM killer */
+#define TIF_FREEZE		17	/* thread is freezing for suspend */
+
+#endif	/* _ASM_M68K_THREAD_INFO_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info_mm.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,71 +0,0 @@
-#ifndef _ASM_M68K_THREAD_INFO_H
-#define _ASM_M68K_THREAD_INFO_H
-
-#ifndef ASM_OFFSETS_C
-#include <asm/asm-offsets.h>
-#endif
-#include <asm/types.h>
-#include <asm/page.h>
-
-#ifndef __ASSEMBLY__
-#include <asm/current.h>
-
-struct thread_info {
-	struct task_struct	*task;		/* main task structure */
-	unsigned long		flags;
-	struct exec_domain	*exec_domain;	/* execution domain */
-	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
-	__u32 cpu; /* should always be 0 on m68k */
-	unsigned long		tp_value;	/* thread pointer */
-	struct restart_block    restart_block;
-};
-#endif /* __ASSEMBLY__ */
-
-#define PREEMPT_ACTIVE		0x4000000
-
-#define INIT_THREAD_INFO(tsk)			\
-{						\
-	.task		= &tsk,			\
-	.exec_domain	= &default_exec_domain,	\
-	.preempt_count	= INIT_PREEMPT_COUNT,	\
-	.restart_block = {			\
-		.fn = do_no_restart_syscall,	\
-	},					\
-}
-
-/* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */
-#define THREAD_SIZE_ORDER (13 - PAGE_SHIFT)
-
-#define init_thread_info	(init_task.thread.info)
-#define init_stack		(init_thread_union.stack)
-
-#ifdef ASM_OFFSETS_C
-#define task_thread_info(tsk)	((struct thread_info *) NULL)
-#else
-#define task_thread_info(tsk)	((struct thread_info *)((char *)tsk+TASK_TINFO))
-#endif
-
-#define task_stack_page(tsk)	((tsk)->stack)
-#define current_thread_info()	task_thread_info(current)
-
-#define __HAVE_THREAD_FUNCTIONS
-
-#define setup_thread_stack(p, org) ({			\
-	*(struct task_struct **)(p)->stack = (p);	\
-	task_thread_info(p)->task = (p);		\
-})
-
-#define end_of_stack(p) ((unsigned long *)(p)->stack + 1)
-
-/* entry.S relies on these definitions!
- * bits 0-7 are tested at every exception exit
- * bits 8-15 are also tested at syscall exit
- */
-#define TIF_SIGPENDING		6	/* signal pending */
-#define TIF_NEED_RESCHED	7	/* rescheduling necessary */
-#define TIF_DELAYED_TRACE	14	/* single step a syscall */
-#define TIF_SYSCALL_TRACE	15	/* syscall trace active */
-#define TIF_MEMDIE		16	/* is terminating due to OOM killer */
-#define TIF_FREEZE		17	/* thread is freezing for suspend */
-
-#endif	/* _ASM_M68K_THREAD_INFO_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/thread_info_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/thread_info_no.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,102 +0,0 @@
-/* thread_info.h: m68knommu low-level thread information
- * adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com)
- *
- * Copyright (C) 2002  David Howells (dhowells@redhat.com)
- * - Incorporating suggestions made by Linus Torvalds and Dave Miller
- */
-
-#ifndef _ASM_THREAD_INFO_H
-#define _ASM_THREAD_INFO_H
-
-#include <asm/page.h>
-
-#ifdef __KERNEL__
-
-/*
- * Size of kernel stack for each process. This must be a power of 2...
- */
-#ifdef CONFIG_4KSTACKS
-#define THREAD_SIZE_ORDER (0)
-#else
-#define THREAD_SIZE_ORDER (1)
-#endif
-                                                                                
-/*
- * for asm files, THREAD_SIZE is now generated by asm-offsets.c
- */
-#define THREAD_SIZE (PAGE_SIZE<<THREAD_SIZE_ORDER)
-
-#ifndef __ASSEMBLY__
-
-/*
- * low level task data.
- */
-struct thread_info {
-	struct task_struct *task;		/* main task structure */
-	struct exec_domain *exec_domain;	/* execution domain */
-	unsigned long	   flags;		/* low level flags */
-	int		   cpu;			/* cpu we're on */
-	int		   preempt_count;	/* 0 => preemptable, <0 => BUG */
-	unsigned long	   tp_value;		/* thread pointer */
-	struct restart_block restart_block;
-};
-
-/*
- * macros/functions for gaining access to the thread information structure
- */
-#define INIT_THREAD_INFO(tsk)			\
-{						\
-	.task		= &tsk,			\
-	.exec_domain	= &default_exec_domain,	\
-	.flags		= 0,			\
-	.cpu		= 0,			\
-	.preempt_count	= INIT_PREEMPT_COUNT,	\
-	.restart_block	= {			\
-		.fn = do_no_restart_syscall,	\
-	},					\
-}
-
-#define init_thread_info	(init_thread_union.thread_info)
-#define init_stack		(init_thread_union.stack)
-
-
-/* how to get the thread information struct from C */
-static inline struct thread_info *current_thread_info(void)
-{
-	struct thread_info *ti;
-	__asm__(
-		"move.l	%%sp, %0 \n\t"
-		"and.l	%1, %0"
-		: "=&d"(ti)
-		: "di" (~(THREAD_SIZE-1))
-		);
-	return ti;
-}
-
-#endif /* __ASSEMBLY__ */
-
-#define	PREEMPT_ACTIVE	0x4000000
-
-/*
- * thread information flag bit numbers
- */
-#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
-#define TIF_SIGPENDING		1	/* signal pending */
-#define TIF_NEED_RESCHED	2	/* rescheduling necessary */
-#define TIF_POLLING_NRFLAG	3	/* true if poll_idle() is polling
-					   TIF_NEED_RESCHED */
-#define TIF_MEMDIE		4	/* is terminating due to OOM killer */
-#define TIF_FREEZE		16	/* is freezing for suspend */
-
-/* as above, but as bit values */
-#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
-#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
-
-#define _TIF_WORK_MASK		0x0000FFFE	/* work to do on interrupt/exception return */
-
-#endif /* __KERNEL__ */
-
-#endif /* _ASM_THREAD_INFO_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,272 @@
-#ifdef __uClinux__
-#include "traps_no.h"
-#else
-#include "traps_mm.h"
+/*
+ *  linux/include/asm/traps.h
+ *
+ *  Copyright (C) 1993        Hamish Macdonald
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _M68K_TRAPS_H
+#define _M68K_TRAPS_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+
+typedef void (*e_vector)(void);
+extern e_vector vectors[];
+
+asmlinkage void auto_inthandler(void);
+asmlinkage void user_inthandler(void);
+asmlinkage void bad_inthandler(void);
+extern void init_vectors(void);
+
 #endif
+
+#define VEC_RESETSP (0)
+#define VEC_RESETPC (1)
+#define VEC_BUSERR  (2)
+#define VEC_ADDRERR (3)
+#define VEC_ILLEGAL (4)
+#define VEC_ZERODIV (5)
+#define VEC_CHK     (6)
+#define VEC_TRAP    (7)
+#define VEC_PRIV    (8)
+#define VEC_TRACE   (9)
+#define VEC_LINE10  (10)
+#define VEC_LINE11  (11)
+#define VEC_RESV12  (12)
+#define VEC_COPROC  (13)
+#define VEC_FORMAT  (14)
+#define VEC_UNINT   (15)
+#define VEC_RESV16  (16)
+#define VEC_RESV17  (17)
+#define VEC_RESV18  (18)
+#define VEC_RESV19  (19)
+#define VEC_RESV20  (20)
+#define VEC_RESV21  (21)
+#define VEC_RESV22  (22)
+#define VEC_RESV23  (23)
+#define VEC_SPUR    (24)
+#define VEC_INT1    (25)
+#define VEC_INT2    (26)
+#define VEC_INT3    (27)
+#define VEC_INT4    (28)
+#define VEC_INT5    (29)
+#define VEC_INT6    (30)
+#define VEC_INT7    (31)
+#define VEC_SYS     (32)
+#define VEC_TRAP1   (33)
+#define VEC_TRAP2   (34)
+#define VEC_TRAP3   (35)
+#define VEC_TRAP4   (36)
+#define VEC_TRAP5   (37)
+#define VEC_TRAP6   (38)
+#define VEC_TRAP7   (39)
+#define VEC_TRAP8   (40)
+#define VEC_TRAP9   (41)
+#define VEC_TRAP10  (42)
+#define VEC_TRAP11  (43)
+#define VEC_TRAP12  (44)
+#define VEC_TRAP13  (45)
+#define VEC_TRAP14  (46)
+#define VEC_TRAP15  (47)
+#define VEC_FPBRUC  (48)
+#define VEC_FPIR    (49)
+#define VEC_FPDIVZ  (50)
+#define VEC_FPUNDER (51)
+#define VEC_FPOE    (52)
+#define VEC_FPOVER  (53)
+#define VEC_FPNAN   (54)
+#define VEC_FPUNSUP (55)
+#define VEC_MMUCFG  (56)
+#define VEC_MMUILL  (57)
+#define VEC_MMUACC  (58)
+#define VEC_RESV59  (59)
+#define	VEC_UNIMPEA (60)
+#define	VEC_UNIMPII (61)
+#define VEC_RESV62  (62)
+#define VEC_RESV63  (63)
+#define VEC_USER    (64)
+
+#define VECOFF(vec) ((vec)<<2)
+
+#ifndef __ASSEMBLY__
+
+/* Status register bits */
+#define PS_T  (0x8000)
+#define PS_S  (0x2000)
+#define PS_M  (0x1000)
+#define PS_C  (0x0001)
+
+/* bits for 68020/68030 special status word */
+
+#define FC    (0x8000)
+#define FB    (0x4000)
+#define RC    (0x2000)
+#define RB    (0x1000)
+#define DF    (0x0100)
+#define RM    (0x0080)
+#define RW    (0x0040)
+#define SZ    (0x0030)
+#define DFC   (0x0007)
+
+/* bits for 68030 MMU status register (mmusr,psr) */
+
+#define MMU_B	     (0x8000)    /* bus error */
+#define MMU_L	     (0x4000)    /* limit violation */
+#define MMU_S	     (0x2000)    /* supervisor violation */
+#define MMU_WP	     (0x0800)    /* write-protected */
+#define MMU_I	     (0x0400)    /* invalid descriptor */
+#define MMU_M	     (0x0200)    /* ATC entry modified */
+#define MMU_T	     (0x0040)    /* transparent translation */
+#define MMU_NUM      (0x0007)    /* number of levels traversed */
+
+
+/* bits for 68040 special status word */
+#define CP_040	(0x8000)
+#define CU_040	(0x4000)
+#define CT_040	(0x2000)
+#define CM_040	(0x1000)
+#define MA_040	(0x0800)
+#define ATC_040 (0x0400)
+#define LK_040	(0x0200)
+#define RW_040	(0x0100)
+#define SIZ_040 (0x0060)
+#define TT_040	(0x0018)
+#define TM_040	(0x0007)
+
+/* bits for 68040 write back status word */
+#define WBV_040   (0x80)
+#define WBSIZ_040 (0x60)
+#define WBBYT_040 (0x20)
+#define WBWRD_040 (0x40)
+#define WBLNG_040 (0x00)
+#define WBTT_040  (0x18)
+#define WBTM_040  (0x07)
+
+/* bus access size codes */
+#define BA_SIZE_BYTE    (0x20)
+#define BA_SIZE_WORD    (0x40)
+#define BA_SIZE_LONG    (0x00)
+#define BA_SIZE_LINE    (0x60)
+
+/* bus access transfer type codes */
+#define BA_TT_MOVE16    (0x08)
+
+/* bits for 68040 MMU status register (mmusr) */
+#define MMU_B_040   (0x0800)
+#define MMU_G_040   (0x0400)
+#define MMU_S_040   (0x0080)
+#define MMU_CM_040  (0x0060)
+#define MMU_M_040   (0x0010)
+#define MMU_WP_040  (0x0004)
+#define MMU_T_040   (0x0002)
+#define MMU_R_040   (0x0001)
+
+/* bits in the 68060 fault status long word (FSLW) */
+#define	MMU060_MA	(0x08000000)	/* misaligned */
+#define	MMU060_LK	(0x02000000)	/* locked transfer */
+#define	MMU060_RW	(0x01800000)	/* read/write */
+# define MMU060_RW_W	(0x00800000)	/* write */
+# define MMU060_RW_R	(0x01000000)	/* read */
+# define MMU060_RW_RMW	(0x01800000)	/* read/modify/write */
+# define MMU060_W	(0x00800000)	/* general write, includes rmw */
+#define	MMU060_SIZ	(0x00600000)	/* transfer size */
+#define	MMU060_TT	(0x00180000)	/* transfer type (TT) bits */
+#define	MMU060_TM	(0x00070000)	/* transfer modifier (TM) bits */
+#define	MMU060_IO	(0x00008000)	/* instruction or operand */
+#define	MMU060_PBE	(0x00004000)	/* push buffer bus error */
+#define	MMU060_SBE	(0x00002000)	/* store buffer bus error */
+#define	MMU060_PTA	(0x00001000)	/* pointer A fault */
+#define	MMU060_PTB	(0x00000800)	/* pointer B fault */
+#define	MMU060_IL	(0x00000400)	/* double indirect descr fault */
+#define	MMU060_PF	(0x00000200)	/* page fault (invalid descr) */
+#define	MMU060_SP	(0x00000100)	/* supervisor protection */
+#define	MMU060_WP	(0x00000080)	/* write protection */
+#define	MMU060_TWE	(0x00000040)	/* bus error on table search */
+#define	MMU060_RE	(0x00000020)	/* bus error on read */
+#define	MMU060_WE	(0x00000010)	/* bus error on write */
+#define	MMU060_TTR	(0x00000008)	/* error caused by TTR translation */
+#define	MMU060_BPE	(0x00000004)	/* branch prediction error */
+#define	MMU060_SEE	(0x00000001)	/* software emulated error */
+
+/* cases of missing or invalid descriptors */
+#define MMU060_DESC_ERR (MMU060_PTA | MMU060_PTB | \
+			 MMU060_IL  | MMU060_PF)
+/* bits that indicate real errors */
+#define MMU060_ERR_BITS (MMU060_PBE | MMU060_SBE | MMU060_DESC_ERR | MMU060_SP | \
+			 MMU060_WP  | MMU060_TWE | MMU060_RE       | MMU060_WE)
+
+/* structure for stack frames */
+
+struct frame {
+    struct pt_regs ptregs;
+    union {
+	    struct {
+		    unsigned long  iaddr;    /* instruction address */
+	    } fmt2;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+	    } fmt3;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+		    unsigned long  pc;	     /* pc of faulted instr */
+	    } fmt4;
+	    struct {
+		    unsigned long  effaddr;  /* effective address */
+		    unsigned short ssw;      /* special status word */
+		    unsigned short wb3s;     /* write back 3 status */
+		    unsigned short wb2s;     /* write back 2 status */
+		    unsigned short wb1s;     /* write back 1 status */
+		    unsigned long  faddr;    /* fault address */
+		    unsigned long  wb3a;     /* write back 3 address */
+		    unsigned long  wb3d;     /* write back 3 data */
+		    unsigned long  wb2a;     /* write back 2 address */
+		    unsigned long  wb2d;     /* write back 2 data */
+		    unsigned long  wb1a;     /* write back 1 address */
+		    unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
+		    unsigned long  pd1;      /* push data 1*/
+		    unsigned long  pd2;      /* push data 2*/
+		    unsigned long  pd3;      /* push data 3*/
+	    } fmt7;
+	    struct {
+		    unsigned long  iaddr;    /* instruction address */
+		    unsigned short int1[4];  /* internal registers */
+	    } fmt9;
+	    struct {
+		    unsigned short int1;
+		    unsigned short ssw;      /* special status word */
+		    unsigned short isc;      /* instruction stage c */
+		    unsigned short isb;      /* instruction stage b */
+		    unsigned long  daddr;    /* data cycle fault address */
+		    unsigned short int2[2];
+		    unsigned long  dobuf;    /* data cycle output buffer */
+		    unsigned short int3[2];
+	    } fmta;
+	    struct {
+		    unsigned short int1;
+		    unsigned short ssw;     /* special status word */
+		    unsigned short isc;     /* instruction stage c */
+		    unsigned short isb;     /* instruction stage b */
+		    unsigned long  daddr;   /* data cycle fault address */
+		    unsigned short int2[2];
+		    unsigned long  dobuf;   /* data cycle output buffer */
+		    unsigned short int3[4];
+		    unsigned long  baddr;   /* stage B address */
+		    unsigned short int4[2];
+		    unsigned long  dibuf;   /* data cycle input buffer */
+		    unsigned short int5[3];
+		    unsigned	   ver : 4; /* stack frame version # */
+		    unsigned	   int6:12;
+		    unsigned short int7[18];
+	    } fmtb;
+    } un;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _M68K_TRAPS_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps_mm.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps_mm.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps_mm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps_mm.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,272 +0,0 @@
-/*
- *  linux/include/asm/traps.h
- *
- *  Copyright (C) 1993        Hamish Macdonald
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef _M68K_TRAPS_H
-#define _M68K_TRAPS_H
-
-#ifndef __ASSEMBLY__
-
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-
-typedef void (*e_vector)(void);
-
-asmlinkage void auto_inthandler(void);
-asmlinkage void user_inthandler(void);
-asmlinkage void bad_inthandler(void);
-
-extern e_vector vectors[];
-
-#endif
-
-#define VEC_RESETSP (0)
-#define VEC_RESETPC (1)
-#define VEC_BUSERR  (2)
-#define VEC_ADDRERR (3)
-#define VEC_ILLEGAL (4)
-#define VEC_ZERODIV (5)
-#define VEC_CHK     (6)
-#define VEC_TRAP    (7)
-#define VEC_PRIV    (8)
-#define VEC_TRACE   (9)
-#define VEC_LINE10  (10)
-#define VEC_LINE11  (11)
-#define VEC_RESV12  (12)
-#define VEC_COPROC  (13)
-#define VEC_FORMAT  (14)
-#define VEC_UNINT   (15)
-#define VEC_RESV16  (16)
-#define VEC_RESV17  (17)
-#define VEC_RESV18  (18)
-#define VEC_RESV19  (19)
-#define VEC_RESV20  (20)
-#define VEC_RESV21  (21)
-#define VEC_RESV22  (22)
-#define VEC_RESV23  (23)
-#define VEC_SPUR    (24)
-#define VEC_INT1    (25)
-#define VEC_INT2    (26)
-#define VEC_INT3    (27)
-#define VEC_INT4    (28)
-#define VEC_INT5    (29)
-#define VEC_INT6    (30)
-#define VEC_INT7    (31)
-#define VEC_SYS     (32)
-#define VEC_TRAP1   (33)
-#define VEC_TRAP2   (34)
-#define VEC_TRAP3   (35)
-#define VEC_TRAP4   (36)
-#define VEC_TRAP5   (37)
-#define VEC_TRAP6   (38)
-#define VEC_TRAP7   (39)
-#define VEC_TRAP8   (40)
-#define VEC_TRAP9   (41)
-#define VEC_TRAP10  (42)
-#define VEC_TRAP11  (43)
-#define VEC_TRAP12  (44)
-#define VEC_TRAP13  (45)
-#define VEC_TRAP14  (46)
-#define VEC_TRAP15  (47)
-#define VEC_FPBRUC  (48)
-#define VEC_FPIR    (49)
-#define VEC_FPDIVZ  (50)
-#define VEC_FPUNDER (51)
-#define VEC_FPOE    (52)
-#define VEC_FPOVER  (53)
-#define VEC_FPNAN   (54)
-#define VEC_FPUNSUP (55)
-#define VEC_MMUCFG  (56)
-#define VEC_MMUILL  (57)
-#define VEC_MMUACC  (58)
-#define VEC_RESV59  (59)
-#define	VEC_UNIMPEA (60)
-#define	VEC_UNIMPII (61)
-#define VEC_RESV62  (62)
-#define VEC_RESV63  (63)
-#define VEC_USER    (64)
-
-#define VECOFF(vec) ((vec)<<2)
-
-#ifndef __ASSEMBLY__
-
-/* Status register bits */
-#define PS_T  (0x8000)
-#define PS_S  (0x2000)
-#define PS_M  (0x1000)
-#define PS_C  (0x0001)
-
-/* bits for 68020/68030 special status word */
-
-#define FC    (0x8000)
-#define FB    (0x4000)
-#define RC    (0x2000)
-#define RB    (0x1000)
-#define DF    (0x0100)
-#define RM    (0x0080)
-#define RW    (0x0040)
-#define SZ    (0x0030)
-#define DFC   (0x0007)
-
-/* bits for 68030 MMU status register (mmusr,psr) */
-
-#define MMU_B	     (0x8000)    /* bus error */
-#define MMU_L	     (0x4000)    /* limit violation */
-#define MMU_S	     (0x2000)    /* supervisor violation */
-#define MMU_WP	     (0x0800)    /* write-protected */
-#define MMU_I	     (0x0400)    /* invalid descriptor */
-#define MMU_M	     (0x0200)    /* ATC entry modified */
-#define MMU_T	     (0x0040)    /* transparent translation */
-#define MMU_NUM      (0x0007)    /* number of levels traversed */
-
-
-/* bits for 68040 special status word */
-#define CP_040	(0x8000)
-#define CU_040	(0x4000)
-#define CT_040	(0x2000)
-#define CM_040	(0x1000)
-#define MA_040	(0x0800)
-#define ATC_040 (0x0400)
-#define LK_040	(0x0200)
-#define RW_040	(0x0100)
-#define SIZ_040 (0x0060)
-#define TT_040	(0x0018)
-#define TM_040	(0x0007)
-
-/* bits for 68040 write back status word */
-#define WBV_040   (0x80)
-#define WBSIZ_040 (0x60)
-#define WBBYT_040 (0x20)
-#define WBWRD_040 (0x40)
-#define WBLNG_040 (0x00)
-#define WBTT_040  (0x18)
-#define WBTM_040  (0x07)
-
-/* bus access size codes */
-#define BA_SIZE_BYTE    (0x20)
-#define BA_SIZE_WORD    (0x40)
-#define BA_SIZE_LONG    (0x00)
-#define BA_SIZE_LINE    (0x60)
-
-/* bus access transfer type codes */
-#define BA_TT_MOVE16    (0x08)
-
-/* bits for 68040 MMU status register (mmusr) */
-#define MMU_B_040   (0x0800)
-#define MMU_G_040   (0x0400)
-#define MMU_S_040   (0x0080)
-#define MMU_CM_040  (0x0060)
-#define MMU_M_040   (0x0010)
-#define MMU_WP_040  (0x0004)
-#define MMU_T_040   (0x0002)
-#define MMU_R_040   (0x0001)
-
-/* bits in the 68060 fault status long word (FSLW) */
-#define	MMU060_MA	(0x08000000)	/* misaligned */
-#define	MMU060_LK	(0x02000000)	/* locked transfer */
-#define	MMU060_RW	(0x01800000)	/* read/write */
-# define MMU060_RW_W	(0x00800000)	/* write */
-# define MMU060_RW_R	(0x01000000)	/* read */
-# define MMU060_RW_RMW	(0x01800000)	/* read/modify/write */
-# define MMU060_W	(0x00800000)	/* general write, includes rmw */
-#define	MMU060_SIZ	(0x00600000)	/* transfer size */
-#define	MMU060_TT	(0x00180000)	/* transfer type (TT) bits */
-#define	MMU060_TM	(0x00070000)	/* transfer modifier (TM) bits */
-#define	MMU060_IO	(0x00008000)	/* instruction or operand */
-#define	MMU060_PBE	(0x00004000)	/* push buffer bus error */
-#define	MMU060_SBE	(0x00002000)	/* store buffer bus error */
-#define	MMU060_PTA	(0x00001000)	/* pointer A fault */
-#define	MMU060_PTB	(0x00000800)	/* pointer B fault */
-#define	MMU060_IL	(0x00000400)	/* double indirect descr fault */
-#define	MMU060_PF	(0x00000200)	/* page fault (invalid descr) */
-#define	MMU060_SP	(0x00000100)	/* supervisor protection */
-#define	MMU060_WP	(0x00000080)	/* write protection */
-#define	MMU060_TWE	(0x00000040)	/* bus error on table search */
-#define	MMU060_RE	(0x00000020)	/* bus error on read */
-#define	MMU060_WE	(0x00000010)	/* bus error on write */
-#define	MMU060_TTR	(0x00000008)	/* error caused by TTR translation */
-#define	MMU060_BPE	(0x00000004)	/* branch prediction error */
-#define	MMU060_SEE	(0x00000001)	/* software emulated error */
-
-/* cases of missing or invalid descriptors */
-#define MMU060_DESC_ERR (MMU060_PTA | MMU060_PTB | \
-			 MMU060_IL  | MMU060_PF)
-/* bits that indicate real errors */
-#define MMU060_ERR_BITS (MMU060_PBE | MMU060_SBE | MMU060_DESC_ERR | MMU060_SP | \
-			 MMU060_WP  | MMU060_TWE | MMU060_RE       | MMU060_WE)
-
-/* structure for stack frames */
-
-struct frame {
-    struct pt_regs ptregs;
-    union {
-	    struct {
-		    unsigned long  iaddr;    /* instruction address */
-	    } fmt2;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-	    } fmt3;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-		    unsigned long  pc;	     /* pc of faulted instr */
-	    } fmt4;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-		    unsigned short ssw;      /* special status word */
-		    unsigned short wb3s;     /* write back 3 status */
-		    unsigned short wb2s;     /* write back 2 status */
-		    unsigned short wb1s;     /* write back 1 status */
-		    unsigned long  faddr;    /* fault address */
-		    unsigned long  wb3a;     /* write back 3 address */
-		    unsigned long  wb3d;     /* write back 3 data */
-		    unsigned long  wb2a;     /* write back 2 address */
-		    unsigned long  wb2d;     /* write back 2 data */
-		    unsigned long  wb1a;     /* write back 1 address */
-		    unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
-		    unsigned long  pd1;      /* push data 1*/
-		    unsigned long  pd2;      /* push data 2*/
-		    unsigned long  pd3;      /* push data 3*/
-	    } fmt7;
-	    struct {
-		    unsigned long  iaddr;    /* instruction address */
-		    unsigned short int1[4];  /* internal registers */
-	    } fmt9;
-	    struct {
-		    unsigned short int1;
-		    unsigned short ssw;      /* special status word */
-		    unsigned short isc;      /* instruction stage c */
-		    unsigned short isb;      /* instruction stage b */
-		    unsigned long  daddr;    /* data cycle fault address */
-		    unsigned short int2[2];
-		    unsigned long  dobuf;    /* data cycle output buffer */
-		    unsigned short int3[2];
-	    } fmta;
-	    struct {
-		    unsigned short int1;
-		    unsigned short ssw;     /* special status word */
-		    unsigned short isc;     /* instruction stage c */
-		    unsigned short isb;     /* instruction stage b */
-		    unsigned long  daddr;   /* data cycle fault address */
-		    unsigned short int2[2];
-		    unsigned long  dobuf;   /* data cycle output buffer */
-		    unsigned short int3[4];
-		    unsigned long  baddr;   /* stage B address */
-		    unsigned short int4[2];
-		    unsigned long  dibuf;   /* data cycle input buffer */
-		    unsigned short int5[3];
-		    unsigned	   ver : 4; /* stack frame version # */
-		    unsigned	   int6:12;
-		    unsigned short int7[18];
-	    } fmtb;
-    } un;
-};
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _M68K_TRAPS_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps_no.h linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps_no.h
--- linux-libre-2.6.36-gnu/arch/m68k/include/asm/traps_no.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/include/asm/traps_no.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,154 +0,0 @@
-/*
- *  linux/include/asm/traps.h
- *
- *  Copyright (C) 1993        Hamish Macdonald
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef _M68KNOMMU_TRAPS_H
-#define _M68KNOMMU_TRAPS_H
-
-#ifndef __ASSEMBLY__
-
-typedef void (*e_vector)(void);
-
-extern e_vector vectors[];
-extern void init_vectors(void);
-extern void enable_vector(unsigned int irq);
-extern void disable_vector(unsigned int irq);
-extern void ack_vector(unsigned int irq);
-
-#endif
-
-#define VEC_BUSERR  (2)
-#define VEC_ADDRERR (3)
-#define VEC_ILLEGAL (4)
-#define VEC_ZERODIV (5)
-#define VEC_CHK     (6)
-#define VEC_TRAP    (7)
-#define VEC_PRIV    (8)
-#define VEC_TRACE   (9)
-#define VEC_LINE10  (10)
-#define VEC_LINE11  (11)
-#define VEC_RESV1   (12)
-#define VEC_COPROC  (13)
-#define VEC_FORMAT  (14)
-#define VEC_UNINT   (15)
-#define VEC_SPUR    (24)
-#define VEC_INT1    (25)
-#define VEC_INT2    (26)
-#define VEC_INT3    (27)
-#define VEC_INT4    (28)
-#define VEC_INT5    (29)
-#define VEC_INT6    (30)
-#define VEC_INT7    (31)
-#define VEC_SYS     (32)
-#define VEC_TRAP1   (33)
-#define VEC_TRAP2   (34)
-#define VEC_TRAP3   (35)
-#define VEC_TRAP4   (36)
-#define VEC_TRAP5   (37)
-#define VEC_TRAP6   (38)
-#define VEC_TRAP7   (39)
-#define VEC_TRAP8   (40)
-#define VEC_TRAP9   (41)
-#define VEC_TRAP10  (42)
-#define VEC_TRAP11  (43)
-#define VEC_TRAP12  (44)
-#define VEC_TRAP13  (45)
-#define VEC_TRAP14  (46)
-#define VEC_TRAP15  (47)
-#define VEC_FPBRUC  (48)
-#define VEC_FPIR    (49)
-#define VEC_FPDIVZ  (50)
-#define VEC_FPUNDER (51)
-#define VEC_FPOE    (52)
-#define VEC_FPOVER  (53)
-#define VEC_FPNAN   (54)
-#define VEC_FPUNSUP (55)
-#define	VEC_UNIMPEA (60)
-#define	VEC_UNIMPII (61)
-#define VEC_USER    (64)
-
-#define VECOFF(vec) ((vec)<<2)
-
-#ifndef __ASSEMBLY__
-
-/* Status register bits */
-#define PS_T  (0x8000)
-#define PS_S  (0x2000)
-#define PS_M  (0x1000)
-#define PS_C  (0x0001)
-
-/* structure for stack frames */
-
-struct frame {
-    struct pt_regs ptregs;
-    union {
-	    struct {
-		    unsigned long  iaddr;    /* instruction address */
-	    } fmt2;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-	    } fmt3;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-		    unsigned long  pc;	     /* pc of faulted instr */
-	    } fmt4;
-	    struct {
-		    unsigned long  effaddr;  /* effective address */
-		    unsigned short ssw;      /* special status word */
-		    unsigned short wb3s;     /* write back 3 status */
-		    unsigned short wb2s;     /* write back 2 status */
-		    unsigned short wb1s;     /* write back 1 status */
-		    unsigned long  faddr;    /* fault address */
-		    unsigned long  wb3a;     /* write back 3 address */
-		    unsigned long  wb3d;     /* write back 3 data */
-		    unsigned long  wb2a;     /* write back 2 address */
-		    unsigned long  wb2d;     /* write back 2 data */
-		    unsigned long  wb1a;     /* write back 1 address */
-		    unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
-		    unsigned long  pd1;      /* push data 1*/
-		    unsigned long  pd2;      /* push data 2*/
-		    unsigned long  pd3;      /* push data 3*/
-	    } fmt7;
-	    struct {
-		    unsigned long  iaddr;    /* instruction address */
-		    unsigned short int1[4];  /* internal registers */
-	    } fmt9;
-	    struct {
-		    unsigned short int1;
-		    unsigned short ssw;      /* special status word */
-		    unsigned short isc;      /* instruction stage c */
-		    unsigned short isb;      /* instruction stage b */
-		    unsigned long  daddr;    /* data cycle fault address */
-		    unsigned short int2[2];
-		    unsigned long  dobuf;    /* data cycle output buffer */
-		    unsigned short int3[2];
-	    } fmta;
-	    struct {
-		    unsigned short int1;
-		    unsigned short ssw;     /* special status word */
-		    unsigned short isc;     /* instruction stage c */
-		    unsigned short isb;     /* instruction stage b */
-		    unsigned long  daddr;   /* data cycle fault address */
-		    unsigned short int2[2];
-		    unsigned long  dobuf;   /* data cycle output buffer */
-		    unsigned short int3[4];
-		    unsigned long  baddr;   /* stage B address */
-		    unsigned short int4[2];
-		    unsigned long  dibuf;   /* data cycle input buffer */
-		    unsigned short int5[3];
-		    unsigned	   ver : 4; /* stack frame version # */
-		    unsigned	   int6:12;
-		    unsigned short int7[18];
-	    } fmtb;
-    } un;
-};
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* _M68KNOMMU_TRAPS_H */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/Kconfig linux-libre-2.6.37-gnu/arch/m68k/Kconfig
--- linux-libre-2.6.36-gnu/arch/m68k/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
 config M68K
 	bool
 	default y
@@ -62,8 +58,6 @@
 config ARCH_USES_GETTIMEOFFSET
 	def_bool y
 
-mainmenu "Linux/68k Kernel Configuration"
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
@@ -434,7 +428,7 @@
 
 config ISA
 	bool
-	depends on Q40 || AMIGA_PCMCIA || GG2
+	depends on Q40 || AMIGA_PCMCIA
 	default y
 	help
 	  Find out whether you have ISA slots on your motherboard.  ISA is the
@@ -445,7 +439,7 @@
 
 config GENERIC_ISA_DMA
 	bool
-	depends on Q40 || AMIGA_PCMCIA || GG2
+	depends on Q40 || AMIGA_PCMCIA
 	default y
 
 config ZONE_DMA
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/m68k/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,13 +22,9 @@
 int main(void)
 {
 	/* offsets into the task struct */
-	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
-	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
 	DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 #ifdef CONFIG_MMU
 	DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
 #endif
@@ -64,14 +60,6 @@
 	/* bitfields are a bit difficult */
 	DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
 
-	/* offsets into the irq_handler struct */
-	DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
-	DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
-	DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
-
-	/* offsets into the kernel_stat struct */
-	DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-
 	/* offsets into the irq_cpustat_t struct */
 	DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
 
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/process.c linux-libre-2.6.37-gnu/arch/m68k/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/m68k/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -156,55 +156,57 @@
 	singlestep_disable(child);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long tmp;
 	int i, ret = 0;
+	int regno = addr >> 2; /* temporary hack. */
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 	/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
 		if (addr & 3)
 			goto out_eio;
-		addr >>= 2;	/* temporary hack. */
 
-		if (addr >= 0 && addr < 19) {
-			tmp = get_reg(child, addr);
-		} else if (addr >= 21 && addr < 49) {
-			tmp = child->thread.fp[addr - 21];
+		if (regno >= 0 && regno < 19) {
+			tmp = get_reg(child, regno);
+		} else if (regno >= 21 && regno < 49) {
+			tmp = child->thread.fp[regno - 21];
 			/* Convert internal fpu reg representation
 			 * into long double format
 			 */
-			if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
+			if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
 				tmp = ((tmp & 0xffff0000) << 15) |
 				      ((tmp & 0x0000ffff) << 16);
 		} else
 			goto out_eio;
-		ret = put_user(tmp, (unsigned long *)data);
+		ret = put_user(tmp, datap);
 		break;
 
-	case PTRACE_POKEUSR:	/* write the word at location addr in the USER area */
+	case PTRACE_POKEUSR:
+	/* write the word at location addr in the USER area */
 		if (addr & 3)
 			goto out_eio;
-		addr >>= 2;	/* temporary hack. */
 
-		if (addr == PT_SR) {
+		if (regno == PT_SR) {
 			data &= SR_MASK;
 			data |= get_reg(child, PT_SR) & ~SR_MASK;
 		}
-		if (addr >= 0 && addr < 19) {
-			if (put_reg(child, addr, data))
+		if (regno >= 0 && regno < 19) {
+			if (put_reg(child, regno, data))
 				goto out_eio;
-		} else if (addr >= 21 && addr < 48) {
+		} else if (regno >= 21 && regno < 48) {
 			/* Convert long double format
 			 * into internal fpu reg representation
 			 */
-			if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
-				data = (unsigned long)data << 15;
+			if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
+				data <<= 15;
 				data = (data & 0xffff0000) |
 				       ((data & 0x0000ffff) >> 1);
 			}
-			child->thread.fp[addr - 21] = data;
+			child->thread.fp[regno - 21] = data;
 		} else
 			goto out_eio;
 		break;
@@ -212,16 +214,16 @@
 	case PTRACE_GETREGS:	/* Get all gp regs from the child. */
 		for (i = 0; i < 19; i++) {
 			tmp = get_reg(child, i);
-			ret = put_user(tmp, (unsigned long *)data);
+			ret = put_user(tmp, datap);
 			if (ret)
 				break;
-			data += sizeof(long);
+			datap++;
 		}
 		break;
 
 	case PTRACE_SETREGS:	/* Set all gp regs in the child. */
 		for (i = 0; i < 19; i++) {
-			ret = get_user(tmp, (unsigned long *)data);
+			ret = get_user(tmp, datap);
 			if (ret)
 				break;
 			if (i == PT_SR) {
@@ -229,25 +231,24 @@
 				tmp |= get_reg(child, PT_SR) & ~SR_MASK;
 			}
 			put_reg(child, i, tmp);
-			data += sizeof(long);
+			datap++;
 		}
 		break;
 
 	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
-		if (copy_to_user((void *)data, &child->thread.fp,
+		if (copy_to_user(datap, &child->thread.fp,
 				 sizeof(struct user_m68kfp_struct)))
 			ret = -EFAULT;
 		break;
 
 	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
-		if (copy_from_user(&child->thread.fp, (void *)data,
+		if (copy_from_user(&child->thread.fp, datap,
 				   sizeof(struct user_m68kfp_struct)))
 			ret = -EFAULT;
 		break;
 
 	case PTRACE_GET_THREAD_AREA:
-		ret = put_user(task_thread_info(child)->tp_value,
-			       (unsigned long __user *)data);
+		ret = put_user(task_thread_info(child)->tp_value, datap);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/setup.c linux-libre-2.6.37-gnu/arch/m68k/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -359,12 +359,6 @@
 		isa_type = ISA_TYPE_Q40;
 		isa_sex = 0;
 	}
-#ifdef CONFIG_GG2
-	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) {
-		isa_type = ISA_TYPE_GG2;
-		isa_sex = 0;
-	}
-#endif
 #ifdef CONFIG_AMIGA_PCMCIA
 	if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
 		isa_type = ISA_TYPE_AG;
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/sys_m68k.c linux-libre-2.6.37-gnu/arch/m68k/kernel/sys_m68k.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/sys_m68k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/sys_m68k.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
@@ -377,7 +376,6 @@
 	struct vm_area_struct *vma;
 	int ret = -EINVAL;
 
-	lock_kernel();
 	if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
 	    cache & ~FLUSH_CACHE_BOTH)
 		goto out;
@@ -446,7 +444,6 @@
 	    }
 	}
 out:
-	unlock_kernel();
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68k/kernel/time.c linux-libre-2.6.37-gnu/arch/m68k/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/m68k/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,9 +42,7 @@
 static irqreturn_t timer_interrupt(int irq, void *dummy)
 {
 	do_timer(1);
-#ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
-#endif
 	profile_tick(CPU_PROFILING);
 
 #ifdef CONFIG_HEARTBEAT
diff -druN linux-libre-2.6.36-gnu/arch/m68k/mac/macboing.c linux-libre-2.6.37-gnu/arch/m68k/mac/macboing.c
--- linux-libre-2.6.36-gnu/arch/m68k/mac/macboing.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/mac/macboing.c	2011-01-04 19:50:19.000000000 -0500
@@ -114,7 +114,8 @@
 			 *   16-bit I/O functionality.  The PowerBook 500 series computers
 			 *   support 16-bit stereo output, but only mono input."
 			 *
-			 *   http://til.info.apple.com/techinfo.nsf/artnum/n16405
+			 *   Technical Information Library (TIL) article number 16405. 
+			 *   http://support.apple.com/kb/TA32601 
 			 *
 			 * --David Kilzer
 			 */
diff -druN linux-libre-2.6.36-gnu/arch/m68k/mvme16x/rtc.c linux-libre-2.6.37-gnu/arch/m68k/mvme16x/rtc.c
--- linux-libre-2.6.36-gnu/arch/m68k/mvme16x/rtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/mvme16x/rtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -144,6 +144,7 @@
 	.unlocked_ioctl	= rtc_ioctl,
 	.open		= rtc_open,
 	.release	= rtc_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice rtc_dev=
diff -druN linux-libre-2.6.36-gnu/arch/m68k/q40/README linux-libre-2.6.37-gnu/arch/m68k/q40/README
--- linux-libre-2.6.36-gnu/arch/m68k/q40/README	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/q40/README	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
 
 You may try http://www.geocities.com/SiliconValley/Bay/2602/ for
 some up to date information. Booter and other tools will be also
-available from this place or ftp.uni-erlangen.de/linux/680x0/q40/
+available from this place or http://ftp.uni-erlangen.de/pub/unix/Linux/680x0/q40/
 and mirrors.
 
 Hints to documentation usually refer to the linux source tree in
diff -druN linux-libre-2.6.36-gnu/arch/m68k/sun3/sun3ints.c linux-libre-2.6.37-gnu/arch/m68k/sun3/sun3ints.c
--- linux-libre-2.6.36-gnu/arch/m68k/sun3/sun3ints.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68k/sun3/sun3ints.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,9 +67,7 @@
 	intersil_clear();
 #endif
         do_timer(1);
-#ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
-#endif
         if (!(kstat_cpu(0).irqs[irq] % 20))
                 sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
 	return IRQ_HANDLED;
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/Kconfig linux-libre-2.6.37-gnu/arch/m68knommu/Kconfig
--- linux-libre-2.6.36-gnu/arch/m68knommu/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "uClinux/68k (w/o MMU) Kernel Configuration"
-
 config M68K
 	bool
 	default y
@@ -59,6 +52,10 @@
 	bool
 	default y
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+	bool
+	default y
+
 config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
@@ -171,6 +168,11 @@
 	help
 	  Motorola ColdFire 5407 processor support.
 
+config M548x
+	bool "MCF548x"
+	help
+	  Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support.
+
 endchoice
 
 config M527x
@@ -181,7 +183,7 @@
 
 config COLDFIRE
 	bool
-	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407)
+	depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x)
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
 	default y
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,14 +21,8 @@
 int main(void)
 {
 	/* offsets into the task struct */
-	DEFINE(TASK_STATE, offsetof(struct task_struct, state));
-	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-	DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-	DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
 	DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-	DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
 	DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-	DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
 
 	/* offsets into the irq_cpustat_t struct */
 	DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
@@ -63,7 +57,7 @@
 	DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
 #else
 	/* bitfields are a bit difficult */
-	DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
+	DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
 #endif
 
 	/* signal defines */
@@ -74,14 +68,9 @@
 
 	DEFINE(PT_PTRACED, PT_PTRACED);
 
-	DEFINE(THREAD_SIZE, THREAD_SIZE);
-
 	/* Offsets in thread_info structure */
-	DEFINE(TI_TASK, offsetof(struct thread_info, task));
-	DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
 	DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/.gitignore linux-libre-2.6.37-gnu/arch/m68knommu/kernel/.gitignore
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/.gitignore	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/.gitignore	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+vmlinux.lds
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/process.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/signal.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -111,9 +112,12 @@
 	user_disable_single_step(child);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	int regno = addr >> 2;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 		/* read the word at location addr in the USER area. */
@@ -121,71 +125,48 @@
 			unsigned long tmp;
 			
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 ||
-			    addr > sizeof(struct user) - 3)
+			if ((addr & 3) || addr > sizeof(struct user) - 3)
 				break;
 			
 			tmp = 0;  /* Default return condition */
-			addr = addr >> 2; /* temporary hack. */
 			ret = -EIO;
-			if (addr < 19) {
-				tmp = get_reg(child, addr);
-				if (addr == PT_SR)
+			if (regno < 19) {
+				tmp = get_reg(child, regno);
+				if (regno == PT_SR)
 					tmp >>= 16;
-			} else if (addr >= 21 && addr < 49) {
-				tmp = child->thread.fp[addr - 21];
-#ifdef CONFIG_M68KFPU_EMU
-				/* Convert internal fpu reg representation
-				 * into long double format
-				 */
-				if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
-					tmp = ((tmp & 0xffff0000) << 15) |
-					      ((tmp & 0x0000ffff) << 16);
-#endif
-			} else if (addr == 49) {
+			} else if (regno >= 21 && regno < 49) {
+				tmp = child->thread.fp[regno - 21];
+			} else if (regno == 49) {
 				tmp = child->mm->start_code;
-			} else if (addr == 50) {
+			} else if (regno == 50) {
 				tmp = child->mm->start_data;
-			} else if (addr == 51) {
+			} else if (regno == 51) {
 				tmp = child->mm->end_code;
 			} else
 				break;
-			ret = put_user(tmp,(unsigned long *) data);
+			ret = put_user(tmp, datap);
 			break;
 		}
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 ||
-			    addr > sizeof(struct user) - 3)
+			if ((addr & 3) || addr > sizeof(struct user) - 3)
 				break;
 
-			addr = addr >> 2; /* temporary hack. */
-			    
-			if (addr == PT_SR) {
+			if (regno == PT_SR) {
 				data &= SR_MASK;
 				data <<= 16;
 				data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
 			}
-			if (addr < 19) {
-				if (put_reg(child, addr, data))
+			if (regno < 19) {
+				if (put_reg(child, regno, data))
 					break;
 				ret = 0;
 				break;
 			}
-			if (addr >= 21 && addr < 48)
+			if (regno >= 21 && regno < 48)
 			{
-#ifdef CONFIG_M68KFPU_EMU
-				/* Convert long double format
-				 * into internal fpu reg representation
-				 */
-				if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
-					data = (unsigned long)data << 15;
-					data = (data & 0xffff0000) |
-					       ((data & 0x0000ffff) >> 1);
-				}
-#endif
-				child->thread.fp[addr - 21] = data;
+				child->thread.fp[regno - 21] = data;
 				ret = 0;
 			}
 			break;
@@ -197,11 +178,11 @@
 			    tmp = get_reg(child, i);
 			    if (i == PT_SR)
 				tmp >>= 16;
-			    if (put_user(tmp, (unsigned long *) data)) {
+			    if (put_user(tmp, datap)) {
 				ret = -EFAULT;
 				break;
 			    }
-			    data += sizeof(long);
+			    datap++;
 			}
 			ret = 0;
 			break;
@@ -211,7 +192,7 @@
 			int i;
 			unsigned long tmp;
 			for (i = 0; i < 19; i++) {
-			    if (get_user(tmp, (unsigned long *) data)) {
+			    if (get_user(tmp, datap)) {
 				ret = -EFAULT;
 				break;
 			    }
@@ -221,7 +202,7 @@
 				tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
 			    }
 			    put_reg(child, i, tmp);
-			    data += sizeof(long);
+			    datap++;
 			}
 			ret = 0;
 			break;
@@ -230,7 +211,7 @@
 #ifdef PTRACE_GETFPREGS
 		case PTRACE_GETFPREGS: { /* Get the child FPU state. */
 			ret = 0;
-			if (copy_to_user((void *)data, &child->thread.fp,
+			if (copy_to_user(datap, &child->thread.fp,
 					 sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
 			break;
@@ -240,7 +221,7 @@
 #ifdef PTRACE_SETFPREGS
 		case PTRACE_SETFPREGS: { /* Set the child FPU state. */
 			ret = 0;
-			if (copy_from_user(&child->thread.fp, (void *)data,
+			if (copy_from_user(&child->thread.fp, datap,
 					   sizeof(struct user_m68kfp_struct)))
 				ret = -EFAULT;
 			break;
@@ -248,8 +229,7 @@
 #endif
 
 	case PTRACE_GET_THREAD_AREA:
-		ret = put_user(task_thread_info(child)->tp_value,
-			       (unsigned long __user *)data);
+		ret = put_user(task_thread_info(child)->tp_value, datap);
 		break;
 
 		default:
@@ -259,21 +239,17 @@
 	return ret;
 }
 
-asmlinkage void syscall_trace(void)
+asmlinkage int syscall_trace_enter(void)
 {
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
-		return;
-	if (!(current->ptrace & PT_PTRACED))
-		return;
-	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-				 ? 0x80 : 0));
-	/*
-	 * this isn't the same as continuing with a signal, but it will do
-	 * for normal use.  strace only continues with a signal if the
-	 * stopping signal is not SIGTRAP.  -brl
-	 */
-	if (current->exit_code) {
-		send_sig(current->exit_code, current, 1);
-		current->exit_code = 0;
-	}
+	int ret = 0;
+
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		ret = tracehook_report_syscall_entry(task_pt_regs(current));
+	return ret;
+}
+
+asmlinkage void syscall_trace_leave(void)
+{
+	if (test_thread_flag(TIF_SYSCALL_TRACE))
+		tracehook_report_syscall_exit(task_pt_regs(current), 0);
 }
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/setup.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,9 +54,6 @@
 void (*mach_halt)(void);
 void (*mach_power_off)(void);
 
-#ifdef CONFIG_M68000
-	#define CPU "MC68000"
-#endif
 #ifdef CONFIG_M68328
 	#define CPU "MC68328"
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/time.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,9 +50,8 @@
 
 	write_sequnlock(&xtime_lock);
 
-#ifndef CONFIG_SMP
 	update_process_times(user_mode(get_irq_regs()));
-#endif
+
 	return(IRQ_HANDLED);
 }
 #endif
@@ -61,13 +60,16 @@
 {
 	unsigned int year, mon, day, hour, min, sec;
 
-	if (mach_gettod)
+	if (mach_gettod) {
 		mach_gettod(&year, &mon, &day, &hour, &min, &sec);
-	else
-		year = mon = day = hour = min = sec = 0;
+		if ((year += 1900) < 1970)
+			year += 100;
+	} else {
+		year = 1970;
+		mon = day = 1;
+		hour = min = sec = 0;
+	}
 
-	if ((year += 1900) < 1970)
-		year += 100;
 
 	return  mktime(year, mon, day, hour, min, sec);
 }
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/kernel/traps.c linux-libre-2.6.37-gnu/arch/m68knommu/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -179,14 +179,16 @@
 
 void bad_super_trap(struct frame *fp)
 {
+	int vector = (fp->ptregs.vector >> 2) & 0xff;
+
 	console_verbose();
-	if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
+	if (vector < ARRAY_SIZE(vec_names))
 		printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
-			vec_names[(fp->ptregs.vector) >> 2],
+			vec_names[vector],
 			fp->ptregs.format);
 	else
 		printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
-			(fp->ptregs.vector) >> 2, 
+			vector,
 			fp->ptregs.format);
 	printk (KERN_WARNING "Current process id is %d\n", current->pid);
 	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
@@ -195,10 +197,11 @@
 asmlinkage void trap_c(struct frame *fp)
 {
 	int sig;
+	int vector = (fp->ptregs.vector >> 2) & 0xff;
 	siginfo_t info;
 
 	if (fp->ptregs.sr & PS_S) {
-		if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+		if (vector == VEC_TRACE) {
 			/* traced a trapping instruction */
 		} else
 			bad_super_trap(fp);
@@ -206,7 +209,7 @@
 	}
 
 	/* send the appropriate signal to the user program */
-	switch ((fp->ptregs.vector) >> 2) {
+	switch (vector) {
 	    case VEC_ADDRERR:
 		info.si_code = BUS_ADRALN;
 		sig = SIGBUS;
@@ -360,16 +363,3 @@
 	else
 		__show_stack(task, stack);
 }
-
-#ifdef CONFIG_M68KFPU_EMU
-asmlinkage void fpemu_signal(int signal, int code, void *addr)
-{
-	siginfo_t info;
-
-	info.si_signo = signal;
-	info.si_errno = 0;
-	info.si_code = code;
-	info.si_addr = addr;
-	force_sig_info(signal, &info, current);
-}
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 platform-$(CONFIG_M5307)	:= 5307
 platform-$(CONFIG_M532x)	:= 532x
 platform-$(CONFIG_M5407)	:= 5407
+platform-$(CONFIG_M548x)	:= 548x
 PLATFORM := $(platform-y)
 
 board-$(CONFIG_PILOT)		:= pilot
@@ -73,6 +74,7 @@
 cpuclass-$(CONFIG_M5307)	:= coldfire
 cpuclass-$(CONFIG_M532x)	:= coldfire
 cpuclass-$(CONFIG_M5407)	:= coldfire
+cpuclass-$(CONFIG_M548x)	:= coldfire
 cpuclass-$(CONFIG_M68328)	:= 68328
 cpuclass-$(CONFIG_M68EZ328)	:= 68328
 cpuclass-$(CONFIG_M68VZ328)	:= 68328
@@ -100,6 +102,7 @@
 cflags-$(CONFIG_M5307)		:= $(call cc-option,-m5307,-m5200)
 cflags-$(CONFIG_M532x)		:= $(call cc-option,-mcpu=532x,-m5307)
 cflags-$(CONFIG_M5407)		:= $(call cc-option,-m5407,-m5200)
+cflags-$(CONFIG_M548x)		:= $(call cc-option,-m5407,-m5200)
 cflags-$(CONFIG_M68328)		:= -m68000
 cflags-$(CONFIG_M68EZ328)	:= -m68000
 cflags-$(CONFIG_M68VZ328)	:= -m68000
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5206/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5206/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5206/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5206/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5206e/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5206e/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5206e/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5206e/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/520x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/520x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/520x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/520x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/523x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/523x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/523x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/523x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5249/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5249/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5249/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5249/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/config.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/config.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/config.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/config.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,8 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -148,9 +150,23 @@
 
 /***************************************************************************/
 
+/*
+ * Some 5272 based boards have the FEC ethernet diectly connected to
+ * an ethernet switch. In this case we need to use the fixed phy type,
+ * and we need to declare it early in boot.
+ */
+static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
+	.link	= 1,
+	.speed	= 100,
+	.duplex	= 0,
+};
+
+/***************************************************************************/
+
 static int __init init_BSP(void)
 {
 	m5272_uarts_init();
+	fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status);
 	platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/intc.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/intc.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/intc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/intc.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <asm/coldfire.h>
@@ -29,6 +30,10 @@
  * via a set of 4 "Interrupt Controller Registers" (ICR). There is a
  * loose mapping of vector number to register and internal bits, but
  * a table is the easiest and quickest way to map them.
+ *
+ * Note that the external interrupts are edge triggered (unlike the
+ * internal interrupt sources which are level triggered). Which means
+ * they also need acknowledgeing via acknowledge bits.
  */
 struct irqmap {
 	unsigned char	icr;
@@ -68,6 +73,11 @@
 	/*MCF_IRQ_SWTO*/	{ .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
 };
 
+/*
+ * The act of masking the interrupt also has a side effect of 'ack'ing
+ * an interrupt on this irq (for the external irqs). So this mask function
+ * is also an ack_mask function.
+ */
 static void intc_irq_mask(unsigned int irq)
 {
 	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
@@ -95,7 +105,9 @@
 		irq -= MCFINT_VECBASE;
 		if (intc_irqmap[irq].ack) {
 			u32 v;
-			v = 0xd << intc_irqmap[irq].index;
+			v = readl(MCF_MBAR + intc_irqmap[irq].icr);
+			v &= (0x7 << intc_irqmap[irq].index);
+			v |= (0x8 << intc_irqmap[irq].index);
 			writel(v, MCF_MBAR + intc_irqmap[irq].icr);
 		}
 	}
@@ -103,21 +115,47 @@
 
 static int intc_irq_set_type(unsigned int irq, unsigned int type)
 {
-	/* We can set the edge type here for external interrupts */
+	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
+		irq -= MCFINT_VECBASE;
+		if (intc_irqmap[irq].ack) {
+			u32 v;
+			v = readl(MCF_MBAR + MCFSIM_PITR);
+			if (type == IRQ_TYPE_EDGE_FALLING)
+				v &= ~(0x1 << (32 - irq));
+			else
+				v |= (0x1 << (32 - irq));
+			writel(v, MCF_MBAR + MCFSIM_PITR);
+		}
+	}
 	return 0;
 }
 
+/*
+ * Simple flow handler to deal with the external edge triggered interrupts.
+ * We need to be careful with the masking/acking due to the side effects
+ * of masking an interrupt.
+ */
+static void intc_external_irq(unsigned int irq, struct irq_desc *desc)
+{
+	kstat_incr_irqs_this_cpu(irq, desc);
+	desc->status |= IRQ_INPROGRESS;
+	desc->chip->ack(irq);
+	handle_IRQ_event(irq, desc->action);
+	desc->status &= ~IRQ_INPROGRESS;
+}
+
 static struct irq_chip intc_irq_chip = {
 	.name		= "CF-INTC",
 	.mask		= intc_irq_mask,
 	.unmask		= intc_irq_unmask,
+	.mask_ack	= intc_irq_mask,
 	.ack		= intc_irq_ack,
 	.set_type	= intc_irq_set_type,
 };
 
 void __init init_IRQ(void)
 {
-	int irq;
+	int irq, edge;
 
 	init_vectors();
 
@@ -128,11 +166,17 @@
 	writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
 
 	for (irq = 0; (irq < NR_IRQS); irq++) {
-		irq_desc[irq].status = IRQ_DISABLED;
-		irq_desc[irq].action = NULL;
-		irq_desc[irq].depth = 1;
-		irq_desc[irq].chip = &intc_irq_chip;
-		intc_irq_set_type(irq, 0);
+		set_irq_chip(irq, &intc_irq_chip);
+		edge = 0;
+		if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX))
+			edge = intc_irqmap[irq - MCFINT_VECBASE].ack;
+		if (edge) {
+			set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+			set_irq_handler(irq, intc_external_irq);
+		} else {
+			set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+			set_irq_handler(irq, handle_level_irq);
+		}
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5272/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5272/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/527x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/527x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/527x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/527x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/528x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/528x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/528x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/528x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs.  You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5307/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5307/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5307/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5307/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/532x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/532x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/532x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/532x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/5407/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/5407/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/5407/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/5407/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/548x/config.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/548x/config.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/548x/config.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/548x/config.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,115 @@
+/***************************************************************************/
+
+/*
+ *	linux/arch/m68knommu/platform/548x/config.c
+ *
+ *	Copyright (C) 2010, Philippe De Muyter <phdm@macqel.be>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/m548xsim.h>
+#include <asm/mcfuart.h>
+#include <asm/m548xgpt.h>
+
+/***************************************************************************/
+
+static struct mcf_platform_uart m548x_uart_platform[] = {
+	{
+		.mapbase	= MCF_MBAR + MCFUART_BASE1,
+		.irq		= 64 + 35,
+	},
+	{
+		.mapbase	= MCF_MBAR + MCFUART_BASE2,
+		.irq		= 64 + 34,
+	},
+	{
+		.mapbase	= MCF_MBAR + MCFUART_BASE3,
+		.irq		= 64 + 33,
+	},
+	{
+		.mapbase	= MCF_MBAR + MCFUART_BASE4,
+		.irq		= 64 + 32,
+	},
+};
+
+static struct platform_device m548x_uart = {
+	.name			= "mcfuart",
+	.id			= 0,
+	.dev.platform_data	= m548x_uart_platform,
+};
+
+static struct platform_device *m548x_devices[] __initdata = {
+	&m548x_uart,
+};
+
+
+/***************************************************************************/
+
+static void __init m548x_uart_init_line(int line, int irq)
+{
+	int rts_cts;
+
+	/* enable io pins */
+	switch (line) {
+	case 0:
+		rts_cts = 0; break;
+	case 1:
+		rts_cts = MCF_PAR_PSC_RTS_RTS; break;
+	case 2:
+		rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break;
+	case 3:
+		rts_cts = 0; break;
+	}
+	__raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD,
+						MCF_MBAR + MCF_PAR_PSC(line));
+}
+
+static void __init m548x_uarts_init(void)
+{
+	const int nrlines = ARRAY_SIZE(m548x_uart_platform);
+	int line;
+
+	for (line = 0; (line < nrlines); line++)
+		m548x_uart_init_line(line, m548x_uart_platform[line].irq);
+}
+
+/***************************************************************************/
+
+static void mcf548x_reset(void)
+{
+	/* disable interrupts and enable the watchdog */
+	asm("movew #0x2700, %sr\n");
+	__raw_writel(0, MCF_MBAR + MCF_GPT_GMS0);
+	__raw_writel(MCF_GPT_GCIR_CNT(1), MCF_MBAR + MCF_GPT_GCIR0);
+	__raw_writel(MCF_GPT_GMS_WDEN | MCF_GPT_GMS_CE | MCF_GPT_GMS_TMS(4),
+						MCF_MBAR + MCF_GPT_GMS0);
+}
+
+/***************************************************************************/
+
+void __init config_BSP(char *commandp, int size)
+{
+	mach_reset = mcf548x_reset;
+	m548x_uarts_init();
+}
+
+/***************************************************************************/
+
+static int __init init_BSP(void)
+{
+
+	platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices));
+	return 0;
+}
+
+arch_initcall(init_BSP);
+
+/***************************************************************************/
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/548x/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/548x/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/548x/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/548x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,18 @@
+#
+# Makefile for the m68knommu linux kernel.
+#
+
+#
+# If you want to play with the HW breakpoints then you will
+# need to add define this,  which will give you a stack backtrace
+# on the console port whenever a DBG interrupt occurs. You have to
+# set up you HW breakpoints to trigger a DBG interrupt:
+#
+# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
+# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+#
+
+asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
+
+obj-y := config.o
+
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/entry.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/entry.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -43,10 +43,10 @@
 	jra	ret_from_exception
 
 do_trace:
-	movel	#-ENOSYS,%sp@(PT_OFF_D0)	/* needed for strace*/
+	movel	#-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
 	subql	#4,%sp
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_enter
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
 	movel	%sp@(PT_OFF_ORIG_D0),%d1
@@ -57,10 +57,10 @@
 	lea	sys_call_table, %a0
 	jbsr	%a0@(%d1)
 
-1:	movel	%d0,%sp@(PT_OFF_D0)		/* save the return value */
+1:	movel	%d0,%sp@(PT_OFF_D0)	/* save the return value */
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_leave
 
 ret_from_signal:
 	RESTORE_SWITCH_STACK
@@ -71,16 +71,16 @@
 	SAVE_ALL
 
 	/* save top of frame*/
-	pea     %sp@
-	jbsr    set_esp0
-	addql   #4,%sp
+	pea	%sp@
+	jbsr	set_esp0
+	addql	#4,%sp
 
 	movel	%sp@(PT_OFF_ORIG_D0),%d0
 
 	movel	%sp,%d1			/* get thread_info pointer */
 	andl	#-THREAD_SIZE,%d1
 	movel	%d1,%a2
-	btst    #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
+	btst	#(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
 	jne	do_trace
 	cmpl	#NR_syscalls,%d0
 	jcc	badsys
@@ -88,10 +88,10 @@
 	lea	sys_call_table,%a0
 	movel	%a0@(%d0), %a0
 	jbsr	%a0@
-	movel	%d0,%sp@(PT_OFF_D0)		/* save the return value*/
+	movel	%d0,%sp@(PT_OFF_D0)	/* save the return value*/
 
 ret_from_exception:
-	btst	#5,%sp@(PT_OFF_SR)		/* check if returning to kernel*/
+	btst	#5,%sp@(PT_OFF_SR)	/* check if returning to kernel*/
 	jeq	Luser_return		/* if so, skip resched, signals*/
 
 Lkernel_return:
@@ -133,7 +133,7 @@
  */
 inthandler1:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -144,7 +144,7 @@
 
 inthandler2:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -155,7 +155,7 @@
 
 inthandler3:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -166,7 +166,7 @@
 
 inthandler4:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -177,7 +177,7 @@
 
 inthandler5:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -188,7 +188,7 @@
 
 inthandler6:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -199,7 +199,7 @@
 
 inthandler7:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
@@ -210,7 +210,7 @@
 
 inthandler:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and	#0x3ff, %d0
 
 	movel	%sp,%sp@-
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/head-de2.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/head-de2.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/head-de2.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/head-de2.S	2011-01-04 19:50:19.000000000 -0500
@@ -1,11 +1,5 @@
 
-#if defined(CONFIG_RAM32MB)
-#define	MEM_END	0x02000000	/* Memory size 32Mb */
-#elif defined(CONFIG_RAM16MB)
-#define	MEM_END	0x01000000	/* Memory size 16Mb */
-#else
 #define	MEM_END	0x00800000	/* Memory size 8Mb */
-#endif
 
 #undef CRT_DEBUG
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/head-ram.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/head-ram.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/head-ram.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/head-ram.S	2011-01-04 19:50:19.000000000 -0500
@@ -67,33 +67,6 @@
 	beq	pclp1
 #endif /* DEBUG */
 
-#ifdef CONFIG_RELOCATE
-	/* Copy me to RAM */
-	moveal	#__rom_start, %a0
-	moveal	#_stext, %a1
-	moveal	#_edata, %a2
-
-	/* Copy %a0 to %a1 until %a1 == %a2 */
-LD1:
-	movel	%a0@+, %d0
-	movel	%d0, %a1@+
-	cmpal	%a1, %a2
-	bhi	LD1
-	
-#ifdef DEBUG
-	moveq	#74, %d7		/* 'J' */
-	moveb	%d7,0xfffff907          /* No absolute addresses */
-pclp2:
-	movew	0xfffff906, %d7
-	andw	#0x2000, %d7
-	beq	pclp2
-#endif /* DEBUG */
-	/* jump into the RAM copy */
-	jmp     ram_jump
-ram_jump:
-
-#endif /* CONFIG_RELOCATE */
-
 #ifdef DEBUG
 	moveq	#82, %d7		/* 'R' */
 	moveb	%d7,0xfffff907          /* No absolute addresses */
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/ints.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/ints.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68328/ints.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68328/ints.c	2011-01-04 19:50:19.000000000 -0500
@@ -179,10 +179,8 @@
 	IMR = ~0;
 
 	for (i = 0; (i < NR_IRQS); i++) {
-		irq_desc[i].status = IRQ_DISABLED;
-		irq_desc[i].action = NULL;
-		irq_desc[i].depth = 1;
-		irq_desc[i].chip = &intc_irq_chip;
+		set_irq_chip(irq, &intc_irq_chip);
+		set_irq_handler(irq, handle_level_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68360/entry.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/68360/entry.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68360/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68360/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,7 @@
 	movel	#-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
 	subql	#4,%sp
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_enter
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
 	movel	%sp@(PT_OFF_ORIG_D0),%d1
@@ -56,7 +56,7 @@
 1:	movel	%d0,%sp@(PT_OFF_D0)	/* save the return value */
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_leave
 
 ret_from_signal:
 	RESTORE_SWITCH_STACK
@@ -71,7 +71,12 @@
 	jbsr	set_esp0
 	addql	#4,%sp
 
-	btst	#PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF)
+	movel	%sp@(PT_OFF_ORIG_D0),%d0
+
+	movel	%sp,%d1			/* get thread_info pointer */
+	andl	#-THREAD_SIZE,%d1
+	movel	%d1,%a2
+	btst	#(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
 	jne	do_trace
 	cmpl	#NR_syscalls,%d0
 	jcc	badsys
@@ -124,7 +129,7 @@
  */
 inthandler:
 	SAVE_ALL
-	movew	%sp@(PT_OFF_VECTOR), %d0
+	movew	%sp@(PT_OFF_FORMATVEC), %d0
 	and.l	#0x3ff, %d0
 	lsr.l   #0x02,  %d0
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68360/ints.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/68360/ints.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68360/ints.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68360/ints.c	2011-01-04 19:50:19.000000000 -0500
@@ -132,10 +132,8 @@
 	pquicc->intr_cimr = 0x00000000;
 
 	for (i = 0; (i < NR_IRQS); i++) {
-		irq_desc[i].status = IRQ_DISABLED;
-		irq_desc[i].action = NULL;
-		irq_desc[i].depth = 1;
-		irq_desc[i].chip = &intc_irq_chip;
+		set_irq_chip(irq, &intc_irq_chip);
+		set_irq_handler(irq, handle_level_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/68VZ328/config.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/68VZ328/config.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/68VZ328/config.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/68VZ328/config.c	2011-01-04 19:50:19.000000000 -0500
@@ -90,11 +90,6 @@
 	PDIQEG &= ~PD(1);
 	PDIRQEN |= PD(1);			/* IRQ enabled */
 
-#ifdef CONFIG_68328_SERIAL_UART2
-	/* Enable RXD TXD port bits to enable UART2 */
-	PJSEL &= ~(PJ(5) | PJ(4));
-#endif
-
 #ifdef CONFIG_INIT_LCD
 	/* initialize LCD controller */
 	LSSA = (long) screen_bits;
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/entry.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/entry.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,7 @@
 	movel	%d2,PT_OFF_D0(%sp)	/* on syscall entry */
 	subql	#4,%sp
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_enter
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
 	movel	%d3,%a0
@@ -96,7 +96,7 @@
 	movel	%d0,%sp@(PT_OFF_D0)		/* save the return value */
 	subql	#4,%sp			/* dummy return address */
 	SAVE_SWITCH_STACK
-	jbsr	syscall_trace
+	jbsr	syscall_trace_leave
 
 ret_from_signal:
 	RESTORE_SWITCH_STACK
@@ -112,7 +112,7 @@
 	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
 	movel	%d1,%a0
 	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
-	andl	#_TIF_NEED_RESCHED,%d1
+	andl	#(1<<TIF_NEED_RESCHED),%d1
 	jeq	Lkernel_return
 
 	movel	%a0@(TI_PREEMPTCOUNT),%d1
@@ -136,7 +136,7 @@
 	andl	#-THREAD_SIZE,%d1	/* at base of kernel stack */
 	movel	%d1,%a0
 	movel	%a0@(TI_FLAGS),%d1	/* get thread_info->flags */
-	andl	#_TIF_WORK_MASK,%d1
+	andl	#0xefff,%d1
 	jne	Lwork_to_do		/* still work to do */
 
 Lreturn:
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/head.S linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/head.S
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <asm/coldfire.h>
 #include <asm/mcfcache.h>
 #include <asm/mcfsim.h>
+#include <asm/thread_info.h>
 
 /*****************************************************************************/
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc-2.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc-2.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc-2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc-2.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,11 @@
 /*
- * intc-1.c
+ * intc-2.c
+ *
+ * General interrupt controller code for the many ColdFire cores that use
+ * interrupt controllers with 63 interrupt sources, organized as 56 fully-
+ * programmable + 7 fixed-level interrupt sources. This includes the 523x
+ * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such
+ * controllers, and the 547x and 548x families which have only one of them.
  *
  * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
  *
@@ -19,21 +25,37 @@
 #include <asm/traps.h>
 
 /*
- *	Each vector needs a unique priority and level asscoiated with it.
+ * Bit definitions for the ICR family of registers.
+ */
+#define MCFSIM_ICR_LEVEL(l)	((l)<<3)	/* Level l intr */
+#define MCFSIM_ICR_PRI(p)	(p)		/* Priority p intr */
+
+/*
+ *	Each vector needs a unique priority and level associated with it.
  *	We don't really care so much what they are, we don't rely on the
- *	tranditional priority interrupt scheme of the m68k/ColdFire.
+ *	traditional priority interrupt scheme of the m68k/ColdFire.
  */
-static u8 intc_intpri = 0x36;
+static u8 intc_intpri = MCFSIM_ICR_LEVEL(6) | MCFSIM_ICR_PRI(6);
+
+#ifdef MCFICM_INTC1
+#define NR_VECS	128
+#else
+#define NR_VECS	64
+#endif
 
 static void intc_irq_mask(unsigned int irq)
 {
-	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
 		unsigned long imraddr;
 		u32 val, imrbit;
 
 		irq -= MCFINT_VECBASE;
 		imraddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
 		imraddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+		imraddr += MCFICM_INTC0;
+#endif
 		imraddr += (irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL;
 		imrbit = 0x1 << (irq & 0x1f);
 
@@ -44,13 +66,17 @@
 
 static void intc_irq_unmask(unsigned int irq)
 {
-	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + 128)) {
+	if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECBASE + NR_VECS)) {
 		unsigned long intaddr, imraddr, icraddr;
 		u32 val, imrbit;
 
 		irq -= MCFINT_VECBASE;
 		intaddr = MCF_IPSBAR;
+#ifdef MCFICM_INTC1
 		intaddr += (irq & 0x40) ? MCFICM_INTC1 : MCFICM_INTC0;
+#else
+		intaddr += MCFICM_INTC0;
+#endif
 		imraddr = intaddr + ((irq & 0x20) ? MCFINTC_IMRH : MCFINTC_IMRL);
 		icraddr = intaddr + MCFINTC_ICR0 + (irq & 0x3f);
 		imrbit = 0x1 << (irq & 0x1f);
@@ -67,10 +93,16 @@
 	}
 }
 
+static int intc_irq_set_type(unsigned int irq, unsigned int type)
+{
+	return 0;
+}
+
 static struct irq_chip intc_irq_chip = {
 	.name		= "CF-INTC",
 	.mask		= intc_irq_mask,
 	.unmask		= intc_irq_unmask,
+	.set_type	= intc_irq_set_type,
 };
 
 void __init init_IRQ(void)
@@ -81,13 +113,14 @@
 
 	/* Mask all interrupt sources */
 	__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+#ifdef MCFICM_INTC1
 	__raw_writel(0x1, MCF_IPSBAR + MCFICM_INTC1 + MCFINTC_IMRL);
+#endif
 
 	for (irq = 0; (irq < NR_IRQS); irq++) {
-		irq_desc[irq].status = IRQ_DISABLED;
-		irq_desc[irq].action = NULL;
-		irq_desc[irq].depth = 1;
-		irq_desc[irq].chip = &intc_irq_chip;
+		set_irq_chip(irq, &intc_irq_chip);
+		set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+		set_irq_handler(irq, handle_level_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc.c	2011-01-04 19:50:19.000000000 -0500
@@ -143,11 +143,9 @@
 	mcf_maskimr(0xffffffff);
 
 	for (irq = 0; (irq < NR_IRQS); irq++) {
-		irq_desc[irq].status = IRQ_DISABLED;
-		irq_desc[irq].action = NULL;
-		irq_desc[irq].depth = 1;
-		irq_desc[irq].chip = &intc_irq_chip;
-		intc_irq_set_type(irq, 0);
+		set_irq_chip(irq, &intc_irq_chip);
+		set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+		set_irq_handler(irq, handle_level_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc-simr.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc-simr.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/intc-simr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/intc-simr.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,8 @@
 /*
  * intc-simr.c
  *
+ * Interrupt controller code for the ColdFire 5208, 5207 & 532x parts.
+ *
  * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -68,11 +70,9 @@
 		__raw_writeb(0xff, MCFINTC1_SIMR);
 
 	for (irq = 0; (irq < NR_IRQS); irq++) {
-		irq_desc[irq].status = IRQ_DISABLED;
-		irq_desc[irq].action = NULL;
-		irq_desc[irq].depth = 1;
-		irq_desc[irq].chip = &intc_irq_chip;
-		intc_irq_set_type(irq, 0);
+		set_irq_chip(irq, &intc_irq_chip);
+		set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
+		set_irq_handler(irq, handle_level_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/Makefile linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/Makefile
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 # on the console port whenever a DBG interrupt occurs. You have to
 # set up you HW breakpoints to trigger a DBG interrupt:
 #
-# EXTRA_CFLAGS += -DTRAP_DBG_INTERRUPT
-# EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT
+# ccflags-y := -DTRAP_DBG_INTERRUPT
+# asflags-y := -DTRAP_DBG_INTERRUPT
 #
 
 asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
@@ -26,6 +26,7 @@
 obj-$(CONFIG_M5307)	+= timers.o intc.o
 obj-$(CONFIG_M532x)	+= timers.o intc-simr.o
 obj-$(CONFIG_M5407)	+= timers.o intc.o
+obj-$(CONFIG_M548x)	+= sltimers.o intc-2.o
 
 obj-y			+= pinmux.o gpio.o
 extra-y := head.o
diff -druN linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/sltimers.c linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/sltimers.c
--- linux-libre-2.6.36-gnu/arch/m68knommu/platform/coldfire/sltimers.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/m68knommu/platform/coldfire/sltimers.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,145 @@
+/***************************************************************************/
+
+/*
+ *	sltimers.c -- generic ColdFire slice timer support.
+ *
+ *	Copyright (C) 2009-2010, Philippe De Muyter <phdm@macqel.be>
+ *	based on
+ *	timers.c -- generic ColdFire hardware timer support.
+ *	Copyright (C) 1999-2008, Greg Ungerer <gerg@snapgear.com>
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <asm/io.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfslt.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+#ifdef CONFIG_HIGHPROFILE
+
+/*
+ *	By default use Slice Timer 1 as the profiler clock timer.
+ */
+#define	PA(a)	(MCF_MBAR + MCFSLT_TIMER1 + (a))
+
+/*
+ *	Choose a reasonably fast profile timer. Make it an odd value to
+ *	try and get good coverage of kernel operations.
+ */
+#define	PROFILEHZ	1013
+
+irqreturn_t mcfslt_profile_tick(int irq, void *dummy)
+{
+	/* Reset Slice Timer 1 */
+	__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, PA(MCFSLT_SSR));
+	if (current->pid)
+		profile_tick(CPU_PROFILING);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction mcfslt_profile_irq = {
+	.name	 = "profile timer",
+	.flags	 = IRQF_DISABLED | IRQF_TIMER,
+	.handler = mcfslt_profile_tick,
+};
+
+void mcfslt_profile_init(void)
+{
+	printk(KERN_INFO "PROFILE: lodging TIMER 1 @ %dHz as profile timer\n",
+	       PROFILEHZ);
+
+	setup_irq(MCF_IRQ_PROFILER, &mcfslt_profile_irq);
+
+	/* Set up TIMER 2 as high speed profile clock */
+	__raw_writel(MCF_BUSCLK / PROFILEHZ - 1, PA(MCFSLT_STCNT));
+	__raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+								PA(MCFSLT_SCR));
+
+}
+
+#endif	/* CONFIG_HIGHPROFILE */
+
+/***************************************************************************/
+
+/*
+ *	By default use Slice Timer 0 as the system clock timer.
+ */
+#define	TA(a)	(MCF_MBAR + MCFSLT_TIMER0 + (a))
+
+static u32 mcfslt_cycles_per_jiffy;
+static u32 mcfslt_cnt;
+
+static irqreturn_t mcfslt_tick(int irq, void *dummy)
+{
+	/* Reset Slice Timer 0 */
+	__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
+	mcfslt_cnt += mcfslt_cycles_per_jiffy;
+	return arch_timer_interrupt(irq, dummy);
+}
+
+static struct irqaction mcfslt_timer_irq = {
+	.name	 = "timer",
+	.flags	 = IRQF_DISABLED | IRQF_TIMER,
+	.handler = mcfslt_tick,
+};
+
+static cycle_t mcfslt_read_clk(struct clocksource *cs)
+{
+	unsigned long flags;
+	u32 cycles;
+	u16 scnt;
+
+	local_irq_save(flags);
+	scnt = __raw_readl(TA(MCFSLT_SCNT));
+	cycles = mcfslt_cnt;
+	local_irq_restore(flags);
+
+	/* substract because slice timers count down */
+	return cycles - scnt;
+}
+
+static struct clocksource mcfslt_clk = {
+	.name	= "slt",
+	.rating	= 250,
+	.read	= mcfslt_read_clk,
+	.shift	= 20,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void hw_timer_init(void)
+{
+	mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
+	/*
+	 *	The coldfire slice timer (SLT) runs from STCNT to 0 included,
+	 *	then STCNT again and so on.  It counts thus actually
+	 *	STCNT + 1 steps for 1 tick, not STCNT.  So if you want
+	 *	n cycles, initialize STCNT with n - 1.
+	 */
+	__raw_writel(mcfslt_cycles_per_jiffy - 1, TA(MCFSLT_STCNT));
+	__raw_writel(MCFSLT_SCR_RUN | MCFSLT_SCR_IEN | MCFSLT_SCR_TEN,
+								TA(MCFSLT_SCR));
+	/* initialize mcfslt_cnt knowing that slice timers count down */
+	mcfslt_cnt = mcfslt_cycles_per_jiffy;
+
+	setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
+
+	mcfslt_clk.mult = clocksource_hz2mult(MCF_BUSCLK, mcfslt_clk.shift);
+	clocksource_register(&mcfslt_clk);
+
+#ifdef CONFIG_HIGHPROFILE
+	mcfslt_profile_init();
+#endif
+}
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/boot/dts/system.dts linux-libre-2.6.37-gnu/arch/microblaze/boot/dts/system.dts
--- linux-libre-2.6.36-gnu/arch/microblaze/boot/dts/system.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/boot/dts/system.dts	2011-01-04 19:50:19.000000000 -0500
@@ -85,6 +85,7 @@
 			xlnx,dynamic-bus-sizing = <0x1>;
 			xlnx,edge-is-positive = <0x1>;
 			xlnx,family = "virtex5";
+			xlnx,endianness = <0x1>;
 			xlnx,fpu-exception = <0x1>;
 			xlnx,fsl-data-size = <0x20>;
 			xlnx,fsl-exception = <0x0>;
@@ -218,6 +219,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,compound";
+			ranges ;
 			ethernet@81c00000 {
 				compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
 				device_type = "network";
@@ -332,6 +334,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,mpmc-4.02.a";
+			ranges ;
 			PIM3: sdma@84600180 {
 				compatible = "xlnx,ll-dma-1.00.a";
 				interrupt-parent = <&xps_intc_0>;
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/byteorder.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/byteorder.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/byteorder.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/byteorder.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,10 @@
 #ifndef _ASM_MICROBLAZE_BYTEORDER_H
 #define _ASM_MICROBLAZE_BYTEORDER_H
 
+#ifdef __MICROBLAZEEL__
+#include <linux/byteorder/little_endian.h>
+#else
 #include <linux/byteorder/big_endian.h>
+#endif
 
 #endif /* _ASM_MICROBLAZE_BYTEORDER_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/checksum.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/checksum.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/checksum.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/checksum.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,8 +24,13 @@
 		"addc %0, %0, %3\n\t"
 		"addc %0, %0, r0\n\t"
 		: "+&d" (sum)
-		: "d" (saddr), "d" (daddr), "d" (len + proto));
-
+		: "d" (saddr), "d" (daddr),
+#ifdef __MICROBLAZEEL__
+	"d" ((len + proto) << 8)
+#else
+	"d" (len + proto)
+#endif
+);
 	return sum;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/cpuinfo.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/cpuinfo.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/cpuinfo.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/cpuinfo.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,7 @@
 	u32 use_exc;
 	u32 ver_code;
 	u32 mmu;
+	u32 endian;
 
 	/* CPU caches */
 	u32 use_icache;
@@ -76,7 +77,6 @@
 	u32 num_rd_brk;
 	u32 num_wr_brk;
 	u32 cpu_clock_freq; /* store real freq of cpu */
-	u32 freq_div_hz; /* store freq/HZ */
 
 	/* FPGA family */
 	u32 fpga_family_code;
@@ -97,7 +97,8 @@
 static inline unsigned int fcpu(struct device_node *cpu, char *n)
 {
 	int *val;
-	return (val = (int *) of_get_property(cpu, n, NULL)) ? *val : 0;
+	return (val = (int *) of_get_property(cpu, n, NULL)) ?
+							be32_to_cpup(val) : 0;
 }
 
 #endif /* _ASM_MICROBLAZE_CPUINFO_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/elf.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -71,7 +71,7 @@
 
 #define ELF_ET_DYN_BASE         (0x08000000)
 
-#ifdef __LITTLE_ENDIAN__
+#ifdef __MICROBLAZEEL__
 #define ELF_DATA	ELFDATA2LSB
 #else
 #define ELF_DATA	ELFDATA2MSB
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/gpio.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/gpio.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,12 +38,9 @@
 	return __gpio_cansleep(gpio);
 }
 
-/*
- * Not implemented, yet.
- */
 static inline int gpio_to_irq(unsigned int gpio)
 {
-	return -ENOSYS;
+	return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/io.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -243,6 +243,8 @@
 #define out_8(a, v) __raw_writeb((v), (a))
 #define in_8(a) __raw_readb(a)
 
+#define mmiowb()
+
 #define ioport_map(port, nr)	((void __iomem *)(port))
 #define ioport_unmap(addr)
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,103 +9,114 @@
 #ifndef _ASM_MICROBLAZE_IRQFLAGS_H
 #define _ASM_MICROBLAZE_IRQFLAGS_H
 
-#include <linux/irqflags.h>
+#include <linux/types.h>
 #include <asm/registers.h>
 
-# if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-
-# define raw_local_irq_save(flags)			\
-	do {						\
-		asm volatile ("	msrclr %0, %1;		\
-				nop;"			\
-				: "=r"(flags)		\
-				: "i"(MSR_IE)		\
-				: "memory");		\
-	} while (0)
+#ifdef CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
-# define raw_local_irq_disable()			\
-	do {						\
-		asm volatile ("	msrclr r0, %0;		\
-				nop;"			\
-				:			\
-				: "i"(MSR_IE)		\
-				: "memory");		\
-	} while (0)
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	asm volatile("	msrclr %0, %1	\n"
+		     "	nop		\n"
+		     : "=r"(flags)
+		     : "i"(MSR_IE)
+		     : "memory");
+	return flags;
+}
 
-# define raw_local_irq_enable()				\
-	do {						\
-		asm volatile ("	msrset	r0, %0;		\
-				nop;"			\
-				:			\
-				: "i"(MSR_IE)		\
-				: "memory");		\
-	} while (0)
+static inline void arch_local_irq_disable(void)
+{
+	/* this uses r0 without declaring it - is that correct? */
+	asm volatile("	msrclr r0, %0	\n"
+		     "	nop		\n"
+		     :
+		     : "i"(MSR_IE)
+		     : "memory");
+}
 
-# else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
+static inline void arch_local_irq_enable(void)
+{
+	/* this uses r0 without declaring it - is that correct? */
+	asm volatile("	msrset	r0, %0	\n"
+		     "	nop		\n"
+		     :
+		     : "i"(MSR_IE)
+		     : "memory");
+}
 
-# define raw_local_irq_save(flags)				\
-	do {							\
-		register unsigned tmp;				\
-		asm volatile ("	mfs	%0, rmsr;		\
-				nop;				\
-				andi	%1, %0, %2;		\
-				mts	rmsr, %1;		\
-				nop;"				\
-				: "=r"(flags), "=r" (tmp)	\
-				: "i"(~MSR_IE)			\
-				: "memory");			\
-	} while (0)
+#else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
-# define raw_local_irq_disable()				\
-	do {							\
-		register unsigned tmp;				\
-		asm volatile ("	mfs	%0, rmsr;		\
-				nop;				\
-				andi	%0, %0, %1;		\
-				mts	rmsr, %0;		\
-				nop;"			\
-				: "=r"(tmp)			\
-				: "i"(~MSR_IE)			\
-				: "memory");			\
-	} while (0)
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags, tmp;
+	asm volatile ("	mfs	%0, rmsr	\n"
+		      "	nop			\n"
+		      "	andi	%1, %0, %2	\n"
+		      "	mts	rmsr, %1	\n"
+		      "	nop			\n"
+		      : "=r"(flags), "=r"(tmp)
+		      : "i"(~MSR_IE)
+		      : "memory");
+	return flags;
+}
 
-# define raw_local_irq_enable()					\
-	do {							\
-		register unsigned tmp;				\
-		asm volatile ("	mfs	%0, rmsr;		\
-				nop;				\
-				ori	%0, %0, %1;		\
-				mts	rmsr, %0;		\
-				nop;"				\
-				: "=r"(tmp)			\
-				: "i"(MSR_IE)			\
-				: "memory");			\
-	} while (0)
+static inline void arch_local_irq_disable(void)
+{
+	unsigned long tmp;
+	asm volatile("	mfs	%0, rmsr	\n"
+		     "	nop			\n"
+		     "	andi	%0, %0, %1	\n"
+		     "	mts	rmsr, %0	\n"
+		     "	nop			\n"
+		     : "=r"(tmp)
+		     : "i"(~MSR_IE)
+		     : "memory");
+}
 
-# endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
+static inline void arch_local_irq_enable(void)
+{
+	unsigned long tmp;
+	asm volatile("	mfs	%0, rmsr	\n"
+		     "	nop			\n"
+		     "	ori	%0, %0, %1	\n"
+		     "	mts	rmsr, %0	\n"
+		     "	nop			\n"
+		     : "=r"(tmp)
+		     : "i"(MSR_IE)
+		     : "memory");
+}
 
-#define raw_local_irq_restore(flags)				\
-	do {							\
-		asm volatile ("	mts	rmsr, %0;		\
-				nop;"				\
-				:				\
-				: "r"(flags)			\
-				: "memory");			\
-	} while (0)
+#endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
-static inline unsigned long get_msr(void)
+static inline unsigned long arch_local_save_flags(void)
 {
 	unsigned long flags;
-	asm volatile ("	mfs	%0, rmsr;	\
-			nop;"			\
-			: "=r"(flags)		\
-			:			\
-			: "memory");		\
+	asm volatile("	mfs	%0, rmsr	\n"
+		     "	nop			\n"
+		     : "=r"(flags)
+		     :
+		     : "memory");
 	return flags;
 }
 
-#define raw_local_save_flags(flags)	((flags) = get_msr())
-#define raw_irqs_disabled()		((get_msr() & MSR_IE) == 0)
-#define raw_irqs_disabled_flags(flags)	((flags & MSR_IE) == 0)
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("	mts	rmsr, %0	\n"
+		     "	nop			\n"
+		     :
+		     : "r"(flags)
+		     : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & MSR_IE) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #endif /* _ASM_MICROBLAZE_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/memblock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,9 +9,6 @@
 #ifndef _ASM_MICROBLAZE_MEMBLOCK_H
 #define _ASM_MICROBLAZE_MEMBLOCK_H
 
-/* MEMBLOCK limit is OFF */
-#define MEMBLOCK_REAL_LIMIT	0xFFFFFFFF
-
 #endif /* _ASM_MICROBLAZE_MEMBLOCK_H */
 
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/page.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/page.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/page.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/page.h	2011-01-04 19:50:19.000000000 -0500
@@ -205,9 +205,6 @@
 #define TOPHYS(addr)  __virt_to_phys(addr)
 
 #ifdef CONFIG_MMU
-#ifdef CONFIG_CONTIGUOUS_PAGE_ALLOC
-#define WANT_PAGE_VIRTUAL 1 /* page alloc 2 relies on this */
-#endif
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pci.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pci.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -165,5 +165,7 @@
 static inline void __init xilinx_pci_init(void) { return; }
 #endif
 
+#include <asm-generic/pci-dma-compat.h>
+
 #endif	/* __KERNEL__ */
 #endif /* __ASM_MICROBLAZE_PCI_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pgalloc.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pgalloc.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pgalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pgalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -165,7 +165,8 @@
 
 #define __pte_free_tlb(tlb, pte, addr)	pte_free((tlb)->mm, (pte))
 
-#define pmd_populate(mm, pmd, pte)	(pmd_val(*(pmd)) = page_address(pte))
+#define pmd_populate(mm, pmd, pte) \
+			(pmd_val(*(pmd)) = (unsigned long)page_address(pte))
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 		(pmd_val(*(pmd)) = (unsigned long) (pte))
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,13 @@
 
 #define pgprot_noncached_wc(prot)	prot
 
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define	VMALLOC_START	0
+#define	VMALLOC_END	0xffffffff
+
 #else /* CONFIG_MMU */
 
 #include <asm-generic/4level-fixup.h>
@@ -497,12 +504,9 @@
 #define pte_offset_kernel(dir, addr)	\
 	((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir, addr)		\
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr)	\
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+	((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
 
-#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
+#define pte_unmap(pte)		kunmap_atomic(pte)
 
 /* Encode and decode a nonlinear file mapping entry */
 #define PTE_FILE_MAX_BITS	29
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/prom.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/prom.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/prom.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/prom.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,7 @@
 
 /* Other Prototypes */
 extern int early_uartlite_console(void);
+extern int early_uart16550_console(void);
 
 #ifdef CONFIG_PCI
 /*
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pvr.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pvr.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/pvr.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/pvr.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,9 @@
 #define PVR0_USE_EXC_MASK		0x04000000
 #define PVR0_USE_ICACHE_MASK		0x02000000
 #define PVR0_USE_DCACHE_MASK		0x01000000
-#define PVR0_USE_MMU			0x00800000	/* new */
+#define PVR0_USE_MMU			0x00800000
+#define PVR0_USE_BTC			0x00400000
+#define PVR0_ENDI			0x00200000
 #define PVR0_VERSION_MASK		0x0000FF00
 #define PVR0_USER1_MASK			0x000000FF
 
@@ -38,9 +40,9 @@
 #define PVR1_USER2_MASK			0xFFFFFFFF
 
 /* Configuration PVR masks */
-#define PVR2_D_OPB_MASK			0x80000000
+#define PVR2_D_OPB_MASK			0x80000000 /* or AXI */
 #define PVR2_D_LMB_MASK			0x40000000
-#define PVR2_I_OPB_MASK			0x20000000
+#define PVR2_I_OPB_MASK			0x20000000 /* or AXI */
 #define PVR2_I_LMB_MASK			0x10000000
 #define PVR2_INTERRUPT_IS_EDGE_MASK	0x08000000
 #define PVR2_EDGE_IS_POSITIVE_MASK	0x04000000
@@ -63,8 +65,8 @@
 #define PVR2_OPCODE_0x0_ILL_MASK	0x00000040
 #define PVR2_UNALIGNED_EXC_MASK		0x00000020
 #define PVR2_ILL_OPCODE_EXC_MASK	0x00000010
-#define PVR2_IOPB_BUS_EXC_MASK		0x00000008
-#define PVR2_DOPB_BUS_EXC_MASK		0x00000004
+#define PVR2_IOPB_BUS_EXC_MASK		0x00000008 /* or AXI */
+#define PVR2_DOPB_BUS_EXC_MASK		0x00000004 /* or AXI */
 #define PVR2_DIV_ZERO_EXC_MASK		0x00000002
 #define PVR2_FPU_EXC_MASK		0x00000001
 
@@ -208,6 +210,8 @@
 #define PVR_MMU_TLB_ACCESS(pvr)	(pvr.pvr[11] & PVR11_MMU_TLB_ACCESS)
 #define PVR_MMU_ZONES(pvr)	(pvr.pvr[11] & PVR11_MMU_ZONES)
 
+/* endian */
+#define PVR_ENDIAN(pvr)	(pvr.pvr[0] & PVR0_ENDI)
 
 int cpu_has_pvr(void);
 void get_pvr(struct pvr_s *pvr);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/seccomp.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/seccomp.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/seccomp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/seccomp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+#ifndef _ASM_MICROBLAZE_SECCOMP_H
+#define _ASM_MICROBLAZE_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read		__NR_read
+#define __NR_seccomp_write		__NR_write
+#define __NR_seccomp_exit		__NR_exit
+#define __NR_seccomp_sigreturn		__NR_sigreturn
+
+#define __NR_seccomp_read_32		__NR_read
+#define __NR_seccomp_write_32		__NR_write
+#define __NR_seccomp_exit_32		__NR_exit
+#define __NR_seccomp_sigreturn_32	__NR_sigreturn
+
+#endif	/* _ASM_MICROBLAZE_SECCOMP_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/setup.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/setup.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/setup.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/setup.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,12 @@
 int setup_early_printk(char *opt);
 void disable_early_printk(void);
 
+#if defined(CONFIG_EARLY_PRINTK)
+#define eprintk early_printk
+#else
+#define eprintk printk
+#endif
+
 void heartbeat(void);
 void setup_heartbeat(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/thread_info.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/thread_info.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/thread_info.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/thread_info.h	2011-01-04 19:50:19.000000000 -0500
@@ -127,23 +127,19 @@
 #define TIF_SECCOMP		10      /* secure computing */
 #define TIF_FREEZE		14	/* Freezing for suspend */
 
-/* FIXME change in entry.S */
-#define TIF_KERNEL_TRACE	8	/* kernel trace active */
-
 /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_POLLING_NRFLAG	16
 
-#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
-#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
-#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
-#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
-#define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
-#define _TIF_IRET		(1<<TIF_IRET)
-#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FREEZE		(1<<TIF_FREEZE)
+#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP		(1 << TIF_SINGLESTEP)
+#define _TIF_IRET		(1 << TIF_IRET)
+#define _TIF_POLLING_NRFLAG	(1 << TIF_POLLING_NRFLAG)
+#define _TIF_FREEZE		(1 << TIF_FREEZE)
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
-#define _TIF_KERNEL_TRACE	(1 << TIF_KERNEL_TRACE)
 
 /* work to do in syscall trace */
 #define _TIF_WORK_SYSCALL_MASK  (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/unaligned.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/unaligned.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/unaligned.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/unaligned.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,12 +12,18 @@
 
 # ifdef __KERNEL__
 
-# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/be_byteshift.h>
 # include <linux/unaligned/le_byteshift.h>
 # include <linux/unaligned/generic.h>
 
-# define get_unaligned	__get_unaligned_be
-# define put_unaligned	__put_unaligned_be
+
+#  ifdef __MICROBLAZEEL__
+#   define get_unaligned	__get_unaligned_le
+#   define put_unaligned	__put_unaligned_le
+#  else
+#   define get_unaligned	__get_unaligned_be
+#   define put_unaligned	__put_unaligned_be
+#  endif
 
 # endif	/* __KERNEL__ */
 #endif /* _ASM_MICROBLAZE_UNALIGNED_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/include/asm/unistd.h linux-libre-2.6.37-gnu/arch/microblaze/include/asm/unistd.h
--- linux-libre-2.6.36-gnu/arch/microblaze/include/asm/unistd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/include/asm/unistd.h	2011-01-04 19:50:19.000000000 -0500
@@ -383,8 +383,11 @@
 #define __NR_rt_tgsigqueueinfo	365 /* new */
 #define __NR_perf_event_open	366 /* new */
 #define __NR_recvmmsg		367 /* new */
+#define __NR_fanotify_init	368
+#define __NR_fanotify_mark	369
+#define __NR_prlimit64		370
 
-#define __NR_syscalls		368
+#define __NR_syscalls		371
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/Kconfig linux-libre-2.6.37-gnu/arch/microblaze/Kconfig
--- linux-libre-2.6.36-gnu/arch/microblaze/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,3 @@
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-
-mainmenu "Linux/Microblaze Kernel Configuration"
-
 config MICROBLAZE
 	def_bool y
 	select HAVE_MEMBLOCK
@@ -121,6 +116,23 @@
 	  Set this to have arguments from the default kernel command string
 	  override those passed by the boot loader.
 
+config SECCOMP
+	bool "Enable seccomp to safely compute untrusted bytecode"
+	depends on PROC_FS
+	default y
+	help
+	  This kernel feature is useful for number crunching applications
+	  that may need to compute untrusted bytecode during their
+	  execution. By using pipes or other transports made available to
+	  the process as file descriptors supporting the read/write
+	  syscalls, it's possible to isolate those applications in
+	  their own address space using seccomp. Once seccomp is
+	  enabled via /proc/<pid>/seccomp, it cannot be disabled
+	  and the task is only allowed to execute a few safe syscalls
+	  defined by each seccomp mode.
+
+	  If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
 menu "Advanced setup"
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/Kconfig.debug linux-libre-2.6.37-gnu/arch/microblaze/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/microblaze/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,7 @@
 
 config EARLY_PRINTK
 	bool "Early printk function for kernel"
-	depends on SERIAL_UARTLITE_CONSOLE
+	depends on SERIAL_UARTLITE_CONSOLE || SERIAL_8250_CONSOLE
 	default n
 	help
 	  This option turns on/off early printk messages to console.
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,8 @@
 	{"7.20.c", 0x0e},
 	{"7.20.d", 0x0f},
 	{"7.30.a", 0x10},
+	{"7.30.b", 0x11},
+	{"8.00.a", 0x12},
 	{NULL, 0},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,6 +72,7 @@
 	CI(pvr_user2, USER2);
 
 	CI(mmu, USE_MMU);
+	CI(endian, ENDIAN);
 
 	CI(use_icache, USE_ICACHE);
 	CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo-static.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo-static.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/cpuinfo-static.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/cpuinfo-static.c	2011-01-04 19:50:19.000000000 -0500
@@ -119,6 +119,7 @@
 	ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
 
 	ci->mmu = fcpu(cpu, "xlnx,use-mmu");
+	ci->endian = fcpu(cpu, "xlnx,endianness");
 
 	ci->ver_code = 0;
 	ci->fpga_family_code = 0;
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/mb.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/mb.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/mb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/mb.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,11 +51,12 @@
 	count = seq_printf(m,
 			"CPU-Family:	MicroBlaze\n"
 			"FPGA-Arch:	%s\n"
-			"CPU-Ver:	%s\n"
+			"CPU-Ver:	%s, %s endian\n"
 			"CPU-MHz:	%d.%02d\n"
 			"BogoMips:	%lu.%02lu\n",
 			fpga_family,
 			cpu_ver,
+			cpuinfo.endian ? "little" : "big",
 			cpuinfo.cpu_clock_freq /
 			1000000,
 			cpuinfo.cpu_clock_freq %
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/pvr.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/pvr.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/cpu/pvr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/cpu/pvr.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,7 @@
 	register unsigned tmp __asm__("r3");			\
 	tmp = 0x0;	/* Prevent warning about unused */	\
 	__asm__ __volatile__ (					\
-			".byte 0x94,0x60,0xa0, " #pvrid "\n\t"	\
+			"mfs	%0, rpvr" #pvrid ";"	\
 			: "=r" (tmp) : : "memory"); 		\
 	val = tmp;						\
 }
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/early_printk.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/early_printk.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/early_printk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/early_printk.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,8 @@
 static u32 early_console_initialized;
 static u32 base_addr;
 
-static void early_printk_putc(char c)
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static void early_printk_uartlite_putc(char c)
 {
 	/*
 	 * Limit how many times we'll spin waiting for TX FIFO status.
@@ -45,25 +46,70 @@
 		out_be32(base_addr + 4, c & 0xff);
 }
 
-static void early_printk_write(struct console *unused,
+static void early_printk_uartlite_write(struct console *unused,
 					const char *s, unsigned n)
 {
 	while (*s && n-- > 0) {
-		early_printk_putc(*s);
+		early_printk_uartlite_putc(*s);
 		if (*s == '\n')
-			early_printk_putc('\r');
+			early_printk_uartlite_putc('\r');
 		s++;
 	}
 }
 
-static struct console early_serial_console = {
+static struct console early_serial_uartlite_console = {
 	.name = "earlyser",
-	.write = early_printk_write,
+	.write = early_printk_uartlite_write,
 	.flags = CON_PRINTBUFFER,
 	.index = -1,
 };
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
 
-static struct console *early_console = &early_serial_console;
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+static void early_printk_uart16550_putc(char c)
+{
+	/*
+	 * Limit how many times we'll spin waiting for TX FIFO status.
+	 * This will prevent lockups if the base address is incorrectly
+	 * set, or any other issue on the UARTLITE.
+	 * This limit is pretty arbitrary, unless we are at about 10 baud
+	 * we'll never timeout on a working UART.
+	 */
+
+	#define UART_LSR_TEMT	0x40 /* Transmitter empty */
+	#define UART_LSR_THRE	0x20 /* Transmit-hold-register empty */
+	#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+	unsigned retries = 10000;
+
+	while (--retries &&
+		!((in_be32(base_addr + 0x14) & BOTH_EMPTY) == BOTH_EMPTY))
+		;
+
+	if (retries)
+		out_be32(base_addr, c & 0xff);
+}
+
+static void early_printk_uart16550_write(struct console *unused,
+					const char *s, unsigned n)
+{
+	while (*s && n-- > 0) {
+		early_printk_uart16550_putc(*s);
+		if (*s == '\n')
+			early_printk_uart16550_putc('\r');
+		s++;
+	}
+}
+
+static struct console early_serial_uart16550_console = {
+	.name = "earlyser",
+	.write = early_printk_uart16550_write,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+};
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+static struct console *early_console;
 
 void early_printk(const char *fmt, ...)
 {
@@ -84,20 +130,43 @@
 	if (early_console_initialized)
 		return 1;
 
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
 	base_addr = early_uartlite_console();
 	if (base_addr) {
 		early_console_initialized = 1;
 #ifdef CONFIG_MMU
 		early_console_reg_tlb_alloc(base_addr);
 #endif
+		early_console = &early_serial_uartlite_console;
 		early_printk("early_printk_console is enabled at 0x%08x\n",
 							base_addr);
 
 		/* register_console(early_console); */
 
 		return 0;
-	} else
-		return 1;
+	}
+#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */
+
+#ifdef CONFIG_SERIAL_8250_CONSOLE
+	base_addr = early_uart16550_console();
+	base_addr &= ~3; /* clear register offset */
+	if (base_addr) {
+		early_console_initialized = 1;
+#ifdef CONFIG_MMU
+		early_console_reg_tlb_alloc(base_addr);
+#endif
+		early_console = &early_serial_uart16550_console;
+
+		early_printk("early_printk_console is enabled at 0x%08x\n",
+							base_addr);
+
+		/* register_console(early_console); */
+
+		return 0;
+	}
+#endif /* CONFIG_SERIAL_8250_CONSOLE */
+
+	return 1;
 }
 
 void __init disable_early_printk(void)
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/entry.S linux-libre-2.6.37-gnu/arch/microblaze/kernel/entry.S
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -186,6 +186,8 @@
 	swi	r13, r1, PTO+PT_R13;	/* Save SDA2 */			\
 	swi	r14, r1, PTO+PT_PC;	/* PC, before IRQ/trap */	\
 	swi	r15, r1, PTO+PT_R15;	/* Save LP */			\
+	swi	r16, r1, PTO+PT_R16;					\
+	swi	r17, r1, PTO+PT_R17;					\
 	swi	r18, r1, PTO+PT_R18;	/* Save asm scratch reg */	\
 	swi	r19, r1, PTO+PT_R19;					\
 	swi	r20, r1, PTO+PT_R20;					\
@@ -220,6 +222,8 @@
 	lwi	r13, r1, PTO+PT_R13;	/* restore SDA2 */		\
 	lwi	r14, r1, PTO+PT_PC;	/* RESTORE_LINK PC, before IRQ/trap */\
 	lwi	r15, r1, PTO+PT_R15;	/* restore LP */		\
+	lwi	r16, r1, PTO+PT_R16;					\
+	lwi	r17, r1, PTO+PT_R17;					\
 	lwi	r18, r1, PTO+PT_R18;	/* restore asm scratch reg */	\
 	lwi	r19, r1, PTO+PT_R19;					\
 	lwi	r20, r1, PTO+PT_R20;					\
@@ -295,6 +299,8 @@
 	/* addik	r1, r1, -STATE_SAVE_SIZE; */
 	addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE;
 	SAVE_REGS
+	swi	r0, r1, PTO + PT_R3
+	swi	r0, r1, PTO + PT_R4
 
 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
 	swi	r11, r1, PTO+PT_R1;		/* Store user SP.  */
@@ -458,14 +464,8 @@
 	addik	r8, r1, PTO;		/* add user context as 4th arg */
 
 C_ENTRY(sys_rt_sigreturn_wrapper):
-	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-	swi	r4, r1, PTO+PT_R4;
-	brlid	r15, sys_rt_sigreturn	/* Do real work */
+	brid	sys_rt_sigreturn	/* Do real work */
 	addik	r5, r1, PTO;		/* add user context as 1st arg */
-	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-	lwi	r4, r1, PTO+PT_R4;
-	bri ret_from_trap /* fall through will not work here due to align */
-	nop;
 
 /*
  * HW EXCEPTION rutine start
@@ -765,9 +765,7 @@
 	/* save all regs to pt_reg structure */
 	swi	r0, r1, PTO+PT_R0;	/* R0 must be saved too */
 	swi	r14, r1, PTO+PT_R14	/* rewrite saved R14 value */
-	swi	r16, r1, PTO+PT_R16
 	swi	r16, r1, PTO+PT_PC; /* PC and r16 are the same */
-	swi	r17, r1, PTO+PT_R17
 	/* save special purpose registers to pt_regs */
 	mfs	r11, rear;
 	swi	r11, r1, PTO+PT_EAR;
@@ -801,8 +799,6 @@
 
 	addik	r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack.  */
 	SAVE_REGS;
-	swi	r17, r1, PTO+PT_R17;
-	swi	r16, r1, PTO+PT_R16;
 	swi	r16, r1, PTO+PT_PC;	/* Save LP */
 	swi	r0, r1, PTO + PT_MODE; /* Was in user-mode.  */
 	lwi	r11, r0, TOPHYS(PER_CPU(ENTRY_SP));
@@ -848,8 +844,6 @@
 	tophys(r1,r1);
 	/* MS: Restore all regs */
 	RESTORE_REGS
-	lwi	r17, r1, PTO+PT_R17;
-	lwi	r16, r1, PTO+PT_R16;
 	addik	r1, r1, STATE_SAVE_SIZE	 /* Clean up stack space */
 	lwi	r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */
 DBTRAP_return_user: /* MS: Make global symbol for debugging */
@@ -863,7 +857,6 @@
 	RESTORE_REGS
 	lwi	r14, r1, PTO+PT_R14;
 	lwi	r16, r1, PTO+PT_PC;
-	lwi	r17, r1, PTO+PT_R17;
 	addik	r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */
 	tovirt(r1,r1);
 DBTRAP_return_kernel: /* MS: Make global symbol for debugging */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/exceptions.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/exceptions.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/exceptions.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/exceptions.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,6 @@
 							int fsr, int addr)
 {
 #ifdef CONFIG_MMU
-	int code;
 	addr = regs->pc;
 #endif
 
@@ -86,8 +85,7 @@
 	switch (type & 0x1F) {
 	case MICROBLAZE_ILL_OPCODE_EXCEPTION:
 		if (user_mode(regs)) {
-			pr_debug(KERN_WARNING "Illegal opcode exception " \
-							"in user mode.\n");
+			pr_debug("Illegal opcode exception in user mode\n");
 			_exception(SIGILL, regs, ILL_ILLOPC, addr);
 			return;
 		}
@@ -97,8 +95,7 @@
 		break;
 	case MICROBLAZE_IBUS_EXCEPTION:
 		if (user_mode(regs)) {
-			pr_debug(KERN_WARNING "Instruction bus error " \
-						"exception in user mode.\n");
+			pr_debug("Instruction bus error exception in user mode\n");
 			_exception(SIGBUS, regs, BUS_ADRERR, addr);
 			return;
 		}
@@ -108,8 +105,7 @@
 		break;
 	case MICROBLAZE_DBUS_EXCEPTION:
 		if (user_mode(regs)) {
-			pr_debug(KERN_WARNING "Data bus error exception " \
-							"in user mode.\n");
+			pr_debug("Data bus error exception in user mode\n");
 			_exception(SIGBUS, regs, BUS_ADRERR, addr);
 			return;
 		}
@@ -119,8 +115,7 @@
 		break;
 	case MICROBLAZE_DIV_ZERO_EXCEPTION:
 		if (user_mode(regs)) {
-			pr_debug(KERN_WARNING "Divide by zero exception " \
-							"in user mode\n");
+			pr_debug("Divide by zero exception in user mode\n");
 			_exception(SIGILL, regs, FPE_INTDIV, addr);
 			return;
 		}
@@ -129,7 +124,7 @@
 		die("Divide by zero exception", regs, SIGBUS);
 		break;
 	case MICROBLAZE_FPU_EXCEPTION:
-		pr_debug(KERN_WARNING "FPU exception\n");
+		pr_debug("FPU exception\n");
 		/* IEEE FP exception */
 		/* I removed fsr variable and use code var for storing fsr */
 		if (fsr & FSR_IO)
@@ -147,14 +142,8 @@
 
 #ifdef CONFIG_MMU
 	case MICROBLAZE_PRIVILEGED_EXCEPTION:
-		pr_debug(KERN_WARNING "Privileged exception\n");
-		/* "brk r0,r0" - used as debug breakpoint - old toolchain */
-		if (get_user(code, (unsigned long *)regs->pc) == 0
-			&& code == 0x980c0000) {
-			_exception(SIGTRAP, regs, TRAP_BRKPT, addr);
-		} else {
-			_exception(SIGILL, regs, ILL_PRVOPC, addr);
-		}
+		pr_debug("Privileged exception\n");
+		_exception(SIGILL, regs, ILL_PRVOPC, addr);
 		break;
 #endif
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/heartbeat.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/heartbeat.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/heartbeat.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/heartbeat.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,11 +47,10 @@
 	struct device_node *gpio = NULL;
 	int *prop;
 	int j;
-	char *gpio_list[] = {
-				"xlnx,xps-gpio-1.00.a",
-				"xlnx,opb-gpio-1.00.a",
-				NULL
-			};
+	const char * const gpio_list[] = {
+		"xlnx,xps-gpio-1.00.a",
+		NULL
+	};
 
 	for (j = 0; gpio_list[j] != NULL; j++) {
 		gpio = of_find_compatible_node(NULL, NULL, gpio_list[j]);
@@ -60,7 +59,7 @@
 	}
 
 	if (gpio) {
-		base_addr = *(int *) of_get_property(gpio, "reg", NULL);
+		base_addr = be32_to_cpup(of_get_property(gpio, "reg", NULL));
 		base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
 		printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/intc.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/intc.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/intc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/intc.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,11 +126,8 @@
 				0
 			};
 #endif
-	static char *intc_list[] = {
+	const char * const intc_list[] = {
 				"xlnx,xps-intc-1.00.a",
-				"xlnx,opb-intc-1.00.c",
-				"xlnx,opb-intc-1.00.b",
-				"xlnx,opb-intc-1.00.a",
 				NULL
 			};
 
@@ -141,12 +138,15 @@
 	}
 	BUG_ON(!intc);
 
-	intc_baseaddr = *(int *) of_get_property(intc, "reg", NULL);
+	intc_baseaddr = be32_to_cpup(of_get_property(intc,
+								"reg", NULL));
 	intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
-	nr_irq = *(int *) of_get_property(intc, "xlnx,num-intr-inputs", NULL);
+	nr_irq = be32_to_cpup(of_get_property(intc,
+						"xlnx,num-intr-inputs", NULL));
 
 	intr_type =
-		*(int *) of_get_property(intc, "xlnx,kind-of-intr", NULL);
+		be32_to_cpup(of_get_property(intc,
+						"xlnx,kind-of-intr", NULL));
 	if (intr_type >= (1 << (nr_irq + 1)))
 		printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n");
 
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/kgdb.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/kgdb.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/kgdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/kgdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -80,7 +80,7 @@
 void microblaze_kgdb_break(struct pt_regs *regs)
 {
 	if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
-		return 0;
+		return;
 
 	/* Jump over the first arch_kgdb_breakpoint which is barrier to
 	 * get kgdb work. The same solution is used for powerpc */
@@ -114,7 +114,6 @@
 {
 	char *ptr;
 	unsigned long address;
-	int cpu = smp_processor_id();
 
 	switch (remcom_in_buffer[0]) {
 	case 'c':
@@ -143,5 +142,9 @@
  * Global data
  */
 struct kgdb_arch arch_kgdb_ops = {
+#ifdef __MICROBLAZEEL__
+	.gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
+#else
 	.gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */
+#endif
 };
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/microblaze_ksyms.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/microblaze_ksyms.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/microblaze_ksyms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/microblaze_ksyms.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,37 +15,13 @@
 #include <linux/syscalls.h>
 
 #include <asm/checksum.h>
+#include <asm/cacheflush.h>
 #include <linux/io.h>
 #include <asm/page.h>
 #include <asm/system.h>
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
-/*
- * libgcc functions - functions that are used internally by the
- * compiler... (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-EXPORT_SYMBOL(__ashldi3);
-extern void __ashrdi3(void);
-EXPORT_SYMBOL(__ashrdi3);
-extern void __divsi3(void);
-EXPORT_SYMBOL(__divsi3);
-extern void __lshrdi3(void);
-EXPORT_SYMBOL(__lshrdi3);
-extern void __modsi3(void);
-EXPORT_SYMBOL(__modsi3);
-extern void __mulsi3(void);
-EXPORT_SYMBOL(__mulsi3);
-extern void __muldi3(void);
-EXPORT_SYMBOL(__muldi3);
-extern void __ucmpdi2(void);
-EXPORT_SYMBOL(__ucmpdi2);
-extern void __udivsi3(void);
-EXPORT_SYMBOL(__udivsi3);
-extern void __umodsi3(void);
-EXPORT_SYMBOL(__umodsi3);
 extern char *_ebss;
 EXPORT_SYMBOL_GPL(_ebss);
 #ifdef CONFIG_FUNCTION_TRACER
@@ -63,3 +39,9 @@
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 #endif
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(empty_zero_page);
+#endif
+
+EXPORT_SYMBOL(mbc);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/prom.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/prom.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/prom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,11 +42,6 @@
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
 
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
-{
-	/* No Microblaze specific code here */
-}
-
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
 	memblock_add(base, size);
@@ -77,11 +72,12 @@
 /* find compatible node with uartlite */
 	p = of_get_flat_dt_prop(node, "compatible", &l);
 	if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) &&
-			(strncmp(p, "xlnx,opb-uartlite", 17) != 0))
+			(strncmp(p, "xlnx,opb-uartlite", 17) != 0) &&
+			(strncmp(p, "xlnx,axi-uartlite", 17) != 0))
 		return 0;
 
 	addr = of_get_flat_dt_prop(node, "reg", &l);
-	return *addr; /* return address */
+	return be32_to_cpup(addr); /* return address */
 }
 
 /* this function is looking for early uartlite console - Microblaze specific */
@@ -89,6 +85,40 @@
 {
 	return of_scan_flat_dt(early_init_dt_scan_serial, NULL);
 }
+
+/* MS this is Microblaze specifig function */
+static int __init early_init_dt_scan_serial_full(unsigned long node,
+				const char *uname, int depth, void *data)
+{
+	unsigned long l;
+	char *p;
+	unsigned int addr;
+
+	pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+/* find all serial nodes */
+	if (strncmp(uname, "serial", 6) != 0)
+		return 0;
+
+	early_init_dt_check_for_initrd(node);
+
+/* find compatible node with uartlite */
+	p = of_get_flat_dt_prop(node, "compatible", &l);
+
+	if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) &&
+		(strncmp(p, "xlnx,axi-uart16550", 18) != 0))
+		return 0;
+
+	addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l);
+	addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l);
+	return be32_to_cpu(addr); /* return address */
+}
+
+/* this function is looking for early uartlite console - Microblaze specific */
+int __init early_uart16550_console(void)
+{
+	return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL);
+}
 #endif
 
 void __init early_init_devtree(void *params)
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -73,7 +73,8 @@
 	return (microblaze_reg_t *)((char *)regs + reg_offs);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int rval;
 	unsigned long val = 0;
@@ -99,7 +100,7 @@
 			} else {
 				rval = -EIO;
 			}
-		} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
+		} else if (addr < PT_SIZE && (addr & 0x3) == 0) {
 			microblaze_reg_t *reg_addr = reg_save_addr(addr, child);
 			if (request == PTRACE_PEEKUSR)
 				val = *reg_addr;
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/setup.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,12 +92,6 @@
 }
 #endif	/* CONFIG_MTD_UCLINUX_EBSS */
 
-#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
-#define eprintk early_printk
-#else
-#define eprintk printk
-#endif
-
 void __init machine_early_init(const char *cmdline, unsigned int ram,
 		unsigned int fdt, unsigned int msr)
 {
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/syscall_table.S linux-libre-2.6.37-gnu/arch/microblaze/kernel/syscall_table.S
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/syscall_table.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/syscall_table.S	2011-01-04 19:50:19.000000000 -0500
@@ -372,3 +372,6 @@
 	.long sys_rt_tgsigqueueinfo	/* 365 */
 	.long sys_perf_event_open
 	.long sys_recvmmsg
+	.long sys_fanotify_init
+	.long sys_fanotify_mark
+	.long sys_prlimit64	/* 370 */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/timer.c linux-libre-2.6.37-gnu/arch/microblaze/kernel/timer.c
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,9 @@
 #define TIMER_BASE	timer_baseaddr
 #endif
 
+unsigned int freq_div_hz;
+unsigned int timer_clock_freq;
+
 #define TCSR0	(0x00)
 #define TLR0	(0x04)
 #define TCR0	(0x08)
@@ -115,7 +118,7 @@
 	switch (mode) {
 	case CLOCK_EVT_MODE_PERIODIC:
 		printk(KERN_INFO "%s: periodic\n", __func__);
-		microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
+		microblaze_timer0_start_periodic(freq_div_hz);
 		break;
 	case CLOCK_EVT_MODE_ONESHOT:
 		printk(KERN_INFO "%s: oneshot\n", __func__);
@@ -168,7 +171,7 @@
 static __init void microblaze_clockevent_init(void)
 {
 	clockevent_microblaze_timer.mult =
-		div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+		div_sc(timer_clock_freq, NSEC_PER_SEC,
 				clockevent_microblaze_timer.shift);
 	clockevent_microblaze_timer.max_delta_ns =
 		clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
@@ -201,7 +204,7 @@
 
 int __init init_microblaze_timecounter(void)
 {
-	microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+	microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
 				microblaze_cc.shift);
 
 	timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
@@ -221,7 +224,7 @@
 static int __init microblaze_clocksource_init(void)
 {
 	clocksource_microblaze.mult =
-			clocksource_hz2mult(cpuinfo.cpu_clock_freq,
+			clocksource_hz2mult(timer_clock_freq,
 						clocksource_microblaze.shift);
 	if (clocksource_register(&clocksource_microblaze))
 		panic("failed to register clocksource");
@@ -247,6 +250,7 @@
 	u32 irq, i = 0;
 	u32 timer_num = 1;
 	struct device_node *timer = NULL;
+	const void *prop;
 #ifdef CONFIG_SELFMOD_TIMER
 	unsigned int timer_baseaddr = 0;
 	int arr_func[] = {
@@ -258,12 +262,10 @@
 				0
 			};
 #endif
-	char *timer_list[] = {
-				"xlnx,xps-timer-1.00.a",
-				"xlnx,opb-timer-1.00.b",
-				"xlnx,opb-timer-1.00.a",
-				NULL
-			};
+	const char * const timer_list[] = {
+		"xlnx,xps-timer-1.00.a",
+		NULL
+	};
 
 	for (i = 0; timer_list[i] != NULL; i++) {
 		timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
@@ -272,13 +274,13 @@
 	}
 	BUG_ON(!timer);
 
-	timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
+	timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
 	timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
-	irq = *(int *) of_get_property(timer, "interrupts", NULL);
-	timer_num =
-		*(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
+	irq = be32_to_cpup(of_get_property(timer, "interrupts", NULL));
+	timer_num = be32_to_cpup(of_get_property(timer,
+						"xlnx,one-timer-only", NULL));
 	if (timer_num) {
-		printk(KERN_EMERG "Please enable two timers in HW\n");
+		eprintk(KERN_EMERG "Please enable two timers in HW\n");
 		BUG();
 	}
 
@@ -288,7 +290,14 @@
 	printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
 		timer_list[i], timer_baseaddr, irq);
 
-	cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
+	/* If there is clock-frequency property than use it */
+	prop = of_get_property(timer, "clock-frequency", NULL);
+	if (prop)
+		timer_clock_freq = be32_to_cpup(prop);
+	else
+		timer_clock_freq = cpuinfo.cpu_clock_freq;
+
+	freq_div_hz = timer_clock_freq / HZ;
 
 	setup_irq(irq, &timer_irqaction);
 #ifdef CONFIG_HEART_BEAT
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/kernel/vmlinux.lds.S linux-libre-2.6.37-gnu/arch/microblaze/kernel/vmlinux.lds.S
--- linux-libre-2.6.36-gnu/arch/microblaze/kernel/vmlinux.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/kernel/vmlinux.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,6 @@
  * for more details.
  */
 
-OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze")
 OUTPUT_ARCH(microblaze)
 ENTRY(microblaze_start)
 
@@ -16,7 +15,11 @@
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
 
+#ifdef __MICROBLAZEEL__
+jiffies = jiffies_64;
+#else
 jiffies = jiffies_64 + 4;
+#endif
 
 SECTIONS {
 	. = CONFIG_KERNEL_START;
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/ashldi3.c linux-libre-2.6.37-gnu/arch/microblaze/lib/ashldi3.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/ashldi3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/ashldi3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashldi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.low = 0;
+		w.s.high = (unsigned int) uu.s.low << -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.low >> bm;
+
+		w.s.low = (unsigned int) uu.s.low << b;
+		w.s.high = ((unsigned int) uu.s.high << b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__ashldi3);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/ashrdi3.c linux-libre-2.6.37-gnu/arch/microblaze/lib/ashrdi3.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/ashrdi3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/ashrdi3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,31 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __ashrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		/* w.s.high = 1..1 or 0..0 */
+		w.s.high =
+		    uu.s.high >> 31;
+		w.s.low = uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__ashrdi3);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/divsi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/divsi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/divsi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/divsi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* Divide operation for 32 bit integers.
+*	Input :	Dividend in Reg r5
+*		Divisor in Reg r6
+*	Output: Result in Reg r3
+*/
+	.text
+	.globl	__divsi3
+	.type __divsi3, @function
+	.ent __divsi3
+__divsi3:
+	.frame	r1, 0, r15
+
+	addik	r1, r1, -16
+	swi	r28, r1, 0
+	swi	r29, r1, 4
+	swi	r30, r1, 8
+	swi	r31, r1, 12
+
+	beqi	r6, div_by_zero /* div_by_zero - division error */
+	beqi	r5, result_is_zero /* result is zero */
+	bgeid	r5, r5_pos
+	xor	r28, r5, r6 /* get the sign of the result */
+	rsubi	r5, r5, 0 /* make r5 positive */
+r5_pos:
+	bgei	r6, r6_pos
+	rsubi	r6, r6, 0 /* make r6 positive */
+r6_pos:
+	addik	r30, r0, 0 /* clear mod */
+	addik	r3, r0, 0 /* clear div */
+	addik	r29, r0, 32 /* initialize the loop count */
+
+	/* first part try to find the first '1' in the r5 */
+div0:
+	blti	r5, div2 /* this traps r5 == 0x80000000 */
+div1:
+	add	r5, r5, r5 /* left shift logical r5 */
+	bgtid	r5, div1
+	addik	r29, r29, -1
+div2:
+	/* left shift logical r5 get the '1' into the carry */
+	add	r5, r5, r5
+	addc	r30, r30, r30 /* move that bit into the mod register */
+	rsub	r31, r6, r30 /* try to subtract (r30 a r6) */
+	blti	r31, mod_too_small
+	/* move the r31 to mod since the result was positive */
+	or	r30, r0, r31
+	addik	r3, r3, 1
+mod_too_small:
+	addik	r29, r29, -1
+	beqi	r29, loop_end
+	add	r3, r3, r3 /* shift in the '1' into div */
+	bri	div2 /* div2 */
+loop_end:
+	bgei	r28, return_here
+	brid	return_here
+	rsubi	r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+	or	r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+	lwi	r28, r1, 0
+	lwi	r29, r1, 4
+	lwi	r30, r1, 8
+	lwi	r31, r1, 12
+	rtsd	r15, 8
+	addik	r1, r1, 16
+
+.size __divsi3, . - __divsi3
+.end __divsi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/libgcc.h linux-libre-2.6.37-gnu/arch/microblaze/lib/libgcc.h
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/libgcc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/libgcc.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,25 @@
+#ifndef __ASM_LIBGCC_H
+#define __ASM_LIBGCC_H
+
+#include <asm/byteorder.h>
+
+typedef int word_type __attribute__ ((mode (__word__)));
+
+#ifdef __BIG_ENDIAN
+struct DWstruct {
+	int high, low;
+};
+#elif defined(__LITTLE_ENDIAN)
+struct DWstruct {
+	int low, high;
+};
+#else
+#error I feel sick.
+#endif
+
+typedef union {
+	struct DWstruct s;
+	long long ll;
+} DWunion;
+
+#endif /* __ASM_LIBGCC_H */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/lshrdi3.c linux-libre-2.6.37-gnu/arch/microblaze/lib/lshrdi3.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/lshrdi3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/lshrdi3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+long long __lshrdi3(long long u, word_type b)
+{
+	DWunion uu, w;
+	word_type bm;
+
+	if (b == 0)
+		return u;
+
+	uu.ll = u;
+	bm = 32 - b;
+
+	if (bm <= 0) {
+		w.s.high = 0;
+		w.s.low = (unsigned int) uu.s.high >> -bm;
+	} else {
+		const unsigned int carries = (unsigned int) uu.s.high << bm;
+
+		w.s.high = (unsigned int) uu.s.high >> b;
+		w.s.low = ((unsigned int) uu.s.low >> b) | carries;
+	}
+
+	return w.ll;
+}
+
+EXPORT_SYMBOL(__lshrdi3);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/Makefile linux-libre-2.6.37-gnu/arch/microblaze/lib/Makefile
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,3 +11,13 @@
 endif
 
 lib-y += uaccess_old.o
+
+lib-y += ashldi3.o
+lib-y += ashrdi3.o
+lib-y += divsi3.o
+lib-y += lshrdi3.o
+lib-y += modsi3.o
+lib-y += muldi3.o
+lib-y += mulsi3.o
+lib-y += udivsi3.o
+lib-y += umodsi3.o
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/memcpy.c linux-libre-2.6.37-gnu/arch/microblaze/lib/memcpy.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/memcpy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/memcpy.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,17 +33,24 @@
 #include <asm/system.h>
 
 #ifdef __HAVE_ARCH_MEMCPY
+#ifndef CONFIG_OPT_LIB_FUNCTION
 void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
 {
 	const char *src = v_src;
 	char *dst = v_dst;
-#ifndef CONFIG_OPT_LIB_FUNCTION
+
 	/* Simple, byte oriented memcpy. */
 	while (c--)
 		*dst++ = *src++;
 
 	return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+	const char *src = v_src;
+	char *dst = v_dst;
+
 	/* The following code tries to optimize the copy by using unsigned
 	 * alignment. This will work fine if both source and destination are
 	 * aligned on the same boundary. However, if they are aligned on
@@ -86,7 +93,7 @@
 		case 0x1:	/* Unaligned - Off by 1 */
 			/* Word align the source */
 			i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *i_src++ << 8;
 
@@ -95,7 +102,16 @@
 				*i_dst++ = buf_hold | value >> 24;
 				buf_hold = value << 8;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
 
+			for (; c >= 4; c -= 4) {
+				value = *i_src++;
+				*i_dst++ = buf_hold | ((value & 0xFF) << 24);
+				buf_hold = (value & 0xFFFFFF00) >>8;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src -= 3;
@@ -103,7 +119,7 @@
 		case 0x2:	/* Unaligned - Off by 2 */
 			/* Word align the source */
 			i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *i_src++ << 16;
 
@@ -112,7 +128,16 @@
 				*i_dst++ = buf_hold | value >> 16;
 				buf_hold = value << 16;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
 
+			for (; c >= 4; c -= 4) {
+				value = *i_src++;
+				*i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
+				buf_hold = (value & 0xFFFF0000) >>16;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src -= 2;
@@ -120,7 +145,7 @@
 		case 0x3:	/* Unaligned - Off by 3 */
 			/* Word align the source */
 			i_src = (const void *) ((unsigned)src & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *i_src++ << 24;
 
@@ -129,7 +154,16 @@
 				*i_dst++ = buf_hold | value >> 8;
 				buf_hold = value << 24;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*i_src++ & 0xFF000000) >> 24;
 
+			for (; c >= 4; c -= 4) {
+				value = *i_src++;
+				*i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
+				buf_hold = (value & 0xFF000000) >> 24;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src -= 1;
@@ -150,7 +184,7 @@
 	}
 
 	return v_dst;
-#endif
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memcpy);
 #endif /* __HAVE_ARCH_MEMCPY */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/memmove.c linux-libre-2.6.37-gnu/arch/microblaze/lib/memmove.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/memmove.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/memmove.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,16 +31,12 @@
 #include <linux/string.h>
 
 #ifdef __HAVE_ARCH_MEMMOVE
+#ifndef CONFIG_OPT_LIB_FUNCTION
 void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
 {
 	const char *src = v_src;
 	char *dst = v_dst;
 
-#ifdef CONFIG_OPT_LIB_FUNCTION
-	const uint32_t *i_src;
-	uint32_t *i_dst;
-#endif
-
 	if (!c)
 		return v_dst;
 
@@ -48,7 +44,6 @@
 	if (v_dst <= v_src)
 		return memcpy(v_dst, v_src, c);
 
-#ifndef CONFIG_OPT_LIB_FUNCTION
 	/* copy backwards, from end to beginning */
 	src += c;
 	dst += c;
@@ -58,7 +53,22 @@
 		*--dst = *--src;
 
 	return v_dst;
-#else
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
+void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
+{
+	const char *src = v_src;
+	char *dst = v_dst;
+	const uint32_t *i_src;
+	uint32_t *i_dst;
+
+	if (!c)
+		return v_dst;
+
+	/* Use memcpy when source is higher than dest */
+	if (v_dst <= v_src)
+		return memcpy(v_dst, v_src, c);
+
 	/* The following code tries to optimize the copy by using unsigned
 	 * alignment. This will work fine if both source and destination are
 	 * aligned on the same boundary. However, if they are aligned on
@@ -104,7 +114,7 @@
 		case 0x1:	/* Unaligned - Off by 1 */
 			/* Word align the source */
 			i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *--i_src >> 24;
 
@@ -113,7 +123,16 @@
 				*--i_dst = buf_hold << 8 | value;
 				buf_hold = value >> 24;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*--i_src & 0xFF) << 24;
 
+			for (; c >= 4; c -= 4) {
+				value = *--i_src;
+				*--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
+				buf_hold = (value  & 0xFF) << 24;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src += 1;
@@ -121,7 +140,7 @@
 		case 0x2:	/* Unaligned - Off by 2 */
 			/* Word align the source */
 			i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *--i_src >> 16;
 
@@ -130,7 +149,16 @@
 				*--i_dst = buf_hold << 16 | value;
 				buf_hold = value >> 16;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*--i_src & 0xFFFF) << 16;
 
+			for (; c >= 4; c -= 4) {
+				value = *--i_src;
+				*--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
+				buf_hold = (value & 0xFFFF) << 16;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src += 2;
@@ -138,7 +166,7 @@
 		case 0x3:	/* Unaligned - Off by 3 */
 			/* Word align the source */
 			i_src = (const void *) (((unsigned)src + 4) & ~3);
-
+#ifndef __MICROBLAZEEL__
 			/* Load the holding buffer */
 			buf_hold = *--i_src >> 8;
 
@@ -147,7 +175,16 @@
 				*--i_dst = buf_hold << 24 | value;
 				buf_hold = value >> 8;
 			}
+#else
+			/* Load the holding buffer */
+			buf_hold = (*--i_src & 0xFFFFFF) << 8;
 
+			for (; c >= 4; c -= 4) {
+				value = *--i_src;
+				*--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
+				buf_hold = (value & 0xFFFFFF) << 8;;
+			}
+#endif
 			/* Realign the source */
 			src = (const void *)i_src;
 			src += 3;
@@ -169,7 +206,7 @@
 		*--dst = *--src;
 	}
 	return v_dst;
-#endif
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memmove);
 #endif /* __HAVE_ARCH_MEMMOVE */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/memset.c linux-libre-2.6.37-gnu/arch/microblaze/lib/memset.c
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/memset.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/memset.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,17 +31,30 @@
 #include <linux/string.h>
 
 #ifdef __HAVE_ARCH_MEMSET
+#ifndef CONFIG_OPT_LIB_FUNCTION
+void *memset(void *v_src, int c, __kernel_size_t n)
+{
+	char *src = v_src;
+
+	/* Truncate c to 8 bits */
+	c = (c & 0xFF);
+
+	/* Simple, byte oriented memset or the rest of count. */
+	while (n--)
+		*src++ = c;
+
+	return v_src;
+}
+#else /* CONFIG_OPT_LIB_FUNCTION */
 void *memset(void *v_src, int c, __kernel_size_t n)
 {
 	char *src = v_src;
-#ifdef CONFIG_OPT_LIB_FUNCTION
 	uint32_t *i_src;
 	uint32_t w32 = 0;
-#endif
+
 	/* Truncate c to 8 bits */
 	c = (c & 0xFF);
 
-#ifdef CONFIG_OPT_LIB_FUNCTION
 	if (unlikely(c)) {
 		/* Make a repeating word out of it */
 		w32 = c;
@@ -72,12 +85,13 @@
 
 		src  = (void *)i_src;
 	}
-#endif
+
 	/* Simple, byte oriented memset or the rest of count. */
 	while (n--)
 		*src++ = c;
 
 	return v_src;
 }
+#endif /* CONFIG_OPT_LIB_FUNCTION */
 EXPORT_SYMBOL(memset);
 #endif /* __HAVE_ARCH_MEMSET */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/modsi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/modsi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/modsi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/modsi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,73 @@
+#include <linux/linkage.h>
+
+/*
+* modulo operation for 32 bit integers.
+*	Input :	op1 in Reg r5
+*		op2 in Reg r6
+*	Output: op1 mod op2 in Reg r3
+*/
+
+	.text
+	.globl	__modsi3
+	.type __modsi3,  @function
+	.ent __modsi3
+
+__modsi3:
+	.frame	r1, 0, r15
+
+	addik	r1, r1, -16
+	swi	r28, r1, 0
+	swi	r29, r1, 4
+	swi	r30, r1, 8
+	swi	r31, r1, 12
+
+	beqi	r6, div_by_zero /* div_by_zero division error */
+	beqi	r5, result_is_zero /* result is zero */
+	bgeid	r5, r5_pos
+	/* get the sign of the result [ depends only on the first arg] */
+	add	r28, r5, r0
+	rsubi	r5, r5, 0	 /* make r5 positive */
+r5_pos:
+	bgei	r6, r6_pos
+	rsubi	r6, r6, 0	 /* make r6 positive */
+r6_pos:
+	addik	r3, r0, 0 /* clear mod */
+	addik	r30, r0, 0 /* clear div */
+	addik	r29, r0, 32 /* initialize the loop count */
+/* first part try to find the first '1' in the r5 */
+div1:
+	add	r5, r5, r5 /* left shift logical r5 */
+	bgeid	r5, div1
+	addik	r29, r29, -1
+div2:
+	/* left shift logical r5 get the '1' into the carry */
+	add	r5, r5, r5
+	addc	r3, r3, r3 /* move that bit into the mod register */
+	rsub	r31, r6, r3 /* try to subtract (r30 a r6) */
+	blti	r31, mod_too_small
+	/* move the r31 to mod since the result was positive */
+	or	r3, r0, r31
+	addik	r30, r30, 1
+mod_too_small:
+	addik	r29, r29, -1
+	beqi	r29, loop_end
+	add	r30, r30, r30 /* shift in the '1' into div */
+	bri	div2 /* div2 */
+loop_end:
+	bgei	r28, return_here
+	brid	return_here
+	rsubi	r3, r3, 0 /* negate the result */
+div_by_zero:
+result_is_zero:
+	or	r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+	lwi	r28, r1, 0
+	lwi	r29, r1, 4
+	lwi	r30, r1, 8
+	lwi	r31, r1, 12
+	rtsd	r15, 8
+	addik	r1, r1, 16
+
+.size __modsi3,  . - __modsi3
+.end __modsi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/muldi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/muldi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/muldi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/muldi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,121 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 64 bit integers, for devices with hard multiply
+ *	Input :	Operand1[H] in Reg r5
+ *		Operand1[L] in Reg r6
+ *		Operand2[H] in Reg r7
+ *		Operand2[L] in Reg r8
+ *	Output: Result[H] in Reg r3
+ *		Result[L] in Reg r4
+ *
+ * Explaination:
+ *
+ *	Both the input numbers are divided into 16 bit number as follows
+ *		op1 = A B C D
+ *		op2 = E F G H
+ *	result = D * H
+ *		 + (C * H + D * G) << 16
+ *		 + (B * H + C * G + D * F) << 32
+ *		 + (A * H + B * G + C * F + D * E) << 48
+ *
+ *	Only 64 bits of the output are considered
+ */
+
+	.text
+	.globl	__muldi3
+	.type __muldi3, @function
+	.ent __muldi3
+
+__muldi3:
+	addi	r1, r1, -40
+
+/* Save the input operands on the caller's stack */
+	swi	r5, r1, 44
+	swi	r6, r1, 48
+	swi	r7, r1, 52
+	swi	r8, r1, 56
+
+/* Store all the callee saved registers */
+	sw	r20, r1, r0
+	swi	r21, r1, 4
+	swi	r22, r1, 8
+	swi	r23, r1, 12
+	swi	r24, r1, 16
+	swi	r25, r1, 20
+	swi	r26, r1, 24
+	swi	r27, r1, 28
+
+/* Load all the 16 bit values for A thru H */
+	lhui	r20, r1, 44 /* A */
+	lhui	r21, r1, 46 /* B */
+	lhui	r22, r1, 48 /* C */
+	lhui	r23, r1, 50 /* D */
+	lhui	r24, r1, 52 /* E */
+	lhui	r25, r1, 54 /* F */
+	lhui	r26, r1, 56 /* G */
+	lhui	r27, r1, 58 /* H */
+
+/* D * H ==> LSB of the result on stack ==> Store1 */
+	mul	r9, r23, r27
+	swi	r9, r1, 36 /* Pos2 and Pos3 */
+
+/* Hi (Store1) + C * H + D * G ==> Store2 ==> Pos1 and Pos2 */
+/* Store the carry generated in position 2 for Pos 3 */
+	lhui	r11, r1, 36 /* Pos2 */
+	mul	r9, r22, r27 /* C * H */
+	mul	r10, r23, r26 /* D * G */
+	add	r9, r9, r10
+	addc	r12, r0, r0
+	add	r9, r9, r11
+	addc	r12, r12, r0 /* Store the Carry */
+	shi	r9, r1, 36 /* Store Pos2 */
+	swi	r9, r1, 32
+	lhui	r11, r1, 32
+	shi	r11, r1, 34 /* Store Pos1 */
+
+/* Hi (Store2) + B * H + C * G + D * F ==> Store3 ==> Pos0 and Pos1 */
+	mul	r9, r21, r27 /* B * H */
+	mul	r10, r22, r26 /* C * G */
+	mul	r7, r23, r25 /* D * F */
+	add	r9, r9, r11
+	add	r9, r9, r10
+	add	r9, r9, r7
+	swi	r9, r1, 32 /* Pos0 and Pos1 */
+
+/* Hi (Store3) + A * H + B * G + C * F + D * E ==> Store3 ==> Pos0 */
+	lhui	r11, r1, 32 /* Pos0 */
+	mul	r9, r20, r27 /* A * H */
+	mul	r10, r21, r26 /* B * G */
+	mul	r7, r22, r25 /* C * F */
+	mul	r8, r23, r24 /* D * E */
+	add	r9, r9, r11
+	add 	r9, r9, r10
+	add	r9, r9, r7
+	add	r9, r9, r8
+	sext16	r9, r9 /* Sign extend the MSB */
+	shi	r9, r1, 32
+
+/* Move results to r3 and r4 */
+	lhui	r3, r1, 32
+	add	r3, r3, r12
+	shi	r3, r1, 32
+	lwi	r3, r1, 32 /* Hi Part */
+	lwi	r4, r1, 36 /* Lo Part */
+
+/* Restore Callee saved registers */
+	lw	r20, r1, r0
+	lwi	r21, r1, 4
+	lwi	r22, r1, 8
+	lwi	r23, r1, 12
+	lwi	r24, r1, 16
+	lwi	r25, r1, 20
+	lwi	r26, r1, 24
+	lwi	r27, r1, 28
+
+/* Restore Frame and return */
+	rtsd	r15, 8
+	addi	r1, r1, 40
+
+.size __muldi3, . - __muldi3
+.end __muldi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/mulsi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/mulsi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/mulsi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/mulsi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,46 @@
+#include <linux/linkage.h>
+
+/*
+ * Multiply operation for 32 bit integers.
+ *	Input :	Operand1 in Reg r5
+ *		Operand2 in Reg r6
+ *	Output: Result [op1 * op2] in Reg r3
+ */
+	.text
+	.globl	__mulsi3
+	.type __mulsi3,  @function
+	.ent __mulsi3
+
+__mulsi3:
+	.frame	r1, 0, r15
+	add	r3, r0, r0
+	beqi	r5, result_is_zero /* multiply by zero */
+	beqi	r6, result_is_zero /* multiply by zero */
+	bgeid	r5, r5_pos
+	xor	r4, r5, r6 /* get the sign of the result */
+	rsubi	r5, r5, 0 /* make r5 positive */
+r5_pos:
+	bgei	r6, r6_pos
+	rsubi	r6, r6, 0 /* make r6 positive */
+r6_pos:
+	bri	l1
+l2:
+	add	r5, r5, r5
+l1:
+	srl	r6, r6
+	addc	r7, r0, r0
+	beqi	r7, l2
+	bneid	r6, l2
+	add	r3, r3, r5
+	blti	r4, negateresult
+	rtsd	r15, 8
+	nop
+negateresult:
+	rtsd	r15, 8
+	rsub	r3, r3, r0
+result_is_zero:
+	rtsd	r15, 8
+	addi	r3, r0, 0
+
+.size __mulsi3,  . - __mulsi3
+.end __mulsi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/udivsi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/udivsi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/udivsi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/udivsi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,84 @@
+#include <linux/linkage.h>
+
+/*
+* Unsigned divide operation.
+*	Input :	Divisor in Reg r5
+*		Dividend in Reg r6
+*	Output: Result in Reg r3
+*/
+
+	.text
+	.globl	__udivsi3
+	.type __udivsi3, @function
+	.ent __udivsi3
+
+__udivsi3:
+
+	.frame	r1, 0, r15
+
+	addik	r1, r1, -12
+	swi	r29, r1, 0
+	swi	r30, r1, 4
+	swi	r31, r1, 8
+
+	beqi	r6, div_by_zero /* div_by_zero /* division error */
+	beqid	r5, result_is_zero /* result is zero */
+	addik	r30, r0, 0 /* clear mod */
+	addik	r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal - if yes, return 1 */
+	rsub	r18, r5, r6
+	beqid	r18, return_here
+	addik	r3, r0, 1
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return 0 */
+	xor	r18, r5, r6
+	bgeid	r18, 16
+	add	r3, r0, r0 /* we would anyways clear r3 */
+	blti	r6, return_here /* r6[bit 31 = 1] hence is greater */
+	bri	checkr6
+	rsub	r18, r6, r5 /* microblazecmp */
+	blti	r18, return_here
+
+/* if r6 [bit 31] is set, then return result as 1 */
+checkr6:
+	bgti	r6, div0
+	brid	return_here
+	addik	r3, r0, 1
+
+/* first part try to find the first '1' in the r5 */
+div0:
+	blti	r5, div2
+div1:
+	add	r5, r5, r5 /* left shift logical r5 */
+	bgtid	r5, div1
+	addik	r29, r29, -1
+div2:
+/* left shift logical r5 get the '1' into the carry */
+	add	r5, r5, r5
+	addc	r30, r30, r30 /* move that bit into the mod register */
+	rsub	r31, r6, r30 /* try to subtract (r30 a r6) */
+	blti	r31, mod_too_small
+/* move the r31 to mod since the result was positive */
+	or	r30, r0, r31
+	addik	r3, r3, 1
+mod_too_small:
+	addik	r29, r29, -1
+	beqi	r29, loop_end
+	add	r3, r3, r3 /* shift in the '1' into div */
+	bri	div2 /* div2 */
+loop_end:
+	bri	return_here
+div_by_zero:
+result_is_zero:
+	or	r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+	lwi	r29, r1, 0
+	lwi	r30, r1, 4
+	lwi	r31, r1, 8
+	rtsd	r15, 8
+	addik	r1, r1, 12
+
+.size __udivsi3, . - __udivsi3
+.end __udivsi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/lib/umodsi3.S linux-libre-2.6.37-gnu/arch/microblaze/lib/umodsi3.S
--- linux-libre-2.6.36-gnu/arch/microblaze/lib/umodsi3.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/microblaze/lib/umodsi3.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,86 @@
+#include <linux/linkage.h>
+
+/*
+ * Unsigned modulo operation for 32 bit integers.
+ *	Input :	op1 in Reg r5
+ *		op2 in Reg r6
+ *	Output: op1 mod op2 in Reg r3
+ */
+
+	.text
+	.globl	__umodsi3
+	.type __umodsi3, @function
+	.ent __umodsi3
+
+__umodsi3:
+	.frame	r1, 0, r15
+
+	addik	r1, r1, -12
+	swi	r29, r1, 0
+	swi	r30, r1, 4
+	swi	r31, r1, 8
+
+	beqi	r6, div_by_zero /* div_by_zero - division error */
+	beqid	r5, result_is_zero /* result is zero */
+	addik	r3, r0, 0 /* clear div */
+	addik	r30, r0, 0 /* clear mod */
+	addik	r29, r0, 32 /* initialize the loop count */
+
+/* check if r6 and r5 are equal /* if yes, return 0 */
+	rsub	r18, r5, r6
+	beqi	r18, return_here
+
+/* check if (uns)r6 is greater than (uns)r5. in that case, just return r5 */
+	xor	r18, r5, r6
+	bgeid	r18, 16
+	addik	r3, r5, 0
+	blti	r6, return_here
+	bri	$lcheckr6
+	rsub	r18, r5, r6 /* microblazecmp */
+	bgti	r18, return_here
+
+/* if r6 [bit 31] is set, then return result as r5-r6 */
+$lcheckr6:
+	bgtid	r6, div0
+	addik	r3, r0, 0
+	addik	r18, r0, 0x7fffffff
+	and	r5, r5, r18
+	and	r6, r6, r18
+	brid	return_here
+	rsub	r3, r6, r5
+/* first part: try to find the first '1' in the r5 */
+div0:
+	blti	r5, div2
+div1:
+	add	r5, r5, r5 /* left shift logical r5 */
+	bgeid	r5, div1
+	addik	r29, r29, -1
+div2:
+	/* left shift logical r5 get the '1' into the carry */
+	add	r5, r5, r5
+	addc	r3, r3, r3 /* move that bit into the mod register */
+	rsub	r31, r6, r3 /* try to subtract (r3 a r6) */
+	blti	r31, mod_too_small
+	/* move the r31 to mod since the result was positive */
+	or	r3, r0, r31
+	addik	r30, r30, 1
+mod_too_small:
+	addik	r29, r29, -1
+	beqi	r29, loop_end
+	add	r30, r30, r30 /* shift in the '1' into div */
+	bri	div2 /* div2 */
+loop_end:
+	bri	return_here
+div_by_zero:
+result_is_zero:
+	or	r3, r0, r0 /* set result to 0 */
+return_here:
+/* restore values of csrs and that of r3 and the divisor and the dividend */
+	lwi	r29, r1, 0
+	lwi	r30, r1, 4
+	lwi	r31, r1, 8
+	rtsd	r15, 8
+	addik	r1, r1, 12
+
+.size __umodsi3, . - __umodsi3
+.end __umodsi3
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/Makefile linux-libre-2.6.37-gnu/arch/microblaze/Makefile
--- linux-libre-2.6.36-gnu/arch/microblaze/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -42,11 +42,8 @@
 LDFLAGS		:=
 LDFLAGS_vmlinux	:=
 
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
 head-y := arch/microblaze/kernel/head.o
 libs-y += arch/microblaze/lib/
-libs-y += $(LIBGCC)
 core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
@@ -72,12 +69,16 @@
 
 all: linux.bin
 
-BOOT_TARGETS = linux.bin linux.bin.gz simpleImage.%
+# With make 3.82 we cannot mix normal and wildcard targets
+BOOT_TARGETS1 = linux.bin linux.bin.gz
+BOOT_TARGETS2 = simpleImage.%
 
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
 
-$(BOOT_TARGETS): vmlinux
+$(BOOT_TARGETS1): vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+$(BOOT_TARGETS2): vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 define archhelp
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/mm/init.c linux-libre-2.6.37-gnu/arch/microblaze/mm/init.c
--- linux-libre-2.6.36-gnu/arch/microblaze/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -70,16 +70,16 @@
 
 void __init setup_memory(void)
 {
-	int i;
 	unsigned long map_size;
+	struct memblock_region *reg;
+
 #ifndef CONFIG_MMU
 	u32 kernel_align_start, kernel_align_size;
 
 	/* Find main memory where is the kernel */
-	for (i = 0; i < memblock.memory.cnt; i++) {
-		memory_start = (u32) memblock.memory.region[i].base;
-		memory_end = (u32) memblock.memory.region[i].base
-				+ (u32) memblock.memory.region[i].size;
+	for_each_memblock(memory, reg) {
+		memory_start = (u32)reg->base;
+		memory_end = (u32) reg->base + reg->size;
 		if ((memory_start <= (u32)_text) &&
 					((u32)_text <= memory_end)) {
 			memory_size = memory_end - memory_start;
@@ -142,12 +142,10 @@
 	free_bootmem(memory_start, memory_size);
 
 	/* reserve allocate blocks */
-	for (i = 0; i < memblock.reserved.cnt; i++) {
-		pr_debug("reserved %d - 0x%08x-0x%08x\n", i,
-			(u32) memblock.reserved.region[i].base,
-			(u32) memblock_size_bytes(&memblock.reserved, i));
-		reserve_bootmem(memblock.reserved.region[i].base,
-			memblock_size_bytes(&memblock.reserved, i) - 1, BOOTMEM_DEFAULT);
+	for_each_memblock(reserved, reg) {
+		pr_debug("reserved - 0x%08x-0x%08x\n",
+			 (u32) reg->base, (u32) reg->size);
+		reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
 	}
 #ifdef CONFIG_MMU
 	init_bootmem_done = 1;
@@ -230,7 +228,7 @@
 		if (maxmem && memory_size > maxmem) {
 			memory_size = maxmem;
 			memory_end = memory_start + memory_size;
-			memblock.memory.region[0].size = memory_size;
+			memblock.memory.regions[0].size = memory_size;
 		}
 	}
 }
@@ -273,14 +271,14 @@
 		machine_restart(NULL);
 	}
 
-	if ((u32) memblock.memory.region[0].size < 0x1000000) {
+	if ((u32) memblock.memory.regions[0].size < 0x1000000) {
 		printk(KERN_EMERG "Memory must be greater than 16MB\n");
 		machine_restart(NULL);
 	}
 	/* Find main memory where the kernel is */
-	memory_start = (u32) memblock.memory.region[0].base;
-	memory_end = (u32) memblock.memory.region[0].base +
-				(u32) memblock.memory.region[0].size;
+	memory_start = (u32) memblock.memory.regions[0].base;
+	memory_end = (u32) memblock.memory.regions[0].base +
+				(u32) memblock.memory.regions[0].size;
 	memory_size = memory_end - memory_start;
 
 	mm_cmdline_setup(); /* FIXME parse args from command line - not used */
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/pci/pci-common.c linux-libre-2.6.37-gnu/arch/microblaze/pci/pci-common.c
--- linux-libre-2.6.36-gnu/arch/microblaze/pci/pci-common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/pci/pci-common.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,21 +60,6 @@
 }
 EXPORT_SYMBOL(get_pci_dma_ops);
 
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
-	return dma_set_mask(&dev->dev, mask);
-}
-
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
-	int rc;
-
-	rc = dma_set_mask(&dev->dev, mask);
-	dev->dev.coherent_dma_mask = dev->dma_mask;
-
-	return rc;
-}
-
 struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
 {
 	struct pci_controller *phb;
@@ -1075,8 +1060,6 @@
 		 bus->number, bus->self ? pci_name(bus->self) : "PHB");
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
-		struct dev_archdata *sd = &dev->dev.archdata;
-
 		/* Setup OF node pointer in archdata */
 		dev->dev.of_node = pci_device_to_OF_node(dev);
 
@@ -1086,8 +1069,8 @@
 		set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
 
 		/* Hook up default DMA ops */
-		sd->dma_ops = pci_dma_ops;
-		sd->dma_data = (void *)PCI_DRAM_OFFSET;
+		set_dma_ops(&dev->dev, pci_dma_ops);
+		dev->dev.archdata.dma_data = (void *)PCI_DRAM_OFFSET;
 
 		/* Read default IRQs and fixup if necessary */
 		pci_read_irq_line(dev);
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/platform/generic/system.dts linux-libre-2.6.37-gnu/arch/microblaze/platform/generic/system.dts
--- linux-libre-2.6.36-gnu/arch/microblaze/platform/generic/system.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/platform/generic/system.dts	2011-01-04 19:50:19.000000000 -0500
@@ -85,6 +85,7 @@
 			xlnx,dynamic-bus-sizing = <0x1>;
 			xlnx,edge-is-positive = <0x1>;
 			xlnx,family = "virtex5";
+			xlnx,endianness = <0x1>;
 			xlnx,fpu-exception = <0x1>;
 			xlnx,fsl-data-size = <0x20>;
 			xlnx,fsl-exception = <0x0>;
@@ -218,6 +219,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,compound";
+			ranges ;
 			ethernet@81c00000 {
 				compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
 				device_type = "network";
@@ -332,6 +334,7 @@
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,mpmc-4.02.a";
+			ranges ;
 			PIM3: sdma@84600180 {
 				compatible = "xlnx,ll-dma-1.00.a";
 				interrupt-parent = <&xps_intc_0>;
diff -druN linux-libre-2.6.36-gnu/arch/microblaze/platform/platform.c linux-libre-2.6.37-gnu/arch/microblaze/platform/platform.c
--- linux-libre-2.6.36-gnu/arch/microblaze/platform/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/microblaze/platform/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,9 +17,6 @@
 
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
 	{ .compatible = "simple-bus", },
-	{ .compatible = "xlnx,plb-v46-1.00.a", },
-	{ .compatible = "xlnx,opb-v20-1.10.c", },
-	{ .compatible = "xlnx,opb-v20-1.10.b", },
 	{ .compatible = "xlnx,compound", },
 	{}
 };
diff -druN linux-libre-2.6.36-gnu/arch/mips/alchemy/common/platform.c linux-libre-2.6.37-gnu/arch/mips/alchemy/common/platform.c
--- linux-libre-2.6.36-gnu/arch/mips/alchemy/common/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/alchemy/common/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,35 @@
 
 #include <prom.h>
 
+static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
+			    unsigned int old_state)
+{
+#ifdef CONFIG_SERIAL_8250
+	switch (state) {
+	case 0:
+		if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) {
+			/* power-on sequence as suggested in the databooks */
+			__raw_writel(0, port->membase + UART_MOD_CNTRL);
+			wmb();
+			__raw_writel(1, port->membase + UART_MOD_CNTRL);
+			wmb();
+		}
+		__raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */
+		wmb();
+		serial8250_do_pm(port, state, old_state);
+		break;
+	case 3:		/* power off */
+		serial8250_do_pm(port, state, old_state);
+		__raw_writel(0, port->membase + UART_MOD_CNTRL);
+		wmb();
+		break;
+	default:
+		serial8250_do_pm(port, state, old_state);
+		break;
+	}
+#endif
+}
+
 #define PORT(_base, _irq)					\
 	{							\
 		.mapbase	= _base,			\
@@ -33,6 +62,7 @@
 		.flags		= UPF_SKIP_TEST | UPF_IOREMAP |	\
 				  UPF_FIXED_TYPE,		\
 		.type		= PORT_16550A,			\
+		.pm		= alchemy_8250_pm,		\
 	}
 
 static struct plat_serial8250_port au1x00_uart_data[] = {
diff -druN linux-libre-2.6.36-gnu/arch/mips/alchemy/common/power.c linux-libre-2.6.37-gnu/arch/mips/alchemy/common/power.c
--- linux-libre-2.6.36-gnu/arch/mips/alchemy/common/power.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/alchemy/common/power.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,11 +49,6 @@
  * We only have to save/restore registers that aren't otherwise
  * done as part of a driver pm_* function.
  */
-static unsigned int sleep_uart0_inten;
-static unsigned int sleep_uart0_fifoctl;
-static unsigned int sleep_uart0_linectl;
-static unsigned int sleep_uart0_clkdiv;
-static unsigned int sleep_uart0_enable;
 static unsigned int sleep_usb[2];
 static unsigned int sleep_sys_clocks[5];
 static unsigned int sleep_sys_pinfunc;
@@ -62,22 +57,6 @@
 
 static void save_core_regs(void)
 {
-	extern void save_au1xxx_intctl(void);
-	extern void pm_eth0_shutdown(void);
-
-	/*
-	 * Do the serial ports.....these really should be a pm_*
-	 * registered function by the driver......but of course the
-	 * standard serial driver doesn't understand our Au1xxx
-	 * unique registers.
-	 */
-	sleep_uart0_inten = au_readl(UART0_ADDR + UART_IER);
-	sleep_uart0_fifoctl = au_readl(UART0_ADDR + UART_FCR);
-	sleep_uart0_linectl = au_readl(UART0_ADDR + UART_LCR);
-	sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK);
-	sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL);
-	au_sync();
-
 #ifndef CONFIG_SOC_AU1200
 	/* Shutdown USB host/device. */
 	sleep_usb[0] = au_readl(USB_HOST_CONFIG);
@@ -175,20 +154,6 @@
 	au_writel(sleep_static_memctlr[3][0], MEM_STCFG3);
 	au_writel(sleep_static_memctlr[3][1], MEM_STTIME3);
 	au_writel(sleep_static_memctlr[3][2], MEM_STADDR3);
-
-	/*
-	 * Enable the UART if it was enabled before sleep.
-	 * I guess I should define module control bits........
-	 */
-	if (sleep_uart0_enable & 0x02) {
-		au_writel(0, UART0_ADDR + UART_MOD_CNTRL); au_sync();
-		au_writel(1, UART0_ADDR + UART_MOD_CNTRL); au_sync();
-		au_writel(3, UART0_ADDR + UART_MOD_CNTRL); au_sync();
-		au_writel(sleep_uart0_inten, UART0_ADDR + UART_IER); au_sync();
-		au_writel(sleep_uart0_fifoctl, UART0_ADDR + UART_FCR); au_sync();
-		au_writel(sleep_uart0_linectl, UART0_ADDR + UART_LCR); au_sync();
-		au_writel(sleep_uart0_clkdiv, UART0_ADDR + UART_CLK); au_sync();
-	}
 }
 
 void au_sleep(void)
diff -druN linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/bcsr.c linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/bcsr.c
--- linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/bcsr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/bcsr.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 #include <asm/addrspace.h>
 #include <asm/io.h>
 #include <asm/mach-db1x00/bcsr.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/db1200/platform.c linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/db1200/platform.c
--- linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/db1200/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/db1200/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -429,6 +429,11 @@
 	.resource	= au1200_psc1_res,
 };
 
+static struct platform_device db1200_stac_dev = {
+	.name		= "ac97-codec",
+	.id		= 1,	/* on PSC1 */
+};
+
 static struct platform_device *db1200_devs[] __initdata = {
 	NULL,		/* PSC0, selected by S6.8 */
 	&db1200_ide_dev,
@@ -436,6 +441,7 @@
 	&db1200_rtc_dev,
 	&db1200_nand_dev,
 	&db1200_audio_dev,
+	&db1200_stac_dev,
 };
 
 static int __init db1200_dev_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/prom.c linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/prom.c
--- linux-libre-2.6.36-gnu/arch/mips/alchemy/devboards/prom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/alchemy/devboards/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,10 +54,9 @@
 
 	prom_init_cmdline();
 	memsize_str = prom_getenv("memsize");
-	if (!memsize_str)
+	if (!memsize_str || strict_strtoul(memsize_str, 0, &memsize))
 		memsize = ALCHEMY_BOARD_DEFAULT_MEMSIZE;
-	else
-		strict_strtoul(memsize_str, 0, &memsize);
+
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/clock.c linux-libre-2.6.37-gnu/arch/mips/ar7/clock.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/clock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/clock.c	2011-01-04 19:50:19.000000000 -0500
@@ -239,12 +239,12 @@
 	calculate(base_clock, frequency, &prediv, &postdiv, &mul);
 
 	writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
-	msleep(1);
+	mdelay(1);
 	writel(4, &clock->pll);
 	while (readl(&clock->pll) & PLL_STATUS)
 		;
 	writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
-	msleep(75);
+	mdelay(75);
 }
 
 static void __init tnetd7300_init_clocks(void)
@@ -456,7 +456,7 @@
 }
 EXPORT_SYMBOL(clk_put);
 
-int __init ar7_init_clocks(void)
+void __init ar7_init_clocks(void)
 {
 	switch (ar7_chip_id()) {
 	case AR7_CHIP_7100:
@@ -472,7 +472,4 @@
 	}
 	/* adjust vbus clock rate */
 	vbus_clk.rate = bus_clk.rate / 2;
-
-	return 0;
 }
-arch_initcall(ar7_init_clocks);
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/gpio.c linux-libre-2.6.37-gnu/arch/mips/ar7/gpio.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
  * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
- * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,6 +37,16 @@
 	return readl(gpio_in) & (1 << gpio);
 }
 
+static int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ar7_gpio_chip *gpch =
+				container_of(chip, struct ar7_gpio_chip, chip);
+	void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0;
+	void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1;
+
+	return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f));
+}
+
 static void ar7_gpio_set_value(struct gpio_chip *chip,
 				unsigned gpio, int value)
 {
@@ -51,6 +61,21 @@
 	writel(tmp, gpio_out);
 }
 
+static void titan_gpio_set_value(struct gpio_chip *chip,
+				unsigned gpio, int value)
+{
+	struct ar7_gpio_chip *gpch =
+				container_of(chip, struct ar7_gpio_chip, chip);
+	void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0;
+	void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1;
+	unsigned tmp;
+
+	tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f));
+	if (value)
+		tmp |= 1 << (gpio & 0x1f);
+	writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0);
+}
+
 static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 {
 	struct ar7_gpio_chip *gpch =
@@ -62,6 +87,21 @@
 	return 0;
 }
 
+static int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	struct ar7_gpio_chip *gpch =
+				container_of(chip, struct ar7_gpio_chip, chip);
+	void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
+	void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
+
+	if (gpio >= TITAN_GPIO_MAX)
+		return -EINVAL;
+
+	writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)),
+			gpio >> 5 ? gpio_dir1 : gpio_dir0);
+	return 0;
+}
+
 static int ar7_gpio_direction_output(struct gpio_chip *chip,
 					unsigned gpio, int value)
 {
@@ -75,6 +115,24 @@
 	return 0;
 }
 
+static int titan_gpio_direction_output(struct gpio_chip *chip,
+					unsigned gpio, int value)
+{
+	struct ar7_gpio_chip *gpch =
+				container_of(chip, struct ar7_gpio_chip, chip);
+	void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0;
+	void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1;
+
+	if (gpio >= TITAN_GPIO_MAX)
+		return -EINVAL;
+
+	titan_gpio_set_value(chip, gpio, value);
+	writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 <<
+		(gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0);
+
+	return 0;
+}
+
 static struct ar7_gpio_chip ar7_gpio_chip = {
 	.chip = {
 		.label			= "ar7-gpio",
@@ -87,7 +145,19 @@
 	}
 };
 
-int ar7_gpio_enable(unsigned gpio)
+static struct ar7_gpio_chip titan_gpio_chip = {
+	.chip = {
+		.label			= "titan-gpio",
+		.direction_input	= titan_gpio_direction_input,
+		.direction_output	= titan_gpio_direction_output,
+		.set			= titan_gpio_set_value,
+		.get			= titan_gpio_get_value,
+		.base			= 0,
+		.ngpio			= TITAN_GPIO_MAX,
+	}
+};
+
+static inline int ar7_gpio_enable_ar7(unsigned gpio)
 {
 	void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
 
@@ -95,9 +165,26 @@
 
 	return 0;
 }
+
+static inline int ar7_gpio_enable_titan(unsigned gpio)
+{
+	void __iomem *gpio_en0 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_0;
+	void __iomem *gpio_en1 = titan_gpio_chip.regs  + TITAN_GPIO_ENBL_1;
+
+	writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)),
+		gpio >> 5 ? gpio_en1 : gpio_en0);
+
+	return 0;
+}
+
+int ar7_gpio_enable(unsigned gpio)
+{
+	return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) :
+				ar7_gpio_enable_ar7(gpio);
+}
 EXPORT_SYMBOL(ar7_gpio_enable);
 
-int ar7_gpio_disable(unsigned gpio)
+static inline int ar7_gpio_disable_ar7(unsigned gpio)
 {
 	void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE;
 
@@ -105,27 +192,159 @@
 
 	return 0;
 }
+
+static inline int ar7_gpio_disable_titan(unsigned gpio)
+{
+	void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0;
+	void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1;
+
+	writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)),
+			gpio >> 5 ? gpio_en1 : gpio_en0);
+
+	return 0;
+}
+
+int ar7_gpio_disable(unsigned gpio)
+{
+	return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) :
+				ar7_gpio_disable_ar7(gpio);
+}
 EXPORT_SYMBOL(ar7_gpio_disable);
 
-static int __init ar7_gpio_init(void)
+struct titan_gpio_cfg {
+	u32 reg;
+	u32 shift;
+	u32 func;
+};
+
+static struct titan_gpio_cfg titan_gpio_table[] = {
+	/* reg, start bit, mux value */
+	{4, 24, 1},
+	{4, 26, 1},
+	{4, 28, 1},
+	{4, 30, 1},
+	{5, 6, 1},
+	{5, 8, 1},
+	{5, 10, 1},
+	{5, 12, 1},
+	{7, 14, 3},
+	{7, 16, 3},
+	{7, 18, 3},
+	{7, 20, 3},
+	{7, 22, 3},
+	{7, 26, 3},
+	{7, 28, 3},
+	{7, 30, 3},
+	{8, 0, 3},
+	{8, 2, 3},
+	{8, 4, 3},
+	{8, 10, 3},
+	{8, 14, 3},
+	{8, 16, 3},
+	{8, 18, 3},
+	{8, 20, 3},
+	{9, 8, 3},
+	{9, 10, 3},
+	{9, 12, 3},
+	{9, 14, 3},
+	{9, 18, 3},
+	{9, 20, 3},
+	{9, 24, 3},
+	{9, 26, 3},
+	{9, 28, 3},
+	{9, 30, 3},
+	{10, 0, 3},
+	{10, 2, 3},
+	{10, 8, 3},
+	{10, 10, 3},
+	{10, 12, 3},
+	{10, 14, 3},
+	{13, 12, 3},
+	{13, 14, 3},
+	{13, 16, 3},
+	{13, 18, 3},
+	{13, 24, 3},
+	{13, 26, 3},
+	{13, 28, 3},
+	{13, 30, 3},
+	{14, 2, 3},
+	{14, 6, 3},
+	{14, 8, 3},
+	{14, 12, 3}
+};
+
+static int titan_gpio_pinsel(unsigned gpio)
+{
+	struct titan_gpio_cfg gpio_cfg;
+	u32 mux_status, pin_sel_reg, tmp;
+	void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL);
+
+	if (gpio >= ARRAY_SIZE(titan_gpio_table))
+		return -EINVAL;
+
+	gpio_cfg = titan_gpio_table[gpio];
+	pin_sel_reg = gpio_cfg.reg - 1;
+
+	mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3;
+
+	/* Check the mux status */
+	if (!((mux_status == 0) || (mux_status == gpio_cfg.func)))
+		return 0;
+
+	/* Set the pin sel value */
+	tmp = readl(pin_sel + pin_sel_reg);
+	tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift);
+	writel(tmp, pin_sel + pin_sel_reg);
+
+	return 0;
+}
+
+/* Perform minimal Titan GPIO configuration */
+static void titan_gpio_init(void)
+{
+	unsigned i;
+
+	for (i = 44; i < 48; i++) {
+		titan_gpio_pinsel(i);
+		ar7_gpio_enable_titan(i);
+		titan_gpio_direction_input(&titan_gpio_chip.chip, i);
+	}
+}
+
+int __init ar7_gpio_init(void)
 {
 	int ret;
+	struct ar7_gpio_chip *gpch;
+	unsigned size;
 
-	ar7_gpio_chip.regs = ioremap_nocache(AR7_REGS_GPIO,
+	if (!ar7_is_titan()) {
+		gpch = &ar7_gpio_chip;
+		size = 0x10;
+	} else {
+		gpch = &titan_gpio_chip;
+		size = 0x1f;
+	}
+
+	gpch->regs = ioremap_nocache(AR7_REGS_GPIO,
 					AR7_REGS_GPIO + 0x10);
 
-	if (!ar7_gpio_chip.regs) {
-		printk(KERN_ERR "ar7-gpio: failed to ioremap regs\n");
+	if (!gpch->regs) {
+		printk(KERN_ERR "%s: failed to ioremap regs\n",
+					gpch->chip.label);
 		return -ENOMEM;
 	}
 
-	ret = gpiochip_add(&ar7_gpio_chip.chip);
+	ret = gpiochip_add(&gpch->chip);
 	if (ret) {
-		printk(KERN_ERR "ar7-gpio: failed to add gpiochip\n");
+		printk(KERN_ERR "%s: failed to add gpiochip\n",
+					gpch->chip.label);
 		return ret;
 	}
-	printk(KERN_INFO "ar7-gpio: registered %d GPIOs\n",
-				ar7_gpio_chip.chip.ngpio);
+	printk(KERN_INFO "%s: registered %d GPIOs\n",
+				gpch->chip.label, gpch->chip.ngpio);
+
+	if (ar7_is_titan())
+		titan_gpio_init();
+
 	return ret;
 }
-arch_initcall(ar7_gpio_init);
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/irq.c linux-libre-2.6.37-gnu/arch/mips/ar7/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/platform.c linux-libre-2.6.37-gnu/arch/mips/ar7/platform.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -357,6 +357,11 @@
 	},
 };
 
+static struct gpio_led titan_leds[] = {
+	{ .name = "status", .gpio = 8, .active_low = 1, },
+	{ .name = "wifi", .gpio = 13, .active_low = 1, },
+};
+
 static struct gpio_led dsl502t_leds[] = {
 	{
 		.name			= "status",
@@ -495,6 +500,9 @@
 	} else if (strstr(prid, "DG834")) {
 		ar7_led_data.num_leds = ARRAY_SIZE(dg834g_leds);
 		ar7_led_data.leds = dg834g_leds;
+	} else if (strstr(prid, "CYWM") || strstr(prid, "CYWL")) {
+		ar7_led_data.num_leds = ARRAY_SIZE(titan_leds);
+		ar7_led_data.leds = titan_leds;
 	}
 }
 
@@ -560,6 +568,51 @@
 	return 0;
 }
 
+static void __init titan_fixup_devices(void)
+{
+	/* Set vlynq0 data */
+	vlynq_low_data.reset_bit = 15;
+	vlynq_low_data.gpio_bit = 14;
+
+	/* Set vlynq1 data */
+	vlynq_high_data.reset_bit = 16;
+	vlynq_high_data.gpio_bit = 7;
+
+	/* Set vlynq0 resources */
+	vlynq_low_res[0].start = TITAN_REGS_VLYNQ0;
+	vlynq_low_res[0].end = TITAN_REGS_VLYNQ0 + 0xff;
+	vlynq_low_res[1].start = 33;
+	vlynq_low_res[1].end = 33;
+	vlynq_low_res[2].start = 0x0c000000;
+	vlynq_low_res[2].end = 0x0fffffff;
+	vlynq_low_res[3].start = 80;
+	vlynq_low_res[3].end = 111;
+
+	/* Set vlynq1 resources */
+	vlynq_high_res[0].start = TITAN_REGS_VLYNQ1;
+	vlynq_high_res[0].end = TITAN_REGS_VLYNQ1 + 0xff;
+	vlynq_high_res[1].start = 34;
+	vlynq_high_res[1].end = 34;
+	vlynq_high_res[2].start = 0x40000000;
+	vlynq_high_res[2].end = 0x43ffffff;
+	vlynq_high_res[3].start = 112;
+	vlynq_high_res[3].end = 143;
+
+	/* Set cpmac0 data */
+	cpmac_low_data.phy_mask = 0x40000000;
+
+	/* Set cpmac1 data */
+	cpmac_high_data.phy_mask = 0x80000000;
+
+	/* Set cpmac0 resources */
+	cpmac_low_res[0].start = TITAN_REGS_MAC0;
+	cpmac_low_res[0].end = TITAN_REGS_MAC0 + 0x7ff;
+
+	/* Set cpmac1 resources */
+	cpmac_high_res[0].start = TITAN_REGS_MAC1;
+	cpmac_high_res[0].end = TITAN_REGS_MAC1 + 0x7ff;
+}
+
 static int __init ar7_register_devices(void)
 {
 	void __iomem *bootcr;
@@ -574,6 +627,9 @@
 	if (res)
 		pr_warning("unable to register physmap-flash: %d\n", res);
 
+	if (ar7_is_titan())
+		titan_fixup_devices();
+
 	ar7_device_disable(vlynq_low_data.reset_bit);
 	res = platform_device_register(&vlynq_low);
 	if (res)
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/prom.c linux-libre-2.6.37-gnu/arch/mips/ar7/prom.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/prom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -246,6 +246,8 @@
 	ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
 	ar7_init_env((struct env_var *)fw_arg2);
 	console_config();
+
+	ar7_gpio_init();
 }
 
 #define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/setup.c linux-libre-2.6.37-gnu/arch/mips/ar7/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,7 @@
 #include <asm/reboot.h>
 #include <asm/mach-ar7/ar7.h>
 #include <asm/mach-ar7/prom.h>
+#include <asm/mach-ar7/gpio.h>
 
 static void ar7_machine_restart(char *command)
 {
@@ -49,6 +50,8 @@
 const char *get_system_type(void)
 {
 	u16 chip_id = ar7_chip_id();
+	u16 titan_variant_id = titan_chip_id();
+
 	switch (chip_id) {
 	case AR7_CHIP_7100:
 		return "TI AR7 (TNETD7100)";
@@ -56,6 +59,17 @@
 		return "TI AR7 (TNETD7200)";
 	case AR7_CHIP_7300:
 		return "TI AR7 (TNETD7300)";
+	case AR7_CHIP_TITAN:
+		switch (titan_variant_id) {
+		case TITAN_CHIP_1050:
+			return "TI AR7 (TNETV1050)";
+		case TITAN_CHIP_1055:
+			return "TI AR7 (TNETV1055)";
+		case TITAN_CHIP_1056:
+			return "TI AR7 (TNETV1056)";
+		case TITAN_CHIP_1060:
+			return "TI AR7 (TNETV1060)";
+		}
 	default:
 		return "TI AR7 (unknown)";
 	}
diff -druN linux-libre-2.6.36-gnu/arch/mips/ar7/time.c linux-libre-2.6.37-gnu/arch/mips/ar7/time.c
--- linux-libre-2.6.36-gnu/arch/mips/ar7/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/ar7/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,9 @@
 {
 	struct clk *cpu_clk;
 
+	/* Initialize ar7 clocks so the CPU clock frequency is correct */
+	ar7_init_clocks();
+
 	cpu_clk = clk_get(NULL, "cpu");
 	if (IS_ERR(cpu_clk)) {
 		printk(KERN_ERR "unable to get cpu clock\n");
diff -druN linux-libre-2.6.36-gnu/arch/mips/bcm47xx/setup.c linux-libre-2.6.37-gnu/arch/mips/bcm47xx/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/bcm47xx/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/bcm47xx/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,6 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
-#include <asm/fw/cfe/cfe_api.h>
 #include <asm/mach-bcm47xx/nvram.h>
 
 struct ssb_bus ssb_bcm47xx;
@@ -57,68 +56,112 @@
 		cpu_relax();
 }
 
-static void str2eaddr(char *str, char *dest)
+#define READ_FROM_NVRAM(_outvar, name, buf) \
+	if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\
+		sprom->_outvar = simple_strtoul(buf, NULL, 0);
+
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
 {
-	int i = 0;
+	char buf[100];
+	u32 boardflags;
 
-	if (str == NULL) {
-		memset(dest, 0, 6);
-		return;
-	}
+	memset(sprom, 0, sizeof(struct ssb_sprom));
 
-	for (;;) {
-		dest[i++] = (char) simple_strtoul(str, NULL, 16);
-		str += 2;
-		if (!*str++ || i == 6)
-			break;
+	sprom->revision = 1; /* Fallback: Old hardware does not define this. */
+	READ_FROM_NVRAM(revision, "sromrev", buf);
+	if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
+		nvram_parse_macaddr(buf, sprom->il0mac);
+	if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+		nvram_parse_macaddr(buf, sprom->et0mac);
+	if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+		nvram_parse_macaddr(buf, sprom->et1mac);
+	READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
+	READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
+	READ_FROM_NVRAM(et0mdcport, "et0mdcport", buf);
+	READ_FROM_NVRAM(et1mdcport, "et1mdcport", buf);
+	READ_FROM_NVRAM(board_rev, "boardrev", buf);
+	READ_FROM_NVRAM(country_code, "ccode", buf);
+	READ_FROM_NVRAM(ant_available_a, "aa5g", buf);
+	READ_FROM_NVRAM(ant_available_bg, "aa2g", buf);
+	READ_FROM_NVRAM(pa0b0, "pa0b0", buf);
+	READ_FROM_NVRAM(pa0b1, "pa0b1", buf);
+	READ_FROM_NVRAM(pa0b2, "pa0b2", buf);
+	READ_FROM_NVRAM(pa1b0, "pa1b0", buf);
+	READ_FROM_NVRAM(pa1b1, "pa1b1", buf);
+	READ_FROM_NVRAM(pa1b2, "pa1b2", buf);
+	READ_FROM_NVRAM(pa1lob0, "pa1lob0", buf);
+	READ_FROM_NVRAM(pa1lob2, "pa1lob1", buf);
+	READ_FROM_NVRAM(pa1lob1, "pa1lob2", buf);
+	READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
+	READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
+	READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
+	READ_FROM_NVRAM(gpio0, "wl0gpio0", buf);
+	READ_FROM_NVRAM(gpio1, "wl0gpio1", buf);
+	READ_FROM_NVRAM(gpio2, "wl0gpio2", buf);
+	READ_FROM_NVRAM(gpio3, "wl0gpio3", buf);
+	READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf);
+	READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf);
+	READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf);
+	READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf);
+	READ_FROM_NVRAM(itssi_a, "pa1itssit", buf);
+	READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf);
+	READ_FROM_NVRAM(tri2g, "tri2g", buf);
+	READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
+	READ_FROM_NVRAM(tri5g, "tri5g", buf);
+	READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
+	READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
+	READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
+	READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
+	READ_FROM_NVRAM(rssismc2g, "rssismc2g", buf);
+	READ_FROM_NVRAM(rssismf2g, "rssismf2g", buf);
+	READ_FROM_NVRAM(bxa2g, "bxa2g", buf);
+	READ_FROM_NVRAM(rssisav5g, "rssisav5g", buf);
+	READ_FROM_NVRAM(rssismc5g, "rssismc5g", buf);
+	READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
+	READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
+	READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
+	READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf);
+	READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf);
+	READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf);
+	READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf);
+
+	if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) {
+		boardflags = simple_strtoul(buf, NULL, 0);
+		if (boardflags) {
+			sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
+			sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
+		}
+	}
+	if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) {
+		boardflags = simple_strtoul(buf, NULL, 0);
+		if (boardflags) {
+			sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
+			sprom->boardflags2_hi = (boardflags & 0xFFFF0000U) >> 16;
+		}
 	}
 }
 
 static int bcm47xx_get_invariants(struct ssb_bus *bus,
 				   struct ssb_init_invariants *iv)
 {
-	char buf[100];
+	char buf[20];
 
 	/* Fill boardinfo structure */
 	memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
 
-	if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
-		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
-	if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
+	if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
+		iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0);
+	else
+		iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
+	if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
 		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
-	if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
+	if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
 		iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
 
-	/* Fill sprom structure */
-	memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
-	iv->sprom.revision = 3;
-
-	if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
-		str2eaddr(buf, iv->sprom.et0mac);
-
-	if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
-		str2eaddr(buf, iv->sprom.et1mac);
-
-	if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
-		iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
-
-	if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
-		iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
-
-	if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
-		iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
+	bcm47xx_fill_sprom(&iv->sprom);
 
-	if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
-	    nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
-		iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
+	if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
+		iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
 
 	return 0;
 }
@@ -126,12 +169,28 @@
 void __init plat_mem_setup(void)
 {
 	int err;
+	char buf[100];
+	struct ssb_mipscore *mcore;
 
 	err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
 				      bcm47xx_get_invariants);
 	if (err)
 		panic("Failed to initialize SSB bus (err %d)\n", err);
 
+	mcore = &ssb_bcm47xx.mipscore;
+	if (nvram_getenv("kernel_args", buf, sizeof(buf)) >= 0) {
+		if (strstr(buf, "console=ttyS1")) {
+			struct ssb_serial_port port;
+
+			printk(KERN_DEBUG "Swapping serial ports!\n");
+			/* swap serial ports */
+			memcpy(&port, &mcore->serial_ports[0], sizeof(port));
+			memcpy(&mcore->serial_ports[0], &mcore->serial_ports[1],
+			       sizeof(port));
+			memcpy(&mcore->serial_ports[1], &port, sizeof(port));
+		}
+	}
+
 	_machine_restart = bcm47xx_machine_restart;
 	_machine_halt = bcm47xx_machine_halt;
 	pm_power_off = bcm47xx_machine_halt;
diff -druN linux-libre-2.6.36-gnu/arch/mips/bcm63xx/cpu.c linux-libre-2.6.37-gnu/arch/mips/bcm63xx/cpu.c
--- linux-libre-2.6.36-gnu/arch/mips/bcm63xx/cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/bcm63xx/cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/cpu.h>
+#include <asm/cpu.h>
 #include <asm/cpu-info.h>
+#include <asm/mipsregs.h>
 #include <bcm63xx_cpu.h>
 #include <bcm63xx_regs.h>
 #include <bcm63xx_io.h>
@@ -296,26 +298,24 @@
 	expected_cpu_id = 0;
 
 	switch (c->cputype) {
-	/*
-	 * BCM6338 as the same PrId as BCM3302 see arch/mips/kernel/cpu-probe.c
-	 */
-	case CPU_BCM3302:
-		__cpu_name[cpu] = "Broadcom BCM6338";
-		expected_cpu_id = BCM6338_CPU_ID;
-		bcm63xx_regs_base = bcm96338_regs_base;
-		bcm63xx_irqs = bcm96338_irqs;
+	case CPU_BMIPS3300:
+		if ((read_c0_prid() & 0xff00) == PRID_IMP_BMIPS3300_ALT) {
+			expected_cpu_id = BCM6348_CPU_ID;
+			bcm63xx_regs_base = bcm96348_regs_base;
+			bcm63xx_irqs = bcm96348_irqs;
+		} else {
+			__cpu_name[cpu] = "Broadcom BCM6338";
+			expected_cpu_id = BCM6338_CPU_ID;
+			bcm63xx_regs_base = bcm96338_regs_base;
+			bcm63xx_irqs = bcm96338_irqs;
+		}
 		break;
-	case CPU_BCM6345:
+	case CPU_BMIPS32:
 		expected_cpu_id = BCM6345_CPU_ID;
 		bcm63xx_regs_base = bcm96345_regs_base;
 		bcm63xx_irqs = bcm96345_irqs;
 		break;
-	case CPU_BCM6348:
-		expected_cpu_id = BCM6348_CPU_ID;
-		bcm63xx_regs_base = bcm96348_regs_base;
-		bcm63xx_irqs = bcm96348_irqs;
-		break;
-	case CPU_BCM6358:
+	case CPU_BMIPS4350:
 		expected_cpu_id = BCM6358_CPU_ID;
 		bcm63xx_regs_base = bcm96358_regs_base;
 		bcm63xx_irqs = bcm96358_irqs;
diff -druN linux-libre-2.6.36-gnu/arch/mips/bcm63xx/irq.c linux-libre-2.6.37-gnu/arch/mips/bcm63xx/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/bcm63xx/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/bcm63xx/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <bcm63xx_cpu.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/csrc-octeon.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/csrc-octeon.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/csrc-octeon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/csrc-octeon.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,14 +4,18 @@
  * for more details.
  *
  * Copyright (C) 2007 by Ralf Baechle
+ * Copyright (C) 2009, 2010 Cavium Networks, Inc.
  */
 #include <linux/clocksource.h>
 #include <linux/init.h>
+#include <linux/smp.h>
 
+#include <asm/cpu-info.h>
 #include <asm/time.h>
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-ipd-defs.h>
+#include <asm/octeon/cvmx-mio-defs.h>
 
 /*
  * Set the current core's cvmcount counter to the value of the
@@ -19,11 +23,23 @@
  * on-line.  This allows for a read from a local cpu register to
  * access a synchronized counter.
  *
+ * On CPU_CAVIUM_OCTEON2 the IPD_CLK_COUNT is scaled by rdiv/sdiv.
  */
 void octeon_init_cvmcount(void)
 {
 	unsigned long flags;
 	unsigned loops = 2;
+	u64 f = 0;
+	u64 rdiv = 0;
+	u64 sdiv = 0;
+	if (current_cpu_type() == CPU_CAVIUM_OCTEON2) {
+		union cvmx_mio_rst_boot rst_boot;
+		rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
+		rdiv = rst_boot.s.c_mul;	/* CPU clock */
+		sdiv = rst_boot.s.pnr_mul;	/* I/O clock */
+		f = (0x8000000000000000ull / sdiv) * 2;
+	}
+
 
 	/* Clobber loops so GCC will not unroll the following while loop. */
 	asm("" : "+r" (loops));
@@ -33,8 +49,20 @@
 	 * Loop several times so we are executing from the cache,
 	 * which should give more deterministic timing.
 	 */
-	while (loops--)
-		write_c0_cvmcount(cvmx_read_csr(CVMX_IPD_CLK_COUNT));
+	while (loops--) {
+		u64 ipd_clk_count = cvmx_read_csr(CVMX_IPD_CLK_COUNT);
+		if (rdiv != 0) {
+			ipd_clk_count *= rdiv;
+			if (f != 0) {
+				asm("dmultu\t%[cnt],%[f]\n\t"
+				    "mfhi\t%[cnt]"
+				    : [cnt] "+r" (ipd_clk_count),
+				      [f] "=r" (f)
+				    : : "hi", "lo");
+			}
+		}
+		write_c0_cvmcount(ipd_clk_count);
+	}
 	local_irq_restore(flags);
 }
 
@@ -77,7 +105,7 @@
 void __init plat_time_init(void)
 {
 	clocksource_mips.rating = 300;
-	clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
+	clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate());
 	clocksource_register(&clocksource_mips);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/dma-octeon.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/dma-octeon.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/dma-octeon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/dma-octeon.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,335 +8,342 @@
  * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
  * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
  * IP32 changes by Ilya.
- * Cavium Networks: Create new dma setup for Cavium Networks Octeon based on
- * the kernels original.
+ * Copyright (C) 2010 Cavium Networks, Inc.
  */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
 #include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
 #include <linux/scatterlist.h>
+#include <linux/bootmem.h>
+#include <linux/swiotlb.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
 
-#include <linux/cache.h>
-#include <linux/io.h>
+#include <asm/bootinfo.h>
 
 #include <asm/octeon/octeon.h>
+
+#ifdef CONFIG_PCI
+#include <asm/octeon/pci-octeon.h>
 #include <asm/octeon/cvmx-npi-defs.h>
 #include <asm/octeon/cvmx-pci-defs.h>
 
-#include <dma-coherence.h>
+static dma_addr_t octeon_hole_phys_to_dma(phys_addr_t paddr)
+{
+	if (paddr >= CVMX_PCIE_BAR1_PHYS_BASE && paddr < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE))
+		return paddr - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE;
+	else
+		return paddr;
+}
 
-#ifdef CONFIG_PCI
-#include <asm/octeon/pci-octeon.h>
-#endif
+static phys_addr_t octeon_hole_dma_to_phys(dma_addr_t daddr)
+{
+	if (daddr >= CVMX_PCIE_BAR1_RC_BASE)
+		return daddr + CVMX_PCIE_BAR1_PHYS_BASE - CVMX_PCIE_BAR1_RC_BASE;
+	else
+		return daddr;
+}
 
-#define BAR2_PCI_ADDRESS 0x8000000000ul
+static dma_addr_t octeon_gen1_phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	if (paddr >= 0x410000000ull && paddr < 0x420000000ull)
+		paddr -= 0x400000000ull;
+	return octeon_hole_phys_to_dma(paddr);
+}
 
-struct bar1_index_state {
-	int16_t ref_count;	/* Number of PCI mappings using this index */
-	uint16_t address_bits;	/* Upper bits of physical address. This is
-				   shifted 22 bits */
-};
+static phys_addr_t octeon_gen1_dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	daddr = octeon_hole_dma_to_phys(daddr);
 
-#ifdef CONFIG_PCI
-static DEFINE_RAW_SPINLOCK(bar1_lock);
-static struct bar1_index_state bar1_state[32];
-#endif
+	if (daddr >= 0x10000000ull && daddr < 0x20000000ull)
+		daddr += 0x400000000ull;
 
-dma_addr_t octeon_map_dma_mem(struct device *dev, void *ptr, size_t size)
+	return daddr;
+}
+
+static dma_addr_t octeon_big_phys_to_dma(struct device *dev, phys_addr_t paddr)
 {
-#ifndef CONFIG_PCI
-	/* Without PCI/PCIe this function can be called for Octeon internal
-	   devices such as USB. These devices all support 64bit addressing */
+	if (paddr >= 0x410000000ull && paddr < 0x420000000ull)
+		paddr -= 0x400000000ull;
+
+	/* Anything in the BAR1 hole or above goes via BAR2 */
+	if (paddr >= 0xf0000000ull)
+		paddr = OCTEON_BAR2_PCI_ADDRESS + paddr;
+
+	return paddr;
+}
+
+static phys_addr_t octeon_big_dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	if (daddr >= OCTEON_BAR2_PCI_ADDRESS)
+		daddr -= OCTEON_BAR2_PCI_ADDRESS;
+
+	if (daddr >= 0x10000000ull && daddr < 0x20000000ull)
+		daddr += 0x400000000ull;
+	return daddr;
+}
+
+static dma_addr_t octeon_small_phys_to_dma(struct device *dev,
+					   phys_addr_t paddr)
+{
+	if (paddr >= 0x410000000ull && paddr < 0x420000000ull)
+		paddr -= 0x400000000ull;
+
+	/* Anything not in the BAR1 range goes via BAR2 */
+	if (paddr >= octeon_bar1_pci_phys && paddr < octeon_bar1_pci_phys + 0x8000000ull)
+		paddr = paddr - octeon_bar1_pci_phys;
+	else
+		paddr = OCTEON_BAR2_PCI_ADDRESS + paddr;
+
+	return paddr;
+}
+
+static phys_addr_t octeon_small_dma_to_phys(struct device *dev,
+					    dma_addr_t daddr)
+{
+	if (daddr >= OCTEON_BAR2_PCI_ADDRESS)
+		daddr -= OCTEON_BAR2_PCI_ADDRESS;
+	else
+		daddr += octeon_bar1_pci_phys;
+
+	if (daddr >= 0x10000000ull && daddr < 0x20000000ull)
+		daddr += 0x400000000ull;
+	return daddr;
+}
+
+#endif /* CONFIG_PCI */
+
+static dma_addr_t octeon_dma_map_page(struct device *dev, struct page *page,
+	unsigned long offset, size_t size, enum dma_data_direction direction,
+	struct dma_attrs *attrs)
+{
+	dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
+					    direction, attrs);
 	mb();
-	return virt_to_phys(ptr);
-#else
-	unsigned long flags;
-	uint64_t dma_mask;
-	int64_t start_index;
-	dma_addr_t result = -1;
-	uint64_t physical = virt_to_phys(ptr);
-	int64_t index;
 
+	return daddr;
+}
+
+static int octeon_dma_map_sg(struct device *dev, struct scatterlist *sg,
+	int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
+{
+	int r = swiotlb_map_sg_attrs(dev, sg, nents, direction, attrs);
 	mb();
-	/*
-	 * Use the DMA masks to determine the allowed memory
-	 * region. For us it doesn't limit the actual memory, just the
-	 * address visible over PCI.  Devices with limits need to use
-	 * lower indexed Bar1 entries.
-	 */
-	if (dev) {
-		dma_mask = dev->coherent_dma_mask;
-		if (dev->dma_mask)
-			dma_mask = *dev->dma_mask;
-	} else {
-		dma_mask = 0xfffffffful;
-	}
+	return r;
+}
 
-	/*
-	 * Platform devices, such as the internal USB, skip all
-	 * translation and use Octeon physical addresses directly.
-	 */
-	if (!dev || dev->bus == &platform_bus_type)
-		return physical;
+static void octeon_dma_sync_single_for_device(struct device *dev,
+	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
+{
+	swiotlb_sync_single_for_device(dev, dma_handle, size, direction);
+	mb();
+}
 
-	switch (octeon_dma_bar_type) {
-	case OCTEON_DMA_BAR_TYPE_PCIE:
-		if (unlikely(physical < (16ul << 10)))
-			panic("dma_map_single: Not allowed to map first 16KB."
-			      " It interferes with BAR0 special area\n");
-		else if ((physical + size >= (256ul << 20)) &&
-			 (physical < (512ul << 20)))
-			panic("dma_map_single: Not allowed to map bootbus\n");
-		else if ((physical + size >= 0x400000000ull) &&
-			 physical < 0x410000000ull)
-			panic("dma_map_single: "
-			      "Attempt to map illegal memory address 0x%llx\n",
-			      physical);
-		else if (physical >= 0x420000000ull)
-			panic("dma_map_single: "
-			      "Attempt to map illegal memory address 0x%llx\n",
-			      physical);
-		else if (physical >= CVMX_PCIE_BAR1_PHYS_BASE &&
-			 physical + size < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE)) {
-			result = physical - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE;
+static void octeon_dma_sync_sg_for_device(struct device *dev,
+	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
+{
+	swiotlb_sync_sg_for_device(dev, sg, nelems, direction);
+	mb();
+}
 
-			if (((result+size-1) & dma_mask) != result+size-1)
-				panic("dma_map_single: Attempt to map address 0x%llx-0x%llx, which can't be accessed according to the dma mask 0x%llx\n",
-				      physical, physical+size-1, dma_mask);
-			goto done;
-		}
+static void *octeon_dma_alloc_coherent(struct device *dev, size_t size,
+	dma_addr_t *dma_handle, gfp_t gfp)
+{
+	void *ret;
 
-		/* The 2nd 256MB is mapped at 256<<20 instead of 0x410000000 */
-		if ((physical >= 0x410000000ull) && physical < 0x420000000ull)
-			result = physical - 0x400000000ull;
-		else
-			result = physical;
-		if (((result+size-1) & dma_mask) != result+size-1)
-			panic("dma_map_single: Attempt to map address "
-			      "0x%llx-0x%llx, which can't be accessed "
-			      "according to the dma mask 0x%llx\n",
-			      physical, physical+size-1, dma_mask);
-		goto done;
+	if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
+		return ret;
 
-	case OCTEON_DMA_BAR_TYPE_BIG:
-#ifdef CONFIG_64BIT
-		/* If the device supports 64bit addressing, then use BAR2 */
-		if (dma_mask > BAR2_PCI_ADDRESS) {
-			result = physical + BAR2_PCI_ADDRESS;
-			goto done;
-		}
-#endif
-		if (unlikely(physical < (4ul << 10))) {
-			panic("dma_map_single: Not allowed to map first 4KB. "
-			      "It interferes with BAR0 special area\n");
-		} else if (physical < (256ul << 20)) {
-			if (unlikely(physical + size > (256ul << 20)))
-				panic("dma_map_single: Requested memory spans "
-				      "Bar0 0:256MB and bootbus\n");
-			result = physical;
-			goto done;
-		} else if (unlikely(physical < (512ul << 20))) {
-			panic("dma_map_single: Not allowed to map bootbus\n");
-		} else if (physical < (2ul << 30)) {
-			if (unlikely(physical + size > (2ul << 30)))
-				panic("dma_map_single: Requested memory spans "
-				      "Bar0 512MB:2GB and BAR1\n");
-			result = physical;
-			goto done;
-		} else if (physical < (2ul << 30) + (128 << 20)) {
-			/* Fall through */
-		} else if (physical <
-			   (4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20)) {
-			if (unlikely
-			    (physical + size >
-			     (4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20)))
-				panic("dma_map_single: Requested memory "
-				      "extends past Bar1 (4GB-%luMB)\n",
-				      OCTEON_PCI_BAR1_HOLE_SIZE);
-			result = physical;
-			goto done;
-		} else if ((physical >= 0x410000000ull) &&
-			   (physical < 0x420000000ull)) {
-			if (unlikely(physical + size > 0x420000000ull))
-				panic("dma_map_single: Requested memory spans "
-				      "non existant memory\n");
-			/* BAR0 fixed mapping 256MB:512MB ->
-			 * 16GB+256MB:16GB+512MB */
-			result = physical - 0x400000000ull;
-			goto done;
-		} else {
-			/* Continued below switch statement */
-		}
-		break;
+	/* ignore region specifiers */
+	gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
 
-	case OCTEON_DMA_BAR_TYPE_SMALL:
-#ifdef CONFIG_64BIT
-		/* If the device supports 64bit addressing, then use BAR2 */
-		if (dma_mask > BAR2_PCI_ADDRESS) {
-			result = physical + BAR2_PCI_ADDRESS;
-			goto done;
-		}
+#ifdef CONFIG_ZONE_DMA
+	if (dev == NULL)
+		gfp |= __GFP_DMA;
+	else if (dev->coherent_dma_mask <= DMA_BIT_MASK(24))
+		gfp |= __GFP_DMA;
+	else
 #endif
-		/* Continued below switch statement */
-		break;
+#ifdef CONFIG_ZONE_DMA32
+	     if (dev->coherent_dma_mask <= DMA_BIT_MASK(32))
+		gfp |= __GFP_DMA32;
+	else
+#endif
+		;
 
-	default:
-		panic("dma_map_single: Invalid octeon_dma_bar_type\n");
-	}
+	/* Don't invoke OOM killer */
+	gfp |= __GFP_NORETRY;
 
-	/* Don't allow mapping to span multiple Bar entries. The hardware guys
-	   won't guarantee that DMA across boards work */
-	if (unlikely((physical >> 22) != ((physical + size - 1) >> 22)))
-		panic("dma_map_single: "
-		      "Requested memory spans more than one Bar1 entry\n");
+	ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
 
-	if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG)
-		start_index = 31;
-	else if (unlikely(dma_mask < (1ul << 27)))
-		start_index = (dma_mask >> 22);
-	else
-		start_index = 31;
+	mb();
 
-	/* Only one processor can access the Bar register at once */
-	raw_spin_lock_irqsave(&bar1_lock, flags);
+	return ret;
+}
 
-	/* Look through Bar1 for existing mapping that will work */
-	for (index = start_index; index >= 0; index--) {
-		if ((bar1_state[index].address_bits == physical >> 22) &&
-		    (bar1_state[index].ref_count)) {
-			/* An existing mapping will work, use it */
-			bar1_state[index].ref_count++;
-			if (unlikely(bar1_state[index].ref_count < 0))
-				panic("dma_map_single: "
-				      "Bar1[%d] reference count overflowed\n",
-				      (int) index);
-			result = (index << 22) | (physical & ((1 << 22) - 1));
-			/* Large BAR1 is offset at 2GB */
-			if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG)
-				result += 2ul << 30;
-			goto done_unlock;
-		}
-	}
+static void octeon_dma_free_coherent(struct device *dev, size_t size,
+	void *vaddr, dma_addr_t dma_handle)
+{
+	int order = get_order(size);
 
-	/* No existing mappings, look for a free entry */
-	for (index = start_index; index >= 0; index--) {
-		if (unlikely(bar1_state[index].ref_count == 0)) {
-			union cvmx_pci_bar1_indexx bar1_index;
-			/* We have a free entry, use it */
-			bar1_state[index].ref_count = 1;
-			bar1_state[index].address_bits = physical >> 22;
-			bar1_index.u32 = 0;
-			/* Address bits[35:22] sent to L2C */
-			bar1_index.s.addr_idx = physical >> 22;
-			/* Don't put PCI accesses in L2. */
-			bar1_index.s.ca = 1;
-			/* Endian Swap Mode */
-			bar1_index.s.end_swp = 1;
-			/* Set '1' when the selected address range is valid. */
-			bar1_index.s.addr_v = 1;
-			octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index),
-					   bar1_index.u32);
-			/* An existing mapping will work, use it */
-			result = (index << 22) | (physical & ((1 << 22) - 1));
-			/* Large BAR1 is offset at 2GB */
-			if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG)
-				result += 2ul << 30;
-			goto done_unlock;
-		}
-	}
+	if (dma_release_from_coherent(dev, order, vaddr))
+		return;
 
-	pr_err("dma_map_single: "
-	       "Can't find empty BAR1 index for physical mapping 0x%llx\n",
-	       (unsigned long long) physical);
+	swiotlb_free_coherent(dev, size, vaddr, dma_handle);
+}
 
-done_unlock:
-	raw_spin_unlock_irqrestore(&bar1_lock, flags);
-done:
-	pr_debug("dma_map_single 0x%llx->0x%llx\n", physical, result);
-	return result;
-#endif
+static dma_addr_t octeon_unity_phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	return paddr;
 }
 
-void octeon_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr)
+static phys_addr_t octeon_unity_dma_to_phys(struct device *dev, dma_addr_t daddr)
 {
-#ifndef CONFIG_PCI
-	/*
-	 * Without PCI/PCIe this function can be called for Octeon internal
-	 * devices such as USB. These devices all support 64bit addressing.
-	 */
-	return;
-#else
-	unsigned long flags;
-	uint64_t index;
+	return daddr;
+}
+
+struct octeon_dma_map_ops {
+	struct dma_map_ops dma_map_ops;
+	dma_addr_t (*phys_to_dma)(struct device *dev, phys_addr_t paddr);
+	phys_addr_t (*dma_to_phys)(struct device *dev, dma_addr_t daddr);
+};
+
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+	struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev),
+						      struct octeon_dma_map_ops,
+						      dma_map_ops);
+
+	return ops->phys_to_dma(dev, paddr);
+}
+EXPORT_SYMBOL(phys_to_dma);
+
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+	struct octeon_dma_map_ops *ops = container_of(get_dma_ops(dev),
+						      struct octeon_dma_map_ops,
+						      dma_map_ops);
+
+	return ops->dma_to_phys(dev, daddr);
+}
+EXPORT_SYMBOL(dma_to_phys);
+
+static struct octeon_dma_map_ops octeon_linear_dma_map_ops = {
+	.dma_map_ops = {
+		.alloc_coherent = octeon_dma_alloc_coherent,
+		.free_coherent = octeon_dma_free_coherent,
+		.map_page = octeon_dma_map_page,
+		.unmap_page = swiotlb_unmap_page,
+		.map_sg = octeon_dma_map_sg,
+		.unmap_sg = swiotlb_unmap_sg_attrs,
+		.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+		.sync_single_for_device = octeon_dma_sync_single_for_device,
+		.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+		.sync_sg_for_device = octeon_dma_sync_sg_for_device,
+		.mapping_error = swiotlb_dma_mapping_error,
+		.dma_supported = swiotlb_dma_supported
+	},
+	.phys_to_dma = octeon_unity_phys_to_dma,
+	.dma_to_phys = octeon_unity_dma_to_phys
+};
+
+char *octeon_swiotlb;
 
+void __init plat_swiotlb_setup(void)
+{
+	int i;
+	phys_t max_addr;
+	phys_t addr_size;
+	size_t swiotlbsize;
+	unsigned long swiotlb_nslabs;
+
+	max_addr = 0;
+	addr_size = 0;
+
+	for (i = 0 ; i < boot_mem_map.nr_map; i++) {
+		struct boot_mem_map_entry *e = &boot_mem_map.map[i];
+		if (e->type != BOOT_MEM_RAM)
+			continue;
+
+		/* These addresses map low for PCI. */
+		if (e->addr > 0x410000000ull)
+			continue;
+
+		addr_size += e->size;
+
+		if (max_addr < e->addr + e->size)
+			max_addr = e->addr + e->size;
+
+	}
+
+	swiotlbsize = PAGE_SIZE;
+
+#ifdef CONFIG_PCI
 	/*
-	 * Platform devices, such as the internal USB, skip all
-	 * translation and use Octeon physical addresses directly.
+	 * For OCTEON_DMA_BAR_TYPE_SMALL, size the iotlb at 1/4 memory
+	 * size to a maximum of 64MB
 	 */
-	if (dev->bus == &platform_bus_type)
-		return;
+	if (OCTEON_IS_MODEL(OCTEON_CN31XX)
+	    || OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2)) {
+		swiotlbsize = addr_size / 4;
+		if (swiotlbsize > 64 * (1<<20))
+			swiotlbsize = 64 * (1<<20);
+	} else if (max_addr > 0xf0000000ul) {
+		/*
+		 * Otherwise only allocate a big iotlb if there is
+		 * memory past the BAR1 hole.
+		 */
+		swiotlbsize = 64 * (1<<20);
+	}
+#endif
+	swiotlb_nslabs = swiotlbsize >> IO_TLB_SHIFT;
+	swiotlb_nslabs = ALIGN(swiotlb_nslabs, IO_TLB_SEGSIZE);
+	swiotlbsize = swiotlb_nslabs << IO_TLB_SHIFT;
+
+	octeon_swiotlb = alloc_bootmem_low_pages(swiotlbsize);
 
+	swiotlb_init_with_tbl(octeon_swiotlb, swiotlb_nslabs, 1);
+
+	mips_dma_map_ops = &octeon_linear_dma_map_ops.dma_map_ops;
+}
+
+#ifdef CONFIG_PCI
+static struct octeon_dma_map_ops _octeon_pci_dma_map_ops = {
+	.dma_map_ops = {
+		.alloc_coherent = octeon_dma_alloc_coherent,
+		.free_coherent = octeon_dma_free_coherent,
+		.map_page = octeon_dma_map_page,
+		.unmap_page = swiotlb_unmap_page,
+		.map_sg = octeon_dma_map_sg,
+		.unmap_sg = swiotlb_unmap_sg_attrs,
+		.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+		.sync_single_for_device = octeon_dma_sync_single_for_device,
+		.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+		.sync_sg_for_device = octeon_dma_sync_sg_for_device,
+		.mapping_error = swiotlb_dma_mapping_error,
+		.dma_supported = swiotlb_dma_supported
+	},
+};
+
+struct dma_map_ops *octeon_pci_dma_map_ops;
+
+void __init octeon_pci_dma_init(void)
+{
 	switch (octeon_dma_bar_type) {
 	case OCTEON_DMA_BAR_TYPE_PCIE:
-		/* Nothing to do, all mappings are static */
-		goto done;
-
+		_octeon_pci_dma_map_ops.phys_to_dma = octeon_gen1_phys_to_dma;
+		_octeon_pci_dma_map_ops.dma_to_phys = octeon_gen1_dma_to_phys;
+		break;
 	case OCTEON_DMA_BAR_TYPE_BIG:
-#ifdef CONFIG_64BIT
-		/* Nothing to do for addresses using BAR2 */
-		if (dma_addr >= BAR2_PCI_ADDRESS)
-			goto done;
-#endif
-		if (unlikely(dma_addr < (4ul << 10)))
-			panic("dma_unmap_single: Unexpect DMA address 0x%llx\n",
-			      dma_addr);
-		else if (dma_addr < (2ul << 30))
-			/* Nothing to do for addresses using BAR0 */
-			goto done;
-		else if (dma_addr < (2ul << 30) + (128ul << 20))
-			/* Need to unmap, fall through */
-			index = (dma_addr - (2ul << 30)) >> 22;
-		else if (dma_addr <
-			 (4ul << 30) - (OCTEON_PCI_BAR1_HOLE_SIZE << 20))
-			goto done;	/* Nothing to do for the rest of BAR1 */
-		else
-			panic("dma_unmap_single: Unexpect DMA address 0x%llx\n",
-			      dma_addr);
-		/* Continued below switch statement */
+		_octeon_pci_dma_map_ops.phys_to_dma = octeon_big_phys_to_dma;
+		_octeon_pci_dma_map_ops.dma_to_phys = octeon_big_dma_to_phys;
 		break;
-
 	case OCTEON_DMA_BAR_TYPE_SMALL:
-#ifdef CONFIG_64BIT
-		/* Nothing to do for addresses using BAR2 */
-		if (dma_addr >= BAR2_PCI_ADDRESS)
-			goto done;
-#endif
-		index = dma_addr >> 22;
-		/* Continued below switch statement */
+		_octeon_pci_dma_map_ops.phys_to_dma = octeon_small_phys_to_dma;
+		_octeon_pci_dma_map_ops.dma_to_phys = octeon_small_dma_to_phys;
 		break;
-
 	default:
-		panic("dma_unmap_single: Invalid octeon_dma_bar_type\n");
+		BUG();
 	}
-
-	if (unlikely(index > 31))
-		panic("dma_unmap_single: "
-		      "Attempt to unmap an invalid address (0x%llx)\n",
-		      dma_addr);
-
-	raw_spin_lock_irqsave(&bar1_lock, flags);
-	bar1_state[index].ref_count--;
-	if (bar1_state[index].ref_count == 0)
-		octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index), 0);
-	else if (unlikely(bar1_state[index].ref_count < 0))
-		panic("dma_unmap_single: Bar1[%u] reference count < 0\n",
-		      (int) index);
-	raw_spin_unlock_irqrestore(&bar1_lock, flags);
-done:
-	pr_debug("dma_unmap_single 0x%llx\n", dma_addr);
-	return;
-#endif
+	octeon_pci_dma_map_ops = &_octeon_pci_dma_map_ops.dma_map_ops;
 }
+#endif /* CONFIG_PCI */
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/executive/cvmx-l2c.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/executive/cvmx-l2c.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/executive/cvmx-l2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/executive/cvmx-l2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -26,8 +26,8 @@
  ***********************license end**************************************/
 
 /*
- * Implementation of the Level 2 Cache (L2C) control, measurement, and
- * debugging facilities.
+ * Implementation of the Level 2 Cache (L2C) control,
+ * measurement, and debugging facilities.
  */
 
 #include <asm/octeon/cvmx.h>
@@ -42,13 +42,7 @@
  * if multiple applications or operating systems are running, then it
  * is up to the user program to coordinate between them.
  */
-static cvmx_spinlock_t cvmx_l2c_spinlock;
-
-static inline int l2_size_half(void)
-{
-	uint64_t val = cvmx_read_csr(CVMX_L2D_FUS3);
-	return !!(val & (1ull << 34));
-}
+cvmx_spinlock_t cvmx_l2c_spinlock;
 
 int cvmx_l2c_get_core_way_partition(uint32_t core)
 {
@@ -58,6 +52,9 @@
 	if (core >= cvmx_octeon_num_cores())
 		return -1;
 
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX))
+		return cvmx_read_csr(CVMX_L2C_WPAR_PPX(core)) & 0xffff;
+
 	/*
 	 * Use the lower two bits of the coreNumber to determine the
 	 * bit offset of the UMSK[] field in the L2C_SPAR register.
@@ -71,17 +68,13 @@
 
 	switch (core & 0xC) {
 	case 0x0:
-		return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >>
-			field;
+		return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> field;
 	case 0x4:
-		return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >>
-			field;
+		return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> field;
 	case 0x8:
-		return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >>
-			field;
+		return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> field;
 	case 0xC:
-		return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >>
-			field;
+		return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> field;
 	}
 	return 0;
 }
@@ -95,48 +88,50 @@
 
 	mask &= valid_mask;
 
-	/* A UMSK setting which blocks all L2C Ways is an error. */
-	if (mask == valid_mask)
+	/* A UMSK setting which blocks all L2C Ways is an error on some chips */
+	if (mask == valid_mask && !OCTEON_IS_MODEL(OCTEON_CN63XX))
 		return -1;
 
 	/* Validate the core number */
 	if (core >= cvmx_octeon_num_cores())
 		return -1;
 
-	/* Check to make sure current mask & new mask don't block all ways */
-	if (((mask | cvmx_l2c_get_core_way_partition(core)) & valid_mask) ==
-	    valid_mask)
-		return -1;
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		cvmx_write_csr(CVMX_L2C_WPAR_PPX(core), mask);
+		return 0;
+	}
 
-	/* Use the lower two bits of core to determine the bit offset of the
+	/*
+	 * Use the lower two bits of core to determine the bit offset of the
 	 * UMSK[] field in the L2C_SPAR register.
 	 */
 	field = (core & 0x3) * 8;
 
-	/* Assign the new mask setting to the UMSK[] field in the appropriate
+	/*
+	 * Assign the new mask setting to the UMSK[] field in the appropriate
 	 * L2C_SPAR register based on the core_num.
 	 *
 	 */
 	switch (core & 0xC) {
 	case 0x0:
 		cvmx_write_csr(CVMX_L2C_SPAR0,
-			       (cvmx_read_csr(CVMX_L2C_SPAR0) &
-				~(0xFF << field)) | mask << field);
+			       (cvmx_read_csr(CVMX_L2C_SPAR0) & ~(0xFF << field)) |
+			       mask << field);
 		break;
 	case 0x4:
 		cvmx_write_csr(CVMX_L2C_SPAR1,
-			       (cvmx_read_csr(CVMX_L2C_SPAR1) &
-				~(0xFF << field)) | mask << field);
+			       (cvmx_read_csr(CVMX_L2C_SPAR1) & ~(0xFF << field)) |
+			       mask << field);
 		break;
 	case 0x8:
 		cvmx_write_csr(CVMX_L2C_SPAR2,
-			       (cvmx_read_csr(CVMX_L2C_SPAR2) &
-				~(0xFF << field)) | mask << field);
+			       (cvmx_read_csr(CVMX_L2C_SPAR2) & ~(0xFF << field)) |
+			       mask << field);
 		break;
 	case 0xC:
 		cvmx_write_csr(CVMX_L2C_SPAR3,
-			       (cvmx_read_csr(CVMX_L2C_SPAR3) &
-				~(0xFF << field)) | mask << field);
+			       (cvmx_read_csr(CVMX_L2C_SPAR3) & ~(0xFF << field)) |
+			       mask << field);
 		break;
 	}
 	return 0;
@@ -146,84 +141,137 @@
 {
 	uint32_t valid_mask;
 
-	valid_mask = 0xff;
-
-	if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN38XX)) {
-		if (l2_size_half())
-			valid_mask = 0xf;
-	} else if (l2_size_half())
-		valid_mask = 0x3;
-
+	valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1;
 	mask &= valid_mask;
 
-	/* A UMSK setting which blocks all L2C Ways is an error. */
-	if (mask == valid_mask)
-		return -1;
-	/* Check to make sure current mask & new mask don't block all ways */
-	if (((mask | cvmx_l2c_get_hw_way_partition()) & valid_mask) ==
-	    valid_mask)
+	/* A UMSK setting which blocks all L2C Ways is an error on some chips */
+	if (mask == valid_mask  && !OCTEON_IS_MODEL(OCTEON_CN63XX))
 		return -1;
 
-	cvmx_write_csr(CVMX_L2C_SPAR4,
-		       (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask);
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX))
+		cvmx_write_csr(CVMX_L2C_WPAR_IOBX(0), mask);
+	else
+		cvmx_write_csr(CVMX_L2C_SPAR4,
+			       (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask);
 	return 0;
 }
 
 int cvmx_l2c_get_hw_way_partition(void)
 {
-	return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF);
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX))
+		return cvmx_read_csr(CVMX_L2C_WPAR_IOBX(0)) & 0xffff;
+	else
+		return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF);
 }
 
 void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event,
 			  uint32_t clear_on_read)
 {
-	union cvmx_l2c_pfctl pfctl;
+	if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+		union cvmx_l2c_pfctl pfctl;
 
-	pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL);
+		pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL);
 
-	switch (counter) {
-	case 0:
-		pfctl.s.cnt0sel = event;
-		pfctl.s.cnt0ena = 1;
-		if (!cvmx_octeon_is_pass1())
+		switch (counter) {
+		case 0:
+			pfctl.s.cnt0sel = event;
+			pfctl.s.cnt0ena = 1;
 			pfctl.s.cnt0rdclr = clear_on_read;
-		break;
-	case 1:
-		pfctl.s.cnt1sel = event;
-		pfctl.s.cnt1ena = 1;
-		if (!cvmx_octeon_is_pass1())
+			break;
+		case 1:
+			pfctl.s.cnt1sel = event;
+			pfctl.s.cnt1ena = 1;
 			pfctl.s.cnt1rdclr = clear_on_read;
-		break;
-	case 2:
-		pfctl.s.cnt2sel = event;
-		pfctl.s.cnt2ena = 1;
-		if (!cvmx_octeon_is_pass1())
+			break;
+		case 2:
+			pfctl.s.cnt2sel = event;
+			pfctl.s.cnt2ena = 1;
 			pfctl.s.cnt2rdclr = clear_on_read;
-		break;
-	case 3:
-	default:
-		pfctl.s.cnt3sel = event;
-		pfctl.s.cnt3ena = 1;
-		if (!cvmx_octeon_is_pass1())
+			break;
+		case 3:
+		default:
+			pfctl.s.cnt3sel = event;
+			pfctl.s.cnt3ena = 1;
 			pfctl.s.cnt3rdclr = clear_on_read;
-		break;
-	}
+			break;
+		}
 
-	cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64);
+		cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64);
+	} else {
+		union cvmx_l2c_tadx_prf l2c_tadx_prf;
+		int tad;
+
+		cvmx_dprintf("L2C performance counter events are different for this chip, mapping 'event' to cvmx_l2c_tad_event_t\n");
+		if (clear_on_read)
+			cvmx_dprintf("L2C counters don't support clear on read for this chip\n");
+
+		l2c_tadx_prf.u64 = cvmx_read_csr(CVMX_L2C_TADX_PRF(0));
+
+		switch (counter) {
+		case 0:
+			l2c_tadx_prf.s.cnt0sel = event;
+			break;
+		case 1:
+			l2c_tadx_prf.s.cnt1sel = event;
+			break;
+		case 2:
+			l2c_tadx_prf.s.cnt2sel = event;
+			break;
+		default:
+		case 3:
+			l2c_tadx_prf.s.cnt3sel = event;
+			break;
+		}
+		for (tad = 0; tad < CVMX_L2C_TADS; tad++)
+			cvmx_write_csr(CVMX_L2C_TADX_PRF(tad),
+				       l2c_tadx_prf.u64);
+	}
 }
 
 uint64_t cvmx_l2c_read_perf(uint32_t counter)
 {
 	switch (counter) {
 	case 0:
-		return cvmx_read_csr(CVMX_L2C_PFC0);
+		if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
+			return cvmx_read_csr(CVMX_L2C_PFC0);
+		else {
+			uint64_t counter = 0;
+			int tad;
+			for (tad = 0; tad < CVMX_L2C_TADS; tad++)
+				counter += cvmx_read_csr(CVMX_L2C_TADX_PFC0(tad));
+			return counter;
+		}
 	case 1:
-		return cvmx_read_csr(CVMX_L2C_PFC1);
+		if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
+			return cvmx_read_csr(CVMX_L2C_PFC1);
+		else {
+			uint64_t counter = 0;
+			int tad;
+			for (tad = 0; tad < CVMX_L2C_TADS; tad++)
+				counter += cvmx_read_csr(CVMX_L2C_TADX_PFC1(tad));
+			return counter;
+		}
 	case 2:
-		return cvmx_read_csr(CVMX_L2C_PFC2);
+		if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
+			return cvmx_read_csr(CVMX_L2C_PFC2);
+		else {
+			uint64_t counter = 0;
+			int tad;
+			for (tad = 0; tad < CVMX_L2C_TADS; tad++)
+				counter += cvmx_read_csr(CVMX_L2C_TADX_PFC2(tad));
+			return counter;
+		}
 	case 3:
 	default:
-		return cvmx_read_csr(CVMX_L2C_PFC3);
+		if (OCTEON_IS_MODEL(OCTEON_CN5XXX) || OCTEON_IS_MODEL(OCTEON_CN3XXX))
+			return cvmx_read_csr(CVMX_L2C_PFC3);
+		else {
+			uint64_t counter = 0;
+			int tad;
+			for (tad = 0; tad < CVMX_L2C_TADS; tad++)
+				counter += cvmx_read_csr(CVMX_L2C_TADX_PFC3(tad));
+			return counter;
+		}
 	}
 }
 
@@ -240,7 +288,7 @@
 	volatile char dummy;
 	/*
 	 * Adjust addr and length so we get all cache lines even for
-	 * small ranges spanning two cache lines
+	 * small ranges spanning two cache lines.
 	 */
 	len += addr & CVMX_CACHE_LINE_MASK;
 	addr &= ~CVMX_CACHE_LINE_MASK;
@@ -259,67 +307,100 @@
 
 int cvmx_l2c_lock_line(uint64_t addr)
 {
-	int retval = 0;
-	union cvmx_l2c_dbg l2cdbg;
-	union cvmx_l2c_lckbase lckbase;
-	union cvmx_l2c_lckoff lckoff;
-	union cvmx_l2t_err l2t_err;
-	l2cdbg.u64 = 0;
-	lckbase.u64 = 0;
-	lckoff.u64 = 0;
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		int shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
+		uint64_t assoc = cvmx_l2c_get_num_assoc();
+		uint64_t tag = addr >> shift;
+		uint64_t index = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, cvmx_l2c_address_to_index(addr) << CVMX_L2C_IDX_ADDR_SHIFT);
+		uint64_t way;
+		union cvmx_l2c_tadx_tag l2c_tadx_tag;
 
-	cvmx_spinlock_lock(&cvmx_l2c_spinlock);
+		CVMX_CACHE_LCKL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, addr), 0);
 
-	/* Clear l2t error bits if set */
-	l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
-	l2t_err.s.lckerr = 1;
-	l2t_err.s.lckerr2 = 1;
-	cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
+		/* Make sure we were able to lock the line */
+		for (way = 0; way < assoc; way++) {
+			CVMX_CACHE_LTGL2I(index | (way << shift), 0);
+			/* make sure CVMX_L2C_TADX_TAG is updated */
+			CVMX_SYNC;
+			l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
+			if (l2c_tadx_tag.s.valid && l2c_tadx_tag.s.tag == tag)
+				break;
+		}
 
-	addr &= ~CVMX_CACHE_LINE_MASK;
+		/* Check if a valid line is found */
+		if (way >= assoc) {
+			/* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: line not found for locking at 0x%llx address\n", (unsigned long long)addr); */
+			return -1;
+		}
 
-	/* Set this core as debug core */
-	l2cdbg.s.ppnum = cvmx_get_core_num();
-	CVMX_SYNC;
-	cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
-	cvmx_read_csr(CVMX_L2C_DBG);
+		/* Check if lock bit is not set */
+		if (!l2c_tadx_tag.s.lock) {
+			/* cvmx_dprintf("ERROR: cvmx_l2c_lock_line: Not able to lock at 0x%llx address\n", (unsigned long long)addr); */
+			return -1;
+		}
+		return way;
+	} else {
+		int retval = 0;
+		union cvmx_l2c_dbg l2cdbg;
+		union cvmx_l2c_lckbase lckbase;
+		union cvmx_l2c_lckoff lckoff;
+		union cvmx_l2t_err l2t_err;
 
-	lckoff.s.lck_offset = 0;	/* Only lock 1 line at a time */
-	cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64);
-	cvmx_read_csr(CVMX_L2C_LCKOFF);
+		cvmx_spinlock_lock(&cvmx_l2c_spinlock);
 
-	if (((union cvmx_l2c_cfg) (cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) {
-		int alias_shift =
-		    CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1;
-		uint64_t addr_tmp =
-		    addr ^ (addr & ((1 << alias_shift) - 1)) >>
-		    CVMX_L2_SET_BITS;
-		lckbase.s.lck_base = addr_tmp >> 7;
-	} else {
-		lckbase.s.lck_base = addr >> 7;
-	}
+		l2cdbg.u64 = 0;
+		lckbase.u64 = 0;
+		lckoff.u64 = 0;
 
-	lckbase.s.lck_ena = 1;
-	cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
-	cvmx_read_csr(CVMX_L2C_LCKBASE);	/* Make sure it gets there */
+		/* Clear l2t error bits if set */
+		l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
+		l2t_err.s.lckerr = 1;
+		l2t_err.s.lckerr2 = 1;
+		cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64);
 
-	fault_in(addr, CVMX_CACHE_LINE_SIZE);
+		addr &= ~CVMX_CACHE_LINE_MASK;
 
-	lckbase.s.lck_ena = 0;
-	cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
-	cvmx_read_csr(CVMX_L2C_LCKBASE);	/* Make sure it gets there */
+		/* Set this core as debug core */
+		l2cdbg.s.ppnum = cvmx_get_core_num();
+		CVMX_SYNC;
+		cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
+		cvmx_read_csr(CVMX_L2C_DBG);
 
-	/* Stop being debug core */
-	cvmx_write_csr(CVMX_L2C_DBG, 0);
-	cvmx_read_csr(CVMX_L2C_DBG);
+		lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */
+		cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64);
+		cvmx_read_csr(CVMX_L2C_LCKOFF);
 
-	l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
-	if (l2t_err.s.lckerr || l2t_err.s.lckerr2)
-		retval = 1;	/* We were unable to lock the line */
+		if (((union cvmx_l2c_cfg)(cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) {
+			int alias_shift = CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1;
+			uint64_t addr_tmp = addr ^ (addr & ((1 << alias_shift) - 1)) >> CVMX_L2_SET_BITS;
+			lckbase.s.lck_base = addr_tmp >> 7;
+		} else {
+			lckbase.s.lck_base = addr >> 7;
+		}
 
-	cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
+		lckbase.s.lck_ena = 1;
+		cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
+		/* Make sure it gets there */
+		cvmx_read_csr(CVMX_L2C_LCKBASE);
 
-	return retval;
+		fault_in(addr, CVMX_CACHE_LINE_SIZE);
+
+		lckbase.s.lck_ena = 0;
+		cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64);
+		/* Make sure it gets there */
+		cvmx_read_csr(CVMX_L2C_LCKBASE);
+
+		/* Stop being debug core */
+		cvmx_write_csr(CVMX_L2C_DBG, 0);
+		cvmx_read_csr(CVMX_L2C_DBG);
+
+		l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR);
+		if (l2t_err.s.lckerr || l2t_err.s.lckerr2)
+			retval = 1;  /* We were unable to lock the line */
+
+		cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
+		return retval;
+	}
 }
 
 int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len)
@@ -336,7 +417,6 @@
 		start += CVMX_CACHE_LINE_SIZE;
 		len -= CVMX_CACHE_LINE_SIZE;
 	}
-
 	return retval;
 }
 
@@ -344,80 +424,73 @@
 {
 	uint64_t assoc, set;
 	uint64_t n_assoc, n_set;
-	union cvmx_l2c_dbg l2cdbg;
-
-	cvmx_spinlock_lock(&cvmx_l2c_spinlock);
 
-	l2cdbg.u64 = 0;
-	if (!OCTEON_IS_MODEL(OCTEON_CN30XX))
-		l2cdbg.s.ppnum = cvmx_get_core_num();
-	l2cdbg.s.finv = 1;
-	n_set = CVMX_L2_SETS;
-	n_assoc = l2_size_half() ? (CVMX_L2_ASSOC / 2) : CVMX_L2_ASSOC;
-	for (set = 0; set < n_set; set++) {
-		for (assoc = 0; assoc < n_assoc; assoc++) {
-			l2cdbg.s.set = assoc;
-			/* Enter debug mode, and make sure all other
-			 ** writes complete before we enter debug
-			 ** mode */
-			CVMX_SYNCW;
-			cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
-			cvmx_read_csr(CVMX_L2C_DBG);
+	n_set = cvmx_l2c_get_num_sets();
+	n_assoc = cvmx_l2c_get_num_assoc();
 
-			CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG
-					       (CVMX_MIPS_SPACE_XKPHYS,
-						set * CVMX_CACHE_LINE_SIZE), 0);
-			CVMX_SYNCW;	/* Push STF out to L2 */
-			/* Exit debug mode */
-			CVMX_SYNC;
-			cvmx_write_csr(CVMX_L2C_DBG, 0);
-			cvmx_read_csr(CVMX_L2C_DBG);
+	if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+		uint64_t address;
+		/* These may look like constants, but they aren't... */
+		int assoc_shift = CVMX_L2C_TAG_ADDR_ALIAS_SHIFT;
+		int set_shift = CVMX_L2C_IDX_ADDR_SHIFT;
+		for (set = 0; set < n_set; set++) {
+			for (assoc = 0; assoc < n_assoc; assoc++) {
+				address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+						       (assoc << assoc_shift) |	(set << set_shift));
+				CVMX_CACHE_WBIL2I(address, 0);
+			}
 		}
+	} else {
+		for (set = 0; set < n_set; set++)
+			for (assoc = 0; assoc < n_assoc; assoc++)
+				cvmx_l2c_flush_line(assoc, set);
 	}
-
-	cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
 }
 
+
 int cvmx_l2c_unlock_line(uint64_t address)
 {
-	int assoc;
-	union cvmx_l2c_tag tag;
-	union cvmx_l2c_dbg l2cdbg;
-	uint32_t tag_addr;
 
-	uint32_t index = cvmx_l2c_address_to_index(address);
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		int assoc;
+		union cvmx_l2c_tag tag;
+		uint32_t tag_addr;
+		uint32_t index = cvmx_l2c_address_to_index(address);
 
-	cvmx_spinlock_lock(&cvmx_l2c_spinlock);
-	/* Compute portion of address that is stored in tag */
-	tag_addr =
-	    ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) &
-	     ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
-	for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
-		tag = cvmx_get_l2c_tag(assoc, index);
+		tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
 
-		if (tag.s.V && (tag.s.addr == tag_addr)) {
-			l2cdbg.u64 = 0;
-			l2cdbg.s.ppnum = cvmx_get_core_num();
-			l2cdbg.s.set = assoc;
-			l2cdbg.s.finv = 1;
+		/*
+		 * For 63XX, we can flush a line by using the physical
+		 * address directly, so finding the cache line used by
+		 * the address is only required to provide the proper
+		 * return value for the function.
+		 */
+		for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
+			tag = cvmx_l2c_get_tag(assoc, index);
 
-			CVMX_SYNC;
-			/* Enter debug mode */
-			cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
-			cvmx_read_csr(CVMX_L2C_DBG);
+			if (tag.s.V && (tag.s.addr == tag_addr)) {
+				CVMX_CACHE_WBIL2(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, address), 0);
+				return tag.s.L;
+			}
+		}
+	} else {
+		int assoc;
+		union cvmx_l2c_tag tag;
+		uint32_t tag_addr;
 
-			CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG
-					       (CVMX_MIPS_SPACE_XKPHYS,
-						address), 0);
-			CVMX_SYNC;
-			/* Exit debug mode */
-			cvmx_write_csr(CVMX_L2C_DBG, 0);
-			cvmx_read_csr(CVMX_L2C_DBG);
-			cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
-			return tag.s.L;
+		uint32_t index = cvmx_l2c_address_to_index(address);
+
+		/* Compute portion of address that is stored in tag */
+		tag_addr = ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1));
+		for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) {
+			tag = cvmx_l2c_get_tag(assoc, index);
+
+			if (tag.s.V && (tag.s.addr == tag_addr)) {
+				cvmx_l2c_flush_line(assoc, index);
+				return tag.s.L;
+			}
 		}
 	}
-	cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
 	return 0;
 }
 
@@ -445,48 +518,49 @@
 	uint64_t u64;
 	struct cvmx_l2c_tag_cn50xx {
 		uint64_t reserved:40;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:20;	/* Phys mem addr (33..14) */
 	} cn50xx;
 	struct cvmx_l2c_tag_cn30xx {
 		uint64_t reserved:41;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:19;	/* Phys mem addr (33..15) */
 	} cn30xx;
 	struct cvmx_l2c_tag_cn31xx {
 		uint64_t reserved:42;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:18;	/* Phys mem addr (33..16) */
 	} cn31xx;
 	struct cvmx_l2c_tag_cn38xx {
 		uint64_t reserved:43;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:17;	/* Phys mem addr (33..17) */
 	} cn38xx;
 	struct cvmx_l2c_tag_cn58xx {
 		uint64_t reserved:44;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:16;	/* Phys mem addr (33..18) */
 	} cn58xx;
 	struct cvmx_l2c_tag_cn58xx cn56xx;	/* 2048 sets */
 	struct cvmx_l2c_tag_cn31xx cn52xx;	/* 512 sets */
 };
 
+
 /**
  * @INTERNAL
  * Function to read a L2C tag.  This code make the current core
@@ -503,7 +577,7 @@
 static union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index)
 {
 
-	uint64_t debug_tag_addr = (((1ULL << 63) | (index << 7)) + 96);
+	uint64_t debug_tag_addr = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, (index << 7) + 96);
 	uint64_t core = cvmx_get_core_num();
 	union __cvmx_l2c_tag tag_val;
 	uint64_t dbg_addr = CVMX_L2C_DBG;
@@ -512,12 +586,15 @@
 	union cvmx_l2c_dbg debug_val;
 	debug_val.u64 = 0;
 	/*
-	 * For low core count parts, the core number is always small enough
-	 * to stay in the correct field and not set any reserved bits.
+	 * For low core count parts, the core number is always small
+	 * enough to stay in the correct field and not set any
+	 * reserved bits.
 	 */
 	debug_val.s.ppnum = core;
 	debug_val.s.l2t = 1;
 	debug_val.s.set = assoc;
+
+	local_irq_save(flags);
 	/*
 	 * Make sure core is quiet (no prefetches, etc.) before
 	 * entering debug mode.
@@ -526,112 +603,139 @@
 	/* Flush L1 to make sure debug load misses L1 */
 	CVMX_DCACHE_INVALIDATE;
 
-	local_irq_save(flags);
-
 	/*
 	 * The following must be done in assembly as when in debug
 	 * mode all data loads from L2 return special debug data, not
-	 * normal memory contents.  Also, interrupts must be
-	 * disabled, since if an interrupt occurs while in debug mode
-	 * the ISR will get debug data from all its memory reads
-	 * instead of the contents of memory
+	 * normal memory contents.  Also, interrupts must be disabled,
+	 * since if an interrupt occurs while in debug mode the ISR
+	 * will get debug data from all its memory * reads instead of
+	 * the contents of memory.
 	 */
 
-	asm volatile (".set push              \n"
-		"        .set mips64              \n"
-		"        .set noreorder           \n"
-		/* Enter debug mode, wait for store */
-		"        sd    %[dbg_val], 0(%[dbg_addr])  \n"
-		"        ld    $0, 0(%[dbg_addr]) \n"
-		/* Read L2C tag data */
-		"        ld    %[tag_val], 0(%[tag_addr]) \n"
-		/* Exit debug mode, wait for store */
-		"        sd    $0, 0(%[dbg_addr])  \n"
-		"        ld    $0, 0(%[dbg_addr]) \n"
-		/* Invalidate dcache to discard debug data */
-		"        cache 9, 0($0) \n"
-		"        .set pop" :
-		[tag_val] "=r"(tag_val.u64) : [dbg_addr] "r"(dbg_addr),
-		[dbg_val] "r"(debug_val.u64),
-		[tag_addr] "r"(debug_tag_addr) : "memory");
+	asm volatile (
+		".set push\n\t"
+		".set mips64\n\t"
+		".set noreorder\n\t"
+		"sd    %[dbg_val], 0(%[dbg_addr])\n\t"   /* Enter debug mode, wait for store */
+		"ld    $0, 0(%[dbg_addr])\n\t"
+		"ld    %[tag_val], 0(%[tag_addr])\n\t"   /* Read L2C tag data */
+		"sd    $0, 0(%[dbg_addr])\n\t"          /* Exit debug mode, wait for store */
+		"ld    $0, 0(%[dbg_addr])\n\t"
+		"cache 9, 0($0)\n\t"             /* Invalidate dcache to discard debug data */
+		".set pop"
+		: [tag_val] "=r" (tag_val)
+		: [dbg_addr] "r" (dbg_addr), [dbg_val] "r" (debug_val), [tag_addr] "r" (debug_tag_addr)
+		: "memory");
 
 	local_irq_restore(flags);
-	return tag_val;
 
+	return tag_val;
 }
 
+
 union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index)
 {
-	union __cvmx_l2c_tag tmp_tag;
 	union cvmx_l2c_tag tag;
 	tag.u64 = 0;
 
 	if ((int)association >= cvmx_l2c_get_num_assoc()) {
-		cvmx_dprintf
-		    ("ERROR: cvmx_get_l2c_tag association out of range\n");
+		cvmx_dprintf("ERROR: cvmx_l2c_get_tag association out of range\n");
 		return tag;
 	}
 	if ((int)index >= cvmx_l2c_get_num_sets()) {
-		cvmx_dprintf("ERROR: cvmx_get_l2c_tag "
-			     "index out of range (arg: %d, max: %d\n",
-		     index, cvmx_l2c_get_num_sets());
+		cvmx_dprintf("ERROR: cvmx_l2c_get_tag index out of range (arg: %d, max: %d)\n",
+			     (int)index, cvmx_l2c_get_num_sets());
 		return tag;
 	}
-	/* __read_l2_tag is intended for internal use only */
-	tmp_tag = __read_l2_tag(association, index);
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		union cvmx_l2c_tadx_tag l2c_tadx_tag;
+		uint64_t address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+						(association << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
+						(index << CVMX_L2C_IDX_ADDR_SHIFT));
+		/*
+		 * Use L2 cache Index load tag cache instruction, as
+		 * hardware loads the virtual tag for the L2 cache
+		 * block with the contents of L2C_TAD0_TAG
+		 * register.
+		 */
+		CVMX_CACHE_LTGL2I(address, 0);
+		CVMX_SYNC;   /* make sure CVMX_L2C_TADX_TAG is updated */
+		l2c_tadx_tag.u64 = cvmx_read_csr(CVMX_L2C_TADX_TAG(0));
 
-	/*
-	 * Convert all tag structure types to generic version, as it
-	 * can represent all models.
-	 */
-	if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
-		tag.s.V = tmp_tag.cn58xx.V;
-		tag.s.D = tmp_tag.cn58xx.D;
-		tag.s.L = tmp_tag.cn58xx.L;
-		tag.s.U = tmp_tag.cn58xx.U;
-		tag.s.addr = tmp_tag.cn58xx.addr;
-	} else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
-		tag.s.V = tmp_tag.cn38xx.V;
-		tag.s.D = tmp_tag.cn38xx.D;
-		tag.s.L = tmp_tag.cn38xx.L;
-		tag.s.U = tmp_tag.cn38xx.U;
-		tag.s.addr = tmp_tag.cn38xx.addr;
-	} else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
-		   || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
-		tag.s.V = tmp_tag.cn31xx.V;
-		tag.s.D = tmp_tag.cn31xx.D;
-		tag.s.L = tmp_tag.cn31xx.L;
-		tag.s.U = tmp_tag.cn31xx.U;
-		tag.s.addr = tmp_tag.cn31xx.addr;
-	} else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) {
-		tag.s.V = tmp_tag.cn30xx.V;
-		tag.s.D = tmp_tag.cn30xx.D;
-		tag.s.L = tmp_tag.cn30xx.L;
-		tag.s.U = tmp_tag.cn30xx.U;
-		tag.s.addr = tmp_tag.cn30xx.addr;
-	} else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
-		tag.s.V = tmp_tag.cn50xx.V;
-		tag.s.D = tmp_tag.cn50xx.D;
-		tag.s.L = tmp_tag.cn50xx.L;
-		tag.s.U = tmp_tag.cn50xx.U;
-		tag.s.addr = tmp_tag.cn50xx.addr;
+		tag.s.V     = l2c_tadx_tag.s.valid;
+		tag.s.D     = l2c_tadx_tag.s.dirty;
+		tag.s.L     = l2c_tadx_tag.s.lock;
+		tag.s.U     = l2c_tadx_tag.s.use;
+		tag.s.addr  = l2c_tadx_tag.s.tag;
 	} else {
-		cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
-	}
+		union __cvmx_l2c_tag tmp_tag;
+		/* __read_l2_tag is intended for internal use only */
+		tmp_tag = __read_l2_tag(association, index);
 
+		/*
+		 * Convert all tag structure types to generic version,
+		 * as it can represent all models.
+		 */
+		if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
+			tag.s.V    = tmp_tag.cn58xx.V;
+			tag.s.D    = tmp_tag.cn58xx.D;
+			tag.s.L    = tmp_tag.cn58xx.L;
+			tag.s.U    = tmp_tag.cn58xx.U;
+			tag.s.addr = tmp_tag.cn58xx.addr;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
+			tag.s.V    = tmp_tag.cn38xx.V;
+			tag.s.D    = tmp_tag.cn38xx.D;
+			tag.s.L    = tmp_tag.cn38xx.L;
+			tag.s.U    = tmp_tag.cn38xx.U;
+			tag.s.addr = tmp_tag.cn38xx.addr;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
+			tag.s.V    = tmp_tag.cn31xx.V;
+			tag.s.D    = tmp_tag.cn31xx.D;
+			tag.s.L    = tmp_tag.cn31xx.L;
+			tag.s.U    = tmp_tag.cn31xx.U;
+			tag.s.addr = tmp_tag.cn31xx.addr;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) {
+			tag.s.V    = tmp_tag.cn30xx.V;
+			tag.s.D    = tmp_tag.cn30xx.D;
+			tag.s.L    = tmp_tag.cn30xx.L;
+			tag.s.U    = tmp_tag.cn30xx.U;
+			tag.s.addr = tmp_tag.cn30xx.addr;
+		} else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
+			tag.s.V    = tmp_tag.cn50xx.V;
+			tag.s.D    = tmp_tag.cn50xx.D;
+			tag.s.L    = tmp_tag.cn50xx.L;
+			tag.s.U    = tmp_tag.cn50xx.U;
+			tag.s.addr = tmp_tag.cn50xx.addr;
+		} else {
+			cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__);
+		}
+	}
 	return tag;
 }
 
 uint32_t cvmx_l2c_address_to_index(uint64_t addr)
 {
 	uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT;
-	union cvmx_l2c_cfg l2c_cfg;
-	l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
+	int indxalias = 0;
 
-	if (l2c_cfg.s.idxalias) {
-		idx ^=
-		    ((addr & CVMX_L2C_ALIAS_MASK) >>
-		     CVMX_L2C_TAG_ADDR_ALIAS_SHIFT);
+	if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+		union cvmx_l2c_ctl l2c_ctl;
+		l2c_ctl.u64 = cvmx_read_csr(CVMX_L2C_CTL);
+		indxalias = !l2c_ctl.s.disidxalias;
+	} else {
+		union cvmx_l2c_cfg l2c_cfg;
+		l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
+		indxalias = l2c_cfg.s.idxalias;
+	}
+
+	if (indxalias) {
+		if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+			uint32_t a_14_12 = (idx / (CVMX_L2C_MEMBANK_SELECT_SIZE/(1<<CVMX_L2C_IDX_ADDR_SHIFT))) & 0x7;
+			idx ^= idx / cvmx_l2c_get_num_sets();
+			idx ^= a_14_12;
+		} else {
+			idx ^= ((addr & CVMX_L2C_ALIAS_MASK) >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT);
+		}
 	}
 	idx &= CVMX_L2C_IDX_MASK;
 	return idx;
@@ -652,10 +756,9 @@
 	int l2_set_bits;
 	if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
 		l2_set_bits = 11;	/* 2048 sets */
-	else if (OCTEON_IS_MODEL(OCTEON_CN38XX))
+	else if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
 		l2_set_bits = 10;	/* 1024 sets */
-	else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
-		 || OCTEON_IS_MODEL(OCTEON_CN52XX))
+	else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
 		l2_set_bits = 9;	/* 512 sets */
 	else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
 		l2_set_bits = 8;	/* 256 sets */
@@ -666,7 +769,6 @@
 		l2_set_bits = 11;	/* 2048 sets */
 	}
 	return l2_set_bits;
-
 }
 
 /* Return the number of sets in the L2 Cache */
@@ -682,8 +784,11 @@
 	if (OCTEON_IS_MODEL(OCTEON_CN56XX) ||
 	    OCTEON_IS_MODEL(OCTEON_CN52XX) ||
 	    OCTEON_IS_MODEL(OCTEON_CN58XX) ||
-	    OCTEON_IS_MODEL(OCTEON_CN50XX) || OCTEON_IS_MODEL(OCTEON_CN38XX))
+	    OCTEON_IS_MODEL(OCTEON_CN50XX) ||
+	    OCTEON_IS_MODEL(OCTEON_CN38XX))
 		l2_assoc = 8;
+	else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
+		l2_assoc = 16;
 	else if (OCTEON_IS_MODEL(OCTEON_CN31XX) ||
 		 OCTEON_IS_MODEL(OCTEON_CN30XX))
 		l2_assoc = 4;
@@ -693,11 +798,42 @@
 	}
 
 	/* Check to see if part of the cache is disabled */
-	if (cvmx_fuse_read(265))
-		l2_assoc = l2_assoc >> 2;
-	else if (cvmx_fuse_read(264))
-		l2_assoc = l2_assoc >> 1;
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		union cvmx_mio_fus_dat3 mio_fus_dat3;
 
+		mio_fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
+		/*
+		 * cvmx_mio_fus_dat3.s.l2c_crip fuses map as follows
+		 * <2> will be not used for 63xx
+		 * <1> disables 1/2 ways
+		 * <0> disables 1/4 ways
+		 * They are cumulative, so for 63xx:
+		 * <1> <0>
+		 * 0 0 16-way 2MB cache
+		 * 0 1 12-way 1.5MB cache
+		 * 1 0 8-way 1MB cache
+		 * 1 1 4-way 512KB cache
+		 */
+
+		if (mio_fus_dat3.s.l2c_crip == 3)
+			l2_assoc = 4;
+		else if (mio_fus_dat3.s.l2c_crip == 2)
+			l2_assoc = 8;
+		else if (mio_fus_dat3.s.l2c_crip == 1)
+			l2_assoc = 12;
+	} else {
+		union cvmx_l2d_fus3 val;
+		val.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
+		/*
+		 * Using shifts here, as bit position names are
+		 * different for each model but they all mean the
+		 * same.
+		 */
+		if ((val.u64 >> 35) & 0x1)
+			l2_assoc = l2_assoc >> 2;
+		else if ((val.u64 >> 34) & 0x1)
+			l2_assoc = l2_assoc >> 1;
+	}
 	return l2_assoc;
 }
 
@@ -711,24 +847,54 @@
  */
 void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index)
 {
-	union cvmx_l2c_dbg l2cdbg;
+	/* Check the range of the index. */
+	if (index > (uint32_t)cvmx_l2c_get_num_sets()) {
+		cvmx_dprintf("ERROR: cvmx_l2c_flush_line index out of range.\n");
+		return;
+	}
 
-	l2cdbg.u64 = 0;
-	l2cdbg.s.ppnum = cvmx_get_core_num();
-	l2cdbg.s.finv = 1;
+	/* Check the range of association. */
+	if (assoc > (uint32_t)cvmx_l2c_get_num_assoc()) {
+		cvmx_dprintf("ERROR: cvmx_l2c_flush_line association out of range.\n");
+		return;
+	}
 
-	l2cdbg.s.set = assoc;
-	/*
-	 * Enter debug mode, and make sure all other writes complete
-	 * before we enter debug mode.
-	 */
-	asm volatile ("sync" : : : "memory");
-	cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
-	cvmx_read_csr(CVMX_L2C_DBG);
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX)) {
+		uint64_t address;
+		/* Create the address based on index and association.
+		 * Bits<20:17> select the way of the cache block involved in
+		 *             the operation
+		 * Bits<16:7> of the effect address select the index
+		 */
+		address = CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+				(assoc << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) |
+				(index << CVMX_L2C_IDX_ADDR_SHIFT));
+		CVMX_CACHE_WBIL2I(address, 0);
+	} else {
+		union cvmx_l2c_dbg l2cdbg;
 
-	CVMX_PREPARE_FOR_STORE(((1ULL << 63) + (index) * 128), 0);
-	/* Exit debug mode */
-	asm volatile ("sync" : : : "memory");
-	cvmx_write_csr(CVMX_L2C_DBG, 0);
-	cvmx_read_csr(CVMX_L2C_DBG);
+		l2cdbg.u64 = 0;
+		if (!OCTEON_IS_MODEL(OCTEON_CN30XX))
+			l2cdbg.s.ppnum = cvmx_get_core_num();
+		l2cdbg.s.finv = 1;
+
+		l2cdbg.s.set = assoc;
+		cvmx_spinlock_lock(&cvmx_l2c_spinlock);
+		/*
+		 * Enter debug mode, and make sure all other writes
+		 * complete before we enter debug mode
+		 */
+		CVMX_SYNC;
+		cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64);
+		cvmx_read_csr(CVMX_L2C_DBG);
+
+		CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS,
+						    index * CVMX_CACHE_LINE_SIZE),
+				       0);
+		/* Exit debug mode */
+		CVMX_SYNC;
+		cvmx_write_csr(CVMX_L2C_DBG, 0);
+		cvmx_read_csr(CVMX_L2C_DBG);
+		cvmx_spinlock_unlock(&cvmx_l2c_spinlock);
+	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/Kconfig linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/Kconfig
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,17 @@
 	depends on CPU_CAVIUM_OCTEON
 	default "y"
 
+config CAVIUM_CN63XXP1
+	bool "Enable CN63XXP1 errata worarounds"
+	depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
+	default "n"
+	help
+	  The CN63XXP1 chip requires build time workarounds to
+	  function reliably, select this option to enable them.  These
+	  workarounds will cause a slight decrease in performance on
+	  non-CN63XXP1 hardware, so it is recommended to select "n"
+	  unless it is known the workarounds are needed.
+
 config CAVIUM_OCTEON_2ND_KERNEL
 	bool "Build the kernel to be used as a 2nd kernel on the same chip"
 	depends on CAVIUM_OCTEON_SPECIFIC_OPTIONS
@@ -87,3 +98,15 @@
 config CAVIUM_OCTEON_HELPER
 	def_bool y
 	depends on OCTEON_ETHERNET || PCI
+
+config IOMMU_HELPER
+	bool
+
+config NEED_SG_DMA_LENGTH
+	bool
+
+config SWIOTLB
+	def_bool y
+	depends on CPU_CAVIUM_OCTEON
+	select IOMMU_HELPER
+	select NEED_SG_DMA_LENGTH
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/octeon-platform.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/octeon-platform.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/octeon-platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/octeon-platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,13 +3,15 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2004-2009 Cavium Networks
+ * Copyright (C) 2004-2010 Cavium Networks
  * Copyright (C) 2008 Wind River Systems
  */
 
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
+#include <linux/usb.h>
+#include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
@@ -198,7 +200,7 @@
 		num_ports = 1;
 
 	for (port = 0; port < num_ports; port++) {
-		octeon_i2c_data[port].sys_freq = octeon_get_clock_rate();
+		octeon_i2c_data[port].sys_freq = octeon_get_io_clock_rate();
 		/*FIXME: should be examined. At the moment is set for 100Khz */
 		octeon_i2c_data[port].i2c_freq = 100000;
 
@@ -301,6 +303,10 @@
 			ret = -ENOMEM;
 			goto out;
 		}
+		/* No DMA restrictions */
+		pd->dev.coherent_dma_mask = DMA_BIT_MASK(64);
+		pd->dev.dma_mask = &pd->dev.coherent_dma_mask;
+
 		switch (port) {
 		case 0:
 			mgmt_port_resource.start = OCTEON_IRQ_MII0;
@@ -332,6 +338,108 @@
 }
 device_initcall(octeon_mgmt_device_init);
 
+#ifdef CONFIG_USB
+
+static int __init octeon_ehci_device_init(void)
+{
+	struct platform_device *pd;
+	int ret = 0;
+
+	struct resource usb_resources[] = {
+		{
+			.flags	= IORESOURCE_MEM,
+		}, {
+			.flags	= IORESOURCE_IRQ,
+		}
+	};
+
+	/* Only Octeon2 has ehci/ohci */
+	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
+		return 0;
+
+	if (octeon_is_simulation() || usb_disabled())
+		return 0; /* No USB in the simulator. */
+
+	pd = platform_device_alloc("octeon-ehci", 0);
+	if (!pd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	usb_resources[0].start = 0x00016F0000000000ULL;
+	usb_resources[0].end = usb_resources[0].start + 0x100;
+
+	usb_resources[1].start = OCTEON_IRQ_USB0;
+	usb_resources[1].end = OCTEON_IRQ_USB0;
+
+	ret = platform_device_add_resources(pd, usb_resources,
+					    ARRAY_SIZE(usb_resources));
+	if (ret)
+		goto fail;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		goto fail;
+
+	return ret;
+fail:
+	platform_device_put(pd);
+out:
+	return ret;
+}
+device_initcall(octeon_ehci_device_init);
+
+static int __init octeon_ohci_device_init(void)
+{
+	struct platform_device *pd;
+	int ret = 0;
+
+	struct resource usb_resources[] = {
+		{
+			.flags	= IORESOURCE_MEM,
+		}, {
+			.flags	= IORESOURCE_IRQ,
+		}
+	};
+
+	/* Only Octeon2 has ehci/ohci */
+	if (!OCTEON_IS_MODEL(OCTEON_CN63XX))
+		return 0;
+
+	if (octeon_is_simulation() || usb_disabled())
+		return 0; /* No USB in the simulator. */
+
+	pd = platform_device_alloc("octeon-ohci", 0);
+	if (!pd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	usb_resources[0].start = 0x00016F0000000400ULL;
+	usb_resources[0].end = usb_resources[0].start + 0x100;
+
+	usb_resources[1].start = OCTEON_IRQ_USB0;
+	usb_resources[1].end = OCTEON_IRQ_USB0;
+
+	ret = platform_device_add_resources(pd, usb_resources,
+					    ARRAY_SIZE(usb_resources));
+	if (ret)
+		goto fail;
+
+	ret = platform_device_add(pd);
+	if (ret)
+		goto fail;
+
+	return ret;
+fail:
+	platform_device_put(pd);
+out:
+	return ret;
+}
+device_initcall(octeon_ohci_device_init);
+
+#endif /* CONFIG_USB */
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/serial.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/serial.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/tty.h>
+#include <linux/irq.h>
 
 #include <asm/time.h>
 
@@ -65,7 +66,7 @@
 		/* Make simulator output fast*/
 		p->uartclk = 115200 * 16;
 	else
-		p->uartclk = mips_hpt_frequency;
+		p->uartclk = octeon_get_io_clock_rate();
 	p->serial_in = octeon_serial_in;
 	p->serial_out = octeon_serial_out;
 }
diff -druN linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/setup.c linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/cavium-octeon/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/cavium-octeon/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/pci-octeon.h>
+#include <asm/octeon/cvmx-mio-defs.h>
 
 #ifdef CONFIG_CAVIUM_DECODE_RSL
 extern void cvmx_interrupt_rsl_decode(void);
@@ -96,12 +97,21 @@
  */
 uint64_t octeon_get_clock_rate(void)
 {
-	if (octeon_is_simulation())
-		octeon_bootinfo->eclock_hz = 6000000;
-	return octeon_bootinfo->eclock_hz;
+	struct cvmx_sysinfo *sysinfo = cvmx_sysinfo_get();
+
+	return sysinfo->cpu_clock_hz;
 }
 EXPORT_SYMBOL(octeon_get_clock_rate);
 
+static u64 octeon_io_clock_rate;
+
+u64 octeon_get_io_clock_rate(void)
+{
+	return octeon_io_clock_rate;
+}
+EXPORT_SYMBOL(octeon_get_io_clock_rate);
+
+
 /**
  * Write to the LCD display connected to the bootbus. This display
  * exists on most Cavium evaluation boards. If it doesn't exist, then
@@ -346,8 +356,18 @@
 	cvmmemctl.s.wbfltime = 0;
 	/* R/W If set, do not put Istream in the L2 cache. */
 	cvmmemctl.s.istrnol2 = 0;
-	/* R/W The write buffer threshold. */
-	cvmmemctl.s.wbthresh = 10;
+
+	/*
+	 * R/W The write buffer threshold. As per erratum Core-14752
+	 * for CN63XX, a sc/scd might fail if the write buffer is
+	 * full.  Lowering WBTHRESH greatly lowers the chances of the
+	 * write buffer ever being full and triggering the erratum.
+	 */
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
+		cvmmemctl.s.wbthresh = 4;
+	else
+		cvmmemctl.s.wbthresh = 10;
+
 	/* R/W If set, CVMSEG is available for loads/stores in
 	 * kernel/debug mode. */
 #if CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0
@@ -365,14 +385,13 @@
 	 * is max legal value. */
 	cvmmemctl.s.lmemsz = CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE;
 
+	write_c0_cvmmemctl(cvmmemctl.u64);
 
 	if (smp_processor_id() == 0)
 		pr_notice("CVMSEG size: %d cache lines (%d bytes)\n",
 			  CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE,
 			  CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128);
 
-	write_c0_cvmmemctl(cvmmemctl.u64);
-
 	/* Move the performance counter interrupts to IRQ 6 */
 	cvmctl = read_c0_cvmctl();
 	cvmctl &= ~(7 << 7);
@@ -416,6 +435,41 @@
 		cvmx_phys_to_ptr(octeon_boot_desc_ptr->cvmx_desc_vaddr);
 	cvmx_bootmem_init(cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr));
 
+	sysinfo = cvmx_sysinfo_get();
+	memset(sysinfo, 0, sizeof(*sysinfo));
+	sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20;
+	sysinfo->phy_mem_desc_ptr =
+		cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr);
+	sysinfo->core_mask = octeon_bootinfo->core_mask;
+	sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr;
+	sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz;
+	sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2;
+	sysinfo->board_type = octeon_bootinfo->board_type;
+	sysinfo->board_rev_major = octeon_bootinfo->board_rev_major;
+	sysinfo->board_rev_minor = octeon_bootinfo->board_rev_minor;
+	memcpy(sysinfo->mac_addr_base, octeon_bootinfo->mac_addr_base,
+	       sizeof(sysinfo->mac_addr_base));
+	sysinfo->mac_addr_count = octeon_bootinfo->mac_addr_count;
+	memcpy(sysinfo->board_serial_number,
+	       octeon_bootinfo->board_serial_number,
+	       sizeof(sysinfo->board_serial_number));
+	sysinfo->compact_flash_common_base_addr =
+		octeon_bootinfo->compact_flash_common_base_addr;
+	sysinfo->compact_flash_attribute_base_addr =
+		octeon_bootinfo->compact_flash_attribute_base_addr;
+	sysinfo->led_display_base_addr = octeon_bootinfo->led_display_base_addr;
+	sysinfo->dfa_ref_clock_hz = octeon_bootinfo->dfa_ref_clock_hz;
+	sysinfo->bootloader_config_flags = octeon_bootinfo->config_flags;
+
+	if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
+		/* I/O clock runs at a different rate than the CPU. */
+		union cvmx_mio_rst_boot rst_boot;
+		rst_boot.u64 = cvmx_read_csr(CVMX_MIO_RST_BOOT);
+		octeon_io_clock_rate = 50000000 * rst_boot.s.pnr_mul;
+	} else {
+		octeon_io_clock_rate = sysinfo->cpu_clock_hz;
+	}
+
 	/*
 	 * Only enable the LED controller if we're running on a CN38XX, CN58XX,
 	 * or CN56XX. The CN30XX and CN31XX don't have an LED controller.
@@ -479,33 +533,6 @@
 	}
 #endif
 
-	sysinfo = cvmx_sysinfo_get();
-	memset(sysinfo, 0, sizeof(*sysinfo));
-	sysinfo->system_dram_size = octeon_bootinfo->dram_size << 20;
-	sysinfo->phy_mem_desc_ptr =
-		cvmx_phys_to_ptr(octeon_bootinfo->phy_mem_desc_addr);
-	sysinfo->core_mask = octeon_bootinfo->core_mask;
-	sysinfo->exception_base_addr = octeon_bootinfo->exception_base_addr;
-	sysinfo->cpu_clock_hz = octeon_bootinfo->eclock_hz;
-	sysinfo->dram_data_rate_hz = octeon_bootinfo->dclock_hz * 2;
-	sysinfo->board_type = octeon_bootinfo->board_type;
-	sysinfo->board_rev_major = octeon_bootinfo->board_rev_major;
-	sysinfo->board_rev_minor = octeon_bootinfo->board_rev_minor;
-	memcpy(sysinfo->mac_addr_base, octeon_bootinfo->mac_addr_base,
-	       sizeof(sysinfo->mac_addr_base));
-	sysinfo->mac_addr_count = octeon_bootinfo->mac_addr_count;
-	memcpy(sysinfo->board_serial_number,
-	       octeon_bootinfo->board_serial_number,
-	       sizeof(sysinfo->board_serial_number));
-	sysinfo->compact_flash_common_base_addr =
-		octeon_bootinfo->compact_flash_common_base_addr;
-	sysinfo->compact_flash_attribute_base_addr =
-		octeon_bootinfo->compact_flash_attribute_base_addr;
-	sysinfo->led_display_base_addr = octeon_bootinfo->led_display_base_addr;
-	sysinfo->dfa_ref_clock_hz = octeon_bootinfo->dfa_ref_clock_hz;
-	sysinfo->bootloader_config_flags = octeon_bootinfo->config_flags;
-
-
 	octeon_check_cpu_bist();
 
 	octeon_uart = octeon_get_boot_uart();
@@ -740,6 +767,31 @@
 
 void prom_free_prom_memory(void)
 {
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X)) {
+		/* Check for presence of Core-14449 fix.  */
+		u32 insn;
+		u32 *foo;
+
+		foo = &insn;
+
+		asm volatile("# before" : : : "memory");
+		prefetch(foo);
+		asm volatile(
+			".set push\n\t"
+			".set noreorder\n\t"
+			"bal 1f\n\t"
+			"nop\n"
+			"1:\tlw %0,-12($31)\n\t"
+			".set pop\n\t"
+			: "=r" (insn) : : "$31", "memory");
+
+		if ((insn >> 26) != 0x33)
+			panic("No PREF instruction at Core-14449 probe point.\n");
+
+		if (((insn >> 16) & 0x1f) != 28)
+			panic("Core-14449 WAR not in place (%04x).\n"
+			      "Please build kernel with proper options (CONFIG_CAVIUM_CN63XXP1).\n", insn);
+	}
 #ifdef CONFIG_CAVIUM_DECODE_RSL
 	cvmx_interrupt_rsl_enable();
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/dec/setup.c linux-libre-2.6.37-gnu/arch/mips/dec/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/dec/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/dec/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/pm.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/atomic.h linux-libre-2.6.37-gnu/arch/mips/include/asm/atomic.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/atomic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/atomic.h	2011-01-04 19:50:19.000000000 -0500
@@ -64,18 +64,16 @@
 	} else if (kernel_uses_llsc) {
 		int temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %1		# atomic_add		\n"
-		"	addu	%0, %2					\n"
-		"	sc	%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%0, %1		# atomic_add	\n"
+			"	addu	%0, %2				\n"
+			"	sc	%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter));
+		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
 
@@ -109,18 +107,16 @@
 	} else if (kernel_uses_llsc) {
 		int temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %1		# atomic_sub		\n"
-		"	subu	%0, %2					\n"
-		"	sc	%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%0, %1		# atomic_sub	\n"
+			"	subu	%0, %2				\n"
+			"	sc	%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter));
+		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
 
@@ -156,20 +152,19 @@
 	} else if (kernel_uses_llsc) {
 		int temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%1, %2		# atomic_add_return	\n"
-		"	addu	%0, %1, %3				\n"
-		"	sc	%0, %2					\n"
-		"	beqz	%0, 2f					\n"
-		"	addu	%0, %1, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%1, %2	# atomic_add_return	\n"
+			"	addu	%0, %1, %3			\n"
+			"	sc	%0, %2				\n"
+			"	.set	mips0				\n"
+			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter)
+			: "memory");
+		} while (unlikely(!result));
+
+		result = temp + i;
 	} else {
 		unsigned long flags;
 
@@ -205,23 +200,24 @@
 		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
 		: "Ir" (i), "m" (v->counter)
 		: "memory");
+
+		result = temp - i;
 	} else if (kernel_uses_llsc) {
 		int temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%1, %2		# atomic_sub_return	\n"
-		"	subu	%0, %1, %3				\n"
-		"	sc	%0, %2					\n"
-		"	beqz	%0, 2f					\n"
-		"	subu	%0, %1, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%1, %2	# atomic_sub_return	\n"
+			"	subu	%0, %1, %3			\n"
+			"	sc	%0, %2				\n"
+			"	.set	mips0				\n"
+			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter)
+			: "memory");
+		} while (unlikely(!result));
+
+		result = temp - i;
 	} else {
 		unsigned long flags;
 
@@ -279,12 +275,9 @@
 		"	bltz	%0, 1f					\n"
 		"	sc	%0, %2					\n"
 		"	.set	noreorder				\n"
-		"	beqz	%0, 2f					\n"
+		"	beqz	%0, 1b					\n"
 		"	 subu	%0, %1, %3				\n"
 		"	.set	reorder					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
 		"1:							\n"
 		"	.set	mips0					\n"
 		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
@@ -443,18 +436,16 @@
 	} else if (kernel_uses_llsc) {
 		long temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %1		# atomic64_add		\n"
-		"	daddu	%0, %2					\n"
-		"	scd	%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%0, %1		# atomic64_add	\n"
+			"	daddu	%0, %2				\n"
+			"	scd	%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter));
+		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
 
@@ -488,18 +479,16 @@
 	} else if (kernel_uses_llsc) {
 		long temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %1		# atomic64_sub		\n"
-		"	dsubu	%0, %2					\n"
-		"	scd	%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%0, %1		# atomic64_sub	\n"
+			"	dsubu	%0, %2				\n"
+			"	scd	%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter));
+		} while (unlikely(!temp));
 	} else {
 		unsigned long flags;
 
@@ -535,20 +524,19 @@
 	} else if (kernel_uses_llsc) {
 		long temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%1, %2		# atomic64_add_return	\n"
-		"	daddu	%0, %1, %3				\n"
-		"	scd	%0, %2					\n"
-		"	beqz	%0, 2f					\n"
-		"	daddu	%0, %1, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%1, %2	# atomic64_add_return	\n"
+			"	daddu	%0, %1, %3			\n"
+			"	scd	%0, %2				\n"
+			"	.set	mips0				\n"
+			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter)
+			: "memory");
+		} while (unlikely(!result));
+
+		result = temp + i;
 	} else {
 		unsigned long flags;
 
@@ -587,20 +575,19 @@
 	} else if (kernel_uses_llsc) {
 		long temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%1, %2		# atomic64_sub_return	\n"
-		"	dsubu	%0, %1, %3				\n"
-		"	scd	%0, %2					\n"
-		"	beqz	%0, 2f					\n"
-		"	dsubu	%0, %1, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
-		: "Ir" (i), "m" (v->counter)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%1, %2	# atomic64_sub_return	\n"
+			"	dsubu	%0, %1, %3			\n"
+			"	scd	%0, %2				\n"
+			"	.set	mips0				\n"
+			: "=&r" (result), "=&r" (temp), "=m" (v->counter)
+			: "Ir" (i), "m" (v->counter)
+			: "memory");
+		} while (unlikely(!result));
+
+		result = temp - i;
 	} else {
 		unsigned long flags;
 
@@ -658,12 +645,9 @@
 		"	bltz	%0, 1f					\n"
 		"	scd	%0, %2					\n"
 		"	.set	noreorder				\n"
-		"	beqz	%0, 2f					\n"
+		"	beqz	%0, 1b					\n"
 		"	 dsubu	%0, %1, %3				\n"
 		"	.set	reorder					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
 		"1:							\n"
 		"	.set	mips0					\n"
 		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/bitops.h linux-libre-2.6.37-gnu/arch/mips/include/asm/bitops.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/bitops.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/bitops.h	2011-01-04 19:50:19.000000000 -0500
@@ -73,30 +73,26 @@
 		: "ir" (1UL << bit), "m" (*m));
 #ifdef CONFIG_CPU_MIPSR2
 	} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
-		__asm__ __volatile__(
-		"1:	" __LL "%0, %1			# set_bit	\n"
-		"	" __INS "%0, %4, %2, 1				\n"
-		"	" __SC "%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (bit), "m" (*m), "r" (~0));
+		do {
+			__asm__ __volatile__(
+			"	" __LL "%0, %1		# set_bit	\n"
+			"	" __INS "%0, %3, %2, 1			\n"
+			"	" __SC "%0, %1				\n"
+			: "=&r" (temp), "+m" (*m)
+			: "ir" (bit), "r" (~0));
+		} while (unlikely(!temp));
 #endif /* CONFIG_CPU_MIPSR2 */
 	} else if (kernel_uses_llsc) {
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	" __LL "%0, %1			# set_bit	\n"
-		"	or	%0, %2					\n"
-		"	" __SC	"%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (1UL << bit), "m" (*m));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL "%0, %1		# set_bit	\n"
+			"	or	%0, %2				\n"
+			"	" __SC	"%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m)
+			: "ir" (1UL << bit));
+		} while (unlikely(!temp));
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -134,34 +130,30 @@
 		"	" __SC "%0, %1					\n"
 		"	beqzl	%0, 1b					\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (~(1UL << bit)), "m" (*m));
+		: "=&r" (temp), "+m" (*m)
+		: "ir" (~(1UL << bit)));
 #ifdef CONFIG_CPU_MIPSR2
 	} else if (kernel_uses_llsc && __builtin_constant_p(bit)) {
-		__asm__ __volatile__(
-		"1:	" __LL "%0, %1			# clear_bit	\n"
-		"	" __INS "%0, $0, %2, 1				\n"
-		"	" __SC "%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (bit), "m" (*m));
+		do {
+			__asm__ __volatile__(
+			"	" __LL "%0, %1		# clear_bit	\n"
+			"	" __INS "%0, $0, %2, 1			\n"
+			"	" __SC "%0, %1				\n"
+			: "=&r" (temp), "+m" (*m)
+			: "ir" (bit));
+		} while (unlikely(!temp));
 #endif /* CONFIG_CPU_MIPSR2 */
 	} else if (kernel_uses_llsc) {
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	" __LL "%0, %1			# clear_bit	\n"
-		"	and	%0, %2					\n"
-		"	" __SC "%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (~(1UL << bit)), "m" (*m));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL "%0, %1		# clear_bit	\n"
+			"	and	%0, %2				\n"
+			"	" __SC "%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m)
+			: "ir" (~(1UL << bit)));
+		} while (unlikely(!temp));
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -213,24 +205,22 @@
 		"	" __SC	"%0, %1				\n"
 		"	beqzl	%0, 1b				\n"
 		"	.set	mips0				\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (1UL << bit), "m" (*m));
+		: "=&r" (temp), "+m" (*m)
+		: "ir" (1UL << bit));
 	} else if (kernel_uses_llsc) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"	.set	mips3				\n"
-		"1:	" __LL "%0, %1		# change_bit	\n"
-		"	xor	%0, %2				\n"
-		"	" __SC	"%0, %1				\n"
-		"	beqz	%0, 2f				\n"
-		"	.subsection 2				\n"
-		"2:	b	1b				\n"
-		"	.previous				\n"
-		"	.set	mips0				\n"
-		: "=&r" (temp), "=m" (*m)
-		: "ir" (1UL << bit), "m" (*m));
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL "%0, %1		# change_bit	\n"
+			"	xor	%0, %2				\n"
+			"	" __SC	"%0, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m)
+			: "ir" (1UL << bit));
+		} while (unlikely(!temp));
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -272,30 +262,26 @@
 		"	beqzl	%2, 1b					\n"
 		"	and	%2, %0, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
+		: "=&r" (temp), "+m" (*m), "=&r" (res)
+		: "r" (1UL << bit)
 		: "memory");
 	} else if (kernel_uses_llsc) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"	.set	push					\n"
-		"	.set	noreorder				\n"
-		"	.set	mips3					\n"
-		"1:	" __LL "%0, %1		# test_and_set_bit	\n"
-		"	or	%2, %0, %3				\n"
-		"	" __SC	"%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	 and	%2, %0, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	pop					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL "%0, %1	# test_and_set_bit	\n"
+			"	or	%2, %0, %3			\n"
+			"	" __SC	"%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m), "=&r" (res)
+			: "r" (1UL << bit)
+			: "memory");
+		} while (unlikely(!res));
+
+		res = temp & (1UL << bit);
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -340,30 +326,26 @@
 		"	beqzl	%2, 1b					\n"
 		"	and	%2, %0, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
+		: "=&r" (temp), "+m" (*m), "=&r" (res)
+		: "r" (1UL << bit)
 		: "memory");
 	} else if (kernel_uses_llsc) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"	.set	push					\n"
-		"	.set	noreorder				\n"
-		"	.set	mips3					\n"
-		"1:	" __LL "%0, %1		# test_and_set_bit	\n"
-		"	or	%2, %0, %3				\n"
-		"	" __SC	"%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	 and	%2, %0, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	pop					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL "%0, %1	# test_and_set_bit	\n"
+			"	or	%2, %0, %3			\n"
+			"	" __SC	"%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m), "=&r" (res)
+			: "r" (1UL << bit)
+			: "memory");
+		} while (unlikely(!res));
+
+		res = temp & (1UL << bit);
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -410,49 +392,43 @@
 		"	beqzl	%2, 1b					\n"
 		"	and	%2, %0, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
+		: "=&r" (temp), "+m" (*m), "=&r" (res)
+		: "r" (1UL << bit)
 		: "memory");
 #ifdef CONFIG_CPU_MIPSR2
 	} else if (kernel_uses_llsc && __builtin_constant_p(nr)) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"1:	" __LL	"%0, %1		# test_and_clear_bit	\n"
-		"	" __EXT "%2, %0, %3, 1				\n"
-		"	" __INS	"%0, $0, %3, 1				\n"
-		"	" __SC 	"%0, %1					\n"
-		"	beqz	%0, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "ir" (bit), "m" (*m)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	" __LL	"%0, %1	# test_and_clear_bit	\n"
+			"	" __EXT "%2, %0, %3, 1			\n"
+			"	" __INS	"%0, $0, %3, 1			\n"
+			"	" __SC 	"%0, %1				\n"
+			: "=&r" (temp), "+m" (*m), "=&r" (res)
+			: "ir" (bit)
+			: "memory");
+		} while (unlikely(!temp));
 #endif
 	} else if (kernel_uses_llsc) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"	.set	push					\n"
-		"	.set	noreorder				\n"
-		"	.set	mips3					\n"
-		"1:	" __LL	"%0, %1		# test_and_clear_bit	\n"
-		"	or	%2, %0, %3				\n"
-		"	xor	%2, %3					\n"
-		"	" __SC 	"%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	 and	%2, %0, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	pop					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL	"%0, %1	# test_and_clear_bit	\n"
+			"	or	%2, %0, %3			\n"
+			"	xor	%2, %3				\n"
+			"	" __SC 	"%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m), "=&r" (res)
+			: "r" (1UL << bit)
+			: "memory");
+		} while (unlikely(!res));
+
+		res = temp & (1UL << bit);
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
@@ -499,30 +475,26 @@
 		"	beqzl	%2, 1b					\n"
 		"	and	%2, %0, %3				\n"
 		"	.set	mips0					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
+		: "=&r" (temp), "+m" (*m), "=&r" (res)
+		: "r" (1UL << bit)
 		: "memory");
 	} else if (kernel_uses_llsc) {
 		unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
 		unsigned long temp;
 
-		__asm__ __volatile__(
-		"	.set	push					\n"
-		"	.set	noreorder				\n"
-		"	.set	mips3					\n"
-		"1:	" __LL	"%0, %1		# test_and_change_bit	\n"
-		"	xor	%2, %0, %3				\n"
-		"	" __SC	"\t%2, %1				\n"
-		"	beqz	%2, 2f					\n"
-		"	 and	%2, %0, %3				\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	 nop						\n"
-		"	.previous					\n"
-		"	.set	pop					\n"
-		: "=&r" (temp), "=m" (*m), "=&r" (res)
-		: "r" (1UL << bit), "m" (*m)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	" __LL	"%0, %1	# test_and_change_bit	\n"
+			"	xor	%2, %0, %3			\n"
+			"	" __SC	"\t%2, %1			\n"
+			"	.set	mips0				\n"
+			: "=&r" (temp), "+m" (*m), "=&r" (res)
+			: "r" (1UL << bit)
+			: "memory");
+		} while (unlikely(!res));
+
+		res = temp & (1UL << bit);
 	} else {
 		volatile unsigned long *a = addr;
 		unsigned long mask;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/bootinfo.h linux-libre-2.6.37-gnu/arch/mips/include/asm/bootinfo.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/bootinfo.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/bootinfo.h	2011-01-04 19:50:19.000000000 -0500
@@ -125,4 +125,16 @@
  */
 extern void plat_mem_setup(void);
 
+#ifdef CONFIG_SWIOTLB
+/*
+ * Optional platform hook to call swiotlb_setup().
+ */
+extern void plat_swiotlb_setup(void);
+
+#else
+
+static inline void plat_swiotlb_setup(void) {}
+
+#endif /* CONFIG_SWIOTLB */
+
 #endif /* _ASM_BOOTINFO_H */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/cmpxchg.h linux-libre-2.6.37-gnu/arch/mips/include/asm/cmpxchg.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/cmpxchg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/cmpxchg.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,12 +44,9 @@
 		"	move	$1, %z4				\n"	\
 		"	.set	mips3				\n"	\
 		"	" st "	$1, %1				\n"	\
-		"	beqz	$1, 3f				\n"	\
-		"2:						\n"	\
-		"	.subsection 2				\n"	\
-		"3:	b	1b				\n"	\
-		"	.previous				\n"	\
+		"	beqz	$1, 1b				\n"	\
 		"	.set	pop				\n"	\
+		"2:						\n"	\
 		: "=&r" (__ret), "=R" (*m)				\
 		: "R" (*m), "Jr" (old), "Jr" (new)			\
 		: "memory");						\
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/cpu.h linux-libre-2.6.37-gnu/arch/mips/include/asm/cpu.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -111,14 +111,16 @@
  * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
  */
 
-#define PRID_IMP_BCM4710	0x4000
-#define PRID_IMP_BCM3302	0x9000
-#define PRID_IMP_BCM6338	0x9000
-#define PRID_IMP_BCM6345	0x8000
-#define PRID_IMP_BCM6348	0x9100
-#define PRID_IMP_BCM4350	0xA000
-#define PRID_REV_BCM6358	0x0010
-#define PRID_REV_BCM6368	0x0030
+#define PRID_IMP_BMIPS32_REV4	0x4000
+#define PRID_IMP_BMIPS32_REV8	0x8000
+#define PRID_IMP_BMIPS3300	0x9000
+#define PRID_IMP_BMIPS3300_ALT	0x9100
+#define PRID_IMP_BMIPS3300_BUG	0x0000
+#define PRID_IMP_BMIPS43XX	0xa000
+#define PRID_IMP_BMIPS5000	0x5a00
+
+#define PRID_REV_BMIPS4380_LO	0x0040
+#define PRID_REV_BMIPS4380_HI	0x006f
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_CAVIUM
@@ -131,6 +133,7 @@
 #define PRID_IMP_CAVIUM_CN56XX 0x0400
 #define PRID_IMP_CAVIUM_CN50XX 0x0600
 #define PRID_IMP_CAVIUM_CN52XX 0x0700
+#define PRID_IMP_CAVIUM_CN63XX 0x9000
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
@@ -223,15 +226,14 @@
 	 * MIPS32 class processors
 	 */
 	CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
-	CPU_ALCHEMY, CPU_PR4450, CPU_BCM3302, CPU_BCM4710,
-	CPU_BCM6338, CPU_BCM6345, CPU_BCM6348, CPU_BCM6358,
-	CPU_JZRISC,
+	CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
+	CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC,
 
 	/*
 	 * MIPS64 class processors
 	 */
 	CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
-	CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS,
+	CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
 
 	CPU_LAST
 };
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/device.h linux-libre-2.6.37-gnu/arch/mips/include/asm/device.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/device.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/device.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,4 +3,17 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_MIPS_DEVICE_H
+#define _ASM_MIPS_DEVICE_H
+
+struct dma_map_ops;
+
+struct dev_archdata {
+	/* DMA operations on that device */
+	struct dma_map_ops *dma_ops;
+};
+
+struct pdev_archdata {
+};
+
+#endif /* _ASM_MIPS_DEVICE_H*/
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/dma.h linux-libre-2.6.37-gnu/arch/mips/include/asm/dma.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,10 @@
 #define MAX_DMA_ADDRESS		(PAGE_OFFSET + 0x01000000)
 #endif
 #define MAX_DMA_PFN		PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS))
+
+#ifndef MAX_DMA32_PFN
 #define MAX_DMA32_PFN		(1UL << (32 - PAGE_SHIFT))
+#endif
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/dma-mapping.h linux-libre-2.6.37-gnu/arch/mips/include/asm/dma-mapping.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/dma-mapping.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/dma-mapping.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,51 +5,41 @@
 #include <asm/cache.h>
 #include <asm-generic/dma-coherent.h>
 
-void *dma_alloc_noncoherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
+#include <dma-coherence.h>
 
-void dma_free_noncoherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
+extern struct dma_map_ops *mips_dma_map_ops;
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
-			   dma_addr_t *dma_handle, gfp_t flag);
+static inline struct dma_map_ops *get_dma_ops(struct device *dev)
+{
+	if (dev && dev->archdata.dma_ops)
+		return dev->archdata.dma_ops;
+	else
+		return mips_dma_map_ops;
+}
 
-void dma_free_coherent(struct device *dev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle);
+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+	if (!dev->dma_mask)
+		return 0;
 
-extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-	enum dma_data_direction direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-	size_t size, enum dma_data_direction direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	enum dma_data_direction direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
-	unsigned long offset, size_t size, enum dma_data_direction direction);
+	return addr + size <= *dev->dma_mask;
+}
 
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-	size_t size, enum dma_data_direction direction)
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+#include <asm-generic/dma-mapping-common.h>
+
+static inline int dma_supported(struct device *dev, u64 mask)
 {
-	dma_unmap_single(dev, dma_address, size, direction);
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	return ops->dma_supported(dev, mask);
 }
 
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-	int nhwentries, enum dma_data_direction direction);
-extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-	size_t size, enum dma_data_direction direction);
-extern void dma_sync_single_for_device(struct device *dev,
-	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction);
-extern void dma_sync_single_range_for_cpu(struct device *dev,
-	dma_addr_t dma_handle, unsigned long offset, size_t size,
-	enum dma_data_direction direction);
-extern void dma_sync_single_range_for_device(struct device *dev,
-	dma_addr_t dma_handle, unsigned long offset, size_t size,
-	enum dma_data_direction direction);
-extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-	int nelems, enum dma_data_direction direction);
-extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
-	int nelems, enum dma_data_direction direction);
-extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
-extern int dma_supported(struct device *dev, u64 mask);
+static inline int dma_mapping_error(struct device *dev, u64 mask)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+	return ops->mapping_error(dev, mask);
+}
 
 static inline int
 dma_set_mask(struct device *dev, u64 mask)
@@ -65,4 +55,34 @@
 extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 	       enum dma_data_direction direction);
 
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t gfp)
+{
+	void *ret;
+	struct dma_map_ops *ops = get_dma_ops(dev);
+
+	ret = ops->alloc_coherent(dev, size, dma_handle, gfp);
+
+	debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
+
+	return ret;
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t dma_handle)
+{
+	struct dma_map_ops *ops = get_dma_ops(dev);
+
+	ops->free_coherent(dev, size, vaddr, dma_handle);
+
+	debug_dma_free_coherent(dev, size, vaddr, dma_handle);
+}
+
+
+void *dma_alloc_noncoherent(struct device *dev, size_t size,
+			   dma_addr_t *dma_handle, gfp_t flag);
+
+void dma_free_noncoherent(struct device *dev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle);
+
 #endif /* _ASM_DMA_MAPPING_H */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/elf.h linux-libre-2.6.37-gnu/arch/mips/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -249,7 +249,8 @@
 
 #define SET_PERSONALITY(ex)						\
 do {									\
-	set_personality(PER_LINUX);					\
+	if (personality(current->personality) != PER_LINUX)		\
+		set_personality(PER_LINUX);				\
 									\
 	current->thread.abi = &mips_abi;				\
 } while (0)
@@ -296,6 +297,8 @@
 
 #define SET_PERSONALITY(ex)						\
 do {									\
+	unsigned int p;							\
+									\
 	clear_thread_flag(TIF_32BIT_REGS);				\
 	clear_thread_flag(TIF_32BIT_ADDR);				\
 									\
@@ -304,7 +307,8 @@
 	else								\
 		current->thread.abi = &mips_abi;			\
 									\
-	if (current->personality != PER_LINUX32)			\
+	p = personality(current->personality);				\
+	if (p != PER_LINUX32 && p != PER_LINUX)				\
 		set_personality(PER_LINUX);				\
 } while (0)
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/mips/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -45,18 +45,12 @@
 extern void * kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
 
-extern void *__kmap(struct page *page);
-extern void __kunmap(struct page *page);
-extern void *__kmap_atomic(struct page *page, enum km_type type);
-extern void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-extern struct page *__kmap_atomic_to_page(void *ptr);
-
-#define kmap			__kmap
-#define kunmap			__kunmap
-#define kmap_atomic		__kmap_atomic
-#define kunmap_atomic_notypecheck		__kunmap_atomic_notypecheck
-#define kmap_atomic_to_page	__kmap_atomic_to_page
+extern void *kmap(struct page *page);
+extern void kunmap(struct page *page);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
+extern void *kmap_atomic_pfn(unsigned long pfn);
+extern struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()	flush_cache_all()
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/io.h linux-libre-2.6.37-gnu/arch/mips/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -329,10 +329,14 @@
 			"dsrl32	%L0, %L0, 0"			"\n\t"	\
 			"dsll32	%M0, %M0, 0"			"\n\t"	\
 			"or	%L0, %L0, %M0"			"\n\t"	\
+			".set	push"				"\n\t"	\
+			".set	noreorder"			"\n\t"	\
+			".set	nomacro"			"\n\t"	\
 			"sd	%L0, %2"			"\n\t"	\
+			".set	pop"				"\n\t"	\
 			".set	mips0"				"\n"	\
 			: "=r" (__tmp)					\
-			: "0" (__val), "m" (*__mem));			\
+			: "0" (__val), "R" (*__mem));			\
 		if (irq)						\
 			local_irq_restore(__flags);			\
 	} else								\
@@ -355,12 +359,16 @@
 			local_irq_save(__flags);			\
 		__asm__ __volatile__(					\
 			".set	mips3"		"\t\t# __readq"	"\n\t"	\
+			".set	push"				"\n\t"	\
+			".set	noreorder"			"\n\t"	\
+			".set	nomacro"			"\n\t"	\
 			"ld	%L0, %1"			"\n\t"	\
+			".set	pop"				"\n\t"	\
 			"dsra32	%M0, %L0, 0"			"\n\t"	\
 			"sll	%L0, %L0, 0"			"\n\t"	\
 			".set	mips0"				"\n"	\
 			: "=r" (__val)					\
-			: "m" (*__mem));				\
+			: "R" (*__mem));				\
 		if (irq)						\
 			local_irq_restore(__flags);			\
 	} else {							\
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/mips/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,7 @@
 #include <asm/hazards.h>
 
 __asm__(
-	"	.macro	raw_local_irq_enable				\n"
+	"	.macro	arch_local_irq_enable				\n"
 	"	.set	push						\n"
 	"	.set	reorder						\n"
 	"	.set	noat						\n"
@@ -40,7 +40,7 @@
 
 extern void smtc_ipi_replay(void);
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
 #ifdef CONFIG_MIPS_MT_SMTC
 	/*
@@ -50,7 +50,7 @@
 	smtc_ipi_replay();
 #endif
 	__asm__ __volatile__(
-		"raw_local_irq_enable"
+		"arch_local_irq_enable"
 		: /* no outputs */
 		: /* no inputs */
 		: "memory");
@@ -76,7 +76,7 @@
  * Workaround: mask EXL bit of the result or place a nop before mfc0.
  */
 __asm__(
-	"	.macro	raw_local_irq_disable\n"
+	"	.macro	arch_local_irq_disable\n"
 	"	.set	push						\n"
 	"	.set	noat						\n"
 #ifdef CONFIG_MIPS_MT_SMTC
@@ -97,17 +97,17 @@
 	"	.set	pop						\n"
 	"	.endm							\n");
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
 	__asm__ __volatile__(
-		"raw_local_irq_disable"
+		"arch_local_irq_disable"
 		: /* no outputs */
 		: /* no inputs */
 		: "memory");
 }
 
 __asm__(
-	"	.macro	raw_local_save_flags flags			\n"
+	"	.macro	arch_local_save_flags flags			\n"
 	"	.set	push						\n"
 	"	.set	reorder						\n"
 #ifdef CONFIG_MIPS_MT_SMTC
@@ -118,13 +118,15 @@
 	"	.set	pop						\n"
 	"	.endm							\n");
 
-#define raw_local_save_flags(x)						\
-__asm__ __volatile__(							\
-	"raw_local_save_flags %0"					\
-	: "=r" (x))
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("arch_local_save_flags %0" : "=r" (flags));
+	return flags;
+}
 
 __asm__(
-	"	.macro	raw_local_irq_save result			\n"
+	"	.macro	arch_local_irq_save result			\n"
 	"	.set	push						\n"
 	"	.set	reorder						\n"
 	"	.set	noat						\n"
@@ -148,15 +150,18 @@
 	"	.set	pop						\n"
 	"	.endm							\n");
 
-#define raw_local_irq_save(x)						\
-__asm__ __volatile__(							\
-	"raw_local_irq_save\t%0"					\
-	: "=r" (x)							\
-	: /* no inputs */						\
-	: "memory")
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	asm volatile("arch_local_irq_save\t%0"
+		     : "=r" (flags)
+		     : /* no inputs */
+		     : "memory");
+	return flags;
+}
 
 __asm__(
-	"	.macro	raw_local_irq_restore flags			\n"
+	"	.macro	arch_local_irq_restore flags			\n"
 	"	.set	push						\n"
 	"	.set	noreorder					\n"
 	"	.set	noat						\n"
@@ -196,7 +201,7 @@
 	"	.endm							\n");
 
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
 	unsigned long __tmp1;
 
@@ -211,24 +216,24 @@
 #endif
 
 	__asm__ __volatile__(
-		"raw_local_irq_restore\t%0"
+		"arch_local_irq_restore\t%0"
 		: "=r" (__tmp1)
 		: "0" (flags)
 		: "memory");
 }
 
-static inline void __raw_local_irq_restore(unsigned long flags)
+static inline void __arch_local_irq_restore(unsigned long flags)
 {
 	unsigned long __tmp1;
 
 	__asm__ __volatile__(
-		"raw_local_irq_restore\t%0"
+		"arch_local_irq_restore\t%0"
 		: "=r" (__tmp1)
 		: "0" (flags)
 		: "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
 #ifdef CONFIG_MIPS_MT_SMTC
 	/*
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/irq.h linux-libre-2.6.37-gnu/arch/mips/include/asm/irq.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,11 @@
 
 #include <irq.h>
 
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+	return;
+}
+
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/local.h linux-libre-2.6.37-gnu/arch/mips/include/asm/local.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/local.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/local.h	2011-01-04 19:50:19.000000000 -0500
@@ -117,7 +117,7 @@
 
 #define local_cmpxchg(l, o, n) \
 	((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
-#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+#define local_xchg(l, n) (atomic_long_xchg((&(l)->a), (n)))
 
 /**
  * local_add_unless - add unless the number is a given value
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ar7/ar7.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ar7/ar7.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ar7/ar7.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ar7/ar7.h	2011-01-04 19:50:19.000000000 -0500
@@ -39,6 +39,7 @@
 #define AR7_REGS_UART0	(AR7_REGS_BASE + 0x0e00)
 #define AR7_REGS_USB	(AR7_REGS_BASE + 0x1200)
 #define AR7_REGS_RESET	(AR7_REGS_BASE + 0x1600)
+#define AR7_REGS_PINSEL (AR7_REGS_BASE + 0x160C)
 #define AR7_REGS_VLYNQ0	(AR7_REGS_BASE + 0x1800)
 #define AR7_REGS_DCL	(AR7_REGS_BASE + 0x1a00)
 #define AR7_REGS_VLYNQ1	(AR7_REGS_BASE + 0x1c00)
@@ -50,6 +51,14 @@
 #define UR8_REGS_WDT	(AR7_REGS_BASE + 0x0b00)
 #define UR8_REGS_UART1	(AR7_REGS_BASE + 0x0f00)
 
+/* Titan registers */
+#define TITAN_REGS_ESWITCH_BASE	(0x08640000)
+#define TITAN_REGS_MAC0		(TITAN_REGS_ESWITCH_BASE)
+#define TITAN_REGS_MAC1		(TITAN_REGS_ESWITCH_BASE + 0x0800)
+#define TITAN_REGS_MDIO		(TITAN_REGS_ESWITCH_BASE + 0x02000)
+#define TITAN_REGS_VLYNQ0	(AR7_REGS_BASE + 0x1c00)
+#define TITAN_REGS_VLYNQ1	(AR7_REGS_BASE + 0x1300)
+
 #define AR7_RESET_PERIPHERAL	0x0
 #define AR7_RESET_SOFTWARE	0x4
 #define AR7_RESET_STATUS	0x8
@@ -59,15 +68,30 @@
 #define AR7_RESET_BIT_MDIO	22
 #define AR7_RESET_BIT_EPHY	26
 
+#define TITAN_RESET_BIT_EPHY1	28
+
 /* GPIO control registers */
 #define AR7_GPIO_INPUT	0x0
 #define AR7_GPIO_OUTPUT	0x4
 #define AR7_GPIO_DIR	0x8
 #define AR7_GPIO_ENABLE	0xc
+#define TITAN_GPIO_INPUT_0	0x0
+#define TITAN_GPIO_INPUT_1	0x4
+#define TITAN_GPIO_OUTPUT_0	0x8
+#define TITAN_GPIO_OUTPUT_1	0xc
+#define TITAN_GPIO_DIR_0	0x10
+#define TITAN_GPIO_DIR_1	0x14
+#define TITAN_GPIO_ENBL_0	0x18
+#define TITAN_GPIO_ENBL_1	0x1c
 
 #define AR7_CHIP_7100	0x18
 #define AR7_CHIP_7200	0x2b
 #define AR7_CHIP_7300	0x05
+#define AR7_CHIP_TITAN	0x07
+#define TITAN_CHIP_1050	0x0f
+#define TITAN_CHIP_1055	0x0e
+#define TITAN_CHIP_1056	0x0d
+#define TITAN_CHIP_1060	0x07
 
 /* Interrupts */
 #define AR7_IRQ_UART0	15
@@ -95,14 +119,29 @@
 
 extern int ar7_cpu_clock, ar7_bus_clock, ar7_dsp_clock;
 
+static inline int ar7_is_titan(void)
+{
+	return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x24)) & 0xffff) ==
+		AR7_CHIP_TITAN;
+}
+
 static inline u16 ar7_chip_id(void)
 {
-	return readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) & 0xffff;
+	return ar7_is_titan() ? AR7_CHIP_TITAN : (readl((void *)
+		KSEG1ADDR(AR7_REGS_GPIO + 0x14)) & 0xffff);
+}
+
+static inline u16 titan_chip_id(void)
+{
+	unsigned int val = readl((void *)KSEG1ADDR(AR7_REGS_GPIO +
+						TITAN_GPIO_INPUT_1));
+	return ((val >> 12) & 0x0f);
 }
 
 static inline u8 ar7_chip_rev(void)
 {
-	return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) >> 16) & 0xff;
+	return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + (ar7_is_titan() ? 0x24 :
+		0x14))) >> 16) & 0xff;
 }
 
 struct clk {
@@ -161,4 +200,7 @@
 	msleep(20);
 }
 
+int __init ar7_gpio_init(void);
+void __init ar7_init_clocks(void);
+
 #endif /* __AR7_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ar7/gpio.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ar7/gpio.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ar7/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ar7/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -22,7 +22,8 @@
 #include <asm/mach-ar7/ar7.h>
 
 #define AR7_GPIO_MAX 32
-#define NR_BUILTIN_GPIO AR7_GPIO_MAX
+#define TITAN_GPIO_MAX	51
+#define NR_BUILTIN_GPIO TITAN_GPIO_MAX
 
 #define gpio_to_irq(gpio)	-1
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-bcm47xx/nvram.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-bcm47xx/nvram.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-bcm47xx/nvram.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-bcm47xx/nvram.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #define __NVRAM_H
 
 #include <linux/types.h>
+#include <linux/kernel.h>
 
 struct nvram_header {
 	u32 magic;
@@ -36,4 +37,10 @@
 
 extern int nvram_getenv(char *name, char *val, size_t val_len);
 
+static inline void nvram_parse_macaddr(char *buf, u8 *macaddr)
+{
+	sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1],
+	       &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]);
+}
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-bcm63xx/bcm963xx_tag.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,97 @@
+#ifndef __BCM963XX_TAG_H
+#define __BCM963XX_TAG_H
+
+#define TAGVER_LEN		4	/* Length of Tag Version */
+#define TAGLAYOUT_LEN		4	/* Length of FlashLayoutVer */
+#define SIG1_LEN		20	/* Company Signature 1 Length */
+#define SIG2_LEN		14	/* Company Signature 2 Lenght */
+#define BOARDID_LEN		16	/* Length of BoardId */
+#define ENDIANFLAG_LEN		2	/* Endian Flag Length */
+#define CHIPID_LEN		6	/* Chip Id Length */
+#define IMAGE_LEN		10	/* Length of Length Field */
+#define ADDRESS_LEN		12	/* Length of Address field */
+#define DUALFLAG_LEN		2	/* Dual Image flag Length */
+#define INACTIVEFLAG_LEN	2	/* Inactie Flag Length */
+#define RSASIG_LEN		20	/* Length of RSA Signature in tag */
+#define TAGINFO1_LEN		30	/* Length of vendor information field1 in tag */
+#define FLASHLAYOUTVER_LEN	4	/* Length of Flash Layout Version String tag */
+#define TAGINFO2_LEN		16	/* Length of vendor information field2 in tag */
+#define CRC_LEN			4	/* Length of CRC in bytes */
+#define ALTTAGINFO_LEN		54	/* Alternate length for vendor information; Pirelli */
+
+#define NUM_PIRELLI		2
+#define IMAGETAG_CRC_START	0xFFFFFFFF
+
+#define PIRELLI_BOARDS { \
+	"AGPF-S0", \
+	"DWV-S0", \
+}
+
+/*
+ * The broadcom firmware assumes the rootfs starts the image,
+ * therefore uses the rootfs start (flash_image_address)
+ * to determine where to flash the image.  Since we have the kernel first
+ * we have to give it the kernel address, but the crc uses the length
+ * associated with this address (root_length), which is added to the kernel
+ * length (kernel_length) to determine the length of image to flash and thus
+ * needs to be rootfs + deadcode (jffs2 EOF marker)
+*/
+
+struct bcm_tag {
+	/* 0-3: Version of the image tag */
+	char tag_version[TAGVER_LEN];
+	/* 4-23: Company Line 1 */
+	char sig_1[SIG1_LEN];
+	/*  24-37: Company Line 2 */
+	char sig_2[SIG2_LEN];
+	/* 38-43: Chip this image is for */
+	char chip_id[CHIPID_LEN];
+	/* 44-59: Board name */
+	char board_id[BOARDID_LEN];
+	/* 60-61: Map endianness -- 1 BE 0 LE */
+	char big_endian[ENDIANFLAG_LEN];
+	/* 62-71: Total length of image */
+	char total_length[IMAGE_LEN];
+	/* 72-83: Address in memory of CFE */
+	char cfe__address[ADDRESS_LEN];
+	/* 84-93: Size of CFE */
+	char cfe_length[IMAGE_LEN];
+	/* 94-105: Address in memory of image start
+	 * (kernel for OpenWRT, rootfs for stock firmware)
+	 */
+	char flash_image_start[ADDRESS_LEN];
+	/* 106-115: Size of rootfs */
+	char root_length[IMAGE_LEN];
+	/* 116-127: Address in memory of kernel */
+	char kernel_address[ADDRESS_LEN];
+	/* 128-137: Size of kernel */
+	char kernel_length[IMAGE_LEN];
+	/* 138-139: Unused at the moment */
+	char dual_image[DUALFLAG_LEN];
+	/* 140-141: Unused at the moment */
+	char inactive_flag[INACTIVEFLAG_LEN];
+	/* 142-161: RSA Signature (not used; some vendors may use this) */
+	char rsa_signature[RSASIG_LEN];
+	/* 162-191: Compilation and related information (not used in OpenWrt) */
+	char information1[TAGINFO1_LEN];
+	/* 192-195: Version flash layout */
+	char flash_layout_ver[FLASHLAYOUTVER_LEN];
+	/* 196-199: kernel+rootfs CRC32 */
+	char fskernel_crc[CRC_LEN];
+	/* 200-215: Unused except on Alice Gate where is is information */
+	char information2[TAGINFO2_LEN];
+	/* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */
+	char image_crc[CRC_LEN];
+	/* 220-223: CRC32 of rootfs partition */
+	char rootfs_crc[CRC_LEN];
+	/* 224-227: CRC32 of kernel partition */
+	char kernel_crc[CRC_LEN];
+	/* 228-235: Unused at present */
+	char reserved1[8];
+	/* 236-239: CRC32 of header excluding tagVersion */
+	char header_crc[CRC_LEN];
+	/* 240-255: Unused at present */
+	char reserved2[16];
+};
+
+#endif /* __BCM63XX_TAG_H */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h	2011-01-04 19:50:19.000000000 -0500
@@ -59,7 +59,7 @@
 #define cpu_has_veic		0
 #define cpu_hwrena_impl_bits	0xc0000000
 
-#define kernel_uses_smartmips_rixi (cpu_data[0].cputype == CPU_CAVIUM_OCTEON_PLUS)
+#define kernel_uses_smartmips_rixi (cpu_data[0].cputype != CPU_CAVIUM_OCTEON)
 
 #define ARCH_HAS_IRQ_PER_CPU	1
 #define ARCH_HAS_SPINLOCK_PREFETCH 1
@@ -81,4 +81,10 @@
 	return id >= 0x000d0300;
 }
 
+/*
+ * The last 256MB are reserved for device to device mappings and the
+ * BAR1 hole.
+ */
+#define MAX_DMA32_PFN (((1ULL << 32) - (1ULL << 28)) >> PAGE_SHIFT)
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-cavium-octeon/dma-coherence.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,41 +15,40 @@
 
 struct device;
 
-dma_addr_t octeon_map_dma_mem(struct device *, void *, size_t);
-void octeon_unmap_dma_mem(struct device *, dma_addr_t);
+extern void octeon_pci_dma_init(void);
 
 static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
 	size_t size)
 {
-	return octeon_map_dma_mem(dev, addr, size);
+	BUG();
 }
 
 static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
 	struct page *page)
 {
-	return octeon_map_dma_mem(dev, page_address(page), PAGE_SIZE);
+	BUG();
 }
 
 static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
 	dma_addr_t dma_addr)
 {
-	return dma_addr;
+	BUG();
 }
 
 static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
 	size_t size, enum dma_data_direction direction)
 {
-	octeon_unmap_dma_mem(dev, dma_addr);
+	BUG();
 }
 
 static inline int plat_dma_supported(struct device *dev, u64 mask)
 {
-	return 1;
+	BUG();
 }
 
 static inline void plat_extra_sync_for_device(struct device *dev)
 {
-	mb();
+	BUG();
 }
 
 static inline int plat_device_is_coherent(struct device *dev)
@@ -60,7 +59,14 @@
 static inline int plat_dma_mapping_error(struct device *dev,
 					 dma_addr_t dma_addr)
 {
-	return dma_addr == -1;
+	BUG();
 }
 
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
+
+struct dma_map_ops;
+extern struct dma_map_ops *octeon_pci_dma_map_ops;
+extern char *octeon_swiotlb;
+
 #endif /* __ASM_MACH_CAVIUM_OCTEON_DMA_COHERENCE_H */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ip27/dma-coherence.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ip27/dma-coherence.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ip27/dma-coherence.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ip27/dma-coherence.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,14 +26,15 @@
 	return pa;
 }
 
-static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
+	struct page *page)
 {
 	dma_addr_t pa = dev_to_baddr(dev, page_to_phys(page));
 
 	return pa;
 }
 
-static unsigned long plat_dma_addr_to_phys(struct device *dev,
+static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
 	dma_addr_t dma_addr)
 {
 	return dma_addr & ~(0xffUL << 56);
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ip32/dma-coherence.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ip32/dma-coherence.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-ip32/dma-coherence.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-ip32/dma-coherence.h	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,8 @@
 	return pa;
 }
 
-static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
+	struct page *page)
 {
 	dma_addr_t pa;
 
@@ -50,7 +51,7 @@
 }
 
 /* This is almost certainly wrong but it's what dma-ip32.c used to use  */
-static unsigned long plat_dma_addr_to_phys(struct device *dev,
+static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
 	dma_addr_t dma_addr)
 {
 	unsigned long addr = dma_addr & RAM_OFFSET_MASK;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-jazz/dma-coherence.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-jazz/dma-coherence.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-jazz/dma-coherence.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-jazz/dma-coherence.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,23 +12,24 @@
 
 struct device;
 
-static dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, size_t size)
 {
 	return vdma_alloc(virt_to_phys(addr), size);
 }
 
-static dma_addr_t plat_map_dma_mem_page(struct device *dev, struct page *page)
+static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
+	struct page *page)
 {
 	return vdma_alloc(page_to_phys(page), PAGE_SIZE);
 }
 
-static unsigned long plat_dma_addr_to_phys(struct device *dev,
+static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
 	dma_addr_t dma_addr)
 {
 	return vdma_log2phys(dma_addr);
 }
 
-static void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
+static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
 	size_t size, enum dma_data_direction direction)
 {
 	vdma_free(dma_addr);
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-loongson/loongson.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-loongson/loongson.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mach-loongson/loongson.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mach-loongson/loongson.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 
 #include <linux/io.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 /* loongson internal northbridge initialization */
 extern void bonito_irq_init(void);
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/mipsregs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/mipsregs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/mipsregs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/mipsregs.h	2011-01-04 19:50:19.000000000 -0500
@@ -1040,6 +1040,12 @@
 #define read_c0_dtaglo()	__read_32bit_c0_register($28, 2)
 #define write_c0_dtaglo(val)	__write_32bit_c0_register($28, 2, val)
 
+#define read_c0_ddatalo()	__read_32bit_c0_register($28, 3)
+#define write_c0_ddatalo(val)	__write_32bit_c0_register($28, 3, val)
+
+#define read_c0_staglo()	__read_32bit_c0_register($28, 4)
+#define write_c0_staglo(val)	__write_32bit_c0_register($28, 4, val)
+
 #define read_c0_taghi()		__read_32bit_c0_register($29, 0)
 #define write_c0_taghi(val)	__write_32bit_c0_register($29, 0, val)
 
@@ -1082,6 +1088,51 @@
 #define read_octeon_c0_dcacheerr()	__read_64bit_c0_register($27, 1)
 #define write_octeon_c0_dcacheerr(val)	__write_64bit_c0_register($27, 1, val)
 
+/* BMIPS3300 */
+#define read_c0_brcm_config_0()		__read_32bit_c0_register($22, 0)
+#define write_c0_brcm_config_0(val)	__write_32bit_c0_register($22, 0, val)
+
+#define read_c0_brcm_bus_pll()		__read_32bit_c0_register($22, 4)
+#define write_c0_brcm_bus_pll(val)	__write_32bit_c0_register($22, 4, val)
+
+#define read_c0_brcm_reset()		__read_32bit_c0_register($22, 5)
+#define write_c0_brcm_reset(val)	__write_32bit_c0_register($22, 5, val)
+
+/* BMIPS4380 */
+#define read_c0_brcm_cmt_intr()		__read_32bit_c0_register($22, 1)
+#define write_c0_brcm_cmt_intr(val)	__write_32bit_c0_register($22, 1, val)
+
+#define read_c0_brcm_cmt_ctrl()		__read_32bit_c0_register($22, 2)
+#define write_c0_brcm_cmt_ctrl(val)	__write_32bit_c0_register($22, 2, val)
+
+#define read_c0_brcm_cmt_local()	__read_32bit_c0_register($22, 3)
+#define write_c0_brcm_cmt_local(val)	__write_32bit_c0_register($22, 3, val)
+
+#define read_c0_brcm_config_1()		__read_32bit_c0_register($22, 5)
+#define write_c0_brcm_config_1(val)	__write_32bit_c0_register($22, 5, val)
+
+#define read_c0_brcm_cbr()		__read_32bit_c0_register($22, 6)
+#define write_c0_brcm_cbr(val)		__write_32bit_c0_register($22, 6, val)
+
+/* BMIPS5000 */
+#define read_c0_brcm_config()		__read_32bit_c0_register($22, 0)
+#define write_c0_brcm_config(val)	__write_32bit_c0_register($22, 0, val)
+
+#define read_c0_brcm_mode()		__read_32bit_c0_register($22, 1)
+#define write_c0_brcm_mode(val)		__write_32bit_c0_register($22, 1, val)
+
+#define read_c0_brcm_action()		__read_32bit_c0_register($22, 2)
+#define write_c0_brcm_action(val)	__write_32bit_c0_register($22, 2, val)
+
+#define read_c0_brcm_edsp()		__read_32bit_c0_register($22, 3)
+#define write_c0_brcm_edsp(val)		__write_32bit_c0_register($22, 3, val)
+
+#define read_c0_brcm_bootvec()		__read_32bit_c0_register($22, 4)
+#define write_c0_brcm_bootvec(val)	__write_32bit_c0_register($22, 4, val)
+
+#define read_c0_brcm_sleepcount()	__read_32bit_c0_register($22, 7)
+#define write_c0_brcm_sleepcount(val)	__write_32bit_c0_register($22, 7, val)
+
 /*
  * Macros to access the floating point coprocessor control registers
  */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-agl-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-agl-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-agl-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-agl-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,148 +28,80 @@
 #ifndef __CVMX_AGL_DEFS_H__
 #define __CVMX_AGL_DEFS_H__
 
-#define CVMX_AGL_GMX_BAD_REG \
-	 CVMX_ADD_IO_SEG(0x00011800E0000518ull)
-#define CVMX_AGL_GMX_BIST \
-	 CVMX_ADD_IO_SEG(0x00011800E0000400ull)
-#define CVMX_AGL_GMX_DRV_CTL \
-	 CVMX_ADD_IO_SEG(0x00011800E00007F0ull)
-#define CVMX_AGL_GMX_INF_MODE \
-	 CVMX_ADD_IO_SEG(0x00011800E00007F8ull)
-#define CVMX_AGL_GMX_PRTX_CFG(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000010ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM0(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000180ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM1(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000188ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM2(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000190ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM3(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000198ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM4(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00001A0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM5(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00001A8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CAM_EN(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000108ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_ADR_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000100ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_DECISION(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000040ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_FRM_CHK(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000020ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_FRM_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000018ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_FRM_MAX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000030ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_FRM_MIN(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000028ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_IFG(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000058ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_INT_EN(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000008ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_INT_REG(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000000ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_JABBER(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000038ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_PAUSE_DROP_TIME(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000068ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000050ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_OCTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000088ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_OCTS_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000098ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_OCTS_DMAC(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00000A8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_OCTS_DRP(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00000B8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_PKTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000080ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00000C0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_PKTS_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000090ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_PKTS_DMAC(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00000A0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00000B0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RXX_UDD_SKP(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000048ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_RX_BP_DROPX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000420ull + (((offset) & 1) * 8))
-#define CVMX_AGL_GMX_RX_BP_OFFX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000460ull + (((offset) & 1) * 8))
-#define CVMX_AGL_GMX_RX_BP_ONX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000440ull + (((offset) & 1) * 8))
-#define CVMX_AGL_GMX_RX_PRT_INFO \
-	 CVMX_ADD_IO_SEG(0x00011800E00004E8ull)
-#define CVMX_AGL_GMX_RX_TX_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011800E00007E8ull)
-#define CVMX_AGL_GMX_SMACX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000230ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_STAT_BP \
-	 CVMX_ADD_IO_SEG(0x00011800E0000520ull)
-#define CVMX_AGL_GMX_TXX_APPEND(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000218ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000270ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_MIN_PKT(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000240ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_PAUSE_PKT_INTERVAL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000248ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_PAUSE_PKT_TIME(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000238ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_PAUSE_TOGO(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000258ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_PAUSE_ZERO(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000260ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_SOFT_PAUSE(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000250ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT0(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000280ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT1(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000288ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT2(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000290ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT3(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000298ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT4(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002A0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT5(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002A8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT6(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002B0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT7(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002B8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT8(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002C0ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STAT9(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E00002C8ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_STATS_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000268ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TXX_THRESH(offset) \
-	 CVMX_ADD_IO_SEG(0x00011800E0000210ull + (((offset) & 1) * 2048))
-#define CVMX_AGL_GMX_TX_BP \
-	 CVMX_ADD_IO_SEG(0x00011800E00004D0ull)
-#define CVMX_AGL_GMX_TX_COL_ATTEMPT \
-	 CVMX_ADD_IO_SEG(0x00011800E0000498ull)
-#define CVMX_AGL_GMX_TX_IFG \
-	 CVMX_ADD_IO_SEG(0x00011800E0000488ull)
-#define CVMX_AGL_GMX_TX_INT_EN \
-	 CVMX_ADD_IO_SEG(0x00011800E0000508ull)
-#define CVMX_AGL_GMX_TX_INT_REG \
-	 CVMX_ADD_IO_SEG(0x00011800E0000500ull)
-#define CVMX_AGL_GMX_TX_JAM \
-	 CVMX_ADD_IO_SEG(0x00011800E0000490ull)
-#define CVMX_AGL_GMX_TX_LFSR \
-	 CVMX_ADD_IO_SEG(0x00011800E00004F8ull)
-#define CVMX_AGL_GMX_TX_OVR_BP \
-	 CVMX_ADD_IO_SEG(0x00011800E00004C8ull)
-#define CVMX_AGL_GMX_TX_PAUSE_PKT_DMAC \
-	 CVMX_ADD_IO_SEG(0x00011800E00004A0ull)
-#define CVMX_AGL_GMX_TX_PAUSE_PKT_TYPE \
-	 CVMX_ADD_IO_SEG(0x00011800E00004A8ull)
+#define CVMX_AGL_GMX_BAD_REG (CVMX_ADD_IO_SEG(0x00011800E0000518ull))
+#define CVMX_AGL_GMX_BIST (CVMX_ADD_IO_SEG(0x00011800E0000400ull))
+#define CVMX_AGL_GMX_DRV_CTL (CVMX_ADD_IO_SEG(0x00011800E00007F0ull))
+#define CVMX_AGL_GMX_INF_MODE (CVMX_ADD_IO_SEG(0x00011800E00007F8ull))
+#define CVMX_AGL_GMX_PRTX_CFG(offset) (CVMX_ADD_IO_SEG(0x00011800E0000010ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM0(offset) (CVMX_ADD_IO_SEG(0x00011800E0000180ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM1(offset) (CVMX_ADD_IO_SEG(0x00011800E0000188ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM2(offset) (CVMX_ADD_IO_SEG(0x00011800E0000190ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM3(offset) (CVMX_ADD_IO_SEG(0x00011800E0000198ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM4(offset) (CVMX_ADD_IO_SEG(0x00011800E00001A0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM5(offset) (CVMX_ADD_IO_SEG(0x00011800E00001A8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CAM_EN(offset) (CVMX_ADD_IO_SEG(0x00011800E0000108ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_ADR_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000100ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_DECISION(offset) (CVMX_ADD_IO_SEG(0x00011800E0000040ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_FRM_CHK(offset) (CVMX_ADD_IO_SEG(0x00011800E0000020ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_FRM_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000018ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_FRM_MAX(offset) (CVMX_ADD_IO_SEG(0x00011800E0000030ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_FRM_MIN(offset) (CVMX_ADD_IO_SEG(0x00011800E0000028ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_IFG(offset) (CVMX_ADD_IO_SEG(0x00011800E0000058ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_INT_EN(offset) (CVMX_ADD_IO_SEG(0x00011800E0000008ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_INT_REG(offset) (CVMX_ADD_IO_SEG(0x00011800E0000000ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_JABBER(offset) (CVMX_ADD_IO_SEG(0x00011800E0000038ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_PAUSE_DROP_TIME(offset) (CVMX_ADD_IO_SEG(0x00011800E0000068ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_RX_INBND(offset) (CVMX_ADD_IO_SEG(0x00011800E0000060ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000050ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_OCTS(offset) (CVMX_ADD_IO_SEG(0x00011800E0000088ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000098ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_DMAC(offset) (CVMX_ADD_IO_SEG(0x00011800E00000A8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_DRP(offset) (CVMX_ADD_IO_SEG(0x00011800E00000B8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_PKTS(offset) (CVMX_ADD_IO_SEG(0x00011800E0000080ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(offset) (CVMX_ADD_IO_SEG(0x00011800E00000C0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000090ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_DMAC(offset) (CVMX_ADD_IO_SEG(0x00011800E00000A0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(offset) (CVMX_ADD_IO_SEG(0x00011800E00000B0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RXX_UDD_SKP(offset) (CVMX_ADD_IO_SEG(0x00011800E0000048ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_RX_BP_DROPX(offset) (CVMX_ADD_IO_SEG(0x00011800E0000420ull) + ((offset) & 1) * 8)
+#define CVMX_AGL_GMX_RX_BP_OFFX(offset) (CVMX_ADD_IO_SEG(0x00011800E0000460ull) + ((offset) & 1) * 8)
+#define CVMX_AGL_GMX_RX_BP_ONX(offset) (CVMX_ADD_IO_SEG(0x00011800E0000440ull) + ((offset) & 1) * 8)
+#define CVMX_AGL_GMX_RX_PRT_INFO (CVMX_ADD_IO_SEG(0x00011800E00004E8ull))
+#define CVMX_AGL_GMX_RX_TX_STATUS (CVMX_ADD_IO_SEG(0x00011800E00007E8ull))
+#define CVMX_AGL_GMX_SMACX(offset) (CVMX_ADD_IO_SEG(0x00011800E0000230ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_STAT_BP (CVMX_ADD_IO_SEG(0x00011800E0000520ull))
+#define CVMX_AGL_GMX_TXX_APPEND(offset) (CVMX_ADD_IO_SEG(0x00011800E0000218ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_CLK(offset) (CVMX_ADD_IO_SEG(0x00011800E0000208ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000270ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_MIN_PKT(offset) (CVMX_ADD_IO_SEG(0x00011800E0000240ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_PAUSE_PKT_INTERVAL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000248ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_PAUSE_PKT_TIME(offset) (CVMX_ADD_IO_SEG(0x00011800E0000238ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_PAUSE_TOGO(offset) (CVMX_ADD_IO_SEG(0x00011800E0000258ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_PAUSE_ZERO(offset) (CVMX_ADD_IO_SEG(0x00011800E0000260ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_SOFT_PAUSE(offset) (CVMX_ADD_IO_SEG(0x00011800E0000250ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT0(offset) (CVMX_ADD_IO_SEG(0x00011800E0000280ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT1(offset) (CVMX_ADD_IO_SEG(0x00011800E0000288ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT2(offset) (CVMX_ADD_IO_SEG(0x00011800E0000290ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT3(offset) (CVMX_ADD_IO_SEG(0x00011800E0000298ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT4(offset) (CVMX_ADD_IO_SEG(0x00011800E00002A0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT5(offset) (CVMX_ADD_IO_SEG(0x00011800E00002A8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT6(offset) (CVMX_ADD_IO_SEG(0x00011800E00002B0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT7(offset) (CVMX_ADD_IO_SEG(0x00011800E00002B8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT8(offset) (CVMX_ADD_IO_SEG(0x00011800E00002C0ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STAT9(offset) (CVMX_ADD_IO_SEG(0x00011800E00002C8ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_STATS_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0000268ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TXX_THRESH(offset) (CVMX_ADD_IO_SEG(0x00011800E0000210ull) + ((offset) & 1) * 2048)
+#define CVMX_AGL_GMX_TX_BP (CVMX_ADD_IO_SEG(0x00011800E00004D0ull))
+#define CVMX_AGL_GMX_TX_COL_ATTEMPT (CVMX_ADD_IO_SEG(0x00011800E0000498ull))
+#define CVMX_AGL_GMX_TX_IFG (CVMX_ADD_IO_SEG(0x00011800E0000488ull))
+#define CVMX_AGL_GMX_TX_INT_EN (CVMX_ADD_IO_SEG(0x00011800E0000508ull))
+#define CVMX_AGL_GMX_TX_INT_REG (CVMX_ADD_IO_SEG(0x00011800E0000500ull))
+#define CVMX_AGL_GMX_TX_JAM (CVMX_ADD_IO_SEG(0x00011800E0000490ull))
+#define CVMX_AGL_GMX_TX_LFSR (CVMX_ADD_IO_SEG(0x00011800E00004F8ull))
+#define CVMX_AGL_GMX_TX_OVR_BP (CVMX_ADD_IO_SEG(0x00011800E00004C8ull))
+#define CVMX_AGL_GMX_TX_PAUSE_PKT_DMAC (CVMX_ADD_IO_SEG(0x00011800E00004A0ull))
+#define CVMX_AGL_GMX_TX_PAUSE_PKT_TYPE (CVMX_ADD_IO_SEG(0x00011800E00004A8ull))
+#define CVMX_AGL_PRTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011800E0002000ull) + ((offset) & 1) * 8)
 
 union cvmx_agl_gmx_bad_reg {
 	uint64_t u64;
@@ -183,14 +115,29 @@
 		uint64_t ovrflw:1;
 		uint64_t reserved_27_31:5;
 		uint64_t statovr:1;
+		uint64_t reserved_24_25:2;
+		uint64_t loststat:2;
+		uint64_t reserved_4_21:18;
+		uint64_t out_ovr:2;
+		uint64_t reserved_0_1:2;
+	} s;
+	struct cvmx_agl_gmx_bad_reg_cn52xx {
+		uint64_t reserved_38_63:26;
+		uint64_t txpsh1:1;
+		uint64_t txpop1:1;
+		uint64_t ovrflw1:1;
+		uint64_t txpsh:1;
+		uint64_t txpop:1;
+		uint64_t ovrflw:1;
+		uint64_t reserved_27_31:5;
+		uint64_t statovr:1;
 		uint64_t reserved_23_25:3;
 		uint64_t loststat:1;
 		uint64_t reserved_4_21:18;
 		uint64_t out_ovr:2;
 		uint64_t reserved_0_1:2;
-	} s;
-	struct cvmx_agl_gmx_bad_reg_s cn52xx;
-	struct cvmx_agl_gmx_bad_reg_s cn52xxp1;
+	} cn52xx;
+	struct cvmx_agl_gmx_bad_reg_cn52xx cn52xxp1;
 	struct cvmx_agl_gmx_bad_reg_cn56xx {
 		uint64_t reserved_35_63:29;
 		uint64_t txpsh:1;
@@ -205,18 +152,25 @@
 		uint64_t reserved_0_1:2;
 	} cn56xx;
 	struct cvmx_agl_gmx_bad_reg_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_bad_reg_s cn63xx;
+	struct cvmx_agl_gmx_bad_reg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_bist {
 	uint64_t u64;
 	struct cvmx_agl_gmx_bist_s {
+		uint64_t reserved_25_63:39;
+		uint64_t status:25;
+	} s;
+	struct cvmx_agl_gmx_bist_cn52xx {
 		uint64_t reserved_10_63:54;
 		uint64_t status:10;
-	} s;
-	struct cvmx_agl_gmx_bist_s cn52xx;
-	struct cvmx_agl_gmx_bist_s cn52xxp1;
-	struct cvmx_agl_gmx_bist_s cn56xx;
-	struct cvmx_agl_gmx_bist_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_agl_gmx_bist_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_bist_cn52xx cn56xx;
+	struct cvmx_agl_gmx_bist_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_bist_s cn63xx;
+	struct cvmx_agl_gmx_bist_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_drv_ctl {
@@ -264,7 +218,13 @@
 union cvmx_agl_gmx_prtx_cfg {
 	uint64_t u64;
 	struct cvmx_agl_gmx_prtx_cfg_s {
-		uint64_t reserved_6_63:58;
+		uint64_t reserved_14_63:50;
+		uint64_t tx_idle:1;
+		uint64_t rx_idle:1;
+		uint64_t reserved_9_11:3;
+		uint64_t speed_msb:1;
+		uint64_t reserved_7_7:1;
+		uint64_t burst:1;
 		uint64_t tx_en:1;
 		uint64_t rx_en:1;
 		uint64_t slottime:1;
@@ -272,10 +232,20 @@
 		uint64_t speed:1;
 		uint64_t en:1;
 	} s;
-	struct cvmx_agl_gmx_prtx_cfg_s cn52xx;
-	struct cvmx_agl_gmx_prtx_cfg_s cn52xxp1;
-	struct cvmx_agl_gmx_prtx_cfg_s cn56xx;
-	struct cvmx_agl_gmx_prtx_cfg_s cn56xxp1;
+	struct cvmx_agl_gmx_prtx_cfg_cn52xx {
+		uint64_t reserved_6_63:58;
+		uint64_t tx_en:1;
+		uint64_t rx_en:1;
+		uint64_t slottime:1;
+		uint64_t duplex:1;
+		uint64_t speed:1;
+		uint64_t en:1;
+	} cn52xx;
+	struct cvmx_agl_gmx_prtx_cfg_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_prtx_cfg_cn52xx cn56xx;
+	struct cvmx_agl_gmx_prtx_cfg_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_prtx_cfg_s cn63xx;
+	struct cvmx_agl_gmx_prtx_cfg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam0 {
@@ -287,6 +257,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam0_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam0_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam0_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam1 {
@@ -298,6 +270,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam1_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam1_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam1_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam2 {
@@ -309,6 +283,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam2_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam2_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam2_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam3 {
@@ -320,6 +296,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam3_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam3_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam3_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam4 {
@@ -331,6 +309,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam4_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam4_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam4_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam5 {
@@ -342,6 +322,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam5_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam5_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam5_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_cam_en {
@@ -354,6 +336,8 @@
 	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_adr_ctl {
@@ -368,6 +352,8 @@
 	struct cvmx_agl_gmx_rxx_adr_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_adr_ctl_s cn56xx;
 	struct cvmx_agl_gmx_rxx_adr_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn63xx;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_decision {
@@ -380,11 +366,26 @@
 	struct cvmx_agl_gmx_rxx_decision_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_decision_s cn56xx;
 	struct cvmx_agl_gmx_rxx_decision_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_decision_s cn63xx;
+	struct cvmx_agl_gmx_rxx_decision_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_frm_chk {
 	uint64_t u64;
 	struct cvmx_agl_gmx_rxx_frm_chk_s {
+		uint64_t reserved_10_63:54;
+		uint64_t niberr:1;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t carext:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_frm_chk_cn52xx {
 		uint64_t reserved_9_63:55;
 		uint64_t skperr:1;
 		uint64_t rcverr:1;
@@ -395,17 +396,21 @@
 		uint64_t maxerr:1;
 		uint64_t reserved_1_1:1;
 		uint64_t minerr:1;
-	} s;
-	struct cvmx_agl_gmx_rxx_frm_chk_s cn52xx;
-	struct cvmx_agl_gmx_rxx_frm_chk_s cn52xxp1;
-	struct cvmx_agl_gmx_rxx_frm_chk_s cn56xx;
-	struct cvmx_agl_gmx_rxx_frm_chk_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_chk_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_chk_cn52xx cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_chk_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn63xx;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_frm_ctl {
 	uint64_t u64;
 	struct cvmx_agl_gmx_rxx_frm_ctl_s {
-		uint64_t reserved_10_63:54;
+		uint64_t reserved_13_63:51;
+		uint64_t ptp_mode:1;
+		uint64_t reserved_11_11:1;
+		uint64_t null_dis:1;
 		uint64_t pre_align:1;
 		uint64_t pad_len:1;
 		uint64_t vlan_len:1;
@@ -417,10 +422,24 @@
 		uint64_t pre_strp:1;
 		uint64_t pre_chk:1;
 	} s;
-	struct cvmx_agl_gmx_rxx_frm_ctl_s cn52xx;
-	struct cvmx_agl_gmx_rxx_frm_ctl_s cn52xxp1;
-	struct cvmx_agl_gmx_rxx_frm_ctl_s cn56xx;
-	struct cvmx_agl_gmx_rxx_frm_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_frm_ctl_cn52xx {
+		uint64_t reserved_10_63:54;
+		uint64_t pre_align:1;
+		uint64_t pad_len:1;
+		uint64_t vlan_len:1;
+		uint64_t pre_free:1;
+		uint64_t ctl_smac:1;
+		uint64_t ctl_mcst:1;
+		uint64_t ctl_bck:1;
+		uint64_t ctl_drp:1;
+		uint64_t pre_strp:1;
+		uint64_t pre_chk:1;
+	} cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_ctl_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_ctl_cn52xx cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_ctl_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn63xx;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_frm_max {
@@ -433,6 +452,8 @@
 	struct cvmx_agl_gmx_rxx_frm_max_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_frm_max_s cn56xx;
 	struct cvmx_agl_gmx_rxx_frm_max_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn63xx;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_frm_min {
@@ -445,6 +466,8 @@
 	struct cvmx_agl_gmx_rxx_frm_min_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_frm_min_s cn56xx;
 	struct cvmx_agl_gmx_rxx_frm_min_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn63xx;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_ifg {
@@ -457,6 +480,8 @@
 	struct cvmx_agl_gmx_rxx_ifg_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_ifg_s cn56xx;
 	struct cvmx_agl_gmx_rxx_ifg_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_ifg_s cn63xx;
+	struct cvmx_agl_gmx_rxx_ifg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_int_en {
@@ -464,6 +489,29 @@
 	struct cvmx_agl_gmx_rxx_int_en_s {
 		uint64_t reserved_20_63:44;
 		uint64_t pause_drp:1;
+		uint64_t phy_dupx:1;
+		uint64_t phy_spd:1;
+		uint64_t phy_link:1;
+		uint64_t ifgerr:1;
+		uint64_t coldet:1;
+		uint64_t falerr:1;
+		uint64_t rsverr:1;
+		uint64_t pcterr:1;
+		uint64_t ovrerr:1;
+		uint64_t niberr:1;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t carext:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_int_en_cn52xx {
+		uint64_t reserved_20_63:44;
+		uint64_t pause_drp:1;
 		uint64_t reserved_16_18:3;
 		uint64_t ifgerr:1;
 		uint64_t coldet:1;
@@ -481,11 +529,12 @@
 		uint64_t maxerr:1;
 		uint64_t reserved_1_1:1;
 		uint64_t minerr:1;
-	} s;
-	struct cvmx_agl_gmx_rxx_int_en_s cn52xx;
-	struct cvmx_agl_gmx_rxx_int_en_s cn52xxp1;
-	struct cvmx_agl_gmx_rxx_int_en_s cn56xx;
-	struct cvmx_agl_gmx_rxx_int_en_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_agl_gmx_rxx_int_en_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_rxx_int_en_cn52xx cn56xx;
+	struct cvmx_agl_gmx_rxx_int_en_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_rxx_int_en_s cn63xx;
+	struct cvmx_agl_gmx_rxx_int_en_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_int_reg {
@@ -493,6 +542,29 @@
 	struct cvmx_agl_gmx_rxx_int_reg_s {
 		uint64_t reserved_20_63:44;
 		uint64_t pause_drp:1;
+		uint64_t phy_dupx:1;
+		uint64_t phy_spd:1;
+		uint64_t phy_link:1;
+		uint64_t ifgerr:1;
+		uint64_t coldet:1;
+		uint64_t falerr:1;
+		uint64_t rsverr:1;
+		uint64_t pcterr:1;
+		uint64_t ovrerr:1;
+		uint64_t niberr:1;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t carext:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_int_reg_cn52xx {
+		uint64_t reserved_20_63:44;
+		uint64_t pause_drp:1;
 		uint64_t reserved_16_18:3;
 		uint64_t ifgerr:1;
 		uint64_t coldet:1;
@@ -510,11 +582,12 @@
 		uint64_t maxerr:1;
 		uint64_t reserved_1_1:1;
 		uint64_t minerr:1;
-	} s;
-	struct cvmx_agl_gmx_rxx_int_reg_s cn52xx;
-	struct cvmx_agl_gmx_rxx_int_reg_s cn52xxp1;
-	struct cvmx_agl_gmx_rxx_int_reg_s cn56xx;
-	struct cvmx_agl_gmx_rxx_int_reg_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_agl_gmx_rxx_int_reg_cn52xx cn52xxp1;
+	struct cvmx_agl_gmx_rxx_int_reg_cn52xx cn56xx;
+	struct cvmx_agl_gmx_rxx_int_reg_cn52xx cn56xxp1;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn63xx;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_jabber {
@@ -527,6 +600,8 @@
 	struct cvmx_agl_gmx_rxx_jabber_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_jabber_s cn56xx;
 	struct cvmx_agl_gmx_rxx_jabber_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_jabber_s cn63xx;
+	struct cvmx_agl_gmx_rxx_jabber_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_pause_drop_time {
@@ -539,6 +614,20 @@
 	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn56xx;
 	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn63xx;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn63xxp1;
+};
+
+union cvmx_agl_gmx_rxx_rx_inbnd {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_rx_inbnd_s {
+		uint64_t reserved_4_63:60;
+		uint64_t duplex:1;
+		uint64_t speed:2;
+		uint64_t status:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_rx_inbnd_s cn63xx;
+	struct cvmx_agl_gmx_rxx_rx_inbnd_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_ctl {
@@ -551,6 +640,8 @@
 	struct cvmx_agl_gmx_rxx_stats_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_ctl_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_octs {
@@ -563,6 +654,8 @@
 	struct cvmx_agl_gmx_rxx_stats_octs_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_octs_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_octs_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_octs_ctl {
@@ -575,6 +668,8 @@
 	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_octs_dmac {
@@ -587,6 +682,8 @@
 	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_octs_drp {
@@ -599,6 +696,8 @@
 	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_pkts {
@@ -611,6 +710,8 @@
 	struct cvmx_agl_gmx_rxx_stats_pkts_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_pkts_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_pkts_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_pkts_bad {
@@ -623,6 +724,8 @@
 	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_pkts_ctl {
@@ -635,6 +738,8 @@
 	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_pkts_dmac {
@@ -647,6 +752,8 @@
 	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_stats_pkts_drp {
@@ -659,6 +766,8 @@
 	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn56xx;
 	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn63xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rxx_udd_skp {
@@ -673,6 +782,8 @@
 	struct cvmx_agl_gmx_rxx_udd_skp_s cn52xxp1;
 	struct cvmx_agl_gmx_rxx_udd_skp_s cn56xx;
 	struct cvmx_agl_gmx_rxx_udd_skp_s cn56xxp1;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn63xx;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rx_bp_dropx {
@@ -685,6 +796,8 @@
 	struct cvmx_agl_gmx_rx_bp_dropx_s cn52xxp1;
 	struct cvmx_agl_gmx_rx_bp_dropx_s cn56xx;
 	struct cvmx_agl_gmx_rx_bp_dropx_s cn56xxp1;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn63xx;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rx_bp_offx {
@@ -697,6 +810,8 @@
 	struct cvmx_agl_gmx_rx_bp_offx_s cn52xxp1;
 	struct cvmx_agl_gmx_rx_bp_offx_s cn56xx;
 	struct cvmx_agl_gmx_rx_bp_offx_s cn56xxp1;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn63xx;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rx_bp_onx {
@@ -709,6 +824,8 @@
 	struct cvmx_agl_gmx_rx_bp_onx_s cn52xxp1;
 	struct cvmx_agl_gmx_rx_bp_onx_s cn56xx;
 	struct cvmx_agl_gmx_rx_bp_onx_s cn56xxp1;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn63xx;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rx_prt_info {
@@ -728,6 +845,8 @@
 		uint64_t commit:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_rx_prt_info_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_rx_prt_info_s cn63xx;
+	struct cvmx_agl_gmx_rx_prt_info_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_rx_tx_status {
@@ -747,6 +866,8 @@
 		uint64_t rx:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_rx_tx_status_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_rx_tx_status_s cn63xx;
+	struct cvmx_agl_gmx_rx_tx_status_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_smacx {
@@ -759,6 +880,8 @@
 	struct cvmx_agl_gmx_smacx_s cn52xxp1;
 	struct cvmx_agl_gmx_smacx_s cn56xx;
 	struct cvmx_agl_gmx_smacx_s cn56xxp1;
+	struct cvmx_agl_gmx_smacx_s cn63xx;
+	struct cvmx_agl_gmx_smacx_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_stat_bp {
@@ -772,6 +895,8 @@
 	struct cvmx_agl_gmx_stat_bp_s cn52xxp1;
 	struct cvmx_agl_gmx_stat_bp_s cn56xx;
 	struct cvmx_agl_gmx_stat_bp_s cn56xxp1;
+	struct cvmx_agl_gmx_stat_bp_s cn63xx;
+	struct cvmx_agl_gmx_stat_bp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_append {
@@ -787,6 +912,18 @@
 	struct cvmx_agl_gmx_txx_append_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_append_s cn56xx;
 	struct cvmx_agl_gmx_txx_append_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_append_s cn63xx;
+	struct cvmx_agl_gmx_txx_append_s cn63xxp1;
+};
+
+union cvmx_agl_gmx_txx_clk {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_clk_s {
+		uint64_t reserved_6_63:58;
+		uint64_t clk_cnt:6;
+	} s;
+	struct cvmx_agl_gmx_txx_clk_s cn63xx;
+	struct cvmx_agl_gmx_txx_clk_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_ctl {
@@ -800,6 +937,8 @@
 	struct cvmx_agl_gmx_txx_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_ctl_s cn56xx;
 	struct cvmx_agl_gmx_txx_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_ctl_s cn63xx;
+	struct cvmx_agl_gmx_txx_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_min_pkt {
@@ -812,6 +951,8 @@
 	struct cvmx_agl_gmx_txx_min_pkt_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_min_pkt_s cn56xx;
 	struct cvmx_agl_gmx_txx_min_pkt_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn63xx;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_pause_pkt_interval {
@@ -824,6 +965,8 @@
 	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn56xx;
 	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn63xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_pause_pkt_time {
@@ -836,6 +979,8 @@
 	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn56xx;
 	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn63xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_pause_togo {
@@ -848,6 +993,8 @@
 	struct cvmx_agl_gmx_txx_pause_togo_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_pause_togo_s cn56xx;
 	struct cvmx_agl_gmx_txx_pause_togo_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn63xx;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_pause_zero {
@@ -860,6 +1007,8 @@
 	struct cvmx_agl_gmx_txx_pause_zero_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_pause_zero_s cn56xx;
 	struct cvmx_agl_gmx_txx_pause_zero_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn63xx;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_soft_pause {
@@ -872,6 +1021,8 @@
 	struct cvmx_agl_gmx_txx_soft_pause_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_soft_pause_s cn56xx;
 	struct cvmx_agl_gmx_txx_soft_pause_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn63xx;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat0 {
@@ -884,6 +1035,8 @@
 	struct cvmx_agl_gmx_txx_stat0_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat0_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat0_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat0_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat0_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat1 {
@@ -896,6 +1049,8 @@
 	struct cvmx_agl_gmx_txx_stat1_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat1_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat1_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat1_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat1_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat2 {
@@ -908,6 +1063,8 @@
 	struct cvmx_agl_gmx_txx_stat2_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat2_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat2_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat2_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat2_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat3 {
@@ -920,6 +1077,8 @@
 	struct cvmx_agl_gmx_txx_stat3_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat3_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat3_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat3_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat3_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat4 {
@@ -932,6 +1091,8 @@
 	struct cvmx_agl_gmx_txx_stat4_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat4_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat4_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat4_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat4_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat5 {
@@ -944,6 +1105,8 @@
 	struct cvmx_agl_gmx_txx_stat5_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat5_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat5_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat5_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat5_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat6 {
@@ -956,6 +1119,8 @@
 	struct cvmx_agl_gmx_txx_stat6_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat6_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat6_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat6_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat6_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat7 {
@@ -968,6 +1133,8 @@
 	struct cvmx_agl_gmx_txx_stat7_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat7_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat7_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat7_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat7_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat8 {
@@ -980,6 +1147,8 @@
 	struct cvmx_agl_gmx_txx_stat8_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat8_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat8_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat8_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat8_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stat9 {
@@ -992,6 +1161,8 @@
 	struct cvmx_agl_gmx_txx_stat9_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stat9_s cn56xx;
 	struct cvmx_agl_gmx_txx_stat9_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stat9_s cn63xx;
+	struct cvmx_agl_gmx_txx_stat9_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_stats_ctl {
@@ -1004,6 +1175,8 @@
 	struct cvmx_agl_gmx_txx_stats_ctl_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_stats_ctl_s cn56xx;
 	struct cvmx_agl_gmx_txx_stats_ctl_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn63xx;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_txx_thresh {
@@ -1016,6 +1189,8 @@
 	struct cvmx_agl_gmx_txx_thresh_s cn52xxp1;
 	struct cvmx_agl_gmx_txx_thresh_s cn56xx;
 	struct cvmx_agl_gmx_txx_thresh_s cn56xxp1;
+	struct cvmx_agl_gmx_txx_thresh_s cn63xx;
+	struct cvmx_agl_gmx_txx_thresh_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_bp {
@@ -1031,6 +1206,8 @@
 		uint64_t bp:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_tx_bp_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_tx_bp_s cn63xx;
+	struct cvmx_agl_gmx_tx_bp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_col_attempt {
@@ -1043,6 +1220,8 @@
 	struct cvmx_agl_gmx_tx_col_attempt_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_col_attempt_s cn56xx;
 	struct cvmx_agl_gmx_tx_col_attempt_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn63xx;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_ifg {
@@ -1056,12 +1235,16 @@
 	struct cvmx_agl_gmx_tx_ifg_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_ifg_s cn56xx;
 	struct cvmx_agl_gmx_tx_ifg_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_ifg_s cn63xx;
+	struct cvmx_agl_gmx_tx_ifg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_int_en {
 	uint64_t u64;
 	struct cvmx_agl_gmx_tx_int_en_s {
-		uint64_t reserved_18_63:46;
+		uint64_t reserved_22_63:42;
+		uint64_t ptp_lost:2;
+		uint64_t reserved_18_19:2;
 		uint64_t late_col:2;
 		uint64_t reserved_14_15:2;
 		uint64_t xsdef:2;
@@ -1072,8 +1255,19 @@
 		uint64_t reserved_1_1:1;
 		uint64_t pko_nxa:1;
 	} s;
-	struct cvmx_agl_gmx_tx_int_en_s cn52xx;
-	struct cvmx_agl_gmx_tx_int_en_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_int_en_cn52xx {
+		uint64_t reserved_18_63:46;
+		uint64_t late_col:2;
+		uint64_t reserved_14_15:2;
+		uint64_t xsdef:2;
+		uint64_t reserved_10_11:2;
+		uint64_t xscol:2;
+		uint64_t reserved_4_7:4;
+		uint64_t undflw:2;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} cn52xx;
+	struct cvmx_agl_gmx_tx_int_en_cn52xx cn52xxp1;
 	struct cvmx_agl_gmx_tx_int_en_cn56xx {
 		uint64_t reserved_17_63:47;
 		uint64_t late_col:1;
@@ -1087,12 +1281,16 @@
 		uint64_t pko_nxa:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_tx_int_en_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_tx_int_en_s cn63xx;
+	struct cvmx_agl_gmx_tx_int_en_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_int_reg {
 	uint64_t u64;
 	struct cvmx_agl_gmx_tx_int_reg_s {
-		uint64_t reserved_18_63:46;
+		uint64_t reserved_22_63:42;
+		uint64_t ptp_lost:2;
+		uint64_t reserved_18_19:2;
 		uint64_t late_col:2;
 		uint64_t reserved_14_15:2;
 		uint64_t xsdef:2;
@@ -1103,8 +1301,19 @@
 		uint64_t reserved_1_1:1;
 		uint64_t pko_nxa:1;
 	} s;
-	struct cvmx_agl_gmx_tx_int_reg_s cn52xx;
-	struct cvmx_agl_gmx_tx_int_reg_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_int_reg_cn52xx {
+		uint64_t reserved_18_63:46;
+		uint64_t late_col:2;
+		uint64_t reserved_14_15:2;
+		uint64_t xsdef:2;
+		uint64_t reserved_10_11:2;
+		uint64_t xscol:2;
+		uint64_t reserved_4_7:4;
+		uint64_t undflw:2;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} cn52xx;
+	struct cvmx_agl_gmx_tx_int_reg_cn52xx cn52xxp1;
 	struct cvmx_agl_gmx_tx_int_reg_cn56xx {
 		uint64_t reserved_17_63:47;
 		uint64_t late_col:1;
@@ -1118,6 +1327,8 @@
 		uint64_t pko_nxa:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_tx_int_reg_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_tx_int_reg_s cn63xx;
+	struct cvmx_agl_gmx_tx_int_reg_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_jam {
@@ -1130,6 +1341,8 @@
 	struct cvmx_agl_gmx_tx_jam_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_jam_s cn56xx;
 	struct cvmx_agl_gmx_tx_jam_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_jam_s cn63xx;
+	struct cvmx_agl_gmx_tx_jam_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_lfsr {
@@ -1142,6 +1355,8 @@
 	struct cvmx_agl_gmx_tx_lfsr_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_lfsr_s cn56xx;
 	struct cvmx_agl_gmx_tx_lfsr_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_lfsr_s cn63xx;
+	struct cvmx_agl_gmx_tx_lfsr_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_ovr_bp {
@@ -1165,6 +1380,8 @@
 		uint64_t ign_full:1;
 	} cn56xx;
 	struct cvmx_agl_gmx_tx_ovr_bp_cn56xx cn56xxp1;
+	struct cvmx_agl_gmx_tx_ovr_bp_s cn63xx;
+	struct cvmx_agl_gmx_tx_ovr_bp_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_pause_pkt_dmac {
@@ -1177,6 +1394,8 @@
 	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn56xx;
 	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn63xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn63xxp1;
 };
 
 union cvmx_agl_gmx_tx_pause_pkt_type {
@@ -1189,6 +1408,39 @@
 	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn52xxp1;
 	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn56xx;
 	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn56xxp1;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn63xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn63xxp1;
+};
+
+union cvmx_agl_prtx_ctl {
+	uint64_t u64;
+	struct cvmx_agl_prtx_ctl_s {
+		uint64_t drv_byp:1;
+		uint64_t reserved_62_62:1;
+		uint64_t cmp_pctl:6;
+		uint64_t reserved_54_55:2;
+		uint64_t cmp_nctl:6;
+		uint64_t reserved_46_47:2;
+		uint64_t drv_pctl:6;
+		uint64_t reserved_38_39:2;
+		uint64_t drv_nctl:6;
+		uint64_t reserved_29_31:3;
+		uint64_t clk_set:5;
+		uint64_t clkrx_byp:1;
+		uint64_t reserved_21_22:2;
+		uint64_t clkrx_set:5;
+		uint64_t clktx_byp:1;
+		uint64_t reserved_13_14:2;
+		uint64_t clktx_set:5;
+		uint64_t reserved_5_7:3;
+		uint64_t dllrst:1;
+		uint64_t comp:1;
+		uint64_t enable:1;
+		uint64_t clkrst:1;
+		uint64_t mode:1;
+	} s;
+	struct cvmx_agl_prtx_ctl_s cn63xx;
+	struct cvmx_agl_prtx_ctl_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-asm.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-asm.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-asm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-asm.h	2011-01-04 19:50:19.000000000 -0500
@@ -114,6 +114,17 @@
 #define CVMX_DCACHE_INVALIDATE \
 	{ CVMX_SYNC; asm volatile ("cache 9, 0($0)" : : ); }
 
+#define CVMX_CACHE(op, address, offset)					\
+	asm volatile ("cache " CVMX_TMP_STR(op) ", " CVMX_TMP_STR(offset) "(%[rbase])" \
+		: : [rbase] "d" (address) )
+/* fetch and lock the state. */
+#define CVMX_CACHE_LCKL2(address, offset) CVMX_CACHE(31, address, offset)
+/* unlock the state. */
+#define CVMX_CACHE_WBIL2(address, offset) CVMX_CACHE(23, address, offset)
+/* invalidate the cache block and clear the USED bits for the block */
+#define CVMX_CACHE_WBIL2I(address, offset) CVMX_CACHE(3, address, offset)
+/* load virtual tag and data for the L2 cache block into L2C_TAD0_TAG register */
+#define CVMX_CACHE_LTGL2I(address, offset) CVMX_CACHE(7, address, offset)
 
 #define CVMX_POP(result, input) \
 	asm ("pop %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input))
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-ciu-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-ciu-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-ciu-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-ciu-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,87 +28,61 @@
 #ifndef __CVMX_CIU_DEFS_H__
 #define __CVMX_CIU_DEFS_H__
 
-#define CVMX_CIU_BIST \
-	 CVMX_ADD_IO_SEG(0x0001070000000730ull)
-#define CVMX_CIU_DINT \
-	 CVMX_ADD_IO_SEG(0x0001070000000720ull)
-#define CVMX_CIU_FUSE \
-	 CVMX_ADD_IO_SEG(0x0001070000000728ull)
-#define CVMX_CIU_GSTOP \
-	 CVMX_ADD_IO_SEG(0x0001070000000710ull)
-#define CVMX_CIU_INTX_EN0(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000200ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN0_W1C(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000002200ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN0_W1S(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000006200ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN1(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000208ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN1_W1C(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000002208ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN1_W1S(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000006208ull + (((offset) & 63) * 16))
-#define CVMX_CIU_INTX_EN4_0(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000C80ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_EN4_0_W1C(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000002C80ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_EN4_0_W1S(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000006C80ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_EN4_1(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000C88ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_EN4_1_W1C(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000002C88ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_EN4_1_W1S(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000006C88ull + (((offset) & 15) * 16))
-#define CVMX_CIU_INTX_SUM0(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000000ull + (((offset) & 63) * 8))
-#define CVMX_CIU_INTX_SUM4(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000C00ull + (((offset) & 15) * 8))
-#define CVMX_CIU_INT_SUM1 \
-	 CVMX_ADD_IO_SEG(0x0001070000000108ull)
-#define CVMX_CIU_MBOX_CLRX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000680ull + (((offset) & 15) * 8))
-#define CVMX_CIU_MBOX_SETX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000600ull + (((offset) & 15) * 8))
-#define CVMX_CIU_NMI \
-	 CVMX_ADD_IO_SEG(0x0001070000000718ull)
-#define CVMX_CIU_PCI_INTA \
-	 CVMX_ADD_IO_SEG(0x0001070000000750ull)
-#define CVMX_CIU_PP_DBG \
-	 CVMX_ADD_IO_SEG(0x0001070000000708ull)
-#define CVMX_CIU_PP_POKEX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000580ull + (((offset) & 15) * 8))
-#define CVMX_CIU_PP_RST \
-	 CVMX_ADD_IO_SEG(0x0001070000000700ull)
-#define CVMX_CIU_QLM_DCOK \
-	 CVMX_ADD_IO_SEG(0x0001070000000760ull)
-#define CVMX_CIU_QLM_JTGC \
-	 CVMX_ADD_IO_SEG(0x0001070000000768ull)
-#define CVMX_CIU_QLM_JTGD \
-	 CVMX_ADD_IO_SEG(0x0001070000000770ull)
-#define CVMX_CIU_SOFT_BIST \
-	 CVMX_ADD_IO_SEG(0x0001070000000738ull)
-#define CVMX_CIU_SOFT_PRST \
-	 CVMX_ADD_IO_SEG(0x0001070000000748ull)
-#define CVMX_CIU_SOFT_PRST1 \
-	 CVMX_ADD_IO_SEG(0x0001070000000758ull)
-#define CVMX_CIU_SOFT_RST \
-	 CVMX_ADD_IO_SEG(0x0001070000000740ull)
-#define CVMX_CIU_TIMX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000480ull + (((offset) & 3) * 8))
-#define CVMX_CIU_WDOGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000500ull + (((offset) & 15) * 8))
+#define CVMX_CIU_BIST (CVMX_ADD_IO_SEG(0x0001070000000730ull))
+#define CVMX_CIU_BLOCK_INT (CVMX_ADD_IO_SEG(0x00010700000007C0ull))
+#define CVMX_CIU_DINT (CVMX_ADD_IO_SEG(0x0001070000000720ull))
+#define CVMX_CIU_FUSE (CVMX_ADD_IO_SEG(0x0001070000000728ull))
+#define CVMX_CIU_GSTOP (CVMX_ADD_IO_SEG(0x0001070000000710ull))
+#define CVMX_CIU_INT33_SUM0 (CVMX_ADD_IO_SEG(0x0001070000000110ull))
+#define CVMX_CIU_INTX_EN0(offset) (CVMX_ADD_IO_SEG(0x0001070000000200ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN0_W1C(offset) (CVMX_ADD_IO_SEG(0x0001070000002200ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN0_W1S(offset) (CVMX_ADD_IO_SEG(0x0001070000006200ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN1(offset) (CVMX_ADD_IO_SEG(0x0001070000000208ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN1_W1C(offset) (CVMX_ADD_IO_SEG(0x0001070000002208ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN1_W1S(offset) (CVMX_ADD_IO_SEG(0x0001070000006208ull) + ((offset) & 63) * 16)
+#define CVMX_CIU_INTX_EN4_0(offset) (CVMX_ADD_IO_SEG(0x0001070000000C80ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_EN4_0_W1C(offset) (CVMX_ADD_IO_SEG(0x0001070000002C80ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_EN4_0_W1S(offset) (CVMX_ADD_IO_SEG(0x0001070000006C80ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_EN4_1(offset) (CVMX_ADD_IO_SEG(0x0001070000000C88ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_EN4_1_W1C(offset) (CVMX_ADD_IO_SEG(0x0001070000002C88ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_EN4_1_W1S(offset) (CVMX_ADD_IO_SEG(0x0001070000006C88ull) + ((offset) & 15) * 16)
+#define CVMX_CIU_INTX_SUM0(offset) (CVMX_ADD_IO_SEG(0x0001070000000000ull) + ((offset) & 63) * 8)
+#define CVMX_CIU_INTX_SUM4(offset) (CVMX_ADD_IO_SEG(0x0001070000000C00ull) + ((offset) & 15) * 8)
+#define CVMX_CIU_INT_DBG_SEL (CVMX_ADD_IO_SEG(0x00010700000007D0ull))
+#define CVMX_CIU_INT_SUM1 (CVMX_ADD_IO_SEG(0x0001070000000108ull))
+#define CVMX_CIU_MBOX_CLRX(offset) (CVMX_ADD_IO_SEG(0x0001070000000680ull) + ((offset) & 15) * 8)
+#define CVMX_CIU_MBOX_SETX(offset) (CVMX_ADD_IO_SEG(0x0001070000000600ull) + ((offset) & 15) * 8)
+#define CVMX_CIU_NMI (CVMX_ADD_IO_SEG(0x0001070000000718ull))
+#define CVMX_CIU_PCI_INTA (CVMX_ADD_IO_SEG(0x0001070000000750ull))
+#define CVMX_CIU_PP_DBG (CVMX_ADD_IO_SEG(0x0001070000000708ull))
+#define CVMX_CIU_PP_POKEX(offset) (CVMX_ADD_IO_SEG(0x0001070000000580ull) + ((offset) & 15) * 8)
+#define CVMX_CIU_PP_RST (CVMX_ADD_IO_SEG(0x0001070000000700ull))
+#define CVMX_CIU_QLM0 (CVMX_ADD_IO_SEG(0x0001070000000780ull))
+#define CVMX_CIU_QLM1 (CVMX_ADD_IO_SEG(0x0001070000000788ull))
+#define CVMX_CIU_QLM2 (CVMX_ADD_IO_SEG(0x0001070000000790ull))
+#define CVMX_CIU_QLM_DCOK (CVMX_ADD_IO_SEG(0x0001070000000760ull))
+#define CVMX_CIU_QLM_JTGC (CVMX_ADD_IO_SEG(0x0001070000000768ull))
+#define CVMX_CIU_QLM_JTGD (CVMX_ADD_IO_SEG(0x0001070000000770ull))
+#define CVMX_CIU_SOFT_BIST (CVMX_ADD_IO_SEG(0x0001070000000738ull))
+#define CVMX_CIU_SOFT_PRST (CVMX_ADD_IO_SEG(0x0001070000000748ull))
+#define CVMX_CIU_SOFT_PRST1 (CVMX_ADD_IO_SEG(0x0001070000000758ull))
+#define CVMX_CIU_SOFT_RST (CVMX_ADD_IO_SEG(0x0001070000000740ull))
+#define CVMX_CIU_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001070000000480ull) + ((offset) & 3) * 8)
+#define CVMX_CIU_WDOGX(offset) (CVMX_ADD_IO_SEG(0x0001070000000500ull) + ((offset) & 15) * 8)
 
 union cvmx_ciu_bist {
 	uint64_t u64;
 	struct cvmx_ciu_bist_s {
+		uint64_t reserved_5_63:59;
+		uint64_t bist:5;
+	} s;
+	struct cvmx_ciu_bist_cn30xx {
 		uint64_t reserved_4_63:60;
 		uint64_t bist:4;
-	} s;
-	struct cvmx_ciu_bist_s cn30xx;
-	struct cvmx_ciu_bist_s cn31xx;
-	struct cvmx_ciu_bist_s cn38xx;
-	struct cvmx_ciu_bist_s cn38xxp2;
+	} cn30xx;
+	struct cvmx_ciu_bist_cn30xx cn31xx;
+	struct cvmx_ciu_bist_cn30xx cn38xx;
+	struct cvmx_ciu_bist_cn30xx cn38xxp2;
 	struct cvmx_ciu_bist_cn50xx {
 		uint64_t reserved_2_63:62;
 		uint64_t bist:2;
@@ -118,10 +92,57 @@
 		uint64_t bist:3;
 	} cn52xx;
 	struct cvmx_ciu_bist_cn52xx cn52xxp1;
-	struct cvmx_ciu_bist_s cn56xx;
-	struct cvmx_ciu_bist_s cn56xxp1;
-	struct cvmx_ciu_bist_s cn58xx;
-	struct cvmx_ciu_bist_s cn58xxp1;
+	struct cvmx_ciu_bist_cn30xx cn56xx;
+	struct cvmx_ciu_bist_cn30xx cn56xxp1;
+	struct cvmx_ciu_bist_cn30xx cn58xx;
+	struct cvmx_ciu_bist_cn30xx cn58xxp1;
+	struct cvmx_ciu_bist_s cn63xx;
+	struct cvmx_ciu_bist_s cn63xxp1;
+};
+
+union cvmx_ciu_block_int {
+	uint64_t u64;
+	struct cvmx_ciu_block_int_s {
+		uint64_t reserved_43_63:21;
+		uint64_t ptp:1;
+		uint64_t dpi:1;
+		uint64_t dfm:1;
+		uint64_t reserved_34_39:6;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t reserved_31_31:1;
+		uint64_t iob:1;
+		uint64_t reserved_29_29:1;
+		uint64_t agl:1;
+		uint64_t reserved_27_27:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t reserved_23_24:2;
+		uint64_t asxpcs0:1;
+		uint64_t reserved_21_21:1;
+		uint64_t pip:1;
+		uint64_t reserved_18_19:2;
+		uint64_t lmc0:1;
+		uint64_t l2c:1;
+		uint64_t reserved_15_15:1;
+		uint64_t rad:1;
+		uint64_t usb:1;
+		uint64_t pow:1;
+		uint64_t tim:1;
+		uint64_t pko:1;
+		uint64_t ipd:1;
+		uint64_t reserved_8_8:1;
+		uint64_t zip:1;
+		uint64_t dfa:1;
+		uint64_t fpa:1;
+		uint64_t key:1;
+		uint64_t sli:1;
+		uint64_t reserved_2_2:1;
+		uint64_t gmx0:1;
+		uint64_t mio:1;
+	} s;
+	struct cvmx_ciu_block_int_s cn63xx;
+	struct cvmx_ciu_block_int_s cn63xxp1;
 };
 
 union cvmx_ciu_dint {
@@ -153,6 +174,11 @@
 	struct cvmx_ciu_dint_cn56xx cn56xxp1;
 	struct cvmx_ciu_dint_s cn58xx;
 	struct cvmx_ciu_dint_s cn58xxp1;
+	struct cvmx_ciu_dint_cn63xx {
+		uint64_t reserved_6_63:58;
+		uint64_t dint:6;
+	} cn63xx;
+	struct cvmx_ciu_dint_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_fuse {
@@ -184,6 +210,11 @@
 	struct cvmx_ciu_fuse_cn56xx cn56xxp1;
 	struct cvmx_ciu_fuse_s cn58xx;
 	struct cvmx_ciu_fuse_s cn58xxp1;
+	struct cvmx_ciu_fuse_cn63xx {
+		uint64_t reserved_6_63:58;
+		uint64_t fuse:6;
+	} cn63xx;
+	struct cvmx_ciu_fuse_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_gstop {
@@ -203,6 +234,8 @@
 	struct cvmx_ciu_gstop_s cn56xxp1;
 	struct cvmx_ciu_gstop_s cn58xx;
 	struct cvmx_ciu_gstop_s cn58xxp1;
+	struct cvmx_ciu_gstop_s cn63xx;
+	struct cvmx_ciu_gstop_s cn63xxp1;
 };
 
 union cvmx_ciu_intx_en0 {
@@ -343,6 +376,8 @@
 	struct cvmx_ciu_intx_en0_cn56xx cn56xxp1;
 	struct cvmx_ciu_intx_en0_cn38xx cn58xx;
 	struct cvmx_ciu_intx_en0_cn38xx cn58xxp1;
+	struct cvmx_ciu_intx_en0_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en0_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en0_w1c {
@@ -412,6 +447,8 @@
 		uint64_t gpio:16;
 		uint64_t workq:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en0_w1c_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en0_w1c_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en0_w1s {
@@ -481,12 +518,42 @@
 		uint64_t gpio:16;
 		uint64_t workq:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en0_w1s_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en0_w1s_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en1 {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en1_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -531,12 +598,76 @@
 	struct cvmx_ciu_intx_en1_cn56xx cn56xxp1;
 	struct cvmx_ciu_intx_en1_cn38xx cn58xx;
 	struct cvmx_ciu_intx_en1_cn38xx cn58xxp1;
+	struct cvmx_ciu_intx_en1_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en1_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en1_w1c {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en1_w1c_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -560,12 +691,76 @@
 		uint64_t reserved_16_63:48;
 		uint64_t wdog:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en1_w1c_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en1_w1c_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en1_w1s {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en1_w1s_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -589,6 +784,42 @@
 		uint64_t reserved_16_63:48;
 		uint64_t wdog:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en1_w1s_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en1_w1s_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_0 {
@@ -705,6 +936,8 @@
 		uint64_t workq:16;
 	} cn58xx;
 	struct cvmx_ciu_intx_en4_0_cn58xx cn58xxp1;
+	struct cvmx_ciu_intx_en4_0_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en4_0_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_0_w1c {
@@ -774,6 +1007,8 @@
 		uint64_t gpio:16;
 		uint64_t workq:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en4_0_w1c_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en4_0_w1c_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_0_w1s {
@@ -843,12 +1078,42 @@
 		uint64_t gpio:16;
 		uint64_t workq:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en4_0_w1s_cn52xx cn63xx;
+	struct cvmx_ciu_intx_en4_0_w1s_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_1 {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en4_1_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -886,12 +1151,76 @@
 		uint64_t wdog:16;
 	} cn58xx;
 	struct cvmx_ciu_intx_en4_1_cn58xx cn58xxp1;
+	struct cvmx_ciu_intx_en4_1_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en4_1_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_1_w1c {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en4_1_w1c_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -915,12 +1244,76 @@
 		uint64_t reserved_16_63:48;
 		uint64_t wdog:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en4_1_w1c_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en4_1_w1c_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_en4_1_w1s {
 	uint64_t u64;
 	struct cvmx_ciu_intx_en4_1_w1s_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -944,6 +1337,42 @@
 		uint64_t reserved_16_63:48;
 		uint64_t wdog:16;
 	} cn58xx;
+	struct cvmx_ciu_intx_en4_1_w1s_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_intx_en4_1_w1s_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_sum0 {
@@ -1084,6 +1513,8 @@
 	struct cvmx_ciu_intx_sum0_cn56xx cn56xxp1;
 	struct cvmx_ciu_intx_sum0_cn38xx cn58xx;
 	struct cvmx_ciu_intx_sum0_cn38xx cn58xxp1;
+	struct cvmx_ciu_intx_sum0_cn52xx cn63xx;
+	struct cvmx_ciu_intx_sum0_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_intx_sum4 {
@@ -1200,12 +1631,85 @@
 		uint64_t workq:16;
 	} cn58xx;
 	struct cvmx_ciu_intx_sum4_cn58xx cn58xxp1;
+	struct cvmx_ciu_intx_sum4_cn52xx cn63xx;
+	struct cvmx_ciu_intx_sum4_cn52xx cn63xxp1;
+};
+
+union cvmx_ciu_int33_sum0 {
+	uint64_t u64;
+	struct cvmx_ciu_int33_sum0_s {
+		uint64_t bootdma:1;
+		uint64_t mii:1;
+		uint64_t ipdppthr:1;
+		uint64_t powiq:1;
+		uint64_t twsi2:1;
+		uint64_t reserved_57_58:2;
+		uint64_t usb:1;
+		uint64_t timer:4;
+		uint64_t reserved_51_51:1;
+		uint64_t ipd_drp:1;
+		uint64_t reserved_49_49:1;
+		uint64_t gmx_drp:1;
+		uint64_t trace:1;
+		uint64_t rml:1;
+		uint64_t twsi:1;
+		uint64_t wdog_sum:1;
+		uint64_t pci_msi:4;
+		uint64_t pci_int:4;
+		uint64_t uart:2;
+		uint64_t mbox:2;
+		uint64_t gpio:16;
+		uint64_t workq:16;
+	} s;
+	struct cvmx_ciu_int33_sum0_s cn63xx;
+	struct cvmx_ciu_int33_sum0_s cn63xxp1;
+};
+
+union cvmx_ciu_int_dbg_sel {
+	uint64_t u64;
+	struct cvmx_ciu_int_dbg_sel_s {
+		uint64_t reserved_19_63:45;
+		uint64_t sel:3;
+		uint64_t reserved_10_15:6;
+		uint64_t irq:2;
+		uint64_t reserved_3_7:5;
+		uint64_t pp:3;
+	} s;
+	struct cvmx_ciu_int_dbg_sel_s cn63xx;
 };
 
 union cvmx_ciu_int_sum1 {
 	uint64_t u64;
 	struct cvmx_ciu_int_sum1_s {
-		uint64_t reserved_20_63:44;
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
 		uint64_t nand:1;
 		uint64_t mii1:1;
 		uint64_t usb1:1;
@@ -1250,6 +1754,42 @@
 	struct cvmx_ciu_int_sum1_cn56xx cn56xxp1;
 	struct cvmx_ciu_int_sum1_cn38xx cn58xx;
 	struct cvmx_ciu_int_sum1_cn38xx cn58xxp1;
+	struct cvmx_ciu_int_sum1_cn63xx {
+		uint64_t rst:1;
+		uint64_t reserved_57_62:6;
+		uint64_t dfm:1;
+		uint64_t reserved_53_55:3;
+		uint64_t lmc0:1;
+		uint64_t srio1:1;
+		uint64_t srio0:1;
+		uint64_t pem1:1;
+		uint64_t pem0:1;
+		uint64_t ptp:1;
+		uint64_t agl:1;
+		uint64_t reserved_37_45:9;
+		uint64_t agx0:1;
+		uint64_t dpi:1;
+		uint64_t sli:1;
+		uint64_t usb:1;
+		uint64_t dfa:1;
+		uint64_t key:1;
+		uint64_t rad:1;
+		uint64_t tim:1;
+		uint64_t zip:1;
+		uint64_t pko:1;
+		uint64_t pip:1;
+		uint64_t ipd:1;
+		uint64_t l2c:1;
+		uint64_t pow:1;
+		uint64_t fpa:1;
+		uint64_t iob:1;
+		uint64_t mio:1;
+		uint64_t nand:1;
+		uint64_t mii1:1;
+		uint64_t reserved_6_17:12;
+		uint64_t wdog:6;
+	} cn63xx;
+	struct cvmx_ciu_int_sum1_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_mbox_clrx {
@@ -1269,6 +1809,8 @@
 	struct cvmx_ciu_mbox_clrx_s cn56xxp1;
 	struct cvmx_ciu_mbox_clrx_s cn58xx;
 	struct cvmx_ciu_mbox_clrx_s cn58xxp1;
+	struct cvmx_ciu_mbox_clrx_s cn63xx;
+	struct cvmx_ciu_mbox_clrx_s cn63xxp1;
 };
 
 union cvmx_ciu_mbox_setx {
@@ -1288,6 +1830,8 @@
 	struct cvmx_ciu_mbox_setx_s cn56xxp1;
 	struct cvmx_ciu_mbox_setx_s cn58xx;
 	struct cvmx_ciu_mbox_setx_s cn58xxp1;
+	struct cvmx_ciu_mbox_setx_s cn63xx;
+	struct cvmx_ciu_mbox_setx_s cn63xxp1;
 };
 
 union cvmx_ciu_nmi {
@@ -1319,6 +1863,11 @@
 	struct cvmx_ciu_nmi_cn56xx cn56xxp1;
 	struct cvmx_ciu_nmi_s cn58xx;
 	struct cvmx_ciu_nmi_s cn58xxp1;
+	struct cvmx_ciu_nmi_cn63xx {
+		uint64_t reserved_6_63:58;
+		uint64_t nmi:6;
+	} cn63xx;
+	struct cvmx_ciu_nmi_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_pci_inta {
@@ -1338,6 +1887,8 @@
 	struct cvmx_ciu_pci_inta_s cn56xxp1;
 	struct cvmx_ciu_pci_inta_s cn58xx;
 	struct cvmx_ciu_pci_inta_s cn58xxp1;
+	struct cvmx_ciu_pci_inta_s cn63xx;
+	struct cvmx_ciu_pci_inta_s cn63xxp1;
 };
 
 union cvmx_ciu_pp_dbg {
@@ -1369,12 +1920,17 @@
 	struct cvmx_ciu_pp_dbg_cn56xx cn56xxp1;
 	struct cvmx_ciu_pp_dbg_s cn58xx;
 	struct cvmx_ciu_pp_dbg_s cn58xxp1;
+	struct cvmx_ciu_pp_dbg_cn63xx {
+		uint64_t reserved_6_63:58;
+		uint64_t ppdbg:6;
+	} cn63xx;
+	struct cvmx_ciu_pp_dbg_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_pp_pokex {
 	uint64_t u64;
 	struct cvmx_ciu_pp_pokex_s {
-		uint64_t reserved_0_63:64;
+		uint64_t poke:64;
 	} s;
 	struct cvmx_ciu_pp_pokex_s cn30xx;
 	struct cvmx_ciu_pp_pokex_s cn31xx;
@@ -1387,6 +1943,8 @@
 	struct cvmx_ciu_pp_pokex_s cn56xxp1;
 	struct cvmx_ciu_pp_pokex_s cn58xx;
 	struct cvmx_ciu_pp_pokex_s cn58xxp1;
+	struct cvmx_ciu_pp_pokex_s cn63xx;
+	struct cvmx_ciu_pp_pokex_s cn63xxp1;
 };
 
 union cvmx_ciu_pp_rst {
@@ -1422,6 +1980,97 @@
 	struct cvmx_ciu_pp_rst_cn56xx cn56xxp1;
 	struct cvmx_ciu_pp_rst_s cn58xx;
 	struct cvmx_ciu_pp_rst_s cn58xxp1;
+	struct cvmx_ciu_pp_rst_cn63xx {
+		uint64_t reserved_6_63:58;
+		uint64_t rst:5;
+		uint64_t rst0:1;
+	} cn63xx;
+	struct cvmx_ciu_pp_rst_cn63xx cn63xxp1;
+};
+
+union cvmx_ciu_qlm0 {
+	uint64_t u64;
+	struct cvmx_ciu_qlm0_s {
+		uint64_t g2bypass:1;
+		uint64_t reserved_53_62:10;
+		uint64_t g2deemph:5;
+		uint64_t reserved_45_47:3;
+		uint64_t g2margin:5;
+		uint64_t reserved_32_39:8;
+		uint64_t txbypass:1;
+		uint64_t reserved_21_30:10;
+		uint64_t txdeemph:5;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} s;
+	struct cvmx_ciu_qlm0_s cn63xx;
+	struct cvmx_ciu_qlm0_cn63xxp1 {
+		uint64_t reserved_32_63:32;
+		uint64_t txbypass:1;
+		uint64_t reserved_20_30:11;
+		uint64_t txdeemph:4;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} cn63xxp1;
+};
+
+union cvmx_ciu_qlm1 {
+	uint64_t u64;
+	struct cvmx_ciu_qlm1_s {
+		uint64_t g2bypass:1;
+		uint64_t reserved_53_62:10;
+		uint64_t g2deemph:5;
+		uint64_t reserved_45_47:3;
+		uint64_t g2margin:5;
+		uint64_t reserved_32_39:8;
+		uint64_t txbypass:1;
+		uint64_t reserved_21_30:10;
+		uint64_t txdeemph:5;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} s;
+	struct cvmx_ciu_qlm1_s cn63xx;
+	struct cvmx_ciu_qlm1_cn63xxp1 {
+		uint64_t reserved_32_63:32;
+		uint64_t txbypass:1;
+		uint64_t reserved_20_30:11;
+		uint64_t txdeemph:4;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} cn63xxp1;
+};
+
+union cvmx_ciu_qlm2 {
+	uint64_t u64;
+	struct cvmx_ciu_qlm2_s {
+		uint64_t reserved_32_63:32;
+		uint64_t txbypass:1;
+		uint64_t reserved_21_30:10;
+		uint64_t txdeemph:5;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} s;
+	struct cvmx_ciu_qlm2_s cn63xx;
+	struct cvmx_ciu_qlm2_cn63xxp1 {
+		uint64_t reserved_32_63:32;
+		uint64_t txbypass:1;
+		uint64_t reserved_20_30:11;
+		uint64_t txdeemph:4;
+		uint64_t reserved_13_15:3;
+		uint64_t txmargin:5;
+		uint64_t reserved_4_7:4;
+		uint64_t lane_en:4;
+	} cn63xxp1;
 };
 
 union cvmx_ciu_qlm_dcok {
@@ -1459,6 +2108,15 @@
 	struct cvmx_ciu_qlm_jtgc_cn52xx cn52xxp1;
 	struct cvmx_ciu_qlm_jtgc_s cn56xx;
 	struct cvmx_ciu_qlm_jtgc_s cn56xxp1;
+	struct cvmx_ciu_qlm_jtgc_cn63xx {
+		uint64_t reserved_11_63:53;
+		uint64_t clk_div:3;
+		uint64_t reserved_6_7:2;
+		uint64_t mux_sel:2;
+		uint64_t reserved_3_3:1;
+		uint64_t bypass:3;
+	} cn63xx;
+	struct cvmx_ciu_qlm_jtgc_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_qlm_jtgd {
@@ -1493,6 +2151,17 @@
 		uint64_t shft_cnt:5;
 		uint64_t shft_reg:32;
 	} cn56xxp1;
+	struct cvmx_ciu_qlm_jtgd_cn63xx {
+		uint64_t capture:1;
+		uint64_t shift:1;
+		uint64_t update:1;
+		uint64_t reserved_43_60:18;
+		uint64_t select:3;
+		uint64_t reserved_37_39:3;
+		uint64_t shft_cnt:5;
+		uint64_t shft_reg:32;
+	} cn63xx;
+	struct cvmx_ciu_qlm_jtgd_cn63xx cn63xxp1;
 };
 
 union cvmx_ciu_soft_bist {
@@ -1512,6 +2181,8 @@
 	struct cvmx_ciu_soft_bist_s cn56xxp1;
 	struct cvmx_ciu_soft_bist_s cn58xx;
 	struct cvmx_ciu_soft_bist_s cn58xxp1;
+	struct cvmx_ciu_soft_bist_s cn63xx;
+	struct cvmx_ciu_soft_bist_s cn63xxp1;
 };
 
 union cvmx_ciu_soft_prst {
@@ -1536,6 +2207,8 @@
 	struct cvmx_ciu_soft_prst_cn52xx cn56xxp1;
 	struct cvmx_ciu_soft_prst_s cn58xx;
 	struct cvmx_ciu_soft_prst_s cn58xxp1;
+	struct cvmx_ciu_soft_prst_cn52xx cn63xx;
+	struct cvmx_ciu_soft_prst_cn52xx cn63xxp1;
 };
 
 union cvmx_ciu_soft_prst1 {
@@ -1548,6 +2221,8 @@
 	struct cvmx_ciu_soft_prst1_s cn52xxp1;
 	struct cvmx_ciu_soft_prst1_s cn56xx;
 	struct cvmx_ciu_soft_prst1_s cn56xxp1;
+	struct cvmx_ciu_soft_prst1_s cn63xx;
+	struct cvmx_ciu_soft_prst1_s cn63xxp1;
 };
 
 union cvmx_ciu_soft_rst {
@@ -1567,6 +2242,8 @@
 	struct cvmx_ciu_soft_rst_s cn56xxp1;
 	struct cvmx_ciu_soft_rst_s cn58xx;
 	struct cvmx_ciu_soft_rst_s cn58xxp1;
+	struct cvmx_ciu_soft_rst_s cn63xx;
+	struct cvmx_ciu_soft_rst_s cn63xxp1;
 };
 
 union cvmx_ciu_timx {
@@ -1587,6 +2264,8 @@
 	struct cvmx_ciu_timx_s cn56xxp1;
 	struct cvmx_ciu_timx_s cn58xx;
 	struct cvmx_ciu_timx_s cn58xxp1;
+	struct cvmx_ciu_timx_s cn63xx;
+	struct cvmx_ciu_timx_s cn63xxp1;
 };
 
 union cvmx_ciu_wdogx {
@@ -1611,6 +2290,8 @@
 	struct cvmx_ciu_wdogx_s cn56xxp1;
 	struct cvmx_ciu_wdogx_s cn58xx;
 	struct cvmx_ciu_wdogx_s cn58xxp1;
+	struct cvmx_ciu_wdogx_s cn63xx;
+	struct cvmx_ciu_wdogx_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-gpio-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-gpio-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-gpio-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-gpio-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,29 +28,22 @@
 #ifndef __CVMX_GPIO_DEFS_H__
 #define __CVMX_GPIO_DEFS_H__
 
-#define CVMX_GPIO_BIT_CFGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000800ull + (((offset) & 15) * 8))
-#define CVMX_GPIO_BOOT_ENA \
-	 CVMX_ADD_IO_SEG(0x00010700000008A8ull)
-#define CVMX_GPIO_CLK_GENX(offset) \
-	 CVMX_ADD_IO_SEG(0x00010700000008C0ull + (((offset) & 3) * 8))
-#define CVMX_GPIO_DBG_ENA \
-	 CVMX_ADD_IO_SEG(0x00010700000008A0ull)
-#define CVMX_GPIO_INT_CLR \
-	 CVMX_ADD_IO_SEG(0x0001070000000898ull)
-#define CVMX_GPIO_RX_DAT \
-	 CVMX_ADD_IO_SEG(0x0001070000000880ull)
-#define CVMX_GPIO_TX_CLR \
-	 CVMX_ADD_IO_SEG(0x0001070000000890ull)
-#define CVMX_GPIO_TX_SET \
-	 CVMX_ADD_IO_SEG(0x0001070000000888ull)
-#define CVMX_GPIO_XBIT_CFGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000000900ull + (((offset) & 31) * 8) - 8 * 16)
+#define CVMX_GPIO_BIT_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001070000000800ull) + ((offset) & 15) * 8)
+#define CVMX_GPIO_BOOT_ENA (CVMX_ADD_IO_SEG(0x00010700000008A8ull))
+#define CVMX_GPIO_CLK_GENX(offset) (CVMX_ADD_IO_SEG(0x00010700000008C0ull) + ((offset) & 3) * 8)
+#define CVMX_GPIO_CLK_QLMX(offset) (CVMX_ADD_IO_SEG(0x00010700000008E0ull) + ((offset) & 1) * 8)
+#define CVMX_GPIO_DBG_ENA (CVMX_ADD_IO_SEG(0x00010700000008A0ull))
+#define CVMX_GPIO_INT_CLR (CVMX_ADD_IO_SEG(0x0001070000000898ull))
+#define CVMX_GPIO_RX_DAT (CVMX_ADD_IO_SEG(0x0001070000000880ull))
+#define CVMX_GPIO_TX_CLR (CVMX_ADD_IO_SEG(0x0001070000000890ull))
+#define CVMX_GPIO_TX_SET (CVMX_ADD_IO_SEG(0x0001070000000888ull))
+#define CVMX_GPIO_XBIT_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001070000000900ull) + ((offset) & 31) * 8 - 8*16)
 
 union cvmx_gpio_bit_cfgx {
 	uint64_t u64;
 	struct cvmx_gpio_bit_cfgx_s {
-		uint64_t reserved_15_63:49;
+		uint64_t reserved_17_63:47;
+		uint64_t synce_sel:2;
 		uint64_t clk_gen:1;
 		uint64_t clk_sel:2;
 		uint64_t fil_sel:4;
@@ -73,12 +66,24 @@
 	struct cvmx_gpio_bit_cfgx_cn30xx cn38xx;
 	struct cvmx_gpio_bit_cfgx_cn30xx cn38xxp2;
 	struct cvmx_gpio_bit_cfgx_cn30xx cn50xx;
-	struct cvmx_gpio_bit_cfgx_s cn52xx;
-	struct cvmx_gpio_bit_cfgx_s cn52xxp1;
-	struct cvmx_gpio_bit_cfgx_s cn56xx;
-	struct cvmx_gpio_bit_cfgx_s cn56xxp1;
+	struct cvmx_gpio_bit_cfgx_cn52xx {
+		uint64_t reserved_15_63:49;
+		uint64_t clk_gen:1;
+		uint64_t clk_sel:2;
+		uint64_t fil_sel:4;
+		uint64_t fil_cnt:4;
+		uint64_t int_type:1;
+		uint64_t int_en:1;
+		uint64_t rx_xor:1;
+		uint64_t tx_oe:1;
+	} cn52xx;
+	struct cvmx_gpio_bit_cfgx_cn52xx cn52xxp1;
+	struct cvmx_gpio_bit_cfgx_cn52xx cn56xx;
+	struct cvmx_gpio_bit_cfgx_cn52xx cn56xxp1;
 	struct cvmx_gpio_bit_cfgx_cn30xx cn58xx;
 	struct cvmx_gpio_bit_cfgx_cn30xx cn58xxp1;
+	struct cvmx_gpio_bit_cfgx_s cn63xx;
+	struct cvmx_gpio_bit_cfgx_s cn63xxp1;
 };
 
 union cvmx_gpio_boot_ena {
@@ -103,6 +108,19 @@
 	struct cvmx_gpio_clk_genx_s cn52xxp1;
 	struct cvmx_gpio_clk_genx_s cn56xx;
 	struct cvmx_gpio_clk_genx_s cn56xxp1;
+	struct cvmx_gpio_clk_genx_s cn63xx;
+	struct cvmx_gpio_clk_genx_s cn63xxp1;
+};
+
+union cvmx_gpio_clk_qlmx {
+	uint64_t u64;
+	struct cvmx_gpio_clk_qlmx_s {
+		uint64_t reserved_3_63:61;
+		uint64_t div:1;
+		uint64_t lane_sel:2;
+	} s;
+	struct cvmx_gpio_clk_qlmx_s cn63xx;
+	struct cvmx_gpio_clk_qlmx_s cn63xxp1;
 };
 
 union cvmx_gpio_dbg_ena {
@@ -133,6 +151,8 @@
 	struct cvmx_gpio_int_clr_s cn56xxp1;
 	struct cvmx_gpio_int_clr_s cn58xx;
 	struct cvmx_gpio_int_clr_s cn58xxp1;
+	struct cvmx_gpio_int_clr_s cn63xx;
+	struct cvmx_gpio_int_clr_s cn63xxp1;
 };
 
 union cvmx_gpio_rx_dat {
@@ -155,6 +175,8 @@
 	struct cvmx_gpio_rx_dat_cn38xx cn56xxp1;
 	struct cvmx_gpio_rx_dat_cn38xx cn58xx;
 	struct cvmx_gpio_rx_dat_cn38xx cn58xxp1;
+	struct cvmx_gpio_rx_dat_cn38xx cn63xx;
+	struct cvmx_gpio_rx_dat_cn38xx cn63xxp1;
 };
 
 union cvmx_gpio_tx_clr {
@@ -177,6 +199,8 @@
 	struct cvmx_gpio_tx_clr_cn38xx cn56xxp1;
 	struct cvmx_gpio_tx_clr_cn38xx cn58xx;
 	struct cvmx_gpio_tx_clr_cn38xx cn58xxp1;
+	struct cvmx_gpio_tx_clr_cn38xx cn63xx;
+	struct cvmx_gpio_tx_clr_cn38xx cn63xxp1;
 };
 
 union cvmx_gpio_tx_set {
@@ -199,6 +223,8 @@
 	struct cvmx_gpio_tx_set_cn38xx cn56xxp1;
 	struct cvmx_gpio_tx_set_cn38xx cn58xx;
 	struct cvmx_gpio_tx_set_cn38xx cn58xxp1;
+	struct cvmx_gpio_tx_set_cn38xx cn63xx;
+	struct cvmx_gpio_tx_set_cn38xx cn63xxp1;
 };
 
 union cvmx_gpio_xbit_cfgx {
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-iob-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-iob-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-iob-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-iob-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,55 +28,39 @@
 #ifndef __CVMX_IOB_DEFS_H__
 #define __CVMX_IOB_DEFS_H__
 
-#define CVMX_IOB_BIST_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011800F00007F8ull)
-#define CVMX_IOB_CTL_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011800F0000050ull)
-#define CVMX_IOB_DWB_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000028ull)
-#define CVMX_IOB_FAU_TIMEOUT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000000ull)
-#define CVMX_IOB_I2C_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000010ull)
-#define CVMX_IOB_INB_CONTROL_MATCH \
-	 CVMX_ADD_IO_SEG(0x00011800F0000078ull)
-#define CVMX_IOB_INB_CONTROL_MATCH_ENB \
-	 CVMX_ADD_IO_SEG(0x00011800F0000088ull)
-#define CVMX_IOB_INB_DATA_MATCH \
-	 CVMX_ADD_IO_SEG(0x00011800F0000070ull)
-#define CVMX_IOB_INB_DATA_MATCH_ENB \
-	 CVMX_ADD_IO_SEG(0x00011800F0000080ull)
-#define CVMX_IOB_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011800F0000060ull)
-#define CVMX_IOB_INT_SUM \
-	 CVMX_ADD_IO_SEG(0x00011800F0000058ull)
-#define CVMX_IOB_N2C_L2C_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000020ull)
-#define CVMX_IOB_N2C_RSP_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000008ull)
-#define CVMX_IOB_OUTB_COM_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000040ull)
-#define CVMX_IOB_OUTB_CONTROL_MATCH \
-	 CVMX_ADD_IO_SEG(0x00011800F0000098ull)
-#define CVMX_IOB_OUTB_CONTROL_MATCH_ENB \
-	 CVMX_ADD_IO_SEG(0x00011800F00000A8ull)
-#define CVMX_IOB_OUTB_DATA_MATCH \
-	 CVMX_ADD_IO_SEG(0x00011800F0000090ull)
-#define CVMX_IOB_OUTB_DATA_MATCH_ENB \
-	 CVMX_ADD_IO_SEG(0x00011800F00000A0ull)
-#define CVMX_IOB_OUTB_FPA_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000048ull)
-#define CVMX_IOB_OUTB_REQ_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000038ull)
-#define CVMX_IOB_P2C_REQ_PRI_CNT \
-	 CVMX_ADD_IO_SEG(0x00011800F0000018ull)
-#define CVMX_IOB_PKT_ERR \
-	 CVMX_ADD_IO_SEG(0x00011800F0000068ull)
+#define CVMX_IOB_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011800F00007F8ull))
+#define CVMX_IOB_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011800F0000050ull))
+#define CVMX_IOB_DWB_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000028ull))
+#define CVMX_IOB_FAU_TIMEOUT (CVMX_ADD_IO_SEG(0x00011800F0000000ull))
+#define CVMX_IOB_I2C_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000010ull))
+#define CVMX_IOB_INB_CONTROL_MATCH (CVMX_ADD_IO_SEG(0x00011800F0000078ull))
+#define CVMX_IOB_INB_CONTROL_MATCH_ENB (CVMX_ADD_IO_SEG(0x00011800F0000088ull))
+#define CVMX_IOB_INB_DATA_MATCH (CVMX_ADD_IO_SEG(0x00011800F0000070ull))
+#define CVMX_IOB_INB_DATA_MATCH_ENB (CVMX_ADD_IO_SEG(0x00011800F0000080ull))
+#define CVMX_IOB_INT_ENB (CVMX_ADD_IO_SEG(0x00011800F0000060ull))
+#define CVMX_IOB_INT_SUM (CVMX_ADD_IO_SEG(0x00011800F0000058ull))
+#define CVMX_IOB_N2C_L2C_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000020ull))
+#define CVMX_IOB_N2C_RSP_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000008ull))
+#define CVMX_IOB_OUTB_COM_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000040ull))
+#define CVMX_IOB_OUTB_CONTROL_MATCH (CVMX_ADD_IO_SEG(0x00011800F0000098ull))
+#define CVMX_IOB_OUTB_CONTROL_MATCH_ENB (CVMX_ADD_IO_SEG(0x00011800F00000A8ull))
+#define CVMX_IOB_OUTB_DATA_MATCH (CVMX_ADD_IO_SEG(0x00011800F0000090ull))
+#define CVMX_IOB_OUTB_DATA_MATCH_ENB (CVMX_ADD_IO_SEG(0x00011800F00000A0ull))
+#define CVMX_IOB_OUTB_FPA_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000048ull))
+#define CVMX_IOB_OUTB_REQ_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000038ull))
+#define CVMX_IOB_P2C_REQ_PRI_CNT (CVMX_ADD_IO_SEG(0x00011800F0000018ull))
+#define CVMX_IOB_PKT_ERR (CVMX_ADD_IO_SEG(0x00011800F0000068ull))
+#define CVMX_IOB_TO_CMB_CREDITS (CVMX_ADD_IO_SEG(0x00011800F00000B0ull))
 
 union cvmx_iob_bist_status {
 	uint64_t u64;
 	struct cvmx_iob_bist_status_s {
-		uint64_t reserved_18_63:46;
+		uint64_t reserved_23_63:41;
+		uint64_t xmdfif:1;
+		uint64_t xmcfif:1;
+		uint64_t iorfif:1;
+		uint64_t rsdfif:1;
+		uint64_t iocfif:1;
 		uint64_t icnrcb:1;
 		uint64_t icr0:1;
 		uint64_t icr1:1;
@@ -96,40 +80,81 @@
 		uint64_t ibd:1;
 		uint64_t icd:1;
 	} s;
-	struct cvmx_iob_bist_status_s cn30xx;
-	struct cvmx_iob_bist_status_s cn31xx;
-	struct cvmx_iob_bist_status_s cn38xx;
-	struct cvmx_iob_bist_status_s cn38xxp2;
-	struct cvmx_iob_bist_status_s cn50xx;
-	struct cvmx_iob_bist_status_s cn52xx;
-	struct cvmx_iob_bist_status_s cn52xxp1;
-	struct cvmx_iob_bist_status_s cn56xx;
-	struct cvmx_iob_bist_status_s cn56xxp1;
-	struct cvmx_iob_bist_status_s cn58xx;
-	struct cvmx_iob_bist_status_s cn58xxp1;
+	struct cvmx_iob_bist_status_cn30xx {
+		uint64_t reserved_18_63:46;
+		uint64_t icnrcb:1;
+		uint64_t icr0:1;
+		uint64_t icr1:1;
+		uint64_t icnr1:1;
+		uint64_t icnr0:1;
+		uint64_t ibdr0:1;
+		uint64_t ibdr1:1;
+		uint64_t ibr0:1;
+		uint64_t ibr1:1;
+		uint64_t icnrt:1;
+		uint64_t ibrq0:1;
+		uint64_t ibrq1:1;
+		uint64_t icrn0:1;
+		uint64_t icrn1:1;
+		uint64_t icrp0:1;
+		uint64_t icrp1:1;
+		uint64_t ibd:1;
+		uint64_t icd:1;
+	} cn30xx;
+	struct cvmx_iob_bist_status_cn30xx cn31xx;
+	struct cvmx_iob_bist_status_cn30xx cn38xx;
+	struct cvmx_iob_bist_status_cn30xx cn38xxp2;
+	struct cvmx_iob_bist_status_cn30xx cn50xx;
+	struct cvmx_iob_bist_status_cn30xx cn52xx;
+	struct cvmx_iob_bist_status_cn30xx cn52xxp1;
+	struct cvmx_iob_bist_status_cn30xx cn56xx;
+	struct cvmx_iob_bist_status_cn30xx cn56xxp1;
+	struct cvmx_iob_bist_status_cn30xx cn58xx;
+	struct cvmx_iob_bist_status_cn30xx cn58xxp1;
+	struct cvmx_iob_bist_status_s cn63xx;
+	struct cvmx_iob_bist_status_s cn63xxp1;
 };
 
 union cvmx_iob_ctl_status {
 	uint64_t u64;
 	struct cvmx_iob_ctl_status_s {
-		uint64_t reserved_5_63:59;
+		uint64_t reserved_10_63:54;
+		uint64_t xmc_per:4;
+		uint64_t rr_mode:1;
 		uint64_t outb_mat:1;
 		uint64_t inb_mat:1;
 		uint64_t pko_enb:1;
 		uint64_t dwb_enb:1;
 		uint64_t fau_end:1;
 	} s;
-	struct cvmx_iob_ctl_status_s cn30xx;
-	struct cvmx_iob_ctl_status_s cn31xx;
-	struct cvmx_iob_ctl_status_s cn38xx;
-	struct cvmx_iob_ctl_status_s cn38xxp2;
-	struct cvmx_iob_ctl_status_s cn50xx;
-	struct cvmx_iob_ctl_status_s cn52xx;
-	struct cvmx_iob_ctl_status_s cn52xxp1;
-	struct cvmx_iob_ctl_status_s cn56xx;
-	struct cvmx_iob_ctl_status_s cn56xxp1;
-	struct cvmx_iob_ctl_status_s cn58xx;
-	struct cvmx_iob_ctl_status_s cn58xxp1;
+	struct cvmx_iob_ctl_status_cn30xx {
+		uint64_t reserved_5_63:59;
+		uint64_t outb_mat:1;
+		uint64_t inb_mat:1;
+		uint64_t pko_enb:1;
+		uint64_t dwb_enb:1;
+		uint64_t fau_end:1;
+	} cn30xx;
+	struct cvmx_iob_ctl_status_cn30xx cn31xx;
+	struct cvmx_iob_ctl_status_cn30xx cn38xx;
+	struct cvmx_iob_ctl_status_cn30xx cn38xxp2;
+	struct cvmx_iob_ctl_status_cn30xx cn50xx;
+	struct cvmx_iob_ctl_status_cn52xx {
+		uint64_t reserved_6_63:58;
+		uint64_t rr_mode:1;
+		uint64_t outb_mat:1;
+		uint64_t inb_mat:1;
+		uint64_t pko_enb:1;
+		uint64_t dwb_enb:1;
+		uint64_t fau_end:1;
+	} cn52xx;
+	struct cvmx_iob_ctl_status_cn30xx cn52xxp1;
+	struct cvmx_iob_ctl_status_cn30xx cn56xx;
+	struct cvmx_iob_ctl_status_cn30xx cn56xxp1;
+	struct cvmx_iob_ctl_status_cn30xx cn58xx;
+	struct cvmx_iob_ctl_status_cn30xx cn58xxp1;
+	struct cvmx_iob_ctl_status_s cn63xx;
+	struct cvmx_iob_ctl_status_s cn63xxp1;
 };
 
 union cvmx_iob_dwb_pri_cnt {
@@ -147,6 +172,8 @@
 	struct cvmx_iob_dwb_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_dwb_pri_cnt_s cn58xx;
 	struct cvmx_iob_dwb_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_dwb_pri_cnt_s cn63xx;
+	struct cvmx_iob_dwb_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_fau_timeout {
@@ -167,6 +194,8 @@
 	struct cvmx_iob_fau_timeout_s cn56xxp1;
 	struct cvmx_iob_fau_timeout_s cn58xx;
 	struct cvmx_iob_fau_timeout_s cn58xxp1;
+	struct cvmx_iob_fau_timeout_s cn63xx;
+	struct cvmx_iob_fau_timeout_s cn63xxp1;
 };
 
 union cvmx_iob_i2c_pri_cnt {
@@ -184,6 +213,8 @@
 	struct cvmx_iob_i2c_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_i2c_pri_cnt_s cn58xx;
 	struct cvmx_iob_i2c_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_i2c_pri_cnt_s cn63xx;
+	struct cvmx_iob_i2c_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_inb_control_match {
@@ -206,6 +237,8 @@
 	struct cvmx_iob_inb_control_match_s cn56xxp1;
 	struct cvmx_iob_inb_control_match_s cn58xx;
 	struct cvmx_iob_inb_control_match_s cn58xxp1;
+	struct cvmx_iob_inb_control_match_s cn63xx;
+	struct cvmx_iob_inb_control_match_s cn63xxp1;
 };
 
 union cvmx_iob_inb_control_match_enb {
@@ -228,6 +261,8 @@
 	struct cvmx_iob_inb_control_match_enb_s cn56xxp1;
 	struct cvmx_iob_inb_control_match_enb_s cn58xx;
 	struct cvmx_iob_inb_control_match_enb_s cn58xxp1;
+	struct cvmx_iob_inb_control_match_enb_s cn63xx;
+	struct cvmx_iob_inb_control_match_enb_s cn63xxp1;
 };
 
 union cvmx_iob_inb_data_match {
@@ -246,6 +281,8 @@
 	struct cvmx_iob_inb_data_match_s cn56xxp1;
 	struct cvmx_iob_inb_data_match_s cn58xx;
 	struct cvmx_iob_inb_data_match_s cn58xxp1;
+	struct cvmx_iob_inb_data_match_s cn63xx;
+	struct cvmx_iob_inb_data_match_s cn63xxp1;
 };
 
 union cvmx_iob_inb_data_match_enb {
@@ -264,6 +301,8 @@
 	struct cvmx_iob_inb_data_match_enb_s cn56xxp1;
 	struct cvmx_iob_inb_data_match_enb_s cn58xx;
 	struct cvmx_iob_inb_data_match_enb_s cn58xxp1;
+	struct cvmx_iob_inb_data_match_enb_s cn63xx;
+	struct cvmx_iob_inb_data_match_enb_s cn63xxp1;
 };
 
 union cvmx_iob_int_enb {
@@ -294,6 +333,8 @@
 	struct cvmx_iob_int_enb_s cn56xxp1;
 	struct cvmx_iob_int_enb_s cn58xx;
 	struct cvmx_iob_int_enb_s cn58xxp1;
+	struct cvmx_iob_int_enb_s cn63xx;
+	struct cvmx_iob_int_enb_s cn63xxp1;
 };
 
 union cvmx_iob_int_sum {
@@ -324,6 +365,8 @@
 	struct cvmx_iob_int_sum_s cn56xxp1;
 	struct cvmx_iob_int_sum_s cn58xx;
 	struct cvmx_iob_int_sum_s cn58xxp1;
+	struct cvmx_iob_int_sum_s cn63xx;
+	struct cvmx_iob_int_sum_s cn63xxp1;
 };
 
 union cvmx_iob_n2c_l2c_pri_cnt {
@@ -341,6 +384,8 @@
 	struct cvmx_iob_n2c_l2c_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_n2c_l2c_pri_cnt_s cn58xx;
 	struct cvmx_iob_n2c_l2c_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_n2c_l2c_pri_cnt_s cn63xx;
+	struct cvmx_iob_n2c_l2c_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_n2c_rsp_pri_cnt {
@@ -358,6 +403,8 @@
 	struct cvmx_iob_n2c_rsp_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_n2c_rsp_pri_cnt_s cn58xx;
 	struct cvmx_iob_n2c_rsp_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_n2c_rsp_pri_cnt_s cn63xx;
+	struct cvmx_iob_n2c_rsp_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_outb_com_pri_cnt {
@@ -375,6 +422,8 @@
 	struct cvmx_iob_outb_com_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_outb_com_pri_cnt_s cn58xx;
 	struct cvmx_iob_outb_com_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_outb_com_pri_cnt_s cn63xx;
+	struct cvmx_iob_outb_com_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_outb_control_match {
@@ -397,6 +446,8 @@
 	struct cvmx_iob_outb_control_match_s cn56xxp1;
 	struct cvmx_iob_outb_control_match_s cn58xx;
 	struct cvmx_iob_outb_control_match_s cn58xxp1;
+	struct cvmx_iob_outb_control_match_s cn63xx;
+	struct cvmx_iob_outb_control_match_s cn63xxp1;
 };
 
 union cvmx_iob_outb_control_match_enb {
@@ -419,6 +470,8 @@
 	struct cvmx_iob_outb_control_match_enb_s cn56xxp1;
 	struct cvmx_iob_outb_control_match_enb_s cn58xx;
 	struct cvmx_iob_outb_control_match_enb_s cn58xxp1;
+	struct cvmx_iob_outb_control_match_enb_s cn63xx;
+	struct cvmx_iob_outb_control_match_enb_s cn63xxp1;
 };
 
 union cvmx_iob_outb_data_match {
@@ -437,6 +490,8 @@
 	struct cvmx_iob_outb_data_match_s cn56xxp1;
 	struct cvmx_iob_outb_data_match_s cn58xx;
 	struct cvmx_iob_outb_data_match_s cn58xxp1;
+	struct cvmx_iob_outb_data_match_s cn63xx;
+	struct cvmx_iob_outb_data_match_s cn63xxp1;
 };
 
 union cvmx_iob_outb_data_match_enb {
@@ -455,6 +510,8 @@
 	struct cvmx_iob_outb_data_match_enb_s cn56xxp1;
 	struct cvmx_iob_outb_data_match_enb_s cn58xx;
 	struct cvmx_iob_outb_data_match_enb_s cn58xxp1;
+	struct cvmx_iob_outb_data_match_enb_s cn63xx;
+	struct cvmx_iob_outb_data_match_enb_s cn63xxp1;
 };
 
 union cvmx_iob_outb_fpa_pri_cnt {
@@ -472,6 +529,8 @@
 	struct cvmx_iob_outb_fpa_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_outb_fpa_pri_cnt_s cn58xx;
 	struct cvmx_iob_outb_fpa_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_outb_fpa_pri_cnt_s cn63xx;
+	struct cvmx_iob_outb_fpa_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_outb_req_pri_cnt {
@@ -489,6 +548,8 @@
 	struct cvmx_iob_outb_req_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_outb_req_pri_cnt_s cn58xx;
 	struct cvmx_iob_outb_req_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_outb_req_pri_cnt_s cn63xx;
+	struct cvmx_iob_outb_req_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_p2c_req_pri_cnt {
@@ -506,25 +567,46 @@
 	struct cvmx_iob_p2c_req_pri_cnt_s cn56xxp1;
 	struct cvmx_iob_p2c_req_pri_cnt_s cn58xx;
 	struct cvmx_iob_p2c_req_pri_cnt_s cn58xxp1;
+	struct cvmx_iob_p2c_req_pri_cnt_s cn63xx;
+	struct cvmx_iob_p2c_req_pri_cnt_s cn63xxp1;
 };
 
 union cvmx_iob_pkt_err {
 	uint64_t u64;
 	struct cvmx_iob_pkt_err_s {
+		uint64_t reserved_12_63:52;
+		uint64_t vport:6;
+		uint64_t port:6;
+	} s;
+	struct cvmx_iob_pkt_err_cn30xx {
 		uint64_t reserved_6_63:58;
 		uint64_t port:6;
+	} cn30xx;
+	struct cvmx_iob_pkt_err_cn30xx cn31xx;
+	struct cvmx_iob_pkt_err_cn30xx cn38xx;
+	struct cvmx_iob_pkt_err_cn30xx cn38xxp2;
+	struct cvmx_iob_pkt_err_cn30xx cn50xx;
+	struct cvmx_iob_pkt_err_cn30xx cn52xx;
+	struct cvmx_iob_pkt_err_cn30xx cn52xxp1;
+	struct cvmx_iob_pkt_err_cn30xx cn56xx;
+	struct cvmx_iob_pkt_err_cn30xx cn56xxp1;
+	struct cvmx_iob_pkt_err_cn30xx cn58xx;
+	struct cvmx_iob_pkt_err_cn30xx cn58xxp1;
+	struct cvmx_iob_pkt_err_s cn63xx;
+	struct cvmx_iob_pkt_err_s cn63xxp1;
+};
+
+union cvmx_iob_to_cmb_credits {
+	uint64_t u64;
+	struct cvmx_iob_to_cmb_credits_s {
+		uint64_t reserved_9_63:55;
+		uint64_t pko_rd:3;
+		uint64_t ncb_rd:3;
+		uint64_t ncb_wr:3;
 	} s;
-	struct cvmx_iob_pkt_err_s cn30xx;
-	struct cvmx_iob_pkt_err_s cn31xx;
-	struct cvmx_iob_pkt_err_s cn38xx;
-	struct cvmx_iob_pkt_err_s cn38xxp2;
-	struct cvmx_iob_pkt_err_s cn50xx;
-	struct cvmx_iob_pkt_err_s cn52xx;
-	struct cvmx_iob_pkt_err_s cn52xxp1;
-	struct cvmx_iob_pkt_err_s cn56xx;
-	struct cvmx_iob_pkt_err_s cn56xxp1;
-	struct cvmx_iob_pkt_err_s cn58xx;
-	struct cvmx_iob_pkt_err_s cn58xxp1;
+	struct cvmx_iob_to_cmb_credits_s cn52xx;
+	struct cvmx_iob_to_cmb_credits_s cn63xx;
+	struct cvmx_iob_to_cmb_credits_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-ipd-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-ipd-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-ipd-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-ipd-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,104 +28,57 @@
 #ifndef __CVMX_IPD_DEFS_H__
 #define __CVMX_IPD_DEFS_H__
 
-#define CVMX_IPD_1ST_MBUFF_SKIP \
-	 CVMX_ADD_IO_SEG(0x00014F0000000000ull)
-#define CVMX_IPD_1st_NEXT_PTR_BACK \
-	 CVMX_ADD_IO_SEG(0x00014F0000000150ull)
-#define CVMX_IPD_2nd_NEXT_PTR_BACK \
-	 CVMX_ADD_IO_SEG(0x00014F0000000158ull)
-#define CVMX_IPD_BIST_STATUS \
-	 CVMX_ADD_IO_SEG(0x00014F00000007F8ull)
-#define CVMX_IPD_BP_PRT_RED_END \
-	 CVMX_ADD_IO_SEG(0x00014F0000000328ull)
-#define CVMX_IPD_CLK_COUNT \
-	 CVMX_ADD_IO_SEG(0x00014F0000000338ull)
-#define CVMX_IPD_CTL_STATUS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000018ull)
-#define CVMX_IPD_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00014F0000000160ull)
-#define CVMX_IPD_INT_SUM \
-	 CVMX_ADD_IO_SEG(0x00014F0000000168ull)
-#define CVMX_IPD_NOT_1ST_MBUFF_SKIP \
-	 CVMX_ADD_IO_SEG(0x00014F0000000008ull)
-#define CVMX_IPD_PACKET_MBUFF_SIZE \
-	 CVMX_ADD_IO_SEG(0x00014F0000000010ull)
-#define CVMX_IPD_PKT_PTR_VALID \
-	 CVMX_ADD_IO_SEG(0x00014F0000000358ull)
-#define CVMX_IPD_PORTX_BP_PAGE_CNT(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000028ull + (((offset) & 63) * 8))
-#define CVMX_IPD_PORTX_BP_PAGE_CNT2(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000368ull + (((offset) & 63) * 8) - 8 * 36)
-#define CVMX_IPD_PORT_BP_COUNTERS2_PAIRX(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000388ull + (((offset) & 63) * 8) - 8 * 36)
-#define CVMX_IPD_PORT_BP_COUNTERS_PAIRX(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F00000001B8ull + (((offset) & 63) * 8))
-#define CVMX_IPD_PORT_QOS_INTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000808ull + (((offset) & 7) * 8))
-#define CVMX_IPD_PORT_QOS_INT_ENBX(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000848ull + (((offset) & 7) * 8))
-#define CVMX_IPD_PORT_QOS_X_CNT(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000888ull + (((offset) & 511) * 8))
-#define CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL \
-	 CVMX_ADD_IO_SEG(0x00014F0000000348ull)
-#define CVMX_IPD_PRC_PORT_PTR_FIFO_CTL \
-	 CVMX_ADD_IO_SEG(0x00014F0000000350ull)
-#define CVMX_IPD_PTR_COUNT \
-	 CVMX_ADD_IO_SEG(0x00014F0000000320ull)
-#define CVMX_IPD_PWP_PTR_FIFO_CTL \
-	 CVMX_ADD_IO_SEG(0x00014F0000000340ull)
-#define CVMX_IPD_QOS0_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000178ull)
-#define CVMX_IPD_QOS1_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000180ull)
-#define CVMX_IPD_QOS2_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000188ull)
-#define CVMX_IPD_QOS3_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000190ull)
-#define CVMX_IPD_QOS4_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000198ull)
-#define CVMX_IPD_QOS5_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F00000001A0ull)
-#define CVMX_IPD_QOS6_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F00000001A8ull)
-#define CVMX_IPD_QOS7_RED_MARKS \
-	 CVMX_ADD_IO_SEG(0x00014F00000001B0ull)
-#define CVMX_IPD_QOSX_RED_MARKS(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F0000000178ull + (((offset) & 7) * 8))
-#define CVMX_IPD_QUE0_FREE_PAGE_CNT \
-	 CVMX_ADD_IO_SEG(0x00014F0000000330ull)
-#define CVMX_IPD_RED_PORT_ENABLE \
-	 CVMX_ADD_IO_SEG(0x00014F00000002D8ull)
-#define CVMX_IPD_RED_PORT_ENABLE2 \
-	 CVMX_ADD_IO_SEG(0x00014F00000003A8ull)
-#define CVMX_IPD_RED_QUE0_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F00000002E0ull)
-#define CVMX_IPD_RED_QUE1_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F00000002E8ull)
-#define CVMX_IPD_RED_QUE2_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F00000002F0ull)
-#define CVMX_IPD_RED_QUE3_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F00000002F8ull)
-#define CVMX_IPD_RED_QUE4_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F0000000300ull)
-#define CVMX_IPD_RED_QUE5_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F0000000308ull)
-#define CVMX_IPD_RED_QUE6_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F0000000310ull)
-#define CVMX_IPD_RED_QUE7_PARAM \
-	 CVMX_ADD_IO_SEG(0x00014F0000000318ull)
-#define CVMX_IPD_RED_QUEX_PARAM(offset) \
-	 CVMX_ADD_IO_SEG(0x00014F00000002E0ull + (((offset) & 7) * 8))
-#define CVMX_IPD_SUB_PORT_BP_PAGE_CNT \
-	 CVMX_ADD_IO_SEG(0x00014F0000000148ull)
-#define CVMX_IPD_SUB_PORT_FCS \
-	 CVMX_ADD_IO_SEG(0x00014F0000000170ull)
-#define CVMX_IPD_SUB_PORT_QOS_CNT \
-	 CVMX_ADD_IO_SEG(0x00014F0000000800ull)
-#define CVMX_IPD_WQE_FPA_QUEUE \
-	 CVMX_ADD_IO_SEG(0x00014F0000000020ull)
-#define CVMX_IPD_WQE_PTR_VALID \
-	 CVMX_ADD_IO_SEG(0x00014F0000000360ull)
+#define CVMX_IPD_1ST_MBUFF_SKIP (CVMX_ADD_IO_SEG(0x00014F0000000000ull))
+#define CVMX_IPD_1st_NEXT_PTR_BACK (CVMX_ADD_IO_SEG(0x00014F0000000150ull))
+#define CVMX_IPD_2nd_NEXT_PTR_BACK (CVMX_ADD_IO_SEG(0x00014F0000000158ull))
+#define CVMX_IPD_BIST_STATUS (CVMX_ADD_IO_SEG(0x00014F00000007F8ull))
+#define CVMX_IPD_BP_PRT_RED_END (CVMX_ADD_IO_SEG(0x00014F0000000328ull))
+#define CVMX_IPD_CLK_COUNT (CVMX_ADD_IO_SEG(0x00014F0000000338ull))
+#define CVMX_IPD_CTL_STATUS (CVMX_ADD_IO_SEG(0x00014F0000000018ull))
+#define CVMX_IPD_INT_ENB (CVMX_ADD_IO_SEG(0x00014F0000000160ull))
+#define CVMX_IPD_INT_SUM (CVMX_ADD_IO_SEG(0x00014F0000000168ull))
+#define CVMX_IPD_NOT_1ST_MBUFF_SKIP (CVMX_ADD_IO_SEG(0x00014F0000000008ull))
+#define CVMX_IPD_PACKET_MBUFF_SIZE (CVMX_ADD_IO_SEG(0x00014F0000000010ull))
+#define CVMX_IPD_PKT_PTR_VALID (CVMX_ADD_IO_SEG(0x00014F0000000358ull))
+#define CVMX_IPD_PORTX_BP_PAGE_CNT(offset) (CVMX_ADD_IO_SEG(0x00014F0000000028ull) + ((offset) & 63) * 8)
+#define CVMX_IPD_PORTX_BP_PAGE_CNT2(offset) (CVMX_ADD_IO_SEG(0x00014F0000000368ull) + ((offset) & 63) * 8 - 8*36)
+#define CVMX_IPD_PORTX_BP_PAGE_CNT3(offset) (CVMX_ADD_IO_SEG(0x00014F00000003D0ull) + ((offset) & 63) * 8 - 8*40)
+#define CVMX_IPD_PORT_BP_COUNTERS2_PAIRX(offset) (CVMX_ADD_IO_SEG(0x00014F0000000388ull) + ((offset) & 63) * 8 - 8*36)
+#define CVMX_IPD_PORT_BP_COUNTERS3_PAIRX(offset) (CVMX_ADD_IO_SEG(0x00014F00000003B0ull) + ((offset) & 63) * 8 - 8*40)
+#define CVMX_IPD_PORT_BP_COUNTERS_PAIRX(offset) (CVMX_ADD_IO_SEG(0x00014F00000001B8ull) + ((offset) & 63) * 8)
+#define CVMX_IPD_PORT_QOS_INTX(offset) (CVMX_ADD_IO_SEG(0x00014F0000000808ull) + ((offset) & 7) * 8)
+#define CVMX_IPD_PORT_QOS_INT_ENBX(offset) (CVMX_ADD_IO_SEG(0x00014F0000000848ull) + ((offset) & 7) * 8)
+#define CVMX_IPD_PORT_QOS_X_CNT(offset) (CVMX_ADD_IO_SEG(0x00014F0000000888ull) + ((offset) & 511) * 8)
+#define CVMX_IPD_PRC_HOLD_PTR_FIFO_CTL (CVMX_ADD_IO_SEG(0x00014F0000000348ull))
+#define CVMX_IPD_PRC_PORT_PTR_FIFO_CTL (CVMX_ADD_IO_SEG(0x00014F0000000350ull))
+#define CVMX_IPD_PTR_COUNT (CVMX_ADD_IO_SEG(0x00014F0000000320ull))
+#define CVMX_IPD_PWP_PTR_FIFO_CTL (CVMX_ADD_IO_SEG(0x00014F0000000340ull))
+#define CVMX_IPD_QOS0_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(0)
+#define CVMX_IPD_QOS1_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(1)
+#define CVMX_IPD_QOS2_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(2)
+#define CVMX_IPD_QOS3_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(3)
+#define CVMX_IPD_QOS4_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(4)
+#define CVMX_IPD_QOS5_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(5)
+#define CVMX_IPD_QOS6_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(6)
+#define CVMX_IPD_QOS7_RED_MARKS CVMX_IPD_QOSX_RED_MARKS(7)
+#define CVMX_IPD_QOSX_RED_MARKS(offset) (CVMX_ADD_IO_SEG(0x00014F0000000178ull) + ((offset) & 7) * 8)
+#define CVMX_IPD_QUE0_FREE_PAGE_CNT (CVMX_ADD_IO_SEG(0x00014F0000000330ull))
+#define CVMX_IPD_RED_PORT_ENABLE (CVMX_ADD_IO_SEG(0x00014F00000002D8ull))
+#define CVMX_IPD_RED_PORT_ENABLE2 (CVMX_ADD_IO_SEG(0x00014F00000003A8ull))
+#define CVMX_IPD_RED_QUE0_PARAM CVMX_IPD_RED_QUEX_PARAM(0)
+#define CVMX_IPD_RED_QUE1_PARAM CVMX_IPD_RED_QUEX_PARAM(1)
+#define CVMX_IPD_RED_QUE2_PARAM CVMX_IPD_RED_QUEX_PARAM(2)
+#define CVMX_IPD_RED_QUE3_PARAM CVMX_IPD_RED_QUEX_PARAM(3)
+#define CVMX_IPD_RED_QUE4_PARAM CVMX_IPD_RED_QUEX_PARAM(4)
+#define CVMX_IPD_RED_QUE5_PARAM CVMX_IPD_RED_QUEX_PARAM(5)
+#define CVMX_IPD_RED_QUE6_PARAM CVMX_IPD_RED_QUEX_PARAM(6)
+#define CVMX_IPD_RED_QUE7_PARAM CVMX_IPD_RED_QUEX_PARAM(7)
+#define CVMX_IPD_RED_QUEX_PARAM(offset) (CVMX_ADD_IO_SEG(0x00014F00000002E0ull) + ((offset) & 7) * 8)
+#define CVMX_IPD_SUB_PORT_BP_PAGE_CNT (CVMX_ADD_IO_SEG(0x00014F0000000148ull))
+#define CVMX_IPD_SUB_PORT_FCS (CVMX_ADD_IO_SEG(0x00014F0000000170ull))
+#define CVMX_IPD_SUB_PORT_QOS_CNT (CVMX_ADD_IO_SEG(0x00014F0000000800ull))
+#define CVMX_IPD_WQE_FPA_QUEUE (CVMX_ADD_IO_SEG(0x00014F0000000020ull))
+#define CVMX_IPD_WQE_PTR_VALID (CVMX_ADD_IO_SEG(0x00014F0000000360ull))
 
 union cvmx_ipd_1st_mbuff_skip {
 	uint64_t u64;
@@ -144,6 +97,8 @@
 	struct cvmx_ipd_1st_mbuff_skip_s cn56xxp1;
 	struct cvmx_ipd_1st_mbuff_skip_s cn58xx;
 	struct cvmx_ipd_1st_mbuff_skip_s cn58xxp1;
+	struct cvmx_ipd_1st_mbuff_skip_s cn63xx;
+	struct cvmx_ipd_1st_mbuff_skip_s cn63xxp1;
 };
 
 union cvmx_ipd_1st_next_ptr_back {
@@ -163,6 +118,8 @@
 	struct cvmx_ipd_1st_next_ptr_back_s cn56xxp1;
 	struct cvmx_ipd_1st_next_ptr_back_s cn58xx;
 	struct cvmx_ipd_1st_next_ptr_back_s cn58xxp1;
+	struct cvmx_ipd_1st_next_ptr_back_s cn63xx;
+	struct cvmx_ipd_1st_next_ptr_back_s cn63xxp1;
 };
 
 union cvmx_ipd_2nd_next_ptr_back {
@@ -182,6 +139,8 @@
 	struct cvmx_ipd_2nd_next_ptr_back_s cn56xxp1;
 	struct cvmx_ipd_2nd_next_ptr_back_s cn58xx;
 	struct cvmx_ipd_2nd_next_ptr_back_s cn58xxp1;
+	struct cvmx_ipd_2nd_next_ptr_back_s cn63xx;
+	struct cvmx_ipd_2nd_next_ptr_back_s cn63xxp1;
 };
 
 union cvmx_ipd_bist_status {
@@ -236,13 +195,15 @@
 	struct cvmx_ipd_bist_status_s cn56xxp1;
 	struct cvmx_ipd_bist_status_cn30xx cn58xx;
 	struct cvmx_ipd_bist_status_cn30xx cn58xxp1;
+	struct cvmx_ipd_bist_status_s cn63xx;
+	struct cvmx_ipd_bist_status_s cn63xxp1;
 };
 
 union cvmx_ipd_bp_prt_red_end {
 	uint64_t u64;
 	struct cvmx_ipd_bp_prt_red_end_s {
-		uint64_t reserved_40_63:24;
-		uint64_t prt_enb:40;
+		uint64_t reserved_44_63:20;
+		uint64_t prt_enb:44;
 	} s;
 	struct cvmx_ipd_bp_prt_red_end_cn30xx {
 		uint64_t reserved_36_63:28;
@@ -252,12 +213,17 @@
 	struct cvmx_ipd_bp_prt_red_end_cn30xx cn38xx;
 	struct cvmx_ipd_bp_prt_red_end_cn30xx cn38xxp2;
 	struct cvmx_ipd_bp_prt_red_end_cn30xx cn50xx;
-	struct cvmx_ipd_bp_prt_red_end_s cn52xx;
-	struct cvmx_ipd_bp_prt_red_end_s cn52xxp1;
-	struct cvmx_ipd_bp_prt_red_end_s cn56xx;
-	struct cvmx_ipd_bp_prt_red_end_s cn56xxp1;
+	struct cvmx_ipd_bp_prt_red_end_cn52xx {
+		uint64_t reserved_40_63:24;
+		uint64_t prt_enb:40;
+	} cn52xx;
+	struct cvmx_ipd_bp_prt_red_end_cn52xx cn52xxp1;
+	struct cvmx_ipd_bp_prt_red_end_cn52xx cn56xx;
+	struct cvmx_ipd_bp_prt_red_end_cn52xx cn56xxp1;
 	struct cvmx_ipd_bp_prt_red_end_cn30xx cn58xx;
 	struct cvmx_ipd_bp_prt_red_end_cn30xx cn58xxp1;
+	struct cvmx_ipd_bp_prt_red_end_s cn63xx;
+	struct cvmx_ipd_bp_prt_red_end_s cn63xxp1;
 };
 
 union cvmx_ipd_clk_count {
@@ -276,12 +242,17 @@
 	struct cvmx_ipd_clk_count_s cn56xxp1;
 	struct cvmx_ipd_clk_count_s cn58xx;
 	struct cvmx_ipd_clk_count_s cn58xxp1;
+	struct cvmx_ipd_clk_count_s cn63xx;
+	struct cvmx_ipd_clk_count_s cn63xxp1;
 };
 
 union cvmx_ipd_ctl_status {
 	uint64_t u64;
 	struct cvmx_ipd_ctl_status_s {
-		uint64_t reserved_15_63:49;
+		uint64_t reserved_18_63:46;
+		uint64_t use_sop:1;
+		uint64_t rst_done:1;
+		uint64_t clken:1;
 		uint64_t no_wptr:1;
 		uint64_t pq_apkt:1;
 		uint64_t pq_nabuf:1;
@@ -322,11 +293,27 @@
 		uint64_t opc_mode:2;
 		uint64_t ipd_en:1;
 	} cn38xxp2;
-	struct cvmx_ipd_ctl_status_s cn50xx;
-	struct cvmx_ipd_ctl_status_s cn52xx;
-	struct cvmx_ipd_ctl_status_s cn52xxp1;
-	struct cvmx_ipd_ctl_status_s cn56xx;
-	struct cvmx_ipd_ctl_status_s cn56xxp1;
+	struct cvmx_ipd_ctl_status_cn50xx {
+		uint64_t reserved_15_63:49;
+		uint64_t no_wptr:1;
+		uint64_t pq_apkt:1;
+		uint64_t pq_nabuf:1;
+		uint64_t ipd_full:1;
+		uint64_t pkt_off:1;
+		uint64_t len_m8:1;
+		uint64_t reset:1;
+		uint64_t addpkt:1;
+		uint64_t naddbuf:1;
+		uint64_t pkt_lend:1;
+		uint64_t wqe_lend:1;
+		uint64_t pbp_en:1;
+		uint64_t opc_mode:2;
+		uint64_t ipd_en:1;
+	} cn50xx;
+	struct cvmx_ipd_ctl_status_cn50xx cn52xx;
+	struct cvmx_ipd_ctl_status_cn50xx cn52xxp1;
+	struct cvmx_ipd_ctl_status_cn50xx cn56xx;
+	struct cvmx_ipd_ctl_status_cn50xx cn56xxp1;
 	struct cvmx_ipd_ctl_status_cn58xx {
 		uint64_t reserved_12_63:52;
 		uint64_t ipd_full:1;
@@ -342,6 +329,25 @@
 		uint64_t ipd_en:1;
 	} cn58xx;
 	struct cvmx_ipd_ctl_status_cn58xx cn58xxp1;
+	struct cvmx_ipd_ctl_status_s cn63xx;
+	struct cvmx_ipd_ctl_status_cn63xxp1 {
+		uint64_t reserved_16_63:48;
+		uint64_t clken:1;
+		uint64_t no_wptr:1;
+		uint64_t pq_apkt:1;
+		uint64_t pq_nabuf:1;
+		uint64_t ipd_full:1;
+		uint64_t pkt_off:1;
+		uint64_t len_m8:1;
+		uint64_t reset:1;
+		uint64_t addpkt:1;
+		uint64_t naddbuf:1;
+		uint64_t pkt_lend:1;
+		uint64_t wqe_lend:1;
+		uint64_t pbp_en:1;
+		uint64_t opc_mode:2;
+		uint64_t ipd_en:1;
+	} cn63xxp1;
 };
 
 union cvmx_ipd_int_enb {
@@ -391,6 +397,8 @@
 	struct cvmx_ipd_int_enb_s cn56xxp1;
 	struct cvmx_ipd_int_enb_cn38xx cn58xx;
 	struct cvmx_ipd_int_enb_cn38xx cn58xxp1;
+	struct cvmx_ipd_int_enb_s cn63xx;
+	struct cvmx_ipd_int_enb_s cn63xxp1;
 };
 
 union cvmx_ipd_int_sum {
@@ -440,6 +448,8 @@
 	struct cvmx_ipd_int_sum_s cn56xxp1;
 	struct cvmx_ipd_int_sum_cn38xx cn58xx;
 	struct cvmx_ipd_int_sum_cn38xx cn58xxp1;
+	struct cvmx_ipd_int_sum_s cn63xx;
+	struct cvmx_ipd_int_sum_s cn63xxp1;
 };
 
 union cvmx_ipd_not_1st_mbuff_skip {
@@ -459,6 +469,8 @@
 	struct cvmx_ipd_not_1st_mbuff_skip_s cn56xxp1;
 	struct cvmx_ipd_not_1st_mbuff_skip_s cn58xx;
 	struct cvmx_ipd_not_1st_mbuff_skip_s cn58xxp1;
+	struct cvmx_ipd_not_1st_mbuff_skip_s cn63xx;
+	struct cvmx_ipd_not_1st_mbuff_skip_s cn63xxp1;
 };
 
 union cvmx_ipd_packet_mbuff_size {
@@ -478,6 +490,8 @@
 	struct cvmx_ipd_packet_mbuff_size_s cn56xxp1;
 	struct cvmx_ipd_packet_mbuff_size_s cn58xx;
 	struct cvmx_ipd_packet_mbuff_size_s cn58xxp1;
+	struct cvmx_ipd_packet_mbuff_size_s cn63xx;
+	struct cvmx_ipd_packet_mbuff_size_s cn63xxp1;
 };
 
 union cvmx_ipd_pkt_ptr_valid {
@@ -496,6 +510,8 @@
 	struct cvmx_ipd_pkt_ptr_valid_s cn56xxp1;
 	struct cvmx_ipd_pkt_ptr_valid_s cn58xx;
 	struct cvmx_ipd_pkt_ptr_valid_s cn58xxp1;
+	struct cvmx_ipd_pkt_ptr_valid_s cn63xx;
+	struct cvmx_ipd_pkt_ptr_valid_s cn63xxp1;
 };
 
 union cvmx_ipd_portx_bp_page_cnt {
@@ -516,6 +532,8 @@
 	struct cvmx_ipd_portx_bp_page_cnt_s cn56xxp1;
 	struct cvmx_ipd_portx_bp_page_cnt_s cn58xx;
 	struct cvmx_ipd_portx_bp_page_cnt_s cn58xxp1;
+	struct cvmx_ipd_portx_bp_page_cnt_s cn63xx;
+	struct cvmx_ipd_portx_bp_page_cnt_s cn63xxp1;
 };
 
 union cvmx_ipd_portx_bp_page_cnt2 {
@@ -529,6 +547,19 @@
 	struct cvmx_ipd_portx_bp_page_cnt2_s cn52xxp1;
 	struct cvmx_ipd_portx_bp_page_cnt2_s cn56xx;
 	struct cvmx_ipd_portx_bp_page_cnt2_s cn56xxp1;
+	struct cvmx_ipd_portx_bp_page_cnt2_s cn63xx;
+	struct cvmx_ipd_portx_bp_page_cnt2_s cn63xxp1;
+};
+
+union cvmx_ipd_portx_bp_page_cnt3 {
+	uint64_t u64;
+	struct cvmx_ipd_portx_bp_page_cnt3_s {
+		uint64_t reserved_18_63:46;
+		uint64_t bp_enb:1;
+		uint64_t page_cnt:17;
+	} s;
+	struct cvmx_ipd_portx_bp_page_cnt3_s cn63xx;
+	struct cvmx_ipd_portx_bp_page_cnt3_s cn63xxp1;
 };
 
 union cvmx_ipd_port_bp_counters2_pairx {
@@ -541,6 +572,18 @@
 	struct cvmx_ipd_port_bp_counters2_pairx_s cn52xxp1;
 	struct cvmx_ipd_port_bp_counters2_pairx_s cn56xx;
 	struct cvmx_ipd_port_bp_counters2_pairx_s cn56xxp1;
+	struct cvmx_ipd_port_bp_counters2_pairx_s cn63xx;
+	struct cvmx_ipd_port_bp_counters2_pairx_s cn63xxp1;
+};
+
+union cvmx_ipd_port_bp_counters3_pairx {
+	uint64_t u64;
+	struct cvmx_ipd_port_bp_counters3_pairx_s {
+		uint64_t reserved_25_63:39;
+		uint64_t cnt_val:25;
+	} s;
+	struct cvmx_ipd_port_bp_counters3_pairx_s cn63xx;
+	struct cvmx_ipd_port_bp_counters3_pairx_s cn63xxp1;
 };
 
 union cvmx_ipd_port_bp_counters_pairx {
@@ -560,6 +603,8 @@
 	struct cvmx_ipd_port_bp_counters_pairx_s cn56xxp1;
 	struct cvmx_ipd_port_bp_counters_pairx_s cn58xx;
 	struct cvmx_ipd_port_bp_counters_pairx_s cn58xxp1;
+	struct cvmx_ipd_port_bp_counters_pairx_s cn63xx;
+	struct cvmx_ipd_port_bp_counters_pairx_s cn63xxp1;
 };
 
 union cvmx_ipd_port_qos_x_cnt {
@@ -572,6 +617,8 @@
 	struct cvmx_ipd_port_qos_x_cnt_s cn52xxp1;
 	struct cvmx_ipd_port_qos_x_cnt_s cn56xx;
 	struct cvmx_ipd_port_qos_x_cnt_s cn56xxp1;
+	struct cvmx_ipd_port_qos_x_cnt_s cn63xx;
+	struct cvmx_ipd_port_qos_x_cnt_s cn63xxp1;
 };
 
 union cvmx_ipd_port_qos_intx {
@@ -583,6 +630,8 @@
 	struct cvmx_ipd_port_qos_intx_s cn52xxp1;
 	struct cvmx_ipd_port_qos_intx_s cn56xx;
 	struct cvmx_ipd_port_qos_intx_s cn56xxp1;
+	struct cvmx_ipd_port_qos_intx_s cn63xx;
+	struct cvmx_ipd_port_qos_intx_s cn63xxp1;
 };
 
 union cvmx_ipd_port_qos_int_enbx {
@@ -594,6 +643,8 @@
 	struct cvmx_ipd_port_qos_int_enbx_s cn52xxp1;
 	struct cvmx_ipd_port_qos_int_enbx_s cn56xx;
 	struct cvmx_ipd_port_qos_int_enbx_s cn56xxp1;
+	struct cvmx_ipd_port_qos_int_enbx_s cn63xx;
+	struct cvmx_ipd_port_qos_int_enbx_s cn63xxp1;
 };
 
 union cvmx_ipd_prc_hold_ptr_fifo_ctl {
@@ -616,6 +667,8 @@
 	struct cvmx_ipd_prc_hold_ptr_fifo_ctl_s cn56xxp1;
 	struct cvmx_ipd_prc_hold_ptr_fifo_ctl_s cn58xx;
 	struct cvmx_ipd_prc_hold_ptr_fifo_ctl_s cn58xxp1;
+	struct cvmx_ipd_prc_hold_ptr_fifo_ctl_s cn63xx;
+	struct cvmx_ipd_prc_hold_ptr_fifo_ctl_s cn63xxp1;
 };
 
 union cvmx_ipd_prc_port_ptr_fifo_ctl {
@@ -637,6 +690,8 @@
 	struct cvmx_ipd_prc_port_ptr_fifo_ctl_s cn56xxp1;
 	struct cvmx_ipd_prc_port_ptr_fifo_ctl_s cn58xx;
 	struct cvmx_ipd_prc_port_ptr_fifo_ctl_s cn58xxp1;
+	struct cvmx_ipd_prc_port_ptr_fifo_ctl_s cn63xx;
+	struct cvmx_ipd_prc_port_ptr_fifo_ctl_s cn63xxp1;
 };
 
 union cvmx_ipd_ptr_count {
@@ -660,6 +715,8 @@
 	struct cvmx_ipd_ptr_count_s cn56xxp1;
 	struct cvmx_ipd_ptr_count_s cn58xx;
 	struct cvmx_ipd_ptr_count_s cn58xxp1;
+	struct cvmx_ipd_ptr_count_s cn63xx;
+	struct cvmx_ipd_ptr_count_s cn63xxp1;
 };
 
 union cvmx_ipd_pwp_ptr_fifo_ctl {
@@ -683,6 +740,8 @@
 	struct cvmx_ipd_pwp_ptr_fifo_ctl_s cn56xxp1;
 	struct cvmx_ipd_pwp_ptr_fifo_ctl_s cn58xx;
 	struct cvmx_ipd_pwp_ptr_fifo_ctl_s cn58xxp1;
+	struct cvmx_ipd_pwp_ptr_fifo_ctl_s cn63xx;
+	struct cvmx_ipd_pwp_ptr_fifo_ctl_s cn63xxp1;
 };
 
 union cvmx_ipd_qosx_red_marks {
@@ -702,6 +761,8 @@
 	struct cvmx_ipd_qosx_red_marks_s cn56xxp1;
 	struct cvmx_ipd_qosx_red_marks_s cn58xx;
 	struct cvmx_ipd_qosx_red_marks_s cn58xxp1;
+	struct cvmx_ipd_qosx_red_marks_s cn63xx;
+	struct cvmx_ipd_qosx_red_marks_s cn63xxp1;
 };
 
 union cvmx_ipd_que0_free_page_cnt {
@@ -721,6 +782,8 @@
 	struct cvmx_ipd_que0_free_page_cnt_s cn56xxp1;
 	struct cvmx_ipd_que0_free_page_cnt_s cn58xx;
 	struct cvmx_ipd_que0_free_page_cnt_s cn58xxp1;
+	struct cvmx_ipd_que0_free_page_cnt_s cn63xx;
+	struct cvmx_ipd_que0_free_page_cnt_s cn63xxp1;
 };
 
 union cvmx_ipd_red_port_enable {
@@ -741,18 +804,25 @@
 	struct cvmx_ipd_red_port_enable_s cn56xxp1;
 	struct cvmx_ipd_red_port_enable_s cn58xx;
 	struct cvmx_ipd_red_port_enable_s cn58xxp1;
+	struct cvmx_ipd_red_port_enable_s cn63xx;
+	struct cvmx_ipd_red_port_enable_s cn63xxp1;
 };
 
 union cvmx_ipd_red_port_enable2 {
 	uint64_t u64;
 	struct cvmx_ipd_red_port_enable2_s {
+		uint64_t reserved_8_63:56;
+		uint64_t prt_enb:8;
+	} s;
+	struct cvmx_ipd_red_port_enable2_cn52xx {
 		uint64_t reserved_4_63:60;
 		uint64_t prt_enb:4;
-	} s;
-	struct cvmx_ipd_red_port_enable2_s cn52xx;
-	struct cvmx_ipd_red_port_enable2_s cn52xxp1;
-	struct cvmx_ipd_red_port_enable2_s cn56xx;
-	struct cvmx_ipd_red_port_enable2_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_ipd_red_port_enable2_cn52xx cn52xxp1;
+	struct cvmx_ipd_red_port_enable2_cn52xx cn56xx;
+	struct cvmx_ipd_red_port_enable2_cn52xx cn56xxp1;
+	struct cvmx_ipd_red_port_enable2_s cn63xx;
+	struct cvmx_ipd_red_port_enable2_s cn63xxp1;
 };
 
 union cvmx_ipd_red_quex_param {
@@ -775,6 +845,8 @@
 	struct cvmx_ipd_red_quex_param_s cn56xxp1;
 	struct cvmx_ipd_red_quex_param_s cn58xx;
 	struct cvmx_ipd_red_quex_param_s cn58xxp1;
+	struct cvmx_ipd_red_quex_param_s cn63xx;
+	struct cvmx_ipd_red_quex_param_s cn63xxp1;
 };
 
 union cvmx_ipd_sub_port_bp_page_cnt {
@@ -795,6 +867,8 @@
 	struct cvmx_ipd_sub_port_bp_page_cnt_s cn56xxp1;
 	struct cvmx_ipd_sub_port_bp_page_cnt_s cn58xx;
 	struct cvmx_ipd_sub_port_bp_page_cnt_s cn58xxp1;
+	struct cvmx_ipd_sub_port_bp_page_cnt_s cn63xx;
+	struct cvmx_ipd_sub_port_bp_page_cnt_s cn63xxp1;
 };
 
 union cvmx_ipd_sub_port_fcs {
@@ -822,6 +896,8 @@
 	struct cvmx_ipd_sub_port_fcs_s cn56xxp1;
 	struct cvmx_ipd_sub_port_fcs_cn38xx cn58xx;
 	struct cvmx_ipd_sub_port_fcs_cn38xx cn58xxp1;
+	struct cvmx_ipd_sub_port_fcs_s cn63xx;
+	struct cvmx_ipd_sub_port_fcs_s cn63xxp1;
 };
 
 union cvmx_ipd_sub_port_qos_cnt {
@@ -835,6 +911,8 @@
 	struct cvmx_ipd_sub_port_qos_cnt_s cn52xxp1;
 	struct cvmx_ipd_sub_port_qos_cnt_s cn56xx;
 	struct cvmx_ipd_sub_port_qos_cnt_s cn56xxp1;
+	struct cvmx_ipd_sub_port_qos_cnt_s cn63xx;
+	struct cvmx_ipd_sub_port_qos_cnt_s cn63xxp1;
 };
 
 union cvmx_ipd_wqe_fpa_queue {
@@ -854,6 +932,8 @@
 	struct cvmx_ipd_wqe_fpa_queue_s cn56xxp1;
 	struct cvmx_ipd_wqe_fpa_queue_s cn58xx;
 	struct cvmx_ipd_wqe_fpa_queue_s cn58xxp1;
+	struct cvmx_ipd_wqe_fpa_queue_s cn63xx;
+	struct cvmx_ipd_wqe_fpa_queue_s cn63xxp1;
 };
 
 union cvmx_ipd_wqe_ptr_valid {
@@ -872,6 +952,8 @@
 	struct cvmx_ipd_wqe_ptr_valid_s cn56xxp1;
 	struct cvmx_ipd_wqe_ptr_valid_s cn58xx;
 	struct cvmx_ipd_wqe_ptr_valid_s cn58xxp1;
+	struct cvmx_ipd_wqe_ptr_valid_s cn63xx;
+	struct cvmx_ipd_wqe_ptr_valid_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2c-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2c-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2c-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2c-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,70 +28,113 @@
 #ifndef __CVMX_L2C_DEFS_H__
 #define __CVMX_L2C_DEFS_H__
 
-#define CVMX_L2C_BST0 \
-	 CVMX_ADD_IO_SEG(0x00011800800007F8ull)
-#define CVMX_L2C_BST1 \
-	 CVMX_ADD_IO_SEG(0x00011800800007F0ull)
-#define CVMX_L2C_BST2 \
-	 CVMX_ADD_IO_SEG(0x00011800800007E8ull)
-#define CVMX_L2C_CFG \
-	 CVMX_ADD_IO_SEG(0x0001180080000000ull)
-#define CVMX_L2C_DBG \
-	 CVMX_ADD_IO_SEG(0x0001180080000030ull)
-#define CVMX_L2C_DUT \
-	 CVMX_ADD_IO_SEG(0x0001180080000050ull)
-#define CVMX_L2C_GRPWRR0 \
-	 CVMX_ADD_IO_SEG(0x00011800800000C8ull)
-#define CVMX_L2C_GRPWRR1 \
-	 CVMX_ADD_IO_SEG(0x00011800800000D0ull)
-#define CVMX_L2C_INT_EN \
-	 CVMX_ADD_IO_SEG(0x0001180080000100ull)
-#define CVMX_L2C_INT_STAT \
-	 CVMX_ADD_IO_SEG(0x00011800800000F8ull)
-#define CVMX_L2C_LCKBASE \
-	 CVMX_ADD_IO_SEG(0x0001180080000058ull)
-#define CVMX_L2C_LCKOFF \
-	 CVMX_ADD_IO_SEG(0x0001180080000060ull)
-#define CVMX_L2C_LFB0 \
-	 CVMX_ADD_IO_SEG(0x0001180080000038ull)
-#define CVMX_L2C_LFB1 \
-	 CVMX_ADD_IO_SEG(0x0001180080000040ull)
-#define CVMX_L2C_LFB2 \
-	 CVMX_ADD_IO_SEG(0x0001180080000048ull)
-#define CVMX_L2C_LFB3 \
-	 CVMX_ADD_IO_SEG(0x00011800800000B8ull)
-#define CVMX_L2C_OOB \
-	 CVMX_ADD_IO_SEG(0x00011800800000D8ull)
-#define CVMX_L2C_OOB1 \
-	 CVMX_ADD_IO_SEG(0x00011800800000E0ull)
-#define CVMX_L2C_OOB2 \
-	 CVMX_ADD_IO_SEG(0x00011800800000E8ull)
-#define CVMX_L2C_OOB3 \
-	 CVMX_ADD_IO_SEG(0x00011800800000F0ull)
-#define CVMX_L2C_PFC0 \
-	 CVMX_ADD_IO_SEG(0x0001180080000098ull)
-#define CVMX_L2C_PFC1 \
-	 CVMX_ADD_IO_SEG(0x00011800800000A0ull)
-#define CVMX_L2C_PFC2 \
-	 CVMX_ADD_IO_SEG(0x00011800800000A8ull)
-#define CVMX_L2C_PFC3 \
-	 CVMX_ADD_IO_SEG(0x00011800800000B0ull)
-#define CVMX_L2C_PFCTL \
-	 CVMX_ADD_IO_SEG(0x0001180080000090ull)
-#define CVMX_L2C_PFCX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180080000098ull + (((offset) & 3) * 8))
-#define CVMX_L2C_PPGRP \
-	 CVMX_ADD_IO_SEG(0x00011800800000C0ull)
-#define CVMX_L2C_SPAR0 \
-	 CVMX_ADD_IO_SEG(0x0001180080000068ull)
-#define CVMX_L2C_SPAR1 \
-	 CVMX_ADD_IO_SEG(0x0001180080000070ull)
-#define CVMX_L2C_SPAR2 \
-	 CVMX_ADD_IO_SEG(0x0001180080000078ull)
-#define CVMX_L2C_SPAR3 \
-	 CVMX_ADD_IO_SEG(0x0001180080000080ull)
-#define CVMX_L2C_SPAR4 \
-	 CVMX_ADD_IO_SEG(0x0001180080000088ull)
+#define CVMX_L2C_BIG_CTL (CVMX_ADD_IO_SEG(0x0001180080800030ull))
+#define CVMX_L2C_BST (CVMX_ADD_IO_SEG(0x00011800808007F8ull))
+#define CVMX_L2C_BST0 (CVMX_ADD_IO_SEG(0x00011800800007F8ull))
+#define CVMX_L2C_BST1 (CVMX_ADD_IO_SEG(0x00011800800007F0ull))
+#define CVMX_L2C_BST2 (CVMX_ADD_IO_SEG(0x00011800800007E8ull))
+#define CVMX_L2C_BST_MEMX(block_id) (CVMX_ADD_IO_SEG(0x0001180080C007F8ull))
+#define CVMX_L2C_BST_TDTX(block_id) (CVMX_ADD_IO_SEG(0x0001180080A007F0ull))
+#define CVMX_L2C_BST_TTGX(block_id) (CVMX_ADD_IO_SEG(0x0001180080A007F8ull))
+#define CVMX_L2C_CFG (CVMX_ADD_IO_SEG(0x0001180080000000ull))
+#define CVMX_L2C_COP0_MAPX(offset) (CVMX_ADD_IO_SEG(0x0001180080940000ull) + ((offset) & 16383) * 8)
+#define CVMX_L2C_CTL (CVMX_ADD_IO_SEG(0x0001180080800000ull))
+#define CVMX_L2C_DBG (CVMX_ADD_IO_SEG(0x0001180080000030ull))
+#define CVMX_L2C_DUT (CVMX_ADD_IO_SEG(0x0001180080000050ull))
+#define CVMX_L2C_DUT_MAPX(offset) (CVMX_ADD_IO_SEG(0x0001180080E00000ull) + ((offset) & 2047) * 8)
+#define CVMX_L2C_ERR_TDTX(block_id) (CVMX_ADD_IO_SEG(0x0001180080A007E0ull))
+#define CVMX_L2C_ERR_TTGX(block_id) (CVMX_ADD_IO_SEG(0x0001180080A007E8ull))
+#define CVMX_L2C_ERR_VBFX(block_id) (CVMX_ADD_IO_SEG(0x0001180080C007F0ull))
+#define CVMX_L2C_ERR_XMC (CVMX_ADD_IO_SEG(0x00011800808007D8ull))
+#define CVMX_L2C_GRPWRR0 (CVMX_ADD_IO_SEG(0x00011800800000C8ull))
+#define CVMX_L2C_GRPWRR1 (CVMX_ADD_IO_SEG(0x00011800800000D0ull))
+#define CVMX_L2C_INT_EN (CVMX_ADD_IO_SEG(0x0001180080000100ull))
+#define CVMX_L2C_INT_ENA (CVMX_ADD_IO_SEG(0x0001180080800020ull))
+#define CVMX_L2C_INT_REG (CVMX_ADD_IO_SEG(0x0001180080800018ull))
+#define CVMX_L2C_INT_STAT (CVMX_ADD_IO_SEG(0x00011800800000F8ull))
+#define CVMX_L2C_IOCX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800420ull))
+#define CVMX_L2C_IORX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800428ull))
+#define CVMX_L2C_LCKBASE (CVMX_ADD_IO_SEG(0x0001180080000058ull))
+#define CVMX_L2C_LCKOFF (CVMX_ADD_IO_SEG(0x0001180080000060ull))
+#define CVMX_L2C_LFB0 (CVMX_ADD_IO_SEG(0x0001180080000038ull))
+#define CVMX_L2C_LFB1 (CVMX_ADD_IO_SEG(0x0001180080000040ull))
+#define CVMX_L2C_LFB2 (CVMX_ADD_IO_SEG(0x0001180080000048ull))
+#define CVMX_L2C_LFB3 (CVMX_ADD_IO_SEG(0x00011800800000B8ull))
+#define CVMX_L2C_OOB (CVMX_ADD_IO_SEG(0x00011800800000D8ull))
+#define CVMX_L2C_OOB1 (CVMX_ADD_IO_SEG(0x00011800800000E0ull))
+#define CVMX_L2C_OOB2 (CVMX_ADD_IO_SEG(0x00011800800000E8ull))
+#define CVMX_L2C_OOB3 (CVMX_ADD_IO_SEG(0x00011800800000F0ull))
+#define CVMX_L2C_PFC0 CVMX_L2C_PFCX(0)
+#define CVMX_L2C_PFC1 CVMX_L2C_PFCX(1)
+#define CVMX_L2C_PFC2 CVMX_L2C_PFCX(2)
+#define CVMX_L2C_PFC3 CVMX_L2C_PFCX(3)
+#define CVMX_L2C_PFCTL (CVMX_ADD_IO_SEG(0x0001180080000090ull))
+#define CVMX_L2C_PFCX(offset) (CVMX_ADD_IO_SEG(0x0001180080000098ull) + ((offset) & 3) * 8)
+#define CVMX_L2C_PPGRP (CVMX_ADD_IO_SEG(0x00011800800000C0ull))
+#define CVMX_L2C_QOS_IOBX(block_id) (CVMX_ADD_IO_SEG(0x0001180080880200ull))
+#define CVMX_L2C_QOS_PPX(offset) (CVMX_ADD_IO_SEG(0x0001180080880000ull) + ((offset) & 7) * 8)
+#define CVMX_L2C_QOS_WGT (CVMX_ADD_IO_SEG(0x0001180080800008ull))
+#define CVMX_L2C_RSCX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800410ull))
+#define CVMX_L2C_RSDX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800418ull))
+#define CVMX_L2C_SPAR0 (CVMX_ADD_IO_SEG(0x0001180080000068ull))
+#define CVMX_L2C_SPAR1 (CVMX_ADD_IO_SEG(0x0001180080000070ull))
+#define CVMX_L2C_SPAR2 (CVMX_ADD_IO_SEG(0x0001180080000078ull))
+#define CVMX_L2C_SPAR3 (CVMX_ADD_IO_SEG(0x0001180080000080ull))
+#define CVMX_L2C_SPAR4 (CVMX_ADD_IO_SEG(0x0001180080000088ull))
+#define CVMX_L2C_TADX_ECC0(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00018ull))
+#define CVMX_L2C_TADX_ECC1(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00020ull))
+#define CVMX_L2C_TADX_IEN(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00000ull))
+#define CVMX_L2C_TADX_INT(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00028ull))
+#define CVMX_L2C_TADX_PFC0(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00400ull))
+#define CVMX_L2C_TADX_PFC1(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00408ull))
+#define CVMX_L2C_TADX_PFC2(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00410ull))
+#define CVMX_L2C_TADX_PFC3(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00418ull))
+#define CVMX_L2C_TADX_PRF(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00008ull))
+#define CVMX_L2C_TADX_TAG(block_id) (CVMX_ADD_IO_SEG(0x0001180080A00010ull))
+#define CVMX_L2C_VER_ID (CVMX_ADD_IO_SEG(0x00011800808007E0ull))
+#define CVMX_L2C_VER_IOB (CVMX_ADD_IO_SEG(0x00011800808007F0ull))
+#define CVMX_L2C_VER_MSC (CVMX_ADD_IO_SEG(0x00011800808007D0ull))
+#define CVMX_L2C_VER_PP (CVMX_ADD_IO_SEG(0x00011800808007E8ull))
+#define CVMX_L2C_VIRTID_IOBX(block_id) (CVMX_ADD_IO_SEG(0x00011800808C0200ull))
+#define CVMX_L2C_VIRTID_PPX(offset) (CVMX_ADD_IO_SEG(0x00011800808C0000ull) + ((offset) & 7) * 8)
+#define CVMX_L2C_VRT_CTL (CVMX_ADD_IO_SEG(0x0001180080800010ull))
+#define CVMX_L2C_VRT_MEMX(offset) (CVMX_ADD_IO_SEG(0x0001180080900000ull) + ((offset) & 1023) * 8)
+#define CVMX_L2C_WPAR_IOBX(block_id) (CVMX_ADD_IO_SEG(0x0001180080840200ull))
+#define CVMX_L2C_WPAR_PPX(offset) (CVMX_ADD_IO_SEG(0x0001180080840000ull) + ((offset) & 7) * 8)
+#define CVMX_L2C_XMCX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800400ull))
+#define CVMX_L2C_XMC_CMD (CVMX_ADD_IO_SEG(0x0001180080800028ull))
+#define CVMX_L2C_XMDX_PFC(block_id) (CVMX_ADD_IO_SEG(0x0001180080800408ull))
+
+union cvmx_l2c_big_ctl {
+	uint64_t u64;
+	struct cvmx_l2c_big_ctl_s {
+		uint64_t reserved_8_63:56;
+		uint64_t maxdram:4;
+		uint64_t reserved_1_3:3;
+		uint64_t disable:1;
+	} s;
+	struct cvmx_l2c_big_ctl_s cn63xx;
+};
+
+union cvmx_l2c_bst {
+	uint64_t u64;
+	struct cvmx_l2c_bst_s {
+		uint64_t reserved_38_63:26;
+		uint64_t dutfl:6;
+		uint64_t reserved_17_31:15;
+		uint64_t ioccmdfl:1;
+		uint64_t reserved_13_15:3;
+		uint64_t iocdatfl:1;
+		uint64_t reserved_9_11:3;
+		uint64_t dutresfl:1;
+		uint64_t reserved_5_7:3;
+		uint64_t vrtfl:1;
+		uint64_t reserved_1_3:3;
+		uint64_t tdffl:1;
+	} s;
+	struct cvmx_l2c_bst_s cn63xx;
+	struct cvmx_l2c_bst_s cn63xxp1;
+};
 
 union cvmx_l2c_bst0 {
 	uint64_t u64;
@@ -253,6 +296,48 @@
 	struct cvmx_l2c_bst2_cn56xx cn58xxp1;
 };
 
+union cvmx_l2c_bst_memx {
+	uint64_t u64;
+	struct cvmx_l2c_bst_memx_s {
+		uint64_t start_bist:1;
+		uint64_t clear_bist:1;
+		uint64_t reserved_5_61:57;
+		uint64_t rdffl:1;
+		uint64_t vbffl:4;
+	} s;
+	struct cvmx_l2c_bst_memx_s cn63xx;
+	struct cvmx_l2c_bst_memx_s cn63xxp1;
+};
+
+union cvmx_l2c_bst_tdtx {
+	uint64_t u64;
+	struct cvmx_l2c_bst_tdtx_s {
+		uint64_t reserved_32_63:32;
+		uint64_t fbfrspfl:8;
+		uint64_t sbffl:8;
+		uint64_t fbffl:8;
+		uint64_t l2dfl:8;
+	} s;
+	struct cvmx_l2c_bst_tdtx_s cn63xx;
+	struct cvmx_l2c_bst_tdtx_cn63xxp1 {
+		uint64_t reserved_24_63:40;
+		uint64_t sbffl:8;
+		uint64_t fbffl:8;
+		uint64_t l2dfl:8;
+	} cn63xxp1;
+};
+
+union cvmx_l2c_bst_ttgx {
+	uint64_t u64;
+	struct cvmx_l2c_bst_ttgx_s {
+		uint64_t reserved_17_63:47;
+		uint64_t lrufl:1;
+		uint64_t tagfl:16;
+	} s;
+	struct cvmx_l2c_bst_ttgx_s cn63xx;
+	struct cvmx_l2c_bst_ttgx_s cn63xxp1;
+};
+
 union cvmx_l2c_cfg {
 	uint64_t u64;
 	struct cvmx_l2c_cfg_s {
@@ -333,6 +418,49 @@
 	} cn58xxp1;
 };
 
+union cvmx_l2c_cop0_mapx {
+	uint64_t u64;
+	struct cvmx_l2c_cop0_mapx_s {
+		uint64_t data:64;
+	} s;
+	struct cvmx_l2c_cop0_mapx_s cn63xx;
+	struct cvmx_l2c_cop0_mapx_s cn63xxp1;
+};
+
+union cvmx_l2c_ctl {
+	uint64_t u64;
+	struct cvmx_l2c_ctl_s {
+		uint64_t reserved_28_63:36;
+		uint64_t disstgl2i:1;
+		uint64_t l2dfsbe:1;
+		uint64_t l2dfdbe:1;
+		uint64_t discclk:1;
+		uint64_t maxvab:4;
+		uint64_t maxlfb:4;
+		uint64_t rsp_arb_mode:1;
+		uint64_t xmc_arb_mode:1;
+		uint64_t ef_ena:1;
+		uint64_t ef_cnt:7;
+		uint64_t vab_thresh:4;
+		uint64_t disecc:1;
+		uint64_t disidxalias:1;
+	} s;
+	struct cvmx_l2c_ctl_s cn63xx;
+	struct cvmx_l2c_ctl_cn63xxp1 {
+		uint64_t reserved_25_63:39;
+		uint64_t discclk:1;
+		uint64_t maxvab:4;
+		uint64_t maxlfb:4;
+		uint64_t rsp_arb_mode:1;
+		uint64_t xmc_arb_mode:1;
+		uint64_t ef_ena:1;
+		uint64_t ef_cnt:7;
+		uint64_t vab_thresh:4;
+		uint64_t disecc:1;
+		uint64_t disidxalias:1;
+	} cn63xxp1;
+};
+
 union cvmx_l2c_dbg {
 	uint64_t u64;
 	struct cvmx_l2c_dbg_s {
@@ -349,7 +477,9 @@
 		uint64_t reserved_13_63:51;
 		uint64_t lfb_enum:2;
 		uint64_t lfb_dmp:1;
-		uint64_t reserved_5_9:5;
+		uint64_t reserved_7_9:3;
+		uint64_t ppnum:1;
+		uint64_t reserved_5_5:1;
 		uint64_t set:2;
 		uint64_t finv:1;
 		uint64_t l2d:1;
@@ -420,6 +550,79 @@
 	struct cvmx_l2c_dut_s cn58xxp1;
 };
 
+union cvmx_l2c_dut_mapx {
+	uint64_t u64;
+	struct cvmx_l2c_dut_mapx_s {
+		uint64_t reserved_38_63:26;
+		uint64_t tag:28;
+		uint64_t reserved_1_9:9;
+		uint64_t valid:1;
+	} s;
+	struct cvmx_l2c_dut_mapx_s cn63xx;
+	struct cvmx_l2c_dut_mapx_s cn63xxp1;
+};
+
+union cvmx_l2c_err_tdtx {
+	uint64_t u64;
+	struct cvmx_l2c_err_tdtx_s {
+		uint64_t dbe:1;
+		uint64_t sbe:1;
+		uint64_t vdbe:1;
+		uint64_t vsbe:1;
+		uint64_t syn:10;
+		uint64_t reserved_21_49:29;
+		uint64_t wayidx:17;
+		uint64_t reserved_2_3:2;
+		uint64_t type:2;
+	} s;
+	struct cvmx_l2c_err_tdtx_s cn63xx;
+	struct cvmx_l2c_err_tdtx_s cn63xxp1;
+};
+
+union cvmx_l2c_err_ttgx {
+	uint64_t u64;
+	struct cvmx_l2c_err_ttgx_s {
+		uint64_t dbe:1;
+		uint64_t sbe:1;
+		uint64_t noway:1;
+		uint64_t reserved_56_60:5;
+		uint64_t syn:6;
+		uint64_t reserved_21_49:29;
+		uint64_t wayidx:14;
+		uint64_t reserved_2_6:5;
+		uint64_t type:2;
+	} s;
+	struct cvmx_l2c_err_ttgx_s cn63xx;
+	struct cvmx_l2c_err_ttgx_s cn63xxp1;
+};
+
+union cvmx_l2c_err_vbfx {
+	uint64_t u64;
+	struct cvmx_l2c_err_vbfx_s {
+		uint64_t reserved_62_63:2;
+		uint64_t vdbe:1;
+		uint64_t vsbe:1;
+		uint64_t vsyn:10;
+		uint64_t reserved_2_49:48;
+		uint64_t type:2;
+	} s;
+	struct cvmx_l2c_err_vbfx_s cn63xx;
+	struct cvmx_l2c_err_vbfx_s cn63xxp1;
+};
+
+union cvmx_l2c_err_xmc {
+	uint64_t u64;
+	struct cvmx_l2c_err_xmc_s {
+		uint64_t cmd:6;
+		uint64_t reserved_52_57:6;
+		uint64_t sid:4;
+		uint64_t reserved_38_47:10;
+		uint64_t addr:38;
+	} s;
+	struct cvmx_l2c_err_xmc_s cn63xx;
+	struct cvmx_l2c_err_xmc_s cn63xxp1;
+};
+
 union cvmx_l2c_grpwrr0 {
 	uint64_t u64;
 	struct cvmx_l2c_grpwrr0_s {
@@ -464,6 +667,60 @@
 	struct cvmx_l2c_int_en_s cn56xxp1;
 };
 
+union cvmx_l2c_int_ena {
+	uint64_t u64;
+	struct cvmx_l2c_int_ena_s {
+		uint64_t reserved_8_63:56;
+		uint64_t bigrd:1;
+		uint64_t bigwr:1;
+		uint64_t vrtpe:1;
+		uint64_t vrtadrng:1;
+		uint64_t vrtidrng:1;
+		uint64_t vrtwr:1;
+		uint64_t holewr:1;
+		uint64_t holerd:1;
+	} s;
+	struct cvmx_l2c_int_ena_s cn63xx;
+	struct cvmx_l2c_int_ena_cn63xxp1 {
+		uint64_t reserved_6_63:58;
+		uint64_t vrtpe:1;
+		uint64_t vrtadrng:1;
+		uint64_t vrtidrng:1;
+		uint64_t vrtwr:1;
+		uint64_t holewr:1;
+		uint64_t holerd:1;
+	} cn63xxp1;
+};
+
+union cvmx_l2c_int_reg {
+	uint64_t u64;
+	struct cvmx_l2c_int_reg_s {
+		uint64_t reserved_17_63:47;
+		uint64_t tad0:1;
+		uint64_t reserved_8_15:8;
+		uint64_t bigrd:1;
+		uint64_t bigwr:1;
+		uint64_t vrtpe:1;
+		uint64_t vrtadrng:1;
+		uint64_t vrtidrng:1;
+		uint64_t vrtwr:1;
+		uint64_t holewr:1;
+		uint64_t holerd:1;
+	} s;
+	struct cvmx_l2c_int_reg_s cn63xx;
+	struct cvmx_l2c_int_reg_cn63xxp1 {
+		uint64_t reserved_17_63:47;
+		uint64_t tad0:1;
+		uint64_t reserved_6_15:10;
+		uint64_t vrtpe:1;
+		uint64_t vrtadrng:1;
+		uint64_t vrtidrng:1;
+		uint64_t vrtwr:1;
+		uint64_t holewr:1;
+		uint64_t holerd:1;
+	} cn63xxp1;
+};
+
 union cvmx_l2c_int_stat {
 	uint64_t u64;
 	struct cvmx_l2c_int_stat_s {
@@ -484,6 +741,24 @@
 	struct cvmx_l2c_int_stat_s cn56xxp1;
 };
 
+union cvmx_l2c_iocx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_iocx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_iocx_pfc_s cn63xx;
+	struct cvmx_l2c_iocx_pfc_s cn63xxp1;
+};
+
+union cvmx_l2c_iorx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_iorx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_iorx_pfc_s cn63xx;
+	struct cvmx_l2c_iorx_pfc_s cn63xxp1;
+};
+
 union cvmx_l2c_lckbase {
 	uint64_t u64;
 	struct cvmx_l2c_lckbase_s {
@@ -855,6 +1130,59 @@
 	struct cvmx_l2c_ppgrp_s cn56xxp1;
 };
 
+union cvmx_l2c_qos_iobx {
+	uint64_t u64;
+	struct cvmx_l2c_qos_iobx_s {
+		uint64_t reserved_6_63:58;
+		uint64_t dwblvl:2;
+		uint64_t reserved_2_3:2;
+		uint64_t lvl:2;
+	} s;
+	struct cvmx_l2c_qos_iobx_s cn63xx;
+	struct cvmx_l2c_qos_iobx_s cn63xxp1;
+};
+
+union cvmx_l2c_qos_ppx {
+	uint64_t u64;
+	struct cvmx_l2c_qos_ppx_s {
+		uint64_t reserved_2_63:62;
+		uint64_t lvl:2;
+	} s;
+	struct cvmx_l2c_qos_ppx_s cn63xx;
+	struct cvmx_l2c_qos_ppx_s cn63xxp1;
+};
+
+union cvmx_l2c_qos_wgt {
+	uint64_t u64;
+	struct cvmx_l2c_qos_wgt_s {
+		uint64_t reserved_32_63:32;
+		uint64_t wgt3:8;
+		uint64_t wgt2:8;
+		uint64_t wgt1:8;
+		uint64_t wgt0:8;
+	} s;
+	struct cvmx_l2c_qos_wgt_s cn63xx;
+	struct cvmx_l2c_qos_wgt_s cn63xxp1;
+};
+
+union cvmx_l2c_rscx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_rscx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_rscx_pfc_s cn63xx;
+	struct cvmx_l2c_rscx_pfc_s cn63xxp1;
+};
+
+union cvmx_l2c_rsdx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_rsdx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_rsdx_pfc_s cn63xx;
+	struct cvmx_l2c_rsdx_pfc_s cn63xxp1;
+};
+
 union cvmx_l2c_spar0 {
 	uint64_t u64;
 	struct cvmx_l2c_spar0_s {
@@ -960,4 +1288,282 @@
 	struct cvmx_l2c_spar4_s cn58xxp1;
 };
 
+union cvmx_l2c_tadx_ecc0 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_ecc0_s {
+		uint64_t reserved_58_63:6;
+		uint64_t ow3ecc:10;
+		uint64_t reserved_42_47:6;
+		uint64_t ow2ecc:10;
+		uint64_t reserved_26_31:6;
+		uint64_t ow1ecc:10;
+		uint64_t reserved_10_15:6;
+		uint64_t ow0ecc:10;
+	} s;
+	struct cvmx_l2c_tadx_ecc0_s cn63xx;
+	struct cvmx_l2c_tadx_ecc0_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_ecc1 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_ecc1_s {
+		uint64_t reserved_58_63:6;
+		uint64_t ow7ecc:10;
+		uint64_t reserved_42_47:6;
+		uint64_t ow6ecc:10;
+		uint64_t reserved_26_31:6;
+		uint64_t ow5ecc:10;
+		uint64_t reserved_10_15:6;
+		uint64_t ow4ecc:10;
+	} s;
+	struct cvmx_l2c_tadx_ecc1_s cn63xx;
+	struct cvmx_l2c_tadx_ecc1_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_ien {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_ien_s {
+		uint64_t reserved_9_63:55;
+		uint64_t wrdislmc:1;
+		uint64_t rddislmc:1;
+		uint64_t noway:1;
+		uint64_t vbfdbe:1;
+		uint64_t vbfsbe:1;
+		uint64_t tagdbe:1;
+		uint64_t tagsbe:1;
+		uint64_t l2ddbe:1;
+		uint64_t l2dsbe:1;
+	} s;
+	struct cvmx_l2c_tadx_ien_s cn63xx;
+	struct cvmx_l2c_tadx_ien_cn63xxp1 {
+		uint64_t reserved_7_63:57;
+		uint64_t noway:1;
+		uint64_t vbfdbe:1;
+		uint64_t vbfsbe:1;
+		uint64_t tagdbe:1;
+		uint64_t tagsbe:1;
+		uint64_t l2ddbe:1;
+		uint64_t l2dsbe:1;
+	} cn63xxp1;
+};
+
+union cvmx_l2c_tadx_int {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_int_s {
+		uint64_t reserved_9_63:55;
+		uint64_t wrdislmc:1;
+		uint64_t rddislmc:1;
+		uint64_t noway:1;
+		uint64_t vbfdbe:1;
+		uint64_t vbfsbe:1;
+		uint64_t tagdbe:1;
+		uint64_t tagsbe:1;
+		uint64_t l2ddbe:1;
+		uint64_t l2dsbe:1;
+	} s;
+	struct cvmx_l2c_tadx_int_s cn63xx;
+};
+
+union cvmx_l2c_tadx_pfc0 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_pfc0_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_tadx_pfc0_s cn63xx;
+	struct cvmx_l2c_tadx_pfc0_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_pfc1 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_pfc1_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_tadx_pfc1_s cn63xx;
+	struct cvmx_l2c_tadx_pfc1_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_pfc2 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_pfc2_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_tadx_pfc2_s cn63xx;
+	struct cvmx_l2c_tadx_pfc2_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_pfc3 {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_pfc3_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_tadx_pfc3_s cn63xx;
+	struct cvmx_l2c_tadx_pfc3_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_prf {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_prf_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt3sel:8;
+		uint64_t cnt2sel:8;
+		uint64_t cnt1sel:8;
+		uint64_t cnt0sel:8;
+	} s;
+	struct cvmx_l2c_tadx_prf_s cn63xx;
+	struct cvmx_l2c_tadx_prf_s cn63xxp1;
+};
+
+union cvmx_l2c_tadx_tag {
+	uint64_t u64;
+	struct cvmx_l2c_tadx_tag_s {
+		uint64_t reserved_46_63:18;
+		uint64_t ecc:6;
+		uint64_t reserved_36_39:4;
+		uint64_t tag:19;
+		uint64_t reserved_4_16:13;
+		uint64_t use:1;
+		uint64_t valid:1;
+		uint64_t dirty:1;
+		uint64_t lock:1;
+	} s;
+	struct cvmx_l2c_tadx_tag_s cn63xx;
+	struct cvmx_l2c_tadx_tag_s cn63xxp1;
+};
+
+union cvmx_l2c_ver_id {
+	uint64_t u64;
+	struct cvmx_l2c_ver_id_s {
+		uint64_t mask:64;
+	} s;
+	struct cvmx_l2c_ver_id_s cn63xx;
+	struct cvmx_l2c_ver_id_s cn63xxp1;
+};
+
+union cvmx_l2c_ver_iob {
+	uint64_t u64;
+	struct cvmx_l2c_ver_iob_s {
+		uint64_t reserved_1_63:63;
+		uint64_t mask:1;
+	} s;
+	struct cvmx_l2c_ver_iob_s cn63xx;
+	struct cvmx_l2c_ver_iob_s cn63xxp1;
+};
+
+union cvmx_l2c_ver_msc {
+	uint64_t u64;
+	struct cvmx_l2c_ver_msc_s {
+		uint64_t reserved_2_63:62;
+		uint64_t invl2:1;
+		uint64_t dwb:1;
+	} s;
+	struct cvmx_l2c_ver_msc_s cn63xx;
+};
+
+union cvmx_l2c_ver_pp {
+	uint64_t u64;
+	struct cvmx_l2c_ver_pp_s {
+		uint64_t reserved_6_63:58;
+		uint64_t mask:6;
+	} s;
+	struct cvmx_l2c_ver_pp_s cn63xx;
+	struct cvmx_l2c_ver_pp_s cn63xxp1;
+};
+
+union cvmx_l2c_virtid_iobx {
+	uint64_t u64;
+	struct cvmx_l2c_virtid_iobx_s {
+		uint64_t reserved_14_63:50;
+		uint64_t dwbid:6;
+		uint64_t reserved_6_7:2;
+		uint64_t id:6;
+	} s;
+	struct cvmx_l2c_virtid_iobx_s cn63xx;
+	struct cvmx_l2c_virtid_iobx_s cn63xxp1;
+};
+
+union cvmx_l2c_virtid_ppx {
+	uint64_t u64;
+	struct cvmx_l2c_virtid_ppx_s {
+		uint64_t reserved_6_63:58;
+		uint64_t id:6;
+	} s;
+	struct cvmx_l2c_virtid_ppx_s cn63xx;
+	struct cvmx_l2c_virtid_ppx_s cn63xxp1;
+};
+
+union cvmx_l2c_vrt_ctl {
+	uint64_t u64;
+	struct cvmx_l2c_vrt_ctl_s {
+		uint64_t reserved_9_63:55;
+		uint64_t ooberr:1;
+		uint64_t reserved_7_7:1;
+		uint64_t memsz:3;
+		uint64_t numid:3;
+		uint64_t enable:1;
+	} s;
+	struct cvmx_l2c_vrt_ctl_s cn63xx;
+	struct cvmx_l2c_vrt_ctl_s cn63xxp1;
+};
+
+union cvmx_l2c_vrt_memx {
+	uint64_t u64;
+	struct cvmx_l2c_vrt_memx_s {
+		uint64_t reserved_36_63:28;
+		uint64_t parity:4;
+		uint64_t data:32;
+	} s;
+	struct cvmx_l2c_vrt_memx_s cn63xx;
+	struct cvmx_l2c_vrt_memx_s cn63xxp1;
+};
+
+union cvmx_l2c_wpar_iobx {
+	uint64_t u64;
+	struct cvmx_l2c_wpar_iobx_s {
+		uint64_t reserved_16_63:48;
+		uint64_t mask:16;
+	} s;
+	struct cvmx_l2c_wpar_iobx_s cn63xx;
+	struct cvmx_l2c_wpar_iobx_s cn63xxp1;
+};
+
+union cvmx_l2c_wpar_ppx {
+	uint64_t u64;
+	struct cvmx_l2c_wpar_ppx_s {
+		uint64_t reserved_16_63:48;
+		uint64_t mask:16;
+	} s;
+	struct cvmx_l2c_wpar_ppx_s cn63xx;
+	struct cvmx_l2c_wpar_ppx_s cn63xxp1;
+};
+
+union cvmx_l2c_xmcx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_xmcx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_xmcx_pfc_s cn63xx;
+	struct cvmx_l2c_xmcx_pfc_s cn63xxp1;
+};
+
+union cvmx_l2c_xmc_cmd {
+	uint64_t u64;
+	struct cvmx_l2c_xmc_cmd_s {
+		uint64_t inuse:1;
+		uint64_t cmd:6;
+		uint64_t reserved_38_56:19;
+		uint64_t addr:38;
+	} s;
+	struct cvmx_l2c_xmc_cmd_s cn63xx;
+	struct cvmx_l2c_xmc_cmd_s cn63xxp1;
+};
+
+union cvmx_l2c_xmdx_pfc {
+	uint64_t u64;
+	struct cvmx_l2c_xmdx_pfc_s {
+		uint64_t count:64;
+	} s;
+	struct cvmx_l2c_xmdx_pfc_s cn63xx;
+	struct cvmx_l2c_xmdx_pfc_s cn63xxp1;
+};
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2c.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2c.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2c.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2c.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -26,7 +26,6 @@
  ***********************license end**************************************/
 
 /*
- *
  * Interface to the Level 2 Cache (L2C) control, measurement, and debugging
  * facilities.
  */
@@ -34,93 +33,126 @@
 #ifndef __CVMX_L2C_H__
 #define __CVMX_L2C_H__
 
-/* Deprecated macro, use function */
-#define CVMX_L2_ASSOC     cvmx_l2c_get_num_assoc()
-
-/* Deprecated macro, use function */
-#define CVMX_L2_SET_BITS  cvmx_l2c_get_set_bits()
+#define CVMX_L2_ASSOC     cvmx_l2c_get_num_assoc()   /* Deprecated macro, use function */
+#define CVMX_L2_SET_BITS  cvmx_l2c_get_set_bits()    /* Deprecated macro, use function */
+#define CVMX_L2_SETS      cvmx_l2c_get_num_sets()    /* Deprecated macro, use function */
 
-/* Deprecated macro, use function */
-#define CVMX_L2_SETS      cvmx_l2c_get_num_sets()
 
 #define CVMX_L2C_IDX_ADDR_SHIFT 7  /* based on 128 byte cache line size */
 #define CVMX_L2C_IDX_MASK       (cvmx_l2c_get_num_sets() - 1)
 
 /* Defines for index aliasing computations */
-#define CVMX_L2C_TAG_ADDR_ALIAS_SHIFT \
-	(CVMX_L2C_IDX_ADDR_SHIFT + cvmx_l2c_get_set_bits())
+#define CVMX_L2C_TAG_ADDR_ALIAS_SHIFT (CVMX_L2C_IDX_ADDR_SHIFT + cvmx_l2c_get_set_bits())
+#define CVMX_L2C_ALIAS_MASK (CVMX_L2C_IDX_MASK << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT)
+#define CVMX_L2C_MEMBANK_SELECT_SIZE  4096
 
-#define CVMX_L2C_ALIAS_MASK \
-	(CVMX_L2C_IDX_MASK << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT)
+/* Defines for Virtualizations, valid only from Octeon II onwards. */
+#define CVMX_L2C_VRT_MAX_VIRTID_ALLOWED ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 64 : 0)
+#define CVMX_L2C_VRT_MAX_MEMSZ_ALLOWED ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 32 : 0)
 
 union cvmx_l2c_tag {
 	uint64_t u64;
 	struct {
 		uint64_t reserved:28;
-		uint64_t V:1;	/* Line valid */
-		uint64_t D:1;	/* Line dirty */
-		uint64_t L:1;	/* Line locked */
-		uint64_t U:1;	/* Use, LRU eviction */
+		uint64_t V:1;		/* Line valid */
+		uint64_t D:1;		/* Line dirty */
+		uint64_t L:1;		/* Line locked */
+		uint64_t U:1;		/* Use, LRU eviction */
 		uint64_t addr:32;	/* Phys mem (not all bits valid) */
 	} s;
 };
 
+/* Number of L2C Tag-and-data sections (TADs) that are connected to LMC. */
+#define CVMX_L2C_TADS  1
+
   /* L2C Performance Counter events. */
 enum cvmx_l2c_event {
-	CVMX_L2C_EVENT_CYCLES = 0,
-	CVMX_L2C_EVENT_INSTRUCTION_MISS = 1,
-	CVMX_L2C_EVENT_INSTRUCTION_HIT = 2,
-	CVMX_L2C_EVENT_DATA_MISS = 3,
-	CVMX_L2C_EVENT_DATA_HIT = 4,
-	CVMX_L2C_EVENT_MISS = 5,
-	CVMX_L2C_EVENT_HIT = 6,
-	CVMX_L2C_EVENT_VICTIM_HIT = 7,
-	CVMX_L2C_EVENT_INDEX_CONFLICT = 8,
-	CVMX_L2C_EVENT_TAG_PROBE = 9,
-	CVMX_L2C_EVENT_TAG_UPDATE = 10,
-	CVMX_L2C_EVENT_TAG_COMPLETE = 11,
-	CVMX_L2C_EVENT_TAG_DIRTY = 12,
-	CVMX_L2C_EVENT_DATA_STORE_NOP = 13,
-	CVMX_L2C_EVENT_DATA_STORE_READ = 14,
+	CVMX_L2C_EVENT_CYCLES           =  0,
+	CVMX_L2C_EVENT_INSTRUCTION_MISS =  1,
+	CVMX_L2C_EVENT_INSTRUCTION_HIT  =  2,
+	CVMX_L2C_EVENT_DATA_MISS        =  3,
+	CVMX_L2C_EVENT_DATA_HIT         =  4,
+	CVMX_L2C_EVENT_MISS             =  5,
+	CVMX_L2C_EVENT_HIT              =  6,
+	CVMX_L2C_EVENT_VICTIM_HIT       =  7,
+	CVMX_L2C_EVENT_INDEX_CONFLICT   =  8,
+	CVMX_L2C_EVENT_TAG_PROBE        =  9,
+	CVMX_L2C_EVENT_TAG_UPDATE       = 10,
+	CVMX_L2C_EVENT_TAG_COMPLETE     = 11,
+	CVMX_L2C_EVENT_TAG_DIRTY        = 12,
+	CVMX_L2C_EVENT_DATA_STORE_NOP   = 13,
+	CVMX_L2C_EVENT_DATA_STORE_READ  = 14,
 	CVMX_L2C_EVENT_DATA_STORE_WRITE = 15,
-	CVMX_L2C_EVENT_FILL_DATA_VALID = 16,
-	CVMX_L2C_EVENT_WRITE_REQUEST = 17,
-	CVMX_L2C_EVENT_READ_REQUEST = 18,
+	CVMX_L2C_EVENT_FILL_DATA_VALID  = 16,
+	CVMX_L2C_EVENT_WRITE_REQUEST    = 17,
+	CVMX_L2C_EVENT_READ_REQUEST     = 18,
 	CVMX_L2C_EVENT_WRITE_DATA_VALID = 19,
-	CVMX_L2C_EVENT_XMC_NOP = 20,
-	CVMX_L2C_EVENT_XMC_LDT = 21,
-	CVMX_L2C_EVENT_XMC_LDI = 22,
-	CVMX_L2C_EVENT_XMC_LDD = 23,
-	CVMX_L2C_EVENT_XMC_STF = 24,
-	CVMX_L2C_EVENT_XMC_STT = 25,
-	CVMX_L2C_EVENT_XMC_STP = 26,
-	CVMX_L2C_EVENT_XMC_STC = 27,
-	CVMX_L2C_EVENT_XMC_DWB = 28,
-	CVMX_L2C_EVENT_XMC_PL2 = 29,
-	CVMX_L2C_EVENT_XMC_PSL1 = 30,
-	CVMX_L2C_EVENT_XMC_IOBLD = 31,
-	CVMX_L2C_EVENT_XMC_IOBST = 32,
-	CVMX_L2C_EVENT_XMC_IOBDMA = 33,
-	CVMX_L2C_EVENT_XMC_IOBRSP = 34,
-	CVMX_L2C_EVENT_XMC_BUS_VALID = 35,
-	CVMX_L2C_EVENT_XMC_MEM_DATA = 36,
-	CVMX_L2C_EVENT_XMC_REFL_DATA = 37,
-	CVMX_L2C_EVENT_XMC_IOBRSP_DATA = 38,
-	CVMX_L2C_EVENT_RSC_NOP = 39,
-	CVMX_L2C_EVENT_RSC_STDN = 40,
-	CVMX_L2C_EVENT_RSC_FILL = 41,
-	CVMX_L2C_EVENT_RSC_REFL = 42,
-	CVMX_L2C_EVENT_RSC_STIN = 43,
-	CVMX_L2C_EVENT_RSC_SCIN = 44,
-	CVMX_L2C_EVENT_RSC_SCFL = 45,
-	CVMX_L2C_EVENT_RSC_SCDN = 46,
-	CVMX_L2C_EVENT_RSC_DATA_VALID = 47,
-	CVMX_L2C_EVENT_RSC_VALID_FILL = 48,
-	CVMX_L2C_EVENT_RSC_VALID_STRSP = 49,
-	CVMX_L2C_EVENT_RSC_VALID_REFL = 50,
-	CVMX_L2C_EVENT_LRF_REQ = 51,
-	CVMX_L2C_EVENT_DT_RD_ALLOC = 52,
-	CVMX_L2C_EVENT_DT_WR_INVAL = 53
+	CVMX_L2C_EVENT_XMC_NOP          = 20,
+	CVMX_L2C_EVENT_XMC_LDT          = 21,
+	CVMX_L2C_EVENT_XMC_LDI          = 22,
+	CVMX_L2C_EVENT_XMC_LDD          = 23,
+	CVMX_L2C_EVENT_XMC_STF          = 24,
+	CVMX_L2C_EVENT_XMC_STT          = 25,
+	CVMX_L2C_EVENT_XMC_STP          = 26,
+	CVMX_L2C_EVENT_XMC_STC          = 27,
+	CVMX_L2C_EVENT_XMC_DWB          = 28,
+	CVMX_L2C_EVENT_XMC_PL2          = 29,
+	CVMX_L2C_EVENT_XMC_PSL1         = 30,
+	CVMX_L2C_EVENT_XMC_IOBLD        = 31,
+	CVMX_L2C_EVENT_XMC_IOBST        = 32,
+	CVMX_L2C_EVENT_XMC_IOBDMA       = 33,
+	CVMX_L2C_EVENT_XMC_IOBRSP       = 34,
+	CVMX_L2C_EVENT_XMC_BUS_VALID    = 35,
+	CVMX_L2C_EVENT_XMC_MEM_DATA     = 36,
+	CVMX_L2C_EVENT_XMC_REFL_DATA    = 37,
+	CVMX_L2C_EVENT_XMC_IOBRSP_DATA  = 38,
+	CVMX_L2C_EVENT_RSC_NOP          = 39,
+	CVMX_L2C_EVENT_RSC_STDN         = 40,
+	CVMX_L2C_EVENT_RSC_FILL         = 41,
+	CVMX_L2C_EVENT_RSC_REFL         = 42,
+	CVMX_L2C_EVENT_RSC_STIN         = 43,
+	CVMX_L2C_EVENT_RSC_SCIN         = 44,
+	CVMX_L2C_EVENT_RSC_SCFL         = 45,
+	CVMX_L2C_EVENT_RSC_SCDN         = 46,
+	CVMX_L2C_EVENT_RSC_DATA_VALID   = 47,
+	CVMX_L2C_EVENT_RSC_VALID_FILL   = 48,
+	CVMX_L2C_EVENT_RSC_VALID_STRSP  = 49,
+	CVMX_L2C_EVENT_RSC_VALID_REFL   = 50,
+	CVMX_L2C_EVENT_LRF_REQ          = 51,
+	CVMX_L2C_EVENT_DT_RD_ALLOC      = 52,
+	CVMX_L2C_EVENT_DT_WR_INVAL      = 53,
+	CVMX_L2C_EVENT_MAX
+};
+
+/* L2C Performance Counter events for Octeon2. */
+enum cvmx_l2c_tad_event {
+	CVMX_L2C_TAD_EVENT_NONE          = 0,
+	CVMX_L2C_TAD_EVENT_TAG_HIT       = 1,
+	CVMX_L2C_TAD_EVENT_TAG_MISS      = 2,
+	CVMX_L2C_TAD_EVENT_TAG_NOALLOC   = 3,
+	CVMX_L2C_TAD_EVENT_TAG_VICTIM    = 4,
+	CVMX_L2C_TAD_EVENT_SC_FAIL       = 5,
+	CVMX_L2C_TAD_EVENT_SC_PASS       = 6,
+	CVMX_L2C_TAD_EVENT_LFB_VALID     = 7,
+	CVMX_L2C_TAD_EVENT_LFB_WAIT_LFB  = 8,
+	CVMX_L2C_TAD_EVENT_LFB_WAIT_VAB  = 9,
+	CVMX_L2C_TAD_EVENT_QUAD0_INDEX   = 128,
+	CVMX_L2C_TAD_EVENT_QUAD0_READ    = 129,
+	CVMX_L2C_TAD_EVENT_QUAD0_BANK    = 130,
+	CVMX_L2C_TAD_EVENT_QUAD0_WDAT    = 131,
+	CVMX_L2C_TAD_EVENT_QUAD1_INDEX   = 144,
+	CVMX_L2C_TAD_EVENT_QUAD1_READ    = 145,
+	CVMX_L2C_TAD_EVENT_QUAD1_BANK    = 146,
+	CVMX_L2C_TAD_EVENT_QUAD1_WDAT    = 147,
+	CVMX_L2C_TAD_EVENT_QUAD2_INDEX   = 160,
+	CVMX_L2C_TAD_EVENT_QUAD2_READ    = 161,
+	CVMX_L2C_TAD_EVENT_QUAD2_BANK    = 162,
+	CVMX_L2C_TAD_EVENT_QUAD2_WDAT    = 163,
+	CVMX_L2C_TAD_EVENT_QUAD3_INDEX   = 176,
+	CVMX_L2C_TAD_EVENT_QUAD3_READ    = 177,
+	CVMX_L2C_TAD_EVENT_QUAD3_BANK    = 178,
+	CVMX_L2C_TAD_EVENT_QUAD3_WDAT    = 179,
+	CVMX_L2C_TAD_EVENT_MAX
 };
 
 /**
@@ -132,10 +164,10 @@
  * @clear_on_read:  When asserted, any read of the performance counter
  *                       clears the counter.
  *
- * The routine does not clear the counter.
+ * @note The routine does not clear the counter.
  */
-void cvmx_l2c_config_perf(uint32_t counter,
-			  enum cvmx_l2c_event event, uint32_t clear_on_read);
+void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event, uint32_t clear_on_read);
+
 /**
  * Read the given L2 Cache performance counter. The counter must be configured
  * before reading, but this routine does not enforce this requirement.
@@ -160,18 +192,18 @@
 /**
  * Partitions the L2 cache for a core
  *
- * @core:  The core that the partitioning applies to.
- *
- * @mask: The partitioning of the ways expressed as a binary mask. A 0
- *        bit allows the core to evict cache lines from a way, while a
- *        1 bit blocks the core from evicting any lines from that
- *        way. There must be at least one allowed way (0 bit) in the
- *        mask.
+ * @core: The core that the partitioning applies to.
+ * @mask: The partitioning of the ways expressed as a binary
+ *             mask. A 0 bit allows the core to evict cache lines from
+ *             a way, while a 1 bit blocks the core from evicting any
+ *             lines from that way. There must be at least one allowed
+ *             way (0 bit) in the mask.
  *
- * If any ways are blocked for all cores and the HW blocks, then those
- * ways will never have any cache lines evicted from them.  All cores
- * and the hardware blocks are free to read from all ways regardless
- * of the partitioning.
+
+ * @note If any ways are blocked for all cores and the HW blocks, then
+ *       those ways will never have any cache lines evicted from them.
+ *       All cores and the hardware blocks are free to read from all
+ *       ways regardless of the partitioning.
  */
 int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask);
 
@@ -187,19 +219,21 @@
 /**
  * Partitions the L2 cache for the hardware blocks.
  *
- * @mask: The partitioning of the ways expressed as a binary mask. A 0
- *        bit allows the core to evict cache lines from a way, while a
- *        1 bit blocks the core from evicting any lines from that
- *        way. There must be at least one allowed way (0 bit) in the
- *        mask.
+ * @mask: The partitioning of the ways expressed as a binary
+ *             mask. A 0 bit allows the core to evict cache lines from
+ *             a way, while a 1 bit blocks the core from evicting any
+ *             lines from that way. There must be at least one allowed
+ *             way (0 bit) in the mask.
  *
- * If any ways are blocked for all cores and the HW blocks, then those
- * ways will never have any cache lines evicted from them.  All cores
- * and the hardware blocks are free to read from all ways regardless
- * of the partitioning.
+
+ * @note If any ways are blocked for all cores and the HW blocks, then
+ *       those ways will never have any cache lines evicted from them.
+ *       All cores and the hardware blocks are free to read from all
+ *       ways regardless of the partitioning.
  */
 int cvmx_l2c_set_hw_way_partition(uint32_t mask);
 
+
 /**
  * Locks a line in the L2 cache at the specified physical address
  *
@@ -263,13 +297,14 @@
  */
 union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index);
 
-/* Wrapper around deprecated old function name */
-static inline union cvmx_l2c_tag cvmx_get_l2c_tag(uint32_t association,
-					      uint32_t index)
+/* Wrapper providing a deprecated old function name */
+static inline union cvmx_l2c_tag cvmx_get_l2c_tag(uint32_t association, uint32_t index) __attribute__((deprecated));
+static inline union cvmx_l2c_tag cvmx_get_l2c_tag(uint32_t association, uint32_t index)
 {
 	return cvmx_l2c_get_tag(association, index);
 }
 
+
 /**
  * Returns the cache index for a given physical address
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2d-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2d-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2d-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2d-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,30 +28,18 @@
 #ifndef __CVMX_L2D_DEFS_H__
 #define __CVMX_L2D_DEFS_H__
 
-#define CVMX_L2D_BST0 \
-	 CVMX_ADD_IO_SEG(0x0001180080000780ull)
-#define CVMX_L2D_BST1 \
-	 CVMX_ADD_IO_SEG(0x0001180080000788ull)
-#define CVMX_L2D_BST2 \
-	 CVMX_ADD_IO_SEG(0x0001180080000790ull)
-#define CVMX_L2D_BST3 \
-	 CVMX_ADD_IO_SEG(0x0001180080000798ull)
-#define CVMX_L2D_ERR \
-	 CVMX_ADD_IO_SEG(0x0001180080000010ull)
-#define CVMX_L2D_FADR \
-	 CVMX_ADD_IO_SEG(0x0001180080000018ull)
-#define CVMX_L2D_FSYN0 \
-	 CVMX_ADD_IO_SEG(0x0001180080000020ull)
-#define CVMX_L2D_FSYN1 \
-	 CVMX_ADD_IO_SEG(0x0001180080000028ull)
-#define CVMX_L2D_FUS0 \
-	 CVMX_ADD_IO_SEG(0x00011800800007A0ull)
-#define CVMX_L2D_FUS1 \
-	 CVMX_ADD_IO_SEG(0x00011800800007A8ull)
-#define CVMX_L2D_FUS2 \
-	 CVMX_ADD_IO_SEG(0x00011800800007B0ull)
-#define CVMX_L2D_FUS3 \
-	 CVMX_ADD_IO_SEG(0x00011800800007B8ull)
+#define CVMX_L2D_BST0 (CVMX_ADD_IO_SEG(0x0001180080000780ull))
+#define CVMX_L2D_BST1 (CVMX_ADD_IO_SEG(0x0001180080000788ull))
+#define CVMX_L2D_BST2 (CVMX_ADD_IO_SEG(0x0001180080000790ull))
+#define CVMX_L2D_BST3 (CVMX_ADD_IO_SEG(0x0001180080000798ull))
+#define CVMX_L2D_ERR (CVMX_ADD_IO_SEG(0x0001180080000010ull))
+#define CVMX_L2D_FADR (CVMX_ADD_IO_SEG(0x0001180080000018ull))
+#define CVMX_L2D_FSYN0 (CVMX_ADD_IO_SEG(0x0001180080000020ull))
+#define CVMX_L2D_FSYN1 (CVMX_ADD_IO_SEG(0x0001180080000028ull))
+#define CVMX_L2D_FUS0 (CVMX_ADD_IO_SEG(0x00011800800007A0ull))
+#define CVMX_L2D_FUS1 (CVMX_ADD_IO_SEG(0x00011800800007A8ull))
+#define CVMX_L2D_FUS2 (CVMX_ADD_IO_SEG(0x00011800800007B0ull))
+#define CVMX_L2D_FUS3 (CVMX_ADD_IO_SEG(0x00011800800007B8ull))
 
 union cvmx_l2d_bst0 {
 	uint64_t u64;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2t-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2t-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-l2t-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-l2t-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,8 +28,7 @@
 #ifndef __CVMX_L2T_DEFS_H__
 #define __CVMX_L2T_DEFS_H__
 
-#define CVMX_L2T_ERR \
-	 CVMX_ADD_IO_SEG(0x0001180080000008ull)
+#define CVMX_L2T_ERR (CVMX_ADD_IO_SEG(0x0001180080000008ull))
 
 union cvmx_l2t_err {
 	uint64_t u64;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-led-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-led-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-led-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-led-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,32 +28,19 @@
 #ifndef __CVMX_LED_DEFS_H__
 #define __CVMX_LED_DEFS_H__
 
-#define CVMX_LED_BLINK \
-	 CVMX_ADD_IO_SEG(0x0001180000001A48ull)
-#define CVMX_LED_CLK_PHASE \
-	 CVMX_ADD_IO_SEG(0x0001180000001A08ull)
-#define CVMX_LED_CYLON \
-	 CVMX_ADD_IO_SEG(0x0001180000001AF8ull)
-#define CVMX_LED_DBG \
-	 CVMX_ADD_IO_SEG(0x0001180000001A18ull)
-#define CVMX_LED_EN \
-	 CVMX_ADD_IO_SEG(0x0001180000001A00ull)
-#define CVMX_LED_POLARITY \
-	 CVMX_ADD_IO_SEG(0x0001180000001A50ull)
-#define CVMX_LED_PRT \
-	 CVMX_ADD_IO_SEG(0x0001180000001A10ull)
-#define CVMX_LED_PRT_FMT \
-	 CVMX_ADD_IO_SEG(0x0001180000001A30ull)
-#define CVMX_LED_PRT_STATUSX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001A80ull + (((offset) & 7) * 8))
-#define CVMX_LED_UDD_CNTX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001A20ull + (((offset) & 1) * 8))
-#define CVMX_LED_UDD_DATX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001A38ull + (((offset) & 1) * 8))
-#define CVMX_LED_UDD_DAT_CLRX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001AC8ull + (((offset) & 1) * 16))
-#define CVMX_LED_UDD_DAT_SETX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001AC0ull + (((offset) & 1) * 16))
+#define CVMX_LED_BLINK (CVMX_ADD_IO_SEG(0x0001180000001A48ull))
+#define CVMX_LED_CLK_PHASE (CVMX_ADD_IO_SEG(0x0001180000001A08ull))
+#define CVMX_LED_CYLON (CVMX_ADD_IO_SEG(0x0001180000001AF8ull))
+#define CVMX_LED_DBG (CVMX_ADD_IO_SEG(0x0001180000001A18ull))
+#define CVMX_LED_EN (CVMX_ADD_IO_SEG(0x0001180000001A00ull))
+#define CVMX_LED_POLARITY (CVMX_ADD_IO_SEG(0x0001180000001A50ull))
+#define CVMX_LED_PRT (CVMX_ADD_IO_SEG(0x0001180000001A10ull))
+#define CVMX_LED_PRT_FMT (CVMX_ADD_IO_SEG(0x0001180000001A30ull))
+#define CVMX_LED_PRT_STATUSX(offset) (CVMX_ADD_IO_SEG(0x0001180000001A80ull) + ((offset) & 7) * 8)
+#define CVMX_LED_UDD_CNTX(offset) (CVMX_ADD_IO_SEG(0x0001180000001A20ull) + ((offset) & 1) * 8)
+#define CVMX_LED_UDD_DATX(offset) (CVMX_ADD_IO_SEG(0x0001180000001A38ull) + ((offset) & 1) * 8)
+#define CVMX_LED_UDD_DAT_CLRX(offset) (CVMX_ADD_IO_SEG(0x0001180000001AC8ull) + ((offset) & 1) * 16)
+#define CVMX_LED_UDD_DAT_SETX(offset) (CVMX_ADD_IO_SEG(0x0001180000001AC0ull) + ((offset) & 1) * 16)
 
 union cvmx_led_blink {
 	uint64_t u64;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-mio-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-mio-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-mio-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-mio-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,191 +28,117 @@
 #ifndef __CVMX_MIO_DEFS_H__
 #define __CVMX_MIO_DEFS_H__
 
-#define CVMX_MIO_BOOT_BIST_STAT \
-	 CVMX_ADD_IO_SEG(0x00011800000000F8ull)
-#define CVMX_MIO_BOOT_COMP \
-	 CVMX_ADD_IO_SEG(0x00011800000000B8ull)
-#define CVMX_MIO_BOOT_DMA_CFGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000100ull + (((offset) & 3) * 8))
-#define CVMX_MIO_BOOT_DMA_INTX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000138ull + (((offset) & 3) * 8))
-#define CVMX_MIO_BOOT_DMA_INT_ENX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000150ull + (((offset) & 3) * 8))
-#define CVMX_MIO_BOOT_DMA_TIMX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000120ull + (((offset) & 3) * 8))
-#define CVMX_MIO_BOOT_ERR \
-	 CVMX_ADD_IO_SEG(0x00011800000000A0ull)
-#define CVMX_MIO_BOOT_INT \
-	 CVMX_ADD_IO_SEG(0x00011800000000A8ull)
-#define CVMX_MIO_BOOT_LOC_ADR \
-	 CVMX_ADD_IO_SEG(0x0001180000000090ull)
-#define CVMX_MIO_BOOT_LOC_CFGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000080ull + (((offset) & 1) * 8))
-#define CVMX_MIO_BOOT_LOC_DAT \
-	 CVMX_ADD_IO_SEG(0x0001180000000098ull)
-#define CVMX_MIO_BOOT_PIN_DEFS \
-	 CVMX_ADD_IO_SEG(0x00011800000000C0ull)
-#define CVMX_MIO_BOOT_REG_CFGX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000000ull + (((offset) & 7) * 8))
-#define CVMX_MIO_BOOT_REG_TIMX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000040ull + (((offset) & 7) * 8))
-#define CVMX_MIO_BOOT_THR \
-	 CVMX_ADD_IO_SEG(0x00011800000000B0ull)
-#define CVMX_MIO_FUS_BNK_DATX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001520ull + (((offset) & 3) * 8))
-#define CVMX_MIO_FUS_DAT0 \
-	 CVMX_ADD_IO_SEG(0x0001180000001400ull)
-#define CVMX_MIO_FUS_DAT1 \
-	 CVMX_ADD_IO_SEG(0x0001180000001408ull)
-#define CVMX_MIO_FUS_DAT2 \
-	 CVMX_ADD_IO_SEG(0x0001180000001410ull)
-#define CVMX_MIO_FUS_DAT3 \
-	 CVMX_ADD_IO_SEG(0x0001180000001418ull)
-#define CVMX_MIO_FUS_EMA \
-	 CVMX_ADD_IO_SEG(0x0001180000001550ull)
-#define CVMX_MIO_FUS_PDF \
-	 CVMX_ADD_IO_SEG(0x0001180000001420ull)
-#define CVMX_MIO_FUS_PLL \
-	 CVMX_ADD_IO_SEG(0x0001180000001580ull)
-#define CVMX_MIO_FUS_PROG \
-	 CVMX_ADD_IO_SEG(0x0001180000001510ull)
-#define CVMX_MIO_FUS_PROG_TIMES \
-	 CVMX_ADD_IO_SEG(0x0001180000001518ull)
-#define CVMX_MIO_FUS_RCMD \
-	 CVMX_ADD_IO_SEG(0x0001180000001500ull)
-#define CVMX_MIO_FUS_SPR_REPAIR_RES \
-	 CVMX_ADD_IO_SEG(0x0001180000001548ull)
-#define CVMX_MIO_FUS_SPR_REPAIR_SUM \
-	 CVMX_ADD_IO_SEG(0x0001180000001540ull)
-#define CVMX_MIO_FUS_UNLOCK \
-	 CVMX_ADD_IO_SEG(0x0001180000001578ull)
-#define CVMX_MIO_FUS_WADR \
-	 CVMX_ADD_IO_SEG(0x0001180000001508ull)
-#define CVMX_MIO_NDF_DMA_CFG \
-	 CVMX_ADD_IO_SEG(0x0001180000000168ull)
-#define CVMX_MIO_NDF_DMA_INT \
-	 CVMX_ADD_IO_SEG(0x0001180000000170ull)
-#define CVMX_MIO_NDF_DMA_INT_EN \
-	 CVMX_ADD_IO_SEG(0x0001180000000178ull)
-#define CVMX_MIO_PLL_CTL \
-	 CVMX_ADD_IO_SEG(0x0001180000001448ull)
-#define CVMX_MIO_PLL_SETTING \
-	 CVMX_ADD_IO_SEG(0x0001180000001440ull)
-#define CVMX_MIO_TWSX_INT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001010ull + (((offset) & 1) * 512))
-#define CVMX_MIO_TWSX_SW_TWSI(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001000ull + (((offset) & 1) * 512))
-#define CVMX_MIO_TWSX_SW_TWSI_EXT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001018ull + (((offset) & 1) * 512))
-#define CVMX_MIO_TWSX_TWSI_SW(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001008ull + (((offset) & 1) * 512))
-#define CVMX_MIO_UART2_DLH \
-	 CVMX_ADD_IO_SEG(0x0001180000000488ull)
-#define CVMX_MIO_UART2_DLL \
-	 CVMX_ADD_IO_SEG(0x0001180000000480ull)
-#define CVMX_MIO_UART2_FAR \
-	 CVMX_ADD_IO_SEG(0x0001180000000520ull)
-#define CVMX_MIO_UART2_FCR \
-	 CVMX_ADD_IO_SEG(0x0001180000000450ull)
-#define CVMX_MIO_UART2_HTX \
-	 CVMX_ADD_IO_SEG(0x0001180000000708ull)
-#define CVMX_MIO_UART2_IER \
-	 CVMX_ADD_IO_SEG(0x0001180000000408ull)
-#define CVMX_MIO_UART2_IIR \
-	 CVMX_ADD_IO_SEG(0x0001180000000410ull)
-#define CVMX_MIO_UART2_LCR \
-	 CVMX_ADD_IO_SEG(0x0001180000000418ull)
-#define CVMX_MIO_UART2_LSR \
-	 CVMX_ADD_IO_SEG(0x0001180000000428ull)
-#define CVMX_MIO_UART2_MCR \
-	 CVMX_ADD_IO_SEG(0x0001180000000420ull)
-#define CVMX_MIO_UART2_MSR \
-	 CVMX_ADD_IO_SEG(0x0001180000000430ull)
-#define CVMX_MIO_UART2_RBR \
-	 CVMX_ADD_IO_SEG(0x0001180000000400ull)
-#define CVMX_MIO_UART2_RFL \
-	 CVMX_ADD_IO_SEG(0x0001180000000608ull)
-#define CVMX_MIO_UART2_RFW \
-	 CVMX_ADD_IO_SEG(0x0001180000000530ull)
-#define CVMX_MIO_UART2_SBCR \
-	 CVMX_ADD_IO_SEG(0x0001180000000620ull)
-#define CVMX_MIO_UART2_SCR \
-	 CVMX_ADD_IO_SEG(0x0001180000000438ull)
-#define CVMX_MIO_UART2_SFE \
-	 CVMX_ADD_IO_SEG(0x0001180000000630ull)
-#define CVMX_MIO_UART2_SRR \
-	 CVMX_ADD_IO_SEG(0x0001180000000610ull)
-#define CVMX_MIO_UART2_SRT \
-	 CVMX_ADD_IO_SEG(0x0001180000000638ull)
-#define CVMX_MIO_UART2_SRTS \
-	 CVMX_ADD_IO_SEG(0x0001180000000618ull)
-#define CVMX_MIO_UART2_STT \
-	 CVMX_ADD_IO_SEG(0x0001180000000700ull)
-#define CVMX_MIO_UART2_TFL \
-	 CVMX_ADD_IO_SEG(0x0001180000000600ull)
-#define CVMX_MIO_UART2_TFR \
-	 CVMX_ADD_IO_SEG(0x0001180000000528ull)
-#define CVMX_MIO_UART2_THR \
-	 CVMX_ADD_IO_SEG(0x0001180000000440ull)
-#define CVMX_MIO_UART2_USR \
-	 CVMX_ADD_IO_SEG(0x0001180000000538ull)
-#define CVMX_MIO_UARTX_DLH(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000888ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_DLL(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000880ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_FAR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000920ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_FCR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000850ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_HTX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000B08ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_IER(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000808ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_IIR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000810ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_LCR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000818ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_LSR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000828ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_MCR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000820ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_MSR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000830ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_RBR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000800ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_RFL(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A08ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_RFW(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000930ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SBCR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A20ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SCR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000838ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SFE(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A30ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SRR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A10ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SRT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A38ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_SRTS(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A18ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_STT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000B00ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_TFL(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000A00ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_TFR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000928ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_THR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000840ull + (((offset) & 1) * 1024))
-#define CVMX_MIO_UARTX_USR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000000938ull + (((offset) & 1) * 1024))
+#define CVMX_MIO_BOOT_BIST_STAT (CVMX_ADD_IO_SEG(0x00011800000000F8ull))
+#define CVMX_MIO_BOOT_COMP (CVMX_ADD_IO_SEG(0x00011800000000B8ull))
+#define CVMX_MIO_BOOT_DMA_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001180000000100ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_BOOT_DMA_INTX(offset) (CVMX_ADD_IO_SEG(0x0001180000000138ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_BOOT_DMA_INT_ENX(offset) (CVMX_ADD_IO_SEG(0x0001180000000150ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_BOOT_DMA_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001180000000120ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_BOOT_ERR (CVMX_ADD_IO_SEG(0x00011800000000A0ull))
+#define CVMX_MIO_BOOT_INT (CVMX_ADD_IO_SEG(0x00011800000000A8ull))
+#define CVMX_MIO_BOOT_LOC_ADR (CVMX_ADD_IO_SEG(0x0001180000000090ull))
+#define CVMX_MIO_BOOT_LOC_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001180000000080ull) + ((offset) & 1) * 8)
+#define CVMX_MIO_BOOT_LOC_DAT (CVMX_ADD_IO_SEG(0x0001180000000098ull))
+#define CVMX_MIO_BOOT_PIN_DEFS (CVMX_ADD_IO_SEG(0x00011800000000C0ull))
+#define CVMX_MIO_BOOT_REG_CFGX(offset) (CVMX_ADD_IO_SEG(0x0001180000000000ull) + ((offset) & 7) * 8)
+#define CVMX_MIO_BOOT_REG_TIMX(offset) (CVMX_ADD_IO_SEG(0x0001180000000040ull) + ((offset) & 7) * 8)
+#define CVMX_MIO_BOOT_THR (CVMX_ADD_IO_SEG(0x00011800000000B0ull))
+#define CVMX_MIO_FUS_BNK_DATX(offset) (CVMX_ADD_IO_SEG(0x0001180000001520ull) + ((offset) & 3) * 8)
+#define CVMX_MIO_FUS_DAT0 (CVMX_ADD_IO_SEG(0x0001180000001400ull))
+#define CVMX_MIO_FUS_DAT1 (CVMX_ADD_IO_SEG(0x0001180000001408ull))
+#define CVMX_MIO_FUS_DAT2 (CVMX_ADD_IO_SEG(0x0001180000001410ull))
+#define CVMX_MIO_FUS_DAT3 (CVMX_ADD_IO_SEG(0x0001180000001418ull))
+#define CVMX_MIO_FUS_EMA (CVMX_ADD_IO_SEG(0x0001180000001550ull))
+#define CVMX_MIO_FUS_PDF (CVMX_ADD_IO_SEG(0x0001180000001420ull))
+#define CVMX_MIO_FUS_PLL (CVMX_ADD_IO_SEG(0x0001180000001580ull))
+#define CVMX_MIO_FUS_PROG (CVMX_ADD_IO_SEG(0x0001180000001510ull))
+#define CVMX_MIO_FUS_PROG_TIMES (CVMX_ADD_IO_SEG(0x0001180000001518ull))
+#define CVMX_MIO_FUS_RCMD (CVMX_ADD_IO_SEG(0x0001180000001500ull))
+#define CVMX_MIO_FUS_READ_TIMES (CVMX_ADD_IO_SEG(0x0001180000001570ull))
+#define CVMX_MIO_FUS_REPAIR_RES0 (CVMX_ADD_IO_SEG(0x0001180000001558ull))
+#define CVMX_MIO_FUS_REPAIR_RES1 (CVMX_ADD_IO_SEG(0x0001180000001560ull))
+#define CVMX_MIO_FUS_REPAIR_RES2 (CVMX_ADD_IO_SEG(0x0001180000001568ull))
+#define CVMX_MIO_FUS_SPR_REPAIR_RES (CVMX_ADD_IO_SEG(0x0001180000001548ull))
+#define CVMX_MIO_FUS_SPR_REPAIR_SUM (CVMX_ADD_IO_SEG(0x0001180000001540ull))
+#define CVMX_MIO_FUS_UNLOCK (CVMX_ADD_IO_SEG(0x0001180000001578ull))
+#define CVMX_MIO_FUS_WADR (CVMX_ADD_IO_SEG(0x0001180000001508ull))
+#define CVMX_MIO_GPIO_COMP (CVMX_ADD_IO_SEG(0x00011800000000C8ull))
+#define CVMX_MIO_NDF_DMA_CFG (CVMX_ADD_IO_SEG(0x0001180000000168ull))
+#define CVMX_MIO_NDF_DMA_INT (CVMX_ADD_IO_SEG(0x0001180000000170ull))
+#define CVMX_MIO_NDF_DMA_INT_EN (CVMX_ADD_IO_SEG(0x0001180000000178ull))
+#define CVMX_MIO_PLL_CTL (CVMX_ADD_IO_SEG(0x0001180000001448ull))
+#define CVMX_MIO_PLL_SETTING (CVMX_ADD_IO_SEG(0x0001180000001440ull))
+#define CVMX_MIO_PTP_CLOCK_CFG (CVMX_ADD_IO_SEG(0x0001070000000F00ull))
+#define CVMX_MIO_PTP_CLOCK_COMP (CVMX_ADD_IO_SEG(0x0001070000000F18ull))
+#define CVMX_MIO_PTP_CLOCK_HI (CVMX_ADD_IO_SEG(0x0001070000000F10ull))
+#define CVMX_MIO_PTP_CLOCK_LO (CVMX_ADD_IO_SEG(0x0001070000000F08ull))
+#define CVMX_MIO_PTP_EVT_CNT (CVMX_ADD_IO_SEG(0x0001070000000F28ull))
+#define CVMX_MIO_PTP_TIMESTAMP (CVMX_ADD_IO_SEG(0x0001070000000F20ull))
+#define CVMX_MIO_RST_BOOT (CVMX_ADD_IO_SEG(0x0001180000001600ull))
+#define CVMX_MIO_RST_CFG (CVMX_ADD_IO_SEG(0x0001180000001610ull))
+#define CVMX_MIO_RST_CTLX(offset) (CVMX_ADD_IO_SEG(0x0001180000001618ull) + ((offset) & 1) * 8)
+#define CVMX_MIO_RST_DELAY (CVMX_ADD_IO_SEG(0x0001180000001608ull))
+#define CVMX_MIO_RST_INT (CVMX_ADD_IO_SEG(0x0001180000001628ull))
+#define CVMX_MIO_RST_INT_EN (CVMX_ADD_IO_SEG(0x0001180000001630ull))
+#define CVMX_MIO_TWSX_INT(offset) (CVMX_ADD_IO_SEG(0x0001180000001010ull) + ((offset) & 1) * 512)
+#define CVMX_MIO_TWSX_SW_TWSI(offset) (CVMX_ADD_IO_SEG(0x0001180000001000ull) + ((offset) & 1) * 512)
+#define CVMX_MIO_TWSX_SW_TWSI_EXT(offset) (CVMX_ADD_IO_SEG(0x0001180000001018ull) + ((offset) & 1) * 512)
+#define CVMX_MIO_TWSX_TWSI_SW(offset) (CVMX_ADD_IO_SEG(0x0001180000001008ull) + ((offset) & 1) * 512)
+#define CVMX_MIO_UART2_DLH (CVMX_ADD_IO_SEG(0x0001180000000488ull))
+#define CVMX_MIO_UART2_DLL (CVMX_ADD_IO_SEG(0x0001180000000480ull))
+#define CVMX_MIO_UART2_FAR (CVMX_ADD_IO_SEG(0x0001180000000520ull))
+#define CVMX_MIO_UART2_FCR (CVMX_ADD_IO_SEG(0x0001180000000450ull))
+#define CVMX_MIO_UART2_HTX (CVMX_ADD_IO_SEG(0x0001180000000708ull))
+#define CVMX_MIO_UART2_IER (CVMX_ADD_IO_SEG(0x0001180000000408ull))
+#define CVMX_MIO_UART2_IIR (CVMX_ADD_IO_SEG(0x0001180000000410ull))
+#define CVMX_MIO_UART2_LCR (CVMX_ADD_IO_SEG(0x0001180000000418ull))
+#define CVMX_MIO_UART2_LSR (CVMX_ADD_IO_SEG(0x0001180000000428ull))
+#define CVMX_MIO_UART2_MCR (CVMX_ADD_IO_SEG(0x0001180000000420ull))
+#define CVMX_MIO_UART2_MSR (CVMX_ADD_IO_SEG(0x0001180000000430ull))
+#define CVMX_MIO_UART2_RBR (CVMX_ADD_IO_SEG(0x0001180000000400ull))
+#define CVMX_MIO_UART2_RFL (CVMX_ADD_IO_SEG(0x0001180000000608ull))
+#define CVMX_MIO_UART2_RFW (CVMX_ADD_IO_SEG(0x0001180000000530ull))
+#define CVMX_MIO_UART2_SBCR (CVMX_ADD_IO_SEG(0x0001180000000620ull))
+#define CVMX_MIO_UART2_SCR (CVMX_ADD_IO_SEG(0x0001180000000438ull))
+#define CVMX_MIO_UART2_SFE (CVMX_ADD_IO_SEG(0x0001180000000630ull))
+#define CVMX_MIO_UART2_SRR (CVMX_ADD_IO_SEG(0x0001180000000610ull))
+#define CVMX_MIO_UART2_SRT (CVMX_ADD_IO_SEG(0x0001180000000638ull))
+#define CVMX_MIO_UART2_SRTS (CVMX_ADD_IO_SEG(0x0001180000000618ull))
+#define CVMX_MIO_UART2_STT (CVMX_ADD_IO_SEG(0x0001180000000700ull))
+#define CVMX_MIO_UART2_TFL (CVMX_ADD_IO_SEG(0x0001180000000600ull))
+#define CVMX_MIO_UART2_TFR (CVMX_ADD_IO_SEG(0x0001180000000528ull))
+#define CVMX_MIO_UART2_THR (CVMX_ADD_IO_SEG(0x0001180000000440ull))
+#define CVMX_MIO_UART2_USR (CVMX_ADD_IO_SEG(0x0001180000000538ull))
+#define CVMX_MIO_UARTX_DLH(offset) (CVMX_ADD_IO_SEG(0x0001180000000888ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_DLL(offset) (CVMX_ADD_IO_SEG(0x0001180000000880ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_FAR(offset) (CVMX_ADD_IO_SEG(0x0001180000000920ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_FCR(offset) (CVMX_ADD_IO_SEG(0x0001180000000850ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_HTX(offset) (CVMX_ADD_IO_SEG(0x0001180000000B08ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_IER(offset) (CVMX_ADD_IO_SEG(0x0001180000000808ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_IIR(offset) (CVMX_ADD_IO_SEG(0x0001180000000810ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_LCR(offset) (CVMX_ADD_IO_SEG(0x0001180000000818ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_LSR(offset) (CVMX_ADD_IO_SEG(0x0001180000000828ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_MCR(offset) (CVMX_ADD_IO_SEG(0x0001180000000820ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_MSR(offset) (CVMX_ADD_IO_SEG(0x0001180000000830ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_RBR(offset) (CVMX_ADD_IO_SEG(0x0001180000000800ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_RFL(offset) (CVMX_ADD_IO_SEG(0x0001180000000A08ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_RFW(offset) (CVMX_ADD_IO_SEG(0x0001180000000930ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SBCR(offset) (CVMX_ADD_IO_SEG(0x0001180000000A20ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SCR(offset) (CVMX_ADD_IO_SEG(0x0001180000000838ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SFE(offset) (CVMX_ADD_IO_SEG(0x0001180000000A30ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SRR(offset) (CVMX_ADD_IO_SEG(0x0001180000000A10ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SRT(offset) (CVMX_ADD_IO_SEG(0x0001180000000A38ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_SRTS(offset) (CVMX_ADD_IO_SEG(0x0001180000000A18ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_STT(offset) (CVMX_ADD_IO_SEG(0x0001180000000B00ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_TFL(offset) (CVMX_ADD_IO_SEG(0x0001180000000A00ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_TFR(offset) (CVMX_ADD_IO_SEG(0x0001180000000928ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_THR(offset) (CVMX_ADD_IO_SEG(0x0001180000000840ull) + ((offset) & 1) * 1024)
+#define CVMX_MIO_UARTX_USR(offset) (CVMX_ADD_IO_SEG(0x0001180000000938ull) + ((offset) & 1) * 1024)
 
 union cvmx_mio_boot_bist_stat {
 	uint64_t u64;
 	struct cvmx_mio_boot_bist_stat_s {
-		uint64_t reserved_2_63:62;
-		uint64_t loc:1;
-		uint64_t ncbi:1;
+		uint64_t reserved_0_63:64;
 	} s;
 	struct cvmx_mio_boot_bist_stat_cn30xx {
 		uint64_t reserved_4_63:60;
@@ -257,20 +183,33 @@
 	struct cvmx_mio_boot_bist_stat_cn52xxp1 cn56xxp1;
 	struct cvmx_mio_boot_bist_stat_cn38xx cn58xx;
 	struct cvmx_mio_boot_bist_stat_cn38xx cn58xxp1;
+	struct cvmx_mio_boot_bist_stat_cn63xx {
+		uint64_t reserved_9_63:55;
+		uint64_t stat:9;
+	} cn63xx;
+	struct cvmx_mio_boot_bist_stat_cn63xx cn63xxp1;
 };
 
 union cvmx_mio_boot_comp {
 	uint64_t u64;
 	struct cvmx_mio_boot_comp_s {
+		uint64_t reserved_0_63:64;
+	} s;
+	struct cvmx_mio_boot_comp_cn50xx {
 		uint64_t reserved_10_63:54;
 		uint64_t pctl:5;
 		uint64_t nctl:5;
-	} s;
-	struct cvmx_mio_boot_comp_s cn50xx;
-	struct cvmx_mio_boot_comp_s cn52xx;
-	struct cvmx_mio_boot_comp_s cn52xxp1;
-	struct cvmx_mio_boot_comp_s cn56xx;
-	struct cvmx_mio_boot_comp_s cn56xxp1;
+	} cn50xx;
+	struct cvmx_mio_boot_comp_cn50xx cn52xx;
+	struct cvmx_mio_boot_comp_cn50xx cn52xxp1;
+	struct cvmx_mio_boot_comp_cn50xx cn56xx;
+	struct cvmx_mio_boot_comp_cn50xx cn56xxp1;
+	struct cvmx_mio_boot_comp_cn63xx {
+		uint64_t reserved_12_63:52;
+		uint64_t pctl:6;
+		uint64_t nctl:6;
+	} cn63xx;
+	struct cvmx_mio_boot_comp_cn63xx cn63xxp1;
 };
 
 union cvmx_mio_boot_dma_cfgx {
@@ -291,6 +230,8 @@
 	struct cvmx_mio_boot_dma_cfgx_s cn52xxp1;
 	struct cvmx_mio_boot_dma_cfgx_s cn56xx;
 	struct cvmx_mio_boot_dma_cfgx_s cn56xxp1;
+	struct cvmx_mio_boot_dma_cfgx_s cn63xx;
+	struct cvmx_mio_boot_dma_cfgx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_dma_intx {
@@ -304,6 +245,8 @@
 	struct cvmx_mio_boot_dma_intx_s cn52xxp1;
 	struct cvmx_mio_boot_dma_intx_s cn56xx;
 	struct cvmx_mio_boot_dma_intx_s cn56xxp1;
+	struct cvmx_mio_boot_dma_intx_s cn63xx;
+	struct cvmx_mio_boot_dma_intx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_dma_int_enx {
@@ -317,6 +260,8 @@
 	struct cvmx_mio_boot_dma_int_enx_s cn52xxp1;
 	struct cvmx_mio_boot_dma_int_enx_s cn56xx;
 	struct cvmx_mio_boot_dma_int_enx_s cn56xxp1;
+	struct cvmx_mio_boot_dma_int_enx_s cn63xx;
+	struct cvmx_mio_boot_dma_int_enx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_dma_timx {
@@ -342,6 +287,8 @@
 	struct cvmx_mio_boot_dma_timx_s cn52xxp1;
 	struct cvmx_mio_boot_dma_timx_s cn56xx;
 	struct cvmx_mio_boot_dma_timx_s cn56xxp1;
+	struct cvmx_mio_boot_dma_timx_s cn63xx;
+	struct cvmx_mio_boot_dma_timx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_err {
@@ -362,6 +309,8 @@
 	struct cvmx_mio_boot_err_s cn56xxp1;
 	struct cvmx_mio_boot_err_s cn58xx;
 	struct cvmx_mio_boot_err_s cn58xxp1;
+	struct cvmx_mio_boot_err_s cn63xx;
+	struct cvmx_mio_boot_err_s cn63xxp1;
 };
 
 union cvmx_mio_boot_int {
@@ -382,6 +331,8 @@
 	struct cvmx_mio_boot_int_s cn56xxp1;
 	struct cvmx_mio_boot_int_s cn58xx;
 	struct cvmx_mio_boot_int_s cn58xxp1;
+	struct cvmx_mio_boot_int_s cn63xx;
+	struct cvmx_mio_boot_int_s cn63xxp1;
 };
 
 union cvmx_mio_boot_loc_adr {
@@ -402,6 +353,8 @@
 	struct cvmx_mio_boot_loc_adr_s cn56xxp1;
 	struct cvmx_mio_boot_loc_adr_s cn58xx;
 	struct cvmx_mio_boot_loc_adr_s cn58xxp1;
+	struct cvmx_mio_boot_loc_adr_s cn63xx;
+	struct cvmx_mio_boot_loc_adr_s cn63xxp1;
 };
 
 union cvmx_mio_boot_loc_cfgx {
@@ -424,6 +377,8 @@
 	struct cvmx_mio_boot_loc_cfgx_s cn56xxp1;
 	struct cvmx_mio_boot_loc_cfgx_s cn58xx;
 	struct cvmx_mio_boot_loc_cfgx_s cn58xxp1;
+	struct cvmx_mio_boot_loc_cfgx_s cn63xx;
+	struct cvmx_mio_boot_loc_cfgx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_loc_dat {
@@ -442,6 +397,8 @@
 	struct cvmx_mio_boot_loc_dat_s cn56xxp1;
 	struct cvmx_mio_boot_loc_dat_s cn58xx;
 	struct cvmx_mio_boot_loc_dat_s cn58xxp1;
+	struct cvmx_mio_boot_loc_dat_s cn63xx;
+	struct cvmx_mio_boot_loc_dat_s cn63xxp1;
 };
 
 union cvmx_mio_boot_pin_defs {
@@ -478,6 +435,8 @@
 		uint64_t term:2;
 		uint64_t reserved_0_8:9;
 	} cn56xx;
+	struct cvmx_mio_boot_pin_defs_cn52xx cn63xx;
+	struct cvmx_mio_boot_pin_defs_cn52xx cn63xxp1;
 };
 
 union cvmx_mio_boot_reg_cfgx {
@@ -539,6 +498,8 @@
 	struct cvmx_mio_boot_reg_cfgx_s cn56xxp1;
 	struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xx;
 	struct cvmx_mio_boot_reg_cfgx_cn30xx cn58xxp1;
+	struct cvmx_mio_boot_reg_cfgx_s cn63xx;
+	struct cvmx_mio_boot_reg_cfgx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_reg_timx {
@@ -583,6 +544,8 @@
 	struct cvmx_mio_boot_reg_timx_s cn56xxp1;
 	struct cvmx_mio_boot_reg_timx_s cn58xx;
 	struct cvmx_mio_boot_reg_timx_s cn58xxp1;
+	struct cvmx_mio_boot_reg_timx_s cn63xx;
+	struct cvmx_mio_boot_reg_timx_s cn63xxp1;
 };
 
 union cvmx_mio_boot_thr {
@@ -611,6 +574,8 @@
 	struct cvmx_mio_boot_thr_s cn56xxp1;
 	struct cvmx_mio_boot_thr_cn30xx cn58xx;
 	struct cvmx_mio_boot_thr_cn30xx cn58xxp1;
+	struct cvmx_mio_boot_thr_s cn63xx;
+	struct cvmx_mio_boot_thr_s cn63xxp1;
 };
 
 union cvmx_mio_fus_bnk_datx {
@@ -625,6 +590,8 @@
 	struct cvmx_mio_fus_bnk_datx_s cn56xxp1;
 	struct cvmx_mio_fus_bnk_datx_s cn58xx;
 	struct cvmx_mio_fus_bnk_datx_s cn58xxp1;
+	struct cvmx_mio_fus_bnk_datx_s cn63xx;
+	struct cvmx_mio_fus_bnk_datx_s cn63xxp1;
 };
 
 union cvmx_mio_fus_dat0 {
@@ -644,6 +611,8 @@
 	struct cvmx_mio_fus_dat0_s cn56xxp1;
 	struct cvmx_mio_fus_dat0_s cn58xx;
 	struct cvmx_mio_fus_dat0_s cn58xxp1;
+	struct cvmx_mio_fus_dat0_s cn63xx;
+	struct cvmx_mio_fus_dat0_s cn63xxp1;
 };
 
 union cvmx_mio_fus_dat1 {
@@ -663,12 +632,15 @@
 	struct cvmx_mio_fus_dat1_s cn56xxp1;
 	struct cvmx_mio_fus_dat1_s cn58xx;
 	struct cvmx_mio_fus_dat1_s cn58xxp1;
+	struct cvmx_mio_fus_dat1_s cn63xx;
+	struct cvmx_mio_fus_dat1_s cn63xxp1;
 };
 
 union cvmx_mio_fus_dat2 {
 	uint64_t u64;
 	struct cvmx_mio_fus_dat2_s {
-		uint64_t reserved_34_63:30;
+		uint64_t reserved_35_63:29;
+		uint64_t dorm_crypto:1;
 		uint64_t fus318:1;
 		uint64_t raid_en:1;
 		uint64_t reserved_30_31:2;
@@ -775,14 +747,38 @@
 		uint64_t pp_dis:16;
 	} cn58xx;
 	struct cvmx_mio_fus_dat2_cn58xx cn58xxp1;
+	struct cvmx_mio_fus_dat2_cn63xx {
+		uint64_t reserved_35_63:29;
+		uint64_t dorm_crypto:1;
+		uint64_t fus318:1;
+		uint64_t raid_en:1;
+		uint64_t reserved_29_31:3;
+		uint64_t nodfa_cp2:1;
+		uint64_t nomul:1;
+		uint64_t nocrypto:1;
+		uint64_t reserved_24_25:2;
+		uint64_t chip_id:8;
+		uint64_t reserved_6_15:10;
+		uint64_t pp_dis:6;
+	} cn63xx;
+	struct cvmx_mio_fus_dat2_cn63xx cn63xxp1;
 };
 
 union cvmx_mio_fus_dat3 {
 	uint64_t u64;
 	struct cvmx_mio_fus_dat3_s {
-		uint64_t reserved_32_63:32;
+		uint64_t reserved_58_63:6;
+		uint64_t pll_ctl:10;
+		uint64_t dfa_info_dte:3;
+		uint64_t dfa_info_clm:4;
+		uint64_t reserved_40_40:1;
+		uint64_t ema:2;
+		uint64_t efus_lck_rsv:1;
+		uint64_t efus_lck_man:1;
+		uint64_t pll_half_dis:1;
+		uint64_t l2c_crip:3;
 		uint64_t pll_div4:1;
-		uint64_t zip_crip:2;
+		uint64_t reserved_29_30:2;
 		uint64_t bar2_en:1;
 		uint64_t efus_lck:1;
 		uint64_t efus_ign:1;
@@ -801,7 +797,17 @@
 		uint64_t nodfa_dte:1;
 		uint64_t icache:24;
 	} cn30xx;
-	struct cvmx_mio_fus_dat3_s cn31xx;
+	struct cvmx_mio_fus_dat3_cn31xx {
+		uint64_t reserved_32_63:32;
+		uint64_t pll_div4:1;
+		uint64_t zip_crip:2;
+		uint64_t bar2_en:1;
+		uint64_t efus_lck:1;
+		uint64_t efus_ign:1;
+		uint64_t nozip:1;
+		uint64_t nodfa_dte:1;
+		uint64_t icache:24;
+	} cn31xx;
 	struct cvmx_mio_fus_dat3_cn38xx {
 		uint64_t reserved_31_63:33;
 		uint64_t zip_crip:2;
@@ -828,6 +834,27 @@
 	struct cvmx_mio_fus_dat3_cn38xx cn56xxp1;
 	struct cvmx_mio_fus_dat3_cn38xx cn58xx;
 	struct cvmx_mio_fus_dat3_cn38xx cn58xxp1;
+	struct cvmx_mio_fus_dat3_cn63xx {
+		uint64_t reserved_58_63:6;
+		uint64_t pll_ctl:10;
+		uint64_t dfa_info_dte:3;
+		uint64_t dfa_info_clm:4;
+		uint64_t reserved_40_40:1;
+		uint64_t ema:2;
+		uint64_t efus_lck_rsv:1;
+		uint64_t efus_lck_man:1;
+		uint64_t pll_half_dis:1;
+		uint64_t l2c_crip:3;
+		uint64_t reserved_31_31:1;
+		uint64_t zip_info:2;
+		uint64_t bar2_en:1;
+		uint64_t efus_lck:1;
+		uint64_t efus_ign:1;
+		uint64_t nozip:1;
+		uint64_t nodfa_dte:1;
+		uint64_t reserved_0_23:24;
+	} cn63xx;
+	struct cvmx_mio_fus_dat3_cn63xx cn63xxp1;
 };
 
 union cvmx_mio_fus_ema {
@@ -848,6 +875,8 @@
 		uint64_t ema:2;
 	} cn58xx;
 	struct cvmx_mio_fus_ema_cn58xx cn58xxp1;
+	struct cvmx_mio_fus_ema_s cn63xx;
+	struct cvmx_mio_fus_ema_s cn63xxp1;
 };
 
 union cvmx_mio_fus_pdf {
@@ -861,60 +890,96 @@
 	struct cvmx_mio_fus_pdf_s cn56xx;
 	struct cvmx_mio_fus_pdf_s cn56xxp1;
 	struct cvmx_mio_fus_pdf_s cn58xx;
+	struct cvmx_mio_fus_pdf_s cn63xx;
+	struct cvmx_mio_fus_pdf_s cn63xxp1;
 };
 
 union cvmx_mio_fus_pll {
 	uint64_t u64;
 	struct cvmx_mio_fus_pll_s {
-		uint64_t reserved_2_63:62;
+		uint64_t reserved_8_63:56;
+		uint64_t c_cout_rst:1;
+		uint64_t c_cout_sel:2;
+		uint64_t pnr_cout_rst:1;
+		uint64_t pnr_cout_sel:2;
 		uint64_t rfslip:1;
 		uint64_t fbslip:1;
 	} s;
-	struct cvmx_mio_fus_pll_s cn50xx;
-	struct cvmx_mio_fus_pll_s cn52xx;
-	struct cvmx_mio_fus_pll_s cn52xxp1;
-	struct cvmx_mio_fus_pll_s cn56xx;
-	struct cvmx_mio_fus_pll_s cn56xxp1;
-	struct cvmx_mio_fus_pll_s cn58xx;
-	struct cvmx_mio_fus_pll_s cn58xxp1;
+	struct cvmx_mio_fus_pll_cn50xx {
+		uint64_t reserved_2_63:62;
+		uint64_t rfslip:1;
+		uint64_t fbslip:1;
+	} cn50xx;
+	struct cvmx_mio_fus_pll_cn50xx cn52xx;
+	struct cvmx_mio_fus_pll_cn50xx cn52xxp1;
+	struct cvmx_mio_fus_pll_cn50xx cn56xx;
+	struct cvmx_mio_fus_pll_cn50xx cn56xxp1;
+	struct cvmx_mio_fus_pll_cn50xx cn58xx;
+	struct cvmx_mio_fus_pll_cn50xx cn58xxp1;
+	struct cvmx_mio_fus_pll_s cn63xx;
+	struct cvmx_mio_fus_pll_s cn63xxp1;
 };
 
 union cvmx_mio_fus_prog {
 	uint64_t u64;
 	struct cvmx_mio_fus_prog_s {
-		uint64_t reserved_1_63:63;
+		uint64_t reserved_2_63:62;
+		uint64_t soft:1;
 		uint64_t prog:1;
 	} s;
-	struct cvmx_mio_fus_prog_s cn30xx;
-	struct cvmx_mio_fus_prog_s cn31xx;
-	struct cvmx_mio_fus_prog_s cn38xx;
-	struct cvmx_mio_fus_prog_s cn38xxp2;
-	struct cvmx_mio_fus_prog_s cn50xx;
-	struct cvmx_mio_fus_prog_s cn52xx;
-	struct cvmx_mio_fus_prog_s cn52xxp1;
-	struct cvmx_mio_fus_prog_s cn56xx;
-	struct cvmx_mio_fus_prog_s cn56xxp1;
-	struct cvmx_mio_fus_prog_s cn58xx;
-	struct cvmx_mio_fus_prog_s cn58xxp1;
+	struct cvmx_mio_fus_prog_cn30xx {
+		uint64_t reserved_1_63:63;
+		uint64_t prog:1;
+	} cn30xx;
+	struct cvmx_mio_fus_prog_cn30xx cn31xx;
+	struct cvmx_mio_fus_prog_cn30xx cn38xx;
+	struct cvmx_mio_fus_prog_cn30xx cn38xxp2;
+	struct cvmx_mio_fus_prog_cn30xx cn50xx;
+	struct cvmx_mio_fus_prog_cn30xx cn52xx;
+	struct cvmx_mio_fus_prog_cn30xx cn52xxp1;
+	struct cvmx_mio_fus_prog_cn30xx cn56xx;
+	struct cvmx_mio_fus_prog_cn30xx cn56xxp1;
+	struct cvmx_mio_fus_prog_cn30xx cn58xx;
+	struct cvmx_mio_fus_prog_cn30xx cn58xxp1;
+	struct cvmx_mio_fus_prog_s cn63xx;
+	struct cvmx_mio_fus_prog_s cn63xxp1;
 };
 
 union cvmx_mio_fus_prog_times {
 	uint64_t u64;
 	struct cvmx_mio_fus_prog_times_s {
+		uint64_t reserved_35_63:29;
+		uint64_t vgate_pin:1;
+		uint64_t fsrc_pin:1;
+		uint64_t prog_pin:1;
+		uint64_t reserved_6_31:26;
+		uint64_t setup:6;
+	} s;
+	struct cvmx_mio_fus_prog_times_cn50xx {
 		uint64_t reserved_33_63:31;
 		uint64_t prog_pin:1;
 		uint64_t out:8;
 		uint64_t sclk_lo:4;
 		uint64_t sclk_hi:12;
 		uint64_t setup:8;
-	} s;
-	struct cvmx_mio_fus_prog_times_s cn50xx;
-	struct cvmx_mio_fus_prog_times_s cn52xx;
-	struct cvmx_mio_fus_prog_times_s cn52xxp1;
-	struct cvmx_mio_fus_prog_times_s cn56xx;
-	struct cvmx_mio_fus_prog_times_s cn56xxp1;
-	struct cvmx_mio_fus_prog_times_s cn58xx;
-	struct cvmx_mio_fus_prog_times_s cn58xxp1;
+	} cn50xx;
+	struct cvmx_mio_fus_prog_times_cn50xx cn52xx;
+	struct cvmx_mio_fus_prog_times_cn50xx cn52xxp1;
+	struct cvmx_mio_fus_prog_times_cn50xx cn56xx;
+	struct cvmx_mio_fus_prog_times_cn50xx cn56xxp1;
+	struct cvmx_mio_fus_prog_times_cn50xx cn58xx;
+	struct cvmx_mio_fus_prog_times_cn50xx cn58xxp1;
+	struct cvmx_mio_fus_prog_times_cn63xx {
+		uint64_t reserved_35_63:29;
+		uint64_t vgate_pin:1;
+		uint64_t fsrc_pin:1;
+		uint64_t prog_pin:1;
+		uint64_t out:7;
+		uint64_t sclk_lo:4;
+		uint64_t sclk_hi:15;
+		uint64_t setup:6;
+	} cn63xx;
+	struct cvmx_mio_fus_prog_times_cn63xx cn63xxp1;
 };
 
 union cvmx_mio_fus_rcmd {
@@ -948,6 +1013,57 @@
 	struct cvmx_mio_fus_rcmd_s cn56xxp1;
 	struct cvmx_mio_fus_rcmd_cn30xx cn58xx;
 	struct cvmx_mio_fus_rcmd_cn30xx cn58xxp1;
+	struct cvmx_mio_fus_rcmd_s cn63xx;
+	struct cvmx_mio_fus_rcmd_s cn63xxp1;
+};
+
+union cvmx_mio_fus_read_times {
+	uint64_t u64;
+	struct cvmx_mio_fus_read_times_s {
+		uint64_t reserved_26_63:38;
+		uint64_t sch:4;
+		uint64_t fsh:4;
+		uint64_t prh:4;
+		uint64_t sdh:4;
+		uint64_t setup:10;
+	} s;
+	struct cvmx_mio_fus_read_times_s cn63xx;
+	struct cvmx_mio_fus_read_times_s cn63xxp1;
+};
+
+union cvmx_mio_fus_repair_res0 {
+	uint64_t u64;
+	struct cvmx_mio_fus_repair_res0_s {
+		uint64_t reserved_55_63:9;
+		uint64_t too_many:1;
+		uint64_t repair2:18;
+		uint64_t repair1:18;
+		uint64_t repair0:18;
+	} s;
+	struct cvmx_mio_fus_repair_res0_s cn63xx;
+	struct cvmx_mio_fus_repair_res0_s cn63xxp1;
+};
+
+union cvmx_mio_fus_repair_res1 {
+	uint64_t u64;
+	struct cvmx_mio_fus_repair_res1_s {
+		uint64_t reserved_54_63:10;
+		uint64_t repair5:18;
+		uint64_t repair4:18;
+		uint64_t repair3:18;
+	} s;
+	struct cvmx_mio_fus_repair_res1_s cn63xx;
+	struct cvmx_mio_fus_repair_res1_s cn63xxp1;
+};
+
+union cvmx_mio_fus_repair_res2 {
+	uint64_t u64;
+	struct cvmx_mio_fus_repair_res2_s {
+		uint64_t reserved_18_63:46;
+		uint64_t repair6:18;
+	} s;
+	struct cvmx_mio_fus_repair_res2_s cn63xx;
+	struct cvmx_mio_fus_repair_res2_s cn63xxp1;
 };
 
 union cvmx_mio_fus_spr_repair_res {
@@ -968,6 +1084,8 @@
 	struct cvmx_mio_fus_spr_repair_res_s cn56xxp1;
 	struct cvmx_mio_fus_spr_repair_res_s cn58xx;
 	struct cvmx_mio_fus_spr_repair_res_s cn58xxp1;
+	struct cvmx_mio_fus_spr_repair_res_s cn63xx;
+	struct cvmx_mio_fus_spr_repair_res_s cn63xxp1;
 };
 
 union cvmx_mio_fus_spr_repair_sum {
@@ -986,6 +1104,8 @@
 	struct cvmx_mio_fus_spr_repair_sum_s cn56xxp1;
 	struct cvmx_mio_fus_spr_repair_sum_s cn58xx;
 	struct cvmx_mio_fus_spr_repair_sum_s cn58xxp1;
+	struct cvmx_mio_fus_spr_repair_sum_s cn63xx;
+	struct cvmx_mio_fus_spr_repair_sum_s cn63xxp1;
 };
 
 union cvmx_mio_fus_unlock {
@@ -1021,6 +1141,22 @@
 	struct cvmx_mio_fus_wadr_cn52xx cn56xxp1;
 	struct cvmx_mio_fus_wadr_cn50xx cn58xx;
 	struct cvmx_mio_fus_wadr_cn50xx cn58xxp1;
+	struct cvmx_mio_fus_wadr_cn63xx {
+		uint64_t reserved_4_63:60;
+		uint64_t addr:4;
+	} cn63xx;
+	struct cvmx_mio_fus_wadr_cn63xx cn63xxp1;
+};
+
+union cvmx_mio_gpio_comp {
+	uint64_t u64;
+	struct cvmx_mio_gpio_comp_s {
+		uint64_t reserved_12_63:52;
+		uint64_t pctl:6;
+		uint64_t nctl:6;
+	} s;
+	struct cvmx_mio_gpio_comp_s cn63xx;
+	struct cvmx_mio_gpio_comp_s cn63xxp1;
 };
 
 union cvmx_mio_ndf_dma_cfg {
@@ -1038,6 +1174,8 @@
 		uint64_t adr:36;
 	} s;
 	struct cvmx_mio_ndf_dma_cfg_s cn52xx;
+	struct cvmx_mio_ndf_dma_cfg_s cn63xx;
+	struct cvmx_mio_ndf_dma_cfg_s cn63xxp1;
 };
 
 union cvmx_mio_ndf_dma_int {
@@ -1047,6 +1185,8 @@
 		uint64_t done:1;
 	} s;
 	struct cvmx_mio_ndf_dma_int_s cn52xx;
+	struct cvmx_mio_ndf_dma_int_s cn63xx;
+	struct cvmx_mio_ndf_dma_int_s cn63xxp1;
 };
 
 union cvmx_mio_ndf_dma_int_en {
@@ -1056,6 +1196,8 @@
 		uint64_t done:1;
 	} s;
 	struct cvmx_mio_ndf_dma_int_en_s cn52xx;
+	struct cvmx_mio_ndf_dma_int_en_s cn63xx;
+	struct cvmx_mio_ndf_dma_int_en_s cn63xxp1;
 };
 
 union cvmx_mio_pll_ctl {
@@ -1078,6 +1220,173 @@
 	struct cvmx_mio_pll_setting_s cn31xx;
 };
 
+union cvmx_mio_ptp_clock_cfg {
+	uint64_t u64;
+	struct cvmx_mio_ptp_clock_cfg_s {
+		uint64_t reserved_24_63:40;
+		uint64_t evcnt_in:6;
+		uint64_t evcnt_edge:1;
+		uint64_t evcnt_en:1;
+		uint64_t tstmp_in:6;
+		uint64_t tstmp_edge:1;
+		uint64_t tstmp_en:1;
+		uint64_t ext_clk_in:6;
+		uint64_t ext_clk_en:1;
+		uint64_t ptp_en:1;
+	} s;
+	struct cvmx_mio_ptp_clock_cfg_s cn63xx;
+	struct cvmx_mio_ptp_clock_cfg_s cn63xxp1;
+};
+
+union cvmx_mio_ptp_clock_comp {
+	uint64_t u64;
+	struct cvmx_mio_ptp_clock_comp_s {
+		uint64_t nanosec:32;
+		uint64_t frnanosec:32;
+	} s;
+	struct cvmx_mio_ptp_clock_comp_s cn63xx;
+	struct cvmx_mio_ptp_clock_comp_s cn63xxp1;
+};
+
+union cvmx_mio_ptp_clock_hi {
+	uint64_t u64;
+	struct cvmx_mio_ptp_clock_hi_s {
+		uint64_t nanosec:64;
+	} s;
+	struct cvmx_mio_ptp_clock_hi_s cn63xx;
+	struct cvmx_mio_ptp_clock_hi_s cn63xxp1;
+};
+
+union cvmx_mio_ptp_clock_lo {
+	uint64_t u64;
+	struct cvmx_mio_ptp_clock_lo_s {
+		uint64_t reserved_32_63:32;
+		uint64_t frnanosec:32;
+	} s;
+	struct cvmx_mio_ptp_clock_lo_s cn63xx;
+	struct cvmx_mio_ptp_clock_lo_s cn63xxp1;
+};
+
+union cvmx_mio_ptp_evt_cnt {
+	uint64_t u64;
+	struct cvmx_mio_ptp_evt_cnt_s {
+		uint64_t cntr:64;
+	} s;
+	struct cvmx_mio_ptp_evt_cnt_s cn63xx;
+	struct cvmx_mio_ptp_evt_cnt_s cn63xxp1;
+};
+
+union cvmx_mio_ptp_timestamp {
+	uint64_t u64;
+	struct cvmx_mio_ptp_timestamp_s {
+		uint64_t nanosec:64;
+	} s;
+	struct cvmx_mio_ptp_timestamp_s cn63xx;
+	struct cvmx_mio_ptp_timestamp_s cn63xxp1;
+};
+
+union cvmx_mio_rst_boot {
+	uint64_t u64;
+	struct cvmx_mio_rst_boot_s {
+		uint64_t reserved_36_63:28;
+		uint64_t c_mul:6;
+		uint64_t pnr_mul:6;
+		uint64_t qlm2_spd:4;
+		uint64_t qlm1_spd:4;
+		uint64_t qlm0_spd:4;
+		uint64_t lboot:10;
+		uint64_t rboot:1;
+		uint64_t rboot_pin:1;
+	} s;
+	struct cvmx_mio_rst_boot_s cn63xx;
+	struct cvmx_mio_rst_boot_s cn63xxp1;
+};
+
+union cvmx_mio_rst_cfg {
+	uint64_t u64;
+	struct cvmx_mio_rst_cfg_s {
+		uint64_t bist_delay:58;
+		uint64_t reserved_3_5:3;
+		uint64_t cntl_clr_bist:1;
+		uint64_t warm_clr_bist:1;
+		uint64_t soft_clr_bist:1;
+	} s;
+	struct cvmx_mio_rst_cfg_s cn63xx;
+	struct cvmx_mio_rst_cfg_cn63xxp1 {
+		uint64_t bist_delay:58;
+		uint64_t reserved_2_5:4;
+		uint64_t warm_clr_bist:1;
+		uint64_t soft_clr_bist:1;
+	} cn63xxp1;
+};
+
+union cvmx_mio_rst_ctlx {
+	uint64_t u64;
+	struct cvmx_mio_rst_ctlx_s {
+		uint64_t reserved_10_63:54;
+		uint64_t prst_link:1;
+		uint64_t rst_done:1;
+		uint64_t rst_link:1;
+		uint64_t host_mode:1;
+		uint64_t prtmode:2;
+		uint64_t rst_drv:1;
+		uint64_t rst_rcv:1;
+		uint64_t rst_chip:1;
+		uint64_t rst_val:1;
+	} s;
+	struct cvmx_mio_rst_ctlx_s cn63xx;
+	struct cvmx_mio_rst_ctlx_cn63xxp1 {
+		uint64_t reserved_9_63:55;
+		uint64_t rst_done:1;
+		uint64_t rst_link:1;
+		uint64_t host_mode:1;
+		uint64_t prtmode:2;
+		uint64_t rst_drv:1;
+		uint64_t rst_rcv:1;
+		uint64_t rst_chip:1;
+		uint64_t rst_val:1;
+	} cn63xxp1;
+};
+
+union cvmx_mio_rst_delay {
+	uint64_t u64;
+	struct cvmx_mio_rst_delay_s {
+		uint64_t reserved_32_63:32;
+		uint64_t soft_rst_dly:16;
+		uint64_t warm_rst_dly:16;
+	} s;
+	struct cvmx_mio_rst_delay_s cn63xx;
+	struct cvmx_mio_rst_delay_s cn63xxp1;
+};
+
+union cvmx_mio_rst_int {
+	uint64_t u64;
+	struct cvmx_mio_rst_int_s {
+		uint64_t reserved_10_63:54;
+		uint64_t perst1:1;
+		uint64_t perst0:1;
+		uint64_t reserved_2_7:6;
+		uint64_t rst_link1:1;
+		uint64_t rst_link0:1;
+	} s;
+	struct cvmx_mio_rst_int_s cn63xx;
+	struct cvmx_mio_rst_int_s cn63xxp1;
+};
+
+union cvmx_mio_rst_int_en {
+	uint64_t u64;
+	struct cvmx_mio_rst_int_en_s {
+		uint64_t reserved_10_63:54;
+		uint64_t perst1:1;
+		uint64_t perst0:1;
+		uint64_t reserved_2_7:6;
+		uint64_t rst_link1:1;
+		uint64_t rst_link0:1;
+	} s;
+	struct cvmx_mio_rst_int_en_s cn63xx;
+	struct cvmx_mio_rst_int_en_s cn63xxp1;
+};
+
 union cvmx_mio_twsx_int {
 	uint64_t u64;
 	struct cvmx_mio_twsx_int_s {
@@ -1115,6 +1424,8 @@
 	struct cvmx_mio_twsx_int_s cn56xxp1;
 	struct cvmx_mio_twsx_int_s cn58xx;
 	struct cvmx_mio_twsx_int_s cn58xxp1;
+	struct cvmx_mio_twsx_int_s cn63xx;
+	struct cvmx_mio_twsx_int_s cn63xxp1;
 };
 
 union cvmx_mio_twsx_sw_twsi {
@@ -1144,6 +1455,8 @@
 	struct cvmx_mio_twsx_sw_twsi_s cn56xxp1;
 	struct cvmx_mio_twsx_sw_twsi_s cn58xx;
 	struct cvmx_mio_twsx_sw_twsi_s cn58xxp1;
+	struct cvmx_mio_twsx_sw_twsi_s cn63xx;
+	struct cvmx_mio_twsx_sw_twsi_s cn63xxp1;
 };
 
 union cvmx_mio_twsx_sw_twsi_ext {
@@ -1164,6 +1477,8 @@
 	struct cvmx_mio_twsx_sw_twsi_ext_s cn56xxp1;
 	struct cvmx_mio_twsx_sw_twsi_ext_s cn58xx;
 	struct cvmx_mio_twsx_sw_twsi_ext_s cn58xxp1;
+	struct cvmx_mio_twsx_sw_twsi_ext_s cn63xx;
+	struct cvmx_mio_twsx_sw_twsi_ext_s cn63xxp1;
 };
 
 union cvmx_mio_twsx_twsi_sw {
@@ -1184,6 +1499,8 @@
 	struct cvmx_mio_twsx_twsi_sw_s cn56xxp1;
 	struct cvmx_mio_twsx_twsi_sw_s cn58xx;
 	struct cvmx_mio_twsx_twsi_sw_s cn58xxp1;
+	struct cvmx_mio_twsx_twsi_sw_s cn63xx;
+	struct cvmx_mio_twsx_twsi_sw_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_dlh {
@@ -1203,6 +1520,8 @@
 	struct cvmx_mio_uartx_dlh_s cn56xxp1;
 	struct cvmx_mio_uartx_dlh_s cn58xx;
 	struct cvmx_mio_uartx_dlh_s cn58xxp1;
+	struct cvmx_mio_uartx_dlh_s cn63xx;
+	struct cvmx_mio_uartx_dlh_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_dll {
@@ -1222,6 +1541,8 @@
 	struct cvmx_mio_uartx_dll_s cn56xxp1;
 	struct cvmx_mio_uartx_dll_s cn58xx;
 	struct cvmx_mio_uartx_dll_s cn58xxp1;
+	struct cvmx_mio_uartx_dll_s cn63xx;
+	struct cvmx_mio_uartx_dll_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_far {
@@ -1241,6 +1562,8 @@
 	struct cvmx_mio_uartx_far_s cn56xxp1;
 	struct cvmx_mio_uartx_far_s cn58xx;
 	struct cvmx_mio_uartx_far_s cn58xxp1;
+	struct cvmx_mio_uartx_far_s cn63xx;
+	struct cvmx_mio_uartx_far_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_fcr {
@@ -1265,6 +1588,8 @@
 	struct cvmx_mio_uartx_fcr_s cn56xxp1;
 	struct cvmx_mio_uartx_fcr_s cn58xx;
 	struct cvmx_mio_uartx_fcr_s cn58xxp1;
+	struct cvmx_mio_uartx_fcr_s cn63xx;
+	struct cvmx_mio_uartx_fcr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_htx {
@@ -1284,6 +1609,8 @@
 	struct cvmx_mio_uartx_htx_s cn56xxp1;
 	struct cvmx_mio_uartx_htx_s cn58xx;
 	struct cvmx_mio_uartx_htx_s cn58xxp1;
+	struct cvmx_mio_uartx_htx_s cn63xx;
+	struct cvmx_mio_uartx_htx_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_ier {
@@ -1308,6 +1635,8 @@
 	struct cvmx_mio_uartx_ier_s cn56xxp1;
 	struct cvmx_mio_uartx_ier_s cn58xx;
 	struct cvmx_mio_uartx_ier_s cn58xxp1;
+	struct cvmx_mio_uartx_ier_s cn63xx;
+	struct cvmx_mio_uartx_ier_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_iir {
@@ -1329,6 +1658,8 @@
 	struct cvmx_mio_uartx_iir_s cn56xxp1;
 	struct cvmx_mio_uartx_iir_s cn58xx;
 	struct cvmx_mio_uartx_iir_s cn58xxp1;
+	struct cvmx_mio_uartx_iir_s cn63xx;
+	struct cvmx_mio_uartx_iir_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_lcr {
@@ -1354,6 +1685,8 @@
 	struct cvmx_mio_uartx_lcr_s cn56xxp1;
 	struct cvmx_mio_uartx_lcr_s cn58xx;
 	struct cvmx_mio_uartx_lcr_s cn58xxp1;
+	struct cvmx_mio_uartx_lcr_s cn63xx;
+	struct cvmx_mio_uartx_lcr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_lsr {
@@ -1380,6 +1713,8 @@
 	struct cvmx_mio_uartx_lsr_s cn56xxp1;
 	struct cvmx_mio_uartx_lsr_s cn58xx;
 	struct cvmx_mio_uartx_lsr_s cn58xxp1;
+	struct cvmx_mio_uartx_lsr_s cn63xx;
+	struct cvmx_mio_uartx_lsr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_mcr {
@@ -1404,6 +1739,8 @@
 	struct cvmx_mio_uartx_mcr_s cn56xxp1;
 	struct cvmx_mio_uartx_mcr_s cn58xx;
 	struct cvmx_mio_uartx_mcr_s cn58xxp1;
+	struct cvmx_mio_uartx_mcr_s cn63xx;
+	struct cvmx_mio_uartx_mcr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_msr {
@@ -1430,6 +1767,8 @@
 	struct cvmx_mio_uartx_msr_s cn56xxp1;
 	struct cvmx_mio_uartx_msr_s cn58xx;
 	struct cvmx_mio_uartx_msr_s cn58xxp1;
+	struct cvmx_mio_uartx_msr_s cn63xx;
+	struct cvmx_mio_uartx_msr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_rbr {
@@ -1449,6 +1788,8 @@
 	struct cvmx_mio_uartx_rbr_s cn56xxp1;
 	struct cvmx_mio_uartx_rbr_s cn58xx;
 	struct cvmx_mio_uartx_rbr_s cn58xxp1;
+	struct cvmx_mio_uartx_rbr_s cn63xx;
+	struct cvmx_mio_uartx_rbr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_rfl {
@@ -1468,6 +1809,8 @@
 	struct cvmx_mio_uartx_rfl_s cn56xxp1;
 	struct cvmx_mio_uartx_rfl_s cn58xx;
 	struct cvmx_mio_uartx_rfl_s cn58xxp1;
+	struct cvmx_mio_uartx_rfl_s cn63xx;
+	struct cvmx_mio_uartx_rfl_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_rfw {
@@ -1489,6 +1832,8 @@
 	struct cvmx_mio_uartx_rfw_s cn56xxp1;
 	struct cvmx_mio_uartx_rfw_s cn58xx;
 	struct cvmx_mio_uartx_rfw_s cn58xxp1;
+	struct cvmx_mio_uartx_rfw_s cn63xx;
+	struct cvmx_mio_uartx_rfw_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_sbcr {
@@ -1508,6 +1853,8 @@
 	struct cvmx_mio_uartx_sbcr_s cn56xxp1;
 	struct cvmx_mio_uartx_sbcr_s cn58xx;
 	struct cvmx_mio_uartx_sbcr_s cn58xxp1;
+	struct cvmx_mio_uartx_sbcr_s cn63xx;
+	struct cvmx_mio_uartx_sbcr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_scr {
@@ -1527,6 +1874,8 @@
 	struct cvmx_mio_uartx_scr_s cn56xxp1;
 	struct cvmx_mio_uartx_scr_s cn58xx;
 	struct cvmx_mio_uartx_scr_s cn58xxp1;
+	struct cvmx_mio_uartx_scr_s cn63xx;
+	struct cvmx_mio_uartx_scr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_sfe {
@@ -1546,6 +1895,8 @@
 	struct cvmx_mio_uartx_sfe_s cn56xxp1;
 	struct cvmx_mio_uartx_sfe_s cn58xx;
 	struct cvmx_mio_uartx_sfe_s cn58xxp1;
+	struct cvmx_mio_uartx_sfe_s cn63xx;
+	struct cvmx_mio_uartx_sfe_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_srr {
@@ -1567,6 +1918,8 @@
 	struct cvmx_mio_uartx_srr_s cn56xxp1;
 	struct cvmx_mio_uartx_srr_s cn58xx;
 	struct cvmx_mio_uartx_srr_s cn58xxp1;
+	struct cvmx_mio_uartx_srr_s cn63xx;
+	struct cvmx_mio_uartx_srr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_srt {
@@ -1586,6 +1939,8 @@
 	struct cvmx_mio_uartx_srt_s cn56xxp1;
 	struct cvmx_mio_uartx_srt_s cn58xx;
 	struct cvmx_mio_uartx_srt_s cn58xxp1;
+	struct cvmx_mio_uartx_srt_s cn63xx;
+	struct cvmx_mio_uartx_srt_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_srts {
@@ -1605,6 +1960,8 @@
 	struct cvmx_mio_uartx_srts_s cn56xxp1;
 	struct cvmx_mio_uartx_srts_s cn58xx;
 	struct cvmx_mio_uartx_srts_s cn58xxp1;
+	struct cvmx_mio_uartx_srts_s cn63xx;
+	struct cvmx_mio_uartx_srts_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_stt {
@@ -1624,6 +1981,8 @@
 	struct cvmx_mio_uartx_stt_s cn56xxp1;
 	struct cvmx_mio_uartx_stt_s cn58xx;
 	struct cvmx_mio_uartx_stt_s cn58xxp1;
+	struct cvmx_mio_uartx_stt_s cn63xx;
+	struct cvmx_mio_uartx_stt_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_tfl {
@@ -1643,6 +2002,8 @@
 	struct cvmx_mio_uartx_tfl_s cn56xxp1;
 	struct cvmx_mio_uartx_tfl_s cn58xx;
 	struct cvmx_mio_uartx_tfl_s cn58xxp1;
+	struct cvmx_mio_uartx_tfl_s cn63xx;
+	struct cvmx_mio_uartx_tfl_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_tfr {
@@ -1662,6 +2023,8 @@
 	struct cvmx_mio_uartx_tfr_s cn56xxp1;
 	struct cvmx_mio_uartx_tfr_s cn58xx;
 	struct cvmx_mio_uartx_tfr_s cn58xxp1;
+	struct cvmx_mio_uartx_tfr_s cn63xx;
+	struct cvmx_mio_uartx_tfr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_thr {
@@ -1681,6 +2044,8 @@
 	struct cvmx_mio_uartx_thr_s cn56xxp1;
 	struct cvmx_mio_uartx_thr_s cn58xx;
 	struct cvmx_mio_uartx_thr_s cn58xxp1;
+	struct cvmx_mio_uartx_thr_s cn63xx;
+	struct cvmx_mio_uartx_thr_s cn63xxp1;
 };
 
 union cvmx_mio_uartx_usr {
@@ -1704,6 +2069,8 @@
 	struct cvmx_mio_uartx_usr_s cn56xxp1;
 	struct cvmx_mio_uartx_usr_s cn58xx;
 	struct cvmx_mio_uartx_usr_s cn58xxp1;
+	struct cvmx_mio_uartx_usr_s cn63xx;
+	struct cvmx_mio_uartx_usr_s cn63xxp1;
 };
 
 union cvmx_mio_uart2_dlh {
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-mixx-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-mixx-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-mixx-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-mixx-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,52 +28,52 @@
 #ifndef __CVMX_MIXX_DEFS_H__
 #define __CVMX_MIXX_DEFS_H__
 
-#define CVMX_MIXX_BIST(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100078ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_CTL(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100020ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_INTENA(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100050ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_IRCNT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100030ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_IRHWM(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100028ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_IRING1(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100010ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_IRING2(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100018ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_ISR(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100048ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_ORCNT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100040ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_ORHWM(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100038ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_ORING1(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100000ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_ORING2(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100008ull + (((offset) & 1) * 2048))
-#define CVMX_MIXX_REMCNT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001070000100058ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_BIST(offset) (CVMX_ADD_IO_SEG(0x0001070000100078ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_CTL(offset) (CVMX_ADD_IO_SEG(0x0001070000100020ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_INTENA(offset) (CVMX_ADD_IO_SEG(0x0001070000100050ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_IRCNT(offset) (CVMX_ADD_IO_SEG(0x0001070000100030ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_IRHWM(offset) (CVMX_ADD_IO_SEG(0x0001070000100028ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_IRING1(offset) (CVMX_ADD_IO_SEG(0x0001070000100010ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_IRING2(offset) (CVMX_ADD_IO_SEG(0x0001070000100018ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_ISR(offset) (CVMX_ADD_IO_SEG(0x0001070000100048ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_ORCNT(offset) (CVMX_ADD_IO_SEG(0x0001070000100040ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_ORHWM(offset) (CVMX_ADD_IO_SEG(0x0001070000100038ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_ORING1(offset) (CVMX_ADD_IO_SEG(0x0001070000100000ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_ORING2(offset) (CVMX_ADD_IO_SEG(0x0001070000100008ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_REMCNT(offset) (CVMX_ADD_IO_SEG(0x0001070000100058ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_TSCTL(offset) (CVMX_ADD_IO_SEG(0x0001070000100068ull) + ((offset) & 1) * 2048)
+#define CVMX_MIXX_TSTAMP(offset) (CVMX_ADD_IO_SEG(0x0001070000100060ull) + ((offset) & 1) * 2048)
 
 union cvmx_mixx_bist {
 	uint64_t u64;
 	struct cvmx_mixx_bist_s {
-		uint64_t reserved_4_63:60;
+		uint64_t reserved_6_63:58;
+		uint64_t opfdat:1;
+		uint64_t mrgdat:1;
 		uint64_t mrqdat:1;
 		uint64_t ipfdat:1;
 		uint64_t irfdat:1;
 		uint64_t orfdat:1;
 	} s;
-	struct cvmx_mixx_bist_s cn52xx;
-	struct cvmx_mixx_bist_s cn52xxp1;
-	struct cvmx_mixx_bist_s cn56xx;
-	struct cvmx_mixx_bist_s cn56xxp1;
+	struct cvmx_mixx_bist_cn52xx {
+		uint64_t reserved_4_63:60;
+		uint64_t mrqdat:1;
+		uint64_t ipfdat:1;
+		uint64_t irfdat:1;
+		uint64_t orfdat:1;
+	} cn52xx;
+	struct cvmx_mixx_bist_cn52xx cn52xxp1;
+	struct cvmx_mixx_bist_cn52xx cn56xx;
+	struct cvmx_mixx_bist_cn52xx cn56xxp1;
+	struct cvmx_mixx_bist_s cn63xx;
+	struct cvmx_mixx_bist_s cn63xxp1;
 };
 
 union cvmx_mixx_ctl {
 	uint64_t u64;
 	struct cvmx_mixx_ctl_s {
-		uint64_t reserved_8_63:56;
+		uint64_t reserved_12_63:52;
+		uint64_t ts_thresh:4;
 		uint64_t crc_strip:1;
 		uint64_t busy:1;
 		uint64_t en:1;
@@ -82,16 +82,28 @@
 		uint64_t nbtarb:1;
 		uint64_t mrq_hwm:2;
 	} s;
-	struct cvmx_mixx_ctl_s cn52xx;
-	struct cvmx_mixx_ctl_s cn52xxp1;
-	struct cvmx_mixx_ctl_s cn56xx;
-	struct cvmx_mixx_ctl_s cn56xxp1;
+	struct cvmx_mixx_ctl_cn52xx {
+		uint64_t reserved_8_63:56;
+		uint64_t crc_strip:1;
+		uint64_t busy:1;
+		uint64_t en:1;
+		uint64_t reset:1;
+		uint64_t lendian:1;
+		uint64_t nbtarb:1;
+		uint64_t mrq_hwm:2;
+	} cn52xx;
+	struct cvmx_mixx_ctl_cn52xx cn52xxp1;
+	struct cvmx_mixx_ctl_cn52xx cn56xx;
+	struct cvmx_mixx_ctl_cn52xx cn56xxp1;
+	struct cvmx_mixx_ctl_s cn63xx;
+	struct cvmx_mixx_ctl_s cn63xxp1;
 };
 
 union cvmx_mixx_intena {
 	uint64_t u64;
 	struct cvmx_mixx_intena_s {
-		uint64_t reserved_7_63:57;
+		uint64_t reserved_8_63:56;
+		uint64_t tsena:1;
 		uint64_t orunena:1;
 		uint64_t irunena:1;
 		uint64_t data_drpena:1;
@@ -100,10 +112,21 @@
 		uint64_t ivfena:1;
 		uint64_t ovfena:1;
 	} s;
-	struct cvmx_mixx_intena_s cn52xx;
-	struct cvmx_mixx_intena_s cn52xxp1;
-	struct cvmx_mixx_intena_s cn56xx;
-	struct cvmx_mixx_intena_s cn56xxp1;
+	struct cvmx_mixx_intena_cn52xx {
+		uint64_t reserved_7_63:57;
+		uint64_t orunena:1;
+		uint64_t irunena:1;
+		uint64_t data_drpena:1;
+		uint64_t ithena:1;
+		uint64_t othena:1;
+		uint64_t ivfena:1;
+		uint64_t ovfena:1;
+	} cn52xx;
+	struct cvmx_mixx_intena_cn52xx cn52xxp1;
+	struct cvmx_mixx_intena_cn52xx cn56xx;
+	struct cvmx_mixx_intena_cn52xx cn56xxp1;
+	struct cvmx_mixx_intena_s cn63xx;
+	struct cvmx_mixx_intena_s cn63xxp1;
 };
 
 union cvmx_mixx_ircnt {
@@ -116,6 +139,8 @@
 	struct cvmx_mixx_ircnt_s cn52xxp1;
 	struct cvmx_mixx_ircnt_s cn56xx;
 	struct cvmx_mixx_ircnt_s cn56xxp1;
+	struct cvmx_mixx_ircnt_s cn63xx;
+	struct cvmx_mixx_ircnt_s cn63xxp1;
 };
 
 union cvmx_mixx_irhwm {
@@ -129,6 +154,8 @@
 	struct cvmx_mixx_irhwm_s cn52xxp1;
 	struct cvmx_mixx_irhwm_s cn56xx;
 	struct cvmx_mixx_irhwm_s cn56xxp1;
+	struct cvmx_mixx_irhwm_s cn63xx;
+	struct cvmx_mixx_irhwm_s cn63xxp1;
 };
 
 union cvmx_mixx_iring1 {
@@ -136,14 +163,21 @@
 	struct cvmx_mixx_iring1_s {
 		uint64_t reserved_60_63:4;
 		uint64_t isize:20;
+		uint64_t ibase:37;
+		uint64_t reserved_0_2:3;
+	} s;
+	struct cvmx_mixx_iring1_cn52xx {
+		uint64_t reserved_60_63:4;
+		uint64_t isize:20;
 		uint64_t reserved_36_39:4;
 		uint64_t ibase:33;
 		uint64_t reserved_0_2:3;
-	} s;
-	struct cvmx_mixx_iring1_s cn52xx;
-	struct cvmx_mixx_iring1_s cn52xxp1;
-	struct cvmx_mixx_iring1_s cn56xx;
-	struct cvmx_mixx_iring1_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_mixx_iring1_cn52xx cn52xxp1;
+	struct cvmx_mixx_iring1_cn52xx cn56xx;
+	struct cvmx_mixx_iring1_cn52xx cn56xxp1;
+	struct cvmx_mixx_iring1_s cn63xx;
+	struct cvmx_mixx_iring1_s cn63xxp1;
 };
 
 union cvmx_mixx_iring2 {
@@ -158,12 +192,15 @@
 	struct cvmx_mixx_iring2_s cn52xxp1;
 	struct cvmx_mixx_iring2_s cn56xx;
 	struct cvmx_mixx_iring2_s cn56xxp1;
+	struct cvmx_mixx_iring2_s cn63xx;
+	struct cvmx_mixx_iring2_s cn63xxp1;
 };
 
 union cvmx_mixx_isr {
 	uint64_t u64;
 	struct cvmx_mixx_isr_s {
-		uint64_t reserved_7_63:57;
+		uint64_t reserved_8_63:56;
+		uint64_t ts:1;
 		uint64_t orun:1;
 		uint64_t irun:1;
 		uint64_t data_drp:1;
@@ -172,10 +209,21 @@
 		uint64_t idblovf:1;
 		uint64_t odblovf:1;
 	} s;
-	struct cvmx_mixx_isr_s cn52xx;
-	struct cvmx_mixx_isr_s cn52xxp1;
-	struct cvmx_mixx_isr_s cn56xx;
-	struct cvmx_mixx_isr_s cn56xxp1;
+	struct cvmx_mixx_isr_cn52xx {
+		uint64_t reserved_7_63:57;
+		uint64_t orun:1;
+		uint64_t irun:1;
+		uint64_t data_drp:1;
+		uint64_t irthresh:1;
+		uint64_t orthresh:1;
+		uint64_t idblovf:1;
+		uint64_t odblovf:1;
+	} cn52xx;
+	struct cvmx_mixx_isr_cn52xx cn52xxp1;
+	struct cvmx_mixx_isr_cn52xx cn56xx;
+	struct cvmx_mixx_isr_cn52xx cn56xxp1;
+	struct cvmx_mixx_isr_s cn63xx;
+	struct cvmx_mixx_isr_s cn63xxp1;
 };
 
 union cvmx_mixx_orcnt {
@@ -188,6 +236,8 @@
 	struct cvmx_mixx_orcnt_s cn52xxp1;
 	struct cvmx_mixx_orcnt_s cn56xx;
 	struct cvmx_mixx_orcnt_s cn56xxp1;
+	struct cvmx_mixx_orcnt_s cn63xx;
+	struct cvmx_mixx_orcnt_s cn63xxp1;
 };
 
 union cvmx_mixx_orhwm {
@@ -200,6 +250,8 @@
 	struct cvmx_mixx_orhwm_s cn52xxp1;
 	struct cvmx_mixx_orhwm_s cn56xx;
 	struct cvmx_mixx_orhwm_s cn56xxp1;
+	struct cvmx_mixx_orhwm_s cn63xx;
+	struct cvmx_mixx_orhwm_s cn63xxp1;
 };
 
 union cvmx_mixx_oring1 {
@@ -207,14 +259,21 @@
 	struct cvmx_mixx_oring1_s {
 		uint64_t reserved_60_63:4;
 		uint64_t osize:20;
+		uint64_t obase:37;
+		uint64_t reserved_0_2:3;
+	} s;
+	struct cvmx_mixx_oring1_cn52xx {
+		uint64_t reserved_60_63:4;
+		uint64_t osize:20;
 		uint64_t reserved_36_39:4;
 		uint64_t obase:33;
 		uint64_t reserved_0_2:3;
-	} s;
-	struct cvmx_mixx_oring1_s cn52xx;
-	struct cvmx_mixx_oring1_s cn52xxp1;
-	struct cvmx_mixx_oring1_s cn56xx;
-	struct cvmx_mixx_oring1_s cn56xxp1;
+	} cn52xx;
+	struct cvmx_mixx_oring1_cn52xx cn52xxp1;
+	struct cvmx_mixx_oring1_cn52xx cn56xx;
+	struct cvmx_mixx_oring1_cn52xx cn56xxp1;
+	struct cvmx_mixx_oring1_s cn63xx;
+	struct cvmx_mixx_oring1_s cn63xxp1;
 };
 
 union cvmx_mixx_oring2 {
@@ -229,6 +288,8 @@
 	struct cvmx_mixx_oring2_s cn52xxp1;
 	struct cvmx_mixx_oring2_s cn56xx;
 	struct cvmx_mixx_oring2_s cn56xxp1;
+	struct cvmx_mixx_oring2_s cn63xx;
+	struct cvmx_mixx_oring2_s cn63xxp1;
 };
 
 union cvmx_mixx_remcnt {
@@ -243,6 +304,31 @@
 	struct cvmx_mixx_remcnt_s cn52xxp1;
 	struct cvmx_mixx_remcnt_s cn56xx;
 	struct cvmx_mixx_remcnt_s cn56xxp1;
+	struct cvmx_mixx_remcnt_s cn63xx;
+	struct cvmx_mixx_remcnt_s cn63xxp1;
+};
+
+union cvmx_mixx_tsctl {
+	uint64_t u64;
+	struct cvmx_mixx_tsctl_s {
+		uint64_t reserved_21_63:43;
+		uint64_t tsavl:5;
+		uint64_t reserved_13_15:3;
+		uint64_t tstot:5;
+		uint64_t reserved_5_7:3;
+		uint64_t tscnt:5;
+	} s;
+	struct cvmx_mixx_tsctl_s cn63xx;
+	struct cvmx_mixx_tsctl_s cn63xxp1;
+};
+
+union cvmx_mixx_tstamp {
+	uint64_t u64;
+	struct cvmx_mixx_tstamp_s {
+		uint64_t tstamp:64;
+	} s;
+	struct cvmx_mixx_tstamp_s cn63xx;
+	struct cvmx_mixx_tstamp_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-npei-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-npei-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-npei-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-npei-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,206 +28,114 @@
 #ifndef __CVMX_NPEI_DEFS_H__
 #define __CVMX_NPEI_DEFS_H__
 
-#define CVMX_NPEI_BAR1_INDEXX(offset) \
-	 (0x0000000000000000ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_BIST_STATUS \
-	 (0x0000000000000580ull)
-#define CVMX_NPEI_BIST_STATUS2 \
-	 (0x0000000000000680ull)
-#define CVMX_NPEI_CTL_PORT0 \
-	 (0x0000000000000250ull)
-#define CVMX_NPEI_CTL_PORT1 \
-	 (0x0000000000000260ull)
-#define CVMX_NPEI_CTL_STATUS \
-	 (0x0000000000000570ull)
-#define CVMX_NPEI_CTL_STATUS2 \
-	 (0x0000000000003C00ull)
-#define CVMX_NPEI_DATA_OUT_CNT \
-	 (0x00000000000005F0ull)
-#define CVMX_NPEI_DBG_DATA \
-	 (0x0000000000000510ull)
-#define CVMX_NPEI_DBG_SELECT \
-	 (0x0000000000000500ull)
-#define CVMX_NPEI_DMA0_INT_LEVEL \
-	 (0x00000000000005C0ull)
-#define CVMX_NPEI_DMA1_INT_LEVEL \
-	 (0x00000000000005D0ull)
-#define CVMX_NPEI_DMAX_COUNTS(offset) \
-	 (0x0000000000000450ull + (((offset) & 7) * 16))
-#define CVMX_NPEI_DMAX_DBELL(offset) \
-	 (0x00000000000003B0ull + (((offset) & 7) * 16))
-#define CVMX_NPEI_DMAX_IBUFF_SADDR(offset) \
-	 (0x0000000000000400ull + (((offset) & 7) * 16))
-#define CVMX_NPEI_DMAX_NADDR(offset) \
-	 (0x00000000000004A0ull + (((offset) & 7) * 16))
-#define CVMX_NPEI_DMA_CNTS \
-	 (0x00000000000005E0ull)
-#define CVMX_NPEI_DMA_CONTROL \
-	 (0x00000000000003A0ull)
-#define CVMX_NPEI_INT_A_ENB \
-	 (0x0000000000000560ull)
-#define CVMX_NPEI_INT_A_ENB2 \
-	 (0x0000000000003CE0ull)
-#define CVMX_NPEI_INT_A_SUM \
-	 (0x0000000000000550ull)
-#define CVMX_NPEI_INT_ENB \
-	 (0x0000000000000540ull)
-#define CVMX_NPEI_INT_ENB2 \
-	 (0x0000000000003CD0ull)
-#define CVMX_NPEI_INT_INFO \
-	 (0x0000000000000590ull)
-#define CVMX_NPEI_INT_SUM \
-	 (0x0000000000000530ull)
-#define CVMX_NPEI_INT_SUM2 \
-	 (0x0000000000003CC0ull)
-#define CVMX_NPEI_LAST_WIN_RDATA0 \
-	 (0x0000000000000600ull)
-#define CVMX_NPEI_LAST_WIN_RDATA1 \
-	 (0x0000000000000610ull)
-#define CVMX_NPEI_MEM_ACCESS_CTL \
-	 (0x00000000000004F0ull)
-#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) \
-	 (0x0000000000000340ull + (((offset) & 31) * 16) - 16 * 12)
-#define CVMX_NPEI_MSI_ENB0 \
-	 (0x0000000000003C50ull)
-#define CVMX_NPEI_MSI_ENB1 \
-	 (0x0000000000003C60ull)
-#define CVMX_NPEI_MSI_ENB2 \
-	 (0x0000000000003C70ull)
-#define CVMX_NPEI_MSI_ENB3 \
-	 (0x0000000000003C80ull)
-#define CVMX_NPEI_MSI_RCV0 \
-	 (0x0000000000003C10ull)
-#define CVMX_NPEI_MSI_RCV1 \
-	 (0x0000000000003C20ull)
-#define CVMX_NPEI_MSI_RCV2 \
-	 (0x0000000000003C30ull)
-#define CVMX_NPEI_MSI_RCV3 \
-	 (0x0000000000003C40ull)
-#define CVMX_NPEI_MSI_RD_MAP \
-	 (0x0000000000003CA0ull)
-#define CVMX_NPEI_MSI_W1C_ENB0 \
-	 (0x0000000000003CF0ull)
-#define CVMX_NPEI_MSI_W1C_ENB1 \
-	 (0x0000000000003D00ull)
-#define CVMX_NPEI_MSI_W1C_ENB2 \
-	 (0x0000000000003D10ull)
-#define CVMX_NPEI_MSI_W1C_ENB3 \
-	 (0x0000000000003D20ull)
-#define CVMX_NPEI_MSI_W1S_ENB0 \
-	 (0x0000000000003D30ull)
-#define CVMX_NPEI_MSI_W1S_ENB1 \
-	 (0x0000000000003D40ull)
-#define CVMX_NPEI_MSI_W1S_ENB2 \
-	 (0x0000000000003D50ull)
-#define CVMX_NPEI_MSI_W1S_ENB3 \
-	 (0x0000000000003D60ull)
-#define CVMX_NPEI_MSI_WR_MAP \
-	 (0x0000000000003C90ull)
-#define CVMX_NPEI_PCIE_CREDIT_CNT \
-	 (0x0000000000003D70ull)
-#define CVMX_NPEI_PCIE_MSI_RCV \
-	 (0x0000000000003CB0ull)
-#define CVMX_NPEI_PCIE_MSI_RCV_B1 \
-	 (0x0000000000000650ull)
-#define CVMX_NPEI_PCIE_MSI_RCV_B2 \
-	 (0x0000000000000660ull)
-#define CVMX_NPEI_PCIE_MSI_RCV_B3 \
-	 (0x0000000000000670ull)
-#define CVMX_NPEI_PKTX_CNTS(offset) \
-	 (0x0000000000002400ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_INSTR_BADDR(offset) \
-	 (0x0000000000002800ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_INSTR_BAOFF_DBELL(offset) \
-	 (0x0000000000002C00ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_INSTR_FIFO_RSIZE(offset) \
-	 (0x0000000000003000ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_INSTR_HEADER(offset) \
-	 (0x0000000000003400ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_IN_BP(offset) \
-	 (0x0000000000003800ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_SLIST_BADDR(offset) \
-	 (0x0000000000001400ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_SLIST_BAOFF_DBELL(offset) \
-	 (0x0000000000001800ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKTX_SLIST_FIFO_RSIZE(offset) \
-	 (0x0000000000001C00ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKT_CNT_INT \
-	 (0x0000000000001110ull)
-#define CVMX_NPEI_PKT_CNT_INT_ENB \
-	 (0x0000000000001130ull)
-#define CVMX_NPEI_PKT_DATA_OUT_ES \
-	 (0x00000000000010B0ull)
-#define CVMX_NPEI_PKT_DATA_OUT_NS \
-	 (0x00000000000010A0ull)
-#define CVMX_NPEI_PKT_DATA_OUT_ROR \
-	 (0x0000000000001090ull)
-#define CVMX_NPEI_PKT_DPADDR \
-	 (0x0000000000001080ull)
-#define CVMX_NPEI_PKT_INPUT_CONTROL \
-	 (0x0000000000001150ull)
-#define CVMX_NPEI_PKT_INSTR_ENB \
-	 (0x0000000000001000ull)
-#define CVMX_NPEI_PKT_INSTR_RD_SIZE \
-	 (0x0000000000001190ull)
-#define CVMX_NPEI_PKT_INSTR_SIZE \
-	 (0x0000000000001020ull)
-#define CVMX_NPEI_PKT_INT_LEVELS \
-	 (0x0000000000001100ull)
-#define CVMX_NPEI_PKT_IN_BP \
-	 (0x00000000000006B0ull)
-#define CVMX_NPEI_PKT_IN_DONEX_CNTS(offset) \
-	 (0x0000000000002000ull + (((offset) & 31) * 16))
-#define CVMX_NPEI_PKT_IN_INSTR_COUNTS \
-	 (0x00000000000006A0ull)
-#define CVMX_NPEI_PKT_IN_PCIE_PORT \
-	 (0x00000000000011A0ull)
-#define CVMX_NPEI_PKT_IPTR \
-	 (0x0000000000001070ull)
-#define CVMX_NPEI_PKT_OUTPUT_WMARK \
-	 (0x0000000000001160ull)
-#define CVMX_NPEI_PKT_OUT_BMODE \
-	 (0x00000000000010D0ull)
-#define CVMX_NPEI_PKT_OUT_ENB \
-	 (0x0000000000001010ull)
-#define CVMX_NPEI_PKT_PCIE_PORT \
-	 (0x00000000000010E0ull)
-#define CVMX_NPEI_PKT_PORT_IN_RST \
-	 (0x0000000000000690ull)
-#define CVMX_NPEI_PKT_SLIST_ES \
-	 (0x0000000000001050ull)
-#define CVMX_NPEI_PKT_SLIST_ID_SIZE \
-	 (0x0000000000001180ull)
-#define CVMX_NPEI_PKT_SLIST_NS \
-	 (0x0000000000001040ull)
-#define CVMX_NPEI_PKT_SLIST_ROR \
-	 (0x0000000000001030ull)
-#define CVMX_NPEI_PKT_TIME_INT \
-	 (0x0000000000001120ull)
-#define CVMX_NPEI_PKT_TIME_INT_ENB \
-	 (0x0000000000001140ull)
-#define CVMX_NPEI_RSL_INT_BLOCKS \
-	 (0x0000000000000520ull)
-#define CVMX_NPEI_SCRATCH_1 \
-	 (0x0000000000000270ull)
-#define CVMX_NPEI_STATE1 \
-	 (0x0000000000000620ull)
-#define CVMX_NPEI_STATE2 \
-	 (0x0000000000000630ull)
-#define CVMX_NPEI_STATE3 \
-	 (0x0000000000000640ull)
-#define CVMX_NPEI_WINDOW_CTL \
-	 (0x0000000000000380ull)
-#define CVMX_NPEI_WIN_RD_ADDR \
-	 (0x0000000000000210ull)
-#define CVMX_NPEI_WIN_RD_DATA \
-	 (0x0000000000000240ull)
-#define CVMX_NPEI_WIN_WR_ADDR \
-	 (0x0000000000000200ull)
-#define CVMX_NPEI_WIN_WR_DATA \
-	 (0x0000000000000220ull)
-#define CVMX_NPEI_WIN_WR_MASK \
-	 (0x0000000000000230ull)
+#define CVMX_NPEI_BAR1_INDEXX(offset) (0x0000000000000000ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_BIST_STATUS (0x0000000000000580ull)
+#define CVMX_NPEI_BIST_STATUS2 (0x0000000000000680ull)
+#define CVMX_NPEI_CTL_PORT0 (0x0000000000000250ull)
+#define CVMX_NPEI_CTL_PORT1 (0x0000000000000260ull)
+#define CVMX_NPEI_CTL_STATUS (0x0000000000000570ull)
+#define CVMX_NPEI_CTL_STATUS2 (0x0000000000003C00ull)
+#define CVMX_NPEI_DATA_OUT_CNT (0x00000000000005F0ull)
+#define CVMX_NPEI_DBG_DATA (0x0000000000000510ull)
+#define CVMX_NPEI_DBG_SELECT (0x0000000000000500ull)
+#define CVMX_NPEI_DMA0_INT_LEVEL (0x00000000000005C0ull)
+#define CVMX_NPEI_DMA1_INT_LEVEL (0x00000000000005D0ull)
+#define CVMX_NPEI_DMAX_COUNTS(offset) (0x0000000000000450ull + ((offset) & 7) * 16)
+#define CVMX_NPEI_DMAX_DBELL(offset) (0x00000000000003B0ull + ((offset) & 7) * 16)
+#define CVMX_NPEI_DMAX_IBUFF_SADDR(offset) (0x0000000000000400ull + ((offset) & 7) * 16)
+#define CVMX_NPEI_DMAX_NADDR(offset) (0x00000000000004A0ull + ((offset) & 7) * 16)
+#define CVMX_NPEI_DMA_CNTS (0x00000000000005E0ull)
+#define CVMX_NPEI_DMA_CONTROL (0x00000000000003A0ull)
+#define CVMX_NPEI_DMA_PCIE_REQ_NUM (0x00000000000005B0ull)
+#define CVMX_NPEI_DMA_STATE1 (0x00000000000006C0ull)
+#define CVMX_NPEI_DMA_STATE1_P1 (0x0000000000000680ull)
+#define CVMX_NPEI_DMA_STATE2 (0x00000000000006D0ull)
+#define CVMX_NPEI_DMA_STATE2_P1 (0x0000000000000690ull)
+#define CVMX_NPEI_DMA_STATE3_P1 (0x00000000000006A0ull)
+#define CVMX_NPEI_DMA_STATE4_P1 (0x00000000000006B0ull)
+#define CVMX_NPEI_DMA_STATE5_P1 (0x00000000000006C0ull)
+#define CVMX_NPEI_INT_A_ENB (0x0000000000000560ull)
+#define CVMX_NPEI_INT_A_ENB2 (0x0000000000003CE0ull)
+#define CVMX_NPEI_INT_A_SUM (0x0000000000000550ull)
+#define CVMX_NPEI_INT_ENB (0x0000000000000540ull)
+#define CVMX_NPEI_INT_ENB2 (0x0000000000003CD0ull)
+#define CVMX_NPEI_INT_INFO (0x0000000000000590ull)
+#define CVMX_NPEI_INT_SUM (0x0000000000000530ull)
+#define CVMX_NPEI_INT_SUM2 (0x0000000000003CC0ull)
+#define CVMX_NPEI_LAST_WIN_RDATA0 (0x0000000000000600ull)
+#define CVMX_NPEI_LAST_WIN_RDATA1 (0x0000000000000610ull)
+#define CVMX_NPEI_MEM_ACCESS_CTL (0x00000000000004F0ull)
+#define CVMX_NPEI_MEM_ACCESS_SUBIDX(offset) (0x0000000000000340ull + ((offset) & 31) * 16 - 16*12)
+#define CVMX_NPEI_MSI_ENB0 (0x0000000000003C50ull)
+#define CVMX_NPEI_MSI_ENB1 (0x0000000000003C60ull)
+#define CVMX_NPEI_MSI_ENB2 (0x0000000000003C70ull)
+#define CVMX_NPEI_MSI_ENB3 (0x0000000000003C80ull)
+#define CVMX_NPEI_MSI_RCV0 (0x0000000000003C10ull)
+#define CVMX_NPEI_MSI_RCV1 (0x0000000000003C20ull)
+#define CVMX_NPEI_MSI_RCV2 (0x0000000000003C30ull)
+#define CVMX_NPEI_MSI_RCV3 (0x0000000000003C40ull)
+#define CVMX_NPEI_MSI_RD_MAP (0x0000000000003CA0ull)
+#define CVMX_NPEI_MSI_W1C_ENB0 (0x0000000000003CF0ull)
+#define CVMX_NPEI_MSI_W1C_ENB1 (0x0000000000003D00ull)
+#define CVMX_NPEI_MSI_W1C_ENB2 (0x0000000000003D10ull)
+#define CVMX_NPEI_MSI_W1C_ENB3 (0x0000000000003D20ull)
+#define CVMX_NPEI_MSI_W1S_ENB0 (0x0000000000003D30ull)
+#define CVMX_NPEI_MSI_W1S_ENB1 (0x0000000000003D40ull)
+#define CVMX_NPEI_MSI_W1S_ENB2 (0x0000000000003D50ull)
+#define CVMX_NPEI_MSI_W1S_ENB3 (0x0000000000003D60ull)
+#define CVMX_NPEI_MSI_WR_MAP (0x0000000000003C90ull)
+#define CVMX_NPEI_PCIE_CREDIT_CNT (0x0000000000003D70ull)
+#define CVMX_NPEI_PCIE_MSI_RCV (0x0000000000003CB0ull)
+#define CVMX_NPEI_PCIE_MSI_RCV_B1 (0x0000000000000650ull)
+#define CVMX_NPEI_PCIE_MSI_RCV_B2 (0x0000000000000660ull)
+#define CVMX_NPEI_PCIE_MSI_RCV_B3 (0x0000000000000670ull)
+#define CVMX_NPEI_PKTX_CNTS(offset) (0x0000000000002400ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_INSTR_BADDR(offset) (0x0000000000002800ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_INSTR_BAOFF_DBELL(offset) (0x0000000000002C00ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_INSTR_FIFO_RSIZE(offset) (0x0000000000003000ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_INSTR_HEADER(offset) (0x0000000000003400ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_IN_BP(offset) (0x0000000000003800ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_SLIST_BADDR(offset) (0x0000000000001400ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_SLIST_BAOFF_DBELL(offset) (0x0000000000001800ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKTX_SLIST_FIFO_RSIZE(offset) (0x0000000000001C00ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKT_CNT_INT (0x0000000000001110ull)
+#define CVMX_NPEI_PKT_CNT_INT_ENB (0x0000000000001130ull)
+#define CVMX_NPEI_PKT_DATA_OUT_ES (0x00000000000010B0ull)
+#define CVMX_NPEI_PKT_DATA_OUT_NS (0x00000000000010A0ull)
+#define CVMX_NPEI_PKT_DATA_OUT_ROR (0x0000000000001090ull)
+#define CVMX_NPEI_PKT_DPADDR (0x0000000000001080ull)
+#define CVMX_NPEI_PKT_INPUT_CONTROL (0x0000000000001150ull)
+#define CVMX_NPEI_PKT_INSTR_ENB (0x0000000000001000ull)
+#define CVMX_NPEI_PKT_INSTR_RD_SIZE (0x0000000000001190ull)
+#define CVMX_NPEI_PKT_INSTR_SIZE (0x0000000000001020ull)
+#define CVMX_NPEI_PKT_INT_LEVELS (0x0000000000001100ull)
+#define CVMX_NPEI_PKT_IN_BP (0x00000000000006B0ull)
+#define CVMX_NPEI_PKT_IN_DONEX_CNTS(offset) (0x0000000000002000ull + ((offset) & 31) * 16)
+#define CVMX_NPEI_PKT_IN_INSTR_COUNTS (0x00000000000006A0ull)
+#define CVMX_NPEI_PKT_IN_PCIE_PORT (0x00000000000011A0ull)
+#define CVMX_NPEI_PKT_IPTR (0x0000000000001070ull)
+#define CVMX_NPEI_PKT_OUTPUT_WMARK (0x0000000000001160ull)
+#define CVMX_NPEI_PKT_OUT_BMODE (0x00000000000010D0ull)
+#define CVMX_NPEI_PKT_OUT_ENB (0x0000000000001010ull)
+#define CVMX_NPEI_PKT_PCIE_PORT (0x00000000000010E0ull)
+#define CVMX_NPEI_PKT_PORT_IN_RST (0x0000000000000690ull)
+#define CVMX_NPEI_PKT_SLIST_ES (0x0000000000001050ull)
+#define CVMX_NPEI_PKT_SLIST_ID_SIZE (0x0000000000001180ull)
+#define CVMX_NPEI_PKT_SLIST_NS (0x0000000000001040ull)
+#define CVMX_NPEI_PKT_SLIST_ROR (0x0000000000001030ull)
+#define CVMX_NPEI_PKT_TIME_INT (0x0000000000001120ull)
+#define CVMX_NPEI_PKT_TIME_INT_ENB (0x0000000000001140ull)
+#define CVMX_NPEI_RSL_INT_BLOCKS (0x0000000000000520ull)
+#define CVMX_NPEI_SCRATCH_1 (0x0000000000000270ull)
+#define CVMX_NPEI_STATE1 (0x0000000000000620ull)
+#define CVMX_NPEI_STATE2 (0x0000000000000630ull)
+#define CVMX_NPEI_STATE3 (0x0000000000000640ull)
+#define CVMX_NPEI_WINDOW_CTL (0x0000000000000380ull)
+#define CVMX_NPEI_WIN_RD_ADDR (0x0000000000000210ull)
+#define CVMX_NPEI_WIN_RD_DATA (0x0000000000000240ull)
+#define CVMX_NPEI_WIN_WR_ADDR (0x0000000000000200ull)
+#define CVMX_NPEI_WIN_WR_DATA (0x0000000000000220ull)
+#define CVMX_NPEI_WIN_WR_MASK (0x0000000000000230ull)
 
 union cvmx_npei_bar1_indexx {
 	uint32_t u32;
@@ -248,9 +156,7 @@
 	uint64_t u64;
 	struct cvmx_npei_bist_status_s {
 		uint64_t pkt_rdf:1;
-		uint64_t pkt_pmem:1;
-		uint64_t pkt_p1:1;
-		uint64_t reserved_60_60:1;
+		uint64_t reserved_60_62:3;
 		uint64_t pcr_gim:1;
 		uint64_t pkt_pif:1;
 		uint64_t pcsr_int:1;
@@ -301,9 +207,7 @@
 	} s;
 	struct cvmx_npei_bist_status_cn52xx {
 		uint64_t pkt_rdf:1;
-		uint64_t pkt_pmem:1;
-		uint64_t pkt_p1:1;
-		uint64_t reserved_60_60:1;
+		uint64_t reserved_60_62:3;
 		uint64_t pcr_gim:1;
 		uint64_t pkt_pif:1;
 		uint64_t pcsr_int:1;
@@ -410,66 +314,7 @@
 		uint64_t msi:1;
 		uint64_t ncb_cmd:1;
 	} cn52xxp1;
-	struct cvmx_npei_bist_status_cn56xx {
-		uint64_t pkt_rdf:1;
-		uint64_t reserved_60_62:3;
-		uint64_t pcr_gim:1;
-		uint64_t pkt_pif:1;
-		uint64_t pcsr_int:1;
-		uint64_t pcsr_im:1;
-		uint64_t pcsr_cnt:1;
-		uint64_t pcsr_id:1;
-		uint64_t pcsr_sl:1;
-		uint64_t pkt_imem:1;
-		uint64_t pkt_pfm:1;
-		uint64_t pkt_pof:1;
-		uint64_t reserved_48_49:2;
-		uint64_t pkt_pop0:1;
-		uint64_t pkt_pop1:1;
-		uint64_t d0_mem:1;
-		uint64_t d1_mem:1;
-		uint64_t d2_mem:1;
-		uint64_t d3_mem:1;
-		uint64_t d4_mem:1;
-		uint64_t ds_mem:1;
-		uint64_t reserved_36_39:4;
-		uint64_t d0_pst:1;
-		uint64_t d1_pst:1;
-		uint64_t d2_pst:1;
-		uint64_t d3_pst:1;
-		uint64_t d4_pst:1;
-		uint64_t n2p0_c:1;
-		uint64_t n2p0_o:1;
-		uint64_t n2p1_c:1;
-		uint64_t n2p1_o:1;
-		uint64_t cpl_p0:1;
-		uint64_t cpl_p1:1;
-		uint64_t p2n1_po:1;
-		uint64_t p2n1_no:1;
-		uint64_t p2n1_co:1;
-		uint64_t p2n0_po:1;
-		uint64_t p2n0_no:1;
-		uint64_t p2n0_co:1;
-		uint64_t p2n0_c0:1;
-		uint64_t p2n0_c1:1;
-		uint64_t p2n0_n:1;
-		uint64_t p2n0_p0:1;
-		uint64_t p2n0_p1:1;
-		uint64_t p2n1_c0:1;
-		uint64_t p2n1_c1:1;
-		uint64_t p2n1_n:1;
-		uint64_t p2n1_p0:1;
-		uint64_t p2n1_p1:1;
-		uint64_t csm0:1;
-		uint64_t csm1:1;
-		uint64_t dif0:1;
-		uint64_t dif1:1;
-		uint64_t dif2:1;
-		uint64_t dif3:1;
-		uint64_t dif4:1;
-		uint64_t msi:1;
-		uint64_t ncb_cmd:1;
-	} cn56xx;
+	struct cvmx_npei_bist_status_cn52xx cn56xx;
 	struct cvmx_npei_bist_status_cn56xxp1 {
 		uint64_t reserved_58_63:6;
 		uint64_t pcsr_int:1;
@@ -536,7 +381,16 @@
 union cvmx_npei_bist_status2 {
 	uint64_t u64;
 	struct cvmx_npei_bist_status2_s {
-		uint64_t reserved_5_63:59;
+		uint64_t reserved_14_63:50;
+		uint64_t prd_tag:1;
+		uint64_t prd_st0:1;
+		uint64_t prd_st1:1;
+		uint64_t prd_err:1;
+		uint64_t nrd_st:1;
+		uint64_t nwe_st:1;
+		uint64_t nwe_wr0:1;
+		uint64_t nwe_wr1:1;
+		uint64_t pkt_rd:1;
 		uint64_t psc_p0:1;
 		uint64_t psc_p1:1;
 		uint64_t pkt_gd:1;
@@ -630,8 +484,7 @@
 	} cn52xxp1;
 	struct cvmx_npei_ctl_status_s cn56xx;
 	struct cvmx_npei_ctl_status_cn56xxp1 {
-		uint64_t reserved_16_63:48;
-		uint64_t ring_en:1;
+		uint64_t reserved_15_63:49;
 		uint64_t lnk_rst:1;
 		uint64_t arb:1;
 		uint64_t pkt_bp:4;
@@ -756,14 +609,14 @@
 		uint64_t saddr:29;
 		uint64_t reserved_0_6:7;
 	} s;
-	struct cvmx_npei_dmax_ibuff_saddr_cn52xx {
+	struct cvmx_npei_dmax_ibuff_saddr_s cn52xx;
+	struct cvmx_npei_dmax_ibuff_saddr_cn52xxp1 {
 		uint64_t reserved_36_63:28;
 		uint64_t saddr:29;
 		uint64_t reserved_0_6:7;
-	} cn52xx;
-	struct cvmx_npei_dmax_ibuff_saddr_cn52xx cn52xxp1;
+	} cn52xxp1;
 	struct cvmx_npei_dmax_ibuff_saddr_s cn56xx;
-	struct cvmx_npei_dmax_ibuff_saddr_cn52xx cn56xxp1;
+	struct cvmx_npei_dmax_ibuff_saddr_cn52xxp1 cn56xxp1;
 };
 
 union cvmx_npei_dmax_naddr {
@@ -817,7 +670,8 @@
 union cvmx_npei_dma_control {
 	uint64_t u64;
 	struct cvmx_npei_dma_control_s {
-		uint64_t reserved_39_63:25;
+		uint64_t reserved_40_63:24;
+		uint64_t p_32b_m:1;
 		uint64_t dma4_enb:1;
 		uint64_t dma3_enb:1;
 		uint64_t dma2_enb:1;
@@ -853,7 +707,161 @@
 		uint64_t csize:14;
 	} cn52xxp1;
 	struct cvmx_npei_dma_control_s cn56xx;
-	struct cvmx_npei_dma_control_s cn56xxp1;
+	struct cvmx_npei_dma_control_cn56xxp1 {
+		uint64_t reserved_39_63:25;
+		uint64_t dma4_enb:1;
+		uint64_t dma3_enb:1;
+		uint64_t dma2_enb:1;
+		uint64_t dma1_enb:1;
+		uint64_t dma0_enb:1;
+		uint64_t b0_lend:1;
+		uint64_t dwb_denb:1;
+		uint64_t dwb_ichk:9;
+		uint64_t fpa_que:3;
+		uint64_t o_add1:1;
+		uint64_t o_ro:1;
+		uint64_t o_ns:1;
+		uint64_t o_es:2;
+		uint64_t o_mode:1;
+		uint64_t csize:14;
+	} cn56xxp1;
+};
+
+union cvmx_npei_dma_pcie_req_num {
+	uint64_t u64;
+	struct cvmx_npei_dma_pcie_req_num_s {
+		uint64_t dma_arb:1;
+		uint64_t reserved_53_62:10;
+		uint64_t pkt_cnt:5;
+		uint64_t reserved_45_47:3;
+		uint64_t dma4_cnt:5;
+		uint64_t reserved_37_39:3;
+		uint64_t dma3_cnt:5;
+		uint64_t reserved_29_31:3;
+		uint64_t dma2_cnt:5;
+		uint64_t reserved_21_23:3;
+		uint64_t dma1_cnt:5;
+		uint64_t reserved_13_15:3;
+		uint64_t dma0_cnt:5;
+		uint64_t reserved_5_7:3;
+		uint64_t dma_cnt:5;
+	} s;
+	struct cvmx_npei_dma_pcie_req_num_s cn52xx;
+	struct cvmx_npei_dma_pcie_req_num_s cn56xx;
+};
+
+union cvmx_npei_dma_state1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state1_s {
+		uint64_t reserved_40_63:24;
+		uint64_t d4_dwe:8;
+		uint64_t d3_dwe:8;
+		uint64_t d2_dwe:8;
+		uint64_t d1_dwe:8;
+		uint64_t d0_dwe:8;
+	} s;
+	struct cvmx_npei_dma_state1_s cn52xx;
+};
+
+union cvmx_npei_dma_state1_p1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state1_p1_s {
+		uint64_t reserved_60_63:4;
+		uint64_t d0_difst:7;
+		uint64_t d1_difst:7;
+		uint64_t d2_difst:7;
+		uint64_t d3_difst:7;
+		uint64_t d4_difst:7;
+		uint64_t d0_reqst:5;
+		uint64_t d1_reqst:5;
+		uint64_t d2_reqst:5;
+		uint64_t d3_reqst:5;
+		uint64_t d4_reqst:5;
+	} s;
+	struct cvmx_npei_dma_state1_p1_cn52xxp1 {
+		uint64_t reserved_60_63:4;
+		uint64_t d0_difst:7;
+		uint64_t d1_difst:7;
+		uint64_t d2_difst:7;
+		uint64_t d3_difst:7;
+		uint64_t reserved_25_31:7;
+		uint64_t d0_reqst:5;
+		uint64_t d1_reqst:5;
+		uint64_t d2_reqst:5;
+		uint64_t d3_reqst:5;
+		uint64_t reserved_0_4:5;
+	} cn52xxp1;
+	struct cvmx_npei_dma_state1_p1_s cn56xxp1;
+};
+
+union cvmx_npei_dma_state2 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state2_s {
+		uint64_t reserved_28_63:36;
+		uint64_t ndwe:4;
+		uint64_t reserved_21_23:3;
+		uint64_t ndre:5;
+		uint64_t reserved_10_15:6;
+		uint64_t prd:10;
+	} s;
+	struct cvmx_npei_dma_state2_s cn52xx;
+};
+
+union cvmx_npei_dma_state2_p1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state2_p1_s {
+		uint64_t reserved_45_63:19;
+		uint64_t d0_dffst:9;
+		uint64_t d1_dffst:9;
+		uint64_t d2_dffst:9;
+		uint64_t d3_dffst:9;
+		uint64_t d4_dffst:9;
+	} s;
+	struct cvmx_npei_dma_state2_p1_cn52xxp1 {
+		uint64_t reserved_45_63:19;
+		uint64_t d0_dffst:9;
+		uint64_t d1_dffst:9;
+		uint64_t d2_dffst:9;
+		uint64_t d3_dffst:9;
+		uint64_t reserved_0_8:9;
+	} cn52xxp1;
+	struct cvmx_npei_dma_state2_p1_s cn56xxp1;
+};
+
+union cvmx_npei_dma_state3_p1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state3_p1_s {
+		uint64_t reserved_60_63:4;
+		uint64_t d0_drest:15;
+		uint64_t d1_drest:15;
+		uint64_t d2_drest:15;
+		uint64_t d3_drest:15;
+	} s;
+	struct cvmx_npei_dma_state3_p1_s cn52xxp1;
+	struct cvmx_npei_dma_state3_p1_s cn56xxp1;
+};
+
+union cvmx_npei_dma_state4_p1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state4_p1_s {
+		uint64_t reserved_52_63:12;
+		uint64_t d0_dwest:13;
+		uint64_t d1_dwest:13;
+		uint64_t d2_dwest:13;
+		uint64_t d3_dwest:13;
+	} s;
+	struct cvmx_npei_dma_state4_p1_s cn52xxp1;
+	struct cvmx_npei_dma_state4_p1_s cn56xxp1;
+};
+
+union cvmx_npei_dma_state5_p1 {
+	uint64_t u64;
+	struct cvmx_npei_dma_state5_p1_s {
+		uint64_t reserved_28_63:36;
+		uint64_t d4_drest:15;
+		uint64_t d4_dwest:13;
+	} s;
+	struct cvmx_npei_dma_state5_p1_s cn56xxp1;
 };
 
 union cvmx_npei_int_a_enb {
@@ -871,17 +879,7 @@
 		uint64_t dma1_cpl:1;
 		uint64_t dma0_cpl:1;
 	} s;
-	struct cvmx_npei_int_a_enb_cn52xx {
-		uint64_t reserved_8_63:56;
-		uint64_t p1_rdlk:1;
-		uint64_t p0_rdlk:1;
-		uint64_t pgl_err:1;
-		uint64_t pdi_err:1;
-		uint64_t pop_err:1;
-		uint64_t pins_err:1;
-		uint64_t dma1_cpl:1;
-		uint64_t dma0_cpl:1;
-	} cn52xx;
+	struct cvmx_npei_int_a_enb_s cn52xx;
 	struct cvmx_npei_int_a_enb_cn52xxp1 {
 		uint64_t reserved_2_63:62;
 		uint64_t dma1_cpl:1;
@@ -905,16 +903,7 @@
 		uint64_t dma1_cpl:1;
 		uint64_t dma0_cpl:1;
 	} s;
-	struct cvmx_npei_int_a_enb2_cn52xx {
-		uint64_t reserved_8_63:56;
-		uint64_t p1_rdlk:1;
-		uint64_t p0_rdlk:1;
-		uint64_t pgl_err:1;
-		uint64_t pdi_err:1;
-		uint64_t pop_err:1;
-		uint64_t pins_err:1;
-		uint64_t reserved_0_1:2;
-	} cn52xx;
+	struct cvmx_npei_int_a_enb2_s cn52xx;
 	struct cvmx_npei_int_a_enb2_cn52xxp1 {
 		uint64_t reserved_2_63:62;
 		uint64_t dma1_cpl:1;
@@ -938,17 +927,7 @@
 		uint64_t dma1_cpl:1;
 		uint64_t dma0_cpl:1;
 	} s;
-	struct cvmx_npei_int_a_sum_cn52xx {
-		uint64_t reserved_8_63:56;
-		uint64_t p1_rdlk:1;
-		uint64_t p0_rdlk:1;
-		uint64_t pgl_err:1;
-		uint64_t pdi_err:1;
-		uint64_t pop_err:1;
-		uint64_t pins_err:1;
-		uint64_t dma1_cpl:1;
-		uint64_t dma0_cpl:1;
-	} cn52xx;
+	struct cvmx_npei_int_a_sum_s cn52xx;
 	struct cvmx_npei_int_a_sum_cn52xxp1 {
 		uint64_t reserved_2_63:62;
 		uint64_t dma1_cpl:1;
@@ -1550,10 +1529,7 @@
 		uint64_t c0_se:1;
 		uint64_t reserved_20_20:1;
 		uint64_t c0_aeri:1;
-		uint64_t ptime:1;
-		uint64_t pcnt:1;
-		uint64_t pidbof:1;
-		uint64_t psldbof:1;
+		uint64_t reserved_15_18:4;
 		uint64_t dtime1:1;
 		uint64_t dtime0:1;
 		uint64_t dcnt1:1;
@@ -1959,7 +1935,6 @@
 	} s;
 	struct cvmx_npei_pktx_cnts_s cn52xx;
 	struct cvmx_npei_pktx_cnts_s cn56xx;
-	struct cvmx_npei_pktx_cnts_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_in_bp {
@@ -1970,7 +1945,6 @@
 	} s;
 	struct cvmx_npei_pktx_in_bp_s cn52xx;
 	struct cvmx_npei_pktx_in_bp_s cn56xx;
-	struct cvmx_npei_pktx_in_bp_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_instr_baddr {
@@ -1981,7 +1955,6 @@
 	} s;
 	struct cvmx_npei_pktx_instr_baddr_s cn52xx;
 	struct cvmx_npei_pktx_instr_baddr_s cn56xx;
-	struct cvmx_npei_pktx_instr_baddr_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_instr_baoff_dbell {
@@ -1992,7 +1965,6 @@
 	} s;
 	struct cvmx_npei_pktx_instr_baoff_dbell_s cn52xx;
 	struct cvmx_npei_pktx_instr_baoff_dbell_s cn56xx;
-	struct cvmx_npei_pktx_instr_baoff_dbell_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_instr_fifo_rsize {
@@ -2006,7 +1978,6 @@
 	} s;
 	struct cvmx_npei_pktx_instr_fifo_rsize_s cn52xx;
 	struct cvmx_npei_pktx_instr_fifo_rsize_s cn56xx;
-	struct cvmx_npei_pktx_instr_fifo_rsize_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_instr_header {
@@ -2014,21 +1985,20 @@
 	struct cvmx_npei_pktx_instr_header_s {
 		uint64_t reserved_44_63:20;
 		uint64_t pbp:1;
-		uint64_t rsv_f:5;
+		uint64_t reserved_38_42:5;
 		uint64_t rparmode:2;
-		uint64_t rsv_e:1;
+		uint64_t reserved_35_35:1;
 		uint64_t rskp_len:7;
-		uint64_t rsv_d:6;
+		uint64_t reserved_22_27:6;
 		uint64_t use_ihdr:1;
-		uint64_t rsv_c:5;
+		uint64_t reserved_16_20:5;
 		uint64_t par_mode:2;
-		uint64_t rsv_b:1;
+		uint64_t reserved_13_13:1;
 		uint64_t skp_len:7;
-		uint64_t rsv_a:6;
+		uint64_t reserved_0_5:6;
 	} s;
 	struct cvmx_npei_pktx_instr_header_s cn52xx;
 	struct cvmx_npei_pktx_instr_header_s cn56xx;
-	struct cvmx_npei_pktx_instr_header_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_slist_baddr {
@@ -2039,7 +2009,6 @@
 	} s;
 	struct cvmx_npei_pktx_slist_baddr_s cn52xx;
 	struct cvmx_npei_pktx_slist_baddr_s cn56xx;
-	struct cvmx_npei_pktx_slist_baddr_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_slist_baoff_dbell {
@@ -2050,7 +2019,6 @@
 	} s;
 	struct cvmx_npei_pktx_slist_baoff_dbell_s cn52xx;
 	struct cvmx_npei_pktx_slist_baoff_dbell_s cn56xx;
-	struct cvmx_npei_pktx_slist_baoff_dbell_s cn56xxp1;
 };
 
 union cvmx_npei_pktx_slist_fifo_rsize {
@@ -2061,7 +2029,6 @@
 	} s;
 	struct cvmx_npei_pktx_slist_fifo_rsize_s cn52xx;
 	struct cvmx_npei_pktx_slist_fifo_rsize_s cn56xx;
-	struct cvmx_npei_pktx_slist_fifo_rsize_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_cnt_int {
@@ -2072,7 +2039,6 @@
 	} s;
 	struct cvmx_npei_pkt_cnt_int_s cn52xx;
 	struct cvmx_npei_pkt_cnt_int_s cn56xx;
-	struct cvmx_npei_pkt_cnt_int_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_cnt_int_enb {
@@ -2083,7 +2049,6 @@
 	} s;
 	struct cvmx_npei_pkt_cnt_int_enb_s cn52xx;
 	struct cvmx_npei_pkt_cnt_int_enb_s cn56xx;
-	struct cvmx_npei_pkt_cnt_int_enb_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_data_out_es {
@@ -2093,7 +2058,6 @@
 	} s;
 	struct cvmx_npei_pkt_data_out_es_s cn52xx;
 	struct cvmx_npei_pkt_data_out_es_s cn56xx;
-	struct cvmx_npei_pkt_data_out_es_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_data_out_ns {
@@ -2104,7 +2068,6 @@
 	} s;
 	struct cvmx_npei_pkt_data_out_ns_s cn52xx;
 	struct cvmx_npei_pkt_data_out_ns_s cn56xx;
-	struct cvmx_npei_pkt_data_out_ns_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_data_out_ror {
@@ -2115,7 +2078,6 @@
 	} s;
 	struct cvmx_npei_pkt_data_out_ror_s cn52xx;
 	struct cvmx_npei_pkt_data_out_ror_s cn56xx;
-	struct cvmx_npei_pkt_data_out_ror_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_dpaddr {
@@ -2126,7 +2088,6 @@
 	} s;
 	struct cvmx_npei_pkt_dpaddr_s cn52xx;
 	struct cvmx_npei_pkt_dpaddr_s cn56xx;
-	struct cvmx_npei_pkt_dpaddr_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_in_bp {
@@ -2135,6 +2096,7 @@
 		uint64_t reserved_32_63:32;
 		uint64_t bp:32;
 	} s;
+	struct cvmx_npei_pkt_in_bp_s cn52xx;
 	struct cvmx_npei_pkt_in_bp_s cn56xx;
 };
 
@@ -2146,7 +2108,6 @@
 	} s;
 	struct cvmx_npei_pkt_in_donex_cnts_s cn52xx;
 	struct cvmx_npei_pkt_in_donex_cnts_s cn56xx;
-	struct cvmx_npei_pkt_in_donex_cnts_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_in_instr_counts {
@@ -2184,7 +2145,6 @@
 	} s;
 	struct cvmx_npei_pkt_input_control_s cn52xx;
 	struct cvmx_npei_pkt_input_control_s cn56xx;
-	struct cvmx_npei_pkt_input_control_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_instr_enb {
@@ -2195,7 +2155,6 @@
 	} s;
 	struct cvmx_npei_pkt_instr_enb_s cn52xx;
 	struct cvmx_npei_pkt_instr_enb_s cn56xx;
-	struct cvmx_npei_pkt_instr_enb_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_instr_rd_size {
@@ -2215,7 +2174,6 @@
 	} s;
 	struct cvmx_npei_pkt_instr_size_s cn52xx;
 	struct cvmx_npei_pkt_instr_size_s cn56xx;
-	struct cvmx_npei_pkt_instr_size_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_int_levels {
@@ -2227,7 +2185,6 @@
 	} s;
 	struct cvmx_npei_pkt_int_levels_s cn52xx;
 	struct cvmx_npei_pkt_int_levels_s cn56xx;
-	struct cvmx_npei_pkt_int_levels_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_iptr {
@@ -2238,7 +2195,6 @@
 	} s;
 	struct cvmx_npei_pkt_iptr_s cn52xx;
 	struct cvmx_npei_pkt_iptr_s cn56xx;
-	struct cvmx_npei_pkt_iptr_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_out_bmode {
@@ -2249,7 +2205,6 @@
 	} s;
 	struct cvmx_npei_pkt_out_bmode_s cn52xx;
 	struct cvmx_npei_pkt_out_bmode_s cn56xx;
-	struct cvmx_npei_pkt_out_bmode_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_out_enb {
@@ -2260,7 +2215,6 @@
 	} s;
 	struct cvmx_npei_pkt_out_enb_s cn52xx;
 	struct cvmx_npei_pkt_out_enb_s cn56xx;
-	struct cvmx_npei_pkt_out_enb_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_output_wmark {
@@ -2280,7 +2234,6 @@
 	} s;
 	struct cvmx_npei_pkt_pcie_port_s cn52xx;
 	struct cvmx_npei_pkt_pcie_port_s cn56xx;
-	struct cvmx_npei_pkt_pcie_port_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_port_in_rst {
@@ -2300,7 +2253,6 @@
 	} s;
 	struct cvmx_npei_pkt_slist_es_s cn52xx;
 	struct cvmx_npei_pkt_slist_es_s cn56xx;
-	struct cvmx_npei_pkt_slist_es_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_slist_id_size {
@@ -2312,7 +2264,6 @@
 	} s;
 	struct cvmx_npei_pkt_slist_id_size_s cn52xx;
 	struct cvmx_npei_pkt_slist_id_size_s cn56xx;
-	struct cvmx_npei_pkt_slist_id_size_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_slist_ns {
@@ -2323,7 +2274,6 @@
 	} s;
 	struct cvmx_npei_pkt_slist_ns_s cn52xx;
 	struct cvmx_npei_pkt_slist_ns_s cn56xx;
-	struct cvmx_npei_pkt_slist_ns_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_slist_ror {
@@ -2334,7 +2284,6 @@
 	} s;
 	struct cvmx_npei_pkt_slist_ror_s cn52xx;
 	struct cvmx_npei_pkt_slist_ror_s cn56xx;
-	struct cvmx_npei_pkt_slist_ror_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_time_int {
@@ -2345,7 +2294,6 @@
 	} s;
 	struct cvmx_npei_pkt_time_int_s cn52xx;
 	struct cvmx_npei_pkt_time_int_s cn56xx;
-	struct cvmx_npei_pkt_time_int_s cn56xxp1;
 };
 
 union cvmx_npei_pkt_time_int_enb {
@@ -2356,7 +2304,6 @@
 	} s;
 	struct cvmx_npei_pkt_time_int_enb_s cn52xx;
 	struct cvmx_npei_pkt_time_int_enb_s cn56xx;
-	struct cvmx_npei_pkt_time_int_enb_s cn56xxp1;
 };
 
 union cvmx_npei_rsl_int_blocks {
@@ -2371,7 +2318,8 @@
 		uint64_t asxpcs0:1;
 		uint64_t reserved_21_21:1;
 		uint64_t pip:1;
-		uint64_t reserved_18_19:2;
+		uint64_t spx1:1;
+		uint64_t spx0:1;
 		uint64_t lmc0:1;
 		uint64_t l2c:1;
 		uint64_t usb1:1;
@@ -2383,7 +2331,7 @@
 		uint64_t ipd:1;
 		uint64_t reserved_8_8:1;
 		uint64_t zip:1;
-		uint64_t reserved_6_6:1;
+		uint64_t dfa:1;
 		uint64_t fpa:1;
 		uint64_t key:1;
 		uint64_t npei:1;
@@ -2393,37 +2341,8 @@
 	} s;
 	struct cvmx_npei_rsl_int_blocks_s cn52xx;
 	struct cvmx_npei_rsl_int_blocks_s cn52xxp1;
-	struct cvmx_npei_rsl_int_blocks_cn56xx {
-		uint64_t reserved_31_63:33;
-		uint64_t iob:1;
-		uint64_t lmc1:1;
-		uint64_t agl:1;
-		uint64_t reserved_24_27:4;
-		uint64_t asxpcs1:1;
-		uint64_t asxpcs0:1;
-		uint64_t reserved_21_21:1;
-		uint64_t pip:1;
-		uint64_t reserved_18_19:2;
-		uint64_t lmc0:1;
-		uint64_t l2c:1;
-		uint64_t reserved_15_15:1;
-		uint64_t rad:1;
-		uint64_t usb:1;
-		uint64_t pow:1;
-		uint64_t tim:1;
-		uint64_t pko:1;
-		uint64_t ipd:1;
-		uint64_t reserved_8_8:1;
-		uint64_t zip:1;
-		uint64_t reserved_6_6:1;
-		uint64_t fpa:1;
-		uint64_t key:1;
-		uint64_t npei:1;
-		uint64_t gmx1:1;
-		uint64_t gmx0:1;
-		uint64_t mio:1;
-	} cn56xx;
-	struct cvmx_npei_rsl_int_blocks_cn56xx cn56xxp1;
+	struct cvmx_npei_rsl_int_blocks_s cn56xx;
+	struct cvmx_npei_rsl_int_blocks_s cn56xxp1;
 };
 
 union cvmx_npei_scratch_1 {
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-npi-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-npi-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-npi-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-npi-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,246 +28,126 @@
 #ifndef __CVMX_NPI_DEFS_H__
 #define __CVMX_NPI_DEFS_H__
 
-#define CVMX_NPI_BASE_ADDR_INPUT0 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000070ull)
-#define CVMX_NPI_BASE_ADDR_INPUT1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000080ull)
-#define CVMX_NPI_BASE_ADDR_INPUT2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000090ull)
-#define CVMX_NPI_BASE_ADDR_INPUT3 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000A0ull)
-#define CVMX_NPI_BASE_ADDR_INPUTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000070ull + (((offset) & 3) * 16))
-#define CVMX_NPI_BASE_ADDR_OUTPUT0 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000B8ull)
-#define CVMX_NPI_BASE_ADDR_OUTPUT1 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000C0ull)
-#define CVMX_NPI_BASE_ADDR_OUTPUT2 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000C8ull)
-#define CVMX_NPI_BASE_ADDR_OUTPUT3 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000D0ull)
-#define CVMX_NPI_BASE_ADDR_OUTPUTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000000B8ull + (((offset) & 3) * 8))
-#define CVMX_NPI_BIST_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011F00000003F8ull)
-#define CVMX_NPI_BUFF_SIZE_OUTPUT0 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000E0ull)
-#define CVMX_NPI_BUFF_SIZE_OUTPUT1 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000E8ull)
-#define CVMX_NPI_BUFF_SIZE_OUTPUT2 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000F0ull)
-#define CVMX_NPI_BUFF_SIZE_OUTPUT3 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000F8ull)
-#define CVMX_NPI_BUFF_SIZE_OUTPUTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000000E0ull + (((offset) & 3) * 8))
-#define CVMX_NPI_COMP_CTL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000218ull)
-#define CVMX_NPI_CTL_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000010ull)
-#define CVMX_NPI_DBG_SELECT \
-	 CVMX_ADD_IO_SEG(0x00011F0000000008ull)
-#define CVMX_NPI_DMA_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000128ull)
-#define CVMX_NPI_DMA_HIGHP_COUNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000148ull)
-#define CVMX_NPI_DMA_HIGHP_NADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000158ull)
-#define CVMX_NPI_DMA_LOWP_COUNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000140ull)
-#define CVMX_NPI_DMA_LOWP_NADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000150ull)
-#define CVMX_NPI_HIGHP_DBELL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000120ull)
-#define CVMX_NPI_HIGHP_IBUFF_SADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000110ull)
-#define CVMX_NPI_INPUT_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000138ull)
-#define CVMX_NPI_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000000020ull)
-#define CVMX_NPI_INT_SUM \
-	 CVMX_ADD_IO_SEG(0x00011F0000000018ull)
-#define CVMX_NPI_LOWP_DBELL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000118ull)
-#define CVMX_NPI_LOWP_IBUFF_SADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000108ull)
-#define CVMX_NPI_MEM_ACCESS_SUBID3 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000028ull)
-#define CVMX_NPI_MEM_ACCESS_SUBID4 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000030ull)
-#define CVMX_NPI_MEM_ACCESS_SUBID5 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000038ull)
-#define CVMX_NPI_MEM_ACCESS_SUBID6 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000040ull)
-#define CVMX_NPI_MEM_ACCESS_SUBIDX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000028ull + (((offset) & 7) * 8) - 8 * 3)
-#define CVMX_NPI_MSI_RCV \
-	 (0x0000000000000190ull)
-#define CVMX_NPI_NPI_MSI_RCV \
-	 CVMX_ADD_IO_SEG(0x00011F0000001190ull)
-#define CVMX_NPI_NUM_DESC_OUTPUT0 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000050ull)
-#define CVMX_NPI_NUM_DESC_OUTPUT1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000058ull)
-#define CVMX_NPI_NUM_DESC_OUTPUT2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000060ull)
-#define CVMX_NPI_NUM_DESC_OUTPUT3 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000068ull)
-#define CVMX_NPI_NUM_DESC_OUTPUTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000050ull + (((offset) & 3) * 8))
-#define CVMX_NPI_OUTPUT_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F0000000100ull)
-#define CVMX_NPI_P0_DBPAIR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000180ull)
-#define CVMX_NPI_P0_INSTR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F00000001C0ull)
-#define CVMX_NPI_P0_INSTR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000001A0ull)
-#define CVMX_NPI_P0_PAIR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000160ull)
-#define CVMX_NPI_P1_DBPAIR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000188ull)
-#define CVMX_NPI_P1_INSTR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F00000001C8ull)
-#define CVMX_NPI_P1_INSTR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000001A8ull)
-#define CVMX_NPI_P1_PAIR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000168ull)
-#define CVMX_NPI_P2_DBPAIR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000190ull)
-#define CVMX_NPI_P2_INSTR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F00000001D0ull)
-#define CVMX_NPI_P2_INSTR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000001B0ull)
-#define CVMX_NPI_P2_PAIR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000170ull)
-#define CVMX_NPI_P3_DBPAIR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000198ull)
-#define CVMX_NPI_P3_INSTR_ADDR \
-	 CVMX_ADD_IO_SEG(0x00011F00000001D8ull)
-#define CVMX_NPI_P3_INSTR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000001B8ull)
-#define CVMX_NPI_P3_PAIR_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000178ull)
-#define CVMX_NPI_PCI_BAR1_INDEXX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000001100ull + (((offset) & 31) * 4))
-#define CVMX_NPI_PCI_BIST_REG \
-	 CVMX_ADD_IO_SEG(0x00011F00000011C0ull)
-#define CVMX_NPI_PCI_BURST_SIZE \
-	 CVMX_ADD_IO_SEG(0x00011F00000000D8ull)
-#define CVMX_NPI_PCI_CFG00 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001800ull)
-#define CVMX_NPI_PCI_CFG01 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001804ull)
-#define CVMX_NPI_PCI_CFG02 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001808ull)
-#define CVMX_NPI_PCI_CFG03 \
-	 CVMX_ADD_IO_SEG(0x00011F000000180Cull)
-#define CVMX_NPI_PCI_CFG04 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001810ull)
-#define CVMX_NPI_PCI_CFG05 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001814ull)
-#define CVMX_NPI_PCI_CFG06 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001818ull)
-#define CVMX_NPI_PCI_CFG07 \
-	 CVMX_ADD_IO_SEG(0x00011F000000181Cull)
-#define CVMX_NPI_PCI_CFG08 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001820ull)
-#define CVMX_NPI_PCI_CFG09 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001824ull)
-#define CVMX_NPI_PCI_CFG10 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001828ull)
-#define CVMX_NPI_PCI_CFG11 \
-	 CVMX_ADD_IO_SEG(0x00011F000000182Cull)
-#define CVMX_NPI_PCI_CFG12 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001830ull)
-#define CVMX_NPI_PCI_CFG13 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001834ull)
-#define CVMX_NPI_PCI_CFG15 \
-	 CVMX_ADD_IO_SEG(0x00011F000000183Cull)
-#define CVMX_NPI_PCI_CFG16 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001840ull)
-#define CVMX_NPI_PCI_CFG17 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001844ull)
-#define CVMX_NPI_PCI_CFG18 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001848ull)
-#define CVMX_NPI_PCI_CFG19 \
-	 CVMX_ADD_IO_SEG(0x00011F000000184Cull)
-#define CVMX_NPI_PCI_CFG20 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001850ull)
-#define CVMX_NPI_PCI_CFG21 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001854ull)
-#define CVMX_NPI_PCI_CFG22 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001858ull)
-#define CVMX_NPI_PCI_CFG56 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018E0ull)
-#define CVMX_NPI_PCI_CFG57 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018E4ull)
-#define CVMX_NPI_PCI_CFG58 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018E8ull)
-#define CVMX_NPI_PCI_CFG59 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018ECull)
-#define CVMX_NPI_PCI_CFG60 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018F0ull)
-#define CVMX_NPI_PCI_CFG61 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018F4ull)
-#define CVMX_NPI_PCI_CFG62 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018F8ull)
-#define CVMX_NPI_PCI_CFG63 \
-	 CVMX_ADD_IO_SEG(0x00011F00000018FCull)
-#define CVMX_NPI_PCI_CNT_REG \
-	 CVMX_ADD_IO_SEG(0x00011F00000011B8ull)
-#define CVMX_NPI_PCI_CTL_STATUS_2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000118Cull)
-#define CVMX_NPI_PCI_INT_ARB_CFG \
-	 CVMX_ADD_IO_SEG(0x00011F0000000130ull)
-#define CVMX_NPI_PCI_INT_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F00000011A0ull)
-#define CVMX_NPI_PCI_INT_SUM2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001198ull)
-#define CVMX_NPI_PCI_READ_CMD \
-	 CVMX_ADD_IO_SEG(0x00011F0000000048ull)
-#define CVMX_NPI_PCI_READ_CMD_6 \
-	 CVMX_ADD_IO_SEG(0x00011F0000001180ull)
-#define CVMX_NPI_PCI_READ_CMD_C \
-	 CVMX_ADD_IO_SEG(0x00011F0000001184ull)
-#define CVMX_NPI_PCI_READ_CMD_E \
-	 CVMX_ADD_IO_SEG(0x00011F0000001188ull)
-#define CVMX_NPI_PCI_SCM_REG \
-	 CVMX_ADD_IO_SEG(0x00011F00000011A8ull)
-#define CVMX_NPI_PCI_TSR_REG \
-	 CVMX_ADD_IO_SEG(0x00011F00000011B0ull)
-#define CVMX_NPI_PORT32_INSTR_HDR \
-	 CVMX_ADD_IO_SEG(0x00011F00000001F8ull)
-#define CVMX_NPI_PORT33_INSTR_HDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000200ull)
-#define CVMX_NPI_PORT34_INSTR_HDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000208ull)
-#define CVMX_NPI_PORT35_INSTR_HDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000000210ull)
-#define CVMX_NPI_PORT_BP_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F00000001F0ull)
-#define CVMX_NPI_PX_DBPAIR_ADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000180ull + (((offset) & 3) * 8))
-#define CVMX_NPI_PX_INSTR_ADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000001C0ull + (((offset) & 3) * 8))
-#define CVMX_NPI_PX_INSTR_CNTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000001A0ull + (((offset) & 3) * 8))
-#define CVMX_NPI_PX_PAIR_CNTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000160ull + (((offset) & 3) * 8))
-#define CVMX_NPI_RSL_INT_BLOCKS \
-	 CVMX_ADD_IO_SEG(0x00011F0000000000ull)
-#define CVMX_NPI_SIZE_INPUT0 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000078ull)
-#define CVMX_NPI_SIZE_INPUT1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000088ull)
-#define CVMX_NPI_SIZE_INPUT2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000000098ull)
-#define CVMX_NPI_SIZE_INPUT3 \
-	 CVMX_ADD_IO_SEG(0x00011F00000000A8ull)
-#define CVMX_NPI_SIZE_INPUTX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000000078ull + (((offset) & 3) * 16))
-#define CVMX_NPI_WIN_READ_TO \
-	 CVMX_ADD_IO_SEG(0x00011F00000001E0ull)
+#define CVMX_NPI_BASE_ADDR_INPUT0 CVMX_NPI_BASE_ADDR_INPUTX(0)
+#define CVMX_NPI_BASE_ADDR_INPUT1 CVMX_NPI_BASE_ADDR_INPUTX(1)
+#define CVMX_NPI_BASE_ADDR_INPUT2 CVMX_NPI_BASE_ADDR_INPUTX(2)
+#define CVMX_NPI_BASE_ADDR_INPUT3 CVMX_NPI_BASE_ADDR_INPUTX(3)
+#define CVMX_NPI_BASE_ADDR_INPUTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000000070ull) + ((offset) & 3) * 16)
+#define CVMX_NPI_BASE_ADDR_OUTPUT0 CVMX_NPI_BASE_ADDR_OUTPUTX(0)
+#define CVMX_NPI_BASE_ADDR_OUTPUT1 CVMX_NPI_BASE_ADDR_OUTPUTX(1)
+#define CVMX_NPI_BASE_ADDR_OUTPUT2 CVMX_NPI_BASE_ADDR_OUTPUTX(2)
+#define CVMX_NPI_BASE_ADDR_OUTPUT3 CVMX_NPI_BASE_ADDR_OUTPUTX(3)
+#define CVMX_NPI_BASE_ADDR_OUTPUTX(offset) (CVMX_ADD_IO_SEG(0x00011F00000000B8ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011F00000003F8ull))
+#define CVMX_NPI_BUFF_SIZE_OUTPUT0 CVMX_NPI_BUFF_SIZE_OUTPUTX(0)
+#define CVMX_NPI_BUFF_SIZE_OUTPUT1 CVMX_NPI_BUFF_SIZE_OUTPUTX(1)
+#define CVMX_NPI_BUFF_SIZE_OUTPUT2 CVMX_NPI_BUFF_SIZE_OUTPUTX(2)
+#define CVMX_NPI_BUFF_SIZE_OUTPUT3 CVMX_NPI_BUFF_SIZE_OUTPUTX(3)
+#define CVMX_NPI_BUFF_SIZE_OUTPUTX(offset) (CVMX_ADD_IO_SEG(0x00011F00000000E0ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_COMP_CTL (CVMX_ADD_IO_SEG(0x00011F0000000218ull))
+#define CVMX_NPI_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011F0000000010ull))
+#define CVMX_NPI_DBG_SELECT (CVMX_ADD_IO_SEG(0x00011F0000000008ull))
+#define CVMX_NPI_DMA_CONTROL (CVMX_ADD_IO_SEG(0x00011F0000000128ull))
+#define CVMX_NPI_DMA_HIGHP_COUNTS (CVMX_ADD_IO_SEG(0x00011F0000000148ull))
+#define CVMX_NPI_DMA_HIGHP_NADDR (CVMX_ADD_IO_SEG(0x00011F0000000158ull))
+#define CVMX_NPI_DMA_LOWP_COUNTS (CVMX_ADD_IO_SEG(0x00011F0000000140ull))
+#define CVMX_NPI_DMA_LOWP_NADDR (CVMX_ADD_IO_SEG(0x00011F0000000150ull))
+#define CVMX_NPI_HIGHP_DBELL (CVMX_ADD_IO_SEG(0x00011F0000000120ull))
+#define CVMX_NPI_HIGHP_IBUFF_SADDR (CVMX_ADD_IO_SEG(0x00011F0000000110ull))
+#define CVMX_NPI_INPUT_CONTROL (CVMX_ADD_IO_SEG(0x00011F0000000138ull))
+#define CVMX_NPI_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000000020ull))
+#define CVMX_NPI_INT_SUM (CVMX_ADD_IO_SEG(0x00011F0000000018ull))
+#define CVMX_NPI_LOWP_DBELL (CVMX_ADD_IO_SEG(0x00011F0000000118ull))
+#define CVMX_NPI_LOWP_IBUFF_SADDR (CVMX_ADD_IO_SEG(0x00011F0000000108ull))
+#define CVMX_NPI_MEM_ACCESS_SUBID3 CVMX_NPI_MEM_ACCESS_SUBIDX(3)
+#define CVMX_NPI_MEM_ACCESS_SUBID4 CVMX_NPI_MEM_ACCESS_SUBIDX(4)
+#define CVMX_NPI_MEM_ACCESS_SUBID5 CVMX_NPI_MEM_ACCESS_SUBIDX(5)
+#define CVMX_NPI_MEM_ACCESS_SUBID6 CVMX_NPI_MEM_ACCESS_SUBIDX(6)
+#define CVMX_NPI_MEM_ACCESS_SUBIDX(offset) (CVMX_ADD_IO_SEG(0x00011F0000000028ull) + ((offset) & 7) * 8 - 8*3)
+#define CVMX_NPI_MSI_RCV (0x0000000000000190ull)
+#define CVMX_NPI_NPI_MSI_RCV (CVMX_ADD_IO_SEG(0x00011F0000001190ull))
+#define CVMX_NPI_NUM_DESC_OUTPUT0 CVMX_NPI_NUM_DESC_OUTPUTX(0)
+#define CVMX_NPI_NUM_DESC_OUTPUT1 CVMX_NPI_NUM_DESC_OUTPUTX(1)
+#define CVMX_NPI_NUM_DESC_OUTPUT2 CVMX_NPI_NUM_DESC_OUTPUTX(2)
+#define CVMX_NPI_NUM_DESC_OUTPUT3 CVMX_NPI_NUM_DESC_OUTPUTX(3)
+#define CVMX_NPI_NUM_DESC_OUTPUTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000000050ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_OUTPUT_CONTROL (CVMX_ADD_IO_SEG(0x00011F0000000100ull))
+#define CVMX_NPI_P0_DBPAIR_ADDR CVMX_NPI_PX_DBPAIR_ADDR(0)
+#define CVMX_NPI_P0_INSTR_ADDR CVMX_NPI_PX_INSTR_ADDR(0)
+#define CVMX_NPI_P0_INSTR_CNTS CVMX_NPI_PX_INSTR_CNTS(0)
+#define CVMX_NPI_P0_PAIR_CNTS CVMX_NPI_PX_PAIR_CNTS(0)
+#define CVMX_NPI_P1_DBPAIR_ADDR CVMX_NPI_PX_DBPAIR_ADDR(1)
+#define CVMX_NPI_P1_INSTR_ADDR CVMX_NPI_PX_INSTR_ADDR(1)
+#define CVMX_NPI_P1_INSTR_CNTS CVMX_NPI_PX_INSTR_CNTS(1)
+#define CVMX_NPI_P1_PAIR_CNTS CVMX_NPI_PX_PAIR_CNTS(1)
+#define CVMX_NPI_P2_DBPAIR_ADDR CVMX_NPI_PX_DBPAIR_ADDR(2)
+#define CVMX_NPI_P2_INSTR_ADDR CVMX_NPI_PX_INSTR_ADDR(2)
+#define CVMX_NPI_P2_INSTR_CNTS CVMX_NPI_PX_INSTR_CNTS(2)
+#define CVMX_NPI_P2_PAIR_CNTS CVMX_NPI_PX_PAIR_CNTS(2)
+#define CVMX_NPI_P3_DBPAIR_ADDR CVMX_NPI_PX_DBPAIR_ADDR(3)
+#define CVMX_NPI_P3_INSTR_ADDR CVMX_NPI_PX_INSTR_ADDR(3)
+#define CVMX_NPI_P3_INSTR_CNTS CVMX_NPI_PX_INSTR_CNTS(3)
+#define CVMX_NPI_P3_PAIR_CNTS CVMX_NPI_PX_PAIR_CNTS(3)
+#define CVMX_NPI_PCI_BAR1_INDEXX(offset) (CVMX_ADD_IO_SEG(0x00011F0000001100ull) + ((offset) & 31) * 4)
+#define CVMX_NPI_PCI_BIST_REG (CVMX_ADD_IO_SEG(0x00011F00000011C0ull))
+#define CVMX_NPI_PCI_BURST_SIZE (CVMX_ADD_IO_SEG(0x00011F00000000D8ull))
+#define CVMX_NPI_PCI_CFG00 (CVMX_ADD_IO_SEG(0x00011F0000001800ull))
+#define CVMX_NPI_PCI_CFG01 (CVMX_ADD_IO_SEG(0x00011F0000001804ull))
+#define CVMX_NPI_PCI_CFG02 (CVMX_ADD_IO_SEG(0x00011F0000001808ull))
+#define CVMX_NPI_PCI_CFG03 (CVMX_ADD_IO_SEG(0x00011F000000180Cull))
+#define CVMX_NPI_PCI_CFG04 (CVMX_ADD_IO_SEG(0x00011F0000001810ull))
+#define CVMX_NPI_PCI_CFG05 (CVMX_ADD_IO_SEG(0x00011F0000001814ull))
+#define CVMX_NPI_PCI_CFG06 (CVMX_ADD_IO_SEG(0x00011F0000001818ull))
+#define CVMX_NPI_PCI_CFG07 (CVMX_ADD_IO_SEG(0x00011F000000181Cull))
+#define CVMX_NPI_PCI_CFG08 (CVMX_ADD_IO_SEG(0x00011F0000001820ull))
+#define CVMX_NPI_PCI_CFG09 (CVMX_ADD_IO_SEG(0x00011F0000001824ull))
+#define CVMX_NPI_PCI_CFG10 (CVMX_ADD_IO_SEG(0x00011F0000001828ull))
+#define CVMX_NPI_PCI_CFG11 (CVMX_ADD_IO_SEG(0x00011F000000182Cull))
+#define CVMX_NPI_PCI_CFG12 (CVMX_ADD_IO_SEG(0x00011F0000001830ull))
+#define CVMX_NPI_PCI_CFG13 (CVMX_ADD_IO_SEG(0x00011F0000001834ull))
+#define CVMX_NPI_PCI_CFG15 (CVMX_ADD_IO_SEG(0x00011F000000183Cull))
+#define CVMX_NPI_PCI_CFG16 (CVMX_ADD_IO_SEG(0x00011F0000001840ull))
+#define CVMX_NPI_PCI_CFG17 (CVMX_ADD_IO_SEG(0x00011F0000001844ull))
+#define CVMX_NPI_PCI_CFG18 (CVMX_ADD_IO_SEG(0x00011F0000001848ull))
+#define CVMX_NPI_PCI_CFG19 (CVMX_ADD_IO_SEG(0x00011F000000184Cull))
+#define CVMX_NPI_PCI_CFG20 (CVMX_ADD_IO_SEG(0x00011F0000001850ull))
+#define CVMX_NPI_PCI_CFG21 (CVMX_ADD_IO_SEG(0x00011F0000001854ull))
+#define CVMX_NPI_PCI_CFG22 (CVMX_ADD_IO_SEG(0x00011F0000001858ull))
+#define CVMX_NPI_PCI_CFG56 (CVMX_ADD_IO_SEG(0x00011F00000018E0ull))
+#define CVMX_NPI_PCI_CFG57 (CVMX_ADD_IO_SEG(0x00011F00000018E4ull))
+#define CVMX_NPI_PCI_CFG58 (CVMX_ADD_IO_SEG(0x00011F00000018E8ull))
+#define CVMX_NPI_PCI_CFG59 (CVMX_ADD_IO_SEG(0x00011F00000018ECull))
+#define CVMX_NPI_PCI_CFG60 (CVMX_ADD_IO_SEG(0x00011F00000018F0ull))
+#define CVMX_NPI_PCI_CFG61 (CVMX_ADD_IO_SEG(0x00011F00000018F4ull))
+#define CVMX_NPI_PCI_CFG62 (CVMX_ADD_IO_SEG(0x00011F00000018F8ull))
+#define CVMX_NPI_PCI_CFG63 (CVMX_ADD_IO_SEG(0x00011F00000018FCull))
+#define CVMX_NPI_PCI_CNT_REG (CVMX_ADD_IO_SEG(0x00011F00000011B8ull))
+#define CVMX_NPI_PCI_CTL_STATUS_2 (CVMX_ADD_IO_SEG(0x00011F000000118Cull))
+#define CVMX_NPI_PCI_INT_ARB_CFG (CVMX_ADD_IO_SEG(0x00011F0000000130ull))
+#define CVMX_NPI_PCI_INT_ENB2 (CVMX_ADD_IO_SEG(0x00011F00000011A0ull))
+#define CVMX_NPI_PCI_INT_SUM2 (CVMX_ADD_IO_SEG(0x00011F0000001198ull))
+#define CVMX_NPI_PCI_READ_CMD (CVMX_ADD_IO_SEG(0x00011F0000000048ull))
+#define CVMX_NPI_PCI_READ_CMD_6 (CVMX_ADD_IO_SEG(0x00011F0000001180ull))
+#define CVMX_NPI_PCI_READ_CMD_C (CVMX_ADD_IO_SEG(0x00011F0000001184ull))
+#define CVMX_NPI_PCI_READ_CMD_E (CVMX_ADD_IO_SEG(0x00011F0000001188ull))
+#define CVMX_NPI_PCI_SCM_REG (CVMX_ADD_IO_SEG(0x00011F00000011A8ull))
+#define CVMX_NPI_PCI_TSR_REG (CVMX_ADD_IO_SEG(0x00011F00000011B0ull))
+#define CVMX_NPI_PORT32_INSTR_HDR (CVMX_ADD_IO_SEG(0x00011F00000001F8ull))
+#define CVMX_NPI_PORT33_INSTR_HDR (CVMX_ADD_IO_SEG(0x00011F0000000200ull))
+#define CVMX_NPI_PORT34_INSTR_HDR (CVMX_ADD_IO_SEG(0x00011F0000000208ull))
+#define CVMX_NPI_PORT35_INSTR_HDR (CVMX_ADD_IO_SEG(0x00011F0000000210ull))
+#define CVMX_NPI_PORT_BP_CONTROL (CVMX_ADD_IO_SEG(0x00011F00000001F0ull))
+#define CVMX_NPI_PX_DBPAIR_ADDR(offset) (CVMX_ADD_IO_SEG(0x00011F0000000180ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_PX_INSTR_ADDR(offset) (CVMX_ADD_IO_SEG(0x00011F00000001C0ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_PX_INSTR_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F00000001A0ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_PX_PAIR_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F0000000160ull) + ((offset) & 3) * 8)
+#define CVMX_NPI_RSL_INT_BLOCKS (CVMX_ADD_IO_SEG(0x00011F0000000000ull))
+#define CVMX_NPI_SIZE_INPUT0 CVMX_NPI_SIZE_INPUTX(0)
+#define CVMX_NPI_SIZE_INPUT1 CVMX_NPI_SIZE_INPUTX(1)
+#define CVMX_NPI_SIZE_INPUT2 CVMX_NPI_SIZE_INPUTX(2)
+#define CVMX_NPI_SIZE_INPUT3 CVMX_NPI_SIZE_INPUTX(3)
+#define CVMX_NPI_SIZE_INPUTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000000078ull) + ((offset) & 3) * 16)
+#define CVMX_NPI_WIN_READ_TO (CVMX_ADD_IO_SEG(0x00011F00000001E0ull))
 
 union cvmx_npi_base_addr_inputx {
 	uint64_t u64;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pci-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pci-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pci-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pci-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,184 +28,91 @@
 #ifndef __CVMX_PCI_DEFS_H__
 #define __CVMX_PCI_DEFS_H__
 
-#define CVMX_PCI_BAR1_INDEXX(offset) \
-	 (0x0000000000000100ull + (((offset) & 31) * 4))
-#define CVMX_PCI_BIST_REG \
-	 (0x00000000000001C0ull)
-#define CVMX_PCI_CFG00 \
-	 (0x0000000000000000ull)
-#define CVMX_PCI_CFG01 \
-	 (0x0000000000000004ull)
-#define CVMX_PCI_CFG02 \
-	 (0x0000000000000008ull)
-#define CVMX_PCI_CFG03 \
-	 (0x000000000000000Cull)
-#define CVMX_PCI_CFG04 \
-	 (0x0000000000000010ull)
-#define CVMX_PCI_CFG05 \
-	 (0x0000000000000014ull)
-#define CVMX_PCI_CFG06 \
-	 (0x0000000000000018ull)
-#define CVMX_PCI_CFG07 \
-	 (0x000000000000001Cull)
-#define CVMX_PCI_CFG08 \
-	 (0x0000000000000020ull)
-#define CVMX_PCI_CFG09 \
-	 (0x0000000000000024ull)
-#define CVMX_PCI_CFG10 \
-	 (0x0000000000000028ull)
-#define CVMX_PCI_CFG11 \
-	 (0x000000000000002Cull)
-#define CVMX_PCI_CFG12 \
-	 (0x0000000000000030ull)
-#define CVMX_PCI_CFG13 \
-	 (0x0000000000000034ull)
-#define CVMX_PCI_CFG15 \
-	 (0x000000000000003Cull)
-#define CVMX_PCI_CFG16 \
-	 (0x0000000000000040ull)
-#define CVMX_PCI_CFG17 \
-	 (0x0000000000000044ull)
-#define CVMX_PCI_CFG18 \
-	 (0x0000000000000048ull)
-#define CVMX_PCI_CFG19 \
-	 (0x000000000000004Cull)
-#define CVMX_PCI_CFG20 \
-	 (0x0000000000000050ull)
-#define CVMX_PCI_CFG21 \
-	 (0x0000000000000054ull)
-#define CVMX_PCI_CFG22 \
-	 (0x0000000000000058ull)
-#define CVMX_PCI_CFG56 \
-	 (0x00000000000000E0ull)
-#define CVMX_PCI_CFG57 \
-	 (0x00000000000000E4ull)
-#define CVMX_PCI_CFG58 \
-	 (0x00000000000000E8ull)
-#define CVMX_PCI_CFG59 \
-	 (0x00000000000000ECull)
-#define CVMX_PCI_CFG60 \
-	 (0x00000000000000F0ull)
-#define CVMX_PCI_CFG61 \
-	 (0x00000000000000F4ull)
-#define CVMX_PCI_CFG62 \
-	 (0x00000000000000F8ull)
-#define CVMX_PCI_CFG63 \
-	 (0x00000000000000FCull)
-#define CVMX_PCI_CNT_REG \
-	 (0x00000000000001B8ull)
-#define CVMX_PCI_CTL_STATUS_2 \
-	 (0x000000000000018Cull)
-#define CVMX_PCI_DBELL_0 \
-	 (0x0000000000000080ull)
-#define CVMX_PCI_DBELL_1 \
-	 (0x0000000000000088ull)
-#define CVMX_PCI_DBELL_2 \
-	 (0x0000000000000090ull)
-#define CVMX_PCI_DBELL_3 \
-	 (0x0000000000000098ull)
-#define CVMX_PCI_DBELL_X(offset) \
-	 (0x0000000000000080ull + (((offset) & 3) * 8))
-#define CVMX_PCI_DMA_CNT0 \
-	 (0x00000000000000A0ull)
-#define CVMX_PCI_DMA_CNT1 \
-	 (0x00000000000000A8ull)
-#define CVMX_PCI_DMA_CNTX(offset) \
-	 (0x00000000000000A0ull + (((offset) & 1) * 8))
-#define CVMX_PCI_DMA_INT_LEV0 \
-	 (0x00000000000000A4ull)
-#define CVMX_PCI_DMA_INT_LEV1 \
-	 (0x00000000000000ACull)
-#define CVMX_PCI_DMA_INT_LEVX(offset) \
-	 (0x00000000000000A4ull + (((offset) & 1) * 8))
-#define CVMX_PCI_DMA_TIME0 \
-	 (0x00000000000000B0ull)
-#define CVMX_PCI_DMA_TIME1 \
-	 (0x00000000000000B4ull)
-#define CVMX_PCI_DMA_TIMEX(offset) \
-	 (0x00000000000000B0ull + (((offset) & 1) * 4))
-#define CVMX_PCI_INSTR_COUNT0 \
-	 (0x0000000000000084ull)
-#define CVMX_PCI_INSTR_COUNT1 \
-	 (0x000000000000008Cull)
-#define CVMX_PCI_INSTR_COUNT2 \
-	 (0x0000000000000094ull)
-#define CVMX_PCI_INSTR_COUNT3 \
-	 (0x000000000000009Cull)
-#define CVMX_PCI_INSTR_COUNTX(offset) \
-	 (0x0000000000000084ull + (((offset) & 3) * 8))
-#define CVMX_PCI_INT_ENB \
-	 (0x0000000000000038ull)
-#define CVMX_PCI_INT_ENB2 \
-	 (0x00000000000001A0ull)
-#define CVMX_PCI_INT_SUM \
-	 (0x0000000000000030ull)
-#define CVMX_PCI_INT_SUM2 \
-	 (0x0000000000000198ull)
-#define CVMX_PCI_MSI_RCV \
-	 (0x00000000000000F0ull)
-#define CVMX_PCI_PKTS_SENT0 \
-	 (0x0000000000000040ull)
-#define CVMX_PCI_PKTS_SENT1 \
-	 (0x0000000000000050ull)
-#define CVMX_PCI_PKTS_SENT2 \
-	 (0x0000000000000060ull)
-#define CVMX_PCI_PKTS_SENT3 \
-	 (0x0000000000000070ull)
-#define CVMX_PCI_PKTS_SENTX(offset) \
-	 (0x0000000000000040ull + (((offset) & 3) * 16))
-#define CVMX_PCI_PKTS_SENT_INT_LEV0 \
-	 (0x0000000000000048ull)
-#define CVMX_PCI_PKTS_SENT_INT_LEV1 \
-	 (0x0000000000000058ull)
-#define CVMX_PCI_PKTS_SENT_INT_LEV2 \
-	 (0x0000000000000068ull)
-#define CVMX_PCI_PKTS_SENT_INT_LEV3 \
-	 (0x0000000000000078ull)
-#define CVMX_PCI_PKTS_SENT_INT_LEVX(offset) \
-	 (0x0000000000000048ull + (((offset) & 3) * 16))
-#define CVMX_PCI_PKTS_SENT_TIME0 \
-	 (0x000000000000004Cull)
-#define CVMX_PCI_PKTS_SENT_TIME1 \
-	 (0x000000000000005Cull)
-#define CVMX_PCI_PKTS_SENT_TIME2 \
-	 (0x000000000000006Cull)
-#define CVMX_PCI_PKTS_SENT_TIME3 \
-	 (0x000000000000007Cull)
-#define CVMX_PCI_PKTS_SENT_TIMEX(offset) \
-	 (0x000000000000004Cull + (((offset) & 3) * 16))
-#define CVMX_PCI_PKT_CREDITS0 \
-	 (0x0000000000000044ull)
-#define CVMX_PCI_PKT_CREDITS1 \
-	 (0x0000000000000054ull)
-#define CVMX_PCI_PKT_CREDITS2 \
-	 (0x0000000000000064ull)
-#define CVMX_PCI_PKT_CREDITS3 \
-	 (0x0000000000000074ull)
-#define CVMX_PCI_PKT_CREDITSX(offset) \
-	 (0x0000000000000044ull + (((offset) & 3) * 16))
-#define CVMX_PCI_READ_CMD_6 \
-	 (0x0000000000000180ull)
-#define CVMX_PCI_READ_CMD_C \
-	 (0x0000000000000184ull)
-#define CVMX_PCI_READ_CMD_E \
-	 (0x0000000000000188ull)
-#define CVMX_PCI_READ_TIMEOUT \
-	 CVMX_ADD_IO_SEG(0x00011F00000000B0ull)
-#define CVMX_PCI_SCM_REG \
-	 (0x00000000000001A8ull)
-#define CVMX_PCI_TSR_REG \
-	 (0x00000000000001B0ull)
-#define CVMX_PCI_WIN_RD_ADDR \
-	 (0x0000000000000008ull)
-#define CVMX_PCI_WIN_RD_DATA \
-	 (0x0000000000000020ull)
-#define CVMX_PCI_WIN_WR_ADDR \
-	 (0x0000000000000000ull)
-#define CVMX_PCI_WIN_WR_DATA \
-	 (0x0000000000000010ull)
-#define CVMX_PCI_WIN_WR_MASK \
-	 (0x0000000000000018ull)
+#define CVMX_PCI_BAR1_INDEXX(offset) (0x0000000000000100ull + ((offset) & 31) * 4)
+#define CVMX_PCI_BIST_REG (0x00000000000001C0ull)
+#define CVMX_PCI_CFG00 (0x0000000000000000ull)
+#define CVMX_PCI_CFG01 (0x0000000000000004ull)
+#define CVMX_PCI_CFG02 (0x0000000000000008ull)
+#define CVMX_PCI_CFG03 (0x000000000000000Cull)
+#define CVMX_PCI_CFG04 (0x0000000000000010ull)
+#define CVMX_PCI_CFG05 (0x0000000000000014ull)
+#define CVMX_PCI_CFG06 (0x0000000000000018ull)
+#define CVMX_PCI_CFG07 (0x000000000000001Cull)
+#define CVMX_PCI_CFG08 (0x0000000000000020ull)
+#define CVMX_PCI_CFG09 (0x0000000000000024ull)
+#define CVMX_PCI_CFG10 (0x0000000000000028ull)
+#define CVMX_PCI_CFG11 (0x000000000000002Cull)
+#define CVMX_PCI_CFG12 (0x0000000000000030ull)
+#define CVMX_PCI_CFG13 (0x0000000000000034ull)
+#define CVMX_PCI_CFG15 (0x000000000000003Cull)
+#define CVMX_PCI_CFG16 (0x0000000000000040ull)
+#define CVMX_PCI_CFG17 (0x0000000000000044ull)
+#define CVMX_PCI_CFG18 (0x0000000000000048ull)
+#define CVMX_PCI_CFG19 (0x000000000000004Cull)
+#define CVMX_PCI_CFG20 (0x0000000000000050ull)
+#define CVMX_PCI_CFG21 (0x0000000000000054ull)
+#define CVMX_PCI_CFG22 (0x0000000000000058ull)
+#define CVMX_PCI_CFG56 (0x00000000000000E0ull)
+#define CVMX_PCI_CFG57 (0x00000000000000E4ull)
+#define CVMX_PCI_CFG58 (0x00000000000000E8ull)
+#define CVMX_PCI_CFG59 (0x00000000000000ECull)
+#define CVMX_PCI_CFG60 (0x00000000000000F0ull)
+#define CVMX_PCI_CFG61 (0x00000000000000F4ull)
+#define CVMX_PCI_CFG62 (0x00000000000000F8ull)
+#define CVMX_PCI_CFG63 (0x00000000000000FCull)
+#define CVMX_PCI_CNT_REG (0x00000000000001B8ull)
+#define CVMX_PCI_CTL_STATUS_2 (0x000000000000018Cull)
+#define CVMX_PCI_DBELL_X(offset) (0x0000000000000080ull + ((offset) & 3) * 8)
+#define CVMX_PCI_DMA_CNT0 CVMX_PCI_DMA_CNTX(0)
+#define CVMX_PCI_DMA_CNT1 CVMX_PCI_DMA_CNTX(1)
+#define CVMX_PCI_DMA_CNTX(offset) (0x00000000000000A0ull + ((offset) & 1) * 8)
+#define CVMX_PCI_DMA_INT_LEV0 CVMX_PCI_DMA_INT_LEVX(0)
+#define CVMX_PCI_DMA_INT_LEV1 CVMX_PCI_DMA_INT_LEVX(1)
+#define CVMX_PCI_DMA_INT_LEVX(offset) (0x00000000000000A4ull + ((offset) & 1) * 8)
+#define CVMX_PCI_DMA_TIME0 CVMX_PCI_DMA_TIMEX(0)
+#define CVMX_PCI_DMA_TIME1 CVMX_PCI_DMA_TIMEX(1)
+#define CVMX_PCI_DMA_TIMEX(offset) (0x00000000000000B0ull + ((offset) & 1) * 4)
+#define CVMX_PCI_INSTR_COUNT0 CVMX_PCI_INSTR_COUNTX(0)
+#define CVMX_PCI_INSTR_COUNT1 CVMX_PCI_INSTR_COUNTX(1)
+#define CVMX_PCI_INSTR_COUNT2 CVMX_PCI_INSTR_COUNTX(2)
+#define CVMX_PCI_INSTR_COUNT3 CVMX_PCI_INSTR_COUNTX(3)
+#define CVMX_PCI_INSTR_COUNTX(offset) (0x0000000000000084ull + ((offset) & 3) * 8)
+#define CVMX_PCI_INT_ENB (0x0000000000000038ull)
+#define CVMX_PCI_INT_ENB2 (0x00000000000001A0ull)
+#define CVMX_PCI_INT_SUM (0x0000000000000030ull)
+#define CVMX_PCI_INT_SUM2 (0x0000000000000198ull)
+#define CVMX_PCI_MSI_RCV (0x00000000000000F0ull)
+#define CVMX_PCI_PKTS_SENT0 CVMX_PCI_PKTS_SENTX(0)
+#define CVMX_PCI_PKTS_SENT1 CVMX_PCI_PKTS_SENTX(1)
+#define CVMX_PCI_PKTS_SENT2 CVMX_PCI_PKTS_SENTX(2)
+#define CVMX_PCI_PKTS_SENT3 CVMX_PCI_PKTS_SENTX(3)
+#define CVMX_PCI_PKTS_SENTX(offset) (0x0000000000000040ull + ((offset) & 3) * 16)
+#define CVMX_PCI_PKTS_SENT_INT_LEV0 CVMX_PCI_PKTS_SENT_INT_LEVX(0)
+#define CVMX_PCI_PKTS_SENT_INT_LEV1 CVMX_PCI_PKTS_SENT_INT_LEVX(1)
+#define CVMX_PCI_PKTS_SENT_INT_LEV2 CVMX_PCI_PKTS_SENT_INT_LEVX(2)
+#define CVMX_PCI_PKTS_SENT_INT_LEV3 CVMX_PCI_PKTS_SENT_INT_LEVX(3)
+#define CVMX_PCI_PKTS_SENT_INT_LEVX(offset) (0x0000000000000048ull + ((offset) & 3) * 16)
+#define CVMX_PCI_PKTS_SENT_TIME0 CVMX_PCI_PKTS_SENT_TIMEX(0)
+#define CVMX_PCI_PKTS_SENT_TIME1 CVMX_PCI_PKTS_SENT_TIMEX(1)
+#define CVMX_PCI_PKTS_SENT_TIME2 CVMX_PCI_PKTS_SENT_TIMEX(2)
+#define CVMX_PCI_PKTS_SENT_TIME3 CVMX_PCI_PKTS_SENT_TIMEX(3)
+#define CVMX_PCI_PKTS_SENT_TIMEX(offset) (0x000000000000004Cull + ((offset) & 3) * 16)
+#define CVMX_PCI_PKT_CREDITS0 CVMX_PCI_PKT_CREDITSX(0)
+#define CVMX_PCI_PKT_CREDITS1 CVMX_PCI_PKT_CREDITSX(1)
+#define CVMX_PCI_PKT_CREDITS2 CVMX_PCI_PKT_CREDITSX(2)
+#define CVMX_PCI_PKT_CREDITS3 CVMX_PCI_PKT_CREDITSX(3)
+#define CVMX_PCI_PKT_CREDITSX(offset) (0x0000000000000044ull + ((offset) & 3) * 16)
+#define CVMX_PCI_READ_CMD_6 (0x0000000000000180ull)
+#define CVMX_PCI_READ_CMD_C (0x0000000000000184ull)
+#define CVMX_PCI_READ_CMD_E (0x0000000000000188ull)
+#define CVMX_PCI_READ_TIMEOUT (CVMX_ADD_IO_SEG(0x00011F00000000B0ull))
+#define CVMX_PCI_SCM_REG (0x00000000000001A8ull)
+#define CVMX_PCI_TSR_REG (0x00000000000001B0ull)
+#define CVMX_PCI_WIN_RD_ADDR (0x0000000000000008ull)
+#define CVMX_PCI_WIN_RD_DATA (0x0000000000000020ull)
+#define CVMX_PCI_WIN_WR_ADDR (0x0000000000000000ull)
+#define CVMX_PCI_WIN_WR_DATA (0x0000000000000010ull)
+#define CVMX_PCI_WIN_WR_MASK (0x0000000000000018ull)
 
 union cvmx_pci_bar1_indexx {
 	uint32_t u32;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pciercx-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,158 +28,83 @@
 #ifndef __CVMX_PCIERCX_DEFS_H__
 #define __CVMX_PCIERCX_DEFS_H__
 
-#define CVMX_PCIERCX_CFG000(offset) \
-	 (0x0000000000000000ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG001(offset) \
-	 (0x0000000000000004ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG002(offset) \
-	 (0x0000000000000008ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG003(offset) \
-	 (0x000000000000000Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG004(offset) \
-	 (0x0000000000000010ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG005(offset) \
-	 (0x0000000000000014ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG006(offset) \
-	 (0x0000000000000018ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG007(offset) \
-	 (0x000000000000001Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG008(offset) \
-	 (0x0000000000000020ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG009(offset) \
-	 (0x0000000000000024ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG010(offset) \
-	 (0x0000000000000028ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG011(offset) \
-	 (0x000000000000002Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG012(offset) \
-	 (0x0000000000000030ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG013(offset) \
-	 (0x0000000000000034ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG014(offset) \
-	 (0x0000000000000038ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG015(offset) \
-	 (0x000000000000003Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG016(offset) \
-	 (0x0000000000000040ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG017(offset) \
-	 (0x0000000000000044ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG020(offset) \
-	 (0x0000000000000050ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG021(offset) \
-	 (0x0000000000000054ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG022(offset) \
-	 (0x0000000000000058ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG023(offset) \
-	 (0x000000000000005Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG028(offset) \
-	 (0x0000000000000070ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG029(offset) \
-	 (0x0000000000000074ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG030(offset) \
-	 (0x0000000000000078ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG031(offset) \
-	 (0x000000000000007Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG032(offset) \
-	 (0x0000000000000080ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG033(offset) \
-	 (0x0000000000000084ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG034(offset) \
-	 (0x0000000000000088ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG035(offset) \
-	 (0x000000000000008Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG036(offset) \
-	 (0x0000000000000090ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG037(offset) \
-	 (0x0000000000000094ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG038(offset) \
-	 (0x0000000000000098ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG039(offset) \
-	 (0x000000000000009Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG040(offset) \
-	 (0x00000000000000A0ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG041(offset) \
-	 (0x00000000000000A4ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG042(offset) \
-	 (0x00000000000000A8ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG064(offset) \
-	 (0x0000000000000100ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG065(offset) \
-	 (0x0000000000000104ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG066(offset) \
-	 (0x0000000000000108ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG067(offset) \
-	 (0x000000000000010Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG068(offset) \
-	 (0x0000000000000110ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG069(offset) \
-	 (0x0000000000000114ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG070(offset) \
-	 (0x0000000000000118ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG071(offset) \
-	 (0x000000000000011Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG072(offset) \
-	 (0x0000000000000120ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG073(offset) \
-	 (0x0000000000000124ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG074(offset) \
-	 (0x0000000000000128ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG075(offset) \
-	 (0x000000000000012Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG076(offset) \
-	 (0x0000000000000130ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG077(offset) \
-	 (0x0000000000000134ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG448(offset) \
-	 (0x0000000000000700ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG449(offset) \
-	 (0x0000000000000704ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG450(offset) \
-	 (0x0000000000000708ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG451(offset) \
-	 (0x000000000000070Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG452(offset) \
-	 (0x0000000000000710ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG453(offset) \
-	 (0x0000000000000714ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG454(offset) \
-	 (0x0000000000000718ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG455(offset) \
-	 (0x000000000000071Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG456(offset) \
-	 (0x0000000000000720ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG458(offset) \
-	 (0x0000000000000728ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG459(offset) \
-	 (0x000000000000072Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG460(offset) \
-	 (0x0000000000000730ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG461(offset) \
-	 (0x0000000000000734ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG462(offset) \
-	 (0x0000000000000738ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG463(offset) \
-	 (0x000000000000073Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG464(offset) \
-	 (0x0000000000000740ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG465(offset) \
-	 (0x0000000000000744ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG466(offset) \
-	 (0x0000000000000748ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG467(offset) \
-	 (0x000000000000074Cull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG468(offset) \
-	 (0x0000000000000750ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG490(offset) \
-	 (0x00000000000007A8ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG491(offset) \
-	 (0x00000000000007ACull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG492(offset) \
-	 (0x00000000000007B0ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG516(offset) \
-	 (0x0000000000000810ull + (((offset) & 1) * 0))
-#define CVMX_PCIERCX_CFG517(offset) \
-	 (0x0000000000000814ull + (((offset) & 1) * 0))
+#define CVMX_PCIERCX_CFG000(block_id) (0x0000000000000000ull)
+#define CVMX_PCIERCX_CFG001(block_id) (0x0000000000000004ull)
+#define CVMX_PCIERCX_CFG002(block_id) (0x0000000000000008ull)
+#define CVMX_PCIERCX_CFG003(block_id) (0x000000000000000Cull)
+#define CVMX_PCIERCX_CFG004(block_id) (0x0000000000000010ull)
+#define CVMX_PCIERCX_CFG005(block_id) (0x0000000000000014ull)
+#define CVMX_PCIERCX_CFG006(block_id) (0x0000000000000018ull)
+#define CVMX_PCIERCX_CFG007(block_id) (0x000000000000001Cull)
+#define CVMX_PCIERCX_CFG008(block_id) (0x0000000000000020ull)
+#define CVMX_PCIERCX_CFG009(block_id) (0x0000000000000024ull)
+#define CVMX_PCIERCX_CFG010(block_id) (0x0000000000000028ull)
+#define CVMX_PCIERCX_CFG011(block_id) (0x000000000000002Cull)
+#define CVMX_PCIERCX_CFG012(block_id) (0x0000000000000030ull)
+#define CVMX_PCIERCX_CFG013(block_id) (0x0000000000000034ull)
+#define CVMX_PCIERCX_CFG014(block_id) (0x0000000000000038ull)
+#define CVMX_PCIERCX_CFG015(block_id) (0x000000000000003Cull)
+#define CVMX_PCIERCX_CFG016(block_id) (0x0000000000000040ull)
+#define CVMX_PCIERCX_CFG017(block_id) (0x0000000000000044ull)
+#define CVMX_PCIERCX_CFG020(block_id) (0x0000000000000050ull)
+#define CVMX_PCIERCX_CFG021(block_id) (0x0000000000000054ull)
+#define CVMX_PCIERCX_CFG022(block_id) (0x0000000000000058ull)
+#define CVMX_PCIERCX_CFG023(block_id) (0x000000000000005Cull)
+#define CVMX_PCIERCX_CFG028(block_id) (0x0000000000000070ull)
+#define CVMX_PCIERCX_CFG029(block_id) (0x0000000000000074ull)
+#define CVMX_PCIERCX_CFG030(block_id) (0x0000000000000078ull)
+#define CVMX_PCIERCX_CFG031(block_id) (0x000000000000007Cull)
+#define CVMX_PCIERCX_CFG032(block_id) (0x0000000000000080ull)
+#define CVMX_PCIERCX_CFG033(block_id) (0x0000000000000084ull)
+#define CVMX_PCIERCX_CFG034(block_id) (0x0000000000000088ull)
+#define CVMX_PCIERCX_CFG035(block_id) (0x000000000000008Cull)
+#define CVMX_PCIERCX_CFG036(block_id) (0x0000000000000090ull)
+#define CVMX_PCIERCX_CFG037(block_id) (0x0000000000000094ull)
+#define CVMX_PCIERCX_CFG038(block_id) (0x0000000000000098ull)
+#define CVMX_PCIERCX_CFG039(block_id) (0x000000000000009Cull)
+#define CVMX_PCIERCX_CFG040(block_id) (0x00000000000000A0ull)
+#define CVMX_PCIERCX_CFG041(block_id) (0x00000000000000A4ull)
+#define CVMX_PCIERCX_CFG042(block_id) (0x00000000000000A8ull)
+#define CVMX_PCIERCX_CFG064(block_id) (0x0000000000000100ull)
+#define CVMX_PCIERCX_CFG065(block_id) (0x0000000000000104ull)
+#define CVMX_PCIERCX_CFG066(block_id) (0x0000000000000108ull)
+#define CVMX_PCIERCX_CFG067(block_id) (0x000000000000010Cull)
+#define CVMX_PCIERCX_CFG068(block_id) (0x0000000000000110ull)
+#define CVMX_PCIERCX_CFG069(block_id) (0x0000000000000114ull)
+#define CVMX_PCIERCX_CFG070(block_id) (0x0000000000000118ull)
+#define CVMX_PCIERCX_CFG071(block_id) (0x000000000000011Cull)
+#define CVMX_PCIERCX_CFG072(block_id) (0x0000000000000120ull)
+#define CVMX_PCIERCX_CFG073(block_id) (0x0000000000000124ull)
+#define CVMX_PCIERCX_CFG074(block_id) (0x0000000000000128ull)
+#define CVMX_PCIERCX_CFG075(block_id) (0x000000000000012Cull)
+#define CVMX_PCIERCX_CFG076(block_id) (0x0000000000000130ull)
+#define CVMX_PCIERCX_CFG077(block_id) (0x0000000000000134ull)
+#define CVMX_PCIERCX_CFG448(block_id) (0x0000000000000700ull)
+#define CVMX_PCIERCX_CFG449(block_id) (0x0000000000000704ull)
+#define CVMX_PCIERCX_CFG450(block_id) (0x0000000000000708ull)
+#define CVMX_PCIERCX_CFG451(block_id) (0x000000000000070Cull)
+#define CVMX_PCIERCX_CFG452(block_id) (0x0000000000000710ull)
+#define CVMX_PCIERCX_CFG453(block_id) (0x0000000000000714ull)
+#define CVMX_PCIERCX_CFG454(block_id) (0x0000000000000718ull)
+#define CVMX_PCIERCX_CFG455(block_id) (0x000000000000071Cull)
+#define CVMX_PCIERCX_CFG456(block_id) (0x0000000000000720ull)
+#define CVMX_PCIERCX_CFG458(block_id) (0x0000000000000728ull)
+#define CVMX_PCIERCX_CFG459(block_id) (0x000000000000072Cull)
+#define CVMX_PCIERCX_CFG460(block_id) (0x0000000000000730ull)
+#define CVMX_PCIERCX_CFG461(block_id) (0x0000000000000734ull)
+#define CVMX_PCIERCX_CFG462(block_id) (0x0000000000000738ull)
+#define CVMX_PCIERCX_CFG463(block_id) (0x000000000000073Cull)
+#define CVMX_PCIERCX_CFG464(block_id) (0x0000000000000740ull)
+#define CVMX_PCIERCX_CFG465(block_id) (0x0000000000000744ull)
+#define CVMX_PCIERCX_CFG466(block_id) (0x0000000000000748ull)
+#define CVMX_PCIERCX_CFG467(block_id) (0x000000000000074Cull)
+#define CVMX_PCIERCX_CFG468(block_id) (0x0000000000000750ull)
+#define CVMX_PCIERCX_CFG490(block_id) (0x00000000000007A8ull)
+#define CVMX_PCIERCX_CFG491(block_id) (0x00000000000007ACull)
+#define CVMX_PCIERCX_CFG492(block_id) (0x00000000000007B0ull)
+#define CVMX_PCIERCX_CFG515(block_id) (0x000000000000080Cull)
+#define CVMX_PCIERCX_CFG516(block_id) (0x0000000000000810ull)
+#define CVMX_PCIERCX_CFG517(block_id) (0x0000000000000814ull)
 
 union cvmx_pciercx_cfg000 {
 	uint32_t u32;
@@ -191,6 +116,8 @@
 	struct cvmx_pciercx_cfg000_s cn52xxp1;
 	struct cvmx_pciercx_cfg000_s cn56xx;
 	struct cvmx_pciercx_cfg000_s cn56xxp1;
+	struct cvmx_pciercx_cfg000_s cn63xx;
+	struct cvmx_pciercx_cfg000_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg001 {
@@ -225,6 +152,8 @@
 	struct cvmx_pciercx_cfg001_s cn52xxp1;
 	struct cvmx_pciercx_cfg001_s cn56xx;
 	struct cvmx_pciercx_cfg001_s cn56xxp1;
+	struct cvmx_pciercx_cfg001_s cn63xx;
+	struct cvmx_pciercx_cfg001_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg002 {
@@ -239,6 +168,8 @@
 	struct cvmx_pciercx_cfg002_s cn52xxp1;
 	struct cvmx_pciercx_cfg002_s cn56xx;
 	struct cvmx_pciercx_cfg002_s cn56xxp1;
+	struct cvmx_pciercx_cfg002_s cn63xx;
+	struct cvmx_pciercx_cfg002_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg003 {
@@ -254,6 +185,8 @@
 	struct cvmx_pciercx_cfg003_s cn52xxp1;
 	struct cvmx_pciercx_cfg003_s cn56xx;
 	struct cvmx_pciercx_cfg003_s cn56xxp1;
+	struct cvmx_pciercx_cfg003_s cn63xx;
+	struct cvmx_pciercx_cfg003_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg004 {
@@ -265,6 +198,8 @@
 	struct cvmx_pciercx_cfg004_s cn52xxp1;
 	struct cvmx_pciercx_cfg004_s cn56xx;
 	struct cvmx_pciercx_cfg004_s cn56xxp1;
+	struct cvmx_pciercx_cfg004_s cn63xx;
+	struct cvmx_pciercx_cfg004_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg005 {
@@ -276,6 +211,8 @@
 	struct cvmx_pciercx_cfg005_s cn52xxp1;
 	struct cvmx_pciercx_cfg005_s cn56xx;
 	struct cvmx_pciercx_cfg005_s cn56xxp1;
+	struct cvmx_pciercx_cfg005_s cn63xx;
+	struct cvmx_pciercx_cfg005_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg006 {
@@ -290,6 +227,8 @@
 	struct cvmx_pciercx_cfg006_s cn52xxp1;
 	struct cvmx_pciercx_cfg006_s cn56xx;
 	struct cvmx_pciercx_cfg006_s cn56xxp1;
+	struct cvmx_pciercx_cfg006_s cn63xx;
+	struct cvmx_pciercx_cfg006_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg007 {
@@ -317,6 +256,8 @@
 	struct cvmx_pciercx_cfg007_s cn52xxp1;
 	struct cvmx_pciercx_cfg007_s cn56xx;
 	struct cvmx_pciercx_cfg007_s cn56xxp1;
+	struct cvmx_pciercx_cfg007_s cn63xx;
+	struct cvmx_pciercx_cfg007_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg008 {
@@ -331,6 +272,8 @@
 	struct cvmx_pciercx_cfg008_s cn52xxp1;
 	struct cvmx_pciercx_cfg008_s cn56xx;
 	struct cvmx_pciercx_cfg008_s cn56xxp1;
+	struct cvmx_pciercx_cfg008_s cn63xx;
+	struct cvmx_pciercx_cfg008_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg009 {
@@ -347,6 +290,8 @@
 	struct cvmx_pciercx_cfg009_s cn52xxp1;
 	struct cvmx_pciercx_cfg009_s cn56xx;
 	struct cvmx_pciercx_cfg009_s cn56xxp1;
+	struct cvmx_pciercx_cfg009_s cn63xx;
+	struct cvmx_pciercx_cfg009_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg010 {
@@ -358,6 +303,8 @@
 	struct cvmx_pciercx_cfg010_s cn52xxp1;
 	struct cvmx_pciercx_cfg010_s cn56xx;
 	struct cvmx_pciercx_cfg010_s cn56xxp1;
+	struct cvmx_pciercx_cfg010_s cn63xx;
+	struct cvmx_pciercx_cfg010_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg011 {
@@ -369,6 +316,8 @@
 	struct cvmx_pciercx_cfg011_s cn52xxp1;
 	struct cvmx_pciercx_cfg011_s cn56xx;
 	struct cvmx_pciercx_cfg011_s cn56xxp1;
+	struct cvmx_pciercx_cfg011_s cn63xx;
+	struct cvmx_pciercx_cfg011_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg012 {
@@ -381,6 +330,8 @@
 	struct cvmx_pciercx_cfg012_s cn52xxp1;
 	struct cvmx_pciercx_cfg012_s cn56xx;
 	struct cvmx_pciercx_cfg012_s cn56xxp1;
+	struct cvmx_pciercx_cfg012_s cn63xx;
+	struct cvmx_pciercx_cfg012_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg013 {
@@ -393,6 +344,8 @@
 	struct cvmx_pciercx_cfg013_s cn52xxp1;
 	struct cvmx_pciercx_cfg013_s cn56xx;
 	struct cvmx_pciercx_cfg013_s cn56xxp1;
+	struct cvmx_pciercx_cfg013_s cn63xx;
+	struct cvmx_pciercx_cfg013_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg014 {
@@ -404,6 +357,8 @@
 	struct cvmx_pciercx_cfg014_s cn52xxp1;
 	struct cvmx_pciercx_cfg014_s cn56xx;
 	struct cvmx_pciercx_cfg014_s cn56xxp1;
+	struct cvmx_pciercx_cfg014_s cn63xx;
+	struct cvmx_pciercx_cfg014_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg015 {
@@ -429,6 +384,8 @@
 	struct cvmx_pciercx_cfg015_s cn52xxp1;
 	struct cvmx_pciercx_cfg015_s cn56xx;
 	struct cvmx_pciercx_cfg015_s cn56xxp1;
+	struct cvmx_pciercx_cfg015_s cn63xx;
+	struct cvmx_pciercx_cfg015_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg016 {
@@ -449,6 +406,8 @@
 	struct cvmx_pciercx_cfg016_s cn52xxp1;
 	struct cvmx_pciercx_cfg016_s cn56xx;
 	struct cvmx_pciercx_cfg016_s cn56xxp1;
+	struct cvmx_pciercx_cfg016_s cn63xx;
+	struct cvmx_pciercx_cfg016_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg017 {
@@ -471,6 +430,8 @@
 	struct cvmx_pciercx_cfg017_s cn52xxp1;
 	struct cvmx_pciercx_cfg017_s cn56xx;
 	struct cvmx_pciercx_cfg017_s cn56xxp1;
+	struct cvmx_pciercx_cfg017_s cn63xx;
+	struct cvmx_pciercx_cfg017_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg020 {
@@ -488,6 +449,8 @@
 	struct cvmx_pciercx_cfg020_s cn52xxp1;
 	struct cvmx_pciercx_cfg020_s cn56xx;
 	struct cvmx_pciercx_cfg020_s cn56xxp1;
+	struct cvmx_pciercx_cfg020_s cn63xx;
+	struct cvmx_pciercx_cfg020_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg021 {
@@ -500,6 +463,8 @@
 	struct cvmx_pciercx_cfg021_s cn52xxp1;
 	struct cvmx_pciercx_cfg021_s cn56xx;
 	struct cvmx_pciercx_cfg021_s cn56xxp1;
+	struct cvmx_pciercx_cfg021_s cn63xx;
+	struct cvmx_pciercx_cfg021_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg022 {
@@ -511,6 +476,8 @@
 	struct cvmx_pciercx_cfg022_s cn52xxp1;
 	struct cvmx_pciercx_cfg022_s cn56xx;
 	struct cvmx_pciercx_cfg022_s cn56xxp1;
+	struct cvmx_pciercx_cfg022_s cn63xx;
+	struct cvmx_pciercx_cfg022_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg023 {
@@ -523,6 +490,8 @@
 	struct cvmx_pciercx_cfg023_s cn52xxp1;
 	struct cvmx_pciercx_cfg023_s cn56xx;
 	struct cvmx_pciercx_cfg023_s cn56xxp1;
+	struct cvmx_pciercx_cfg023_s cn63xx;
+	struct cvmx_pciercx_cfg023_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg028 {
@@ -540,6 +509,8 @@
 	struct cvmx_pciercx_cfg028_s cn52xxp1;
 	struct cvmx_pciercx_cfg028_s cn56xx;
 	struct cvmx_pciercx_cfg028_s cn56xxp1;
+	struct cvmx_pciercx_cfg028_s cn63xx;
+	struct cvmx_pciercx_cfg028_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg029 {
@@ -561,6 +532,8 @@
 	struct cvmx_pciercx_cfg029_s cn52xxp1;
 	struct cvmx_pciercx_cfg029_s cn56xx;
 	struct cvmx_pciercx_cfg029_s cn56xxp1;
+	struct cvmx_pciercx_cfg029_s cn63xx;
+	struct cvmx_pciercx_cfg029_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg030 {
@@ -590,6 +563,8 @@
 	struct cvmx_pciercx_cfg030_s cn52xxp1;
 	struct cvmx_pciercx_cfg030_s cn56xx;
 	struct cvmx_pciercx_cfg030_s cn56xxp1;
+	struct cvmx_pciercx_cfg030_s cn63xx;
+	struct cvmx_pciercx_cfg030_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg031 {
@@ -611,6 +586,8 @@
 	struct cvmx_pciercx_cfg031_s cn52xxp1;
 	struct cvmx_pciercx_cfg031_s cn56xx;
 	struct cvmx_pciercx_cfg031_s cn56xxp1;
+	struct cvmx_pciercx_cfg031_s cn63xx;
+	struct cvmx_pciercx_cfg031_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg032 {
@@ -641,6 +618,8 @@
 	struct cvmx_pciercx_cfg032_s cn52xxp1;
 	struct cvmx_pciercx_cfg032_s cn56xx;
 	struct cvmx_pciercx_cfg032_s cn56xxp1;
+	struct cvmx_pciercx_cfg032_s cn63xx;
+	struct cvmx_pciercx_cfg032_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg033 {
@@ -663,6 +642,8 @@
 	struct cvmx_pciercx_cfg033_s cn52xxp1;
 	struct cvmx_pciercx_cfg033_s cn56xx;
 	struct cvmx_pciercx_cfg033_s cn56xxp1;
+	struct cvmx_pciercx_cfg033_s cn63xx;
+	struct cvmx_pciercx_cfg033_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg034 {
@@ -695,6 +676,8 @@
 	struct cvmx_pciercx_cfg034_s cn52xxp1;
 	struct cvmx_pciercx_cfg034_s cn56xx;
 	struct cvmx_pciercx_cfg034_s cn56xxp1;
+	struct cvmx_pciercx_cfg034_s cn63xx;
+	struct cvmx_pciercx_cfg034_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg035 {
@@ -713,6 +696,8 @@
 	struct cvmx_pciercx_cfg035_s cn52xxp1;
 	struct cvmx_pciercx_cfg035_s cn56xx;
 	struct cvmx_pciercx_cfg035_s cn56xxp1;
+	struct cvmx_pciercx_cfg035_s cn63xx;
+	struct cvmx_pciercx_cfg035_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg036 {
@@ -727,6 +712,8 @@
 	struct cvmx_pciercx_cfg036_s cn52xxp1;
 	struct cvmx_pciercx_cfg036_s cn56xx;
 	struct cvmx_pciercx_cfg036_s cn56xxp1;
+	struct cvmx_pciercx_cfg036_s cn63xx;
+	struct cvmx_pciercx_cfg036_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg037 {
@@ -740,6 +727,8 @@
 	struct cvmx_pciercx_cfg037_s cn52xxp1;
 	struct cvmx_pciercx_cfg037_s cn56xx;
 	struct cvmx_pciercx_cfg037_s cn56xxp1;
+	struct cvmx_pciercx_cfg037_s cn63xx;
+	struct cvmx_pciercx_cfg037_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg038 {
@@ -753,28 +742,51 @@
 	struct cvmx_pciercx_cfg038_s cn52xxp1;
 	struct cvmx_pciercx_cfg038_s cn56xx;
 	struct cvmx_pciercx_cfg038_s cn56xxp1;
+	struct cvmx_pciercx_cfg038_s cn63xx;
+	struct cvmx_pciercx_cfg038_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg039 {
 	uint32_t u32;
 	struct cvmx_pciercx_cfg039_s {
-		uint32_t reserved_0_31:32;
+		uint32_t reserved_9_31:23;
+		uint32_t cls:1;
+		uint32_t slsv:7;
+		uint32_t reserved_0_0:1;
 	} s;
-	struct cvmx_pciercx_cfg039_s cn52xx;
-	struct cvmx_pciercx_cfg039_s cn52xxp1;
-	struct cvmx_pciercx_cfg039_s cn56xx;
-	struct cvmx_pciercx_cfg039_s cn56xxp1;
+	struct cvmx_pciercx_cfg039_cn52xx {
+		uint32_t reserved_0_31:32;
+	} cn52xx;
+	struct cvmx_pciercx_cfg039_cn52xx cn52xxp1;
+	struct cvmx_pciercx_cfg039_cn52xx cn56xx;
+	struct cvmx_pciercx_cfg039_cn52xx cn56xxp1;
+	struct cvmx_pciercx_cfg039_s cn63xx;
+	struct cvmx_pciercx_cfg039_cn52xx cn63xxp1;
 };
 
 union cvmx_pciercx_cfg040 {
 	uint32_t u32;
 	struct cvmx_pciercx_cfg040_s {
-		uint32_t reserved_0_31:32;
+		uint32_t reserved_17_31:15;
+		uint32_t cdl:1;
+		uint32_t reserved_13_15:3;
+		uint32_t cde:1;
+		uint32_t csos:1;
+		uint32_t emc:1;
+		uint32_t tm:3;
+		uint32_t sde:1;
+		uint32_t hasd:1;
+		uint32_t ec:1;
+		uint32_t tls:4;
 	} s;
-	struct cvmx_pciercx_cfg040_s cn52xx;
-	struct cvmx_pciercx_cfg040_s cn52xxp1;
-	struct cvmx_pciercx_cfg040_s cn56xx;
-	struct cvmx_pciercx_cfg040_s cn56xxp1;
+	struct cvmx_pciercx_cfg040_cn52xx {
+		uint32_t reserved_0_31:32;
+	} cn52xx;
+	struct cvmx_pciercx_cfg040_cn52xx cn52xxp1;
+	struct cvmx_pciercx_cfg040_cn52xx cn56xx;
+	struct cvmx_pciercx_cfg040_cn52xx cn56xxp1;
+	struct cvmx_pciercx_cfg040_s cn63xx;
+	struct cvmx_pciercx_cfg040_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg041 {
@@ -786,6 +798,8 @@
 	struct cvmx_pciercx_cfg041_s cn52xxp1;
 	struct cvmx_pciercx_cfg041_s cn56xx;
 	struct cvmx_pciercx_cfg041_s cn56xxp1;
+	struct cvmx_pciercx_cfg041_s cn63xx;
+	struct cvmx_pciercx_cfg041_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg042 {
@@ -797,6 +811,8 @@
 	struct cvmx_pciercx_cfg042_s cn52xxp1;
 	struct cvmx_pciercx_cfg042_s cn56xx;
 	struct cvmx_pciercx_cfg042_s cn56xxp1;
+	struct cvmx_pciercx_cfg042_s cn63xx;
+	struct cvmx_pciercx_cfg042_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg064 {
@@ -810,6 +826,8 @@
 	struct cvmx_pciercx_cfg064_s cn52xxp1;
 	struct cvmx_pciercx_cfg064_s cn56xx;
 	struct cvmx_pciercx_cfg064_s cn56xxp1;
+	struct cvmx_pciercx_cfg064_s cn63xx;
+	struct cvmx_pciercx_cfg064_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg065 {
@@ -834,6 +852,8 @@
 	struct cvmx_pciercx_cfg065_s cn52xxp1;
 	struct cvmx_pciercx_cfg065_s cn56xx;
 	struct cvmx_pciercx_cfg065_s cn56xxp1;
+	struct cvmx_pciercx_cfg065_s cn63xx;
+	struct cvmx_pciercx_cfg065_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg066 {
@@ -858,6 +878,8 @@
 	struct cvmx_pciercx_cfg066_s cn52xxp1;
 	struct cvmx_pciercx_cfg066_s cn56xx;
 	struct cvmx_pciercx_cfg066_s cn56xxp1;
+	struct cvmx_pciercx_cfg066_s cn63xx;
+	struct cvmx_pciercx_cfg066_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg067 {
@@ -882,6 +904,8 @@
 	struct cvmx_pciercx_cfg067_s cn52xxp1;
 	struct cvmx_pciercx_cfg067_s cn56xx;
 	struct cvmx_pciercx_cfg067_s cn56xxp1;
+	struct cvmx_pciercx_cfg067_s cn63xx;
+	struct cvmx_pciercx_cfg067_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg068 {
@@ -901,6 +925,8 @@
 	struct cvmx_pciercx_cfg068_s cn52xxp1;
 	struct cvmx_pciercx_cfg068_s cn56xx;
 	struct cvmx_pciercx_cfg068_s cn56xxp1;
+	struct cvmx_pciercx_cfg068_s cn63xx;
+	struct cvmx_pciercx_cfg068_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg069 {
@@ -920,6 +946,8 @@
 	struct cvmx_pciercx_cfg069_s cn52xxp1;
 	struct cvmx_pciercx_cfg069_s cn56xx;
 	struct cvmx_pciercx_cfg069_s cn56xxp1;
+	struct cvmx_pciercx_cfg069_s cn63xx;
+	struct cvmx_pciercx_cfg069_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg070 {
@@ -936,6 +964,8 @@
 	struct cvmx_pciercx_cfg070_s cn52xxp1;
 	struct cvmx_pciercx_cfg070_s cn56xx;
 	struct cvmx_pciercx_cfg070_s cn56xxp1;
+	struct cvmx_pciercx_cfg070_s cn63xx;
+	struct cvmx_pciercx_cfg070_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg071 {
@@ -947,6 +977,8 @@
 	struct cvmx_pciercx_cfg071_s cn52xxp1;
 	struct cvmx_pciercx_cfg071_s cn56xx;
 	struct cvmx_pciercx_cfg071_s cn56xxp1;
+	struct cvmx_pciercx_cfg071_s cn63xx;
+	struct cvmx_pciercx_cfg071_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg072 {
@@ -958,6 +990,8 @@
 	struct cvmx_pciercx_cfg072_s cn52xxp1;
 	struct cvmx_pciercx_cfg072_s cn56xx;
 	struct cvmx_pciercx_cfg072_s cn56xxp1;
+	struct cvmx_pciercx_cfg072_s cn63xx;
+	struct cvmx_pciercx_cfg072_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg073 {
@@ -969,6 +1003,8 @@
 	struct cvmx_pciercx_cfg073_s cn52xxp1;
 	struct cvmx_pciercx_cfg073_s cn56xx;
 	struct cvmx_pciercx_cfg073_s cn56xxp1;
+	struct cvmx_pciercx_cfg073_s cn63xx;
+	struct cvmx_pciercx_cfg073_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg074 {
@@ -980,6 +1016,8 @@
 	struct cvmx_pciercx_cfg074_s cn52xxp1;
 	struct cvmx_pciercx_cfg074_s cn56xx;
 	struct cvmx_pciercx_cfg074_s cn56xxp1;
+	struct cvmx_pciercx_cfg074_s cn63xx;
+	struct cvmx_pciercx_cfg074_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg075 {
@@ -994,6 +1032,8 @@
 	struct cvmx_pciercx_cfg075_s cn52xxp1;
 	struct cvmx_pciercx_cfg075_s cn56xx;
 	struct cvmx_pciercx_cfg075_s cn56xxp1;
+	struct cvmx_pciercx_cfg075_s cn63xx;
+	struct cvmx_pciercx_cfg075_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg076 {
@@ -1013,6 +1053,8 @@
 	struct cvmx_pciercx_cfg076_s cn52xxp1;
 	struct cvmx_pciercx_cfg076_s cn56xx;
 	struct cvmx_pciercx_cfg076_s cn56xxp1;
+	struct cvmx_pciercx_cfg076_s cn63xx;
+	struct cvmx_pciercx_cfg076_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg077 {
@@ -1025,6 +1067,8 @@
 	struct cvmx_pciercx_cfg077_s cn52xxp1;
 	struct cvmx_pciercx_cfg077_s cn56xx;
 	struct cvmx_pciercx_cfg077_s cn56xxp1;
+	struct cvmx_pciercx_cfg077_s cn63xx;
+	struct cvmx_pciercx_cfg077_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg448 {
@@ -1037,6 +1081,8 @@
 	struct cvmx_pciercx_cfg448_s cn52xxp1;
 	struct cvmx_pciercx_cfg448_s cn56xx;
 	struct cvmx_pciercx_cfg448_s cn56xxp1;
+	struct cvmx_pciercx_cfg448_s cn63xx;
+	struct cvmx_pciercx_cfg448_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg449 {
@@ -1048,6 +1094,8 @@
 	struct cvmx_pciercx_cfg449_s cn52xxp1;
 	struct cvmx_pciercx_cfg449_s cn56xx;
 	struct cvmx_pciercx_cfg449_s cn56xxp1;
+	struct cvmx_pciercx_cfg449_s cn63xx;
+	struct cvmx_pciercx_cfg449_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg450 {
@@ -1064,6 +1112,8 @@
 	struct cvmx_pciercx_cfg450_s cn52xxp1;
 	struct cvmx_pciercx_cfg450_s cn56xx;
 	struct cvmx_pciercx_cfg450_s cn56xxp1;
+	struct cvmx_pciercx_cfg450_s cn63xx;
+	struct cvmx_pciercx_cfg450_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg451 {
@@ -1080,6 +1130,8 @@
 	struct cvmx_pciercx_cfg451_s cn52xxp1;
 	struct cvmx_pciercx_cfg451_s cn56xx;
 	struct cvmx_pciercx_cfg451_s cn56xxp1;
+	struct cvmx_pciercx_cfg451_s cn63xx;
+	struct cvmx_pciercx_cfg451_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg452 {
@@ -1103,6 +1155,8 @@
 	struct cvmx_pciercx_cfg452_s cn52xxp1;
 	struct cvmx_pciercx_cfg452_s cn56xx;
 	struct cvmx_pciercx_cfg452_s cn56xxp1;
+	struct cvmx_pciercx_cfg452_s cn63xx;
+	struct cvmx_pciercx_cfg452_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg453 {
@@ -1118,6 +1172,8 @@
 	struct cvmx_pciercx_cfg453_s cn52xxp1;
 	struct cvmx_pciercx_cfg453_s cn56xx;
 	struct cvmx_pciercx_cfg453_s cn56xxp1;
+	struct cvmx_pciercx_cfg453_s cn63xx;
+	struct cvmx_pciercx_cfg453_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg454 {
@@ -1136,6 +1192,8 @@
 	struct cvmx_pciercx_cfg454_s cn52xxp1;
 	struct cvmx_pciercx_cfg454_s cn56xx;
 	struct cvmx_pciercx_cfg454_s cn56xxp1;
+	struct cvmx_pciercx_cfg454_s cn63xx;
+	struct cvmx_pciercx_cfg454_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg455 {
@@ -1165,6 +1223,8 @@
 	struct cvmx_pciercx_cfg455_s cn52xxp1;
 	struct cvmx_pciercx_cfg455_s cn56xx;
 	struct cvmx_pciercx_cfg455_s cn56xxp1;
+	struct cvmx_pciercx_cfg455_s cn63xx;
+	struct cvmx_pciercx_cfg455_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg456 {
@@ -1178,6 +1238,8 @@
 	struct cvmx_pciercx_cfg456_s cn52xxp1;
 	struct cvmx_pciercx_cfg456_s cn56xx;
 	struct cvmx_pciercx_cfg456_s cn56xxp1;
+	struct cvmx_pciercx_cfg456_s cn63xx;
+	struct cvmx_pciercx_cfg456_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg458 {
@@ -1189,6 +1251,8 @@
 	struct cvmx_pciercx_cfg458_s cn52xxp1;
 	struct cvmx_pciercx_cfg458_s cn56xx;
 	struct cvmx_pciercx_cfg458_s cn56xxp1;
+	struct cvmx_pciercx_cfg458_s cn63xx;
+	struct cvmx_pciercx_cfg458_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg459 {
@@ -1200,6 +1264,8 @@
 	struct cvmx_pciercx_cfg459_s cn52xxp1;
 	struct cvmx_pciercx_cfg459_s cn56xx;
 	struct cvmx_pciercx_cfg459_s cn56xxp1;
+	struct cvmx_pciercx_cfg459_s cn63xx;
+	struct cvmx_pciercx_cfg459_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg460 {
@@ -1213,6 +1279,8 @@
 	struct cvmx_pciercx_cfg460_s cn52xxp1;
 	struct cvmx_pciercx_cfg460_s cn56xx;
 	struct cvmx_pciercx_cfg460_s cn56xxp1;
+	struct cvmx_pciercx_cfg460_s cn63xx;
+	struct cvmx_pciercx_cfg460_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg461 {
@@ -1226,6 +1294,8 @@
 	struct cvmx_pciercx_cfg461_s cn52xxp1;
 	struct cvmx_pciercx_cfg461_s cn56xx;
 	struct cvmx_pciercx_cfg461_s cn56xxp1;
+	struct cvmx_pciercx_cfg461_s cn63xx;
+	struct cvmx_pciercx_cfg461_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg462 {
@@ -1239,6 +1309,8 @@
 	struct cvmx_pciercx_cfg462_s cn52xxp1;
 	struct cvmx_pciercx_cfg462_s cn56xx;
 	struct cvmx_pciercx_cfg462_s cn56xxp1;
+	struct cvmx_pciercx_cfg462_s cn63xx;
+	struct cvmx_pciercx_cfg462_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg463 {
@@ -1253,6 +1325,8 @@
 	struct cvmx_pciercx_cfg463_s cn52xxp1;
 	struct cvmx_pciercx_cfg463_s cn56xx;
 	struct cvmx_pciercx_cfg463_s cn56xxp1;
+	struct cvmx_pciercx_cfg463_s cn63xx;
+	struct cvmx_pciercx_cfg463_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg464 {
@@ -1267,6 +1341,8 @@
 	struct cvmx_pciercx_cfg464_s cn52xxp1;
 	struct cvmx_pciercx_cfg464_s cn56xx;
 	struct cvmx_pciercx_cfg464_s cn56xxp1;
+	struct cvmx_pciercx_cfg464_s cn63xx;
+	struct cvmx_pciercx_cfg464_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg465 {
@@ -1281,6 +1357,8 @@
 	struct cvmx_pciercx_cfg465_s cn52xxp1;
 	struct cvmx_pciercx_cfg465_s cn56xx;
 	struct cvmx_pciercx_cfg465_s cn56xxp1;
+	struct cvmx_pciercx_cfg465_s cn63xx;
+	struct cvmx_pciercx_cfg465_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg466 {
@@ -1298,6 +1376,8 @@
 	struct cvmx_pciercx_cfg466_s cn52xxp1;
 	struct cvmx_pciercx_cfg466_s cn56xx;
 	struct cvmx_pciercx_cfg466_s cn56xxp1;
+	struct cvmx_pciercx_cfg466_s cn63xx;
+	struct cvmx_pciercx_cfg466_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg467 {
@@ -1313,6 +1393,8 @@
 	struct cvmx_pciercx_cfg467_s cn52xxp1;
 	struct cvmx_pciercx_cfg467_s cn56xx;
 	struct cvmx_pciercx_cfg467_s cn56xxp1;
+	struct cvmx_pciercx_cfg467_s cn63xx;
+	struct cvmx_pciercx_cfg467_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg468 {
@@ -1328,6 +1410,8 @@
 	struct cvmx_pciercx_cfg468_s cn52xxp1;
 	struct cvmx_pciercx_cfg468_s cn56xx;
 	struct cvmx_pciercx_cfg468_s cn56xxp1;
+	struct cvmx_pciercx_cfg468_s cn63xx;
+	struct cvmx_pciercx_cfg468_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg490 {
@@ -1342,6 +1426,8 @@
 	struct cvmx_pciercx_cfg490_s cn52xxp1;
 	struct cvmx_pciercx_cfg490_s cn56xx;
 	struct cvmx_pciercx_cfg490_s cn56xxp1;
+	struct cvmx_pciercx_cfg490_s cn63xx;
+	struct cvmx_pciercx_cfg490_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg491 {
@@ -1356,6 +1442,8 @@
 	struct cvmx_pciercx_cfg491_s cn52xxp1;
 	struct cvmx_pciercx_cfg491_s cn56xx;
 	struct cvmx_pciercx_cfg491_s cn56xxp1;
+	struct cvmx_pciercx_cfg491_s cn63xx;
+	struct cvmx_pciercx_cfg491_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg492 {
@@ -1370,6 +1458,23 @@
 	struct cvmx_pciercx_cfg492_s cn52xxp1;
 	struct cvmx_pciercx_cfg492_s cn56xx;
 	struct cvmx_pciercx_cfg492_s cn56xxp1;
+	struct cvmx_pciercx_cfg492_s cn63xx;
+	struct cvmx_pciercx_cfg492_s cn63xxp1;
+};
+
+union cvmx_pciercx_cfg515 {
+	uint32_t u32;
+	struct cvmx_pciercx_cfg515_s {
+		uint32_t reserved_21_31:11;
+		uint32_t s_d_e:1;
+		uint32_t ctcrb:1;
+		uint32_t cpyts:1;
+		uint32_t dsc:1;
+		uint32_t le:9;
+		uint32_t n_fts:8;
+	} s;
+	struct cvmx_pciercx_cfg515_s cn63xx;
+	struct cvmx_pciercx_cfg515_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg516 {
@@ -1381,6 +1486,8 @@
 	struct cvmx_pciercx_cfg516_s cn52xxp1;
 	struct cvmx_pciercx_cfg516_s cn56xx;
 	struct cvmx_pciercx_cfg516_s cn56xxp1;
+	struct cvmx_pciercx_cfg516_s cn63xx;
+	struct cvmx_pciercx_cfg516_s cn63xxp1;
 };
 
 union cvmx_pciercx_cfg517 {
@@ -1392,6 +1499,8 @@
 	struct cvmx_pciercx_cfg517_s cn52xxp1;
 	struct cvmx_pciercx_cfg517_s cn56xx;
 	struct cvmx_pciercx_cfg517_s cn56xxp1;
+	struct cvmx_pciercx_cfg517_s cn63xx;
+	struct cvmx_pciercx_cfg517_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pescx-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pescx-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pescx-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pescx-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,38 +28,22 @@
 #ifndef __CVMX_PESCX_DEFS_H__
 #define __CVMX_PESCX_DEFS_H__
 
-#define CVMX_PESCX_BIST_STATUS(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000018ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_BIST_STATUS2(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000418ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_CFG_RD(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000030ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_CFG_WR(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000028ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_CPL_LUT_VALID(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000098ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_CTL_STATUS(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000000ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_CTL_STATUS2(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000400ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_DBG_INFO(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000008ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_DBG_INFO_EN(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C80000A0ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_DIAG_STATUS(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000020ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_P2N_BAR0_START(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000080ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_P2N_BAR1_START(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000088ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_P2N_BAR2_START(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000090ull + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_P2P_BARX_END(offset, block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000048ull + (((offset) & 3) * 16) + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_P2P_BARX_START(offset, block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000040ull + (((offset) & 3) * 16) + (((block_id) & 1) * 0x8000000ull))
-#define CVMX_PESCX_TLP_CREDITS(block_id) \
-	 CVMX_ADD_IO_SEG(0x00011800C8000038ull + (((block_id) & 1) * 0x8000000ull))
+#define CVMX_PESCX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000018ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_BIST_STATUS2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000418ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_CFG_RD(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000030ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_CFG_WR(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000028ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_CPL_LUT_VALID(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000098ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_CTL_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000000ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_CTL_STATUS2(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000400ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_DBG_INFO(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000008ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_DBG_INFO_EN(block_id) (CVMX_ADD_IO_SEG(0x00011800C80000A0ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_DIAG_STATUS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000020ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_P2N_BAR0_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000080ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_P2N_BAR1_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000088ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_P2N_BAR2_START(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000090ull) + ((block_id) & 1) * 0x8000000ull)
+#define CVMX_PESCX_P2P_BARX_END(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000048ull) + (((offset) & 3) + ((block_id) & 1) * 0x800000ull) * 16)
+#define CVMX_PESCX_P2P_BARX_START(offset, block_id) (CVMX_ADD_IO_SEG(0x00011800C8000040ull) + (((offset) & 3) + ((block_id) & 1) * 0x800000ull) * 16)
+#define CVMX_PESCX_TLP_CREDITS(block_id) (CVMX_ADD_IO_SEG(0x00011800C8000038ull) + ((block_id) & 1) * 0x8000000ull)
 
 union cvmx_pescx_bist_status {
 	uint64_t u64;
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pexp-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pexp-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pexp-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pexp-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -35,195 +35,191 @@
 #ifndef __CVMX_PEXP_DEFS_H__
 #define __CVMX_PEXP_DEFS_H__
 
-#define CVMX_PEXP_NPEI_BAR1_INDEXX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000008000ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_BIST_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011F0000008580ull)
-#define CVMX_PEXP_NPEI_BIST_STATUS2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008680ull)
-#define CVMX_PEXP_NPEI_CTL_PORT0 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008250ull)
-#define CVMX_PEXP_NPEI_CTL_PORT1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008260ull)
-#define CVMX_PEXP_NPEI_CTL_STATUS \
-	 CVMX_ADD_IO_SEG(0x00011F0000008570ull)
-#define CVMX_PEXP_NPEI_CTL_STATUS2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC00ull)
-#define CVMX_PEXP_NPEI_DATA_OUT_CNT \
-	 CVMX_ADD_IO_SEG(0x00011F00000085F0ull)
-#define CVMX_PEXP_NPEI_DBG_DATA \
-	 CVMX_ADD_IO_SEG(0x00011F0000008510ull)
-#define CVMX_PEXP_NPEI_DBG_SELECT \
-	 CVMX_ADD_IO_SEG(0x00011F0000008500ull)
-#define CVMX_PEXP_NPEI_DMA0_INT_LEVEL \
-	 CVMX_ADD_IO_SEG(0x00011F00000085C0ull)
-#define CVMX_PEXP_NPEI_DMA1_INT_LEVEL \
-	 CVMX_ADD_IO_SEG(0x00011F00000085D0ull)
-#define CVMX_PEXP_NPEI_DMAX_COUNTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000008450ull + (((offset) & 7) * 16))
-#define CVMX_PEXP_NPEI_DMAX_DBELL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000083B0ull + (((offset) & 7) * 16))
-#define CVMX_PEXP_NPEI_DMAX_IBUFF_SADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000008400ull + (((offset) & 7) * 16))
-#define CVMX_PEXP_NPEI_DMAX_NADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F00000084A0ull + (((offset) & 7) * 16))
-#define CVMX_PEXP_NPEI_DMA_CNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000085E0ull)
-#define CVMX_PEXP_NPEI_DMA_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F00000083A0ull)
-#define CVMX_PEXP_NPEI_INT_A_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000008560ull)
-#define CVMX_PEXP_NPEI_INT_A_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCE0ull)
-#define CVMX_PEXP_NPEI_INT_A_SUM \
-	 CVMX_ADD_IO_SEG(0x00011F0000008550ull)
-#define CVMX_PEXP_NPEI_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000008540ull)
-#define CVMX_PEXP_NPEI_INT_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCD0ull)
-#define CVMX_PEXP_NPEI_INT_INFO \
-	 CVMX_ADD_IO_SEG(0x00011F0000008590ull)
-#define CVMX_PEXP_NPEI_INT_SUM \
-	 CVMX_ADD_IO_SEG(0x00011F0000008530ull)
-#define CVMX_PEXP_NPEI_INT_SUM2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCC0ull)
-#define CVMX_PEXP_NPEI_LAST_WIN_RDATA0 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008600ull)
-#define CVMX_PEXP_NPEI_LAST_WIN_RDATA1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008610ull)
-#define CVMX_PEXP_NPEI_MEM_ACCESS_CTL \
-	 CVMX_ADD_IO_SEG(0x00011F00000084F0ull)
-#define CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000008280ull + (((offset) & 31) * 16) - 16 * 12)
-#define CVMX_PEXP_NPEI_MSI_ENB0 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC50ull)
-#define CVMX_PEXP_NPEI_MSI_ENB1 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC60ull)
-#define CVMX_PEXP_NPEI_MSI_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC70ull)
-#define CVMX_PEXP_NPEI_MSI_ENB3 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC80ull)
-#define CVMX_PEXP_NPEI_MSI_RCV0 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC10ull)
-#define CVMX_PEXP_NPEI_MSI_RCV1 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC20ull)
-#define CVMX_PEXP_NPEI_MSI_RCV2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC30ull)
-#define CVMX_PEXP_NPEI_MSI_RCV3 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC40ull)
-#define CVMX_PEXP_NPEI_MSI_RD_MAP \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCA0ull)
-#define CVMX_PEXP_NPEI_MSI_W1C_ENB0 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCF0ull)
-#define CVMX_PEXP_NPEI_MSI_W1C_ENB1 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD00ull)
-#define CVMX_PEXP_NPEI_MSI_W1C_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD10ull)
-#define CVMX_PEXP_NPEI_MSI_W1C_ENB3 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD20ull)
-#define CVMX_PEXP_NPEI_MSI_W1S_ENB0 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD30ull)
-#define CVMX_PEXP_NPEI_MSI_W1S_ENB1 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD40ull)
-#define CVMX_PEXP_NPEI_MSI_W1S_ENB2 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD50ull)
-#define CVMX_PEXP_NPEI_MSI_W1S_ENB3 \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD60ull)
-#define CVMX_PEXP_NPEI_MSI_WR_MAP \
-	 CVMX_ADD_IO_SEG(0x00011F000000BC90ull)
-#define CVMX_PEXP_NPEI_PCIE_CREDIT_CNT \
-	 CVMX_ADD_IO_SEG(0x00011F000000BD70ull)
-#define CVMX_PEXP_NPEI_PCIE_MSI_RCV \
-	 CVMX_ADD_IO_SEG(0x00011F000000BCB0ull)
-#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008650ull)
-#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008660ull)
-#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B3 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008670ull)
-#define CVMX_PEXP_NPEI_PKTX_CNTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000A400ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_INSTR_BADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000A800ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_INSTR_BAOFF_DBELL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000AC00ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_INSTR_FIFO_RSIZE(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000B000ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_INSTR_HEADER(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000B400ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_IN_BP(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000B800ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_SLIST_BADDR(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000009400ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_SLIST_BAOFF_DBELL(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000009800ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKTX_SLIST_FIFO_RSIZE(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F0000009C00ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKT_CNT_INT \
-	 CVMX_ADD_IO_SEG(0x00011F0000009110ull)
-#define CVMX_PEXP_NPEI_PKT_CNT_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000009130ull)
-#define CVMX_PEXP_NPEI_PKT_DATA_OUT_ES \
-	 CVMX_ADD_IO_SEG(0x00011F00000090B0ull)
-#define CVMX_PEXP_NPEI_PKT_DATA_OUT_NS \
-	 CVMX_ADD_IO_SEG(0x00011F00000090A0ull)
-#define CVMX_PEXP_NPEI_PKT_DATA_OUT_ROR \
-	 CVMX_ADD_IO_SEG(0x00011F0000009090ull)
-#define CVMX_PEXP_NPEI_PKT_DPADDR \
-	 CVMX_ADD_IO_SEG(0x00011F0000009080ull)
-#define CVMX_PEXP_NPEI_PKT_INPUT_CONTROL \
-	 CVMX_ADD_IO_SEG(0x00011F0000009150ull)
-#define CVMX_PEXP_NPEI_PKT_INSTR_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000009000ull)
-#define CVMX_PEXP_NPEI_PKT_INSTR_RD_SIZE \
-	 CVMX_ADD_IO_SEG(0x00011F0000009190ull)
-#define CVMX_PEXP_NPEI_PKT_INSTR_SIZE \
-	 CVMX_ADD_IO_SEG(0x00011F0000009020ull)
-#define CVMX_PEXP_NPEI_PKT_INT_LEVELS \
-	 CVMX_ADD_IO_SEG(0x00011F0000009100ull)
-#define CVMX_PEXP_NPEI_PKT_IN_BP \
-	 CVMX_ADD_IO_SEG(0x00011F00000086B0ull)
-#define CVMX_PEXP_NPEI_PKT_IN_DONEX_CNTS(offset) \
-	 CVMX_ADD_IO_SEG(0x00011F000000A000ull + (((offset) & 31) * 16))
-#define CVMX_PEXP_NPEI_PKT_IN_INSTR_COUNTS \
-	 CVMX_ADD_IO_SEG(0x00011F00000086A0ull)
-#define CVMX_PEXP_NPEI_PKT_IN_PCIE_PORT \
-	 CVMX_ADD_IO_SEG(0x00011F00000091A0ull)
-#define CVMX_PEXP_NPEI_PKT_IPTR \
-	 CVMX_ADD_IO_SEG(0x00011F0000009070ull)
-#define CVMX_PEXP_NPEI_PKT_OUTPUT_WMARK \
-	 CVMX_ADD_IO_SEG(0x00011F0000009160ull)
-#define CVMX_PEXP_NPEI_PKT_OUT_BMODE \
-	 CVMX_ADD_IO_SEG(0x00011F00000090D0ull)
-#define CVMX_PEXP_NPEI_PKT_OUT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000009010ull)
-#define CVMX_PEXP_NPEI_PKT_PCIE_PORT \
-	 CVMX_ADD_IO_SEG(0x00011F00000090E0ull)
-#define CVMX_PEXP_NPEI_PKT_PORT_IN_RST \
-	 CVMX_ADD_IO_SEG(0x00011F0000008690ull)
-#define CVMX_PEXP_NPEI_PKT_SLIST_ES \
-	 CVMX_ADD_IO_SEG(0x00011F0000009050ull)
-#define CVMX_PEXP_NPEI_PKT_SLIST_ID_SIZE \
-	 CVMX_ADD_IO_SEG(0x00011F0000009180ull)
-#define CVMX_PEXP_NPEI_PKT_SLIST_NS \
-	 CVMX_ADD_IO_SEG(0x00011F0000009040ull)
-#define CVMX_PEXP_NPEI_PKT_SLIST_ROR \
-	 CVMX_ADD_IO_SEG(0x00011F0000009030ull)
-#define CVMX_PEXP_NPEI_PKT_TIME_INT \
-	 CVMX_ADD_IO_SEG(0x00011F0000009120ull)
-#define CVMX_PEXP_NPEI_PKT_TIME_INT_ENB \
-	 CVMX_ADD_IO_SEG(0x00011F0000009140ull)
-#define CVMX_PEXP_NPEI_RSL_INT_BLOCKS \
-	 CVMX_ADD_IO_SEG(0x00011F0000008520ull)
-#define CVMX_PEXP_NPEI_SCRATCH_1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008270ull)
-#define CVMX_PEXP_NPEI_STATE1 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008620ull)
-#define CVMX_PEXP_NPEI_STATE2 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008630ull)
-#define CVMX_PEXP_NPEI_STATE3 \
-	 CVMX_ADD_IO_SEG(0x00011F0000008640ull)
-#define CVMX_PEXP_NPEI_WINDOW_CTL \
-	 CVMX_ADD_IO_SEG(0x00011F0000008380ull)
+#define CVMX_PEXP_NPEI_BAR1_INDEXX(offset) (CVMX_ADD_IO_SEG(0x00011F0000008000ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011F0000008580ull))
+#define CVMX_PEXP_NPEI_BIST_STATUS2 (CVMX_ADD_IO_SEG(0x00011F0000008680ull))
+#define CVMX_PEXP_NPEI_CTL_PORT0 (CVMX_ADD_IO_SEG(0x00011F0000008250ull))
+#define CVMX_PEXP_NPEI_CTL_PORT1 (CVMX_ADD_IO_SEG(0x00011F0000008260ull))
+#define CVMX_PEXP_NPEI_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011F0000008570ull))
+#define CVMX_PEXP_NPEI_CTL_STATUS2 (CVMX_ADD_IO_SEG(0x00011F000000BC00ull))
+#define CVMX_PEXP_NPEI_DATA_OUT_CNT (CVMX_ADD_IO_SEG(0x00011F00000085F0ull))
+#define CVMX_PEXP_NPEI_DBG_DATA (CVMX_ADD_IO_SEG(0x00011F0000008510ull))
+#define CVMX_PEXP_NPEI_DBG_SELECT (CVMX_ADD_IO_SEG(0x00011F0000008500ull))
+#define CVMX_PEXP_NPEI_DMA0_INT_LEVEL (CVMX_ADD_IO_SEG(0x00011F00000085C0ull))
+#define CVMX_PEXP_NPEI_DMA1_INT_LEVEL (CVMX_ADD_IO_SEG(0x00011F00000085D0ull))
+#define CVMX_PEXP_NPEI_DMAX_COUNTS(offset) (CVMX_ADD_IO_SEG(0x00011F0000008450ull) + ((offset) & 7) * 16)
+#define CVMX_PEXP_NPEI_DMAX_DBELL(offset) (CVMX_ADD_IO_SEG(0x00011F00000083B0ull) + ((offset) & 7) * 16)
+#define CVMX_PEXP_NPEI_DMAX_IBUFF_SADDR(offset) (CVMX_ADD_IO_SEG(0x00011F0000008400ull) + ((offset) & 7) * 16)
+#define CVMX_PEXP_NPEI_DMAX_NADDR(offset) (CVMX_ADD_IO_SEG(0x00011F00000084A0ull) + ((offset) & 7) * 16)
+#define CVMX_PEXP_NPEI_DMA_CNTS (CVMX_ADD_IO_SEG(0x00011F00000085E0ull))
+#define CVMX_PEXP_NPEI_DMA_CONTROL (CVMX_ADD_IO_SEG(0x00011F00000083A0ull))
+#define CVMX_PEXP_NPEI_DMA_PCIE_REQ_NUM (CVMX_ADD_IO_SEG(0x00011F00000085B0ull))
+#define CVMX_PEXP_NPEI_DMA_STATE1 (CVMX_ADD_IO_SEG(0x00011F00000086C0ull))
+#define CVMX_PEXP_NPEI_DMA_STATE1_P1 (CVMX_ADD_IO_SEG(0x00011F0000008680ull))
+#define CVMX_PEXP_NPEI_DMA_STATE2 (CVMX_ADD_IO_SEG(0x00011F00000086D0ull))
+#define CVMX_PEXP_NPEI_DMA_STATE2_P1 (CVMX_ADD_IO_SEG(0x00011F0000008690ull))
+#define CVMX_PEXP_NPEI_DMA_STATE3_P1 (CVMX_ADD_IO_SEG(0x00011F00000086A0ull))
+#define CVMX_PEXP_NPEI_DMA_STATE4_P1 (CVMX_ADD_IO_SEG(0x00011F00000086B0ull))
+#define CVMX_PEXP_NPEI_DMA_STATE5_P1 (CVMX_ADD_IO_SEG(0x00011F00000086C0ull))
+#define CVMX_PEXP_NPEI_INT_A_ENB (CVMX_ADD_IO_SEG(0x00011F0000008560ull))
+#define CVMX_PEXP_NPEI_INT_A_ENB2 (CVMX_ADD_IO_SEG(0x00011F000000BCE0ull))
+#define CVMX_PEXP_NPEI_INT_A_SUM (CVMX_ADD_IO_SEG(0x00011F0000008550ull))
+#define CVMX_PEXP_NPEI_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000008540ull))
+#define CVMX_PEXP_NPEI_INT_ENB2 (CVMX_ADD_IO_SEG(0x00011F000000BCD0ull))
+#define CVMX_PEXP_NPEI_INT_INFO (CVMX_ADD_IO_SEG(0x00011F0000008590ull))
+#define CVMX_PEXP_NPEI_INT_SUM (CVMX_ADD_IO_SEG(0x00011F0000008530ull))
+#define CVMX_PEXP_NPEI_INT_SUM2 (CVMX_ADD_IO_SEG(0x00011F000000BCC0ull))
+#define CVMX_PEXP_NPEI_LAST_WIN_RDATA0 (CVMX_ADD_IO_SEG(0x00011F0000008600ull))
+#define CVMX_PEXP_NPEI_LAST_WIN_RDATA1 (CVMX_ADD_IO_SEG(0x00011F0000008610ull))
+#define CVMX_PEXP_NPEI_MEM_ACCESS_CTL (CVMX_ADD_IO_SEG(0x00011F00000084F0ull))
+#define CVMX_PEXP_NPEI_MEM_ACCESS_SUBIDX(offset) (CVMX_ADD_IO_SEG(0x00011F0000008280ull) + ((offset) & 31) * 16 - 16*12)
+#define CVMX_PEXP_NPEI_MSI_ENB0 (CVMX_ADD_IO_SEG(0x00011F000000BC50ull))
+#define CVMX_PEXP_NPEI_MSI_ENB1 (CVMX_ADD_IO_SEG(0x00011F000000BC60ull))
+#define CVMX_PEXP_NPEI_MSI_ENB2 (CVMX_ADD_IO_SEG(0x00011F000000BC70ull))
+#define CVMX_PEXP_NPEI_MSI_ENB3 (CVMX_ADD_IO_SEG(0x00011F000000BC80ull))
+#define CVMX_PEXP_NPEI_MSI_RCV0 (CVMX_ADD_IO_SEG(0x00011F000000BC10ull))
+#define CVMX_PEXP_NPEI_MSI_RCV1 (CVMX_ADD_IO_SEG(0x00011F000000BC20ull))
+#define CVMX_PEXP_NPEI_MSI_RCV2 (CVMX_ADD_IO_SEG(0x00011F000000BC30ull))
+#define CVMX_PEXP_NPEI_MSI_RCV3 (CVMX_ADD_IO_SEG(0x00011F000000BC40ull))
+#define CVMX_PEXP_NPEI_MSI_RD_MAP (CVMX_ADD_IO_SEG(0x00011F000000BCA0ull))
+#define CVMX_PEXP_NPEI_MSI_W1C_ENB0 (CVMX_ADD_IO_SEG(0x00011F000000BCF0ull))
+#define CVMX_PEXP_NPEI_MSI_W1C_ENB1 (CVMX_ADD_IO_SEG(0x00011F000000BD00ull))
+#define CVMX_PEXP_NPEI_MSI_W1C_ENB2 (CVMX_ADD_IO_SEG(0x00011F000000BD10ull))
+#define CVMX_PEXP_NPEI_MSI_W1C_ENB3 (CVMX_ADD_IO_SEG(0x00011F000000BD20ull))
+#define CVMX_PEXP_NPEI_MSI_W1S_ENB0 (CVMX_ADD_IO_SEG(0x00011F000000BD30ull))
+#define CVMX_PEXP_NPEI_MSI_W1S_ENB1 (CVMX_ADD_IO_SEG(0x00011F000000BD40ull))
+#define CVMX_PEXP_NPEI_MSI_W1S_ENB2 (CVMX_ADD_IO_SEG(0x00011F000000BD50ull))
+#define CVMX_PEXP_NPEI_MSI_W1S_ENB3 (CVMX_ADD_IO_SEG(0x00011F000000BD60ull))
+#define CVMX_PEXP_NPEI_MSI_WR_MAP (CVMX_ADD_IO_SEG(0x00011F000000BC90ull))
+#define CVMX_PEXP_NPEI_PCIE_CREDIT_CNT (CVMX_ADD_IO_SEG(0x00011F000000BD70ull))
+#define CVMX_PEXP_NPEI_PCIE_MSI_RCV (CVMX_ADD_IO_SEG(0x00011F000000BCB0ull))
+#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B1 (CVMX_ADD_IO_SEG(0x00011F0000008650ull))
+#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B2 (CVMX_ADD_IO_SEG(0x00011F0000008660ull))
+#define CVMX_PEXP_NPEI_PCIE_MSI_RCV_B3 (CVMX_ADD_IO_SEG(0x00011F0000008670ull))
+#define CVMX_PEXP_NPEI_PKTX_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F000000A400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_INSTR_BADDR(offset) (CVMX_ADD_IO_SEG(0x00011F000000A800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_INSTR_BAOFF_DBELL(offset) (CVMX_ADD_IO_SEG(0x00011F000000AC00ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_INSTR_FIFO_RSIZE(offset) (CVMX_ADD_IO_SEG(0x00011F000000B000ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_INSTR_HEADER(offset) (CVMX_ADD_IO_SEG(0x00011F000000B400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_IN_BP(offset) (CVMX_ADD_IO_SEG(0x00011F000000B800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_SLIST_BADDR(offset) (CVMX_ADD_IO_SEG(0x00011F0000009400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_SLIST_BAOFF_DBELL(offset) (CVMX_ADD_IO_SEG(0x00011F0000009800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKTX_SLIST_FIFO_RSIZE(offset) (CVMX_ADD_IO_SEG(0x00011F0000009C00ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKT_CNT_INT (CVMX_ADD_IO_SEG(0x00011F0000009110ull))
+#define CVMX_PEXP_NPEI_PKT_CNT_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000009130ull))
+#define CVMX_PEXP_NPEI_PKT_DATA_OUT_ES (CVMX_ADD_IO_SEG(0x00011F00000090B0ull))
+#define CVMX_PEXP_NPEI_PKT_DATA_OUT_NS (CVMX_ADD_IO_SEG(0x00011F00000090A0ull))
+#define CVMX_PEXP_NPEI_PKT_DATA_OUT_ROR (CVMX_ADD_IO_SEG(0x00011F0000009090ull))
+#define CVMX_PEXP_NPEI_PKT_DPADDR (CVMX_ADD_IO_SEG(0x00011F0000009080ull))
+#define CVMX_PEXP_NPEI_PKT_INPUT_CONTROL (CVMX_ADD_IO_SEG(0x00011F0000009150ull))
+#define CVMX_PEXP_NPEI_PKT_INSTR_ENB (CVMX_ADD_IO_SEG(0x00011F0000009000ull))
+#define CVMX_PEXP_NPEI_PKT_INSTR_RD_SIZE (CVMX_ADD_IO_SEG(0x00011F0000009190ull))
+#define CVMX_PEXP_NPEI_PKT_INSTR_SIZE (CVMX_ADD_IO_SEG(0x00011F0000009020ull))
+#define CVMX_PEXP_NPEI_PKT_INT_LEVELS (CVMX_ADD_IO_SEG(0x00011F0000009100ull))
+#define CVMX_PEXP_NPEI_PKT_IN_BP (CVMX_ADD_IO_SEG(0x00011F00000086B0ull))
+#define CVMX_PEXP_NPEI_PKT_IN_DONEX_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F000000A000ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_NPEI_PKT_IN_INSTR_COUNTS (CVMX_ADD_IO_SEG(0x00011F00000086A0ull))
+#define CVMX_PEXP_NPEI_PKT_IN_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000091A0ull))
+#define CVMX_PEXP_NPEI_PKT_IPTR (CVMX_ADD_IO_SEG(0x00011F0000009070ull))
+#define CVMX_PEXP_NPEI_PKT_OUTPUT_WMARK (CVMX_ADD_IO_SEG(0x00011F0000009160ull))
+#define CVMX_PEXP_NPEI_PKT_OUT_BMODE (CVMX_ADD_IO_SEG(0x00011F00000090D0ull))
+#define CVMX_PEXP_NPEI_PKT_OUT_ENB (CVMX_ADD_IO_SEG(0x00011F0000009010ull))
+#define CVMX_PEXP_NPEI_PKT_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000090E0ull))
+#define CVMX_PEXP_NPEI_PKT_PORT_IN_RST (CVMX_ADD_IO_SEG(0x00011F0000008690ull))
+#define CVMX_PEXP_NPEI_PKT_SLIST_ES (CVMX_ADD_IO_SEG(0x00011F0000009050ull))
+#define CVMX_PEXP_NPEI_PKT_SLIST_ID_SIZE (CVMX_ADD_IO_SEG(0x00011F0000009180ull))
+#define CVMX_PEXP_NPEI_PKT_SLIST_NS (CVMX_ADD_IO_SEG(0x00011F0000009040ull))
+#define CVMX_PEXP_NPEI_PKT_SLIST_ROR (CVMX_ADD_IO_SEG(0x00011F0000009030ull))
+#define CVMX_PEXP_NPEI_PKT_TIME_INT (CVMX_ADD_IO_SEG(0x00011F0000009120ull))
+#define CVMX_PEXP_NPEI_PKT_TIME_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000009140ull))
+#define CVMX_PEXP_NPEI_RSL_INT_BLOCKS (CVMX_ADD_IO_SEG(0x00011F0000008520ull))
+#define CVMX_PEXP_NPEI_SCRATCH_1 (CVMX_ADD_IO_SEG(0x00011F0000008270ull))
+#define CVMX_PEXP_NPEI_STATE1 (CVMX_ADD_IO_SEG(0x00011F0000008620ull))
+#define CVMX_PEXP_NPEI_STATE2 (CVMX_ADD_IO_SEG(0x00011F0000008630ull))
+#define CVMX_PEXP_NPEI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000008640ull))
+#define CVMX_PEXP_NPEI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F0000008380ull))
+#define CVMX_PEXP_SLI_BIST_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010580ull))
+#define CVMX_PEXP_SLI_CTL_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010050ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_CTL_STATUS (CVMX_ADD_IO_SEG(0x00011F0000010570ull))
+#define CVMX_PEXP_SLI_DATA_OUT_CNT (CVMX_ADD_IO_SEG(0x00011F00000105F0ull))
+#define CVMX_PEXP_SLI_DBG_DATA (CVMX_ADD_IO_SEG(0x00011F0000010310ull))
+#define CVMX_PEXP_SLI_DBG_SELECT (CVMX_ADD_IO_SEG(0x00011F0000010300ull))
+#define CVMX_PEXP_SLI_DMAX_CNT(offset) (CVMX_ADD_IO_SEG(0x00011F0000010400ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_DMAX_INT_LEVEL(offset) (CVMX_ADD_IO_SEG(0x00011F00000103E0ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_DMAX_TIM(offset) (CVMX_ADD_IO_SEG(0x00011F0000010420ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_INT_ENB_CIU (CVMX_ADD_IO_SEG(0x00011F0000013CD0ull))
+#define CVMX_PEXP_SLI_INT_ENB_PORTX(offset) (CVMX_ADD_IO_SEG(0x00011F0000010340ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_INT_SUM (CVMX_ADD_IO_SEG(0x00011F0000010330ull))
+#define CVMX_PEXP_SLI_LAST_WIN_RDATA0 (CVMX_ADD_IO_SEG(0x00011F0000010600ull))
+#define CVMX_PEXP_SLI_LAST_WIN_RDATA1 (CVMX_ADD_IO_SEG(0x00011F0000010610ull))
+#define CVMX_PEXP_SLI_MAC_CREDIT_CNT (CVMX_ADD_IO_SEG(0x00011F0000013D70ull))
+#define CVMX_PEXP_SLI_MEM_ACCESS_CTL (CVMX_ADD_IO_SEG(0x00011F00000102F0ull))
+#define CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(offset) (CVMX_ADD_IO_SEG(0x00011F00000100E0ull) + ((offset) & 31) * 16 - 16*12)
+#define CVMX_PEXP_SLI_MSI_ENB0 (CVMX_ADD_IO_SEG(0x00011F0000013C50ull))
+#define CVMX_PEXP_SLI_MSI_ENB1 (CVMX_ADD_IO_SEG(0x00011F0000013C60ull))
+#define CVMX_PEXP_SLI_MSI_ENB2 (CVMX_ADD_IO_SEG(0x00011F0000013C70ull))
+#define CVMX_PEXP_SLI_MSI_ENB3 (CVMX_ADD_IO_SEG(0x00011F0000013C80ull))
+#define CVMX_PEXP_SLI_MSI_RCV0 (CVMX_ADD_IO_SEG(0x00011F0000013C10ull))
+#define CVMX_PEXP_SLI_MSI_RCV1 (CVMX_ADD_IO_SEG(0x00011F0000013C20ull))
+#define CVMX_PEXP_SLI_MSI_RCV2 (CVMX_ADD_IO_SEG(0x00011F0000013C30ull))
+#define CVMX_PEXP_SLI_MSI_RCV3 (CVMX_ADD_IO_SEG(0x00011F0000013C40ull))
+#define CVMX_PEXP_SLI_MSI_RD_MAP (CVMX_ADD_IO_SEG(0x00011F0000013CA0ull))
+#define CVMX_PEXP_SLI_MSI_W1C_ENB0 (CVMX_ADD_IO_SEG(0x00011F0000013CF0ull))
+#define CVMX_PEXP_SLI_MSI_W1C_ENB1 (CVMX_ADD_IO_SEG(0x00011F0000013D00ull))
+#define CVMX_PEXP_SLI_MSI_W1C_ENB2 (CVMX_ADD_IO_SEG(0x00011F0000013D10ull))
+#define CVMX_PEXP_SLI_MSI_W1C_ENB3 (CVMX_ADD_IO_SEG(0x00011F0000013D20ull))
+#define CVMX_PEXP_SLI_MSI_W1S_ENB0 (CVMX_ADD_IO_SEG(0x00011F0000013D30ull))
+#define CVMX_PEXP_SLI_MSI_W1S_ENB1 (CVMX_ADD_IO_SEG(0x00011F0000013D40ull))
+#define CVMX_PEXP_SLI_MSI_W1S_ENB2 (CVMX_ADD_IO_SEG(0x00011F0000013D50ull))
+#define CVMX_PEXP_SLI_MSI_W1S_ENB3 (CVMX_ADD_IO_SEG(0x00011F0000013D60ull))
+#define CVMX_PEXP_SLI_MSI_WR_MAP (CVMX_ADD_IO_SEG(0x00011F0000013C90ull))
+#define CVMX_PEXP_SLI_PCIE_MSI_RCV (CVMX_ADD_IO_SEG(0x00011F0000013CB0ull))
+#define CVMX_PEXP_SLI_PCIE_MSI_RCV_B1 (CVMX_ADD_IO_SEG(0x00011F0000010650ull))
+#define CVMX_PEXP_SLI_PCIE_MSI_RCV_B2 (CVMX_ADD_IO_SEG(0x00011F0000010660ull))
+#define CVMX_PEXP_SLI_PCIE_MSI_RCV_B3 (CVMX_ADD_IO_SEG(0x00011F0000010670ull))
+#define CVMX_PEXP_SLI_PKTX_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F0000012400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_INSTR_BADDR(offset) (CVMX_ADD_IO_SEG(0x00011F0000012800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_INSTR_BAOFF_DBELL(offset) (CVMX_ADD_IO_SEG(0x00011F0000012C00ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_INSTR_FIFO_RSIZE(offset) (CVMX_ADD_IO_SEG(0x00011F0000013000ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_INSTR_HEADER(offset) (CVMX_ADD_IO_SEG(0x00011F0000013400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_IN_BP(offset) (CVMX_ADD_IO_SEG(0x00011F0000013800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_OUT_SIZE(offset) (CVMX_ADD_IO_SEG(0x00011F0000010C00ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_SLIST_BADDR(offset) (CVMX_ADD_IO_SEG(0x00011F0000011400ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_SLIST_BAOFF_DBELL(offset) (CVMX_ADD_IO_SEG(0x00011F0000011800ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKTX_SLIST_FIFO_RSIZE(offset) (CVMX_ADD_IO_SEG(0x00011F0000011C00ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKT_CNT_INT (CVMX_ADD_IO_SEG(0x00011F0000011130ull))
+#define CVMX_PEXP_SLI_PKT_CNT_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011150ull))
+#define CVMX_PEXP_SLI_PKT_CTL (CVMX_ADD_IO_SEG(0x00011F0000011220ull))
+#define CVMX_PEXP_SLI_PKT_DATA_OUT_ES (CVMX_ADD_IO_SEG(0x00011F00000110B0ull))
+#define CVMX_PEXP_SLI_PKT_DATA_OUT_NS (CVMX_ADD_IO_SEG(0x00011F00000110A0ull))
+#define CVMX_PEXP_SLI_PKT_DATA_OUT_ROR (CVMX_ADD_IO_SEG(0x00011F0000011090ull))
+#define CVMX_PEXP_SLI_PKT_DPADDR (CVMX_ADD_IO_SEG(0x00011F0000011080ull))
+#define CVMX_PEXP_SLI_PKT_INPUT_CONTROL (CVMX_ADD_IO_SEG(0x00011F0000011170ull))
+#define CVMX_PEXP_SLI_PKT_INSTR_ENB (CVMX_ADD_IO_SEG(0x00011F0000011000ull))
+#define CVMX_PEXP_SLI_PKT_INSTR_RD_SIZE (CVMX_ADD_IO_SEG(0x00011F00000111A0ull))
+#define CVMX_PEXP_SLI_PKT_INSTR_SIZE (CVMX_ADD_IO_SEG(0x00011F0000011020ull))
+#define CVMX_PEXP_SLI_PKT_INT_LEVELS (CVMX_ADD_IO_SEG(0x00011F0000011120ull))
+#define CVMX_PEXP_SLI_PKT_IN_BP (CVMX_ADD_IO_SEG(0x00011F0000011210ull))
+#define CVMX_PEXP_SLI_PKT_IN_DONEX_CNTS(offset) (CVMX_ADD_IO_SEG(0x00011F0000012000ull) + ((offset) & 31) * 16)
+#define CVMX_PEXP_SLI_PKT_IN_INSTR_COUNTS (CVMX_ADD_IO_SEG(0x00011F0000011200ull))
+#define CVMX_PEXP_SLI_PKT_IN_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000111B0ull))
+#define CVMX_PEXP_SLI_PKT_IPTR (CVMX_ADD_IO_SEG(0x00011F0000011070ull))
+#define CVMX_PEXP_SLI_PKT_OUTPUT_WMARK (CVMX_ADD_IO_SEG(0x00011F0000011180ull))
+#define CVMX_PEXP_SLI_PKT_OUT_BMODE (CVMX_ADD_IO_SEG(0x00011F00000110D0ull))
+#define CVMX_PEXP_SLI_PKT_OUT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011010ull))
+#define CVMX_PEXP_SLI_PKT_PCIE_PORT (CVMX_ADD_IO_SEG(0x00011F00000110E0ull))
+#define CVMX_PEXP_SLI_PKT_PORT_IN_RST (CVMX_ADD_IO_SEG(0x00011F00000111F0ull))
+#define CVMX_PEXP_SLI_PKT_SLIST_ES (CVMX_ADD_IO_SEG(0x00011F0000011050ull))
+#define CVMX_PEXP_SLI_PKT_SLIST_NS (CVMX_ADD_IO_SEG(0x00011F0000011040ull))
+#define CVMX_PEXP_SLI_PKT_SLIST_ROR (CVMX_ADD_IO_SEG(0x00011F0000011030ull))
+#define CVMX_PEXP_SLI_PKT_TIME_INT (CVMX_ADD_IO_SEG(0x00011F0000011140ull))
+#define CVMX_PEXP_SLI_PKT_TIME_INT_ENB (CVMX_ADD_IO_SEG(0x00011F0000011160ull))
+#define CVMX_PEXP_SLI_S2M_PORTX_CTL(offset) (CVMX_ADD_IO_SEG(0x00011F0000013D80ull) + ((offset) & 1) * 16)
+#define CVMX_PEXP_SLI_SCRATCH_1 (CVMX_ADD_IO_SEG(0x00011F00000103C0ull))
+#define CVMX_PEXP_SLI_SCRATCH_2 (CVMX_ADD_IO_SEG(0x00011F00000103D0ull))
+#define CVMX_PEXP_SLI_STATE1 (CVMX_ADD_IO_SEG(0x00011F0000010620ull))
+#define CVMX_PEXP_SLI_STATE2 (CVMX_ADD_IO_SEG(0x00011F0000010630ull))
+#define CVMX_PEXP_SLI_STATE3 (CVMX_ADD_IO_SEG(0x00011F0000010640ull))
+#define CVMX_PEXP_SLI_WINDOW_CTL (CVMX_ADD_IO_SEG(0x00011F00000102E0ull))
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pow-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pow-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-pow-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-pow-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,52 +28,29 @@
 #ifndef __CVMX_POW_DEFS_H__
 #define __CVMX_POW_DEFS_H__
 
-#define CVMX_POW_BIST_STAT \
-	 CVMX_ADD_IO_SEG(0x00016700000003F8ull)
-#define CVMX_POW_DS_PC \
-	 CVMX_ADD_IO_SEG(0x0001670000000398ull)
-#define CVMX_POW_ECC_ERR \
-	 CVMX_ADD_IO_SEG(0x0001670000000218ull)
-#define CVMX_POW_INT_CTL \
-	 CVMX_ADD_IO_SEG(0x0001670000000220ull)
-#define CVMX_POW_IQ_CNTX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000340ull + (((offset) & 7) * 8))
-#define CVMX_POW_IQ_COM_CNT \
-	 CVMX_ADD_IO_SEG(0x0001670000000388ull)
-#define CVMX_POW_IQ_INT \
-	 CVMX_ADD_IO_SEG(0x0001670000000238ull)
-#define CVMX_POW_IQ_INT_EN \
-	 CVMX_ADD_IO_SEG(0x0001670000000240ull)
-#define CVMX_POW_IQ_THRX(offset) \
-	 CVMX_ADD_IO_SEG(0x00016700000003A0ull + (((offset) & 7) * 8))
-#define CVMX_POW_NOS_CNT \
-	 CVMX_ADD_IO_SEG(0x0001670000000228ull)
-#define CVMX_POW_NW_TIM \
-	 CVMX_ADD_IO_SEG(0x0001670000000210ull)
-#define CVMX_POW_PF_RST_MSK \
-	 CVMX_ADD_IO_SEG(0x0001670000000230ull)
-#define CVMX_POW_PP_GRP_MSKX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000000ull + (((offset) & 15) * 8))
-#define CVMX_POW_QOS_RNDX(offset) \
-	 CVMX_ADD_IO_SEG(0x00016700000001C0ull + (((offset) & 7) * 8))
-#define CVMX_POW_QOS_THRX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000180ull + (((offset) & 7) * 8))
-#define CVMX_POW_TS_PC \
-	 CVMX_ADD_IO_SEG(0x0001670000000390ull)
-#define CVMX_POW_WA_COM_PC \
-	 CVMX_ADD_IO_SEG(0x0001670000000380ull)
-#define CVMX_POW_WA_PCX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000300ull + (((offset) & 7) * 8))
-#define CVMX_POW_WQ_INT \
-	 CVMX_ADD_IO_SEG(0x0001670000000200ull)
-#define CVMX_POW_WQ_INT_CNTX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000100ull + (((offset) & 15) * 8))
-#define CVMX_POW_WQ_INT_PC \
-	 CVMX_ADD_IO_SEG(0x0001670000000208ull)
-#define CVMX_POW_WQ_INT_THRX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000080ull + (((offset) & 15) * 8))
-#define CVMX_POW_WS_PCX(offset) \
-	 CVMX_ADD_IO_SEG(0x0001670000000280ull + (((offset) & 15) * 8))
+#define CVMX_POW_BIST_STAT (CVMX_ADD_IO_SEG(0x00016700000003F8ull))
+#define CVMX_POW_DS_PC (CVMX_ADD_IO_SEG(0x0001670000000398ull))
+#define CVMX_POW_ECC_ERR (CVMX_ADD_IO_SEG(0x0001670000000218ull))
+#define CVMX_POW_INT_CTL (CVMX_ADD_IO_SEG(0x0001670000000220ull))
+#define CVMX_POW_IQ_CNTX(offset) (CVMX_ADD_IO_SEG(0x0001670000000340ull) + ((offset) & 7) * 8)
+#define CVMX_POW_IQ_COM_CNT (CVMX_ADD_IO_SEG(0x0001670000000388ull))
+#define CVMX_POW_IQ_INT (CVMX_ADD_IO_SEG(0x0001670000000238ull))
+#define CVMX_POW_IQ_INT_EN (CVMX_ADD_IO_SEG(0x0001670000000240ull))
+#define CVMX_POW_IQ_THRX(offset) (CVMX_ADD_IO_SEG(0x00016700000003A0ull) + ((offset) & 7) * 8)
+#define CVMX_POW_NOS_CNT (CVMX_ADD_IO_SEG(0x0001670000000228ull))
+#define CVMX_POW_NW_TIM (CVMX_ADD_IO_SEG(0x0001670000000210ull))
+#define CVMX_POW_PF_RST_MSK (CVMX_ADD_IO_SEG(0x0001670000000230ull))
+#define CVMX_POW_PP_GRP_MSKX(offset) (CVMX_ADD_IO_SEG(0x0001670000000000ull) + ((offset) & 15) * 8)
+#define CVMX_POW_QOS_RNDX(offset) (CVMX_ADD_IO_SEG(0x00016700000001C0ull) + ((offset) & 7) * 8)
+#define CVMX_POW_QOS_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000180ull) + ((offset) & 7) * 8)
+#define CVMX_POW_TS_PC (CVMX_ADD_IO_SEG(0x0001670000000390ull))
+#define CVMX_POW_WA_COM_PC (CVMX_ADD_IO_SEG(0x0001670000000380ull))
+#define CVMX_POW_WA_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000300ull) + ((offset) & 7) * 8)
+#define CVMX_POW_WQ_INT (CVMX_ADD_IO_SEG(0x0001670000000200ull))
+#define CVMX_POW_WQ_INT_CNTX(offset) (CVMX_ADD_IO_SEG(0x0001670000000100ull) + ((offset) & 15) * 8)
+#define CVMX_POW_WQ_INT_PC (CVMX_ADD_IO_SEG(0x0001670000000208ull))
+#define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8)
+#define CVMX_POW_WS_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000280ull) + ((offset) & 15) * 8)
 
 union cvmx_pow_bist_stat {
 	uint64_t u64;
@@ -160,6 +137,19 @@
 	struct cvmx_pow_bist_stat_cn56xx cn56xxp1;
 	struct cvmx_pow_bist_stat_cn38xx cn58xx;
 	struct cvmx_pow_bist_stat_cn38xx cn58xxp1;
+	struct cvmx_pow_bist_stat_cn63xx {
+		uint64_t reserved_22_63:42;
+		uint64_t pp:6;
+		uint64_t reserved_12_15:4;
+		uint64_t cam:1;
+		uint64_t nbr:3;
+		uint64_t nbt:4;
+		uint64_t index:1;
+		uint64_t fidx:1;
+		uint64_t pend:1;
+		uint64_t adr:1;
+	} cn63xx;
+	struct cvmx_pow_bist_stat_cn63xx cn63xxp1;
 };
 
 union cvmx_pow_ds_pc {
@@ -179,6 +169,8 @@
 	struct cvmx_pow_ds_pc_s cn56xxp1;
 	struct cvmx_pow_ds_pc_s cn58xx;
 	struct cvmx_pow_ds_pc_s cn58xxp1;
+	struct cvmx_pow_ds_pc_s cn63xx;
+	struct cvmx_pow_ds_pc_s cn63xxp1;
 };
 
 union cvmx_pow_ecc_err {
@@ -219,6 +211,8 @@
 	struct cvmx_pow_ecc_err_s cn56xxp1;
 	struct cvmx_pow_ecc_err_s cn58xx;
 	struct cvmx_pow_ecc_err_s cn58xxp1;
+	struct cvmx_pow_ecc_err_s cn63xx;
+	struct cvmx_pow_ecc_err_s cn63xxp1;
 };
 
 union cvmx_pow_int_ctl {
@@ -239,6 +233,8 @@
 	struct cvmx_pow_int_ctl_s cn56xxp1;
 	struct cvmx_pow_int_ctl_s cn58xx;
 	struct cvmx_pow_int_ctl_s cn58xxp1;
+	struct cvmx_pow_int_ctl_s cn63xx;
+	struct cvmx_pow_int_ctl_s cn63xxp1;
 };
 
 union cvmx_pow_iq_cntx {
@@ -258,6 +254,8 @@
 	struct cvmx_pow_iq_cntx_s cn56xxp1;
 	struct cvmx_pow_iq_cntx_s cn58xx;
 	struct cvmx_pow_iq_cntx_s cn58xxp1;
+	struct cvmx_pow_iq_cntx_s cn63xx;
+	struct cvmx_pow_iq_cntx_s cn63xxp1;
 };
 
 union cvmx_pow_iq_com_cnt {
@@ -277,6 +275,8 @@
 	struct cvmx_pow_iq_com_cnt_s cn56xxp1;
 	struct cvmx_pow_iq_com_cnt_s cn58xx;
 	struct cvmx_pow_iq_com_cnt_s cn58xxp1;
+	struct cvmx_pow_iq_com_cnt_s cn63xx;
+	struct cvmx_pow_iq_com_cnt_s cn63xxp1;
 };
 
 union cvmx_pow_iq_int {
@@ -289,6 +289,8 @@
 	struct cvmx_pow_iq_int_s cn52xxp1;
 	struct cvmx_pow_iq_int_s cn56xx;
 	struct cvmx_pow_iq_int_s cn56xxp1;
+	struct cvmx_pow_iq_int_s cn63xx;
+	struct cvmx_pow_iq_int_s cn63xxp1;
 };
 
 union cvmx_pow_iq_int_en {
@@ -301,6 +303,8 @@
 	struct cvmx_pow_iq_int_en_s cn52xxp1;
 	struct cvmx_pow_iq_int_en_s cn56xx;
 	struct cvmx_pow_iq_int_en_s cn56xxp1;
+	struct cvmx_pow_iq_int_en_s cn63xx;
+	struct cvmx_pow_iq_int_en_s cn63xxp1;
 };
 
 union cvmx_pow_iq_thrx {
@@ -313,6 +317,8 @@
 	struct cvmx_pow_iq_thrx_s cn52xxp1;
 	struct cvmx_pow_iq_thrx_s cn56xx;
 	struct cvmx_pow_iq_thrx_s cn56xxp1;
+	struct cvmx_pow_iq_thrx_s cn63xx;
+	struct cvmx_pow_iq_thrx_s cn63xxp1;
 };
 
 union cvmx_pow_nos_cnt {
@@ -341,6 +347,11 @@
 	struct cvmx_pow_nos_cnt_s cn56xxp1;
 	struct cvmx_pow_nos_cnt_s cn58xx;
 	struct cvmx_pow_nos_cnt_s cn58xxp1;
+	struct cvmx_pow_nos_cnt_cn63xx {
+		uint64_t reserved_11_63:53;
+		uint64_t nos_cnt:11;
+	} cn63xx;
+	struct cvmx_pow_nos_cnt_cn63xx cn63xxp1;
 };
 
 union cvmx_pow_nw_tim {
@@ -360,6 +371,8 @@
 	struct cvmx_pow_nw_tim_s cn56xxp1;
 	struct cvmx_pow_nw_tim_s cn58xx;
 	struct cvmx_pow_nw_tim_s cn58xxp1;
+	struct cvmx_pow_nw_tim_s cn63xx;
+	struct cvmx_pow_nw_tim_s cn63xxp1;
 };
 
 union cvmx_pow_pf_rst_msk {
@@ -375,6 +388,8 @@
 	struct cvmx_pow_pf_rst_msk_s cn56xxp1;
 	struct cvmx_pow_pf_rst_msk_s cn58xx;
 	struct cvmx_pow_pf_rst_msk_s cn58xxp1;
+	struct cvmx_pow_pf_rst_msk_s cn63xx;
+	struct cvmx_pow_pf_rst_msk_s cn63xxp1;
 };
 
 union cvmx_pow_pp_grp_mskx {
@@ -405,6 +420,8 @@
 	struct cvmx_pow_pp_grp_mskx_s cn56xxp1;
 	struct cvmx_pow_pp_grp_mskx_s cn58xx;
 	struct cvmx_pow_pp_grp_mskx_s cn58xxp1;
+	struct cvmx_pow_pp_grp_mskx_s cn63xx;
+	struct cvmx_pow_pp_grp_mskx_s cn63xxp1;
 };
 
 union cvmx_pow_qos_rndx {
@@ -427,6 +444,8 @@
 	struct cvmx_pow_qos_rndx_s cn56xxp1;
 	struct cvmx_pow_qos_rndx_s cn58xx;
 	struct cvmx_pow_qos_rndx_s cn58xxp1;
+	struct cvmx_pow_qos_rndx_s cn63xx;
+	struct cvmx_pow_qos_rndx_s cn63xxp1;
 };
 
 union cvmx_pow_qos_thrx {
@@ -485,6 +504,19 @@
 	struct cvmx_pow_qos_thrx_s cn56xxp1;
 	struct cvmx_pow_qos_thrx_s cn58xx;
 	struct cvmx_pow_qos_thrx_s cn58xxp1;
+	struct cvmx_pow_qos_thrx_cn63xx {
+		uint64_t reserved_59_63:5;
+		uint64_t des_cnt:11;
+		uint64_t reserved_47_47:1;
+		uint64_t buf_cnt:11;
+		uint64_t reserved_35_35:1;
+		uint64_t free_cnt:11;
+		uint64_t reserved_22_23:2;
+		uint64_t max_thr:10;
+		uint64_t reserved_10_11:2;
+		uint64_t min_thr:10;
+	} cn63xx;
+	struct cvmx_pow_qos_thrx_cn63xx cn63xxp1;
 };
 
 union cvmx_pow_ts_pc {
@@ -504,6 +536,8 @@
 	struct cvmx_pow_ts_pc_s cn56xxp1;
 	struct cvmx_pow_ts_pc_s cn58xx;
 	struct cvmx_pow_ts_pc_s cn58xxp1;
+	struct cvmx_pow_ts_pc_s cn63xx;
+	struct cvmx_pow_ts_pc_s cn63xxp1;
 };
 
 union cvmx_pow_wa_com_pc {
@@ -523,6 +557,8 @@
 	struct cvmx_pow_wa_com_pc_s cn56xxp1;
 	struct cvmx_pow_wa_com_pc_s cn58xx;
 	struct cvmx_pow_wa_com_pc_s cn58xxp1;
+	struct cvmx_pow_wa_com_pc_s cn63xx;
+	struct cvmx_pow_wa_com_pc_s cn63xxp1;
 };
 
 union cvmx_pow_wa_pcx {
@@ -542,6 +578,8 @@
 	struct cvmx_pow_wa_pcx_s cn56xxp1;
 	struct cvmx_pow_wa_pcx_s cn58xx;
 	struct cvmx_pow_wa_pcx_s cn58xxp1;
+	struct cvmx_pow_wa_pcx_s cn63xx;
+	struct cvmx_pow_wa_pcx_s cn63xxp1;
 };
 
 union cvmx_pow_wq_int {
@@ -562,6 +600,8 @@
 	struct cvmx_pow_wq_int_s cn56xxp1;
 	struct cvmx_pow_wq_int_s cn58xx;
 	struct cvmx_pow_wq_int_s cn58xxp1;
+	struct cvmx_pow_wq_int_s cn63xx;
+	struct cvmx_pow_wq_int_s cn63xxp1;
 };
 
 union cvmx_pow_wq_int_cntx {
@@ -604,6 +644,15 @@
 	struct cvmx_pow_wq_int_cntx_s cn56xxp1;
 	struct cvmx_pow_wq_int_cntx_s cn58xx;
 	struct cvmx_pow_wq_int_cntx_s cn58xxp1;
+	struct cvmx_pow_wq_int_cntx_cn63xx {
+		uint64_t reserved_28_63:36;
+		uint64_t tc_cnt:4;
+		uint64_t reserved_23_23:1;
+		uint64_t ds_cnt:11;
+		uint64_t reserved_11_11:1;
+		uint64_t iq_cnt:11;
+	} cn63xx;
+	struct cvmx_pow_wq_int_cntx_cn63xx cn63xxp1;
 };
 
 union cvmx_pow_wq_int_pc {
@@ -626,6 +675,8 @@
 	struct cvmx_pow_wq_int_pc_s cn56xxp1;
 	struct cvmx_pow_wq_int_pc_s cn58xx;
 	struct cvmx_pow_wq_int_pc_s cn58xxp1;
+	struct cvmx_pow_wq_int_pc_s cn63xx;
+	struct cvmx_pow_wq_int_pc_s cn63xxp1;
 };
 
 union cvmx_pow_wq_int_thrx {
@@ -674,6 +725,16 @@
 	struct cvmx_pow_wq_int_thrx_s cn56xxp1;
 	struct cvmx_pow_wq_int_thrx_s cn58xx;
 	struct cvmx_pow_wq_int_thrx_s cn58xxp1;
+	struct cvmx_pow_wq_int_thrx_cn63xx {
+		uint64_t reserved_29_63:35;
+		uint64_t tc_en:1;
+		uint64_t tc_thr:4;
+		uint64_t reserved_22_23:2;
+		uint64_t ds_thr:10;
+		uint64_t reserved_10_11:2;
+		uint64_t iq_thr:10;
+	} cn63xx;
+	struct cvmx_pow_wq_int_thrx_cn63xx cn63xxp1;
 };
 
 union cvmx_pow_ws_pcx {
@@ -693,6 +754,8 @@
 	struct cvmx_pow_ws_pcx_s cn56xxp1;
 	struct cvmx_pow_ws_pcx_s cn58xx;
 	struct cvmx_pow_ws_pcx_s cn58xxp1;
+	struct cvmx_pow_ws_pcx_s cn63xx;
+	struct cvmx_pow_ws_pcx_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-rnm-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-rnm-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-rnm-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-rnm-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -30,10 +30,11 @@
 
 #include <linux/types.h>
 
-#define CVMX_RNM_BIST_STATUS \
-	 CVMX_ADD_IO_SEG(0x0001180040000008ull)
-#define CVMX_RNM_CTL_STATUS \
-	 CVMX_ADD_IO_SEG(0x0001180040000000ull)
+#define CVMX_RNM_BIST_STATUS (CVMX_ADD_IO_SEG(0x0001180040000008ull))
+#define CVMX_RNM_CTL_STATUS (CVMX_ADD_IO_SEG(0x0001180040000000ull))
+#define CVMX_RNM_EER_DBG (CVMX_ADD_IO_SEG(0x0001180040000018ull))
+#define CVMX_RNM_EER_KEY (CVMX_ADD_IO_SEG(0x0001180040000010ull))
+#define CVMX_RNM_SERIAL_NUM (CVMX_ADD_IO_SEG(0x0001180040000020ull))
 
 union cvmx_rnm_bist_status {
 	uint64_t u64;
@@ -53,12 +54,16 @@
 	struct cvmx_rnm_bist_status_s cn56xxp1;
 	struct cvmx_rnm_bist_status_s cn58xx;
 	struct cvmx_rnm_bist_status_s cn58xxp1;
+	struct cvmx_rnm_bist_status_s cn63xx;
+	struct cvmx_rnm_bist_status_s cn63xxp1;
 };
 
 union cvmx_rnm_ctl_status {
 	uint64_t u64;
 	struct cvmx_rnm_ctl_status_s {
-		uint64_t reserved_9_63:55;
+		uint64_t reserved_11_63:53;
+		uint64_t eer_lck:1;
+		uint64_t eer_val:1;
 		uint64_t ent_sel:4;
 		uint64_t exp_ent:1;
 		uint64_t rng_rst:1;
@@ -76,13 +81,49 @@
 	struct cvmx_rnm_ctl_status_cn30xx cn31xx;
 	struct cvmx_rnm_ctl_status_cn30xx cn38xx;
 	struct cvmx_rnm_ctl_status_cn30xx cn38xxp2;
-	struct cvmx_rnm_ctl_status_s cn50xx;
-	struct cvmx_rnm_ctl_status_s cn52xx;
-	struct cvmx_rnm_ctl_status_s cn52xxp1;
-	struct cvmx_rnm_ctl_status_s cn56xx;
-	struct cvmx_rnm_ctl_status_s cn56xxp1;
-	struct cvmx_rnm_ctl_status_s cn58xx;
-	struct cvmx_rnm_ctl_status_s cn58xxp1;
+	struct cvmx_rnm_ctl_status_cn50xx {
+		uint64_t reserved_9_63:55;
+		uint64_t ent_sel:4;
+		uint64_t exp_ent:1;
+		uint64_t rng_rst:1;
+		uint64_t rnm_rst:1;
+		uint64_t rng_en:1;
+		uint64_t ent_en:1;
+	} cn50xx;
+	struct cvmx_rnm_ctl_status_cn50xx cn52xx;
+	struct cvmx_rnm_ctl_status_cn50xx cn52xxp1;
+	struct cvmx_rnm_ctl_status_cn50xx cn56xx;
+	struct cvmx_rnm_ctl_status_cn50xx cn56xxp1;
+	struct cvmx_rnm_ctl_status_cn50xx cn58xx;
+	struct cvmx_rnm_ctl_status_cn50xx cn58xxp1;
+	struct cvmx_rnm_ctl_status_s cn63xx;
+	struct cvmx_rnm_ctl_status_s cn63xxp1;
+};
+
+union cvmx_rnm_eer_dbg {
+	uint64_t u64;
+	struct cvmx_rnm_eer_dbg_s {
+		uint64_t dat:64;
+	} s;
+	struct cvmx_rnm_eer_dbg_s cn63xx;
+	struct cvmx_rnm_eer_dbg_s cn63xxp1;
+};
+
+union cvmx_rnm_eer_key {
+	uint64_t u64;
+	struct cvmx_rnm_eer_key_s {
+		uint64_t key:64;
+	} s;
+	struct cvmx_rnm_eer_key_s cn63xx;
+	struct cvmx_rnm_eer_key_s cn63xxp1;
+};
+
+union cvmx_rnm_serial_num {
+	uint64_t u64;
+	struct cvmx_rnm_serial_num_s {
+		uint64_t dat:64;
+	} s;
+	struct cvmx_rnm_serial_num_s cn63xx;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-smix-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-smix-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-smix-defs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-smix-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * Contact: support@caviumnetworks.com
  * This file is part of the OCTEON SDK
  *
- * Copyright (c) 2003-2008 Cavium Networks
+ * Copyright (c) 2003-2010 Cavium Networks
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, Version 2, as
@@ -28,16 +28,11 @@
 #ifndef __CVMX_SMIX_DEFS_H__
 #define __CVMX_SMIX_DEFS_H__
 
-#define CVMX_SMIX_CLK(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_CMD(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_EN(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_RD_DAT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256))
-#define CVMX_SMIX_WR_DAT(offset) \
-	 CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256))
+#define CVMX_SMIX_CLK(offset) (CVMX_ADD_IO_SEG(0x0001180000001818ull) + ((offset) & 1) * 256)
+#define CVMX_SMIX_CMD(offset) (CVMX_ADD_IO_SEG(0x0001180000001800ull) + ((offset) & 1) * 256)
+#define CVMX_SMIX_EN(offset) (CVMX_ADD_IO_SEG(0x0001180000001820ull) + ((offset) & 1) * 256)
+#define CVMX_SMIX_RD_DAT(offset) (CVMX_ADD_IO_SEG(0x0001180000001810ull) + ((offset) & 1) * 256)
+#define CVMX_SMIX_WR_DAT(offset) (CVMX_ADD_IO_SEG(0x0001180000001808ull) + ((offset) & 1) * 256)
 
 union cvmx_smix_clk {
 	uint64_t u64;
@@ -56,7 +51,8 @@
 	struct cvmx_smix_clk_cn30xx {
 		uint64_t reserved_21_63:43;
 		uint64_t sample_hi:5;
-		uint64_t reserved_14_15:2;
+		uint64_t sample_mode:1;
+		uint64_t reserved_14_14:1;
 		uint64_t clk_idle:1;
 		uint64_t preamble:1;
 		uint64_t sample:4;
@@ -65,23 +61,15 @@
 	struct cvmx_smix_clk_cn30xx cn31xx;
 	struct cvmx_smix_clk_cn30xx cn38xx;
 	struct cvmx_smix_clk_cn30xx cn38xxp2;
-	struct cvmx_smix_clk_cn50xx {
-		uint64_t reserved_25_63:39;
-		uint64_t mode:1;
-		uint64_t reserved_21_23:3;
-		uint64_t sample_hi:5;
-		uint64_t reserved_14_15:2;
-		uint64_t clk_idle:1;
-		uint64_t preamble:1;
-		uint64_t sample:4;
-		uint64_t phase:8;
-	} cn50xx;
+	struct cvmx_smix_clk_s cn50xx;
 	struct cvmx_smix_clk_s cn52xx;
-	struct cvmx_smix_clk_cn50xx cn52xxp1;
+	struct cvmx_smix_clk_s cn52xxp1;
 	struct cvmx_smix_clk_s cn56xx;
-	struct cvmx_smix_clk_cn50xx cn56xxp1;
+	struct cvmx_smix_clk_s cn56xxp1;
 	struct cvmx_smix_clk_cn30xx cn58xx;
 	struct cvmx_smix_clk_cn30xx cn58xxp1;
+	struct cvmx_smix_clk_s cn63xx;
+	struct cvmx_smix_clk_s cn63xxp1;
 };
 
 union cvmx_smix_cmd {
@@ -112,6 +100,8 @@
 	struct cvmx_smix_cmd_s cn56xxp1;
 	struct cvmx_smix_cmd_cn30xx cn58xx;
 	struct cvmx_smix_cmd_cn30xx cn58xxp1;
+	struct cvmx_smix_cmd_s cn63xx;
+	struct cvmx_smix_cmd_s cn63xxp1;
 };
 
 union cvmx_smix_en {
@@ -131,6 +121,8 @@
 	struct cvmx_smix_en_s cn56xxp1;
 	struct cvmx_smix_en_s cn58xx;
 	struct cvmx_smix_en_s cn58xxp1;
+	struct cvmx_smix_en_s cn63xx;
+	struct cvmx_smix_en_s cn63xxp1;
 };
 
 union cvmx_smix_rd_dat {
@@ -152,6 +144,8 @@
 	struct cvmx_smix_rd_dat_s cn56xxp1;
 	struct cvmx_smix_rd_dat_s cn58xx;
 	struct cvmx_smix_rd_dat_s cn58xxp1;
+	struct cvmx_smix_rd_dat_s cn63xx;
+	struct cvmx_smix_rd_dat_s cn63xxp1;
 };
 
 union cvmx_smix_wr_dat {
@@ -173,6 +167,8 @@
 	struct cvmx_smix_wr_dat_s cn56xxp1;
 	struct cvmx_smix_wr_dat_s cn58xx;
 	struct cvmx_smix_wr_dat_s cn58xxp1;
+	struct cvmx_smix_wr_dat_s cn63xx;
+	struct cvmx_smix_wr_dat_s cn63xxp1;
 };
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/cvmx-uctlx-defs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,261 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2010 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_UCTLX_TYPEDEFS_H__
+#define __CVMX_UCTLX_TYPEDEFS_H__
+
+#define CVMX_UCTLX_BIST_STATUS(block_id) (CVMX_ADD_IO_SEG(0x000118006F0000A0ull))
+#define CVMX_UCTLX_CLK_RST_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000000ull))
+#define CVMX_UCTLX_EHCI_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000080ull))
+#define CVMX_UCTLX_EHCI_FLA(block_id) (CVMX_ADD_IO_SEG(0x000118006F0000A8ull))
+#define CVMX_UCTLX_ERTO_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000090ull))
+#define CVMX_UCTLX_IF_ENA(block_id) (CVMX_ADD_IO_SEG(0x000118006F000030ull))
+#define CVMX_UCTLX_INT_ENA(block_id) (CVMX_ADD_IO_SEG(0x000118006F000028ull))
+#define CVMX_UCTLX_INT_REG(block_id) (CVMX_ADD_IO_SEG(0x000118006F000020ull))
+#define CVMX_UCTLX_OHCI_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000088ull))
+#define CVMX_UCTLX_ORTO_CTL(block_id) (CVMX_ADD_IO_SEG(0x000118006F000098ull))
+#define CVMX_UCTLX_PPAF_WM(block_id) (CVMX_ADD_IO_SEG(0x000118006F000038ull))
+#define CVMX_UCTLX_UPHY_CTL_STATUS(block_id) (CVMX_ADD_IO_SEG(0x000118006F000008ull))
+#define CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(offset, block_id) (CVMX_ADD_IO_SEG(0x000118006F000010ull) + (((offset) & 1) + ((block_id) & 0) * 0x0ull) * 8)
+
+union cvmx_uctlx_bist_status {
+	uint64_t u64;
+	struct cvmx_uctlx_bist_status_s {
+		uint64_t reserved_6_63:58;
+		uint64_t data_bis:1;
+		uint64_t desc_bis:1;
+		uint64_t erbm_bis:1;
+		uint64_t orbm_bis:1;
+		uint64_t wrbm_bis:1;
+		uint64_t ppaf_bis:1;
+	} s;
+	struct cvmx_uctlx_bist_status_s       cn63xx;
+	struct cvmx_uctlx_bist_status_s       cn63xxp1;
+};
+
+union cvmx_uctlx_clk_rst_ctl {
+	uint64_t u64;
+	struct cvmx_uctlx_clk_rst_ctl_s {
+		uint64_t reserved_25_63:39;
+		uint64_t clear_bist:1;
+		uint64_t start_bist:1;
+		uint64_t ehci_sm:1;
+		uint64_t ohci_clkcktrst:1;
+		uint64_t ohci_sm:1;
+		uint64_t ohci_susp_lgcy:1;
+		uint64_t app_start_clk:1;
+		uint64_t o_clkdiv_rst:1;
+		uint64_t h_clkdiv_byp:1;
+		uint64_t h_clkdiv_rst:1;
+		uint64_t h_clkdiv_en:1;
+		uint64_t o_clkdiv_en:1;
+		uint64_t h_div:4;
+		uint64_t p_refclk_sel:2;
+		uint64_t p_refclk_div:2;
+		uint64_t reserved_4_4:1;
+		uint64_t p_com_on:1;
+		uint64_t p_por:1;
+		uint64_t p_prst:1;
+		uint64_t hrst:1;
+	} s;
+	struct cvmx_uctlx_clk_rst_ctl_s       cn63xx;
+	struct cvmx_uctlx_clk_rst_ctl_s       cn63xxp1;
+};
+
+union cvmx_uctlx_ehci_ctl {
+	uint64_t u64;
+	struct cvmx_uctlx_ehci_ctl_s {
+		uint64_t reserved_20_63:44;
+		uint64_t desc_rbm:1;
+		uint64_t reg_nb:1;
+		uint64_t l2c_dc:1;
+		uint64_t l2c_bc:1;
+		uint64_t l2c_0pag:1;
+		uint64_t l2c_stt:1;
+		uint64_t l2c_buff_emod:2;
+		uint64_t l2c_desc_emod:2;
+		uint64_t inv_reg_a2:1;
+		uint64_t ehci_64b_addr_en:1;
+		uint64_t l2c_addr_msb:8;
+	} s;
+	struct cvmx_uctlx_ehci_ctl_s          cn63xx;
+	struct cvmx_uctlx_ehci_ctl_s          cn63xxp1;
+};
+
+union cvmx_uctlx_ehci_fla {
+	uint64_t u64;
+	struct cvmx_uctlx_ehci_fla_s {
+		uint64_t reserved_6_63:58;
+		uint64_t fla:6;
+	} s;
+	struct cvmx_uctlx_ehci_fla_s          cn63xx;
+	struct cvmx_uctlx_ehci_fla_s          cn63xxp1;
+};
+
+union cvmx_uctlx_erto_ctl {
+	uint64_t u64;
+	struct cvmx_uctlx_erto_ctl_s {
+		uint64_t reserved_32_63:32;
+		uint64_t to_val:27;
+		uint64_t reserved_0_4:5;
+	} s;
+	struct cvmx_uctlx_erto_ctl_s          cn63xx;
+	struct cvmx_uctlx_erto_ctl_s          cn63xxp1;
+};
+
+union cvmx_uctlx_if_ena {
+	uint64_t u64;
+	struct cvmx_uctlx_if_ena_s {
+		uint64_t reserved_1_63:63;
+		uint64_t en:1;
+	} s;
+	struct cvmx_uctlx_if_ena_s            cn63xx;
+	struct cvmx_uctlx_if_ena_s            cn63xxp1;
+};
+
+union cvmx_uctlx_int_ena {
+	uint64_t u64;
+	struct cvmx_uctlx_int_ena_s {
+		uint64_t reserved_8_63:56;
+		uint64_t ec_ovf_e:1;
+		uint64_t oc_ovf_e:1;
+		uint64_t wb_pop_e:1;
+		uint64_t wb_psh_f:1;
+		uint64_t cf_psh_f:1;
+		uint64_t or_psh_f:1;
+		uint64_t er_psh_f:1;
+		uint64_t pp_psh_f:1;
+	} s;
+	struct cvmx_uctlx_int_ena_s           cn63xx;
+	struct cvmx_uctlx_int_ena_s           cn63xxp1;
+};
+
+union cvmx_uctlx_int_reg {
+	uint64_t u64;
+	struct cvmx_uctlx_int_reg_s {
+		uint64_t reserved_8_63:56;
+		uint64_t ec_ovf_e:1;
+		uint64_t oc_ovf_e:1;
+		uint64_t wb_pop_e:1;
+		uint64_t wb_psh_f:1;
+		uint64_t cf_psh_f:1;
+		uint64_t or_psh_f:1;
+		uint64_t er_psh_f:1;
+		uint64_t pp_psh_f:1;
+	} s;
+	struct cvmx_uctlx_int_reg_s           cn63xx;
+	struct cvmx_uctlx_int_reg_s           cn63xxp1;
+};
+
+union cvmx_uctlx_ohci_ctl {
+	uint64_t u64;
+	struct cvmx_uctlx_ohci_ctl_s {
+		uint64_t reserved_19_63:45;
+		uint64_t reg_nb:1;
+		uint64_t l2c_dc:1;
+		uint64_t l2c_bc:1;
+		uint64_t l2c_0pag:1;
+		uint64_t l2c_stt:1;
+		uint64_t l2c_buff_emod:2;
+		uint64_t l2c_desc_emod:2;
+		uint64_t inv_reg_a2:1;
+		uint64_t reserved_8_8:1;
+		uint64_t l2c_addr_msb:8;
+	} s;
+	struct cvmx_uctlx_ohci_ctl_s          cn63xx;
+	struct cvmx_uctlx_ohci_ctl_s          cn63xxp1;
+};
+
+union cvmx_uctlx_orto_ctl {
+	uint64_t u64;
+	struct cvmx_uctlx_orto_ctl_s {
+		uint64_t reserved_32_63:32;
+		uint64_t to_val:24;
+		uint64_t reserved_0_7:8;
+	} s;
+	struct cvmx_uctlx_orto_ctl_s          cn63xx;
+	struct cvmx_uctlx_orto_ctl_s          cn63xxp1;
+};
+
+union cvmx_uctlx_ppaf_wm {
+	uint64_t u64;
+	struct cvmx_uctlx_ppaf_wm_s {
+		uint64_t reserved_5_63:59;
+		uint64_t wm:5;
+	} s;
+	struct cvmx_uctlx_ppaf_wm_s           cn63xx;
+	struct cvmx_uctlx_ppaf_wm_s           cn63xxp1;
+};
+
+union cvmx_uctlx_uphy_ctl_status {
+	uint64_t u64;
+	struct cvmx_uctlx_uphy_ctl_status_s {
+		uint64_t reserved_10_63:54;
+		uint64_t bist_done:1;
+		uint64_t bist_err:1;
+		uint64_t hsbist:1;
+		uint64_t fsbist:1;
+		uint64_t lsbist:1;
+		uint64_t siddq:1;
+		uint64_t vtest_en:1;
+		uint64_t uphy_bist:1;
+		uint64_t bist_en:1;
+		uint64_t ate_reset:1;
+	} s;
+	struct cvmx_uctlx_uphy_ctl_status_s   cn63xx;
+	struct cvmx_uctlx_uphy_ctl_status_s   cn63xxp1;
+};
+
+union cvmx_uctlx_uphy_portx_ctl_status {
+	uint64_t u64;
+	struct cvmx_uctlx_uphy_portx_ctl_status_s {
+		uint64_t reserved_43_63:21;
+		uint64_t tdata_out:4;
+		uint64_t txbiststuffenh:1;
+		uint64_t txbiststuffen:1;
+		uint64_t dmpulldown:1;
+		uint64_t dppulldown:1;
+		uint64_t vbusvldext:1;
+		uint64_t portreset:1;
+		uint64_t txhsvxtune:2;
+		uint64_t txvreftune:4;
+		uint64_t txrisetune:1;
+		uint64_t txpreemphasistune:1;
+		uint64_t txfslstune:4;
+		uint64_t sqrxtune:3;
+		uint64_t compdistune:3;
+		uint64_t loop_en:1;
+		uint64_t tclk:1;
+		uint64_t tdata_sel:1;
+		uint64_t taddr_in:4;
+		uint64_t tdata_in:8;
+	} s;
+	struct cvmx_uctlx_uphy_portx_ctl_status_s cn63xx;
+	struct cvmx_uctlx_uphy_portx_ctl_status_s cn63xxp1;
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/octeon.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/octeon.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/octeon.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/octeon.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 extern int octeon_is_pci_host(void);
 extern int octeon_usb_is_ref_clk(void);
 extern uint64_t octeon_get_clock_rate(void);
+extern u64 octeon_get_io_clock_rate(void);
 extern const char *octeon_board_type_string(void);
 extern const char *octeon_get_pci_interrupts(void);
 extern int octeon_get_southbridge_interrupt(void);
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/octeon-model.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/octeon-model.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/octeon-model.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/octeon-model.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,14 +35,6 @@
 #ifndef __OCTEON_MODEL_H__
 #define __OCTEON_MODEL_H__
 
-/* NOTE: These must match what is checked in common-config.mk */
-/* Defines to represent the different versions of Octeon.  */
-
-/*
- * IMPORTANT: When the default pass is updated for an Octeon Model,
- * the corresponding change must also be made in the oct-sim script.
- */
-
 /*
  * The defines below should be used with the OCTEON_IS_MODEL() macro
  * to determine what model of chip the software is running on.  Models
@@ -71,6 +63,21 @@
 #define OM_IGNORE_MINOR_REVISION  0x08000000
 #define OM_FLAG_MASK              0xff000000
 
+#define OM_MATCH_5XXX_FAMILY_MODELS     0x20000000 /* Match all cn5XXX Octeon models. */
+#define OM_MATCH_6XXX_FAMILY_MODELS     0x40000000 /* Match all cn6XXX Octeon models. */
+
+/*
+ * CN6XXX models with new revision encoding
+ */
+#define OCTEON_CN63XX_PASS1_0   0x000d9000
+#define OCTEON_CN63XX_PASS1_1   0x000d9001
+#define OCTEON_CN63XX_PASS1_2   0x000d9002
+#define OCTEON_CN63XX_PASS2_0   0x000d9008
+
+#define OCTEON_CN63XX           (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_REVISION)
+#define OCTEON_CN63XX_PASS1_X   (OCTEON_CN63XX_PASS1_0 | OM_IGNORE_MINOR_REVISION)
+#define OCTEON_CN63XX_PASS2_X   (OCTEON_CN63XX_PASS2_0 | OM_IGNORE_MINOR_REVISION)
+
 /*
  * CN5XXX models with new revision encoding
  */
@@ -189,6 +196,9 @@
 				 | OM_MATCH_PREVIOUS_MODELS \
 				 | OM_IGNORE_REVISION)
 
+#define OCTEON_CN5XXX           (OCTEON_CN58XX_PASS1_0 | OM_MATCH_5XXX_FAMILY_MODELS)
+#define OCTEON_CN6XXX           (OCTEON_CN63XX_PASS1_0 | OM_MATCH_6XXX_FAMILY_MODELS)
+
 /* The revision byte (low byte) has two different encodings.
  * CN3XXX:
  *
@@ -222,6 +232,7 @@
 				      | OCTEON_58XX_MODEL_MASK)
 #define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK \
 					  & 0x00fffff8)
+#define OCTEON_5XXX_MODEL_MASK       0x00ff0fc0
 
 #define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z)))
 
@@ -273,6 +284,15 @@
 		    __OCTEON_MATCH_MASK__((chip_model), (arg_model),
 					  OCTEON_58XX_MODEL_REV_MASK))
 			return 1;
+
+		if (((arg_model & OM_MATCH_5XXX_FAMILY_MODELS) == OM_MATCH_5XXX_FAMILY_MODELS) &&
+		    ((chip_model) >= OCTEON_CN58XX_PASS1_0) && ((chip_model) < OCTEON_CN63XX_PASS1_0))
+			return 1;
+
+		if (((arg_model & OM_MATCH_6XXX_FAMILY_MODELS) == OM_MATCH_6XXX_FAMILY_MODELS) &&
+		    ((chip_model) >= OCTEON_CN63XX_PASS1_0))
+			return 1;
+
 		if ((arg_model & OM_MATCH_PREVIOUS_MODELS) &&
 		    ((chip_model & OCTEON_58XX_MODEL_MASK) <
 			    (arg_model & OCTEON_58XX_MODEL_MASK)))
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/pci-octeon.h linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/pci-octeon.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/octeon/pci-octeon.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/octeon/pci-octeon.h	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,16 @@
 				     u8 slot, u8 pin);
 
 /*
+ * For PCI (not PCIe) the BAR2 base address.
+ */
+#define OCTEON_BAR2_PCI_ADDRESS 0x8000000000ull
+
+/*
+ * For PCI (not PCIe) the base of the memory mapped by BAR1
+ */
+extern u64 octeon_bar1_pci_phys;
+
+/*
  * The following defines are used when octeon_dma_bar_type =
  * OCTEON_DMA_BAR_TYPE_BIG
  */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/pci/bridge.h linux-libre-2.6.37-gnu/arch/mips/include/asm/pci/bridge.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/pci/bridge.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/pci/bridge.h	2011-01-04 19:50:19.000000000 -0500
@@ -839,7 +839,7 @@
 	nasid_t			nasid;
 	unsigned int		widget_id;
 	unsigned int 		irq_cpu;
-	dma64_addr_t		baddr;
+	u64			baddr;
 	unsigned int		pci_int[8];
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/mips/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/perf_event.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,25 @@
+/*
+ * linux/arch/mips/include/asm/perf_event.h
+ *
+ * Copyright (C) 2010 MIPS Technologies, Inc.
+ * Author: Deng-Cheng Zhu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MIPS_PERF_EVENT_H__
+#define __MIPS_PERF_EVENT_H__
+
+/*
+ * MIPS performance counters do not raise NMI upon overflow, a regular
+ * interrupt will be signaled. Hence we can do the pending perf event
+ * work at the tail of the irq handler.
+ */
+static inline void
+set_perf_event_pending(void)
+{
+}
+
+#endif /* __MIPS_PERF_EVENT_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/pgtable-32.h linux-libre-2.6.37-gnu/arch/mips/include/asm/pgtable-32.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/pgtable-32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/pgtable-32.h	2011-01-04 19:50:19.000000000 -0500
@@ -154,10 +154,7 @@
 
 #define pte_offset_map(dir, address)                                    \
 	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)                             \
-	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/pgtable-64.h linux-libre-2.6.37-gnu/arch/mips/include/asm/pgtable-64.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/pgtable-64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/pgtable-64.h	2011-01-04 19:50:19.000000000 -0500
@@ -113,10 +113,10 @@
 #endif
 #define PTRS_PER_PTE	((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
 
-#if PGDIR_SIZE >= TASK_SIZE
+#if PGDIR_SIZE >= TASK_SIZE64
 #define USER_PTRS_PER_PGD       (1)
 #else
-#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
+#define USER_PTRS_PER_PGD	(TASK_SIZE64 / PGDIR_SIZE)
 #endif
 #define FIRST_USER_ADDRESS	0UL
 
@@ -257,10 +257,7 @@
 	((pte_t *) pmd_page_vaddr(*(dir)) + __pte_offset(address))
 #define pte_offset_map(dir, address)					\
 	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)				\
-	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 /*
  * Initialize a new pgd / pmd table with invalid pointers.
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/processor.h linux-libre-2.6.37-gnu/arch/mips/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,13 +50,10 @@
  * so don't change it unless you know what you are doing.
  */
 #define TASK_SIZE	0x7fff8000UL
-#define STACK_TOP	((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE)
 
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE	((TASK_SIZE / 3) & ~(PAGE_SIZE))
+#ifdef __KERNEL__
+#define STACK_TOP_MAX	TASK_SIZE
+#endif
 
 #define TASK_IS_32BIT_ADDR 1
 
@@ -71,28 +68,29 @@
  * 8192EB ...
  */
 #define TASK_SIZE32	0x7fff8000UL
-#define TASK_SIZE	0x10000000000UL
-#define STACK_TOP	\
-	(((test_thread_flag(TIF_32BIT_ADDR) ?				\
-	   TASK_SIZE32 : TASK_SIZE) & PAGE_MASK) - SPECIAL_PAGES_SIZE)
+#define TASK_SIZE64	0x10000000000UL
+#define TASK_SIZE (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64)
+
+#ifdef __KERNEL__
+#define STACK_TOP_MAX	TASK_SIZE64
+#endif
+
 
-/*
- * This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE						\
-	(test_thread_flag(TIF_32BIT_ADDR) ?				\
-		PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3))
 #define TASK_SIZE_OF(tsk)						\
-	(test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
+	(test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE64)
 
 #define TASK_IS_32BIT_ADDR test_thread_flag(TIF_32BIT_ADDR)
 
 #endif
 
-#ifdef __KERNEL__
-#define STACK_TOP_MAX	TASK_SIZE
-#endif
+#define STACK_TOP	((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3)
+
 
 #define NUM_FPU_REGS	32
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/prom.h linux-libre-2.6.37-gnu/arch/mips/include/asm/prom.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/prom.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/prom.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,31 @@
+/*
+ *  arch/mips/include/asm/prom.h
+ *
+ *  Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef __ASM_MIPS_PROM_H
+#define __ASM_MIPS_PROM_H
+
+#ifdef CONFIG_OF
+#include <asm/bootinfo.h>
+
+/* which is compatible with the flattened device tree (FDT) */
+#define cmd_line arcs_cmdline
+
+extern int early_init_dt_scan_memory_arch(unsigned long node,
+	const char *uname, int depth, void *data);
+
+extern int reserve_mem_mach(unsigned long addr, unsigned long size);
+extern void free_mem_mach(unsigned long addr, unsigned long size);
+
+extern void device_tree_init(void);
+#else /* CONFIG_OF */
+static inline void device_tree_init(void) { }
+#endif /* CONFIG_OF */
+
+#endif /* _ASM_MIPS_PROM_H */
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/system.h linux-libre-2.6.37-gnu/arch/mips/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -115,21 +115,19 @@
 	} else if (kernel_uses_llsc) {
 		unsigned long dummy;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	ll	%0, %3			# xchg_u32	\n"
-		"	.set	mips0					\n"
-		"	move	%2, %z4					\n"
-		"	.set	mips3					\n"
-		"	sc	%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	ll	%0, %3		# xchg_u32	\n"
+			"	.set	mips0				\n"
+			"	move	%2, %z4				\n"
+			"	.set	mips3				\n"
+			"	sc	%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+			: "R" (*m), "Jr" (val)
+			: "memory");
+		} while (unlikely(!dummy));
 	} else {
 		unsigned long flags;
 
@@ -167,19 +165,17 @@
 	} else if (kernel_uses_llsc) {
 		unsigned long dummy;
 
-		__asm__ __volatile__(
-		"	.set	mips3					\n"
-		"1:	lld	%0, %3			# xchg_u64	\n"
-		"	move	%2, %z4					\n"
-		"	scd	%2, %1					\n"
-		"	beqz	%2, 2f					\n"
-		"	.subsection 2					\n"
-		"2:	b	1b					\n"
-		"	.previous					\n"
-		"	.set	mips0					\n"
-		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
-		: "R" (*m), "Jr" (val)
-		: "memory");
+		do {
+			__asm__ __volatile__(
+			"	.set	mips3				\n"
+			"	lld	%0, %3		# xchg_u64	\n"
+			"	move	%2, %z4				\n"
+			"	scd	%2, %1				\n"
+			"	.set	mips0				\n"
+			: "=&r" (retval), "=m" (*m), "=&r" (dummy)
+			: "R" (*m), "Jr" (val)
+			: "memory");
+		} while (unlikely(!dummy));
 	} else {
 		unsigned long flags;
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/thread_info.h linux-libre-2.6.37-gnu/arch/mips/include/asm/thread_info.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/thread_info.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/thread_info.h	2011-01-04 19:50:19.000000000 -0500
@@ -83,6 +83,8 @@
 #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
 #define THREAD_MASK (THREAD_SIZE - 1UL)
 
+#define STACK_WARN	(THREAD_SIZE / 8)
+
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
diff -druN linux-libre-2.6.36-gnu/arch/mips/include/asm/uaccess.h linux-libre-2.6.37-gnu/arch/mips/include/asm/uaccess.h
--- linux-libre-2.6.36-gnu/arch/mips/include/asm/uaccess.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/include/asm/uaccess.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,9 @@
 
 #ifdef CONFIG_64BIT
 
-#define __UA_LIMIT	(- TASK_SIZE)
+extern u64 __ua_limit;
+
+#define __UA_LIMIT	__ua_limit
 
 #define __UA_ADDR	".dword"
 #define __UA_LA		"dla"
diff -druN linux-libre-2.6.36-gnu/arch/mips/jazz/irq.c linux-libre-2.6.37-gnu/arch/mips/jazz/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/jazz/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/jazz/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/i8253.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/jz4740/board-qi_lb60.c linux-libre-2.6.37-gnu/arch/mips/jz4740/board-qi_lb60.c
--- linux-libre-2.6.36-gnu/arch/mips/jz4740/board-qi_lb60.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/jz4740/board-qi_lb60.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2009 Qi Hardware inc.,
  * Author: Xiangfu Liu <xiangfu@qi-hardware.com>
- * Copyright 2010, Lars-Petrer Clausen <lars@metafoo.de>
+ * Copyright 2010, Lars-Peter Clausen <lars@metafoo.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 or later
@@ -235,7 +235,7 @@
 	QI_LB60_GPIO_KEYIN(3),
 	QI_LB60_GPIO_KEYIN(4),
 	QI_LB60_GPIO_KEYIN(5),
-	QI_LB60_GPIO_KEYIN(7),
+	QI_LB60_GPIO_KEYIN(6),
 	QI_LB60_GPIO_KEYIN8,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/jz4740/platform.c linux-libre-2.6.37-gnu/arch/mips/jz4740/platform.c
--- linux-libre-2.6.36-gnu/arch/mips/jz4740/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/jz4740/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -208,7 +208,7 @@
 
 /* PCM */
 struct platform_device jz4740_pcm_device = {
-	.name		= "jz4740-pcm",
+	.name		= "jz4740-pcm-audio",
 	.id		= -1,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/jz4740/prom.c linux-libre-2.6.37-gnu/arch/mips/jz4740/prom.c
--- linux-libre-2.6.36-gnu/arch/mips/jz4740/prom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/jz4740/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,7 @@
 #include <asm/bootinfo.h>
 #include <asm/mach-jz4740/base.h>
 
-void jz4740_init_cmdline(int argc, char *argv[])
+static __init void jz4740_init_cmdline(int argc, char *argv[])
 {
 	unsigned int count = COMMAND_LINE_SIZE - 1;
 	int i;
diff -druN linux-libre-2.6.36-gnu/arch/mips/Kconfig linux-libre-2.6.37-gnu/arch/mips/Kconfig
--- linux-libre-2.6.36-gnu/arch/mips/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,18 +4,23 @@
 	select HAVE_GENERIC_DMA_COHERENT
 	select HAVE_IDE
 	select HAVE_OPROFILE
+	select HAVE_PERF_EVENTS
+	select PERF_USE_VMALLOC
 	select HAVE_ARCH_KGDB
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_C_RECORDMCOUNT
 	select HAVE_FUNCTION_GRAPH_TRACER
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
 	select RTC_LIB if !MACH_LOONGSON
 	select GENERIC_ATOMIC64 if !64BIT
-
-mainmenu "Linux/MIPS Kernel Configuration"
+	select HAVE_DMA_ATTRS
+	select HAVE_DMA_API_DEBUG
+	select HAVE_GENERIC_HARDIRQS
+	select GENERIC_IRQ_PROBE
 
 menu "Machine selection"
 
@@ -693,6 +698,9 @@
 	select SWAP_IO_SPACE
 	select HW_HAS_PCI
 	select ARCH_SUPPORTS_MSI
+	select ZONE_DMA32
+	select USB_ARCH_HAS_OHCI
+	select USB_ARCH_HAS_EHCI
 	help
 	  This option supports all of the Octeon reference boards from Cavium
 	  Networks. It builds a kernel that dynamically determines the Octeon
@@ -1336,6 +1344,57 @@
 	  can have up to 16 Mips64v2 cores and 8 integrated gigabit ethernets.
 	  Full details can be found at http://www.caviumnetworks.com.
 
+config CPU_BMIPS3300
+	bool "BMIPS3300"
+	depends on SYS_HAS_CPU_BMIPS3300
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select WEAK_ORDERING
+	help
+	  Broadcom BMIPS3300 processors.
+
+config CPU_BMIPS4350
+	bool "BMIPS4350"
+	depends on SYS_HAS_CPU_BMIPS4350
+	select CPU_SUPPORTS_32BIT_KERNEL
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_SMP
+	select SYS_SUPPORTS_HOTPLUG_CPU
+	select WEAK_ORDERING
+	help
+	  Broadcom BMIPS4350 ("VIPER") processors.
+
+config CPU_BMIPS4380
+	bool "BMIPS4380"
+	depends on SYS_HAS_CPU_BMIPS4380
+	select CPU_SUPPORTS_32BIT_KERNEL
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_SMP
+	select SYS_SUPPORTS_HOTPLUG_CPU
+	select WEAK_ORDERING
+	help
+	  Broadcom BMIPS4380 processors.
+
+config CPU_BMIPS5000
+	bool "BMIPS5000"
+	depends on SYS_HAS_CPU_BMIPS5000
+	select CPU_SUPPORTS_32BIT_KERNEL
+	select CPU_SUPPORTS_HIGHMEM
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SWAP_IO_SPACE
+	select SYS_SUPPORTS_SMP
+	select SYS_SUPPORTS_HOTPLUG_CPU
+	select WEAK_ORDERING
+	help
+	  Broadcom BMIPS5000 processors.
+
 endchoice
 
 if CPU_LOONGSON2F
@@ -1454,6 +1513,18 @@
 config SYS_HAS_CPU_CAVIUM_OCTEON
 	bool
 
+config SYS_HAS_CPU_BMIPS3300
+	bool
+
+config SYS_HAS_CPU_BMIPS4350
+	bool
+
+config SYS_HAS_CPU_BMIPS4380
+	bool
+
+config SYS_HAS_CPU_BMIPS5000
+	bool
+
 #
 # CPU may reorder R->R, R->W, W->R, W->W
 # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
@@ -1595,6 +1666,28 @@
 
 endchoice
 
+config FORCE_MAX_ZONEORDER
+	int "Maximum zone order"
+	range 13 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB
+	default "13" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_32KB
+	range 12 64 if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB
+	default "12" if SYS_SUPPORTS_HUGETLBFS && PAGE_SIZE_16KB
+	range 11 64
+	default "11"
+	help
+	  The kernel memory allocator divides physically contiguous memory
+	  blocks into "zones", where each zone is a power of two number of
+	  pages.  This option selects the largest power of two that the kernel
+	  keeps in the memory allocator.  If you need to allocate very large
+	  blocks of physically contiguous memory, then you may need to
+	  increase this value.
+
+	  This config option is actually maximum order plus one. For example,
+	  a value of 11 means that the largest free memory block is 2^10 pages.
+
+	  The page size is not necessarily 4KB.  Keep this in mind
+	  when choosing a value for this option.
+
 config BOARD_SCACHE
 	bool
 
@@ -1853,20 +1946,6 @@
 	bool
 
 #
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
-	bool
-	default y
-
-config GENERIC_IRQ_PROBE
-	bool
-	default y
-
-config IRQ_PER_CPU
-	bool
-
-#
 # - Highmem only makes sense for the 32-bit kernel.
 # - The current highmem code will only work properly on physically indexed
 #   caches such as R3000, SB1, R7000 or those that look like they're virtually
@@ -1930,6 +2009,14 @@
 	default "6"
 	depends on NEED_MULTIPLE_NODES
 
+config HW_PERF_EVENTS
+	bool "Enable hardware performance counter support for perf events"
+	depends on PERF_EVENTS && !MIPS_MT_SMTC && OPROFILE=n && CPU_MIPS32
+	default y
+	help
+	  Enable hardware performance counter support for perf events. If
+	  disabled, perf events will use software events only.
+
 source "mm/Kconfig"
 
 config SMP
@@ -2128,6 +2215,13 @@
 
 	  If unsure, say Y. Only embedded should say N here.
 
+config USE_OF
+	bool "Flattened Device Tree support"
+	select OF
+	select OF_FLATTREE
+	help
+	  Include support for flattened device tree machine descriptions.
+
 endmenu
 
 config LOCKDEP_SUPPORT
@@ -2196,10 +2290,14 @@
 	bool "TURBOchannel support"
 	depends on MACH_DECSTATION
 	help
-	  TurboChannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS
-	  processors.  Documentation on writing device drivers for TurboChannel
-	  is available at:
-	  <http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/AA-PS3HD-TET1_html/TITLE.html>.
+	  TURBOchannel is a DEC (now Compaq (now HP)) bus for Alpha and MIPS
+	  processors.  TURBOchannel programming specifications are available
+	  at:
+	  <ftp://ftp.hp.com/pub/alphaserver/archive/triadd/>
+	  and:
+	  <http://www.computer-refuge.org/classiccmp/ftp.digital.com/pub/DEC/TriAdd/>
+	  Linux driver support status is documented at:
+	  <http://www.linux-mips.org/wiki/DECstation>
 
 #config ACCESSBUS
 #	bool "Access.Bus support"
diff -druN linux-libre-2.6.36-gnu/arch/mips/Kconfig.debug linux-libre-2.6.37-gnu/arch/mips/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/mips/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -67,6 +67,15 @@
 
 	  Normally, you will choose 'N' here.
 
+config DEBUG_STACKOVERFLOW
+	bool "Check for stack overflows"
+	depends on DEBUG_KERNEL
+	help
+	  This option will cause messages to be printed if free stack space
+	  drops below a certain limit(2GB on MIPS). The debugging option
+	  provides another way to check stack overflow happened on kernel mode
+	  stack usually caused by nested interruption.
+
 config DEBUG_STACK_USAGE
 	bool "Enable stack utilization instrumentation"
 	depends on DEBUG_KERNEL
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-bcm1480.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-bcm1480.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-bcm1480.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-bcm1480.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/addrspace.h>
 #include <asm/io.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-ds1287.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-ds1287.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-ds1287.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-ds1287.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
+#include <linux/irq.h>
 
 #include <asm/time.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-gt641xx.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-gt641xx.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-gt641xx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-gt641xx.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/gt64120.h>
 #include <asm/time.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-r4k.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-r4k.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-r4k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-r4k.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
@@ -31,7 +32,7 @@
 	cnt = read_c0_count();
 	cnt += delta;
 	write_c0_compare(cnt);
-	res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0;
+	res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0;
 	return res;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-sb1250.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-sb1250.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-sb1250.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-sb1250.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
  */
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-smtc.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-smtc.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-smtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-smtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-txx9.c linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-txx9.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cevt-txx9.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cevt-txx9.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/time.h>
 #include <asm/txx9tmr.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/cpu-probe.c linux-libre-2.6.37-gnu/arch/mips/kernel/cpu-probe.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/cpu-probe.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/cpu-probe.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,8 @@
 #include <asm/system.h>
 #include <asm/watch.h>
 #include <asm/spram.h>
+#include <asm/uaccess.h>
+
 /*
  * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
  * the implementation of the "wait" feature differs between CPU families. This
@@ -181,12 +183,13 @@
 	case CPU_5KC:
 	case CPU_25KF:
 	case CPU_PR4450:
-	case CPU_BCM3302:
-	case CPU_BCM6338:
-	case CPU_BCM6348:
-	case CPU_BCM6358:
+	case CPU_BMIPS3300:
+	case CPU_BMIPS4350:
+	case CPU_BMIPS4380:
+	case CPU_BMIPS5000:
 	case CPU_CAVIUM_OCTEON:
 	case CPU_CAVIUM_OCTEON_PLUS:
+	case CPU_CAVIUM_OCTEON2:
 	case CPU_JZRISC:
 		cpu_wait = r4k_wait;
 		break;
@@ -902,35 +905,36 @@
 {
 	decode_configs(c);
 	switch (c->processor_id & 0xff00) {
-	case PRID_IMP_BCM3302:
-	 /* same as PRID_IMP_BCM6338 */
-		c->cputype = CPU_BCM3302;
-		__cpu_name[cpu] = "Broadcom BCM3302";
-		break;
-	case PRID_IMP_BCM4710:
-		c->cputype = CPU_BCM4710;
-		__cpu_name[cpu] = "Broadcom BCM4710";
-		break;
-	case PRID_IMP_BCM6345:
-		c->cputype = CPU_BCM6345;
-		__cpu_name[cpu] = "Broadcom BCM6345";
+	case PRID_IMP_BMIPS32_REV4:
+	case PRID_IMP_BMIPS32_REV8:
+		c->cputype = CPU_BMIPS32;
+		__cpu_name[cpu] = "Broadcom BMIPS32";
 		break;
-	case PRID_IMP_BCM6348:
-		c->cputype = CPU_BCM6348;
-		__cpu_name[cpu] = "Broadcom BCM6348";
+	case PRID_IMP_BMIPS3300:
+	case PRID_IMP_BMIPS3300_ALT:
+	case PRID_IMP_BMIPS3300_BUG:
+		c->cputype = CPU_BMIPS3300;
+		__cpu_name[cpu] = "Broadcom BMIPS3300";
 		break;
-	case PRID_IMP_BCM4350:
-		switch (c->processor_id & 0xf0) {
-		case PRID_REV_BCM6358:
-			c->cputype = CPU_BCM6358;
-			__cpu_name[cpu] = "Broadcom BCM6358";
-			break;
-		default:
-			c->cputype = CPU_UNKNOWN;
-			break;
+	case PRID_IMP_BMIPS43XX: {
+		int rev = c->processor_id & 0xff;
+
+		if (rev >= PRID_REV_BMIPS4380_LO &&
+				rev <= PRID_REV_BMIPS4380_HI) {
+			c->cputype = CPU_BMIPS4380;
+			__cpu_name[cpu] = "Broadcom BMIPS4380";
+		} else {
+			c->cputype = CPU_BMIPS4350;
+			__cpu_name[cpu] = "Broadcom BMIPS4350";
 		}
 		break;
 	}
+	case PRID_IMP_BMIPS5000:
+		c->cputype = CPU_BMIPS5000;
+		__cpu_name[cpu] = "Broadcom BMIPS5000";
+		c->options |= MIPS_CPU_ULRI;
+		break;
+	}
 }
 
 static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
@@ -953,6 +957,12 @@
 		if (cpu == 0)
 			__elf_platform = "octeon";
 		break;
+	case PRID_IMP_CAVIUM_CN63XX:
+		c->cputype = CPU_CAVIUM_OCTEON2;
+		__cpu_name[cpu] = "Cavium Octeon II";
+		if (cpu == 0)
+			__elf_platform = "octeon2";
+		break;
 	default:
 		printk(KERN_INFO "Unknown Octeon chip!\n");
 		c->cputype = CPU_UNKNOWN;
@@ -976,6 +986,12 @@
 	}
 }
 
+#ifdef CONFIG_64BIT
+/* For use by uaccess.h */
+u64 __ua_limit;
+EXPORT_SYMBOL(__ua_limit);
+#endif
+
 const char *__cpu_name[NR_CPUS];
 const char *__elf_platform;
 
@@ -1053,6 +1069,11 @@
 		c->srsets = 1;
 
 	cpu_probe_vmbits(c);
+
+#ifdef CONFIG_64BIT
+	if (cpu == 0)
+		__ua_limit = ~((1ull << cpu_vmbits) - 1);
+#endif
 }
 
 __cpuinit void cpu_report(void)
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/i8253.c linux-libre-2.6.37-gnu/arch/mips/kernel/i8253.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/i8253.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/i8253.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/delay.h>
 #include <asm/i8253.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/i8259.c linux-libre-2.6.37-gnu/arch/mips/kernel/i8259.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/i8259.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/i8259.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/sysdev.h>
+#include <linux/irq.h>
 
 #include <asm/i8259.h>
 #include <asm/io.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -151,6 +151,29 @@
 #endif
 }
 
+#ifdef DEBUG_STACKOVERFLOW
+static inline void check_stack_overflow(void)
+{
+	unsigned long sp;
+
+	__asm__ __volatile__("move %0, $sp" : "=r" (sp));
+	sp &= THREAD_MASK;
+
+	/*
+	 * Check for stack overflow: is there less than STACK_WARN free?
+	 * STACK_WARN is defined as 1/8 of THREAD_SIZE by default.
+	 */
+	if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
+		printk("do_IRQ: stack overflow: %ld\n",
+		       sp - sizeof(struct thread_info));
+		dump_stack();
+	}
+}
+#else
+static inline void check_stack_overflow(void) {}
+#endif
+
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
@@ -159,6 +182,7 @@
 void __irq_entry do_IRQ(unsigned int irq)
 {
 	irq_enter();
+	check_stack_overflow();
 	__DO_IRQ_SMTC_HOOK(irq);
 	generic_handle_irq(irq);
 	irq_exit();
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq_cpu.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq_cpu.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq_cpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq_cpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq-gic.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq-gic.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq-gic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq-gic.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,11 +3,11 @@
 #include <linux/bitmap.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/gic.h>
 #include <asm/gcmpregs.h>
-#include <asm/irq.h>
 #include <linux/hardirq.h>
 #include <asm-generic/bitops/find.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq-rm7000.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq-rm7000.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq-rm7000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq-rm7000.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 
 #include <asm/irq_cpu.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq-rm9000.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq-rm9000.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq-rm9000.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq-rm9000.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/irq_txx9.c linux-libre-2.6.37-gnu/arch/mips/kernel/irq_txx9.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/irq_txx9.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/irq_txx9.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/types.h>
+#include <linux/irq.h>
 #include <asm/txx9irq.h>
 
 struct txx9_irc_reg {
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/linux32.c linux-libre-2.6.37-gnu/arch/mips/kernel/linux32.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/linux32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/linux32.c	2011-01-04 19:50:19.000000000 -0500
@@ -251,14 +251,15 @@
 
 SYSCALL_DEFINE1(32_personality, unsigned long, personality)
 {
+	unsigned int p = personality & 0xffffffff;
 	int ret;
-	personality &= 0xffffffff;
+
 	if (personality(current->personality) == PER_LINUX32 &&
-	    personality == PER_LINUX)
-		personality = PER_LINUX32;
-	ret = sys_personality(personality);
-	if (ret == PER_LINUX32)
-		ret = PER_LINUX;
+	    personality(p) == PER_LINUX)
+		p = (p & ~PER_MASK) | PER_LINUX32;
+	ret = sys_personality(p);
+	if (ret != -1 && personality(ret) == PER_LINUX32)
+		ret = (ret & ~PER_MASK) | PER_LINUX;
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/Makefile linux-libre-2.6.37-gnu/arch/mips/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/mips/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -96,10 +96,14 @@
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_SPINLOCK_TEST)	+= spinlock_test.o
 
+obj-$(CONFIG_OF)		+= prom.o
+
 CFLAGS_cpu-bugs64.o	= $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
 
 obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT)	+= 8250-platform.o
 
 obj-$(CONFIG_MIPS_CPUFREQ)	+= cpufreq/
 
+obj-$(CONFIG_HW_PERF_EVENTS)	+= perf_event.o
+
 CPPFLAGS_vmlinux.lds		:= $(KBUILD_CFLAGS)
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/mips-mt-fpaff.c linux-libre-2.6.37-gnu/arch/mips/kernel/mips-mt-fpaff.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/mips-mt-fpaff.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/mips-mt-fpaff.c	2011-01-04 19:50:19.000000000 -0500
@@ -103,7 +103,7 @@
 	if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
 		goto out_unlock;
 
-	retval = security_task_setscheduler(p, 0, NULL);
+	retval = security_task_setscheduler(p);
 	if (retval)
 		goto out_unlock;
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/mips/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/perf_event.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,601 @@
+/*
+ * Linux performance counter support for MIPS.
+ *
+ * Copyright (C) 2010 MIPS Technologies, Inc.
+ * Author: Deng-Cheng Zhu
+ *
+ * This code is based on the implementation for ARM, which is in turn
+ * based on the sparc64 perf event code and the x86 code. Performance
+ * counter access is based on the MIPS Oprofile code. And the callchain
+ * support references the code of MIPS stacktrace.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/uaccess.h>
+
+#include <asm/irq.h>
+#include <asm/irq_regs.h>
+#include <asm/stacktrace.h>
+#include <asm/time.h> /* For perf_irq */
+
+/* These are for 32bit counters. For 64bit ones, define them accordingly. */
+#define MAX_PERIOD	((1ULL << 32) - 1)
+#define VALID_COUNT	0x7fffffff
+#define TOTAL_BITS	32
+#define HIGHEST_BIT	31
+
+#define MIPS_MAX_HWEVENTS 4
+
+struct cpu_hw_events {
+	/* Array of events on this cpu. */
+	struct perf_event	*events[MIPS_MAX_HWEVENTS];
+
+	/*
+	 * Set the bit (indexed by the counter number) when the counter
+	 * is used for an event.
+	 */
+	unsigned long		used_mask[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)];
+
+	/*
+	 * The borrowed MSB for the performance counter. A MIPS performance
+	 * counter uses its bit 31 (for 32bit counters) or bit 63 (for 64bit
+	 * counters) as a factor of determining whether a counter overflow
+	 * should be signaled. So here we use a separate MSB for each
+	 * counter to make things easy.
+	 */
+	unsigned long		msbs[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)];
+
+	/*
+	 * Software copy of the control register for each performance counter.
+	 * MIPS CPUs vary in performance counters. They use this differently,
+	 * and even may not use it.
+	 */
+	unsigned int		saved_ctrl[MIPS_MAX_HWEVENTS];
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = {
+	.saved_ctrl = {0},
+};
+
+/* The description of MIPS performance events. */
+struct mips_perf_event {
+	unsigned int event_id;
+	/*
+	 * MIPS performance counters are indexed starting from 0.
+	 * CNTR_EVEN indicates the indexes of the counters to be used are
+	 * even numbers.
+	 */
+	unsigned int cntr_mask;
+	#define CNTR_EVEN	0x55555555
+	#define CNTR_ODD	0xaaaaaaaa
+#ifdef CONFIG_MIPS_MT_SMP
+	enum {
+		T  = 0,
+		V  = 1,
+		P  = 2,
+	} range;
+#else
+	#define T
+	#define V
+	#define P
+#endif
+};
+
+static struct mips_perf_event raw_event;
+static DEFINE_MUTEX(raw_event_mutex);
+
+#define UNSUPPORTED_PERF_EVENT_ID 0xffffffff
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+struct mips_pmu {
+	const char	*name;
+	int		irq;
+	irqreturn_t	(*handle_irq)(int irq, void *dev);
+	int		(*handle_shared_irq)(void);
+	void		(*start)(void);
+	void		(*stop)(void);
+	int		(*alloc_counter)(struct cpu_hw_events *cpuc,
+					struct hw_perf_event *hwc);
+	u64		(*read_counter)(unsigned int idx);
+	void		(*write_counter)(unsigned int idx, u64 val);
+	void		(*enable_event)(struct hw_perf_event *evt, int idx);
+	void		(*disable_event)(int idx);
+	const struct mips_perf_event *(*map_raw_event)(u64 config);
+	const struct mips_perf_event (*general_event_map)[PERF_COUNT_HW_MAX];
+	const struct mips_perf_event (*cache_event_map)
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX];
+	unsigned int	num_counters;
+};
+
+static const struct mips_pmu *mipspmu;
+
+static int
+mipspmu_event_set_period(struct perf_event *event,
+			struct hw_perf_event *hwc,
+			int idx)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	s64 left = local64_read(&hwc->period_left);
+	s64 period = hwc->sample_period;
+	int ret = 0;
+	u64 uleft;
+	unsigned long flags;
+
+	if (unlikely(left <= -period)) {
+		left = period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (unlikely(left <= 0)) {
+		left += period;
+		local64_set(&hwc->period_left, left);
+		hwc->last_period = period;
+		ret = 1;
+	}
+
+	if (left > (s64)MAX_PERIOD)
+		left = MAX_PERIOD;
+
+	local64_set(&hwc->prev_count, (u64)-left);
+
+	local_irq_save(flags);
+	uleft = (u64)(-left) & MAX_PERIOD;
+	uleft > VALID_COUNT ?
+		set_bit(idx, cpuc->msbs) : clear_bit(idx, cpuc->msbs);
+	mipspmu->write_counter(idx, (u64)(-left) & VALID_COUNT);
+	local_irq_restore(flags);
+
+	perf_event_update_userpage(event);
+
+	return ret;
+}
+
+static int mipspmu_enable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	int idx;
+	int err = 0;
+
+	/* To look for a free counter for this event. */
+	idx = mipspmu->alloc_counter(cpuc, hwc);
+	if (idx < 0) {
+		err = idx;
+		goto out;
+	}
+
+	/*
+	 * If there is an event in the counter we are going to use then
+	 * make sure it is disabled.
+	 */
+	event->hw.idx = idx;
+	mipspmu->disable_event(idx);
+	cpuc->events[idx] = event;
+
+	/* Set the period for the event. */
+	mipspmu_event_set_period(event, hwc, idx);
+
+	/* Enable the event. */
+	mipspmu->enable_event(hwc, idx);
+
+	/* Propagate our changes to the userspace mapping. */
+	perf_event_update_userpage(event);
+
+out:
+	return err;
+}
+
+static void mipspmu_event_update(struct perf_event *event,
+			struct hw_perf_event *hwc,
+			int idx)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	unsigned long flags;
+	int shift = 64 - TOTAL_BITS;
+	s64 prev_raw_count, new_raw_count;
+	s64 delta;
+
+again:
+	prev_raw_count = local64_read(&hwc->prev_count);
+	local_irq_save(flags);
+	/* Make the counter value be a "real" one. */
+	new_raw_count = mipspmu->read_counter(idx);
+	if (new_raw_count & (test_bit(idx, cpuc->msbs) << HIGHEST_BIT)) {
+		new_raw_count &= VALID_COUNT;
+		clear_bit(idx, cpuc->msbs);
+	} else
+		new_raw_count |= (test_bit(idx, cpuc->msbs) << HIGHEST_BIT);
+	local_irq_restore(flags);
+
+	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+				new_raw_count) != prev_raw_count)
+		goto again;
+
+	delta = (new_raw_count << shift) - (prev_raw_count << shift);
+	delta >>= shift;
+
+	local64_add(delta, &event->count);
+	local64_sub(delta, &hwc->period_left);
+
+	return;
+}
+
+static void mipspmu_disable(struct perf_event *event)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
+
+
+	WARN_ON(idx < 0 || idx >= mipspmu->num_counters);
+
+	/* We are working on a local event. */
+	mipspmu->disable_event(idx);
+
+	barrier();
+
+	mipspmu_event_update(event, hwc, idx);
+	cpuc->events[idx] = NULL;
+	clear_bit(idx, cpuc->used_mask);
+
+	perf_event_update_userpage(event);
+}
+
+static void mipspmu_unthrottle(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	mipspmu->enable_event(hwc, hwc->idx);
+}
+
+static void mipspmu_read(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	/* Don't read disabled counters! */
+	if (hwc->idx < 0)
+		return;
+
+	mipspmu_event_update(event, hwc, hwc->idx);
+}
+
+static struct pmu pmu = {
+	.enable		= mipspmu_enable,
+	.disable	= mipspmu_disable,
+	.unthrottle	= mipspmu_unthrottle,
+	.read		= mipspmu_read,
+};
+
+static atomic_t active_events = ATOMIC_INIT(0);
+static DEFINE_MUTEX(pmu_reserve_mutex);
+static int (*save_perf_irq)(void);
+
+static int mipspmu_get_irq(void)
+{
+	int err;
+
+	if (mipspmu->irq >= 0) {
+		/* Request my own irq handler. */
+		err = request_irq(mipspmu->irq, mipspmu->handle_irq,
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			"mips_perf_pmu", NULL);
+		if (err) {
+			pr_warning("Unable to request IRQ%d for MIPS "
+			   "performance counters!\n", mipspmu->irq);
+		}
+	} else if (cp0_perfcount_irq < 0) {
+		/*
+		 * We are sharing the irq number with the timer interrupt.
+		 */
+		save_perf_irq = perf_irq;
+		perf_irq = mipspmu->handle_shared_irq;
+		err = 0;
+	} else {
+		pr_warning("The platform hasn't properly defined its "
+			"interrupt controller.\n");
+		err = -ENOENT;
+	}
+
+	return err;
+}
+
+static void mipspmu_free_irq(void)
+{
+	if (mipspmu->irq >= 0)
+		free_irq(mipspmu->irq, NULL);
+	else if (cp0_perfcount_irq < 0)
+		perf_irq = save_perf_irq;
+}
+
+static inline unsigned int
+mipspmu_perf_event_encode(const struct mips_perf_event *pev)
+{
+/*
+ * Top 8 bits for range, next 16 bits for cntr_mask, lowest 8 bits for
+ * event_id.
+ */
+#ifdef CONFIG_MIPS_MT_SMP
+	return ((unsigned int)pev->range << 24) |
+		(pev->cntr_mask & 0xffff00) |
+		(pev->event_id & 0xff);
+#else
+	return (pev->cntr_mask & 0xffff00) |
+		(pev->event_id & 0xff);
+#endif
+}
+
+static const struct mips_perf_event *
+mipspmu_map_general_event(int idx)
+{
+	const struct mips_perf_event *pev;
+
+	pev = ((*mipspmu->general_event_map)[idx].event_id ==
+		UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) :
+		&(*mipspmu->general_event_map)[idx]);
+
+	return pev;
+}
+
+static const struct mips_perf_event *
+mipspmu_map_cache_event(u64 config)
+{
+	unsigned int cache_type, cache_op, cache_result;
+	const struct mips_perf_event *pev;
+
+	cache_type = (config >> 0) & 0xff;
+	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+		return ERR_PTR(-EINVAL);
+
+	cache_op = (config >> 8) & 0xff;
+	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+		return ERR_PTR(-EINVAL);
+
+	cache_result = (config >> 16) & 0xff;
+	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	pev = &((*mipspmu->cache_event_map)
+					[cache_type]
+					[cache_op]
+					[cache_result]);
+
+	if (pev->event_id == UNSUPPORTED_PERF_EVENT_ID)
+		return ERR_PTR(-EOPNOTSUPP);
+
+	return pev;
+
+}
+
+static int validate_event(struct cpu_hw_events *cpuc,
+	       struct perf_event *event)
+{
+	struct hw_perf_event fake_hwc = event->hw;
+
+	if (event->pmu && event->pmu != &pmu)
+		return 0;
+
+	return mipspmu->alloc_counter(cpuc, &fake_hwc) >= 0;
+}
+
+static int validate_group(struct perf_event *event)
+{
+	struct perf_event *sibling, *leader = event->group_leader;
+	struct cpu_hw_events fake_cpuc;
+
+	memset(&fake_cpuc, 0, sizeof(fake_cpuc));
+
+	if (!validate_event(&fake_cpuc, leader))
+		return -ENOSPC;
+
+	list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+		if (!validate_event(&fake_cpuc, sibling))
+			return -ENOSPC;
+	}
+
+	if (!validate_event(&fake_cpuc, event))
+		return -ENOSPC;
+
+	return 0;
+}
+
+/*
+ * mipsxx/rm9000/loongson2 have different performance counters, they have
+ * specific low-level init routines.
+ */
+static void reset_counters(void *arg);
+static int __hw_perf_event_init(struct perf_event *event);
+
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+	if (atomic_dec_and_mutex_lock(&active_events,
+				&pmu_reserve_mutex)) {
+		/*
+		 * We must not call the destroy function with interrupts
+		 * disabled.
+		 */
+		on_each_cpu(reset_counters,
+			(void *)(long)mipspmu->num_counters, 1);
+		mipspmu_free_irq();
+		mutex_unlock(&pmu_reserve_mutex);
+	}
+}
+
+const struct pmu *hw_perf_event_init(struct perf_event *event)
+{
+	int err = 0;
+
+	if (!mipspmu || event->cpu >= nr_cpumask_bits ||
+		(event->cpu >= 0 && !cpu_online(event->cpu)))
+		return ERR_PTR(-ENODEV);
+
+	if (!atomic_inc_not_zero(&active_events)) {
+		if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) {
+			atomic_dec(&active_events);
+			return ERR_PTR(-ENOSPC);
+		}
+
+		mutex_lock(&pmu_reserve_mutex);
+		if (atomic_read(&active_events) == 0)
+			err = mipspmu_get_irq();
+
+		if (!err)
+			atomic_inc(&active_events);
+		mutex_unlock(&pmu_reserve_mutex);
+	}
+
+	if (err)
+		return ERR_PTR(err);
+
+	err = __hw_perf_event_init(event);
+	if (err)
+		hw_perf_event_destroy(event);
+
+	return err ? ERR_PTR(err) : &pmu;
+}
+
+void hw_perf_enable(void)
+{
+	if (mipspmu)
+		mipspmu->start();
+}
+
+void hw_perf_disable(void)
+{
+	if (mipspmu)
+		mipspmu->stop();
+}
+
+/* This is needed by specific irq handlers in perf_event_*.c */
+static void
+handle_associated_event(struct cpu_hw_events *cpuc,
+	int idx, struct perf_sample_data *data, struct pt_regs *regs)
+{
+	struct perf_event *event = cpuc->events[idx];
+	struct hw_perf_event *hwc = &event->hw;
+
+	mipspmu_event_update(event, hwc, idx);
+	data->period = event->hw.last_period;
+	if (!mipspmu_event_set_period(event, hwc, idx))
+		return;
+
+	if (perf_event_overflow(event, 0, data, regs))
+		mipspmu->disable_event(idx);
+}
+
+#include "perf_event_mipsxx.c"
+
+/* Callchain handling code. */
+static inline void
+callchain_store(struct perf_callchain_entry *entry,
+		u64 ip)
+{
+	if (entry->nr < PERF_MAX_STACK_DEPTH)
+		entry->ip[entry->nr++] = ip;
+}
+
+/*
+ * Leave userspace callchain empty for now. When we find a way to trace
+ * the user stack callchains, we add here.
+ */
+static void
+perf_callchain_user(struct pt_regs *regs,
+		    struct perf_callchain_entry *entry)
+{
+}
+
+static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
+	unsigned long reg29)
+{
+	unsigned long *sp = (unsigned long *)reg29;
+	unsigned long addr;
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		if (__kernel_text_address(addr)) {
+			callchain_store(entry, addr);
+			if (entry->nr >= PERF_MAX_STACK_DEPTH)
+				break;
+		}
+	}
+}
+
+static void
+perf_callchain_kernel(struct pt_regs *regs,
+		      struct perf_callchain_entry *entry)
+{
+	unsigned long sp = regs->regs[29];
+#ifdef CONFIG_KALLSYMS
+	unsigned long ra = regs->regs[31];
+	unsigned long pc = regs->cp0_epc;
+
+	callchain_store(entry, PERF_CONTEXT_KERNEL);
+	if (raw_show_trace || !__kernel_text_address(pc)) {
+		unsigned long stack_page =
+			(unsigned long)task_stack_page(current);
+		if (stack_page && sp >= stack_page &&
+		    sp <= stack_page + THREAD_SIZE - 32)
+			save_raw_perf_callchain(entry, sp);
+		return;
+	}
+	do {
+		callchain_store(entry, pc);
+		if (entry->nr >= PERF_MAX_STACK_DEPTH)
+			break;
+		pc = unwind_stack(current, &sp, pc, &ra);
+	} while (pc);
+#else
+	callchain_store(entry, PERF_CONTEXT_KERNEL);
+	save_raw_perf_callchain(entry, sp);
+#endif
+}
+
+static void
+perf_do_callchain(struct pt_regs *regs,
+		  struct perf_callchain_entry *entry)
+{
+	int is_user;
+
+	if (!regs)
+		return;
+
+	is_user = user_mode(regs);
+
+	if (!current || !current->pid)
+		return;
+
+	if (is_user && current->state != TASK_RUNNING)
+		return;
+
+	if (!is_user) {
+		perf_callchain_kernel(regs, entry);
+		if (current->mm)
+			regs = task_pt_regs(current);
+		else
+			regs = NULL;
+	}
+	if (regs)
+		perf_callchain_user(regs, entry);
+}
+
+static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
+
+struct perf_callchain_entry *
+perf_callchain(struct pt_regs *regs)
+{
+	struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
+
+	entry->nr = 0;
+	perf_do_callchain(regs, entry);
+	return entry;
+}
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/perf_event_mipsxx.c linux-libre-2.6.37-gnu/arch/mips/kernel/perf_event_mipsxx.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/perf_event_mipsxx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/perf_event_mipsxx.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1052 @@
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) || \
+    defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_SB1)
+
+#define M_CONFIG1_PC	(1 << 4)
+
+#define M_PERFCTL_EXL			(1UL      <<  0)
+#define M_PERFCTL_KERNEL		(1UL      <<  1)
+#define M_PERFCTL_SUPERVISOR		(1UL      <<  2)
+#define M_PERFCTL_USER			(1UL      <<  3)
+#define M_PERFCTL_INTERRUPT_ENABLE	(1UL      <<  4)
+#define M_PERFCTL_EVENT(event)		(((event) & 0x3ff)  << 5)
+#define M_PERFCTL_VPEID(vpe)		((vpe)    << 16)
+#define M_PERFCTL_MT_EN(filter)		((filter) << 20)
+#define    M_TC_EN_ALL			M_PERFCTL_MT_EN(0)
+#define    M_TC_EN_VPE			M_PERFCTL_MT_EN(1)
+#define    M_TC_EN_TC			M_PERFCTL_MT_EN(2)
+#define M_PERFCTL_TCID(tcid)		((tcid)   << 22)
+#define M_PERFCTL_WIDE			(1UL      << 30)
+#define M_PERFCTL_MORE			(1UL      << 31)
+
+#define M_PERFCTL_COUNT_EVENT_WHENEVER	(M_PERFCTL_EXL |		\
+					M_PERFCTL_KERNEL |		\
+					M_PERFCTL_USER |		\
+					M_PERFCTL_SUPERVISOR |		\
+					M_PERFCTL_INTERRUPT_ENABLE)
+
+#ifdef CONFIG_MIPS_MT_SMP
+#define M_PERFCTL_CONFIG_MASK		0x3fff801f
+#else
+#define M_PERFCTL_CONFIG_MASK		0x1f
+#endif
+#define M_PERFCTL_EVENT_MASK		0xfe0
+
+#define M_COUNTER_OVERFLOW		(1UL      << 31)
+
+#ifdef CONFIG_MIPS_MT_SMP
+static int cpu_has_mipsmt_pertccounters;
+
+/*
+ * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because
+ * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs.
+ */
+#if defined(CONFIG_HW_PERF_EVENTS)
+#define vpe_id()	(cpu_has_mipsmt_pertccounters ? \
+			0 : smp_processor_id())
+#else
+#define vpe_id()	(cpu_has_mipsmt_pertccounters ? \
+			0 : cpu_data[smp_processor_id()].vpe_id)
+#endif
+
+/* Copied from op_model_mipsxx.c */
+static inline unsigned int vpe_shift(void)
+{
+	if (num_possible_cpus() > 1)
+		return 1;
+
+	return 0;
+}
+#else /* !CONFIG_MIPS_MT_SMP */
+#define vpe_id()	0
+
+static inline unsigned int vpe_shift(void)
+{
+	return 0;
+}
+#endif /* CONFIG_MIPS_MT_SMP */
+
+static inline unsigned int
+counters_total_to_per_cpu(unsigned int counters)
+{
+	return counters >> vpe_shift();
+}
+
+static inline unsigned int
+counters_per_cpu_to_total(unsigned int counters)
+{
+	return counters << vpe_shift();
+}
+
+#define __define_perf_accessors(r, n, np)				\
+									\
+static inline unsigned int r_c0_ ## r ## n(void)			\
+{									\
+	unsigned int cpu = vpe_id();					\
+									\
+	switch (cpu) {							\
+	case 0:								\
+		return read_c0_ ## r ## n();				\
+	case 1:								\
+		return read_c0_ ## r ## np();				\
+	default:							\
+		BUG();							\
+	}								\
+	return 0;							\
+}									\
+									\
+static inline void w_c0_ ## r ## n(unsigned int value)			\
+{									\
+	unsigned int cpu = vpe_id();					\
+									\
+	switch (cpu) {							\
+	case 0:								\
+		write_c0_ ## r ## n(value);				\
+		return;							\
+	case 1:								\
+		write_c0_ ## r ## np(value);				\
+		return;							\
+	default:							\
+		BUG();							\
+	}								\
+	return;								\
+}									\
+
+__define_perf_accessors(perfcntr, 0, 2)
+__define_perf_accessors(perfcntr, 1, 3)
+__define_perf_accessors(perfcntr, 2, 0)
+__define_perf_accessors(perfcntr, 3, 1)
+
+__define_perf_accessors(perfctrl, 0, 2)
+__define_perf_accessors(perfctrl, 1, 3)
+__define_perf_accessors(perfctrl, 2, 0)
+__define_perf_accessors(perfctrl, 3, 1)
+
+static inline int __n_counters(void)
+{
+	if (!(read_c0_config1() & M_CONFIG1_PC))
+		return 0;
+	if (!(read_c0_perfctrl0() & M_PERFCTL_MORE))
+		return 1;
+	if (!(read_c0_perfctrl1() & M_PERFCTL_MORE))
+		return 2;
+	if (!(read_c0_perfctrl2() & M_PERFCTL_MORE))
+		return 3;
+
+	return 4;
+}
+
+static inline int n_counters(void)
+{
+	int counters;
+
+	switch (current_cpu_type()) {
+	case CPU_R10000:
+		counters = 2;
+		break;
+
+	case CPU_R12000:
+	case CPU_R14000:
+		counters = 4;
+		break;
+
+	default:
+		counters = __n_counters();
+	}
+
+	return counters;
+}
+
+static void reset_counters(void *arg)
+{
+	int counters = (int)(long)arg;
+	switch (counters) {
+	case 4:
+		w_c0_perfctrl3(0);
+		w_c0_perfcntr3(0);
+	case 3:
+		w_c0_perfctrl2(0);
+		w_c0_perfcntr2(0);
+	case 2:
+		w_c0_perfctrl1(0);
+		w_c0_perfcntr1(0);
+	case 1:
+		w_c0_perfctrl0(0);
+		w_c0_perfcntr0(0);
+	}
+}
+
+static inline u64
+mipsxx_pmu_read_counter(unsigned int idx)
+{
+	switch (idx) {
+	case 0:
+		return r_c0_perfcntr0();
+	case 1:
+		return r_c0_perfcntr1();
+	case 2:
+		return r_c0_perfcntr2();
+	case 3:
+		return r_c0_perfcntr3();
+	default:
+		WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx);
+		return 0;
+	}
+}
+
+static inline void
+mipsxx_pmu_write_counter(unsigned int idx, u64 val)
+{
+	switch (idx) {
+	case 0:
+		w_c0_perfcntr0(val);
+		return;
+	case 1:
+		w_c0_perfcntr1(val);
+		return;
+	case 2:
+		w_c0_perfcntr2(val);
+		return;
+	case 3:
+		w_c0_perfcntr3(val);
+		return;
+	}
+}
+
+static inline unsigned int
+mipsxx_pmu_read_control(unsigned int idx)
+{
+	switch (idx) {
+	case 0:
+		return r_c0_perfctrl0();
+	case 1:
+		return r_c0_perfctrl1();
+	case 2:
+		return r_c0_perfctrl2();
+	case 3:
+		return r_c0_perfctrl3();
+	default:
+		WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx);
+		return 0;
+	}
+}
+
+static inline void
+mipsxx_pmu_write_control(unsigned int idx, unsigned int val)
+{
+	switch (idx) {
+	case 0:
+		w_c0_perfctrl0(val);
+		return;
+	case 1:
+		w_c0_perfctrl1(val);
+		return;
+	case 2:
+		w_c0_perfctrl2(val);
+		return;
+	case 3:
+		w_c0_perfctrl3(val);
+		return;
+	}
+}
+
+#ifdef CONFIG_MIPS_MT_SMP
+static DEFINE_RWLOCK(pmuint_rwlock);
+#endif
+
+/* 24K/34K/1004K cores can share the same event map. */
+static const struct mips_perf_event mipsxxcore_event_map
+				[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
+	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
+	[PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
+	[PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x02, CNTR_EVEN, T },
+	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
+	[PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
+};
+
+/* 74K core has different branch event code. */
+static const struct mips_perf_event mipsxx74Kcore_event_map
+				[PERF_COUNT_HW_MAX] = {
+	[PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
+	[PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
+	[PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
+	[PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x27, CNTR_EVEN, T },
+	[PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T },
+	[PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
+};
+
+/* 24K/34K/1004K cores can share the same cache event map. */
+static const struct mips_perf_event mipsxxcore_cache_map
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+[C(L1D)] = {
+	/*
+	 * Like some other architectures (e.g. ARM), the performance
+	 * counters don't differentiate between read and write
+	 * accesses/misses, so this isn't strictly correct, but it's the
+	 * best we can do. Writes and reads get combined.
+	 */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x0a, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x0b, CNTR_EVEN | CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x0a, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x0b, CNTR_EVEN | CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(L1I)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x09, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x09, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x09, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x09, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { 0x14, CNTR_EVEN, T },
+		/*
+		 * Note that MIPS has only "hit" events countable for
+		 * the prefetch operation.
+		 */
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(LL)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x15, CNTR_ODD, P },
+		[C(RESULT_MISS)]	= { 0x16, CNTR_EVEN, P },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x15, CNTR_ODD, P },
+		[C(RESULT_MISS)]	= { 0x16, CNTR_EVEN, P },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(DTLB)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x06, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x06, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x06, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x06, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(ITLB)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x05, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x05, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x05, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x05, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(BPU)] = {
+	/* Using the same code for *HW_BRANCH* */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x02, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x02, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x02, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x02, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+};
+
+/* 74K core has completely different cache event map. */
+static const struct mips_perf_event mipsxx74Kcore_cache_map
+				[PERF_COUNT_HW_CACHE_MAX]
+				[PERF_COUNT_HW_CACHE_OP_MAX]
+				[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+[C(L1D)] = {
+	/*
+	 * Like some other architectures (e.g. ARM), the performance
+	 * counters don't differentiate between read and write
+	 * accesses/misses, so this isn't strictly correct, but it's the
+	 * best we can do. Writes and reads get combined.
+	 */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x17, CNTR_ODD, T },
+		[C(RESULT_MISS)]	= { 0x18, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x17, CNTR_ODD, T },
+		[C(RESULT_MISS)]	= { 0x18, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(L1I)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x06, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x06, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x06, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x06, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { 0x34, CNTR_EVEN, T },
+		/*
+		 * Note that MIPS has only "hit" events countable for
+		 * the prefetch operation.
+		 */
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(LL)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x1c, CNTR_ODD, P },
+		[C(RESULT_MISS)]	= { 0x1d, CNTR_EVEN | CNTR_ODD, P },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x1c, CNTR_ODD, P },
+		[C(RESULT_MISS)]	= { 0x1d, CNTR_EVEN | CNTR_ODD, P },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(DTLB)] = {
+	/* 74K core does not have specific DTLB events. */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(ITLB)] = {
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x04, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x04, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x04, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x04, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+[C(BPU)] = {
+	/* Using the same code for *HW_BRANCH* */
+	[C(OP_READ)] = {
+		[C(RESULT_ACCESS)]	= { 0x27, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x27, CNTR_ODD, T },
+	},
+	[C(OP_WRITE)] = {
+		[C(RESULT_ACCESS)]	= { 0x27, CNTR_EVEN, T },
+		[C(RESULT_MISS)]	= { 0x27, CNTR_ODD, T },
+	},
+	[C(OP_PREFETCH)] = {
+		[C(RESULT_ACCESS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+		[C(RESULT_MISS)]	= { UNSUPPORTED_PERF_EVENT_ID },
+	},
+},
+};
+
+#ifdef CONFIG_MIPS_MT_SMP
+static void
+check_and_calc_range(struct perf_event *event,
+			const struct mips_perf_event *pev)
+{
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (event->cpu >= 0) {
+		if (pev->range > V) {
+			/*
+			 * The user selected an event that is processor
+			 * wide, while expecting it to be VPE wide.
+			 */
+			hwc->config_base |= M_TC_EN_ALL;
+		} else {
+			/*
+			 * FIXME: cpu_data[event->cpu].vpe_id reports 0
+			 * for both CPUs.
+			 */
+			hwc->config_base |= M_PERFCTL_VPEID(event->cpu);
+			hwc->config_base |= M_TC_EN_VPE;
+		}
+	} else
+		hwc->config_base |= M_TC_EN_ALL;
+}
+#else
+static void
+check_and_calc_range(struct perf_event *event,
+			const struct mips_perf_event *pev)
+{
+}
+#endif
+
+static int __hw_perf_event_init(struct perf_event *event)
+{
+	struct perf_event_attr *attr = &event->attr;
+	struct hw_perf_event *hwc = &event->hw;
+	const struct mips_perf_event *pev;
+	int err;
+
+	/* Returning MIPS event descriptor for generic perf event. */
+	if (PERF_TYPE_HARDWARE == event->attr.type) {
+		if (event->attr.config >= PERF_COUNT_HW_MAX)
+			return -EINVAL;
+		pev = mipspmu_map_general_event(event->attr.config);
+	} else if (PERF_TYPE_HW_CACHE == event->attr.type) {
+		pev = mipspmu_map_cache_event(event->attr.config);
+	} else if (PERF_TYPE_RAW == event->attr.type) {
+		/* We are working on the global raw event. */
+		mutex_lock(&raw_event_mutex);
+		pev = mipspmu->map_raw_event(event->attr.config);
+	} else {
+		/* The event type is not (yet) supported. */
+		return -EOPNOTSUPP;
+	}
+
+	if (IS_ERR(pev)) {
+		if (PERF_TYPE_RAW == event->attr.type)
+			mutex_unlock(&raw_event_mutex);
+		return PTR_ERR(pev);
+	}
+
+	/*
+	 * We allow max flexibility on how each individual counter shared
+	 * by the single CPU operates (the mode exclusion and the range).
+	 */
+	hwc->config_base = M_PERFCTL_INTERRUPT_ENABLE;
+
+	/* Calculate range bits and validate it. */
+	if (num_possible_cpus() > 1)
+		check_and_calc_range(event, pev);
+
+	hwc->event_base = mipspmu_perf_event_encode(pev);
+	if (PERF_TYPE_RAW == event->attr.type)
+		mutex_unlock(&raw_event_mutex);
+
+	if (!attr->exclude_user)
+		hwc->config_base |= M_PERFCTL_USER;
+	if (!attr->exclude_kernel) {
+		hwc->config_base |= M_PERFCTL_KERNEL;
+		/* MIPS kernel mode: KSU == 00b || EXL == 1 || ERL == 1 */
+		hwc->config_base |= M_PERFCTL_EXL;
+	}
+	if (!attr->exclude_hv)
+		hwc->config_base |= M_PERFCTL_SUPERVISOR;
+
+	hwc->config_base &= M_PERFCTL_CONFIG_MASK;
+	/*
+	 * The event can belong to another cpu. We do not assign a local
+	 * counter for it for now.
+	 */
+	hwc->idx = -1;
+	hwc->config = 0;
+
+	if (!hwc->sample_period) {
+		hwc->sample_period  = MAX_PERIOD;
+		hwc->last_period    = hwc->sample_period;
+		local64_set(&hwc->period_left, hwc->sample_period);
+	}
+
+	err = 0;
+	if (event->group_leader != event) {
+		err = validate_group(event);
+		if (err)
+			return -EINVAL;
+	}
+
+	event->destroy = hw_perf_event_destroy;
+
+	return err;
+}
+
+static void pause_local_counters(void)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	int counters = mipspmu->num_counters;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	switch (counters) {
+	case 4:
+		cpuc->saved_ctrl[3] = r_c0_perfctrl3();
+		w_c0_perfctrl3(cpuc->saved_ctrl[3] &
+			~M_PERFCTL_COUNT_EVENT_WHENEVER);
+	case 3:
+		cpuc->saved_ctrl[2] = r_c0_perfctrl2();
+		w_c0_perfctrl2(cpuc->saved_ctrl[2] &
+			~M_PERFCTL_COUNT_EVENT_WHENEVER);
+	case 2:
+		cpuc->saved_ctrl[1] = r_c0_perfctrl1();
+		w_c0_perfctrl1(cpuc->saved_ctrl[1] &
+			~M_PERFCTL_COUNT_EVENT_WHENEVER);
+	case 1:
+		cpuc->saved_ctrl[0] = r_c0_perfctrl0();
+		w_c0_perfctrl0(cpuc->saved_ctrl[0] &
+			~M_PERFCTL_COUNT_EVENT_WHENEVER);
+	}
+	local_irq_restore(flags);
+}
+
+static void resume_local_counters(void)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	int counters = mipspmu->num_counters;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	switch (counters) {
+	case 4:
+		w_c0_perfctrl3(cpuc->saved_ctrl[3]);
+	case 3:
+		w_c0_perfctrl2(cpuc->saved_ctrl[2]);
+	case 2:
+		w_c0_perfctrl1(cpuc->saved_ctrl[1]);
+	case 1:
+		w_c0_perfctrl0(cpuc->saved_ctrl[0]);
+	}
+	local_irq_restore(flags);
+}
+
+static int mipsxx_pmu_handle_shared_irq(void)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct perf_sample_data data;
+	unsigned int counters = mipspmu->num_counters;
+	unsigned int counter;
+	int handled = IRQ_NONE;
+	struct pt_regs *regs;
+
+	if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26)))
+		return handled;
+
+	/*
+	 * First we pause the local counters, so that when we are locked
+	 * here, the counters are all paused. When it gets locked due to
+	 * perf_disable(), the timer interrupt handler will be delayed.
+	 *
+	 * See also mipsxx_pmu_start().
+	 */
+	pause_local_counters();
+#ifdef CONFIG_MIPS_MT_SMP
+	read_lock(&pmuint_rwlock);
+#endif
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	switch (counters) {
+#define HANDLE_COUNTER(n)						\
+	case n + 1:							\
+		if (test_bit(n, cpuc->used_mask)) {			\
+			counter = r_c0_perfcntr ## n();			\
+			if (counter & M_COUNTER_OVERFLOW) {		\
+				w_c0_perfcntr ## n(counter &		\
+						VALID_COUNT);		\
+				if (test_and_change_bit(n, cpuc->msbs))	\
+					handle_associated_event(cpuc,	\
+						n, &data, regs);	\
+				handled = IRQ_HANDLED;			\
+			}						\
+		}
+	HANDLE_COUNTER(3)
+	HANDLE_COUNTER(2)
+	HANDLE_COUNTER(1)
+	HANDLE_COUNTER(0)
+	}
+
+	/*
+	 * Do all the work for the pending perf events. We can do this
+	 * in here because the performance counter interrupt is a regular
+	 * interrupt, not NMI.
+	 */
+	if (handled == IRQ_HANDLED)
+		perf_event_do_pending();
+
+#ifdef CONFIG_MIPS_MT_SMP
+	read_unlock(&pmuint_rwlock);
+#endif
+	resume_local_counters();
+	return handled;
+}
+
+static irqreturn_t
+mipsxx_pmu_handle_irq(int irq, void *dev)
+{
+	return mipsxx_pmu_handle_shared_irq();
+}
+
+static void mipsxx_pmu_start(void)
+{
+#ifdef CONFIG_MIPS_MT_SMP
+	write_unlock(&pmuint_rwlock);
+#endif
+	resume_local_counters();
+}
+
+/*
+ * MIPS performance counters can be per-TC. The control registers can
+ * not be directly accessed accross CPUs. Hence if we want to do global
+ * control, we need cross CPU calls. on_each_cpu() can help us, but we
+ * can not make sure this function is called with interrupts enabled. So
+ * here we pause local counters and then grab a rwlock and leave the
+ * counters on other CPUs alone. If any counter interrupt raises while
+ * we own the write lock, simply pause local counters on that CPU and
+ * spin in the handler. Also we know we won't be switched to another
+ * CPU after pausing local counters and before grabbing the lock.
+ */
+static void mipsxx_pmu_stop(void)
+{
+	pause_local_counters();
+#ifdef CONFIG_MIPS_MT_SMP
+	write_lock(&pmuint_rwlock);
+#endif
+}
+
+static int
+mipsxx_pmu_alloc_counter(struct cpu_hw_events *cpuc,
+			struct hw_perf_event *hwc)
+{
+	int i;
+
+	/*
+	 * We only need to care the counter mask. The range has been
+	 * checked definitely.
+	 */
+	unsigned long cntr_mask = (hwc->event_base >> 8) & 0xffff;
+
+	for (i = mipspmu->num_counters - 1; i >= 0; i--) {
+		/*
+		 * Note that some MIPS perf events can be counted by both
+		 * even and odd counters, wheresas many other are only by
+		 * even _or_ odd counters. This introduces an issue that
+		 * when the former kind of event takes the counter the
+		 * latter kind of event wants to use, then the "counter
+		 * allocation" for the latter event will fail. In fact if
+		 * they can be dynamically swapped, they both feel happy.
+		 * But here we leave this issue alone for now.
+		 */
+		if (test_bit(i, &cntr_mask) &&
+			!test_and_set_bit(i, cpuc->used_mask))
+			return i;
+	}
+
+	return -EAGAIN;
+}
+
+static void
+mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	unsigned long flags;
+
+	WARN_ON(idx < 0 || idx >= mipspmu->num_counters);
+
+	local_irq_save(flags);
+	cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) |
+		(evt->config_base & M_PERFCTL_CONFIG_MASK) |
+		/* Make sure interrupt enabled. */
+		M_PERFCTL_INTERRUPT_ENABLE;
+	/*
+	 * We do not actually let the counter run. Leave it until start().
+	 */
+	local_irq_restore(flags);
+}
+
+static void
+mipsxx_pmu_disable_event(int idx)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	unsigned long flags;
+
+	WARN_ON(idx < 0 || idx >= mipspmu->num_counters);
+
+	local_irq_save(flags);
+	cpuc->saved_ctrl[idx] = mipsxx_pmu_read_control(idx) &
+		~M_PERFCTL_COUNT_EVENT_WHENEVER;
+	mipsxx_pmu_write_control(idx, cpuc->saved_ctrl[idx]);
+	local_irq_restore(flags);
+}
+
+/* 24K */
+#define IS_UNSUPPORTED_24K_EVENT(r, b)					\
+	((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 ||		\
+	 (b) == 27 || (r) == 28 || (r) == 158 || (b) == 31 ||		\
+	 (b) == 32 || (b) == 34 || (b) == 36 || (r) == 168 ||		\
+	 (r) == 172 || (b) == 47 || ((b) >= 56 && (b) <= 63) ||		\
+	 ((b) >= 68 && (b) <= 127))
+#define IS_BOTH_COUNTERS_24K_EVENT(b)					\
+	((b) == 0 || (b) == 1 || (b) == 11)
+
+/* 34K */
+#define IS_UNSUPPORTED_34K_EVENT(r, b)					\
+	((b) == 12 || (r) == 27 || (r) == 158 || (b) == 36 ||		\
+	 (b) == 38 || (r) == 175 || ((b) >= 56 && (b) <= 63) ||		\
+	 ((b) >= 68 && (b) <= 127))
+#define IS_BOTH_COUNTERS_34K_EVENT(b)					\
+	((b) == 0 || (b) == 1 || (b) == 11)
+#ifdef CONFIG_MIPS_MT_SMP
+#define IS_RANGE_P_34K_EVENT(r, b)					\
+	((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 ||		\
+	 (b) == 25 || (b) == 39 || (r) == 44 || (r) == 174 ||		\
+	 (r) == 176 || ((b) >= 50 && (b) <= 55) ||			\
+	 ((b) >= 64 && (b) <= 67))
+#define IS_RANGE_V_34K_EVENT(r)	((r) == 47)
+#endif
+
+/* 74K */
+#define IS_UNSUPPORTED_74K_EVENT(r, b)					\
+	((r) == 5 || ((r) >= 135 && (r) <= 137) ||			\
+	 ((b) >= 10 && (b) <= 12) || (b) == 22 || (b) == 27 ||		\
+	 (b) == 33 || (b) == 34 || ((b) >= 47 && (b) <= 49) ||		\
+	 (r) == 178 || (b) == 55 || (b) == 57 || (b) == 60 ||		\
+	 (b) == 61 || (r) == 62 || (r) == 191 ||			\
+	 ((b) >= 64 && (b) <= 127))
+#define IS_BOTH_COUNTERS_74K_EVENT(b)					\
+	((b) == 0 || (b) == 1)
+
+/* 1004K */
+#define IS_UNSUPPORTED_1004K_EVENT(r, b)				\
+	((b) == 12 || (r) == 27 || (r) == 158 || (b) == 38 ||		\
+	 (r) == 175 || (b) == 63 || ((b) >= 68 && (b) <= 127))
+#define IS_BOTH_COUNTERS_1004K_EVENT(b)					\
+	((b) == 0 || (b) == 1 || (b) == 11)
+#ifdef CONFIG_MIPS_MT_SMP
+#define IS_RANGE_P_1004K_EVENT(r, b)					\
+	((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 ||		\
+	 (b) == 25 || (b) == 36 || (b) == 39 || (r) == 44 ||		\
+	 (r) == 174 || (r) == 176 || ((b) >= 50 && (b) <= 59) ||	\
+	 (r) == 188 || (b) == 61 || (b) == 62 ||			\
+	 ((b) >= 64 && (b) <= 67))
+#define IS_RANGE_V_1004K_EVENT(r)	((r) == 47)
+#endif
+
+/*
+ * User can use 0-255 raw events, where 0-127 for the events of even
+ * counters, and 128-255 for odd counters. Note that bit 7 is used to
+ * indicate the parity. So, for example, when user wants to take the
+ * Event Num of 15 for odd counters (by referring to the user manual),
+ * then 128 needs to be added to 15 as the input for the event config,
+ * i.e., 143 (0x8F) to be used.
+ */
+static const struct mips_perf_event *
+mipsxx_pmu_map_raw_event(u64 config)
+{
+	unsigned int raw_id = config & 0xff;
+	unsigned int base_id = raw_id & 0x7f;
+
+	switch (current_cpu_type()) {
+	case CPU_24K:
+		if (IS_UNSUPPORTED_24K_EVENT(raw_id, base_id))
+			return ERR_PTR(-EOPNOTSUPP);
+		raw_event.event_id = base_id;
+		if (IS_BOTH_COUNTERS_24K_EVENT(base_id))
+			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		else
+			raw_event.cntr_mask =
+				raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+		/*
+		 * This is actually doing nothing. Non-multithreading
+		 * CPUs will not check and calculate the range.
+		 */
+		raw_event.range = P;
+#endif
+		break;
+	case CPU_34K:
+		if (IS_UNSUPPORTED_34K_EVENT(raw_id, base_id))
+			return ERR_PTR(-EOPNOTSUPP);
+		raw_event.event_id = base_id;
+		if (IS_BOTH_COUNTERS_34K_EVENT(base_id))
+			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		else
+			raw_event.cntr_mask =
+				raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+		if (IS_RANGE_P_34K_EVENT(raw_id, base_id))
+			raw_event.range = P;
+		else if (unlikely(IS_RANGE_V_34K_EVENT(raw_id)))
+			raw_event.range = V;
+		else
+			raw_event.range = T;
+#endif
+		break;
+	case CPU_74K:
+		if (IS_UNSUPPORTED_74K_EVENT(raw_id, base_id))
+			return ERR_PTR(-EOPNOTSUPP);
+		raw_event.event_id = base_id;
+		if (IS_BOTH_COUNTERS_74K_EVENT(base_id))
+			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		else
+			raw_event.cntr_mask =
+				raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+		raw_event.range = P;
+#endif
+		break;
+	case CPU_1004K:
+		if (IS_UNSUPPORTED_1004K_EVENT(raw_id, base_id))
+			return ERR_PTR(-EOPNOTSUPP);
+		raw_event.event_id = base_id;
+		if (IS_BOTH_COUNTERS_1004K_EVENT(base_id))
+			raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+		else
+			raw_event.cntr_mask =
+				raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
+#ifdef CONFIG_MIPS_MT_SMP
+		if (IS_RANGE_P_1004K_EVENT(raw_id, base_id))
+			raw_event.range = P;
+		else if (unlikely(IS_RANGE_V_1004K_EVENT(raw_id)))
+			raw_event.range = V;
+		else
+			raw_event.range = T;
+#endif
+		break;
+	}
+
+	return &raw_event;
+}
+
+static struct mips_pmu mipsxxcore_pmu = {
+	.handle_irq = mipsxx_pmu_handle_irq,
+	.handle_shared_irq = mipsxx_pmu_handle_shared_irq,
+	.start = mipsxx_pmu_start,
+	.stop = mipsxx_pmu_stop,
+	.alloc_counter = mipsxx_pmu_alloc_counter,
+	.read_counter = mipsxx_pmu_read_counter,
+	.write_counter = mipsxx_pmu_write_counter,
+	.enable_event = mipsxx_pmu_enable_event,
+	.disable_event = mipsxx_pmu_disable_event,
+	.map_raw_event = mipsxx_pmu_map_raw_event,
+	.general_event_map = &mipsxxcore_event_map,
+	.cache_event_map = &mipsxxcore_cache_map,
+};
+
+static struct mips_pmu mipsxx74Kcore_pmu = {
+	.handle_irq = mipsxx_pmu_handle_irq,
+	.handle_shared_irq = mipsxx_pmu_handle_shared_irq,
+	.start = mipsxx_pmu_start,
+	.stop = mipsxx_pmu_stop,
+	.alloc_counter = mipsxx_pmu_alloc_counter,
+	.read_counter = mipsxx_pmu_read_counter,
+	.write_counter = mipsxx_pmu_write_counter,
+	.enable_event = mipsxx_pmu_enable_event,
+	.disable_event = mipsxx_pmu_disable_event,
+	.map_raw_event = mipsxx_pmu_map_raw_event,
+	.general_event_map = &mipsxx74Kcore_event_map,
+	.cache_event_map = &mipsxx74Kcore_cache_map,
+};
+
+static int __init
+init_hw_perf_events(void)
+{
+	int counters, irq;
+
+	pr_info("Performance counters: ");
+
+	counters = n_counters();
+	if (counters == 0) {
+		pr_cont("No available PMU.\n");
+		return -ENODEV;
+	}
+
+#ifdef CONFIG_MIPS_MT_SMP
+	cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
+	if (!cpu_has_mipsmt_pertccounters)
+		counters = counters_total_to_per_cpu(counters);
+#endif
+
+#ifdef MSC01E_INT_BASE
+	if (cpu_has_veic) {
+		/*
+		 * Using platform specific interrupt controller defines.
+		 */
+		irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
+	} else {
+#endif
+		if (cp0_perfcount_irq >= 0)
+			irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
+		else
+			irq = -1;
+#ifdef MSC01E_INT_BASE
+	}
+#endif
+
+	on_each_cpu(reset_counters, (void *)(long)counters, 1);
+
+	switch (current_cpu_type()) {
+	case CPU_24K:
+		mipsxxcore_pmu.name = "mips/24K";
+		mipsxxcore_pmu.num_counters = counters;
+		mipsxxcore_pmu.irq = irq;
+		mipspmu = &mipsxxcore_pmu;
+		break;
+	case CPU_34K:
+		mipsxxcore_pmu.name = "mips/34K";
+		mipsxxcore_pmu.num_counters = counters;
+		mipsxxcore_pmu.irq = irq;
+		mipspmu = &mipsxxcore_pmu;
+		break;
+	case CPU_74K:
+		mipsxx74Kcore_pmu.name = "mips/74K";
+		mipsxx74Kcore_pmu.num_counters = counters;
+		mipsxx74Kcore_pmu.irq = irq;
+		mipspmu = &mipsxx74Kcore_pmu;
+		break;
+	case CPU_1004K:
+		mipsxxcore_pmu.name = "mips/1004K";
+		mipsxxcore_pmu.num_counters = counters;
+		mipsxxcore_pmu.irq = irq;
+		mipspmu = &mipsxxcore_pmu;
+		break;
+	default:
+		pr_cont("Either hardware does not support performance "
+			"counters, or not yet implemented.\n");
+		return -ENODEV;
+	}
+
+	if (mipspmu)
+		pr_cont("%s PMU enabled, %d counters available to each "
+			"CPU, irq %d%s\n", mipspmu->name, counters, irq,
+			irq < 0 ? " (share with timer interrupt)" : "");
+
+	return 0;
+}
+arch_initcall(init_hw_perf_events);
+
+#endif /* defined(CONFIG_CPU_MIPS32)... */
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/process.c linux-libre-2.6.37-gnu/arch/mips/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -142,7 +142,6 @@
 	childregs->regs[7] = 0;	/* Clear error flag */
 
 	childregs->regs[2] = 0;	/* Child gets zero as return value */
-	regs->regs[2] = p->pid;
 
 	if (childregs->cp0_status & ST0_CU0) {
 		childregs->regs[28] = (unsigned long) ti;
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/prom.c linux-libre-2.6.37-gnu/arch/mips/kernel/prom.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/prom.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,112 @@
+/*
+ * MIPS support for CONFIG_OF device tree support
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/page.h>
+#include <asm/prom.h>
+
+int __init early_init_dt_scan_memory_arch(unsigned long node,
+					  const char *uname, int depth,
+					  void *data)
+{
+	return early_init_dt_scan_memory(node, uname, depth, data);
+}
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+	return add_memory_region(base, size, BOOT_MEM_RAM);
+}
+
+int __init reserve_mem_mach(unsigned long addr, unsigned long size)
+{
+	return reserve_bootmem(addr, size, BOOTMEM_DEFAULT);
+}
+
+void __init free_mem_mach(unsigned long addr, unsigned long size)
+{
+	return free_bootmem(addr, size);
+}
+
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+	return virt_to_phys(
+		__alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS))
+		);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+					    unsigned long end)
+{
+	initrd_start = (unsigned long)__va(start);
+	initrd_end = (unsigned long)__va(end);
+	initrd_below_start_ok = 1;
+}
+#endif
+
+/*
+ * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
+ *
+ * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
+ * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
+ * supported.
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+				   const u32 *intspec, unsigned int intsize)
+{
+	return intspec[0];
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+void __init early_init_devtree(void *params)
+{
+	/* Setup flat device-tree pointer */
+	initial_boot_params = params;
+
+	/* Retrieve various informations from the /chosen node of the
+	 * device-tree, including the platform type, initrd location and
+	 * size, and more ...
+	 */
+	of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+
+	/* Scan memory nodes */
+	of_scan_flat_dt(early_init_dt_scan_root, NULL);
+	of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL);
+}
+
+void __init device_tree_init(void)
+{
+	unsigned long base, size;
+
+	if (!initial_boot_params)
+		return;
+
+	base = virt_to_phys((void *)initial_boot_params);
+	size = be32_to_cpu(initial_boot_params->totalsize);
+
+	/* Before we do anything, lets reserve the dt blob */
+	reserve_mem_mach(base, size);
+
+	unflatten_device_tree();
+
+	/* free the space reserved for the dt blob */
+	free_mem_mach(base, size);
+}
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/mips/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -255,9 +255,13 @@
 	return 0;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	void __user *addrp = (void __user *) addr;
+	void __user *datavp = (void __user *) data;
+	unsigned long __user *datalp = (void __user *) data;
 
 	switch (request) {
 	/* when I and D space are separate, these will need to be fixed. */
@@ -386,7 +390,7 @@
 			ret = -EIO;
 			goto out;
 		}
-		ret = put_user(tmp, (unsigned long __user *) data);
+		ret = put_user(tmp, datalp);
 		break;
 	}
 
@@ -478,34 +482,31 @@
 		}
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs(child, (__s64 __user *) data);
+		ret = ptrace_getregs(child, datavp);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs(child, (__s64 __user *) data);
+		ret = ptrace_setregs(child, datavp);
 		break;
 
 	case PTRACE_GETFPREGS:
-		ret = ptrace_getfpregs(child, (__u32 __user *) data);
+		ret = ptrace_getfpregs(child, datavp);
 		break;
 
 	case PTRACE_SETFPREGS:
-		ret = ptrace_setfpregs(child, (__u32 __user *) data);
+		ret = ptrace_setfpregs(child, datavp);
 		break;
 
 	case PTRACE_GET_THREAD_AREA:
-		ret = put_user(task_thread_info(child)->tp_value,
-				(unsigned long __user *) data);
+		ret = put_user(task_thread_info(child)->tp_value, datalp);
 		break;
 
 	case PTRACE_GET_WATCH_REGS:
-		ret = ptrace_get_watch_regs(child,
-					(struct pt_watch_regs __user *) addr);
+		ret = ptrace_get_watch_regs(child, addrp);
 		break;
 
 	case PTRACE_SET_WATCH_REGS:
-		ret = ptrace_set_watch_regs(child,
-					(struct pt_watch_regs __user *) addr);
+		ret = ptrace_set_watch_regs(child, addrp);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/rtlx.c linux-libre-2.6.37-gnu/arch/mips/kernel/rtlx.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/rtlx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/rtlx.c	2011-01-04 19:50:19.000000000 -0500
@@ -468,7 +468,8 @@
 	.release = file_release,
 	.write =   file_write,
 	.read =    file_read,
-	.poll =    file_poll
+	.poll =    file_poll,
+	.llseek =  noop_llseek,
 };
 
 static struct irqaction rtlx_irq = {
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/setup.c linux-libre-2.6.37-gnu/arch/mips/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 #include <asm/setup.h>
 #include <asm/smp-ops.h>
 #include <asm/system.h>
+#include <asm/prom.h>
 
 struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
 
@@ -487,7 +488,9 @@
 	}
 
 	bootmem_init();
+	device_tree_init();
 	sparse_init();
+	plat_swiotlb_setup();
 	paging_init();
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/smp-mt.c linux-libre-2.6.37-gnu/arch/mips/kernel/smp-mt.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/smp-mt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/smp-mt.c	2011-01-04 19:50:19.000000000 -0500
@@ -153,7 +153,7 @@
 {
 	extern int gic_present;
 
-	/* This is Malta specific: IPI,performance and timer inetrrupts */
+	/* This is Malta specific: IPI,performance and timer interrupts */
 	if (gic_present)
 		change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 |
 					 STATUSF_IP6 | STATUSF_IP7);
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/smtc.c linux-libre-2.6.37-gnu/arch/mips/kernel/smtc.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/smtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/smtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -1038,7 +1038,7 @@
 		 * but it's more efficient, given that we're already
 		 * running down the IPI queue.
 		 */
-		__raw_local_irq_restore(flags);
+		__arch_local_irq_restore(flags);
 	}
 }
 
@@ -1190,7 +1190,7 @@
 		/*
 		 ** But use a raw restore here to avoid recursion.
 		 */
-		__raw_local_irq_restore(flags);
+		__arch_local_irq_restore(flags);
 
 		if (pipi) {
 			self_ipi(pipi);
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/traps.c linux-libre-2.6.37-gnu/arch/mips/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,8 @@
 #include <linux/kprobes.h>
 #include <linux/notifier.h>
 #include <linux/kdb.h>
+#include <linux/irq.h>
+#include <linux/perf_event.h>
 
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
@@ -51,7 +53,6 @@
 #include <asm/mmu_context.h>
 #include <asm/types.h>
 #include <asm/stacktrace.h>
-#include <asm/irq.h>
 #include <asm/uasm.h>
 
 extern void check_wait(void);
@@ -82,7 +83,8 @@
 extern asmlinkage void handle_reserved(void);
 
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
-	struct mips_fpu_struct *ctx, int has_fpu);
+				    struct mips_fpu_struct *ctx, int has_fpu,
+				    void *__user *fault_addr);
 
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
@@ -576,10 +578,16 @@
  */
 static int simulate_llsc(struct pt_regs *regs, unsigned int opcode)
 {
-	if ((opcode & OPCODE) == LL)
+	if ((opcode & OPCODE) == LL) {
+		perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+				1, 0, regs, 0);
 		return simulate_ll(regs, opcode);
-	if ((opcode & OPCODE) == SC)
+	}
+	if ((opcode & OPCODE) == SC) {
+		perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+				1, 0, regs, 0);
 		return simulate_sc(regs, opcode);
+	}
 
 	return -1;			/* Must be something else ... */
 }
@@ -595,6 +603,8 @@
 	if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {
 		int rd = (opcode & RD) >> 11;
 		int rt = (opcode & RT) >> 16;
+		perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+				1, 0, regs, 0);
 		switch (rd) {
 		case 0:		/* CPU number */
 			regs->regs[rt] = smp_processor_id();
@@ -630,8 +640,11 @@
 
 static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
 {
-	if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC)
+	if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) {
+		perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+				1, 0, regs, 0);
 		return 0;
+	}
 
 	return -1;			/* Must be something else ... */
 }
@@ -649,12 +662,36 @@
 	force_sig_info(SIGFPE, &info, current);
 }
 
+static int process_fpemu_return(int sig, void __user *fault_addr)
+{
+	if (sig == SIGSEGV || sig == SIGBUS) {
+		struct siginfo si = {0};
+		si.si_addr = fault_addr;
+		si.si_signo = sig;
+		if (sig == SIGSEGV) {
+			if (find_vma(current->mm, (unsigned long)fault_addr))
+				si.si_code = SEGV_ACCERR;
+			else
+				si.si_code = SEGV_MAPERR;
+		} else {
+			si.si_code = BUS_ADRERR;
+		}
+		force_sig_info(sig, &si, current);
+		return 1;
+	} else if (sig) {
+		force_sig(sig, current);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
 /*
  * XXX Delayed fp exceptions when doing a lazy ctx switch XXX
  */
 asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
 {
-	siginfo_t info;
+	siginfo_t info = {0};
 
 	if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE)
 	    == NOTIFY_STOP)
@@ -663,6 +700,7 @@
 
 	if (fcr31 & FPU_CSR_UNI_X) {
 		int sig;
+		void __user *fault_addr = NULL;
 
 		/*
 		 * Unimplemented operation exception.  If we've got the full
@@ -678,7 +716,8 @@
 		lose_fpu(1);
 
 		/* Run the emulator */
-		sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1);
+		sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
+					       &fault_addr);
 
 		/*
 		 * We can't allow the emulated instruction to leave any of
@@ -690,8 +729,7 @@
 		own_fpu(1);	/* Using the FPU again.  */
 
 		/* If something went wrong, signal */
-		if (sig)
-			force_sig(sig, current);
+		process_fpemu_return(sig, fault_addr);
 
 		return;
 	} else if (fcr31 & FPU_CSR_INV_X)
@@ -984,11 +1022,11 @@
 
 		if (!raw_cpu_has_fpu) {
 			int sig;
+			void __user *fault_addr = NULL;
 			sig = fpu_emulator_cop1Handler(regs,
-						&current->thread.fpu, 0);
-			if (sig)
-				force_sig(sig, current);
-			else
+						       &current->thread.fpu,
+						       0, &fault_addr);
+			if (!process_fpemu_return(sig, fault_addr))
 				mt_ase_fp_affinity();
 		}
 
@@ -1469,6 +1507,7 @@
 {
 	unsigned int cpu = smp_processor_id();
 	unsigned int status_set = ST0_CU0;
+	unsigned int hwrena = cpu_hwrena_impl_bits;
 #ifdef CONFIG_MIPS_MT_SMTC
 	int secondaryTC = 0;
 	int bootTC = (cpu == 0);
@@ -1501,14 +1540,14 @@
 	change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
 			 status_set);
 
-	if (cpu_has_mips_r2) {
-		unsigned int enable = 0x0000000f | cpu_hwrena_impl_bits;
+	if (cpu_has_mips_r2)
+		hwrena |= 0x0000000f;
 
-		if (!noulri && cpu_has_userlocal)
-			enable |= (1 << 29);
+	if (!noulri && cpu_has_userlocal)
+		hwrena |= (1 << 29);
 
-		write_c0_hwrena(enable);
-	}
+	if (hwrena)
+		write_c0_hwrena(hwrena);
 
 #ifdef CONFIG_MIPS_MT_SMTC
 	if (!secondaryTC) {
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/unaligned.c linux-libre-2.6.37-gnu/arch/mips/kernel/unaligned.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/unaligned.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/unaligned.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,6 +78,8 @@
 #include <linux/smp.h>
 #include <linux/sched.h>
 #include <linux/debugfs.h>
+#include <linux/perf_event.h>
+
 #include <asm/asm.h>
 #include <asm/branch.h>
 #include <asm/byteorder.h>
@@ -109,6 +111,9 @@
 	unsigned long value;
 	unsigned int res;
 
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+		      1, 0, regs, 0);
+
 	/*
 	 * This load never faults.
 	 */
@@ -511,6 +516,8 @@
 	unsigned int __user *pc;
 	mm_segment_t seg;
 
+	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS,
+			1, 0, regs, regs->cp0_badvaddr);
 	/*
 	 * Did we catch a fault trying to load an instruction?
 	 * Or are we running in MIPS16 mode?
diff -druN linux-libre-2.6.36-gnu/arch/mips/kernel/vpe.c linux-libre-2.6.37-gnu/arch/mips/kernel/vpe.c
--- linux-libre-2.6.36-gnu/arch/mips/kernel/vpe.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/kernel/vpe.c	2011-01-04 19:50:19.000000000 -0500
@@ -1092,6 +1092,10 @@
 
 	/* this of-course trashes what was there before... */
 	v->pbuffer = vmalloc(P_SIZE);
+	if (!v->pbuffer) {
+		pr_warning("VPE loader: unable to allocate memory\n");
+		return -ENOMEM;
+	}
 	v->plen = P_SIZE;
 	v->load_addr = NULL;
 	v->len = 0;
@@ -1149,10 +1153,9 @@
 	if (ret < 0)
 		v->shared_ptr = NULL;
 
-	// cleanup any temp buffers
-	if (v->pbuffer)
-		vfree(v->pbuffer);
+	vfree(v->pbuffer);
 	v->plen = 0;
+
 	return ret;
 }
 
@@ -1169,11 +1172,6 @@
 	if (v == NULL)
 		return -ENODEV;
 
-	if (v->pbuffer == NULL) {
-		printk(KERN_ERR "VPE loader: no buffer for program\n");
-		return -ENOMEM;
-	}
-
 	if ((count + v->len) > v->plen) {
 		printk(KERN_WARNING
 		       "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
@@ -1192,7 +1190,8 @@
 	.owner = THIS_MODULE,
 	.open = vpe_open,
 	.release = vpe_release,
-	.write = vpe_write
+	.write = vpe_write,
+	.llseek = noop_llseek,
 };
 
 /* module wrapper entry points */
diff -druN linux-libre-2.6.36-gnu/arch/mips/lib/memset.S linux-libre-2.6.37-gnu/arch/mips/lib/memset.S
--- linux-libre-2.6.36-gnu/arch/mips/lib/memset.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/lib/memset.S	2011-01-04 19:50:19.000000000 -0500
@@ -161,16 +161,16 @@
 
 .Lfwd_fixup:
 	PTR_L		t0, TI_TASK($28)
-	LONG_L		t0, THREAD_BUADDR(t0)
 	andi		a2, 0x3f
+	LONG_L		t0, THREAD_BUADDR(t0)
 	LONG_ADDU	a2, t1
 	jr		ra
 	 LONG_SUBU	a2, t0
 
 .Lpartial_fixup:
 	PTR_L		t0, TI_TASK($28)
-	LONG_L		t0, THREAD_BUADDR(t0)
 	andi		a2, LONGMASK
+	LONG_L		t0, THREAD_BUADDR(t0)
 	LONG_ADDU	a2, t1
 	jr		ra
 	 LONG_SUBU	a2, t0
diff -druN linux-libre-2.6.36-gnu/arch/mips/loongson/common/env.c linux-libre-2.6.37-gnu/arch/mips/loongson/common/env.c
--- linux-libre-2.6.36-gnu/arch/mips/loongson/common/env.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/loongson/common/env.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,9 +29,9 @@
 
 #define parse_even_earlier(res, option, p)				\
 do {									\
+	int ret;							\
 	if (strncmp(option, (char *)p, strlen(option)) == 0)		\
-			strict_strtol((char *)p + strlen(option"="),	\
-					10, &res);			\
+		ret = strict_strtol((char *)p + strlen(option"="), 10, &res); \
 } while (0)
 
 void __init prom_init_env(void)
diff -druN linux-libre-2.6.36-gnu/arch/mips/loongson/Kconfig linux-libre-2.6.37-gnu/arch/mips/loongson/Kconfig
--- linux-libre-2.6.36-gnu/arch/mips/loongson/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/loongson/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	select SYS_SUPPORTS_HIGHMEM
 	select SYS_HAS_EARLY_PRINTK
-	select GENERIC_HARDIRQS_NO__DO_IRQ
 	select GENERIC_ISA_DMA_SUPPORT_BROKEN
 	select CPU_HAS_WB
 	select LOONGSON_MC146818
@@ -40,7 +39,6 @@
 	select CS5536
 	select CSRC_R4K if ! MIPS_EXTERNAL_TIMER
 	select DMA_NONCOHERENT
-	select GENERIC_HARDIRQS_NO__DO_IRQ
 	select GENERIC_ISA_DMA_SUPPORT_BROKEN
 	select HW_HAS_PCI
 	select I8259
diff -druN linux-libre-2.6.36-gnu/arch/mips/Makefile linux-libre-2.6.37-gnu/arch/mips/Makefile
--- linux-libre-2.6.36-gnu/arch/mips/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -48,9 +48,6 @@
   endif
 endif
 
-ifndef CONFIG_FUNCTION_TRACER
-cflags-y := -ffunction-sections
-endif
 ifdef CONFIG_FUNCTION_GRAPH_TRACER
   ifndef KBUILD_MCOUNT_RA_ADDRESS
     ifeq ($(call cc-option-yn,-mmcount-ra-address), y)
@@ -159,6 +156,7 @@
 ifeq (,$(findstring march=octeon, $(cflags-$(CONFIG_CPU_CAVIUM_OCTEON))))
 cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -Wa,-march=octeon
 endif
+cflags-$(CONFIG_CAVIUM_CN63XXP1) += -Wa,-mfix-cn63xxp1
 
 cflags-$(CONFIG_CPU_R4000_WORKAROUNDS)	+= $(call cc-option,-mfix-r4000,)
 cflags-$(CONFIG_CPU_R4400_WORKAROUNDS)	+= $(call cc-option,-mfix-r4400,)
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/cp1emu.c linux-libre-2.6.37-gnu/arch/mips/math-emu/cp1emu.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/cp1emu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/cp1emu.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
  *
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000  MIPS Technologies, Inc.
@@ -37,6 +36,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/perf_event.h>
 
 #include <asm/inst.h>
 #include <asm/bootinfo.h>
@@ -64,7 +64,7 @@
 
 #if __mips >= 4 && __mips != 32
 static int fpux_emu(struct pt_regs *,
-	struct mips_fpu_struct *, mips_instruction);
+	struct mips_fpu_struct *, mips_instruction, void *__user *);
 #endif
 
 /* Further private data for which no space exists in mips_fpu_struct */
@@ -208,16 +208,23 @@
  * Two instructions if the instruction is in a branch delay slot.
  */
 
-static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
+static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+		       void *__user *fault_addr)
 {
 	mips_instruction ir;
 	unsigned long emulpc, contpc;
 	unsigned int cond;
 
-	if (get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
+	if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
 		MIPS_FPU_EMU_INC_STATS(errors);
+		*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
 		return SIGBUS;
 	}
+	if (__get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
+		MIPS_FPU_EMU_INC_STATS(errors);
+		*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+		return SIGSEGV;
+	}
 
 	/* XXX NEC Vr54xx bug workaround */
 	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
@@ -245,10 +252,16 @@
 #endif
 			return SIGILL;
 		}
-		if (get_user(ir, (mips_instruction __user *) emulpc)) {
+		if (!access_ok(VERIFY_READ, emulpc, sizeof(mips_instruction))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = (mips_instruction __user *)emulpc;
 			return SIGBUS;
 		}
+		if (__get_user(ir, (mips_instruction __user *) emulpc)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = (mips_instruction __user *)emulpc;
+			return SIGSEGV;
+		}
 		/* __compute_return_epc() will have updated cp0_epc */
 		contpc = xcp->cp0_epc;
 		/* In order not to confuse ptrace() et al, tweak context */
@@ -259,6 +272,8 @@
 	}
 
       emul:
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
+			1, 0, xcp, 0);
 	MIPS_FPU_EMU_INC_STATS(emulated);
 	switch (MIPSInst_OPCODE(ir)) {
 	case ldc1_op:{
@@ -267,10 +282,17 @@
 		u64 val;
 
 		MIPS_FPU_EMU_INC_STATS(loads);
-		if (get_user(val, va)) {
+
+		if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
 			return SIGBUS;
 		}
+		if (__get_user(val, va)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
+			return SIGSEGV;
+		}
 		DITOREG(val, MIPSInst_RT(ir));
 		break;
 	}
@@ -282,10 +304,16 @@
 
 		MIPS_FPU_EMU_INC_STATS(stores);
 		DIFROMREG(val, MIPSInst_RT(ir));
-		if (put_user(val, va)) {
+		if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
 			return SIGBUS;
 		}
+		if (__put_user(val, va)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
+			return SIGSEGV;
+		}
 		break;
 	}
 
@@ -295,10 +323,16 @@
 		u32 val;
 
 		MIPS_FPU_EMU_INC_STATS(loads);
-		if (get_user(val, va)) {
+		if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
 			return SIGBUS;
 		}
+		if (__get_user(val, va)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
+			return SIGSEGV;
+		}
 		SITOREG(val, MIPSInst_RT(ir));
 		break;
 	}
@@ -310,10 +344,16 @@
 
 		MIPS_FPU_EMU_INC_STATS(stores);
 		SIFROMREG(val, MIPSInst_RT(ir));
-		if (put_user(val, va)) {
+		if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
 			return SIGBUS;
 		}
+		if (__put_user(val, va)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = va;
+			return SIGSEGV;
+		}
 		break;
 	}
 
@@ -438,11 +478,18 @@
 				contpc = (xcp->cp0_epc +
 					(MIPSInst_SIMM(ir) << 2));
 
-				if (get_user(ir,
-				    (mips_instruction __user *) xcp->cp0_epc)) {
+				if (!access_ok(VERIFY_READ, xcp->cp0_epc,
+					       sizeof(mips_instruction))) {
 					MIPS_FPU_EMU_INC_STATS(errors);
+					*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
 					return SIGBUS;
 				}
+				if (__get_user(ir,
+				    (mips_instruction __user *) xcp->cp0_epc)) {
+					MIPS_FPU_EMU_INC_STATS(errors);
+					*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+					return SIGSEGV;
+				}
 
 				switch (MIPSInst_OPCODE(ir)) {
 				case lwc1_op:
@@ -504,9 +551,8 @@
 
 #if __mips >= 4 && __mips != 32
 	case cop1x_op:{
-		int sig;
-
-		if ((sig = fpux_emu(xcp, ctx, ir)))
+		int sig = fpux_emu(xcp, ctx, ir, fault_addr);
+		if (sig)
 			return sig;
 		break;
 	}
@@ -602,7 +648,7 @@
 DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
 
 static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
-	mips_instruction ir)
+	mips_instruction ir, void *__user *fault_addr)
 {
 	unsigned rcsr = 0;	/* resulting csr */
 
@@ -622,10 +668,16 @@
 				xcp->regs[MIPSInst_FT(ir)]);
 
 			MIPS_FPU_EMU_INC_STATS(loads);
-			if (get_user(val, va)) {
+			if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
 				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
 				return SIGBUS;
 			}
+			if (__get_user(val, va)) {
+				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
+				return SIGSEGV;
+			}
 			SITOREG(val, MIPSInst_FD(ir));
 			break;
 
@@ -636,10 +688,16 @@
 			MIPS_FPU_EMU_INC_STATS(stores);
 
 			SIFROMREG(val, MIPSInst_FS(ir));
-			if (put_user(val, va)) {
+			if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
 				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
 				return SIGBUS;
 			}
+			if (put_user(val, va)) {
+				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
+				return SIGSEGV;
+			}
 			break;
 
 		case madd_s_op:
@@ -699,10 +757,16 @@
 				xcp->regs[MIPSInst_FT(ir)]);
 
 			MIPS_FPU_EMU_INC_STATS(loads);
-			if (get_user(val, va)) {
+			if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
 				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
 				return SIGBUS;
 			}
+			if (__get_user(val, va)) {
+				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
+				return SIGSEGV;
+			}
 			DITOREG(val, MIPSInst_FD(ir));
 			break;
 
@@ -712,10 +776,16 @@
 
 			MIPS_FPU_EMU_INC_STATS(stores);
 			DIFROMREG(val, MIPSInst_FS(ir));
-			if (put_user(val, va)) {
+			if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
 				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
 				return SIGBUS;
 			}
+			if (__put_user(val, va)) {
+				MIPS_FPU_EMU_INC_STATS(errors);
+				*fault_addr = va;
+				return SIGSEGV;
+			}
 			break;
 
 		case madd_d_op:
@@ -1240,7 +1310,7 @@
 }
 
 int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
-	int has_fpu)
+	int has_fpu, void *__user *fault_addr)
 {
 	unsigned long oldepc, prevepc;
 	mips_instruction insn;
@@ -1250,10 +1320,16 @@
 	do {
 		prevepc = xcp->cp0_epc;
 
-		if (get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {
+		if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
 			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
 			return SIGBUS;
 		}
+		if (__get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {
+			MIPS_FPU_EMU_INC_STATS(errors);
+			*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
+			return SIGSEGV;
+		}
 		if (insn == 0)
 			xcp->cp0_epc += 4;	/* skip nops */
 		else {
@@ -1265,7 +1341,7 @@
 			 */
 			/* convert to ieee library modes */
 			ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
-			sig = cop1Emulate(xcp, ctx);
+			sig = cop1Emulate(xcp, ctx, fault_addr);
 			/* revert to mips rounding mode */
 			ieee754_csr.rm = mips_rm[ieee754_csr.rm];
 		}
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_add.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_add.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_add.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_add.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_cmp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_cmp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_cmp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_cmp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_div.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_div.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_div.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_div.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_fint.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_fint.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_fint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_fint.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_flong.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_flong.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_flong.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_flong.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_frexp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_frexp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_frexp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_frexp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_fsp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_fsp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_fsp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_fsp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_logb.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_logb.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_logb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_logb.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_modf.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_modf.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_modf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_modf.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_mul.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_mul.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_mul.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_mul.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_scalb.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_scalb.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_scalb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_scalb.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_simple.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_simple.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_simple.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_simple.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_sqrt.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_sqrt.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_sqrt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_sqrt.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_sub.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_sub.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_sub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_sub.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_tint.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_tint.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_tint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_tint.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_tlong.c linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_tlong.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/dp_tlong.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/dp_tlong.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754d.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754d.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754d.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754d.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
  * MIPS floating point support
  *
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754dp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754dp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754dp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754dp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754dp.h linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754dp.h
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754dp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754dp.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754.h linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754.h
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  *  This program is free software; you can distribute it and/or modify it
  *  under the terms of the GNU General Public License (Version 2) as
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754int.h linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754int.h
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754int.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754int.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754m.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754m.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754m.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754m.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754sp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754sp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754sp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754sp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754sp.h linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754sp.h
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754sp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754sp.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754xcpt.c linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754xcpt.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/ieee754xcpt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/ieee754xcpt.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_add.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_add.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_add.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_add.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_cmp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_cmp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_cmp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_cmp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_div.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_div.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_div.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_div.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_fdp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_fdp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_fdp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_fdp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_fint.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_fint.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_fint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_fint.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_flong.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_flong.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_flong.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_flong.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_frexp.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_frexp.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_frexp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_frexp.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_logb.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_logb.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_logb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_logb.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_modf.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_modf.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_modf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_modf.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_mul.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_mul.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_mul.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_mul.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_scalb.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_scalb.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_scalb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_scalb.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_simple.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_simple.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_simple.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_simple.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_sqrt.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_sqrt.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_sqrt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_sqrt.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_sub.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_sub.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_sub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_sub.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_tint.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_tint.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_tint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_tint.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_tlong.c linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_tlong.c
--- linux-libre-2.6.36-gnu/arch/mips/math-emu/sp_tlong.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/math-emu/sp_tlong.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 /*
  * MIPS floating point support
  * Copyright (C) 1994-2000 Algorithmics Ltd.
- * http://www.algor.co.uk
  *
  * ########################################################################
  *
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/c-octeon.c linux-libre-2.6.37-gnu/arch/mips/mm/c-octeon.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/c-octeon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/c-octeon.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,10 +181,10 @@
 	unsigned int config1;
 	struct cpuinfo_mips *c = &current_cpu_data;
 
+	config1 = read_c0_config1();
 	switch (c->cputype) {
 	case CPU_CAVIUM_OCTEON:
 	case CPU_CAVIUM_OCTEON_PLUS:
-		config1 = read_c0_config1();
 		c->icache.linesz = 2 << ((config1 >> 19) & 7);
 		c->icache.sets = 64 << ((config1 >> 22) & 7);
 		c->icache.ways = 1 + ((config1 >> 16) & 7);
@@ -204,6 +204,20 @@
 		c->options |= MIPS_CPU_PREFETCH;
 		break;
 
+	case CPU_CAVIUM_OCTEON2:
+		c->icache.linesz = 2 << ((config1 >> 19) & 7);
+		c->icache.sets = 8;
+		c->icache.ways = 37;
+		c->icache.flags |= MIPS_CACHE_VTAG;
+		icache_size = c->icache.sets * c->icache.ways * c->icache.linesz;
+
+		c->dcache.linesz = 128;
+		c->dcache.ways = 32;
+		c->dcache.sets = 8;
+		dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz;
+		c->options |= MIPS_CPU_PREFETCH;
+		break;
+
 	default:
 		panic("Unsupported Cavium Networks CPU type\n");
 		break;
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/c-r4k.c linux-libre-2.6.37-gnu/arch/mips/mm/c-r4k.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/c-r4k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/c-r4k.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,14 +42,14 @@
  *  o collapses to normal function call on UP kernels
  *  o collapses to normal function call on systems with a single shared
  *    primary cache.
+ *  o doesn't disable interrupts on the local CPU
  */
-static inline void r4k_on_each_cpu(void (*func) (void *info), void *info,
-                                   int wait)
+static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
 {
 	preempt_disable();
 
 #if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
-	smp_call_function(func, info, wait);
+	smp_call_function(func, info, 1);
 #endif
 	func(info);
 	preempt_enable();
@@ -363,7 +363,7 @@
 
 static void r4k___flush_cache_all(void)
 {
-	r4k_on_each_cpu(local_r4k___flush_cache_all, NULL, 1);
+	r4k_on_each_cpu(local_r4k___flush_cache_all, NULL);
 }
 
 static inline int has_valid_asid(const struct mm_struct *mm)
@@ -410,7 +410,7 @@
 	int exec = vma->vm_flags & VM_EXEC;
 
 	if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc))
-		r4k_on_each_cpu(local_r4k_flush_cache_range, vma, 1);
+		r4k_on_each_cpu(local_r4k_flush_cache_range, vma);
 }
 
 static inline void local_r4k_flush_cache_mm(void * args)
@@ -442,7 +442,7 @@
 	if (!cpu_has_dc_aliases)
 		return;
 
-	r4k_on_each_cpu(local_r4k_flush_cache_mm, mm, 1);
+	r4k_on_each_cpu(local_r4k_flush_cache_mm, mm);
 }
 
 struct flush_cache_page_args {
@@ -534,7 +534,7 @@
 	args.addr = addr;
 	args.pfn = pfn;
 
-	r4k_on_each_cpu(local_r4k_flush_cache_page, &args, 1);
+	r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
 }
 
 static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -547,8 +547,7 @@
 	if (in_atomic())
 		local_r4k_flush_data_cache_page((void *)addr);
 	else
-		r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr,
-			        1);
+		r4k_on_each_cpu(local_r4k_flush_data_cache_page, (void *) addr);
 }
 
 struct flush_icache_range_args {
@@ -589,7 +588,7 @@
 	args.start = start;
 	args.end = end;
 
-	r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args, 1);
+	r4k_on_each_cpu(local_r4k_flush_icache_range_ipi, &args);
 	instruction_hazard();
 }
 
@@ -710,7 +709,7 @@
 
 static void r4k_flush_cache_sigtramp(unsigned long addr)
 {
-	r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr, 1);
+	r4k_on_each_cpu(local_r4k_flush_cache_sigtramp, (void *) addr);
 }
 
 static void r4k_flush_icache_all(void)
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/dma-default.c linux-libre-2.6.37-gnu/arch/mips/mm/dma-default.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/dma-default.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/dma-default.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,10 +95,9 @@
 
 	return ret;
 }
-
 EXPORT_SYMBOL(dma_alloc_noncoherent);
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
+static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
 	dma_addr_t * dma_handle, gfp_t gfp)
 {
 	void *ret;
@@ -123,7 +122,6 @@
 	return ret;
 }
 
-EXPORT_SYMBOL(dma_alloc_coherent);
 
 void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
 	dma_addr_t dma_handle)
@@ -131,10 +129,9 @@
 	plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL);
 	free_pages((unsigned long) vaddr, get_order(size));
 }
-
 EXPORT_SYMBOL(dma_free_noncoherent);
 
-void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 	dma_addr_t dma_handle)
 {
 	unsigned long addr = (unsigned long) vaddr;
@@ -151,8 +148,6 @@
 	free_pages(addr, get_order(size));
 }
 
-EXPORT_SYMBOL(dma_free_coherent);
-
 static inline void __dma_sync(unsigned long addr, size_t size,
 	enum dma_data_direction direction)
 {
@@ -174,21 +169,8 @@
 	}
 }
 
-dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
-	enum dma_data_direction direction)
-{
-	unsigned long addr = (unsigned long) ptr;
-
-	if (!plat_device_is_coherent(dev))
-		__dma_sync(addr, size, direction);
-
-	return plat_map_dma_mem(dev, ptr, size);
-}
-
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-	enum dma_data_direction direction)
+static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
+	size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
 {
 	if (cpu_is_noncoherent_r10000(dev))
 		__dma_sync(dma_addr_to_virt(dev, dma_addr), size,
@@ -197,15 +179,11 @@
 	plat_unmap_dma_mem(dev, dma_addr, size, direction);
 }
 
-EXPORT_SYMBOL(dma_unmap_single);
-
-int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	enum dma_data_direction direction)
+static int mips_dma_map_sg(struct device *dev, struct scatterlist *sg,
+	int nents, enum dma_data_direction direction, struct dma_attrs *attrs)
 {
 	int i;
 
-	BUG_ON(direction == DMA_NONE);
-
 	for (i = 0; i < nents; i++, sg++) {
 		unsigned long addr;
 
@@ -219,33 +197,27 @@
 	return nents;
 }
 
-EXPORT_SYMBOL(dma_map_sg);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-	unsigned long offset, size_t size, enum dma_data_direction direction)
+static dma_addr_t mips_dma_map_page(struct device *dev, struct page *page,
+	unsigned long offset, size_t size, enum dma_data_direction direction,
+	struct dma_attrs *attrs)
 {
-	BUG_ON(direction == DMA_NONE);
+	unsigned long addr;
 
-	if (!plat_device_is_coherent(dev)) {
-		unsigned long addr;
+	addr = (unsigned long) page_address(page) + offset;
 
-		addr = (unsigned long) page_address(page) + offset;
+	if (!plat_device_is_coherent(dev))
 		__dma_sync(addr, size, direction);
-	}
 
-	return plat_map_dma_mem_page(dev, page) + offset;
+	return plat_map_dma_mem(dev, (void *)addr, size);
 }
 
-EXPORT_SYMBOL(dma_map_page);
-
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	enum dma_data_direction direction)
+static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+	int nhwentries, enum dma_data_direction direction,
+	struct dma_attrs *attrs)
 {
 	unsigned long addr;
 	int i;
 
-	BUG_ON(direction == DMA_NONE);
-
 	for (i = 0; i < nhwentries; i++, sg++) {
 		if (!plat_device_is_coherent(dev) &&
 		    direction != DMA_TO_DEVICE) {
@@ -257,13 +229,9 @@
 	}
 }
 
-EXPORT_SYMBOL(dma_unmap_sg);
-
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-	size_t size, enum dma_data_direction direction)
+static void mips_dma_sync_single_for_cpu(struct device *dev,
+	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
 {
-	BUG_ON(direction == DMA_NONE);
-
 	if (cpu_is_noncoherent_r10000(dev)) {
 		unsigned long addr;
 
@@ -272,13 +240,9 @@
 	}
 }
 
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
-
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-	size_t size, enum dma_data_direction direction)
+static void mips_dma_sync_single_for_device(struct device *dev,
+	dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
 {
-	BUG_ON(direction == DMA_NONE);
-
 	plat_extra_sync_for_device(dev);
 	if (!plat_device_is_coherent(dev)) {
 		unsigned long addr;
@@ -288,46 +252,11 @@
 	}
 }
 
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-	unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-
-	if (cpu_is_noncoherent_r10000(dev)) {
-		unsigned long addr;
-
-		addr = dma_addr_to_virt(dev, dma_handle);
-		__dma_sync(addr + offset, size, direction);
-	}
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-	unsigned long offset, size_t size, enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
-
-	plat_extra_sync_for_device(dev);
-	if (!plat_device_is_coherent(dev)) {
-		unsigned long addr;
-
-		addr = dma_addr_to_virt(dev, dma_handle);
-		__dma_sync(addr + offset, size, direction);
-	}
-}
-
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
-
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-	enum dma_data_direction direction)
+static void mips_dma_sync_sg_for_cpu(struct device *dev,
+	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
 {
 	int i;
 
-	BUG_ON(direction == DMA_NONE);
-
 	/* Make sure that gcc doesn't leave the empty loop body.  */
 	for (i = 0; i < nelems; i++, sg++) {
 		if (cpu_is_noncoherent_r10000(dev))
@@ -336,15 +265,11 @@
 	}
 }
 
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
-
-void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-	enum dma_data_direction direction)
+static void mips_dma_sync_sg_for_device(struct device *dev,
+	struct scatterlist *sg, int nelems, enum dma_data_direction direction)
 {
 	int i;
 
-	BUG_ON(direction == DMA_NONE);
-
 	/* Make sure that gcc doesn't leave the empty loop body.  */
 	for (i = 0; i < nelems; i++, sg++) {
 		if (!plat_device_is_coherent(dev))
@@ -353,24 +278,18 @@
 	}
 }
 
-EXPORT_SYMBOL(dma_sync_sg_for_device);
-
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+int mips_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
 	return plat_dma_mapping_error(dev, dma_addr);
 }
 
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_supported(struct device *dev, u64 mask)
+int mips_dma_supported(struct device *dev, u64 mask)
 {
 	return plat_dma_supported(dev, mask);
 }
 
-EXPORT_SYMBOL(dma_supported);
-
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-	       enum dma_data_direction direction)
+			 enum dma_data_direction direction)
 {
 	BUG_ON(direction == DMA_NONE);
 
@@ -380,3 +299,31 @@
 }
 
 EXPORT_SYMBOL(dma_cache_sync);
+
+static struct dma_map_ops mips_default_dma_map_ops = {
+	.alloc_coherent = mips_dma_alloc_coherent,
+	.free_coherent = mips_dma_free_coherent,
+	.map_page = mips_dma_map_page,
+	.unmap_page = mips_dma_unmap_page,
+	.map_sg = mips_dma_map_sg,
+	.unmap_sg = mips_dma_unmap_sg,
+	.sync_single_for_cpu = mips_dma_sync_single_for_cpu,
+	.sync_single_for_device = mips_dma_sync_single_for_device,
+	.sync_sg_for_cpu = mips_dma_sync_sg_for_cpu,
+	.sync_sg_for_device = mips_dma_sync_sg_for_device,
+	.mapping_error = mips_dma_mapping_error,
+	.dma_supported = mips_dma_supported
+};
+
+struct dma_map_ops *mips_dma_map_ops = &mips_default_dma_map_ops;
+EXPORT_SYMBOL(mips_dma_map_ops);
+
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init mips_dma_init(void)
+{
+	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+	return 0;
+}
+fs_initcall(mips_dma_init);
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/fault.c linux-libre-2.6.37-gnu/arch/mips/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/module.h>
 #include <linux/kprobes.h>
+#include <linux/perf_event.h>
 
 #include <asm/branch.h>
 #include <asm/mmu_context.h>
@@ -144,6 +145,7 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		if (fault & VM_FAULT_OOM)
 			goto out_of_memory;
@@ -151,10 +153,15 @@
 			goto do_sigbus;
 		BUG();
 	}
-	if (fault & VM_FAULT_MAJOR)
+	if (fault & VM_FAULT_MAJOR) {
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ,
+				1, 0, regs, address);
 		tsk->maj_flt++;
-	else
+	} else {
+		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN,
+				1, 0, regs, address);
 		tsk->min_flt++;
+	}
 
 	up_read(&mm->mmap_sem);
 	return;
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/highmem.c linux-libre-2.6.37-gnu/arch/mips/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,7 @@
 
 unsigned long highstart_pfn, highend_pfn;
 
-void *__kmap(struct page *page)
+void *kmap(struct page *page)
 {
 	void *addr;
 
@@ -21,16 +21,16 @@
 
 	return addr;
 }
-EXPORT_SYMBOL(__kmap);
+EXPORT_SYMBOL(kmap);
 
-void __kunmap(struct page *page)
+void kunmap(struct page *page)
 {
 	BUG_ON(in_interrupt());
 	if (!PageHighMem(page))
 		return;
 	kunmap_high(page);
 }
-EXPORT_SYMBOL(__kunmap);
+EXPORT_SYMBOL(kunmap);
 
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -41,17 +41,17 @@
  * kmaps are appropriate for short, tight code paths only.
  */
 
-void *__kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
 	pagefault_disable();
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -64,43 +64,48 @@
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
-void __kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+	int type;
 
 	if (vaddr < FIXADDR_START) { // FIXME
 		pagefault_enable();
 		return;
 	}
 
-	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+	type = kmap_atomic_idx();
+#ifdef CONFIG_DEBUG_HIGHMEM
+	{
+		int idx = type + KM_TYPE_NR * smp_processor_id();
 
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(&init_mm, vaddr, kmap_pte-idx);
-	local_flush_tlb_one(vaddr);
-#endif
+		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
 
+		/*
+		 * force other mappings to Oops if they'll try to access
+		 * this pte without first remap it
+		 */
+		pte_clear(&init_mm, vaddr, kmap_pte-idx);
+		local_flush_tlb_one(vaddr);
+	}
+#endif
+	kmap_atomic_idx_pop();
 	pagefault_enable();
 }
-EXPORT_SYMBOL(__kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /*
  * This is the same as kmap_atomic() but can map memory that doesn't
  * have a struct page associated with it.
  */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	pagefault_disable();
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 	set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
@@ -109,7 +114,7 @@
 	return (void*) vaddr;
 }
 
-struct page *__kmap_atomic_to_page(void *ptr)
+struct page *kmap_atomic_to_page(void *ptr)
 {
 	unsigned long idx, vaddr = (unsigned long)ptr;
 	pte_t *pte;
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/sc-mips.c linux-libre-2.6.37-gnu/arch/mips/mm/sc-mips.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/sc-mips.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/sc-mips.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,38 @@
 	.bc_inv = mips_sc_inv
 };
 
+/*
+ * Check if the L2 cache controller is activated on a particular platform.
+ * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS
+ * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the
+ * cache being disabled.  However there is no guarantee for this to be
+ * true on all platforms.  In an act of stupidity the spec defined bits
+ * 12..15 as implementation defined so below function will eventually have
+ * to be replaced by a platform specific probe.
+ */
+static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
+{
+	unsigned int config2 = read_c0_config2();
+	unsigned int tmp;
+
+	/* Check the bypass bit (L2B) */
+	switch (c->cputype) {
+	case CPU_34K:
+	case CPU_74K:
+	case CPU_1004K:
+	case CPU_BMIPS5000:
+		if (config2 & (1 << 12))
+			return 0;
+	}
+
+	tmp = (config2 >> 4) & 0x0f;
+	if (0 < tmp && tmp <= 7)
+		c->scache.linesz = 2 << tmp;
+	else
+		return 0;
+	return 1;
+}
+
 static inline int __init mips_sc_probe(void)
 {
 	struct cpuinfo_mips *c = &current_cpu_data;
@@ -79,10 +111,8 @@
 		return 0;
 
 	config2 = read_c0_config2();
-	tmp = (config2 >> 4) & 0x0f;
-	if (0 < tmp && tmp <= 7)
-		c->scache.linesz = 2 << tmp;
-	else
+
+	if (!mips_sc_is_activated(c))
 		return 0;
 
 	tmp = (config2 >> 8) & 0x0f;
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/tlbex.c linux-libre-2.6.37-gnu/arch/mips/mm/tlbex.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/tlbex.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/tlbex.c	2011-01-04 19:50:19.000000000 -0500
@@ -338,13 +338,12 @@
 	case CPU_4KSC:
 	case CPU_20KC:
 	case CPU_25KF:
-	case CPU_BCM3302:
-	case CPU_BCM4710:
+	case CPU_BMIPS32:
+	case CPU_BMIPS3300:
+	case CPU_BMIPS4350:
+	case CPU_BMIPS4380:
+	case CPU_BMIPS5000:
 	case CPU_LOONGSON2:
-	case CPU_BCM6338:
-	case CPU_BCM6345:
-	case CPU_BCM6348:
-	case CPU_BCM6358:
 	case CPU_R5500:
 		if (m4kc_tlbp_war())
 			uasm_i_nop(p);
diff -druN linux-libre-2.6.36-gnu/arch/mips/mm/uasm.c linux-libre-2.6.37-gnu/arch/mips/mm/uasm.c
--- linux-libre-2.6.36-gnu/arch/mips/mm/uasm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mm/uasm.c	2011-01-04 19:50:19.000000000 -0500
@@ -405,7 +405,6 @@
 I_u1u2u3(_mtc0)
 I_u2u1u3(_ori)
 I_u3u1u2(_or)
-I_u2s3u1(_pref)
 I_0(_rfe)
 I_u2s3u1(_sc)
 I_u2s3u1(_scd)
@@ -427,6 +426,25 @@
 I_u1u2s3(_bbit0);
 I_u1u2s3(_bbit1);
 
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+#include <asm/octeon/octeon.h>
+void __uasminit uasm_i_pref(u32 **buf, unsigned int a, signed int b,
+			    unsigned int c)
+{
+	if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X) && a <= 24 && a != 5)
+		/*
+		 * As per erratum Core-14449, replace prefetches 0-4,
+		 * 6-24 with 'pref 28'.
+		 */
+		build_insn(buf, insn_pref, c, 28, b);
+	else
+		build_insn(buf, insn_pref, c, a, b);
+}
+UASM_EXPORT_SYMBOL(uasm_i_pref);
+#else
+I_u2s3u1(_pref)
+#endif
+
 /* Handle labels. */
 void __uasminit uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
 {
diff -druN linux-libre-2.6.36-gnu/arch/mips/mti-malta/malta-platform.c linux-libre-2.6.37-gnu/arch/mips/mti-malta/malta-platform.c
--- linux-libre-2.6.36-gnu/arch/mips/mti-malta/malta-platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/mti-malta/malta-platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include <linux/serial_8250.h>
 #include <linux/mc146818rtc.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/pci/fixup-fuloong2e.c linux-libre-2.6.37-gnu/arch/mips/pci/fixup-fuloong2e.c
--- linux-libre-2.6.36-gnu/arch/mips/pci/fixup-fuloong2e.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pci/fixup-fuloong2e.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
 {
 	unsigned int val;
 
-	/* Configues port 1, 2, 3, 4 to be validate*/
+	/* Configures port 1, 2, 3, 4 to be validate*/
 	pci_read_config_dword(pdev, 0xe0, &val);
 	pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x4);
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/pci/ops-tx3927.c linux-libre-2.6.37-gnu/arch/mips/pci/ops-tx3927.c
--- linux-libre-2.6.36-gnu/arch/mips/pci/ops-tx3927.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pci/ops-tx3927.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/addrspace.h>
 #include <asm/txx9irq.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/pci/ops-tx4927.c linux-libre-2.6.37-gnu/arch/mips/pci/ops-tx4927.c
--- linux-libre-2.6.36-gnu/arch/mips/pci/ops-tx4927.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pci/ops-tx4927.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/txx9/pci.h>
 #include <asm/txx9/tx4927pcic.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/pci/pcie-octeon.c linux-libre-2.6.37-gnu/arch/mips/pci/pcie-octeon.c
--- linux-libre-2.6.36-gnu/arch/mips/pci/pcie-octeon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pci/pcie-octeon.c	2011-01-04 19:50:19.000000000 -0500
@@ -75,6 +75,8 @@
 	} mem;
 };
 
+#include <dma-coherence.h>
+
 /**
  * Return the Core virtual base address for PCIe IO access. IOs are
  * read/written as an offset from this address.
@@ -1391,6 +1393,9 @@
 			cvmx_pcie_get_io_size(1) - 1;
 		register_pci_controller(&octeon_pcie1_controller);
 	}
+
+	octeon_pci_dma_init();
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/pci/pci-octeon.c linux-libre-2.6.37-gnu/arch/mips/pci/pci-octeon.c
--- linux-libre-2.6.36-gnu/arch/mips/pci/pci-octeon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pci/pci-octeon.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/delay.h>
+#include <linux/swiotlb.h>
 
 #include <asm/time.h>
 
@@ -19,6 +20,8 @@
 #include <asm/octeon/cvmx-pci-defs.h>
 #include <asm/octeon/pci-octeon.h>
 
+#include <dma-coherence.h>
+
 #define USE_OCTEON_INTERNAL_ARBITER
 
 /*
@@ -32,6 +35,8 @@
 /* Octeon't PCI controller uses did=3, subdid=3 for PCI memory. */
 #define OCTEON_PCI_MEMSPACE_OFFSET  (0x00011b0000000000ull)
 
+u64 octeon_bar1_pci_phys;
+
 /**
  * This is the bit decoding used for the Octeon PCI controller addresses
  */
@@ -170,6 +175,8 @@
 		pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, dconfig);
 	}
 
+	dev->dev.archdata.dma_ops = octeon_pci_dma_map_ops;
+
 	return 0;
 }
 
@@ -618,12 +625,10 @@
 	 * before the readl()'s below. We don't want BAR2 overlapping
 	 * with BAR0/BAR1 during these reads.
 	 */
-	octeon_npi_write32(CVMX_NPI_PCI_CFG08, 0);
-	octeon_npi_write32(CVMX_NPI_PCI_CFG09, 0x80);
-
-	/* Disable the BAR1 movable mappings */
-	for (index = 0; index < 32; index++)
-		octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index), 0);
+	octeon_npi_write32(CVMX_NPI_PCI_CFG08,
+			   (u32)(OCTEON_BAR2_PCI_ADDRESS & 0xffffffffull));
+	octeon_npi_write32(CVMX_NPI_PCI_CFG09,
+			   (u32)(OCTEON_BAR2_PCI_ADDRESS >> 32));
 
 	if (octeon_dma_bar_type == OCTEON_DMA_BAR_TYPE_BIG) {
 		/* Remap the Octeon BAR 0 to 0-2GB */
@@ -637,6 +642,25 @@
 		octeon_npi_write32(CVMX_NPI_PCI_CFG06, 2ul << 30);
 		octeon_npi_write32(CVMX_NPI_PCI_CFG07, 0);
 
+		/* BAR1 movable mappings set for identity mapping */
+		octeon_bar1_pci_phys = 0x80000000ull;
+		for (index = 0; index < 32; index++) {
+			union cvmx_pci_bar1_indexx bar1_index;
+
+			bar1_index.u32 = 0;
+			/* Address bits[35:22] sent to L2C */
+			bar1_index.s.addr_idx =
+				(octeon_bar1_pci_phys >> 22) + index;
+			/* Don't put PCI accesses in L2. */
+			bar1_index.s.ca = 1;
+			/* Endian Swap Mode */
+			bar1_index.s.end_swp = 1;
+			/* Set '1' when the selected address range is valid. */
+			bar1_index.s.addr_v = 1;
+			octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index),
+					   bar1_index.u32);
+		}
+
 		/* Devices go after BAR1 */
 		octeon_pci_mem_resource.start =
 			OCTEON_PCI_MEMSPACE_OFFSET + (4ul << 30) -
@@ -652,6 +676,27 @@
 		octeon_npi_write32(CVMX_NPI_PCI_CFG06, 0);
 		octeon_npi_write32(CVMX_NPI_PCI_CFG07, 0);
 
+		/* BAR1 movable regions contiguous to cover the swiotlb */
+		octeon_bar1_pci_phys =
+			virt_to_phys(octeon_swiotlb) & ~((1ull << 22) - 1);
+
+		for (index = 0; index < 32; index++) {
+			union cvmx_pci_bar1_indexx bar1_index;
+
+			bar1_index.u32 = 0;
+			/* Address bits[35:22] sent to L2C */
+			bar1_index.s.addr_idx =
+				(octeon_bar1_pci_phys >> 22) + index;
+			/* Don't put PCI accesses in L2. */
+			bar1_index.s.ca = 1;
+			/* Endian Swap Mode */
+			bar1_index.s.end_swp = 1;
+			/* Set '1' when the selected address range is valid. */
+			bar1_index.s.addr_v = 1;
+			octeon_npi_write32(CVMX_NPI_PCI_BAR1_INDEXX(index),
+					   bar1_index.u32);
+		}
+
 		/* Devices go after BAR0 */
 		octeon_pci_mem_resource.start =
 			OCTEON_PCI_MEMSPACE_OFFSET + (128ul << 20) +
@@ -667,6 +712,9 @@
 	 * was setup properly.
 	 */
 	cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, -1);
+
+	octeon_pci_dma_init();
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c linux-libre-2.6.37-gnu/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
--- linux-libre-2.6.36-gnu/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/irq.h>
 
 #include <asm/system.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/pmc-sierra/yosemite/py-console.c linux-libre-2.6.37-gnu/arch/mips/pmc-sierra/yosemite/py-console.c
--- linux-libre-2.6.36-gnu/arch/mips/pmc-sierra/yosemite/py-console.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/pmc-sierra/yosemite/py-console.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,11 +65,15 @@
 
 	__asm__ __volatile__ (
 	"	.set	mips3		\n"
+	"	.set	push		\n"
+	"	.set	noreorder	\n"
+	"	.set	nomacro		\n"
 	"	ld	%0, %1		\n"
+	"	.set	pop		\n"
 	"	lbu	%0, (%0)	\n"
 	"	.set	mips0		\n"
 	: "=r" (res)
-	: "m" (vaddr));
+	: "R" (vaddr));
 
 	write_c0_status(sr);
 	ssnop_4();
@@ -89,11 +93,15 @@
 
 	__asm__ __volatile__ (
 	"	.set	mips3		\n"
+	"	.set	push		\n"
+	"	.set	noreorder	\n"
+	"	.set	nomacro		\n"
 	"	ld	%0, %1		\n"
+	"	.set	pop		\n"
 	"	sb	%2, (%0)	\n"
 	"	.set	mips0		\n"
 	: "=&r" (tmp)
-	: "m" (vaddr), "r" (c));
+	: "R" (vaddr), "r" (c));
 
 	write_c0_status(sr);
 	ssnop_4();
diff -druN linux-libre-2.6.36-gnu/arch/mips/powertv/asic/irq_asic.c linux-libre-2.6.37-gnu/arch/mips/powertv/asic/irq_asic.c
--- linux-libre-2.6.36-gnu/arch/mips/powertv/asic/irq_asic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/powertv/asic/irq_asic.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/rb532/serial.c linux-libre-2.6.37-gnu/arch/mips/rb532/serial.c
--- linux-libre-2.6.36-gnu/arch/mips/rb532/serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/rb532/serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,6 +29,7 @@
 #include <linux/tty.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/irq.h>
 
 #include <asm/serial.h>
 #include <asm/mach-rc32434/rb.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/sibyte/common/sb_tbprof.c linux-libre-2.6.37-gnu/arch/mips/sibyte/common/sb_tbprof.c
--- linux-libre-2.6.36-gnu/arch/mips/sibyte/common/sb_tbprof.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sibyte/common/sb_tbprof.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 #include <asm/sibyte/sb1250_scd.h>
 #include <asm/sibyte/sb1250_int.h>
 #else
-#error invalid SiByte UART configuation
+#error invalid SiByte UART configuration
 #endif
 
 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
@@ -545,6 +545,7 @@
 	.unlocked_ioctl	= sbprof_tb_ioctl,
 	.compat_ioctl	= sbprof_tb_ioctl,
 	.mmap		= NULL,
+	.llseek		= default_llseek,
 };
 
 static struct class *tb_class;
diff -druN linux-libre-2.6.36-gnu/arch/mips/sibyte/swarm/setup.c linux-libre-2.6.37-gnu/arch/mips/sibyte/swarm/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/sibyte/swarm/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sibyte/swarm/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,7 +82,7 @@
 enum swarm_rtc_type {
 	RTC_NONE,
 	RTC_XICOR,
-	RTC_M4LT81
+	RTC_M41T81,
 };
 
 enum swarm_rtc_type swarm_rtc_type;
@@ -96,7 +96,7 @@
 		sec = xicor_get_time();
 		break;
 
-	case RTC_M4LT81:
+	case RTC_M41T81:
 		sec = m41t81_get_time();
 		break;
 
@@ -115,7 +115,7 @@
 	case RTC_XICOR:
 		return xicor_set_time(sec);
 
-	case RTC_M4LT81:
+	case RTC_M41T81:
 		return m41t81_set_time(sec);
 
 	case RTC_NONE:
@@ -141,7 +141,7 @@
 	if (xicor_probe())
 		swarm_rtc_type = RTC_XICOR;
 	if (m41t81_probe())
-		swarm_rtc_type = RTC_M4LT81;
+		swarm_rtc_type = RTC_M41T81;
 
 #ifdef CONFIG_VT
 	screen_info = (struct screen_info) {
diff -druN linux-libre-2.6.36-gnu/arch/mips/sni/a20r.c linux-libre-2.6.37-gnu/arch/mips/sni/a20r.c
--- linux-libre-2.6.36-gnu/arch/mips/sni/a20r.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sni/a20r.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/sni/pcimt.c linux-libre-2.6.37-gnu/arch/mips/sni/pcimt.c
--- linux-libre-2.6.36-gnu/arch/mips/sni/pcimt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sni/pcimt.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/sni/pcit.c linux-libre-2.6.37-gnu/arch/mips/sni/pcit.c
--- linux-libre-2.6.36-gnu/arch/mips/sni/pcit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sni/pcit.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/sni/rm200.c linux-libre-2.6.37-gnu/arch/mips/sni/rm200.c
--- linux-libre-2.6.36-gnu/arch/mips/sni/rm200.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sni/rm200.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/io.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/sni/time.c linux-libre-2.6.37-gnu/arch/mips/sni/time.c
--- linux-libre-2.6.36-gnu/arch/mips/sni/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/sni/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,6 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/time.h>
 #include <linux/clockchips.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4927.c linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4927.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4927.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4927.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9/tx4927.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4938.c linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4938.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4938.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4938.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9/tx4938.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4939.c linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4939.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/generic/irq_tx4939.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/generic/irq_tx4939.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/types.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9irq.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/generic/setup.c linux-libre-2.6.37-gnu/arch/mips/txx9/generic/setup.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/generic/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/generic/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <linux/leds.h>
 #include <linux/sysdev.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/reboot.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/jmr3927/irq.c linux-libre-2.6.37-gnu/arch/mips/txx9/jmr3927/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/jmr3927/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/jmr3927/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/mipsregs.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4927/irq.c linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4927/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4927/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4927/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -111,6 +111,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/generic.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4938/irq.c linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4938/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4938/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4938/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,6 +64,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/rbtx4938.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4939/irq.c linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4939/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/txx9/rbtx4939/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/txx9/rbtx4939/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/rbtx4939.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mips/vr41xx/common/irq.c linux-libre-2.6.37-gnu/arch/mips/vr41xx/common/irq.c
--- linux-libre-2.6.36-gnu/arch/mips/vr41xx/common/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/vr41xx/common/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/system.h>
diff -druN linux-libre-2.6.36-gnu/arch/mips/vr41xx/common/siu.c linux-libre-2.6.37-gnu/arch/mips/vr41xx/common/siu.c
--- linux-libre-2.6.36-gnu/arch/mips/vr41xx/common/siu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mips/vr41xx/common/siu.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/irq.h>
 
 #include <asm/cpu.h>
 #include <asm/vr41xx/siu.h>
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/boot/compressed/head.S linux-libre-2.6.37-gnu/arch/mn10300/boot/compressed/head.S
--- linux-libre-2.6.36-gnu/arch/mn10300/boot/compressed/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/boot/compressed/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -14,10 +14,29 @@
 
 #include <linux/linkage.h>
 #include <asm/cpu-regs.h>
+#include <asm/cache.h>
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+#endif
 
 	.globl startup_32
 startup_32:
-	# first save off parameters from bootloader
+#ifdef CONFIG_SMP
+	#
+	# Secondary CPUs jump directly to the kernel entry point
+	#
+	# Must save primary CPU's D0-D2 registers as they hold boot parameters
+	#
+	mov	(CPUID), d3
+	and	CPUID_MASK,d3
+	beq	startup_primary
+	mov	CONFIG_KERNEL_TEXT_ADDRESS,a0
+	jmp	(a0)
+
+startup_primary:
+#endif /* CONFIG_SMP */
+
+	# first save parameters from bootloader
 	mov	param_save_area,a0
 	mov	d0,(a0)
 	mov	d1,(4,a0)
@@ -37,8 +56,15 @@
 	mov	(a0),d0
 	btst	CHCTR_ICBUSY|CHCTR_DCBUSY,d0		# wait till not busy
 	lne
-	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0	# writethru dcache
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+#ifdef CONFIG_MN10300_CACHE_WBACK
+	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
+#else
+	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
+#endif /* WBACK */
 	movhu	d0,(a0)					# enable
+#endif /* !ENABLED */
 
 	# clear the BSS area
 	mov	__bss_start,a0
@@ -54,6 +80,9 @@
 
 	# decompress the kernel
 	call	decompress_kernel[],0
+#ifdef CONFIG_MN10300_CACHE_WBACK
+	call	mn10300_dcache_flush_inv[],0
+#endif
 
 	# disable caches again
 	mov	CHCTR,a0
@@ -69,10 +98,46 @@
 	mov	(4,a0),d1
 	mov	(8,a0),d2
 
+	# jump to the kernel proper entry point
 	mov	a3,sp
 	mov	CONFIG_KERNEL_TEXT_ADDRESS,a0
 	jmp	(a0)
 
+
+###############################################################################
+#
+# Cache flush routines
+#
+###############################################################################
+#ifdef CONFIG_MN10300_CACHE_WBACK
+mn10300_dcache_flush_inv:
+	movhu	(CHCTR),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_dcache_flush_inv_end
+
+	mov	L1_CACHE_NENTRIES,d1
+	clr	a1
+
+mn10300_dcache_flush_inv_loop:
+	mov	(DCACHE_PURGE_WAY0(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY1(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY2(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY3(0),a1),d0	# unconditional purge
+
+	add	L1_CACHE_BYTES,a1
+	add	-1,d1
+	bne	mn10300_dcache_flush_inv_loop
+
+mn10300_dcache_flush_inv_end:
+	ret	[],0
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+
+###############################################################################
+#
+# Data areas
+#
+###############################################################################
 	.data
 	.align		4
 param_save_area:
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/configs/asb2303_defconfig linux-libre-2.6.37-gnu/arch/mn10300/configs/asb2303_defconfig
--- linux-libre-2.6.36-gnu/arch/mn10300/configs/asb2303_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/configs/asb2303_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,8 @@
 CONFIG_PROFILING=y
 # CONFIG_BLOCK is not set
 CONFIG_PREEMPT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_MN10300_RTC=y
 CONFIG_MN10300_TTYSM_CONSOLE=y
 CONFIG_MN10300_TTYSM0=y
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/configs/asb2364_defconfig linux-libre-2.6.37-gnu/arch/mn10300/configs/asb2364_defconfig
--- linux-libre-2.6.36-gnu/arch/mn10300/configs/asb2364_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/configs/asb2364_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,98 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_NS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_RELAY=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLOCK is not set
+CONFIG_MN10300_UNIT_ASB2364=y
+CONFIG_PREEMPT=y
+# CONFIG_MN10300_USING_JTAG is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_MN10300_TTYSM_CONSOLE=y
+CONFIG_MN10300_TTYSM0=y
+CONFIG_MN10300_TTYSM0_TIMER2=y
+CONFIG_MN10300_TTYSM1=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_I4=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_PROC_KCORE=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/atomic.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/atomic.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/atomic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/atomic.h	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1,351 @@
+/* MN10300 Atomic counter operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _ASM_ATOMIC_H
+#define _ASM_ATOMIC_H
+
+#include <asm/irqflags.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_SMP
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+	unsigned long status;
+	unsigned long oldval;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	mov	%5,(_ADR,%3)	\n"
+		"	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(oldval), "=m"(*m)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
+		: "memory", "cc");
+
+	return oldval;
+}
+
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+				      unsigned long old, unsigned long new)
+{
+	unsigned long status;
+	unsigned long oldval;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	cmp	%5,%1		\n"
+		"	bne	2f		\n"
+		"	mov	%6,(_ADR,%3)	\n"
+		"2:	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(oldval), "=m"(*m)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
+		  "r"(old), "r"(new)
+		: "memory", "cc");
+
+	return oldval;
+}
+#else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+#error "No SMP atomic operation support!"
+#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+
+#else  /* CONFIG_SMP */
+
+/*
+ * Emulate xchg for non-SMP MN10300
+ */
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+static inline
+unsigned long __xchg(volatile unsigned long *m, unsigned long val)
+{
+	unsigned long oldval;
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	oldval = *m;
+	*m = val;
+	arch_local_irq_restore(flags);
+	return oldval;
+}
+
+/*
+ * Emulate cmpxchg for non-SMP MN10300
+ */
+static inline unsigned long __cmpxchg(volatile unsigned long *m,
+				      unsigned long old, unsigned long new)
+{
+	unsigned long oldval;
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	oldval = *m;
+	if (oldval == old)
+		*m = new;
+	arch_local_irq_restore(flags);
+	return oldval;
+}
+
+#endif /* CONFIG_SMP */
+
+#define xchg(ptr, v)						\
+	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
+				     (unsigned long)(v)))
+
+#define cmpxchg(ptr, o, n)					\
+	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
+					(unsigned long)(o),	\
+					(unsigned long)(n)))
+
+#define atomic_xchg(ptr, v)		(xchg(&(ptr)->counter, (v)))
+#define atomic_cmpxchg(v, old, new)	(cmpxchg(&((v)->counter), (old), (new)))
+
+#endif /* !__ASSEMBLY__ */
+
+#ifndef CONFIG_SMP
 #include <asm-generic/atomic.h>
+#else
+
+/*
+ * Atomic operations that C can't guarantee us.  Useful for
+ * resource counting etc..
+ */
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#ifdef __KERNEL__
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_read(v)	((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
+#define atomic_set(v, i) (((v)->counter) = (i))
+
+/**
+ * atomic_add_return - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+	int retval;
+#ifdef CONFIG_SMP
+	int status;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	add	%5,%1		\n"
+		"	mov	%1,(_ADR,%3)	\n"
+		"	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(retval), "=m"(v->counter)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
+		: "memory", "cc");
+
+#else
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	retval = v->counter;
+	retval += i;
+	v->counter = retval;
+	arch_local_irq_restore(flags);
+#endif
+	return retval;
+}
+
+/**
+ * atomic_sub_return - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns the result
+ * Note that the guaranteed useful range of an atomic_t is only 24 bits.
+ */
+static inline int atomic_sub_return(int i, atomic_t *v)
+{
+	int retval;
+#ifdef CONFIG_SMP
+	int status;
+
+	asm volatile(
+		"1:	mov	%4,(_AAR,%3)	\n"
+		"	mov	(_ADR,%3),%1	\n"
+		"	sub	%5,%1		\n"
+		"	mov	%1,(_ADR,%3)	\n"
+		"	mov	(_ADR,%3),%0	\n"	/* flush */
+		"	mov	(_ASR,%3),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=&r"(retval), "=m"(v->counter)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
+		: "memory", "cc");
+
+#else
+	unsigned long flags;
+	flags = arch_local_cli_save();
+	retval = v->counter;
+	retval -= i;
+	v->counter = retval;
+	arch_local_irq_restore(flags);
+#endif
+	return retval;
+}
+
+static inline int atomic_add_negative(int i, atomic_t *v)
+{
+	return atomic_add_return(i, v) < 0;
+}
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+	atomic_add_return(i, v);
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+	atomic_sub_return(i, v);
+}
+
+static inline void atomic_inc(atomic_t *v)
+{
+	atomic_add_return(1, v);
+}
+
+static inline void atomic_dec(atomic_t *v)
+{
+	atomic_sub_return(1, v);
+}
+
+#define atomic_dec_return(v)		atomic_sub_return(1, (v))
+#define atomic_inc_return(v)		atomic_add_return(1, (v))
+
+#define atomic_sub_and_test(i, v)	(atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_and_test(v)		(atomic_add_return(1, (v)) == 0)
+
+#define atomic_add_unless(v, a, u)				\
+({								\
+	int c, old;						\
+	c = atomic_read(v);					\
+	while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+		c = old;					\
+	c != (u);						\
+})
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+/**
+ * atomic_clear_mask - Atomically clear bits in memory
+ * @mask: Mask of the bits to be cleared
+ * @v: pointer to word in memory
+ *
+ * Atomically clears the bits set in mask from the memory word specified.
+ */
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+#ifdef CONFIG_SMP
+	int status;
+
+	asm volatile(
+		"1:	mov	%3,(_AAR,%2)	\n"
+		"	mov	(_ADR,%2),%0	\n"
+		"	and	%4,%0		\n"
+		"	mov	%0,(_ADR,%2)	\n"
+		"	mov	(_ADR,%2),%0	\n"	/* flush */
+		"	mov	(_ASR,%2),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=m"(*addr)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
+		: "memory", "cc");
+#else
+	unsigned long flags;
+
+	mask = ~mask;
+	flags = arch_local_cli_save();
+	*addr &= mask;
+	arch_local_irq_restore(flags);
+#endif
+}
+
+/**
+ * atomic_set_mask - Atomically set bits in memory
+ * @mask: Mask of the bits to be set
+ * @v: pointer to word in memory
+ *
+ * Atomically sets the bits set in mask from the memory word specified.
+ */
+static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
+{
+#ifdef CONFIG_SMP
+	int status;
+
+	asm volatile(
+		"1:	mov	%3,(_AAR,%2)	\n"
+		"	mov	(_ADR,%2),%0	\n"
+		"	or	%4,%0		\n"
+		"	mov	%0,(_ADR,%2)	\n"
+		"	mov	(_ADR,%2),%0	\n"	/* flush */
+		"	mov	(_ASR,%2),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	1b		\n"
+		: "=&r"(status), "=m"(*addr)
+		: "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
+		: "memory", "cc");
+#else
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+	*addr |= mask;
+	arch_local_irq_restore(flags);
+#endif
+}
+
+/* Atomic operations are already serializing on MN10300??? */
+#define smp_mb__before_atomic_dec()	barrier()
+#define smp_mb__after_atomic_dec()	barrier()
+#define smp_mb__before_atomic_inc()	barrier()
+#define smp_mb__after_atomic_inc()	barrier()
+
+#include <asm-generic/atomic-long.h>
+
+#endif /* __KERNEL__ */
+#endif /* CONFIG_SMP */
+#endif /* _ASM_ATOMIC_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/bitops.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/bitops.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/bitops.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/bitops.h	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,7 @@
 #define clear_bit(nr, addr) ___clear_bit((nr), (addr))
 
 
-static inline void __clear_bit(int nr, volatile void *addr)
+static inline void __clear_bit(unsigned long nr, volatile void *addr)
 {
 	unsigned int *a = (unsigned int *) addr;
 	int mask;
@@ -70,15 +70,15 @@
 /*
  * test bit
  */
-static inline int test_bit(int nr, const volatile void *addr)
+static inline int test_bit(unsigned long nr, const volatile void *addr)
 {
-	return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31));
+	return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31));
 }
 
 /*
  * change bit
  */
-static inline void __change_bit(int nr, volatile void *addr)
+static inline void __change_bit(unsigned long nr, volatile void *addr)
 {
 	int	mask;
 	unsigned int *a = (unsigned int *) addr;
@@ -88,7 +88,7 @@
 	*a ^= mask;
 }
 
-extern void change_bit(int nr, volatile void *addr);
+extern void change_bit(unsigned long nr, volatile void *addr);
 
 /*
  * test and set bit
@@ -135,7 +135,7 @@
 /*
  * test and change bit
  */
-static inline int __test_and_change_bit(int nr, volatile void *addr)
+static inline int __test_and_change_bit(unsigned long nr, volatile void *addr)
 {
 	int	mask, retval;
 	unsigned int *a = (unsigned int *)addr;
@@ -148,7 +148,7 @@
 	return retval;
 }
 
-extern int test_and_change_bit(int nr, volatile void *addr);
+extern int test_and_change_bit(unsigned long nr, volatile void *addr);
 
 #include <asm-generic/bitops/lock.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cacheflush.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cacheflush.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cacheflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cacheflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,66 +17,55 @@
 #include <linux/mm.h>
 
 /*
- * virtually-indexed cache management (our cache is physically indexed)
- */
-#define flush_cache_all()			do {} while (0)
-#define flush_cache_mm(mm)			do {} while (0)
-#define flush_cache_dup_mm(mm)			do {} while (0)
-#define flush_cache_range(mm, start, end)	do {} while (0)
-#define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
-#define flush_cache_vmap(start, end)		do {} while (0)
-#define flush_cache_vunmap(start, end)		do {} while (0)
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-#define flush_dcache_page(page)			do {} while (0)
-#define flush_dcache_mmap_lock(mapping)		do {} while (0)
-#define flush_dcache_mmap_unlock(mapping)	do {} while (0)
-
-/*
- * physically-indexed cache management
- */
-#ifndef CONFIG_MN10300_CACHE_DISABLED
-
-extern void flush_icache_range(unsigned long start, unsigned long end);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *pg);
-
-#else
-
-#define flush_icache_range(start, end)		do {} while (0)
-#define flush_icache_page(vma, pg)		do {} while (0)
-
-#endif
-
-#define flush_icache_user_range(vma, pg, adr, len) \
-	flush_icache_range(adr, adr + len)
-
-#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-	do {					\
-		memcpy(dst, src, len);		\
-		flush_icache_page(vma, page);	\
-	} while (0)
-
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	memcpy(dst, src, len)
-
-/*
- * primitive routines
+ * Primitive routines
  */
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+extern void mn10300_local_icache_inv(void);
+extern void mn10300_local_icache_inv_page(unsigned long start);
+extern void mn10300_local_icache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size);
+extern void mn10300_local_dcache_inv(void);
+extern void mn10300_local_dcache_inv_page(unsigned long start);
+extern void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size);
 extern void mn10300_icache_inv(void);
+extern void mn10300_icache_inv_page(unsigned long start);
+extern void mn10300_icache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_icache_inv_range2(unsigned long start, unsigned long size);
 extern void mn10300_dcache_inv(void);
-extern void mn10300_dcache_inv_page(unsigned start);
-extern void mn10300_dcache_inv_range(unsigned start, unsigned end);
-extern void mn10300_dcache_inv_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_inv_page(unsigned long start);
+extern void mn10300_dcache_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_inv_range2(unsigned long start, unsigned long size);
 #ifdef CONFIG_MN10300_CACHE_WBACK
+extern void mn10300_local_dcache_flush(void);
+extern void mn10300_local_dcache_flush_page(unsigned long start);
+extern void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size);
+extern void mn10300_local_dcache_flush_inv(void);
+extern void mn10300_local_dcache_flush_inv_page(unsigned long start);
+extern void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size);
 extern void mn10300_dcache_flush(void);
-extern void mn10300_dcache_flush_page(unsigned start);
-extern void mn10300_dcache_flush_range(unsigned start, unsigned end);
-extern void mn10300_dcache_flush_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_flush_page(unsigned long start);
+extern void mn10300_dcache_flush_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_flush_range2(unsigned long start, unsigned long size);
 extern void mn10300_dcache_flush_inv(void);
-extern void mn10300_dcache_flush_inv_page(unsigned start);
-extern void mn10300_dcache_flush_inv_range(unsigned start, unsigned end);
-extern void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size);
+extern void mn10300_dcache_flush_inv_page(unsigned long start);
+extern void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end);
+extern void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size);
 #else
+#define mn10300_local_dcache_flush()			do {} while (0)
+#define mn10300_local_dcache_flush_page(start)		do {} while (0)
+#define mn10300_local_dcache_flush_range(start, end)	do {} while (0)
+#define mn10300_local_dcache_flush_range2(start, size)	do {} while (0)
+#define mn10300_local_dcache_flush_inv() \
+		mn10300_local_dcache_inv()
+#define mn10300_local_dcache_flush_inv_page(start) \
+		mn10300_local_dcache_inv_page(start)
+#define mn10300_local_dcache_flush_inv_range(start, end) \
+		mn10300_local_dcache_inv_range(start, end)
+#define mn10300_local_dcache_flush_inv_range2(start, size) \
+		mn10300_local_dcache_inv_range2(start, size)
 #define mn10300_dcache_flush()				do {} while (0)
 #define mn10300_dcache_flush_page(start)		do {} while (0)
 #define mn10300_dcache_flush_range(start, end)		do {} while (0)
@@ -90,7 +79,26 @@
 	mn10300_dcache_inv_range2((start), (size))
 #endif /* CONFIG_MN10300_CACHE_WBACK */
 #else
+#define mn10300_local_icache_inv()			do {} while (0)
+#define mn10300_local_icache_inv_page(start)		do {} while (0)
+#define mn10300_local_icache_inv_range(start, end)	do {} while (0)
+#define mn10300_local_icache_inv_range2(start, size)	do {} while (0)
+#define mn10300_local_dcache_inv()			do {} while (0)
+#define mn10300_local_dcache_inv_page(start)		do {} while (0)
+#define mn10300_local_dcache_inv_range(start, end)	do {} while (0)
+#define mn10300_local_dcache_inv_range2(start, size)	do {} while (0)
+#define mn10300_local_dcache_flush()			do {} while (0)
+#define mn10300_local_dcache_flush_inv_page(start)	do {} while (0)
+#define mn10300_local_dcache_flush_inv()		do {} while (0)
+#define mn10300_local_dcache_flush_inv_range(start, end)do {} while (0)
+#define mn10300_local_dcache_flush_inv_range2(start, size) do {} while (0)
+#define mn10300_local_dcache_flush_page(start)		do {} while (0)
+#define mn10300_local_dcache_flush_range(start, end)	do {} while (0)
+#define mn10300_local_dcache_flush_range2(start, size)	do {} while (0)
 #define mn10300_icache_inv()				do {} while (0)
+#define mn10300_icache_inv_page(start)			do {} while (0)
+#define mn10300_icache_inv_range(start, end)		do {} while (0)
+#define mn10300_icache_inv_range2(start, size)		do {} while (0)
 #define mn10300_dcache_inv()				do {} while (0)
 #define mn10300_dcache_inv_page(start)			do {} while (0)
 #define mn10300_dcache_inv_range(start, end)		do {} while (0)
@@ -103,10 +111,56 @@
 #define mn10300_dcache_flush_page(start)		do {} while (0)
 #define mn10300_dcache_flush_range(start, end)		do {} while (0)
 #define mn10300_dcache_flush_range2(start, size)	do {} while (0)
-#endif /* CONFIG_MN10300_CACHE_DISABLED */
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
 
 /*
- * internal debugging function
+ * Virtually-indexed cache management (our cache is physically indexed)
+ */
+#define flush_cache_all()			do {} while (0)
+#define flush_cache_mm(mm)			do {} while (0)
+#define flush_cache_dup_mm(mm)			do {} while (0)
+#define flush_cache_range(mm, start, end)	do {} while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do {} while (0)
+#define flush_cache_vmap(start, end)		do {} while (0)
+#define flush_cache_vunmap(start, end)		do {} while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+#define flush_dcache_page(page)			do {} while (0)
+#define flush_dcache_mmap_lock(mapping)		do {} while (0)
+#define flush_dcache_mmap_unlock(mapping)	do {} while (0)
+
+/*
+ * Physically-indexed cache management
+ */
+#if defined(CONFIG_MN10300_CACHE_FLUSH_ICACHE)
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_range(unsigned long start, unsigned long end);
+#elif defined(CONFIG_MN10300_CACHE_INV_ICACHE)
+static inline void flush_icache_page(struct vm_area_struct *vma,
+				     struct page *page)
+{
+	mn10300_icache_inv_page(page_to_phys(page));
+}
+extern void flush_icache_range(unsigned long start, unsigned long end);
+#else
+#define flush_icache_range(start, end)		do {} while (0)
+#define flush_icache_page(vma, pg)		do {} while (0)
+#endif
+
+
+#define flush_icache_user_range(vma, pg, adr, len) \
+	flush_icache_range(adr, adr + len)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+	do {					\
+		memcpy(dst, src, len);		\
+		flush_icache_page(vma, page);	\
+	} while (0)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+	memcpy(dst, src, len)
+
+/*
+ * Internal debugging function
  */
 #ifdef CONFIG_DEBUG_PAGEALLOC
 extern void kernel_map_pages(struct page *page, int numpages, int enable);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cache.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cache.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cache.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cache.h	2011-01-04 19:50:19.000000000 -0500
@@ -43,14 +43,18 @@
 
 /* instruction cache access registers */
 #define ICACHE_DATA(WAY, ENTRY, OFF) \
-	__SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32)
+	__SYSREG(0xc8000000 + (WAY) * L1_CACHE_WAYDISP + \
+		(ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32)
 #define ICACHE_TAG(WAY, ENTRY)	 \
-	__SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32)
+	__SYSREG(0xc8100000 + (WAY) * L1_CACHE_WAYDISP + \
+		(ENTRY) * L1_CACHE_BYTES, u32)
 
-/* instruction cache access registers */
+/* data cache access registers */
 #define DCACHE_DATA(WAY, ENTRY, OFF) \
-	__SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10 + (OFF) * 4, u32)
+	__SYSREG(0xc8200000 + (WAY) * L1_CACHE_WAYDISP + \
+		(ENTRY) * L1_CACHE_BYTES + (OFF) * 4, u32)
 #define DCACHE_TAG(WAY, ENTRY)	 \
-	__SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + (ENTRY) * 0x10, u32)
+	__SYSREG(0xc8300000 + (WAY) * L1_CACHE_WAYDISP + \
+		(ENTRY) * L1_CACHE_BYTES, u32)
 
 #endif /* _ASM_CACHE_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cpu-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cpu-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/cpu-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/cpu-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,6 @@
 #include <linux/types.h>
 #endif
 
-#ifdef CONFIG_MN10300_CPU_AM33V2
 /* we tell the compiler to pretend to be AM33 so that it doesn't try and use
  * the FP regs, but tell the assembler that we're actually allowed AM33v2
  * instructions */
@@ -24,7 +23,6 @@
 #else
 .am33_2
 #endif
-#endif
 
 #ifdef __KERNEL__
 
@@ -58,6 +56,9 @@
 #define EPSW_nAR		0x00040000	/* register bank control */
 #define EPSW_ML			0x00080000	/* monitor level */
 #define EPSW_FE			0x00100000	/* FPU enable */
+#define EPSW_IM_SHIFT		8		/* EPSW_IM_SHIFT determines the interrupt mode */
+
+#define NUM2EPSW_IM(num)	((num) << EPSW_IM_SHIFT)
 
 /* FPU registers */
 #define FPCR_EF_I		0x00000001	/* inexact result FPU exception flag */
@@ -99,9 +100,11 @@
 #define CPUREV			__SYSREGC(0xc0000050, u32)	/* CPU revision register */
 #define CPUREV_TYPE		0x0000000f	/* CPU type */
 #define CPUREV_TYPE_S		0
-#define CPUREV_TYPE_AM33V1	0x00000000	/* - AM33 V1 core, AM33/1.00 arch */
-#define CPUREV_TYPE_AM33V2	0x00000001	/* - AM33 V2 core, AM33/2.00 arch */
-#define CPUREV_TYPE_AM34V1	0x00000002	/* - AM34 V1 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM33_1	0x00000000	/* - AM33-1 core, AM33/1.00 arch */
+#define CPUREV_TYPE_AM33_2	0x00000001	/* - AM33-2 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM34_1	0x00000002	/* - AM34-1 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM33_3	0x00000003	/* - AM33-3 core, AM33/2.00 arch */
+#define CPUREV_TYPE_AM34_2	0x00000004	/* - AM34-2 core, AM33/3.00 arch */
 #define CPUREV_REVISION		0x000000f0	/* CPU revision */
 #define CPUREV_REVISION_S	4
 #define CPUREV_ICWAY		0x00000f00	/* number of instruction cache ways */
@@ -180,6 +183,21 @@
 #define CHCTR_ICWMD		0x0f00		/* instruction cache way mode */
 #define CHCTR_DCWMD		0xf000		/* data cache way mode */
 
+#ifdef CONFIG_AM34_2
+#define ICIVCR			__SYSREG(0xc0000c00, u32)	/* icache area invalidate control */
+#define ICIVCR_ICIVBSY		0x00000008			/* icache area invalidate busy */
+#define ICIVCR_ICI		0x00000001			/* icache area invalidate */
+
+#define ICIVMR			__SYSREG(0xc0000c04, u32)	/* icache area invalidate mask */
+
+#define	DCPGCR			__SYSREG(0xc0000c10, u32)	/* data cache area purge control */
+#define	DCPGCR_DCPGBSY		0x00000008			/* data cache area purge busy */
+#define	DCPGCR_DCP		0x00000002			/* data cache area purge */
+#define	DCPGCR_DCI		0x00000001			/* data cache area invalidate */
+
+#define	DCPGMR			__SYSREG(0xc0000c14, u32)	/* data cache area purge mask */
+#endif /* CONFIG_AM34_2 */
+
 /* MMU control registers */
 #define MMUCTR			__SYSREG(0xc0000090, u32)	/* MMU control register */
 #define MMUCTR_IRP		0x0000003f	/* instruction TLB replace pointer */
@@ -203,6 +221,9 @@
 #define MMUCTR_DTL_LOCK0_3	0x03000000	/* - entry 0-3 locked */
 #define MMUCTR_DTL_LOCK0_7	0x04000000	/* - entry 0-7 locked */
 #define MMUCTR_DTL_LOCK0_15	0x05000000	/* - entry 0-15 locked */
+#ifdef CONFIG_AM34_2
+#define MMUCTR_WTE		0x80000000	/* write-through cache TLB entry bit enable */
+#endif
 
 #define PIDR			__SYSREG(0xc0000094, u16)	/* PID register */
 #define PIDR_PID		0x00ff		/* process identifier */
@@ -231,14 +252,6 @@
 #define xPTEL_PS_4Mb		0x00000c00	/* - 4Mb page */
 #define xPTEL_PPN		0xfffff006	/* physical page number */
 
-#define xPTEL_V_BIT		0	/* bit numbers corresponding to above masks */
-#define xPTEL_UNUSED1_BIT	1
-#define xPTEL_UNUSED2_BIT	2
-#define xPTEL_C_BIT		3
-#define xPTEL_PV_BIT		4
-#define xPTEL_D_BIT		5
-#define xPTEL_G_BIT		9
-
 #define IPTEU			__SYSREG(0xc00000a4, u32)	/* instruction TLB virtual addr */
 #define DPTEU			__SYSREG(0xc00000b4, u32)	/* data TLB virtual addr */
 #define xPTEU_VPN		0xfffffc00	/* virtual page number */
@@ -262,7 +275,16 @@
 #define xPTEL2_PS_128Kb		0x00000100	/* - 128Kb page */
 #define xPTEL2_PS_1Kb		0x00000200	/* - 1Kb page */
 #define xPTEL2_PS_4Mb		0x00000300	/* - 4Mb page */
-#define xPTEL2_PPN		0xfffffc00	/* physical page number */
+#define xPTEL2_CWT		0x00000400	/* cacheable write-through */
+#define xPTEL2_UNUSED1		0x00000800	/* unused bit (broadcast mask) */
+#define xPTEL2_PPN		0xfffff000	/* physical page number */
+
+#define xPTEL2_V_BIT		0	/* bit numbers corresponding to above masks */
+#define xPTEL2_C_BIT		1
+#define xPTEL2_PV_BIT		2
+#define xPTEL2_D_BIT		3
+#define xPTEL2_G_BIT		7
+#define xPTEL2_UNUSED1_BIT	11
 
 #define MMUFCR			__SYSREGC(0xc000009c, u32)	/* MMU exception cause */
 #define MMUFCR_IFC		__SYSREGC(0xc000009c, u16)	/* MMU instruction excep cause */
@@ -285,6 +307,47 @@
 #define MMUFCR_xFC_PR_RWK_RWU	0x01c0		/* - R/W kernel and R/W user */
 #define MMUFCR_xFC_ILLADDR	0x0200		/* illegal address excep flag */
 
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+/* atomic operation registers */
+#define AAR		__SYSREG(0xc0000a00, u32)	/* cacheable address */
+#define AAR2		__SYSREG(0xc0000a04, u32)	/* uncacheable address */
+#define ADR		__SYSREG(0xc0000a08, u32)	/* data */
+#define ASR		__SYSREG(0xc0000a0c, u32)	/* status */
+#define AARU		__SYSREG(0xd400aa00, u32)	/* user address */
+#define ADRU		__SYSREG(0xd400aa08, u32)	/* user data */
+#define ASRU		__SYSREG(0xd400aa0c, u32)	/* user status */
+
+#define ASR_RW		0x00000008	/* read */
+#define ASR_BW		0x00000004	/* bus error */
+#define ASR_IW		0x00000002	/* interrupt */
+#define ASR_LW		0x00000001	/* bus lock */
+
+#define ASRU_RW		ASR_RW		/* read */
+#define ASRU_BW		ASR_BW		/* bus error */
+#define ASRU_IW		ASR_IW		/* interrupt */
+#define ASRU_LW		ASR_LW		/* bus lock */
+
+/* in inline ASM, we stick the base pointer in to a reg and use offsets from
+ * it */
+#define ATOMIC_OPS_BASE_ADDR 0xc0000a00
+#ifndef __ASSEMBLY__
+asm(
+	"_AAR	= 0\n"
+	"_AAR2	= 4\n"
+	"_ADR	= 8\n"
+	"_ASR	= 12\n");
+#else
+#define _AAR		0
+#define _AAR2		4
+#define _ADR		8
+#define _ASR		12
+#endif
+
+/* physical page address for userspace atomic operations registers */
+#define USER_ATOMIC_OPS_PAGE_ADDR  0xd400a000
+
+#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_CPU_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/dmactl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/dmactl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/dmactl-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/dmactl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,91 +11,6 @@
 #ifndef _ASM_DMACTL_REGS_H
 #define _ASM_DMACTL_REGS_H
 
-#include <asm/cpu-regs.h>
-
-#ifdef __KERNEL__
-
-/* DMA registers */
-#define	DMxCTR(N)		__SYSREG(0xd2000000 + ((N) * 0x100), u32)	/* control reg */
-#define	DMxCTR_BG		0x0000001f	/* transfer request source */
-#define	DMxCTR_BG_SOFT		0x00000000	/* - software source */
-#define	DMxCTR_BG_SC0TX		0x00000002	/* - serial port 0 transmission */
-#define	DMxCTR_BG_SC0RX		0x00000003	/* - serial port 0 reception */
-#define	DMxCTR_BG_SC1TX		0x00000004	/* - serial port 1 transmission */
-#define	DMxCTR_BG_SC1RX		0x00000005	/* - serial port 1 reception */
-#define	DMxCTR_BG_SC2TX		0x00000006	/* - serial port 2 transmission */
-#define	DMxCTR_BG_SC2RX		0x00000007	/* - serial port 2 reception */
-#define	DMxCTR_BG_TM0UFLOW	0x00000008	/* - timer 0 underflow */
-#define	DMxCTR_BG_TM1UFLOW	0x00000009	/* - timer 1 underflow */
-#define	DMxCTR_BG_TM2UFLOW	0x0000000a	/* - timer 2 underflow */
-#define	DMxCTR_BG_TM3UFLOW	0x0000000b	/* - timer 3 underflow */
-#define	DMxCTR_BG_TM6ACMPCAP	0x0000000c	/* - timer 6A compare/capture */
-#define	DMxCTR_BG_AFE		0x0000000d	/* - analogue front-end interrupt source */
-#define	DMxCTR_BG_ADC		0x0000000e	/* - A/D conversion end interrupt source */
-#define	DMxCTR_BG_IRDA		0x0000000f	/* - IrDA interrupt source */
-#define	DMxCTR_BG_RTC		0x00000010	/* - RTC interrupt source */
-#define	DMxCTR_BG_XIRQ0		0x00000011	/* - XIRQ0 pin interrupt source */
-#define	DMxCTR_BG_XIRQ1		0x00000012	/* - XIRQ1 pin interrupt source */
-#define	DMxCTR_BG_XDMR0		0x00000013	/* - external request 0 source (XDMR0 pin) */
-#define	DMxCTR_BG_XDMR1		0x00000014	/* - external request 1 source (XDMR1 pin) */
-#define	DMxCTR_SAM		0x000000e0	/* DMA transfer src addr mode */
-#define	DMxCTR_SAM_INCR		0x00000000	/* - increment */
-#define	DMxCTR_SAM_DECR		0x00000020	/* - decrement */
-#define	DMxCTR_SAM_FIXED	0x00000040	/* - fixed */
-#define	DMxCTR_DAM		0x00000000	/* DMA transfer dest addr mode */
-#define	DMxCTR_DAM_INCR		0x00000000	/* - increment */
-#define	DMxCTR_DAM_DECR		0x00000100	/* - decrement */
-#define	DMxCTR_DAM_FIXED	0x00000200	/* - fixed */
-#define	DMxCTR_TM		0x00001800	/* DMA transfer mode */
-#define	DMxCTR_TM_BATCH		0x00000000	/* - batch transfer */
-#define	DMxCTR_TM_INTERM	0x00001000	/* - intermittent transfer */
-#define	DMxCTR_UT		0x00006000	/* DMA transfer unit */
-#define	DMxCTR_UT_1		0x00000000	/* - 1 byte */
-#define	DMxCTR_UT_2		0x00002000	/* - 2 byte */
-#define	DMxCTR_UT_4		0x00004000	/* - 4 byte */
-#define	DMxCTR_UT_16		0x00006000	/* - 16 byte */
-#define	DMxCTR_TEN		0x00010000	/* DMA channel transfer enable */
-#define	DMxCTR_RQM		0x00060000	/* external request input source mode */
-#define	DMxCTR_RQM_FALLEDGE	0x00000000	/* - falling edge */
-#define	DMxCTR_RQM_RISEEDGE	0x00020000	/* - rising edge */
-#define	DMxCTR_RQM_LOLEVEL	0x00040000	/* - low level */
-#define	DMxCTR_RQM_HILEVEL	0x00060000	/* - high level */
-#define	DMxCTR_RQF		0x01000000	/* DMA transfer request flag */
-#define	DMxCTR_XEND		0x80000000	/* DMA transfer end flag */
-
-#define	DMxSRC(N)		__SYSREG(0xd2000004 + ((N) * 0x100), u32)	/* control reg */
-
-#define	DMxDST(N)		__SYSREG(0xd2000008 + ((N) * 0x100), u32)	/* src addr reg */
-
-#define	DMxSIZ(N)		__SYSREG(0xd200000c + ((N) * 0x100), u32)	/* dest addr reg */
-#define DMxSIZ_CT		0x000fffff	/* number of bytes to transfer */
-
-#define	DMxCYC(N)		__SYSREG(0xd2000010 + ((N) * 0x100), u32)	/* intermittent
-										 * size reg */
-#define DMxCYC_CYC		0x000000ff	/* number of interrmittent transfers -1 */
-
-#define DM0IRQ			16		/* DMA channel 0 complete IRQ */
-#define DM1IRQ			17		/* DMA channel 1 complete IRQ */
-#define DM2IRQ			18		/* DMA channel 2 complete IRQ */
-#define DM3IRQ			19		/* DMA channel 3 complete IRQ */
-
-#define	DM0ICR			GxICR(DM0IRQ)	/* DMA channel 0 complete intr ctrl reg */
-#define	DM1ICR			GxICR(DM0IR1)	/* DMA channel 1 complete intr ctrl reg */
-#define	DM2ICR			GxICR(DM0IR2)	/* DMA channel 2 complete intr ctrl reg */
-#define	DM3ICR			GxICR(DM0IR3)	/* DMA channel 3 complete intr ctrl reg */
-
-#ifndef __ASSEMBLY__
-
-struct mn10300_dmactl_regs {
-	u32		ctr;
-	const void	*src;
-	void		*dst;
-	u32		siz;
-	u32		cyc;
-} __attribute__((aligned(0x100)));
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
+#include <proc/dmactl-regs.h>
 
 #endif /* _ASM_DMACTL_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/elf.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,12 @@
 #define R_MN10300_ALIGN 	34	/* Alignment requirement. */
 
 /*
+ * AM33/AM34 HW Capabilities
+ */
+#define HWCAP_MN10300_ATOMIC_OP_UNIT	1	/* Has AM34 Atomic Operations */
+
+
+/*
  * ELF register definitions..
  */
 typedef unsigned long elf_greg_t;
@@ -47,8 +53,6 @@
 	u_int32_t	fpcr;
 } elf_fpregset_t;
 
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
 /*
  * This is used to ensure we don't load something for the wrong architecture
  */
@@ -130,7 +134,11 @@
  * instruction set this CPU supports.  This could be done in user space,
  * but it's not easy, and we've already done it here.
  */
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+#define ELF_HWCAP	(HWCAP_MN10300_ATOMIC_OP_UNIT)
+#else
 #define ELF_HWCAP	(0)
+#endif
 
 /*
  * This yields a string that ld.so will use to load implementation
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/exceptions.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/exceptions.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/exceptions.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/exceptions.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,8 +15,8 @@
 
 /*
  * define the breakpoint instruction opcode to use
- * - note that the JTAG unit steals 0xFF, so we want to avoid that if we can
- *   (can use 0xF7)
+ * - note that the JTAG unit steals 0xFF, so you can't use JTAG and GDBSTUB at
+ *   the same time.
  */
 #define GDBSTUB_BKPT		0xFF
 
@@ -90,7 +90,6 @@
 
 extern void __set_intr_stub(enum exception_code code, void *handler);
 extern void set_intr_stub(enum exception_code code, void *handler);
-extern void set_jtag_stub(enum exception_code code, void *handler);
 
 struct pt_regs;
 
@@ -102,7 +101,6 @@
 extern asmlinkage void raw_bus_error(void);
 extern asmlinkage void double_fault(void);
 extern asmlinkage int  system_call(struct pt_regs *);
-extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
 extern asmlinkage void nmi(struct pt_regs *, enum exception_code);
 extern asmlinkage void uninitialised_exception(struct pt_regs *,
 					       enum exception_code);
@@ -116,6 +114,8 @@
 
 extern int die_if_no_fixup(const char *, struct pt_regs *, enum exception_code);
 
+#define NUM2EXCEP_IRQ_LEVEL(num)	(EXCEP_IRQ_LEVEL0 + (num) * 8)
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_EXCEPTIONS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/fpu.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/fpu.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/fpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/fpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,74 +12,125 @@
 #ifndef _ASM_FPU_H
 #define _ASM_FPU_H
 
-#include <asm/processor.h>
+#ifndef __ASSEMBLY__
+
+#include <linux/sched.h>
+#include <asm/exceptions.h>
 #include <asm/sigcontext.h>
-#include <asm/user.h>
 
 #ifdef __KERNEL__
 
-/* the task that owns the FPU state */
-extern struct task_struct *fpu_state_owner;
+extern asmlinkage void fpu_disabled(void);
 
-#define set_using_fpu(tsk)				\
-do {							\
-	(tsk)->thread.fpu_flags |= THREAD_USING_FPU;	\
-} while (0)
+#ifdef CONFIG_FPU
 
-#define clear_using_fpu(tsk)				\
-do {							\
-	(tsk)->thread.fpu_flags &= ~THREAD_USING_FPU;	\
-} while (0)
+#ifdef CONFIG_LAZY_SAVE_FPU
+/* the task that currently owns the FPU state */
+extern struct task_struct *fpu_state_owner;
+#endif
 
-#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU)
+#if (THREAD_USING_FPU & ~0xff)
+#error THREAD_USING_FPU must be smaller than 0x100.
+#endif
 
-#define unlazy_fpu(tsk)					\
-do {							\
-	preempt_disable();				\
-	if (fpu_state_owner == (tsk))			\
-		fpu_save(&tsk->thread.fpu_state);	\
-	preempt_enable();				\
-} while (0)
+static inline void set_using_fpu(struct task_struct *tsk)
+{
+	asm volatile(
+		"bset %0,(0,%1)"
+		:
+		: "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags)
+		: "memory", "cc");
+}
 
-#define exit_fpu()				\
-do {						\
-	struct task_struct *__tsk = current;	\
-	preempt_disable();			\
-	if (fpu_state_owner == __tsk)		\
-		fpu_state_owner = NULL;		\
-	preempt_enable();			\
-} while (0)
+static inline void clear_using_fpu(struct task_struct *tsk)
+{
+	asm volatile(
+		"bclr %0,(0,%1)"
+		:
+		: "i"(THREAD_USING_FPU), "a"(&tsk->thread.fpu_flags)
+		: "memory", "cc");
+}
 
-#define flush_fpu()					\
-do {							\
-	struct task_struct *__tsk = current;		\
-	preempt_disable();				\
-	if (fpu_state_owner == __tsk) {			\
-		fpu_state_owner = NULL;			\
-		__tsk->thread.uregs->epsw &= ~EPSW_FE;	\
-	}						\
-	preempt_enable();				\
-	clear_using_fpu(__tsk);				\
-} while (0)
+#define is_using_fpu(tsk) ((tsk)->thread.fpu_flags & THREAD_USING_FPU)
 
-extern asmlinkage void fpu_init_state(void);
 extern asmlinkage void fpu_kill_state(struct task_struct *);
-extern asmlinkage void fpu_disabled(struct pt_regs *, enum exception_code);
 extern asmlinkage void fpu_exception(struct pt_regs *, enum exception_code);
-
-#ifdef CONFIG_FPU
+extern asmlinkage void fpu_invalid_op(struct pt_regs *, enum exception_code);
+extern asmlinkage void fpu_init_state(void);
 extern asmlinkage void fpu_save(struct fpu_state_struct *);
-extern asmlinkage void fpu_restore(struct fpu_state_struct *);
-#else
-#define fpu_save(a)
-#define fpu_restore(a)
-#endif /* CONFIG_FPU  */
-
-/*
- * signal frame handlers
- */
 extern int fpu_setup_sigcontext(struct fpucontext *buf);
 extern int fpu_restore_sigcontext(struct fpucontext *buf);
 
+static inline void unlazy_fpu(struct task_struct *tsk)
+{
+	preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+	if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+		fpu_save(&tsk->thread.fpu_state);
+		tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+		tsk->thread.uregs->epsw &= ~EPSW_FE;
+	}
+#else
+	if (fpu_state_owner == tsk)
+		fpu_save(&tsk->thread.fpu_state);
+#endif
+	preempt_enable();
+}
+
+static inline void exit_fpu(void)
+{
+#ifdef CONFIG_LAZY_SAVE_FPU
+	struct task_struct *tsk = current;
+
+	preempt_disable();
+	if (fpu_state_owner == tsk)
+		fpu_state_owner = NULL;
+	preempt_enable();
+#endif
+}
+
+static inline void flush_fpu(void)
+{
+	struct task_struct *tsk = current;
+
+	preempt_disable();
+#ifndef CONFIG_LAZY_SAVE_FPU
+	if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+		tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+		tsk->thread.uregs->epsw &= ~EPSW_FE;
+	}
+#else
+	if (fpu_state_owner == tsk) {
+		fpu_state_owner = NULL;
+		tsk->thread.uregs->epsw &= ~EPSW_FE;
+	}
+#endif
+	preempt_enable();
+	clear_using_fpu(tsk);
+}
+
+#else /* CONFIG_FPU */
+
+extern asmlinkage
+void unexpected_fpu_exception(struct pt_regs *, enum exception_code);
+#define fpu_invalid_op unexpected_fpu_exception
+#define fpu_exception unexpected_fpu_exception
+
+struct task_struct;
+struct fpu_state_struct;
+static inline bool is_using_fpu(struct task_struct *tsk) { return false; }
+static inline void set_using_fpu(struct task_struct *tsk) {}
+static inline void clear_using_fpu(struct task_struct *tsk) {}
+static inline void fpu_init_state(void) {}
+static inline void fpu_save(struct fpu_state_struct *s) {}
+static inline void fpu_kill_state(struct task_struct *tsk) {}
+static inline void unlazy_fpu(struct task_struct *tsk) {}
+static inline void exit_fpu(void) {}
+static inline void flush_fpu(void) {}
+static inline int fpu_setup_sigcontext(struct fpucontext *buf) { return 0; }
+static inline int fpu_restore_sigcontext(struct fpucontext *buf) { return 0; }
+#endif /* CONFIG_FPU  */
+
 #endif /* __KERNEL__ */
+#endif /* !__ASSEMBLY__ */
 #endif /* _ASM_FPU_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/frame.inc linux-libre-2.6.37-gnu/arch/mn10300/include/asm/frame.inc
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/frame.inc	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/frame.inc	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #ifndef __ASM_OFFSETS_H__
 #include <asm/asm-offsets.h>
 #endif
+#include <asm/thread_info.h>
 
 #define pi break
 
@@ -37,11 +38,15 @@
 	movm	[d2,d3,a2,a3,exreg0,exreg1,exother],(sp)
 	mov	sp,fp				# FRAME pointer in A3
 	add	-12,sp				# allow for calls to be made
-	mov	(__frame),a1
-	mov	a1,(REG_NEXT,fp)
-	mov	fp,(__frame)
 
-	and	~EPSW_FE,epsw			# disable the FPU inside the kernel
+	# push the exception frame onto the front of the list
+	GET_THREAD_INFO a1
+	mov	(TI_frame,a1),a0
+	mov	a0,(REG_NEXT,fp)
+	mov	fp,(TI_frame,a1)
+
+	# disable the FPU inside the kernel
+	and	~EPSW_FE,epsw
 
 	# we may be holding current in E2
 #ifdef CONFIG_MN10300_CURRENT_IN_E2
@@ -57,10 +62,11 @@
 .macro RESTORE_ALL
 	# peel back the stack to the calling frame
 	# - this permits execve() to discard extra frames due to kernel syscalls
-	mov	(__frame),fp
+	GET_THREAD_INFO a0
+	mov	(TI_frame,a0),fp
 	mov	fp,sp
-	mov	(REG_NEXT,fp),d0                # userspace has regs->next == 0
-	mov	d0,(__frame)
+	mov	(REG_NEXT,fp),d0
+	mov	d0,(TI_frame,a0)                # userspace has regs->next == 0
 
 #ifndef CONFIG_MN10300_USING_JTAG
 	mov	(REG_EPSW,fp),d0
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/gdb-stub.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/gdb-stub.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/gdb-stub.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/gdb-stub.h	2011-01-04 19:50:19.000000000 -0500
@@ -110,7 +110,7 @@
 extern asmlinkage void __gdbstub_bug_trap(void);
 extern asmlinkage void __gdbstub_pause(void);
 
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
 extern asmlinkage void gdbstub_purge_cache(void);
 #else
 #define gdbstub_purge_cache()	do {} while (0)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/hardirq.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/hardirq.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/hardirq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/hardirq.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,9 +19,10 @@
 /* assembly code in softirq.h is sensitive to the offsets of these fields */
 typedef struct {
 	unsigned int	__softirq_pending;
-	unsigned long	idle_timestamp;
+#ifdef CONFIG_MN10300_WD_TIMER
 	unsigned int	__nmi_count;	/* arch dependent */
 	unsigned int	__irq_count;	/* arch dependent */
+#endif
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -70,15 +70,16 @@
  * be used in IRQ contexts, so in some (very limited) cases we need
  * it.
  */
-static inline unsigned long kmap_atomic(struct page *page, enum km_type type)
+static inline unsigned long __kmap_atomic(struct page *page)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 
+	pagefault_disable();
 	if (page < highmem_start_page)
 		return page_address(page);
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #if HIGHMEM_DEBUG
@@ -86,31 +87,42 @@
 		BUG();
 #endif
 	set_pte(kmap_pte - idx, mk_pte(page, kmap_prot));
-	__flush_tlb_one(vaddr);
+	local_flush_tlb_one(vaddr);
 
 	return vaddr;
 }
 
-static inline void kunmap_atomic_notypecheck(unsigned long vaddr, enum km_type type)
+static inline void __kunmap_atomic(unsigned long vaddr)
 {
-#if HIGHMEM_DEBUG
-	enum fixed_addresses idx = type + KM_TYPE_NR * smp_processor_id();
+	int type;
 
-	if (vaddr < FIXADDR_START) /* FIXME */
+	if (vaddr < FIXADDR_START) { /* FIXME */
+		pagefault_enable();
 		return;
+	}
 
-	if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
-		BUG();
+	type = kmap_atomic_idx();
 
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(kmap_pte - idx);
-	__flush_tlb_one(vaddr);
+#if HIGHMEM_DEBUG
+	{
+		unsigned int idx;
+		idx = type + KM_TYPE_NR * smp_processor_id();
+
+		if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx))
+			BUG();
+
+		/*
+		 * force other mappings to Oops if they'll try to access
+		 * this pte without first remap it
+		 */
+		pte_clear(kmap_pte - idx);
+		local_flush_tlb_one(vaddr);
+	}
 #endif
-}
 
+	kmap_atomic_idx_pop();
+	pagefault_enable();
+}
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_HIGHMEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/intctl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/intctl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/intctl-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/intctl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,24 +15,19 @@
 
 #ifdef __KERNEL__
 
-/* interrupt controller registers */
-#define GxICR(X)		__SYSREG(0xd4000000 + (X) * 4, u16)	/* group irq ctrl regs */
-
-#define IAGR			__SYSREG(0xd4000100, u16)	/* intr acceptance group reg */
-#define IAGR_GN			0x00fc		/* group number register
-						 * (documentation _has_ to be wrong)
-						 */
+/*
+ * Interrupt controller registers
+ * - Registers 64-191 are at addresses offset from the main array
+ */
+#define GxICR(X)						\
+	__SYSREG(0xd4000000 + (X) * 4 +				\
+		 (((X) >= 64) && ((X) < 192)) * 0xf00, u16)
 
-#define EXTMD			__SYSREG(0xd4000200, u16)	/* external pin intr spec reg */
-#define GET_XIRQ_TRIGGER(X) ((EXTMD >> ((X) * 2)) & 3)
+#define GxICR_u8(X)							\
+	__SYSREG(0xd4000000 + (X) * 4 +					\
+		 (((X) >= 64) && ((X) < 192)) * 0xf00, u8)
 
-#define SET_XIRQ_TRIGGER(X,Y)			\
-do {						\
-	u16 x = EXTMD;				\
-	x &= ~(3 << ((X) * 2));			\
-	x |= ((Y) & 3) << ((X) * 2);		\
-	EXTMD = x;				\
-} while (0)
+#include <proc/intctl-regs.h>
 
 #define XIRQ_TRIGGER_LOWLEVEL	0
 #define XIRQ_TRIGGER_HILEVEL	1
@@ -59,10 +54,18 @@
 #define GxICR_LEVEL_5		0x5000		/* - level 5 */
 #define GxICR_LEVEL_6		0x6000		/* - level 6 */
 #define GxICR_LEVEL_SHIFT	12
+#define GxICR_NMI		0x8000		/* nmi request flag */
+
+#define NUM2GxICR_LEVEL(num)	((num) << GxICR_LEVEL_SHIFT)
 
 #ifndef __ASSEMBLY__
 extern void set_intr_level(int irq, u16 level);
-extern void set_intr_postackable(int irq);
+extern void mn10300_intc_set_level(unsigned int irq, unsigned int level);
+extern void mn10300_intc_clear(unsigned int irq);
+extern void mn10300_intc_set(unsigned int irq);
+extern void mn10300_intc_enable(unsigned int irq);
+extern void mn10300_intc_disable(unsigned int irq);
+extern void mn10300_set_lateack_irq_type(int irq);
 #endif
 
 /* external interrupts */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,88 +1,6 @@
 #ifndef _ASM_IOCTLS_H
 #define _ASM_IOCTLS_H
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-/* #define TIOCTTYGSTRUCT 0x5426 - Former debugging-only ioctl */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T', 0x2A, struct termios2)
-#define TCSETS2		_IOW('T', 0x2B, struct termios2)
-#define TCSETSW2	_IOW('T', 0x2C, struct termios2)
-#define TCSETSF2	_IOW('T', 0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T', 0x30, unsigned int) /* Get Pty Number
-						       * (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T', 0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T', 0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
-#define FIOQSIZE	0x5460
-
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif /* _ASM_IOCTLS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/io.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -206,6 +206,19 @@
 #define iowrite32_rep(p, src, count) \
 	outsl((unsigned long) (p), (src), (count))
 
+#define readsb(p, dst, count) \
+	insb((unsigned long) (p), (dst), (count))
+#define readsw(p, dst, count) \
+	insw((unsigned long) (p), (dst), (count))
+#define readsl(p, dst, count) \
+	insl((unsigned long) (p), (dst), (count))
+
+#define writesb(p, src, count) \
+	outsb((unsigned long) (p), (src), (count))
+#define writesw(p, src, count) \
+	outsw((unsigned long) (p), (src), (count))
+#define writesl(p, src, count) \
+	outsl((unsigned long) (p), (src), (count))
 
 #define IO_SPACE_LIMIT 0xffffffff
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,216 @@
+/* MN10300 IRQ flag handling
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#include <asm/cpu-regs.h>
+#ifndef __ASSEMBLY__
+#include <linux/smp.h>
+#endif
+
+/*
+ * interrupt control
+ * - "disabled": run in IM1/2
+ *   - level 0 - GDB stub
+ *   - level 1 - virtual serial DMA (if present)
+ *   - level 5 - normal interrupt priority
+ *   - level 6 - timer interrupt
+ * - "enabled":  run in IM7
+ */
+#define MN10300_CLI_LEVEL	(CONFIG_LINUX_CLI_LEVEL << EPSW_IM_SHIFT)
+
+#ifndef __ASSEMBLY__
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+
+	asm volatile("mov epsw,%0" : "=d"(flags));
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile(
+		"	and %0,epsw	\n"
+		"	or %1,epsw	\n"
+		"	nop		\n"
+		"	nop		\n"
+		"	nop		\n"
+		:
+		: "i"(~EPSW_IM), "i"(EPSW_IE | MN10300_CLI_LEVEL)
+		: "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+
+	flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+/*
+ * we make sure arch_irq_enable() doesn't cause priority inversion
+ */
+extern unsigned long __mn10300_irq_enabled_epsw[];
+
+static inline void arch_local_irq_enable(void)
+{
+	unsigned long tmp;
+	int cpu = raw_smp_processor_id();
+
+	asm volatile(
+		"	mov	epsw,%0		\n"
+		"	and	%1,%0		\n"
+		"	or	%2,%0		\n"
+		"	mov	%0,epsw		\n"
+		: "=&d"(tmp)
+		: "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw[cpu])
+		: "memory", "cc");
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile(
+		"	mov %0,epsw	\n"
+		"	nop		\n"
+		"	nop		\n"
+		"	nop		\n"
+		:
+		: "d"(flags)
+		: "memory", "cc");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & (EPSW_IE | EPSW_IM)) != (EPSW_IE | EPSW_IM_7);
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+/*
+ * Hook to save power by halting the CPU
+ * - called from the idle loop
+ * - must reenable interrupts (which takes three instruction cycles to complete)
+ */
+static inline void arch_safe_halt(void)
+{
+#ifdef CONFIG_SMP
+	arch_local_irq_enable();
+#else
+	asm volatile(
+		"	or	%0,epsw	\n"
+		"	nop		\n"
+		"	nop		\n"
+		"	bset	%2,(%1)	\n"
+		:
+		: "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)
+		: "cc");
+#endif
+}
+
+#define __sleep_cpu()				\
+do {						\
+	asm volatile(				\
+		"	bset	%1,(%0)\n"	\
+		"1:	btst	%1,(%0)\n"	\
+		"	bne	1b\n"		\
+		:				\
+		: "i"(&CPUM), "i"(CPUM_SLEEP)	\
+		: "cc"				\
+		);				\
+} while (0)
+
+static inline void arch_local_cli(void)
+{
+	asm volatile(
+		"	and	%0,epsw		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		:
+		: "i"(~EPSW_IE)
+		: "memory"
+		);
+}
+
+static inline unsigned long arch_local_cli_save(void)
+{
+	unsigned long flags = arch_local_save_flags();
+	arch_local_cli();
+	return flags;
+}
+
+static inline void arch_local_sti(void)
+{
+	asm volatile(
+		"	or	%0,epsw		\n"
+		:
+		: "i"(EPSW_IE)
+		: "memory");
+}
+
+static inline void arch_local_change_intr_mask_level(unsigned long level)
+{
+	asm volatile(
+		"	and	%0,epsw		\n"
+		"	or	%1,epsw		\n"
+		:
+		: "i"(~EPSW_IM), "i"(EPSW_IE | level)
+		: "cc", "memory");
+}
+
+#else /* !__ASSEMBLY__ */
+
+#define LOCAL_SAVE_FLAGS(reg)			\
+	mov	epsw,reg
+
+#define LOCAL_IRQ_DISABLE				\
+	and	~EPSW_IM,epsw;				\
+	or	EPSW_IE|MN10300_CLI_LEVEL,epsw;		\
+	nop;						\
+	nop;						\
+	nop
+
+#define LOCAL_IRQ_ENABLE		\
+	or	EPSW_IE|EPSW_IM_7,epsw
+
+#define LOCAL_IRQ_RESTORE(reg)	\
+	mov	reg,epsw
+
+#define LOCAL_CLI_SAVE(reg)	\
+	mov	epsw,reg;	\
+	and	~EPSW_IE,epsw;	\
+	nop;			\
+	nop;			\
+	nop
+
+#define LOCAL_CLI		\
+	and	~EPSW_IE,epsw;	\
+	nop;			\
+	nop;			\
+	nop
+
+#define LOCAL_STI		\
+	or	EPSW_IE,epsw
+
+#define LOCAL_CHANGE_INTR_MASK_LEVEL(level)	\
+	and	~EPSW_IM,epsw;			\
+	or	EPSW_IE|(level),epsw
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irq.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irq.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,16 @@
 /* this number is used when no interrupt has been assigned */
 #define NO_IRQ		INT_MAX
 
-/* hardware irq numbers */
-#define NR_IRQS		GxICR_NUM_IRQS
+/*
+ * hardware irq numbers
+ * - the ASB2364 has an FPGA with an IRQ multiplexer on it
+ */
+#ifdef CONFIG_MN10300_UNIT_ASB2364
+#include <unit/irq.h>
+#else
+#define NR_CPU_IRQS	GxICR_NUM_IRQS
+#define NR_IRQS		NR_CPU_IRQS
+#endif
 
 /* external hardware irq numbers */
 #define NR_XIRQS	GxICR_NUM_XIRQS
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irq_regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irq_regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/irq_regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/irq_regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,11 @@
 #define ARCH_HAS_OWN_IRQ_REGS
 
 #ifndef __ASSEMBLY__
-#define get_irq_regs() (__frame)
+static inline __attribute__((const))
+struct pt_regs *get_irq_regs(void)
+{
+	return current_frame();
+}
 #endif
 
 #endif /* _ASM_IRQ_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/mmu_context.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/mmu_context.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/mmu_context.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/mmu_context.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,28 +27,38 @@
 #include <asm/tlbflush.h>
 #include <asm-generic/mm_hooks.h>
 
+#define MMU_CONTEXT_TLBPID_NR		256
 #define MMU_CONTEXT_TLBPID_MASK		0x000000ffUL
 #define MMU_CONTEXT_VERSION_MASK	0xffffff00UL
 #define MMU_CONTEXT_FIRST_VERSION	0x00000100UL
 #define MMU_NO_CONTEXT			0x00000000UL
-
-extern unsigned long mmu_context_cache[NR_CPUS];
-#define mm_context(mm)	(mm->context.tlbpid[smp_processor_id()])
+#define MMU_CONTEXT_TLBPID_LOCK_NR	0
 
 #define enter_lazy_tlb(mm, tsk)	do {} while (0)
 
+static inline void cpu_ran_vm(int cpu, struct mm_struct *mm)
+{
 #ifdef CONFIG_SMP
-#define cpu_ran_vm(cpu, mm) \
-	cpumask_set_cpu((cpu), mm_cpumask(mm))
-#define cpu_maybe_ran_vm(cpu, mm) \
-	cpumask_test_and_set_cpu((cpu), mm_cpumask(mm))
+	cpumask_set_cpu(cpu, mm_cpumask(mm));
+#endif
+}
+
+static inline bool cpu_maybe_ran_vm(int cpu, struct mm_struct *mm)
+{
+#ifdef CONFIG_SMP
+	return cpumask_test_and_set_cpu(cpu, mm_cpumask(mm));
 #else
-#define cpu_ran_vm(cpu, mm)		do {} while (0)
-#define cpu_maybe_ran_vm(cpu, mm)	true
-#endif /* CONFIG_SMP */
+	return true;
+#endif
+}
 
-/*
- * allocate an MMU context
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+extern unsigned long mmu_context_cache[NR_CPUS];
+#define mm_context(mm)	(mm->context.tlbpid[smp_processor_id()])
+
+/**
+ * allocate_mmu_context - Allocate storage for the arch-specific MMU data
+ * @mm: The userspace VM context being set up
  */
 static inline unsigned long allocate_mmu_context(struct mm_struct *mm)
 {
@@ -58,7 +68,7 @@
 	if (!(mc & MMU_CONTEXT_TLBPID_MASK)) {
 		/* we exhausted the TLB PIDs of this version on this CPU, so we
 		 * flush this CPU's TLB in its entirety and start new cycle */
-		flush_tlb_all();
+		local_flush_tlb_all();
 
 		/* fix the TLB version if needed (we avoid version #0 so as to
 		 * distingush MMU_NO_CONTEXT) */
@@ -101,22 +111,34 @@
 }
 
 /*
- * destroy context related info for an mm_struct that is about to be put to
- * rest
- */
-#define destroy_context(mm)	do { } while (0)
-
-/*
  * after we have set current->mm to a new value, this activates the context for
  * the new mm so we see the new mappings.
  */
-static inline void activate_context(struct mm_struct *mm, int cpu)
+static inline void activate_context(struct mm_struct *mm)
 {
 	PIDR = get_mmu_context(mm) & MMU_CONTEXT_TLBPID_MASK;
 }
+#else  /* CONFIG_MN10300_TLB_USE_PIDR */
 
-/*
- * change between virtual memory sets
+#define init_new_context(tsk, mm)	(0)
+#define activate_context(mm)		local_flush_tlb()
+
+#endif /* CONFIG_MN10300_TLB_USE_PIDR */
+
+/**
+ * destroy_context - Destroy mm context information
+ * @mm: The MM being destroyed.
+ *
+ * Destroy context related info for an mm_struct that is about to be put to
+ * rest
+ */
+#define destroy_context(mm)	do {} while (0)
+
+/**
+ * switch_mm - Change between userspace virtual memory contexts
+ * @prev: The outgoing MM context.
+ * @next: The incoming MM context.
+ * @tsk: The incoming task.
  */
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 			     struct task_struct *tsk)
@@ -124,11 +146,12 @@
 	int cpu = smp_processor_id();
 
 	if (prev != next) {
+#ifdef CONFIG_SMP
+		per_cpu(cpu_tlbstate, cpu).active_mm = next;
+#endif
 		cpu_ran_vm(cpu, next);
-		activate_context(next, cpu);
 		PTBR = (unsigned long) next->pgd;
-	} else if (!cpu_maybe_ran_vm(cpu, next)) {
-		activate_context(next, cpu);
+		activate_context(next);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/pgalloc.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/pgalloc.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/pgalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/pgalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,6 @@
 #ifndef _ASM_PGALLOC_H
 #define _ASM_PGALLOC_H
 
-#include <asm/processor.h>
 #include <asm/page.h>
 #include <linux/threads.h>
 #include <linux/mm.h>		/* for struct page */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -90,46 +90,58 @@
  * The vmalloc() routines also leaves a hole of 4kB between each vmalloced
  * area to catch addressing errors.
  */
+#ifndef __ASSEMBLY__
+#define VMALLOC_OFFSET	(8UL * 1024 * 1024)
+#define VMALLOC_START	(0x70000000UL)
+#define VMALLOC_END	(0x7C000000UL)
+#else
 #define VMALLOC_OFFSET	(8 * 1024 * 1024)
 #define VMALLOC_START	(0x70000000)
 #define VMALLOC_END	(0x7C000000)
+#endif
 
 #ifndef __ASSEMBLY__
 extern pte_t kernel_vmalloc_ptes[(VMALLOC_END - VMALLOC_START) / PAGE_SIZE];
 #endif
 
-/* IPTEL/DPTEL bit assignments */
-#define _PAGE_BIT_VALID		xPTEL_V_BIT
-#define _PAGE_BIT_ACCESSED	xPTEL_UNUSED1_BIT	/* mustn't be loaded into IPTEL/DPTEL */
-#define _PAGE_BIT_NX		xPTEL_UNUSED2_BIT	/* mustn't be loaded into IPTEL/DPTEL */
-#define _PAGE_BIT_CACHE		xPTEL_C_BIT
-#define _PAGE_BIT_PRESENT	xPTEL_PV_BIT
-#define _PAGE_BIT_DIRTY		xPTEL_D_BIT
-#define _PAGE_BIT_GLOBAL	xPTEL_G_BIT
+/* IPTEL2/DPTEL2 bit assignments */
+#define _PAGE_BIT_VALID		xPTEL2_V_BIT
+#define _PAGE_BIT_CACHE		xPTEL2_C_BIT
+#define _PAGE_BIT_PRESENT	xPTEL2_PV_BIT
+#define _PAGE_BIT_DIRTY		xPTEL2_D_BIT
+#define _PAGE_BIT_GLOBAL	xPTEL2_G_BIT
+#define _PAGE_BIT_ACCESSED	xPTEL2_UNUSED1_BIT	/* mustn't be loaded into IPTEL2/DPTEL2 */
 
-#define _PAGE_VALID		xPTEL_V
-#define _PAGE_ACCESSED		xPTEL_UNUSED1
-#define _PAGE_NX		xPTEL_UNUSED2		/* no-execute bit */
-#define _PAGE_CACHE		xPTEL_C
-#define _PAGE_PRESENT		xPTEL_PV
-#define _PAGE_DIRTY		xPTEL_D
-#define _PAGE_PROT		xPTEL_PR
-#define _PAGE_PROT_RKNU		xPTEL_PR_ROK
-#define _PAGE_PROT_WKNU		xPTEL_PR_RWK
-#define _PAGE_PROT_RKRU		xPTEL_PR_ROK_ROU
-#define _PAGE_PROT_WKRU		xPTEL_PR_RWK_ROU
-#define _PAGE_PROT_WKWU		xPTEL_PR_RWK_RWU
-#define _PAGE_GLOBAL		xPTEL_G
-#define _PAGE_PSE		xPTEL_PS_4Mb		/* 4MB page */
+#define _PAGE_VALID		xPTEL2_V
+#define _PAGE_CACHE		xPTEL2_C
+#define _PAGE_PRESENT		xPTEL2_PV
+#define _PAGE_DIRTY		xPTEL2_D
+#define _PAGE_PROT		xPTEL2_PR
+#define _PAGE_PROT_RKNU		xPTEL2_PR_ROK
+#define _PAGE_PROT_WKNU		xPTEL2_PR_RWK
+#define _PAGE_PROT_RKRU		xPTEL2_PR_ROK_ROU
+#define _PAGE_PROT_WKRU		xPTEL2_PR_RWK_ROU
+#define _PAGE_PROT_WKWU		xPTEL2_PR_RWK_RWU
+#define _PAGE_GLOBAL		xPTEL2_G
+#define _PAGE_PS_MASK		xPTEL2_PS
+#define _PAGE_PS_4Kb		xPTEL2_PS_4Kb
+#define _PAGE_PS_128Kb		xPTEL2_PS_128Kb
+#define _PAGE_PS_1Kb		xPTEL2_PS_1Kb
+#define _PAGE_PS_4Mb		xPTEL2_PS_4Mb
+#define _PAGE_PSE		xPTEL2_PS_4Mb		/* 4MB page */
+#define _PAGE_CACHE_WT		xPTEL2_CWT
+#define _PAGE_ACCESSED		xPTEL2_UNUSED1
+#define _PAGE_NX		0			/* no-execute bit */
 
-#define _PAGE_FILE		xPTEL_UNUSED1_BIT	/* set:pagecache unset:swap */
+/* If _PAGE_VALID is clear, we use these: */
+#define _PAGE_FILE		xPTEL2_C	/* set:pagecache unset:swap */
+#define _PAGE_PROTNONE		0x000		/* If not present */
 
-#define __PAGE_PROT_UWAUX	0x040
-#define __PAGE_PROT_USER	0x080
-#define __PAGE_PROT_WRITE	0x100
+#define __PAGE_PROT_UWAUX	0x010
+#define __PAGE_PROT_USER	0x020
+#define __PAGE_PROT_WRITE	0x040
 
 #define _PAGE_PRESENTV		(_PAGE_PRESENT|_PAGE_VALID)
-#define _PAGE_PROTNONE		0x000	/* If not present */
 
 #ifndef __ASSEMBLY__
 
@@ -170,6 +182,9 @@
 #define PAGE_KERNEL_LARGE	__pgprot(__PAGE_KERNEL_LARGE)
 #define PAGE_KERNEL_LARGE_EXEC	__pgprot(__PAGE_KERNEL_LARGE_EXEC)
 
+#define __PAGE_USERIO		(__PAGE_KERNEL_BASE | _PAGE_PROT_WKWU | _PAGE_NX)
+#define PAGE_USERIO		__pgprot(__PAGE_USERIO)
+
 /*
  * Whilst the MN10300 can do page protection for execute (given separate data
  * and insn TLBs), we are not supporting it at the moment. Write permission,
@@ -323,11 +338,7 @@
 	return 1;
 }
 
-/*
- * Bits 0 and 1 are taken, split up the 29 bits of offset
- * into this range:
- */
-#define PTE_FILE_MAX_BITS	29
+#define PTE_FILE_MAX_BITS	30
 
 #define pte_to_pgoff(pte)	(pte_val(pte) >> 2)
 #define pgoff_to_pte(off)	__pte((off) << 2 | _PAGE_FILE)
@@ -373,8 +384,13 @@
  * Macro to mark a page protection value as "uncacheable".  On processors which
  * do not support it, this is a no-op.
  */
-#define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) | _PAGE_CACHE)
+#define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) & ~_PAGE_CACHE)
 
+/*
+ * Macro to mark a page protection value as "Write-Through".
+ * On processors which do not support it, this is a no-op.
+ */
+#define pgprot_through(prot)	__pgprot(pgprot_val(prot) | _PAGE_CACHE_WT)
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -457,9 +473,7 @@
 
 #define pte_offset_map(dir, address) \
 	((pte_t *) page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte)		do {} while (0)
-#define pte_unmap_nested(pte)	do {} while (0)
 
 /*
  * The MN10300 has external MMU info in the form of a TLB: this is adapted from
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/processor.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,10 +13,13 @@
 #ifndef _ASM_PROCESSOR_H
 #define _ASM_PROCESSOR_H
 
+#include <linux/threads.h>
+#include <linux/thread_info.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/cpu-regs.h>
-#include <linux/threads.h>
+#include <asm/uaccess.h>
+#include <asm/current.h>
 
 /* Forward declaration, a strange C thing */
 struct task_struct;
@@ -33,6 +36,8 @@
 	__pc;					\
 })
 
+extern void get_mem_info(unsigned long *mem_base, unsigned long *mem_size);
+
 extern void show_registers(struct pt_regs *regs);
 
 /*
@@ -43,17 +48,22 @@
 
 struct mn10300_cpuinfo {
 	int		type;
-	unsigned long	loops_per_sec;
+	unsigned long	loops_per_jiffy;
 	char		hard_math;
-	unsigned long	*pgd_quick;
-	unsigned long	*pte_quick;
-	unsigned long	pgtable_cache_sz;
 };
 
 extern struct mn10300_cpuinfo boot_cpu_data;
 
+#ifdef CONFIG_SMP
+#if CONFIG_NR_CPUS < 2 || CONFIG_NR_CPUS > 8
+# error Sorry, NR_CPUS should be 2 to 8
+#endif
+extern struct mn10300_cpuinfo cpu_data[];
+#define current_cpu_data cpu_data[smp_processor_id()]
+#else  /* CONFIG_SMP */
 #define cpu_data &boot_cpu_data
 #define current_cpu_data boot_cpu_data
+#endif /* CONFIG_SMP */
 
 extern void identify_cpu(struct mn10300_cpuinfo *);
 extern void print_cpu_info(struct mn10300_cpuinfo *);
@@ -76,10 +86,6 @@
  */
 #define TASK_UNMAPPED_BASE	0x30000000
 
-typedef struct {
-	unsigned long	seg;
-} mm_segment_t;
-
 struct fpu_state_struct {
 	unsigned long	fs[32];		/* fpu registers */
 	unsigned long	fpcr;		/* fpu control register */
@@ -92,20 +98,19 @@
 	unsigned long		a3;		/* kernel FP */
 	unsigned long		wchan;
 	unsigned long		usp;
-	struct pt_regs		*__frame;
 	unsigned long		fpu_flags;
 #define THREAD_USING_FPU	0x00000001	/* T if this task is using the FPU */
+#define THREAD_HAS_FPU		0x00000002	/* T if this task owns the FPU right now */
 	struct fpu_state_struct	fpu_state;
 };
 
-#define INIT_THREAD				\
-{						\
-	.uregs		= init_uregs,		\
-	.pc		= 0,			\
-	.sp		= 0,			\
-	.a3		= 0,			\
-	.wchan		= 0,			\
-	.__frame	= NULL,			\
+#define INIT_THREAD		\
+{				\
+	.uregs	= init_uregs,	\
+	.pc	= 0,		\
+	.sp	= 0,		\
+	.a3	= 0,		\
+	.wchan	= 0,		\
 }
 
 #define INIT_MMAP \
@@ -117,13 +122,20 @@
  * - need to discard the frame stacked by the kernel thread invoking the execve
  *   syscall (see RESTORE_ALL macro)
  */
-#define start_thread(regs, new_pc, new_sp) do {		\
-	set_fs(USER_DS);				\
-	__frame = current->thread.uregs;		\
-	__frame->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;	\
-	__frame->pc = new_pc;				\
-	__frame->sp = new_sp;				\
-} while (0)
+static inline void start_thread(struct pt_regs *regs,
+				unsigned long new_pc, unsigned long new_sp)
+{
+	struct thread_info *ti = current_thread_info();
+	struct pt_regs *frame0;
+	set_fs(USER_DS);
+
+	frame0 = thread_info_to_uregs(ti);
+	frame0->epsw = EPSW_nSL | EPSW_IE | EPSW_IM;
+	frame0->pc = new_pc;
+	frame0->sp = new_sp;
+	ti->frame = frame0;
+}
+
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
@@ -157,7 +169,7 @@
 
 static inline void prefetch(const void *x)
 {
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
 #ifdef CONFIG_MN10300_PROC_MN103E010
 	asm volatile ("nop; nop; dcpf (%0)" : : "r"(x));
 #else
@@ -168,7 +180,7 @@
 
 static inline void prefetchw(const void *x)
 {
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
 #ifdef CONFIG_MN10300_PROC_MN103E010
 	asm volatile ("nop; nop; dcpf (%0)" : : "r"(x));
 #else
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,6 @@
 #define	PT_PC		26
 #define NR_PTREGS	27
 
-#ifndef __ASSEMBLY__
 /*
  * This defines the way registers are stored in the event of an exception
  * - the strange order is due to the MOVM instruction
@@ -75,7 +74,6 @@
 	unsigned long		epsw;
 	unsigned long		pc;
 };
-#endif
 
 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
 #define PTRACE_GETREGS            12
@@ -86,12 +84,7 @@
 /* options set using PTRACE_SETOPTIONS */
 #define PTRACE_O_TRACESYSGOOD     0x00000001
 
-#if defined(__KERNEL__)
-
-extern struct pt_regs *__frame;		/* current frame pointer */
-
-#if !defined(__ASSEMBLY__)
-struct task_struct;
+#ifdef __KERNEL__
 
 #define user_mode(regs)			(((regs)->epsw & EPSW_nSL) == EPSW_nSL)
 #define instruction_pointer(regs)	((regs)->pc)
@@ -100,9 +93,7 @@
 
 #define arch_has_single_step()	(1)
 
-#endif  /*  !__ASSEMBLY  */
-
 #define profile_pc(regs) ((regs)->pc)
 
-#endif  /*  __KERNEL__  */
+#endif /* __KERNEL__  */
 #endif /* _ASM_PTRACE_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/reset-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/reset-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/reset-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/reset-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,7 +50,7 @@
 	RSTCTR |= RSTCTR_CHIPRST;
 }
 
-extern unsigned int watchdog_alert_counter;
+extern unsigned int watchdog_alert_counter[];
 
 extern void watchdog_go(void);
 extern asmlinkage void watchdog_handler(void);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/rtc.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/rtc.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/rtc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/rtc.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,25 +15,14 @@
 
 #include <linux/init.h>
 
-extern void check_rtc_time(void);
 extern void __init calibrate_clock(void);
-extern unsigned long __init get_initial_rtc_time(void);
 
 #else /* !CONFIG_MN10300_RTC */
 
-static inline void check_rtc_time(void)
-{
-}
-
 static inline void calibrate_clock(void)
 {
 }
 
-static inline unsigned long get_initial_rtc_time(void)
-{
-	return 0;
-}
-
 #endif /* !CONFIG_MN10300_RTC */
 
 #include <asm-generic/rtc.h>
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/rwlock.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/rwlock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/rwlock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/rwlock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,125 @@
+/*
+ * Helpers used by both rw spinlocks and rw semaphores.
+ *
+ * Based in part on code from semaphore.h and
+ * spinlock.h Copyright 1996 Linus Torvalds.
+ *
+ * Copyright 1999 Red Hat, Inc.
+ *
+ * Written by Benjamin LaHaise.
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ * 13-Nov-2006 MEI Temporarily delete lock functions for SMP support.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+#ifndef _ASM_RWLOCK_H
+#define _ASM_RWLOCK_H
+
+#define RW_LOCK_BIAS		 0x01000000
+
+#ifndef CONFIG_SMP
+
+typedef struct { unsigned long a[100]; } __dummy_lock_t;
+#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
+
+#define RW_LOCK_BIAS_STR	"0x01000000"
+
+#define __build_read_lock_ptr(rw, helper)				\
+	do {								\
+		asm volatile(						\
+			"	mov	(%0),d3			\n"	\
+			"	sub	1,d3			\n"	\
+			"	mov	d3,(%0)			\n"	\
+			"	blt	1f			\n"	\
+			"	bra	2f			\n"	\
+			"1:	jmp	3f			\n"	\
+			"2:					\n"	\
+			"	.section .text.lock,\"ax\"	\n"	\
+			"3:	call	"helper"[],0		\n"	\
+			"	jmp	2b			\n"	\
+			"	.previous"				\
+			:						\
+			: "d" (rw)					\
+			: "memory", "d3", "cc");			\
+	} while (0)
+
+#define __build_read_lock_const(rw, helper)				\
+	do {								\
+		asm volatile(						\
+			"	mov	(%0),d3			\n"	\
+			"	sub	1,d3			\n"	\
+			"	mov	d3,(%0)			\n"	\
+			"	blt	1f			\n"	\
+			"	bra	2f			\n"	\
+			"1:	jmp	3f			\n"	\
+			"2:					\n"	\
+			"	.section .text.lock,\"ax\"	\n"	\
+			"3:	call	"helper"[],0		\n"	\
+			"	jmp	2b			\n"	\
+			"	.previous"				\
+			:						\
+			: "d" (rw)					\
+			: "memory", "d3", "cc");			\
+	} while (0)
+
+#define __build_read_lock(rw, helper) \
+	do {								\
+		if (__builtin_constant_p(rw))				\
+			__build_read_lock_const(rw, helper);		\
+		else							\
+			__build_read_lock_ptr(rw, helper);		\
+	} while (0)
+
+#define __build_write_lock_ptr(rw, helper)				\
+	do {								\
+		asm volatile(						\
+			"	mov	(%0),d3			\n"	\
+			"	sub	1,d3			\n"	\
+			"	mov	d3,(%0)			\n"	\
+			"	blt	1f			\n"	\
+			"	bra	2f			\n"	\
+			"1:	jmp	3f			\n"	\
+			"2:					\n"	\
+			"	.section .text.lock,\"ax\"	\n"	\
+			"3:	call	"helper"[],0		\n"	\
+			"	jmp	2b			\n"	\
+			"	.previous"				\
+			:						\
+			: "d" (rw)					\
+			: "memory", "d3", "cc");			\
+	} while (0)
+
+#define __build_write_lock_const(rw, helper)				\
+	do {								\
+		asm volatile(						\
+			"	mov	(%0),d3			\n"	\
+			"	sub	1,d3			\n"	\
+			"	mov	d3,(%0)			\n"	\
+			"	blt	1f			\n"	\
+			"	bra	2f			\n"	\
+			"1:	jmp	3f			\n"	\
+			"2:					\n"	\
+			"	.section .text.lock,\"ax\"	\n"	\
+			"3:	call	"helper"[],0		\n"	\
+			"	jmp	2b			\n"	\
+			"	.previous"				\
+			:						\
+			: "d" (rw)					\
+			: "memory", "d3", "cc");			\
+	} while (0)
+
+#define __build_write_lock(rw, helper)					\
+	do {								\
+		if (__builtin_constant_p(rw))				\
+			__build_write_lock_const(rw, helper);		\
+		else							\
+			__build_write_lock_ptr(rw, helper);		\
+	} while (0)
+
+#endif /* CONFIG_SMP */
+#endif /* _ASM_RWLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/serial.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/serial.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/serial.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,10 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-/*
- * The ASB2305 has an 18.432 MHz clock the UART
- */
-#define BASE_BAUD	(18432000 / 16)
+#ifndef _ASM_SERIAL_H
+#define _ASM_SERIAL_H
 
 /* Standard COM flags (except for COM4, because of the 8514 problem) */
 #ifdef CONFIG_SERIAL_DETECT_IRQ
@@ -34,3 +32,5 @@
 #endif
 
 #include <unit/serial.h>
+
+#endif /* _ASM_SERIAL_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/serial-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/serial-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/serial-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/serial-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,18 +20,25 @@
 /* serial port 0 */
 #define	SC0CTR			__SYSREG(0xd4002000, u16)	/* control reg */
 #define	SC01CTR_CK		0x0007	/* clock source select */
-#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */
-#define	SC1CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow (serial port 1 only) */
 #define	SC01CTR_CK_IOCLK_8	0x0001	/* - 1/8 IOCLK */
 #define	SC01CTR_CK_IOCLK_32	0x0002	/* - 1/32 IOCLK */
+#define	SC01CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */
+#define	SC01CTR_CK_EXTERN	0x0007	/* - external closk */
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */
 #define	SC0CTR_CK_TM2UFLOW_2	0x0003	/* - 1/2 timer 2 underflow (serial port 0 only) */
-#define	SC1CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow (serial port 1 only) */
-#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 1 underflow (serial port 0 only) */
-#define	SC1CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 2 underflow (serial port 1 only) */
+#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 0 underflow (serial port 0 only) */
 #define	SC0CTR_CK_TM2UFLOW_8	0x0005	/* - 1/8 timer 2 underflow (serial port 0 only) */
+#define	SC1CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow (serial port 1 only) */
+#define	SC1CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow (serial port 1 only) */
+#define	SC1CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 1 underflow (serial port 1 only) */
 #define	SC1CTR_CK_TM3UFLOW_8	0x0005	/* - 1/8 timer 3 underflow (serial port 1 only) */
-#define	SC01CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */
-#define	SC01CTR_CK_EXTERN	0x0007	/* - external closk */
+#else  /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+#define	SC0CTR_CK_TM8UFLOW_8	0x0000	/* - 1/8 timer 8 underflow (serial port 0 only) */
+#define	SC0CTR_CK_TM0UFLOW_8	0x0004	/* - 1/8 timer 0 underflow (serial port 0 only) */
+#define	SC0CTR_CK_TM2UFLOW_8	0x0005	/* - 1/8 timer 2 underflow (serial port 0 only) */
+#define	SC1CTR_CK_TM12UFLOW_8	0x0000	/* - 1/8 timer 12 underflow (serial port 1 only) */
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
 #define	SC01CTR_STB		0x0008	/* stop bit select */
 #define	SC01CTR_STB_1BIT	0x0000	/* - 1 stop bit */
 #define	SC01CTR_STB_2BIT	0x0008	/* - 2 stop bits */
@@ -100,11 +107,23 @@
 
 /* serial port 2 */
 #define	SC2CTR			__SYSREG(0xd4002020, u16)	/* control reg */
+#ifdef CONFIG_AM33_2
 #define	SC2CTR_CK		0x0003	/* clock source select */
 #define	SC2CTR_CK_TM10UFLOW	0x0000	/* - timer 10 underflow */
 #define	SC2CTR_CK_TM2UFLOW	0x0001	/* - timer 2 underflow */
 #define	SC2CTR_CK_EXTERN	0x0002	/* - external closk */
 #define	SC2CTR_CK_TM3UFLOW	0x0003	/* - timer 3 underflow */
+#else  /* CONFIG_AM33_2 */
+#define	SC2CTR_CK		0x0007	/* clock source select */
+#define	SC2CTR_CK_TM9UFLOW_8	0x0000	/* - 1/8 timer 9 underflow */
+#define	SC2CTR_CK_IOCLK_8	0x0001	/* - 1/8 IOCLK */
+#define	SC2CTR_CK_IOCLK_32	0x0002	/* - 1/32 IOCLK */
+#define	SC2CTR_CK_TM3UFLOW_2	0x0003	/* - 1/2 timer 3 underflow */
+#define	SC2CTR_CK_TM1UFLOW_8	0x0004	/* - 1/8 timer 1 underflow */
+#define	SC2CTR_CK_TM3UFLOW_8	0x0005	/* - 1/8 timer 3 underflow */
+#define	SC2CTR_CK_EXTERN_8	0x0006	/* - 1/8 external closk */
+#define	SC2CTR_CK_EXTERN	0x0007	/* - external closk */
+#endif /* CONFIG_AM33_2 */
 #define	SC2CTR_STB		0x0008	/* stop bit select */
 #define	SC2CTR_STB_1BIT		0x0000	/* - 1 stop bit */
 #define	SC2CTR_STB_2BIT		0x0008	/* - 2 stop bits */
@@ -134,9 +153,14 @@
 #define SC2ICR_RES		0x04	/* receive error select */
 #define SC2ICR_RI		0x01	/* receive interrupt cause */
 
-#define	SC2TXB			__SYSREG(0xd4002018, u8)	/* transmit buffer reg */
-#define	SC2RXB			__SYSREG(0xd4002019, u8)	/* receive buffer reg */
-#define	SC2STR			__SYSREG(0xd400201c, u8)	/* status reg */
+#define	SC2TXB			__SYSREG(0xd4002028, u8)	/* transmit buffer reg */
+#define	SC2RXB			__SYSREG(0xd4002029, u8)	/* receive buffer reg */
+
+#ifdef CONFIG_AM33_2
+#define	SC2STR			__SYSREG(0xd400202c, u8)	/* status reg */
+#else  /* CONFIG_AM33_2 */
+#define	SC2STR			__SYSREG(0xd400202c, u16)	/* status reg */
+#endif /* CONFIG_AM33_2 */
 #define SC2STR_OEF		0x0001	/* overrun error found */
 #define SC2STR_PEF		0x0002	/* parity error found */
 #define SC2STR_FEF		0x0004	/* framing error found */
@@ -146,10 +170,17 @@
 #define SC2STR_RXF		0x0040	/* receive status */
 #define SC2STR_TXF		0x0080	/* transmit status */
 
+#ifdef CONFIG_AM33_2
 #define	SC2TIM			__SYSREG(0xd400202d, u8)	/* status reg */
+#endif
 
+#ifdef CONFIG_AM33_2
 #define SC2RXIRQ		24	/* serial 2 Receive IRQ */
 #define SC2TXIRQ		25	/* serial 2 Transmit IRQ */
+#else  /* CONFIG_AM33_2 */
+#define SC2RXIRQ		68	/* serial 2 Receive IRQ */
+#define SC2TXIRQ		69	/* serial 2 Transmit IRQ */
+#endif /* CONFIG_AM33_2 */
 
 #define	SC2RXICR		GxICR(SC2RXIRQ)	/* serial 2 receive intr ctrl reg */
 #define	SC2TXICR		GxICR(SC2TXIRQ)	/* serial 2 transmit intr ctrl reg */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/smp.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/smp.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,16 @@
  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ *  13-Nov-2006 MEI Define IPI-IRQ number and add inline/macro function
+ *                  for SMP support.
+ *  22-Jan-2007 MEI Add the define related to SMP_BOOT_IRQ.
+ *  23-Feb-2007 MEI Add the define related to SMP icahce invalidate.
+ *  23-Jun-2008 MEI Delete INTC_IPI.
+ *  22-Jul-2008 MEI Add smp_nmi_call_function and related defines.
+ *  04-Aug-2008 MEI Delete USE_DOIRQ_CACHE_IPI.
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public Licence
  * as published by the Free Software Foundation; either version
@@ -11,8 +21,85 @@
 #ifndef _ASM_SMP_H
 #define _ASM_SMP_H
 
-#ifdef CONFIG_SMP
-#error SMP not yet supported for MN10300
+#ifndef __ASSEMBLY__
+#include <linux/threads.h>
+#include <linux/cpumask.h>
 #endif
 
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+
+#define RESCHEDULE_IPI		63
+#define CALL_FUNC_SINGLE_IPI	192
+#define LOCAL_TIMER_IPI		193
+#define FLUSH_CACHE_IPI		194
+#define CALL_FUNCTION_NMI_IPI	195
+#define GDB_NMI_IPI		196
+
+#define SMP_BOOT_IRQ		195
+
+#define RESCHEDULE_GxICR_LV	GxICR_LEVEL_6
+#define CALL_FUNCTION_GxICR_LV	GxICR_LEVEL_4
+#define LOCAL_TIMER_GxICR_LV	GxICR_LEVEL_4
+#define FLUSH_CACHE_GxICR_LV	GxICR_LEVEL_0
+#define SMP_BOOT_GxICR_LV	GxICR_LEVEL_0
+
+#define TIME_OUT_COUNT_BOOT_IPI	100
+#define DELAY_TIME_BOOT_IPI	75000
+
+
+#ifndef __ASSEMBLY__
+
+/**
+ * raw_smp_processor_id - Determine the raw CPU ID of the CPU running it
+ *
+ * What we really want to do is to use the CPUID hardware CPU register to get
+ * this information, but accesses to that aren't cached, and run at system bus
+ * speed, not CPU speed.  A copy of this value is, however, stored in the
+ * thread_info struct, and that can be cached.
+ *
+ * An alternate way of dealing with this could be to use the EPSW.S bits to
+ * cache this information for systems with up to four CPUs.
+ */
+#if 0
+#define raw_smp_processor_id()	(CPUID)
+#else
+#define raw_smp_processor_id()	(current_thread_info()->cpu)
 #endif
+
+static inline int cpu_logical_map(int cpu)
+{
+	return cpu;
+}
+
+static inline int cpu_number_map(int cpu)
+{
+	return cpu;
+}
+
+
+extern cpumask_t cpu_boot_map;
+
+extern void smp_init_cpus(void);
+extern void smp_cache_interrupt(void);
+extern void send_IPI_allbutself(int irq);
+extern int smp_nmi_call_function(smp_call_func_t func, void *info, int wait);
+
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+#ifdef CONFIG_HOTPLUG_CPU
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#endif /* __ASSEMBLY__ */
+#else /* CONFIG_SMP */
+#ifndef __ASSEMBLY__
+
+static inline void smp_init_cpus(void) {}
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_SMP */
+
+#endif /* _ASM_SMP_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/smsc911x.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/smsc911x.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/smsc911x.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/smsc911x.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+#include <unit/smsc911x.h>
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/spinlock.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/spinlock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/spinlock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/spinlock.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,183 @@
 #ifndef _ASM_SPINLOCK_H
 #define _ASM_SPINLOCK_H
 
-#error SMP spinlocks not implemented for MN10300
+#include <asm/atomic.h>
+#include <asm/rwlock.h>
+#include <asm/page.h>
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0)
+#define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x))
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+	asm volatile(
+		"	bclr	1,(0,%0)	\n"
+		:
+		: "a"(&lock->slock)
+		: "memory", "cc");
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *lock)
+{
+	int ret;
+
+	asm volatile(
+		"	mov	1,%0		\n"
+		"	bset	%0,(%1)		\n"
+		"	bne	1f		\n"
+		"	clr	%0		\n"
+		"1:	xor	1,%0		\n"
+		: "=d"(ret)
+		: "a"(&lock->slock)
+		: "memory", "cc");
+
+	return ret;
+}
+
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+	asm volatile(
+		"1:	bset	1,(0,%0)	\n"
+		"	bne	1b		\n"
+		:
+		: "a"(&lock->slock)
+		: "memory", "cc");
+}
+
+static inline void arch_spin_lock_flags(arch_spinlock_t *lock,
+					 unsigned long flags)
+{
+	int temp;
 
+	asm volatile(
+		"1:	bset	1,(0,%2)	\n"
+		"	beq	3f		\n"
+		"	mov	%1,epsw		\n"
+		"2:	mov	(0,%2),%0	\n"
+		"	or	%0,%0		\n"
+		"	bne	2b		\n"
+		"	mov	%3,%0		\n"
+		"	mov	%0,epsw		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	bra	1b\n"
+		"3:				\n"
+		: "=&d" (temp)
+		: "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL)
+		: "memory", "cc");
+}
+
+#ifdef __KERNEL__
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_read_can_lock(x) ((int)(x)->lock > 0)
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
+
+/*
+ * On mn10300, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ */
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+	__build_read_lock(rw, "__read_lock_failed");
+#else
+	{
+		atomic_t *count = (atomic_t *)rw;
+		while (atomic_dec_return(count) < 0)
+			atomic_inc(count);
+	}
+#endif
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+	__build_write_lock(rw, "__write_lock_failed");
+#else
+	{
+		atomic_t *count = (atomic_t *)rw;
+		while (!atomic_sub_and_test(RW_LOCK_BIAS, count))
+			atomic_add(RW_LOCK_BIAS, count);
+	}
+#endif
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+	__build_read_unlock(rw);
+#else
+	{
+		atomic_t *count = (atomic_t *)rw;
+		atomic_inc(count);
+	}
+#endif
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+#if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+	__build_write_unlock(rw);
+#else
+	{
+		atomic_t *count = (atomic_t *)rw;
+		atomic_add(RW_LOCK_BIAS, count);
+	}
+#endif
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *lock)
+{
+	atomic_t *count = (atomic_t *)lock;
+	atomic_dec(count);
+	if (atomic_read(count) >= 0)
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *lock)
+{
+	atomic_t *count = (atomic_t *)lock;
+	if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+		return 1;
+	atomic_add(RW_LOCK_BIAS, count);
+	return 0;
+}
+
+#define arch_read_lock_flags(lock, flags)  arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#define _raw_spin_relax(lock)	cpu_relax()
+#define _raw_read_relax(lock)	cpu_relax()
+#define _raw_write_relax(lock)	cpu_relax()
+
+#endif /* __KERNEL__ */
 #endif /* _ASM_SPINLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/spinlock_types.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/spinlock_types.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/spinlock_types.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/spinlock_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+#ifndef _ASM_SPINLOCK_TYPES_H
+#define _ASM_SPINLOCK_TYPES_H
+
+#ifndef __LINUX_SPINLOCK_TYPES_H
+# error "please don't include this file directly"
+#endif
+
+typedef struct arch_spinlock {
+	unsigned int slock;
+} arch_spinlock_t;
+
+#define __ARCH_SPIN_LOCK_UNLOCKED	{ 0 }
+
+typedef struct {
+	unsigned int lock;
+} arch_rwlock_t;
+
+#define __ARCH_RW_LOCK_UNLOCKED		{ RW_LOCK_BIAS }
+
+#endif /* _ASM_SPINLOCK_TYPES_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/syscall.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/syscall.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/syscall.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/syscall.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,117 @@
+/* Access to user system call parameters and results
+ *
+ * See asm-generic/syscall.h for function descriptions.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_SYSCALL_H
+#define _ASM_SYSCALL_H
+
+#include <linux/sched.h>
+#include <linux/err.h>
+
+extern const unsigned long sys_call_table[];
+
+static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+	return regs->orig_d0;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+				    struct pt_regs *regs)
+{
+	regs->d0 = regs->orig_d0;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+				     struct pt_regs *regs)
+{
+	unsigned long error = regs->d0;
+	return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+					    struct pt_regs *regs)
+{
+	return regs->d0;
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+					    struct pt_regs *regs,
+					    int error, long val)
+{
+	regs->d0 = (long) error ?: val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 unsigned long *args)
+{
+	switch (i) {
+	case 0:
+		if (!n--) break;
+		*args++ = regs->a0;
+	case 1:
+		if (!n--) break;
+		*args++ = regs->d1;
+	case 2:
+		if (!n--) break;
+		*args++ = regs->a3;
+	case 3:
+		if (!n--) break;
+		*args++ = regs->a2;
+	case 4:
+		if (!n--) break;
+		*args++ = regs->d3;
+	case 5:
+		if (!n--) break;
+		*args++ = regs->d2;
+	case 6:
+		if (!n--) break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+					 struct pt_regs *regs,
+					 unsigned int i, unsigned int n,
+					 const unsigned long *args)
+{
+	switch (i) {
+	case 0:
+		if (!n--) break;
+		regs->a0 = *args++;
+	case 1:
+		if (!n--) break;
+		regs->d1 = *args++;
+	case 2:
+		if (!n--) break;
+		regs->a3 = *args++;
+	case 3:
+		if (!n--) break;
+		regs->a2 = *args++;
+	case 4:
+		if (!n--) break;
+		regs->d3 = *args++;
+	case 5:
+		if (!n--) break;
+		regs->d2 = *args++;
+	case 6:
+		if (!n--) break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+#endif /* _ASM_SYSCALL_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/system.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,11 +12,29 @@
 #define _ASM_SYSTEM_H
 
 #include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
 #include <linux/kernel.h>
+#include <linux/irqflags.h>
+#include <asm/atomic.h>
+
+#if !defined(CONFIG_LAZY_SAVE_FPU)
+struct fpu_state_struct;
+extern asmlinkage void fpu_save(struct fpu_state_struct *);
+#define switch_fpu(prev, next)						\
+	do {								\
+		if ((prev)->thread.fpu_flags & THREAD_HAS_FPU) {	\
+			(prev)->thread.fpu_flags &= ~THREAD_HAS_FPU;	\
+			(prev)->thread.uregs->epsw &= ~EPSW_FE;		\
+			fpu_save(&(prev)->thread.fpu_state);		\
+		}							\
+	} while (0)
+#else
+#define switch_fpu(prev, next) do {} while (0)
+#endif
 
 struct task_struct;
 struct thread_struct;
@@ -29,6 +47,7 @@
 /* context switching is now performed out-of-line in switch_to.S */
 #define switch_to(prev, next, last)					\
 do {									\
+	switch_fpu(prev, next);						\
 	current->thread.wchan = (u_long) __builtin_return_address(0);	\
 	(last) = __switch_to(&(prev)->thread, &(next)->thread, (prev));	\
 	mb();								\
@@ -39,8 +58,6 @@
 
 #define nop() asm volatile ("nop")
 
-#endif /* !__ASSEMBLY__ */
-
 /*
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
@@ -67,172 +84,19 @@
 #define smp_mb()	mb()
 #define smp_rmb()	rmb()
 #define smp_wmb()	wmb()
-#else
+#define set_mb(var, value)  do { xchg(&var, value); } while (0)
+#else  /* CONFIG_SMP */
 #define smp_mb()	barrier()
 #define smp_rmb()	barrier()
 #define smp_wmb()	barrier()
-#endif
-
 #define set_mb(var, value)  do { var = value;  mb(); } while (0)
+#endif /* CONFIG_SMP */
+
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 #define read_barrier_depends()		do {} while (0)
 #define smp_read_barrier_depends()	do {} while (0)
 
-/*****************************************************************************/
-/*
- * interrupt control
- * - "disabled": run in IM1/2
- *   - level 0 - GDB stub
- *   - level 1 - virtual serial DMA (if present)
- *   - level 5 - normal interrupt priority
- *   - level 6 - timer interrupt
- * - "enabled":  run in IM7
- */
-#ifdef CONFIG_MN10300_TTYSM
-#define MN10300_CLI_LEVEL	EPSW_IM_2
-#else
-#define MN10300_CLI_LEVEL	EPSW_IM_1
-#endif
-
-#define local_save_flags(x)			\
-do {						\
-	typecheck(unsigned long, x);		\
-	asm volatile(				\
-		"	mov epsw,%0	\n"	\
-		: "=d"(x)			\
-		);				\
-} while (0)
-
-#define local_irq_disable()						\
-do {									\
-	asm volatile(							\
-		"	and %0,epsw	\n"				\
-		"	or %1,epsw	\n"				\
-		"	nop		\n"				\
-		"	nop		\n"				\
-		"	nop		\n"				\
-		:							\
-		: "i"(~EPSW_IM), "i"(EPSW_IE | MN10300_CLI_LEVEL)	\
-		);							\
-} while (0)
-
-#define local_irq_save(x)			\
-do {						\
-	local_save_flags(x);			\
-	local_irq_disable();			\
-} while (0)
-
-/*
- * we make sure local_irq_enable() doesn't cause priority inversion
- */
-#ifndef __ASSEMBLY__
-
-extern unsigned long __mn10300_irq_enabled_epsw;
-
-#endif
-
-#define local_irq_enable()						\
-do {									\
-	unsigned long tmp;						\
-									\
-	asm volatile(							\
-		"	mov	epsw,%0		\n"			\
-		"	and	%1,%0		\n"			\
-		"	or	%2,%0		\n"			\
-		"	mov	%0,epsw		\n"			\
-		: "=&d"(tmp)						\
-		: "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw)	\
-		: "cc"							\
-		);							\
-} while (0)
-
-#define local_irq_restore(x)			\
-do {						\
-	typecheck(unsigned long, x);		\
-	asm volatile(				\
-		"	mov %0,epsw	\n"	\
-		"	nop		\n"	\
-		"	nop		\n"	\
-		"	nop		\n"	\
-		:				\
-		: "d"(x)			\
-		: "memory", "cc"		\
-		);				\
-} while (0)
-
-#define irqs_disabled()				\
-({						\
-	unsigned long flags;			\
-	local_save_flags(flags);		\
-	(flags & EPSW_IM) <= MN10300_CLI_LEVEL;	\
-})
-
-/* hook to save power by halting the CPU
- * - called from the idle loop
- * - must reenable interrupts (which takes three instruction cycles to complete)
- */
-#define safe_halt()							\
-do {									\
-	asm volatile("	or	%0,epsw	\n"				\
-		     "	nop		\n"				\
-		     "	nop		\n"				\
-		     "	bset	%2,(%1)	\n"				\
-		     :							\
-		     : "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)\
-		     : "cc"						\
-		     );							\
-} while (0)
-
-#define STI	or EPSW_IE|EPSW_IM,epsw
-#define CLI	and ~EPSW_IM,epsw; or EPSW_IE|MN10300_CLI_LEVEL,epsw; nop; nop; nop
-
-/*****************************************************************************/
-/*
- * MN10300 doesn't actually have an exchange instruction
- */
-#ifndef __ASSEMBLY__
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-static inline
-unsigned long __xchg(volatile unsigned long *m, unsigned long val)
-{
-	unsigned long retval;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = *m;
-	*m = val;
-	local_irq_restore(flags);
-	return retval;
-}
-
-#define xchg(ptr, v)						\
-	((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),	\
-				     (unsigned long)(v)))
-
-static inline unsigned long __cmpxchg(volatile unsigned long *m,
-				      unsigned long old, unsigned long new)
-{
-	unsigned long retval;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	retval = *m;
-	if (retval == old)
-		*m = new;
-	local_irq_restore(flags);
-	return retval;
-}
-
-#define cmpxchg(ptr, o, n)					\
-	((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
-					(unsigned long)(o),	\
-					(unsigned long)(n)))
-
 #endif /* !__ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_SYSTEM_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/thread_info.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/thread_info.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/thread_info.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/thread_info.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,10 +16,6 @@
 
 #include <asm/page.h>
 
-#ifndef __ASSEMBLY__
-#include <asm/processor.h>
-#endif
-
 #define PREEMPT_ACTIVE		0x10000000
 
 #ifdef CONFIG_4KSTACKS
@@ -38,10 +34,14 @@
  *   must also be changed
  */
 #ifndef __ASSEMBLY__
+typedef struct {
+	unsigned long	seg;
+} mm_segment_t;
 
 struct thread_info {
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
+	struct pt_regs		*frame;		/* current exception frame */
 	unsigned long		flags;		/* low level flags */
 	__u32			cpu;		/* current CPU */
 	__s32			preempt_count;	/* 0 => preemptable, <0 => BUG */
@@ -55,6 +55,10 @@
 	__u8			supervisor_stack[0];
 };
 
+#define thread_info_to_uregs(ti)					\
+	((struct pt_regs *)						\
+	 ((unsigned long)ti + THREAD_SIZE - sizeof(struct pt_regs)))
+
 #else /* !__ASSEMBLY__ */
 
 #ifndef __ASM_OFFSETS_H__
@@ -102,6 +106,12 @@
 	return ti;
 }
 
+static inline __attribute__((const))
+struct pt_regs *current_frame(void)
+{
+	return current_thread_info()->frame;
+}
+
 /* how to get the current stack pointer from C */
 static inline unsigned long current_stack_pointer(void)
 {
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/timer-regs.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/timer-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/timer-regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/timer-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,21 +17,27 @@
 
 #ifdef __KERNEL__
 
-/* timer prescalar control */
+/*
+ * Timer prescalar control
+ */
 #define	TMPSCNT			__SYSREG(0xd4003071, u8) /* timer prescaler control */
 #define	TMPSCNT_ENABLE		0x80	/* timer prescaler enable */
 #define	TMPSCNT_DISABLE		0x00	/* timer prescaler disable */
 
-/* 8 bit timers */
+/*
+ * 8-bit timers
+ */
 #define	TM0MD			__SYSREG(0xd4003000, u8) /* timer 0 mode register */
 #define	TM0MD_SRC		0x07	/* timer source */
 #define	TM0MD_SRC_IOCLK		0x00	/* - IOCLK */
 #define	TM0MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
 #define	TM0MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
-#define	TM0MD_SRC_TM2IO		0x03	/* - TM2IO pin input */
 #define	TM0MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM0MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if	defined(CONFIG_AM33_2)
+#define	TM0MD_SRC_TM2IO		0x03	/* - TM2IO pin input */
 #define	TM0MD_SRC_TM0IO		0x07	/* - TM0IO pin input */
+#endif /* CONFIG_AM33_2 */
 #define	TM0MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM0MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -43,7 +49,9 @@
 #define	TM1MD_SRC_TM0CASCADE	0x03	/* - cascade with timer 0 */
 #define	TM1MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM1MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM1MD_SRC_TM1IO		0x07	/* - TM1IO pin input */
+#endif	/* CONFIG_AM33_2 */
 #define	TM1MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM1MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -55,7 +63,9 @@
 #define	TM2MD_SRC_TM1CASCADE	0x03	/* - cascade with timer 1 */
 #define	TM2MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM2MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM2MD_SRC_TM2IO		0x07	/* - TM2IO pin input */
+#endif	/* CONFIG_AM33_2 */
 #define	TM2MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM2MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -64,11 +74,13 @@
 #define	TM3MD_SRC_IOCLK		0x00	/* - IOCLK */
 #define	TM3MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
 #define	TM3MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
-#define	TM3MD_SRC_TM1CASCADE	0x03	/* - cascade with timer 2 */
+#define	TM3MD_SRC_TM2CASCADE	0x03	/* - cascade with timer 2 */
 #define	TM3MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM3MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM3MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM3MD_SRC_TM3IO		0x07	/* - TM3IO pin input */
+#endif	/* CONFIG_AM33_2 */
 #define	TM3MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM3MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -96,7 +108,9 @@
 #define	TM2ICR			GxICR(TM2IRQ)	/* timer 2 uflow intr ctrl reg */
 #define	TM3ICR			GxICR(TM3IRQ)	/* timer 3 uflow intr ctrl reg */
 
-/* 16-bit timers 4,5 & 7-11 */
+/*
+ * 16-bit timers 4,5 & 7-15
+ */
 #define	TM4MD			__SYSREG(0xd4003080, u8)   /* timer 4 mode register */
 #define	TM4MD_SRC		0x07	/* timer source */
 #define	TM4MD_SRC_IOCLK		0x00	/* - IOCLK */
@@ -105,7 +119,9 @@
 #define	TM4MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM4MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM4MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM4MD_SRC_TM4IO		0x07	/* - TM4IO pin input */
+#endif	/* CONFIG_AM33_2 */
 #define	TM4MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM4MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -118,7 +134,11 @@
 #define	TM5MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM5MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM5MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM5MD_SRC_TM5IO		0x07	/* - TM5IO pin input */
+#else	/* !CONFIG_AM33_2 */
+#define	TM5MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#endif	/* CONFIG_AM33_2 */
 #define	TM5MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM5MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -130,7 +150,9 @@
 #define	TM7MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM7MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM7MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM7MD_SRC_TM7IO		0x07	/* - TM7IO pin input */
+#endif	/* CONFIG_AM33_2 */
 #define	TM7MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM7MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -143,7 +165,11 @@
 #define	TM8MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM8MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM8MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM8MD_SRC_TM8IO		0x07	/* - TM8IO pin input */
+#else	/* !CONFIG_AM33_2 */
+#define	TM8MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#endif	/* CONFIG_AM33_2 */
 #define	TM8MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM8MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -156,7 +182,11 @@
 #define	TM9MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM9MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM9MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM9MD_SRC_TM9IO		0x07	/* - TM9IO pin input */
+#else	/* !CONFIG_AM33_2 */
+#define	TM9MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#endif	/* CONFIG_AM33_2 */
 #define	TM9MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM9MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -169,7 +199,11 @@
 #define	TM10MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM10MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM10MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM10MD_SRC_TM10IO	0x07	/* - TM10IO pin input */
+#else	/* !CONFIG_AM33_2 */
+#define	TM10MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#endif	/* CONFIG_AM33_2 */
 #define	TM10MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM10MD_COUNT_ENABLE	0x80	/* timer count enable */
 
@@ -178,32 +212,101 @@
 #define	TM11MD_SRC_IOCLK	0x00	/* - IOCLK */
 #define	TM11MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
 #define	TM11MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
-#define	TM11MD_SRC_TM7CASCADE	0x03	/* - cascade with timer 7 */
 #define	TM11MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
 #define	TM11MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
 #define	TM11MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
 #define	TM11MD_SRC_TM11IO	0x07	/* - TM11IO pin input */
+#else	/* !CONFIG_AM33_2 */
+#define	TM11MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#endif	/* CONFIG_AM33_2 */
 #define	TM11MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
 #define	TM11MD_COUNT_ENABLE	0x80	/* timer count enable */
 
+#if defined(CONFIG_AM34_2)
+#define	TM12MD			__SYSREG(0xd4003180, u8)   /* timer 11 mode register */
+#define	TM12MD_SRC		0x07	/* timer source */
+#define	TM12MD_SRC_IOCLK	0x00	/* - IOCLK */
+#define	TM12MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
+#define	TM12MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
+#define	TM12MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
+#define	TM12MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
+#define	TM12MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#define	TM12MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#define	TM12MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
+#define	TM12MD_COUNT_ENABLE	0x80	/* timer count enable */
+
+#define	TM13MD			__SYSREG(0xd4003182, u8)   /* timer 11 mode register */
+#define	TM13MD_SRC		0x07	/* timer source */
+#define	TM13MD_SRC_IOCLK	0x00	/* - IOCLK */
+#define	TM13MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
+#define	TM13MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
+#define	TM13MD_SRC_TM12CASCADE	0x03	/* - cascade with timer 12 */
+#define	TM13MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
+#define	TM13MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
+#define	TM13MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#define	TM13MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#define	TM13MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
+#define	TM13MD_COUNT_ENABLE	0x80	/* timer count enable */
+
+#define	TM14MD			__SYSREG(0xd4003184, u8)   /* timer 11 mode register */
+#define	TM14MD_SRC		0x07	/* timer source */
+#define	TM14MD_SRC_IOCLK	0x00	/* - IOCLK */
+#define	TM14MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
+#define	TM14MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
+#define	TM14MD_SRC_TM13CASCADE	0x03	/* - cascade with timer 13 */
+#define	TM14MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
+#define	TM14MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
+#define	TM14MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#define	TM14MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#define	TM14MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
+#define	TM14MD_COUNT_ENABLE	0x80	/* timer count enable */
+
+#define	TM15MD			__SYSREG(0xd4003186, u8)   /* timer 11 mode register */
+#define	TM15MD_SRC		0x07	/* timer source */
+#define	TM15MD_SRC_IOCLK	0x00	/* - IOCLK */
+#define	TM15MD_SRC_IOCLK_8	0x01	/* - 1/8 IOCLK */
+#define	TM15MD_SRC_IOCLK_32	0x02	/* - 1/32 IOCLK */
+#define	TM15MD_SRC_TM0UFLOW	0x04	/* - timer 0 underflow */
+#define	TM15MD_SRC_TM1UFLOW	0x05	/* - timer 1 underflow */
+#define	TM15MD_SRC_TM2UFLOW	0x06	/* - timer 2 underflow */
+#define	TM15MD_SRC_TM7UFLOW	0x07	/* - timer 7 underflow */
+#define	TM15MD_INIT_COUNTER	0x40	/* initialize TMnBC = TMnBR */
+#define	TM15MD_COUNT_ENABLE	0x80	/* timer count enable */
+#endif	/* CONFIG_AM34_2 */
+
+
 #define	TM4BR			__SYSREG(0xd4003090, u16)  /* timer 4 base register */
 #define	TM5BR			__SYSREG(0xd4003092, u16)  /* timer 5 base register */
+#define	TM45BR			__SYSREG(0xd4003090, u32)  /* timer 4:5 base register */
 #define	TM7BR			__SYSREG(0xd4003096, u16)  /* timer 7 base register */
 #define	TM8BR			__SYSREG(0xd4003098, u16)  /* timer 8 base register */
 #define	TM9BR			__SYSREG(0xd400309a, u16)  /* timer 9 base register */
+#define	TM89BR			__SYSREG(0xd4003098, u32)  /* timer 8:9 base register */
 #define	TM10BR			__SYSREG(0xd400309c, u16)  /* timer 10 base register */
 #define	TM11BR			__SYSREG(0xd400309e, u16)  /* timer 11 base register */
-#define	TM45BR			__SYSREG(0xd4003090, u32)  /* timer 4:5 base register */
+#if defined(CONFIG_AM34_2)
+#define	TM12BR			__SYSREG(0xd4003190, u16)  /* timer 12 base register */
+#define	TM13BR			__SYSREG(0xd4003192, u16)  /* timer 13 base register */
+#define	TM14BR			__SYSREG(0xd4003194, u16)  /* timer 14 base register */
+#define	TM15BR			__SYSREG(0xd4003196, u16)  /* timer 15 base register */
+#endif	/* CONFIG_AM34_2 */
 
 #define	TM4BC			__SYSREG(0xd40030a0, u16)  /* timer 4 binary counter */
 #define	TM5BC			__SYSREG(0xd40030a2, u16)  /* timer 5 binary counter */
 #define	TM45BC			__SYSREG(0xd40030a0, u32)  /* timer 4:5 binary counter */
-
 #define	TM7BC			__SYSREG(0xd40030a6, u16)  /* timer 7 binary counter */
 #define	TM8BC			__SYSREG(0xd40030a8, u16)  /* timer 8 binary counter */
 #define	TM9BC			__SYSREG(0xd40030aa, u16)  /* timer 9 binary counter */
+#define	TM89BC			__SYSREG(0xd40030a8, u32)  /* timer 8:9 binary counter */
 #define	TM10BC			__SYSREG(0xd40030ac, u16)  /* timer 10 binary counter */
 #define	TM11BC			__SYSREG(0xd40030ae, u16)  /* timer 11 binary counter */
+#if defined(CONFIG_AM34_2)
+#define	TM12BC			__SYSREG(0xd40031a0, u16)  /* timer 12 binary counter */
+#define	TM13BC			__SYSREG(0xd40031a2, u16)  /* timer 13 binary counter */
+#define	TM14BC			__SYSREG(0xd40031a4, u16)  /* timer 14 binary counter */
+#define	TM15BC			__SYSREG(0xd40031a6, u16)  /* timer 15 binary counter */
+#endif	/* CONFIG_AM34_2 */
 
 #define TM4IRQ			6	/* timer 4 IRQ */
 #define TM5IRQ			7	/* timer 5 IRQ */
@@ -212,6 +315,12 @@
 #define TM9IRQ			13	/* timer 9 IRQ */
 #define TM10IRQ			14	/* timer 10 IRQ */
 #define TM11IRQ			15	/* timer 11 IRQ */
+#if defined(CONFIG_AM34_2)
+#define TM12IRQ			64	/* timer 12 IRQ */
+#define TM13IRQ			65	/* timer 13 IRQ */
+#define TM14IRQ			66	/* timer 14 IRQ */
+#define TM15IRQ			67	/* timer 15 IRQ */
+#endif	/* CONFIG_AM34_2 */
 
 #define	TM4ICR			GxICR(TM4IRQ)	/* timer 4 uflow intr ctrl reg */
 #define	TM5ICR			GxICR(TM5IRQ)	/* timer 5 uflow intr ctrl reg */
@@ -220,8 +329,16 @@
 #define	TM9ICR			GxICR(TM9IRQ)	/* timer 9 uflow intr ctrl reg */
 #define	TM10ICR			GxICR(TM10IRQ)	/* timer 10 uflow intr ctrl reg */
 #define	TM11ICR			GxICR(TM11IRQ)	/* timer 11 uflow intr ctrl reg */
+#if defined(CONFIG_AM34_2)
+#define	TM12ICR			GxICR(TM12IRQ)	/* timer 12 uflow intr ctrl reg */
+#define	TM13ICR			GxICR(TM13IRQ)	/* timer 13 uflow intr ctrl reg */
+#define	TM14ICR			GxICR(TM14IRQ)	/* timer 14 uflow intr ctrl reg */
+#define	TM15ICR			GxICR(TM15IRQ)	/* timer 15 uflow intr ctrl reg */
+#endif	/* CONFIG_AM34_2 */
 
-/* 16-bit timer 6 */
+/*
+ * 16-bit timer 6
+ */
 #define	TM6MD			__SYSREG(0xd4003084, u16)  /* timer6 mode register */
 #define	TM6MD_SRC		0x0007	/* timer source */
 #define	TM6MD_SRC_IOCLK		0x0000	/* - IOCLK */
@@ -229,10 +346,14 @@
 #define	TM6MD_SRC_IOCLK_32	0x0002	/* - 1/32 IOCLK */
 #define	TM6MD_SRC_TM0UFLOW	0x0004	/* - timer 0 underflow */
 #define	TM6MD_SRC_TM1UFLOW	0x0005	/* - timer 1 underflow */
-#define	TM6MD_SRC_TM6IOB_BOTH	0x0006	/* - TM6IOB pin input (both edges) */
+#define	TM6MD_SRC_TM2UFLOW	0x0006	/* - timer 2 underflow */
+#if defined(CONFIG_AM33_2)
+/* #define	TM6MD_SRC_TM6IOB_BOTH	0x0006 */	/* - TM6IOB pin input (both edges) */
 #define	TM6MD_SRC_TM6IOB_SINGLE	0x0007	/* - TM6IOB pin input (single edge) */
-#define	TM6MD_CLR_ENABLE	0x0010	/* clear count enable */
+#endif	/* CONFIG_AM33_2 */
 #define	TM6MD_ONESHOT_ENABLE	0x0040	/* oneshot count */
+#define	TM6MD_CLR_ENABLE	0x0010	/* clear count enable */
+#if	defined(CONFIG_AM33_2)
 #define	TM6MD_TRIG_ENABLE	0x0080	/* TM6IOB pin trigger enable */
 #define TM6MD_PWM		0x3800	/* PWM output mode */
 #define TM6MD_PWM_DIS		0x0000	/* - disabled */
@@ -240,10 +361,15 @@
 #define	TM6MD_PWM_11BIT		0x1800	/* - 11 bits mode */
 #define	TM6MD_PWM_12BIT		0x3000	/* - 12 bits mode */
 #define	TM6MD_PWM_14BIT		0x3800	/* - 14 bits mode */
+#endif	/* CONFIG_AM33_2 */
+
 #define	TM6MD_INIT_COUNTER	0x4000	/* initialize TMnBC to zero */
 #define	TM6MD_COUNT_ENABLE	0x8000	/* timer count enable */
 
 #define	TM6MDA			__SYSREG(0xd40030b4, u8)   /* timer6 cmp/cap A mode reg */
+#define	TM6MDA_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */
+#define	TM6MDA_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */
+#if	defined(CONFIG_AM33_2)
 #define TM6MDA_OUT		0x07	/* output select */
 #define	TM6MDA_OUT_SETA_RESETB	0x00	/* - set at match A, reset at match B */
 #define	TM6MDA_OUT_SETA_RESETOV	0x01	/* - set at match A, reset at overflow */
@@ -251,30 +377,35 @@
 #define	TM6MDA_OUT_RESETA	0x03	/* - reset at match A */
 #define	TM6MDA_OUT_TOGGLE	0x04	/* - toggle on match A */
 #define TM6MDA_MODE		0xc0	/* compare A register mode */
-#define	TM6MDA_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */
-#define	TM6MDA_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */
 #define	TM6MDA_MODE_CAP_S_EDGE	0x80	/* - capture, single edge mode */
 #define	TM6MDA_MODE_CAP_D_EDGE	0xc0	/* - capture, double edge mode */
 #define TM6MDA_EDGE		0x20	/* compare A edge select */
 #define	TM6MDA_EDGE_FALLING	0x00	/* capture on falling edge */
 #define	TM6MDA_EDGE_RISING	0x20	/* capture on rising edge */
 #define	TM6MDA_CAPTURE_ENABLE	0x10	/* capture enable */
+#else	/* !CONFIG_AM33_2 */
+#define	TM6MDA_MODE		0x40	/* compare A register mode */
+#endif	/* CONFIG_AM33_2 */
 
 #define	TM6MDB			__SYSREG(0xd40030b5, u8)   /* timer6 cmp/cap B mode reg */
+#define	TM6MDB_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */
+#define	TM6MDB_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */
+#if defined(CONFIG_AM33_2)
 #define TM6MDB_OUT		0x07	/* output select */
 #define	TM6MDB_OUT_SETB_RESETA	0x00	/* - set at match B, reset at match A */
 #define	TM6MDB_OUT_SETB_RESETOV	0x01	/* - set at match B */
 #define	TM6MDB_OUT_RESETB	0x03	/* - reset at match B */
 #define	TM6MDB_OUT_TOGGLE	0x04	/* - toggle on match B */
 #define TM6MDB_MODE		0xc0	/* compare B register mode */
-#define	TM6MDB_MODE_CMP_SINGLE	0x00	/* - compare, single buffer mode */
-#define	TM6MDB_MODE_CMP_DOUBLE	0x40	/* - compare, double buffer mode */
 #define	TM6MDB_MODE_CAP_S_EDGE	0x80	/* - capture, single edge mode */
 #define	TM6MDB_MODE_CAP_D_EDGE	0xc0	/* - capture, double edge mode */
 #define TM6MDB_EDGE		0x20	/* compare B edge select */
 #define	TM6MDB_EDGE_FALLING	0x00	/* capture on falling edge */
 #define	TM6MDB_EDGE_RISING	0x20	/* capture on rising edge */
 #define	TM6MDB_CAPTURE_ENABLE	0x10	/* capture enable */
+#else	/* !CONFIG_AM33_2 */
+#define	TM6MDB_MODE		0x40	/* compare B register mode */
+#endif	/* CONFIG_AM33_2 */
 
 #define	TM6CA			__SYSREG(0xd40030c4, u16)   /* timer6 cmp/capture reg A */
 #define	TM6CB			__SYSREG(0xd40030d4, u16)   /* timer6 cmp/capture reg B */
@@ -288,6 +419,34 @@
 #define	TM6AICR			GxICR(TM6AIRQ)	/* timer 6A intr control reg */
 #define	TM6BICR			GxICR(TM6BIRQ)	/* timer 6B intr control reg */
 
+#if defined(CONFIG_AM34_2)
+/*
+ * MTM: OS Tick-Timer
+ */
+#define	TMTMD			__SYSREG(0xd4004100, u8)	/* Tick Timer mode register */
+#define	TMTMD_TMTLDE		0x40	/* initialize TMTBC = TMTBR */
+#define	TMTMD_TMTCNE		0x80	/* timer count enable       */
+
+#define	TMTBR			__SYSREG(0xd4004110, u32)	/* Tick Timer mode reg */
+#define	TMTBC			__SYSREG(0xd4004120, u32)	/* Tick Timer mode reg */
+
+/*
+ * MTM: OS Timestamp-Timer
+ */
+#define	TMSMD			__SYSREG(0xd4004140, u8)	/* Tick Timer mode register */
+#define	TMSMD_TMSLDE		0x40		/* initialize TMSBC = TMSBR */
+#define	TMSMD_TMSCNE		0x80		/* timer count enable       */
+
+#define	TMSBR			__SYSREG(0xd4004150, u32)	/* Tick Timer mode register */
+#define	TMSBC			__SYSREG(0xd4004160, u32)	/* Tick Timer mode register */
+
+#define TMTIRQ			119		/* OS Tick timer   IRQ */
+#define TMSIRQ			120		/* Timestamp timer IRQ */
+
+#define	TMTICR			GxICR(TMTIRQ)	/* OS Tick timer   uflow intr ctrl reg */
+#define	TMSICR			GxICR(TMSIRQ)	/* Timestamp timer uflow intr ctrl reg */
+#endif	/* CONFIG_AM34_2 */
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TIMER_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/timex.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/timex.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/timex.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,18 +16,30 @@
 
 #define TICK_SIZE (tick_nsec / 1000)
 
-#define CLOCK_TICK_RATE 1193180 /* Underlying HZ - this should probably be set
-				 * to something appropriate, but what? */
-
-extern cycles_t cacheflush_time;
+#define CLOCK_TICK_RATE MN10300_JCCLK /* Underlying HZ */
 
 #ifdef __KERNEL__
 
+extern cycles_t cacheflush_time;
+
 static inline cycles_t get_cycles(void)
 {
 	return read_timestamp_counter();
 }
 
+extern int init_clockevents(void);
+extern int init_clocksource(void);
+
+static inline void setup_jiffies_interrupt(int irq,
+					   struct irqaction *action)
+{
+	u16 tmp;
+	setup_irq(irq, action);
+	set_intr_level(irq, NUM2GxICR_LEVEL(CONFIG_TIMER_IRQ_LEVEL));
+	GxICR(irq) |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
+	tmp = GxICR(irq);
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_TIMEX_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/tlbflush.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/tlbflush.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/tlbflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/tlbflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,24 +11,78 @@
 #ifndef _ASM_TLBFLUSH_H
 #define _ASM_TLBFLUSH_H
 
+#include <linux/mm.h>
 #include <asm/processor.h>
 
-#define __flush_tlb()						\
-do {								\
-	int w;							\
-	__asm__ __volatile__					\
-		("	mov %1,%0		\n"		\
-		 "	or %2,%0		\n"		\
-		 "	mov %0,%1		\n"		\
-		 : "=d"(w)					\
-		 : "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV)	\
-		 : "cc", "memory"				\
-		 );						\
-} while (0)
+struct tlb_state {
+	struct mm_struct	*active_mm;
+	int			state;
+};
+DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
 
-#define __flush_tlb_all() __flush_tlb()
-#define __flush_tlb_one(addr) __flush_tlb()
+/**
+ * local_flush_tlb - Flush the current MM's entries from the local CPU's TLBs
+ */
+static inline void local_flush_tlb(void)
+{
+	int w;
+	asm volatile(
+		"	mov	%1,%0		\n"
+		"	or	%2,%0		\n"
+		"	mov	%0,%1		\n"
+		: "=d"(w)
+		: "m"(MMUCTR), "i"(MMUCTR_IIV|MMUCTR_DIV)
+		: "cc", "memory");
+}
 
+/**
+ * local_flush_tlb_all - Flush all entries from the local CPU's TLBs
+ */
+static inline void local_flush_tlb_all(void)
+{
+	local_flush_tlb();
+}
+
+/**
+ * local_flush_tlb_one - Flush one entry from the local CPU's TLBs
+ */
+static inline void local_flush_tlb_one(unsigned long addr)
+{
+	local_flush_tlb();
+}
+
+/**
+ * local_flush_tlb_page - Flush a page's entry from the local CPU's TLBs
+ * @mm: The MM to flush for
+ * @addr: The address of the target page in RAM (not its page struct)
+ */
+static inline
+void local_flush_tlb_page(struct mm_struct *mm, unsigned long addr)
+{
+	unsigned long pteu, flags, cnx;
+
+	addr &= PAGE_MASK;
+
+	local_irq_save(flags);
+
+	cnx = 1;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+	cnx = mm->context.tlbpid[smp_processor_id()];
+#endif
+	if (cnx) {
+		pteu = addr;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+		pteu |= cnx & xPTEU_PID;
+#endif
+		IPTEU = pteu;
+		DPTEU = pteu;
+		if (IPTEL & xPTEL_V)
+			IPTEL = 0;
+		if (DPTEL & xPTEL_V)
+			DPTEL = 0;
+	}
+	local_irq_restore(flags);
+}
 
 /*
  * TLB flushing:
@@ -40,41 +94,61 @@
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
-#define flush_tlb_all()				\
-do {						\
-	preempt_disable();			\
-	__flush_tlb_all();			\
-	preempt_enable();			\
-} while (0)
+#ifdef CONFIG_SMP
 
-#define flush_tlb_mm(mm)			\
-do {						\
-	preempt_disable();			\
-	__flush_tlb_all();			\
-	preempt_enable();			\
-} while (0)
+#include <asm/smp.h>
 
-#define flush_tlb_range(vma, start, end)			\
-do {								\
-	unsigned long __s __attribute__((unused)) = (start);	\
-	unsigned long __e __attribute__((unused)) = (end);	\
-	preempt_disable();					\
-	__flush_tlb_all();					\
-	preempt_enable();					\
-} while (0)
+extern void flush_tlb_all(void);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
 
+#define flush_tlb()		flush_tlb_current_task()
 
-#define __flush_tlb_global()			flush_tlb_all()
-#define flush_tlb()				flush_tlb_all()
-#define flush_tlb_kernel_range(start, end)			\
-do {								\
-	unsigned long __s __attribute__((unused)) = (start);	\
-	unsigned long __e __attribute__((unused)) = (end);	\
-	flush_tlb_all();					\
-} while (0)
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	flush_tlb_mm(vma->vm_mm);
+}
 
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
+#else   /* CONFIG_SMP */
 
-#define flush_tlb_pgtables(mm, start, end)	do {} while (0)
+static inline void flush_tlb_all(void)
+{
+	preempt_disable();
+	local_flush_tlb_all();
+	preempt_enable();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	preempt_disable();
+	local_flush_tlb_all();
+	preempt_enable();
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	preempt_disable();
+	local_flush_tlb_all();
+	preempt_enable();
+}
+
+#define flush_tlb_page(vma, addr)	local_flush_tlb_page((vma)->vm_mm, addr)
+#define flush_tlb()			flush_tlb_all()
+
+#endif /* CONFIG_SMP */
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+					  unsigned long end)
+{
+	flush_tlb_all();
+}
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{
+}
 
 #endif /* _ASM_TLBFLUSH_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/include/asm/uaccess.h linux-libre-2.6.37-gnu/arch/mn10300/include/asm/uaccess.h
--- linux-libre-2.6.36-gnu/arch/mn10300/include/asm/uaccess.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/include/asm/uaccess.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,9 +14,8 @@
 /*
  * User space memory access functions
  */
-#include <linux/sched.h>
+#include <linux/thread_info.h>
 #include <asm/page.h>
-#include <asm/pgtable.h>
 #include <asm/errno.h>
 
 #define VERIFY_READ 0
@@ -29,7 +28,6 @@
  *
  * For historical reasons, these macros are grossly misnamed.
  */
-
 #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
 
 #define KERNEL_XDS	MAKE_MM_SEG(0xBFFFFFFF)
@@ -377,7 +375,7 @@
 
 
 #if 0
-#error don't use - these macros don't increment to & from pointers
+#error "don't use - these macros don't increment to & from pointers"
 /* Optimize just a little bit when we know the size of the move. */
 #define __constant_copy_user(to, from, size)	\
 do {						\
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/Kconfig linux-libre-2.6.37-gnu/arch/mn10300/Kconfig
--- linux-libre-2.6.36-gnu/arch/mn10300/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,16 +1,20 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux Kernel Configuration"
-
 config MN10300
 	def_bool y
 	select HAVE_OPROFILE
 
-config AM33
-	def_bool y
+config AM33_2
+	def_bool n
+
+config AM33_3
+	def_bool n
+
+config AM34_2
+	def_bool n
+	select MN10300_HAS_ATOMIC_OPS_UNIT
+	select MN10300_HAS_CACHE_SNOOP
+
+config ERRATUM_NEED_TO_RELOAD_MMUCTR
+	def_bool y if AM33_3 || AM34_2
 
 config MMU
 	def_bool y
@@ -37,7 +41,7 @@
 	def_bool y
 
 config GENERIC_CMOS_UPDATE
-        def_bool y
+        def_bool n
 
 config GENERIC_FIND_NEXT_BIT
 	def_bool y
@@ -45,6 +49,27 @@
 config GENERIC_HWEIGHT
 	def_bool y
 
+config GENERIC_TIME
+	def_bool y
+
+config GENERIC_CLOCKEVENTS
+	def_bool y
+
+config GENERIC_CLOCKEVENTS_BUILD
+	def_bool y
+	depends on GENERIC_CLOCKEVENTS
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+	bool
+
+config CEVT_MN10300
+       def_bool y
+       depends on GENERIC_CLOCKEVENTS
+
+config CSRC_MN10300
+       def_bool y
+       depends on GENERIC_TIME
+
 config GENERIC_BUG
 	def_bool y
 
@@ -61,18 +86,12 @@
 config HOTPLUG_CPU
 	def_bool n
 
-config HZ
-	int
-	default 1000
-
-mainmenu "Matsushita MN10300/AM33 Kernel Configuration"
-
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
 
 
-menu "Matsushita MN10300 system setup"
+menu "Panasonic MN10300 system setup"
 
 choice
 	prompt "Unit type"
@@ -87,6 +106,10 @@
 config MN10300_UNIT_ASB2305
 	bool "ASB2305"
 
+config MN10300_UNIT_ASB2364
+	bool "ASB2364"
+	select SMSC911X_ARCH_HOOKS if SMSC911X
+
 endchoice
 
 choice
@@ -99,57 +122,51 @@
 config MN10300_PROC_MN103E010
 	bool "MN103E010"
 	depends on MN10300_UNIT_ASB2303 || MN10300_UNIT_ASB2305
+	select AM33_2
+	select MN10300_PROC_HAS_TTYSM0
+	select MN10300_PROC_HAS_TTYSM1
+	select MN10300_PROC_HAS_TTYSM2
+
+config MN10300_PROC_MN2WS0050
+	bool "MN2WS0050"
+	depends on MN10300_UNIT_ASB2364
+	select AM34_2
 	select MN10300_PROC_HAS_TTYSM0
 	select MN10300_PROC_HAS_TTYSM1
 	select MN10300_PROC_HAS_TTYSM2
 
 endchoice
 
-choice
-	prompt "Processor core support"
-	default MN10300_CPU_AM33V2
+config MN10300_HAS_ATOMIC_OPS_UNIT
+	def_bool n
 	help
-	  This option specifies the processor core for which the kernel will be
-	  compiled. It affects the instruction set used.
-
-config MN10300_CPU_AM33V2
-	bool "AM33v2"
-
-endchoice
+	  This should be enabled if the processor has an atomic ops unit
+	  capable of doing LL/SC equivalent operations.
 
 config FPU
 	bool "FPU present"
 	default y
-	depends on MN10300_PROC_MN103E010
+	depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
 
-choice
-	prompt "CPU Caching mode"
-	default MN10300_CACHE_WBACK
+config LAZY_SAVE_FPU
+	bool "Save FPU state lazily"
+	default y
+	depends on FPU && !SMP
 	help
-	  This option determines the caching mode for the kernel.
-
-	  Write-Back caching mode involves the all reads and writes causing
-	  the affected cacheline to be read into the cache first before being
-	  operated upon. Memory is not then updated by a write until the cache
-	  is filled and a cacheline needs to be displaced from the cache to
-	  make room. Only at that point is it written back.
-
-	  Write-Through caching only fetches cachelines from memory on a
-	  read. Writes always get written directly to memory. If the affected
-	  cacheline is also in cache, it will be updated too.
-
-	  The final option is to turn of caching entirely.
-
-config MN10300_CACHE_WBACK
-	bool "Write-Back"
+	  Enable this to be lazy in the saving of the FPU state to the owning
+	  task's thread struct.  This is useful if most tasks on the system
+	  don't use the FPU as only those tasks that use it will pass it
+	  between them, and the state needn't be saved for a task that isn't
+	  using it.
 
-config MN10300_CACHE_WTHRU
-	bool "Write-Through"
+	  This can't be so easily used on SMP as the process that owns the FPU
+	  state on a CPU may be currently running on another CPU, so for the
+	  moment, it is disabled.
 
-config MN10300_CACHE_DISABLED
-	bool "Disabled"
+source "arch/mn10300/mm/Kconfig.cache"
 
-endchoice
+config MN10300_TLB_USE_PIDR
+	def_bool y
 
 menu "Memory layout options"
 
@@ -170,24 +187,55 @@
 
 config KERNEL_ZIMAGE_BASE_ADDRESS
 	hex "Base address of compressed vmlinux image"
-	default "0x90700000"
+	default "0x50700000"
 
+config BOOT_STACK_OFFSET
+	hex
+	default	"0xF00"	if SMP
+	default	"0xFF0" if !SMP
+
+config BOOT_STACK_SIZE
+	hex
+	depends on SMP
+	default	"0x100"
 endmenu
 
-config PREEMPT
-	bool "Preemptible Kernel"
-	help
-	  This option reduces the latency of the kernel when reacting to
-	  real-time or interactive events by allowing a low priority process to
-	  be preempted even if it is in kernel mode executing a system call.
-	  This allows applications to run more reliably even when the system is
-	  under load.
+config SMP
+	bool "Symmetric multi-processing support"
+	default y
+	depends on MN10300_PROC_MN2WS0038 || MN10300_PROC_MN2WS0050
+	---help---
+	  This enables support for systems with more than one CPU. If you have
+	  a system with only one CPU, like most personal computers, say N. If
+	  you have a system with more than one CPU, say Y.
 
-	  Say Y here if you are building a kernel for a desktop, embedded
-	  or real-time system.  Say N if you are unsure.
+	  If you say N here, the kernel will run on single and multiprocessor
+	  machines, but will use only one CPU of a multiprocessor machine. If
+	  you say Y here, the kernel will run on many, but not all,
+	  singleprocessor machines. On a singleprocessor machine, the kernel
+	  will run faster if you say N here.
+
+	  See also <file:Documentation/i386/IO-APIC.txt>,
+	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  If you don't know what to do here, say N.
+
+config NR_CPUS
+	int
+	depends on SMP
+	default "2"
+
+config USE_GENERIC_SMP_HELPERS
+	bool
+	depends on SMP
+	default y
+
+source "kernel/Kconfig.preempt"
 
 config MN10300_CURRENT_IN_E2
 	bool "Hold current task address in E2 register"
+	depends on !SMP
 	default y
 	help
 	  This option removes the E2/R2 register from the set available to gcc
@@ -209,12 +257,15 @@
 	  suppresses the use of certain hardware debugging features, such as
 	  single-stepping, which are taken over completely by the JTAG unit.
 
+source "kernel/Kconfig.hz"
+source "kernel/time/Kconfig"
+
 config MN10300_RTC
 	bool "Using MN10300 RTC"
-	depends on MN10300_PROC_MN103E010
+	depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
+	select GENERIC_CMOS_UPDATE
 	default n
 	help
-
 	  This option enables support for the RTC, thus enabling time to be
 	  tracked, even when system is powered down. This is available on-chip
 	  on the MN103E010.
@@ -306,14 +357,23 @@
 
 choice
 	prompt "Select the timer to supply the clock for SIF1"
-	default MN10300_TTYSM0_TIMER9
+	default MN10300_TTYSM1_TIMER12 \
+		if !(AM33_2 || AM33_3)
+	default MN10300_TTYSM1_TIMER9 \
+		if AM33_2 || AM33_3
 	depends on MN10300_TTYSM1
 
+config MN10300_TTYSM1_TIMER12
+	bool "Use timer 12 (16-bit)"
+	depends on !(AM33_2 || AM33_3)
+
 config MN10300_TTYSM1_TIMER9
 	bool "Use timer 9 (16-bit)"
+	depends on AM33_2 || AM33_3
 
 config MN10300_TTYSM1_TIMER3
 	bool "Use timer 3 (8-bit)"
+	depends on AM33_2 || AM33_3
 
 endchoice
 
@@ -328,17 +388,107 @@
 
 choice
 	prompt "Select the timer to supply the clock for SIF2"
-	default MN10300_TTYSM0_TIMER10
+	default MN10300_TTYSM2_TIMER3 \
+		if !(AM33_2 || AM33_3)
+	default MN10300_TTYSM2_TIMER10 \
+		if AM33_2 || AM33_3
 	depends on MN10300_TTYSM2
 
+config MN10300_TTYSM2_TIMER9
+	bool "Use timer 9 (16-bit)"
+	depends on !(AM33_2 || AM33_3)
+
+config MN10300_TTYSM2_TIMER1
+	bool "Use timer 1 (8-bit)"
+	depends on !(AM33_2 || AM33_3)
+
+config MN10300_TTYSM2_TIMER3
+	bool "Use timer 3 (8-bit)"
+	depends on !(AM33_2 || AM33_3)
+
 config MN10300_TTYSM2_TIMER10
 	bool "Use timer 10 (16-bit)"
+	depends on AM33_2 || AM33_3
 
 endchoice
 
 config MN10300_TTYSM2_CTS
 	bool "Enable the use of the CTS line /dev/ttySM2"
-	depends on MN10300_TTYSM2
+	depends on MN10300_TTYSM2 && AM33_2
+
+endmenu
+
+menu "Interrupt request priority options"
+
+comment "[!] NOTE: A lower number/level indicates a higher priority (0 is highest, 6 is lowest)"
+
+comment "____Non-maskable interrupt levels____"
+comment "The following must be set to a higher priority than local_irq_disable() and on-chip serial"
+
+config GDBSTUB_IRQ_LEVEL
+	int "GDBSTUB interrupt priority"
+	depends on GDBSTUB
+	range 0 1 if LINUX_CLI_LEVEL = 2
+	range 0 2 if LINUX_CLI_LEVEL = 3
+	range 0 3 if LINUX_CLI_LEVEL = 4
+	range 0 4 if LINUX_CLI_LEVEL = 5
+	range 0 5 if LINUX_CLI_LEVEL = 6
+	default 0
+
+comment "The following must be set to a higher priority than local_irq_disable()"
+
+config MN10300_SERIAL_IRQ_LEVEL
+	int "MN10300 on-chip serial interrupt priority"
+	depends on MN10300_TTYSM
+	range 1 1 if LINUX_CLI_LEVEL = 2
+	range 1 2 if LINUX_CLI_LEVEL = 3
+	range 1 3 if LINUX_CLI_LEVEL = 4
+	range 1 4 if LINUX_CLI_LEVEL = 5
+	range 1 5 if LINUX_CLI_LEVEL = 6
+	default 1
+
+comment "-"
+comment "____Maskable interrupt levels____"
+
+config LINUX_CLI_LEVEL
+	int "The highest interrupt priority excluded by local_irq_disable() (2-6)"
+	range 2 6
+	default 2
+	help
+	  local_irq_disable() doesn't actually disable maskable interrupts -
+	  what it does is restrict the levels of interrupt which are permitted
+	  (a lower level indicates a higher priority) by lowering the value in
+	  EPSW.IM from 7.  Any interrupt is permitted for which the level is
+	  lower than EPSW.IM.
+
+	  Certain interrupts, such as GDBSTUB and virtual MN10300 on-chip
+	  serial DMA interrupts are allowed to interrupt normal disabled
+	  sections.
+
+comment "The following must be set to a equal to or lower priority than LINUX_CLI_LEVEL"
+
+config TIMER_IRQ_LEVEL
+	int "Kernel timer interrupt priority"
+	range LINUX_CLI_LEVEL 6
+	default 4
+
+config PCI_IRQ_LEVEL
+	int "PCI interrupt priority"
+	depends on PCI
+	range LINUX_CLI_LEVEL 6
+	default 5
+
+config ETHERNET_IRQ_LEVEL
+	int "Ethernet interrupt priority"
+	depends on SMC91X || SMC911X || SMSC911X
+	range LINUX_CLI_LEVEL 6
+	default 6
+
+config EXT_SERIAL_IRQ_LEVEL
+	int "External serial port interrupt priority"
+	depends on SERIAL_8250
+	range LINUX_CLI_LEVEL 6
+	default 6
 
 endmenu
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,7 @@
 
 	OFFSET(TI_task,			thread_info, task);
 	OFFSET(TI_exec_domain,		thread_info, exec_domain);
+	OFFSET(TI_frame,		thread_info, frame);
 	OFFSET(TI_flags,		thread_info, flags);
 	OFFSET(TI_cpu,			thread_info, cpu);
 	OFFSET(TI_preempt_count,	thread_info, preempt_count);
@@ -66,7 +67,15 @@
 	OFFSET(THREAD_SP,		thread_struct, sp);
 	OFFSET(THREAD_A3,		thread_struct, a3);
 	OFFSET(THREAD_USP,		thread_struct, usp);
-	OFFSET(THREAD_FRAME,		thread_struct, __frame);
+#ifdef CONFIG_FPU
+	OFFSET(THREAD_FPU_FLAGS,	thread_struct, fpu_flags);
+	OFFSET(THREAD_FPU_STATE,	thread_struct, fpu_state);
+	DEFINE(__THREAD_USING_FPU,	THREAD_USING_FPU);
+	DEFINE(__THREAD_HAS_FPU,	THREAD_HAS_FPU);
+#endif /* CONFIG_FPU */
+	BLANK();
+
+	OFFSET(TASK_THREAD,		task_struct, thread);
 	BLANK();
 
 	DEFINE(CLONE_VM_asm,		CLONE_VM);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/cevt-mn10300.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/cevt-mn10300.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/cevt-mn10300.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/cevt-mn10300.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,131 @@
+/* MN10300 clockevents
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <asm/timex.h>
+#include "internal.h"
+
+#ifdef CONFIG_SMP
+#if (CONFIG_NR_CPUS > 2) && !defined(CONFIG_GEENERIC_CLOCKEVENTS_BROADCAST)
+#error "This doesn't scale well! Need per-core local timers."
+#endif
+#else /* CONFIG_SMP */
+#define stop_jiffies_counter1()
+#define reload_jiffies_counter1(x)
+#define TMJC1IRQ TMJCIRQ
+#endif
+
+
+static int next_event(unsigned long delta,
+		      struct clock_event_device *evt)
+{
+	unsigned int cpu = smp_processor_id();
+
+	if (cpu == 0) {
+		stop_jiffies_counter();
+		reload_jiffies_counter(delta - 1);
+	} else {
+		stop_jiffies_counter1();
+		reload_jiffies_counter1(delta - 1);
+	}
+	return 0;
+}
+
+static void set_clock_mode(enum clock_event_mode mode,
+			   struct clock_event_device *evt)
+{
+	/* Nothing to do ...  */
+}
+
+static DEFINE_PER_CPU(struct clock_event_device, mn10300_clockevent_device);
+static DEFINE_PER_CPU(struct irqaction, timer_irq);
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *cd;
+	unsigned int cpu = smp_processor_id();
+
+	if (cpu == 0)
+		stop_jiffies_counter();
+	else
+		stop_jiffies_counter1();
+
+	cd = &per_cpu(mn10300_clockevent_device, cpu);
+	cd->event_handler(cd);
+
+	return IRQ_HANDLED;
+}
+
+static void event_handler(struct clock_event_device *dev)
+{
+}
+
+int __init init_clockevents(void)
+{
+	struct clock_event_device *cd;
+	struct irqaction *iact;
+	unsigned int cpu = smp_processor_id();
+
+	cd = &per_cpu(mn10300_clockevent_device, cpu);
+
+	if (cpu == 0) {
+		stop_jiffies_counter();
+		cd->irq	= TMJCIRQ;
+	} else {
+		stop_jiffies_counter1();
+		cd->irq	= TMJC1IRQ;
+	}
+
+	cd->name		= "Timestamp";
+	cd->features		= CLOCK_EVT_FEAT_ONESHOT;
+
+	/* Calculate the min / max delta */
+	clockevent_set_clock(cd, MN10300_JCCLK);
+
+	cd->max_delta_ns	= clockevent_delta2ns(TMJCBR_MAX, cd);
+	cd->min_delta_ns	= clockevent_delta2ns(100, cd);
+
+	cd->rating		= 200;
+	cd->cpumask		= cpumask_of(smp_processor_id());
+	cd->set_mode		= set_clock_mode;
+	cd->event_handler	= event_handler;
+	cd->set_next_event	= next_event;
+
+	iact = &per_cpu(timer_irq, cpu);
+	iact->flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER;
+	iact->handler = timer_interrupt;
+
+	clockevents_register_device(cd);
+
+#if defined(CONFIG_SMP) && !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+	/* setup timer irq affinity so it only runs on this cpu */
+	{
+		struct irq_desc *desc;
+		desc = irq_to_desc(cd->irq);
+		cpumask_copy(desc->affinity, cpumask_of(cpu));
+		iact->flags |= IRQF_NOBALANCING;
+	}
+#endif
+
+	if (cpu == 0) {
+		reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
+		iact->name = "CPU0 Timer";
+	} else {
+		reload_jiffies_counter1(MN10300_JC_PER_HZ - 1);
+		iact->name = "CPU1 Timer";
+	}
+
+	setup_jiffies_interrupt(cd->irq, iact);
+
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/csrc-mn10300.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/csrc-mn10300.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/csrc-mn10300.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/csrc-mn10300.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/* MN10300 clocksource
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by Mark Salter (msalter@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <asm/timex.h>
+#include "internal.h"
+
+static cycle_t mn10300_read(struct clocksource *cs)
+{
+	return read_timestamp_counter();
+}
+
+static struct clocksource clocksource_mn10300 = {
+	.name	= "TSC",
+	.rating	= 200,
+	.read	= mn10300_read,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+int __init init_clocksource(void)
+{
+	startup_timestamp_counter();
+	clocksource_set_clock(&clocksource_mn10300, MN10300_TSCCLK);
+	clocksource_register(&clocksource_mn10300);
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/entry.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/entry.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/linkage.h>
 #include <asm/smp.h>
 #include <asm/system.h>
+#include <asm/irqflags.h>
 #include <asm/thread_info.h>
 #include <asm/intctl-regs.h>
 #include <asm/busctl-regs.h>
@@ -27,25 +28,17 @@
 #include <asm/asm-offsets.h>
 #include <asm/frame.inc>
 
+#if defined(CONFIG_SMP) && defined(CONFIG_GDBSTUB)
+#include <asm/gdb-stub.h>
+#endif /* CONFIG_SMP && CONFIG_GDBSTUB */
+
 #ifdef CONFIG_PREEMPT
-#define preempt_stop		__cli
+#define preempt_stop		LOCAL_IRQ_DISABLE
 #else
 #define preempt_stop
 #define resume_kernel		restore_all
 #endif
 
-	.macro __cli
-	and	~EPSW_IM,epsw
-	or	EPSW_IE|MN10300_CLI_LEVEL,epsw
-	nop
-	nop
-	nop
-	.endm
-	.macro __sti
-	or	EPSW_IE|EPSW_IM_7,epsw
-	.endm
-
-
 	.am33_2
 
 ###############################################################################
@@ -87,7 +80,7 @@
 syscall_exit:
 	# make sure we don't miss an interrupt setting need_resched or
 	# sigpending between sampling and the rti
-	__cli
+	LOCAL_IRQ_DISABLE
 	mov	(TI_flags,a2),d2
 	btst	_TIF_ALLWORK_MASK,d2
 	bne	syscall_exit_work
@@ -104,7 +97,7 @@
 syscall_exit_work:
 	btst	_TIF_SYSCALL_TRACE,d2
 	beq	work_pending
-	__sti				# could let syscall_trace_exit() call
+	LOCAL_IRQ_ENABLE		# could let syscall_trace_exit() call
 					# schedule() instead
 	mov	fp,d0
 	call	syscall_trace_exit[],0	# do_syscall_trace(regs)
@@ -120,7 +113,7 @@
 
 	# make sure we don't miss an interrupt setting need_resched or
 	# sigpending between sampling and the rti
-	__cli
+	LOCAL_IRQ_DISABLE
 
 	# is there any work to be done other than syscall tracing?
 	mov	(TI_flags,a2),d2
@@ -167,7 +160,7 @@
 ENTRY(resume_userspace)
 	# make sure we don't miss an interrupt setting need_resched or
 	# sigpending between sampling and the rti
-	__cli
+	LOCAL_IRQ_DISABLE
 
 	# is there any work to be done on int/exception return?
 	mov	(TI_flags,a2),d2
@@ -177,7 +170,7 @@
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
-	__cli
+	LOCAL_IRQ_DISABLE
 	mov	(TI_preempt_count,a2),d0	# non-zero preempt_count ?
 	cmp	0,d0
 	bne	restore_all
@@ -215,31 +208,6 @@
 
 ###############################################################################
 #
-# Monitor Signal handler entry point
-#
-###############################################################################
-ENTRY(monitor_signal)
-	movbu	(0xae000001),d1
-	cmp	1,d1
-	beq	monsignal
-	ret	[],0
-
-monsignal:
-	or	EPSW_NMID,epsw
-	mov	d0,a0
-	mov	a0,sp
-	mov	(REG_EPSW,fp),d1
-	and	~EPSW_nSL,d1
-	mov	d1,(REG_EPSW,fp)
-	movm	(sp),[d2,d3,a2,a3,exreg0,exreg1,exother]
-	mov	(sp),a1
-	mov	a1,usp
-	movm	(sp),[other]
-	add	4,sp
-here:	jmp	0x8e000008-here+0x8e000008
-
-###############################################################################
-#
 # Double Fault handler entry point
 # - note that there will not be a stack, D0/A0 will hold EPSW/PC as were
 #
@@ -275,6 +243,10 @@
 ENTRY(raw_bus_error)
 	add	-4,sp
 	mov	d0,(sp)
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d0
+	mov	d0,(MMUCTR)
+#endif
 	mov	(BCBERR),d0		# what
 	btst	BCBERR_BEMR_DMA,d0	# see if it was an external bus error
 	beq	__common_exception_aux	# it wasn't
@@ -301,11 +273,88 @@
 	add	-4,sp
 	mov	d0,(sp)
 	mov	(TBR),d0
+
+#ifdef CONFIG_SMP
+	add	-4,sp
+	mov	d0,(sp)			# save d0(TBR)
+	movhu	(NMIAGR),d0
+	and	NMIAGR_GN,d0
+	lsr	0x2,d0
+	cmp	CALL_FUNCTION_NMI_IPI,d0
+	bne	5f			# if not call function, jump
+
+	# function call nmi ipi
+	add	4,sp			# no need to store TBR
+	mov	GxICR_DETECT,d0		# clear NMI request
+	movbu	d0,(GxICR(CALL_FUNCTION_NMI_IPI))
+	movhu	(GxICR(CALL_FUNCTION_NMI_IPI)),d0
+	and	~EPSW_NMID,epsw		# enable NMI
+
+	mov	(sp),d0			# restore d0
+	SAVE_ALL
+	call	smp_nmi_call_function_interrupt[],0
+	RESTORE_ALL
+
+5:
+#ifdef CONFIG_GDBSTUB
+	cmp	GDB_NMI_IPI,d0
+	bne	3f			# if not gdb nmi ipi, jump
+
+	# gdb nmi ipi
+	add	4,sp			# no need to store TBR
+	mov	GxICR_DETECT,d0		# clear NMI
+	movbu	d0,(GxICR(GDB_NMI_IPI))
+	movhu	(GxICR(GDB_NMI_IPI)),d0
+	and	~EPSW_NMID,epsw		# enable NMI
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+	mov	(gdbstub_nmi_opr_type),d0
+	cmp	GDBSTUB_NMI_CACHE_PURGE,d0
+	bne	4f			# if not gdb cache purge, jump
+
+	# gdb cache purge nmi ipi
+	add	-20,sp
+	mov	d1,(4,sp)
+	mov	a0,(8,sp)
+	mov	a1,(12,sp)
+	mov	mdr,d0
+	mov	d0,(16,sp)
+	call	gdbstub_local_purge_cache[],0
+	mov	0x1,d0
+	mov	(CPUID),d1
+	asl	d1,d0
+	mov	gdbstub_nmi_cpumask,a0
+	bclr	d0,(a0)
+	mov	(4,sp),d1
+	mov	(8,sp),a0
+	mov	(12,sp),a1
+	mov	(16,sp),d0
+	mov	d0,mdr
+	add	20,sp
+	mov	(sp),d0
+	add	4,sp
+	rti
+4:
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
+	# gdb wait nmi ipi
+	mov     (sp),d0
+	SAVE_ALL
+	call    gdbstub_nmi_wait[],0
+	RESTORE_ALL
+3:
+#endif /* CONFIG_GDBSTUB */
+	mov     (sp),d0                 # restore TBR to d0
+	add     4,sp
+#endif /* CONFIG_SMP */
+
 	bra	__common_exception_nonmi
 
 ENTRY(__common_exception)
 	add	-4,sp
 	mov	d0,(sp)
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d0
+	mov	d0,(MMUCTR)
+#endif
 
 __common_exception_aux:
 	mov	(TBR),d0
@@ -330,15 +379,21 @@
 	mov	d0,(REG_ORIG_D0,fp)
 
 #ifdef CONFIG_GDBSTUB
+#ifdef CONFIG_SMP
+	call	gdbstub_busy_check[],0
+	and	d0,d0			# check return value
+	beq	2f
+#else  /* CONFIG_SMP */
 	btst	0x01,(gdbstub_busy)
 	beq	2f
+#endif /* CONFIG_SMP */
 	and	~EPSW_IE,epsw
 	mov	fp,d0
 	mov	a2,d1
 	call	gdbstub_exception[],0	# gdbstub itself caused an exception
 	bra	restore_all
 2:
-#endif
+#endif /* CONFIG_GDBSTUB */
 
 	mov	fp,d0			# arg 0: stacked register file
 	mov	a2,d1			# arg 1: exception number
@@ -373,11 +428,7 @@
 	add	exception_table,d0
 	mov	d1,(d0)
 	mov	4,d1
-#if defined(CONFIG_MN10300_CACHE_WBACK)
-	jmp	mn10300_dcache_flush_inv_range2
-#else
 	ret	[],0
-#endif
 
 ###############################################################################
 #
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,56 +12,19 @@
 #include <asm/fpu.h>
 #include <asm/elf.h>
 #include <asm/exceptions.h>
+#include <asm/system.h>
 
+#ifdef CONFIG_LAZY_SAVE_FPU
 struct task_struct *fpu_state_owner;
+#endif
 
 /*
- * handle an exception due to the FPU being disabled
+ * error functions in FPU disabled exception
  */
-asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
+asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs)
 {
-	struct task_struct *tsk = current;
-
-	if (!user_mode(regs))
-		die_if_no_fixup("An FPU Disabled exception happened in"
-				" kernel space\n",
-				regs, code);
-
-#ifdef CONFIG_FPU
-	preempt_disable();
-
-	/* transfer the last process's FPU state to memory */
-	if (fpu_state_owner) {
-		fpu_save(&fpu_state_owner->thread.fpu_state);
-		fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
-	}
-
-	/* the current process now owns the FPU state */
-	fpu_state_owner = tsk;
-	regs->epsw |= EPSW_FE;
-
-	/* load the FPU with the current process's FPU state or invent a new
-	 * clean one if the process doesn't have one */
-	if (is_using_fpu(tsk)) {
-		fpu_restore(&tsk->thread.fpu_state);
-	} else {
-		fpu_init_state();
-		set_using_fpu(tsk);
-	}
-
-	preempt_enable();
-#else
-	{
-		siginfo_t info;
-
-		info.si_signo = SIGFPE;
-		info.si_errno = 0;
-		info.si_addr = (void *) tsk->thread.uregs->pc;
-		info.si_code = FPE_FLTINV;
-
-		force_sig_info(SIGFPE, &info, tsk);
-	}
-#endif  /* CONFIG_FPU */
+	die_if_no_fixup("An FPU Disabled exception happened in kernel space\n",
+			regs, EXCEP_FPU_DISABLED);
 }
 
 /*
@@ -71,15 +34,16 @@
  */
 asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
 {
-	struct task_struct *tsk = fpu_state_owner;
+	struct task_struct *tsk = current;
 	siginfo_t info;
+	u32 fpcr;
 
 	if (!user_mode(regs))
 		die_if_no_fixup("An FPU Operation exception happened in"
 				" kernel space\n",
 				regs, code);
 
-	if (!tsk)
+	if (!is_using_fpu(tsk))
 		die_if_no_fixup("An FPU Operation exception happened,"
 				" but the FPU is not in use",
 				regs, code);
@@ -89,48 +53,45 @@
 	info.si_addr = (void *) tsk->thread.uregs->pc;
 	info.si_code = FPE_FLTINV;
 
-#ifdef CONFIG_FPU
-	{
-		u32 fpcr;
+	unlazy_fpu(tsk);
 
-		/* get FPCR (we need to enable the FPU whilst we do this) */
-		asm volatile("	or	%1,epsw		\n"
-#ifdef CONFIG_MN10300_PROC_MN103E010
-			     "	nop			\n"
-			     "	nop			\n"
-			     "	nop			\n"
-#endif
-			     "	fmov	fpcr,%0		\n"
-#ifdef CONFIG_MN10300_PROC_MN103E010
-			     "	nop			\n"
-			     "	nop			\n"
-			     "	nop			\n"
-#endif
-			     "	and	%2,epsw		\n"
-			     : "=&d"(fpcr)
-			     : "i"(EPSW_FE), "i"(~EPSW_FE)
-			     );
+	fpcr = tsk->thread.fpu_state.fpcr;
 
-		if (fpcr & FPCR_EC_Z)
-			info.si_code = FPE_FLTDIV;
-		else if	(fpcr & FPCR_EC_O)
-			info.si_code = FPE_FLTOVF;
-		else if	(fpcr & FPCR_EC_U)
-			info.si_code = FPE_FLTUND;
-		else if	(fpcr & FPCR_EC_I)
-			info.si_code = FPE_FLTRES;
-	}
-#endif
+	if (fpcr & FPCR_EC_Z)
+		info.si_code = FPE_FLTDIV;
+	else if	(fpcr & FPCR_EC_O)
+		info.si_code = FPE_FLTOVF;
+	else if	(fpcr & FPCR_EC_U)
+		info.si_code = FPE_FLTUND;
+	else if	(fpcr & FPCR_EC_I)
+		info.si_code = FPE_FLTRES;
 
 	force_sig_info(SIGFPE, &info, tsk);
 }
 
 /*
+ * handle an FPU invalid_op exception
+ * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c
+ */
+asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code)
+{
+	siginfo_t info;
+
+	if (!user_mode(regs))
+		die_if_no_fixup("FPU invalid opcode", regs, code);
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code = ILL_COPROC;
+	info.si_addr = (void *) regs->pc;
+	force_sig_info(info.si_signo, &info, current);
+}
+
+/*
  * save the FPU state to a signal context
  */
 int fpu_setup_sigcontext(struct fpucontext *fpucontext)
 {
-#ifdef CONFIG_FPU
 	struct task_struct *tsk = current;
 
 	if (!is_using_fpu(tsk))
@@ -142,11 +103,19 @@
 	 */
 	preempt_disable();
 
+#ifndef CONFIG_LAZY_SAVE_FPU
+	if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+		fpu_save(&tsk->thread.fpu_state);
+		tsk->thread.uregs->epsw &= ~EPSW_FE;
+		tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+	}
+#else /* !CONFIG_LAZY_SAVE_FPU */
 	if (fpu_state_owner == tsk) {
 		fpu_save(&tsk->thread.fpu_state);
 		fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
 		fpu_state_owner = NULL;
 	}
+#endif /* !CONFIG_LAZY_SAVE_FPU */
 
 	preempt_enable();
 
@@ -161,9 +130,6 @@
 		return -1;
 
 	return 1;
-#else
-	return 0;
-#endif
 }
 
 /*
@@ -171,17 +137,23 @@
  */
 void fpu_kill_state(struct task_struct *tsk)
 {
-#ifdef CONFIG_FPU
 	/* disown anything left in the FPU */
 	preempt_disable();
 
+#ifndef CONFIG_LAZY_SAVE_FPU
+	if (tsk->thread.fpu_flags & THREAD_HAS_FPU) {
+		tsk->thread.uregs->epsw &= ~EPSW_FE;
+		tsk->thread.fpu_flags &= ~THREAD_HAS_FPU;
+	}
+#else /* !CONFIG_LAZY_SAVE_FPU */
 	if (fpu_state_owner == tsk) {
 		fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
 		fpu_state_owner = NULL;
 	}
+#endif /* !CONFIG_LAZY_SAVE_FPU */
 
 	preempt_enable();
-#endif
+
 	/* we no longer have a valid current FPU state */
 	clear_using_fpu(tsk);
 }
@@ -195,8 +167,7 @@
 	int ret;
 
 	/* load up the old FPU state */
-	ret = copy_from_user(&tsk->thread.fpu_state,
-			     fpucontext,
+	ret = copy_from_user(&tsk->thread.fpu_state, fpucontext,
 			     min(sizeof(struct fpu_state_struct),
 				 sizeof(struct fpucontext)));
 	if (!ret)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-low.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,25 +8,14 @@
  * as published by the Free Software Foundation; either version
  * 2 of the Licence, or (at your option) any later version.
  */
+#include <linux/linkage.h>
 #include <asm/cpu-regs.h>
+#include <asm/smp.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
 
-###############################################################################
-#
-# void fpu_init_state(void)
-# - initialise the FPU
-#
-###############################################################################
-	.globl	fpu_init_state
-	.type	fpu_init_state,@function
-fpu_init_state:
-	mov	epsw,d0
-	or	EPSW_FE,epsw
-
-#ifdef CONFIG_MN10300_PROC_MN103E010
-	nop
-	nop
-	nop
-#endif
+.macro FPU_INIT_STATE_ALL
 	fmov	0,fs0
 	fmov	fs0,fs1
 	fmov	fs0,fs2
@@ -60,7 +49,100 @@
 	fmov	fs0,fs30
 	fmov	fs0,fs31
 	fmov	FPCR_INIT,fpcr
+.endm
 
+.macro FPU_SAVE_ALL areg,dreg
+	fmov	fs0,(\areg+)
+	fmov	fs1,(\areg+)
+	fmov	fs2,(\areg+)
+	fmov	fs3,(\areg+)
+	fmov	fs4,(\areg+)
+	fmov	fs5,(\areg+)
+	fmov	fs6,(\areg+)
+	fmov	fs7,(\areg+)
+	fmov	fs8,(\areg+)
+	fmov	fs9,(\areg+)
+	fmov	fs10,(\areg+)
+	fmov	fs11,(\areg+)
+	fmov	fs12,(\areg+)
+	fmov	fs13,(\areg+)
+	fmov	fs14,(\areg+)
+	fmov	fs15,(\areg+)
+	fmov	fs16,(\areg+)
+	fmov	fs17,(\areg+)
+	fmov	fs18,(\areg+)
+	fmov	fs19,(\areg+)
+	fmov	fs20,(\areg+)
+	fmov	fs21,(\areg+)
+	fmov	fs22,(\areg+)
+	fmov	fs23,(\areg+)
+	fmov	fs24,(\areg+)
+	fmov	fs25,(\areg+)
+	fmov	fs26,(\areg+)
+	fmov	fs27,(\areg+)
+	fmov	fs28,(\areg+)
+	fmov	fs29,(\areg+)
+	fmov	fs30,(\areg+)
+	fmov	fs31,(\areg+)
+	fmov	fpcr,\dreg
+	mov	\dreg,(\areg)
+.endm
+
+.macro FPU_RESTORE_ALL areg,dreg
+	fmov	(\areg+),fs0
+	fmov	(\areg+),fs1
+	fmov	(\areg+),fs2
+	fmov	(\areg+),fs3
+	fmov	(\areg+),fs4
+	fmov	(\areg+),fs5
+	fmov	(\areg+),fs6
+	fmov	(\areg+),fs7
+	fmov	(\areg+),fs8
+	fmov	(\areg+),fs9
+	fmov	(\areg+),fs10
+	fmov	(\areg+),fs11
+	fmov	(\areg+),fs12
+	fmov	(\areg+),fs13
+	fmov	(\areg+),fs14
+	fmov	(\areg+),fs15
+	fmov	(\areg+),fs16
+	fmov	(\areg+),fs17
+	fmov	(\areg+),fs18
+	fmov	(\areg+),fs19
+	fmov	(\areg+),fs20
+	fmov	(\areg+),fs21
+	fmov	(\areg+),fs22
+	fmov	(\areg+),fs23
+	fmov	(\areg+),fs24
+	fmov	(\areg+),fs25
+	fmov	(\areg+),fs26
+	fmov	(\areg+),fs27
+	fmov	(\areg+),fs28
+	fmov	(\areg+),fs29
+	fmov	(\areg+),fs30
+	fmov	(\areg+),fs31
+	mov	(\areg),\dreg
+	fmov	\dreg,fpcr
+.endm
+
+###############################################################################
+#
+# void fpu_init_state(void)
+# - initialise the FPU
+#
+###############################################################################
+	.globl	fpu_init_state
+	.type	fpu_init_state,@function
+fpu_init_state:
+	mov	epsw,d0
+	or	EPSW_FE,epsw
+
+#ifdef CONFIG_MN10300_PROC_MN103E010
+	nop
+	nop
+	nop
+#endif
+	FPU_INIT_STATE_ALL
 #ifdef CONFIG_MN10300_PROC_MN103E010
 	nop
 	nop
@@ -89,40 +171,7 @@
 	nop
 #endif
 	mov	d0,a0
-	fmov	fs0,(a0+)
-	fmov	fs1,(a0+)
-	fmov	fs2,(a0+)
-	fmov	fs3,(a0+)
-	fmov	fs4,(a0+)
-	fmov	fs5,(a0+)
-	fmov	fs6,(a0+)
-	fmov	fs7,(a0+)
-	fmov	fs8,(a0+)
-	fmov	fs9,(a0+)
-	fmov	fs10,(a0+)
-	fmov	fs11,(a0+)
-	fmov	fs12,(a0+)
-	fmov	fs13,(a0+)
-	fmov	fs14,(a0+)
-	fmov	fs15,(a0+)
-	fmov	fs16,(a0+)
-	fmov	fs17,(a0+)
-	fmov	fs18,(a0+)
-	fmov	fs19,(a0+)
-	fmov	fs20,(a0+)
-	fmov	fs21,(a0+)
-	fmov	fs22,(a0+)
-	fmov	fs23,(a0+)
-	fmov	fs24,(a0+)
-	fmov	fs25,(a0+)
-	fmov	fs26,(a0+)
-	fmov	fs27,(a0+)
-	fmov	fs28,(a0+)
-	fmov	fs29,(a0+)
-	fmov	fs30,(a0+)
-	fmov	fs31,(a0+)
-	fmov	fpcr,d0
-	mov	d0,(a0)
+	FPU_SAVE_ALL	a0,d0
 #ifdef CONFIG_MN10300_PROC_MN103E010
 	nop
 	nop
@@ -135,63 +184,75 @@
 
 ###############################################################################
 #
-# void fpu_restore(struct fpu_state_struct *)
-# - restore the fpu state
-# - note that an FPU Operational exception might occur during this process
+# void fpu_disabled(void)
+# - handle an exception due to the FPU being disabled
+#   when CONFIG_FPU is enabled
 #
 ###############################################################################
-	.globl	fpu_restore
-	.type	fpu_restore,@function
-fpu_restore:
-	mov	epsw,d1
-	or	EPSW_FE,epsw		/* enable the FPU so we can access it */
-
-#ifdef CONFIG_MN10300_PROC_MN103E010
+	.type	fpu_disabled,@function
+	.globl	fpu_disabled
+fpu_disabled:
+	or	EPSW_nAR|EPSW_FE,epsw
 	nop
 	nop
-#endif
-	mov	d0,a0
-	fmov	(a0+),fs0
-	fmov	(a0+),fs1
-	fmov	(a0+),fs2
-	fmov	(a0+),fs3
-	fmov	(a0+),fs4
-	fmov	(a0+),fs5
-	fmov	(a0+),fs6
-	fmov	(a0+),fs7
-	fmov	(a0+),fs8
-	fmov	(a0+),fs9
-	fmov	(a0+),fs10
-	fmov	(a0+),fs11
-	fmov	(a0+),fs12
-	fmov	(a0+),fs13
-	fmov	(a0+),fs14
-	fmov	(a0+),fs15
-	fmov	(a0+),fs16
-	fmov	(a0+),fs17
-	fmov	(a0+),fs18
-	fmov	(a0+),fs19
-	fmov	(a0+),fs20
-	fmov	(a0+),fs21
-	fmov	(a0+),fs22
-	fmov	(a0+),fs23
-	fmov	(a0+),fs24
-	fmov	(a0+),fs25
-	fmov	(a0+),fs26
-	fmov	(a0+),fs27
-	fmov	(a0+),fs28
-	fmov	(a0+),fs29
-	fmov	(a0+),fs30
-	fmov	(a0+),fs31
-	mov	(a0),d0
-	fmov	d0,fpcr
-#ifdef CONFIG_MN10300_PROC_MN103E010
 	nop
+
+	mov	sp,a1
+	mov	(a1),d1			/* get epsw of user context */
+	and	~(THREAD_SIZE-1),a1	/* a1: (thread_info *ti) */
+	mov	(TI_task,a1),a2		/* a2: (task_struct *tsk) */
+	btst	EPSW_nSL,d1
+	beq	fpu_used_in_kernel
+
+	or	EPSW_FE,d1
+	mov	d1,(sp)
+	mov	(TASK_THREAD+THREAD_FPU_FLAGS,a2),d1
+#ifndef CONFIG_LAZY_SAVE_FPU
+	or	__THREAD_HAS_FPU,d1
+	mov	d1,(TASK_THREAD+THREAD_FPU_FLAGS,a2)
+#else  /* !CONFIG_LAZY_SAVE_FPU */
+	mov	(fpu_state_owner),a0
+	cmp	0,a0
+	beq	fpu_regs_save_end
+
+	mov	(TASK_THREAD+THREAD_UREGS,a0),a1
+	add	TASK_THREAD+THREAD_FPU_STATE,a0
+	FPU_SAVE_ALL a0,d0
+
+	mov	(REG_EPSW,a1),d0
+	and	~EPSW_FE,d0
+	mov	d0,(REG_EPSW,a1)
+
+fpu_regs_save_end:
+	mov	a2,(fpu_state_owner)
+#endif /* !CONFIG_LAZY_SAVE_FPU */
+
+	btst	__THREAD_USING_FPU,d1
+	beq	fpu_regs_init
+	add	TASK_THREAD+THREAD_FPU_STATE,a2
+	FPU_RESTORE_ALL a2,d0
+	rti
+
+fpu_regs_init:
+	FPU_INIT_STATE_ALL
+	add	TASK_THREAD+THREAD_FPU_FLAGS,a2
+	bset	__THREAD_USING_FPU,(0,a2)
+	rti
+
+fpu_used_in_kernel:
+	and	~(EPSW_nAR|EPSW_FE),epsw
 	nop
 	nop
-#endif
 
-	mov	d1,epsw
-	ret	[],0
+	add	-4,sp
+	SAVE_ALL
+	mov	-1,d0
+	mov	d0,(REG_ORIG_D0,fp)
 
-	.size	fpu_restore,.-fpu_restore
+	and	~EPSW_NMID,epsw
+
+	mov	fp,d0
+	call	fpu_disabled_in_kernel[],0
+	jmp	ret_from_exception
+
+	.size	fpu_disabled,.-fpu_disabled
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-nofpu.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-nofpu.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-nofpu.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-nofpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,30 @@
+/* MN10300 FPU management
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <asm/fpu.h>
+
+/*
+ * handle an FPU operational exception
+ * - there's a possibility that if the FPU is asynchronous, the signal might
+ *   be meant for a process other than the current one
+ */
+asmlinkage
+void unexpected_fpu_exception(struct pt_regs *regs, enum exception_code code)
+{
+	panic("An FPU exception was received, but there's no FPU enabled.");
+}
+
+/*
+ * fill in the FPU structure for a core dump
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
+{
+	return 0; /* not valid */
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-nofpu-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-nofpu-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/fpu-nofpu-low.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/fpu-nofpu-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,39 @@
+/* MN10300 Low level FPU management operations
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/linkage.h>
+#include <asm/cpu-regs.h>
+#include <asm/smp.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
+
+###############################################################################
+#
+# void fpu_disabled(void)
+# - handle an exception due to the FPU being disabled
+#   when CONFIG_FPU is disabled
+#
+###############################################################################
+	.type	fpu_disabled,@function
+	.globl	fpu_disabled
+fpu_disabled:
+	add	-4,sp
+	SAVE_ALL
+	mov	-1,d0
+	mov	d0,(REG_ORIG_D0,fp)
+
+	and	~EPSW_NMID,epsw
+
+	mov	fp,d0
+	call	unexpected_fpu_exception[],0
+	jmp	ret_from_exception
+
+	.size	fpu_disabled,.-fpu_disabled
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-serial.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-serial.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,7 @@
 #include <asm/exceptions.h>
 #include <asm/serial-regs.h>
 #include <unit/serial.h>
+#include <asm/smp.h>
 
 /*
  * initialise the GDB stub
@@ -45,22 +46,35 @@
 	XIRQxICR(GDBPORT_SERIAL_IRQ) = 0;
 	tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
 
+#if   CONFIG_GDBSTUB_IRQ_LEVEL == 0
 	IVAR0 = EXCEP_IRQ_LEVEL0;
-	set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 1
+	IVAR1 = EXCEP_IRQ_LEVEL1;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 2
+	IVAR2 = EXCEP_IRQ_LEVEL2;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 3
+	IVAR3 = EXCEP_IRQ_LEVEL3;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 4
+	IVAR4 = EXCEP_IRQ_LEVEL4;
+#elif CONFIG_GDBSTUB_IRQ_LEVEL == 5
+	IVAR5 = EXCEP_IRQ_LEVEL5;
+#else
+#error "Unknown irq level for gdbstub."
+#endif
+
+	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
+		gdbstub_io_rx_handler);
 
 	XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST;
-	XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0;
+	XIRQxICR(GDBPORT_SERIAL_IRQ) =
+		GxICR_ENABLE | NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL);
 	tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
 
 	GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;
 
 	/* permit level 0 IRQs to take place */
-	asm volatile(
-		"	and %0,epsw	\n"
-		"	or %1,epsw	\n"
-		:
-		: "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1)
-		);
+	arch_local_change_intr_mask_level(
+		NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
 }
 
 /*
@@ -87,6 +101,9 @@
 {
 	unsigned ix;
 	u8 ch, st;
+#if defined(CONFIG_MN10300_WD_TIMER)
+	int cpu;
+#endif
 
 	*_ch = 0xff;
 
@@ -104,8 +121,9 @@
 		if (nonblock)
 			return -EAGAIN;
 #ifdef CONFIG_MN10300_WD_TIMER
-		watchdog_alert_counter = 0;
-#endif /* CONFIG_MN10300_WD_TIMER */
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		watchdog_alert_counter[cpu] = 0;
+#endif
 		goto try_again;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-serial-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-serial-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-serial-low.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-serial-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <asm/thread_info.h>
 #include <asm/frame.inc>
 #include <asm/intctl-regs.h>
+#include <asm/irqflags.h>
 #include <unit/serial.h>
 
 	.text
@@ -69,7 +70,7 @@
 	bra	gdbstub_io_rx_done
 
 gdbstub_io_rx_enter:
-	or	EPSW_IE|EPSW_IM_1,epsw
+	LOCAL_CHANGE_INTR_MASK_LEVEL(NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL+1))
 	add	-4,sp
 	SAVE_ALL
 
@@ -80,7 +81,7 @@
 	mov	fp,d0
 	call	gdbstub_rx_irq[],0	# gdbstub_rx_irq(regs,excep)
 
-	and	~EPSW_IE,epsw
+	LOCAL_CLI
 	bclr	0x01,(gdbstub_busy)
 
 	.globl gdbstub_return
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-ttysm.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-ttysm.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-io-ttysm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-io-ttysm.c	2011-01-04 19:50:19.000000000 -0500
@@ -58,9 +58,12 @@
 	gdbstub_io_set_baud(115200);
 
 	/* we want to get serial receive interrupts */
-	set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0);
-	set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0);
-	set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
+	set_intr_level(gdbstub_port->rx_irq,
+		NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
+	set_intr_level(gdbstub_port->tx_irq,
+		NUM2GxICR_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL));
+	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_GDBSTUB_IRQ_LEVEL),
+		gdbstub_io_rx_handler);
 
 	*gdbstub_port->rx_icr |= GxICR_ENABLE;
 	tmp = *gdbstub_port->rx_icr;
@@ -84,12 +87,8 @@
 	tmp = *gdbstub_port->_control;
 
 	/* permit level 0 IRQs only */
-	asm volatile(
-		"	and %0,epsw	\n"
-		"	or %1,epsw	\n"
-		:
-		: "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1)
-		);
+	arch_local_change_intr_mask_level(
+		NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
 }
 
 /*
@@ -184,6 +183,9 @@
 {
 	unsigned ix;
 	u8 ch, st;
+#if defined(CONFIG_MN10300_WD_TIMER)
+	int cpu;
+#endif
 
 	*_ch = 0xff;
 
@@ -201,8 +203,9 @@
 		if (nonblock)
 			return -EAGAIN;
 #ifdef CONFIG_MN10300_WD_TIMER
-		watchdog_alert_counter = 0;
-#endif /* CONFIG_MN10300_WD_TIMER */
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		watchdog_alert_counter[cpu] = 0;
+#endif
 		goto try_again;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-stub.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-stub.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/gdb-stub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/gdb-stub.c	2011-01-04 19:50:19.000000000 -0500
@@ -440,15 +440,11 @@
 
 static int __gdbstub_mark_bp(u8 *addr, int ix)
 {
-	if (addr < (u8 *) 0x70000000UL)
-		return 0;
-	/* 70000000-7fffffff: vmalloc area */
-	if (addr < (u8 *) 0x80000000UL)
+	/* vmalloc area */
+	if (((u8 *) VMALLOC_START <= addr) && (addr < (u8 *) VMALLOC_END))
 		goto okay;
-	if (addr < (u8 *) 0x8c000000UL)
-		return 0;
-	/* 8c000000-93ffffff: SRAM, SDRAM */
-	if (addr < (u8 *) 0x94000000UL)
+	/* SRAM, SDRAM */
+	if (((u8 *) 0x80000000UL <= addr) && (addr < (u8 *) 0xa0000000UL))
 		goto okay;
 	return 0;
 
@@ -1197,9 +1193,9 @@
 	mn10300_set_gdbleds(1);
 
 	asm volatile("mov mdr,%0" : "=d"(mdr));
-	asm volatile("mov epsw,%0" : "=d"(epsw));
-	asm volatile("mov %0,epsw"
-		     :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1));
+	local_save_flags(epsw);
+	arch_local_change_intr_mask_level(
+		NUM2EPSW_IM(CONFIG_GDBSTUB_IRQ_LEVEL + 1));
 
 	gdbstub_store_fpu();
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/head.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/head.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,12 @@
 #include <asm/frame.inc>
 #include <asm/param.h>
 #include <unit/serial.h>
+#ifdef CONFIG_SMP
+#include <asm/smp.h>
+#include <asm/intctl-regs.h>
+#include <asm/cpu-regs.h>
+#include <proc/smp-regs.h>
+#endif /* CONFIG_SMP */
 
 	__HEAD
 
@@ -30,17 +36,51 @@
 	.globl	_start
 	.type	_start,@function
 _start:
+#ifdef CONFIG_SMP
+	#
+	# If this is a secondary CPU (AP), then deal with that elsewhere
+	#
+	mov	(CPUID),d3
+	and	CPUID_MASK,d3
+	bne	startup_secondary
+
+	#
+	# We're dealing with the primary CPU (BP) here, then.
+	# Keep BP's D0,D1,D2 register for boot check.
+	#
+
+	# Set up the Boot IPI for each secondary CPU
+	mov	0x1,a0
+loop_set_secondary_icr:
+	mov	a0,a1
+	asl	CROSS_ICR_CPU_SHIFT,a1
+	add	CROSS_GxICR(SMP_BOOT_IRQ,0),a1
+	movhu	(a1),d3
+	or	GxICR_ENABLE|GxICR_LEVEL_0,d3
+	movhu	d3,(a1)
+	movhu	(a1),d3				# flush
+	inc	a0
+	cmp	NR_CPUS,a0
+	bne	loop_set_secondary_icr
+#endif /* CONFIG_SMP */
+
 	# save commandline pointer
 	mov	d0,a3
 
 	# preload the PGD pointer register
 	mov	swapper_pg_dir,d0
 	mov	d0,(PTBR)
+	clr	d0
+	movbu	d0,(PIDR)
 
 	# turn on the TLBs
 	mov	MMUCTR_IIV|MMUCTR_DIV,d0
 	mov	d0,(MMUCTR)
+#ifdef CONFIG_AM34_2
+	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0
+#else
 	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
+#endif
 	mov	d0,(MMUCTR)
 
 	# turn on AM33v2 exception handling mode and set the trap table base
@@ -51,6 +91,11 @@
 	mov	d0,(TBR)
 
 	# invalidate and enable both of the caches
+#ifdef CONFIG_SMP
+	mov	ECHCTR,a0
+	clr	d0
+	mov	d0,(a0)
+#endif
 	mov	CHCTR,a0
 	clr	d0
 	movhu	d0,(a0)					# turn off first
@@ -61,18 +106,18 @@
 	btst	CHCTR_ICBUSY|CHCTR_DCBUSY,d0		# wait till not busy
 	lne
 
-#ifndef CONFIG_MN10300_CACHE_DISABLED
+#ifdef CONFIG_MN10300_CACHE_ENABLED
 #ifdef CONFIG_MN10300_CACHE_WBACK
 #ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
 	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
 #else
 	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
-#endif /* CACHE_DISABLED */
+#endif /* NOWRALLOC */
 #else
 	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
 #endif /* WBACK */
 	movhu	d0,(a0)					# enable
-#endif /* NOWRALLOC */
+#endif /* ENABLED */
 
 	# turn on RTS on the debug serial port if applicable
 #ifdef CONFIG_MN10300_UNIT_ASB2305
@@ -206,6 +251,44 @@
 	call	processor_init[],0
 	call	unit_init[],0
 
+#ifdef CONFIG_SMP
+	# mark the primary CPU in cpu_boot_map
+	mov	cpu_boot_map,a0
+	mov	0x1,d0
+	mov	d0,(a0)
+
+	# signal each secondary CPU to begin booting
+	mov	0x1,d2				# CPU ID
+
+loop_request_boot_secondary:
+	mov	d2,a0
+	# send SMP_BOOT_IPI to secondary CPU
+	asl	CROSS_ICR_CPU_SHIFT,a0
+	add	CROSS_GxICR(SMP_BOOT_IRQ,0),a0
+	movhu	(a0),d0
+	or	GxICR_REQUEST|GxICR_DETECT,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0				# flush
+
+	# wait up to 100ms for AP's IPI to be received
+	clr	d3
+wait_on_secondary_boot:
+	mov	DELAY_TIME_BOOT_IPI,d0
+	call	__delay[],0
+	inc	d3
+	mov	cpu_boot_map,a0
+	mov	(a0),d0
+	lsr	d2,d0
+	btst	0x1,d0
+	bne	1f
+	cmp	TIME_OUT_COUNT_BOOT_IPI,d3
+	bne	wait_on_secondary_boot
+1:
+	inc	d2
+	cmp	NR_CPUS,d2
+	bne	loop_request_boot_secondary
+#endif /* CONFIG_SMP */
+
 #ifdef CONFIG_GDBSTUB
 	call	gdbstub_init[],0
 
@@ -217,7 +300,118 @@
 #endif
 
 	jmp	start_kernel
-	.size	_start, _start-.
+	.size	_start,.-_start
+
+###############################################################################
+#
+# Secondary CPU boot point
+#
+###############################################################################
+#ifdef CONFIG_SMP
+startup_secondary:
+	# preload the PGD pointer register
+	mov	swapper_pg_dir,d0
+	mov	d0,(PTBR)
+	clr	d0
+	movbu	d0,(PIDR)
+
+	# turn on the TLBs
+	mov	MMUCTR_IIV|MMUCTR_DIV,d0
+	mov	d0,(MMUCTR)
+#ifdef CONFIG_AM34_2
+	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE|MMUCTR_WTE,d0
+#else
+	mov	MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
+#endif
+	mov	d0,(MMUCTR)
+
+	# turn on AM33v2 exception handling mode and set the trap table base
+	movhu	(CPUP),d0
+	or	CPUP_EXM_AM33V2,d0
+	movhu	d0,(CPUP)
+
+	# set the interrupt vector table
+	mov	CONFIG_INTERRUPT_VECTOR_BASE,d0
+	mov	d0,(TBR)
+
+	# invalidate and enable both of the caches
+	mov	ECHCTR,a0
+	clr	d0
+	mov	d0,(a0)
+	mov	CHCTR,a0
+	clr	d0
+	movhu	d0,(a0)					# turn off first
+	mov	CHCTR_ICINV|CHCTR_DCINV,d0
+	movhu	d0,(a0)
+	setlb
+	mov	(a0),d0
+	btst	CHCTR_ICBUSY|CHCTR_DCBUSY,d0		# wait till not busy (use CPU loop buffer)
+	lne
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+#ifdef  CONFIG_MN10300_CACHE_WBACK
+#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
+	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
+#else
+	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
+#endif  /* !NOWRALLOC */
+#else
+	mov	CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
+#endif  /* WBACK */
+	movhu	d0,(a0)					# enable
+#endif  /* ENABLED */
+
+	# Clear the boot IPI interrupt for this CPU
+	movhu	(GxICR(SMP_BOOT_IRQ)),d0
+	and	~GxICR_REQUEST,d0
+	movhu	d0,(GxICR(SMP_BOOT_IRQ))
+	movhu	(GxICR(SMP_BOOT_IRQ)),d0		# flush
+
+	/* get stack */
+	mov	CONFIG_INTERRUPT_VECTOR_BASE + CONFIG_BOOT_STACK_OFFSET,a0
+	mov	(CPUID),d0
+	and	CPUID_MASK,d0
+	mulu	CONFIG_BOOT_STACK_SIZE,d0
+	sub	d0,a0
+	mov	a0,sp
+
+	# init interrupt for AP
+	call	smp_prepare_cpu_init[],0
+
+	# mark this secondary CPU in cpu_boot_map
+	mov	(CPUID),d0
+	mov	0x1,d1
+	asl	d0,d1
+	mov	cpu_boot_map,a0
+	bset	d1,(a0)
+
+	or	EPSW_IE|EPSW_IM_1,epsw  # permit level 0 interrupts
+	nop
+	nop
+#ifdef  CONFIG_MN10300_CACHE_WBACK
+	# flush the local cache if it's in writeback mode
+	call	mn10300_local_dcache_flush_inv[],0
+	setlb
+	mov	(CHCTR),d0
+	btst	CHCTR_DCBUSY,d0		# wait till not busy (use CPU loop buffer)
+	lne
+#endif
+
+	# now sleep waiting for further instructions
+secondary_sleep:
+	mov	CPUM_SLEEP,d0
+	movhu	d0,(CPUM)
+	nop
+	nop
+	bra	secondary_sleep
+	.size	startup_secondary,.-startup_secondary
+#endif /* CONFIG_SMP */
+
+###############################################################################
+#
+#
+#
+###############################################################################
 ENTRY(__head_end)
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/internal.h linux-libre-2.6.37-gnu/arch/mn10300/kernel/internal.h
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/internal.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/internal.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,9 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+struct clocksource;
+struct clock_event_device;
+
 /*
  * kthread.S
  */
@@ -18,3 +21,25 @@
  * entry.S
  */
 extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
+
+/*
+ * smp-low.S
+ */
+#ifdef CONFIG_SMP
+extern void mn10300_low_ipi_handler(void);
+#endif
+
+/*
+ * time.c
+ */
+extern irqreturn_t local_timer_interrupt(void);
+
+/*
+ * time.c
+ */
+#ifdef CONFIG_CEVT_MN10300
+extern void clockevent_set_clock(struct clock_event_device *, unsigned int);
+#endif
+#ifdef CONFIG_CSRC_MN10300
+extern void clocksource_set_clock(struct clocksource *, unsigned int);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/irq.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,11 +12,26 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/seq_file.h>
+#include <linux/cpumask.h>
 #include <asm/setup.h>
+#include <asm/serial-regs.h>
 
-unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7;
+unsigned long __mn10300_irq_enabled_epsw[NR_CPUS] __cacheline_aligned_in_smp = {
+	[0 ... NR_CPUS - 1] = EPSW_IE | EPSW_IM_7
+};
 EXPORT_SYMBOL(__mn10300_irq_enabled_epsw);
 
+#ifdef CONFIG_SMP
+static char irq_affinity_online[NR_IRQS] = {
+	[0 ... NR_IRQS - 1] = 0
+};
+
+#define NR_IRQ_WORDS	((NR_IRQS + 31) / 32)
+static unsigned long irq_affinity_request[NR_IRQ_WORDS] = {
+	[0 ... NR_IRQ_WORDS - 1] = 0
+};
+#endif  /* CONFIG_SMP */
+
 atomic_t irq_err_count;
 
 /*
@@ -24,30 +39,67 @@
  */
 static void mn10300_cpupic_ack(unsigned int irq)
 {
+	unsigned long flags;
 	u16 tmp;
-	*(volatile u8 *) &GxICR(irq) = GxICR_DETECT;
+
+	flags = arch_local_cli_save();
+	GxICR_u8(irq) = GxICR_DETECT;
 	tmp = GxICR(irq);
+	arch_local_irq_restore(flags);
 }
 
-static void mn10300_cpupic_mask(unsigned int irq)
+static void __mask_and_set_icr(unsigned int irq,
+			       unsigned int mask, unsigned int set)
 {
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL);
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+	tmp = GxICR(irq);
+	GxICR(irq) = (tmp & mask) | set;
 	tmp = GxICR(irq);
+	arch_local_irq_restore(flags);
+}
+
+static void mn10300_cpupic_mask(unsigned int irq)
+{
+	__mask_and_set_icr(irq, GxICR_LEVEL, 0);
 }
 
 static void mn10300_cpupic_mask_ack(unsigned int irq)
 {
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
-	tmp = GxICR(irq);
+#ifdef CONFIG_SMP
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+
+	if (!test_and_clear_bit(irq, irq_affinity_request)) {
+		tmp = GxICR(irq);
+		GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+		tmp = GxICR(irq);
+	} else {
+		u16 tmp2;
+		tmp = GxICR(irq);
+		GxICR(irq) = (tmp & GxICR_LEVEL);
+		tmp2 = GxICR(irq);
+
+		irq_affinity_online[irq] =
+			any_online_cpu(*irq_desc[irq].affinity);
+		CROSS_GxICR(irq, irq_affinity_online[irq]) =
+			(tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
+		tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
+	}
+
+	arch_local_irq_restore(flags);
+#else  /* CONFIG_SMP */
+	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_DETECT);
+#endif /* CONFIG_SMP */
 }
 
 static void mn10300_cpupic_unmask(unsigned int irq)
 {
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
-	tmp = GxICR(irq);
+	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE);
 }
 
 static void mn10300_cpupic_unmask_clear(unsigned int irq)
@@ -56,10 +108,88 @@
 	 * device has ceased to assert its interrupt line and the interrupt
 	 * channel has been disabled in the PIC, so for level-triggered
 	 * interrupts we need to clear the request bit when we re-enable */
-	u16 tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
-	tmp = GxICR(irq);
+#ifdef CONFIG_SMP
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+
+	if (!test_and_clear_bit(irq, irq_affinity_request)) {
+		tmp = GxICR(irq);
+		GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+		tmp = GxICR(irq);
+	} else {
+		tmp = GxICR(irq);
+
+		irq_affinity_online[irq] = any_online_cpu(*irq_desc[irq].affinity);
+		CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
+		tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
+	}
+
+	arch_local_irq_restore(flags);
+#else  /* CONFIG_SMP */
+	__mask_and_set_icr(irq, GxICR_LEVEL, GxICR_ENABLE | GxICR_DETECT);
+#endif /* CONFIG_SMP */
+}
+
+#ifdef CONFIG_SMP
+static int
+mn10300_cpupic_setaffinity(unsigned int irq, const struct cpumask *mask)
+{
+	unsigned long flags;
+	int err;
+
+	flags = arch_local_cli_save();
+
+	/* check irq no */
+	switch (irq) {
+	case TMJCIRQ:
+	case RESCHEDULE_IPI:
+	case CALL_FUNC_SINGLE_IPI:
+	case LOCAL_TIMER_IPI:
+	case FLUSH_CACHE_IPI:
+	case CALL_FUNCTION_NMI_IPI:
+	case GDB_NMI_IPI:
+#ifdef CONFIG_MN10300_TTYSM0
+	case SC0RXIRQ:
+	case SC0TXIRQ:
+#ifdef CONFIG_MN10300_TTYSM0_TIMER8
+	case TM8IRQ:
+#elif CONFIG_MN10300_TTYSM0_TIMER2
+	case TM2IRQ:
+#endif /* CONFIG_MN10300_TTYSM0_TIMER8 */
+#endif /* CONFIG_MN10300_TTYSM0 */
+
+#ifdef CONFIG_MN10300_TTYSM1
+	case SC1RXIRQ:
+	case SC1TXIRQ:
+#ifdef CONFIG_MN10300_TTYSM1_TIMER12
+	case TM12IRQ:
+#elif CONFIG_MN10300_TTYSM1_TIMER9
+	case TM9IRQ:
+#elif CONFIG_MN10300_TTYSM1_TIMER3
+	case TM3IRQ:
+#endif /* CONFIG_MN10300_TTYSM1_TIMER12 */
+#endif /* CONFIG_MN10300_TTYSM1 */
+
+#ifdef CONFIG_MN10300_TTYSM2
+	case SC2RXIRQ:
+	case SC2TXIRQ:
+	case TM10IRQ:
+#endif /* CONFIG_MN10300_TTYSM2 */
+		err = -1;
+		break;
+
+	default:
+		set_bit(irq, irq_affinity_request);
+		err = 0;
+		break;
+	}
+
+	arch_local_irq_restore(flags);
+	return err;
 }
+#endif /* CONFIG_SMP */
 
 /*
  * MN10300 PIC level-triggered IRQ handling.
@@ -79,6 +209,9 @@
 	.mask		= mn10300_cpupic_mask,
 	.mask_ack	= mn10300_cpupic_mask,
 	.unmask		= mn10300_cpupic_unmask_clear,
+#ifdef CONFIG_SMP
+	.set_affinity	= mn10300_cpupic_setaffinity,
+#endif
 };
 
 /*
@@ -94,6 +227,9 @@
 	.mask		= mn10300_cpupic_mask,
 	.mask_ack	= mn10300_cpupic_mask_ack,
 	.unmask		= mn10300_cpupic_unmask,
+#ifdef CONFIG_SMP
+	.set_affinity	= mn10300_cpupic_setaffinity,
+#endif
 };
 
 /*
@@ -111,14 +247,34 @@
  */
 void set_intr_level(int irq, u16 level)
 {
-	u16 tmp;
+	BUG_ON(in_interrupt());
 
-	if (in_interrupt())
-		BUG();
+	__mask_and_set_icr(irq, GxICR_ENABLE, level);
+}
 
-	tmp = GxICR(irq);
-	GxICR(irq) = (tmp & GxICR_ENABLE) | level;
-	tmp = GxICR(irq);
+void mn10300_intc_set_level(unsigned int irq, unsigned int level)
+{
+	set_intr_level(irq, NUM2GxICR_LEVEL(level) & GxICR_LEVEL);
+}
+
+void mn10300_intc_clear(unsigned int irq)
+{
+	__mask_and_set_icr(irq, GxICR_LEVEL | GxICR_ENABLE, GxICR_DETECT);
+}
+
+void mn10300_intc_set(unsigned int irq)
+{
+	__mask_and_set_icr(irq, 0, GxICR_REQUEST | GxICR_DETECT);
+}
+
+void mn10300_intc_enable(unsigned int irq)
+{
+	mn10300_cpupic_unmask(irq);
+}
+
+void mn10300_intc_disable(unsigned int irq)
+{
+	mn10300_cpupic_mask(irq);
 }
 
 /*
@@ -126,7 +282,7 @@
  * than before
  * - see Documentation/mn10300/features.txt
  */
-void set_intr_postackable(int irq)
+void mn10300_set_lateack_irq_type(int irq)
 {
 	set_irq_chip_and_handler(irq, &mn10300_cpu_pic_level,
 				 handle_level_irq);
@@ -147,6 +303,7 @@
 			 * interrupts */
 			set_irq_chip_and_handler(irq, &mn10300_cpu_pic_edge,
 						 handle_level_irq);
+
 	unit_init_IRQ();
 }
 
@@ -156,20 +313,22 @@
 asmlinkage void do_IRQ(void)
 {
 	unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw;
+	unsigned int cpu_id = smp_processor_id();
 	int irq;
 
 	sp = current_stack_pointer();
-	if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN)
-		BUG();
+	BUG_ON(sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN);
 
 	/* make sure local_irq_enable() doesn't muck up the interrupt priority
 	 * setting in EPSW */
-	old_irq_enabled_epsw = __mn10300_irq_enabled_epsw;
+	old_irq_enabled_epsw = __mn10300_irq_enabled_epsw[cpu_id];
 	local_save_flags(epsw);
-	__mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw);
+	__mn10300_irq_enabled_epsw[cpu_id] = EPSW_IE | (EPSW_IM & epsw);
 	irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL;
 
-	__IRQ_STAT(smp_processor_id(), __irq_count)++;
+#ifdef CONFIG_MN10300_WD_TIMER
+	__IRQ_STAT(cpu_id, __irq_count)++;
+#endif
 
 	irq_enter();
 
@@ -189,7 +348,7 @@
 		local_irq_restore(epsw);
 	}
 
-	__mn10300_irq_enabled_epsw = old_irq_enabled_epsw;
+	__mn10300_irq_enabled_epsw[cpu_id] = old_irq_enabled_epsw;
 
 	irq_exit();
 }
@@ -222,9 +381,16 @@
 			seq_printf(p, "%3d: ", i);
 			for_each_present_cpu(cpu)
 				seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
-			seq_printf(p, " %14s.%u", irq_desc[i].chip->name,
-				   (GxICR(i) & GxICR_LEVEL) >>
-				   GxICR_LEVEL_SHIFT);
+
+			if (i < NR_CPU_IRQS)
+				seq_printf(p, " %14s.%u",
+					   irq_desc[i].chip->name,
+					   (GxICR(i) & GxICR_LEVEL) >>
+					   GxICR_LEVEL_SHIFT);
+			else
+				seq_printf(p, " %14s",
+					   irq_desc[i].chip->name);
+
 			seq_printf(p, "  %s", action->name);
 
 			for (action = action->next;
@@ -240,11 +406,13 @@
 
 		/* polish off with NMI and error counters */
 	case NR_IRQS:
+#ifdef CONFIG_MN10300_WD_TIMER
 		seq_printf(p, "NMI: ");
 		for (j = 0; j < NR_CPUS; j++)
 			if (cpu_online(j))
 				seq_printf(p, "%10u ", nmi_count(j));
 		seq_putc(p, '\n');
+#endif
 
 		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
 		break;
@@ -252,3 +420,51 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_HOTPLUG_CPU
+void migrate_irqs(void)
+{
+	irq_desc_t *desc;
+	int irq;
+	unsigned int self, new;
+	unsigned long flags;
+
+	self = smp_processor_id();
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		desc = irq_desc + irq;
+
+		if (desc->status == IRQ_PER_CPU)
+			continue;
+
+		if (cpu_isset(self, irq_desc[irq].affinity) &&
+		    !cpus_intersects(irq_affinity[irq], cpu_online_map)) {
+			int cpu_id;
+			cpu_id = first_cpu(cpu_online_map);
+			cpu_set(cpu_id, irq_desc[irq].affinity);
+		}
+		/* We need to operate irq_affinity_online atomically. */
+		arch_local_cli_save(flags);
+		if (irq_affinity_online[irq] == self) {
+			u16 x, tmp;
+
+			x = GxICR(irq);
+			GxICR(irq) = x & GxICR_LEVEL;
+			tmp = GxICR(irq);
+
+			new = any_online_cpu(irq_desc[irq].affinity);
+			irq_affinity_online[irq] = new;
+
+			CROSS_GxICR(irq, new) =
+				(x & GxICR_LEVEL) | GxICR_DETECT;
+			tmp = CROSS_GxICR(irq, new);
+
+			x &= GxICR_LEVEL | GxICR_ENABLE;
+			if (GxICR(irq) & GxICR_REQUEST)
+				x |= GxICR_REQUEST | GxICR_DETECT;
+			CROSS_GxICR(irq, new) = x;
+			tmp = CROSS_GxICR(irq, new);
+		}
+		arch_local_irq_restore(flags);
+	}
+}
+#endif /* CONFIG_HOTPLUG_CPU */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/kprobes.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/kprobes.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/kprobes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/kprobes.c	2011-01-04 19:50:19.000000000 -0500
@@ -377,8 +377,10 @@
 
 void __kprobes arch_disarm_kprobe(struct kprobe *p)
 {
+#ifndef CONFIG_MN10300_CACHE_SNOOP
 	mn10300_dcache_flush();
 	mn10300_icache_inv();
+#endif
 }
 
 void arch_remove_kprobe(struct kprobe *p)
@@ -390,8 +392,10 @@
 {
 	*p->addr = p->opcode;
 	regs->pc = (unsigned long) p->addr;
+#ifndef CONFIG_MN10300_CACHE_SNOOP
 	mn10300_dcache_flush();
 	mn10300_icache_inv();
+#endif
 }
 
 static inline
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/Makefile linux-libre-2.6.37-gnu/arch/mn10300/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,13 +3,16 @@
 #
 extra-y := head.o init_task.o vmlinux.lds
 
-obj-y   := process.o signal.o entry.o fpu.o traps.o irq.o \
+fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o
+fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o
+
+obj-y   := process.o signal.o entry.o traps.o irq.o \
 	   ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
-	   switch_to.o mn10300_ksyms.o kernel_execve.o
+	   switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y)
 
-obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
+obj-$(CONFIG_SMP) += smp.o smp-low.o
 
-obj-$(CONFIG_FPU) += fpu-low.o
+obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
 
 obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \
 			       mn10300-debug.o
@@ -17,7 +20,7 @@
 obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o
 obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o
 
-ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
+ifeq ($(CONFIG_MN10300_CACHE_ENABLED),y)
 obj-$(CONFIG_GDBSTUB) += gdb-cache.o
 endif
 
@@ -25,3 +28,5 @@
 obj-$(CONFIG_PROFILE) += profile.o profile-low.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_CSRC_MN10300) += csrc-mn10300.o
+obj-$(CONFIG_CEVT_MN10300) += cevt-mn10300.o
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-serial.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-serial.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,11 @@
 #include <unit/timex.h>
 #include "mn10300-serial.h"
 
+#ifdef CONFIG_SMP
+#undef  GxICR
+#define GxICR(X) CROSS_GxICR(X, 0)
+#endif /* CONFIG_SMP */
+
 #define kenter(FMT, ...) \
 	printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)
 #define _enter(FMT, ...) \
@@ -57,6 +62,11 @@
 #define _proto(FMT, ...) \
 	no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__)
 
+#ifndef CODMSB
+/* c_cflag bit meaning */
+#define CODMSB	004000000000	/* change Transfer bit-order */
+#endif
+
 #define NR_UARTS 3
 
 #ifdef CONFIG_MN10300_TTYSM_CONSOLE
@@ -152,26 +162,35 @@
 	.name		= "ttySM0",
 	._iobase	= &SC0CTR,
 	._control	= &SC0CTR,
-	._status	= (volatile u8 *) &SC0STR,
+	._status	= (volatile u8 *)&SC0STR,
 	._intr		= &SC0ICR,
 	._rxb		= &SC0RXB,
 	._txb		= &SC0TXB,
 	.rx_name	= "ttySM0:Rx",
 	.tx_name	= "ttySM0:Tx",
-#ifdef CONFIG_MN10300_TTYSM0_TIMER8
+#if defined(CONFIG_MN10300_TTYSM0_TIMER8)
 	.tm_name	= "ttySM0:Timer8",
 	._tmxmd		= &TM8MD,
 	._tmxbr		= &TM8BR,
 	._tmicr		= &TM8ICR,
 	.tm_irq		= TM8IRQ,
 	.div_timer	= MNSCx_DIV_TIMER_16BIT,
-#else /* CONFIG_MN10300_TTYSM0_TIMER2 */
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER0)
+	.tm_name	= "ttySM0:Timer0",
+	._tmxmd		= &TM0MD,
+	._tmxbr		= (volatile u16 *)&TM0BR,
+	._tmicr		= &TM0ICR,
+	.tm_irq		= TM0IRQ,
+	.div_timer	= MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)
 	.tm_name	= "ttySM0:Timer2",
 	._tmxmd		= &TM2MD,
-	._tmxbr		= (volatile u16 *) &TM2BR,
+	._tmxbr		= (volatile u16 *)&TM2BR,
 	._tmicr		= &TM2ICR,
 	.tm_irq		= TM2IRQ,
 	.div_timer	= MNSCx_DIV_TIMER_8BIT,
+#else
+#error "Unknown config for ttySM0"
 #endif
 	.rx_irq		= SC0RXIRQ,
 	.tx_irq		= SC0TXIRQ,
@@ -205,26 +224,35 @@
 	.name		= "ttySM1",
 	._iobase	= &SC1CTR,
 	._control	= &SC1CTR,
-	._status	= (volatile u8 *) &SC1STR,
+	._status	= (volatile u8 *)&SC1STR,
 	._intr		= &SC1ICR,
 	._rxb		= &SC1RXB,
 	._txb		= &SC1TXB,
 	.rx_name	= "ttySM1:Rx",
 	.tx_name	= "ttySM1:Tx",
-#ifdef CONFIG_MN10300_TTYSM1_TIMER9
+#if defined(CONFIG_MN10300_TTYSM1_TIMER9)
 	.tm_name	= "ttySM1:Timer9",
 	._tmxmd		= &TM9MD,
 	._tmxbr		= &TM9BR,
 	._tmicr		= &TM9ICR,
 	.tm_irq		= TM9IRQ,
 	.div_timer	= MNSCx_DIV_TIMER_16BIT,
-#else /* CONFIG_MN10300_TTYSM1_TIMER3 */
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
 	.tm_name	= "ttySM1:Timer3",
 	._tmxmd		= &TM3MD,
-	._tmxbr		= (volatile u16 *) &TM3BR,
+	._tmxbr		= (volatile u16 *)&TM3BR,
 	._tmicr		= &TM3ICR,
 	.tm_irq		= TM3IRQ,
 	.div_timer	= MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER12)
+	.tm_name	= "ttySM1/Timer12",
+	._tmxmd		= &TM12MD,
+	._tmxbr		= &TM12BR,
+	._tmicr		= &TM12ICR,
+	.tm_irq		= TM12IRQ,
+	.div_timer	= MNSCx_DIV_TIMER_16BIT,
+#else
+#error "Unknown config for ttySM1"
 #endif
 	.rx_irq		= SC1RXIRQ,
 	.tx_irq		= SC1TXIRQ,
@@ -260,20 +288,45 @@
 	.uart.lock	=
 	__SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock),
 	.name		= "ttySM2",
-	.rx_name	= "ttySM2:Rx",
-	.tx_name	= "ttySM2:Tx",
-	.tm_name	= "ttySM2:Timer10",
 	._iobase	= &SC2CTR,
 	._control	= &SC2CTR,
-	._status	= &SC2STR,
+	._status	= (volatile u8 *)&SC2STR,
 	._intr		= &SC2ICR,
 	._rxb		= &SC2RXB,
 	._txb		= &SC2TXB,
+	.rx_name	= "ttySM2:Rx",
+	.tx_name	= "ttySM2:Tx",
+#if defined(CONFIG_MN10300_TTYSM2_TIMER10)
+	.tm_name	= "ttySM2/Timer10",
 	._tmxmd		= &TM10MD,
 	._tmxbr		= &TM10BR,
 	._tmicr		= &TM10ICR,
 	.tm_irq		= TM10IRQ,
 	.div_timer	= MNSCx_DIV_TIMER_16BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER9)
+	.tm_name	= "ttySM2/Timer9",
+	._tmxmd		= &TM9MD,
+	._tmxbr		= &TM9BR,
+	._tmicr		= &TM9ICR,
+	.tm_irq		= TM9IRQ,
+	.div_timer	= MNSCx_DIV_TIMER_16BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER1)
+	.tm_name	= "ttySM2/Timer1",
+	._tmxmd		= &TM1MD,
+	._tmxbr		= (volatile u16 *)&TM1BR,
+	._tmicr		= &TM1ICR,
+	.tm_irq		= TM1IRQ,
+	.div_timer	= MNSCx_DIV_TIMER_8BIT,
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER3)
+	.tm_name	= "ttySM2/Timer3",
+	._tmxmd		= &TM3MD,
+	._tmxbr		= (volatile u16 *)&TM3BR,
+	._tmicr		= &TM3ICR,
+	.tm_irq		= TM3IRQ,
+	.div_timer	= MNSCx_DIV_TIMER_8BIT,
+#else
+#error "Unknown config for ttySM2"
+#endif
 	.rx_irq		= SC2RXIRQ,
 	.tx_irq		= SC2TXIRQ,
 	.rx_icr		= &GxICR(SC2RXIRQ),
@@ -322,9 +375,13 @@
  */
 static void mn10300_serial_mask_ack(unsigned int irq)
 {
+	unsigned long flags;
 	u16 tmp;
+
+	flags = arch_local_cli_save();
 	GxICR(irq) = GxICR_LEVEL_6;
 	tmp = GxICR(irq); /* flush write buffer */
+	arch_local_irq_restore(flags);
 }
 
 static void mn10300_serial_nop(unsigned int irq)
@@ -348,23 +405,36 @@
 
 static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)
 {
+	unsigned long flags;
 	u16 x;
-	*port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
+
+	flags = arch_local_cli_save();
+	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
 	x = *port->tx_icr;
+	arch_local_irq_restore(flags);
 }
 
 static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)
 {
+	unsigned long flags;
 	u16 x;
-	*port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE;
+
+	flags = arch_local_cli_save();
+	*port->tx_icr =
+		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL) | GxICR_ENABLE;
 	x = *port->tx_icr;
+	arch_local_irq_restore(flags);
 }
 
 static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)
 {
+	unsigned long flags;
 	u16 x;
-	*port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
+
+	flags = arch_local_cli_save();
+	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
 	x = *port->rx_icr;
+	arch_local_irq_restore(flags);
 }
 
 /*
@@ -650,7 +720,7 @@
 static void mn10300_serial_set_mctrl(struct uart_port *_port,
 				     unsigned int mctrl)
 {
-	struct mn10300_serial_port *port =
+	struct mn10300_serial_port *port __attribute__ ((unused)) =
 		container_of(_port, struct mn10300_serial_port, uart);
 
 	_enter("%s,%x", port->name, mctrl);
@@ -706,6 +776,7 @@
 			UART_XMIT_SIZE));
 
 	/* kick the virtual DMA controller */
+	arch_local_cli();
 	x = *port->tx_icr;
 	x |= GxICR_ENABLE;
 
@@ -716,10 +787,14 @@
 
 	_debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",
 	       *port->_control, *port->_intr, *port->_status,
-	       *port->_tmxmd, *port->_tmxbr, *port->tx_icr);
+	       *port->_tmxmd,
+	       (port->div_timer == MNSCx_DIV_TIMER_8BIT) ?
+	           *(volatile u8 *)port->_tmxbr : *port->_tmxbr,
+	       *port->tx_icr);
 
 	*port->tx_icr = x;
 	x = *port->tx_icr;
+	arch_local_sti();
 }
 
 /*
@@ -842,8 +917,10 @@
 	pint->port = port;
 	pint->vdma = mn10300_serial_vdma_tx_handler;
 
-	set_intr_level(port->rx_irq, GxICR_LEVEL_1);
-	set_intr_level(port->tx_irq, GxICR_LEVEL_1);
+	set_intr_level(port->rx_irq,
+		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
+	set_intr_level(port->tx_irq,
+		NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL));
 	set_irq_chip(port->tm_irq, &mn10300_serial_pic);
 
 	if (request_irq(port->rx_irq, mn10300_serial_interrupt,
@@ -876,6 +953,7 @@
  */
 static void mn10300_serial_shutdown(struct uart_port *_port)
 {
+	u16 x;
 	struct mn10300_serial_port *port =
 		container_of(_port, struct mn10300_serial_port, uart);
 
@@ -897,8 +975,12 @@
 	free_irq(port->rx_irq, port);
 	free_irq(port->tx_irq, port);
 
-	*port->rx_icr = GxICR_LEVEL_1;
-	*port->tx_icr = GxICR_LEVEL_1;
+	arch_local_cli();
+	*port->rx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+	x = *port->rx_icr;
+	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
+	x = *port->tx_icr;
+	arch_local_sti();
 }
 
 /*
@@ -947,11 +1029,66 @@
 	/* Determine divisor based on baud rate */
 	battempt = 0;
 
-	if (div_timer == MNSCx_DIV_TIMER_16BIT)
-		scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8
-						 *   == SC2CTR_CK_TM10UFLOW) */
-	else if (div_timer == MNSCx_DIV_TIMER_8BIT)
+	switch (port->uart.line) {
+#ifdef CONFIG_MN10300_TTYSM0
+	case 0: /* ttySM0 */
+#if   defined(CONFIG_MN10300_TTYSM0_TIMER8)
+		scxctr |= SC0CTR_CK_TM8UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER0)
+		scxctr |= SC0CTR_CK_TM0UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM0_TIMER2)
 		scxctr |= SC0CTR_CK_TM2UFLOW_8;
+#else
+#error "Unknown config for ttySM0"
+#endif
+		break;
+#endif /* CONFIG_MN10300_TTYSM0 */
+
+#ifdef CONFIG_MN10300_TTYSM1
+	case 1: /* ttySM1 */
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+#if   defined(CONFIG_MN10300_TTYSM1_TIMER9)
+		scxctr |= SC1CTR_CK_TM9UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM1_TIMER3)
+		scxctr |= SC1CTR_CK_TM3UFLOW_8;
+#else
+#error "Unknown config for ttySM1"
+#endif
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+#if defined(CONFIG_MN10300_TTYSM1_TIMER12)
+		scxctr |= SC1CTR_CK_TM12UFLOW_8;
+#else
+#error "Unknown config for ttySM1"
+#endif
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+		break;
+#endif /* CONFIG_MN10300_TTYSM1 */
+
+#ifdef CONFIG_MN10300_TTYSM2
+	case 2: /* ttySM2 */
+#if defined(CONFIG_AM33_2)
+#if   defined(CONFIG_MN10300_TTYSM2_TIMER10)
+		scxctr |= SC2CTR_CK_TM10UFLOW;
+#else
+#error "Unknown config for ttySM2"
+#endif
+#else /* CONFIG_AM33_2 */
+#if   defined(CONFIG_MN10300_TTYSM2_TIMER9)
+		scxctr |= SC2CTR_CK_TM9UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER1)
+		scxctr |= SC2CTR_CK_TM1UFLOW_8;
+#elif defined(CONFIG_MN10300_TTYSM2_TIMER3)
+		scxctr |= SC2CTR_CK_TM3UFLOW_8;
+#else
+#error "Unknown config for ttySM2"
+#endif
+#endif /* CONFIG_AM33_2 */
+		break;
+#endif /* CONFIG_MN10300_TTYSM2 */
+
+	default:
+		break;
+	}
 
 try_alternative:
 	baud = uart_get_baud_rate(&port->uart, new, old, 0,
@@ -1195,6 +1332,12 @@
 		ctr &= ~SC2CTR_TWE;
 		*port->_control = ctr;
 	}
+
+	/* change Transfer bit-order (LSB/MSB) */
+	if (new->c_cflag & CODMSB)
+		*port->_control |= SC01CTR_OD_MSBFIRST; /* MSB MODE */
+	else
+		*port->_control &= ~SC01CTR_OD_MSBFIRST; /* LSB MODE */
 }
 
 /*
@@ -1302,11 +1445,16 @@
 	printk(KERN_INFO "%s version %s (%s)\n",
 	       serial_name, serial_version, serial_revdate);
 
-#ifdef CONFIG_MN10300_TTYSM2
-	SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */
+#if defined(CONFIG_MN10300_TTYSM2) && defined(CONFIG_AM33_2)
+	{
+		int tmp;
+		SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */
+		tmp = SC2TIM;
+	}
 #endif
 
-	set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt);
+	set_intr_stub(NUM2EXCEP_IRQ_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL),
+		mn10300_serial_vdma_interrupt);
 
 	ret = uart_register_driver(&mn10300_serial_driver);
 	if (!ret) {
@@ -1366,9 +1514,11 @@
 	port = mn10300_serial_ports[co->index];
 
 	/* firstly hijack the serial port from the "virtual DMA" controller */
+	arch_local_cli();
 	txicr = *port->tx_icr;
-	*port->tx_icr = GxICR_LEVEL_1;
+	*port->tx_icr = NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL);
 	tmp = *port->tx_icr;
+	arch_local_sti();
 
 	/* the transmitter may be disabled */
 	scxctr = *port->_control;
@@ -1422,8 +1572,10 @@
 	if (!(scxctr & SC01CTR_TXE))
 		*port->_control = scxctr;
 
+	arch_local_cli();
 	*port->tx_icr = txicr;
 	tmp = *port->tx_icr;
+	arch_local_sti();
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-serial-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-serial-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-serial-low.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-serial-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 ###############################################################################
 	.balign	L1_CACHE_BYTES
 ENTRY(mn10300_serial_vdma_interrupt)
-	or	EPSW_IE,psw			# permit overriding by
+#	or	EPSW_IE,psw			# permit overriding by
 						# debugging interrupts
 	movm	[d2,d3,a2,a3,exreg0],(sp)
 
@@ -164,7 +164,7 @@
 	rti
 
 mnsc_vdma_tx_empty:
-	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2
+	mov	+(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2
 	movhu	d2,(e3)			# disable the interrupt
 	movhu	(e3),d2			# flush
 
@@ -175,7 +175,7 @@
 	movhu	(SCxCTR,e2),d2		# turn on break mode
 	or	SC01CTR_BKE,d2
 	movhu	d2,(SCxCTR,e2)
-	mov	+(GxICR_LEVEL_1|GxICR_DETECT),d2
+	mov	+(NUM2GxICR_LEVEL(CONFIG_MN10300_SERIAL_IRQ_LEVEL)|GxICR_DETECT),d2
 	movhu	d2,(e3)			# disable transmit interrupts on this
 					# channel
 	movhu	(e3),d2			# flush
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-watchdog.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-watchdog.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-watchdog.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-watchdog.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,7 @@
 static DEFINE_SPINLOCK(watchdog_print_lock);
 static unsigned int watchdog;
 static unsigned int watchdog_hz = 1;
-unsigned int watchdog_alert_counter;
+unsigned int watchdog_alert_counter[NR_CPUS];
 
 EXPORT_SYMBOL(touch_nmi_watchdog);
 
@@ -39,9 +39,6 @@
  * is to check its timer makes IRQ counts. If they are not
  * changing then that CPU has some problem.
  *
- * as these watchdog NMI IRQs are generated on every CPU, we only
- * have to check the current processor.
- *
  * since NMIs dont listen to _any_ locks, we have to be extremely
  * careful not to rely on unsafe variables. The printk might lock
  * up though, so we have to break up any console locks first ...
@@ -69,8 +66,8 @@
 
 	printk(KERN_INFO "OK.\n");
 
-	/* now that we know it works we can reduce NMI frequency to
-	 * something more reasonable; makes a difference in some configs
+	/* now that we know it works we can reduce NMI frequency to something
+	 * more reasonable; makes a difference in some configs
 	 */
 	watchdog_hz = 1;
 
@@ -121,15 +118,22 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+static void watchdog_dump_register(void *dummy)
+{
+	printk(KERN_ERR "--- Register Dump (CPU%d) ---\n", CPUID);
+	show_registers(current_frame());
+}
+#endif
+
 asmlinkage
 void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
 {
-
 	/*
 	 * Since current-> is always on the stack, and we always switch
 	 * the stack NMI-atomically, it's safe to use smp_processor_id().
 	 */
-	int sum, cpu = smp_processor_id();
+	int sum, cpu;
 	int irq = NMIIRQ;
 	u8 wdt, tmp;
 
@@ -138,43 +142,61 @@
 	tmp = WDCTR;
 	NMICR = NMICR_WDIF;
 
-	nmi_count(cpu)++;
+	nmi_count(smp_processor_id())++;
 	kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
-	sum = irq_stat[cpu].__irq_count;
 
-	if (last_irq_sums[cpu] == sum) {
-		/*
-		 * Ayiee, looks like this CPU is stuck ...
-		 * wait a few IRQs (5 seconds) before doing the oops ...
-		 */
-		watchdog_alert_counter++;
-		if (watchdog_alert_counter == 5 * watchdog_hz) {
-			spin_lock(&watchdog_print_lock);
+	for_each_online_cpu(cpu) {
+
+		sum = irq_stat[cpu].__irq_count;
+
+		if ((last_irq_sums[cpu] == sum)
+#if defined(CONFIG_GDBSTUB) && defined(CONFIG_SMP)
+			&& !(CHK_GDBSTUB_BUSY()
+			     || atomic_read(&cpu_doing_single_step))
+#endif
+			) {
 			/*
-			 * We are in trouble anyway, lets at least try
-			 * to get a message out.
+			 * Ayiee, looks like this CPU is stuck ...
+			 * wait a few IRQs (5 seconds) before doing the oops ...
 			 */
-			bust_spinlocks(1);
-			printk(KERN_ERR
-			       "NMI Watchdog detected LOCKUP on CPU%d,"
-			       " pc %08lx, registers:\n",
-			       cpu, regs->pc);
-			show_registers(regs);
-			printk("console shuts up ...\n");
-			console_silent();
-			spin_unlock(&watchdog_print_lock);
-			bust_spinlocks(0);
+			watchdog_alert_counter[cpu]++;
+			if (watchdog_alert_counter[cpu] == 5 * watchdog_hz) {
+				spin_lock(&watchdog_print_lock);
+				/*
+				 * We are in trouble anyway, lets at least try
+				 * to get a message out.
+				 */
+				bust_spinlocks(1);
+				printk(KERN_ERR
+				       "NMI Watchdog detected LOCKUP on CPU%d,"
+				       " pc %08lx, registers:\n",
+				       cpu, regs->pc);
+#ifdef CONFIG_SMP
+				printk(KERN_ERR
+				       "--- Register Dump (CPU%d) ---\n",
+				       CPUID);
+#endif
+				show_registers(regs);
+#ifdef CONFIG_SMP
+				smp_nmi_call_function(watchdog_dump_register,
+					NULL, 1);
+#endif
+				printk(KERN_NOTICE "console shuts up ...\n");
+				console_silent();
+				spin_unlock(&watchdog_print_lock);
+				bust_spinlocks(0);
 #ifdef CONFIG_GDBSTUB
-			if (gdbstub_busy)
-				gdbstub_exception(regs, excep);
-			else
-				gdbstub_intercept(regs, excep);
+				if (CHK_GDBSTUB_BUSY_AND_ACTIVE())
+					gdbstub_exception(regs, excep);
+				else
+					gdbstub_intercept(regs, excep);
 #endif
-			do_exit(SIGSEGV);
+				do_exit(SIGSEGV);
+			}
+		} else {
+			last_irq_sums[cpu] = sum;
+			watchdog_alert_counter[cpu] = 0;
 		}
-	} else {
-		last_irq_sums[cpu] = sum;
-		watchdog_alert_counter = 0;
 	}
 
 	WDCTR = wdt | WDCTR_WDRST;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-watchdog-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-watchdog-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/mn10300-watchdog-low.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/mn10300-watchdog-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <asm/intctl-regs.h>
 #include <asm/timer-regs.h>
 #include <asm/frame.inc>
+#include <linux/threads.h>
 
 	.text
 
@@ -53,7 +54,13 @@
 	.type	touch_nmi_watchdog,@function
 touch_nmi_watchdog:
 	clr	d0
-	mov	d0,(watchdog_alert_counter)
+	clr	d1
+	mov	watchdog_alert_counter, a0
+	setlb
+	mov	d0, (a0+)
+	inc	d1
+	cmp	NR_CPUS, d1
+	lne
 	ret	[],0
 
 	.size	touch_nmi_watchdog,.-touch_nmi_watchdog
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/process.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
@@ -57,6 +56,7 @@
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
+#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
 /*
  * we use this if we don't have any better idle routine
  */
@@ -69,6 +69,35 @@
 		local_irq_enable();
 }
 
+#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU  */
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static inline void poll_idle(void)
+{
+	int oldval;
+
+	local_irq_enable();
+
+	/*
+	 * Deal with another CPU just having chosen a thread to
+	 * run here:
+	 */
+	oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+	if (!oldval) {
+		set_thread_flag(TIF_POLLING_NRFLAG);
+		while (!need_resched())
+			cpu_relax();
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+	} else {
+		set_need_resched();
+	}
+}
+#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */
+
 /*
  * the idle thread
  * - there's no useful work to be done, so just try to conserve power and have
@@ -77,8 +106,6 @@
  */
 void cpu_idle(void)
 {
-	int cpu = smp_processor_id();
-
 	/* endless idle loop with no priority at all */
 	for (;;) {
 		while (!need_resched()) {
@@ -86,10 +113,13 @@
 
 			smp_rmb();
 			idle = pm_idle;
-			if (!idle)
+			if (!idle) {
+#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
+				idle = poll_idle;
+#else  /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
 				idle = default_idle;
-
-			irq_stat[cpu].idle_timestamp = jiffies;
+#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
+			}
 			idle();
 		}
 
@@ -197,6 +227,7 @@
 		unsigned long c_usp, unsigned long ustk_size,
 		struct task_struct *p, struct pt_regs *kregs)
 {
+	struct thread_info *ti = task_thread_info(p);
 	struct pt_regs *c_uregs, *c_kregs, *uregs;
 	unsigned long c_ksp;
 
@@ -217,7 +248,7 @@
 
 	/* the new TLS pointer is passed in as arg #5 to sys_clone() */
 	if (clone_flags & CLONE_SETTLS)
-		c_uregs->e2 = __frame->d3;
+		c_uregs->e2 = current_frame()->d3;
 
 	/* set up the return kernel frame if called from kernel_thread() */
 	c_kregs = c_uregs;
@@ -235,7 +266,7 @@
 	}
 
 	/* set up things up so the scheduler can start the new task */
-	p->thread.__frame = c_kregs;
+	ti->frame	= c_kregs;
 	p->thread.a3	= (unsigned long) c_kregs;
 	p->thread.sp	= c_ksp;
 	p->thread.pc	= (unsigned long) ret_from_fork;
@@ -247,25 +278,26 @@
 
 /*
  * clone a process
- * - tlsptr is retrieved by copy_thread() from __frame->d3
+ * - tlsptr is retrieved by copy_thread() from current_frame()->d3
  */
 asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
 			  int __user *parent_tidptr, int __user *child_tidptr,
 			  int __user *tlsptr)
 {
-	return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0,
-		       parent_tidptr, child_tidptr);
+	return do_fork(clone_flags, newsp ?: current_frame()->sp,
+		       current_frame(), 0, parent_tidptr, child_tidptr);
 }
 
 asmlinkage long sys_fork(void)
 {
-	return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL);
+	return do_fork(SIGCHLD, current_frame()->sp,
+		       current_frame(), 0, NULL, NULL);
 }
 
 asmlinkage long sys_vfork(void)
 {
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame,
-		       0, NULL, NULL);
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, current_frame()->sp,
+		       current_frame(), 0, NULL, NULL);
 }
 
 asmlinkage long sys_execve(const char __user *name,
@@ -279,7 +311,7 @@
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		return error;
-	error = do_execve(filename, argv, envp, __frame);
+	error = do_execve(filename, argv, envp, current_frame());
 	putname(filename);
 	return error;
 }
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/profile.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/profile.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/profile.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/profile.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 	tmp = TM11ICR;
 
 	printk(KERN_INFO "Profiling initiated on timer 11, priority 0, %uHz\n",
-	       mn10300_ioclk / 8 / (TM11BR + 1));
+	       MN10300_IOCLK / 8 / (TM11BR + 1));
 	printk(KERN_INFO "Profile histogram stored %p-%p\n",
 	       prof_buffer, (u8 *)(prof_buffer + prof_len) - 1);
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -295,31 +295,31 @@
 /*
  * handle the arch-specific side of process tracing
  */
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long tmp;
 	int ret;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 	/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 3) || addr > sizeof(struct user) - 3)
 			break;
 
 		tmp = 0;  /* Default return condition */
 		if (addr < NR_PTREGS << 2)
 			tmp = get_stack_long(child,
 					     ptrace_regid_to_frame[addr]);
-		ret = put_user(tmp, (unsigned long *) data);
+		ret = put_user(tmp, datap);
 		break;
 
 		/* write the word at location addr in the USER area */
 	case PTRACE_POKEUSR:
 		ret = -EIO;
-		if ((addr & 3) || addr < 0 ||
-		    addr > sizeof(struct user) - 3)
+		if ((addr & 3) || addr > sizeof(struct user) - 3)
 			break;
 
 		ret = 0;
@@ -332,25 +332,25 @@
 		return copy_regset_to_user(child, &user_mn10300_native_view,
 					   REGSET_GENERAL,
 					   0, NR_PTREGS * sizeof(long),
-					   (void __user *)data);
+					   datap);
 
 	case PTRACE_SETREGS:	/* Set all integer regs in the child. */
 		return copy_regset_from_user(child, &user_mn10300_native_view,
 					     REGSET_GENERAL,
 					     0, NR_PTREGS * sizeof(long),
-					     (const void __user *)data);
+					     datap);
 
 	case PTRACE_GETFPREGS:	/* Get the child FPU state. */
 		return copy_regset_to_user(child, &user_mn10300_native_view,
 					   REGSET_FPU,
 					   0, sizeof(struct fpu_state_struct),
-					   (void __user *)data);
+					   datap);
 
 	case PTRACE_SETFPREGS:	/* Set the child FPU state. */
 		return copy_regset_from_user(child, &user_mn10300_native_view,
 					     REGSET_FPU,
 					     0, sizeof(struct fpu_state_struct),
-					     (const void __user *)data);
+					     datap);
 
 	default:
 		ret = ptrace_request(child, request, addr, data);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/rtc.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/rtc.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/rtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/rtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,18 +20,22 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
-/* time for RTC to update itself in ioclks */
-static unsigned long mn10300_rtc_update_period;
-
+/*
+ * Read the current RTC time
+ */
 void read_persistent_clock(struct timespec *ts)
 {
 	struct rtc_time tm;
 
 	get_rtc_time(&tm);
 
-	ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
-		      tm.tm_hour, tm.tm_min, tm.tm_sec);
 	ts->tv_nsec = 0;
+	ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
+			    tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	/* if rtc is way off in the past, set something reasonable */
+	if (ts->tv_sec < 0)
+		ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0);
 }
 
 /*
@@ -115,39 +119,14 @@
  */
 void __init calibrate_clock(void)
 {
-	unsigned long count0, counth, count1;
 	unsigned char status;
 
 	/* make sure the RTC is running and is set to operate in 24hr mode */
 	status = RTSRC;
 	RTCRB |= RTCRB_SET;
 	RTCRB |= RTCRB_TM_24HR;
+	RTCRB &= ~RTCRB_DM_BINARY;
 	RTCRA |= RTCRA_DVR;
 	RTCRA &= ~RTCRA_DVR;
 	RTCRB &= ~RTCRB_SET;
-
-	/* work out the clock speed by counting clock cycles between ends of
-	 * the RTC update cycle - track the RTC through one complete update
-	 * cycle (1 second)
-	 */
-	startup_timestamp_counter();
-
-	while (!(RTCRA & RTCRA_UIP)) {}
-	while ((RTCRA & RTCRA_UIP)) {}
-
-	count0 = TMTSCBC;
-
-	while (!(RTCRA & RTCRA_UIP)) {}
-
-	counth = TMTSCBC;
-
-	while ((RTCRA & RTCRA_UIP)) {}
-
-	count1 = TMTSCBC;
-
-	shutdown_timestamp_counter();
-
-	MN10300_TSCCLK = count0 - count1; /* the timers count down */
-	mn10300_rtc_update_period = counth - count1;
-	MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ;
 }
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/setup.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
+#include <linux/cpu.h>
 #include <asm/processor.h>
 #include <linux/console.h>
 #include <asm/uaccess.h>
@@ -30,7 +31,6 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <proc/proc.h>
-#include <asm/busctl-regs.h>
 #include <asm/fpu.h>
 #include <asm/sections.h>
 
@@ -64,11 +64,13 @@
 struct thread_info *__current_ti = &init_thread_union.thread_info;
 struct task_struct *__current = &init_task;
 
-#define mn10300_known_cpus 3
+#define mn10300_known_cpus 5
 static const char *const mn10300_cputypes[] = {
-	"am33v1",
-	"am33v2",
-	"am34v1",
+	"am33-1",
+	"am33-2",
+	"am34-1",
+	"am33-3",
+	"am34-2",
 	"unknown"
 };
 
@@ -123,6 +125,7 @@
 
 	cpu_init();
 	unit_setup();
+	smp_init_cpus();
 	parse_mem_cmdline(cmdline_p);
 
 	init_mm.start_code = (unsigned long)&_text;
@@ -179,57 +182,55 @@
 void __init cpu_init(void)
 {
 	unsigned long cpurev = CPUREV, type;
-	unsigned long base, size;
 
 	type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
 	if (type > mn10300_known_cpus)
 		type = mn10300_known_cpus;
 
-	printk(KERN_INFO "Matsushita %s, rev %ld\n",
+	printk(KERN_INFO "Panasonic %s, rev %ld\n",
 	       mn10300_cputypes[type],
 	       (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S);
 
-	/* determine the memory size and base from the memory controller regs */
-	memory_size = 0;
-
-	base = SDBASE(0);
-	if (base & SDBASE_CE) {
-		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
-		size = ~size + 1;
-		base &= SDBASE_CBA;
+	get_mem_info(&phys_memory_base, &memory_size);
+	phys_memory_end = phys_memory_base + memory_size;
 
-		printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base);
-		memory_size += size;
-		phys_memory_base = base;
-	}
+	fpu_init_state();
+}
 
-	base = SDBASE(1);
-	if (base & SDBASE_CE) {
-		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
-		size = ~size + 1;
-		base &= SDBASE_CBA;
+static struct cpu cpu_devices[NR_CPUS];
 
-		printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base);
-		memory_size += size;
-		if (phys_memory_base == 0)
-			phys_memory_base = base;
-	}
+static int __init topology_init(void)
+{
+	int i;
 
-	phys_memory_end = phys_memory_base + memory_size;
+	for_each_present_cpu(i)
+		register_cpu(&cpu_devices[i], i);
 
-#ifdef CONFIG_FPU
-	fpu_init_state();
-#endif
+	return 0;
 }
 
+subsys_initcall(topology_init);
+
 /*
  * Get CPU information for use by the procfs.
  */
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
+#ifdef CONFIG_SMP
+	struct mn10300_cpuinfo *c = v;
+	unsigned long cpu_id = c - cpu_data;
+	unsigned long cpurev = c->type, type, icachesz, dcachesz;
+#else  /* CONFIG_SMP */
+	unsigned long cpu_id = 0;
 	unsigned long cpurev = CPUREV, type, icachesz, dcachesz;
+#endif /* CONFIG_SMP */
 
-	type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
+#ifdef CONFIG_SMP
+	if (!cpu_online(cpu_id))
+		return 0;
+#endif
+
+	type = (cpurev & CPUREV_TYPE) >> CPUREV_TYPE_S;
 	if (type > mn10300_known_cpus)
 		type = mn10300_known_cpus;
 
@@ -244,13 +245,14 @@
 		1024;
 
 	seq_printf(m,
-		   "processor  : 0\n"
-		   "vendor_id  : Matsushita\n"
+		   "processor  : %ld\n"
+		   "vendor_id  : " PROCESSOR_VENDOR_NAME "\n"
 		   "cpu core   : %s\n"
 		   "cpu rev    : %lu\n"
 		   "model name : " PROCESSOR_MODEL_NAME		"\n"
 		   "icache size: %lu\n"
 		   "dcache size: %lu\n",
+		   cpu_id,
 		   mn10300_cputypes[type],
 		   (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S,
 		   icachesz,
@@ -262,8 +264,13 @@
 		   "bogomips   : %lu.%02lu\n\n",
 		   MN10300_IOCLK / 1000000,
 		   (MN10300_IOCLK / 10000) % 100,
+#ifdef CONFIG_SMP
+		   c->loops_per_jiffy / (500000 / HZ),
+		   (c->loops_per_jiffy / (5000 / HZ)) % 100
+#else  /* CONFIG_SMP */
 		   loops_per_jiffy / (500000 / HZ),
 		   (loops_per_jiffy / (5000 / HZ)) % 100
+#endif /* CONFIG_SMP */
 		   );
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/signal.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/signal.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/signal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/signal.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,7 @@
  */
 asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss)
 {
-	return do_sigaltstack(uss, uoss, __frame->sp);
+	return do_sigaltstack(uss, uoss, current_frame()->sp);
 }
 
 /*
@@ -156,10 +156,11 @@
  */
 asmlinkage long sys_sigreturn(void)
 {
-	struct sigframe __user *frame = (struct sigframe __user *) __frame->sp;
+	struct sigframe __user *frame;
 	sigset_t set;
 	long d0;
 
+	frame = (struct sigframe __user *) current_frame()->sp;
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__get_user(set.sig[0], &frame->sc.oldmask))
@@ -176,7 +177,7 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(__frame, &frame->sc, &d0))
+	if (restore_sigcontext(current_frame(), &frame->sc, &d0))
 		goto badframe;
 
 	return d0;
@@ -191,11 +192,11 @@
  */
 asmlinkage long sys_rt_sigreturn(void)
 {
-	struct rt_sigframe __user *frame =
-		(struct rt_sigframe __user *) __frame->sp;
+	struct rt_sigframe __user *frame;
 	sigset_t set;
-	unsigned long d0;
+	long d0;
 
+	frame = (struct rt_sigframe __user *) current_frame()->sp;
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -207,10 +208,11 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(__frame, &frame->uc.uc_mcontext, &d0))
+	if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
 		goto badframe;
 
-	if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT)
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, current_frame()->sp) ==
+	    -EFAULT)
 		goto badframe;
 
 	return d0;
@@ -572,7 +574,7 @@
 
 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
 		clear_thread_flag(TIF_NOTIFY_RESUME);
-		tracehook_notify_resume(__frame);
+		tracehook_notify_resume(current_frame());
 		if (current->replacement_session_keyring)
 			key_replace_session_keyring();
 	}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/smp.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/smp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1152 @@
+/* SMP support routines.
+ *
+ * Copyright (C) 2006-2008 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/bug.h>
+#include <asm/exceptions.h>
+#include <asm/hardirq.h>
+#include <asm/fpu.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
+#include "internal.h"
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <linux/cpu.h>
+#include <asm/cacheflush.h>
+
+static unsigned long sleep_mode[NR_CPUS];
+
+static void run_sleep_cpu(unsigned int cpu);
+static void run_wakeup_cpu(unsigned int cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/*
+ * Debug Message function
+ */
+
+#undef DEBUG_SMP
+#ifdef DEBUG_SMP
+#define Dprintk(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
+#else
+#define Dprintk(fmt, ...) no_printk(KERN_DEBUG fmt, ##__VA_ARGS__)
+#endif
+
+/* timeout value in msec for smp_nmi_call_function. zero is no timeout. */
+#define	CALL_FUNCTION_NMI_IPI_TIMEOUT	0
+
+/*
+ * Structure and data for smp_nmi_call_function().
+ */
+struct nmi_call_data_struct {
+	smp_call_func_t	func;
+	void		*info;
+	cpumask_t	started;
+	cpumask_t	finished;
+	int		wait;
+	char		size_alignment[0]
+	__attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+
+static DEFINE_SPINLOCK(smp_nmi_call_lock);
+static struct nmi_call_data_struct *nmi_call_data;
+
+/*
+ * Data structures and variables
+ */
+static cpumask_t cpu_callin_map;	/* Bitmask of callin CPUs */
+static cpumask_t cpu_callout_map;	/* Bitmask of callout CPUs */
+cpumask_t cpu_boot_map;			/* Bitmask of boot APs */
+unsigned long start_stack[NR_CPUS - 1];
+
+/*
+ * Per CPU parameters
+ */
+struct mn10300_cpuinfo cpu_data[NR_CPUS] __cacheline_aligned;
+
+static int cpucount;			/* The count of boot CPUs */
+static cpumask_t smp_commenced_mask;
+cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+
+/*
+ * Function Prototypes
+ */
+static int do_boot_cpu(int);
+static void smp_show_cpu_info(int cpu_id);
+static void smp_callin(void);
+static void smp_online(void);
+static void smp_store_cpu_info(int);
+static void smp_cpu_init(void);
+static void smp_tune_scheduling(void);
+static void send_IPI_mask(const cpumask_t *cpumask, int irq);
+static void init_ipi(void);
+
+/*
+ * IPI Initialization interrupt definitions
+ */
+static void mn10300_ipi_disable(unsigned int irq);
+static void mn10300_ipi_enable(unsigned int irq);
+static void mn10300_ipi_ack(unsigned int irq);
+static void mn10300_ipi_nop(unsigned int irq);
+
+static struct irq_chip mn10300_ipi_type = {
+	.name		= "cpu_ipi",
+	.disable	= mn10300_ipi_disable,
+	.enable		= mn10300_ipi_enable,
+	.ack		= mn10300_ipi_ack,
+	.eoi		= mn10300_ipi_nop
+};
+
+static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id);
+static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id);
+
+static struct irqaction reschedule_ipi = {
+	.handler	= smp_reschedule_interrupt,
+	.name		= "smp reschedule IPI"
+};
+static struct irqaction call_function_ipi = {
+	.handler	= smp_call_function_interrupt,
+	.name		= "smp call function IPI"
+};
+
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id);
+static struct irqaction local_timer_ipi = {
+	.handler	= smp_ipi_timer_interrupt,
+	.flags		= IRQF_DISABLED,
+	.name		= "smp local timer IPI"
+};
+#endif
+
+/**
+ * init_ipi - Initialise the IPI mechanism
+ */
+static void init_ipi(void)
+{
+	unsigned long flags;
+	u16 tmp16;
+
+	/* set up the reschedule IPI */
+	set_irq_chip_and_handler(RESCHEDULE_IPI,
+				 &mn10300_ipi_type, handle_percpu_irq);
+	setup_irq(RESCHEDULE_IPI, &reschedule_ipi);
+	set_intr_level(RESCHEDULE_IPI, RESCHEDULE_GxICR_LV);
+	mn10300_ipi_enable(RESCHEDULE_IPI);
+
+	/* set up the call function IPI */
+	set_irq_chip_and_handler(CALL_FUNC_SINGLE_IPI,
+				 &mn10300_ipi_type, handle_percpu_irq);
+	setup_irq(CALL_FUNC_SINGLE_IPI, &call_function_ipi);
+	set_intr_level(CALL_FUNC_SINGLE_IPI, CALL_FUNCTION_GxICR_LV);
+	mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI);
+
+	/* set up the local timer IPI */
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
+    defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+	set_irq_chip_and_handler(LOCAL_TIMER_IPI,
+				 &mn10300_ipi_type, handle_percpu_irq);
+	setup_irq(LOCAL_TIMER_IPI, &local_timer_ipi);
+	set_intr_level(LOCAL_TIMER_IPI, LOCAL_TIMER_GxICR_LV);
+	mn10300_ipi_enable(LOCAL_TIMER_IPI);
+#endif
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+	/* set up the cache flush IPI */
+	flags = arch_local_cli_save();
+	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(FLUSH_CACHE_GxICR_LV),
+			mn10300_low_ipi_handler);
+	GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT;
+	mn10300_ipi_enable(FLUSH_CACHE_IPI);
+	arch_local_irq_restore(flags);
+#endif
+
+	/* set up the NMI call function IPI */
+	flags = arch_local_cli_save();
+	GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+	tmp16 = GxICR(CALL_FUNCTION_NMI_IPI);
+	arch_local_irq_restore(flags);
+
+	/* set up the SMP boot IPI */
+	flags = arch_local_cli_save();
+	__set_intr_stub(NUM2EXCEP_IRQ_LEVEL(SMP_BOOT_GxICR_LV),
+			mn10300_low_ipi_handler);
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_shutdown - Shut down handling of an IPI
+ * @irq: The IPI to be shut down.
+ */
+static void mn10300_ipi_shutdown(unsigned int irq)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+
+	tmp = GxICR(irq);
+	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+	tmp = GxICR(irq);
+
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_enable - Enable an IPI
+ * @irq: The IPI to be enabled.
+ */
+static void mn10300_ipi_enable(unsigned int irq)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+
+	tmp = GxICR(irq);
+	GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
+	tmp = GxICR(irq);
+
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_disable - Disable an IPI
+ * @irq: The IPI to be disabled.
+ */
+static void mn10300_ipi_disable(unsigned int irq)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+
+	tmp = GxICR(irq);
+	GxICR(irq) = tmp & GxICR_LEVEL;
+	tmp = GxICR(irq);
+
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_ack - Acknowledge an IPI interrupt in the PIC
+ * @irq: The IPI to be acknowledged.
+ *
+ * Clear the interrupt detection flag for the IPI on the appropriate interrupt
+ * channel in the PIC.
+ */
+static void mn10300_ipi_ack(unsigned int irq)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	flags = arch_local_cli_save();
+	GxICR_u8(irq) = GxICR_DETECT;
+	tmp = GxICR(irq);
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * mn10300_ipi_nop - Dummy IPI action
+ * @irq: The IPI to be acted upon.
+ */
+static void mn10300_ipi_nop(unsigned int irq)
+{
+}
+
+/**
+ * send_IPI_mask - Send IPIs to all CPUs in list
+ * @cpumask: The list of CPUs to target.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to all the CPUs in the list, not waiting for them to
+ * finish before returning.  The caller is responsible for synchronisation if
+ * that is needed.
+ */
+static void send_IPI_mask(const cpumask_t *cpumask, int irq)
+{
+	int i;
+	u16 tmp;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (cpu_isset(i, *cpumask)) {
+			/* send IPI */
+			tmp = CROSS_GxICR(irq, i);
+			CROSS_GxICR(irq, i) =
+				tmp | GxICR_REQUEST | GxICR_DETECT;
+			tmp = CROSS_GxICR(irq, i); /* flush write buffer */
+		}
+	}
+}
+
+/**
+ * send_IPI_self - Send an IPI to this CPU.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to the current CPU.
+ */
+void send_IPI_self(int irq)
+{
+	send_IPI_mask(cpumask_of(smp_processor_id()), irq);
+}
+
+/**
+ * send_IPI_allbutself - Send IPIs to all the other CPUs.
+ * @irq: The IPI request to be sent.
+ *
+ * Send the specified IPI to all CPUs in the system barring the current one,
+ * not waiting for them to finish before returning.  The caller is responsible
+ * for synchronisation if that is needed.
+ */
+void send_IPI_allbutself(int irq)
+{
+	cpumask_t cpumask;
+
+	cpumask = cpu_online_map;
+	cpu_clear(smp_processor_id(), cpumask);
+	send_IPI_mask(&cpumask, irq);
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+	BUG();
+	/*send_IPI_mask(mask, CALL_FUNCTION_IPI);*/
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+	send_IPI_mask(cpumask_of(cpu), CALL_FUNC_SINGLE_IPI);
+}
+
+/**
+ * smp_send_reschedule - Send reschedule IPI to a CPU
+ * @cpu: The CPU to target.
+ */
+void smp_send_reschedule(int cpu)
+{
+	send_IPI_mask(cpumask_of(cpu), RESCHEDULE_IPI);
+}
+
+/**
+ * smp_nmi_call_function - Send a call function NMI IPI to all CPUs
+ * @func: The function to ask to be run.
+ * @info: The context data to pass to that function.
+ * @wait: If true, wait (atomically) until function is run on all CPUs.
+ *
+ * Send a non-maskable request to all CPUs in the system, requesting them to
+ * run the specified function with the given context data, and, potentially, to
+ * wait for completion of that function on all CPUs.
+ *
+ * Returns 0 if successful, -ETIMEDOUT if we were asked to wait, but hit the
+ * timeout.
+ */
+int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
+{
+	struct nmi_call_data_struct data;
+	unsigned long flags;
+	unsigned int cnt;
+	int cpus, ret = 0;
+
+	cpus = num_online_cpus() - 1;
+	if (cpus < 1)
+		return 0;
+
+	data.func = func;
+	data.info = info;
+	data.started = cpu_online_map;
+	cpu_clear(smp_processor_id(), data.started);
+	data.wait = wait;
+	if (wait)
+		data.finished = data.started;
+
+	spin_lock_irqsave(&smp_nmi_call_lock, flags);
+	nmi_call_data = &data;
+	smp_mb();
+
+	/* Send a message to all other CPUs and wait for them to respond */
+	send_IPI_allbutself(CALL_FUNCTION_NMI_IPI);
+
+	/* Wait for response */
+	if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) {
+		for (cnt = 0;
+		     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
+			     !cpus_empty(data.started);
+		     cnt++)
+			mdelay(1);
+
+		if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) {
+			for (cnt = 0;
+			     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
+				     !cpus_empty(data.finished);
+			     cnt++)
+				mdelay(1);
+		}
+
+		if (cnt >= CALL_FUNCTION_NMI_IPI_TIMEOUT)
+			ret = -ETIMEDOUT;
+
+	} else {
+		/* If timeout value is zero, wait until cpumask has been
+		 * cleared */
+		while (!cpus_empty(data.started))
+			barrier();
+		if (wait)
+			while (!cpus_empty(data.finished))
+				barrier();
+	}
+
+	spin_unlock_irqrestore(&smp_nmi_call_lock, flags);
+	return ret;
+}
+
+/**
+ * stop_this_cpu - Callback to stop a CPU.
+ * @unused: Callback context (ignored).
+ */
+void stop_this_cpu(void *unused)
+{
+	static volatile int stopflag;
+	unsigned long flags;
+
+#ifdef CONFIG_GDBSTUB
+	/* In case of single stepping smp_send_stop by other CPU,
+	 * clear procindebug to avoid deadlock.
+	 */
+	atomic_set(&procindebug[smp_processor_id()], 0);
+#endif	/* CONFIG_GDBSTUB */
+
+	flags = arch_local_cli_save();
+	cpu_clear(smp_processor_id(), cpu_online_map);
+
+	while (!stopflag)
+		cpu_relax();
+
+	cpu_set(smp_processor_id(), cpu_online_map);
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * smp_send_stop - Send a stop request to all CPUs.
+ */
+void smp_send_stop(void)
+{
+	smp_nmi_call_function(stop_this_cpu, NULL, 0);
+}
+
+/**
+ * smp_reschedule_interrupt - Reschedule IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * We need do nothing here, since the scheduling will be effected on our way
+ * back through entry.S.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id)
+{
+	/* do nothing */
+	return IRQ_HANDLED;
+}
+
+/**
+ * smp_call_function_interrupt - Call function IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_call_function_interrupt(int irq, void *dev_id)
+{
+	/* generic_smp_call_function_interrupt(); */
+	generic_smp_call_function_single_interrupt();
+	return IRQ_HANDLED;
+}
+
+/**
+ * smp_nmi_call_function_interrupt - Non-maskable call function IPI handler
+ */
+void smp_nmi_call_function_interrupt(void)
+{
+	smp_call_func_t func = nmi_call_data->func;
+	void *info = nmi_call_data->info;
+	int wait = nmi_call_data->wait;
+
+	/* Notify the initiating CPU that I've grabbed the data and am about to
+	 * execute the function
+	 */
+	smp_mb();
+	cpu_clear(smp_processor_id(), nmi_call_data->started);
+	(*func)(info);
+
+	if (wait) {
+		smp_mb();
+		cpu_clear(smp_processor_id(), nmi_call_data->finished);
+	}
+}
+
+#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || \
+    defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+/**
+ * smp_ipi_timer_interrupt - Local timer IPI handler
+ * @irq: The interrupt number.
+ * @dev_id: The device ID.
+ *
+ * Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
+ */
+static irqreturn_t smp_ipi_timer_interrupt(int irq, void *dev_id)
+{
+	return local_timer_interrupt();
+}
+#endif
+
+void __init smp_init_cpus(void)
+{
+	int i;
+	for (i = 0; i < NR_CPUS; i++) {
+		set_cpu_possible(i, true);
+		set_cpu_present(i, true);
+	}
+}
+
+/**
+ * smp_cpu_init - Initialise AP in start_secondary.
+ *
+ * For this Application Processor, set up init_mm, initialise FPU and set
+ * interrupt level 0-6 setting.
+ */
+static void __init smp_cpu_init(void)
+{
+	unsigned long flags;
+	int cpu_id = smp_processor_id();
+	u16 tmp16;
+
+	if (test_and_set_bit(cpu_id, &cpu_initialized)) {
+		printk(KERN_WARNING "CPU#%d already initialized!\n", cpu_id);
+		for (;;)
+			local_irq_enable();
+	}
+	printk(KERN_INFO "Initializing CPU#%d\n", cpu_id);
+
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	BUG_ON(current->mm);
+
+	enter_lazy_tlb(&init_mm, current);
+
+	/* Force FPU initialization */
+	clear_using_fpu(current);
+
+	GxICR(CALL_FUNC_SINGLE_IPI) = CALL_FUNCTION_GxICR_LV | GxICR_DETECT;
+	mn10300_ipi_enable(CALL_FUNC_SINGLE_IPI);
+
+	GxICR(LOCAL_TIMER_IPI) = LOCAL_TIMER_GxICR_LV | GxICR_DETECT;
+	mn10300_ipi_enable(LOCAL_TIMER_IPI);
+
+	GxICR(RESCHEDULE_IPI) = RESCHEDULE_GxICR_LV | GxICR_DETECT;
+	mn10300_ipi_enable(RESCHEDULE_IPI);
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+	GxICR(FLUSH_CACHE_IPI) = FLUSH_CACHE_GxICR_LV | GxICR_DETECT;
+	mn10300_ipi_enable(FLUSH_CACHE_IPI);
+#endif
+
+	mn10300_ipi_shutdown(SMP_BOOT_IRQ);
+
+	/* Set up the non-maskable call function IPI */
+	flags = arch_local_cli_save();
+	GxICR(CALL_FUNCTION_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+	tmp16 = GxICR(CALL_FUNCTION_NMI_IPI);
+	arch_local_irq_restore(flags);
+}
+
+/**
+ * smp_prepare_cpu_init - Initialise CPU in startup_secondary
+ *
+ * Set interrupt level 0-6 setting and init ICR of gdbstub.
+ */
+void smp_prepare_cpu_init(void)
+{
+	int loop;
+
+	/* Set the interrupt vector registers */
+	IVAR0 = EXCEP_IRQ_LEVEL0;
+	IVAR1 = EXCEP_IRQ_LEVEL1;
+	IVAR2 = EXCEP_IRQ_LEVEL2;
+	IVAR3 = EXCEP_IRQ_LEVEL3;
+	IVAR4 = EXCEP_IRQ_LEVEL4;
+	IVAR5 = EXCEP_IRQ_LEVEL5;
+	IVAR6 = EXCEP_IRQ_LEVEL6;
+
+	/* Disable all interrupts and set to priority 6 (lowest) */
+	for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
+		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+
+#ifdef CONFIG_GDBSTUB
+	/* initialise GDB-stub */
+	do {
+		unsigned long flags;
+		u16 tmp16;
+
+		flags = arch_local_cli_save();
+		GxICR(GDB_NMI_IPI) = GxICR_NMI | GxICR_ENABLE | GxICR_DETECT;
+		tmp16 = GxICR(GDB_NMI_IPI);
+		arch_local_irq_restore(flags);
+	} while (0);
+#endif
+}
+
+/**
+ * start_secondary - Activate a secondary CPU (AP)
+ * @unused: Thread parameter (ignored).
+ */
+int __init start_secondary(void *unused)
+{
+	smp_cpu_init();
+	smp_callin();
+	while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+		cpu_relax();
+
+	local_flush_tlb();
+	preempt_disable();
+	smp_online();
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	init_clockevents();
+#endif
+	cpu_idle();
+	return 0;
+}
+
+/**
+ * smp_prepare_cpus - Boot up secondary CPUs (APs)
+ * @max_cpus: Maximum number of CPUs to boot.
+ *
+ * Call do_boot_cpu, and boot up APs.
+ */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	int phy_id;
+
+	/* Setup boot CPU information */
+	smp_store_cpu_info(0);
+	smp_tune_scheduling();
+
+	init_ipi();
+
+	/* If SMP should be disabled, then finish */
+	if (max_cpus == 0) {
+		printk(KERN_INFO "SMP mode deactivated.\n");
+		goto smp_done;
+	}
+
+	/* Boot secondary CPUs (for which phy_id > 0) */
+	for (phy_id = 0; phy_id < NR_CPUS; phy_id++) {
+		/* Don't boot primary CPU */
+		if (max_cpus <= cpucount + 1)
+			continue;
+		if (phy_id != 0)
+			do_boot_cpu(phy_id);
+		set_cpu_possible(phy_id, true);
+		smp_show_cpu_info(phy_id);
+	}
+
+smp_done:
+	Dprintk("Boot done.\n");
+}
+
+/**
+ * smp_store_cpu_info - Save a CPU's information
+ * @cpu: The CPU to save for.
+ *
+ * Save boot_cpu_data and jiffy for the specified CPU.
+ */
+static void __init smp_store_cpu_info(int cpu)
+{
+	struct mn10300_cpuinfo *ci = &cpu_data[cpu];
+
+	*ci = boot_cpu_data;
+	ci->loops_per_jiffy = loops_per_jiffy;
+	ci->type = CPUREV;
+}
+
+/**
+ * smp_tune_scheduling - Set time slice value
+ *
+ * Nothing to do here.
+ */
+static void __init smp_tune_scheduling(void)
+{
+}
+
+/**
+ * do_boot_cpu: Boot up one CPU
+ * @phy_id: Physical ID of CPU to boot.
+ *
+ * Send an IPI to a secondary CPU to boot it.  Returns 0 on success, 1
+ * otherwise.
+ */
+static int __init do_boot_cpu(int phy_id)
+{
+	struct task_struct *idle;
+	unsigned long send_status, callin_status;
+	int timeout, cpu_id;
+
+	send_status = GxICR_REQUEST;
+	callin_status = 0;
+	timeout = 0;
+	cpu_id = phy_id;
+
+	cpucount++;
+
+	/* Create idle thread for this CPU */
+	idle = fork_idle(cpu_id);
+	if (IS_ERR(idle))
+		panic("Failed fork for CPU#%d.", cpu_id);
+
+	idle->thread.pc = (unsigned long)start_secondary;
+
+	printk(KERN_NOTICE "Booting CPU#%d\n", cpu_id);
+	start_stack[cpu_id - 1] = idle->thread.sp;
+
+	task_thread_info(idle)->cpu = cpu_id;
+
+	/* Send boot IPI to AP */
+	send_IPI_mask(cpumask_of(phy_id), SMP_BOOT_IRQ);
+
+	Dprintk("Waiting for send to finish...\n");
+
+	/* Wait for AP's IPI receive in 100[ms] */
+	do {
+		udelay(1000);
+		send_status =
+			CROSS_GxICR(SMP_BOOT_IRQ, phy_id) & GxICR_REQUEST;
+	} while (send_status == GxICR_REQUEST && timeout++ < 100);
+
+	Dprintk("Waiting for cpu_callin_map.\n");
+
+	if (send_status == 0) {
+		/* Allow AP to start initializing */
+		cpu_set(cpu_id, cpu_callout_map);
+
+		/* Wait for setting cpu_callin_map */
+		timeout = 0;
+		do {
+			udelay(1000);
+			callin_status = cpu_isset(cpu_id, cpu_callin_map);
+		} while (callin_status == 0 && timeout++ < 5000);
+
+		if (callin_status == 0)
+			Dprintk("Not responding.\n");
+	} else {
+		printk(KERN_WARNING "IPI not delivered.\n");
+	}
+
+	if (send_status == GxICR_REQUEST || callin_status == 0) {
+		cpu_clear(cpu_id, cpu_callout_map);
+		cpu_clear(cpu_id, cpu_callin_map);
+		cpu_clear(cpu_id, cpu_initialized);
+		cpucount--;
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * smp_show_cpu_info - Show SMP CPU information
+ * @cpu: The CPU of interest.
+ */
+static void __init smp_show_cpu_info(int cpu)
+{
+	struct mn10300_cpuinfo *ci = &cpu_data[cpu];
+
+	printk(KERN_INFO
+	       "CPU#%d : ioclk speed: %lu.%02luMHz : bogomips : %lu.%02lu\n",
+	       cpu,
+	       MN10300_IOCLK / 1000000,
+	       (MN10300_IOCLK / 10000) % 100,
+	       ci->loops_per_jiffy / (500000 / HZ),
+	       (ci->loops_per_jiffy / (5000 / HZ)) % 100);
+}
+
+/**
+ * smp_callin - Set cpu_callin_map of the current CPU ID
+ */
+static void __init smp_callin(void)
+{
+	unsigned long timeout;
+	int cpu;
+
+	cpu = smp_processor_id();
+	timeout = jiffies + (2 * HZ);
+
+	if (cpu_isset(cpu, cpu_callin_map)) {
+		printk(KERN_ERR "CPU#%d already present.\n", cpu);
+		BUG();
+	}
+	Dprintk("CPU#%d waiting for CALLOUT\n", cpu);
+
+	/* Wait for AP startup 2s total */
+	while (time_before(jiffies, timeout)) {
+		if (cpu_isset(cpu, cpu_callout_map))
+			break;
+		cpu_relax();
+	}
+
+	if (!time_before(jiffies, timeout)) {
+		printk(KERN_ERR
+		       "BUG: CPU#%d started up but did not get a callout!\n",
+		       cpu);
+		BUG();
+	}
+
+#ifdef CONFIG_CALIBRATE_DELAY
+	calibrate_delay();		/* Get our bogomips */
+#endif
+
+	/* Save our processor parameters */
+	smp_store_cpu_info(cpu);
+
+	/* Allow the boot processor to continue */
+	cpu_set(cpu, cpu_callin_map);
+}
+
+/**
+ * smp_online - Set cpu_online_map
+ */
+static void __init smp_online(void)
+{
+	int cpu;
+
+	cpu = smp_processor_id();
+
+	local_irq_enable();
+
+	cpu_set(cpu, cpu_online_map);
+	smp_wmb();
+}
+
+/**
+ * smp_cpus_done -
+ * @max_cpus: Maximum CPU count.
+ *
+ * Do nothing.
+ */
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+/*
+ * smp_prepare_boot_cpu - Set up stuff for the boot processor.
+ *
+ * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot
+ * processor (CPU 0).
+ */
+void __devinit smp_prepare_boot_cpu(void)
+{
+	cpu_set(0, cpu_callout_map);
+	cpu_set(0, cpu_callin_map);
+	current_thread_info()->cpu = 0;
+}
+
+/*
+ * initialize_secondary - Initialise a secondary CPU (Application Processor).
+ *
+ * Set SP register and jump to thread's PC address.
+ */
+void initialize_secondary(void)
+{
+	asm volatile (
+		"mov	%0,sp	\n"
+		"jmp	(%1)	\n"
+		:
+		: "a"(current->thread.sp), "a"(current->thread.pc));
+}
+
+/**
+ * __cpu_up - Set smp_commenced_mask for the nominated CPU
+ * @cpu: The target CPU.
+ */
+int __devinit __cpu_up(unsigned int cpu)
+{
+	int timeout;
+
+#ifdef CONFIG_HOTPLUG_CPU
+	if (num_online_cpus() == 1)
+		disable_hlt();
+	if (sleep_mode[cpu])
+		run_wakeup_cpu(cpu);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+	cpu_set(cpu, smp_commenced_mask);
+
+	/* Wait 5s total for a response */
+	for (timeout = 0 ; timeout < 5000 ; timeout++) {
+		if (cpu_isset(cpu, cpu_online_map))
+			break;
+		udelay(1000);
+	}
+
+	BUG_ON(!cpu_isset(cpu, cpu_online_map));
+	return 0;
+}
+
+/**
+ * setup_profiling_timer - Set up the profiling timer
+ * @multiplier - The frequency multiplier to use
+ *
+ * The frequency of the profiling timer can be changed by writing a multiplier
+ * value into /proc/profile.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	return -EINVAL;
+}
+
+/*
+ * CPU hotplug routines
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+static int __init topology_init(void)
+{
+	int cpu, ret;
+
+	for_each_cpu(cpu) {
+		ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
+		if (ret)
+			printk(KERN_WARNING
+			       "topology_init: register_cpu %d failed (%d)\n",
+			       cpu, ret);
+	}
+	return 0;
+}
+
+subsys_initcall(topology_init);
+
+int __cpu_disable(void)
+{
+	int cpu = smp_processor_id();
+	if (cpu == 0)
+		return -EBUSY;
+
+	migrate_irqs();
+	cpu_clear(cpu, current->active_mm->cpu_vm_mask);
+	return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+	run_sleep_cpu(cpu);
+
+	if (num_online_cpus() == 1)
+		enable_hlt();
+}
+
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+static inline void hotplug_cpu_disable_cache(void)
+{
+	int tmp;
+	asm volatile(
+		"	movhu	(%1),%0	\n"
+		"	and	%2,%0	\n"
+		"	movhu	%0,(%1)	\n"
+		"1:	movhu	(%1),%0	\n"
+		"	btst	%3,%0	\n"
+		"	bne	1b	\n"
+		: "=&r"(tmp)
+		: "a"(&CHCTR),
+		  "i"(~(CHCTR_ICEN | CHCTR_DCEN)),
+		  "i"(CHCTR_ICBUSY | CHCTR_DCBUSY)
+		: "memory", "cc");
+}
+
+static inline void hotplug_cpu_enable_cache(void)
+{
+	int tmp;
+	asm volatile(
+		"movhu	(%1),%0	\n"
+		"or	%2,%0	\n"
+		"movhu	%0,(%1)	\n"
+		: "=&r"(tmp)
+		: "a"(&CHCTR),
+		  "i"(CHCTR_ICEN | CHCTR_DCEN)
+		: "memory", "cc");
+}
+
+static inline void hotplug_cpu_invalidate_cache(void)
+{
+	int tmp;
+	asm volatile (
+		"movhu	(%1),%0	\n"
+		"or	%2,%0	\n"
+		"movhu	%0,(%1)	\n"
+		: "=&r"(tmp)
+		: "a"(&CHCTR),
+		  "i"(CHCTR_ICINV | CHCTR_DCINV)
+		: "cc");
+}
+
+#else /* CONFIG_MN10300_CACHE_ENABLED */
+#define hotplug_cpu_disable_cache()	do {} while (0)
+#define hotplug_cpu_enable_cache()	do {} while (0)
+#define hotplug_cpu_invalidate_cache()	do {} while (0)
+#endif /* CONFIG_MN10300_CACHE_ENABLED */
+
+/**
+ * hotplug_cpu_nmi_call_function - Call a function on other CPUs for hotplug
+ * @cpumask: List of target CPUs.
+ * @func: The function to call on those CPUs.
+ * @info: The context data for the function to be called.
+ * @wait: Whether to wait for the calls to complete.
+ *
+ * Non-maskably call a function on another CPU for hotplug purposes.
+ *
+ * This function must be called with maskable interrupts disabled.
+ */
+static int hotplug_cpu_nmi_call_function(cpumask_t cpumask,
+					 smp_call_func_t func, void *info,
+					 int wait)
+{
+	/*
+	 * The address and the size of nmi_call_func_mask_data
+	 * need to be aligned on L1_CACHE_BYTES.
+	 */
+	static struct nmi_call_data_struct nmi_call_func_mask_data
+		__cacheline_aligned;
+	unsigned long start, end;
+
+	start = (unsigned long)&nmi_call_func_mask_data;
+	end = start + sizeof(struct nmi_call_data_struct);
+
+	nmi_call_func_mask_data.func = func;
+	nmi_call_func_mask_data.info = info;
+	nmi_call_func_mask_data.started = cpumask;
+	nmi_call_func_mask_data.wait = wait;
+	if (wait)
+		nmi_call_func_mask_data.finished = cpumask;
+
+	spin_lock(&smp_nmi_call_lock);
+	nmi_call_data = &nmi_call_func_mask_data;
+	mn10300_local_dcache_flush_range(start, end);
+	smp_wmb();
+
+	send_IPI_mask(cpumask, CALL_FUNCTION_NMI_IPI);
+
+	do {
+		mn10300_local_dcache_inv_range(start, end);
+		barrier();
+	} while (!cpus_empty(nmi_call_func_mask_data.started));
+
+	if (wait) {
+		do {
+			mn10300_local_dcache_inv_range(start, end);
+			barrier();
+		} while (!cpus_empty(nmi_call_func_mask_data.finished));
+	}
+
+	spin_unlock(&smp_nmi_call_lock);
+	return 0;
+}
+
+static void restart_wakeup_cpu(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	cpu_set(cpu, cpu_callin_map);
+	local_flush_tlb();
+	cpu_set(cpu, cpu_online_map);
+	smp_wmb();
+}
+
+static void prepare_sleep_cpu(void *unused)
+{
+	sleep_mode[smp_processor_id()] = 1;
+	smp_mb();
+	mn10300_local_dcache_flush_inv();
+	hotplug_cpu_disable_cache();
+	hotplug_cpu_invalidate_cache();
+}
+
+/* when this function called, IE=0, NMID=0. */
+static void sleep_cpu(void *unused)
+{
+	unsigned int cpu_id = smp_processor_id();
+	/*
+	 * CALL_FUNCTION_NMI_IPI for wakeup_cpu() shall not be requested,
+	 * before this cpu goes in SLEEP mode.
+	 */
+	do {
+		smp_mb();
+		__sleep_cpu();
+	} while (sleep_mode[cpu_id]);
+	restart_wakeup_cpu();
+}
+
+static void run_sleep_cpu(unsigned int cpu)
+{
+	unsigned long flags;
+	cpumask_t cpumask = cpumask_of(cpu);
+
+	flags = arch_local_cli_save();
+	hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1);
+	hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0);
+	udelay(1);		/* delay for the cpu to sleep. */
+	arch_local_irq_restore(flags);
+}
+
+static void wakeup_cpu(void)
+{
+	hotplug_cpu_invalidate_cache();
+	hotplug_cpu_enable_cache();
+	smp_mb();
+	sleep_mode[smp_processor_id()] = 0;
+}
+
+static void run_wakeup_cpu(unsigned int cpu)
+{
+	unsigned long flags;
+
+	flags = arch_local_cli_save();
+#if NR_CPUS == 2
+	mn10300_local_dcache_flush_inv();
+#else
+	/*
+	 * Before waking up the cpu,
+	 * all online cpus should stop and flush D-Cache for global data.
+	 */
+#error not support NR_CPUS > 2, when CONFIG_HOTPLUG_CPU=y.
+#endif
+	hotplug_cpu_nmi_call_function(cpumask_of(cpu), wakeup_cpu, NULL, 1);
+	arch_local_irq_restore(flags);
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/smp-low.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/smp-low.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/smp-low.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/smp-low.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,97 @@
+/* SMP IPI low-level handler
+ *
+ * Copyright (C) 2006-2007 Matsushita Electric Industrial Co., Ltd.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <proc/smp-regs.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.inc>
+
+	.am33_2
+
+###############################################################################
+#
+# IPI interrupt handler
+#
+###############################################################################
+	.globl mn10300_low_ipi_handler
+mn10300_low_ipi_handler:
+	add	-4,sp
+	mov	d0,(sp)
+	movhu	(IAGR),d0
+	and	IAGR_GN,d0
+	lsr	0x2,d0
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+	cmp	FLUSH_CACHE_IPI,d0
+	beq	mn10300_flush_cache_ipi
+#endif
+	cmp	SMP_BOOT_IRQ,d0
+	beq	mn10300_smp_boot_ipi
+	/* OTHERS */
+	mov	(sp),d0
+	add	4,sp
+#ifdef CONFIG_GDBSTUB
+	jmp	gdbstub_io_rx_handler
+#else
+	jmp	end
+#endif
+
+###############################################################################
+#
+# Cache flush IPI interrupt handler
+#
+###############################################################################
+#ifdef CONFIG_MN10300_CACHE_ENABLED
+mn10300_flush_cache_ipi:
+	mov	(sp),d0
+	add	4,sp
+
+	/* FLUSH_CACHE_IPI */
+	add	-4,sp
+	SAVE_ALL
+	mov	GxICR_DETECT,d2
+	movbu	d2,(GxICR(FLUSH_CACHE_IPI))	# ACK the interrupt
+	movhu	(GxICR(FLUSH_CACHE_IPI)),d2
+	call	smp_cache_interrupt[],0
+	RESTORE_ALL
+	jmp	end
+#endif
+
+###############################################################################
+#
+# SMP boot CPU IPI interrupt handler
+#
+###############################################################################
+mn10300_smp_boot_ipi:
+	/* clear interrupt */
+	movhu	(GxICR(SMP_BOOT_IRQ)),d0
+	and	~GxICR_REQUEST,d0
+	movhu	d0,(GxICR(SMP_BOOT_IRQ))
+	mov	(sp),d0
+	add	4,sp
+
+	# get stack
+	mov	(CPUID),a0
+	add	-1,a0
+	add	a0,a0
+	add	a0,a0
+	mov	(start_stack,a0),a0
+	mov	a0,sp
+	jmp	initialize_secondary
+
+
+# Jump here after RTI to suppress the icache lookahead
+end:
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/switch_to.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/switch_to.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/switch_to.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/switch_to.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,9 @@
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/cpu-regs.h>
+#ifdef CONFIG_SMP
+#include <proc/smp-regs.h>
+#endif /* CONFIG_SMP */
 
 	.text
 
@@ -35,8 +38,6 @@
 	mov	d1,a1
 
 	# save prev context
-	mov	(__frame),d0
-	mov	d0,(THREAD_FRAME,a0)
 	mov	__switch_back,d0
 	mov	d0,(THREAD_PC,a0)
 	mov	sp,a2
@@ -58,8 +59,6 @@
 	mov	a2,e2
 #endif
 
-	mov	(THREAD_FRAME,a1),a2
-	mov	a2,(__frame)
 	mov	(THREAD_PC,a1),a2
 	mov	d2,d0			# for ret_from_fork
 	mov	d0,a0			# for __switch_to
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/time.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,29 +17,18 @@
 #include <linux/smp.h>
 #include <linux/profile.h>
 #include <linux/cnt32_to_63.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <asm/processor.h>
 #include <asm/intctl-regs.h>
 #include <asm/rtc.h>
-
-#ifdef CONFIG_MN10300_RTC
-unsigned long mn10300_ioclk;		/* system I/O clock frequency */
-unsigned long mn10300_iobclk;		/* system I/O clock frequency */
-unsigned long mn10300_tsc_per_HZ;	/* number of ioclks per jiffy */
-#endif /* CONFIG_MN10300_RTC */
+#include "internal.h"
 
 static unsigned long mn10300_last_tsc;	/* time-stamp counter at last time
 					 * interrupt occurred */
 
-static irqreturn_t timer_interrupt(int irq, void *dev_id);
-
-static struct irqaction timer_irq = {
-	.handler	= timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
-	.name		= "timer",
-};
-
 static unsigned long sched_clock_multiplier;
 
 /*
@@ -51,18 +40,19 @@
 		unsigned long long ll;
 		unsigned l[2];
 	} tsc64, result;
-	unsigned long tsc, tmp;
+	unsigned long tmp;
 	unsigned product[3]; /* 96-bit intermediate value */
 
-	/* read the TSC value
-	 */
-	tsc = 0 - get_cycles(); /* get_cycles() counts down */
+	/* cnt32_to_63() is not safe with preemption */
+	preempt_disable();
 
-	/* expand to 64-bits.
+	/* expand the tsc to 64-bits.
 	 * - sched_clock() must be called once a minute or better or the
 	 *   following will go horribly wrong - see cnt32_to_63()
 	 */
-	tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
+	tsc64.ll = cnt32_to_63(get_cycles()) & 0x7fffffffffffffffULL;
+
+	preempt_enable();
 
 	/* scale the 64-bit TSC value to a nanosecond value via a 96-bit
 	 * intermediate
@@ -90,6 +80,20 @@
 		__muldiv64u(NSEC_PER_SEC, 1 << 16, MN10300_TSCCLK);
 }
 
+/**
+ * local_timer_interrupt - Local timer interrupt handler
+ *
+ * Handle local timer interrupts for this CPU.  They may have been propagated
+ * to this CPU from the CPU that actually gets them by way of an IPI.
+ */
+irqreturn_t local_timer_interrupt(void)
+{
+	profile_tick(CPU_PROFILING);
+	update_process_times(user_mode(get_irq_regs()));
+	return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_GENERIC_TIME
 /*
  * advance the kernel's time keeping clocks (xtime and jiffies)
  * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time
@@ -98,27 +102,73 @@
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 	unsigned tsc, elapse;
+	irqreturn_t ret;
 
 	write_seqlock(&xtime_lock);
 
 	while (tsc = get_cycles(),
-	       elapse = mn10300_last_tsc - tsc, /* time elapsed since last
+	       elapse = tsc - mn10300_last_tsc, /* time elapsed since last
 						 * tick */
 	       elapse > MN10300_TSC_PER_HZ
 	       ) {
-		mn10300_last_tsc -= MN10300_TSC_PER_HZ;
+		mn10300_last_tsc += MN10300_TSC_PER_HZ;
 
 		/* advance the kernel's time tracking system */
-		profile_tick(CPU_PROFILING);
 		do_timer(1);
 	}
 
 	write_sequnlock(&xtime_lock);
 
-	update_process_times(user_mode(get_irq_regs()));
+	ret = local_timer_interrupt();
+#ifdef CONFIG_SMP
+	send_IPI_allbutself(LOCAL_TIMER_IPI);
+#endif
+	return ret;
+}
 
-	return IRQ_HANDLED;
+static struct irqaction timer_irq = {
+	.handler	= timer_interrupt,
+	.flags		= IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
+	.name		= "timer",
+};
+#endif /* CONFIG_GENERIC_TIME */
+
+#ifdef CONFIG_CSRC_MN10300
+void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
+{
+	u64 temp;
+	u32 shift;
+
+	/* Find a shift value */
+	for (shift = 32; shift > 0; shift--) {
+		temp = (u64) NSEC_PER_SEC << shift;
+		do_div(temp, clock);
+		if ((temp >> 32) == 0)
+			break;
+	}
+	cs->shift = shift;
+	cs->mult = (u32) temp;
 }
+#endif
+
+#if CONFIG_CEVT_MN10300
+void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
+				    unsigned int clock)
+{
+	u64 temp;
+	u32 shift;
+
+	/* Find a shift value */
+	for (shift = 32; shift > 0; shift--) {
+		temp = (u64) clock << shift;
+		do_div(temp, NSEC_PER_SEC);
+		if ((temp >> 32) == 0)
+			break;
+	}
+	cd->shift = shift;
+	cd->mult = (u32) temp;
+}
+#endif
 
 /*
  * initialise the various timers used by the main part of the kernel
@@ -131,21 +181,25 @@
 	 */
 	TMPSCNT |= TMPSCNT_ENABLE;
 
+#ifdef CONFIG_GENERIC_TIME
+	init_clocksource();
+#else
 	startup_timestamp_counter();
+#endif
 
 	printk(KERN_INFO
 	       "timestamp counter I/O clock running at %lu.%02lu"
 	       " (calibrated against RTC)\n",
 	       MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100);
 
-	mn10300_last_tsc = TMTSCBC;
-
-	/* use timer 0 & 1 cascaded to tick at as close to HZ as possible */
-	setup_irq(TMJCIRQ, &timer_irq);
-
-	set_intr_level(TMJCIRQ, TMJCICR_LEVEL);
+	mn10300_last_tsc = read_timestamp_counter();
 
-	startup_jiffies_counter();
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+	init_clockevents();
+#else
+	reload_jiffies_counter(MN10300_JC_PER_HZ - 1);
+	setup_jiffies_interrupt(TMJCIRQ, &timer_irq, CONFIG_TIMER_IRQ_LEVEL);
+#endif
 
 #ifdef CONFIG_MN10300_WD_TIMER
 	/* start the watchdog timer */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/traps.c linux-libre-2.6.37-gnu/arch/mn10300/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,9 +45,6 @@
 #error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
 #endif
 
-struct pt_regs *__frame; /* current frame pointer */
-EXPORT_SYMBOL(__frame);
-
 int kstack_depth_to_print = 24;
 
 spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock);
@@ -101,7 +98,6 @@
 DO_EINFO(SIGILL,  {}, "invalid ex opcode",	invalid_exop,	ILL_ILLOPC);
 DO_EINFO(SIGBUS,  {}, "invalid address",	mem_error,	BUS_ADRERR);
 DO_EINFO(SIGBUS,  {}, "bus error",		bus_error,	BUS_ADRERR);
-DO_EINFO(SIGILL,  {}, "FPU invalid opcode", 	fpu_invalid_op,	ILL_COPROC);
 
 DO_ERROR(SIGTRAP,
 #ifndef CONFIG_MN10300_USING_JTAG
@@ -222,11 +218,14 @@
 	printk(KERN_EMERG "threadinfo=%p task=%p)\n",
 	       current_thread_info(), current);
 
-	if ((unsigned long) current >= 0x90000000UL &&
-	    (unsigned long) current < 0x94000000UL)
+	if ((unsigned long) current >= PAGE_OFFSET &&
+	    (unsigned long) current < (unsigned long)high_memory)
 		printk(KERN_EMERG "Process %s (pid: %d)\n",
 		       current->comm, current->pid);
 
+#ifdef CONFIG_SMP
+	printk(KERN_EMERG "CPUID:  %08x\n", CPUID);
+#endif
 	printk(KERN_EMERG "CPUP:   %04hx\n", CPUP);
 	printk(KERN_EMERG "TBR:    %08x\n", TBR);
 	printk(KERN_EMERG "DEAR:   %08x\n", DEAR);
@@ -522,8 +521,12 @@
 {
 	unsigned long addr;
 	u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
+	unsigned long flags;
 
 	addr = (unsigned long) handler - (unsigned long) vector;
+
+	flags = arch_local_cli_save();
+
 	vector[0] = 0xdc;		/* JMP handler */
 	vector[1] = addr;
 	vector[2] = addr >> 8;
@@ -533,30 +536,12 @@
 	vector[6] = 0xcb;
 	vector[7] = 0xcb;
 
-	mn10300_dcache_flush_inv();
-	mn10300_icache_inv();
-}
-
-/*
- * set an interrupt stub to invoke the JTAG unit and then jump to a handler
- */
-void __init set_jtag_stub(enum exception_code code, void *handler)
-{
-	unsigned long addr;
-	u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
-
-	addr = (unsigned long) handler - ((unsigned long) vector + 1);
-	vector[0] = 0xff;		/* PI to jump into JTAG debugger */
-	vector[1] = 0xdc;		/* jmp handler */
-	vector[2] = addr;
-	vector[3] = addr >> 8;
-	vector[4] = addr >> 16;
-	vector[5] = addr >> 24;
-	vector[6] = 0xcb;
-	vector[7] = 0xcb;
+	arch_local_irq_restore(flags);
 
+#ifndef CONFIG_MN10300_CACHE_SNOOP
 	mn10300_dcache_flush_inv();
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 8);
+	mn10300_icache_inv();
+#endif
 }
 
 /*
@@ -581,7 +566,6 @@
 	set_excp_vector(EXCEP_PRIVINSACC,	insn_acc_error);
 	set_excp_vector(EXCEP_PRIVDATACC,	data_acc_error);
 	set_excp_vector(EXCEP_DATINSACC,	insn_acc_error);
-	set_excp_vector(EXCEP_FPU_DISABLED,	fpu_disabled);
 	set_excp_vector(EXCEP_FPU_UNIMPINS,	fpu_invalid_op);
 	set_excp_vector(EXCEP_FPU_OPERATION,	fpu_exception);
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/kernel/vmlinux.lds.S linux-libre-2.6.37-gnu/arch/mn10300/kernel/vmlinux.lds.S
--- linux-libre-2.6.36-gnu/arch/mn10300/kernel/vmlinux.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/kernel/vmlinux.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -70,7 +70,7 @@
 	.exit.text : { EXIT_TEXT; }
 	.exit.data : { EXIT_DATA; }
 
-  PERCPU(32)
+  PERCPU(PAGE_SIZE)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/lib/bitops.c linux-libre-2.6.37-gnu/arch/mn10300/lib/bitops.c
--- linux-libre-2.6.36-gnu/arch/mn10300/lib/bitops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/lib/bitops.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
 /*
  * try flipping a bit using BSET and BCLR
  */
-void change_bit(int nr, volatile void *addr)
+void change_bit(unsigned long nr, volatile void *addr)
 {
 	if (test_bit(nr, addr))
 		goto try_clear_bit;
@@ -34,7 +34,7 @@
 /*
  * try flipping a bit using BSET and BCLR and returning the old value
  */
-int test_and_change_bit(int nr, volatile void *addr)
+int test_and_change_bit(unsigned long nr, volatile void *addr)
 {
 	if (test_bit(nr, addr))
 		goto try_clear_bit;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/lib/delay.c linux-libre-2.6.37-gnu/arch/mn10300/lib/delay.c
--- linux-libre-2.6.36-gnu/arch/mn10300/lib/delay.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/lib/delay.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,14 +38,14 @@
  */
 void __udelay(unsigned long usecs)
 {
-	signed long ioclk, stop;
+	unsigned long start, stop, cnt;
 
 	/* usecs * CLK / 1E6 */
 	stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000);
-	stop = TMTSCBC - stop;
+	start = TMTSCBC;
 
 	do {
-		ioclk = TMTSCBC;
-	} while (stop < ioclk);
+		cnt = start - TMTSCBC;
+	} while (cnt < stop);
 }
 EXPORT_SYMBOL(__udelay);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/lib/do_csum.S linux-libre-2.6.37-gnu/arch/mn10300/lib/do_csum.S
--- linux-libre-2.6.36-gnu/arch/mn10300/lib/do_csum.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/lib/do_csum.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,26 +10,25 @@
  */
 #include <asm/cache.h>
 
-        .section .text
-        .balign	L1_CACHE_BYTES
+	.section .text
+	.balign	L1_CACHE_BYTES
 
 ###############################################################################
 #
-# unsigned int do_csum(const unsigned char *buff, size_t len)
+# unsigned int do_csum(const unsigned char *buff, int len)
 #
 ###############################################################################
 	.globl	do_csum
-        .type	do_csum,@function
+	.type	do_csum,@function
 do_csum:
 	movm	[d2,d3],(sp)
-	mov	d0,(12,sp)
-	mov	d1,(16,sp)
 	mov	d1,d2				# count
 	mov	d0,a0				# buff
+	mov	a0,a1
 	clr	d1				# accumulator
 
 	cmp	+0,d2
-	beq	do_csum_done			# return if zero-length buffer
+	ble	do_csum_done			# check for zero length or negative
 
 	# 4-byte align the buffer pointer
 	btst	+3,a0
@@ -41,17 +40,15 @@
 	inc	a0
 	asl	+8,d0
 	add	d0,d1
-	addc	+0,d1
 	add	-1,d2
-do_csum_addr_not_odd:
 
+do_csum_addr_not_odd:
 	cmp	+2,d2
 	bcs	do_csum_fewer_than_4
 	btst	+2,a0
 	beq	do_csum_now_4b_aligned
 	movhu	(a0+),d0
 	add	d0,d1
-	addc	+0,d1
 	add	-2,d2
 	cmp	+4,d2
 	bcs	do_csum_fewer_than_4
@@ -66,20 +63,20 @@
 
 do_csum_loop:
 	mov	(a0+),d0
-	add	d0,d1
 	mov	(a0+),e0
-	addc	e0,d1
 	mov	(a0+),e1
-	addc	e1,d1
 	mov	(a0+),e3
+	add	d0,d1
+	addc	e0,d1
+	addc	e1,d1
 	addc	e3,d1
 	mov	(a0+),d0
-	addc	d0,d1
 	mov	(a0+),e0
-	addc	e0,d1
 	mov	(a0+),e1
-	addc	e1,d1
 	mov	(a0+),e3
+	addc	d0,d1
+	addc	e0,d1
+	addc	e1,d1
 	addc	e3,d1
 	addc	+0,d1
 
@@ -94,12 +91,12 @@
 	cmp	+16,d2
 	bcs	do_csum_fewer_than_16
 	mov	(a0+),d0
-	add	d0,d1
 	mov	(a0+),e0
-	addc	e0,d1
 	mov	(a0+),e1
-	addc	e1,d1
 	mov	(a0+),e3
+	add	d0,d1
+	addc	e0,d1
+	addc	e1,d1
 	addc	e3,d1
 	addc	+0,d1
 	add	-16,d2
@@ -131,9 +128,9 @@
 	xor_cmp	d0,d0,+2,d2
 	bcs	do_csum_fewer_than_2
 	movhu	(a0+),d0
-do_csum_fewer_than_2:
 	and	+1,d2
 	beq	do_csum_add_last_bit
+do_csum_fewer_than_2:
 	movbu	(a0),d3
 	add	d3,d0
 do_csum_add_last_bit:
@@ -142,21 +139,19 @@
 
 do_csum_done:
 	# compress the checksum down to 16 bits
-	mov	+0xffff0000,d2
-	and	d1,d2
+	mov	+0xffff0000,d0
+	and	d1,d0
 	asl	+16,d1
-	add	d2,d1,d0
+	add	d1,d0
 	addc	+0xffff,d0
 	lsr	+16,d0
 
 	# flip the halves of the word result if the buffer was oddly aligned
-	mov	(12,sp),d1
-	and	+1,d1
+	and	+1,a1
 	beq	do_csum_not_oddly_aligned
 	swaph	d0,d0				# exchange bits 15:8 with 7:0
 
 do_csum_not_oddly_aligned:
 	ret	[d2,d3],8
 
-do_csum_end:
-	.size	do_csum, do_csum_end-do_csum
+	.size	do_csum, .-do_csum
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/Makefile linux-libre-2.6.37-gnu/arch/mn10300/Makefile
--- linux-libre-2.6.36-gnu/arch/mn10300/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,9 @@
 ifeq ($(CONFIG_MN10300_PROC_MN103E010),y)
 PROCESSOR	:= mn103e010
 endif
+ifeq ($(CONFIG_MN10300_PROC_MN2WS0050),y)
+PROCESSOR	:= mn2ws0050
+endif
 
 ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y)
 UNIT		:= asb2303
@@ -43,6 +46,9 @@
 ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y)
 UNIT		:= asb2305
 endif
+ifeq ($(CONFIG_MN10300_UNIT_ASB2364),y)
+UNIT		:= asb2364
+endif
 
 
 head-y		:= arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,8 +18,13 @@
 #include <asm/cacheflush.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
 
 EXPORT_SYMBOL(mn10300_icache_inv);
+EXPORT_SYMBOL(mn10300_icache_inv_range);
+EXPORT_SYMBOL(mn10300_icache_inv_range2);
+EXPORT_SYMBOL(mn10300_icache_inv_page);
 EXPORT_SYMBOL(mn10300_dcache_inv);
 EXPORT_SYMBOL(mn10300_dcache_inv_range);
 EXPORT_SYMBOL(mn10300_dcache_inv_range2);
@@ -37,96 +42,6 @@
 #endif
 
 /*
- * write a page back from the dcache and invalidate the icache so that we can
- * run code from it that we've just written into it
- */
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
-	mn10300_dcache_flush_page(page_to_phys(page));
-	mn10300_icache_inv();
-}
-EXPORT_SYMBOL(flush_icache_page);
-
-/*
- * write some code we've just written back from the dcache and invalidate the
- * icache so that we can run that code
- */
-void flush_icache_range(unsigned long start, unsigned long end)
-{
-#ifdef CONFIG_MN10300_CACHE_WBACK
-	unsigned long addr, size, base, off;
-	struct page *page;
-	pgd_t *pgd;
-	pud_t *pud;
-	pmd_t *pmd;
-	pte_t *ppte, pte;
-
-	if (end > 0x80000000UL) {
-		/* addresses above 0xa0000000 do not go through the cache */
-		if (end > 0xa0000000UL) {
-			end = 0xa0000000UL;
-			if (start >= end)
-				return;
-		}
-
-		/* kernel addresses between 0x80000000 and 0x9fffffff do not
-		 * require page tables, so we just map such addresses directly */
-		base = (start >= 0x80000000UL) ? start : 0x80000000UL;
-		mn10300_dcache_flush_range(base, end);
-		if (base == start)
-			goto invalidate;
-		end = base;
-	}
-
-	for (; start < end; start += size) {
-		/* work out how much of the page to flush */
-		off = start & (PAGE_SIZE - 1);
-
-		size = end - start;
-		if (size > PAGE_SIZE - off)
-			size = PAGE_SIZE - off;
-
-		/* get the physical address the page is mapped to from the page
-		 * tables */
-		pgd = pgd_offset(current->mm, start);
-		if (!pgd || !pgd_val(*pgd))
-			continue;
-
-		pud = pud_offset(pgd, start);
-		if (!pud || !pud_val(*pud))
-			continue;
-
-		pmd = pmd_offset(pud, start);
-		if (!pmd || !pmd_val(*pmd))
-			continue;
-
-		ppte = pte_offset_map(pmd, start);
-		if (!ppte)
-			continue;
-		pte = *ppte;
-		pte_unmap(ppte);
-
-		if (pte_none(pte))
-			continue;
-
-		page = pte_page(pte);
-		if (!page)
-			continue;
-
-		addr = page_to_phys(page);
-
-		/* flush the dcache and invalidate the icache coverage on that
-		 * region */
-		mn10300_dcache_flush_range2(addr + off, size);
-	}
-#endif
-
-invalidate:
-	mn10300_icache_inv();
-}
-EXPORT_SYMBOL(flush_icache_range);
-
-/*
  * allow userspace to flush the instruction cache
  */
 asmlinkage long sys_cacheflush(unsigned long start, unsigned long end)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-by-reg.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-by-reg.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-by-reg.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-by-reg.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,308 @@
+/* MN10300 CPU core caching routines, using indirect regs on cache controller
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+
+	.am33_2
+
+#ifndef CONFIG_SMP
+	.globl mn10300_dcache_flush
+	.globl mn10300_dcache_flush_page
+	.globl mn10300_dcache_flush_range
+	.globl mn10300_dcache_flush_range2
+	.globl mn10300_dcache_flush_inv
+	.globl mn10300_dcache_flush_inv_page
+	.globl mn10300_dcache_flush_inv_range
+	.globl mn10300_dcache_flush_inv_range2
+
+mn10300_dcache_flush		= mn10300_local_dcache_flush
+mn10300_dcache_flush_page	= mn10300_local_dcache_flush_page
+mn10300_dcache_flush_range	= mn10300_local_dcache_flush_range
+mn10300_dcache_flush_range2	= mn10300_local_dcache_flush_range2
+mn10300_dcache_flush_inv	= mn10300_local_dcache_flush_inv
+mn10300_dcache_flush_inv_page	= mn10300_local_dcache_flush_inv_page
+mn10300_dcache_flush_inv_range	= mn10300_local_dcache_flush_inv_range
+mn10300_dcache_flush_inv_range2	= mn10300_local_dcache_flush_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush(void)
+# Flush the entire data cache back to RAM
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush
+        .type	mn10300_local_dcache_flush,@function
+mn10300_local_dcache_flush:
+	movhu	(CHCTR),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_flush_end
+
+	mov	DCPGCR,a0
+
+	LOCAL_CLI_SAVE(d1)
+
+	# wait for busy bit of area purge
+	setlb
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	# set mask
+	clr	d0
+	mov	d0,(DCPGMR)
+
+	# area purge
+	#
+	# DCPGCR = DCPGCR_DCP
+	#
+	mov	DCPGCR_DCP,d0
+	mov	d0,(a0)
+
+	# wait for busy bit of area purge
+	setlb
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	LOCAL_IRQ_RESTORE(d1)
+
+mn10300_local_dcache_flush_end:
+	ret	[],0
+	.size	mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_page(unsigned long start)
+# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
+# Flush a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_page
+	.globl	mn10300_local_dcache_flush_range
+	.globl	mn10300_local_dcache_flush_range2
+	.type	mn10300_local_dcache_flush_page,@function
+	.type	mn10300_local_dcache_flush_range,@function
+	.type	mn10300_local_dcache_flush_range2,@function
+mn10300_local_dcache_flush_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_flush_range2:
+	add	d0,d1
+mn10300_local_dcache_flush_range:
+	movm	[d2,d3,a2],(sp)
+
+	movhu	(CHCTR),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_flush_range_end
+
+	# calculate alignsize
+	#
+	# alignsize = L1_CACHE_BYTES;
+	# for (i = (end - start - 1) / L1_CACHE_BYTES ;  i > 0; i >>= 1)
+	#     alignsize <<= 1;
+	# d2 = alignsize;
+	#
+	mov	L1_CACHE_BYTES,d2
+	sub	d0,d1,d3
+	add	-1,d3
+	lsr	L1_CACHE_SHIFT,d3
+	beq	2f
+1:
+	add     d2,d2
+	lsr     1,d3
+	bne     1b
+2:
+	mov	d1,a1		# a1 = end
+
+	LOCAL_CLI_SAVE(d3)
+	mov	DCPGCR,a0
+
+	# wait for busy bit of area purge
+	setlb
+	mov	(a0),d1
+	btst	DCPGCR_DCPGBSY,d1
+	lne
+
+	# determine the mask
+	mov	d2,d1
+	add	-1,d1
+	not	d1		# d1 = mask = ~(alignsize-1)
+	mov	d1,(DCPGMR)
+
+	and	d1,d0,a2	# a2 = mask & start
+
+dcpgloop:
+	# area purge
+	mov	a2,d0
+	or	DCPGCR_DCP,d0
+	mov	d0,(a0)		# DCPGCR = (mask & start) | DCPGCR_DCP
+
+	# wait for busy bit of area purge
+	setlb
+	mov	(a0),d1
+	btst	DCPGCR_DCPGBSY,d1
+	lne
+
+	# check purge of end address
+	add	d2,a2		# a2 += alignsize
+	cmp	a1,a2		# if (a2 < end) goto dcpgloop
+	bns	dcpgloop
+
+	LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_flush_range_end:
+	ret	[d2,d3,a2],12
+
+	.size	mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
+	.size	mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
+	.size	mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv(void)
+# Flush the entire data cache and invalidate all entries
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_inv
+	.type	mn10300_local_dcache_flush_inv,@function
+mn10300_local_dcache_flush_inv:
+	movhu	(CHCTR),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_flush_inv_end
+
+	mov	DCPGCR,a0
+
+	LOCAL_CLI_SAVE(d1)
+
+	# wait for busy bit of area purge & invalidate
+	setlb
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	# set the mask to cover everything
+	clr	d0
+	mov	d0,(DCPGMR)
+
+	# area purge & invalidate
+	mov	DCPGCR_DCP|DCPGCR_DCI,d0
+	mov	d0,(a0)
+
+	# wait for busy bit of area purge & invalidate
+	setlb
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	LOCAL_IRQ_RESTORE(d1)
+
+mn10300_local_dcache_flush_inv_end:
+	ret	[],0
+	.size	mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv_page(unsigned long start)
+# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+# Flush and invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_inv_page
+	.globl	mn10300_local_dcache_flush_inv_range
+	.globl	mn10300_local_dcache_flush_inv_range2
+	.type	mn10300_local_dcache_flush_inv_page,@function
+	.type	mn10300_local_dcache_flush_inv_range,@function
+	.type	mn10300_local_dcache_flush_inv_range2,@function
+mn10300_local_dcache_flush_inv_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_flush_inv_range2:
+	add	d0,d1
+mn10300_local_dcache_flush_inv_range:
+	movm	[d2,d3,a2],(sp)
+
+	movhu	(CHCTR),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_flush_inv_range_end
+
+	# calculate alignsize
+	#
+	# alignsize = L1_CACHE_BYTES;
+	# for (i = (end - start - 1) / L1_CACHE_BYTES; i > 0; i >>= 1)
+	#     alignsize <<= 1;
+	# d2 = alignsize
+	#
+	mov	L1_CACHE_BYTES,d2
+	sub	d0,d1,d3
+	add	-1,d3
+	lsr	L1_CACHE_SHIFT,d3
+	beq	2f
+1:
+	add     d2,d2
+	lsr     1,d3
+	bne     1b
+2:
+	mov	d1,a1		# a1 = end
+
+	LOCAL_CLI_SAVE(d3)
+	mov	DCPGCR,a0
+
+	# wait for busy bit of area purge & invalidate
+	setlb
+	mov	(a0),d1
+	btst	DCPGCR_DCPGBSY,d1
+	lne
+
+	# set the mask
+	mov	d2,d1
+	add	-1,d1
+	not	d1		# d1 = mask = ~(alignsize-1)
+	mov	d1,(DCPGMR)
+
+	and	d1,d0,a2	# a2 = mask & start
+
+dcpgivloop:
+	# area purge & invalidate
+	mov	a2,d0
+	or	DCPGCR_DCP|DCPGCR_DCI,d0
+	mov	d0,(a0)		# DCPGCR = (mask & start)|DCPGCR_DCP|DCPGCR_DCI
+
+	# wait for busy bit of area purge & invalidate
+	setlb
+	mov	(a0),d1
+	btst	DCPGCR_DCPGBSY,d1
+	lne
+
+	# check purge & invalidate of end address
+	add	d2,a2		# a2 += alignsize
+	cmp	a1,a2		# if (a2 < end) goto dcpgivloop
+	bns	dcpgivloop
+
+	LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_flush_inv_range_end:
+	ret	[d2,d3,a2],12
+	.size	mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
+	.size	mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
+	.size	mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-by-tag.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-by-tag.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-by-tag.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-by-tag.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,251 @@
+/* MN10300 CPU core caching routines, using direct tag flushing
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+
+	.am33_2
+
+#ifndef CONFIG_SMP
+	.globl mn10300_dcache_flush
+	.globl mn10300_dcache_flush_page
+	.globl mn10300_dcache_flush_range
+	.globl mn10300_dcache_flush_range2
+	.globl mn10300_dcache_flush_inv
+	.globl mn10300_dcache_flush_inv_page
+	.globl mn10300_dcache_flush_inv_range
+	.globl mn10300_dcache_flush_inv_range2
+
+mn10300_dcache_flush		= mn10300_local_dcache_flush
+mn10300_dcache_flush_page	= mn10300_local_dcache_flush_page
+mn10300_dcache_flush_range	= mn10300_local_dcache_flush_range
+mn10300_dcache_flush_range2	= mn10300_local_dcache_flush_range2
+mn10300_dcache_flush_inv	= mn10300_local_dcache_flush_inv
+mn10300_dcache_flush_inv_page	= mn10300_local_dcache_flush_inv_page
+mn10300_dcache_flush_inv_range	= mn10300_local_dcache_flush_inv_range
+mn10300_dcache_flush_inv_range2	= mn10300_local_dcache_flush_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush(void)
+# Flush the entire data cache back to RAM
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush
+        .type	mn10300_local_dcache_flush,@function
+mn10300_local_dcache_flush:
+	movhu	(CHCTR),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_flush_end
+
+	# read the addresses tagged in the cache's tag RAM and attempt to flush
+	# those addresses specifically
+	# - we rely on the hardware to filter out invalid tag entry addresses
+	mov	DCACHE_TAG(0,0),a0		# dcache tag RAM access address
+	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
+	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
+
+mn10300_local_dcache_flush_loop:
+	mov	(a0),d0
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+	or	L1_CACHE_TAG_VALID,d0		# retain valid entries in the
+						# cache
+	mov	d0,(a1)				# conditional purge
+
+	add	L1_CACHE_BYTES,a0
+	add	L1_CACHE_BYTES,a1
+	add	-1,d1
+	bne	mn10300_local_dcache_flush_loop
+
+mn10300_local_dcache_flush_end:
+	ret	[],0
+	.size	mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_page(unsigned long start)
+# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
+# Flush a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_page
+	.globl	mn10300_local_dcache_flush_range
+	.globl	mn10300_local_dcache_flush_range2
+	.type	mn10300_local_dcache_flush_page,@function
+	.type	mn10300_local_dcache_flush_range,@function
+	.type	mn10300_local_dcache_flush_range2,@function
+mn10300_local_dcache_flush_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_flush_range2:
+	add	d0,d1
+mn10300_local_dcache_flush_range:
+	movm	[d2],(sp)
+
+	movhu	(CHCTR),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_flush_range_end
+
+	sub	d0,d1,a0
+	cmp	MN10300_DCACHE_FLUSH_BORDER,a0
+	ble	1f
+
+	movm	(sp),[d2]
+	bra	mn10300_local_dcache_flush
+1:
+
+	# round start addr down
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
+	mov	d0,a1
+
+	add	L1_CACHE_BYTES,d1			# round end addr up
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+
+	# write a request to flush all instances of an address from the cache
+	mov	DCACHE_PURGE(0,0),a0
+	mov	a1,d0
+	and	L1_CACHE_TAG_ENTRY,d0
+	add	d0,a0				# starting dcache purge control
+						# reg address
+
+	sub	a1,d1
+	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
+						# examine
+
+	or	L1_CACHE_TAG_VALID,a1		# retain valid entries in the
+						# cache
+
+mn10300_local_dcache_flush_range_loop:
+	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
+						# all ways
+
+	add	L1_CACHE_BYTES,a0
+	add	L1_CACHE_BYTES,a1
+	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
+	add	-1,d1
+	bne	mn10300_local_dcache_flush_range_loop
+
+mn10300_local_dcache_flush_range_end:
+	ret	[d2],4
+
+	.size	mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
+	.size	mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
+	.size	mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv(void)
+# Flush the entire data cache and invalidate all entries
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_inv
+	.type	mn10300_local_dcache_flush_inv,@function
+mn10300_local_dcache_flush_inv:
+	movhu	(CHCTR),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_flush_inv_end
+
+	mov	L1_CACHE_NENTRIES,d1
+	clr	a1
+
+mn10300_local_dcache_flush_inv_loop:
+	mov	(DCACHE_PURGE_WAY0(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY1(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY2(0),a1),d0	# unconditional purge
+	mov	(DCACHE_PURGE_WAY3(0),a1),d0	# unconditional purge
+
+	add	L1_CACHE_BYTES,a1
+	add	-1,d1
+	bne	mn10300_local_dcache_flush_inv_loop
+
+mn10300_local_dcache_flush_inv_end:
+	ret	[],0
+	.size	mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_flush_inv_page(unsigned long start)
+# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+# Flush and invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_flush_inv_page
+	.globl	mn10300_local_dcache_flush_inv_range
+	.globl	mn10300_local_dcache_flush_inv_range2
+	.type	mn10300_local_dcache_flush_inv_page,@function
+	.type	mn10300_local_dcache_flush_inv_range,@function
+	.type	mn10300_local_dcache_flush_inv_range2,@function
+mn10300_local_dcache_flush_inv_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_flush_inv_range2:
+	add	d0,d1
+mn10300_local_dcache_flush_inv_range:
+	movm	[d2],(sp)
+
+	movhu	(CHCTR),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_flush_inv_range_end
+
+	sub	d0,d1,a0
+	cmp	MN10300_DCACHE_FLUSH_INV_BORDER,a0
+	ble	1f
+
+	movm	(sp),[d2]
+	bra	mn10300_local_dcache_flush_inv
+1:
+
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start
+								# addr down
+	mov	d0,a1
+
+	add	L1_CACHE_BYTES,d1			# round end addr up
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+
+	# write a request to flush and invalidate all instances of an address
+	# from the cache
+	mov	DCACHE_PURGE(0,0),a0
+	mov	a1,d0
+	and	L1_CACHE_TAG_ENTRY,d0
+	add	d0,a0				# starting dcache purge control
+						# reg address
+
+	sub	a1,d1
+	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
+						# examine
+
+mn10300_local_dcache_flush_inv_range_loop:
+	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
+						# in all ways
+
+	add	L1_CACHE_BYTES,a0
+	add	L1_CACHE_BYTES,a1
+	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
+	add	-1,d1
+	bne	mn10300_local_dcache_flush_inv_range_loop
+
+mn10300_local_dcache_flush_inv_range_end:
+	ret	[d2],4
+	.size	mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
+	.size	mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
+	.size	mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-icache.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-icache.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-icache.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-icache.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,155 @@
+/* Flush dcache and invalidate icache when the dcache is in writeback mode
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+/**
+ * flush_icache_page - Flush a page from the dcache and invalidate the icache
+ * @vma: The VMA the page is part of.
+ * @page: The page to be flushed.
+ *
+ * Write a page back from the dcache and invalidate the icache so that we can
+ * run code from it that we've just written into it
+ */
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+	unsigned long start = page_to_phys(page);
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+
+	mn10300_local_dcache_flush_page(start);
+	mn10300_local_icache_inv_page(start);
+
+	smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, start + PAGE_SIZE);
+	smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_page);
+
+/**
+ * flush_icache_page_range - Flush dcache and invalidate icache for part of a
+ *				single page
+ * @start: The starting virtual address of the page part.
+ * @end: The ending virtual address of the page part.
+ *
+ * Flush the dcache and invalidate the icache for part of a single page, as
+ * determined by the virtual addresses given.  The page must be in the paged
+ * area.
+ */
+static void flush_icache_page_range(unsigned long start, unsigned long end)
+{
+	unsigned long addr, size, off;
+	struct page *page;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *ppte, pte;
+
+	/* work out how much of the page to flush */
+	off = start & ~PAGE_MASK;
+	size = end - start;
+
+	/* get the physical address the page is mapped to from the page
+	 * tables */
+	pgd = pgd_offset(current->mm, start);
+	if (!pgd || !pgd_val(*pgd))
+		return;
+
+	pud = pud_offset(pgd, start);
+	if (!pud || !pud_val(*pud))
+		return;
+
+	pmd = pmd_offset(pud, start);
+	if (!pmd || !pmd_val(*pmd))
+		return;
+
+	ppte = pte_offset_map(pmd, start);
+	if (!ppte)
+		return;
+	pte = *ppte;
+	pte_unmap(ppte);
+
+	if (pte_none(pte))
+		return;
+
+	page = pte_page(pte);
+	if (!page)
+		return;
+
+	addr = page_to_phys(page);
+
+	/* flush the dcache and invalidate the icache coverage on that
+	 * region */
+	mn10300_local_dcache_flush_range2(addr + off, size);
+	mn10300_local_icache_inv_range2(addr + off, size);
+	smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start, end);
+}
+
+/**
+ * flush_icache_range - Globally flush dcache and invalidate icache for region
+ * @start: The starting virtual address of the region.
+ * @end: The ending virtual address of the region.
+ *
+ * This is used by the kernel to globally flush some code it has just written
+ * from the dcache back to RAM and then to globally invalidate the icache over
+ * that region so that that code can be run on all CPUs in the system.
+ */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+	unsigned long start_page, end_page;
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+
+	if (end > 0x80000000UL) {
+		/* addresses above 0xa0000000 do not go through the cache */
+		if (end > 0xa0000000UL) {
+			end = 0xa0000000UL;
+			if (start >= end)
+				goto done;
+		}
+
+		/* kernel addresses between 0x80000000 and 0x9fffffff do not
+		 * require page tables, so we just map such addresses
+		 * directly */
+		start_page = (start >= 0x80000000UL) ? start : 0x80000000UL;
+		mn10300_local_dcache_flush_range(start_page, end);
+		mn10300_local_icache_inv_range(start_page, end);
+		smp_cache_call(SMP_IDCACHE_INV_FLUSH_RANGE, start_page, end);
+		if (start_page == start)
+			goto done;
+		end = start_page;
+	}
+
+	start_page = start & PAGE_MASK;
+	end_page = (end - 1) & PAGE_MASK;
+
+	if (start_page == end_page) {
+		/* the first and last bytes are on the same page */
+		flush_icache_page_range(start, end);
+	} else if (start_page + 1 == end_page) {
+		/* split over two virtually contiguous pages */
+		flush_icache_page_range(start, end_page);
+		flush_icache_page_range(end_page, end);
+	} else {
+		/* more than 2 pages; just flush the entire cache */
+		mn10300_dcache_flush();
+		mn10300_icache_inv();
+		smp_cache_call(SMP_IDCACHE_INV_FLUSH, 0, 0);
+	}
+
+done:
+	smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_range);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-mn10300.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-mn10300.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-flush-mn10300.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-flush-mn10300.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,192 +0,0 @@
-/* MN10300 CPU core caching routines
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/smp.h>
-#include <asm/page.h>
-#include <asm/cache.h>
-
-	.am33_2
-	.globl mn10300_dcache_flush
-	.globl mn10300_dcache_flush_page
-	.globl mn10300_dcache_flush_range
-	.globl mn10300_dcache_flush_range2
-	.globl mn10300_dcache_flush_inv
-	.globl mn10300_dcache_flush_inv_page
-	.globl mn10300_dcache_flush_inv_range
-	.globl mn10300_dcache_flush_inv_range2
-
-###############################################################################
-#
-# void mn10300_dcache_flush(void)
-# Flush the entire data cache back to RAM
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_flush:
-	movhu	(CHCTR),d0
-	btst	CHCTR_DCEN,d0
-	beq	mn10300_dcache_flush_end
-
-	# read the addresses tagged in the cache's tag RAM and attempt to flush
-	# those addresses specifically
-	# - we rely on the hardware to filter out invalid tag entry addresses
-	mov	DCACHE_TAG(0,0),a0		# dcache tag RAM access address
-	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
-	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
-
-mn10300_dcache_flush_loop:
-	mov	(a0),d0
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
-	or	L1_CACHE_TAG_VALID,d0		# retain valid entries in the
-						# cache
-	mov	d0,(a1)				# conditional purge
-
-mn10300_dcache_flush_skip:
-	add	L1_CACHE_BYTES,a0
-	add	L1_CACHE_BYTES,a1
-	add	-1,d1
-	bne	mn10300_dcache_flush_loop
-
-mn10300_dcache_flush_end:
-	ret	[],0
-
-###############################################################################
-#
-# void mn10300_dcache_flush_page(unsigned start)
-# void mn10300_dcache_flush_range(unsigned start, unsigned end)
-# void mn10300_dcache_flush_range2(unsigned start, unsigned size)
-# Flush a range of addresses on a page in the dcache
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_flush_page:
-	mov	PAGE_SIZE,d1
-mn10300_dcache_flush_range2:
-	add	d0,d1
-mn10300_dcache_flush_range:
-	movm	[d2,d3],(sp)
-
-	movhu	(CHCTR),d2
-	btst	CHCTR_DCEN,d2
-	beq	mn10300_dcache_flush_range_end
-
-	# round start addr down
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
-	mov	d0,a1
-
-	add	L1_CACHE_BYTES,d1			# round end addr up
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
-	# write a request to flush all instances of an address from the cache
-	mov	DCACHE_PURGE(0,0),a0
-	mov	a1,d0
-	and	L1_CACHE_TAG_ENTRY,d0
-	add	d0,a0				# starting dcache purge control
-						# reg address
-
-	sub	a1,d1
-	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
-						# examine
-
-	or	L1_CACHE_TAG_VALID,a1		# retain valid entries in the
-						# cache
-
-mn10300_dcache_flush_range_loop:
-	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
-						# all ways
-
-	add	L1_CACHE_BYTES,a0
-	add	L1_CACHE_BYTES,a1
-	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
-	add	-1,d1
-	bne	mn10300_dcache_flush_range_loop
-
-mn10300_dcache_flush_range_end:
-	ret	[d2,d3],8
-
-###############################################################################
-#
-# void mn10300_dcache_flush_inv(void)
-# Flush the entire data cache and invalidate all entries
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_flush_inv:
-	movhu	(CHCTR),d0
-	btst	CHCTR_DCEN,d0
-	beq	mn10300_dcache_flush_inv_end
-
-	# hit each line in the dcache with an unconditional purge
-	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
-	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
-
-mn10300_dcache_flush_inv_loop:
-	mov	(a1),d0				# unconditional purge
-
-	add	L1_CACHE_BYTES,a1
-	add	-1,d1
-	bne	mn10300_dcache_flush_inv_loop
-
-mn10300_dcache_flush_inv_end:
-	ret	[],0
-
-###############################################################################
-#
-# void mn10300_dcache_flush_inv_page(unsigned start)
-# void mn10300_dcache_flush_inv_range(unsigned start, unsigned end)
-# void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size)
-# Flush and invalidate a range of addresses on a page in the dcache
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_flush_inv_page:
-	mov	PAGE_SIZE,d1
-mn10300_dcache_flush_inv_range2:
-	add	d0,d1
-mn10300_dcache_flush_inv_range:
-	movm	[d2,d3],(sp)
-	movhu	(CHCTR),d2
-	btst	CHCTR_DCEN,d2
-	beq	mn10300_dcache_flush_inv_range_end
-
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start
-								# addr down
-	mov	d0,a1
-
-	add	L1_CACHE_BYTES,d1			# round end addr up
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
-	# write a request to flush and invalidate all instances of an address
-	# from the cache
-	mov	DCACHE_PURGE(0,0),a0
-	mov	a1,d0
-	and	L1_CACHE_TAG_ENTRY,d0
-	add	d0,a0				# starting dcache purge control
-						# reg address
-
-	sub	a1,d1
-	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
-						# examine
-
-mn10300_dcache_flush_inv_range_loop:
-	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
-						# in all ways
-
-	add	L1_CACHE_BYTES,a0
-	add	L1_CACHE_BYTES,a1
-	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
-	add	-1,d1
-	bne	mn10300_dcache_flush_inv_range_loop
-
-mn10300_dcache_flush_inv_range_end:
-	ret	[d2,d3],8
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-by-reg.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-by-reg.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-by-reg.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-by-reg.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,356 @@
+/* MN10300 CPU cache invalidation routines, using automatic purge registers
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+
+#define mn10300_local_dcache_inv_range_intr_interval \
+	+((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
+
+#if mn10300_local_dcache_inv_range_intr_interval > 0xff
+#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
+#endif
+
+	.am33_2
+
+#ifndef CONFIG_SMP
+	.globl	mn10300_icache_inv
+	.globl	mn10300_icache_inv_page
+	.globl	mn10300_icache_inv_range
+	.globl	mn10300_icache_inv_range2
+	.globl	mn10300_dcache_inv
+	.globl	mn10300_dcache_inv_page
+	.globl	mn10300_dcache_inv_range
+	.globl	mn10300_dcache_inv_range2
+
+mn10300_icache_inv		= mn10300_local_icache_inv
+mn10300_icache_inv_page		= mn10300_local_icache_inv_page
+mn10300_icache_inv_range	= mn10300_local_icache_inv_range
+mn10300_icache_inv_range2	= mn10300_local_icache_inv_range2
+mn10300_dcache_inv		= mn10300_local_dcache_inv
+mn10300_dcache_inv_page		= mn10300_local_dcache_inv_page
+mn10300_dcache_inv_range	= mn10300_local_dcache_inv_range
+mn10300_dcache_inv_range2	= mn10300_local_dcache_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_icache_inv(void)
+# Invalidate the entire icache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_icache_inv
+        .type	mn10300_local_icache_inv,@function
+mn10300_local_icache_inv:
+	mov	CHCTR,a0
+
+	movhu	(a0),d0
+	btst	CHCTR_ICEN,d0
+	beq	mn10300_local_icache_inv_end
+
+	# invalidate
+	or	CHCTR_ICINV,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+
+mn10300_local_icache_inv_end:
+	ret	[],0
+	.size	mn10300_local_icache_inv,.-mn10300_local_icache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv(void)
+# Invalidate the entire dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_inv
+	.type	mn10300_local_dcache_inv,@function
+mn10300_local_dcache_inv:
+	mov	CHCTR,a0
+
+	movhu	(a0),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_inv_end
+
+	# invalidate
+	or	CHCTR_DCINV,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+
+mn10300_local_dcache_inv_end:
+	ret	[],0
+	.size	mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_dcache_inv_page(unsigned long start)
+# Invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_inv_page
+	.globl	mn10300_local_dcache_inv_range
+	.globl	mn10300_local_dcache_inv_range2
+	.type	mn10300_local_dcache_inv_page,@function
+	.type	mn10300_local_dcache_inv_range,@function
+	.type	mn10300_local_dcache_inv_range2,@function
+mn10300_local_dcache_inv_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_inv_range2:
+	add	d0,d1
+mn10300_local_dcache_inv_range:
+	# If we are in writeback mode we check the start and end alignments,
+	# and if they're not cacheline-aligned, we must flush any bits outside
+	# the range that share cachelines with stuff inside the range
+#ifdef CONFIG_MN10300_CACHE_WBACK
+	btst	~(L1_CACHE_BYTES-1),d0
+	bne	1f
+	btst	~(L1_CACHE_BYTES-1),d1
+	beq	2f
+1:
+	bra	mn10300_local_dcache_flush_inv_range
+2:
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+	movm	[d2,d3,a2],(sp)
+
+	mov	CHCTR,a0
+	movhu	(a0),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_inv_range_end
+
+	# round the addresses out to be full cachelines, unless we're in
+	# writeback mode, in which case we would be in flush and invalidate by
+	# now
+#ifndef CONFIG_MN10300_CACHE_WBACK
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start
+								# addr down
+
+	mov	L1_CACHE_BYTES-1,d2
+	add	d2,d1
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1	# round end addr up
+#endif /* !CONFIG_MN10300_CACHE_WBACK */
+
+	sub	d0,d1,d2		# calculate the total size
+	mov	d0,a2			# A2 = start address
+	mov	d1,a1			# A1 = end address
+
+	LOCAL_CLI_SAVE(d3)
+
+	mov	DCPGCR,a0		# make sure the purger isn't busy
+	setlb
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	# skip initial address alignment calculation if address is zero
+	mov	d2,d1
+	cmp	0,a2
+	beq	1f
+
+dcivloop:
+	/* calculate alignsize
+	 *
+	 * alignsize = L1_CACHE_BYTES;
+	 * while (! start & alignsize) {
+	 *	alignsize <<=1;
+	 * }
+	 * d1 = alignsize;
+	 */
+	mov	L1_CACHE_BYTES,d1
+	lsr	1,d1
+	setlb
+	add	d1,d1
+	mov	d1,d0
+	and	a2,d0
+	leq
+
+1:
+	/* calculate invsize
+	 *
+	 * if (totalsize > alignsize) {
+	 *	invsize = alignsize;
+	 * } else {
+	 *	invsize = totalsize;
+	 *	tmp = 0x80000000;
+	 *	while (! invsize & tmp) {
+	 *		tmp >>= 1;
+	 *	}
+	 *	invsize = tmp;
+	 * }
+	 * d1 = invsize
+	 */
+	cmp	d2,d1
+	bns	2f
+	mov	d2,d1
+
+	mov	0x80000000,d0		# start from 31bit=1
+	setlb
+	lsr	1,d0
+	mov	d0,e0
+	and	d1,e0
+	leq
+	mov	d0,d1
+
+2:
+	/* set mask
+	 *
+	 * mask = ~(invsize-1);
+	 * DCPGMR = mask;
+	 */
+	mov	d1,d0
+	add	-1,d0
+	not	d0
+	mov	d0,(DCPGMR)
+
+	# invalidate area
+	mov	a2,d0
+	or	DCPGCR_DCI,d0
+	mov	d0,(a0)			# DCPGCR = (mask & start) | DCPGCR_DCI
+
+	setlb				# wait for the purge to complete
+	mov	(a0),d0
+	btst	DCPGCR_DCPGBSY,d0
+	lne
+
+	sub	d1,d2			# decrease size remaining
+	add	d1,a2			# increase next start address
+
+	/* check invalidating of end address
+	 *
+	 * a2 = a2 + invsize
+	 * if (a2 < end) {
+	 *     goto dcivloop;
+	 * } */
+	cmp	a1,a2
+	bns	dcivloop
+
+	LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_dcache_inv_range_end:
+	ret	[d2,d3,a2],12
+	.size	mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
+	.size	mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
+	.size	mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
+
+###############################################################################
+#
+# void mn10300_local_icache_inv_page(unsigned long start)
+# void mn10300_local_icache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_icache_inv_range(unsigned long start, unsigned long end)
+# Invalidate a range of addresses on a page in the icache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_icache_inv_page
+	.globl	mn10300_local_icache_inv_range
+	.globl	mn10300_local_icache_inv_range2
+	.type	mn10300_local_icache_inv_page,@function
+	.type	mn10300_local_icache_inv_range,@function
+	.type	mn10300_local_icache_inv_range2,@function
+mn10300_local_icache_inv_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_icache_inv_range2:
+	add	d0,d1
+mn10300_local_icache_inv_range:
+	movm	[d2,d3,a2],(sp)
+
+	mov	CHCTR,a0
+	movhu	(a0),d2
+	btst	CHCTR_ICEN,d2
+	beq	mn10300_local_icache_inv_range_reg_end
+
+	/* calculate alignsize
+	 *
+	 * alignsize = L1_CACHE_BYTES;
+	 * for (i = (end - start - 1) / L1_CACHE_BYTES ;  i > 0; i >>= 1) {
+	 *     alignsize <<= 1;
+	 * }
+	 * d2 = alignsize;
+	 */
+	mov	L1_CACHE_BYTES,d2
+	sub	d0,d1,d3
+	add	-1,d3
+	lsr	L1_CACHE_SHIFT,d3
+	beq	2f
+1:
+	add	d2,d2
+	lsr	1,d3
+	bne	1b
+2:
+
+	/* a1 = end */
+	mov	d1,a1
+
+	LOCAL_CLI_SAVE(d3)
+
+	mov	ICIVCR,a0
+	/* wait for busy bit of area invalidation */
+	setlb
+	mov	(a0),d1
+	btst	ICIVCR_ICIVBSY,d1
+	lne
+
+	/* set mask
+	 *
+	 * mask = ~(alignsize-1);
+	 * ICIVMR = mask;
+	 */
+	mov	d2,d1
+	add	-1,d1
+	not	d1
+	mov	d1,(ICIVMR)
+	/* a2 = mask & start */
+	and	d1,d0,a2
+
+icivloop:
+	/* area invalidate
+	 *
+	 * ICIVCR = (mask & start) | ICIVCR_ICI
+	 */
+	mov	a2,d0
+	or	ICIVCR_ICI,d0
+	mov	d0,(a0)
+
+	/* wait for busy bit of area invalidation */
+	setlb
+	mov	(a0),d1
+	btst	ICIVCR_ICIVBSY,d1
+	lne
+
+	/* check invalidating of end address
+	 *
+	 * a2 = a2 + alignsize
+	 * if (a2 < end) {
+	 *     goto icivloop;
+	 * } */
+	add	d2,a2
+	cmp	a1,a2
+	bns	icivloop
+
+	LOCAL_IRQ_RESTORE(d3)
+
+mn10300_local_icache_inv_range_reg_end:
+	ret	[d2,d3,a2],12
+	.size	mn10300_local_icache_inv_page,.-mn10300_local_icache_inv_page
+	.size	mn10300_local_icache_inv_range,.-mn10300_local_icache_inv_range
+	.size	mn10300_local_icache_inv_range2,.-mn10300_local_icache_inv_range2
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-by-tag.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-by-tag.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-by-tag.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-by-tag.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,348 @@
+/* MN10300 CPU core caching routines
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/irqflags.h>
+#include <asm/cacheflush.h>
+
+#define mn10300_local_dcache_inv_range_intr_interval \
+	+((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
+
+#if mn10300_local_dcache_inv_range_intr_interval > 0xff
+#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
+#endif
+
+	.am33_2
+
+	.globl	mn10300_local_icache_inv_page
+	.globl	mn10300_local_icache_inv_range
+	.globl	mn10300_local_icache_inv_range2
+
+mn10300_local_icache_inv_page	= mn10300_local_icache_inv
+mn10300_local_icache_inv_range	= mn10300_local_icache_inv
+mn10300_local_icache_inv_range2	= mn10300_local_icache_inv
+
+#ifndef CONFIG_SMP
+	.globl	mn10300_icache_inv
+	.globl	mn10300_icache_inv_page
+	.globl	mn10300_icache_inv_range
+	.globl	mn10300_icache_inv_range2
+	.globl	mn10300_dcache_inv
+	.globl	mn10300_dcache_inv_page
+	.globl	mn10300_dcache_inv_range
+	.globl	mn10300_dcache_inv_range2
+
+mn10300_icache_inv		= mn10300_local_icache_inv
+mn10300_icache_inv_page		= mn10300_local_icache_inv_page
+mn10300_icache_inv_range	= mn10300_local_icache_inv_range
+mn10300_icache_inv_range2	= mn10300_local_icache_inv_range2
+mn10300_dcache_inv		= mn10300_local_dcache_inv
+mn10300_dcache_inv_page		= mn10300_local_dcache_inv_page
+mn10300_dcache_inv_range	= mn10300_local_dcache_inv_range
+mn10300_dcache_inv_range2	= mn10300_local_dcache_inv_range2
+
+#endif /* !CONFIG_SMP */
+
+###############################################################################
+#
+# void mn10300_local_icache_inv(void)
+# Invalidate the entire icache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_icache_inv
+        .type	mn10300_local_icache_inv,@function
+mn10300_local_icache_inv:
+	mov	CHCTR,a0
+
+	movhu	(a0),d0
+	btst	CHCTR_ICEN,d0
+	beq	mn10300_local_icache_inv_end
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+	LOCAL_CLI_SAVE(d1)
+
+	# disable the icache
+	and	~CHCTR_ICEN,d0
+	movhu	d0,(a0)
+
+	# and wait for it to calm down
+	setlb
+	movhu	(a0),d0
+	btst	CHCTR_ICBUSY,d0
+	lne
+
+	# invalidate
+	or	CHCTR_ICINV,d0
+	movhu	d0,(a0)
+
+	# wait for the cache to finish
+	mov	CHCTR,a0
+	setlb
+	movhu	(a0),d0
+	btst	CHCTR_ICBUSY,d0
+	lne
+
+	# and reenable it
+	and	~CHCTR_ICINV,d0
+	or	CHCTR_ICEN,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+
+	LOCAL_IRQ_RESTORE(d1)
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+	# invalidate
+	or	CHCTR_ICINV,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+mn10300_local_icache_inv_end:
+	ret	[],0
+	.size	mn10300_local_icache_inv,.-mn10300_local_icache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv(void)
+# Invalidate the entire dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_inv
+	.type	mn10300_local_dcache_inv,@function
+mn10300_local_dcache_inv:
+	mov	CHCTR,a0
+
+	movhu	(a0),d0
+	btst	CHCTR_DCEN,d0
+	beq	mn10300_local_dcache_inv_end
+
+#if defined(CONFIG_AM33_2) || defined(CONFIG_AM33_3)
+	LOCAL_CLI_SAVE(d1)
+
+	# disable the dcache
+	and	~CHCTR_DCEN,d0
+	movhu	d0,(a0)
+
+	# and wait for it to calm down
+	setlb
+	movhu	(a0),d0
+	btst	CHCTR_DCBUSY,d0
+	lne
+
+	# invalidate
+	or	CHCTR_DCINV,d0
+	movhu	d0,(a0)
+
+	# wait for the cache to finish
+	mov	CHCTR,a0
+	setlb
+	movhu	(a0),d0
+	btst	CHCTR_DCBUSY,d0
+	lne
+
+	# and reenable it
+	and	~CHCTR_DCINV,d0
+	or	CHCTR_DCEN,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+
+	LOCAL_IRQ_RESTORE(d1)
+#else /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+	# invalidate
+	or	CHCTR_DCINV,d0
+	movhu	d0,(a0)
+	movhu	(a0),d0
+#endif /* CONFIG_AM33_2 || CONFIG_AM33_3 */
+
+mn10300_local_dcache_inv_end:
+	ret	[],0
+	.size	mn10300_local_dcache_inv,.-mn10300_local_dcache_inv
+
+###############################################################################
+#
+# void mn10300_local_dcache_inv_range(unsigned long start, unsigned long end)
+# void mn10300_local_dcache_inv_range2(unsigned long start, unsigned long size)
+# void mn10300_local_dcache_inv_page(unsigned long start)
+# Invalidate a range of addresses on a page in the dcache
+#
+###############################################################################
+	ALIGN
+	.globl	mn10300_local_dcache_inv_page
+	.globl	mn10300_local_dcache_inv_range
+	.globl	mn10300_local_dcache_inv_range2
+	.type	mn10300_local_dcache_inv_page,@function
+	.type	mn10300_local_dcache_inv_range,@function
+	.type	mn10300_local_dcache_inv_range2,@function
+mn10300_local_dcache_inv_page:
+	and	~(PAGE_SIZE-1),d0
+	mov	PAGE_SIZE,d1
+mn10300_local_dcache_inv_range2:
+	add	d0,d1
+mn10300_local_dcache_inv_range:
+	# If we are in writeback mode we check the start and end alignments,
+	# and if they're not cacheline-aligned, we must flush any bits outside
+	# the range that share cachelines with stuff inside the range
+#ifdef CONFIG_MN10300_CACHE_WBACK
+	btst	~(L1_CACHE_BYTES-1),d0
+	bne	1f
+	btst	~(L1_CACHE_BYTES-1),d1
+	beq	2f
+1:
+	bra	mn10300_local_dcache_flush_inv_range
+2:
+#endif /* CONFIG_MN10300_CACHE_WBACK */
+
+	movm	[d2,d3,a2],(sp)
+
+	mov	CHCTR,a2
+	movhu	(a2),d2
+	btst	CHCTR_DCEN,d2
+	beq	mn10300_local_dcache_inv_range_end
+
+#ifndef CONFIG_MN10300_CACHE_WBACK
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start
+								# addr down
+
+	add	L1_CACHE_BYTES,d1		# round end addr up
+	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
+#endif /* !CONFIG_MN10300_CACHE_WBACK */
+	mov	d0,a1
+
+	clr	d2				# we're going to clear tag RAM
+						# entries
+
+	# read the tags from the tag RAM, and if they indicate a valid dirty
+	# cache line then invalidate that line
+	mov	DCACHE_TAG(0,0),a0
+	mov	a1,d0
+	and	L1_CACHE_TAG_ENTRY,d0
+	add	d0,a0				# starting dcache tag RAM
+						# access address
+
+	sub	a1,d1
+	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
+						# examine
+
+	and	~(L1_CACHE_DISPARITY-1),a1	# determine comparator base
+
+mn10300_local_dcache_inv_range_outer_loop:
+	LOCAL_CLI_SAVE(d3)
+
+	# disable the dcache
+	movhu	(a2),d0
+	and	~CHCTR_DCEN,d0
+	movhu	d0,(a2)
+
+	# and wait for it to calm down
+	setlb
+	movhu	(a2),d0
+	btst	CHCTR_DCBUSY,d0
+	lne
+
+mn10300_local_dcache_inv_range_loop:
+
+	# process the way 0 slot
+	mov	(L1_CACHE_WAYDISP*0,a0),d0	# read the tag in the way 0 slot
+	btst	L1_CACHE_TAG_VALID,d0
+	beq	mn10300_local_dcache_inv_range_skip_0	# jump if this cacheline
+						# is not valid
+
+	xor	a1,d0
+	lsr	12,d0
+	bne	mn10300_local_dcache_inv_range_skip_0	# jump if not this cacheline
+
+	mov	d2,(L1_CACHE_WAYDISP*0,a0)	# kill the tag
+
+mn10300_local_dcache_inv_range_skip_0:
+
+	# process the way 1 slot
+	mov	(L1_CACHE_WAYDISP*1,a0),d0	# read the tag in the way 1 slot
+	btst	L1_CACHE_TAG_VALID,d0
+	beq	mn10300_local_dcache_inv_range_skip_1	# jump if this cacheline
+						# is not valid
+
+	xor	a1,d0
+	lsr	12,d0
+	bne	mn10300_local_dcache_inv_range_skip_1	# jump if not this cacheline
+
+	mov	d2,(L1_CACHE_WAYDISP*1,a0)	# kill the tag
+
+mn10300_local_dcache_inv_range_skip_1:
+
+	# process the way 2 slot
+	mov	(L1_CACHE_WAYDISP*2,a0),d0	# read the tag in the way 2 slot
+	btst	L1_CACHE_TAG_VALID,d0
+	beq	mn10300_local_dcache_inv_range_skip_2	# jump if this cacheline
+						# is not valid
+
+	xor	a1,d0
+	lsr	12,d0
+	bne	mn10300_local_dcache_inv_range_skip_2	# jump if not this cacheline
+
+	mov	d2,(L1_CACHE_WAYDISP*2,a0)	# kill the tag
+
+mn10300_local_dcache_inv_range_skip_2:
+
+	# process the way 3 slot
+	mov	(L1_CACHE_WAYDISP*3,a0),d0	# read the tag in the way 3 slot
+	btst	L1_CACHE_TAG_VALID,d0
+	beq	mn10300_local_dcache_inv_range_skip_3	# jump if this cacheline
+						# is not valid
+
+	xor	a1,d0
+	lsr	12,d0
+	bne	mn10300_local_dcache_inv_range_skip_3	# jump if not this cacheline
+
+	mov	d2,(L1_CACHE_WAYDISP*3,a0)	# kill the tag
+
+mn10300_local_dcache_inv_range_skip_3:
+
+	# approx every N steps we re-enable the cache and see if there are any
+	# interrupts to be processed
+	# we also break out if we've reached the end of the loop
+	# (the bottom nibble of the count is zero in both cases)
+	add	L1_CACHE_BYTES,a0
+	add	L1_CACHE_BYTES,a1
+	and	~L1_CACHE_WAYDISP,a0
+	add	-1,d1
+	btst	mn10300_local_dcache_inv_range_intr_interval,d1
+	bne	mn10300_local_dcache_inv_range_loop
+
+	# wait for the cache to finish what it's doing
+	setlb
+	movhu	(a2),d0
+	btst	CHCTR_DCBUSY,d0
+	lne
+
+	# and reenable it
+	or	CHCTR_DCEN,d0
+	movhu	d0,(a2)
+	movhu	(a2),d0
+
+	# re-enable interrupts
+	# - we don't bother with delay NOPs as we'll have enough instructions
+	#   before we disable interrupts again to give the interrupts a chance
+	#   to happen
+	LOCAL_IRQ_RESTORE(d3)
+
+	# go around again if the counter hasn't yet reached zero
+	add	0,d1
+	bne	mn10300_local_dcache_inv_range_outer_loop
+
+mn10300_local_dcache_inv_range_end:
+	ret	[d2,d3,a2],12
+	.size	mn10300_local_dcache_inv_page,.-mn10300_local_dcache_inv_page
+	.size	mn10300_local_dcache_inv_range,.-mn10300_local_dcache_inv_range
+	.size	mn10300_local_dcache_inv_range2,.-mn10300_local_dcache_inv_range2
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-icache.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-icache.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-inv-icache.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-inv-icache.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,129 @@
+/* Invalidate icache when dcache doesn't need invalidation as it's in
+ * write-through mode
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+/**
+ * flush_icache_page_range - Flush dcache and invalidate icache for part of a
+ *				single page
+ * @start: The starting virtual address of the page part.
+ * @end: The ending virtual address of the page part.
+ *
+ * Invalidate the icache for part of a single page, as determined by the
+ * virtual addresses given.  The page must be in the paged area.  The dcache is
+ * not flushed as the cache must be in write-through mode to get here.
+ */
+static void flush_icache_page_range(unsigned long start, unsigned long end)
+{
+	unsigned long addr, size, off;
+	struct page *page;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *ppte, pte;
+
+	/* work out how much of the page to flush */
+	off = start & ~PAGE_MASK;
+	size = end - start;
+
+	/* get the physical address the page is mapped to from the page
+	 * tables */
+	pgd = pgd_offset(current->mm, start);
+	if (!pgd || !pgd_val(*pgd))
+		return;
+
+	pud = pud_offset(pgd, start);
+	if (!pud || !pud_val(*pud))
+		return;
+
+	pmd = pmd_offset(pud, start);
+	if (!pmd || !pmd_val(*pmd))
+		return;
+
+	ppte = pte_offset_map(pmd, start);
+	if (!ppte)
+		return;
+	pte = *ppte;
+	pte_unmap(ppte);
+
+	if (pte_none(pte))
+		return;
+
+	page = pte_page(pte);
+	if (!page)
+		return;
+
+	addr = page_to_phys(page);
+
+	/* invalidate the icache coverage on that region */
+	mn10300_local_icache_inv_range2(addr + off, size);
+	smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+}
+
+/**
+ * flush_icache_range - Globally flush dcache and invalidate icache for region
+ * @start: The starting virtual address of the region.
+ * @end: The ending virtual address of the region.
+ *
+ * This is used by the kernel to globally flush some code it has just written
+ * from the dcache back to RAM and then to globally invalidate the icache over
+ * that region so that that code can be run on all CPUs in the system.
+ */
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+	unsigned long start_page, end_page;
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+
+	if (end > 0x80000000UL) {
+		/* addresses above 0xa0000000 do not go through the cache */
+		if (end > 0xa0000000UL) {
+			end = 0xa0000000UL;
+			if (start >= end)
+				goto done;
+		}
+
+		/* kernel addresses between 0x80000000 and 0x9fffffff do not
+		 * require page tables, so we just map such addresses
+		 * directly */
+		start_page = (start >= 0x80000000UL) ? start : 0x80000000UL;
+		mn10300_icache_inv_range(start_page, end);
+		smp_cache_call(SMP_ICACHE_INV_FLUSH_RANGE, start, end);
+		if (start_page == start)
+			goto done;
+		end = start_page;
+	}
+
+	start_page = start & PAGE_MASK;
+	end_page = (end - 1) & PAGE_MASK;
+
+	if (start_page == end_page) {
+		/* the first and last bytes are on the same page */
+		flush_icache_page_range(start, end);
+	} else if (start_page + 1 == end_page) {
+		/* split over two virtually contiguous pages */
+		flush_icache_page_range(start, end_page);
+		flush_icache_page_range(end_page, end);
+	} else {
+		/* more than 2 pages; just flush the entire cache */
+		mn10300_local_icache_inv();
+		smp_cache_call(SMP_ICACHE_INV, 0, 0);
+	}
+
+done:
+	smp_unlock_cache(flags);
+}
+EXPORT_SYMBOL(flush_icache_range);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-mn10300.S linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-mn10300.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-mn10300.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-mn10300.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,289 +0,0 @@
-/* MN10300 CPU core caching routines
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-#include <linux/sys.h>
-#include <linux/linkage.h>
-#include <asm/smp.h>
-#include <asm/page.h>
-#include <asm/cache.h>
-
-#define mn10300_dcache_inv_range_intr_interval \
-	+((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
-
-#if mn10300_dcache_inv_range_intr_interval > 0xff
-#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
-#endif
-
-	.am33_2
-
-	.globl mn10300_icache_inv
-	.globl mn10300_dcache_inv
-	.globl mn10300_dcache_inv_range
-	.globl mn10300_dcache_inv_range2
-	.globl mn10300_dcache_inv_page
-
-###############################################################################
-#
-# void mn10300_icache_inv(void)
-# Invalidate the entire icache
-#
-###############################################################################
-	ALIGN
-mn10300_icache_inv:
-	mov	CHCTR,a0
-
-	movhu	(a0),d0
-	btst	CHCTR_ICEN,d0
-	beq	mn10300_icache_inv_end
-
-	mov	epsw,d1
-	and	~EPSW_IE,epsw
-	nop
-	nop
-
-	# disable the icache
-	and	~CHCTR_ICEN,d0
-	movhu	d0,(a0)
-
-	# and wait for it to calm down
-	setlb
-	movhu	(a0),d0
-	btst	CHCTR_ICBUSY,d0
-	lne
-
-	# invalidate
-	or	CHCTR_ICINV,d0
-	movhu	d0,(a0)
-
-	# wait for the cache to finish
-	mov	CHCTR,a0
-	setlb
-	movhu	(a0),d0
-	btst	CHCTR_ICBUSY,d0
-	lne
-
-	# and reenable it
-	and	~CHCTR_ICINV,d0
-	or	CHCTR_ICEN,d0
-	movhu	d0,(a0)
-	movhu	(a0),d0
-
-	mov	d1,epsw
-
-mn10300_icache_inv_end:
-	ret	[],0
-
-###############################################################################
-#
-# void mn10300_dcache_inv(void)
-# Invalidate the entire dcache
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_inv:
-	mov	CHCTR,a0
-
-	movhu	(a0),d0
-	btst	CHCTR_DCEN,d0
-	beq	mn10300_dcache_inv_end
-
-	mov	epsw,d1
-	and	~EPSW_IE,epsw
-	nop
-	nop
-
-	# disable the dcache
-	and	~CHCTR_DCEN,d0
-	movhu	d0,(a0)
-
-	# and wait for it to calm down
-	setlb
-	movhu	(a0),d0
-	btst	CHCTR_DCBUSY,d0
-	lne
-
-	# invalidate
-	or	CHCTR_DCINV,d0
-	movhu	d0,(a0)
-
-	# wait for the cache to finish
-	mov	CHCTR,a0
-	setlb
-	movhu	(a0),d0
-	btst	CHCTR_DCBUSY,d0
-	lne
-
-	# and reenable it
-	and	~CHCTR_DCINV,d0
-	or	CHCTR_DCEN,d0
-	movhu	d0,(a0)
-	movhu	(a0),d0
-
-	mov	d1,epsw
-
-mn10300_dcache_inv_end:
-	ret	[],0
-
-###############################################################################
-#
-# void mn10300_dcache_inv_range(unsigned start, unsigned end)
-# void mn10300_dcache_inv_range2(unsigned start, unsigned size)
-# void mn10300_dcache_inv_page(unsigned start)
-# Invalidate a range of addresses on a page in the dcache
-#
-###############################################################################
-	ALIGN
-mn10300_dcache_inv_page:
-	mov	PAGE_SIZE,d1
-mn10300_dcache_inv_range2:
-	add	d0,d1
-mn10300_dcache_inv_range:
-	movm	[d2,d3,a2],(sp)
-	mov	CHCTR,a2
-
-	movhu	(a2),d2
-	btst	CHCTR_DCEN,d2
-	beq	mn10300_dcache_inv_range_end
-
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0	# round start
-								# addr down
-	mov	d0,a1
-
-	add	L1_CACHE_BYTES,d1			# round end addr up
-	and	L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
-
-	clr	d2				# we're going to clear tag ram
-						# entries
-
-	# read the tags from the tag RAM, and if they indicate a valid dirty
-	# cache line then invalidate that line
-	mov	DCACHE_TAG(0,0),a0
-	mov	a1,d0
-	and	L1_CACHE_TAG_ENTRY,d0
-	add	d0,a0				# starting dcache tag RAM
-						# access address
-
-	sub	a1,d1
-	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
-						# examine
-
-	and	~(L1_CACHE_DISPARITY-1),a1	# determine comparator base
-
-mn10300_dcache_inv_range_outer_loop:
-	# disable interrupts
-	mov	epsw,d3
-	and	~EPSW_IE,epsw
-	nop					# note that reading CHCTR and
-						# AND'ing D0 occupy two delay
-						# slots after disabling
-						# interrupts
-
-	# disable the dcache
-	movhu	(a2),d0
-	and	~CHCTR_DCEN,d0
-	movhu	d0,(a2)
-
-	# and wait for it to calm down
-	setlb
-	movhu	(a2),d0
-	btst	CHCTR_DCBUSY,d0
-	lne
-
-mn10300_dcache_inv_range_loop:
-
-	# process the way 0 slot
-	mov	(L1_CACHE_WAYDISP*0,a0),d0	# read the tag in the way 0 slot
-	btst	L1_CACHE_TAG_VALID,d0
-	beq	mn10300_dcache_inv_range_skip_0	# jump if this cacheline is not
-						# valid
-
-	xor	a1,d0
-	lsr	12,d0
-	bne	mn10300_dcache_inv_range_skip_0	# jump if not this cacheline
-
-	mov	d2,(a0)				# kill the tag
-
-mn10300_dcache_inv_range_skip_0:
-
-	# process the way 1 slot
-	mov	(L1_CACHE_WAYDISP*1,a0),d0	# read the tag in the way 1 slot
-	btst	L1_CACHE_TAG_VALID,d0
-	beq	mn10300_dcache_inv_range_skip_1	# jump if this cacheline is not
-						# valid
-
-	xor	a1,d0
-	lsr	12,d0
-	bne	mn10300_dcache_inv_range_skip_1	# jump if not this cacheline
-
-	mov	d2,(a0)				# kill the tag
-
-mn10300_dcache_inv_range_skip_1:
-
-	# process the way 2 slot
-	mov	(L1_CACHE_WAYDISP*2,a0),d0	# read the tag in the way 2 slot
-	btst	L1_CACHE_TAG_VALID,d0
-	beq	mn10300_dcache_inv_range_skip_2	# jump if this cacheline is not
-						# valid
-
-	xor	a1,d0
-	lsr	12,d0
-	bne	mn10300_dcache_inv_range_skip_2	# jump if not this cacheline
-
-	mov	d2,(a0)				# kill the tag
-
-mn10300_dcache_inv_range_skip_2:
-
-	# process the way 3 slot
-	mov	(L1_CACHE_WAYDISP*3,a0),d0	# read the tag in the way 3 slot
-	btst	L1_CACHE_TAG_VALID,d0
-	beq	mn10300_dcache_inv_range_skip_3	# jump if this cacheline is not
-						# valid
-
-	xor	a1,d0
-	lsr	12,d0
-	bne	mn10300_dcache_inv_range_skip_3	# jump if not this cacheline
-
-	mov	d2,(a0)				# kill the tag
-
-mn10300_dcache_inv_range_skip_3:
-
-	# approx every N steps we re-enable the cache and see if there are any
-	# interrupts to be processed
-	# we also break out if we've reached the end of the loop
-	# (the bottom nibble of the count is zero in both cases)
-	add	L1_CACHE_BYTES,a0
-	add	L1_CACHE_BYTES,a1
-	add	-1,d1
-	btst	mn10300_dcache_inv_range_intr_interval,d1
-	bne	mn10300_dcache_inv_range_loop
-
-	# wait for the cache to finish what it's doing
-	setlb
-	movhu	(a2),d0
-	btst	CHCTR_DCBUSY,d0
-	lne
-
-	# and reenable it
-	or	CHCTR_DCEN,d0
-	movhu	d0,(a2)
-	movhu	(a2),d0
-
-	# re-enable interrupts
-	# - we don't bother with delay NOPs as we'll have enough instructions
-	#   before we disable interrupts again to give the interrupts a chance
-	#   to happen
-	mov	d3,epsw
-
-	# go around again if the counter hasn't yet reached zero
-	add	0,d1
-	bne	mn10300_dcache_inv_range_outer_loop
-
-mn10300_dcache_inv_range_end:
-	ret	[d2,d3,a2],12
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,105 @@
+/* SMP global caching code
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include "cache-smp.h"
+
+DEFINE_SPINLOCK(smp_cache_lock);
+static unsigned long smp_cache_mask;
+static unsigned long smp_cache_start;
+static unsigned long smp_cache_end;
+static cpumask_t smp_cache_ipi_map;		/* Bitmask of cache IPI done CPUs */
+
+/**
+ * smp_cache_interrupt - Handle IPI request to flush caches.
+ *
+ * Handle a request delivered by IPI to flush the current CPU's
+ * caches.  The parameters are stored in smp_cache_*.
+ */
+void smp_cache_interrupt(void)
+{
+	unsigned long opr_mask = smp_cache_mask;
+
+	switch ((enum smp_dcache_ops)(opr_mask & SMP_DCACHE_OP_MASK)) {
+	case SMP_DCACHE_NOP:
+		break;
+	case SMP_DCACHE_INV:
+		mn10300_local_dcache_inv();
+		break;
+	case SMP_DCACHE_INV_RANGE:
+		mn10300_local_dcache_inv_range(smp_cache_start, smp_cache_end);
+		break;
+	case SMP_DCACHE_FLUSH:
+		mn10300_local_dcache_flush();
+		break;
+	case SMP_DCACHE_FLUSH_RANGE:
+		mn10300_local_dcache_flush_range(smp_cache_start,
+						 smp_cache_end);
+		break;
+	case SMP_DCACHE_FLUSH_INV:
+		mn10300_local_dcache_flush_inv();
+		break;
+	case SMP_DCACHE_FLUSH_INV_RANGE:
+		mn10300_local_dcache_flush_inv_range(smp_cache_start,
+						     smp_cache_end);
+		break;
+	}
+
+	switch ((enum smp_icache_ops)(opr_mask & SMP_ICACHE_OP_MASK)) {
+	case SMP_ICACHE_NOP:
+		break;
+	case SMP_ICACHE_INV:
+		mn10300_local_icache_inv();
+		break;
+	case SMP_ICACHE_INV_RANGE:
+		mn10300_local_icache_inv_range(smp_cache_start, smp_cache_end);
+		break;
+	}
+
+	cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+}
+
+/**
+ * smp_cache_call - Issue an IPI to request the other CPUs flush caches
+ * @opr_mask: Cache operation flags
+ * @start: Start address of request
+ * @end: End address of request
+ *
+ * Send cache flush IPI to other CPUs.  This invokes smp_cache_interrupt()
+ * above on those other CPUs and then waits for them to finish.
+ *
+ * The caller must hold smp_cache_lock.
+ */
+void smp_cache_call(unsigned long opr_mask,
+		    unsigned long start, unsigned long end)
+{
+	smp_cache_mask = opr_mask;
+	smp_cache_start = start;
+	smp_cache_end = end;
+	smp_cache_ipi_map = cpu_online_map;
+	cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+
+	send_IPI_allbutself(FLUSH_CACHE_IPI);
+
+	while (!cpus_empty(smp_cache_ipi_map))
+		/* nothing. lockup detection does not belong here */
+		mb();
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp-flush.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp-flush.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp-flush.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp-flush.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,156 @@
+/* Functions for global dcache flush when writeback caching in SMP
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include "cache-smp.h"
+
+/**
+ * mn10300_dcache_flush - Globally flush data cache
+ *
+ * Flush the data cache on all CPUs.
+ */
+void mn10300_dcache_flush(void)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush();
+	smp_cache_call(SMP_DCACHE_FLUSH, 0, 0);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_page - Globally flush a page of data cache
+ * @start: The address of the page of memory to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs covering
+ * the page that includes the given address.
+ */
+void mn10300_dcache_flush_page(unsigned long start)
+{
+	unsigned long flags;
+
+	start &= ~(PAGE_SIZE-1);
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_page(start);
+	smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + PAGE_SIZE);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_range - Globally flush range of data cache
+ * @start: The start address of the region to be flushed.
+ * @end: The end address of the region to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs, between start and
+ * end-1 inclusive.
+ */
+void mn10300_dcache_flush_range(unsigned long start, unsigned long end)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_range(start, end);
+	smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, end);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_range2 - Globally flush range of data cache
+ * @start: The start address of the region to be flushed.
+ * @size: The size of the region to be flushed.
+ *
+ * Flush a range of addresses in the data cache on all CPUs, between start and
+ * start+size-1 inclusive.
+ */
+void mn10300_dcache_flush_range2(unsigned long start, unsigned long size)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_range2(start, size);
+	smp_cache_call(SMP_DCACHE_FLUSH_RANGE, start, start + size);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv - Globally flush and invalidate data cache
+ *
+ * Flush and invalidate the data cache on all CPUs.
+ */
+void mn10300_dcache_flush_inv(void)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_inv();
+	smp_cache_call(SMP_DCACHE_FLUSH_INV, 0, 0);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_page - Globally flush and invalidate a page of data
+ *	cache
+ * @start: The address of the page of memory to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs
+ * covering the page that includes the given address.
+ */
+void mn10300_dcache_flush_inv_page(unsigned long start)
+{
+	unsigned long flags;
+
+	start &= ~(PAGE_SIZE-1);
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_inv_page(start);
+	smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + PAGE_SIZE);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_range - Globally flush and invalidate range of data
+ *	cache
+ * @start: The start address of the region to be flushed and invalidated.
+ * @end: The end address of the region to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs,
+ * between start and end-1 inclusive.
+ */
+void mn10300_dcache_flush_inv_range(unsigned long start, unsigned long end)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_inv_range(start, end);
+	smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, end);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_flush_inv_range2 - Globally flush and invalidate range of data
+ *	cache
+ * @start: The start address of the region to be flushed and invalidated.
+ * @size: The size of the region to be flushed and invalidated.
+ *
+ * Flush and invalidate a range of addresses in the data cache on all CPUs,
+ * between start and start+size-1 inclusive.
+ */
+void mn10300_dcache_flush_inv_range2(unsigned long start, unsigned long size)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_flush_inv_range2(start, size);
+	smp_cache_call(SMP_DCACHE_FLUSH_INV_RANGE, start, start + size);
+	smp_unlock_cache(flags);
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp.h linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp.h
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,69 @@
+/* SMP caching definitions
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+
+/*
+ * Operation requests for smp_cache_call().
+ *
+ * One of smp_icache_ops and one of smp_dcache_ops can be OR'd together.
+ */
+enum smp_icache_ops {
+	SMP_ICACHE_NOP			= 0x0000,
+	SMP_ICACHE_INV			= 0x0001,
+	SMP_ICACHE_INV_RANGE		= 0x0002,
+};
+#define SMP_ICACHE_OP_MASK		0x0003
+
+enum smp_dcache_ops {
+	SMP_DCACHE_NOP			= 0x0000,
+	SMP_DCACHE_INV			= 0x0004,
+	SMP_DCACHE_INV_RANGE		= 0x0008,
+	SMP_DCACHE_FLUSH		= 0x000c,
+	SMP_DCACHE_FLUSH_RANGE		= 0x0010,
+	SMP_DCACHE_FLUSH_INV		= 0x0014,
+	SMP_DCACHE_FLUSH_INV_RANGE	= 0x0018,
+};
+#define SMP_DCACHE_OP_MASK		0x001c
+
+#define	SMP_IDCACHE_INV_FLUSH		(SMP_ICACHE_INV | SMP_DCACHE_FLUSH)
+#define SMP_IDCACHE_INV_FLUSH_RANGE	(SMP_ICACHE_INV_RANGE | SMP_DCACHE_FLUSH_RANGE)
+
+/*
+ * cache-smp.c
+ */
+#ifdef CONFIG_SMP
+extern spinlock_t smp_cache_lock;
+
+extern void smp_cache_call(unsigned long opr_mask,
+			   unsigned long addr, unsigned long end);
+
+static inline unsigned long smp_lock_cache(void)
+	__acquires(&smp_cache_lock)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&smp_cache_lock, flags);
+	return flags;
+}
+
+static inline void smp_unlock_cache(unsigned long flags)
+	__releases(&smp_cache_lock)
+{
+	spin_unlock_irqrestore(&smp_cache_lock, flags);
+}
+
+#else
+static inline unsigned long smp_lock_cache(void) { return 0; }
+static inline void smp_unlock_cache(unsigned long flags) {}
+static inline void smp_cache_call(unsigned long opr_mask,
+				  unsigned long addr, unsigned long end)
+{
+}
+#endif /* CONFIG_SMP */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp-inv.c linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp-inv.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/cache-smp-inv.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/cache-smp-inv.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,153 @@
+/* Functions for global i/dcache invalidation when caching in SMP
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include "cache-smp.h"
+
+/**
+ * mn10300_icache_inv - Globally invalidate instruction cache
+ *
+ * Invalidate the instruction cache on all CPUs.
+ */
+void mn10300_icache_inv(void)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_icache_inv();
+	smp_cache_call(SMP_ICACHE_INV, 0, 0);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_page - Globally invalidate a page of instruction cache
+ * @start: The address of the page of memory to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs
+ * covering the page that includes the given address.
+ */
+void mn10300_icache_inv_page(unsigned long start)
+{
+	unsigned long flags;
+
+	start &= ~(PAGE_SIZE-1);
+
+	flags = smp_lock_cache();
+	mn10300_local_icache_inv_page(start);
+	smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + PAGE_SIZE);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_range - Globally invalidate range of instruction cache
+ * @start: The start address of the region to be invalidated.
+ * @end: The end address of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs,
+ * between start and end-1 inclusive.
+ */
+void mn10300_icache_inv_range(unsigned long start, unsigned long end)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_icache_inv_range(start, end);
+	smp_cache_call(SMP_ICACHE_INV_RANGE, start, end);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_icache_inv_range2 - Globally invalidate range of instruction cache
+ * @start: The start address of the region to be invalidated.
+ * @size: The size of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the instruction cache on all CPUs,
+ * between start and start+size-1 inclusive.
+ */
+void mn10300_icache_inv_range2(unsigned long start, unsigned long size)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_icache_inv_range2(start, size);
+	smp_cache_call(SMP_ICACHE_INV_RANGE, start, start + size);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv - Globally invalidate data cache
+ *
+ * Invalidate the data cache on all CPUs.
+ */
+void mn10300_dcache_inv(void)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_inv();
+	smp_cache_call(SMP_DCACHE_INV, 0, 0);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_page - Globally invalidate a page of data cache
+ * @start: The address of the page of memory to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs covering the
+ * page that includes the given address.
+ */
+void mn10300_dcache_inv_page(unsigned long start)
+{
+	unsigned long flags;
+
+	start &= ~(PAGE_SIZE-1);
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_inv_page(start);
+	smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + PAGE_SIZE);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_range - Globally invalidate range of data cache
+ * @start: The start address of the region to be invalidated.
+ * @end: The end address of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs, between start
+ * and end-1 inclusive.
+ */
+void mn10300_dcache_inv_range(unsigned long start, unsigned long end)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_inv_range(start, end);
+	smp_cache_call(SMP_DCACHE_INV_RANGE, start, end);
+	smp_unlock_cache(flags);
+}
+
+/**
+ * mn10300_dcache_inv_range2 - Globally invalidate range of data cache
+ * @start: The start address of the region to be invalidated.
+ * @size: The size of the region to be invalidated.
+ *
+ * Invalidate a range of addresses in the data cache on all CPUs, between start
+ * and start+size-1 inclusive.
+ */
+void mn10300_dcache_inv_range2(unsigned long start, unsigned long size)
+{
+	unsigned long flags;
+
+	flags = smp_lock_cache();
+	mn10300_local_dcache_inv_range2(start, size);
+	smp_cache_call(SMP_DCACHE_INV_RANGE, start, start + size);
+	smp_unlock_cache(flags);
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/fault.c linux-libre-2.6.37-gnu/arch/mn10300/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,10 +39,6 @@
 {
 	if (yes) {
 		oops_in_progress = 1;
-#ifdef CONFIG_SMP
-		/* Many serial drivers do __global_cli() */
-		global_irq_lock = 0;
-#endif
 	} else {
 		int loglevel_save = console_loglevel;
 #ifdef CONFIG_VT
@@ -100,8 +96,6 @@
 }
 #endif
 
-asmlinkage void monitor_signal(struct pt_regs *);
-
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -279,7 +273,6 @@
  */
 bad_area:
 	up_read(&mm->mmap_sem);
-	monitor_signal(regs);
 
 	/* User mode accesses just cause a SIGSEGV */
 	if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) {
@@ -292,7 +285,6 @@
 	}
 
 no_context:
-	monitor_signal(regs);
 	/* Are we prepared to handle this kernel fault?  */
 	if (fixup_exception(regs))
 		return;
@@ -338,14 +330,13 @@
  */
 out_of_memory:
 	up_read(&mm->mmap_sem);
-	if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR)
-		goto no_context;
-	pagefault_out_of_memory();
-	return;
+	printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
+	if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
+		do_exit(SIGKILL);
+	goto no_context;
 
 do_sigbus:
 	up_read(&mm->mmap_sem);
-	monitor_signal(regs);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/init.c linux-libre-2.6.37-gnu/arch/mn10300/mm/init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,10 @@
 
 unsigned long highstart_pfn, highend_pfn;
 
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+static struct vm_struct user_iomap_vm;
+#endif
+
 /*
  * set up paging
  */
@@ -73,7 +77,24 @@
 	/* pass the memory from the bootmem allocator to the main allocator */
 	free_area_init(zones_size);
 
-	__flush_tlb_all();
+#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
+	/* The Atomic Operation Unit registers need to be mapped to userspace
+	 * for all processes.  The following uses vm_area_register_early() to
+	 * reserve the first page of the vmalloc area and sets the pte for that
+	 * page.
+	 *
+	 * glibc hardcodes this virtual mapping, so we're pretty much stuck with
+	 * it from now on.
+	 */
+	user_iomap_vm.flags = VM_USERMAP;
+	user_iomap_vm.size = 1 << PAGE_SHIFT;
+	vm_area_register_early(&user_iomap_vm, PAGE_SIZE);
+	ppte = kernel_vmalloc_ptes;
+	set_pte(ppte, pfn_pte(USER_ATOMIC_OPS_PAGE_ADDR >> PAGE_SHIFT,
+			      PAGE_USERIO));
+#endif
+
+	local_flush_tlb_all();
 }
 
 /*
@@ -84,8 +105,7 @@
 	int codesize, reservedpages, datasize, initsize;
 	int tmp;
 
-	if (!mem_map)
-		BUG();
+	BUG_ON(!mem_map);
 
 #define START_PFN	(contig_page_data.bdata->node_min_pfn)
 #define MAX_LOW_PFN	(contig_page_data.bdata->node_low_pfn)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/Kconfig.cache linux-libre-2.6.37-gnu/arch/mn10300/mm/Kconfig.cache
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/Kconfig.cache	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/Kconfig.cache	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,101 @@
+#
+# MN10300 CPU cache options
+#
+
+choice
+	prompt "CPU Caching mode"
+	default MN10300_CACHE_WBACK
+	help
+	  This option determines the caching mode for the kernel.
+
+	  Write-Back caching mode involves the all reads and writes causing
+	  the affected cacheline to be read into the cache first before being
+	  operated upon. Memory is not then updated by a write until the cache
+	  is filled and a cacheline needs to be displaced from the cache to
+	  make room. Only at that point is it written back.
+
+	  Write-Through caching only fetches cachelines from memory on a
+	  read. Writes always get written directly to memory. If the affected
+	  cacheline is also in cache, it will be updated too.
+
+	  The final option is to turn of caching entirely.
+
+config MN10300_CACHE_WBACK
+	bool "Write-Back"
+	help
+	  The dcache operates in delayed write-back mode.  It must be manually
+	  flushed if writes are made that subsequently need to be executed or
+	  to be DMA'd by a device.
+
+config MN10300_CACHE_WTHRU
+	bool "Write-Through"
+	help
+	  The dcache operates in immediate write-through mode.  Writes are
+	  committed to RAM immediately in addition to being stored in the
+	  cache.  This means that the written data is immediately available for
+	  execution or DMA.
+
+	  This is not available for use with an SMP kernel if cache flushing
+	  and invalidation by automatic purge register is not selected.
+
+config MN10300_CACHE_DISABLED
+	bool "Disabled"
+	help
+	  The icache and dcache are disabled.
+
+endchoice
+
+config MN10300_CACHE_ENABLED
+	def_bool y if !MN10300_CACHE_DISABLED
+
+
+choice
+	prompt "CPU cache flush/invalidate method"
+	default MN10300_CACHE_MANAGE_BY_TAG if !AM34_2
+	default MN10300_CACHE_MANAGE_BY_REG if AM34_2
+	depends on MN10300_CACHE_ENABLED
+	help
+	  This determines the method by which CPU cache flushing and
+	  invalidation is performed.
+
+config MN10300_CACHE_MANAGE_BY_TAG
+	bool "Use the cache tag registers directly"
+	depends on !(SMP && MN10300_CACHE_WTHRU)
+
+config MN10300_CACHE_MANAGE_BY_REG
+	bool "Flush areas by way of automatic purge registers (AM34 only)"
+	depends on AM34_2
+
+endchoice
+
+config MN10300_CACHE_INV_BY_TAG
+	def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_ENABLED
+
+config MN10300_CACHE_INV_BY_REG
+	def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_ENABLED
+
+config MN10300_CACHE_FLUSH_BY_TAG
+	def_bool y if MN10300_CACHE_MANAGE_BY_TAG && MN10300_CACHE_WBACK
+
+config MN10300_CACHE_FLUSH_BY_REG
+	def_bool y if MN10300_CACHE_MANAGE_BY_REG && MN10300_CACHE_WBACK
+
+
+config MN10300_HAS_CACHE_SNOOP
+	def_bool n
+
+config MN10300_CACHE_SNOOP
+	bool "Use CPU Cache Snooping"
+	depends on MN10300_CACHE_ENABLED && MN10300_HAS_CACHE_SNOOP
+	default y
+
+config MN10300_CACHE_FLUSH_ICACHE
+	def_bool y if MN10300_CACHE_WBACK && !MN10300_CACHE_SNOOP
+	help
+	  Set if we need the dcache flushing before the icache is invalidated.
+
+config MN10300_CACHE_INV_ICACHE
+	def_bool y if MN10300_CACHE_WTHRU && !MN10300_CACHE_SNOOP
+	help
+	  Set if we need the icache to be invalidated, even if the dcache is in
+	  write-through mode and doesn't need flushing.
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/Makefile linux-libre-2.6.37-gnu/arch/mn10300/mm/Makefile
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,11 +2,21 @@
 # Makefile for the MN10300-specific memory management code
 #
 
-cacheflush-y	:= cache.o cache-mn10300.o
-cacheflush-$(CONFIG_MN10300_CACHE_WBACK) += cache-flush-mn10300.o
+cache-smp-wback-$(CONFIG_MN10300_CACHE_WBACK) := cache-smp-flush.o
+
+cacheflush-y	:= cache.o
+cacheflush-$(CONFIG_SMP) += cache-smp.o cache-smp-inv.o $(cache-smp-wback-y)
+cacheflush-$(CONFIG_MN10300_CACHE_INV_ICACHE) += cache-inv-icache.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_ICACHE) += cache-flush-icache.o
+cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_TAG) += cache-inv-by-tag.o
+cacheflush-$(CONFIG_MN10300_CACHE_INV_BY_REG) += cache-inv-by-reg.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_TAG) += cache-flush-by-tag.o
+cacheflush-$(CONFIG_MN10300_CACHE_FLUSH_BY_REG) += cache-flush-by-reg.o
 
 cacheflush-$(CONFIG_MN10300_CACHE_DISABLED) := cache-disabled.o
 
 obj-y := \
 	init.o fault.o pgtable.o extable.o tlb-mn10300.o mmu-context.o \
 	misalignment.o dma-alloc.o $(cacheflush-y)
+
+obj-$(CONFIG_SMP) += tlb-smp.o
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/misalignment.c linux-libre-2.6.37-gnu/arch/mn10300/mm/misalignment.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/misalignment.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/misalignment.c	2011-01-04 19:50:19.000000000 -0500
@@ -449,8 +449,7 @@
 	       regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
 
 	tmp = format_tbl[pop->format].opsz;
-	if (tmp > noc)
-		BUG(); /* match was less complete than it ought to have been */
+	BUG_ON(tmp > noc); /* match was less complete than it ought to have been */
 
 	if (tmp < noc) {
 		tmp = noc - tmp;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/mmu-context.c linux-libre-2.6.37-gnu/arch/mn10300/mm/mmu-context.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/mmu-context.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/mmu-context.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,40 +13,15 @@
 #include <asm/mmu_context.h>
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
 /*
  * list of the MMU contexts last allocated on each CPU
  */
 unsigned long mmu_context_cache[NR_CPUS] = {
-	[0 ... NR_CPUS - 1] = MMU_CONTEXT_FIRST_VERSION * 2 - 1,
+	[0 ... NR_CPUS - 1] =
+	MMU_CONTEXT_FIRST_VERSION * 2 - (1 - MMU_CONTEXT_TLBPID_LOCK_NR),
 };
-
-/*
- * flush the specified TLB entry
- */
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-{
-	unsigned long pteu, cnx, flags;
-
-	addr &= PAGE_MASK;
-
-	/* make sure the context doesn't migrate and defend against
-	 * interference from vmalloc'd regions */
-	local_irq_save(flags);
-
-	cnx = mm_context(vma->vm_mm);
-
-	if (cnx != MMU_NO_CONTEXT) {
-		pteu = addr | (cnx & 0x000000ffUL);
-		IPTEU = pteu;
-		DPTEU = pteu;
-		if (IPTEL & xPTEL_V)
-			IPTEL = 0;
-		if (DPTEL & xPTEL_V)
-			DPTEL = 0;
-	}
-
-	local_irq_restore(flags);
-}
+#endif /* CONFIG_MN10300_TLB_USE_PIDR */
 
 /*
  * preemptively set a TLB entry
@@ -63,10 +38,16 @@
 	 * interference from vmalloc'd regions */
 	local_irq_save(flags);
 
+	cnx = ~MMU_NO_CONTEXT;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
 	cnx = mm_context(vma->vm_mm);
+#endif
 
 	if (cnx != MMU_NO_CONTEXT) {
-		pteu = addr | (cnx & 0x000000ffUL);
+		pteu = addr;
+#ifdef CONFIG_MN10300_TLB_USE_PIDR
+		pteu |= cnx & MMU_CONTEXT_TLBPID_MASK;
+#endif
 		if (!(pte_val(pte) & _PAGE_NX)) {
 			IPTEU = pteu;
 			if (IPTEL & xPTEL_V)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/pgtable.c linux-libre-2.6.37-gnu/arch/mn10300/mm/pgtable.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/pgtable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/pgtable.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,7 +59,7 @@
 	 * It's enough to flush this one mapping.
 	 * (PGE mappings get flushed as well)
 	 */
-	__flush_tlb_one(vaddr);
+	local_flush_tlb_one(vaddr);
 }
 
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/tlb-mn10300.S linux-libre-2.6.37-gnu/arch/mn10300/mm/tlb-mn10300.S
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/tlb-mn10300.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/tlb-mn10300.S	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,6 @@
 ###############################################################################
 	.type	itlb_miss,@function
 ENTRY(itlb_miss)
-	and	~EPSW_NMID,epsw
 #ifdef CONFIG_GDBSTUB
 	movm	[d2,d3,a2],(sp)
 #else
@@ -38,6 +37,12 @@
 	nop
 #endif
 
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d2
+	mov	d2,(MMUCTR)
+#endif
+
+	and	~EPSW_NMID,epsw
 	mov	(IPTEU),d3
 	mov	(PTBR),a2
 	mov	d3,d2
@@ -56,10 +61,16 @@
 	btst	_PAGE_VALID,d2
 	beq	itlb_miss_fault		# jump if doesn't point to a page
 					# (might be a swap id)
+#if	((_PAGE_ACCESSED & 0xffffff00) == 0)
 	bset	_PAGE_ACCESSED,(0,a2)
-	and	~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
+#elif	((_PAGE_ACCESSED & 0xffff00ff) == 0)
+	bset	+(_PAGE_ACCESSED >> 8),(1,a2)
+#else
+#error	"_PAGE_ACCESSED value is out of range"
+#endif
+	and	~xPTEL2_UNUSED1,d2
 itlb_miss_set:
-	mov	d2,(IPTEL)		# change the TLB
+	mov	d2,(IPTEL2)		# change the TLB
 #ifdef CONFIG_GDBSTUB
 	movm	(sp),[d2,d3,a2]
 #endif
@@ -79,7 +90,6 @@
 ###############################################################################
 	.type	dtlb_miss,@function
 ENTRY(dtlb_miss)
-	and	~EPSW_NMID,epsw
 #ifdef CONFIG_GDBSTUB
 	movm	[d2,d3,a2],(sp)
 #else
@@ -90,6 +100,12 @@
 	nop
 #endif
 
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d2
+	mov	d2,(MMUCTR)
+#endif
+
+	and	~EPSW_NMID,epsw
 	mov	(DPTEU),d3
 	mov	(PTBR),a2
 	mov	d3,d2
@@ -108,10 +124,16 @@
 	btst	_PAGE_VALID,d2
 	beq	dtlb_miss_fault		# jump if doesn't point to a page
 					# (might be a swap id)
+#if	((_PAGE_ACCESSED & 0xffffff00) == 0)
 	bset	_PAGE_ACCESSED,(0,a2)
-	and	~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
+#elif	((_PAGE_ACCESSED & 0xffff00ff) == 0)
+	bset	+(_PAGE_ACCESSED >> 8),(1,a2)
+#else
+#error	"_PAGE_ACCESSED value is out of range"
+#endif
+	and	~xPTEL2_UNUSED1,d2
 dtlb_miss_set:
-	mov	d2,(DPTEL)		# change the TLB
+	mov	d2,(DPTEL2)		# change the TLB
 #ifdef CONFIG_GDBSTUB
 	movm	(sp),[d2,d3,a2]
 #endif
@@ -130,9 +152,15 @@
 ###############################################################################
 	.type	itlb_aerror,@function
 ENTRY(itlb_aerror)
-	and	~EPSW_NMID,epsw
 	add	-4,sp
 	SAVE_ALL
+
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d1
+	mov	d1,(MMUCTR)
+#endif
+
+	and	~EPSW_NMID,epsw
 	add	-4,sp				# need to pass three params
 
 	# calculate the fault code
@@ -140,15 +168,13 @@
 	or	0x00010000,d1			# it's an instruction fetch
 
 	# determine the page address
-	mov	(IPTEU),a2
-	mov	a2,d0
+	mov	(IPTEU),d0
 	and	PAGE_MASK,d0
 	mov	d0,(12,sp)
 
 	clr	d0
-	mov	d0,(IPTEL)
+	mov	d0,(IPTEL2)
 
-	and	~EPSW_NMID,epsw
 	or	EPSW_IE,epsw
 	mov	fp,d0
 	call	do_page_fault[],0		# do_page_fault(regs,code,addr
@@ -163,10 +189,16 @@
 ###############################################################################
 	.type	dtlb_aerror,@function
 ENTRY(dtlb_aerror)
-	and	~EPSW_NMID,epsw
 	add	-4,sp
 	SAVE_ALL
+
+#if defined(CONFIG_ERRATUM_NEED_TO_RELOAD_MMUCTR)
+	mov	(MMUCTR),d1
+	mov	d1,(MMUCTR)
+#endif
+
 	add	-4,sp				# need to pass three params
+	and	~EPSW_NMID,epsw
 
 	# calculate the fault code
 	movhu	(MMUFCR_DFC),d1
@@ -178,9 +210,8 @@
 	mov	d0,(12,sp)
 
 	clr	d0
-	mov	d0,(DPTEL)
+	mov	d0,(DPTEL2)
 
-	and	~EPSW_NMID,epsw
 	or	EPSW_IE,epsw
 	mov	fp,d0
 	call	do_page_fault[],0		# do_page_fault(regs,code,addr
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/mm/tlb-smp.c linux-libre-2.6.37-gnu/arch/mn10300/mm/tlb-smp.c
--- linux-libre-2.6.36-gnu/arch/mn10300/mm/tlb-smp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/mm/tlb-smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,214 @@
+/* SMP TLB support routines.
+ *
+ * Copyright (C) 2006-2008 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+#include <asm/bug.h>
+#include <asm/exceptions.h>
+#include <asm/hardirq.h>
+#include <asm/fpu.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+#include <asm/cpu-regs.h>
+#include <asm/intctl-regs.h>
+
+/*
+ * For flush TLB
+ */
+#define FLUSH_ALL	0xffffffff
+
+static cpumask_t flush_cpumask;
+static struct mm_struct *flush_mm;
+static unsigned long flush_va;
+static DEFINE_SPINLOCK(tlbstate_lock);
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = {
+	&init_mm, 0
+};
+
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+			     unsigned long va);
+static void do_flush_tlb_all(void *info);
+
+/**
+ * smp_flush_tlb - Callback to invalidate the TLB.
+ * @unused: Callback context (ignored).
+ */
+void smp_flush_tlb(void *unused)
+{
+	unsigned long cpu_id;
+
+	cpu_id = get_cpu();
+
+	if (!cpu_isset(cpu_id, flush_cpumask))
+		/* This was a BUG() but until someone can quote me the line
+		 * from the intel manual that guarantees an IPI to multiple
+		 * CPUs is retried _only_ on the erroring CPUs its staying as a
+		 * return
+		 *
+		 * BUG();
+		 */
+		goto out;
+
+	if (flush_va == FLUSH_ALL)
+		local_flush_tlb();
+	else
+		local_flush_tlb_page(flush_mm, flush_va);
+
+	smp_mb__before_clear_bit();
+	cpu_clear(cpu_id, flush_cpumask);
+	smp_mb__after_clear_bit();
+out:
+	put_cpu();
+}
+
+/**
+ * flush_tlb_others - Tell the specified CPUs to invalidate their TLBs
+ * @cpumask: The list of CPUs to target.
+ * @mm: The VM context to flush from (if va!=FLUSH_ALL).
+ * @va: Virtual address to flush or FLUSH_ALL to flush everything.
+ */
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+			     unsigned long va)
+{
+	cpumask_t tmp;
+
+	/* A couple of sanity checks (to be removed):
+	 * - mask must not be empty
+	 * - current CPU must not be in mask
+	 * - we do not send IPIs to as-yet unbooted CPUs.
+	 */
+	BUG_ON(!mm);
+	BUG_ON(cpus_empty(cpumask));
+	BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+
+	cpus_and(tmp, cpumask, cpu_online_map);
+	BUG_ON(!cpus_equal(cpumask, tmp));
+
+	/* I'm not happy about this global shared spinlock in the MM hot path,
+	 * but we'll see how contended it is.
+	 *
+	 * Temporarily this turns IRQs off, so that lockups are detected by the
+	 * NMI watchdog.
+	 */
+	spin_lock(&tlbstate_lock);
+
+	flush_mm = mm;
+	flush_va = va;
+#if NR_CPUS <= BITS_PER_LONG
+	atomic_set_mask(cpumask.bits[0], &flush_cpumask.bits[0]);
+#else
+#error Not supported.
+#endif
+
+	/* FIXME: if NR_CPUS>=3, change send_IPI_mask */
+	smp_call_function(smp_flush_tlb, NULL, 1);
+
+	while (!cpus_empty(flush_cpumask))
+		/* Lockup detection does not belong here */
+		smp_mb();
+
+	flush_mm = NULL;
+	flush_va = 0;
+	spin_unlock(&tlbstate_lock);
+}
+
+/**
+ * flush_tlb_mm - Invalidate TLB of specified VM context
+ * @mm: The VM context to invalidate.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+	cpumask_t cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask;
+	cpu_clear(smp_processor_id(), cpu_mask);
+
+	local_flush_tlb();
+	if (!cpus_empty(cpu_mask))
+		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+	preempt_enable();
+}
+
+/**
+ * flush_tlb_current_task - Invalidate TLB of current task
+ */
+void flush_tlb_current_task(void)
+{
+	struct mm_struct *mm = current->mm;
+	cpumask_t cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask;
+	cpu_clear(smp_processor_id(), cpu_mask);
+
+	local_flush_tlb();
+	if (!cpus_empty(cpu_mask))
+		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+	preempt_enable();
+}
+
+/**
+ * flush_tlb_page - Invalidate TLB of page
+ * @vma: The VM context to invalidate the page for.
+ * @va: The virtual address of the page to invalidate.
+ */
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	cpumask_t cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask;
+	cpu_clear(smp_processor_id(), cpu_mask);
+
+	local_flush_tlb_page(mm, va);
+	if (!cpus_empty(cpu_mask))
+		flush_tlb_others(cpu_mask, mm, va);
+
+	preempt_enable();
+}
+
+/**
+ * do_flush_tlb_all - Callback to completely invalidate a TLB
+ * @unused: Callback context (ignored).
+ */
+static void do_flush_tlb_all(void *unused)
+{
+	local_flush_tlb_all();
+}
+
+/**
+ * flush_tlb_all - Completely invalidate TLBs on all CPUs
+ */
+void flush_tlb_all(void)
+{
+	on_each_cpu(do_flush_tlb_all, 0, 1);
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/cache.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/cache.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/cache.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/cache.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,4 +30,13 @@
  */
 #define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL	4
 
+/*
+ * The size of range at which it becomes more economical to just flush the
+ * whole cache rather than trying to flush the specified range.
+ */
+#define MN10300_DCACHE_FLUSH_BORDER	\
+	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+#define MN10300_DCACHE_FLUSH_INV_BORDER	\
+	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+
 #endif /* _ASM_PROC_CACHE_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/clock.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/clock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,4 @@
 
 #include <unit/clock.h>
 
-#define MN10300_WDCLK		MN10300_IOCLK
-
 #endif /* _ASM_PROC_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/dmactl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,102 @@
+/* MN103E010 on-board DMA controller registers
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PROC_DMACTL_REGS_H
+#define _ASM_PROC_DMACTL_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+/* DMA registers */
+#define	DMxCTR(N)		__SYSREG(0xd2000000 + ((N) * 0x100), u32)	/* control reg */
+#define	DMxCTR_BG		0x0000001f	/* transfer request source */
+#define	DMxCTR_BG_SOFT		0x00000000	/* - software source */
+#define	DMxCTR_BG_SC0TX		0x00000002	/* - serial port 0 transmission */
+#define	DMxCTR_BG_SC0RX		0x00000003	/* - serial port 0 reception */
+#define	DMxCTR_BG_SC1TX		0x00000004	/* - serial port 1 transmission */
+#define	DMxCTR_BG_SC1RX		0x00000005	/* - serial port 1 reception */
+#define	DMxCTR_BG_SC2TX		0x00000006	/* - serial port 2 transmission */
+#define	DMxCTR_BG_SC2RX		0x00000007	/* - serial port 2 reception */
+#define	DMxCTR_BG_TM0UFLOW	0x00000008	/* - timer 0 underflow */
+#define	DMxCTR_BG_TM1UFLOW	0x00000009	/* - timer 1 underflow */
+#define	DMxCTR_BG_TM2UFLOW	0x0000000a	/* - timer 2 underflow */
+#define	DMxCTR_BG_TM3UFLOW	0x0000000b	/* - timer 3 underflow */
+#define	DMxCTR_BG_TM6ACMPCAP	0x0000000c	/* - timer 6A compare/capture */
+#define	DMxCTR_BG_AFE		0x0000000d	/* - analogue front-end interrupt source */
+#define	DMxCTR_BG_ADC		0x0000000e	/* - A/D conversion end interrupt source */
+#define	DMxCTR_BG_IRDA		0x0000000f	/* - IrDA interrupt source */
+#define	DMxCTR_BG_RTC		0x00000010	/* - RTC interrupt source */
+#define	DMxCTR_BG_XIRQ0		0x00000011	/* - XIRQ0 pin interrupt source */
+#define	DMxCTR_BG_XIRQ1		0x00000012	/* - XIRQ1 pin interrupt source */
+#define	DMxCTR_BG_XDMR0		0x00000013	/* - external request 0 source (XDMR0 pin) */
+#define	DMxCTR_BG_XDMR1		0x00000014	/* - external request 1 source (XDMR1 pin) */
+#define	DMxCTR_SAM		0x000000e0	/* DMA transfer src addr mode */
+#define	DMxCTR_SAM_INCR		0x00000000	/* - increment */
+#define	DMxCTR_SAM_DECR		0x00000020	/* - decrement */
+#define	DMxCTR_SAM_FIXED	0x00000040	/* - fixed */
+#define	DMxCTR_DAM		0x00000000	/* DMA transfer dest addr mode */
+#define	DMxCTR_DAM_INCR		0x00000000	/* - increment */
+#define	DMxCTR_DAM_DECR		0x00000100	/* - decrement */
+#define	DMxCTR_DAM_FIXED	0x00000200	/* - fixed */
+#define	DMxCTR_TM		0x00001800	/* DMA transfer mode */
+#define	DMxCTR_TM_BATCH		0x00000000	/* - batch transfer */
+#define	DMxCTR_TM_INTERM	0x00001000	/* - intermittent transfer */
+#define	DMxCTR_UT		0x00006000	/* DMA transfer unit */
+#define	DMxCTR_UT_1		0x00000000	/* - 1 byte */
+#define	DMxCTR_UT_2		0x00002000	/* - 2 byte */
+#define	DMxCTR_UT_4		0x00004000	/* - 4 byte */
+#define	DMxCTR_UT_16		0x00006000	/* - 16 byte */
+#define	DMxCTR_TEN		0x00010000	/* DMA channel transfer enable */
+#define	DMxCTR_RQM		0x00060000	/* external request input source mode */
+#define	DMxCTR_RQM_FALLEDGE	0x00000000	/* - falling edge */
+#define	DMxCTR_RQM_RISEEDGE	0x00020000	/* - rising edge */
+#define	DMxCTR_RQM_LOLEVEL	0x00040000	/* - low level */
+#define	DMxCTR_RQM_HILEVEL	0x00060000	/* - high level */
+#define	DMxCTR_RQF		0x01000000	/* DMA transfer request flag */
+#define	DMxCTR_XEND		0x80000000	/* DMA transfer end flag */
+
+#define	DMxSRC(N)		__SYSREG(0xd2000004 + ((N) * 0x100), u32)	/* control reg */
+
+#define	DMxDST(N)		__SYSREG(0xd2000008 + ((N) * 0x100), u32)	/* src addr reg */
+
+#define	DMxSIZ(N)		__SYSREG(0xd200000c + ((N) * 0x100), u32)	/* dest addr reg */
+#define DMxSIZ_CT		0x000fffff	/* number of bytes to transfer */
+
+#define	DMxCYC(N)		__SYSREG(0xd2000010 + ((N) * 0x100), u32)	/* intermittent
+										 * size reg */
+#define DMxCYC_CYC		0x000000ff	/* number of interrmittent transfers -1 */
+
+#define DM0IRQ			16		/* DMA channel 0 complete IRQ */
+#define DM1IRQ			17		/* DMA channel 1 complete IRQ */
+#define DM2IRQ			18		/* DMA channel 2 complete IRQ */
+#define DM3IRQ			19		/* DMA channel 3 complete IRQ */
+
+#define	DM0ICR			GxICR(DM0IRQ)	/* DMA channel 0 complete intr ctrl reg */
+#define	DM1ICR			GxICR(DM0IR1)	/* DMA channel 1 complete intr ctrl reg */
+#define	DM2ICR			GxICR(DM0IR2)	/* DMA channel 2 complete intr ctrl reg */
+#define	DM3ICR			GxICR(DM0IR3)	/* DMA channel 3 complete intr ctrl reg */
+
+#ifndef __ASSEMBLY__
+
+struct mn10300_dmactl_regs {
+	u32		ctr;
+	const void	*src;
+	void		*dst;
+	u32		siz;
+	u32		cyc;
+} __attribute__((aligned(0x100)));
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PROC_DMACTL_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/intctl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+#ifndef _ASM_PROC_INTCTL_REGS_H
+#define _ASM_PROC_INTCTL_REGS_H
+
+#ifndef _ASM_INTCTL_REGS_H
+# error "please don't include this file directly"
+#endif
+
+/* intr acceptance group reg */
+#define IAGR			__SYSREG(0xd4000100, u16)
+
+/* group number register */
+#define IAGR_GN			0x00fc
+
+#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3)
+
+#define __SET_XIRQ_TRIGGER(X, Y, Z)		\
+({						\
+	typeof(Z) x = (Z);			\
+	x &= ~(3 << ((X) * 2));			\
+	x |= ((Y) & 3) << ((X) * 2);		\
+	(Z) = x;				\
+})
+
+/* external pin intr spec reg */
+#define EXTMD			__SYSREG(0xd4000200, u16)
+#define GET_XIRQ_TRIGGER(X)	__GET_XIRQ_TRIGGER(X, EXTMD)
+#define SET_XIRQ_TRIGGER(X, Y)	__SET_XIRQ_TRIGGER(X, Y, EXTMD)
+
+#endif /* _ASM_PROC_INTCTL_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/proc.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/proc.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/include/proc/proc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/include/proc/proc.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
 #ifndef _ASM_PROC_PROC_H
 #define _ASM_PROC_PROC_H
 
-#define PROCESSOR_VENDOR_NAME	"Matsushita"
+#define PROCESSOR_VENDOR_NAME	"Panasonic"
 #define PROCESSOR_MODEL_NAME	"mn103e010"
 
 #endif /* _ASM_PROC_PROC_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/proc-init.c linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/proc-init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn103e010/proc-init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn103e010/proc-init.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,9 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 #include <linux/kernel.h>
+#include <asm/fpu.h>
 #include <asm/rtc.h>
+#include <asm/busctl-regs.h>
 
 /*
  * initialise the on-silicon processor peripherals
@@ -28,6 +30,7 @@
 	__set_intr_stub(EXCEP_DAERROR,		dtlb_aerror);
 	__set_intr_stub(EXCEP_BUSERROR,		raw_bus_error);
 	__set_intr_stub(EXCEP_DOUBLE_FAULT,	double_fault);
+	__set_intr_stub(EXCEP_FPU_DISABLED,	fpu_disabled);
 	__set_intr_stub(EXCEP_SYSCALL0,		system_call);
 
 	__set_intr_stub(EXCEP_NMI,		nmi_handler);
@@ -73,3 +76,37 @@
 
 	calibrate_clock();
 }
+
+/*
+ * determine the memory size and base from the memory controller regs
+ */
+void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size)
+{
+	unsigned long base, size;
+
+	*mem_base = 0;
+	*mem_size = 0;
+
+	base = SDBASE(0);
+	if (base & SDBASE_CE) {
+		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
+		size = ~size + 1;
+		base &= SDBASE_CBA;
+
+		printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base);
+		*mem_size += size;
+		*mem_base = base;
+	}
+
+	base = SDBASE(1);
+	if (base & SDBASE_CE) {
+		size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
+		size = ~size + 1;
+		base &= SDBASE_CBA;
+
+		printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base);
+		*mem_size += size;
+		if (*mem_base == 0)
+			*mem_base = base;
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/cache.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/cache.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/cache.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/cache.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+/* Cache specification
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ *  13-Nov-2006 MEI Add L1_CACHE_SHIFT_MAX definition.
+ *  29-Jul-2008 MEI Add define for MN10300_HAS_AREAPURGE_REG.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_PROC_CACHE_H
+#define _ASM_PROC_CACHE_H
+
+/*
+ * L1 cache
+ */
+#define L1_CACHE_NWAYS		4		/* number of ways in caches */
+#define L1_CACHE_NENTRIES	128		/* number of entries in each way */
+#define L1_CACHE_BYTES		32		/* bytes per entry */
+#define L1_CACHE_SHIFT		5		/* shift for bytes per entry */
+#define L1_CACHE_WAYDISP	0x1000		/* distance from one way to the next */
+
+#define L1_CACHE_TAG_VALID	0x00000001	/* cache tag valid bit */
+#define L1_CACHE_TAG_DIRTY	0x00000008	/* data cache tag dirty bit */
+#define L1_CACHE_TAG_ENTRY	0x00000fe0	/* cache tag entry address mask */
+#define L1_CACHE_TAG_ADDRESS	0xfffff000	/* cache tag line address mask */
+
+/*
+ * specification of the interval between interrupt checking intervals whilst
+ * managing the cache with the interrupts disabled
+ */
+#define MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL	4
+
+/*
+ * The size of range at which it becomes more economical to just flush the
+ * whole cache rather than trying to flush the specified range.
+ */
+#define MN10300_DCACHE_FLUSH_BORDER \
+	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+#define MN10300_DCACHE_FLUSH_INV_BORDER	\
+	+(L1_CACHE_NWAYS * L1_CACHE_NENTRIES * L1_CACHE_BYTES)
+
+#endif /* _ASM_PROC_CACHE_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/clock.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/clock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+/* clock.h: proc-specific clocks
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ *  23-Feb-2007 MEI Delete define for watchdog timer.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_PROC_CLOCK_H
+#define _ASM_PROC_CLOCK_H
+
+#include <unit/clock.h>
+
+#endif /* _ASM_PROC_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/dmactl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,103 @@
+/* MN2WS0050 on-board DMA controller registers
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_PROC_DMACTL_REGS_H
+#define _ASM_PROC_DMACTL_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+/* DMA registers */
+#define	DMxCTR(N)		__SYSREG(0xd4005000+(N*0x100), u32)	/* control reg */
+#define	DMxCTR_BG		0x0000001f	/* transfer request source */
+#define	DMxCTR_BG_SOFT		0x00000000	/* - software source */
+#define	DMxCTR_BG_SC0TX		0x00000002	/* - serial port 0 transmission */
+#define	DMxCTR_BG_SC0RX		0x00000003	/* - serial port 0 reception */
+#define	DMxCTR_BG_SC1TX		0x00000004	/* - serial port 1 transmission */
+#define	DMxCTR_BG_SC1RX		0x00000005	/* - serial port 1 reception */
+#define	DMxCTR_BG_SC2TX		0x00000006	/* - serial port 2 transmission */
+#define	DMxCTR_BG_SC2RX		0x00000007	/* - serial port 2 reception */
+#define	DMxCTR_BG_TM0UFLOW	0x00000008	/* - timer 0 underflow */
+#define	DMxCTR_BG_TM1UFLOW	0x00000009	/* - timer 1 underflow */
+#define	DMxCTR_BG_TM2UFLOW	0x0000000a	/* - timer 2 underflow */
+#define	DMxCTR_BG_TM3UFLOW	0x0000000b	/* - timer 3 underflow */
+#define	DMxCTR_BG_TM6ACMPCAP	0x0000000c	/* - timer 6A compare/capture */
+#define	DMxCTR_BG_RYBY		0x0000000d	/* - NAND Flash RY/BY request source */
+#define	DMxCTR_BG_RMC		0x0000000e	/* - remote controller output */
+#define	DMxCTR_BG_XIRQ12	0x00000011	/* - XIRQ12 pin interrupt source */
+#define	DMxCTR_BG_XIRQ13	0x00000012	/* - XIRQ13 pin interrupt source */
+#define	DMxCTR_BG_TCK		0x00000014	/* - tick timer underflow */
+#define	DMxCTR_BG_SC4TX		0x00000019	/* - serial port4 transmission */
+#define	DMxCTR_BG_SC4RX		0x0000001a	/* - serial port4 reception */
+#define	DMxCTR_BG_SC5TX		0x0000001b	/* - serial port5 transmission */
+#define	DMxCTR_BG_SC5RX		0x0000001c	/* - serial port5 reception */
+#define	DMxCTR_BG_SC6TX		0x0000001d	/* - serial port6 transmission */
+#define	DMxCTR_BG_SC6RX		0x0000001e	/* - serial port6 reception */
+#define	DMxCTR_BG_TMSUFLOW	0x0000001f	/* - timestamp timer underflow */
+#define	DMxCTR_SAM		0x00000060	/* DMA transfer src addr mode */
+#define	DMxCTR_SAM_INCR		0x00000000	/* - increment */
+#define	DMxCTR_SAM_DECR		0x00000020	/* - decrement */
+#define	DMxCTR_SAM_FIXED	0x00000040	/* - fixed */
+#define	DMxCTR_DAM		0x00000300	/* DMA transfer dest addr mode */
+#define	DMxCTR_DAM_INCR		0x00000000	/* - increment */
+#define	DMxCTR_DAM_DECR		0x00000100	/* - decrement */
+#define	DMxCTR_DAM_FIXED	0x00000200	/* - fixed */
+#define	DMxCTR_UT		0x00006000	/* DMA transfer unit */
+#define	DMxCTR_UT_1		0x00000000	/* - 1 byte */
+#define	DMxCTR_UT_2		0x00002000	/* - 2 byte */
+#define	DMxCTR_UT_4		0x00004000	/* - 4 byte */
+#define	DMxCTR_UT_16		0x00006000	/* - 16 byte */
+#define DMxCTR_RRE		0x00008000	/* DMA round robin enable */
+#define	DMxCTR_TEN		0x00010000	/* DMA channel transfer enable */
+#define	DMxCTR_RQM		0x00060000	/* external request input source mode */
+#define	DMxCTR_RQM_FALLEDGE	0x00000000	/* - falling edge */
+#define	DMxCTR_RQM_RISEEDGE	0x00020000	/* - rising edge */
+#define	DMxCTR_RQM_LOLEVEL	0x00040000	/* - low level */
+#define	DMxCTR_RQM_HILEVEL	0x00060000	/* - high level */
+#define	DMxCTR_RQF		0x01000000	/* DMA transfer request flag */
+#define	DMxCTR_PERR		0x40000000	/* DMA transfer parameter error flag */
+#define	DMxCTR_XEND		0x80000000	/* DMA transfer end flag */
+
+#define	DMxSRC(N)		__SYSREG(0xd4005004+(N*0x100), u32)	/* control reg */
+
+#define	DMxDST(N)		__SYSREG(0xd4005008+(N*0x100), u32)	/* source addr reg */
+
+#define	DMxSIZ(N)		__SYSREG(0xd400500c+(N*0x100), u32)	/* dest addr reg */
+#define DMxSIZ_CT		0x000fffff	/* number of bytes to transfer */
+
+#define	DMxCYC(N)		__SYSREG(0xd4005010+(N*0x100), u32)	/* intermittent size reg */
+#define DMxCYC_CYC		0x000000ff	/* number of interrmittent transfers -1 */
+
+#define DM0IRQ			16		/* DMA channel 0 complete IRQ */
+#define DM1IRQ			17		/* DMA channel 1 complete IRQ */
+#define DM2IRQ			18		/* DMA channel 2 complete IRQ */
+#define DM3IRQ			19		/* DMA channel 3 complete IRQ */
+
+#define	DM0ICR			GxICR(DM0IRQ)	/* DMA channel 0 complete intr ctrl reg */
+#define	DM1ICR			GxICR(DM0IR1)	/* DMA channel 1 complete intr ctrl reg */
+#define	DM2ICR			GxICR(DM0IR2)	/* DMA channel 2 complete intr ctrl reg */
+#define	DM3ICR			GxICR(DM0IR3)	/* DMA channel 3 complete intr ctrl reg */
+
+#ifndef __ASSEMBLY__
+
+struct mn10300_dmactl_regs {
+	u32		ctr;
+	const void	*src;
+	void		*dst;
+	u32		siz;
+	u32		cyc;
+} __attribute__((aligned(0x100)));
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_PROC_DMACTL_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/intctl-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+#ifndef _ASM_PROC_INTCTL_REGS_H
+#define _ASM_PROC_INTCTL_REGS_H
+
+#ifndef _ASM_INTCTL_REGS_H
+# error "please don't include this file directly"
+#endif
+
+/* intr acceptance group reg */
+#define IAGR			__SYSREG(0xd4000100, u16)
+
+/* group number register */
+#define IAGR_GN			0x003fc
+
+#define __GET_XIRQ_TRIGGER(X, Z) (((Z) >> ((X) * 2)) & 3)
+
+#define __SET_XIRQ_TRIGGER(X, Y, Z)		\
+({						\
+	typeof(Z) x = (Z);			\
+	x &= ~(3 << ((X) * 2));			\
+	x |= ((Y) & 3) << ((X) * 2);		\
+	(Z) = x;				\
+})
+
+/* external pin intr spec reg */
+#define EXTMD0			__SYSREG(0xd4000200, u32)
+#define GET_XIRQ_TRIGGER(X)	__GET_XIRQ_TRIGGER(X, EXTMD0)
+#define SET_XIRQ_TRIGGER(X, Y)	__SET_XIRQ_TRIGGER(X, Y, EXTMD0)
+
+#endif /* _ASM_PROC_INTCTL_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/irq.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/irq.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/irq.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,49 @@
+/* MN2WS0050 on-board interrupt controller registers
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ *  13-Nov-2006 MEI Define extended IRQ number for SMP support.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _PROC_IRQ_H
+#define _PROC_IRQ_H
+
+#ifdef __KERNEL__
+
+#define GxICR_NUM_IRQS		163
+#ifdef CONFIG_SMP
+#define GxICR_NUM_EXT_IRQS	197
+#endif  /* CONFIG_SMP */
+
+#define GxICR_NUM_XIRQS		16
+
+#define XIRQ0		34
+#define XIRQ1		35
+#define XIRQ2		36
+#define XIRQ3		37
+#define XIRQ4		38
+#define XIRQ5		39
+#define XIRQ6		40
+#define XIRQ7		41
+#define XIRQ8		42
+#define XIRQ9		43
+#define XIRQ10		44
+#define XIRQ11		45
+#define XIRQ12		46
+#define XIRQ13		47
+#define XIRQ14		48
+#define XIRQ15		49
+
+#define XIRQ2IRQ(num)	(XIRQ0 + num)
+
+#endif /* __KERNEL__ */
+
+#endif /* _PROC_IRQ_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/nand-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,120 @@
+/* NAND flash interface register definitions
+ *
+ * Copyright (C) 2008-2009 Panasonic Corporation
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef	_PROC_NAND_REGS_H_
+#define	_PROC_NAND_REGS_H_
+
+/* command register */
+#define FCOMMAND_0		__SYSREG(0xd8f00000, u8) /* fcommand[24:31] */
+#define FCOMMAND_1		__SYSREG(0xd8f00001, u8) /* fcommand[16:23] */
+#define FCOMMAND_2		__SYSREG(0xd8f00002, u8) /* fcommand[8:15] */
+#define FCOMMAND_3		__SYSREG(0xd8f00003, u8) /* fcommand[0:7] */
+
+/* for dma 16 byte trans, use FCOMMAND2 register */
+#define FCOMMAND2_0		__SYSREG(0xd8f00110, u8) /* fcommand2[24:31] */
+#define FCOMMAND2_1		__SYSREG(0xd8f00111, u8) /* fcommand2[16:23] */
+#define FCOMMAND2_2		__SYSREG(0xd8f00112, u8) /* fcommand2[8:15] */
+#define FCOMMAND2_3		__SYSREG(0xd8f00113, u8) /* fcommand2[0:7] */
+
+#define FCOMMAND_FIEN		0x80		/* nand flash I/F enable */
+#define FCOMMAND_BW_8BIT	0x00		/* 8bit bus width */
+#define FCOMMAND_BW_16BIT	0x40		/* 16bit bus width */
+#define FCOMMAND_BLOCKSZ_SMALL	0x00		/* small block */
+#define FCOMMAND_BLOCKSZ_LARGE	0x20		/* large block */
+#define FCOMMAND_DMASTART	0x10		/* dma start */
+#define FCOMMAND_RYBY		0x08		/* ready/busy flag */
+#define FCOMMAND_RYBYINTMSK	0x04		/* mask ready/busy interrupt */
+#define FCOMMAND_XFWP		0x02		/* write protect enable */
+#define FCOMMAND_XFCE		0x01		/* flash device disable */
+#define FCOMMAND_SEQKILL	0x10		/* stop seq-read */
+#define FCOMMAND_ANUM		0x07		/* address cycle */
+#define FCOMMAND_ANUM_NONE	0x00		/* address cycle none */
+#define FCOMMAND_ANUM_1CYC	0x01		/* address cycle 1cycle */
+#define FCOMMAND_ANUM_2CYC	0x02		/* address cycle 2cycle */
+#define FCOMMAND_ANUM_3CYC	0x03		/* address cycle 3cycle */
+#define FCOMMAND_ANUM_4CYC	0x04		/* address cycle 4cycle */
+#define FCOMMAND_ANUM_5CYC	0x05		/* address cycle 5cycle */
+#define FCOMMAND_FCMD_READ0	0x00		/* read1 command */
+#define FCOMMAND_FCMD_SEQIN	0x80		/* page program 1st command */
+#define FCOMMAND_FCMD_PAGEPROG	0x10		/* page program 2nd command */
+#define FCOMMAND_FCMD_RESET	0xff		/* reset command */
+#define FCOMMAND_FCMD_ERASE1	0x60		/* erase 1st command */
+#define FCOMMAND_FCMD_ERASE2	0xd0		/* erase 2nd command */
+#define FCOMMAND_FCMD_STATUS	0x70		/* read status command */
+#define FCOMMAND_FCMD_READID	0x90		/* read id command */
+#define FCOMMAND_FCMD_READOOB	0x50		/* read3 command */
+/* address register */
+#define FADD			__SYSREG(0xd8f00004, u32)
+/* address register 2 */
+#define FADD2			__SYSREG(0xd8f00008, u32)
+/* error judgement register */
+#define FJUDGE			__SYSREG(0xd8f0000c, u32)
+#define FJUDGE_NOERR		0x0		/* no error */
+#define FJUDGE_1BITERR		0x1		/* 1bit error in data area */
+#define FJUDGE_PARITYERR	0x2		/* parity error */
+#define FJUDGE_UNCORRECTABLE	0x3		/* uncorrectable error */
+#define FJUDGE_ERRJDG_MSK	0x3		/* mask of judgement result */
+/* 1st ECC store register */
+#define FECC11			__SYSREG(0xd8f00010, u32)
+/* 2nd ECC store register */
+#define FECC12			__SYSREG(0xd8f00014, u32)
+/* 3rd ECC store register */
+#define FECC21			__SYSREG(0xd8f00018, u32)
+/* 4th ECC store register */
+#define FECC22			__SYSREG(0xd8f0001c, u32)
+/* 5th ECC store register */
+#define FECC31			__SYSREG(0xd8f00020, u32)
+/* 6th ECC store register */
+#define FECC32			__SYSREG(0xd8f00024, u32)
+/* 7th ECC store register */
+#define FECC41			__SYSREG(0xd8f00028, u32)
+/* 8th ECC store register */
+#define FECC42			__SYSREG(0xd8f0002c, u32)
+/* data register */
+#define FDATA			__SYSREG(0xd8f00030, u32)
+/* access pulse register */
+#define FPWS			__SYSREG(0xd8f00100, u32)
+#define FPWS_PWS1W_2CLK		0x00000000 /* write pulse width 1clock */
+#define FPWS_PWS1W_3CLK		0x01000000 /* write pulse width 2clock */
+#define FPWS_PWS1W_4CLK		0x02000000 /* write pulse width 4clock */
+#define FPWS_PWS1W_5CLK		0x03000000 /* write pulse width 5clock */
+#define FPWS_PWS1W_6CLK		0x04000000 /* write pulse width 6clock */
+#define FPWS_PWS1W_7CLK		0x05000000 /* write pulse width 7clock */
+#define FPWS_PWS1W_8CLK		0x06000000 /* write pulse width 8clock */
+#define FPWS_PWS1R_3CLK		0x00010000 /* read pulse width 3clock */
+#define FPWS_PWS1R_4CLK		0x00020000 /* read pulse width 4clock */
+#define FPWS_PWS1R_5CLK		0x00030000 /* read pulse width 5clock */
+#define FPWS_PWS1R_6CLK		0x00040000 /* read pulse width 6clock */
+#define FPWS_PWS1R_7CLK		0x00050000 /* read pulse width 7clock */
+#define FPWS_PWS1R_8CLK		0x00060000 /* read pulse width 8clock */
+#define FPWS_PWS2W_2CLK		0x00000100 /* write pulse interval 2clock */
+#define FPWS_PWS2W_3CLK		0x00000200 /* write pulse interval 3clock */
+#define FPWS_PWS2W_4CLK		0x00000300 /* write pulse interval 4clock */
+#define FPWS_PWS2W_5CLK		0x00000400 /* write pulse interval 5clock */
+#define FPWS_PWS2W_6CLK		0x00000500 /* write pulse interval 6clock */
+#define FPWS_PWS2R_2CLK		0x00000001 /* read pulse interval 2clock */
+#define FPWS_PWS2R_3CLK		0x00000002 /* read pulse interval 3clock */
+#define FPWS_PWS2R_4CLK		0x00000003 /* read pulse interval 4clock */
+#define FPWS_PWS2R_5CLK		0x00000004 /* read pulse interval 5clock */
+#define FPWS_PWS2R_6CLK		0x00000005 /* read pulse interval 6clock */
+/* command register 2 */
+#define FCOMMAND2		__SYSREG(0xd8f00110, u32)
+/* transfer frequency register */
+#define FNUM			__SYSREG(0xd8f00114, u32)
+#define FSDATA_ADDR		0xd8f00400
+/* active data register */
+#define FSDATA			__SYSREG(FSDATA_ADDR, u32)
+
+#endif /* _PROC_NAND_REGS_H_ */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/proc.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/proc.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/proc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/proc.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,18 @@
+/* proc.h: MN2WS0050 processor description
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PROC_PROC_H
+#define _ASM_PROC_PROC_H
+
+#define PROCESSOR_VENDOR_NAME	"Panasonic"
+#define PROCESSOR_MODEL_NAME	"mn2ws0050"
+
+#endif /* _ASM_PROC_PROC_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/include/proc/smp-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,51 @@
+/* MN10300/AM33v2 Microcontroller SMP registers
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
+ * All Rights Reserved.
+ * Created:
+ *  13-Nov-2006 MEI Add extended cache and atomic operation register
+ *                  for SMP support.
+ *  23-Feb-2007 MEI Add define for gdbstub SMP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_PROC_SMP_REGS_H
+#define _ASM_PROC_SMP_REGS_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#endif
+#include <asm/cpu-regs.h>
+
+/*
+ * Reference to the interrupt controllers of other CPUs
+ */
+#define CROSS_ICR_CPU_SHIFT	16
+
+#define CROSS_GxICR(X, CPU)	__SYSREG(0xc4000000 + (X) * 4 + \
+	((X) >= 64 && (X) < 192) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u16)
+#define CROSS_GxICR_u8(X, CPU)	__SYSREG(0xc4000000 + (X) * 4 +		\
+	(((X) >= 64) && ((X) < 192)) * 0xf00 + ((CPU) << CROSS_ICR_CPU_SHIFT), u8)
+
+/* CPU ID register */
+#define CPUID		__SYSREGC(0xc0000054, u32)
+#define CPUID_MASK	0x00000007	/* CPU ID mask */
+
+/* extended cache control register */
+#define ECHCTR		__SYSREG(0xc0000c20, u32)
+#define ECHCTR_IBCM	0x00000001	/* instruction cache broad cast mask */
+#define ECHCTR_DBCM	0x00000002	/* data cache broad cast mask */
+#define ECHCTR_ISPM	0x00000004	/* instruction cache snoop mask */
+#define ECHCTR_DSPM	0x00000008	/* data cache snoop mask */
+
+#define NMIAGR		__SYSREG(0xd400013c, u16)
+#define NMIAGR_GN	0x03fc
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_PROC_SMP_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/Makefile linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/Makefile
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,5 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y   := proc-init.o
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/proc-init.c linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/proc-init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/proc-mn2ws0050/proc-init.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/proc-mn2ws0050/proc-init.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,134 @@
+/* MN2WS0050 processor initialisation
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+#include <asm/busctl-regs.h>
+#include <unit/timex.h>
+#include <asm/fpu.h>
+#include <asm/rtc.h>
+
+#define MEMCONF __SYSREGC(0xdf800400, u32)
+
+/*
+ * initialise the on-silicon processor peripherals
+ */
+asmlinkage void __init processor_init(void)
+{
+	int loop;
+
+	/* set up the exception table first */
+	for (loop = 0x000; loop < 0x400; loop += 8)
+		__set_intr_stub(loop, __common_exception);
+
+	__set_intr_stub(EXCEP_ITLBMISS,		itlb_miss);
+	__set_intr_stub(EXCEP_DTLBMISS,		dtlb_miss);
+	__set_intr_stub(EXCEP_IAERROR,		itlb_aerror);
+	__set_intr_stub(EXCEP_DAERROR,		dtlb_aerror);
+	__set_intr_stub(EXCEP_BUSERROR,		raw_bus_error);
+	__set_intr_stub(EXCEP_DOUBLE_FAULT,	double_fault);
+	__set_intr_stub(EXCEP_FPU_DISABLED,	fpu_disabled);
+	__set_intr_stub(EXCEP_SYSCALL0,		system_call);
+
+	__set_intr_stub(EXCEP_NMI,		nmi_handler);
+	__set_intr_stub(EXCEP_WDT,		nmi_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL0,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL1,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL2,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL3,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL4,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL5,	irq_handler);
+	__set_intr_stub(EXCEP_IRQ_LEVEL6,	irq_handler);
+
+	IVAR0 = EXCEP_IRQ_LEVEL0;
+	IVAR1 = EXCEP_IRQ_LEVEL1;
+	IVAR2 = EXCEP_IRQ_LEVEL2;
+	IVAR3 = EXCEP_IRQ_LEVEL3;
+	IVAR4 = EXCEP_IRQ_LEVEL4;
+	IVAR5 = EXCEP_IRQ_LEVEL5;
+	IVAR6 = EXCEP_IRQ_LEVEL6;
+
+#ifndef CONFIG_MN10300_HAS_CACHE_SNOOP
+	mn10300_dcache_flush_inv();
+	mn10300_icache_inv();
+#endif
+
+	/* disable all interrupts and set to priority 6 (lowest) */
+#ifdef	CONFIG_SMP
+	for (loop = 0; loop < GxICR_NUM_IRQS; loop++)
+		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+#else	/* !CONFIG_SMP */
+	for (loop = 0; loop < NR_IRQS; loop++)
+		GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
+#endif	/* !CONFIG_SMP */
+
+	/* clear the timers */
+	TM0MD	= 0;
+	TM1MD	= 0;
+	TM2MD	= 0;
+	TM3MD	= 0;
+	TM4MD	= 0;
+	TM5MD	= 0;
+	TM6MD	= 0;
+	TM6MDA	= 0;
+	TM6MDB	= 0;
+	TM7MD	= 0;
+	TM8MD	= 0;
+	TM9MD	= 0;
+	TM10MD	= 0;
+	TM11MD	= 0;
+	TM12MD	= 0;
+	TM13MD	= 0;
+	TM14MD	= 0;
+	TM15MD	= 0;
+
+	calibrate_clock();
+}
+
+/*
+ * determine the memory size and base from the memory controller regs
+ */
+void __init get_mem_info(unsigned long *mem_base, unsigned long *mem_size)
+{
+	unsigned long memconf = MEMCONF;
+	unsigned long size = 0; /* order: MByte */
+
+	*mem_base = 0x90000000; /* fixed address */
+
+	switch (memconf & 0x00000003) {
+	case 0x01:
+		size = 256 / 8;		/* 256 Mbit per chip */
+		break;
+	case 0x02:
+		size = 512 / 8;		/* 512 Mbit per chip */
+		break;
+	case 0x03:
+		size = 1024 / 8;	/*   1 Gbit per chip */
+		break;
+	default:
+		panic("Invalid SDRAM size");
+		break;
+	}
+
+	printk(KERN_INFO "DDR2-SDRAM: %luMB x 2 @%08lx\n", size, *mem_base);
+
+	*mem_size = (size * 2) << 20;
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/clock.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/clock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,32 +14,11 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_MN10300_RTC
-
-extern unsigned long mn10300_ioclk;	/* IOCLK (crystal speed) in HZ */
-extern unsigned long mn10300_iobclk;
-extern unsigned long mn10300_tsc_per_HZ;
-
-#define MN10300_IOCLK		mn10300_ioclk
-/* If this processors has a another clock, uncomment the below. */
-/* #define MN10300_IOBCLK	mn10300_iobclk */
-
-#else /* !CONFIG_MN10300_RTC */
-
 #define MN10300_IOCLK		33333333UL
 /* #define MN10300_IOBCLK	66666666UL */
 
-#endif /* !CONFIG_MN10300_RTC */
-
-#define MN10300_JCCLK		MN10300_IOCLK
-#define MN10300_TSCCLK		MN10300_IOCLK
-
-#ifdef CONFIG_MN10300_RTC
-#define MN10300_TSC_PER_HZ	mn10300_tsc_per_HZ
-#else /* !CONFIG_MN10300_RTC */
-#define MN10300_TSC_PER_HZ	(MN10300_TSCCLK/HZ)
-#endif /* !CONFIG_MN10300_RTC */
-
 #endif /* !__ASSEMBLY__ */
 
+#define MN10300_WDCLK		MN10300_IOCLK
+
 #endif /* _ASM_UNIT_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/serial.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/serial.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/serial.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,11 @@
 #define SERIAL_IRQ	XIRQ0	/* Dual serial (PC16552)	(Hi) */
 
 /*
+ * The ASB2303 has an 18.432 MHz clock the UART
+ */
+#define BASE_BAUD	(18432000 / 16)
+
+/*
  * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports
  */
 #ifndef CONFIG_GDBSTUB_ON_TTYSx
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/timex.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/timex.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/include/unit/timex.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/include/unit/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,6 @@
-/* ASB2303-specific timer specifcations
+/* ASB2303-specific timer specifications
  *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -17,67 +17,72 @@
 
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
+#include <asm/param.h>
 
 /*
  * jiffies counter specifications
  */
 
 #define	TMJCBR_MAX		0xffff
-#define	TMJCBC			TM01BC
-
-#define	TMJCMD			TM01MD
-#define	TMJCBR			TM01BR
 #define	TMJCIRQ			TM1IRQ
 #define	TMJCICR			TM1ICR
-#define	TMJCICR_LEVEL		GxICR_LEVEL_5
 
 #ifndef __ASSEMBLY__
 
-static inline void startup_jiffies_counter(void)
-{
-	unsigned rate;
-	u16 md, t16;
+#define MN10300_SRC_IOCLK	MN10300_IOCLK
 
-	/* use as little prescaling as possible to avoid losing accuracy */
-	md = TM0MD_SRC_IOCLK;
-	rate = MN10300_JCCLK / HZ;
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+/* use as little prescaling as possible to avoid losing accuracy */
+#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		1
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK
+#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		8
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_8
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_8
+#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		32
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_32
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_32
+#else
+# error You lose.
+#endif
 
-	if (rate > TMJCBR_MAX) {
-		md = TM0MD_SRC_IOCLK_8;
-		rate = MN10300_JCCLK / 8 / HZ;
+#define MN10300_JCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+#define MN10300_TSCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE)
 
-		if (rate > TMJCBR_MAX) {
-			md = TM0MD_SRC_IOCLK_32;
-			rate = MN10300_JCCLK / 32 / HZ;
+#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ)
 
-			if (rate > TMJCBR_MAX)
-				BUG();
-		}
-	}
+static inline void stop_jiffies_counter(void)
+{
+	u16 tmp;
+	TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
+	tmp = TM01MD;
+}
 
-	TMJCBR = rate - 1;
-	t16 = TMJCBR;
+static inline void reload_jiffies_counter(u32 cnt)
+{
+	u32 tmp;
 
-	TMJCMD =
-		md |
-		TM1MD_SRC_TM0CASCADE << 8 |
-		TM0MD_INIT_COUNTER |
-		TM1MD_INIT_COUNTER << 8;
+	TM01BR = cnt;
+	tmp = TM01BR;
 
-	TMJCMD =
-		md |
-		TM1MD_SRC_TM0CASCADE << 8 |
-		TM0MD_COUNT_ENABLE |
-		TM1MD_COUNT_ENABLE << 8;
+	TM01MD = JC_TIMER_CLKSRC |		\
+		 TM1MD_SRC_TM0CASCADE << 8 |	\
+		 TM0MD_INIT_COUNTER |		\
+		 TM1MD_INIT_COUNTER << 8;
 
-	t16 = TMJCMD;
 
-	TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
-	t16 = TMJCICR;
-}
+	TM01MD = JC_TIMER_CLKSRC |		\
+		 TM1MD_SRC_TM0CASCADE << 8 |	\
+		 TM0MD_COUNT_ENABLE |		\
+		 TM1MD_COUNT_ENABLE << 8;
 
-static inline void shutdown_jiffies_counter(void)
-{
+	tmp = TM01MD;
 }
 
 #endif /* !__ASSEMBLY__ */
@@ -94,29 +99,39 @@
 
 static inline void startup_timestamp_counter(void)
 {
+	u32 t32;
+
 	/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time
 	 * - count down from 4Gig-1 to 0 and wrap at IOCLK rate
 	 */
 	TM45BR = TMTSCBR_MAX;
+	t32 = TM45BR;
 
-	TM4MD = TM4MD_SRC_IOCLK;
+	TM4MD = TSC_TIMER_CLKSRC;
 	TM4MD |= TM4MD_INIT_COUNTER;
 	TM4MD &= ~TM4MD_INIT_COUNTER;
 	TM4ICR = 0;
+	t32 = TM4ICR;
 
 	TM5MD = TM5MD_SRC_TM4CASCADE;
 	TM5MD |= TM5MD_INIT_COUNTER;
 	TM5MD &= ~TM5MD_INIT_COUNTER;
 	TM5ICR = 0;
+	t32 = TM5ICR;
 
 	TM5MD |= TM5MD_COUNT_ENABLE;
 	TM4MD |= TM4MD_COUNT_ENABLE;
+	t32 = TM5MD;
+	t32 = TM4MD;
 }
 
 static inline void shutdown_timestamp_counter(void)
 {
+	u8 t8;
 	TM4MD = 0;
 	TM5MD = 0;
+	t8 = TM4MD;
+	t8 = TM5MD;
 }
 
 /*
@@ -127,7 +142,7 @@
 
 static inline cycles_t read_timestamp_counter(void)
 {
-	return (cycles_t)TMTSCBC;
+	return (cycles_t)~TMTSCBC;
 }
 
 #endif /* !__ASSEMBLY__ */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/unit-init.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/unit-init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2303/unit-init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2303/unit-init.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,14 @@
 	SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL);
 	SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL);
 	SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL);
+
+#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL
+	set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
+#endif
+
+#ifdef CONFIG_ETHERNET_IRQ_LEVEL
+	set_intr_level(XIRQ3, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL));
+#endif
 }
 
 /*
@@ -51,7 +59,7 @@
 		switch (GET_XIRQ_TRIGGER(extnum)) {
 		case XIRQ_TRIGGER_HILEVEL:
 		case XIRQ_TRIGGER_LOWLEVEL:
-			set_intr_postackable(XIRQ2IRQ(extnum));
+			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
 			break;
 		default:
 			break;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/clock.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/clock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/clock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,32 +14,11 @@
 
 #ifndef __ASSEMBLY__
 
-#ifdef CONFIG_MN10300_RTC
-
-extern unsigned long mn10300_ioclk;	/* IOCLK (crystal speed) in HZ */
-extern unsigned long mn10300_iobclk;
-extern unsigned long mn10300_tsc_per_HZ;
-
-#define MN10300_IOCLK		mn10300_ioclk
-/* If this processors has a another clock, uncomment the below. */
-/* #define MN10300_IOBCLK	mn10300_iobclk */
-
-#else /* !CONFIG_MN10300_RTC */
-
 #define MN10300_IOCLK		33333333UL
 /* #define MN10300_IOBCLK	66666666UL */
 
-#endif /* !CONFIG_MN10300_RTC */
-
-#define MN10300_JCCLK		MN10300_IOCLK
-#define MN10300_TSCCLK		MN10300_IOCLK
-
-#ifdef CONFIG_MN10300_RTC
-#define MN10300_TSC_PER_HZ	mn10300_tsc_per_HZ
-#else /* !CONFIG_MN10300_RTC */
-#define MN10300_TSC_PER_HZ	(MN10300_TSCCLK/HZ)
-#endif /* !CONFIG_MN10300_RTC */
-
 #endif /* !__ASSEMBLY__ */
 
+#define MN10300_WDCLK		MN10300_IOCLK
+
 #endif /* _ASM_UNIT_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/serial.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/serial.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/serial.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,11 @@
 #define SERIAL_IRQ	XIRQ0	/* Dual serial (PC16552)	(Hi) */
 
 /*
+ * The ASB2305 has an 18.432 MHz clock the UART
+ */
+#define BASE_BAUD	(18432000 / 16)
+
+/*
  * dispose of the /dev/ttyS0 serial port
  */
 #ifndef CONFIG_GDBSTUB_ON_TTYSx
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/timex.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/timex.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/include/unit/timex.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/include/unit/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,6 @@
-/* ASB2305 timer specifcations
+/* ASB2305-specific timer specifications
  *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2010 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -17,67 +17,72 @@
 
 #include <asm/timer-regs.h>
 #include <unit/clock.h>
+#include <asm/param.h>
 
 /*
  * jiffies counter specifications
  */
 
 #define	TMJCBR_MAX		0xffff
-#define	TMJCBC			TM01BC
-
-#define	TMJCMD			TM01MD
-#define	TMJCBR			TM01BR
 #define	TMJCIRQ			TM1IRQ
 #define	TMJCICR			TM1ICR
-#define	TMJCICR_LEVEL		GxICR_LEVEL_5
 
 #ifndef __ASSEMBLY__
 
-static inline void startup_jiffies_counter(void)
-{
-	unsigned rate;
-	u16 md, t16;
+#define MN10300_SRC_IOCLK	MN10300_IOCLK
 
-	/* use as little prescaling as possible to avoid losing accuracy */
-	md = TM0MD_SRC_IOCLK;
-	rate = MN10300_JCCLK / HZ;
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+/* use as little prescaling as possible to avoid losing accuracy */
+#if (MN10300_SRC_IOCLK + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		1
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK
+#elif (MN10300_SRC_IOCLK / 8 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		8
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_8
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_8
+#elif (MN10300_SRC_IOCLK / 32 + HZ / 2) / HZ - 1 <= TMJCBR_MAX
+# define IOCLK_PRESCALE		32
+# define JC_TIMER_CLKSRC	TM0MD_SRC_IOCLK_32
+# define TSC_TIMER_CLKSRC	TM4MD_SRC_IOCLK_32
+#else
+# error You lose.
+#endif
 
-	if (rate > TMJCBR_MAX) {
-		md = TM0MD_SRC_IOCLK_8;
-		rate = MN10300_JCCLK / 8 / HZ;
+#define MN10300_JCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE)
+#define MN10300_TSCCLK		(MN10300_SRC_IOCLK / IOCLK_PRESCALE)
 
-		if (rate > TMJCBR_MAX) {
-			md = TM0MD_SRC_IOCLK_32;
-			rate = MN10300_JCCLK / 32 / HZ;
+#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ)
 
-			if (rate > TMJCBR_MAX)
-				BUG();
-		}
-	}
+static inline void stop_jiffies_counter(void)
+{
+	u16 tmp;
+	TM01MD = JC_TIMER_CLKSRC | TM1MD_SRC_TM0CASCADE << 8;
+	tmp = TM01MD;
+}
 
-	TMJCBR = rate - 1;
-	t16 = TMJCBR;
+static inline void reload_jiffies_counter(u32 cnt)
+{
+	u32 tmp;
 
-	TMJCMD =
-		md |
-		TM1MD_SRC_TM0CASCADE << 8 |
-		TM0MD_INIT_COUNTER |
-		TM1MD_INIT_COUNTER << 8;
+	TM01BR = cnt;
+	tmp = TM01BR;
 
-	TMJCMD =
-		md |
-		TM1MD_SRC_TM0CASCADE << 8 |
-		TM0MD_COUNT_ENABLE |
-		TM1MD_COUNT_ENABLE << 8;
+	TM01MD = JC_TIMER_CLKSRC |		\
+		 TM1MD_SRC_TM0CASCADE << 8 |	\
+		 TM0MD_INIT_COUNTER |		\
+		 TM1MD_INIT_COUNTER << 8;
 
-	t16 = TMJCMD;
 
-	TMJCICR |= GxICR_ENABLE | GxICR_DETECT | GxICR_REQUEST;
-	t16 = TMJCICR;
-}
+	TM01MD = JC_TIMER_CLKSRC |		\
+		 TM1MD_SRC_TM0CASCADE << 8 |	\
+		 TM0MD_COUNT_ENABLE |		\
+		 TM1MD_COUNT_ENABLE << 8;
 
-static inline void shutdown_jiffies_counter(void)
-{
+	tmp = TM01MD;
 }
 
 #endif /* !__ASSEMBLY__ */
@@ -94,29 +99,39 @@
 
 static inline void startup_timestamp_counter(void)
 {
+	u32 t32;
+
 	/* set up timer 4 & 5 cascaded as a 32-bit counter to count real time
 	 * - count down from 4Gig-1 to 0 and wrap at IOCLK rate
 	 */
 	TM45BR = TMTSCBR_MAX;
+	t32 = TM45BR;
 
-	TM4MD = TM4MD_SRC_IOCLK;
+	TM4MD = TSC_TIMER_CLKSRC;
 	TM4MD |= TM4MD_INIT_COUNTER;
 	TM4MD &= ~TM4MD_INIT_COUNTER;
 	TM4ICR = 0;
+	t32 = TM4ICR;
 
 	TM5MD = TM5MD_SRC_TM4CASCADE;
 	TM5MD |= TM5MD_INIT_COUNTER;
 	TM5MD &= ~TM5MD_INIT_COUNTER;
 	TM5ICR = 0;
+	t32 = TM5ICR;
 
 	TM5MD |= TM5MD_COUNT_ENABLE;
 	TM4MD |= TM4MD_COUNT_ENABLE;
+	t32 = TM5MD;
+	t32 = TM4MD;
 }
 
 static inline void shutdown_timestamp_counter(void)
 {
+	u8 t8;
 	TM4MD = 0;
 	TM5MD = 0;
+	t8 = TM4MD;
+	t8 = TM5MD;
 }
 
 /*
@@ -127,7 +142,7 @@
 
 static inline cycles_t read_timestamp_counter(void)
 {
-	return (cycles_t) TMTSCBC;
+	return (cycles_t)~TMTSCBC;
 }
 
 #endif /* !__ASSEMBLY__ */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/pci-asb2305.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/pci-asb2305.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/pci-asb2305.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/pci-asb2305.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,7 +93,7 @@
 	struct pci_bus *bus;
 	struct pci_dev *dev;
 	int idx;
-	struct resource *r, *pr;
+	struct resource *r;
 
 	/* Depth-First Search on bus tree */
 	list_for_each_entry(bus, bus_list, node) {
@@ -105,10 +105,8 @@
 				r = &dev->resource[idx];
 				if (!r->flags)
 					continue;
-				pr = pci_find_parent_resource(dev, r);
 				if (!r->start ||
-				    !pr ||
-				    request_resource(pr, r) < 0) {
+				    pci_claim_resource(dev, idx) < 0) {
 					printk(KERN_ERR "PCI:"
 					       " Cannot allocate resource"
 					       " region %d of bridge %s\n",
@@ -131,7 +129,7 @@
 	struct pci_dev *dev = NULL;
 	int idx, disabled;
 	u16 command;
-	struct resource *r, *pr;
+	struct resource *r;
 
 	for_each_pci_dev(dev) {
 		pci_read_config_word(dev, PCI_COMMAND, &command);
@@ -150,8 +148,7 @@
 				    " (f=%lx, d=%d, p=%d)\n",
 				    pci_name(dev), r->start, r->end, r->flags,
 				    disabled, pass);
-				pr = pci_find_parent_resource(dev, r);
-				if (!pr || request_resource(pr, r) < 0) {
+				if (pci_claim_resource(dev, idx) < 0) {
 					printk(KERN_ERR "PCI:"
 					       " Cannot allocate resource"
 					       " region %d of device %s\n",
@@ -184,7 +181,7 @@
 static int __init pcibios_assign_resources(void)
 {
 	struct pci_dev *dev = NULL;
-	struct resource *r, *pr;
+	struct resource *r;
 
 	if (!(pci_probe & PCI_ASSIGN_ROMS)) {
 		/* Try to use BIOS settings for ROMs, otherwise let
@@ -194,8 +191,7 @@
 			r = &dev->resource[PCI_ROM_RESOURCE];
 			if (!r->flags || !r->start)
 				continue;
-			pr = pci_find_parent_resource(dev, r);
-			if (!pr || request_resource(pr, r) < 0) {
+			if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
 				r->end -= r->start;
 				r->start = 0;
 			}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/pci.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/pci.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/pci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/pci.c	2011-01-04 19:50:19.000000000 -0500
@@ -503,7 +503,7 @@
 	struct pci_ops *o = &pci_direct_ampci;
 	u32 x;
 
-	set_intr_level(XIRQ1, GxICR_LEVEL_3);
+	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_PCI_IRQ_LEVEL));
 
 	memset(&bus, 0, sizeof(bus));
 
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/unit-init.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/unit-init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2305/unit-init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2305/unit-init.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,8 +26,10 @@
 {
 #ifndef CONFIG_GDBSTUB_ON_TTYSx
 	/* set the 16550 interrupt line to level 3 if not being used for GDB */
-	set_intr_level(XIRQ0, GxICR_LEVEL_3);
+#ifdef CONFIG_EXT_SERIAL_IRQ_LEVEL
+	set_intr_level(XIRQ0, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
 #endif
+#endif /* CONFIG_GDBSTUB_ON_TTYSx */
 }
 
 /*
@@ -51,7 +53,7 @@
 		switch (GET_XIRQ_TRIGGER(extnum)) {
 		case XIRQ_TRIGGER_HILEVEL:
 		case XIRQ_TRIGGER_LOWLEVEL:
-			set_intr_postackable(XIRQ2IRQ(extnum));
+			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
 			break;
 		default:
 			break;
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/clock.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/clock.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/clock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/clock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,29 @@
+/* clock.h: unit-specific clocks
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Modified by Matsushita Electric Industrial Co., Ltd.
+ * Modifications:
+ *	23-Feb-2007 MEI Add define for watchdog timer.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_UNIT_CLOCK_H
+#define _ASM_UNIT_CLOCK_H
+
+#ifndef __ASSEMBLY__
+
+#define MN10300_IOCLK		100000000UL		/* for DDR800 */
+/*#define MN10300_IOCLK		83333333UL */		/* for DDR667 */
+#define MN10300_IOBCLK		MN10300_IOCLK		/* IOBCLK is equal to IOCLK */
+
+#endif /* !__ASSEMBLY__ */
+
+#define MN10300_WDCLK		27000000UL
+
+#endif /* _ASM_UNIT_CLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/fpga-regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,52 @@
+/* ASB2364 FPGA registers
+ */
+
+#ifndef _ASM_UNIT_FPGA_REGS_H
+#define _ASM_UNIT_FPGA_REGS_H
+
+#include <asm/cpu-regs.h>
+
+#ifdef __KERNEL__
+
+#define ASB2364_FPGA_REG_RESET_LAN	__SYSREG(0xa9001300, u16)
+#define ASB2364_FPGA_REG_RESET_UART	__SYSREG(0xa9001304, u16)
+#define ASB2364_FPGA_REG_RESET_I2C	__SYSREG(0xa9001308, u16)
+#define ASB2364_FPGA_REG_RESET_USB	__SYSREG(0xa900130c, u16)
+#define ASB2364_FPGA_REG_RESET_AV	__SYSREG(0xa9001310, u16)
+
+#define ASB2364_FPGA_REG_IRQ(X)		__SYSREG(0xa9001590+((X)*4), u16)
+#define ASB2364_FPGA_REG_IRQ_LAN	ASB2364_FPGA_REG_IRQ(0)
+#define ASB2364_FPGA_REG_IRQ_UART	ASB2364_FPGA_REG_IRQ(1)
+#define ASB2364_FPGA_REG_IRQ_I2C	ASB2364_FPGA_REG_IRQ(2)
+#define ASB2364_FPGA_REG_IRQ_USB	ASB2364_FPGA_REG_IRQ(3)
+#define ASB2364_FPGA_REG_IRQ_FPGA	ASB2364_FPGA_REG_IRQ(5)
+
+#define ASB2364_FPGA_REG_MASK(X)	__SYSREG(0xa9001590+((X)*4), u16)
+#define ASB2364_FPGA_REG_MASK_LAN	ASB2364_FPGA_REG_MASK(0)
+#define ASB2364_FPGA_REG_MASK_UART	ASB2364_FPGA_REG_MASK(1)
+#define ASB2364_FPGA_REG_MASK_I2C	ASB2364_FPGA_REG_MASK(2)
+#define ASB2364_FPGA_REG_MASK_USB	ASB2364_FPGA_REG_MASK(3)
+#define ASB2364_FPGA_REG_MASK_FPGA	ASB2364_FPGA_REG_MASK(5)
+
+#define ASB2364_FPGA_REG_CPLD5_SET1	__SYSREG(0xa9002500, u16)
+#define ASB2364_FPGA_REG_CPLD5_SET2	__SYSREG(0xa9002504, u16)
+#define ASB2364_FPGA_REG_CPLD6_SET1	__SYSREG(0xa9002600, u16)
+#define ASB2364_FPGA_REG_CPLD6_SET2	__SYSREG(0xa9002604, u16)
+#define ASB2364_FPGA_REG_CPLD7_SET1	__SYSREG(0xa9002700, u16)
+#define ASB2364_FPGA_REG_CPLD7_SET2	__SYSREG(0xa9002704, u16)
+#define ASB2364_FPGA_REG_CPLD8_SET1	__SYSREG(0xa9002800, u16)
+#define ASB2364_FPGA_REG_CPLD8_SET2	__SYSREG(0xa9002804, u16)
+#define ASB2364_FPGA_REG_CPLD9_SET1	__SYSREG(0xa9002900, u16)
+#define ASB2364_FPGA_REG_CPLD9_SET2	__SYSREG(0xa9002904, u16)
+#define ASB2364_FPGA_REG_CPLD10_SET1	__SYSREG(0xa9002a00, u16)
+#define ASB2364_FPGA_REG_CPLD10_SET2	__SYSREG(0xa9002a04, u16)
+
+#define SyncExBus()					\
+	do {						\
+		unsigned short w;			\
+		w = *(volatile short *)0xa9000000;	\
+	} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UNIT_FPGA_REGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/irq.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/irq.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/irq.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/* ASB2364 FPGA irq numbers
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#ifndef _UNIT_IRQ_H
+#define _UNIT_IRQ_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_SMP
+#define NR_CPU_IRQS	GxICR_NUM_EXT_IRQS
+#else
+#define NR_CPU_IRQS	GxICR_NUM_IRQS
+#endif
+
+enum {
+	FPGA_LAN_IRQ	= NR_CPU_IRQS,
+	FPGA_UART_IRQ,
+	FPGA_I2C_IRQ,
+	FPGA_USB_IRQ,
+	FPGA_RESERVED_IRQ,
+	FPGA_FPGA_IRQ,
+	NR_IRQS
+};
+
+extern void __init irq_fpga_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _UNIT_IRQ_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/leds.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/leds.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/leds.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/leds.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,54 @@
+/* Unit-specific leds
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_UNIT_LEDS_H
+#define _ASM_UNIT_LEDS_H
+
+#include <asm/pio-regs.h>
+#include <asm/cpu-regs.h>
+#include <asm/exceptions.h>
+
+#define MN10300_USE_7SEGLEDS	0
+
+#define ASB2364_7SEGLEDS	__SYSREG(0xA9001630, u32)
+
+/*
+ * use the 7-segment LEDs to indicate states
+ */
+
+#if MN10300_USE_7SEGLEDS
+/* flip the 7-segment LEDs between "Gdb-" and "----" */
+#define mn10300_set_gdbleds(ONOFF)					\
+	do {								\
+		ASB2364_7SEGLEDS = (ONOFF) ? 0x8543077f : 0x7f7f7f7f;	\
+	} while (0)
+#else
+#define mn10300_set_gdbleds(ONOFF) do {} while (0)
+#endif
+
+#if MN10300_USE_7SEGLEDS
+/* indicate double-fault by displaying "db-f" on the LEDs */
+#define mn10300_set_dbfleds			\
+	mov	0x43077f1d,d0		;	\
+	mov	d0,(ASB2364_7SEGLEDS)
+#else
+#define mn10300_set_dbfleds
+#endif
+
+#ifndef __ASSEMBLY__
+extern void peripheral_leds_display_exception(enum exception_code);
+extern void peripheral_leds_led_chase(void);
+extern void peripheral_leds7x4_display_dec(unsigned int, unsigned int);
+extern void peripheral_leds7x4_display_hex(unsigned int, unsigned int);
+extern void debug_to_serial(const char *, int);
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_UNIT_LEDS_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/serial.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/serial.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/serial.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/serial.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,151 @@
+/* Unit-specific 8250 serial ports
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_UNIT_SERIAL_H
+#define _ASM_UNIT_SERIAL_H
+
+#include <asm/cpu-regs.h>
+#include <proc/irq.h>
+#include <unit/fpga-regs.h>
+#include <linux/serial_reg.h>
+
+#define SERIAL_PORT0_BASE_ADDRESS	0xA8200000
+
+#define SERIAL_IRQ	XIRQ1	/* single serial (TL16C550C)	(Lo) */
+
+/*
+ * The ASB2364 has an 12.288 MHz clock
+ * for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD (12288000 / 16)
+
+/*
+ * dispose of the /dev/ttyS0 and /dev/ttyS1 serial ports
+ */
+#ifndef CONFIG_GDBSTUB_ON_TTYSx
+
+#define SERIAL_PORT_DFNS						\
+	{								\
+		.baud_base	= BASE_BAUD,				\
+		.irq		= SERIAL_IRQ,				\
+		.flags		= STD_COM_FLAGS,			\
+		.iomem_base	= (u8 *) SERIAL_PORT0_BASE_ADDRESS,	\
+		.iomem_reg_shift = 1,					\
+		.io_type	= SERIAL_IO_MEM,			\
+	},
+
+#ifndef __ASSEMBLY__
+
+static inline void __debug_to_serial(const char *p, int n)
+{
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#else /* CONFIG_GDBSTUB_ON_TTYSx */
+
+#define SERIAL_PORT_DFNS /* stolen by gdb-stub */
+
+#if defined(CONFIG_GDBSTUB_ON_TTYS0)
+#define GDBPORT_SERIAL_RX	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_RX  * 4, u8)
+#define GDBPORT_SERIAL_TX	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_TX  * 4, u8)
+#define GDBPORT_SERIAL_DLL	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLL * 4, u8)
+#define GDBPORT_SERIAL_DLM	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_DLM * 4, u8)
+#define GDBPORT_SERIAL_IER	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IER * 4, u8)
+#define GDBPORT_SERIAL_IIR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_IIR * 4, u8)
+#define GDBPORT_SERIAL_FCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_FCR * 4, u8)
+#define GDBPORT_SERIAL_LCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LCR * 4, u8)
+#define GDBPORT_SERIAL_MCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MCR * 4, u8)
+#define GDBPORT_SERIAL_LSR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_LSR * 4, u8)
+#define GDBPORT_SERIAL_MSR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_MSR * 4, u8)
+#define GDBPORT_SERIAL_SCR	__SYSREG(SERIAL_PORT0_BASE_ADDRESS + UART_SCR * 4, u8)
+#define GDBPORT_SERIAL_IRQ	SERIAL_IRQ
+
+#elif defined(CONFIG_GDBSTUB_ON_TTYS1)
+#error The ASB2364 does not have a /dev/ttyS1
+#endif
+
+#ifndef __ASSEMBLY__
+
+static inline void __debug_to_serial(const char *p, int n)
+{
+	char ch;
+
+#define LSR_WAIT_FOR(STATE)	\
+	do {} while (!(GDBPORT_SERIAL_LSR & UART_LSR_##STATE))
+#define FLOWCTL_QUERY(LINE)	\
+	({ GDBPORT_SERIAL_MSR & UART_MSR_##LINE; })
+#define FLOWCTL_WAIT_FOR(LINE)	\
+	do {} while (!(GDBPORT_SERIAL_MSR & UART_MSR_##LINE))
+#define FLOWCTL_CLEAR(LINE)	\
+	do { GDBPORT_SERIAL_MCR &= ~UART_MCR_##LINE; } while (0)
+#define FLOWCTL_SET(LINE)	\
+	do { GDBPORT_SERIAL_MCR |= UART_MCR_##LINE; } while (0)
+
+	FLOWCTL_SET(DTR);
+
+	for (; n > 0; n--) {
+		LSR_WAIT_FOR(THRE);
+		FLOWCTL_WAIT_FOR(CTS);
+
+		ch = *p++;
+		if (ch == 0x0a) {
+			GDBPORT_SERIAL_TX = 0x0d;
+			LSR_WAIT_FOR(THRE);
+			FLOWCTL_WAIT_FOR(CTS);
+		}
+		GDBPORT_SERIAL_TX = ch;
+	}
+
+	FLOWCTL_CLEAR(DTR);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* CONFIG_GDBSTUB_ON_TTYSx */
+
+#define SERIAL_INITIALIZE					\
+do {								\
+	/* release reset */					\
+	ASB2364_FPGA_REG_RESET_UART = 0x0001;			\
+	SyncExBus();						\
+} while (0)
+
+#define SERIAL_CHECK_INTERRUPT					\
+do {								\
+	if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) == 0x0001) {	\
+		return IRQ_NONE;				\
+	}							\
+} while (0)
+
+#define SERIAL_CLEAR_INTERRUPT					\
+do {								\
+	ASB2364_FPGA_REG_IRQ_UART = 0x0001;			\
+	SyncExBus();						\
+} while (0)
+
+#define SERIAL_SET_INT_MASK					\
+do {								\
+	ASB2364_FPGA_REG_MASK_UART = 0x0001;			\
+	SyncExBus();						\
+} while (0)
+
+#define SERIAL_CLEAR_INT_MASK					\
+do {								\
+	ASB2364_FPGA_REG_MASK_UART = 0x0000;			\
+	SyncExBus();						\
+} while (0)
+
+#endif /* _ASM_UNIT_SERIAL_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/smsc911x.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/smsc911x.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/smsc911x.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/smsc911x.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,171 @@
+/* Support for the SMSC911x NIC
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_UNIT_SMSC911X_H
+#define _ASM_UNIT_SMSC911X_H
+
+#include <linux/netdevice.h>
+#include <proc/irq.h>
+#include <unit/fpga-regs.h>
+
+#define MN10300_USE_EXT_EEPROM
+
+
+#define SMSC911X_BASE		0xA8000000UL
+#define SMSC911X_BASE_END	0xA8000100UL
+#define SMSC911X_IRQ		FPGA_LAN_IRQ
+
+/*
+ * Allow the FPGA to be initialised by the SMSC911x driver
+ */
+#undef SMSC_INITIALIZE
+#define SMSC_INITIALIZE()					\
+do {								\
+	/* release reset */					\
+	ASB2364_FPGA_REG_RESET_LAN = 0x0001;			\
+	SyncExBus();						\
+} while (0)
+
+#ifdef MN10300_USE_EXT_EEPROM
+#include <linux/delay.h>
+#include <unit/clock.h>
+
+#define EEPROM_ADDRESS	0xA0
+#define MAC_OFFSET	0x0008
+#define USE_IIC_CH	0	/* 0 or 1 */
+#define IIC_OFFSET	(0x80000 * USE_IIC_CH)
+#define IIC_DTRM	__SYSREG(0xd8400000 + IIC_OFFSET, u32)
+#define IIC_DREC	__SYSREG(0xd8400004 + IIC_OFFSET, u32)
+#define IIC_MYADD	__SYSREG(0xd8400008 + IIC_OFFSET, u32)
+#define IIC_CLK		__SYSREG(0xd840000c + IIC_OFFSET, u32)
+#define IIC_BRST	__SYSREG(0xd8400010 + IIC_OFFSET, u32)
+#define IIC_HOLD	__SYSREG(0xd8400014 + IIC_OFFSET, u32)
+#define IIC_BSTS	__SYSREG(0xd8400018 + IIC_OFFSET, u32)
+#define IIC_ICR		__SYSREG(0xd4000080 + 4 * USE_IIC_CH, u16)
+
+#define IIC_CLK_PLS	((unsigned short)(MN10300_IOCLK / 100000 - 1))
+#define IIC_CLK_LOW	((unsigned short)(IIC_CLK_PLS / 2))
+
+#define SYS_IIC_DTRM_Bit_STA	((unsigned short)0x0400)
+#define SYS_IIC_DTRM_Bit_STO	((unsigned short)0x0200)
+#define SYS_IIC_DTRM_Bit_ACK	((unsigned short)0x0100)
+#define SYS_IIC_DTRM_Bit_DATA	((unsigned short)0x00FF)
+
+static inline void POLL_INT_REQ(volatile u16 *icr)
+{
+	unsigned long flags;
+	u16 tmp;
+
+	while (!(*icr & GxICR_REQUEST))
+		;
+	flags = arch_local_cli_save();
+	tmp = *icr;
+	*icr = (tmp & GxICR_LEVEL) | GxICR_DETECT;
+	tmp = *icr;
+	arch_local_irq_restore(flags);
+}
+
+/*
+ * Implement the SMSC911x hook for MAC address retrieval
+ */
+#undef smsc_get_mac
+static inline int smsc_get_mac(struct net_device *dev)
+{
+	unsigned char *mac_buf = dev->dev_addr;
+	int i;
+	unsigned short value;
+	unsigned int data;
+	int mac_length = 6;
+	int check;
+	u16 orig_gicr, tmp;
+	unsigned long flags;
+
+	/* save original GnICR and clear GnICR.IE */
+	flags = arch_local_cli_save();
+	orig_gicr = IIC_ICR;
+	IIC_ICR = orig_gicr & GxICR_LEVEL;
+	tmp = IIC_ICR;
+	arch_local_irq_restore(flags);
+
+	IIC_MYADD = 0x00000008;
+	IIC_CLK = (IIC_CLK_LOW << 16) + (IIC_CLK_PLS);
+	/* bus hung recovery */
+
+	while (1) {
+		check = 0;
+		for (i = 0; i < 3; i++) {
+			if ((IIC_BSTS & 0x00000003) == 0x00000003)
+				check++;
+			udelay(3);
+		}
+
+		if (check == 3) {
+			IIC_BRST = 0x00000003;
+			break;
+		} else {
+			for (i = 0; i < 3; i++) {
+				IIC_BRST = 0x00000002;
+				udelay(8);
+				IIC_BRST = 0x00000003;
+				udelay(8);
+			}
+		}
+	}
+
+	IIC_BRST = 0x00000002;
+	IIC_BRST = 0x00000003;
+
+	value	=  SYS_IIC_DTRM_Bit_STA | SYS_IIC_DTRM_Bit_ACK;
+	value	|= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
+		    (unsigned short)0x0000);
+	IIC_DTRM = value;
+	POLL_INT_REQ(&IIC_ICR);
+
+	/** send offset of MAC address in EEPROM **/
+	IIC_DTRM = (unsigned char)((MAC_OFFSET & 0xFF00) >> 8);
+	POLL_INT_REQ(&IIC_ICR);
+
+	IIC_DTRM = (unsigned char)(MAC_OFFSET & 0x00FF);
+	POLL_INT_REQ(&IIC_ICR);
+
+	udelay(1000);
+
+	value	=  SYS_IIC_DTRM_Bit_STA;
+	value	|= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
+		    (unsigned short)0x0001);
+	IIC_DTRM = value;
+	POLL_INT_REQ(&IIC_ICR);
+
+	IIC_DTRM = 0x00000000;
+	while (mac_length > 0) {
+		POLL_INT_REQ(&IIC_ICR);
+
+		data = IIC_DREC;
+		mac_length--;
+		if (mac_length == 0)
+			value = 0x00000300;	/* stop IIC bus */
+		else if (mac_length == 1)
+			value = 0x00000100;	/* no ack */
+		else
+			value = 0x00000000;	/* ack */
+		IIC_DTRM = value;
+		*mac_buf++ = (unsigned char)(data & 0xff);
+	}
+
+	/* restore GnICR.LV and GnICR.IE */
+	flags = arch_local_cli_save();
+	IIC_ICR = (orig_gicr & (GxICR_LEVEL | GxICR_ENABLE));
+	tmp = IIC_ICR;
+	arch_local_irq_restore(flags);
+
+	return 0;
+}
+#endif /* MN10300_USE_EXT_EEPROM */
+#endif /* _ASM_UNIT_SMSC911X_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/timex.h linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/timex.h
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/include/unit/timex.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/include/unit/timex.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,159 @@
+/* timex.h: MN2WS0038 architecture timer specifications
+ *
+ * Copyright (C) 2002, 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_UNIT_TIMEX_H
+#define _ASM_UNIT_TIMEX_H
+
+#ifndef __ASSEMBLY__
+#include <linux/irq.h>
+#endif /* __ASSEMBLY__ */
+
+#include <asm/timer-regs.h>
+#include <unit/clock.h>
+#include <asm/param.h>
+
+/*
+ * jiffies counter specifications
+ */
+
+#define	TMJCBR_MAX		0xffffff	/* 24bit */
+#define	TMJCIRQ			TMTIRQ
+
+#ifndef __ASSEMBLY__
+
+#define MN10300_SRC_IOBCLK	MN10300_IOBCLK
+
+#ifndef HZ
+# error HZ undeclared.
+#endif /* !HZ */
+
+#define MN10300_JCCLK		(MN10300_SRC_IOBCLK)
+#define MN10300_TSCCLK		(MN10300_SRC_IOBCLK)
+
+#define MN10300_JC_PER_HZ	((MN10300_JCCLK + HZ / 2) / HZ)
+#define MN10300_TSC_PER_HZ	((MN10300_TSCCLK + HZ / 2) / HZ)
+
+/* Check bit width of MTM interval value that sets base register */
+#if (MN10300_JC_PER_HZ - 1) > TMJCBR_MAX
+# error MTM tick timer interval value is overflow.
+#endif
+
+static inline void stop_jiffies_counter(void)
+{
+	u16 tmp;
+	TMTMD = 0;
+	tmp = TMTMD;
+}
+
+static inline void reload_jiffies_counter(u32 cnt)
+{
+	u32 tmp;
+
+	TMTBR = cnt;
+	tmp = TMTBR;
+
+	TMTMD = TMTMD_TMTLDE;
+	TMTMD = TMTMD_TMTCNE;
+	tmp = TMTMD;
+}
+
+#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS) && \
+    !defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+/*
+ * If we aren't using broadcasting, each core needs its own event timer.
+ * Since CPU0 uses the tick timer which is 24-bits, we use timer 4 & 5
+ * cascaded to 32-bits for CPU1 (but only really use 24-bits to match
+ * CPU0).
+ */
+
+#define	TMJC1IRQ		TM5IRQ
+
+static inline void stop_jiffies_counter1(void)
+{
+	u8 tmp;
+	TM4MD = 0;
+	TM5MD = 0;
+	tmp = TM4MD;
+	tmp = TM5MD;
+}
+
+static inline void reload_jiffies_counter1(u32 cnt)
+{
+	u32 tmp;
+
+	TM45BR = cnt;
+	tmp = TM45BR;
+
+	TM4MD = TM4MD_INIT_COUNTER;
+	tmp = TM4MD;
+
+	TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_INIT_COUNTER;
+	TM5MD = TM5MD_SRC_TM4CASCADE | TM5MD_COUNT_ENABLE;
+	tmp = TM5MD;
+
+	TM4MD = TM4MD_COUNT_ENABLE;
+	tmp = TM4MD;
+}
+#endif /* CONFIG_SMP&GENERIC_CLOCKEVENTS&!GENERIC_CLOCKEVENTS_BROADCAST */
+
+#endif /* !__ASSEMBLY__ */
+
+
+/*
+ * timestamp counter specifications
+ */
+#define	TMTSCBR_MAX	0xffffffff
+
+#ifndef __ASSEMBLY__
+
+/* Use 32-bit timestamp counter */
+#define	TMTSCMD		TMSMD
+#define	TMTSCBR		TMSBR
+#define	TMTSCBC		TMSBC
+#define	TMTSCICR	TMSICR
+
+static inline void startup_timestamp_counter(void)
+{
+	u32 sync;
+
+	/* set up TMS(Timestamp) 32bit timer register to count real time
+	 * - count down from 4Gig-1 to 0 and wrap at IOBCLK rate
+	 */
+
+	TMTSCBR = TMTSCBR_MAX;
+	sync = TMTSCBR;
+
+	TMTSCICR = 0;
+	sync = TMTSCICR;
+
+	TMTSCMD = TMTMD_TMTLDE;
+	TMTSCMD = TMTMD_TMTCNE;
+	sync = TMTSCMD;
+}
+
+static inline void shutdown_timestamp_counter(void)
+{
+	TMTSCMD = 0;
+}
+
+/*
+ * we use a cascaded pair of 16-bit down-counting timers to count I/O
+ * clock cycles for the purposes of time keeping
+ */
+typedef unsigned long cycles_t;
+
+static inline cycles_t read_timestamp_counter(void)
+{
+	return (cycles_t)~TMTSCBC;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_UNIT_TIMEX_H */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/irq-fpga.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/irq-fpga.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/irq-fpga.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/irq-fpga.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,96 @@
+/* ASB2364 FPGA interrupt multiplexing
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <unit/fpga-regs.h>
+
+/*
+ * FPGA PIC operations
+ */
+static void asb2364_fpga_mask(unsigned int irq)
+{
+	ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+	SyncExBus();
+}
+
+static void asb2364_fpga_ack(unsigned int irq)
+{
+	ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+	SyncExBus();
+}
+
+static void asb2364_fpga_mask_ack(unsigned int irq)
+{
+	ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0001;
+	SyncExBus();
+	ASB2364_FPGA_REG_IRQ(irq - NR_CPU_IRQS) = 0x0001;
+	SyncExBus();
+}
+
+static void asb2364_fpga_unmask(unsigned int irq)
+{
+	ASB2364_FPGA_REG_MASK(irq - NR_CPU_IRQS) = 0x0000;
+	SyncExBus();
+}
+
+static struct irq_chip asb2364_fpga_pic = {
+	.name		= "fpga",
+	.ack		= asb2364_fpga_ack,
+	.mask		= asb2364_fpga_mask,
+	.mask_ack	= asb2364_fpga_mask_ack,
+	.unmask		= asb2364_fpga_unmask,
+};
+
+/*
+ * FPGA PIC interrupt handler
+ */
+static irqreturn_t fpga_interrupt(int irq, void *_mask)
+{
+	if ((ASB2364_FPGA_REG_IRQ_LAN  & 0x0001) != 0x0001)
+		generic_handle_irq(FPGA_LAN_IRQ);
+	if ((ASB2364_FPGA_REG_IRQ_UART & 0x0001) != 0x0001)
+		generic_handle_irq(FPGA_UART_IRQ);
+	if ((ASB2364_FPGA_REG_IRQ_I2C  & 0x0001) != 0x0001)
+		generic_handle_irq(FPGA_I2C_IRQ);
+	if ((ASB2364_FPGA_REG_IRQ_USB  & 0x0001) != 0x0001)
+		generic_handle_irq(FPGA_USB_IRQ);
+	if ((ASB2364_FPGA_REG_IRQ_FPGA & 0x0001) != 0x0001)
+		generic_handle_irq(FPGA_FPGA_IRQ);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Define an interrupt action for each FPGA PIC output
+ */
+static struct irqaction fpga_irq[]  = {
+	[0] = {
+		.handler	= fpga_interrupt,
+		.flags		= IRQF_DISABLED | IRQF_SHARED,
+		.name		= "fpga",
+	},
+};
+
+/*
+ * Initialise the FPGA's PIC
+ */
+void __init irq_fpga_init(void)
+{
+	int irq;
+
+	for (irq = NR_CPU_IRQS; irq < NR_IRQS; irq++)
+		set_irq_chip_and_handler(irq, &asb2364_fpga_pic, handle_level_irq);
+
+	/* the FPGA drives the XIRQ1 input on the CPU PIC */
+	setup_irq(XIRQ1, &fpga_irq[0]);
+}
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/leds.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/leds.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/leds.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/leds.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,98 @@
+/* leds.c: ASB2364 peripheral 7seg LEDs x4 support
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/intctl-regs.h>
+#include <asm/rtc-regs.h>
+#include <unit/leds.h>
+
+#if MN10300_USE_7SEGLEDS
+static const u8 asb2364_led_hex_tbl[16] = {
+	0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0,
+	0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c
+};
+
+static const u32 asb2364_led_chase_tbl[6] = {
+	~0x02020202,	/* top		- segA */
+	~0x04040404,	/* right top	- segB */
+	~0x08080808,	/* right bottom	- segC */
+	~0x10101010,	/* bottom	- segD */
+	~0x20202020,	/* left bottom	- segE */
+	~0x40404040,	/* left top	- segF */
+};
+
+static unsigned asb2364_led_chase;
+
+void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points)
+{
+	u32 leds;
+
+	leds = asb2364_led_hex_tbl[(val/1000) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[(val/100) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[(val/10) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[val % 10];
+	leds |= points^0x01010101;
+
+	ASB2364_7SEGLEDS = leds;
+}
+
+void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points)
+{
+	u32 leds;
+
+	leds = asb2364_led_hex_tbl[(val/1000) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[(val/100) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[(val/10) % 10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[val % 10];
+	leds |= points^0x01010101;
+
+	ASB2364_7SEGLEDS = leds;
+}
+
+/* display triple horizontal bar and exception code */
+void peripheral_leds_display_exception(enum exception_code code)
+{
+	u32 leds;
+
+	leds = asb2364_led_hex_tbl[(code/0x100) % 0x10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[(code/0x10) % 0x10];
+	leds <<= 8;
+	leds |= asb2364_led_hex_tbl[code % 0x10];
+	leds |= 0x6d010101;
+
+	ASB2364_7SEGLEDS = leds;
+}
+
+void peripheral_leds_led_chase(void)
+{
+	ASB2364_7SEGLEDS = asb2364_led_chase_tbl[asb2364_led_chase];
+	asb2364_led_chase++;
+	if (asb2364_led_chase >= 6)
+		asb2364_led_chase = 0;
+}
+#else  /* MN10300_USE_7SEGLEDS */
+void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points) { }
+void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points) { }
+void peripheral_leds_display_exception(enum exception_code code) { }
+void peripheral_leds_led_chase(void) { }
+#endif /* MN10300_USE_7SEGLEDS */
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/Makefile linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/Makefile
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+obj-y   := unit-init.o leds.o irq-fpga.o
+
+obj-$(CONFIG_SMSC911X) += smsc911x.o
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/smsc911x.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/smsc911x.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/smsc911x.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/smsc911x.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,58 @@
+/* Specification for the SMSC911x NIC
+ *
+ * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/smsc911x.h>
+#include <unit/smsc911x.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+	.flags		= SMSC911X_USE_32BIT,
+};
+
+static struct resource smsc911x_resources[] = {
+	[0] = {
+		.start	= SMSC911X_BASE,
+		.end	= SMSC911X_BASE_END,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= SMSC911X_IRQ,
+		.end	= SMSC911X_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smsc911x_device = {
+	.name		= "smsc911x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smsc911x_resources),
+	.resource	= smsc911x_resources,
+	.dev		= {
+		.platform_data = &smsc911x_config,
+	}
+};
+
+/*
+ * add platform devices
+ */
+static int __init unit_device_init(void)
+{
+	platform_device_register(&smsc911x_device);
+	return 0;
+}
+
+device_initcall(unit_device_init);
diff -druN linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/unit-init.c linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/unit-init.c
--- linux-libre-2.6.36-gnu/arch/mn10300/unit-asb2364/unit-init.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/mn10300/unit-asb2364/unit-init.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,88 @@
+/* ASB2364 initialisation
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/intctl-regs.h>
+#include <unit/fpga-regs.h>
+
+/*
+ * initialise some of the unit hardware before gdbstub is set up
+ */
+asmlinkage void __init unit_init(void)
+{
+	/* set up the external interrupts */
+
+	/* XIRQ[0]: NAND RXBY */
+	/* SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_LOWLEVEL); */
+
+	/* XIRQ[1]: LAN, UART, I2C, USB, PCI, FPGA */
+	SET_XIRQ_TRIGGER(1, XIRQ_TRIGGER_LOWLEVEL);
+
+	/* XIRQ[2]: Extend Slot 1-9 */
+	/* SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL); */
+
+#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL) &&	\
+    defined(CONFIG_ETHERNET_IRQ_LEVEL) &&	\
+    (CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL)
+# error CONFIG_EXT_SERIAL_IRQ_LEVEL != CONFIG_ETHERNET_IRQ_LEVEL
+#endif
+
+#if defined(CONFIG_EXT_SERIAL_IRQ_LEVEL)
+	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_EXT_SERIAL_IRQ_LEVEL));
+#elif defined(CONFIG_ETHERNET_IRQ_LEVEL)
+	set_intr_level(XIRQ1, NUM2GxICR_LEVEL(CONFIG_ETHERNET_IRQ_LEVEL));
+#endif
+}
+
+/*
+ * initialise the rest of the unit hardware after gdbstub is ready
+ */
+asmlinkage void __init unit_setup(void)
+{
+
+}
+
+/*
+ * initialise the external interrupts used by a unit of this type
+ */
+void __init unit_init_IRQ(void)
+{
+	unsigned int extnum;
+
+	for (extnum = 0 ; extnum < NR_XIRQS ; extnum++) {
+		switch (GET_XIRQ_TRIGGER(extnum)) {
+			/* LEVEL triggered interrupts should be made
+			 * post-ACK'able as they hold their lines until
+			 * serviced
+			 */
+		case XIRQ_TRIGGER_HILEVEL:
+		case XIRQ_TRIGGER_LOWLEVEL:
+			mn10300_set_lateack_irq_type(XIRQ2IRQ(extnum));
+			break;
+		default:
+			break;
+		}
+	}
+
+#define IRQCTL	__SYSREG(0xd5000090, u32)
+	IRQCTL |= 0x02;
+
+	irq_fpga_init();
+}
diff -druN linux-libre-2.6.36-gnu/arch/parisc/hpux/sys_hpux.c linux-libre-2.6.37-gnu/arch/parisc/hpux/sys_hpux.c
--- linux-libre-2.6.36-gnu/arch/parisc/hpux/sys_hpux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/hpux/sys_hpux.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/utsname.h>
 #include <linux/vfs.h>
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/cacheflush.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/cacheflush.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/cacheflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/cacheflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -126,20 +126,20 @@
 
 #define kunmap(page)			kunmap_parisc(page_address(page))
 
-static inline void *kmap_atomic(struct page *page, enum km_type idx)
+static inline void *__kmap_atomic(struct page *page)
 {
 	pagefault_disable();
 	return page_address(page);
 }
 
-static inline void kunmap_atomic_notypecheck(void *addr, enum km_type idx)
+static inline void __kunmap_atomic(void *addr)
 {
 	kunmap_parisc(addr);
 	pagefault_enable();
 }
 
-#define kmap_atomic_prot(page, idx, prot)	kmap_atomic(page, idx)
-#define kmap_atomic_pfn(pfn, idx)	kmap_atomic(pfn_to_page(pfn), (idx))
+#define kmap_atomic_prot(page, prot)	kmap_atomic(page)
+#define kmap_atomic_pfn(pfn)	kmap_atomic(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/cache.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/cache.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/cache.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/cache.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,8 +24,6 @@
 
 #ifndef __ASSEMBLY__
 
-#define L1_CACHE_ALIGN(x)       (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
-
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 
 #define ARCH_DMA_MINALIGN	L1_CACHE_BYTES
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,46 @@
+#ifndef __PARISC_IRQFLAGS_H
+#define __PARISC_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <asm/psw.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("ssm 0, %0" : "=r" (flags) : : "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("mtsm %0" : : "r" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & PSW_I) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __PARISC_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/irq.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/irq.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,7 @@
 void no_ack_irq(unsigned int irq);
 void no_end_irq(unsigned int irq);
 void cpu_ack_irq(unsigned int irq);
-void cpu_end_irq(unsigned int irq);
+void cpu_eoi_irq(unsigned int irq);
 
 extern int txn_alloc_irq(unsigned int nbits);
 extern int txn_claim_irq(int);
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 #ifndef __ASM_PARISC_PERF_EVENT_H
 #define __ASM_PARISC_PERF_EVENT_H
 
-/* parisc only supports software events through this interface. */
-static inline void set_perf_event_pending(void) { }
+/* Empty, just to avoid compiling error */
 
 #endif /* __ASM_PARISC_PERF_EVENT_H */
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -397,9 +397,7 @@
 #define pte_offset_kernel(pmd, address) \
 	((pte_t *) pmd_page_vaddr(*(pmd)) + pte_index(address))
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 #define pte_unmap(pte)			do { } while (0)
 #define pte_unmap_nested(pte)		do { } while (0)
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/system.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 #ifndef __PARISC_SYSTEM_H
 #define __PARISC_SYSTEM_H
 
-#include <asm/psw.h>
+#include <linux/irqflags.h>
 
 /* The program status word as bitfields.  */
 struct pa_psw {
@@ -48,23 +48,6 @@
 	(last) = _switch_to(prev, next);			\
 } while(0)
 
-/* interrupt control */
-#define local_save_flags(x)	__asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
-#define local_irq_disable()	__asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-#define local_irq_enable()	__asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-
-#define local_irq_save(x) \
-	__asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_restore(x) \
-	__asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
-
-#define irqs_disabled()			\
-({					\
-	unsigned long flags;		\
-	local_save_flags(flags);	\
-	(flags & PSW_I) == 0;		\
-})
-
 #define mfctl(reg)	({		\
 	unsigned long cr;		\
 	__asm__ __volatile__(		\
diff -druN linux-libre-2.6.36-gnu/arch/parisc/include/asm/unistd.h linux-libre-2.6.37-gnu/arch/parisc/include/asm/unistd.h
--- linux-libre-2.6.36-gnu/arch/parisc/include/asm/unistd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/include/asm/unistd.h	2011-01-04 19:50:19.000000000 -0500
@@ -813,8 +813,9 @@
 #define __NR_perf_event_open	(__NR_Linux + 318)
 #define __NR_recvmmsg		(__NR_Linux + 319)
 #define __NR_accept4		(__NR_Linux + 320)
+#define __NR_prlimit64		(__NR_Linux + 321)
 
-#define __NR_Linux_syscalls	(__NR_accept4 + 1)
+#define __NR_Linux_syscalls	(__NR_prlimit64 + 1)
 
 
 #define __IGNORE_select		/* newselect */
diff -druN linux-libre-2.6.36-gnu/arch/parisc/Kconfig linux-libre-2.6.37-gnu/arch/parisc/Kconfig
--- linux-libre-2.6.36-gnu/arch/parisc/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux/PA-RISC Kernel Configuration"
-
 config PARISC
 	def_bool y
 	select HAVE_IDE
@@ -16,8 +9,10 @@
 	select RTC_DRV_GENERIC
 	select INIT_ALL_POSSIBLE
 	select BUG
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select GENERIC_ATOMIC64 if !64BIT
+	select GENERIC_HARDIRQS_NO__DO_IRQ
 	help
 	  The PA-RISC microprocessor is designed by Hewlett-Packard and used
 	  in many of their workstations & servers (HP9000 700 and 800 series,
@@ -84,6 +79,9 @@
 	bool
 	default y
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+	def_bool y
+
 # unless you want to implement ACPI on PA-RISC ... ;-)
 config PM
 	bool
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/irq.c linux-libre-2.6.37-gnu/arch/parisc/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
 */
 static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
 
-static void cpu_disable_irq(unsigned int irq)
+static void cpu_mask_irq(unsigned int irq)
 {
 	unsigned long eirr_bit = EIEM_MASK(irq);
 
@@ -63,7 +63,7 @@
 	 * then gets disabled */
 }
 
-static void cpu_enable_irq(unsigned int irq)
+static void cpu_unmask_irq(unsigned int irq)
 {
 	unsigned long eirr_bit = EIEM_MASK(irq);
 
@@ -75,15 +75,6 @@
 	smp_send_all_nop();
 }
 
-static unsigned int cpu_startup_irq(unsigned int irq)
-{
-	cpu_enable_irq(irq);
-	return 0;
-}
-
-void no_ack_irq(unsigned int irq) { }
-void no_end_irq(unsigned int irq) { }
-
 void cpu_ack_irq(unsigned int irq)
 {
 	unsigned long mask = EIEM_MASK(irq);
@@ -99,7 +90,7 @@
 	mtctl(mask, 23);
 }
 
-void cpu_end_irq(unsigned int irq)
+void cpu_eoi_irq(unsigned int irq)
 {
 	unsigned long mask = EIEM_MASK(irq);
 	int cpu = smp_processor_id();
@@ -146,12 +137,10 @@
 
 static struct irq_chip cpu_interrupt_type = {
 	.name		= "CPU",
-	.startup	= cpu_startup_irq,
-	.shutdown	= cpu_disable_irq,
-	.enable		= cpu_enable_irq,
-	.disable	= cpu_disable_irq,
+	.mask		= cpu_mask_irq,
+	.unmask		= cpu_unmask_irq,
 	.ack		= cpu_ack_irq,
-	.end		= cpu_end_irq,
+	.eoi		= cpu_eoi_irq,
 #ifdef CONFIG_SMP
 	.set_affinity	= cpu_set_affinity_irq,
 #endif
@@ -247,10 +236,11 @@
 	if (irq_desc[irq].chip != &cpu_interrupt_type)
 		return -EBUSY;
 
+	/* for iosapic interrupts */
 	if (type) {
-		irq_desc[irq].chip = type;
-		irq_desc[irq].chip_data = data;
-		cpu_interrupt_type.enable(irq);
+		set_irq_chip_and_handler(irq, type, handle_percpu_irq);
+		set_irq_chip_data(irq, data);
+		cpu_unmask_irq(irq);
 	}
 	return 0;
 }
@@ -368,7 +358,7 @@
 		goto set_out;
 	}
 #endif
-	__do_IRQ(irq);
+	generic_handle_irq(irq);
 
  out:
 	irq_exit();
@@ -398,14 +388,15 @@
 {
 	int i;
 	for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
-		irq_desc[i].chip = &cpu_interrupt_type;
+		set_irq_chip_and_handler(i, &cpu_interrupt_type,
+					 handle_percpu_irq);
 	}
 
-	irq_desc[TIMER_IRQ].action = &timer_action;
-	irq_desc[TIMER_IRQ].status = IRQ_PER_CPU;
+	set_irq_handler(TIMER_IRQ, handle_percpu_irq);
+	setup_irq(TIMER_IRQ, &timer_action);
 #ifdef CONFIG_SMP
-	irq_desc[IPI_IRQ].action = &ipi_action;
-	irq_desc[IPI_IRQ].status = IRQ_PER_CPU;
+	set_irq_handler(IPI_IRQ, handle_percpu_irq);
+	setup_irq(IPI_IRQ, &ipi_action);
 #endif
 }
 
@@ -423,3 +414,4 @@
         set_eiem(cpu_eiem);	/* EIEM : enable all external intr */
 
 }
+
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/pdc_cons.c linux-libre-2.6.37-gnu/arch/parisc/kernel/pdc_cons.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/pdc_cons.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/pdc_cons.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
  *    Copyright (C) 2001 Helge Deller <deller at parisc-linux.org>
  *    Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
  *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ *    Copyright (C) 2010 Guy Martin <gmsoft at tuxicoman.be>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -31,12 +32,11 @@
 
 /*
  *  The PDC console is a simple console, which can be used for debugging 
- *  boot related problems on HP PA-RISC machines.
+ *  boot related problems on HP PA-RISC machines. It is also useful when no
+ *  other console works.
  *
  *  This code uses the ROM (=PDC) based functions to read and write characters
  *  from and to PDC's boot path.
- *  Since all character read from that path must be polled, this code never
- *  can or will be a fully functional linux console.
  */
 
 /* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
@@ -53,6 +53,7 @@
 #include <asm/pdc.h>		/* for iodc_call() proto and friends */
 
 static DEFINE_SPINLOCK(pdc_console_lock);
+static struct console pdc_cons;
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
@@ -85,12 +86,138 @@
 
 #if defined(CONFIG_PDC_CONSOLE)
 #include <linux/vt_kern.h>
+#include <linux/tty_flip.h>
+
+#define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
+
+static struct timer_list pdc_console_timer;
+
+extern struct console * console_drivers;
+
+static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
+{
+
+	mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+
+	return 0;
+}
+
+static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	if (!tty->count)
+		del_timer(&pdc_console_timer);
+}
+
+static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+	pdc_console_write(NULL, buf, count);
+	return count;
+}
+
+static int pdc_console_tty_write_room(struct tty_struct *tty)
+{
+	return 32768; /* no limit, no buffer used */
+}
+
+static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	return 0; /* no buffer */
+}
+
+static struct tty_driver *pdc_console_tty_driver;
+
+static const struct tty_operations pdc_console_tty_ops = {
+	.open = pdc_console_tty_open,
+	.close = pdc_console_tty_close,
+	.write = pdc_console_tty_write,
+	.write_room = pdc_console_tty_write_room,
+	.chars_in_buffer = pdc_console_tty_chars_in_buffer,
+};
+
+static void pdc_console_poll(unsigned long unused)
+{
+
+	int data, count = 0;
+
+	struct tty_struct *tty = pdc_console_tty_driver->ttys[0];
+
+	if (!tty)
+		return;
+
+	while (1) {
+		data = pdc_console_poll_key(NULL);
+		if (data == -1)
+			break;
+		tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
+		count ++;
+	}
+
+	if (count)
+		tty_flip_buffer_push(tty);
+
+	if (tty->count && (pdc_cons.flags & CON_ENABLED))
+		mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
+}
+
+static int __init pdc_console_tty_driver_init(void)
+{
+
+	int err;
+	struct tty_driver *drv;
+
+	/* Check if the console driver is still registered.
+	 * It is unregistered if the pdc console was not selected as the
+	 * primary console. */
+
+	struct console *tmp = console_drivers;
+
+	for (tmp = console_drivers; tmp; tmp = tmp->next)
+		if (tmp == &pdc_cons)
+			break;
+
+	if (!tmp) {
+		printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
+	pdc_cons.flags &= ~CON_BOOT;
+
+	drv = alloc_tty_driver(1);
+
+	if (!drv)
+		return -ENOMEM;
+
+	drv->driver_name = "pdc_cons";
+	drv->name = "ttyB";
+	drv->major = MUX_MAJOR;
+	drv->minor_start = 0;
+	drv->type = TTY_DRIVER_TYPE_SYSTEM;
+	drv->init_termios = tty_std_termios;
+	drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+	tty_set_operations(drv, &pdc_console_tty_ops);
+
+	err = tty_register_driver(drv);
+	if (err) {
+		printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
+		return err;
+	}
+
+	pdc_console_tty_driver = drv;
+
+	/* No need to initialize the pdc_console_timer if tty isn't allocated */
+	init_timer(&pdc_console_timer);
+	pdc_console_timer.function = pdc_console_poll;
+
+	return 0;
+}
+
+module_init(pdc_console_tty_driver_init);
 
 static struct tty_driver * pdc_console_device (struct console *c, int *index)
 {
-	extern struct tty_driver console_driver;
-	*index = c->index ? c->index-1 : fg_console;
-	return &console_driver;
+	*index = c->index;
+	return pdc_console_tty_driver;
 }
 #else
 #define pdc_console_device NULL
@@ -101,7 +228,7 @@
 	.write =	pdc_console_write,
 	.device =	pdc_console_device,
 	.setup =	pdc_console_setup,
-	.flags =	CON_BOOT | CON_PRINTBUFFER | CON_ENABLED,
+	.flags =	CON_BOOT | CON_PRINTBUFFER,
 	.index =	-1,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/perf.c linux-libre-2.6.37-gnu/arch/parisc/kernel/perf.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/perf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/perf.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,6 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
@@ -261,16 +260,13 @@
  */
 static int perf_open(struct inode *inode, struct file *file)
 {
-	lock_kernel();
 	spin_lock(&perf_lock);
 	if (perf_enabled) {
 		spin_unlock(&perf_lock);
-		unlock_kernel();
 		return -EBUSY;
 	}
 	perf_enabled = 1;
  	spin_unlock(&perf_lock);
-	unlock_kernel();
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/parisc/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -110,7 +110,8 @@
 	pa_psw(task)->l = 0;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long tmp;
 	long ret = -EIO;
@@ -120,11 +121,11 @@
 	/* Read the word at location addr in the USER area.  For ptraced
 	   processes, the kernel saves all regs on a syscall. */
 	case PTRACE_PEEKUSR:
-		if ((addr & (sizeof(long)-1)) ||
-		    (unsigned long) addr >= sizeof(struct pt_regs))
+		if ((addr & (sizeof(unsigned long)-1)) ||
+		     addr >= sizeof(struct pt_regs))
 			break;
 		tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
-		ret = put_user(tmp, (unsigned long *) data);
+		ret = put_user(tmp, (unsigned long __user *) data);
 		break;
 
 	/* Write the word at location addr in the USER area.  This will need
@@ -151,8 +152,8 @@
 			break;
 		}
 
-		if ((addr & (sizeof(long)-1)) ||
-		    (unsigned long) addr >= sizeof(struct pt_regs))
+		if ((addr & (sizeof(unsigned long)-1)) ||
+		     addr >= sizeof(struct pt_regs))
 			break;
 		if ((addr >= PT_GR1 && addr <= PT_GR31) ||
 				addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/signal.c linux-libre-2.6.37-gnu/arch/parisc/kernel/signal.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/signal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/signal.c	2011-01-04 19:50:19.000000000 -0500
@@ -98,7 +98,6 @@
 sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
 {
 	struct rt_sigframe __user *frame;
-	struct siginfo si;
 	sigset_t set;
 	unsigned long usp = (regs->gr[30] & ~(0x01UL));
 	unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
@@ -178,13 +177,7 @@
 
 give_sigsegv:
 	DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n");
-	si.si_signo = SIGSEGV;
-	si.si_errno = 0;
-	si.si_code = SI_KERNEL;
-	si.si_pid = task_pid_vnr(current);
-	si.si_uid = current_uid();
-	si.si_addr = &frame->uc;
-	force_sig_info(SIGSEGV, &si, current);
+	force_sig(SIGSEGV, current);
 	return;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/syscall_table.S linux-libre-2.6.37-gnu/arch/parisc/kernel/syscall_table.S
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/syscall_table.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/syscall_table.S	2011-01-04 19:50:19.000000000 -0500
@@ -419,6 +419,7 @@
 	ENTRY_SAME(perf_event_open)
 	ENTRY_COMP(recvmmsg)
 	ENTRY_SAME(accept4)		/* 320 */
+	ENTRY_SAME(prlimit64)
 
 	/* Nothing yet */
 
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/sys_parisc32.c linux-libre-2.6.37-gnu/arch/parisc/kernel/sys_parisc32.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/sys_parisc32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/sys_parisc32.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
 #include <linux/times.h>
 #include <linux/time.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/unaligned.c linux-libre-2.6.37-gnu/arch/parisc/kernel/unaligned.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/unaligned.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/unaligned.c	2011-01-04 19:50:19.000000000 -0500
@@ -619,15 +619,12 @@
 		flop=1;
 		ret = emulate_std(regs, R2(regs->iir),1);
 		break;
-
-#ifdef CONFIG_PA20
 	case OPCODE_LDD_L:
 		ret = emulate_ldd(regs, R2(regs->iir),0);
 		break;
 	case OPCODE_STD_L:
 		ret = emulate_std(regs, R2(regs->iir),0);
 		break;
-#endif
 	}
 #endif
 	switch (regs->iir & OPCODE3_MASK)
diff -druN linux-libre-2.6.36-gnu/arch/parisc/kernel/unwind.c linux-libre-2.6.37-gnu/arch/parisc/kernel/unwind.c
--- linux-libre-2.6.36-gnu/arch/parisc/kernel/unwind.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/kernel/unwind.c	2011-01-04 19:50:19.000000000 -0500
@@ -80,8 +80,11 @@
 			if (addr >= table->start && 
 			    addr <= table->end)
 				e = find_unwind_entry_in_table(table, addr);
-			if (e)
+			if (e) {
+				/* Move-to-front to exploit common traces */
+				list_move(&table->list, &unwind_tables);
 				break;
+			}
 		}
 
 	return e;
diff -druN linux-libre-2.6.36-gnu/arch/parisc/math-emu/Makefile linux-libre-2.6.37-gnu/arch/parisc/math-emu/Makefile
--- linux-libre-2.6.36-gnu/arch/parisc/math-emu/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/parisc/math-emu/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
 #
 
 # See arch/parisc/math-emu/README
-EXTRA_CFLAGS += -Wno-parentheses -Wno-implicit-function-declaration \
+ccflags-y := -Wno-parentheses -Wno-implicit-function-declaration \
 	-Wno-uninitialized -Wno-strict-prototypes -Wno-return-type \
 	-Wno-implicit-int
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/addnote.c linux-libre-2.6.37-gnu/arch/powerpc/boot/addnote.c
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/addnote.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/addnote.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 #include <string.h>
 
 /* CHRP note section */
-char arch[] = "PowerPC";
+static const char arch[] = "PowerPC";
 
 #define N_DESCR	6
 unsigned int descr[N_DESCR] = {
@@ -33,7 +33,7 @@
 };
 
 /* RPA note section */
-char rpaname[] = "IBM,RPA-Client-Config";
+static const char rpaname[] = "IBM,RPA-Client-Config";
 
 /*
  * Note: setting ignore_my_client_config *should* mean that OF ignores
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/div64.S linux-libre-2.6.37-gnu/arch/powerpc/boot/div64.S
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/div64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/div64.S	2011-01-04 19:50:19.000000000 -0500
@@ -33,9 +33,10 @@
 	cntlzw	r0,r5		# we are shifting the dividend right
 	li	r10,-1		# to make it < 2^32, and shifting
 	srw	r10,r10,r0	# the divisor right the same amount,
-	add	r9,r4,r10	# rounding up (so the estimate cannot
+	addc	r9,r4,r10	# rounding up (so the estimate cannot
 	andc	r11,r6,r10	# ever be too large, only too small)
 	andc	r9,r9,r10
+	addze	r9,r9
 	or	r11,r5,r11
 	rotlw	r9,r9,r0
 	rotlw	r11,r11,r0
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/bluestone.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/bluestone.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/bluestone.dts	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/bluestone.dts	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,254 @@
+/*
+ * Device Tree for Bluestone (APM821xx) board.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Author: Tirumala R Marri <tmarri@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/dts-v1/;
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	model = "apm,bluestone";
+	compatible = "apm,bluestone";
+	dcr-parent = <&{/cpus/cpu@0}>;
+
+	aliases {
+		ethernet0 = &EMAC0;
+		serial0 = &UART0;
+		serial1 = &UART1;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			model = "PowerPC,apm821xx";
+			reg = <0x00000000>;
+			clock-frequency = <0>; /* Filled in by U-Boot */
+			timebase-frequency = <0>; /* Filled in by U-Boot */
+			i-cache-line-size = <32>;
+			d-cache-line-size = <32>;
+			i-cache-size = <32768>;
+			d-cache-size = <32768>;
+			dcr-controller;
+			dcr-access-method = "native";
+			next-level-cache = <&L2C0>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+	};
+
+	UIC0: interrupt-controller0 {
+		compatible = "ibm,uic";
+		interrupt-controller;
+		cell-index = <0>;
+		dcr-reg = <0x0c0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+	};
+
+	UIC1: interrupt-controller1 {
+		compatible = "ibm,uic";
+		interrupt-controller;
+		cell-index = <1>;
+		dcr-reg = <0x0d0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	UIC2: interrupt-controller2 {
+		compatible = "ibm,uic";
+		interrupt-controller;
+		cell-index = <2>;
+		dcr-reg = <0x0e0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	UIC3: interrupt-controller3 {
+		compatible = "ibm,uic";
+		interrupt-controller;
+		cell-index = <3>;
+		dcr-reg = <0x0f0 0x009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	SDR0: sdr {
+		compatible = "ibm,sdr-apm821xx";
+		dcr-reg = <0x00e 0x002>;
+	};
+
+	CPR0: cpr {
+		compatible = "ibm,cpr-apm821xx";
+		dcr-reg = <0x00c 0x002>;
+	};
+
+	plb {
+		compatible = "ibm,plb4";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges;
+		clock-frequency = <0>; /* Filled in by U-Boot */
+
+		SDRAM0: sdram {
+			compatible = "ibm,sdram-apm821xx";
+			dcr-reg = <0x010 0x002>;
+		};
+
+		MAL0: mcmal {
+			compatible = "ibm,mcmal2";
+			descriptor-memory = "ocm";
+			dcr-reg = <0x180 0x062>;
+			num-tx-chans = <1>;
+			num-rx-chans = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-parent = <&UIC2>;
+			interrupts = <	/*TXEOB*/ 0x6 0x4
+					/*RXEOB*/ 0x7 0x4
+					/*SERR*/  0x3 0x4
+					/*TXDE*/  0x4 0x4
+					/*RXDE*/  0x5 0x4
+		};
+
+		POB0: opb {
+			compatible = "ibm,opb";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+			clock-frequency = <0>; /* Filled in by U-Boot */
+
+			EBC0: ebc {
+				compatible = "ibm,ebc";
+				dcr-reg = <0x012 0x002>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				clock-frequency = <0>; /* Filled in by U-Boot */
+				/* ranges property is supplied by U-Boot */
+				ranges = < 0x00000003 0x00000000 0xe0000000 0x8000000>;
+				interrupts = <0x6 0x4>;
+				interrupt-parent = <&UIC1>;
+
+				nor_flash@0,0 {
+					compatible = "amd,s29gl512n", "cfi-flash";
+					bank-width = <2>;
+					reg = <0x00000000 0x00000000 0x00400000>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					partition@0 {
+						label = "kernel";
+						reg = <0x00000000 0x00180000>;
+					};
+					partition@180000 {
+						label = "env";
+						reg = <0x00180000 0x00020000>;
+					};
+					partition@1a0000 {
+						label = "u-boot";
+						reg = <0x001a0000 0x00060000>;
+					};
+				};
+			}
+
+			UART0: serial@ef600300 {
+				device_type = "serial";
+				compatible = "ns16550";
+				reg = <0xef600300 0x00000008>;
+				virtual-reg = <0xef600300>;
+				clock-frequency = <0>; /* Filled in by U-Boot */
+				current-speed = <0>; /* Filled in by U-Boot */
+				interrupt-parent = <&UIC1>;
+				interrupts = <0x1 0x4>;
+			};
+
+			IIC0: i2c@ef600700 {
+				compatible = "ibm,iic";
+				reg = <0xef600700 0x00000014>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x2 0x4>;
+			};
+
+			IIC1: i2c@ef600800 {
+				compatible = "ibm,iic";
+				reg = <0xef600800 0x00000014>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <0x3 0x4>;
+			};
+
+			RGMII0: emac-rgmii@ef601500 {
+				compatible = "ibm,rgmii";
+				reg = <0xef601500 0x00000008>;
+				has-mdio;
+			};
+
+			TAH0: emac-tah@ef601350 {
+				compatible = "ibm,tah";
+				reg = <0xef601350 0x00000030>;
+			};
+
+			EMAC0: ethernet@ef600c00 {
+				device_type = "network";
+				compatible = "ibm,emac4sync";
+				interrupt-parent = <&EMAC0>;
+				interrupts = <0x0 0x1>;
+				#interrupt-cells = <1>;
+				#address-cells = <0>;
+				#size-cells = <0>;
+				interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
+						 /*Wake*/   0x1 &UIC2 0x14 0x4>;
+				reg = <0xef600c00 0x000000c4>;
+				local-mac-address = [000000000000]; /* Filled in by U-Boot */
+				mal-device = <&MAL0>;
+				mal-tx-channel = <0>;
+				mal-rx-channel = <0>;
+				cell-index = <0>;
+				max-frame-size = <9000>;
+				rx-fifo-size = <16384>;
+				tx-fifo-size = <2048>;
+				phy-mode = "rgmii";
+				phy-map = <0x00000000>;
+				rgmii-device = <&RGMII0>;
+				rgmii-channel = <0>;
+				tah-device = <&TAH0>;
+				tah-channel = <0>;
+				has-inverted-stacr-oc;
+				has-new-stacr-staopc;
+			};
+		};
+
+	};
+};
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8308_p1m.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8308_p1m.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8308_p1m.dts	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8308_p1m.dts	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,332 @@
+/*
+ * mpc8308_p1m Device Tree Source
+ *
+ * Copyright 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.com
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+
+/ {
+	compatible = "denx,mpc8308_p1m";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	aliases {
+		ethernet0 = &enet0;
+		ethernet1 = &enet1;
+		serial0 = &serial0;
+		serial1 = &serial1;
+		pci0 = &pci0;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8308@0 {
+			device_type = "cpu";
+			reg = <0x0>;
+			d-cache-line-size = <32>;
+			i-cache-line-size = <32>;
+			d-cache-size = <16384>;
+			i-cache-size = <16384>;
+			timebase-frequency = <0>;	// from bootloader
+			bus-frequency = <0>;		// from bootloader
+			clock-frequency = <0>;		// from bootloader
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x08000000>;	// 128MB at 0
+	};
+
+	localbus@e0005000 {
+		#address-cells = <2>;
+		#size-cells = <1>;
+		compatible = "fsl,mpc8315-elbc", "fsl,elbc", "simple-bus";
+		reg = <0xe0005000 0x1000>;
+		interrupts = <77 0x8>;
+		interrupt-parent = <&ipic>;
+
+		ranges = <0x0 0x0 0xfc000000 0x04000000
+		          0x1 0x0 0xfbff0000 0x00008000
+		          0x2 0x0 0xfbff8000 0x00008000>;
+
+		flash@0,0 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			compatible = "cfi-flash";
+			reg = <0x0 0x0 0x4000000>;
+			bank-width = <2>;
+			device-width = <1>;
+
+			u-boot@0 {
+				reg = <0x0 0x60000>;
+				read-only;
+			};
+			env@60000 {
+				reg = <0x60000 0x20000>;
+			};
+			env1@80000 {
+				reg = <0x80000 0x20000>;
+			};
+			kernel@a0000 {
+				reg = <0xa0000 0x200000>;
+			};
+			dtb@2a0000 {
+				reg = <0x2a0000 0x20000>;
+			};
+			ramdisk@2c0000 {
+				reg = <0x2c0000 0x640000>;
+			};
+			user@700000 {
+				reg = <0x700000 0x3900000>;
+			};
+		};
+
+		can@1,0 {
+			compatible = "nxp,sja1000";
+			reg = <0x1 0x0 0x80>;
+			interrupts = <18 0x8>;
+			interrups-parent = <&ipic>;
+		};
+
+		cpld@2,0 {
+			compatible = "denx,mpc8308_p1m-cpld";
+			reg = <0x2 0x0 0x8>;
+			interrupts = <48 0x8>;
+			interrups-parent = <&ipic>;
+		};
+	};
+
+	immr@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "fsl,mpc8308-immr", "simple-bus";
+		ranges = <0 0xe0000000 0x00100000>;
+		reg = <0xe0000000 0x00000200>;
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x3000 0x100>;
+			interrupts = <14 0x8>;
+			interrupt-parent = <&ipic>;
+			dfsrr;
+			fram@50 {
+				compatible = "ramtron,24c64";
+				reg = <0x50>;
+			};
+		};
+
+		i2c@3100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl-i2c";
+			reg = <0x3100 0x100>;
+			interrupts = <15 0x8>;
+			interrupt-parent = <&ipic>;
+			dfsrr;
+			pwm@28 {
+				compatible = "maxim,ds1050";
+				reg = <0x28>;
+			};
+			sensor@48 {
+				compatible = "maxim,max6625";
+				reg = <0x48>;
+			};
+			sensor@49 {
+				compatible = "maxim,max6625";
+				reg = <0x49>;
+			};
+			sensor@4b {
+				compatible = "maxim,max6625";
+				reg = <0x4b>;
+			};
+		};
+
+		usb@23000 {
+			compatible = "fsl-usb2-dr";
+			reg = <0x23000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			interrupt-parent = <&ipic>;
+			interrupts = <38 0x8>;
+			dr_mode = "peripheral";
+			phy_type = "ulpi";
+		};
+
+		enet0: ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x24000 0x1000>;
+
+			cell-index = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <32 0x8 33 0x8 34 0x8>;
+			interrupt-parent = <&ipic>;
+			phy-handle = < &phy1 >;
+
+			mdio@520 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,gianfar-mdio";
+				reg = <0x520 0x20>;
+				phy1: ethernet-phy@1 {
+					interrupt-parent = <&ipic>;
+					interrupts = <17 0x8>;
+					reg = <0x1>;
+					device_type = "ethernet-phy";
+				};
+				phy2: ethernet-phy@2 {
+					interrupt-parent = <&ipic>;
+					interrupts = <19 0x8>;
+					reg = <0x2>;
+					device_type = "ethernet-phy";
+				};
+				tbi0: tbi-phy@11 {
+					reg = <0x11>;
+					device_type = "tbi-phy";
+				};
+			};
+		};
+
+		enet1: ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			cell-index = <1>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <0x25000 0x1000>;
+			ranges = <0x0 0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <35 0x8 36 0x8 37 0x8>;
+			interrupt-parent = <&ipic>;
+			phy-handle = < &phy2 >;
+
+			mdio@520 {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,gianfar-tbi";
+				reg = <0x520 0x20>;
+				tbi1: tbi-phy@11 {
+					reg = <0x11>;
+					device_type = "tbi-phy";
+				};
+			};
+		};
+
+		serial0: serial@4500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4500 0x100>;
+			clock-frequency = <133333333>;
+			interrupts = <9 0x8>;
+			interrupt-parent = <&ipic>;
+		};
+
+		serial1: serial@4600 {
+			cell-index = <1>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4600 0x100>;
+			clock-frequency = <133333333>;
+			interrupts = <10 0x8>;
+			interrupt-parent = <&ipic>;
+		};
+
+		gpio@c00 {
+			#gpio-cells = <2>;
+			compatible = "fsl,mpc8308-gpio", "fsl,mpc8349-gpio";
+			reg = <0xc00 0x18>;
+			interrupts = <74 0x8>;
+			interrupt-parent = <&ipic>;
+			gpio-controller;
+		};
+
+		timer@500 {
+			compatible = "fsl,mpc8308-gtm", "fsl,gtm";
+			reg = <0x500 0x100>;
+			interrupts = <90 8 78 8 84 8 72 8>;
+			interrupt-parent = <&ipic>;
+			clock-frequency = <133333333>;
+		};
+
+		/* IPIC
+		 * interrupts cell = <intr #, sense>
+		 * sense values match linux IORESOURCE_IRQ_* defines:
+		 * sense == 8: Level, low assertion
+		 * sense == 2: Edge, high-to-low change
+		 */
+		ipic: interrupt-controller@700 {
+			compatible = "fsl,ipic";
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x700 0x100>;
+			device_type = "ipic";
+		};
+
+		ipic-msi@7c0 {
+			compatible = "fsl,ipic-msi";
+			reg = <0x7c0 0x40>;
+			msi-available-ranges = <0x0 0x100>;
+			interrupts = < 0x43 0x8
+					0x4  0x8
+					0x51 0x8
+					0x52 0x8
+					0x56 0x8
+					0x57 0x8
+					0x58 0x8
+					0x59 0x8 >;
+			interrupt-parent = < &ipic >;
+		};
+
+	};
+
+	pci0: pcie@e0009000 {
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		device_type = "pci";
+		compatible = "fsl,mpc8308-pcie", "fsl,mpc8314-pcie";
+		reg = <0xe0009000 0x00001000
+			0xb0000000 0x01000000>;
+		ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+		          0x01000000 0 0x00000000 0xb1000000 0 0x00800000>;
+		bus-range = <0 0>;
+		interrupt-map-mask = <0 0 0 0>;
+		interrupt-map = <0 0 0 0 &ipic 1 8>;
+		interrupts = <0x1 0x8>;
+		interrupt-parent = <&ipic>;
+		clock-frequency = <0>;
+
+		pcie@0 {
+			#address-cells = <3>;
+			#size-cells = <2>;
+			device_type = "pci";
+			reg = <0 0 0 0 0>;
+			ranges = <0x02000000 0 0xa0000000
+				  0x02000000 0 0xa0000000
+				  0 0x10000000
+				  0x01000000 0 0x00000000
+				  0x01000000 0 0x00000000
+				  0 0x00800000>;
+		};
+	};
+};
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8536ds.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8536ds.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8536ds.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8536ds.dts	2011-01-04 19:50:19.000000000 -0500
@@ -108,6 +108,58 @@
 			};
 		};
 
+		spi@7000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,mpc8536-espi";
+			reg = <0x7000 0x1000>;
+			interrupts = <59 0x2>;
+			interrupt-parent = <&mpic>;
+			fsl,espi-num-chipselects = <4>;
+
+			flash@0 {
+				#address-cells = <1>;
+				#size-cells = <1>;
+				compatible = "spansion,s25sl12801";
+				reg = <0>;
+				spi-max-frequency = <40000000>;
+				partition@u-boot {
+					label = "u-boot";
+					reg = <0x00000000 0x00100000>;
+					read-only;
+				};
+				partition@kernel {
+					label = "kernel";
+					reg = <0x00100000 0x00500000>;
+					read-only;
+				};
+				partition@dtb {
+					label = "dtb";
+					reg = <0x00600000 0x00100000>;
+					read-only;
+				};
+				partition@fs {
+					label = "file system";
+					reg = <0x00700000 0x00900000>;
+				};
+			};
+			flash@1 {
+				compatible = "spansion,s25sl12801";
+				reg = <1>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@2 {
+				compatible = "spansion,s25sl12801";
+				reg = <2>;
+				spi-max-frequency = <40000000>;
+			};
+			flash@3 {
+				compatible = "spansion,s25sl12801";
+				reg = <3>;
+				spi-max-frequency = <40000000>;
+			};
+		};
+
 		dma@21300 {
 			#address-cells = <1>;
 			#size-cells = <1>;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8610_hpcd.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8610_hpcd.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/mpc8610_hpcd.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/mpc8610_hpcd.dts	2011-01-04 19:50:19.000000000 -0500
@@ -286,6 +286,7 @@
 
 		ssi@16100 {
 			compatible = "fsl,mpc8610-ssi";
+			status = "disabled";
 			cell-index = <1>;
 			reg = <0x16100 0x100>;
 			interrupt-parent = <&mpic>;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/p1022ds.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/p1022ds.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/p1022ds.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/p1022ds.dts	2011-01-04 19:50:19.000000000 -0500
@@ -148,6 +148,17 @@
 				label = "reserved-nand";
 			};
 		};
+
+		board-control@3,0 {
+			compatible = "fsl,p1022ds-pixis";
+			reg = <3 0 0x30>;
+			interrupt-parent = <&mpic>;
+			/*
+			 * IRQ8 is generated if the "EVENT" switch is pressed
+			 * and PX_CTL[EVESEL] is set to 00.
+			 */
+			interrupts = <8 8>;
+		};
 	};
 
 	soc@fffe00000 {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/p4080ds.dts linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/p4080ds.dts
--- linux-libre-2.6.36-gnu/arch/powerpc/boot/dts/p4080ds.dts	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/boot/dts/p4080ds.dts	2011-01-04 19:50:19.000000000 -0500
@@ -236,22 +236,19 @@
 		};
 
 		spi@110000 {
-			cell-index = <0>;
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "fsl,espi";
+			compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
 			reg = <0x110000 0x1000>;
 			interrupts = <53 0x2>;
 			interrupt-parent = <&mpic>;
-			espi,num-ss-bits = <4>;
-			mode = "cpu";
+			fsl,espi-num-chipselects = <4>;
 
-			fsl_m25p80@0 {
+			flash@0 {
 				#address-cells = <1>;
 				#size-cells = <1>;
-				compatible = "fsl,espi-flash";
+				compatible = "spansion,s25sl12801";
 				reg = <0>;
-				linux,modalias = "fsl_m25p80";
 				spi-max-frequency = <40000000>; /* input clock */
 				partition@u-boot {
 					label = "u-boot";
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/44x/bluestone_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/44x/bluestone_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/44x/bluestone_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/44x/bluestone_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,68 @@
+CONFIG_44x=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_PCI_QUIRKS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BLUESTONE=y
+# CONFIG_EBONY is not set
+# CONFIG_KVM_GUEST is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=35000
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=256
+CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_IBM_IIC=y
+CONFIG_SENSORS_AD7414=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS=y
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/e55xx_smp_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/e55xx_smp_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/e55xx_smp_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/e55xx_smp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,84 @@
+CONFIG_PPC64=y
+CONFIG_PPC_BOOK3E_64=y
+# CONFIG_VIRT_CPU_ACCOUNTING is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_P5020_DS=y
+# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BINFMT_MISC=m
+CONFIG_SPARSE_IRQ=y
+# CONFIG_PCI is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_EEPROM_LEGACY=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_I2C=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_DMADEVICES=y
+CONFIG_FSL_DMA=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_UTF8=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_LIBCRC32C=m
+CONFIG_FRAME_WARN=1024
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_VIRQ_DEBUG=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TALITOS=y
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/mpc85xx_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/mpc85xx_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/mpc85xx_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/mpc85xx_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -124,6 +124,9 @@
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/mpc85xx_smp_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/mpc85xx_smp_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/mpc85xx_smp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/mpc85xx_smp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -126,6 +126,9 @@
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/ppc44x_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/ppc44x_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/ppc44x_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/ppc44x_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_BAMBOO=y
+CONFIG_BLUESTONE=y
 CONFIG_SAM440EP=y
 CONFIG_SEQUOIA=y
 CONFIG_TAISHAN=y
@@ -97,14 +98,17 @@
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=m
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
 CONFIG_VFAT_FS=m
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_UBIFS_FS=m
 CONFIG_UBIFS_FS_XATTR=y
+CONFIG_LOGFS=m
 CONFIG_CRAMFS=y
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
@@ -116,11 +120,8 @@
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 CONFIG_VIRTUALIZATION=y
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/configs/ppc64e_defconfig linux-libre-2.6.37-gnu/arch/powerpc/configs/ppc64e_defconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/configs/ppc64e_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/configs/ppc64e_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_P5020_DS=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -256,7 +257,6 @@
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
 # CONFIG_USB_EHCI_HCD_PPC_OF is not set
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=m
@@ -290,7 +290,6 @@
 CONFIG_JFS_SECURITY=y
 CONFIG_XFS_FS=m
 CONFIG_XFS_POSIX_ACL=y
-CONFIG_INOTIFY=y
 CONFIG_AUTOFS4_FS=m
 CONFIG_ISO9660_FS=y
 CONFIG_UDF_FS=m
@@ -384,7 +383,6 @@
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_KHAZAD=m
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/checksum.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/checksum.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/checksum.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/checksum.h	2011-01-04 19:50:19.000000000 -0500
@@ -52,12 +52,22 @@
 extern __wsum csum_partial_copy_generic(const void *src, void *dst,
 					      int len, __wsum sum,
 					      int *src_err, int *dst_err);
+
+#ifdef __powerpc64__
+#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
+				      int len, __wsum sum, int *err_ptr);
+#define HAVE_CSUM_COPY_USER
+extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
+				    int len, __wsum sum, int *err_ptr);
+#else
 /*
  * the same as csum_partial, but copies from src to dst while it
  * checksums.
  */
 #define csum_partial_copy_from_user(src, dst, len, sum, errp)   \
         csum_partial_copy_generic((__force const void *)(src), (dst), (len), (sum), (errp), NULL)
+#endif
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)   \
         csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/compat.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/compat.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/compat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/compat.h	2011-01-04 19:50:19.000000000 -0500
@@ -143,7 +143,7 @@
 	 * We cant access below the stack pointer in the 32bit ABI and
 	 * can access 288 bytes in the 64bit ABI
 	 */
-	if (!(test_thread_flag(TIF_32BIT)))
+	if (!is_32bit_task())
 		usp -= 288;
 
 	return (void __user *) (usp - len);
@@ -213,7 +213,7 @@
 
 static inline int is_compat_task(void)
 {
-	return test_thread_flag(TIF_32BIT);
+	return is_32bit_task();
 }
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/cputable.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/cputable.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/cputable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/cputable.h	2011-01-04 19:50:19.000000000 -0500
@@ -198,6 +198,7 @@
 #define CPU_FTR_CP_USE_DCBTZ		LONG_ASM_CONST(0x0040000000000000)
 #define CPU_FTR_UNALIGNED_LD_STD	LONG_ASM_CONST(0x0080000000000000)
 #define CPU_FTR_ASYM_SMT		LONG_ASM_CONST(0x0100000000000000)
+#define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -392,28 +393,31 @@
 	    CPU_FTR_MMCRA | CPU_FTR_CTRL)
 #define CPU_FTRS_POWER4	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
-	    CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
+	    CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ | \
+	    CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_PPC970	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
-	    CPU_FTR_CP_USE_DCBTZ)
+	    CPU_FTR_CP_USE_DCBTZ | CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER5	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
-	    CPU_FTR_PURR)
+	    CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
-	    CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD)
+	    CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \
+	    CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
 	    CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
-	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT)
+	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
+	    CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/cputime.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/cputime.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/cputime.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/cputime.h	2011-01-04 19:50:19.000000000 -0500
@@ -124,23 +124,23 @@
 }
 
 /*
- * Convert cputime <-> milliseconds
+ * Convert cputime <-> microseconds
  */
 extern u64 __cputime_msec_factor;
 
-static inline unsigned long cputime_to_msecs(const cputime_t ct)
+static inline unsigned long cputime_to_usecs(const cputime_t ct)
 {
-	return mulhdu(ct, __cputime_msec_factor);
+	return mulhdu(ct, __cputime_msec_factor) * USEC_PER_MSEC;
 }
 
-static inline cputime_t msecs_to_cputime(const unsigned long ms)
+static inline cputime_t usecs_to_cputime(const unsigned long us)
 {
 	cputime_t ct;
 	unsigned long sec;
 
 	/* have to be a little careful about overflow */
-	ct = ms % 1000;
-	sec = ms / 1000;
+	ct = us % 1000000;
+	sec = us / 1000000;
 	if (ct) {
 		ct *= tb_ticks_per_sec;
 		do_div(ct, 1000);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/dma-mapping.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/dma-mapping.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/dma-mapping.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/dma-mapping.h	2011-01-04 19:50:19.000000000 -0500
@@ -127,19 +127,7 @@
 	return dma_ops->dma_supported(dev, mask);
 }
 
-static inline int dma_set_mask(struct device *dev, u64 dma_mask)
-{
-	struct dma_map_ops *dma_ops = get_dma_ops(dev);
-
-	if (unlikely(dma_ops == NULL))
-		return -EIO;
-	if (dma_ops->set_dma_mask != NULL)
-		return dma_ops->set_dma_mask(dev, dma_mask);
-	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
-		return -EIO;
-	*dev->dma_mask = dma_mask;
-	return 0;
-}
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
 
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
 				       dma_addr_t *dma_handle, gfp_t flag)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/elf.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -250,7 +250,7 @@
  * the 64bit ABI has never had these issues dont enable the workaround
  * even if we have an executable stack.
  */
-# define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \
+# define elf_read_implies_exec(ex, exec_stk) (is_32bit_task() ? \
 		(exec_stk == EXSTACK_DEFAULT) : 0)
 #else 
 # define SET_PERSONALITY(ex) \
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/exception-64s.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/exception-64s.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/exception-64s.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/exception-64s.h	2011-01-04 19:50:19.000000000 -0500
@@ -137,7 +137,8 @@
 	li	r10,0;							   \
 	ld	r11,exception_marker@toc(r2);				   \
 	std	r10,RESULT(r1);		/* clear regs->result		*/ \
-	std	r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame	*/
+	std	r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame	*/ \
+	ACCOUNT_STOLEN_TIME
 
 /*
  * Exception vectors.
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_85xx_cache_sram.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_85xx_cache_sram.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_85xx_cache_sram.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Cache SRAM handling for QorIQ platform
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+#define __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+
+#include <asm/rheap.h>
+#include <linux/spinlock.h>
+
+/*
+ * Cache-SRAM
+ */
+
+struct mpc85xx_cache_sram {
+	phys_addr_t base_phys;
+	void *base_virt;
+	unsigned int size;
+	rh_info_t *rh;
+	spinlock_t lock;
+};
+
+extern void mpc85xx_cache_sram_free(void *ptr);
+extern void *mpc85xx_cache_sram_alloc(unsigned int size,
+				  phys_addr_t *phys, unsigned int align);
+
+#endif /* __AMS_POWERPC_FSL_85XX_CACHE_SRAM_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsldma.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsldma.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsldma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsldma.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,137 +0,0 @@
-/*
- * Freescale MPC83XX / MPC85XX DMA Controller
- *
- * Copyright (c) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __ARCH_POWERPC_ASM_FSLDMA_H__
-#define __ARCH_POWERPC_ASM_FSLDMA_H__
-
-#include <linux/slab.h>
-#include <linux/dmaengine.h>
-
-/*
- * Definitions for the Freescale DMA controller's DMA_SLAVE implemention
- *
- * The Freescale DMA_SLAVE implementation was designed to handle many-to-many
- * transfers. An example usage would be an accelerated copy between two
- * scatterlists. Another example use would be an accelerated copy from
- * multiple non-contiguous device buffers into a single scatterlist.
- *
- * A DMA_SLAVE transaction is defined by a struct fsl_dma_slave. This
- * structure contains a list of hardware addresses that should be copied
- * to/from the scatterlist passed into device_prep_slave_sg(). The structure
- * also has some fields to enable hardware-specific features.
- */
-
-/**
- * struct fsl_dma_hw_addr
- * @entry: linked list entry
- * @address: the hardware address
- * @length: length to transfer
- *
- * Holds a single physical hardware address / length pair for use
- * with the DMAEngine DMA_SLAVE API.
- */
-struct fsl_dma_hw_addr {
-	struct list_head entry;
-
-	dma_addr_t address;
-	size_t length;
-};
-
-/**
- * struct fsl_dma_slave
- * @addresses: a linked list of struct fsl_dma_hw_addr structures
- * @request_count: value for DMA request count
- * @src_loop_size: setup and enable constant source-address DMA transfers
- * @dst_loop_size: setup and enable constant destination address DMA transfers
- * @external_start: enable externally started DMA transfers
- * @external_pause: enable externally paused DMA transfers
- *
- * Holds a list of address / length pairs for use with the DMAEngine
- * DMA_SLAVE API implementation for the Freescale DMA controller.
- */
-struct fsl_dma_slave {
-
-	/* List of hardware address/length pairs */
-	struct list_head addresses;
-
-	/* Support for extra controller features */
-	unsigned int request_count;
-	unsigned int src_loop_size;
-	unsigned int dst_loop_size;
-	bool external_start;
-	bool external_pause;
-};
-
-/**
- * fsl_dma_slave_append - add an address/length pair to a struct fsl_dma_slave
- * @slave: the &struct fsl_dma_slave to add to
- * @address: the hardware address to add
- * @length: the length of bytes to transfer from @address
- *
- * Add a hardware address/length pair to a struct fsl_dma_slave. Returns 0 on
- * success, -ERRNO otherwise.
- */
-static inline int fsl_dma_slave_append(struct fsl_dma_slave *slave,
-				       dma_addr_t address, size_t length)
-{
-	struct fsl_dma_hw_addr *addr;
-
-	addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
-	if (!addr)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&addr->entry);
-	addr->address = address;
-	addr->length = length;
-
-	list_add_tail(&addr->entry, &slave->addresses);
-	return 0;
-}
-
-/**
- * fsl_dma_slave_free - free a struct fsl_dma_slave
- * @slave: the struct fsl_dma_slave to free
- *
- * Free a struct fsl_dma_slave and all associated address/length pairs
- */
-static inline void fsl_dma_slave_free(struct fsl_dma_slave *slave)
-{
-	struct fsl_dma_hw_addr *addr, *tmp;
-
-	if (slave) {
-		list_for_each_entry_safe(addr, tmp, &slave->addresses, entry) {
-			list_del(&addr->entry);
-			kfree(addr);
-		}
-
-		kfree(slave);
-	}
-}
-
-/**
- * fsl_dma_slave_alloc - allocate a struct fsl_dma_slave
- * @gfp: the flags to pass to kmalloc when allocating this structure
- *
- * Allocate a struct fsl_dma_slave for use by the DMA_SLAVE API. Returns a new
- * struct fsl_dma_slave on success, or NULL on failure.
- */
-static inline struct fsl_dma_slave *fsl_dma_slave_alloc(gfp_t gfp)
-{
-	struct fsl_dma_slave *slave;
-
-	slave = kzalloc(sizeof(*slave), gfp);
-	if (!slave)
-		return NULL;
-
-	INIT_LIST_HEAD(&slave->addresses);
-	return slave;
-}
-
-#endif /* __ARCH_POWERPC_ASM_FSLDMA_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_guts.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_guts.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_guts.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_guts.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,197 @@
+/**
+ * Freecale 85xx and 86xx Global Utilties register set
+ *
+ * Authors: Jeff Brown
+ *          Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2004,2007 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
+#ifdef __KERNEL__
+
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names.  In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
+	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
+	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
+	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
+	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
+	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
+	__be32	pordevsr2;	/* 0x.0014 - POR device status register 2 */
+	u8	res018[0x20 - 0x18];
+	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
+	u8	res024[0x30 - 0x24];
+	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
+	u8	res034[0x40 - 0x34];
+	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
+	u8	res044[0x50 - 0x44];
+	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
+	u8	res054[0x60 - 0x54];
+	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
+        __be32  pmuxcr2;	/* 0x.0064 - Alternate function signal multiplex control 2 */
+        __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
+        u8	res06c[0x70 - 0x6c];
+	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
+	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
+	u8	res078[0x7c - 0x78];
+	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
+	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
+	__be32  pmrccr;		/* 0x.0084 - Power Management Reset Counter Configuration Register */
+	__be32  pmpdccr;	/* 0x.0088 - Power Management Power Down Counter Configuration Register */
+	__be32  pmcdr;		/* 0x.008c - 4Power management clock disable register */
+	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
+	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
+	__be32  ectrstcr;	/* 0x.0098 - Exception reset control register */
+	__be32  autorstsr;	/* 0x.009c - Automatic reset status register */
+	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
+	__be32	svr;		/* 0x.00a4 - System Version Register */
+	u8	res0a8[0xb0 - 0xa8];
+	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
+	u8	res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register */
+#else
+	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
+#endif
+	u8	res0c4[0x224 - 0xc4];
+	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
+	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
+	u8	res22c[0x800 - 0x22c];
+	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
+	u8	res804[0x900 - 0x804];
+	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
+	u8	res904[0x908 - 0x904];
+	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
+	u8	res90c[0x914 - 0x90c];
+	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
+	u8	res918[0xb20 - 0x918];
+	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
+	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
+	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
+	u8	resb2c[0xe00 - 0xb2c];
+	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
+	u8	rese04[0xe10 - 0xe04];
+	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
+	u8	rese14[0xe20 - 0xe14];
+	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
+	__be32  cpfor;		/* 0x.0e24 - L2 charge pump fuse override register */
+	u8	rese28[0xf04 - 0xe28];
+	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
+	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
+	u8	resf0c[0xf2c - 0xf0c];
+	__be32  itcr;		/* 0x.0f2c - Internal transaction control register */
+	u8	resf30[0xf40 - 0xf30];
+	__be32	srds2cr0;	/* 0x.0f40 - SerDes2 Control Register 0 */
+	__be32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
+} __attribute__ ((packed));
+
+#ifdef CONFIG_PPC_86xx
+
+#define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
+#define CCSR_GUTS_DMACR_DEV_IR	1	/* DMA controller/channel set to IR */
+
+/*
+ * Set the DMACR register in the GUTS
+ *
+ * The DMACR register determines the source of initiated transfers for each
+ * channel on each DMA controller.  Rather than have a bunch of repetitive
+ * macros for the bit patterns, we just have a function that calculates
+ * them.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
+ */
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
+	unsigned int co, unsigned int ch, unsigned int device)
+{
+	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
+
+	clrsetbits_be32(&guts->dmacr, 3 << shift, device << shift);
+}
+
+#define CCSR_GUTS_PMUXCR_LDPSEL		0x00010000
+#define CCSR_GUTS_PMUXCR_SSI1_MASK	0x0000C000	/* Bitmask for SSI1 */
+#define CCSR_GUTS_PMUXCR_SSI1_LA	0x00000000	/* Latched address */
+#define CCSR_GUTS_PMUXCR_SSI1_HI	0x00004000	/* High impedance */
+#define CCSR_GUTS_PMUXCR_SSI1_SSI	0x00008000	/* Used for SSI1 */
+#define CCSR_GUTS_PMUXCR_SSI2_MASK	0x00003000	/* Bitmask for SSI2 */
+#define CCSR_GUTS_PMUXCR_SSI2_LA	0x00000000	/* Latched address */
+#define CCSR_GUTS_PMUXCR_SSI2_HI	0x00001000	/* High impedance */
+#define CCSR_GUTS_PMUXCR_SSI2_SSI	0x00002000	/* Used for SSI2 */
+#define CCSR_GUTS_PMUXCR_LA_22_25_LA	0x00000000	/* Latched Address */
+#define CCSR_GUTS_PMUXCR_LA_22_25_HI	0x00000400	/* High impedance */
+#define CCSR_GUTS_PMUXCR_DBGDRV		0x00000200	/* Signals not driven */
+#define CCSR_GUTS_PMUXCR_DMA2_0		0x00000008
+#define CCSR_GUTS_PMUXCR_DMA2_3		0x00000004
+#define CCSR_GUTS_PMUXCR_DMA1_0		0x00000002
+#define CCSR_GUTS_PMUXCR_DMA1_3		0x00000001
+
+/*
+ * Set the DMA external control bits in the GUTS
+ *
+ * The DMA external control bits in the PMUXCR are only meaningful for
+ * channels 0 and 3.  Any other channels are ignored.
+ *
+ * guts: Pointer to GUTS structure
+ * co: The DMA controller (0 or 1)
+ * ch: The channel on the DMA controller (0, 1, 2, or 3)
+ * value: the new value for the bit (0 or 1)
+ */
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
+	unsigned int co, unsigned int ch, unsigned int value)
+{
+	if ((ch == 0) || (ch == 3)) {
+		unsigned int shift = 2 * (co + 1) - (ch & 1) - 1;
+
+		clrsetbits_be32(&guts->pmuxcr, 1 << shift, value << shift);
+	}
+}
+
+#define CCSR_GUTS_CLKDVDR_PXCKEN	0x80000000
+#define CCSR_GUTS_CLKDVDR_SSICKEN	0x20000000
+#define CCSR_GUTS_CLKDVDR_PXCKINV	0x10000000
+#define CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT 25
+#define CCSR_GUTS_CLKDVDR_PXCKDLY_MASK	0x06000000
+#define CCSR_GUTS_CLKDVDR_PXCKDLY(x) \
+	(((x) & 3) << CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT)
+#define CCSR_GUTS_CLKDVDR_PXCLK_SHIFT	16
+#define CCSR_GUTS_CLKDVDR_PXCLK_MASK	0x001F0000
+#define CCSR_GUTS_CLKDVDR_PXCLK(x) (((x) & 31) << CCSR_GUTS_CLKDVDR_PXCLK_SHIFT)
+#define CCSR_GUTS_CLKDVDR_SSICLK_MASK	0x000000FF
+#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
+
+#endif
+
+#endif
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_lbc.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_lbc.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/fsl_lbc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/fsl_lbc.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,9 +1,10 @@
 /* Freescale Local Bus Controller
  *
- * Copyright (c) 2006-2007 Freescale Semiconductor
+ * Copyright Â© 2006-2007, 2010 Freescale Semiconductor
  *
  * Authors: Nick Spence <nick.spence@freescale.com>,
  *          Scott Wood <scottwood@freescale.com>
+ *          Jack Lan <jack.lan@freescale.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,6 +27,8 @@
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
 
 struct fsl_lbc_bank {
 	__be32 br;             /**< Base Register  */
@@ -125,13 +128,23 @@
 #define LTESR_ATMW 0x00800000
 #define LTESR_ATMR 0x00400000
 #define LTESR_CS   0x00080000
+#define LTESR_UPM  0x00000002
 #define LTESR_CC   0x00000001
 #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC)
+#define LTESR_MASK      (LTESR_BM | LTESR_FCT | LTESR_PAR | LTESR_WP \
+			 | LTESR_ATMW | LTESR_ATMR | LTESR_CS | LTESR_UPM \
+			 | LTESR_CC)
+#define LTESR_CLEAR	0xFFFFFFFF
+#define LTECCR_CLEAR	0xFFFFFFFF
+#define LTESR_STATUS	LTESR_MASK
+#define LTEIR_ENABLE	LTESR_MASK
+#define LTEDR_ENABLE	0x00000000
 	__be32 ltedr;           /**< Transfer Error Disable Register */
 	__be32 lteir;           /**< Transfer Error Interrupt Register */
 	__be32 lteatr;          /**< Transfer Error Attributes Register */
 	__be32 ltear;           /**< Transfer Error Address Register */
-	u8 res6[0xC];
+	__be32 lteccr;          /**< Transfer Error ECC Register */
+	u8 res6[0x8];
 	__be32 lbcr;            /**< Configuration Register */
 #define LBCR_LDIS  0x80000000
 #define LBCR_LDIS_SHIFT    31
@@ -235,6 +248,7 @@
 	int width;
 };
 
+extern u32 fsl_lbc_addr(phys_addr_t addr_base);
 extern int fsl_lbc_find(phys_addr_t addr_base);
 extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm);
 
@@ -265,7 +279,23 @@
 		cpu_relax();
 }
 
+/* overview of the fsl lbc controller */
+
+struct fsl_lbc_ctrl {
+	/* device info */
+	struct device			*dev;
+	struct fsl_lbc_regs __iomem	*regs;
+	int				irq;
+	wait_queue_head_t		irq_wait;
+	spinlock_t			lock;
+	void				*nand;
+
+	/* status read from LTESR by irq handler */
+	unsigned int			irq_status;
+};
+
 extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
 			       u32 mar);
+extern struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
 
 #endif /* __ASM_FSL_LBC_H */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -60,9 +60,8 @@
 
 extern void *kmap_high(struct page *page);
 extern void kunmap_high(struct page *page);
-extern void *kmap_atomic_prot(struct page *page, enum km_type type,
-			      pgprot_t prot);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+extern void __kunmap_atomic(void *kvaddr);
 
 static inline void *kmap(struct page *page)
 {
@@ -80,9 +79,9 @@
 	kunmap_high(page);
 }
 
-static inline void *kmap_atomic(struct page *page, enum km_type type)
+static inline void *__kmap_atomic(struct page *page)
 {
-	return kmap_atomic_prot(page, type, kmap_prot);
+	return kmap_atomic_prot(page, kmap_prot);
 }
 
 static inline struct page *kmap_atomic_to_page(void *ptr)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/hw_irq.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/hw_irq.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/hw_irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/hw_irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,42 +16,57 @@
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 
-static inline unsigned long local_get_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
 	unsigned long flags;
 
-	__asm__ __volatile__("lbz %0,%1(13)"
-	: "=r" (flags)
-	: "i" (offsetof(struct paca_struct, soft_enabled)));
+	asm volatile(
+		"lbz %0,%1(13)"
+		: "=r" (flags)
+		: "i" (offsetof(struct paca_struct, soft_enabled)));
 
 	return flags;
 }
 
-static inline unsigned long raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_disable(void)
 {
 	unsigned long flags, zero;
 
-	__asm__ __volatile__("li %1,0; lbz %0,%2(13); stb %1,%2(13)"
-	: "=r" (flags), "=&r" (zero)
-	: "i" (offsetof(struct paca_struct, soft_enabled))
-	: "memory");
+	asm volatile(
+		"li %1,0; lbz %0,%2(13); stb %1,%2(13)"
+		: "=r" (flags), "=&r" (zero)
+		: "i" (offsetof(struct paca_struct, soft_enabled))
+		: "memory");
 
 	return flags;
 }
 
-extern void raw_local_irq_restore(unsigned long);
+extern void arch_local_irq_restore(unsigned long);
 extern void iseries_handle_interrupts(void);
 
-#define raw_local_irq_enable()		raw_local_irq_restore(1)
-#define raw_local_save_flags(flags)	((flags) = local_get_flags())
-#define raw_local_irq_save(flags)	((flags) = raw_local_irq_disable())
+static inline void arch_local_irq_enable(void)
+{
+	arch_local_irq_restore(1);
+}
 
-#define raw_irqs_disabled()		(local_get_flags() == 0)
-#define raw_irqs_disabled_flags(flags)	((flags) == 0)
+static inline unsigned long arch_local_irq_save(void)
+{
+	return arch_local_irq_disable();
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return flags == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #ifdef CONFIG_PPC_BOOK3E
-#define __hard_irq_enable()	__asm__ __volatile__("wrteei 1": : :"memory");
-#define __hard_irq_disable()	__asm__ __volatile__("wrteei 0": : :"memory");
+#define __hard_irq_enable()	asm volatile("wrteei 1" : : : "memory");
+#define __hard_irq_disable()	asm volatile("wrteei 0" : : : "memory");
 #else
 #define __hard_irq_enable()	__mtmsrd(mfmsr() | MSR_EE, 1)
 #define __hard_irq_disable()	__mtmsrd(mfmsr() & ~MSR_EE, 1)
@@ -64,64 +79,66 @@
 		get_paca()->hard_enabled = 0;	\
 	} while(0)
 
-#else
+#else /* CONFIG_PPC64 */
 
-#if defined(CONFIG_BOOKE)
 #define SET_MSR_EE(x)	mtmsr(x)
-#define raw_local_irq_restore(flags)	__asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	return mfmsr();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+#if defined(CONFIG_BOOKE)
+	asm volatile("wrtee %0" : : "r" (flags) : "memory");
 #else
-#define SET_MSR_EE(x)	mtmsr(x)
-#define raw_local_irq_restore(flags)	mtmsr(flags)
+	mtmsr(flags);
 #endif
+}
 
-static inline void raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_save(void)
 {
+	unsigned long flags = arch_local_save_flags();
 #ifdef CONFIG_BOOKE
-	__asm__ __volatile__("wrteei 0": : :"memory");
+	asm volatile("wrteei 0" : : : "memory");
 #else
-	unsigned long msr;
-
-	msr = mfmsr();
-	SET_MSR_EE(msr & ~MSR_EE);
+	SET_MSR_EE(flags & ~MSR_EE);
 #endif
+	return flags;
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_disable(void)
 {
 #ifdef CONFIG_BOOKE
-	__asm__ __volatile__("wrteei 1": : :"memory");
+	asm volatile("wrteei 0" : : : "memory");
 #else
-	unsigned long msr;
-
-	msr = mfmsr();
-	SET_MSR_EE(msr | MSR_EE);
+	arch_local_irq_save();
 #endif
 }
 
-static inline void raw_local_irq_save_ptr(unsigned long *flags)
+static inline void arch_local_irq_enable(void)
 {
-	unsigned long msr;
-	msr = mfmsr();
-	*flags = msr;
 #ifdef CONFIG_BOOKE
-	__asm__ __volatile__("wrteei 0": : :"memory");
+	asm volatile("wrteei 1" : : : "memory");
 #else
-	SET_MSR_EE(msr & ~MSR_EE);
+	unsigned long msr = mfmsr();
+	SET_MSR_EE(msr | MSR_EE);
 #endif
 }
 
-#define raw_local_save_flags(flags)	((flags) = mfmsr())
-#define raw_local_irq_save(flags)	raw_local_irq_save_ptr(&flags)
-#define raw_irqs_disabled()		((mfmsr() & MSR_EE) == 0)
-#define raw_irqs_disabled_flags(flags)	(((flags) & MSR_EE) == 0)
-
-#define hard_irq_disable()		raw_local_irq_disable()
-
-static inline int irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
 	return (flags & MSR_EE) == 0;
 }
 
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#define hard_irq_disable()		arch_local_irq_disable()
+
 #endif /* CONFIG_PPC64 */
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/hydra.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/hydra.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/hydra.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/hydra.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,7 @@
  *
  *	Â© Copyright 1995 Apple Computer, Inc. All rights reserved.
  *
- *  It's available online from http://chrp.apple.com/MacTech.pdf.
+ *  It's available online from http://www.cpu.lu/~mlan/ftp/MacTech.pdf
  *  You can obtain paper copies of this book from computer bookstores or by
  *  writing Morgan Kaufmann Publishers, Inc., 340 Pine Street, Sixth Floor, San
  *  Francisco, CA 94104. Reference ISBN 1-55860-393-X.
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/immap_86xx.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/immap_86xx.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/immap_86xx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/immap_86xx.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,156 +0,0 @@
-/**
- * MPC86xx Internal Memory Map
- *
- * Authors: Jeff Brown
- *          Timur Tabi <timur@freescale.com>
- *
- * Copyright 2004,2007 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- * This header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
- */
-
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
-#ifdef __KERNEL__
-
-/* Global Utility Registers */
-struct ccsr_guts {
-	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
-	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
-	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
-	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
-	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
-	u8	res1[0x20 - 0x14];
-	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
-	u8	res2[0x30 - 0x24];
-	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
-	u8	res3[0x40 - 0x34];
-	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
-	u8	res4[0x50 - 0x44];
-	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
-	u8	res5[0x60 - 0x54];
-	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
-	u8	res6[0x70 - 0x64];
-	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
-	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
-	u8	res7[0x80 - 0x78];
-	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
-	u8	res8[0x90 - 0x84];
-	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
-	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
-	u8	res9[0xA0 - 0x98];
-	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
-	__be32	svr;		/* 0x.00a4 - System Version Register */
-	u8	res10[0xB0 - 0xA8];
-	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
-	u8	res11[0xC0 - 0xB4];
-	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-	u8	res12[0x800 - 0xC4];
-	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
-	u8	res13[0x900 - 0x804];
-	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
-	u8	res14[0x908 - 0x904];
-	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
-	u8	res15[0x914 - 0x90C];
-	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
-	u8	res16[0xB20 - 0x918];
-	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
-	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
-	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
-	u8	res17[0xE00 - 0xB2C];
-	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
-	u8	res18[0xE10 - 0xE04];
-	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
-	u8	res19[0xE20 - 0xE14];
-	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
-	u8	res20[0xF04 - 0xE24];
-	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
-	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
-	u8	res21[0xF40 - 0xF0C];
-	__be32	srds2cr0;	/* 0x.0f40 - SerDes1 Control Register 0 */
-	__be32	srds2cr1;	/* 0x.0f44 - SerDes1 Control Register 0 */
-} __attribute__ ((packed));
-
-#define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
-#define CCSR_GUTS_DMACR_DEV_IR	1	/* DMA controller/channel set to IR */
-
-/*
- * Set the DMACR register in the GUTS
- *
- * The DMACR register determines the source of initiated transfers for each
- * channel on each DMA controller.  Rather than have a bunch of repetitive
- * macros for the bit patterns, we just have a function that calculates
- * them.
- *
- * guts: Pointer to GUTS structure
- * co: The DMA controller (0 or 1)
- * ch: The channel on the DMA controller (0, 1, 2, or 3)
- * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
- */
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
-	unsigned int co, unsigned int ch, unsigned int device)
-{
-	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
-
-	clrsetbits_be32(&guts->dmacr, 3 << shift, device << shift);
-}
-
-#define CCSR_GUTS_PMUXCR_LDPSEL		0x00010000
-#define CCSR_GUTS_PMUXCR_SSI1_MASK	0x0000C000	/* Bitmask for SSI1 */
-#define CCSR_GUTS_PMUXCR_SSI1_LA	0x00000000	/* Latched address */
-#define CCSR_GUTS_PMUXCR_SSI1_HI	0x00004000	/* High impedance */
-#define CCSR_GUTS_PMUXCR_SSI1_SSI	0x00008000	/* Used for SSI1 */
-#define CCSR_GUTS_PMUXCR_SSI2_MASK	0x00003000	/* Bitmask for SSI2 */
-#define CCSR_GUTS_PMUXCR_SSI2_LA	0x00000000	/* Latched address */
-#define CCSR_GUTS_PMUXCR_SSI2_HI	0x00001000	/* High impedance */
-#define CCSR_GUTS_PMUXCR_SSI2_SSI	0x00002000	/* Used for SSI2 */
-#define CCSR_GUTS_PMUXCR_LA_22_25_LA	0x00000000	/* Latched Address */
-#define CCSR_GUTS_PMUXCR_LA_22_25_HI	0x00000400	/* High impedance */
-#define CCSR_GUTS_PMUXCR_DBGDRV		0x00000200	/* Signals not driven */
-#define CCSR_GUTS_PMUXCR_DMA2_0		0x00000008
-#define CCSR_GUTS_PMUXCR_DMA2_3		0x00000004
-#define CCSR_GUTS_PMUXCR_DMA1_0		0x00000002
-#define CCSR_GUTS_PMUXCR_DMA1_3		0x00000001
-
-/*
- * Set the DMA external control bits in the GUTS
- *
- * The DMA external control bits in the PMUXCR are only meaningful for
- * channels 0 and 3.  Any other channels are ignored.
- *
- * guts: Pointer to GUTS structure
- * co: The DMA controller (0 or 1)
- * ch: The channel on the DMA controller (0, 1, 2, or 3)
- * value: the new value for the bit (0 or 1)
- */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
-	unsigned int co, unsigned int ch, unsigned int value)
-{
-	if ((ch == 0) || (ch == 3)) {
-		unsigned int shift = 2 * (co + 1) - (ch & 1) - 1;
-
-		clrsetbits_be32(&guts->pmuxcr, 1 << shift, value << shift);
-	}
-}
-
-#define CCSR_GUTS_CLKDVDR_PXCKEN	0x80000000
-#define CCSR_GUTS_CLKDVDR_SSICKEN	0x20000000
-#define CCSR_GUTS_CLKDVDR_PXCKINV	0x10000000
-#define CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT 25
-#define CCSR_GUTS_CLKDVDR_PXCKDLY_MASK	0x06000000
-#define CCSR_GUTS_CLKDVDR_PXCKDLY(x) \
-	(((x) & 3) << CCSR_GUTS_CLKDVDR_PXCKDLY_SHIFT)
-#define CCSR_GUTS_CLKDVDR_PXCLK_SHIFT	16
-#define CCSR_GUTS_CLKDVDR_PXCLK_MASK	0x001F0000
-#define CCSR_GUTS_CLKDVDR_PXCLK(x) (((x) & 31) << CCSR_GUTS_CLKDVDR_PXCLK_SHIFT)
-#define CCSR_GUTS_CLKDVDR_SSICLK_MASK	0x000000FF
-#define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
-
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,7 @@
 
 #ifndef __ASSEMBLY__
 /*
- * Get definitions for raw_local_save_flags(x), etc.
+ * Get definitions for arch_local_save_flags(x), etc.
  */
 #include <asm/hw_irq.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kexec.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kexec.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kexec.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kexec.h	2011-01-04 19:50:19.000000000 -0500
@@ -91,6 +91,7 @@
 extern void crash_kexec_secondary(struct pt_regs *regs);
 extern int overlaps_crashkernel(unsigned long start, unsigned long size);
 extern void reserve_crashkernel(void);
+extern void machine_kexec_mask_interrupts(void);
 
 #else /* !CONFIG_KEXEC */
 static inline int kexec_sr_activated(int cpu) { return 0; }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kgdb.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kgdb.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kgdb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kgdb.h	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 	asm(".long 0x7d821008"); /* twge r2, r2 */
 }
 #define CACHE_FLUSH_IS_SAFE	1
+#define DBG_MAX_REG_NUM     70
 
 /* The number bytes of registers we have to save depends on a few
  * things.  For 64bit we default to not including vector registers and
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_asm.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_asm.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_asm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_asm.h	2011-01-04 19:50:19.000000000 -0500
@@ -58,6 +58,7 @@
 #define BOOK3S_INTERRUPT_INST_STORAGE	0x400
 #define BOOK3S_INTERRUPT_INST_SEGMENT	0x480
 #define BOOK3S_INTERRUPT_EXTERNAL	0x500
+#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL	0x501
 #define BOOK3S_INTERRUPT_ALIGNMENT	0x600
 #define BOOK3S_INTERRUPT_PROGRAM	0x700
 #define BOOK3S_INTERRUPT_FP_UNAVAIL	0x800
@@ -84,7 +85,8 @@
 #define BOOK3S_IRQPRIO_EXTERNAL			13
 #define BOOK3S_IRQPRIO_DECREMENTER		14
 #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR	15
-#define BOOK3S_IRQPRIO_MAX			16
+#define BOOK3S_IRQPRIO_EXTERNAL_LEVEL		16
+#define BOOK3S_IRQPRIO_MAX			17
 
 #define BOOK3S_HFLAG_DCBZ32			0x1
 #define BOOK3S_HFLAG_SLB			0x2
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_book3s.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_book3s.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_book3s.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_book3s.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,15 +38,6 @@
 	bool class	: 1;
 };
 
-struct kvmppc_sr {
-	u32 raw;
-	u32 vsid;
-	bool Ks		: 1;
-	bool Kp		: 1;
-	bool nx		: 1;
-	bool valid	: 1;
-};
-
 struct kvmppc_bat {
 	u64 raw;
 	u32 bepi;
@@ -69,6 +60,13 @@
 #define SID_MAP_NUM     (1 << SID_MAP_BITS)
 #define SID_MAP_MASK    (SID_MAP_NUM - 1)
 
+#ifdef CONFIG_PPC_BOOK3S_64
+#define SID_CONTEXTS	1
+#else
+#define SID_CONTEXTS	128
+#define VSID_POOL_SIZE	(SID_CONTEXTS * 16)
+#endif
+
 struct kvmppc_vcpu_book3s {
 	struct kvm_vcpu vcpu;
 	struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
@@ -79,20 +77,22 @@
 		u64 vsid;
 	} slb_shadow[64];
 	u8 slb_shadow_max;
-	struct kvmppc_sr sr[16];
 	struct kvmppc_bat ibat[8];
 	struct kvmppc_bat dbat[8];
 	u64 hid[6];
 	u64 gqr[8];
 	int slb_nr;
-	u32 dsisr;
 	u64 sdr1;
 	u64 hior;
 	u64 msr_mask;
-	u64 vsid_first;
 	u64 vsid_next;
+#ifdef CONFIG_PPC_BOOK3S_32
+	u32 vsid_pool[VSID_POOL_SIZE];
+#else
+	u64 vsid_first;
 	u64 vsid_max;
-	int context_id;
+#endif
+	int context_id[SID_CONTEXTS];
 	ulong prog_flags; /* flags to inject when giving a 700 trap */
 };
 
@@ -131,9 +131,10 @@
 			   bool upper, u32 val);
 extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
 extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
+extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 
-extern u32 kvmppc_trampoline_lowmem;
-extern u32 kvmppc_trampoline_enter;
+extern ulong kvmppc_trampoline_lowmem;
+extern ulong kvmppc_trampoline_enter;
 extern void kvmppc_rmcall(ulong srr0, ulong srr1);
 extern void kvmppc_load_up_fpu(void);
 extern void kvmppc_load_up_altivec(void);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_fpu.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_fpu.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_fpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_fpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -82,7 +82,7 @@
 FPD_THREE_IN(fnmsub)
 FPD_THREE_IN(fnmadd)
 
-extern void kvm_cvt_fd(u32 *from, u64 *to, u64 *fpscr);
-extern void kvm_cvt_df(u64 *from, u32 *to, u64 *fpscr);
+extern void kvm_cvt_fd(u32 *from, u64 *to);
+extern void kvm_cvt_df(u64 *from, u32 *to);
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm.h	2011-01-04 19:50:19.000000000 -0500
@@ -86,5 +86,6 @@
 
 #define KVM_INTERRUPT_SET	-1U
 #define KVM_INTERRUPT_UNSET	-2U
+#define KVM_INTERRUPT_SET_LEVEL	-3U
 
 #endif /* __LINUX_KVM_POWERPC_H */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_host.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_host.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_host.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_host.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/kvm_types.h>
+#include <linux/kvm_para.h>
 #include <asm/kvm_asm.h>
 
 #define KVM_MAX_VCPUS 1
@@ -41,12 +42,17 @@
 
 #define HPTEG_CACHE_NUM			(1 << 15)
 #define HPTEG_HASH_BITS_PTE		13
+#define HPTEG_HASH_BITS_PTE_LONG	12
 #define HPTEG_HASH_BITS_VPTE		13
 #define HPTEG_HASH_BITS_VPTE_LONG	5
 #define HPTEG_HASH_NUM_PTE		(1 << HPTEG_HASH_BITS_PTE)
+#define HPTEG_HASH_NUM_PTE_LONG		(1 << HPTEG_HASH_BITS_PTE_LONG)
 #define HPTEG_HASH_NUM_VPTE		(1 << HPTEG_HASH_BITS_VPTE)
 #define HPTEG_HASH_NUM_VPTE_LONG	(1 << HPTEG_HASH_BITS_VPTE_LONG)
 
+/* Physical Address Mask - allowed range of real mode RAM access */
+#define KVM_PAM			0x0fffffffffffffffULL
+
 struct kvm;
 struct kvm_run;
 struct kvm_vcpu;
@@ -159,8 +165,10 @@
 
 struct hpte_cache {
 	struct hlist_node list_pte;
+	struct hlist_node list_pte_long;
 	struct hlist_node list_vpte;
 	struct hlist_node list_vpte_long;
+	struct rcu_head rcu_head;
 	u64 host_va;
 	u64 pfn;
 	ulong slot;
@@ -210,28 +218,20 @@
 	u32 cr;
 #endif
 
-	ulong msr;
 #ifdef CONFIG_PPC_BOOK3S
 	ulong shadow_msr;
 	ulong hflags;
 	ulong guest_owned_ext;
 #endif
 	u32 mmucr;
-	ulong sprg0;
-	ulong sprg1;
-	ulong sprg2;
-	ulong sprg3;
 	ulong sprg4;
 	ulong sprg5;
 	ulong sprg6;
 	ulong sprg7;
-	ulong srr0;
-	ulong srr1;
 	ulong csrr0;
 	ulong csrr1;
 	ulong dsrr0;
 	ulong dsrr1;
-	ulong dear;
 	ulong esr;
 	u32 dec;
 	u32 decar;
@@ -290,12 +290,17 @@
 	struct tasklet_struct tasklet;
 	u64 dec_jiffies;
 	unsigned long pending_exceptions;
+	struct kvm_vcpu_arch_shared *shared;
+	unsigned long magic_page_pa; /* phys addr to map the magic page to */
+	unsigned long magic_page_ea; /* effect. addr to map the magic page to */
 
 #ifdef CONFIG_PPC_BOOK3S
 	struct hlist_head hpte_hash_pte[HPTEG_HASH_NUM_PTE];
+	struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
 	struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
 	struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
 	int hpte_cache_count;
+	spinlock_t mmu_lock;
 #endif
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_para.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_para.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_para.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_para.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,16 +20,153 @@
 #ifndef __POWERPC_KVM_PARA_H__
 #define __POWERPC_KVM_PARA_H__
 
+#include <linux/types.h>
+
+struct kvm_vcpu_arch_shared {
+	__u64 scratch1;
+	__u64 scratch2;
+	__u64 scratch3;
+	__u64 critical;		/* Guest may not get interrupts if == r1 */
+	__u64 sprg0;
+	__u64 sprg1;
+	__u64 sprg2;
+	__u64 sprg3;
+	__u64 srr0;
+	__u64 srr1;
+	__u64 dar;
+	__u64 msr;
+	__u32 dsisr;
+	__u32 int_pending;	/* Tells the guest if we have an interrupt */
+	__u32 sr[16];
+};
+
+#define KVM_SC_MAGIC_R0		0x4b564d21 /* "KVM!" */
+#define HC_VENDOR_KVM		(42 << 16)
+#define HC_EV_SUCCESS		0
+#define HC_EV_UNIMPLEMENTED	12
+
+#define KVM_FEATURE_MAGIC_PAGE	1
+
+#define KVM_MAGIC_FEAT_SR	(1 << 0)
+
 #ifdef __KERNEL__
 
+#ifdef CONFIG_KVM_GUEST
+
+#include <linux/of.h>
+
+static inline int kvm_para_available(void)
+{
+	struct device_node *hyper_node;
+
+	hyper_node = of_find_node_by_path("/hypervisor");
+	if (!hyper_node)
+		return 0;
+
+	if (!of_device_is_compatible(hyper_node, "linux,kvm"))
+		return 0;
+
+	return 1;
+}
+
+extern unsigned long kvm_hypercall(unsigned long *in,
+				   unsigned long *out,
+				   unsigned long nr);
+
+#else
+
 static inline int kvm_para_available(void)
 {
 	return 0;
 }
 
+static unsigned long kvm_hypercall(unsigned long *in,
+				   unsigned long *out,
+				   unsigned long nr)
+{
+	return HC_EV_UNIMPLEMENTED;
+}
+
+#endif
+
+static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+	unsigned long r;
+
+	r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+	*r2 = out[0];
+
+	return r;
+}
+
+static inline long kvm_hypercall0(unsigned int nr)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+
+	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+
+	in[0] = p1;
+	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
+				  unsigned long p2)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+
+	in[0] = p1;
+	in[1] = p2;
+	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
+				  unsigned long p2, unsigned long p3)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+
+	in[0] = p1;
+	in[1] = p2;
+	in[2] = p3;
+	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
+				  unsigned long p2, unsigned long p3,
+				  unsigned long p4)
+{
+	unsigned long in[8];
+	unsigned long out[8];
+
+	in[0] = p1;
+	in[1] = p2;
+	in[2] = p3;
+	in[3] = p4;
+	return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+}
+
+
 static inline unsigned int kvm_arch_para_features(void)
 {
-	return 0;
+	unsigned long r;
+
+	if (!kvm_para_available())
+		return 0;
+
+	if(kvm_hypercall0_1(KVM_HC_FEATURES, &r))
+		return 0;
+
+	return r;
 }
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_ppc.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_ppc.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/kvm_ppc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/kvm_ppc.h	2011-01-04 19:50:19.000000000 -0500
@@ -107,6 +107,7 @@
 extern void kvmppc_booke_exit(void);
 
 extern void kvmppc_core_destroy_mmu(struct kvm_vcpu *vcpu);
+extern int kvmppc_kvm_pv(struct kvm_vcpu *vcpu);
 
 /*
  * Cuts out inst bits with ordering according to spec.
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/lppaca.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/lppaca.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/lppaca.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/lppaca.h	2011-01-04 19:50:19.000000000 -0500
@@ -153,6 +153,8 @@
 
 extern struct lppaca lppaca[];
 
+#define lppaca_of(cpu)	(*paca[cpu].lppaca_ptr)
+
 /*
  * SLB shadow buffer structure as defined in the PAPR.  The save_area
  * contains adjacent ESID and VSID pairs for each shadowed SLB.  The
@@ -170,6 +172,33 @@
 
 extern struct slb_shadow slb_shadow[];
 
+/*
+ * Layout of entries in the hypervisor's dispatch trace log buffer.
+ */
+struct dtl_entry {
+	u8	dispatch_reason;
+	u8	preempt_reason;
+	u16	processor_id;
+	u32	enqueue_to_dispatch_time;
+	u32	ready_to_enqueue_time;
+	u32	waiting_to_ready_time;
+	u64	timebase;
+	u64	fault_addr;
+	u64	srr0;
+	u64	srr1;
+};
+
+#define DISPATCH_LOG_BYTES	4096	/* bytes per cpu */
+#define N_DISPATCH_LOG		(DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
+
+/*
+ * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
+ * reading from the dispatch trace log.  If other code wants to consume
+ * DTL entries, it can set this pointer to a function that will get
+ * called once for each DTL entry that gets processed.
+ */
+extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
+
 #endif /* CONFIG_PPC_BOOK3S */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/machdep.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/machdep.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/machdep.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/machdep.h	2011-01-04 19:50:19.000000000 -0500
@@ -102,6 +102,9 @@
 	void		(*pci_dma_dev_setup)(struct pci_dev *dev);
 	void		(*pci_dma_bus_setup)(struct pci_bus *bus);
 
+	/* Platform set_dma_mask override */
+	int		(*dma_set_mask)(struct device *dev, u64 dma_mask);
+
 	int		(*probe)(void);
 	void		(*setup_arch)(void); /* Optional, may be NULL */
 	void		(*init_early)(void);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/memblock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,11 +5,4 @@
 
 #define MEMBLOCK_DBG(fmt...) udbg_printf(fmt)
 
-#ifdef CONFIG_PPC32
-extern phys_addr_t lowmem_end_addr;
-#define MEMBLOCK_REAL_LIMIT	lowmem_end_addr
-#else
-#define MEMBLOCK_REAL_LIMIT	0
-#endif
-
 #endif /* _ASM_POWERPC_MEMBLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/mmu-book3e.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/mmu-book3e.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/mmu-book3e.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/mmu-book3e.h	2011-01-04 19:50:19.000000000 -0500
@@ -114,6 +114,17 @@
 
 #define MAS7_RPN		0xFFFFFFFF
 
+/* Bit definitions for MMUCFG */
+#define MMUCFG_MAVN	0x00000003	/* MMU Architecture Version Number */
+#define MMUCFG_MAVN_V1	0x00000000	/* v1.0 */
+#define MMUCFG_MAVN_V2	0x00000001	/* v2.0 */
+#define MMUCFG_NTLBS	0x0000000c	/* Number of TLBs */
+#define MMUCFG_PIDSIZE	0x000007c0	/* PID Reg Size */
+#define MMUCFG_TWC	0x00008000	/* TLB Write Conditional (v2.0) */
+#define MMUCFG_LRAT	0x00010000	/* LRAT Supported (v2.0) */
+#define MMUCFG_RASIZE	0x00fe0000	/* Real Addr Size */
+#define MMUCFG_LPIDSIZE	0x0f000000	/* LPID Reg Size */
+
 /* Bit definitions for MMUCSR0 */
 #define MMUCSR0_TLB1FI	0x00000002	/* TLB1 Flash invalidate */
 #define MMUCSR0_TLB0FI	0x00000004	/* TLB0 Flash invalidate */
@@ -133,6 +144,10 @@
 #define TLBnCFG_GTWE		0x00010000	/* Guest can write */
 #define TLBnCFG_IND		0x00020000	/* IND entries supported */
 #define TLBnCFG_PT		0x00040000	/* Can load from page table */
+#define TLBnCFG_MINSIZE		0x00f00000	/* Minimum Page Size (v1.0) */
+#define TLBnCFG_MINSIZE_SHIFT	20
+#define TLBnCFG_MAXSIZE		0x000f0000	/* Maximum Page Size (v1.0) */
+#define TLBnCFG_MAXSIZE_SHIFT	16
 #define TLBnCFG_ASSOC		0xff000000	/* Associativity */
 
 /* TLBnPS encoding */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/mmu.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/mmu.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/mmu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/mmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,8 @@
 #define _ASM_POWERPC_MMU_H_
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+
 #include <asm/asm-compat.h>
 #include <asm/feature-fixups.h>
 
@@ -82,6 +84,16 @@
 extern void early_init_mmu(void);
 extern void early_init_mmu_secondary(void);
 
+extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				       phys_addr_t first_memblock_size);
+
+#ifdef CONFIG_PPC64
+/* This is our real memory area size on ppc64 server, on embedded, we
+ * make it match the size our of bolted TLB area
+ */
+extern u64 ppc64_rma_size;
+#endif /* CONFIG_PPC64 */
+
 #endif /* !__ASSEMBLY__ */
 
 /* The kernel use the constants below to index in the page sizes array.
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/paca.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/paca.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/paca.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/paca.h	2011-01-04 19:50:19.000000000 -0500
@@ -85,6 +85,8 @@
 	u8 kexec_state;		/* set when kexec down has irqs off */
 #ifdef CONFIG_PPC_STD_MMU_64
 	struct slb_shadow *slb_shadow_ptr;
+	struct dtl_entry *dispatch_log;
+	struct dtl_entry *dispatch_log_end;
 
 	/*
 	 * Now, starting in cacheline 2, the exception save areas
@@ -129,13 +131,19 @@
 	u8 soft_enabled;		/* irq soft-enable flag */
 	u8 hard_enabled;		/* set if irqs are enabled in MSR */
 	u8 io_sync;			/* writel() needs spin_unlock sync */
-	u8 perf_event_pending;		/* PM interrupt while soft-disabled */
+	u8 irq_work_pending;		/* IRQ_WORK interrupt while soft-disable */
 
 	/* Stuff for accurate time accounting */
 	u64 user_time;			/* accumulated usermode TB ticks */
 	u64 system_time;		/* accumulated system TB ticks */
-	u64 startpurr;			/* PURR/TB value snapshot */
+	u64 user_time_scaled;		/* accumulated usermode SPURR ticks */
+	u64 starttime;			/* TB value snapshot */
+	u64 starttime_user;		/* TB value on exit to usermode */
 	u64 startspurr;			/* SPURR value snapshot */
+	u64 utime_sspurr;		/* ->user_time when ->startspurr set */
+	u64 stolen_time;		/* TB ticks taken by hypervisor */
+	u64 dtl_ridx;			/* read index in dispatch log */
+	struct dtl_entry *dtl_curr;	/* pointer corresponding to dtl_ridx */
 
 #ifdef CONFIG_KVM_BOOK3S_HANDLER
 	/* We use this to store guest state in */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/page_64.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/page_64.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/page_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/page_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -163,7 +163,7 @@
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #define VM_DATA_DEFAULT_FLAGS \
-	(test_thread_flag(TIF_32BIT) ? \
+	(is_32bit_task() ? \
 	 VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
 
 /*
@@ -179,7 +179,7 @@
 					 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define VM_STACK_DEFAULT_FLAGS \
-	(test_thread_flag(TIF_32BIT) ? \
+	(is_32bit_task() ? \
 	 VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
 
 #include <asm-generic/getorder.h>
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pgtable-ppc32.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pgtable-ppc32.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pgtable-ppc32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pgtable-ppc32.h	2011-01-04 19:50:19.000000000 -0500
@@ -308,12 +308,8 @@
 #define pte_offset_kernel(dir, addr)	\
 	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir, addr)		\
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
-#define pte_offset_map_nested(dir, addr)	\
-	((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
-
-#define pte_unmap(pte)		kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte)	kunmap_atomic(pte, KM_PTE1)
+	((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
+#define pte_unmap(pte)		kunmap_atomic(pte)
 
 /*
  * Encode and decode a swap entry.
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pgtable-ppc64.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pgtable-ppc64.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pgtable-ppc64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pgtable-ppc64.h	2011-01-04 19:50:19.000000000 -0500
@@ -193,9 +193,7 @@
   (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 
 #define pte_offset_map(dir,addr)	pte_offset_kernel((dir), (addr))
-#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir), (addr))
 #define pte_unmap(pte)			do { } while(0)
-#define pte_unmap_nested(pte)		do { } while(0)
 
 /* to find an entry in a kernel page-table-directory */
 /* This now only contains the vmalloc pages */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/ppc_asm.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/ppc_asm.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/ppc_asm.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/ppc_asm.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
 #include <asm/ppc-opcode.h>
+#include <asm/firmware.h>
 
 #ifndef __ASSEMBLY__
 #error __FILE__ should only be used in assembler files
@@ -26,17 +27,13 @@
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)
+#define ACCOUNT_STOLEN_TIME
 #else
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)					\
 	beq	2f;			/* if from kernel mode */	\
-BEGIN_FTR_SECTION;							\
-	mfspr	ra,SPRN_PURR;		/* get processor util. reg */	\
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);					\
-BEGIN_FTR_SECTION;							\
-	MFTB(ra);			/* or get TB if no PURR */	\
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR);					\
-	ld	rb,PACA_STARTPURR(r13);					\
-	std	ra,PACA_STARTPURR(r13);					\
+	MFTB(ra);			/* get timebase */		\
+	ld	rb,PACA_STARTTIME_USER(r13);				\
+	std	ra,PACA_STARTTIME(r13);					\
 	subf	rb,rb,ra;		/* subtract start value */	\
 	ld	ra,PACA_USER_TIME(r13);					\
 	add	ra,ra,rb;		/* add on to user time */	\
@@ -44,19 +41,34 @@
 2:
 
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)					\
-BEGIN_FTR_SECTION;							\
-	mfspr	ra,SPRN_PURR;		/* get processor util. reg */	\
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);					\
-BEGIN_FTR_SECTION;							\
-	MFTB(ra);			/* or get TB if no PURR */	\
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR);					\
-	ld	rb,PACA_STARTPURR(r13);					\
-	std	ra,PACA_STARTPURR(r13);					\
+	MFTB(ra);			/* get timebase */		\
+	ld	rb,PACA_STARTTIME(r13);					\
+	std	ra,PACA_STARTTIME_USER(r13);				\
 	subf	rb,rb,ra;		/* subtract start value */	\
 	ld	ra,PACA_SYSTEM_TIME(r13);				\
-	add	ra,ra,rb;		/* add on to user time */	\
-	std	ra,PACA_SYSTEM_TIME(r13);
-#endif
+	add	ra,ra,rb;		/* add on to system time */	\
+	std	ra,PACA_SYSTEM_TIME(r13)
+
+#ifdef CONFIG_PPC_SPLPAR
+#define ACCOUNT_STOLEN_TIME						\
+BEGIN_FW_FTR_SECTION;							\
+	beq	33f;							\
+	/* from user - see if there are any DTL entries to process */	\
+	ld	r10,PACALPPACAPTR(r13);	/* get ptr to VPA */		\
+	ld	r11,PACA_DTL_RIDX(r13);	/* get log read index */	\
+	ld	r10,LPPACA_DTLIDX(r10);	/* get log write index */	\
+	cmpd	cr1,r11,r10;						\
+	beq+	cr1,33f;						\
+	bl	.accumulate_stolen_time;				\
+33:									\
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
+
+#else  /* CONFIG_PPC_SPLPAR */
+#define ACCOUNT_STOLEN_TIME
+
+#endif /* CONFIG_PPC_SPLPAR */
+
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 
 /*
  * Macros for storing registers into and loading registers from
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/ppc-pci.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/ppc-pci.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/ppc-pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/ppc-pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,8 +28,8 @@
 extern struct pci_dev *isa_bridge_pcidev;	/* may be NULL if no ISA bus */
 
 /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
-#define BUID_HI(buid) ((buid) >> 32)
-#define BUID_LO(buid) ((buid) & 0xffffffff)
+#define BUID_HI(buid) upper_32_bits(buid)
+#define BUID_LO(buid) lower_32_bits(buid)
 
 /* PCI device_node operations */
 struct device_node;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/processor.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -118,7 +118,7 @@
 #define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4))
 #define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4))
 
-#define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)) ? \
+#define TASK_UNMAPPED_BASE ((is_32bit_task()) ? \
 		TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
 #endif
 
@@ -128,7 +128,7 @@
 #define STACK_TOP_USER64 TASK_SIZE_USER64
 #define STACK_TOP_USER32 TASK_SIZE_USER32
 
-#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
+#define STACK_TOP (is_32bit_task() ? \
 		   STACK_TOP_USER32 : STACK_TOP_USER64)
 
 #define STACK_TOP_MAX STACK_TOP_USER64
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pte-common.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pte-common.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/pte-common.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/pte-common.h	2011-01-04 19:50:19.000000000 -0500
@@ -171,6 +171,13 @@
 /* Make modules code happy. We don't set RO yet */
 #define PAGE_KERNEL_EXEC	PAGE_KERNEL_X
 
+/*
+ * Don't just check for any non zero bits in __PAGE_USER, since for book3e
+ * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
+ * _PAGE_USER.  Need to explictly match _PAGE_BAP_UR bit in that case too.
+ */
+#define pte_user(val)		((val & _PAGE_USER) == _PAGE_USER)
+
 /* Advertise special mapping type for AGP */
 #define PAGE_AGP		(PAGE_KERNEL_NC)
 #define HAVE_PAGE_AGP
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/rtas.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/rtas.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/rtas.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/rtas.h	2011-01-04 19:50:19.000000000 -0500
@@ -187,6 +187,7 @@
 extern void rtas_initialize(void);
 extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data);
 extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data);
+extern int rtas_ibm_suspend_me(struct rtas_args *);
 
 struct rtc_time;
 extern unsigned long rtas_get_boot_time(void);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/systbl.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/systbl.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/systbl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/systbl.h	2011-01-04 19:50:19.000000000 -0500
@@ -329,3 +329,22 @@
 SYSCALL(fanotify_init)
 COMPAT_SYS(fanotify_mark)
 SYSCALL_SPU(prlimit64)
+SYSCALL_SPU(socket)
+SYSCALL_SPU(bind)
+SYSCALL_SPU(connect)
+SYSCALL_SPU(listen)
+SYSCALL_SPU(accept)
+SYSCALL_SPU(getsockname)
+SYSCALL_SPU(getpeername)
+SYSCALL_SPU(socketpair)
+SYSCALL_SPU(send)
+SYSCALL_SPU(sendto)
+COMPAT_SYS_SPU(recv)
+COMPAT_SYS_SPU(recvfrom)
+SYSCALL_SPU(shutdown)
+COMPAT_SYS_SPU(setsockopt)
+COMPAT_SYS_SPU(getsockopt)
+COMPAT_SYS_SPU(sendmsg)
+COMPAT_SYS_SPU(recvmsg)
+COMPAT_SYS_SPU(recvmmsg)
+SYSCALL_SPU(accept4)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/system.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -154,8 +154,8 @@
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 extern int fix_alignment(struct pt_regs *);
-extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
-extern void cvt_df(double *from, float *to, struct thread_struct *thread);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
 
 #ifndef CONFIG_SMP
 extern void discard_lazy_cpu_state(void);
@@ -542,10 +542,6 @@
 
 #define PTRRELOC(x)	((typeof(x)) add_reloc_offset((unsigned long)(x)))
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_system_vtime(struct task_struct *);
-#endif
-
 extern struct dentry *powerpc_debugfs_root;
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/time.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/time.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/time.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/time.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,6 @@
 extern void GregorianDay(struct rtc_time *tm);
 
 extern void generic_calibrate_decr(void);
-extern void snapshot_timebase(void);
 
 extern void set_dec_cpu6(unsigned int val);
 
@@ -212,12 +211,8 @@
 DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
 
 #if defined(CONFIG_VIRT_CPU_ACCOUNTING)
-extern void calculate_steal_time(void);
-extern void snapshot_timebases(void);
 #define account_process_vtime(tsk)		account_process_tick(tsk, 0)
 #else
-#define calculate_steal_time()			do { } while (0)
-#define snapshot_timebases()			do { } while (0)
 #define account_process_vtime(tsk)		do { } while (0)
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/include/asm/unistd.h linux-libre-2.6.37-gnu/arch/powerpc/include/asm/unistd.h
--- linux-libre-2.6.36-gnu/arch/powerpc/include/asm/unistd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/include/asm/unistd.h	2011-01-04 19:50:19.000000000 -0500
@@ -348,10 +348,29 @@
 #define __NR_fanotify_init	323
 #define __NR_fanotify_mark	324
 #define __NR_prlimit64		325
+#define __NR_socket		326
+#define __NR_bind		327
+#define __NR_connect		328
+#define __NR_listen		329
+#define __NR_accept		330
+#define __NR_getsockname	331
+#define __NR_getpeername	332
+#define __NR_socketpair		333
+#define __NR_send		334
+#define __NR_sendto		335
+#define __NR_recv		336
+#define __NR_recvfrom		337
+#define __NR_shutdown		338
+#define __NR_setsockopt		339
+#define __NR_getsockopt		340
+#define __NR_sendmsg		341
+#define __NR_recvmsg		342
+#define __NR_recvmmsg		343
+#define __NR_accept4		344
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls		326
+#define __NR_syscalls		345
 
 #define __NR__exit __NR_exit
 #define NR_syscalls	__NR_syscalls
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,15 +1,13 @@
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux/PowerPC Kernel Configuration"
-
 source "arch/powerpc/platforms/Kconfig.cputype"
 
 config PPC32
 	bool
 	default y if !PPC64
 
+config 32BIT
+	bool
+	default y if PPC32
+
 config 64BIT
 	bool
 	default y if PPC64
@@ -138,6 +136,7 @@
 	select HAVE_OPROFILE
 	select HAVE_SYSCALL_WRAPPERS if PPC64
 	select GENERIC_ATOMIC64 if PPC32
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select HAVE_REGS_AND_STACK_ACCESS_API
 	select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
@@ -687,9 +686,12 @@
 	bool
 
 config FSL_LBC
-	bool
+	bool "Freescale Local Bus support"
+	depends on FSL_SOC
 	help
-	  Freescale Localbus support
+	  Enables reporting of errors from the Freescale local bus
+	  controller.  Also contains some common code used by
+	  drivers for specific local bus peripherals.
 
 config FSL_GTM
 	bool
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/align.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/align.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/align.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/align.c	2011-01-04 19:50:19.000000000 -0500
@@ -889,7 +889,7 @@
 #ifdef CONFIG_PPC_FPU
 			preempt_disable();
 			enable_kernel_fp();
-			cvt_df(&data.dd, (float *)&data.v[4], &current->thread);
+			cvt_df(&data.dd, (float *)&data.v[4]);
 			preempt_enable();
 #else
 			return 0;
@@ -933,7 +933,7 @@
 #ifdef CONFIG_PPC_FPU
 		preempt_disable();
 		enable_kernel_fp();
-		cvt_fd((float *)&data.v[4], &data.dd, &current->thread);
+		cvt_fd((float *)&data.v[4], &data.dd);
 		preempt_enable();
 #else
 		return 0;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,11 +48,11 @@
 #ifdef CONFIG_PPC_ISERIES
 #include <asm/iseries/alpaca.h>
 #endif
-#ifdef CONFIG_KVM
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST)
 #include <linux/kvm_host.h>
-#ifndef CONFIG_BOOKE
-#include <asm/kvm_book3s.h>
 #endif
+#if defined(CONFIG_KVM) && defined(CONFIG_PPC_BOOK3S)
+#include <asm/kvm_book3s.h>
 #endif
 
 #ifdef CONFIG_PPC32
@@ -61,7 +61,7 @@
 #endif
 #endif
 
-#if defined(CONFIG_FSL_BOOKE)
+#if defined(CONFIG_PPC_FSL_BOOK3E)
 #include "../mm/mmu_decl.h"
 #endif
 
@@ -181,17 +181,19 @@
 	       offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
 	DEFINE(SLBSHADOW_STACKESID,
 	       offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
+	DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
 	DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
 	DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
 	DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
 	DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
-	DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
+	DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
+	DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx));
 #endif /* CONFIG_PPC_STD_MMU_64 */
 	DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
 	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
 	DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
-	DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr));
-	DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr));
+	DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
+	DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
 	DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
 	DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
 	DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
@@ -394,12 +396,13 @@
 	DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
 	DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
 	DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
-	DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.msr));
 	DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
 	DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
 	DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
 	DEFINE(VCPU_SPRG7, offsetof(struct kvm_vcpu, arch.sprg7));
 	DEFINE(VCPU_SHADOW_PID, offsetof(struct kvm_vcpu, arch.shadow_pid));
+	DEFINE(VCPU_SHARED, offsetof(struct kvm_vcpu, arch.shared));
+	DEFINE(VCPU_SHARED_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
 
 	/* book3s */
 #ifdef CONFIG_PPC_BOOK3S
@@ -464,11 +467,27 @@
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif /* CONFIG_PPC_BOOK3S */
 #endif
+
+#ifdef CONFIG_KVM_GUEST
+	DEFINE(KVM_MAGIC_SCRATCH1, offsetof(struct kvm_vcpu_arch_shared,
+					    scratch1));
+	DEFINE(KVM_MAGIC_SCRATCH2, offsetof(struct kvm_vcpu_arch_shared,
+					    scratch2));
+	DEFINE(KVM_MAGIC_SCRATCH3, offsetof(struct kvm_vcpu_arch_shared,
+					    scratch3));
+	DEFINE(KVM_MAGIC_INT, offsetof(struct kvm_vcpu_arch_shared,
+				       int_pending));
+	DEFINE(KVM_MAGIC_MSR, offsetof(struct kvm_vcpu_arch_shared, msr));
+	DEFINE(KVM_MAGIC_CRITICAL, offsetof(struct kvm_vcpu_arch_shared,
+					    critical));
+	DEFINE(KVM_MAGIC_SR, offsetof(struct kvm_vcpu_arch_shared, sr));
+#endif
+
 #ifdef CONFIG_44x
 	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
 	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
 #endif
-#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_PPC_FSL_BOOK3E
 	DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam));
 	DEFINE(TLBCAM_MAS0, offsetof(struct tlbcam, MAS0));
 	DEFINE(TLBCAM_MAS1, offsetof(struct tlbcam, MAS1));
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/cpu_setup_44x.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/cpu_setup_44x.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/cpu_setup_44x.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/cpu_setup_44x.S	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 _GLOBAL(__setup_cpu_460ex)
 _GLOBAL(__setup_cpu_460gt)
 _GLOBAL(__setup_cpu_460sx)
+_GLOBAL(__setup_cpu_apm821xx)
 	mflr	r4
 	bl	__init_fpu_44x
 	bl	__fixup_440A_mcheck
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/cpu_setup_fsl_booke.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/cpu_setup_fsl_booke.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/cpu_setup_fsl_booke.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/cpu_setup_fsl_booke.S	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,7 @@
 	isync
 	blr
 
+#ifdef CONFIG_PPC32
 _GLOBAL(__setup_cpu_e200)
 	/* enable dedicated debug exception handling resources (Debug APU) */
 	mfspr	r3,SPRN_HID0
@@ -72,3 +73,17 @@
 	bl	__setup_e500mc_ivors
 	mtlr	r4
 	blr
+#endif
+/* Right now, restore and setup are the same thing */
+_GLOBAL(__restore_cpu_e5500)
+_GLOBAL(__setup_cpu_e5500)
+	mflr	r4
+	bl	__e500_icache_setup
+	bl	__e500_dcache_setup
+#ifdef CONFIG_PPC_BOOK3E_64
+	bl	.__setup_base_ivors
+#else
+	bl	__setup_e500mc_ivors
+#endif
+	mtlr	r4
+	blr
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/cputable.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/cputable.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/cputable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/cputable.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,6 +48,7 @@
 extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_apm821xx(unsigned long offset, struct cpu_spec *spec);
 extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -66,6 +67,10 @@
 extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power7(void);
 #endif /* CONFIG_PPC64 */
+#if defined(CONFIG_E500)
+extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_e5500(void);
+#endif /* CONFIG_E500 */
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -1805,6 +1810,20 @@
 		.machine_check		= machine_check_440A,
 		.platform		= "ppc440",
 	},
+	{ /* 464 in APM821xx */
+		.pvr_mask		= 0xffffff00,
+		.pvr_value		= 0x12C41C80,
+		.cpu_name		= "APM821XX",
+		.cpu_features		= CPU_FTRS_44X,
+		.cpu_user_features	= COMMON_USER_BOOKE |
+			PPC_FEATURE_HAS_FPU,
+		.mmu_features		= MMU_FTR_TYPE_44x,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+		.cpu_setup		= __setup_cpu_apm821xx,
+		.machine_check		= machine_check_440A,
+		.platform		= "ppc440",
+	},
 	{ /* 476 core */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x11a50000,
@@ -1891,7 +1910,9 @@
 		.platform		= "ppc5554",
 	}
 #endif /* CONFIG_E200 */
+#endif /* CONFIG_PPC32 */
 #ifdef CONFIG_E500
+#ifdef CONFIG_PPC32
 	{	/* e500 */
 		.pvr_mask		= 0xffff0000,
 		.pvr_value		= 0x80200000,
@@ -1946,6 +1967,26 @@
 		.machine_check		= machine_check_e500mc,
 		.platform		= "ppce500mc",
 	},
+#endif /* CONFIG_PPC32 */
+	{	/* e5500 */
+		.pvr_mask		= 0xffff0000,
+		.pvr_value		= 0x80240000,
+		.cpu_name		= "e5500",
+		.cpu_features		= CPU_FTRS_E500MC,
+		.cpu_user_features	= COMMON_USER_BOOKE,
+		.mmu_features		= MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
+			MMU_FTR_USE_TLBILX,
+		.icache_bsize		= 64,
+		.dcache_bsize		= 64,
+		.num_pmcs		= 4,
+		.oprofile_cpu_type	= "ppc/e500mc",
+		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
+		.cpu_setup		= __setup_cpu_e5500,
+		.cpu_restore		= __restore_cpu_e5500,
+		.machine_check		= machine_check_e500mc,
+		.platform		= "ppce5500",
+	},
+#ifdef CONFIG_PPC32
 	{	/* default match */
 		.pvr_mask		= 0x00000000,
 		.pvr_value		= 0x00000000,
@@ -1960,8 +2001,8 @@
 		.machine_check		= machine_check_e500,
 		.platform		= "powerpc",
 	}
-#endif /* CONFIG_E500 */
 #endif /* CONFIG_PPC32 */
+#endif /* CONFIG_E500 */
 
 #ifdef CONFIG_PPC_BOOK3E_64
 	{	/* This is a default entry to get going, to be replaced by
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/crash.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/crash.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/crash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/crash.c	2011-01-04 19:50:19.000000000 -0500
@@ -414,18 +414,7 @@
 	crash_kexec_wait_realmode(crashing_cpu);
 #endif
 
-	for_each_irq(i) {
-		struct irq_desc *desc = irq_to_desc(i);
-
-		if (!desc || !desc->chip || !desc->chip->eoi)
-			continue;
-
-		if (desc->status & IRQ_INPROGRESS)
-			desc->chip->eoi(i);
-
-		if (!(desc->status & IRQ_DISABLED))
-			desc->chip->shutdown(i);
-	}
+	machine_kexec_mask_interrupts();
 
 	/*
 	 * Call registered shutdown routines savely.  Swap out
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/dma.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/dma.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/memblock.h>
 #include <asm/bug.h>
 #include <asm/abs_addr.h>
+#include <asm/machdep.h>
 
 /*
  * Generic direct DMA implementation
@@ -89,7 +90,7 @@
 	/* Could be improved so platforms can set the limit in case
 	 * they have limited DMA windows
 	 */
-	return mask >= (memblock_end_of_DRAM() - 1);
+	return mask >= get_dma_offset(dev) + (memblock_end_of_DRAM() - 1);
 #else
 	return 1;
 #endif
@@ -154,6 +155,23 @@
 
 #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
 
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	struct dma_map_ops *dma_ops = get_dma_ops(dev);
+
+	if (ppc_md.dma_set_mask)
+		return ppc_md.dma_set_mask(dev, dma_mask);
+	if (unlikely(dma_ops == NULL))
+		return -EIO;
+	if (dma_ops->set_dma_mask != NULL)
+		return dma_ops->set_dma_mask(dev, dma_mask);
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+	*dev->dma_mask = dma_mask;
+	return 0;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
 static int __init dma_init(void)
 {
        dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/dma-iommu.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/dma-iommu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/dma-iommu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/dma-iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,16 +74,17 @@
 {
 	struct iommu_table *tbl = get_iommu_table_base(dev);
 
-	if (!tbl || tbl->it_offset > mask) {
-		printk(KERN_INFO
-		       "Warning: IOMMU offset too big for device mask\n");
-		if (tbl)
-			printk(KERN_INFO
-			       "mask: 0x%08llx, table offset: 0x%08lx\n",
-				mask, tbl->it_offset);
-		else
-			printk(KERN_INFO "mask: 0x%08llx, table unavailable\n",
-				mask);
+	if (!tbl) {
+		dev_info(dev, "Warning: IOMMU dma not supported: mask 0x%08llx"
+			", table unavailable\n", mask);
+		return 0;
+	}
+
+	if ((tbl->it_offset + tbl->it_size) > (mask >> IOMMU_PAGE_SHIFT)) {
+		dev_info(dev, "Warning: IOMMU window too big for device mask\n");
+		dev_info(dev, "mask: 0x%08llx, table end: 0x%08lx\n",
+				mask, (tbl->it_offset + tbl->it_size) <<
+				IOMMU_PAGE_SHIFT);
 		return 0;
 	} else
 		return 1;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/entry_64.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/entry_64.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/entry_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/entry_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -97,6 +97,24 @@
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	ld	r11,exception_marker@toc(r2)
 	std	r11,-16(r9)		/* "regshere" marker */
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
+BEGIN_FW_FTR_SECTION
+	beq	33f
+	/* if from user, see if there are any DTL entries to process */
+	ld	r10,PACALPPACAPTR(r13)	/* get ptr to VPA */
+	ld	r11,PACA_DTL_RIDX(r13)	/* get log read index */
+	ld	r10,LPPACA_DTLIDX(r10)	/* get log write index */
+	cmpd	cr1,r11,r10
+	beq+	cr1,33f
+	bl	.accumulate_stolen_time
+	REST_GPR(0,r1)
+	REST_4GPRS(3,r1)
+	REST_2GPRS(7,r1)
+	addi	r9,r1,STACK_FRAME_OVERHEAD
+33:
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
+
 #ifdef CONFIG_TRACE_IRQFLAGS
 	bl	.trace_hardirqs_on
 	REST_GPR(0,r1)
@@ -202,7 +220,9 @@
 	bge-	syscall_error
 syscall_error_cont:
 	ld	r7,_NIP(r1)
+BEGIN_FTR_SECTION
 	stdcx.	r0,0,r1			/* to clear the reservation */
+END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
 	andi.	r6,r8,MSR_PR
 	ld	r4,_LINK(r1)
 	/*
@@ -419,6 +439,17 @@
 	sync
 #endif /* CONFIG_SMP */
 
+	/*
+	 * If we optimise away the clear of the reservation in system
+	 * calls because we know the CPU tracks the address of the
+	 * reservation, then we need to clear it here to cover the
+	 * case that the kernel context switch path has no larx
+	 * instructions.
+	 */
+BEGIN_FTR_SECTION
+	ldarx	r6,0,r1
+END_FTR_SECTION_IFSET(CPU_FTR_STCX_CHECKS_ADDRESS)
+
 	addi	r6,r4,-THREAD	/* Convert THREAD to 'current' */
 	std	r6,PACACURRENT(r13)	/* Set new 'current' */
 
@@ -576,7 +607,16 @@
 	andi.	r0,r3,MSR_RI
 	beq-	unrecov_restore
 
+	/*
+	 * Clear the reservation. If we know the CPU tracks the address of
+	 * the reservation then we can potentially save some cycles and use
+	 * a larx. On POWER6 and POWER7 this is significantly faster.
+	 */
+BEGIN_FTR_SECTION
 	stdcx.	r0,0,r1		/* to clear the reservation */
+FTR_SECTION_ELSE
+	ldarx	r4,0,r1
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
 
 	/*
 	 * Clear RI before restoring r13.  If we are returning to
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/exceptions-64s.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/exceptions-64s.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/exceptions-64s.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/exceptions-64s.S	2011-01-04 19:50:19.000000000 -0500
@@ -299,6 +299,12 @@
 	b	.				/* prevent spec. execution */
 #endif /* __DISABLED__ */
 
+/* KVM's trampoline code needs to be close to the interrupt handlers */
+
+#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
+#include "../kvm/book3s_rmhandlers.S"
+#endif
+
 	.align	7
 	.globl	__end_interrupts
 __end_interrupts:
@@ -818,12 +824,12 @@
 
 	/*
 	 * hash_page couldn't handle it, set soft interrupt enable back
-	 * to what it was before the trap.  Note that .raw_local_irq_restore
+	 * to what it was before the trap.  Note that .arch_local_irq_restore
 	 * handles any interrupts pending at this point.
 	 */
 	ld	r3,SOFTE(r1)
 	TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f)
-	bl	.raw_local_irq_restore
+	bl	.arch_local_irq_restore
 	b	11f
 
 /* We have a data breakpoint exception - handle it */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/fpu.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/fpu.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/fpu.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/fpu.S	2011-01-04 19:50:19.000000000 -0500
@@ -163,24 +163,14 @@
 /*
  * These are used in the alignment trap handler when emulating
  * single-precision loads and stores.
- * We restore and save the fpscr so the task gets the same result
- * and exceptions as if the cpu had performed the load or store.
  */
 
 _GLOBAL(cvt_fd)
-	lfd	0,THREAD_FPSCR(r5)	/* load up fpscr value */
-	MTFSF_L(0)
 	lfs	0,0(r3)
 	stfd	0,0(r4)
-	mffs	0
-	stfd	0,THREAD_FPSCR(r5)	/* save new fpscr value */
 	blr
 
 _GLOBAL(cvt_df)
-	lfd	0,THREAD_FPSCR(r5)	/* load up fpscr value */
-	MTFSF_L(0)
 	lfd	0,0(r3)
 	stfs	0,0(r4)
-	mffs	0
-	stfd	0,THREAD_FPSCR(r5)	/* save new fpscr value */
 	blr
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_40x.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_40x.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_40x.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_40x.S	2011-01-04 19:50:19.000000000 -0500
@@ -923,11 +923,7 @@
 	mtspr	SPRN_PID,r0
 	sync
 
-	/* Configure and load two entries into TLB slots 62 and 63.
-	 * In case we are pinning TLBs, these are reserved in by the
-	 * other TLB functions.  If not reserving, then it doesn't
-	 * matter where they are loaded.
-	 */
+	/* Configure and load one entry into TLB slots 63 */
 	clrrwi	r4,r4,10		/* Mask off the real page number */
 	ori	r4,r4,(TLB_WR | TLB_EX)	/* Set the write and execute bits */
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_64.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_64.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -166,12 +166,6 @@
 #include "exceptions-64s.S"
 #endif
 
-/* KVM trampoline code needs to be close to the interrupt handlers */
-
-#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
-#include "../kvm/book3s_rmhandlers.S"
-#endif
-
 _GLOBAL(generic_secondary_thread_init)
 	mr	r24,r3
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_fsl_booke.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_fsl_booke.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/head_fsl_booke.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/head_fsl_booke.S	2011-01-04 19:50:19.000000000 -0500
@@ -152,8 +152,11 @@
 	/* Check to see if we're the second processor, and jump
 	 * to the secondary_start code if so
 	 */
-	mfspr	r24,SPRN_PIR
-	cmpwi	r24,0
+	lis	r24, boot_cpuid@h
+	ori	r24, r24, boot_cpuid@l
+	lwz	r24, 0(r24)
+	cmpwi	r24, -1
+	mfspr   r24,SPRN_PIR
 	bne	__secondary_start
 #endif
 
@@ -175,6 +178,9 @@
 	li	r0,0
 	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
 
+	rlwinm  r22,r1,0,0,31-THREAD_SHIFT      /* current thread_info */
+	stw	r24, TI_CPU(r22)
+
 	bl	early_init
 
 #ifdef CONFIG_RELOCATABLE
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/ibmebus.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/ibmebus.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/ibmebus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/ibmebus.c	2011-01-04 19:50:19.000000000 -0500
@@ -162,13 +162,10 @@
 	dev->dev.bus = &ibmebus_bus_type;
 	dev->dev.archdata.dma_ops = &ibmebus_dma_ops;
 
-	ret = of_device_register(dev);
-	if (ret) {
-		of_device_free(dev);
-		return ret;
-	}
-
-	return 0;
+	ret = of_device_add(dev);
+	if (ret)
+		platform_device_put(dev);
+	return ret;
 }
 
 static int ibmebus_create_devices(const struct of_device_id *matches)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/irq.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -116,7 +116,7 @@
 	: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
 }
 
-notrace void raw_local_irq_restore(unsigned long en)
+notrace void arch_local_irq_restore(unsigned long en)
 {
 	/*
 	 * get_paca()->soft_enabled = en;
@@ -192,7 +192,7 @@
 
 	__hard_irq_enable();
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 #endif /* CONFIG_PPC64 */
 
 static int show_other_interrupts(struct seq_file *p, int prec)
@@ -587,8 +587,10 @@
 			 * this will be fixed once slab is made available early
 			 * instead of the current cruft
 			 */
-			if (mem_init_done)
+			if (mem_init_done) {
+				of_node_put(host->of_node);
 				kfree(host);
+			}
 			return NULL;
 		}
 		irq_map[0].host = host;
@@ -1143,7 +1145,7 @@
 	unsigned long flags;
 	struct irq_desc *desc;
 	const char *p;
-	char none[] = "none";
+	static const char none[] = "none";
 	int i;
 
 	seq_printf(m, "%-5s  %-7s  %-15s  %s\n", "virq", "hwirq",
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/kgdb.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/kgdb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/kgdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/kgdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -194,40 +194,6 @@
 	ptr = (unsigned long *)ptr32; \
 	} while (0)
 
-
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
-	unsigned long *ptr = gdb_regs;
-	int reg;
-
-	memset(gdb_regs, 0, NUMREGBYTES);
-
-	for (reg = 0; reg < 32; reg++)
-		PACK64(ptr, regs->gpr[reg]);
-
-#ifdef CONFIG_FSL_BOOKE
-#ifdef CONFIG_SPE
-	for (reg = 0; reg < 32; reg++)
-		PACK64(ptr, current->thread.evr[reg]);
-#else
-	ptr += 32;
-#endif
-#else
-	/* fp registers not used by kernel, leave zero */
-	ptr += 32 * 8 / sizeof(long);
-#endif
-
-	PACK64(ptr, regs->nip);
-	PACK64(ptr, regs->msr);
-	PACK32(ptr, regs->ccr);
-	PACK64(ptr, regs->link);
-	PACK64(ptr, regs->ctr);
-	PACK32(ptr, regs->xer);
-
-	BUG_ON((unsigned long)ptr >
-	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
-}
-
 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 {
 	struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
@@ -271,44 +237,140 @@
 	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
 }
 
-#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0)
+#define GDB_SIZEOF_REG sizeof(unsigned long)
+#define GDB_SIZEOF_REG_U32 sizeof(u32)
 
-#define UNPACK32(dest, ptr) do {       \
-	u32 *ptr32;                   \
-	ptr32 = (u32 *)ptr;           \
-	dest = *(ptr32++);            \
-	ptr = (unsigned long *)ptr32; \
-	} while (0)
+#ifdef CONFIG_FSL_BOOKE
+#define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long)
+#else
+#define GDB_SIZEOF_FLOAT_REG sizeof(u64)
+#endif
 
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
 {
-	unsigned long *ptr = gdb_regs;
-	int reg;
+	{ "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) },
+	{ "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) },
+	{ "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) },
+	{ "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) },
+	{ "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) },
+	{ "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) },
+	{ "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) },
+	{ "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) },
+	{ "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) },
+	{ "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) },
+	{ "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) },
+	{ "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) },
+	{ "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) },
+	{ "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) },
+	{ "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) },
+	{ "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) },
+	{ "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) },
+	{ "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) },
+	{ "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) },
+	{ "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) },
+	{ "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) },
+	{ "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) },
+	{ "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) },
+	{ "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) },
+	{ "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) },
+	{ "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) },
+	{ "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) },
+	{ "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) },
+	{ "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) },
+	{ "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) },
+	{ "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) },
+	{ "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) },
 
-	for (reg = 0; reg < 32; reg++)
-		UNPACK64(regs->gpr[reg], ptr);
+	{ "f0", GDB_SIZEOF_FLOAT_REG, 0 },
+	{ "f1", GDB_SIZEOF_FLOAT_REG, 1 },
+	{ "f2", GDB_SIZEOF_FLOAT_REG, 2 },
+	{ "f3", GDB_SIZEOF_FLOAT_REG, 3 },
+	{ "f4", GDB_SIZEOF_FLOAT_REG, 4 },
+	{ "f5", GDB_SIZEOF_FLOAT_REG, 5 },
+	{ "f6", GDB_SIZEOF_FLOAT_REG, 6 },
+	{ "f7", GDB_SIZEOF_FLOAT_REG, 7 },
+	{ "f8", GDB_SIZEOF_FLOAT_REG, 8 },
+	{ "f9", GDB_SIZEOF_FLOAT_REG, 9 },
+	{ "f10", GDB_SIZEOF_FLOAT_REG, 10 },
+	{ "f11", GDB_SIZEOF_FLOAT_REG, 11 },
+	{ "f12", GDB_SIZEOF_FLOAT_REG, 12 },
+	{ "f13", GDB_SIZEOF_FLOAT_REG, 13 },
+	{ "f14", GDB_SIZEOF_FLOAT_REG, 14 },
+	{ "f15", GDB_SIZEOF_FLOAT_REG, 15 },
+	{ "f16", GDB_SIZEOF_FLOAT_REG, 16 },
+	{ "f17", GDB_SIZEOF_FLOAT_REG, 17 },
+	{ "f18", GDB_SIZEOF_FLOAT_REG, 18 },
+	{ "f19", GDB_SIZEOF_FLOAT_REG, 19 },
+	{ "f20", GDB_SIZEOF_FLOAT_REG, 20 },
+	{ "f21", GDB_SIZEOF_FLOAT_REG, 21 },
+	{ "f22", GDB_SIZEOF_FLOAT_REG, 22 },
+	{ "f23", GDB_SIZEOF_FLOAT_REG, 23 },
+	{ "f24", GDB_SIZEOF_FLOAT_REG, 24 },
+	{ "f25", GDB_SIZEOF_FLOAT_REG, 25 },
+	{ "f26", GDB_SIZEOF_FLOAT_REG, 26 },
+	{ "f27", GDB_SIZEOF_FLOAT_REG, 27 },
+	{ "f28", GDB_SIZEOF_FLOAT_REG, 28 },
+	{ "f29", GDB_SIZEOF_FLOAT_REG, 29 },
+	{ "f30", GDB_SIZEOF_FLOAT_REG, 30 },
+	{ "f31", GDB_SIZEOF_FLOAT_REG, 31 },
 
-#ifdef CONFIG_FSL_BOOKE
-#ifdef CONFIG_SPE
-	for (reg = 0; reg < 32; reg++)
-		UNPACK64(current->thread.evr[reg], ptr);
+	{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) },
+	{ "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) },
+	{ "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) },
+	{ "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) },
+	{ "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) },
+	{ "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) },
+};
+
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
+{
+	if (regno >= DBG_MAX_REG_NUM || regno < 0)
+		return NULL;
+
+	if (regno < 32 || regno >= 64)
+		/* First 0 -> 31 gpr registers*/
+		/* pc, msr, ls... registers 64 -> 69 */
+		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+				dbg_reg_def[regno].size);
+
+	if (regno >= 32 && regno < 64) {
+		/* FP registers 32 -> 63 */
+#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
+		if (current)
+			memcpy(mem, &current->thread.evr[regno-32],
+					dbg_reg_def[regno].size);
 #else
-	ptr += 32;
+		/* fp registers not used by kernel, leave zero */
+		memset(mem, 0, dbg_reg_def[regno].size);
 #endif
+	}
+
+	return dbg_reg_def[regno].name;
+}
+
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+	if (regno >= DBG_MAX_REG_NUM || regno < 0)
+		return -EINVAL;
+
+	if (regno < 32 || regno >= 64)
+		/* First 0 -> 31 gpr registers*/
+		/* pc, msr, ls... registers 64 -> 69 */
+		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+				dbg_reg_def[regno].size);
+
+	if (regno >= 32 && regno < 64) {
+		/* FP registers 32 -> 63 */
+#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE)
+		memcpy(&current->thread.evr[regno-32], mem,
+				dbg_reg_def[regno].size);
 #else
-	/* fp registers not used by kernel, leave zero */
-	ptr += 32 * 8 / sizeof(int);
+		/* fp registers not used by kernel, leave zero */
+		return 0;
 #endif
+	}
 
-	UNPACK64(regs->nip, ptr);
-	UNPACK64(regs->msr, ptr);
-	UNPACK32(regs->ccr, ptr);
-	UNPACK64(regs->link, ptr);
-	UNPACK64(regs->ctr, ptr);
-	UNPACK32(regs->xer, ptr);
-
-	BUG_ON((unsigned long)ptr >
-	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+	return 0;
 }
 
 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/kvm.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/kvm.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/kvm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/kvm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2010 SUSE Linux Products GmbH. All rights reserved.
+ *
+ * Authors:
+ *     Alexander Graf <agraf@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kvm_host.h>
+#include <linux/init.h>
+#include <linux/kvm_para.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <asm/reg.h>
+#include <asm/sections.h>
+#include <asm/cacheflush.h>
+#include <asm/disassemble.h>
+
+#define KVM_MAGIC_PAGE		(-4096L)
+#define magic_var(x) KVM_MAGIC_PAGE + offsetof(struct kvm_vcpu_arch_shared, x)
+
+#define KVM_INST_LWZ		0x80000000
+#define KVM_INST_STW		0x90000000
+#define KVM_INST_LD		0xe8000000
+#define KVM_INST_STD		0xf8000000
+#define KVM_INST_NOP		0x60000000
+#define KVM_INST_B		0x48000000
+#define KVM_INST_B_MASK		0x03ffffff
+#define KVM_INST_B_MAX		0x01ffffff
+
+#define KVM_MASK_RT		0x03e00000
+#define KVM_RT_30		0x03c00000
+#define KVM_MASK_RB		0x0000f800
+#define KVM_INST_MFMSR		0x7c0000a6
+#define KVM_INST_MFSPR_SPRG0	0x7c1042a6
+#define KVM_INST_MFSPR_SPRG1	0x7c1142a6
+#define KVM_INST_MFSPR_SPRG2	0x7c1242a6
+#define KVM_INST_MFSPR_SPRG3	0x7c1342a6
+#define KVM_INST_MFSPR_SRR0	0x7c1a02a6
+#define KVM_INST_MFSPR_SRR1	0x7c1b02a6
+#define KVM_INST_MFSPR_DAR	0x7c1302a6
+#define KVM_INST_MFSPR_DSISR	0x7c1202a6
+
+#define KVM_INST_MTSPR_SPRG0	0x7c1043a6
+#define KVM_INST_MTSPR_SPRG1	0x7c1143a6
+#define KVM_INST_MTSPR_SPRG2	0x7c1243a6
+#define KVM_INST_MTSPR_SPRG3	0x7c1343a6
+#define KVM_INST_MTSPR_SRR0	0x7c1a03a6
+#define KVM_INST_MTSPR_SRR1	0x7c1b03a6
+#define KVM_INST_MTSPR_DAR	0x7c1303a6
+#define KVM_INST_MTSPR_DSISR	0x7c1203a6
+
+#define KVM_INST_TLBSYNC	0x7c00046c
+#define KVM_INST_MTMSRD_L0	0x7c000164
+#define KVM_INST_MTMSRD_L1	0x7c010164
+#define KVM_INST_MTMSR		0x7c000124
+
+#define KVM_INST_WRTEEI_0	0x7c000146
+#define KVM_INST_WRTEEI_1	0x7c008146
+
+#define KVM_INST_MTSRIN		0x7c0001e4
+
+static bool kvm_patching_worked = true;
+static char kvm_tmp[1024 * 1024];
+static int kvm_tmp_index;
+
+static inline void kvm_patch_ins(u32 *inst, u32 new_inst)
+{
+	*inst = new_inst;
+	flush_icache_range((ulong)inst, (ulong)inst + 4);
+}
+
+static void kvm_patch_ins_ll(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+	kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
+#else
+	kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_ld(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+	kvm_patch_ins(inst, KVM_INST_LD | rt | (addr & 0x0000fffc));
+#else
+	kvm_patch_ins(inst, KVM_INST_LWZ | rt | ((addr + 4) & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_lwz(u32 *inst, long addr, u32 rt)
+{
+	kvm_patch_ins(inst, KVM_INST_LWZ | rt | (addr & 0x0000ffff));
+}
+
+static void kvm_patch_ins_std(u32 *inst, long addr, u32 rt)
+{
+#ifdef CONFIG_64BIT
+	kvm_patch_ins(inst, KVM_INST_STD | rt | (addr & 0x0000fffc));
+#else
+	kvm_patch_ins(inst, KVM_INST_STW | rt | ((addr + 4) & 0x0000fffc));
+#endif
+}
+
+static void kvm_patch_ins_stw(u32 *inst, long addr, u32 rt)
+{
+	kvm_patch_ins(inst, KVM_INST_STW | rt | (addr & 0x0000fffc));
+}
+
+static void kvm_patch_ins_nop(u32 *inst)
+{
+	kvm_patch_ins(inst, KVM_INST_NOP);
+}
+
+static void kvm_patch_ins_b(u32 *inst, int addr)
+{
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
+	/* On relocatable kernels interrupts handlers and our code
+	   can be in different regions, so we don't patch them */
+
+	extern u32 __end_interrupts;
+	if ((ulong)inst < (ulong)&__end_interrupts)
+		return;
+#endif
+
+	kvm_patch_ins(inst, KVM_INST_B | (addr & KVM_INST_B_MASK));
+}
+
+static u32 *kvm_alloc(int len)
+{
+	u32 *p;
+
+	if ((kvm_tmp_index + len) > ARRAY_SIZE(kvm_tmp)) {
+		printk(KERN_ERR "KVM: No more space (%d + %d)\n",
+				kvm_tmp_index, len);
+		kvm_patching_worked = false;
+		return NULL;
+	}
+
+	p = (void*)&kvm_tmp[kvm_tmp_index];
+	kvm_tmp_index += len;
+
+	return p;
+}
+
+extern u32 kvm_emulate_mtmsrd_branch_offs;
+extern u32 kvm_emulate_mtmsrd_reg_offs;
+extern u32 kvm_emulate_mtmsrd_orig_ins_offs;
+extern u32 kvm_emulate_mtmsrd_len;
+extern u32 kvm_emulate_mtmsrd[];
+
+static void kvm_patch_ins_mtmsrd(u32 *inst, u32 rt)
+{
+	u32 *p;
+	int distance_start;
+	int distance_end;
+	ulong next_inst;
+
+	p = kvm_alloc(kvm_emulate_mtmsrd_len * 4);
+	if (!p)
+		return;
+
+	/* Find out where we are and put everything there */
+	distance_start = (ulong)p - (ulong)inst;
+	next_inst = ((ulong)inst + 4);
+	distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsrd_branch_offs];
+
+	/* Make sure we only write valid b instructions */
+	if (distance_start > KVM_INST_B_MAX) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	/* Modify the chunk to fit the invocation */
+	memcpy(p, kvm_emulate_mtmsrd, kvm_emulate_mtmsrd_len * 4);
+	p[kvm_emulate_mtmsrd_branch_offs] |= distance_end & KVM_INST_B_MASK;
+	switch (get_rt(rt)) {
+	case 30:
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
+				 magic_var(scratch2), KVM_RT_30);
+		break;
+	case 31:
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsrd_reg_offs],
+				 magic_var(scratch1), KVM_RT_30);
+		break;
+	default:
+		p[kvm_emulate_mtmsrd_reg_offs] |= rt;
+		break;
+	}
+
+	p[kvm_emulate_mtmsrd_orig_ins_offs] = *inst;
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsrd_len * 4);
+
+	/* Patch the invocation */
+	kvm_patch_ins_b(inst, distance_start);
+}
+
+extern u32 kvm_emulate_mtmsr_branch_offs;
+extern u32 kvm_emulate_mtmsr_reg1_offs;
+extern u32 kvm_emulate_mtmsr_reg2_offs;
+extern u32 kvm_emulate_mtmsr_orig_ins_offs;
+extern u32 kvm_emulate_mtmsr_len;
+extern u32 kvm_emulate_mtmsr[];
+
+static void kvm_patch_ins_mtmsr(u32 *inst, u32 rt)
+{
+	u32 *p;
+	int distance_start;
+	int distance_end;
+	ulong next_inst;
+
+	p = kvm_alloc(kvm_emulate_mtmsr_len * 4);
+	if (!p)
+		return;
+
+	/* Find out where we are and put everything there */
+	distance_start = (ulong)p - (ulong)inst;
+	next_inst = ((ulong)inst + 4);
+	distance_end = next_inst - (ulong)&p[kvm_emulate_mtmsr_branch_offs];
+
+	/* Make sure we only write valid b instructions */
+	if (distance_start > KVM_INST_B_MAX) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	/* Modify the chunk to fit the invocation */
+	memcpy(p, kvm_emulate_mtmsr, kvm_emulate_mtmsr_len * 4);
+	p[kvm_emulate_mtmsr_branch_offs] |= distance_end & KVM_INST_B_MASK;
+
+	/* Make clobbered registers work too */
+	switch (get_rt(rt)) {
+	case 30:
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
+				 magic_var(scratch2), KVM_RT_30);
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
+				 magic_var(scratch2), KVM_RT_30);
+		break;
+	case 31:
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg1_offs],
+				 magic_var(scratch1), KVM_RT_30);
+		kvm_patch_ins_ll(&p[kvm_emulate_mtmsr_reg2_offs],
+				 magic_var(scratch1), KVM_RT_30);
+		break;
+	default:
+		p[kvm_emulate_mtmsr_reg1_offs] |= rt;
+		p[kvm_emulate_mtmsr_reg2_offs] |= rt;
+		break;
+	}
+
+	p[kvm_emulate_mtmsr_orig_ins_offs] = *inst;
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtmsr_len * 4);
+
+	/* Patch the invocation */
+	kvm_patch_ins_b(inst, distance_start);
+}
+
+#ifdef CONFIG_BOOKE
+
+extern u32 kvm_emulate_wrteei_branch_offs;
+extern u32 kvm_emulate_wrteei_ee_offs;
+extern u32 kvm_emulate_wrteei_len;
+extern u32 kvm_emulate_wrteei[];
+
+static void kvm_patch_ins_wrteei(u32 *inst)
+{
+	u32 *p;
+	int distance_start;
+	int distance_end;
+	ulong next_inst;
+
+	p = kvm_alloc(kvm_emulate_wrteei_len * 4);
+	if (!p)
+		return;
+
+	/* Find out where we are and put everything there */
+	distance_start = (ulong)p - (ulong)inst;
+	next_inst = ((ulong)inst + 4);
+	distance_end = next_inst - (ulong)&p[kvm_emulate_wrteei_branch_offs];
+
+	/* Make sure we only write valid b instructions */
+	if (distance_start > KVM_INST_B_MAX) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	/* Modify the chunk to fit the invocation */
+	memcpy(p, kvm_emulate_wrteei, kvm_emulate_wrteei_len * 4);
+	p[kvm_emulate_wrteei_branch_offs] |= distance_end & KVM_INST_B_MASK;
+	p[kvm_emulate_wrteei_ee_offs] |= (*inst & MSR_EE);
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_wrteei_len * 4);
+
+	/* Patch the invocation */
+	kvm_patch_ins_b(inst, distance_start);
+}
+
+#endif
+
+#ifdef CONFIG_PPC_BOOK3S_32
+
+extern u32 kvm_emulate_mtsrin_branch_offs;
+extern u32 kvm_emulate_mtsrin_reg1_offs;
+extern u32 kvm_emulate_mtsrin_reg2_offs;
+extern u32 kvm_emulate_mtsrin_orig_ins_offs;
+extern u32 kvm_emulate_mtsrin_len;
+extern u32 kvm_emulate_mtsrin[];
+
+static void kvm_patch_ins_mtsrin(u32 *inst, u32 rt, u32 rb)
+{
+	u32 *p;
+	int distance_start;
+	int distance_end;
+	ulong next_inst;
+
+	p = kvm_alloc(kvm_emulate_mtsrin_len * 4);
+	if (!p)
+		return;
+
+	/* Find out where we are and put everything there */
+	distance_start = (ulong)p - (ulong)inst;
+	next_inst = ((ulong)inst + 4);
+	distance_end = next_inst - (ulong)&p[kvm_emulate_mtsrin_branch_offs];
+
+	/* Make sure we only write valid b instructions */
+	if (distance_start > KVM_INST_B_MAX) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	/* Modify the chunk to fit the invocation */
+	memcpy(p, kvm_emulate_mtsrin, kvm_emulate_mtsrin_len * 4);
+	p[kvm_emulate_mtsrin_branch_offs] |= distance_end & KVM_INST_B_MASK;
+	p[kvm_emulate_mtsrin_reg1_offs] |= (rb << 10);
+	p[kvm_emulate_mtsrin_reg2_offs] |= rt;
+	p[kvm_emulate_mtsrin_orig_ins_offs] = *inst;
+	flush_icache_range((ulong)p, (ulong)p + kvm_emulate_mtsrin_len * 4);
+
+	/* Patch the invocation */
+	kvm_patch_ins_b(inst, distance_start);
+}
+
+#endif
+
+static void kvm_map_magic_page(void *data)
+{
+	u32 *features = data;
+
+	ulong in[8];
+	ulong out[8];
+
+	in[0] = KVM_MAGIC_PAGE;
+	in[1] = KVM_MAGIC_PAGE;
+
+	kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE);
+
+	*features = out[0];
+}
+
+static void kvm_check_ins(u32 *inst, u32 features)
+{
+	u32 _inst = *inst;
+	u32 inst_no_rt = _inst & ~KVM_MASK_RT;
+	u32 inst_rt = _inst & KVM_MASK_RT;
+
+	switch (inst_no_rt) {
+	/* Loads */
+	case KVM_INST_MFMSR:
+		kvm_patch_ins_ld(inst, magic_var(msr), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SPRG0:
+		kvm_patch_ins_ld(inst, magic_var(sprg0), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SPRG1:
+		kvm_patch_ins_ld(inst, magic_var(sprg1), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SPRG2:
+		kvm_patch_ins_ld(inst, magic_var(sprg2), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SPRG3:
+		kvm_patch_ins_ld(inst, magic_var(sprg3), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SRR0:
+		kvm_patch_ins_ld(inst, magic_var(srr0), inst_rt);
+		break;
+	case KVM_INST_MFSPR_SRR1:
+		kvm_patch_ins_ld(inst, magic_var(srr1), inst_rt);
+		break;
+	case KVM_INST_MFSPR_DAR:
+		kvm_patch_ins_ld(inst, magic_var(dar), inst_rt);
+		break;
+	case KVM_INST_MFSPR_DSISR:
+		kvm_patch_ins_lwz(inst, magic_var(dsisr), inst_rt);
+		break;
+
+	/* Stores */
+	case KVM_INST_MTSPR_SPRG0:
+		kvm_patch_ins_std(inst, magic_var(sprg0), inst_rt);
+		break;
+	case KVM_INST_MTSPR_SPRG1:
+		kvm_patch_ins_std(inst, magic_var(sprg1), inst_rt);
+		break;
+	case KVM_INST_MTSPR_SPRG2:
+		kvm_patch_ins_std(inst, magic_var(sprg2), inst_rt);
+		break;
+	case KVM_INST_MTSPR_SPRG3:
+		kvm_patch_ins_std(inst, magic_var(sprg3), inst_rt);
+		break;
+	case KVM_INST_MTSPR_SRR0:
+		kvm_patch_ins_std(inst, magic_var(srr0), inst_rt);
+		break;
+	case KVM_INST_MTSPR_SRR1:
+		kvm_patch_ins_std(inst, magic_var(srr1), inst_rt);
+		break;
+	case KVM_INST_MTSPR_DAR:
+		kvm_patch_ins_std(inst, magic_var(dar), inst_rt);
+		break;
+	case KVM_INST_MTSPR_DSISR:
+		kvm_patch_ins_stw(inst, magic_var(dsisr), inst_rt);
+		break;
+
+	/* Nops */
+	case KVM_INST_TLBSYNC:
+		kvm_patch_ins_nop(inst);
+		break;
+
+	/* Rewrites */
+	case KVM_INST_MTMSRD_L1:
+		kvm_patch_ins_mtmsrd(inst, inst_rt);
+		break;
+	case KVM_INST_MTMSR:
+	case KVM_INST_MTMSRD_L0:
+		kvm_patch_ins_mtmsr(inst, inst_rt);
+		break;
+	}
+
+	switch (inst_no_rt & ~KVM_MASK_RB) {
+#ifdef CONFIG_PPC_BOOK3S_32
+	case KVM_INST_MTSRIN:
+		if (features & KVM_MAGIC_FEAT_SR) {
+			u32 inst_rb = _inst & KVM_MASK_RB;
+			kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb);
+		}
+		break;
+		break;
+#endif
+	}
+
+	switch (_inst) {
+#ifdef CONFIG_BOOKE
+	case KVM_INST_WRTEEI_0:
+	case KVM_INST_WRTEEI_1:
+		kvm_patch_ins_wrteei(inst);
+		break;
+#endif
+	}
+}
+
+static void kvm_use_magic_page(void)
+{
+	u32 *p;
+	u32 *start, *end;
+	u32 tmp;
+	u32 features;
+
+	/* Tell the host to map the magic page to -4096 on all CPUs */
+	on_each_cpu(kvm_map_magic_page, &features, 1);
+
+	/* Quick self-test to see if the mapping works */
+	if (__get_user(tmp, (u32*)KVM_MAGIC_PAGE)) {
+		kvm_patching_worked = false;
+		return;
+	}
+
+	/* Now loop through all code and find instructions */
+	start = (void*)_stext;
+	end = (void*)_etext;
+
+	for (p = start; p < end; p++)
+		kvm_check_ins(p, features);
+
+	printk(KERN_INFO "KVM: Live patching for a fast VM %s\n",
+			 kvm_patching_worked ? "worked" : "failed");
+}
+
+unsigned long kvm_hypercall(unsigned long *in,
+			    unsigned long *out,
+			    unsigned long nr)
+{
+	unsigned long register r0 asm("r0");
+	unsigned long register r3 asm("r3") = in[0];
+	unsigned long register r4 asm("r4") = in[1];
+	unsigned long register r5 asm("r5") = in[2];
+	unsigned long register r6 asm("r6") = in[3];
+	unsigned long register r7 asm("r7") = in[4];
+	unsigned long register r8 asm("r8") = in[5];
+	unsigned long register r9 asm("r9") = in[6];
+	unsigned long register r10 asm("r10") = in[7];
+	unsigned long register r11 asm("r11") = nr;
+	unsigned long register r12 asm("r12");
+
+	asm volatile("bl	kvm_hypercall_start"
+		     : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
+		       "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
+		       "=r"(r12)
+		     : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
+		       "r"(r9), "r"(r10), "r"(r11)
+		     : "memory", "cc", "xer", "ctr", "lr");
+
+	out[0] = r4;
+	out[1] = r5;
+	out[2] = r6;
+	out[3] = r7;
+	out[4] = r8;
+	out[5] = r9;
+	out[6] = r10;
+	out[7] = r11;
+
+	return r3;
+}
+EXPORT_SYMBOL_GPL(kvm_hypercall);
+
+static int kvm_para_setup(void)
+{
+	extern u32 kvm_hypercall_start;
+	struct device_node *hyper_node;
+	u32 *insts;
+	int len, i;
+
+	hyper_node = of_find_node_by_path("/hypervisor");
+	if (!hyper_node)
+		return -1;
+
+	insts = (u32*)of_get_property(hyper_node, "hcall-instructions", &len);
+	if (len % 4)
+		return -1;
+	if (len > (4 * 4))
+		return -1;
+
+	for (i = 0; i < (len / 4); i++)
+		kvm_patch_ins(&(&kvm_hypercall_start)[i], insts[i]);
+
+	return 0;
+}
+
+static __init void kvm_free_tmp(void)
+{
+	unsigned long start, end;
+
+	start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
+	end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
+
+	/* Free the tmp space we don't need */
+	for (; start < end; start += PAGE_SIZE) {
+		ClearPageReserved(virt_to_page(start));
+		init_page_count(virt_to_page(start));
+		free_page(start);
+		totalram_pages++;
+	}
+}
+
+static int __init kvm_guest_init(void)
+{
+	if (!kvm_para_available())
+		goto free_tmp;
+
+	if (kvm_para_setup())
+		goto free_tmp;
+
+	if (kvm_para_has_feature(KVM_FEATURE_MAGIC_PAGE))
+		kvm_use_magic_page();
+
+#ifdef CONFIG_PPC_BOOK3S_64
+	/* Enable napping */
+	powersave_nap = 1;
+#endif
+
+free_tmp:
+	kvm_free_tmp();
+
+	return 0;
+}
+
+postcore_initcall(kvm_guest_init);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/kvm_emul.S linux-libre-2.6.37-gnu/arch/powerpc/kernel/kvm_emul.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/kvm_emul.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/kvm_emul.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,302 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright SUSE Linux Products GmbH 2010
+ *
+ * Authors: Alexander Graf <agraf@suse.de>
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/kvm_asm.h>
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+
+/* Hypercall entry point. Will be patched with device tree instructions. */
+
+.global kvm_hypercall_start
+kvm_hypercall_start:
+	li	r3, -1
+	nop
+	nop
+	nop
+	blr
+
+#define KVM_MAGIC_PAGE		(-4096)
+
+#ifdef CONFIG_64BIT
+#define LL64(reg, offs, reg2)	ld	reg, (offs)(reg2)
+#define STL64(reg, offs, reg2)	std	reg, (offs)(reg2)
+#else
+#define LL64(reg, offs, reg2)	lwz	reg, (offs + 4)(reg2)
+#define STL64(reg, offs, reg2)	stw	reg, (offs + 4)(reg2)
+#endif
+
+#define SCRATCH_SAVE							\
+	/* Enable critical section. We are critical if			\
+	   shared->critical == r1 */					\
+	STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);		\
+									\
+	/* Save state */						\
+	PPC_STL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
+	PPC_STL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
+	mfcr	r31;							\
+	stw	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);
+
+#define SCRATCH_RESTORE							\
+	/* Restore state */						\
+	PPC_LL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
+	lwz	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);		\
+	mtcr	r30;							\
+	PPC_LL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
+									\
+	/* Disable critical section. We are critical if			\
+	   shared->critical == r1 and r2 is always != r1 */		\
+	STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
+
+.global kvm_emulate_mtmsrd
+kvm_emulate_mtmsrd:
+
+	SCRATCH_SAVE
+
+	/* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
+	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+	lis	r30, (~(MSR_EE | MSR_RI))@h
+	ori	r30, r30, (~(MSR_EE | MSR_RI))@l
+	and	r31, r31, r30
+
+	/* OR the register's (MSR_EE|MSR_RI) on MSR */
+kvm_emulate_mtmsrd_reg:
+	ori	r30, r0, 0
+	andi.	r30, r30, (MSR_EE|MSR_RI)
+	or	r31, r31, r30
+
+	/* Put MSR back into magic page */
+	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	/* Check if we have to fetch an interrupt */
+	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+	cmpwi	r31, 0
+	beq+	no_check
+
+	/* Check if we may trigger an interrupt */
+	andi.	r30, r30, MSR_EE
+	beq	no_check
+
+	SCRATCH_RESTORE
+
+	/* Nag hypervisor */
+kvm_emulate_mtmsrd_orig_ins:
+	tlbsync
+
+	b	kvm_emulate_mtmsrd_branch
+
+no_check:
+
+	SCRATCH_RESTORE
+
+	/* Go back to caller */
+kvm_emulate_mtmsrd_branch:
+	b	.
+kvm_emulate_mtmsrd_end:
+
+.global kvm_emulate_mtmsrd_branch_offs
+kvm_emulate_mtmsrd_branch_offs:
+	.long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_reg_offs
+kvm_emulate_mtmsrd_reg_offs:
+	.long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_orig_ins_offs
+kvm_emulate_mtmsrd_orig_ins_offs:
+	.long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4
+
+.global kvm_emulate_mtmsrd_len
+kvm_emulate_mtmsrd_len:
+	.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
+
+
+#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI)
+#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
+
+.global kvm_emulate_mtmsr
+kvm_emulate_mtmsr:
+
+	SCRATCH_SAVE
+
+	/* Fetch old MSR in r31 */
+	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	/* Find the changed bits between old and new MSR */
+kvm_emulate_mtmsr_reg1:
+	ori	r30, r0, 0
+	xor	r31, r30, r31
+
+	/* Check if we need to really do mtmsr */
+	LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
+	and.	r31, r31, r30
+
+	/* No critical bits changed? Maybe we can stay in the guest. */
+	beq	maybe_stay_in_guest
+
+do_mtmsr:
+
+	SCRATCH_RESTORE
+
+	/* Just fire off the mtmsr if it's critical */
+kvm_emulate_mtmsr_orig_ins:
+	mtmsr	r0
+
+	b	kvm_emulate_mtmsr_branch
+
+maybe_stay_in_guest:
+
+	/* Get the target register in r30 */
+kvm_emulate_mtmsr_reg2:
+	ori	r30, r0, 0
+
+	/* Check if we have to fetch an interrupt */
+	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
+	cmpwi	r31, 0
+	beq+	no_mtmsr
+
+	/* Check if we may trigger an interrupt */
+	andi.	r31, r30, MSR_EE
+	beq	no_mtmsr
+
+	b	do_mtmsr
+
+no_mtmsr:
+
+	/* Put MSR into magic page because we don't call mtmsr */
+	STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	SCRATCH_RESTORE
+
+	/* Go back to caller */
+kvm_emulate_mtmsr_branch:
+	b	.
+kvm_emulate_mtmsr_end:
+
+.global kvm_emulate_mtmsr_branch_offs
+kvm_emulate_mtmsr_branch_offs:
+	.long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_reg1_offs
+kvm_emulate_mtmsr_reg1_offs:
+	.long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_reg2_offs
+kvm_emulate_mtmsr_reg2_offs:
+	.long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_orig_ins_offs
+kvm_emulate_mtmsr_orig_ins_offs:
+	.long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
+
+.global kvm_emulate_mtmsr_len
+kvm_emulate_mtmsr_len:
+	.long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
+
+
+
+.global kvm_emulate_wrteei
+kvm_emulate_wrteei:
+
+	SCRATCH_SAVE
+
+	/* Fetch old MSR in r31 */
+	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	/* Remove MSR_EE from old MSR */
+	li	r30, 0
+	ori	r30, r30, MSR_EE
+	andc	r31, r31, r30
+
+	/* OR new MSR_EE onto the old MSR */
+kvm_emulate_wrteei_ee:
+	ori	r31, r31, 0
+
+	/* Write new MSR value back */
+	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+
+	SCRATCH_RESTORE
+
+	/* Go back to caller */
+kvm_emulate_wrteei_branch:
+	b	.
+kvm_emulate_wrteei_end:
+
+.global kvm_emulate_wrteei_branch_offs
+kvm_emulate_wrteei_branch_offs:
+	.long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
+
+.global kvm_emulate_wrteei_ee_offs
+kvm_emulate_wrteei_ee_offs:
+	.long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
+
+.global kvm_emulate_wrteei_len
+kvm_emulate_wrteei_len:
+	.long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
+
+
+.global kvm_emulate_mtsrin
+kvm_emulate_mtsrin:
+
+	SCRATCH_SAVE
+
+	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
+	andi.	r31, r31, MSR_DR | MSR_IR
+	beq	kvm_emulate_mtsrin_reg1
+
+	SCRATCH_RESTORE
+
+kvm_emulate_mtsrin_orig_ins:
+	nop
+	b	kvm_emulate_mtsrin_branch
+
+kvm_emulate_mtsrin_reg1:
+	/* rX >> 26 */
+	rlwinm  r30,r0,6,26,29
+
+kvm_emulate_mtsrin_reg2:
+	stw	r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
+
+	SCRATCH_RESTORE
+
+	/* Go back to caller */
+kvm_emulate_mtsrin_branch:
+	b	.
+kvm_emulate_mtsrin_end:
+
+.global kvm_emulate_mtsrin_branch_offs
+kvm_emulate_mtsrin_branch_offs:
+	.long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_reg1_offs
+kvm_emulate_mtsrin_reg1_offs:
+	.long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_reg2_offs
+kvm_emulate_mtsrin_reg2_offs:
+	.long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_orig_ins_offs
+kvm_emulate_mtsrin_orig_ins_offs:
+	.long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
+
+.global kvm_emulate_mtsrin_len
+kvm_emulate_mtsrin_len:
+	.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/legacy_serial.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/legacy_serial.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/legacy_serial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/legacy_serial.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,14 +52,14 @@
 				  phys_addr_t taddr, unsigned long irq,
 				  upf_t flags, int irq_check_parent)
 {
-	const u32 *clk, *spd;
+	const __be32 *clk, *spd;
 	u32 clock = BASE_BAUD * 16;
 	int index;
 
 	/* get clock freq. if present */
 	clk = of_get_property(np, "clock-frequency", NULL);
 	if (clk && *clk)
-		clock = *clk;
+		clock = be32_to_cpup(clk);
 
 	/* get default speed if present */
 	spd = of_get_property(np, "current-speed", NULL);
@@ -109,7 +109,7 @@
 	legacy_serial_infos[index].taddr = taddr;
 	legacy_serial_infos[index].np = of_node_get(np);
 	legacy_serial_infos[index].clock = clock;
-	legacy_serial_infos[index].speed = spd ? *spd : 0;
+	legacy_serial_infos[index].speed = spd ? be32_to_cpup(spd) : 0;
 	legacy_serial_infos[index].irq_check_parent = irq_check_parent;
 
 	printk(KERN_DEBUG "Found legacy serial port %d for %s\n",
@@ -168,7 +168,7 @@
 static int __init add_legacy_isa_port(struct device_node *np,
 				      struct device_node *isa_brg)
 {
-	const u32 *reg;
+	const __be32 *reg;
 	const char *typep;
 	int index = -1;
 	u64 taddr;
@@ -181,7 +181,7 @@
 		return -1;
 
 	/* Verify it's an IO port, we don't support anything else */
-	if (!(reg[0] & 0x00000001))
+	if (!(be32_to_cpu(reg[0]) & 0x00000001))
 		return -1;
 
 	/* Now look for an "ibm,aix-loc" property that gives us ordering
@@ -202,7 +202,7 @@
 		taddr = 0;
 
 	/* Add port, irq will be dealt with later */
-	return add_legacy_port(np, index, UPIO_PORT, reg[1], taddr,
+	return add_legacy_port(np, index, UPIO_PORT, be32_to_cpu(reg[1]), taddr,
 			       NO_IRQ, UPF_BOOT_AUTOCONF, 0);
 
 }
@@ -251,9 +251,9 @@
 	 * we get to their "reg" property
 	 */
 	if (np != pci_dev) {
-		const u32 *reg = of_get_property(np, "reg", NULL);
-		if (reg && (*reg < 4))
-			index = lindex = *reg;
+		const __be32 *reg = of_get_property(np, "reg", NULL);
+		if (reg && (be32_to_cpup(reg) < 4))
+			index = lindex = be32_to_cpup(reg);
 	}
 
 	/* Local index means it's the Nth port in the PCI chip. Unfortunately
@@ -507,7 +507,7 @@
 	struct device_node *prom_stdout = NULL;
 	int i, speed = 0, offset = 0;
 	const char *name;
-	const u32 *spd;
+	const __be32 *spd;
 
 	DBG(" -> check_legacy_serial_console()\n");
 
@@ -547,7 +547,7 @@
 	}
 	spd = of_get_property(prom_stdout, "current-speed", NULL);
 	if (spd)
-		speed = *spd;
+		speed = be32_to_cpup(spd);
 
 	if (strcmp(name, "serial") != 0)
 		goto not_found;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/lparcfg.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/lparcfg.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/lparcfg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/lparcfg.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,7 +56,7 @@
 
 	for_each_possible_cpu(cpu) {
 		if (firmware_has_feature(FW_FEATURE_ISERIES))
-			sum_purr += lppaca[cpu].emulated_time_base;
+			sum_purr += lppaca_of(cpu).emulated_time_base;
 		else {
 			struct cpu_usage *cu;
 
@@ -263,7 +263,7 @@
 	           ppp_data.active_system_procs);
 
 	/* pool related entries are apropriate for shared configs */
-	if (lppaca[0].shared_proc) {
+	if (lppaca_of(0).shared_proc) {
 		unsigned long pool_idle_time, pool_procs;
 
 		seq_printf(m, "pool=%d\n", ppp_data.pool_num);
@@ -460,8 +460,8 @@
 		return;
 
 	for_each_possible_cpu(cpu) {
-		cmo_faults += lppaca[cpu].cmo_faults;
-		cmo_fault_time += lppaca[cpu].cmo_fault_time;
+		cmo_faults += lppaca_of(cpu).cmo_faults;
+		cmo_fault_time += lppaca_of(cpu).cmo_fault_time;
 	}
 
 	seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
@@ -479,8 +479,8 @@
 	unsigned long dispatch_dispersions = 0;
 
 	for_each_possible_cpu(cpu) {
-		dispatches += lppaca[cpu].yield_count;
-		dispatch_dispersions += lppaca[cpu].dispersion_count;
+		dispatches += lppaca_of(cpu).yield_count;
+		dispatch_dispersions += lppaca_of(cpu).dispersion_count;
 	}
 
 	seq_printf(m, "dispatches=%lu\n", dispatches);
@@ -545,7 +545,7 @@
 	seq_printf(m, "partition_potential_processors=%d\n",
 		   partition_potential_processors);
 
-	seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
+	seq_printf(m, "shared_processor_mode=%d\n", lppaca_of(0).shared_proc);
 
 	seq_printf(m, "slb_size=%d\n", mmu_slb_size);
 
@@ -780,6 +780,7 @@
 	.write		= lparcfg_write,
 	.open		= lparcfg_open,
 	.release	= single_release,
+	.llseek		= seq_lseek,
 };
 
 static int __init lparcfg_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/machine_kexec_32.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/machine_kexec_32.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/machine_kexec_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/machine_kexec_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,6 +39,10 @@
 	/* Interrupts aren't acceptable while we reboot */
 	local_irq_disable();
 
+	/* mask each interrupt so we are in a more sane state for the
+	 * kexec kernel */
+	machine_kexec_mask_interrupts();
+
 	page_list = image->head;
 
 	/* we need both effective and real address here */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/machine_kexec.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/machine_kexec.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/machine_kexec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/machine_kexec.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,10 +14,34 @@
 #include <linux/threads.h>
 #include <linux/memblock.h>
 #include <linux/of.h>
+#include <linux/irq.h>
+
 #include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
 
+void machine_kexec_mask_interrupts(void) {
+	unsigned int i;
+
+	for_each_irq(i) {
+		struct irq_desc *desc = irq_to_desc(i);
+
+		if (!desc || !desc->chip)
+			continue;
+
+		if (desc->chip->eoi &&
+		    desc->status & IRQ_INPROGRESS)
+			desc->chip->eoi(i);
+
+		if (desc->chip->mask)
+			desc->chip->mask(i);
+
+		if (desc->chip->disable &&
+		    !(desc->status & IRQ_DISABLED))
+			desc->chip->disable(i);
+	}
+}
+
 void machine_crash_shutdown(struct pt_regs *regs)
 {
 	if (ppc_md.machine_crash_shutdown)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/Makefile linux-libre-2.6.37-gnu/arch/powerpc/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -55,7 +55,9 @@
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)	+= smp-tbsync.o
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o
+ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)		+= idle_e500.o
+endif
 obj-$(CONFIG_6xx)		+= idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)		+= tau_6xx.o
 obj-$(CONFIG_HIBERNATION)	+= swsusp.o suspend.o
@@ -67,7 +69,7 @@
 obj64-$(CONFIG_HIBERNATION)	+= swsusp_asm64.o
 obj-$(CONFIG_MODULES)		+= module.o module_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_44x)		+= cpu_setup_44x.o
-obj-$(CONFIG_FSL_BOOKE)		+= cpu_setup_fsl_booke.o dbell.o
+obj-$(CONFIG_PPC_FSL_BOOK3E)	+= cpu_setup_fsl_booke.o dbell.o
 obj-$(CONFIG_PPC_BOOK3E_64)	+= dbell.o
 
 extra-y				:= head_$(CONFIG_WORD_SIZE).o
@@ -127,6 +129,8 @@
 obj-y				+= ppc_save_regs.o
 endif
 
+obj-$(CONFIG_KVM_GUEST)		+= kvm.o kvm_emul.o
+
 # Disable GCOV in odd or sensitive code
 GCOV_PROFILE_prom_init.o := n
 GCOV_PROFILE_ftrace.o := n
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/paca.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/paca.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/paca.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/paca.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,20 @@
 #ifdef CONFIG_PPC_BOOK3S
 
 /*
+ * We only have to have statically allocated lppaca structs on
+ * legacy iSeries, which supports at most 64 cpus.
+ */
+#ifdef CONFIG_PPC_ISERIES
+#if NR_CPUS < 64
+#define NR_LPPACAS	NR_CPUS
+#else
+#define NR_LPPACAS	64
+#endif
+#else /* not iSeries */
+#define NR_LPPACAS	1
+#endif
+
+/*
  * The structure which the hypervisor knows about - this structure
  * should not cross a page boundary.  The vpa_init/register_vpa call
  * is now known to fail if the lppaca structure crosses a page
@@ -36,7 +50,7 @@
  * will suffice to ensure that it doesn't cross a page boundary.
  */
 struct lppaca lppaca[] = {
-	[0 ... (NR_CPUS-1)] = {
+	[0 ... (NR_LPPACAS-1)] = {
 		.desc = 0xd397d781,	/* "LpPa" */
 		.size = sizeof(struct lppaca),
 		.dyn_proc_status = 2,
@@ -49,6 +63,54 @@
 	},
 };
 
+static struct lppaca *extra_lppacas;
+static long __initdata lppaca_size;
+
+static void allocate_lppacas(int nr_cpus, unsigned long limit)
+{
+	if (nr_cpus <= NR_LPPACAS)
+		return;
+
+	lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
+				 (nr_cpus - NR_LPPACAS));
+	extra_lppacas = __va(memblock_alloc_base(lppaca_size,
+						 PAGE_SIZE, limit));
+}
+
+static struct lppaca *new_lppaca(int cpu)
+{
+	struct lppaca *lp;
+
+	if (cpu < NR_LPPACAS)
+		return &lppaca[cpu];
+
+	lp = extra_lppacas + (cpu - NR_LPPACAS);
+	*lp = lppaca[0];
+
+	return lp;
+}
+
+static void free_lppacas(void)
+{
+	long new_size = 0, nr;
+
+	if (!lppaca_size)
+		return;
+	nr = num_possible_cpus() - NR_LPPACAS;
+	if (nr > 0)
+		new_size = PAGE_ALIGN(nr * sizeof(struct lppaca));
+	if (new_size >= lppaca_size)
+		return;
+
+	memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
+	lppaca_size = new_size;
+}
+
+#else
+
+static inline void allocate_lppacas(int nr_cpus, unsigned long limit) { }
+static inline void free_lppacas(void) { }
+
 #endif /* CONFIG_PPC_BOOK3S */
 
 #ifdef CONFIG_PPC_STD_MMU_64
@@ -88,7 +150,7 @@
 	unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
 
 #ifdef CONFIG_PPC_BOOK3S
-	new_paca->lppaca_ptr = &lppaca[cpu];
+	new_paca->lppaca_ptr = new_lppaca(cpu);
 #else
 	new_paca->kernel_pgd = swapper_pg_dir;
 #endif
@@ -127,7 +189,7 @@
 	 * the first segment. On iSeries they must be within the area mapped
 	 * by the HV, which is HvPagesToMap * HVPAGESIZE bytes.
 	 */
-	limit = min(0x10000000ULL, memblock.rmo_size);
+	limit = min(0x10000000ULL, ppc64_rma_size);
 	if (firmware_has_feature(FW_FEATURE_ISERIES))
 		limit = min(limit, HvPagesToMap * HVPAGESIZE);
 
@@ -144,6 +206,8 @@
 	printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
 		paca_size, nr_cpus, paca);
 
+	allocate_lppacas(nr_cpus, limit);
+
 	/* Can't use for_each_*_cpu, as they aren't functional yet */
 	for (cpu = 0; cpu < nr_cpus; cpu++)
 		initialise_paca(&paca[cpu], cpu);
@@ -164,4 +228,6 @@
 		paca_size - new_size);
 
 	paca_size = new_size;
+
+	free_lppacas();
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/pci-common.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/pci-common.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/pci-common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/pci-common.c	2011-01-04 19:50:19.000000000 -0500
@@ -1090,8 +1090,6 @@
 		 bus->number, bus->self ? pci_name(bus->self) : "PHB");
 
 	list_for_each_entry(dev, &bus->devices, bus_list) {
-		struct dev_archdata *sd = &dev->dev.archdata;
-
 		/* Cardbus can call us to add new devices to a bus, so ignore
 		 * those who are already fully discovered
 		 */
@@ -1107,7 +1105,7 @@
 		set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
 
 		/* Hook up default DMA ops */
-		sd->dma_ops = pci_dma_ops;
+		set_dma_ops(&dev->dev, pci_dma_ops);
 		set_dma_offset(&dev->dev, PCI_DRAM_OFFSET);
 
 		/* Additional platform DMA/iommu setup */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_callchain.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_callchain.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_callchain.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_callchain.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,18 +23,6 @@
 #include "ppc32.h"
 #endif
 
-/*
- * Store another value in a callchain_entry.
- */
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-	unsigned int nr = entry->nr;
-
-	if (nr < PERF_MAX_STACK_DEPTH) {
-		entry->ip[nr] = ip;
-		entry->nr = nr + 1;
-	}
-}
 
 /*
  * Is sp valid as the address of the next kernel stack frame after prev_sp?
@@ -58,8 +46,8 @@
 	return 0;
 }
 
-static void perf_callchain_kernel(struct pt_regs *regs,
-				  struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
 	unsigned long sp, next_sp;
 	unsigned long next_ip;
@@ -69,8 +57,7 @@
 
 	lr = regs->link;
 	sp = regs->gpr[1];
-	callchain_store(entry, PERF_CONTEXT_KERNEL);
-	callchain_store(entry, regs->nip);
+	perf_callchain_store(entry, regs->nip);
 
 	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
 		return;
@@ -89,7 +76,7 @@
 			next_ip = regs->nip;
 			lr = regs->link;
 			level = 0;
-			callchain_store(entry, PERF_CONTEXT_KERNEL);
+			perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
 
 		} else {
 			if (level == 0)
@@ -111,7 +98,7 @@
 			++level;
 		}
 
-		callchain_store(entry, next_ip);
+		perf_callchain_store(entry, next_ip);
 		if (!valid_next_sp(next_sp, sp))
 			return;
 		sp = next_sp;
@@ -233,8 +220,8 @@
 		puc == (unsigned long) &sf->uc;
 }
 
-static void perf_callchain_user_64(struct pt_regs *regs,
-				   struct perf_callchain_entry *entry)
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
 {
 	unsigned long sp, next_sp;
 	unsigned long next_ip;
@@ -246,8 +233,7 @@
 	next_ip = regs->nip;
 	lr = regs->link;
 	sp = regs->gpr[1];
-	callchain_store(entry, PERF_CONTEXT_USER);
-	callchain_store(entry, next_ip);
+	perf_callchain_store(entry, next_ip);
 
 	for (;;) {
 		fp = (unsigned long __user *) sp;
@@ -276,14 +262,14 @@
 			    read_user_stack_64(&uregs[PT_R1], &sp))
 				return;
 			level = 0;
-			callchain_store(entry, PERF_CONTEXT_USER);
-			callchain_store(entry, next_ip);
+			perf_callchain_store(entry, PERF_CONTEXT_USER);
+			perf_callchain_store(entry, next_ip);
 			continue;
 		}
 
 		if (level == 0)
 			next_ip = lr;
-		callchain_store(entry, next_ip);
+		perf_callchain_store(entry, next_ip);
 		++level;
 		sp = next_sp;
 	}
@@ -315,8 +301,8 @@
 	return __get_user_inatomic(*ret, ptr);
 }
 
-static inline void perf_callchain_user_64(struct pt_regs *regs,
-					  struct perf_callchain_entry *entry)
+static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
+					  struct pt_regs *regs)
 {
 }
 
@@ -435,8 +421,8 @@
 	return mctx->mc_gregs;
 }
 
-static void perf_callchain_user_32(struct pt_regs *regs,
-				   struct perf_callchain_entry *entry)
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
 {
 	unsigned int sp, next_sp;
 	unsigned int next_ip;
@@ -447,8 +433,7 @@
 	next_ip = regs->nip;
 	lr = regs->link;
 	sp = regs->gpr[1];
-	callchain_store(entry, PERF_CONTEXT_USER);
-	callchain_store(entry, next_ip);
+	perf_callchain_store(entry, next_ip);
 
 	while (entry->nr < PERF_MAX_STACK_DEPTH) {
 		fp = (unsigned int __user *) (unsigned long) sp;
@@ -470,45 +455,24 @@
 			    read_user_stack_32(&uregs[PT_R1], &sp))
 				return;
 			level = 0;
-			callchain_store(entry, PERF_CONTEXT_USER);
-			callchain_store(entry, next_ip);
+			perf_callchain_store(entry, PERF_CONTEXT_USER);
+			perf_callchain_store(entry, next_ip);
 			continue;
 		}
 
 		if (level == 0)
 			next_ip = lr;
-		callchain_store(entry, next_ip);
+		perf_callchain_store(entry, next_ip);
 		++level;
 		sp = next_sp;
 	}
 }
 
-/*
- * Since we can't get PMU interrupts inside a PMU interrupt handler,
- * we don't need separate irq and nmi entries here.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, cpu_perf_callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-	struct perf_callchain_entry *entry = &__get_cpu_var(cpu_perf_callchain);
-
-	entry->nr = 0;
-
-	if (!user_mode(regs)) {
-		perf_callchain_kernel(regs, entry);
-		if (current->mm)
-			regs = task_pt_regs(current);
-		else
-			regs = NULL;
-	}
-
-	if (regs) {
-		if (current_is_64bit())
-			perf_callchain_user_64(regs, entry);
-		else
-			perf_callchain_user_32(regs, entry);
-	}
-
-	return entry;
+	if (current_is_64bit())
+		perf_callchain_user_64(entry, regs);
+	else
+		perf_callchain_user_32(entry, regs);
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -402,6 +402,9 @@
 {
 	s64 val, delta, prev;
 
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
 	if (!event->hw.idx)
 		return;
 	/*
@@ -517,7 +520,7 @@
  * Disable all events to prevent PMU interrupts and to allow
  * events to be added or removed.
  */
-void hw_perf_disable(void)
+static void power_pmu_disable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw;
 	unsigned long flags;
@@ -565,7 +568,7 @@
  * If we were previously disabled and events were added, then
  * put the new config on the PMU.
  */
-void hw_perf_enable(void)
+static void power_pmu_enable(struct pmu *pmu)
 {
 	struct perf_event *event;
 	struct cpu_hw_events *cpuhw;
@@ -672,6 +675,8 @@
 		}
 		local64_set(&event->hw.prev_count, val);
 		event->hw.idx = idx;
+		if (event->hw.state & PERF_HES_STOPPED)
+			val = 0;
 		write_pmc(idx, val);
 		perf_event_update_userpage(event);
 	}
@@ -727,7 +732,7 @@
  * re-enable the PMU in order to get hw_perf_enable to do the
  * actual work of reconfiguring the PMU.
  */
-static int power_pmu_enable(struct perf_event *event)
+static int power_pmu_add(struct perf_event *event, int ef_flags)
 {
 	struct cpu_hw_events *cpuhw;
 	unsigned long flags;
@@ -735,7 +740,7 @@
 	int ret = -EAGAIN;
 
 	local_irq_save(flags);
-	perf_disable();
+	perf_pmu_disable(event->pmu);
 
 	/*
 	 * Add the event to the list (if there is room)
@@ -749,6 +754,9 @@
 	cpuhw->events[n0] = event->hw.config;
 	cpuhw->flags[n0] = event->hw.event_base;
 
+	if (!(ef_flags & PERF_EF_START))
+		event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
 	/*
 	 * If group events scheduling transaction was started,
 	 * skip the schedulability test here, it will be peformed
@@ -769,7 +777,7 @@
 
 	ret = 0;
  out:
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 	return ret;
 }
@@ -777,14 +785,14 @@
 /*
  * Remove a event from the PMU.
  */
-static void power_pmu_disable(struct perf_event *event)
+static void power_pmu_del(struct perf_event *event, int ef_flags)
 {
 	struct cpu_hw_events *cpuhw;
 	long i;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	perf_disable();
+	perf_pmu_disable(event->pmu);
 
 	power_pmu_read(event);
 
@@ -821,34 +829,60 @@
 		cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
 	}
 
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 }
 
 /*
- * Re-enable interrupts on a event after they were throttled
- * because they were coming too fast.
+ * POWER-PMU does not support disabling individual counters, hence
+ * program their cycle counter to their max value and ignore the interrupts.
  */
-static void power_pmu_unthrottle(struct perf_event *event)
+
+static void power_pmu_start(struct perf_event *event, int ef_flags)
 {
-	s64 val, left;
 	unsigned long flags;
+	s64 left;
 
 	if (!event->hw.idx || !event->hw.sample_period)
 		return;
+
+	if (!(event->hw.state & PERF_HES_STOPPED))
+		return;
+
+	if (ef_flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
 	local_irq_save(flags);
-	perf_disable();
+	perf_pmu_disable(event->pmu);
+
+	event->hw.state = 0;
+	left = local64_read(&event->hw.period_left);
+	write_pmc(event->hw.idx, left);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
+
+static void power_pmu_stop(struct perf_event *event, int ef_flags)
+{
+	unsigned long flags;
+
+	if (!event->hw.idx || !event->hw.sample_period)
+		return;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
 	power_pmu_read(event);
-	left = event->hw.sample_period;
-	event->hw.last_period = left;
-	val = 0;
-	if (left < 0x80000000L)
-		val = 0x80000000L - left;
-	write_pmc(event->hw.idx, val);
-	local64_set(&event->hw.prev_count, val);
-	local64_set(&event->hw.period_left, left);
+	event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	write_pmc(event->hw.idx, 0);
+
 	perf_event_update_userpage(event);
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 }
 
@@ -857,10 +891,11 @@
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-void power_pmu_start_txn(const struct pmu *pmu)
+void power_pmu_start_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
+	perf_pmu_disable(pmu);
 	cpuhw->group_flag |= PERF_EVENT_TXN;
 	cpuhw->n_txn_start = cpuhw->n_events;
 }
@@ -870,11 +905,12 @@
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-void power_pmu_cancel_txn(const struct pmu *pmu)
+void power_pmu_cancel_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
 	cpuhw->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
 }
 
 /*
@@ -882,7 +918,7 @@
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-int power_pmu_commit_txn(const struct pmu *pmu)
+int power_pmu_commit_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw;
 	long i, n;
@@ -901,19 +937,10 @@
 		cpuhw->event[i]->hw.config = cpuhw->events[i];
 
 	cpuhw->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
 	return 0;
 }
 
-struct pmu power_pmu = {
-	.enable		= power_pmu_enable,
-	.disable	= power_pmu_disable,
-	.read		= power_pmu_read,
-	.unthrottle	= power_pmu_unthrottle,
-	.start_txn	= power_pmu_start_txn,
-	.cancel_txn	= power_pmu_cancel_txn,
-	.commit_txn	= power_pmu_commit_txn,
-};
-
 /*
  * Return 1 if we might be able to put event on a limited PMC,
  * or 0 if not.
@@ -1014,7 +1041,7 @@
 	return 0;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int power_pmu_event_init(struct perf_event *event)
 {
 	u64 ev;
 	unsigned long flags;
@@ -1026,25 +1053,27 @@
 	struct cpu_hw_events *cpuhw;
 
 	if (!ppmu)
-		return ERR_PTR(-ENXIO);
+		return -ENOENT;
+
 	switch (event->attr.type) {
 	case PERF_TYPE_HARDWARE:
 		ev = event->attr.config;
 		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-			return ERR_PTR(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 		ev = ppmu->generic_events[ev];
 		break;
 	case PERF_TYPE_HW_CACHE:
 		err = hw_perf_cache_event(event->attr.config, &ev);
 		if (err)
-			return ERR_PTR(err);
+			return err;
 		break;
 	case PERF_TYPE_RAW:
 		ev = event->attr.config;
 		break;
 	default:
-		return ERR_PTR(-EINVAL);
+		return -ENOENT;
 	}
+
 	event->hw.config_base = ev;
 	event->hw.idx = 0;
 
@@ -1063,7 +1092,7 @@
 	 * XXX we should check if the task is an idle task.
 	 */
 	flags = 0;
-	if (event->ctx->task)
+	if (event->attach_state & PERF_ATTACH_TASK)
 		flags |= PPMU_ONLY_COUNT_RUN;
 
 	/*
@@ -1081,7 +1110,7 @@
 			 */
 			ev = normal_pmc_alternative(ev, flags);
 			if (!ev)
-				return ERR_PTR(-EINVAL);
+				return -EINVAL;
 		}
 	}
 
@@ -1095,19 +1124,19 @@
 		n = collect_events(event->group_leader, ppmu->n_counter - 1,
 				   ctrs, events, cflags);
 		if (n < 0)
-			return ERR_PTR(-EINVAL);
+			return -EINVAL;
 	}
 	events[n] = ev;
 	ctrs[n] = event;
 	cflags[n] = flags;
 	if (check_excludes(ctrs, cflags, n, 1))
-		return ERR_PTR(-EINVAL);
+		return -EINVAL;
 
 	cpuhw = &get_cpu_var(cpu_hw_events);
 	err = power_check_constraints(cpuhw, events, cflags, n + 1);
 	put_cpu_var(cpu_hw_events);
 	if (err)
-		return ERR_PTR(-EINVAL);
+		return -EINVAL;
 
 	event->hw.config = events[n];
 	event->hw.event_base = cflags[n];
@@ -1132,11 +1161,23 @@
 	}
 	event->destroy = hw_perf_event_destroy;
 
-	if (err)
-		return ERR_PTR(err);
-	return &power_pmu;
+	return err;
 }
 
+struct pmu power_pmu = {
+	.pmu_enable	= power_pmu_enable,
+	.pmu_disable	= power_pmu_disable,
+	.event_init	= power_pmu_event_init,
+	.add		= power_pmu_add,
+	.del		= power_pmu_del,
+	.start		= power_pmu_start,
+	.stop		= power_pmu_stop,
+	.read		= power_pmu_read,
+	.start_txn	= power_pmu_start_txn,
+	.cancel_txn	= power_pmu_cancel_txn,
+	.commit_txn	= power_pmu_commit_txn,
+};
+
 /*
  * A counter has overflowed; update its count and record
  * things if requested.  Note that interrupts are hard-disabled
@@ -1149,6 +1190,11 @@
 	s64 prev, delta, left;
 	int record = 0;
 
+	if (event->hw.state & PERF_HES_STOPPED) {
+		write_pmc(event->hw.idx, 0);
+		return;
+	}
+
 	/* we don't have to worry about interrupts here */
 	prev = local64_read(&event->hw.prev_count);
 	delta = (val - prev) & 0xfffffffful;
@@ -1171,6 +1217,11 @@
 			val = 0x80000000LL - left;
 	}
 
+	write_pmc(event->hw.idx, val);
+	local64_set(&event->hw.prev_count, val);
+	local64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+
 	/*
 	 * Finally record data if requested.
 	 */
@@ -1183,23 +1234,9 @@
 		if (event->attr.sample_type & PERF_SAMPLE_ADDR)
 			perf_get_data_addr(regs, &data.addr);
 
-		if (perf_event_overflow(event, nmi, &data, regs)) {
-			/*
-			 * Interrupts are coming too fast - throttle them
-			 * by setting the event to 0, so it will be
-			 * at least 2^30 cycles until the next interrupt
-			 * (assuming each event counts at most 2 counts
-			 * per cycle).
-			 */
-			val = 0;
-			left = ~0ULL >> 1;
-		}
+		if (perf_event_overflow(event, nmi, &data, regs))
+			power_pmu_stop(event, 0);
 	}
-
-	write_pmc(event->hw.idx, val);
-	local64_set(&event->hw.prev_count, val);
-	local64_set(&event->hw.period_left, left);
-	perf_event_update_userpage(event);
 }
 
 /*
@@ -1342,6 +1379,7 @@
 		freeze_events_kernel = MMCR0_FCHV;
 #endif /* CONFIG_PPC64 */
 
+	perf_pmu_register(&power_pmu);
 	perf_cpu_notifier(power_pmu_notifier);
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_event_fsl_emb.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_event_fsl_emb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/perf_event_fsl_emb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/perf_event_fsl_emb.c	2011-01-04 19:50:19.000000000 -0500
@@ -156,6 +156,9 @@
 {
 	s64 val, delta, prev;
 
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
 	/*
 	 * Performance monitor interrupts come even when interrupts
 	 * are soft-disabled, as long as interrupts are hard-enabled.
@@ -177,7 +180,7 @@
  * Disable all events to prevent PMU interrupts and to allow
  * events to be added or removed.
  */
-void hw_perf_disable(void)
+static void fsl_emb_pmu_disable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw;
 	unsigned long flags;
@@ -216,7 +219,7 @@
  * If we were previously disabled and events were added, then
  * put the new config on the PMU.
  */
-void hw_perf_enable(void)
+static void fsl_emb_pmu_enable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw;
 	unsigned long flags;
@@ -262,8 +265,8 @@
 	return n;
 }
 
-/* perf must be disabled, context locked on entry */
-static int fsl_emb_pmu_enable(struct perf_event *event)
+/* context locked on entry */
+static int fsl_emb_pmu_add(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuhw;
 	int ret = -EAGAIN;
@@ -271,6 +274,7 @@
 	u64 val;
 	int i;
 
+	perf_pmu_disable(event->pmu);
 	cpuhw = &get_cpu_var(cpu_hw_events);
 
 	if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
@@ -301,6 +305,12 @@
 			val = 0x80000000L - left;
 	}
 	local64_set(&event->hw.prev_count, val);
+
+	if (!(flags & PERF_EF_START)) {
+		event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+		val = 0;
+	}
+
 	write_pmc(i, val);
 	perf_event_update_userpage(event);
 
@@ -310,15 +320,17 @@
 	ret = 0;
  out:
 	put_cpu_var(cpu_hw_events);
+	perf_pmu_enable(event->pmu);
 	return ret;
 }
 
-/* perf must be disabled, context locked on entry */
-static void fsl_emb_pmu_disable(struct perf_event *event)
+/* context locked on entry */
+static void fsl_emb_pmu_del(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuhw;
 	int i = event->hw.idx;
 
+	perf_pmu_disable(event->pmu);
 	if (i < 0)
 		goto out;
 
@@ -346,44 +358,57 @@
 	cpuhw->n_events--;
 
  out:
+	perf_pmu_enable(event->pmu);
 	put_cpu_var(cpu_hw_events);
 }
 
-/*
- * Re-enable interrupts on a event after they were throttled
- * because they were coming too fast.
- *
- * Context is locked on entry, but perf is not disabled.
- */
-static void fsl_emb_pmu_unthrottle(struct perf_event *event)
+static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
 {
-	s64 val, left;
 	unsigned long flags;
+	s64 left;
 
 	if (event->hw.idx < 0 || !event->hw.sample_period)
 		return;
+
+	if (!(event->hw.state & PERF_HES_STOPPED))
+		return;
+
+	if (ef_flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
 	local_irq_save(flags);
-	perf_disable();
-	fsl_emb_pmu_read(event);
-	left = event->hw.sample_period;
-	event->hw.last_period = left;
-	val = 0;
-	if (left < 0x80000000L)
-		val = 0x80000000L - left;
-	write_pmc(event->hw.idx, val);
-	local64_set(&event->hw.prev_count, val);
-	local64_set(&event->hw.period_left, left);
+	perf_pmu_disable(event->pmu);
+
+	event->hw.state = 0;
+	left = local64_read(&event->hw.period_left);
+	write_pmc(event->hw.idx, left);
+
 	perf_event_update_userpage(event);
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 }
 
-static struct pmu fsl_emb_pmu = {
-	.enable		= fsl_emb_pmu_enable,
-	.disable	= fsl_emb_pmu_disable,
-	.read		= fsl_emb_pmu_read,
-	.unthrottle	= fsl_emb_pmu_unthrottle,
-};
+static void fsl_emb_pmu_stop(struct perf_event *event, int ef_flags)
+{
+	unsigned long flags;
+
+	if (event->hw.idx < 0 || !event->hw.sample_period)
+		return;
+
+	if (event->hw.state & PERF_HES_STOPPED)
+		return;
+
+	local_irq_save(flags);
+	perf_pmu_disable(event->pmu);
+
+	fsl_emb_pmu_read(event);
+	event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+	write_pmc(event->hw.idx, 0);
+
+	perf_event_update_userpage(event);
+	perf_pmu_enable(event->pmu);
+	local_irq_restore(flags);
+}
 
 /*
  * Release the PMU if this is the last perf_event.
@@ -428,7 +453,7 @@
 	return 0;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int fsl_emb_pmu_event_init(struct perf_event *event)
 {
 	u64 ev;
 	struct perf_event *events[MAX_HWEVENTS];
@@ -441,14 +466,14 @@
 	case PERF_TYPE_HARDWARE:
 		ev = event->attr.config;
 		if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-			return ERR_PTR(-EOPNOTSUPP);
+			return -EOPNOTSUPP;
 		ev = ppmu->generic_events[ev];
 		break;
 
 	case PERF_TYPE_HW_CACHE:
 		err = hw_perf_cache_event(event->attr.config, &ev);
 		if (err)
-			return ERR_PTR(err);
+			return err;
 		break;
 
 	case PERF_TYPE_RAW:
@@ -456,12 +481,12 @@
 		break;
 
 	default:
-		return ERR_PTR(-EINVAL);
+		return -ENOENT;
 	}
 
 	event->hw.config = ppmu->xlate_event(ev);
 	if (!(event->hw.config & FSL_EMB_EVENT_VALID))
-		return ERR_PTR(-EINVAL);
+		return -EINVAL;
 
 	/*
 	 * If this is in a group, check if it can go on with all the
@@ -473,7 +498,7 @@
 		n = collect_events(event->group_leader,
 		                   ppmu->n_counter - 1, events);
 		if (n < 0)
-			return ERR_PTR(-EINVAL);
+			return -EINVAL;
 	}
 
 	if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
@@ -484,7 +509,7 @@
 		}
 
 		if (num_restricted >= ppmu->n_restricted)
-			return ERR_PTR(-EINVAL);
+			return -EINVAL;
 	}
 
 	event->hw.idx = -1;
@@ -497,7 +522,7 @@
 	if (event->attr.exclude_kernel)
 		event->hw.config_base |= PMLCA_FCS;
 	if (event->attr.exclude_idle)
-		return ERR_PTR(-ENOTSUPP);
+		return -ENOTSUPP;
 
 	event->hw.last_period = event->hw.sample_period;
 	local64_set(&event->hw.period_left, event->hw.last_period);
@@ -523,11 +548,20 @@
 	}
 	event->destroy = hw_perf_event_destroy;
 
-	if (err)
-		return ERR_PTR(err);
-	return &fsl_emb_pmu;
+	return err;
 }
 
+static struct pmu fsl_emb_pmu = {
+	.pmu_enable	= fsl_emb_pmu_enable,
+	.pmu_disable	= fsl_emb_pmu_disable,
+	.event_init	= fsl_emb_pmu_event_init,
+	.add		= fsl_emb_pmu_add,
+	.del		= fsl_emb_pmu_del,
+	.start		= fsl_emb_pmu_start,
+	.stop		= fsl_emb_pmu_stop,
+	.read		= fsl_emb_pmu_read,
+};
+
 /*
  * A counter has overflowed; update its count and record
  * things if requested.  Note that interrupts are hard-disabled
@@ -540,6 +574,11 @@
 	s64 prev, delta, left;
 	int record = 0;
 
+	if (event->hw.state & PERF_HES_STOPPED) {
+		write_pmc(event->hw.idx, 0);
+		return;
+	}
+
 	/* we don't have to worry about interrupts here */
 	prev = local64_read(&event->hw.prev_count);
 	delta = (val - prev) & 0xfffffffful;
@@ -562,6 +601,11 @@
 			val = 0x80000000LL - left;
 	}
 
+	write_pmc(event->hw.idx, val);
+	local64_set(&event->hw.prev_count, val);
+	local64_set(&event->hw.period_left, left);
+	perf_event_update_userpage(event);
+
 	/*
 	 * Finally record data if requested.
 	 */
@@ -571,23 +615,9 @@
 		perf_sample_data_init(&data, 0);
 		data.period = event->hw.last_period;
 
-		if (perf_event_overflow(event, nmi, &data, regs)) {
-			/*
-			 * Interrupts are coming too fast - throttle them
-			 * by setting the event to 0, so it will be
-			 * at least 2^30 cycles until the next interrupt
-			 * (assuming each event counts at most 2 counts
-			 * per cycle).
-			 */
-			val = 0;
-			left = ~0ULL >> 1;
-		}
+		if (perf_event_overflow(event, nmi, &data, regs))
+			fsl_emb_pmu_stop(event, 0);
 	}
-
-	write_pmc(event->hw.idx, val);
-	local64_set(&event->hw.prev_count, val);
-	local64_set(&event->hw.period_left, left);
-	perf_event_update_userpage(event);
 }
 
 static void perf_event_interrupt(struct pt_regs *regs)
@@ -651,5 +681,7 @@
 	pr_info("%s performance monitor hardware support registered\n",
 		pmu->name);
 
+	perf_pmu_register(&fsl_emb_pmu);
+
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/ppc970-pmu.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/ppc970-pmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/ppc970-pmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/ppc970-pmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -169,9 +169,11 @@
 	switch (unit) {
 	case PM_VPU:
 		mask = 0x4c;		/* byte 0 bits 2,3,6 */
+		break;
 	case PM_LSU0:
 		/* byte 2 bits 0,2,3,4,6; all of byte 1 */
 		mask = 0x085dff00;
+		break;
 	case PM_LSU1L:
 		mask = 0x50 << 24;	/* byte 3 bits 4,6 */
 		break;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/process.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -517,7 +517,6 @@
 
 	account_system_vtime(current);
 	account_process_vtime(current);
-	calculate_steal_time();
 
 	/*
 	 * We can't take a PMU exception inside _switch() since there is a
@@ -1298,14 +1297,3 @@
 
 	return ret;
 }
-
-#ifdef CONFIG_SMP
-int arch_sd_sibling_asym_packing(void)
-{
-	if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
-		printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
-		return SD_ASYM_PACKING;
-	}
-	return 0;
-}
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/prom.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/prom.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/prom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/prom.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,6 +66,7 @@
 int __initdata iommu_is_off;
 int __initdata iommu_force_on;
 unsigned long tce_alloc_start, tce_alloc_end;
+u64 ppc64_rma_size;
 #endif
 
 static int __init early_parse_mem(char *p)
@@ -98,7 +99,7 @@
 
 	if ((memory_limit && (start + size) > memory_limit) ||
 			overlaps_crashkernel(start, size)) {
-		p = __va(memblock_alloc_base(size, PAGE_SIZE, memblock.rmo_size));
+		p = __va(memblock_alloc(size, PAGE_SIZE));
 		memcpy(p, initial_boot_params, size);
 		initial_boot_params = (struct boot_param_header *)p;
 		DBG("Moved device tree to 0x%p\n", p);
@@ -363,10 +364,15 @@
 	return 0;
 }
 
-void __init early_init_dt_scan_chosen_arch(unsigned long node)
+int __init early_init_dt_scan_chosen_ppc(unsigned long node, const char *uname,
+					 int depth, void *data)
 {
 	unsigned long *lprop;
 
+	/* Use common scan routine to determine if this is the chosen node */
+	if (early_init_dt_scan_chosen(node, uname, depth, data) == 0)
+		return 0;
+
 #ifdef CONFIG_PPC64
 	/* check if iommu is forced on or off */
 	if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -398,6 +404,9 @@
 	if (lprop)
 		crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
+
+	/* break now */
+	return 1;
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -492,7 +501,7 @@
 
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
-#if defined(CONFIG_PPC64)
+#ifdef CONFIG_PPC64
 	if (iommu_is_off) {
 		if (base >= 0x80000000ul)
 			return;
@@ -501,9 +510,13 @@
 	}
 #endif
 
-	memblock_add(base, size);
-
+	/* First MEMBLOCK added, do some special initializations */
+	if (memstart_addr == ~(phys_addr_t)0)
+		setup_initial_memory_limit(base, size);
 	memstart_addr = min((u64)memstart_addr, base);
+
+	/* Add the chunk to the MEMBLOCK list */
+	memblock_add(base, size);
 }
 
 u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
@@ -655,7 +668,6 @@
 static inline void __init phyp_dump_reserve_mem(void) {}
 #endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */
 
-
 void __init early_init_devtree(void *params)
 {
 	phys_addr_t limit;
@@ -679,10 +691,11 @@
 	 * device-tree, including the platform type, initrd location and
 	 * size, TCE reserve, and more ...
 	 */
-	of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
+	of_scan_flat_dt(early_init_dt_scan_chosen_ppc, NULL);
 
 	/* Scan memory nodes and rebuild MEMBLOCKs */
 	memblock_init();
+
 	of_scan_flat_dt(early_init_dt_scan_root, NULL);
 	of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -1406,37 +1406,42 @@
  * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
  * we mark them as obsolete now, they will be removed in a future version
  */
-static long arch_ptrace_old(struct task_struct *child, long request, long addr,
-			    long data)
+static long arch_ptrace_old(struct task_struct *child, long request,
+			    unsigned long addr, unsigned long data)
 {
+	void __user *datavp = (void __user *) data;
+
 	switch (request) {
 	case PPC_PTRACE_GETREGS:	/* Get GPRs 0 - 31. */
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_GPR, 0, 32 * sizeof(long),
-					   (void __user *) data);
+					   datavp);
 
 	case PPC_PTRACE_SETREGS:	/* Set GPRs 0 - 31. */
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_GPR, 0, 32 * sizeof(long),
-					     (const void __user *) data);
+					     datavp);
 
 	case PPC_PTRACE_GETFPREGS:	/* Get FPRs 0 - 31. */
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_FPR, 0, 32 * sizeof(double),
-					   (void __user *) data);
+					   datavp);
 
 	case PPC_PTRACE_SETFPREGS:	/* Set FPRs 0 - 31. */
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_FPR, 0, 32 * sizeof(double),
-					     (const void __user *) data);
+					     datavp);
 	}
 
 	return -EPERM;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret = -EPERM;
+	void __user *datavp = (void __user *) data;
+	unsigned long __user *datalp = datavp;
 
 	switch (request) {
 	/* read the word at location addr in the USER area. */
@@ -1446,11 +1451,11 @@
 		ret = -EIO;
 		/* convert to index and check */
 #ifdef CONFIG_PPC32
-		index = (unsigned long) addr >> 2;
+		index = addr >> 2;
 		if ((addr & 3) || (index > PT_FPSCR)
 		    || (child->thread.regs == NULL))
 #else
-		index = (unsigned long) addr >> 3;
+		index = addr >> 3;
 		if ((addr & 7) || (index > PT_FPSCR))
 #endif
 			break;
@@ -1463,7 +1468,7 @@
 			tmp = ((unsigned long *)child->thread.fpr)
 				[TS_FPRWIDTH * (index - PT_FPR0)];
 		}
-		ret = put_user(tmp,(unsigned long __user *) data);
+		ret = put_user(tmp, datalp);
 		break;
 	}
 
@@ -1474,11 +1479,11 @@
 		ret = -EIO;
 		/* convert to index and check */
 #ifdef CONFIG_PPC32
-		index = (unsigned long) addr >> 2;
+		index = addr >> 2;
 		if ((addr & 3) || (index > PT_FPSCR)
 		    || (child->thread.regs == NULL))
 #else
-		index = (unsigned long) addr >> 3;
+		index = addr >> 3;
 		if ((addr & 7) || (index > PT_FPSCR))
 #endif
 			break;
@@ -1525,11 +1530,11 @@
 		dbginfo.features = 0;
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
-		if (!access_ok(VERIFY_WRITE, data,
+		if (!access_ok(VERIFY_WRITE, datavp,
 			       sizeof(struct ppc_debug_info)))
 			return -EFAULT;
-		ret = __copy_to_user((struct ppc_debug_info __user *)data,
-				     &dbginfo, sizeof(struct ppc_debug_info)) ?
+		ret = __copy_to_user(datavp, &dbginfo,
+				     sizeof(struct ppc_debug_info)) ?
 		      -EFAULT : 0;
 		break;
 	}
@@ -1537,11 +1542,10 @@
 	case PPC_PTRACE_SETHWDEBUG: {
 		struct ppc_hw_breakpoint bp_info;
 
-		if (!access_ok(VERIFY_READ, data,
+		if (!access_ok(VERIFY_READ, datavp,
 			       sizeof(struct ppc_hw_breakpoint)))
 			return -EFAULT;
-		ret = __copy_from_user(&bp_info,
-				       (struct ppc_hw_breakpoint __user *)data,
+		ret = __copy_from_user(&bp_info, datavp,
 				       sizeof(struct ppc_hw_breakpoint)) ?
 		      -EFAULT : 0;
 		if (!ret)
@@ -1560,11 +1564,9 @@
 		if (addr > 0)
 			break;
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-		ret = put_user(child->thread.dac1,
-			       (unsigned long __user *)data);
+		ret = put_user(child->thread.dac1, datalp);
 #else
-		ret = put_user(child->thread.dabr,
-			       (unsigned long __user *)data);
+		ret = put_user(child->thread.dabr, datalp);
 #endif
 		break;
 	}
@@ -1580,7 +1582,7 @@
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_GPR,
 					   0, sizeof(struct pt_regs),
-					   (void __user *) data);
+					   datavp);
 
 #ifdef CONFIG_PPC64
 	case PTRACE_SETREGS64:
@@ -1589,19 +1591,19 @@
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_GPR,
 					     0, sizeof(struct pt_regs),
-					     (const void __user *) data);
+					     datavp);
 
 	case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_FPR,
 					   0, sizeof(elf_fpregset_t),
-					   (void __user *) data);
+					   datavp);
 
 	case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_FPR,
 					     0, sizeof(elf_fpregset_t),
-					     (const void __user *) data);
+					     datavp);
 
 #ifdef CONFIG_ALTIVEC
 	case PTRACE_GETVRREGS:
@@ -1609,40 +1611,40 @@
 					   REGSET_VMX,
 					   0, (33 * sizeof(vector128) +
 					       sizeof(u32)),
-					   (void __user *) data);
+					   datavp);
 
 	case PTRACE_SETVRREGS:
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_VMX,
 					     0, (33 * sizeof(vector128) +
 						 sizeof(u32)),
-					     (const void __user *) data);
+					     datavp);
 #endif
 #ifdef CONFIG_VSX
 	case PTRACE_GETVSRREGS:
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_VSX,
 					   0, 32 * sizeof(double),
-					   (void __user *) data);
+					   datavp);
 
 	case PTRACE_SETVSRREGS:
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_VSX,
 					     0, 32 * sizeof(double),
-					     (const void __user *) data);
+					     datavp);
 #endif
 #ifdef CONFIG_SPE
 	case PTRACE_GETEVRREGS:
 		/* Get the child spe register state. */
 		return copy_regset_to_user(child, &user_ppc_native_view,
 					   REGSET_SPE, 0, 35 * sizeof(u32),
-					   (void __user *) data);
+					   datavp);
 
 	case PTRACE_SETEVRREGS:
 		/* Set the child spe register state. */
 		return copy_regset_from_user(child, &user_ppc_native_view,
 					     REGSET_SPE, 0, 35 * sizeof(u32),
-					     (const void __user *) data);
+					     datavp);
 #endif
 
 	/* Old reverse args ptrace callss */
@@ -1681,7 +1683,7 @@
 
 	if (unlikely(current->audit_context)) {
 #ifdef CONFIG_PPC64
-		if (!test_thread_flag(TIF_32BIT))
+		if (!is_32bit_task())
 			audit_syscall_entry(AUDIT_ARCH_PPC64,
 					    regs->gpr[0],
 					    regs->gpr[3], regs->gpr[4],
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtas.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtas.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtas.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtas.c	2011-01-04 19:50:19.000000000 -0500
@@ -805,7 +805,7 @@
 	__rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
 }
 
-static int rtas_ibm_suspend_me(struct rtas_args *args)
+int rtas_ibm_suspend_me(struct rtas_args *args)
 {
 	long state;
 	long rc;
@@ -855,7 +855,7 @@
 	return atomic_read(&data.error);
 }
 #else /* CONFIG_PPC_PSERIES */
-static int rtas_ibm_suspend_me(struct rtas_args *args)
+int rtas_ibm_suspend_me(struct rtas_args *args)
 {
 	return -ENOSYS;
 }
@@ -969,7 +969,7 @@
 	 */
 #ifdef CONFIG_PPC64
 	if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
-		rtas_region = min(memblock.rmo_size, RTAS_INSTANTIATE_MAX);
+		rtas_region = min(ppc64_rma_size, RTAS_INSTANTIATE_MAX);
 		ibm_suspend_me_token = rtas_token("ibm,suspend-me");
 	}
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtasd.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtasd.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtasd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtasd.c	2011-01-04 19:50:19.000000000 -0500
@@ -354,6 +354,7 @@
 	.poll =		rtas_log_poll,
 	.open =		rtas_log_open,
 	.release =	rtas_log_release,
+	.llseek =	noop_llseek,
 };
 
 static int enable_surveillance(int timeout)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtas_flash.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtas_flash.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/rtas_flash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/rtas_flash.c	2011-01-04 19:50:19.000000000 -0500
@@ -716,6 +716,7 @@
 	.write		= rtas_flash_write,
 	.open		= rtas_excl_open,
 	.release	= rtas_flash_release,
+	.llseek		= default_llseek,
 };
 
 static const struct file_operations manage_flash_operations = {
@@ -724,6 +725,7 @@
 	.write		= manage_flash_write,
 	.open		= rtas_excl_open,
 	.release	= rtas_excl_release,
+	.llseek		= default_llseek,
 };
 
 static const struct file_operations validate_flash_operations = {
@@ -732,6 +734,7 @@
 	.write		= validate_flash_write,
 	.open		= rtas_excl_open,
 	.release	= validate_flash_release,
+	.llseek		= default_llseek,
 };
 
 static int __init rtas_flash_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/setup_32.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/setup_32.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/setup_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/setup_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-int boot_cpuid;
+int boot_cpuid = -1;
 EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 
@@ -246,7 +246,7 @@
 	unsigned int i;
 
 	/* interrupt stacks must be in lowmem, we get that for free on ppc32
-	 * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
+	 * as the memblock is limited to lowmem by default */
 	for_each_possible_cpu(i) {
 		softirq_ctx[i] = (struct thread_info *)
 			__va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/setup_64.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/setup_64.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/setup_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/setup_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -486,7 +486,7 @@
 	 * bringup, we need to get at them in real mode. This means they
 	 * must also be within the RMO region.
 	 */
-	limit = min(slb0_limit(), memblock.rmo_size);
+	limit = min(slb0_limit(), ppc64_rma_size);
 
 	for_each_possible_cpu(i) {
 		unsigned long sp;
@@ -497,9 +497,8 @@
 }
 
 /*
- * Called into from start_kernel, after lock_kernel has been called.
- * Initializes bootmem, which is unsed to manage page allocation until
- * mem_init is called.
+ * Called into from start_kernel this initializes bootmem, which is used
+ * to manage page allocation until mem_init is called.
  */
 void __init setup_arch(char **cmdline_p)
 {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/smp.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -508,9 +508,6 @@
 	if (smp_ops->take_timebase)
 		smp_ops->take_timebase();
 
-	if (system_state > SYSTEM_BOOTING)
-		snapshot_timebase();
-
 	secondary_cpu_time_init();
 
 	ipi_call_lock();
@@ -575,11 +572,18 @@
 
 	free_cpumask_var(old_mask);
 
-	snapshot_timebases();
-
 	dump_numa_cpu_topology();
 }
 
+int arch_sd_sibling_asym_packing(void)
+{
+	if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
+		printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
+		return SD_ASYM_PACKING;
+	}
+	return 0;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 int __cpu_disable(void)
 {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/sys_ppc32.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/sys_ppc32.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/sys_ppc32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/sys_ppc32.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/time.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -53,7 +53,7 @@
 #include <linux/posix-timers.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 #include <asm/trace.h>
 
 #include <asm/io.h>
@@ -161,10 +161,9 @@
 static long timezone_offset;
 
 unsigned long ppc_proc_freq;
-EXPORT_SYMBOL(ppc_proc_freq);
+EXPORT_SYMBOL_GPL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
-
-static DEFINE_PER_CPU(u64, last_jiffy);
+EXPORT_SYMBOL_GPL(ppc_tb_freq);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
@@ -185,6 +184,8 @@
 
 cputime_t cputime_one_jiffy;
 
+void (*dtl_consumer)(struct dtl_entry *, u64);
+
 static void calc_cputime_factors(void)
 {
 	struct div_result res;
@@ -200,62 +201,153 @@
 }
 
 /*
- * Read the PURR on systems that have it, otherwise the timebase.
+ * Read the SPURR on systems that have it, otherwise the PURR,
+ * or if that doesn't exist return the timebase value passed in.
  */
-static u64 read_purr(void)
+static u64 read_spurr(u64 tb)
 {
+	if (cpu_has_feature(CPU_FTR_SPURR))
+		return mfspr(SPRN_SPURR);
 	if (cpu_has_feature(CPU_FTR_PURR))
 		return mfspr(SPRN_PURR);
-	return mftb();
+	return tb;
 }
 
+#ifdef CONFIG_PPC_SPLPAR
+
 /*
- * Read the SPURR on systems that have it, otherwise the purr
+ * Scan the dispatch trace log and count up the stolen time.
+ * Should be called with interrupts disabled.
  */
-static u64 read_spurr(u64 purr)
+static u64 scan_dispatch_log(u64 stop_tb)
 {
-	/*
-	 * cpus without PURR won't have a SPURR
-	 * We already know the former when we use this, so tell gcc
-	 */
-	if (cpu_has_feature(CPU_FTR_PURR) && cpu_has_feature(CPU_FTR_SPURR))
-		return mfspr(SPRN_SPURR);
-	return purr;
+	u64 i = local_paca->dtl_ridx;
+	struct dtl_entry *dtl = local_paca->dtl_curr;
+	struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
+	struct lppaca *vpa = local_paca->lppaca_ptr;
+	u64 tb_delta;
+	u64 stolen = 0;
+	u64 dtb;
+
+	if (i == vpa->dtl_idx)
+		return 0;
+	while (i < vpa->dtl_idx) {
+		if (dtl_consumer)
+			dtl_consumer(dtl, i);
+		dtb = dtl->timebase;
+		tb_delta = dtl->enqueue_to_dispatch_time +
+			dtl->ready_to_enqueue_time;
+		barrier();
+		if (i + N_DISPATCH_LOG < vpa->dtl_idx) {
+			/* buffer has overflowed */
+			i = vpa->dtl_idx - N_DISPATCH_LOG;
+			dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
+			continue;
+		}
+		if (dtb > stop_tb)
+			break;
+		stolen += tb_delta;
+		++i;
+		++dtl;
+		if (dtl == dtl_end)
+			dtl = local_paca->dispatch_log;
+	}
+	local_paca->dtl_ridx = i;
+	local_paca->dtl_curr = dtl;
+	return stolen;
 }
 
 /*
+ * Accumulate stolen time by scanning the dispatch trace log.
+ * Called on entry from user mode.
+ */
+void accumulate_stolen_time(void)
+{
+	u64 sst, ust;
+
+	sst = scan_dispatch_log(get_paca()->starttime_user);
+	ust = scan_dispatch_log(get_paca()->starttime);
+	get_paca()->system_time -= sst;
+	get_paca()->user_time -= ust;
+	get_paca()->stolen_time += ust + sst;
+}
+
+static inline u64 calculate_stolen_time(u64 stop_tb)
+{
+	u64 stolen = 0;
+
+	if (get_paca()->dtl_ridx != get_paca()->lppaca_ptr->dtl_idx) {
+		stolen = scan_dispatch_log(stop_tb);
+		get_paca()->system_time -= stolen;
+	}
+
+	stolen += get_paca()->stolen_time;
+	get_paca()->stolen_time = 0;
+	return stolen;
+}
+
+#else /* CONFIG_PPC_SPLPAR */
+static inline u64 calculate_stolen_time(u64 stop_tb)
+{
+	return 0;
+}
+
+#endif /* CONFIG_PPC_SPLPAR */
+
+/*
  * Account time for a transition between system, hard irq
  * or soft irq state.
  */
 void account_system_vtime(struct task_struct *tsk)
 {
-	u64 now, nowscaled, delta, deltascaled, sys_time;
+	u64 now, nowscaled, delta, deltascaled;
 	unsigned long flags;
+	u64 stolen, udelta, sys_scaled, user_scaled;
 
 	local_irq_save(flags);
-	now = read_purr();
+	now = mftb();
 	nowscaled = read_spurr(now);
-	delta = now - get_paca()->startpurr;
+	get_paca()->system_time += now - get_paca()->starttime;
+	get_paca()->starttime = now;
 	deltascaled = nowscaled - get_paca()->startspurr;
-	get_paca()->startpurr = now;
 	get_paca()->startspurr = nowscaled;
-	if (!in_interrupt()) {
-		/* deltascaled includes both user and system time.
-		 * Hence scale it based on the purr ratio to estimate
-		 * the system time */
-		sys_time = get_paca()->system_time;
-		if (get_paca()->user_time)
-			deltascaled = deltascaled * sys_time /
-			     (sys_time + get_paca()->user_time);
-		delta += sys_time;
-		get_paca()->system_time = 0;
+
+	stolen = calculate_stolen_time(now);
+
+	delta = get_paca()->system_time;
+	get_paca()->system_time = 0;
+	udelta = get_paca()->user_time - get_paca()->utime_sspurr;
+	get_paca()->utime_sspurr = get_paca()->user_time;
+
+	/*
+	 * Because we don't read the SPURR on every kernel entry/exit,
+	 * deltascaled includes both user and system SPURR ticks.
+	 * Apportion these ticks to system SPURR ticks and user
+	 * SPURR ticks in the same ratio as the system time (delta)
+	 * and user time (udelta) values obtained from the timebase
+	 * over the same interval.  The system ticks get accounted here;
+	 * the user ticks get saved up in paca->user_time_scaled to be
+	 * used by account_process_tick.
+	 */
+	sys_scaled = delta;
+	user_scaled = udelta;
+	if (deltascaled != delta + udelta) {
+		if (udelta) {
+			sys_scaled = deltascaled * delta / (delta + udelta);
+			user_scaled = deltascaled - sys_scaled;
+		} else {
+			sys_scaled = deltascaled;
+		}
+	}
+	get_paca()->user_time_scaled += user_scaled;
+
+	if (in_irq() || idle_task(smp_processor_id()) != tsk) {
+		account_system_time(tsk, 0, delta, sys_scaled);
+		if (stolen)
+			account_steal_time(stolen);
+	} else {
+		account_idle_time(delta + stolen);
 	}
-	if (in_irq() || idle_task(smp_processor_id()) != tsk)
-		account_system_time(tsk, 0, delta, deltascaled);
-	else
-		account_idle_time(delta);
-	__get_cpu_var(cputime_last_delta) = delta;
-	__get_cpu_var(cputime_scaled_last_delta) = deltascaled;
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(account_system_vtime);
@@ -265,125 +357,26 @@
  * by the exception entry and exit code to the generic process
  * user and system time records.
  * Must be called with interrupts disabled.
+ * Assumes that account_system_vtime() has been called recently
+ * (i.e. since the last entry from usermode) so that
+ * get_paca()->user_time_scaled is up to date.
  */
 void account_process_tick(struct task_struct *tsk, int user_tick)
 {
 	cputime_t utime, utimescaled;
 
 	utime = get_paca()->user_time;
+	utimescaled = get_paca()->user_time_scaled;
 	get_paca()->user_time = 0;
-	utimescaled = cputime_to_scaled(utime);
+	get_paca()->user_time_scaled = 0;
+	get_paca()->utime_sspurr = 0;
 	account_user_time(tsk, utime, utimescaled);
 }
 
-/*
- * Stuff for accounting stolen time.
- */
-struct cpu_purr_data {
-	int	initialized;			/* thread is running */
-	u64	tb;			/* last TB value read */
-	u64	purr;			/* last PURR value read */
-	u64	spurr;			/* last SPURR value read */
-};
-
-/*
- * Each entry in the cpu_purr_data array is manipulated only by its
- * "owner" cpu -- usually in the timer interrupt but also occasionally
- * in process context for cpu online.  As long as cpus do not touch
- * each others' cpu_purr_data, disabling local interrupts is
- * sufficient to serialize accesses.
- */
-static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data);
-
-static void snapshot_tb_and_purr(void *data)
-{
-	unsigned long flags;
-	struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
-
-	local_irq_save(flags);
-	p->tb = get_tb_or_rtc();
-	p->purr = mfspr(SPRN_PURR);
-	wmb();
-	p->initialized = 1;
-	local_irq_restore(flags);
-}
-
-/*
- * Called during boot when all cpus have come up.
- */
-void snapshot_timebases(void)
-{
-	if (!cpu_has_feature(CPU_FTR_PURR))
-		return;
-	on_each_cpu(snapshot_tb_and_purr, NULL, 1);
-}
-
-/*
- * Must be called with interrupts disabled.
- */
-void calculate_steal_time(void)
-{
-	u64 tb, purr;
-	s64 stolen;
-	struct cpu_purr_data *pme;
-
-	pme = &__get_cpu_var(cpu_purr_data);
-	if (!pme->initialized)
-		return;		/* !CPU_FTR_PURR or early in early boot */
-	tb = mftb();
-	purr = mfspr(SPRN_PURR);
-	stolen = (tb - pme->tb) - (purr - pme->purr);
-	if (stolen > 0) {
-		if (idle_task(smp_processor_id()) != current)
-			account_steal_time(stolen);
-		else
-			account_idle_time(stolen);
-	}
-	pme->tb = tb;
-	pme->purr = purr;
-}
-
-#ifdef CONFIG_PPC_SPLPAR
-/*
- * Must be called before the cpu is added to the online map when
- * a cpu is being brought up at runtime.
- */
-static void snapshot_purr(void)
-{
-	struct cpu_purr_data *pme;
-	unsigned long flags;
-
-	if (!cpu_has_feature(CPU_FTR_PURR))
-		return;
-	local_irq_save(flags);
-	pme = &__get_cpu_var(cpu_purr_data);
-	pme->tb = mftb();
-	pme->purr = mfspr(SPRN_PURR);
-	pme->initialized = 1;
-	local_irq_restore(flags);
-}
-
-#endif /* CONFIG_PPC_SPLPAR */
-
 #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
 #define calc_cputime_factors()
-#define calculate_steal_time()		do { } while (0)
-#endif
-
-#if !(defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR))
-#define snapshot_purr()			do { } while (0)
 #endif
 
-/*
- * Called when a cpu comes up after the system has finished booting,
- * i.e. as a result of a hotplug cpu action.
- */
-void snapshot_timebase(void)
-{
-	__get_cpu_var(last_jiffy) = get_tb_or_rtc();
-	snapshot_purr();
-}
-
 void __delay(unsigned long loops)
 {
 	unsigned long start;
@@ -493,60 +486,60 @@
 }
 #endif /* CONFIG_PPC_ISERIES */
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_IRQ_WORK
 
 /*
  * 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
  */
 #ifdef CONFIG_PPC64
-static inline unsigned long test_perf_event_pending(void)
+static inline unsigned long test_irq_work_pending(void)
 {
 	unsigned long x;
 
 	asm volatile("lbz %0,%1(13)"
 		: "=r" (x)
-		: "i" (offsetof(struct paca_struct, perf_event_pending)));
+		: "i" (offsetof(struct paca_struct, irq_work_pending)));
 	return x;
 }
 
-static inline void set_perf_event_pending_flag(void)
+static inline void set_irq_work_pending_flag(void)
 {
 	asm volatile("stb %0,%1(13)" : :
 		"r" (1),
-		"i" (offsetof(struct paca_struct, perf_event_pending)));
+		"i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
-static inline void clear_perf_event_pending(void)
+static inline void clear_irq_work_pending(void)
 {
 	asm volatile("stb %0,%1(13)" : :
 		"r" (0),
-		"i" (offsetof(struct paca_struct, perf_event_pending)));
+		"i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
 #else /* 32-bit */
 
-DEFINE_PER_CPU(u8, perf_event_pending);
+DEFINE_PER_CPU(u8, irq_work_pending);
 
-#define set_perf_event_pending_flag()	__get_cpu_var(perf_event_pending) = 1
-#define test_perf_event_pending()	__get_cpu_var(perf_event_pending)
-#define clear_perf_event_pending()	__get_cpu_var(perf_event_pending) = 0
+#define set_irq_work_pending_flag()	__get_cpu_var(irq_work_pending) = 1
+#define test_irq_work_pending()		__get_cpu_var(irq_work_pending)
+#define clear_irq_work_pending()	__get_cpu_var(irq_work_pending) = 0
 
 #endif /* 32 vs 64 bit */
 
-void set_perf_event_pending(void)
+void set_irq_work_pending(void)
 {
 	preempt_disable();
-	set_perf_event_pending_flag();
+	set_irq_work_pending_flag();
 	set_dec(1);
 	preempt_enable();
 }
 
-#else  /* CONFIG_PERF_EVENTS */
+#else  /* CONFIG_IRQ_WORK */
 
-#define test_perf_event_pending()	0
-#define clear_perf_event_pending()
+#define test_irq_work_pending()	0
+#define clear_irq_work_pending()
 
-#endif /* CONFIG_PERF_EVENTS */
+#endif /* CONFIG_IRQ_WORK */
 
 /*
  * For iSeries shared processors, we have to let the hypervisor
@@ -585,11 +578,9 @@
 	old_regs = set_irq_regs(regs);
 	irq_enter();
 
-	calculate_steal_time();
-
-	if (test_perf_event_pending()) {
-		clear_perf_event_pending();
-		perf_event_do_pending();
+	if (test_irq_work_pending()) {
+		clear_irq_work_pending();
+		irq_work_run();
 	}
 
 #ifdef CONFIG_PPC_ISERIES
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/traps.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -538,6 +538,11 @@
 
 	return 0;
 }
+
+int machine_check_generic(struct pt_regs *regs)
+{
+	return 0;
+}
 #elif defined(CONFIG_E200)
 int machine_check_e200(struct pt_regs *regs)
 {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso32/Makefile linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso32/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso32/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso32/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -14,10 +14,10 @@
 
 GCOV_PROFILE := n
 
-EXTRA_CFLAGS := -shared -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
 		$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-EXTRA_AFLAGS := -D__VDSO32__ -s
+asflags-y := -D__VDSO32__ -s
 
 obj-y += vdso32_wrapper.o
 extra-y += vdso32.lds
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso64/Makefile linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso64/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso64/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso64/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -9,10 +9,10 @@
 
 GCOV_PROFILE := n
 
-EXTRA_CFLAGS := -shared -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
 		$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-EXTRA_AFLAGS := -D__VDSO64__ -s
+asflags-y := -D__VDSO64__ -s
 
 obj-y += vdso64_wrapper.o
 extra-y += vdso64.lds
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/vdso.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/vdso.c	2011-01-04 19:50:19.000000000 -0500
@@ -159,7 +159,7 @@
 {
 	int i;
 
-	if (!vma || test_thread_flag(TIF_32BIT)) {
+	if (!vma || is_32bit_task()) {
 		printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
 		for (i=0; i<vdso32_pages; i++) {
 			struct page *pg = virt_to_page(vdso32_kbase +
@@ -170,7 +170,7 @@
 			dump_one_vdso_page(pg, upg);
 		}
 	}
-	if (!vma || !test_thread_flag(TIF_32BIT)) {
+	if (!vma || !is_32bit_task()) {
 		printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
 		for (i=0; i<vdso64_pages; i++) {
 			struct page *pg = virt_to_page(vdso64_kbase +
@@ -200,7 +200,7 @@
 		return 0;
 
 #ifdef CONFIG_PPC64
-	if (test_thread_flag(TIF_32BIT)) {
+	if (is_32bit_task()) {
 		vdso_pagelist = vdso32_pagelist;
 		vdso_pages = vdso32_pages;
 		vdso_base = VDSO32_MBASE;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kernel/vio.c linux-libre-2.6.37-gnu/arch/powerpc/kernel/vio.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kernel/vio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kernel/vio.c	2011-01-04 19:50:19.000000000 -0500
@@ -238,9 +238,7 @@
 	 * memory in this pool does not change.
 	 */
 	if (spare_needed && reserve_freed) {
-		tmp = min(spare_needed, min(reserve_freed,
-		                            (viodev->cmo.entitled -
-		                             VIO_CMO_MIN_ENT)));
+		tmp = min3(spare_needed, reserve_freed, (viodev->cmo.entitled - VIO_CMO_MIN_ENT));
 
 		vio_cmo.spare += tmp;
 		viodev->cmo.entitled -= tmp;
@@ -1184,7 +1182,12 @@
 /* vio_dev refcount hit 0 */
 static void __devinit vio_dev_release(struct device *dev)
 {
-	/* XXX should free TCE table */
+	struct iommu_table *tbl = get_iommu_table_base(dev);
+
+	/* iSeries uses a common table for all vio devices */
+	if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl)
+		iommu_free_table(tbl, dev->of_node ?
+			dev->of_node->full_name : dev_name(dev));
 	of_node_put(dev->of_node);
 	kfree(to_vio_dev(dev));
 }
@@ -1254,8 +1257,7 @@
 	if (device_register(&viodev->dev)) {
 		printk(KERN_ERR "%s: failed to register device %s\n",
 				__func__, dev_name(&viodev->dev));
-		/* XXX free TCE table */
-		kfree(viodev);
+		put_device(&viodev->dev);
 		return NULL;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/44x.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/44x.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/44x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/44x.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,7 @@
 {
 	int r;
 
-	if (strcmp(cur_cpu_spec->platform, "ppc440") == 0)
+	if (strncmp(cur_cpu_spec->platform, "ppc440", 6) == 0)
 		r = 0;
 	else
 		r = -ENOTSUPP;
@@ -72,6 +72,7 @@
 	/* Since the guest can directly access the timebase, it must know the
 	 * real timebase frequency. Accordingly, it must see the state of
 	 * CCR1[TCS]. */
+	/* XXX CCR1 doesn't exist on all 440 SoCs. */
 	vcpu->arch.ccr1 = mfspr(SPRN_CCR1);
 
 	for (i = 0; i < ARRAY_SIZE(vcpu_44x->shadow_refs); i++)
@@ -123,8 +124,14 @@
 	if (err)
 		goto free_vcpu;
 
+	vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+	if (!vcpu->arch.shared)
+		goto uninit_vcpu;
+
 	return vcpu;
 
+uninit_vcpu:
+	kvm_vcpu_uninit(vcpu);
 free_vcpu:
 	kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
 out:
@@ -135,6 +142,7 @@
 {
 	struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
 
+	free_page((unsigned long)vcpu->arch.shared);
 	kvm_vcpu_uninit(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/44x_tlb.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/44x_tlb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/44x_tlb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/44x_tlb.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 #ifdef DEBUG
 void kvmppc_dump_tlbs(struct kvm_vcpu *vcpu)
 {
+	struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
 	struct kvmppc_44x_tlbe *tlbe;
 	int i;
 
@@ -221,14 +222,14 @@
 
 int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
 	return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
 
 int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
 
 	return kvmppc_44x_tlb_index(vcpu, eaddr, vcpu->arch.pid, as);
 }
@@ -354,7 +355,7 @@
 
 	stlbe.word1 = (hpaddr & 0xfffffc00) | ((hpaddr >> 32) & 0xf);
 	stlbe.word2 = kvmppc_44x_tlb_shadow_attrib(flags,
-	                                            vcpu->arch.msr & MSR_PR);
+	                                            vcpu->arch.shared->msr & MSR_PR);
 	stlbe.tid = !(asid & 0xff);
 
 	/* Keep track of the reference so we can properly release it later. */
@@ -423,7 +424,7 @@
 
 	/* Does it match current guest AS? */
 	/* XXX what about IS != DS? */
-	if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+	if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
 		return 0;
 
 	gpa = get_tlb_raddr(tlbe);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_32_mmu.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_32_mmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_32_mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_32_mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -58,14 +58,39 @@
 #endif
 }
 
+static inline u32 sr_vsid(u32 sr_raw)
+{
+	return sr_raw & 0x0fffffff;
+}
+
+static inline bool sr_valid(u32 sr_raw)
+{
+	return (sr_raw & 0x80000000) ? false : true;
+}
+
+static inline bool sr_ks(u32 sr_raw)
+{
+	return (sr_raw & 0x40000000) ? true: false;
+}
+
+static inline bool sr_kp(u32 sr_raw)
+{
+	return (sr_raw & 0x20000000) ? true: false;
+}
+
+static inline bool sr_nx(u32 sr_raw)
+{
+	return (sr_raw & 0x10000000) ? true: false;
+}
+
 static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
 					  struct kvmppc_pte *pte, bool data);
 static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
 					     u64 *vsid);
 
-static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr)
+static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
-	return &vcpu_book3s->sr[(eaddr >> 28) & 0xf];
+	return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf];
 }
 
 static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
@@ -87,7 +112,7 @@
 }
 
 static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s,
-				      struct kvmppc_sr *sre, gva_t eaddr,
+				      u32 sre, gva_t eaddr,
 				      bool primary)
 {
 	u32 page, hash, pteg, htabmask;
@@ -96,7 +121,7 @@
 	page = (eaddr & 0x0FFFFFFF) >> 12;
 	htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0;
 
-	hash = ((sre->vsid ^ page) << 6);
+	hash = ((sr_vsid(sre) ^ page) << 6);
 	if (!primary)
 		hash = ~hash;
 	hash &= htabmask;
@@ -104,8 +129,8 @@
 	pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash;
 
 	dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n",
-		vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg,
-		sre->vsid);
+		kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg,
+		sr_vsid(sre));
 
 	r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT);
 	if (kvm_is_error_hva(r))
@@ -113,10 +138,9 @@
 	return r | (pteg & ~PAGE_MASK);
 }
 
-static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr,
-				    bool primary)
+static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary)
 {
-	return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) |
+	return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) |
 	       (primary ? 0 : 0x40) | 0x80000000;
 }
 
@@ -133,7 +157,7 @@
 		else
 			bat = &vcpu_book3s->ibat[i];
 
-		if (vcpu->arch.msr & MSR_PR) {
+		if (vcpu->arch.shared->msr & MSR_PR) {
 			if (!bat->vp)
 				continue;
 		} else {
@@ -180,17 +204,17 @@
 				     bool primary)
 {
 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
-	struct kvmppc_sr *sre;
+	u32 sre;
 	hva_t ptegp;
 	u32 pteg[16];
 	u32 ptem = 0;
 	int i;
 	int found = 0;
 
-	sre = find_sr(vcpu_book3s, eaddr);
+	sre = find_sr(vcpu, eaddr);
 
 	dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28,
-		    sre->vsid, sre->raw);
+		    sr_vsid(sre), sre);
 
 	pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
 
@@ -214,8 +238,8 @@
 			pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF);
 			pp = pteg[i+1] & 3;
 
-			if ((sre->Kp &&  (vcpu->arch.msr & MSR_PR)) ||
-			    (sre->Ks && !(vcpu->arch.msr & MSR_PR)))
+			if ((sr_kp(sre) &&  (vcpu->arch.shared->msr & MSR_PR)) ||
+			    (sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR)))
 				pp |= 4;
 
 			pte->may_write = false;
@@ -269,7 +293,7 @@
 		dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n",
 			    to_book3s(vcpu)->sdr1, ptegp);
 		for (i=0; i<16; i+=2) {
-			dprintk_pte("   %02d: 0x%x - 0x%x (0x%llx)\n",
+			dprintk_pte("   %02d: 0x%x - 0x%x (0x%x)\n",
 				    i, pteg[i], pteg[i+1], ptem);
 		}
 	}
@@ -281,8 +305,24 @@
 				      struct kvmppc_pte *pte, bool data)
 {
 	int r;
+	ulong mp_ea = vcpu->arch.magic_page_ea;
 
 	pte->eaddr = eaddr;
+
+	/* Magic page override */
+	if (unlikely(mp_ea) &&
+	    unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
+	    !(vcpu->arch.shared->msr & MSR_PR)) {
+		pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
+		pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff);
+		pte->raddr &= KVM_PAM;
+		pte->may_execute = true;
+		pte->may_read = true;
+		pte->may_write = true;
+
+		return 0;
+	}
+
 	r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data);
 	if (r < 0)
 	       r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true);
@@ -295,30 +335,13 @@
 
 static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum)
 {
-	return to_book3s(vcpu)->sr[srnum].raw;
+	return vcpu->arch.shared->sr[srnum];
 }
 
 static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
 					ulong value)
 {
-	struct kvmppc_sr *sre;
-
-	sre = &to_book3s(vcpu)->sr[srnum];
-
-	/* Flush any left-over shadows from the previous SR */
-
-	/* XXX Not necessary? */
-	/* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */
-
-	/* And then put in the new SR */
-	sre->raw = value;
-	sre->vsid = (value & 0x0fffffff);
-	sre->valid = (value & 0x80000000) ? false : true;
-	sre->Ks = (value & 0x40000000) ? true : false;
-	sre->Kp = (value & 0x20000000) ? true : false;
-	sre->nx = (value & 0x10000000) ? true : false;
-
-	/* Map the new segment */
+	vcpu->arch.shared->sr[srnum] = value;
 	kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT);
 }
 
@@ -331,19 +354,19 @@
 					     u64 *vsid)
 {
 	ulong ea = esid << SID_SHIFT;
-	struct kvmppc_sr *sr;
+	u32 sr;
 	u64 gvsid = esid;
 
-	if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
-		sr = find_sr(to_book3s(vcpu), ea);
-		if (sr->valid)
-			gvsid = sr->vsid;
+	if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
+		sr = find_sr(vcpu, ea);
+		if (sr_valid(sr))
+			gvsid = sr_vsid(sr);
 	}
 
 	/* In case we only have one of MSR_IR or MSR_DR set, let's put
 	   that in the real-mode context (and hope RM doesn't access
 	   high memory) */
-	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+	switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
 	case 0:
 		*vsid = VSID_REAL | esid;
 		break;
@@ -354,8 +377,8 @@
 		*vsid = VSID_REAL_DR | gvsid;
 		break;
 	case MSR_DR|MSR_IR:
-		if (sr->valid)
-			*vsid = sr->vsid;
+		if (sr_valid(sr))
+			*vsid = sr_vsid(sr);
 		else
 			*vsid = VSID_BAT | gvsid;
 		break;
@@ -363,7 +386,7 @@
 		BUG();
 	}
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		*vsid |= VSID_PR;
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_32_mmu_host.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_32_mmu_host.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_32_mmu_host.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_32_mmu_host.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,6 @@
  */
 
 #include <linux/kvm_host.h>
-#include <linux/hash.h>
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -77,7 +76,14 @@
  * a hash, so we don't waste cycles on looping */
 static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
 {
-	return hash_64(gvsid, SID_MAP_BITS);
+	return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
 }
 
 
@@ -86,7 +92,7 @@
 	struct kvmppc_sid_map *map;
 	u16 sid_map_mask;
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		gvsid |= VSID_PR;
 
 	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
@@ -147,8 +153,8 @@
 	struct hpte_cache *pte;
 
 	/* Get host physical address for gpa */
-	hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
-	if (kvm_is_error_hva(hpaddr)) {
+	hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
+	if (is_error_pfn(hpaddr)) {
 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
 				 orig_pte->eaddr);
 		return -EINVAL;
@@ -253,7 +259,7 @@
 	u16 sid_map_mask;
 	static int backwards_map = 0;
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		gvsid |= VSID_PR;
 
 	/* We might get collisions that trap in preceding order, so let's
@@ -269,18 +275,15 @@
 	backwards_map = !backwards_map;
 
 	/* Uh-oh ... out of mappings. Let's flush! */
-	if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) {
-		vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
+	if (vcpu_book3s->vsid_next >= VSID_POOL_SIZE) {
+		vcpu_book3s->vsid_next = 0;
 		memset(vcpu_book3s->sid_map, 0,
 		       sizeof(struct kvmppc_sid_map) * SID_MAP_NUM);
 		kvmppc_mmu_pte_flush(vcpu, 0, 0);
 		kvmppc_mmu_flush_segments(vcpu);
 	}
-	map->host_vsid = vcpu_book3s->vsid_next;
-
-	/* Would have to be 111 to be completely aligned with the rest of
-	   Linux, but that is just way too little space! */
-	vcpu_book3s->vsid_next+=1;
+	map->host_vsid = vcpu_book3s->vsid_pool[vcpu_book3s->vsid_next];
+	vcpu_book3s->vsid_next++;
 
 	map->guest_vsid = gvsid;
 	map->valid = true;
@@ -327,40 +330,38 @@
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
+	int i;
+
 	kvmppc_mmu_hpte_destroy(vcpu);
 	preempt_disable();
-	__destroy_context(to_book3s(vcpu)->context_id);
+	for (i = 0; i < SID_CONTEXTS; i++)
+		__destroy_context(to_book3s(vcpu)->context_id[i]);
 	preempt_enable();
 }
 
 /* From mm/mmu_context_hash32.c */
-#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff)
+#define CTX_TO_VSID(c, id)	((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff)
 
 int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
 	int err;
 	ulong sdr1;
+	int i;
+	int j;
 
-	err = __init_new_context();
-	if (err < 0)
-		return -1;
-	vcpu3s->context_id = err;
-
-	vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1;
-	vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id);
-
-#if 0 /* XXX still doesn't guarantee uniqueness */
-	/* We could collide with the Linux vsid space because the vsid
-	 * wraps around at 24 bits. We're safe if we do our own space
-	 * though, so let's always set the highest bit. */
+	for (i = 0; i < SID_CONTEXTS; i++) {
+		err = __init_new_context();
+		if (err < 0)
+			goto init_fail;
+		vcpu3s->context_id[i] = err;
 
-	vcpu3s->vsid_max |= 0x00800000;
-	vcpu3s->vsid_first |= 0x00800000;
-#endif
-	BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first);
+		/* Remember context id for this combination */
+		for (j = 0; j < 16; j++)
+			vcpu3s->vsid_pool[(i * 16) + j] = CTX_TO_VSID(err, j);
+	}
 
-	vcpu3s->vsid_next = vcpu3s->vsid_first;
+	vcpu3s->vsid_next = 0;
 
 	/* Remember where the HTAB is */
 	asm ( "mfsdr1 %0" : "=r"(sdr1) );
@@ -370,4 +371,14 @@
 	kvmppc_mmu_hpte_init(vcpu);
 
 	return 0;
+
+init_fail:
+	for (j = 0; j < i; j++) {
+		if (!vcpu3s->context_id[j])
+			continue;
+
+		__destroy_context(to_book3s(vcpu)->context_id[j]);
+	}
+
+	return -1;
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_64_mmu.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_64_mmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_64_mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_64_mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -163,6 +163,22 @@
 	bool found = false;
 	bool perm_err = false;
 	int second = 0;
+	ulong mp_ea = vcpu->arch.magic_page_ea;
+
+	/* Magic page override */
+	if (unlikely(mp_ea) &&
+	    unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) &&
+	    !(vcpu->arch.shared->msr & MSR_PR)) {
+		gpte->eaddr = eaddr;
+		gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
+		gpte->raddr = vcpu->arch.magic_page_pa | (gpte->raddr & 0xfff);
+		gpte->raddr &= KVM_PAM;
+		gpte->may_execute = true;
+		gpte->may_read = true;
+		gpte->may_write = true;
+
+		return 0;
+	}
 
 	slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr);
 	if (!slbe)
@@ -180,9 +196,9 @@
 		goto no_page_found;
 	}
 
-	if ((vcpu->arch.msr & MSR_PR) && slbe->Kp)
+	if ((vcpu->arch.shared->msr & MSR_PR) && slbe->Kp)
 		key = 4;
-	else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks)
+	else if (!(vcpu->arch.shared->msr & MSR_PR) && slbe->Ks)
 		key = 4;
 
 	for (i=0; i<16; i+=2) {
@@ -381,7 +397,7 @@
 	for (i = 1; i < vcpu_book3s->slb_nr; i++)
 		vcpu_book3s->slb[i].valid = false;
 
-	if (vcpu->arch.msr & MSR_IR) {
+	if (vcpu->arch.shared->msr & MSR_IR) {
 		kvmppc_mmu_flush_segments(vcpu);
 		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
 	}
@@ -445,14 +461,15 @@
 	ulong ea = esid << SID_SHIFT;
 	struct kvmppc_slb *slb;
 	u64 gvsid = esid;
+	ulong mp_ea = vcpu->arch.magic_page_ea;
 
-	if (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+	if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
 		slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea);
 		if (slb)
 			gvsid = slb->vsid;
 	}
 
-	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+	switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
 	case 0:
 		*vsid = VSID_REAL | esid;
 		break;
@@ -464,7 +481,7 @@
 		break;
 	case MSR_DR|MSR_IR:
 		if (!slb)
-			return -ENOENT;
+			goto no_slb;
 
 		*vsid = gvsid;
 		break;
@@ -473,10 +490,21 @@
 		break;
 	}
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		*vsid |= VSID_PR;
 
 	return 0;
+
+no_slb:
+	/* Catch magic page case */
+	if (unlikely(mp_ea) &&
+	    unlikely(esid == (mp_ea >> SID_SHIFT)) &&
+	    !(vcpu->arch.shared->msr & MSR_PR)) {
+		*vsid = VSID_REAL | esid;
+		return 0;
+	}
+
+	return -EINVAL;
 }
 
 static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_64_mmu_host.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_64_mmu_host.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_64_mmu_host.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_64_mmu_host.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
  */
 
 #include <linux/kvm_host.h>
-#include <linux/hash.h>
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -28,24 +27,9 @@
 #include <asm/machdep.h>
 #include <asm/mmu_context.h>
 #include <asm/hw_irq.h>
+#include "trace.h"
 
 #define PTE_SIZE 12
-#define VSID_ALL 0
-
-/* #define DEBUG_MMU */
-/* #define DEBUG_SLB */
-
-#ifdef DEBUG_MMU
-#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_mmu(a, ...) do { } while(0)
-#endif
-
-#ifdef DEBUG_SLB
-#define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_slb(a, ...) do { } while(0)
-#endif
 
 void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 {
@@ -58,34 +42,39 @@
  * a hash, so we don't waste cycles on looping */
 static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid)
 {
-	return hash_64(gvsid, SID_MAP_BITS);
+	return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^
+		     ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK));
 }
 
+
 static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
 {
 	struct kvmppc_sid_map *map;
 	u16 sid_map_mask;
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		gvsid |= VSID_PR;
 
 	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
 	map = &to_book3s(vcpu)->sid_map[sid_map_mask];
-	if (map->guest_vsid == gvsid) {
-		dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n",
-			    gvsid, map->host_vsid);
+	if (map->valid && (map->guest_vsid == gvsid)) {
+		trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
 		return map;
 	}
 
 	map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask];
-	if (map->guest_vsid == gvsid) {
-		dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n",
-			    gvsid, map->host_vsid);
+	if (map->valid && (map->guest_vsid == gvsid)) {
+		trace_kvm_book3s_slb_found(gvsid, map->host_vsid);
 		return map;
 	}
 
-	dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n",
-		    sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid);
+	trace_kvm_book3s_slb_fail(sid_map_mask, gvsid);
 	return NULL;
 }
 
@@ -101,18 +90,13 @@
 	struct kvmppc_sid_map *map;
 
 	/* Get host physical address for gpa */
-	hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
-	if (kvm_is_error_hva(hpaddr)) {
+	hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT);
+	if (is_error_pfn(hpaddr)) {
 		printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
 		return -EINVAL;
 	}
 	hpaddr <<= PAGE_SHIFT;
-#if PAGE_SHIFT == 12
-#elif PAGE_SHIFT == 16
-	hpaddr |= orig_pte->raddr & 0xf000;
-#else
-#error Unknown page size
-#endif
+	hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
 
 	/* and write the mapping ea -> hpa into the pt */
 	vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
@@ -161,10 +145,7 @@
 	} else {
 		struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
 
-		dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
-			    ((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
-			    (rflags & HPTE_R_N) ? '-' : 'x',
-			    orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr);
+		trace_kvm_book3s_64_mmu_map(rflags, hpteg, va, hpaddr, orig_pte);
 
 		/* The ppc_md code may give us a secondary entry even though we
 		   asked for a primary. Fix up. */
@@ -191,7 +172,7 @@
 	u16 sid_map_mask;
 	static int backwards_map = 0;
 
-	if (vcpu->arch.msr & MSR_PR)
+	if (vcpu->arch.shared->msr & MSR_PR)
 		gvsid |= VSID_PR;
 
 	/* We might get collisions that trap in preceding order, so let's
@@ -219,8 +200,7 @@
 	map->guest_vsid = gvsid;
 	map->valid = true;
 
-	dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n",
-		    sid_map_mask, gvsid, map->host_vsid);
+	trace_kvm_book3s_slb_map(sid_map_mask, gvsid, map->host_vsid);
 
 	return map;
 }
@@ -292,7 +272,7 @@
 	to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
 	to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
 
-	dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid);
+	trace_kvm_book3s_slbmte(slb_vsid, slb_esid);
 
 	return 0;
 }
@@ -306,7 +286,7 @@
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
 	kvmppc_mmu_hpte_destroy(vcpu);
-	__destroy_context(to_book3s(vcpu)->context_id);
+	__destroy_context(to_book3s(vcpu)->context_id[0]);
 }
 
 int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
@@ -317,10 +297,10 @@
 	err = __init_new_context();
 	if (err < 0)
 		return -1;
-	vcpu3s->context_id = err;
+	vcpu3s->context_id[0] = err;
 
-	vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
-	vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
+	vcpu3s->vsid_max = ((vcpu3s->context_id[0] + 1) << USER_ESID_BITS) - 1;
+	vcpu3s->vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS;
 	vcpu3s->vsid_next = vcpu3s->vsid_first;
 
 	kvmppc_mmu_hpte_init(vcpu);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
 #include <linux/kvm_host.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include "trace.h"
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -35,7 +36,6 @@
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
 
 /* #define EXIT_DEBUG */
-/* #define EXIT_DEBUG_SIMPLE */
 /* #define DEBUG_EXT */
 
 static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
@@ -105,65 +105,71 @@
 	kvmppc_giveup_ext(vcpu, MSR_VSX);
 }
 
-#if defined(EXIT_DEBUG)
-static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu)
-{
-	u64 jd = mftb() - vcpu->arch.dec_jiffies;
-	return vcpu->arch.dec - jd;
-}
-#endif
-
 static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.shadow_msr = vcpu->arch.msr;
+	ulong smsr = vcpu->arch.shared->msr;
+
 	/* Guest MSR values */
-	vcpu->arch.shadow_msr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE |
-				 MSR_BE | MSR_DE;
+	smsr &= MSR_FE0 | MSR_FE1 | MSR_SF | MSR_SE | MSR_BE | MSR_DE;
 	/* Process MSR values */
-	vcpu->arch.shadow_msr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR |
-				 MSR_EE;
+	smsr |= MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_PR | MSR_EE;
 	/* External providers the guest reserved */
-	vcpu->arch.shadow_msr |= (vcpu->arch.msr & vcpu->arch.guest_owned_ext);
+	smsr |= (vcpu->arch.shared->msr & vcpu->arch.guest_owned_ext);
 	/* 64-bit Process MSR values */
 #ifdef CONFIG_PPC_BOOK3S_64
-	vcpu->arch.shadow_msr |= MSR_ISF | MSR_HV;
+	smsr |= MSR_ISF | MSR_HV;
 #endif
+	vcpu->arch.shadow_msr = smsr;
 }
 
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
 {
-	ulong old_msr = vcpu->arch.msr;
+	ulong old_msr = vcpu->arch.shared->msr;
 
 #ifdef EXIT_DEBUG
 	printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr);
 #endif
 
 	msr &= to_book3s(vcpu)->msr_mask;
-	vcpu->arch.msr = msr;
+	vcpu->arch.shared->msr = msr;
 	kvmppc_recalc_shadow_msr(vcpu);
 
-	if (msr & (MSR_WE|MSR_POW)) {
+	if (msr & MSR_POW) {
 		if (!vcpu->arch.pending_exceptions) {
 			kvm_vcpu_block(vcpu);
 			vcpu->stat.halt_wakeup++;
+
+			/* Unset POW bit after we woke up */
+			msr &= ~MSR_POW;
+			vcpu->arch.shared->msr = msr;
 		}
 	}
 
-	if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
+	if ((vcpu->arch.shared->msr & (MSR_PR|MSR_IR|MSR_DR)) !=
 		   (old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
 		kvmppc_mmu_flush_segments(vcpu);
 		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
+
+		/* Preload magic page segment when in kernel mode */
+		if (!(msr & MSR_PR) && vcpu->arch.magic_page_pa) {
+			struct kvm_vcpu_arch *a = &vcpu->arch;
+
+			if (msr & MSR_DR)
+				kvmppc_mmu_map_segment(vcpu, a->magic_page_ea);
+			else
+				kvmppc_mmu_map_segment(vcpu, a->magic_page_pa);
+		}
 	}
 
 	/* Preload FPU if it's enabled */
-	if (vcpu->arch.msr & MSR_FP)
+	if (vcpu->arch.shared->msr & MSR_FP)
 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 }
 
 void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
 {
-	vcpu->arch.srr0 = kvmppc_get_pc(vcpu);
-	vcpu->arch.srr1 = vcpu->arch.msr | flags;
+	vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu);
+	vcpu->arch.shared->srr1 = vcpu->arch.shared->msr | flags;
 	kvmppc_set_pc(vcpu, to_book3s(vcpu)->hior + vec);
 	vcpu->arch.mmu.reset_msr(vcpu);
 }
@@ -180,6 +186,7 @@
 	case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE;		break;
 	case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT;		break;
 	case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL;		break;
+	case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL;	break;
 	case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT;		break;
 	case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM;		break;
 	case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL;		break;
@@ -199,6 +206,9 @@
 {
 	clear_bit(kvmppc_book3s_vec2irqprio(vec),
 		  &vcpu->arch.pending_exceptions);
+
+	if (!vcpu->arch.pending_exceptions)
+		vcpu->arch.shared->int_pending = 0;
 }
 
 void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
@@ -237,13 +247,19 @@
 void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                 struct kvm_interrupt *irq)
 {
-	kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
+	unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL;
+
+	if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
+		vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL;
+
+	kvmppc_book3s_queue_irqprio(vcpu, vec);
 }
 
 void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
                                   struct kvm_interrupt *irq)
 {
 	kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL);
+	kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL);
 }
 
 int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
@@ -251,14 +267,29 @@
 	int deliver = 1;
 	int vec = 0;
 	ulong flags = 0ULL;
+	ulong crit_raw = vcpu->arch.shared->critical;
+	ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
+	bool crit;
+
+	/* Truncate crit indicators in 32 bit mode */
+	if (!(vcpu->arch.shared->msr & MSR_SF)) {
+		crit_raw &= 0xffffffff;
+		crit_r1 &= 0xffffffff;
+	}
+
+	/* Critical section when crit == r1 */
+	crit = (crit_raw == crit_r1);
+	/* ... and we're in supervisor mode */
+	crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
 
 	switch (priority) {
 	case BOOK3S_IRQPRIO_DECREMENTER:
-		deliver = vcpu->arch.msr & MSR_EE;
+		deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
 		vec = BOOK3S_INTERRUPT_DECREMENTER;
 		break;
 	case BOOK3S_IRQPRIO_EXTERNAL:
-		deliver = vcpu->arch.msr & MSR_EE;
+	case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
+		deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
 		vec = BOOK3S_INTERRUPT_EXTERNAL;
 		break;
 	case BOOK3S_IRQPRIO_SYSTEM_RESET:
@@ -320,9 +351,27 @@
 	return deliver;
 }
 
+/*
+ * This function determines if an irqprio should be cleared once issued.
+ */
+static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority)
+{
+	switch (priority) {
+		case BOOK3S_IRQPRIO_DECREMENTER:
+			/* DEC interrupts get cleared by mtdec */
+			return false;
+		case BOOK3S_IRQPRIO_EXTERNAL_LEVEL:
+			/* External interrupts get cleared by userspace */
+			return false;
+	}
+
+	return true;
+}
+
 void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
 {
 	unsigned long *pending = &vcpu->arch.pending_exceptions;
+	unsigned long old_pending = vcpu->arch.pending_exceptions;
 	unsigned int priority;
 
 #ifdef EXIT_DEBUG
@@ -332,8 +381,7 @@
 	priority = __ffs(*pending);
 	while (priority < BOOK3S_IRQPRIO_MAX) {
 		if (kvmppc_book3s_irqprio_deliver(vcpu, priority) &&
-		    (priority != BOOK3S_IRQPRIO_DECREMENTER)) {
-			/* DEC interrupts get cleared by mtdec */
+		    clear_irqprio(vcpu, priority)) {
 			clear_bit(priority, &vcpu->arch.pending_exceptions);
 			break;
 		}
@@ -342,6 +390,12 @@
 					 BITS_PER_BYTE * sizeof(*pending),
 					 priority + 1);
 	}
+
+	/* Tell the guest about our interrupt status */
+	if (*pending)
+		vcpu->arch.shared->int_pending = 1;
+	else if (old_pending)
+		vcpu->arch.shared->int_pending = 0;
 }
 
 void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
@@ -398,6 +452,25 @@
 	}
 }
 
+pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+	ulong mp_pa = vcpu->arch.magic_page_pa;
+
+	/* Magic page override */
+	if (unlikely(mp_pa) &&
+	    unlikely(((gfn << PAGE_SHIFT) & KVM_PAM) ==
+		     ((mp_pa & PAGE_MASK) & KVM_PAM))) {
+		ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
+		pfn_t pfn;
+
+		pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
+		get_page(pfn_to_page(pfn));
+		return pfn;
+	}
+
+	return gfn_to_pfn(vcpu->kvm, gfn);
+}
+
 /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
  * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to
  * emulate 32 bytes dcbz length.
@@ -415,8 +488,10 @@
 	int i;
 
 	hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
-	if (is_error_page(hpage))
+	if (is_error_page(hpage)) {
+		kvm_release_page_clean(hpage);
 		return;
+	}
 
 	hpage_offset = pte->raddr & ~PAGE_MASK;
 	hpage_offset &= ~0xFFFULL;
@@ -437,14 +512,14 @@
 static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
 			 struct kvmppc_pte *pte)
 {
-	int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR));
+	int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR));
 	int r;
 
 	if (relocated) {
 		r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data);
 	} else {
 		pte->eaddr = eaddr;
-		pte->raddr = eaddr & 0xffffffff;
+		pte->raddr = eaddr & KVM_PAM;
 		pte->vpage = VSID_REAL | eaddr >> 12;
 		pte->may_read = true;
 		pte->may_write = true;
@@ -533,6 +608,13 @@
 
 static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn)
 {
+	ulong mp_pa = vcpu->arch.magic_page_pa;
+
+	if (unlikely(mp_pa) &&
+	    unlikely((mp_pa & KVM_PAM) >> PAGE_SHIFT == gfn)) {
+		return 1;
+	}
+
 	return kvm_is_visible_gfn(vcpu->kvm, gfn);
 }
 
@@ -545,8 +627,8 @@
 	int page_found = 0;
 	struct kvmppc_pte pte;
 	bool is_mmio = false;
-	bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
-	bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
+	bool dr = (vcpu->arch.shared->msr & MSR_DR) ? true : false;
+	bool ir = (vcpu->arch.shared->msr & MSR_IR) ? true : false;
 	u64 vsid;
 
 	relocated = data ? dr : ir;
@@ -558,12 +640,12 @@
 		pte.may_execute = true;
 		pte.may_read = true;
 		pte.may_write = true;
-		pte.raddr = eaddr & 0xffffffff;
+		pte.raddr = eaddr & KVM_PAM;
 		pte.eaddr = eaddr;
 		pte.vpage = eaddr >> 12;
 	}
 
-	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
+	switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
 	case 0:
 		pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
 		break;
@@ -571,7 +653,7 @@
 	case MSR_IR:
 		vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
 
-		if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
+		if ((vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) == MSR_DR)
 			pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
 		else
 			pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
@@ -594,20 +676,23 @@
 
 	if (page_found == -ENOENT) {
 		/* Page not found in guest PTE entries */
-		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
-		to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
-		vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
+		vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
+		vcpu->arch.shared->msr |=
+			(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
 		kvmppc_book3s_queue_irqprio(vcpu, vec);
 	} else if (page_found == -EPERM) {
 		/* Storage protection */
-		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
-		to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
-		to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT;
-		vcpu->arch.msr |= (to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
+		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
+		vcpu->arch.shared->dsisr =
+			to_svcpu(vcpu)->fault_dsisr & ~DSISR_NOHPTE;
+		vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
+		vcpu->arch.shared->msr |=
+			(to_svcpu(vcpu)->shadow_srr1 & 0x00000000f8000000ULL);
 		kvmppc_book3s_queue_irqprio(vcpu, vec);
 	} else if (page_found == -EINVAL) {
 		/* Page not found in guest SLB */
-		vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+		vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
 		kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
 	} else if (!is_mmio &&
 		   kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
@@ -695,9 +780,11 @@
 
 	ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
 	if (ret == -ENOENT) {
-		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 33, 1);
-		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 34, 36, 0);
-		vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
+		ulong msr = vcpu->arch.shared->msr;
+
+		msr = kvmppc_set_field(msr, 33, 33, 1);
+		msr = kvmppc_set_field(msr, 34, 36, 0);
+		vcpu->arch.shared->msr = kvmppc_set_field(msr, 42, 47, 0);
 		kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
 		return EMULATE_AGAIN;
 	}
@@ -736,7 +823,7 @@
 	if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
 		return RESUME_GUEST;
 
-	if (!(vcpu->arch.msr & msr)) {
+	if (!(vcpu->arch.shared->msr & msr)) {
 		kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 		return RESUME_GUEST;
 	}
@@ -796,16 +883,8 @@
 
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
-#ifdef EXIT_DEBUG
-	printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n",
-		exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
-		kvmppc_get_dec(vcpu), to_svcpu(vcpu)->shadow_srr1);
-#elif defined (EXIT_DEBUG_SIMPLE)
-	if ((exit_nr != 0x900) && (exit_nr != 0x500))
-		printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n",
-			exit_nr, kvmppc_get_pc(vcpu), kvmppc_get_fault_dar(vcpu),
-			vcpu->arch.msr);
-#endif
+
+	trace_kvm_book3s_exit(exit_nr, vcpu);
 	kvm_resched(vcpu);
 	switch (exit_nr) {
 	case BOOK3S_INTERRUPT_INST_STORAGE:
@@ -836,9 +915,9 @@
 			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
 			r = RESUME_GUEST;
 		} else {
-			vcpu->arch.msr |= to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
+			vcpu->arch.shared->msr |=
+				to_svcpu(vcpu)->shadow_srr1 & 0x58000000;
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
-			kvmppc_mmu_pte_flush(vcpu, kvmppc_get_pc(vcpu), ~0xFFFUL);
 			r = RESUME_GUEST;
 		}
 		break;
@@ -861,17 +940,16 @@
 		if (to_svcpu(vcpu)->fault_dsisr & DSISR_NOHPTE) {
 			r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
 		} else {
-			vcpu->arch.dear = dar;
-			to_book3s(vcpu)->dsisr = to_svcpu(vcpu)->fault_dsisr;
+			vcpu->arch.shared->dar = dar;
+			vcpu->arch.shared->dsisr = to_svcpu(vcpu)->fault_dsisr;
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
-			kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFUL);
 			r = RESUME_GUEST;
 		}
 		break;
 	}
 	case BOOK3S_INTERRUPT_DATA_SEGMENT:
 		if (kvmppc_mmu_map_segment(vcpu, kvmppc_get_fault_dar(vcpu)) < 0) {
-			vcpu->arch.dear = kvmppc_get_fault_dar(vcpu);
+			vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
 			kvmppc_book3s_queue_irqprio(vcpu,
 				BOOK3S_INTERRUPT_DATA_SEGMENT);
 		}
@@ -904,7 +982,7 @@
 program_interrupt:
 		flags = to_svcpu(vcpu)->shadow_srr1 & 0x1f0000ull;
 
-		if (vcpu->arch.msr & MSR_PR) {
+		if (vcpu->arch.shared->msr & MSR_PR) {
 #ifdef EXIT_DEBUG
 			printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
 #endif
@@ -941,10 +1019,10 @@
 		break;
 	}
 	case BOOK3S_INTERRUPT_SYSCALL:
-		// XXX make user settable
 		if (vcpu->arch.osi_enabled &&
 		    (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
 		    (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
+			/* MOL hypercalls */
 			u64 *gprs = run->osi.gprs;
 			int i;
 
@@ -953,8 +1031,13 @@
 				gprs[i] = kvmppc_get_gpr(vcpu, i);
 			vcpu->arch.osi_needed = 1;
 			r = RESUME_HOST_NV;
-
+		} else if (!(vcpu->arch.shared->msr & MSR_PR) &&
+		    (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
+			/* KVM PV hypercalls */
+			kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
+			r = RESUME_GUEST;
 		} else {
+			/* Guest syscalls */
 			vcpu->stat.syscall_exits++;
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 			r = RESUME_GUEST;
@@ -989,9 +1072,9 @@
 	}
 	case BOOK3S_INTERRUPT_ALIGNMENT:
 		if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
-			to_book3s(vcpu)->dsisr = kvmppc_alignment_dsisr(vcpu,
+			vcpu->arch.shared->dsisr = kvmppc_alignment_dsisr(vcpu,
 				kvmppc_get_last_inst(vcpu));
-			vcpu->arch.dear = kvmppc_alignment_dar(vcpu,
+			vcpu->arch.shared->dar = kvmppc_alignment_dar(vcpu,
 				kvmppc_get_last_inst(vcpu));
 			kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
 		}
@@ -1031,9 +1114,7 @@
 		}
 	}
 
-#ifdef EXIT_DEBUG
-	printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, kvmppc_get_pc(vcpu), r);
-#endif
+	trace_kvm_book3s_reenter(r, vcpu);
 
 	return r;
 }
@@ -1052,14 +1133,14 @@
 	regs->ctr = kvmppc_get_ctr(vcpu);
 	regs->lr = kvmppc_get_lr(vcpu);
 	regs->xer = kvmppc_get_xer(vcpu);
-	regs->msr = vcpu->arch.msr;
-	regs->srr0 = vcpu->arch.srr0;
-	regs->srr1 = vcpu->arch.srr1;
+	regs->msr = vcpu->arch.shared->msr;
+	regs->srr0 = vcpu->arch.shared->srr0;
+	regs->srr1 = vcpu->arch.shared->srr1;
 	regs->pid = vcpu->arch.pid;
-	regs->sprg0 = vcpu->arch.sprg0;
-	regs->sprg1 = vcpu->arch.sprg1;
-	regs->sprg2 = vcpu->arch.sprg2;
-	regs->sprg3 = vcpu->arch.sprg3;
+	regs->sprg0 = vcpu->arch.shared->sprg0;
+	regs->sprg1 = vcpu->arch.shared->sprg1;
+	regs->sprg2 = vcpu->arch.shared->sprg2;
+	regs->sprg3 = vcpu->arch.shared->sprg3;
 	regs->sprg5 = vcpu->arch.sprg4;
 	regs->sprg6 = vcpu->arch.sprg5;
 	regs->sprg7 = vcpu->arch.sprg6;
@@ -1080,12 +1161,12 @@
 	kvmppc_set_lr(vcpu, regs->lr);
 	kvmppc_set_xer(vcpu, regs->xer);
 	kvmppc_set_msr(vcpu, regs->msr);
-	vcpu->arch.srr0 = regs->srr0;
-	vcpu->arch.srr1 = regs->srr1;
-	vcpu->arch.sprg0 = regs->sprg0;
-	vcpu->arch.sprg1 = regs->sprg1;
-	vcpu->arch.sprg2 = regs->sprg2;
-	vcpu->arch.sprg3 = regs->sprg3;
+	vcpu->arch.shared->srr0 = regs->srr0;
+	vcpu->arch.shared->srr1 = regs->srr1;
+	vcpu->arch.shared->sprg0 = regs->sprg0;
+	vcpu->arch.shared->sprg1 = regs->sprg1;
+	vcpu->arch.shared->sprg2 = regs->sprg2;
+	vcpu->arch.shared->sprg3 = regs->sprg3;
 	vcpu->arch.sprg5 = regs->sprg4;
 	vcpu->arch.sprg6 = regs->sprg5;
 	vcpu->arch.sprg7 = regs->sprg6;
@@ -1111,10 +1192,9 @@
 			sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv;
 		}
 	} else {
-		for (i = 0; i < 16; i++) {
-			sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
-			sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw;
-		}
+		for (i = 0; i < 16; i++)
+			sregs->u.s.ppc32.sr[i] = vcpu->arch.shared->sr[i];
+
 		for (i = 0; i < 8; i++) {
 			sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw;
 			sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw;
@@ -1225,6 +1305,7 @@
 	struct kvmppc_vcpu_book3s *vcpu_book3s;
 	struct kvm_vcpu *vcpu;
 	int err = -ENOMEM;
+	unsigned long p;
 
 	vcpu_book3s = vmalloc(sizeof(struct kvmppc_vcpu_book3s));
 	if (!vcpu_book3s)
@@ -1242,6 +1323,12 @@
 	if (err)
 		goto free_shadow_vcpu;
 
+	p = __get_free_page(GFP_KERNEL|__GFP_ZERO);
+	/* the real shared page fills the last 4k of our page */
+	vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096);
+	if (!p)
+		goto uninit_vcpu;
+
 	vcpu->arch.host_retip = kvm_return_point;
 	vcpu->arch.host_msr = mfmsr();
 #ifdef CONFIG_PPC_BOOK3S_64
@@ -1268,10 +1355,12 @@
 
 	err = kvmppc_mmu_init(vcpu);
 	if (err < 0)
-		goto free_shadow_vcpu;
+		goto uninit_vcpu;
 
 	return vcpu;
 
+uninit_vcpu:
+	kvm_vcpu_uninit(vcpu);
 free_shadow_vcpu:
 	kfree(vcpu_book3s->shadow_vcpu);
 free_vcpu:
@@ -1284,6 +1373,7 @@
 {
 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
 
+	free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
 	kvm_vcpu_uninit(vcpu);
 	kfree(vcpu_book3s->shadow_vcpu);
 	vfree(vcpu_book3s);
@@ -1346,7 +1436,7 @@
 	local_irq_enable();
 
 	/* Preload FPU if it's enabled */
-	if (vcpu->arch.msr & MSR_FP)
+	if (vcpu->arch.shared->msr & MSR_FP)
 		kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 
 	ret = __kvmppc_vcpu_entry(kvm_run, vcpu);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_emulate.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_emulate.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_emulate.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_emulate.c	2011-01-04 19:50:19.000000000 -0500
@@ -73,8 +73,8 @@
 		switch (get_xop(inst)) {
 		case OP_19_XOP_RFID:
 		case OP_19_XOP_RFI:
-			kvmppc_set_pc(vcpu, vcpu->arch.srr0);
-			kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+			kvmppc_set_pc(vcpu, vcpu->arch.shared->srr0);
+			kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
 			*advance = 0;
 			break;
 
@@ -86,14 +86,15 @@
 	case 31:
 		switch (get_xop(inst)) {
 		case OP_31_XOP_MFMSR:
-			kvmppc_set_gpr(vcpu, get_rt(inst), vcpu->arch.msr);
+			kvmppc_set_gpr(vcpu, get_rt(inst),
+				       vcpu->arch.shared->msr);
 			break;
 		case OP_31_XOP_MTMSRD:
 		{
 			ulong rs = kvmppc_get_gpr(vcpu, get_rs(inst));
 			if (inst & 0x10000) {
-				vcpu->arch.msr &= ~(MSR_RI | MSR_EE);
-				vcpu->arch.msr |= rs & (MSR_RI | MSR_EE);
+				vcpu->arch.shared->msr &= ~(MSR_RI | MSR_EE);
+				vcpu->arch.shared->msr |= rs & (MSR_RI | MSR_EE);
 			} else
 				kvmppc_set_msr(vcpu, rs);
 			break;
@@ -204,14 +205,14 @@
 				ra = kvmppc_get_gpr(vcpu, get_ra(inst));
 
 			addr = (ra + rb) & ~31ULL;
-			if (!(vcpu->arch.msr & MSR_SF))
+			if (!(vcpu->arch.shared->msr & MSR_SF))
 				addr &= 0xffffffff;
 			vaddr = addr;
 
 			r = kvmppc_st(vcpu, &addr, 32, zeros, true);
 			if ((r == -ENOENT) || (r == -EPERM)) {
 				*advance = 0;
-				vcpu->arch.dear = vaddr;
+				vcpu->arch.shared->dar = vaddr;
 				to_svcpu(vcpu)->fault_dar = vaddr;
 
 				dsisr = DSISR_ISSTORE;
@@ -220,7 +221,7 @@
 				else if (r == -EPERM)
 					dsisr |= DSISR_PROTFAULT;
 
-				to_book3s(vcpu)->dsisr = dsisr;
+				vcpu->arch.shared->dsisr = dsisr;
 				to_svcpu(vcpu)->fault_dsisr = dsisr;
 
 				kvmppc_book3s_queue_irqprio(vcpu,
@@ -263,35 +264,7 @@
 	}
 }
 
-static u32 kvmppc_read_bat(struct kvm_vcpu *vcpu, int sprn)
-{
-	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
-	struct kvmppc_bat *bat;
-
-	switch (sprn) {
-	case SPRN_IBAT0U ... SPRN_IBAT3L:
-		bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2];
-		break;
-	case SPRN_IBAT4U ... SPRN_IBAT7L:
-		bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)];
-		break;
-	case SPRN_DBAT0U ... SPRN_DBAT3L:
-		bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2];
-		break;
-	case SPRN_DBAT4U ... SPRN_DBAT7L:
-		bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)];
-		break;
-	default:
-		BUG();
-	}
-
-	if (sprn % 2)
-		return bat->raw >> 32;
-	else
-		return bat->raw;
-}
-
-static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val)
+static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn)
 {
 	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
 	struct kvmppc_bat *bat;
@@ -313,7 +286,7 @@
 		BUG();
 	}
 
-	kvmppc_set_bat(vcpu, bat, !(sprn % 2), val);
+	return bat;
 }
 
 int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
@@ -326,10 +299,10 @@
 		to_book3s(vcpu)->sdr1 = spr_val;
 		break;
 	case SPRN_DSISR:
-		to_book3s(vcpu)->dsisr = spr_val;
+		vcpu->arch.shared->dsisr = spr_val;
 		break;
 	case SPRN_DAR:
-		vcpu->arch.dear = spr_val;
+		vcpu->arch.shared->dar = spr_val;
 		break;
 	case SPRN_HIOR:
 		to_book3s(vcpu)->hior = spr_val;
@@ -338,12 +311,16 @@
 	case SPRN_IBAT4U ... SPRN_IBAT7L:
 	case SPRN_DBAT0U ... SPRN_DBAT3L:
 	case SPRN_DBAT4U ... SPRN_DBAT7L:
-		kvmppc_write_bat(vcpu, sprn, (u32)spr_val);
+	{
+		struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
+
+		kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val);
 		/* BAT writes happen so rarely that we're ok to flush
 		 * everything here */
 		kvmppc_mmu_pte_flush(vcpu, 0, 0);
 		kvmppc_mmu_flush_segments(vcpu);
 		break;
+	}
 	case SPRN_HID0:
 		to_book3s(vcpu)->hid[0] = spr_val;
 		break;
@@ -433,16 +410,24 @@
 	case SPRN_IBAT4U ... SPRN_IBAT7L:
 	case SPRN_DBAT0U ... SPRN_DBAT3L:
 	case SPRN_DBAT4U ... SPRN_DBAT7L:
-		kvmppc_set_gpr(vcpu, rt, kvmppc_read_bat(vcpu, sprn));
+	{
+		struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn);
+
+		if (sprn % 2)
+			kvmppc_set_gpr(vcpu, rt, bat->raw >> 32);
+		else
+			kvmppc_set_gpr(vcpu, rt, bat->raw);
+
 		break;
+	}
 	case SPRN_SDR1:
 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
 		break;
 	case SPRN_DSISR:
-		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->dsisr);
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dsisr);
 		break;
 	case SPRN_DAR:
-		kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear);
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar);
 		break;
 	case SPRN_HIOR:
 		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->hior);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_mmu_hpte.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_mmu_hpte.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_mmu_hpte.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_mmu_hpte.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/kvm_host.h>
 #include <linux/hash.h>
 #include <linux/slab.h>
+#include "trace.h"
 
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
@@ -30,14 +31,6 @@
 
 #define PTE_SIZE	12
 
-/* #define DEBUG_MMU */
-
-#ifdef DEBUG_MMU
-#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
-#else
-#define dprintk_mmu(a, ...) do { } while(0)
-#endif
-
 static struct kmem_cache *hpte_cache;
 
 static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
@@ -45,6 +38,12 @@
 	return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
 }
 
+static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr)
+{
+	return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE,
+		       HPTEG_HASH_BITS_PTE_LONG);
+}
+
 static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
 {
 	return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
@@ -60,77 +59,128 @@
 {
 	u64 index;
 
+	trace_kvm_book3s_mmu_map(pte);
+
+	spin_lock(&vcpu->arch.mmu_lock);
+
 	/* Add to ePTE list */
 	index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
-	hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+	hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
+
+	/* Add to ePTE_long list */
+	index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
+	hlist_add_head_rcu(&pte->list_pte_long,
+			   &vcpu->arch.hpte_hash_pte_long[index]);
 
 	/* Add to vPTE list */
 	index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
-	hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
+	hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
 
 	/* Add to vPTE_long list */
 	index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
-	hlist_add_head(&pte->list_vpte_long,
-		       &vcpu->arch.hpte_hash_vpte_long[index]);
+	hlist_add_head_rcu(&pte->list_vpte_long,
+			   &vcpu->arch.hpte_hash_vpte_long[index]);
+
+	spin_unlock(&vcpu->arch.mmu_lock);
+}
+
+static void free_pte_rcu(struct rcu_head *head)
+{
+	struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head);
+	kmem_cache_free(hpte_cache, pte);
 }
 
 static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
 {
-	dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
-		    pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+	trace_kvm_book3s_mmu_invalidate(pte);
 
 	/* Different for 32 and 64 bit */
 	kvmppc_mmu_invalidate_pte(vcpu, pte);
 
+	spin_lock(&vcpu->arch.mmu_lock);
+
+	/* pte already invalidated in between? */
+	if (hlist_unhashed(&pte->list_pte)) {
+		spin_unlock(&vcpu->arch.mmu_lock);
+		return;
+	}
+
+	hlist_del_init_rcu(&pte->list_pte);
+	hlist_del_init_rcu(&pte->list_pte_long);
+	hlist_del_init_rcu(&pte->list_vpte);
+	hlist_del_init_rcu(&pte->list_vpte_long);
+
 	if (pte->pte.may_write)
 		kvm_release_pfn_dirty(pte->pfn);
 	else
 		kvm_release_pfn_clean(pte->pfn);
 
-	hlist_del(&pte->list_pte);
-	hlist_del(&pte->list_vpte);
-	hlist_del(&pte->list_vpte_long);
+	spin_unlock(&vcpu->arch.mmu_lock);
 
 	vcpu->arch.hpte_cache_count--;
-	kmem_cache_free(hpte_cache, pte);
+	call_rcu(&pte->rcu_head, free_pte_rcu);
 }
 
 static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
 {
 	struct hpte_cache *pte;
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
 	int i;
 
+	rcu_read_lock();
+
 	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
 		struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
 
-		hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+		hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
 			invalidate_pte(vcpu, pte);
 	}
+
+	rcu_read_unlock();
 }
 
 static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
 {
 	struct hlist_head *list;
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
 	struct hpte_cache *pte;
 
 	/* Find the list of entries in the map */
 	list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
 
+	rcu_read_lock();
+
 	/* Check the list for matching entries and invalidate */
-	hlist_for_each_entry_safe(pte, node, tmp, list, list_pte)
+	hlist_for_each_entry_rcu(pte, node, list, list_pte)
 		if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
 			invalidate_pte(vcpu, pte);
+
+	rcu_read_unlock();
 }
 
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
 {
-	u64 i;
+	struct hlist_head *list;
+	struct hlist_node *node;
+	struct hpte_cache *pte;
 
-	dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
-		    vcpu->arch.hpte_cache_count, guest_ea, ea_mask);
+	/* Find the list of entries in the map */
+	list = &vcpu->arch.hpte_hash_pte_long[
+			kvmppc_mmu_hash_pte_long(guest_ea)];
+
+	rcu_read_lock();
 
+	/* Check the list for matching entries and invalidate */
+	hlist_for_each_entry_rcu(pte, node, list, list_pte_long)
+		if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea)
+			invalidate_pte(vcpu, pte);
+
+	rcu_read_unlock();
+}
+
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
+{
+	trace_kvm_book3s_mmu_flush("", vcpu, guest_ea, ea_mask);
 	guest_ea &= ea_mask;
 
 	switch (ea_mask) {
@@ -138,9 +188,7 @@
 		kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
 		break;
 	case 0x0ffff000:
-		/* 32-bit flush w/o segment, go through all possible segments */
-		for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
-			kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
+		kvmppc_mmu_pte_flush_long(vcpu, guest_ea);
 		break;
 	case 0:
 		/* Doing a complete flush -> start from scratch */
@@ -156,39 +204,46 @@
 static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
 {
 	struct hlist_head *list;
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
 	struct hpte_cache *pte;
 	u64 vp_mask = 0xfffffffffULL;
 
 	list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
 
+	rcu_read_lock();
+
 	/* Check the list for matching entries and invalidate */
-	hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte)
+	hlist_for_each_entry_rcu(pte, node, list, list_vpte)
 		if ((pte->pte.vpage & vp_mask) == guest_vp)
 			invalidate_pte(vcpu, pte);
+
+	rcu_read_unlock();
 }
 
 /* Flush with mask 0xffffff000 */
 static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
 {
 	struct hlist_head *list;
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
 	struct hpte_cache *pte;
 	u64 vp_mask = 0xffffff000ULL;
 
 	list = &vcpu->arch.hpte_hash_vpte_long[
 		kvmppc_mmu_hash_vpte_long(guest_vp)];
 
+	rcu_read_lock();
+
 	/* Check the list for matching entries and invalidate */
-	hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+	hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
 		if ((pte->pte.vpage & vp_mask) == guest_vp)
 			invalidate_pte(vcpu, pte);
+
+	rcu_read_unlock();
 }
 
 void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
 {
-	dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n",
-		    vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
+	trace_kvm_book3s_mmu_flush("v", vcpu, guest_vp, vp_mask);
 	guest_vp &= vp_mask;
 
 	switch(vp_mask) {
@@ -206,21 +261,24 @@
 
 void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
 {
-	struct hlist_node *node, *tmp;
+	struct hlist_node *node;
 	struct hpte_cache *pte;
 	int i;
 
-	dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n",
-		    vcpu->arch.hpte_cache_count, pa_start, pa_end);
+	trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end);
+
+	rcu_read_lock();
 
 	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
 		struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
 
-		hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long)
+		hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
 			if ((pte->pte.raddr >= pa_start) &&
 			    (pte->pte.raddr < pa_end))
 				invalidate_pte(vcpu, pte);
 	}
+
+	rcu_read_unlock();
 }
 
 struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
@@ -254,11 +312,15 @@
 	/* init hpte lookup hashes */
 	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
 				  ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
+	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
+				  ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
 	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
 				  ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
 	kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
 				  ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
 
+	spin_lock_init(&vcpu->arch.mmu_lock);
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_paired_singles.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_paired_singles.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_paired_singles.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_paired_singles.c	2011-01-04 19:50:19.000000000 -0500
@@ -159,20 +159,21 @@
 
 static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
 {
-	kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt], &vcpu->arch.fpscr);
+	kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt]);
 }
 
 static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
 {
 	u64 dsisr;
+	struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared;
 
-	vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 33, 36, 0);
-	vcpu->arch.msr = kvmppc_set_field(vcpu->arch.msr, 42, 47, 0);
-	vcpu->arch.dear = eaddr;
+	shared->msr = kvmppc_set_field(shared->msr, 33, 36, 0);
+	shared->msr = kvmppc_set_field(shared->msr, 42, 47, 0);
+	shared->dar = eaddr;
 	/* Page Fault */
 	dsisr = kvmppc_set_field(0, 33, 33, 1);
 	if (is_store)
-		to_book3s(vcpu)->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
+		shared->dsisr = kvmppc_set_field(dsisr, 38, 38, 1);
 	kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
 }
 
@@ -204,7 +205,7 @@
 	/* put in registers */
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
+		kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs]);
 		vcpu->arch.qpr[rs] = *((u32*)tmp);
 		break;
 	case FPU_LS_DOUBLE:
@@ -230,7 +231,7 @@
 
 	switch (ls_type) {
 	case FPU_LS_SINGLE:
-		kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp, &vcpu->arch.fpscr);
+		kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp);
 		val = *((u32*)tmp);
 		len = sizeof(u32);
 		break;
@@ -296,7 +297,7 @@
 	emulated = EMULATE_DONE;
 
 	/* put in registers */
-	kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
+	kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs]);
 	vcpu->arch.qpr[rs] = tmp[1];
 
 	dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
@@ -314,7 +315,7 @@
 	u32 tmp[2];
 	int len = w ? sizeof(u32) : sizeof(u64);
 
-	kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0], &vcpu->arch.fpscr);
+	kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0]);
 	tmp[1] = vcpu->arch.qpr[rs];
 
 	r = kvmppc_st(vcpu, &addr, len, tmp, true);
@@ -516,9 +517,9 @@
 	WARN_ON(rc);
 
 	/* PS0 */
-	kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
-	kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
-	kvm_cvt_df(&fpr[reg_in3], &ps0_in3, &vcpu->arch.fpscr);
+	kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
+	kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
+	kvm_cvt_df(&fpr[reg_in3], &ps0_in3);
 
 	if (scalar & SCALAR_LOW)
 		ps0_in2 = qpr[reg_in2];
@@ -529,7 +530,7 @@
 			  ps0_in1, ps0_in2, ps0_in3, ps0_out);
 
 	if (!(scalar & SCALAR_NO_PS0))
-		kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+		kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
 
 	/* PS1 */
 	ps1_in1 = qpr[reg_in1];
@@ -566,12 +567,12 @@
 	WARN_ON(rc);
 
 	/* PS0 */
-	kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
+	kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
 
 	if (scalar & SCALAR_LOW)
 		ps0_in2 = qpr[reg_in2];
 	else
-		kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
+		kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
 
 	func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
 
@@ -579,7 +580,7 @@
 		dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
 				  ps0_in1, ps0_in2, ps0_out);
 
-		kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+		kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
 	}
 
 	/* PS1 */
@@ -615,13 +616,13 @@
 	WARN_ON(rc);
 
 	/* PS0 */
-	kvm_cvt_df(&fpr[reg_in], &ps0_in, &vcpu->arch.fpscr);
+	kvm_cvt_df(&fpr[reg_in], &ps0_in);
 	func(&vcpu->arch.fpscr, &ps0_out, &ps0_in);
 
 	dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
 			  ps0_in, ps0_out);
 
-	kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+	kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
 
 	/* PS1 */
 	ps1_in = qpr[reg_in];
@@ -658,7 +659,7 @@
 	if (!kvmppc_inst_is_paired_single(vcpu, inst))
 		return EMULATE_FAIL;
 
-	if (!(vcpu->arch.msr & MSR_FP)) {
+	if (!(vcpu->arch.shared->msr & MSR_FP)) {
 		kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL);
 		return EMULATE_AGAIN;
 	}
@@ -671,7 +672,7 @@
 #ifdef DEBUG
 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
 		u32 f;
-		kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
+		kvm_cvt_df(&vcpu->arch.fpr[i], &f);
 		dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx    QPR[%d] = 0x%x\n",
 			i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
 	}
@@ -796,8 +797,7 @@
 			vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
 			/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
 			kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
-				   &vcpu->arch.qpr[ax_rd],
-				   &vcpu->arch.fpscr);
+				   &vcpu->arch.qpr[ax_rd]);
 			break;
 		case OP_4X_PS_MERGE01:
 			WARN_ON(rcomp);
@@ -808,19 +808,16 @@
 			WARN_ON(rcomp);
 			/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
 			kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-				   &vcpu->arch.fpr[ax_rd],
-				   &vcpu->arch.fpscr);
+				   &vcpu->arch.fpr[ax_rd]);
 			/* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
 			kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
-				   &vcpu->arch.qpr[ax_rd],
-				   &vcpu->arch.fpscr);
+				   &vcpu->arch.qpr[ax_rd]);
 			break;
 		case OP_4X_PS_MERGE11:
 			WARN_ON(rcomp);
 			/* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
 			kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-				   &vcpu->arch.fpr[ax_rd],
-				   &vcpu->arch.fpscr);
+				   &vcpu->arch.fpr[ax_rd]);
 			vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
 			break;
 		}
@@ -1255,7 +1252,7 @@
 #ifdef DEBUG
 	for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
 		u32 f;
-		kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
+		kvm_cvt_df(&vcpu->arch.fpr[i], &f);
 		dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
 	}
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_rmhandlers.S linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_rmhandlers.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/book3s_rmhandlers.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/book3s_rmhandlers.S	2011-01-04 19:50:19.000000000 -0500
@@ -202,8 +202,25 @@
 
 #if defined(CONFIG_PPC_BOOK3S_32)
 #define STACK_LR	INT_FRAME_SIZE+4
+
+/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */
+#define MSR_EXT_START						\
+	PPC_STL	r20, _NIP(r1);					\
+	mfmsr	r20;						\
+	LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE);			\
+	andc	r3,r20,r3;		/* Disable DR,EE */	\
+	mtmsr	r3;						\
+	sync
+
+#define MSR_EXT_END						\
+	mtmsr	r20;			/* Enable DR,EE */	\
+	sync;							\
+	PPC_LL	r20, _NIP(r1)
+
 #elif defined(CONFIG_PPC_BOOK3S_64)
 #define STACK_LR	_LINK
+#define MSR_EXT_START
+#define MSR_EXT_END
 #endif
 
 /*
@@ -215,19 +232,12 @@
 	PPC_STLU r1, -INT_FRAME_SIZE(r1);			\
 	mflr	r3;						\
 	PPC_STL	r3, STACK_LR(r1);				\
-	PPC_STL	r20, _NIP(r1);					\
-	mfmsr	r20;						\
-	LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE);			\
-	andc	r3,r20,r3;		/* Disable DR,EE */	\
-	mtmsr	r3;						\
-	sync;							\
+	MSR_EXT_START;						\
 								\
 	bl	FUNC(load_up_ ## what);				\
 								\
-	mtmsr	r20;			/* Enable DR,EE */	\
-	sync;							\
+	MSR_EXT_END;						\
 	PPC_LL	r3, STACK_LR(r1);				\
-	PPC_LL	r20, _NIP(r1);					\
 	mtlr	r3;						\
 	addi	r1, r1, INT_FRAME_SIZE;				\
 	blr
@@ -242,10 +252,10 @@
 
 .global kvmppc_trampoline_lowmem
 kvmppc_trampoline_lowmem:
-	.long kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START
+	PPC_LONG kvmppc_handler_lowmem_trampoline - CONFIG_KERNEL_START
 
 .global kvmppc_trampoline_enter
 kvmppc_trampoline_enter:
-	.long kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START
+	PPC_LONG kvmppc_handler_trampoline_enter - CONFIG_KERNEL_START
 
 #include "book3s_segment.S"
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke.c	2011-01-04 19:50:19.000000000 -0500
@@ -62,9 +62,10 @@
 {
 	int i;
 
-	printk("pc:   %08lx msr:  %08lx\n", vcpu->arch.pc, vcpu->arch.msr);
+	printk("pc:   %08lx msr:  %08llx\n", vcpu->arch.pc, vcpu->arch.shared->msr);
 	printk("lr:   %08lx ctr:  %08lx\n", vcpu->arch.lr, vcpu->arch.ctr);
-	printk("srr0: %08lx srr1: %08lx\n", vcpu->arch.srr0, vcpu->arch.srr1);
+	printk("srr0: %08llx srr1: %08llx\n", vcpu->arch.shared->srr0,
+					    vcpu->arch.shared->srr1);
 
 	printk("exceptions: %08lx\n", vcpu->arch.pending_exceptions);
 
@@ -130,13 +131,19 @@
 void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                 struct kvm_interrupt *irq)
 {
-	kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL);
+	unsigned int prio = BOOKE_IRQPRIO_EXTERNAL;
+
+	if (irq->irq == KVM_INTERRUPT_SET_LEVEL)
+		prio = BOOKE_IRQPRIO_EXTERNAL_LEVEL;
+
+	kvmppc_booke_queue_irqprio(vcpu, prio);
 }
 
 void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
                                   struct kvm_interrupt *irq)
 {
 	clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
+	clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
 }
 
 /* Deliver the interrupt of the corresponding priority, if possible. */
@@ -146,6 +153,26 @@
 	int allowed = 0;
 	ulong uninitialized_var(msr_mask);
 	bool update_esr = false, update_dear = false;
+	ulong crit_raw = vcpu->arch.shared->critical;
+	ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
+	bool crit;
+	bool keep_irq = false;
+
+	/* Truncate crit indicators in 32 bit mode */
+	if (!(vcpu->arch.shared->msr & MSR_SF)) {
+		crit_raw &= 0xffffffff;
+		crit_r1 &= 0xffffffff;
+	}
+
+	/* Critical section when crit == r1 */
+	crit = (crit_raw == crit_r1);
+	/* ... and we're in supervisor mode */
+	crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
+
+	if (priority == BOOKE_IRQPRIO_EXTERNAL_LEVEL) {
+		priority = BOOKE_IRQPRIO_EXTERNAL;
+		keep_irq = true;
+	}
 
 	switch (priority) {
 	case BOOKE_IRQPRIO_DTLB_MISS:
@@ -169,36 +196,38 @@
 		break;
 	case BOOKE_IRQPRIO_CRITICAL:
 	case BOOKE_IRQPRIO_WATCHDOG:
-		allowed = vcpu->arch.msr & MSR_CE;
+		allowed = vcpu->arch.shared->msr & MSR_CE;
 		msr_mask = MSR_ME;
 		break;
 	case BOOKE_IRQPRIO_MACHINE_CHECK:
-		allowed = vcpu->arch.msr & MSR_ME;
+		allowed = vcpu->arch.shared->msr & MSR_ME;
 		msr_mask = 0;
 		break;
 	case BOOKE_IRQPRIO_EXTERNAL:
 	case BOOKE_IRQPRIO_DECREMENTER:
 	case BOOKE_IRQPRIO_FIT:
-		allowed = vcpu->arch.msr & MSR_EE;
+		allowed = vcpu->arch.shared->msr & MSR_EE;
+		allowed = allowed && !crit;
 		msr_mask = MSR_CE|MSR_ME|MSR_DE;
 		break;
 	case BOOKE_IRQPRIO_DEBUG:
-		allowed = vcpu->arch.msr & MSR_DE;
+		allowed = vcpu->arch.shared->msr & MSR_DE;
 		msr_mask = MSR_ME;
 		break;
 	}
 
 	if (allowed) {
-		vcpu->arch.srr0 = vcpu->arch.pc;
-		vcpu->arch.srr1 = vcpu->arch.msr;
+		vcpu->arch.shared->srr0 = vcpu->arch.pc;
+		vcpu->arch.shared->srr1 = vcpu->arch.shared->msr;
 		vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
 		if (update_esr == true)
 			vcpu->arch.esr = vcpu->arch.queued_esr;
 		if (update_dear == true)
-			vcpu->arch.dear = vcpu->arch.queued_dear;
-		kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask);
+			vcpu->arch.shared->dar = vcpu->arch.queued_dear;
+		kvmppc_set_msr(vcpu, vcpu->arch.shared->msr & msr_mask);
 
-		clear_bit(priority, &vcpu->arch.pending_exceptions);
+		if (!keep_irq)
+			clear_bit(priority, &vcpu->arch.pending_exceptions);
 	}
 
 	return allowed;
@@ -208,6 +237,7 @@
 void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
 {
 	unsigned long *pending = &vcpu->arch.pending_exceptions;
+	unsigned long old_pending = vcpu->arch.pending_exceptions;
 	unsigned int priority;
 
 	priority = __ffs(*pending);
@@ -219,6 +249,12 @@
 		                         BITS_PER_BYTE * sizeof(*pending),
 		                         priority + 1);
 	}
+
+	/* Tell the guest about our interrupt status */
+	if (*pending)
+		vcpu->arch.shared->int_pending = 1;
+	else if (old_pending)
+		vcpu->arch.shared->int_pending = 0;
 }
 
 /**
@@ -265,7 +301,7 @@
 		break;
 
 	case BOOKE_INTERRUPT_PROGRAM:
-		if (vcpu->arch.msr & MSR_PR) {
+		if (vcpu->arch.shared->msr & MSR_PR) {
 			/* Program traps generated by user-level software must be handled
 			 * by the guest kernel. */
 			kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr);
@@ -337,7 +373,15 @@
 		break;
 
 	case BOOKE_INTERRUPT_SYSCALL:
-		kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
+		if (!(vcpu->arch.shared->msr & MSR_PR) &&
+		    (((u32)kvmppc_get_gpr(vcpu, 0)) == KVM_SC_MAGIC_R0)) {
+			/* KVM PV hypercalls */
+			kvmppc_set_gpr(vcpu, 3, kvmppc_kvm_pv(vcpu));
+			r = RESUME_GUEST;
+		} else {
+			/* Guest syscalls */
+			kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
+		}
 		kvmppc_account_exit(vcpu, SYSCALL_EXITS);
 		r = RESUME_GUEST;
 		break;
@@ -466,15 +510,19 @@
 /* Initial guest state: 16MB mapping 0 -> 0, PC = 0, MSR = 0, R1 = 16MB */
 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
+	int i;
+
 	vcpu->arch.pc = 0;
-	vcpu->arch.msr = 0;
+	vcpu->arch.shared->msr = 0;
 	kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 
 	vcpu->arch.shadow_pid = 1;
 
-	/* Eye-catching number so we know if the guest takes an interrupt
-	 * before it's programmed its own IVPR. */
+	/* Eye-catching numbers so we know if the guest takes an interrupt
+	 * before it's programmed its own IVPR/IVORs. */
 	vcpu->arch.ivpr = 0x55550000;
+	for (i = 0; i < BOOKE_IRQPRIO_MAX; i++)
+		vcpu->arch.ivor[i] = 0x7700 | i * 4;
 
 	kvmppc_init_timing_stats(vcpu);
 
@@ -490,14 +538,14 @@
 	regs->ctr = vcpu->arch.ctr;
 	regs->lr = vcpu->arch.lr;
 	regs->xer = kvmppc_get_xer(vcpu);
-	regs->msr = vcpu->arch.msr;
-	regs->srr0 = vcpu->arch.srr0;
-	regs->srr1 = vcpu->arch.srr1;
+	regs->msr = vcpu->arch.shared->msr;
+	regs->srr0 = vcpu->arch.shared->srr0;
+	regs->srr1 = vcpu->arch.shared->srr1;
 	regs->pid = vcpu->arch.pid;
-	regs->sprg0 = vcpu->arch.sprg0;
-	regs->sprg1 = vcpu->arch.sprg1;
-	regs->sprg2 = vcpu->arch.sprg2;
-	regs->sprg3 = vcpu->arch.sprg3;
+	regs->sprg0 = vcpu->arch.shared->sprg0;
+	regs->sprg1 = vcpu->arch.shared->sprg1;
+	regs->sprg2 = vcpu->arch.shared->sprg2;
+	regs->sprg3 = vcpu->arch.shared->sprg3;
 	regs->sprg5 = vcpu->arch.sprg4;
 	regs->sprg6 = vcpu->arch.sprg5;
 	regs->sprg7 = vcpu->arch.sprg6;
@@ -518,12 +566,12 @@
 	vcpu->arch.lr = regs->lr;
 	kvmppc_set_xer(vcpu, regs->xer);
 	kvmppc_set_msr(vcpu, regs->msr);
-	vcpu->arch.srr0 = regs->srr0;
-	vcpu->arch.srr1 = regs->srr1;
-	vcpu->arch.sprg0 = regs->sprg0;
-	vcpu->arch.sprg1 = regs->sprg1;
-	vcpu->arch.sprg2 = regs->sprg2;
-	vcpu->arch.sprg3 = regs->sprg3;
+	vcpu->arch.shared->srr0 = regs->srr0;
+	vcpu->arch.shared->srr1 = regs->srr1;
+	vcpu->arch.shared->sprg0 = regs->sprg0;
+	vcpu->arch.shared->sprg1 = regs->sprg1;
+	vcpu->arch.shared->sprg2 = regs->sprg2;
+	vcpu->arch.shared->sprg3 = regs->sprg3;
 	vcpu->arch.sprg5 = regs->sprg4;
 	vcpu->arch.sprg6 = regs->sprg5;
 	vcpu->arch.sprg7 = regs->sprg6;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke_emulate.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke_emulate.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke_emulate.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke_emulate.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,8 +31,8 @@
 
 static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu)
 {
-	vcpu->arch.pc = vcpu->arch.srr0;
-	kvmppc_set_msr(vcpu, vcpu->arch.srr1);
+	vcpu->arch.pc = vcpu->arch.shared->srr0;
+	kvmppc_set_msr(vcpu, vcpu->arch.shared->srr1);
 }
 
 int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
@@ -62,7 +62,7 @@
 
 		case OP_31_XOP_MFMSR:
 			rt = get_rt(inst);
-			kvmppc_set_gpr(vcpu, rt, vcpu->arch.msr);
+			kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->msr);
 			kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS);
 			break;
 
@@ -74,13 +74,13 @@
 
 		case OP_31_XOP_WRTEE:
 			rs = get_rs(inst);
-			vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+			vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE)
 					| (kvmppc_get_gpr(vcpu, rs) & MSR_EE);
 			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
 			break;
 
 		case OP_31_XOP_WRTEEI:
-			vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE)
+			vcpu->arch.shared->msr = (vcpu->arch.shared->msr & ~MSR_EE)
 							 | (inst & MSR_EE);
 			kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS);
 			break;
@@ -105,7 +105,7 @@
 
 	switch (sprn) {
 	case SPRN_DEAR:
-		vcpu->arch.dear = spr_val; break;
+		vcpu->arch.shared->dar = spr_val; break;
 	case SPRN_ESR:
 		vcpu->arch.esr = spr_val; break;
 	case SPRN_DBCR0:
@@ -200,7 +200,7 @@
 	case SPRN_IVPR:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivpr); break;
 	case SPRN_DEAR:
-		kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear); break;
+		kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->dar); break;
 	case SPRN_ESR:
 		kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break;
 	case SPRN_DBCR0:
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke.h linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke.h
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke.h	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,9 @@
 #define BOOKE_IRQPRIO_FIT 17
 #define BOOKE_IRQPRIO_DECREMENTER 18
 #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19
-#define BOOKE_IRQPRIO_MAX 19
+/* Internal pseudo-irqprio for level triggered externals */
+#define BOOKE_IRQPRIO_EXTERNAL_LEVEL 20
+#define BOOKE_IRQPRIO_MAX 20
 
 extern unsigned long kvmppc_booke_handlers;
 
@@ -54,12 +56,12 @@
  * changing. */
 static inline void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
 {
-	if ((new_msr & MSR_PR) != (vcpu->arch.msr & MSR_PR))
+	if ((new_msr & MSR_PR) != (vcpu->arch.shared->msr & MSR_PR))
 		kvmppc_mmu_priv_switch(vcpu, new_msr & MSR_PR);
 
-	vcpu->arch.msr = new_msr;
+	vcpu->arch.shared->msr = new_msr;
 
-	if (vcpu->arch.msr & MSR_WE) {
+	if (vcpu->arch.shared->msr & MSR_WE) {
 		kvm_vcpu_block(vcpu);
 		kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
 	};
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke_interrupts.S linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke_interrupts.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/booke_interrupts.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/booke_interrupts.S	2011-01-04 19:50:19.000000000 -0500
@@ -415,7 +415,8 @@
 	lwz	r8, VCPU_GPR(r8)(r4)
 	lwz	r3, VCPU_PC(r4)
 	mtsrr0	r3
-	lwz	r3, VCPU_MSR(r4)
+	lwz	r3, VCPU_SHARED(r4)
+	lwz	r3, (VCPU_SHARED_MSR + 4)(r3)
 	oris	r3, r3, KVMPPC_MSR_MASK@h
 	ori	r3, r3, KVMPPC_MSR_MASK@l
 	mtsrr1	r3
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500.c	2011-01-04 19:50:19.000000000 -0500
@@ -117,8 +117,14 @@
 	if (err)
 		goto uninit_vcpu;
 
+	vcpu->arch.shared = (void*)__get_free_page(GFP_KERNEL|__GFP_ZERO);
+	if (!vcpu->arch.shared)
+		goto uninit_tlb;
+
 	return vcpu;
 
+uninit_tlb:
+	kvmppc_e500_tlb_uninit(vcpu_e500);
 uninit_vcpu:
 	kvm_vcpu_uninit(vcpu);
 free_vcpu:
@@ -131,8 +137,9 @@
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 
-	kvmppc_e500_tlb_uninit(vcpu_e500);
+	free_page((unsigned long)vcpu->arch.shared);
 	kvm_vcpu_uninit(vcpu);
+	kvmppc_e500_tlb_uninit(vcpu_e500);
 	kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500_tlb.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500_tlb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500_tlb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500_tlb.c	2011-01-04 19:50:19.000000000 -0500
@@ -226,8 +226,7 @@
 
 	kvmppc_e500_shadow_release(vcpu_e500, tlbsel, esel);
 	stlbe->mas1 = 0;
-	trace_kvm_stlb_inval(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
-			     stlbe->mas3, stlbe->mas7);
+	trace_kvm_stlb_inval(index_of(tlbsel, esel));
 }
 
 static void kvmppc_e500_tlb1_invalidate(struct kvmppc_vcpu_e500 *vcpu_e500,
@@ -298,7 +297,8 @@
 	/* Get reference to new page. */
 	new_page = gfn_to_page(vcpu_e500->vcpu.kvm, gfn);
 	if (is_error_page(new_page)) {
-		printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn);
+		printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n",
+				(long)gfn);
 		kvm_release_page_clean(new_page);
 		return;
 	}
@@ -314,10 +314,10 @@
 		| MAS1_TID(get_tlb_tid(gtlbe)) | MAS1_TS | MAS1_VALID;
 	stlbe->mas2 = (gvaddr & MAS2_EPN)
 		| e500_shadow_mas2_attrib(gtlbe->mas2,
-				vcpu_e500->vcpu.arch.msr & MSR_PR);
+				vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
 	stlbe->mas3 = (hpaddr & MAS3_RPN)
 		| e500_shadow_mas3_attrib(gtlbe->mas3,
-				vcpu_e500->vcpu.arch.msr & MSR_PR);
+				vcpu_e500->vcpu.arch.shared->msr & MSR_PR);
 	stlbe->mas7 = (hpaddr >> 32) & MAS7_RPN;
 
 	trace_kvm_stlb_write(index_of(tlbsel, esel), stlbe->mas1, stlbe->mas2,
@@ -576,28 +576,28 @@
 
 int kvmppc_mmu_itlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
 	return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
 }
 
 int kvmppc_mmu_dtlb_index(struct kvm_vcpu *vcpu, gva_t eaddr)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
 
 	return kvmppc_e500_tlb_search(vcpu, eaddr, get_cur_pid(vcpu), as);
 }
 
 void kvmppc_mmu_itlb_miss(struct kvm_vcpu *vcpu)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_IS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_IS);
 
 	kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.pc, as);
 }
 
 void kvmppc_mmu_dtlb_miss(struct kvm_vcpu *vcpu)
 {
-	unsigned int as = !!(vcpu->arch.msr & MSR_DS);
+	unsigned int as = !!(vcpu->arch.shared->msr & MSR_DS);
 
 	kvmppc_e500_deliver_tlb_miss(vcpu, vcpu->arch.fault_dear, as);
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500_tlb.h linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500_tlb.h
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/e500_tlb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/e500_tlb.h	2011-01-04 19:50:19.000000000 -0500
@@ -171,7 +171,7 @@
 
 	/* Does it match current guest AS? */
 	/* XXX what about IS != DS? */
-	if (get_tlb_ts(tlbe) != !!(vcpu->arch.msr & MSR_IS))
+	if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
 		return 0;
 
 	gpa = get_tlb_raddr(tlbe);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/emulate.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/emulate.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/emulate.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/emulate.c	2011-01-04 19:50:19.000000000 -0500
@@ -145,7 +145,7 @@
 	/* this default type might be overwritten by subcategories */
 	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
 
-	pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
+	pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
 	switch (get_op(inst)) {
 	case OP_TRAP:
@@ -242,9 +242,11 @@
 
 			switch (sprn) {
 			case SPRN_SRR0:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr0); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr0);
+				break;
 			case SPRN_SRR1:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.srr1); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->srr1);
+				break;
 			case SPRN_PVR:
 				kvmppc_set_gpr(vcpu, rt, vcpu->arch.pvr); break;
 			case SPRN_PIR:
@@ -261,13 +263,17 @@
 				kvmppc_set_gpr(vcpu, rt, get_tb()); break;
 
 			case SPRN_SPRG0:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg0); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg0);
+				break;
 			case SPRN_SPRG1:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg1); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg1);
+				break;
 			case SPRN_SPRG2:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg2); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg2);
+				break;
 			case SPRN_SPRG3:
-				kvmppc_set_gpr(vcpu, rt, vcpu->arch.sprg3); break;
+				kvmppc_set_gpr(vcpu, rt, vcpu->arch.shared->sprg3);
+				break;
 			/* Note: SPRG4-7 are user-readable, so we don't get
 			 * a trap. */
 
@@ -275,7 +281,7 @@
 			{
 				u64 jd = get_tb() - vcpu->arch.dec_jiffies;
 				kvmppc_set_gpr(vcpu, rt, vcpu->arch.dec - jd);
-				pr_debug(KERN_INFO "mfDEC: %x - %llx = %lx\n",
+				pr_debug("mfDEC: %x - %llx = %lx\n",
 					 vcpu->arch.dec, jd,
 					 kvmppc_get_gpr(vcpu, rt));
 				break;
@@ -320,9 +326,11 @@
 			rs = get_rs(inst);
 			switch (sprn) {
 			case SPRN_SRR0:
-				vcpu->arch.srr0 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->srr0 = kvmppc_get_gpr(vcpu, rs);
+				break;
 			case SPRN_SRR1:
-				vcpu->arch.srr1 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->srr1 = kvmppc_get_gpr(vcpu, rs);
+				break;
 
 			/* XXX We need to context-switch the timebase for
 			 * watchdog and FIT. */
@@ -337,13 +345,17 @@
 				break;
 
 			case SPRN_SPRG0:
-				vcpu->arch.sprg0 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->sprg0 = kvmppc_get_gpr(vcpu, rs);
+				break;
 			case SPRN_SPRG1:
-				vcpu->arch.sprg1 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->sprg1 = kvmppc_get_gpr(vcpu, rs);
+				break;
 			case SPRN_SPRG2:
-				vcpu->arch.sprg2 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->sprg2 = kvmppc_get_gpr(vcpu, rs);
+				break;
 			case SPRN_SPRG3:
-				vcpu->arch.sprg3 = kvmppc_get_gpr(vcpu, rs); break;
+				vcpu->arch.shared->sprg3 = kvmppc_get_gpr(vcpu, rs);
+				break;
 
 			default:
 				emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, rs);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/fpu.S linux-libre-2.6.37-gnu/arch/powerpc/kvm/fpu.S
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/fpu.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/fpu.S	2011-01-04 19:50:19.000000000 -0500
@@ -273,19 +273,11 @@
 FPD_THREE_IN(fnmadd)
 
 _GLOBAL(kvm_cvt_fd)
-	lfd	0,0(r5)			/* load up fpscr value */
-	MTFSF_L(0)
 	lfs	0,0(r3)
 	stfd	0,0(r4)
-	mffs	0
-	stfd	0,0(r5)			/* save new fpscr value */
 	blr
 
 _GLOBAL(kvm_cvt_df)
-	lfd	0,0(r5)			/* load up fpscr value */
-	MTFSF_L(0)
 	lfd	0,0(r3)
 	stfs	0,0(r4)
-	mffs	0
-	stfd	0,0(r5)			/* save new fpscr value */
 	blr
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/Makefile linux-libre-2.6.37-gnu/arch/powerpc/kvm/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
+ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
 
 common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/powerpc.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/powerpc.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/powerpc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/powerpc.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,9 +38,56 @@
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-	return !(v->arch.msr & MSR_WE) || !!(v->arch.pending_exceptions);
+	return !(v->arch.shared->msr & MSR_WE) ||
+	       !!(v->arch.pending_exceptions);
 }
 
+int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
+{
+	int nr = kvmppc_get_gpr(vcpu, 11);
+	int r;
+	unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3);
+	unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4);
+	unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5);
+	unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6);
+	unsigned long r2 = 0;
+
+	if (!(vcpu->arch.shared->msr & MSR_SF)) {
+		/* 32 bit mode */
+		param1 &= 0xffffffff;
+		param2 &= 0xffffffff;
+		param3 &= 0xffffffff;
+		param4 &= 0xffffffff;
+	}
+
+	switch (nr) {
+	case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+	{
+		vcpu->arch.magic_page_pa = param1;
+		vcpu->arch.magic_page_ea = param2;
+
+		r2 = KVM_MAGIC_FEAT_SR;
+
+		r = HC_EV_SUCCESS;
+		break;
+	}
+	case HC_VENDOR_KVM | KVM_HC_FEATURES:
+		r = HC_EV_SUCCESS;
+#if defined(CONFIG_PPC_BOOK3S) /* XXX Missing magic page on BookE */
+		r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
+#endif
+
+		/* Second return value is in r4 */
+		break;
+	default:
+		r = HC_EV_UNIMPLEMENTED;
+		break;
+	}
+
+	kvmppc_set_gpr(vcpu, 4, r2);
+
+	return r;
+}
 
 int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 {
@@ -145,8 +192,10 @@
 	case KVM_CAP_PPC_SEGSTATE:
 	case KVM_CAP_PPC_PAIRED_SINGLES:
 	case KVM_CAP_PPC_UNSET_IRQ:
+	case KVM_CAP_PPC_IRQ_LEVEL:
 	case KVM_CAP_ENABLE_CAP:
 	case KVM_CAP_PPC_OSI:
+	case KVM_CAP_PPC_GET_PVINFO:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -534,16 +583,54 @@
 	return r;
 }
 
+static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
+{
+	u32 inst_lis = 0x3c000000;
+	u32 inst_ori = 0x60000000;
+	u32 inst_nop = 0x60000000;
+	u32 inst_sc = 0x44000002;
+	u32 inst_imm_mask = 0xffff;
+
+	/*
+	 * The hypercall to get into KVM from within guest context is as
+	 * follows:
+	 *
+	 *    lis r0, r0, KVM_SC_MAGIC_R0@h
+	 *    ori r0, KVM_SC_MAGIC_R0@l
+	 *    sc
+	 *    nop
+	 */
+	pvinfo->hcall[0] = inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask);
+	pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
+	pvinfo->hcall[2] = inst_sc;
+	pvinfo->hcall[3] = inst_nop;
+
+	return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                        unsigned int ioctl, unsigned long arg)
 {
+	void __user *argp = (void __user *)arg;
 	long r;
 
 	switch (ioctl) {
+	case KVM_PPC_GET_PVINFO: {
+		struct kvm_ppc_pvinfo pvinfo;
+		memset(&pvinfo, 0, sizeof(pvinfo));
+		r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
+		if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
+			r = -EFAULT;
+			goto out;
+		}
+
+		break;
+	}
 	default:
 		r = -ENOTTY;
 	}
 
+out:
 	return r;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/timing.c linux-libre-2.6.37-gnu/arch/powerpc/kvm/timing.c
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/timing.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/timing.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,6 @@
 	int i;
 
 	/* pause guest execution to avoid concurrent updates */
-	local_irq_disable();
 	mutex_lock(&vcpu->mutex);
 
 	vcpu->arch.last_exit_type = 0xDEAD;
@@ -51,7 +50,6 @@
 	vcpu->arch.timing_last_enter.tv64 = 0;
 
 	mutex_unlock(&vcpu->mutex);
-	local_irq_enable();
 }
 
 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/kvm/trace.h linux-libre-2.6.37-gnu/arch/powerpc/kvm/trace.h
--- linux-libre-2.6.36-gnu/arch/powerpc/kvm/trace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/kvm/trace.h	2011-01-04 19:50:19.000000000 -0500
@@ -98,6 +98,245 @@
 		__entry->word1, __entry->word2)
 );
 
+
+/*************************************************************************
+ *                         Book3S trace points                           *
+ *************************************************************************/
+
+#ifdef CONFIG_PPC_BOOK3S
+
+TRACE_EVENT(kvm_book3s_exit,
+	TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
+	TP_ARGS(exit_nr, vcpu),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	exit_nr		)
+		__field(	unsigned long,	pc		)
+		__field(	unsigned long,	msr		)
+		__field(	unsigned long,	dar		)
+		__field(	unsigned long,	srr1		)
+	),
+
+	TP_fast_assign(
+		__entry->exit_nr	= exit_nr;
+		__entry->pc		= kvmppc_get_pc(vcpu);
+		__entry->dar		= kvmppc_get_fault_dar(vcpu);
+		__entry->msr		= vcpu->arch.shared->msr;
+		__entry->srr1		= to_svcpu(vcpu)->shadow_srr1;
+	),
+
+	TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
+		  __entry->exit_nr, __entry->pc, __entry->msr, __entry->dar,
+		  __entry->srr1)
+);
+
+TRACE_EVENT(kvm_book3s_reenter,
+	TP_PROTO(int r, struct kvm_vcpu *vcpu),
+	TP_ARGS(r, vcpu),
+
+	TP_STRUCT__entry(
+		__field(	unsigned int,	r		)
+		__field(	unsigned long,	pc		)
+	),
+
+	TP_fast_assign(
+		__entry->r		= r;
+		__entry->pc		= kvmppc_get_pc(vcpu);
+	),
+
+	TP_printk("reentry r=%d | pc=0x%lx", __entry->r, __entry->pc)
+);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+
+TRACE_EVENT(kvm_book3s_64_mmu_map,
+	TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
+		 struct kvmppc_pte *orig_pte),
+	TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
+
+	TP_STRUCT__entry(
+		__field(	unsigned char,		flag_w		)
+		__field(	unsigned char,		flag_x		)
+		__field(	unsigned long,		eaddr		)
+		__field(	unsigned long,		hpteg		)
+		__field(	unsigned long,		va		)
+		__field(	unsigned long long,	vpage		)
+		__field(	unsigned long,		hpaddr		)
+	),
+
+	TP_fast_assign(
+		__entry->flag_w	= ((rflags & HPTE_R_PP) == 3) ? '-' : 'w';
+		__entry->flag_x	= (rflags & HPTE_R_N) ? '-' : 'x';
+		__entry->eaddr	= orig_pte->eaddr;
+		__entry->hpteg	= hpteg;
+		__entry->va	= va;
+		__entry->vpage	= orig_pte->vpage;
+		__entry->hpaddr	= hpaddr;
+	),
+
+	TP_printk("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx",
+		  __entry->flag_w, __entry->flag_x, __entry->eaddr,
+		  __entry->hpteg, __entry->va, __entry->vpage, __entry->hpaddr)
+);
+
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
+TRACE_EVENT(kvm_book3s_mmu_map,
+	TP_PROTO(struct hpte_cache *pte),
+	TP_ARGS(pte),
+
+	TP_STRUCT__entry(
+		__field(	u64,		host_va		)
+		__field(	u64,		pfn		)
+		__field(	ulong,		eaddr		)
+		__field(	u64,		vpage		)
+		__field(	ulong,		raddr		)
+		__field(	int,		flags		)
+	),
+
+	TP_fast_assign(
+		__entry->host_va	= pte->host_va;
+		__entry->pfn		= pte->pfn;
+		__entry->eaddr		= pte->pte.eaddr;
+		__entry->vpage		= pte->pte.vpage;
+		__entry->raddr		= pte->pte.raddr;
+		__entry->flags		= (pte->pte.may_read ? 0x4 : 0) |
+					  (pte->pte.may_write ? 0x2 : 0) |
+					  (pte->pte.may_execute ? 0x1 : 0);
+	),
+
+	TP_printk("Map: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
+		  __entry->host_va, __entry->pfn, __entry->eaddr,
+		  __entry->vpage, __entry->raddr, __entry->flags)
+);
+
+TRACE_EVENT(kvm_book3s_mmu_invalidate,
+	TP_PROTO(struct hpte_cache *pte),
+	TP_ARGS(pte),
+
+	TP_STRUCT__entry(
+		__field(	u64,		host_va		)
+		__field(	u64,		pfn		)
+		__field(	ulong,		eaddr		)
+		__field(	u64,		vpage		)
+		__field(	ulong,		raddr		)
+		__field(	int,		flags		)
+	),
+
+	TP_fast_assign(
+		__entry->host_va	= pte->host_va;
+		__entry->pfn		= pte->pfn;
+		__entry->eaddr		= pte->pte.eaddr;
+		__entry->vpage		= pte->pte.vpage;
+		__entry->raddr		= pte->pte.raddr;
+		__entry->flags		= (pte->pte.may_read ? 0x4 : 0) |
+					  (pte->pte.may_write ? 0x2 : 0) |
+					  (pte->pte.may_execute ? 0x1 : 0);
+	),
+
+	TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
+		  __entry->host_va, __entry->pfn, __entry->eaddr,
+		  __entry->vpage, __entry->raddr, __entry->flags)
+);
+
+TRACE_EVENT(kvm_book3s_mmu_flush,
+	TP_PROTO(const char *type, struct kvm_vcpu *vcpu, unsigned long long p1,
+		 unsigned long long p2),
+	TP_ARGS(type, vcpu, p1, p2),
+
+	TP_STRUCT__entry(
+		__field(	int,			count		)
+		__field(	unsigned long long,	p1		)
+		__field(	unsigned long long,	p2		)
+		__field(	const char *,		type		)
+	),
+
+	TP_fast_assign(
+		__entry->count		= vcpu->arch.hpte_cache_count;
+		__entry->p1		= p1;
+		__entry->p2		= p2;
+		__entry->type		= type;
+	),
+
+	TP_printk("Flush %d %sPTEs: %llx - %llx",
+		  __entry->count, __entry->type, __entry->p1, __entry->p2)
+);
+
+TRACE_EVENT(kvm_book3s_slb_found,
+	TP_PROTO(unsigned long long gvsid, unsigned long long hvsid),
+	TP_ARGS(gvsid, hvsid),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long long,	gvsid		)
+		__field(	unsigned long long,	hvsid		)
+	),
+
+	TP_fast_assign(
+		__entry->gvsid		= gvsid;
+		__entry->hvsid		= hvsid;
+	),
+
+	TP_printk("%llx -> %llx", __entry->gvsid, __entry->hvsid)
+);
+
+TRACE_EVENT(kvm_book3s_slb_fail,
+	TP_PROTO(u16 sid_map_mask, unsigned long long gvsid),
+	TP_ARGS(sid_map_mask, gvsid),
+
+	TP_STRUCT__entry(
+		__field(	unsigned short,		sid_map_mask	)
+		__field(	unsigned long long,	gvsid		)
+	),
+
+	TP_fast_assign(
+		__entry->sid_map_mask	= sid_map_mask;
+		__entry->gvsid		= gvsid;
+	),
+
+	TP_printk("%x/%x: %llx", __entry->sid_map_mask,
+		  SID_MAP_MASK - __entry->sid_map_mask, __entry->gvsid)
+);
+
+TRACE_EVENT(kvm_book3s_slb_map,
+	TP_PROTO(u16 sid_map_mask, unsigned long long gvsid,
+		 unsigned long long hvsid),
+	TP_ARGS(sid_map_mask, gvsid, hvsid),
+
+	TP_STRUCT__entry(
+		__field(	unsigned short,		sid_map_mask	)
+		__field(	unsigned long long,	guest_vsid	)
+		__field(	unsigned long long,	host_vsid	)
+	),
+
+	TP_fast_assign(
+		__entry->sid_map_mask	= sid_map_mask;
+		__entry->guest_vsid	= gvsid;
+		__entry->host_vsid	= hvsid;
+	),
+
+	TP_printk("%x: %llx -> %llx", __entry->sid_map_mask,
+		  __entry->guest_vsid, __entry->host_vsid)
+);
+
+TRACE_EVENT(kvm_book3s_slbmte,
+	TP_PROTO(u64 slb_vsid, u64 slb_esid),
+	TP_ARGS(slb_vsid, slb_esid),
+
+	TP_STRUCT__entry(
+		__field(	u64,	slb_vsid	)
+		__field(	u64,	slb_esid	)
+	),
+
+	TP_fast_assign(
+		__entry->slb_vsid	= slb_vsid;
+		__entry->slb_esid	= slb_esid;
+	),
+
+	TP_printk("%llx, %llx", __entry->slb_vsid, __entry->slb_esid)
+);
+
+#endif /* CONFIG_PPC_BOOK3S */
+
 #endif /* _TRACE_KVM_H */
 
 /* This part must be outside protection */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/checksum_64.S linux-libre-2.6.37-gnu/arch/powerpc/lib/checksum_64.S
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/checksum_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/checksum_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -65,165 +65,393 @@
 	srwi	r3,r3,16
 	blr
 
+#define STACKFRAMESIZE 256
+#define STK_REG(i)	(112 + ((i)-14)*8)
+
 /*
  * Computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit).
  *
- * This code assumes at least halfword alignment, though the length
- * can be any number of bytes.  The sum is accumulated in r5.
- *
  * csum_partial(r3=buff, r4=len, r5=sum)
  */
 _GLOBAL(csum_partial)
-        subi	r3,r3,8		/* we'll offset by 8 for the loads */
-        srdi.	r6,r4,3         /* divide by 8 for doubleword count */
-        addic   r5,r5,0         /* clear carry */
-        beq	3f              /* if we're doing < 8 bytes */
-        andi.	r0,r3,2         /* aligned on a word boundary already? */
-        beq+	1f
-        lhz     r6,8(r3)        /* do 2 bytes to get aligned */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        addc    r5,r5,r6
-        srdi.   r6,r4,3         /* recompute number of doublewords */
-        beq     3f              /* any left? */
-1:      mtctr   r6
-2:      ldu     r6,8(r3)        /* main sum loop */
-        adde    r5,r5,r6
-        bdnz    2b
-        andi.	r4,r4,7         /* compute bytes left to sum after doublewords */
-3:	cmpwi	0,r4,4		/* is at least a full word left? */
-	blt	4f
-	lwz	r6,8(r3)	/* sum this word */
+	addic	r0,r5,0			/* clear carry */
+
+	srdi.	r6,r4,3			/* less than 8 bytes? */
+	beq	.Lcsum_tail_word
+
+	/*
+	 * If only halfword aligned, align to a double word. Since odd
+	 * aligned addresses should be rare and they would require more
+	 * work to calculate the correct checksum, we ignore that case
+	 * and take the potential slowdown of unaligned loads.
+	 */
+	rldicl. r6,r3,64-1,64-2		/* r6 = (r3 & 0x3) >> 1 */
+	beq	.Lcsum_aligned
+
+	li	r7,4
+	sub	r6,r7,r6
+	mtctr	r6
+
+1:
+	lhz	r6,0(r3)		/* align to doubleword */
+	subi	r4,r4,2
+	addi	r3,r3,2
+	adde	r0,r0,r6
+	bdnz	1b
+
+.Lcsum_aligned:
+	/*
+	 * We unroll the loop such that each iteration is 64 bytes with an
+	 * entry and exit limb of 64 bytes, meaning a minimum size of
+	 * 128 bytes.
+	 */
+	srdi.	r6,r4,7
+	beq	.Lcsum_tail_doublewords		/* len < 128 */
+
+	srdi	r6,r4,6
+	subi	r6,r6,1
+	mtctr	r6
+
+	stdu	r1,-STACKFRAMESIZE(r1)
+	std	r14,STK_REG(r14)(r1)
+	std	r15,STK_REG(r15)(r1)
+	std	r16,STK_REG(r16)(r1)
+
+	ld	r6,0(r3)
+	ld	r9,8(r3)
+
+	ld	r10,16(r3)
+	ld	r11,24(r3)
+
+	/*
+	 * On POWER6 and POWER7 back to back addes take 2 cycles because of
+	 * the XER dependency. This means the fastest this loop can go is
+	 * 16 cycles per iteration. The scheduling of the loop below has
+	 * been shown to hit this on both POWER6 and POWER7.
+	 */
+	.align 5
+2:
+	adde	r0,r0,r6
+	ld	r12,32(r3)
+	ld	r14,40(r3)
+
+	adde	r0,r0,r9
+	ld	r15,48(r3)
+	ld	r16,56(r3)
+	addi	r3,r3,64
+
+	adde	r0,r0,r10
+
+	adde	r0,r0,r11
+
+	adde	r0,r0,r12
+
+	adde	r0,r0,r14
+
+	adde	r0,r0,r15
+	ld	r6,0(r3)
+	ld	r9,8(r3)
+
+	adde	r0,r0,r16
+	ld	r10,16(r3)
+	ld	r11,24(r3)
+	bdnz	2b
+
+
+	adde	r0,r0,r6
+	ld	r12,32(r3)
+	ld	r14,40(r3)
+
+	adde	r0,r0,r9
+	ld	r15,48(r3)
+	ld	r16,56(r3)
+	addi	r3,r3,64
+
+	adde	r0,r0,r10
+	adde	r0,r0,r11
+	adde	r0,r0,r12
+	adde	r0,r0,r14
+	adde	r0,r0,r15
+	adde	r0,r0,r16
+
+	ld	r14,STK_REG(r14)(r1)
+	ld	r15,STK_REG(r15)(r1)
+	ld	r16,STK_REG(r16)(r1)
+	addi	r1,r1,STACKFRAMESIZE
+
+	andi.	r4,r4,63
+
+.Lcsum_tail_doublewords:		/* Up to 127 bytes to go */
+	srdi.	r6,r4,3
+	beq	.Lcsum_tail_word
+
+	mtctr	r6
+3:
+	ld	r6,0(r3)
+	addi	r3,r3,8
+	adde	r0,r0,r6
+	bdnz	3b
+
+	andi.	r4,r4,7
+
+.Lcsum_tail_word:			/* Up to 7 bytes to go */
+	srdi.	r6,r4,2
+	beq	.Lcsum_tail_halfword
+
+	lwz	r6,0(r3)
 	addi	r3,r3,4
+	adde	r0,r0,r6
 	subi	r4,r4,4
-	adde	r5,r5,r6
-4:	cmpwi	0,r4,2		/* is at least a halfword left? */
-        blt+	5f
-        lhz     r6,8(r3)        /* sum this halfword */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        adde    r5,r5,r6
-5:	cmpwi	0,r4,1		/* is at least a byte left? */
-        bne+    6f
-        lbz     r6,8(r3)        /* sum this byte */
-        slwi    r6,r6,8         /* this byte is assumed to be the upper byte of a halfword */
-        adde    r5,r5,r6
-6:      addze	r5,r5		/* add in final carry */
-	rldicl  r4,r5,32,0      /* fold two 32-bit halves together */
-        add     r3,r4,r5
-        srdi    r3,r3,32
-        blr
+
+.Lcsum_tail_halfword:			/* Up to 3 bytes to go */
+	srdi.	r6,r4,1
+	beq	.Lcsum_tail_byte
+
+	lhz	r6,0(r3)
+	addi	r3,r3,2
+	adde	r0,r0,r6
+	subi	r4,r4,2
+
+.Lcsum_tail_byte:			/* Up to 1 byte to go */
+	andi.	r6,r4,1
+	beq	.Lcsum_finish
+
+	lbz	r6,0(r3)
+	sldi	r9,r6,8			/* Pad the byte out to 16 bits */
+	adde	r0,r0,r9
+
+.Lcsum_finish:
+	addze	r0,r0			/* add in final carry */
+	rldicl	r4,r0,32,0		/* fold two 32 bit halves together */
+	add	r3,r4,r0
+	srdi	r3,r3,32
+	blr
+
+
+	.macro source
+100:
+	.section __ex_table,"a"
+	.align 3
+	.llong 100b,.Lsrc_error
+	.previous
+	.endm
+
+	.macro dest
+200:
+	.section __ex_table,"a"
+	.align 3
+	.llong 200b,.Ldest_error
+	.previous
+	.endm
 
 /*
  * Computes the checksum of a memory block at src, length len,
  * and adds in "sum" (32-bit), while copying the block to dst.
  * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively, and (for an error on
- * src) zeroes the rest of dst.
- *
- * This code needs to be reworked to take advantage of 64 bit sum+copy.
- * However, due to tokenring halfword alignment problems this will be very
- * tricky.  For now we'll leave it until we instrument it somehow.
+ * to *src_err or *dst_err respectively. The caller must take any action
+ * required in this case (zeroing memory, recalculating partial checksum etc).
  *
  * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
  */
 _GLOBAL(csum_partial_copy_generic)
-	addic	r0,r6,0
-	subi	r3,r3,4
-	subi	r4,r4,4
-	srwi.	r6,r5,2
-	beq	3f		/* if we're doing < 4 bytes */
-	andi.	r9,r4,2		/* Align dst to longword boundary */
-	beq+	1f
-81:	lhz	r6,4(r3)	/* do 2 bytes to get aligned */
-	addi	r3,r3,2
+	addic	r0,r6,0			/* clear carry */
+
+	srdi.	r6,r5,3			/* less than 8 bytes? */
+	beq	.Lcopy_tail_word
+
+	/*
+	 * If only halfword aligned, align to a double word. Since odd
+	 * aligned addresses should be rare and they would require more
+	 * work to calculate the correct checksum, we ignore that case
+	 * and take the potential slowdown of unaligned loads.
+	 *
+	 * If the source and destination are relatively unaligned we only
+	 * align the source. This keeps things simple.
+	 */
+	rldicl. r6,r3,64-1,64-2		/* r6 = (r3 & 0x3) >> 1 */
+	beq	.Lcopy_aligned
+
+	li	r7,4
+	sub	r6,r7,r6
+	mtctr	r6
+
+1:
+source;	lhz	r6,0(r3)		/* align to doubleword */
 	subi	r5,r5,2
-91:	sth	r6,4(r4)
-	addi	r4,r4,2
-	addc	r0,r0,r6
-	srwi.	r6,r5,2		/* # words to do */
-	beq	3f
-1:	mtctr	r6
-82:	lwzu	r6,4(r3)	/* the bdnz has zero overhead, so it should */
-92:	stwu	r6,4(r4)	/* be unnecessary to unroll this loop */
-	adde	r0,r0,r6
-	bdnz	82b
-	andi.	r5,r5,3
-3:	cmpwi	0,r5,2
-	blt+	4f
-83:	lhz	r6,4(r3)
 	addi	r3,r3,2
-	subi	r5,r5,2
-93:	sth	r6,4(r4)
+	adde	r0,r0,r6
+dest;	sth	r6,0(r4)
 	addi	r4,r4,2
+	bdnz	1b
+
+.Lcopy_aligned:
+	/*
+	 * We unroll the loop such that each iteration is 64 bytes with an
+	 * entry and exit limb of 64 bytes, meaning a minimum size of
+	 * 128 bytes.
+	 */
+	srdi.	r6,r5,7
+	beq	.Lcopy_tail_doublewords		/* len < 128 */
+
+	srdi	r6,r5,6
+	subi	r6,r6,1
+	mtctr	r6
+
+	stdu	r1,-STACKFRAMESIZE(r1)
+	std	r14,STK_REG(r14)(r1)
+	std	r15,STK_REG(r15)(r1)
+	std	r16,STK_REG(r16)(r1)
+
+source;	ld	r6,0(r3)
+source;	ld	r9,8(r3)
+
+source;	ld	r10,16(r3)
+source;	ld	r11,24(r3)
+
+	/*
+	 * On POWER6 and POWER7 back to back addes take 2 cycles because of
+	 * the XER dependency. This means the fastest this loop can go is
+	 * 16 cycles per iteration. The scheduling of the loop below has
+	 * been shown to hit this on both POWER6 and POWER7.
+	 */
+	.align 5
+2:
 	adde	r0,r0,r6
-4:	cmpwi	0,r5,1
-	bne+	5f
-84:	lbz	r6,4(r3)
-94:	stb	r6,4(r4)
-	slwi	r6,r6,8		/* Upper byte of word */
+source;	ld	r12,32(r3)
+source;	ld	r14,40(r3)
+
+	adde	r0,r0,r9
+source;	ld	r15,48(r3)
+source;	ld	r16,56(r3)
+	addi	r3,r3,64
+
+	adde	r0,r0,r10
+dest;	std	r6,0(r4)
+dest;	std	r9,8(r4)
+
+	adde	r0,r0,r11
+dest;	std	r10,16(r4)
+dest;	std	r11,24(r4)
+
+	adde	r0,r0,r12
+dest;	std	r12,32(r4)
+dest;	std	r14,40(r4)
+
+	adde	r0,r0,r14
+dest;	std	r15,48(r4)
+dest;	std	r16,56(r4)
+	addi	r4,r4,64
+
+	adde	r0,r0,r15
+source;	ld	r6,0(r3)
+source;	ld	r9,8(r3)
+
+	adde	r0,r0,r16
+source;	ld	r10,16(r3)
+source;	ld	r11,24(r3)
+	bdnz	2b
+
+
 	adde	r0,r0,r6
-5:	addze	r3,r0		/* add in final carry (unlikely with 64-bit regs) */
-        rldicl  r4,r3,32,0      /* fold 64 bit value */
-        add     r3,r4,r3
-        srdi    r3,r3,32
-	blr
+source;	ld	r12,32(r3)
+source;	ld	r14,40(r3)
 
-/* These shouldn't go in the fixup section, since that would
-   cause the ex_table addresses to get out of order. */
+	adde	r0,r0,r9
+source;	ld	r15,48(r3)
+source;	ld	r16,56(r3)
+	addi	r3,r3,64
+
+	adde	r0,r0,r10
+dest;	std	r6,0(r4)
+dest;	std	r9,8(r4)
+
+	adde	r0,r0,r11
+dest;	std	r10,16(r4)
+dest;	std	r11,24(r4)
+
+	adde	r0,r0,r12
+dest;	std	r12,32(r4)
+dest;	std	r14,40(r4)
+
+	adde	r0,r0,r14
+dest;	std	r15,48(r4)
+dest;	std	r16,56(r4)
+	addi	r4,r4,64
+
+	adde	r0,r0,r15
+	adde	r0,r0,r16
+
+	ld	r14,STK_REG(r14)(r1)
+	ld	r15,STK_REG(r15)(r1)
+	ld	r16,STK_REG(r16)(r1)
+	addi	r1,r1,STACKFRAMESIZE
+
+	andi.	r5,r5,63
+
+.Lcopy_tail_doublewords:		/* Up to 127 bytes to go */
+	srdi.	r6,r5,3
+	beq	.Lcopy_tail_word
 
-	.globl src_error_1
-src_error_1:
-	li	r6,0
-	subi	r5,r5,2
-95:	sth	r6,4(r4)
-	addi	r4,r4,2
-	srwi.	r6,r5,2
-	beq	3f
 	mtctr	r6
-	.globl src_error_2
-src_error_2:
-	li	r6,0
-96:	stwu	r6,4(r4)
-	bdnz	96b
-3:	andi.	r5,r5,3
-	beq	src_error
-	.globl src_error_3
-src_error_3:
-	li	r6,0
-	mtctr	r5
-	addi	r4,r4,3
-97:	stbu	r6,1(r4)
-	bdnz	97b
-	.globl src_error
-src_error:
+3:
+source;	ld	r6,0(r3)
+	addi	r3,r3,8
+	adde	r0,r0,r6
+dest;	std	r6,0(r4)
+	addi	r4,r4,8
+	bdnz	3b
+
+	andi.	r5,r5,7
+
+.Lcopy_tail_word:			/* Up to 7 bytes to go */
+	srdi.	r6,r5,2
+	beq	.Lcopy_tail_halfword
+
+source;	lwz	r6,0(r3)
+	addi	r3,r3,4
+	adde	r0,r0,r6
+dest;	stw	r6,0(r4)
+	addi	r4,r4,4
+	subi	r5,r5,4
+
+.Lcopy_tail_halfword:			/* Up to 3 bytes to go */
+	srdi.	r6,r5,1
+	beq	.Lcopy_tail_byte
+
+source;	lhz	r6,0(r3)
+	addi	r3,r3,2
+	adde	r0,r0,r6
+dest;	sth	r6,0(r4)
+	addi	r4,r4,2
+	subi	r5,r5,2
+
+.Lcopy_tail_byte:			/* Up to 1 byte to go */
+	andi.	r6,r5,1
+	beq	.Lcopy_finish
+
+source;	lbz	r6,0(r3)
+	sldi	r9,r6,8			/* Pad the byte out to 16 bits */
+	adde	r0,r0,r9
+dest;	stb	r6,0(r4)
+
+.Lcopy_finish:
+	addze	r0,r0			/* add in final carry */
+	rldicl	r4,r0,32,0		/* fold two 32 bit halves together */
+	add	r3,r4,r0
+	srdi	r3,r3,32
+	blr
+
+.Lsrc_error:
 	cmpdi	0,r7,0
-	beq	1f
+	beqlr
 	li	r6,-EFAULT
 	stw	r6,0(r7)
-1:	addze	r3,r0
 	blr
 
-	.globl dst_error
-dst_error:
+.Ldest_error:
 	cmpdi	0,r8,0
-	beq	1f
+	beqlr
 	li	r6,-EFAULT
 	stw	r6,0(r8)
-1:	addze	r3,r0
 	blr
-
-.section __ex_table,"a"
-	.align  3
-	.llong	81b,src_error_1
-	.llong	91b,dst_error
-	.llong	82b,src_error_2
-	.llong	92b,dst_error
-	.llong	83b,src_error_3
-	.llong	93b,dst_error
-	.llong	84b,src_error_3
-	.llong	94b,dst_error
-	.llong	95b,dst_error
-	.llong	96b,dst_error
-	.llong	97b,dst_error
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/checksum_wrappers_64.c linux-libre-2.6.37-gnu/arch/powerpc/lib/checksum_wrappers_64.c
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/checksum_wrappers_64.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/checksum_wrappers_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,102 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/checksum.h>
+#include <asm/uaccess.h>
+
+__wsum csum_and_copy_from_user(const void __user *src, void *dst,
+			       int len, __wsum sum, int *err_ptr)
+{
+	unsigned int csum;
+
+	might_sleep();
+
+	*err_ptr = 0;
+
+	if (!len) {
+		csum = 0;
+		goto out;
+	}
+
+	if (unlikely((len < 0) || !access_ok(VERIFY_READ, src, len))) {
+		*err_ptr = -EFAULT;
+		csum = (__force unsigned int)sum;
+		goto out;
+	}
+
+	csum = csum_partial_copy_generic((void __force *)src, dst,
+					 len, sum, err_ptr, NULL);
+
+	if (unlikely(*err_ptr)) {
+		int missing = __copy_from_user(dst, src, len);
+
+		if (missing) {
+			memset(dst + len - missing, 0, missing);
+			*err_ptr = -EFAULT;
+		} else {
+			*err_ptr = 0;
+		}
+
+		csum = csum_partial(dst, len, sum);
+	}
+
+out:
+	return (__force __wsum)csum;
+}
+EXPORT_SYMBOL(csum_and_copy_from_user);
+
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
+			     __wsum sum, int *err_ptr)
+{
+	unsigned int csum;
+
+	might_sleep();
+
+	*err_ptr = 0;
+
+	if (!len) {
+		csum = 0;
+		goto out;
+	}
+
+	if (unlikely((len < 0) || !access_ok(VERIFY_WRITE, dst, len))) {
+		*err_ptr = -EFAULT;
+		csum = -1; /* invalid checksum */
+		goto out;
+	}
+
+	csum = csum_partial_copy_generic(src, (void __force *)dst,
+					 len, sum, NULL, err_ptr);
+
+	if (unlikely(*err_ptr)) {
+		csum = csum_partial(src, len, sum);
+
+		if (copy_to_user(dst, src, len)) {
+			*err_ptr = -EFAULT;
+			csum = -1; /* invalid checksum */
+		}
+	}
+
+out:
+	return (__force __wsum)csum;
+}
+EXPORT_SYMBOL(csum_and_copy_to_user);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/copy_32.S linux-libre-2.6.37-gnu/arch/powerpc/lib/copy_32.S
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/copy_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/copy_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -62,7 +62,7 @@
 
 	.text
 	.stabs	"arch/powerpc/lib/",N_SO,0,0,0f
-	.stabs	"copy32.S",N_SO,0,0,0f
+	.stabs	"copy_32.S",N_SO,0,0,0f
 0:
 
 CACHELINE_BYTES = L1_CACHE_BYTES
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/ldstfp.S linux-libre-2.6.37-gnu/arch/powerpc/lib/ldstfp.S
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/ldstfp.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/ldstfp.S	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,8 @@
 #include <asm/asm-offsets.h>
 #include <linux/errno.h>
 
+#ifdef CONFIG_PPC_FPU
+
 #define STKFRM	(PPC_MIN_STKFRM + 16)
 
 	.macro	extab	instr,handler
@@ -81,7 +83,7 @@
 	mfmsr	r6
 	ori	r7,r6,MSR_FP
 	cmpwi	cr7,r3,0
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stfd	fr0,STKFRM-16(r1)
@@ -93,7 +95,7 @@
 	lfd	fr0,STKFRM-16(r1)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -108,7 +110,7 @@
 	mfmsr	r6
 	ori	r7,r6,MSR_FP
 	cmpwi	cr7,r3,0
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stfd	fr0,STKFRM-16(r1)
@@ -120,7 +122,7 @@
 	lfd	fr0,STKFRM-16(r1)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -135,7 +137,7 @@
 	mfmsr	r6
 	ori	r7,r6,MSR_FP
 	cmpwi	cr7,r3,0
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stfd	fr0,STKFRM-16(r1)
@@ -147,7 +149,7 @@
 	lfd	fr0,STKFRM-16(r1)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -162,7 +164,7 @@
 	mfmsr	r6
 	ori	r7,r6,MSR_FP
 	cmpwi	cr7,r3,0
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stfd	fr0,STKFRM-16(r1)
@@ -174,7 +176,7 @@
 	lfd	fr0,STKFRM-16(r1)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -229,7 +231,7 @@
 	oris	r7,r6,MSR_VEC@h
 	cmpwi	cr7,r3,0
 	li	r8,STKFRM-16
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stvx	vr0,r1,r8
@@ -241,7 +243,7 @@
 	lvx	vr0,r1,r8
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -257,7 +259,7 @@
 	oris	r7,r6,MSR_VEC@h
 	cmpwi	cr7,r3,0
 	li	r8,STKFRM-16
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	stvx	vr0,r1,r8
@@ -269,7 +271,7 @@
 	lvx	vr0,r1,r8
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -325,7 +327,7 @@
 	oris	r7,r6,MSR_VSX@h
 	cmpwi	cr7,r3,0
 	li	r8,STKFRM-16
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	STXVD2X(0,r1,r8)
@@ -337,7 +339,7 @@
 	LXVD2X(0,r1,r8)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -353,7 +355,7 @@
 	oris	r7,r6,MSR_VSX@h
 	cmpwi	cr7,r3,0
 	li	r8,STKFRM-16
-	mtmsrd	r7
+	MTMSRD(r7)
 	isync
 	beq	cr7,1f
 	STXVD2X(0,r1,r8)
@@ -365,7 +367,7 @@
 	LXVD2X(0,r1,r8)
 4:	PPC_LL	r0,STKFRM+PPC_LR_STKOFF(r1)
 	mtlr	r0
-	mtmsrd	r6
+	MTMSRD(r6)
 	isync
 	mr	r3,r9
 	addi	r1,r1,STKFRM
@@ -373,3 +375,5 @@
 	extab	2b,3b
 
 #endif /* CONFIG_VSX */
+
+#endif	/* CONFIG_PPC_FPU */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/locks.c linux-libre-2.6.37-gnu/arch/powerpc/lib/locks.c
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/locks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/locks.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 		return;
 	holder_cpu = lock_value & 0xffff;
 	BUG_ON(holder_cpu >= NR_CPUS);
-	yield_count = lppaca[holder_cpu].yield_count;
+	yield_count = lppaca_of(holder_cpu).yield_count;
 	if ((yield_count & 1) == 0)
 		return;		/* virtual cpu is currently running */
 	rmb();
@@ -65,7 +65,7 @@
 		return;		/* no write lock at present */
 	holder_cpu = lock_value & 0xffff;
 	BUG_ON(holder_cpu >= NR_CPUS);
-	yield_count = lppaca[holder_cpu].yield_count;
+	yield_count = lppaca_of(holder_cpu).yield_count;
 	if ((yield_count & 1) == 0)
 		return;		/* virtual cpu is currently running */
 	rmb();
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/Makefile linux-libre-2.6.37-gnu/arch/powerpc/lib/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,9 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS		+= -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)	:= -mno-minimal-toc
 
 CFLAGS_REMOVE_code-patching.o = -pg
 CFLAGS_REMOVE_feature-fixups.o = -pg
@@ -17,7 +15,8 @@
 obj-$(CONFIG_HAS_IOMEM)	+= devres.o
 
 obj-$(CONFIG_PPC64)	+= copypage_64.o copyuser_64.o \
-			   memcpy_64.o usercopy_64.o mem_64.o string.o
+			   memcpy_64.o usercopy_64.o mem_64.o string.o \
+			   checksum_wrappers_64.o
 obj-$(CONFIG_XMON)	+= sstep.o ldstfp.o
 obj-$(CONFIG_KPROBES)	+= sstep.o ldstfp.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= sstep.o ldstfp.o
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/lib/sstep.c linux-libre-2.6.37-gnu/arch/powerpc/lib/sstep.c
--- linux-libre-2.6.36-gnu/arch/powerpc/lib/sstep.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/lib/sstep.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #define XER_OV		0x40000000U
 #define XER_CA		0x20000000U
 
+#ifdef CONFIG_PPC_FPU
 /*
  * Functions in ldstfp.S
  */
@@ -41,6 +42,7 @@
 extern int do_stvx(int rn, unsigned long ea);
 extern int do_lxvd2x(int rn, unsigned long ea);
 extern int do_stxvd2x(int rn, unsigned long ea);
+#endif
 
 /*
  * Determine whether a conditional branch instruction would branch.
@@ -290,6 +292,7 @@
 	return write_mem_unaligned(val, ea, nb, regs);
 }
 
+#ifdef CONFIG_PPC_FPU
 /*
  * Check the address and alignment, and call func to do the actual
  * load or store.
@@ -351,6 +354,7 @@
 	}
 	return err;
 }
+#endif
 
 #ifdef CONFIG_ALTIVEC
 /* For Altivec/VMX, no need to worry about alignment */
@@ -1393,6 +1397,7 @@
 				regs->gpr[rd] = byterev_4(val);
 			goto ldst_done;
 
+#ifdef CONFIG_PPC_CPU
 		case 535:	/* lfsx */
 		case 567:	/* lfsux */
 			if (!(regs->msr & MSR_FP))
@@ -1424,6 +1429,7 @@
 			ea = xform_ea(instr, regs, u);
 			err = do_fp_store(rd, do_stfd, ea, 8, regs);
 			goto ldst_done;
+#endif
 
 #ifdef __powerpc64__
 		case 660:	/* stdbrx */
@@ -1534,6 +1540,7 @@
 		} while (++rd < 32);
 		goto instr_done;
 
+#ifdef CONFIG_PPC_FPU
 	case 48:	/* lfs */
 	case 49:	/* lfsu */
 		if (!(regs->msr & MSR_FP))
@@ -1565,6 +1572,7 @@
 		ea = dform_ea(instr, regs);
 		err = do_fp_store(rd, do_stfd, ea, 8, regs);
 		goto ldst_done;
+#endif
 
 #ifdef __powerpc64__
 	case 58:	/* ld[u], lwa */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/math-emu/Makefile linux-libre-2.6.37-gnu/arch/powerpc/math-emu/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/math-emu/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/math-emu/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -15,4 +15,4 @@
 CFLAGS_fabs.o = -fno-builtin-fabs
 CFLAGS_math.o = -fno-builtin-fabs
 
-EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
+ccflags-y = -I. -Iinclude/math-emu -w
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/40x_mmu.c linux-libre-2.6.37-gnu/arch/powerpc/mm/40x_mmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/40x_mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/40x_mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/memblock.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -47,6 +48,7 @@
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/setup.h>
+
 #include "mmu_decl.h"
 
 extern int __map_without_ltlbs;
@@ -139,8 +141,19 @@
 	 * coverage with normal-sized pages (or other reasons) do not
 	 * attempt to allocate outside the allowed range.
 	 */
-
-	__initial_memory_limit_addr = memstart_addr + mapped;
+	memblock_set_current_limit(mapped);
 
 	return mapped;
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* We don't currently support the first MEMBLOCK not mapping 0
+	 * physical on those processors
+	 */
+	BUG_ON(first_memblock_base != 0);
+
+	/* 40x can only access 16MB at the moment (see head_40x.S) */
+	memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000));
+}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/44x_mmu.c linux-libre-2.6.37-gnu/arch/powerpc/mm/44x_mmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/44x_mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/44x_mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,8 @@
  */
 
 #include <linux/init.h>
+#include <linux/memblock.h>
+
 #include <asm/mmu.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -213,6 +215,18 @@
 	return total_lowmem;
 }
 
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* We don't currently support the first MEMBLOCK not mapping 0
+	 * physical on those processors
+	 */
+	BUG_ON(first_memblock_base != 0);
+
+	/* 44x has a 256M TLB entry pinned at boot */
+	memblock_set_current_limit(min_t(u64, first_memblock_size, PPC_PIN_SIZE));
+}
+
 #ifdef CONFIG_SMP
 void __cpuinit mmu_init_secondary(int cpu)
 {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/fault.c linux-libre-2.6.37-gnu/arch/powerpc/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/perf_event.h>
+#include <linux/magic.h>
 
 #include <asm/firmware.h>
 #include <asm/page.h>
@@ -385,6 +386,7 @@
 void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 {
 	const struct exception_table_entry *entry;
+	unsigned long *stackend;
 
 	/* Are we prepared to handle this fault?  */
 	if ((entry = search_exception_tables(regs->nip)) != NULL) {
@@ -413,5 +415,9 @@
 	printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
 		regs->nip);
 
+	stackend = end_of_stack(current);
+	if (current != &init_task && *stackend != STACK_END_MAGIC)
+		printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
+
 	die("Kernel access of bad area", regs, sig);
 }
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/fsl_booke_mmu.c linux-libre-2.6.37-gnu/arch/powerpc/mm/fsl_booke_mmu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/fsl_booke_mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/fsl_booke_mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/memblock.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -56,11 +57,6 @@
 
 unsigned int tlbcam_index;
 
-
-#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
-#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
-#endif
-
 #define NUM_TLBCAMS	(64)
 struct tlbcam TLBCAM[NUM_TLBCAMS];
 
@@ -137,7 +133,8 @@
 	if (mmu_has_feature(MMU_FTR_BIG_PHYS))
 		TLBCAM[index].MAS7 = (u64)phys >> 32;
 
-	if (flags & _PAGE_USER) {
+	/* Below is unlikely -- only for large user pages or similar */
+	if (pte_user(flags)) {
 	   TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
 	   TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
 	}
@@ -184,6 +181,12 @@
 	return amount_mapped;
 }
 
+#ifdef CONFIG_PPC32
+
+#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
+#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
+#endif
+
 unsigned long __init mmu_mapin_ram(unsigned long top)
 {
 	return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1;
@@ -213,5 +216,15 @@
 	pr_cont("%lu Mb, residual: %dMb\n", tlbcam_sz(tlbcam_index - 1) >> 20,
 	        (unsigned int)((total_lowmem - __max_low_memory) >> 20));
 
-	__initial_memory_limit_addr = memstart_addr + __max_low_memory;
+	memblock_set_current_limit(memstart_addr + __max_low_memory);
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	phys_addr_t limit = first_memblock_base + first_memblock_size;
+
+	/* 64M mapped initially according to head_fsl_booke.S */
+	memblock_set_current_limit(min_t(u64, limit, 0x04000000));
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/hash_utils_64.c linux-libre-2.6.37-gnu/arch/powerpc/mm/hash_utils_64.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/hash_utils_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/hash_utils_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -588,7 +588,7 @@
 	unsigned long pteg_count;
 	unsigned long prot;
 	unsigned long base = 0, size = 0, limit;
-	int i;
+	struct memblock_region *reg;
 
 	DBG(" -> htab_initialize()\n");
 
@@ -625,7 +625,7 @@
 		if (machine_is(cell))
 			limit = 0x80000000;
 		else
-			limit = 0;
+			limit = MEMBLOCK_ALLOC_ANYWHERE;
 
 		table = memblock_alloc_base(htab_size_bytes, htab_size_bytes, limit);
 
@@ -649,7 +649,7 @@
 #ifdef CONFIG_DEBUG_PAGEALLOC
 	linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT;
 	linear_map_hash_slots = __va(memblock_alloc_base(linear_map_hash_count,
-						    1, memblock.rmo_size));
+						    1, ppc64_rma_size));
 	memset(linear_map_hash_slots, 0, linear_map_hash_count);
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
@@ -659,9 +659,9 @@
 	 */
 
 	/* create bolted the linear mapping in the hash table */
-	for (i=0; i < memblock.memory.cnt; i++) {
-		base = (unsigned long)__va(memblock.memory.region[i].base);
-		size = memblock.memory.region[i].size;
+	for_each_memblock(memory, reg) {
+		base = (unsigned long)__va(reg->base);
+		size = reg->size;
 
 		DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",
 		    base, size, prot);
@@ -696,7 +696,8 @@
 #endif /* CONFIG_U3_DART */
 		BUG_ON(htab_bolt_mapping(base, base + size, __pa(base),
 				prot, mmu_linear_psize, mmu_kernel_ssize));
-       }
+	}
+	memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
 
 	/*
 	 * If we have a memory_limit and we've allocated TCEs then we need to
@@ -1122,7 +1123,7 @@
 	else
 #endif /* CONFIG_PPC_HAS_HASH_64K */
 		rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
-				    subpage_protection(pgdir, ea));
+				    subpage_protection(mm, ea));
 
 	/* Dump some info in case of hash insertion failure, they should
 	 * never happen so it is really useful to know if/when they do
@@ -1247,3 +1248,23 @@
 	local_irq_restore(flags);
 }
 #endif /* CONFIG_DEBUG_PAGEALLOC */
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* We don't currently support the first MEMBLOCK not mapping 0
+	 * physical on those processors
+	 */
+	BUG_ON(first_memblock_base != 0);
+
+	/* On LPAR systems, the first entry is our RMA region,
+	 * non-LPAR 64-bit hash MMU systems don't have a limitation
+	 * on real mode access, but using the first entry works well
+	 * enough. We also clamp it to 1G to avoid some funky things
+	 * such as RTAS bugs etc...
+	 */
+	ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
+
+	/* Finally limit subsequent allocations */
+	memblock_set_current_limit(ppc64_rma_size);
+}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/highmem.c linux-libre-2.6.37-gnu/arch/powerpc/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,17 +29,17 @@
  * be used in IRQ contexts, so in some (very limited) cases we need
  * it.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-	unsigned int idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
 	pagefault_disable();
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
@@ -52,26 +52,35 @@
 }
 EXPORT_SYMBOL(kmap_atomic_prot);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+	int type;
 
 	if (vaddr < __fix_to_virt(FIX_KMAP_END)) {
 		pagefault_enable();
 		return;
 	}
 
-	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+	type = kmap_atomic_idx();
 
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(&init_mm, vaddr, kmap_pte-idx);
-	local_flush_tlb_page(NULL, vaddr);
+#ifdef CONFIG_DEBUG_HIGHMEM
+	{
+		unsigned int idx;
+
+		idx = type + KM_TYPE_NR * smp_processor_id();
+		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+
+		/*
+		 * force other mappings to Oops if they'll try to access
+		 * this pte without first remap it
+		 */
+		pte_clear(&init_mm, vaddr, kmap_pte-idx);
+		local_flush_tlb_page(NULL, vaddr);
+	}
 #endif
+
+	kmap_atomic_idx_pop();
 	pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/init_32.c linux-libre-2.6.37-gnu/arch/powerpc/mm/init_32.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/init_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/init_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,12 +92,6 @@
 unsigned long __max_low_memory = MAX_LOW_MEM;
 
 /*
- * address of the limit of what is accessible with initial MMU setup -
- * 256MB usually, but only 16MB on 601.
- */
-phys_addr_t __initial_memory_limit_addr = (phys_addr_t)0x10000000;
-
-/*
  * Check for command-line options that affect what MMU_init will do.
  */
 void MMU_setup(void)
@@ -126,13 +120,6 @@
 	if (ppc_md.progress)
 		ppc_md.progress("MMU:enter", 0x111);
 
-	/* 601 can only access 16MB at the moment */
-	if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-		__initial_memory_limit_addr = 0x01000000;
-	/* 8xx can only access 8MB at the moment */
-	if (PVR_VER(mfspr(SPRN_PVR)) == 0x50)
-		__initial_memory_limit_addr = 0x00800000;
-
 	/* parse args from command line */
 	MMU_setup();
 
@@ -190,20 +177,18 @@
 #ifdef CONFIG_BOOTX_TEXT
 	btext_unmap();
 #endif
+
+	/* Shortly after that, the entire linear mapping will be available */
+	memblock_set_current_limit(lowmem_end_addr);
 }
 
 /* This is only called until mem_init is done. */
 void __init *early_get_page(void)
 {
-	void *p;
-
-	if (init_bootmem_done) {
-		p = alloc_bootmem_pages(PAGE_SIZE);
-	} else {
-		p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
-					__initial_memory_limit_addr));
-	}
-	return p;
+	if (init_bootmem_done)
+		return alloc_bootmem_pages(PAGE_SIZE);
+	else
+		return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE));
 }
 
 /* Free up now-unused memory */
@@ -252,3 +237,17 @@
 }
 #endif
 
+
+#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* We don't currently support the first MEMBLOCK not mapping 0
+	 * physical on those processors
+	 */
+	BUG_ON(first_memblock_base != 0);
+
+	/* 8xx can only access 8MB at the moment */
+	memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000));
+}
+#endif /* CONFIG_8xx */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/init_64.c linux-libre-2.6.37-gnu/arch/powerpc/mm/init_64.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/init_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/init_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -330,3 +330,4 @@
 	return 0;
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
+
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/Makefile linux-libre-2.6.37-gnu/arch/powerpc/mm/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,9 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS	+= -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)	:= -mno-minimal-toc
 
 obj-y				:= fault.o mem.o pgtable.o gup.o \
 				   init_$(CONFIG_WORD_SIZE).o \
@@ -25,7 +23,7 @@
 				   mmu_context_hash$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_40x)		+= 40x_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
-obj-$(CONFIG_FSL_BOOKE)		+= fsl_booke_mmu.o
+obj-$(CONFIG_PPC_FSL_BOOK3E)	+= fsl_booke_mmu.o
 obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
 obj-$(CONFIG_PPC_MM_SLICES)	+= slice.o
 ifeq ($(CONFIG_HUGETLB_PAGE),y)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/mem.c linux-libre-2.6.37-gnu/arch/powerpc/mm/mem.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/mem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/mem.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,18 +82,11 @@
 	return pfn < max_pfn;
 #else
 	unsigned long paddr = (pfn << PAGE_SHIFT);
-	int i;
-	for (i=0; i < memblock.memory.cnt; i++) {
-		unsigned long base;
-
-		base = memblock.memory.region[i].base;
+	struct memblock_region *reg;
 
-		if ((paddr >= base) &&
-			(paddr < (base + memblock.memory.region[i].size))) {
+	for_each_memblock(memory, reg)
+		if (paddr >= reg->base && paddr < (reg->base + reg->size))
 			return 1;
-		}
-	}
-
 	return 0;
 #endif
 }
@@ -149,23 +142,19 @@
 walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
 		void *arg, int (*func)(unsigned long, unsigned long, void *))
 {
-	struct memblock_property res;
-	unsigned long pfn, len;
-	u64 end;
+	struct memblock_region *reg;
+	unsigned long end_pfn = start_pfn + nr_pages;
+	unsigned long tstart, tend;
 	int ret = -1;
 
-	res.base = (u64) start_pfn << PAGE_SHIFT;
-	res.size = (u64) nr_pages << PAGE_SHIFT;
-
-	end = res.base + res.size - 1;
-	while ((res.base < end) && (memblock_find(&res) >= 0)) {
-		pfn = (unsigned long)(res.base >> PAGE_SHIFT);
-		len = (unsigned long)(res.size >> PAGE_SHIFT);
-		ret = (*func)(pfn, len, arg);
+	for_each_memblock(memory, reg) {
+		tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
+		tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
+		if (tstart >= tend)
+			continue;
+		ret = (*func)(tstart, tend - tstart, arg);
 		if (ret)
 			break;
-		res.base += (res.size + 1);
-		res.size = (end - res.base + 1);
 	}
 	return ret;
 }
@@ -179,9 +168,9 @@
 #ifndef CONFIG_NEED_MULTIPLE_NODES
 void __init do_init_bootmem(void)
 {
-	unsigned long i;
 	unsigned long start, bootmap_pages;
 	unsigned long total_pages;
+	struct memblock_region *reg;
 	int boot_mapsize;
 
 	max_low_pfn = max_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT;
@@ -204,10 +193,10 @@
 	boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
 
 	/* Add active regions with valid PFNs */
-	for (i = 0; i < memblock.memory.cnt; i++) {
+	for_each_memblock(memory, reg) {
 		unsigned long start_pfn, end_pfn;
-		start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-		end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+		start_pfn = memblock_region_memory_base_pfn(reg);
+		end_pfn = memblock_region_memory_end_pfn(reg);
 		add_active_range(0, start_pfn, end_pfn);
 	}
 
@@ -218,29 +207,21 @@
 	free_bootmem_with_active_regions(0, lowmem_end_addr >> PAGE_SHIFT);
 
 	/* reserve the sections we're already using */
-	for (i = 0; i < memblock.reserved.cnt; i++) {
-		unsigned long addr = memblock.reserved.region[i].base +
-				     memblock_size_bytes(&memblock.reserved, i) - 1;
-		if (addr < lowmem_end_addr)
-			reserve_bootmem(memblock.reserved.region[i].base,
-					memblock_size_bytes(&memblock.reserved, i),
-					BOOTMEM_DEFAULT);
-		else if (memblock.reserved.region[i].base < lowmem_end_addr) {
-			unsigned long adjusted_size = lowmem_end_addr -
-				      memblock.reserved.region[i].base;
-			reserve_bootmem(memblock.reserved.region[i].base,
-					adjusted_size, BOOTMEM_DEFAULT);
+	for_each_memblock(reserved, reg) {
+		unsigned long top = reg->base + reg->size - 1;
+		if (top < lowmem_end_addr)
+			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+		else if (reg->base < lowmem_end_addr) {
+			unsigned long trunc_size = lowmem_end_addr - reg->base;
+			reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
 		}
 	}
 #else
 	free_bootmem_with_active_regions(0, max_pfn);
 
 	/* reserve the sections we're already using */
-	for (i = 0; i < memblock.reserved.cnt; i++)
-		reserve_bootmem(memblock.reserved.region[i].base,
-				memblock_size_bytes(&memblock.reserved, i),
-				BOOTMEM_DEFAULT);
-
+	for_each_memblock(reserved, reg)
+		reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
 #endif
 	/* XXX need to clip this if using highmem? */
 	sparse_memory_present_with_active_regions(0);
@@ -251,22 +232,15 @@
 /* mark pages that don't exist as nosave */
 static int __init mark_nonram_nosave(void)
 {
-	unsigned long memblock_next_region_start_pfn,
-		      memblock_region_max_pfn;
-	int i;
-
-	for (i = 0; i < memblock.memory.cnt - 1; i++) {
-		memblock_region_max_pfn =
-			(memblock.memory.region[i].base >> PAGE_SHIFT) +
-			(memblock.memory.region[i].size >> PAGE_SHIFT);
-		memblock_next_region_start_pfn =
-			memblock.memory.region[i+1].base >> PAGE_SHIFT;
+	struct memblock_region *reg, *prev = NULL;
 
-		if (memblock_region_max_pfn < memblock_next_region_start_pfn)
-			register_nosave_region(memblock_region_max_pfn,
-					       memblock_next_region_start_pfn);
+	for_each_memblock(memory, reg) {
+		if (prev &&
+		    memblock_region_memory_end_pfn(prev) < memblock_region_memory_base_pfn(reg))
+			register_nosave_region(memblock_region_memory_end_pfn(prev),
+					       memblock_region_memory_base_pfn(reg));
+		prev = reg;
 	}
-
 	return 0;
 }
 
@@ -327,7 +301,7 @@
 		swiotlb_init(1);
 #endif
 
-	num_physpages = memblock.memory.size >> PAGE_SHIFT;
+	num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
 #ifdef CONFIG_NEED_MULTIPLE_NODES
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/mmu_context_nohash.c linux-libre-2.6.37-gnu/arch/powerpc/mm/mmu_context_nohash.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/mmu_context_nohash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/mmu_context_nohash.c	2011-01-04 19:50:19.000000000 -0500
@@ -334,7 +334,7 @@
 	/* We don't touch CPU 0 map, it's allocated at aboot and kept
 	 * around forever
 	 */
-	if (cpu == 0)
+	if (cpu == boot_cpuid)
 		return NOTIFY_OK;
 
 	switch (action) {
@@ -420,9 +420,11 @@
 	 */
 	context_map = alloc_bootmem(CTX_MAP_SIZE);
 	context_mm = alloc_bootmem(sizeof(void *) * (last_context + 1));
+#ifndef CONFIG_SMP
 	stale_map[0] = alloc_bootmem(CTX_MAP_SIZE);
+#else
+	stale_map[boot_cpuid] = alloc_bootmem(CTX_MAP_SIZE);
 
-#ifdef CONFIG_SMP
 	register_cpu_notifier(&mmu_context_cpu_nb);
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/mmu_decl.h linux-libre-2.6.37-gnu/arch/powerpc/mm/mmu_decl.h
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/mmu_decl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/mmu_decl.h	2011-01-04 19:50:19.000000000 -0500
@@ -140,10 +140,13 @@
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(unsigned long top);
 
-#elif defined(CONFIG_FSL_BOOKE)
+#elif defined(CONFIG_PPC_FSL_BOOK3E)
+extern unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx);
+#ifdef CONFIG_PPC32
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(unsigned long top);
 extern void adjust_total_lowmem(void);
+#endif
 extern void loadcam_entry(unsigned int index);
 
 struct tlbcam {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/numa.c linux-libre-2.6.37-gnu/arch/powerpc/mm/numa.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/numa.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/numa.c	2011-01-04 19:50:19.000000000 -0500
@@ -802,16 +802,17 @@
 	unsigned long top_of_ram = memblock_end_of_DRAM();
 	unsigned long total_ram = memblock_phys_mem_size();
 	unsigned long start_pfn, end_pfn;
-	unsigned int i, nid = 0;
+	unsigned int nid = 0;
+	struct memblock_region *reg;
 
 	printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
 	       top_of_ram, total_ram);
 	printk(KERN_DEBUG "Memory hole size: %ldMB\n",
 	       (top_of_ram - total_ram) >> 20);
 
-	for (i = 0; i < memblock.memory.cnt; ++i) {
-		start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-		end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+	for_each_memblock(memory, reg) {
+		start_pfn = memblock_region_memory_base_pfn(reg);
+		end_pfn = memblock_region_memory_end_pfn(reg);
 
 		fake_numa_create_new_node(end_pfn, &nid);
 		add_active_range(nid, start_pfn, end_pfn);
@@ -947,11 +948,11 @@
 static void mark_reserved_regions_for_nid(int nid)
 {
 	struct pglist_data *node = NODE_DATA(nid);
-	int i;
+	struct memblock_region *reg;
 
-	for (i = 0; i < memblock.reserved.cnt; i++) {
-		unsigned long physbase = memblock.reserved.region[i].base;
-		unsigned long size = memblock.reserved.region[i].size;
+	for_each_memblock(reserved, reg) {
+		unsigned long physbase = reg->base;
+		unsigned long size = reg->size;
 		unsigned long start_pfn = physbase >> PAGE_SHIFT;
 		unsigned long end_pfn = PFN_UP(physbase + size);
 		struct node_active_region node_ar;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/pgtable.c linux-libre-2.6.37-gnu/arch/powerpc/mm/pgtable.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/pgtable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/pgtable.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,7 +92,7 @@
 
 static void pte_free_submit(struct pte_freelist_batch *batch)
 {
-	call_rcu(&batch->rcu, pte_free_rcu_callback);
+	call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
 }
 
 void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/ppc_mmu_32.c linux-libre-2.6.37-gnu/arch/powerpc/mm/ppc_mmu_32.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/ppc_mmu_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/ppc_mmu_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -223,8 +223,7 @@
 	 * Find some memory for the hash table.
 	 */
 	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-	Hash = __va(memblock_alloc_base(Hash_size, Hash_size,
-				   __initial_memory_limit_addr));
+	Hash = __va(memblock_alloc(Hash_size, Hash_size));
 	cacheable_memzero(Hash, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
 
@@ -272,3 +271,18 @@
 
 	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* We don't currently support the first MEMBLOCK not mapping 0
+	 * physical on those processors
+	 */
+	BUG_ON(first_memblock_base != 0);
+
+	/* 601 can only access 16MB at the moment */
+	if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+		memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01000000));
+	else /* Anything else has 256M mapped */
+		memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
+}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_low_64e.S linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_low_64e.S
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_low_64e.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_low_64e.S	2011-01-04 19:50:19.000000000 -0500
@@ -138,8 +138,11 @@
 	cmpldi	cr0,r15,0			/* Check for user region */
 	std	r14,EX_TLB_ESR(r12)		/* write crazy -1 to frame */
 	beq	normal_tlb_miss
+
+	li	r11,_PAGE_PRESENT|_PAGE_BAP_SX	/* Base perm */
+	oris	r11,r11,_PAGE_ACCESSED@h
 	/* XXX replace the RMW cycles with immediate loads + writes */
-1:	mfspr	r10,SPRN_MAS1
+	mfspr	r10,SPRN_MAS1
 	cmpldi	cr0,r15,8			/* Check for vmalloc region */
 	rlwinm	r10,r10,0,16,1			/* Clear TID */
 	mtspr	SPRN_MAS1,r10
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_nohash.c linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_nohash.c
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_nohash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_nohash.c	2011-01-04 19:50:19.000000000 -0500
@@ -349,11 +349,47 @@
 
 static void setup_page_sizes(void)
 {
-	unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
-	unsigned int tlb0ps = mfspr(SPRN_TLB0PS);
-	unsigned int eptcfg = mfspr(SPRN_EPTCFG);
+	unsigned int tlb0cfg;
+	unsigned int tlb0ps;
+	unsigned int eptcfg;
 	int i, psize;
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+	unsigned int mmucfg = mfspr(SPRN_MMUCFG);
+
+	if (((mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) &&
+		(mmu_has_feature(MMU_FTR_TYPE_FSL_E))) {
+		unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG);
+		unsigned int min_pg, max_pg;
+
+		min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+		max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
+
+		for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
+			struct mmu_psize_def *def;
+			unsigned int shift;
+
+			def = &mmu_psize_defs[psize];
+			shift = def->shift;
+
+			if (shift == 0)
+				continue;
+
+			/* adjust to be in terms of 4^shift Kb */
+			shift = (shift - 10) >> 1;
+
+			if ((shift >= min_pg) && (shift <= max_pg))
+				def->flags |= MMU_PAGE_SIZE_DIRECT;
+		}
+
+		goto no_indirect;
+	}
+#endif
+
+	tlb0cfg = mfspr(SPRN_TLB0CFG);
+	tlb0ps = mfspr(SPRN_TLB0PS);
+	eptcfg = mfspr(SPRN_EPTCFG);
+
 	/* Look for supported direct sizes */
 	for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
 		struct mmu_psize_def *def = &mmu_psize_defs[psize];
@@ -505,10 +541,26 @@
 	 */
 	linear_map_top = memblock_end_of_DRAM();
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+	if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
+		unsigned int num_cams;
+
+		/* use a quarter of the TLBCAM for bolted linear map */
+		num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
+		linear_map_top = map_mem_in_cams(linear_map_top, num_cams);
+
+		/* limit memory so we dont have linear faults */
+		memblock_enforce_memory_limit(linear_map_top);
+		memblock_analyze();
+	}
+#endif
+
 	/* A sync won't hurt us after mucking around with
 	 * the MMU configuration
 	 */
 	mb();
+
+	memblock_set_current_limit(linear_map_top);
 }
 
 void __init early_init_mmu(void)
@@ -521,4 +573,18 @@
 	__early_init_mmu(0);
 }
 
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+				phys_addr_t first_memblock_size)
+{
+	/* On Embedded 64-bit, we adjust the RMA size to match
+	 * the bolted TLB entry. We know for now that only 1G
+	 * entries are supported though that may eventually
+	 * change. We crop it to the size of the first MEMBLOCK to
+	 * avoid going over total available memory just in case...
+	 */
+	ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
+
+	/* Finally limit subsequent allocations */
+	memblock_set_current_limit(first_memblock_base + ppc64_rma_size);
+}
 #endif /* CONFIG_PPC64 */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_nohash_low.S linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_nohash_low.S
--- linux-libre-2.6.36-gnu/arch/powerpc/mm/tlb_nohash_low.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/mm/tlb_nohash_low.S	2011-01-04 19:50:19.000000000 -0500
@@ -367,7 +367,7 @@
 #error Unsupported processor type !
 #endif
 
-#if defined(CONFIG_FSL_BOOKE)
+#if defined(CONFIG_PPC_FSL_BOOK3E)
 /*
  * extern void loadcam_entry(unsigned int index)
  *
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/oprofile/backtrace.c linux-libre-2.6.37-gnu/arch/powerpc/oprofile/backtrace.c
--- linux-libre-2.6.36-gnu/arch/powerpc/oprofile/backtrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/oprofile/backtrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -105,7 +105,7 @@
 		}
 	} else {
 #ifdef CONFIG_PPC64
-		if (!test_thread_flag(TIF_32BIT)) {
+		if (!is_32bit_task()) {
 			while (depth--) {
 				sp = user_getsp64(sp, first_frame);
 				if (!sp)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/oprofile/Makefile linux-libre-2.6.37-gnu/arch/powerpc/oprofile/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/oprofile/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/oprofile/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,6 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS	+= -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)	:= -mno-minimal-toc
 
 obj-$(CONFIG_OPROFILE) += oprofile.o
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/oprofile/op_model_fsl_emb.c linux-libre-2.6.37-gnu/arch/powerpc/oprofile/op_model_fsl_emb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/oprofile/op_model_fsl_emb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/oprofile/op_model_fsl_emb.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
  * Freescale Embedded oprofile support, based on ppc64 oprofile support
  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
  *
- * Copyright (c) 2004 Freescale Semiconductor, Inc
+ * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
  *
  * Author: Andy Fleming
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
@@ -321,9 +321,6 @@
 	int val;
 	int i;
 
-	/* set the PMM bit (see comment below) */
-	mtmsr(mfmsr() | MSR_PMM);
-
 	pc = regs->nip;
 	is_kernel = is_kernel_addr(pc);
 
@@ -340,9 +337,13 @@
 	}
 
 	/* The freeze bit was set by the interrupt. */
-	/* Clear the freeze bit, and reenable the interrupt.
-	 * The counters won't actually start until the rfi clears
-	 * the PMM bit */
+	/* Clear the freeze bit, and reenable the interrupt.  The
+	 * counters won't actually start until the rfi clears the PMM
+	 * bit.  The PMM bit should not be set until after the interrupt
+	 * is cleared to avoid it getting lost in some hypervisor
+	 * environments.
+	 */
+	mtmsr(mfmsr() | MSR_PMM);
 	pmc_start_ctrs(1);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/44x/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/platforms/44x/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/44x/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/44x/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,16 @@
 	help
 	  This option enables support for the IBM PPC440EP evaluation board.
 
+config BLUESTONE
+	bool "Bluestone"
+	depends on 44x
+	default n
+	select PPC44x_SIMPLE
+	select APM821xx
+	select IBM_NEW_EMAC_RGMII
+	help
+	  This option enables support for the APM APM821xx Evaluation board.
+
 config EBONY
 	bool "Ebony"
 	depends on 44x
@@ -293,6 +303,12 @@
 	select IBM_NEW_EMAC_ZMII
 	select IBM_NEW_EMAC_TAH
 
+config APM821xx
+	bool
+	select PPC_FPU
+	select IBM_NEW_EMAC_EMAC4
+	select IBM_NEW_EMAC_TAH
+
 # 44x errata/workaround config symbols, selected by the CPU models above
 config IBM440EP_ERR42
 	bool
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/44x/ppc44x_simple.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/44x/ppc44x_simple.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/44x/ppc44x_simple.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/44x/ppc44x_simple.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,6 +52,7 @@
 static char *board[] __initdata = {
 	"amcc,arches",
 	"amcc,bamboo",
+	"amcc,bluestone",
 	"amcc,canyonlands",
 	"amcc,glacier",
 	"ibm,ebony",
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/52xx/mpc52xx_gpt.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/52xx/mpc52xx_gpt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/52xx/mpc52xx_gpt.c	2011-01-04 19:50:19.000000000 -0500
@@ -63,6 +63,7 @@
 #include <linux/of_gpio.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/fs.h>
 #include <linux/watchdog.h>
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/83xx/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/platforms/83xx/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/83xx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/83xx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -10,12 +10,12 @@
 if PPC_83xx
 
 config MPC830x_RDB
-	bool "Freescale MPC830x RDB"
+	bool "Freescale MPC830x RDB and derivatives"
 	select DEFAULT_UIMAGE
 	select PPC_MPC831x
 	select FSL_GTM
 	help
-	  This option enables support for the MPC8308 RDB board.
+	  This option enables support for the MPC8308 RDB and MPC8308 P1M boards.
 
 config MPC831x_RDB
 	bool "Freescale MPC831x RDB"
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/83xx/mpc830x_rdb.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/83xx/mpc830x_rdb.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/83xx/mpc830x_rdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/83xx/mpc830x_rdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,8 @@
 	unsigned long root = of_get_flat_dt_root();
 
 	return of_flat_dt_is_compatible(root, "MPC8308RDB") ||
-	       of_flat_dt_is_compatible(root, "fsl,mpc8308rdb");
+	       of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") ||
+	       of_flat_dt_is_compatible(root, "denx,mpc8308_p1m");
 }
 
 static struct of_device_id __initdata of_bus_ids[] = {
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,8 @@
 
 if FSL_SOC_BOOKE
 
+if PPC32
+
 config MPC8540_ADS
 	bool "Freescale MPC8540 ADS"
 	select DEFAULT_UIMAGE
@@ -153,10 +155,20 @@
 	help
 	  This option enables support for the Wind River SBC8560 board
 
+config P3041_DS
+	bool "Freescale P3041 DS"
+	select DEFAULT_UIMAGE
+	select PPC_E500MC
+	select PHYS_64BIT
+	select SWIOTLB
+	select MPC8xxx_GPIO
+	select HAS_RAPIDIO
+	help
+	  This option enables support for the P3041 DS board
+
 config P4080_DS
 	bool "Freescale P4080 DS"
 	select DEFAULT_UIMAGE
-	select PPC_FSL_BOOK3E
 	select PPC_E500MC
 	select PHYS_64BIT
 	select SWIOTLB
@@ -165,6 +177,20 @@
 	help
 	  This option enables support for the P4080 DS board
 
+endif # PPC32
+
+config P5020_DS
+	bool "Freescale P5020 DS"
+	select DEFAULT_UIMAGE
+	select E500
+	select PPC_E500MC
+	select PHYS_64BIT
+	select SWIOTLB
+	select MPC8xxx_GPIO
+	select HAS_RAPIDIO
+	help
+	  This option enables support for the P5020 DS board
+
 endif # FSL_SOC_BOOKE
 
 config TQM85xx
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/Makefile linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,9 @@
 obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
 obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
+obj-$(CONFIG_P3041_DS)    += p3041_ds.o corenet_ds.o
 obj-$(CONFIG_P4080_DS)    += p4080_ds.o corenet_ds.o
+obj-$(CONFIG_P5020_DS)    += p5020_ds.o corenet_ds.o
 obj-$(CONFIG_STX_GP3)	  += stx_gp3.o
 obj-$(CONFIG_TQM85xx)	  += tqm85xx.o
 obj-$(CONFIG_SBC8560)     += sbc8560.o
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p1022_ds.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p1022_ds.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p1022_ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p1022_ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,6 @@
  * Copyright 2010 Freescale Semiconductor, Inc.
  *
  * This file is taken from the Freescale P1022DS BSP, with modifications:
- * 1) No DIU support (pending rewrite of DIU code)
  * 2) No AMP support
  * 3) No PCI endpoint support
  *
@@ -20,12 +19,211 @@
 #include <linux/pci.h>
 #include <linux/of_platform.h>
 #include <linux/memblock.h>
-
+#include <asm/div64.h>
 #include <asm/mpic.h>
 #include <asm/swiotlb.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
+#include <asm/fsl_guts.h>
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/*
+ * Board-specific initialization of the DIU.  This code should probably be
+ * executed when the DIU is opened, rather than in arch code, but the DIU
+ * driver does not have a mechanism for this (yet).
+ *
+ * This is especially problematic on the P1022DS because the local bus (eLBC)
+ * and the DIU video signals share the same pins, which means that enabling the
+ * DIU will disable access to NOR flash.
+ */
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN		0x80000000
+#define CLKDVDR_PXCKINV		0x10000000
+#define CLKDVDR_PXCKDLY		0x06000000
+#define CLKDVDR_PXCLK_MASK	0x00FF0000
+
+/* Some ngPIXIS register definitions */
+#define PX_BRDCFG1_DVIEN	0x80
+#define PX_BRDCFG1_DFPEN	0x40
+#define PX_BRDCFG1_BACKLIGHT	0x20
+#define PX_BRDCFG1_DDCEN	0x10
+
+/*
+ * DIU Area Descriptor
+ *
+ * Note that we need to byte-swap the value before it's written to the AD
+ * register.  So even though the registers don't look like they're in the same
+ * bit positions as they are on the MPC8610, the same value is written to the
+ * AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F		0x10000000
+#define AD_ALPHA_C_MASK		0x0E000000
+#define AD_ALPHA_C_SHIFT	25
+#define AD_BLUE_C_MASK		0x01800000
+#define AD_BLUE_C_SHIFT		23
+#define AD_GREEN_C_MASK		0x00600000
+#define AD_GREEN_C_SHIFT	21
+#define AD_RED_C_MASK		0x00180000
+#define AD_RED_C_SHIFT		19
+#define AD_PALETTE		0x00040000
+#define AD_PIXEL_S_MASK		0x00030000
+#define AD_PIXEL_S_SHIFT	16
+#define AD_COMP_3_MASK		0x0000F000
+#define AD_COMP_3_SHIFT		12
+#define AD_COMP_2_MASK		0x00000F00
+#define AD_COMP_2_SHIFT		8
+#define AD_COMP_1_MASK		0x000000F0
+#define AD_COMP_1_SHIFT		4
+#define AD_COMP_0_MASK		0x0000000F
+#define AD_COMP_0_SHIFT		0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+	cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+	(blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+	(red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+	(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+	(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+
+/**
+ * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+ *
+ * The Area Descriptor is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color.
+ */
+static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+	int monitor_port)
+{
+	switch (bits_per_pixel) {
+	case 32:
+		/* 0x88883316 */
+		return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+	case 24:
+		/* 0x88082219 */
+		return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+	case 16:
+		/* 0x65053118 */
+		return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+	default:
+		pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+		return 0;
+	}
+}
+
+/**
+ * p1022ds_set_gamma_table: update the gamma table, if necessary
+ *
+ * On some boards, the gamma table for some ports may need to be modified.
+ * This is not the case on the P1022DS, so we do nothing.
+*/
+static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+/**
+ * p1022ds_set_monitor_port: switch the output to a different monitor port
+ *
+ */
+static void p1022ds_set_monitor_port(int monitor_port)
+{
+	struct device_node *pixis_node;
+	u8 __iomem *brdcfg1;
+
+	pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+	if (!pixis_node) {
+		pr_err("p1022ds: missing ngPIXIS node\n");
+		return;
+	}
+
+	brdcfg1 = of_iomap(pixis_node, 0);
+	if (!brdcfg1) {
+		pr_err("p1022ds: could not map ngPIXIS registers\n");
+		return;
+	}
+	brdcfg1 += 9;	/* BRDCFG1 is at offset 9 in the ngPIXIS */
+
+	switch (monitor_port) {
+	case 0: /* DVI */
+		/* Enable the DVI port, disable the DFP and the backlight */
+		clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+			     PX_BRDCFG1_DVIEN);
+		break;
+	case 1: /* Single link LVDS */
+		/* Enable the DFP port, disable the DVI and the backlight */
+		clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+			     PX_BRDCFG1_DFPEN);
+		break;
+	default:
+		pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+	}
+}
+
+/**
+ * p1022ds_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022ds_set_pixel_clock(unsigned int pixclock)
+{
+	struct device_node *guts_np = NULL;
+	struct ccsr_guts_85xx __iomem *guts;
+	unsigned long freq;
+	u64 temp;
+	u32 pxclk;
+
+	/* Map the global utilities registers. */
+	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+	if (!guts_np) {
+		pr_err("p1022ds: missing global utilties device node\n");
+		return;
+	}
+
+	guts = of_iomap(guts_np, 0);
+	of_node_put(guts_np);
+	if (!guts) {
+		pr_err("p1022ds: could not map global utilties device\n");
+		return;
+	}
+
+	/* Convert pixclock from a wavelength to a frequency */
+	temp = 1000000000000ULL;
+	do_div(temp, pixclock);
+	freq = temp;
+
+	/* pixclk is the ratio of the platform clock to the pixel clock */
+	pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+
+	/* Disable the pixel clock, and set it to non-inverted and no delay */
+	clrbits32(&guts->clkdvdr,
+		  CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+	/* Enable the clock and set the pxclk */
+	setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+}
+
+/**
+ * p1022ds_show_monitor_port: show the current monitor
+ *
+ * This function returns a string indicating whether the current monitor is
+ * set to DVI or LVDS.
+ */
+ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+{
+	return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+		monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+}
+
+/**
+ * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+ */
+int p1022ds_set_sysfs_monitor_port(int val)
+{
+	return val < 2 ? val : 0;
+}
+
+#endif
 
 void __init p1022_ds_pic_init(void)
 {
@@ -92,6 +290,15 @@
 	}
 #endif
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.get_pixel_format	= p1022ds_get_pixel_format;
+	diu_ops.set_gamma_table		= p1022ds_set_gamma_table;
+	diu_ops.set_monitor_port	= p1022ds_set_monitor_port;
+	diu_ops.set_pixel_clock		= p1022ds_set_pixel_clock;
+	diu_ops.show_monitor_port	= p1022ds_show_monitor_port;
+	diu_ops.set_sysfs_monitor_port	= p1022ds_set_sysfs_monitor_port;
+#endif
+
 #ifdef CONFIG_SMP
 	mpc85xx_smp_init();
 #endif
@@ -112,6 +319,8 @@
 	{ .compatible = "soc", },
 	{ .compatible = "simple-bus", },
 	{ .compatible = "gianfar", },
+	/* So that the DMA channel nodes can be probed individually: */
+	{ .compatible = "fsl,eloplus-dma", },
 	{},
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p3041_ds.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p3041_ds.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p3041_ds.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p3041_ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,64 @@
+/*
+ * P3041 DS Setup
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2009-2010 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p3041_ds_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P3041DS");
+}
+
+define_machine(p3041_ds) {
+	.name			= "P3041 DS",
+	.probe			= p3041_ds_probe,
+	.setup_arch		= corenet_ds_setup_arch,
+	.init_IRQ		= corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+	.get_irq		= mpic_get_coreint_irq,
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+machine_device_initcall(p3041_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p3041_ds, swiotlb_setup_bus_notifier);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p5020_ds.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p5020_ds.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/p5020_ds.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/p5020_ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,69 @@
+/*
+ * P5020 DS Setup
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2009-2010 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p5020_ds_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	return of_flat_dt_is_compatible(root, "fsl,P5020DS");
+}
+
+define_machine(p5020_ds) {
+	.name			= "P5020 DS",
+	.probe			= p5020_ds_probe,
+	.setup_arch		= corenet_ds_setup_arch,
+	.init_IRQ		= corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+#endif
+/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
+#ifdef CONFIG_PPC64
+	.get_irq		= mpic_get_irq,
+#else
+	.get_irq		= mpic_get_coreint_irq,
+#endif
+	.restart		= fsl_rstcr_restart,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= udbg_progress,
+};
+
+machine_device_initcall(p5020_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p5020_ds, swiotlb_setup_bus_notifier);
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/smp.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/smp.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/85xx/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/85xx/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/kexec.h>
+#include <linux/highmem.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -79,6 +80,7 @@
 	local_irq_save(flags);
 
 	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
+#ifdef CONFIG_PPC32
 	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
 
 	if (!ioremappable)
@@ -88,6 +90,12 @@
 	/* Wait a bit for the CPU to ack. */
 	while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
 		mdelay(1);
+#else
+	out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
+		__pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+
+	smp_generic_kick_cpu(nr);
+#endif
 
 	local_irq_restore(flags);
 
@@ -114,19 +122,15 @@
 };
 
 #ifdef CONFIG_KEXEC
-static int kexec_down_cpus = 0;
+atomic_t kexec_down_cpus = ATOMIC_INIT(0);
 
 void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
 {
-	mpic_teardown_this_cpu(1);
-
-	/* When crashing, this gets called on all CPU's we only
-	 * take down the non-boot cpus */
-	if (smp_processor_id() != boot_cpuid)
-	{
-		local_irq_disable();
-		kexec_down_cpus++;
+	local_irq_disable();
 
+	if (secondary) {
+		atomic_inc(&kexec_down_cpus);
+		/* loop forever */
 		while (1);
 	}
 }
@@ -137,16 +141,65 @@
 		ppc_md.kexec_cpu_down(0,1);
 }
 
-static void mpc85xx_smp_machine_kexec(struct kimage *image)
+static void map_and_flush(unsigned long paddr)
 {
-	int timeout = 2000;
+	struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
+	unsigned long kaddr  = (unsigned long)kmap(page);
+
+	flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
+	kunmap(page);
+}
+
+/**
+ * Before we reset the other cores, we need to flush relevant cache
+ * out to memory so we don't get anything corrupted, some of these flushes
+ * are performed out of an overabundance of caution as interrupts are not
+ * disabled yet and we can switch cores
+ */
+static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image)
+{
+	kimage_entry_t *ptr, entry;
+	unsigned long paddr;
 	int i;
 
-	set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
+	if (image->type == KEXEC_TYPE_DEFAULT) {
+		/* normal kexec images are stored in temporary pages */
+		for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+		     ptr = (entry & IND_INDIRECTION) ?
+				phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+			if (!(entry & IND_DESTINATION)) {
+				map_and_flush(entry);
+			}
+		}
+		/* flush out last IND_DONE page */
+		map_and_flush(entry);
+	} else {
+		/* crash type kexec images are copied to the crash region */
+		for (i = 0; i < image->nr_segments; i++) {
+			struct kexec_segment *seg = &image->segment[i];
+			for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
+			     paddr += PAGE_SIZE) {
+				map_and_flush(paddr);
+			}
+		}
+	}
 
-	smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
+	/* also flush the kimage struct to be passed in as well */
+	flush_dcache_range((unsigned long)image,
+			   (unsigned long)image + sizeof(*image));
+}
 
-	while ( (kexec_down_cpus != (num_online_cpus() - 1)) &&
+static void mpc85xx_smp_machine_kexec(struct kimage *image)
+{
+	int timeout = INT_MAX;
+	int i, num_cpus = num_present_cpus();
+
+	mpc85xx_smp_flush_dcache_kexec(image);
+
+	if (image->type == KEXEC_TYPE_DEFAULT)
+		smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
+
+	while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
 		( timeout > 0 ) )
 	{
 		timeout--;
@@ -155,7 +208,7 @@
 	if ( !timeout )
 		printk(KERN_ERR "Unable to bring down secondary cpu(s)");
 
-	for (i = 0; i < num_present_cpus(); i++)
+	for (i = 0; i < num_cpus; i++)
 	{
 		if ( i == smp_processor_id() ) continue;
 		mpic_reset_core(i);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/axon_msi.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/axon_msi.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/axon_msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/axon_msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -310,9 +310,9 @@
 }
 
 static struct irq_chip msic_irq_chip = {
-	.mask		= mask_msi_irq,
-	.unmask		= unmask_msi_irq,
-	.shutdown	= unmask_msi_irq,
+	.irq_mask	= mask_msi_irq,
+	.irq_unmask	= unmask_msi_irq,
+	.irq_shutdown	= mask_msi_irq,
 	.name		= "AXON-MSI",
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/ras.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/ras.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/ras.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/ras.c	2011-01-04 19:50:19.000000000 -0500
@@ -173,8 +173,10 @@
 		return -ENODEV;
 
 	size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
-	if (!size)
+	if (!size) {
+		of_node_put(np);
 		return -ENODEV;
+	}
 
 	pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size);
 	order = get_order(*size);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spider-pic.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spider-pic.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spider-pic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spider-pic.c	2011-01-04 19:50:19.000000000 -0500
@@ -258,8 +258,10 @@
 		return NO_IRQ;
 	imap += intsize + 1;
 	tmp = of_get_property(iic, "#interrupt-cells", NULL);
-	if (tmp == NULL)
+	if (tmp == NULL) {
+		of_node_put(iic);
 		return NO_IRQ;
+	}
 	intsize = *tmp;
 	/* Assume unit is last entry of interrupt specifier */
 	unit = imap[intsize - 1];
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spufs/file.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spufs/file.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spufs/file.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spufs/file.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,6 +154,7 @@
 	.release = spufs_attr_release,					\
 	.read	 = spufs_attr_read,					\
 	.write	 = spufs_attr_write,					\
+	.llseek  = generic_file_llseek,					\
 };
 
 
@@ -521,6 +522,7 @@
 	.release = spufs_cntl_release,
 	.read = simple_attr_read,
 	.write = simple_attr_write,
+	.llseek	= generic_file_llseek,
 	.mmap = spufs_cntl_mmap,
 };
 
@@ -714,6 +716,7 @@
 static const struct file_operations spufs_mbox_fops = {
 	.open	= spufs_pipe_open,
 	.read	= spufs_mbox_read,
+	.llseek	= no_llseek,
 };
 
 static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
@@ -743,6 +746,7 @@
 static const struct file_operations spufs_mbox_stat_fops = {
 	.open	= spufs_pipe_open,
 	.read	= spufs_mbox_stat_read,
+	.llseek = no_llseek,
 };
 
 /* low-level ibox access function */
@@ -863,6 +867,7 @@
 	.read	= spufs_ibox_read,
 	.poll	= spufs_ibox_poll,
 	.fasync	= spufs_ibox_fasync,
+	.llseek = no_llseek,
 };
 
 static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
@@ -890,6 +895,7 @@
 static const struct file_operations spufs_ibox_stat_fops = {
 	.open	= spufs_pipe_open,
 	.read	= spufs_ibox_stat_read,
+	.llseek = no_llseek,
 };
 
 /* low-level mailbox write */
@@ -1011,6 +1017,7 @@
 	.write	= spufs_wbox_write,
 	.poll	= spufs_wbox_poll,
 	.fasync	= spufs_wbox_fasync,
+	.llseek = no_llseek,
 };
 
 static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
@@ -1038,6 +1045,7 @@
 static const struct file_operations spufs_wbox_stat_fops = {
 	.open	= spufs_pipe_open,
 	.read	= spufs_wbox_stat_read,
+	.llseek = no_llseek,
 };
 
 static int spufs_signal1_open(struct inode *inode, struct file *file)
@@ -1166,6 +1174,7 @@
 	.read = spufs_signal1_read,
 	.write = spufs_signal1_write,
 	.mmap = spufs_signal1_mmap,
+	.llseek = no_llseek,
 };
 
 static const struct file_operations spufs_signal1_nosched_fops = {
@@ -1173,6 +1182,7 @@
 	.release = spufs_signal1_release,
 	.write = spufs_signal1_write,
 	.mmap = spufs_signal1_mmap,
+	.llseek = no_llseek,
 };
 
 static int spufs_signal2_open(struct inode *inode, struct file *file)
@@ -1305,6 +1315,7 @@
 	.read = spufs_signal2_read,
 	.write = spufs_signal2_write,
 	.mmap = spufs_signal2_mmap,
+	.llseek = no_llseek,
 };
 
 static const struct file_operations spufs_signal2_nosched_fops = {
@@ -1312,6 +1323,7 @@
 	.release = spufs_signal2_release,
 	.write = spufs_signal2_write,
 	.mmap = spufs_signal2_mmap,
+	.llseek = no_llseek,
 };
 
 /*
@@ -1451,6 +1463,7 @@
 	.open	 = spufs_mss_open,
 	.release = spufs_mss_release,
 	.mmap	 = spufs_mss_mmap,
+	.llseek  = no_llseek,
 };
 
 static int
@@ -1508,6 +1521,7 @@
 	.open	 = spufs_psmap_open,
 	.release = spufs_psmap_release,
 	.mmap	 = spufs_psmap_mmap,
+	.llseek  = no_llseek,
 };
 
 
@@ -1871,6 +1885,7 @@
 	.fsync	 = spufs_mfc_fsync,
 	.fasync	 = spufs_mfc_fasync,
 	.mmap	 = spufs_mfc_mmap,
+	.llseek  = no_llseek,
 };
 
 static int spufs_npc_set(void *data, u64 val)
@@ -2246,6 +2261,7 @@
 static const struct file_operations spufs_dma_info_fops = {
 	.open = spufs_info_open,
 	.read = spufs_dma_info_read,
+	.llseek = no_llseek,
 };
 
 static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
@@ -2299,6 +2315,7 @@
 static const struct file_operations spufs_proxydma_info_fops = {
 	.open = spufs_info_open,
 	.read = spufs_proxydma_info_read,
+	.llseek = no_llseek,
 };
 
 static int spufs_show_tid(struct seq_file *s, void *private)
@@ -2585,6 +2602,7 @@
 	.read		= spufs_switch_log_read,
 	.poll		= spufs_switch_log_poll,
 	.release	= spufs_switch_log_release,
+	.llseek		= no_llseek,
 };
 
 /**
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spufs/inode.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spufs/inode.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/cell/spufs/inode.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/cell/spufs/inode.c	2011-01-04 19:50:19.000000000 -0500
@@ -798,17 +798,17 @@
 	return spufs_create_root(sb, data);
 }
 
-static int
-spufs_get_sb(struct file_system_type *fstype, int flags,
-		const char *name, void *data, struct vfsmount *mnt)
+static struct dentry *
+spufs_mount(struct file_system_type *fstype, int flags,
+		const char *name, void *data)
 {
-	return get_sb_single(fstype, flags, data, spufs_fill_super, mnt);
+	return mount_single(fstype, flags, data, spufs_fill_super);
 }
 
 static struct file_system_type spufs_type = {
 	.owner = THIS_MODULE,
 	.name = "spufs",
-	.get_sb = spufs_get_sb,
+	.mount = spufs_mount,
 	.kill_sb = kill_litter_super,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/chrp/nvram.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/chrp/nvram.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/chrp/nvram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/chrp/nvram.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,8 +74,10 @@
 		return;
 
 	nbytes_p = of_get_property(nvram, "#bytes", &proplen);
-	if (nbytes_p == NULL || proplen != sizeof(unsigned int))
+	if (nbytes_p == NULL || proplen != sizeof(unsigned int)) {
+		of_node_put(nvram);
 		return;
+	}
 
 	nvram_size = *nbytes_p;
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/embedded6xx/wii.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/embedded6xx/wii.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/embedded6xx/wii.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/embedded6xx/wii.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,7 @@
 
 void __init wii_memory_fixups(void)
 {
-	struct memblock_property *p = memblock.memory.region;
+	struct memblock_region *p = memblock.memory.regions;
 
 	/*
 	 * This is part of a workaround to allow the use of two
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/dt.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/dt.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/dt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/dt.c	2011-01-04 19:50:19.000000000 -0500
@@ -243,7 +243,7 @@
 	pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
 
 	for (i = 0; i < NR_CPUS; i++) {
-		if (lppaca[i].dyn_proc_status >= 2)
+		if (lppaca_of(i).dyn_proc_status >= 2)
 			continue;
 
 		snprintf(p, 32 - (p - buf), "@%d", i);
@@ -251,7 +251,7 @@
 
 		dt_prop_str(dt, "device_type", device_type_cpu);
 
-		index = lppaca[i].dyn_hv_phys_proc_index;
+		index = lppaca_of(i).dyn_hv_phys_proc_index;
 		d = &xIoHriProcessorVpd[index];
 
 		dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/Makefile linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS	+= -mno-minimal-toc
+ccflags-y	:= -mno-minimal-toc
 
 obj-y += exception.o
 obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/mf.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/mf.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/mf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/mf.c	2011-01-04 19:50:19.000000000 -0500
@@ -1249,6 +1249,7 @@
 
 static const struct file_operations proc_vmlinux_operations = {
 	.write		= proc_mf_change_vmlinux,
+	.llseek		= default_llseek,
 };
 
 static int __init mf_proc_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/smp.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/smp.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/iseries/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/iseries/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,7 @@
 	BUG_ON((nr < 0) || (nr >= NR_CPUS));
 
 	/* Verify that our partition has a processor nr */
-	if (lppaca[nr].dyn_proc_status >= 2)
+	if (lppaca_of(nr).dyn_proc_status >= 2)
 		return;
 
 	/* The processor is currently spinning, waiting
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/platforms/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,16 @@
 source "arch/powerpc/platforms/40x/Kconfig"
 source "arch/powerpc/platforms/amigaone/Kconfig"
 
+config KVM_GUEST
+	bool "KVM Guest support"
+	default y
+	---help---
+	  This option enables various optimizations for running under the KVM
+	  hypervisor. Overhead for the kernel when not running inside KVM should
+	  be minimal.
+
+	  In case of doubt, say Y
+
 config PPC_NATIVE
 	bool
 	depends on 6xx || PPC64
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/Kconfig.cputype linux-libre-2.6.37-gnu/arch/powerpc/platforms/Kconfig.cputype
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/Kconfig.cputype	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/Kconfig.cputype	2011-01-04 19:50:19.000000000 -0500
@@ -125,6 +125,7 @@
 
 config E500
 	select FSL_EMB_PERFMON
+	select PPC_FSL_BOOK3E
 	bool
 
 config PPC_E500MC
@@ -166,9 +167,14 @@
 
 config FSL_BOOKE
 	bool
-	depends on E200 || E500
+	depends on (E200 || E500) && PPC32
 	default y
 
+# this is for common code between PPC32 & PPC64 FSL BOOKE
+config PPC_FSL_BOOK3E
+	bool
+	select FSL_EMB_PERFMON
+	default y if FSL_BOOKE
 
 config PTE_64BIT
 	bool
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/maple/setup.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/maple/setup.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/maple/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/maple/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -358,6 +358,7 @@
 	model = (const unsigned char *)of_get_property(np, "model", NULL);
 	if (!model) {
 		printk(KERN_ERR "%s: Unabel to get model info\n", __func__);
+		of_node_put(np);
 		return -ENODEV;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/powermac/pfunc_core.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/powermac/pfunc_core.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/powermac/pfunc_core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/powermac/pfunc_core.c	2011-01-04 19:50:19.000000000 -0500
@@ -837,8 +837,10 @@
 		return NULL;
  find_it:
 	dev = pmf_find_device(actor);
-	if (dev == NULL)
-		return NULL;
+	if (dev == NULL) {
+		result = NULL;
+		goto out;
+	}
 
 	list_for_each_entry(func, &dev->functions, link) {
 		if (name && strcmp(name, func->name))
@@ -850,8 +852,9 @@
 		result = func;
 		break;
 	}
-	of_node_put(actor);
 	pmf_put_device(dev);
+out:
+	of_node_put(actor);
 	return result;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/dlpar.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/dlpar.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/dlpar.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/dlpar.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,7 @@
 	u32	prop_offset;
 };
 
-static void dlpar_free_cc_property(struct property *prop)
+void dlpar_free_cc_property(struct property *prop)
 {
 	kfree(prop->name);
 	kfree(prop->value);
@@ -55,13 +55,12 @@
 
 	prop->length = ccwa->prop_length;
 	value = (char *)ccwa + ccwa->prop_offset;
-	prop->value = kzalloc(prop->length, GFP_KERNEL);
+	prop->value = kmemdup(value, prop->length, GFP_KERNEL);
 	if (!prop->value) {
 		dlpar_free_cc_property(prop);
 		return NULL;
 	}
 
-	memcpy(prop->value, value, prop->length);
 	return prop;
 }
 
@@ -102,7 +101,7 @@
 	kfree(dn);
 }
 
-static void dlpar_free_cc_nodes(struct device_node *dn)
+void dlpar_free_cc_nodes(struct device_node *dn)
 {
 	if (dn->child)
 		dlpar_free_cc_nodes(dn->child);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/dtl.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/dtl.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/dtl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/dtl.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,37 +23,22 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/spinlock.h>
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
+#include <asm/lppaca.h>
 
 #include "plpar_wrappers.h"
 
-/*
- * Layout of entries in the hypervisor's DTL buffer. Although we don't
- * actually access the internals of an entry (we only need to know the size),
- * we might as well define it here for reference.
- */
-struct dtl_entry {
-	u8	dispatch_reason;
-	u8	preempt_reason;
-	u16	processor_id;
-	u32	enqueue_to_dispatch_time;
-	u32	ready_to_enqueue_time;
-	u32	waiting_to_ready_time;
-	u64	timebase;
-	u64	fault_addr;
-	u64	srr0;
-	u64	srr1;
-};
-
 struct dtl {
 	struct dtl_entry	*buf;
 	struct dentry		*file;
 	int			cpu;
 	int			buf_entries;
 	u64			last_idx;
+	spinlock_t		lock;
 };
 static DEFINE_PER_CPU(struct dtl, cpu_dtl);
 
@@ -72,25 +57,97 @@
 static int dtl_buf_entries = (16 * 85);
 
 
-static int dtl_enable(struct dtl *dtl)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+struct dtl_ring {
+	u64	write_index;
+	struct dtl_entry *write_ptr;
+	struct dtl_entry *buf;
+	struct dtl_entry *buf_end;
+	u8	saved_dtl_mask;
+};
+
+static DEFINE_PER_CPU(struct dtl_ring, dtl_rings);
+
+static atomic_t dtl_count;
+
+/*
+ * The cpu accounting code controls the DTL ring buffer, and we get
+ * given entries as they are processed.
+ */
+static void consume_dtle(struct dtl_entry *dtle, u64 index)
 {
-	unsigned long addr;
-	int ret, hwcpu;
+	struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings);
+	struct dtl_entry *wp = dtlr->write_ptr;
+	struct lppaca *vpa = local_paca->lppaca_ptr;
 
-	/* only allow one reader */
-	if (dtl->buf)
-		return -EBUSY;
+	if (!wp)
+		return;
 
-	/* we need to store the original allocation size for use during read */
-	dtl->buf_entries = dtl_buf_entries;
+	*wp = *dtle;
+	barrier();
 
-	dtl->buf = kmalloc_node(dtl->buf_entries * sizeof(struct dtl_entry),
-			GFP_KERNEL, cpu_to_node(dtl->cpu));
-	if (!dtl->buf) {
-		printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
-				__func__, dtl->cpu);
-		return -ENOMEM;
-	}
+	/* check for hypervisor ring buffer overflow, ignore this entry if so */
+	if (index + N_DISPATCH_LOG < vpa->dtl_idx)
+		return;
+
+	++wp;
+	if (wp == dtlr->buf_end)
+		wp = dtlr->buf;
+	dtlr->write_ptr = wp;
+
+	/* incrementing write_index makes the new entry visible */
+	smp_wmb();
+	++dtlr->write_index;
+}
+
+static int dtl_start(struct dtl *dtl)
+{
+	struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
+
+	dtlr->buf = dtl->buf;
+	dtlr->buf_end = dtl->buf + dtl->buf_entries;
+	dtlr->write_index = 0;
+
+	/* setting write_ptr enables logging into our buffer */
+	smp_wmb();
+	dtlr->write_ptr = dtl->buf;
+
+	/* enable event logging */
+	dtlr->saved_dtl_mask = lppaca_of(dtl->cpu).dtl_enable_mask;
+	lppaca_of(dtl->cpu).dtl_enable_mask |= dtl_event_mask;
+
+	dtl_consumer = consume_dtle;
+	atomic_inc(&dtl_count);
+	return 0;
+}
+
+static void dtl_stop(struct dtl *dtl)
+{
+	struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
+
+	dtlr->write_ptr = NULL;
+	smp_wmb();
+
+	dtlr->buf = NULL;
+
+	/* restore dtl_enable_mask */
+	lppaca_of(dtl->cpu).dtl_enable_mask = dtlr->saved_dtl_mask;
+
+	if (atomic_dec_and_test(&dtl_count))
+		dtl_consumer = NULL;
+}
+
+static u64 dtl_current_index(struct dtl *dtl)
+{
+	return per_cpu(dtl_rings, dtl->cpu).write_index;
+}
+
+#else /* CONFIG_VIRT_CPU_ACCOUNTING */
+
+static int dtl_start(struct dtl *dtl)
+{
+	unsigned long addr;
+	int ret, hwcpu;
 
 	/* Register our dtl buffer with the hypervisor. The HV expects the
 	 * buffer size to be passed in the second word of the buffer */
@@ -102,34 +159,82 @@
 	if (ret) {
 		printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) "
 		       "failed with %d\n", __func__, dtl->cpu, hwcpu, ret);
-		kfree(dtl->buf);
 		return -EIO;
 	}
 
 	/* set our initial buffer indices */
-	dtl->last_idx = lppaca[dtl->cpu].dtl_idx = 0;
+	lppaca_of(dtl->cpu).dtl_idx = 0;
 
 	/* ensure that our updates to the lppaca fields have occurred before
 	 * we actually enable the logging */
 	smp_wmb();
 
 	/* enable event logging */
-	lppaca[dtl->cpu].dtl_enable_mask = dtl_event_mask;
+	lppaca_of(dtl->cpu).dtl_enable_mask = dtl_event_mask;
 
 	return 0;
 }
 
-static void dtl_disable(struct dtl *dtl)
+static void dtl_stop(struct dtl *dtl)
 {
 	int hwcpu = get_hard_smp_processor_id(dtl->cpu);
 
-	lppaca[dtl->cpu].dtl_enable_mask = 0x0;
+	lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
 
 	unregister_dtl(hwcpu, __pa(dtl->buf));
+}
+
+static u64 dtl_current_index(struct dtl *dtl)
+{
+	return lppaca_of(dtl->cpu).dtl_idx;
+}
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+
+static int dtl_enable(struct dtl *dtl)
+{
+	long int n_entries;
+	long int rc;
+	struct dtl_entry *buf = NULL;
+
+	/* only allow one reader */
+	if (dtl->buf)
+		return -EBUSY;
+
+	n_entries = dtl_buf_entries;
+	buf = kmalloc_node(n_entries * sizeof(struct dtl_entry),
+			GFP_KERNEL, cpu_to_node(dtl->cpu));
+	if (!buf) {
+		printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
+				__func__, dtl->cpu);
+		return -ENOMEM;
+	}
+
+	spin_lock(&dtl->lock);
+	rc = -EBUSY;
+	if (!dtl->buf) {
+		/* store the original allocation size for use during read */
+		dtl->buf_entries = n_entries;
+		dtl->buf = buf;
+		dtl->last_idx = 0;
+		rc = dtl_start(dtl);
+		if (rc)
+			dtl->buf = NULL;
+	}
+	spin_unlock(&dtl->lock);
+
+	if (rc)
+		kfree(buf);
+	return rc;
+}
 
+static void dtl_disable(struct dtl *dtl)
+{
+	spin_lock(&dtl->lock);
+	dtl_stop(dtl);
 	kfree(dtl->buf);
 	dtl->buf = NULL;
 	dtl->buf_entries = 0;
+	spin_unlock(&dtl->lock);
 }
 
 /* file interface */
@@ -157,8 +262,9 @@
 static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
 		loff_t *pos)
 {
-	int rc, cur_idx, last_idx, n_read, n_req, read_size;
+	long int rc, n_read, n_req, read_size;
 	struct dtl *dtl;
+	u64 cur_idx, last_idx, i;
 
 	if ((len % sizeof(struct dtl_entry)) != 0)
 		return -EINVAL;
@@ -171,41 +277,48 @@
 	/* actual number of entries read */
 	n_read = 0;
 
-	cur_idx = lppaca[dtl->cpu].dtl_idx;
+	spin_lock(&dtl->lock);
+
+	cur_idx = dtl_current_index(dtl);
 	last_idx = dtl->last_idx;
 
-	if (cur_idx - last_idx > dtl->buf_entries) {
-		pr_debug("%s: hv buffer overflow for cpu %d, samples lost\n",
-				__func__, dtl->cpu);
-	}
+	if (last_idx + dtl->buf_entries <= cur_idx)
+		last_idx = cur_idx - dtl->buf_entries + 1;
 
-	cur_idx  %= dtl->buf_entries;
-	last_idx %= dtl->buf_entries;
+	if (last_idx + n_req > cur_idx)
+		n_req = cur_idx - last_idx;
+
+	if (n_req > 0)
+		dtl->last_idx = last_idx + n_req;
+
+	spin_unlock(&dtl->lock);
+
+	if (n_req <= 0)
+		return 0;
+
+	i = last_idx % dtl->buf_entries;
 
 	/* read the tail of the buffer if we've wrapped */
-	if (last_idx > cur_idx) {
-		read_size = min(n_req, dtl->buf_entries - last_idx);
+	if (i + n_req > dtl->buf_entries) {
+		read_size = dtl->buf_entries - i;
 
-		rc = copy_to_user(buf, &dtl->buf[last_idx],
+		rc = copy_to_user(buf, &dtl->buf[i],
 				read_size * sizeof(struct dtl_entry));
 		if (rc)
 			return -EFAULT;
 
-		last_idx = 0;
+		i = 0;
 		n_req -= read_size;
 		n_read += read_size;
 		buf += read_size * sizeof(struct dtl_entry);
 	}
 
 	/* .. and now the head */
-	read_size = min(n_req, cur_idx - last_idx);
-	rc = copy_to_user(buf, &dtl->buf[last_idx],
-			read_size * sizeof(struct dtl_entry));
+	rc = copy_to_user(buf, &dtl->buf[i], n_req * sizeof(struct dtl_entry));
 	if (rc)
 		return -EFAULT;
 
-	n_read += read_size;
-	dtl->last_idx += n_read;
+	n_read += n_req;
 
 	return n_read * sizeof(struct dtl_entry);
 }
@@ -263,6 +376,7 @@
 	/* set up the per-cpu log structures */
 	for_each_possible_cpu(i) {
 		struct dtl *dtl = &per_cpu(cpu_dtl, i);
+		spin_lock_init(&dtl->lock);
 		dtl->cpu = i;
 
 		rc = dtl_setup_file(dtl);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/eeh.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/eeh.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/eeh.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/eeh.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,6 @@
  * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
  */
 
-#undef DEBUG
-
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/list.h>
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/Kconfig linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/Kconfig
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,12 @@
 config PPC_PSERIES_DEBUG
 	depends on PPC_PSERIES && PPC_EARLY_DEBUG
 	bool "Enable extra debug logging in platforms/pseries"
+        help
+	  Say Y here if you want the pseries core to produce a bunch of
+	  debug messages to the system log. Select this if you are having a
+	  problem with the pseries core and want to see more of what is
+	  going on. This does not enable debugging in lpar.c, which must
+	  be manually done due to its verbosity.
 	default y
 
 config PPC_SMLPAR
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/lpar.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/lpar.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/lpar.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/lpar.c	2011-01-04 19:50:19.000000000 -0500
@@ -248,11 +248,13 @@
 	int hwcpu = get_hard_smp_processor_id(cpu);
 	unsigned long addr;
 	long ret;
+	struct paca_struct *pp;
+	struct dtl_entry *dtl;
 
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
-		lppaca[cpu].vmxregs_in_use = 1;
+		lppaca_of(cpu).vmxregs_in_use = 1;
 
-	addr = __pa(&lppaca[cpu]);
+	addr = __pa(&lppaca_of(cpu));
 	ret = register_vpa(hwcpu, addr);
 
 	if (ret) {
@@ -274,6 +276,25 @@
 			       "registration for cpu %d (hw %d) of area %lx "
 			       "returns %ld\n", cpu, hwcpu, addr, ret);
 	}
+
+	/*
+	 * Register dispatch trace log, if one has been allocated.
+	 */
+	pp = &paca[cpu];
+	dtl = pp->dispatch_log;
+	if (dtl) {
+		pp->dtl_ridx = 0;
+		pp->dtl_curr = dtl;
+		lppaca_of(cpu).dtl_idx = 0;
+
+		/* hypervisor reads buffer length from this field */
+		dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
+		ret = register_dtl(hwcpu, __pa(dtl));
+		if (ret)
+			pr_warn("DTL registration failed for cpu %d (%ld)\n",
+				cpu, ret);
+		lppaca_of(cpu).dtl_enable_mask = 2;
+	}
 }
 
 static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/Makefile linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,14 +1,9 @@
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS		+= -mno-minimal-toc
-endif
-
-ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y)
-EXTRA_CFLAGS		+= -DDEBUG
-endif
+ccflags-$(CONFIG_PPC64)			:= -mno-minimal-toc
+ccflags-$(CONFIG_PPC_PSERIES_DEBUG)	+= -DDEBUG
 
 obj-y			:= lpar.o hvCall.o nvram.o reconfig.o \
 			   setup.o iommu.o event_sources.o ras.o \
-			   firmware.o power.o dlpar.o
+			   firmware.o power.o dlpar.o mobility.o
 obj-$(CONFIG_SMP)	+= smp.o
 obj-$(CONFIG_XICS)	+= xics.o
 obj-$(CONFIG_SCANLOG)	+= scanlog.o
@@ -23,7 +18,7 @@
 obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
 obj-$(CONFIG_HVCS)		+= hvcserver.o
 obj-$(CONFIG_HCALL_STATS)	+= hvCall_inst.o
-obj-$(CONFIG_PHYP_DUMP)	+= phyp_dump.o
+obj-$(CONFIG_PHYP_DUMP)		+= phyp_dump.o
 obj-$(CONFIG_CMM)		+= cmm.o
 obj-$(CONFIG_DTL)		+= dtl.o
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/mobility.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/mobility.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/mobility.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/mobility.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,362 @@
+/*
+ * Support for Partition Mobility/Migration
+ *
+ * Copyright (C) 2010 Nathan Fontenot
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <asm/rtas.h>
+#include "pseries.h"
+
+static struct kobject *mobility_kobj;
+
+struct update_props_workarea {
+	u32 phandle;
+	u32 state;
+	u64 reserved;
+	u32 nprops;
+};
+
+#define NODE_ACTION_MASK	0xff000000
+#define NODE_COUNT_MASK		0x00ffffff
+
+#define DELETE_DT_NODE	0x01000000
+#define UPDATE_DT_NODE	0x02000000
+#define ADD_DT_NODE	0x03000000
+
+static int mobility_rtas_call(int token, char *buf)
+{
+	int rc;
+
+	spin_lock(&rtas_data_buf_lock);
+
+	memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
+	rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, 1);
+	memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+
+	spin_unlock(&rtas_data_buf_lock);
+	return rc;
+}
+
+static int delete_dt_node(u32 phandle)
+{
+	struct device_node *dn;
+
+	dn = of_find_node_by_phandle(phandle);
+	if (!dn)
+		return -ENOENT;
+
+	dlpar_detach_node(dn);
+	return 0;
+}
+
+static int update_dt_property(struct device_node *dn, struct property **prop,
+			      const char *name, u32 vd, char *value)
+{
+	struct property *new_prop = *prop;
+	struct property *old_prop;
+	int more = 0;
+
+	/* A negative 'vd' value indicates that only part of the new property
+	 * value is contained in the buffer and we need to call
+	 * ibm,update-properties again to get the rest of the value.
+	 *
+	 * A negative value is also the two's compliment of the actual value.
+	 */
+	if (vd & 0x80000000) {
+		vd = ~vd + 1;
+		more = 1;
+	}
+
+	if (new_prop) {
+		/* partial property fixup */
+		char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL);
+		if (!new_data)
+			return -ENOMEM;
+
+		memcpy(new_data, new_prop->value, new_prop->length);
+		memcpy(new_data + new_prop->length, value, vd);
+
+		kfree(new_prop->value);
+		new_prop->value = new_data;
+		new_prop->length += vd;
+	} else {
+		new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+		if (!new_prop)
+			return -ENOMEM;
+
+		new_prop->name = kstrdup(name, GFP_KERNEL);
+		if (!new_prop->name) {
+			kfree(new_prop);
+			return -ENOMEM;
+		}
+
+		new_prop->length = vd;
+		new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
+		if (!new_prop->value) {
+			kfree(new_prop->name);
+			kfree(new_prop);
+			return -ENOMEM;
+		}
+
+		memcpy(new_prop->value, value, vd);
+		*prop = new_prop;
+	}
+
+	if (!more) {
+		old_prop = of_find_property(dn, new_prop->name, NULL);
+		if (old_prop)
+			prom_update_property(dn, new_prop, old_prop);
+		else
+			prom_add_property(dn, new_prop);
+
+		new_prop = NULL;
+	}
+
+	return 0;
+}
+
+static int update_dt_node(u32 phandle)
+{
+	struct update_props_workarea *upwa;
+	struct device_node *dn;
+	struct property *prop = NULL;
+	int i, rc;
+	char *prop_data;
+	char *rtas_buf;
+	int update_properties_token;
+
+	update_properties_token = rtas_token("ibm,update-properties");
+	if (update_properties_token == RTAS_UNKNOWN_SERVICE)
+		return -EINVAL;
+
+	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+	if (!rtas_buf)
+		return -ENOMEM;
+
+	dn = of_find_node_by_phandle(phandle);
+	if (!dn) {
+		kfree(rtas_buf);
+		return -ENOENT;
+	}
+
+	upwa = (struct update_props_workarea *)&rtas_buf[0];
+	upwa->phandle = phandle;
+
+	do {
+		rc = mobility_rtas_call(update_properties_token, rtas_buf);
+		if (rc < 0)
+			break;
+
+		prop_data = rtas_buf + sizeof(*upwa);
+
+		for (i = 0; i < upwa->nprops; i++) {
+			char *prop_name;
+			u32 vd;
+
+			prop_name = prop_data + 1;
+			prop_data += strlen(prop_name) + 1;
+			vd = *prop_data++;
+
+			switch (vd) {
+			case 0x00000000:
+				/* name only property, nothing to do */
+				break;
+
+			case 0x80000000:
+				prop = of_find_property(dn, prop_name, NULL);
+				prom_remove_property(dn, prop);
+				prop = NULL;
+				break;
+
+			default:
+				rc = update_dt_property(dn, &prop, prop_name,
+							vd, prop_data);
+				if (rc) {
+					printk(KERN_ERR "Could not update %s"
+					       " property\n", prop_name);
+				}
+
+				prop_data += vd;
+			}
+		}
+	} while (rc == 1);
+
+	of_node_put(dn);
+	kfree(rtas_buf);
+	return 0;
+}
+
+static int add_dt_node(u32 parent_phandle, u32 drc_index)
+{
+	struct device_node *dn;
+	struct device_node *parent_dn;
+	int rc;
+
+	dn = dlpar_configure_connector(drc_index);
+	if (!dn)
+		return -ENOENT;
+
+	parent_dn = of_find_node_by_phandle(parent_phandle);
+	if (!parent_dn) {
+		dlpar_free_cc_nodes(dn);
+		return -ENOENT;
+	}
+
+	dn->parent = parent_dn;
+	rc = dlpar_attach_node(dn);
+	if (rc)
+		dlpar_free_cc_nodes(dn);
+
+	of_node_put(parent_dn);
+	return rc;
+}
+
+static int pseries_devicetree_update(void)
+{
+	char *rtas_buf;
+	u32 *data;
+	int update_nodes_token;
+	int rc;
+
+	update_nodes_token = rtas_token("ibm,update-nodes");
+	if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
+		return -EINVAL;
+
+	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+	if (!rtas_buf)
+		return -ENOMEM;
+
+	do {
+		rc = mobility_rtas_call(update_nodes_token, rtas_buf);
+		if (rc && rc != 1)
+			break;
+
+		data = (u32 *)rtas_buf + 4;
+		while (*data & NODE_ACTION_MASK) {
+			int i;
+			u32 action = *data & NODE_ACTION_MASK;
+			int node_count = *data & NODE_COUNT_MASK;
+
+			data++;
+
+			for (i = 0; i < node_count; i++) {
+				u32 phandle = *data++;
+				u32 drc_index;
+
+				switch (action) {
+				case DELETE_DT_NODE:
+					delete_dt_node(phandle);
+					break;
+				case UPDATE_DT_NODE:
+					update_dt_node(phandle);
+					break;
+				case ADD_DT_NODE:
+					drc_index = *data++;
+					add_dt_node(phandle, drc_index);
+					break;
+				}
+			}
+		}
+	} while (rc == 1);
+
+	kfree(rtas_buf);
+	return rc;
+}
+
+void post_mobility_fixup(void)
+{
+	int rc;
+	int activate_fw_token;
+
+	rc = pseries_devicetree_update();
+	if (rc) {
+		printk(KERN_ERR "Initial post-mobility device tree update "
+		       "failed: %d\n", rc);
+		return;
+	}
+
+	activate_fw_token = rtas_token("ibm,activate-firmware");
+	if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
+		printk(KERN_ERR "Could not make post-mobility "
+		       "activate-fw call.\n");
+		return;
+	}
+
+	rc = rtas_call(activate_fw_token, 0, 1, NULL);
+	if (!rc) {
+		rc = pseries_devicetree_update();
+		if (rc)
+			printk(KERN_ERR "Secondary post-mobility device tree "
+			       "update failed: %d\n", rc);
+	} else {
+		printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
+		return;
+	}
+
+	return;
+}
+
+static ssize_t migrate_store(struct class *class, struct class_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct rtas_args args;
+	u64 streamid;
+	int rc;
+
+	rc = strict_strtoull(buf, 0, &streamid);
+	if (rc)
+		return rc;
+
+	memset(&args, 0, sizeof(args));
+	args.token = rtas_token("ibm,suspend-me");
+	args.nargs = 2;
+	args.nret = 1;
+
+	args.args[0] = streamid >> 32 ;
+	args.args[1] = streamid & 0xffffffff;
+	args.rets = &args.args[args.nargs];
+
+	do {
+		args.rets[0] = 0;
+		rc = rtas_ibm_suspend_me(&args);
+		if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE)
+			ssleep(1);
+	} while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE);
+
+	if (rc)
+		return rc;
+	else if (args.rets[0])
+		return args.rets[0];
+
+	post_mobility_fixup();
+	return count;
+}
+
+static CLASS_ATTR(migration, S_IWUSR, NULL, migrate_store);
+
+static int __init mobility_sysfs_init(void)
+{
+	int rc;
+
+	mobility_kobj = kobject_create_and_add("mobility", kernel_kobj);
+	if (!mobility_kobj)
+		return -ENOMEM;
+
+	rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr);
+
+	return rc;
+}
+device_initcall(mobility_sysfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/pci_dlpar.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/pci_dlpar.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/pci_dlpar.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/pci_dlpar.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,8 +25,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#undef DEBUG
-
 #include <linux/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/ppc-pci.h>
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/pseries.h linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/pseries.h
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/pseries.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/pseries.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,8 @@
 extern void request_event_sources_irqs(struct device_node *np,
 				       irq_handler_t handler, const char *name);
 
+#include <linux/of.h>
+
 extern void __init fw_feature_init(const char *hypertas, unsigned long len);
 
 struct pt_regs;
@@ -47,4 +49,11 @@
 
 extern void find_udbg_vterm(void);
 
+/* Dynamic logical Partitioning/Mobility */
+extern void dlpar_free_cc_nodes(struct device_node *);
+extern void dlpar_free_cc_property(struct property *);
+extern struct device_node *dlpar_configure_connector(u32);
+extern int dlpar_attach_node(struct device_node *);
+extern int dlpar_detach_node(struct device_node *);
+
 #endif /* _PSERIES_PSERIES_H */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/reconfig.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/reconfig.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/reconfig.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/reconfig.c	2011-01-04 19:50:19.000000000 -0500
@@ -539,7 +539,8 @@
 }
 
 static const struct file_operations ofdt_fops = {
-	.write = ofdt_write
+	.write = ofdt_write,
+	.llseek = noop_llseek,
 };
 
 /* create /proc/powerpc/ofdt write-only by root */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/scanlog.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/scanlog.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/scanlog.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/scanlog.c	2011-01-04 19:50:19.000000000 -0500
@@ -170,6 +170,7 @@
 	.write		= scanlog_write,
 	.open		= scanlog_open,
 	.release	= scanlog_release,
+	.llseek		= noop_llseek,
 };
 
 static int __init scanlog_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/setup.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/setup.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -273,6 +273,58 @@
 	.notifier_call = pci_dn_reconfig_notifier,
 };
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+/*
+ * Allocate space for the dispatch trace log for all possible cpus
+ * and register the buffers with the hypervisor.  This is used for
+ * computing time stolen by the hypervisor.
+ */
+static int alloc_dispatch_logs(void)
+{
+	int cpu, ret;
+	struct paca_struct *pp;
+	struct dtl_entry *dtl;
+
+	if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+		return 0;
+
+	for_each_possible_cpu(cpu) {
+		pp = &paca[cpu];
+		dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL,
+				   cpu_to_node(cpu));
+		if (!dtl) {
+			pr_warn("Failed to allocate dispatch trace log for cpu %d\n",
+				cpu);
+			pr_warn("Stolen time statistics will be unreliable\n");
+			break;
+		}
+
+		pp->dtl_ridx = 0;
+		pp->dispatch_log = dtl;
+		pp->dispatch_log_end = dtl + N_DISPATCH_LOG;
+		pp->dtl_curr = dtl;
+	}
+
+	/* Register the DTL for the current (boot) cpu */
+	dtl = get_paca()->dispatch_log;
+	get_paca()->dtl_ridx = 0;
+	get_paca()->dtl_curr = dtl;
+	get_paca()->lppaca_ptr->dtl_idx = 0;
+
+	/* hypervisor reads buffer length from this field */
+	dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
+	ret = register_dtl(hard_smp_processor_id(), __pa(dtl));
+	if (ret)
+		pr_warn("DTL registration failed for boot cpu %d (%d)\n",
+			smp_processor_id(), ret);
+	get_paca()->lppaca_ptr->dtl_enable_mask = 2;
+
+	return 0;
+}
+
+early_initcall(alloc_dispatch_logs);
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+
 static void __init pSeries_setup_arch(void)
 {
 	/* Discover PIC type and setup ppc_md accordingly */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/xics.c linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/xics.c
--- linux-libre-2.6.36-gnu/arch/powerpc/platforms/pseries/xics.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/platforms/pseries/xics.c	2011-01-04 19:50:19.000000000 -0500
@@ -178,7 +178,7 @@
 	if (!distribute_irqs)
 		return default_server;
 
-	if (!cpumask_equal(cpumask, cpu_all_mask)) {
+	if (!cpumask_subset(cpu_possible_mask, cpumask)) {
 		int server = cpumask_first_and(cpu_online_mask, cpumask);
 
 		if (server < nr_cpu_ids)
@@ -243,7 +243,7 @@
 	 * at that level, so we do it here by hand.
 	 */
 	if (irq_to_desc(virq)->msi_desc)
-		unmask_msi_irq(virq);
+		unmask_msi_irq(irq_get_irq_data(virq));
 
 	/* unmask it */
 	xics_unmask_irq(virq);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/dart_iommu.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/dart_iommu.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/dart_iommu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/dart_iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -70,6 +70,8 @@
 static int dart_dirty;
 static int dart_is_u4;
 
+#define DART_U4_BYPASS_BASE	0x8000000000ull
+
 #define DBG(...)
 
 static inline void dart_tlb_invalidate_all(void)
@@ -292,12 +294,20 @@
 	set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
 }
 
-static void pci_dma_dev_setup_dart(struct pci_dev *dev)
+static void dma_dev_setup_dart(struct device *dev)
 {
 	/* We only have one iommu table on the mac for now, which makes
 	 * things simple. Setup all PCI devices to point to this table
 	 */
-	set_iommu_table_base(&dev->dev, &iommu_table_dart);
+	if (get_dma_ops(dev) == &dma_direct_ops)
+		set_dma_offset(dev, DART_U4_BYPASS_BASE);
+	else
+		set_iommu_table_base(dev, &iommu_table_dart);
+}
+
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
+{
+	dma_dev_setup_dart(&dev->dev);
 }
 
 static void pci_dma_bus_setup_dart(struct pci_bus *bus)
@@ -315,6 +325,45 @@
 		PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
+static bool dart_device_on_pcie(struct device *dev)
+{
+	struct device_node *np = of_node_get(dev->of_node);
+
+	while(np) {
+		if (of_device_is_compatible(np, "U4-pcie") ||
+		    of_device_is_compatible(np, "u4-pcie")) {
+			of_node_put(np);
+			return true;
+		}
+		np = of_get_next_parent(np);
+	}
+	return false;
+}
+
+static int dart_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+		return -EIO;
+
+	/* U4 supports a DART bypass, we use it for 64-bit capable
+	 * devices to improve performances. However, that only works
+	 * for devices connected to U4 own PCIe interface, not bridged
+	 * through hypertransport. We need the device to support at
+	 * least 40 bits of addresses.
+	 */
+	if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) {
+		dev_info(dev, "Using 64-bit DMA iommu bypass\n");
+		set_dma_ops(dev, &dma_direct_ops);
+	} else {
+		dev_info(dev, "Using 32-bit DMA via iommu\n");
+		set_dma_ops(dev, &dma_iommu_ops);
+	}
+	dma_dev_setup_dart(dev);
+
+	*dev->dma_mask = dma_mask;
+	return 0;
+}
+
 void __init iommu_init_early_dart(void)
 {
 	struct device_node *dn;
@@ -328,20 +377,25 @@
 		dart_is_u4 = 1;
 	}
 
+	/* Initialize the DART HW */
+	if (dart_init(dn) != 0)
+		goto bail;
+
 	/* Setup low level TCE operations for the core IOMMU code */
 	ppc_md.tce_build = dart_build;
 	ppc_md.tce_free  = dart_free;
 	ppc_md.tce_flush = dart_flush;
 
-	/* Initialize the DART HW */
-	if (dart_init(dn) == 0) {
-		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
-		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
+	/* Setup bypass if supported */
+	if (dart_is_u4)
+		ppc_md.dma_set_mask = dart_dma_set_mask;
 
-		/* Setup pci_dma ops */
-		set_pci_dma_ops(&dma_iommu_ops);
-		return;
-	}
+	ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
+	ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
+
+	/* Setup pci_dma ops */
+	set_pci_dma_ops(&dma_iommu_ops);
+	return;
 
  bail:
 	/* If init failed, use direct iommu and null setup functions */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc
+ *
+ * QorIQ based Cache Controller Memory Mapped Registers
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FSL_85XX_CACHE_CTLR_H__
+#define __FSL_85XX_CACHE_CTLR_H__
+
+#define L2CR_L2FI		0x40000000	/* L2 flash invalidate */
+#define L2CR_L2IO		0x00200000	/* L2 instruction only */
+#define L2CR_SRAM_ZERO		0x00000000	/* L2SRAM zero size */
+#define L2CR_SRAM_FULL		0x00010000	/* L2SRAM full size */
+#define L2CR_SRAM_HALF		0x00020000	/* L2SRAM half size */
+#define L2CR_SRAM_TWO_HALFS	0x00030000	/* L2SRAM two half sizes */
+#define L2CR_SRAM_QUART		0x00040000	/* L2SRAM one quarter size */
+#define L2CR_SRAM_TWO_QUARTS	0x00050000	/* L2SRAM two quarter size */
+#define L2CR_SRAM_EIGHTH	0x00060000	/* L2SRAM one eighth size */
+#define L2CR_SRAM_TWO_EIGHTH	0x00070000	/* L2SRAM two eighth size */
+
+#define L2SRAM_OPTIMAL_SZ_SHIFT	0x00000003	/* Optimum size for L2SRAM */
+
+#define L2SRAM_BAR_MSK_LO18	0xFFFFC000	/* Lower 18 bits */
+#define L2SRAM_BARE_MSK_HI4	0x0000000F	/* Upper 4 bits */
+
+enum cache_sram_lock_ways {
+	LOCK_WAYS_ZERO,
+	LOCK_WAYS_EIGHTH,
+	LOCK_WAYS_TWO_EIGHTH,
+	LOCK_WAYS_HALF = 4,
+	LOCK_WAYS_FULL = 8,
+};
+
+struct mpc85xx_l2ctlr {
+	u32	ctl;		/* 0x000 - L2 control */
+	u8	res1[0xC];
+	u32	ewar0;		/* 0x010 - External write address 0 */
+	u32	ewarea0;	/* 0x014 - External write address extended 0 */
+	u32	ewcr0;		/* 0x018 - External write ctrl */
+	u8	res2[4];
+	u32	ewar1;		/* 0x020 - External write address 1 */
+	u32	ewarea1;	/* 0x024 - External write address extended 1 */
+	u32	ewcr1;		/* 0x028 - External write ctrl 1 */
+	u8	res3[4];
+	u32	ewar2;		/* 0x030 - External write address 2 */
+	u32	ewarea2;	/* 0x034 - External write address extended 2 */
+	u32	ewcr2;		/* 0x038 - External write ctrl 2 */
+	u8	res4[4];
+	u32	ewar3;		/* 0x040 - External write address 3 */
+	u32	ewarea3;	/* 0x044 - External write address extended 3 */
+	u32	ewcr3;		/* 0x048 - External write ctrl 3 */
+	u8	res5[0xB4];
+	u32	srbar0;		/* 0x100 - SRAM base address 0 */
+	u32	srbarea0;	/* 0x104 - SRAM base addr reg ext address 0 */
+	u32	srbar1;		/* 0x108 - SRAM base address 1 */
+	u32	srbarea1;	/* 0x10C - SRAM base addr reg ext address 1 */
+	u8	res6[0xCF0];
+	u32	errinjhi;	/* 0xE00 - Error injection mask high */
+	u32	errinjlo;	/* 0xE04 - Error injection mask low */
+	u32	errinjctl;	/* 0xE08 - Error injection tag/ecc control */
+	u8	res7[0x14];
+	u32	captdatahi;	/* 0xE20 - Error data high capture */
+	u32	captdatalo;	/* 0xE24 - Error data low capture */
+	u32	captecc;	/* 0xE28 - Error syndrome */
+	u8	res8[0x14];
+	u32	errdet;		/* 0xE40 - Error detect */
+	u32	errdis;		/* 0xE44 - Error disable */
+	u32	errinten;	/* 0xE48 - Error interrupt enable */
+	u32	errattr;	/* 0xE4c - Error attribute capture */
+	u32	erradrrl;	/* 0xE50 - Error address capture low */
+	u32	erradrrh;	/* 0xE54 - Error address capture high */
+	u32	errctl;		/* 0xE58 - Error control */
+	u8	res9[0x1A4];
+};
+
+struct sram_parameters {
+	unsigned int sram_size;
+	uint64_t sram_offset;
+};
+
+extern int instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params);
+extern void remove_cache_sram(struct platform_device *dev);
+
+#endif /* __FSL_85XX_CACHE_CTLR_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_cache_sram.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_cache_sram.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_cache_sram.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <asm/pgtable.h>
+#include <asm/fsl_85xx_cache_sram.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+struct mpc85xx_cache_sram *cache_sram;
+
+void *mpc85xx_cache_sram_alloc(unsigned int size,
+				phys_addr_t *phys, unsigned int align)
+{
+	unsigned long offset;
+	unsigned long flags;
+
+	if (unlikely(cache_sram == NULL))
+		return NULL;
+
+	if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
+		pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
+			__func__, size, align);
+		return NULL;
+	}
+
+	if ((align & (align - 1)) || align <= 1) {
+		pr_err("%s(): align(=%x) must be power of two and >1\n",
+			__func__, align);
+		return NULL;
+	}
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+
+	if (IS_ERR_VALUE(offset))
+		return NULL;
+
+	*phys = cache_sram->base_phys + offset;
+
+	return (unsigned char *)cache_sram->base_virt + offset;
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
+
+void mpc85xx_cache_sram_free(void *ptr)
+{
+	unsigned long flags;
+	BUG_ON(!ptr);
+
+	spin_lock_irqsave(&cache_sram->lock, flags);
+	rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
+	spin_unlock_irqrestore(&cache_sram->lock, flags);
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_free);
+
+int __init instantiate_cache_sram(struct platform_device *dev,
+		struct sram_parameters sram_params)
+{
+	int ret = 0;
+
+	if (cache_sram) {
+		dev_err(&dev->dev, "Already initialized cache-sram\n");
+		return -EBUSY;
+	}
+
+	cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
+	if (!cache_sram) {
+		dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
+		return -ENOMEM;
+	}
+
+	cache_sram->base_phys = sram_params.sram_offset;
+	cache_sram->size = sram_params.sram_size;
+
+	if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+						"fsl_85xx_cache_sram")) {
+		dev_err(&dev->dev, "%s: request memory failed\n",
+				dev->dev.of_node->full_name);
+		ret = -ENXIO;
+		goto out_free;
+	}
+
+	cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+				cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
+	if (!cache_sram->base_virt) {
+		dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+				dev->dev.of_node->full_name);
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	cache_sram->rh = rh_create(sizeof(unsigned int));
+	if (IS_ERR(cache_sram->rh)) {
+		dev_err(&dev->dev, "%s: Unable to create remote heap\n",
+				dev->dev.of_node->full_name);
+		ret = PTR_ERR(cache_sram->rh);
+		goto out_unmap;
+	}
+
+	rh_attach_region(cache_sram->rh, 0, cache_sram->size);
+	spin_lock_init(&cache_sram->lock);
+
+	dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
+		(unsigned long long)cache_sram->base_phys, cache_sram->size);
+
+	return 0;
+
+out_unmap:
+	iounmap(cache_sram->base_virt);
+
+out_release:
+	release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+out_free:
+	kfree(cache_sram);
+	return ret;
+}
+
+void remove_cache_sram(struct platform_device *dev)
+{
+	BUG_ON(!cache_sram);
+
+	rh_detach_region(cache_sram->rh, 0, cache_sram->size);
+	rh_destroy(cache_sram->rh);
+
+	iounmap(cache_sram->base_virt);
+	release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+	kfree(cache_sram);
+	cache_sram = NULL;
+
+	dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
+}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+static char *sram_size;
+static char *sram_offset;
+struct mpc85xx_l2ctlr __iomem *l2ctlr;
+
+static long get_cache_sram_size(void)
+{
+	unsigned long val;
+
+	if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static long get_cache_sram_offset(void)
+{
+	unsigned long val;
+
+	if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0))
+		return -EINVAL;
+
+	return val;
+}
+
+static int __init get_size_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_size = str;
+	return 1;
+}
+
+static int __init get_offset_from_cmdline(char *str)
+{
+	if (!str)
+		return 0;
+
+	sram_offset = str;
+	return 1;
+}
+
+__setup("cache-sram-size=", get_size_from_cmdline);
+__setup("cache-sram-offset=", get_offset_from_cmdline);
+
+static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev,
+					  const struct of_device_id *match)
+{
+	long rval;
+	unsigned int rem;
+	unsigned char ways;
+	const unsigned int *prop;
+	unsigned int l2cache_size;
+	struct sram_parameters sram_params;
+
+	if (!dev->dev.of_node) {
+		dev_err(&dev->dev, "Device's OF-node is NULL\n");
+		return -EINVAL;
+	}
+
+	prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
+	if (!prop) {
+		dev_err(&dev->dev, "Missing L2 cache-size\n");
+		return -EINVAL;
+	}
+	l2cache_size = *prop;
+
+	sram_params.sram_size  = get_cache_sram_size();
+	if (sram_params.sram_size <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, Aborting Cache-SRAM stuff\n");
+		return -EINVAL;
+	}
+
+	sram_params.sram_offset  = get_cache_sram_offset();
+	if (sram_params.sram_offset <= 0) {
+		dev_err(&dev->dev,
+			"Entire L2 as cache, provide a valid sram offset\n");
+		return -EINVAL;
+	}
+
+
+	rem = l2cache_size % sram_params.sram_size;
+	ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
+	if (rem || (ways & (ways - 1))) {
+		dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
+		return -EINVAL;
+	}
+
+	l2ctlr = of_iomap(dev->dev.of_node, 0);
+	if (!l2ctlr) {
+		dev_err(&dev->dev, "Can't map L2 controller\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Write bits[0-17] to srbar0
+	 */
+	out_be32(&l2ctlr->srbar0,
+		sram_params.sram_offset & L2SRAM_BAR_MSK_LO18);
+
+	/*
+	 * Write bits[18-21] to srbare0
+	 */
+#ifdef CONFIG_PHYS_64BIT
+	out_be32(&l2ctlr->srbarea0,
+		(sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4);
+#endif
+
+	clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
+
+	switch (ways) {
+	case LOCK_WAYS_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
+		break;
+
+	case LOCK_WAYS_TWO_EIGHTH:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
+		break;
+
+	case LOCK_WAYS_HALF:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
+		break;
+
+	case LOCK_WAYS_FULL:
+	default:
+		setbits32(&l2ctlr->ctl,
+			L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
+		break;
+	}
+	eieio();
+
+	rval = instantiate_cache_sram(dev, sram_params);
+	if (rval < 0) {
+		dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
+		iounmap(l2ctlr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
+{
+	BUG_ON(!l2ctlr);
+
+	iounmap(l2ctlr);
+	remove_cache_sram(dev);
+	dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
+
+	return 0;
+}
+
+static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
+	{
+		.compatible = "fsl,p2020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p2010-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1020-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1011-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1013-l2-cache-controller",
+	},
+	{
+		.compatible = "fsl,p1022-l2-cache-controller",
+	},
+	{},
+};
+
+static struct of_platform_driver mpc85xx_l2ctlr_of_platform_driver = {
+	.driver	= {
+		.name		= "fsl-l2ctlr",
+		.owner		= THIS_MODULE,
+		.of_match_table	= mpc85xx_l2ctlr_of_match,
+	},
+	.probe		= mpc85xx_l2ctlr_of_probe,
+	.remove		= __devexit_p(mpc85xx_l2ctlr_of_remove),
+};
+
+static __init int mpc85xx_l2ctlr_of_init(void)
+{
+	return of_register_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+static void __exit mpc85xx_l2ctlr_of_exit(void)
+{
+	of_unregister_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+subsys_initcall(mpc85xx_l2ctlr_of_init);
+module_exit(mpc85xx_l2ctlr_of_exit);
+
+MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
+MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_lbc.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_lbc.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_lbc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_lbc.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,9 +1,12 @@
 /*
  * Freescale LBC and UPM routines.
  *
- * Copyright (c) 2007-2008  MontaVista Software, Inc.
+ * Copyright Â© 2007-2008  MontaVista Software, Inc.
+ * Copyright Â© 2010 Freescale Semiconductor
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ * Author: Jack Lan <Jack.Lan@freescale.com>
+ * Author: Roy Zang <tie-fei.zang@freescale.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,39 +22,37 @@
 #include <linux/types.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
 #include <asm/prom.h>
 #include <asm/fsl_lbc.h>
 
 static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
-static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-
-static char __initdata *compat_lbc[] = {
-	"fsl,pq2-localbus",
-	"fsl,pq2pro-localbus",
-	"fsl,pq3-localbus",
-	"fsl,elbc",
-};
+struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
+EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
 
-static int __init fsl_lbc_init(void)
+/**
+ * fsl_lbc_addr - convert the base address
+ * @addr_base:	base address of the memory bank
+ *
+ * This function converts a base address of lbc into the right format for the
+ * BR register. If the SOC has eLBC then it returns 32bit physical address
+ * else it convers a 34bit local bus physical address to correct format of
+ * 32bit address for BR register (Example: MPC8641).
+ */
+u32 fsl_lbc_addr(phys_addr_t addr_base)
 {
-	struct device_node *lbus;
-	int i;
+	struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
+	u32 addr = addr_base & 0xffff8000;
 
-	for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
-		lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
-		if (lbus)
-			goto found;
-	}
-	return -ENODEV;
+	if (of_device_is_compatible(np, "fsl,elbc"))
+		return addr;
 
-found:
-	fsl_lbc_regs = of_iomap(lbus, 0);
-	of_node_put(lbus);
-	if (!fsl_lbc_regs)
-		return -ENOMEM;
-	return 0;
+	return addr | ((addr_base & 0x300000000ull) >> 19);
 }
-arch_initcall(fsl_lbc_init);
+EXPORT_SYMBOL(fsl_lbc_addr);
 
 /**
  * fsl_lbc_find - find Localbus bank
@@ -65,15 +66,17 @@
 int fsl_lbc_find(phys_addr_t addr_base)
 {
 	int i;
+	struct fsl_lbc_regs __iomem *lbc;
 
-	if (!fsl_lbc_regs)
+	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
 		return -ENODEV;
 
-	for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
-		__be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
-		__be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
+	lbc = fsl_lbc_ctrl_dev->regs;
+	for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
+		__be32 br = in_be32(&lbc->bank[i].br);
+		__be32 or = in_be32(&lbc->bank[i].or);
 
-		if (br & BR_V && (br & or & BR_BA) == addr_base)
+		if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
 			return i;
 	}
 
@@ -94,22 +97,27 @@
 {
 	int bank;
 	__be32 br;
+	struct fsl_lbc_regs __iomem *lbc;
 
 	bank = fsl_lbc_find(addr_base);
 	if (bank < 0)
 		return bank;
 
-	br = in_be32(&fsl_lbc_regs->bank[bank].br);
+	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+		return -ENODEV;
+
+	lbc = fsl_lbc_ctrl_dev->regs;
+	br = in_be32(&lbc->bank[bank].br);
 
 	switch (br & BR_MSEL) {
 	case BR_MS_UPMA:
-		upm->mxmr = &fsl_lbc_regs->mamr;
+		upm->mxmr = &lbc->mamr;
 		break;
 	case BR_MS_UPMB:
-		upm->mxmr = &fsl_lbc_regs->mbmr;
+		upm->mxmr = &lbc->mbmr;
 		break;
 	case BR_MS_UPMC:
-		upm->mxmr = &fsl_lbc_regs->mcmr;
+		upm->mxmr = &lbc->mcmr;
 		break;
 	default:
 		return -EINVAL;
@@ -148,9 +156,12 @@
 	int ret = 0;
 	unsigned long flags;
 
+	if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+		return -ENODEV;
+
 	spin_lock_irqsave(&fsl_lbc_lock, flags);
 
-	out_be32(&fsl_lbc_regs->mar, mar);
+	out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
 
 	switch (upm->width) {
 	case 8:
@@ -172,3 +183,166 @@
 	return ret;
 }
 EXPORT_SYMBOL(fsl_upm_run_pattern);
+
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+{
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+
+	/* clear event registers */
+	setbits32(&lbc->ltesr, LTESR_CLEAR);
+	out_be32(&lbc->lteatr, 0);
+	out_be32(&lbc->ltear, 0);
+	out_be32(&lbc->lteccr, LTECCR_CLEAR);
+	out_be32(&lbc->ltedr, LTEDR_ENABLE);
+
+	/* Enable interrupts for any detected events */
+	out_be32(&lbc->lteir, LTEIR_ENABLE);
+
+	return 0;
+}
+
+/*
+ * NOTE: This interrupt is used to report localbus events of various kinds,
+ * such as transaction errors on the chipselects.
+ */
+
+static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
+{
+	struct fsl_lbc_ctrl *ctrl = data;
+	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+	u32 status;
+
+	status = in_be32(&lbc->ltesr);
+	if (!status)
+		return IRQ_NONE;
+
+	out_be32(&lbc->ltesr, LTESR_CLEAR);
+	out_be32(&lbc->lteatr, 0);
+	out_be32(&lbc->ltear, 0);
+	ctrl->irq_status = status;
+
+	if (status & LTESR_BM)
+		dev_err(ctrl->dev, "Local bus monitor time-out: "
+			"LTESR 0x%08X\n", status);
+	if (status & LTESR_WP)
+		dev_err(ctrl->dev, "Write protect error: "
+			"LTESR 0x%08X\n", status);
+	if (status & LTESR_ATMW)
+		dev_err(ctrl->dev, "Atomic write error: "
+			"LTESR 0x%08X\n", status);
+	if (status & LTESR_ATMR)
+		dev_err(ctrl->dev, "Atomic read error: "
+			"LTESR 0x%08X\n", status);
+	if (status & LTESR_CS)
+		dev_err(ctrl->dev, "Chip select error: "
+			"LTESR 0x%08X\n", status);
+	if (status & LTESR_UPM)
+		;
+	if (status & LTESR_FCT) {
+		dev_err(ctrl->dev, "FCM command time-out: "
+			"LTESR 0x%08X\n", status);
+		smp_wmb();
+		wake_up(&ctrl->irq_wait);
+	}
+	if (status & LTESR_PAR) {
+		dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
+			"LTESR 0x%08X\n", status);
+		smp_wmb();
+		wake_up(&ctrl->irq_wait);
+	}
+	if (status & LTESR_CC) {
+		smp_wmb();
+		wake_up(&ctrl->irq_wait);
+	}
+	if (status & ~LTESR_MASK)
+		dev_err(ctrl->dev, "Unknown error: "
+			"LTESR 0x%08X\n", status);
+	return IRQ_HANDLED;
+}
+
+/*
+ * fsl_lbc_ctrl_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code allocates all of
+ * the resources needed for the controller only.  The
+ * resources for the NAND banks themselves are allocated
+ * in the chip probe function.
+*/
+
+static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
+{
+	int ret;
+
+	if (!dev->dev.of_node) {
+		dev_err(&dev->dev, "Device OF-Node is NULL");
+		return -EFAULT;
+	}
+
+	fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
+	if (!fsl_lbc_ctrl_dev)
+		return -ENOMEM;
+
+	dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
+
+	spin_lock_init(&fsl_lbc_ctrl_dev->lock);
+	init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
+
+	fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
+	if (!fsl_lbc_ctrl_dev->regs) {
+		dev_err(&dev->dev, "failed to get memory region\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
+	if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
+		dev_err(&dev->dev, "failed to get irq resource\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	fsl_lbc_ctrl_dev->dev = &dev->dev;
+
+	ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+	if (ret < 0)
+		goto err;
+
+	ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
+				"fsl-lbc", fsl_lbc_ctrl_dev);
+	if (ret != 0) {
+		dev_err(&dev->dev, "failed to install irq (%d)\n",
+			fsl_lbc_ctrl_dev->irq);
+		ret = fsl_lbc_ctrl_dev->irq;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	iounmap(fsl_lbc_ctrl_dev->regs);
+	kfree(fsl_lbc_ctrl_dev);
+	return ret;
+}
+
+static const struct of_device_id fsl_lbc_match[] = {
+	{ .compatible = "fsl,elbc", },
+	{ .compatible = "fsl,pq3-localbus", },
+	{ .compatible = "fsl,pq2-localbus", },
+	{ .compatible = "fsl,pq2pro-localbus", },
+	{},
+};
+
+static struct platform_driver fsl_lbc_ctrl_driver = {
+	.driver = {
+		.name = "fsl-lbc",
+		.of_match_table = fsl_lbc_match,
+	},
+	.probe = fsl_lbc_ctrl_probe,
+};
+
+static int __init fsl_lbc_init(void)
+{
+	return platform_driver_register(&fsl_lbc_ctrl_driver);
+}
+module_init(fsl_lbc_init);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_msi.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_msi.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <asm/ppc-pci.h>
 #include <asm/mpic.h>
 #include "fsl_msi.h"
+#include "fsl_pci.h"
 
 LIST_HEAD(msi_head);
 
@@ -51,8 +52,8 @@
 }
 
 static struct irq_chip fsl_msi_chip = {
-	.mask		= mask_msi_irq,
-	.unmask		= unmask_msi_irq,
+	.irq_mask	= mask_msi_irq,
+	.irq_unmask	= unmask_msi_irq,
 	.ack		= fsl_msi_end_irq,
 	.name		= "FSL-MSI",
 };
@@ -125,13 +126,11 @@
 {
 	struct fsl_msi *msi_data = fsl_msi_data;
 	struct pci_controller *hose = pci_bus_to_host(pdev->bus);
-	u32 base = 0;
+	u64 base = fsl_pci_immrbar_base(hose);
 
-	pci_bus_read_config_dword(hose->bus,
-		PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+	msg->address_lo = msi_data->msi_addr_lo + lower_32_bits(base);
+	msg->address_hi = msi_data->msi_addr_hi + upper_32_bits(base);
 
-	msg->address_lo = msi_data->msi_addr_lo + base;
-	msg->address_hi = msi_data->msi_addr_hi;
 	msg->data = hwirq;
 
 	pr_debug("%s: allocated srs: %d, ibs: %d\n",
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_pci.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_pci.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_pci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_pci.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * MPC83xx/85xx/86xx PCI/PCIE support routing.
  *
- * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
  * Copyright 2008-2009 MontaVista Software, Inc.
  *
  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
@@ -34,7 +34,7 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
-static int fsl_pcie_bus_fixup;
+static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
 
 static void __init quirk_fsl_pcie_header(struct pci_dev *dev)
 {
@@ -407,10 +407,18 @@
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020, quirk_fsl_pcie_header);
 #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
 
 #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
@@ -430,6 +438,13 @@
 	u32 dev_base;
 };
 
+struct pex_inbound_window {
+	u32 ar;
+	u32 tar;
+	u32 barl;
+	u32 barh;
+};
+
 /*
  * With the convention of u-boot, the PCIE outbound window 0 serves
  * as configuration transactions outbound.
@@ -437,6 +452,8 @@
 #define PEX_OUTWIN0_BAR		0xCA4
 #define PEX_OUTWIN0_TAL		0xCA8
 #define PEX_OUTWIN0_TAH		0xCAC
+#define PEX_RC_INWIN_BASE	0xE60
+#define PEX_RCIWARn_EN		0x1
 
 static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)
 {
@@ -604,6 +621,8 @@
 	const int *bus_range;
 	int primary;
 
+	is_mpc83xx_pci = 1;
+
 	if (!of_device_is_available(dev)) {
 		pr_warning("%s: disabled by the firmware.\n",
 			   dev->full_name);
@@ -683,3 +702,40 @@
 	return ret;
 }
 #endif /* CONFIG_PPC_83xx */
+
+u64 fsl_pci_immrbar_base(struct pci_controller *hose)
+{
+#ifdef CONFIG_PPC_83xx
+	if (is_mpc83xx_pci) {
+		struct mpc83xx_pcie_priv *pcie = hose->dn->data;
+		struct pex_inbound_window *in;
+		int i;
+
+		/* Walk the Root Complex Inbound windows to match IMMR base */
+		in = pcie->cfg_type0 + PEX_RC_INWIN_BASE;
+		for (i = 0; i < 4; i++) {
+			/* not enabled, skip */
+			if (!in_le32(&in[i].ar) & PEX_RCIWARn_EN)
+				 continue;
+
+			if (get_immrbase() == in_le32(&in[i].tar))
+				return (u64)in_le32(&in[i].barh) << 32 |
+					    in_le32(&in[i].barl);
+		}
+
+		printk(KERN_WARNING "could not find PCI BAR matching IMMR\n");
+	}
+#endif
+
+#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
+	if (!is_mpc83xx_pci) {
+		u32 base;
+
+		pci_bus_read_config_dword(hose->bus,
+			PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+		return base;
+	}
+#endif
+
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_pci.h linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_pci.h
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -88,6 +88,7 @@
 extern int fsl_add_bridge(struct device_node *dev, int is_primary);
 extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
 extern int mpc83xx_add_bridge(struct device_node *dev);
+u64 fsl_pci_immrbar_base(struct pci_controller *hose);
 
 #endif /* __POWERPC_FSL_PCI_H */
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_rio.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_rio.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_rio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_rio.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,6 +50,7 @@
 #define RIO_ATMU_REGS_OFFSET	0x10c00
 #define RIO_P_MSG_REGS_OFFSET	0x11000
 #define RIO_S_MSG_REGS_OFFSET	0x13000
+#define RIO_GCCSR		0x13c
 #define RIO_ESCSR		0x158
 #define RIO_CCSR		0x15c
 #define RIO_LTLEDCSR		0x0608
@@ -87,6 +88,9 @@
 #define RIO_IPWSR_PWD		0x00000008
 #define RIO_IPWSR_PWB		0x00000004
 
+#define RIO_EPWISR_PINT		0x80000000
+#define RIO_EPWISR_PW		0x00000001
+
 #define RIO_MSG_DESC_SIZE	32
 #define RIO_MSG_BUFFER_SIZE	4096
 #define RIO_MIN_TX_RING_SIZE	2
@@ -117,44 +121,59 @@
 };
 
 struct rio_msg_regs {
-	u32 omr;
-	u32 osr;
+	u32 omr;	/* 0xD_3000 - Outbound message 0 mode register */
+	u32 osr;	/* 0xD_3004 - Outbound message 0 status register */
 	u32 pad1;
-	u32 odqdpar;
+	u32 odqdpar;	/* 0xD_300C - Outbound message 0 descriptor queue
+			   dequeue pointer address register */
 	u32 pad2;
-	u32 osar;
-	u32 odpr;
-	u32 odatr;
-	u32 odcr;
+	u32 osar;	/* 0xD_3014 - Outbound message 0 source address
+			   register */
+	u32 odpr;	/* 0xD_3018 - Outbound message 0 destination port
+			   register */
+	u32 odatr;	/* 0xD_301C - Outbound message 0 destination attributes
+			   Register*/
+	u32 odcr;	/* 0xD_3020 - Outbound message 0 double-word count
+			   register */
 	u32 pad3;
-	u32 odqepar;
+	u32 odqepar;	/* 0xD_3028 - Outbound message 0 descriptor queue
+			   enqueue pointer address register */
 	u32 pad4[13];
-	u32 imr;
-	u32 isr;
+	u32 imr;	/* 0xD_3060 - Inbound message 0 mode register */
+	u32 isr;	/* 0xD_3064 - Inbound message 0 status register */
 	u32 pad5;
-	u32 ifqdpar;
+	u32 ifqdpar;	/* 0xD_306C - Inbound message 0 frame queue dequeue
+			   pointer address register*/
 	u32 pad6;
-	u32 ifqepar;
+	u32 ifqepar;	/* 0xD_3074 - Inbound message 0 frame queue enqueue
+			   pointer address register */
 	u32 pad7[226];
-	u32 odmr;
-	u32 odsr;
+	u32 odmr;	/* 0xD_3400 - Outbound doorbell mode register */
+	u32 odsr;	/* 0xD_3404 - Outbound doorbell status register */
 	u32 res0[4];
-	u32 oddpr;
-	u32 oddatr;
+	u32 oddpr;	/* 0xD_3418 - Outbound doorbell destination port
+			   register */
+	u32 oddatr;	/* 0xD_341c - Outbound doorbell destination attributes
+			   register */
 	u32 res1[3];
-	u32 odretcr;
+	u32 odretcr;	/* 0xD_342C - Outbound doorbell retry error threshold
+			   configuration register */
 	u32 res2[12];
-	u32 dmr;
-	u32 dsr;
+	u32 dmr;	/* 0xD_3460 - Inbound doorbell mode register */
+	u32 dsr;	/* 0xD_3464 - Inbound doorbell status register */
 	u32 pad8;
-	u32 dqdpar;
+	u32 dqdpar;	/* 0xD_346C - Inbound doorbell queue dequeue Pointer
+			   address register */
 	u32 pad9;
-	u32 dqepar;
+	u32 dqepar;	/* 0xD_3474 - Inbound doorbell Queue enqueue pointer
+			   address register */
 	u32 pad10[26];
-	u32 pwmr;
-	u32 pwsr;
-	u32 epwqbar;
-	u32 pwqbar;
+	u32 pwmr;	/* 0xD_34E0 - Inbound port-write mode register */
+	u32 pwsr;	/* 0xD_34E4 - Inbound port-write status register */
+	u32 epwqbar;	/* 0xD_34E8 - Extended Port-Write Queue Base Address
+			   register */
+	u32 pwqbar;	/* 0xD_34EC - Inbound port-write queue base address
+			   register */
 };
 
 struct rio_tx_desc {
@@ -1067,18 +1086,12 @@
 	struct rio_priv *priv = port->priv;
 	u32 epwisr, tmp;
 
-	ipwmr = in_be32(&priv->msg_regs->pwmr);
-	ipwsr = in_be32(&priv->msg_regs->pwsr);
-
 	epwisr = in_be32(priv->regs_win + RIO_EPWISR);
-	if (epwisr & 0x80000000) {
-		tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
-		pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
-		out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
-	}
+	if (!(epwisr & RIO_EPWISR_PW))
+		goto pw_done;
 
-	if (!(epwisr & 0x00000001))
-		return IRQ_HANDLED;
+	ipwmr = in_be32(&priv->msg_regs->pwmr);
+	ipwsr = in_be32(&priv->msg_regs->pwsr);
 
 #ifdef DEBUG_PW
 	pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
@@ -1094,20 +1107,6 @@
 		pr_debug(" PWB");
 	pr_debug(" )\n");
 #endif
-	out_be32(&priv->msg_regs->pwsr,
-		 ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
-
-	if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
-		priv->port_write_msg.err_count++;
-		pr_info("RIO: Port-Write Transaction Err (%d)\n",
-			 priv->port_write_msg.err_count);
-	}
-	if (ipwsr & RIO_IPWSR_PWD) {
-		priv->port_write_msg.discard_count++;
-		pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
-			 priv->port_write_msg.discard_count);
-	}
-
 	/* Schedule deferred processing if PW was received */
 	if (ipwsr & RIO_IPWSR_QFI) {
 		/* Save PW message (if there is room in FIFO),
@@ -1119,16 +1118,43 @@
 				 RIO_PW_MSG_SIZE);
 		} else {
 			priv->port_write_msg.discard_count++;
-			pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+			pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
 				 priv->port_write_msg.discard_count);
 		}
+		/* Clear interrupt and issue Clear Queue command. This allows
+		 * another port-write to be received.
+		 */
+		out_be32(&priv->msg_regs->pwsr,	RIO_IPWSR_QFI);
+		out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
 		schedule_work(&priv->pw_work);
 	}
 
-	/* Issue Clear Queue command. This allows another
-	 * port-write to be received.
-	 */
-	out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+	if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+		priv->port_write_msg.err_count++;
+		pr_debug("RIO: Port-Write Transaction Err (%d)\n",
+			 priv->port_write_msg.err_count);
+		/* Clear Transaction Error: port-write controller should be
+		 * disabled when clearing this error
+		 */
+		out_be32(&priv->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE);
+		out_be32(&priv->msg_regs->pwsr,	RIO_IPWSR_TE);
+		out_be32(&priv->msg_regs->pwmr, ipwmr);
+	}
+
+	if (ipwsr & RIO_IPWSR_PWD) {
+		priv->port_write_msg.discard_count++;
+		pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+			 priv->port_write_msg.discard_count);
+		out_be32(&priv->msg_regs->pwsr, RIO_IPWSR_PWD);
+	}
+
+pw_done:
+	if (epwisr & RIO_EPWISR_PINT) {
+		tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+		pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+		out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -1446,6 +1472,7 @@
 	port->host_deviceid = fsl_rio_get_hdid(port->id);
 
 	port->priv = priv;
+	port->phys_efptr = 0x100;
 	rio_register_mport(port);
 
 	priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
@@ -1493,6 +1520,12 @@
 	dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n",
 			port->sys_size ? 65536 : 256);
 
+	if (port->host_deviceid >= 0)
+		out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST |
+			RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED);
+	else
+		out_be32(priv->regs_win + RIO_GCCSR, 0x00000000);
+
 	priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win
 					+ RIO_ATMU_REGS_OFFSET);
 	priv->maint_atmu_regs = priv->atmu_regs + 1;
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_soc.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_soc.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/fsl_soc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/fsl_soc.c	2011-01-04 19:50:19.000000000 -0500
@@ -209,186 +209,29 @@
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
-static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
-{
-	if (!phy_type)
-		return FSL_USB2_PHY_NONE;
-	if (!strcasecmp(phy_type, "ulpi"))
-		return FSL_USB2_PHY_ULPI;
-	if (!strcasecmp(phy_type, "utmi"))
-		return FSL_USB2_PHY_UTMI;
-	if (!strcasecmp(phy_type, "utmi_wide"))
-		return FSL_USB2_PHY_UTMI_WIDE;
-	if (!strcasecmp(phy_type, "serial"))
-		return FSL_USB2_PHY_SERIAL;
-
-	return FSL_USB2_PHY_NONE;
-}
+#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
+static __be32 __iomem *rstcr;
 
-static int __init fsl_usb_of_init(void)
+static int __init setup_rstcr(void)
 {
 	struct device_node *np;
-	unsigned int i = 0;
-	struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
-		*usb_dev_dr_client = NULL;
-	int ret;
 
-	for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		usb_dev_mph =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_mph)) {
-			ret = PTR_ERR(usb_dev_mph);
-			goto err;
-		}
-
-		usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
-
-		usb_data.operating_mode = FSL_USB2_MPH_HOST;
-
-		prop = of_get_property(np, "port0", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
-
-		prop = of_get_property(np, "port1", NULL);
-		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		ret =
-		    platform_device_add_data(usb_dev_mph, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
-		if (ret)
-			goto unreg_mph;
-		i++;
-	}
-
-	for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		if (!of_device_is_available(np))
-			continue;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
-		if (ret)
-			goto unreg_mph;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		prop = of_get_property(np, "dr_mode", NULL);
-
-		if (!prop || !strcmp(prop, "host")) {
-			usb_data.operating_mode = FSL_USB2_DR_HOST;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "peripheral")) {
-			usb_data.operating_mode = FSL_USB2_DR_DEVICE;
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "otg")) {
-			usb_data.operating_mode = FSL_USB2_DR_OTG;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		if (usb_dev_dr_host) {
-			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_host,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		if (usb_dev_dr_client) {
-			usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_client,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
+	for_each_node_by_name(np, "global-utilities") {
+		if ((of_get_property(np, "fsl,has-rstcr", NULL))) {
+			rstcr = of_iomap(np, 0) + 0xb0;
+			if (!rstcr)
+				printk (KERN_ERR "Error: reset control "
+						"register not mapped!\n");
+			break;
 		}
-		i++;
 	}
-	return 0;
 
-unreg_dr:
-	if (usb_dev_dr_host)
-		platform_device_unregister(usb_dev_dr_host);
-	if (usb_dev_dr_client)
-		platform_device_unregister(usb_dev_dr_client);
-unreg_mph:
-	if (usb_dev_mph)
-		platform_device_unregister(usb_dev_mph);
-err:
-	return ret;
-}
-
-arch_initcall(fsl_usb_of_init);
-
-#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-static __be32 __iomem *rstcr;
-
-static int __init setup_rstcr(void)
-{
-	struct device_node *np;
-	np = of_find_node_by_name(NULL, "global-utilities");
-	if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) {
-		rstcr = of_iomap(np, 0) + 0xb0;
-		if (!rstcr)
-			printk (KERN_EMERG "Error: reset control register "
-					"not mapped!\n");
-	} else if (ppc_md.restart == fsl_rstcr_restart)
+	if (!rstcr && ppc_md.restart == fsl_rstcr_restart)
 		printk(KERN_ERR "No RSTCR register, warm reboot won't work\n");
 
 	if (np)
 		of_node_put(np);
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/Makefile linux-libre-2.6.37-gnu/arch/powerpc/sysdev/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,6 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS			+= -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)		:= -mno-minimal-toc
 
 mpic-msi-obj-$(CONFIG_PCI_MSI)	+= mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)		+= mpic.o $(mpic-msi-obj-y)
@@ -20,6 +18,7 @@
 obj-$(CONFIG_FSL_LBC)		+= fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)		+= fsl_gtm.o
 obj-$(CONFIG_MPC8xxx_GPIO)	+= mpc8xxx_gpio.o
+obj-$(CONFIG_FSL_85XX_CACHE_SRAM)	+= fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)	+= simple_gpio.o
 obj-$(CONFIG_RAPIDIO)		+= fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpc8xxx_gpio.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpc8xxx_gpio.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpc8xxx_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpc8xxx_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -330,6 +330,9 @@
 	for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
 		mpc8xxx_add_controller(np);
 
+	for_each_compatible_node(np, NULL, "fsl,qoriq-gpio")
+		mpc8xxx_add_controller(np);
+
 	return 0;
 }
 arch_initcall(mpc8xxx_add_gpiochips);
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpic_pasemi_msi.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpic_pasemi_msi.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpic_pasemi_msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpic_pasemi_msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,24 +39,24 @@
 static struct mpic *msi_mpic;
 
 
-static void mpic_pasemi_msi_mask_irq(unsigned int irq)
+static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
 {
-	pr_debug("mpic_pasemi_msi_mask_irq %d\n", irq);
-	mask_msi_irq(irq);
-	mpic_mask_irq(irq);
+	pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
+	mask_msi_irq(data);
+	mpic_mask_irq(data->irq);
 }
 
-static void mpic_pasemi_msi_unmask_irq(unsigned int irq)
+static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
 {
-	pr_debug("mpic_pasemi_msi_unmask_irq %d\n", irq);
-	mpic_unmask_irq(irq);
-	unmask_msi_irq(irq);
+	pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
+	mpic_unmask_irq(data->irq);
+	unmask_msi_irq(data);
 }
 
 static struct irq_chip mpic_pasemi_msi_chip = {
-	.shutdown	= mpic_pasemi_msi_mask_irq,
-	.mask		= mpic_pasemi_msi_mask_irq,
-	.unmask		= mpic_pasemi_msi_unmask_irq,
+	.irq_shutdown	= mpic_pasemi_msi_mask_irq,
+	.irq_mask	= mpic_pasemi_msi_mask_irq,
+	.irq_unmask	= mpic_pasemi_msi_unmask_irq,
 	.eoi		= mpic_end_irq,
 	.set_type	= mpic_set_irq_type,
 	.set_affinity	= mpic_set_affinity,
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpic_u3msi.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpic_u3msi.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/mpic_u3msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/mpic_u3msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,22 +23,22 @@
 /* A bit ugly, can we get this from the pci_dev somehow? */
 static struct mpic *msi_mpic;
 
-static void mpic_u3msi_mask_irq(unsigned int irq)
+static void mpic_u3msi_mask_irq(struct irq_data *data)
 {
-	mask_msi_irq(irq);
-	mpic_mask_irq(irq);
+	mask_msi_irq(data);
+	mpic_mask_irq(data->irq);
 }
 
-static void mpic_u3msi_unmask_irq(unsigned int irq)
+static void mpic_u3msi_unmask_irq(struct irq_data *data)
 {
-	mpic_unmask_irq(irq);
-	unmask_msi_irq(irq);
+	mpic_unmask_irq(data->irq);
+	unmask_msi_irq(data);
 }
 
 static struct irq_chip mpic_u3msi_chip = {
-	.shutdown	= mpic_u3msi_mask_irq,
-	.mask		= mpic_u3msi_mask_irq,
-	.unmask		= mpic_u3msi_unmask_irq,
+	.irq_shutdown	= mpic_u3msi_mask_irq,
+	.irq_mask	= mpic_u3msi_mask_irq,
+	.irq_unmask	= mpic_u3msi_unmask_irq,
 	.eoi		= mpic_end_irq,
 	.set_type	= mpic_set_irq_type,
 	.set_affinity	= mpic_set_affinity,
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/sysdev/pmi.c linux-libre-2.6.37-gnu/arch/powerpc/sysdev/pmi.c
--- linux-libre-2.6.36-gnu/arch/powerpc/sysdev/pmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/sysdev/pmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -114,7 +114,7 @@
 
 	spin_lock(&data->handler_spinlock);
 	list_for_each_entry(handler, &data->handler, node) {
-		pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
+		pr_debug("pmi: notifying handler %p\n", handler);
 		if (handler->type == data->msg.type)
 			handler->handle_pmi_message(data->msg);
 	}
diff -druN linux-libre-2.6.36-gnu/arch/powerpc/xmon/Makefile linux-libre-2.6.37-gnu/arch/powerpc/xmon/Makefile
--- linux-libre-2.6.36-gnu/arch/powerpc/xmon/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/powerpc/xmon/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,9 +4,7 @@
 
 GCOV_PROFILE := n
 
-ifdef CONFIG_PPC64
-EXTRA_CFLAGS += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
 
 obj-y			+= xmon.o start.o nonstdio.o
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/crypto/crypt_s390.h linux-libre-2.6.37-gnu/arch/s390/crypto/crypt_s390.h
--- linux-libre-2.6.36-gnu/arch/s390/crypto/crypt_s390.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/crypto/crypt_s390.h	2011-01-04 19:50:19.000000000 -0500
@@ -297,7 +297,7 @@
 	int ret;
 
 	/* check if CPACF facility (bit 17) is available */
-	if (!(stfl() & 1ULL << (31 - 17)))
+	if (!test_facility(17))
 		return 0;
 
 	switch (func & CRYPT_S390_OP_MASK) {
diff -druN linux-libre-2.6.36-gnu/arch/s390/crypto/prng.c linux-libre-2.6.37-gnu/arch/s390/crypto/prng.c
--- linux-libre-2.6.36-gnu/arch/s390/crypto/prng.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/crypto/prng.c	2011-01-04 19:50:19.000000000 -0500
@@ -152,6 +152,7 @@
 	.open		= &prng_open,
 	.release	= NULL,
 	.read		= &prng_read,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice prng_dev = {
diff -druN linux-libre-2.6.36-gnu/arch/s390/hypfs/hypfs_diag.c linux-libre-2.6.37-gnu/arch/s390/hypfs/hypfs_diag.c
--- linux-libre-2.6.36-gnu/arch/s390/hypfs/hypfs_diag.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/hypfs/hypfs_diag.c	2011-01-04 19:50:19.000000000 -0500
@@ -618,6 +618,7 @@
 	.open		= dbfs_d204_open,
 	.read		= dbfs_d204_read,
 	.release	= dbfs_d204_release,
+	.llseek		= no_llseek,
 };
 
 static int hypfs_dbfs_init(void)
@@ -637,18 +638,21 @@
 		pr_err("The hardware system does not support hypfs\n");
 		return -ENODATA;
 	}
-	rc = diag224_get_name_table();
-	if (rc) {
-		diag204_free_buffer();
-		pr_err("The hardware system does not provide all "
-		       "functions required by hypfs\n");
-	}
 	if (diag204_info_type == INFO_EXT) {
 		rc = hypfs_dbfs_init();
 		if (rc)
-			diag204_free_buffer();
+			return rc;
 	}
-	return rc;
+	if (MACHINE_IS_LPAR) {
+		rc = diag224_get_name_table();
+		if (rc) {
+			pr_err("The hardware system does not provide all "
+			       "functions required by hypfs\n");
+			debugfs_remove(dbfs_d204_file);
+			return rc;
+		}
+	}
+	return 0;
 }
 
 void hypfs_diag_exit(void)
diff -druN linux-libre-2.6.36-gnu/arch/s390/hypfs/hypfs_vm.c linux-libre-2.6.37-gnu/arch/s390/hypfs/hypfs_vm.c
--- linux-libre-2.6.36-gnu/arch/s390/hypfs/hypfs_vm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/hypfs/hypfs_vm.c	2011-01-04 19:50:19.000000000 -0500
@@ -275,6 +275,7 @@
 	.open		= dbfs_d2fc_open,
 	.read		= dbfs_d2fc_read,
 	.release	= dbfs_d2fc_release,
+	.llseek		= no_llseek,
 };
 
 int hypfs_vm_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/s390/hypfs/inode.c linux-libre-2.6.37-gnu/arch/s390/hypfs/inode.c
--- linux-libre-2.6.36-gnu/arch/s390/hypfs/inode.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/hypfs/inode.c	2011-01-04 19:50:19.000000000 -0500
@@ -316,10 +316,10 @@
 	return 0;
 }
 
-static int hypfs_get_super(struct file_system_type *fst, int flags,
-			const char *devname, void *data, struct vfsmount *mnt)
+static struct dentry *hypfs_mount(struct file_system_type *fst, int flags,
+			const char *devname, void *data)
 {
-	return get_sb_single(fst, flags, data, hypfs_fill_super, mnt);
+	return mount_single(fst, flags, data, hypfs_fill_super);
 }
 
 static void hypfs_kill_super(struct super_block *sb)
@@ -449,12 +449,13 @@
 	.write		= do_sync_write,
 	.aio_read	= hypfs_aio_read,
 	.aio_write	= hypfs_aio_write,
+	.llseek		= no_llseek,
 };
 
 static struct file_system_type hypfs_type = {
 	.owner		= THIS_MODULE,
 	.name		= "s390_hypfs",
-	.get_sb		= hypfs_get_super,
+	.mount		= hypfs_mount,
 	.kill_sb	= hypfs_kill_super
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/ccwdev.h linux-libre-2.6.37-gnu/arch/s390/include/asm/ccwdev.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/ccwdev.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/ccwdev.h	2011-01-04 19:50:19.000000000 -0500
@@ -92,6 +92,16 @@
 };
 
 /*
+ * Possible events used by the path_event notifier.
+ */
+#define PE_NONE				0x0
+#define PE_PATH_GONE			0x1 /* A path is no longer available. */
+#define PE_PATH_AVAILABLE		0x2 /* A path has become available and
+					       was successfully verified. */
+#define PE_PATHGROUP_ESTABLISHED	0x4 /* A pathgroup was reset and had
+					       to be established again. */
+
+/*
  * Possible CIO actions triggered by the unit check handler.
  */
 enum uc_todo {
@@ -109,6 +119,7 @@
  * @set_online: called when setting device online
  * @set_offline: called when setting device offline
  * @notify: notify driver of device state changes
+ * @path_event: notify driver of channel path events
  * @shutdown: called at device shutdown
  * @prepare: prepare for pm state transition
  * @complete: undo work done in @prepare
@@ -127,6 +138,7 @@
 	int (*set_online) (struct ccw_device *);
 	int (*set_offline) (struct ccw_device *);
 	int (*notify) (struct ccw_device *, int);
+	void (*path_event) (struct ccw_device *, int *);
 	void (*shutdown) (struct ccw_device *);
 	int (*prepare) (struct ccw_device *);
 	void (*complete) (struct ccw_device *);
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/cpu.h linux-libre-2.6.37-gnu/arch/s390/include/asm/cpu.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 	unsigned int ident   : 24;
 	unsigned int machine : 16;
 	unsigned int unused  : 16;
-} __packed;
+} __attribute__ ((packed, aligned(8)));
 
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_S390_CPU_H */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/cputime.h linux-libre-2.6.37-gnu/arch/s390/include/asm/cputime.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/cputime.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/cputime.h	2011-01-04 19:50:19.000000000 -0500
@@ -73,18 +73,18 @@
 }
 
 /*
- * Convert cputime to milliseconds and back.
+ * Convert cputime to microseconds and back.
  */
 static inline unsigned int
-cputime_to_msecs(const cputime_t cputime)
+cputime_to_usecs(const cputime_t cputime)
 {
-	return cputime_div(cputime, 4096000);
+	return cputime_div(cputime, 4096);
 }
 
 static inline cputime_t
-msecs_to_cputime(const unsigned int m)
+usecs_to_cputime(const unsigned int m)
 {
-	return (cputime_t) m * 4096000;
+	return (cputime_t) m * 4096;
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/dasd.h linux-libre-2.6.37-gnu/arch/s390/include/asm/dasd.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/dasd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/dasd.h	2011-01-04 19:50:19.000000000 -0500
@@ -217,6 +217,25 @@
 	int rssd_result_len;
 } __attribute__ ((packed)) dasd_symmio_parms_t;
 
+/*
+ * Data returned by Sense Path Group ID (SNID)
+ */
+struct dasd_snid_data {
+	struct {
+		__u8 group:2;
+		__u8 reserve:2;
+		__u8 mode:1;
+		__u8 res:3;
+	} __attribute__ ((packed)) path_state;
+	__u8 pgid[11];
+} __attribute__ ((packed));
+
+struct dasd_snid_ioctl_data {
+	struct dasd_snid_data data;
+	__u8 path_mask;
+} __attribute__ ((packed));
+
+
 /********************************************************************************
  * SECTION: Definition of IOCTLs
  *
@@ -261,25 +280,10 @@
 /* Set Attributes (cache operations) */
 #define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
 
+/* Get Sense Path Group ID (SNID) data */
+#define BIODASDSNID    _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
+
 #define BIODASDSYMMIO  _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t)
 
 #endif				/* DASD_H */
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/hardirq.h linux-libre-2.6.37-gnu/arch/s390/include/asm/hardirq.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/hardirq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/hardirq.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,10 +12,6 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/cache.h>
-#include <linux/interrupt.h>
 #include <asm/lowcore.h>
 
 #define local_softirq_pending() (S390_lowcore.softirq_pending)
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/hugetlb.h linux-libre-2.6.37-gnu/arch/s390/include/asm/hugetlb.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/hugetlb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/hugetlb.h	2011-01-04 19:50:19.000000000 -0500
@@ -37,32 +37,6 @@
 int arch_prepare_hugepage(struct page *page);
 void arch_release_hugepage(struct page *page);
 
-static inline pte_t pte_mkhuge(pte_t pte)
-{
-	/*
-	 * PROT_NONE needs to be remapped from the pte type to the ste type.
-	 * The HW invalid bit is also different for pte and ste. The pte
-	 * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
-	 * bit, so we don't have to clear it.
-	 */
-	if (pte_val(pte) & _PAGE_INVALID) {
-		if (pte_val(pte) & _PAGE_SWT)
-			pte_val(pte) |= _HPAGE_TYPE_NONE;
-		pte_val(pte) |= _SEGMENT_ENTRY_INV;
-	}
-	/*
-	 * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
-	 * table entry.
-	 */
-	pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
-	/*
-	 * Also set the change-override bit because we don't need dirty bit
-	 * tracking for hugetlbfs pages.
-	 */
-	pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
-	return pte;
-}
-
 static inline pte_t huge_pte_wrprotect(pte_t pte)
 {
 	pte_val(pte) |= _PAGE_RO;
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/ioctls.h linux-libre-2.6.37-gnu/arch/s390/include/asm/ioctls.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/ioctls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/ioctls.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,94 +1,8 @@
-/*
- *  include/asm-s390/ioctls.h
- *
- *  S390 version
- *
- *  Derived from "include/asm-i386/ioctls.h"
- */
-
 #ifndef __ARCH_S390_IOCTLS_H__
 #define __ARCH_S390_IOCTLS_H__
 
-#include <asm/ioctl.h>
-
-/* 0x54 is just a magic number to make these relatively unique ('T') */
-
-#define TCGETS		0x5401
-#define TCSETS		0x5402
-#define TCSETSW		0x5403
-#define TCSETSF		0x5404
-#define TCGETA		0x5405
-#define TCSETA		0x5406
-#define TCSETAW		0x5407
-#define TCSETAF		0x5408
-#define TCSBRK		0x5409
-#define TCXONC		0x540A
-#define TCFLSH		0x540B
-#define TIOCEXCL	0x540C
-#define TIOCNXCL	0x540D
-#define TIOCSCTTY	0x540E
-#define TIOCGPGRP	0x540F
-#define TIOCSPGRP	0x5410
-#define TIOCOUTQ	0x5411
-#define TIOCSTI		0x5412
-#define TIOCGWINSZ	0x5413
-#define TIOCSWINSZ	0x5414
-#define TIOCMGET	0x5415
-#define TIOCMBIS	0x5416
-#define TIOCMBIC	0x5417
-#define TIOCMSET	0x5418
-#define TIOCGSOFTCAR	0x5419
-#define TIOCSSOFTCAR	0x541A
-#define FIONREAD	0x541B
-#define TIOCINQ		FIONREAD
-#define TIOCLINUX	0x541C
-#define TIOCCONS	0x541D
-#define TIOCGSERIAL	0x541E
-#define TIOCSSERIAL	0x541F
-#define TIOCPKT		0x5420
-#define FIONBIO		0x5421
-#define TIOCNOTTY	0x5422
-#define TIOCSETD	0x5423
-#define TIOCGETD	0x5424
-#define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
-#define TIOCSBRK	0x5427  /* BSD compatibility */
-#define TIOCCBRK	0x5428  /* BSD compatibility */
-#define TIOCGSID	0x5429  /* Return the session ID of FD */
-#define TCGETS2		_IOR('T',0x2A, struct termios2)
-#define TCSETS2		_IOW('T',0x2B, struct termios2)
-#define TCSETSW2	_IOW('T',0x2C, struct termios2)
-#define TCSETSF2	_IOW('T',0x2D, struct termios2)
-#define TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-#define TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
-#define TIOCSIG		_IOW('T',0x36, int)  /* Generate signal on Pty slave */
-
-#define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
-#define FIOCLEX		0x5451
-#define FIOASYNC	0x5452
-#define TIOCSERCONFIG	0x5453
-#define TIOCSERGWILD	0x5454
-#define TIOCSERSWILD	0x5455
-#define TIOCGLCKTRMIOS	0x5456
-#define TIOCSLCKTRMIOS	0x5457
-#define TIOCSERGSTRUCT	0x5458 /* For debugging only */
-#define TIOCSERGETLSR   0x5459 /* Get line status register */
-#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-
-#define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
-#define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
 
-/* Used for packet mode */
-#define TIOCPKT_DATA		 0
-#define TIOCPKT_FLUSHREAD	 1
-#define TIOCPKT_FLUSHWRITE	 2
-#define TIOCPKT_STOP		 4
-#define TIOCPKT_START		 8
-#define TIOCPKT_NOSTOP		16
-#define TIOCPKT_DOSTOP		32
-#define TIOCPKT_IOCTL		64
-
-#define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#include <asm-generic/ioctls.h>
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/s390/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,8 +8,8 @@
 
 #include <linux/types.h>
 
-/* store then or system mask. */
-#define __raw_local_irq_stosm(__or)					\
+/* store then OR system mask. */
+#define __arch_local_irq_stosm(__or)					\
 ({									\
 	unsigned long __mask;						\
 	asm volatile(							\
@@ -18,8 +18,8 @@
 	__mask;								\
 })
 
-/* store then and system mask. */
-#define __raw_local_irq_stnsm(__and)					\
+/* store then AND system mask. */
+#define __arch_local_irq_stnsm(__and)					\
 ({									\
 	unsigned long __mask;						\
 	asm volatile(							\
@@ -29,39 +29,44 @@
 })
 
 /* set system mask. */
-#define __raw_local_irq_ssm(__mask)					\
-({									\
-	asm volatile("ssm   %0" : : "Q" (__mask) : "memory");		\
-})
+static inline void __arch_local_irq_ssm(unsigned long flags)
+{
+	asm volatile("ssm   %0" : : "Q" (flags) : "memory");
+}
 
-/* interrupt control.. */
-static inline unsigned long raw_local_irq_enable(void)
+static inline unsigned long arch_local_save_flags(void)
 {
-	return __raw_local_irq_stosm(0x03);
+	return __arch_local_irq_stosm(0x00);
 }
 
-static inline unsigned long raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-	return __raw_local_irq_stnsm(0xfc);
+	return __arch_local_irq_stnsm(0xfc);
 }
 
-#define raw_local_save_flags(x)						\
-do {									\
-	typecheck(unsigned long, x);					\
-	(x) = __raw_local_irq_stosm(0x00);				\
-} while (0)
+static inline void arch_local_irq_disable(void)
+{
+	arch_local_irq_save();
+}
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_enable(void)
 {
-	__raw_local_irq_ssm(flags);
+	__arch_local_irq_stosm(0x03);
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	__arch_local_irq_ssm(flags);
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
 	return !(flags & (3UL << (BITS_PER_LONG - 8)));
 }
 
-/* For spinlocks etc */
-#define raw_local_irq_save(x)	((x) = raw_local_irq_disable())
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #endif /* __ASM_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/Kbuild linux-libre-2.6.37-gnu/arch/s390/include/asm/Kbuild
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,7 @@
 header-y += cmb.h
 header-y += dasd.h
 header-y += debug.h
+header-y += kvm_virtio.h
 header-y += monwriter.h
 header-y += qeth.h
 header-y += schid.h
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/kvm_virtio.h linux-libre-2.6.37-gnu/arch/s390/include/asm/kvm_virtio.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/kvm_virtio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/kvm_virtio.h	2011-01-04 19:50:19.000000000 -0500
@@ -54,4 +54,11 @@
  * This is pagesize for historical reasons. */
 #define KVM_S390_VIRTIO_RING_ALIGN	4096
 
+
+/* These values are supposed to be in ext_params on an interrupt */
+#define VIRTIO_PARAM_MASK		0xff
+#define VIRTIO_PARAM_VRING_INTERRUPT	0x0
+#define VIRTIO_PARAM_CONFIG_CHANGED	0x1
+#define VIRTIO_PARAM_DEV_ADD		0x2
+
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/lowcore.h linux-libre-2.6.37-gnu/arch/s390/include/asm/lowcore.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/lowcore.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/lowcore.h	2011-01-04 19:50:19.000000000 -0500
@@ -150,9 +150,10 @@
 	 */
 	__u32	ipib;				/* 0x0e00 */
 	__u32	ipib_checksum;			/* 0x0e04 */
+	__u8	pad_0x0e08[0x0f00-0x0e08];	/* 0x0e08 */
 
-	/* Align to the top 1k of prefix area */
-	__u8	pad_0x0e08[0x1000-0x0e08];	/* 0x0e08 */
+	/* Extended facility list */
+	__u64	stfle_fac_list[32];		/* 0x0f00 */
 } __packed;
 
 #else /* CONFIG_32BIT */
@@ -285,7 +286,11 @@
 	 */
 	__u64	ipib;				/* 0x0e00 */
 	__u32	ipib_checksum;			/* 0x0e08 */
-	__u8	pad_0x0e0c[0x11b8-0x0e0c];	/* 0x0e0c */
+	__u8	pad_0x0e0c[0x0f00-0x0e0c];	/* 0x0e0c */
+
+	/* Extended facility list */
+	__u64	stfle_fac_list[32];		/* 0x0f00 */
+	__u8	pad_0x1000[0x11b8-0x1000];	/* 0x1000 */
 
 	/* 64 bit extparam used for pfault/diag 250: defined by architecture */
 	__u64	ext_params2;			/* 0x11B8 */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/page.h linux-libre-2.6.37-gnu/arch/s390/include/asm/page.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/page.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/page.h	2011-01-04 19:50:19.000000000 -0500
@@ -108,9 +108,13 @@
 #define __pgprot(x)     ((pgprot_t) { (x) } )
 
 static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey)
+page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
 {
-	asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
+	if (!mapped)
+		asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
+			     : : "d" (skey), "a" (addr));
+	else
+		asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
 }
 
 static inline unsigned int
@@ -126,6 +130,11 @@
 void arch_free_page(struct page *page, int order);
 void arch_alloc_page(struct page *page, int order);
 
+static inline int devmem_is_allowed(unsigned long pfn)
+{
+	return 0;
+}
+
 #define HAVE_ARCH_FREE_PAGE
 #define HAVE_ARCH_ALLOC_PAGE
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/s390/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
  * Copyright 2009 Martin Schwidefsky, IBM Corporation.
  */
 
-static inline void set_perf_event_pending(void) {}
-static inline void clear_perf_event_pending(void) {}
+/* Empty, just to avoid compiling error */
 
 #define PERF_EVENT_INDEX_OFFSET 0
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/pgalloc.h linux-libre-2.6.37-gnu/arch/s390/include/asm/pgalloc.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/pgalloc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/pgalloc.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,9 +21,11 @@
 
 unsigned long *crst_table_alloc(struct mm_struct *, int);
 void crst_table_free(struct mm_struct *, unsigned long *);
+void crst_table_free_rcu(struct mm_struct *, unsigned long *);
 
 unsigned long *page_table_alloc(struct mm_struct *);
 void page_table_free(struct mm_struct *, unsigned long *);
+void page_table_free_rcu(struct mm_struct *, unsigned long *);
 void disable_noexec(struct mm_struct *, struct task_struct *);
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
@@ -176,4 +178,6 @@
 #define pte_free_kernel(mm, pte) page_table_free(mm, (unsigned long *) pte)
 #define pte_free(mm, pte) page_table_free(mm, (unsigned long *) pte)
 
+extern void rcu_table_freelist_finish(void);
+
 #endif /* _S390_PGALLOC_H */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/s390/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,7 @@
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
 extern void vmem_map_init(void);
+extern void fault_init(void);
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
@@ -46,11 +47,27 @@
 #define update_mmu_cache(vma, address, ptep)     do { } while (0)
 
 /*
- * ZERO_PAGE is a global shared page that is always zero: used
+ * ZERO_PAGE is a global shared page that is always zero; used
  * for zero-mapped memory areas etc..
  */
-extern char empty_zero_page[PAGE_SIZE];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern unsigned long empty_zero_page;
+extern unsigned long zero_page_mask;
+
+#define ZERO_PAGE(vaddr) \
+	(virt_to_page((void *)(empty_zero_page + \
+	 (((unsigned long)(vaddr)) &zero_page_mask))))
+
+#define is_zero_pfn is_zero_pfn
+static inline int is_zero_pfn(unsigned long pfn)
+{
+	extern unsigned long zero_pfn;
+	unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+	return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+#define my_zero_pfn(addr)	page_to_pfn(ZERO_PAGE(addr))
+
 #endif /* !__ASSEMBLY__ */
 
 /*
@@ -300,6 +317,7 @@
 
 /* Bits in the segment table entry */
 #define _SEGMENT_ENTRY_ORIGIN	0x7fffffc0UL	/* page table origin	    */
+#define _SEGMENT_ENTRY_RO	0x200	/* page protection bit		    */
 #define _SEGMENT_ENTRY_INV	0x20	/* invalid segment table entry	    */
 #define _SEGMENT_ENTRY_COMMON	0x10	/* common segment bit		    */
 #define _SEGMENT_ENTRY_PTL	0x0f	/* page table length		    */
@@ -572,7 +590,7 @@
 }
 
 /* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page);
+static inline void page_clear_dirty(struct page *page, int mapped);
 #include <linux/page-flags.h>
 
 static inline void ptep_rcp_copy(pte_t *ptep)
@@ -754,6 +772,34 @@
 	return pte;
 }
 
+#ifdef CONFIG_HUGETLB_PAGE
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+	/*
+	 * PROT_NONE needs to be remapped from the pte type to the ste type.
+	 * The HW invalid bit is also different for pte and ste. The pte
+	 * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
+	 * bit, so we don't have to clear it.
+	 */
+	if (pte_val(pte) & _PAGE_INVALID) {
+		if (pte_val(pte) & _PAGE_SWT)
+			pte_val(pte) |= _HPAGE_TYPE_NONE;
+		pte_val(pte) |= _SEGMENT_ENTRY_INV;
+	}
+	/*
+	 * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
+	 * table entry.
+	 */
+	pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
+	/*
+	 * Also set the change-override bit because we don't need dirty bit
+	 * tracking for hugetlbfs pages.
+	 */
+	pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+	return pte;
+}
+#endif
+
 #ifdef CONFIG_PGSTE
 /*
  * Get (and clear) the user dirty bit for a PTE.
@@ -782,7 +828,7 @@
 	}
 	dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
 	if (skey & _PAGE_CHANGED)
-		page_clear_dirty(page);
+		page_clear_dirty(page, 1);
 	rcp_unlock(ptep);
 	return dirty;
 }
@@ -957,9 +1003,9 @@
 }
 
 #define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page)
+static inline void page_clear_dirty(struct page *page, int mapped)
 {
-	page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY);
+	page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
 }
 
 /*
@@ -1048,9 +1094,7 @@
 #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr))
 #define pte_offset_kernel(pmd, address) pte_offset(pmd,address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
-#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 /*
  * 31 bit swap entry format:
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/processor.h linux-libre-2.6.37-gnu/arch/s390/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -82,8 +82,6 @@
         unsigned long prot_addr;        /* address of protection-excep.     */
         unsigned int trap_no;
         per_struct per_info;
-	/* Used to give failing instruction back to user for ieee exceptions */
-	unsigned long ieee_instruction_pointer; 
         /* pfault_wait is used to block the process on a pfault event */
 	unsigned long pfault_wait;
 };
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/s390/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -481,8 +481,7 @@
 	 * watchpoints. This is the way intel does it.
 	 */
 	per_struct per_info;
-	unsigned long ieee_instruction_pointer; 
-	/* Used to give failing instruction back to user for ieee exceptions */
+	unsigned long ieee_instruction_pointer;	/* obsolete, always 0 */
 };
 
 #ifdef __KERNEL__
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/qdio.h linux-libre-2.6.37-gnu/arch/s390/include/asm/qdio.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/qdio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/qdio.h	2011-01-04 19:50:19.000000000 -0500
@@ -360,6 +360,7 @@
 	unsigned int no_output_qs;
 	qdio_handler_t *input_handler;
 	qdio_handler_t *output_handler;
+	void (*queue_start_poll) (struct ccw_device *, int, unsigned long);
 	unsigned long int_parm;
 	void **input_sbal_addr_array;
 	void **output_sbal_addr_array;
@@ -377,11 +378,13 @@
 extern int qdio_allocate(struct qdio_initialize *);
 extern int qdio_establish(struct qdio_initialize *);
 extern int qdio_activate(struct ccw_device *);
-
-extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags,
-		   int q_nr, unsigned int bufnr, unsigned int count);
-extern int qdio_shutdown(struct ccw_device*, int);
+extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
+		   unsigned int);
+extern int qdio_start_irq(struct ccw_device *, int);
+extern int qdio_stop_irq(struct ccw_device *, int);
+extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
+extern int qdio_shutdown(struct ccw_device *, int);
 extern int qdio_free(struct ccw_device *);
-extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*);
+extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
 
 #endif /* __QDIO_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/s390_ext.h linux-libre-2.6.37-gnu/arch/s390/include/asm/s390_ext.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/s390_ext.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/s390_ext.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
 
 #include <linux/types.h>
 
-typedef void (*ext_int_handler_t)(__u16 code);
+typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
 
 typedef struct ext_int_info_t {
 	struct ext_int_info_t *next;
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/scatterlist.h linux-libre-2.6.37-gnu/arch/s390/include/asm/scatterlist.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/scatterlist.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/scatterlist.h	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1,3 @@
 #include <asm-generic/scatterlist.h>
+
+#define ARCH_HAS_SG_CHAIN
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/setup.h linux-libre-2.6.37-gnu/arch/s390/include/asm/setup.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/setup.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/setup.h	2011-01-04 19:50:19.000000000 -0500
@@ -73,6 +73,7 @@
 #define MACHINE_FLAG_PFMF	(1UL << 11)
 #define MACHINE_FLAG_LPAR	(1UL << 12)
 #define MACHINE_FLAG_SPP	(1UL << 13)
+#define MACHINE_FLAG_TOPOLOGY	(1UL << 14)
 
 #define MACHINE_IS_VM		(S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM		(S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -90,6 +91,7 @@
 #define MACHINE_HAS_HPAGE	(0)
 #define MACHINE_HAS_PFMF	(0)
 #define MACHINE_HAS_SPP		(0)
+#define MACHINE_HAS_TOPOLOGY	(0)
 #else /* __s390x__ */
 #define MACHINE_HAS_IEEE	(1)
 #define MACHINE_HAS_CSP		(1)
@@ -100,6 +102,7 @@
 #define MACHINE_HAS_HPAGE	(S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE)
 #define MACHINE_HAS_PFMF	(S390_lowcore.machine_flags & MACHINE_FLAG_PFMF)
 #define MACHINE_HAS_SPP		(S390_lowcore.machine_flags & MACHINE_FLAG_SPP)
+#define MACHINE_HAS_TOPOLOGY	(S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
 #endif /* __s390x__ */
 
 #define ZFCPDUMP_HSA_SIZE	(32UL<<20)
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/syscall.h linux-libre-2.6.37-gnu/arch/s390/include/asm/syscall.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/syscall.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/syscall.h	2011-01-04 19:50:19.000000000 -0500
@@ -65,8 +65,6 @@
 	if (test_tsk_thread_flag(task, TIF_31BIT))
 		mask = 0xffffffff;
 #endif
-	if (i + n == 6)
-		args[--n] = regs->args[0] & mask;
 	while (n-- > 0)
 		if (i + n > 0)
 			args[n] = regs->gprs[2 + i + n] & mask;
@@ -80,8 +78,6 @@
 					 const unsigned long *args)
 {
 	BUG_ON(i + n > 6);
-	if (i + n == 6)
-		regs->args[0] = args[--n];
 	while (n-- > 0)
 		if (i + n > 0)
 			regs->gprs[2 + i + n] = args[n];
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/sysinfo.h linux-libre-2.6.37-gnu/arch/s390/include/asm/sysinfo.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/sysinfo.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/sysinfo.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,8 +14,13 @@
 #ifndef __ASM_S390_SYSINFO_H
 #define __ASM_S390_SYSINFO_H
 
+#include <asm/bitsperlong.h>
+
 struct sysinfo_1_1_1 {
-	char reserved_0[32];
+	unsigned short :16;
+	unsigned char ccr;
+	unsigned char cai;
+	char reserved_0[28];
 	char manufacturer[16];
 	char type[4];
 	char reserved_1[12];
@@ -104,6 +109,39 @@
 	char reserved_544[3552];
 };
 
+#define TOPOLOGY_CPU_BITS	64
+#define TOPOLOGY_NR_MAG		6
+
+struct topology_cpu {
+	unsigned char reserved0[4];
+	unsigned char :6;
+	unsigned char pp:2;
+	unsigned char reserved1;
+	unsigned short origin;
+	unsigned long mask[TOPOLOGY_CPU_BITS / BITS_PER_LONG];
+};
+
+struct topology_container {
+	unsigned char reserved[7];
+	unsigned char id;
+};
+
+union topology_entry {
+	unsigned char nl;
+	struct topology_cpu cpu;
+	struct topology_container container;
+};
+
+struct sysinfo_15_1_x {
+	unsigned char reserved0[2];
+	unsigned short length;
+	unsigned char mag[TOPOLOGY_NR_MAG];
+	unsigned char reserved1;
+	unsigned char mnest;
+	unsigned char reserved2[4];
+	union topology_entry tle[0];
+};
+
 static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
 {
 	register int r0 asm("0") = (fc << 28) | sel1;
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/system.h linux-libre-2.6.37-gnu/arch/s390/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -85,19 +85,20 @@
 	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
 }
 
-#define switch_to(prev,next,last) do {					     \
-	if (prev == next)						     \
-		break;							     \
-	save_fp_regs(&prev->thread.fp_regs);				     \
-	restore_fp_regs(&next->thread.fp_regs);				     \
-	save_access_regs(&prev->thread.acrs[0]);			     \
-	restore_access_regs(&next->thread.acrs[0]);			     \
-	prev = __switch_to(prev,next);					     \
+#define switch_to(prev,next,last) do {					\
+	if (prev->mm) {							\
+		save_fp_regs(&prev->thread.fp_regs);			\
+		save_access_regs(&prev->thread.acrs[0]);		\
+	}								\
+	if (next->mm) {							\
+		restore_fp_regs(&next->thread.fp_regs);			\
+		restore_access_regs(&next->thread.acrs[0]);		\
+	}								\
+	prev = __switch_to(prev,next);					\
 } while (0)
 
 extern void account_vtime(struct task_struct *, struct task_struct *);
 extern void account_tick_vtime(struct task_struct *);
-extern void account_system_vtime(struct task_struct *);
 
 #ifdef CONFIG_PFAULT
 extern void pfault_irq_init(void);
@@ -399,7 +400,7 @@
 static inline void
 __set_psw_mask(unsigned long mask)
 {
-	__load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
+	__load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
 }
 
 #define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
@@ -419,30 +420,21 @@
 
 #endif /* CONFIG_SMP */
 
-static inline unsigned int stfl(void)
-{
-	asm volatile(
-		"	.insn	s,0xb2b10000,0(0)\n" /* stfl */
-		"0:\n"
-		EX_TABLE(0b,0b));
-	return S390_lowcore.stfl_fac_list;
-}
+#define MAX_FACILITY_BIT (256*8)	/* stfle_fac_list has 256 bytes */
 
-static inline int __stfle(unsigned long long *list, int doublewords)
+/*
+ * The test_facility function uses the bit odering where the MSB is bit 0.
+ * That makes it easier to query facility bits with the bit number as
+ * documented in the Principles of Operation.
+ */
+static inline int test_facility(unsigned long nr)
 {
-	typedef struct { unsigned long long _[doublewords]; } addrtype;
-	register unsigned long __nr asm("0") = doublewords - 1;
-
-	asm volatile(".insn s,0xb2b00000,%0" /* stfle */
-		     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
-	return __nr + 1;
-}
+	unsigned char *ptr;
 
-static inline int stfle(unsigned long long *list, int doublewords)
-{
-	if (!(stfl() & (1UL << 24)))
-		return -EOPNOTSUPP;
-	return __stfle(list, doublewords);
+	if (nr >= MAX_FACILITY_BIT)
+		return 0;
+	ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
+	return (*ptr & (0x80 >> (nr & 7))) != 0;
 }
 
 static inline unsigned short stap(void)
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/tlb.h linux-libre-2.6.37-gnu/arch/s390/include/asm/tlb.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/tlb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/tlb.h	2011-01-04 19:50:19.000000000 -0500
@@ -64,10 +64,9 @@
 	if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
 		__tlb_flush_mm(tlb->mm);
 	while (tlb->nr_ptes > 0)
-		pte_free(tlb->mm, tlb->array[--tlb->nr_ptes]);
+		page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
 	while (tlb->nr_pxds < TLB_NR_PTRS)
-		/* pgd_free frees the pointer as region or segment table */
-		pgd_free(tlb->mm, tlb->array[tlb->nr_pxds++]);
+		crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
@@ -75,6 +74,8 @@
 {
 	tlb_flush_mmu(tlb, start, end);
 
+	rcu_table_freelist_finish();
+
 	/* keep the page table cache within bounds */
 	check_pgt_cache();
 
@@ -103,7 +104,7 @@
 		if (tlb->nr_ptes >= tlb->nr_pxds)
 			tlb_flush_mmu(tlb, 0, 0);
 	} else
-		pte_free(tlb->mm, pte);
+		page_table_free(tlb->mm, (unsigned long *) pte);
 }
 
 /*
@@ -124,7 +125,7 @@
 		if (tlb->nr_ptes >= tlb->nr_pxds)
 			tlb_flush_mmu(tlb, 0, 0);
 	} else
-		pmd_free(tlb->mm, pmd);
+		crst_table_free(tlb->mm, (unsigned long *) pmd);
 #endif
 }
 
@@ -146,7 +147,7 @@
 		if (tlb->nr_ptes >= tlb->nr_pxds)
 			tlb_flush_mmu(tlb, 0, 0);
 	} else
-		pud_free(tlb->mm, pud);
+		crst_table_free(tlb->mm, (unsigned long *) pud);
 #endif
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/include/asm/topology.h linux-libre-2.6.37-gnu/arch/s390/include/asm/topology.h
--- linux-libre-2.6.36-gnu/arch/s390/include/asm/topology.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/include/asm/topology.h	2011-01-04 19:50:19.000000000 -0500
@@ -2,19 +2,38 @@
 #define _ASM_S390_TOPOLOGY_H
 
 #include <linux/cpumask.h>
-
-#define mc_capable()	(1)
-
-const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+#include <asm/sysinfo.h>
 
 extern unsigned char cpu_core_id[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
 
+static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+	return &cpu_core_map[cpu];
+}
+
 #define topology_core_id(cpu)		(cpu_core_id[cpu])
 #define topology_core_cpumask(cpu)	(&cpu_core_map[cpu])
+#define mc_capable()			(1)
+
+#ifdef CONFIG_SCHED_BOOK
+
+extern unsigned char cpu_book_id[NR_CPUS];
+extern cpumask_t cpu_book_map[NR_CPUS];
+
+static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
+{
+	return &cpu_book_map[cpu];
+}
+
+#define topology_book_id(cpu)		(cpu_book_id[cpu])
+#define topology_book_cpumask(cpu)	(&cpu_book_map[cpu])
+
+#endif /* CONFIG_SCHED_BOOK */
 
 int topology_set_cpu_management(int fc);
 void topology_schedule_update(void);
+void store_topology(struct sysinfo_15_1_x *info);
 
 #define POLARIZATION_UNKNWN	(-1)
 #define POLARIZATION_HRZ	(0)
@@ -30,6 +49,8 @@
 };
 #endif
 
+#define SD_BOOK_INIT	SD_CPU_INIT
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_S390_TOPOLOGY_H */
diff -druN linux-libre-2.6.36-gnu/arch/s390/Kbuild linux-libre-2.6.37-gnu/arch/s390/Kbuild
--- linux-libre-2.6.36-gnu/arch/s390/Kbuild	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/s390/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,6 @@
+obj-y += kernel/
+obj-y += mm/
+obj-y += crypto/
+obj-y += appldata/
+obj-y += hypfs/
+obj-y += kvm/
diff -druN linux-libre-2.6.36-gnu/arch/s390/Kconfig linux-libre-2.6.37-gnu/arch/s390/Kconfig
--- linux-libre-2.6.36-gnu/arch/s390/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
 config SCHED_MC
 	def_bool y
 	depends on SMP
@@ -60,6 +55,9 @@
 config NO_DMA
 	def_bool y
 
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool 64BIT
+
 config GENERIC_LOCKBREAK
 	bool
 	default y
@@ -75,8 +73,6 @@
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 	def_bool y
 
-mainmenu "Linux Kernel Configuration"
-
 config S390
 	def_bool y
 	select USE_GENERIC_SMP_HELPERS if SMP
@@ -84,6 +80,7 @@
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
 	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_C_RECORDMCOUNT
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FUNCTION_GRAPH_TRACER
@@ -95,11 +92,13 @@
 	select HAVE_KVM if 64BIT
 	select HAVE_ARCH_TRACEHOOK
 	select INIT_ALL_POSSIBLE
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select HAVE_KERNEL_GZIP
 	select HAVE_KERNEL_BZIP2
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
+	select HAVE_GET_USER_PAGES_FAST
 	select ARCH_INLINE_SPIN_TRYLOCK
 	select ARCH_INLINE_SPIN_TRYLOCK_BH
 	select ARCH_INLINE_SPIN_LOCK
@@ -146,7 +145,7 @@
 config 64BIT
 	bool "64 bit kernel"
 	help
-	  Select this option if you have a 64 bit IBM zSeries machine
+	  Select this option if you have an IBM z/Architecture machine
 	  and want to use the 64 bit addressing mode.
 
 config 32BIT
@@ -198,12 +197,28 @@
 	  can be controlled through /sys/devices/system/cpu/cpu#.
 	  Say N if you want to disable CPU hotplug.
 
+config SCHED_MC
+	def_bool y
+	prompt "Multi-core scheduler support"
+	depends on SMP
+	help
+	  Multi-core scheduler support improves the CPU scheduler's decision
+	  making when dealing with multi-core CPU chips at a cost of slightly
+	  increased overhead in some places.
+
+config SCHED_BOOK
+	bool "Book scheduler support"
+	depends on SMP && SCHED_MC
+	help
+	  Book scheduler support improves the CPU scheduler's decision making
+	  when dealing with machines that have several books.
+
 config MATHEMU
 	bool "IEEE FPU emulation"
 	depends on MARCH_G5
 	help
 	  This option is required for IEEE compliant floating point arithmetic
-	  on older S/390 machines. Say Y unless you know your machine doesn't
+	  on older ESA/390 machines. Say Y unless you know your machine doesn't
 	  need this.
 
 config COMPAT
@@ -232,8 +247,8 @@
 	  space programs and it also selects the addressing mode option above.
 	  The kernel parameter noexec=on will enable this feature and also
 	  switch the addressing modes, default is disabled. Enabling this (via
-	  kernel parameter) on machines earlier than IBM System z9-109 EC/BC
-	  will reduce system performance.
+	  kernel parameter) on machines earlier than IBM System z9 this will
+	  reduce system performance.
 
 comment "Code generation options"
 
@@ -242,41 +257,46 @@
 	default MARCH_G5
 
 config MARCH_G5
-	bool "S/390 model G5 and G6"
+	bool "System/390 model G5 and G6"
 	depends on !64BIT
 	help
 	  Select this to build a 31 bit kernel that works
-	  on all S/390 and zSeries machines.
+	  on all ESA/390 and z/Architecture machines.
 
 config MARCH_Z900
-	bool "IBM eServer zSeries model z800 and z900"
+	bool "IBM zSeries model z800 and z900"
 	help
-	  Select this to optimize for zSeries machines. This
-	  will enable some optimizations that are not available
-	  on older 31 bit only CPUs.
+	  Select this to enable optimizations for model z800/z900 (2064 and
+	  2066 series). This will enable some optimizations that are not
+	  available on older ESA/390 (31 Bit) only CPUs.
 
 config MARCH_Z990
-	bool "IBM eServer zSeries model z890 and z990"
+	bool "IBM zSeries model z890 and z990"
 	help
-	  Select this enable optimizations for model z890/z990.
-	  This will be slightly faster but does not work on
-	  older machines such as the z900.
+	  Select this to enable optimizations for model z890/z990 (2084 and
+	  2086 series). The kernel will be slightly faster but will not work
+	  on older machines.
 
 config MARCH_Z9_109
 	bool "IBM System z9"
 	help
-	  Select this to enable optimizations for IBM System z9-109, IBM
-	  System z9 Enterprise Class (z9 EC), and IBM System z9 Business
-	  Class (z9 BC). The kernel will be slightly faster but will not
-	  work on older machines such as the z990, z890, z900, and z800.
+	  Select this to enable optimizations for IBM System z9 (2094 and
+	  2096 series). The kernel will be slightly faster but will not work
+	  on older machines.
 
 config MARCH_Z10
 	bool "IBM System z10"
 	help
-	  Select this to enable optimizations for IBM System z10. The
-	  kernel will be slightly faster but will not work on older
-	  machines such as the z990, z890, z900, z800, z9-109, z9-ec
-	  and z9-bc.
+	  Select this to enable optimizations for IBM System z10 (2097 and
+	  2098 series). The kernel will be slightly faster but will not work
+	  on older machines.
+
+config MARCH_Z196
+	bool "IBM zEnterprise 196"
+	help
+	  Select this to enable optimizations for IBM zEnterprise 196
+	  (2817 series). The kernel will be slightly faster but will not work
+	  on older machines.
 
 endchoice
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/Kconfig.debug linux-libre-2.6.37-gnu/arch/s390/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/s390/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -6,6 +6,18 @@
 
 source "lib/Kconfig.debug"
 
+config STRICT_DEVMEM
+	def_bool y
+	prompt "Filter access to /dev/mem"
+	---help---
+	  This option restricts access to /dev/mem.  If this option is
+	  disabled, you allow userspace access to all memory, including
+	  kernel and userspace memory. Accidental memory access is likely
+	  to be disastrous.
+	  Memory access is required for experts who want to debug the kernel.
+
+	  If you are unsure, say Y.
+
 config DEBUG_STRICT_USER_COPY_CHECKS
 	bool "Strict user copy size checks"
 	---help---
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/asm-offsets.c linux-libre-2.6.37-gnu/arch/s390/kernel/asm-offsets.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/asm-offsets.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/asm-offsets.c	2011-01-04 19:50:19.000000000 -0500
@@ -66,9 +66,9 @@
 	DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base));
 	DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time));
 	/* constants used by the vdso */
-	DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
-	DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
-	DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
+	DEFINE(__CLOCK_REALTIME, CLOCK_REALTIME);
+	DEFINE(__CLOCK_MONOTONIC, CLOCK_MONOTONIC);
+	DEFINE(__CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC);
 	BLANK();
 	/* constants for SIGP */
 	DEFINE(__SIGP_STOP, sigp_stop);
@@ -84,6 +84,7 @@
 	DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code));
 	DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc));
 	DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code));
+	DEFINE(__LC_TRANS_EXC_CODE, offsetof(struct _lowcore, trans_exc_code));
 	DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid));
 	DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address));
 	DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id));
@@ -142,10 +143,8 @@
 	DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area));
 	DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area));
 #ifdef CONFIG_32BIT
-	DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params));
 	DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr));
 #else /* CONFIG_32BIT */
-	DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2));
 	DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2));
 	DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area));
 	DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste));
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/compat_linux.c linux-libre-2.6.37-gnu/arch/s390/kernel/compat_linux.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/compat_linux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/compat_linux.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/compat_ptrace.h linux-libre-2.6.37-gnu/arch/s390/kernel/compat_ptrace.h
--- linux-libre-2.6.36-gnu/arch/s390/kernel/compat_ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/compat_ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -51,8 +51,7 @@
 	 * watchpoints. This is the way intel does it.
 	 */
 	per_struct32 per_info;
-	u32  ieee_instruction_pointer; 
-	/* Used to give failing instruction back to user for ieee exceptions */
+	u32  ieee_instruction_pointer;	/* obsolete, always 0 */
 };
 
 struct user32 {
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/debug.c linux-libre-2.6.37-gnu/arch/s390/kernel/debug.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -174,6 +174,7 @@
 	.write   = debug_input,
 	.open    = debug_open,
 	.release = debug_close,
+	.llseek  = no_llseek,
 };
 
 static struct dentry *debug_debugfs_root_entry;
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/dis.c linux-libre-2.6.37-gnu/arch/s390/kernel/dis.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/dis.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/dis.c	2011-01-04 19:50:19.000000000 -0500
@@ -113,7 +113,7 @@
 	INSTR_INVALID,
 	INSTR_E,
 	INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU,
-	INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU,
+	INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, INSTR_RIE_RRI0,
 	INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP,
 	INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU,
 	INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
@@ -122,13 +122,14 @@
 	INSTR_RRE_RR, INSTR_RRE_RR_OPT,
 	INSTR_RRF_0UFF, INSTR_RRF_F0FF, INSTR_RRF_F0FF2, INSTR_RRF_F0FR,
 	INSTR_RRF_FFRU, INSTR_RRF_FUFF, INSTR_RRF_M0RR, INSTR_RRF_R0RR,
-	INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, INSTR_RRF_U0RR,
-	INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
+	INSTR_RRF_R0RR2, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF,
+	INSTR_RRF_U0RR, INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU,
 	INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
 	INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD,
 	INSTR_RSI_RRP,
 	INSTR_RSL_R0RD,
 	INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD,
+	INSTR_RSY_RDRM,
 	INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD,
 	INSTR_RS_RURD,
 	INSTR_RXE_FRRD, INSTR_RXE_RRRD,
@@ -139,7 +140,7 @@
 	INSTR_SIY_IRD, INSTR_SIY_URD,
 	INSTR_SI_URD,
 	INSTR_SSE_RDRD,
-	INSTR_SSF_RRDRD,
+	INSTR_SSF_RRDRD, INSTR_SSF_RRDRD2,
 	INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD,
 	INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
 	INSTR_S_00, INSTR_S_RD,
@@ -152,7 +153,7 @@
 };
 
 struct insn {
-	const char name[6];
+	const char name[5];
 	unsigned char opfrag;
 	unsigned char format;
 };
@@ -217,6 +218,7 @@
 	[INSTR_RIE_RRP]	  = { 0xff, R_8,R_12,J16_16,0,0,0 },
 	[INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 },
 	[INSTR_RIE_RUPI]  = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 },
+	[INSTR_RIE_RRI0]  = { 0xff, R_8,R_12,I16_16,0,0,0 },
 	[INSTR_RIL_RI]	  = { 0x0f, R_8,I32_16,0,0,0,0 },
 	[INSTR_RIL_RP]	  = { 0x0f, R_8,J32_16,0,0,0,0 },
 	[INSTR_RIL_RU]	  = { 0x0f, R_8,U32_16,0,0,0,0 },
@@ -248,6 +250,7 @@
 	[INSTR_RRF_FUFF]  = { 0xff, F_24,F_16,F_28,U4_20,0,0 },
 	[INSTR_RRF_M0RR]  = { 0xff, R_24,R_28,M_16,0,0,0 },
 	[INSTR_RRF_R0RR]  = { 0xff, R_24,R_16,R_28,0,0,0 },
+	[INSTR_RRF_R0RR2] = { 0xff, R_24,R_28,R_16,0,0,0 },
 	[INSTR_RRF_RURR]  = { 0xff, R_24,R_28,R_16,U4_20,0,0 },
 	[INSTR_RRF_U0FF]  = { 0xff, F_24,U4_16,F_28,0,0,0 },
 	[INSTR_RRF_U0RF]  = { 0xff, R_24,U4_16,F_28,0,0,0 },
@@ -269,6 +272,7 @@
 	[INSTR_RSY_CCRD]  = { 0xff, C_8,C_12,D20_20,B_16,0,0 },
 	[INSTR_RSY_RRRD]  = { 0xff, R_8,R_12,D20_20,B_16,0,0 },
 	[INSTR_RSY_RURD]  = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
+	[INSTR_RSY_RDRM]  = { 0xff, R_8,D20_20,B_16,U4_12,0,0 },
 	[INSTR_RS_AARD]	  = { 0xff, A_8,A_12,D_20,B_16,0,0 },
 	[INSTR_RS_CCRD]	  = { 0xff, C_8,C_12,D_20,B_16,0,0 },
 	[INSTR_RS_R0RD]	  = { 0xff, R_8,D_20,B_16,0,0,0 },
@@ -290,6 +294,7 @@
 	[INSTR_SI_URD]	  = { 0xff, D_20,B_16,U8_8,0,0,0 },
 	[INSTR_SSE_RDRD]  = { 0xff, D_20,B_16,D_36,B_32,0,0 },
 	[INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 },
+	[INSTR_SSF_RRDRD2]= { 0x00, R_8,D_20,B_16,D_36,B_32,0 },
 	[INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
 	[INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
 	[INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
@@ -300,6 +305,36 @@
 	[INSTR_S_RD]	  = { 0xff, D_20,B_16,0,0,0,0 },
 };
 
+enum {
+	LONG_INSN_ALGHSIK,
+	LONG_INSN_ALHSIK,
+	LONG_INSN_CLFHSI,
+	LONG_INSN_CLGFRL,
+	LONG_INSN_CLGHRL,
+	LONG_INSN_CLGHSI,
+	LONG_INSN_CLHHSI,
+	LONG_INSN_LLGFRL,
+	LONG_INSN_LLGHRL,
+	LONG_INSN_POPCNT,
+	LONG_INSN_RISBHG,
+	LONG_INSN_RISBLG,
+};
+
+static char *long_insn_name[] = {
+	[LONG_INSN_ALGHSIK] = "alghsik",
+	[LONG_INSN_ALHSIK] = "alhsik",
+	[LONG_INSN_CLFHSI] = "clfhsi",
+	[LONG_INSN_CLGFRL] = "clgfrl",
+	[LONG_INSN_CLGHRL] = "clghrl",
+	[LONG_INSN_CLGHSI] = "clghsi",
+	[LONG_INSN_CLHHSI] = "clhhsi",
+	[LONG_INSN_LLGFRL] = "llgfrl",
+	[LONG_INSN_LLGHRL] = "llghrl",
+	[LONG_INSN_POPCNT] = "popcnt",
+	[LONG_INSN_RISBHG] = "risbhg",
+	[LONG_INSN_RISBLG] = "risblk",
+};
+
 static struct insn opcode[] = {
 #ifdef CONFIG_64BIT
 	{ "lmd", 0xef, INSTR_SS_RRRDRD3 },
@@ -881,6 +916,35 @@
 	{ "pfmf", 0xaf, INSTR_RRE_RR },
 	{ "trte", 0xbf, INSTR_RRF_M0RR },
 	{ "trtre", 0xbd, INSTR_RRF_M0RR },
+	{ "ahhhr", 0xc8, INSTR_RRF_R0RR2 },
+	{ "shhhr", 0xc9, INSTR_RRF_R0RR2 },
+	{ "alhhh", 0xca, INSTR_RRF_R0RR2 },
+	{ "alhhl", 0xca, INSTR_RRF_R0RR2 },
+	{ "slhhh", 0xcb, INSTR_RRF_R0RR2 },
+	{ "chhr ", 0xcd, INSTR_RRE_RR },
+	{ "clhhr", 0xcf, INSTR_RRE_RR },
+	{ "ahhlr", 0xd8, INSTR_RRF_R0RR2 },
+	{ "shhlr", 0xd9, INSTR_RRF_R0RR2 },
+	{ "slhhl", 0xdb, INSTR_RRF_R0RR2 },
+	{ "chlr", 0xdd, INSTR_RRE_RR },
+	{ "clhlr", 0xdf, INSTR_RRE_RR },
+	{ { 0, LONG_INSN_POPCNT }, 0xe1, INSTR_RRE_RR },
+	{ "locgr", 0xe2, INSTR_RRF_M0RR },
+	{ "ngrk", 0xe4, INSTR_RRF_R0RR2 },
+	{ "ogrk", 0xe6, INSTR_RRF_R0RR2 },
+	{ "xgrk", 0xe7, INSTR_RRF_R0RR2 },
+	{ "agrk", 0xe8, INSTR_RRF_R0RR2 },
+	{ "sgrk", 0xe9, INSTR_RRF_R0RR2 },
+	{ "algrk", 0xea, INSTR_RRF_R0RR2 },
+	{ "slgrk", 0xeb, INSTR_RRF_R0RR2 },
+	{ "locr", 0xf2, INSTR_RRF_M0RR },
+	{ "nrk", 0xf4, INSTR_RRF_R0RR2 },
+	{ "ork", 0xf6, INSTR_RRF_R0RR2 },
+	{ "xrk", 0xf7, INSTR_RRF_R0RR2 },
+	{ "ark", 0xf8, INSTR_RRF_R0RR2 },
+	{ "srk", 0xf9, INSTR_RRF_R0RR2 },
+	{ "alrk", 0xfa, INSTR_RRF_R0RR2 },
+	{ "slrk", 0xfb, INSTR_RRF_R0RR2 },
 #endif
 	{ "kmac", 0x1e, INSTR_RRE_RR },
 	{ "lrvr", 0x1f, INSTR_RRE_RR },
@@ -949,9 +1013,9 @@
 	{ "lgfrl", 0x0c, INSTR_RIL_RP },
 	{ "lhrl", 0x05, INSTR_RIL_RP },
 	{ "lghrl", 0x04, INSTR_RIL_RP },
-	{ "llgfrl", 0x0e, INSTR_RIL_RP },
+	{ { 0, LONG_INSN_LLGFRL }, 0x0e, INSTR_RIL_RP },
 	{ "llhrl", 0x02, INSTR_RIL_RP },
-	{ "llghrl", 0x06, INSTR_RIL_RP },
+	{ { 0, LONG_INSN_LLGHRL }, 0x06, INSTR_RIL_RP },
 	{ "strl", 0x0f, INSTR_RIL_RP },
 	{ "stgrl", 0x0b, INSTR_RIL_RP },
 	{ "sthrl", 0x07, INSTR_RIL_RP },
@@ -968,9 +1032,9 @@
 	{ "cghrl", 0x04, INSTR_RIL_RP },
 	{ "clrl", 0x0f, INSTR_RIL_RP },
 	{ "clgrl", 0x0a, INSTR_RIL_RP },
-	{ "clgfrl", 0x0e, INSTR_RIL_RP },
+	{ { 0, LONG_INSN_CLGFRL }, 0x0e, INSTR_RIL_RP },
 	{ "clhrl", 0x07, INSTR_RIL_RP },
-	{ "clghrl", 0x06, INSTR_RIL_RP },
+	{ { 0, LONG_INSN_CLGHRL }, 0x06, INSTR_RIL_RP },
 	{ "pfdrl", 0x02, INSTR_RIL_UP },
 	{ "exrl", 0x00, INSTR_RIL_RP },
 #endif
@@ -982,6 +1046,20 @@
 	{ "mvcos", 0x00, INSTR_SSF_RRDRD },
 	{ "ectg", 0x01, INSTR_SSF_RRDRD },
 	{ "csst", 0x02, INSTR_SSF_RRDRD },
+	{ "lpd", 0x04, INSTR_SSF_RRDRD2 },
+	{ "lpdg ", 0x05, INSTR_SSF_RRDRD2 },
+#endif
+	{ "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_cc[] = {
+#ifdef CONFIG_64BIT
+	{ "brcth", 0x06, INSTR_RIL_RP },
+	{ "aih", 0x08, INSTR_RIL_RI },
+	{ "alsih", 0x0a, INSTR_RIL_RI },
+	{ "alsih", 0x0b, INSTR_RIL_RI },
+	{ "cih", 0x0d, INSTR_RIL_RI },
+	{ "clih ", 0x0f, INSTR_RIL_RI },
 #endif
 	{ "", 0, INSTR_INVALID }
 };
@@ -1063,6 +1141,16 @@
 	{ "mfy", 0x5c, INSTR_RXY_RRRD },
 	{ "mhy", 0x7c, INSTR_RXY_RRRD },
 	{ "pfd", 0x36, INSTR_RXY_URRD },
+	{ "lbh", 0xc0, INSTR_RXY_RRRD },
+	{ "llch", 0xc2, INSTR_RXY_RRRD },
+	{ "stch", 0xc3, INSTR_RXY_RRRD },
+	{ "lhh", 0xc4, INSTR_RXY_RRRD },
+	{ "llhh", 0xc6, INSTR_RXY_RRRD },
+	{ "sthh", 0xc7, INSTR_RXY_RRRD },
+	{ "lfh", 0xca, INSTR_RXY_RRRD },
+	{ "stfh", 0xcb, INSTR_RXY_RRRD },
+	{ "chf", 0xcd, INSTR_RXY_RRRD },
+	{ "clhf", 0xcf, INSTR_RXY_RRRD },
 #endif
 	{ "lrv", 0x1e, INSTR_RXY_RRRD },
 	{ "lrvh", 0x1f, INSTR_RXY_RRRD },
@@ -1080,9 +1168,9 @@
 	{ "chhsi", 0x54, INSTR_SIL_RDI },
 	{ "chsi", 0x5c, INSTR_SIL_RDI },
 	{ "cghsi", 0x58, INSTR_SIL_RDI },
-	{ "clhhsi", 0x55, INSTR_SIL_RDU },
-	{ "clfhsi", 0x5d, INSTR_SIL_RDU },
-	{ "clghsi", 0x59, INSTR_SIL_RDU },
+	{ { 0, LONG_INSN_CLHHSI }, 0x55, INSTR_SIL_RDU },
+	{ { 0, LONG_INSN_CLFHSI }, 0x5d, INSTR_SIL_RDU },
+	{ { 0, LONG_INSN_CLGHSI }, 0x59, INSTR_SIL_RDU },
 	{ "mvhhi", 0x44, INSTR_SIL_RDI },
 	{ "mvhi", 0x4c, INSTR_SIL_RDI },
 	{ "mvghi", 0x48, INSTR_SIL_RDI },
@@ -1137,6 +1225,24 @@
 	{ "alsi", 0x6e, INSTR_SIY_IRD },
 	{ "algsi", 0x7e, INSTR_SIY_IRD },
 	{ "ecag", 0x4c, INSTR_RSY_RRRD },
+	{ "srak", 0xdc, INSTR_RSY_RRRD },
+	{ "slak", 0xdd, INSTR_RSY_RRRD },
+	{ "srlk", 0xde, INSTR_RSY_RRRD },
+	{ "sllk", 0xdf, INSTR_RSY_RRRD },
+	{ "locg", 0xe2, INSTR_RSY_RDRM },
+	{ "stocg", 0xe3, INSTR_RSY_RDRM },
+	{ "lang", 0xe4, INSTR_RSY_RRRD },
+	{ "laog", 0xe6, INSTR_RSY_RRRD },
+	{ "laxg", 0xe7, INSTR_RSY_RRRD },
+	{ "laag", 0xe8, INSTR_RSY_RRRD },
+	{ "laalg", 0xea, INSTR_RSY_RRRD },
+	{ "loc", 0xf2, INSTR_RSY_RDRM },
+	{ "stoc", 0xf3, INSTR_RSY_RDRM },
+	{ "lan", 0xf4, INSTR_RSY_RRRD },
+	{ "lao", 0xf6, INSTR_RSY_RRRD },
+	{ "lax", 0xf7, INSTR_RSY_RRRD },
+	{ "laa", 0xf8, INSTR_RSY_RRRD },
+	{ "laal", 0xfa, INSTR_RSY_RRRD },
 #endif
 	{ "rll", 0x1d, INSTR_RSY_RRRD },
 	{ "mvclu", 0x8e, INSTR_RSY_RRRD },
@@ -1172,6 +1278,12 @@
 	{ "rxsbg", 0x57, INSTR_RIE_RRUUU },
 	{ "rosbg", 0x56, INSTR_RIE_RRUUU },
 	{ "risbg", 0x55, INSTR_RIE_RRUUU },
+	{ { 0, LONG_INSN_RISBLG }, 0x51, INSTR_RIE_RRUUU },
+	{ { 0, LONG_INSN_RISBHG }, 0x5D, INSTR_RIE_RRUUU },
+	{ "ahik", 0xd8, INSTR_RIE_RRI0 },
+	{ "aghik", 0xd9, INSTR_RIE_RRI0 },
+	{ { 0, LONG_INSN_ALHSIK }, 0xda, INSTR_RIE_RRI0 },
+	{ { 0, LONG_INSN_ALGHSIK }, 0xdb, INSTR_RIE_RRI0 },
 #endif
 	{ "", 0, INSTR_INVALID }
 };
@@ -1321,6 +1433,9 @@
 	case 0xc8:
 		table = opcode_c8;
 		break;
+	case 0xcc:
+		table = opcode_cc;
+		break;
 	case 0xe3:
 		table = opcode_e3;
 		opfrag = code[5];
@@ -1367,7 +1482,11 @@
 	ptr = buffer;
 	insn = find_insn(code);
 	if (insn) {
-		ptr += sprintf(ptr, "%.5s\t", insn->name);
+		if (insn->name[0] == '\0')
+			ptr += sprintf(ptr, "%s\t",
+				       long_insn_name[(int) insn->name[1]]);
+		else
+			ptr += sprintf(ptr, "%.5s\t", insn->name);
 		/* Extract the operands. */
 		separator = 0;
 		for (ops = formats[insn->format] + 1, i = 0;
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/early.c linux-libre-2.6.37-gnu/arch/s390/kernel/early.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/early.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/early.c	2011-01-04 19:50:19.000000000 -0500
@@ -208,7 +208,8 @@
 	end_pfn = PFN_UP(__pa(&_end));
 
 	for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
-		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+		page_set_storage_key(init_pfn << PAGE_SHIFT,
+				     PAGE_DEFAULT_KEY, 0);
 }
 
 static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
@@ -255,13 +256,33 @@
 	s390_base_pgm_handler_fn = early_pgm_check_handler;
 }
 
+static noinline __init void setup_facility_list(void)
+{
+	unsigned long nr;
+
+	S390_lowcore.stfl_fac_list = 0;
+	asm volatile(
+		"	.insn	s,0xb2b10000,0(0)\n" /* stfl */
+		"0:\n"
+		EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
+	memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
+	nr = 4;				/* # bytes stored by stfl */
+	if (test_facility(7)) {
+		/* More facility bits available with stfle */
+		register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
+		asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+			     : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
+			     : : "cc");
+		nr = (reg0 + 1) * 8;	/* # bytes stored by stfle */
+	}
+	memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
+	       MAX_FACILITY_BIT/8 - nr);
+}
+
 static noinline __init void setup_hpage(void)
 {
 #ifndef CONFIG_DEBUG_PAGEALLOC
-	unsigned int facilities;
-
-	facilities = stfl();
-	if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
+	if (!test_facility(2) || !test_facility(8))
 		return;
 	S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
 	__ctl_set_bit(0, 23);
@@ -355,18 +376,15 @@
 static __init void detect_machine_facilities(void)
 {
 #ifdef CONFIG_64BIT
-	unsigned int facilities;
-	unsigned long long facility_bits;
-
-	facilities = stfl();
-	if (facilities & (1 << 28))
+	if (test_facility(3))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
-	if (facilities & (1 << 23))
+	if (test_facility(8))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
-	if (facilities & (1 << 4))
+	if (test_facility(11))
+		S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
+	if (test_facility(27))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
-	if ((stfle(&facility_bits, 1) > 0) &&
-	    (facility_bits & (1ULL << (63 - 40))))
+	if (test_facility(40))
 		S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
 #endif
 }
@@ -447,6 +465,7 @@
 	lockdep_off();
 	sort_main_extable();
 	setup_lowcore_early();
+	setup_facility_list();
 	detect_machine_type();
 	ipl_update_parameters();
 	setup_boot_command_line();
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/entry64.S linux-libre-2.6.37-gnu/arch/s390/kernel/entry64.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/entry64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/entry64.S	2011-01-04 19:50:19.000000000 -0500
@@ -79,25 +79,9 @@
 	basr	%r2,%r0
 	brasl	%r14,trace_hardirqs_off_caller
 	.endm
-
-	.macro TRACE_IRQS_CHECK_ON
-	tm	SP_PSW(%r15),0x03	# irqs enabled?
-	jz	0f
-	TRACE_IRQS_ON
-0:
-	.endm
-
-	.macro TRACE_IRQS_CHECK_OFF
-	tm	SP_PSW(%r15),0x03	# irqs enabled?
-	jz	0f
-	TRACE_IRQS_OFF
-0:
-	.endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -207,6 +191,12 @@
 0:
 	.endm
 
+	.macro REENABLE_IRQS
+	mvc	__SF_EMPTY(1,%r15),SP_PSW(%r15)
+	ni	__SF_EMPTY(%r15),0xbf
+	ssm	__SF_EMPTY(%r15)
+	.endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -256,7 +246,6 @@
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(16,%r15),__LC_SVC_OLD_PSW
 	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
-	stg	%r7,SP_ARGS(%r15)
 	lg	%r12,__LC_THREAD_INFO	# load pointer to thread_info struct
 sysc_vtime:
 	UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -284,6 +273,7 @@
 sysc_noemu:
 #endif
 	tm	__TI_flags+6(%r12),_TIF_SYSCALL
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 	lgf	%r8,0(%r7,%r10) # load address of system call routine
 	jnz	sysc_tracesys
 	basr	%r14,%r8	# call sys_xxxx
@@ -397,6 +387,7 @@
 	lgf	%r8,0(%r7,%r10)
 sysc_tracego:
 	lmg	%r3,%r6,SP_R3(%r15)
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 	lg	%r2,SP_ORIG_R2(%r15)
 	basr	%r14,%r8		# call sys_xxx
 	stg	%r2,SP_R2(%r15)		# store return value
@@ -443,14 +434,12 @@
 	br	%r14
 	# execve succeeded.
 0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
-#	TRACE_IRQS_OFF
 	lg	%r15,__LC_KERNEL_STACK	# load ksp
 	aghi	%r15,-SP_SIZE		# make room for registers & psw
 	lg	%r13,__LC_SVC_NEW_PSW+8
 	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
 	lg	%r12,__LC_THREAD_INFO
 	xc	__SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
-#	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	brasl	%r14,execve_tail
 	j	sysc_return
@@ -490,19 +479,18 @@
 	LAST_BREAK
 pgm_no_vtime:
 	HANDLE_SIE_INTERCEPT
-	TRACE_IRQS_CHECK_OFF
 	stg	%r11,SP_ARGS(%r15)
 	lgf	%r3,__LC_PGM_ILC	# load program interruption code
+	lg	%r4,__LC_TRANS_EXC_CODE
+	REENABLE_IRQS
 	lghi	%r8,0x7f
 	ngr	%r8,%r3
-pgm_do_call:
 	sll	%r8,3
 	larl	%r1,pgm_check_table
 	lg	%r1,0(%r8,%r1)		# load address of handler routine
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	basr	%r14,%r1		# branch to interrupt-handler
 pgm_exit:
-	TRACE_IRQS_CHECK_ON
 	j	sysc_return
 
 #
@@ -533,7 +521,6 @@
 	LAST_BREAK
 pgm_no_vtime2:
 	HANDLE_SIE_INTERCEPT
-	TRACE_IRQS_CHECK_OFF
 	lg	%r1,__TI_task(%r12)
 	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
 	jz	kernel_per
@@ -542,6 +529,8 @@
 	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
 	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
 	lgf	%r3,__LC_PGM_ILC	# load program interruption code
+	lg	%r4,__LC_TRANS_EXC_CODE
+	REENABLE_IRQS
 	lghi	%r8,0x7f
 	ngr	%r8,%r3			# clear per-event-bit and ilc
 	je	pgm_exit2
@@ -551,8 +540,6 @@
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	basr	%r14,%r1		# branch to interrupt-handler
 pgm_exit2:
-	TRACE_IRQS_ON
-	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	j	sysc_return
 
 #
@@ -568,13 +555,11 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 	LAST_BREAK
-	TRACE_IRQS_OFF
 	lg	%r8,__TI_task(%r12)
 	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
 	mvc	__THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS
 	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
 	oi	__TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	lmg	%r2,%r6,SP_R2(%r15)	# load svc arguments
 	j	sysc_do_svc
@@ -583,6 +568,7 @@
 # per was called from kernel, must be kprobes
 #
 kernel_per:
+	REENABLE_IRQS
 	xc	SP_SVCNR(2,%r15),SP_SVCNR(%r15)	# clear svc number
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	brasl	%r14,do_single_step
@@ -743,8 +729,11 @@
 ext_no_vtime:
 	HANDLE_SIE_INTERCEPT
 	TRACE_IRQS_OFF
+	lghi	%r1,4096
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
-	llgh	%r3,__LC_EXT_INT_CODE	# get interruption code
+	llgf	%r3,__LC_CPU_ADDRESS	# get cpu address + interruption code
+	llgf	%r4,__LC_EXT_PARAMS	# get external parameter
+	lg	%r5,__LC_EXT_PARAMS2-4096(%r1)	# get 64 bit external parameter
 	brasl	%r14,do_extint
 	j	io_return
 
@@ -966,7 +955,6 @@
 	CREATE_STACK_FRAME __LC_SAVE_AREA
 	mvc	SP_PSW(16,%r15),__LC_SVC_OLD_PSW
 	mvc	SP_ILC(4,%r15),__LC_SVC_ILC
-	stg	%r7,SP_ARGS(%r15)
 	mvc	8(8,%r12),__LC_THREAD_INFO
 cleanup_vtime:
 	clc	__LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/entry.h linux-libre-2.6.37-gnu/arch/s390/kernel/entry.h
--- linux-libre-2.6.36-gnu/arch/s390/kernel/entry.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/entry.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
 #include <linux/signal.h>
 #include <asm/ptrace.h>
 
-typedef void pgm_check_handler_t(struct pt_regs *, long);
+typedef void pgm_check_handler_t(struct pt_regs *, long, unsigned long);
 extern pgm_check_handler_t *pgm_check_table[128];
 pgm_check_handler_t do_protection_exception;
 pgm_check_handler_t do_dat_exception;
@@ -19,7 +19,7 @@
 int handle_signal32(unsigned long sig, struct k_sigaction *ka,
 		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
 
-void do_extint(struct pt_regs *regs, unsigned short code);
+void do_extint(struct pt_regs *regs, unsigned int, unsigned int, unsigned long);
 int __cpuinit start_secondary(void *cpuvoid);
 void __init startup_init(void);
 void die(const char * str, struct pt_regs * regs, long err);
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/entry.S linux-libre-2.6.37-gnu/arch/s390/kernel/entry.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -72,25 +72,9 @@
 	l	%r1,BASED(.Ltrace_irq_off_caller)
 	basr	%r14,%r1
 	.endm
-
-	.macro	TRACE_IRQS_CHECK_ON
-	tm	SP_PSW(%r15),0x03	# irqs enabled?
-	bz	BASED(0f)
-	TRACE_IRQS_ON
-0:
-	.endm
-
-	.macro	TRACE_IRQS_CHECK_OFF
-	tm	SP_PSW(%r15),0x03	# irqs enabled?
-	bz	BASED(0f)
-	TRACE_IRQS_OFF
-0:
-	.endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK_ON
-#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -198,6 +182,12 @@
 	lpsw	\psworg			# back to caller
 	.endm
 
+	.macro REENABLE_IRQS
+	mvc	__SF_EMPTY(1,%r15),SP_PSW(%r15)
+	ni	__SF_EMPTY(%r15),0xbf
+	ssm	__SF_EMPTY(%r15)
+	.endm
+
 /*
  * Scheduler resume function, called by switch_to
  *  gpr2 = (task_struct *) prev
@@ -264,12 +254,11 @@
 	bnl	BASED(sysc_nr_ok)
 	lr	%r7,%r1 	  # copy svc number to %r7
 sysc_nr_ok:
-	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
-sysc_do_restart:
 	sth	%r7,SP_SVCNR(%r15)
 	sll	%r7,2		  # svc number *4
 	l	%r8,BASED(.Lsysc_table)
 	tm	__TI_flags+2(%r9),_TIF_SYSCALL
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 	l	%r8,0(%r7,%r8)	  # get system call addr.
 	bnz	BASED(sysc_tracesys)
 	basr	%r14,%r8	  # call sys_xxxx
@@ -357,7 +346,7 @@
 	l	%r7,SP_R2(%r15) 	# load new svc number
 	mvc	SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
 	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
-	b	BASED(sysc_do_restart)	# restart svc
+	b	BASED(sysc_nr_ok)	# restart svc
 
 #
 # _TIF_SINGLE_STEP is set, call do_single_step
@@ -390,6 +379,7 @@
 	l	%r8,0(%r7,%r8)
 sysc_tracego:
 	lm	%r3,%r6,SP_R3(%r15)
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 	l	%r2,SP_ORIG_R2(%r15)
 	basr	%r14,%r8		# call sys_xxx
 	st	%r2,SP_R2(%r15)		# store return value
@@ -440,13 +430,11 @@
 	br	%r14
 	# execve succeeded.
 0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
-	TRACE_IRQS_OFF
 	l	%r15,__LC_KERNEL_STACK	# load ksp
 	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
 	l	%r9,__LC_THREAD_INFO
 	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
-	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	l	%r1,BASED(.Lexecve_tail)
 	basr	%r14,%r1
@@ -483,9 +471,10 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
-	TRACE_IRQS_CHECK_OFF
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	l	%r3,__LC_PGM_ILC	# load program interruption code
+	l	%r4,__LC_TRANS_EXC_CODE
+	REENABLE_IRQS
 	la	%r8,0x7f
 	nr	%r8,%r3
 pgm_do_call:
@@ -495,7 +484,6 @@
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	basr	%r14,%r7		# branch to interrupt-handler
 pgm_exit:
-	TRACE_IRQS_CHECK_ON
 	b	BASED(sysc_return)
 
 #
@@ -523,7 +511,6 @@
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
-	TRACE_IRQS_CHECK_OFF
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	l	%r1,__TI_task(%r9)
 	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
@@ -533,6 +520,8 @@
 	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
 	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
 	l	%r3,__LC_PGM_ILC	# load program interruption code
+	l	%r4,__LC_TRANS_EXC_CODE
+	REENABLE_IRQS
 	la	%r8,0x7f
 	nr	%r8,%r3 		# clear per-event-bit and ilc
 	be	BASED(pgm_exit2)	# only per or per+check ?
@@ -542,8 +531,6 @@
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	basr	%r14,%r7		# branch to interrupt-handler
 pgm_exit2:
-	TRACE_IRQS_ON
-	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	b	BASED(sysc_return)
 
 #
@@ -557,13 +544,11 @@
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 	lh	%r7,0x8a		# get svc number from lowcore
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
-	TRACE_IRQS_OFF
 	l	%r8,__TI_task(%r9)
 	mvc	__THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID
 	mvc	__THREAD_per+__PER_address(4,%r8),__LC_PER_ADDRESS
 	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
 	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
 	b	BASED(sysc_do_svc)
@@ -572,6 +557,7 @@
 # per was called from kernel, must be kprobes
 #
 kernel_per:
+	REENABLE_IRQS
 	mvi	SP_SVCNR(%r15),0xff	# set trap indication to pgm check
 	mvi	SP_SVCNR+1(%r15),0xff
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
@@ -737,7 +723,8 @@
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
-	lh	%r3,__LC_EXT_INT_CODE	# get interruption code
+	l	%r3,__LC_CPU_ADDRESS	# get cpu address + interruption code
+	l	%r4,__LC_EXT_PARAMS	# get external parameters
 	l	%r1,BASED(.Ldo_extint)
 	basr	%r14,%r1
 	b	BASED(io_return)
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/head.S linux-libre-2.6.37-gnu/arch/s390/kernel/head.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/head.S	2011-01-04 19:50:19.000000000 -0500
@@ -488,7 +488,9 @@
 	.align 16
 2:	.long	0x000a0000,0x8badcccc
 #if defined(CONFIG_64BIT)
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+	.long 0xc100efe3, 0xf46c0000
+#elif defined(CONFIG_MARCH_Z10)
 	.long 0xc100efe3, 0xf0680000
 #elif defined(CONFIG_MARCH_Z9_109)
 	.long 0xc100efc3, 0x00000000
@@ -498,7 +500,9 @@
 	.long 0xc0000000, 0x00000000
 #endif
 #else
-#if defined(CONFIG_MARCH_Z10)
+#if defined(CONFIG_MARCH_Z196)
+	.long 0x8100c880, 0x00000000
+#elif defined(CONFIG_MARCH_Z10)
 	.long 0x8100c880, 0x00000000
 #elif defined(CONFIG_MARCH_Z9_109)
 	.long 0x8100c880, 0x00000000
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/kprobes.c linux-libre-2.6.37-gnu/arch/s390/kernel/kprobes.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/kprobes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/kprobes.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <asm/sections.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/hardirq.h>
 
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -212,7 +213,7 @@
 	/* Set the PER control regs, turns on single step for this address */
 	__ctl_load(kprobe_per_regs, 9, 11);
 	regs->psw.mask |= PSW_MASK_PER;
-	regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+	regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
 }
 
 static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
@@ -239,7 +240,7 @@
 	__get_cpu_var(current_kprobe) = p;
 	/* Save the interrupt and per flags */
 	kcb->kprobe_saved_imask = regs->psw.mask &
-	    (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+		(PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
 	/* Save the control regs that govern PER */
 	__ctl_store(kcb->kprobe_saved_ctl, 9, 11);
 }
@@ -348,6 +349,7 @@
 	struct hlist_node *node, *tmp;
 	unsigned long flags, orig_ret_address = 0;
 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+	kprobe_opcode_t *correct_ret_addr = NULL;
 
 	INIT_HLIST_HEAD(&empty_rp);
 	kretprobe_hash_lock(current, &head, &flags);
@@ -370,10 +372,32 @@
 			/* another task is sharing our hash bucket */
 			continue;
 
-		if (ri->rp && ri->rp->handler)
-			ri->rp->handler(ri, regs);
+		orig_ret_address = (unsigned long)ri->ret_addr;
+
+		if (orig_ret_address != trampoline_address)
+			/*
+			 * This is the real return address. Any other
+			 * instances associated with this task are for
+			 * other calls deeper on the call stack
+			 */
+			break;
+	}
+
+	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
+	correct_ret_addr = ri->ret_addr;
+	hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+		if (ri->task != current)
+			/* another task is sharing our hash bucket */
+			continue;
 
 		orig_ret_address = (unsigned long)ri->ret_addr;
+
+		if (ri->rp && ri->rp->handler) {
+			ri->ret_addr = correct_ret_addr;
+			ri->rp->handler(ri, regs);
+		}
+
 		recycle_rp_inst(ri, &empty_rp);
 
 		if (orig_ret_address != trampoline_address) {
@@ -385,7 +409,7 @@
 			break;
 		}
 	}
-	kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
 	regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
 
 	reset_current_kprobe();
@@ -478,7 +502,7 @@
 	return 1;
 }
 
-int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
 {
 	struct kprobe *cur = kprobe_running();
 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -502,8 +526,9 @@
 		regs->psw.mask |= kcb->kprobe_saved_imask;
 		if (kcb->kprobe_status == KPROBE_REENTER)
 			restore_previous_kprobe(kcb);
-		else
+		else {
 			reset_current_kprobe();
+		}
 		preempt_enable_no_resched();
 		break;
 	case KPROBE_HIT_ACTIVE:
@@ -546,6 +571,18 @@
 	return 0;
 }
 
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+	int ret;
+
+	if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+		local_irq_disable();
+	ret = kprobe_trap_handler(regs, trapnr);
+	if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+		local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+	return ret;
+}
+
 /*
  * Wrapper routine to for handling exceptions.
  */
@@ -553,8 +590,12 @@
 				       unsigned long val, void *data)
 {
 	struct die_args *args = (struct die_args *)data;
+	struct pt_regs *regs = args->regs;
 	int ret = NOTIFY_DONE;
 
+	if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+		local_irq_disable();
+
 	switch (val) {
 	case DIE_BPT:
 		if (kprobe_handler(args->regs))
@@ -565,16 +606,17 @@
 			ret = NOTIFY_STOP;
 		break;
 	case DIE_TRAP:
-		/* kprobe_running() needs smp_processor_id() */
-		preempt_disable();
-		if (kprobe_running() &&
-		    kprobe_fault_handler(args->regs, args->trapnr))
+		if (!preemptible() && kprobe_running() &&
+		    kprobe_trap_handler(args->regs, args->trapnr))
 			ret = NOTIFY_STOP;
-		preempt_enable();
 		break;
 	default:
 		break;
 	}
+
+	if (regs->psw.mask & (PSW_MASK_IO | PSW_MASK_EXT))
+		local_irq_restore(regs->psw.mask & ~PSW_MASK_PER);
+
 	return ret;
 }
 
@@ -588,6 +630,7 @@
 
 	/* setup return addr to the jprobe handler routine */
 	regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
+	regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
 
 	/* r14 is the function return address */
 	kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/mem_detect.c linux-libre-2.6.37-gnu/arch/s390/kernel/mem_detect.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/mem_detect.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/mem_detect.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,11 +54,11 @@
 	 * right thing and we don't get scheduled away with low address
 	 * protection disabled.
 	 */
-	flags = __raw_local_irq_stnsm(0xf8);
+	flags = __arch_local_irq_stnsm(0xf8);
 	__ctl_store(cr0, 0, 0);
 	__ctl_clear_bit(0, 28);
 	find_memory_chunks(chunk);
 	__ctl_load(cr0, 0, 0);
-	__raw_local_irq_ssm(flags);
+	arch_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(detect_memory_layout);
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/nmi.c linux-libre-2.6.37-gnu/arch/s390/kernel/nmi.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/nmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/nmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,7 +95,6 @@
 static int notrace s390_revalidate_registers(struct mci *mci)
 {
 	int kill_task;
-	u64 tmpclock;
 	u64 zero;
 	void *fpt_save_area, *fpt_creg_save_area;
 
@@ -214,11 +213,10 @@
 			: "0", "cc");
 #endif
 	/* Revalidate clock comparator register */
-	asm volatile(
-		"	stck	0(%1)\n"
-		"	sckc	0(%1)"
-		: "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
-
+	if (S390_lowcore.clock_comparator == -1)
+		set_clock_comparator(S390_lowcore.mcck_clock);
+	else
+		set_clock_comparator(S390_lowcore.clock_comparator);
 	/* Check if old PSW is valid */
 	if (!mci->wp)
 		/*
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/process.c linux-libre-2.6.37-gnu/arch/s390/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,17 +76,17 @@
 static void default_idle(void)
 {
 	/* CPU is going idle. */
-	local_irq_disable();
-	if (need_resched()) {
-		local_irq_enable();
-		return;
-	}
 #ifdef CONFIG_HOTPLUG_CPU
 	if (cpu_is_offline(smp_processor_id())) {
 		preempt_enable_no_resched();
 		cpu_die();
 	}
 #endif
+	local_irq_disable();
+	if (need_resched()) {
+		local_irq_enable();
+		return;
+	}
 	local_mcck_disable();
 	if (test_thread_flag(TIF_MCCK_PENDING)) {
 		local_mcck_enable();
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/processor.c linux-libre-2.6.37-gnu/arch/s390/kernel/processor.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/processor.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/processor.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,7 @@
 	struct cpuid *id = &per_cpu(cpu_id, smp_processor_id());
 
 	pr_info("Processor %d started, address %d, identification %06X\n",
-		S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident);
+		S390_lowcore.cpu_nr, stap(), id->ident);
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/s390/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -343,7 +343,8 @@
 	return __poke_user(child, addr, data);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	ptrace_area parea; 
 	int copied, ret;
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/s390_ext.c linux-libre-2.6.37-gnu/arch/s390/kernel/s390_ext.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/s390_ext.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/s390_ext.c	2011-01-04 19:50:19.000000000 -0500
@@ -113,12 +113,15 @@
 	return 0;
 }
 
-void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
+void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+			   unsigned int param32, unsigned long param64)
 {
+	struct pt_regs *old_regs;
+	unsigned short code;
         ext_int_info_t *p;
         int index;
-	struct pt_regs *old_regs;
 
+	code = (unsigned short) ext_int_code;
 	old_regs = set_irq_regs(regs);
 	s390_idle_check(regs, S390_lowcore.int_clock,
 			S390_lowcore.async_enter_timer);
@@ -132,7 +135,7 @@
         index = ext_hash(code);
 	for (p = ext_int_hash[index]; p; p = p->next) {
 		if (likely(p->code == code))
-			p->handler(code);
+			p->handler(ext_int_code, param32, param64);
 	}
 	irq_exit();
 	set_irq_regs(old_regs);
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/setup.c linux-libre-2.6.37-gnu/arch/s390/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -409,6 +409,9 @@
 	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
 	lc->thread_info = (unsigned long) &init_thread_union;
 	lc->machine_flags = S390_lowcore.machine_flags;
+	lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
+	memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
+	       MAX_FACILITY_BIT/8);
 #ifndef CONFIG_64BIT
 	if (MACHINE_HAS_IEEE) {
 		lc->extended_save_area_addr = (__u32)
@@ -627,7 +630,8 @@
 		add_active_range(0, start_chunk, end_chunk);
 		pfn = max(start_chunk, start_pfn);
 		for (; pfn < end_chunk; pfn++)
-			page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
+			page_set_storage_key(PFN_PHYS(pfn),
+					     PAGE_DEFAULT_KEY, 0);
 	}
 
 	psw_set_key(PAGE_DEFAULT_KEY);
@@ -674,12 +678,9 @@
 static void __init setup_hwcaps(void)
 {
 	static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
-	unsigned long long facility_list_extended;
-	unsigned int facility_list;
 	struct cpuid cpu_id;
 	int i;
 
-	facility_list = stfl();
 	/*
 	 * The store facility list bits numbers as found in the principles
 	 * of operation are numbered with bit 1UL<<31 as number 0 to
@@ -699,11 +700,10 @@
 	 *   HWCAP_S390_ETF3EH bit 8 (22 && 30).
 	 */
 	for (i = 0; i < 6; i++)
-		if (facility_list & (1UL << (31 - stfl_bits[i])))
+		if (test_facility(stfl_bits[i]))
 			elf_hwcap |= 1UL << i;
 
-	if ((facility_list & (1UL << (31 - 22)))
-	    && (facility_list & (1UL << (31 - 30))))
+	if (test_facility(22) && test_facility(30))
 		elf_hwcap |= HWCAP_S390_ETF3EH;
 
 	/*
@@ -719,12 +719,8 @@
 	 * translated to:
 	 *   HWCAP_S390_DFP bit 6 (42 && 44).
 	 */
-	if ((elf_hwcap & (1UL << 2)) &&
-	    __stfle(&facility_list_extended, 1) > 0) {
-		if ((facility_list_extended & (1ULL << (63 - 42)))
-		    && (facility_list_extended & (1ULL << (63 - 44))))
-			elf_hwcap |= HWCAP_S390_DFP;
-	}
+	if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
+		elf_hwcap |= HWCAP_S390_DFP;
 
 	/*
 	 * Huge page support HWCAP_S390_HPAGE is bit 7.
@@ -765,6 +761,9 @@
 	case 0x2098:
 		strcpy(elf_platform, "z10");
 		break;
+	case 0x2817:
+		strcpy(elf_platform, "z196");
+		break;
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/smp.c linux-libre-2.6.37-gnu/arch/s390/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -156,7 +156,8 @@
  * cpus are handled.
  */
 
-static void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(unsigned int ext_int_code,
+				  unsigned int param32, unsigned long param64)
 {
 	unsigned long bits;
 
@@ -593,6 +594,8 @@
 	cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
 	cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
 	cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
+	memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
+	       MAX_FACILITY_BIT/8);
 	eieio();
 
 	while (sigp(cpu, sigp_restart) == sigp_busy)
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/sysinfo.c linux-libre-2.6.37-gnu/arch/s390/kernel/sysinfo.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/sysinfo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/sysinfo.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <asm/ebcdic.h>
 #include <asm/sysinfo.h>
 #include <asm/cpcmd.h>
+#include <asm/topology.h>
 
 /* Sigh, math-emu. Don't ask. */
 #include <asm/sfp-util.h>
@@ -74,6 +75,44 @@
 			       "Model Temp. Capacity: %-16.16s %08u\n",
 			       info->model_temp_cap,
 			       *(u32 *) info->model_temp_cap_rating);
+	if (info->cai) {
+		len += sprintf(page + len,
+			       "Capacity Adj. Ind.:   %d\n",
+			       info->cai);
+		len += sprintf(page + len, "Capacity Ch. Reason:  %d\n",
+			       info->ccr);
+	}
+	return len;
+}
+
+static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len)
+{
+	static int max_mnest;
+	int i, rc;
+
+	len += sprintf(page + len, "\n");
+	if (!MACHINE_HAS_TOPOLOGY)
+		return len;
+	if (max_mnest) {
+		stsi(info, 15, 1, max_mnest);
+	} else {
+		for (max_mnest = 6; max_mnest > 1; max_mnest--) {
+			rc = stsi(info, 15, 1, max_mnest);
+			if (rc != -ENOSYS)
+				break;
+		}
+	}
+	len += sprintf(page + len, "CPU Topology HW:     ");
+	for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+		len += sprintf(page + len, " %d", info->mag[i]);
+	len += sprintf(page + len, "\n");
+#ifdef CONFIG_SCHED_MC
+	store_topology(info);
+	len += sprintf(page + len, "CPU Topology SW:     ");
+	for (i = 0; i < TOPOLOGY_NR_MAG; i++)
+		len += sprintf(page + len, " %d", info->mag[i]);
+	len += sprintf(page + len, "\n");
+#endif
 	return len;
 }
 
@@ -87,7 +126,6 @@
 	ext = (struct sysinfo_1_2_2_extension *)
 		((unsigned long) info + info->acc_offset);
 
-	len += sprintf(page + len, "\n");
 	len += sprintf(page + len, "CPUs Total:           %d\n",
 		       info->cpus_total);
 	len += sprintf(page + len, "CPUs Configured:      %d\n",
@@ -217,6 +255,9 @@
 		len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
 
 	if (level >= 1)
+		len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len);
+
+	if (level >= 1)
 		len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
 
 	if (level >= 2)
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/time.c linux-libre-2.6.37-gnu/arch/s390/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -155,7 +155,9 @@
 	__ctl_set_bit(0, 4);
 }
 
-static void clock_comparator_interrupt(__u16 code)
+static void clock_comparator_interrupt(unsigned int ext_int_code,
+				       unsigned int param32,
+				       unsigned long param64)
 {
 	if (S390_lowcore.clock_comparator == -1ULL)
 		set_clock_comparator(S390_lowcore.clock_comparator);
@@ -164,14 +166,13 @@
 static void etr_timing_alert(struct etr_irq_parm *);
 static void stp_timing_alert(struct stp_irq_parm *);
 
-static void timing_alert_interrupt(__u16 code)
+static void timing_alert_interrupt(unsigned int ext_int_code,
+				   unsigned int param32, unsigned long param64)
 {
-	if (S390_lowcore.ext_params & 0x00c40000)
-		etr_timing_alert((struct etr_irq_parm *)
-				 &S390_lowcore.ext_params);
-	if (S390_lowcore.ext_params & 0x00038000)
-		stp_timing_alert((struct stp_irq_parm *)
-				 &S390_lowcore.ext_params);
+	if (param32 & 0x00c40000)
+		etr_timing_alert((struct etr_irq_parm *) &param32);
+	if (param32 & 0x00038000)
+		stp_timing_alert((struct stp_irq_parm *) &param32);
 }
 
 static void etr_reset(void);
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/topology.c linux-libre-2.6.37-gnu/arch/s390/kernel/topology.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/topology.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/topology.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,158 +18,140 @@
 #include <linux/cpuset.h>
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
-#include <asm/sysinfo.h>
-
-#define CPU_BITS 64
-#define NR_MAG 6
 
 #define PTF_HORIZONTAL	(0UL)
 #define PTF_VERTICAL	(1UL)
 #define PTF_CHECK	(2UL)
 
-struct tl_cpu {
-	unsigned char reserved0[4];
-	unsigned char :6;
-	unsigned char pp:2;
-	unsigned char reserved1;
-	unsigned short origin;
-	unsigned long mask[CPU_BITS / BITS_PER_LONG];
-};
-
-struct tl_container {
-	unsigned char reserved[7];
-	unsigned char id;
-};
-
-union tl_entry {
-	unsigned char nl;
-	struct tl_cpu cpu;
-	struct tl_container container;
-};
-
-struct tl_info {
-	unsigned char reserved0[2];
-	unsigned short length;
-	unsigned char mag[NR_MAG];
-	unsigned char reserved1;
-	unsigned char mnest;
-	unsigned char reserved2[4];
-	union tl_entry tle[0];
-};
-
-struct core_info {
-	struct core_info *next;
+struct mask_info {
+	struct mask_info *next;
 	unsigned char id;
 	cpumask_t mask;
 };
 
-static int topology_enabled;
+static int topology_enabled = 1;
 static void topology_work_fn(struct work_struct *work);
-static struct tl_info *tl_info;
-static struct core_info core_info;
-static int machine_has_topology;
+static struct sysinfo_15_1_x *tl_info;
 static struct timer_list topology_timer;
 static void set_topology_timer(void);
 static DECLARE_WORK(topology_work, topology_work_fn);
 /* topology_lock protects the core linked list */
 static DEFINE_SPINLOCK(topology_lock);
 
+static struct mask_info core_info;
 cpumask_t cpu_core_map[NR_CPUS];
 unsigned char cpu_core_id[NR_CPUS];
 
-static cpumask_t cpu_coregroup_map(unsigned int cpu)
+#ifdef CONFIG_SCHED_BOOK
+static struct mask_info book_info;
+cpumask_t cpu_book_map[NR_CPUS];
+unsigned char cpu_book_id[NR_CPUS];
+#endif
+
+static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
-	struct core_info *core = &core_info;
-	unsigned long flags;
 	cpumask_t mask;
 
 	cpus_clear(mask);
-	if (!topology_enabled || !machine_has_topology)
-		return cpu_possible_map;
-	spin_lock_irqsave(&topology_lock, flags);
-	while (core) {
-		if (cpu_isset(cpu, core->mask)) {
-			mask = core->mask;
+	if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) {
+		cpumask_copy(&mask, cpumask_of(cpu));
+		return mask;
+	}
+	while (info) {
+		if (cpu_isset(cpu, info->mask)) {
+			mask = info->mask;
 			break;
 		}
-		core = core->next;
+		info = info->next;
 	}
-	spin_unlock_irqrestore(&topology_lock, flags);
 	if (cpus_empty(mask))
 		mask = cpumask_of_cpu(cpu);
 	return mask;
 }
 
-const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
-{
-	return &cpu_core_map[cpu];
-}
-
-static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core)
+static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
+			     struct mask_info *book, struct mask_info *core)
 {
 	unsigned int cpu;
 
-	for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS);
-	     cpu < CPU_BITS;
-	     cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1))
+	for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS);
+	     cpu < TOPOLOGY_CPU_BITS;
+	     cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1))
 	{
 		unsigned int rcpu, lcpu;
 
-		rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
+		rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin;
 		for_each_present_cpu(lcpu) {
-			if (cpu_logical_map(lcpu) == rcpu) {
-				cpu_set(lcpu, core->mask);
-				cpu_core_id[lcpu] = core->id;
-				smp_cpu_polarization[lcpu] = tl_cpu->pp;
-			}
+			if (cpu_logical_map(lcpu) != rcpu)
+				continue;
+#ifdef CONFIG_SCHED_BOOK
+			cpu_set(lcpu, book->mask);
+			cpu_book_id[lcpu] = book->id;
+#endif
+			cpu_set(lcpu, core->mask);
+			cpu_core_id[lcpu] = core->id;
+			smp_cpu_polarization[lcpu] = tl_cpu->pp;
 		}
 	}
 }
 
-static void clear_cores(void)
+static void clear_masks(void)
 {
-	struct core_info *core = &core_info;
+	struct mask_info *info;
 
-	while (core) {
-		cpus_clear(core->mask);
-		core = core->next;
+	info = &core_info;
+	while (info) {
+		cpus_clear(info->mask);
+		info = info->next;
 	}
+#ifdef CONFIG_SCHED_BOOK
+	info = &book_info;
+	while (info) {
+		cpus_clear(info->mask);
+		info = info->next;
+	}
+#endif
 }
 
-static union tl_entry *next_tle(union tl_entry *tle)
+static union topology_entry *next_tle(union topology_entry *tle)
 {
-	if (tle->nl)
-		return (union tl_entry *)((struct tl_container *)tle + 1);
-	else
-		return (union tl_entry *)((struct tl_cpu *)tle + 1);
+	if (!tle->nl)
+		return (union topology_entry *)((struct topology_cpu *)tle + 1);
+	return (union topology_entry *)((struct topology_container *)tle + 1);
 }
 
-static void tl_to_cores(struct tl_info *info)
+static void tl_to_cores(struct sysinfo_15_1_x *info)
 {
-	union tl_entry *tle, *end;
-	struct core_info *core = &core_info;
+#ifdef CONFIG_SCHED_BOOK
+	struct mask_info *book = &book_info;
+#else
+	struct mask_info *book = NULL;
+#endif
+	struct mask_info *core = &core_info;
+	union topology_entry *tle, *end;
+
 
 	spin_lock_irq(&topology_lock);
-	clear_cores();
+	clear_masks();
 	tle = info->tle;
-	end = (union tl_entry *)((unsigned long)info + info->length);
+	end = (union topology_entry *)((unsigned long)info + info->length);
 	while (tle < end) {
 		switch (tle->nl) {
-		case 5:
-		case 4:
-		case 3:
+#ifdef CONFIG_SCHED_BOOK
 		case 2:
+			book = book->next;
+			book->id = tle->container.id;
 			break;
+#endif
 		case 1:
 			core = core->next;
 			core->id = tle->container.id;
 			break;
 		case 0:
-			add_cpus_to_core(&tle->cpu, core);
+			add_cpus_to_mask(&tle->cpu, book, core);
 			break;
 		default:
-			clear_cores();
-			machine_has_topology = 0;
+			clear_masks();
 			goto out;
 		}
 		tle = next_tle(tle);
@@ -206,7 +188,7 @@
 	int cpu;
 	int rc;
 
-	if (!machine_has_topology)
+	if (!MACHINE_HAS_TOPOLOGY)
 		return -EOPNOTSUPP;
 	if (fc)
 		rc = ptf(PTF_VERTICAL);
@@ -221,24 +203,43 @@
 
 static void update_cpu_core_map(void)
 {
+	unsigned long flags;
 	int cpu;
 
-	for_each_possible_cpu(cpu)
-		cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+	spin_lock_irqsave(&topology_lock, flags);
+	for_each_possible_cpu(cpu) {
+		cpu_core_map[cpu] = cpu_group_map(&core_info, cpu);
+#ifdef CONFIG_SCHED_BOOK
+		cpu_book_map[cpu] = cpu_group_map(&book_info, cpu);
+#endif
+	}
+	spin_unlock_irqrestore(&topology_lock, flags);
+}
+
+void store_topology(struct sysinfo_15_1_x *info)
+{
+#ifdef CONFIG_SCHED_BOOK
+	int rc;
+
+	rc = stsi(info, 15, 1, 3);
+	if (rc != -ENOSYS)
+		return;
+#endif
+	stsi(info, 15, 1, 2);
 }
 
 int arch_update_cpu_topology(void)
 {
-	struct tl_info *info = tl_info;
+	struct sysinfo_15_1_x *info = tl_info;
 	struct sys_device *sysdev;
 	int cpu;
 
-	if (!machine_has_topology) {
+	if (!MACHINE_HAS_TOPOLOGY) {
 		update_cpu_core_map();
 		topology_update_polarization_simple();
 		return 0;
 	}
-	stsi(info, 15, 1, 2);
+	store_topology(info);
 	tl_to_cores(info);
 	update_cpu_core_map();
 	for_each_online_cpu(cpu) {
@@ -275,9 +276,9 @@
 
 static int __init early_parse_topology(char *p)
 {
-	if (strncmp(p, "on", 2))
+	if (strncmp(p, "off", 3))
 		return 0;
-	topology_enabled = 1;
+	topology_enabled = 0;
 	return 0;
 }
 early_param("topology", early_parse_topology);
@@ -287,7 +288,7 @@
 	int rc;
 
 	rc = 0;
-	if (!machine_has_topology) {
+	if (!MACHINE_HAS_TOPOLOGY) {
 		topology_update_polarization_simple();
 		goto out;
 	}
@@ -299,41 +300,37 @@
 }
 __initcall(init_topology_update);
 
+static void alloc_masks(struct sysinfo_15_1_x *info, struct mask_info *mask,
+			int offset)
+{
+	int i, nr_masks;
+
+	nr_masks = info->mag[TOPOLOGY_NR_MAG - offset];
+	for (i = 0; i < info->mnest - offset; i++)
+		nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i];
+	nr_masks = max(nr_masks, 1);
+	for (i = 0; i < nr_masks; i++) {
+		mask->next = alloc_bootmem(sizeof(struct mask_info));
+		mask = mask->next;
+	}
+}
+
 void __init s390_init_cpu_topology(void)
 {
-	unsigned long long facility_bits;
-	struct tl_info *info;
-	struct core_info *core;
-	int nr_cores;
+	struct sysinfo_15_1_x *info;
 	int i;
 
-	if (stfle(&facility_bits, 1) <= 0)
-		return;
-	if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
+	if (!MACHINE_HAS_TOPOLOGY)
 		return;
-	machine_has_topology = 1;
-
 	tl_info = alloc_bootmem_pages(PAGE_SIZE);
 	info = tl_info;
-	stsi(info, 15, 1, 2);
-
-	nr_cores = info->mag[NR_MAG - 2];
-	for (i = 0; i < info->mnest - 2; i++)
-		nr_cores *= info->mag[NR_MAG - 3 - i];
-
+	store_topology(info);
 	pr_info("The CPU configuration topology of the machine is:");
-	for (i = 0; i < NR_MAG; i++)
+	for (i = 0; i < TOPOLOGY_NR_MAG; i++)
 		printk(" %d", info->mag[i]);
 	printk(" / %d\n", info->mnest);
-
-	core = &core_info;
-	for (i = 0; i < nr_cores; i++) {
-		core->next = alloc_bootmem(sizeof(struct core_info));
-		core = core->next;
-		if (!core)
-			goto error;
-	}
-	return;
-error:
-	machine_has_topology = 0;
+	alloc_masks(info, &core_info, 2);
+#ifdef CONFIG_SCHED_BOOK
+	alloc_masks(info, &book_info, 3);
+#endif
 }
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/traps.c linux-libre-2.6.37-gnu/arch/s390/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -329,27 +329,19 @@
 	return 1;
 }
 
-static void __kprobes inline do_trap(long interruption_code, int signr,
-					char *str, struct pt_regs *regs,
-					siginfo_t *info)
+static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
+				     struct pt_regs *regs, siginfo_t *info)
 {
-	/*
-	 * We got all needed information from the lowcore and can
-	 * now safely switch on interrupts.
-	 */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-		local_irq_enable();
-
-	if (notify_die(DIE_TRAP, str, regs, interruption_code,
-				interruption_code, signr) == NOTIFY_STOP)
+	if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
+		       pgm_int_code, signr) == NOTIFY_STOP)
 		return;
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code & 0xffff;
+		tsk->thread.trap_no = pgm_int_code & 0xffff;
 		force_sig_info(signr, info, tsk);
-		report_user_fault(regs, interruption_code, signr);
+		report_user_fault(regs, pgm_int_code, signr);
         } else {
                 const struct exception_table_entry *fixup;
                 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,14 +353,16 @@
 			btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
 			if (btt == BUG_TRAP_TYPE_WARN)
 				return;
-			die(str, regs, interruption_code);
+			die(str, regs, pgm_int_code);
 		}
         }
 }
 
-static inline void __user *get_check_address(struct pt_regs *regs)
+static inline void __user *get_psw_address(struct pt_regs *regs,
+					   long pgm_int_code)
 {
-	return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+	return (void __user *)
+		((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
 }
 
 void __kprobes do_single_step(struct pt_regs *regs)
@@ -381,57 +375,57 @@
 		force_sig(SIGTRAP, current);
 }
 
-static void default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
+				 unsigned long trans_exc_code)
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
-		local_irq_enable();
-		report_user_fault(regs, interruption_code, SIGSEGV);
+		report_user_fault(regs, pgm_int_code, SIGSEGV);
 		do_exit(SIGSEGV);
 	} else
-		die("Unknown program exception", regs, interruption_code);
+		die("Unknown program exception", regs, pgm_int_code);
 }
 
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-static void name(struct pt_regs * regs, long interruption_code) \
+#define DO_ERROR_INFO(name, signr, sicode, str) \
+static void name(struct pt_regs *regs, long pgm_int_code, \
+		 unsigned long trans_exc_code) \
 { \
         siginfo_t info; \
         info.si_signo = signr; \
         info.si_errno = 0; \
         info.si_code = sicode; \
-	info.si_addr = siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
+	info.si_addr = get_psw_address(regs, pgm_int_code); \
+	do_trap(pgm_int_code, signr, str, regs, &info);	    \
 }
 
-DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
-	      ILL_ILLADR, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
-	      ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
-	      FPE_INTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "fixpoint overflow exception", overflow_exception,
-	      FPE_INTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP overflow exception", hfp_overflow_exception,
-	      FPE_FLTOVF, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP underflow exception", hfp_underflow_exception,
-	      FPE_FLTUND, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP significance exception", hfp_significance_exception,
-	      FPE_FLTRES, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP divide exception", hfp_divide_exception,
-	      FPE_FLTDIV, get_check_address(regs))
-DO_ERROR_INFO(SIGFPE,  "HFP square root exception", hfp_sqrt_exception,
-	      FPE_FLTINV, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
-	      ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
-	      ILL_PRVOPC, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
-	      ILL_ILLOPN, get_check_address(regs))
-DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
-	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
+	      "addressing exception")
+DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
+	      "execute exception")
+DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
+	      "fixpoint divide exception")
+DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
+	      "fixpoint overflow exception")
+DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
+	      "HFP overflow exception")
+DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
+	      "HFP underflow exception")
+DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
+	      "HFP significance exception")
+DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
+	      "HFP divide exception")
+DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
+	      "HFP square root exception")
+DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
+	      "operand exception")
+DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
+	      "privileged operation")
+DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
+	      "special operation exception")
+DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
+	      "translation exception")
 
-static inline void
-do_fp_trap(struct pt_regs *regs, void __user *location,
-           int fpc, long interruption_code)
+static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
+			      int fpc, long pgm_int_code)
 {
 	siginfo_t si;
 
@@ -453,26 +447,19 @@
 		else if (fpc & 0x0800) /* inexact */
 			si.si_code = FPE_FLTRES;
 	}
-	current->thread.ieee_instruction_pointer = (addr_t) location;
-	do_trap(interruption_code, SIGFPE,
+	do_trap(pgm_int_code, SIGFPE,
 		"floating point exception", regs, &si);
 }
 
-static void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs *regs, long pgm_int_code,
+		       unsigned long trans_exc_code)
 {
 	siginfo_t info;
         __u8 opcode[6];
 	__u16 __user *location;
 	int signal = 0;
 
-	location = get_check_address(regs);
-
-	/*
-	 * We got all needed information from the lowcore and can
-	 * now safely switch on interrupts.
-	 */
-	if (regs->psw.mask & PSW_MASK_PSTATE)
-		local_irq_enable();
+	location = get_psw_address(regs, pgm_int_code);
 
 	if (regs->psw.mask & PSW_MASK_PSTATE) {
 		if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +499,7 @@
 		 * If we get an illegal op in kernel mode, send it through the
 		 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
 		 */
-		if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+		if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
 			       3, SIGTRAP) != NOTIFY_STOP)
 			signal = SIGILL;
 	}
@@ -520,13 +507,13 @@
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
 		do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+			   current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal == SIGSEGV) {
 		info.si_signo = signal;
 		info.si_errno = 0;
 		info.si_code = SEGV_MAPERR;
 		info.si_addr = (void __user *) location;
-		do_trap(interruption_code, signal,
+		do_trap(pgm_int_code, signal,
 			"user address fault", regs, &info);
 	} else
 #endif
@@ -535,28 +522,22 @@
 		info.si_errno = 0;
 		info.si_code = ILL_ILLOPC;
 		info.si_addr = (void __user *) location;
-		do_trap(interruption_code, signal,
+		do_trap(pgm_int_code, signal,
 			"illegal operation", regs, &info);
 	}
 }
 
 
 #ifdef CONFIG_MATHEMU
-asmlinkage void 
-specification_exception(struct pt_regs * regs, long interruption_code)
+asmlinkage void specification_exception(struct pt_regs *regs,
+					long pgm_int_code,
+					unsigned long trans_exc_code)
 {
         __u8 opcode[6];
 	__u16 __user *location = NULL;
 	int signal = 0;
 
-	location = (__u16 __user *) get_check_address(regs);
-
-	/*
-	 * We got all needed information from the lowcore and can
-	 * now safely switch on interrupts.
-	 */
-        if (regs->psw.mask & PSW_MASK_PSTATE)
-		local_irq_enable();
+	location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
 
         if (regs->psw.mask & PSW_MASK_PSTATE) {
 		get_user(*((__u16 *) opcode), location);
@@ -592,35 +573,29 @@
 
         if (signal == SIGFPE)
 		do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+			   current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal) {
 		siginfo_t info;
 		info.si_signo = signal;
 		info.si_errno = 0;
 		info.si_code = ILL_ILLOPN;
 		info.si_addr = location;
-		do_trap(interruption_code, signal, 
+		do_trap(pgm_int_code, signal,
 			"specification exception", regs, &info);
 	}
 }
 #else
-DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
-	      ILL_ILLOPN, get_check_address(regs));
+DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
+	      "specification exception");
 #endif
 
-static void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs *regs, long pgm_int_code,
+			   unsigned long trans_exc_code)
 {
 	__u16 __user *location;
 	int signal = 0;
 
-	location = get_check_address(regs);
-
-	/*
-	 * We got all needed information from the lowcore and can
-	 * now safely switch on interrupts.
-	 */
-	if (regs->psw.mask & PSW_MASK_PSTATE)
-		local_irq_enable();
+	location = get_psw_address(regs, pgm_int_code);
 
 	if (MACHINE_HAS_IEEE)
 		asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +661,19 @@
 		signal = SIGILL;
         if (signal == SIGFPE)
 		do_fp_trap(regs, location,
-                           current->thread.fp_regs.fpc, interruption_code);
+			   current->thread.fp_regs.fpc, pgm_int_code);
         else if (signal) {
 		siginfo_t info;
 		info.si_signo = signal;
 		info.si_errno = 0;
 		info.si_code = ILL_ILLOPN;
 		info.si_addr = location;
-		do_trap(interruption_code, signal, 
-			"data exception", regs, &info);
+		do_trap(pgm_int_code, signal, "data exception", regs, &info);
 	}
 }
 
-static void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
+				   unsigned long trans_exc_code)
 {
         siginfo_t info;
 
@@ -709,8 +684,8 @@
         info.si_signo = SIGILL;
         info.si_errno = 0;
         info.si_code = ILL_PRVOPC;
-        info.si_addr = get_check_address(regs);
-        do_trap(int_code, SIGILL, "space switch event", regs, &info);
+	info.si_addr = get_psw_address(regs, pgm_int_code);
+	do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
 }
 
 asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vdso32/clock_getres.S linux-libre-2.6.37-gnu/arch/s390/kernel/vdso32/clock_getres.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vdso32/clock_getres.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vdso32/clock_getres.S	2011-01-04 19:50:19.000000000 -0500
@@ -19,9 +19,9 @@
 	.type  __kernel_clock_getres,@function
 __kernel_clock_getres:
 	.cfi_startproc
-	chi	%r2,CLOCK_REALTIME
+	chi	%r2,__CLOCK_REALTIME
 	je	0f
-	chi	%r2,CLOCK_MONOTONIC
+	chi	%r2,__CLOCK_MONOTONIC
 	jne	3f
 0:	ltr	%r3,%r3
 	jz	2f				/* res == NULL */
@@ -34,6 +34,6 @@
 3:	lhi	%r1,__NR_clock_getres		/* fallback to svc */
 	svc	0
 	br	%r14
-4:	.long	CLOCK_REALTIME_RES
+4:	.long	__CLOCK_REALTIME_RES
 	.cfi_endproc
 	.size	__kernel_clock_getres,.-__kernel_clock_getres
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vdso32/clock_gettime.S linux-libre-2.6.37-gnu/arch/s390/kernel/vdso32/clock_gettime.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vdso32/clock_gettime.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vdso32/clock_gettime.S	2011-01-04 19:50:19.000000000 -0500
@@ -21,9 +21,9 @@
 	.cfi_startproc
 	basr	%r5,0
 0:	al	%r5,21f-0b(%r5)			/* get &_vdso_data */
-	chi	%r2,CLOCK_REALTIME
+	chi	%r2,__CLOCK_REALTIME
 	je	10f
-	chi	%r2,CLOCK_MONOTONIC
+	chi	%r2,__CLOCK_MONOTONIC
 	jne	19f
 
 	/* CLOCK_MONOTONIC */
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vdso64/clock_getres.S linux-libre-2.6.37-gnu/arch/s390/kernel/vdso64/clock_getres.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vdso64/clock_getres.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vdso64/clock_getres.S	2011-01-04 19:50:19.000000000 -0500
@@ -19,9 +19,9 @@
 	.type  __kernel_clock_getres,@function
 __kernel_clock_getres:
 	.cfi_startproc
-	cghi	%r2,CLOCK_REALTIME
+	cghi	%r2,__CLOCK_REALTIME
 	je	0f
-	cghi	%r2,CLOCK_MONOTONIC
+	cghi	%r2,__CLOCK_MONOTONIC
 	je	0f
 	cghi	%r2,-2		/* CLOCK_THREAD_CPUTIME_ID for this thread */
 	jne	2f
@@ -39,6 +39,6 @@
 2:	lghi	%r1,__NR_clock_getres		/* fallback to svc */
 	svc	0
 	br	%r14
-3:	.quad	CLOCK_REALTIME_RES
+3:	.quad	__CLOCK_REALTIME_RES
 	.cfi_endproc
 	.size	__kernel_clock_getres,.-__kernel_clock_getres
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vdso64/clock_gettime.S linux-libre-2.6.37-gnu/arch/s390/kernel/vdso64/clock_gettime.S
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vdso64/clock_gettime.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vdso64/clock_gettime.S	2011-01-04 19:50:19.000000000 -0500
@@ -20,11 +20,11 @@
 __kernel_clock_gettime:
 	.cfi_startproc
 	larl	%r5,_vdso_data
-	cghi	%r2,CLOCK_REALTIME
+	cghi	%r2,__CLOCK_REALTIME
 	je	4f
 	cghi	%r2,-2		/* CLOCK_THREAD_CPUTIME_ID for this thread */
 	je	9f
-	cghi	%r2,CLOCK_MONOTONIC
+	cghi	%r2,__CLOCK_MONOTONIC
 	jne	12f
 
 	/* CLOCK_MONOTONIC */
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vdso.c linux-libre-2.6.37-gnu/arch/s390/kernel/vdso.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vdso.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vdso.c	2011-01-04 19:50:19.000000000 -0500
@@ -84,11 +84,7 @@
  */
 static void vdso_init_data(struct vdso_data *vd)
 {
-	unsigned int facility_list;
-
-	facility_list = stfl();
-	vd->ectg_available =
-		user_mode != HOME_SPACE_MODE && (facility_list & 1);
+	vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
 }
 
 #ifdef CONFIG_64BIT
diff -druN linux-libre-2.6.36-gnu/arch/s390/kernel/vtime.c linux-libre-2.6.37-gnu/arch/s390/kernel/vtime.c
--- linux-libre-2.6.36-gnu/arch/s390/kernel/vtime.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kernel/vtime.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/rcupdate.h>
 #include <linux/posix-timers.h>
+#include <linux/cpu.h>
 
 #include <asm/s390_ext.h>
 #include <asm/timer.h>
@@ -314,7 +315,8 @@
 /*
  * Handler for the virtual CPU timer.
  */
-static void do_cpu_timer_interrupt(__u16 error_code)
+static void do_cpu_timer_interrupt(unsigned int ext_int_code,
+				   unsigned int param32, unsigned long param64)
 {
 	struct vtimer_queue *vq;
 	struct vtimer_list *event, *tmp;
@@ -565,6 +567,23 @@
 	__ctl_set_bit(0,10);
 }
 
+static int __cpuinit s390_nohz_notify(struct notifier_block *self,
+				      unsigned long action, void *hcpu)
+{
+	struct s390_idle_data *idle;
+	long cpu = (long) hcpu;
+
+	idle = &per_cpu(s390_idle, cpu);
+	switch (action) {
+	case CPU_DYING:
+	case CPU_DYING_FROZEN:
+		idle->nohz_delay = 0;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
 void __init vtime_init(void)
 {
 	/* request the cpu timer external interrupt */
@@ -573,5 +592,6 @@
 
 	/* Enable cpu timer interrupts on the boot cpu. */
 	init_cpu_vtimer();
+	cpu_notifier(s390_nohz_notify, 0);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/kvm/kvm-s390.c linux-libre-2.6.37-gnu/arch/s390/kvm/kvm-s390.c
--- linux-libre-2.6.36-gnu/arch/s390/kvm/kvm-s390.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kvm/kvm-s390.c	2011-01-04 19:50:19.000000000 -0500
@@ -740,8 +740,8 @@
 		kvm_exit();
 		return -ENOMEM;
 	}
-	stfle(facilities, 1);
-	facilities[0] &= 0xff00fff3f0700000ULL;
+	memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
+	facilities[0] &= 0xff00fff3f47c0000ULL;
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/kvm/priv.c linux-libre-2.6.37-gnu/arch/s390/kvm/priv.c
--- linux-libre-2.6.36-gnu/arch/s390/kvm/priv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/kvm/priv.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,12 +154,12 @@
 
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
-	unsigned int facility_list = stfl();
+	unsigned int facility_list;
 	int rc;
 
 	vcpu->stat.instruction_stfl++;
 	/* only pass the facility bits, which we can handle */
-	facility_list &= 0xff00fff3;
+	facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
 
 	rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
 			   &facility_list, sizeof(facility_list));
diff -druN linux-libre-2.6.36-gnu/arch/s390/lib/delay.c linux-libre-2.6.37-gnu/arch/s390/lib/delay.c
--- linux-libre-2.6.36-gnu/arch/s390/lib/delay.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/lib/delay.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,17 +29,21 @@
 {
 	unsigned long mask, cr0, cr0_saved;
 	u64 clock_saved;
+	u64 end;
 
+	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+	end = get_clock() + (usecs << 12);
 	clock_saved = local_tick_disable();
-	set_clock_comparator(get_clock() + (usecs << 12));
 	__ctl_store(cr0_saved, 0, 0);
 	cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
 	__ctl_load(cr0 , 0, 0);
-	mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
 	lockdep_off();
-	trace_hardirqs_on();
-	__load_psw_mask(mask);
-	local_irq_disable();
+	do {
+		set_clock_comparator(end);
+		trace_hardirqs_on();
+		__load_psw_mask(mask);
+		local_irq_disable();
+	} while (get_clock() < end);
 	lockdep_on();
 	__ctl_load(cr0_saved, 0, 0);
 	local_tick_enable(clock_saved);
diff -druN linux-libre-2.6.36-gnu/arch/s390/Makefile linux-libre-2.6.37-gnu/arch/s390/Makefile
--- linux-libre-2.6.36-gnu/arch/s390/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
 cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
 cflags-$(CONFIG_MARCH_Z10) += $(call cc-option,-march=z10)
+cflags-$(CONFIG_MARCH_Z196) += $(call cc-option,-march=z196)
 
 #KBUILD_IMAGE is necessary for make rpm
 KBUILD_IMAGE	:=arch/s390/boot/image
@@ -94,8 +95,8 @@
 head-y		+= arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o)
 head-y		+= arch/s390/kernel/init_task.o
 
-core-y		+= arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
-		   arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
+# See arch/s390/Kbuild for content of core part of the kernel
+core-y		+= arch/s390/
 
 libs-y		+= arch/s390/lib/
 drivers-y	+= drivers/s390/
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/cmm.c linux-libre-2.6.37-gnu/arch/s390/mm/cmm.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/cmm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/cmm.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,10 @@
 #include <asm/pgalloc.h>
 #include <asm/diag.h>
 
-static char *sender = "VMRMSVM";
+#ifdef CONFIG_CMM_IUCV
+static char *cmm_default_sender = "VMRMSVM";
+#endif
+static char *sender;
 module_param(sender, charp, 0400);
 MODULE_PARM_DESC(sender,
 		 "Guest name that may send SMSG messages (default VMRMSVM)");
@@ -440,6 +443,8 @@
 		int len = strlen(sender);
 		while (len--)
 			sender[len] = toupper(sender[len]);
+	} else {
+		sender = cmm_default_sender;
 	}
 
 	rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/fault.c linux-libre-2.6.37-gnu/arch/s390/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,6 +52,14 @@
 #define VM_FAULT_BADMAP		0x020000
 #define VM_FAULT_BADACCESS	0x040000
 
+static unsigned long store_indication;
+
+void fault_init(void)
+{
+	if (test_facility(2) && test_facility(75))
+		store_indication = 0xc00;
+}
+
 static inline int notify_page_fault(struct pt_regs *regs)
 {
 	int ret = 0;
@@ -199,14 +207,21 @@
 			       unsigned long trans_exc_code)
 {
 	struct task_struct *tsk = current;
+	unsigned long address;
+	struct siginfo si;
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	tsk->thread.prot_addr = trans_exc_code & __FAIL_ADDR_MASK;
+	address = trans_exc_code & __FAIL_ADDR_MASK;
+	tsk->thread.prot_addr = address;
 	tsk->thread.trap_no = int_code;
-	force_sig(SIGBUS, tsk);
+	si.si_signo = SIGBUS;
+	si.si_errno = 0;
+	si.si_code = BUS_ADRERR;
+	si.si_addr = (void __user *) address;
+	force_sig_info(SIGBUS, &si, tsk);
 }
 
 #ifdef CONFIG_S390_EXEC_PROTECT
@@ -266,10 +281,11 @@
 		if (fault & VM_FAULT_OOM)
 			pagefault_out_of_memory();
 		else if (fault & VM_FAULT_SIGBUS) {
-			do_sigbus(regs, int_code, trans_exc_code);
 			/* Kernel mode? Handle exceptions or die */
 			if (!(regs->psw.mask & PSW_MASK_PSTATE))
 				do_no_context(regs, int_code, trans_exc_code);
+			else
+				do_sigbus(regs, int_code, trans_exc_code);
 		} else
 			BUG();
 		break;
@@ -294,7 +310,7 @@
 	struct mm_struct *mm;
 	struct vm_area_struct *vma;
 	unsigned long address;
-	int fault;
+	int fault, write;
 
 	if (notify_page_fault(regs))
 		return 0;
@@ -312,12 +328,6 @@
 		goto out;
 
 	address = trans_exc_code & __FAIL_ADDR_MASK;
-	/*
-	 * When we get here, the fault happened in the current
-	 * task's user address space, so we can switch on the
-	 * interrupts again and then search the VMAs
-	 */
-	local_irq_enable();
 	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
 	down_read(&mm->mmap_sem);
 
@@ -348,8 +358,10 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	fault = handle_mm_fault(mm, vma, address,
-				(access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+	write = (access == VM_WRITE ||
+		 (trans_exc_code & store_indication) == 0x400) ?
+		FAULT_FLAG_WRITE : 0;
+	fault = handle_mm_fault(mm, vma, address, write);
 	if (unlikely(fault & VM_FAULT_ERROR))
 		goto out_up;
 
@@ -374,20 +386,20 @@
 	return fault;
 }
 
-void __kprobes do_protection_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_protection_exception(struct pt_regs *regs, long pgm_int_code,
+				       unsigned long trans_exc_code)
 {
-	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
 	int fault;
 
 	/* Protection exception is supressing, decrement psw address. */
-	regs->psw.addr -= (int_code >> 16);
+	regs->psw.addr -= (pgm_int_code >> 16);
 	/*
 	 * Check for low-address protection.  This needs to be treated
 	 * as a special case because the translation exception code
 	 * field is not guaranteed to contain valid data in this case.
 	 */
 	if (unlikely(!(trans_exc_code & 4))) {
-		do_low_address(regs, int_code, trans_exc_code);
+		do_low_address(regs, pgm_int_code, trans_exc_code);
 		return;
 	}
 	fault = do_exception(regs, VM_WRITE, trans_exc_code);
@@ -395,9 +407,9 @@
 		do_fault_error(regs, 4, trans_exc_code, fault);
 }
 
-void __kprobes do_dat_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
+				unsigned long trans_exc_code)
 {
-	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
 	int access, fault;
 
 	access = VM_READ | VM_EXEC | VM_WRITE;
@@ -408,21 +420,19 @@
 #endif
 	fault = do_exception(regs, access, trans_exc_code);
 	if (unlikely(fault))
-		do_fault_error(regs, int_code & 255, trans_exc_code, fault);
+		do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
 }
 
 #ifdef CONFIG_64BIT
-void __kprobes do_asce_exception(struct pt_regs *regs, long int_code)
+void __kprobes do_asce_exception(struct pt_regs *regs, long pgm_int_code,
+				 unsigned long trans_exc_code)
 {
-	unsigned long trans_exc_code = S390_lowcore.trans_exc_code;
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
 
 	if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
 		goto no_context;
 
-	local_irq_enable();
-
 	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, trans_exc_code & __FAIL_ADDR_MASK);
 	up_read(&mm->mmap_sem);
@@ -434,16 +444,16 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (regs->psw.mask & PSW_MASK_PSTATE) {
-		do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
+		do_sigsegv(regs, pgm_int_code, SEGV_MAPERR, trans_exc_code);
 		return;
 	}
 
 no_context:
-	do_no_context(regs, int_code, trans_exc_code);
+	do_no_context(regs, pgm_int_code, trans_exc_code);
 }
 #endif
 
-int __handle_fault(unsigned long uaddr, unsigned long int_code, int write_user)
+int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
 {
 	struct pt_regs regs;
 	int access, fault;
@@ -454,14 +464,14 @@
 	regs.psw.addr = (unsigned long) __builtin_return_address(0);
 	regs.psw.addr |= PSW_ADDR_AMODE;
 	uaddr &= PAGE_MASK;
-	access = write_user ? VM_WRITE : VM_READ;
+	access = write ? VM_WRITE : VM_READ;
 	fault = do_exception(&regs, access, uaddr | 2);
 	if (unlikely(fault)) {
 		if (fault & VM_FAULT_OOM) {
 			pagefault_out_of_memory();
 			fault = 0;
 		} else if (fault & VM_FAULT_SIGBUS)
-			do_sigbus(&regs, int_code, uaddr);
+			do_sigbus(&regs, pgm_int_code, uaddr);
 	}
 	return fault ? -EFAULT : 0;
 }
@@ -527,7 +537,8 @@
 		: : "a" (&refbk), "m" (refbk) : "cc");
 }
 
-static void pfault_interrupt(__u16 int_code)
+static void pfault_interrupt(unsigned int ext_int_code,
+			     unsigned int param32, unsigned long param64)
 {
 	struct task_struct *tsk;
 	__u16 subcode;
@@ -538,14 +549,18 @@
 	 * in the 'cpu address' field associated with the
          * external interrupt. 
 	 */
-	subcode = S390_lowcore.cpu_addr;
+	subcode = ext_int_code >> 16;
 	if ((subcode & 0xff00) != __SUBCODE_MASK)
 		return;
 
 	/*
 	 * Get the token (= address of the task structure of the affected task).
 	 */
-	tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
+#ifdef CONFIG_64BIT
+	tsk = *(struct task_struct **) param64;
+#else
+	tsk = *(struct task_struct **) param32;
+#endif
 
 	if (subcode & 0x0080) {
 		/* signal bit is set -> a page has been swapped in by VM */
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/gup.c linux-libre-2.6.37-gnu/arch/s390/mm/gup.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/gup.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/s390/mm/gup.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,224 @@
+/*
+ *  Lockless get_user_pages_fast for s390
+ *
+ *  Copyright IBM Corp. 2010
+ *  Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/vmstat.h>
+#include <linux/pagemap.h>
+#include <linux/rwsem.h>
+#include <asm/pgtable.h>
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+		unsigned long end, int write, struct page **pages, int *nr)
+{
+	unsigned long mask;
+	pte_t *ptep, pte;
+	struct page *page;
+
+	mask = (write ? _PAGE_RO : 0) | _PAGE_INVALID | _PAGE_SPECIAL;
+
+	ptep = ((pte_t *) pmd_deref(pmd)) + pte_index(addr);
+	do {
+		pte = *ptep;
+		barrier();
+		if ((pte_val(pte) & mask) != 0)
+			return 0;
+		VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+		page = pte_page(pte);
+		if (!page_cache_get_speculative(page))
+			return 0;
+		if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+			put_page(page);
+			return 0;
+		}
+		pages[*nr] = page;
+		(*nr)++;
+
+	} while (ptep++, addr += PAGE_SIZE, addr != end);
+
+	return 1;
+}
+
+static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+		unsigned long end, int write, struct page **pages, int *nr)
+{
+	unsigned long mask, result;
+	struct page *head, *page;
+	int refs;
+
+	result = write ? 0 : _SEGMENT_ENTRY_RO;
+	mask = result | _SEGMENT_ENTRY_INV;
+	if ((pmd_val(pmd) & mask) != result)
+		return 0;
+	VM_BUG_ON(!pfn_valid(pmd_val(pmd) >> PAGE_SHIFT));
+
+	refs = 0;
+	head = pmd_page(pmd);
+	page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+	do {
+		VM_BUG_ON(compound_head(page) != head);
+		pages[*nr] = page;
+		(*nr)++;
+		page++;
+		refs++;
+	} while (addr += PAGE_SIZE, addr != end);
+
+	if (!page_cache_add_speculative(head, refs)) {
+		*nr -= refs;
+		return 0;
+	}
+
+	if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
+		*nr -= refs;
+		while (refs--)
+			put_page(head);
+	}
+
+	return 1;
+}
+
+
+static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
+		unsigned long end, int write, struct page **pages, int *nr)
+{
+	unsigned long next;
+	pmd_t *pmdp, pmd;
+
+	pmdp = (pmd_t *) pudp;
+#ifdef CONFIG_64BIT
+	if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+		pmdp = (pmd_t *) pud_deref(pud);
+	pmdp += pmd_index(addr);
+#endif
+	do {
+		pmd = *pmdp;
+		barrier();
+		next = pmd_addr_end(addr, end);
+		if (pmd_none(pmd))
+			return 0;
+		if (unlikely(pmd_huge(pmd))) {
+			if (!gup_huge_pmd(pmdp, pmd, addr, next,
+					  write, pages, nr))
+				return 0;
+		} else if (!gup_pte_range(pmdp, pmd, addr, next,
+					  write, pages, nr))
+			return 0;
+	} while (pmdp++, addr = next, addr != end);
+
+	return 1;
+}
+
+static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr,
+		unsigned long end, int write, struct page **pages, int *nr)
+{
+	unsigned long next;
+	pud_t *pudp, pud;
+
+	pudp = (pud_t *) pgdp;
+#ifdef CONFIG_64BIT
+	if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
+		pudp = (pud_t *) pgd_deref(pgd);
+	pudp += pud_index(addr);
+#endif
+	do {
+		pud = *pudp;
+		barrier();
+		next = pud_addr_end(addr, end);
+		if (pud_none(pud))
+			return 0;
+		if (!gup_pmd_range(pudp, pud, addr, next, write, pages, nr))
+			return 0;
+	} while (pudp++, addr = next, addr != end);
+
+	return 1;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:	starting user address
+ * @nr_pages:	number of pages from start to pin
+ * @write:	whether pages will be written to
+ * @pages:	array that receives pointers to the pages pinned.
+ *		Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+			struct page **pages)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr, len, end;
+	unsigned long next;
+	pgd_t *pgdp, pgd;
+	int nr = 0;
+
+	start &= PAGE_MASK;
+	addr = start;
+	len = (unsigned long) nr_pages << PAGE_SHIFT;
+	end = start + len;
+	if (end < start)
+		goto slow_irqon;
+
+	/*
+	 * local_irq_disable() doesn't prevent pagetable teardown, but does
+	 * prevent the pagetables from being freed on s390.
+	 *
+	 * So long as we atomically load page table pointers versus teardown,
+	 * we can follow the address down to the the page and take a ref on it.
+	 */
+	local_irq_disable();
+	pgdp = pgd_offset(mm, addr);
+	do {
+		pgd = *pgdp;
+		barrier();
+		next = pgd_addr_end(addr, end);
+		if (pgd_none(pgd))
+			goto slow;
+		if (!gup_pud_range(pgdp, pgd, addr, next, write, pages, &nr))
+			goto slow;
+	} while (pgdp++, addr = next, addr != end);
+	local_irq_enable();
+
+	VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+	return nr;
+
+	{
+		int ret;
+slow:
+		local_irq_enable();
+slow_irqon:
+		/* Try to get the remaining pages with get_user_pages */
+		start += nr << PAGE_SHIFT;
+		pages += nr;
+
+		down_read(&mm->mmap_sem);
+		ret = get_user_pages(current, mm, start,
+			(end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+		up_read(&mm->mmap_sem);
+
+		/* Have to be a bit careful with return values */
+		if (nr > 0) {
+			if (ret < 0)
+				ret = nr;
+			else
+				ret += nr;
+		}
+
+		return ret;
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/hugetlbpage.c linux-libre-2.6.37-gnu/arch/s390/mm/hugetlbpage.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/hugetlbpage.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/hugetlbpage.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,7 +68,7 @@
 	ptep = (pte_t *) page[1].index;
 	if (!ptep)
 		return;
-	pte_free(&init_mm, ptep);
+	page_table_free(&init_mm, (unsigned long *) ptep);
 	page[1].index = 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/init.c linux-libre-2.6.37-gnu/arch/s390/mm/init.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,19 +38,59 @@
 #include <asm/tlbflush.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 
-char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned long empty_zero_page, zero_page_mask;
 EXPORT_SYMBOL(empty_zero_page);
 
+static unsigned long setup_zero_pages(void)
+{
+	struct cpuid cpu_id;
+	unsigned int order;
+	unsigned long size;
+	struct page *page;
+	int i;
+
+	get_cpu_id(&cpu_id);
+	switch (cpu_id.machine) {
+	case 0x9672:	/* g5 */
+	case 0x2064:	/* z900 */
+	case 0x2066:	/* z900 */
+	case 0x2084:	/* z990 */
+	case 0x2086:	/* z990 */
+	case 0x2094:	/* z9-109 */
+	case 0x2096:	/* z9-109 */
+		order = 0;
+		break;
+	case 0x2097:	/* z10 */
+	case 0x2098:	/* z10 */
+	default:
+		order = 2;
+		break;
+	}
+
+	empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+	if (!empty_zero_page)
+		panic("Out of memory in setup_zero_pages");
+
+	page = virt_to_page((void *) empty_zero_page);
+	split_page(page, order);
+	for (i = 1 << order; i > 0; i--) {
+		SetPageReserved(page);
+		page++;
+	}
+
+	size = PAGE_SIZE << order;
+	zero_page_mask = (size - 1) & PAGE_MASK;
+
+	return 1UL << order;
+}
+
 /*
  * paging_init() sets up the page tables
  */
 void __init paging_init(void)
 {
-	static const int ssm_mask = 0x04000000L;
 	unsigned long max_zone_pfns[MAX_NR_ZONES];
 	unsigned long pgd_type;
 
@@ -72,7 +112,7 @@
 	__ctl_load(S390_lowcore.kernel_asce, 1, 1);
 	__ctl_load(S390_lowcore.kernel_asce, 7, 7);
 	__ctl_load(S390_lowcore.kernel_asce, 13, 13);
-	__raw_local_irq_ssm(ssm_mask);
+	arch_local_irq_restore(4UL << (BITS_PER_LONG - 8));
 
 	atomic_set(&init_mm.context.attach_count, 1);
 
@@ -84,6 +124,7 @@
 #endif
 	max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
 	free_area_init_nodes(max_zone_pfns);
+	fault_init();
 }
 
 void __init mem_init(void)
@@ -93,14 +134,12 @@
         max_mapnr = num_physpages = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
-        /* clear the zero-page */
-        memset(empty_zero_page, 0, PAGE_SIZE);
-
 	/* Setup guest page hinting */
 	cmma_init();
 
 	/* this will put all low memory onto the freelists */
 	totalram_pages += free_all_bootmem();
+	totalram_pages -= setup_zero_pages();	/* Setup zeroed pages. */
 
 	reservedpages = 0;
 
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/maccess.c linux-libre-2.6.37-gnu/arch/s390/mm/maccess.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/maccess.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/maccess.c	2011-01-04 19:50:19.000000000 -0500
@@ -71,7 +71,7 @@
 
 	if (!count)
 		return 0;
-	flags = __raw_local_irq_stnsm(0xf8UL);
+	flags = __arch_local_irq_stnsm(0xf8UL);
 	asm volatile (
 		"0:	mvcle	%1,%2,0x0\n"
 		"1:	jo	0b\n"
@@ -82,6 +82,6 @@
 		  "+d" (_len2), "=m" (*((long *) dest))
 		: "m" (*((long *) src))
 		: "cc", "memory");
-	__raw_local_irq_ssm(flags);
+	arch_local_irq_restore(flags);
 	return rc;
 }
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/Makefile linux-libre-2.6.37-gnu/arch/s390/mm/Makefile
--- linux-libre-2.6.36-gnu/arch/s390/mm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,6 @@
 #
 
 obj-y	 := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \
-	    page-states.o
+	    page-states.o gup.o
 obj-$(CONFIG_CMM) += cmm.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff -druN linux-libre-2.6.36-gnu/arch/s390/mm/pgtable.c linux-libre-2.6.37-gnu/arch/s390/mm/pgtable.c
--- linux-libre-2.6.36-gnu/arch/s390/mm/pgtable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/s390/mm/pgtable.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/quicklist.h>
+#include <linux/rcupdate.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -23,6 +24,67 @@
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 
+struct rcu_table_freelist {
+	struct rcu_head rcu;
+	struct mm_struct *mm;
+	unsigned int pgt_index;
+	unsigned int crst_index;
+	unsigned long *table[0];
+};
+
+#define RCU_FREELIST_SIZE \
+	((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
+	  / sizeof(unsigned long))
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
+
+static void __page_table_free(struct mm_struct *mm, unsigned long *table);
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
+
+static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
+{
+	struct rcu_table_freelist **batchp = &__get_cpu_var(rcu_table_freelist);
+	struct rcu_table_freelist *batch = *batchp;
+
+	if (batch)
+		return batch;
+	batch = (struct rcu_table_freelist *) __get_free_page(GFP_ATOMIC);
+	if (batch) {
+		batch->mm = mm;
+		batch->pgt_index = 0;
+		batch->crst_index = RCU_FREELIST_SIZE;
+		*batchp = batch;
+	}
+	return batch;
+}
+
+static void rcu_table_freelist_callback(struct rcu_head *head)
+{
+	struct rcu_table_freelist *batch =
+		container_of(head, struct rcu_table_freelist, rcu);
+
+	while (batch->pgt_index > 0)
+		__page_table_free(batch->mm, batch->table[--batch->pgt_index]);
+	while (batch->crst_index < RCU_FREELIST_SIZE)
+		__crst_table_free(batch->mm, batch->table[batch->crst_index++]);
+	free_page((unsigned long) batch);
+}
+
+void rcu_table_freelist_finish(void)
+{
+	struct rcu_table_freelist *batch = __get_cpu_var(rcu_table_freelist);
+
+	if (!batch)
+		return;
+	call_rcu(&batch->rcu, rcu_table_freelist_callback);
+	__get_cpu_var(rcu_table_freelist) = NULL;
+}
+
+static void smp_sync(void *arg)
+{
+}
+
 #ifndef CONFIG_64BIT
 #define ALLOC_ORDER	1
 #define TABLES_PER_PAGE	4
@@ -78,25 +140,55 @@
 		}
 		page->index = page_to_phys(shadow);
 	}
-	spin_lock(&mm->context.list_lock);
+	spin_lock_bh(&mm->context.list_lock);
 	list_add(&page->lru, &mm->context.crst_list);
-	spin_unlock(&mm->context.list_lock);
+	spin_unlock_bh(&mm->context.list_lock);
 	return (unsigned long *) page_to_phys(page);
 }
 
-void crst_table_free(struct mm_struct *mm, unsigned long *table)
+static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
 {
 	unsigned long *shadow = get_shadow_table(table);
-	struct page *page = virt_to_page(table);
 
-	spin_lock(&mm->context.list_lock);
-	list_del(&page->lru);
-	spin_unlock(&mm->context.list_lock);
 	if (shadow)
 		free_pages((unsigned long) shadow, ALLOC_ORDER);
 	free_pages((unsigned long) table, ALLOC_ORDER);
 }
 
+void crst_table_free(struct mm_struct *mm, unsigned long *table)
+{
+	struct page *page = virt_to_page(table);
+
+	spin_lock_bh(&mm->context.list_lock);
+	list_del(&page->lru);
+	spin_unlock_bh(&mm->context.list_lock);
+	__crst_table_free(mm, table);
+}
+
+void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+	struct rcu_table_freelist *batch;
+	struct page *page = virt_to_page(table);
+
+	spin_lock_bh(&mm->context.list_lock);
+	list_del(&page->lru);
+	spin_unlock_bh(&mm->context.list_lock);
+	if (atomic_read(&mm->mm_users) < 2 &&
+	    cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+		__crst_table_free(mm, table);
+		return;
+	}
+	batch = rcu_table_freelist_get(mm);
+	if (!batch) {
+		smp_call_function(smp_sync, NULL, 1);
+		__crst_table_free(mm, table);
+		return;
+	}
+	batch->table[--batch->crst_index] = table;
+	if (batch->pgt_index >= batch->crst_index)
+		rcu_table_freelist_finish();
+}
+
 #ifdef CONFIG_64BIT
 int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
 {
@@ -108,7 +200,7 @@
 	table = crst_table_alloc(mm, mm->context.noexec);
 	if (!table)
 		return -ENOMEM;
-	spin_lock(&mm->page_table_lock);
+	spin_lock_bh(&mm->page_table_lock);
 	if (mm->context.asce_limit < limit) {
 		pgd = (unsigned long *) mm->pgd;
 		if (mm->context.asce_limit <= (1UL << 31)) {
@@ -130,7 +222,7 @@
 		mm->task_size = mm->context.asce_limit;
 		table = NULL;
 	}
-	spin_unlock(&mm->page_table_lock);
+	spin_unlock_bh(&mm->page_table_lock);
 	if (table)
 		crst_table_free(mm, table);
 	if (mm->context.asce_limit < limit)
@@ -182,7 +274,7 @@
 	unsigned long bits;
 
 	bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
-	spin_lock(&mm->context.list_lock);
+	spin_lock_bh(&mm->context.list_lock);
 	page = NULL;
 	if (!list_empty(&mm->context.pgtable_list)) {
 		page = list_first_entry(&mm->context.pgtable_list,
@@ -191,7 +283,7 @@
 			page = NULL;
 	}
 	if (!page) {
-		spin_unlock(&mm->context.list_lock);
+		spin_unlock_bh(&mm->context.list_lock);
 		page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
 		if (!page)
 			return NULL;
@@ -202,7 +294,7 @@
 			clear_table_pgstes(table);
 		else
 			clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
-		spin_lock(&mm->context.list_lock);
+		spin_lock_bh(&mm->context.list_lock);
 		list_add(&page->lru, &mm->context.pgtable_list);
 	}
 	table = (unsigned long *) page_to_phys(page);
@@ -213,10 +305,25 @@
 	page->flags |= bits;
 	if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
 		list_move_tail(&page->lru, &mm->context.pgtable_list);
-	spin_unlock(&mm->context.list_lock);
+	spin_unlock_bh(&mm->context.list_lock);
 	return table;
 }
 
+static void __page_table_free(struct mm_struct *mm, unsigned long *table)
+{
+	struct page *page;
+	unsigned long bits;
+
+	bits = ((unsigned long) table) & 15;
+	table = (unsigned long *)(((unsigned long) table) ^ bits);
+	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+	page->flags ^= bits;
+	if (!(page->flags & FRAG_MASK)) {
+		pgtable_page_dtor(page);
+		__free_page(page);
+	}
+}
+
 void page_table_free(struct mm_struct *mm, unsigned long *table)
 {
 	struct page *page;
@@ -225,7 +332,7 @@
 	bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
 	bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
 	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
-	spin_lock(&mm->context.list_lock);
+	spin_lock_bh(&mm->context.list_lock);
 	page->flags ^= bits;
 	if (page->flags & FRAG_MASK) {
 		/* Page now has some free pgtable fragments. */
@@ -234,18 +341,48 @@
 	} else
 		/* All fragments of the 4K page have been freed. */
 		list_del(&page->lru);
-	spin_unlock(&mm->context.list_lock);
+	spin_unlock_bh(&mm->context.list_lock);
 	if (page) {
 		pgtable_page_dtor(page);
 		__free_page(page);
 	}
 }
 
+void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
+{
+	struct rcu_table_freelist *batch;
+	struct page *page;
+	unsigned long bits;
+
+	if (atomic_read(&mm->mm_users) < 2 &&
+	    cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+		page_table_free(mm, table);
+		return;
+	}
+	batch = rcu_table_freelist_get(mm);
+	if (!batch) {
+		smp_call_function(smp_sync, NULL, 1);
+		page_table_free(mm, table);
+		return;
+	}
+	bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+	bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+	page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+	spin_lock_bh(&mm->context.list_lock);
+	/* Delayed freeing with rcu prevents reuse of pgtable fragments */
+	list_del_init(&page->lru);
+	spin_unlock_bh(&mm->context.list_lock);
+	table = (unsigned long *)(((unsigned long) table) | bits);
+	batch->table[batch->pgt_index++] = table;
+	if (batch->pgt_index >= batch->crst_index)
+		rcu_table_freelist_finish();
+}
+
 void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
 {
 	struct page *page;
 
-	spin_lock(&mm->context.list_lock);
+	spin_lock_bh(&mm->context.list_lock);
 	/* Free shadow region and segment tables. */
 	list_for_each_entry(page, &mm->context.crst_list, lru)
 		if (page->index) {
@@ -255,7 +392,7 @@
 	/* "Free" second halves of page tables. */
 	list_for_each_entry(page, &mm->context.pgtable_list, lru)
 		page->flags &= ~SECOND_HALVES;
-	spin_unlock(&mm->context.list_lock);
+	spin_unlock_bh(&mm->context.list_lock);
 	mm->context.noexec = 0;
 	update_mm(mm, tsk);
 }
@@ -312,6 +449,8 @@
 	tsk->mm = tsk->active_mm = mm;
 	preempt_disable();
 	update_mm(mm, tsk);
+	atomic_inc(&mm->context.attach_count);
+	atomic_dec(&old_mm->context.attach_count);
 	cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
 	preempt_enable();
 	task_unlock(tsk);
diff -druN linux-libre-2.6.36-gnu/arch/score/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/score/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/score/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/score/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,107 +3,118 @@
 
 #ifndef __ASSEMBLY__
 
-#define raw_local_irq_save(x)			\
-{						\
-	__asm__ __volatile__(			\
-		"mfcr	r8, cr0;"		\
-		"li	r9, 0xfffffffe;"	\
-		"nop;"				\
-		"mv	%0, r8;"		\
-		"and	r8, r8, r9;"		\
-		"mtcr	r8, cr0;"		\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		: "=r" (x)			\
-		:				\
-		: "r8", "r9"			\
-		);				\
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+
+	asm volatile(
+		"	mfcr	r8, cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	mv	%0, r8		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	ldi	r9, 0x1		\n"
+		"	and	%0, %0, r9	\n"
+		: "=r" (flags)
+		:
+		: "r8", "r9");
+	return flags;
 }
 
-#define raw_local_irq_restore(x)		\
-{						\
-	__asm__ __volatile__(			\
-		"mfcr	r8, cr0;"		\
-		"ldi	r9, 0x1;"		\
-		"and	%0, %0, r9;"		\
-		"or	r8, r8, %0;"		\
-		"mtcr	r8, cr0;"		\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		:				\
-		: "r"(x)			\
-		: "r8", "r9"			\
-		);				\
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags
+
+	asm volatile(
+		"	mfcr	r8, cr0		\n"
+		"	li	r9, 0xfffffffe	\n"
+		"	nop			\n"
+		"	mv	%0, r8		\n"
+		"	and	r8, r8, r9	\n"
+		"	mtcr	r8, cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		: "=r" (flags)
+		:
+		: "r8", "r9", "memory");
+
+	return flags;
 }
 
-#define raw_local_irq_enable(void)		\
-{						\
-	__asm__ __volatile__(			\
-		"mfcr\tr8,cr0;"			\
-		"nop;"				\
-		"nop;"				\
-		"ori\tr8,0x1;"			\
-		"mtcr\tr8,cr0;"			\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		:				\
-		:				\
-		: "r8");			\
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile(
+		"	mfcr	r8, cr0		\n"
+		"	ldi	r9, 0x1		\n"
+		"	and	%0, %0, r9	\n"
+		"	or	r8, r8, %0	\n"
+		"	mtcr	r8, cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		:
+		: "r"(flags)
+		: "r8", "r9", "memory");
 }
 
-#define raw_local_irq_disable(void)		\
-{						\
-	__asm__ __volatile__(			\
-		"mfcr\tr8,cr0;"			\
-		"nop;"				\
-		"nop;"				\
-		"srli\tr8,r8,1;"		\
-		"slli\tr8,r8,1;"		\
-		"mtcr\tr8,cr0;"			\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		:				\
-		:				\
-		: "r8");			\
+static inline void arch_local_irq_enable(void)
+{
+	asm volatile(
+		"	mfcr	r8,cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	ori	r8,0x1		\n"
+		"	mtcr	r8,cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		:
+		:
+		: "r8", "memory");
 }
 
-#define raw_local_save_flags(x)			\
-{						\
-	__asm__ __volatile__(			\
-		"mfcr	r8, cr0;"		\
-		"nop;"				\
-		"nop;"				\
-		"mv	%0, r8;"		\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"nop;"				\
-		"ldi	r9, 0x1;"		\
-		"and	%0, %0, r9;"		\
-		: "=r" (x)			\
-		:				\
-		: "r8", "r9"			\
-		);				\
+static inline void arch_local_irq_disable(void)
+{
+	asm volatile(
+		"	mfcr	r8,cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	srli	r8,r8,1		\n"
+		"	slli	r8,r8,1		\n"
+		"	mtcr	r8,cr0		\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		"	nop			\n"
+		:
+		:
+		: "r8", "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
 	return !(flags & 1);
 }
 
-#endif
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_SCORE_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/score/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/score/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/score/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/score/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -88,10 +88,7 @@
 
 #define pte_offset_map(dir, address)	\
 	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
-#define pte_offset_map_nested(dir, address)	\
-	((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address))
 #define pte_unmap(pte) ((void)(pte))
-#define pte_unmap_nested(pte) ((void)(pte))
 
 /*
  * Bits 9(_PAGE_PRESENT) and 10(_PAGE_FILE)are taken,
diff -druN linux-libre-2.6.36-gnu/arch/score/Kconfig linux-libre-2.6.37-gnu/arch/score/Kconfig
--- linux-libre-2.6.36-gnu/arch/score/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/score/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,3 @@
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-
-mainmenu "Linux/SCORE Kernel Configuration"
-
 menu "Machine selection"
 
 choice
diff -druN linux-libre-2.6.36-gnu/arch/score/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/score/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/score/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/score/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -325,7 +325,8 @@
 }
 
 long
-arch_ptrace(struct task_struct *child, long request, long addr, long data)
+arch_ptrace(struct task_struct *child, long request,
+	    unsigned long addr, unsigned long data)
 {
 	int ret;
 	unsigned long __user *datap = (void __user *)data;
@@ -335,14 +336,14 @@
 		ret = copy_regset_to_user(child, &user_score_native_view,
 						REGSET_GENERAL,
 						0, sizeof(struct pt_regs),
-						(void __user *)datap);
+						datap);
 		break;
 
 	case PTRACE_SETREGS:
 		ret = copy_regset_from_user(child, &user_score_native_view,
 						REGSET_GENERAL,
 						0, sizeof(struct pt_regs),
-						(const void __user *)datap);
+						datap);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/board-edosk7705.c linux-libre-2.6.37-gnu/arch/sh/boards/board-edosk7705.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/board-edosk7705.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/board-edosk7705.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,78 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smc91x.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+
+#define SMC_IOBASE	0xA2000000
+#define SMC_IO_OFFSET	0x300
+#define SMC_IOADDR	(SMC_IOBASE + SMC_IO_OFFSET)
+
+#define ETHERNET_IRQ	0x09
+
+static void __init sh_edosk7705_init_irq(void)
+{
+	make_imask_irq(ETHERNET_IRQ);
+}
+
+/* eth initialization functions */
+static struct smc91x_platdata smc91x_info = {
+	.flags = SMC91X_USE_16BIT | SMC91X_IO_SHIFT_1 | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static struct resource smc91x_res[] = {
+	[0] = {
+		.start	= SMC_IOADDR,
+		.end	= SMC_IOADDR + SZ_32 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= ETHERNET_IRQ,
+		.end	= ETHERNET_IRQ,
+		.flags	= IORESOURCE_IRQ ,
+	}
+};
+
+static struct platform_device smc91x_dev = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(smc91x_res),
+	.resource	= smc91x_res,
+
+	.dev	= {
+		.platform_data	= &smc91x_info,
+	},
+};
+
+/* platform init code */
+static struct platform_device *edosk7705_devices[] __initdata = {
+	&smc91x_dev,
+};
+
+static int __init init_edosk7705_devices(void)
+{
+	return platform_add_devices(edosk7705_devices,
+				    ARRAY_SIZE(edosk7705_devices));
+}
+__initcall(init_edosk7705_devices);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_edosk7705 __initmv = {
+	.mv_name		= "EDOSK7705",
+	.mv_nr_irqs		= 80,
+	.mv_init_irq		= sh_edosk7705_init_irq,
+};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/board-secureedge5410.c linux-libre-2.6.37-gnu/arch/sh/boards/board-secureedge5410.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/board-secureedge5410.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/board-secureedge5410.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * Based on files with the following comments:
+ *
+ *           Copyright (C) 2000  Kazumoto Kojima
+ *
+ *           Modified for 7751 Solution Engine by
+ *           Ian da Silva and Jeremy Siegel, 2001.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/machvec.h>
+#include <mach/secureedge5410.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <cpu/timer.h>
+
+unsigned short secureedge5410_ioport;
+
+/*
+ * EraseConfig handling functions
+ */
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
+{
+	ctrl_delay();	/* dummy read */
+
+	printk("SnapGear: erase switch interrupt!\n");
+
+	return IRQ_HANDLED;
+}
+
+static int __init eraseconfig_init(void)
+{
+	unsigned int irq = evt2irq(0x240);
+
+	printk("SnapGear: EraseConfig init\n");
+
+	/* Setup "EraseConfig" switch on external IRQ 0 */
+	if (request_irq(irq, eraseconfig_interrupt, IRQF_DISABLED,
+				"Erase Config", NULL))
+		printk("SnapGear: failed to register IRQ%d for Reset witch\n",
+				irq);
+	else
+		printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
+				irq);
+	return 0;
+}
+module_init(eraseconfig_init);
+
+/*
+ * Initialize IRQ setting
+ *
+ * IRL0 = erase switch
+ * IRL1 = eth0
+ * IRL2 = eth1
+ * IRL3 = crypto
+ */
+static void __init init_snapgear_IRQ(void)
+{
+	printk("Setup SnapGear IRQ/IPR ...\n");
+	/* enable individual interrupt mode for externals */
+	plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_snapgear __initmv = {
+	.mv_name		= "SnapGear SecureEdge5410",
+	.mv_nr_irqs		= 72,
+	.mv_init_irq		= init_snapgear_IRQ,
+};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/board-sh2007.c linux-libre-2.6.37-gnu/arch/sh/boards/board-sh2007.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/board-sh2007.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/board-sh2007.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,133 @@
+/*
+ * SH-2007 board support.
+ *
+ * Copyright (C) 2003, 2004  SUGIOKA Toshinobu
+ * Copyright (C) 2010  Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smsc911x.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/io.h>
+#include <asm/machvec.h>
+#include <mach/sh2007.h>
+
+struct smsc911x_platform_config smc911x_info = {
+	.flags		= SMSC911X_USE_32BIT,
+	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+	.irq_type	= SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct resource smsc9118_0_resources[] = {
+	[0] = {
+		.start	= SMC0_BASE,
+		.end	= SMC0_BASE + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x240),
+		.end	= evt2irq(0x240),
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct resource smsc9118_1_resources[] = {
+	[0] = {
+		.start	= SMC1_BASE,
+		.end	= SMC1_BASE + 0xff,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= evt2irq(0x280),
+		.end	= evt2irq(0x280),
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device smsc9118_0_device = {
+	.name		= "smsc911x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smsc9118_0_resources),
+	.resource	= smsc9118_0_resources,
+	.dev = {
+		.platform_data = &smc911x_info,
+	},
+};
+
+static struct platform_device smsc9118_1_device = {
+	.name		= "smsc911x",
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(smsc9118_1_resources),
+	.resource	= smsc9118_1_resources,
+	.dev = {
+		.platform_data = &smc911x_info,
+	},
+};
+
+static struct resource cf_resources[] = {
+	[0] = {
+		.start	= CF_BASE + CF_OFFSET,
+		.end	= CF_BASE + CF_OFFSET + 0x0f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= CF_BASE + CF_OFFSET + 0x206,
+		.end	= CF_BASE + CF_OFFSET + 0x20f,
+		.flags	= IORESOURCE_MEM,
+	},
+	[2] = {
+		.start	= evt2irq(0x2c0),
+		.end	= evt2irq(0x2c0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device cf_device  = {
+	.name		= "pata_platform",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(cf_resources),
+	.resource	= cf_resources,
+};
+
+static struct platform_device *sh2007_devices[] __initdata = {
+	&smsc9118_0_device,
+	&smsc9118_1_device,
+	&cf_device,
+};
+
+static int __init sh2007_io_init(void)
+{
+	platform_add_devices(sh2007_devices, ARRAY_SIZE(sh2007_devices));
+	return 0;
+}
+subsys_initcall(sh2007_io_init);
+
+static void __init sh2007_init_irq(void)
+{
+	plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * Initialize the board
+ */
+static void __init sh2007_setup(char **cmdline_p)
+{
+	printk(KERN_INFO "SH-2007 Setup...");
+
+	/* setup wait control registers for area 5 */
+	__raw_writel(CS5BCR_D, CS5BCR);
+	__raw_writel(CS5WCR_D, CS5WCR);
+	__raw_writel(CS5PCR_D, CS5PCR);
+
+	printk(KERN_INFO " done.\n");
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh2007 __initmv = {
+	.mv_setup		= sh2007_setup,
+	.mv_name		= "sh2007",
+	.mv_init_irq		= sh2007_init_irq,
+};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/board-sh7757lcr.c linux-libre-2.6.37-gnu/arch/sh/boards/board-sh7757lcr.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/board-sh7757lcr.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/board-sh7757lcr.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,374 @@
+/*
+ * Renesas R0P7757LC0012RL Support.
+ *
+ * Copyright (C) 2009 - 2010  Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/io.h>
+#include <cpu/sh7757.h>
+#include <asm/sh_eth.h>
+#include <asm/heartbeat.h>
+
+static struct resource heartbeat_resource = {
+	.start	= 0xffec005c,	/* PUDR */
+	.end	= 0xffec005c,
+	.flags	= IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
+};
+
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3 };
+
+static struct heartbeat_data heartbeat_data = {
+	.bit_pos	= heartbeat_bit_pos,
+	.nr_bits	= ARRAY_SIZE(heartbeat_bit_pos),
+	.flags		= HEARTBEAT_INVERTED,
+};
+
+static struct platform_device heartbeat_device = {
+	.name		= "heartbeat",
+	.id		= -1,
+	.dev	= {
+		.platform_data	= &heartbeat_data,
+	},
+	.num_resources	= 1,
+	.resource	= &heartbeat_resource,
+};
+
+/* Fast Ethernet */
+static struct resource sh_eth0_resources[] = {
+	{
+		.start  = 0xfef00000,
+		.end    = 0xfef001ff,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.start  = 84,
+		.end    = 84,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct sh_eth_plat_data sh7757_eth0_pdata = {
+	.phy = 1,
+	.edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth0_device = {
+	.name		= "sh-eth",
+	.resource	= sh_eth0_resources,
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(sh_eth0_resources),
+	.dev		= {
+		.platform_data = &sh7757_eth0_pdata,
+	},
+};
+
+static struct resource sh_eth1_resources[] = {
+	{
+		.start  = 0xfef00800,
+		.end    = 0xfef009ff,
+		.flags  = IORESOURCE_MEM,
+	}, {
+		.start  = 84,
+		.end    = 84,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct sh_eth_plat_data sh7757_eth1_pdata = {
+	.phy = 1,
+	.edmac_endian = EDMAC_LITTLE_ENDIAN,
+};
+
+static struct platform_device sh7757_eth1_device = {
+	.name		= "sh-eth",
+	.resource	= sh_eth1_resources,
+	.id		= 1,
+	.num_resources	= ARRAY_SIZE(sh_eth1_resources),
+	.dev		= {
+		.platform_data = &sh7757_eth1_pdata,
+	},
+};
+
+static struct platform_device *sh7757lcr_devices[] __initdata = {
+	&heartbeat_device,
+	&sh7757_eth0_device,
+	&sh7757_eth1_device,
+};
+
+static int __init sh7757lcr_devices_setup(void)
+{
+	/* RGMII (PTA) */
+	gpio_request(GPIO_FN_ET0_MDC, NULL);
+	gpio_request(GPIO_FN_ET0_MDIO, NULL);
+	gpio_request(GPIO_FN_ET1_MDC, NULL);
+	gpio_request(GPIO_FN_ET1_MDIO, NULL);
+
+	/* ONFI (PTB, PTZ) */
+	gpio_request(GPIO_FN_ON_NRE, NULL);
+	gpio_request(GPIO_FN_ON_NWE, NULL);
+	gpio_request(GPIO_FN_ON_NWP, NULL);
+	gpio_request(GPIO_FN_ON_NCE0, NULL);
+	gpio_request(GPIO_FN_ON_R_B0, NULL);
+	gpio_request(GPIO_FN_ON_ALE, NULL);
+	gpio_request(GPIO_FN_ON_CLE, NULL);
+
+	gpio_request(GPIO_FN_ON_DQ7, NULL);
+	gpio_request(GPIO_FN_ON_DQ6, NULL);
+	gpio_request(GPIO_FN_ON_DQ5, NULL);
+	gpio_request(GPIO_FN_ON_DQ4, NULL);
+	gpio_request(GPIO_FN_ON_DQ3, NULL);
+	gpio_request(GPIO_FN_ON_DQ2, NULL);
+	gpio_request(GPIO_FN_ON_DQ1, NULL);
+	gpio_request(GPIO_FN_ON_DQ0, NULL);
+
+	/* IRQ8 to 0 (PTB, PTC) */
+	gpio_request(GPIO_FN_IRQ8, NULL);
+	gpio_request(GPIO_FN_IRQ7, NULL);
+	gpio_request(GPIO_FN_IRQ6, NULL);
+	gpio_request(GPIO_FN_IRQ5, NULL);
+	gpio_request(GPIO_FN_IRQ4, NULL);
+	gpio_request(GPIO_FN_IRQ3, NULL);
+	gpio_request(GPIO_FN_IRQ2, NULL);
+	gpio_request(GPIO_FN_IRQ1, NULL);
+	gpio_request(GPIO_FN_IRQ0, NULL);
+
+	/* SPI0 (PTD) */
+	gpio_request(GPIO_FN_SP0_MOSI, NULL);
+	gpio_request(GPIO_FN_SP0_MISO, NULL);
+	gpio_request(GPIO_FN_SP0_SCK, NULL);
+	gpio_request(GPIO_FN_SP0_SCK_FB, NULL);
+	gpio_request(GPIO_FN_SP0_SS0, NULL);
+	gpio_request(GPIO_FN_SP0_SS1, NULL);
+	gpio_request(GPIO_FN_SP0_SS2, NULL);
+	gpio_request(GPIO_FN_SP0_SS3, NULL);
+
+	/* RMII 0/1 (PTE, PTF) */
+	gpio_request(GPIO_FN_RMII0_CRS_DV, NULL);
+	gpio_request(GPIO_FN_RMII0_TXD1, NULL);
+	gpio_request(GPIO_FN_RMII0_TXD0, NULL);
+	gpio_request(GPIO_FN_RMII0_TXEN, NULL);
+	gpio_request(GPIO_FN_RMII0_REFCLK, NULL);
+	gpio_request(GPIO_FN_RMII0_RXD1, NULL);
+	gpio_request(GPIO_FN_RMII0_RXD0, NULL);
+	gpio_request(GPIO_FN_RMII0_RX_ER, NULL);
+	gpio_request(GPIO_FN_RMII1_CRS_DV, NULL);
+	gpio_request(GPIO_FN_RMII1_TXD1, NULL);
+	gpio_request(GPIO_FN_RMII1_TXD0, NULL);
+	gpio_request(GPIO_FN_RMII1_TXEN, NULL);
+	gpio_request(GPIO_FN_RMII1_REFCLK, NULL);
+	gpio_request(GPIO_FN_RMII1_RXD1, NULL);
+	gpio_request(GPIO_FN_RMII1_RXD0, NULL);
+	gpio_request(GPIO_FN_RMII1_RX_ER, NULL);
+
+	/* eMMC (PTG) */
+	gpio_request(GPIO_FN_MMCCLK, NULL);
+	gpio_request(GPIO_FN_MMCCMD, NULL);
+	gpio_request(GPIO_FN_MMCDAT7, NULL);
+	gpio_request(GPIO_FN_MMCDAT6, NULL);
+	gpio_request(GPIO_FN_MMCDAT5, NULL);
+	gpio_request(GPIO_FN_MMCDAT4, NULL);
+	gpio_request(GPIO_FN_MMCDAT3, NULL);
+	gpio_request(GPIO_FN_MMCDAT2, NULL);
+	gpio_request(GPIO_FN_MMCDAT1, NULL);
+	gpio_request(GPIO_FN_MMCDAT0, NULL);
+
+	/* LPC (PTG, PTH, PTQ, PTU) */
+	gpio_request(GPIO_FN_SERIRQ, NULL);
+	gpio_request(GPIO_FN_LPCPD, NULL);
+	gpio_request(GPIO_FN_LDRQ, NULL);
+	gpio_request(GPIO_FN_WP, NULL);
+	gpio_request(GPIO_FN_FMS0, NULL);
+	gpio_request(GPIO_FN_LAD3, NULL);
+	gpio_request(GPIO_FN_LAD2, NULL);
+	gpio_request(GPIO_FN_LAD1, NULL);
+	gpio_request(GPIO_FN_LAD0, NULL);
+	gpio_request(GPIO_FN_LFRAME, NULL);
+	gpio_request(GPIO_FN_LRESET, NULL);
+	gpio_request(GPIO_FN_LCLK, NULL);
+	gpio_request(GPIO_FN_LGPIO7, NULL);
+	gpio_request(GPIO_FN_LGPIO6, NULL);
+	gpio_request(GPIO_FN_LGPIO5, NULL);
+	gpio_request(GPIO_FN_LGPIO4, NULL);
+
+	/* SPI1 (PTH) */
+	gpio_request(GPIO_FN_SP1_MOSI, NULL);
+	gpio_request(GPIO_FN_SP1_MISO, NULL);
+	gpio_request(GPIO_FN_SP1_SCK, NULL);
+	gpio_request(GPIO_FN_SP1_SCK_FB, NULL);
+	gpio_request(GPIO_FN_SP1_SS0, NULL);
+	gpio_request(GPIO_FN_SP1_SS1, NULL);
+
+	/* SDHI (PTI) */
+	gpio_request(GPIO_FN_SD_WP, NULL);
+	gpio_request(GPIO_FN_SD_CD, NULL);
+	gpio_request(GPIO_FN_SD_CLK, NULL);
+	gpio_request(GPIO_FN_SD_CMD, NULL);
+	gpio_request(GPIO_FN_SD_D3, NULL);
+	gpio_request(GPIO_FN_SD_D2, NULL);
+	gpio_request(GPIO_FN_SD_D1, NULL);
+	gpio_request(GPIO_FN_SD_D0, NULL);
+
+	/* SCIF3/4 (PTJ, PTW) */
+	gpio_request(GPIO_FN_RTS3, NULL);
+	gpio_request(GPIO_FN_CTS3, NULL);
+	gpio_request(GPIO_FN_TXD3, NULL);
+	gpio_request(GPIO_FN_RXD3, NULL);
+	gpio_request(GPIO_FN_RTS4, NULL);
+	gpio_request(GPIO_FN_RXD4, NULL);
+	gpio_request(GPIO_FN_TXD4, NULL);
+	gpio_request(GPIO_FN_CTS4, NULL);
+
+	/* SERMUX (PTK, PTL, PTO, PTV) */
+	gpio_request(GPIO_FN_COM2_TXD, NULL);
+	gpio_request(GPIO_FN_COM2_RXD, NULL);
+	gpio_request(GPIO_FN_COM2_RTS, NULL);
+	gpio_request(GPIO_FN_COM2_CTS, NULL);
+	gpio_request(GPIO_FN_COM2_DTR, NULL);
+	gpio_request(GPIO_FN_COM2_DSR, NULL);
+	gpio_request(GPIO_FN_COM2_DCD, NULL);
+	gpio_request(GPIO_FN_COM2_RI, NULL);
+	gpio_request(GPIO_FN_RAC_RXD, NULL);
+	gpio_request(GPIO_FN_RAC_RTS, NULL);
+	gpio_request(GPIO_FN_RAC_CTS, NULL);
+	gpio_request(GPIO_FN_RAC_DTR, NULL);
+	gpio_request(GPIO_FN_RAC_DSR, NULL);
+	gpio_request(GPIO_FN_RAC_DCD, NULL);
+	gpio_request(GPIO_FN_RAC_TXD, NULL);
+	gpio_request(GPIO_FN_COM1_TXD, NULL);
+	gpio_request(GPIO_FN_COM1_RXD, NULL);
+	gpio_request(GPIO_FN_COM1_RTS, NULL);
+	gpio_request(GPIO_FN_COM1_CTS, NULL);
+
+	writeb(0x10, 0xfe470000);	/* SMR0: SerMux mode 0 */
+
+	/* IIC (PTM, PTR, PTS) */
+	gpio_request(GPIO_FN_SDA7, NULL);
+	gpio_request(GPIO_FN_SCL7, NULL);
+	gpio_request(GPIO_FN_SDA6, NULL);
+	gpio_request(GPIO_FN_SCL6, NULL);
+	gpio_request(GPIO_FN_SDA5, NULL);
+	gpio_request(GPIO_FN_SCL5, NULL);
+	gpio_request(GPIO_FN_SDA4, NULL);
+	gpio_request(GPIO_FN_SCL4, NULL);
+	gpio_request(GPIO_FN_SDA3, NULL);
+	gpio_request(GPIO_FN_SCL3, NULL);
+	gpio_request(GPIO_FN_SDA2, NULL);
+	gpio_request(GPIO_FN_SCL2, NULL);
+	gpio_request(GPIO_FN_SDA1, NULL);
+	gpio_request(GPIO_FN_SCL1, NULL);
+	gpio_request(GPIO_FN_SDA0, NULL);
+	gpio_request(GPIO_FN_SCL0, NULL);
+
+	/* USB (PTN) */
+	gpio_request(GPIO_FN_VBUS_EN, NULL);
+	gpio_request(GPIO_FN_VBUS_OC, NULL);
+
+	/* SGPIO1/0 (PTN, PTO) */
+	gpio_request(GPIO_FN_SGPIO1_CLK, NULL);
+	gpio_request(GPIO_FN_SGPIO1_LOAD, NULL);
+	gpio_request(GPIO_FN_SGPIO1_DI, NULL);
+	gpio_request(GPIO_FN_SGPIO1_DO, NULL);
+	gpio_request(GPIO_FN_SGPIO0_CLK, NULL);
+	gpio_request(GPIO_FN_SGPIO0_LOAD, NULL);
+	gpio_request(GPIO_FN_SGPIO0_DI, NULL);
+	gpio_request(GPIO_FN_SGPIO0_DO, NULL);
+
+	/* WDT (PTN) */
+	gpio_request(GPIO_FN_SUB_CLKIN, NULL);
+
+	/* System (PTT) */
+	gpio_request(GPIO_FN_STATUS1, NULL);
+	gpio_request(GPIO_FN_STATUS0, NULL);
+
+	/* PWMX (PTT) */
+	gpio_request(GPIO_FN_PWMX1, NULL);
+	gpio_request(GPIO_FN_PWMX0, NULL);
+
+	/* R-SPI (PTV) */
+	gpio_request(GPIO_FN_R_SPI_MOSI, NULL);
+	gpio_request(GPIO_FN_R_SPI_MISO, NULL);
+	gpio_request(GPIO_FN_R_SPI_RSPCK, NULL);
+	gpio_request(GPIO_FN_R_SPI_SSL0, NULL);
+	gpio_request(GPIO_FN_R_SPI_SSL1, NULL);
+
+	/* EVC (PTV, PTW) */
+	gpio_request(GPIO_FN_EVENT7, NULL);
+	gpio_request(GPIO_FN_EVENT6, NULL);
+	gpio_request(GPIO_FN_EVENT5, NULL);
+	gpio_request(GPIO_FN_EVENT4, NULL);
+	gpio_request(GPIO_FN_EVENT3, NULL);
+	gpio_request(GPIO_FN_EVENT2, NULL);
+	gpio_request(GPIO_FN_EVENT1, NULL);
+	gpio_request(GPIO_FN_EVENT0, NULL);
+
+	/* LED for heartbeat */
+	gpio_request(GPIO_PTU3, NULL);
+	gpio_direction_output(GPIO_PTU3, 1);
+	gpio_request(GPIO_PTU2, NULL);
+	gpio_direction_output(GPIO_PTU2, 1);
+	gpio_request(GPIO_PTU1, NULL);
+	gpio_direction_output(GPIO_PTU1, 1);
+	gpio_request(GPIO_PTU0, NULL);
+	gpio_direction_output(GPIO_PTU0, 1);
+
+	/* control for MDIO of Gigabit Ethernet */
+	gpio_request(GPIO_PTT4, NULL);
+	gpio_direction_output(GPIO_PTT4, 1);
+
+	/* control for eMMC */
+	gpio_request(GPIO_PTT7, NULL);		/* eMMC_RST# */
+	gpio_direction_output(GPIO_PTT7, 0);
+	gpio_request(GPIO_PTT6, NULL);		/* eMMC_INDEX# */
+	gpio_direction_output(GPIO_PTT6, 0);
+	gpio_request(GPIO_PTT5, NULL);		/* eMMC_PRST# */
+	gpio_direction_output(GPIO_PTT5, 1);
+
+	/* General platform */
+	return platform_add_devices(sh7757lcr_devices,
+				    ARRAY_SIZE(sh7757lcr_devices));
+}
+arch_initcall(sh7757lcr_devices_setup);
+
+/* Initialize IRQ setting */
+void __init init_sh7757lcr_IRQ(void)
+{
+	plat_irq_setup_pins(IRQ_MODE_IRQ7654);
+	plat_irq_setup_pins(IRQ_MODE_IRQ3210);
+}
+
+/* Initialize the board */
+static void __init sh7757lcr_setup(char **cmdline_p)
+{
+	printk(KERN_INFO "Renesas R0P7757LC0012RL support.\n");
+}
+
+static int sh7757lcr_mode_pins(void)
+{
+	int value = 0;
+
+	/* These are the factory default settings of S3 (Low active).
+	 * If you change these dip switches then you will need to
+	 * adjust the values below as well.
+	 */
+	value |= MODE_PIN0;	/* Clock Mode: 1 */
+
+	return value;
+}
+
+/* The Machine Vector */
+static struct sh_machine_vector mv_sh7757lcr __initmv = {
+	.mv_name		= "SH7757LCR",
+	.mv_setup		= sh7757lcr_setup,
+	.mv_init_irq		= init_sh7757lcr_IRQ,
+	.mv_mode_pins		= sh7757lcr_mode_pins,
+};
+
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/Kconfig linux-libre-2.6.37-gnu/arch/sh/boards/Kconfig
--- linux-libre-2.6.36-gnu/arch/sh/boards/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -81,13 +81,6 @@
 	  Select 7343 SolutionEngine if configuring for a Hitachi
 	  SH7343 (SH-Mobile 3AS) evaluation board.
 
-config SH_7751_SYSTEMH
-	bool "SystemH7751R"
-	depends on CPU_SUBTYPE_SH7751R
-	help
-	  Select SystemH if you are configuring for a Renesas SystemH
-	  7751R evaluation board.
-
 config SH_HP6XX
 	bool "HP6XX"
 	select SYS_SUPPORTS_APM_EMULATION
@@ -155,6 +148,8 @@
 	depends on CPU_SUBTYPE_SH7786
 	select SYS_SUPPORTS_PCI
 	select NO_IOPORT if !PCI
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select HAVE_SRAM_POOL
 	help
 	  Select SDK7786 if configuring for a Renesas Technology Europe
 	  SH7786-65nm board.
@@ -165,6 +160,11 @@
 	select SYS_SUPPORTS_PCI
 	select IO_TRAPPED if MMU
 
+config SH_SH7757LCR
+	bool "SH7757LCR"
+	depends on CPU_SUBTYPE_SH7757
+	select ARCH_REQUIRE_GPIOLIB
+
 config SH_SH7785LCR
 	bool "SH7785LCR"
 	depends on CPU_SUBTYPE_SH7785
@@ -309,6 +309,17 @@
 	help
 	  Select if configuring for an SMSC Polaris development board
 
+config SH_SH2007
+	bool "SH-2007 board"
+	select NO_IOPORT
+	depends on CPU_SUBTYPE_SH7780
+	help
+	  SH-2007 is a single-board computer based around SH7780 chip
+	  intended for embedded applications.
+	  It has an Ethernet interface (SMC9118), direct connected
+	  Compact Flash socket, two serial ports and PC-104 bus.
+	  More information at <http://sh2000.sh-linux.org>.
+
 endmenu
 
 source "arch/sh/boards/mach-r2d/Kconfig"
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-ap325rxa/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-ap325rxa/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-ap325rxa/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-ap325rxa/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -176,6 +176,21 @@
 	__raw_writew(0, FPGA_LCDREG);
 }
 
+const static struct fb_videomode ap325rxa_lcdc_modes[] = {
+	{
+		.name = "LB070WV1",
+		.xres = 800,
+		.yres = 480,
+		.left_margin = 32,
+		.right_margin = 160,
+		.hsync_len = 8,
+		.upper_margin = 63,
+		.lower_margin = 80,
+		.vsync_len = 1,
+		.sync = 0, /* hsync and vsync are active low */
+	},
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
 	.clock_source = LCDC_CLK_EXTERNAL,
 	.ch[0] = {
@@ -183,18 +198,8 @@
 		.bpp = 16,
 		.interface_type = RGB18,
 		.clock_divider = 1,
-		.lcd_cfg = {
-			.name = "LB070WV1",
-			.xres = 800,
-			.yres = 480,
-			.left_margin = 32,
-			.right_margin = 160,
-			.hsync_len = 8,
-			.upper_margin = 63,
-			.lower_margin = 80,
-			.vsync_len = 1,
-			.sync = 0, /* hsync and vsync are active low */
-		},
+		.lcd_cfg = ap325rxa_lcdc_modes,
+		.num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes),
 		.lcd_size_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
@@ -481,7 +486,6 @@
 	.power		= ov7725_power,
 	.board_info	= &ap325rxa_i2c_camera[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "ov772x",
 	.priv		= &ov7725_info,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-cayman/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-cayman/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-cayman/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-cayman/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -55,8 +55,9 @@
 	.flags		= IRQF_DISABLED,
 };
 
-static void enable_cayman_irq(unsigned int irq)
+static void enable_cayman_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned long flags;
 	unsigned long mask;
 	unsigned int reg;
@@ -72,8 +73,9 @@
 	local_irq_restore(flags);
 }
 
-void disable_cayman_irq(unsigned int irq)
+static void disable_cayman_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned long flags;
 	unsigned long mask;
 	unsigned int reg;
@@ -89,16 +91,10 @@
 	local_irq_restore(flags);
 }
 
-static void ack_cayman_irq(unsigned int irq)
-{
-	disable_cayman_irq(irq);
-}
-
 struct irq_chip cayman_irq_type = {
 	.name		= "Cayman-IRQ",
-	.unmask 	= enable_cayman_irq,
-	.mask		= disable_cayman_irq,
-	.mask_ack	= ack_cayman_irq,
+	.irq_unmask	= enable_cayman_irq,
+	.irq_mask	= disable_cayman_irq,
 };
 
 int cayman_irq_demux(int evt)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-dreamcast/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-dreamcast/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-dreamcast/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-dreamcast/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,8 +60,9 @@
  */
 
 /* Disable the hardware event by masking its bit in its EMR */
-static inline void disable_systemasic_irq(unsigned int irq)
+static inline void disable_systemasic_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
 	__u32 mask;
 
@@ -71,8 +72,9 @@
 }
 
 /* Enable the hardware event by setting its bit in its EMR */
-static inline void enable_systemasic_irq(unsigned int irq)
+static inline void enable_systemasic_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
 	__u32 mask;
 
@@ -82,18 +84,19 @@
 }
 
 /* Acknowledge a hardware event by writing its bit back to its ESR */
-static void mask_ack_systemasic_irq(unsigned int irq)
+static void mask_ack_systemasic_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
-	disable_systemasic_irq(irq);
+	disable_systemasic_irq(data);
 	outl((1 << EVENT_BIT(irq)), esr);
 }
 
 struct irq_chip systemasic_int = {
 	.name		= "System ASIC",
-	.mask		= disable_systemasic_irq,
-	.mask_ack	= mask_ack_systemasic_irq,
-	.unmask		= enable_systemasic_irq,
+	.irq_mask	= disable_systemasic_irq,
+	.irq_mask_ack	= mask_ack_systemasic_irq,
+	.irq_unmask	= enable_systemasic_irq,
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-ecovec24/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-ecovec24/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-ecovec24/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-ecovec24/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -231,14 +231,41 @@
 };
 
 /* LCDC */
+const static struct fb_videomode ecovec_lcd_modes[] = {
+	{
+		.name		= "Panel",
+		.xres		= 800,
+		.yres		= 480,
+		.left_margin	= 220,
+		.right_margin	= 110,
+		.hsync_len	= 70,
+		.upper_margin	= 20,
+		.lower_margin	= 5,
+		.vsync_len	= 5,
+		.sync		= 0, /* hsync and vsync are active low */
+	},
+};
+
+const static struct fb_videomode ecovec_dvi_modes[] = {
+	{
+		.name		= "DVI",
+		.xres		= 1280,
+		.yres		= 720,
+		.left_margin	= 220,
+		.right_margin	= 110,
+		.hsync_len	= 40,
+		.upper_margin	= 20,
+		.lower_margin	= 5,
+		.vsync_len	= 5,
+		.sync = 0, /* hsync and vsync are active low */
+	},
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
 	.ch[0] = {
 		.interface_type = RGB18,
 		.chan = LCDC_CHAN_MAINLCD,
 		.bpp = 16,
-		.lcd_cfg = {
-			.sync = 0, /* hsync and vsync are active low */
-		},
 		.lcd_size_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
@@ -620,7 +647,6 @@
 	.bus_id		= 1,
 	.power		= tw9910_power,
 	.board_info	= &i2c_camera[0],
-	.module_name	= "tw9910",
 	.priv		= &tw9910_info,
 };
 
@@ -644,7 +670,6 @@
 	.power		= mt9t112_power1,
 	.bus_id		= 0,
 	.board_info	= &i2c_camera[1],
-	.module_name	= "mt9t112",
 	.priv		= &mt9t112_info1,
 };
 
@@ -667,7 +692,6 @@
 	.power		= mt9t112_power2,
 	.bus_id		= 1,
 	.board_info	= &i2c_camera[2],
-	.module_name	= "mt9t112",
 	.priv		= &mt9t112_info2,
 };
 
@@ -696,32 +720,6 @@
 };
 
 /* FSI */
-/*
- * FSI-B use external clock which came from da7210.
- * So, we should change parent of fsi
- */
-#define FCLKBCR		0xa415000c
-static void fsimck_init(struct clk *clk)
-{
-	u32 status = __raw_readl(clk->enable_reg);
-
-	/* use external clock */
-	status &= ~0x000000ff;
-	status |= 0x00000080;
-
-	__raw_writel(status, clk->enable_reg);
-}
-
-static struct clk_ops fsimck_clk_ops = {
-	.init = fsimck_init,
-};
-
-static struct clk fsimckb_clk = {
-	.ops		= &fsimck_clk_ops,
-	.enable_reg	= (void __iomem *)FCLKBCR,
-	.rate		= 0, /* unknown */
-};
-
 static struct sh_fsi_platform_info fsi_info = {
 	.portb_flags = SH_FSI_BRS_INV |
 		       SH_FSI_OUT_SLAVE_MODE |
@@ -793,7 +791,6 @@
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,
 	.i2c_adap	= 0,
-	.module_name	= "ak881x",
 };
 
 static struct resource sh_vou_resources[] = {
@@ -1079,33 +1076,18 @@
 	if (gpio_get_value(GPIO_PTE6)) {
 		/* DVI */
 		lcdc_info.clock_source			= LCDC_CLK_EXTERNAL;
-		lcdc_info.ch[0].clock_divider		= 1,
-		lcdc_info.ch[0].lcd_cfg.name		= "DVI";
-		lcdc_info.ch[0].lcd_cfg.xres		= 1280;
-		lcdc_info.ch[0].lcd_cfg.yres		= 720;
-		lcdc_info.ch[0].lcd_cfg.left_margin	= 220;
-		lcdc_info.ch[0].lcd_cfg.right_margin	= 110;
-		lcdc_info.ch[0].lcd_cfg.hsync_len	= 40;
-		lcdc_info.ch[0].lcd_cfg.upper_margin	= 20;
-		lcdc_info.ch[0].lcd_cfg.lower_margin	= 5;
-		lcdc_info.ch[0].lcd_cfg.vsync_len	= 5;
+		lcdc_info.ch[0].clock_divider		= 1;
+		lcdc_info.ch[0].lcd_cfg			= ecovec_dvi_modes;
+		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_dvi_modes);
 
 		gpio_set_value(GPIO_PTA2, 1);
 		gpio_set_value(GPIO_PTU1, 1);
 	} else {
 		/* Panel */
-
 		lcdc_info.clock_source			= LCDC_CLK_PERIPHERAL;
-		lcdc_info.ch[0].clock_divider		= 2,
-		lcdc_info.ch[0].lcd_cfg.name		= "Panel";
-		lcdc_info.ch[0].lcd_cfg.xres		= 800;
-		lcdc_info.ch[0].lcd_cfg.yres		= 480;
-		lcdc_info.ch[0].lcd_cfg.left_margin	= 220;
-		lcdc_info.ch[0].lcd_cfg.right_margin	= 110;
-		lcdc_info.ch[0].lcd_cfg.hsync_len	= 70;
-		lcdc_info.ch[0].lcd_cfg.upper_margin	= 20;
-		lcdc_info.ch[0].lcd_cfg.lower_margin	= 5;
-		lcdc_info.ch[0].lcd_cfg.vsync_len	= 5;
+		lcdc_info.ch[0].clock_divider		= 2;
+		lcdc_info.ch[0].lcd_cfg			= ecovec_lcd_modes;
+		lcdc_info.ch[0].num_cfg			= ARRAY_SIZE(ecovec_lcd_modes);
 
 		gpio_set_value(GPIO_PTR1, 1);
 
@@ -1248,18 +1230,18 @@
 
 	/* set SPU2 clock to 83.4 MHz */
 	clk = clk_get(NULL, "spu_clk");
-	if (clk) {
+	if (!IS_ERR(clk)) {
 		clk_set_rate(clk, clk_round_rate(clk, 83333333));
 		clk_put(clk);
 	}
 
 	/* change parent of FSI B */
 	clk = clk_get(NULL, "fsib_clk");
-	if (clk) {
-		clk_register(&fsimckb_clk);
-		clk_set_parent(clk, &fsimckb_clk);
-		clk_set_rate(clk, 11000);
-		clk_set_rate(&fsimckb_clk, 11000);
+	if (!IS_ERR(clk)) {
+		/* 48kHz dummy clock was used to make sure 1/1 divide */
+		clk_set_rate(&sh7724_fsimckb_clk, 48000);
+		clk_set_parent(clk, &sh7724_fsimckb_clk);
+		clk_set_rate(clk, 48000);
 		clk_put(clk);
 	}
 
@@ -1273,7 +1255,7 @@
 
 	/* set VPU clock to 166 MHz */
 	clk = clk_get(NULL, "vpu_clk");
-	if (clk) {
+	if (!IS_ERR(clk)) {
 		clk_set_rate(clk, clk_round_rate(clk, 166000000));
 		clk_put(clk);
 	}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,71 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routines for Hitachi EDOSK7705 board.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <mach/edosk7705.h>
-#include <asm/addrspace.h>
-
-#define SMC_IOADDR	0xA2000000
-
-/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
-{
-	/*
-	 * SMC91C96 registers are 4 byte aligned rather than the
-	 * usual 2 byte!
-	 */
-	if (port >= 0x300 && port < 0x320)
-		return SMC_IOADDR + ((port - 0x300) * 2);
-
-	maybebadio(port);
-	return port;
-}
-
-/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
- * registers causes problems. So we bit-shift the value and read / write
- * in 2 byte chunks. Setting the low byte to 0 does not cause problems
- * now as odd byte writes are only made on the bit mask / interrupt
- * register. This may not be the case in future Mar-2003 SJD
- */
-unsigned char sh_edosk7705_inb(unsigned long port)
-{
-	if (port >= 0x300 && port < 0x320 && port & 0x01)
-		return __raw_readw(port - 1) >> 8;
-
-	return __raw_readb(sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_outb(unsigned char value, unsigned long port)
-{
-	if (port >= 0x300 && port < 0x320 && port & 0x01) {
-		__raw_writew(((unsigned short)value << 8), port - 1);
-		return;
-	}
-
-	__raw_writeb(value, sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned char *p = addr;
-
-	while (count--)
-		*p++ = sh_edosk7705_inb(port);
-}
-
-void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned char *p = (unsigned char *)addr;
-
-	while (count--)
-		sh_edosk7705_outb(*p++, port);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,5 +0,0 @@
-#
-# Makefile for the EDOSK7705 specific parts of the kernel
-#
-
-obj-y	 := setup.o io.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-edosk7705/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-edosk7705/setup.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,36 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SolutionEngine Support.
- *
- * Modified for edosk7705 development
- * board by S. Dunn, 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/machvec.h>
-#include <mach/edosk7705.h>
-
-static void __init sh_edosk7705_init_irq(void)
-{
-	/* This is the Ethernet interrupt */
-	make_imask_irq(0x09);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_edosk7705 __initmv = {
-	.mv_name		= "EDOSK7705",
-	.mv_nr_irqs		= 80,
-
-	.mv_inb			= sh_edosk7705_inb,
-	.mv_outb		= sh_edosk7705_outb,
-
-	.mv_insb		= sh_edosk7705_insb,
-	.mv_outsb		= sh_edosk7705_outsb,
-
-	.mv_init_irq		= sh_edosk7705_init_irq,
-};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-kfr2r09/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-kfr2r09/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-kfr2r09/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-kfr2r09/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,6 +126,21 @@
 	},
 };
 
+const static struct fb_videomode kfr2r09_lcdc_modes[] = {
+	{
+		.name = "TX07D34VM0AAA",
+		.xres = 240,
+		.yres = 400,
+		.left_margin = 0,
+		.right_margin = 16,
+		.hsync_len = 8,
+		.upper_margin = 0,
+		.lower_margin = 1,
+		.vsync_len = 1,
+		.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	},
+};
+
 static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = {
 	.clock_source = LCDC_CLK_BUS,
 	.ch[0] = {
@@ -134,18 +149,8 @@
 		.interface_type = SYS18,
 		.clock_divider = 6,
 		.flags = LCDC_FLAGS_DWPOL,
-		.lcd_cfg = {
-			.name = "TX07D34VM0AAA",
-			.xres = 240,
-			.yres = 400,
-			.left_margin = 0,
-			.right_margin = 16,
-			.hsync_len = 8,
-			.upper_margin = 0,
-			.lower_margin = 1,
-			.vsync_len = 1,
-			.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-		},
+		.lcd_cfg = kfr2r09_lcdc_modes,
+		.num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes),
 		.lcd_size_cfg = {
 			.width = 35,
 			.height = 58,
@@ -333,7 +338,6 @@
 	.power		= camera_power,
 	.board_info	= &kfr2r09_i2c_camera,
 	.i2c_adapter_id	= 1,
-	.module_name	= "rj54n1cb0c",
 	.priv		= &rj54n1_priv,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-landisk/gio.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-landisk/gio.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-landisk/gio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-landisk/gio.c	2011-01-04 19:50:19.000000000 -0500
@@ -128,6 +128,7 @@
 	.open = gio_open,	/* open */
 	.release = gio_close,	/* release */
 	.unlocked_ioctl = gio_ioctl,
+	.llseek = noop_llseek,
 };
 
 static int __init gio_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-landisk/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-landisk/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-landisk/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-landisk/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,25 +18,24 @@
 #include <linux/io.h>
 #include <mach-landisk/mach/iodata_landisk.h>
 
-static void disable_landisk_irq(unsigned int irq)
+static void disable_landisk_irq(struct irq_data *data)
 {
-	unsigned char mask = 0xff ^ (0x01 << (irq - 5));
+	unsigned char mask = 0xff ^ (0x01 << (data->irq - 5));
 
 	__raw_writeb(__raw_readb(PA_IMASK) & mask, PA_IMASK);
 }
 
-static void enable_landisk_irq(unsigned int irq)
+static void enable_landisk_irq(struct irq_data *data)
 {
-	unsigned char value = (0x01 << (irq - 5));
+	unsigned char value = (0x01 << (data->irq - 5));
 
 	__raw_writeb(__raw_readb(PA_IMASK) | value, PA_IMASK);
 }
 
 static struct irq_chip landisk_irq_chip __read_mostly = {
 	.name		= "LANDISK",
-	.mask		= disable_landisk_irq,
-	.unmask		= enable_landisk_irq,
-	.mask_ack	= disable_landisk_irq,
+	.irq_mask	= disable_landisk_irq,
+	.irq_unmask	= enable_landisk_irq,
 };
 
 /*
@@ -50,7 +49,7 @@
 		disable_irq_nosync(i);
 		set_irq_chip_and_handler_name(i, &landisk_irq_chip,
 					      handle_level_irq, "level");
-		enable_landisk_irq(i);
+		enable_landisk_irq(irq_get_irq_data(i));
 	}
 	__raw_writeb(0x00, PA_PWRINT_CLR);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/io.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,7 @@
 /*
  * map I/O ports to memory-mapped addresses
  */
-static unsigned long microdev_isa_port2addr(unsigned long offset)
+void __iomem *microdev_ioport_map(unsigned long offset, unsigned int len)
 {
 	unsigned long result;
 
@@ -72,16 +72,6 @@
 			 *	Configuration Registers
 			 */
 		result = IO_SUPERIO_PHYS + (offset << 1);
-#if 0
-	} else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
-		   offset == KBD_STATUS_REG) {
-			/*
-			 *	SMSC FDC37C93xAPM SuperIO chip
-			 *
-			 *	PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
-			 */
-	        result = IO_SUPERIO_PHYS + (offset << 1);
-#endif
 	} else if (((offset >= IO_IDE1_BASE) &&
 		    (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
 		    (offset == IO_IDE1_MISC)) {
@@ -131,237 +121,5 @@
 		result = PVR;
 	}
 
-	return result;
-}
-
-#define PORT2ADDR(x) (microdev_isa_port2addr(x))
-
-static inline void delay(void)
-{
-#if defined(CONFIG_PCI)
-	/* System board present, just make a dummy SRAM access.  (CS0 will be
-	   mapped to PCI memory, probably good to avoid it.) */
-	__raw_readw(0xa6800000);
-#else
-	/* CS0 will be mapped to flash, ROM etc so safe to access it. */
-	__raw_readw(0xa0000000);
-#endif
-}
-
-unsigned char microdev_inb(unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO)
-		return microdev_pci_inb(port);
-#endif
-	return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned short microdev_inw(unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO)
-		return microdev_pci_inw(port);
-#endif
-	return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int microdev_inl(unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO)
-		return microdev_pci_inl(port);
-#endif
-	return *(volatile unsigned int*)PORT2ADDR(port);
-}
-
-void microdev_outw(unsigned short b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO) {
-		microdev_pci_outw(b, port);
-		return;
-	}
-#endif
-	*(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void microdev_outb(unsigned char b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO) {
-		microdev_pci_outb(b, port);
-		return;
-	}
-#endif
-
-	/*
-	 *	There is a board feature with the current SH4-202 MicroDev in
-	 *	that the 2 byte enables (nBE0 and nBE1) are tied together (and
-	 *	to the Chip Select Line (Ethernet_CS)). Due to this connectivity,
-	 *	it is not possible to safely perform 8-bit writes to the
-	 *	Ethernet registers, as 16-bits will be consumed from the Data
-	 *	lines (corrupting the other byte).  Hence, this function is
-	 *	written to implement 16-bit read/modify/write for all byte-wide
-	 *	accesses.
-	 *
-	 *	Note: there is no problem with byte READS (even or odd).
-	 *
-	 *			Sean McGoogan - 16th June 2003.
-	 */
-	if ((port >= IO_LAN91C111_BASE) &&
-	    (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
-			/*
-			 * Then are trying to perform a byte-write to the
-			 * LAN91C111.  This needs special care.
-			 */
-		if (port % 2 == 1) {	/* is the port odd ? */
-			/* unset bit-0, i.e. make even */
-			const unsigned long evenPort = port-1;
-			unsigned short word;
-
-			/*
-			 * do a 16-bit read/write to write to 'port',
-			 * preserving even byte.
-			 *
-			 *	Even addresses are bits 0-7
-			 *	Odd  addresses are bits 8-15
-			 */
-			word = microdev_inw(evenPort);
-			word = (word & 0xffu) | (b << 8);
-			microdev_outw(word, evenPort);
-		} else {
-			/* else, we are trying to do an even byte write */
-			unsigned short word;
-
-			/*
-			 * do a 16-bit read/write to write to 'port',
-			 * preserving odd byte.
-			 *
-			 *	Even addresses are bits 0-7
-			 *	Odd  addresses are bits 8-15
-			 */
-			word = microdev_inw(port);
-			word = (word & 0xff00u) | (b);
-			microdev_outw(word, port);
-		}
-	} else {
-		*(volatile unsigned char*)PORT2ADDR(port) = b;
-	}
-}
-
-void microdev_outl(unsigned int b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-	if (port >= PCIBIOS_MIN_IO) {
-		microdev_pci_outl(b, port);
-		return;
-	}
-#endif
-	*(volatile unsigned int*)PORT2ADDR(port) = b;
-}
-
-unsigned char microdev_inb_p(unsigned long port)
-{
-	unsigned char v = microdev_inb(port);
-	delay();
-	return v;
-}
-
-unsigned short microdev_inw_p(unsigned long port)
-{
-	unsigned short v = microdev_inw(port);
-	delay();
-	return v;
-}
-
-unsigned int microdev_inl_p(unsigned long port)
-{
-	unsigned int v = microdev_inl(port);
-	delay();
-	return v;
-}
-
-void microdev_outb_p(unsigned char b, unsigned long port)
-{
-	microdev_outb(b, port);
-	delay();
-}
-
-void microdev_outw_p(unsigned short b, unsigned long port)
-{
-	microdev_outw(b, port);
-	delay();
-}
-
-void microdev_outl_p(unsigned int b, unsigned long port)
-{
-	microdev_outl(b, port);
-	delay();
-}
-
-void microdev_insb(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned char *port_addr;
-	unsigned char *buf = buffer;
-
-	port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-	while (count--)
-		*buf++ = *port_addr;
-}
-
-void microdev_insw(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned short *port_addr;
-	unsigned short *buf = buffer;
-
-	port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-	while (count--)
-		*buf++ = *port_addr;
-}
-
-void microdev_insl(unsigned long port, void *buffer, unsigned long count)
-{
-	volatile unsigned long *port_addr;
-	unsigned int *buf = buffer;
-
-	port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-	while (count--)
-		*buf++ = *port_addr;
-}
-
-void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned char *port_addr;
-	const unsigned char *buf = buffer;
-
-	port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-	while (count--)
-		*port_addr = *buf++;
-}
-
-void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned short *port_addr;
-	const unsigned short *buf = buffer;
-
-	port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-	while (count--)
-		*port_addr = *buf++;
-}
-
-void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-	volatile unsigned long *port_addr;
-	const unsigned int *buf = buffer;
-
-	port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-	while (count--)
-		*port_addr = *buf++;
+	return (void __iomem *)result;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,19 +65,9 @@
 #  error Inconsistancy in defining the IRQ# for primary IDE!
 #endif
 
-static void enable_microdev_irq(unsigned int irq);
-static void disable_microdev_irq(unsigned int irq);
-static void mask_and_ack_microdev(unsigned int);
-
-static struct irq_chip microdev_irq_type = {
-	.name = "MicroDev-IRQ",
-	.unmask = enable_microdev_irq,
-	.mask = disable_microdev_irq,
-	.ack = mask_and_ack_microdev,
-};
-
-static void disable_microdev_irq(unsigned int irq)
+static void disable_microdev_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned int fpgaIrq;
 
 	if (irq >= NUM_EXTERNAL_IRQS)
@@ -91,8 +81,9 @@
 	__raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
 }
 
-static void enable_microdev_irq(unsigned int irq)
+static void enable_microdev_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned long priorityReg, priorities, pri;
 	unsigned int fpgaIrq;
 
@@ -116,17 +107,18 @@
 	__raw_writel(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
 }
 
+static struct irq_chip microdev_irq_type = {
+	.name = "MicroDev-IRQ",
+	.irq_unmask = enable_microdev_irq,
+	.irq_mask = disable_microdev_irq,
+};
+
 /* This function sets the desired irq handler to be a MicroDev type */
 static void __init make_microdev_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
 	set_irq_chip_and_handler(irq, &microdev_irq_type, handle_level_irq);
-	disable_microdev_irq(irq);
-}
-
-static void mask_and_ack_microdev(unsigned int irq)
-{
-	disable_microdev_irq(irq);
+	disable_microdev_irq(irq_get_irq_data(irq));
 }
 
 extern void __init init_microdev_irq(void)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-microdev/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-microdev/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,27 +195,6 @@
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
 	.mv_name		= "SH4-202 MicroDev",
 	.mv_nr_irqs		= 72,
-
-	.mv_inb			= microdev_inb,
-	.mv_inw			= microdev_inw,
-	.mv_inl			= microdev_inl,
-	.mv_outb		= microdev_outb,
-	.mv_outw		= microdev_outw,
-	.mv_outl		= microdev_outl,
-
-	.mv_inb_p		= microdev_inb_p,
-	.mv_inw_p		= microdev_inw_p,
-	.mv_inl_p		= microdev_inl_p,
-	.mv_outb_p		= microdev_outb_p,
-	.mv_outw_p		= microdev_outw_p,
-	.mv_outl_p		= microdev_outl_p,
-
-	.mv_insb		= microdev_insb,
-	.mv_insw		= microdev_insw,
-	.mv_insl		= microdev_insl,
-	.mv_outsb		= microdev_outsb,
-	.mv_outsw		= microdev_outsw,
-	.mv_outsl		= microdev_outsl,
-
+	.mv_ioport_map		= microdev_ioport_map,
 	.mv_init_irq		= init_microdev_irq,
 };
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-migor/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-migor/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-migor/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-migor/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -213,51 +213,55 @@
 	}
 };
 
+const static struct fb_videomode migor_lcd_modes[] = {
+	{
+#if defined(CONFIG_SH_MIGOR_RTA_WVGA)
+		.name = "LB070WV1",
+		.xres = 800,
+		.yres = 480,
+		.left_margin = 64,
+		.right_margin = 16,
+		.hsync_len = 120,
+		.sync = 0,
+#elif defined(CONFIG_SH_MIGOR_QVGA)
+		.name = "PH240320T",
+		.xres = 320,
+		.yres = 240,
+		.left_margin = 0,
+		.right_margin = 16,
+		.hsync_len = 8,
+		.sync = FB_SYNC_HOR_HIGH_ACT,
+#endif
+		.upper_margin = 1,
+		.lower_margin = 17,
+		.vsync_len = 2,
+	},
+};
+
 static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
-#ifdef CONFIG_SH_MIGOR_RTA_WVGA
+#if defined(CONFIG_SH_MIGOR_RTA_WVGA)
 	.clock_source = LCDC_CLK_BUS,
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.bpp = 16,
 		.interface_type = RGB16,
 		.clock_divider = 2,
-		.lcd_cfg = {
-			.name = "LB070WV1",
-			.xres = 800,
-			.yres = 480,
-			.left_margin = 64,
-			.right_margin = 16,
-			.hsync_len = 120,
-			.upper_margin = 1,
-			.lower_margin = 17,
-			.vsync_len = 2,
-			.sync = 0,
-		},
+		.lcd_cfg = migor_lcd_modes,
+		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
 		.lcd_size_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
 		},
 	}
-#endif
-#ifdef CONFIG_SH_MIGOR_QVGA
+#elif defined(CONFIG_SH_MIGOR_QVGA)
 	.clock_source = LCDC_CLK_PERIPHERAL,
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.bpp = 16,
 		.interface_type = SYS16A,
 		.clock_divider = 10,
-		.lcd_cfg = {
-			.name = "PH240320T",
-			.xres = 320,
-			.yres = 240,
-			.left_margin = 0,
-			.right_margin = 16,
-			.hsync_len = 8,
-			.upper_margin = 1,
-			.lower_margin = 17,
-			.vsync_len = 2,
-			.sync = FB_SYNC_HOR_HIGH_ACT,
-		},
+		.lcd_cfg = migor_lcd_modes,
+		.num_cfg = ARRAY_SIZE(migor_lcd_modes),
 		.lcd_size_cfg = { /* 2.4 inch */
 			.width = 49,
 			.height = 37,
@@ -450,7 +454,6 @@
 	.power		= ov7725_power,
 	.board_info	= &migor_i2c_camera[0],
 	.i2c_adapter_id	= 0,
-	.module_name	= "ov772x",
 	.priv		= &ov7725_info,
 };
 
@@ -463,7 +466,6 @@
 	.power		= tw9910_power,
 	.board_info	= &migor_i2c_camera[1],
 	.i2c_adapter_id	= 0,
-	.module_name	= "tw9910",
 	.priv		= &tw9910_info,
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/gpio.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/gpio.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,49 @@
+/*
+ * SDK7786 FPGA USRGPIR Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/fpga.h>
+
+#define NR_FPGA_GPIOS	8
+
+static const char *usrgpir_gpio_names[NR_FPGA_GPIOS] = {
+	"in0", "in1", "in2", "in3", "in4", "in5", "in6", "in7",
+};
+
+static int usrgpir_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	/* always in */
+	return 0;
+}
+
+static int usrgpir_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+	return !!(fpga_read_reg(USRGPIR) & (1 << gpio));
+}
+
+static struct gpio_chip usrgpir_gpio_chip = {
+	.label			= "sdk7786-fpga",
+	.names			= usrgpir_gpio_names,
+	.direction_input	= usrgpir_gpio_direction_input,
+	.get			= usrgpir_gpio_get,
+	.base			= -1, /* don't care */
+	.ngpio			= NR_FPGA_GPIOS,
+};
+
+static int __init usrgpir_gpio_setup(void)
+{
+	return gpiochip_add(&usrgpir_gpio_chip);
+}
+device_initcall(usrgpir_gpio_setup);
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1,4 @@
-obj-y	:= setup.o fpga.o irq.o
+obj-y	:= fpga.o irq.o setup.o
+
+obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
+obj-$(CONFIG_HAVE_SRAM_POOL)	+= sram.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,8 @@
 #include <asm/machvec.h>
 #include <asm/heartbeat.h>
 #include <asm/sizes.h>
+#include <asm/clock.h>
+#include <asm/clkdev.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
 
@@ -140,6 +142,45 @@
 	return fpga_read_reg(MODSWR);
 }
 
+/*
+ * FPGA-driven PCIe clocks
+ *
+ * Historically these include the oscillator, clock B (slots 2/3/4) and
+ * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove
+ * everything under a single PCIe clocks enable bit that happens to map
+ * to the same bit position as the oscillator bit for earlier FPGA
+ * versions.
+ *
+ * Given that the legacy clocks have the side-effect of shutting the CPU
+ * off through the FPGA along with the PCI slots, we simply leave them in
+ * their initial state and don't bother registering them with the clock
+ * framework.
+ */
+static int sdk7786_pcie_clk_enable(struct clk *clk)
+{
+	fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR);
+	return 0;
+}
+
+static void sdk7786_pcie_clk_disable(struct clk *clk)
+{
+	fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
+}
+
+static struct clk_ops sdk7786_pcie_clk_ops = {
+	.enable		= sdk7786_pcie_clk_enable,
+	.disable	= sdk7786_pcie_clk_disable,
+};
+
+static struct clk sdk7786_pcie_clk = {
+	.ops		= &sdk7786_pcie_clk_ops,
+};
+
+static struct clk_lookup sdk7786_pcie_cl = {
+	.con_id		= "pcie_plat_clk",
+	.clk		= &sdk7786_pcie_clk,
+};
+
 static int sdk7786_clk_init(void)
 {
 	struct clk *clk;
@@ -158,7 +199,18 @@
 	ret = clk_set_rate(clk, 33333333);
 	clk_put(clk);
 
-	return ret;
+	/*
+	 * Setup the FPGA clocks.
+	 */
+	ret = clk_register(&sdk7786_pcie_clk);
+	if (unlikely(ret)) {
+		pr_err("FPGA clock registration failed\n");
+		return ret;
+	}
+
+	clkdev_add(&sdk7786_pcie_cl);
+
+	return 0;
 }
 
 static void sdk7786_restart(char *cmd)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/sram.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/sram.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-sdk7786/sram.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-sdk7786/sram.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,72 @@
+/*
+ * SDK7786 FPGA SRAM Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <mach/fpga.h>
+#include <asm/sram.h>
+#include <asm/sizes.h>
+
+static int __init fpga_sram_init(void)
+{
+	unsigned long phys;
+	unsigned int area;
+	void __iomem *vaddr;
+	int ret;
+	u16 data;
+
+	/* Enable FPGA SRAM */
+	data = fpga_read_reg(LCLASR);
+	data |= LCLASR_FRAMEN;
+	fpga_write_reg(data, LCLASR);
+
+	/*
+	 * FPGA_SEL determines the area mapping
+	 */
+	area = (data & LCLASR_FPGA_SEL_MASK) >> LCLASR_FPGA_SEL_SHIFT;
+	if (unlikely(area == LCLASR_AREA_MASK)) {
+		pr_err("FPGA memory unmapped.\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * The memory itself occupies a 2KiB range at the top of the area
+	 * immediately below the system registers.
+	 */
+	phys = (area << 26) + SZ_64M - SZ_4K;
+
+	/*
+	 * The FPGA SRAM resides in translatable physical space, so set
+	 * up a mapping prior to inserting it in to the pool.
+	 */
+	vaddr = ioremap(phys, SZ_2K);
+	if (unlikely(!vaddr)) {
+		pr_err("Failed remapping FPGA memory.\n");
+		return -ENXIO;
+	}
+
+	pr_info("Adding %dKiB of FPGA memory at 0x%08lx-0x%08lx "
+		"(area %d) to pool.\n",
+		SZ_2K >> 10, phys, phys + SZ_2K - 1, area);
+
+	ret = gen_pool_add(sram_pool, (unsigned long)vaddr, SZ_2K, -1);
+	if (unlikely(ret < 0)) {
+		pr_err("Failed adding memory\n");
+		iounmap(vaddr);
+		return ret;
+	}
+
+	return 0;
+}
+postcore_initcall(fpga_sram_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,104 +0,0 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
- *
- * linux/arch/sh/boards/se/7206/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7206 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7206.h>
-
-
-static inline void delay(void)
-{
-	__raw_readw(0x20000000);  /* P2 ROM Area */
-}
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-	if (port >= 0x2000 && port < 0x2020)
-		return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-	else if (port >= 0x300 && port < 0x310)
-		return (volatile __u16 *) (PA_SMSC + (port - 0x300));
-
-	return (volatile __u16 *)port;
-}
-
-unsigned char se7206_inb(unsigned long port)
-{
-	return (*port2adr(port)) & 0xff;
-}
-
-unsigned char se7206_inb_p(unsigned long port)
-{
-	unsigned long v;
-
-	v = (*port2adr(port)) & 0xff;
-	delay();
-	return v;
-}
-
-unsigned short se7206_inw(unsigned long port)
-{
-	return *port2adr(port);
-}
-
-void se7206_outb(unsigned char value, unsigned long port)
-{
-	*(port2adr(port)) = value;
-}
-
-void se7206_outb_p(unsigned char value, unsigned long port)
-{
-	*(port2adr(port)) = value;
-	delay();
-}
-
-void se7206_outw(unsigned short value, unsigned long port)
-{
-	*port2adr(port) = value;
-}
-
-void se7206_insb(unsigned long port, void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	__u8 *ap = addr;
-
-	while (count--)
-		*ap++ = *p;
-}
-
-void se7206_insw(unsigned long port, void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	__u16 *ap = addr;
-	while (count--)
-		*ap++ = *p;
-}
-
-void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	const __u8 *ap = addr;
-
-	while (count--)
-		*p = *ap++;
-}
-
-void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	const __u16 *ap = addr;
-	while (count--)
-		*p = *ap++;
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,8 +25,9 @@
 #define INTC_IPR01 0xfffe0818
 #define INTC_ICR1  0xfffe0802
 
-static void disable_se7206_irq(unsigned int irq)
+static void disable_se7206_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned short val;
 	unsigned short mask = 0xffff ^ (0x0f << 4 * (3 - (IRQ0_IRQ - irq)));
 	unsigned short msk0,msk1;
@@ -55,8 +56,9 @@
 	__raw_writew(msk1, INTMSK1);
 }
 
-static void enable_se7206_irq(unsigned int irq)
+static void enable_se7206_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned short val;
 	unsigned short value = (0x0001 << 4 * (3 - (IRQ0_IRQ - irq)));
 	unsigned short msk0,msk1;
@@ -86,13 +88,14 @@
 	__raw_writew(msk1, INTMSK1);
 }
 
-static void eoi_se7206_irq(unsigned int irq)
+static void eoi_se7206_irq(struct irq_data *data)
 {
 	unsigned short sts0,sts1;
+	unsigned int irq = data->irq;
 	struct irq_desc *desc = irq_to_desc(irq);
 
 	if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
-		enable_se7206_irq(irq);
+		enable_se7206_irq(data);
 	/* FPGA isr clear */
 	sts0 = __raw_readw(INTSTS0);
 	sts1 = __raw_readw(INTSTS1);
@@ -115,10 +118,9 @@
 
 static struct irq_chip se7206_irq_chip __read_mostly = {
 	.name		= "SE7206-FPGA",
-	.mask		= disable_se7206_irq,
-	.unmask		= enable_se7206_irq,
-	.mask_ack	= disable_se7206_irq,
-	.eoi		= eoi_se7206_irq,
+	.irq_mask	= disable_se7206_irq,
+	.irq_unmask	= enable_se7206_irq,
+	.irq_eoi	= eoi_se7206_irq,
 };
 
 static void make_se7206_irq(unsigned int irq)
@@ -126,7 +128,7 @@
 	disable_irq_nosync(irq);
 	set_irq_chip_and_handler_name(irq, &se7206_irq_chip,
 				      handle_level_irq, "level");
-	disable_se7206_irq(irq);
+	disable_se7206_irq(irq_get_irq_data(irq));
 }
 
 /*
@@ -137,11 +139,13 @@
 	make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */
 	make_se7206_irq(IRQ1_IRQ); /* ATA */
 	make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
-	__raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */
+
+	__raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR1); /* ICR1 */
 
 	/* FPGA System register setup*/
 	__raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
 	__raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */
+
 	/* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */
 	__raw_writew(0x0001,INTSEL);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,4 +2,4 @@
 # Makefile for the 7206 SolutionEngine specific parts of the kernel
 #
 
-obj-y	 := setup.o io.o irq.o
+obj-y	 := setup.o irq.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7206/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7206/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -86,20 +86,5 @@
 static struct sh_machine_vector mv_se __initmv = {
 	.mv_name		= "SolutionEngine",
 	.mv_nr_irqs		= 256,
-	.mv_inb			= se7206_inb,
-	.mv_inw			= se7206_inw,
-	.mv_outb		= se7206_outb,
-	.mv_outw		= se7206_outw,
-
-	.mv_inb_p		= se7206_inb_p,
-	.mv_inw_p		= se7206_inw,
-	.mv_outb_p		= se7206_outb_p,
-	.mv_outw_p		= se7206_outw,
-
-	.mv_insb		= se7206_insb,
-	.mv_insw		= se7206_insw,
-	.mv_outsb		= se7206_outsb,
-	.mv_outsw		= se7206_outsw,
-
 	.mv_init_irq		= init_se7206_IRQ,
 };
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7343/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7343/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7343/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7343/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,23 +18,22 @@
 
 unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, };
 
-static void disable_se7343_irq(unsigned int irq)
+static void disable_se7343_irq(struct irq_data *data)
 {
-	unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
 	__raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
 }
 
-static void enable_se7343_irq(unsigned int irq)
+static void enable_se7343_irq(struct irq_data *data)
 {
-	unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
 	__raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK);
 }
 
 static struct irq_chip se7343_irq_chip __read_mostly = {
-	.name           = "SE7343-FPGA",
-	.mask           = disable_se7343_irq,
-	.unmask         = enable_se7343_irq,
-	.mask_ack       = disable_se7343_irq,
+	.name		= "SE7343-FPGA",
+	.irq_mask	= disable_se7343_irq,
+	.irq_unmask	= enable_se7343_irq,
 };
 
 static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * I/O routine for Hitachi SolutionEngine.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se.h>
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-	if (port & 0xff000000)
-		return ( volatile __u16 *) port;
-	if (port >= 0x2000)
-		return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-	else if (port >= 0x1000)
-		return (volatile __u16 *) (PA_83902 + (port << 1));
-	else
-		return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-}
-
-static inline int
-shifted_port(unsigned long port)
-{
-	/* For IDE registers, value is not shifted */
-	if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
-		return 0;
-	else
-		return 1;
-}
-
-unsigned char se_inb(unsigned long port)
-{
-	if (shifted_port(port))
-		return (*port2adr(port) >> 8);
-	else
-		return (*port2adr(port))&0xff;
-}
-
-unsigned char se_inb_p(unsigned long port)
-{
-	unsigned long v;
-
-	if (shifted_port(port))
-		v = (*port2adr(port) >> 8);
-	else
-		v = (*port2adr(port))&0xff;
-	ctrl_delay();
-	return v;
-}
-
-unsigned short se_inw(unsigned long port)
-{
-	if (port >= 0x2000)
-		return *port2adr(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-unsigned int se_inl(unsigned long port)
-{
-	maybebadio(port);
-	return 0;
-}
-
-void se_outb(unsigned char value, unsigned long port)
-{
-	if (shifted_port(port))
-		*(port2adr(port)) = value << 8;
-	else
-		*(port2adr(port)) = value;
-}
-
-void se_outb_p(unsigned char value, unsigned long port)
-{
-	if (shifted_port(port))
-		*(port2adr(port)) = value << 8;
-	else
-		*(port2adr(port)) = value;
-	ctrl_delay();
-}
-
-void se_outw(unsigned short value, unsigned long port)
-{
-	if (port >= 0x2000)
-		*port2adr(port) = value;
-	else
-		maybebadio(port);
-}
-
-void se_outl(unsigned int value, unsigned long port)
-{
-	maybebadio(port);
-}
-
-void se_insb(unsigned long port, void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	__u8 *ap = addr;
-
-	if (shifted_port(port)) {
-		while (count--)
-			*ap++ = *p >> 8;
-	} else {
-		while (count--)
-			*ap++ = *p;
-	}
-}
-
-void se_insw(unsigned long port, void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	__u16 *ap = addr;
-	while (count--)
-		*ap++ = *p;
-}
-
-void se_insl(unsigned long port, void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
-
-void se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	const __u8 *ap = addr;
-
-	if (shifted_port(port)) {
-		while (count--)
-			*p = *ap++ << 8;
-	} else {
-		while (count--)
-			*p = *ap++;
-	}
-}
-
-void se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-	volatile __u16 *p = port2adr(port);
-	const __u16 *ap = addr;
-
-	while (count--)
-		*p = *ap++;
-}
-
-void se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,4 +2,4 @@
 # Makefile for the 770x SolutionEngine specific parts of the kernel
 #
 
-obj-y	 := setup.o io.o irq.o
+obj-y	 := setup.o irq.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/770x/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/770x/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,27 +195,5 @@
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
 	.mv_nr_irqs             = 104,
 #endif
-
-	.mv_inb			= se_inb,
-	.mv_inw			= se_inw,
-	.mv_inl			= se_inl,
-	.mv_outb		= se_outb,
-	.mv_outw		= se_outw,
-	.mv_outl		= se_outl,
-
-	.mv_inb_p		= se_inb_p,
-	.mv_inw_p		= se_inw,
-	.mv_inl_p		= se_inl,
-	.mv_outb_p		= se_outb_p,
-	.mv_outw_p		= se_outw,
-	.mv_outl_p		= se_outl,
-
-	.mv_insb		= se_insb,
-	.mv_insw		= se_insw,
-	.mv_insl		= se_insl,
-	.mv_outsb		= se_outsb,
-	.mv_outsw		= se_outsw,
-	.mv_outsl		= se_outsl,
-
 	.mv_init_irq		= init_se_IRQ,
 };
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7722/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7722/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7722/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7722/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,23 +18,22 @@
 
 unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
 
-static void disable_se7722_irq(unsigned int irq)
+static void disable_se7722_irq(struct irq_data *data)
 {
-	unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
 	__raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
 }
 
-static void enable_se7722_irq(unsigned int irq)
+static void enable_se7722_irq(struct irq_data *data)
 {
-	unsigned int bit = (unsigned int)get_irq_chip_data(irq);
+	unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
 	__raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
 }
 
 static struct irq_chip se7722_irq_chip __read_mostly = {
-	.name           = "SE7722-FPGA",
-	.mask           = disable_se7722_irq,
-	.unmask         = enable_se7722_irq,
-	.mask_ack       = disable_se7722_irq,
+	.name		= "SE7722-FPGA",
+	.irq_mask	= disable_se7722_irq,
+	.irq_unmask	= enable_se7722_irq,
 };
 
 static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7724/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7724/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7724/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7724/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,25 +68,26 @@
 	return set;
 }
 
-static void disable_se7724_irq(unsigned int irq)
+static void disable_se7724_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
 	unsigned int bit = irq - set.base;
 	__raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
 }
 
-static void enable_se7724_irq(unsigned int irq)
+static void enable_se7724_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
 	unsigned int bit = irq - set.base;
 	__raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
 }
 
 static struct irq_chip se7724_irq_chip __read_mostly = {
-	.name           = "SE7724-FPGA",
-	.mask           = disable_se7724_irq,
-	.unmask         = enable_se7724_irq,
-	.mask_ack       = disable_se7724_irq,
+	.name		= "SE7724-FPGA",
+	.irq_mask	= disable_se7724_irq,
+	.irq_unmask	= enable_se7724_irq,
 };
 
 static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7724/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7724/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7724/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7724/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -144,16 +144,42 @@
 };
 
 /* LCDC */
+const static struct fb_videomode lcdc_720p_modes[] = {
+	{
+		.name		= "LB070WV1",
+		.sync		= 0, /* hsync and vsync are active low */
+		.xres		= 1280,
+		.yres		= 720,
+		.left_margin	= 220,
+		.right_margin	= 110,
+		.hsync_len	= 40,
+		.upper_margin	= 20,
+		.lower_margin	= 5,
+		.vsync_len	= 5,
+	},
+};
+
+const static struct fb_videomode lcdc_vga_modes[] = {
+	{
+		.name		= "LB070WV1",
+		.sync		= 0, /* hsync and vsync are active low */
+		.xres		= 640,
+		.yres		= 480,
+		.left_margin	= 105,
+		.right_margin	= 50,
+		.hsync_len	= 96,
+		.upper_margin	= 33,
+		.lower_margin	= 10,
+		.vsync_len	= 2,
+	},
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
 	.clock_source = LCDC_CLK_EXTERNAL,
 	.ch[0] = {
 		.chan = LCDC_CHAN_MAINLCD,
 		.bpp = 16,
 		.clock_divider = 1,
-		.lcd_cfg = {
-			.name = "LB070WV1",
-			.sync = 0, /* hsync and vsync are active low */
-		},
 		.lcd_size_cfg = { /* 7.0 inch */
 			.width = 152,
 			.height = 91,
@@ -257,31 +283,6 @@
 };
 
 /* FSI */
-/*
- * FSI-A use external clock which came from ak464x.
- * So, we should change parent of fsi
- */
-#define FCLKACR		0xa4150008
-static void fsimck_init(struct clk *clk)
-{
-	u32 status = __raw_readl(clk->enable_reg);
-
-	/* use external clock */
-	status &= ~0x000000ff;
-	status |= 0x00000080;
-	__raw_writel(status, clk->enable_reg);
-}
-
-static struct clk_ops fsimck_clk_ops = {
-	.init = fsimck_init,
-};
-
-static struct clk fsimcka_clk = {
-	.ops		= &fsimck_clk_ops,
-	.enable_reg	= (void __iomem *)FCLKACR,
-	.rate		= 0, /* unknown */
-};
-
 /* change J20, J21, J22 pin to 1-2 connection to use slave mode */
 static struct sh_fsi_platform_info fsi_info = {
 	.porta_flags = SH_FSI_BRS_INV |
@@ -550,7 +551,6 @@
 	.flags		= SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
 	.board_info	= &ak8813,
 	.i2c_adap	= 0,
-	.module_name	= "ak881x",
 };
 
 static struct resource sh_vou_resources[] = {
@@ -827,37 +827,29 @@
 	gpio_request(GPIO_FN_KEYOUT0,     NULL);
 
 	/* enable FSI */
-	gpio_request(GPIO_FN_FSIMCKB,    NULL);
 	gpio_request(GPIO_FN_FSIMCKA,    NULL);
+	gpio_request(GPIO_FN_FSIIASD,    NULL);
 	gpio_request(GPIO_FN_FSIOASD,    NULL);
 	gpio_request(GPIO_FN_FSIIABCK,   NULL);
 	gpio_request(GPIO_FN_FSIIALRCK,  NULL);
 	gpio_request(GPIO_FN_FSIOABCK,   NULL);
 	gpio_request(GPIO_FN_FSIOALRCK,  NULL);
 	gpio_request(GPIO_FN_CLKAUDIOAO, NULL);
-	gpio_request(GPIO_FN_FSIIBSD,    NULL);
-	gpio_request(GPIO_FN_FSIOBSD,    NULL);
-	gpio_request(GPIO_FN_FSIIBBCK,   NULL);
-	gpio_request(GPIO_FN_FSIIBLRCK,  NULL);
-	gpio_request(GPIO_FN_FSIOBBCK,   NULL);
-	gpio_request(GPIO_FN_FSIOBLRCK,  NULL);
-	gpio_request(GPIO_FN_CLKAUDIOBO, NULL);
-	gpio_request(GPIO_FN_FSIIASD,    NULL);
 
 	/* set SPU2 clock to 83.4 MHz */
 	clk = clk_get(NULL, "spu_clk");
-	if (clk) {
+	if (!IS_ERR(clk)) {
 		clk_set_rate(clk, clk_round_rate(clk, 83333333));
 		clk_put(clk);
 	}
 
 	/* change parent of FSI A */
 	clk = clk_get(NULL, "fsia_clk");
-	if (clk) {
-		clk_register(&fsimcka_clk);
-		clk_set_parent(clk, &fsimcka_clk);
-		clk_set_rate(clk, 11000);
-		clk_set_rate(&fsimcka_clk, 11000);
+	if (!IS_ERR(clk)) {
+		/* 48kHz dummy clock was used to make sure 1/1 divide */
+		clk_set_rate(&sh7724_fsimcka_clk, 48000);
+		clk_set_parent(clk, &sh7724_fsimcka_clk);
+		clk_set_rate(clk, 48000);
 		clk_put(clk);
 	}
 
@@ -909,24 +901,12 @@
 
 	if (sw & SW41_B) {
 		/* 720p */
-		lcdc_info.ch[0].lcd_cfg.xres         = 1280;
-		lcdc_info.ch[0].lcd_cfg.yres         = 720;
-		lcdc_info.ch[0].lcd_cfg.left_margin  = 220;
-		lcdc_info.ch[0].lcd_cfg.right_margin = 110;
-		lcdc_info.ch[0].lcd_cfg.hsync_len    = 40;
-		lcdc_info.ch[0].lcd_cfg.upper_margin = 20;
-		lcdc_info.ch[0].lcd_cfg.lower_margin = 5;
-		lcdc_info.ch[0].lcd_cfg.vsync_len    = 5;
+		lcdc_info.ch[0].lcd_cfg	= lcdc_720p_modes;
+		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_720p_modes);
 	} else {
 		/* VGA */
-		lcdc_info.ch[0].lcd_cfg.xres         = 640;
-		lcdc_info.ch[0].lcd_cfg.yres         = 480;
-		lcdc_info.ch[0].lcd_cfg.left_margin  = 105;
-		lcdc_info.ch[0].lcd_cfg.right_margin = 50;
-		lcdc_info.ch[0].lcd_cfg.hsync_len    = 96;
-		lcdc_info.ch[0].lcd_cfg.upper_margin = 33;
-		lcdc_info.ch[0].lcd_cfg.lower_margin = 10;
-		lcdc_info.ch[0].lcd_cfg.vsync_len    = 2;
+		lcdc_info.ch[0].lcd_cfg	= lcdc_vga_modes;
+		lcdc_info.ch[0].num_cfg	= ARRAY_SIZE(lcdc_vga_modes);
 	}
 
 	if (sw & SW41_A) {
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7751.h>
-#include <asm/addrspace.h>
-
-static inline volatile u16 *port2adr(unsigned int port)
-{
-	if (port >= 0x2000)
-		return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-	maybebadio((unsigned long)port);
-	return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751se_inb(unsigned long port)
-{
-	if (PXSEG(port))
-		return *(volatile unsigned char *)port;
-	else
-		return (*port2adr(port)) & 0xff;
-}
-
-unsigned char sh7751se_inb_p(unsigned long port)
-{
-	unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-	else
-		v = (*port2adr(port)) & 0xff;
-	ctrl_delay();
-	return v;
-}
-
-unsigned short sh7751se_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-unsigned int sh7751se_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-void sh7751se_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-	else
-		*(port2adr(port)) = value;
-}
-
-void sh7751se_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-	else
-		*(port2adr(port)) = value;
-	ctrl_delay();
-}
-
-void sh7751se_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-	else if (port >= 0x2000)
-		*port2adr(port) = value;
-	else
-		maybebadio(port);
-}
-
-void sh7751se_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-	else
-		maybebadio(port);
-}
-
-void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
-
-void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,4 +2,4 @@
 # Makefile for the 7751 SolutionEngine specific parts of the kernel
 #
 
-obj-y	 := setup.o io.o irq.o
+obj-y	 := setup.o irq.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-se/7751/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-se/7751/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,23 +56,5 @@
 static struct sh_machine_vector mv_7751se __initmv = {
 	.mv_name		= "7751 SolutionEngine",
 	.mv_nr_irqs		= 72,
-
-	.mv_inb			= sh7751se_inb,
-	.mv_inw			= sh7751se_inw,
-	.mv_inl			= sh7751se_inl,
-	.mv_outb		= sh7751se_outb,
-	.mv_outw		= sh7751se_outw,
-	.mv_outl		= sh7751se_outl,
-
-	.mv_inb_p		= sh7751se_inb_p,
-	.mv_inw_p		= sh7751se_inw,
-	.mv_inl_p		= sh7751se_inl,
-	.mv_outb_p		= sh7751se_outb_p,
-	.mv_outw_p		= sh7751se_outw,
-	.mv_outl_p		= sh7751se_outl,
-
-	.mv_insl		= sh7751se_insl,
-	.mv_outsl		= sh7751se_outsl,
-
 	.mv_init_irq		= init_7751se_IRQ,
 };
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-unsigned short secureedge5410_ioport;
-#endif
-
-static inline volatile __u16 *port2adr(unsigned int port)
-{
-	maybebadio((unsigned long)port);
-	return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char snapgear_inb(unsigned long port)
-{
-	if (PXSEG(port))
-		return *(volatile unsigned char *)port;
-	else
-		return (*port2adr(port)) & 0xff;
-}
-
-unsigned char snapgear_inb_p(unsigned long port)
-{
-	unsigned char v;
-
-	if (PXSEG(port))
-		v = *(volatile unsigned char *)port;
-	else
-		v = (*port2adr(port))&0xff;
-	ctrl_delay();
-	return v;
-}
-
-unsigned short snapgear_inw(unsigned long port)
-{
-	if (PXSEG(port))
-		return *(volatile unsigned short *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-unsigned int snapgear_inl(unsigned long port)
-{
-	if (PXSEG(port))
-		return *(volatile unsigned long *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-void snapgear_outb(unsigned char value, unsigned long port)
-{
-
-	if (PXSEG(port))
-		*(volatile unsigned char *)port = value;
-	else
-		*(port2adr(port)) = value;
-}
-
-void snapgear_outb_p(unsigned char value, unsigned long port)
-{
-	if (PXSEG(port))
-		*(volatile unsigned char *)port = value;
-	else
-		*(port2adr(port)) = value;
-	ctrl_delay();
-}
-
-void snapgear_outw(unsigned short value, unsigned long port)
-{
-	if (PXSEG(port))
-		*(volatile unsigned short *)port = value;
-	else if (port >= 0x2000)
-		*port2adr(port) = value;
-	else
-		maybebadio(port);
-}
-
-void snapgear_outl(unsigned int value, unsigned long port)
-{
-	if (PXSEG(port))
-		*(volatile unsigned long *)port = value;
-	else
-		maybebadio(port);
-}
-
-void snapgear_insl(unsigned long port, void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
-
-void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,5 +0,0 @@
-#
-# Makefile for the SnapGear specific parts of the kernel
-#
-
-obj-y	 := setup.o io.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-snapgear/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-snapgear/setup.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,95 +0,0 @@
-/*
- * linux/arch/sh/boards/snapgear/setup.c
- *
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
- *
- * Based on files with the following comments:
- *
- *           Copyright (C) 2000  Kazumoto Kojima
- *
- *           Modified for 7751 Solution Engine by
- *           Ian da Silva and Jeremy Siegel, 2001.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <asm/machvec.h>
-#include <mach/snapgear.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <cpu/timer.h>
-
-/*
- * EraseConfig handling functions
- */
-
-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
-{
-	(void)__raw_readb(0xb8000000);	/* dummy read */
-
-	printk("SnapGear: erase switch interrupt!\n");
-
-	return IRQ_HANDLED;
-}
-
-static int __init eraseconfig_init(void)
-{
-	printk("SnapGear: EraseConfig init\n");
-	/* Setup "EraseConfig" switch on external IRQ 0 */
-	if (request_irq(IRL0_IRQ, eraseconfig_interrupt, IRQF_DISABLED,
-				"Erase Config", NULL))
-		printk("SnapGear: failed to register IRQ%d for Reset witch\n",
-				IRL0_IRQ);
-	else
-		printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
-				IRL0_IRQ);
-	return(0);
-}
-
-module_init(eraseconfig_init);
-
-/****************************************************************************/
-/*
- * Initialize IRQ setting
- *
- * IRL0 = erase switch
- * IRL1 = eth0
- * IRL2 = eth1
- * IRL3 = crypto
- */
-
-static void __init init_snapgear_IRQ(void)
-{
-	printk("Setup SnapGear IRQ/IPR ...\n");
-	/* enable individual interrupt mode for externals */
-	plat_irq_setup_pins(IRQ_MODE_IRQ);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_snapgear __initmv = {
-	.mv_name		= "SnapGear SecureEdge5410",
-	.mv_nr_irqs		= 72,
-
-	.mv_inb			= snapgear_inb,
-	.mv_inw			= snapgear_inw,
-	.mv_inl			= snapgear_inl,
-	.mv_outb		= snapgear_outb,
-	.mv_outw		= snapgear_outw,
-	.mv_outl		= snapgear_outl,
-
-	.mv_inb_p		= snapgear_inb_p,
-	.mv_inw_p		= snapgear_inw,
-	.mv_inl_p		= snapgear_inl,
-	.mv_outb_p		= snapgear_outb_p,
-	.mv_outw_p		= snapgear_outw,
-	.mv_outl_p		= snapgear_outl,
-
-	.mv_init_irq		= init_snapgear_IRQ,
-};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/io.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/io.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,158 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 Systemh.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <mach/systemh7751.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
-                                                of smc lan chip*/
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-	if (port >= 0x2000)
-		return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-	maybebadio((unsigned long)port);
-	return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751systemh_inb(unsigned long port)
-{
-	if (PXSEG(port))
-		return *(volatile unsigned char *)port;
-	else if (port <= 0x3F1)
-		return *(volatile unsigned char *)ETHER_IOMAP(port);
-	else
-		return (*port2adr(port))&0xff;
-}
-
-unsigned char sh7751systemh_inb_p(unsigned long port)
-{
-	unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-	else if (port <= 0x3F1)
-		v = *(volatile unsigned char *)ETHER_IOMAP(port);
-	else
-		v = (*port2adr(port))&0xff;
-	ctrl_delay();
-	return v;
-}
-
-unsigned short sh7751systemh_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else if (port <= 0x3F1)
-		return *(volatile unsigned int *)ETHER_IOMAP(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-unsigned int sh7751systemh_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-	else if (port >= 0x2000)
-		return *port2adr(port);
-	else if (port <= 0x3F1)
-		return *(volatile unsigned int *)ETHER_IOMAP(port);
-	else
-		maybebadio(port);
-	return 0;
-}
-
-void sh7751systemh_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-	else if (port <= 0x3F1)
-		*(volatile unsigned char *)ETHER_IOMAP(port) = value;
-	else
-		*(port2adr(port)) = value;
-}
-
-void sh7751systemh_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-	else if (port <= 0x3F1)
-		*(volatile unsigned char *)ETHER_IOMAP(port) = value;
-	else
-		*(port2adr(port)) = value;
-	ctrl_delay();
-}
-
-void sh7751systemh_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-	else if (port >= 0x2000)
-		*port2adr(port) = value;
-	else if (port <= 0x3F1)
-		*(volatile unsigned short *)ETHER_IOMAP(port) = value;
-	else
-		maybebadio(port);
-}
-
-void sh7751systemh_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-	else
-		maybebadio(port);
-}
-
-void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned char *p = addr;
-	while (count--) *p++ = sh7751systemh_inb(port);
-}
-
-void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
-{
-	unsigned short *p = addr;
-	while (count--) *p++ = sh7751systemh_inw(port);
-}
-
-void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
-
-void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned char *p = (unsigned char*)addr;
-	while (count--) sh7751systemh_outb(*p++, port);
-}
-
-void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-	unsigned short *p = (unsigned short*)addr;
-	while (count--) sh7751systemh_outw(*p++, port);
-}
-
-void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-	maybebadio(port);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/irq.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/irq.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,76 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/irq.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by
- * Jonathan Short.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <mach/systemh7751.h>
-#include <asm/smc37c93x.h>
-
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
-static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-
-/* forward declaration */
-static void enable_systemh_irq(unsigned int irq);
-static void disable_systemh_irq(unsigned int irq);
-static void mask_and_ack_systemh(unsigned int);
-
-static struct irq_chip systemh_irq_type = {
-	.name = " SystemH Register",
-	.unmask = enable_systemh_irq,
-	.mask = disable_systemh_irq,
-	.ack = mask_and_ack_systemh,
-};
-
-static void disable_systemh_irq(unsigned int irq)
-{
-	if (systemh_irq_mask_register) {
-		unsigned long val, mask = 0x01 << 1;
-
-		/* Clear the "irq"th bit in the mask and set it in the request */
-		val = __raw_readl((unsigned long)systemh_irq_mask_register);
-		val &= ~mask;
-		__raw_writel(val, (unsigned long)systemh_irq_mask_register);
-
-		val = __raw_readl((unsigned long)systemh_irq_request_register);
-		val |= mask;
-		__raw_writel(val, (unsigned long)systemh_irq_request_register);
-	}
-}
-
-static void enable_systemh_irq(unsigned int irq)
-{
-	if (systemh_irq_mask_register) {
-		unsigned long val, mask = 0x01 << 1;
-
-		/* Set "irq"th bit in the mask register */
-		val = __raw_readl((unsigned long)systemh_irq_mask_register);
-		val |= mask;
-		__raw_writel(val, (unsigned long)systemh_irq_mask_register);
-	}
-}
-
-static void mask_and_ack_systemh(unsigned int irq)
-{
-	disable_systemh_irq(irq);
-}
-
-void make_systemh_irq(unsigned int irq)
-{
-	disable_irq_nosync(irq);
-	set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-	disable_systemh_irq(irq);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,13 +0,0 @@
-#
-# Makefile for the SystemH specific parts of the kernel
-#
-
-obj-y	 := setup.o irq.o io.o
-
-# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
-# importantly, with the generic sh7751_pcic_init() code. For now, we'll
-# just abuse the hell out of kbuild, because we can..
-
-obj-$(CONFIG_PCI) += pci.o
-pci-y := ../../se/7751/pci.o
-
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-systemh/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-systemh/setup.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,57 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2003  Paul Mundt
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by Jonathan Short.
- *
- * Rewritten for 2.6 by Paul Mundt.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-#include <mach/systemh7751.h>
-
-extern void make_systemh_irq(unsigned int irq);
-
-/*
- * Initialize IRQ setting
- */
-static void __init sh7751systemh_init_irq(void)
-{
-	make_systemh_irq(0xb);	/* Ethernet interrupt */
-}
-
-static struct sh_machine_vector mv_7751systemh __initmv = {
-	.mv_name		= "7751 SystemH",
-	.mv_nr_irqs		= 72,
-
-	.mv_inb			= sh7751systemh_inb,
-	.mv_inw			= sh7751systemh_inw,
-	.mv_inl			= sh7751systemh_inl,
-	.mv_outb		= sh7751systemh_outb,
-	.mv_outw		= sh7751systemh_outw,
-	.mv_outl		= sh7751systemh_outl,
-
-	.mv_inb_p		= sh7751systemh_inb_p,
-	.mv_inw_p		= sh7751systemh_inw,
-	.mv_inl_p		= sh7751systemh_inl,
-	.mv_outb_p		= sh7751systemh_outb_p,
-	.mv_outw_p		= sh7751systemh_outw,
-	.mv_outl_p		= sh7751systemh_outl,
-
-	.mv_insb		= sh7751systemh_insb,
-	.mv_insw		= sh7751systemh_insw,
-	.mv_insl		= sh7751systemh_insl,
-	.mv_outsb		= sh7751systemh_outsb,
-	.mv_outsw		= sh7751systemh_outsw,
-	.mv_outsl		= sh7751systemh_outsl,
-
-	.mv_init_irq		= sh7751systemh_init_irq,
-};
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/gpio.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/gpio.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,136 @@
+/*
+ * arch/sh/boards/mach-x3proto/gpio.c
+ *
+ * Renesas SH-X3 Prototype Baseboard GPIO Support.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
+
+#define KEYCTLR	0xb81c0000
+#define KEYOUTR	0xb81c0002
+#define KEYDETR 0xb81c0004
+
+static DEFINE_SPINLOCK(x3proto_gpio_lock);
+static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, };
+
+static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+	unsigned long flags;
+	unsigned int data;
+
+	spin_lock_irqsave(&x3proto_gpio_lock, flags);
+	data = __raw_readw(KEYCTLR);
+	data |= (1 << gpio);
+	__raw_writew(data, KEYCTLR);
+	spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+
+	return 0;
+}
+
+static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+	return !!(__raw_readw(KEYDETR) & (1 << gpio));
+}
+
+static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	return x3proto_gpio_irq_map[gpio];
+}
+
+static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct irq_data *data = irq_get_irq_data(irq);
+	struct irq_chip *chip = irq_data_get_irq_chip(data);
+	unsigned long mask;
+	int pin;
+
+	chip->irq_mask_ack(data);
+
+	mask = __raw_readw(KEYDETR);
+
+	for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
+		generic_handle_irq(x3proto_gpio_to_irq(NULL, pin));
+
+	chip->irq_unmask(data);
+}
+
+struct gpio_chip x3proto_gpio_chip = {
+	.label			= "x3proto-gpio",
+	.direction_input	= x3proto_gpio_direction_input,
+	.get			= x3proto_gpio_get,
+	.to_irq			= x3proto_gpio_to_irq,
+	.base			= -1,
+	.ngpio			= NR_BASEBOARD_GPIOS,
+};
+
+int __init x3proto_gpio_setup(void)
+{
+	int ilsel;
+	int ret, i;
+
+	ilsel = ilsel_enable(ILSEL_KEY);
+	if (unlikely(ilsel < 0))
+		return ilsel;
+
+	ret = gpiochip_add(&x3proto_gpio_chip);
+	if (unlikely(ret))
+		goto err_gpio;
+
+	for (i = 0; i < NR_BASEBOARD_GPIOS; i++) {
+		unsigned long flags;
+		int irq = create_irq();
+
+		if (unlikely(irq < 0)) {
+			ret = -EINVAL;
+			goto err_irq;
+		}
+
+		spin_lock_irqsave(&x3proto_gpio_lock, flags);
+		x3proto_gpio_irq_map[i] = irq;
+		set_irq_chip_and_handler_name(irq, &dummy_irq_chip,
+					handle_simple_irq, "gpio");
+		spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
+	}
+
+	pr_info("registering '%s' support, handling GPIOs %u -> %u, "
+		"bound to IRQ %u\n",
+		x3proto_gpio_chip.label, x3proto_gpio_chip.base,
+		x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
+		ilsel);
+
+	set_irq_chained_handler(ilsel, x3proto_gpio_irq_handler);
+	set_irq_wake(ilsel, 1);
+
+	return 0;
+
+err_irq:
+	for (; i >= 0; --i)
+		if (x3proto_gpio_irq_map[i])
+			destroy_irq(x3proto_gpio_irq_map[i]);
+
+	ret = gpiochip_remove(&x3proto_gpio_chip);
+	if (unlikely(ret))
+		pr_err("Failed deregistering GPIO\n");
+
+err_gpio:
+	synchronize_irq(ilsel);
+
+	ilsel_disable(ILSEL_KEY);
+
+	return ret;
+}
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/ilsel.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/ilsel.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/ilsel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/ilsel.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,20 +1,22 @@
 /*
- * arch/sh/boards/renesas/x3proto/ilsel.c
+ * arch/sh/boards/mach-x3proto/ilsel.c
  *
  * Helper routines for SH-X3 proto board ILSEL.
  *
- * Copyright (C) 2007 Paul Mundt
+ * Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/bitmap.h>
 #include <linux/io.h>
-#include <asm/ilsel.h>
+#include <mach/ilsel.h>
 
 /*
  * ILSEL is split across:
@@ -64,6 +66,8 @@
 	unsigned int tmp, shift;
 	unsigned long addr;
 
+	pr_notice("enabling ILSEL set %d\n", set);
+
 	addr = mk_ilsel_addr(bit);
 	shift = mk_ilsel_shift(bit);
 
@@ -92,8 +96,10 @@
 {
 	unsigned int bit;
 
-	/* Aliased sources must use ilsel_enable_fixed() */
-	BUG_ON(set > ILSEL_KEY);
+	if (unlikely(set > ILSEL_KEY)) {
+		pr_err("Aliased sources must use ilsel_enable_fixed()\n");
+		return -EINVAL;
+	}
 
 	do {
 		bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
@@ -140,6 +146,8 @@
 	unsigned long addr;
 	unsigned int tmp;
 
+	pr_notice("disabling ILSEL set %d\n", irq);
+
 	addr = mk_ilsel_addr(irq);
 
 	tmp = __raw_readw(addr);
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1,3 @@
 obj-y += setup.o ilsel.o
+
+obj-$(CONFIG_GENERIC_GPIO)	+= gpio.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/setup.c linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/boards/mach-x3proto/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/mach-x3proto/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,9 +1,9 @@
 /*
- * arch/sh/boards/renesas/x3proto/setup.c
+ * arch/sh/boards/mach-x3proto/setup.c
  *
  * Renesas SH-X3 Prototype Board Support.
  *
- * Copyright (C) 2007 - 2008 Paul Mundt
+ * Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -16,9 +16,13 @@
 #include <linux/smc91x.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/input.h>
 #include <linux/usb/r8a66597.h>
 #include <linux/usb/m66592.h>
-#include <asm/ilsel.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <mach/ilsel.h>
+#include <mach/hardware.h>
 #include <asm/smp-ops.h>
 
 static struct resource heartbeat_resources[] = {
@@ -122,15 +126,128 @@
 	.resource	= m66592_usb_peripheral_resources,
 };
 
+static struct gpio_keys_button baseboard_buttons[NR_BASEBOARD_GPIOS] = {
+	{
+		.desc		= "key44",
+		.code		= KEY_POWER,
+		.active_low	= 1,
+		.wakeup		= 1,
+	}, {
+		.desc		= "key43",
+		.code		= KEY_SUSPEND,
+		.active_low	= 1,
+		.wakeup		= 1,
+	}, {
+		.desc		= "key42",
+		.code		= KEY_KATAKANAHIRAGANA,
+		.active_low	= 1,
+	}, {
+		.desc		= "key41",
+		.code		= KEY_SWITCHVIDEOMODE,
+		.active_low	= 1,
+	}, {
+		.desc		= "key34",
+		.code		= KEY_F12,
+		.active_low	= 1,
+	}, {
+		.desc		= "key33",
+		.code		= KEY_F11,
+		.active_low	= 1,
+	}, {
+		.desc		= "key32",
+		.code		= KEY_F10,
+		.active_low	= 1,
+	}, {
+		.desc		= "key31",
+		.code		= KEY_F9,
+		.active_low	= 1,
+	}, {
+		.desc		= "key24",
+		.code		= KEY_F8,
+		.active_low	= 1,
+	}, {
+		.desc		= "key23",
+		.code		= KEY_F7,
+		.active_low	= 1,
+	}, {
+		.desc		= "key22",
+		.code		= KEY_F6,
+		.active_low	= 1,
+	}, {
+		.desc		= "key21",
+		.code		= KEY_F5,
+		.active_low	= 1,
+	}, {
+		.desc		= "key14",
+		.code		= KEY_F4,
+		.active_low	= 1,
+	}, {
+		.desc		= "key13",
+		.code		= KEY_F3,
+		.active_low	= 1,
+	}, {
+		.desc		= "key12",
+		.code		= KEY_F2,
+		.active_low	= 1,
+	}, {
+		.desc		= "key11",
+		.code		= KEY_F1,
+		.active_low	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data baseboard_buttons_data = {
+	.buttons	= baseboard_buttons,
+	.nbuttons	= ARRAY_SIZE(baseboard_buttons),
+};
+
+static struct platform_device baseboard_buttons_device = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &baseboard_buttons_data,
+	},
+};
+
 static struct platform_device *x3proto_devices[] __initdata = {
 	&heartbeat_device,
 	&smc91x_device,
 	&r8a66597_usb_host_device,
 	&m66592_usb_peripheral_device,
+	&baseboard_buttons_device,
 };
 
+static void __init x3proto_init_irq(void)
+{
+	plat_irq_setup_pins(IRQ_MODE_IRL3210);
+
+	/* Set ICR0.LVLMODE */
+	__raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
+}
+
 static int __init x3proto_devices_setup(void)
 {
+	int ret, i;
+
+	/*
+	 * IRLs are only needed for ILSEL mappings, so flip over the INTC
+	 * pins at a later point to enable the GPIOs to settle.
+	 */
+	x3proto_init_irq();
+
+	/*
+	 * Now that ILSELs are available, set up the baseboard GPIOs.
+	 */
+	ret = x3proto_gpio_setup();
+	if (unlikely(ret))
+		return ret;
+
+	/*
+	 * Propagate dynamic GPIOs for the baseboard button device.
+	 */
+	for (i = 0; i < ARRAY_SIZE(baseboard_buttons); i++)
+		baseboard_buttons[i].gpio = x3proto_gpio_chip.base + i;
+
 	r8a66597_usb_host_resources[1].start =
 		r8a66597_usb_host_resources[1].end = ilsel_enable(ILSEL_USBH_I);
 
@@ -145,14 +262,6 @@
 }
 device_initcall(x3proto_devices_setup);
 
-static void __init x3proto_init_irq(void)
-{
-	plat_irq_setup_pins(IRQ_MODE_IRL3210);
-
-	/* Set ICR0.LVLMODE */
-	__raw_writel(__raw_readl(0xfe410000) | (1 << 21), 0xfe410000);
-}
-
 static void __init x3proto_setup(char **cmdline_p)
 {
 	register_smp_ops(&shx3_smp_ops);
@@ -161,5 +270,4 @@
 static struct sh_machine_vector mv_x3proto __initmv = {
 	.mv_name		= "x3proto",
 	.mv_setup		= x3proto_setup,
-	.mv_init_irq		= x3proto_init_irq,
 };
diff -druN linux-libre-2.6.36-gnu/arch/sh/boards/Makefile linux-libre-2.6.37-gnu/arch/sh/boards/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/boards/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boards/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,10 +2,14 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)	+= board-magicpanelr2.o
+obj-$(CONFIG_SH_SECUREEDGE5410)	+= board-secureedge5410.o
+obj-$(CONFIG_SH_SH2007)		+= board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)	+= board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)	+= board-urquell.o
 obj-$(CONFIG_SH_SHMIN)		+= board-shmin.o
+obj-$(CONFIG_SH_EDOSK7705)	+= board-edosk7705.o
 obj-$(CONFIG_SH_EDOSK7760)	+= board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)		+= board-espt.o
 obj-$(CONFIG_SH_POLARIS)	+= board-polaris.o
 obj-$(CONFIG_SH_TITAN)		+= board-titan.o
+obj-$(CONFIG_SH_SH7757LCR)	+= board-sh7757lcr.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/boot/compressed/head_32.S linux-libre-2.6.37-gnu/arch/sh/boot/compressed/head_32.S
--- linux-libre-2.6.36-gnu/arch/sh/boot/compressed/head_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/boot/compressed/head_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,9 @@
 end_addr:
 	.long	_end
 init_sr:
-	.long	0x400000F0	/* Privileged mode, Bank=0, Block=0, IMASK=0xF */
+	.long	0x500000F0	/* Privileged mode, Bank=0, Block=1, IMASK=0xF */
+kexec_magic:
+	.long	0x400000F0	/* magic used by kexec to parse zImage format */
 init_stack_addr:
 	.long	stack_start
 decompress_kernel_addr:
diff -druN linux-libre-2.6.36-gnu/arch/sh/cchips/hd6446x/hd64461.c linux-libre-2.6.37-gnu/arch/sh/cchips/hd6446x/hd64461.c
--- linux-libre-2.6.36-gnu/arch/sh/cchips/hd6446x/hd64461.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/cchips/hd6446x/hd64461.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,8 +17,9 @@
 /* This belongs in cpu specific */
 #define INTC_ICR1 0xA4140010UL
 
-static void hd64461_mask_irq(unsigned int irq)
+static void hd64461_mask_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned short nimr;
 	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
@@ -27,8 +28,9 @@
 	__raw_writew(nimr, HD64461_NIMR);
 }
 
-static void hd64461_unmask_irq(unsigned int irq)
+static void hd64461_unmask_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned short nimr;
 	unsigned short mask = 1 << (irq - HD64461_IRQBASE);
 
@@ -37,20 +39,21 @@
 	__raw_writew(nimr, HD64461_NIMR);
 }
 
-static void hd64461_mask_and_ack_irq(unsigned int irq)
+static void hd64461_mask_and_ack_irq(struct irq_data *data)
 {
-	hd64461_mask_irq(irq);
+	hd64461_mask_irq(data);
+
 #ifdef CONFIG_HD64461_ENABLER
-	if (irq == HD64461_IRQBASE + 13)
+	if (data->irq == HD64461_IRQBASE + 13)
 		__raw_writeb(0x00, HD64461_PCC1CSCR);
 #endif
 }
 
 static struct irq_chip hd64461_irq_chip = {
 	.name		= "HD64461-IRQ",
-	.mask		= hd64461_mask_irq,
-	.mask_ack	= hd64461_mask_and_ack_irq,
-	.unmask		= hd64461_unmask_irq,
+	.irq_mask	= hd64461_mask_irq,
+	.irq_mask_ack	= hd64461_mask_and_ack_irq,
+	.irq_unmask	= hd64461_unmask_irq,
 };
 
 static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
diff -druN linux-libre-2.6.36-gnu/arch/sh/cchips/hd6446x/Makefile linux-libre-2.6.37-gnu/arch/sh/cchips/hd6446x/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/cchips/hd6446x/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/cchips/hd6446x/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,3 +1,3 @@
 obj-$(CONFIG_HD64461)	+= hd64461.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/ap325rxa_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/ap325rxa_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/ap325rxa_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/ap325rxa_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/cayman_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/cayman_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/cayman_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/cayman_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/dreamcast_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/dreamcast_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/dreamcast_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/dreamcast_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/ecovec24-romimage_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/ecovec24-romimage_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/ecovec24-romimage_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/ecovec24-romimage_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/edosk7760_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/edosk7760_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/edosk7760_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/edosk7760_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/espt_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/espt_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/espt_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/espt_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
 CONFIG_IPC_NS=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/hp6xx_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/hp6xx_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/hp6xx_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/hp6xx_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/kfr2r09_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/kfr2r09_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/kfr2r09_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/kfr2r09_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/kfr2r09-romimage_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/kfr2r09-romimage_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/kfr2r09-romimage_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/kfr2r09-romimage_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/landisk_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/landisk_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/landisk_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/landisk_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/lboxre2_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/lboxre2_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/lboxre2_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/lboxre2_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/magicpanelr2_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/magicpanelr2_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/magicpanelr2_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/magicpanelr2_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_AUDIT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/microdev_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/microdev_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/microdev_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/microdev_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/migor_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/migor_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/migor_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/migor_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/polaris_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/polaris_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/polaris_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/polaris_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,6 @@
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_AUDIT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/r7780mp_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/r7780mp_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/r7780mp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/r7780mp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/r7785rp_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/r7785rp_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/r7785rp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/r7785rp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/rts7751r2d1_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/rts7751r2d1_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/rts7751r2d1_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/rts7751r2d1_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/rts7751r2dplus_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/rts7751r2dplus_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/rts7751r2dplus_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/rts7751r2dplus_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,6 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sdk7780_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sdk7780_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sdk7780_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sdk7780_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7343_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7343_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7343_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7343_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7712_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7712_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7712_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7712_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_BUG is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7721_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7721_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7721_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7721_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_BUG is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7722_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7722_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7722_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7722_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7724_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7724_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7724_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7724_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 CONFIG_SLAB=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7750_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7750_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7750_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7750_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_HOTPLUG is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7751_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7751_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7751_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7751_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/se7780_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/se7780_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/se7780_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/se7780_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_KALLSYMS is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_EPOLL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/secureedge5410_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/secureedge5410_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/secureedge5410_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/configs/secureedge5410_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SECUREEDGE5410=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK_RO=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1302=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh03_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh03_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh03_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh03_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_POSIX_MQUEUE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_SYSCTL_SYSCALL is not set
 CONFIG_SLAB=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh2007_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh2007_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh2007_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh2007_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,212 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+CONFIG_MEMORY_SIZE=0x08000000
+# CONFIG_VSYSCALL is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH2007=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_NR_DMA_CHANNELS_BOOL=y
+CONFIG_HZ_100=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC1,115200 ip=dhcp root=/dev/nfs rw nfsroot=/nfs/rootfs,rsize=1024,wsize=1024 earlyprintk=sh-sci.1"
+CONFIG_PCCARD=y
+CONFIG_BINFMT_MISC=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_NET_IPIP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NET_PKTGEN=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_CDROM_PKTCDVD=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_RAID_ATTRS=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_EQUALIZER=y
+CONFIG_TUN=y
+CONFIG_VETH=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMSC911X=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_SH_WDT=y
+CONFIG_SSB=y
+CONFIG_FB=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_MON=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_DMADEVICES=y
+CONFIG_TIMB_DMA=y
+CONFIG_EXT3_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=932
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=y
+CONFIG_CRYPTO_PCBC=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_TGR192=y
+CONFIG_CRYPTO_WP512=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=y
+CONFIG_CRYPTO_CAMELLIA=y
+CONFIG_CRYPTO_CAST5=y
+CONFIG_CRYPTO_CAST6=y
+CONFIG_CRYPTO_FCRYPT=y
+CONFIG_CRYPTO_KHAZAD=y
+CONFIG_CRYPTO_SEED=y
+CONFIG_CRYPTO_SERPENT=y
+CONFIG_CRYPTO_TEA=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=y
+CONFIG_LIBCRC32C=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh7710voipgw_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh7710voipgw_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh7710voipgw_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh7710voipgw_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_SYSCTL_SYSCALL is not set
 # CONFIG_FUTEX is not set
 # CONFIG_EPOLL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh7757lcr_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh7757lcr_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh7757lcr_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh7757lcr_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,85 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7757=y
+CONFIG_MEMORY_START=0x40000000
+CONFIG_MEMORY_SIZE=0x0f000000
+CONFIG_PMB=y
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SH7757LCR=y
+CONFIG_HEARTBEAT=y
+CONFIG_SECCOMP=y
+CONFIG_CMDLINE_OVERWRITE=y
+CONFIG_CMDLINE="console=ttySC2,115200 root=/dev/nfs ip=dhcp"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_PHYLIB=y
+CONFIG_VITESSE_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_INOTIFY=y
+CONFIG_ISO9660_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_SQUASHFS=y
+CONFIG_MINIX_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_FTRACE is not set
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh7763rdp_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh7763rdp_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh7763rdp_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh7763rdp_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
 CONFIG_IPC_NS=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/sh7785lcr_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/sh7785lcr_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/sh7785lcr_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/sh7785lcr_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_SLAB=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/shx3_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/shx3_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/shx3_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/shx3_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,6 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_MEM_RES_CTLR=y
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_RELAY=y
 CONFIG_NAMESPACES=y
 CONFIG_UTS_NS=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/snapgear_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/snapgear_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/snapgear_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/snapgear_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,64 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_SECUREEDGE5410=y
-CONFIG_SH_DMA=y
-CONFIG_SH_DMA_API=y
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
-# CONFIG_MTD_CFI_I2 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_8139CP=y
-CONFIG_8139TOO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_DS1302=y
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/systemh_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/systemh_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/systemh_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/systemh_defconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,29 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_7751_SYSTEMH=y
-CONFIG_PREEMPT=y
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_HW_RANDOM=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/titan_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/titan_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/titan_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/titan_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_SYSCTL_SYSCALL is not set
diff -druN linux-libre-2.6.36-gnu/arch/sh/configs/ul2_defconfig linux-libre-2.6.37-gnu/arch/sh/configs/ul2_defconfig
--- linux-libre-2.6.36-gnu/arch/sh/configs/ul2_defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/configs/ul2_defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,6 @@
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_MODULES=y
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/dma/dma-api.c linux-libre-2.6.37-gnu/arch/sh/drivers/dma/dma-api.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/dma/dma-api.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/dma/dma-api.c	2011-01-04 19:50:19.000000000 -0500
@@ -412,8 +412,8 @@
 static int __init dma_api_init(void)
 {
 	printk(KERN_NOTICE "DMA: Registering DMA API.\n");
-	create_proc_read_entry("dma", 0, 0, dma_read_proc, 0);
-	return 0;
+	return create_proc_read_entry("dma", 0, 0, dma_read_proc, 0)
+		    ? 0 : -ENOMEM;
 }
 subsys_initcall(dma_api_init);
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/fixups-sdk7786.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/fixups-sdk7786.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/fixups-sdk7786.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/fixups-sdk7786.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+/*
+ * SDK7786 FPGA PCIe mux handling
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#define pr_fmt(fmt) "PCI: " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <mach/fpga.h>
+
+/*
+ * The SDK7786 FPGA supports mangling of most of the slots in some way or
+ * another. Slots 3/4 are special in that only one can be supported at a
+ * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4
+ * (the horizontal edge connector) will disable slot 3 entirely.
+ *
+ * Misconfigurations can be detected through the FPGA via the slot
+ * resistors to determine card presence. Hotplug remains unsupported.
+ */
+static unsigned int slot4en __devinitdata;
+
+char *__devinit pcibios_setup(char *str)
+{
+	if (strcmp(str, "slot4en") == 0) {
+		slot4en = 1;
+		return NULL;
+	}
+
+	return str;
+}
+
+static int __init sdk7786_pci_init(void)
+{
+	u16 data = fpga_read_reg(PCIECR);
+
+	/*
+	 * Enable slot #4 if it's been specified on the command line.
+	 *
+	 * Optionally reroute if slot #4 has a card present while slot #3
+	 * does not, regardless of command line value.
+	 *
+	 * Card presence is logically inverted.
+	 */
+	slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3));
+	if (slot4en) {
+		pr_info("Activating PCIe slot#4 (disabling slot#3)\n");
+
+		data &= ~PCIECR_PCIEMUX1;
+		fpga_write_reg(data, PCIECR);
+
+		/* Warn about forced rerouting if slot#3 is occupied */
+		if ((data & PCIECR_PRST3) == 0) {
+			pr_warning("Unreachable card detected in slot#3\n");
+			return -EBUSY;
+		}
+	} else
+		pr_info("PCIe slot#4 disabled\n");
+
+	return 0;
+}
+postcore_initcall(sdk7786_pci_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/Makefile linux-libre-2.6.37-gnu/arch/sh/drivers/pci/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 obj-$(CONFIG_SH_SH03)			+= fixups-sh03.o
 obj-$(CONFIG_SH_HIGHLANDER)		+= fixups-r7780rp.o
 obj-$(CONFIG_SH_SH7785LCR)		+= fixups-r7780rp.o
+obj-$(CONFIG_SH_SDK7786)		+= fixups-sdk7786.o
 obj-$(CONFIG_SH_SDK7780)		+= fixups-sdk7780.o
 obj-$(CONFIG_SH_7780_SOLUTION_ENGINE)	+= fixups-sdk7780.o
 obj-$(CONFIG_SH_TITAN)			+= fixups-titan.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/ops-sh4.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/ops-sh4.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/ops-sh4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/ops-sh4.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
  */
 #include <linux/pci.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 #include <asm/addrspace.h>
 #include "pci-sh4.h"
 
@@ -18,8 +19,6 @@
 #define CONFIG_CMD(bus, devfn, where) \
 	(0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
 
-static DEFINE_SPINLOCK(sh4_pci_lock);
-
 /*
  * Functions for accessing PCI configuration space with type 1 accesses
  */
@@ -34,10 +33,10 @@
 	 * PCIPDR may only be accessed as 32 bit words,
 	 * so we must do byte alignment by hand
 	 */
-	spin_lock_irqsave(&sh4_pci_lock, flags);
+	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
 	data = pci_read_reg(chan, SH4_PCIPDR);
-	spin_unlock_irqrestore(&sh4_pci_lock, flags);
+	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
 	switch (size) {
 	case 1:
@@ -69,10 +68,10 @@
 	int shift;
 	u32 data;
 
-	spin_lock_irqsave(&sh4_pci_lock, flags);
+	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
 	data = pci_read_reg(chan, SH4_PCIPDR);
-	spin_unlock_irqrestore(&sh4_pci_lock, flags);
+	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 
 	switch (size) {
 	case 1:
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/ops-sh7786.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/ops-sh7786.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/ops-sh7786.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/ops-sh7786.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * Generic SH7786 PCI-Express operations.
  *
- *  Copyright (C) 2009  Paul Mundt
+ *  Copyright (C) 2009 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License v2. See the file "COPYING" in the main directory of this archive
@@ -19,37 +19,72 @@
 	PCI_ACCESS_WRITE,
 };
 
-static DEFINE_SPINLOCK(sh7786_pcie_lock);
-
 static int sh7786_pcie_config_access(unsigned char access_type,
 		struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
 {
 	struct pci_channel *chan = bus->sysdata;
-	int dev, func;
+	int dev, func, type, reg;
 
 	dev = PCI_SLOT(devfn);
 	func = PCI_FUNC(devfn);
+	type = !!bus->parent;
+	reg = where & ~3;
 
 	if (bus->number > 255 || dev > 31 || func > 7)
 		return PCIBIOS_FUNC_NOT_SUPPORTED;
-	if (devfn)
-		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * While each channel has its own memory-mapped extended config
+	 * space, it's generally only accessible when in endpoint mode.
+	 * When in root complex mode, the controller is unable to target
+	 * itself with either type 0 or type 1 accesses, and indeed, any
+	 * controller initiated target transfer to its own config space
+	 * result in a completer abort.
+	 *
+	 * Each channel effectively only supports a single device, but as
+	 * the same channel <-> device access works for any PCI_SLOT()
+	 * value, we cheat a bit here and bind the controller's config
+	 * space to devfn 0 in order to enable self-enumeration. In this
+	 * case the regular PAR/PDR path is sidelined and the mangled
+	 * config access itself is initiated as a SuperHyway transaction.
+	 */
+	if (pci_is_root_bus(bus)) {
+		if (dev == 0) {
+			if (access_type == PCI_ACCESS_READ)
+				*data = pci_read_reg(chan, PCI_REG(reg));
+			else
+				pci_write_reg(chan, *data, PCI_REG(reg));
+
+			return PCIBIOS_SUCCESSFUL;
+		} else if (dev > 1)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	/* Clear errors */
+	pci_write_reg(chan, pci_read_reg(chan, SH4A_PCIEERRFR), SH4A_PCIEERRFR);
 
 	/* Set the PIO address */
 	pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
-				(func << 16) | (where & ~3), SH4A_PCIEPAR);
+				(func << 16) | reg, SH4A_PCIEPAR);
 
 	/* Enable the configuration access */
-	pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
+	pci_write_reg(chan, (1 << 31) | (type << 8), SH4A_PCIEPCTLR);
+
+	/* Check for errors */
+	if (pci_read_reg(chan, SH4A_PCIEERRFR) & 0x10)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Check for master and target aborts */
+	if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
+		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (access_type == PCI_ACCESS_READ)
 		*data = pci_read_reg(chan, SH4A_PCIEPDR);
 	else
 		pci_write_reg(chan, *data, SH4A_PCIEPDR);
 
-	/* Check for master and target aborts */
-	if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
-		return PCIBIOS_DEVICE_NOT_FOUND;
+	/* Disable the configuration access */
+	pci_write_reg(chan, 0, SH4A_PCIEPCTLR);
 
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -66,11 +101,13 @@
 	else if ((size == 4) && (where & 3))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
-	spin_lock_irqsave(&sh7786_pcie_lock, flags);
+	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
 					devfn, where, &data);
-	if (ret != PCIBIOS_SUCCESSFUL)
+	if (ret != PCIBIOS_SUCCESSFUL) {
+		*val = 0xffffffff;
 		goto out;
+	}
 
 	if (size == 1)
 		*val = (data >> ((where & 3) << 3)) & 0xff;
@@ -84,7 +121,7 @@
 		devfn, where, size, (unsigned long)*val);
 
 out:
-	spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 	return ret;
 }
 
@@ -100,7 +137,7 @@
 	else if ((size == 4) && (where & 3))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 
-	spin_lock_irqsave(&sh7786_pcie_lock, flags);
+	raw_spin_lock_irqsave(&pci_config_lock, flags);
 	ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
 					devfn, where, &data);
 	if (ret != PCIBIOS_SUCCESSFUL)
@@ -124,7 +161,7 @@
 	ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
 					devfn, where, &data);
 out:
-	spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+	raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/dma-debug.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 
 unsigned long PCIBIOS_MIN_IO = 0x0000;
 unsigned long PCIBIOS_MIN_MEM = 0;
@@ -56,6 +57,11 @@
 	}
 }
 
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+DEFINE_RAW_SPINLOCK(pci_config_lock);
 static DEFINE_MUTEX(pci_scan_mutex);
 
 int __devinit register_pci_controller(struct pci_channel *hose)
@@ -233,40 +239,7 @@
 
 int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-	u16 cmd, old_cmd;
-	int idx;
-	struct resource *r;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
-	for (idx=0; idx < PCI_NUM_RESOURCES; idx++) {
-		/* Only set up the requested stuff */
-		if (!(mask & (1<<idx)))
-			continue;
-
-		r = &dev->resource[idx];
-		if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
-			continue;
-		if ((idx == PCI_ROM_RESOURCE) &&
-				(!(r->flags & IORESOURCE_ROM_ENABLE)))
-			continue;
-		if (!r->start && r->end) {
-			printk(KERN_ERR "PCI: Device %s not available "
-			       "because of resource collisions\n",
-			       pci_name(dev));
-			return -EINVAL;
-		}
-		if (r->flags & IORESOURCE_IO)
-			cmd |= PCI_COMMAND_IO;
-		if (r->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-	}
-	if (cmd != old_cmd) {
-		printk("PCI: Enabling device %s (%04x -> %04x)\n",
-		       pci_name(dev), old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
-	return 0;
+	return pci_enable_resources(dev, mask);
 }
 
 /*
@@ -295,7 +268,7 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-char * __devinit pcibios_setup(char *str)
+char * __devinit __weak pcibios_setup(char *str)
 {
 	return str;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pcie-sh7786.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pcie-sh7786.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pcie-sh7786.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pcie-sh7786.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,11 +13,14 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
 #include "pcie-sh7786.h"
 #include <asm/sizes.h>
 
 struct sh7786_pcie_port {
 	struct pci_channel	*hose;
+	struct clk		*fclk, phy_clk;
 	unsigned int		index;
 	int			endpoint;
 	int			link;
@@ -51,6 +54,7 @@
 		.name	= "PCIe0 MEM 2",
 		.start	= 0xfe100000,
 		.end	= 0xfe100000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
 	},
 };
 
@@ -74,6 +78,7 @@
 		.name	= "PCIe1 MEM 2",
 		.start	= 0xfe300000,
 		.end	= 0xfe300000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
 	},
 };
 
@@ -82,6 +87,7 @@
 		.name	= "PCIe2 IO",
 		.start	= 0xfc800000,
 		.end	= 0xfc800000 + SZ_4M - 1,
+		.flags	= IORESOURCE_IO,
 	}, {
 		.name	= "PCIe2 MEM 0",
 		.start	= 0x80000000,
@@ -96,6 +102,7 @@
 		.name	= "PCIe2 MEM 2",
 		.start	= 0xfcd00000,
 		.end	= 0xfcd00000 + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
 	},
 };
 
@@ -117,7 +124,29 @@
 	DEFINE_CONTROLLER(0xfcc00000, 2),
 };
 
-static int phy_wait_for_ack(struct pci_channel *chan)
+static struct clk fixed_pciexclkp = {
+	.rate = 100000000,	/* 100 MHz reference clock */
+};
+
+static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+{
+	/*
+	 * Prevent enumeration of root complex resources.
+	 */
+	if (pci_is_root_bus(dev->bus) && dev->devfn == 0) {
+		int i;
+
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			dev->resource[i].start	= 0;
+			dev->resource[i].end	= 0;
+			dev->resource[i].flags	= 0;
+		}
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_SH7786,
+			 sh7786_pci_fixup);
+
+static int __init phy_wait_for_ack(struct pci_channel *chan)
 {
 	unsigned int timeout = 100;
 
@@ -131,7 +160,7 @@
 	return -ETIMEDOUT;
 }
 
-static int pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
+static int __init pci_wait_for_irq(struct pci_channel *chan, unsigned int mask)
 {
 	unsigned int timeout = 100;
 
@@ -145,19 +174,14 @@
 	return -ETIMEDOUT;
 }
 
-static void phy_write_reg(struct pci_channel *chan, unsigned int addr,
-			  unsigned int lane, unsigned int data)
+static void __init phy_write_reg(struct pci_channel *chan, unsigned int addr,
+				 unsigned int lane, unsigned int data)
 {
-	unsigned long phyaddr, ctrl;
+	unsigned long phyaddr;
 
 	phyaddr = (1 << BITS_CMD) + ((lane & 0xf) << BITS_LANE) +
 			((addr & 0xff) << BITS_ADR);
 
-	/* Enable clock */
-	ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-	ctrl |= (1 << BITS_CKE);
-	pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
-
 	/* Set write data */
 	pci_write_reg(chan, data, SH4A_PCIEPHYDOUTR);
 	pci_write_reg(chan, phyaddr, SH4A_PCIEPHYADRR);
@@ -165,20 +189,74 @@
 	phy_wait_for_ack(chan);
 
 	/* Clear command */
+	pci_write_reg(chan, 0, SH4A_PCIEPHYDOUTR);
 	pci_write_reg(chan, 0, SH4A_PCIEPHYADRR);
 
 	phy_wait_for_ack(chan);
+}
 
-	/* Disable clock */
-	ctrl = pci_read_reg(chan, SH4A_PCIEPHYCTLR);
-	ctrl &= ~(1 << BITS_CKE);
-	pci_write_reg(chan, ctrl, SH4A_PCIEPHYCTLR);
+static int __init pcie_clk_init(struct sh7786_pcie_port *port)
+{
+	struct pci_channel *chan = port->hose;
+	struct clk *clk;
+	char fclk_name[16];
+	int ret;
+
+	/*
+	 * First register the fixed clock
+	 */
+	ret = clk_register(&fixed_pciexclkp);
+	if (unlikely(ret != 0))
+		return ret;
+
+	/*
+	 * Grab the port's function clock, which the PHY clock depends
+	 * on. clock lookups don't help us much at this point, since no
+	 * dev_id is available this early. Lame.
+	 */
+	snprintf(fclk_name, sizeof(fclk_name), "pcie%d_fck", port->index);
+
+	port->fclk = clk_get(NULL, fclk_name);
+	if (IS_ERR(port->fclk)) {
+		ret = PTR_ERR(port->fclk);
+		goto err_fclk;
+	}
+
+	clk_enable(port->fclk);
+
+	/*
+	 * And now, set up the PHY clock
+	 */
+	clk = &port->phy_clk;
+
+	memset(clk, 0, sizeof(struct clk));
+
+	clk->parent = &fixed_pciexclkp;
+	clk->enable_reg = (void __iomem *)(chan->reg_base + SH4A_PCIEPHYCTLR);
+	clk->enable_bit = BITS_CKE;
+
+	ret = sh_clk_mstp32_register(clk, 1);
+	if (unlikely(ret < 0))
+		goto err_phy;
+
+	return 0;
+
+err_phy:
+	clk_disable(port->fclk);
+	clk_put(port->fclk);
+err_fclk:
+	clk_unregister(&fixed_pciexclkp);
+
+	return ret;
 }
 
-static int phy_init(struct pci_channel *chan)
+static int __init phy_init(struct sh7786_pcie_port *port)
 {
+	struct pci_channel *chan = port->hose;
 	unsigned int timeout = 100;
 
+	clk_enable(&port->phy_clk);
+
 	/* Initialize the phy */
 	phy_write_reg(chan, 0x60, 0xf, 0x004b008b);
 	phy_write_reg(chan, 0x61, 0xf, 0x00007b41);
@@ -187,9 +265,13 @@
 	phy_write_reg(chan, 0x66, 0xf, 0x00000010);
 	phy_write_reg(chan, 0x74, 0xf, 0x0007001c);
 	phy_write_reg(chan, 0x79, 0xf, 0x01fc000d);
+	phy_write_reg(chan, 0xb0, 0xf, 0x00000610);
 
 	/* Deassert Standby */
-	phy_write_reg(chan, 0x67, 0xf, 0x00000400);
+	phy_write_reg(chan, 0x67, 0x1, 0x00000400);
+
+	/* Disable clock */
+	clk_disable(&port->phy_clk);
 
 	while (timeout--) {
 		if (pci_read_reg(chan, SH4A_PCIEPHYSR))
@@ -201,22 +283,33 @@
 	return -ETIMEDOUT;
 }
 
-static int pcie_init(struct sh7786_pcie_port *port)
+static void __init pcie_reset(struct sh7786_pcie_port *port)
+{
+	struct pci_channel *chan = port->hose;
+
+	pci_write_reg(chan, 1, SH4A_PCIESRSTR);
+	pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+	pci_write_reg(chan, 0, SH4A_PCIESRSTR);
+	pci_write_reg(chan, 0, SH4A_PCIETXVC0SR);
+}
+
+static int __init pcie_init(struct sh7786_pcie_port *port)
 {
 	struct pci_channel *chan = port->hose;
 	unsigned int data;
 	phys_addr_t memphys;
 	size_t memsize;
-	int ret, i;
+	int ret, i, win;
 
 	/* Begin initialization */
-	pci_write_reg(chan, 0, SH4A_PCIETCTLR);
+	pcie_reset(port);
 
-	/* Initialize as type1. */
-	data = pci_read_reg(chan, SH4A_PCIEPCICONF3);
-	data &= ~(0x7f << 16);
-	data |= PCI_HEADER_TYPE_BRIDGE << 16;
-	pci_write_reg(chan, data, SH4A_PCIEPCICONF3);
+	/*
+	 * Initial header for port config space is type 1, set the device
+	 * class to match. Hardware takes care of propagating the IDSETR
+	 * settings, so there is no need to bother with a quirk.
+	 */
+	pci_write_reg(chan, PCI_CLASS_BRIDGE_PCI << 16, SH4A_PCIEIDSETR1);
 
 	/* Initialize default capabilities. */
 	data = pci_read_reg(chan, SH4A_PCIEEXPCAP0);
@@ -268,30 +361,33 @@
 	 * LAR1/LAMR1.
 	 */
 	if (memsize > SZ_512M) {
-		__raw_writel(memphys + SZ_512M, chan->reg_base + SH4A_PCIELAR1);
-		__raw_writel(((memsize - SZ_512M) - SZ_256) | 1,
-			     chan->reg_base + SH4A_PCIELAMR1);
+		pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
+		pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
+			      SH4A_PCIELAMR1);
 		memsize = SZ_512M;
 	} else {
 		/*
 		 * Otherwise just zero it out and disable it.
 		 */
-		__raw_writel(0, chan->reg_base + SH4A_PCIELAR1);
-		__raw_writel(0, chan->reg_base + SH4A_PCIELAMR1);
+		pci_write_reg(chan, 0, SH4A_PCIELAR1);
+		pci_write_reg(chan, 0, SH4A_PCIELAMR1);
 	}
 
 	/*
 	 * LAR0/LAMR0 covers up to the first 512MB, which is enough to
 	 * cover all of lowmem on most platforms.
 	 */
-	__raw_writel(memphys, chan->reg_base + SH4A_PCIELAR0);
-	__raw_writel((memsize - SZ_256) | 1, chan->reg_base + SH4A_PCIELAMR0);
+	pci_write_reg(chan, memphys, SH4A_PCIELAR0);
+	pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
 
 	/* Finish initialization */
 	data = pci_read_reg(chan, SH4A_PCIETCTLR);
 	data |= 0x1;
 	pci_write_reg(chan, data, SH4A_PCIETCTLR);
 
+	/* Let things settle down a bit.. */
+	mdelay(100);
+
 	/* Enable DL_Active Interrupt generation */
 	data = pci_read_reg(chan, SH4A_PCIEDLINTENR);
 	data |= PCIEDLINTENR_DLL_ACT_ENABLE;
@@ -302,9 +398,12 @@
 	data |= PCIEMACCTLR_SCR_DIS | (0xff << 16);
 	pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
 
+	/*
+	 * This will timeout if we don't have a link, but we permit the
+	 * port to register anyways in order to support hotplug on future
+	 * hardware.
+	 */
 	ret = pci_wait_for_irq(chan, MASK_INT_TX_CTRL);
-	if (unlikely(ret != 0))
-		return -ENODEV;
 
 	data = pci_read_reg(chan, SH4A_PCIEPCICONF1);
 	data &= ~(PCI_STATUS_DEVSEL_MASK << 16);
@@ -317,35 +416,48 @@
 
 	wmb();
 
-	data = pci_read_reg(chan, SH4A_PCIEMACSR);
-	printk(KERN_NOTICE "PCI: PCIe#%d link width %d\n",
-	       port->index, (data >> 20) & 0x3f);
-
+	if (ret == 0) {
+		data = pci_read_reg(chan, SH4A_PCIEMACSR);
+		printk(KERN_NOTICE "PCI: PCIe#%d x%d link detected\n",
+		       port->index, (data >> 20) & 0x3f);
+	} else
+		printk(KERN_NOTICE "PCI: PCIe#%d link down\n",
+		       port->index);
 
-	for (i = 0; i < chan->nr_resources; i++) {
+	for (i = win = 0; i < chan->nr_resources; i++) {
 		struct resource *res = chan->resources + i;
 		resource_size_t size;
-		u32 enable_mask;
+		u32 mask;
 
-		pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(i));
+		/*
+		 * We can't use the 32-bit mode windows in legacy 29-bit
+		 * mode, so just skip them entirely.
+		 */
+		if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
+			continue;
 
-		size = resource_size(res);
+		pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
 
 		/*
 		 * The PAMR mask is calculated in units of 256kB, which
 		 * keeps things pretty simple.
 		 */
-		__raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,
-			     chan->reg_base + SH4A_PCIEPAMR(i));
+		size = resource_size(res);
+		mask = (roundup_pow_of_two(size) / SZ_256K) - 1;
+		pci_write_reg(chan, mask << 18, SH4A_PCIEPAMR(win));
 
-		pci_write_reg(chan, 0x00000000, SH4A_PCIEPARH(i));
-		pci_write_reg(chan, 0x00000000, SH4A_PCIEPARL(i));
+		pci_write_reg(chan, upper_32_bits(res->start),
+			      SH4A_PCIEPARH(win));
+		pci_write_reg(chan, lower_32_bits(res->start),
+			      SH4A_PCIEPARL(win));
 
-		enable_mask = MASK_PARE;
+		mask = MASK_PARE;
 		if (res->flags & IORESOURCE_IO)
-			enable_mask |= MASK_SPC;
+			mask |= MASK_SPC;
 
-		pci_write_reg(chan, enable_mask, SH4A_PCIEPTCTLR(i));
+		pci_write_reg(chan, mask, SH4A_PCIEPTCTLR(win));
+
+		win++;
 	}
 
 	return 0;
@@ -356,26 +468,33 @@
         return 71;
 }
 
-static int sh7786_pcie_core_init(void)
+static int __init sh7786_pcie_core_init(void)
 {
 	/* Return the number of ports */
 	return test_mode_pin(MODE_PIN12) ? 3 : 2;
 }
 
-static int __devinit sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
+static int __init sh7786_pcie_init_hw(struct sh7786_pcie_port *port)
 {
 	int ret;
 
-	ret = phy_init(port->hose);
-	if (unlikely(ret < 0))
-		return ret;
-
 	/*
 	 * Check if we are configured in endpoint or root complex mode,
 	 * this is a fixed pin setting that applies to all PCIe ports.
 	 */
 	port->endpoint = test_mode_pin(MODE_PIN11);
 
+	/*
+	 * Setup clocks, needed both for PHY and PCIe registers.
+	 */
+	ret = pcie_clk_init(port);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = phy_init(port);
+	if (unlikely(ret < 0))
+		return ret;
+
 	ret = pcie_init(port);
 	if (unlikely(ret < 0))
 		return ret;
@@ -390,9 +509,10 @@
 
 static int __init sh7786_pcie_init(void)
 {
+	struct clk *platclk;
 	int ret = 0, i;
 
-	printk(KERN_NOTICE "PCI: Starting intialization.\n");
+	printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
 	sh7786_pcie_hwops = &sh7786_65nm_pcie_hwops;
 
@@ -407,6 +527,22 @@
 	if (unlikely(!sh7786_pcie_ports))
 		return -ENOMEM;
 
+	/*
+	 * Fetch any optional platform clock associated with this block.
+	 *
+	 * This is a rather nasty hack for boards with spec-mocking FPGAs
+	 * that have a secondary set of clocks outside of the on-chip
+	 * ones that need to be accounted for before there is any chance
+	 * of touching the existing MSTP bits or CPG clocks.
+	 */
+	platclk = clk_get(NULL, "pcie_plat_clk");
+	if (IS_ERR(platclk)) {
+		/* Sane hardware should probably get a WARN_ON.. */
+		platclk = NULL;
+	}
+
+	clk_enable(platclk);
+
 	printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
 
 	for (i = 0; i < nr_ports; i++) {
@@ -419,8 +555,11 @@
 		ret |= sh7786_pcie_hwops->port_init_hw(port);
 	}
 
-	if (unlikely(ret))
+	if (unlikely(ret)) {
+		clk_disable(platclk);
+		clk_put(platclk);
 		return ret;
+	}
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pcie-sh7786.h linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pcie-sh7786.h
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pcie-sh7786.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pcie-sh7786.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,8 +55,11 @@
 #define		BITS_ERRRCV	(0)		/* 0 ERRRCV 0 */
 #define		MASK_ERRRCV	(1<<BITS_ERRRCV)
 
+/*	PCIEENBLR	 */
+#define	SH4A_PCIEENBLR		(0x000008)	/* R/W - 0x0000 0001 32 */
+
 /*	PCIEECR		*/
-#define	SH4A_PCIEECR		(0x000008)	/* R/W - 0x0000 0000 32 */
+#define	SH4A_PCIEECR		(0x00000C)	/* R/W - 0x0000 0000 32 */
 #define		BITS_ENBL	(0)	/* 0 ENBL 0 R/W */
 #define		MASK_ENBL	(1<<BITS_ENBL)
 
@@ -113,6 +116,27 @@
 #define		BITS_MDATA	(0)
 #define		MASK_MDATA	(0xffffffff<<BITS_MDATA)
 
+/*	PCIEUNLOCKCR	*/
+#define	SH4A_PCIEUNLOCKCR	(0x000048)	/* R/W - 0x0000 0000 32 */
+
+/*	PCIEIDR		*/
+#define	SH4A_PCIEIDR		(0x000060)	/* R/W - 0x0101 1101 32 */
+
+/*	PCIEDBGCTLR	*/
+#define	SH4A_PCIEDBGCTLR	(0x000100)	/* R/W - 0x0000 0000 32 */
+
+/*	PCIEINTXR	*/
+#define	SH4A_PCIEINTXR		(0x004000)	/* R/W - 0x0000 0000 32 */
+
+/*	PCIERMSGR	*/
+#define	SH4A_PCIERMSGR		(0x004010)	/* R/W - 0x0000 0000 32 */
+
+/*	PCIERSTR	*/
+#define SH4A_PCIERSTR(x)	(0x008000 + ((x) * 0x4)) /* R/W - 0x0000 0000 32 */
+
+/*	PCIESRSTR	 */
+#define SH4A_PCIESRSTR		(0x008040)	/* R/W - 0x0000 0000 32 */
+
 /*	PCIEPHYCTLR	*/
 #define	SH4A_PCIEPHYCTLR	(0x010000)	/* R/W - 0x0000 0000 32 */
 #define		BITS_CKE	(0)
@@ -121,6 +145,9 @@
 /*	PCIERMSGIER	*/
 #define	SH4A_PCIERMSGIER	(0x004040)	/* R/W - 0x0000 0000 32 */
 
+/*	PCIEPHYCTLR	*/
+#define SH4A_PCIEPHYCTLR	(0x010000)	/* R/W - 0x0000 0000 32 */
+
 /*	PCIEPHYADRR	*/
 #define	SH4A_PCIEPHYADRR	(0x010004)	/* R/W - 0x0000 0000 32 */
 #define		BITS_ACK	(24)			// Rev1.171
@@ -152,7 +179,7 @@
 #define		MASK_CFINT	(1<<BITS_CFINT)
 
 /*	PCIETSTR	*/
-#define	SH4A_PCIETSTR		(0x020004)	/* R/W R/W 0x0000 0000 32  */
+#define	SH4A_PCIETSTR		(0x020004)	/* R 0x0000 0000 32  */
 
 /*	PCIEINTR	*/
 #define	SH4A_PCIEINTR		(0x020008)	/* R/W R/W 0x0000 0000 32  */
@@ -236,6 +263,9 @@
 #define		BITS_INTPM			(8)
 #define		MASK_INTPM			(1<<BITS_INTPM)
 
+/*	PCIEEH0R	*/
+#define SH4A_PCIEEHR(x)		(0x020010 + ((x) * 0x4)) /* R - 0x0000 0000 32 */
+
 /*	PCIEAIR	 */
 #define	SH4A_PCIEAIR		(SH4A_PCIE_BASE + 0x020010)	/* R/W R/W 0xxxxx xxxx 32 */
 
@@ -244,6 +274,25 @@
 
 /*	 PCIEERRFR	 */								// Rev1.18
 #define	SH4A_PCIEERRFR		(0x020020)		/* R/W R/W 0xxxxx xxxx 32 */	// Rev1.18
+
+/*	PCIEERRFER	*/
+#define SH4A_PCIEERRFER		(0x020024)		/* R/W R/W 0x0000 0000 32 */
+
+/*	PCIEERRFR2	*/
+#define SH4A_PCIEERRFR2		(0x020028)		/* R/W R/W 0x0000 0000 32 */
+
+/*	PCIEMSIR	*/
+#define SH4A_PCIEMSIR		(0x020040)		/* R/W - 0x0000 0000 32 */
+
+/*	PCIEMSIFR	*/
+#define SH4A_PCIEMSIFR		(0x020044)		/* R/W R/W 0x0000 0000 32 */
+
+/*	PCIEPWRCTLR	*/
+#define SH4A_PCIEPWRCTLR	(0x020100)		/* R/W - 0x0000 0000 32 */
+
+/*	PCIEPCCTLR	*/
+#define SH4A_PCIEPCCTLR		(0x020180)		/* R/W - 0x0000 0000 32 */
+
 											// Rev1.18
 /*	PCIELAR0	*/
 #define	SH4A_PCIELAR0		(0x020200)	/* R/W R/W 0x0000 0000 32 */
@@ -352,6 +401,7 @@
 #define	SH4A_PCIEDMCCR0		(0x021120)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMCC2R0	(0x021124)	/* R/W R/W 0x0000 0000 - */
 #define	SH4A_PCIEDMCCCR0	(0x021128)	/* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR0	(0x02112C)	/* R/W - 0x0000 0000 32 */
 #define	SH4A_PCIEDMSAR1		(0x021140)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMSAHR1	(0x021144)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMDAR1		(0x021148)	/* R/W R/W 0x0000 0000 32 */
@@ -363,6 +413,7 @@
 #define	SH4A_PCIEDMCCR1		(0x021160)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMCC2R1	(0x021164)	/* R/W R/W 0x0000 0000 - */
 #define	SH4A_PCIEDMCCCR1	(0x021168)	/* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR1	(0x02116C)	/* R/W - 0x0000 0000 32 */
 #define	SH4A_PCIEDMSAR2		(0x021180)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMSAHR2	(0x021184)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMDAR2		(0x021188)	/* R/W R/W 0x0000 0000 32 */
@@ -385,6 +436,7 @@
 #define	SH4A_PCIEDMCCR3		(0x0211E0)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEDMCC2R3	(0x0211E4)	/* R/W R/W 0x0000 0000 -  */
 #define	SH4A_PCIEDMCCCR3	(0x0211E8)	/* R/W R/W 0x0000 0000 32 */
+#define SH4A_PCIEDMCHSR3	(0x0211EC)	/* R/W R/W 0x0000 0000 32 */
 #define	SH4A_PCIEPCICONF0	(0x040000)	/* R R - 8/16/32 */
 #define	SH4A_PCIEPCICONF1	(0x040004)	/* R/W R/W 0x0008 0000 8/16/32 */
 #define	SH4A_PCIEPCICONF2	(0x040008)	/* R/W R/W 0xFF00 0000 8/16/32 */
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7751.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7751.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7751.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7751.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,7 +81,7 @@
 	unsigned int id;
 	u32 word, reg;
 
-	printk(KERN_NOTICE "PCI: Starting intialization.\n");
+	printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
 	chan->reg_base = 0xfe200000;
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7780.c linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7780.c
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7780.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7780.c	2011-01-04 19:50:19.000000000 -0500
@@ -246,7 +246,7 @@
 	const char *type;
 	int ret, i;
 
-	printk(KERN_NOTICE "PCI: Starting intialization.\n");
+	printk(KERN_NOTICE "PCI: Starting initialization.\n");
 
 	chan->reg_base = 0xfe040000;
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7780.h linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7780.h
--- linux-libre-2.6.36-gnu/arch/sh/drivers/pci/pci-sh7780.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/drivers/pci/pci-sh7780.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,12 +12,6 @@
 #ifndef _PCI_SH7780_H_
 #define _PCI_SH7780_H_
 
-#define PCI_VENDOR_ID_RENESAS		0x1912
-#define PCI_DEVICE_ID_RENESAS_SH7781	0x0001
-#define PCI_DEVICE_ID_RENESAS_SH7780	0x0002
-#define PCI_DEVICE_ID_RENESAS_SH7763	0x0004
-#define PCI_DEVICE_ID_RENESAS_SH7785	0x0007
-
 /* SH7780 Control Registers */
 #define	PCIECR			0xFE000008
 #define PCIECR_ENBL		0x01
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/addrspace.h linux-libre-2.6.37-gnu/arch/sh/include/asm/addrspace.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/addrspace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/addrspace.h	2011-01-04 19:50:19.000000000 -0500
@@ -44,10 +44,10 @@
 /*
  * These will never work in 32-bit, don't even bother.
  */
-#define P1SEGADDR(a)	__futile_remapping_attempt
-#define P2SEGADDR(a)	__futile_remapping_attempt
-#define P3SEGADDR(a)	__futile_remapping_attempt
-#define P4SEGADDR(a)	__futile_remapping_attempt
+#define P1SEGADDR(a)	({ (void)(a); BUG(); NULL; })
+#define P2SEGADDR(a)	({ (void)(a); BUG(); NULL; })
+#define P3SEGADDR(a)	({ (void)(a); BUG(); NULL; })
+#define P4SEGADDR(a)	({ (void)(a); BUG(); NULL; })
 #endif
 #endif /* P1SEG */
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/cacheflush.h linux-libre-2.6.37-gnu/arch/sh/include/asm/cacheflush.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/cacheflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/cacheflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -96,7 +96,7 @@
 void *kmap_coherent(struct page *page, unsigned long addr);
 void kunmap_coherent(void *kvaddr);
 
-#define PG_dcache_dirty	PG_arch_1
+#define PG_dcache_clean	PG_arch_1
 
 void cpu_cache_init(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/elf.h linux-libre-2.6.37-gnu/arch/sh/include/asm/elf.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/elf.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/elf.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,25 +50,14 @@
 #define	R_SH_GOTPC		167
 
 /* FDPIC relocs */
-#define R_SH_GOT20		70
-#define R_SH_GOTOFF20		71
-#define R_SH_GOTFUNCDESC	72
-#define R_SH_GOTFUNCDESC20	73
-#define R_SH_GOTOFFFUNCDESC	74
-#define R_SH_GOTOFFFUNCDESC20	75
-#define R_SH_FUNCDESC		76
-#define R_SH_FUNCDESC_VALUE	77
-
-#if 0 /* XXX - later .. */
-#define R_SH_GOT20		198
-#define R_SH_GOTOFF20		199
-#define R_SH_GOTFUNCDESC	200
-#define R_SH_GOTFUNCDESC20	201
-#define R_SH_GOTOFFFUNCDESC	202
-#define R_SH_GOTOFFFUNCDESC20	203
-#define R_SH_FUNCDESC		204
-#define R_SH_FUNCDESC_VALUE	205
-#endif
+#define R_SH_GOT20		201
+#define R_SH_GOTOFF20		202
+#define R_SH_GOTFUNCDESC	203
+#define R_SH_GOTFUNCDESC20	204
+#define R_SH_GOTOFFFUNCDESC	205
+#define R_SH_GOTOFFFUNCDESC20	206
+#define R_SH_FUNCDESC		207
+#define R_SH_FUNCDESC_VALUE	208
 
 /* SHmedia relocs */
 #define R_SH_IMM_LOW16		246
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/fixmap.h linux-libre-2.6.37-gnu/arch/sh/include/asm/fixmap.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/fixmap.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/fixmap.h	2011-01-04 19:50:19.000000000 -0500
@@ -58,7 +58,7 @@
 
 #ifdef CONFIG_HIGHMEM
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
-	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+	FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
 #endif
 
 #ifdef CONFIG_IOREMAP_FIXED
@@ -69,7 +69,7 @@
 	 */
 #define FIX_N_IOREMAPS	32
 	FIX_IOREMAP_BEGIN,
-	FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS,
+	FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1,
 #endif
 
 	__end_of_fixed_addresses
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/gpio.h linux-libre-2.6.37-gnu/arch/sh/include/asm/gpio.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/gpio.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/gpio.h	2011-01-04 19:50:19.000000000 -0500
@@ -41,14 +41,12 @@
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-	WARN_ON(1);
-	return -ENOSYS;
+	return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-	WARN_ON(1);
-	return -EINVAL;
+	return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/ilsel.h linux-libre-2.6.37-gnu/arch/sh/include/asm/ilsel.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/ilsel.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/ilsel.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,45 +0,0 @@
-#ifndef __ASM_SH_ILSEL_H
-#define __ASM_SH_ILSEL_H
-
-typedef enum {
-	ILSEL_NONE,
-	ILSEL_LAN,
-	ILSEL_USBH_I,
-	ILSEL_USBH_S,
-	ILSEL_USBH_V,
-	ILSEL_RTC,
-	ILSEL_USBP_I,
-	ILSEL_USBP_S,
-	ILSEL_USBP_V,
-	ILSEL_KEY,
-
-	/*
-	 * ILSEL Aliases - corner cases for interleaved level tables.
-	 *
-	 * Someone thought this was a good idea and less hassle than
-	 * demuxing a shared vector, really.
-	 */
-
-	/* ILSEL0 and 2 */
-	ILSEL_FPGA0,
-	ILSEL_FPGA1,
-	ILSEL_EX1,
-	ILSEL_EX2,
-	ILSEL_EX3,
-	ILSEL_EX4,
-
-	/* ILSEL1 and 3 */
-	ILSEL_FPGA2 = ILSEL_FPGA0,
-	ILSEL_FPGA3 = ILSEL_FPGA1,
-	ILSEL_EX5 = ILSEL_EX1,
-	ILSEL_EX6 = ILSEL_EX2,
-	ILSEL_EX7 = ILSEL_EX3,
-	ILSEL_EX8 = ILSEL_EX4,
-} ilsel_source_t;
-
-/* arch/sh/boards/renesas/x3proto/ilsel.c */
-int ilsel_enable(ilsel_source_t set);
-int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
-void ilsel_disable(unsigned int irq);
-
-#endif /* __ASM_SH_ILSEL_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/sh/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 #ifndef __ASM_SH_IRQFLAGS_H
 #define __ASM_SH_IRQFLAGS_H
 
-#define RAW_IRQ_DISABLED	0xf0
-#define RAW_IRQ_ENABLED		0x00
+#define ARCH_IRQ_DISABLED	0xf0
+#define ARCH_IRQ_ENABLED	0x00
 
 #include <asm-generic/irqflags.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/irq.h linux-libre-2.6.37-gnu/arch/sh/include/asm/irq.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,7 @@
  * advised to cap this at the hard limit that they're interested in
  * through the machvec.
  */
-#define NR_IRQS			256
+#define NR_IRQS			512
 #define NR_IRQS_LEGACY		8	/* Legacy external IRQ0-7 */
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/Kbuild linux-libre-2.6.37-gnu/arch/sh/include/asm/Kbuild
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -5,5 +5,7 @@
 header-y += hw_breakpoint.h
 header-y += posix_types_32.h
 header-y += posix_types_64.h
+header-y += ptrace_32.h
+header-y += ptrace_64.h
 header-y += unistd_32.h
 header-y += unistd_64.h
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/kprobes.h linux-libre-2.6.37-gnu/arch/sh/include/asm/kprobes.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/kprobes.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/kprobes.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 	? (MAX_STACK_SIZE) \
 	: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
 
-#define regs_return_value(_regs)		((_regs)->regs[0])
 #define flush_insn_slot(p)		do { } while (0)
 #define kretprobe_blacklist_size	0
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/sh/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/memblock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,4 @@
 #ifndef __ASM_SH_MEMBLOCK_H
 #define __ASM_SH_MEMBLOCK_H
 
-#define MEMBLOCK_REAL_LIMIT	0
-
 #endif /* __ASM_SH_MEMBLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/pci.h linux-libre-2.6.37-gnu/arch/sh/include/asm/pci.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -37,6 +37,8 @@
 };
 
 /* arch/sh/drivers/pci/pci.c */
+extern raw_spinlock_t pci_config_lock;
+
 extern int register_pci_controller(struct pci_channel *hose);
 extern void pcibios_report_status(unsigned int status_mask, int warn);
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/sh/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,11 +26,4 @@
 extern int reserve_pmc_hardware(void);
 extern void release_pmc_hardware(void);
 
-static inline void set_perf_event_pending(void)
-{
-	/* Nothing to see here, move along. */
-}
-
-#define PERF_EVENT_INDEX_OFFSET	0
-
 #endif /* __ASM_SH_PERF_EVENT_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -378,8 +378,6 @@
 PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED);
 PTE_BIT_FUNC(low, mkspecial, |= _PAGE_SPECIAL);
 
-#define __HAVE_ARCH_PTE_SPECIAL
-
 /*
  * Macro and implementation to make a page protection as uncachable.
  */
@@ -429,10 +427,7 @@
 #define pte_offset_kernel(dir, address) \
 	((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address))
 #define pte_offset_map(dir, address)		pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address)	pte_offset_kernel(dir, address)
-
 #define pte_unmap(pte)		do { } while (0)
-#define pte_unmap_nested(pte)	do { } while (0)
 
 #ifdef CONFIG_X2TLB
 #define pte_ERROR(e) \
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable_64.h linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable_64.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -84,9 +84,7 @@
 		((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr)))
 
 #define pte_offset_map(dir,addr)	pte_offset_kernel(dir, addr)
-#define pte_offset_map_nested(dir,addr)	pte_offset_kernel(dir, addr)
 #define pte_unmap(pte)		do { } while (0)
-#define pte_unmap_nested(pte)	do { } while (0)
 
 #ifndef __ASSEMBLY__
 #define IOBASE_VADDR	0xff000000
@@ -132,6 +130,7 @@
  * anything above the PPN field.
  */
 #define _PAGE_WIRED	_PAGE_EXT(0x001) /* software: wire the tlb entry */
+#define _PAGE_SPECIAL	_PAGE_EXT(0x002)
 
 #define _PAGE_CLEAR_FLAGS	(_PAGE_PRESENT | _PAGE_FILE | _PAGE_SHARED | \
 				 _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED)
@@ -175,7 +174,8 @@
 /* Default flags for a User page */
 #define _PAGE_TABLE	(_KERNPG_TABLE | _PAGE_USER)
 
-#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
+			 _PAGE_SPECIAL)
 
 /*
  * We have full permissions (Read/Write/Execute/Shared).
@@ -265,7 +265,7 @@
 static inline int pte_young(pte_t pte)  { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)   { return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_write(pte_t pte)  { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_special(pte_t pte){ return 0; }
+static inline int pte_special(pte_t pte){ return pte_val(pte) & _PAGE_SPECIAL; }
 
 static inline pte_t pte_wrprotect(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; }
 static inline pte_t pte_mkclean(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
@@ -274,8 +274,7 @@
 static inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 static inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 static inline pte_t pte_mkhuge(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; }
-static inline pte_t pte_mkspecial(pte_t pte)	{ return pte; }
-
+static inline pte_t pte_mkspecial(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; }
 
 /*
  * Conversion functions: convert a page and protection to a page entry.
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -66,7 +66,6 @@
 #define PHYS_ADDR_MASK29		0x1fffffff
 #define PHYS_ADDR_MASK32		0xffffffff
 
-#ifdef CONFIG_PMB
 static inline unsigned long phys_addr_mask(void)
 {
 	/* Is the MMU in 29bit mode? */
@@ -75,17 +74,6 @@
 
 	return PHYS_ADDR_MASK32;
 }
-#elif defined(CONFIG_32BIT)
-static inline unsigned long phys_addr_mask(void)
-{
-	return PHYS_ADDR_MASK32;
-}
-#else
-static inline unsigned long phys_addr_mask(void)
-{
-	return PHYS_ADDR_MASK29;
-}
-#endif
 
 #define PTE_PHYS_MASK		(phys_addr_mask() & PAGE_MASK)
 #define PTE_FLAGS_MASK		(~(PTE_PHYS_MASK) << PAGE_SHIFT)
@@ -169,6 +157,8 @@
 #define HAVE_ARCH_UNMAPPED_AREA
 #define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
 
+#define __HAVE_ARCH_PTE_SPECIAL
+
 #include <asm-generic/pgtable.h>
 
 #endif /* __ASM_SH_PGTABLE_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/processor_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/processor_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/processor_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/processor_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 #include <asm/page.h>
 #include <asm/types.h>
-#include <asm/ptrace.h>
 #include <asm/hw_breakpoint.h>
 
 /*
@@ -194,18 +193,19 @@
 #define KSTK_EIP(tsk)  (task_pt_regs(tsk)->pc)
 #define KSTK_ESP(tsk)  (task_pt_regs(tsk)->regs[15])
 
-#define user_stack_pointer(_regs)	((_regs)->regs[15])
-
 #if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4)
 #define PREFETCH_STRIDE		L1_CACHE_BYTES
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
 static inline void prefetch(void *x)
 {
-	__asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
+	__builtin_prefetch(x, 0, 3);
 }
 
-#define prefetchw(x)	prefetch(x)
+static inline void prefetchw(void *x)
+{
+	__builtin_prefetch(x, 1, 3);
+}
 #endif
 
 #endif /* __KERNEL__ */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/processor_64.h linux-libre-2.6.37-gnu/arch/sh/include/asm/processor_64.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/processor_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/processor_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,6 @@
 #include <linux/compiler.h>
 #include <asm/page.h>
 #include <asm/types.h>
-#include <asm/ptrace.h>
 #include <cpu/registers.h>
 
 /*
@@ -231,7 +230,5 @@
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 #define KSTK_ESP(tsk)  ((tsk)->thread.sp)
 
-#define user_stack_pointer(_regs)	((_regs)->regs[15])
-
 #endif	/* __ASSEMBLY__ */
 #endif /* __ASM_SH_PROCESSOR_64_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/processor.h linux-libre-2.6.37-gnu/arch/sh/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -89,6 +89,7 @@
 	struct task_struct *idle;
 #endif
 
+	unsigned int phys_bits;
 	unsigned long flags;
 } __attribute__ ((aligned(L1_CACHE_BYTES)));
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace_32.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,83 @@
+#ifndef __ASM_SH_PTRACE_32_H
+#define __ASM_SH_PTRACE_32_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ *	 0 - 15 are integer registers
+ *	17 - 22 are control/special registers
+ *	24 - 39 fp registers
+ *	40 - 47 xd registers
+ *	48 -    fpscr register
+ * -----------------------------
+ *
+ * We follows above, except:
+ *	16 --- program counter (PC)
+ *	22 --- syscall #
+ *	23 --- floating point communication register
+ */
+#define REG_REG0	 0
+#define REG_REG15	15
+
+#define REG_PC		16
+
+#define REG_PR		17
+#define REG_SR		18
+#define REG_GBR		19
+#define REG_MACH	20
+#define REG_MACL	21
+
+#define REG_SYSCALL	22
+
+#define REG_FPREG0	23
+#define REG_FPREG15	38
+#define REG_XFREG0	39
+#define REG_XFREG15	54
+
+#define REG_FPSCR	55
+#define REG_FPUL	56
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+	unsigned long regs[16];
+	unsigned long pc;
+	unsigned long pr;
+	unsigned long sr;
+	unsigned long gbr;
+	unsigned long mach;
+	unsigned long macl;
+	long tra;
+};
+
+/*
+ * This struct defines the way the DSP registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_dspregs {
+	unsigned long	a1;
+	unsigned long	a0g;
+	unsigned long	a1g;
+	unsigned long	m0;
+	unsigned long	m1;
+	unsigned long	a0;
+	unsigned long	x0;
+	unsigned long	x1;
+	unsigned long	y0;
+	unsigned long	y1;
+	unsigned long	dsr;
+	unsigned long	rs;
+	unsigned long	re;
+	unsigned long	mod;
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET		offsetof(struct pt_regs, tra)
+#define regs_return_value(regs)	((regs)->regs[0])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_32_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace_64.h linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace_64.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace_64.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,20 @@
+#ifndef __ASM_SH_PTRACE_64_H
+#define __ASM_SH_PTRACE_64_H
+
+struct pt_regs {
+	unsigned long long pc;
+	unsigned long long sr;
+	long long syscall_nr;
+	unsigned long long regs[63];
+	unsigned long long tregs[8];
+	unsigned long long pad[2];
+};
+
+#ifdef __KERNEL__
+
+#define MAX_REG_OFFSET		offsetof(struct pt_regs, tregs[7])
+#define regs_return_value(regs)	((regs)->regs[3])
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_SH_PTRACE_64_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,90 +3,7 @@
 
 /*
  * Copyright (C) 1999, 2000  Niibe Yutaka
- *
  */
-#if defined(__SH5__)
-struct pt_regs {
-	unsigned long long pc;
-	unsigned long long sr;
-	long long syscall_nr;
-	unsigned long long regs[63];
-	unsigned long long tregs[8];
-	unsigned long long pad[2];
-};
-#else
-/*
- * GCC defines register number like this:
- * -----------------------------
- *	 0 - 15 are integer registers
- *	17 - 22 are control/special registers
- *	24 - 39 fp registers
- *	40 - 47 xd registers
- *	48 -    fpscr register
- * -----------------------------
- *
- * We follows above, except:
- *	16 --- program counter (PC)
- *	22 --- syscall #
- *	23 --- floating point communication register
- */
-#define REG_REG0	 0
-#define REG_REG15	15
-
-#define REG_PC		16
-
-#define REG_PR		17
-#define REG_SR		18
-#define REG_GBR		19
-#define REG_MACH	20
-#define REG_MACL	21
-
-#define REG_SYSCALL	22
-
-#define REG_FPREG0	23
-#define REG_FPREG15	38
-#define REG_XFREG0	39
-#define REG_XFREG15	54
-
-#define REG_FPSCR	55
-#define REG_FPUL	56
-
-/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_regs {
-	unsigned long regs[16];
-	unsigned long pc;
-	unsigned long pr;
-	unsigned long sr;
-	unsigned long gbr;
-	unsigned long mach;
-	unsigned long macl;
-	long tra;
-};
-
-/*
- * This struct defines the way the DSP registers are stored on the
- * kernel stack during a system call or other kernel entry.
- */
-struct pt_dspregs {
-	unsigned long	a1;
-	unsigned long	a0g;
-	unsigned long	a1g;
-	unsigned long	m0;
-	unsigned long	m1;
-	unsigned long	a0;
-	unsigned long	x0;
-	unsigned long	x1;
-	unsigned long	y0;
-	unsigned long	y1;
-	unsigned long	dsr;
-	unsigned long	rs;
-	unsigned long	re;
-	unsigned long	mod;
-};
-#endif
 
 #define PTRACE_GETREGS		12	/* General registers */
 #define PTRACE_SETREGS		13
@@ -107,22 +24,102 @@
 #define PT_DATA_ADDR		248	/* &(struct user)->start_data */
 #define PT_TEXT_LEN		252
 
+#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
+#include "ptrace_64.h"
+#else
+#include "ptrace_32.h"
+#endif
+
 #ifdef __KERNEL__
+
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
 #include <asm/addrspace.h>
 #include <asm/page.h>
 #include <asm/system.h>
 
 #define user_mode(regs)			(((regs)->sr & 0x40000000)==0)
+#define user_stack_pointer(regs)	((unsigned long)(regs)->regs[15])
+#define kernel_stack_pointer(regs)	((unsigned long)(regs)->regs[15])
 #define instruction_pointer(regs)	((unsigned long)(regs)->pc)
 
 extern void show_regs(struct pt_regs *);
 
+#define arch_has_single_step()	(1)
+
 /*
- * These are defined as per linux/ptrace.h.
+ * kprobe-based event tracer support
  */
-struct task_struct;
+struct pt_regs_offset {
+	const char *name;
+	int offset;
+};
 
-#define arch_has_single_step()	(1)
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REGS_OFFSET_NAME(num)	\
+	{.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])}
+#define TREGS_OFFSET_NAME(num)	\
+	{.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+
+extern const struct pt_regs_offset regoffset_table[];
+
+/**
+ * regs_get_register() - get register value from its offset
+ * @regs:	pt_regs from which register value is gotten.
+ * @offset:	offset number of the register.
+ *
+ * regs_get_register returns the value of a register. The @offset is the
+ * offset of the register in struct pt_regs address which specified by @regs.
+ * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
+ */
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+					      unsigned int offset)
+{
+	if (unlikely(offset > MAX_REG_OFFSET))
+		return 0;
+	return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs:	pt_regs which contains kernel stack pointer.
+ * @addr:	address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+static inline int regs_within_kernel_stack(struct pt_regs *regs,
+					   unsigned long addr)
+{
+	return ((addr & ~(THREAD_SIZE - 1))  ==
+		(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs:	pt_regs which contains kernel stack pointer.
+ * @n:		stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
+						      unsigned int n)
+{
+	unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+	addr += n;
+	if (regs_within_kernel_stack(regs, (unsigned long)addr))
+		return *addr;
+	else
+		return 0;
+}
 
 struct perf_event;
 struct perf_sample_data;
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/sizes.h linux-libre-2.6.37-gnu/arch/sh/include/asm/sizes.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/sizes.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/sizes.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #define SZ_512				0x00000200
 
 #define SZ_1K                           0x00000400
+#define SZ_2K                           0x00000800
 #define SZ_4K                           0x00001000
 #define SZ_8K                           0x00002000
 #define SZ_16K                          0x00004000
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/sram.h linux-libre-2.6.37-gnu/arch/sh/include/asm/sram.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/sram.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/sram.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+#ifndef __ASM_SRAM_H
+#define __ASM_SRAM_H
+
+#ifdef CONFIG_HAVE_SRAM_POOL
+
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+/* arch/sh/mm/sram.c */
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+	if (!sram_pool)
+		return 0UL;
+
+	return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+	return gen_pool_free(sram_pool, addr, len);
+}
+
+#else
+
+static inline unsigned long sram_alloc(size_t len)
+{
+	return 0;
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+}
+
+#endif /* CONFIG_HAVE_SRAM_POOL */
+
+#endif /* __ASM_SRAM_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/syscalls_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/syscalls_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/syscalls_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/syscalls_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,9 +19,10 @@
 asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
 			 unsigned long r6, unsigned long r7,
 			 struct pt_regs __regs);
-asmlinkage int sys_execve(const char __user *ufilename, char __user * __user *uargv,
-			  char __user * __user *uenvp, unsigned long r7,
-			  struct pt_regs __regs);
+asmlinkage int sys_execve(const char __user *ufilename,
+			  const char __user *const __user *uargv,
+			  const char __user *const __user *uenvp,
+			  unsigned long r7, struct pt_regs __regs);
 asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5,
 			      unsigned long r6, unsigned long r7,
 			      struct pt_regs __regs);
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/system_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/system_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/system_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/system_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -145,42 +145,6 @@
 		__restore_dsp(prev);				\
 } while (0)
 
-/*
- * Jump to uncached area.
- * When handling TLB or caches, we need to do it from an uncached area.
- */
-#define jump_to_uncached()			\
-do {						\
-	unsigned long __dummy;			\
-						\
-	__asm__ __volatile__(			\
-		"mova	1f, %0\n\t"		\
-		"add	%1, %0\n\t"		\
-		"jmp	@%0\n\t"		\
-		" nop\n\t"			\
-		".balign 4\n"			\
-		"1:"				\
-		: "=&z" (__dummy)		\
-		: "r" (cached_to_uncached));	\
-} while (0)
-
-/*
- * Back to cached area.
- */
-#define back_to_cached()				\
-do {							\
-	unsigned long __dummy;				\
-	ctrl_barrier();					\
-	__asm__ __volatile__(				\
-		"mov.l	1f, %0\n\t"			\
-		"jmp	@%0\n\t"			\
-		" nop\n\t"				\
-		".balign 4\n"				\
-		"1:	.long 2f\n"			\
-		"2:"					\
-		: "=&r" (__dummy));			\
-} while (0)
-
 #ifdef CONFIG_CPU_HAS_SR_RB
 #define lookup_exception_vector()	\
 ({					\
@@ -212,17 +176,16 @@
 }
 
 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
-			    struct mem_access *ma, int);
+			    struct mem_access *ma, int, unsigned long address);
 
 static inline void trigger_address_error(void)
 {
-	if (__in_29bit_mode())
-		__asm__ __volatile__ (
-			"ldc %0, sr\n\t"
-			"mov.l @%1, %0"
-			:
-			: "r" (0x10000000), "r" (0x80000001)
-		);
+	__asm__ __volatile__ (
+		"ldc %0, sr\n\t"
+		"mov.l @%1, %0"
+		:
+		: "r" (0x10000000), "r" (0x80000001)
+	);
 }
 
 asmlinkage void do_address_error(struct pt_regs *regs,
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/system_64.h linux-libre-2.6.37-gnu/arch/sh/include/asm/system_64.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/system_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/system_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,9 +34,6 @@
 			      &next->thread);			\
 } while (0)
 
-#define jump_to_uncached()	do { } while (0)
-#define back_to_cached()	do { } while (0)
-
 #define __icbi(addr)	__asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
 #define __ocbp(addr)	__asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
 #define __ocbi(addr)	__asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/system.h linux-libre-2.6.37-gnu/arch/sh/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <asm/types.h>
+#include <asm/uncached.h>
 
 #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
 
@@ -137,11 +138,6 @@
 #define instruction_size(insn)	(4)
 #endif
 
-extern unsigned long cached_to_uncached;
-extern unsigned long uncached_size;
-
-extern struct dentry *sh_debugfs_root;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/tlbflush.h linux-libre-2.6.37-gnu/arch/sh/include/asm/tlbflush.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/tlbflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/tlbflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,8 @@
 					 unsigned long end);
 extern void local_flush_tlb_one(unsigned long asid, unsigned long page);
 
+extern void __flush_tlb_global(void);
+
 #ifdef CONFIG_SMP
 
 extern void flush_tlb_all(void);
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/uncached.h linux-libre-2.6.37-gnu/arch/sh/include/asm/uncached.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/uncached.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/uncached.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,15 +4,55 @@
 #include <linux/bug.h>
 
 #ifdef CONFIG_UNCACHED_MAPPING
+extern unsigned long cached_to_uncached;
+extern unsigned long uncached_size;
 extern unsigned long uncached_start, uncached_end;
 
 extern int virt_addr_uncached(unsigned long kaddr);
 extern void uncached_init(void);
 extern void uncached_resize(unsigned long size);
+
+/*
+ * Jump to uncached area.
+ * When handling TLB or caches, we need to do it from an uncached area.
+ */
+#define jump_to_uncached()			\
+do {						\
+	unsigned long __dummy;			\
+						\
+	__asm__ __volatile__(			\
+		"mova	1f, %0\n\t"		\
+		"add	%1, %0\n\t"		\
+		"jmp	@%0\n\t"		\
+		" nop\n\t"			\
+		".balign 4\n"			\
+		"1:"				\
+		: "=&z" (__dummy)		\
+		: "r" (cached_to_uncached));	\
+} while (0)
+
+/*
+ * Back to cached area.
+ */
+#define back_to_cached()				\
+do {							\
+	unsigned long __dummy;				\
+	ctrl_barrier();					\
+	__asm__ __volatile__(				\
+		"mov.l	1f, %0\n\t"			\
+		"jmp	@%0\n\t"			\
+		" nop\n\t"				\
+		".balign 4\n"				\
+		"1:	.long 2f\n"			\
+		"2:"					\
+		: "=&r" (__dummy));			\
+} while (0)
 #else
 #define virt_addr_uncached(kaddr)	(0)
 #define uncached_init()			do { } while (0)
 #define uncached_resize(size)		BUG()
+#define jump_to_uncached()		do { } while (0)
+#define back_to_cached()		do { } while (0)
 #endif
 
 #endif /* __ASM_SH_UNCACHED_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/unistd_32.h linux-libre-2.6.37-gnu/arch/sh/include/asm/unistd_32.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/unistd_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/unistd_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -345,12 +345,34 @@
 #define __NR_pwritev		334
 #define __NR_rt_tgsigqueueinfo	335
 #define __NR_perf_event_open	336
+#define __NR_fanotify_init	337
+#define __NR_fanotify_mark	338
+#define __NR_prlimit64		339
 
-#define NR_syscalls 337
+/* Non-multiplexed socket family */
+#define __NR_socket		340
+#define __NR_bind		341
+#define __NR_connect		342
+#define __NR_listen		343
+#define __NR_accept		344
+#define __NR_getsockname	345
+#define __NR_getpeername	346
+#define __NR_socketpair		347
+#define __NR_send		348
+#define __NR_sendto		349
+#define __NR_recv		350
+#define __NR_recvfrom		351
+#define __NR_shutdown		352
+#define __NR_setsockopt		353
+#define __NR_getsockopt		354
+#define __NR_sendmsg		355
+#define __NR_recvmsg		356
+#define __NR_recvmmsg		357
+#define __NR_accept4		358
 
-#ifdef __KERNEL__
+#define NR_syscalls 359
 
-#define __IGNORE_recvmmsg
+#ifdef __KERNEL__
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/asm/unistd_64.h linux-libre-2.6.37-gnu/arch/sh/include/asm/unistd_64.h
--- linux-libre-2.6.36-gnu/arch/sh/include/asm/unistd_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/asm/unistd_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -387,10 +387,13 @@
 #define __NR_perf_event_open	364
 #define __NR_recvmmsg		365
 #define __NR_accept4		366
+#define __NR_fanotify_init	367
+#define __NR_fanotify_mark	368
+#define __NR_prlimit64		369
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 367
+#define NR_syscalls 370
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh3/cpu/mmu_context.h linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh3/cpu/mmu_context.h
--- linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh3/cpu/mmu_context.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh3/cpu/mmu_context.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #define MMU_TEA		0xFFFFFFFC	/* TLB Exception Address */
 
 #define MMUCR		0xFFFFFFE0	/* MMU Control Register */
+#define MMUCR_TI	(1 << 2)	/* TLB flush bit */
 
 #define MMU_TLB_ADDRESS_ARRAY	0xF2000000
 #define MMU_PAGE_ASSOC_BIT	0x80
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/freq.h linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/freq.h
--- linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/freq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/freq.h	2011-01-04 19:50:19.000000000 -0500
@@ -56,7 +56,9 @@
 #define FRQCR1			0xffc40004
 #define FRQMR1			0xffc40014
 #elif defined(CONFIG_CPU_SUBTYPE_SHX3)
-#define FRQCR			0xffc00014
+#define FRQCR0			0xffc00000
+#define FRQCR1			0xffc00004
+#define FRQMR1			0xffc00014
 #else
 #define FRQCR			0xffc00000
 #define FRQCR_PSTBY		0x0200
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/sh7724.h linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/sh7724.h
--- linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/sh7724.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/sh7724.h	2011-01-04 19:50:19.000000000 -0500
@@ -303,4 +303,7 @@
 	SHDMA_SLAVE_SDHI1_RX,
 };
 
+extern struct clk sh7724_fsimcka_clk;
+extern struct clk sh7724_fsimckb_clk;
+
 #endif /* __ASM_SH7724_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/sh7757.h linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/sh7757.h
--- linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/sh7757.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/sh7757.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,241 +3,252 @@
 
 enum {
 	/* PTA */
-	GPIO_PTA7, GPIO_PTA6, GPIO_PTA5, GPIO_PTA4,
-	GPIO_PTA3, GPIO_PTA2, GPIO_PTA1, GPIO_PTA0,
+	GPIO_PTA0, GPIO_PTA1, GPIO_PTA2, GPIO_PTA3,
+	GPIO_PTA4, GPIO_PTA5, GPIO_PTA6, GPIO_PTA7,
 
 	/* PTB */
-	GPIO_PTB7, GPIO_PTB6, GPIO_PTB5, GPIO_PTB4,
-	GPIO_PTB3, GPIO_PTB2, GPIO_PTB1, GPIO_PTB0,
+	GPIO_PTB0, GPIO_PTB1, GPIO_PTB2, GPIO_PTB3,
+	GPIO_PTB4, GPIO_PTB5, GPIO_PTB6, GPIO_PTB7,
 
 	/* PTC */
-	GPIO_PTC7, GPIO_PTC6, GPIO_PTC5, GPIO_PTC4,
-	GPIO_PTC3, GPIO_PTC2, GPIO_PTC1, GPIO_PTC0,
+	GPIO_PTC0, GPIO_PTC1, GPIO_PTC2, GPIO_PTC3,
+	GPIO_PTC4, GPIO_PTC5, GPIO_PTC6, GPIO_PTC7,
 
 	/* PTD */
-	GPIO_PTD7, GPIO_PTD6, GPIO_PTD5, GPIO_PTD4,
-	GPIO_PTD3, GPIO_PTD2, GPIO_PTD1, GPIO_PTD0,
+	GPIO_PTD0, GPIO_PTD1, GPIO_PTD2, GPIO_PTD3,
+	GPIO_PTD4, GPIO_PTD5, GPIO_PTD6, GPIO_PTD7,
 
 	/* PTE */
-	GPIO_PTE7, GPIO_PTE6, GPIO_PTE5, GPIO_PTE4,
-	GPIO_PTE3, GPIO_PTE2, GPIO_PTE1, GPIO_PTE0,
+	GPIO_PTE0, GPIO_PTE1, GPIO_PTE2, GPIO_PTE3,
+	GPIO_PTE4, GPIO_PTE5, GPIO_PTE6, GPIO_PTE7,
 
 	/* PTF */
-	GPIO_PTF7, GPIO_PTF6, GPIO_PTF5, GPIO_PTF4,
-	GPIO_PTF3, GPIO_PTF2, GPIO_PTF1, GPIO_PTF0,
+	GPIO_PTF0, GPIO_PTF1, GPIO_PTF2, GPIO_PTF3,
+	GPIO_PTF4, GPIO_PTF5, GPIO_PTF6, GPIO_PTF7,
 
 	/* PTG */
-	GPIO_PTG7, GPIO_PTG6, GPIO_PTG5, GPIO_PTG4,
-	GPIO_PTG3, GPIO_PTG2, GPIO_PTG1, GPIO_PTG0,
+	GPIO_PTG0, GPIO_PTG1, GPIO_PTG2, GPIO_PTG3,
+	GPIO_PTG4, GPIO_PTG5, GPIO_PTG6, GPIO_PTG7,
 
 	/* PTH */
-	GPIO_PTH7, GPIO_PTH6, GPIO_PTH5, GPIO_PTH4,
-	GPIO_PTH3, GPIO_PTH2, GPIO_PTH1, GPIO_PTH0,
+	GPIO_PTH0, GPIO_PTH1, GPIO_PTH2, GPIO_PTH3,
+	GPIO_PTH4, GPIO_PTH5, GPIO_PTH6, GPIO_PTH7,
 
 	/* PTI */
-	GPIO_PTI7, GPIO_PTI6, GPIO_PTI5, GPIO_PTI4,
-	GPIO_PTI3, GPIO_PTI2, GPIO_PTI1, GPIO_PTI0,
+	GPIO_PTI0, GPIO_PTI1, GPIO_PTI2, GPIO_PTI3,
+	GPIO_PTI4, GPIO_PTI5, GPIO_PTI6, GPIO_PTI7,
 
 	/* PTJ */
-	GPIO_PTJ7, GPIO_PTJ6, GPIO_PTJ5, GPIO_PTJ4,
-	GPIO_PTJ3, GPIO_PTJ2, GPIO_PTJ1, GPIO_PTJ0,
+	GPIO_PTJ0, GPIO_PTJ1, GPIO_PTJ2, GPIO_PTJ3,
+	GPIO_PTJ4, GPIO_PTJ5, GPIO_PTJ6, GPIO_PTJ7_RESV,
 
 	/* PTK */
-	GPIO_PTK7, GPIO_PTK6, GPIO_PTK5, GPIO_PTK4,
-	GPIO_PTK3, GPIO_PTK2, GPIO_PTK1, GPIO_PTK0,
+	GPIO_PTK0, GPIO_PTK1, GPIO_PTK2, GPIO_PTK3,
+	GPIO_PTK4, GPIO_PTK5, GPIO_PTK6, GPIO_PTK7,
 
 	/* PTL */
-	GPIO_PTL7, GPIO_PTL6, GPIO_PTL5, GPIO_PTL4,
-	GPIO_PTL3, GPIO_PTL2, GPIO_PTL1, GPIO_PTL0,
+	GPIO_PTL0, GPIO_PTL1, GPIO_PTL2, GPIO_PTL3,
+	GPIO_PTL4, GPIO_PTL5, GPIO_PTL6, GPIO_PTL7_RESV,
 
 	/* PTM */
-		   GPIO_PTM6, GPIO_PTM5, GPIO_PTM4,
-	GPIO_PTM3, GPIO_PTM2, GPIO_PTM1, GPIO_PTM0,
+	GPIO_PTM0, GPIO_PTM1, GPIO_PTM2, GPIO_PTM3,
+	GPIO_PTM4, GPIO_PTM5, GPIO_PTM6, GPIO_PTM7,
 
 	/* PTN */
-	GPIO_PTN7, GPIO_PTN6, GPIO_PTN5, GPIO_PTN4,
-	GPIO_PTN3, GPIO_PTN2, GPIO_PTN1, GPIO_PTN0,
+	GPIO_PTN0, GPIO_PTN1, GPIO_PTN2, GPIO_PTN3,
+	GPIO_PTN4, GPIO_PTN5, GPIO_PTN6, GPIO_PTN7_RESV,
 
 	/* PTO */
-	GPIO_PTO7, GPIO_PTO6, GPIO_PTO5, GPIO_PTO4,
-	GPIO_PTO3, GPIO_PTO2, GPIO_PTO1, GPIO_PTO0,
+	GPIO_PTO0, GPIO_PTO1, GPIO_PTO2, GPIO_PTO3,
+	GPIO_PTO4, GPIO_PTO5, GPIO_PTO6, GPIO_PTO7,
 
 	/* PTP */
-		   GPIO_PTP6, GPIO_PTP5, GPIO_PTP4,
-	GPIO_PTP3, GPIO_PTP2, GPIO_PTP1, GPIO_PTP0,
+	GPIO_PTP0, GPIO_PTP1, GPIO_PTP2, GPIO_PTP3,
+	GPIO_PTP4, GPIO_PTP5, GPIO_PTP6, GPIO_PTP7,
 
 	/* PTQ */
-		   GPIO_PTQ6, GPIO_PTQ5, GPIO_PTQ4,
-	GPIO_PTQ3, GPIO_PTQ2, GPIO_PTQ1, GPIO_PTQ0,
+	GPIO_PTQ0, GPIO_PTQ1, GPIO_PTQ2, GPIO_PTQ3,
+	GPIO_PTQ4, GPIO_PTQ5, GPIO_PTQ6, GPIO_PTQ7_RESV,
 
 	/* PTR */
-	GPIO_PTR7, GPIO_PTR6, GPIO_PTR5, GPIO_PTR4,
-	GPIO_PTR3, GPIO_PTR2, GPIO_PTR1, GPIO_PTR0,
+	GPIO_PTR0, GPIO_PTR1, GPIO_PTR2, GPIO_PTR3,
+	GPIO_PTR4, GPIO_PTR5, GPIO_PTR6, GPIO_PTR7,
 
 	/* PTS */
-	GPIO_PTS7, GPIO_PTS6, GPIO_PTS5, GPIO_PTS4,
-	GPIO_PTS3, GPIO_PTS2, GPIO_PTS1, GPIO_PTS0,
+	GPIO_PTS0, GPIO_PTS1, GPIO_PTS2, GPIO_PTS3,
+	GPIO_PTS4, GPIO_PTS5, GPIO_PTS6, GPIO_PTS7,
 
 	/* PTT */
-			      GPIO_PTT5, GPIO_PTT4,
-	GPIO_PTT3, GPIO_PTT2, GPIO_PTT1, GPIO_PTT0,
+	GPIO_PTT0, GPIO_PTT1, GPIO_PTT2, GPIO_PTT3,
+	GPIO_PTT4, GPIO_PTT5, GPIO_PTT6, GPIO_PTT7,
 
 	/* PTU */
-	GPIO_PTU7, GPIO_PTU6, GPIO_PTU5, GPIO_PTU4,
-	GPIO_PTU3, GPIO_PTU2, GPIO_PTU1, GPIO_PTU0,
+	GPIO_PTU0, GPIO_PTU1, GPIO_PTU2, GPIO_PTU3,
+	GPIO_PTU4, GPIO_PTU5, GPIO_PTU6, GPIO_PTU7,
 
 	/* PTV */
-	GPIO_PTV7, GPIO_PTV6, GPIO_PTV5, GPIO_PTV4,
-	GPIO_PTV3, GPIO_PTV2, GPIO_PTV1, GPIO_PTV0,
+	GPIO_PTV0, GPIO_PTV1, GPIO_PTV2, GPIO_PTV3,
+	GPIO_PTV4, GPIO_PTV5, GPIO_PTV6, GPIO_PTV7,
 
 	/* PTW */
-	GPIO_PTW7, GPIO_PTW6, GPIO_PTW5, GPIO_PTW4,
-	GPIO_PTW3, GPIO_PTW2, GPIO_PTW1, GPIO_PTW0,
+	GPIO_PTW0, GPIO_PTW1, GPIO_PTW2, GPIO_PTW3,
+	GPIO_PTW4, GPIO_PTW5, GPIO_PTW6, GPIO_PTW7,
 
 	/* PTX */
-	GPIO_PTX7, GPIO_PTX6, GPIO_PTX5, GPIO_PTX4,
-	GPIO_PTX3, GPIO_PTX2, GPIO_PTX1, GPIO_PTX0,
+	GPIO_PTX0, GPIO_PTX1, GPIO_PTX2, GPIO_PTX3,
+	GPIO_PTX4, GPIO_PTX5, GPIO_PTX6, GPIO_PTX7,
 
 	/* PTY */
-	GPIO_PTY7, GPIO_PTY6, GPIO_PTY5, GPIO_PTY4,
-	GPIO_PTY3, GPIO_PTY2, GPIO_PTY1, GPIO_PTY0,
+	GPIO_PTY0, GPIO_PTY1, GPIO_PTY2, GPIO_PTY3,
+	GPIO_PTY4, GPIO_PTY5, GPIO_PTY6, GPIO_PTY7,
 
 	/* PTZ */
-	GPIO_PTZ7, GPIO_PTZ6, GPIO_PTZ5, GPIO_PTZ4,
-	GPIO_PTZ3, GPIO_PTZ2, GPIO_PTZ1, GPIO_PTZ0,
+	GPIO_PTZ0, GPIO_PTZ1, GPIO_PTZ2, GPIO_PTZ3,
+	GPIO_PTZ4, GPIO_PTZ5, GPIO_PTZ6, GPIO_PTZ7,
 
 
-	/* PTA (mobule: LBSC, CPG, LPC) */
+	/* PTA (mobule: LBSC, RGMII) */
 	GPIO_FN_BS,	GPIO_FN_RDWR,	GPIO_FN_WE1,	GPIO_FN_RDY,
-	GPIO_FN_MD10,	GPIO_FN_MD9,	GPIO_FN_MD8,
-	GPIO_FN_LGPIO7,	GPIO_FN_LGPIO6,	GPIO_FN_LGPIO5,	GPIO_FN_LGPIO4,
-	GPIO_FN_LGPIO3,	GPIO_FN_LGPIO2,	GPIO_FN_LGPIO1,	GPIO_FN_LGPIO0,
-
-	/* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-	GPIO_FN_D15,	GPIO_FN_D14,	GPIO_FN_D13,	GPIO_FN_D12,
-	GPIO_FN_D11,	GPIO_FN_D10,	GPIO_FN_D9,	GPIO_FN_D8,
-	GPIO_FN_ET0_MDC,		GPIO_FN_ET0_MDIO,
-	GPIO_FN_ET1_MDC,		GPIO_FN_ET1_MDIO,
-	GPIO_FN_SIM_D,	GPIO_FN_SIM_CLK,		GPIO_FN_SIM_RST,
-	GPIO_FN_WPSZ1,	GPIO_FN_WPSZ0,	GPIO_FN_FWID,	GPIO_FN_FLSHSZ,
-	GPIO_FN_LPC_SPIEN,		GPIO_FN_BASEL,
+	GPIO_FN_ET0_MDC,	GPIO_FN_ET0_MDIO,
+	GPIO_FN_ET1_MDC,	GPIO_FN_ET1_MDIO,
 
-	/* PTC (mobule: SD) */
-	GPIO_FN_SD_WP,	GPIO_FN_SD_CD,	GPIO_FN_SD_CLK,	GPIO_FN_SD_CMD,
-	GPIO_FN_SD_D3,	GPIO_FN_SD_D2,	GPIO_FN_SD_D1,	GPIO_FN_SD_D0,
+	/* PTB (mobule: INTC, ONFI, TMU) */
+	GPIO_FN_IRQ15,	GPIO_FN_IRQ14,	GPIO_FN_IRQ13,	GPIO_FN_IRQ12,
+	GPIO_FN_IRQ11,	GPIO_FN_IRQ10,	GPIO_FN_IRQ9,	GPIO_FN_IRQ8,
+	GPIO_FN_ON_NRE,	GPIO_FN_ON_NWE,	GPIO_FN_ON_NWP,	GPIO_FN_ON_NCE0,
+	GPIO_FN_ON_R_B0,	GPIO_FN_ON_ALE,	GPIO_FN_ON_CLE,
+	GPIO_FN_TCLK,
 
-	/* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+	/* PTC (mobule: IRQ, PWMU) */
 	GPIO_FN_IRQ7,	GPIO_FN_IRQ6,	GPIO_FN_IRQ5,	GPIO_FN_IRQ4,
 	GPIO_FN_IRQ3,	GPIO_FN_IRQ2,	GPIO_FN_IRQ1,	GPIO_FN_IRQ0,
-	GPIO_FN_MD6,	GPIO_FN_MD5,	GPIO_FN_MD3,	GPIO_FN_MD2,
-	GPIO_FN_MD1,	GPIO_FN_MD0,	GPIO_FN_ADTRG1,	GPIO_FN_ADTRG0,
+	GPIO_FN_PWMU0,	GPIO_FN_PWMU1,	GPIO_FN_PWMU2,	GPIO_FN_PWMU3,
+	GPIO_FN_PWMU4,	GPIO_FN_PWMU5,
 
-	/* PTE (mobule: EtherC) */
-	GPIO_FN_ET0_CRS_DV,		GPIO_FN_ET0_TXD1,
-	GPIO_FN_ET0_TXD0,		GPIO_FN_ET0_TX_EN,
-	GPIO_FN_ET0_REF_CLK,		GPIO_FN_ET0_RXD1,
-	GPIO_FN_ET0_RXD0,		GPIO_FN_ET0_RX_ER,
+	/* PTD (mobule: SPI0, DMAC) */
+	GPIO_FN_SP0_MOSI,	GPIO_FN_SP0_MISO,	GPIO_FN_SP0_SCK,
+	GPIO_FN_SP0_SCK_FB,	GPIO_FN_SP0_SS0,	GPIO_FN_SP0_SS1,
+	GPIO_FN_SP0_SS2,	GPIO_FN_SP0_SS3,	GPIO_FN_DREQ0,
+	GPIO_FN_DACK0,		GPIO_FN_TEND0,
 
-	/* PTF (mobule: EtherC) */
-	GPIO_FN_ET1_CRS_DV,		GPIO_FN_ET1_TXD1,
-	GPIO_FN_ET1_TXD0,		GPIO_FN_ET1_TX_EN,
-	GPIO_FN_ET1_REF_CLK,		GPIO_FN_ET1_RXD1,
-	GPIO_FN_ET1_RXD0,		GPIO_FN_ET1_RX_ER,
+	/* PTE (mobule: RMII) */
+	GPIO_FN_RMII0_CRS_DV,	GPIO_FN_RMII0_TXD1,	GPIO_FN_RMII0_TXD0,
+	GPIO_FN_RMII0_TXEN,	GPIO_FN_RMII0_REFCLK,	GPIO_FN_RMII0_RXD1,
+	GPIO_FN_RMII0_RXD0,	GPIO_FN_RMII0_RX_ER,
 
-	/* PTG (mobule: SYSTEM, PWMX, LPC) */
-	GPIO_FN_STATUS0,		GPIO_FN_STATUS1,
-	GPIO_FN_PWX0,	GPIO_FN_PWX1,	GPIO_FN_PWX2,	GPIO_FN_PWX3,
-	GPIO_FN_SERIRQ,	GPIO_FN_CLKRUN,	GPIO_FN_LPCPD,	GPIO_FN_LDRQ,
+	/* PTF (mobule: RMII, SerMux) */
+	GPIO_FN_RMII1_CRS_DV,	GPIO_FN_RMII1_TXD1,	GPIO_FN_RMII1_TXD0,
+	GPIO_FN_RMII1_TXEN,	GPIO_FN_RMII1_REFCLK,	GPIO_FN_RMII1_RXD1,
+	GPIO_FN_RMII1_RXD0,	GPIO_FN_RMII1_RX_ER,	GPIO_FN_RAC_RI,
 
-	/* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-	GPIO_FN_TCLK,	GPIO_FN_RXD4,	GPIO_FN_TXD4,
+	/* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+	GPIO_FN_BOOTFMS,		GPIO_FN_BOOTWP,
+	GPIO_FN_A25,	GPIO_FN_A24,	GPIO_FN_SERIRQ,	GPIO_FN_WDTOVF,
+	GPIO_FN_LPCPD,	GPIO_FN_LDRQ,	GPIO_FN_MMCCLK,	GPIO_FN_MMCCMD,
+
+	/* PTH (mobule: SPI1, LPC, DMAC, ADC) */
 	GPIO_FN_SP1_MOSI,		GPIO_FN_SP1_MISO,
 	GPIO_FN_SP1_SCK,		GPIO_FN_SP1_SCK_FB,
 	GPIO_FN_SP1_SS0,		GPIO_FN_SP1_SS1,
-	GPIO_FN_SP0_SS1,
+	GPIO_FN_WP,	GPIO_FN_FMS0,	GPIO_FN_TEND1,	GPIO_FN_DREQ1,
+	GPIO_FN_DACK1,	GPIO_FN_ADTRG1,	GPIO_FN_ADTRG0,
 
-	/* PTI (mobule: INTC) */
-	GPIO_FN_IRQ15,	GPIO_FN_IRQ14,	GPIO_FN_IRQ13,	GPIO_FN_IRQ12,
-	GPIO_FN_IRQ11,	GPIO_FN_IRQ10,	GPIO_FN_IRQ9,	GPIO_FN_IRQ8,
+	/* PTI (mobule: LBSC, SDHI) */
+	GPIO_FN_D15,	GPIO_FN_D14,	GPIO_FN_D13,	GPIO_FN_D12,
+	GPIO_FN_D11,	GPIO_FN_D10,	GPIO_FN_D9,	GPIO_FN_D8,
+	GPIO_FN_SD_WP,	GPIO_FN_SD_CD,	GPIO_FN_SD_CLK,	GPIO_FN_SD_CMD,
+	GPIO_FN_SD_D3,	GPIO_FN_SD_D2,	GPIO_FN_SD_D1,	GPIO_FN_SD_D0,
 
-	/* PTJ (mobule: SCIF234, SERMUX) */
-	GPIO_FN_RXD3,	GPIO_FN_TXD3,	GPIO_FN_RXD2,	GPIO_FN_TXD2,
-	GPIO_FN_COM1_TXD,		GPIO_FN_COM1_RXD,
-	GPIO_FN_COM1_RTS,		GPIO_FN_COM1_CTS,
+	/* PTJ (mobule: SCIF234) */
+	GPIO_FN_RTS3,	GPIO_FN_CTS3,	GPIO_FN_TXD3,	GPIO_FN_RXD3,
+	GPIO_FN_RTS4,	GPIO_FN_RXD4,	GPIO_FN_TXD4,
 
-	/* PTK (mobule: SERMUX) */
-	GPIO_FN_COM2_TXD,		GPIO_FN_COM2_RXD,
-	GPIO_FN_COM2_RTS,		GPIO_FN_COM2_CTS,
-	GPIO_FN_COM2_DTR,		GPIO_FN_COM2_DSR,
-	GPIO_FN_COM2_DCD,		GPIO_FN_COM2_RI,
+	/* PTK (mobule: SERMUX, LBSC, SCIF) */
+	GPIO_FN_COM2_TXD,	GPIO_FN_COM2_RXD,	GPIO_FN_COM2_RTS,
+	GPIO_FN_COM2_CTS,	GPIO_FN_COM2_DTR,	GPIO_FN_COM2_DSR,
+	GPIO_FN_COM2_DCD,	GPIO_FN_CLKOUT,
+	GPIO_FN_SCK2,		GPIO_FN_SCK4,	GPIO_FN_SCK3,
 
-	/* PTL (mobule: SERMUX) */
-	GPIO_FN_RAC_TXD,		GPIO_FN_RAC_RXD,
-	GPIO_FN_RAC_RTS,		GPIO_FN_RAC_CTS,
-	GPIO_FN_RAC_DTR,		GPIO_FN_RAC_DSR,
-	GPIO_FN_RAC_DCD,		GPIO_FN_RAC_RI,
+	/* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+	GPIO_FN_RAC_RXD,	GPIO_FN_RAC_RTS,	GPIO_FN_RAC_CTS,
+	GPIO_FN_RAC_DTR,	GPIO_FN_RAC_DSR,	GPIO_FN_RAC_DCD,
+	GPIO_FN_RAC_TXD,	GPIO_FN_RXD2,		GPIO_FN_CS5,
+	GPIO_FN_CS6,		GPIO_FN_AUDSYNC,	GPIO_FN_AUDCK,
+	GPIO_FN_TXD2,
 
-	/* PTM (mobule: IIC, LPC) */
+	/* PTM (mobule: LBSC, IIC) */
+	GPIO_FN_CS4,	GPIO_FN_RD,	GPIO_FN_WE0,	GPIO_FN_CS0,
 	GPIO_FN_SDA6,	GPIO_FN_SCL6,	GPIO_FN_SDA7,	GPIO_FN_SCL7,
-	GPIO_FN_WP,	GPIO_FN_FMS0,	GPIO_FN_FMS1,
 
-	/* PTN (mobule: SCIF234, EVC) */
-	GPIO_FN_SCK2,	GPIO_FN_RTS4,	GPIO_FN_RTS3,	GPIO_FN_RTS2,
-	GPIO_FN_CTS4,	GPIO_FN_CTS3,	GPIO_FN_CTS2,
-	GPIO_FN_EVENT7,	GPIO_FN_EVENT6,	GPIO_FN_EVENT5,	GPIO_FN_EVENT4,
-	GPIO_FN_EVENT3,	GPIO_FN_EVENT2,	GPIO_FN_EVENT1,	GPIO_FN_EVENT0,
-
-	/* PTO (mobule: SGPIO) */
-	GPIO_FN_SGPIO0_CLK,		GPIO_FN_SGPIO0_LOAD,
-	GPIO_FN_SGPIO0_DI,		GPIO_FN_SGPIO0_DO,
-	GPIO_FN_SGPIO1_CLK,		GPIO_FN_SGPIO1_LOAD,
-	GPIO_FN_SGPIO1_DI,		GPIO_FN_SGPIO1_DO,
+	/* PTN (mobule: USB, JMC, SGPIO, WDT) */
+	GPIO_FN_VBUS_EN,	GPIO_FN_VBUS_OC,	GPIO_FN_JMCTCK,
+	GPIO_FN_JMCTMS,		GPIO_FN_JMCTDO,		GPIO_FN_JMCTDI,
+	GPIO_FN_JMCTRST,
+	GPIO_FN_SGPIO1_CLK,	GPIO_FN_SGPIO1_LOAD,	GPIO_FN_SGPIO1_DI,
+	GPIO_FN_SGPIO1_DO,	GPIO_FN_SUB_CLKIN,
 
-	/* PTP (mobule: JMC, SCIF234) */
-	GPIO_FN_JMCTCK,	GPIO_FN_JMCTMS,	GPIO_FN_JMCTDO,	GPIO_FN_JMCTDI,
-	GPIO_FN_JMCRST,	GPIO_FN_SCK4,	GPIO_FN_SCK3,
+	/* PTO (mobule: SGPIO, SerMux) */
+	GPIO_FN_SGPIO0_CLK,	GPIO_FN_SGPIO0_LOAD,	GPIO_FN_SGPIO0_DI,
+	GPIO_FN_SGPIO0_DO,	GPIO_FN_SGPIO2_CLK,	GPIO_FN_SGPIO2_LOAD,
+	GPIO_FN_SGPIO2_DI,	GPIO_FN_SGPIO2_DO,	GPIO_FN_COM1_TXD,
+	GPIO_FN_COM1_RXD,	GPIO_FN_COM1_RTS,	GPIO_FN_COM1_CTS,
 
 	/* PTQ (mobule: LPC) */
 	GPIO_FN_LAD3,	GPIO_FN_LAD2,	GPIO_FN_LAD1,	GPIO_FN_LAD0,
 	GPIO_FN_LFRAME,	GPIO_FN_LRESET,	GPIO_FN_LCLK,
 
 	/* PTR (mobule: GRA, IIC) */
-	GPIO_FN_DDC3,	GPIO_FN_DDC2,
-	GPIO_FN_SDA8,	GPIO_FN_SCL8,	GPIO_FN_SDA2,	GPIO_FN_SCL2,
+	GPIO_FN_DDC3,	GPIO_FN_DDC2,	GPIO_FN_SDA2,	GPIO_FN_SCL2,
 	GPIO_FN_SDA1,	GPIO_FN_SCL1,	GPIO_FN_SDA0,	GPIO_FN_SCL0,
+	GPIO_FN_SDA8,	GPIO_FN_SCL8,
 
 	/* PTS (mobule: GRA, IIC) */
-	GPIO_FN_DDC1,	GPIO_FN_DDC0,
-	GPIO_FN_SDA9,	GPIO_FN_SCL9,	GPIO_FN_SDA5,	GPIO_FN_SCL5,
+	GPIO_FN_DDC1,	GPIO_FN_DDC0,	GPIO_FN_SDA5,	GPIO_FN_SCL5,
 	GPIO_FN_SDA4,	GPIO_FN_SCL4,	GPIO_FN_SDA3,	GPIO_FN_SCL3,
+	GPIO_FN_SDA9,	GPIO_FN_SCL9,
 
-	/* PTT (mobule: SYSTEM, PWMX) */
-	GPIO_FN_AUDSYNC,		GPIO_FN_AUDCK,
-	GPIO_FN_AUDATA3,		GPIO_FN_AUDATA2,
-	GPIO_FN_AUDATA1,		GPIO_FN_AUDATA0,
-	GPIO_FN_PWX7,	GPIO_FN_PWX6,	GPIO_FN_PWX5,	GPIO_FN_PWX4,
+	/* PTT (mobule: PWMX, AUD) */
+	GPIO_FN_PWMX7,	GPIO_FN_PWMX6,	GPIO_FN_PWMX5,	GPIO_FN_PWMX4,
+	GPIO_FN_PWMX3,	GPIO_FN_PWMX2,	GPIO_FN_PWMX1,	GPIO_FN_PWMX0,
+	GPIO_FN_AUDATA3,	GPIO_FN_AUDATA2,	GPIO_FN_AUDATA1,
+	GPIO_FN_AUDATA0,	GPIO_FN_STATUS1,	GPIO_FN_STATUS0,
 
-	/* PTU (mobule: LBSC, DMAC) */
-	GPIO_FN_CS6,	GPIO_FN_CS5,	GPIO_FN_CS4,	GPIO_FN_CS0,
-	GPIO_FN_RD,	GPIO_FN_WE0,	GPIO_FN_A25,	GPIO_FN_A24,
-	GPIO_FN_DREQ0,	GPIO_FN_DACK0,
+	/* PTU (mobule: LPC, APM) */
+	GPIO_FN_LGPIO7,	GPIO_FN_LGPIO6,	GPIO_FN_LGPIO5,	GPIO_FN_LGPIO4,
+	GPIO_FN_LGPIO3,	GPIO_FN_LGPIO2,	GPIO_FN_LGPIO1,	GPIO_FN_LGPIO0,
+	GPIO_FN_APMONCTL_O,	GPIO_FN_APMPWBTOUT_O,	GPIO_FN_APMSCI_O,
+	GPIO_FN_APMVDDON,	GPIO_FN_APMSLPBTN,	GPIO_FN_APMPWRBTN,
+	GPIO_FN_APMS5N,		GPIO_FN_APMS3N,
 
-	/* PTV (mobule: LBSC, DMAC) */
+	/* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
 	GPIO_FN_A23,	GPIO_FN_A22,	GPIO_FN_A21,	GPIO_FN_A20,
 	GPIO_FN_A19,	GPIO_FN_A18,	GPIO_FN_A17,	GPIO_FN_A16,
-	GPIO_FN_TEND0,	GPIO_FN_DREQ1,	GPIO_FN_DACK1,	GPIO_FN_TEND1,
+	GPIO_FN_COM2_RI,	GPIO_FN_R_SPI_MOSI,	GPIO_FN_R_SPI_MISO,
+	GPIO_FN_R_SPI_RSPCK,	GPIO_FN_R_SPI_SSL0,	GPIO_FN_R_SPI_SSL1,
+	GPIO_FN_EVENT7,		GPIO_FN_EVENT6,		GPIO_FN_VBIOS_DI,
+	GPIO_FN_VBIOS_DO,	GPIO_FN_VBIOS_CLK,	GPIO_FN_VBIOS_CS,
 
-	/* PTW (mobule: LBSC) */
+	/* PTW (mobule: LBSC, EVC, SCIF) */
 	GPIO_FN_A15,	GPIO_FN_A14,	GPIO_FN_A13,	GPIO_FN_A12,
 	GPIO_FN_A11,	GPIO_FN_A10,	GPIO_FN_A9,	GPIO_FN_A8,
+	GPIO_FN_EVENT5,	GPIO_FN_EVENT4,	GPIO_FN_EVENT3,	GPIO_FN_EVENT2,
+	GPIO_FN_EVENT1,	GPIO_FN_EVENT0,	GPIO_FN_CTS4,	GPIO_FN_CTS2,
 
-	/* PTX (mobule: LBSC) */
+	/* PTX (mobule: LBSC, SCIF, SIM) */
 	GPIO_FN_A7,	GPIO_FN_A6,	GPIO_FN_A5,	GPIO_FN_A4,
 	GPIO_FN_A3,	GPIO_FN_A2,	GPIO_FN_A1,	GPIO_FN_A0,
+	GPIO_FN_RTS2,	GPIO_FN_SIM_D,	GPIO_FN_SIM_CLK, GPIO_FN_SIM_RST,
 
 	/* PTY (mobule: LBSC) */
 	GPIO_FN_D7,	GPIO_FN_D6,	GPIO_FN_D5,	GPIO_FN_D4,
 	GPIO_FN_D3,	GPIO_FN_D2,	GPIO_FN_D1,	GPIO_FN_D0,
+
+	/* PTZ (mobule: eMMC, ONFI) */
+	GPIO_FN_MMCDAT7,	GPIO_FN_MMCDAT6,	GPIO_FN_MMCDAT5,
+	GPIO_FN_MMCDAT4,	GPIO_FN_MMCDAT3,	GPIO_FN_MMCDAT2,
+	GPIO_FN_MMCDAT1,	GPIO_FN_MMCDAT0,
+	GPIO_FN_ON_DQ7,	GPIO_FN_ON_DQ6,	GPIO_FN_ON_DQ5,	GPIO_FN_ON_DQ4,
+	GPIO_FN_ON_DQ3,	GPIO_FN_ON_DQ2,	GPIO_FN_ON_DQ1,	GPIO_FN_ON_DQ0,
 };
 
 #endif /* __ASM_SH7757_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/shx3.h linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/shx3.h
--- linux-libre-2.6.36-gnu/arch/sh/include/cpu-sh4/cpu/shx3.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/cpu-sh4/cpu/shx3.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,64 @@
+#ifndef __CPU_SHX3_H
+#define __CPU_SHX3_H
+
+enum {
+	/* PA */
+	GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
+	GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+	/* PB */
+	GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+	GPIO_PB3, GPIO_PB2, GPIO_PB1, GPIO_PB0,
+
+	/* PC */
+	GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+	GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+	/* PD */
+	GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+	GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+	/* PE */
+	GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+	GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+	/* PF */
+	GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+	GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+	/* PG */
+	GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+	GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+	/* PH */
+	GPIO_PH5, GPIO_PH4,
+	GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+	/* SCIF */
+	GPIO_FN_SCK3, GPIO_FN_TXD3, GPIO_FN_RXD3,
+	GPIO_FN_SCK2, GPIO_FN_TXD2, GPIO_FN_RXD2,
+	GPIO_FN_SCK1, GPIO_FN_TXD1, GPIO_FN_RXD1,
+	GPIO_FN_SCK0, GPIO_FN_TXD0, GPIO_FN_RXD0,
+
+	/* LBSC */
+	GPIO_FN_D31, GPIO_FN_D30, GPIO_FN_D29, GPIO_FN_D28,
+	GPIO_FN_D27, GPIO_FN_D26, GPIO_FN_D25, GPIO_FN_D24,
+	GPIO_FN_D23, GPIO_FN_D22, GPIO_FN_D21, GPIO_FN_D20,
+	GPIO_FN_D19, GPIO_FN_D18, GPIO_FN_D17, GPIO_FN_D16,
+	GPIO_FN_WE3, GPIO_FN_WE2, GPIO_FN_CS6, GPIO_FN_CS5,
+	GPIO_FN_CS4, GPIO_FN_CLKOUTENB, GPIO_FN_BREQ,
+	GPIO_FN_IOIS16, GPIO_FN_CE2B, GPIO_FN_CE2A, GPIO_FN_BACK,
+
+	/* DMAC */
+	GPIO_FN_DACK0, GPIO_FN_DREQ0, GPIO_FN_DRAK0,
+	GPIO_FN_DACK1, GPIO_FN_DREQ1, GPIO_FN_DRAK1,
+	GPIO_FN_DACK2, GPIO_FN_DREQ2, GPIO_FN_DRAK2,
+	GPIO_FN_DACK3, GPIO_FN_DREQ3, GPIO_FN_DRAK3,
+
+	/* INTC */
+	GPIO_FN_IRQ3, GPIO_FN_IRQ2, GPIO_FN_IRQ1, GPIO_FN_IRQ0,
+	GPIO_FN_IRL3, GPIO_FN_IRL2, GPIO_FN_IRL1, GPIO_FN_IRL0,
+	GPIO_FN_IRQOUT, GPIO_FN_STATUS1, GPIO_FN_STATUS0,
+};
+
+#endif /* __CPU_SHX3_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/edosk7705.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/edosk7705.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/edosk7705.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/edosk7705.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,7 +0,0 @@
-#ifndef __ASM_SH_EDOSK7705_H
-#define __ASM_SH_EDOSK7705_H
-
-#define __IO_PREFIX sh_edosk7705
-#include <asm/io_generic.h>
-
-#endif /* __ASM_SH_EDOSK7705_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/microdev.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/microdev.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/microdev.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/microdev.h	2011-01-04 19:50:19.000000000 -0500
@@ -68,13 +68,4 @@
 #define __IO_PREFIX microdev
 #include <asm/io_generic.h>
 
-#if defined(CONFIG_PCI)
-unsigned char  microdev_pci_inb(unsigned long port);
-unsigned short microdev_pci_inw(unsigned long port);
-unsigned long  microdev_pci_inl(unsigned long port);
-void           microdev_pci_outb(unsigned char  data, unsigned long port);
-void           microdev_pci_outw(unsigned short data, unsigned long port);
-void           microdev_pci_outl(unsigned long  data, unsigned long port);
-#endif
-
 #endif /* __ASM_SH_MICRODEV_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/secureedge5410.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/secureedge5410.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/secureedge5410.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/secureedge5410.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,49 @@
+/*
+ * include/asm-sh/snapgear.h
+ *
+ * Modified version of io_se.h for the snapgear-specific functions.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a SnapGear
+ */
+
+#ifndef _ASM_SH_IO_SNAPGEAR_H
+#define _ASM_SH_IO_SNAPGEAR_H
+
+#define __IO_PREFIX	snapgear
+#include <asm/io_generic.h>
+
+/*
+ * We need to remember what was written to the ioport as some bits
+ * are shared with other functions and you cannot read back what was
+ * written :-|
+ *
+ * Bit        Read                   Write
+ * -----------------------------------------------
+ * D0         DCD on ttySC1          power
+ * D1         Reset Switch           heatbeat
+ * D2         ttySC0 CTS (7100)      LAN
+ * D3         -                      WAN
+ * D4         ttySC0 DCD (7100)      CONSOLE
+ * D5         -                      ONLINE
+ * D6         -                      VPN
+ * D7         -                      DTR on ttySC1
+ * D8         -                      ttySC0 RTS (7100)
+ * D9         -                      ttySC0 DTR (7100)
+ * D10        -                      RTC SCLK
+ * D11        RTC DATA               RTC DATA
+ * D12        -                      RTS RESET
+ */
+
+#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+extern unsigned short secureedge5410_ioport;
+
+#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+	 (secureedge5410_ioport = \
+			((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+#define SECUREEDGE_READ_IOPORT() \
+	 ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+
+#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/sh2007.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/sh2007.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/sh2007.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/sh2007.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,117 @@
+#ifndef __MACH_SH2007_H
+#define __MACH_SH2007_H
+
+#define CS5BCR		0xff802050
+#define CS5WCR		0xff802058
+#define CS5PCR		0xff802070
+
+#define BUS_SZ8		1
+#define BUS_SZ16	2
+#define BUS_SZ32	3
+
+#define PCMCIA_IODYN	1
+#define PCMCIA_ATA	0
+#define PCMCIA_IO8	2
+#define PCMCIA_IO16	3
+#define PCMCIA_COMM8	4
+#define PCMCIA_COMM16	5
+#define PCMCIA_ATTR8	6
+#define PCMCIA_ATTR16	7
+
+#define TYPE_SRAM	0
+#define TYPE_PCMCIA	4
+
+/* write-read/write-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWW5		0
+#define IWW6		3
+/* different area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWD5		2
+#define IWRWD6		2
+/* same area, read-write delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRWS5		2
+#define IWRWS6		2
+/* different area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRD5		2
+#define IWRRD6		2
+/* same area, read-read delay (0-7:0,1,2,3,4,5,6,7) */
+#define IWRRS5		0
+#define IWRRS6		2
+/* burst count (0-3:4,8,16,32) */
+#define BST5		0
+#define BST6		0
+/* bus size */
+#define SZ5		BUS_SZ16
+#define SZ6		BUS_SZ16
+/* RD hold for SRAM (0-1:0,1) */
+#define RDSPL5		0
+#define RDSPL6		0
+/* Burst pitch (0-7:0,1,2,3,4,5,6,7) */
+#define BW5		0
+#define BW6		0
+/* Multiplex (0-1:0,1) */
+#define MPX5		0
+#define MPX6		0
+/* device type */
+#define TYPE5		TYPE_PCMCIA
+#define TYPE6		TYPE_PCMCIA
+/* address setup before assert CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADS5		0
+#define ADS6		0
+/* address hold after negate CSn for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define ADH5		0
+#define ADH6		0
+/* CSn assert to RD assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDS5		0
+#define RDS6		0
+/* RD negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define RDH5		0
+#define RDH6		0
+/* CSn assert to WE assert delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTS5		0
+#define WTS6		0
+/* WE negate to CSn negate delay for SRAM (0-7:0,1,2,3,4,5,6,7) */
+#define WTH5		0
+#define WTH6		0
+/* BS hold (0-1:1,2) */
+#define BSH5		0
+#define BSH6		0
+/* wait cycle (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define IW5		6	/* 60ns PIO mode 4 */
+#define IW6		15	/* 250ns */
+
+#define SAA5		PCMCIA_IODYN	/* IDE area b4000000-b5ffffff */
+#define SAB5		PCMCIA_IODYN	/* CF  area b6000000-b7ffffff */
+#define PCWA5		0	/* additional wait A (0-3:0,15,30,50) */
+#define PCWB5		0	/* additional wait B (0-3:0,15,30,50) */
+/* wait B (0-15:0,1,2,3,4,5,6,7,8,9,11,13,15,17,21,25) */
+#define PCIW5		12
+/* Address->OE/WE assert delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEDA5		2
+/* Address->OE/WE assert delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEDB5		4
+/* OE/WE negate->Address delay A (0-7:0,1,2,3,6,9,12,15) */
+#define TEHA5		2
+/* OE/WE negate->Address delay B (0-7:0,1,2,3,6,9,12,15) */
+#define TEHB5		3
+
+#define CS5BCR_D	((IWW5<<28)|(IWRWD5<<24)|(IWRWS5<<20)|		\
+			(IWRRD5<<16)|(IWRRS5<<12)|(BST5<<10)|		\
+			(SZ5<<8)|(RDSPL5<<7)|(BW5<<4)|(MPX5<<3)|TYPE5)
+#define CS5WCR_D	((ADS5<<28)|(ADH5<<24)|(RDS5<<20)|	\
+			(RDH5<<16)|(WTS5<<12)|(WTH5<<8)|(BSH5<<4)|IW5)
+#define CS5PCR_D	((SAA5<<28)|(SAB5<<24)|(PCWA5<<22)|		\
+			(PCWB5<<20)|(PCIW5<<16)|(TEDA5<<12)|		\
+			(TEDB5<<8)|(TEHA5<<4)|TEHB5)
+
+#define SMC0_BASE       0xb0800000      /* eth0 */
+#define SMC1_BASE       0xb0900000      /* eth1 */
+#define CF_BASE         0xb6100000      /* Compact Flash (I/O area) */
+#define IDE_BASE        0xb4000000      /* IDE */
+#define PC104_IO_BASE   0xb8000000
+#define PC104_MEM_BASE  0xba000000
+#define SMC_IO_SIZE     0x100
+
+#define CF_OFFSET       0x1f0
+#define IDE_OFFSET      0x170
+
+#endif /* __MACH_SH2007_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/snapgear.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/snapgear.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/snapgear.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/snapgear.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,71 +0,0 @@
-/*
- * include/asm-sh/snapgear.h
- *
- * Modified version of io_se.h for the snapgear-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for a SnapGear
- */
-
-#ifndef _ASM_SH_IO_SNAPGEAR_H
-#define _ASM_SH_IO_SNAPGEAR_H
-
-#if defined(CONFIG_CPU_SH4)
-/*
- * The external interrupt lines, these take up ints 0 - 15 inclusive
- * depending on the priority for the interrupt.  In fact the priority
- * is the interrupt :-)
- */
-
-#define IRL0_IRQ	2
-#define IRL0_PRIORITY	13
-
-#define IRL1_IRQ	5
-#define IRL1_PRIORITY	10
-
-#define IRL2_IRQ	8
-#define IRL2_PRIORITY	7
-
-#define IRL3_IRQ	11
-#define IRL3_PRIORITY	4
-#endif
-
-#define __IO_PREFIX	snapgear
-#include <asm/io_generic.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-/*
- * We need to remember what was written to the ioport as some bits
- * are shared with other functions and you cannot read back what was
- * written :-|
- *
- * Bit        Read                   Write
- * -----------------------------------------------
- * D0         DCD on ttySC1          power
- * D1         Reset Switch           heatbeat
- * D2         ttySC0 CTS (7100)      LAN
- * D3         -                      WAN
- * D4         ttySC0 DCD (7100)      CONSOLE
- * D5         -                      ONLINE
- * D6         -                      VPN
- * D7         -                      DTR on ttySC1
- * D8         -                      ttySC0 RTS (7100)
- * D9         -                      ttySC0 DTR (7100)
- * D10        -                      RTC SCLK
- * D11        RTC DATA               RTC DATA
- * D12        -                      RTS RESET
- */
-
-#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
-extern unsigned short secureedge5410_ioport;
-
-#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
-	 (secureedge5410_ioport = \
-			((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
-#define SECUREEDGE_READ_IOPORT() \
-	 ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
-#endif
-
-#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/systemh7751.h linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/systemh7751.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-common/mach/systemh7751.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-common/mach/systemh7751.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,71 +0,0 @@
-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
-
-/*
- * linux/include/asm-sh/systemh/7751systemh.h
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH support
-
- * Modified for 7751 SystemH by
- * Jonathan Short, 2002.
- */
-
-/* Box specific addresses.  */
-
-#define PA_ROM		0x00000000	/* EPROM */
-#define PA_ROM_SIZE	0x00400000	/* EPROM size 4M byte */
-#define PA_FROM		0x01000000	/* EPROM */
-#define PA_FROM_SIZE	0x00400000	/* EPROM size 4M byte */
-#define PA_EXT1		0x04000000
-#define PA_EXT1_SIZE	0x04000000
-#define PA_EXT2		0x08000000
-#define PA_EXT2_SIZE	0x04000000
-#define PA_SDRAM	0x0c000000
-#define PA_SDRAM_SIZE	0x04000000
-
-#define PA_EXT4		0x12000000
-#define PA_EXT4_SIZE	0x02000000
-#define PA_EXT5		0x14000000
-#define PA_EXT5_SIZE	0x04000000
-#define PA_PCIC		0x18000000	/* MR-SHPC-01 PCMCIA */
-
-#define PA_DIPSW0	0xb9000000	/* Dip switch 5,6 */
-#define PA_DIPSW1	0xb9000002	/* Dip switch 7,8 */
-#define PA_LED		0xba000000	/* LED */
-#define	PA_BCR		0xbb000000	/* FPGA on the MS7751SE01 */
-
-#define PA_MRSHPC	0xb83fffe0	/* MR-SHPC-01 PCMCIA controller */
-#define PA_MRSHPC_MW1	0xb8400000	/* MR-SHPC-01 memory window base */
-#define PA_MRSHPC_MW2	0xb8500000	/* MR-SHPC-01 attribute window base */
-#define PA_MRSHPC_IO	0xb8600000	/* MR-SHPC-01 I/O window base */
-#define MRSHPC_MODE     (PA_MRSHPC + 4)
-#define MRSHPC_OPTION   (PA_MRSHPC + 6)
-#define MRSHPC_CSR      (PA_MRSHPC + 8)
-#define MRSHPC_ISR      (PA_MRSHPC + 10)
-#define MRSHPC_ICR      (PA_MRSHPC + 12)
-#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
-#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
-#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
-#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
-#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
-#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
-#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
-#define MRSHPC_CDCR     (PA_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
-
-#define BCR_ILCRA	(PA_BCR + 0)
-#define BCR_ILCRB	(PA_BCR + 2)
-#define BCR_ILCRC	(PA_BCR + 4)
-#define BCR_ILCRD	(PA_BCR + 6)
-#define BCR_ILCRE	(PA_BCR + 8)
-#define BCR_ILCRF	(PA_BCR + 10)
-#define BCR_ILCRG	(PA_BCR + 12)
-
-#define IRQ_79C973	13
-
-#define __IO_PREFIX	sh7751systemh
-#include <asm/io_generic.h>
-
-#endif  /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-sdk7786/mach/fpga.h linux-libre-2.6.37-gnu/arch/sh/include/mach-sdk7786/mach/fpga.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-sdk7786/mach/fpga.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-sdk7786/mach/fpga.h	2011-01-04 19:50:19.000000000 -0500
@@ -31,11 +31,35 @@
 #define EXTASR		0x110
 #define SPCAR		0x120
 #define INTMSR		0x130
+
 #define PCIECR		0x140
+#define  PCIECR_PCIEMUX1	BIT(15)
+#define  PCIECR_PCIEMUX0	BIT(14)
+#define  PCIECR_PRST4		BIT(12) /* slot 4 card present */
+#define  PCIECR_PRST3		BIT(11) /* slot 3 card present */
+#define  PCIECR_PRST2		BIT(10) /* slot 2 card present */
+#define  PCIECR_PRST1		BIT(9)  /* slot 1 card present */
+#define  PCIECR_CLKEN		BIT(4)	/* oscillator enable */
+
 #define FAER		0x150
 #define USRGPIR		0x160
+
 /* 0x170 reserved */
-#define LCLASR		0x180
+
+#define LCLASR			0x180
+#define  LCLASR_FRAMEN		BIT(15)
+
+#define  LCLASR_FPGA_SEL_SHIFT	12
+#define  LCLASR_NAND_SEL_SHIFT	8
+#define  LCLASR_NORB_SEL_SHIFT	4
+#define  LCLASR_NORA_SEL_SHIFT	0
+
+#define  LCLASR_AREA_MASK	0x7
+
+#define  LCLASR_FPGA_SEL_MASK	(LCLASR_AREA_MASK << LCLASR_FPGA_SEL_SHIFT)
+#define  LCLASR_NAND_SEL_MASK	(LCLASR_AREA_MASK << LCLASR_NAND_SEL_SHIFT)
+#define  LCLASR_NORB_SEL_MASK	(LCLASR_AREA_MASK << LCLASR_NORB_SEL_SHIFT)
+#define  LCLASR_NORA_SEL_MASK	(LCLASR_AREA_MASK << LCLASR_NORA_SEL_SHIFT)
 
 #define SBCR		0x190
 #define  SCBR_I2CMEN	BIT(0)	/* FPGA I2C master enable */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-x3proto/mach/hardware.h linux-libre-2.6.37-gnu/arch/sh/include/mach-x3proto/mach/hardware.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-x3proto/mach/hardware.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-x3proto/mach/hardware.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,12 @@
+#ifndef __MACH_X3PROTO_HARDWARE_H
+#define __MACH_X3PROTO_HARDWARE_H
+
+struct gpio_chip;
+
+/* arch/sh/boards/mach-x3proto/gpio.c */
+int x3proto_gpio_setup(void);
+extern struct gpio_chip x3proto_gpio_chip;
+
+#define NR_BASEBOARD_GPIOS	16
+
+#endif /* __MACH_X3PROTO_HARDWARE_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/include/mach-x3proto/mach/ilsel.h linux-libre-2.6.37-gnu/arch/sh/include/mach-x3proto/mach/ilsel.h
--- linux-libre-2.6.36-gnu/arch/sh/include/mach-x3proto/mach/ilsel.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/include/mach-x3proto/mach/ilsel.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,45 @@
+#ifndef __ASM_SH_ILSEL_H
+#define __ASM_SH_ILSEL_H
+
+typedef enum {
+	ILSEL_NONE,
+	ILSEL_LAN,
+	ILSEL_USBH_I,
+	ILSEL_USBH_S,
+	ILSEL_USBH_V,
+	ILSEL_RTC,
+	ILSEL_USBP_I,
+	ILSEL_USBP_S,
+	ILSEL_USBP_V,
+	ILSEL_KEY,
+
+	/*
+	 * ILSEL Aliases - corner cases for interleaved level tables.
+	 *
+	 * Someone thought this was a good idea and less hassle than
+	 * demuxing a shared vector, really.
+	 */
+
+	/* ILSEL0 and 2 */
+	ILSEL_FPGA0,
+	ILSEL_FPGA1,
+	ILSEL_EX1,
+	ILSEL_EX2,
+	ILSEL_EX3,
+	ILSEL_EX4,
+
+	/* ILSEL1 and 3 */
+	ILSEL_FPGA2 = ILSEL_FPGA0,
+	ILSEL_FPGA3 = ILSEL_FPGA1,
+	ILSEL_EX5 = ILSEL_EX1,
+	ILSEL_EX6 = ILSEL_EX2,
+	ILSEL_EX7 = ILSEL_EX3,
+	ILSEL_EX8 = ILSEL_EX4,
+} ilsel_source_t;
+
+/* arch/sh/boards/renesas/x3proto/ilsel.c */
+int ilsel_enable(ilsel_source_t set);
+int ilsel_enable_fixed(ilsel_source_t set, unsigned int level);
+void ilsel_disable(unsigned int irq);
+
+#endif /* __ASM_SH_ILSEL_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/Kconfig linux-libre-2.6.37-gnu/arch/sh/Kconfig
--- linux-libre-2.6.36-gnu/arch/sh/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,3 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux/SuperH Kernel Configuration"
-
 config SUPERH
 	def_bool y
 	select EMBEDDED
@@ -16,6 +9,7 @@
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_DMA_API_DEBUG
 	select HAVE_DMA_ATTRS
+	select HAVE_IRQ_WORK
 	select HAVE_PERF_EVENTS
 	select PERF_USE_VMALLOC
 	select HAVE_KERNEL_GZIP
@@ -23,8 +17,13 @@
 	select HAVE_KERNEL_LZMA
 	select HAVE_KERNEL_LZO
 	select HAVE_SYSCALL_TRACEPOINTS
+	select HAVE_REGS_AND_STACK_ACCESS_API
+	select HAVE_GENERIC_HARDIRQS
+	select HAVE_SPARSE_IRQ
 	select RTC_LIB
 	select GENERIC_ATOMIC64
+	# Support the deprecated APIs until MFD and GPIOLIB catch up.
+	select GENERIC_HARDIRQS_NO_DEPRECATED if !MFD_SUPPORT && !GPIOLIB
 	help
 	  The SuperH is a RISC processor targeted for use in embedded systems
 	  and consumer electronics; it was also used in the Sega Dreamcast
@@ -45,8 +44,9 @@
 	select HAVE_ARCH_KGDB
 	select HAVE_HW_BREAKPOINT
 	select HAVE_MIXED_BREAKPOINTS_REGS
-	select PERF_EVENTS if HAVE_HW_BREAKPOINT
+	select PERF_EVENTS
 	select ARCH_HIBERNATION_POSSIBLE if MMU
+	select SPARSE_IRQ
 
 config SUPERH64
 	def_bool ARCH = "sh64"
@@ -76,19 +76,9 @@
 config GENERIC_HWEIGHT
 	def_bool y
 
-config GENERIC_HARDIRQS
-	def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-	def_bool y
-
 config IRQ_PER_CPU
 	def_bool y
 
-config SPARSE_IRQ
-	def_bool y
-	depends on SUPERH32
-
 config GENERIC_GPIO
 	def_bool n
 
@@ -204,6 +194,7 @@
 config CPU_SH2A
 	bool
 	select CPU_SH2
+	select UNCACHED_MAPPING
 
 config CPU_SH3
 	bool
@@ -249,6 +240,11 @@
 	select PM
 	select PM_RUNTIME
 
+config CPU_HAS_PMU
+       depends on CPU_SH4 || CPU_SH4A
+       default y
+       bool
+
 if SUPERH32
 
 choice
@@ -465,6 +461,7 @@
 	select CPU_SH4A
 	select CPU_SHX3
 	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+	select ARCH_REQUIRE_GPIOLIB
 
 # SH4AL-DSP Processor Support
 
@@ -569,7 +566,7 @@
 config SH_CLK_CPG_LEGACY
 	depends on SH_CLK_CPG
 	def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
-		      !CPU_SUBTYPE_SH7786
+		      !CPU_SHX3 && !CPU_SUBTYPE_SH7757
 
 config SH_CLK_MD
 	int "CPU Mode Pin Setting"
@@ -738,6 +735,14 @@
 	  LLSC, this should be more efficient than the other alternative of
 	  disabling interrupts around the atomic sequence.
 
+config HW_PERF_EVENTS
+	bool "Enable hardware performance counter support for perf events"
+	depends on PERF_EVENTS && CPU_HAS_PMU
+	default y
+	help
+	  Enable hardware performance counter support for perf events. If
+	  disabled, perf events will use software events only.
+
 source "drivers/sh/Kconfig"
 
 endmenu
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/clkdev.c linux-libre-2.6.37-gnu/arch/sh/kernel/clkdev.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/clkdev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/clkdev.c	2011-01-04 19:50:19.000000000 -0500
@@ -161,9 +161,11 @@
  */
 void clkdev_drop(struct clk_lookup *cl)
 {
+	struct clk_lookup_alloc *cla = container_of(cl, struct clk_lookup_alloc, cl);
+
 	mutex_lock(&clocks_mutex);
 	list_del(&cl->node);
 	mutex_unlock(&clocks_mutex);
-	kfree(cl);
+	kfree(cla);
 }
 EXPORT_SYMBOL(clkdev_drop);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/init.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/init.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -340,6 +340,8 @@
 	 */
 	current_cpu_data.asid_cache = NO_CONTEXT;
 
+	current_cpu_data.phys_bits = __in_29bit_mode() ? 29 : 32;
+
 	speculative_execution_init();
 	expmask_init();
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/imask.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/imask.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/imask.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/imask.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,16 +51,20 @@
 		     : "t");
 }
 
-static void mask_imask_irq(unsigned int irq)
+static void mask_imask_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
+
 	clear_bit(irq, imask_mask);
 	if (interrupt_priority < IMASK_PRIORITY - irq)
 		interrupt_priority = IMASK_PRIORITY - irq;
 	set_interrupt_registers(interrupt_priority);
 }
 
-static void unmask_imask_irq(unsigned int irq)
+static void unmask_imask_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
+
 	set_bit(irq, imask_mask);
 	interrupt_priority = IMASK_PRIORITY -
 		find_first_zero_bit(imask_mask, IMASK_PRIORITY);
@@ -69,9 +73,9 @@
 
 static struct irq_chip imask_irq_chip = {
 	.name		= "SR.IMASK",
-	.mask		= mask_imask_irq,
-	.unmask		= unmask_imask_irq,
-	.mask_ack	= mask_imask_irq,
+	.irq_mask	= mask_imask_irq,
+	.irq_unmask	= unmask_imask_irq,
+	.irq_mask_ack	= mask_imask_irq,
 };
 
 void make_imask_irq(unsigned int irq)
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/intc-sh5.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/intc-sh5.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/intc-sh5.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/intc-sh5.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,39 +76,11 @@
 };
 
 static unsigned long intc_virt;
-
-static unsigned int startup_intc_irq(unsigned int irq);
-static void shutdown_intc_irq(unsigned int irq);
-static void enable_intc_irq(unsigned int irq);
-static void disable_intc_irq(unsigned int irq);
-static void mask_and_ack_intc(unsigned int);
-static void end_intc_irq(unsigned int irq);
-
-static struct irq_chip intc_irq_type = {
-	.name = "INTC",
-	.startup = startup_intc_irq,
-	.shutdown = shutdown_intc_irq,
-	.enable = enable_intc_irq,
-	.disable = disable_intc_irq,
-	.ack = mask_and_ack_intc,
-	.end = end_intc_irq
-};
-
 static int irlm;		/* IRL mode */
 
-static unsigned int startup_intc_irq(unsigned int irq)
-{
-	enable_intc_irq(irq);
-	return 0; /* never anything pending */
-}
-
-static void shutdown_intc_irq(unsigned int irq)
-{
-	disable_intc_irq(irq);
-}
-
-static void enable_intc_irq(unsigned int irq)
+static void enable_intc_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned long reg;
 	unsigned long bitmask;
 
@@ -126,8 +98,9 @@
 	__raw_writel(bitmask, reg);
 }
 
-static void disable_intc_irq(unsigned int irq)
+static void disable_intc_irq(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned long reg;
 	unsigned long bitmask;
 
@@ -142,15 +115,11 @@
 	__raw_writel(bitmask, reg);
 }
 
-static void mask_and_ack_intc(unsigned int irq)
-{
-	disable_intc_irq(irq);
-}
-
-static void end_intc_irq(unsigned int irq)
-{
-	enable_intc_irq(irq);
-}
+static struct irq_chip intc_irq_type = {
+	.name = "INTC",
+	.irq_enable = enable_intc_irq,
+	.irq_disable = disable_intc_irq,
+};
 
 void __init plat_irq_setup(void)
 {
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/ipr.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/ipr.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/irq/ipr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/irq/ipr.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,25 +24,25 @@
 #include <linux/module.h>
 #include <linux/topology.h>
 
-static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
+static inline struct ipr_desc *get_ipr_desc(struct irq_data *data)
 {
-	struct irq_chip *chip = get_irq_chip(irq);
+	struct irq_chip *chip = irq_data_get_irq_chip(data);
 	return container_of(chip, struct ipr_desc, chip);
 }
 
-static void disable_ipr_irq(unsigned int irq)
+static void disable_ipr_irq(struct irq_data *data)
 {
-	struct ipr_data *p = get_irq_chip_data(irq);
-	unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+	struct ipr_data *p = irq_data_get_irq_chip_data(data);
+	unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
 	/* Set the priority in IPR to 0 */
 	__raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr);
 	(void)__raw_readw(addr);	/* Read back to flush write posting */
 }
 
-static void enable_ipr_irq(unsigned int irq)
+static void enable_ipr_irq(struct irq_data *data)
 {
-	struct ipr_data *p = get_irq_chip_data(irq);
-	unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
+	struct ipr_data *p = irq_data_get_irq_chip_data(data);
+	unsigned long addr = get_ipr_desc(data)->ipr_offsets[p->ipr_idx];
 	/* Set priority in IPR back to original value */
 	__raw_writew(__raw_readw(addr) | (p->priority << p->shift), addr);
 }
@@ -56,19 +56,18 @@
 {
 	int i;
 
-	desc->chip.mask = disable_ipr_irq;
-	desc->chip.unmask = enable_ipr_irq;
-	desc->chip.mask_ack = disable_ipr_irq;
+	desc->chip.irq_mask = disable_ipr_irq;
+	desc->chip.irq_unmask = enable_ipr_irq;
 
 	for (i = 0; i < desc->nr_irqs; i++) {
 		struct ipr_data *p = desc->ipr_data + i;
-		struct irq_desc *irq_desc;
+		int res;
 
 		BUG_ON(p->ipr_idx >= desc->nr_offsets);
 		BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
 
-		irq_desc = irq_to_desc_alloc_node(p->irq, numa_node_id());
-		if (unlikely(!irq_desc)) {
+		res = irq_alloc_desc_at(p->irq, numa_node_id());
+		if (unlikely(res != p->irq && res != -EEXIST)) {
 			printk(KERN_INFO "can not get irq_desc for %d\n",
 			       p->irq);
 			continue;
@@ -78,7 +77,7 @@
 		set_irq_chip_and_handler_name(p->irq, &desc->chip,
 				      handle_level_irq, "level");
 		set_irq_chip_data(p->irq, p);
-		disable_ipr_irq(p->irq);
+		disable_ipr_irq(irq_get_irq_data(p->irq));
 	}
 }
 EXPORT_SYMBOL(register_ipr_controller);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh2a/clock-sh7201.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh2a/clock-sh7201.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh2a/clock-sh7201.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh2a/clock-sh7201.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 
 static void master_clk_init(struct clk *clk)
 {
-	return 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
+	clk->rate = 10000000 * PLL2 * pll1rate[(__raw_readw(FREQCR) >> 8) & 0x0007];
 }
 
 static struct clk_ops sh7201_master_clk_ops = {
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/clock-sh4-202.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/clock-sh4-202.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/clock-sh4-202.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,8 +81,7 @@
 	for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
 		int divisor = frqcr3_divisors[i];
 
-		if (clk->ops->set_rate(clk, clk->parent->rate /
-						divisor, 0) == 0)
+		if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
 			break;
 	}
 
@@ -110,7 +109,7 @@
 	return 0;
 }
 
-static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+static int shoc_clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	unsigned long frqcr3;
 	unsigned int tmp;
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/perf_event.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/perf_event.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -225,7 +225,7 @@
 }
 
 static struct sh_pmu sh7750_pmu = {
-	.name		= "SH7750",
+	.name		= "sh7750",
 	.num_events	= 2,
 	.event_map	= sh7750_event_map,
 	.max_events	= ARRAY_SIZE(sh7750_general_events),
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/probe.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/probe.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4/probe.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4/probe.c	2011-01-04 19:50:19.000000000 -0500
@@ -150,7 +150,7 @@
 			boot_cpu_data.type = CPU_SH7724;
 			boot_cpu_data.flags |= CPU_HAS_L2_CACHE;
 			break;
-		case 0x50:
+		case 0x10:
 			boot_cpu_data.type = CPU_SH7757;
 			break;
 		}
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7724.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7724.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7724.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,7 +48,7 @@
  * Default rate for the root input clock, reset this with clk_set_rate()
  * from the platform code.
  */
-struct clk extal_clk = {
+static struct clk extal_clk = {
 	.rate		= 33333333,
 };
 
@@ -111,12 +111,21 @@
 	.parent		= &pll_clk,
 };
 
-struct clk *main_clks[] = {
+/* External input clock (pin name: FSIMCKA/FSIMCKB ) */
+struct clk sh7724_fsimcka_clk = {
+};
+
+struct clk sh7724_fsimckb_clk = {
+};
+
+static struct clk *main_clks[] = {
 	&r_clk,
 	&extal_clk,
 	&fll_clk,
 	&pll_clk,
 	&div3_clk,
+	&sh7724_fsimcka_clk,
+	&sh7724_fsimckb_clk,
 };
 
 static void div4_kick(struct clk *clk)
@@ -154,16 +163,38 @@
 	[DIV4_M1] = DIV4(FRQCRB, 4, 0x2f7c, CLK_ENABLE_ON_INIT),
 };
 
-enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
+enum { DIV6_V, DIV6_I, DIV6_S, DIV6_NR };
 
-struct clk div6_clks[DIV6_NR] = {
+static struct clk div6_clks[DIV6_NR] = {
 	[DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
-	[DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
-	[DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
 	[DIV6_I] = SH_CLK_DIV6(&div3_clk, IRDACLKCR, 0),
 	[DIV6_S] = SH_CLK_DIV6(&div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
 };
 
+enum { DIV6_FA, DIV6_FB, DIV6_REPARENT_NR };
+
+/* Indices are important - they are the actual src selecting values */
+static struct clk *fclkacr_parent[] = {
+	[0] = &div3_clk,
+	[1] = NULL,
+	[2] = &sh7724_fsimcka_clk,
+	[3] = NULL,
+};
+
+static struct clk *fclkbcr_parent[] = {
+	[0] = &div3_clk,
+	[1] = NULL,
+	[2] = &sh7724_fsimckb_clk,
+	[3] = NULL,
+};
+
+static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
+	[DIV6_FA] = SH_CLK_DIV6_EXT(&div3_clk, FCLKACR, 0,
+				      fclkacr_parent, ARRAY_SIZE(fclkacr_parent), 6, 2),
+	[DIV6_FB] = SH_CLK_DIV6_EXT(&div3_clk, FCLKBCR, 0,
+				      fclkbcr_parent, ARRAY_SIZE(fclkbcr_parent), 6, 2),
+};
+
 static struct clk mstp_clks[HWBLK_NR] = {
 	SH_HWBLK_CLK(HWBLK_TLB, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
 	SH_HWBLK_CLK(HWBLK_IC, &div4_clks[DIV4_I], CLK_ENABLE_ON_INIT),
@@ -240,8 +271,8 @@
 
 	/* DIV6 clocks */
 	CLKDEV_CON_ID("video_clk", &div6_clks[DIV6_V]),
-	CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FA]),
-	CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FB]),
+	CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FA]),
+	CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FB]),
 	CLKDEV_CON_ID("irda_clk", &div6_clks[DIV6_I]),
 	CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_S]),
 
@@ -376,6 +407,9 @@
 		ret = sh_clk_div6_register(div6_clks, DIV6_NR);
 
 	if (!ret)
+		ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR);
+
+	if (!ret)
 		ret = sh_hwblk_clk_register(mstp_clks, HWBLK_NR);
 
 	return ret;
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7757.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7757.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7757.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-sh7757.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
  *
  * SH7757 support for the clock framework
  *
- *  Copyright (C) 2009  Renesas Solutions Corp.
+ *  Copyright (C) 2009-2010  Renesas Solutions Corp.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -16,124 +16,147 @@
 #include <asm/clock.h>
 #include <asm/freq.h>
 
-static int ifc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-			      16, 1, 1, 32, 1, 1, 1, 1 };
-static int sfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-			      16, 1, 1, 32, 1, 1, 1, 1 };
-static int bfc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-			      16, 1, 1, 32, 1, 1, 1, 1 };
-static int p1fc_divisors[] = { 2, 1, 4, 1, 1, 8, 1, 1,
-			       16, 1, 1, 32, 1, 1, 1, 1 };
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+	.rate		= 48000000,
+};
 
-static void master_clk_init(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
 {
-	clk->rate = CONFIG_SH_PCLK_FREQ * 16;
-}
+	int multiplier;
 
-static struct clk_ops sh7757_master_clk_ops = {
-	.init		= master_clk_init,
-};
+	multiplier = test_mode_pin(MODE_PIN0) ? 24 : 16;
 
-static void module_clk_recalc(struct clk *clk)
-{
-	int idx = __raw_readl(FRQCR) & 0x0000000f;
-	clk->rate = clk->parent->rate / p1fc_divisors[idx];
+	return clk->parent->rate * multiplier;
 }
 
-static struct clk_ops sh7757_module_clk_ops = {
-	.recalc		= module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+	.recalc		= pll_recalc,
 };
 
-static void bus_clk_recalc(struct clk *clk)
-{
-	int idx = (__raw_readl(FRQCR) >> 8) & 0x0000000f;
-	clk->rate = clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+	.ops		= &pll_clk_ops,
+	.parent		= &extal_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
 
-static struct clk_ops sh7757_bus_clk_ops = {
-	.recalc		= bus_clk_recalc,
+static struct clk *clks[] = {
+	&extal_clk,
+	&pll_clk,
 };
 
-static void cpu_clk_recalc(struct clk *clk)
-{
-	int idx = (__raw_readl(FRQCR) >> 20) & 0x0000000f;
-	clk->rate = clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 1, 2, 1, 1, 4, 1, 6,
+			       1, 1, 1, 16, 1, 24, 1, 1 };
 
-static struct clk_ops sh7757_cpu_clk_ops = {
-	.recalc		= cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+	.divisors = div2,
+	.nr_divisors = ARRAY_SIZE(div2),
 };
 
-static struct clk_ops *sh7757_clk_ops[] = {
-	&sh7757_master_clk_ops,
-	&sh7757_module_clk_ops,
-	&sh7757_bus_clk_ops,
-	&sh7757_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+	.div_mult_table = &div4_div_mult_table,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
-	if (idx < ARRAY_SIZE(sh7757_clk_ops))
-		*ops = sh7757_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_P, DIV4_NR };
 
-static void shyway_clk_recalc(struct clk *clk)
-{
-	int idx = (__raw_readl(FRQCR) >> 12) & 0x0000000f;
-	clk->rate = clk->parent->rate / sfc_divisors[idx];
-}
+#define DIV4(_bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, FRQCR, _bit, _mask, _flags)
 
-static struct clk_ops sh7757_shyway_clk_ops = {
-	.recalc		= shyway_clk_recalc,
+struct clk div4_clks[DIV4_NR] = {
+	/*
+	 * P clock is always enable, because some P clock modules is used
+	 * by Host PC.
+	 */
+	[DIV4_P] = DIV4(0, 0x2800, CLK_ENABLE_ON_INIT),
+	[DIV4_SH] = DIV4(12, 0x00a0, CLK_ENABLE_ON_INIT),
+	[DIV4_I] = DIV4(20, 0x0004, CLK_ENABLE_ON_INIT),
 };
 
-static struct clk sh7757_shyway_clk = {
-	.flags		= CLK_ENABLE_ON_INIT,
-	.ops		= &sh7757_shyway_clk_ops,
-};
+#define MSTPCR0		0xffc80030
+#define MSTPCR1		0xffc80034
 
-/*
- * Additional sh7757-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *sh7757_onchip_clocks[] = {
-	&sh7757_shyway_clk,
+enum { MSTP004, MSTP000, MSTP114, MSTP113, MSTP112,
+       MSTP111, MSTP110, MSTP103, MSTP102,
+       MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+	/* MSTPCR0 */
+	[MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0),
+	[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+	/* MSTPCR1 */
+	[MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+	[MSTP113] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 13, 0),
+	[MSTP112] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 12, 0),
+	[MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+	[MSTP110] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 10, 0),
+	[MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+	[MSTP102] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 2, 0),
 };
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
 	/* main clocks */
-	CLKDEV_CON_ID("shyway_clk", &sh7757_shyway_clk),
-};
-
-static int __init sh7757_clk_init(void)
-{
-	struct clk *clk = clk_get(NULL, "master_clk");
-	int i;
+	CLKDEV_CON_ID("extal", &extal_clk),
+	CLKDEV_CON_ID("pll_clk", &pll_clk),
 
-	for (i = 0; i < ARRAY_SIZE(sh7757_onchip_clocks); i++) {
-		struct clk *clkp = sh7757_onchip_clocks[i];
+	/* DIV4 clocks */
+	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+	CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 
-		clkp->parent = clk;
-		clk_register(clkp);
-		clk_enable(clkp);
-	}
+	/* MSTP32 clocks */
+	CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP004]),
+	CLKDEV_CON_ID("riic", &mstp_clks[MSTP000]),
+	{
+		/* TMU0 */
+		.dev_id		= "sh_tmu.0",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP113],
+	}, {
+		/* TMU1 */
+		.dev_id		= "sh_tmu.1",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP114],
+	},
+	{
+		/* SCIF4 (But, ID is 2) */
+		.dev_id		= "sh-sci.2",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP112],
+	}, {
+		/* SCIF3 */
+		.dev_id		= "sh-sci.1",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP111],
+	}, {
+		/* SCIF2 */
+		.dev_id		= "sh-sci.0",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP110],
+	},
+	CLKDEV_CON_ID("usb0", &mstp_clks[MSTP102]),
+};
 
-	/*
-	 * Now that we have the rest of the clocks registered, we need to
-	 * force the parent clock to propagate so that these clocks will
-	 * automatically figure out their rate. We cheat by handing the
-	 * parent clock its current rate and forcing child propagation.
-	 */
-	clk_set_rate(clk, clk_get_rate(clk));
+int __init arch_clk_init(void)
+{
+	int i, ret = 0;
 
-	clk_put(clk);
+	for (i = 0; i < ARRAY_SIZE(clks); i++)
+		ret |= clk_register(clks[i]);
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
 
-	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+	if (!ret)
+		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+					   &div4_table);
+	if (!ret)
+		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
-	return 0;
+	return ret;
 }
 
-arch_initcall(sh7757_clk_init);
-
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-shx3.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-shx3.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/clock-shx3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/clock-shx3.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  *  Copyright (C) 2006-2007  Renesas Technology Corp.
  *  Copyright (C) 2006-2007  Renesas Solutions Corp.
- *  Copyright (C) 2006-2007  Paul Mundt
+ *  Copyright (C) 2006-2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -18,120 +18,179 @@
 #include <asm/clock.h>
 #include <asm/freq.h>
 
-static int ifc_divisors[] = { 1, 2, 4 ,6 };
-static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
-static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
-static int cfc_divisors[] = { 1, 1, 4, 6 };
-
-#define IFC_POS		28
-#define IFC_MSK		0x0003
-#define BFC_MSK		0x000f
-#define PFC_MSK		0x000f
-#define CFC_MSK		0x0003
-#define BFC_POS		16
-#define PFC_POS		0
-#define CFC_POS		20
-
-static void master_clk_init(struct clk *clk)
-{
-	clk->rate *= pfc_divisors[(__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK];
-}
-
-static struct clk_ops shx3_master_clk_ops = {
-	.init		= master_clk_init,
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+	.rate		= 16666666,
 };
 
-static unsigned long module_clk_recalc(struct clk *clk)
+static unsigned long pll_recalc(struct clk *clk)
 {
-	int idx = ((__raw_readl(FRQCR) >> PFC_POS) & PFC_MSK);
-	return clk->parent->rate / pfc_divisors[idx];
+	/* PLL1 has a fixed x72 multiplier.  */
+	return clk->parent->rate * 72;
 }
 
-static struct clk_ops shx3_module_clk_ops = {
-	.recalc		= module_clk_recalc,
+static struct clk_ops pll_clk_ops = {
+	.recalc		= pll_recalc,
 };
 
-static unsigned long bus_clk_recalc(struct clk *clk)
-{
-	int idx = ((__raw_readl(FRQCR) >> BFC_POS) & BFC_MSK);
-	return clk->parent->rate / bfc_divisors[idx];
-}
+static struct clk pll_clk = {
+	.ops		= &pll_clk_ops,
+	.parent		= &extal_clk,
+	.flags		= CLK_ENABLE_ON_INIT,
+};
 
-static struct clk_ops shx3_bus_clk_ops = {
-	.recalc		= bus_clk_recalc,
+static struct clk *clks[] = {
+	&extal_clk,
+	&pll_clk,
 };
 
-static unsigned long cpu_clk_recalc(struct clk *clk)
-{
-	int idx = ((__raw_readl(FRQCR) >> IFC_POS) & IFC_MSK);
-	return clk->parent->rate / ifc_divisors[idx];
-}
+static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18,
+			       24, 32, 36, 48 };
 
-static struct clk_ops shx3_cpu_clk_ops = {
-	.recalc		= cpu_clk_recalc,
+static struct clk_div_mult_table div4_div_mult_table = {
+	.divisors = div2,
+	.nr_divisors = ARRAY_SIZE(div2),
 };
 
-static struct clk_ops *shx3_clk_ops[] = {
-	&shx3_master_clk_ops,
-	&shx3_module_clk_ops,
-	&shx3_bus_clk_ops,
-	&shx3_cpu_clk_ops,
+static struct clk_div4_table div4_table = {
+	.div_mult_table = &div4_div_mult_table,
 };
 
-void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
-{
-	if (idx < ARRAY_SIZE(shx3_clk_ops))
-		*ops = shx3_clk_ops[idx];
-}
+enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_SHA, DIV4_P, DIV4_NR };
 
-static unsigned long shyway_clk_recalc(struct clk *clk)
-{
-	int idx = ((__raw_readl(FRQCR) >> CFC_POS) & CFC_MSK);
-	return clk->parent->rate / cfc_divisors[idx];
-}
+#define DIV4(_bit, _mask, _flags) \
+  SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags)
 
-static struct clk_ops shx3_shyway_clk_ops = {
-	.recalc		= shyway_clk_recalc,
+struct clk div4_clks[DIV4_NR] = {
+	[DIV4_P] = DIV4(0, 0x0f80, 0),
+	[DIV4_SHA] = DIV4(4, 0x0ff0, 0),
+	[DIV4_DDR] = DIV4(12, 0x000c, CLK_ENABLE_ON_INIT),
+	[DIV4_B] = DIV4(16, 0x0fe0, CLK_ENABLE_ON_INIT),
+	[DIV4_SH] = DIV4(20, 0x000c, CLK_ENABLE_ON_INIT),
+	[DIV4_I] = DIV4(28, 0x000e, CLK_ENABLE_ON_INIT),
 };
 
-static struct clk shx3_shyway_clk = {
-	.flags		= CLK_ENABLE_ON_INIT,
-	.ops		= &shx3_shyway_clk_ops,
-};
+#define MSTPCR0		0xffc00030
+#define MSTPCR1		0xffc00034
 
-/*
- * Additional SHx3-specific on-chip clocks that aren't already part of the
- * clock framework
- */
-static struct clk *shx3_onchip_clocks[] = {
-	&shx3_shyway_clk,
+enum { MSTP027, MSTP026, MSTP025, MSTP024,
+       MSTP009, MSTP008, MSTP003, MSTP002,
+       MSTP001, MSTP000, MSTP119, MSTP105,
+       MSTP104, MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+	/* MSTPCR0 */
+	[MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0),
+	[MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+	[MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+	[MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+	[MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+	[MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+	[MSTP003] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 3, 0),
+	[MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0),
+	[MSTP001] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 1, 0),
+	[MSTP000] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 0, 0),
+
+	/* MSTPCR1 */
+	[MSTP119] = SH_CLK_MSTP32(NULL, MSTPCR1, 19, 0),
+	[MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0),
+	[MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0),
 };
 
 #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
 
 static struct clk_lookup lookups[] = {
 	/* main clocks */
-	CLKDEV_CON_ID("shyway_clk", &shx3_shyway_clk),
+	CLKDEV_CON_ID("extal", &extal_clk),
+	CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+	/* DIV4 clocks */
+	CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+	CLKDEV_CON_ID("shywaya_clk", &div4_clks[DIV4_SHA]),
+	CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]),
+	CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+	CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]),
+	CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+
+	/* MSTP32 clocks */
+	{
+		/* SCIF3 */
+		.dev_id		= "sh-sci.3",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP027],
+	}, {
+		/* SCIF2 */
+		.dev_id		= "sh-sci.2",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP026],
+	}, {
+		/* SCIF1 */
+		.dev_id		= "sh-sci.1",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP025],
+	}, {
+		/* SCIF0 */
+		.dev_id		= "sh-sci.0",
+		.con_id		= "sci_fck",
+		.clk		= &mstp_clks[MSTP024],
+	},
+	CLKDEV_CON_ID("h8ex_fck", &mstp_clks[MSTP003]),
+	CLKDEV_CON_ID("csm_fck", &mstp_clks[MSTP002]),
+	CLKDEV_CON_ID("fe1_fck", &mstp_clks[MSTP001]),
+	CLKDEV_CON_ID("fe0_fck", &mstp_clks[MSTP000]),
+	{
+		/* TMU0 */
+		.dev_id		= "sh_tmu.0",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP008],
+	}, {
+		/* TMU1 */
+		.dev_id		= "sh_tmu.1",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP008],
+	}, {
+		/* TMU2 */
+		.dev_id		= "sh_tmu.2",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP008],
+	}, {
+		/* TMU3 */
+		.dev_id		= "sh_tmu.3",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP009],
+	}, {
+		/* TMU4 */
+		.dev_id		= "sh_tmu.4",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP009],
+	}, {
+		/* TMU5 */
+		.dev_id		= "sh_tmu.5",
+		.con_id		= "tmu_fck",
+		.clk		= &mstp_clks[MSTP009],
+	},
+	CLKDEV_CON_ID("hudi_fck", &mstp_clks[MSTP119]),
+	CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]),
+	CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]),
 };
 
 int __init arch_clk_init(void)
 {
-	struct clk *clk;
 	int i, ret = 0;
 
-	cpg_clk_init();
-
-	clk = clk_get(NULL, "master_clk");
-	for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
-		struct clk *clkp = shx3_onchip_clocks[i];
-
-		clkp->parent = clk;
-		ret |= clk_register(clkp);
-	}
-
-	clk_put(clk);
+	for (i = 0; i < ARRAY_SIZE(clks); i++)
+		ret |= clk_register(clks[i]);
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
 
-	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+	if (!ret)
+		ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+					   &div4_table);
+	if (!ret)
+		ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/intc-shx3.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/intc-shx3.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/intc-shx3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/intc-shx3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,34 @@
+/*
+ * Shared support for SH-X3 interrupt controllers.
+ *
+ *  Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/init.h>
+
+#define INTACK		0xfe4100b8
+#define INTACKCLR	0xfe4100bc
+#define INTC_USERIMASK	0xfe411000
+
+#ifdef CONFIG_INTC_BALANCING
+unsigned int irq_lookup(unsigned int irq)
+{
+	return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
+}
+
+void irq_finish(unsigned int irq)
+{
+	__raw_writel(irq2evt(irq), INTACKCLR);
+}
+#endif
+
+static int __init shx3_irq_setup(void)
+{
+	return register_intc_userimask(INTC_USERIMASK);
+}
+arch_initcall(shx3_irq_setup);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/Makefile linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,13 +8,13 @@
 obj-$(CONFIG_CPU_SUBTYPE_SH7770)	+= setup-sh7770.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)	+= setup-sh7780.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)	+= setup-sh7785.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7786)	+= setup-sh7786.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786)	+= setup-sh7786.o intc-shx3.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7343)	+= setup-sh7343.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7722)	+= setup-sh7722.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7723)	+= setup-sh7723.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7724)	+= setup-sh7724.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7366)	+= setup-sh7366.o
-obj-$(CONFIG_CPU_SUBTYPE_SHX3)		+= setup-shx3.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3)		+= setup-shx3.o intc-shx3.o
 
 # SMP setup
 smp-$(CONFIG_CPU_SHX3)			:= smp-shx3.o
@@ -40,6 +40,7 @@
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7757)	:= pinmux-sh7757.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)	:= pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)	:= pinmux-sh7786.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SHX3)	:= pinmux-shx3.o
 
 obj-y					+= $(clock-y)
 obj-$(CONFIG_SMP)			+= $(smp-y)
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/perf_event.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/perf_event.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * Performance events support for SH-4A performance counters
  *
- *  Copyright (C) 2009  Paul Mundt
+ *  Copyright (C) 2009, 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -22,7 +22,25 @@
 #define CCBR_CMDS	(1 << 1)
 #define CCBR_PPCE	(1 << 0)
 
+#ifdef CONFIG_CPU_SHX3
+/*
+ * The PMCAT location for SH-X3 CPUs was quietly moved, while the CCBR
+ * and PMCTR locations remains tentatively constant. This change remains
+ * wholly undocumented, and was simply found through trial and error.
+ *
+ * Early cuts of SH-X3 still appear to use the SH-X/SH-X2 locations, and
+ * it's unclear when this ceased to be the case. For now we always use
+ * the new location (if future parts keep up with this trend then
+ * scanning for them at runtime also remains a viable option.)
+ *
+ * The gap in the register space also suggests that there are other
+ * undocumented counters, so this will need to be revisited at a later
+ * point in time.
+ */
+#define PPC_PMCAT	0xfc100240
+#else
 #define PPC_PMCAT	0xfc100080
+#endif
 
 #define PMCAT_OVF3	(1 << 27)
 #define PMCAT_CNN3	(1 << 26)
@@ -241,7 +259,7 @@
 }
 
 static struct sh_pmu sh4a_pmu = {
-	.name		= "SH-4A",
+	.name		= "sh4a",
 	.num_events	= 2,
 	.event_map	= sh4a_event_map,
 	.max_events	= ARRAY_SIZE(sh4a_general_events),
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/pinmux-sh7757.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,11 +1,11 @@
 /*
- * SH7757 (A0 step) Pinmux
+ * SH7757 (B0 step) Pinmux
  *
- *  Copyright (C) 2009  Renesas Solutions Corp.
+ *  Copyright (C) 2009-2010  Renesas Solutions Corp.
  *
  *  Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
  *
- * Based on SH7757 Pinmux
+ * Based on SH7723 Pinmux
  *  Copyright (C) 2008  Magnus Damm
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -40,27 +40,27 @@
 	PTH3_DATA, PTH2_DATA, PTH1_DATA, PTH0_DATA,
 	PTI7_DATA, PTI6_DATA, PTI5_DATA, PTI4_DATA,
 	PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA,
-	PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+		   PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
 	PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA,
 	PTK7_DATA, PTK6_DATA, PTK5_DATA, PTK4_DATA,
 	PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA,
-	PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+		   PTL6_DATA, PTL5_DATA, PTL4_DATA,
 	PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA,
-	PTM6_DATA, PTM5_DATA, PTM4_DATA,
+	PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
 	PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA,
-	PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+		   PTN6_DATA, PTN5_DATA, PTN4_DATA,
 	PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA,
 	PTO7_DATA, PTO6_DATA, PTO5_DATA, PTO4_DATA,
 	PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA,
-	PTP6_DATA, PTP5_DATA, PTP4_DATA,
+	PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
 	PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA,
-	PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
+		   PTQ6_DATA, PTQ5_DATA, PTQ4_DATA,
 	PTQ3_DATA, PTQ2_DATA, PTQ1_DATA, PTQ0_DATA,
 	PTR7_DATA, PTR6_DATA, PTR5_DATA, PTR4_DATA,
 	PTR3_DATA, PTR2_DATA, PTR1_DATA, PTR0_DATA,
 	PTS7_DATA, PTS6_DATA, PTS5_DATA, PTS4_DATA,
 	PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA,
-	PTT5_DATA, PTT4_DATA,
+	PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
 	PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA,
 	PTU7_DATA, PTU6_DATA, PTU5_DATA, PTU4_DATA,
 	PTU3_DATA, PTU2_DATA, PTU1_DATA, PTU0_DATA,
@@ -95,27 +95,27 @@
 	PTH3_IN, PTH2_IN, PTH1_IN, PTH0_IN,
 	PTI7_IN, PTI6_IN, PTI5_IN, PTI4_IN,
 	PTI3_IN, PTI2_IN, PTI1_IN, PTI0_IN,
-	PTJ7_IN, PTJ6_IN, PTJ5_IN, PTJ4_IN,
+		 PTJ6_IN, PTJ5_IN, PTJ4_IN,
 	PTJ3_IN, PTJ2_IN, PTJ1_IN, PTJ0_IN,
 	PTK7_IN, PTK6_IN, PTK5_IN, PTK4_IN,
 	PTK3_IN, PTK2_IN, PTK1_IN, PTK0_IN,
-	PTL7_IN, PTL6_IN, PTL5_IN, PTL4_IN,
+		 PTL6_IN, PTL5_IN, PTL4_IN,
 	PTL3_IN, PTL2_IN, PTL1_IN, PTL0_IN,
-	PTM6_IN, PTM5_IN, PTM4_IN,
+	PTM7_IN, PTM6_IN, PTM5_IN, PTM4_IN,
 	PTM3_IN, PTM2_IN, PTM1_IN, PTM0_IN,
-	PTN7_IN, PTN6_IN, PTN5_IN, PTN4_IN,
+		 PTN6_IN, PTN5_IN, PTN4_IN,
 	PTN3_IN, PTN2_IN, PTN1_IN, PTN0_IN,
 	PTO7_IN, PTO6_IN, PTO5_IN, PTO4_IN,
 	PTO3_IN, PTO2_IN, PTO1_IN, PTO0_IN,
-	PTP6_IN, PTP5_IN, PTP4_IN,
+	PTP7_IN, PTP6_IN, PTP5_IN, PTP4_IN,
 	PTP3_IN, PTP2_IN, PTP1_IN, PTP0_IN,
-	PTQ6_IN, PTQ5_IN, PTQ4_IN,
+		 PTQ6_IN, PTQ5_IN, PTQ4_IN,
 	PTQ3_IN, PTQ2_IN, PTQ1_IN, PTQ0_IN,
 	PTR7_IN, PTR6_IN, PTR5_IN, PTR4_IN,
 	PTR3_IN, PTR2_IN, PTR1_IN, PTR0_IN,
 	PTS7_IN, PTS6_IN, PTS5_IN, PTS4_IN,
 	PTS3_IN, PTS2_IN, PTS1_IN, PTS0_IN,
-	PTT5_IN, PTT4_IN,
+	PTT7_IN, PTT6_IN, PTT5_IN, PTT4_IN,
 	PTT3_IN, PTT2_IN, PTT1_IN, PTT0_IN,
 	PTU7_IN, PTU6_IN, PTU5_IN, PTU4_IN,
 	PTU3_IN, PTU2_IN, PTU1_IN, PTU0_IN,
@@ -132,16 +132,43 @@
 	PINMUX_INPUT_END,
 
 	PINMUX_INPUT_PULLUP_BEGIN,
+	PTA7_IN_PU, PTA6_IN_PU, PTA5_IN_PU, PTA4_IN_PU,
+	PTA3_IN_PU, PTA2_IN_PU, PTA1_IN_PU, PTA0_IN_PU,
+	PTD7_IN_PU, PTD6_IN_PU, PTD5_IN_PU, PTD4_IN_PU,
+	PTD3_IN_PU, PTD2_IN_PU, PTD1_IN_PU, PTD0_IN_PU,
+	PTE7_IN_PU, PTE6_IN_PU, PTE5_IN_PU, PTE4_IN_PU,
+	PTE3_IN_PU, PTE2_IN_PU, PTE1_IN_PU, PTE0_IN_PU,
+	PTF7_IN_PU, PTF6_IN_PU, PTF5_IN_PU, PTF4_IN_PU,
+	PTF3_IN_PU, PTF2_IN_PU, PTF1_IN_PU, PTF0_IN_PU,
+	PTG7_IN_PU, PTG6_IN_PU,		    PTG4_IN_PU,
+	PTH7_IN_PU, PTH6_IN_PU, PTH5_IN_PU, PTH4_IN_PU,
+	PTH3_IN_PU, PTH2_IN_PU, PTH1_IN_PU, PTH0_IN_PU,
+	PTI7_IN_PU, PTI6_IN_PU,		    PTI4_IN_PU,
+	PTI3_IN_PU, PTI2_IN_PU, PTI1_IN_PU, PTI0_IN_PU,
+		    PTJ6_IN_PU, PTJ5_IN_PU, PTJ4_IN_PU,
+	PTJ3_IN_PU, PTJ2_IN_PU, PTJ1_IN_PU, PTJ0_IN_PU,
+	PTK7_IN_PU, PTK6_IN_PU, PTK5_IN_PU, PTK4_IN_PU,
+	PTK3_IN_PU, PTK2_IN_PU, PTK1_IN_PU, PTK0_IN_PU,
+		    PTL6_IN_PU, PTL5_IN_PU, PTL4_IN_PU,
+	PTL3_IN_PU, PTL2_IN_PU, PTL1_IN_PU, PTL0_IN_PU,
+	PTM7_IN_PU, PTM6_IN_PU, PTM5_IN_PU, PTM4_IN_PU,
+					    PTN4_IN_PU,
+	PTN3_IN_PU, PTN2_IN_PU, PTN1_IN_PU, PTN0_IN_PU,
+	PTO7_IN_PU, PTO6_IN_PU, PTO5_IN_PU, PTO4_IN_PU,
+	PTO3_IN_PU, PTO2_IN_PU, PTO1_IN_PU, PTO0_IN_PU,
+	PTT7_IN_PU, PTT6_IN_PU, PTT5_IN_PU, PTT4_IN_PU,
+	PTT3_IN_PU, PTT2_IN_PU, PTT1_IN_PU, PTT0_IN_PU,
 	PTU7_IN_PU, PTU6_IN_PU, PTU5_IN_PU, PTU4_IN_PU,
 	PTU3_IN_PU, PTU2_IN_PU, PTU1_IN_PU, PTU0_IN_PU,
 	PTV7_IN_PU, PTV6_IN_PU, PTV5_IN_PU, PTV4_IN_PU,
-	PTV3_IN_PU, PTV2_IN_PU, PTV1_IN_PU, PTV0_IN_PU,
-	PTW7_IN_PU, PTW6_IN_PU, PTW5_IN_PU, PTW4_IN_PU,
-	PTW3_IN_PU, PTW2_IN_PU, PTW1_IN_PU, PTW0_IN_PU,
+	PTV3_IN_PU, PTV2_IN_PU,
+				PTW1_IN_PU, PTW0_IN_PU,
 	PTX7_IN_PU, PTX6_IN_PU, PTX5_IN_PU, PTX4_IN_PU,
 	PTX3_IN_PU, PTX2_IN_PU, PTX1_IN_PU, PTX0_IN_PU,
 	PTY7_IN_PU, PTY6_IN_PU, PTY5_IN_PU, PTY4_IN_PU,
 	PTY3_IN_PU, PTY2_IN_PU, PTY1_IN_PU, PTY0_IN_PU,
+	PTZ7_IN_PU, PTZ6_IN_PU, PTZ5_IN_PU, PTZ4_IN_PU,
+	PTZ3_IN_PU, PTZ2_IN_PU, PTZ1_IN_PU, PTZ0_IN_PU,
 	PINMUX_INPUT_PULLUP_END,
 
 	PINMUX_OUTPUT_BEGIN,
@@ -163,27 +190,27 @@
 	PTH3_OUT, PTH2_OUT, PTH1_OUT, PTH0_OUT,
 	PTI7_OUT, PTI6_OUT, PTI5_OUT, PTI4_OUT,
 	PTI3_OUT, PTI2_OUT, PTI1_OUT, PTI0_OUT,
-	PTJ7_OUT, PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
+		  PTJ6_OUT, PTJ5_OUT, PTJ4_OUT,
 	PTJ3_OUT, PTJ2_OUT, PTJ1_OUT, PTJ0_OUT,
 	PTK7_OUT, PTK6_OUT, PTK5_OUT, PTK4_OUT,
 	PTK3_OUT, PTK2_OUT, PTK1_OUT, PTK0_OUT,
-	PTL7_OUT, PTL6_OUT, PTL5_OUT, PTL4_OUT,
+		  PTL6_OUT, PTL5_OUT, PTL4_OUT,
 	PTL3_OUT, PTL2_OUT, PTL1_OUT, PTL0_OUT,
-	PTM6_OUT, PTM5_OUT, PTM4_OUT,
+	PTM7_OUT, PTM6_OUT, PTM5_OUT, PTM4_OUT,
 	PTM3_OUT, PTM2_OUT, PTM1_OUT, PTM0_OUT,
-	PTN7_OUT, PTN6_OUT, PTN5_OUT, PTN4_OUT,
+		  PTN6_OUT, PTN5_OUT, PTN4_OUT,
 	PTN3_OUT, PTN2_OUT, PTN1_OUT, PTN0_OUT,
 	PTO7_OUT, PTO6_OUT, PTO5_OUT, PTO4_OUT,
 	PTO3_OUT, PTO2_OUT, PTO1_OUT, PTO0_OUT,
-	PTP6_OUT, PTP5_OUT, PTP4_OUT,
+	PTP7_OUT, PTP6_OUT, PTP5_OUT, PTP4_OUT,
 	PTP3_OUT, PTP2_OUT, PTP1_OUT, PTP0_OUT,
-	PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
+		  PTQ6_OUT, PTQ5_OUT, PTQ4_OUT,
 	PTQ3_OUT, PTQ2_OUT, PTQ1_OUT, PTQ0_OUT,
 	PTR7_OUT, PTR6_OUT, PTR5_OUT, PTR4_OUT,
 	PTR3_OUT, PTR2_OUT, PTR1_OUT, PTR0_OUT,
 	PTS7_OUT, PTS6_OUT, PTS5_OUT, PTS4_OUT,
 	PTS3_OUT, PTS2_OUT, PTS1_OUT, PTS0_OUT,
-	PTT5_OUT, PTT4_OUT,
+	PTT7_OUT, PTT6_OUT, PTT5_OUT, PTT4_OUT,
 	PTT3_OUT, PTT2_OUT, PTT1_OUT, PTT0_OUT,
 	PTU7_OUT, PTU6_OUT, PTU5_OUT, PTU4_OUT,
 	PTU3_OUT, PTU2_OUT, PTU1_OUT, PTU0_OUT,
@@ -218,27 +245,27 @@
 	PTH3_FN, PTH2_FN, PTH1_FN, PTH0_FN,
 	PTI7_FN, PTI6_FN, PTI5_FN, PTI4_FN,
 	PTI3_FN, PTI2_FN, PTI1_FN, PTI0_FN,
-	PTJ7_FN, PTJ6_FN, PTJ5_FN, PTJ4_FN,
+		 PTJ6_FN, PTJ5_FN, PTJ4_FN,
 	PTJ3_FN, PTJ2_FN, PTJ1_FN, PTJ0_FN,
 	PTK7_FN, PTK6_FN, PTK5_FN, PTK4_FN,
 	PTK3_FN, PTK2_FN, PTK1_FN, PTK0_FN,
-	PTL7_FN, PTL6_FN, PTL5_FN, PTL4_FN,
+		 PTL6_FN, PTL5_FN, PTL4_FN,
 	PTL3_FN, PTL2_FN, PTL1_FN, PTL0_FN,
-	PTM6_FN, PTM5_FN, PTM4_FN,
+	PTM7_FN, PTM6_FN, PTM5_FN, PTM4_FN,
 	PTM3_FN, PTM2_FN, PTM1_FN, PTM0_FN,
-	PTN7_FN, PTN6_FN, PTN5_FN, PTN4_FN,
+		 PTN6_FN, PTN5_FN, PTN4_FN,
 	PTN3_FN, PTN2_FN, PTN1_FN, PTN0_FN,
 	PTO7_FN, PTO6_FN, PTO5_FN, PTO4_FN,
 	PTO3_FN, PTO2_FN, PTO1_FN, PTO0_FN,
-	PTP6_FN, PTP5_FN, PTP4_FN,
+	PTP7_FN, PTP6_FN, PTP5_FN, PTP4_FN,
 	PTP3_FN, PTP2_FN, PTP1_FN, PTP0_FN,
-	PTQ6_FN, PTQ5_FN, PTQ4_FN,
+		 PTQ6_FN, PTQ5_FN, PTQ4_FN,
 	PTQ3_FN, PTQ2_FN, PTQ1_FN, PTQ0_FN,
 	PTR7_FN, PTR6_FN, PTR5_FN, PTR4_FN,
 	PTR3_FN, PTR2_FN, PTR1_FN, PTR0_FN,
 	PTS7_FN, PTS6_FN, PTS5_FN, PTS4_FN,
 	PTS3_FN, PTS2_FN, PTS1_FN, PTS0_FN,
-	PTT5_FN, PTT4_FN,
+	PTT7_FN, PTT6_FN, PTT5_FN, PTT4_FN,
 	PTT3_FN, PTT2_FN, PTT1_FN, PTT0_FN,
 	PTU7_FN, PTU6_FN, PTU5_FN, PTU4_FN,
 	PTU3_FN, PTU2_FN, PTU1_FN, PTU0_FN,
@@ -253,181 +280,248 @@
 	PTZ7_FN, PTZ6_FN, PTZ5_FN, PTZ4_FN,
 	PTZ3_FN, PTZ2_FN, PTZ1_FN, PTZ0_FN,
 
-	PS0_15_FN1, PS0_15_FN3,
-	PS0_14_FN1, PS0_14_FN3,
-	PS0_13_FN1, PS0_13_FN3,
-	PS0_12_FN1, PS0_12_FN3,
+	PS0_15_FN1, PS0_15_FN2,
+	PS0_14_FN1, PS0_14_FN2,
+	PS0_13_FN1, PS0_13_FN2,
+	PS0_12_FN1, PS0_12_FN2,
+	PS0_11_FN1, PS0_11_FN2,
+	PS0_10_FN1, PS0_10_FN2,
+	PS0_9_FN1, PS0_9_FN2,
+	PS0_8_FN1, PS0_8_FN2,
 	PS0_7_FN1, PS0_7_FN2,
 	PS0_6_FN1, PS0_6_FN2,
 	PS0_5_FN1, PS0_5_FN2,
 	PS0_4_FN1, PS0_4_FN2,
 	PS0_3_FN1, PS0_3_FN2,
 	PS0_2_FN1, PS0_2_FN2,
-	PS0_1_FN1, PS0_1_FN2,
 
-	PS1_7_FN1, PS1_7_FN3,
-	PS1_6_FN1, PS1_6_FN3,
+	PS1_10_FN1, PS1_10_FN2,
+	PS1_9_FN1, PS1_9_FN2,
+	PS1_8_FN1, PS1_8_FN2,
+	PS1_2_FN1, PS1_2_FN2,
 
-	PS2_13_FN1, PS2_13_FN3,
-	PS2_12_FN1, PS2_12_FN3,
-	PS2_1_FN1, PS2_1_FN2,
-	PS2_0_FN1, PS2_0_FN2,
+	PS2_13_FN1, PS2_13_FN2,
+	PS2_12_FN1, PS2_12_FN2,
+	PS2_7_FN1, PS2_7_FN2,
+	PS2_6_FN1, PS2_6_FN2,
+	PS2_5_FN1, PS2_5_FN2,
+	PS2_4_FN1, PS2_4_FN2,
+	PS2_2_FN1, PS2_2_FN2,
+
+	PS3_15_FN1, PS3_15_FN2,
+	PS3_14_FN1, PS3_14_FN2,
+	PS3_13_FN1, PS3_13_FN2,
+	PS3_12_FN1, PS3_12_FN2,
+	PS3_11_FN1, PS3_11_FN2,
+	PS3_10_FN1, PS3_10_FN2,
+	PS3_9_FN1, PS3_9_FN2,
+	PS3_8_FN1, PS3_8_FN2,
+	PS3_7_FN1, PS3_7_FN2,
+	PS3_2_FN1, PS3_2_FN2,
+	PS3_1_FN1, PS3_1_FN2,
 
-	PS4_15_FN1, PS4_15_FN2,
 	PS4_14_FN1, PS4_14_FN2,
 	PS4_13_FN1, PS4_13_FN2,
 	PS4_12_FN1, PS4_12_FN2,
-	PS4_11_FN1, PS4_11_FN2,
 	PS4_10_FN1, PS4_10_FN2,
 	PS4_9_FN1, PS4_9_FN2,
+	PS4_8_FN1, PS4_8_FN2,
+	PS4_4_FN1, PS4_4_FN2,
 	PS4_3_FN1, PS4_3_FN2,
 	PS4_2_FN1, PS4_2_FN2,
 	PS4_1_FN1, PS4_1_FN2,
 	PS4_0_FN1, PS4_0_FN2,
 
+	PS5_11_FN1, PS5_11_FN2,
+	PS5_10_FN1, PS5_10_FN2,
 	PS5_9_FN1, PS5_9_FN2,
 	PS5_8_FN1, PS5_8_FN2,
 	PS5_7_FN1, PS5_7_FN2,
 	PS5_6_FN1, PS5_6_FN2,
 	PS5_5_FN1, PS5_5_FN2,
 	PS5_4_FN1, PS5_4_FN2,
+	PS5_3_FN1, PS5_3_FN2,
+	PS5_2_FN1, PS5_2_FN2,
 
-	/* AN15 to 8 : EVENT15 to 8 */
-	PS6_7_FN_AN, PS6_7_FN_EV,
-	PS6_6_FN_AN, PS6_6_FN_EV,
-	PS6_5_FN_AN, PS6_5_FN_EV,
-	PS6_4_FN_AN, PS6_4_FN_EV,
-	PS6_3_FN_AN, PS6_3_FN_EV,
-	PS6_2_FN_AN, PS6_2_FN_EV,
-	PS6_1_FN_AN, PS6_1_FN_EV,
-	PS6_0_FN_AN, PS6_0_FN_EV,
+	PS6_15_FN1, PS6_15_FN2,
+	PS6_14_FN1, PS6_14_FN2,
+	PS6_13_FN1, PS6_13_FN2,
+	PS6_12_FN1, PS6_12_FN2,
+	PS6_11_FN1, PS6_11_FN2,
+	PS6_10_FN1, PS6_10_FN2,
+	PS6_9_FN1, PS6_9_FN2,
+	PS6_8_FN1, PS6_8_FN2,
+	PS6_7_FN1, PS6_7_FN2,
+	PS6_6_FN1, PS6_6_FN2,
+	PS6_5_FN1, PS6_5_FN2,
+	PS6_4_FN1, PS6_4_FN2,
+	PS6_3_FN1, PS6_3_FN2,
+	PS6_2_FN1, PS6_2_FN2,
+	PS6_1_FN1, PS6_1_FN2,
+	PS6_0_FN1, PS6_0_FN2,
+
+	PS7_15_FN1, PS7_15_FN2,
+	PS7_14_FN1, PS7_14_FN2,
+	PS7_13_FN1, PS7_13_FN2,
+	PS7_12_FN1, PS7_12_FN2,
+	PS7_11_FN1, PS7_11_FN2,
+	PS7_10_FN1, PS7_10_FN2,
+	PS7_9_FN1, PS7_9_FN2,
+	PS7_8_FN1, PS7_8_FN2,
+	PS7_7_FN1, PS7_7_FN2,
+	PS7_6_FN1, PS7_6_FN2,
+	PS7_5_FN1, PS7_5_FN2,
+	PS7_4_FN1, PS7_4_FN2,
 
+	PS8_15_FN1, PS8_15_FN2,
+	PS8_14_FN1, PS8_14_FN2,
+	PS8_13_FN1, PS8_13_FN2,
+	PS8_12_FN1, PS8_12_FN2,
+	PS8_11_FN1, PS8_11_FN2,
+	PS8_10_FN1, PS8_10_FN2,
+	PS8_9_FN1, PS8_9_FN2,
+	PS8_8_FN1, PS8_8_FN2,
 	PINMUX_FUNCTION_END,
 
 	PINMUX_MARK_BEGIN,
-	/* PTA (mobule: LBSC, CPG, LPC) */
+	/* PTA (mobule: LBSC, RGMII) */
 	BS_MARK,	RDWR_MARK,	WE1_MARK,	RDY_MARK,
-	MD10_MARK,	MD9_MARK,	MD8_MARK,
-	LGPIO7_MARK,	LGPIO6_MARK,	LGPIO5_MARK,	LGPIO4_MARK,
-	LGPIO3_MARK,	LGPIO2_MARK,	LGPIO1_MARK,	LGPIO0_MARK,
-
-	/* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-	D15_MARK,	D14_MARK,	D13_MARK,	D12_MARK,
-	D11_MARK,	D10_MARK,	D9_MARK,	D8_MARK,
 	ET0_MDC_MARK,	ET0_MDIO_MARK,	ET1_MDC_MARK,	ET1_MDIO_MARK,
-	SIM_D_MARK,	SIM_CLK_MARK,	SIM_RST_MARK,
-	WPSZ1_MARK,	WPSZ0_MARK,	FWID_MARK,	FLSHSZ_MARK,
-	LPC_SPIEN_MARK,	BASEL_MARK,
 
-	/* PTC (mobule: SD) */
-	SD_WP_MARK,	SD_CD_MARK,	SD_CLK_MARK,	SD_CMD_MARK,
-	SD_D3_MARK,	SD_D2_MARK,	SD_D1_MARK,	SD_D0_MARK,
+	/* PTB (mobule: INTC, ONFI, TMU) */
+	IRQ15_MARK,	IRQ14_MARK,	IRQ13_MARK,	IRQ12_MARK,
+	IRQ11_MARK,	IRQ10_MARK,	IRQ9_MARK,	IRQ8_MARK,
+	ON_NRE_MARK,	ON_NWE_MARK,	ON_NWP_MARK,	ON_NCE0_MARK,
+	ON_R_B0_MARK,	ON_ALE_MARK,	ON_CLE_MARK,	TCLK_MARK,
 
-	/* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+	/* PTC (mobule: IRQ, PWMU) */
 	IRQ7_MARK,	IRQ6_MARK,	IRQ5_MARK,	IRQ4_MARK,
 	IRQ3_MARK,	IRQ2_MARK,	IRQ1_MARK,	IRQ0_MARK,
-	MD6_MARK,	MD5_MARK,	MD3_MARK,	MD2_MARK,
-	MD1_MARK,	MD0_MARK,	ADTRG1_MARK,	ADTRG0_MARK,
+	PWMU0_MARK,	PWMU1_MARK,	PWMU2_MARK,	PWMU3_MARK,
+	PWMU4_MARK,	PWMU5_MARK,
 
-	/* PTE (mobule: EtherC) */
-	ET0_CRS_DV_MARK,	ET0_TXD1_MARK,
-	ET0_TXD0_MARK,		ET0_TX_EN_MARK,
-	ET0_REF_CLK_MARK,	ET0_RXD1_MARK,
-	ET0_RXD0_MARK,		ET0_RX_ER_MARK,
+	/* PTD (mobule: SPI0, DMAC) */
+	SP0_MOSI_MARK,	SP0_MISO_MARK,	SP0_SCK_MARK,	SP0_SCK_FB_MARK,
+	SP0_SS0_MARK,	SP0_SS1_MARK,	SP0_SS2_MARK,	SP0_SS3_MARK,
+	DREQ0_MARK,	DACK0_MARK,	TEND0_MARK,
 
-	/* PTF (mobule: EtherC) */
-	ET1_CRS_DV_MARK,	ET1_TXD1_MARK,
-	ET1_TXD0_MARK,		ET1_TX_EN_MARK,
-	ET1_REF_CLK_MARK,	ET1_RXD1_MARK,
-	ET1_RXD0_MARK,		ET1_RX_ER_MARK,
+	/* PTE (mobule: RMII) */
+	RMII0_CRS_DV_MARK,	RMII0_TXD1_MARK,
+	RMII0_TXD0_MARK,	RMII0_TXEN_MARK,
+	RMII0_REFCLK_MARK,	RMII0_RXD1_MARK,
+	RMII0_RXD0_MARK,	RMII0_RX_ER_MARK,
 
-	/* PTG (mobule: SYSTEM, PWMX, LPC) */
-	STATUS0_MARK,	STATUS1_MARK,
-	PWX0_MARK,	PWX1_MARK,	PWX2_MARK,	PWX3_MARK,
-	SERIRQ_MARK,	CLKRUN_MARK,	LPCPD_MARK,	LDRQ_MARK,
+	/* PTF (mobule: RMII, SerMux) */
+	RMII1_CRS_DV_MARK,	RMII1_TXD1_MARK,
+	RMII1_TXD0_MARK,	RMII1_TXEN_MARK,
+	RMII1_REFCLK_MARK,	RMII1_RXD1_MARK,
+	RMII1_RXD0_MARK,	RMII1_RX_ER_MARK,
+	RAC_RI_MARK,
 
-	/* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-	TCLK_MARK,	RXD4_MARK,	TXD4_MARK,
+	/* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+	BOOTFMS_MARK,	BOOTWP_MARK,	A25_MARK,	A24_MARK,
+	SERIRQ_MARK,	WDTOVF_MARK,	LPCPD_MARK,	LDRQ_MARK,
+	MMCCLK_MARK,	MMCCMD_MARK,
+
+	/* PTH (mobule: SPI1, LPC, DMAC, ADC) */
 	SP1_MOSI_MARK,	SP1_MISO_MARK,	SP1_SCK_MARK,	SP1_SCK_FB_MARK,
-	SP1_SS0_MARK,	SP1_SS1_MARK,	SP0_SS1_MARK,
+	SP1_SS0_MARK,	SP1_SS1_MARK,	WP_MARK,	FMS0_MARK,
+	TEND1_MARK,	DREQ1_MARK,	DACK1_MARK,	ADTRG1_MARK,
+	ADTRG0_MARK,
 
-	/* PTI (mobule: INTC) */
-	IRQ15_MARK,	IRQ14_MARK,	IRQ13_MARK,	IRQ12_MARK,
-	IRQ11_MARK,	IRQ10_MARK,	IRQ9_MARK,	IRQ8_MARK,
+	/* PTI (mobule: LBSC, SDHI) */
+	D15_MARK,	D14_MARK,	D13_MARK,	D12_MARK,
+	D11_MARK,	D10_MARK,	D9_MARK,	D8_MARK,
+	SD_WP_MARK,	SD_CD_MARK,	SD_CLK_MARK,	SD_CMD_MARK,
+	SD_D3_MARK,	SD_D2_MARK,	SD_D1_MARK,	SD_D0_MARK,
 
-	/* PTJ (mobule: SCIF234, SERMUX) */
-	RXD3_MARK,	TXD3_MARK,	RXD2_MARK,	TXD2_MARK,
-	COM1_TXD_MARK,	COM1_RXD_MARK,	COM1_RTS_MARK,	COM1_CTS_MARK,
+	/* PTJ (mobule: SCIF234) */
+	RTS3_MARK,	CTS3_MARK,	TXD3_MARK,	RXD3_MARK,
+	RTS4_MARK,	RXD4_MARK,	TXD4_MARK,
 
-	/* PTK (mobule: SERMUX) */
+	/* PTK (mobule: SERMUX, LBSC, SCIF) */
 	COM2_TXD_MARK,	COM2_RXD_MARK,	COM2_RTS_MARK,	COM2_CTS_MARK,
-	COM2_DTR_MARK,	COM2_DSR_MARK,	COM2_DCD_MARK,	COM2_RI_MARK,
+	COM2_DTR_MARK,	COM2_DSR_MARK,	COM2_DCD_MARK,	CLKOUT_MARK,
+	SCK2_MARK,	SCK4_MARK,	SCK3_MARK,
 
-	/* PTL (mobule: SERMUX) */
-	RAC_TXD_MARK,	RAC_RXD_MARK,	RAC_RTS_MARK,	RAC_CTS_MARK,
-	RAC_DTR_MARK,	RAC_DSR_MARK,	RAC_DCD_MARK,	RAC_RI_MARK,
+	/* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
+	RAC_RXD_MARK,	RAC_RTS_MARK,	RAC_CTS_MARK,	RAC_DTR_MARK,
+	RAC_DSR_MARK,	RAC_DCD_MARK,	RAC_TXD_MARK,	RXD2_MARK,
+	CS5_MARK,	CS6_MARK,	AUDSYNC_MARK,	AUDCK_MARK,
+	TXD2_MARK,
 
-	/* PTM (mobule: IIC, LPC) */
+	/* PTM (mobule: LBSC, IIC) */
+	CS4_MARK,	RD_MARK,	WE0_MARK,	CS0_MARK,
 	SDA6_MARK,	SCL6_MARK,	SDA7_MARK,	SCL7_MARK,
-	WP_MARK,	FMS0_MARK,	FMS1_MARK,
 
-	/* PTN (mobule: SCIF234, EVC) */
-	SCK2_MARK,	RTS4_MARK,	RTS3_MARK,	RTS2_MARK,
-	CTS4_MARK,	CTS3_MARK,	CTS2_MARK,
-	EVENT7_MARK,	EVENT6_MARK,	EVENT5_MARK,	EVENT4_MARK,
-	EVENT3_MARK,	EVENT2_MARK,	EVENT1_MARK,	EVENT0_MARK,
-
-	/* PTO (mobule: SGPIO) */
-	SGPIO0_CLK_MARK,	SGPIO0_LOAD_MARK,
-	SGPIO0_DI_MARK,		SGPIO0_DO_MARK,
-	SGPIO1_CLK_MARK,	SGPIO1_LOAD_MARK,
-	SGPIO1_DI_MARK,		SGPIO1_DO_MARK,
+	/* PTN (mobule: USB, JMC, SGPIO, WDT) */
+	VBUS_EN_MARK,	VBUS_OC_MARK,	JMCTCK_MARK,	JMCTMS_MARK,
+	JMCTDO_MARK,	JMCTDI_MARK,	JMCTRST_MARK,
+	SGPIO1_CLK_MARK,	SGPIO1_LOAD_MARK,	SGPIO1_DI_MARK,
+	SGPIO1_DO_MARK,		SUB_CLKIN_MARK,
 
-	/* PTP (mobule: JMC, SCIF234) */
-	JMCTCK_MARK,	JMCTMS_MARK,	JMCTDO_MARK,	JMCTDI_MARK,
-	JMCRST_MARK,	SCK4_MARK,	SCK3_MARK,
+	/* PTO (mobule: SGPIO, SerMux) */
+	SGPIO0_CLK_MARK,	SGPIO0_LOAD_MARK,	SGPIO0_DI_MARK,
+	SGPIO0_DO_MARK,		SGPIO2_CLK_MARK,	SGPIO2_LOAD_MARK,
+	SGPIO2_DI_MARK,		SGPIO2_DO_MARK,
+	COM1_TXD_MARK,	COM1_RXD_MARK,	COM1_RTS_MARK,	COM1_CTS_MARK,
 
 	/* PTQ (mobule: LPC) */
 	LAD3_MARK,	LAD2_MARK,	LAD1_MARK,	LAD0_MARK,
 	LFRAME_MARK,	LRESET_MARK,	LCLK_MARK,
 
 	/* PTR (mobule: GRA, IIC) */
-	DDC3_MARK,	DDC2_MARK,
-	SDA8_MARK,	SCL8_MARK,	SDA2_MARK,	SCL2_MARK,
+	DDC3_MARK,	DDC2_MARK,	SDA2_MARK,	SCL2_MARK,
 	SDA1_MARK,	SCL1_MARK,	SDA0_MARK,	SCL0_MARK,
+	SDA8_MARK,	SCL8_MARK,
 
 	/* PTS (mobule: GRA, IIC) */
-	DDC1_MARK,	DDC0_MARK,
-	SDA9_MARK,	SCL9_MARK,	SDA5_MARK,	SCL5_MARK,
+	DDC1_MARK,	DDC0_MARK,	SDA5_MARK,	SCL5_MARK,
 	SDA4_MARK,	SCL4_MARK,	SDA3_MARK,	SCL3_MARK,
+	SDA9_MARK,	SCL9_MARK,
 
-	/* PTT (mobule: SYSTEM, PWMX) */
-	AUDSYNC_MARK,		AUDCK_MARK,
-	AUDATA3_MARK,		AUDATA2_MARK,
-	AUDATA1_MARK,		AUDATA0_MARK,
-	PWX7_MARK,	PWX6_MARK,	PWX5_MARK,	PWX4_MARK,
+	/* PTT (mobule: PWMX, AUD) */
+	PWMX7_MARK,	PWMX6_MARK,	PWMX5_MARK,	PWMX4_MARK,
+	PWMX3_MARK,	PWMX2_MARK,	PWMX1_MARK,	PWMX0_MARK,
+	AUDATA3_MARK,	AUDATA2_MARK,	AUDATA1_MARK,	AUDATA0_MARK,
+	STATUS1_MARK,	STATUS0_MARK,
 
-	/* PTU (mobule: LBSC, DMAC) */
-	CS6_MARK,	CS5_MARK,	CS4_MARK,	CS0_MARK,
-	RD_MARK,	WE0_MARK,	A25_MARK,	A24_MARK,
-	DREQ0_MARK,	DACK0_MARK,
+	/* PTU (mobule: LPC, APM) */
+	LGPIO7_MARK,	LGPIO6_MARK,	LGPIO5_MARK,	LGPIO4_MARK,
+	LGPIO3_MARK,	LGPIO2_MARK,	LGPIO1_MARK,	LGPIO0_MARK,
+	APMONCTL_O_MARK,	APMPWBTOUT_O_MARK,	APMSCI_O_MARK,
+	APMVDDON_MARK,	APMSLPBTN_MARK,	APMPWRBTN_MARK,	APMS5N_MARK,
+	APMS3N_MARK,
 
-	/* PTV (mobule: LBSC, DMAC) */
+	/* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
 	A23_MARK,	A22_MARK,	A21_MARK,	A20_MARK,
 	A19_MARK,	A18_MARK,	A17_MARK,	A16_MARK,
-	TEND0_MARK,	DREQ1_MARK,	DACK1_MARK,	TEND1_MARK,
+	COM2_RI_MARK,		R_SPI_MOSI_MARK,	R_SPI_MISO_MARK,
+	R_SPI_RSPCK_MARK,	R_SPI_SSL0_MARK,	R_SPI_SSL1_MARK,
+	EVENT7_MARK,	EVENT6_MARK,	VBIOS_DI_MARK,	VBIOS_DO_MARK,
+	VBIOS_CLK_MARK,	VBIOS_CS_MARK,
 
-	/* PTW (mobule: LBSC) */
+	/* PTW (mobule: LBSC, EVC, SCIF) */
 	A15_MARK,	A14_MARK,	A13_MARK,	A12_MARK,
 	A11_MARK,	A10_MARK,	A9_MARK,	A8_MARK,
+	EVENT5_MARK,	EVENT4_MARK,	EVENT3_MARK,	EVENT2_MARK,
+	EVENT1_MARK,	EVENT0_MARK,	CTS4_MARK,	CTS2_MARK,
 
-	/* PTX (mobule: LBSC) */
+	/* PTX (mobule: LBSC, SCIF, SIM) */
 	A7_MARK,	A6_MARK,	A5_MARK,	A4_MARK,
 	A3_MARK,	A2_MARK,	A1_MARK,	A0_MARK,
+	RTS2_MARK,	SIM_D_MARK,	SIM_CLK_MARK,	SIM_RST_MARK,
 
 	/* PTY (mobule: LBSC) */
 	D7_MARK,	D6_MARK,	D5_MARK,	D4_MARK,
 	D3_MARK,	D2_MARK,	D1_MARK,	D0_MARK,
+
+	/* PTZ (mobule: eMMC, ONFI) */
+	MMCDAT7_MARK,	MMCDAT6_MARK,	MMCDAT5_MARK,	MMCDAT4_MARK,
+	MMCDAT3_MARK,	MMCDAT2_MARK,	MMCDAT1_MARK,	MMCDAT0_MARK,
+	ON_DQ7_MARK,	ON_DQ6_MARK,	ON_DQ5_MARK,	ON_DQ4_MARK,
+	ON_DQ3_MARK,	ON_DQ2_MARK,	ON_DQ1_MARK,	ON_DQ0_MARK,
+
 	PINMUX_MARK_END,
 };
 
@@ -473,6 +567,8 @@
 	PINMUX_DATA(PTD0_DATA, PTD0_IN, PTD0_OUT),
 
 	/* PTE GPIO */
+	PINMUX_DATA(PTE7_DATA, PTE7_IN, PTE7_OUT),
+	PINMUX_DATA(PTE6_DATA, PTE6_IN, PTE6_OUT),
 	PINMUX_DATA(PTE5_DATA, PTE5_IN, PTE5_OUT),
 	PINMUX_DATA(PTE4_DATA, PTE4_IN, PTE4_OUT),
 	PINMUX_DATA(PTE3_DATA, PTE3_IN, PTE3_OUT),
@@ -521,7 +617,6 @@
 	PINMUX_DATA(PTI0_DATA, PTI0_IN, PTI0_OUT),
 
 	/* PTJ GPIO */
-	PINMUX_DATA(PTJ7_DATA, PTJ7_IN, PTJ7_OUT),
 	PINMUX_DATA(PTJ6_DATA, PTJ6_IN, PTJ6_OUT),
 	PINMUX_DATA(PTJ5_DATA, PTJ5_IN, PTJ5_OUT),
 	PINMUX_DATA(PTJ4_DATA, PTJ4_IN, PTJ4_OUT),
@@ -541,7 +636,6 @@
 	PINMUX_DATA(PTK0_DATA, PTK0_IN, PTK0_OUT),
 
 	/* PTL GPIO */
-	PINMUX_DATA(PTL7_DATA, PTL7_IN, PTL7_OUT),
 	PINMUX_DATA(PTL6_DATA, PTL6_IN, PTL6_OUT),
 	PINMUX_DATA(PTL5_DATA, PTL5_IN, PTL5_OUT),
 	PINMUX_DATA(PTL4_DATA, PTL4_IN, PTL4_OUT),
@@ -560,7 +654,6 @@
 	PINMUX_DATA(PTM0_DATA, PTM0_IN, PTM0_OUT),
 
 	/* PTN GPIO */
-	PINMUX_DATA(PTN7_DATA, PTN7_IN, PTN7_OUT),
 	PINMUX_DATA(PTN6_DATA, PTN6_IN, PTN6_OUT),
 	PINMUX_DATA(PTN5_DATA, PTN5_IN, PTN5_OUT),
 	PINMUX_DATA(PTN4_DATA, PTN4_IN, PTN4_OUT),
@@ -609,6 +702,8 @@
 	PINMUX_DATA(PTS0_DATA, PTS0_IN, PTS0_OUT),
 
 	/* PTT GPIO */
+	PINMUX_DATA(PTT7_DATA, PTT7_IN, PTT7_OUT),
+	PINMUX_DATA(PTT6_DATA, PTT6_IN, PTT6_OUT),
 	PINMUX_DATA(PTT5_DATA, PTT5_IN, PTT5_OUT),
 	PINMUX_DATA(PTT4_DATA, PTT4_IN, PTT4_OUT),
 	PINMUX_DATA(PTT3_DATA, PTT3_IN, PTT3_OUT),
@@ -677,186 +772,204 @@
 	PINMUX_DATA(PTZ0_DATA, PTZ0_IN, PTZ0_OUT),
 
 	/* PTA FN */
-	PINMUX_DATA(BS_MARK, PS0_15_FN1, PTA7_FN),
-	PINMUX_DATA(LGPIO7_MARK, PS0_15_FN3, PTA7_FN),
-	PINMUX_DATA(RDWR_MARK, PS0_14_FN1, PTA6_FN),
-	PINMUX_DATA(LGPIO6_MARK, PS0_14_FN3, PTA6_FN),
-	PINMUX_DATA(WE1_MARK, PS0_13_FN1, PTA5_FN),
-	PINMUX_DATA(LGPIO5_MARK, PS0_13_FN3, PTA5_FN),
-	PINMUX_DATA(RDY_MARK, PS0_12_FN1, PTA4_FN),
-	PINMUX_DATA(LGPIO4_MARK, PS0_12_FN3, PTA4_FN),
-	PINMUX_DATA(LGPIO3_MARK, PTA3_FN),
-	PINMUX_DATA(LGPIO2_MARK, PTA2_FN),
-	PINMUX_DATA(LGPIO1_MARK, PTA1_FN),
-	PINMUX_DATA(LGPIO0_MARK, PTA0_FN),
+	PINMUX_DATA(BS_MARK, PTA7_FN),
+	PINMUX_DATA(RDWR_MARK, PTA6_FN),
+	PINMUX_DATA(WE1_MARK, PTA5_FN),
+	PINMUX_DATA(RDY_MARK, PTA4_FN),
+	PINMUX_DATA(ET0_MDC_MARK, PTA3_FN),
+	PINMUX_DATA(ET0_MDIO_MARK, PTA2_FN),
+	PINMUX_DATA(ET1_MDC_MARK, PTA1_FN),
+	PINMUX_DATA(ET1_MDIO_MARK, PTA0_FN),
 
 	/* PTB FN */
-	PINMUX_DATA(D15_MARK, PS0_7_FN1, PTB7_FN),
-	PINMUX_DATA(ET0_MDC_MARK, PS0_7_FN2, PTB7_FN),
-	PINMUX_DATA(D14_MARK, PS0_6_FN1, PTB6_FN),
-	PINMUX_DATA(ET0_MDIO_MARK, PS0_6_FN2, PTB6_FN),
-	PINMUX_DATA(D13_MARK, PS0_5_FN1, PTB5_FN),
-	PINMUX_DATA(ET1_MDC_MARK, PS0_5_FN2, PTB5_FN),
-	PINMUX_DATA(D12_MARK, PS0_4_FN1, PTB4_FN),
-	PINMUX_DATA(ET1_MDIO_MARK, PS0_4_FN2, PTB4_FN),
-	PINMUX_DATA(D11_MARK, PS0_3_FN1, PTB3_FN),
-	PINMUX_DATA(SIM_D_MARK, PS0_3_FN2, PTB3_FN),
-	PINMUX_DATA(D10_MARK, PS0_2_FN1, PTB2_FN),
-	PINMUX_DATA(SIM_CLK_MARK, PS0_2_FN2, PTB2_FN),
-	PINMUX_DATA(D9_MARK, PS0_1_FN1, PTB1_FN),
-	PINMUX_DATA(SIM_RST_MARK, PS0_1_FN2, PTB1_FN),
-	PINMUX_DATA(D8_MARK, PTB0_FN),
+	PINMUX_DATA(IRQ15_MARK, PS0_15_FN1, PTB7_FN),
+	PINMUX_DATA(ON_NRE_MARK, PS0_15_FN2, PTB7_FN),
+	PINMUX_DATA(IRQ14_MARK, PS0_14_FN1, PTB6_FN),
+	PINMUX_DATA(ON_NWE_MARK, PS0_14_FN2, PTB6_FN),
+	PINMUX_DATA(IRQ13_MARK, PS0_13_FN1, PTB5_FN),
+	PINMUX_DATA(ON_NWP_MARK, PS0_13_FN2, PTB5_FN),
+	PINMUX_DATA(IRQ12_MARK, PS0_12_FN1, PTB4_FN),
+	PINMUX_DATA(ON_NCE0_MARK, PS0_12_FN2, PTB4_FN),
+	PINMUX_DATA(IRQ11_MARK, PS0_11_FN1, PTB3_FN),
+	PINMUX_DATA(ON_R_B0_MARK, PS0_11_FN2, PTB3_FN),
+	PINMUX_DATA(IRQ10_MARK, PS0_10_FN1, PTB2_FN),
+	PINMUX_DATA(ON_ALE_MARK, PS0_10_FN2, PTB2_FN),
+	PINMUX_DATA(IRQ9_MARK, PS0_9_FN1, PTB1_FN),
+	PINMUX_DATA(ON_CLE_MARK, PS0_9_FN2, PTB1_FN),
+	PINMUX_DATA(IRQ8_MARK, PS0_8_FN1, PTB0_FN),
+	PINMUX_DATA(TCLK_MARK, PS0_8_FN2, PTB0_FN),
 
 	/* PTC FN */
-	PINMUX_DATA(SD_WP_MARK, PTC7_FN),
-	PINMUX_DATA(SD_CD_MARK, PTC6_FN),
-	PINMUX_DATA(SD_CLK_MARK, PTC5_FN),
-	PINMUX_DATA(SD_CMD_MARK, PTC4_FN),
-	PINMUX_DATA(SD_D3_MARK, PTC3_FN),
-	PINMUX_DATA(SD_D2_MARK, PTC2_FN),
-	PINMUX_DATA(SD_D1_MARK, PTC1_FN),
-	PINMUX_DATA(SD_D0_MARK, PTC0_FN),
+	PINMUX_DATA(IRQ7_MARK, PS0_7_FN1, PTC7_FN),
+	PINMUX_DATA(PWMU0_MARK, PS0_7_FN2, PTC7_FN),
+	PINMUX_DATA(IRQ6_MARK, PS0_6_FN1, PTC6_FN),
+	PINMUX_DATA(PWMU1_MARK, PS0_6_FN2, PTC6_FN),
+	PINMUX_DATA(IRQ5_MARK, PS0_5_FN1, PTC5_FN),
+	PINMUX_DATA(PWMU2_MARK, PS0_5_FN2, PTC5_FN),
+	PINMUX_DATA(IRQ4_MARK, PS0_4_FN1, PTC5_FN),
+	PINMUX_DATA(PWMU3_MARK, PS0_4_FN2, PTC4_FN),
+	PINMUX_DATA(IRQ3_MARK, PS0_3_FN1, PTC3_FN),
+	PINMUX_DATA(PWMU4_MARK, PS0_3_FN2, PTC3_FN),
+	PINMUX_DATA(IRQ2_MARK, PS0_2_FN1, PTC2_FN),
+	PINMUX_DATA(PWMU5_MARK, PS0_2_FN2, PTC2_FN),
+	PINMUX_DATA(IRQ1_MARK, PTC1_FN),
+	PINMUX_DATA(IRQ0_MARK, PTC0_FN),
 
 	/* PTD FN */
-	PINMUX_DATA(IRQ7_MARK, PS1_7_FN1, PTD7_FN),
-	PINMUX_DATA(ADTRG1_MARK, PS1_7_FN3, PTD7_FN),
-	PINMUX_DATA(IRQ6_MARK, PS1_6_FN1, PTD6_FN),
-	PINMUX_DATA(ADTRG0_MARK, PS1_6_FN3, PTD6_FN),
-	PINMUX_DATA(IRQ5_MARK, PTD5_FN),
-	PINMUX_DATA(IRQ4_MARK, PTD4_FN),
-	PINMUX_DATA(IRQ3_MARK, PTD3_FN),
-	PINMUX_DATA(IRQ2_MARK, PTD2_FN),
-	PINMUX_DATA(IRQ1_MARK, PTD1_FN),
-	PINMUX_DATA(IRQ0_MARK, PTD0_FN),
+	PINMUX_DATA(SP0_MOSI_MARK, PTD7_FN),
+	PINMUX_DATA(SP0_MISO_MARK, PTD6_FN),
+	PINMUX_DATA(SP0_SCK_MARK, PTD5_FN),
+	PINMUX_DATA(SP0_SCK_FB_MARK, PTD4_FN),
+	PINMUX_DATA(SP0_SS0_MARK, PTD3_FN),
+	PINMUX_DATA(SP0_SS1_MARK, PS1_10_FN1, PTD2_FN),
+	PINMUX_DATA(DREQ0_MARK, PS1_10_FN2, PTD2_FN),
+	PINMUX_DATA(SP0_SS2_MARK, PS1_9_FN1, PTD1_FN),
+	PINMUX_DATA(DACK0_MARK, PS1_9_FN2, PTD1_FN),
+	PINMUX_DATA(SP0_SS3_MARK, PS1_8_FN1, PTD0_FN),
+	PINMUX_DATA(TEND0_MARK, PS1_8_FN2, PTD0_FN),
 
 	/* PTE FN */
-	PINMUX_DATA(ET0_CRS_DV_MARK, PTE7_FN),
-	PINMUX_DATA(ET0_TXD1_MARK, PTE6_FN),
-	PINMUX_DATA(ET0_TXD0_MARK, PTE5_FN),
-	PINMUX_DATA(ET0_TX_EN_MARK, PTE4_FN),
-	PINMUX_DATA(ET0_REF_CLK_MARK, PTE3_FN),
-	PINMUX_DATA(ET0_RXD1_MARK, PTE2_FN),
-	PINMUX_DATA(ET0_RXD0_MARK, PTE1_FN),
-	PINMUX_DATA(ET0_RX_ER_MARK, PTE0_FN),
+	PINMUX_DATA(RMII0_CRS_DV_MARK, PTE7_FN),
+	PINMUX_DATA(RMII0_TXD1_MARK, PTE6_FN),
+	PINMUX_DATA(RMII0_TXD0_MARK, PTE5_FN),
+	PINMUX_DATA(RMII0_TXEN_MARK, PTE4_FN),
+	PINMUX_DATA(RMII0_REFCLK_MARK, PTE3_FN),
+	PINMUX_DATA(RMII0_RXD1_MARK, PTE2_FN),
+	PINMUX_DATA(RMII0_RXD0_MARK, PTE1_FN),
+	PINMUX_DATA(RMII0_RX_ER_MARK, PTE0_FN),
 
 	/* PTF FN */
-	PINMUX_DATA(ET1_CRS_DV_MARK, PTF7_FN),
-	PINMUX_DATA(ET1_TXD1_MARK, PTF6_FN),
-	PINMUX_DATA(ET1_TXD0_MARK, PTF5_FN),
-	PINMUX_DATA(ET1_TX_EN_MARK, PTF4_FN),
-	PINMUX_DATA(ET1_REF_CLK_MARK, PTF3_FN),
-	PINMUX_DATA(ET1_RXD1_MARK, PTF2_FN),
-	PINMUX_DATA(ET1_RXD0_MARK, PTF1_FN),
-	PINMUX_DATA(ET1_RX_ER_MARK, PTF0_FN),
+	PINMUX_DATA(RMII1_CRS_DV_MARK, PTF7_FN),
+	PINMUX_DATA(RMII1_TXD1_MARK, PTF6_FN),
+	PINMUX_DATA(RMII1_TXD0_MARK, PTF5_FN),
+	PINMUX_DATA(RMII1_TXEN_MARK, PTF4_FN),
+	PINMUX_DATA(RMII1_REFCLK_MARK, PTF3_FN),
+	PINMUX_DATA(RMII1_RXD1_MARK, PS1_2_FN1, PTF2_FN),
+	PINMUX_DATA(RAC_RI_MARK, PS1_2_FN2, PTF2_FN),
+	PINMUX_DATA(RMII1_RXD0_MARK, PTF1_FN),
+	PINMUX_DATA(RMII1_RX_ER_MARK, PTF0_FN),
 
 	/* PTG FN */
-	PINMUX_DATA(PWX0_MARK, PTG7_FN),
-	PINMUX_DATA(PWX1_MARK, PTG6_FN),
-	PINMUX_DATA(STATUS0_MARK, PS2_13_FN1, PTG5_FN),
-	PINMUX_DATA(PWX2_MARK, PS2_13_FN3, PTG5_FN),
-	PINMUX_DATA(STATUS1_MARK, PS2_12_FN1, PTG4_FN),
-	PINMUX_DATA(PWX3_MARK, PS2_12_FN3, PTG4_FN),
+	PINMUX_DATA(BOOTFMS_MARK, PTG7_FN),
+	PINMUX_DATA(BOOTWP_MARK, PTG6_FN),
+	PINMUX_DATA(A25_MARK, PS2_13_FN1, PTG5_FN),
+	PINMUX_DATA(MMCCLK_MARK, PS2_13_FN2, PTG5_FN),
+	PINMUX_DATA(A24_MARK, PS2_12_FN1, PTG4_FN),
+	PINMUX_DATA(MMCCMD_MARK, PS2_12_FN2, PTG4_FN),
 	PINMUX_DATA(SERIRQ_MARK, PTG3_FN),
-	PINMUX_DATA(CLKRUN_MARK, PTG2_FN),
+	PINMUX_DATA(WDTOVF_MARK, PTG2_FN),
 	PINMUX_DATA(LPCPD_MARK, PTG1_FN),
 	PINMUX_DATA(LDRQ_MARK, PTG0_FN),
 
 	/* PTH FN */
-	PINMUX_DATA(SP1_MOSI_MARK, PTH7_FN),
-	PINMUX_DATA(SP1_MISO_MARK, PTH6_FN),
-	PINMUX_DATA(SP1_SCK_MARK, PTH5_FN),
-	PINMUX_DATA(SP1_SCK_FB_MARK, PTH4_FN),
+	PINMUX_DATA(SP1_MOSI_MARK, PS2_7_FN1, PTH7_FN),
+	PINMUX_DATA(TEND1_MARK, PS2_7_FN2, PTH7_FN),
+	PINMUX_DATA(SP1_MISO_MARK, PS2_6_FN1, PTH6_FN),
+	PINMUX_DATA(DREQ1_MARK, PS2_6_FN2, PTH6_FN),
+	PINMUX_DATA(SP1_SCK_MARK, PS2_5_FN1, PTH5_FN),
+	PINMUX_DATA(DACK1_MARK, PS2_5_FN2, PTH5_FN),
+	PINMUX_DATA(SP1_SCK_FB_MARK, PS2_4_FN1, PTH4_FN),
+	PINMUX_DATA(ADTRG1_MARK, PS2_4_FN2, PTH4_FN),
 	PINMUX_DATA(SP1_SS0_MARK, PTH3_FN),
-	PINMUX_DATA(TCLK_MARK, PTH2_FN),
-	PINMUX_DATA(RXD4_MARK, PS2_1_FN1, PTH1_FN),
-	PINMUX_DATA(SP1_SS1_MARK, PS2_1_FN2, PTH1_FN),
-	PINMUX_DATA(TXD4_MARK, PS2_0_FN1, PTH0_FN),
-	PINMUX_DATA(SP0_SS1_MARK, PS2_0_FN2, PTH0_FN),
+	PINMUX_DATA(SP1_SS1_MARK, PS2_2_FN1, PTH2_FN),
+	PINMUX_DATA(ADTRG0_MARK, PS2_2_FN2, PTH2_FN),
+	PINMUX_DATA(WP_MARK, PTH1_FN),
+	PINMUX_DATA(FMS0_MARK, PTH0_FN),
 
 	/* PTI FN */
-	PINMUX_DATA(IRQ15_MARK, PTI7_FN),
-	PINMUX_DATA(IRQ14_MARK, PTI6_FN),
-	PINMUX_DATA(IRQ13_MARK, PTI5_FN),
-	PINMUX_DATA(IRQ12_MARK, PTI4_FN),
-	PINMUX_DATA(IRQ11_MARK, PTI3_FN),
-	PINMUX_DATA(IRQ10_MARK, PTI2_FN),
-	PINMUX_DATA(IRQ9_MARK, PTI1_FN),
-	PINMUX_DATA(IRQ8_MARK, PTI0_FN),
+	PINMUX_DATA(D15_MARK, PS3_15_FN1, PTI7_FN),
+	PINMUX_DATA(SD_WP_MARK, PS3_15_FN2, PTI7_FN),
+	PINMUX_DATA(D14_MARK, PS3_14_FN1, PTI6_FN),
+	PINMUX_DATA(SD_CD_MARK, PS3_14_FN2, PTI6_FN),
+	PINMUX_DATA(D13_MARK, PS3_13_FN1, PTI5_FN),
+	PINMUX_DATA(SD_CLK_MARK, PS3_13_FN2, PTI5_FN),
+	PINMUX_DATA(D12_MARK, PS3_12_FN1, PTI4_FN),
+	PINMUX_DATA(SD_CMD_MARK, PS3_12_FN2, PTI4_FN),
+	PINMUX_DATA(D11_MARK, PS3_11_FN1, PTI3_FN),
+	PINMUX_DATA(SD_D3_MARK, PS3_11_FN2, PTI3_FN),
+	PINMUX_DATA(D10_MARK, PS3_10_FN1, PTI2_FN),
+	PINMUX_DATA(SD_D2_MARK, PS3_10_FN2, PTI2_FN),
+	PINMUX_DATA(D9_MARK, PS3_9_FN1, PTI1_FN),
+	PINMUX_DATA(SD_D1_MARK, PS3_9_FN2, PTI1_FN),
+	PINMUX_DATA(D8_MARK, PS3_8_FN1, PTI0_FN),
+	PINMUX_DATA(SD_D0_MARK, PS3_8_FN2, PTI0_FN),
 
 	/* PTJ FN */
-	PINMUX_DATA(RXD3_MARK, PTJ7_FN),
-	PINMUX_DATA(TXD3_MARK, PTJ6_FN),
-	PINMUX_DATA(RXD2_MARK, PTJ5_FN),
-	PINMUX_DATA(TXD2_MARK, PTJ4_FN),
-	PINMUX_DATA(COM1_TXD_MARK, PTJ3_FN),
-	PINMUX_DATA(COM1_RXD_MARK, PTJ2_FN),
-	PINMUX_DATA(COM1_RTS_MARK, PTJ1_FN),
-	PINMUX_DATA(COM1_CTS_MARK, PTJ0_FN),
+	PINMUX_DATA(RTS3_MARK, PTJ6_FN),
+	PINMUX_DATA(CTS3_MARK, PTJ5_FN),
+	PINMUX_DATA(TXD3_MARK, PTJ4_FN),
+	PINMUX_DATA(RXD3_MARK, PTJ3_FN),
+	PINMUX_DATA(RTS4_MARK, PTJ2_FN),
+	PINMUX_DATA(RXD4_MARK, PTJ1_FN),
+	PINMUX_DATA(TXD4_MARK, PTJ0_FN),
 
 	/* PTK FN */
-	PINMUX_DATA(COM2_TXD_MARK, PTK7_FN),
+	PINMUX_DATA(COM2_TXD_MARK, PS3_7_FN1, PTK7_FN),
+	PINMUX_DATA(SCK2_MARK, PS3_7_FN2, PTK7_FN),
 	PINMUX_DATA(COM2_RXD_MARK, PTK6_FN),
 	PINMUX_DATA(COM2_RTS_MARK, PTK5_FN),
 	PINMUX_DATA(COM2_CTS_MARK, PTK4_FN),
 	PINMUX_DATA(COM2_DTR_MARK, PTK3_FN),
-	PINMUX_DATA(COM2_DSR_MARK, PTK2_FN),
-	PINMUX_DATA(COM2_DCD_MARK, PTK1_FN),
-	PINMUX_DATA(COM2_RI_MARK, PTK0_FN),
+	PINMUX_DATA(COM2_DSR_MARK, PS3_2_FN1, PTK2_FN),
+	PINMUX_DATA(SCK4_MARK, PS3_2_FN2, PTK2_FN),
+	PINMUX_DATA(COM2_DCD_MARK, PS3_1_FN1, PTK1_FN),
+	PINMUX_DATA(SCK3_MARK, PS3_1_FN2, PTK1_FN),
+	PINMUX_DATA(CLKOUT_MARK, PTK0_FN),
 
 	/* PTL FN */
-	PINMUX_DATA(RAC_TXD_MARK, PTL7_FN),
-	PINMUX_DATA(RAC_RXD_MARK, PTL6_FN),
-	PINMUX_DATA(RAC_RTS_MARK, PTL5_FN),
-	PINMUX_DATA(RAC_CTS_MARK, PTL4_FN),
+	PINMUX_DATA(RAC_RXD_MARK, PS4_14_FN1, PTL6_FN),
+	PINMUX_DATA(RXD2_MARK, PS4_14_FN2, PTL6_FN),
+	PINMUX_DATA(RAC_RTS_MARK, PS4_13_FN1, PTL5_FN),
+	PINMUX_DATA(CS5_MARK, PS4_13_FN2, PTL5_FN),
+	PINMUX_DATA(RAC_CTS_MARK, PS4_12_FN1, PTL4_FN),
+	PINMUX_DATA(CS6_MARK, PS4_12_FN2, PTL4_FN),
 	PINMUX_DATA(RAC_DTR_MARK, PTL3_FN),
-	PINMUX_DATA(RAC_DSR_MARK, PTL2_FN),
-	PINMUX_DATA(RAC_DCD_MARK, PTL1_FN),
-	PINMUX_DATA(RAC_RI_MARK, PTL0_FN),
+	PINMUX_DATA(RAC_DSR_MARK, PS4_10_FN1, PTL2_FN),
+	PINMUX_DATA(AUDSYNC_MARK, PS4_10_FN2, PTL2_FN),
+	PINMUX_DATA(RAC_DCD_MARK, PS4_9_FN1, PTL1_FN),
+	PINMUX_DATA(AUDCK_MARK, PS4_9_FN2, PTL1_FN),
+	PINMUX_DATA(RAC_TXD_MARK, PS4_8_FN1, PTL0_FN),
+	PINMUX_DATA(TXD2_MARK, PS4_8_FN1, PTL0_FN),
 
 	/* PTM FN */
-	PINMUX_DATA(WP_MARK, PTM6_FN),
-	PINMUX_DATA(FMS0_MARK, PTM5_FN),
-	PINMUX_DATA(FMS1_MARK, PTM4_FN),
+	PINMUX_DATA(CS4_MARK, PTM7_FN),
+	PINMUX_DATA(RD_MARK, PTM6_FN),
+	PINMUX_DATA(WE0_MARK, PTM7_FN),
+	PINMUX_DATA(CS0_MARK, PTM4_FN),
 	PINMUX_DATA(SDA6_MARK, PTM3_FN),
 	PINMUX_DATA(SCL6_MARK, PTM2_FN),
 	PINMUX_DATA(SDA7_MARK, PTM1_FN),
 	PINMUX_DATA(SCL7_MARK, PTM0_FN),
 
 	/* PTN FN */
-	PINMUX_DATA(SCK2_MARK, PS4_15_FN1, PTN7_FN),
-	PINMUX_DATA(EVENT7_MARK, PS4_15_FN2, PTN7_FN),
-	PINMUX_DATA(RTS4_MARK, PS4_14_FN1, PTN6_FN),
-	PINMUX_DATA(EVENT6_MARK, PS4_14_FN2, PTN6_FN),
-	PINMUX_DATA(RTS3_MARK, PS4_13_FN1, PTN5_FN),
-	PINMUX_DATA(EVENT5_MARK, PS4_13_FN2, PTN5_FN),
-	PINMUX_DATA(RTS2_MARK, PS4_12_FN1, PTN4_FN),
-	PINMUX_DATA(EVENT4_MARK, PS4_12_FN2, PTN4_FN),
-	PINMUX_DATA(CTS4_MARK, PS4_11_FN1, PTN3_FN),
-	PINMUX_DATA(EVENT3_MARK, PS4_11_FN2, PTN3_FN),
-	PINMUX_DATA(CTS3_MARK, PS4_10_FN1, PTN2_FN),
-	PINMUX_DATA(EVENT2_MARK, PS4_10_FN2, PTN2_FN),
-	PINMUX_DATA(CTS2_MARK, PS4_9_FN1, PTN1_FN),
-	PINMUX_DATA(EVENT1_MARK, PS4_9_FN2, PTN1_FN),
-	PINMUX_DATA(EVENT0_MARK, PTN0_FN),
+	PINMUX_DATA(VBUS_EN_MARK, PTN6_FN),
+	PINMUX_DATA(VBUS_OC_MARK, PTN5_FN),
+	PINMUX_DATA(JMCTCK_MARK, PS4_4_FN1, PTN4_FN),
+	PINMUX_DATA(SGPIO1_CLK_MARK, PS4_4_FN2, PTN4_FN),
+	PINMUX_DATA(JMCTMS_MARK, PS4_3_FN1, PTN5_FN),
+	PINMUX_DATA(SGPIO1_LOAD_MARK, PS4_3_FN2, PTN5_FN),
+	PINMUX_DATA(JMCTDO_MARK, PS4_2_FN1, PTN2_FN),
+	PINMUX_DATA(SGPIO1_DO_MARK, PS4_2_FN2, PTN2_FN),
+	PINMUX_DATA(JMCTDI_MARK, PS4_1_FN1, PTN1_FN),
+	PINMUX_DATA(SGPIO1_DI_MARK, PS4_1_FN2, PTN1_FN),
+	PINMUX_DATA(JMCTRST_MARK, PS4_0_FN1, PTN0_FN),
+	PINMUX_DATA(SUB_CLKIN_MARK, PS4_0_FN2, PTN0_FN),
 
 	/* PTO FN */
 	PINMUX_DATA(SGPIO0_CLK_MARK, PTO7_FN),
 	PINMUX_DATA(SGPIO0_LOAD_MARK, PTO6_FN),
 	PINMUX_DATA(SGPIO0_DI_MARK, PTO5_FN),
 	PINMUX_DATA(SGPIO0_DO_MARK, PTO4_FN),
-	PINMUX_DATA(SGPIO1_CLK_MARK, PTO3_FN),
-	PINMUX_DATA(SGPIO1_LOAD_MARK, PTO2_FN),
-	PINMUX_DATA(SGPIO1_DI_MARK, PTO1_FN),
-	PINMUX_DATA(SGPIO1_DO_MARK, PTO0_FN),
+	PINMUX_DATA(SGPIO2_CLK_MARK, PS5_11_FN1, PTO3_FN),
+	PINMUX_DATA(COM1_TXD_MARK, PS5_11_FN2, PTO3_FN),
+	PINMUX_DATA(SGPIO2_LOAD_MARK, PS5_10_FN1, PTO2_FN),
+	PINMUX_DATA(COM1_RXD_MARK, PS5_10_FN2, PTO2_FN),
+	PINMUX_DATA(SGPIO2_DI_MARK, PS5_9_FN1, PTO1_FN),
+	PINMUX_DATA(COM1_RTS_MARK, PS5_9_FN2, PTO1_FN),
+	PINMUX_DATA(SGPIO2_DO_MARK, PS5_8_FN1, PTO0_FN),
+	PINMUX_DATA(COM1_CTS_MARK, PS5_8_FN2, PTO0_FN),
 
 	/* PTP FN */
-	PINMUX_DATA(JMCTCK_MARK, PTP6_FN),
-	PINMUX_DATA(JMCTMS_MARK, PTP5_FN),
-	PINMUX_DATA(JMCTDO_MARK, PTP4_FN),
-	PINMUX_DATA(JMCTDI_MARK, PTP3_FN),
-	PINMUX_DATA(JMCRST_MARK, PTP2_FN),
-	PINMUX_DATA(SCK4_MARK, PTP1_FN),
-	PINMUX_DATA(SCK3_MARK, PTP0_FN),
 
 	/* PTQ FN */
 	PINMUX_DATA(LAD3_MARK, PTQ6_FN),
@@ -864,8 +977,8 @@
 	PINMUX_DATA(LAD1_MARK, PTQ4_FN),
 	PINMUX_DATA(LAD0_MARK, PTQ3_FN),
 	PINMUX_DATA(LFRAME_MARK, PTQ2_FN),
-	PINMUX_DATA(SCK4_MARK, PTQ1_FN),
-	PINMUX_DATA(SCK3_MARK, PTQ0_FN),
+	PINMUX_DATA(LRESET_MARK, PTQ1_FN),
+	PINMUX_DATA(LCLK_MARK, PTQ0_FN),
 
 	/* PTR FN */
 	PINMUX_DATA(SDA8_MARK, PTR7_FN),	/* DDC3? */
@@ -888,58 +1001,84 @@
 	PINMUX_DATA(SCL3_MARK, PTS0_FN),
 
 	/* PTT FN */
-	PINMUX_DATA(AUDSYNC_MARK, PTS5_FN),
-	PINMUX_DATA(AUDCK_MARK, PTS4_FN),
-	PINMUX_DATA(AUDATA3_MARK, PS4_3_FN1, PTS3_FN),
-	PINMUX_DATA(PWX7_MARK, PS4_3_FN2, PTS3_FN),
-	PINMUX_DATA(AUDATA2_MARK, PS4_2_FN1, PTS2_FN),
-	PINMUX_DATA(PWX6_MARK, PS4_2_FN2, PTS2_FN),
-	PINMUX_DATA(AUDATA1_MARK, PS4_1_FN1, PTS1_FN),
-	PINMUX_DATA(PWX5_MARK, PS4_1_FN2, PTS1_FN),
-	PINMUX_DATA(AUDATA0_MARK, PS4_0_FN1, PTS0_FN),
-	PINMUX_DATA(PWX4_MARK, PS4_0_FN2, PTS0_FN),
+	PINMUX_DATA(PWMX7_MARK, PS5_7_FN1, PTT7_FN),
+	PINMUX_DATA(AUDATA3_MARK, PS5_7_FN2, PTT7_FN),
+	PINMUX_DATA(PWMX6_MARK, PS5_6_FN1, PTT6_FN),
+	PINMUX_DATA(AUDATA2_MARK, PS5_6_FN2, PTT6_FN),
+	PINMUX_DATA(PWMX5_MARK, PS5_5_FN1, PTT5_FN),
+	PINMUX_DATA(AUDATA1_MARK, PS5_5_FN2, PTT5_FN),
+	PINMUX_DATA(PWMX4_MARK, PS5_4_FN1, PTT4_FN),
+	PINMUX_DATA(AUDATA0_MARK, PS5_4_FN2, PTT4_FN),
+	PINMUX_DATA(PWMX3_MARK, PS5_3_FN1, PTT3_FN),
+	PINMUX_DATA(STATUS1_MARK, PS5_3_FN2, PTT3_FN),
+	PINMUX_DATA(PWMX2_MARK, PS5_2_FN1, PTT2_FN),
+	PINMUX_DATA(STATUS0_MARK, PS5_2_FN2, PTT2_FN),
+	PINMUX_DATA(PWMX1_MARK, PTT1_FN),
+	PINMUX_DATA(PWMX0_MARK, PTT0_FN),
 
 	/* PTU FN */
-	PINMUX_DATA(CS6_MARK, PTU7_FN),
-	PINMUX_DATA(CS5_MARK, PTU6_FN),
-	PINMUX_DATA(CS4_MARK, PTU5_FN),
-	PINMUX_DATA(CS0_MARK, PTU4_FN),
-	PINMUX_DATA(RD_MARK, PTU3_FN),
-	PINMUX_DATA(WE0_MARK, PTU2_FN),
-	PINMUX_DATA(A25_MARK, PS5_9_FN1, PTU1_FN),
-	PINMUX_DATA(DREQ0_MARK, PS5_9_FN2, PTU1_FN),
-	PINMUX_DATA(A24_MARK, PS5_8_FN1, PTU0_FN),
-	PINMUX_DATA(DACK0_MARK, PS5_8_FN2, PTU0_FN),
+	PINMUX_DATA(LGPIO7_MARK, PS6_15_FN1, PTU7_FN),
+	PINMUX_DATA(APMONCTL_O_MARK, PS6_15_FN2, PTU7_FN),
+	PINMUX_DATA(LGPIO6_MARK, PS6_14_FN1, PTU6_FN),
+	PINMUX_DATA(APMPWBTOUT_O_MARK, PS6_14_FN2, PTU6_FN),
+	PINMUX_DATA(LGPIO5_MARK, PS6_13_FN1, PTU5_FN),
+	PINMUX_DATA(APMSCI_O_MARK, PS6_13_FN2, PTU5_FN),
+	PINMUX_DATA(LGPIO4_MARK, PS6_12_FN1, PTU4_FN),
+	PINMUX_DATA(APMVDDON_MARK, PS6_12_FN2, PTU4_FN),
+	PINMUX_DATA(LGPIO3_MARK, PS6_11_FN1, PTU3_FN),
+	PINMUX_DATA(APMSLPBTN_MARK, PS6_11_FN2, PTU3_FN),
+	PINMUX_DATA(LGPIO2_MARK, PS6_10_FN1, PTU2_FN),
+	PINMUX_DATA(APMPWRBTN_MARK, PS6_10_FN2, PTU2_FN),
+	PINMUX_DATA(LGPIO1_MARK, PS6_9_FN1, PTU1_FN),
+	PINMUX_DATA(APMS5N_MARK, PS6_9_FN2, PTU1_FN),
+	PINMUX_DATA(LGPIO0_MARK, PS6_8_FN1, PTU0_FN),
+	PINMUX_DATA(APMS3N_MARK, PS6_8_FN2, PTU0_FN),
 
 	/* PTV FN */
-	PINMUX_DATA(A23_MARK, PS5_7_FN1, PTV7_FN),
-	PINMUX_DATA(TEND0_MARK, PS5_7_FN2, PTV7_FN),
-	PINMUX_DATA(A22_MARK, PS5_6_FN1, PTV6_FN),
-	PINMUX_DATA(DREQ1_MARK, PS5_6_FN2, PTV6_FN),
-	PINMUX_DATA(A21_MARK, PS5_5_FN1, PTV5_FN),
-	PINMUX_DATA(DACK1_MARK, PS5_5_FN2, PTV5_FN),
-	PINMUX_DATA(A20_MARK, PS5_4_FN1, PTV4_FN),
-	PINMUX_DATA(TEND1_MARK, PS5_4_FN2, PTV4_FN),
-	PINMUX_DATA(A19_MARK, PTV3_FN),
-	PINMUX_DATA(A18_MARK, PTV2_FN),
-	PINMUX_DATA(A17_MARK, PTV1_FN),
-	PINMUX_DATA(A16_MARK, PTV0_FN),
+	PINMUX_DATA(A23_MARK, PS6_7_FN1, PTV7_FN),
+	PINMUX_DATA(COM2_RI_MARK, PS6_7_FN2, PTV7_FN),
+	PINMUX_DATA(A22_MARK, PS6_6_FN1, PTV6_FN),
+	PINMUX_DATA(R_SPI_MOSI_MARK, PS6_6_FN2, PTV6_FN),
+	PINMUX_DATA(A21_MARK, PS6_5_FN1, PTV5_FN),
+	PINMUX_DATA(R_SPI_MISO_MARK, PS6_5_FN2, PTV5_FN),
+	PINMUX_DATA(A20_MARK, PS6_4_FN1, PTV4_FN),
+	PINMUX_DATA(R_SPI_RSPCK_MARK, PS6_4_FN2, PTV4_FN),
+	PINMUX_DATA(A19_MARK, PS6_3_FN1, PTV3_FN),
+	PINMUX_DATA(R_SPI_SSL0_MARK, PS6_3_FN2, PTV3_FN),
+	PINMUX_DATA(A18_MARK, PS6_2_FN1, PTV2_FN),
+	PINMUX_DATA(R_SPI_SSL1_MARK, PS6_2_FN2, PTV2_FN),
+	PINMUX_DATA(A17_MARK, PS6_1_FN1, PTV1_FN),
+	PINMUX_DATA(EVENT7_MARK, PS6_1_FN2, PTV1_FN),
+	PINMUX_DATA(A16_MARK, PS6_0_FN1, PTV0_FN),
+	PINMUX_DATA(EVENT6_MARK, PS6_0_FN1, PTV0_FN),
 
 	/* PTW FN */
-	PINMUX_DATA(A15_MARK, PTW7_FN),
-	PINMUX_DATA(A14_MARK, PTW6_FN),
-	PINMUX_DATA(A13_MARK, PTW5_FN),
-	PINMUX_DATA(A12_MARK, PTW4_FN),
-	PINMUX_DATA(A11_MARK, PTW3_FN),
-	PINMUX_DATA(A10_MARK, PTW2_FN),
-	PINMUX_DATA(A9_MARK, PTW1_FN),
-	PINMUX_DATA(A8_MARK, PTW0_FN),
+	PINMUX_DATA(A15_MARK, PS7_15_FN1, PTW7_FN),
+	PINMUX_DATA(EVENT5_MARK, PS7_15_FN2, PTW7_FN),
+	PINMUX_DATA(A14_MARK, PS7_14_FN1, PTW6_FN),
+	PINMUX_DATA(EVENT4_MARK, PS7_14_FN2, PTW6_FN),
+	PINMUX_DATA(A13_MARK, PS7_13_FN1, PTW5_FN),
+	PINMUX_DATA(EVENT3_MARK, PS7_13_FN2, PTW5_FN),
+	PINMUX_DATA(A12_MARK, PS7_12_FN1, PTW4_FN),
+	PINMUX_DATA(EVENT2_MARK, PS7_12_FN2, PTW4_FN),
+	PINMUX_DATA(A11_MARK, PS7_11_FN1, PTW3_FN),
+	PINMUX_DATA(EVENT1_MARK, PS7_11_FN2, PTW3_FN),
+	PINMUX_DATA(A10_MARK, PS7_10_FN1, PTW2_FN),
+	PINMUX_DATA(EVENT0_MARK, PS7_10_FN2, PTW2_FN),
+	PINMUX_DATA(A9_MARK, PS7_9_FN1, PTW1_FN),
+	PINMUX_DATA(CTS4_MARK, PS7_9_FN2, PTW1_FN),
+	PINMUX_DATA(A8_MARK, PS7_8_FN1, PTW0_FN),
+	PINMUX_DATA(CTS2_MARK, PS7_8_FN2, PTW0_FN),
 
 	/* PTX FN */
-	PINMUX_DATA(A7_MARK, PTX7_FN),
-	PINMUX_DATA(A6_MARK, PTX6_FN),
-	PINMUX_DATA(A5_MARK, PTX5_FN),
-	PINMUX_DATA(A4_MARK, PTX4_FN),
+	PINMUX_DATA(A7_MARK, PS7_7_FN1, PTX7_FN),
+	PINMUX_DATA(RTS2_MARK, PS7_7_FN2, PTX7_FN),
+	PINMUX_DATA(A6_MARK, PS7_6_FN1, PTX6_FN),
+	PINMUX_DATA(SIM_D_MARK, PS7_6_FN2, PTX6_FN),
+	PINMUX_DATA(A5_MARK, PS7_5_FN1, PTX5_FN),
+	PINMUX_DATA(SIM_CLK_MARK, PS7_5_FN2, PTX5_FN),
+	PINMUX_DATA(A4_MARK, PS7_4_FN1, PTX4_FN),
+	PINMUX_DATA(SIM_RST_MARK, PS7_4_FN2, PTX4_FN),
 	PINMUX_DATA(A3_MARK, PTX3_FN),
 	PINMUX_DATA(A2_MARK, PTX2_FN),
 	PINMUX_DATA(A1_MARK, PTX1_FN),
@@ -954,6 +1093,24 @@
 	PINMUX_DATA(D2_MARK, PTY2_FN),
 	PINMUX_DATA(D1_MARK, PTY1_FN),
 	PINMUX_DATA(D0_MARK, PTY0_FN),
+
+	/* PTZ FN */
+	PINMUX_DATA(MMCDAT7_MARK, PS8_15_FN1, PTZ7_FN),
+	PINMUX_DATA(ON_DQ7_MARK, PS8_15_FN2, PTZ7_FN),
+	PINMUX_DATA(MMCDAT6_MARK, PS8_14_FN1, PTZ6_FN),
+	PINMUX_DATA(ON_DQ6_MARK, PS8_14_FN2, PTZ6_FN),
+	PINMUX_DATA(MMCDAT5_MARK, PS8_13_FN1, PTZ5_FN),
+	PINMUX_DATA(ON_DQ5_MARK, PS8_13_FN2, PTZ5_FN),
+	PINMUX_DATA(MMCDAT4_MARK, PS8_12_FN1, PTZ4_FN),
+	PINMUX_DATA(ON_DQ4_MARK, PS8_12_FN2, PTZ4_FN),
+	PINMUX_DATA(MMCDAT3_MARK, PS8_11_FN1, PTZ3_FN),
+	PINMUX_DATA(ON_DQ3_MARK, PS8_11_FN2, PTZ3_FN),
+	PINMUX_DATA(MMCDAT2_MARK, PS8_10_FN1, PTZ2_FN),
+	PINMUX_DATA(ON_DQ2_MARK, PS8_10_FN2, PTZ2_FN),
+	PINMUX_DATA(MMCDAT1_MARK, PS8_9_FN1, PTZ1_FN),
+	PINMUX_DATA(ON_DQ1_MARK, PS8_9_FN2, PTZ1_FN),
+	PINMUX_DATA(MMCDAT0_MARK, PS8_8_FN1, PTZ0_FN),
+	PINMUX_DATA(ON_DQ0_MARK, PS8_8_FN2, PTZ0_FN),
 };
 
 static struct pinmux_gpio pinmux_gpios[] = {
@@ -1048,7 +1205,6 @@
 	PINMUX_GPIO(GPIO_PTI0, PTI0_DATA),
 
 	/* PTJ */
-	PINMUX_GPIO(GPIO_PTJ7, PTJ7_DATA),
 	PINMUX_GPIO(GPIO_PTJ6, PTJ6_DATA),
 	PINMUX_GPIO(GPIO_PTJ5, PTJ5_DATA),
 	PINMUX_GPIO(GPIO_PTJ4, PTJ4_DATA),
@@ -1068,7 +1224,6 @@
 	PINMUX_GPIO(GPIO_PTK0, PTK0_DATA),
 
 	/* PTL */
-	PINMUX_GPIO(GPIO_PTL7, PTL7_DATA),
 	PINMUX_GPIO(GPIO_PTL6, PTL6_DATA),
 	PINMUX_GPIO(GPIO_PTL5, PTL5_DATA),
 	PINMUX_GPIO(GPIO_PTL4, PTL4_DATA),
@@ -1078,6 +1233,7 @@
 	PINMUX_GPIO(GPIO_PTL0, PTL0_DATA),
 
 	/* PTM */
+	PINMUX_GPIO(GPIO_PTM7, PTM7_DATA),
 	PINMUX_GPIO(GPIO_PTM6, PTM6_DATA),
 	PINMUX_GPIO(GPIO_PTM5, PTM5_DATA),
 	PINMUX_GPIO(GPIO_PTM4, PTM4_DATA),
@@ -1087,7 +1243,6 @@
 	PINMUX_GPIO(GPIO_PTM0, PTM0_DATA),
 
 	/* PTN */
-	PINMUX_GPIO(GPIO_PTN7, PTN7_DATA),
 	PINMUX_GPIO(GPIO_PTN6, PTN6_DATA),
 	PINMUX_GPIO(GPIO_PTN5, PTN5_DATA),
 	PINMUX_GPIO(GPIO_PTN4, PTN4_DATA),
@@ -1107,6 +1262,7 @@
 	PINMUX_GPIO(GPIO_PTO0, PTO0_DATA),
 
 	/* PTP */
+	PINMUX_GPIO(GPIO_PTP7, PTP7_DATA),
 	PINMUX_GPIO(GPIO_PTP6, PTP6_DATA),
 	PINMUX_GPIO(GPIO_PTP5, PTP5_DATA),
 	PINMUX_GPIO(GPIO_PTP4, PTP4_DATA),
@@ -1145,6 +1301,8 @@
 	PINMUX_GPIO(GPIO_PTS0, PTS0_DATA),
 
 	/* PTT */
+	PINMUX_GPIO(GPIO_PTT7, PTT7_DATA),
+	PINMUX_GPIO(GPIO_PTT6, PTT6_DATA),
 	PINMUX_GPIO(GPIO_PTT5, PTT5_DATA),
 	PINMUX_GPIO(GPIO_PTT4, PTT4_DATA),
 	PINMUX_GPIO(GPIO_PTT3, PTT3_DATA),
@@ -1212,54 +1370,35 @@
 	PINMUX_GPIO(GPIO_PTZ1, PTZ1_DATA),
 	PINMUX_GPIO(GPIO_PTZ0, PTZ0_DATA),
 
-	/* PTA (mobule: LBSC, CPG, LPC) */
+	/* PTA (mobule: LBSC, RGMII) */
 	PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
 	PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
 	PINMUX_GPIO(GPIO_FN_WE1, WE1_MARK),
 	PINMUX_GPIO(GPIO_FN_RDY, RDY_MARK),
-	PINMUX_GPIO(GPIO_FN_MD10, MD10_MARK),
-	PINMUX_GPIO(GPIO_FN_MD9, MD9_MARK),
-	PINMUX_GPIO(GPIO_FN_MD8, MD8_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
-	PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
-
-	/* PTB (mobule: LBSC, EtherC, SIM, LPC) */
-	PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
-	PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
-	PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
-	PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
-	PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
-	PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
-	PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
-	PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
 	PINMUX_GPIO(GPIO_FN_ET0_MDC, ET0_MDC_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDIO_MARK),
+	PINMUX_GPIO(GPIO_FN_ET0_MDIO, ET0_MDC_MARK),
 	PINMUX_GPIO(GPIO_FN_ET1_MDC, ET1_MDC_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDIO_MARK),
-	PINMUX_GPIO(GPIO_FN_WPSZ1, WPSZ1_MARK),
-	PINMUX_GPIO(GPIO_FN_WPSZ0, WPSZ0_MARK),
-	PINMUX_GPIO(GPIO_FN_FWID, FWID_MARK),
-	PINMUX_GPIO(GPIO_FN_FLSHSZ, FLSHSZ_MARK),
-	PINMUX_GPIO(GPIO_FN_LPC_SPIEN, LPC_SPIEN_MARK),
-	PINMUX_GPIO(GPIO_FN_BASEL, BASEL_MARK),
+	PINMUX_GPIO(GPIO_FN_ET1_MDIO, ET1_MDC_MARK),
 
-	/* PTC (mobule: SD) */
-	PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
-	PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
+	/* PTB (mobule: INTC, ONFI, TMU) */
+	PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_NRE, ON_NRE_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_NWE, ON_NWE_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_NWP, ON_NWP_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_NCE0, ON_NCE0_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_R_B0, ON_R_B0_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_ALE, ON_ALE_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_CLE, ON_CLE_MARK),
+	PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
 
-	/* PTD (mobule: INTC, SPI0, LBSC, CPG, ADC) */
+	/* PTC (mobule: IRQ, PWMU) */
 	PINMUX_GPIO(GPIO_FN_IRQ7, IRQ7_MARK),
 	PINMUX_GPIO(GPIO_FN_IRQ6, IRQ6_MARK),
 	PINMUX_GPIO(GPIO_FN_IRQ5, IRQ5_MARK),
@@ -1268,80 +1407,102 @@
 	PINMUX_GPIO(GPIO_FN_IRQ2, IRQ2_MARK),
 	PINMUX_GPIO(GPIO_FN_IRQ1, IRQ1_MARK),
 	PINMUX_GPIO(GPIO_FN_IRQ0, IRQ0_MARK),
-	PINMUX_GPIO(GPIO_FN_MD6, MD6_MARK),
-	PINMUX_GPIO(GPIO_FN_MD5, MD5_MARK),
-	PINMUX_GPIO(GPIO_FN_MD3, MD3_MARK),
-	PINMUX_GPIO(GPIO_FN_MD2, MD2_MARK),
-	PINMUX_GPIO(GPIO_FN_MD1, MD1_MARK),
-	PINMUX_GPIO(GPIO_FN_MD0, MD0_MARK),
-	PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
-	PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU0, PWMU0_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU1, PWMU1_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU2, PWMU2_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU3, PWMU3_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU4, PWMU4_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMU5, PWMU5_MARK),
 
-	/* PTE (mobule: EtherC) */
-	PINMUX_GPIO(GPIO_FN_ET0_CRS_DV, ET0_CRS_DV_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_TXD1, ET0_TXD1_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_TXD0, ET0_TXD0_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_TX_EN, ET0_TX_EN_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_REF_CLK, ET0_REF_CLK_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_RXD1, ET0_RXD1_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_RXD0, ET0_RXD0_MARK),
-	PINMUX_GPIO(GPIO_FN_ET0_RX_ER, ET0_RX_ER_MARK),
+	/* PTD (mobule: SPI0, DMAC) */
+	PINMUX_GPIO(GPIO_FN_SP0_MOSI, SP0_MOSI_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_MISO, SP0_MISO_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SCK, SP0_SCK_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SCK_FB, SP0_SCK_FB_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SS0, SP0_SS0_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SS2, SP0_SS2_MARK),
+	PINMUX_GPIO(GPIO_FN_SP0_SS3, SP0_SS3_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+	PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
 
-	/* PTF (mobule: EtherC) */
-	PINMUX_GPIO(GPIO_FN_ET1_CRS_DV, ET1_CRS_DV_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_TXD1, ET1_TXD1_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_TXD0, ET1_TXD0_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_TX_EN, ET1_TX_EN_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_REF_CLK, ET1_REF_CLK_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_RXD1, ET1_RXD1_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_RXD0, ET1_RXD0_MARK),
-	PINMUX_GPIO(GPIO_FN_ET1_RX_ER, ET1_RX_ER_MARK),
+	/* PTE (mobule: RMII) */
+	PINMUX_GPIO(GPIO_FN_RMII0_CRS_DV, RMII0_CRS_DV_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_TXD1, RMII0_TXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_TXD0, RMII0_TXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_TXEN, RMII0_TXEN_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_REFCLK, RMII0_REFCLK_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_RXD1, RMII0_RXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_RXD0, RMII0_RXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII0_RX_ER, RMII0_RX_ER_MARK),
 
-	/* PTG (mobule: SYSTEM, PWMX, LPC) */
-	PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
-	PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX0, PWX0_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX1, PWX1_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX2, PWX2_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX3, PWX3_MARK),
+	/* PTF (mobule: RMII, SerMux) */
+	PINMUX_GPIO(GPIO_FN_RMII1_CRS_DV, RMII1_CRS_DV_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_TXD1, RMII1_TXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_TXD0, RMII1_TXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_TXEN, RMII1_TXEN_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_REFCLK, RMII1_REFCLK_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_RXD1, RMII1_RXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_RXD0, RMII1_RXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RMII1_RX_ER, RMII1_RX_ER_MARK),
+	PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+
+	/* PTG (mobule: system, LBSC, LPC, WDT, LPC, eMMC) */
+	PINMUX_GPIO(GPIO_FN_BOOTFMS, BOOTFMS_MARK),
+	PINMUX_GPIO(GPIO_FN_BOOTWP, BOOTWP_MARK),
+	PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+	PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
 	PINMUX_GPIO(GPIO_FN_SERIRQ, SERIRQ_MARK),
-	PINMUX_GPIO(GPIO_FN_CLKRUN, CLKRUN_MARK),
+	PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
 	PINMUX_GPIO(GPIO_FN_LPCPD, LPCPD_MARK),
 	PINMUX_GPIO(GPIO_FN_LDRQ, LDRQ_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCCLK, MMCCLK_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCCMD, MMCCMD_MARK),
 
-	/* PTH (mobule: TMU, SCIF234, SPI1, SPI0) */
-	PINMUX_GPIO(GPIO_FN_TCLK, TCLK_MARK),
-	PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
-	PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+	/* PTH (mobule: SPI1, LPC, DMAC, ADC) */
 	PINMUX_GPIO(GPIO_FN_SP1_MOSI, SP1_MOSI_MARK),
 	PINMUX_GPIO(GPIO_FN_SP1_MISO, SP1_MISO_MARK),
 	PINMUX_GPIO(GPIO_FN_SP1_SCK, SP1_SCK_MARK),
 	PINMUX_GPIO(GPIO_FN_SP1_SCK_FB, SP1_SCK_FB_MARK),
 	PINMUX_GPIO(GPIO_FN_SP1_SS0, SP1_SS0_MARK),
 	PINMUX_GPIO(GPIO_FN_SP1_SS1, SP1_SS1_MARK),
-	PINMUX_GPIO(GPIO_FN_SP0_SS1, SP0_SS1_MARK),
+	PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
+	PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
+	PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+	PINMUX_GPIO(GPIO_FN_ADTRG1, ADTRG1_MARK),
+	PINMUX_GPIO(GPIO_FN_ADTRG0, ADTRG0_MARK),
 
-	/* PTI (mobule: INTC) */
-	PINMUX_GPIO(GPIO_FN_IRQ15, IRQ15_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ14, IRQ14_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ13, IRQ13_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ12, IRQ12_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ11, IRQ11_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ10, IRQ10_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ9, IRQ9_MARK),
-	PINMUX_GPIO(GPIO_FN_IRQ8, IRQ8_MARK),
+	/* PTI (mobule: LBSC, SDHI) */
+	PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+	PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+	PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+	PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+	PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+	PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+	PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+	PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_WP, SD_WP_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_CD, SD_CD_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_CLK, SD_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_CMD, SD_CMD_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_D3, SD_D3_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_D2, SD_D2_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_D1, SD_D1_MARK),
+	PINMUX_GPIO(GPIO_FN_SD_D0, SD_D0_MARK),
 
 	/* PTJ (mobule: SCIF234, SERMUX) */
-	PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
 	PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
-	PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
-	PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
-	PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
-	PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
-	PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
-	PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
 
-	/* PTK (mobule: SERMUX) */
+	/* PTK (mobule: SERMUX, LBSC, SCIF) */
 	PINMUX_GPIO(GPIO_FN_COM2_TXD, COM2_TXD_MARK),
 	PINMUX_GPIO(GPIO_FN_COM2_RXD, COM2_RXD_MARK),
 	PINMUX_GPIO(GPIO_FN_COM2_RTS, COM2_RTS_MARK),
@@ -1349,62 +1510,65 @@
 	PINMUX_GPIO(GPIO_FN_COM2_DTR, COM2_DTR_MARK),
 	PINMUX_GPIO(GPIO_FN_COM2_DSR, COM2_DSR_MARK),
 	PINMUX_GPIO(GPIO_FN_COM2_DCD, COM2_DCD_MARK),
-	PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+	PINMUX_GPIO(GPIO_FN_CLKOUT, CLKOUT_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
 
-	/* PTL (mobule: SERMUX) */
-	PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+	/* PTL (mobule: SERMUX, SCIF, LBSC, AUD) */
 	PINMUX_GPIO(GPIO_FN_RAC_RXD, RAC_RXD_MARK),
 	PINMUX_GPIO(GPIO_FN_RAC_RTS, RAC_RTS_MARK),
 	PINMUX_GPIO(GPIO_FN_RAC_CTS, RAC_CTS_MARK),
 	PINMUX_GPIO(GPIO_FN_RAC_DTR, RAC_DTR_MARK),
 	PINMUX_GPIO(GPIO_FN_RAC_DSR, RAC_DSR_MARK),
 	PINMUX_GPIO(GPIO_FN_RAC_DCD, RAC_DCD_MARK),
-	PINMUX_GPIO(GPIO_FN_RAC_RI, RAC_RI_MARK),
+	PINMUX_GPIO(GPIO_FN_RAC_TXD, RAC_TXD_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
+	PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
+	PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
+	PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
 
-	/* PTM (mobule: IIC, LPC) */
+	/* PTM (mobule: LBSC, IIC) */
+	PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+	PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+	PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
+	PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
 	PINMUX_GPIO(GPIO_FN_SDA6, SDA6_MARK),
 	PINMUX_GPIO(GPIO_FN_SCL6, SCL6_MARK),
 	PINMUX_GPIO(GPIO_FN_SDA7, SDA7_MARK),
 	PINMUX_GPIO(GPIO_FN_SCL7, SCL7_MARK),
-	PINMUX_GPIO(GPIO_FN_WP, WP_MARK),
-	PINMUX_GPIO(GPIO_FN_FMS0, FMS0_MARK),
-	PINMUX_GPIO(GPIO_FN_FMS1, FMS1_MARK),
 
-	/* PTN (mobule: SCIF234, EVC) */
-	PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
-	PINMUX_GPIO(GPIO_FN_RTS4, RTS4_MARK),
-	PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
-	PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
-	PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
-	PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
-	PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
-	PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+	/* PTN (mobule: USB, JMC, SGPIO, WDT) */
+	PINMUX_GPIO(GPIO_FN_VBUS_EN, VBUS_EN_MARK),
+	PINMUX_GPIO(GPIO_FN_VBUS_OC, VBUS_OC_MARK),
+	PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
+	PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
+	PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
+	PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
+	PINMUX_GPIO(GPIO_FN_JMCTRST, JMCTRST_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+	PINMUX_GPIO(GPIO_FN_SUB_CLKIN, SUB_CLKIN_MARK),
 
-	/* PTO (mobule: SGPIO) */
+	/* PTO (mobule: SGPIO, SerMux) */
 	PINMUX_GPIO(GPIO_FN_SGPIO0_CLK, SGPIO0_CLK_MARK),
 	PINMUX_GPIO(GPIO_FN_SGPIO0_LOAD, SGPIO0_LOAD_MARK),
 	PINMUX_GPIO(GPIO_FN_SGPIO0_DI, SGPIO0_DI_MARK),
 	PINMUX_GPIO(GPIO_FN_SGPIO0_DO, SGPIO0_DO_MARK),
-	PINMUX_GPIO(GPIO_FN_SGPIO1_CLK, SGPIO1_CLK_MARK),
-	PINMUX_GPIO(GPIO_FN_SGPIO1_LOAD, SGPIO1_LOAD_MARK),
-	PINMUX_GPIO(GPIO_FN_SGPIO1_DI, SGPIO1_DI_MARK),
-	PINMUX_GPIO(GPIO_FN_SGPIO1_DO, SGPIO1_DO_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO2_CLK, SGPIO2_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO2_LOAD, SGPIO2_LOAD_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO2_DI, SGPIO2_DI_MARK),
+	PINMUX_GPIO(GPIO_FN_SGPIO2_DO, SGPIO2_DO_MARK),
+	PINMUX_GPIO(GPIO_FN_COM1_TXD, COM1_TXD_MARK),
+	PINMUX_GPIO(GPIO_FN_COM1_RXD, COM1_RXD_MARK),
+	PINMUX_GPIO(GPIO_FN_COM1_RTS, COM1_RTS_MARK),
+	PINMUX_GPIO(GPIO_FN_COM1_CTS, COM1_CTS_MARK),
 
-	/* PTP (mobule: JMC, SCIF234) */
-	PINMUX_GPIO(GPIO_FN_JMCTCK, JMCTCK_MARK),
-	PINMUX_GPIO(GPIO_FN_JMCTMS, JMCTMS_MARK),
-	PINMUX_GPIO(GPIO_FN_JMCTDO, JMCTDO_MARK),
-	PINMUX_GPIO(GPIO_FN_JMCTDI, JMCTDI_MARK),
-	PINMUX_GPIO(GPIO_FN_JMCRST, JMCRST_MARK),
-	PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
-	PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+	/* PTP (mobule: EVC, ADC) */
 
 	/* PTQ (mobule: LPC) */
 	PINMUX_GPIO(GPIO_FN_LAD3, LAD3_MARK),
@@ -1439,31 +1603,41 @@
 	PINMUX_GPIO(GPIO_FN_SDA3, SDA3_MARK),
 	PINMUX_GPIO(GPIO_FN_SCL3, SCL3_MARK),
 
-	/* PTT (mobule: SYSTEM, PWMX) */
-	PINMUX_GPIO(GPIO_FN_AUDSYNC, AUDSYNC_MARK),
-	PINMUX_GPIO(GPIO_FN_AUDCK, AUDCK_MARK),
+	/* PTT (mobule: PWMX, AUD) */
+	PINMUX_GPIO(GPIO_FN_PWMX7, PWMX7_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX6, PWMX6_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX5, PWMX5_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX4, PWMX4_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX3, PWMX3_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX2, PWMX2_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX1, PWMX1_MARK),
+	PINMUX_GPIO(GPIO_FN_PWMX0, PWMX0_MARK),
 	PINMUX_GPIO(GPIO_FN_AUDATA3, AUDATA3_MARK),
 	PINMUX_GPIO(GPIO_FN_AUDATA2, AUDATA2_MARK),
 	PINMUX_GPIO(GPIO_FN_AUDATA1, AUDATA1_MARK),
 	PINMUX_GPIO(GPIO_FN_AUDATA0, AUDATA0_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX7, PWX7_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX6, PWX6_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX5, PWX5_MARK),
-	PINMUX_GPIO(GPIO_FN_PWX4, PWX4_MARK),
+	PINMUX_GPIO(GPIO_FN_STATUS1, STATUS1_MARK),
+	PINMUX_GPIO(GPIO_FN_STATUS0, STATUS0_MARK),
 
-	/* PTU (mobule: LBSC, DMAC) */
-	PINMUX_GPIO(GPIO_FN_CS6, CS6_MARK),
-	PINMUX_GPIO(GPIO_FN_CS5, CS5_MARK),
-	PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
-	PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
-	PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
-	PINMUX_GPIO(GPIO_FN_WE0, WE0_MARK),
-	PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
-	PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
-	PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
-	PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+	/* PTU (mobule: LPC, APM) */
+	PINMUX_GPIO(GPIO_FN_LGPIO7, LGPIO7_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO6, LGPIO6_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO5, LGPIO5_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO4, LGPIO4_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO3, LGPIO3_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO2, LGPIO2_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO1, LGPIO1_MARK),
+	PINMUX_GPIO(GPIO_FN_LGPIO0, LGPIO0_MARK),
+	PINMUX_GPIO(GPIO_FN_APMONCTL_O, APMONCTL_O_MARK),
+	PINMUX_GPIO(GPIO_FN_APMPWBTOUT_O, APMPWBTOUT_O_MARK),
+	PINMUX_GPIO(GPIO_FN_APMSCI_O, APMSCI_O_MARK),
+	PINMUX_GPIO(GPIO_FN_APMVDDON, APMVDDON_MARK),
+	PINMUX_GPIO(GPIO_FN_APMSLPBTN, APMSLPBTN_MARK),
+	PINMUX_GPIO(GPIO_FN_APMPWRBTN, APMPWRBTN_MARK),
+	PINMUX_GPIO(GPIO_FN_APMS5N, APMS5N_MARK),
+	PINMUX_GPIO(GPIO_FN_APMS3N, APMS3N_MARK),
 
-	/* PTV (mobule: LBSC, DMAC) */
+	/* PTV (mobule: LBSC, SerMux, R-SPI, EVC, GRA) */
 	PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
 	PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
 	PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
@@ -1472,12 +1646,20 @@
 	PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
 	PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
 	PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
-	PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
-	PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
-	PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
-	PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+	PINMUX_GPIO(GPIO_FN_COM2_RI, COM2_RI_MARK),
+	PINMUX_GPIO(GPIO_FN_R_SPI_MOSI, R_SPI_MOSI_MARK),
+	PINMUX_GPIO(GPIO_FN_R_SPI_MISO, R_SPI_MISO_MARK),
+	PINMUX_GPIO(GPIO_FN_R_SPI_RSPCK, R_SPI_RSPCK_MARK),
+	PINMUX_GPIO(GPIO_FN_R_SPI_SSL0, R_SPI_SSL0_MARK),
+	PINMUX_GPIO(GPIO_FN_R_SPI_SSL1, R_SPI_SSL1_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT7, EVENT7_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT6, EVENT6_MARK),
+	PINMUX_GPIO(GPIO_FN_VBIOS_DI, VBIOS_DI_MARK),
+	PINMUX_GPIO(GPIO_FN_VBIOS_DO, VBIOS_DO_MARK),
+	PINMUX_GPIO(GPIO_FN_VBIOS_CLK, VBIOS_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_VBIOS_CS, VBIOS_CS_MARK),
 
-	/* PTW (mobule: LBSC) */
+	/* PTW (mobule: LBSC, EVC, SCIF) */
 	PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
 	PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
 	PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
@@ -1487,6 +1669,14 @@
 	PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
 	PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
 	PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT5, EVENT5_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT4, EVENT4_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT3, EVENT3_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT2, EVENT2_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT1, EVENT1_MARK),
+	PINMUX_GPIO(GPIO_FN_EVENT0, EVENT0_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS4, CTS4_MARK),
+	PINMUX_GPIO(GPIO_FN_CTS2, CTS2_MARK),
 
 	/* PTX (mobule: LBSC) */
 	PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
@@ -1497,6 +1687,10 @@
 	PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
 	PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
 	PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+	PINMUX_GPIO(GPIO_FN_RTS2, RTS2_MARK),
+	PINMUX_GPIO(GPIO_FN_SIM_D, SIM_D_MARK),
+	PINMUX_GPIO(GPIO_FN_SIM_CLK, SIM_CLK_MARK),
+	PINMUX_GPIO(GPIO_FN_SIM_RST, SIM_RST_MARK),
 
 	/* PTY (mobule: LBSC) */
 	PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
@@ -1507,18 +1701,36 @@
 	PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
 	PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
 	PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+	/* PTZ (mobule: eMMC, ONFI) */
+	PINMUX_GPIO(GPIO_FN_MMCDAT7, MMCDAT7_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT6, MMCDAT6_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT5, MMCDAT5_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT4, MMCDAT4_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT3, MMCDAT3_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT2, MMCDAT2_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT1, MMCDAT1_MARK),
+	PINMUX_GPIO(GPIO_FN_MMCDAT0, MMCDAT0_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ7, ON_DQ7_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ6, ON_DQ6_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ5, ON_DQ5_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ4, ON_DQ4_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ3, ON_DQ3_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ2, ON_DQ2_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ1, ON_DQ1_MARK),
+	PINMUX_GPIO(GPIO_FN_ON_DQ0, ON_DQ0_MARK),
  };
 
 static struct pinmux_cfg_reg pinmux_config_regs[] = {
 	{ PINMUX_CFG_REG("PACR", 0xffec0000, 16, 2) {
-		PTA7_FN, PTA7_OUT, PTA7_IN, 0,
-		PTA6_FN, PTA6_OUT, PTA6_IN, 0,
-		PTA5_FN, PTA5_OUT, PTA5_IN, 0,
-		PTA4_FN, PTA4_OUT, PTA4_IN, 0,
-		PTA3_FN, PTA3_OUT, PTA3_IN, 0,
-		PTA2_FN, PTA2_OUT, PTA2_IN, 0,
-		PTA1_FN, PTA1_OUT, PTA1_IN, 0,
-		PTA0_FN, PTA0_OUT, PTA0_IN, 0 }
+		PTA7_FN, PTA7_OUT, PTA7_IN, PTA7_IN_PU,
+		PTA6_FN, PTA6_OUT, PTA6_IN, PTA6_IN_PU,
+		PTA5_FN, PTA5_OUT, PTA5_IN, PTA5_IN_PU,
+		PTA4_FN, PTA4_OUT, PTA4_IN, PTA4_IN_PU,
+		PTA3_FN, PTA3_OUT, PTA3_IN, PTA3_IN_PU,
+		PTA2_FN, PTA2_OUT, PTA2_IN, PTA2_IN_PU,
+		PTA1_FN, PTA1_OUT, PTA1_IN, PTA1_IN_PU,
+		PTA0_FN, PTA0_OUT, PTA0_IN, PTA0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PBCR", 0xffec0002, 16, 2) {
 		PTB7_FN, PTB7_OUT, PTB7_IN, 0,
@@ -1541,125 +1753,126 @@
 		PTC0_FN, PTC0_OUT, PTC0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PDCR", 0xffec0006, 16, 2) {
-		PTD7_FN, PTD7_OUT, PTD7_IN, 0,
-		PTD6_FN, PTD6_OUT, PTD6_IN, 0,
-		PTD5_FN, PTD5_OUT, PTD5_IN, 0,
-		PTD4_FN, PTD4_OUT, PTD4_IN, 0,
-		PTD3_FN, PTD3_OUT, PTD3_IN, 0,
-		PTD2_FN, PTD2_OUT, PTD2_IN, 0,
-		PTD1_FN, PTD1_OUT, PTD1_IN, 0,
-		PTD0_FN, PTD0_OUT, PTD0_IN, 0 }
+		PTD7_FN, PTD7_OUT, PTD7_IN, PTD7_IN_PU,
+		PTD6_FN, PTD6_OUT, PTD6_IN, PTD6_IN_PU,
+		PTD5_FN, PTD5_OUT, PTD5_IN, PTD5_IN_PU,
+		PTD4_FN, PTD4_OUT, PTD4_IN, PTD4_IN_PU,
+		PTD3_FN, PTD3_OUT, PTD3_IN, PTD3_IN_PU,
+		PTD2_FN, PTD2_OUT, PTD2_IN, PTD2_IN_PU,
+		PTD1_FN, PTD1_OUT, PTD1_IN, PTD1_IN_PU,
+		PTD0_FN, PTD0_OUT, PTD0_IN, PTD0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PECR", 0xffec0008, 16, 2) {
-		PTE7_FN, PTE7_OUT, PTE7_IN, 0,
-		PTE6_FN, PTE6_OUT, PTE6_IN, 0,
-		PTE5_FN, PTE5_OUT, PTE5_IN, 0,
-		PTE4_FN, PTE4_OUT, PTE4_IN, 0,
-		PTE3_FN, PTE3_OUT, PTE3_IN, 0,
-		PTE2_FN, PTE2_OUT, PTE2_IN, 0,
-		PTE1_FN, PTE1_OUT, PTE1_IN, 0,
-		PTE0_FN, PTE0_OUT, PTE0_IN, 0 }
+		PTE7_FN, PTE7_OUT, PTE7_IN, PTE7_IN_PU,
+		PTE6_FN, PTE6_OUT, PTE6_IN, PTE6_IN_PU,
+		PTE5_FN, PTE5_OUT, PTE5_IN, PTE5_IN_PU,
+		PTE4_FN, PTE4_OUT, PTE4_IN, PTE4_IN_PU,
+		PTE3_FN, PTE3_OUT, PTE3_IN, PTE3_IN_PU,
+		PTE2_FN, PTE2_OUT, PTE2_IN, PTE2_IN_PU,
+		PTE1_FN, PTE1_OUT, PTE1_IN, PTE1_IN_PU,
+		PTE0_FN, PTE0_OUT, PTE0_IN, PTE0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PFCR", 0xffec000a, 16, 2) {
-		PTF7_FN, PTF7_OUT, PTF7_IN, 0,
-		PTF6_FN, PTF6_OUT, PTF6_IN, 0,
-		PTF5_FN, PTF5_OUT, PTF5_IN, 0,
-		PTF4_FN, PTF4_OUT, PTF4_IN, 0,
-		PTF3_FN, PTF3_OUT, PTF3_IN, 0,
-		PTF2_FN, PTF2_OUT, PTF2_IN, 0,
-		PTF1_FN, PTF1_OUT, PTF1_IN, 0,
-		PTF0_FN, PTF0_OUT, PTF0_IN, 0 }
+		PTF7_FN, PTF7_OUT, PTF7_IN, PTF7_IN_PU,
+		PTF6_FN, PTF6_OUT, PTF6_IN, PTF6_IN_PU,
+		PTF5_FN, PTF5_OUT, PTF5_IN, PTF5_IN_PU,
+		PTF4_FN, PTF4_OUT, PTF4_IN, PTF4_IN_PU,
+		PTF3_FN, PTF3_OUT, PTF3_IN, PTF3_IN_PU,
+		PTF2_FN, PTF2_OUT, PTF2_IN, PTF2_IN_PU,
+		PTF1_FN, PTF1_OUT, PTF1_IN, PTF1_IN_PU,
+		PTF0_FN, PTF0_OUT, PTF0_IN, PTF0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PGCR", 0xffec000c, 16, 2) {
-		PTG7_FN, PTG7_OUT, PTG7_IN, 0,
-		PTG6_FN, PTG6_OUT, PTG6_IN, 0,
+		PTG7_FN, PTG7_OUT, PTG7_IN, PTG7_IN_PU ,
+		PTG6_FN, PTG6_OUT, PTG6_IN, PTG6_IN_PU ,
 		PTG5_FN, PTG5_OUT, PTG5_IN, 0,
-		PTG4_FN, PTG4_OUT, PTG4_IN, 0,
+		PTG4_FN, PTG4_OUT, PTG4_IN, PTG4_IN_PU ,
 		PTG3_FN, PTG3_OUT, PTG3_IN, 0,
 		PTG2_FN, PTG2_OUT, PTG2_IN, 0,
 		PTG1_FN, PTG1_OUT, PTG1_IN, 0,
 		PTG0_FN, PTG0_OUT, PTG0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PHCR", 0xffec000e, 16, 2) {
-		PTH7_FN, PTH7_OUT, PTH7_IN, 0,
-		PTH6_FN, PTH6_OUT, PTH6_IN, 0,
-		PTH5_FN, PTH5_OUT, PTH5_IN, 0,
-		PTH4_FN, PTH4_OUT, PTH4_IN, 0,
-		PTH3_FN, PTH3_OUT, PTH3_IN, 0,
-		PTH2_FN, PTH2_OUT, PTH2_IN, 0,
-		PTH1_FN, PTH1_OUT, PTH1_IN, 0,
-		PTH0_FN, PTH0_OUT, PTH0_IN, 0 }
+		PTH7_FN, PTH7_OUT, PTH7_IN, PTH7_IN_PU,
+		PTH6_FN, PTH6_OUT, PTH6_IN, PTH6_IN_PU,
+		PTH5_FN, PTH5_OUT, PTH5_IN, PTH5_IN_PU,
+		PTH4_FN, PTH4_OUT, PTH4_IN, PTH4_IN_PU,
+		PTH3_FN, PTH3_OUT, PTH3_IN, PTH3_IN_PU,
+		PTH2_FN, PTH2_OUT, PTH2_IN, PTH2_IN_PU,
+		PTH1_FN, PTH1_OUT, PTH1_IN, PTH1_IN_PU,
+		PTH0_FN, PTH0_OUT, PTH0_IN, PTH0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PICR", 0xffec0010, 16, 2) {
-		PTI7_FN, PTI7_OUT, PTI7_IN, 0,
-		PTI6_FN, PTI6_OUT, PTI6_IN, 0,
+		PTI7_FN, PTI7_OUT, PTI7_IN, PTI7_IN_PU,
+		PTI6_FN, PTI6_OUT, PTI6_IN, PTI6_IN_PU,
 		PTI5_FN, PTI5_OUT, PTI5_IN, 0,
-		PTI4_FN, PTI4_OUT, PTI4_IN, 0,
-		PTI3_FN, PTI3_OUT, PTI3_IN, 0,
-		PTI2_FN, PTI2_OUT, PTI2_IN, 0,
-		PTI1_FN, PTI1_OUT, PTI1_IN, 0,
-		PTI0_FN, PTI0_OUT, PTI0_IN, 0 }
+		PTI4_FN, PTI4_OUT, PTI4_IN, PTI4_IN_PU,
+		PTI3_FN, PTI3_OUT, PTI3_IN, PTI3_IN_PU,
+		PTI2_FN, PTI2_OUT, PTI2_IN, PTI2_IN_PU,
+		PTI1_FN, PTI1_OUT, PTI1_IN, PTI1_IN_PU,
+		PTI0_FN, PTI0_OUT, PTI0_IN, PTI0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PJCR", 0xffec0012, 16, 2) {
-		PTJ7_FN, PTJ7_OUT, PTJ7_IN, 0,
-		PTJ6_FN, PTJ6_OUT, PTJ6_IN, 0,
-		PTJ5_FN, PTJ5_OUT, PTJ5_IN, 0,
-		PTJ4_FN, PTJ4_OUT, PTJ4_IN, 0,
-		PTJ3_FN, PTJ3_OUT, PTJ3_IN, 0,
-		PTJ2_FN, PTJ2_OUT, PTJ2_IN, 0,
-		PTJ1_FN, PTJ1_OUT, PTJ1_IN, 0,
-		PTJ0_FN, PTJ0_OUT, PTJ0_IN, 0 }
+		0, 0, 0, 0,	/* reserved: always set 1 */
+		PTJ6_FN, PTJ6_OUT, PTJ6_IN, PTJ6_IN_PU,
+		PTJ5_FN, PTJ5_OUT, PTJ5_IN, PTJ5_IN_PU,
+		PTJ4_FN, PTJ4_OUT, PTJ4_IN, PTJ4_IN_PU,
+		PTJ3_FN, PTJ3_OUT, PTJ3_IN, PTJ3_IN_PU,
+		PTJ2_FN, PTJ2_OUT, PTJ2_IN, PTJ2_IN_PU,
+		PTJ1_FN, PTJ1_OUT, PTJ1_IN, PTJ1_IN_PU,
+		PTJ0_FN, PTJ0_OUT, PTJ0_IN, PTJ0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PKCR", 0xffec0014, 16, 2) {
-		PTK7_FN, PTK7_OUT, PTK7_IN, 0,
-		PTK6_FN, PTK6_OUT, PTK6_IN, 0,
-		PTK5_FN, PTK5_OUT, PTK5_IN, 0,
-		PTK4_FN, PTK4_OUT, PTK4_IN, 0,
-		PTK3_FN, PTK3_OUT, PTK3_IN, 0,
-		PTK2_FN, PTK2_OUT, PTK2_IN, 0,
-		PTK1_FN, PTK1_OUT, PTK1_IN, 0,
-		PTK0_FN, PTK0_OUT, PTK0_IN, 0 }
+		PTK7_FN, PTK7_OUT, PTK7_IN, PTK7_IN_PU,
+		PTK6_FN, PTK6_OUT, PTK6_IN, PTK6_IN_PU,
+		PTK5_FN, PTK5_OUT, PTK5_IN, PTK5_IN_PU,
+		PTK4_FN, PTK4_OUT, PTK4_IN, PTK4_IN_PU,
+		PTK3_FN, PTK3_OUT, PTK3_IN, PTK3_IN_PU,
+		PTK2_FN, PTK2_OUT, PTK2_IN, PTK2_IN_PU,
+		PTK1_FN, PTK1_OUT, PTK1_IN, PTK1_IN_PU,
+		PTK0_FN, PTK0_OUT, PTK0_IN, PTK0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PLCR", 0xffec0016, 16, 2) {
-		PTL7_FN, PTL7_OUT, PTL7_IN, 0,
-		PTL6_FN, PTL6_OUT, PTL6_IN, 0,
-		PTL5_FN, PTL5_OUT, PTL5_IN, 0,
-		PTL4_FN, PTL4_OUT, PTL4_IN, 0,
-		PTL3_FN, PTL3_OUT, PTL3_IN, 0,
-		PTL2_FN, PTL2_OUT, PTL2_IN, 0,
-		PTL1_FN, PTL1_OUT, PTL1_IN, 0,
-		PTL0_FN, PTL0_OUT, PTL0_IN, 0 }
+		0, 0, 0, 0,	/* reserved: always set 1 */
+		PTL6_FN, PTL6_OUT, PTL6_IN, PTL6_IN_PU,
+		PTL5_FN, PTL5_OUT, PTL5_IN, PTL5_IN_PU,
+		PTL4_FN, PTL4_OUT, PTL4_IN, PTL4_IN_PU,
+		PTL3_FN, PTL3_OUT, PTL3_IN, PTL3_IN_PU,
+		PTL2_FN, PTL2_OUT, PTL2_IN, PTL2_IN_PU,
+		PTL1_FN, PTL1_OUT, PTL1_IN, PTL1_IN_PU,
+		PTL0_FN, PTL0_OUT, PTL0_IN, PTL0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PMCR", 0xffec0018, 16, 2) {
-		0, 0, 0, 0,	/* reserved: always set 1 */
-		PTM6_FN, PTM6_OUT, PTM6_IN, 0,
-		PTM5_FN, PTM5_OUT, PTM5_IN, 0,
-		PTM4_FN, PTM4_OUT, PTM4_IN, 0,
+		PTM7_FN, PTM7_OUT, PTM7_IN, PTM7_IN_PU,
+		PTM6_FN, PTM6_OUT, PTM6_IN, PTM6_IN_PU,
+		PTM5_FN, PTM5_OUT, PTM5_IN, PTM5_IN_PU,
+		PTM4_FN, PTM4_OUT, PTM4_IN, PTM4_IN_PU,
 		PTM3_FN, PTM3_OUT, PTM3_IN, 0,
 		PTM2_FN, PTM2_OUT, PTM2_IN, 0,
 		PTM1_FN, PTM1_OUT, PTM1_IN, 0,
 		PTM0_FN, PTM0_OUT, PTM0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PNCR", 0xffec001a, 16, 2) {
-		PTN7_FN, PTN7_OUT, PTN7_IN, 0,
+		0, 0, 0, 0,	/* reserved: always set 1 */
 		PTN6_FN, PTN6_OUT, PTN6_IN, 0,
 		PTN5_FN, PTN5_OUT, PTN5_IN, 0,
-		PTN4_FN, PTN4_OUT, PTN4_IN, 0,
-		PTN3_FN, PTN3_OUT, PTN3_IN, 0,
-		PTN2_FN, PTN2_OUT, PTN2_IN, 0,
-		PTN1_FN, PTN1_OUT, PTN1_IN, 0,
-		PTN0_FN, PTN0_OUT, PTN0_IN, 0 }
+		PTN4_FN, PTN4_OUT, PTN4_IN, PTN4_IN_PU,
+		PTN3_FN, PTN3_OUT, PTN3_IN, PTN3_IN_PU,
+		PTN2_FN, PTN2_OUT, PTN2_IN, PTN2_IN_PU,
+		PTN1_FN, PTN1_OUT, PTN1_IN, PTN1_IN_PU,
+		PTN0_FN, PTN0_OUT, PTN0_IN, PTN0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("POCR", 0xffec001c, 16, 2) {
-		PTO7_FN, PTO7_OUT, PTO7_IN, 0,
-		PTO6_FN, PTO6_OUT, PTO6_IN, 0,
-		PTO5_FN, PTO5_OUT, PTO5_IN, 0,
-		PTO4_FN, PTO4_OUT, PTO4_IN, 0,
-		PTO3_FN, PTO3_OUT, PTO3_IN, 0,
-		PTO2_FN, PTO2_OUT, PTO2_IN, 0,
-		PTO1_FN, PTO1_OUT, PTO1_IN, 0,
-		PTO0_FN, PTO0_OUT, PTO0_IN, 0 }
+		PTO7_FN, PTO7_OUT, PTO7_IN, PTO7_IN_PU,
+		PTO6_FN, PTO6_OUT, PTO6_IN, PTO6_IN_PU,
+		PTO5_FN, PTO5_OUT, PTO5_IN, PTO5_IN_PU,
+		PTO4_FN, PTO4_OUT, PTO4_IN, PTO4_IN_PU,
+		PTO3_FN, PTO3_OUT, PTO3_IN, PTO3_IN_PU,
+		PTO2_FN, PTO2_OUT, PTO2_IN, PTO2_IN_PU,
+		PTO1_FN, PTO1_OUT, PTO1_IN, PTO1_IN_PU,
+		PTO0_FN, PTO0_OUT, PTO0_IN, PTO0_IN_PU }
 	},
+#if 0	/* FIXME: Remove it? */
 	{ PINMUX_CFG_REG("PPCR", 0xffec001e, 16, 2) {
 		0, 0, 0, 0,	/* reserved: always set 1 */
 		PTP6_FN, PTP6_OUT, PTP6_IN, 0,
@@ -1670,6 +1883,7 @@
 		PTP1_FN, PTP1_OUT, PTP1_IN, 0,
 		PTP0_FN, PTP0_OUT, PTP0_IN, 0 }
 	},
+#endif
 	{ PINMUX_CFG_REG("PQCR", 0xffec0020, 16, 2) {
 		0, 0, 0, 0,	/* reserved: always set 1 */
 		PTQ6_FN, PTQ6_OUT, PTQ6_IN, 0,
@@ -1701,14 +1915,14 @@
 		PTS0_FN, PTS0_OUT, PTS0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PTCR", 0xffec0026, 16, 2) {
-		0, 0, 0, 0,	/* reserved: always set 1 */
-		0, 0, 0, 0,	/* reserved: always set 1 */
-		PTT5_FN, PTT5_OUT, PTT5_IN, 0,
-		PTT4_FN, PTT4_OUT, PTT4_IN, 0,
-		PTT3_FN, PTT3_OUT, PTT3_IN, 0,
-		PTT2_FN, PTT2_OUT, PTT2_IN, 0,
-		PTT1_FN, PTT1_OUT, PTT1_IN, 0,
-		PTT0_FN, PTT0_OUT, PTT0_IN, 0 }
+		PTT7_FN, PTT7_OUT, PTT7_IN, PTO7_IN_PU,
+		PTT6_FN, PTT6_OUT, PTT6_IN, PTO6_IN_PU,
+		PTT5_FN, PTT5_OUT, PTT5_IN, PTO5_IN_PU,
+		PTT4_FN, PTT4_OUT, PTT4_IN, PTO4_IN_PU,
+		PTT3_FN, PTT3_OUT, PTT3_IN, PTO3_IN_PU,
+		PTT2_FN, PTT2_OUT, PTT2_IN, PTO2_IN_PU,
+		PTT1_FN, PTT1_OUT, PTT1_IN, PTO1_IN_PU,
+		PTT0_FN, PTT0_OUT, PTT0_IN, PTO0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PUCR", 0xffec0028, 16, 2) {
 		PTU7_FN, PTU7_OUT, PTU7_IN, PTU7_IN_PU,
@@ -1727,16 +1941,16 @@
 		PTV4_FN, PTV4_OUT, PTV4_IN, PTV4_IN_PU,
 		PTV3_FN, PTV3_OUT, PTV3_IN, PTV3_IN_PU,
 		PTV2_FN, PTV2_OUT, PTV2_IN, PTV2_IN_PU,
-		PTV1_FN, PTV1_OUT, PTV1_IN, PTV1_IN_PU,
-		PTV0_FN, PTV0_OUT, PTV0_IN, PTV0_IN_PU }
+		PTV1_FN, PTV1_OUT, PTV1_IN, 0,
+		PTV0_FN, PTV0_OUT, PTV0_IN, 0 }
 	},
 	{ PINMUX_CFG_REG("PWCR", 0xffec002c, 16, 2) {
-		PTW7_FN, PTW7_OUT, PTW7_IN, PTW7_IN_PU,
-		PTW6_FN, PTW6_OUT, PTW6_IN, PTW6_IN_PU,
-		PTW5_FN, PTW5_OUT, PTW5_IN, PTW5_IN_PU,
-		PTW4_FN, PTW4_OUT, PTW4_IN, PTW4_IN_PU,
-		PTW3_FN, PTW3_OUT, PTW3_IN, PTW3_IN_PU,
-		PTW2_FN, PTW2_OUT, PTW2_IN, PTW2_IN_PU,
+		PTW7_FN, PTW7_OUT, PTW7_IN, 0,
+		PTW6_FN, PTW6_OUT, PTW6_IN, 0,
+		PTW5_FN, PTW5_OUT, PTW5_IN, 0,
+		PTW4_FN, PTW4_OUT, PTW4_IN, 0,
+		PTW3_FN, PTW3_OUT, PTW3_IN, 0,
+		PTW2_FN, PTW2_OUT, PTW2_IN, 0,
 		PTW1_FN, PTW1_OUT, PTW1_IN, PTW1_IN_PU,
 		PTW0_FN, PTW0_OUT, PTW0_IN, PTW0_IN_PU }
 	},
@@ -1761,32 +1975,32 @@
 		PTY0_FN, PTY0_OUT, PTY0_IN, PTY0_IN_PU }
 	},
 	{ PINMUX_CFG_REG("PZCR", 0xffec0032, 16, 2) {
-		0, PTZ7_OUT, PTZ7_IN, 0,
-		0, PTZ6_OUT, PTZ6_IN, 0,
-		0, PTZ5_OUT, PTZ5_IN, 0,
-		0, PTZ4_OUT, PTZ4_IN, 0,
-		0, PTZ3_OUT, PTZ3_IN, 0,
-		0, PTZ2_OUT, PTZ2_IN, 0,
-		0, PTZ1_OUT, PTZ1_IN, 0,
-		0, PTZ0_OUT, PTZ0_IN, 0 }
+		PTZ7_FN, PTZ7_OUT, PTZ7_IN, 0,
+		PTZ6_FN, PTZ6_OUT, PTZ6_IN, 0,
+		PTZ5_FN, PTZ5_OUT, PTZ5_IN, 0,
+		PTZ4_FN, PTZ4_OUT, PTZ4_IN, 0,
+		PTZ3_FN, PTZ3_OUT, PTZ3_IN, 0,
+		PTZ2_FN, PTZ2_OUT, PTZ2_IN, 0,
+		PTZ1_FN, PTZ1_OUT, PTZ1_IN, 0,
+		PTZ0_FN, PTZ0_OUT, PTZ0_IN, 0 }
 	},
 
 	{ PINMUX_CFG_REG("PSEL0", 0xffec0070, 16, 1) {
-		PS0_15_FN3, PS0_15_FN1,
-		PS0_14_FN3, PS0_14_FN1,
-		PS0_13_FN3, PS0_13_FN1,
-		PS0_12_FN3, PS0_12_FN1,
-		0, 0,
-		0, 0,
-		0, 0,
+		PS0_15_FN1, PS0_15_FN2,
+		PS0_14_FN1, PS0_14_FN2,
+		PS0_13_FN1, PS0_13_FN2,
+		PS0_12_FN1, PS0_12_FN2,
+		PS0_11_FN1, PS0_11_FN2,
+		PS0_10_FN1, PS0_10_FN2,
+		PS0_9_FN1, PS0_9_FN2,
+		PS0_8_FN1, PS0_8_FN2,
+		PS0_7_FN1, PS0_7_FN2,
+		PS0_6_FN1, PS0_6_FN2,
+		PS0_5_FN1, PS0_5_FN2,
+		PS0_4_FN1, PS0_4_FN2,
+		PS0_3_FN1, PS0_3_FN2,
+		PS0_2_FN1, PS0_2_FN2,
 		0, 0,
-		PS0_7_FN2, PS0_7_FN1,
-		PS0_6_FN2, PS0_6_FN1,
-		PS0_5_FN2, PS0_5_FN1,
-		PS0_4_FN2, PS0_4_FN1,
-		PS0_3_FN2, PS0_3_FN1,
-		PS0_2_FN2, PS0_2_FN1,
-		PS0_1_FN2, PS0_1_FN1,
 		0, 0, }
 	},
 	{ PINMUX_CFG_REG("PSEL1", 0xffec0072, 16, 1) {
@@ -1795,74 +2009,136 @@
 		0, 0,
 		0, 0,
 		0, 0,
+		PS1_10_FN1, PS1_10_FN2,
+		PS1_9_FN1, PS1_9_FN2,
+		PS1_8_FN1, PS1_8_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
-		PS1_7_FN1, PS1_7_FN3,
-		PS1_6_FN1, PS1_6_FN3,
-		0, 0,
-		0, 0,
 		0, 0,
 		0, 0,
+		PS1_2_FN1, PS1_2_FN2,
 		0, 0,
 		0, 0, }
 	},
 	{ PINMUX_CFG_REG("PSEL2", 0xffec0074, 16, 1) {
 		0, 0,
 		0, 0,
-		PS2_13_FN3, PS2_13_FN1,
-		PS2_12_FN3, PS2_12_FN1,
+		PS2_13_FN1, PS2_13_FN2,
+		PS2_12_FN1, PS2_12_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
 		0, 0,
+		PS2_7_FN1, PS2_7_FN2,
+		PS2_6_FN1, PS2_6_FN2,
+		PS2_5_FN1, PS2_5_FN2,
+		PS2_4_FN1, PS2_4_FN2,
 		0, 0,
+		PS2_2_FN1, PS2_2_FN2,
 		0, 0,
+		0, 0, }
+	},
+	{ PINMUX_CFG_REG("PSEL3", 0xffec0076, 16, 1) {
+		PS3_15_FN1, PS3_15_FN2,
+		PS3_14_FN1, PS3_14_FN2,
+		PS3_13_FN1, PS3_13_FN2,
+		PS3_12_FN1, PS3_12_FN2,
+		PS3_11_FN1, PS3_11_FN2,
+		PS3_10_FN1, PS3_10_FN2,
+		PS3_9_FN1, PS3_9_FN2,
+		PS3_8_FN1, PS3_8_FN2,
+		PS3_7_FN1, PS3_7_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
 		0, 0,
-		PS2_1_FN1, PS2_1_FN2,
-		PS2_0_FN1, PS2_0_FN2, }
+		PS3_2_FN1, PS3_2_FN2,
+		PS3_1_FN1, PS3_1_FN2,
+		0, 0, }
 	},
+
 	{ PINMUX_CFG_REG("PSEL4", 0xffec0078, 16, 1) {
-		PS4_15_FN2, PS4_15_FN1,
-		PS4_14_FN2, PS4_14_FN1,
-		PS4_13_FN2, PS4_13_FN1,
-		PS4_12_FN2, PS4_12_FN1,
-		PS4_11_FN2, PS4_11_FN1,
-		PS4_10_FN2, PS4_10_FN1,
-		PS4_9_FN2, PS4_9_FN1,
 		0, 0,
+		PS4_14_FN1, PS4_14_FN2,
+		PS4_13_FN1, PS4_13_FN2,
+		PS4_12_FN1, PS4_12_FN2,
 		0, 0,
+		PS4_10_FN1, PS4_10_FN2,
+		PS4_9_FN1, PS4_9_FN2,
+		PS4_8_FN1, PS4_8_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
-		PS4_3_FN2, PS4_3_FN1,
-		PS4_2_FN2, PS4_2_FN1,
-		PS4_1_FN2, PS4_1_FN1,
-		PS4_0_FN2, PS4_0_FN1, }
+		PS4_4_FN1, PS4_4_FN2,
+		PS4_3_FN1, PS4_3_FN2,
+		PS4_2_FN1, PS4_2_FN2,
+		PS4_1_FN1, PS4_1_FN2,
+		PS4_0_FN1, PS4_0_FN2, }
 	},
 	{ PINMUX_CFG_REG("PSEL5", 0xffec007a, 16, 1) {
 		0, 0,
 		0, 0,
 		0, 0,
 		0, 0,
-		0, 0,
-		0, 0,
+		PS5_11_FN1, PS5_11_FN2,
+		PS5_10_FN1, PS5_10_FN2,
 		PS5_9_FN1, PS5_9_FN2,
 		PS5_8_FN1, PS5_8_FN2,
 		PS5_7_FN1, PS5_7_FN2,
 		PS5_6_FN1, PS5_6_FN2,
 		PS5_5_FN1, PS5_5_FN2,
+		PS5_4_FN1, PS5_4_FN2,
+		PS5_3_FN1, PS5_3_FN2,
+		PS5_2_FN1, PS5_2_FN2,
+		0, 0,
+		0, 0, }
+	},
+	{ PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
+		PS6_15_FN1, PS6_15_FN2,
+		PS6_14_FN1, PS6_14_FN2,
+		PS6_13_FN1, PS6_13_FN2,
+		PS6_12_FN1, PS6_12_FN2,
+		PS6_11_FN1, PS6_11_FN2,
+		PS6_10_FN1, PS6_10_FN2,
+		PS6_9_FN1, PS6_9_FN2,
+		PS6_8_FN1, PS6_8_FN2,
+		PS6_7_FN1, PS6_7_FN2,
+		PS6_6_FN1, PS6_6_FN2,
+		PS6_5_FN1, PS6_5_FN2,
+		PS6_4_FN1, PS6_4_FN2,
+		PS6_3_FN1, PS6_3_FN2,
+		PS6_2_FN1, PS6_2_FN2,
+		PS6_1_FN1, PS6_1_FN2,
+		PS6_0_FN1, PS6_0_FN2, }
+	},
+	{ PINMUX_CFG_REG("PSEL7", 0xffec0082, 16, 1) {
+		PS7_15_FN1, PS7_15_FN2,
+		PS7_14_FN1, PS7_14_FN2,
+		PS7_13_FN1, PS7_13_FN2,
+		PS7_12_FN1, PS7_12_FN2,
+		PS7_11_FN1, PS7_11_FN2,
+		PS7_10_FN1, PS7_10_FN2,
+		PS7_9_FN1, PS7_9_FN2,
+		PS7_8_FN1, PS7_8_FN2,
+		PS7_7_FN1, PS7_7_FN2,
+		PS7_6_FN1, PS7_6_FN2,
+		PS7_5_FN1, PS7_5_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
 		0, 0,
 		0, 0, }
 	},
-	{ PINMUX_CFG_REG("PSEL6", 0xffec007c, 16, 1) {
-		0, 0,
+	{ PINMUX_CFG_REG("PSEL8", 0xffec0084, 16, 1) {
+		PS8_15_FN1, PS8_15_FN2,
+		PS8_14_FN1, PS8_14_FN2,
+		PS8_13_FN1, PS8_13_FN2,
+		PS8_12_FN1, PS8_12_FN2,
+		PS8_11_FN1, PS8_11_FN2,
+		PS8_10_FN1, PS8_10_FN2,
+		PS8_9_FN1, PS8_9_FN2,
+		PS8_8_FN1, PS8_8_FN2,
 		0, 0,
 		0, 0,
 		0, 0,
@@ -1870,14 +2146,7 @@
 		0, 0,
 		0, 0,
 		0, 0,
-		PS6_7_FN_AN, PS6_7_FN_EV,
-		PS6_6_FN_AN, PS6_6_FN_EV,
-		PS6_5_FN_AN, PS6_5_FN_EV,
-		PS6_4_FN_AN, PS6_4_FN_EV,
-		PS6_3_FN_AN, PS6_3_FN_EV,
-		PS6_2_FN_AN, PS6_2_FN_EV,
-		PS6_1_FN_AN, PS6_1_FN_EV,
-		PS6_0_FN_AN, PS6_0_FN_EV, }
+		0, 0, }
 	},
 	{}
 };
@@ -1920,7 +2189,7 @@
 		PTI3_DATA, PTI2_DATA, PTI1_DATA, PTI0_DATA }
 	},
 	{ PINMUX_DATA_REG("PJDR", 0xffec0046, 8) {
-		PTJ7_DATA, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
+		0, PTJ6_DATA, PTJ5_DATA, PTJ4_DATA,
 		PTJ3_DATA, PTJ2_DATA, PTJ1_DATA, PTJ0_DATA }
 	},
 	{ PINMUX_DATA_REG("PKDR", 0xffec0048, 8) {
@@ -1928,15 +2197,15 @@
 		PTK3_DATA, PTK2_DATA, PTK1_DATA, PTK0_DATA }
 	},
 	{ PINMUX_DATA_REG("PLDR", 0xffec004a, 8) {
-		PTL7_DATA, PTL6_DATA, PTL5_DATA, PTL4_DATA,
+		0, PTL6_DATA, PTL5_DATA, PTL4_DATA,
 		PTL3_DATA, PTL2_DATA, PTL1_DATA, PTL0_DATA }
 	},
 	{ PINMUX_DATA_REG("PMDR", 0xffec004c, 8) {
-		0, PTM6_DATA, PTM5_DATA, PTM4_DATA,
+		PTM7_DATA, PTM6_DATA, PTM5_DATA, PTM4_DATA,
 		PTM3_DATA, PTM2_DATA, PTM1_DATA, PTM0_DATA }
 	},
 	{ PINMUX_DATA_REG("PNDR", 0xffec004e, 8) {
-		PTN7_DATA, PTN6_DATA, PTN5_DATA, PTN4_DATA,
+		0, PTN6_DATA, PTN5_DATA, PTN4_DATA,
 		PTN3_DATA, PTN2_DATA, PTN1_DATA, PTN0_DATA }
 	},
 	{ PINMUX_DATA_REG("PODR", 0xffec0050, 8) {
@@ -1944,7 +2213,7 @@
 		PTO3_DATA, PTO2_DATA, PTO1_DATA, PTO0_DATA }
 	},
 	{ PINMUX_DATA_REG("PPDR", 0xffec0052, 8) {
-		0, PTP6_DATA, PTP5_DATA, PTP4_DATA,
+		PTP7_DATA, PTP6_DATA, PTP5_DATA, PTP4_DATA,
 		PTP3_DATA, PTP2_DATA, PTP1_DATA, PTP0_DATA }
 	},
 	{ PINMUX_DATA_REG("PQDR", 0xffec0054, 8) {
@@ -1960,7 +2229,7 @@
 		PTS3_DATA, PTS2_DATA, PTS1_DATA, PTS0_DATA }
 	},
 	{ PINMUX_DATA_REG("PTDR", 0xffec005a, 8) {
-		0, 0, PTT5_DATA, PTT4_DATA,
+		PTT7_DATA, PTT6_DATA, PTT5_DATA, PTT4_DATA,
 		PTT3_DATA, PTT2_DATA, PTT1_DATA, PTT0_DATA }
 	},
 	{ PINMUX_DATA_REG("PUDR", 0xffec005c, 8) {
@@ -2000,8 +2269,8 @@
 	.mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
 	.function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
 
-	.first_gpio = GPIO_PTA7,
-	.last_gpio = GPIO_FN_D0,
+	.first_gpio = GPIO_PTA0,
+	.last_gpio = GPIO_FN_ON_DQ0,
 
 	.gpios = pinmux_gpios,
 	.cfg_regs = pinmux_config_regs,
@@ -2015,5 +2284,4 @@
 {
 	return register_pinmux(&sh7757_pinmux_info);
 }
-
 arch_initcall(plat_pinmux_setup);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/pinmux-shx3.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,587 @@
+/*
+ * SH-X3 prototype CPU pinmux
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/shx3.h>
+
+enum {
+	PINMUX_RESERVED = 0,
+
+	PINMUX_DATA_BEGIN,
+	PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+	PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+	PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+	PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA,
+	PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+	PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+	PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+	PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+	PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+	PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+	PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+	PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+	PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+	PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+
+	PH5_DATA, PH4_DATA,
+	PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+	PINMUX_DATA_END,
+
+	PINMUX_INPUT_BEGIN,
+	PA7_IN, PA6_IN, PA5_IN, PA4_IN,
+	PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+	PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+	PB3_IN, PB2_IN, PB1_IN, PB0_IN,
+	PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+	PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+	PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+	PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+	PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+	PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+	PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+	PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+	PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+	PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+
+	PH5_IN, PH4_IN,
+	PH3_IN, PH2_IN, PH1_IN, PH0_IN,
+	PINMUX_INPUT_END,
+
+	PINMUX_INPUT_PULLUP_BEGIN,
+	PA7_IN_PU, PA6_IN_PU, PA5_IN_PU, PA4_IN_PU,
+	PA3_IN_PU, PA2_IN_PU, PA1_IN_PU, PA0_IN_PU,
+	PB7_IN_PU, PB6_IN_PU, PB5_IN_PU, PB4_IN_PU,
+	PB3_IN_PU, PB2_IN_PU, PB1_IN_PU, PB0_IN_PU,
+	PC7_IN_PU, PC6_IN_PU, PC5_IN_PU, PC4_IN_PU,
+	PC3_IN_PU, PC2_IN_PU, PC1_IN_PU, PC0_IN_PU,
+	PD7_IN_PU, PD6_IN_PU, PD5_IN_PU, PD4_IN_PU,
+	PD3_IN_PU, PD2_IN_PU, PD1_IN_PU, PD0_IN_PU,
+	PE7_IN_PU, PE6_IN_PU, PE5_IN_PU, PE4_IN_PU,
+	PE3_IN_PU, PE2_IN_PU, PE1_IN_PU, PE0_IN_PU,
+	PF7_IN_PU, PF6_IN_PU, PF5_IN_PU, PF4_IN_PU,
+	PF3_IN_PU, PF2_IN_PU, PF1_IN_PU, PF0_IN_PU,
+	PG7_IN_PU, PG6_IN_PU, PG5_IN_PU, PG4_IN_PU,
+	PG3_IN_PU, PG2_IN_PU, PG1_IN_PU, PG0_IN_PU,
+
+	PH5_IN_PU, PH4_IN_PU,
+	PH3_IN_PU, PH2_IN_PU, PH1_IN_PU, PH0_IN_PU,
+	PINMUX_INPUT_PULLUP_END,
+
+	PINMUX_OUTPUT_BEGIN,
+	PA7_OUT, PA6_OUT, PA5_OUT, PA4_OUT,
+	PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+	PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+	PB3_OUT, PB2_OUT, PB1_OUT, PB0_OUT,
+	PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+	PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+	PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+	PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+	PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+	PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+	PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+	PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+	PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+	PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+
+	PH5_OUT, PH4_OUT,
+	PH3_OUT, PH2_OUT, PH1_OUT, PH0_OUT,
+	PINMUX_OUTPUT_END,
+
+	PINMUX_FUNCTION_BEGIN,
+	PA7_FN, PA6_FN, PA5_FN, PA4_FN,
+	PA3_FN, PA2_FN, PA1_FN, PA0_FN,
+	PB7_FN, PB6_FN, PB5_FN, PB4_FN,
+	PB3_FN, PB2_FN, PB1_FN, PB0_FN,
+	PC7_FN, PC6_FN, PC5_FN, PC4_FN,
+	PC3_FN, PC2_FN, PC1_FN, PC0_FN,
+	PD7_FN, PD6_FN, PD5_FN, PD4_FN,
+	PD3_FN, PD2_FN, PD1_FN, PD0_FN,
+	PE7_FN, PE6_FN, PE5_FN, PE4_FN,
+	PE3_FN, PE2_FN, PE1_FN, PE0_FN,
+	PF7_FN, PF6_FN, PF5_FN, PF4_FN,
+	PF3_FN, PF2_FN, PF1_FN, PF0_FN,
+	PG7_FN, PG6_FN, PG5_FN, PG4_FN,
+	PG3_FN, PG2_FN, PG1_FN, PG0_FN,
+
+	PH5_FN, PH4_FN,
+	PH3_FN, PH2_FN, PH1_FN, PH0_FN,
+	PINMUX_FUNCTION_END,
+
+	PINMUX_MARK_BEGIN,
+
+	D31_MARK, D30_MARK, D29_MARK, D28_MARK, D27_MARK, D26_MARK,
+	D25_MARK, D24_MARK, D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+	D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+
+	BACK_MARK, BREQ_MARK,
+	WE3_MARK, WE2_MARK,
+	CS6_MARK, CS5_MARK, CS4_MARK,
+	CLKOUTENB_MARK,
+
+	DACK3_MARK, DACK2_MARK, DACK1_MARK, DACK0_MARK,
+	DREQ3_MARK, DREQ2_MARK, DREQ1_MARK, DREQ0_MARK,
+
+	IRQ3_MARK, IRQ2_MARK, IRQ1_MARK, IRQ0_MARK,
+
+	DRAK3_MARK, DRAK2_MARK, DRAK1_MARK, DRAK0_MARK,
+
+	SCK3_MARK, SCK2_MARK, SCK1_MARK, SCK0_MARK,
+	IRL3_MARK, IRL2_MARK, IRL1_MARK, IRL0_MARK,
+	TXD3_MARK, TXD2_MARK, TXD1_MARK, TXD0_MARK,
+	RXD3_MARK, RXD2_MARK, RXD1_MARK, RXD0_MARK,
+
+	CE2B_MARK, CE2A_MARK, IOIS16_MARK,
+	STATUS1_MARK, STATUS0_MARK,
+
+	IRQOUT_MARK,
+
+	PINMUX_MARK_END,
+};
+
+static pinmux_enum_t shx3_pinmux_data[] = {
+
+	/* PA GPIO */
+	PINMUX_DATA(PA7_DATA, PA7_IN, PA7_OUT, PA7_IN_PU),
+	PINMUX_DATA(PA6_DATA, PA6_IN, PA6_OUT, PA6_IN_PU),
+	PINMUX_DATA(PA5_DATA, PA5_IN, PA5_OUT, PA5_IN_PU),
+	PINMUX_DATA(PA4_DATA, PA4_IN, PA4_OUT, PA4_IN_PU),
+	PINMUX_DATA(PA3_DATA, PA3_IN, PA3_OUT, PA3_IN_PU),
+	PINMUX_DATA(PA2_DATA, PA2_IN, PA2_OUT, PA2_IN_PU),
+	PINMUX_DATA(PA1_DATA, PA1_IN, PA1_OUT, PA1_IN_PU),
+	PINMUX_DATA(PA0_DATA, PA0_IN, PA0_OUT, PA0_IN_PU),
+
+	/* PB GPIO */
+	PINMUX_DATA(PB7_DATA, PB7_IN, PB7_OUT, PB7_IN_PU),
+	PINMUX_DATA(PB6_DATA, PB6_IN, PB6_OUT, PB6_IN_PU),
+	PINMUX_DATA(PB5_DATA, PB5_IN, PB5_OUT, PB5_IN_PU),
+	PINMUX_DATA(PB4_DATA, PB4_IN, PB4_OUT, PB4_IN_PU),
+	PINMUX_DATA(PB3_DATA, PB3_IN, PB3_OUT, PB3_IN_PU),
+	PINMUX_DATA(PB2_DATA, PB2_IN, PB2_OUT, PB2_IN_PU),
+	PINMUX_DATA(PB1_DATA, PB1_IN, PB1_OUT, PB1_IN_PU),
+	PINMUX_DATA(PB0_DATA, PB0_IN, PB0_OUT, PB0_IN_PU),
+
+	/* PC GPIO */
+	PINMUX_DATA(PC7_DATA, PC7_IN, PC7_OUT, PC7_IN_PU),
+	PINMUX_DATA(PC6_DATA, PC6_IN, PC6_OUT, PC6_IN_PU),
+	PINMUX_DATA(PC5_DATA, PC5_IN, PC5_OUT, PC5_IN_PU),
+	PINMUX_DATA(PC4_DATA, PC4_IN, PC4_OUT, PC4_IN_PU),
+	PINMUX_DATA(PC3_DATA, PC3_IN, PC3_OUT, PC3_IN_PU),
+	PINMUX_DATA(PC2_DATA, PC2_IN, PC2_OUT, PC2_IN_PU),
+	PINMUX_DATA(PC1_DATA, PC1_IN, PC1_OUT, PC1_IN_PU),
+	PINMUX_DATA(PC0_DATA, PC0_IN, PC0_OUT, PC0_IN_PU),
+
+	/* PD GPIO */
+	PINMUX_DATA(PD7_DATA, PD7_IN, PD7_OUT, PD7_IN_PU),
+	PINMUX_DATA(PD6_DATA, PD6_IN, PD6_OUT, PD6_IN_PU),
+	PINMUX_DATA(PD5_DATA, PD5_IN, PD5_OUT, PD5_IN_PU),
+	PINMUX_DATA(PD4_DATA, PD4_IN, PD4_OUT, PD4_IN_PU),
+	PINMUX_DATA(PD3_DATA, PD3_IN, PD3_OUT, PD3_IN_PU),
+	PINMUX_DATA(PD2_DATA, PD2_IN, PD2_OUT, PD2_IN_PU),
+	PINMUX_DATA(PD1_DATA, PD1_IN, PD1_OUT, PD1_IN_PU),
+	PINMUX_DATA(PD0_DATA, PD0_IN, PD0_OUT, PD0_IN_PU),
+
+	/* PE GPIO */
+	PINMUX_DATA(PE7_DATA, PE7_IN, PE7_OUT, PE7_IN_PU),
+	PINMUX_DATA(PE6_DATA, PE6_IN, PE6_OUT, PE6_IN_PU),
+	PINMUX_DATA(PE5_DATA, PE5_IN, PE5_OUT, PE5_IN_PU),
+	PINMUX_DATA(PE4_DATA, PE4_IN, PE4_OUT, PE4_IN_PU),
+	PINMUX_DATA(PE3_DATA, PE3_IN, PE3_OUT, PE3_IN_PU),
+	PINMUX_DATA(PE2_DATA, PE2_IN, PE2_OUT, PE2_IN_PU),
+	PINMUX_DATA(PE1_DATA, PE1_IN, PE1_OUT, PE1_IN_PU),
+	PINMUX_DATA(PE0_DATA, PE0_IN, PE0_OUT, PE0_IN_PU),
+
+	/* PF GPIO */
+	PINMUX_DATA(PF7_DATA, PF7_IN, PF7_OUT, PF7_IN_PU),
+	PINMUX_DATA(PF6_DATA, PF6_IN, PF6_OUT, PF6_IN_PU),
+	PINMUX_DATA(PF5_DATA, PF5_IN, PF5_OUT, PF5_IN_PU),
+	PINMUX_DATA(PF4_DATA, PF4_IN, PF4_OUT, PF4_IN_PU),
+	PINMUX_DATA(PF3_DATA, PF3_IN, PF3_OUT, PF3_IN_PU),
+	PINMUX_DATA(PF2_DATA, PF2_IN, PF2_OUT, PF2_IN_PU),
+	PINMUX_DATA(PF1_DATA, PF1_IN, PF1_OUT, PF1_IN_PU),
+	PINMUX_DATA(PF0_DATA, PF0_IN, PF0_OUT, PF0_IN_PU),
+
+	/* PG GPIO */
+	PINMUX_DATA(PG7_DATA, PG7_IN, PG7_OUT, PG7_IN_PU),
+	PINMUX_DATA(PG6_DATA, PG6_IN, PG6_OUT, PG6_IN_PU),
+	PINMUX_DATA(PG5_DATA, PG5_IN, PG5_OUT, PG5_IN_PU),
+	PINMUX_DATA(PG4_DATA, PG4_IN, PG4_OUT, PG4_IN_PU),
+	PINMUX_DATA(PG3_DATA, PG3_IN, PG3_OUT, PG3_IN_PU),
+	PINMUX_DATA(PG2_DATA, PG2_IN, PG2_OUT, PG2_IN_PU),
+	PINMUX_DATA(PG1_DATA, PG1_IN, PG1_OUT, PG1_IN_PU),
+	PINMUX_DATA(PG0_DATA, PG0_IN, PG0_OUT, PG0_IN_PU),
+
+	/* PH GPIO */
+	PINMUX_DATA(PH5_DATA, PH5_IN, PH5_OUT, PH5_IN_PU),
+	PINMUX_DATA(PH4_DATA, PH4_IN, PH4_OUT, PH4_IN_PU),
+	PINMUX_DATA(PH3_DATA, PH3_IN, PH3_OUT, PH3_IN_PU),
+	PINMUX_DATA(PH2_DATA, PH2_IN, PH2_OUT, PH2_IN_PU),
+	PINMUX_DATA(PH1_DATA, PH1_IN, PH1_OUT, PH1_IN_PU),
+	PINMUX_DATA(PH0_DATA, PH0_IN, PH0_OUT, PH0_IN_PU),
+
+	/* PA FN */
+	PINMUX_DATA(D31_MARK, PA7_FN),
+	PINMUX_DATA(D30_MARK, PA6_FN),
+	PINMUX_DATA(D29_MARK, PA5_FN),
+	PINMUX_DATA(D28_MARK, PA4_FN),
+	PINMUX_DATA(D27_MARK, PA3_FN),
+	PINMUX_DATA(D26_MARK, PA2_FN),
+	PINMUX_DATA(D25_MARK, PA1_FN),
+	PINMUX_DATA(D24_MARK, PA0_FN),
+
+	/* PB FN */
+	PINMUX_DATA(D23_MARK, PB7_FN),
+	PINMUX_DATA(D22_MARK, PB6_FN),
+	PINMUX_DATA(D21_MARK, PB5_FN),
+	PINMUX_DATA(D20_MARK, PB4_FN),
+	PINMUX_DATA(D19_MARK, PB3_FN),
+	PINMUX_DATA(D18_MARK, PB2_FN),
+	PINMUX_DATA(D17_MARK, PB1_FN),
+	PINMUX_DATA(D16_MARK, PB0_FN),
+
+	/* PC FN */
+	PINMUX_DATA(BACK_MARK,		PC7_FN),
+	PINMUX_DATA(BREQ_MARK,		PC6_FN),
+	PINMUX_DATA(WE3_MARK,		PC5_FN),
+	PINMUX_DATA(WE2_MARK,		PC4_FN),
+	PINMUX_DATA(CS6_MARK,		PC3_FN),
+	PINMUX_DATA(CS5_MARK,		PC2_FN),
+	PINMUX_DATA(CS4_MARK,		PC1_FN),
+	PINMUX_DATA(CLKOUTENB_MARK,	PC0_FN),
+
+	/* PD FN */
+	PINMUX_DATA(DACK3_MARK,	PD7_FN),
+	PINMUX_DATA(DACK2_MARK, PD6_FN),
+	PINMUX_DATA(DACK1_MARK, PD5_FN),
+	PINMUX_DATA(DACK0_MARK, PD4_FN),
+	PINMUX_DATA(DREQ3_MARK, PD3_FN),
+	PINMUX_DATA(DREQ2_MARK, PD2_FN),
+	PINMUX_DATA(DREQ1_MARK, PD1_FN),
+	PINMUX_DATA(DREQ0_MARK, PD0_FN),
+
+	/* PE FN */
+	PINMUX_DATA(IRQ3_MARK,	PE7_FN),
+	PINMUX_DATA(IRQ2_MARK,	PE6_FN),
+	PINMUX_DATA(IRQ1_MARK,	PE5_FN),
+	PINMUX_DATA(IRQ0_MARK,	PE4_FN),
+	PINMUX_DATA(DRAK3_MARK, PE3_FN),
+	PINMUX_DATA(DRAK2_MARK, PE2_FN),
+	PINMUX_DATA(DRAK1_MARK, PE1_FN),
+	PINMUX_DATA(DRAK0_MARK, PE0_FN),
+
+	/* PF FN */
+	PINMUX_DATA(SCK3_MARK, PF7_FN),
+	PINMUX_DATA(SCK2_MARK, PF6_FN),
+	PINMUX_DATA(SCK1_MARK, PF5_FN),
+	PINMUX_DATA(SCK0_MARK, PF4_FN),
+	PINMUX_DATA(IRL3_MARK, PF3_FN),
+	PINMUX_DATA(IRL2_MARK, PF2_FN),
+	PINMUX_DATA(IRL1_MARK, PF1_FN),
+	PINMUX_DATA(IRL0_MARK, PF0_FN),
+
+	/* PG FN */
+	PINMUX_DATA(TXD3_MARK, PG7_FN),
+	PINMUX_DATA(TXD2_MARK, PG6_FN),
+	PINMUX_DATA(TXD1_MARK, PG5_FN),
+	PINMUX_DATA(TXD0_MARK, PG4_FN),
+	PINMUX_DATA(RXD3_MARK, PG3_FN),
+	PINMUX_DATA(RXD2_MARK, PG2_FN),
+	PINMUX_DATA(RXD1_MARK, PG1_FN),
+	PINMUX_DATA(RXD0_MARK, PG0_FN),
+
+	/* PH FN */
+	PINMUX_DATA(CE2B_MARK,		PH5_FN),
+	PINMUX_DATA(CE2A_MARK,		PH4_FN),
+	PINMUX_DATA(IOIS16_MARK,	PH3_FN),
+	PINMUX_DATA(STATUS1_MARK,	PH2_FN),
+	PINMUX_DATA(STATUS0_MARK,	PH1_FN),
+	PINMUX_DATA(IRQOUT_MARK,	PH0_FN),
+};
+
+static struct pinmux_gpio shx3_pinmux_gpios[] = {
+	/* PA */
+	PINMUX_GPIO(GPIO_PA7, PA7_DATA),
+	PINMUX_GPIO(GPIO_PA6, PA6_DATA),
+	PINMUX_GPIO(GPIO_PA5, PA5_DATA),
+	PINMUX_GPIO(GPIO_PA4, PA4_DATA),
+	PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+	PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+	PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+	PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+	/* PB */
+	PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+	PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+	PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+	PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+	PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+	PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+	PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+	PINMUX_GPIO(GPIO_PB0, PB0_DATA),
+
+	/* PC */
+	PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+	PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+	PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+	PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+	PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+	PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+	PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+	PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+	/* PD */
+	PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+	PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+	PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+	PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+	PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+	PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+	PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+	PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+	/* PE */
+	PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+	PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+	PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+	PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+	PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+	PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+	PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+	PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+	/* PF */
+	PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+	PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+	PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+	PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+	PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+	PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+	PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+	PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+	/* PG */
+	PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+	PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+	PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+	PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+	PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+	PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+	PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+	PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+	/* PH */
+	PINMUX_GPIO(GPIO_PH5, PH5_DATA),
+	PINMUX_GPIO(GPIO_PH4, PH4_DATA),
+	PINMUX_GPIO(GPIO_PH3, PH3_DATA),
+	PINMUX_GPIO(GPIO_PH2, PH2_DATA),
+	PINMUX_GPIO(GPIO_PH1, PH1_DATA),
+	PINMUX_GPIO(GPIO_PH0, PH0_DATA),
+
+	/* FN */
+	PINMUX_GPIO(GPIO_FN_D31,	D31_MARK),
+	PINMUX_GPIO(GPIO_FN_D30,	D30_MARK),
+	PINMUX_GPIO(GPIO_FN_D29,	D29_MARK),
+	PINMUX_GPIO(GPIO_FN_D28,	D28_MARK),
+	PINMUX_GPIO(GPIO_FN_D27,	D27_MARK),
+	PINMUX_GPIO(GPIO_FN_D26,	D26_MARK),
+	PINMUX_GPIO(GPIO_FN_D25,	D25_MARK),
+	PINMUX_GPIO(GPIO_FN_D24,	D24_MARK),
+	PINMUX_GPIO(GPIO_FN_D23,	D23_MARK),
+	PINMUX_GPIO(GPIO_FN_D22,	D22_MARK),
+	PINMUX_GPIO(GPIO_FN_D21,	D21_MARK),
+	PINMUX_GPIO(GPIO_FN_D20,	D20_MARK),
+	PINMUX_GPIO(GPIO_FN_D19,	D19_MARK),
+	PINMUX_GPIO(GPIO_FN_D18,	D18_MARK),
+	PINMUX_GPIO(GPIO_FN_D17,	D17_MARK),
+	PINMUX_GPIO(GPIO_FN_D16,	D16_MARK),
+	PINMUX_GPIO(GPIO_FN_BACK,	BACK_MARK),
+	PINMUX_GPIO(GPIO_FN_BREQ,	BREQ_MARK),
+	PINMUX_GPIO(GPIO_FN_WE3,	WE3_MARK),
+	PINMUX_GPIO(GPIO_FN_WE2,	WE2_MARK),
+	PINMUX_GPIO(GPIO_FN_CS6,	CS6_MARK),
+	PINMUX_GPIO(GPIO_FN_CS5,	CS5_MARK),
+	PINMUX_GPIO(GPIO_FN_CS4,	CS4_MARK),
+	PINMUX_GPIO(GPIO_FN_CLKOUTENB,	CLKOUTENB_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK3,	DACK3_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK2,	DACK2_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK1,	DACK1_MARK),
+	PINMUX_GPIO(GPIO_FN_DACK0,	DACK0_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ3,	DREQ3_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ2,	DREQ2_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ1,	DREQ1_MARK),
+	PINMUX_GPIO(GPIO_FN_DREQ0,	DREQ0_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ3,	IRQ3_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ2,	IRQ2_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ1,	IRQ1_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQ0,	IRQ0_MARK),
+	PINMUX_GPIO(GPIO_FN_DRAK3,	DRAK3_MARK),
+	PINMUX_GPIO(GPIO_FN_DRAK2,	DRAK2_MARK),
+	PINMUX_GPIO(GPIO_FN_DRAK1,	DRAK1_MARK),
+	PINMUX_GPIO(GPIO_FN_DRAK0,	DRAK0_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK3,	SCK3_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK2,	SCK2_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK1,	SCK1_MARK),
+	PINMUX_GPIO(GPIO_FN_SCK0,	SCK0_MARK),
+	PINMUX_GPIO(GPIO_FN_IRL3,	IRL3_MARK),
+	PINMUX_GPIO(GPIO_FN_IRL2,	IRL2_MARK),
+	PINMUX_GPIO(GPIO_FN_IRL1,	IRL1_MARK),
+	PINMUX_GPIO(GPIO_FN_IRL0,	IRL0_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD3,	TXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD2,	TXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD1,	TXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_TXD0,	TXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD3,	RXD3_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD2,	RXD2_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD1,	RXD1_MARK),
+	PINMUX_GPIO(GPIO_FN_RXD0,	RXD0_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2B,	CE2B_MARK),
+	PINMUX_GPIO(GPIO_FN_CE2A,	CE2A_MARK),
+	PINMUX_GPIO(GPIO_FN_IOIS16,	IOIS16_MARK),
+	PINMUX_GPIO(GPIO_FN_STATUS1,	STATUS1_MARK),
+	PINMUX_GPIO(GPIO_FN_STATUS0,	STATUS0_MARK),
+	PINMUX_GPIO(GPIO_FN_IRQOUT,	IRQOUT_MARK),
+};
+
+static struct pinmux_cfg_reg shx3_pinmux_config_regs[] = {
+	{ PINMUX_CFG_REG("PABCR", 0xffc70000, 32, 2) {
+		PA7_FN, PA7_OUT, PA7_IN, PA7_IN_PU,
+		PA6_FN, PA6_OUT, PA6_IN, PA6_IN_PU,
+		PA5_FN, PA5_OUT, PA5_IN, PA5_IN_PU,
+		PA4_FN, PA4_OUT, PA4_IN, PA4_IN_PU,
+		PA3_FN, PA3_OUT, PA3_IN, PA3_IN_PU,
+		PA2_FN, PA2_OUT, PA2_IN, PA2_IN_PU,
+		PA1_FN, PA1_OUT, PA1_IN, PA1_IN_PU,
+		PA0_FN, PA0_OUT, PA0_IN, PA0_IN_PU,
+		PB7_FN, PB7_OUT, PB7_IN, PB7_IN_PU,
+		PB6_FN, PB6_OUT, PB6_IN, PB6_IN_PU,
+		PB5_FN, PB5_OUT, PB5_IN, PB5_IN_PU,
+		PB4_FN, PB4_OUT, PB4_IN, PB4_IN_PU,
+		PB3_FN, PB3_OUT, PB3_IN, PB3_IN_PU,
+		PB2_FN, PB2_OUT, PB2_IN, PB2_IN_PU,
+		PB1_FN, PB1_OUT, PB1_IN, PB1_IN_PU,
+		PB0_FN, PB0_OUT, PB0_IN, PB0_IN_PU, },
+	},
+	{ PINMUX_CFG_REG("PCDCR", 0xffc70004, 32, 2) {
+		PC7_FN, PC7_OUT, PC7_IN, PC7_IN_PU,
+		PC6_FN, PC6_OUT, PC6_IN, PC6_IN_PU,
+		PC5_FN, PC5_OUT, PC5_IN, PC5_IN_PU,
+		PC4_FN, PC4_OUT, PC4_IN, PC4_IN_PU,
+		PC3_FN, PC3_OUT, PC3_IN, PC3_IN_PU,
+		PC2_FN, PC2_OUT, PC2_IN, PC2_IN_PU,
+		PC1_FN, PC1_OUT, PC1_IN, PC1_IN_PU,
+		PC0_FN, PC0_OUT, PC0_IN, PC0_IN_PU,
+		PD7_FN, PD7_OUT, PD7_IN, PD7_IN_PU,
+		PD6_FN, PD6_OUT, PD6_IN, PD6_IN_PU,
+		PD5_FN, PD5_OUT, PD5_IN, PD5_IN_PU,
+		PD4_FN, PD4_OUT, PD4_IN, PD4_IN_PU,
+		PD3_FN, PD3_OUT, PD3_IN, PD3_IN_PU,
+		PD2_FN, PD2_OUT, PD2_IN, PD2_IN_PU,
+		PD1_FN, PD1_OUT, PD1_IN, PD1_IN_PU,
+		PD0_FN, PD0_OUT, PD0_IN, PD0_IN_PU, },
+	},
+	{ PINMUX_CFG_REG("PEFCR", 0xffc70008, 32, 2) {
+		PE7_FN, PE7_OUT, PE7_IN, PE7_IN_PU,
+		PE6_FN, PE6_OUT, PE6_IN, PE6_IN_PU,
+		PE5_FN, PE5_OUT, PE5_IN, PE5_IN_PU,
+		PE4_FN, PE4_OUT, PE4_IN, PE4_IN_PU,
+		PE3_FN, PE3_OUT, PE3_IN, PE3_IN_PU,
+		PE2_FN, PE2_OUT, PE2_IN, PE2_IN_PU,
+		PE1_FN, PE1_OUT, PE1_IN, PE1_IN_PU,
+		PE0_FN, PE0_OUT, PE0_IN, PE0_IN_PU,
+		PF7_FN, PF7_OUT, PF7_IN, PF7_IN_PU,
+		PF6_FN, PF6_OUT, PF6_IN, PF6_IN_PU,
+		PF5_FN, PF5_OUT, PF5_IN, PF5_IN_PU,
+		PF4_FN, PF4_OUT, PF4_IN, PF4_IN_PU,
+		PF3_FN, PF3_OUT, PF3_IN, PF3_IN_PU,
+		PF2_FN, PF2_OUT, PF2_IN, PF2_IN_PU,
+		PF1_FN, PF1_OUT, PF1_IN, PF1_IN_PU,
+		PF0_FN, PF0_OUT, PF0_IN, PF0_IN_PU, },
+	},
+	{ PINMUX_CFG_REG("PGHCR", 0xffc7000c, 32, 2) {
+		PG7_FN, PG7_OUT, PG7_IN, PG7_IN_PU,
+		PG6_FN, PG6_OUT, PG6_IN, PG6_IN_PU,
+		PG5_FN, PG5_OUT, PG5_IN, PG5_IN_PU,
+		PG4_FN, PG4_OUT, PG4_IN, PG4_IN_PU,
+		PG3_FN, PG3_OUT, PG3_IN, PG3_IN_PU,
+		PG2_FN, PG2_OUT, PG2_IN, PG2_IN_PU,
+		PG1_FN, PG1_OUT, PG1_IN, PG1_IN_PU,
+		PG0_FN, PG0_OUT, PG0_IN, PG0_IN_PU,
+		0, 0, 0, 0,
+		0, 0, 0, 0,
+		PH5_FN, PH5_OUT, PH5_IN, PH5_IN_PU,
+		PH4_FN, PH4_OUT, PH4_IN, PH4_IN_PU,
+		PH3_FN, PH3_OUT, PH3_IN, PH3_IN_PU,
+		PH2_FN, PH2_OUT, PH2_IN, PH2_IN_PU,
+		PH1_FN, PH1_OUT, PH1_IN, PH1_IN_PU,
+		PH0_FN, PH0_OUT, PH0_IN, PH0_IN_PU, },
+	},
+	{ },
+};
+
+static struct pinmux_data_reg shx3_pinmux_data_regs[] = {
+	{ PINMUX_DATA_REG("PABDR", 0xffc70010, 32) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PA7_DATA, PA6_DATA, PA5_DATA, PA4_DATA,
+		PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+		PB3_DATA, PB2_DATA, PB1_DATA, PB0_DATA, },
+	},
+	{ PINMUX_DATA_REG("PCDDR", 0xffc70014, 32) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+		PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+		PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA, },
+	},
+	{ PINMUX_DATA_REG("PEFDR", 0xffc70018, 32) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+		PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+		PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA, },
+	},
+	{ PINMUX_DATA_REG("PGHDR", 0xffc7001c, 32) {
+		0, 0, 0, 0, 0, 0, 0, 0,
+		PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+		PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, PH5_DATA, PH4_DATA,
+		PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA, },
+	},
+	{ },
+};
+
+static struct pinmux_info shx3_pinmux_info = {
+	.name		= "shx3_pfc",
+	.reserved_id	= PINMUX_RESERVED,
+	.data		= { PINMUX_DATA_BEGIN,	   PINMUX_DATA_END },
+	.input		= { PINMUX_INPUT_BEGIN,	   PINMUX_INPUT_END },
+	.input_pu	= { PINMUX_INPUT_PULLUP_BEGIN,
+			    PINMUX_INPUT_PULLUP_END },
+	.output		= { PINMUX_OUTPUT_BEGIN,   PINMUX_OUTPUT_END },
+	.mark		= { PINMUX_MARK_BEGIN,     PINMUX_MARK_END },
+	.function	= { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+	.first_gpio	= GPIO_PA7,
+	.last_gpio	= GPIO_FN_IRQOUT,
+	.gpios		= shx3_pinmux_gpios,
+	.gpio_data	= shx3_pinmux_data,
+	.gpio_data_size	= ARRAY_SIZE(shx3_pinmux_data),
+	.cfg_regs	= shx3_pinmux_config_regs,
+	.data_regs	= shx3_pinmux_data_regs,
+};
+
+static int __init shx3_pinmux_setup(void)
+{
+	return register_pinmux(&shx3_pinmux_info);
+}
+arch_initcall(shx3_pinmux_setup);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7722.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7722.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7722.c	2011-01-04 19:50:19.000000000 -0500
@@ -551,7 +551,7 @@
 };
 
 static struct platform_device siu_device = {
-	.name		= "sh_siu",
+	.name		= "siu-pcm-audio",
 	.id		= -1,
 	.dev = {
 		.platform_data	= &siu_platform_data,
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7724.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7724.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7724.c	2011-01-04 19:50:19.000000000 -0500
@@ -524,6 +524,70 @@
 	},
 };
 
+/* BEU0 */
+static struct uio_info beu0_platform_data = {
+	.name = "BEU0",
+	.version = "0",
+	.irq = evt2irq(0x8A0),
+};
+
+static struct resource beu0_resources[] = {
+	[0] = {
+		.name	= "BEU0",
+		.start	= 0xfe930000,
+		.end	= 0xfe933400,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		/* place holder for contiguous memory */
+	},
+};
+
+static struct platform_device beu0_device = {
+	.name		= "uio_pdrv_genirq",
+	.id		= 6,
+	.dev = {
+		.platform_data	= &beu0_platform_data,
+	},
+	.resource	= beu0_resources,
+	.num_resources	= ARRAY_SIZE(beu0_resources),
+	.archdata = {
+		.hwblk_id = HWBLK_BEU0,
+	},
+};
+
+/* BEU1 */
+static struct uio_info beu1_platform_data = {
+	.name = "BEU1",
+	.version = "0",
+	.irq = evt2irq(0xA00),
+};
+
+static struct resource beu1_resources[] = {
+	[0] = {
+		.name	= "BEU1",
+		.start	= 0xfe940000,
+		.end	= 0xfe943400,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		/* place holder for contiguous memory */
+	},
+};
+
+static struct platform_device beu1_device = {
+	.name		= "uio_pdrv_genirq",
+	.id		= 7,
+	.dev = {
+		.platform_data	= &beu1_platform_data,
+	},
+	.resource	= beu1_resources,
+	.num_resources	= ARRAY_SIZE(beu1_resources),
+	.archdata = {
+		.hwblk_id = HWBLK_BEU1,
+	},
+};
+
 static struct sh_timer_config cmt_platform_data = {
 	.channel_offset = 0x60,
 	.timer_bit = 5,
@@ -857,6 +921,8 @@
 	&vpu_device,
 	&veu0_device,
 	&veu1_device,
+	&beu0_device,
+	&beu1_device,
 	&jpu_device,
 	&spu0_device,
 	&spu1_device,
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7757.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7757.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7757.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,7 @@
 
 static struct platform_device scif2_device = {
 	.name		= "sh-sci",
-	.id		= 2,
+	.id		= 0,
 	.dev		= {
 		.platform_data	= &scif2_platform_data,
 	},
@@ -41,7 +41,7 @@
 
 static struct platform_device scif3_device = {
 	.name		= "sh-sci",
-	.id		= 3,
+	.id		= 1,
 	.dev		= {
 		.platform_data	= &scif3_platform_data,
 	},
@@ -56,7 +56,7 @@
 
 static struct platform_device scif4_device = {
 	.name		= "sh-sci",
-	.id		= 4,
+	.id		= 2,
 	.dev		= {
 		.platform_data	= &scif4_platform_data,
 	},
@@ -163,39 +163,23 @@
 	IRL4_HHLL, IRL4_HHLH, IRL4_HHHL,
 	IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
 
-	SDHI,
-	DVC,
-	IRQ8, IRQ9, IRQ10,
-	WDT0,
-	TMU0, TMU1, TMU2, TMU2_TICPI,
+	SDHI, DVC,
+	IRQ8, IRQ9, IRQ11, IRQ10, IRQ12, IRQ13, IRQ14, IRQ15,
+	TMU0, TMU1, TMU2, TMU2_TICPI, TMU3, TMU4, TMU5,
 	HUDI,
-
 	ARC4,
-	DMAC0,
-	IRQ11,
-	SCIF2,
-	DMAC1_6,
-	USB0,
-	IRQ12,
+	DMAC0_5, DMAC6_7, DMAC8_11,
+	SCIF0, SCIF1, SCIF2, SCIF3, SCIF4,
+	USB0, USB1,
 	JMC,
-	SPI1,
-	IRQ13, IRQ14,
-	USB1,
+	SPI0, SPI1,
 	TMR01, TMR23, TMR45,
-	WDT1,
 	FRT,
-	LPC,
-	SCIF0, SCIF1, SCIF3,
-	PECI0I, PECI1I, PECI2I,
-	IRQ15,
+	LPC, LPC5, LPC6, LPC7, LPC8,
+	PECI0, PECI1, PECI2, PECI3, PECI4, PECI5,
 	ETHERC,
-	SPI0,
-	ADC1,
-	DMAC1_8,
+	ADC0, ADC1,
 	SIM,
-	TMU3, TMU4, TMU5,
-	ADC0,
-	SCIF4,
 	IIC0_0, IIC0_1, IIC0_2, IIC0_3,
 	IIC1_0, IIC1_1, IIC1_2, IIC1_3,
 	IIC2_0, IIC2_1, IIC2_2, IIC2_3,
@@ -206,9 +190,23 @@
 	IIC7_0, IIC7_1, IIC7_2, IIC7_3,
 	IIC8_0, IIC8_1, IIC8_2, IIC8_3,
 	IIC9_0, IIC9_1, IIC9_2, IIC9_3,
-	PCIINTA,
-	PCIE,
+	ONFICTL,
+	MMC1, MMC2,
+	ECCU,
+	PCIC,
+	G200,
+	RSPI,
 	SGPIO,
+	DMINT12, DMINT13, DMINT14, DMINT15, DMINT16, DMINT17, DMINT18, DMINT19,
+	DMINT20, DMINT21, DMINT22, DMINT23,
+	DDRECC,
+	TSIP,
+	PCIE_BRIDGE,
+	WDT0B, WDT1B, WDT2B, WDT3B, WDT4B, WDT5B, WDT6B, WDT7B, WDT8B,
+	GETHER0, GETHER1, GETHER2,
+	PBIA, PBIB, PBIC,
+	DMAE2, DMAE3,
+	SERMUX2, SERMUX3,
 
 	/* interrupt groups */
 
@@ -221,19 +219,18 @@
 	INTC_VECT(DVC, 0x4e0),
 	INTC_VECT(IRQ8, 0x500), INTC_VECT(IRQ9, 0x520),
 	INTC_VECT(IRQ10, 0x540),
-	INTC_VECT(WDT0, 0x560),
 	INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
 	INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
 	INTC_VECT(HUDI, 0x600),
 	INTC_VECT(ARC4, 0x620),
-	INTC_VECT(DMAC0, 0x640), INTC_VECT(DMAC0, 0x660),
-	INTC_VECT(DMAC0, 0x680), INTC_VECT(DMAC0, 0x6a0),
-	INTC_VECT(DMAC0, 0x6c0),
+	INTC_VECT(DMAC0_5, 0x640), INTC_VECT(DMAC0_5, 0x660),
+	INTC_VECT(DMAC0_5, 0x680), INTC_VECT(DMAC0_5, 0x6a0),
+	INTC_VECT(DMAC0_5, 0x6c0),
 	INTC_VECT(IRQ11, 0x6e0),
 	INTC_VECT(SCIF2, 0x700), INTC_VECT(SCIF2, 0x720),
 	INTC_VECT(SCIF2, 0x740), INTC_VECT(SCIF2, 0x760),
-	INTC_VECT(DMAC0, 0x780), INTC_VECT(DMAC0, 0x7a0),
-	INTC_VECT(DMAC1_6, 0x7c0), INTC_VECT(DMAC1_6, 0x7e0),
+	INTC_VECT(DMAC0_5, 0x780), INTC_VECT(DMAC0_5, 0x7a0),
+	INTC_VECT(DMAC6_7, 0x7c0), INTC_VECT(DMAC6_7, 0x7e0),
 	INTC_VECT(USB0, 0x840),
 	INTC_VECT(IRQ12, 0x880),
 	INTC_VECT(JMC, 0x8a0),
@@ -242,7 +239,6 @@
 	INTC_VECT(USB1, 0x920),
 	INTC_VECT(TMR01, 0xa00), INTC_VECT(TMR23, 0xa20),
 	INTC_VECT(TMR45, 0xa40),
-	INTC_VECT(WDT1, 0xa60),
 	INTC_VECT(FRT, 0xa80),
 	INTC_VECT(LPC, 0xaa0), INTC_VECT(LPC, 0xac0),
 	INTC_VECT(LPC, 0xae0), INTC_VECT(LPC, 0xb00),
@@ -250,14 +246,14 @@
 	INTC_VECT(SCIF0, 0xb40), INTC_VECT(SCIF1, 0xb60),
 	INTC_VECT(SCIF3, 0xb80), INTC_VECT(SCIF3, 0xba0),
 	INTC_VECT(SCIF3, 0xbc0), INTC_VECT(SCIF3, 0xbe0),
-	INTC_VECT(PECI0I, 0xc00), INTC_VECT(PECI1I, 0xc20),
-	INTC_VECT(PECI2I, 0xc40),
+	INTC_VECT(PECI0, 0xc00), INTC_VECT(PECI1, 0xc20),
+	INTC_VECT(PECI2, 0xc40),
 	INTC_VECT(IRQ15, 0xc60),
 	INTC_VECT(ETHERC, 0xc80), INTC_VECT(ETHERC, 0xca0),
 	INTC_VECT(SPI0, 0xcc0),
 	INTC_VECT(ADC1, 0xce0),
-	INTC_VECT(DMAC1_8, 0xd00), INTC_VECT(DMAC1_8, 0xd20),
-	INTC_VECT(DMAC1_8, 0xd40), INTC_VECT(DMAC1_8, 0xd60),
+	INTC_VECT(DMAC8_11, 0xd00), INTC_VECT(DMAC8_11, 0xd20),
+	INTC_VECT(DMAC8_11, 0xd40), INTC_VECT(DMAC8_11, 0xd60),
 	INTC_VECT(SIM, 0xd80), INTC_VECT(SIM, 0xda0),
 	INTC_VECT(SIM, 0xdc0), INTC_VECT(SIM, 0xde0),
 	INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
@@ -278,17 +274,47 @@
 	INTC_VECT(IIC5_0, 0x1860), INTC_VECT(IIC5_1, 0x1880),
 	INTC_VECT(IIC5_2, 0x18a0), INTC_VECT(IIC5_3, 0x18c0),
 	INTC_VECT(IIC6_0, 0x18e0), INTC_VECT(IIC6_1, 0x1900),
-	INTC_VECT(IIC6_2, 0x1920), INTC_VECT(IIC6_3, 0x1980),
+	INTC_VECT(IIC6_2, 0x1920),
+	INTC_VECT(ONFICTL, 0x1960),
+	INTC_VECT(IIC6_3, 0x1980),
 	INTC_VECT(IIC7_0, 0x19a0), INTC_VECT(IIC7_1, 0x1a00),
 	INTC_VECT(IIC7_2, 0x1a20), INTC_VECT(IIC7_3, 0x1a40),
 	INTC_VECT(IIC8_0, 0x1a60), INTC_VECT(IIC8_1, 0x1a80),
 	INTC_VECT(IIC8_2, 0x1aa0), INTC_VECT(IIC8_3, 0x1b40),
 	INTC_VECT(IIC9_0, 0x1b60), INTC_VECT(IIC9_1, 0x1b80),
 	INTC_VECT(IIC9_2, 0x1c00), INTC_VECT(IIC9_3, 0x1c20),
-	INTC_VECT(PCIINTA, 0x1ce0),
-	INTC_VECT(PCIE, 0x1e00),
-	INTC_VECT(SGPIO, 0x1f80),
-	INTC_VECT(SGPIO, 0x1fa0),
+	INTC_VECT(MMC1, 0x1c60), INTC_VECT(MMC2, 0x1c80),
+	INTC_VECT(ECCU, 0x1cc0),
+	INTC_VECT(PCIC, 0x1ce0),
+	INTC_VECT(G200, 0x1d00),
+	INTC_VECT(RSPI, 0x1d80), INTC_VECT(RSPI, 0x1da0),
+	INTC_VECT(RSPI, 0x1dc0), INTC_VECT(RSPI, 0x1de0),
+	INTC_VECT(PECI3, 0x1ec0), INTC_VECT(PECI4, 0x1ee0),
+	INTC_VECT(PECI5, 0x1f00),
+	INTC_VECT(SGPIO, 0x1f80), INTC_VECT(SGPIO, 0x1fa0),
+	INTC_VECT(SGPIO, 0x1fc0),
+	INTC_VECT(DMINT12, 0x2400), INTC_VECT(DMINT13, 0x2420),
+	INTC_VECT(DMINT14, 0x2440), INTC_VECT(DMINT15, 0x2460),
+	INTC_VECT(DMINT16, 0x2480), INTC_VECT(DMINT17, 0x24e0),
+	INTC_VECT(DMINT18, 0x2500), INTC_VECT(DMINT19, 0x2520),
+	INTC_VECT(DMINT20, 0x2540), INTC_VECT(DMINT21, 0x2560),
+	INTC_VECT(DMINT22, 0x2580), INTC_VECT(DMINT23, 0x2600),
+	INTC_VECT(DDRECC, 0x2620),
+	INTC_VECT(TSIP, 0x2640),
+	INTC_VECT(PCIE_BRIDGE, 0x27c0),
+	INTC_VECT(WDT0B, 0x2800), INTC_VECT(WDT1B, 0x2820),
+	INTC_VECT(WDT2B, 0x2840), INTC_VECT(WDT3B, 0x2860),
+	INTC_VECT(WDT4B, 0x2880), INTC_VECT(WDT5B, 0x28a0),
+	INTC_VECT(WDT6B, 0x28c0), INTC_VECT(WDT7B, 0x28e0),
+	INTC_VECT(WDT8B, 0x2900),
+	INTC_VECT(GETHER0, 0x2960), INTC_VECT(GETHER1, 0x2980),
+	INTC_VECT(GETHER2, 0x29a0),
+	INTC_VECT(PBIA, 0x2a00), INTC_VECT(PBIB, 0x2a20),
+	INTC_VECT(PBIC, 0x2a40),
+	INTC_VECT(DMAE2, 0x2a60), INTC_VECT(DMAE3, 0x2a80),
+	INTC_VECT(SERMUX2, 0x2aa0), INTC_VECT(SERMUX3, 0x2b40),
+	INTC_VECT(LPC5, 0x2b60), INTC_VECT(LPC6, 0x2b80),
+	INTC_VECT(LPC7, 0x2c00), INTC_VECT(LPC8, 0x2c20),
 };
 
 static struct intc_group groups[] __initdata = {
@@ -312,31 +338,45 @@
 
 	{ 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
 	  { 0, 0, 0, 0, 0, 0, 0, 0,
-	    0, DMAC1_8, 0, PECI0I, LPC, FRT, WDT1, TMR45,
-	    TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0,
-	    HUDI, 0, WDT0, SCIF3, SCIF2, SDHI, TMU345, TMU012
+	    0, DMAC8_11, 0, PECI0, LPC, FRT, 0, TMR45,
+	    TMR23, TMR01, 0, 0, 0, 0, 0, DMAC0_5,
+	    HUDI, 0, 0, SCIF3, SCIF2, SDHI, TMU345, TMU012
 	     } },
 
 	{ 0xffd400d0, 0xffd400d4, 32, /* INT2MSKR1 / INT2MSKCR1 */
 	  { IRQ15, IRQ14, IRQ13, IRQ12, IRQ11, IRQ10, SCIF4, ETHERC,
 	    IRQ9, IRQ8, SCIF1, SCIF0, USB0, 0, 0, USB1,
-	    ADC1, 0, DMAC1_6, ADC0, SPI0, SIM, PECI2I, PECI1I,
+	    ADC1, 0, DMAC6_7, ADC0, SPI0, SIM, PECI2, PECI1,
 	    ARC4, 0, SPI1, JMC, 0, 0, 0, DVC
 	     } },
 
 	{ 0xffd10038, 0xffd1003c, 32, /* INT2MSKR2 / INT2MSKCR2 */
-	  { IIC4_1, IIC4_2, IIC5_0, 0, 0, 0, SGPIO, 0,
-	    0, 0, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
+	  { IIC4_1, IIC4_2, IIC5_0, ONFICTL, 0, 0, SGPIO, 0,
+	    0, G200, 0, IIC9_2, IIC8_2, IIC8_1, IIC8_0, IIC7_3,
 	    IIC7_2, IIC7_1, IIC6_3, IIC0_0, IIC0_1, IIC0_2, IIC0_3, IIC3_1,
-	    IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, PCIE, IIC2_2
+	    IIC2_3, 0, IIC2_1, IIC9_1, IIC3_3, IIC1_0, 0, IIC2_2
 	     } },
 
-	{ 0xffd100d0, 0xff1400d4, 32, /* INT2MSKR3 / INT2MSKCR4 */
-	  { 0, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, 0, 0,
+	{ 0xffd100d0, 0xffd100d4, 32, /* INT2MSKR3 / INT2MSKCR3 */
+	  { MMC1, IIC6_1, IIC6_0, IIC5_1, IIC3_2, IIC2_0, PECI5, MMC2,
 	    IIC1_3, IIC1_2, IIC9_0, IIC8_3, IIC4_3, IIC7_0, 0, IIC6_2,
-	    PCIINTA, 0, IIC4_0, 0, 0, 0, 0, IIC9_3,
+	    PCIC, 0, IIC4_0, 0, ECCU, RSPI, 0, IIC9_3,
 	    IIC3_0, 0, IIC5_3, IIC5_2, 0, 0, 0, IIC1_1
 	     } },
+
+	{ 0xffd20038, 0xffd2003c, 32, /* INT2MSKR4 / INT2MSKCR4 */
+	  { WDT0B, WDT1B, WDT3B, GETHER0, 0, 0, 0, 0,
+	    0, 0, 0, LPC7, SERMUX2, DMAE3, DMAE2, PBIC,
+	    PBIB, PBIA, GETHER1, DMINT12, DMINT13, DMINT14, DMINT15, TSIP,
+	    DMINT23, 0, DMINT21, LPC6, 0, DMINT16, 0, DMINT22
+	     } },
+
+	{ 0xffd200d0, 0xffd200d4, 32, /* INT2MSKR5 / INT2MSKCR5 */
+	  { 0, WDT8B, WDT7B, WDT4B, 0, DMINT20, 0, 0,
+	    DMINT19, DMINT18, LPC5, SERMUX3, WDT2B, GETHER2, 0, 0,
+	    0, 0, PCIE_BRIDGE, 0, 0, 0, 0, LPC8,
+	    DDRECC, 0, WDT6B, WDT5B, 0, 0, 0, DMINT17
+	     } },
 };
 
 #define INTPRI		0xffd00010
@@ -372,6 +412,22 @@
 #define INT2PRI29	0xffd100b4
 #define INT2PRI30	0xffd100b8
 #define INT2PRI31	0xffd100bc
+#define INT2PRI32	0xffd20000
+#define INT2PRI33	0xffd20004
+#define INT2PRI34	0xffd20008
+#define INT2PRI35	0xffd2000c
+#define INT2PRI36	0xffd20010
+#define INT2PRI37	0xffd20014
+#define INT2PRI38	0xffd20018
+#define INT2PRI39	0xffd2001c
+#define INT2PRI40	0xffd200a0
+#define INT2PRI41	0xffd200a4
+#define INT2PRI42	0xffd200a8
+#define INT2PRI43	0xffd200ac
+#define INT2PRI44	0xffd200b0
+#define INT2PRI45	0xffd200b4
+#define INT2PRI46	0xffd200b8
+#define INT2PRI47	0xffd200bc
 
 static struct intc_prio_reg prio_registers[] __initdata = {
 	{ INTPRI, 0, 32, 4, { IRQ0, IRQ1, IRQ2, IRQ3,
@@ -379,39 +435,61 @@
 
 	{ INT2PRI0, 0, 32, 8, { TMU0, TMU1, TMU2, TMU2_TICPI } },
 	{ INT2PRI1, 0, 32, 8, { TMU3, TMU4, TMU5, SDHI } },
-	{ INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, WDT0, IRQ8 } },
-	{ INT2PRI3, 0, 32, 8, { HUDI, DMAC0, ADC0, IRQ9 } },
+	{ INT2PRI2, 0, 32, 8, { SCIF2, SCIF3, 0, IRQ8 } },
+	{ INT2PRI3, 0, 32, 8, { HUDI, DMAC0_5, ADC0, IRQ9 } },
 	{ INT2PRI4, 0, 32, 8, { IRQ10, 0, TMR01, TMR23 } },
-	{ INT2PRI5, 0, 32, 8, { TMR45, WDT1, FRT, LPC } },
-	{ INT2PRI6, 0, 32, 8, { PECI0I, ETHERC, DMAC1_8, 0 } },
+	{ INT2PRI5, 0, 32, 8, { TMR45, 0, FRT, LPC } },
+	{ INT2PRI6, 0, 32, 8, { PECI0, ETHERC, DMAC8_11, 0 } },
 	{ INT2PRI7, 0, 32, 8, { SCIF4, 0, IRQ11, IRQ12 } },
 	{ INT2PRI8, 0, 32, 8, { 0, 0, 0, DVC } },
 	{ INT2PRI9, 0, 32, 8, { ARC4, 0, SPI1, JMC } },
-	{ INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2I, PECI1I } },
-	{ INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC1_6, IRQ14 } },
+	{ INT2PRI10, 0, 32, 8, { SPI0, SIM, PECI2, PECI1 } },
+	{ INT2PRI11, 0, 32, 8, { ADC1, IRQ13, DMAC6_7, IRQ14 } },
 	{ INT2PRI12, 0, 32, 8, { USB0, 0, IRQ15, USB1 } },
 	{ INT2PRI13, 0, 32, 8, { 0, 0, SCIF1, SCIF0 } },
 
 	{ INT2PRI16, 0, 32, 8, { IIC2_2, 0, 0, 0 } },
-	{ INT2PRI17, 0, 32, 8, { PCIE, 0, 0, IIC1_0 } },
+	{ INT2PRI17, 0, 32, 8, { 0, 0, 0, IIC1_0 } },
 	{ INT2PRI18, 0, 32, 8, { IIC3_3, IIC9_1, IIC2_1, IIC1_2 } },
 	{ INT2PRI19, 0, 32, 8, { IIC2_3, IIC3_1, 0, IIC1_3 } },
 	{ INT2PRI20, 0, 32, 8, { IIC2_0, IIC6_3, IIC7_1, IIC7_2 } },
 	{ INT2PRI21, 0, 32, 8, { IIC7_3, IIC8_0, IIC8_1, IIC8_2 } },
-	{ INT2PRI22, 0, 32, 8, { IIC9_2, 0, 0, 0 } },
-	{ INT2PRI23, 0, 32, 8, { 0, SGPIO, IIC3_2, IIC5_1 } },
-	{ INT2PRI24, 0, 32, 8, { 0, 0, 0, IIC1_1 } },
+	{ INT2PRI22, 0, 32, 8, { IIC9_2, MMC2, G200, 0 } },
+	{ INT2PRI23, 0, 32, 8, { PECI5, SGPIO, IIC3_2, IIC5_1 } },
+	{ INT2PRI24, 0, 32, 8, { PECI4, PECI3, 0, IIC1_1 } },
 	{ INT2PRI25, 0, 32, 8, { IIC3_0, 0, IIC5_3, IIC5_2 } },
-	{ INT2PRI26, 0, 32, 8, { 0, 0, 0, IIC9_3 } },
-	{ INT2PRI27, 0, 32, 8, { PCIINTA, IIC6_0, IIC4_0, IIC6_1 } },
-	{ INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, 0, IIC6_2 } },
+	{ INT2PRI26, 0, 32, 8, { ECCU, RSPI, 0, IIC9_3 } },
+	{ INT2PRI27, 0, 32, 8, { PCIC, IIC6_0, IIC4_0, IIC6_1 } },
+	{ INT2PRI28, 0, 32, 8, { IIC4_3, IIC7_0, MMC1, IIC6_2 } },
 	{ INT2PRI29, 0, 32, 8, { 0, 0, IIC9_0, IIC8_3 } },
-	{ INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, 0 } },
+	{ INT2PRI30, 0, 32, 8, { IIC4_1, IIC4_2, IIC5_0, ONFICTL } },
 	{ INT2PRI31, 0, 32, 8, { IIC0_0, IIC0_1, IIC0_2, IIC0_3 } },
+	{ INT2PRI32, 0, 32, 8, { DMINT22, 0, 0, 0 } },
+	{ INT2PRI33, 0, 32, 8, { 0, 0, 0, DMINT16 } },
+	{ INT2PRI34, 0, 32, 8, { 0, LPC6, DMINT21, DMINT18 } },
+	{ INT2PRI35, 0, 32, 8, { DMINT23, TSIP, 0, DMINT19 } },
+	{ INT2PRI36, 0, 32, 8, { DMINT20, GETHER1, PBIA, PBIB } },
+	{ INT2PRI37, 0, 32, 8, { PBIC, DMAE2, DMAE3, SERMUX2 } },
+	{ INT2PRI38, 0, 32, 8, { LPC7, 0, 0, 0 } },
+	{ INT2PRI39, 0, 32, 8, { 0, 0, 0, WDT4B } },
+	{ INT2PRI40, 0, 32, 8, { 0, 0, 0, DMINT17 } },
+	{ INT2PRI41, 0, 32, 8, { DDRECC, 0, WDT6B, WDT5B } },
+	{ INT2PRI42, 0, 32, 8, { 0, 0, 0, LPC8 } },
+	{ INT2PRI43, 0, 32, 8, { 0, WDT7B, PCIE_BRIDGE, WDT8B } },
+	{ INT2PRI44, 0, 32, 8, { WDT2B, GETHER2, 0, 0 } },
+	{ INT2PRI45, 0, 32, 8, { 0, 0, LPC5, SERMUX3 } },
+	{ INT2PRI46, 0, 32, 8, { WDT0B, WDT1B, WDT3B, GETHER0 } },
+	{ INT2PRI47, 0, 32, 8, { DMINT12, DMINT13, DMINT14, DMINT15 } },
+};
+
+static struct intc_sense_reg sense_registers_irq8to15[] __initdata = {
+	{ 0xffd100f8, 32, 2, /* ICR2 */   { IRQ15, IRQ14, IRQ13, IRQ12,
+					    IRQ11, IRQ10, IRQ9, IRQ8 } },
 };
 
 static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
-			 mask_registers, prio_registers, NULL);
+			 mask_registers, prio_registers,
+			 sense_registers_irq8to15);
 
 /* Support for external interrupt pins in IRQ mode */
 static struct intc_vect vectors_irq0123[] __initdata = {
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7786.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7786.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-sh7786.c	2011-01-04 19:50:19.000000000 -0500
@@ -629,33 +629,10 @@
 	}
 }
 
-static int __init sh7786_devices_setup(void)
-{
-	int ret;
-
-	sh7786_usb_setup();
-
-	ret = platform_add_devices(sh7786_early_devices,
-				   ARRAY_SIZE(sh7786_early_devices));
-	if (unlikely(ret != 0))
-		return ret;
-
-	return platform_add_devices(sh7786_devices,
-				    ARRAY_SIZE(sh7786_devices));
-}
-arch_initcall(sh7786_devices_setup);
-
-void __init plat_early_device_setup(void)
-{
-	early_platform_add_devices(sh7786_early_devices,
-				   ARRAY_SIZE(sh7786_early_devices));
-}
-
 enum {
 	UNUSED = 0,
 
 	/* interrupt sources */
-
 	IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
 	IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
 	IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
@@ -693,9 +670,12 @@
 	Thermal,
 	INTICI0, INTICI1, INTICI2, INTICI3,
 	INTICI4, INTICI5, INTICI6, INTICI7,
+
+	/* Muxed sub-events */
+	TXI1, BRI1, RXI1, ERI1,
 };
 
-static struct intc_vect vectors[] __initdata = {
+static struct intc_vect sh7786_vectors[] __initdata = {
 	INTC_VECT(WDT, 0x3e0),
 	INTC_VECT(TMU0_0, 0x400), INTC_VECT(TMU0_1, 0x420),
 	INTC_VECT(TMU0_2, 0x440), INTC_VECT(TMU0_3, 0x460),
@@ -756,14 +736,12 @@
 
 #define INTDISTCR0	0xfe4100b0
 #define INTDISTCR1	0xfe4100b4
-#define INTACK		0xfe4100b8
-#define INTACKCLR	0xfe4100bc
 #define INT2DISTCR0	0xfe410900
 #define INT2DISTCR1	0xfe410904
 #define INT2DISTCR2	0xfe410908
 #define INT2DISTCR3	0xfe41090c
 
-static struct intc_mask_reg mask_registers[] __initdata = {
+static struct intc_mask_reg sh7786_mask_registers[] __initdata = {
 	{ CnINTMSK0, CnINTMSKCLR0, 32,
 	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 },
 	    INTC_SMP_BALANCING(INTDISTCR0) },
@@ -807,7 +785,7 @@
 	    0, 0, 0, 0, 0, 0, 0, 0 }, INTC_SMP_BALANCING(INT2DISTCR3) },
 };
 
-static struct intc_prio_reg prio_registers[] __initdata = {
+static struct intc_prio_reg sh7786_prio_registers[] __initdata = {
 	{ 0xfe410010, 0, 32, 4, /* INTPRI */   { IRQ0, IRQ1, IRQ2, IRQ3,
 						 IRQ4, IRQ5, IRQ6, IRQ7 } },
 	{ 0xfe410800, 0, 32, 8, /* INT2PRI0 */ { 0, 0, 0, WDT } },
@@ -851,11 +829,27 @@
 	    INTICI3, INTICI2, INTICI1, INTICI0 }, INTC_SMP(4, 2) },
 };
 
-static DECLARE_INTC_DESC(intc_desc, "sh7786", vectors, NULL,
-			 mask_registers, prio_registers, NULL);
+static struct intc_subgroup sh7786_subgroups[] __initdata = {
+	{ 0xfe410c20, 32, SCIF1,
+	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TXI1, BRI1, RXI1, ERI1 } },
+};
 
-/* Support for external interrupt pins in IRQ mode */
+static struct intc_desc sh7786_intc_desc __initdata = {
+	.name		= "sh7786",
+	.hw		= {
+		.vectors	= sh7786_vectors,
+		.nr_vectors	= ARRAY_SIZE(sh7786_vectors),
+		.mask_regs	= sh7786_mask_registers,
+		.nr_mask_regs	= ARRAY_SIZE(sh7786_mask_registers),
+		.subgroups	= sh7786_subgroups,
+		.nr_subgroups	= ARRAY_SIZE(sh7786_subgroups),
+		.prio_regs	= sh7786_prio_registers,
+		.nr_prio_regs	= ARRAY_SIZE(sh7786_prio_registers),
+	},
+};
 
+/* Support for external interrupt pins in IRQ mode */
 static struct intc_vect vectors_irq0123[] __initdata = {
 	INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
 	INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
@@ -866,23 +860,25 @@
 	INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
 };
 
-static struct intc_sense_reg sense_registers[] __initdata = {
+static struct intc_sense_reg sh7786_sense_registers[] __initdata = {
 	{ 0xfe41001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
 					    IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-static struct intc_mask_reg ack_registers[] __initdata = {
+static struct intc_mask_reg sh7786_ack_registers[] __initdata = {
 	{ 0xfe410024, 0, 32, /* INTREQ */
 	  { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
 static DECLARE_INTC_DESC_ACK(intc_desc_irq0123, "sh7786-irq0123",
-			     vectors_irq0123, NULL, mask_registers,
-			     prio_registers, sense_registers, ack_registers);
+			     vectors_irq0123, NULL, sh7786_mask_registers,
+			     sh7786_prio_registers, sh7786_sense_registers,
+			     sh7786_ack_registers);
 
 static DECLARE_INTC_DESC_ACK(intc_desc_irq4567, "sh7786-irq4567",
-			     vectors_irq4567, NULL, mask_registers,
-			     prio_registers, sense_registers, ack_registers);
+			     vectors_irq4567, NULL, sh7786_mask_registers,
+			     sh7786_prio_registers, sh7786_sense_registers,
+			     sh7786_ack_registers);
 
 /* External interrupt pins in IRL mode */
 
@@ -909,10 +905,10 @@
 };
 
 static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7786-irl0123", vectors_irl0123,
-			 NULL, mask_registers, NULL, NULL);
+			 NULL, sh7786_mask_registers, NULL, NULL);
 
 static DECLARE_INTC_DESC(intc_desc_irl4567, "sh7786-irl4567", vectors_irl4567,
-			 NULL, mask_registers, NULL, NULL);
+			 NULL, sh7786_mask_registers, NULL, NULL);
 
 #define INTC_ICR0	0xfe410000
 #define INTC_INTMSK0	CnINTMSK0
@@ -920,19 +916,6 @@
 #define INTC_INTMSK2	INTMSK2
 #define INTC_INTMSKCLR1	CnINTMSKCLR1
 #define INTC_INTMSKCLR2	INTMSKCLR2
-#define INTC_USERIMASK	0xfe411000
-
-#ifdef CONFIG_INTC_BALANCING
-unsigned int irq_lookup(unsigned int irq)
-{
-	return __raw_readl(INTACK) & 1 ? irq : NO_IRQ_IGNORE;
-}
-
-void irq_finish(unsigned int irq)
-{
-	__raw_writel(irq2evt(irq), INTACKCLR);
-}
-#endif
 
 void __init plat_irq_setup(void)
 {
@@ -946,8 +929,7 @@
 	/* select IRL mode for IRL3-0 + IRL7-4 */
 	__raw_writel(__raw_readl(INTC_ICR0) & ~0x00c00000, INTC_ICR0);
 
-	register_intc_controller(&intc_desc);
-	register_intc_userimask(INTC_USERIMASK);
+	register_intc_controller(&sh7786_intc_desc);
 }
 
 void __init plat_irq_setup_pins(int mode)
@@ -991,3 +973,39 @@
 void __init plat_mem_setup(void)
 {
 }
+
+static int __init sh7786_devices_setup(void)
+{
+	int ret, irq;
+
+	sh7786_usb_setup();
+
+	/*
+	 * De-mux SCIF1 IRQs if possible
+	 */
+	irq = intc_irq_lookup(sh7786_intc_desc.name, TXI1);
+	if (irq > 0) {
+		scif1_platform_data.irqs[SCIx_TXI_IRQ] = irq;
+		scif1_platform_data.irqs[SCIx_ERI_IRQ] =
+			intc_irq_lookup(sh7786_intc_desc.name, ERI1);
+		scif1_platform_data.irqs[SCIx_BRI_IRQ] =
+			intc_irq_lookup(sh7786_intc_desc.name, BRI1);
+		scif1_platform_data.irqs[SCIx_RXI_IRQ] =
+			intc_irq_lookup(sh7786_intc_desc.name, RXI1);
+	}
+
+	ret = platform_add_devices(sh7786_early_devices,
+				   ARRAY_SIZE(sh7786_early_devices));
+	if (unlikely(ret != 0))
+		return ret;
+
+	return platform_add_devices(sh7786_devices,
+				    ARRAY_SIZE(sh7786_devices));
+}
+arch_initcall(sh7786_devices_setup);
+
+void __init plat_early_device_setup(void)
+{
+	early_platform_add_devices(sh7786_early_devices,
+				   ARRAY_SIZE(sh7786_early_devices));
+}
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-shx3.c linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-shx3.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/cpu/sh4a/setup-shx3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/cpu/sh4a/setup-shx3.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * SH-X3 Prototype Setup
  *
- *  Copyright (C) 2007 - 2009  Paul Mundt
+ *  Copyright (C) 2007 - 2010  Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -12,7 +12,9 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 #include <linux/sh_timer.h>
+#include <cpu/shx3.h>
 #include <asm/mmzone.h>
 
 /*
@@ -354,6 +356,10 @@
 		   DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
 };
 
+#define INT2DISTCR0	0xfe4108a0
+#define INT2DISTCR1	0xfe4108a4
+#define INT2DISTCR2	0xfe4108a8
+
 static struct intc_mask_reg mask_registers[] __initdata = {
 	{ 0xfe410030, 0xfe410050, 32, /* CnINTMSK0 / CnINTMSKCLR0 */
 	  { IRQ0, IRQ1, IRQ2, IRQ3 } },
@@ -363,20 +369,23 @@
 	  { FE1, FE0, 0, ATAPI, VCORE0, VIN1, VIN0, IIC,
 	    DU, GPIO3, GPIO2, GPIO1, GPIO0, PAM, 0, 0,
 	    0, 0, 0, 0, 0, 0, 0, 0, /* HUDI bits ignored */
-	    0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, } },
+	    0, TMU5, TMU4, TMU3, TMU2, TMU1, TMU0, 0, },
+	    INTC_SMP_BALANCING(INT2DISTCR0) },
 	{ 0xfe410830, 0xfe410860, 32, /* CnINT2MSK1 / CnINT2MSKCLR1 */
 	  { 0, 0, 0, 0, DTU3, DTU2, DTU1, DTU0, /* IRM bits ignored */
 	    PCII9, PCII8, PCII7, PCII6, PCII5, PCII4, PCII3, PCII2,
 	    PCII1, PCII0, DMAC1_DMAE, DMAC1_DMINT11,
 	    DMAC1_DMINT10, DMAC1_DMINT9, DMAC1_DMINT8, DMAC1_DMINT7,
 	    DMAC1_DMINT6, DMAC0_DMAE, DMAC0_DMINT5, DMAC0_DMINT4,
-	    DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 } },
+	    DMAC0_DMINT3, DMAC0_DMINT2, DMAC0_DMINT1, DMAC0_DMINT0 },
+	    INTC_SMP_BALANCING(INT2DISTCR1) },
 	{ 0xfe410840, 0xfe410870, 32, /* CnINT2MSK2 / CnINT2MSKCLR2 */
 	  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	    SCIF3_TXI, SCIF3_BRI, SCIF3_RXI, SCIF3_ERI,
 	    SCIF2_TXI, SCIF2_BRI, SCIF2_RXI, SCIF2_ERI,
 	    SCIF1_TXI, SCIF1_BRI, SCIF1_RXI, SCIF1_ERI,
-	    SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI } },
+	    SCIF0_TXI, SCIF0_BRI, SCIF0_RXI, SCIF0_ERI },
+	    INTC_SMP_BALANCING(INT2DISTCR2) },
 };
 
 static struct intc_prio_reg prio_registers[] __initdata = {
@@ -433,11 +442,33 @@
 
 void __init plat_irq_setup_pins(int mode)
 {
+	int ret = 0;
+
 	switch (mode) {
 	case IRQ_MODE_IRQ:
+		ret |= gpio_request(GPIO_FN_IRQ3, intc_desc_irq.name);
+		ret |= gpio_request(GPIO_FN_IRQ2, intc_desc_irq.name);
+		ret |= gpio_request(GPIO_FN_IRQ1, intc_desc_irq.name);
+		ret |= gpio_request(GPIO_FN_IRQ0, intc_desc_irq.name);
+
+		if (unlikely(ret)) {
+			pr_err("Failed to set IRQ mode\n");
+			return;
+		}
+
 		register_intc_controller(&intc_desc_irq);
 		break;
 	case IRQ_MODE_IRL3210:
+		ret |= gpio_request(GPIO_FN_IRL3, intc_desc_irl.name);
+		ret |= gpio_request(GPIO_FN_IRL2, intc_desc_irl.name);
+		ret |= gpio_request(GPIO_FN_IRL1, intc_desc_irl.name);
+		ret |= gpio_request(GPIO_FN_IRL0, intc_desc_irl.name);
+
+		if (unlikely(ret)) {
+			pr_err("Failed to set IRL mode\n");
+			return;
+		}
+
 		register_intc_controller(&intc_desc_irl);
 		break;
 	default:
@@ -447,6 +478,9 @@
 
 void __init plat_irq_setup(void)
 {
+	reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
+	reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
+
 	register_intc_controller(&intc_desc);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/head_32.S linux-libre-2.6.37-gnu/arch/sh/kernel/head_32.S
--- linux-libre-2.6.36-gnu/arch/sh/kernel/head_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/head_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -330,7 +330,7 @@
 #if defined(CONFIG_CPU_SH2)
 1:	.long	0x000000F0		! IMASK=0xF
 #else
-1:	.long	0x400080F0		! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+1:	.long	0x500080F0		! MD=1, RB=0, BL=1, FD=1, IMASK=0xF
 #endif
 ENTRY(stack_start)
 2:	.long	init_thread_union+THREAD_SIZE
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/io_trapped.c linux-libre-2.6.37-gnu/arch/sh/kernel/io_trapped.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/io_trapped.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/io_trapped.c	2011-01-04 19:50:19.000000000 -0500
@@ -291,7 +291,7 @@
 	}
 
 	tmp = handle_unaligned_access(instruction, regs,
-				      &trapped_io_access, 1);
+				      &trapped_io_access, 1, address);
 	set_fs(oldfs);
 	return tmp == 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/irq_32.c linux-libre-2.6.37-gnu/arch/sh/kernel/irq_32.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/irq_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/irq_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,11 +10,11 @@
 #include <linux/irqflags.h>
 #include <linux/module.h>
 
-void notrace raw_local_irq_restore(unsigned long flags)
+void notrace arch_local_irq_restore(unsigned long flags)
 {
 	unsigned long __dummy0, __dummy1;
 
-	if (flags == RAW_IRQ_DISABLED) {
+	if (flags == ARCH_IRQ_DISABLED) {
 		__asm__ __volatile__ (
 			"stc	sr, %0\n\t"
 			"or	#0xf0, %0\n\t"
@@ -33,14 +33,14 @@
 #endif
 			"ldc	%0, sr\n\t"
 			: "=&r" (__dummy0), "=r" (__dummy1)
-			: "1" (~RAW_IRQ_DISABLED)
+			: "1" (~ARCH_IRQ_DISABLED)
 			: "memory"
 		);
 	}
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
-unsigned long notrace __raw_local_save_flags(void)
+unsigned long notrace arch_local_save_flags(void)
 {
 	unsigned long flags;
 
@@ -54,4 +54,4 @@
 
 	return flags;
 }
-EXPORT_SYMBOL(__raw_local_save_flags);
+EXPORT_SYMBOL(arch_local_save_flags);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/irq_64.c linux-libre-2.6.37-gnu/arch/sh/kernel/irq_64.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/irq_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/irq_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,17 +11,17 @@
 #include <linux/module.h>
 #include <cpu/registers.h>
 
-void notrace raw_local_irq_restore(unsigned long flags)
+void notrace arch_local_irq_restore(unsigned long flags)
 {
 	unsigned long long __dummy;
 
-	if (flags == RAW_IRQ_DISABLED) {
+	if (flags == ARCH_IRQ_DISABLED) {
 		__asm__ __volatile__ (
 			"getcon	" __SR ", %0\n\t"
 			"or	%0, %1, %0\n\t"
 			"putcon	%0, " __SR "\n\t"
 			: "=&r" (__dummy)
-			: "r" (RAW_IRQ_DISABLED)
+			: "r" (ARCH_IRQ_DISABLED)
 		);
 	} else {
 		__asm__ __volatile__ (
@@ -29,13 +29,13 @@
 			"and	%0, %1, %0\n\t"
 			"putcon	%0, " __SR "\n\t"
 			: "=&r" (__dummy)
-			: "r" (~RAW_IRQ_DISABLED)
+			: "r" (~ARCH_IRQ_DISABLED)
 		);
 	}
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
-unsigned long notrace __raw_local_save_flags(void)
+unsigned long notrace arch_local_save_flags(void)
 {
 	unsigned long flags;
 
@@ -43,9 +43,9 @@
 		"getcon	" __SR ", %0\n\t"
 		"and	%0, %1, %0"
 		: "=&r" (flags)
-		: "r" (RAW_IRQ_DISABLED)
+		: "r" (ARCH_IRQ_DISABLED)
 	);
 
 	return flags;
 }
-EXPORT_SYMBOL(__raw_local_save_flags);
+EXPORT_SYMBOL(arch_local_save_flags);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/irq.c linux-libre-2.6.37-gnu/arch/sh/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,6 +56,8 @@
 	int i = *(loff_t *)v, j, prec;
 	struct irqaction *action;
 	struct irq_desc *desc;
+	struct irq_data *data;
+	struct irq_chip *chip;
 
 	if (i > nr_irqs)
 		return 0;
@@ -77,6 +79,9 @@
 	if (!desc)
 		return 0;
 
+	data = irq_get_irq_data(i);
+	chip = irq_data_get_irq_chip(data);
+
 	raw_spin_lock_irqsave(&desc->lock, flags);
 	for_each_online_cpu(j)
 		any_count |= kstat_irqs_cpu(i, j);
@@ -87,7 +92,7 @@
 	seq_printf(p, "%*d: ", prec, i);
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-	seq_printf(p, " %14s", desc->chip->name);
+	seq_printf(p, " %14s", chip->name);
 	seq_printf(p, "-%-8s", desc->name);
 
 	if (action) {
@@ -273,16 +278,12 @@
 {
 	plat_irq_setup();
 
-	/*
-	 * Pin any of the legacy IRQ vectors that haven't already been
-	 * grabbed by the platform
-	 */
-	reserve_irq_legacy();
-
 	/* Perform the machine specific initialisation */
 	if (sh_mv.mv_init_irq)
 		sh_mv.mv_init_irq();
 
+	intc_finalize();
+
 	irq_ctx_init(smp_processor_id());
 }
 
@@ -290,18 +291,21 @@
 int __init arch_probe_nr_irqs(void)
 {
 	nr_irqs = sh_mv.mv_nr_irqs;
-	return 0;
+	return NR_IRQS_LEGACY;
 }
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
+static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
 {
+	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_chip *chip = irq_data_get_irq_chip(data);
+
 	printk(KERN_INFO "IRQ%u: moving from cpu%u to cpu%u\n",
-	       irq, desc->node, cpu);
+	       irq, data->node, cpu);
 
 	raw_spin_lock_irq(&desc->lock);
-	desc->chip->set_affinity(irq, cpumask_of(cpu));
+	chip->irq_set_affinity(data, cpumask_of(cpu), false);
 	raw_spin_unlock_irq(&desc->lock);
 }
 
@@ -312,24 +316,25 @@
  */
 void migrate_irqs(void)
 {
-	struct irq_desc *desc;
 	unsigned int irq, cpu = smp_processor_id();
 
-	for_each_irq_desc(irq, desc) {
-		if (desc->node == cpu) {
-			unsigned int newcpu = cpumask_any_and(desc->affinity,
+	for_each_active_irq(irq) {
+		struct irq_data *data = irq_get_irq_data(irq);
+
+		if (data->node == cpu) {
+			unsigned int newcpu = cpumask_any_and(data->affinity,
 							      cpu_online_mask);
 			if (newcpu >= nr_cpu_ids) {
 				if (printk_ratelimit())
 					printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
 					       irq, cpu);
 
-				cpumask_setall(desc->affinity);
-				newcpu = cpumask_any_and(desc->affinity,
+				cpumask_setall(data->affinity);
+				newcpu = cpumask_any_and(data->affinity,
 							 cpu_online_mask);
 			}
 
-			route_irq(desc, irq, newcpu);
+			route_irq(data, irq, newcpu);
 		}
 	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/kdebugfs.c linux-libre-2.6.37-gnu/arch/sh/kernel/kdebugfs.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/kdebugfs.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/kdebugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+
+struct dentry *arch_debugfs_dir;
+EXPORT_SYMBOL(arch_debugfs_dir);
+
+static int __init arch_kdebugfs_init(void)
+{
+	arch_debugfs_dir = debugfs_create_dir("sh", NULL);
+	if (!arch_debugfs_dir)
+		return -ENOMEM;
+
+	return 0;
+}
+arch_initcall(arch_kdebugfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/kprobes.c linux-libre-2.6.37-gnu/arch/sh/kernel/kprobes.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/kprobes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/kprobes.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,9 +20,9 @@
 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
-static struct kprobe saved_current_opcode;
-static struct kprobe saved_next_opcode;
-static struct kprobe saved_next_opcode2;
+static DEFINE_PER_CPU(struct kprobe, saved_current_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode);
+static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2);
 
 #define OPCODE_JMP(x)	(((x) & 0xF0FF) == 0x402b)
 #define OPCODE_JSR(x)	(((x) & 0xF0FF) == 0x400b)
@@ -102,16 +102,21 @@
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
-	if (saved_next_opcode.addr != 0x0) {
+	struct kprobe *saved = &__get_cpu_var(saved_next_opcode);
+
+	if (saved->addr) {
 		arch_disarm_kprobe(p);
-		arch_disarm_kprobe(&saved_next_opcode);
-		saved_next_opcode.addr = 0x0;
-		saved_next_opcode.opcode = 0x0;
+		arch_disarm_kprobe(saved);
 
-		if (saved_next_opcode2.addr != 0x0) {
-			arch_disarm_kprobe(&saved_next_opcode2);
-			saved_next_opcode2.addr = 0x0;
-			saved_next_opcode2.opcode = 0x0;
+		saved->addr = NULL;
+		saved->opcode = 0;
+
+		saved = &__get_cpu_var(saved_next_opcode2);
+		if (saved->addr) {
+			arch_disarm_kprobe(saved);
+
+			saved->addr = NULL;
+			saved->opcode = 0;
 		}
 	}
 }
@@ -141,57 +146,59 @@
  */
 static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 {
-	kprobe_opcode_t *addr = NULL;
-	saved_current_opcode.addr = (kprobe_opcode_t *) (regs->pc);
-	addr = saved_current_opcode.addr;
+	__get_cpu_var(saved_current_opcode).addr = (kprobe_opcode_t *)regs->pc;
 
 	if (p != NULL) {
+		struct kprobe *op1, *op2;
+
 		arch_disarm_kprobe(p);
 
+		op1 = &__get_cpu_var(saved_next_opcode);
+		op2 = &__get_cpu_var(saved_next_opcode2);
+
 		if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) {
 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
-			saved_next_opcode.addr =
-			    (kprobe_opcode_t *) regs->regs[reg_nr];
+			op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr];
 		} else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) {
 			unsigned long disp = (p->opcode & 0x0FFF);
-			saved_next_opcode.addr =
+			op1->addr =
 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
 
 		} else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) {
 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F);
-			saved_next_opcode.addr =
+			op1->addr =
 			    (kprobe_opcode_t *) (regs->pc + 4 +
 						 regs->regs[reg_nr]);
 
 		} else if (OPCODE_RTS(p->opcode)) {
-			saved_next_opcode.addr = (kprobe_opcode_t *) regs->pr;
+			op1->addr = (kprobe_opcode_t *) regs->pr;
 
 		} else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) {
 			unsigned long disp = (p->opcode & 0x00FF);
 			/* case 1 */
-			saved_next_opcode.addr = p->addr + 1;
+			op1->addr = p->addr + 1;
 			/* case 2 */
-			saved_next_opcode2.addr =
+			op2->addr =
 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
-			saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
-			arch_arm_kprobe(&saved_next_opcode2);
+			op2->opcode = *(op2->addr);
+			arch_arm_kprobe(op2);
 
 		} else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) {
 			unsigned long disp = (p->opcode & 0x00FF);
 			/* case 1 */
-			saved_next_opcode.addr = p->addr + 2;
+			op1->addr = p->addr + 2;
 			/* case 2 */
-			saved_next_opcode2.addr =
+			op2->addr =
 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2);
-			saved_next_opcode2.opcode = *(saved_next_opcode2.addr);
-			arch_arm_kprobe(&saved_next_opcode2);
+			op2->opcode = *(op2->addr);
+			arch_arm_kprobe(op2);
 
 		} else {
-			saved_next_opcode.addr = p->addr + 1;
+			op1->addr = p->addr + 1;
 		}
 
-		saved_next_opcode.opcode = *(saved_next_opcode.addr);
-		arch_arm_kprobe(&saved_next_opcode);
+		op1->opcode = *(op1->addr);
+		arch_arm_kprobe(op1);
 	}
 }
 
@@ -376,21 +383,23 @@
 		cur->post_handler(cur, regs, 0);
 	}
 
-	if (saved_next_opcode.addr != 0x0) {
-		arch_disarm_kprobe(&saved_next_opcode);
-		saved_next_opcode.addr = 0x0;
-		saved_next_opcode.opcode = 0x0;
+	p = &__get_cpu_var(saved_next_opcode);
+	if (p->addr) {
+		arch_disarm_kprobe(p);
+		p->addr = NULL;
+		p->opcode = 0;
 
-		addr = saved_current_opcode.addr;
-		saved_current_opcode.addr = 0x0;
+		addr = __get_cpu_var(saved_current_opcode).addr;
+		__get_cpu_var(saved_current_opcode).addr = NULL;
 
 		p = get_kprobe(addr);
 		arch_arm_kprobe(p);
 
-		if (saved_next_opcode2.addr != 0x0) {
-			arch_disarm_kprobe(&saved_next_opcode2);
-			saved_next_opcode2.addr = 0x0;
-			saved_next_opcode2.opcode = 0x0;
+		p = &__get_cpu_var(saved_next_opcode2);
+		if (p->addr) {
+			arch_disarm_kprobe(p);
+			p->addr = NULL;
+			p->opcode = 0;
 		}
 	}
 
@@ -572,14 +581,5 @@
 
 int __init arch_init_kprobes(void)
 {
-	saved_next_opcode.addr = 0x0;
-	saved_next_opcode.opcode = 0x0;
-
-	saved_current_opcode.addr = 0x0;
-	saved_current_opcode.opcode = 0x0;
-
-	saved_next_opcode2.addr = 0x0;
-	saved_next_opcode2.opcode = 0x0;
-
 	return register_kprobe(&trampoline_p);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/Makefile linux-libre-2.6.37-gnu/arch/sh/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -12,9 +12,9 @@
 CFLAGS_REMOVE_return_address.o = -pg
 
 obj-y	:= clkdev.o debugtraps.o dma-nommu.o dumpstack.o 		\
-	   idle.o io.o irq.o						\
-	   irq_$(BITS).o machvec.o nmi_debug.o process.o		\
-	   process_$(BITS).o ptrace_$(BITS).o				\
+	   idle.o io.o irq.o irq_$(BITS).o kdebugfs.o			\
+	   machvec.o nmi_debug.o process.o				\
+	   process_$(BITS).o ptrace.o ptrace_$(BITS).o			\
 	   reboot.o return_address.o					\
 	   setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o		\
 	   syscalls_$(BITS).o time.o topology.o traps.o			\
@@ -44,4 +44,4 @@
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)		+= hw_breakpoint.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)	+= localtimer.o
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/perf_callchain.c linux-libre-2.6.37-gnu/arch/sh/kernel/perf_callchain.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/perf_callchain.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/perf_callchain.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,11 +14,6 @@
 #include <asm/unwinder.h>
 #include <asm/ptrace.h>
 
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-	if (entry->nr < PERF_MAX_STACK_DEPTH)
-		entry->ip[entry->nr++] = ip;
-}
 
 static void callchain_warning(void *data, char *msg)
 {
@@ -39,7 +34,7 @@
 	struct perf_callchain_entry *entry = data;
 
 	if (reliable)
-		callchain_store(entry, addr);
+		perf_callchain_store(entry, addr);
 }
 
 static const struct stacktrace_ops callchain_ops = {
@@ -49,47 +44,10 @@
 	.address	= callchain_address,
 };
 
-static void
-perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-	callchain_store(entry, PERF_CONTEXT_KERNEL);
-	callchain_store(entry, regs->pc);
+	perf_callchain_store(entry, regs->pc);
 
 	unwind_stack(NULL, regs, NULL, &callchain_ops, entry);
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
-{
-	int is_user;
-
-	if (!regs)
-		return;
-
-	is_user = user_mode(regs);
-
-	if (is_user && current->state != TASK_RUNNING)
-		return;
-
-	/*
-	 * Only the kernel side is implemented for now.
-	 */
-	if (!is_user)
-		perf_callchain_kernel(regs, entry);
-}
-
-/*
- * No need for separate IRQ and NMI entries.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-	struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
-
-	entry->nr = 0;
-
-	perf_do_callchain(regs, entry);
-
-	return entry;
-}
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/sh/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,6 +59,24 @@
 	return !!sh_pmu;
 }
 
+const char *perf_pmu_name(void)
+{
+	if (!sh_pmu)
+		return NULL;
+
+	return sh_pmu->name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+	if (!sh_pmu)
+		return 0;
+
+	return sh_pmu->num_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
 /*
  * Release the PMU if this is the last perf_event.
  */
@@ -206,50 +224,80 @@
 	local64_add(delta, &event->count);
 }
 
-static void sh_pmu_disable(struct perf_event *event)
+static void sh_pmu_stop(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
 	int idx = hwc->idx;
 
-	clear_bit(idx, cpuc->active_mask);
-	sh_pmu->disable(hwc, idx);
+	if (!(event->hw.state & PERF_HES_STOPPED)) {
+		sh_pmu->disable(hwc, idx);
+		cpuc->events[idx] = NULL;
+		event->hw.state |= PERF_HES_STOPPED;
+	}
 
-	barrier();
+	if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
+		sh_perf_event_update(event, &event->hw, idx);
+		event->hw.state |= PERF_HES_UPTODATE;
+	}
+}
 
-	sh_perf_event_update(event, &event->hw, idx);
+static void sh_pmu_start(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	struct hw_perf_event *hwc = &event->hw;
+	int idx = hwc->idx;
 
-	cpuc->events[idx] = NULL;
-	clear_bit(idx, cpuc->used_mask);
+	if (WARN_ON_ONCE(idx == -1))
+		return;
+
+	if (flags & PERF_EF_RELOAD)
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+	cpuc->events[idx] = event;
+	event->hw.state = 0;
+	sh_pmu->enable(hwc, idx);
+}
+
+static void sh_pmu_del(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+	sh_pmu_stop(event, PERF_EF_UPDATE);
+	__clear_bit(event->hw.idx, cpuc->used_mask);
 
 	perf_event_update_userpage(event);
 }
 
-static int sh_pmu_enable(struct perf_event *event)
+static int sh_pmu_add(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
 	int idx = hwc->idx;
+	int ret = -EAGAIN;
 
-	if (test_and_set_bit(idx, cpuc->used_mask)) {
+	perf_pmu_disable(event->pmu);
+
+	if (__test_and_set_bit(idx, cpuc->used_mask)) {
 		idx = find_first_zero_bit(cpuc->used_mask, sh_pmu->num_events);
 		if (idx == sh_pmu->num_events)
-			return -EAGAIN;
+			goto out;
 
-		set_bit(idx, cpuc->used_mask);
+		__set_bit(idx, cpuc->used_mask);
 		hwc->idx = idx;
 	}
 
 	sh_pmu->disable(hwc, idx);
 
-	cpuc->events[idx] = event;
-	set_bit(idx, cpuc->active_mask);
-
-	sh_pmu->enable(hwc, idx);
+	event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+	if (flags & PERF_EF_START)
+		sh_pmu_start(event, PERF_EF_RELOAD);
 
 	perf_event_update_userpage(event);
-
-	return 0;
+	ret = 0;
+out:
+	perf_pmu_enable(event->pmu);
+	return ret;
 }
 
 static void sh_pmu_read(struct perf_event *event)
@@ -257,24 +305,56 @@
 	sh_perf_event_update(event, &event->hw, event->hw.idx);
 }
 
-static const struct pmu pmu = {
-	.enable		= sh_pmu_enable,
-	.disable	= sh_pmu_disable,
-	.read		= sh_pmu_read,
-};
-
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int sh_pmu_event_init(struct perf_event *event)
 {
-	int err = __hw_perf_event_init(event);
+	int err;
+
+	switch (event->attr.type) {
+	case PERF_TYPE_RAW:
+	case PERF_TYPE_HW_CACHE:
+	case PERF_TYPE_HARDWARE:
+		err = __hw_perf_event_init(event);
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
 	if (unlikely(err)) {
 		if (event->destroy)
 			event->destroy(event);
-		return ERR_PTR(err);
 	}
 
-	return &pmu;
+	return err;
+}
+
+static void sh_pmu_enable(struct pmu *pmu)
+{
+	if (!sh_pmu_initialized())
+		return;
+
+	sh_pmu->enable_all();
 }
 
+static void sh_pmu_disable(struct pmu *pmu)
+{
+	if (!sh_pmu_initialized())
+		return;
+
+	sh_pmu->disable_all();
+}
+
+static struct pmu pmu = {
+	.pmu_enable	= sh_pmu_enable,
+	.pmu_disable	= sh_pmu_disable,
+	.event_init	= sh_pmu_event_init,
+	.add		= sh_pmu_add,
+	.del		= sh_pmu_del,
+	.start		= sh_pmu_start,
+	.stop		= sh_pmu_stop,
+	.read		= sh_pmu_read,
+};
+
 static void sh_pmu_setup(int cpu)
 {
 	struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
@@ -299,32 +379,17 @@
 	return NOTIFY_OK;
 }
 
-void hw_perf_enable(void)
-{
-	if (!sh_pmu_initialized())
-		return;
-
-	sh_pmu->enable_all();
-}
-
-void hw_perf_disable(void)
-{
-	if (!sh_pmu_initialized())
-		return;
-
-	sh_pmu->disable_all();
-}
-
-int __cpuinit register_sh_pmu(struct sh_pmu *pmu)
+int __cpuinit register_sh_pmu(struct sh_pmu *_pmu)
 {
 	if (sh_pmu)
 		return -EBUSY;
-	sh_pmu = pmu;
+	sh_pmu = _pmu;
 
-	pr_info("Performance Events: %s support registered\n", pmu->name);
+	pr_info("Performance Events: %s support registered\n", _pmu->name);
 
-	WARN_ON(pmu->num_events > MAX_HWEVENTS);
+	WARN_ON(_pmu->num_events > MAX_HWEVENTS);
 
+	perf_pmu_register(&pmu);
 	perf_cpu_notifier(sh_pmu_notifier);
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace_32.c linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace_32.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -274,6 +274,33 @@
 }
 #endif
 
+const struct pt_regs_offset regoffset_table[] = {
+	REGS_OFFSET_NAME(0),
+	REGS_OFFSET_NAME(1),
+	REGS_OFFSET_NAME(2),
+	REGS_OFFSET_NAME(3),
+	REGS_OFFSET_NAME(4),
+	REGS_OFFSET_NAME(5),
+	REGS_OFFSET_NAME(6),
+	REGS_OFFSET_NAME(7),
+	REGS_OFFSET_NAME(8),
+	REGS_OFFSET_NAME(9),
+	REGS_OFFSET_NAME(10),
+	REGS_OFFSET_NAME(11),
+	REGS_OFFSET_NAME(12),
+	REGS_OFFSET_NAME(13),
+	REGS_OFFSET_NAME(14),
+	REGS_OFFSET_NAME(15),
+	REG_OFFSET_NAME(pc),
+	REG_OFFSET_NAME(pr),
+	REG_OFFSET_NAME(sr),
+	REG_OFFSET_NAME(gbr),
+	REG_OFFSET_NAME(mach),
+	REG_OFFSET_NAME(macl),
+	REG_OFFSET_NAME(tra),
+	REG_OFFSET_END,
+};
+
 /*
  * These are our native regset flavours.
  */
@@ -338,9 +365,9 @@
 	return &user_sh_native_view;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
-	struct user * dummy = NULL;
 	unsigned long __user *datap = (unsigned long __user *)data;
 	int ret;
 
@@ -356,17 +383,20 @@
 
 		if (addr < sizeof(struct pt_regs))
 			tmp = get_stack_long(child, addr);
-		else if (addr >= (long) &dummy->fpu &&
-			 addr < (long) &dummy->u_fpvalid) {
+		else if (addr >= offsetof(struct user, fpu) &&
+			 addr < offsetof(struct user, u_fpvalid)) {
 			if (!tsk_used_math(child)) {
-				if (addr == (long)&dummy->fpu.fpscr)
+				if (addr == offsetof(struct user, fpu.fpscr))
 					tmp = FPSCR_INIT;
 				else
 					tmp = 0;
-			} else
-				tmp = ((long *)child->thread.xstate)
-					[(addr - (long)&dummy->fpu) >> 2];
-		} else if (addr == (long) &dummy->u_fpvalid)
+			} else {
+				unsigned long index;
+				index = addr - offsetof(struct user, fpu);
+				tmp = ((unsigned long *)child->thread.xstate)
+					[index >> 2];
+			}
+		} else if (addr == offsetof(struct user, u_fpvalid))
 			tmp = !!tsk_used_math(child);
 		else if (addr == PT_TEXT_ADDR)
 			tmp = child->mm->start_code;
@@ -390,13 +420,15 @@
 
 		if (addr < sizeof(struct pt_regs))
 			ret = put_stack_long(child, addr, data);
-		else if (addr >= (long) &dummy->fpu &&
-			 addr < (long) &dummy->u_fpvalid) {
+		else if (addr >= offsetof(struct user, fpu) &&
+			 addr < offsetof(struct user, u_fpvalid)) {
+			unsigned long index;
+			index = addr - offsetof(struct user, fpu);
 			set_stopped_child_used_math(child);
-			((long *)child->thread.xstate)
-				[(addr - (long)&dummy->fpu) >> 2] = data;
+			((unsigned long *)child->thread.xstate)
+				[index >> 2] = data;
 			ret = 0;
-		} else if (addr == (long) &dummy->u_fpvalid) {
+		} else if (addr == offsetof(struct user, u_fpvalid)) {
 			conditional_stopped_child_used_math(data, child);
 			ret = 0;
 		}
@@ -406,35 +438,35 @@
 		return copy_regset_to_user(child, &user_sh_native_view,
 					   REGSET_GENERAL,
 					   0, sizeof(struct pt_regs),
-					   (void __user *)data);
+					   datap);
 	case PTRACE_SETREGS:
 		return copy_regset_from_user(child, &user_sh_native_view,
 					     REGSET_GENERAL,
 					     0, sizeof(struct pt_regs),
-					     (const void __user *)data);
+					     datap);
 #ifdef CONFIG_SH_FPU
 	case PTRACE_GETFPREGS:
 		return copy_regset_to_user(child, &user_sh_native_view,
 					   REGSET_FPU,
 					   0, sizeof(struct user_fpu_struct),
-					   (void __user *)data);
+					   datap);
 	case PTRACE_SETFPREGS:
 		return copy_regset_from_user(child, &user_sh_native_view,
 					     REGSET_FPU,
 					     0, sizeof(struct user_fpu_struct),
-					     (const void __user *)data);
+					     datap);
 #endif
 #ifdef CONFIG_SH_DSP
 	case PTRACE_GETDSPREGS:
 		return copy_regset_to_user(child, &user_sh_native_view,
 					   REGSET_DSP,
 					   0, sizeof(struct pt_dspregs),
-					   (void __user *)data);
+					   datap);
 	case PTRACE_SETDSPREGS:
 		return copy_regset_from_user(child, &user_sh_native_view,
 					     REGSET_DSP,
 					     0, sizeof(struct pt_dspregs),
-					     (const void __user *)data);
+					     datap);
 #endif
 	default:
 		ret = ptrace_request(child, request, addr, data);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace_64.c linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace_64.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
@@ -252,6 +252,85 @@
 }
 #endif
 
+const struct pt_regs_offset regoffset_table[] = {
+	REG_OFFSET_NAME(pc),
+	REG_OFFSET_NAME(sr),
+	REG_OFFSET_NAME(syscall_nr),
+	REGS_OFFSET_NAME(0),
+	REGS_OFFSET_NAME(1),
+	REGS_OFFSET_NAME(2),
+	REGS_OFFSET_NAME(3),
+	REGS_OFFSET_NAME(4),
+	REGS_OFFSET_NAME(5),
+	REGS_OFFSET_NAME(6),
+	REGS_OFFSET_NAME(7),
+	REGS_OFFSET_NAME(8),
+	REGS_OFFSET_NAME(9),
+	REGS_OFFSET_NAME(10),
+	REGS_OFFSET_NAME(11),
+	REGS_OFFSET_NAME(12),
+	REGS_OFFSET_NAME(13),
+	REGS_OFFSET_NAME(14),
+	REGS_OFFSET_NAME(15),
+	REGS_OFFSET_NAME(16),
+	REGS_OFFSET_NAME(17),
+	REGS_OFFSET_NAME(18),
+	REGS_OFFSET_NAME(19),
+	REGS_OFFSET_NAME(20),
+	REGS_OFFSET_NAME(21),
+	REGS_OFFSET_NAME(22),
+	REGS_OFFSET_NAME(23),
+	REGS_OFFSET_NAME(24),
+	REGS_OFFSET_NAME(25),
+	REGS_OFFSET_NAME(26),
+	REGS_OFFSET_NAME(27),
+	REGS_OFFSET_NAME(28),
+	REGS_OFFSET_NAME(29),
+	REGS_OFFSET_NAME(30),
+	REGS_OFFSET_NAME(31),
+	REGS_OFFSET_NAME(32),
+	REGS_OFFSET_NAME(33),
+	REGS_OFFSET_NAME(34),
+	REGS_OFFSET_NAME(35),
+	REGS_OFFSET_NAME(36),
+	REGS_OFFSET_NAME(37),
+	REGS_OFFSET_NAME(38),
+	REGS_OFFSET_NAME(39),
+	REGS_OFFSET_NAME(40),
+	REGS_OFFSET_NAME(41),
+	REGS_OFFSET_NAME(42),
+	REGS_OFFSET_NAME(43),
+	REGS_OFFSET_NAME(44),
+	REGS_OFFSET_NAME(45),
+	REGS_OFFSET_NAME(46),
+	REGS_OFFSET_NAME(47),
+	REGS_OFFSET_NAME(48),
+	REGS_OFFSET_NAME(49),
+	REGS_OFFSET_NAME(50),
+	REGS_OFFSET_NAME(51),
+	REGS_OFFSET_NAME(52),
+	REGS_OFFSET_NAME(53),
+	REGS_OFFSET_NAME(54),
+	REGS_OFFSET_NAME(55),
+	REGS_OFFSET_NAME(56),
+	REGS_OFFSET_NAME(57),
+	REGS_OFFSET_NAME(58),
+	REGS_OFFSET_NAME(59),
+	REGS_OFFSET_NAME(60),
+	REGS_OFFSET_NAME(61),
+	REGS_OFFSET_NAME(62),
+	REGS_OFFSET_NAME(63),
+	TREGS_OFFSET_NAME(0),
+	TREGS_OFFSET_NAME(1),
+	TREGS_OFFSET_NAME(2),
+	TREGS_OFFSET_NAME(3),
+	TREGS_OFFSET_NAME(4),
+	TREGS_OFFSET_NAME(5),
+	TREGS_OFFSET_NAME(6),
+	TREGS_OFFSET_NAME(7),
+	REG_OFFSET_END,
+};
+
 /*
  * These are our native regset flavours.
  */
@@ -304,9 +383,11 @@
 	return &user_sh64_native_view;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
+	unsigned long __user *datap = (unsigned long __user *) data;
 
 	switch (request) {
 	/* read the word at location addr in the USER area. */
@@ -321,13 +402,15 @@
 			tmp = get_stack_long(child, addr);
 		else if ((addr >= offsetof(struct user, fpu)) &&
 			 (addr <  offsetof(struct user, u_fpvalid))) {
-			tmp = get_fpu_long(child, addr - offsetof(struct user, fpu));
+			unsigned long index;
+			index = addr - offsetof(struct user, fpu);
+			tmp = get_fpu_long(child, index);
 		} else if (addr == offsetof(struct user, u_fpvalid)) {
 			tmp = !!tsk_used_math(child);
 		} else {
 			break;
 		}
-		ret = put_user(tmp, (unsigned long *)data);
+		ret = put_user(tmp, datap);
 		break;
 	}
 
@@ -358,7 +441,9 @@
 		}
 		else if ((addr >= offsetof(struct user, fpu)) &&
 			 (addr <  offsetof(struct user, u_fpvalid))) {
-			ret = put_fpu_long(child, addr - offsetof(struct user, fpu), data);
+			unsigned long index;
+			index = addr - offsetof(struct user, fpu);
+			ret = put_fpu_long(child, index, data);
 		}
 		break;
 
@@ -366,23 +451,23 @@
 		return copy_regset_to_user(child, &user_sh64_native_view,
 					   REGSET_GENERAL,
 					   0, sizeof(struct pt_regs),
-					   (void __user *)data);
+					   datap);
 	case PTRACE_SETREGS:
 		return copy_regset_from_user(child, &user_sh64_native_view,
 					     REGSET_GENERAL,
 					     0, sizeof(struct pt_regs),
-					     (const void __user *)data);
+					     datap);
 #ifdef CONFIG_SH_FPU
 	case PTRACE_GETFPREGS:
 		return copy_regset_to_user(child, &user_sh64_native_view,
 					   REGSET_FPU,
 					   0, sizeof(struct user_fpu_struct),
-					   (void __user *)data);
+					   datap);
 	case PTRACE_SETFPREGS:
 		return copy_regset_from_user(child, &user_sh64_native_view,
 					     REGSET_FPU,
 					     0, sizeof(struct user_fpu_struct),
-					     (const void __user *)data);
+					     datap);
 #endif
 	default:
 		ret = ptrace_request(child, request, addr, data);
@@ -392,13 +477,13 @@
 	return ret;
 }
 
-asmlinkage int sh64_ptrace(long request, long pid, long addr, long data)
+asmlinkage int sh64_ptrace(long request, long pid,
+			   unsigned long addr, unsigned long data)
 {
 #define WPC_DBRMODE 0x0d104008
-	static int first_call = 1;
+	static unsigned long first_call;
 
-	lock_kernel();
-	if (first_call) {
+	if (!test_and_set_bit(0, &first_call)) {
 		/* Set WPC.DBRMODE to 0.  This makes all debug events get
 		 * delivered through RESVEC, i.e. into the handlers in entry.S.
 		 * (If the kernel was downloaded using a remote gdb, WPC.DBRMODE
@@ -408,9 +493,7 @@
 		 * the remote gdb.) */
 		printk("DBRMODE set to 0 to permit native debugging\n");
 		poke_real_address_q(WPC_DBRMODE, 0);
-		first_call = 0;
 	}
-	unlock_kernel();
 
 	return sys_ptrace(request, pid, addr, data);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/ptrace.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,33 @@
+#include <linux/ptrace.h>
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name:	the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+	const struct pt_regs_offset *roff;
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (!strcmp(roff->name, name))
+			return roff->offset;
+	return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset:	the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+	const struct pt_regs_offset *roff;
+	for (roff = regoffset_table; roff->name != NULL; roff++)
+		if (roff->offset == offset)
+			return roff->name;
+	return NULL;
+}
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/reboot.c linux-libre-2.6.37-gnu/arch/sh/kernel/reboot.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/reboot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/reboot.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
 #include <asm/addrspace.h>
 #include <asm/reboot.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
 
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
@@ -25,6 +26,9 @@
 {
 	local_irq_disable();
 
+	/* Destroy all of the TLBs in preparation for reset by MMU */
+	__flush_tlb_global();
+
 	/* Address error with SR.BL=1 first. */
 	trigger_address_error();
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/setup.c linux-libre-2.6.37-gnu/arch/sh/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/err.h>
-#include <linux/debugfs.h>
 #include <linux/crash_dump.h>
 #include <linux/mmzone.h>
 #include <linux/clk.h>
@@ -42,6 +41,7 @@
 #include <asm/smp.h>
 #include <asm/mmu_context.h>
 #include <asm/mmzone.h>
+#include <asm/sparsemem.h>
 
 /*
  * Initialize loops_per_jiffy as 10000000 (1000MIPS).
@@ -53,6 +53,7 @@
 		.type			= CPU_SH_NONE,
 		.family			= CPU_FAMILY_UNKNOWN,
 		.loops_per_jiffy	= 10000000,
+		.phys_bits		= MAX_PHYSMEM_BITS,
 	},
 };
 EXPORT_SYMBOL(cpu_data);
@@ -136,8 +137,9 @@
 		goto disable;
 	}
 
-	if (unlikely(start < PAGE_OFFSET)) {
-		pr_err("initrd start < PAGE_OFFSET\n");
+	if (unlikely(start < __MEMORY_START)) {
+		pr_err("initrd start (%08lx) < __MEMORY_START(%x)\n",
+			start, __MEMORY_START);
 		goto disable;
 	}
 
@@ -158,7 +160,7 @@
 	/*
 	 * Address sanitization
 	 */
-	initrd_start = (unsigned long)__va(__pa(start));
+	initrd_start = (unsigned long)__va(start);
 	initrd_end = initrd_start + INITRD_SIZE;
 
 	memblock_reserve(__pa(initrd_start), INITRD_SIZE);
@@ -432,6 +434,8 @@
 	if (c->flags & CPU_HAS_L2_CACHE)
 		show_cacheinfo(m, "scache", c->scache);
 
+	seq_printf(m, "address sizes\t: %u bits physical\n", c->phys_bits);
+
 	seq_printf(m, "bogomips\t: %lu.%02lu\n",
 		     c->loops_per_jiffy/(500000/HZ),
 		     (c->loops_per_jiffy/(5000/HZ)) % 100);
@@ -458,17 +462,3 @@
 	.show	= show_cpuinfo,
 };
 #endif /* CONFIG_PROC_FS */
-
-struct dentry *sh_debugfs_root;
-
-static int __init sh_debugfs_init(void)
-{
-	sh_debugfs_root = debugfs_create_dir("sh", NULL);
-	if (!sh_debugfs_root)
-		return -ENOMEM;
-	if (IS_ERR(sh_debugfs_root))
-		return PTR_ERR(sh_debugfs_root);
-
-	return 0;
-}
-arch_initcall(sh_debugfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/syscalls_32.S linux-libre-2.6.37-gnu/arch/sh/kernel/syscalls_32.S
--- linux-libre-2.6.36-gnu/arch/sh/kernel/syscalls_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/syscalls_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -353,3 +353,26 @@
 	.long sys_pwritev
 	.long sys_rt_tgsigqueueinfo	/* 335 */
 	.long sys_perf_event_open
+	.long sys_fanotify_init
+	.long sys_fanotify_mark
+	.long sys_prlimit64
+	/* Broken-out socket family */
+	.long sys_socket		/* 340 */
+	.long sys_bind
+	.long sys_connect
+	.long sys_listen
+	.long sys_accept
+	.long sys_getsockname	/* 345 */
+	.long sys_getpeername
+	.long sys_socketpair
+	.long sys_send
+	.long sys_sendto
+	.long sys_recv			/* 350 */
+	.long sys_recvfrom
+	.long sys_shutdown
+	.long sys_setsockopt
+	.long sys_getsockopt
+	.long sys_sendmsg		/* 355 */
+	.long sys_recvmsg
+	.long sys_recvmmsg
+	.long sys_accept4
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/syscalls_64.S linux-libre-2.6.37-gnu/arch/sh/kernel/syscalls_64.S
--- linux-libre-2.6.36-gnu/arch/sh/kernel/syscalls_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/syscalls_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -393,3 +393,6 @@
 	.long sys_perf_event_open
 	.long sys_recvmmsg		/* 365 */
 	.long sys_accept4
+	.long sys_fanotify_init
+	.long sys_fanotify_mark
+	.long sys_prlimit64
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/sys_sh.c linux-libre-2.6.37-gnu/arch/sh/kernel/sys_sh.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/sys_sh.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/sys_sh.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,7 @@
 	}
 
 	if (op & CACHEFLUSH_I)
-		flush_cache_all();
+		flush_icache_range(addr, addr+len);
 
 	up_read(&current->mm->mmap_sem);
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/traps_32.c linux-libre-2.6.37-gnu/arch/sh/kernel/traps_32.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/traps_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/traps_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  *                  Copyright (C) 2000 Philipp Rumpf
  *                  Copyright (C) 2000 David Howells
- *                  Copyright (C) 2002 - 2007 Paul Mundt
+ *                  Copyright (C) 2002 - 2010 Paul Mundt
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -26,6 +26,7 @@
 #include <linux/limits.h>
 #include <linux/sysfs.h>
 #include <linux/uaccess.h>
+#include <linux/perf_event.h>
 #include <asm/system.h>
 #include <asm/alignment.h>
 #include <asm/fpu.h>
@@ -369,7 +370,8 @@
 #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
 
 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
-			    struct mem_access *ma, int expected)
+			    struct mem_access *ma, int expected,
+			    unsigned long address)
 {
 	u_int rm;
 	int ret, index;
@@ -383,9 +385,18 @@
 	index = (instruction>>8)&15;	/* 0x0F00 */
 	rm = regs->regs[index];
 
-	/* shout about fixups */
-	if (!expected)
+	/*
+	 * Log the unexpected fixups, and then pass them on to perf.
+	 *
+	 * We intentionally don't report the expected cases to perf as
+	 * otherwise the trapped I/O case will skew the results too much
+	 * to be useful.
+	 */
+	if (!expected) {
 		unaligned_fixups_notify(current, instruction, regs);
+		perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
+			      regs, address);
+	}
 
 	ret = -EFAULT;
 	switch (instruction&0xF000) {
@@ -574,7 +585,8 @@
 
 		set_fs(USER_DS);
 		tmp = handle_unaligned_access(instruction, regs,
-					      &user_mem_access, 0);
+					      &user_mem_access, 0,
+					      address);
 		set_fs(oldfs);
 
 		if (tmp == 0)
@@ -607,8 +619,8 @@
 
 		unaligned_fixups_notify(current, instruction, regs);
 
-		handle_unaligned_access(instruction, regs,
-					&user_mem_access, 0);
+		handle_unaligned_access(instruction, regs, &user_mem_access,
+					0, address);
 		set_fs(oldfs);
 	}
 }
@@ -802,6 +814,9 @@
 		     : /* no output */
 		     : "r" (&vbr_base)
 		     : "memory");
+
+	/* disable exception blocking now when the vbr has been setup */
+	clear_bl_bit();
 }
 
 void *set_exception_table_vec(unsigned int vec, void *handler)
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/traps_64.c linux-libre-2.6.37-gnu/arch/sh/kernel/traps_64.c
--- linux-libre-2.6.36-gnu/arch/sh/kernel/traps_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/traps_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
 #include <linux/module.h>
+#include <linux/perf_event.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -50,7 +51,7 @@
 	do_unhandled_exception(trapnr, signr, str, __stringify(name), error_code, regs, current); \
 }
 
-spinlock_t die_lock;
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
@@ -433,6 +434,8 @@
 		return error;
 	}
 
+	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
 	destreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
 		__u64 buffer;
@@ -509,6 +512,8 @@
 		return error;
 	}
 
+	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
+
 	srcreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
 		__u64 buffer;
@@ -583,6 +588,8 @@
 		return error;
 	}
 
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
 	destreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
 		__u64 buffer;
@@ -658,6 +665,8 @@
 		return error;
 	}
 
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
+
 	srcreg = (opcode >> 4) & 0x3f;
 	if (user_mode(regs)) {
 		__u64 buffer;
diff -druN linux-libre-2.6.36-gnu/arch/sh/kernel/vsyscall/vsyscall-trapa.S linux-libre-2.6.37-gnu/arch/sh/kernel/vsyscall/vsyscall-trapa.S
--- linux-libre-2.6.36-gnu/arch/sh/kernel/vsyscall/vsyscall-trapa.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/kernel/vsyscall/vsyscall-trapa.S	2011-01-04 19:50:19.000000000 -0500
@@ -8,9 +8,9 @@
 	 * fill out .eh_frame -- PFM. */
 .LEND_vsyscall:
 	.size __kernel_vsyscall,.-.LSTART_vsyscall
-	.previous
 
 	.section .eh_frame,"a",@progbits
+	.previous
 .LCIE:
 	.ualong	.LCIE_end - .LCIE_start
 .LCIE_start:
diff -druN linux-libre-2.6.36-gnu/arch/sh/lib/Makefile linux-libre-2.6.37-gnu/arch/sh/lib/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/lib/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/lib/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -30,4 +30,4 @@
 lib-$(CONFIG_MCOUNT)		+= mcount.o
 lib-y				+= $(memcpy-y) $(memset-y) $(udivsi3-y)
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff -druN linux-libre-2.6.36-gnu/arch/sh/Makefile linux-libre-2.6.37-gnu/arch/sh/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -133,10 +133,7 @@
 machdir-$(CONFIG_SH_HP6XX)			+= mach-hp6xx
 machdir-$(CONFIG_SH_DREAMCAST)			+= mach-dreamcast
 machdir-$(CONFIG_SH_SH03)			+= mach-sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410)		+= mach-snapgear
 machdir-$(CONFIG_SH_RTS7751R2D)			+= mach-r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH)		+= mach-systemh
-machdir-$(CONFIG_SH_EDOSK7705)			+= mach-edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)			+= mach-highlander
 machdir-$(CONFIG_SH_MIGOR)			+= mach-migor
 machdir-$(CONFIG_SH_AP325RXA)			+= mach-ap325rxa
diff -druN linux-libre-2.6.36-gnu/arch/sh/math-emu/math.c linux-libre-2.6.37-gnu/arch/sh/math-emu/math.c
--- linux-libre-2.6.36-gnu/arch/sh/math-emu/math.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/math-emu/math.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/perf_event.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -619,6 +620,8 @@
 	struct task_struct *tsk = current;
 	struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
 
+	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
+
 	if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
 		/* initialize once. */
 		fpu_init(fpu);
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/asids-debugfs.c linux-libre-2.6.37-gnu/arch/sh/mm/asids-debugfs.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/asids-debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/asids-debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -63,7 +63,7 @@
 {
 	struct dentry *asids_dentry;
 
-	asids_dentry = debugfs_create_file("asids", S_IRUSR, sh_debugfs_root,
+	asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
 					   NULL, &asids_debugfs_fops);
 	if (!asids_dentry)
 		return -ENOMEM;
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/cache.c linux-libre-2.6.37-gnu/arch/sh/mm/cache.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/cache.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/cache.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,14 +60,14 @@
 		       unsigned long len)
 {
 	if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
-	    !test_bit(PG_dcache_dirty, &page->flags)) {
+	    test_bit(PG_dcache_clean, &page->flags)) {
 		void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
 		memcpy(vto, src, len);
 		kunmap_coherent(vto);
 	} else {
 		memcpy(dst, src, len);
 		if (boot_cpu_data.dcache.n_aliases)
-			set_bit(PG_dcache_dirty, &page->flags);
+			clear_bit(PG_dcache_clean, &page->flags);
 	}
 
 	if (vma->vm_flags & VM_EXEC)
@@ -79,14 +79,14 @@
 			 unsigned long len)
 {
 	if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
-	    !test_bit(PG_dcache_dirty, &page->flags)) {
+	    test_bit(PG_dcache_clean, &page->flags)) {
 		void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
 		memcpy(dst, vfrom, len);
 		kunmap_coherent(vfrom);
 	} else {
 		memcpy(dst, src, len);
 		if (boot_cpu_data.dcache.n_aliases)
-			set_bit(PG_dcache_dirty, &page->flags);
+			clear_bit(PG_dcache_clean, &page->flags);
 	}
 }
 
@@ -98,7 +98,7 @@
 	vto = kmap_atomic(to, KM_USER1);
 
 	if (boot_cpu_data.dcache.n_aliases && page_mapped(from) &&
-	    !test_bit(PG_dcache_dirty, &from->flags)) {
+	    test_bit(PG_dcache_clean, &from->flags)) {
 		vfrom = kmap_coherent(from, vaddr);
 		copy_page(vto, vfrom);
 		kunmap_coherent(vfrom);
@@ -141,7 +141,7 @@
 
 	page = pfn_to_page(pfn);
 	if (pfn_valid(pfn)) {
-		int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
+		int dirty = !test_and_set_bit(PG_dcache_clean, &page->flags);
 		if (dirty)
 			__flush_purge_region(page_address(page), PAGE_SIZE);
 	}
@@ -153,7 +153,7 @@
 
 	if (pages_do_alias(addr, vmaddr)) {
 		if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
-		    !test_bit(PG_dcache_dirty, &page->flags)) {
+		    test_bit(PG_dcache_clean, &page->flags)) {
 			void *kaddr;
 
 			kaddr = kmap_coherent(page, vmaddr);
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/cache-debugfs.c linux-libre-2.6.37-gnu/arch/sh/mm/cache-debugfs.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/cache-debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/cache-debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,25 +126,19 @@
 {
 	struct dentry *dcache_dentry, *icache_dentry;
 
-	dcache_dentry = debugfs_create_file("dcache", S_IRUSR, sh_debugfs_root,
+	dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
 					    (unsigned int *)CACHE_TYPE_DCACHE,
 					    &cache_debugfs_fops);
 	if (!dcache_dentry)
 		return -ENOMEM;
-	if (IS_ERR(dcache_dentry))
-		return PTR_ERR(dcache_dentry);
 
-	icache_dentry = debugfs_create_file("icache", S_IRUSR, sh_debugfs_root,
+	icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
 					    (unsigned int *)CACHE_TYPE_ICACHE,
 					    &cache_debugfs_fops);
 	if (!icache_dentry) {
 		debugfs_remove(dcache_dentry);
 		return -ENOMEM;
 	}
-	if (IS_ERR(icache_dentry)) {
-		debugfs_remove(dcache_dentry);
-		return PTR_ERR(icache_dentry);
-	}
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/cache-sh4.c linux-libre-2.6.37-gnu/arch/sh/mm/cache-sh4.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/cache-sh4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/cache-sh4.c	2011-01-04 19:50:19.000000000 -0500
@@ -114,7 +114,7 @@
 	struct address_space *mapping = page_mapping(page);
 
 	if (mapping && !mapping_mapped(mapping))
-		set_bit(PG_dcache_dirty, &page->flags);
+		clear_bit(PG_dcache_clean, &page->flags);
 	else
 #endif
 		flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
@@ -239,7 +239,7 @@
 		 * another ASID than the current one.
 		 */
 		map_coherent = (current_cpu_data.dcache.n_aliases &&
-			!test_bit(PG_dcache_dirty, &page->flags) &&
+			test_bit(PG_dcache_clean, &page->flags) &&
 			page_mapped(page));
 		if (map_coherent)
 			vaddr = kmap_coherent(page, address);
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/cache-sh7705.c linux-libre-2.6.37-gnu/arch/sh/mm/cache-sh7705.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/cache-sh7705.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/cache-sh7705.c	2011-01-04 19:50:19.000000000 -0500
@@ -139,7 +139,7 @@
 	struct address_space *mapping = page_mapping(page);
 
 	if (mapping && !mapping_mapped(mapping))
-		set_bit(PG_dcache_dirty, &page->flags);
+		clear_bit(PG_dcache_clean, &page->flags);
 	else
 		__flush_dcache_page(__pa(page_address(page)));
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/consistent.c linux-libre-2.6.37-gnu/arch/sh/mm/consistent.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/consistent.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/consistent.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,11 +38,12 @@
 	void *ret, *ret_nocache;
 	int order = get_order(size);
 
+	gfp |= __GFP_ZERO;
+
 	ret = (void *)__get_free_pages(gfp, order);
 	if (!ret)
 		return NULL;
 
-	memset(ret, 0, size);
 	/*
 	 * Pages from the page allocator may have data present in
 	 * cache. So flush the cache before using uncached memory.
@@ -78,21 +79,20 @@
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 		    enum dma_data_direction direction)
 {
-#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
-	void *p1addr = vaddr;
-#else
-	void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
-#endif
+	void *addr;
+
+	addr = __in_29bit_mode() ?
+	       (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
 
 	switch (direction) {
 	case DMA_FROM_DEVICE:		/* invalidate only */
-		__flush_invalidate_region(p1addr, size);
+		__flush_invalidate_region(addr, size);
 		break;
 	case DMA_TO_DEVICE:		/* writeback only */
-		__flush_wback_region(p1addr, size);
+		__flush_wback_region(addr, size);
 		break;
 	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
-		__flush_purge_region(p1addr, size);
+		__flush_purge_region(addr, size);
 		break;
 	default:
 		BUG();
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/gup.c linux-libre-2.6.37-gnu/arch/sh/mm/gup.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/gup.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/mm/gup.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,273 @@
+/*
+ * Lockless get_user_pages_fast for SuperH
+ *
+ * Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * Cloned from the x86 and PowerPC versions, by:
+ *
+ *	Copyright (C) 2008 Nick Piggin
+ *	Copyright (C) 2008 Novell Inc.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/highmem.h>
+#include <asm/pgtable.h>
+
+static inline pte_t gup_get_pte(pte_t *ptep)
+{
+#ifndef CONFIG_X2TLB
+	return ACCESS_ONCE(*ptep);
+#else
+	/*
+	 * With get_user_pages_fast, we walk down the pagetables without
+	 * taking any locks.  For this we would like to load the pointers
+	 * atomically, but that is not possible with 64-bit PTEs.  What
+	 * we do have is the guarantee that a pte will only either go
+	 * from not present to present, or present to not present or both
+	 * -- it will not switch to a completely different present page
+	 * without a TLB flush in between; something that we are blocking
+	 * by holding interrupts off.
+	 *
+	 * Setting ptes from not present to present goes:
+	 * ptep->pte_high = h;
+	 * smp_wmb();
+	 * ptep->pte_low = l;
+	 *
+	 * And present to not present goes:
+	 * ptep->pte_low = 0;
+	 * smp_wmb();
+	 * ptep->pte_high = 0;
+	 *
+	 * We must ensure here that the load of pte_low sees l iff pte_high
+	 * sees h. We load pte_high *after* loading pte_low, which ensures we
+	 * don't see an older value of pte_high.  *Then* we recheck pte_low,
+	 * which ensures that we haven't picked up a changed pte high. We might
+	 * have got rubbish values from pte_low and pte_high, but we are
+	 * guaranteed that pte_low will not have the present bit set *unless*
+	 * it is 'l'. And get_user_pages_fast only operates on present ptes, so
+	 * we're safe.
+	 *
+	 * gup_get_pte should not be used or copied outside gup.c without being
+	 * very careful -- it does not atomically load the pte or anything that
+	 * is likely to be useful for you.
+	 */
+	pte_t pte;
+
+retry:
+	pte.pte_low = ptep->pte_low;
+	smp_rmb();
+	pte.pte_high = ptep->pte_high;
+	smp_rmb();
+	if (unlikely(pte.pte_low != ptep->pte_low))
+		goto retry;
+
+	return pte;
+#endif
+}
+
+/*
+ * The performance critical leaf functions are made noinline otherwise gcc
+ * inlines everything into a single function which results in too much
+ * register pressure.
+ */
+static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
+		unsigned long end, int write, struct page **pages, int *nr)
+{
+	u64 mask, result;
+	pte_t *ptep;
+
+#ifdef CONFIG_X2TLB
+	result = _PAGE_PRESENT | _PAGE_EXT(_PAGE_EXT_KERN_READ | _PAGE_EXT_USER_READ);
+	if (write)
+		result |= _PAGE_EXT(_PAGE_EXT_KERN_WRITE | _PAGE_EXT_USER_WRITE);
+#elif defined(CONFIG_SUPERH64)
+	result = _PAGE_PRESENT | _PAGE_USER | _PAGE_READ;
+	if (write)
+		result |= _PAGE_WRITE;
+#else
+	result = _PAGE_PRESENT | _PAGE_USER;
+	if (write)
+		result |= _PAGE_RW;
+#endif
+
+	mask = result | _PAGE_SPECIAL;
+
+	ptep = pte_offset_map(&pmd, addr);
+	do {
+		pte_t pte = gup_get_pte(ptep);
+		struct page *page;
+
+		if ((pte_val(pte) & mask) != result) {
+			pte_unmap(ptep);
+			return 0;
+		}
+		VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+		page = pte_page(pte);
+		get_page(page);
+		pages[*nr] = page;
+		(*nr)++;
+
+	} while (ptep++, addr += PAGE_SIZE, addr != end);
+	pte_unmap(ptep - 1);
+
+	return 1;
+}
+
+static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
+		int write, struct page **pages, int *nr)
+{
+	unsigned long next;
+	pmd_t *pmdp;
+
+	pmdp = pmd_offset(&pud, addr);
+	do {
+		pmd_t pmd = *pmdp;
+
+		next = pmd_addr_end(addr, end);
+		if (pmd_none(pmd))
+			return 0;
+		if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+			return 0;
+	} while (pmdp++, addr = next, addr != end);
+
+	return 1;
+}
+
+static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
+			int write, struct page **pages, int *nr)
+{
+	unsigned long next;
+	pud_t *pudp;
+
+	pudp = pud_offset(&pgd, addr);
+	do {
+		pud_t pud = *pudp;
+
+		next = pud_addr_end(addr, end);
+		if (pud_none(pud))
+			return 0;
+		if (!gup_pmd_range(pud, addr, next, write, pages, nr))
+			return 0;
+	} while (pudp++, addr = next, addr != end);
+
+	return 1;
+}
+
+/*
+ * Like get_user_pages_fast() except its IRQ-safe in that it won't fall
+ * back to the regular GUP.
+ */
+int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
+			  struct page **pages)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr, len, end;
+	unsigned long next;
+	unsigned long flags;
+	pgd_t *pgdp;
+	int nr = 0;
+
+	start &= PAGE_MASK;
+	addr = start;
+	len = (unsigned long) nr_pages << PAGE_SHIFT;
+	end = start + len;
+	if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
+					(void __user *)start, len)))
+		return 0;
+
+	/*
+	 * This doesn't prevent pagetable teardown, but does prevent
+	 * the pagetables and pages from being freed.
+	 */
+	local_irq_save(flags);
+	pgdp = pgd_offset(mm, addr);
+	do {
+		pgd_t pgd = *pgdp;
+
+		next = pgd_addr_end(addr, end);
+		if (pgd_none(pgd))
+			break;
+		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+			break;
+	} while (pgdp++, addr = next, addr != end);
+	local_irq_restore(flags);
+
+	return nr;
+}
+
+/**
+ * get_user_pages_fast() - pin user pages in memory
+ * @start:	starting user address
+ * @nr_pages:	number of pages from start to pin
+ * @write:	whether pages will be written to
+ * @pages:	array that receives pointers to the pages pinned.
+ *		Should be at least nr_pages long.
+ *
+ * Attempt to pin user pages in memory without taking mm->mmap_sem.
+ * If not successful, it will fall back to taking the lock and
+ * calling get_user_pages().
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If nr_pages is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno.
+ */
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+			struct page **pages)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr, len, end;
+	unsigned long next;
+	pgd_t *pgdp;
+	int nr = 0;
+
+	start &= PAGE_MASK;
+	addr = start;
+	len = (unsigned long) nr_pages << PAGE_SHIFT;
+
+	end = start + len;
+	if (end < start)
+		goto slow_irqon;
+
+	local_irq_disable();
+	pgdp = pgd_offset(mm, addr);
+	do {
+		pgd_t pgd = *pgdp;
+
+		next = pgd_addr_end(addr, end);
+		if (pgd_none(pgd))
+			goto slow;
+		if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
+			goto slow;
+	} while (pgdp++, addr = next, addr != end);
+	local_irq_enable();
+
+	VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
+	return nr;
+
+	{
+		int ret;
+
+slow:
+		local_irq_enable();
+slow_irqon:
+		/* Try to get the remaining pages with get_user_pages */
+		start += nr << PAGE_SHIFT;
+		pages += nr;
+
+		down_read(&mm->mmap_sem);
+		ret = get_user_pages(current, mm, start,
+			(end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
+		up_read(&mm->mmap_sem);
+
+		/* Have to be a bit careful with return values */
+		if (nr > 0) {
+			if (ret < 0)
+				ret = nr;
+			else
+				ret += nr;
+		}
+
+		return ret;
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/init.c linux-libre-2.6.37-gnu/arch/sh/mm/init.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,7 +47,6 @@
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
-	pte_t *pte;
 
 	pgd = pgd_offset_k(addr);
 	if (pgd_none(*pgd)) {
@@ -67,8 +66,7 @@
 		return NULL;
 	}
 
-	pte = pte_offset_kernel(pmd, addr);
-	return pte;
+	return pte_offset_kernel(pmd, addr);
 }
 
 static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
@@ -125,13 +123,45 @@
 	clear_pte_phys(address, prot);
 }
 
+static pmd_t * __init one_md_table_init(pud_t *pud)
+{
+	if (pud_none(*pud)) {
+		pmd_t *pmd;
+
+		pmd = alloc_bootmem_pages(PAGE_SIZE);
+		pud_populate(&init_mm, pud, pmd);
+		BUG_ON(pmd != pmd_offset(pud, 0));
+	}
+
+	return pmd_offset(pud, 0);
+}
+
+static pte_t * __init one_page_table_init(pmd_t *pmd)
+{
+	if (pmd_none(*pmd)) {
+		pte_t *pte;
+
+		pte = alloc_bootmem_pages(PAGE_SIZE);
+		pmd_populate_kernel(&init_mm, pmd, pte);
+		BUG_ON(pte != pte_offset_kernel(pmd, 0));
+	}
+
+	return pte_offset_kernel(pmd, 0);
+}
+
+static pte_t * __init page_table_kmap_check(pte_t *pte, pmd_t *pmd,
+					    unsigned long vaddr, pte_t *lastpte)
+{
+	return pte;
+}
+
 void __init page_table_range_init(unsigned long start, unsigned long end,
 					 pgd_t *pgd_base)
 {
 	pgd_t *pgd;
 	pud_t *pud;
 	pmd_t *pmd;
-	pte_t *pte;
+	pte_t *pte = NULL;
 	int i, j, k;
 	unsigned long vaddr;
 
@@ -144,19 +174,13 @@
 	for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
 		pud = (pud_t *)pgd;
 		for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
-#ifdef __PAGETABLE_PMD_FOLDED
-			pmd = (pmd_t *)pud;
-#else
-			pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
-			pud_populate(&init_mm, pud, pmd);
+			pmd = one_md_table_init(pud);
+#ifndef __PAGETABLE_PMD_FOLDED
 			pmd += k;
 #endif
 			for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
-				if (pmd_none(*pmd)) {
-					pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-					pmd_populate_kernel(&init_mm, pmd, pte);
-					BUG_ON(pte != pte_offset_kernel(pmd, 0));
-				}
+				pte = page_table_kmap_check(one_page_table_init(pmd),
+							    pmd, vaddr, pte);
 				vaddr += PMD_SIZE;
 			}
 			k = 0;
@@ -200,7 +224,6 @@
 	unsigned long total_pages, paddr;
 	unsigned long end_pfn;
 	struct pglist_data *p;
-	int i;
 
 	p = NODE_DATA(nid);
 
@@ -226,11 +249,12 @@
 	 * reservations in other nodes.
 	 */
 	if (nid == 0) {
+		struct memblock_region *reg;
+
 		/* Reserve the sections we're already using. */
-		for (i = 0; i < memblock.reserved.cnt; i++)
-			reserve_bootmem(memblock.reserved.region[i].base,
-					memblock_size_bytes(&memblock.reserved, i),
-					BOOTMEM_DEFAULT);
+		for_each_memblock(reserved, reg) {
+			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+		}
 	}
 
 	sparse_memory_present_with_active_regions(nid);
@@ -238,13 +262,14 @@
 
 static void __init do_init_bootmem(void)
 {
+	struct memblock_region *reg;
 	int i;
 
 	/* Add active regions with valid PFNs. */
-	for (i = 0; i < memblock.memory.cnt; i++) {
+	for_each_memblock(memory, reg) {
 		unsigned long start_pfn, end_pfn;
-		start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-		end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+		start_pfn = memblock_region_memory_base_pfn(reg);
+		end_pfn = memblock_region_memory_end_pfn(reg);
 		__add_active_range(0, start_pfn, end_pfn);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/Kconfig linux-libre-2.6.37-gnu/arch/sh/mm/Kconfig
--- linux-libre-2.6.36-gnu/arch/sh/mm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 
 config 32BIT
 	bool
-	default y if CPU_SH5
+	default y if CPU_SH5 || !MMU
 
 config PMB
 	bool "Support 32-bit physical addressing through PMB"
@@ -168,6 +168,10 @@
 config UNCACHED_MAPPING
 	bool
 
+config HAVE_SRAM_POOL
+	bool
+	select GENERIC_ALLOCATOR
+
 choice
 	prompt "Kernel page size"
 	default PAGE_SIZE_4KB
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/kmap.c linux-libre-2.6.37-gnu/arch/sh/mm/kmap.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/kmap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/kmap.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 	enum fixed_addresses idx;
 	unsigned long vaddr;
 
-	BUG_ON(test_bit(PG_dcache_dirty, &page->flags));
+	BUG_ON(!test_bit(PG_dcache_clean, &page->flags));
 
 	pagefault_disable();
 
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/Makefile linux-libre-2.6.37-gnu/arch/sh/mm/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/mm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
 obj-y			+= $(cacheops-y)
 
 mmu-y			:= nommu.o extable_32.o
-mmu-$(CONFIG_MMU)	:= extable_$(BITS).o fault_$(BITS).o \
+mmu-$(CONFIG_MMU)	:= extable_$(BITS).o fault_$(BITS).o gup.o \
 			   ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
 
 obj-y			+= $(mmu-y)
@@ -40,6 +40,7 @@
 obj-$(CONFIG_NUMA)		+= numa.o
 obj-$(CONFIG_IOREMAP_FIXED)	+= ioremap_fixed.o
 obj-$(CONFIG_UNCACHED_MAPPING)	+= uncached.o
+obj-$(CONFIG_HAVE_SRAM_POOL)	+= sram.o
 
 # Special flags for fault_64.o.  This puts restrictions on the number of
 # caller-save registers that the compiler can target when building this file.
@@ -66,4 +67,4 @@
 	-ffixed-r60 -ffixed-r61 -ffixed-r62 \
 	-fomit-frame-pointer
 
-EXTRA_CFLAGS += -Werror
+ccflags-y := -Werror
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/nommu.c linux-libre-2.6.37-gnu/arch/sh/mm/nommu.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/nommu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/nommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,6 +67,10 @@
 	BUG();
 }
 
+void __flush_tlb_global(void)
+{
+}
+
 void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/pmb.c linux-libre-2.6.37-gnu/arch/sh/mm/pmb.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/pmb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/pmb.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,7 @@
 	unsigned long flags;
 	unsigned long size;
 
-	spinlock_t lock;
+	raw_spinlock_t lock;
 
 	/*
 	 * 0 .. NR_PMB_ENTRIES for specific entry selection, or
@@ -265,7 +265,7 @@
 
 	memset(pmbe, 0, sizeof(struct pmb_entry));
 
-	spin_lock_init(&pmbe->lock);
+	raw_spin_lock_init(&pmbe->lock);
 
 	pmbe->vpn	= vpn;
 	pmbe->ppn	= ppn;
@@ -327,9 +327,9 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&pmbe->lock, flags);
+	raw_spin_lock_irqsave(&pmbe->lock, flags);
 	__set_pmb_entry(pmbe);
-	spin_unlock_irqrestore(&pmbe->lock, flags);
+	raw_spin_unlock_irqrestore(&pmbe->lock, flags);
 }
 #endif /* CONFIG_PM */
 
@@ -368,7 +368,7 @@
 				return PTR_ERR(pmbe);
 			}
 
-			spin_lock_irqsave(&pmbe->lock, flags);
+			raw_spin_lock_irqsave(&pmbe->lock, flags);
 
 			pmbe->size = pmb_sizes[i].size;
 
@@ -383,9 +383,10 @@
 			 * entries for easier tear-down.
 			 */
 			if (likely(pmbp)) {
-				spin_lock(&pmbp->lock);
+				raw_spin_lock_nested(&pmbp->lock,
+						     SINGLE_DEPTH_NESTING);
 				pmbp->link = pmbe;
-				spin_unlock(&pmbp->lock);
+				raw_spin_unlock(&pmbp->lock);
 			}
 
 			pmbp = pmbe;
@@ -398,7 +399,7 @@
 			i--;
 			mapped++;
 
-			spin_unlock_irqrestore(&pmbe->lock, flags);
+			raw_spin_unlock_irqrestore(&pmbe->lock, flags);
 		}
 	} while (size >= SZ_16M);
 
@@ -627,15 +628,14 @@
 			continue;
 		}
 
-		spin_lock_irqsave(&pmbe->lock, irqflags);
+		raw_spin_lock_irqsave(&pmbe->lock, irqflags);
 
 		for (j = 0; j < ARRAY_SIZE(pmb_sizes); j++)
 			if (pmb_sizes[j].flag == size)
 				pmbe->size = pmb_sizes[j].size;
 
 		if (pmbp) {
-			spin_lock(&pmbp->lock);
-
+			raw_spin_lock_nested(&pmbp->lock, SINGLE_DEPTH_NESTING);
 			/*
 			 * Compare the previous entry against the current one to
 			 * see if the entries span a contiguous mapping. If so,
@@ -644,13 +644,12 @@
 			 */
 			if (pmb_can_merge(pmbp, pmbe))
 				pmbp->link = pmbe;
-
-			spin_unlock(&pmbp->lock);
+			raw_spin_unlock(&pmbp->lock);
 		}
 
 		pmbp = pmbe;
 
-		spin_unlock_irqrestore(&pmbe->lock, irqflags);
+		raw_spin_unlock_irqrestore(&pmbe->lock, irqflags);
 	}
 }
 
@@ -757,7 +756,7 @@
 		/*
 		 * Found it, now resize it.
 		 */
-		spin_lock_irqsave(&pmbe->lock, flags);
+		raw_spin_lock_irqsave(&pmbe->lock, flags);
 
 		pmbe->size = SZ_16M;
 		pmbe->flags &= ~PMB_SZ_MASK;
@@ -767,7 +766,7 @@
 
 		__set_pmb_entry(pmbe);
 
-		spin_unlock_irqrestore(&pmbe->lock, flags);
+		raw_spin_unlock_irqrestore(&pmbe->lock, flags);
 	}
 
 	read_unlock(&pmb_rwlock);
@@ -866,11 +865,9 @@
 	struct dentry *dentry;
 
 	dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
-				     sh_debugfs_root, NULL, &pmb_debugfs_fops);
+				     arch_debugfs_dir, NULL, &pmb_debugfs_fops);
 	if (!dentry)
 		return -ENOMEM;
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/sram.c linux-libre-2.6.37-gnu/arch/sh/mm/sram.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/sram.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sh/mm/sram.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,34 @@
+/*
+ * SRAM pool for tiny memories not otherwise managed.
+ *
+ * Copyright (C) 2010  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/sram.h>
+
+/*
+ * This provides a standard SRAM pool for tiny memories that can be
+ * added either by the CPU or the platform code. Typical SRAM sizes
+ * to be inserted in to the pool will generally be less than the page
+ * size, with anything more reasonably sized handled as a NUMA memory
+ * node.
+ */
+struct gen_pool *sram_pool;
+
+static int __init sram_pool_init(void)
+{
+	/*
+	 * This is a global pool, we don't care about node locality.
+	 */
+	sram_pool = gen_pool_create(1, -1);
+	if (unlikely(!sram_pool))
+		return -ENOMEM;
+
+	return 0;
+}
+core_initcall(sram_pool_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/tlb-debugfs.c linux-libre-2.6.37-gnu/arch/sh/mm/tlb-debugfs.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/tlb-debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/tlb-debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -151,15 +151,13 @@
 {
 	struct dentry *itlb, *utlb;
 
-	itlb = debugfs_create_file("itlb", S_IRUSR, sh_debugfs_root,
+	itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
 				   (unsigned int *)TLB_TYPE_ITLB,
 				   &tlb_debugfs_fops);
 	if (unlikely(!itlb))
 		return -ENOMEM;
-	if (IS_ERR(itlb))
-		return PTR_ERR(itlb);
 
-	utlb = debugfs_create_file("utlb", S_IRUSR, sh_debugfs_root,
+	utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
 				   (unsigned int *)TLB_TYPE_UTLB,
 				   &tlb_debugfs_fops);
 	if (unlikely(!utlb)) {
@@ -167,11 +165,6 @@
 		return -ENOMEM;
 	}
 
-	if (IS_ERR(utlb)) {
-		debugfs_remove(itlb);
-		return PTR_ERR(utlb);
-	}
-
 	return 0;
 }
 module_init(tlb_debugfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/tlbflush_32.c linux-libre-2.6.37-gnu/arch/sh/mm/tlbflush_32.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/tlbflush_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/tlbflush_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -119,3 +119,19 @@
 		local_irq_restore(flags);
 	}
 }
+
+void __flush_tlb_global(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/*
+	 * This is the most destructive of the TLB flushing options,
+	 * and will tear down all of the UTLB/ITLB mappings, including
+	 * wired entries.
+	 */
+	__raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
+
+	local_irq_restore(flags);
+}
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/tlbflush_64.c linux-libre-2.6.37-gnu/arch/sh/mm/tlbflush_64.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/tlbflush_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/tlbflush_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -455,6 +455,11 @@
         flush_tlb_all();
 }
 
+void __flush_tlb_global(void)
+{
+	flush_tlb_all();
+}
+
 void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
 {
 }
diff -druN linux-libre-2.6.36-gnu/arch/sh/mm/uncached.c linux-libre-2.6.37-gnu/arch/sh/mm/uncached.c
--- linux-libre-2.6.36-gnu/arch/sh/mm/uncached.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/mm/uncached.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
 
 void __init uncached_init(void)
 {
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || !defined(CONFIG_MMU)
 	uncached_start = P2SEG;
 #else
 	uncached_start = memory_end;
diff -druN linux-libre-2.6.36-gnu/arch/sh/oprofile/backtrace.c linux-libre-2.6.37-gnu/arch/sh/oprofile/backtrace.c
--- linux-libre-2.6.36-gnu/arch/sh/oprofile/backtrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/oprofile/backtrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,7 @@
 	if (depth > backtrace_limit)
 		depth = backtrace_limit;
 
-	stackaddr = (unsigned long *)regs->regs[15];
+	stackaddr = (unsigned long *)kernel_stack_pointer(regs);
 	if (!user_mode(regs)) {
 		if (depth)
 			unwind_stack(NULL, regs, stackaddr,
diff -druN linux-libre-2.6.36-gnu/arch/sh/oprofile/common.c linux-libre-2.6.37-gnu/arch/sh/oprofile/common.c
--- linux-libre-2.6.36-gnu/arch/sh/oprofile/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/oprofile/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * arch/sh/oprofile/init.c
  *
- * Copyright (C) 2003 - 2008  Paul Mundt
+ * Copyright (C) 2003 - 2010  Paul Mundt
  *
  * Based on arch/mips/oprofile/common.c:
  *
@@ -17,114 +17,48 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
 #include <asm/processor.h>
-#include "op_impl.h"
-
-static struct op_sh_model *model;
-
-static struct op_counter_config ctr[20];
 
 extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
 
-static int op_sh_setup(void)
-{
-	/* Pre-compute the values to stuff in the hardware registers.  */
-	model->reg_setup(ctr);
-
-	/* Configure the registers on all cpus.  */
-	on_each_cpu(model->cpu_setup, NULL, 1);
-
-        return 0;
-}
-
-static int op_sh_create_files(struct super_block *sb, struct dentry *root)
-{
-	int i, ret = 0;
-
-	for (i = 0; i < model->num_counters; i++) {
-		struct dentry *dir;
-		char buf[4];
-
-		snprintf(buf, sizeof(buf), "%d", i);
-		dir = oprofilefs_mkdir(sb, root, buf);
-
-		ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
-		ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
-		ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
-		ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
-
-		if (model->create_files)
-			ret |= model->create_files(sb, dir);
-		else
-			ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
-
-		/* Dummy entries */
-		ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
-	}
-
-	return ret;
-}
-
-static int op_sh_start(void)
-{
-	/* Enable performance monitoring for all counters.  */
-	on_each_cpu(model->cpu_start, NULL, 1);
-
-	return 0;
-}
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *sh_pmu_op_name;
 
-static void op_sh_stop(void)
+char *op_name_from_perf_id(void)
 {
-	/* Disable performance monitoring for all counters.  */
-	on_each_cpu(model->cpu_stop, NULL, 1);
+	return sh_pmu_op_name;
 }
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-	struct op_sh_model *lmodel = NULL;
-	int ret;
-
-	/*
-	 * Always assign the backtrace op. If the counter initialization
-	 * fails, we fall back to the timer which will still make use of
-	 * this.
-	 */
 	ops->backtrace = sh_backtrace;
 
-	/*
-	 * XXX
-	 *
-	 * All of the SH7750/SH-4A counters have been converted to perf,
-	 * this infrastructure hook is left for other users until they've
-	 * had a chance to convert over, at which point all of this
-	 * will be deleted.
-	 */
-
-	if (!lmodel)
-		return -ENODEV;
-	if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
+	if (perf_num_counters() == 0)
 		return -ENODEV;
 
-	ret = lmodel->init();
-	if (unlikely(ret != 0))
-		return ret;
-
-	model = lmodel;
-
-	ops->setup		= op_sh_setup;
-	ops->create_files	= op_sh_create_files;
-	ops->start		= op_sh_start;
-	ops->stop		= op_sh_stop;
-	ops->cpu_type		= lmodel->cpu_type;
-
-	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
-	       lmodel->cpu_type);
+	sh_pmu_op_name = kasprintf(GFP_KERNEL, "%s/%s",
+				   UTS_MACHINE, perf_pmu_name());
+	if (unlikely(!sh_pmu_op_name))
+		return -ENOMEM;
 
-	return 0;
+	return oprofile_perf_init(ops);
 }
 
-void oprofile_arch_exit(void)
+void __exit oprofile_arch_exit(void)
 {
-	if (model && model->exit)
-		model->exit();
+	oprofile_perf_exit();
+	kfree(sh_pmu_op_name);
 }
+#else
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+	ops->backtrace = sh_backtrace;
+	return -ENODEV;
+}
+void __exit oprofile_arch_exit(void) {}
+#endif /* CONFIG_HW_PERF_EVENTS */
diff -druN linux-libre-2.6.36-gnu/arch/sh/oprofile/Makefile linux-libre-2.6.37-gnu/arch/sh/oprofile/Makefile
--- linux-libre-2.6.36-gnu/arch/sh/oprofile/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/oprofile/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,9 +1,15 @@
 obj-$(CONFIG_OPROFILE) += oprofile.o
 
+CFLAGS_common.o	+= -DUTS_MACHINE='"$(UTS_MACHINE)"'
+
 DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
 		oprof.o cpu_buffer.o buffer_sync.o \
 		event_buffer.o oprofile_files.o \
 		oprofilefs.o oprofile_stats.o \
 		timer_int.o )
 
+ifeq ($(CONFIG_HW_PERF_EVENTS),y)
+DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
+endif
+
 oprofile-y	:= $(DRIVER_OBJS) common.o backtrace.o
diff -druN linux-libre-2.6.36-gnu/arch/sh/oprofile/op_impl.h linux-libre-2.6.37-gnu/arch/sh/oprofile/op_impl.h
--- linux-libre-2.6.36-gnu/arch/sh/oprofile/op_impl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/oprofile/op_impl.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,33 +0,0 @@
-#ifndef __OP_IMPL_H
-#define __OP_IMPL_H
-
-/* Per-counter configuration as set via oprofilefs.  */
-struct op_counter_config {
-	unsigned long enabled;
-	unsigned long event;
-
-	unsigned long count;
-
-	/* Dummy values for userspace tool compliance */
-	unsigned long kernel;
-	unsigned long user;
-	unsigned long unit_mask;
-};
-
-/* Per-architecture configury and hooks.  */
-struct op_sh_model {
-	void (*reg_setup)(struct op_counter_config *);
-	int (*create_files)(struct super_block *sb, struct dentry *dir);
-	void (*cpu_setup)(void *dummy);
-	int (*init)(void);
-	void (*exit)(void);
-	void (*cpu_start)(void *args);
-	void (*cpu_stop)(void *args);
-	char *cpu_type;
-	unsigned char num_counters;
-};
-
-/* arch/sh/oprofile/common.c */
-extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
-
-#endif /* __OP_IMPL_H */
diff -druN linux-libre-2.6.36-gnu/arch/sh/tools/mach-types linux-libre-2.6.37-gnu/arch/sh/tools/mach-types
--- linux-libre-2.6.36-gnu/arch/sh/tools/mach-types	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sh/tools/mach-types	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,6 @@
 7724SE			SH_7724_SOLUTION_ENGINE
 7751SE			SH_7751_SOLUTION_ENGINE
 7780SE			SH_7780_SOLUTION_ENGINE
-7751SYSTEMH		SH_7751_SYSTEMH
 HP6XX			SH_HP6XX
 DREAMCAST		SH_DREAMCAST
 SNAPGEAR		SH_SECUREEDGE5410
@@ -52,6 +51,8 @@
 RSK7201			SH_RSK7201
 RSK7203			SH_RSK7203
 AP325RXA		SH_AP325RXA
+SH2007			SH_SH2007
+SH7757LCR		SH_SH7757LCR
 SH7763RDP		SH_SH7763RDP
 SH7785LCR		SH_SH7785LCR
 SH7785LCR_PT		SH_SH7785LCR_PT
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/floppy_32.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/floppy_32.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/floppy_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/floppy_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -304,7 +304,8 @@
 static int sun_floppy_init(void)
 {
 	char state[128];
-	int tnode, fd_node, num_regs;
+	phandle tnode, fd_node;
+	int num_regs;
 	struct resource r;
 
 	use_virtual_dma = 1;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -70,8 +70,8 @@
 	kunmap_high(page);
 }
 
-extern void *kmap_atomic(struct page *page, enum km_type type);
-extern void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
+extern void *__kmap_atomic(struct page *page);
+extern void __kunmap_atomic(void *kvaddr);
 extern struct page *kmap_atomic_to_page(void *vaddr);
 
 #define flush_cache_kmaps()	flush_cache_all()
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/io_32.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/io_32.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/io_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/io_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -208,6 +208,21 @@
 #define memset_io(d,c,sz)	_memset_io(d,c,sz)
 
 static inline void
+_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
+		    __kernel_size_t n)
+{
+	char *d = dst;
+
+	while (n--) {
+		char tmp = sbus_readb(src);
+		*d++ = tmp;
+		src++;
+	}
+}
+
+#define sbus_memcpy_fromio(d, s, sz)	_sbus_memcpy_fromio(d, s, sz)
+
+static inline void
 _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
 {
 	char *d = dst;
@@ -222,6 +237,22 @@
 #define memcpy_fromio(d,s,sz)	_memcpy_fromio(d,s,sz)
 
 static inline void
+_sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
+		  __kernel_size_t n)
+{
+	const char *s = src;
+	volatile void __iomem *d = dst;
+
+	while (n--) {
+		char tmp = *s++;
+		sbus_writeb(tmp, d);
+		d++;
+	}
+}
+
+#define sbus_memcpy_toio(d, s, sz)	_sbus_memcpy_toio(d, s, sz)
+
+static inline void
 _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
 {
 	const char *s = src;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/io_64.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/io_64.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/io_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/io_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -419,6 +419,21 @@
 #define memset_io(d,c,sz)	_memset_io(d,c,sz)
 
 static inline void
+_sbus_memcpy_fromio(void *dst, const volatile void __iomem *src,
+		    __kernel_size_t n)
+{
+	char *d = dst;
+
+	while (n--) {
+		char tmp = sbus_readb(src);
+		*d++ = tmp;
+		src++;
+	}
+}
+
+#define sbus_memcpy_fromio(d, s, sz)	_sbus_memcpy_fromio(d, s, sz)
+
+static inline void
 _memcpy_fromio(void *dst, const volatile void __iomem *src, __kernel_size_t n)
 {
 	char *d = dst;
@@ -433,6 +448,22 @@
 #define memcpy_fromio(d,s,sz)	_memcpy_fromio(d,s,sz)
 
 static inline void
+_sbus_memcpy_toio(volatile void __iomem *dst, const void *src,
+		  __kernel_size_t n)
+{
+	const char *s = src;
+	volatile void __iomem *d = dst;
+
+	while (n--) {
+		char tmp = *s++;
+		sbus_writeb(tmp, d);
+		d++;
+	}
+}
+
+#define sbus_memcpy_toio(d, s, sz)	_sbus_memcpy_toio(d, s, sz)
+
+static inline void
 _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
 {
 	const char *s = src;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/irqflags_32.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/irqflags_32.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/irqflags_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/irqflags_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,33 +5,40 @@
  *
  * This file gets included from lowlevel asm headers too, to provide
  * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() functions from the lowlevel headers.
+ * arch_local_irq_*() functions from the lowlevel headers.
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
 
 #ifndef __ASSEMBLY__
 
-extern void raw_local_irq_restore(unsigned long);
-extern unsigned long __raw_local_irq_save(void);
-extern void raw_local_irq_enable(void);
+#include <linux/types.h>
 
-static inline unsigned long getipl(void)
+extern void arch_local_irq_restore(unsigned long);
+extern unsigned long arch_local_irq_save(void);
+extern void arch_local_irq_enable(void);
+
+static inline unsigned long arch_local_save_flags(void)
 {
-        unsigned long retval;
+	unsigned long flags;
 
-        __asm__ __volatile__("rd        %%psr, %0" : "=r" (retval));
-        return retval;
+	asm volatile("rd        %%psr, %0" : "=r" (flags));
+	return flags;
 }
 
-#define raw_local_save_flags(flags) ((flags) = getipl())
-#define raw_local_irq_save(flags)   ((flags) = __raw_local_irq_save())
-#define raw_local_irq_disable()     ((void) __raw_local_irq_save())
-#define raw_irqs_disabled()         ((getipl() & PSR_PIL) != 0)
+static inline void arch_local_irq_disable(void)
+{
+	arch_local_irq_save();
+}
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
-        return ((flags & PSR_PIL) != 0);
+	return (flags & PSR_PIL) != 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
 #endif /* (__ASSEMBLY__) */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/irqflags_64.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/irqflags_64.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/irqflags_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/irqflags_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  * This file gets included from lowlevel asm headers too, to provide
  * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() functions from the lowlevel headers.
+ * arch_local_irq_*() functions from the lowlevel headers.
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
@@ -14,7 +14,7 @@
 
 #ifndef __ASSEMBLY__
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
 	unsigned long flags;
 
@@ -26,10 +26,7 @@
 	return flags;
 }
 
-#define raw_local_save_flags(flags) \
-		do { (flags) = __raw_local_save_flags(); } while (0)
-
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
 	__asm__ __volatile__(
 		"wrpr	%0, %%pil"
@@ -39,7 +36,7 @@
 	);
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
 	__asm__ __volatile__(
 		"wrpr	%0, %%pil"
@@ -49,7 +46,7 @@
 	);
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
 	__asm__ __volatile__(
 		"wrpr	0, %%pil"
@@ -59,22 +56,17 @@
 	);
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
 	return (flags > 0);
 }
 
-static inline int raw_irqs_disabled(void)
+static inline int arch_irqs_disabled(void)
 {
-	unsigned long flags = __raw_local_save_flags();
-
-	return raw_irqs_disabled_flags(flags);
+	return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
-/*
- * For spinlocks, etc:
- */
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
 	unsigned long flags, tmp;
 
@@ -100,9 +92,6 @@
 	return flags;
 }
 
-#define raw_local_irq_save(flags) \
-		do { (flags) = __raw_local_irq_save(); } while (0)
-
 #endif /* (__ASSEMBLY__) */
 
 #endif /* !(_ASM_IRQFLAGS_H) */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/jump_label.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/jump_label.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/jump_label.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/jump_label.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_JUMP_LABEL_H
+#define _ASM_SPARC_JUMP_LABEL_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+#define JUMP_LABEL(key, label)					\
+	do {							\
+		asm goto("1:\n\t"				\
+			 "nop\n\t"				\
+			 "nop\n\t"				\
+			 ".pushsection __jump_table,  \"a\"\n\t"\
+			 ".align 4\n\t"				\
+			 ".word 1b, %l[" #label "], %c0\n\t"	\
+			 ".popsection \n\t"			\
+			 : :  "i" (key) :  : label);\
+	} while (0)
+
+#endif /* __KERNEL__ */
+
+typedef u32 jump_label_t;
+
+struct jump_entry {
+	jump_label_t code;
+	jump_label_t target;
+	jump_label_t key;
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/Kbuild linux-libre-2.6.37-gnu/arch/sparc/include/asm/Kbuild
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,6 @@
 header-y += envctrl.h
 header-y += fbio.h
 header-y += jsflash.h
-header-y += openprom.h
 header-y += openpromio.h
 header-y += perfctr.h
 header-y += psrcompat.h
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/memblock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,4 @@
 
 #define MEMBLOCK_DBG(fmt...) prom_printf(fmt)
 
-#define MEMBLOCK_REAL_LIMIT	0
-
 #endif /* !(_SPARC64_MEMBLOCK_H) */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/openprom.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/openprom.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/openprom.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/openprom.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,8 @@
 #define LINUX_OPPROM_MAGIC      0x10010407
 
 #ifndef __ASSEMBLY__
+#include <linux/of.h>
+
 /* V0 prom device operations. */
 struct linux_dev_v0_funcs {
 	int (*v0_devopen)(char *device_str);
@@ -26,7 +28,7 @@
 
 /* V2 and later prom device operations. */
 struct linux_dev_v2_funcs {
-	int (*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */
+	phandle (*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */
 	char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
 	void (*v2_dumb_mem_free)(char *va, unsigned sz);
 
@@ -37,7 +39,7 @@
 	int (*v2_dev_open)(char *devpath);
 	void (*v2_dev_close)(int d);
 	int (*v2_dev_read)(int d, char *buf, int nbytes);
-	int (*v2_dev_write)(int d, char *buf, int nbytes);
+	int (*v2_dev_write)(int d, const char *buf, int nbytes);
 	int (*v2_dev_seek)(int d, int hi, int lo);
 
 	/* Never issued (multistage load support) */
@@ -168,12 +170,12 @@
 
 /* Routines for traversing the prom device tree. */
 struct linux_nodeops {
-	int (*no_nextnode)(int node);
-	int (*no_child)(int node);
-	int (*no_proplen)(int node, const char *name);
-	int (*no_getprop)(int node, const char *name, char *val);
-	int (*no_setprop)(int node, const char *name, char *val, int len);
-	char * (*no_nextprop)(int node, char *name);
+	phandle (*no_nextnode)(phandle node);
+	phandle (*no_child)(phandle node);
+	int (*no_proplen)(phandle node, const char *name);
+	int (*no_getprop)(phandle node, const char *name, char *val);
+	int (*no_setprop)(phandle node, const char *name, char *val, int len);
+	char * (*no_nextprop)(phandle node, char *name);
 };
 
 /* More fun PROM structures for device probing. */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/oplib_32.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/oplib_32.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/oplib_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/oplib_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,7 @@
 /* Root node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_root_node;
+extern phandle prom_root_node;
 
 /* Pointer to prom structure containing the device tree traversal
  * and usage utility functions.  Only prom-lib should use these,
@@ -60,25 +60,6 @@
 extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes);
 extern void prom_unmapio(char *virt_addr, unsigned int num_bytes);
 
-/* Device operations. */
-
-/* Open the device described by the passed string.  Note, that the format
- * of the string is different on V0 vs. V2->higher proms.  The caller must
- * know what he/she is doing!  Returns the device descriptor, an int.
- */
-extern int prom_devopen(char *device_string);
-
-/* Close a previously opened device described by the passed integer
- * descriptor.
- */
-extern int prom_devclose(int device_handle);
-
-/* Do a seek operation on the device described by the passed integer
- * descriptor.
- */
-extern void prom_seek(int device_handle, unsigned int seek_hival,
-		      unsigned int seek_lowval);
-
 /* Miscellaneous routines, don't really fit in any category per se. */
 
 /* Reboot the machine with the command line passed. */
@@ -121,19 +102,8 @@
 /* Get the prom firmware revision. */
 extern int prom_getprev(void);
 
-/* Character operations to/from the console.... */
-
-/* Non-blocking get character from console. */
-extern int prom_nbgetchar(void);
-
-/* Non-blocking put character to console. */
-extern int prom_nbputchar(char character);
-
-/* Blocking get character from console. */
-extern char prom_getchar(void);
-
-/* Blocking put character to console. */
-extern void prom_putchar(char character);
+/* Write a buffer of characters to the console. */
+extern void prom_console_write_buf(const char *buf, int len);
 
 /* Prom's internal routines, don't use in kernel/boot code. */
 extern void prom_printf(const char *fmt, ...);
@@ -178,68 +148,67 @@
 /* PROM device tree traversal functions... */
 
 /* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
 
 /* Get the next sibling node of the given node, or zero if no further
  * siblings exist.
  */
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
 
 /* Get the length, at the passed node, of the given property type.
  * Returns -1 on error (ie. no such property at this node).
  */
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
 
 /* Fetch the requested property using the given buffer.  Returns
  * the number of bytes the prom put into your buffer or -1 on error.
  */
-extern int __must_check prom_getproperty(int thisnode, const char *property,
+extern int __must_check prom_getproperty(phandle thisnode, const char *property,
 					 char *prop_buffer, int propbuf_size);
 
 /* Acquire an integer property. */
-extern int prom_getint(int node, char *property);
+extern int prom_getint(phandle node, char *property);
 
 /* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, char *property, int defval);
+extern int prom_getintdefault(phandle node, char *property, int defval);
 
 /* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, char *prop);
+extern int prom_getbool(phandle node, char *prop);
 
 /* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, char *prop, char *buf, int bufsize);
 
 /* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, char *name);
+extern int prom_nodematch(phandle thisnode, char *name);
 
 /* Search all siblings starting at the passed node for "name" matching
  * the given string.  Returns the node on success, zero on failure.
  */
-extern int prom_searchsiblings(int node_start, char *name);
+extern phandle prom_searchsiblings(phandle node_start, char *name);
 
 /* Return the first property type, as a string, for the given node.
  * Returns a null string on error.
  */
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
 
 /* Returns the next property after the passed property for the given
  * node.  Returns null string on failure.
  */
-extern char *prom_nextprop(int node, char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, char *prev_property, char *buffer);
 
 /* Returns phandle of the path specified */
-extern int prom_finddevice(char *name);
+extern phandle prom_finddevice(char *name);
 
 /* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, char *property);
+extern int prom_node_has_property(phandle node, char *property);
 
 /* Set the indicated property at the given node with the passed value.
  * Returns the number of bytes of your value that the prom took.
  */
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
 			int value_size);
 
-extern int prom_pathtoinode(char *path);
-extern int prom_inst2pkg(int);
+extern phandle prom_inst2pkg(int);
 
 /* Dorking with Bus ranges... */
 
@@ -247,13 +216,13 @@
 extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
 
 /* Apply ranges of any prom node (and optionally parent node as well) to registers. */
-extern void prom_apply_generic_ranges(int node, int parent,
+extern void prom_apply_generic_ranges(phandle node, phandle parent,
 				      struct linux_prom_registers *sbusregs, int nregs);
 
 /* CPU probing helpers.  */
-int cpu_find_by_instance(int instance, int *prom_node, int *mid);
-int cpu_find_by_mid(int mid, int *prom_node);
-int cpu_get_hwmid(int prom_node);
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid);
+int cpu_find_by_mid(int mid, phandle *prom_node);
+int cpu_get_hwmid(phandle prom_node);
 
 extern spinlock_t prom_lock;
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/oplib_64.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/oplib_64.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/oplib_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/oplib_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 /* Root node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_root_node;
+extern phandle prom_root_node;
 
 /* PROM stdin and stdout */
 extern int prom_stdin, prom_stdout;
@@ -24,7 +24,7 @@
 /* /chosen node of the prom device tree, this stays constant after
  * initialization is complete.
  */
-extern int prom_chosen_node;
+extern phandle prom_chosen_node;
 
 /* Helper values and strings in arch/sparc64/kernel/head.S */
 extern const char prom_peer_name[];
@@ -67,27 +67,6 @@
 /* Boot argument acquisition, returns the boot command line string. */
 extern char *prom_getbootargs(void);
 
-/* Device utilities. */
-
-/* Device operations. */
-
-/* Open the device described by the passed string.  Note, that the format
- * of the string is different on V0 vs. V2->higher proms.  The caller must
- * know what he/she is doing!  Returns the device descriptor, an int.
- */
-extern int prom_devopen(const char *device_string);
-
-/* Close a previously opened device described by the passed integer
- * descriptor.
- */
-extern int prom_devclose(int device_handle);
-
-/* Do a seek operation on the device described by the passed integer
- * descriptor.
- */
-extern void prom_seek(int device_handle, unsigned int seek_hival,
-		      unsigned int seek_lowval);
-
 /* Miscellaneous routines, don't really fit in any category per se. */
 
 /* Reboot the machine with the command line passed. */
@@ -109,33 +88,14 @@
 /* Halt and power-off the machine. */
 extern void prom_halt_power_off(void) __attribute__ ((noreturn));
 
-/* Set the PROM 'sync' callback function to the passed function pointer.
- * When the user gives the 'sync' command at the prom prompt while the
- * kernel is still active, the prom will call this routine.
- *
- */
-typedef int (*callback_func_t)(long *cmd);
-extern void prom_setcallback(callback_func_t func_ptr);
-
 /* Acquire the IDPROM of the root node in the prom device tree.  This
  * gets passed a buffer where you would like it stuffed.  The return value
  * is the format type of this idprom or 0xff on error.
  */
 extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size);
 
-/* Character operations to/from the console.... */
-
-/* Non-blocking get character from console. */
-extern int prom_nbgetchar(void);
-
-/* Non-blocking put character to console. */
-extern int prom_nbputchar(char character);
-
-/* Blocking get character from console. */
-extern char prom_getchar(void);
-
-/* Blocking put character to console. */
-extern void prom_putchar(char character);
+/* Write a buffer of characters to the console. */
+extern void prom_console_write_buf(const char *buf, int len);
 
 /* Prom's internal routines, don't use in kernel/boot code. */
 extern void prom_printf(const char *fmt, ...);
@@ -218,69 +178,68 @@
 /* PROM device tree traversal functions... */
 
 /* Get the child node of the given node, or zero if no child exists. */
-extern int prom_getchild(int parent_node);
+extern phandle prom_getchild(phandle parent_node);
 
 /* Get the next sibling node of the given node, or zero if no further
  * siblings exist.
  */
-extern int prom_getsibling(int node);
+extern phandle prom_getsibling(phandle node);
 
 /* Get the length, at the passed node, of the given property type.
  * Returns -1 on error (ie. no such property at this node).
  */
-extern int prom_getproplen(int thisnode, const char *property);
+extern int prom_getproplen(phandle thisnode, const char *property);
 
 /* Fetch the requested property using the given buffer.  Returns
  * the number of bytes the prom put into your buffer or -1 on error.
  */
-extern int prom_getproperty(int thisnode, const char *property,
+extern int prom_getproperty(phandle thisnode, const char *property,
 			    char *prop_buffer, int propbuf_size);
 
 /* Acquire an integer property. */
-extern int prom_getint(int node, const char *property);
+extern int prom_getint(phandle node, const char *property);
 
 /* Acquire an integer property, with a default value. */
-extern int prom_getintdefault(int node, const char *property, int defval);
+extern int prom_getintdefault(phandle node, const char *property, int defval);
 
 /* Acquire a boolean property, 0=FALSE 1=TRUE. */
-extern int prom_getbool(int node, const char *prop);
+extern int prom_getbool(phandle node, const char *prop);
 
 /* Acquire a string property, null string on error. */
-extern void prom_getstring(int node, const char *prop, char *buf, int bufsize);
+extern void prom_getstring(phandle node, const char *prop, char *buf,
+			   int bufsize);
 
 /* Does the passed node have the given "name"? YES=1 NO=0 */
-extern int prom_nodematch(int thisnode, const char *name);
+extern int prom_nodematch(phandle thisnode, const char *name);
 
 /* Search all siblings starting at the passed node for "name" matching
  * the given string.  Returns the node on success, zero on failure.
  */
-extern int prom_searchsiblings(int node_start, const char *name);
+extern phandle prom_searchsiblings(phandle node_start, const char *name);
 
 /* Return the first property type, as a string, for the given node.
  * Returns a null string on error. Buffer should be at least 32B long.
  */
-extern char *prom_firstprop(int node, char *buffer);
+extern char *prom_firstprop(phandle node, char *buffer);
 
 /* Returns the next property after the passed property for the given
  * node.  Returns null string on failure. Buffer should be at least 32B long.
  */
-extern char *prom_nextprop(int node, const char *prev_property, char *buffer);
+extern char *prom_nextprop(phandle node, const char *prev_property, char *buf);
 
 /* Returns 1 if the specified node has given property. */
-extern int prom_node_has_property(int node, const char *property);
+extern int prom_node_has_property(phandle node, const char *property);
 
 /* Returns phandle of the path specified */
-extern int prom_finddevice(const char *name);
+extern phandle prom_finddevice(const char *name);
 
 /* Set the indicated property at the given node with the passed value.
  * Returns the number of bytes of your value that the prom took.
  */
-extern int prom_setprop(int node, const char *prop_name, char *prop_value,
+extern int prom_setprop(phandle node, const char *prop_name, char *prop_value,
 			int value_size);
 
-extern int prom_pathtoinode(const char *path);
-extern int prom_inst2pkg(int);
-extern int prom_service_exists(const char *service_name);
+extern phandle prom_inst2pkg(int);
 extern void prom_sun4v_guest_soft_state(void);
 
 extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/pci_64.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/pci_64.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/pci_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/pci_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,7 +38,7 @@
  * types on sparc64.  However, it requires that the device
  * can drive enough of the 64 bits.
  */
-#define PCI64_REQUIRED_MASK	(~(dma64_addr_t)0)
+#define PCI64_REQUIRED_MASK	(~(u64)0)
 #define PCI64_ADDR_BASE		0xfffc000000000000UL
 
 #ifdef CONFIG_PCI
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,6 @@
 #ifndef __ASM_SPARC_PERF_EVENT_H
 #define __ASM_SPARC_PERF_EVENT_H
 
-extern void set_perf_event_pending(void);
-
-#define	PERF_EVENT_INDEX_OFFSET	0
-
 #ifdef CONFIG_PERF_EVENTS
 #include <asm/ptrace.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/pgtable_32.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/pgtable_32.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/pgtable_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/pgtable_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -304,10 +304,7 @@
  * and sun4c is guaranteed to have no highmem anyway.
  */
 #define pte_offset_map(d, a)		pte_offset_kernel(d,a)
-#define pte_offset_map_nested(d, a)	pte_offset_kernel(d,a)
-
 #define pte_unmap(pte)		do{}while(0)
-#define pte_unmap_nested(pte)	do{}while(0)
 
 /* Certain architectures need to do special things when pte's
  * within a page table are directly modified.  Thus, the following
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/pgtable_64.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/pgtable_64.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/pgtable_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/pgtable_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -652,9 +652,7 @@
 	 ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
 #define pte_offset_kernel		pte_index
 #define pte_offset_map			pte_index
-#define pte_offset_map_nested		pte_index
 #define pte_unmap(pte)			do { } while (0)
-#define pte_unmap_nested(pte)		do { } while (0)
 
 /* Actual page table PTE updates.  */
 extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
diff -druN linux-libre-2.6.36-gnu/arch/sparc/include/asm/prom.h linux-libre-2.6.37-gnu/arch/sparc/include/asm/prom.h
--- linux-libre-2.6.36-gnu/arch/sparc/include/asm/prom.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/include/asm/prom.h	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <linux/types.h>
+#include <linux/of_pdt.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <asm/atomic.h>
@@ -67,8 +68,8 @@
 extern char *of_console_path;
 extern char *of_console_options;
 
-extern void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-extern char *build_full_name(struct device_node *dp);
+extern void irq_trans_init(struct device_node *dp);
+extern char *build_path_component(struct device_node *dp);
 
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/Kconfig linux-libre-2.6.37-gnu/arch/sparc/Kconfig
--- linux-libre-2.6.36-gnu/arch/sparc/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,9 +1,3 @@
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-mainmenu "Linux/SPARC Kernel Configuration"
-
 config 64BIT
 	bool "64-bit kernel" if ARCH = "sparc"
 	default ARCH = "sparc64"
@@ -19,6 +13,7 @@
 	bool
 	default y
 	select OF
+	select OF_PROMTREE
 	select HAVE_IDE
 	select HAVE_OPROFILE
 	select HAVE_ARCH_KGDB if !SMP || SPARC64
@@ -26,10 +21,10 @@
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select RTC_CLASS
 	select RTC_DRV_M48T59
-	select HAVE_PERF_EVENTS
-	select PERF_USE_VMALLOC
+	select HAVE_IRQ_WORK
 	select HAVE_DMA_ATTRS
 	select HAVE_DMA_API_DEBUG
+	select HAVE_ARCH_JUMP_LABEL
 
 config SPARC32
 	def_bool !64BIT
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/apc.c linux-libre-2.6.37-gnu/arch/sparc/kernel/apc.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/apc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/apc.c	2011-01-04 19:50:19.000000000 -0500
@@ -132,6 +132,7 @@
 	.unlocked_ioctl =	apc_ioctl,
 	.open =			apc_open,
 	.release =		apc_release,
+	.llseek =		noop_llseek,
 };
 
 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/auxio_32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/auxio_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/auxio_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/auxio_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,7 @@
 
 void __init auxio_probe(void)
 {
-	int node, auxio_nd;
+	phandle node, auxio_nd;
 	struct linux_prom_registers auxregs[1];
 	struct resource r;
 
@@ -113,7 +113,7 @@
 void __init auxio_power_probe(void)
 {
 	struct linux_prom_registers regs;
-	int node;
+	phandle node;
 	struct resource r;
 
 	/* Attempt to find the sun4m power control node. */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/btext.c linux-libre-2.6.37-gnu/arch/sparc/kernel/btext.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/btext.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/btext.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,7 @@
 
 static unsigned char vga_font[cmapsz];
 
-static int __init btext_initialize(unsigned int node)
+static int __init btext_initialize(phandle node)
 {
 	unsigned int width, height, depth, pitch;
 	unsigned long address = 0;
@@ -309,7 +309,7 @@
 
 int __init btext_find_display(void)
 {
-	unsigned int node;
+	phandle node;
 	char type[32];
 	int ret;
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/devices.c linux-libre-2.6.37-gnu/arch/sparc/kernel/devices.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/devices.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/devices.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,9 +31,9 @@
 	return "mid";
 }
 
-static int check_cpu_node(int nd, int *cur_inst,
-			  int (*compare)(int, int, void *), void *compare_arg,
-			  int *prom_node, int *mid)
+static int check_cpu_node(phandle nd, int *cur_inst,
+		int (*compare)(phandle, int, void *), void *compare_arg,
+		phandle *prom_node, int *mid)
 {
 	if (!compare(nd, *cur_inst, compare_arg)) {
 		if (prom_node)
@@ -51,8 +51,8 @@
 	return -ENODEV;
 }
 
-static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
-			 int *prom_node, int *mid)
+static int __cpu_find_by(int (*compare)(phandle, int, void *),
+		void *compare_arg, phandle *prom_node, int *mid)
 {
 	struct device_node *dp;
 	int cur_inst;
@@ -71,7 +71,7 @@
 	return -ENODEV;
 }
 
-static int cpu_instance_compare(int nd, int instance, void *_arg)
+static int cpu_instance_compare(phandle nd, int instance, void *_arg)
 {
 	int desired_instance = (int) _arg;
 
@@ -80,13 +80,13 @@
 	return -ENODEV;
 }
 
-int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+int cpu_find_by_instance(int instance, phandle *prom_node, int *mid)
 {
 	return __cpu_find_by(cpu_instance_compare, (void *)instance,
 			     prom_node, mid);
 }
 
-static int cpu_mid_compare(int nd, int instance, void *_arg)
+static int cpu_mid_compare(phandle nd, int instance, void *_arg)
 {
 	int desired_mid = (int) _arg;
 	int this_mid;
@@ -98,7 +98,7 @@
 	return -ENODEV;
 }
 
-int cpu_find_by_mid(int mid, int *prom_node)
+int cpu_find_by_mid(int mid, phandle *prom_node)
 {
 	return __cpu_find_by(cpu_mid_compare, (void *)mid,
 			     prom_node, NULL);
@@ -108,7 +108,7 @@
  * address (0-3).  This gives us the true hardware mid, which might have
  * some other bits set.  On 4d hardware and software mids are the same.
  */
-int cpu_get_hwmid(int prom_node)
+int cpu_get_hwmid(phandle prom_node)
 {
 	return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
 }
@@ -119,7 +119,8 @@
 
 #ifndef CONFIG_SMP
 	{
-		int err, cpu_node;
+		phandle cpu_node;
+		int err;
 		err = cpu_find_by_instance(0, &cpu_node, NULL);
 		if (err) {
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/irq_32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/irq_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/irq_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/irq_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,7 @@
 #define SMP_NOP2
 #define SMP_NOP3
 #endif /* SMP */
-unsigned long __raw_local_irq_save(void)
+unsigned long arch_local_irq_save(void)
 {
 	unsigned long retval;
 	unsigned long tmp;
@@ -74,8 +74,9 @@
 
 	return retval;
 }
+EXPORT_SYMBOL(arch_local_irq_save);
 
-void raw_local_irq_enable(void)
+void arch_local_irq_enable(void)
 {
 	unsigned long tmp;
 
@@ -89,8 +90,9 @@
 		: "i" (PSR_PIL)
 		: "memory");
 }
+EXPORT_SYMBOL(arch_local_irq_enable);
 
-void raw_local_irq_restore(unsigned long old_psr)
+void arch_local_irq_restore(unsigned long old_psr)
 {
 	unsigned long tmp;
 
@@ -105,10 +107,7 @@
 		: "i" (PSR_PIL), "r" (old_psr)
 		: "memory");
 }
-
-EXPORT_SYMBOL(__raw_local_irq_save);
-EXPORT_SYMBOL(raw_local_irq_enable);
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
 /*
  * Dave Redman (djhr@tadpole.co.uk)
@@ -366,7 +365,7 @@
 	unsigned long flags;
 	unsigned int cpu_irq;
 	int ret;
-#ifdef CONFIG_SMP
+#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON
 	struct tt_entry *trap_table;
 	extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
 #endif
@@ -426,7 +425,7 @@
 	table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
 
 	INSTANTIATE(sparc_ttable)
-#ifdef CONFIG_SMP
+#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON
 	trap_table = &trapbase_cpu1; INSTANTIATE(trap_table)
 	trap_table = &trapbase_cpu2; INSTANTIATE(trap_table)
 	trap_table = &trapbase_cpu3; INSTANTIATE(trap_table)
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/jump_label.c linux-libre-2.6.37-gnu/arch/sparc/kernel/jump_label.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/jump_label.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/jump_label.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,47 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	u32 val;
+	u32 *insn = (u32 *) (unsigned long) entry->code;
+
+	if (type == JUMP_LABEL_ENABLE) {
+		s32 off = (s32)entry->target - (s32)entry->code;
+
+#ifdef CONFIG_SPARC64
+		/* ba,pt %xcc, . + (off << 2) */
+		val = 0x10680000 | ((u32) off >> 2);
+#else
+		/* ba . + (off << 2) */
+		val = 0x10800000 | ((u32) off >> 2);
+#endif
+	} else {
+		val = 0x01000000;
+	}
+
+	get_online_cpus();
+	mutex_lock(&text_mutex);
+	*insn = val;
+	flushi(insn);
+	mutex_unlock(&text_mutex);
+	put_online_cpus();
+}
+
+void arch_jump_label_text_poke_early(jump_label_t addr)
+{
+	u32 *insn_p = (u32 *) (unsigned long) addr;
+
+	*insn_p = 0x01000000;
+	flushi(insn_p);
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/leon_kernel.c linux-libre-2.6.37-gnu/arch/sparc/kernel/leon_kernel.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/leon_kernel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/leon_kernel.c	2011-01-04 19:50:19.000000000 -0500
@@ -114,7 +114,7 @@
 	if (leon3_gptimer_regs && leon3_irqctrl_regs) {
 		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0);
 		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld,
-				      (((1000000 / 100) - 1)));
+				      (((1000000 / HZ) - 1)));
 		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
 
 #ifdef CONFIG_SMP
@@ -128,7 +128,7 @@
 		}
 
 		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
-		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
+		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1)));
 		LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
 # endif
 
@@ -282,5 +282,5 @@
 
 void __init leon_init(void)
 {
-	prom_build_more = &leon_node_init;
+	of_pdt_build_more = &leon_node_init;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/leon_smp.c linux-libre-2.6.37-gnu/arch/sparc/kernel/leon_smp.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/leon_smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/leon_smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,6 @@
 #include <linux/sched.h>
 #include <linux/threads.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
@@ -56,8 +55,8 @@
 static inline unsigned long do_swap(volatile unsigned long *ptr,
 				    unsigned long val)
 {
-	__asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val)
-			     : "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
+	__asm__ __volatile__("swapa [%2] %3, %0\n\t" : "=&r"(val)
+			     : "0"(val), "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
 			     : "memory");
 	return val;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/Makefile linux-libre-2.6.37-gnu/arch/sparc/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -119,3 +119,5 @@
 
 pc--$(CONFIG_PERF_EVENTS) := perf_event.o
 obj-$(CONFIG_SPARC64)	+= $(pc--y)
+
+obj-$(CONFIG_SPARC64)	+= jump_label.o
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/mdesc.c linux-libre-2.6.37-gnu/arch/sparc/kernel/mdesc.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/mdesc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/mdesc.c	2011-01-04 19:50:19.000000000 -0500
@@ -890,6 +890,7 @@
 static const struct file_operations mdesc_fops = {
 	.read	= mdesc_read,
 	.owner	= THIS_MODULE,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice mdesc_misc = {
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/module.c linux-libre-2.6.37-gnu/arch/sparc/kernel/module.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/module.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/module.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,9 @@
 #include <asm/spitfire.h>
 
 #ifdef CONFIG_SPARC64
+
+#include <linux/jump_label.h>
+
 static void *module_map(unsigned long size)
 {
 	struct vm_struct *area;
@@ -227,6 +230,9 @@
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
 {
+	/* make jump label nops */
+	jump_label_apply_nops(me);
+
 	/* Cheetah's I-cache is fully coherent.  */
 	if (tlb_type == spitfire) {
 		unsigned long va;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/pcic.c linux-libre-2.6.37-gnu/arch/sparc/kernel/pcic.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/pcic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/pcic.c	2011-01-04 19:50:19.000000000 -0500
@@ -284,7 +284,7 @@
 	struct linux_prom_registers regs[PROMREG_MAX];
 	struct linux_pbm_info* pbm;
 	char namebuf[64];
-	int node;
+	phandle node;
 	int err;
 
 	if (pcic0_up) {
@@ -440,7 +440,7 @@
 {
 	struct linux_prom_pci_registers regs[PROMREG_MAX];
 	int err;
-	int node = prom_getchild(pbm->prom_node);
+	phandle node = prom_getchild(pbm->prom_node);
 
 	while(node) {
 		err = prom_getproperty(node, "reg", 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/pci_msi.c linux-libre-2.6.37-gnu/arch/sparc/kernel/pci_msi.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/pci_msi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/pci_msi.c	2011-01-04 19:50:19.000000000 -0500
@@ -114,10 +114,10 @@
 
 static struct irq_chip msi_irq = {
 	.name		= "PCI-MSI",
-	.mask		= mask_msi_irq,
-	.unmask		= unmask_msi_irq,
-	.enable		= unmask_msi_irq,
-	.disable	= mask_msi_irq,
+	.irq_mask	= mask_msi_irq,
+	.irq_unmask	= unmask_msi_irq,
+	.irq_enable	= unmask_msi_irq,
+	.irq_disable	= mask_msi_irq,
 	/* XXX affinity XXX */
 };
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/pcr.c linux-libre-2.6.37-gnu/arch/sparc/kernel/pcr.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/pcr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/pcr.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 #include <linux/ftrace.h>
 
 #include <asm/pil.h>
@@ -43,14 +43,14 @@
 
 	old_regs = set_irq_regs(regs);
 	irq_enter();
-#ifdef CONFIG_PERF_EVENTS
-	perf_event_do_pending();
+#ifdef CONFIG_IRQ_WORK
+	irq_work_run();
 #endif
 	irq_exit();
 	set_irq_regs(old_regs);
 }
 
-void set_perf_event_pending(void)
+void arch_irq_work_raise(void)
 {
 	set_softint(1 << PIL_DEFERRED_PCR_WORK);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/perf_event.c linux-libre-2.6.37-gnu/arch/sparc/kernel/perf_event.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -658,13 +658,16 @@
 
 		enc = perf_event_get_enc(cpuc->events[i]);
 		pcr &= ~mask_for_index(idx);
-		pcr |= event_encoding(enc, idx);
+		if (hwc->state & PERF_HES_STOPPED)
+			pcr |= nop_for_index(idx);
+		else
+			pcr |= event_encoding(enc, idx);
 	}
 out:
 	return pcr;
 }
 
-void hw_perf_enable(void)
+static void sparc_pmu_enable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	u64 pcr;
@@ -691,7 +694,7 @@
 	pcr_ops->write(cpuc->pcr);
 }
 
-void hw_perf_disable(void)
+static void sparc_pmu_disable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	u64 val;
@@ -710,19 +713,65 @@
 	pcr_ops->write(cpuc->pcr);
 }
 
-static void sparc_pmu_disable(struct perf_event *event)
+static int active_event_index(struct cpu_hw_events *cpuc,
+			      struct perf_event *event)
+{
+	int i;
+
+	for (i = 0; i < cpuc->n_events; i++) {
+		if (cpuc->event[i] == event)
+			break;
+	}
+	BUG_ON(i == cpuc->n_events);
+	return cpuc->current_idx[i];
+}
+
+static void sparc_pmu_start(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	int idx = active_event_index(cpuc, event);
+
+	if (flags & PERF_EF_RELOAD) {
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+		sparc_perf_event_set_period(event, &event->hw, idx);
+	}
+
+	event->hw.state = 0;
+
+	sparc_pmu_enable_event(cpuc, &event->hw, idx);
+}
+
+static void sparc_pmu_stop(struct perf_event *event, int flags)
+{
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+	int idx = active_event_index(cpuc, event);
+
+	if (!(event->hw.state & PERF_HES_STOPPED)) {
+		sparc_pmu_disable_event(cpuc, &event->hw, idx);
+		event->hw.state |= PERF_HES_STOPPED;
+	}
+
+	if (!(event->hw.state & PERF_HES_UPTODATE) && (flags & PERF_EF_UPDATE)) {
+		sparc_perf_event_update(event, &event->hw, idx);
+		event->hw.state |= PERF_HES_UPTODATE;
+	}
+}
+
+static void sparc_pmu_del(struct perf_event *event, int _flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-	struct hw_perf_event *hwc = &event->hw;
 	unsigned long flags;
 	int i;
 
 	local_irq_save(flags);
-	perf_disable();
+	perf_pmu_disable(event->pmu);
 
 	for (i = 0; i < cpuc->n_events; i++) {
 		if (event == cpuc->event[i]) {
-			int idx = cpuc->current_idx[i];
+			/* Absorb the final count and turn off the
+			 * event.
+			 */
+			sparc_pmu_stop(event, PERF_EF_UPDATE);
 
 			/* Shift remaining entries down into
 			 * the existing slot.
@@ -734,13 +783,6 @@
 					cpuc->current_idx[i];
 			}
 
-			/* Absorb the final count and turn off the
-			 * event.
-			 */
-			sparc_pmu_disable_event(cpuc, hwc, idx);
-			barrier();
-			sparc_perf_event_update(event, hwc, idx);
-
 			perf_event_update_userpage(event);
 
 			cpuc->n_events--;
@@ -748,23 +790,10 @@
 		}
 	}
 
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 }
 
-static int active_event_index(struct cpu_hw_events *cpuc,
-			      struct perf_event *event)
-{
-	int i;
-
-	for (i = 0; i < cpuc->n_events; i++) {
-		if (cpuc->event[i] == event)
-			break;
-	}
-	BUG_ON(i == cpuc->n_events);
-	return cpuc->current_idx[i];
-}
-
 static void sparc_pmu_read(struct perf_event *event)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -774,15 +803,6 @@
 	sparc_perf_event_update(event, hwc, idx);
 }
 
-static void sparc_pmu_unthrottle(struct perf_event *event)
-{
-	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-	int idx = active_event_index(cpuc, event);
-	struct hw_perf_event *hwc = &event->hw;
-
-	sparc_pmu_enable_event(cpuc, hwc, idx);
-}
-
 static atomic_t active_events = ATOMIC_INIT(0);
 static DEFINE_MUTEX(pmc_grab_mutex);
 
@@ -877,7 +897,7 @@
 	if (!n_ev)
 		return 0;
 
-	if (n_ev > perf_max_events)
+	if (n_ev > MAX_HWEVENTS)
 		return -1;
 
 	msk0 = perf_event_get_msk(events[0]);
@@ -984,23 +1004,27 @@
 	return n;
 }
 
-static int sparc_pmu_enable(struct perf_event *event)
+static int sparc_pmu_add(struct perf_event *event, int ef_flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int n0, ret = -EAGAIN;
 	unsigned long flags;
 
 	local_irq_save(flags);
-	perf_disable();
+	perf_pmu_disable(event->pmu);
 
 	n0 = cpuc->n_events;
-	if (n0 >= perf_max_events)
+	if (n0 >= MAX_HWEVENTS)
 		goto out;
 
 	cpuc->event[n0] = event;
 	cpuc->events[n0] = event->hw.event_base;
 	cpuc->current_idx[n0] = PIC_NO_INDEX;
 
+	event->hw.state = PERF_HES_UPTODATE;
+	if (!(ef_flags & PERF_EF_START))
+		event->hw.state |= PERF_HES_STOPPED;
+
 	/*
 	 * If group events scheduling transaction was started,
 	 * skip the schedulability test here, it will be peformed
@@ -1020,12 +1044,12 @@
 
 	ret = 0;
 out:
-	perf_enable();
+	perf_pmu_enable(event->pmu);
 	local_irq_restore(flags);
 	return ret;
 }
 
-static int __hw_perf_event_init(struct perf_event *event)
+static int sparc_pmu_event_init(struct perf_event *event)
 {
 	struct perf_event_attr *attr = &event->attr;
 	struct perf_event *evts[MAX_HWEVENTS];
@@ -1038,22 +1062,33 @@
 	if (atomic_read(&nmi_active) < 0)
 		return -ENODEV;
 
-	pmap = NULL;
-	if (attr->type == PERF_TYPE_HARDWARE) {
+	switch (attr->type) {
+	case PERF_TYPE_HARDWARE:
 		if (attr->config >= sparc_pmu->max_events)
 			return -EINVAL;
 		pmap = sparc_pmu->event_map(attr->config);
-	} else if (attr->type == PERF_TYPE_HW_CACHE) {
+		break;
+
+	case PERF_TYPE_HW_CACHE:
 		pmap = sparc_map_cache_event(attr->config);
 		if (IS_ERR(pmap))
 			return PTR_ERR(pmap);
-	} else if (attr->type != PERF_TYPE_RAW)
-		return -EOPNOTSUPP;
+		break;
+
+	case PERF_TYPE_RAW:
+		pmap = NULL;
+		break;
+
+	default:
+		return -ENOENT;
+
+	}
 
 	if (pmap) {
 		hwc->event_base = perf_event_encode(pmap);
 	} else {
-		/* User gives us "(encoding << 16) | pic_mask" for
+		/*
+		 * User gives us "(encoding << 16) | pic_mask" for
 		 * PERF_TYPE_RAW events.
 		 */
 		hwc->event_base = attr->config;
@@ -1071,7 +1106,7 @@
 	n = 0;
 	if (event->group_leader != event) {
 		n = collect_events(event->group_leader,
-				   perf_max_events - 1,
+				   MAX_HWEVENTS - 1,
 				   evts, events, current_idx_dmy);
 		if (n < 0)
 			return -EINVAL;
@@ -1107,10 +1142,11 @@
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-static void sparc_pmu_start_txn(const struct pmu *pmu)
+static void sparc_pmu_start_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
+	perf_pmu_disable(pmu);
 	cpuhw->group_flag |= PERF_EVENT_TXN;
 }
 
@@ -1119,11 +1155,12 @@
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-static void sparc_pmu_cancel_txn(const struct pmu *pmu)
+static void sparc_pmu_cancel_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
 	cpuhw->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
 }
 
 /*
@@ -1131,7 +1168,7 @@
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-static int sparc_pmu_commit_txn(const struct pmu *pmu)
+static int sparc_pmu_commit_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int n;
@@ -1147,28 +1184,24 @@
 		return -EAGAIN;
 
 	cpuc->group_flag &= ~PERF_EVENT_TXN;
+	perf_pmu_enable(pmu);
 	return 0;
 }
 
-static const struct pmu pmu = {
-	.enable		= sparc_pmu_enable,
-	.disable	= sparc_pmu_disable,
+static struct pmu pmu = {
+	.pmu_enable	= sparc_pmu_enable,
+	.pmu_disable	= sparc_pmu_disable,
+	.event_init	= sparc_pmu_event_init,
+	.add		= sparc_pmu_add,
+	.del		= sparc_pmu_del,
+	.start		= sparc_pmu_start,
+	.stop		= sparc_pmu_stop,
 	.read		= sparc_pmu_read,
-	.unthrottle	= sparc_pmu_unthrottle,
 	.start_txn	= sparc_pmu_start_txn,
 	.cancel_txn	= sparc_pmu_cancel_txn,
 	.commit_txn	= sparc_pmu_commit_txn,
 };
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
-{
-	int err = __hw_perf_event_init(event);
-
-	if (err)
-		return ERR_PTR(err);
-	return &pmu;
-}
-
 void perf_event_print_debug(void)
 {
 	unsigned long flags;
@@ -1244,7 +1277,7 @@
 			continue;
 
 		if (perf_event_overflow(event, 1, &data, regs))
-			sparc_pmu_disable_event(cpuc, hwc, idx);
+			sparc_pmu_stop(event, 0);
 	}
 
 	return NOTIFY_STOP;
@@ -1285,28 +1318,21 @@
 
 	pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
 
-	/* All sparc64 PMUs currently have 2 events.  */
-	perf_max_events = 2;
-
+	perf_pmu_register(&pmu);
 	register_die_notifier(&perf_event_nmi_notifier);
 }
 
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-	if (entry->nr < PERF_MAX_STACK_DEPTH)
-		entry->ip[entry->nr++] = ip;
-}
-
-static void perf_callchain_kernel(struct pt_regs *regs,
-				  struct perf_callchain_entry *entry)
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+			   struct pt_regs *regs)
 {
 	unsigned long ksp, fp;
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	int graph = 0;
 #endif
 
-	callchain_store(entry, PERF_CONTEXT_KERNEL);
-	callchain_store(entry, regs->tpc);
+	stack_trace_flush();
+
+	perf_callchain_store(entry, regs->tpc);
 
 	ksp = regs->u_regs[UREG_I6];
 	fp = ksp + STACK_BIAS;
@@ -1330,13 +1356,13 @@
 			pc = sf->callers_pc;
 			fp = (unsigned long)sf->fp + STACK_BIAS;
 		}
-		callchain_store(entry, pc);
+		perf_callchain_store(entry, pc);
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 		if ((pc + 8UL) == (unsigned long) &return_to_handler) {
 			int index = current->curr_ret_stack;
 			if (current->ret_stack && index >= graph) {
 				pc = current->ret_stack[index - graph].ret;
-				callchain_store(entry, pc);
+				perf_callchain_store(entry, pc);
 				graph++;
 			}
 		}
@@ -1344,13 +1370,12 @@
 	} while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-static void perf_callchain_user_64(struct pt_regs *regs,
-				   struct perf_callchain_entry *entry)
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
 {
 	unsigned long ufp;
 
-	callchain_store(entry, PERF_CONTEXT_USER);
-	callchain_store(entry, regs->tpc);
+	perf_callchain_store(entry, regs->tpc);
 
 	ufp = regs->u_regs[UREG_I6] + STACK_BIAS;
 	do {
@@ -1363,17 +1388,16 @@
 
 		pc = sf.callers_pc;
 		ufp = (unsigned long)sf.fp + STACK_BIAS;
-		callchain_store(entry, pc);
+		perf_callchain_store(entry, pc);
 	} while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-static void perf_callchain_user_32(struct pt_regs *regs,
-				   struct perf_callchain_entry *entry)
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+				   struct pt_regs *regs)
 {
 	unsigned long ufp;
 
-	callchain_store(entry, PERF_CONTEXT_USER);
-	callchain_store(entry, regs->tpc);
+	perf_callchain_store(entry, regs->tpc);
 
 	ufp = regs->u_regs[UREG_I6] & 0xffffffffUL;
 	do {
@@ -1386,34 +1410,16 @@
 
 		pc = sf.callers_pc;
 		ufp = (unsigned long)sf.fp;
-		callchain_store(entry, pc);
+		perf_callchain_store(entry, pc);
 	} while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-/* Like powerpc we can't get PMU interrupts within the PMU handler,
- * so no need for separate NMI and IRQ chains as on x86.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-	struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
-
-	entry->nr = 0;
-	if (!user_mode(regs)) {
-		stack_trace_flush();
-		perf_callchain_kernel(regs, entry);
-		if (current->mm)
-			regs = task_pt_regs(current);
-		else
-			regs = NULL;
-	}
-	if (regs) {
-		flushw_user();
-		if (test_thread_flag(TIF_32BIT))
-			perf_callchain_user_32(regs, entry);
-		else
-			perf_callchain_user_64(regs, entry);
-	}
-	return entry;
+	flushw_user();
+	if (test_thread_flag(TIF_32BIT))
+		perf_callchain_user_32(entry, regs);
+	else
+		perf_callchain_user_64(entry, regs);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/prom_common.c linux-libre-2.6.37-gnu/arch/sparc/kernel/prom_common.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/prom_common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/prom_common.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,14 +20,13 @@
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_pdt.h>
 #include <asm/prom.h>
 #include <asm/oplib.h>
 #include <asm/leon.h>
 
 #include "prom.h"
 
-void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp);
-
 struct device_node *of_console_device;
 EXPORT_SYMBOL(of_console_device);
 
@@ -119,192 +118,47 @@
 }
 EXPORT_SYMBOL(of_find_in_proplist);
 
-unsigned int prom_unique_id;
-
-static struct property * __init build_one_prop(phandle node, char *prev,
-					       char *special_name,
-					       void *special_val,
-					       int special_len)
+/*
+ * SPARC32 and SPARC64's prom_nextprop() do things differently
+ * here, despite sharing the same interface.  SPARC32 doesn't fill in 'buf',
+ * returning NULL on an error.  SPARC64 fills in 'buf', but sets it to an
+ * empty string upon error.
+ */
+static int __init handle_nextprop_quirks(char *buf, const char *name)
 {
-	static struct property *tmp = NULL;
-	struct property *p;
-	const char *name;
-
-	if (tmp) {
-		p = tmp;
-		memset(p, 0, sizeof(*p) + 32);
-		tmp = NULL;
-	} else {
-		p = prom_early_alloc(sizeof(struct property) + 32);
-		p->unique_id = prom_unique_id++;
-	}
-
-	p->name = (char *) (p + 1);
-	if (special_name) {
-		strcpy(p->name, special_name);
-		p->length = special_len;
-		p->value = prom_early_alloc(special_len);
-		memcpy(p->value, special_val, special_len);
-	} else {
-		if (prev == NULL) {
-			name = prom_firstprop(node, p->name);
-		} else {
-			name = prom_nextprop(node, prev, p->name);
-		}
+	if (!name || strlen(name) == 0)
+		return -1;
 
-		if (!name || strlen(name) == 0) {
-			tmp = p;
-			return NULL;
-		}
 #ifdef CONFIG_SPARC32
-		strcpy(p->name, name);
+	strcpy(buf, name);
 #endif
-		p->length = prom_getproplen(node, p->name);
-		if (p->length <= 0) {
-			p->length = 0;
-		} else {
-			int len;
-
-			p->value = prom_early_alloc(p->length + 1);
-			len = prom_getproperty(node, p->name, p->value,
-					       p->length);
-			if (len <= 0)
-				p->length = 0;
-			((unsigned char *)p->value)[p->length] = '\0';
-		}
-	}
-	return p;
-}
-
-static struct property * __init build_prop_list(phandle node)
-{
-	struct property *head, *tail;
-
-	head = tail = build_one_prop(node, NULL,
-				     ".node", &node, sizeof(node));
-
-	tail->next = build_one_prop(node, NULL, NULL, NULL, 0);
-	tail = tail->next;
-	while(tail) {
-		tail->next = build_one_prop(node, tail->name,
-					    NULL, NULL, 0);
-		tail = tail->next;
-	}
-
-	return head;
-}
-
-static char * __init get_one_property(phandle node, const char *name)
-{
-	char *buf = "<NULL>";
-	int len;
-
-	len = prom_getproplen(node, name);
-	if (len > 0) {
-		buf = prom_early_alloc(len);
-		len = prom_getproperty(node, name, buf, len);
-	}
-
-	return buf;
-}
-
-static struct device_node * __init prom_create_node(phandle node,
-						    struct device_node *parent)
-{
-	struct device_node *dp;
-
-	if (!node)
-		return NULL;
-
-	dp = prom_early_alloc(sizeof(*dp));
-	dp->unique_id = prom_unique_id++;
-	dp->parent = parent;
-
-	kref_init(&dp->kref);
-
-	dp->name = get_one_property(node, "name");
-	dp->type = get_one_property(node, "device_type");
-	dp->phandle = node;
-
-	dp->properties = build_prop_list(node);
-
-	irq_trans_init(dp);
-
-	return dp;
-}
-
-char * __init build_full_name(struct device_node *dp)
-{
-	int len, ourlen, plen;
-	char *n;
-
-	plen = strlen(dp->parent->full_name);
-	ourlen = strlen(dp->path_component_name);
-	len = ourlen + plen + 2;
-
-	n = prom_early_alloc(len);
-	strcpy(n, dp->parent->full_name);
-	if (!of_node_is_root(dp->parent)) {
-		strcpy(n + plen, "/");
-		plen++;
-	}
-	strcpy(n + plen, dp->path_component_name);
-
-	return n;
+	return 0;
 }
 
-static struct device_node * __init prom_build_tree(struct device_node *parent,
-						   phandle node,
-						   struct device_node ***nextp)
+static int __init prom_common_nextprop(phandle node, char *prev, char *buf)
 {
-	struct device_node *ret = NULL, *prev_sibling = NULL;
-	struct device_node *dp;
-
-	while (1) {
-		dp = prom_create_node(node, parent);
-		if (!dp)
-			break;
-
-		if (prev_sibling)
-			prev_sibling->sibling = dp;
-
-		if (!ret)
-			ret = dp;
-		prev_sibling = dp;
-
-		*(*nextp) = dp;
-		*nextp = &dp->allnext;
-
-		dp->path_component_name = build_path_component(dp);
-		dp->full_name = build_full_name(dp);
-
-		dp->child = prom_build_tree(dp, prom_getchild(node), nextp);
-
-		if (prom_build_more)
-			prom_build_more(dp, nextp);
-
-		node = prom_getsibling(node);
-	}
+	const char *name;
 
-	return ret;
+	buf[0] = '\0';
+	name = prom_nextprop(node, prev, buf);
+	return handle_nextprop_quirks(buf, name);
 }
 
 unsigned int prom_early_allocated __initdata;
 
+static struct of_pdt_ops prom_sparc_ops __initdata = {
+	.nextprop = prom_common_nextprop,
+	.getproplen = prom_getproplen,
+	.getproperty = prom_getproperty,
+	.getchild = prom_getchild,
+	.getsibling = prom_getsibling,
+};
+
 void __init prom_build_devicetree(void)
 {
-	struct device_node **nextp;
-
-	allnodes = prom_create_node(prom_root_node, NULL);
-	allnodes->path_component_name = "";
-	allnodes->full_name = "/";
-
-	nextp = &allnodes->allnext;
-	allnodes->child = prom_build_tree(allnodes,
-					  prom_getchild(allnodes->phandle),
-					  &nextp);
+	of_pdt_build_devicetree(prom_root_node, &prom_sparc_ops);
 	of_console_init();
 
-	printk("PROM: Built device tree with %u bytes of memory.\n",
-	       prom_early_allocated);
+	pr_info("PROM: Built device tree with %u bytes of memory.\n",
+			prom_early_allocated);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/prom.h linux-libre-2.6.37-gnu/arch/sparc/kernel/prom.h
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/prom.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/prom.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,12 +4,6 @@
 #include <linux/spinlock.h>
 #include <asm/prom.h>
 
-extern void * prom_early_alloc(unsigned long size);
-extern void irq_trans_init(struct device_node *dp);
-
-extern unsigned int prom_unique_id;
-
-extern char *build_path_component(struct device_node *dp);
 extern void of_console_init(void);
 
 extern unsigned int prom_early_allocated;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/ptrace_32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/ptrace_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/ptrace_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/ptrace_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -323,18 +323,35 @@
 	return &user_sparc32_view;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+struct fps {
+	unsigned long regs[32];
+	unsigned long fsr;
+	unsigned long flags;
+	unsigned long extra;
+	unsigned long fpqd;
+	struct fq {
+		unsigned long *insnaddr;
+		unsigned long insn;
+	} fpq[16];
+};
+
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	unsigned long addr2 = current->thread.kregs->u_regs[UREG_I4];
+	void __user *addr2p;
 	const struct user_regset_view *view;
+	struct pt_regs __user *pregs;
+	struct fps __user *fps;
 	int ret;
 
 	view = task_user_regset_view(current);
+	addr2p = (void __user *) addr2;
+	pregs = (struct pt_regs __user *) addr;
+	fps = (struct fps __user *) addr;
 
 	switch(request) {
 	case PTRACE_GETREGS: {
-		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
 		ret = copy_regset_to_user(child, view, REGSET_GENERAL,
 					  32 * sizeof(u32),
 					  4 * sizeof(u32),
@@ -348,8 +365,6 @@
 	}
 
 	case PTRACE_SETREGS: {
-		struct pt_regs __user *pregs = (struct pt_regs __user *) addr;
-
 		ret = copy_regset_from_user(child, view, REGSET_GENERAL,
 					    32 * sizeof(u32),
 					    4 * sizeof(u32),
@@ -363,19 +378,6 @@
 	}
 
 	case PTRACE_GETFPREGS: {
-		struct fps {
-			unsigned long regs[32];
-			unsigned long fsr;
-			unsigned long flags;
-			unsigned long extra;
-			unsigned long fpqd;
-			struct fq {
-				unsigned long *insnaddr;
-				unsigned long insn;
-			} fpq[16];
-		};
-		struct fps __user *fps = (struct fps __user *) addr;
-
 		ret = copy_regset_to_user(child, view, REGSET_FP,
 					  0 * sizeof(u32),
 					  32 * sizeof(u32),
@@ -397,19 +399,6 @@
 	}
 
 	case PTRACE_SETFPREGS: {
-		struct fps {
-			unsigned long regs[32];
-			unsigned long fsr;
-			unsigned long flags;
-			unsigned long extra;
-			unsigned long fpqd;
-			struct fq {
-				unsigned long *insnaddr;
-				unsigned long insn;
-			} fpq[16];
-		};
-		struct fps __user *fps = (struct fps __user *) addr;
-
 		ret = copy_regset_from_user(child, view, REGSET_FP,
 					    0 * sizeof(u32),
 					    32 * sizeof(u32),
@@ -424,8 +413,7 @@
 
 	case PTRACE_READTEXT:
 	case PTRACE_READDATA:
-		ret = ptrace_readdata(child, addr,
-				      (void __user *) addr2, data);
+		ret = ptrace_readdata(child, addr, addr2p, data);
 
 		if (ret == data)
 			ret = 0;
@@ -435,8 +423,7 @@
 
 	case PTRACE_WRITETEXT:
 	case PTRACE_WRITEDATA:
-		ret = ptrace_writedata(child, (void __user *) addr2,
-				       addr, data);
+		ret = ptrace_writedata(child, addr2p, addr, data);
 
 		if (ret == data)
 			ret = 0;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/ptrace_64.c linux-libre-2.6.37-gnu/arch/sparc/kernel/ptrace_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/ptrace_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/ptrace_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -969,16 +969,19 @@
 	unsigned long fsr;
 };
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	const struct user_regset_view *view = task_user_regset_view(current);
 	unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4];
 	struct pt_regs __user *pregs;
 	struct fps __user *fps;
+	void __user *addr2p;
 	int ret;
 
-	pregs = (struct pt_regs __user *) (unsigned long) addr;
-	fps = (struct fps __user *) (unsigned long) addr;
+	pregs = (struct pt_regs __user *) addr;
+	fps = (struct fps __user *) addr;
+	addr2p = (void __user *) addr2;
 
 	switch (request) {
 	case PTRACE_PEEKUSR:
@@ -1029,8 +1032,7 @@
 
 	case PTRACE_READTEXT:
 	case PTRACE_READDATA:
-		ret = ptrace_readdata(child, addr,
-				      (char __user *)addr2, data);
+		ret = ptrace_readdata(child, addr, addr2p, data);
 		if (ret == data)
 			ret = 0;
 		else if (ret >= 0)
@@ -1039,8 +1041,7 @@
 
 	case PTRACE_WRITETEXT:
 	case PTRACE_WRITEDATA:
-		ret = ptrace_writedata(child, (char __user *) addr2,
-				       addr, data);
+		ret = ptrace_writedata(child, addr2p, addr, data);
 		if (ret == data)
 			ret = 0;
 		else if (ret >= 0)
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/rtrap_32.S linux-libre-2.6.37-gnu/arch/sparc/kernel/rtrap_32.S
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/rtrap_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/rtrap_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -78,9 +78,9 @@
 	call	do_notify_resume
 	 add	%sp, STACKFRAME_SZ, %o0	! pt_regs ptr
 
-	/* Fall through. */
-	ld	[%sp + STACKFRAME_SZ + PT_PSR], %t_psr
-	clr	%l6
+	b	signal_p
+	 ld	[%curptr + TI_FLAGS], %g2
+
 ret_trap_continue:
 	sethi	%hi(PSR_SYSCALL), %g1
 	andn	%t_psr, %g1, %t_psr
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/rtrap_64.S linux-libre-2.6.37-gnu/arch/sparc/kernel/rtrap_64.S
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/rtrap_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/rtrap_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -34,37 +34,9 @@
 __handle_user_windows:
 		call			fault_in_user_windows
 		 wrpr			%g0, RTRAP_PSTATE, %pstate
-		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		/* Redo sched+sig checks */
-		ldx			[%g6 + TI_FLAGS], %l0
-		andcc			%l0, _TIF_NEED_RESCHED, %g0
-
-		be,pt			%xcc, 1f
-		 nop
-		call			schedule
-		 wrpr			%g0, RTRAP_PSTATE, %pstate
-		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		ldx			[%g6 + TI_FLAGS], %l0
-
-1:		andcc			%l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0
-		be,pt			%xcc, __handle_user_windows_continue
-		 nop
-		mov			%l5, %o1
-		add			%sp, PTREGS_OFF, %o0
-		mov			%l0, %o2
-
-		call			do_notify_resume
-		 wrpr			%g0, RTRAP_PSTATE, %pstate
-		wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
-		/* Signal delivery can modify pt_regs tstate, so we must
-		 * reload it.
-		 */
-		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
-		sethi			%hi(0xf << 20), %l4
-		and			%l1, %l4, %l4
-		ba,pt			%xcc, __handle_user_windows_continue
+		ba,pt			%xcc, __handle_preemption_continue
+		 wrpr			%g0, RTRAP_PSTATE_IRQOFF, %pstate
 
-		 andn			%l1, %l4, %l1
 __handle_userfpu:
 		rd			%fprs, %l5
 		andcc			%l5, FPRS_FEF, %g0
@@ -87,7 +59,7 @@
 		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 		sethi			%hi(0xf << 20), %l4
 		and			%l1, %l4, %l4
-		ba,pt			%xcc, __handle_signal_continue
+		ba,pt			%xcc, __handle_preemption_continue
 		 andn			%l1, %l4, %l1
 
 		/* When returning from a NMI (%pil==15) interrupt we want to
@@ -177,11 +149,9 @@
 		bne,pn			%xcc, __handle_preemption
 		 andcc			%l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0
 		bne,pn			%xcc, __handle_signal
-__handle_signal_continue:
 		 ldub			[%g6 + TI_WSAVED], %o2
 		brnz,pn			%o2, __handle_user_windows
 		 nop
-__handle_user_windows_continue:
 		sethi			%hi(TSTATE_PEF), %o0
 		andcc			%l1, %o0, %g0
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/setup_64.c linux-libre-2.6.37-gnu/arch/sparc/kernel/setup_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/setup_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/setup_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -315,7 +315,7 @@
 
 #ifdef CONFIG_IP_PNP
 	if (!ic_set_manually) {
-		int chosen = prom_finddevice ("/chosen");
+		phandle chosen = prom_finddevice("/chosen");
 		u32 cl, sv, gw;
 		
 		cl = prom_getintdefault (chosen, "client-ip", 0);
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/starfire.c linux-libre-2.6.37-gnu/arch/sparc/kernel/starfire.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/starfire.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/starfire.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,7 @@
 
 void check_if_starfire(void)
 {
-	int ssnode = prom_finddevice("/ssp-serial");
+	phandle ssnode = prom_finddevice("/ssp-serial");
 	if (ssnode != 0 && ssnode != -1)
 		this_is_starfire = 1;
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/sys_sparc_32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/sys_sparc_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/sys_sparc_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/sys_sparc_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,6 @@
 #include <linux/mman.h>
 #include <linux/utsname.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/ipc.h>
 
 #include <asm/uaccess.h>
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/sys_sparc32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/sys_sparc32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/sys_sparc32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/sys_sparc32.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,6 @@
 #include <linux/resource.h>
 #include <linux/times.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/tadpole.c linux-libre-2.6.37-gnu/arch/sparc/kernel/tadpole.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/tadpole.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/tadpole.c	2011-01-04 19:50:19.000000000 -0500
@@ -100,7 +100,7 @@
 
 void __init clock_stop_probe(void)
 {
-	unsigned int node, clk_nd;
+	phandle node, clk_nd;
 	char name[20];
     
 	prom_getstring(prom_root_node, "name", name, sizeof(name));
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/unaligned_32.c linux-libre-2.6.37-gnu/arch/sparc/kernel/unaligned_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/unaligned_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/unaligned_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/perf_event.h>
 
 enum direction {
diff -druN linux-libre-2.6.36-gnu/arch/sparc/kernel/windows.c linux-libre-2.6.37-gnu/arch/sparc/kernel/windows.c
--- linux-libre-2.6.36-gnu/arch/sparc/kernel/windows.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/kernel/windows.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,6 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/mm/fault_32.c linux-libre-2.6.37-gnu/arch/sparc/mm/fault_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/mm/fault_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/mm/fault_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -539,6 +539,12 @@
 	__do_fault_siginfo(BUS_ADRERR, SIGBUS, tsk->thread.kregs, address);
 }
 
+static void check_stack_aligned(unsigned long sp)
+{
+	if (sp & 0x7UL)
+		force_sig(SIGILL, current);
+}
+
 void window_overflow_fault(void)
 {
 	unsigned long sp;
@@ -547,6 +553,8 @@
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 1);
 	force_user_fault(sp, 1);
+
+	check_stack_aligned(sp);
 }
 
 void window_underflow_fault(unsigned long sp)
@@ -554,6 +562,8 @@
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
+
+	check_stack_aligned(sp);
 }
 
 void window_ret_fault(struct pt_regs *regs)
@@ -564,4 +574,6 @@
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
+
+	check_stack_aligned(sp);
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/mm/highmem.c linux-libre-2.6.37-gnu/arch/sparc/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/sparc/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,17 +29,17 @@
 #include <asm/tlbflush.h>
 #include <asm/fixmap.h>
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
-	unsigned long idx;
 	unsigned long vaddr;
+	long idx, type;
 
 	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
 	pagefault_disable();
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 
@@ -63,44 +63,52 @@
 
 	return (void*) vaddr;
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
-#ifdef CONFIG_DEBUG_HIGHMEM
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	unsigned long idx = type + KM_TYPE_NR*smp_processor_id();
+	int type;
 
 	if (vaddr < FIXADDR_START) { // FIXME
 		pagefault_enable();
 		return;
 	}
 
-	BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+	type = kmap_atomic_idx();
 
-/* XXX Fix - Anton */
+#ifdef CONFIG_DEBUG_HIGHMEM
+	{
+		unsigned long idx;
+
+		idx = type + KM_TYPE_NR * smp_processor_id();
+		BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx));
+
+		/* XXX Fix - Anton */
 #if 0
-	__flush_cache_one(vaddr);
+		__flush_cache_one(vaddr);
 #else
-	flush_cache_all();
+		flush_cache_all();
 #endif
 
-	/*
-	 * force other mappings to Oops if they'll try to access
-	 * this pte without first remap it
-	 */
-	pte_clear(&init_mm, vaddr, kmap_pte-idx);
-/* XXX Fix - Anton */
+		/*
+		 * force other mappings to Oops if they'll try to access
+		 * this pte without first remap it
+		 */
+		pte_clear(&init_mm, vaddr, kmap_pte-idx);
+		/* XXX Fix - Anton */
 #if 0
-	__flush_tlb_one(vaddr);
+		__flush_tlb_one(vaddr);
 #else
-	flush_tlb_all();
+		flush_tlb_all();
 #endif
+	}
 #endif
 
+	kmap_atomic_idx_pop();
 	pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /* We may be fed a pagetable here by ptep_to_xxx and others. */
 struct page *kmap_atomic_to_page(void *ptr)
diff -druN linux-libre-2.6.36-gnu/arch/sparc/mm/init_64.c linux-libre-2.6.37-gnu/arch/sparc/mm/init_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/mm/init_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/mm/init_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,7 @@
 				   struct linux_prom64_registers *regs,
 				   int *num_ents)
 {
-	int node = prom_finddevice("/memory");
+	phandle node = prom_finddevice("/memory");
 	int prop_size = prom_getproplen(node, property);
 	int ents, ret, i;
 
@@ -785,8 +785,7 @@
 	return -1;
 }
 
-static unsigned long long nid_range(unsigned long long start,
-				    unsigned long long end, int *nid)
+u64 memblock_nid_range(u64 start, u64 end, int *nid)
 {
 	*nid = find_node(start);
 	start += PAGE_SIZE;
@@ -804,8 +803,7 @@
 	return start;
 }
 #else
-static unsigned long long nid_range(unsigned long long start,
-				    unsigned long long end, int *nid)
+u64 memblock_nid_range(u64 start, u64 end, int *nid)
 {
 	*nid = 0;
 	return end;
@@ -822,8 +820,7 @@
 	struct pglist_data *p;
 
 #ifdef CONFIG_NEED_MULTIPLE_NODES
-	paddr = memblock_alloc_nid(sizeof(struct pglist_data),
-			      SMP_CACHE_BYTES, nid, nid_range);
+	paddr = memblock_alloc_try_nid(sizeof(struct pglist_data), SMP_CACHE_BYTES, nid);
 	if (!paddr) {
 		prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid);
 		prom_halt();
@@ -843,8 +840,7 @@
 	if (p->node_spanned_pages) {
 		num_pages = bootmem_bootmap_pages(p->node_spanned_pages);
 
-		paddr = memblock_alloc_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid,
-				      nid_range);
+		paddr = memblock_alloc_try_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid);
 		if (!paddr) {
 			prom_printf("Cannot allocate bootmap for nid[%d]\n",
 				  nid);
@@ -972,19 +968,19 @@
 
 static void __init add_node_ranges(void)
 {
-	int i;
+	struct memblock_region *reg;
 
-	for (i = 0; i < memblock.memory.cnt; i++) {
-		unsigned long size = memblock_size_bytes(&memblock.memory, i);
+	for_each_memblock(memory, reg) {
+		unsigned long size = reg->size;
 		unsigned long start, end;
 
-		start = memblock.memory.region[i].base;
+		start = reg->base;
 		end = start + size;
 		while (start < end) {
 			unsigned long this_end;
 			int nid;
 
-			this_end = nid_range(start, end, &nid);
+			this_end = memblock_nid_range(start, end, &nid);
 
 			numadbg("Adding active range nid[%d] "
 				"start[%lx] end[%lx]\n",
@@ -1281,7 +1277,7 @@
 {
 	unsigned long top_of_ram = memblock_end_of_DRAM();
 	unsigned long total_ram = memblock_phys_mem_size();
-	unsigned int i;
+	struct memblock_region *reg;
 
 	numadbg("bootmem_init_nonnuma()\n");
 
@@ -1292,15 +1288,14 @@
 
 	init_node_masks_nonnuma();
 
-	for (i = 0; i < memblock.memory.cnt; i++) {
-		unsigned long size = memblock_size_bytes(&memblock.memory, i);
+	for_each_memblock(memory, reg) {
 		unsigned long start_pfn, end_pfn;
 
-		if (!size)
+		if (!reg->size)
 			continue;
 
-		start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-		end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+		start_pfn = memblock_region_memory_base_pfn(reg);
+		end_pfn = memblock_region_memory_end_pfn(reg);
 		add_active_range(0, start_pfn, end_pfn);
 	}
 
@@ -1318,7 +1313,7 @@
 		unsigned long this_end;
 		int n;
 
-		this_end = nid_range(start, end, &n);
+		this_end = memblock_nid_range(start, end, &n);
 		if (n == nid) {
 			numadbg("      MATCH reserving range [%lx:%lx]\n",
 				start, this_end);
@@ -1334,17 +1329,12 @@
 
 static void __init trim_reserved_in_node(int nid)
 {
-	int i;
+	struct memblock_region *reg;
 
 	numadbg("  trim_reserved_in_node(%d)\n", nid);
 
-	for (i = 0; i < memblock.reserved.cnt; i++) {
-		unsigned long start = memblock.reserved.region[i].base;
-		unsigned long size = memblock_size_bytes(&memblock.reserved, i);
-		unsigned long end = start + size;
-
-		reserve_range_in_node(nid, start, end);
-	}
+	for_each_memblock(reserved, reg)
+		reserve_range_in_node(nid, reg->base, reg->base + reg->size);
 }
 
 static void __init bootmem_init_one_node(int nid)
diff -druN linux-libre-2.6.36-gnu/arch/sparc/mm/srmmu.c linux-libre-2.6.37-gnu/arch/sparc/mm/srmmu.c
--- linux-libre-2.6.36-gnu/arch/sparc/mm/srmmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/mm/srmmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -1262,7 +1262,8 @@
 
 void __init srmmu_paging_init(void)
 {
-	int i, cpunode;
+	int i;
+	phandle cpunode;
 	char node_str[128];
 	pgd_t *pgd;
 	pmd_t *pmd;
@@ -1398,7 +1399,8 @@
 
 static void __init init_vac_layout(void)
 {
-	int nd, cache_lines;
+	phandle nd;
+	int cache_lines;
 	char node_str[128];
 #ifdef CONFIG_SMP
 	int cpu = 0;
@@ -2082,7 +2084,7 @@
 
 	/* Next check for Fujitsu Swift. */
 	if(psr_typ == 0 && psr_vers == 4) {
-		int cpunode;
+		phandle cpunode;
 		char node_str[128];
 
 		/* Look if it is not a TurboSparc emulating Swift... */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/mm/sun4c.c linux-libre-2.6.37-gnu/arch/sparc/mm/sun4c.c
--- linux-libre-2.6.36-gnu/arch/sparc/mm/sun4c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/mm/sun4c.c	2011-01-04 19:50:19.000000000 -0500
@@ -420,7 +420,7 @@
 
 void __init sun4c_probe_memerr_reg(void)
 {
-	int node;
+	phandle node;
 	struct linux_prom_registers regs[1];
 
 	node = prom_getchild(prom_root_node);
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/console_32.c linux-libre-2.6.37-gnu/arch/sparc/prom/console_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/console_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/console_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,63 +16,26 @@
 
 extern void restore_current(void);
 
-/* Non blocking get character from console input device, returns -1
- * if no input was taken.  This can be used for polling.
- */
-int
-prom_nbgetchar(void)
-{
-	static char inc;
-	int i = -1;
-	unsigned long flags;
-
-	spin_lock_irqsave(&prom_lock, flags);
-	switch(prom_vers) {
-	case PROM_V0:
-		i = (*(romvec->pv_nbgetchar))();
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		if( (*(romvec->pv_v2devops).v2_dev_read)(*romvec->pv_v2bootargs.fd_stdin , &inc, 0x1) == 1) {
-			i = inc;
-		} else {
-			i = -1;
-		}
-		break;
-	default:
-		i = -1;
-		break;
-	};
-	restore_current();
-	spin_unlock_irqrestore(&prom_lock, flags);
-	return i; /* Ugh, we could spin forever on unsupported proms ;( */
-}
-
 /* Non blocking put character to console device, returns -1 if
  * unsuccessful.
  */
-int
-prom_nbputchar(char c)
+static int prom_nbputchar(const char *buf)
 {
-	static char outc;
 	unsigned long flags;
 	int i = -1;
 
 	spin_lock_irqsave(&prom_lock, flags);
 	switch(prom_vers) {
 	case PROM_V0:
-		i = (*(romvec->pv_nbputchar))(c);
+		i = (*(romvec->pv_nbputchar))(*buf);
 		break;
 	case PROM_V2:
 	case PROM_V3:
-		outc = c;
-		if( (*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout, &outc, 0x1) == 1)
+		if ((*(romvec->pv_v2devops).v2_dev_write)(*romvec->pv_v2bootargs.fd_stdout,
+							  buf, 0x1) == 1)
 			i = 0;
-		else
-			i = -1;
 		break;
 	default:
-		i = -1;
 		break;
 	};
 	restore_current();
@@ -80,18 +43,14 @@
 	return i; /* Ugh, we could spin forever on unsupported proms ;( */
 }
 
-/* Blocking version of get character routine above. */
-char
-prom_getchar(void)
+void prom_console_write_buf(const char *buf, int len)
 {
-	int character;
-	while((character = prom_nbgetchar()) == -1) ;
-	return (char) character;
+	while (len) {
+		int n = prom_nbputchar(buf);
+		if (n)
+			continue;
+		len--;
+		buf++;
+	}
 }
 
-/* Blocking version of put character routine above. */
-void
-prom_putchar(char c)
-{
-	while(prom_nbputchar(c) == -1) ;
-}
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/console_64.c linux-libre-2.6.37-gnu/arch/sparc/prom/console_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/console_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/console_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,85 +15,34 @@
 
 extern int prom_stdin, prom_stdout;
 
-/* Non blocking get character from console input device, returns -1
- * if no input was taken.  This can be used for polling.
- */
-inline int
-prom_nbgetchar(void)
-{
-	unsigned long args[7];
-	char inc;
-
-	args[0] = (unsigned long) "read";
-	args[1] = 3;
-	args[2] = 1;
-	args[3] = (unsigned int) prom_stdin;
-	args[4] = (unsigned long) &inc;
-	args[5] = 1;
-	args[6] = (unsigned long) -1;
-
-	p1275_cmd_direct(args);
-
-	if (args[6] == 1)
-		return inc;
-	return -1;
-}
-
-/* Non blocking put character to console device, returns -1 if
- * unsuccessful.
- */
-inline int
-prom_nbputchar(char c)
+static int __prom_console_write_buf(const char *buf, int len)
 {
 	unsigned long args[7];
-	char outc;
-	
-	outc = c;
+	int ret;
 
 	args[0] = (unsigned long) "write";
 	args[1] = 3;
 	args[2] = 1;
 	args[3] = (unsigned int) prom_stdout;
-	args[4] = (unsigned long) &outc;
-	args[5] = 1;
+	args[4] = (unsigned long) buf;
+	args[5] = (unsigned int) len;
 	args[6] = (unsigned long) -1;
 
 	p1275_cmd_direct(args);
 
-	if (args[6] == 1)
-		return 0;
-	else
+	ret = (int) args[6];
+	if (ret < 0)
 		return -1;
+	return ret;
 }
 
-/* Blocking version of get character routine above. */
-char
-prom_getchar(void)
-{
-	int character;
-	while((character = prom_nbgetchar()) == -1) ;
-	return (char) character;
-}
-
-/* Blocking version of put character routine above. */
-void
-prom_putchar(char c)
-{
-	prom_nbputchar(c);
-}
-
-void
-prom_puts(const char *s, int len)
+void prom_console_write_buf(const char *buf, int len)
 {
-	unsigned long args[7];
-
-	args[0] = (unsigned long) "write";
-	args[1] = 3;
-	args[2] = 1;
-	args[3] = (unsigned int) prom_stdout;
-	args[4] = (unsigned long) s;
-	args[5] = len;
-	args[6] = (unsigned long) -1;
-
-	p1275_cmd_direct(args);
+	while (len) {
+		int n = __prom_console_write_buf(buf, len);
+		if (n < 0)
+			continue;
+		len -= n;
+		buf += len;
+	}
 }
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/devops_32.c linux-libre-2.6.37-gnu/arch/sparc/prom/devops_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/devops_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/devops_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,87 +0,0 @@
-/*
- * devops.c:  Device operations using the PROM.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-
-extern void restore_current(void);
-
-/* Open the device described by the string 'dstr'.  Returns the handle
- * to that device used for subsequent operations on that device.
- * Returns -1 on failure.
- */
-int
-prom_devopen(char *dstr)
-{
-	int handle;
-	unsigned long flags;
-	spin_lock_irqsave(&prom_lock, flags);
-	switch(prom_vers) {
-	case PROM_V0:
-		handle = (*(romvec->pv_v0devops.v0_devopen))(dstr);
-		if(handle == 0) handle = -1;
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
-		break;
-	default:
-		handle = -1;
-		break;
-	};
-	restore_current();
-	spin_unlock_irqrestore(&prom_lock, flags);
-
-	return handle;
-}
-
-/* Close the device described by device handle 'dhandle'. */
-int
-prom_devclose(int dhandle)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&prom_lock, flags);
-	switch(prom_vers) {
-	case PROM_V0:
-		(*(romvec->pv_v0devops.v0_devclose))(dhandle);
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		(*(romvec->pv_v2devops.v2_dev_close))(dhandle);
-		break;
-	default:
-		break;
-	};
-	restore_current();
-	spin_unlock_irqrestore(&prom_lock, flags);
-	return 0;
-}
-
-/* Seek to specified location described by 'seekhi' and 'seeklo'
- * for device 'dhandle'.
- */
-void
-prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&prom_lock, flags);
-	switch(prom_vers) {
-	case PROM_V0:
-		(*(romvec->pv_v0devops.v0_seekdev))(dhandle, seekhi, seeklo);
-		break;
-	case PROM_V2:
-	case PROM_V3:
-		(*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
-		break;
-	default:
-		break;
-	};
-	restore_current();
-	spin_unlock_irqrestore(&prom_lock, flags);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/devops_64.c linux-libre-2.6.37-gnu/arch/sparc/prom/devops_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/devops_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/devops_64.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,67 +0,0 @@
-/*
- * devops.c:  Device operations using the PROM.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-
-/* Open the device described by the string 'dstr'.  Returns the handle
- * to that device used for subsequent operations on that device.
- * Returns 0 on failure.
- */
-int
-prom_devopen(const char *dstr)
-{
-	unsigned long args[5];
-
-	args[0] = (unsigned long) "open";
-	args[1] = 1;
-	args[2] = 1;
-	args[3] = (unsigned long) dstr;
-	args[4] = (unsigned long) -1;
-
-	p1275_cmd_direct(args);
-
-	return (int) args[4];
-}
-
-/* Close the device described by device handle 'dhandle'. */
-int
-prom_devclose(int dhandle)
-{
-	unsigned long args[4];
-
-	args[0] = (unsigned long) "close";
-	args[1] = 1;
-	args[2] = 0;
-	args[3] = (unsigned int) dhandle;
-
-	p1275_cmd_direct(args);
-
-	return 0;
-}
-
-/* Seek to specified location described by 'seekhi' and 'seeklo'
- * for device 'dhandle'.
- */
-void
-prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
-{
-	unsigned long args[7];
-
-	args[0] = (unsigned long) "seek";
-	args[1] = 3;
-	args[2] = 1;
-	args[3] = (unsigned int) dhandle;
-	args[4] = seekhi;
-	args[5] = seeklo;
-	args[6] = (unsigned long) -1;
-
-	p1275_cmd_direct(args);
-}
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/init_32.c linux-libre-2.6.37-gnu/arch/sparc/prom/init_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/init_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/init_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 unsigned int prom_rev, prom_prev;
 
 /* The root node of the prom device tree. */
-int prom_root_node;
+phandle prom_root_node;
 EXPORT_SYMBOL(prom_root_node);
 
 /* Pointer to the device tree operations structure. */
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/init_64.c linux-libre-2.6.37-gnu/arch/sparc/prom/init_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/init_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/init_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,7 @@
 
 /* The root node of the prom device tree. */
 int prom_stdin, prom_stdout;
-int prom_chosen_node;
+phandle prom_chosen_node;
 
 /* You must call prom_init() before you attempt to use any of the
  * routines in the prom library.  It returns 0 on success, 1 on
@@ -30,7 +30,7 @@
 
 void __init prom_init(void *cif_handler, void *cif_stack)
 {
-	int node;
+	phandle node;
 
 	prom_cif_init(cif_handler, cif_stack);
 
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/Makefile linux-libre-2.6.37-gnu/arch/sparc/prom/Makefile
--- linux-libre-2.6.36-gnu/arch/sparc/prom/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,6 @@
 
 lib-y                 := bootstr_$(BITS).o
 lib-$(CONFIG_SPARC32) += devmap.o
-lib-y                 += devops_$(BITS).o
 lib-y                 += init_$(BITS).o
 lib-$(CONFIG_SPARC32) += memory.o
 lib-y                 += misc_$(BITS).o
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/memory.c linux-libre-2.6.37-gnu/arch/sparc/prom/memory.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/memory.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/memory.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,7 +31,8 @@
 static int __init prom_meminit_v2(void)
 {
 	struct linux_prom_registers reg[64];
-	int node, size, num_ents, i;
+	phandle node;
+	int size, num_ents, i;
 
 	node = prom_searchsiblings(prom_getchild(prom_root_node), "memory");
 	size = prom_getproperty(node, "available", (char *) reg, sizeof(reg));
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/misc_64.c linux-libre-2.6.37-gnu/arch/sparc/prom/misc_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/misc_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/misc_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,7 @@
 #include <asm/system.h>
 #include <asm/ldc.h>
 
-int prom_service_exists(const char *service_name)
+static int prom_service_exists(const char *service_name)
 {
 	unsigned long args[5];
 
@@ -150,20 +150,6 @@
 	prom_halt();
 }
 
-/* Set prom sync handler to call function 'funcp'. */
-void prom_setcallback(callback_func_t funcp)
-{
-	unsigned long args[5];
-	if (!funcp)
-		return;
-	args[0] = (unsigned long) "set-callback";
-	args[1] = 1;
-	args[2] = 1;
-	args[3] = (unsigned long) funcp;
-	args[4] = (unsigned long) -1;
-	p1275_cmd_direct(args);
-}
-
 /* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
  * format type.  'num_bytes' is the number of bytes that your idbuf
  * has space for.  Returns 0xff on error.
@@ -183,7 +169,8 @@
 
 int prom_get_mmu_ihandle(void)
 {
-	int node, ret;
+	phandle node;
+	int ret;
 
 	if (prom_mmu_ihandle_cache != 0)
 		return prom_mmu_ihandle_cache;
@@ -201,7 +188,8 @@
 static int prom_get_memory_ihandle(void)
 {
 	static int memory_ihandle_cache;
-	int node, ret;
+	phandle node;
+	int ret;
 
 	if (memory_ihandle_cache != 0)
 		return memory_ihandle_cache;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/p1275.c linux-libre-2.6.37-gnu/arch/sparc/prom/p1275.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/p1275.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/p1275.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 	unsigned long flags;
 
 	raw_local_save_flags(flags);
-	raw_local_irq_restore(PIL_NMI);
+	raw_local_irq_restore((unsigned long)PIL_NMI);
 	raw_spin_lock(&prom_entry_lock);
 
 	prom_world(1);
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/printf.c linux-libre-2.6.37-gnu/arch/sparc/prom/printf.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/printf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/printf.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,22 +15,45 @@
 
 #include <linux/kernel.h>
 #include <linux/compiler.h>
+#include <linux/spinlock.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
+#define CONSOLE_WRITE_BUF_SIZE	1024
+
 static char ppbuf[1024];
+static char console_write_buf[CONSOLE_WRITE_BUF_SIZE];
+static DEFINE_RAW_SPINLOCK(console_write_lock);
 
 void notrace prom_write(const char *buf, unsigned int n)
 {
-	char ch;
+	unsigned int dest_len;
+	unsigned long flags;
+	char *dest;
 
-	while (n != 0) {
-		--n;
-		if ((ch = *buf++) == '\n')
-			prom_putchar('\r');
-		prom_putchar(ch);
+	dest = console_write_buf;
+	raw_spin_lock_irqsave(&console_write_lock, flags);
+
+	dest_len = 0;
+	while (n-- != 0) {
+		char ch = *buf++;
+		if (ch == '\n') {
+			*dest++ = '\r';
+			dest_len++;
+		}
+		*dest++ = ch;
+		dest_len++;
+		if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) {
+			prom_console_write_buf(console_write_buf, dest_len);
+			dest = console_write_buf;
+			dest_len = 0;
+		}
 	}
+	if (dest_len)
+		prom_console_write_buf(console_write_buf, dest_len);
+
+	raw_spin_unlock_irqrestore(&console_write_lock, flags);
 }
 
 void notrace prom_printf(const char *fmt, ...)
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/ranges.c linux-libre-2.6.37-gnu/arch/sparc/prom/ranges.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/ranges.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/ranges.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,7 +68,7 @@
 
 void __init prom_ranges_init(void)
 {
-	int node, obio_node;
+	phandle node, obio_node;
 	int success;
 
 	num_obio_ranges = 0;
@@ -89,8 +89,8 @@
 		prom_printf("PROMLIB: obio_ranges %d\n", num_obio_ranges);
 }
 
-void
-prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
+void prom_apply_generic_ranges(phandle node, phandle parent,
+		struct linux_prom_registers *regs, int nregs)
 {
 	int success;
 	int num_ranges;
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/tree_32.c linux-libre-2.6.37-gnu/arch/sparc/prom/tree_32.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/tree_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/tree_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,10 +20,10 @@
 static char promlib_buf[128];
 
 /* Internal version of prom_getchild that does not alter return values. */
-int __prom_getchild(int node)
+phandle __prom_getchild(phandle node)
 {
 	unsigned long flags;
-	int cnode;
+	phandle cnode;
 
 	spin_lock_irqsave(&prom_lock, flags);
 	cnode = prom_nodeops->no_child(node);
@@ -36,9 +36,9 @@
 /* Return the child of node 'node' or zero if no this node has no
  * direct descendent.
  */
-int prom_getchild(int node)
+phandle prom_getchild(phandle node)
 {
-	int cnode;
+	phandle cnode;
 
 	if (node == -1)
 		return 0;
@@ -52,10 +52,10 @@
 EXPORT_SYMBOL(prom_getchild);
 
 /* Internal version of prom_getsibling that does not alter return values. */
-int __prom_getsibling(int node)
+phandle __prom_getsibling(phandle node)
 {
 	unsigned long flags;
-	int cnode;
+	phandle cnode;
 
 	spin_lock_irqsave(&prom_lock, flags);
 	cnode = prom_nodeops->no_nextnode(node);
@@ -68,9 +68,9 @@
 /* Return the next sibling of node 'node' or zero if no more siblings
  * at this level of depth in the tree.
  */
-int prom_getsibling(int node)
+phandle prom_getsibling(phandle node)
 {
-	int sibnode;
+	phandle sibnode;
 
 	if (node == -1)
 		return 0;
@@ -86,7 +86,7 @@
 /* Return the length in bytes of property 'prop' at node 'node'.
  * Return -1 on error.
  */
-int prom_getproplen(int node, const char *prop)
+int prom_getproplen(phandle node, const char *prop)
 {
 	int ret;
 	unsigned long flags;
@@ -106,7 +106,7 @@
  * 'buffer' which has a size of 'bufsize'.  If the acquisition
  * was successful the length will be returned, else -1 is returned.
  */
-int prom_getproperty(int node, const char *prop, char *buffer, int bufsize)
+int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
 {
 	int plen, ret;
 	unsigned long flags;
@@ -126,7 +126,7 @@
 /* Acquire an integer property and return its value.  Returns -1
  * on failure.
  */
-int prom_getint(int node, char *prop)
+int prom_getint(phandle node, char *prop)
 {
 	static int intprop;
 
@@ -140,7 +140,7 @@
 /* Acquire an integer property, upon error return the passed default
  * integer.
  */
-int prom_getintdefault(int node, char *property, int deflt)
+int prom_getintdefault(phandle node, char *property, int deflt)
 {
 	int retval;
 
@@ -152,7 +152,7 @@
 EXPORT_SYMBOL(prom_getintdefault);
 
 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, char *prop)
+int prom_getbool(phandle node, char *prop)
 {
 	int retval;
 
@@ -166,7 +166,7 @@
  * string on error.  The char pointer is the user supplied string
  * buffer.
  */
-void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
 {
 	int len;
 
@@ -180,7 +180,7 @@
 /* Does the device at node 'node' have name 'name'?
  * YES = 1   NO = 0
  */
-int prom_nodematch(int node, char *name)
+int prom_nodematch(phandle node, char *name)
 {
 	int error;
 
@@ -194,10 +194,11 @@
 /* Search siblings at 'node_start' for a node with name
  * 'nodename'.  Return node if successful, zero if not.
  */
-int prom_searchsiblings(int node_start, char *nodename)
+phandle prom_searchsiblings(phandle node_start, char *nodename)
 {
 
-	int thisnode, error;
+	phandle thisnode;
+	int error;
 
 	for(thisnode = node_start; thisnode;
 	    thisnode=prom_getsibling(thisnode)) {
@@ -213,7 +214,7 @@
 EXPORT_SYMBOL(prom_searchsiblings);
 
 /* Interal version of nextprop that does not alter return values. */
-char * __prom_nextprop(int node, char * oprop)
+char *__prom_nextprop(phandle node, char * oprop)
 {
 	unsigned long flags;
 	char *prop;
@@ -228,7 +229,7 @@
 
 /* Return the first property name for node 'node'. */
 /* buffer is unused argument, but as v9 uses it, we need to have the same interface */
-char * prom_firstprop(int node, char *bufer)
+char *prom_firstprop(phandle node, char *bufer)
 {
 	if (node == 0 || node == -1)
 		return "";
@@ -241,7 +242,7 @@
  * at node 'node' .  Returns empty string if no more
  * property types for this node.
  */
-char * prom_nextprop(int node, char *oprop, char *buffer)
+char *prom_nextprop(phandle node, char *oprop, char *buffer)
 {
 	if (node == 0 || node == -1)
 		return "";
@@ -250,11 +251,11 @@
 }
 EXPORT_SYMBOL(prom_nextprop);
 
-int prom_finddevice(char *name)
+phandle prom_finddevice(char *name)
 {
 	char nbuf[128];
 	char *s = name, *d;
-	int node = prom_root_node, node2;
+	phandle node = prom_root_node, node2;
 	unsigned int which_io, phys_addr;
 	struct linux_prom_registers reg[PROMREG_MAX];
 
@@ -298,7 +299,7 @@
 }
 EXPORT_SYMBOL(prom_finddevice);
 
-int prom_node_has_property(int node, char *prop)
+int prom_node_has_property(phandle node, char *prop)
 {
 	char *current_property = "";
 
@@ -314,7 +315,7 @@
 /* Set property 'pname' at node 'node' to value 'value' which has a length
  * of 'size' bytes.  Return the number of bytes the prom accepted.
  */
-int prom_setprop(int node, const char *pname, char *value, int size)
+int prom_setprop(phandle node, const char *pname, char *value, int size)
 {
 	unsigned long flags;
 	int ret;
@@ -329,9 +330,9 @@
 }
 EXPORT_SYMBOL(prom_setprop);
 
-int prom_inst2pkg(int inst)
+phandle prom_inst2pkg(int inst)
 {
-	int node;
+	phandle node;
 	unsigned long flags;
 	
 	spin_lock_irqsave(&prom_lock, flags);
@@ -341,18 +342,3 @@
 	if (node == -1) return 0;
 	return node;
 }
-
-/* Return 'node' assigned to a particular prom 'path'
- * FIXME: Should work for v0 as well
- */
-int prom_pathtoinode(char *path)
-{
-	int node, inst;
-	
-	inst = prom_devopen (path);
-	if (inst == -1) return 0;
-	node = prom_inst2pkg (inst);
-	prom_devclose (inst);
-	if (node == -1) return 0;
-	return node;
-}
diff -druN linux-libre-2.6.36-gnu/arch/sparc/prom/tree_64.c linux-libre-2.6.37-gnu/arch/sparc/prom/tree_64.c
--- linux-libre-2.6.36-gnu/arch/sparc/prom/tree_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/sparc/prom/tree_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 #include <asm/oplib.h>
 #include <asm/ldc.h>
 
-static int prom_node_to_node(const char *type, int node)
+static phandle prom_node_to_node(const char *type, phandle node)
 {
 	unsigned long args[5];
 
@@ -28,20 +28,20 @@
 
 	p1275_cmd_direct(args);
 
-	return (int) args[4];
+	return (phandle) args[4];
 }
 
 /* Return the child of node 'node' or zero if no this node has no
  * direct descendent.
  */
-inline int __prom_getchild(int node)
+inline phandle __prom_getchild(phandle node)
 {
 	return prom_node_to_node("child", node);
 }
 
-inline int prom_getchild(int node)
+inline phandle prom_getchild(phandle node)
 {
-	int cnode;
+	phandle cnode;
 
 	if (node == -1)
 		return 0;
@@ -52,9 +52,9 @@
 }
 EXPORT_SYMBOL(prom_getchild);
 
-inline int prom_getparent(int node)
+inline phandle prom_getparent(phandle node)
 {
-	int cnode;
+	phandle cnode;
 
 	if (node == -1)
 		return 0;
@@ -67,14 +67,14 @@
 /* Return the next sibling of node 'node' or zero if no more siblings
  * at this level of depth in the tree.
  */
-inline int __prom_getsibling(int node)
+inline phandle __prom_getsibling(phandle node)
 {
 	return prom_node_to_node(prom_peer_name, node);
 }
 
-inline int prom_getsibling(int node)
+inline phandle prom_getsibling(phandle node)
 {
-	int sibnode;
+	phandle sibnode;
 
 	if (node == -1)
 		return 0;
@@ -89,7 +89,7 @@
 /* Return the length in bytes of property 'prop' at node 'node'.
  * Return -1 on error.
  */
-inline int prom_getproplen(int node, const char *prop)
+inline int prom_getproplen(phandle node, const char *prop)
 {
 	unsigned long args[6];
 
@@ -113,7 +113,7 @@
  * 'buffer' which has a size of 'bufsize'.  If the acquisition
  * was successful the length will be returned, else -1 is returned.
  */
-inline int prom_getproperty(int node, const char *prop,
+inline int prom_getproperty(phandle node, const char *prop,
 			    char *buffer, int bufsize)
 {
 	unsigned long args[8];
@@ -141,7 +141,7 @@
 /* Acquire an integer property and return its value.  Returns -1
  * on failure.
  */
-inline int prom_getint(int node, const char *prop)
+inline int prom_getint(phandle node, const char *prop)
 {
 	int intprop;
 
@@ -156,7 +156,7 @@
  * integer.
  */
 
-int prom_getintdefault(int node, const char *property, int deflt)
+int prom_getintdefault(phandle node, const char *property, int deflt)
 {
 	int retval;
 
@@ -169,7 +169,7 @@
 EXPORT_SYMBOL(prom_getintdefault);
 
 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
-int prom_getbool(int node, const char *prop)
+int prom_getbool(phandle node, const char *prop)
 {
 	int retval;
 
@@ -184,7 +184,8 @@
  * string on error.  The char pointer is the user supplied string
  * buffer.
  */
-void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size)
+void prom_getstring(phandle node, const char *prop, char *user_buf,
+		int ubuf_size)
 {
 	int len;
 
@@ -198,7 +199,7 @@
 /* Does the device at node 'node' have name 'name'?
  * YES = 1   NO = 0
  */
-int prom_nodematch(int node, const char *name)
+int prom_nodematch(phandle node, const char *name)
 {
 	char namebuf[128];
 	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
@@ -210,10 +211,10 @@
 /* Search siblings at 'node_start' for a node with name
  * 'nodename'.  Return node if successful, zero if not.
  */
-int prom_searchsiblings(int node_start, const char *nodename)
+phandle prom_searchsiblings(phandle node_start, const char *nodename)
 {
-
-	int thisnode, error;
+	phandle thisnode;
+	int error;
 	char promlib_buf[128];
 
 	for(thisnode = node_start; thisnode;
@@ -234,7 +235,7 @@
 /* Return the first property type for node 'node'.
  * buffer should be at least 32B in length
  */
-inline char *prom_firstprop(int node, char *buffer)
+inline char *prom_firstprop(phandle node, char *buffer)
 {
 	unsigned long args[7];
 
@@ -260,7 +261,7 @@
  * at node 'node' .  Returns NULL string if no more
  * property types for this node.
  */
-inline char *prom_nextprop(int node, const char *oprop, char *buffer)
+inline char *prom_nextprop(phandle node, const char *oprop, char *buffer)
 {
 	unsigned long args[7];
 	char buf[32];
@@ -288,8 +289,7 @@
 }
 EXPORT_SYMBOL(prom_nextprop);
 
-int
-prom_finddevice(const char *name)
+phandle prom_finddevice(const char *name)
 {
 	unsigned long args[5];
 
@@ -307,7 +307,7 @@
 }
 EXPORT_SYMBOL(prom_finddevice);
 
-int prom_node_has_property(int node, const char *prop)
+int prom_node_has_property(phandle node, const char *prop)
 {
 	char buf [32];
         
@@ -325,7 +325,7 @@
  * of 'size' bytes.  Return the number of bytes the prom accepted.
  */
 int
-prom_setprop(int node, const char *pname, char *value, int size)
+prom_setprop(phandle node, const char *pname, char *value, int size)
 {
 	unsigned long args[8];
 
@@ -355,10 +355,10 @@
 }
 EXPORT_SYMBOL(prom_setprop);
 
-inline int prom_inst2pkg(int inst)
+inline phandle prom_inst2pkg(int inst)
 {
 	unsigned long args[5];
-	int node;
+	phandle node;
 	
 	args[0] = (unsigned long) "instance-to-package";
 	args[1] = 1;
@@ -372,24 +372,6 @@
 	if (node == -1)
 		return 0;
 	return node;
-}
-
-/* Return 'node' assigned to a particular prom 'path'
- * FIXME: Should work for v0 as well
- */
-int
-prom_pathtoinode(const char *path)
-{
-	int node, inst;
-
-	inst = prom_devopen (path);
-	if (inst == 0)
-		return 0;
-	node = prom_inst2pkg(inst);
-	prom_devclose(inst);
-	if (node == -1)
-		return 0;
-	return node;
 }
 
 int prom_ihandle2path(int handle, char *buffer, int bufsize)
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/arch/sim_def.h linux-libre-2.6.37-gnu/arch/tile/include/arch/sim_def.h
--- linux-libre-2.6.36-gnu/arch/tile/include/arch/sim_def.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/arch/sim_def.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,477 +1,461 @@
-// Copyright 2010 Tilera Corporation. All Rights Reserved.
-//
-//   This program is free software; you can redistribute it and/or
-//   modify it under the terms of the GNU General Public License
-//   as published by the Free Software Foundation, version 2.
-//
-//   This program is distributed in the hope that it will be useful, but
-//   WITHOUT ANY WARRANTY; without even the implied warranty of
-//   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
-//   NON INFRINGEMENT.  See the GNU General Public License for
-//   more details.
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
 
-//! @file
-//!
-//! Some low-level simulator definitions.
-//!
+/**
+ * @file
+ *
+ * Some low-level simulator definitions.
+ */
 
 #ifndef __ARCH_SIM_DEF_H__
 #define __ARCH_SIM_DEF_H__
 
 
-//! Internal: the low bits of the SIM_CONTROL_* SPR values specify
-//! the operation to perform, and the remaining bits are
-//! an operation-specific parameter (often unused).
-//!
+/**
+ * Internal: the low bits of the SIM_CONTROL_* SPR values specify
+ * the operation to perform, and the remaining bits are
+ * an operation-specific parameter (often unused).
+ */
 #define _SIM_CONTROL_OPERATOR_BITS 8
 
 
-//== Values which can be written to SPR_SIM_CONTROL.
+/*
+ * Values which can be written to SPR_SIM_CONTROL.
+ */
 
-//! If written to SPR_SIM_CONTROL, stops profiling.
-//!
+/** If written to SPR_SIM_CONTROL, stops profiling. */
 #define SIM_CONTROL_PROFILER_DISABLE 0
 
-//! If written to SPR_SIM_CONTROL, starts profiling.
-//!
+/** If written to SPR_SIM_CONTROL, starts profiling. */
 #define SIM_CONTROL_PROFILER_ENABLE 1
 
-//! If written to SPR_SIM_CONTROL, clears profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears profiling counters. */
 #define SIM_CONTROL_PROFILER_CLEAR 2
 
-//! If written to SPR_SIM_CONTROL, checkpoints the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, checkpoints the simulator. */
 #define SIM_CONTROL_CHECKPOINT 3
 
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! sets the tracing mask to the given mask. See "sim_set_tracing()".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * sets the tracing mask to the given mask. See "sim_set_tracing()".
+ */
 #define SIM_CONTROL_SET_TRACING 4
 
-//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
-//! dumps the requested items of machine state to the log.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+ * dumps the requested items of machine state to the log.
+ */
 #define SIM_CONTROL_DUMP 5
 
-//! If written to SPR_SIM_CONTROL, clears chip-level profiling counters.
-//!
+/** If written to SPR_SIM_CONTROL, clears chip-level profiling counters. */
 #define SIM_CONTROL_PROFILER_CHIP_CLEAR 6
 
-//! If written to SPR_SIM_CONTROL, disables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level profiling. */
 #define SIM_CONTROL_PROFILER_CHIP_DISABLE 7
 
-//! If written to SPR_SIM_CONTROL, enables chip-level profiling.
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level profiling. */
 #define SIM_CONTROL_PROFILER_CHIP_ENABLE 8
 
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode
-//!
+/** If written to SPR_SIM_CONTROL, enables chip-level functional mode */
 #define SIM_CONTROL_ENABLE_FUNCTIONAL 9
 
-//! If written to SPR_SIM_CONTROL, disables chip-level functional mode.
-//!
+/** If written to SPR_SIM_CONTROL, disables chip-level functional mode. */
 #define SIM_CONTROL_DISABLE_FUNCTIONAL 10
 
-//! If written to SPR_SIM_CONTROL, enables chip-level functional mode.
-//! All tiles must perform this write for functional mode to be enabled.
-//! Ignored in naked boot mode unless --functional is specified.
-//! WARNING: Only the hypervisor startup code should use this!
-//!
+/**
+ * If written to SPR_SIM_CONTROL, enables chip-level functional mode.
+ * All tiles must perform this write for functional mode to be enabled.
+ * Ignored in naked boot mode unless --functional is specified.
+ * WARNING: Only the hypervisor startup code should use this!
+ */
 #define SIM_CONTROL_ENABLE_FUNCTIONAL_BARRIER 11
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! writes a string directly to the simulator output.  Written to once for
-//! each character in the string, plus a final NUL.  Instead of NUL,
-//! you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
-//!
-// ISSUE: Document the meaning of "newline", and the handling of NUL.
-//
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * writes a string directly to the simulator output.  Written to once for
+ * each character in the string, plus a final NUL.  Instead of NUL,
+ * you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
+ */
+/* ISSUE: Document the meaning of "newline", and the handling of NUL. */
 #define SIM_CONTROL_PUTC 12
 
-//! If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
-//! this core.  This is intended to be used before a loop that will
-//! invalidate the cache by loading new data and evicting all current data.
-//! Generally speaking, this API should only be used by system code.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
+ * this core.  This is intended to be used before a loop that will
+ * invalidate the cache by loading new data and evicting all current data.
+ * Generally speaking, this API should only be used by system code.
+ */
 #define SIM_CONTROL_GRINDER_CLEAR 13
 
-//! If written to SPR_SIM_CONTROL, shuts down the simulator.
-//!
+/** If written to SPR_SIM_CONTROL, shuts down the simulator. */
 #define SIM_CONTROL_SHUTDOWN 14
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that a fork syscall just created the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that a fork syscall just created the given process.
+ */
 #define SIM_CONTROL_OS_FORK 15
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that an exit syscall was just executed by the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that an exit syscall was just executed by the given process.
+ */
 #define SIM_CONTROL_OS_EXIT 16
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! indicates that the OS just switched to the given process.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * indicates that the OS just switched to the given process.
+ */
 #define SIM_CONTROL_OS_SWITCH 17
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an exec syscall was just executed. Written to once for
-//! each character in the executable name, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an exec syscall was just executed. Written to once for
+ * each character in the executable name, plus a final NUL.
+ */
 #define SIM_CONTROL_OS_EXEC 18
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that an interpreter (PT_INTERP) was loaded.  Written to once
-//! for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
-//! hex load address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that an interpreter (PT_INTERP) was loaded.  Written to once
+ * for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
+ * hex load address starting with "0x", and "PATH" is the executable name.
+ */
 #define SIM_CONTROL_OS_INTERP 19
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was loaded.  Written to once for each character
-//! in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x", and "PATH" is the executable name.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was loaded.  Written to once for each character
+ * in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x", and "PATH" is the executable name.
+ */
 #define SIM_CONTROL_DLOPEN 20
 
-//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
-//! indicates that a dll was unloaded.  Written to once for each character
-//! in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
-//! address starting with "0x".
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+ * indicates that a dll was unloaded.  Written to once for each character
+ * in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
+ * address starting with "0x".
+ */
 #define SIM_CONTROL_DLCLOSE 21
 
-//! If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
-//! indicates whether to allow data reads to remotely-cached
-//! dirty cache lines to be cached locally without grinder warnings or
-//! assertions (used by Linux kernel fast memcpy).
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
+ * indicates whether to allow data reads to remotely-cached
+ * dirty cache lines to be cached locally without grinder warnings or
+ * assertions (used by Linux kernel fast memcpy).
+ */
 #define SIM_CONTROL_ALLOW_MULTIPLE_CACHING 22
 
-//! If written to SPR_SIM_CONTROL, enables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, enables memory tracing. */
 #define SIM_CONTROL_ENABLE_MEM_LOGGING 23
 
-//! If written to SPR_SIM_CONTROL, disables memory tracing.
-//!
+/** If written to SPR_SIM_CONTROL, disables memory tracing. */
 #define SIM_CONTROL_DISABLE_MEM_LOGGING 24
 
-//! If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
-//! the gbe or xgbe shims. Must specify the shim id, the type, the units, and
-//! the rate, as defined in SIM_SHAPING_SPR_ARG.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
+ * the gbe or xgbe shims. Must specify the shim id, the type, the units, and
+ * the rate, as defined in SIM_SHAPING_SPR_ARG.
+ */
 #define SIM_CONTROL_SHAPING 25
 
-//! If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
-//! requests that a simulator command be executed.  Written to once for each
-//! character in the command, plus a final NUL.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
+ * requests that a simulator command be executed.  Written to once for each
+ * character in the command, plus a final NUL.
+ */
 #define SIM_CONTROL_COMMAND 26
 
-//! If written to SPR_SIM_CONTROL, indicates that the simulated system
-//! is panicking, to allow debugging via --debug-on-panic.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, indicates that the simulated system
+ * is panicking, to allow debugging via --debug-on-panic.
+ */
 #define SIM_CONTROL_PANIC 27
 
-//! If written to SPR_SIM_CONTROL, triggers a simulator syscall.
-//! See "sim_syscall()" for more info.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, triggers a simulator syscall.
+ * See "sim_syscall()" for more info.
+ */
 #define SIM_CONTROL_SYSCALL 32
 
-//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
-//! provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
-//! use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
-//!
+/**
+ * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+ * provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
+ * use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
+ */
 #define SIM_CONTROL_OS_FORK_PARENT 33
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), clears the pending magic data section.  The cleared
-//! pending magic data section and any subsequently appended magic bytes
-//! will only take effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), clears the pending magic data section.  The cleared
+ * pending magic data section and any subsequently appended magic bytes
+ * will only take effect when the classifier blast programmer is run.
+ */
 #define SIM_CONTROL_CLEAR_MPIPE_MAGIC_BYTES 34
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8) and a byte of data (shifted by 16), appends that byte
-//! to the shim's pending magic data section.  The pending magic data
-//! section takes effect when the classifier blast programmer is run.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8) and a byte of data (shifted by 16), appends that byte
+ * to the shim's pending magic data section.  The pending magic data
+ * section takes effect when the classifier blast programmer is run.
+ */
 #define SIM_CONTROL_APPEND_MPIPE_MAGIC_BYTE 35
 
-//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
-//! (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
-//! mask of links (shifted by 32), enable or disable the corresponding
-//! mPIPE links.
+/**
+ * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+ * (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
+ * mask of links (shifted by 32), enable or disable the corresponding
+ * mPIPE links.
+ */
 #define SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE 36
 
-//== Syscall numbers for use with "sim_syscall()".
 
-//! Syscall number for sim_add_watchpoint().
-//!
+/*
+ * Syscall numbers for use with "sim_syscall()".
+ */
+
+/** Syscall number for sim_add_watchpoint(). */
 #define SIM_SYSCALL_ADD_WATCHPOINT 2
 
-//! Syscall number for sim_remove_watchpoint().
-//!
+/** Syscall number for sim_remove_watchpoint(). */
 #define SIM_SYSCALL_REMOVE_WATCHPOINT 3
 
-//! Syscall number for sim_query_watchpoint().
-//!
+/** Syscall number for sim_query_watchpoint(). */
 #define SIM_SYSCALL_QUERY_WATCHPOINT 4
 
-//! Syscall number that asserts that the cache lines whose 64-bit PA
-//! is passed as the second argument to sim_syscall(), and over a
-//! range passed as the third argument, are no longer in cache.
-//! The simulator raises an error if this is not the case.
-//!
+/**
+ * Syscall number that asserts that the cache lines whose 64-bit PA
+ * is passed as the second argument to sim_syscall(), and over a
+ * range passed as the third argument, are no longer in cache.
+ * The simulator raises an error if this is not the case.
+ */
 #define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Enable --trace-cycle when passed to simulator_set_tracing().
-//!
+/** Enable --trace-cycle when passed to simulator_set_tracing(). */
 #define SIM_TRACE_CYCLES          0x01
 
-//! Enable --trace-router when passed to simulator_set_tracing().
-//!
+/** Enable --trace-router when passed to simulator_set_tracing(). */
 #define SIM_TRACE_ROUTER          0x02
 
-//! Enable --trace-register-writes when passed to simulator_set_tracing().
-//!
+/** Enable --trace-register-writes when passed to simulator_set_tracing(). */
 #define SIM_TRACE_REGISTER_WRITES 0x04
 
-//! Enable --trace-disasm when passed to simulator_set_tracing().
-//!
+/** Enable --trace-disasm when passed to simulator_set_tracing(). */
 #define SIM_TRACE_DISASM          0x08
 
-//! Enable --trace-stall-info when passed to simulator_set_tracing().
-//!
+/** Enable --trace-stall-info when passed to simulator_set_tracing(). */
 #define SIM_TRACE_STALL_INFO      0x10
 
-//! Enable --trace-memory-controller when passed to simulator_set_tracing().
-//!
+/** Enable --trace-memory-controller when passed to simulator_set_tracing(). */
 #define SIM_TRACE_MEMORY_CONTROLLER 0x20
 
-//! Enable --trace-l2 when passed to simulator_set_tracing().
-//!
+/** Enable --trace-l2 when passed to simulator_set_tracing(). */
 #define SIM_TRACE_L2_CACHE 0x40
 
-//! Enable --trace-lines when passed to simulator_set_tracing().
-//!
+/** Enable --trace-lines when passed to simulator_set_tracing(). */
 #define SIM_TRACE_LINES 0x80
 
-//! Turn off all tracing when passed to simulator_set_tracing().
-//!
+/** Turn off all tracing when passed to simulator_set_tracing(). */
 #define SIM_TRACE_NONE 0
 
-//! Turn on all tracing when passed to simulator_set_tracing().
-//!
+/** Turn on all tracing when passed to simulator_set_tracing(). */
 #define SIM_TRACE_ALL (-1)
 
-//! @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to set tracing flags.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to set tracing flags. */
 #define SIM_TRACE_SPR_ARG(mask) \
   (SIM_CONTROL_SET_TRACING | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Dump the general-purpose registers.
-//!
+/** Dump the general-purpose registers. */
 #define SIM_DUMP_REGS          0x001
 
-//! Dump the SPRs.
-//!
+/** Dump the SPRs. */
 #define SIM_DUMP_SPRS          0x002
 
-//! Dump the ITLB.
-//!
+/** Dump the ITLB. */
 #define SIM_DUMP_ITLB          0x004
 
-//! Dump the DTLB.
-//!
+/** Dump the DTLB. */
 #define SIM_DUMP_DTLB          0x008
 
-//! Dump the L1 I-cache.
-//!
+/** Dump the L1 I-cache. */
 #define SIM_DUMP_L1I           0x010
 
-//! Dump the L1 D-cache.
-//!
+/** Dump the L1 D-cache. */
 #define SIM_DUMP_L1D           0x020
 
-//! Dump the L2 cache.
-//!
+/** Dump the L2 cache. */
 #define SIM_DUMP_L2            0x040
 
-//! Dump the switch registers.
-//!
+/** Dump the switch registers. */
 #define SIM_DUMP_SNREGS        0x080
 
-//! Dump the switch ITLB.
-//!
+/** Dump the switch ITLB. */
 #define SIM_DUMP_SNITLB        0x100
 
-//! Dump the switch L1 I-cache.
-//!
+/** Dump the switch L1 I-cache. */
 #define SIM_DUMP_SNL1I         0x200
 
-//! Dump the current backtrace.
-//!
+/** Dump the current backtrace. */
 #define SIM_DUMP_BACKTRACE     0x400
 
-//! Only dump valid lines in caches.
-//!
+/** Only dump valid lines in caches. */
 #define SIM_DUMP_VALID_LINES   0x800
 
-//! Dump everything that is dumpable.
-//!
+/** Dump everything that is dumpable. */
 #define SIM_DUMP_ALL (-1 & ~SIM_DUMP_VALID_LINES)
 
-// @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to dump machine state.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to dump machine state. */
 #define SIM_DUMP_SPR_ARG(mask) \
   (SIM_CONTROL_DUMP | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
-//== Bit masks which can be shifted by 8, combined with
-//== SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+/*
+ * Bit masks which can be shifted by 8, combined with
+ * SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+ */
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers. */
 #define SIM_CHIP_MEMCTL        0x001
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface. */
 #define SIM_CHIP_XAUI          0x002
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface. */
 #define SIM_CHIP_PCIE          0x004
 
-//! Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface. */
 #define SIM_CHIP_MPIPE         0x008
 
-//! Reference all chip devices.
-//!
+/** Use with with SIM_PROFILER_CHIP_xxx to control the TRIO interface. */
+#define SIM_CHIP_TRIO          0x010
+
+/** Reference all chip devices. */
 #define SIM_CHIP_ALL (-1)
 
-//! @}
+/** @} */
 
-//! Computes the value to write to SPR_SIM_CONTROL to clear chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to clear chip statistics. */
 #define SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_CLEAR | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.*/
 #define SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_DISABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to enable chip statistics.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to enable chip statistics. */
 #define SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask) \
   (SIM_CONTROL_PROFILER_CHIP_ENABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
 
 
 
-// Shim bitrate controls.
+/* Shim bitrate controls. */
 
-//! The number of bits used to store the shim id.
-//!
+/** The number of bits used to store the shim id. */
 #define SIM_CONTROL_SHAPING_SHIM_ID_BITS 3
 
-//! @addtogroup arch_sim
-//! @{
+/**
+ * @addtogroup arch_sim
+ * @{
+ */
 
-//! Change the gbe 0 bitrate.
-//!
+/** Change the gbe 0 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_0 0x0
 
-//! Change the gbe 1 bitrate.
-//!
+/** Change the gbe 1 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_1 0x1
 
-//! Change the gbe 2 bitrate.
-//!
+/** Change the gbe 2 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_2 0x2
 
-//! Change the gbe 3 bitrate.
-//!
+/** Change the gbe 3 bitrate. */
 #define SIM_CONTROL_SHAPING_GBE_3 0x3
 
-//! Change the xgbe 0 bitrate.
-//!
+/** Change the xgbe 0 bitrate. */
 #define SIM_CONTROL_SHAPING_XGBE_0 0x4
 
-//! Change the xgbe 1 bitrate.
-//!
+/** Change the xgbe 1 bitrate. */
 #define SIM_CONTROL_SHAPING_XGBE_1 0x5
 
-//! The type of shaping to do.
-//!
+/** The type of shaping to do. */
 #define SIM_CONTROL_SHAPING_TYPE_BITS 2
 
-//! Control the multiplier.
-//!
+/** Control the multiplier. */
 #define SIM_CONTROL_SHAPING_MULTIPLIER 0
 
-//! Control the PPS.
-//!
+/** Control the PPS. */
 #define SIM_CONTROL_SHAPING_PPS 1
 
-//! Control the BPS.
-//!
+/** Control the BPS. */
 #define SIM_CONTROL_SHAPING_BPS 2
 
-//! The number of bits for the units for the shaping parameter.
-//!
+/** The number of bits for the units for the shaping parameter. */
 #define SIM_CONTROL_SHAPING_UNITS_BITS 2
 
-//! Provide a number in single units.
-//!
+/** Provide a number in single units. */
 #define SIM_CONTROL_SHAPING_UNITS_SINGLE 0
 
-//! Provide a number in kilo units.
-//!
+/** Provide a number in kilo units. */
 #define SIM_CONTROL_SHAPING_UNITS_KILO 1
 
-//! Provide a number in mega units.
-//!
+/** Provide a number in mega units. */
 #define SIM_CONTROL_SHAPING_UNITS_MEGA 2
 
-//! Provide a number in giga units.
-//!
+/** Provide a number in giga units. */
 #define SIM_CONTROL_SHAPING_UNITS_GIGA 3
 
-// @}
+/** @} */
 
-//! How many bits are available for the rate.
-//!
+/** How many bits are available for the rate. */
 #define SIM_CONTROL_SHAPING_RATE_BITS \
   (32 - (_SIM_CONTROL_OPERATOR_BITS + \
          SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
          SIM_CONTROL_SHAPING_TYPE_BITS + \
          SIM_CONTROL_SHAPING_UNITS_BITS))
 
-//! Computes the value to write to SPR_SIM_CONTROL to change a bitrate.
-//!
+/** Computes the value to write to SPR_SIM_CONTROL to change a bitrate. */
 #define SIM_SHAPING_SPR_ARG(shim, type, units, rate) \
   (SIM_CONTROL_SHAPING | \
    ((shim) | \
@@ -483,30 +467,36 @@
                SIM_CONTROL_SHAPING_UNITS_BITS))) << _SIM_CONTROL_OPERATOR_BITS)
 
 
-//== Values returned when reading SPR_SIM_CONTROL.
-// ISSUE: These names should share a longer common prefix.
+/*
+ * Values returned when reading SPR_SIM_CONTROL.
+ * ISSUE: These names should share a longer common prefix.
+ */
 
-//! When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
-//! (SIM_TRACE_xxx values).
-//!
+/**
+ * When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
+ * (SIM_TRACE_xxx values).
+ */
 #define SIM_TRACE_FLAG_MASK 0xFFFF
 
-//! When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled.
-//!
+/** When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled. */
 #define SIM_PROFILER_ENABLED_MASK 0x10000
 
 
-//== Special arguments for "SIM_CONTROL_PUTC".
+/*
+ * Special arguments for "SIM_CONTROL_PUTC".
+ */
 
-//! Flag value for forcing a PUTC string-flush, including
-//! coordinate/cycle prefix and newline.
-//!
+/**
+ * Flag value for forcing a PUTC string-flush, including
+ * coordinate/cycle prefix and newline.
+ */
 #define SIM_PUTC_FLUSH_STRING 0x100
 
-//! Flag value for forcing a PUTC binary-data-flush, which skips the
-//! prefix and does not append a newline.
-//!
+/**
+ * Flag value for forcing a PUTC binary-data-flush, which skips the
+ * prefix and does not append a newline.
+ */
 #define SIM_PUTC_FLUSH_BINARY 0x101
 
 
-#endif //__ARCH_SIM_DEF_H__
+#endif /* __ARCH_SIM_DEF_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/arch/sim.h linux-libre-2.6.37-gnu/arch/tile/include/arch/sim.h
--- linux-libre-2.6.36-gnu/arch/tile/include/arch/sim.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/include/arch/sim.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file
+ *
+ * Provides an API for controlling the simulator at runtime.
+ */
+
+/**
+ * @addtogroup arch_sim
+ * @{
+ *
+ * An API for controlling the simulator at runtime.
+ *
+ * The simulator's behavior can be modified while it is running.
+ * For example, human-readable trace output can be enabled and disabled
+ * around code of interest.
+ *
+ * There are two ways to modify simulator behavior:
+ * programmatically, by calling various sim_* functions, and
+ * interactively, by entering commands like "sim set functional true"
+ * at the tile-monitor prompt.  Typing "sim help" at that prompt provides
+ * a list of interactive commands.
+ *
+ * All interactive commands can also be executed programmatically by
+ * passing a string to the sim_command function.
+ */
+
+#ifndef __ARCH_SIM_H__
+#define __ARCH_SIM_H__
+
+#include <arch/sim_def.h>
+#include <arch/abi.h>
+
+#ifndef __ASSEMBLER__
+
+#include <arch/spr_def.h>
+
+
+/**
+ * Return true if the current program is running under a simulator,
+ * rather than on real hardware.  If running on hardware, other "sim_xxx()"
+ * calls have no useful effect.
+ */
+static inline int
+sim_is_simulator(void)
+{
+  return __insn_mfspr(SPR_SIM_CONTROL) != 0;
+}
+
+
+/**
+ * Checkpoint the simulator state to a checkpoint file.
+ *
+ * The checkpoint file name is either the default or the name specified
+ * on the command line with "--checkpoint-file".
+ */
+static __inline void
+sim_checkpoint(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT);
+}
+
+
+/**
+ * Report whether or not various kinds of simulator tracing are enabled.
+ *
+ * @return The bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline unsigned int
+sim_get_tracing(void)
+{
+  return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK;
+}
+
+
+/**
+ * Turn on or off different kinds of simulator tracing.
+ *
+ * @param mask Either one of these special values:
+ *
+ * SIM_TRACE_NONE (turns off tracing),
+ * SIM_TRACE_ALL (turns on all possible tracing).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_TRACE_CYCLES (--trace-cycles),
+ * SIM_TRACE_ROUTER (--trace-router),
+ * SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
+ * SIM_TRACE_DISASM (--trace-disasm),
+ * SIM_TRACE_STALL_INFO (--trace-stall-info)
+ * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
+ * SIM_TRACE_L2_CACHE (--trace-l2)
+ * SIM_TRACE_LINES (--trace-lines)
+ */
+static __inline void
+sim_set_tracing(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask));
+}
+
+
+/**
+ * Request dumping of different kinds of simulator state.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_DUMP_ALL (dump all known state)
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_DUMP_REGS (the register file),
+ * SIM_DUMP_SPRS (the SPRs),
+ * SIM_DUMP_ITLB (the iTLB),
+ * SIM_DUMP_DTLB (the dTLB),
+ * SIM_DUMP_L1I (the L1 I-cache),
+ * SIM_DUMP_L1D (the L1 D-cache),
+ * SIM_DUMP_L2 (the L2 cache),
+ * SIM_DUMP_SNREGS (the switch register file),
+ * SIM_DUMP_SNITLB (the switch iTLB),
+ * SIM_DUMP_SNL1I (the switch L1 I-cache),
+ * SIM_DUMP_BACKTRACE (the current backtrace)
+ */
+static __inline void
+sim_dump(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask));
+}
+
+
+/**
+ * Print a string to the simulator stdout.
+ *
+ * @param str The string to be written; a newline is automatically added.
+ */
+static __inline void
+sim_print_string(const char* str)
+{
+  int i;
+  for (i = 0; str[i] != 0; i++)
+  {
+    __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+                 (str[i] << _SIM_CONTROL_OPERATOR_BITS));
+  }
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
+               (SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS));
+}
+
+
+/**
+ * Execute a simulator command string.
+ *
+ * Type 'sim help' at the tile-monitor prompt to learn what commands
+ * are available.  Note the use of the tile-monitor "sim" command to
+ * pass commands to the simulator.
+ *
+ * The argument to sim_command() does not include the leading "sim"
+ * prefix used at the tile-monitor prompt; for example, you might call
+ * sim_command("trace disasm").
+ */
+static __inline void
+sim_command(const char* str)
+{
+  int c;
+  do
+  {
+    c = *str++;
+    __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND |
+                 (c << _SIM_CONTROL_OPERATOR_BITS));
+  }
+  while (c);
+}
+
+
+
+#ifndef __DOXYGEN__
+
+/**
+ * The underlying implementation of "_sim_syscall()".
+ *
+ * We use extra "and" instructions to ensure that all the values
+ * we are passing to the simulator are actually valid in the registers
+ * (i.e. returned from memory) prior to the SIM_CONTROL spr.
+ */
+static __inline int _sim_syscall0(int val)
+{
+  long result;
+  __asm__ __volatile__ ("mtspr SIM_CONTROL, r0"
+                        : "=R00" (result) : "R00" (val));
+  return result;
+}
+
+static __inline int _sim_syscall1(int val, long arg1)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result) : "R00" (val), "R01" (arg1));
+  return result;
+}
+
+static __inline int _sim_syscall2(int val, long arg1, long arg2)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2));
+  return result;
+}
+
+/* Note that _sim_syscall3() and higher are technically at risk of
+   receiving an interrupt right before the mtspr bundle, in which case
+   the register values for arguments 3 and up may still be in flight
+   to the core from a stack frame reload. */
+
+static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r3 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3));
+  return result;
+}
+
+static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
+                                  long arg4)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r4 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3), "R04" (arg4));
+  return result;
+}
+
+static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
+                                  long arg4, long arg5)
+{
+  long result;
+  __asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };"
+                        "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (result)
+                        : "R00" (val), "R01" (arg1), "R02" (arg2),
+                          "R03" (arg3), "R04" (arg4), "R05" (arg5));
+  return result;
+}
+
+
+/**
+ * Make a special syscall to the simulator itself, if running under
+ * simulation. This is used as the implementation of other functions
+ * and should not be used outside this file.
+ *
+ * @param syscall_num The simulator syscall number.
+ * @param nr The number of additional arguments provided.
+ *
+ * @return Varies by syscall.
+ */
+#define _sim_syscall(syscall_num, nr, args...) \
+  _sim_syscall##nr( \
+    ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, args)
+
+
+/* Values for the "access_mask" parameters below. */
+#define SIM_WATCHPOINT_READ    1
+#define SIM_WATCHPOINT_WRITE   2
+#define SIM_WATCHPOINT_EXECUTE 4
+
+
+static __inline int
+sim_add_watchpoint(unsigned int process_id,
+                   unsigned long address,
+                   unsigned long size,
+                   unsigned int access_mask,
+                   unsigned long user_data)
+{
+  return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id,
+                     address, size, access_mask, user_data);
+}
+
+
+static __inline int
+sim_remove_watchpoint(unsigned int process_id,
+                      unsigned long address,
+                      unsigned long size,
+                      unsigned int access_mask,
+                      unsigned long user_data)
+{
+  return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id,
+                     address, size, access_mask, user_data);
+}
+
+
+/**
+ * Return value from sim_query_watchpoint.
+ */
+struct SimQueryWatchpointStatus
+{
+  /**
+   * 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for
+   * error (meaning a bad process_id).
+   */
+  int syscall_status;
+
+  /**
+   * The address of the watchpoint that fired (this is the address
+   * passed to sim_add_watchpoint, not an address within that range
+   * that actually triggered the watchpoint).
+   */
+  unsigned long address;
+
+  /** The arbitrary user_data installed by sim_add_watchpoint. */
+  unsigned long user_data;
+};
+
+
+static __inline struct SimQueryWatchpointStatus
+sim_query_watchpoint(unsigned int process_id)
+{
+  struct SimQueryWatchpointStatus status;
+  long val = SIM_CONTROL_SYSCALL |
+    (SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS);
+  __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
+                        : "=R00" (status.syscall_status),
+                          "=R01" (status.address),
+                          "=R02" (status.user_data)
+                        : "R00" (val), "R01" (process_id));
+  return status;
+}
+
+
+/* On the simulator, confirm lines have been evicted everywhere. */
+static __inline void
+sim_validate_lines_evicted(unsigned long long pa, unsigned long length)
+{
+#ifdef __LP64__
+  _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length);
+#else
+  _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4,
+               0 /* dummy */, (long)(pa), (long)(pa >> 32), length);
+#endif
+}
+
+
+#endif /* !__DOXYGEN__ */
+
+
+
+
+/**
+ * Modify the shaping parameters of a shim.
+ *
+ * @param shim The shim to modify. One of:
+ *   SIM_CONTROL_SHAPING_GBE_0
+ *   SIM_CONTROL_SHAPING_GBE_1
+ *   SIM_CONTROL_SHAPING_GBE_2
+ *   SIM_CONTROL_SHAPING_GBE_3
+ *   SIM_CONTROL_SHAPING_XGBE_0
+ *   SIM_CONTROL_SHAPING_XGBE_1
+ *
+ * @param type The type of shaping. This should be the same type of
+ * shaping that is already in place on the shim. One of:
+ *   SIM_CONTROL_SHAPING_MULTIPLIER
+ *   SIM_CONTROL_SHAPING_PPS
+ *   SIM_CONTROL_SHAPING_BPS
+ *
+ * @param units The magnitude of the rate. One of:
+ *   SIM_CONTROL_SHAPING_UNITS_SINGLE
+ *   SIM_CONTROL_SHAPING_UNITS_KILO
+ *   SIM_CONTROL_SHAPING_UNITS_MEGA
+ *   SIM_CONTROL_SHAPING_UNITS_GIGA
+ *
+ * @param rate The rate to which to change it. This must fit in
+ * SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and
+ * the shaping is not changed.
+ *
+ * @return 0 if no problems were detected in the arguments to sim_set_shaping
+ * or 1 if problems were detected (for example, rate does not fit in 17 bits).
+ */
+static __inline int
+sim_set_shaping(unsigned shim,
+                unsigned type,
+                unsigned units,
+                unsigned rate)
+{
+  if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0)
+    return 1;
+
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate));
+  return 0;
+}
+
+#ifdef __tilegx__
+
+/** Enable a set of mPIPE links.  Pass a -1 link_mask to enable all links. */
+static __inline void
+sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL,
+               (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+                (mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+/** Disable a set of mPIPE links.  Pass a -1 link_mask to disable all links. */
+static __inline void
+sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL,
+               (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
+                (mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32)));
+}
+
+#endif /* __tilegx__ */
+
+
+/*
+ * An API for changing "functional" mode.
+ */
+
+#ifndef __DOXYGEN__
+
+#define sim_enable_functional() \
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL)
+
+#define sim_disable_functional() \
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL)
+
+#endif /* __DOXYGEN__ */
+
+
+/*
+ * Profiler support.
+ */
+
+/**
+ * Turn profiling on for the current task.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_enable(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE);
+}
+
+
+/** Turn profiling off for the current task. */
+static __inline void
+sim_profiler_disable(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE);
+}
+
+
+/**
+ * Turn profiling on or off for the current task.
+ *
+ * @param enabled If true, turns on profiling. If false, turns it off.
+ *
+ * Note that this has no effect if run in an environment without
+ * profiling support (thus, the proper flags to the simulator must
+ * be supplied).
+ */
+static __inline void
+sim_profiler_set_enabled(int enabled)
+{
+  int val =
+    enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE;
+  __insn_mtspr(SPR_SIM_CONTROL, val);
+}
+
+
+/**
+ * Return true if and only if profiling is currently enabled
+ * for the current task.
+ *
+ * This returns false even if sim_profiler_enable() was called
+ * if the current execution environment does not support profiling.
+ */
+static __inline int
+sim_profiler_is_enabled(void)
+{
+  return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0);
+}
+
+
+/**
+ * Reset profiling counters to zero for the current task.
+ *
+ * Resetting can be done while profiling is enabled.  It does not affect
+ * the chip-wide profiling counters.
+ */
+static __inline void
+sim_profiler_clear(void)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR);
+}
+
+
+/**
+ * Enable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (enables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (enable all memory controllers)
+ * SIM_CHIP_XAUI (enable all XAUI controllers)
+ * SIM_CHIP_MPIPE (enable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_enable(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Disable specified chip-level profiling counters.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (disables all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (disable all memory controllers)
+ * SIM_CHIP_XAUI (disable all XAUI controllers)
+ * SIM_CHIP_MPIPE (disable all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_disable(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask));
+}
+
+
+/**
+ * Reset specified chip-level profiling counters to zero.
+ *
+ * Does not affect the per-task profiling counters.
+ *
+ * @param mask Either this special value:
+ *
+ * SIM_CHIP_ALL (clears all chip-level components).
+ *
+ * or the bitwise OR of these values:
+ *
+ * SIM_CHIP_MEMCTL (clear all memory controllers)
+ * SIM_CHIP_XAUI (clear all XAUI controllers)
+ * SIM_CHIP_MPIPE (clear all MPIPE controllers)
+ */
+static __inline void
+sim_profiler_chip_clear(unsigned int mask)
+{
+  __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask));
+}
+
+
+/*
+ * Event support.
+ */
+
+#ifndef __DOXYGEN__
+
+static __inline void
+sim_event_begin(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+  __insn_mtspr(SPR_EVENT_BEGIN, x);
+#endif
+}
+
+static __inline void
+sim_event_end(unsigned int x)
+{
+#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
+  __insn_mtspr(SPR_EVENT_END, x);
+#endif
+}
+
+#endif /* !__DOXYGEN__ */
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* !__ARCH_SIM_H__ */
+
+/** @} */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/arch/spr_def_32.h linux-libre-2.6.37-gnu/arch/tile/include/arch/spr_def_32.h
--- linux-libre-2.6.36-gnu/arch/tile/include/arch/spr_def_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/arch/spr_def_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -56,58 +56,93 @@
 #define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
 #define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
 #define SPR_EX_CONTEXT_1_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_2_0 0x4605
+#define SPR_EX_CONTEXT_2_1 0x4606
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
 #define SPR_FAIL 0x4e09
 #define SPR_INTCTRL_0_STATUS 0x4a07
 #define SPR_INTCTRL_1_STATUS 0x4807
+#define SPR_INTCTRL_2_STATUS 0x4607
 #define SPR_INTERRUPT_CRITICAL_SECTION 0x4e0a
 #define SPR_INTERRUPT_MASK_0_0 0x4a08
 #define SPR_INTERRUPT_MASK_0_1 0x4a09
 #define SPR_INTERRUPT_MASK_1_0 0x4809
 #define SPR_INTERRUPT_MASK_1_1 0x480a
+#define SPR_INTERRUPT_MASK_2_0 0x4608
+#define SPR_INTERRUPT_MASK_2_1 0x4609
 #define SPR_INTERRUPT_MASK_RESET_0_0 0x4a0a
 #define SPR_INTERRUPT_MASK_RESET_0_1 0x4a0b
 #define SPR_INTERRUPT_MASK_RESET_1_0 0x480b
 #define SPR_INTERRUPT_MASK_RESET_1_1 0x480c
+#define SPR_INTERRUPT_MASK_RESET_2_0 0x460a
+#define SPR_INTERRUPT_MASK_RESET_2_1 0x460b
 #define SPR_INTERRUPT_MASK_SET_0_0 0x4a0c
 #define SPR_INTERRUPT_MASK_SET_0_1 0x4a0d
 #define SPR_INTERRUPT_MASK_SET_1_0 0x480d
 #define SPR_INTERRUPT_MASK_SET_1_1 0x480e
+#define SPR_INTERRUPT_MASK_SET_2_0 0x460c
+#define SPR_INTERRUPT_MASK_SET_2_1 0x460d
 #define SPR_MPL_DMA_CPL_SET_0 0x5800
 #define SPR_MPL_DMA_CPL_SET_1 0x5801
+#define SPR_MPL_DMA_CPL_SET_2 0x5802
 #define SPR_MPL_DMA_NOTIFY_SET_0 0x3800
 #define SPR_MPL_DMA_NOTIFY_SET_1 0x3801
+#define SPR_MPL_DMA_NOTIFY_SET_2 0x3802
 #define SPR_MPL_INTCTRL_0_SET_0 0x4a00
 #define SPR_MPL_INTCTRL_0_SET_1 0x4a01
+#define SPR_MPL_INTCTRL_0_SET_2 0x4a02
 #define SPR_MPL_INTCTRL_1_SET_0 0x4800
 #define SPR_MPL_INTCTRL_1_SET_1 0x4801
+#define SPR_MPL_INTCTRL_1_SET_2 0x4802
+#define SPR_MPL_INTCTRL_2_SET_0 0x4600
+#define SPR_MPL_INTCTRL_2_SET_1 0x4601
+#define SPR_MPL_INTCTRL_2_SET_2 0x4602
 #define SPR_MPL_SN_ACCESS_SET_0 0x0800
 #define SPR_MPL_SN_ACCESS_SET_1 0x0801
+#define SPR_MPL_SN_ACCESS_SET_2 0x0802
 #define SPR_MPL_SN_CPL_SET_0 0x5a00
 #define SPR_MPL_SN_CPL_SET_1 0x5a01
+#define SPR_MPL_SN_CPL_SET_2 0x5a02
 #define SPR_MPL_SN_FIREWALL_SET_0 0x2c00
 #define SPR_MPL_SN_FIREWALL_SET_1 0x2c01
+#define SPR_MPL_SN_FIREWALL_SET_2 0x2c02
 #define SPR_MPL_SN_NOTIFY_SET_0 0x2a00
 #define SPR_MPL_SN_NOTIFY_SET_1 0x2a01
+#define SPR_MPL_SN_NOTIFY_SET_2 0x2a02
 #define SPR_MPL_UDN_ACCESS_SET_0 0x0c00
 #define SPR_MPL_UDN_ACCESS_SET_1 0x0c01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0c02
 #define SPR_MPL_UDN_AVAIL_SET_0 0x4000
 #define SPR_MPL_UDN_AVAIL_SET_1 0x4001
+#define SPR_MPL_UDN_AVAIL_SET_2 0x4002
 #define SPR_MPL_UDN_CA_SET_0 0x3c00
 #define SPR_MPL_UDN_CA_SET_1 0x3c01
+#define SPR_MPL_UDN_CA_SET_2 0x3c02
 #define SPR_MPL_UDN_COMPLETE_SET_0 0x1400
 #define SPR_MPL_UDN_COMPLETE_SET_1 0x1401
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x1402
 #define SPR_MPL_UDN_FIREWALL_SET_0 0x3000
 #define SPR_MPL_UDN_FIREWALL_SET_1 0x3001
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x3002
 #define SPR_MPL_UDN_REFILL_SET_0 0x1000
 #define SPR_MPL_UDN_REFILL_SET_1 0x1001
+#define SPR_MPL_UDN_REFILL_SET_2 0x1002
 #define SPR_MPL_UDN_TIMER_SET_0 0x3600
 #define SPR_MPL_UDN_TIMER_SET_1 0x3601
+#define SPR_MPL_UDN_TIMER_SET_2 0x3602
 #define SPR_MPL_WORLD_ACCESS_SET_0 0x4e00
 #define SPR_MPL_WORLD_ACCESS_SET_1 0x4e01
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x4e02
 #define SPR_PASS 0x4e0b
 #define SPR_PERF_COUNT_0 0x4205
 #define SPR_PERF_COUNT_1 0x4206
 #define SPR_PERF_COUNT_CTL 0x4207
+#define SPR_PERF_COUNT_DN_CTL 0x4210
 #define SPR_PERF_COUNT_STS 0x4208
 #define SPR_PROC_STATUS 0x4f00
 #define SPR_SIM_CONTROL 0x4e0c
@@ -124,6 +159,10 @@
 #define SPR_SYSTEM_SAVE_1_1 0x4901
 #define SPR_SYSTEM_SAVE_1_2 0x4902
 #define SPR_SYSTEM_SAVE_1_3 0x4903
+#define SPR_SYSTEM_SAVE_2_0 0x4700
+#define SPR_SYSTEM_SAVE_2_1 0x4701
+#define SPR_SYSTEM_SAVE_2_2 0x4702
+#define SPR_SYSTEM_SAVE_2_3 0x4703
 #define SPR_TILE_COORD 0x4c17
 #define SPR_TILE_RTF_HWM 0x4e10
 #define SPR_TILE_TIMER_CONTROL 0x3205
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/arch/spr_def.h linux-libre-2.6.37-gnu/arch/tile/include/arch/spr_def.h
--- linux-libre-2.6.36-gnu/arch/tile/include/arch/spr_def.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/arch/spr_def.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,8 +12,93 @@
  *   more details.
  */
 
+/*
+ * In addition to including the proper base SPR definition file, depending
+ * on machine architecture, this file defines several macros which allow
+ * kernel code to use protection-level dependent SPRs without worrying
+ * about which PL it's running at.  In these macros, the PL that the SPR
+ * or interrupt number applies to is replaced by K.
+ */
+
+#if CONFIG_KERNEL_PL != 1 && CONFIG_KERNEL_PL != 2
+#error CONFIG_KERNEL_PL must be 1 or 2
+#endif
+
+/* Concatenate 4 strings. */
+#define __concat4(a, b, c, d) a ## b ## c ## d
+#define _concat4(a, b, c, d)  __concat4(a, b, c, d)
+
 #ifdef __tilegx__
 #include <arch/spr_def_64.h>
+
+/* TILE-Gx dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K \
+	_concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_SET_K \
+	_concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_MASK_RESET_K \
+	_concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_INTERRUPT_VECTOR_BASE_K \
+	_concat4(SPR_INTERRUPT_VECTOR_BASE_, CONFIG_KERNEL_PL,,)
+
+#define SPR_IPI_MASK_K \
+	_concat4(SPR_IPI_MASK_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_RESET_K \
+	_concat4(SPR_IPI_MASK_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+	_concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_K \
+	_concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_EVENT_RESET_K \
+	_concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,)
+#define SPR_IPI_MASK_SET_K \
+	_concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,)
+#define INT_IPI_K \
+	_concat4(INT_IPI_, CONFIG_KERNEL_PL,,)
+
+#define SPR_SINGLE_STEP_CONTROL_K \
+	_concat4(SPR_SINGLE_STEP_CONTROL_, CONFIG_KERNEL_PL,,)
+#define SPR_SINGLE_STEP_EN_K_K \
+	_concat4(SPR_SINGLE_STEP_EN_, CONFIG_KERNEL_PL, _, CONFIG_KERNEL_PL)
+#define INT_SINGLE_STEP_K \
+	_concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
+
 #else
 #include <arch/spr_def_32.h>
+
+/* TILEPro dependent, protection-level dependent SPRs. */
+
+#define SPR_INTERRUPT_MASK_K_0 \
+	_concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_K_1 \
+	_concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_SET_K_0 \
+	_concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_SET_K_1 \
+	_concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTERRUPT_MASK_RESET_K_0 \
+	_concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _0,)
+#define SPR_INTERRUPT_MASK_RESET_K_1 \
+	_concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _1,)
+
 #endif
+
+/* Generic protection-level dependent SPRs. */
+
+#define SPR_SYSTEM_SAVE_K_0 \
+	_concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _0,)
+#define SPR_SYSTEM_SAVE_K_1 \
+	_concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _1,)
+#define SPR_SYSTEM_SAVE_K_2 \
+	_concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _2,)
+#define SPR_SYSTEM_SAVE_K_3 \
+	_concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _3,)
+#define SPR_EX_CONTEXT_K_0 \
+	_concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _0,)
+#define SPR_EX_CONTEXT_K_1 \
+	_concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _1,)
+#define SPR_INTCTRL_K_STATUS \
+	_concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
+#define INT_INTCTRL_K \
+	_concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/backtrace.h linux-libre-2.6.37-gnu/arch/tile/include/asm/backtrace.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/backtrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/backtrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -146,7 +146,10 @@
 
 	CALLER_SP_IN_R52_BASE = 4,
 
-	CALLER_SP_OFFSET_BASE = 8
+	CALLER_SP_OFFSET_BASE = 8,
+
+	/* Marks the entry point of certain functions. */
+	ENTRY_POINT_INFO_OP = 16
 };
 
 
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/bitops.h linux-libre-2.6.37-gnu/arch/tile/include/asm/bitops.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/bitops.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/bitops.h	2011-01-04 19:50:19.000000000 -0500
@@ -120,6 +120,7 @@
 
 #include <asm-generic/bitops/const_hweight.h>
 #include <asm-generic/bitops/lock.h>
+#include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/sched.h>
 #include <asm-generic/bitops/ext2-non-atomic.h>
 #include <asm-generic/bitops/minix.h>
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/cacheflush.h linux-libre-2.6.37-gnu/arch/tile/include/asm/cacheflush.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/cacheflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/cacheflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -137,4 +137,56 @@
 	mb_incoherent();
 }
 
+/*
+ * Flush & invalidate a VA range that is homed remotely on a single core,
+ * waiting until the memory controller holds the flushed values.
+ */
+static inline void finv_buffer_remote(void *buffer, size_t size)
+{
+	char *p;
+	int i;
+
+	/*
+	 * Flush and invalidate the buffer out of the local L1/L2
+	 * and request the home cache to flush and invalidate as well.
+	 */
+	__finv_buffer(buffer, size);
+
+	/*
+	 * Wait for the home cache to acknowledge that it has processed
+	 * all the flush-and-invalidate requests.  This does not mean
+	 * that the flushed data has reached the memory controller yet,
+	 * but it does mean the home cache is processing the flushes.
+	 */
+	__insn_mf();
+
+	/*
+	 * Issue a load to the last cache line, which can't complete
+	 * until all the previously-issued flushes to the same memory
+	 * controller have also completed.  If we weren't striping
+	 * memory, that one load would be sufficient, but since we may
+	 * be, we also need to back up to the last load issued to
+	 * another memory controller, which would be the point where
+	 * we crossed an 8KB boundary (the granularity of striping
+	 * across memory controllers).  Keep backing up and doing this
+	 * until we are before the beginning of the buffer, or have
+	 * hit all the controllers.
+	 */
+	for (i = 0, p = (char *)buffer + size - 1;
+	     i < (1 << CHIP_LOG_NUM_MSHIMS()) && p >= (char *)buffer;
+	     ++i) {
+		const unsigned long STRIPE_WIDTH = 8192;
+
+		/* Force a load instruction to issue. */
+		*(volatile char *)p;
+
+		/* Jump to end of previous stripe. */
+		p -= STRIPE_WIDTH;
+		p = (char *)((unsigned long)p | (STRIPE_WIDTH - 1));
+	}
+
+	/* Wait for the loads (and thus flushes) to have completed. */
+	__insn_mf();
+}
+
 #endif /* _ASM_TILE_CACHEFLUSH_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/compat.h linux-libre-2.6.37-gnu/arch/tile/include/asm/compat.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/compat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/compat.h	2011-01-04 19:50:19.000000000 -0500
@@ -216,15 +216,16 @@
 struct compat_sigaltstack;
 long compat_sys_execve(const char __user *path,
 		       const compat_uptr_t __user *argv,
-		       const compat_uptr_t __user *envp);
+		       const compat_uptr_t __user *envp, struct pt_regs *);
 long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
 			     struct compat_sigaction __user *oact,
 			     size_t sigsetsize);
 long compat_sys_rt_sigqueueinfo(int pid, int sig,
 				struct compat_siginfo __user *uinfo);
-long compat_sys_rt_sigreturn(void);
+long compat_sys_rt_sigreturn(struct pt_regs *);
 long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-			    struct compat_sigaltstack __user *uoss_ptr);
+			    struct compat_sigaltstack __user *uoss_ptr,
+			    struct pt_regs *);
 long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
 long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
 long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
@@ -255,4 +256,12 @@
 /* Tilera Linux syscalls that don't have "compat" versions. */
 #define compat_sys_flush_cache sys_flush_cache
 
+/* These are the intvec_64.S trampolines. */
+long _compat_sys_execve(const char __user *path,
+			const compat_uptr_t __user *argv,
+			const compat_uptr_t __user *envp);
+long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+			    struct compat_sigaltstack __user *uoss_ptr);
+long _compat_sys_rt_sigreturn(void);
+
 #endif /* _ASM_TILE_COMPAT_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/tile/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/threads.h>
-#include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/homecache.h>
 
@@ -60,12 +59,12 @@
 /* This macro is used only in map_new_virtual() to map "page". */
 #define kmap_prot page_to_kpgprot(page)
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
 void kmap_atomic_fix_kpte(struct page *page, int finished);
 
 #define flush_cache_kmaps()	do { } while (0)
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/io.h linux-libre-2.6.37-gnu/arch/tile/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,9 +55,6 @@
 #define ioremap_writethrough(physaddr, size)	ioremap(physaddr, size)
 #define ioremap_fullcache(physaddr, size)	ioremap(physaddr, size)
 
-void __iomem *ioport_map(unsigned long port, unsigned int len);
-extern inline void ioport_unmap(void __iomem *addr) {}
-
 #define mmiowb()
 
 /* Conversion between virtual and physical mappings.  */
@@ -189,12 +186,22 @@
  * we never run, uses them unconditionally.
  */
 
-static inline int ioport_panic(void)
+static inline long ioport_panic(void)
 {
 	panic("inb/outb and friends do not exist on tile");
 	return 0;
 }
 
+static inline void __iomem *ioport_map(unsigned long port, unsigned int len)
+{
+	return (void __iomem *) ioport_panic();
+}
+
+static inline void ioport_unmap(void __iomem *addr)
+{
+	ioport_panic();
+}
+
 static inline u8 inb(unsigned long addr)
 {
 	return ioport_panic();
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/tile/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,53 +47,53 @@
 	int __n = (n); \
 	int __mask = 1 << (__n & 0x1f); \
 	if (__n < 32) \
-		__insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, __mask); \
+		__insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, __mask); \
 	else \
-		__insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, __mask); \
+		__insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, __mask); \
 } while (0)
 #define interrupt_mask_reset(n) do { \
 	int __n = (n); \
 	int __mask = 1 << (__n & 0x1f); \
 	if (__n < 32) \
-		__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, __mask); \
+		__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, __mask); \
 	else \
-		__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, __mask); \
+		__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, __mask); \
 } while (0)
 #define interrupt_mask_check(n) ({ \
 	int __n = (n); \
 	(((__n < 32) ? \
-	 __insn_mfspr(SPR_INTERRUPT_MASK_1_0) : \
-	 __insn_mfspr(SPR_INTERRUPT_MASK_1_1)) \
+	 __insn_mfspr(SPR_INTERRUPT_MASK_K_0) : \
+	 __insn_mfspr(SPR_INTERRUPT_MASK_K_1)) \
 	  >> (__n & 0x1f)) & 1; \
 })
 #define interrupt_mask_set_mask(mask) do { \
 	unsigned long long __m = (mask); \
-	__insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, (unsigned long)(__m)); \
-	__insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, (unsigned long)(__m>>32)); \
+	__insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, (unsigned long)(__m)); \
+	__insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, (unsigned long)(__m>>32)); \
 } while (0)
 #define interrupt_mask_reset_mask(mask) do { \
 	unsigned long long __m = (mask); \
-	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, (unsigned long)(__m)); \
-	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, (unsigned long)(__m>>32)); \
+	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \
+	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m>>32)); \
 } while (0)
 #else
 #define interrupt_mask_set(n) \
-	__insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (1UL << (n)))
+	__insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL << (n)))
 #define interrupt_mask_reset(n) \
-	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (1UL << (n)))
+	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (1UL << (n)))
 #define interrupt_mask_check(n) \
-	((__insn_mfspr(SPR_INTERRUPT_MASK_1) >> (n)) & 1)
+	((__insn_mfspr(SPR_INTERRUPT_MASK_K) >> (n)) & 1)
 #define interrupt_mask_set_mask(mask) \
-	__insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (mask))
+	__insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask))
 #define interrupt_mask_reset_mask(mask) \
-	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (mask))
+	__insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask))
 #endif
 
 /*
  * The set of interrupts we want active if irqs are enabled.
  * Note that in particular, the tile timer interrupt comes and goes
  * from this set, since we have no other way to turn off the timer.
- * Likewise, INTCTRL_1 is removed and re-added during device
+ * Likewise, INTCTRL_K is removed and re-added during device
  * interrupts, as is the the hardwall UDN_FIREWALL interrupt.
  * We use a low bit (MEM_ERROR) as our sentinel value and make sure it
  * is always claimed as an "active interrupt" so we can query that bit
@@ -103,55 +103,57 @@
 #define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
 
 /* Disable interrupts. */
-#define raw_local_irq_disable() \
+#define arch_local_irq_disable() \
 	interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS)
 
 /* Disable all interrupts, including NMIs. */
-#define raw_local_irq_disable_all() \
+#define arch_local_irq_disable_all() \
 	interrupt_mask_set_mask(-1UL)
 
 /* Re-enable all maskable interrupts. */
-#define raw_local_irq_enable() \
+#define arch_local_irq_enable() \
 	interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask))
 
 /* Disable or enable interrupts based on flag argument. */
-#define raw_local_irq_restore(disabled) do { \
+#define arch_local_irq_restore(disabled) do { \
 	if (disabled) \
-		raw_local_irq_disable(); \
+		arch_local_irq_disable(); \
 	else \
-		raw_local_irq_enable(); \
+		arch_local_irq_enable(); \
 } while (0)
 
 /* Return true if "flags" argument means interrupts are disabled. */
-#define raw_irqs_disabled_flags(flags) ((flags) != 0)
+#define arch_irqs_disabled_flags(flags) ((flags) != 0)
 
 /* Return true if interrupts are currently disabled. */
-#define raw_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
+#define arch_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
 
 /* Save whether interrupts are currently disabled. */
-#define raw_local_save_flags(flags) ((flags) = raw_irqs_disabled())
+#define arch_local_save_flags() arch_irqs_disabled()
 
 /* Save whether interrupts are currently disabled, then disable them. */
-#define raw_local_irq_save(flags) \
-	do { raw_local_save_flags(flags); raw_local_irq_disable(); } while (0)
+#define arch_local_irq_save() ({ \
+	unsigned long __flags = arch_local_save_flags(); \
+	arch_local_irq_disable(); \
+	__flags; })
 
 /* Prevent the given interrupt from being enabled next time we enable irqs. */
-#define raw_local_irq_mask(interrupt) \
+#define arch_local_irq_mask(interrupt) \
 	(__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
 
 /* Prevent the given interrupt from being enabled immediately. */
-#define raw_local_irq_mask_now(interrupt) do { \
-	raw_local_irq_mask(interrupt); \
+#define arch_local_irq_mask_now(interrupt) do { \
+	arch_local_irq_mask(interrupt); \
 	interrupt_mask_set(interrupt); \
 } while (0)
 
 /* Allow the given interrupt to be enabled next time we enable irqs. */
-#define raw_local_irq_unmask(interrupt) \
+#define arch_local_irq_unmask(interrupt) \
 	(__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
 
 /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
-#define raw_local_irq_unmask_now(interrupt) do { \
-	raw_local_irq_unmask(interrupt); \
+#define arch_local_irq_unmask_now(interrupt) do { \
+	arch_local_irq_unmask(interrupt); \
 	if (!irqs_disabled()) \
 		interrupt_mask_reset(interrupt); \
 } while (0)
@@ -168,14 +170,14 @@
 
 /* Return 0 or 1 to indicate whether interrupts are currently disabled. */
 #define IRQS_DISABLED(tmp)					\
-	mfspr   tmp, INTERRUPT_MASK_1;				\
+	mfspr   tmp, SPR_INTERRUPT_MASK_K;			\
 	andi    tmp, tmp, 1
 
 /* Load up a pointer to &interrupts_enabled_mask. */
 #define GET_INTERRUPTS_ENABLED_MASK_PTR(reg)			\
-	moveli reg, hw2_last(interrupts_enabled_mask); \
-	shl16insli reg, reg, hw1(interrupts_enabled_mask); \
-	shl16insli reg, reg, hw0(interrupts_enabled_mask); \
+	moveli reg, hw2_last(interrupts_enabled_mask);		\
+	shl16insli reg, reg, hw1(interrupts_enabled_mask);	\
+	shl16insli reg, reg, hw0(interrupts_enabled_mask);	\
 	add     reg, reg, tp
 
 /* Disable interrupts. */
@@ -183,18 +185,18 @@
 	moveli  tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS);	\
 	shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS);	\
 	shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS);	\
-	mtspr   INTERRUPT_MASK_SET_1, tmp0
+	mtspr   SPR_INTERRUPT_MASK_SET_K, tmp0
 
 /* Disable ALL synchronous interrupts (used by NMI entry). */
 #define IRQ_DISABLE_ALL(tmp)					\
 	movei   tmp, -1;					\
-	mtspr   INTERRUPT_MASK_SET_1, tmp
+	mtspr   SPR_INTERRUPT_MASK_SET_K, tmp
 
 /* Enable interrupts. */
 #define IRQ_ENABLE(tmp0, tmp1)					\
 	GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0);			\
 	ld      tmp0, tmp0;					\
-	mtspr   INTERRUPT_MASK_RESET_1, tmp0
+	mtspr   SPR_INTERRUPT_MASK_RESET_K, tmp0
 
 #else /* !__tilegx__ */
 
@@ -208,14 +210,14 @@
  * (making the original code's write of the "high" mask word idempotent).
  */
 #define IRQS_DISABLED(tmp)					\
-	mfspr   tmp, INTERRUPT_MASK_1_0;			\
+	mfspr   tmp, SPR_INTERRUPT_MASK_K_0;			\
 	shri    tmp, tmp, INT_MEM_ERROR;			\
 	andi    tmp, tmp, 1
 
 /* Load up a pointer to &interrupts_enabled_mask. */
 #define GET_INTERRUPTS_ENABLED_MASK_PTR(reg)			\
-	moveli  reg, lo16(interrupts_enabled_mask);	\
-	auli    reg, reg, ha16(interrupts_enabled_mask);\
+	moveli  reg, lo16(interrupts_enabled_mask);		\
+	auli    reg, reg, ha16(interrupts_enabled_mask);	\
 	add     reg, reg, tp
 
 /* Disable interrupts. */
@@ -225,16 +227,16 @@
 	 moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS)		\
 	};							\
 	{							\
-	 mtspr  INTERRUPT_MASK_SET_1_0, tmp0;			\
+	 mtspr  SPR_INTERRUPT_MASK_SET_K_0, tmp0;		\
 	 auli   tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS)	\
 	};							\
-	mtspr   INTERRUPT_MASK_SET_1_1, tmp1
+	mtspr   SPR_INTERRUPT_MASK_SET_K_1, tmp1
 
 /* Disable ALL synchronous interrupts (used by NMI entry). */
 #define IRQ_DISABLE_ALL(tmp)					\
 	movei   tmp, -1;					\
-	mtspr   INTERRUPT_MASK_SET_1_0, tmp;			\
-	mtspr   INTERRUPT_MASK_SET_1_1, tmp
+	mtspr   SPR_INTERRUPT_MASK_SET_K_0, tmp;		\
+	mtspr   SPR_INTERRUPT_MASK_SET_K_1, tmp
 
 /* Enable interrupts. */
 #define IRQ_ENABLE(tmp0, tmp1)					\
@@ -244,8 +246,8 @@
 	 addi   tmp1, tmp0, 4					\
 	};							\
 	lw      tmp1, tmp1;					\
-	mtspr   INTERRUPT_MASK_RESET_1_0, tmp0;			\
-	mtspr   INTERRUPT_MASK_RESET_1_1, tmp1
+	mtspr   SPR_INTERRUPT_MASK_RESET_K_0, tmp0;		\
+	mtspr   SPR_INTERRUPT_MASK_RESET_K_1, tmp1
 #endif
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/kmap_types.h linux-libre-2.6.37-gnu/arch/tile/include/asm/kmap_types.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/kmap_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/kmap_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,28 +16,42 @@
 #define _ASM_TILE_KMAP_TYPES_H
 
 /*
- * In TILE Linux each set of four of these uses another 16MB chunk of
- * address space, given 64 tiles and 64KB pages, so we only enable
- * ones that are required by the kernel configuration.
+ * In 32-bit TILE Linux we have to balance the desire to have a lot of
+ * nested atomic mappings with the fact that large page sizes and many
+ * processors chew up address space quickly.  In a typical
+ * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger
+ * adds 4MB of required address-space.  For now we leave KM_TYPE_NR
+ * set to depth 8.
  */
 enum km_type {
+	KM_TYPE_NR = 8
+};
+
+/*
+ * We provide dummy definitions of all the stray values that used to be
+ * required for kmap_atomic() and no longer are.
+ */
+enum {
 	KM_BOUNCE_READ,
 	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
 	KM_BIO_SRC_IRQ,
+	KM_BIO_DST_IRQ,
+	KM_PTE0,
+	KM_PTE1,
 	KM_IRQ0,
 	KM_IRQ1,
 	KM_SOFTIRQ0,
 	KM_SOFTIRQ1,
-	KM_MEMCPY0,
-	KM_MEMCPY1,
-#if defined(CONFIG_HIGHPTE)
-	KM_PTE0,
-	KM_PTE1,
-#endif
-	KM_TYPE_NR
+	KM_SYNC_ICACHE,
+	KM_SYNC_DCACHE,
+	KM_UML_USERCOPY,
+	KM_IRQ_PTE,
+	KM_NMI,
+	KM_NMI_PTE,
+	KM_KDB
 };
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/mman.h linux-libre-2.6.37-gnu/arch/tile/include/asm/mman.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/mman.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/mman.h	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,7 @@
 #define MAP_POPULATE	0x0040		/* populate (prefault) pagetables */
 #define MAP_NONBLOCK	0x0080		/* do not block on IO */
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_STACK	MAP_GROWSDOWN	/* provide convenience alias */
 #define MAP_LOCKED	0x0200		/* pages are locked */
 #define MAP_NORESERVE	0x0400		/* don't check for reservations */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/page.h linux-libre-2.6.37-gnu/arch/tile/include/asm/page.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/page.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/page.h	2011-01-04 19:50:19.000000000 -0500
@@ -199,17 +199,17 @@
  * If you want more physical memory than this then see the CONFIG_HIGHMEM
  * option in the kernel configuration.
  *
- * The top two 16MB chunks in the table below (VIRT and HV) are
- * unavailable to Linux.  Since the kernel interrupt vectors must live
- * at 0xfd000000, we map all of the bottom of RAM at this address with
- * a huge page table entry to minimize its ITLB footprint (as well as
- * at PAGE_OFFSET).  The last architected requirement is that user
- * interrupt vectors live at 0xfc000000, so we make that range of
- * memory available to user processes.  The remaining regions are sized
- * as shown; after the first four addresses, we show "typical" values,
- * since the actual addresses depend on kernel #defines.
+ * The top 16MB chunk in the table below is unavailable to Linux.  Since
+ * the kernel interrupt vectors must live at ether 0xfe000000 or 0xfd000000
+ * (depending on whether the kernel is at PL2 or Pl1), we map all of the
+ * bottom of RAM at this address with a huge page table entry to minimize
+ * its ITLB footprint (as well as at PAGE_OFFSET).  The last architected
+ * requirement is that user interrupt vectors live at 0xfc000000, so we
+ * make that range of memory available to user processes.  The remaining
+ * regions are sized as shown; the first four addresses use the PL 1
+ * values, and after that, we show "typical" values, since the actual
+ * addresses depend on kernel #defines.
  *
- * MEM_VIRT_INTRPT                 0xff000000
  * MEM_HV_INTRPT                   0xfe000000
  * MEM_SV_INTRPT (kernel code)     0xfd000000
  * MEM_USER_INTRPT (user vector)   0xfc000000
@@ -221,9 +221,14 @@
  */
 
 #define MEM_USER_INTRPT		_AC(0xfc000000, UL)
+#if CONFIG_KERNEL_PL == 1
 #define MEM_SV_INTRPT		_AC(0xfd000000, UL)
 #define MEM_HV_INTRPT		_AC(0xfe000000, UL)
-#define MEM_VIRT_INTRPT		_AC(0xff000000, UL)
+#else
+#define MEM_GUEST_INTRPT	_AC(0xfd000000, UL)
+#define MEM_SV_INTRPT		_AC(0xfe000000, UL)
+#define MEM_HV_INTRPT		_AC(0xff000000, UL)
+#endif
 
 #define INTRPT_SIZE		0x4000
 
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/pci-bridge.h linux-libre-2.6.37-gnu/arch/tile/include/asm/pci-bridge.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/pci-bridge.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/pci-bridge.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,117 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- */
-
-#ifndef _ASM_TILE_PCI_BRIDGE_H
-#define _ASM_TILE_PCI_BRIDGE_H
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-
-struct device_node;
-struct pci_controller;
-
-/*
- * pci_io_base returns the memory address at which you can access
- * the I/O space for PCI bus number `bus' (or NULL on error).
- */
-extern void __iomem *pci_bus_io_base(unsigned int bus);
-extern unsigned long pci_bus_io_base_phys(unsigned int bus);
-extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
-
-/* Allocate a new PCI host bridge structure */
-extern struct pci_controller *pcibios_alloc_controller(void);
-
-/* Helper function for setting up resources */
-extern void pci_init_resource(struct resource *res, unsigned long start,
-			      unsigned long end, int flags, char *name);
-
-/* Get the PCI host controller for a bus */
-extern struct pci_controller *pci_bus_to_hose(int bus);
-
-/*
- * Structure of a PCI controller (host bridge)
- */
-struct pci_controller {
-	int index;		/* PCI domain number */
-	struct pci_bus *root_bus;
-
-	int first_busno;
-	int last_busno;
-
-	int hv_cfg_fd[2];	/* config{0,1} fds for this PCIe controller */
-	int hv_mem_fd;		/* fd to Hypervisor for MMIO operations */
-
-	struct pci_ops *ops;
-
-	int irq_base;		/* Base IRQ from the Hypervisor	*/
-	int plx_gen1;		/* flag for PLX Gen 1 configuration */
-
-	/* Address ranges that are routed to this controller/bridge. */
-	struct resource mem_resources[3];
-};
-
-static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
-{
-	return bus->sysdata;
-}
-
-extern void setup_indirect_pci_nomap(struct pci_controller *hose,
-			       void __iomem *cfg_addr, void __iomem *cfg_data);
-extern void setup_indirect_pci(struct pci_controller *hose,
-			       u32 cfg_addr, u32 cfg_data);
-extern void setup_grackle(struct pci_controller *hose);
-
-extern unsigned char common_swizzle(struct pci_dev *, unsigned char *);
-
-/*
- *   The following code swizzles for exactly one bridge.  The routine
- *   common_swizzle below handles multiple bridges.  But there are a
- *   some boards that don't follow the PCI spec's suggestion so we
- *   break this piece out separately.
- */
-static inline unsigned char bridge_swizzle(unsigned char pin,
-		unsigned char idsel)
-{
-	return (((pin-1) + idsel) % 4) + 1;
-}
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those PPC systems that do not already have PCI
- * interrupts properly routed.
- */
-/* FIXME - double check this */
-#define PCI_IRQ_TABLE_LOOKUP ({ \
-	long _ctl_ = -1; \
-	if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \
-		_ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \
-	_ctl_; \
-})
-
-/*
- * Scan the buses below a given PCI host bridge and assign suitable
- * resources to all devices found.
- */
-extern int pciauto_bus_scan(struct pci_controller *, int);
-
-#ifdef CONFIG_PCI
-extern unsigned long pci_address_to_pio(phys_addr_t address);
-#else
-static inline unsigned long pci_address_to_pio(phys_addr_t address)
-{
-	return (unsigned long)-1;
-}
-#endif
-
-#endif /* _ASM_TILE_PCI_BRIDGE_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/pci.h linux-libre-2.6.37-gnu/arch/tile/include/asm/pci.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,65 +15,43 @@
 #ifndef _ASM_TILE_PCI_H
 #define _ASM_TILE_PCI_H
 
-#include <asm/pci-bridge.h>
+#include <linux/pci.h>
 
 /*
- * The hypervisor maps the entirety of CPA-space as bus addresses, so
- * bus addresses are physical addresses.  The networking and block
- * device layers use this boolean for bounce buffer decisions.
+ * Structure of a PCI controller (host bridge)
  */
-#define PCI_DMA_BUS_IS_PHYS     1
+struct pci_controller {
+	int index;		/* PCI domain number */
+	struct pci_bus *root_bus;
 
-struct pci_controller *pci_bus_to_hose(int bus);
-unsigned char __init common_swizzle(struct pci_dev *dev, unsigned char *pinp);
-int __init tile_pci_init(void);
-void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
-void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-void __devinit pcibios_fixup_bus(struct pci_bus *bus);
+	int first_busno;
+	int last_busno;
 
-int __devinit _tile_cfg_read(struct pci_controller *hose,
-				    int bus,
-				    int slot,
-				    int function,
-				    int offset,
-				    int size,
-				    u32 *val);
-int __devinit _tile_cfg_write(struct pci_controller *hose,
-				     int bus,
-				     int slot,
-				     int function,
-				     int offset,
-				     int size,
-				     u32 val);
+	int hv_cfg_fd[2];	/* config{0,1} fds for this PCIe controller */
+	int hv_mem_fd;		/* fd to Hypervisor for MMIO operations */
+
+	struct pci_ops *ops;
+
+	int irq_base;		/* Base IRQ from the Hypervisor	*/
+	int plx_gen1;		/* flag for PLX Gen 1 configuration */
+
+	/* Address ranges that are routed to this controller/bridge. */
+	struct resource mem_resources[3];
+};
 
 /*
- * These are used to to config reads and writes in the early stages of
- * setup before the driver infrastructure has been set up enough to be
- * able to do config reads and writes.
+ * The hypervisor maps the entirety of CPA-space as bus addresses, so
+ * bus addresses are physical addresses.  The networking and block
+ * device layers use this boolean for bounce buffer decisions.
  */
-#define early_cfg_read(where, size, value) \
-	_tile_cfg_read(controller, \
-		       current_bus, \
-		       pci_slot, \
-		       pci_fn, \
-		       where, \
-		       size, \
-		       value)
-
-#define early_cfg_write(where, size, value) \
-	_tile_cfg_write(controller, \
-		       current_bus, \
-		       pci_slot, \
-		       pci_fn, \
-		       where, \
-		       size, \
-		       value)
+#define PCI_DMA_BUS_IS_PHYS     1
 
+int __init tile_pci_init(void);
 
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
 
-#define PCICFG_BYTE	1
-#define PCICFG_WORD	2
-#define PCICFG_DWORD	4
+void __devinit pcibios_fixup_bus(struct pci_bus *bus);
 
 #define	TILE_NUM_PCIE	2
 
@@ -88,33 +66,33 @@
 }
 
 /*
- * I/O space is currently not supported.
+ * pcibios_assign_all_busses() tells whether or not the bus numbers
+ * should be reassigned, in case the BIOS didn't do it correctly, or
+ * in case we don't have a BIOS and we want to let Linux do it.
  */
+static inline int pcibios_assign_all_busses(void)
+{
+	return 1;
+}
 
-#define TILE_PCIE_LOWER_IO		0x0
-#define TILE_PCIE_UPPER_IO		0x10000
-#define TILE_PCIE_PCIE_IO_SIZE		0x0000FFFF
-
-#define _PAGE_NO_CACHE		0
-#define _PAGE_GUARDED		0
-
-
-#define pcibios_assign_all_busses()    pci_assign_all_buses
-extern int pci_assign_all_buses;
-
+/*
+ * No special bus mastering setup handling.
+ */
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
-	/* No special bus mastering setup handling */
 }
 
 #define PCIBIOS_MIN_MEM		0
-#define PCIBIOS_MIN_IO		TILE_PCIE_LOWER_IO
+#define PCIBIOS_MIN_IO		0
 
 /*
  * This flag tells if the platform is TILEmpower that needs
  * special configuration for the PLX switch chip.
  */
-extern int blade_pci;
+extern int tile_plx_gen1;
+
+/* Use any cpu for PCI. */
+#define cpumask_of_pcibus(bus) cpu_online_mask
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
 #include <asm-generic/pci-dma-compat.h>
@@ -122,7 +100,4 @@
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
-/* Use any cpu for PCI. */
-#define cpumask_of_pcibus(bus) cpu_online_mask
-
 #endif /* _ASM_TILE_PCI_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/tile/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -344,18 +344,11 @@
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 #if defined(CONFIG_HIGHPTE)
-extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
-#define pte_offset_map(dir, address) \
-	_pte_offset_map(dir, address, KM_PTE0)
-#define pte_offset_map_nested(dir, address) \
-	_pte_offset_map(dir, address, KM_PTE1)
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
-#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /* Clear a non-executable kernel PTE and flush it from the TLB. */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/processor.h linux-libre-2.6.37-gnu/arch/tile/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -292,8 +292,18 @@
 /* Are we using huge pages in the TLB for kernel data? */
 extern int kdata_huge;
 
+/* Support standard Linux prefetching. */
+#define ARCH_HAS_PREFETCH
+#define prefetch(x) __builtin_prefetch(x)
 #define PREFETCH_STRIDE CHIP_L2_LINE_SIZE()
 
+/* Bring a value into the L1D, faulting the TLB if necessary. */
+#ifdef __tilegx__
+#define prefetch_L1(x) __insn_prefetch_l1_fault((void *)(x))
+#else
+#define prefetch_L1(x) __insn_prefetch_L1((void *)(x))
+#endif
+
 #else /* __ASSEMBLY__ */
 
 /* Do some slow action (e.g. read a slow SPR). */
@@ -328,18 +338,21 @@
  * Note that assembly code assumes that USER_PL is zero.
  */
 #define USER_PL 0
-#define KERNEL_PL 1
+#if CONFIG_KERNEL_PL == 2
+#define GUEST_PL 1
+#endif
+#define KERNEL_PL CONFIG_KERNEL_PL
 
-/* SYSTEM_SAVE_1_0 holds the current cpu number ORed with ksp0. */
+/* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */
 #define CPU_LOG_MASK_VALUE 12
 #define CPU_MASK_VALUE ((1 << CPU_LOG_MASK_VALUE) - 1)
 #if CONFIG_NR_CPUS > CPU_MASK_VALUE
 # error Too many cpus!
 #endif
 #define raw_smp_processor_id() \
-	((int)__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & CPU_MASK_VALUE)
+	((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & CPU_MASK_VALUE)
 #define get_current_ksp0() \
-	(__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & ~CPU_MASK_VALUE)
+	(__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~CPU_MASK_VALUE)
 #define next_current_ksp0(task) ({ \
 	unsigned long __ksp0 = task_ksp0(task); \
 	int __cpu = raw_smp_processor_id(); \
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/ptrace.h linux-libre-2.6.37-gnu/arch/tile/include/asm/ptrace.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/ptrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/ptrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -62,8 +62,8 @@
 	pt_reg_t lr;		/* aliases regs[TREG_LR] */
 
 	/* Saved special registers. */
-	pt_reg_t pc;		/* stored in EX_CONTEXT_1_0 */
-	pt_reg_t ex1;		/* stored in EX_CONTEXT_1_1 (PL and ICS bit) */
+	pt_reg_t pc;		/* stored in EX_CONTEXT_K_0 */
+	pt_reg_t ex1;		/* stored in EX_CONTEXT_K_1 (PL and ICS bit) */
 	pt_reg_t faultnum;	/* fault number (INT_SWINT_1 for syscall) */
 	pt_reg_t orig_r0;	/* r0 at syscall entry, else zero */
 	pt_reg_t flags;		/* flags (see below) */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/signal.h linux-libre-2.6.37-gnu/arch/tile/include/asm/signal.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/signal.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/signal.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 struct pt_regs;
-int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *);
+int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
 int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
 void do_signal(struct pt_regs *regs);
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/stat.h linux-libre-2.6.37-gnu/arch/tile/include/asm/stat.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/stat.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/stat.h	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1,4 @@
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_STAT64	/* Used for compat_sys_stat64() etc. */
+#endif
 #include <asm-generic/stat.h>
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/syscalls.h linux-libre-2.6.37-gnu/arch/tile/include/asm/syscalls.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/syscalls.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/syscalls.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,8 +32,9 @@
 
 /*
  * Note that by convention, any syscall which requires the current
- * register set takes an additional "struct pt_regs *" pointer; the
- * sys_xxx() function just adds the pointer and tail-calls to _sys_xxx().
+ * register set takes an additional "struct pt_regs *" pointer; a
+ * _sys_xxx() trampoline in intvec*.S just sets up the pointer and
+ * jumps to sys_xxx().
  */
 
 /* kernel/sys.c */
@@ -43,66 +44,17 @@
 int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
 		       u32 len_lo, u32 len_hi, int advice);
 long sys_flush_cache(void);
-long sys_mmap2(unsigned long addr, unsigned long len,
-	       unsigned long prot, unsigned long flags,
-	       unsigned long fd, unsigned long pgoff);
-#ifdef __tilegx__
-long sys_mmap(unsigned long addr, unsigned long len,
-	      unsigned long prot, unsigned long flags,
-	      unsigned long fd, off_t pgoff);
+#ifndef __tilegx__  /* No mmap() in the 32-bit kernel. */
+#define sys_mmap sys_mmap
 #endif
 
-/* kernel/process.c */
-long sys_clone(unsigned long clone_flags, unsigned long newsp,
-	       void __user *parent_tid, void __user *child_tid);
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
-		void __user *parent_tid, void __user *child_tid,
-		struct pt_regs *regs);
-long sys_fork(void);
-long _sys_fork(struct pt_regs *regs);
-long sys_vfork(void);
-long _sys_vfork(struct pt_regs *regs);
-long sys_execve(const char __user *filename,
-		const char __user *const __user *argv,
-		const char __user *const __user *envp);
-long _sys_execve(const char __user *filename,
-		 const char __user *const __user *argv,
-		 const char __user *const __user *envp, struct pt_regs *regs);
-
-/* kernel/signal.c */
-long sys_sigaltstack(const stack_t __user *, stack_t __user *);
-long _sys_sigaltstack(const stack_t __user *, stack_t __user *,
-		      struct pt_regs *);
-long sys_rt_sigreturn(void);
-long _sys_rt_sigreturn(struct pt_regs *regs);
-
-/* platform-independent functions */
-long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
-long sys_rt_sigaction(int sig, const struct sigaction __user *act,
-		      struct sigaction __user *oact, size_t sigsetsize);
-
 #ifndef __tilegx__
 /* mm/fault.c */
-int sys_cmpxchg_badaddr(unsigned long address);
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+long _sys_cmpxchg_badaddr(unsigned long address);
 #endif
 
 #ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
-		       const compat_uptr_t __user *argv,
-		       const compat_uptr_t __user *envp);
-long _compat_sys_execve(const char __user *path,
-			const compat_uptr_t __user *argv,
-			const compat_uptr_t __user *envp,
-			struct pt_regs *regs);
-long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-			    struct compat_sigaltstack __user *uoss_ptr);
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-			     struct compat_sigaltstack __user *uoss_ptr,
-			     struct pt_regs *regs);
-long compat_sys_rt_sigreturn(void);
-long _compat_sys_rt_sigreturn(struct pt_regs *regs);
-
 /* These four are not defined for 64-bit, but serve as "compat" syscalls. */
 long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg);
 long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
@@ -110,4 +62,15 @@
 long sys_ftruncate64(unsigned int fd, loff_t length);
 #endif
 
+/* These are the intvec*.S trampolines. */
+long _sys_sigaltstack(const stack_t __user *, stack_t __user *);
+long _sys_rt_sigreturn(void);
+long _sys_clone(unsigned long clone_flags, unsigned long newsp,
+		void __user *parent_tid, void __user *child_tid);
+long _sys_execve(const char __user *filename,
+		 const char __user *const __user *argv,
+		 const char __user *const __user *envp);
+
+#include <asm-generic/syscalls.h>
+
 #endif /* _ASM_TILE_SYSCALLS_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/system.h linux-libre-2.6.37-gnu/arch/tile/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -89,6 +89,10 @@
 #define get_cycles_low() __insn_mfspr(SPR_CYCLE)   /* just get all 64 bits */
 #endif
 
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+int __mb_incoherent(void);  /* Helper routine for mb_incoherent(). */
+#endif
+
 /* Fence to guarantee visibility of stores to incoherent memory. */
 static inline void
 mb_incoherent(void)
@@ -97,7 +101,6 @@
 
 #if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
 	{
-		int __mb_incoherent(void);
 #if CHIP_HAS_TILE_WRITE_PENDING()
 		const unsigned long WRITE_TIMEOUT_CYCLES = 400;
 		unsigned long start = get_cycles_low();
@@ -161,7 +164,7 @@
 /* Helper function for _switch_to(). */
 extern struct task_struct *__switch_to(struct task_struct *prev,
 				       struct task_struct *next,
-				       unsigned long new_system_save_1_0);
+				       unsigned long new_system_save_k_0);
 
 /* Address that switched-away from tasks are at. */
 extern unsigned long get_switch_to_pc(void);
@@ -214,13 +217,6 @@
 } while (0)
 #endif
 
-/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
-extern int _sim_syscall(int syscall_num, ...);
-#define sim_syscall(syscall_num, ...) \
-	_sim_syscall(SIM_CONTROL_SYSCALL + \
-		((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
-		## __VA_ARGS__)
-
 /*
  * Kernel threads can check to see if they need to migrate their
  * stack whenever they return from a context switch; for user
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/traps.h linux-libre-2.6.37-gnu/arch/tile/include/asm/traps.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/traps.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/traps.h	2011-01-04 19:50:19.000000000 -0500
@@ -59,4 +59,8 @@
 void do_breakpoint(struct pt_regs *, int fault_num);
 
 
+#ifdef __tilegx__
+void gx_singlestep_handle(struct pt_regs *, int fault_num);
+#endif
+
 #endif /* _ASM_TILE_SYSCALLS_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/asm/unistd.h linux-libre-2.6.37-gnu/arch/tile/include/asm/unistd.h
--- linux-libre-2.6.36-gnu/arch/tile/include/asm/unistd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/asm/unistd.h	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,7 @@
 #ifdef CONFIG_COMPAT
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
+#define __ARCH_WANT_SYS_NEWFSTATAT
 #endif
 
 #endif /* _ASM_TILE_UNISTD_H */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/hv/drv_xgbe_impl.h linux-libre-2.6.37-gnu/arch/tile/include/hv/drv_xgbe_impl.h
--- linux-libre-2.6.36-gnu/arch/tile/include/hv/drv_xgbe_impl.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/include/hv/drv_xgbe_impl.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file drivers/xgbe/impl.h
+ * Implementation details for the NetIO library.
+ */
+
+#ifndef __DRV_XGBE_IMPL_H__
+#define __DRV_XGBE_IMPL_H__
+
+#include <hv/netio_errors.h>
+#include <hv/netio_intf.h>
+#include <hv/drv_xgbe_intf.h>
+
+
+/** How many groups we have (log2). */
+#define LOG2_NUM_GROUPS (12)
+/** How many groups we have. */
+#define NUM_GROUPS (1 << LOG2_NUM_GROUPS)
+
+/** Number of output requests we'll buffer per tile. */
+#define EPP_REQS_PER_TILE (32)
+
+/** Words used in an eDMA command without checksum acceleration. */
+#define EDMA_WDS_NO_CSUM      8
+/** Words used in an eDMA command with checksum acceleration. */
+#define EDMA_WDS_CSUM        10
+/** Total available words in the eDMA command FIFO. */
+#define EDMA_WDS_TOTAL      128
+
+
+/*
+ * FIXME: These definitions are internal and should have underscores!
+ * NOTE: The actual numeric values here are intentional and allow us to
+ * optimize the concept "if small ... else if large ... else ...", by
+ * checking for the low bit being set, and then for non-zero.
+ * These are used as array indices, so they must have the values (0, 1, 2)
+ * in some order.
+ */
+#define SIZE_SMALL (1)       /**< Small packet queue. */
+#define SIZE_LARGE (2)       /**< Large packet queue. */
+#define SIZE_JUMBO (0)       /**< Jumbo packet queue. */
+
+/** The number of "SIZE_xxx" values. */
+#define NETIO_NUM_SIZES 3
+
+
+/*
+ * Default numbers of packets for IPP drivers.  These values are chosen
+ * such that CIPP1 will not overflow its L2 cache.
+ */
+
+/** The default number of small packets. */
+#define NETIO_DEFAULT_SMALL_PACKETS 2750
+/** The default number of large packets. */
+#define NETIO_DEFAULT_LARGE_PACKETS 2500
+/** The default number of jumbo packets. */
+#define NETIO_DEFAULT_JUMBO_PACKETS 250
+
+
+/** Log2 of the size of a memory arena. */
+#define NETIO_ARENA_SHIFT      24      /* 16 MB */
+/** Size of a memory arena. */
+#define NETIO_ARENA_SIZE       (1 << NETIO_ARENA_SHIFT)
+
+
+/** A queue of packets.
+ *
+ * This structure partially defines a queue of packets waiting to be
+ * processed.  The queue as a whole is written to by an interrupt handler and
+ * read by non-interrupt code; this data structure is what's touched by the
+ * interrupt handler.  The other part of the queue state, the read offset, is
+ * kept in user space, not in hypervisor space, so it is in a separate data
+ * structure.
+ *
+ * The read offset (__packet_receive_read in the user part of the queue
+ * structure) points to the next packet to be read. When the read offset is
+ * equal to the write offset, the queue is empty; therefore the queue must
+ * contain one more slot than the required maximum queue size.
+ *
+ * Here's an example of all 3 state variables and what they mean.  All
+ * pointers move left to right.
+ *
+ * @code
+ *   I   I   V   V   V   V   I   I   I   I
+ *   0   1   2   3   4   5   6   7   8   9  10
+ *           ^       ^       ^               ^
+ *           |               |               |
+ *           |               |               __last_packet_plus_one
+ *           |               __buffer_write
+ *           __packet_receive_read
+ * @endcode
+ *
+ * This queue has 10 slots, and thus can hold 9 packets (_last_packet_plus_one
+ * = 10).  The read pointer is at 2, and the write pointer is at 6; thus,
+ * there are valid, unread packets in slots 2, 3, 4, and 5.  The remaining
+ * slots are invalid (do not contain a packet).
+ */
+typedef struct {
+  /** Byte offset of the next notify packet to be written: zero for the first
+   *  packet on the queue, sizeof (netio_pkt_t) for the second packet on the
+   *  queue, etc. */
+  volatile uint32_t __packet_write;
+
+  /** Offset of the packet after the last valid packet (i.e., when any
+   *  pointer is incremented to this value, it wraps back to zero). */
+  uint32_t __last_packet_plus_one;
+}
+__netio_packet_queue_t;
+
+
+/** A queue of buffers.
+ *
+ * This structure partially defines a queue of empty buffers which have been
+ * obtained via requests to the IPP.  (The elements of the queue are packet
+ * handles, which are transformed into a full netio_pkt_t when the buffer is
+ * retrieved.)  The queue as a whole is written to by an interrupt handler and
+ * read by non-interrupt code; this data structure is what's touched by the
+ * interrupt handler.  The other parts of the queue state, the read offset and
+ * requested write offset, are kept in user space, not in hypervisor space, so
+ * they are in a separate data structure.
+ *
+ * The read offset (__buffer_read in the user part of the queue structure)
+ * points to the next buffer to be read. When the read offset is equal to the
+ * write offset, the queue is empty; therefore the queue must contain one more
+ * slot than the required maximum queue size.
+ *
+ * The requested write offset (__buffer_requested_write in the user part of
+ * the queue structure) points to the slot which will hold the next buffer we
+ * request from the IPP, once we get around to sending such a request.  When
+ * the requested write offset is equal to the write offset, no requests for
+ * new buffers are outstanding; when the requested write offset is one greater
+ * than the read offset, no more requests may be sent.
+ *
+ * Note that, unlike the packet_queue, the buffer_queue places incoming
+ * buffers at decreasing addresses.  This makes the check for "is it time to
+ * wrap the buffer pointer" cheaper in the assembly code which receives new
+ * buffers, and means that the value which defines the queue size,
+ * __last_buffer, is different than in the packet queue.  Also, the offset
+ * used in the packet_queue is already scaled by the size of a packet; here we
+ * use unscaled slot indices for the offsets.  (These differences are
+ * historical, and in the future it's possible that the packet_queue will look
+ * more like this queue.)
+ *
+ * @code
+ * Here's an example of all 4 state variables and what they mean.  Remember:
+ * all pointers move right to left.
+ *
+ *   V   V   V   I   I   R   R   V   V   V
+ *   0   1   2   3   4   5   6   7   8   9
+ *           ^       ^       ^           ^
+ *           |       |       |           |
+ *           |       |       |           __last_buffer
+ *           |       |       __buffer_write
+ *           |       __buffer_requested_write
+ *           __buffer_read
+ * @endcode
+ *
+ * This queue has 10 slots, and thus can hold 9 buffers (_last_buffer = 9).
+ * The read pointer is at 2, and the write pointer is at 6; thus, there are
+ * valid, unread buffers in slots 2, 1, 0, 9, 8, and 7.  The requested write
+ * pointer is at 4; thus, requests have been made to the IPP for buffers which
+ * will be placed in slots 6 and 5 when they arrive.  Finally, the remaining
+ * slots are invalid (do not contain a buffer).
+ */
+typedef struct
+{
+  /** Ordinal number of the next buffer to be written: 0 for the first slot in
+   *  the queue, 1 for the second slot in the queue, etc. */
+  volatile uint32_t __buffer_write;
+
+  /** Ordinal number of the last buffer (i.e., when any pointer is decremented
+   *  below zero, it is reloaded with this value). */
+  uint32_t __last_buffer;
+}
+__netio_buffer_queue_t;
+
+
+/**
+ * An object for providing Ethernet packets to a process.
+ */
+typedef struct __netio_queue_impl_t
+{
+  /** The queue of packets waiting to be received. */
+  __netio_packet_queue_t __packet_receive_queue;
+  /** The intr bit mask that IDs this device. */
+  unsigned int __intr_id;
+  /** Offset to queues of empty buffers, one per size. */
+  uint32_t __buffer_queue[NETIO_NUM_SIZES];
+  /** The address of the first EPP tile, or -1 if no EPP. */
+  /* ISSUE: Actually this is always "0" or "~0". */
+  uint32_t __epp_location;
+  /** The queue ID that this queue represents. */
+  unsigned int __queue_id;
+  /** Number of acknowledgements received. */
+  volatile uint32_t __acks_received;
+  /** Last completion number received for packet_sendv. */
+  volatile uint32_t __last_completion_rcv;
+  /** Number of packets allowed to be outstanding. */
+  uint32_t __max_outstanding;
+  /** First VA available for packets. */
+  void* __va_0;
+  /** First VA in second range available for packets. */
+  void* __va_1;
+  /** Padding to align the "__packets" field to the size of a netio_pkt_t. */
+  uint32_t __padding[3];
+  /** The packets themselves. */
+  netio_pkt_t __packets[0];
+}
+netio_queue_impl_t;
+
+
+/**
+ * An object for managing the user end of a NetIO queue.
+ */
+typedef struct __netio_queue_user_impl_t
+{
+  /** The next incoming packet to be read. */
+  uint32_t __packet_receive_read;
+  /** The next empty buffers to be read, one index per size. */
+  uint8_t __buffer_read[NETIO_NUM_SIZES];
+  /** Where the empty buffer we next request from the IPP will go, one index
+   * per size. */
+  uint8_t __buffer_requested_write[NETIO_NUM_SIZES];
+  /** PCIe interface flag. */
+  uint8_t __pcie;
+  /** Number of packets left to be received before we send a credit update. */
+  uint32_t __receive_credit_remaining;
+  /** Value placed in __receive_credit_remaining when it reaches zero. */
+  uint32_t __receive_credit_interval;
+  /** First fast I/O routine index. */
+  uint32_t __fastio_index;
+  /** Number of acknowledgements expected. */
+  uint32_t __acks_outstanding;
+  /** Last completion number requested. */
+  uint32_t __last_completion_req;
+  /** File descriptor for driver. */
+  int __fd;
+}
+netio_queue_user_impl_t;
+
+
+#define NETIO_GROUP_CHUNK_SIZE   64   /**< Max # groups in one IPP request */
+#define NETIO_BUCKET_CHUNK_SIZE  64   /**< Max # buckets in one IPP request */
+
+
+/** Internal structure used to convey packet send information to the
+ * hypervisor.  FIXME: Actually, it's not used for that anymore, but
+ * netio_packet_send() still uses it internally.
+ */
+typedef struct
+{
+  uint16_t flags;              /**< Packet flags (__NETIO_SEND_FLG_xxx) */
+  uint16_t transfer_size;      /**< Size of packet */
+  uint32_t va;                 /**< VA of start of packet */
+  __netio_pkt_handle_t handle; /**< Packet handle */
+  uint32_t csum0;              /**< First checksum word */
+  uint32_t csum1;              /**< Second checksum word */
+}
+__netio_send_cmd_t;
+
+
+/** Flags used in two contexts:
+ *  - As the "flags" member in the __netio_send_cmd_t, above; used only
+ *    for netio_pkt_send_{prepare,commit}.
+ *  - As part of the flags passed to the various send packet fast I/O calls.
+ */
+
+/** Need acknowledgement on this packet.  Note that some code in the
+ *  normal send_pkt fast I/O handler assumes that this is equal to 1. */
+#define __NETIO_SEND_FLG_ACK    0x1
+
+/** Do checksum on this packet.  (Only used with the __netio_send_cmd_t;
+ *  normal packet sends use a special fast I/O index to denote checksumming,
+ *  and multi-segment sends test the checksum descriptor.) */
+#define __NETIO_SEND_FLG_CSUM   0x2
+
+/** Get a completion on this packet.  Only used with multi-segment sends.  */
+#define __NETIO_SEND_FLG_COMPLETION 0x4
+
+/** Position of the number-of-extra-segments value in the flags word.
+    Only used with multi-segment sends. */
+#define __NETIO_SEND_FLG_XSEG_SHIFT 3
+
+/** Width of the number-of-extra-segments value in the flags word. */
+#define __NETIO_SEND_FLG_XSEG_WIDTH 2
+
+#endif /* __DRV_XGBE_IMPL_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/hv/drv_xgbe_intf.h linux-libre-2.6.37-gnu/arch/tile/include/hv/drv_xgbe_intf.h
--- linux-libre-2.6.36-gnu/arch/tile/include/hv/drv_xgbe_intf.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/include/hv/drv_xgbe_intf.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,615 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * @file drv_xgbe_intf.h
+ * Interface to the hypervisor XGBE driver.
+ */
+
+#ifndef __DRV_XGBE_INTF_H__
+#define __DRV_XGBE_INTF_H__
+
+/**
+ * An object for forwarding VAs and PAs to the hypervisor.
+ * @ingroup types
+ *
+ * This allows the supervisor to specify a number of areas of memory to
+ * store packet buffers.
+ */
+typedef struct
+{
+  /** The physical address of the memory. */
+  HV_PhysAddr pa;
+  /** Page table entry for the memory.  This is only used to derive the
+   *  memory's caching mode; the PA bits are ignored. */
+  HV_PTE pte;
+  /** The virtual address of the memory. */
+  HV_VirtAddr va;
+  /** Size (in bytes) of the memory area. */
+  int size;
+
+}
+netio_ipp_address_t;
+
+/** The various pread/pwrite offsets into the hypervisor-level driver.
+ * @ingroup types
+ */
+typedef enum
+{
+  /** Inform the Linux driver of the address of the NetIO arena memory.
+   *  This offset is actually only used to convey information from netio
+   *  to the Linux driver; it never makes it from there to the hypervisor.
+   *  Write-only; takes a uint32_t specifying the VA address. */
+  NETIO_FIXED_ADDR               = 0x5000000000000000ULL,
+
+  /** Inform the Linux driver of the size of the NetIO arena memory.
+   *  This offset is actually only used to convey information from netio
+   *  to the Linux driver; it never makes it from there to the hypervisor.
+   *  Write-only; takes a uint32_t specifying the VA size. */
+  NETIO_FIXED_SIZE               = 0x5100000000000000ULL,
+
+  /** Register current tile with IPP.  Write then read: write, takes a
+   *  netio_input_config_t, read returns a pointer to a netio_queue_impl_t. */
+  NETIO_IPP_INPUT_REGISTER_OFF   = 0x6000000000000000ULL,
+
+  /** Unregister current tile from IPP.  Write-only, takes a dummy argument. */
+  NETIO_IPP_INPUT_UNREGISTER_OFF = 0x6100000000000000ULL,
+
+  /** Start packets flowing.  Write-only, takes a dummy argument. */
+  NETIO_IPP_INPUT_INIT_OFF       = 0x6200000000000000ULL,
+
+  /** Stop packets flowing.  Write-only, takes a dummy argument. */
+  NETIO_IPP_INPUT_UNINIT_OFF     = 0x6300000000000000ULL,
+
+  /** Configure group (typically we group on VLAN).  Write-only: takes an
+   *  array of netio_group_t's, low 24 bits of the offset is the base group
+   *  number times the size of a netio_group_t. */
+  NETIO_IPP_INPUT_GROUP_CFG_OFF  = 0x6400000000000000ULL,
+
+  /** Configure bucket.  Write-only: takes an array of netio_bucket_t's, low
+   *  24 bits of the offset is the base bucket number times the size of a
+   *  netio_bucket_t. */
+  NETIO_IPP_INPUT_BUCKET_CFG_OFF = 0x6500000000000000ULL,
+
+  /** Get/set a parameter.  Read or write: read or write data is the parameter
+   *  value, low 32 bits of the offset is a __netio_getset_offset_t. */
+  NETIO_IPP_PARAM_OFF            = 0x6600000000000000ULL,
+
+  /** Get fast I/O index.  Read-only; returns a 4-byte base index value. */
+  NETIO_IPP_GET_FASTIO_OFF       = 0x6700000000000000ULL,
+
+  /** Configure hijack IP address.  Packets with this IPv4 dest address
+   *  go to bucket NETIO_NUM_BUCKETS - 1.  Write-only: takes an IP address
+   *  in some standard form.  FIXME: Define the form! */
+  NETIO_IPP_INPUT_HIJACK_CFG_OFF  = 0x6800000000000000ULL,
+
+  /**
+   * Offsets beyond this point are reserved for the supervisor (although that
+   * enforcement must be done by the supervisor driver itself).
+   */
+  NETIO_IPP_USER_MAX_OFF         = 0x6FFFFFFFFFFFFFFFULL,
+
+  /** Register I/O memory.  Write-only, takes a netio_ipp_address_t. */
+  NETIO_IPP_IOMEM_REGISTER_OFF   = 0x7000000000000000ULL,
+
+  /** Unregister I/O memory.  Write-only, takes a netio_ipp_address_t. */
+  NETIO_IPP_IOMEM_UNREGISTER_OFF = 0x7100000000000000ULL,
+
+  /* Offsets greater than 0x7FFFFFFF can't be used directly from Linux
+   * userspace code due to limitations in the pread/pwrite syscalls. */
+
+  /** Drain LIPP buffers. */
+  NETIO_IPP_DRAIN_OFF              = 0xFA00000000000000ULL,
+
+  /** Supply a netio_ipp_address_t to be used as shared memory for the
+   *  LEPP command queue. */
+  NETIO_EPP_SHM_OFF              = 0xFB00000000000000ULL,
+
+  /* 0xFC... is currently unused. */
+
+  /** Stop IPP/EPP tiles.  Write-only, takes a dummy argument.  */
+  NETIO_IPP_STOP_SHIM_OFF        = 0xFD00000000000000ULL,
+
+  /** Start IPP/EPP tiles.  Write-only, takes a dummy argument.  */
+  NETIO_IPP_START_SHIM_OFF       = 0xFE00000000000000ULL,
+
+  /** Supply packet arena.  Write-only, takes an array of
+    * netio_ipp_address_t values. */
+  NETIO_IPP_ADDRESS_OFF          = 0xFF00000000000000ULL,
+} netio_hv_offset_t;
+
+/** Extract the base offset from an offset */
+#define NETIO_BASE_OFFSET(off)    ((off) & 0xFF00000000000000ULL)
+/** Extract the local offset from an offset */
+#define NETIO_LOCAL_OFFSET(off)   ((off) & 0x00FFFFFFFFFFFFFFULL)
+
+
+/**
+ * Get/set offset.
+ */
+typedef union
+{
+  struct
+  {
+    uint64_t addr:48;        /**< Class-specific address */
+    unsigned int class:8;    /**< Class (e.g., NETIO_PARAM) */
+    unsigned int opcode:8;   /**< High 8 bits of NETIO_IPP_PARAM_OFF */
+  }
+  bits;                      /**< Bitfields */
+  uint64_t word;             /**< Aggregated value to use as the offset */
+}
+__netio_getset_offset_t;
+
+/**
+ * Fast I/O index offsets (must be contiguous).
+ */
+typedef enum
+{
+  NETIO_FASTIO_ALLOCATE         = 0, /**< Get empty packet buffer */
+  NETIO_FASTIO_FREE_BUFFER      = 1, /**< Give buffer back to IPP */
+  NETIO_FASTIO_RETURN_CREDITS   = 2, /**< Give credits to IPP */
+  NETIO_FASTIO_SEND_PKT_NOCK    = 3, /**< Send a packet, no checksum */
+  NETIO_FASTIO_SEND_PKT_CK      = 4, /**< Send a packet, with checksum */
+  NETIO_FASTIO_SEND_PKT_VEC     = 5, /**< Send a vector of packets */
+  NETIO_FASTIO_SENDV_PKT        = 6, /**< Sendv one packet */
+  NETIO_FASTIO_NUM_INDEX        = 7, /**< Total number of fast I/O indices */
+} netio_fastio_index_t;
+
+/** 3-word return type for Fast I/O call. */
+typedef struct
+{
+  int err;            /**< Error code. */
+  uint32_t val0;      /**< Value.  Meaning depends upon the specific call. */
+  uint32_t val1;      /**< Value.  Meaning depends upon the specific call. */
+} netio_fastio_rv3_t;
+
+/** 0-argument fast I/O call */
+int __netio_fastio0(uint32_t fastio_index);
+/** 1-argument fast I/O call */
+int __netio_fastio1(uint32_t fastio_index, uint32_t arg0);
+/** 3-argument fast I/O call, 2-word return value */
+netio_fastio_rv3_t __netio_fastio3_rv3(uint32_t fastio_index, uint32_t arg0,
+                                       uint32_t arg1, uint32_t arg2);
+/** 4-argument fast I/O call */
+int __netio_fastio4(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+                    uint32_t arg2, uint32_t arg3);
+/** 6-argument fast I/O call */
+int __netio_fastio6(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+                    uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5);
+/** 9-argument fast I/O call */
+int __netio_fastio9(uint32_t fastio_index, uint32_t arg0, uint32_t arg1,
+                    uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
+                    uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+/** Allocate an empty packet.
+ * @param fastio_index Fast I/O index.
+ * @param size Size of the packet to allocate.
+ */
+#define __netio_fastio_allocate(fastio_index, size) \
+  __netio_fastio1((fastio_index) + NETIO_FASTIO_ALLOCATE, size)
+
+/** Free a buffer.
+ * @param fastio_index Fast I/O index.
+ * @param handle Handle for the packet to free.
+ */
+#define __netio_fastio_free_buffer(fastio_index, handle) \
+  __netio_fastio1((fastio_index) + NETIO_FASTIO_FREE_BUFFER, handle)
+
+/** Increment our receive credits.
+ * @param fastio_index Fast I/O index.
+ * @param credits Number of credits to add.
+ */
+#define __netio_fastio_return_credits(fastio_index, credits) \
+  __netio_fastio1((fastio_index) + NETIO_FASTIO_RETURN_CREDITS, credits)
+
+/** Send packet, no checksum.
+ * @param fastio_index Fast I/O index.
+ * @param ackflag Nonzero if we want an ack.
+ * @param size Size of the packet.
+ * @param va Virtual address of start of packet.
+ * @param handle Packet handle.
+ */
+#define __netio_fastio_send_pkt_nock(fastio_index, ackflag, size, va, handle) \
+  __netio_fastio4((fastio_index) + NETIO_FASTIO_SEND_PKT_NOCK, ackflag, \
+                  size, va, handle)
+
+/** Send packet, calculate checksum.
+ * @param fastio_index Fast I/O index.
+ * @param ackflag Nonzero if we want an ack.
+ * @param size Size of the packet.
+ * @param va Virtual address of start of packet.
+ * @param handle Packet handle.
+ * @param csum0 Shim checksum header.
+ * @param csum1 Checksum seed.
+ */
+#define __netio_fastio_send_pkt_ck(fastio_index, ackflag, size, va, handle, \
+                                   csum0, csum1) \
+  __netio_fastio6((fastio_index) + NETIO_FASTIO_SEND_PKT_CK, ackflag, \
+                  size, va, handle, csum0, csum1)
+
+
+/** Format for the "csum0" argument to the __netio_fastio_send routines
+ * and LEPP.  Note that this is currently exactly identical to the
+ * ShimProtocolOffloadHeader.
+ */
+typedef union
+{
+  struct
+  {
+    unsigned int start_byte:7;       /**< The first byte to be checksummed */
+    unsigned int count:14;           /**< Number of bytes to be checksummed. */
+    unsigned int destination_byte:7; /**< The byte to write the checksum to. */
+    unsigned int reserved:4;         /**< Reserved. */
+  } bits;                            /**< Decomposed method of access. */
+  unsigned int word;                 /**< To send out the IDN. */
+} __netio_checksum_header_t;
+
+
+/** Sendv packet with 1 or 2 segments.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus
+ *        1 in next 2 bits; expected checksum in high 16 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; if zero, no checksum.
+ * @param va_F Virtual address of first segment.
+ * @param va_L Virtual address of last segment, if 2 segments.
+ * @param len_F_L Length of first segment in low 16 bits; length of last
+ *        segment, if 2 segments, in high 16 bits.
+ */
+#define __netio_fastio_sendv_pkt_1_2(fastio_index, flags, confno, csum0, \
+                                     va_F, va_L, len_F_L) \
+  __netio_fastio6((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \
+                  csum0, va_F, va_L, len_F_L)
+
+/** Send packet on PCIe interface.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; Hard wired 0, not needed for PCIe.
+ * @param va_F Virtual address of the packet buffer.
+ * @param va_L Virtual address of last segment, if 2 segments. Hard wired 0.
+ * @param len_F_L Length of the packet buffer in low 16 bits.
+ */
+#define __netio_fastio_send_pcie_pkt(fastio_index, flags, confno, csum0, \
+                                     va_F, va_L, len_F_L) \
+  __netio_fastio6((fastio_index) + PCIE_FASTIO_SENDV_PKT, flags, confno, \
+                  csum0, va_F, va_L, len_F_L)
+
+/** Sendv packet with 3 or 4 segments.
+ * @param fastio_index Fast I/O index.
+ * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus
+ *        1 in next 2 bits; expected checksum in high 16 bits.
+ * @param confno Confirmation number to request, if notify flag set.
+ * @param csum0 Checksum descriptor; if zero, no checksum.
+ * @param va_F Virtual address of first segment.
+ * @param va_L Virtual address of last segment (third segment if 3 segments,
+ *        fourth segment if 4 segments).
+ * @param len_F_L Length of first segment in low 16 bits; length of last
+ *        segment in high 16 bits.
+ * @param va_M0 Virtual address of "middle 0" segment; this segment is sent
+ *        second when there are three segments, and third if there are four.
+ * @param va_M1 Virtual address of "middle 1" segment; this segment is sent
+ *        second when there are four segments.
+ * @param len_M0_M1 Length of middle 0 segment in low 16 bits; length of middle
+ *        1 segment, if 4 segments, in high 16 bits.
+ */
+#define __netio_fastio_sendv_pkt_3_4(fastio_index, flags, confno, csum0, va_F, \
+                                     va_L, len_F_L, va_M0, va_M1, len_M0_M1) \
+  __netio_fastio9((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \
+                  csum0, va_F, va_L, len_F_L, va_M0, va_M1, len_M0_M1)
+
+/** Send vector of packets.
+ * @param fastio_index Fast I/O index.
+ * @param seqno Number of packets transmitted so far on this interface;
+ *        used to decide which packets should be acknowledged.
+ * @param nentries Number of entries in vector.
+ * @param va Virtual address of start of vector entry array.
+ * @return 3-word netio_fastio_rv3_t structure.  The structure's err member
+ *         is an error code, or zero if no error.  The val0 member is the
+ *         updated value of seqno; it has been incremented by 1 for each
+ *         packet sent.  That increment may be less than nentries if an
+ *         error occured, or if some of the entries in the vector contain
+ *         handles equal to NETIO_PKT_HANDLE_NONE.  The val1 member is the
+ *         updated value of nentries; it has been decremented by 1 for each
+ *         vector entry processed.  Again, that decrement may be less than
+ *         nentries (leaving the returned value positive) if an error
+ *         occurred.
+ */
+#define __netio_fastio_send_pkt_vec(fastio_index, seqno, nentries, va) \
+  __netio_fastio3_rv3((fastio_index) + NETIO_FASTIO_SEND_PKT_VEC, seqno, \
+                      nentries, va)
+
+
+/** An egress DMA command for LEPP. */
+typedef struct
+{
+  /** Is this a TSO transfer?
+   *
+   * NOTE: This field is always 0, to distinguish it from
+   * lepp_tso_cmd_t.  It must come first!
+   */
+  uint8_t tso               : 1;
+
+  /** Unused padding bits. */
+  uint8_t _unused           : 3;
+
+  /** Should this packet be sent directly from caches instead of DRAM,
+   * using hash-for-home to locate the packet data?
+   */
+  uint8_t hash_for_home     : 1;
+
+  /** Should we compute a checksum? */
+  uint8_t compute_checksum  : 1;
+
+  /** Is this the final buffer for this packet?
+   *
+   * A single packet can be split over several input buffers (a "gather"
+   * operation).  This flag indicates that this is the last buffer
+   * in a packet.
+   */
+  uint8_t end_of_packet     : 1;
+
+  /** Should LEPP advance 'comp_busy' when this DMA is fully finished? */
+  uint8_t send_completion   : 1;
+
+  /** High bits of Client Physical Address of the start of the buffer
+   *  to be egressed.
+   *
+   *  NOTE: Only 6 bits are actually needed here, as CPAs are
+   *  currently 38 bits.  So two bits could be scavenged from this.
+   */
+  uint8_t cpa_hi;
+
+  /** The number of bytes to be egressed. */
+  uint16_t length;
+
+  /** Low 32 bits of Client Physical Address of the start of the buffer
+   *  to be egressed.
+   */
+  uint32_t cpa_lo;
+
+  /** Checksum information (only used if 'compute_checksum'). */
+  __netio_checksum_header_t checksum_data;
+
+} lepp_cmd_t;
+
+
+/** A chunk of physical memory for a TSO egress. */
+typedef struct
+{
+  /** The low bits of the CPA. */
+  uint32_t cpa_lo;
+  /** The high bits of the CPA. */
+  uint16_t cpa_hi		: 15;
+  /** Should this packet be sent directly from caches instead of DRAM,
+   *  using hash-for-home to locate the packet data?
+   */
+  uint16_t hash_for_home	: 1;
+  /** The length in bytes. */
+  uint16_t length;
+} lepp_frag_t;
+
+
+/** An LEPP command that handles TSO. */
+typedef struct
+{
+  /** Is this a TSO transfer?
+   *
+   *  NOTE: This field is always 1, to distinguish it from
+   *  lepp_cmd_t.  It must come first!
+   */
+  uint8_t tso             : 1;
+
+  /** Unused padding bits. */
+  uint8_t _unused         : 7;
+
+  /** Size of the header[] array in bytes.  It must be in the range
+   *  [40, 127], which are the smallest header for a TCP packet over
+   *  Ethernet and the maximum possible prepend size supported by
+   *  hardware, respectively.  Note that the array storage must be
+   *  padded out to a multiple of four bytes so that the following
+   *  LEPP command is aligned properly.
+   */
+  uint8_t header_size;
+
+  /** Byte offset of the IP header in header[]. */
+  uint8_t ip_offset;
+
+  /** Byte offset of the TCP header in header[]. */
+  uint8_t tcp_offset;
+
+  /** The number of bytes to use for the payload of each packet,
+   *  except of course the last one, which may not have enough bytes.
+   *  This means that each Ethernet packet except the last will have a
+   *  size of header_size + payload_size.
+   */
+  uint16_t payload_size;
+
+  /** The length of the 'frags' array that follows this struct. */
+  uint16_t num_frags;
+
+  /** The actual frags. */
+  lepp_frag_t frags[0 /* Variable-sized; num_frags entries. */];
+
+  /*
+   * The packet header template logically follows frags[],
+   * but you can't declare that in C.
+   *
+   * uint32_t header[header_size_in_words_rounded_up];
+   */
+
+} lepp_tso_cmd_t;
+
+
+/** An LEPP completion ring entry. */
+typedef void* lepp_comp_t;
+
+
+/** Maximum number of frags for one TSO command.  This is adapted from
+ *  linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for
+ *  our page size of exactly 65536.  We add one for a "body" fragment.
+ */
+#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1)
+
+/** Total number of bytes needed for an lepp_tso_cmd_t. */
+#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \
+  (sizeof(lepp_tso_cmd_t) + \
+   (num_frags) * sizeof(lepp_frag_t) + \
+   (((header_size) + 3) & -4))
+
+/** The size of the lepp "cmd" queue. */
+#define LEPP_CMD_QUEUE_BYTES \
+ (((CHIP_L2_CACHE_SIZE() - 2 * CHIP_L2_LINE_SIZE()) / \
+  (sizeof(lepp_cmd_t) + sizeof(lepp_comp_t))) * sizeof(lepp_cmd_t))
+
+/** The largest possible command that can go in lepp_queue_t::cmds[]. */
+#define LEPP_MAX_CMD_SIZE LEPP_TSO_CMD_SIZE(LEPP_MAX_FRAGS, 128)
+
+/** The largest possible value of lepp_queue_t::cmd_{head, tail} (inclusive).
+ */
+#define LEPP_CMD_LIMIT \
+  (LEPP_CMD_QUEUE_BYTES - LEPP_MAX_CMD_SIZE)
+
+/** The maximum number of completions in an LEPP queue. */
+#define LEPP_COMP_QUEUE_SIZE \
+  ((LEPP_CMD_LIMIT + sizeof(lepp_cmd_t) - 1) / sizeof(lepp_cmd_t))
+
+/** Increment an index modulo the queue size. */
+#define LEPP_QINC(var) \
+  (var = __insn_mnz(var - (LEPP_COMP_QUEUE_SIZE - 1), var + 1))
+
+/** A queue used to convey egress commands from the client to LEPP. */
+typedef struct
+{
+  /** Index of first completion not yet processed by user code.
+   *  If this is equal to comp_busy, there are no such completions.
+   *
+   *  NOTE: This is only read/written by the user.
+   */
+  unsigned int comp_head;
+
+  /** Index of first completion record not yet completed.
+   *  If this is equal to comp_tail, there are no such completions.
+   *  This index gets advanced (modulo LEPP_QUEUE_SIZE) whenever
+   *  a command with the 'completion' bit set is finished.
+   *
+   *  NOTE: This is only written by LEPP, only read by the user.
+   */
+  volatile unsigned int comp_busy;
+
+  /** Index of the first empty slot in the completion ring.
+   *  Entries from this up to but not including comp_head (in ring order)
+   *  can be filled in with completion data.
+   *
+   *  NOTE: This is only read/written by the user.
+   */
+  unsigned int comp_tail;
+
+  /** Byte index of first command enqueued for LEPP but not yet processed.
+   *
+   *  This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT.
+   *
+   *  NOTE: LEPP advances this counter as soon as it no longer needs
+   *  the cmds[] storage for this entry, but the transfer is not actually
+   *  complete (i.e. the buffer pointed to by the command is no longer
+   *  needed) until comp_busy advances.
+   *
+   *  If this is equal to cmd_tail, the ring is empty.
+   *
+   *  NOTE: This is only written by LEPP, only read by the user.
+   */
+  volatile unsigned int cmd_head;
+
+  /** Byte index of first empty slot in the command ring.  This field can
+   *  be incremented up to but not equal to cmd_head (because that would
+   *  mean the ring is empty).
+   *
+   *  This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT.
+   *
+   *  NOTE: This is read/written by the user, only read by LEPP.
+   */
+  volatile unsigned int cmd_tail;
+
+  /** A ring of variable-sized egress DMA commands.
+   *
+   *  NOTE: Only written by the user, only read by LEPP.
+   */
+  char cmds[LEPP_CMD_QUEUE_BYTES]
+    __attribute__((aligned(CHIP_L2_LINE_SIZE())));
+
+  /** A ring of user completion data.
+   *  NOTE: Only read/written by the user.
+   */
+  lepp_comp_t comps[LEPP_COMP_QUEUE_SIZE]
+    __attribute__((aligned(CHIP_L2_LINE_SIZE())));
+} lepp_queue_t;
+
+
+/** An internal helper function for determining the number of entries
+ *  available in a ring buffer, given that there is one sentinel.
+ */
+static inline unsigned int
+_lepp_num_free_slots(unsigned int head, unsigned int tail)
+{
+  /*
+   * One entry is reserved for use as a sentinel, to distinguish
+   * "empty" from "full".  So we compute
+   * (head - tail - 1) % LEPP_QUEUE_SIZE, but without using a slow % operation.
+   */
+  return (head - tail - 1) + ((head <= tail) ? LEPP_COMP_QUEUE_SIZE : 0);
+}
+
+
+/** Returns how many new comp entries can be enqueued. */
+static inline unsigned int
+lepp_num_free_comp_slots(const lepp_queue_t* q)
+{
+  return _lepp_num_free_slots(q->comp_head, q->comp_tail);
+}
+
+static inline int
+lepp_qsub(int v1, int v2)
+{
+  int delta = v1 - v2;
+  return delta + ((delta >> 31) & LEPP_COMP_QUEUE_SIZE);
+}
+
+
+/** FIXME: Check this from linux, via a new "pwrite()" call. */
+#define LIPP_VERSION 1
+
+
+/** We use exactly two bytes of alignment padding. */
+#define LIPP_PACKET_PADDING 2
+
+/** The minimum size of a "small" buffer (including the padding). */
+#define LIPP_SMALL_PACKET_SIZE 128
+
+/*
+ * NOTE: The following two values should total to less than around
+ * 13582, to keep the total size used for "lipp_state_t" below 64K.
+ */
+
+/** The maximum number of "small" buffers.
+ *  This is enough for 53 network cpus with 128 credits.  Note that
+ *  if these are exhausted, we will fall back to using large buffers.
+ */
+#define LIPP_SMALL_BUFFERS 6785
+
+/** The maximum number of "large" buffers.
+ *  This is enough for 53 network cpus with 128 credits.
+ */
+#define LIPP_LARGE_BUFFERS 6785
+
+#endif /* __DRV_XGBE_INTF_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/hv/hypervisor.h linux-libre-2.6.37-gnu/arch/tile/include/hv/hypervisor.h
--- linux-libre-2.6.36-gnu/arch/tile/include/hv/hypervisor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/include/hv/hypervisor.h	2011-01-04 19:50:19.000000000 -0500
@@ -1003,37 +1003,37 @@
  *  when these occur in a client's interrupt critical section, they must
  *  be delivered through the downcall mechanism.
  *
- *  A downcall is initially delivered to the client as an INTCTRL_1
- *  interrupt.  Upon entry to the INTCTRL_1 vector, the client must
- *  immediately invoke the hv_downcall_dispatch service.  This service
- *  will not return; instead it will cause one of the client's actual
- *  downcall-handling interrupt vectors to be entered.  The EX_CONTEXT
- *  registers in the client will be set so that when the client irets,
- *  it will return to the code which was interrupted by the INTCTRL_1
- *  interrupt.
+ *  A downcall is initially delivered to the client as an INTCTRL_CL
+ *  interrupt, where CL is the client's PL.  Upon entry to the INTCTRL_CL
+ *  vector, the client must immediately invoke the hv_downcall_dispatch
+ *  service.  This service will not return; instead it will cause one of
+ *  the client's actual downcall-handling interrupt vectors to be entered.
+ *  The EX_CONTEXT registers in the client will be set so that when the
+ *  client irets, it will return to the code which was interrupted by the
+ *  INTCTRL_CL interrupt.
  *
- *  Under some circumstances, the firing of INTCTRL_1 can race with
+ *  Under some circumstances, the firing of INTCTRL_CL can race with
  *  the lowering of a device interrupt.  In such a case, the
  *  hv_downcall_dispatch service may issue an iret instruction instead
  *  of entering one of the client's actual downcall-handling interrupt
  *  vectors.  This will return execution to the location that was
- *  interrupted by INTCTRL_1.
+ *  interrupted by INTCTRL_CL.
  *
  *  Any saving of registers should be done by the actual handling
- *  vectors; no registers should be changed by the INTCTRL_1 handler.
+ *  vectors; no registers should be changed by the INTCTRL_CL handler.
  *  In particular, the client should not use a jal instruction to invoke
  *  the hv_downcall_dispatch service, as that would overwrite the client's
  *  lr register.  Note that the hv_downcall_dispatch service may overwrite
  *  one or more of the client's system save registers.
  *
- *  The client must not modify the INTCTRL_1_STATUS SPR.  The hypervisor
+ *  The client must not modify the INTCTRL_CL_STATUS SPR.  The hypervisor
  *  will set this register to cause a downcall to happen, and will clear
  *  it when no further downcalls are pending.
  *
- *  When a downcall vector is entered, the INTCTRL_1 interrupt will be
+ *  When a downcall vector is entered, the INTCTRL_CL interrupt will be
  *  masked.  When the client is done processing a downcall, and is ready
  *  to accept another, it must unmask this interrupt; if more downcalls
- *  are pending, this will cause the INTCTRL_1 vector to be reentered.
+ *  are pending, this will cause the INTCTRL_CL vector to be reentered.
  *  Currently the following interrupt vectors can be entered through a
  *  downcall:
  *
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/hv/netio_errors.h linux-libre-2.6.37-gnu/arch/tile/include/hv/netio_errors.h
--- linux-libre-2.6.36-gnu/arch/tile/include/hv/netio_errors.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/include/hv/netio_errors.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * Error codes returned from NetIO routines.
+ */
+
+#ifndef __NETIO_ERRORS_H__
+#define __NETIO_ERRORS_H__
+
+/**
+ * @addtogroup error
+ *
+ * @brief The error codes returned by NetIO functions.
+ *
+ * NetIO functions return 0 (defined as ::NETIO_NO_ERROR) on success, and
+ * a negative value if an error occurs.
+ *
+ * In cases where a NetIO function failed due to a error reported by
+ * system libraries, the error code will be the negation of the
+ * system errno at the time of failure.  The @ref netio_strerror()
+ * function will deliver error strings for both NetIO and system error
+ * codes.
+ *
+ * @{
+ */
+
+/** The set of all NetIO errors. */
+typedef enum
+{
+  /** Operation successfully completed. */
+  NETIO_NO_ERROR        = 0,
+
+  /** A packet was successfully retrieved from an input queue. */
+  NETIO_PKT             = 0,
+
+  /** Largest NetIO error number. */
+  NETIO_ERR_MAX         = -701,
+
+  /** The tile is not registered with the IPP. */
+  NETIO_NOT_REGISTERED  = -701,
+
+  /** No packet was available to retrieve from the input queue. */
+  NETIO_NOPKT           = -702,
+
+  /** The requested function is not implemented. */
+  NETIO_NOT_IMPLEMENTED = -703,
+
+  /** On a registration operation, the target queue already has the maximum
+   *  number of tiles registered for it, and no more may be added.  On a
+   *  packet send operation, the output queue is full and nothing more can
+   *  be queued until some of the queued packets are actually transmitted. */
+  NETIO_QUEUE_FULL      = -704,
+
+  /** The calling process or thread is not bound to exactly one CPU. */
+  NETIO_BAD_AFFINITY    = -705,
+
+  /** Cannot allocate memory on requested controllers. */
+  NETIO_CANNOT_HOME     = -706,
+
+  /** On a registration operation, the IPP specified is not configured
+   *  to support the options requested; for instance, the application
+   *  wants a specific type of tagged headers which the configured IPP
+   *  doesn't support.  Or, the supplied configuration information is
+   *  not self-consistent, or is out of range; for instance, specifying
+   *  both NETIO_RECV and NETIO_NO_RECV, or asking for more than
+   *  NETIO_MAX_SEND_BUFFERS to be preallocated.  On a VLAN or bucket
+   *  configure operation, the number of items, or the base item, was
+   *  out of range.
+   */
+  NETIO_BAD_CONFIG      = -707,
+
+  /** Too many tiles have registered to transmit packets. */
+  NETIO_TOOMANY_XMIT    = -708,
+
+  /** Packet transmission was attempted on a queue which was registered
+      with transmit disabled. */
+  NETIO_UNREG_XMIT      = -709,
+
+  /** This tile is already registered with the IPP. */
+  NETIO_ALREADY_REGISTERED = -710,
+
+  /** The Ethernet link is down. The application should try again later. */
+  NETIO_LINK_DOWN       = -711,
+
+  /** An invalid memory buffer has been specified.  This may be an unmapped
+   * virtual address, or one which does not meet alignment requirements.
+   * For netio_input_register(), this error may be returned when multiple
+   * processes specify different memory regions to be used for NetIO
+   * buffers.  That can happen if these processes specify explicit memory
+   * regions with the ::NETIO_FIXED_BUFFER_VA flag, or if tmc_cmem_init()
+   * has not been called by a common ancestor of the processes.
+   */
+  NETIO_FAULT           = -712,
+
+  /** Cannot combine user-managed shared memory and cache coherence. */
+  NETIO_BAD_CACHE_CONFIG = -713,
+
+  /** Smallest NetIO error number. */
+  NETIO_ERR_MIN         = -713,
+
+#ifndef __DOXYGEN__
+  /** Used internally to mean that no response is needed; never returned to
+   *  an application. */
+  NETIO_NO_RESPONSE     = 1
+#endif
+} netio_error_t;
+
+/** @} */
+
+#endif /* __NETIO_ERRORS_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/include/hv/netio_intf.h linux-libre-2.6.37-gnu/arch/tile/include/hv/netio_intf.h
--- linux-libre-2.6.36-gnu/arch/tile/include/hv/netio_intf.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/include/hv/netio_intf.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2975 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/**
+ * NetIO interface structures and macros.
+ */
+
+#ifndef __NETIO_INTF_H__
+#define __NETIO_INTF_H__
+
+#include <hv/netio_errors.h>
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__)
+#include <assert.h>
+#define netio_assert assert  /**< Enable assertions from macros */
+#else
+#define netio_assert(...) ((void)(0))  /**< Disable assertions from macros */
+#endif
+
+/*
+ * If none of these symbols are defined, we're building libnetio in an
+ * environment where we have pthreads, so we'll enable locking.
+ */
+#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) && \
+    !defined(__NEWLIB__)
+#define _NETIO_PTHREAD       /**< Include a mutex in netio_queue_t below */
+
+/*
+ * If NETIO_UNLOCKED is defined, we don't do use per-cpu locks on
+ * per-packet NetIO operations.  We still do pthread locking on things
+ * like netio_input_register, though.  This is used for building
+ * libnetio_unlocked.
+ */
+#ifndef NETIO_UNLOCKED
+
+/* Avoid PLT overhead by using our own inlined per-cpu lock. */
+#include <sched.h>
+typedef int _netio_percpu_mutex_t;
+
+static __inline int
+_netio_percpu_mutex_init(_netio_percpu_mutex_t* lock)
+{
+  *lock = 0;
+  return 0;
+}
+
+static __inline int
+_netio_percpu_mutex_lock(_netio_percpu_mutex_t* lock)
+{
+  while (__builtin_expect(__insn_tns(lock), 0))
+    sched_yield();
+  return 0;
+}
+
+static __inline int
+_netio_percpu_mutex_unlock(_netio_percpu_mutex_t* lock)
+{
+  *lock = 0;
+  return 0;
+}
+
+#else /* NETIO_UNLOCKED */
+
+/* Don't do any locking for per-packet NetIO operations. */
+typedef int _netio_percpu_mutex_t;
+#define _netio_percpu_mutex_init(L)
+#define _netio_percpu_mutex_lock(L)
+#define _netio_percpu_mutex_unlock(L)
+
+#endif /* NETIO_UNLOCKED */
+#endif /* !__HV__, !__BOGUX, !__KERNEL__, !__NEWLIB__ */
+
+/** How many tiles can register for a given queue.
+ *  @ingroup setup */
+#define NETIO_MAX_TILES_PER_QUEUE  64
+
+
+/** Largest permissible queue identifier.
+ *  @ingroup setup  */
+#define NETIO_MAX_QUEUE_ID        255
+
+
+#ifndef __DOXYGEN__
+
+/* Metadata packet checksum/ethertype flags. */
+
+/** The L4 checksum has not been calculated. */
+#define _NETIO_PKT_NO_L4_CSUM_SHIFT           0
+#define _NETIO_PKT_NO_L4_CSUM_RMASK           1
+#define _NETIO_PKT_NO_L4_CSUM_MASK \
+         (_NETIO_PKT_NO_L4_CSUM_RMASK << _NETIO_PKT_NO_L4_CSUM_SHIFT)
+
+/** The L3 checksum has not been calculated. */
+#define _NETIO_PKT_NO_L3_CSUM_SHIFT           1
+#define _NETIO_PKT_NO_L3_CSUM_RMASK           1
+#define _NETIO_PKT_NO_L3_CSUM_MASK \
+         (_NETIO_PKT_NO_L3_CSUM_RMASK << _NETIO_PKT_NO_L3_CSUM_SHIFT)
+
+/** The L3 checksum is incorrect (or perhaps has not been calculated). */
+#define _NETIO_PKT_BAD_L3_CSUM_SHIFT          2
+#define _NETIO_PKT_BAD_L3_CSUM_RMASK          1
+#define _NETIO_PKT_BAD_L3_CSUM_MASK \
+         (_NETIO_PKT_BAD_L3_CSUM_RMASK << _NETIO_PKT_BAD_L3_CSUM_SHIFT)
+
+/** The Ethernet packet type is unrecognized. */
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT    3
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_RMASK    1
+#define _NETIO_PKT_TYPE_UNRECOGNIZED_MASK \
+         (_NETIO_PKT_TYPE_UNRECOGNIZED_RMASK << \
+          _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT)
+
+/* Metadata packet type flags. */
+
+/** Where the packet type bits are; this field is the index into
+ *  _netio_pkt_info. */
+#define _NETIO_PKT_TYPE_SHIFT        4
+#define _NETIO_PKT_TYPE_RMASK        0x3F
+
+/** How many VLAN tags the packet has, and, if we have two, which one we
+ *  actually grouped on.  A VLAN within a proprietary (Marvell or Broadcom)
+ *  tag is counted here. */
+#define _NETIO_PKT_VLAN_SHIFT        4
+#define _NETIO_PKT_VLAN_RMASK        0x3
+#define _NETIO_PKT_VLAN_MASK \
+         (_NETIO_PKT_VLAN_RMASK << _NETIO_PKT_VLAN_SHIFT)
+#define _NETIO_PKT_VLAN_NONE         0   /* No VLAN tag. */
+#define _NETIO_PKT_VLAN_ONE          1   /* One VLAN tag. */
+#define _NETIO_PKT_VLAN_TWO_OUTER    2   /* Two VLAN tags, outer one used. */
+#define _NETIO_PKT_VLAN_TWO_INNER    3   /* Two VLAN tags, inner one used. */
+
+/** Which proprietary tags the packet has. */
+#define _NETIO_PKT_TAG_SHIFT         6
+#define _NETIO_PKT_TAG_RMASK         0x3
+#define _NETIO_PKT_TAG_MASK \
+          (_NETIO_PKT_TAG_RMASK << _NETIO_PKT_TAG_SHIFT)
+#define _NETIO_PKT_TAG_NONE          0   /* No proprietary tags. */
+#define _NETIO_PKT_TAG_MRVL          1   /* Marvell HyperG.Stack tags. */
+#define _NETIO_PKT_TAG_MRVL_EXT      2   /* HyperG.Stack extended tags. */
+#define _NETIO_PKT_TAG_BRCM          3   /* Broadcom HiGig tags. */
+
+/** Whether a packet has an LLC + SNAP header. */
+#define _NETIO_PKT_SNAP_SHIFT        8
+#define _NETIO_PKT_SNAP_RMASK        0x1
+#define _NETIO_PKT_SNAP_MASK \
+          (_NETIO_PKT_SNAP_RMASK << _NETIO_PKT_SNAP_SHIFT)
+
+/* NOTE: Bits 9 and 10 are unused. */
+
+/** Length of any custom data before the L2 header, in words. */
+#define _NETIO_PKT_CUSTOM_LEN_SHIFT  11
+#define _NETIO_PKT_CUSTOM_LEN_RMASK  0x1F
+#define _NETIO_PKT_CUSTOM_LEN_MASK \
+          (_NETIO_PKT_CUSTOM_LEN_RMASK << _NETIO_PKT_CUSTOM_LEN_SHIFT)
+
+/** The L4 checksum is incorrect (or perhaps has not been calculated). */
+#define _NETIO_PKT_BAD_L4_CSUM_SHIFT 16
+#define _NETIO_PKT_BAD_L4_CSUM_RMASK 0x1
+#define _NETIO_PKT_BAD_L4_CSUM_MASK \
+          (_NETIO_PKT_BAD_L4_CSUM_RMASK << _NETIO_PKT_BAD_L4_CSUM_SHIFT)
+
+/** Length of the L2 header, in words. */
+#define _NETIO_PKT_L2_LEN_SHIFT  17
+#define _NETIO_PKT_L2_LEN_RMASK  0x1F
+#define _NETIO_PKT_L2_LEN_MASK \
+          (_NETIO_PKT_L2_LEN_RMASK << _NETIO_PKT_L2_LEN_SHIFT)
+
+
+/* Flags in minimal packet metadata. */
+
+/** We need an eDMA checksum on this packet. */
+#define _NETIO_PKT_NEED_EDMA_CSUM_SHIFT            0
+#define _NETIO_PKT_NEED_EDMA_CSUM_RMASK            1
+#define _NETIO_PKT_NEED_EDMA_CSUM_MASK \
+         (_NETIO_PKT_NEED_EDMA_CSUM_RMASK << _NETIO_PKT_NEED_EDMA_CSUM_SHIFT)
+
+/* Data within the packet information table. */
+
+/* Note that, for efficiency, code which uses these fields assumes that none
+ * of the shift values below are zero.  See uses below for an explanation. */
+
+/** Offset within the L2 header of the innermost ethertype (in halfwords). */
+#define _NETIO_PKT_INFO_ETYPE_SHIFT       6
+#define _NETIO_PKT_INFO_ETYPE_RMASK    0x1F
+
+/** Offset within the L2 header of the VLAN tag (in halfwords). */
+#define _NETIO_PKT_INFO_VLAN_SHIFT       11
+#define _NETIO_PKT_INFO_VLAN_RMASK     0x1F
+
+#endif
+
+
+/** The size of a memory buffer representing a small packet.
+ *  @ingroup egress */
+#define SMALL_PACKET_SIZE 256
+
+/** The size of a memory buffer representing a large packet.
+ *  @ingroup egress */
+#define LARGE_PACKET_SIZE 2048
+
+/** The size of a memory buffer representing a jumbo packet.
+ *  @ingroup egress */
+#define JUMBO_PACKET_SIZE (12 * 1024)
+
+
+/* Common ethertypes.
+ * @ingroup ingress */
+/** @{ */
+/** The ethertype of IPv4. */
+#define ETHERTYPE_IPv4 (0x0800)
+/** The ethertype of ARP. */
+#define ETHERTYPE_ARP (0x0806)
+/** The ethertype of VLANs. */
+#define ETHERTYPE_VLAN (0x8100)
+/** The ethertype of a Q-in-Q header. */
+#define ETHERTYPE_Q_IN_Q (0x9100)
+/** The ethertype of IPv6. */
+#define ETHERTYPE_IPv6 (0x86DD)
+/** The ethertype of MPLS. */
+#define ETHERTYPE_MPLS (0x8847)
+/** @} */
+
+
+/** The possible return values of NETIO_PKT_STATUS.
+ * @ingroup ingress
+ */
+typedef enum
+{
+  /** No problems were detected with this packet. */
+  NETIO_PKT_STATUS_OK,
+  /** The packet is undersized; this is expected behavior if the packet's
+    * ethertype is unrecognized, but otherwise the packet is likely corrupt. */
+  NETIO_PKT_STATUS_UNDERSIZE,
+  /** The packet is oversized and some trailing bytes have been discarded.
+      This is expected behavior for short packets, since it's impossible to
+      precisely determine the amount of padding which may have been added to
+      them to make them meet the minimum Ethernet packet size. */
+  NETIO_PKT_STATUS_OVERSIZE,
+  /** The packet was judged to be corrupt by hardware (for instance, it had
+      a bad CRC, or part of it was discarded due to lack of buffer space in
+      the I/O shim) and should be discarded. */
+  NETIO_PKT_STATUS_BAD
+} netio_pkt_status_t;
+
+
+/** Log2 of how many buckets we have. */
+#define NETIO_LOG2_NUM_BUCKETS (10)
+
+/** How many buckets we have.
+ * @ingroup ingress */
+#define NETIO_NUM_BUCKETS (1 << NETIO_LOG2_NUM_BUCKETS)
+
+
+/**
+ * @brief A group-to-bucket identifier.
+ *
+ * @ingroup setup
+ *
+ * This tells us what to do with a given group.
+ */
+typedef union {
+  /** The header broken down into bits. */
+  struct {
+    /** Whether we should balance on L4, if available */
+    unsigned int __balance_on_l4:1;
+    /** Whether we should balance on L3, if available */
+    unsigned int __balance_on_l3:1;
+    /** Whether we should balance on L2, if available */
+    unsigned int __balance_on_l2:1;
+    /** Reserved for future use */
+    unsigned int __reserved:1;
+    /** The base bucket to use to send traffic */
+    unsigned int __bucket_base:NETIO_LOG2_NUM_BUCKETS;
+    /** The mask to apply to the balancing value. This must be one less
+     * than a power of two, e.g. 0x3 or 0xFF.
+     */
+    unsigned int __bucket_mask:NETIO_LOG2_NUM_BUCKETS;
+    /** Pad to 32 bits */
+    unsigned int __padding:(32 - 4 - 2 * NETIO_LOG2_NUM_BUCKETS);
+  } bits;
+  /** To send out the IDN. */
+  unsigned int word;
+}
+netio_group_t;
+
+
+/**
+ * @brief A VLAN-to-bucket identifier.
+ *
+ * @ingroup setup
+ *
+ * This tells us what to do with a given VLAN.
+ */
+typedef netio_group_t netio_vlan_t;
+
+
+/**
+ * A bucket-to-queue mapping.
+ * @ingroup setup
+ */
+typedef unsigned char netio_bucket_t;
+
+
+/**
+ * A packet size can always fit in a netio_size_t.
+ * @ingroup setup
+ */
+typedef unsigned int netio_size_t;
+
+
+/**
+ * @brief Ethernet standard (ingress) packet metadata.
+ *
+ * @ingroup ingress
+ *
+ * This is additional data associated with each packet.
+ * This structure is opaque and accessed through the @ref ingress.
+ *
+ * Also, the buffer population operation currently assumes that standard
+ * metadata is at least as large as minimal metadata, and will need to be
+ * modified if that is no longer the case.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+  /** This structure is opaque. */
+  unsigned char opaque[24];
+#else
+  /** The overall ordinal of the packet */
+  unsigned int __packet_ordinal;
+  /** The ordinal of the packet within the group */
+  unsigned int __group_ordinal;
+  /** The best flow hash IPP could compute. */
+  unsigned int __flow_hash;
+  /** Flags pertaining to checksum calculation, packet type, etc. */
+  unsigned int __flags;
+  /** The first word of "user data". */
+  unsigned int __user_data_0;
+  /** The second word of "user data". */
+  unsigned int __user_data_1;
+#endif
+}
+netio_pkt_metadata_t;
+
+
+/** To ensure that the L3 header is aligned mod 4, the L2 header should be
+ * aligned mod 4 plus 2, since every supported L2 header is 4n + 2 bytes
+ * long.  The standard way to do this is to simply add 2 bytes of padding
+ * before the L2 header.
+ */
+#define NETIO_PACKET_PADDING 2
+
+
+
+/**
+ * @brief Ethernet minimal (egress) packet metadata.
+ *
+ * @ingroup egress
+ *
+ * This structure represents information about packets which have
+ * been processed by @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer().  This structure is opaque
+ * and accessed through the @ref egress.
+ *
+ * @internal This structure is actually copied into the memory used by
+ * standard metadata, which is assumed to be large enough.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+  /** This structure is opaque. */
+  unsigned char opaque[14];
+#else
+  /** The offset of the L2 header from the start of the packet data. */
+  unsigned short l2_offset;
+  /** The offset of the L3 header from the start of the packet data. */
+  unsigned short l3_offset;
+  /** Where to write the checksum. */
+  unsigned char csum_location;
+  /** Where to start checksumming from. */
+  unsigned char csum_start;
+  /** Flags pertaining to checksum calculation etc. */
+  unsigned short flags;
+  /** The L2 length of the packet. */
+  unsigned short l2_length;
+  /** The checksum with which to seed the checksum generator. */
+  unsigned short csum_seed;
+  /** How much to checksum. */
+  unsigned short csum_length;
+#endif
+}
+netio_pkt_minimal_metadata_t;
+
+
+#ifndef __DOXYGEN__
+
+/**
+ * @brief An I/O notification header.
+ *
+ * This is the first word of data received from an I/O shim in a notification
+ * packet. It contains framing and status information.
+ */
+typedef union
+{
+  unsigned int word; /**< The whole word. */
+  /** The various fields. */
+  struct
+  {
+    unsigned int __channel:7;    /**< Resource channel. */
+    unsigned int __type:4;       /**< Type. */
+    unsigned int __ack:1;        /**< Whether an acknowledgement is needed. */
+    unsigned int __reserved:1;   /**< Reserved. */
+    unsigned int __protocol:1;   /**< A protocol-specific word is added. */
+    unsigned int __status:2;     /**< Status of the transfer. */
+    unsigned int __framing:2;    /**< Framing of the transfer. */
+    unsigned int __transfer_size:14; /**< Transfer size in bytes (total). */
+  } bits;
+}
+__netio_pkt_notif_t;
+
+
+/**
+ * Returns the base address of the packet.
+ */
+#define _NETIO_PKT_HANDLE_BASE(p) \
+  ((unsigned char*)((p).word & 0xFFFFFFC0))
+
+/**
+ * Returns the base address of the packet.
+ */
+#define _NETIO_PKT_BASE(p) \
+  _NETIO_PKT_HANDLE_BASE(p->__packet)
+
+/**
+ * @brief An I/O notification packet (second word)
+ *
+ * This is the second word of data received from an I/O shim in a notification
+ * packet.  This is the virtual address of the packet buffer, plus some flag
+ * bits.  (The virtual address of the packet is always 256-byte aligned so we
+ * have room for 8 bits' worth of flags in the low 8 bits.)
+ *
+ * @internal
+ * NOTE: The low two bits must contain "__queue", so the "packet size"
+ * (SIZE_SMALL, SIZE_LARGE, or SIZE_JUMBO) can be determined quickly.
+ *
+ * If __addr or __offset are moved, _NETIO_PKT_BASE
+ * (defined right below this) must be changed.
+ */
+typedef union
+{
+  unsigned int word; /**< The whole word. */
+  /** The various fields. */
+  struct
+  {
+    /** Which queue the packet will be returned to once it is sent back to
+        the IPP.  This is one of the SIZE_xxx values. */
+    unsigned int __queue:2;
+
+    /** The IPP handle of the sending IPP. */
+    unsigned int __ipp_handle:2;
+
+    /** Reserved for future use. */
+    unsigned int __reserved:1;
+
+    /** If 1, this packet has minimal (egress) metadata; otherwise, it
+        has standard (ingress) metadata. */
+    unsigned int __minimal:1;
+
+    /** Offset of the metadata within the packet.  This value is multiplied
+     *  by 64 and added to the base packet address to get the metadata
+     *  address.  Note that this field is aligned within the word such that
+     *  you can easily extract the metadata address with a 26-bit mask. */
+    unsigned int __offset:2;
+
+    /** The top 24 bits of the packet's virtual address. */
+    unsigned int __addr:24;
+  } bits;
+}
+__netio_pkt_handle_t;
+
+#endif /* !__DOXYGEN__ */
+
+
+/**
+ * @brief A handle for an I/O packet's storage.
+ * @ingroup ingress
+ *
+ * netio_pkt_handle_t encodes the concept of a ::netio_pkt_t with its
+ * packet metadata removed.  It is a much smaller type that exists to
+ * facilitate applications where the full ::netio_pkt_t type is too
+ * large, such as those that cache enormous numbers of packets or wish
+ * to transmit packet descriptors over the UDN.
+ *
+ * Because there is no metadata, most ::netio_pkt_t operations cannot be
+ * performed on a netio_pkt_handle_t.  It supports only
+ * netio_free_handle() (to free the buffer) and
+ * NETIO_PKT_CUSTOM_DATA_H() (to access a pointer to its contents).
+ * The application must acquire any additional metadata it wants from the
+ * original ::netio_pkt_t and record it separately.
+ *
+ * A netio_pkt_handle_t can be extracted from a ::netio_pkt_t by calling
+ * NETIO_PKT_HANDLE().  An invalid handle (analogous to NULL) can be
+ * created by assigning the value ::NETIO_PKT_HANDLE_NONE. A handle can
+ * be tested for validity with NETIO_PKT_HANDLE_IS_VALID().
+ */
+typedef struct
+{
+  unsigned int word; /**< Opaque bits. */
+} netio_pkt_handle_t;
+
+/**
+ * @brief A packet descriptor.
+ *
+ * @ingroup ingress
+ * @ingroup egress
+ *
+ * This data structure represents a packet.  The structure is manipulated
+ * through the @ref ingress and the @ref egress.
+ *
+ * While the contents of a netio_pkt_t are opaque, the structure itself is
+ * portable.  This means that it may be shared between all tiles which have
+ * done a netio_input_register() call for the interface on which the pkt_t
+ * was initially received (via netio_get_packet()) or retrieved (via
+ * netio_get_buffer()).  The contents of a netio_pkt_t can be transmitted to
+ * another tile via shared memory, or via a UDN message, or by other means.
+ * The destination tile may then use the pkt_t as if it had originally been
+ * received locally; it may read or write the packet's data, read its
+ * metadata, free the packet, send the packet, transfer the netio_pkt_t to
+ * yet another tile, and so forth.
+ *
+ * Once a netio_pkt_t has been transferred to a second tile, the first tile
+ * should not reference the original copy; in particular, if more than one
+ * tile frees or sends the same netio_pkt_t, the IPP's packet free lists will
+ * become corrupted.  Note also that each tile which reads or modifies
+ * packet data must obey the memory coherency rules outlined in @ref input.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+  /** This structure is opaque. */
+  unsigned char opaque[32];
+#else
+  /** For an ingress packet (one with standard metadata), this is the
+   *  notification header we got from the I/O shim.  For an egress packet
+   *  (one with minimal metadata), this word is zero if the packet has not
+   *  been populated, and nonzero if it has. */
+  __netio_pkt_notif_t __notif_header;
+
+  /** Virtual address of the packet buffer, plus state flags. */
+  __netio_pkt_handle_t __packet;
+
+  /** Metadata associated with the packet. */
+  netio_pkt_metadata_t __metadata;
+#endif
+}
+netio_pkt_t;
+
+
+#ifndef __DOXYGEN__
+
+#define __NETIO_PKT_NOTIF_HEADER(pkt) ((pkt)->__notif_header)
+#define __NETIO_PKT_IPP_HANDLE(pkt) ((pkt)->__packet.bits.__ipp_handle)
+#define __NETIO_PKT_QUEUE(pkt) ((pkt)->__packet.bits.__queue)
+#define __NETIO_PKT_NOTIF_HEADER_M(mda, pkt) ((pkt)->__notif_header)
+#define __NETIO_PKT_IPP_HANDLE_M(mda, pkt) ((pkt)->__packet.bits.__ipp_handle)
+#define __NETIO_PKT_MINIMAL(pkt) ((pkt)->__packet.bits.__minimal)
+#define __NETIO_PKT_QUEUE_M(mda, pkt) ((pkt)->__packet.bits.__queue)
+#define __NETIO_PKT_FLAGS_M(mda, pkt) ((mda)->__flags)
+
+/* Packet information table, used by the attribute access functions below. */
+extern const uint16_t _netio_pkt_info[];
+
+#endif /* __DOXYGEN__ */
+
+
+#ifndef __DOXYGEN__
+/* These macros are deprecated and will disappear in a future MDE release. */
+#define NETIO_PKT_GOOD_CHECKSUM(pkt) \
+  NETIO_PKT_L4_CSUM_CORRECT(pkt)
+#define NETIO_PKT_GOOD_CHECKSUM_M(mda, pkt) \
+  NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt)
+#endif /* __DOXYGEN__ */
+
+
+/* Packet attribute access functions. */
+
+/** Return a pointer to the metadata for a packet.
+ * @ingroup ingress
+ *
+ * Calling this function once and passing the result to other retrieval
+ * functions with a "_M" suffix usually improves performance.  This
+ * function must be called on an 'ingress' packet (i.e. one retrieved
+ * by @ref netio_get_packet(), on which @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer have not been called). Use of this
+ * function on an 'egress' packet will cause an assertion failure.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's standard metadata.
+ */
+static __inline netio_pkt_metadata_t*
+NETIO_PKT_METADATA(netio_pkt_t* pkt)
+{
+  netio_assert(!pkt->__packet.bits.__minimal);
+  return &pkt->__metadata;
+}
+
+
+/** Return a pointer to the minimal metadata for a packet.
+ * @ingroup egress
+ *
+ * Calling this function once and passing the result to other retrieval
+ * functions with a "_MM" suffix usually improves performance.  This
+ * function must be called on an 'egress' packet (i.e. one on which
+ * @ref netio_populate_buffer() or @ref netio_populate_prepend_buffer()
+ * have been called, or one retrieved by @ref netio_get_buffer()). Use of
+ * this function on an 'ingress' packet will cause an assertion failure.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's standard metadata.
+ */
+static __inline netio_pkt_minimal_metadata_t*
+NETIO_PKT_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+  netio_assert(pkt->__packet.bits.__minimal);
+  return (netio_pkt_minimal_metadata_t*) &pkt->__metadata;
+}
+
+
+/** Determine whether a packet has 'minimal' metadata.
+ * @ingroup pktfuncs
+ *
+ * This function will return nonzero if the packet is an 'egress'
+ * packet (i.e. one on which @ref netio_populate_buffer() or
+ * @ref netio_populate_prepend_buffer() have been called, or one
+ * retrieved by @ref netio_get_buffer()), and zero if the packet
+ * is an 'ingress' packet (i.e. one retrieved by @ref netio_get_packet(),
+ * which has not been converted into an 'egress' packet).
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet has minimal metadata.
+ */
+static __inline unsigned int
+NETIO_PKT_IS_MINIMAL(netio_pkt_t* pkt)
+{
+  return pkt->__packet.bits.__minimal;
+}
+
+
+/** Return a handle for a packet's storage.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A handle for the packet's storage.
+ */
+static __inline netio_pkt_handle_t
+NETIO_PKT_HANDLE(netio_pkt_t* pkt)
+{
+  netio_pkt_handle_t h;
+  h.word = pkt->__packet.word;
+  return h;
+}
+
+
+/** A special reserved value indicating the absence of a packet handle.
+ *
+ * @ingroup pktfuncs
+ */
+#define NETIO_PKT_HANDLE_NONE ((netio_pkt_handle_t) { 0 })
+
+
+/** Test whether a packet handle is valid.
+ *
+ * Applications may wish to use the reserved value NETIO_PKT_HANDLE_NONE
+ * to indicate no packet at all.  This function tests to see if a packet
+ * handle is a real handle, not this special reserved value.
+ *
+ * @ingroup pktfuncs
+ *
+ * @param[in] handle Handle on which to operate.
+ * @return One if the packet handle is valid, else zero.
+ */
+static __inline unsigned int
+NETIO_PKT_HANDLE_IS_VALID(netio_pkt_handle_t handle)
+{
+  return handle.word != 0;
+}
+
+
+
+/** Return a pointer to the start of the packet's custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] handle Handle on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA_H(netio_pkt_handle_t handle)
+{
+  return _NETIO_PKT_HANDLE_BASE(handle) + NETIO_PACKET_PADDING;
+}
+
+
+/** Return the length of the packet's custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's custom header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  /*
+   * Note that we effectively need to extract a quantity from the flags word
+   * which is measured in words, and then turn it into bytes by shifting
+   * it left by 2.  We do this all at once by just shifting right two less
+   * bits, and shifting the mask up two bits.
+   */
+  return ((mda->__flags >> (_NETIO_PKT_CUSTOM_LEN_SHIFT - 2)) &
+          (_NETIO_PKT_CUSTOM_LEN_RMASK << 2));
+}
+
+
+/** Return the length of the packet, starting with the custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (__NETIO_PKT_NOTIF_HEADER(pkt).bits.__transfer_size -
+          NETIO_PACKET_PADDING);
+}
+
+
+/** Return a pointer to the start of the packet's custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return NETIO_PKT_CUSTOM_DATA_H(NETIO_PKT_HANDLE(pkt));
+}
+
+
+/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  /*
+   * Note that we effectively need to extract a quantity from the flags word
+   * which is measured in words, and then turn it into bytes by shifting
+   * it left by 2.  We do this all at once by just shifting right two less
+   * bits, and shifting the mask up two bits.  We then add two bytes.
+   */
+  return ((mda->__flags >> (_NETIO_PKT_L2_LEN_SHIFT - 2)) &
+          (_NETIO_PKT_L2_LEN_RMASK << 2)) + 2;
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt) -
+          NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda,pkt));
+}
+
+
+/** Return a pointer to the start of the packet's L2 (Ethernet) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (NETIO_PKT_CUSTOM_DATA_M(mda, pkt) +
+          NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt));
+}
+
+
+/** Retrieve the length of the packet, starting with the L3 (generally,
+ *  the IP) header.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (NETIO_PKT_L2_LENGTH_M(mda, pkt) -
+          NETIO_PKT_L2_HEADER_LENGTH_M(mda,pkt));
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup ingress
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (NETIO_PKT_L2_DATA_M(mda, pkt) +
+          NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt));
+}
+
+
+/** Return the ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given an ordinal number when it is delivered by the IPP.
+ * In the medium term, the ordinal is unique and monotonically increasing,
+ * being incremented by 1 for each packet; the ordinal of the first packet
+ * delivered after the IPP starts is zero.  (Since the ordinal is of finite
+ * size, given enough input packets, it will eventually wrap around to zero;
+ * in the long term, therefore, ordinals are not unique.)  The ordinals
+ * handed out by different IPPs are not disjoint, so two packets from
+ * different IPPs may have identical ordinals.  Packets dropped by the
+ * IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP packet ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return mda->__packet_ordinal;
+}
+
+
+/** Return the per-group ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given a per-group ordinal number when it is
+ * delivered by the IPP. By default, the group is the packet's VLAN,
+ * although IPP can be recompiled to use different values.  In
+ * the medium term, the ordinal is unique and monotonically
+ * increasing, being incremented by 1 for each packet; the ordinal of
+ * the first packet distributed to a particular group is zero.
+ * (Since the ordinal is of finite size, given enough input packets,
+ * it will eventually wrap around to zero; in the long term,
+ * therefore, ordinals are not unique.)  The ordinals handed out by
+ * different IPPs are not disjoint, so two packets from different IPPs
+ * may have identical ordinals; similarly, packets distributed to
+ * different groups may have identical ordinals.  Packets dropped by
+ * the IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP, per-group ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_GROUP_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return mda->__group_ordinal;
+}
+
+
+/** Return the VLAN ID assigned to the packet.
+ * @ingroup ingress
+ *
+ * This value is usually contained within the packet header.
+ *
+ * This value will be zero if the packet does not have a VLAN tag, or if
+ * this value was not extracted from the packet.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's VLAN ID.
+ */
+static __inline unsigned short
+NETIO_PKT_VLAN_ID_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  int vl = (mda->__flags >> _NETIO_PKT_VLAN_SHIFT) & _NETIO_PKT_VLAN_RMASK;
+  unsigned short* pkt_p;
+  int index;
+  unsigned short val;
+
+  if (vl == _NETIO_PKT_VLAN_NONE)
+    return 0;
+
+  pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt);
+  index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK;
+
+  val = pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_VLAN_SHIFT) &
+              _NETIO_PKT_INFO_VLAN_RMASK];
+
+#ifdef __TILECC__
+  return (__insn_bytex(val) >> 16) & 0xFFF;
+#else
+  return (__builtin_bswap32(val) >> 16) & 0xFFF;
+#endif
+}
+
+
+/** Return the ethertype of the packet.
+ * @ingroup ingress
+ *
+ * This value is usually contained within the packet header.
+ *
+ * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED_M()
+ * returns true, and otherwise, may not be well defined.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's ethertype.
+ */
+static __inline unsigned short
+NETIO_PKT_ETHERTYPE_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  unsigned short* pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt);
+  int index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK;
+
+  unsigned short val =
+    pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_ETYPE_SHIFT) &
+          _NETIO_PKT_INFO_ETYPE_RMASK];
+
+  return __builtin_bswap32(val) >> 16;
+}
+
+
+/** Return the flow hash computed on the packet.
+ * @ingroup ingress
+ *
+ * For TCP and UDP packets, this hash is calculated by hashing together
+ * the "5-tuple" values, specifically the source IP address, destination
+ * IP address, protocol type, source port and destination port.
+ * The hash value is intended to be helpful for millions of distinct
+ * flows.
+ *
+ * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is
+ * derived by hashing together the source and destination IP addresses.
+ *
+ * For MPLS-encapsulated packets, the flow hash is derived by hashing
+ * the first MPLS label.
+ *
+ * For all other packets the flow hash is computed from the source
+ * and destination Ethernet addresses.
+ *
+ * The hash is symmetric, meaning it produces the same value if the
+ * source and destination are swapped. The only exceptions are
+ * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple
+ * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32
+ * (Encap Security Payload), which use only the destination address
+ * since the source address is not meaningful.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's 32-bit flow hash.
+ */
+static __inline unsigned int
+NETIO_PKT_FLOW_HASH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return mda->__flow_hash;
+}
+
+
+/** Return the first word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first
+ * word of user data contains the least significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_low()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's first word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_0_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return mda->__user_data_0;
+}
+
+
+/** Return the second word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second
+ * word of user data contains the most significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_high()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's second word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_1_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return mda->__user_data_1;
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L4 checksum was calculated.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return !(mda->__flags & _NETIO_PKT_NO_L4_CSUM_MASK);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to
+ *  be correct.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return !(mda->__flags &
+           (_NETIO_PKT_BAD_L4_CSUM_MASK | _NETIO_PKT_NO_L4_CSUM_MASK));
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L3 (IP) checksum was calculated.
+*/
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return !(mda->__flags & _NETIO_PKT_NO_L3_CSUM_MASK);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated and found to be
+ *  correct.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return !(mda->__flags &
+           (_NETIO_PKT_BAD_L3_CSUM_MASK | _NETIO_PKT_NO_L3_CSUM_MASK));
+}
+
+
+/** Determine whether the ethertype was recognized and L3 packet data was
+ *  processed.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the ethertype was recognized and L3 packet data was
+ *   processed.
+ */
+static __inline unsigned int
+NETIO_PKT_ETHERTYPE_RECOGNIZED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return !(mda->__flags & _NETIO_PKT_TYPE_UNRECOGNIZED_MASK);
+}
+
+
+/** Retrieve the status of a packet and any errors that may have occurred
+ * during ingress processing (length mismatches, CRC errors, etc.).
+ * @ingroup ingress
+ *
+ * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns zero are always reported as underlength, as there is no a priori
+ * means to determine their length.  Normally, applications should use
+ * @ref NETIO_PKT_BAD_M() instead of explicitly checking status with this
+ * function.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's status.
+ */
+static __inline netio_pkt_status_t
+NETIO_PKT_STATUS_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status;
+}
+
+
+/** Report whether a packet is bad (i.e., was shorter than expected based on
+ *  its headers, or had a bad CRC).
+ * @ingroup ingress
+ *
+ * Note that this function does not verify L3 or L4 checksums.
+ *
+ * @param[in] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet is bad and should be discarded.
+ */
+static __inline unsigned int
+NETIO_PKT_BAD_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return ((NETIO_PKT_STATUS_M(mda, pkt) & 1) &&
+          (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt) ||
+           NETIO_PKT_STATUS_M(mda, pkt) == NETIO_PKT_STATUS_BAD));
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+  return mmd->l2_length;
+}
+
+
+/** Return the length of the L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd,
+                              netio_pkt_t* pkt)
+{
+  return mmd->l3_offset - mmd->l2_offset;
+}
+
+
+/** Return the length of the packet, starting with the L3 (IP) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+  return (NETIO_PKT_L2_LENGTH_MM(mmd, pkt) -
+          NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt));
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup egress
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+  return _NETIO_PKT_BASE(pkt) + mmd->l3_offset;
+}
+
+
+/** Return a pointer to the packet's L2 (Ethernet) header.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+  return _NETIO_PKT_BASE(pkt) + mmd->l2_offset;
+}
+
+
+/** Retrieve the status of a packet and any errors that may have occurred
+ * during ingress processing (length mismatches, CRC errors, etc.).
+ * @ingroup ingress
+ *
+ * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns zero are always reported as underlength, as there is no a priori
+ * means to determine their length.  Normally, applications should use
+ * @ref NETIO_PKT_BAD() instead of explicitly checking status with this
+ * function.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's status.
+ */
+static __inline netio_pkt_status_t
+NETIO_PKT_STATUS(netio_pkt_t* pkt)
+{
+  netio_assert(!pkt->__packet.bits.__minimal);
+
+  return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status;
+}
+
+
+/** Report whether a packet is bad (i.e., was shorter than expected based on
+ *  its headers, or had a bad CRC).
+ * @ingroup ingress
+ *
+ * Note that this function does not verify L3 or L4 checksums.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the packet is bad and should be discarded.
+ */
+static __inline unsigned int
+NETIO_PKT_BAD(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_BAD_M(mda, pkt);
+}
+
+
+/** Return the length of the packet's custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's custom header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_HEADER_LENGTH(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt);
+}
+
+
+/** Return the length of the packet, starting with the custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return  The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_CUSTOM_LENGTH(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt);
+}
+
+
+/** Return a pointer to the packet's custom header.
+ *  A custom header may or may not be present, depending upon the IPP; its
+ *  contents and alignment are also IPP-dependent.  Currently, none of the
+ *  standard IPPs supplied by Tilera produce a custom header.  If present,
+ *  the custom header precedes the L2 header in the packet buffer.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_CUSTOM_DATA(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_CUSTOM_DATA_M(mda, pkt);
+}
+
+
+/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The length of the packet's L2 header, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_HEADER_LENGTH(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt);
+  }
+}
+
+
+/** Return the length of the packet, starting with the L2 (Ethernet) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return  The length of the packet, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L2_LENGTH(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_L2_LENGTH_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_L2_LENGTH_M(mda, pkt);
+  }
+}
+
+
+/** Return a pointer to the packet's L2 (Ethernet) header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to start of the packet.
+ */
+static __inline unsigned char*
+NETIO_PKT_L2_DATA(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_L2_DATA_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_L2_DATA_M(mda, pkt);
+  }
+}
+
+
+/** Retrieve the length of the packet, starting with the L3 (generally, the IP)
+ * header.
+ * @ingroup pktfuncs
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Length of the packet's L3 header and data, in bytes.
+ */
+static __inline netio_size_t
+NETIO_PKT_L3_LENGTH(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_L3_LENGTH_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_L3_LENGTH_M(mda, pkt);
+  }
+}
+
+
+/** Return a pointer to the packet's L3 (generally, the IP) header.
+ * @ingroup pktfuncs
+ *
+ * Note that we guarantee word alignment of the L3 header.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return A pointer to the packet's L3 header.
+ */
+static __inline unsigned char*
+NETIO_PKT_L3_DATA(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_L3_DATA_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_L3_DATA_M(mda, pkt);
+  }
+}
+
+
+/** Return the ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given an ordinal number when it is delivered by the IPP.
+ * In the medium term, the ordinal is unique and monotonically increasing,
+ * being incremented by 1 for each packet; the ordinal of the first packet
+ * delivered after the IPP starts is zero.  (Since the ordinal is of finite
+ * size, given enough input packets, it will eventually wrap around to zero;
+ * in the long term, therefore, ordinals are not unique.)  The ordinals
+ * handed out by different IPPs are not disjoint, so two packets from
+ * different IPPs may have identical ordinals.  Packets dropped by the
+ * IPP or by the I/O shim are not assigned ordinals.
+ *
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP packet ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_ORDINAL(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_ORDINAL_M(mda, pkt);
+}
+
+
+/** Return the per-group ordinal of the packet.
+ * @ingroup ingress
+ *
+ * Each packet is given a per-group ordinal number when it is
+ * delivered by the IPP. By default, the group is the packet's VLAN,
+ * although IPP can be recompiled to use different values.  In
+ * the medium term, the ordinal is unique and monotonically
+ * increasing, being incremented by 1 for each packet; the ordinal of
+ * the first packet distributed to a particular group is zero.
+ * (Since the ordinal is of finite size, given enough input packets,
+ * it will eventually wrap around to zero; in the long term,
+ * therefore, ordinals are not unique.)  The ordinals handed out by
+ * different IPPs are not disjoint, so two packets from different IPPs
+ * may have identical ordinals; similarly, packets distributed to
+ * different groups may have identical ordinals.  Packets dropped by
+ * the IPP or by the I/O shim are not assigned ordinals.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's per-IPP, per-group ordinal.
+ */
+static __inline unsigned int
+NETIO_PKT_GROUP_ORDINAL(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_GROUP_ORDINAL_M(mda, pkt);
+}
+
+
+/** Return the VLAN ID assigned to the packet.
+ * @ingroup ingress
+ *
+ * This is usually also contained within the packet header.  If the packet
+ * does not have a VLAN tag, the VLAN ID returned by this function is zero.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's VLAN ID.
+ */
+static __inline unsigned short
+NETIO_PKT_VLAN_ID(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_VLAN_ID_M(mda, pkt);
+}
+
+
+/** Return the ethertype of the packet.
+ * @ingroup ingress
+ *
+ * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED()
+ * returns true, and otherwise, may not be well defined.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's ethertype.
+ */
+static __inline unsigned short
+NETIO_PKT_ETHERTYPE(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_ETHERTYPE_M(mda, pkt);
+}
+
+
+/** Return the flow hash computed on the packet.
+ * @ingroup ingress
+ *
+ * For TCP and UDP packets, this hash is calculated by hashing together
+ * the "5-tuple" values, specifically the source IP address, destination
+ * IP address, protocol type, source port and destination port.
+ * The hash value is intended to be helpful for millions of distinct
+ * flows.
+ *
+ * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is
+ * derived by hashing together the source and destination IP addresses.
+ *
+ * For MPLS-encapsulated packets, the flow hash is derived by hashing
+ * the first MPLS label.
+ *
+ * For all other packets the flow hash is computed from the source
+ * and destination Ethernet addresses.
+ *
+ * The hash is symmetric, meaning it produces the same value if the
+ * source and destination are swapped. The only exceptions are
+ * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple
+ * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32
+ * (Encap Security Payload), which use only the destination address
+ * since the source address is not meaningful.
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's 32-bit flow hash.
+ */
+static __inline unsigned int
+NETIO_PKT_FLOW_HASH(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_FLOW_HASH_M(mda, pkt);
+}
+
+
+/** Return the first word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first
+ * word of user data contains the least significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_low()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's first word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_0(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_USER_DATA_0_M(mda, pkt);
+}
+
+
+/** Return the second word of "user data" for the packet.
+ *
+ * The contents of the user data words depend on the IPP.
+ *
+ * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second
+ * word of user data contains the most significant bits of the 64-bit
+ * arrival cycle count (see @c get_cycle_count_high()).
+ *
+ * See the <em>System Programmer's Guide</em> for details.
+ *
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return The packet's second word of "user data".
+ */
+static __inline unsigned int
+NETIO_PKT_USER_DATA_1(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_USER_DATA_1_M(mda, pkt);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L4 checksum was calculated.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CALCULATED(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_L4_CSUM_CALCULATED_M(mda, pkt);
+}
+
+
+/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to
+ *  be correct.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L4_CSUM_CORRECT(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the L3 (IP) checksum was calculated.
+*/
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CALCULATED(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_L3_CSUM_CALCULATED_M(mda, pkt);
+}
+
+
+/** Determine whether the L3 (IP) checksum was calculated and found to be
+ *  correct.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the checksum was calculated and is correct.
+ */
+static __inline unsigned int
+NETIO_PKT_L3_CSUM_CORRECT(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_L3_CSUM_CORRECT_M(mda, pkt);
+}
+
+
+/** Determine whether the Ethertype was recognized and L3 packet data was
+ *  processed.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ * @return Nonzero if the Ethertype was recognized and L3 packet data was
+ *   processed.
+ */
+static __inline unsigned int
+NETIO_PKT_ETHERTYPE_RECOGNIZED(netio_pkt_t* pkt)
+{
+  netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+  return NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt);
+}
+
+
+/** Set an egress packet's L2 length, using a metadata pointer to speed the
+ * computation.
+ * @ingroup egress
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] len Packet L2 length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt,
+                           int len)
+{
+  mmd->l2_length = len;
+}
+
+
+/** Set an egress packet's L2 length.
+ * @ingroup egress
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] len Packet L2 length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_LENGTH(netio_pkt_t* pkt, int len)
+{
+  netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+  NETIO_PKT_SET_L2_LENGTH_MM(mmd, pkt, len);
+}
+
+
+/** Set an egress packet's L2 header length, using a metadata pointer to
+ *  speed the computation.
+ * @ingroup egress
+ *
+ * It is not normally necessary to call this routine; only the L2 length,
+ * not the header length, is needed to transmit a packet.  It may be useful if
+ * the egress packet will later be processed by code which expects to use
+ * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload.
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] len Packet L2 header length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd,
+                                  netio_pkt_t* pkt, int len)
+{
+  mmd->l3_offset = mmd->l2_offset + len;
+}
+
+
+/** Set an egress packet's L2 header length.
+ * @ingroup egress
+ *
+ * It is not normally necessary to call this routine; only the L2 length,
+ * not the header length, is needed to transmit a packet.  It may be useful if
+ * the egress packet will later be processed by code which expects to use
+ * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload.
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] len Packet L2 header length, in bytes.
+ */
+static __inline void
+NETIO_PKT_SET_L2_HEADER_LENGTH(netio_pkt_t* pkt, int len)
+{
+  netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+  NETIO_PKT_SET_L2_HEADER_LENGTH_MM(mmd, pkt, len);
+}
+
+
+/** Set up an egress packet for hardware checksum computation, using a
+ *  metadata pointer to speed the operation.
+ * @ingroup egress
+ *
+ *  NetIO provides the ability to automatically calculate a standard
+ *  16-bit Internet checksum on transmitted packets.  The application
+ *  may specify the point in the packet where the checksum starts, the
+ *  number of bytes to be checksummed, and the two bytes in the packet
+ *  which will be replaced with the completed checksum.  (If the range
+ *  of bytes to be checksummed includes the bytes to be replaced, the
+ *  initial values of those bytes will be included in the checksum.)
+ *
+ *  For some protocols, the packet checksum covers data which is not present
+ *  in the packet, or is at least not contiguous to the main data payload.
+ *  For instance, the TCP checksum includes a "pseudo-header" which includes
+ *  the source and destination IP addresses of the packet.  To accommodate
+ *  this, the checksum engine may be "seeded" with an initial value, which
+ *  the application would need to compute based on the specific protocol's
+ *  requirements.  Note that the seed is given in host byte order (little-
+ *  endian), not network byte order (big-endian); code written to compute a
+ *  pseudo-header checksum in network byte order will need to byte-swap it
+ *  before use as the seed.
+ *
+ *  Note that the checksum is computed as part of the transmission process,
+ *  so it will not be present in the packet upon completion of this routine.
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ * @param[in] start Offset within L2 packet of the first byte to include in
+ *   the checksum.
+ * @param[in] length Number of bytes to include in the checksum.
+ *   the checksum.
+ * @param[in] location Offset within L2 packet of the first of the two bytes
+ *   to be replaced with the calculated checksum.
+ * @param[in] seed Initial value of the running checksum before any of the
+ *   packet data is added.
+ */
+static __inline void
+NETIO_PKT_DO_EGRESS_CSUM_MM(netio_pkt_minimal_metadata_t* mmd,
+                            netio_pkt_t* pkt, int start, int length,
+                            int location, uint16_t seed)
+{
+  mmd->csum_start = start;
+  mmd->csum_length = length;
+  mmd->csum_location = location;
+  mmd->csum_seed = seed;
+  mmd->flags |= _NETIO_PKT_NEED_EDMA_CSUM_MASK;
+}
+
+
+/** Set up an egress packet for hardware checksum computation.
+ * @ingroup egress
+ *
+ *  NetIO provides the ability to automatically calculate a standard
+ *  16-bit Internet checksum on transmitted packets.  The application
+ *  may specify the point in the packet where the checksum starts, the
+ *  number of bytes to be checksummed, and the two bytes in the packet
+ *  which will be replaced with the completed checksum.  (If the range
+ *  of bytes to be checksummed includes the bytes to be replaced, the
+ *  initial values of those bytes will be included in the checksum.)
+ *
+ *  For some protocols, the packet checksum covers data which is not present
+ *  in the packet, or is at least not contiguous to the main data payload.
+ *  For instance, the TCP checksum includes a "pseudo-header" which includes
+ *  the source and destination IP addresses of the packet.  To accommodate
+ *  this, the checksum engine may be "seeded" with an initial value, which
+ *  the application would need to compute based on the specific protocol's
+ *  requirements.  Note that the seed is given in host byte order (little-
+ *  endian), not network byte order (big-endian); code written to compute a
+ *  pseudo-header checksum in network byte order will need to byte-swap it
+ *  before use as the seed.
+ *
+ *  Note that the checksum is computed as part of the transmission process,
+ *  so it will not be present in the packet upon completion of this routine.
+ *
+ * @param[in,out] pkt Packet on which to operate.
+ * @param[in] start Offset within L2 packet of the first byte to include in
+ *   the checksum.
+ * @param[in] length Number of bytes to include in the checksum.
+ *   the checksum.
+ * @param[in] location Offset within L2 packet of the first of the two bytes
+ *   to be replaced with the calculated checksum.
+ * @param[in] seed Initial value of the running checksum before any of the
+ *   packet data is added.
+ */
+static __inline void
+NETIO_PKT_DO_EGRESS_CSUM(netio_pkt_t* pkt, int start, int length,
+                         int location, uint16_t seed)
+{
+  netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+  NETIO_PKT_DO_EGRESS_CSUM_MM(mmd, pkt, start, length, location, seed);
+}
+
+
+/** Return the number of bytes which could be prepended to a packet, using a
+ *  metadata pointer to speed the operation.
+ *  See @ref netio_populate_prepend_buffer() to get a full description of
+ *  prepending.
+ *
+ * @param[in,out] mda Pointer to packet's standard metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+  return (pkt->__packet.bits.__offset << 6) +
+         NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt);
+}
+
+
+/** Return the number of bytes which could be prepended to a packet, using a
+ *  metadata pointer to speed the operation.
+ *  See @ref netio_populate_prepend_buffer() to get a full description of
+ *  prepending.
+ * @ingroup egress
+ *
+ * @param[in,out] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt)
+{
+  return (pkt->__packet.bits.__offset << 6) + mmd->l2_offset;
+}
+
+
+/** Return the number of bytes which could be prepended to a packet.
+ *  See @ref netio_populate_prepend_buffer() to get a full description of
+ *  prepending.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline int
+NETIO_PKT_PREPEND_AVAIL(netio_pkt_t* pkt)
+{
+  if (NETIO_PKT_IS_MINIMAL(pkt))
+  {
+    netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt);
+
+    return NETIO_PKT_PREPEND_AVAIL_MM(mmd, pkt);
+  }
+  else
+  {
+    netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt);
+
+    return NETIO_PKT_PREPEND_AVAIL_M(mda, pkt);
+  }
+}
+
+
+/** Flush a packet's minimal metadata from the cache, using a metadata pointer
+ *  to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+                                    netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's minimal metadata from the cache, using a metadata
+ *  pointer to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+                                  netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's minimal metadata from the cache,
+ *  using a metadata pointer to speed the operation.
+ * @ingroup egress
+ *
+ * @param[in] mmd Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd,
+                                        netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's metadata from the cache, using a metadata pointer
+ *  to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's minimal metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's metadata from the cache, using a metadata
+ *  pointer to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's metadata from the cache,
+ *  using a metadata pointer to speed the operation.
+ * @ingroup ingress
+ *
+ * @param[in] mda Pointer to packet's metadata.
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's minimal metadata from the cache.
+ * @ingroup egress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_MINIMAL_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Invalidate a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_INV_METADATA(netio_pkt_t* pkt)
+{
+}
+
+
+/** Flush and then invalidate a packet's metadata from the cache.
+ * @ingroup ingress
+ *
+ * @param[in] pkt Packet on which to operate.
+ */
+static __inline void
+NETIO_PKT_FLUSH_INV_METADATA(netio_pkt_t* pkt)
+{
+}
+
+/** Number of NUMA nodes we can distribute buffers to.
+ * @ingroup setup */
+#define NETIO_NUM_NODE_WEIGHTS  16
+
+/**
+ * @brief An object for specifying the characteristics of NetIO communication
+ * endpoint.
+ *
+ * @ingroup setup
+ *
+ * The @ref netio_input_register() function uses this structure to define
+ * how an application tile will communicate with an IPP.
+ *
+ *
+ * Future updates to NetIO may add new members to this structure,
+ * which can affect the success of the registration operation.  Thus,
+ * if dynamically initializing the structure, applications are urged to
+ * zero it out first, for example:
+ *
+ * @code
+ * netio_input_config_t config;
+ * memset(&config, 0, sizeof (config));
+ * config.flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE;
+ * config.num_receive_packets = NETIO_MAX_RECEIVE_PKTS;
+ * config.queue_id = 0;
+ *     .
+ *     .
+ *     .
+ * @endcode
+ *
+ * since that guarantees that any unused structure members, including
+ * members which did not exist when the application was first developed,
+ * will not have unexpected values.
+ *
+ * If statically initializing the structure, we strongly recommend use of
+ * C99-style named initializers, for example:
+ *
+ * @code
+ * netio_input_config_t config = {
+ *    .flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE,
+ *    .num_receive_packets = NETIO_MAX_RECEIVE_PKTS,
+ *    .queue_id = 0,
+ * },
+ * @endcode
+ *
+ * instead of the old-style structure initialization:
+ *
+ * @code
+ * // Bad example! Currently equivalent to the above, but don't do this.
+ * netio_input_config_t config = {
+ *    NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, NETIO_MAX_RECEIVE_PKTS, 0
+ * },
+ * @endcode
+ *
+ * since the C99 style requires no changes to the code if elements of the
+ * config structure are rearranged.  (It also makes the initialization much
+ * easier to understand.)
+ *
+ * Except for items which address a particular tile's transmit or receive
+ * characteristics, such as the ::NETIO_RECV flag, applications are advised
+ * to specify the same set of configuration data on all registrations.
+ * This prevents differing results if multiple tiles happen to do their
+ * registration operations in a different order on different invocations of
+ * the application.  This is particularly important for things like link
+ * management flags, and buffer size and homing specifications.
+ *
+ * Unless the ::NETIO_FIXED_BUFFER_VA flag is specified in flags, the NetIO
+ * buffer pool is automatically created and mapped into the application's
+ * virtual address space at an address chosen by the operating system,
+ * using the common memory (cmem) facility in the Tilera Multicore
+ * Components library.  The cmem facility allows multiple processes to gain
+ * access to shared memory which is mapped into each process at an
+ * identical virtual address.  In order for this to work, the processes
+ * must have a common ancestor, which must create the common memory using
+ * tmc_cmem_init().
+ *
+ * In programs using the iLib process creation API, or in programs which use
+ * only one process (which include programs using the pthreads library),
+ * tmc_cmem_init() is called automatically.  All other applications
+ * must call it explicitly, before any child processes which might call
+ * netio_input_register() are created.
+ */
+typedef struct
+{
+  /** Registration characteristics.
+
+      This value determines several characteristics of the registration;
+      flags for different types of behavior are ORed together to make the
+      final flag value.  Generally applications should specify exactly
+      one flag from each of the following categories:
+
+      - Whether the application will be receiving packets on this queue
+        (::NETIO_RECV or ::NETIO_NO_RECV).
+
+      - Whether the application will be transmitting packets on this queue,
+        and if so, whether it will request egress checksum calculation
+        (::NETIO_XMIT, ::NETIO_XMIT_CSUM, or ::NETIO_NO_XMIT).  It is
+        legal to call netio_get_buffer() without one of the XMIT flags,
+        as long as ::NETIO_RECV is specified; in this case, the retrieved
+        buffers must be passed to another tile for transmission.
+
+      - Whether the application expects any vendor-specific tags in
+        its packets' L2 headers (::NETIO_TAG_NONE, ::NETIO_TAG_BRCM,
+        or ::NETIO_TAG_MRVL).  This must match the configuration of the
+        target IPP.
+
+      To accommodate applications written to previous versions of the NetIO
+      interface, none of the flags above are currently required; if omitted,
+      NetIO behaves more or less as if ::NETIO_RECV | ::NETIO_XMIT_CSUM |
+      ::NETIO_TAG_NONE were used.  However, explicit specification of
+      the relevant flags allows NetIO to do a better job of resource
+      allocation, allows earlier detection of certain configuration errors,
+      and may enable advanced features or higher performance in the future,
+      so their use is strongly recommended.
+
+      Note that specifying ::NETIO_NO_RECV along with ::NETIO_NO_XMIT
+      is a special case, intended primarily for use by programs which
+      retrieve network statistics or do link management operations.
+      When these flags are both specified, the resulting queue may not
+      be used with NetIO routines other than netio_get(), netio_set(),
+      and netio_input_unregister().  See @ref link for more information
+      on link management.
+
+      Other flags are optional; their use is described below.
+  */
+  int flags;
+
+  /** Interface name.  This is a string which identifies the specific
+      Ethernet controller hardware to be used.  The format of the string
+      is a device type and a device index, separated by a slash; so,
+      the first 10 Gigabit Ethernet controller is named "xgbe/0", while
+      the second 10/100/1000 Megabit Ethernet controller is named "gbe/1".
+   */
+  const char* interface;
+
+  /** Receive packet queue size.  This specifies the maximum number
+      of ingress packets that can be received on this queue without
+      being retrieved by @ref netio_get_packet().  If the IPP's distribution
+      algorithm calls for a packet to be sent to this queue, and this
+      number of packets are already pending there, the new packet
+      will either be discarded, or sent to another tile registered
+      for the same queue_id (see @ref drops).  This value must
+      be at least ::NETIO_MIN_RECEIVE_PKTS, can always be at least
+      ::NETIO_MAX_RECEIVE_PKTS, and may be larger than that on certain
+      interfaces.
+   */
+  int num_receive_packets;
+
+  /** The queue ID being requested.  Legal values for this range from 0
+      to ::NETIO_MAX_QUEUE_ID, inclusive.  ::NETIO_MAX_QUEUE_ID is always
+      greater than or equal to the number of tiles; this allows one queue
+      for each tile, plus at least one additional queue.  Some applications
+      may wish to use the additional queue as a destination for unwanted
+      packets, since packets delivered to queues for which no tiles have
+      registered are discarded.
+   */
+  unsigned int queue_id;
+
+  /** Maximum number of small send buffers to be held in the local empty
+      buffer cache.  This specifies the size of the area which holds
+      empty small egress buffers requested from the IPP but not yet
+      retrieved via @ref netio_get_buffer().  This value must be greater
+      than zero if the application will ever use @ref netio_get_buffer()
+      to allocate empty small egress buffers; it may be no larger than
+      ::NETIO_MAX_SEND_BUFFERS.  See @ref epp for more details on empty
+      buffer caching.
+   */
+  int num_send_buffers_small_total;
+
+  /** Number of small send buffers to be preallocated at registration.
+      If this value is nonzero, the specified number of empty small egress
+      buffers will be requested from the IPP during the netio_input_register
+      operation; this may speed the execution of @ref netio_get_buffer().
+      This may be no larger than @ref num_send_buffers_small_total.  See @ref
+      epp for more details on empty buffer caching.
+   */
+  int num_send_buffers_small_prealloc;
+
+  /** Maximum number of large send buffers to be held in the local empty
+      buffer cache.  This specifies the size of the area which holds empty
+      large egress buffers requested from the IPP but not yet retrieved via
+      @ref netio_get_buffer().  This value must be greater than zero if the
+      application will ever use @ref netio_get_buffer() to allocate empty
+      large egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS.
+      See @ref epp for more details on empty buffer caching.
+   */
+  int num_send_buffers_large_total;
+
+  /** Number of large send buffers to be preallocated at registration.
+      If this value is nonzero, the specified number of empty large egress
+      buffers will be requested from the IPP during the netio_input_register
+      operation; this may speed the execution of @ref netio_get_buffer().
+      This may be no larger than @ref num_send_buffers_large_total.  See @ref
+      epp for more details on empty buffer caching.
+   */
+  int num_send_buffers_large_prealloc;
+
+  /** Maximum number of jumbo send buffers to be held in the local empty
+      buffer cache.  This specifies the size of the area which holds empty
+      jumbo egress buffers requested from the IPP but not yet retrieved via
+      @ref netio_get_buffer().  This value must be greater than zero if the
+      application will ever use @ref netio_get_buffer() to allocate empty
+      jumbo egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS.
+      See @ref epp for more details on empty buffer caching.
+   */
+  int num_send_buffers_jumbo_total;
+
+  /** Number of jumbo send buffers to be preallocated at registration.
+      If this value is nonzero, the specified number of empty jumbo egress
+      buffers will be requested from the IPP during the netio_input_register
+      operation; this may speed the execution of @ref netio_get_buffer().
+      This may be no larger than @ref num_send_buffers_jumbo_total.  See @ref
+      epp for more details on empty buffer caching.
+   */
+  int num_send_buffers_jumbo_prealloc;
+
+  /** Total packet buffer size.  This determines the total size, in bytes,
+      of the NetIO buffer pool.  Note that the maximum number of available
+      buffers of each size is determined during hypervisor configuration
+      (see the <em>System Programmer's Guide</em> for details); this just
+      influences how much host memory is allocated for those buffers.
+
+      The buffer pool is allocated from common memory, which will be
+      automatically initialized if needed.  If your buffer pool is larger
+      than 240 MB, you might need to explicitly call @c tmc_cmem_init(),
+      as described in the Application Libraries Reference Manual (UG227).
+
+      Packet buffers are currently allocated in chunks of 16 MB; this
+      value will be rounded up to the next larger multiple of 16 MB.
+      If this value is zero, a default of 32 MB will be used; this was
+      the value used by previous versions of NetIO.  Note that taking this
+      default also affects the placement of buffers on Linux NUMA nodes.
+      See @ref buffer_node_weights for an explanation of buffer placement.
+
+      In order to successfully allocate packet buffers, Linux must have
+      available huge pages on the relevant Linux NUMA nodes.  See the
+      <em>System Programmer's Guide</em> for information on configuring
+      huge page support in Linux.
+   */
+  uint64_t total_buffer_size;
+
+  /** Buffer placement weighting factors.
+
+      This array specifies the relative amount of buffering to place
+      on each of the available Linux NUMA nodes.  This array is
+      indexed by the NUMA node, and the values in the array are
+      proportional to the amount of buffer space to allocate on that
+      node.
+
+      If memory striping is enabled in the Hypervisor, then there is
+      only one logical NUMA node (node 0). In that case, NetIO will by
+      default ignore the suggested buffer node weights, and buffers
+      will be striped across the physical memory controllers. See
+      UG209 System Programmer's Guide for a description of the
+      hypervisor option that controls memory striping.
+
+      If memory striping is disabled, then there are up to four NUMA
+      nodes, corresponding to the four DDRAM controllers in the TILE
+      processor architecture.  See UG100 Tile Processor Architecture
+      Overview for a diagram showing the location of each of the DDRAM
+      controllers relative to the tile array.
+
+      For instance, if memory striping is disabled, the following
+      configuration strucure:
+
+      @code
+      netio_input_config_t config = {
+            .
+            .
+            .
+        .total_buffer_size = 4 * 16 * 1024 * 1024;
+        .buffer_node_weights = { 1, 0, 1, 0 },
+      },
+      @endcode
+
+      would result in 32 MB of buffers being placed on controller 0, and
+      32 MB on controller 2.  (Since buffers are allocated in units of
+      16 MB, some sets of weights will not be able to be matched exactly.)
+
+      For the weights to be effective, @ref total_buffer_size must be
+      nonzero.  If @ref total_buffer_size is zero, causing the default
+      32 MB of buffer space to be used, then any specified weights will
+      be ignored, and buffers will positioned as they were in previous
+      versions of NetIO:
+
+      - For xgbe/0 and gbe/0, 16 MB of buffers will be placed on controller 1,
+        and the other 16 MB will be placed on controller 2.
+
+      - For xgbe/1 and gbe/1, 16 MB of buffers will be placed on controller 2,
+        and the other 16 MB will be placed on controller 3.
+
+      If @ref total_buffer_size is nonzero, but all weights are zero,
+      then all buffer space will be allocated on Linux NUMA node zero.
+
+      By default, the specified buffer placement is treated as a hint;
+      if sufficient free memory is not available on the specified
+      controllers, the buffers will be allocated elsewhere.  However,
+      if the ::NETIO_STRICT_HOMING flag is specified in @ref flags, then a
+      failure to allocate buffer space exactly as requested will cause the
+      registration operation to fail with an error of ::NETIO_CANNOT_HOME.
+
+      Note that maximal network performance cannot be achieved with
+      only one memory controller.
+   */
+  uint8_t buffer_node_weights[NETIO_NUM_NODE_WEIGHTS];
+
+  /** Fixed virtual address for packet buffers.  Only valid when
+      ::NETIO_FIXED_BUFFER_VA is specified in @ref flags; see the
+      description of that flag for details.
+   */
+  void* fixed_buffer_va;
+
+  /**
+      Maximum number of outstanding send packet requests.  This value is
+      only relevant when an EPP is in use; it determines the number of
+      slots in the EPP's outgoing packet queue which this tile is allowed
+      to consume, and thus the number of packets which may be sent before
+      the sending tile must wait for an acknowledgment from the EPP.
+      Modifying this value is generally only helpful when using @ref
+      netio_send_packet_vector(), where it can help improve performance by
+      allowing a single vector send operation to process more packets.
+      Typically it is not specified, and the default, which divides the
+      outgoing packet slots evenly between all tiles on the chip, is used.
+
+      If a registration asks for more outgoing packet queue slots than are
+      available, ::NETIO_TOOMANY_XMIT will be returned.  The total number
+      of packet queue slots which are available for all tiles for each EPP
+      is subject to change, but is currently ::NETIO_TOTAL_SENDS_OUTSTANDING.
+
+
+      This value is ignored if ::NETIO_XMIT is not specified in flags.
+      If you want to specify a large value here for a specific tile, you are
+      advised to specify NETIO_NO_XMIT on other, non-transmitting tiles so
+      that they do not consume a default number of packet slots.  Any tile
+      transmitting is required to have at least ::NETIO_MIN_SENDS_OUTSTANDING
+      slots allocated to it; values less than that will be silently
+      increased by the NetIO library.
+   */
+  int num_sends_outstanding;
+}
+netio_input_config_t;
+
+
+/** Registration flags; used in the @ref netio_input_config_t structure.
+ * @addtogroup setup
+ */
+/** @{ */
+
+/** Fail a registration request if we can't put packet buffers
+    on the specified memory controllers. */
+#define NETIO_STRICT_HOMING   0x00000002
+
+/** This application expects no tags on its L2 headers. */
+#define NETIO_TAG_NONE        0x00000004
+
+/** This application expects Marvell extended tags on its L2 headers. */
+#define NETIO_TAG_MRVL        0x00000008
+
+/** This application expects Broadcom tags on its L2 headers. */
+#define NETIO_TAG_BRCM        0x00000010
+
+/** This registration may call routines which receive packets. */
+#define NETIO_RECV            0x00000020
+
+/** This registration may not call routines which receive packets. */
+#define NETIO_NO_RECV         0x00000040
+
+/** This registration may call routines which transmit packets. */
+#define NETIO_XMIT            0x00000080
+
+/** This registration may call routines which transmit packets with
+    checksum acceleration. */
+#define NETIO_XMIT_CSUM       0x00000100
+
+/** This registration may not call routines which transmit packets. */
+#define NETIO_NO_XMIT         0x00000200
+
+/** This registration wants NetIO buffers mapped at an application-specified
+    virtual address.
+
+    NetIO buffers are by default created by the TMC common memory facility,
+    which must be configured by a common ancestor of all processes sharing
+    a network interface.  When this flag is specified, NetIO buffers are
+    instead mapped at an address chosen by the application (and specified
+    in @ref netio_input_config_t::fixed_buffer_va).  This allows multiple
+    unrelated but cooperating processes to share a NetIO interface.
+    All processes sharing the same interface must specify this flag,
+    and all must specify the same fixed virtual address.
+
+    @ref netio_input_config_t::fixed_buffer_va must be a
+    multiple of 16 MB, and the packet buffers will occupy @ref
+    netio_input_config_t::total_buffer_size bytes of virtual address
+    space, beginning at that address.  If any of those virtual addresses
+    are currently occupied by other memory objects, like application or
+    shared library code or data, @ref netio_input_register() will return
+    ::NETIO_FAULT.  While it is impossible to provide a fixed_buffer_va
+    which will work for all applications, a good first guess might be to
+    use 0xb0000000 minus @ref netio_input_config_t::total_buffer_size.
+    If that fails, it might be helpful to consult the running application's
+    virtual address description file (/proc/<em>pid</em>/maps) to see
+    which regions of virtual address space are available.
+ */
+#define NETIO_FIXED_BUFFER_VA 0x00000400
+
+/** This registration call will not complete unless the network link
+    is up.  The process will wait several seconds for this to happen (the
+    precise interval is link-dependent), but if the link does not come up,
+    ::NETIO_LINK_DOWN will be returned.  This flag is the default if
+    ::NETIO_NOREQUIRE_LINK_UP is not specified.  Note that this flag by
+    itself does not request that the link be brought up; that can be done
+    with the ::NETIO_AUTO_LINK_UPDN or ::NETIO_AUTO_LINK_UP flags (the
+    latter is the default if no NETIO_AUTO_LINK_xxx flags are specified),
+    or by explicitly setting the link's desired state via netio_set().
+    If the link is not brought up by one of those methods, and this flag
+    is specified, the registration operation will return ::NETIO_LINK_DOWN.
+    This flag is ignored if it is specified along with ::NETIO_NO_XMIT and
+    ::NETIO_NO_RECV.  See @ref link for more information on link
+    management.
+ */
+#define NETIO_REQUIRE_LINK_UP    0x00000800
+
+/** This registration call will complete even if the network link is not up.
+    Whenever the link is not up, packets will not be sent or received:
+    netio_get_packet() will return ::NETIO_NOPKT once all queued packets
+    have been drained, and netio_send_packet() and similar routines will
+    return NETIO_QUEUE_FULL once the outgoing packet queue in the EPP
+    or the I/O shim is full.  See @ref link for more information on link
+    management.
+ */
+#define NETIO_NOREQUIRE_LINK_UP  0x00001000
+
+#ifndef __DOXYGEN__
+/*
+ * These are part of the implementation of the NETIO_AUTO_LINK_xxx flags,
+ * but should not be used directly by applications, and are thus not
+ * documented.
+ */
+#define _NETIO_AUTO_UP        0x00002000
+#define _NETIO_AUTO_DN        0x00004000
+#define _NETIO_AUTO_PRESENT   0x00008000
+#endif
+
+/** Set the desired state of the link to up, allowing any speeds which are
+    supported by the link hardware, as part of this registration operation.
+    Do not take down the link automatically.  This is the default if
+    no other NETIO_AUTO_LINK_xxx flags are specified.  This flag is ignored
+    if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+    See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_UP     (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP)
+
+/** Set the desired state of the link to up, allowing any speeds which are
+    supported by the link hardware, as part of this registration operation.
+    Set the desired state of the link to down the next time no tiles are
+    registered for packet reception or transmission.  This flag is ignored
+    if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+    See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_UPDN   (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP | \
+                                _NETIO_AUTO_DN)
+
+/** Set the desired state of the link to down the next time no tiles are
+    registered for packet reception or transmission.  This flag is ignored
+    if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV.
+    See @ref link for more information on link management.
+ */
+#define NETIO_AUTO_LINK_DN     (_NETIO_AUTO_PRESENT | _NETIO_AUTO_DN)
+
+/** Do not bring up the link automatically as part of this registration
+    operation.  Do not take down the link automatically.  This flag
+    is ignored if it is specified along with ::NETIO_NO_XMIT and
+    ::NETIO_NO_RECV.  See @ref link for more information on link management.
+  */
+#define NETIO_AUTO_LINK_NONE   _NETIO_AUTO_PRESENT
+
+
+/** Minimum number of receive packets. */
+#define NETIO_MIN_RECEIVE_PKTS            16
+
+/** Lower bound on the maximum number of receive packets; may be higher
+    than this on some interfaces. */
+#define NETIO_MAX_RECEIVE_PKTS           128
+
+/** Maximum number of send buffers, per packet size. */
+#define NETIO_MAX_SEND_BUFFERS            16
+
+/** Number of EPP queue slots, and thus outstanding sends, per EPP. */
+#define NETIO_TOTAL_SENDS_OUTSTANDING   2015
+
+/** Minimum number of EPP queue slots, and thus outstanding sends, per
+ *  transmitting tile. */
+#define NETIO_MIN_SENDS_OUTSTANDING       16
+
+
+/**@}*/
+
+#ifndef __DOXYGEN__
+
+/**
+ * An object for providing Ethernet packets to a process.
+ */
+struct __netio_queue_impl_t;
+
+/**
+ * An object for managing the user end of a NetIO queue.
+ */
+struct __netio_queue_user_impl_t;
+
+#endif /* !__DOXYGEN__ */
+
+
+/** A netio_queue_t describes a NetIO communications endpoint.
+ * @ingroup setup
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+  uint8_t opaque[8];                 /**< This is an opaque structure. */
+#else
+  struct __netio_queue_impl_t* __system_part;    /**< The system part. */
+  struct __netio_queue_user_impl_t* __user_part; /**< The user part. */
+#ifdef _NETIO_PTHREAD
+  _netio_percpu_mutex_t lock;                    /**< Queue lock. */
+#endif
+#endif
+}
+netio_queue_t;
+
+
+/**
+ * @brief Packet send context.
+ *
+ * @ingroup egress
+ *
+ * Packet send context for use with netio_send_packet_prepare and _commit.
+ */
+typedef struct
+{
+#ifdef __DOXYGEN__
+  uint8_t opaque[44];   /**< This is an opaque structure. */
+#else
+  uint8_t flags;        /**< Defined below */
+  uint8_t datalen;      /**< Number of valid words pointed to by data. */
+  uint32_t request[9];  /**< Request to be sent to the EPP or shim.  Note
+                             that this is smaller than the 11-word maximum
+                             request size, since some constant values are
+                             not saved in the context. */
+  uint32_t *data;       /**< Data to be sent to the EPP or shim via IDN. */
+#endif
+}
+netio_send_pkt_context_t;
+
+
+#ifndef __DOXYGEN__
+#define SEND_PKT_CTX_USE_EPP   1  /**< We're sending to an EPP. */
+#define SEND_PKT_CTX_SEND_CSUM 2  /**< Request includes a checksum. */
+#endif
+
+/**
+ * @brief Packet vector entry.
+ *
+ * @ingroup egress
+ *
+ * This data structure is used with netio_send_packet_vector() to send multiple
+ * packets with one NetIO call.  The structure should be initialized by
+ * calling netio_pkt_vector_set(), rather than by setting the fields
+ * directly.
+ *
+ * This structure is guaranteed to be a power of two in size, no
+ * bigger than one L2 cache line, and to be aligned modulo its size.
+ */
+typedef struct
+#ifndef __DOXYGEN__
+__attribute__((aligned(8)))
+#endif
+{
+  /** Reserved for use by the user application.  When initialized with
+   *  the netio_set_pkt_vector_entry() function, this field is guaranteed
+   *  to be visible to readers only after all other fields are already
+   *  visible.  This way it can be used as a valid flag or generation
+   *  counter. */
+  uint8_t user_data;
+
+  /* Structure members below this point should not be accessed directly by
+   * applications, as they may change in the future. */
+
+  /** Low 8 bits of the packet address to send.  The high bits are
+   *  acquired from the 'handle' field. */
+  uint8_t buffer_address_low;
+
+  /** Number of bytes to transmit. */
+  uint16_t size;
+
+  /** The raw handle from a netio_pkt_t.  If this is NETIO_PKT_HANDLE_NONE,
+   *  this vector entry will be skipped and no packet will be transmitted. */
+  netio_pkt_handle_t handle;
+}
+netio_pkt_vector_entry_t;
+
+
+/**
+ * @brief Initialize fields in a packet vector entry.
+ *
+ * @ingroup egress
+ *
+ * @param[out] v Pointer to the vector entry to be initialized.
+ * @param[in] pkt Packet to be transmitted when the vector entry is passed to
+ *        netio_send_packet_vector().  Note that the packet's attributes
+ *        (e.g., its L2 offset and length) are captured at the time this
+ *        routine is called; subsequent changes in those attributes will not
+ *        be reflected in the packet which is actually transmitted.
+ *        Changes in the packet's contents, however, will be so reflected.
+ *        If this is NULL, no packet will be transmitted.
+ * @param[in] user_data User data to be set in the vector entry.
+ *        This function guarantees that the "user_data" field will become
+ *        visible to a reader only after all other fields have become visible.
+ *        This allows a structure in a ring buffer to be written and read
+ *        by a polling reader without any locks or other synchronization.
+ */
+static __inline void
+netio_pkt_vector_set(volatile netio_pkt_vector_entry_t* v, netio_pkt_t* pkt,
+                     uint8_t user_data)
+{
+  if (pkt)
+  {
+    if (NETIO_PKT_IS_MINIMAL(pkt))
+    {
+      netio_pkt_minimal_metadata_t* mmd =
+        (netio_pkt_minimal_metadata_t*) &pkt->__metadata;
+      v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_MM(mmd, pkt) & 0xFF;
+      v->size = NETIO_PKT_L2_LENGTH_MM(mmd, pkt);
+    }
+    else
+    {
+      netio_pkt_metadata_t* mda = &pkt->__metadata;
+      v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_M(mda, pkt) & 0xFF;
+      v->size = NETIO_PKT_L2_LENGTH_M(mda, pkt);
+    }
+    v->handle.word = pkt->__packet.word;
+  }
+  else
+  {
+    v->handle.word = 0;   /* Set handle to NETIO_PKT_HANDLE_NONE. */
+  }
+
+  __asm__("" : : : "memory");
+
+  v->user_data = user_data;
+}
+
+
+/**
+ * Flags and structures for @ref netio_get() and @ref netio_set().
+ * @ingroup config
+ */
+
+/** @{ */
+/** Parameter class; addr is a NETIO_PARAM_xxx value. */
+#define NETIO_PARAM       0
+/** Interface MAC address. This address is only valid with @ref netio_get().
+ *  The value is a 6-byte MAC address.  Depending upon the overall system
+ *  design, a MAC address may or may not be available for each interface. */
+#define NETIO_PARAM_MAC        0
+
+/** Determine whether to suspend output on the receipt of pause frames.
+ *  If the value is nonzero, the I/O shim will suspend output when a pause
+ *  frame is received.  If the value is zero, pause frames will be ignored. */
+#define NETIO_PARAM_PAUSE_IN   1
+
+/** Determine whether to send pause frames if the I/O shim packet FIFOs are
+ *  nearly full.  If the value is zero, pause frames are not sent.  If
+ *  the value is nonzero, it is the delay value which will be sent in any
+ *  pause frames which are output, in units of 512 bit times. */
+#define NETIO_PARAM_PAUSE_OUT  2
+
+/** Jumbo frame support.  The value is a 4-byte integer.  If the value is
+ *  nonzero, the MAC will accept frames of up to 10240 bytes.  If the value
+ *  is zero, the MAC will only accept frames of up to 1544 bytes. */
+#define NETIO_PARAM_JUMBO      3
+
+/** I/O shim's overflow statistics register.  The value is two 16-bit integers.
+ *  The first 16-bit value (or the low 16 bits, if the value is treated as a
+ *  32-bit number) is the count of packets which were completely dropped and
+ *  not delivered by the shim.  The second 16-bit value (or the high 16 bits,
+ *  if the value is treated as a 32-bit number) is the count of packets
+ *  which were truncated and thus only partially delivered by the shim.  This
+ *  register is automatically reset to zero after it has been read.
+ */
+#define NETIO_PARAM_OVERFLOW   4
+
+/** IPP statistics.  This address is only valid with @ref netio_get().  The
+ *  value is a netio_stat_t structure.  Unlike the I/O shim statistics, the
+ *  IPP statistics are not all reset to zero on read; see the description
+ *  of the netio_stat_t for details. */
+#define NETIO_PARAM_STAT 5
+
+/** Possible link state.  The value is a combination of "NETIO_LINK_xxx"
+ *  flags.  With @ref netio_get(), this will indicate which flags are
+ *  actually supported by the hardware.
+ *
+ *  For historical reasons, specifying this value to netio_set() will have
+ *  the same behavior as using ::NETIO_PARAM_LINK_CONFIG, but this usage is
+ *  discouraged.
+ */
+#define NETIO_PARAM_LINK_POSSIBLE_STATE 6
+
+/** Link configuration. The value is a combination of "NETIO_LINK_xxx" flags.
+ *  With @ref netio_set(), this will attempt to immediately bring up the
+ *  link using whichever of the requested flags are supported by the
+ *  hardware, or take down the link if the flags are zero; if this is
+ *  not possible, an error will be returned.  Many programs will want
+ *  to use ::NETIO_PARAM_LINK_DESIRED_STATE instead.
+ *
+ *  For historical reasons, specifying this value to netio_get() will
+ *  have the same behavior as using ::NETIO_PARAM_LINK_POSSIBLE_STATE,
+ *  but this usage is discouraged.
+ */
+#define NETIO_PARAM_LINK_CONFIG NETIO_PARAM_LINK_POSSIBLE_STATE
+
+/** Current link state. This address is only valid with @ref netio_get().
+ *  The value is zero or more of the "NETIO_LINK_xxx" flags, ORed together.
+ *  If the link is down, the value ANDed with NETIO_LINK_SPEED will be
+ *  zero; if the link is up, the value ANDed with NETIO_LINK_SPEED will
+ *  result in exactly one of the NETIO_LINK_xxx values, indicating the
+ *  current speed. */
+#define NETIO_PARAM_LINK_CURRENT_STATE 7
+
+/** Variant symbol for current state, retained for compatibility with
+ *  pre-MDE-2.1 programs. */
+#define NETIO_PARAM_LINK_STATUS NETIO_PARAM_LINK_CURRENT_STATE
+
+/** Packet Coherence protocol. This address is only valid with @ref netio_get().
+ *  The value is nonzero if the interface is configured for cache-coherent DMA.
+ */
+#define NETIO_PARAM_COHERENT 8
+
+/** Desired link state. The value is a conbination of "NETIO_LINK_xxx"
+ *  flags, which specify the desired state for the link.  With @ref
+ *  netio_set(), this will, in the background, attempt to bring up the link
+ *  using whichever of the requested flags are reasonable, or take down the
+ *  link if the flags are zero.  The actual link up or down operation may
+ *  happen after this call completes.  If the link state changes in the
+ *  future, the system will continue to try to get back to the desired link
+ *  state; for instance, if the link is brought up successfully, and then
+ *  the network cable is disconnected, the link will go down.  However, the
+ *  desired state of the link is still up, so if the cable is reconnected,
+ *  the link will be brought up again.
+ *
+ *  With @ref netio_get(), this will indicate the desired state for the
+ *  link, as set with a previous netio_set() call, or implicitly by a
+ *  netio_input_register() or netio_input_unregister() operation.  This may
+ *  not reflect the current state of the link; to get that, use
+ *  ::NETIO_PARAM_LINK_CURRENT_STATE. */
+#define NETIO_PARAM_LINK_DESIRED_STATE 9
+
+/** NetIO statistics structure.  Retrieved using the ::NETIO_PARAM_STAT
+ *  address passed to @ref netio_get(). */
+typedef struct
+{
+  /** Number of packets which have been received by the IPP and forwarded
+   *  to a tile's receive queue for processing.  This value wraps at its
+   *  maximum, and is not cleared upon read. */
+  uint32_t packets_received;
+
+  /** Number of packets which have been dropped by the IPP, because they could
+   *  not be received, or could not be forwarded to a tile.  The former happens
+   *  when the IPP does not have a free packet buffer of suitable size for an
+   *  incoming frame.  The latter happens when all potential destination tiles
+   *  for a packet, as defined by the group, bucket, and queue configuration,
+   *  have full receive queues.   This value wraps at its maximum, and is not
+   *  cleared upon read. */
+  uint32_t packets_dropped;
+
+  /*
+   * Note: the #defines after each of the following four one-byte values
+   * denote their location within the third word of the netio_stat_t.  They
+   * are intended for use only by the IPP implementation and are thus omitted
+   * from the Doxygen output.
+   */
+
+  /** Number of packets dropped because no worker was able to accept a new
+   *  packet.  This value saturates at its maximum, and is cleared upon
+   *  read. */
+  uint8_t drops_no_worker;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_WORKER   0
+#endif
+
+  /** Number of packets dropped because no small buffers were available.
+   *  This value saturates at its maximum, and is cleared upon read. */
+  uint8_t drops_no_smallbuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_SMALLBUF 1
+#endif
+
+  /** Number of packets dropped because no large buffers were available.
+   *  This value saturates at its maximum, and is cleared upon read. */
+  uint8_t drops_no_largebuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_LARGEBUF 2
+#endif
+
+  /** Number of packets dropped because no jumbo buffers were available.
+   *  This value saturates at its maximum, and is cleared upon read. */
+  uint8_t drops_no_jumbobuf;
+#ifndef __DOXYGEN__
+#define NETIO_STAT_DROPS_NO_JUMBOBUF 3
+#endif
+}
+netio_stat_t;
+
+
+/** Link can run, should run, or is running at 10 Mbps. */
+#define NETIO_LINK_10M         0x01
+
+/** Link can run, should run, or is running at 100 Mbps. */
+#define NETIO_LINK_100M        0x02
+
+/** Link can run, should run, or is running at 1 Gbps. */
+#define NETIO_LINK_1G          0x04
+
+/** Link can run, should run, or is running at 10 Gbps. */
+#define NETIO_LINK_10G         0x08
+
+/** Link should run at the highest speed supported by the link and by
+ *  the device connected to the link.  Only usable as a value for
+ *  the link's desired state; never returned as a value for the current
+ *  or possible states. */
+#define NETIO_LINK_ANYSPEED    0x10
+
+/** All legal link speeds. */
+#define NETIO_LINK_SPEED  (NETIO_LINK_10M  | \
+                           NETIO_LINK_100M | \
+                           NETIO_LINK_1G   | \
+                           NETIO_LINK_10G  | \
+                           NETIO_LINK_ANYSPEED)
+
+
+/** MAC register class.  Addr is a register offset within the MAC.
+ *  Registers within the XGbE and GbE MACs are documented in the Tile
+ *  Processor I/O Device Guide (UG104). MAC registers start at address
+ *  0x4000, and do not include the MAC_INTERFACE registers. */
+#define NETIO_MAC             1
+
+/** MDIO register class (IEEE 802.3 clause 22 format).  Addr is the "addr"
+ *  member of a netio_mdio_addr_t structure. */
+#define NETIO_MDIO            2
+
+/** MDIO register class (IEEE 802.3 clause 45 format).  Addr is the "addr"
+ *  member of a netio_mdio_addr_t structure. */
+#define NETIO_MDIO_CLAUSE45   3
+
+/** NetIO MDIO address type.  Retrieved or provided using the ::NETIO_MDIO
+ *  address passed to @ref netio_get() or @ref netio_set(). */
+typedef union
+{
+  struct
+  {
+    unsigned int reg:16;  /**< MDIO register offset.  For clause 22 access,
+                               must be less than 32. */
+    unsigned int phy:5;   /**< Which MDIO PHY to access. */
+    unsigned int dev:5;   /**< Which MDIO device to access within that PHY.
+                               Applicable for clause 45 access only; ignored
+                               for clause 22 access. */
+  }
+  bits;                   /**< Container for bitfields. */
+  uint64_t addr;          /**< Value to pass to @ref netio_get() or
+                           *   @ref netio_set(). */
+}
+netio_mdio_addr_t;
+
+/** @} */
+
+#endif /* __NETIO_INTF_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/Kconfig linux-libre-2.6.37-gnu/arch/tile/Kconfig
--- linux-libre-2.6.36-gnu/arch/tile/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -58,6 +58,9 @@
 config ARCH_PHYS_ADDR_T_64BIT
 	def_bool y
 
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool y
+
 config LOCKDEP_SUPPORT
 	def_bool y
 
@@ -96,6 +99,7 @@
 
 config TILE
 	def_bool y
+	select HAVE_KVM if !TILEGX
 	select GENERIC_FIND_FIRST_BIT
 	select GENERIC_FIND_NEXT_BIT
 	select USE_GENERIC_SMP_HELPERS
@@ -113,8 +117,6 @@
 #       config HUGETLB_PAGE_SIZE_VARIABLE
 
 
-mainmenu "Linux/TILE Kernel Configuration"
-
 # Please note: TILE-Gx support is not yet finalized; this is
 # the preliminary support.  TILE-Gx drivers are only provided
 # with the alpha or beta test versions for Tilera customers.
@@ -236,9 +238,9 @@
 	  If you are not absolutely sure what you are doing, leave this
 	  option alone!
 
-	config VMSPLIT_375G
+	config VMSPLIT_3_75G
 		bool "3.75G/0.25G user/kernel split (no kernel networking)"
-	config VMSPLIT_35G
+	config VMSPLIT_3_5G
 		bool "3.5G/0.5G user/kernel split"
 	config VMSPLIT_3G
 		bool "3G/1G user/kernel split"
@@ -252,8 +254,8 @@
 
 config PAGE_OFFSET
 	hex
-	default 0xF0000000 if VMSPLIT_375G
-	default 0xE0000000 if VMSPLIT_35G
+	default 0xF0000000 if VMSPLIT_3_75G
+	default 0xE0000000 if VMSPLIT_3_5G
 	default 0xB0000000 if VMSPLIT_3G_OPT
 	default 0x80000000 if VMSPLIT_2G
 	default 0x40000000 if VMSPLIT_1G
@@ -314,10 +316,31 @@
 	bool "Hardwall support to allow access to user dynamic network"
 	default y
 
+config KERNEL_PL
+	int "Processor protection level for kernel"
+	range 1 2
+	default "1"
+	---help---
+	  This setting determines the processor protection level the
+	  kernel will be built to run at.  Generally you should use
+	  the default value here.
+
 endmenu  # Tilera-specific configuration
 
 menu "Bus options"
 
+config PCI
+	bool "PCI support"
+	default y
+	select PCI_DOMAINS
+	---help---
+	  Enable PCI root complex support, so PCIe endpoint devices can
+	  be attached to the Tile chip.  Many, but not all, PCI devices
+	  are supported under Tilera's root complex driver.
+
+config PCI_DOMAINS
+	bool
+
 config NO_IOMEM
 	def_bool !PCI
 
@@ -354,3 +377,5 @@
 source "crypto/Kconfig"
 
 source "lib/Kconfig"
+
+source "arch/tile/kvm/Kconfig"
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/backtrace.c linux-libre-2.6.37-gnu/arch/tile/kernel/backtrace.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/backtrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/backtrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -369,6 +369,10 @@
 					/* Weird; reserved value, ignore it. */
 					continue;
 				}
+				if (info_operand & ENTRY_POINT_INFO_OP)	{
+					/* This info op is ignored by the backtracer. */
+					continue;
+				}
 
 				/* Skip info ops which are not in the
 				 * "one_ago" mode we want right now.
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/compat.c linux-libre-2.6.37-gnu/arch/tile/kernel/compat.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/compat.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/compat.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
 #include <linux/kdev_t.h>
 #include <linux/fs.h>
 #include <linux/fcntl.h>
-#include <linux/smp_lock.h>
 #include <linux/uaccess.h>
 #include <linux/signal.h>
 #include <asm/syscalls.h>
@@ -148,14 +147,20 @@
 #define compat_sys_readahead sys32_readahead
 #define compat_sys_sync_file_range compat_sys_sync_file_range2
 
-/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
-#define compat_sys_stat64 sys_newstat
-#define compat_sys_lstat64 sys_newlstat
-#define compat_sys_fstat64 sys_newfstat
-#define compat_sys_fstatat64 sys_newfstatat
+/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
+#define compat_sys_stat64 sys_stat64
+#define compat_sys_lstat64 sys_lstat64
+#define compat_sys_fstat64 sys_fstat64
+#define compat_sys_fstatat64 sys_fstatat64
 
-/* Pass full 64-bit values through ptrace. */
-#define compat_sys_ptrace tile_compat_sys_ptrace
+/* The native sys_ptrace dynamically handles compat binaries. */
+#define compat_sys_ptrace sys_ptrace
+
+/* Call the trampolines to manage pt_regs where necessary. */
+#define compat_sys_execve _compat_sys_execve
+#define compat_sys_sigaltstack _compat_sys_sigaltstack
+#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
+#define sys_clone _sys_clone
 
 /*
  * Note that we can't include <linux/unistd.h> here since the header
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/compat_signal.c linux-libre-2.6.37-gnu/arch/tile/kernel/compat_signal.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/compat_signal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/compat_signal.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -256,9 +255,9 @@
 	return err;
 }
 
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
-			     struct compat_sigaltstack __user *uoss_ptr,
-			     struct pt_regs *regs)
+long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+			    struct compat_sigaltstack __user *uoss_ptr,
+			    struct pt_regs *regs)
 {
 	stack_t uss, uoss;
 	int ret;
@@ -291,12 +290,12 @@
 	return ret;
 }
 
-long _compat_sys_rt_sigreturn(struct pt_regs *regs)
+/* The assembly shim for this function arranges to ignore the return value. */
+long compat_sys_rt_sigreturn(struct pt_regs *regs)
 {
 	struct compat_rt_sigframe __user *frame =
 		(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
 	sigset_t set;
-	long r0;
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -309,13 +308,13 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
-	if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+	if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
 		goto badframe;
 
-	return r0;
+	return 0;
 
 badframe:
 	force_sig(SIGSEGV, current);
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/early_printk.c linux-libre-2.6.37-gnu/arch/tile/kernel/early_printk.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/early_printk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/early_printk.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,7 @@
 void early_panic(const char *fmt, ...)
 {
 	va_list ap;
-	raw_local_irq_disable_all();
+	arch_local_irq_disable_all();
 	va_start(ap, fmt);
 	early_printk("Kernel panic - not syncing: ");
 	early_vprintk(fmt, ap);
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/entry.S linux-libre-2.6.37-gnu/arch/tile/kernel/entry.S
--- linux-libre-2.6.36-gnu/arch/tile/kernel/entry.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/entry.S	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,9 @@
 #include <linux/linkage.h>
 #include <linux/unistd.h>
 #include <asm/irqflags.h>
+#include <asm/processor.h>
 #include <arch/abi.h>
+#include <arch/spr_def.h>
 
 #ifdef __tilegx__
 #define bnzt bnezt
@@ -25,28 +27,6 @@
 	{ move r0, lr; jrp lr }
 	STD_ENDPROC(current_text_addr)
 
-STD_ENTRY(_sim_syscall)
-	/*
-	 * Wait for r0-r9 to be ready (and lr on the off chance we
-	 * want the syscall to locate its caller), then make a magic
-	 * simulator syscall.
-	 *
-	 * We carefully stall until the registers are readable in case they
-	 * are the target of a slow load, etc. so that tile-sim will
-	 * definitely be able to read all of them inside the magic syscall.
-	 *
-	 * Technically this is wrong for r3-r9 and lr, since an interrupt
-	 * could come in and restore the registers with a slow load right
-	 * before executing the mtspr. We may need to modify tile-sim to
-	 * explicitly stall for this case, but we do not yet have
-	 * a way to implement such a stall.
-	 */
-	{ and zero, lr, r9 ; and zero, r8, r7 }
-	{ and zero, r6, r5 ; and zero, r4, r3 }
-	{ and zero, r2, r1 ; mtspr SIM_CONTROL, r0 }
-	{ jrp lr }
-	STD_ENDPROC(_sim_syscall)
-
 /*
  * Implement execve().  The i386 code has a note that forking from kernel
  * space results in no copy on write until the execve, so we should be
@@ -102,7 +82,7 @@
 STD_ENTRY(cpu_idle_on_new_stack)
 	{
 	 move sp, r1
-	 mtspr SYSTEM_SAVE_1_0, r2
+	 mtspr SPR_SYSTEM_SAVE_K_0, r2
 	}
 	jal free_thread_info
 	j cpu_idle
@@ -124,15 +104,15 @@
 STD_ENTRY(_cpu_idle)
 	{
 	 lnk r0
-	 movei r1, 1
+	 movei r1, KERNEL_PL
 	}
 	{
 	 addli r0, r0, _cpu_idle_nap - .
 	 mtspr INTERRUPT_CRITICAL_SECTION, r1
 	}
-	IRQ_ENABLE(r2, r3)         /* unmask, but still with ICS set */
-	mtspr EX_CONTEXT_1_1, r1   /* PL1, ICS clear */
-	mtspr EX_CONTEXT_1_0, r0
+	IRQ_ENABLE(r2, r3)             /* unmask, but still with ICS set */
+	mtspr SPR_EX_CONTEXT_K_1, r1   /* Kernel PL, ICS clear */
+	mtspr SPR_EX_CONTEXT_K_0, r0
 	iret
 	.global _cpu_idle_nap
 _cpu_idle_nap:
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/hardwall.c linux-libre-2.6.37-gnu/arch/tile/kernel/hardwall.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/hardwall.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/hardwall.c	2011-01-04 19:50:19.000000000 -0500
@@ -151,12 +151,12 @@
 
 static void enable_firewall_interrupts(void)
 {
-	raw_local_irq_unmask_now(INT_UDN_FIREWALL);
+	arch_local_irq_unmask_now(INT_UDN_FIREWALL);
 }
 
 static void disable_firewall_interrupts(void)
 {
-	raw_local_irq_mask_now(INT_UDN_FIREWALL);
+	arch_local_irq_mask_now(INT_UDN_FIREWALL);
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
@@ -768,6 +768,7 @@
 }
 
 static const struct file_operations dev_hardwall_fops = {
+	.open           = nonseekable_open,
 	.unlocked_ioctl = hardwall_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl   = hardwall_compat_ioctl,
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/head_32.S linux-libre-2.6.37-gnu/arch/tile/kernel/head_32.S
--- linux-libre-2.6.36-gnu/arch/tile/kernel/head_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/head_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -23,6 +23,7 @@
 #include <asm/asm-offsets.h>
 #include <hv/hypervisor.h>
 #include <arch/chip.h>
+#include <arch/spr_def.h>
 
 /*
  * This module contains the entry code for kernel images. It performs the
@@ -76,7 +77,7 @@
 	}
 1:
 
-	/* Get our processor number and save it away in SAVE_1_0. */
+	/* Get our processor number and save it away in SAVE_K_0. */
 	jal hv_inquire_topology
 	mulll_uu r4, r1, r2        /* r1 == y, r2 == width */
 	add r4, r4, r0             /* r0 == x, so r4 == cpu == y*width + x */
@@ -124,7 +125,7 @@
 	lw r0, r0
 	lw sp, r1
 	or r4, sp, r4
-	mtspr SYSTEM_SAVE_1_0, r4  /* save ksp0 + cpu */
+	mtspr SPR_SYSTEM_SAVE_K_0, r4  /* save ksp0 + cpu */
 	addi sp, sp, -STACK_TOP_DELTA
 	{
 	  move lr, zero   /* stop backtraces in the called function */
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/intvec_32.S linux-libre-2.6.37-gnu/arch/tile/kernel/intvec_32.S
--- linux-libre-2.6.36-gnu/arch/tile/kernel/intvec_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/intvec_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -32,8 +32,8 @@
 # error "No support for kernel preemption currently"
 #endif
 
-#if INT_INTCTRL_1 < 32 || INT_INTCTRL_1 >= 48
-# error INT_INTCTRL_1 coded to set high interrupt mask
+#if INT_INTCTRL_K < 32 || INT_INTCTRL_K >= 48
+# error INT_INTCTRL_K coded to set high interrupt mask
 #endif
 
 #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
@@ -132,8 +132,8 @@
 
 	/* Temporarily save a register so we have somewhere to work. */
 
-	mtspr   SYSTEM_SAVE_1_1, r0
-	mfspr   r0, EX_CONTEXT_1_1
+	mtspr   SPR_SYSTEM_SAVE_K_1, r0
+	mfspr   r0, SPR_EX_CONTEXT_K_1
 
 	/* The cmpxchg code clears sp to force us to reset it here on fault. */
 	{
@@ -167,18 +167,18 @@
 	 * The page_fault handler may be downcalled directly by the
 	 * hypervisor even when Linux is running and has ICS set.
 	 *
-	 * In this case the contents of EX_CONTEXT_1_1 reflect the
+	 * In this case the contents of EX_CONTEXT_K_1 reflect the
 	 * previous fault and can't be relied on to choose whether or
 	 * not to reinitialize the stack pointer.  So we add a test
-	 * to see whether SYSTEM_SAVE_1_2 has the high bit set,
+	 * to see whether SYSTEM_SAVE_K_2 has the high bit set,
 	 * and if so we don't reinitialize sp, since we must be coming
 	 * from Linux.  (In fact the precise case is !(val & ~1),
 	 * but any Linux PC has to have the high bit set.)
 	 *
-	 * Note that the hypervisor *always* sets SYSTEM_SAVE_1_2 for
+	 * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
 	 * any path that turns into a downcall to one of our TLB handlers.
 	 */
-	mfspr   r0, SYSTEM_SAVE_1_2
+	mfspr   r0, SPR_SYSTEM_SAVE_K_2
 	{
 	 blz    r0, 0f    /* high bit in S_S_1_2 is for a PC to use */
 	 move   r0, sp
@@ -187,12 +187,12 @@
 
 2:
 	/*
-	 * SYSTEM_SAVE_1_0 holds the cpu number in the low bits, and
+	 * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
 	 * the current stack top in the higher bits.  So we recover
 	 * our stack top by just masking off the low bits, then
 	 * point sp at the top aligned address on the actual stack page.
 	 */
-	mfspr   r0, SYSTEM_SAVE_1_0
+	mfspr   r0, SPR_SYSTEM_SAVE_K_0
 	mm      r0, r0, zero, LOG2_THREAD_SIZE, 31
 
 0:
@@ -254,7 +254,7 @@
 	 sw     sp, r3
 	 addli  sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
 	}
-	mfspr   r0, EX_CONTEXT_1_0
+	mfspr   r0, SPR_EX_CONTEXT_K_0
 	.ifc \processing,handle_syscall
 	/*
 	 * Bump the saved PC by one bundle so that when we return, we won't
@@ -267,7 +267,7 @@
 	 sw     sp, r0
 	 addli  sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
 	}
-	mfspr   r0, EX_CONTEXT_1_1
+	mfspr   r0, SPR_EX_CONTEXT_K_1
 	{
 	 sw     sp, r0
 	 addi   sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
@@ -289,7 +289,7 @@
 	 .endif
 	 addli  sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
 	}
-	mfspr   r0, SYSTEM_SAVE_1_1    /* Original r0 */
+	mfspr   r0, SPR_SYSTEM_SAVE_K_1    /* Original r0 */
 	{
 	 sw     sp, r0
 	 addi   sp, sp, -PTREGS_OFFSET_REG(0) - 4
@@ -309,12 +309,12 @@
 	 * See discussion below at "finish_interrupt_save".
 	 */
 	.ifc \c_routine, do_page_fault
-	mfspr   r2, SYSTEM_SAVE_1_3   /* address of page fault */
-	mfspr   r3, SYSTEM_SAVE_1_2   /* info about page fault */
+	mfspr   r2, SPR_SYSTEM_SAVE_K_3   /* address of page fault */
+	mfspr   r3, SPR_SYSTEM_SAVE_K_2   /* info about page fault */
 	.else
 	.ifc \vecnum, INT_DOUBLE_FAULT
 	{
-	 mfspr  r2, SYSTEM_SAVE_1_2   /* double fault info from HV */
+	 mfspr  r2, SPR_SYSTEM_SAVE_K_2   /* double fault info from HV */
 	 movei  r3, 0
 	}
 	.else
@@ -467,7 +467,7 @@
 	/* Load tp with our per-cpu offset. */
 #ifdef CONFIG_SMP
 	{
-	 mfspr  r20, SYSTEM_SAVE_1_0
+	 mfspr  r20, SPR_SYSTEM_SAVE_K_0
 	 moveli r21, lo16(__per_cpu_offset)
 	}
 	{
@@ -487,7 +487,7 @@
 	 * We load flags in r32 here so we can jump to .Lrestore_regs
 	 * directly after do_page_fault_ics() if necessary.
 	 */
-	mfspr   r32, EX_CONTEXT_1_1
+	mfspr   r32, SPR_EX_CONTEXT_K_1
 	{
 	 andi   r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
 	 PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
@@ -957,11 +957,11 @@
 	pop_reg_zero r21, r3, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
 	pop_reg_zero lr, r4, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_EX1
 	{
-	 mtspr  EX_CONTEXT_1_0, r21
+	 mtspr  SPR_EX_CONTEXT_K_0, r21
 	 move   r5, zero
 	}
 	{
-	 mtspr  EX_CONTEXT_1_1, lr
+	 mtspr  SPR_EX_CONTEXT_K_1, lr
 	 andi   lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
 	}
 
@@ -1020,7 +1020,7 @@
 
 	/* Set r1 to errno if we are returning an error, otherwise zero. */
 	{
-	 moveli r29, 1024
+	 moveli r29, 4096
 	 sub    r1, zero, r0
 	}
 	slt_u   r29, r1, r29
@@ -1199,7 +1199,7 @@
 	STD_ENDPROC(interrupt_return)
 
 	/*
-	 * This interrupt variant clears the INT_INTCTRL_1 interrupt mask bit
+	 * This interrupt variant clears the INT_INTCTRL_K interrupt mask bit
 	 * before returning, so we can properly get more downcalls.
 	 */
 	.pushsection .text.handle_interrupt_downcall,"ax"
@@ -1208,11 +1208,11 @@
 	check_single_stepping normal, .Ldispatch_downcall
 .Ldispatch_downcall:
 
-	/* Clear INTCTRL_1 from the set of interrupts we ever enable. */
+	/* Clear INTCTRL_K from the set of interrupts we ever enable. */
 	GET_INTERRUPTS_ENABLED_MASK_PTR(r30)
 	{
 	 addi   r30, r30, 4
-	 movei  r31, INT_MASK(INT_INTCTRL_1)
+	 movei  r31, INT_MASK(INT_INTCTRL_K)
 	}
 	{
 	 lw     r20, r30
@@ -1227,7 +1227,7 @@
 	}
 	FEEDBACK_REENTER(handle_interrupt_downcall)
 
-	/* Allow INTCTRL_1 to be enabled next time we enable interrupts. */
+	/* Allow INTCTRL_K to be enabled next time we enable interrupts. */
 	lw      r20, r30
 	or      r20, r20, r31
 	sw      r30, r20
@@ -1342,8 +1342,8 @@
 	lw      r20, r20
 
 	/* Jump to syscall handler. */
-	jalr    r20; .Lhandle_syscall_link:
-	FEEDBACK_REENTER(handle_syscall)
+	jalr    r20
+.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
 
 	/*
 	 * Write our r0 onto the stack so it gets restored instead
@@ -1352,6 +1352,9 @@
 	PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
 	sw      r29, r0
 
+.Lsyscall_sigreturn_skip:
+	FEEDBACK_REENTER(handle_syscall)
+
 	/* Do syscall trace again, if requested. */
 	lw	r30, r31
 	andi    r30, r30, _TIF_SYSCALL_TRACE
@@ -1472,7 +1475,12 @@
 	lw      r26, r24
 	sw      r28, r26
 
-	/* Clear TIF_SINGLESTEP */
+	/*
+	 * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill.
+	 * The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we
+	 * need to clear it here and can't really impose on all other arches.
+	 * So what's another write between friends?
+	 */
 	GET_THREAD_INFO(r0)
 
 	addi    r1, r0, THREAD_INFO_FLAGS_OFFSET
@@ -1509,7 +1517,7 @@
 /* Various stub interrupt handlers and syscall handlers */
 
 STD_ENTRY_LOCAL(_kernel_double_fault)
-	mfspr   r1, EX_CONTEXT_1_0
+	mfspr   r1, SPR_EX_CONTEXT_K_0
 	move    r2, lr
 	move    r3, sp
 	move    r4, r52
@@ -1518,34 +1526,44 @@
 	STD_ENDPROC(_kernel_double_fault)
 
 STD_ENTRY_LOCAL(bad_intr)
-	mfspr   r2, EX_CONTEXT_1_0
+	mfspr   r2, SPR_EX_CONTEXT_K_0
 	panic   "Unhandled interrupt %#x: PC %#lx"
 	STD_ENDPROC(bad_intr)
 
 /* Put address of pt_regs in reg and jump. */
 #define PTREGS_SYSCALL(x, reg)                          \
-	STD_ENTRY(x);                                   \
+	STD_ENTRY(_##x);                                \
 	{                                               \
 	 PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
-	 j      _##x                                    \
+	 j      x                                       \
 	};                                              \
-	STD_ENDPROC(x)
+	STD_ENDPROC(_##x)
+
+/*
+ * Special-case sigreturn to not write r0 to the stack on return.
+ * This is technically more efficient, but it also avoids difficulties
+ * in the 64-bit OS when handling 32-bit compat code, since we must not
+ * sign-extend r0 for the sigreturn return-value case.
+ */
+#define PTREGS_SYSCALL_SIGRETURN(x, reg)                \
+	STD_ENTRY(_##x);                                \
+	addli   lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
+	{                                               \
+	 PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
+	 j      x                                       \
+	};                                              \
+	STD_ENDPROC(_##x)
 
 PTREGS_SYSCALL(sys_execve, r3)
 PTREGS_SYSCALL(sys_sigaltstack, r2)
-PTREGS_SYSCALL(sys_rt_sigreturn, r0)
-
-/* Save additional callee-saves to pt_regs, put address in reg and jump. */
-#define PTREGS_SYSCALL_ALL_REGS(x, reg)                 \
-	STD_ENTRY(x);                                   \
-	push_extra_callee_saves reg;                    \
-	j       _##x;                                   \
-	STD_ENDPROC(x)
+PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
+PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
 
-PTREGS_SYSCALL_ALL_REGS(sys_fork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_vfork, r0)
-PTREGS_SYSCALL_ALL_REGS(sys_clone, r4)
-PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+	push_extra_callee_saves r4
+	j       sys_clone
+	STD_ENDPROC(_sys_clone)
 
 /*
  * This entrypoint is taken for the cmpxchg and atomic_update fast
@@ -1558,12 +1576,14 @@
  * to be available to it on entry.  It does not modify any callee-save
  * registers (including "lr").  It does not check what PL it is being
  * called at, so you'd better not call it other than at PL0.
+ * The <atomic.h> wrapper assumes it only clobbers r20-r29, so if
+ * it ever is necessary to use more registers, be aware.
  *
  * It does not use the stack, but since it might be re-interrupted by
  * a page fault which would assume the stack was valid, it does
  * save/restore the stack pointer and zero it out to make sure it gets reset.
  * Since we always keep interrupts disabled, the hypervisor won't
- * clobber our EX_CONTEXT_1_x registers, so we don't save/restore them
+ * clobber our EX_CONTEXT_K_x registers, so we don't save/restore them
  * (other than to advance the PC on return).
  *
  * We have to manually validate the user vs kernel address range
@@ -1769,7 +1789,7 @@
 	/* Do slow mtspr here so the following "mf" waits less. */
 	{
 	 move   sp, r27
-	 mtspr  EX_CONTEXT_1_0, r28
+	 mtspr  SPR_EX_CONTEXT_K_0, r28
 	}
 	mf
 
@@ -1788,7 +1808,7 @@
 	}
 	{
 	 move   sp, r27
-	 mtspr  EX_CONTEXT_1_0, r28
+	 mtspr  SPR_EX_CONTEXT_K_0, r28
 	}
 	iret
 
@@ -1816,7 +1836,7 @@
 #endif
 
 	/* Issue the slow SPR here while the tns result is in flight. */
-	mfspr   r28, EX_CONTEXT_1_0
+	mfspr   r28, SPR_EX_CONTEXT_K_0
 
 	{
 	 addi   r28, r28, 8    /* return to the instruction after the swint1 */
@@ -1904,7 +1924,7 @@
 .Lcmpxchg64_mismatch:
 	{
 	 move   sp, r27
-	 mtspr  EX_CONTEXT_1_0, r28
+	 mtspr  SPR_EX_CONTEXT_K_0, r28
 	}
 	mf
 	{
@@ -1985,8 +2005,13 @@
 	int_hand     INT_PERF_COUNT, PERF_COUNT, \
 		     op_handle_perf_interrupt, handle_nmi
 	int_hand     INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+	dc_dispatch  INT_INTCTRL_2, INTCTRL_2
+	int_hand     INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
 	int_hand     INT_INTCTRL_2, INTCTRL_2, bad_intr
 	dc_dispatch  INT_INTCTRL_1, INTCTRL_1
+#endif
 	int_hand     INT_INTCTRL_0, INTCTRL_0, bad_intr
 	int_hand     INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
 		     hv_message_intr, handle_interrupt_downcall
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/irq.c linux-libre-2.6.37-gnu/arch/tile/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,7 @@
 #define IS_HW_CLEARED 1
 
 /*
- * The set of interrupts we enable for raw_local_irq_enable().
+ * The set of interrupts we enable for arch_local_irq_enable().
  * This is initialized to have just a single interrupt that the kernel
  * doesn't actually use as a sentinel.  During kernel init,
  * interrupts are added as the kernel gets prepared to support them.
@@ -61,9 +61,9 @@
 
 #if CHIP_HAS_IPI()
 /* Use SPRs to manipulate device interrupts. */
-#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_1, irq_mask)
-#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_1, irq_mask)
-#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_1, irq_mask)
+#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask)
+#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_K, irq_mask)
+#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_K, irq_mask)
 #else
 /* Use HV to manipulate device interrupts. */
 #define mask_irqs(irq_mask) hv_disable_intr(irq_mask)
@@ -89,16 +89,16 @@
 	 * masked by a previous interrupt.  Then, mask out the ones
 	 * we're going to handle.
 	 */
-	unsigned long masked = __insn_mfspr(SPR_IPI_MASK_1);
-	original_irqs = __insn_mfspr(SPR_IPI_EVENT_1) & ~masked;
-	__insn_mtspr(SPR_IPI_MASK_SET_1, original_irqs);
+	unsigned long masked = __insn_mfspr(SPR_IPI_MASK_K);
+	original_irqs = __insn_mfspr(SPR_IPI_EVENT_K) & ~masked;
+	__insn_mtspr(SPR_IPI_MASK_SET_K, original_irqs);
 #else
 	/*
 	 * Hypervisor performs the equivalent of the Gx code above and
 	 * then puts the pending interrupt mask into a system save reg
 	 * for us to find.
 	 */
-	original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_1_3);
+	original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_K_3);
 #endif
 	remaining_irqs = original_irqs;
 
@@ -208,7 +208,7 @@
 }
 
 static struct irq_chip tile_irq_chip = {
-	.typename = "tile_irq_chip",
+	.name = "tile_irq_chip",
 	.ack = tile_irq_chip_ack,
 	.eoi = tile_irq_chip_eoi,
 	.mask = tile_irq_chip_mask,
@@ -225,7 +225,7 @@
 	/* Enable interrupt delivery. */
 	unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-	raw_local_irq_unmask(INT_IPI_1);
+	arch_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
@@ -288,7 +288,7 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %14s", irq_desc[i].chip->name);
 		seq_printf(p, "  %s", action->name);
 
 		for (action = action->next; action; action = action->next)
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/machine_kexec.c linux-libre-2.6.37-gnu/arch/tile/kernel/machine_kexec.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/machine_kexec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/machine_kexec.c	2011-01-04 19:50:19.000000000 -0500
@@ -182,13 +182,13 @@
 
 		if ((entry & IND_SOURCE)) {
 			void *va =
-				kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+				kmap_atomic_pfn(entry >> PAGE_SHIFT);
 			r = kexec_bn2cl(va);
 			if (r) {
 				command_line = r;
 				break;
 			}
-			kunmap_atomic(va, KM_USER0);
+			kunmap_atomic(va);
 		}
 	}
 
@@ -198,7 +198,7 @@
 
 		hverr = hv_set_command_line(
 			(HV_VirtAddr) command_line, strlen(command_line));
-		kunmap_atomic(command_line, KM_USER0);
+		kunmap_atomic(command_line);
 	} else {
 		pr_info("%s: no command line found; making empty\n",
 		       __func__);
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/Makefile linux-libre-2.6.37-gnu/arch/tile/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/tile/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -15,3 +15,4 @@
 obj-$(CONFIG_MODULES)		+= module.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_PCI)		+= pci.o
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/messaging.c linux-libre-2.6.37-gnu/arch/tile/kernel/messaging.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/messaging.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/messaging.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 		panic("hv_register_message_state: error %d", rc);
 
 	/* Make sure downcall interrupts will be enabled. */
-	raw_local_irq_unmask(INT_INTCTRL_1);
+	arch_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/pci.c linux-libre-2.6.37-gnu/arch/tile/kernel/pci.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/pci.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/pci.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,621 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/byteorder.h>
+#include <asm/hv_driver.h>
+#include <hv/drv_pcie_rc_intf.h>
+
+
+/*
+ * Initialization flow and process
+ * -------------------------------
+ *
+ * This files containes the routines to search for PCI buses,
+ * enumerate the buses, and configure any attached devices.
+ *
+ * There are two entry points here:
+ * 1) tile_pci_init
+ *    This sets up the pci_controller structs, and opens the
+ *    FDs to the hypervisor.  This is called from setup_arch() early
+ *    in the boot process.
+ * 2) pcibios_init
+ *    This probes the PCI bus(es) for any attached hardware.  It's
+ *    called by subsys_initcall.  All of the real work is done by the
+ *    generic Linux PCI layer.
+ *
+ */
+
+/*
+ * This flag tells if the platform is TILEmpower that needs
+ * special configuration for the PLX switch chip.
+ */
+int __write_once tile_plx_gen1;
+
+static struct pci_controller controllers[TILE_NUM_PCIE];
+static int num_controllers;
+
+static struct pci_ops tile_cfg_ops;
+
+
+/*
+ * We don't need to worry about the alignment of resources.
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+			    resource_size_t size, resource_size_t align)
+{
+	return res->start;
+}
+EXPORT_SYMBOL(pcibios_align_resource);
+
+/*
+ * Open a FD to the hypervisor PCI device.
+ *
+ * controller_id is the controller number, config type is 0 or 1 for
+ * config0 or config1 operations.
+ */
+static int __init tile_pcie_open(int controller_id, int config_type)
+{
+	char filename[32];
+	int fd;
+
+	sprintf(filename, "pcie/%d/config%d", controller_id, config_type);
+
+	fd = hv_dev_open((HV_VirtAddr)filename, 0);
+
+	return fd;
+}
+
+
+/*
+ * Get the IRQ numbers from the HV and set up the handlers for them.
+ */
+static int __init tile_init_irqs(int controller_id,
+				 struct pci_controller *controller)
+{
+	char filename[32];
+	int fd;
+	int ret;
+	int x;
+	struct pcie_rc_config rc_config;
+
+	sprintf(filename, "pcie/%d/ctl", controller_id);
+	fd = hv_dev_open((HV_VirtAddr)filename, 0);
+	if (fd < 0) {
+		pr_err("PCI: hv_dev_open(%s) failed\n", filename);
+		return -1;
+	}
+	ret = hv_dev_pread(fd, 0, (HV_VirtAddr)(&rc_config),
+			   sizeof(rc_config), PCIE_RC_CONFIG_MASK_OFF);
+	hv_dev_close(fd);
+	if (ret != sizeof(rc_config)) {
+		pr_err("PCI: wanted %zd bytes, got %d\n",
+		       sizeof(rc_config), ret);
+		return -1;
+	}
+	/* Record irq_base so that we can map INTx to IRQ # later. */
+	controller->irq_base = rc_config.intr;
+
+	for (x = 0; x < 4; x++)
+		tile_irq_activate(rc_config.intr + x,
+				  TILE_IRQ_HW_CLEAR);
+
+	if (rc_config.plx_gen1)
+		controller->plx_gen1 = 1;
+
+	return 0;
+}
+
+/*
+ * First initialization entry point, called from setup_arch().
+ *
+ * Find valid controllers and fill in pci_controller structs for each
+ * of them.
+ *
+ * Returns the number of controllers discovered.
+ */
+int __init tile_pci_init(void)
+{
+	int i;
+
+	pr_info("PCI: Searching for controllers...\n");
+
+	/* Do any configuration we need before using the PCIe */
+
+	for (i = 0; i < TILE_NUM_PCIE; i++) {
+		int hv_cfg_fd0 = -1;
+		int hv_cfg_fd1 = -1;
+		int hv_mem_fd = -1;
+		char name[32];
+		struct pci_controller *controller;
+
+		/*
+		 * Open the fd to the HV.  If it fails then this
+		 * device doesn't exist.
+		 */
+		hv_cfg_fd0 = tile_pcie_open(i, 0);
+		if (hv_cfg_fd0 < 0)
+			continue;
+		hv_cfg_fd1 = tile_pcie_open(i, 1);
+		if (hv_cfg_fd1 < 0) {
+			pr_err("PCI: Couldn't open config fd to HV "
+			    "for controller %d\n", i);
+			goto err_cont;
+		}
+
+		sprintf(name, "pcie/%d/mem", i);
+		hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
+		if (hv_mem_fd < 0) {
+			pr_err("PCI: Could not open mem fd to HV!\n");
+			goto err_cont;
+		}
+
+		pr_info("PCI: Found PCI controller #%d\n", i);
+
+		controller = &controllers[num_controllers];
+
+		if (tile_init_irqs(i, controller)) {
+			pr_err("PCI: Could not initialize "
+			       "IRQs, aborting.\n");
+			goto err_cont;
+		}
+
+		controller->index = num_controllers;
+		controller->hv_cfg_fd[0] = hv_cfg_fd0;
+		controller->hv_cfg_fd[1] = hv_cfg_fd1;
+		controller->hv_mem_fd = hv_mem_fd;
+		controller->first_busno = 0;
+		controller->last_busno = 0xff;
+		controller->ops = &tile_cfg_ops;
+
+		num_controllers++;
+		continue;
+
+err_cont:
+		if (hv_cfg_fd0 >= 0)
+			hv_dev_close(hv_cfg_fd0);
+		if (hv_cfg_fd1 >= 0)
+			hv_dev_close(hv_cfg_fd1);
+		if (hv_mem_fd >= 0)
+			hv_dev_close(hv_mem_fd);
+		continue;
+	}
+
+	/*
+	 * Before using the PCIe, see if we need to do any platform-specific
+	 * configuration, such as the PLX switch Gen 1 issue on TILEmpower.
+	 */
+	for (i = 0; i < num_controllers; i++) {
+		struct pci_controller *controller = &controllers[i];
+
+		if (controller->plx_gen1)
+			tile_plx_gen1 = 1;
+	}
+
+	return num_controllers;
+}
+
+/*
+ * (pin - 1) converts from the PCI standard's [1:4] convention to
+ * a normal [0:3] range.
+ */
+static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	struct pci_controller *controller =
+		(struct pci_controller *)dev->sysdata;
+	return (pin - 1) + controller->irq_base;
+}
+
+
+static void __init fixup_read_and_payload_sizes(void)
+{
+	struct pci_dev *dev = NULL;
+	int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
+	int max_read_size = 0x2; /* Limit to 512 byte reads. */
+	u16 new_values;
+
+	/* Scan for the smallest maximum payload size. */
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		int pcie_caps_offset;
+		u32 devcap;
+		int max_payload;
+
+		pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
+		if (pcie_caps_offset == 0)
+			continue;
+
+		pci_read_config_dword(dev, pcie_caps_offset + PCI_EXP_DEVCAP,
+				      &devcap);
+		max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
+		if (max_payload < smallest_max_payload)
+			smallest_max_payload = max_payload;
+	}
+
+	/* Now, set the max_payload_size for all devices to that value. */
+	new_values = (max_read_size << 12) | (smallest_max_payload << 5);
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		int pcie_caps_offset;
+		u16 devctl;
+
+		pcie_caps_offset = pci_find_capability(dev, PCI_CAP_ID_EXP);
+		if (pcie_caps_offset == 0)
+			continue;
+
+		pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
+				     &devctl);
+		devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ);
+		devctl |= new_values;
+		pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL,
+				      devctl);
+	}
+}
+
+
+/*
+ * Second PCI initialization entry point, called by subsys_initcall.
+ *
+ * The controllers have been set up by the time we get here, by a call to
+ * tile_pci_init.
+ */
+static int __init pcibios_init(void)
+{
+	int i;
+
+	pr_info("PCI: Probing PCI hardware\n");
+
+	/*
+	 * Delay a bit in case devices aren't ready.  Some devices are
+	 * known to require at least 20ms here, but we use a more
+	 * conservative value.
+	 */
+	mdelay(250);
+
+	/* Scan all of the recorded PCI controllers.  */
+	for (i = 0; i < num_controllers; i++) {
+		struct pci_controller *controller = &controllers[i];
+		struct pci_bus *bus;
+
+		pr_info("PCI: initializing controller #%d\n", i);
+
+		/*
+		 * This comes from the generic Linux PCI driver.
+		 *
+		 * It reads the PCI tree for this bus into the Linux
+		 * data structures.
+		 *
+		 * This is inlined in linux/pci.h and calls into
+		 * pci_scan_bus_parented() in probe.c.
+		 */
+		bus = pci_scan_bus(0, controller->ops, controller);
+		controller->root_bus = bus;
+		controller->last_busno = bus->subordinate;
+
+	}
+
+	/* Do machine dependent PCI interrupt routing */
+	pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
+
+	/*
+	 * This comes from the generic Linux PCI driver.
+	 *
+	 * It allocates all of the resources (I/O memory, etc)
+	 * associated with the devices read in above.
+	 */
+
+	pci_assign_unassigned_resources();
+
+	/* Configure the max_read_size and max_payload_size values. */
+	fixup_read_and_payload_sizes();
+
+	/* Record the I/O resources in the PCI controller structure. */
+	for (i = 0; i < num_controllers; i++) {
+		struct pci_bus *root_bus = controllers[i].root_bus;
+		struct pci_bus *next_bus;
+		struct pci_dev *dev;
+
+		list_for_each_entry(dev, &root_bus->devices, bus_list) {
+			/* Find the PCI host controller, ie. the 1st bridge. */
+			if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+				(PCI_SLOT(dev->devfn) == 0)) {
+				next_bus = dev->subordinate;
+				controllers[i].mem_resources[0] =
+					*next_bus->resource[0];
+				controllers[i].mem_resources[1] =
+					 *next_bus->resource[1];
+				controllers[i].mem_resources[2] =
+					 *next_bus->resource[2];
+
+				break;
+			}
+		}
+
+	}
+
+	return 0;
+}
+subsys_initcall(pcibios_init);
+
+/*
+ * No bus fixups needed.
+ */
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+{
+	/* Nothing needs to be done. */
+}
+
+/*
+ * This can be called from the generic PCI layer, but doesn't need to
+ * do anything.
+ */
+char __devinit *pcibios_setup(char *str)
+{
+	/* Nothing needs to be done. */
+	return str;
+}
+
+/*
+ * This is called from the generic Linux layer.
+ */
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/*
+ * Enable memory and/or address decoding, as appropriate, for the
+ * device described by the 'dev' struct.
+ *
+ * This is called from the generic PCI layer, and can be called
+ * for bridges or endpoints.
+ */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	u8 header_type;
+	int i;
+	struct resource *r;
+
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+		/*
+		 * For bridges, we enable both memory and I/O decoding
+		 * in call cases.
+		 */
+		cmd |= PCI_COMMAND_IO;
+		cmd |= PCI_COMMAND_MEMORY;
+	} else {
+		/*
+		 * For endpoints, we enable memory and/or I/O decoding
+		 * only if they have a memory resource of that type.
+		 */
+		for (i = 0; i < 6; i++) {
+			r = &dev->resource[i];
+			if (r->flags & IORESOURCE_UNSET) {
+				pr_err("PCI: Device %s not available "
+				       "because of resource collisions\n",
+				       pci_name(dev));
+				return -EINVAL;
+			}
+			if (r->flags & IORESOURCE_IO)
+				cmd |= PCI_COMMAND_IO;
+			if (r->flags & IORESOURCE_MEM)
+				cmd |= PCI_COMMAND_MEMORY;
+		}
+	}
+
+	/*
+	 * We only write the command if it changed.
+	 */
+	if (cmd != old_cmd)
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	return 0;
+}
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+	unsigned long start = pci_resource_start(dev, bar);
+	unsigned long len = pci_resource_len(dev, bar);
+	unsigned long flags = pci_resource_flags(dev, bar);
+
+	if (!len)
+		return NULL;
+	if (max && len > max)
+		len = max;
+
+	if (!(flags & IORESOURCE_MEM)) {
+		pr_info("PCI: Trying to map invalid resource %#lx\n", flags);
+		start = 0;
+	}
+
+	return (void __iomem *)start;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+
+/****************************************************************
+ *
+ * Tile PCI config space read/write routines
+ *
+ ****************************************************************/
+
+/*
+ * These are the normal read and write ops
+ * These are expanded with macros from  pci_bus_read_config_byte() etc.
+ *
+ * devfn is the combined PCI slot & function.
+ *
+ * offset is in bytes, from the start of config space for the
+ * specified bus & slot.
+ */
+
+static int __devinit tile_cfg_read(struct pci_bus *bus,
+				   unsigned int devfn,
+				   int offset,
+				   int size,
+				   u32 *val)
+{
+	struct pci_controller *controller = bus->sysdata;
+	int busnum = bus->number & 0xff;
+	int slot = (devfn >> 3) & 0x1f;
+	int function = devfn & 0x7;
+	u32 addr;
+	int config_mode = 1;
+
+	/*
+	 * There is no bridge between the Tile and bus 0, so we
+	 * use config0 to talk to bus 0.
+	 *
+	 * If we're talking to a bus other than zero then we
+	 * must have found a bridge.
+	 */
+	if (busnum == 0) {
+		/*
+		 * We fake an empty slot for (busnum == 0) && (slot > 0),
+		 * since there is only one slot on bus 0.
+		 */
+		if (slot) {
+			*val = 0xFFFFFFFF;
+			return 0;
+		}
+		config_mode = 0;
+	}
+
+	addr = busnum << 20;		/* Bus in 27:20 */
+	addr |= slot << 15;		/* Slot (device) in 19:15 */
+	addr |= function << 12;		/* Function is in 14:12 */
+	addr |= (offset & 0xFFF);	/* byte address in 0:11 */
+
+	return hv_dev_pread(controller->hv_cfg_fd[config_mode], 0,
+			    (HV_VirtAddr)(val), size, addr);
+}
+
+
+/*
+ * See tile_cfg_read() for relevent comments.
+ * Note that "val" is the value to write, not a pointer to that value.
+ */
+static int __devinit tile_cfg_write(struct pci_bus *bus,
+				    unsigned int devfn,
+				    int offset,
+				    int size,
+				    u32 val)
+{
+	struct pci_controller *controller = bus->sysdata;
+	int busnum = bus->number & 0xff;
+	int slot = (devfn >> 3) & 0x1f;
+	int function = devfn & 0x7;
+	u32 addr;
+	int config_mode = 1;
+	HV_VirtAddr valp = (HV_VirtAddr)&val;
+
+	/*
+	 * For bus 0 slot 0 we use config 0 accesses.
+	 */
+	if (busnum == 0) {
+		/*
+		 * We fake an empty slot for (busnum == 0) && (slot > 0),
+		 * since there is only one slot on bus 0.
+		 */
+		if (slot)
+			return 0;
+		config_mode = 0;
+	}
+
+	addr = busnum << 20;		/* Bus in 27:20 */
+	addr |= slot << 15;		/* Slot (device) in 19:15 */
+	addr |= function << 12;		/* Function is in 14:12 */
+	addr |= (offset & 0xFFF);	/* byte address in 0:11 */
+
+#ifdef __BIG_ENDIAN
+	/* Point to the correct part of the 32-bit "val". */
+	valp += 4 - size;
+#endif
+
+	return hv_dev_pwrite(controller->hv_cfg_fd[config_mode], 0,
+			     valp, size, addr);
+}
+
+
+static struct pci_ops tile_cfg_ops = {
+	.read =         tile_cfg_read,
+	.write =        tile_cfg_write,
+};
+
+
+/*
+ * In the following, each PCI controller's mem_resources[1]
+ * represents its (non-prefetchable) PCI memory resource.
+ * mem_resources[0] and mem_resources[2] refer to its PCI I/O and
+ * prefetchable PCI memory resources, respectively.
+ * For more details, see pci_setup_bridge() in setup-bus.c.
+ * By comparing the target PCI memory address against the
+ * end address of controller 0, we can determine the controller
+ * that should accept the PCI memory access.
+ */
+#define TILE_READ(size, type)						\
+type _tile_read##size(unsigned long addr)				\
+{									\
+	type val;							\
+	int idx = 0;							\
+	if (addr > controllers[0].mem_resources[1].end &&		\
+	    addr > controllers[0].mem_resources[2].end)			\
+		idx = 1;                                                \
+	if (hv_dev_pread(controllers[idx].hv_mem_fd, 0,			\
+			 (HV_VirtAddr)(&val), sizeof(type), addr))	\
+		pr_err("PCI: read %zd bytes at 0x%lX failed\n",		\
+		       sizeof(type), addr);				\
+	return val;							\
+}									\
+EXPORT_SYMBOL(_tile_read##size)
+
+TILE_READ(b, u8);
+TILE_READ(w, u16);
+TILE_READ(l, u32);
+TILE_READ(q, u64);
+
+#define TILE_WRITE(size, type)						\
+void _tile_write##size(type val, unsigned long addr)			\
+{									\
+	int idx = 0;							\
+	if (addr > controllers[0].mem_resources[1].end &&		\
+	    addr > controllers[0].mem_resources[2].end)			\
+		idx = 1;                                                \
+	if (hv_dev_pwrite(controllers[idx].hv_mem_fd, 0,		\
+			  (HV_VirtAddr)(&val), sizeof(type), addr))	\
+		pr_err("PCI: write %zd bytes at 0x%lX failed\n",	\
+		       sizeof(type), addr);				\
+}									\
+EXPORT_SYMBOL(_tile_write##size)
+
+TILE_WRITE(b, u8);
+TILE_WRITE(w, u16);
+TILE_WRITE(l, u32);
+TILE_WRITE(q, u64);
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/process.c linux-libre-2.6.37-gnu/arch/tile/kernel/process.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/process.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/process.c	2011-01-04 19:50:19.000000000 -0500
@@ -212,11 +212,19 @@
 	childregs->sp = sp;  /* override with new user stack pointer */
 
 	/*
+	 * If CLONE_SETTLS is set, set "tp" in the new task to "r4",
+	 * which is passed in as arg #5 to sys_clone().
+	 */
+	if (clone_flags & CLONE_SETTLS)
+		childregs->tp = regs->regs[4];
+
+	/*
 	 * Copy the callee-saved registers from the passed pt_regs struct
 	 * into the context-switch callee-saved registers area.
-	 * We have to restore the callee-saved registers since we may
-	 * be cloning a userspace task with userspace register state,
-	 * and we won't be unwinding the same kernel frames to restore them.
+	 * This way when we start the interrupt-return sequence, the
+	 * callee-save registers will be correctly in registers, which
+	 * is how we assume the compiler leaves them as we start doing
+	 * the normal return-from-interrupt path after calling C code.
 	 * Zero out the C ABI save area to mark the top of the stack.
 	 */
 	ksp = (unsigned long) childregs;
@@ -304,15 +312,25 @@
 /* Allow user processes to access the DMA SPRs */
 void grant_dma_mpls(void)
 {
+#if CONFIG_KERNEL_PL == 2
+	__insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
+	__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#else
 	__insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1);
 	__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1);
+#endif
 }
 
 /* Forbid user processes from accessing the DMA SPRs */
 void restrict_dma_mpls(void)
 {
+#if CONFIG_KERNEL_PL == 2
+	__insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1);
+	__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1);
+#else
 	__insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
 	__insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+#endif
 }
 
 /* Pause the DMA engine, then save off its state registers. */
@@ -523,19 +541,15 @@
 	 * Switch kernel SP, PC, and callee-saved registers.
 	 * In the context of the new task, return the old task pointer
 	 * (i.e. the task that actually called __switch_to).
-	 * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp.
+	 * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp.
 	 */
 	return __switch_to(prev, next, next_current_ksp0(next));
 }
 
-long _sys_fork(struct pt_regs *regs)
-{
-	return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
-}
-
-long _sys_clone(unsigned long clone_flags, unsigned long newsp,
-		void __user *parent_tidptr, void __user *child_tidptr,
-		struct pt_regs *regs)
+/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
+SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
+		void __user *, parent_tidptr, void __user *, child_tidptr,
+		struct pt_regs *, regs)
 {
 	if (!newsp)
 		newsp = regs->sp;
@@ -543,18 +557,13 @@
 		       parent_tidptr, child_tidptr);
 }
 
-long _sys_vfork(struct pt_regs *regs)
-{
-	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
-		       regs, 0, NULL, NULL);
-}
-
 /*
  * sys_execve() executes a new program.
  */
-long _sys_execve(const char __user *path,
-		 const char __user *const __user *argv,
-		 const char __user *const __user *envp, struct pt_regs *regs)
+SYSCALL_DEFINE4(execve, const char __user *, path,
+		const char __user *const __user *, argv,
+		const char __user *const __user *, envp,
+		struct pt_regs *, regs)
 {
 	long error;
 	char *filename;
@@ -570,9 +579,10 @@
 }
 
 #ifdef CONFIG_COMPAT
-long _compat_sys_execve(const char __user *path,
-			const compat_uptr_t __user *argv,
-			const compat_uptr_t __user *envp, struct pt_regs *regs)
+long compat_sys_execve(const char __user *path,
+		       const compat_uptr_t __user *argv,
+		       const compat_uptr_t __user *envp,
+		       struct pt_regs *regs)
 {
 	long error;
 	char *filename;
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/tile/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,25 +32,6 @@
 }
 
 /*
- * This routine will put a word on the process's privileged stack.
- */
-static void putreg(struct task_struct *task,
-		   unsigned long addr, unsigned long value)
-{
-	unsigned int regno = addr / sizeof(unsigned long);
-	struct pt_regs *childregs = task_pt_regs(task);
-	childregs->regs[regno] = value;
-	childregs->flags |= PT_FLAGS_RESTORE_REGS;
-}
-
-static unsigned long getreg(struct task_struct *task, unsigned long addr)
-{
-	unsigned int regno = addr / sizeof(unsigned long);
-	struct pt_regs *childregs = task_pt_regs(task);
-	return childregs->regs[regno];
-}
-
-/*
  * Called by kernel/ptrace.c when detaching..
  */
 void ptrace_disable(struct task_struct *child)
@@ -64,61 +45,80 @@
 	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
-	unsigned long __user *datap;
+	unsigned long __user *datap = (long __user __force *)data;
 	unsigned long tmp;
-	int i;
 	long ret = -EIO;
-
-#ifdef CONFIG_COMPAT
-	if (task_thread_info(current)->status & TS_COMPAT)
-		data = (u32)data;
-	if (task_thread_info(child)->status & TS_COMPAT)
-		addr = (u32)addr;
-#endif
-	datap = (unsigned long __user __force *)data;
+	char *childreg;
+	struct pt_regs copyregs;
+	int ex1_offset;
 
 	switch (request) {
 
 	case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
-		if (addr & (sizeof(data)-1))
-			break;
-		if (addr < 0 || addr >= PTREGS_SIZE)
+		if (addr >= PTREGS_SIZE)
 			break;
-		tmp = getreg(child, addr);   /* Read register */
-		ret = put_user(tmp, datap);
+		childreg = (char *)task_pt_regs(child) + addr;
+#ifdef CONFIG_COMPAT
+		if (is_compat_task()) {
+			if (addr & (sizeof(compat_long_t)-1))
+				break;
+			ret = put_user(*(compat_long_t *)childreg,
+				       (compat_long_t __user *)datap);
+		} else
+#endif
+		{
+			if (addr & (sizeof(long)-1))
+				break;
+			ret = put_user(*(long *)childreg, datap);
+		}
 		break;
 
 	case PTRACE_POKEUSR:  /* Write register in pt_regs. */
-		if (addr & (sizeof(data)-1))
-			break;
-		if (addr < 0 || addr >= PTREGS_SIZE)
+		if (addr >= PTREGS_SIZE)
 			break;
-		putreg(child, addr, data);   /* Write register */
+		childreg = (char *)task_pt_regs(child) + addr;
+
+		/* Guard against overwrites of the privilege level. */
+		ex1_offset = PTREGS_OFFSET_EX1;
+#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
+		if (is_compat_task())   /* point at low word */
+			ex1_offset += sizeof(compat_long_t);
+#endif
+		if (addr == ex1_offset)
+			data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
+
+#ifdef CONFIG_COMPAT
+		if (is_compat_task()) {
+			if (addr & (sizeof(compat_long_t)-1))
+				break;
+			*(compat_long_t *)childreg = data;
+		} else
+#endif
+		{
+			if (addr & (sizeof(long)-1))
+				break;
+			*(long *)childreg = data;
+		}
 		ret = 0;
 		break;
 
 	case PTRACE_GETREGS:  /* Get all registers from the child. */
-		if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
-			break;
-		for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
-			ret = __put_user(getreg(child, i), datap);
-			if (ret != 0)
-				break;
-			datap++;
+		if (copy_to_user(datap, task_pt_regs(child),
+				 sizeof(struct pt_regs)) == 0) {
+			ret = 0;
 		}
 		break;
 
 	case PTRACE_SETREGS:  /* Set all registers in the child. */
-		if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
-			break;
-		for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
-			ret = __get_user(tmp, datap);
-			if (ret != 0)
-				break;
-			putreg(child, i, tmp);
-			datap++;
+		if (copy_from_user(&copyregs, datap,
+				   sizeof(struct pt_regs)) == 0) {
+			copyregs.ex1 =
+				PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
+			*task_pt_regs(child) = copyregs;
+			ret = 0;
 		}
 		break;
 
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/reboot.c linux-libre-2.6.37-gnu/arch/tile/kernel/reboot.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/reboot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/reboot.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,7 @@
 void machine_halt(void)
 {
 	warn_early_printk();
-	raw_local_irq_disable_all();
+	arch_local_irq_disable_all();
 	smp_send_stop();
 	hv_halt();
 }
@@ -35,14 +35,14 @@
 void machine_power_off(void)
 {
 	warn_early_printk();
-	raw_local_irq_disable_all();
+	arch_local_irq_disable_all();
 	smp_send_stop();
 	hv_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-	raw_local_irq_disable_all();
+	arch_local_irq_disable_all();
 	smp_send_stop();
 	hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
 }
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/regs_32.S linux-libre-2.6.37-gnu/arch/tile/kernel/regs_32.S
--- linux-libre-2.6.36-gnu/arch/tile/kernel/regs_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/regs_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -85,7 +85,7 @@
 	{
 	  /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
 	  move sp, r13
-	  mtspr SYSTEM_SAVE_1_0, r2
+	  mtspr SPR_SYSTEM_SAVE_K_0, r2
 	}
 	FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
 .L__switch_to_pc:
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/setup.c linux-libre-2.6.37-gnu/arch/tile/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,6 @@
 #include <linux/timex.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
-#include <asm/sections.h>
-#include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
@@ -187,11 +185,11 @@
 
 #ifdef CONFIG_HIGHMEM
 /*
- * Determine for each controller where its lowmem is mapped and how
- * much of it is mapped there.  On controller zero, the first few
- * megabytes are mapped at 0xfd000000 as code, so in principle we
- * could start our data mappings higher up, but for now we don't
- * bother, to avoid additional confusion.
+ * Determine for each controller where its lowmem is mapped and how much of
+ * it is mapped there.  On controller zero, the first few megabytes are
+ * already mapped in as code at MEM_SV_INTRPT, so in principle we could
+ * start our data mappings higher up, but for now we don't bother, to avoid
+ * additional confusion.
  *
  * One question is whether, on systems with more than 768 Mb and
  * controllers of different sizes, to map in a proportionate amount of
@@ -311,7 +309,7 @@
 #endif
 
 	/* We are using a char to hold the cpu_2_node[] mapping */
-	BUG_ON(MAX_NUMNODES > 127);
+	BUILD_BUG_ON(MAX_NUMNODES > 127);
 
 	/* Discover the ranges of memory available to us */
 	for (i = 0; ; ++i) {
@@ -842,7 +840,7 @@
 	for_each_online_node(i)
 		register_one_node(i);
 
-	for_each_present_cpu(i)
+	for (i = 0; i < smp_height * smp_width; ++i)
 		register_cpu(&cpu_devices[i], i);
 
 	return 0;
@@ -870,11 +868,14 @@
 
 	/* Allow asynchronous TLB interrupts. */
 #if CHIP_HAS_TILE_DMA()
-	raw_local_irq_unmask(INT_DMATLB_MISS);
-	raw_local_irq_unmask(INT_DMATLB_ACCESS);
+	arch_local_irq_unmask(INT_DMATLB_MISS);
+	arch_local_irq_unmask(INT_DMATLB_ACCESS);
 #endif
 #if CHIP_HAS_SN_PROC()
-	raw_local_irq_unmask(INT_SNITLB_MISS);
+	arch_local_irq_unmask(INT_SNITLB_MISS);
+#endif
+#ifdef __tilegx__
+	arch_local_irq_unmask(INT_SINGLE_STEP_K);
 #endif
 
 	/*
@@ -893,11 +894,12 @@
 #endif
 
 	/*
-	 * Set the MPL for interrupt control 0 to user level.
-	 * This includes access to the SYSTEM_SAVE and EX_CONTEXT SPRs,
-	 * as well as the PL 0 interrupt mask.
+	 * Set the MPL for interrupt control 0 & 1 to the corresponding
+	 * values.  This includes access to the SYSTEM_SAVE and EX_CONTEXT
+	 * SPRs, as well as the interrupt mask.
 	 */
 	__insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1);
+	__insn_mtspr(SPR_MPL_INTCTRL_1_SET_1, 1);
 
 	/* Initialize IRQ support for this cpu. */
 	setup_irq_regs();
@@ -1033,7 +1035,7 @@
 	 * In addition, make sure we CAN'T use the end of memory, since
 	 * we use the last chunk of each pgd for the pgd_list.
 	 */
-	int i, fc_fd_ok = 0;
+	int i, user_kernel_ok = 0;
 	unsigned long max_va = 0;
 	unsigned long list_va =
 		((PGD_LIST_OFFSET / sizeof(pgd_t)) << PGDIR_SHIFT);
@@ -1044,13 +1046,13 @@
 			break;
 		if (range.start <= MEM_USER_INTRPT &&
 		    range.start + range.size >= MEM_HV_INTRPT)
-			fc_fd_ok = 1;
+			user_kernel_ok = 1;
 		if (range.start == 0)
 			max_va = range.size;
 		BUG_ON(range.start + range.size > list_va);
 	}
-	if (!fc_fd_ok)
-		early_panic("Hypervisor not configured for VAs 0xfc/0xfd\n");
+	if (!user_kernel_ok)
+		early_panic("Hypervisor not configured for user/kernel VAs\n");
 	if (max_va == 0)
 		early_panic("Hypervisor not configured for low VAs\n");
 	if (max_va < KERNEL_HIGH_VADDR)
@@ -1334,6 +1336,10 @@
 	pte_t *pte;
 
 	BUG_ON(pgd_addr_invalid(addr));
+	if (addr < VMALLOC_START || addr >= VMALLOC_END)
+		panic("PCPU addr %#lx outside vmalloc range %#lx..%#lx;"
+		      " try increasing CONFIG_VMALLOC_RESERVE\n",
+		      addr, VMALLOC_START, VMALLOC_END);
 
 	pgd = swapper_pg_dir + pgd_index(addr);
 	pud = pud_offset(pgd, addr);
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/signal.c linux-libre-2.6.37-gnu/arch/tile/kernel/signal.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/signal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/signal.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
@@ -41,8 +40,8 @@
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 
-long _sys_sigaltstack(const stack_t __user *uss,
-		      stack_t __user *uoss, struct pt_regs *regs)
+SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
+		stack_t __user *, uoss, struct pt_regs *, regs)
 {
 	return do_sigaltstack(uss, uoss, regs->sp);
 }
@@ -53,7 +52,7 @@
  */
 
 int restore_sigcontext(struct pt_regs *regs,
-		       struct sigcontext __user *sc, long *pr0)
+		       struct sigcontext __user *sc)
 {
 	int err = 0;
 	int i;
@@ -71,19 +70,20 @@
 	for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
 		err |= __get_user(regs->regs[i], &sc->gregs[i]);
 
+	/* Ensure that the PL is always set to USER_PL. */
+	regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1));
+
 	regs->faultnum = INT_SWINT_1_SIGRETURN;
 
-	err |= __get_user(*pr0, &sc->gregs[0]);
 	return err;
 }
 
-/* sigreturn() returns long since it restores r0 in the interrupted code. */
-long _sys_rt_sigreturn(struct pt_regs *regs)
+/* The assembly shim for this function arranges to ignore the return value. */
+SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
 {
 	struct rt_sigframe __user *frame =
 		(struct rt_sigframe __user *)(regs->sp);
 	sigset_t set;
-	long r0;
 
 	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
@@ -96,13 +96,13 @@
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
 
-	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
 	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
 		goto badframe;
 
-	return r0;
+	return 0;
 
 badframe:
 	force_sig(SIGSEGV, current);
@@ -330,7 +330,7 @@
 			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
 		}
 
-		return;
+		goto done;
 	}
 
 	/* Did we come from a system call? */
@@ -358,4 +358,8 @@
 		current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
+
+done:
+	/* Avoid double syscall restart if there are nested signals. */
+	regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/single_step.c linux-libre-2.6.37-gnu/arch/tile/kernel/single_step.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/single_step.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/single_step.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
  * Derived from iLib's single-stepping code.
  */
 
-#ifndef __tilegx__   /* No support for single-step yet. */
+#ifndef __tilegx__   /* Hardware support for single step unavailable. */
 
 /* These functions are only used on the TILE platform */
 #include <linux/slab.h>
@@ -660,4 +660,75 @@
 		regs->pc += 8;
 }
 
+#else
+#include <linux/smp.h>
+#include <linux/ptrace.h>
+#include <arch/spr_def.h>
+
+static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
+
+
+/*
+ * Called directly on the occasion of an interrupt.
+ *
+ * If the process doesn't have single step set, then we use this as an
+ * opportunity to turn single step off.
+ *
+ * It has been mentioned that we could conditionally turn off single stepping
+ * on each entry into the kernel and rely on single_step_once to turn it
+ * on for the processes that matter (as we already do), but this
+ * implementation is somewhat more efficient in that we muck with registers
+ * once on a bum interrupt rather than on every entry into the kernel.
+ *
+ * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred,
+ * so we have to run through this process again before we can say that an
+ * instruction has executed.
+ *
+ * swint will set CANCELED, but it's a legitimate instruction.  Fortunately
+ * it changes the PC.  If it hasn't changed, then we know that the interrupt
+ * wasn't generated by swint and we'll need to run this process again before
+ * we can say an instruction has executed.
+ *
+ * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get
+ * on with our lives.
+ */
+
+void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
+{
+	unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+	struct thread_info *info = (void *)current_thread_info();
+	int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
+	unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+	if (is_single_step == 0) {
+		__insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0);
+
+	} else if ((*ss_pc != regs->pc) ||
+		   (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) {
+
+		ptrace_notify(SIGTRAP);
+		control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+		control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+		__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+	}
+}
+
+
+/*
+ * Called from need_singlestep.  Set up the control registers and the enable
+ * register, then return back.
+ */
+
+void single_step_once(struct pt_regs *regs)
+{
+	unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
+	unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
+
+	*ss_pc = regs->pc;
+	control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
+	control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
+	__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
+	__insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL);
+}
+
 #endif /* !__tilegx__ */
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/smpboot.c linux-libre-2.6.37-gnu/arch/tile/kernel/smpboot.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/smpboot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/smpboot.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,6 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/smp.c linux-libre-2.6.37-gnu/arch/tile/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -115,7 +115,7 @@
 static void smp_stop_cpu_interrupt(void)
 {
 	set_cpu_online(smp_processor_id(), 0);
-	raw_local_irq_disable_all();
+	arch_local_irq_disable_all();
 	for (;;)
 		asm("nap");
 }
@@ -212,7 +212,7 @@
 
 		tile.x = cpu_x(cpu);
 		tile.y = cpu_y(cpu);
-		if (hv_get_ipi_pte(tile, 1, &pte) != 0)
+		if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0)
 			panic("Failed to initialize IPI for cpu %d\n", cpu);
 
 		offset = hv_pte_get_pfn(pte) << PAGE_SHIFT;
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/stack.c linux-libre-2.6.37-gnu/arch/tile/kernel/stack.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/stack.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/stack.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,10 @@
 #include <arch/abi.h>
 #include <arch/interrupts.h>
 
+#define KBT_ONGOING	0  /* Backtrace still ongoing */
+#define KBT_DONE	1  /* Backtrace cleanly completed */
+#define KBT_RUNNING	2  /* Can't run backtrace on a running task */
+#define KBT_LOOP	3  /* Backtrace entered a loop */
 
 /* Is address on the specified kernel stack? */
 static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
@@ -207,11 +211,11 @@
 	for (;;) {
 		do {
 			if (!KBacktraceIterator_is_sigreturn(kbt))
-				return 1;
+				return KBT_ONGOING;
 		} while (backtrace_next(&kbt->it));
 
 		if (!KBacktraceIterator_restart(kbt))
-			return 0;
+			return KBT_DONE;
 	}
 }
 
@@ -264,7 +268,7 @@
 	kbt->pgtable = NULL;
 	kbt->verbose = 0;   /* override in caller if desired */
 	kbt->profile = 0;   /* override in caller if desired */
-	kbt->end = 0;
+	kbt->end = KBT_ONGOING;
 	kbt->new_context = 0;
 	if (is_current) {
 		HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
@@ -290,7 +294,7 @@
 	if (regs == NULL) {
 		if (is_current || t->state == TASK_RUNNING) {
 			/* Can't do this; we need registers */
-			kbt->end = 1;
+			kbt->end = KBT_RUNNING;
 			return;
 		}
 		pc = get_switch_to_pc();
@@ -305,26 +309,29 @@
 	}
 
 	backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
-	kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+	kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
 }
 EXPORT_SYMBOL(KBacktraceIterator_init);
 
 int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
 {
-	return kbt->end;
+	return kbt->end != KBT_ONGOING;
 }
 EXPORT_SYMBOL(KBacktraceIterator_end);
 
 void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
 {
+	VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
 	kbt->new_context = 0;
-	if (!backtrace_next(&kbt->it) &&
-	    !KBacktraceIterator_restart(kbt)) {
-			kbt->end = 1;
-			return;
-		}
-
-	kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+	if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
+		kbt->end = KBT_DONE;
+		return;
+	}
+	kbt->end = KBacktraceIterator_next_item_inclusive(kbt);
+	if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) {
+		/* Trapped in a loop; give up. */
+		kbt->end = KBT_LOOP;
+	}
 }
 EXPORT_SYMBOL(KBacktraceIterator_next);
 
@@ -387,6 +394,8 @@
 			break;
 		}
 	}
+	if (kbt->end == KBT_LOOP)
+		pr_err("Stack dump stopped; next frame identical to this one\n");
 	if (headers)
 		pr_err("Stack dump complete\n");
 }
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/sys.c linux-libre-2.6.37-gnu/arch/tile/kernel/sys.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/sys.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/sys.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/mman.h>
 #include <linux/file.h>
@@ -110,6 +109,15 @@
 #define sys_sync_file_range sys_sync_file_range2
 #endif
 
+/* Call the trampolines to manage pt_regs where necessary. */
+#define sys_execve _sys_execve
+#define sys_sigaltstack _sys_sigaltstack
+#define sys_rt_sigreturn _sys_rt_sigreturn
+#define sys_clone _sys_clone
+#ifndef __tilegx__
+#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
+#endif
+
 /*
  * Note that we can't include <linux/unistd.h> here since the header
  * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/time.c linux-libre-2.6.37-gnu/arch/tile/kernel/time.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -132,7 +132,7 @@
 {
 	BUG_ON(ticks > MAX_TICK);
 	__insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
-	raw_local_irq_unmask_now(INT_TILE_TIMER);
+	arch_local_irq_unmask_now(INT_TILE_TIMER);
 	return 0;
 }
 
@@ -143,7 +143,7 @@
 static void tile_timer_set_mode(enum clock_event_mode mode,
 				struct clock_event_device *evt)
 {
-	raw_local_irq_mask_now(INT_TILE_TIMER);
+	arch_local_irq_mask_now(INT_TILE_TIMER);
 }
 
 /*
@@ -172,7 +172,7 @@
 	evt->cpumask = cpumask_of(smp_processor_id());
 
 	/* Start out with timer not firing. */
-	raw_local_irq_mask_now(INT_TILE_TIMER);
+	arch_local_irq_mask_now(INT_TILE_TIMER);
 
 	/* Register tile timer. */
 	clockevents_register_device(evt);
@@ -188,7 +188,7 @@
 	 * Mask the timer interrupt here, since we are a oneshot timer
 	 * and there are now by definition no events pending.
 	 */
-	raw_local_irq_mask(INT_TILE_TIMER);
+	arch_local_irq_mask(INT_TILE_TIMER);
 
 	/* Track time spent here in an interrupt context */
 	irq_enter();
diff -druN linux-libre-2.6.36-gnu/arch/tile/kernel/traps.c linux-libre-2.6.37-gnu/arch/tile/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/tile/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -260,7 +260,7 @@
 		address = regs->pc;
 		break;
 	case INT_UNALIGN_DATA:
-#ifndef __tilegx__  /* FIXME: GX: no single-step yet */
+#ifndef __tilegx__  /* Emulated support for single step debugging */
 		if (unaligned_fixup >= 0) {
 			struct single_step_state *state =
 				current_thread_info()->step_state;
@@ -278,7 +278,7 @@
 	case INT_DOUBLE_FAULT:
 		/*
 		 * For double fault, "reason" is actually passed as
-		 * SYSTEM_SAVE_1_2, the hypervisor's double-fault info, so
+		 * SYSTEM_SAVE_K_2, the hypervisor's double-fault info, so
 		 * we can provide the original fault number rather than
 		 * the uninteresting "INT_DOUBLE_FAULT" so the user can
 		 * learn what actually struck while PL0 ICS was set.
diff -druN linux-libre-2.6.36-gnu/arch/tile/kvm/Kconfig linux-libre-2.6.37-gnu/arch/tile/kvm/Kconfig
--- linux-libre-2.6.36-gnu/arch/tile/kvm/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/kvm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,38 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+	bool "Virtualization"
+	---help---
+	  Say Y here to get to see options for using your Linux host to run
+	  other operating systems inside virtual machines (guests).
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and
+	  disabled.
+
+if VIRTUALIZATION
+
+config KVM
+	tristate "Kernel-based Virtual Machine (KVM) support"
+	depends on HAVE_KVM && MODULES && EXPERIMENTAL
+	select PREEMPT_NOTIFIERS
+	select ANON_INODES
+	---help---
+	  Support hosting paravirtualized guest machines.
+
+	  This module provides access to the hardware capabilities through
+	  a character device node named /dev/kvm.
+
+	  To compile this as a module, choose M here: the module
+	  will be called kvm.
+
+	  If unsure, say N.
+
+source drivers/vhost/Kconfig
+source drivers/virtio/Kconfig
+
+endif # VIRTUALIZATION
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/atomic_32.c linux-libre-2.6.37-gnu/arch/tile/lib/atomic_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/atomic_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/atomic_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -300,7 +300,7 @@
 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
 	/* Validate power-of-two and "bigger than cpus" assumption */
-	BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
+	BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
 	BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids);
 
 	/*
@@ -314,17 +314,17 @@
 	BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0);
 
 	/* The locks must all fit on one page. */
-	BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
+	BUILD_BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
 
 	/*
 	 * We use the page offset of the atomic value's address as
 	 * an index into atomic_locks, excluding the low 3 bits.
 	 * That should not produce more indices than ATOMIC_HASH_SIZE.
 	 */
-	BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
+	BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
 	/* The futex code makes this assumption, so we validate it here. */
-	BUG_ON(sizeof(atomic_t) != sizeof(int));
+	BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 }
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/exports.c linux-libre-2.6.37-gnu/arch/tile/lib/exports.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/exports.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/exports.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,6 +45,9 @@
 EXPORT_SYMBOL(__copy_in_user_inatomic);
 #endif
 
+/* arch/tile/lib/mb_incoherent.S */
+EXPORT_SYMBOL(__mb_incoherent);
+
 /* hypervisor glue */
 #include <hv/hypervisor.h>
 EXPORT_SYMBOL(hv_dev_open);
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/Makefile linux-libre-2.6.37-gnu/arch/tile/lib/Makefile
--- linux-libre-2.6.36-gnu/arch/tile/lib/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,8 +3,8 @@
 #
 
 lib-y = cacheflush.o checksum.o cpumask.o delay.o \
-	mb_incoherent.o uaccess.o \
-	memcpy_$(BITS).o memchr_$(BITS).o memmove_$(BITS).o memset_$(BITS).o \
+	mb_incoherent.o uaccess.o memmove.o \
+	memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
 	strchr_$(BITS).o strlen_$(BITS).o
 
 ifeq ($(CONFIG_TILEGX),y)
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memchr_32.c linux-libre-2.6.37-gnu/arch/tile/lib/memchr_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/memchr_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memchr_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,12 +18,24 @@
 
 void *memchr(const void *s, int c, size_t n)
 {
+	const uint32_t *last_word_ptr;
+	const uint32_t *p;
+	const char *last_byte_ptr;
+	uintptr_t s_int;
+	uint32_t goal, before_mask, v, bits;
+	char *ret;
+
+	if (__builtin_expect(n == 0, 0)) {
+		/* Don't dereference any memory if the array is empty. */
+		return NULL;
+	}
+
 	/* Get an aligned pointer. */
-	const uintptr_t s_int = (uintptr_t) s;
-	const uint32_t *p = (const uint32_t *)(s_int & -4);
+	s_int = (uintptr_t) s;
+	p = (const uint32_t *)(s_int & -4);
 
 	/* Create four copies of the byte for which we are looking. */
-	const uint32_t goal = 0x01010101 * (uint8_t) c;
+	goal = 0x01010101 * (uint8_t) c;
 
 	/* Read the first word, but munge it so that bytes before the array
 	 * will not match goal.
@@ -31,23 +43,14 @@
 	 * Note that this shift count expression works because we know
 	 * shift counts are taken mod 32.
 	 */
-	const uint32_t before_mask = (1 << (s_int << 3)) - 1;
-	uint32_t v = (*p | before_mask) ^ (goal & before_mask);
+	before_mask = (1 << (s_int << 3)) - 1;
+	v = (*p | before_mask) ^ (goal & before_mask);
 
 	/* Compute the address of the last byte. */
-	const char *const last_byte_ptr = (const char *)s + n - 1;
+	last_byte_ptr = (const char *)s + n - 1;
 
 	/* Compute the address of the word containing the last byte. */
-	const uint32_t *const last_word_ptr =
-	    (const uint32_t *)((uintptr_t) last_byte_ptr & -4);
-
-	uint32_t bits;
-	char *ret;
-
-	if (__builtin_expect(n == 0, 0)) {
-		/* Don't dereference any memory if the array is empty. */
-		return NULL;
-	}
+	last_word_ptr = (const uint32_t *)((uintptr_t) last_byte_ptr & -4);
 
 	while ((bits = __insn_seqb(v, goal)) == 0) {
 		if (__builtin_expect(p == last_word_ptr, 0)) {
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memcpy_32.S linux-libre-2.6.37-gnu/arch/tile/lib/memcpy_32.S
--- linux-libre-2.6.36-gnu/arch/tile/lib/memcpy_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memcpy_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -10,14 +10,16 @@
  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  *   NON INFRINGEMENT.  See the GNU General Public License for
  *   more details.
- *
- * This file shares the implementation of the userspace memcpy and
- * the kernel's memcpy, copy_to_user and copy_from_user.
  */
 
 #include <arch/chip.h>
 
 
+/*
+ * This file shares the implementation of the userspace memcpy and
+ * the kernel's memcpy, copy_to_user and copy_from_user.
+ */
+
 #include <linux/linkage.h>
 
 /* On TILE64, we wrap these functions via arch/tile/lib/memcpy_tile64.c */
@@ -53,9 +55,9 @@
  */
 ENTRY(__copy_from_user_inatomic)
 .type __copy_from_user_inatomic, @function
-        FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
+	FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
 	  .text.memcpy_common, \
-          .Lend_memcpy_common - __copy_from_user_inatomic)
+	  .Lend_memcpy_common - __copy_from_user_inatomic)
 	{ movei r29, IS_COPY_FROM_USER; j memcpy_common }
 	.size __copy_from_user_inatomic, . - __copy_from_user_inatomic
 
@@ -64,7 +66,7 @@
  */
 ENTRY(__copy_from_user_zeroing)
 .type __copy_from_user_zeroing, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+	FEEDBACK_REENTER(__copy_from_user_inatomic)
 	{ movei r29, IS_COPY_FROM_USER_ZEROING; j memcpy_common }
 	.size __copy_from_user_zeroing, . - __copy_from_user_zeroing
 
@@ -74,13 +76,13 @@
  */
 ENTRY(__copy_to_user_inatomic)
 .type __copy_to_user_inatomic, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+	FEEDBACK_REENTER(__copy_from_user_inatomic)
 	{ movei r29, IS_COPY_TO_USER; j memcpy_common }
 	.size __copy_to_user_inatomic, . - __copy_to_user_inatomic
 
 ENTRY(memcpy)
 .type memcpy, @function
-        FEEDBACK_REENTER(__copy_from_user_inatomic)
+	FEEDBACK_REENTER(__copy_from_user_inatomic)
 	{ movei r29, IS_MEMCPY }
 	.size memcpy, . - memcpy
 	/* Fall through */
@@ -157,35 +159,35 @@
 	{ addi r3, r1, 60; andi r9, r9, -64 }
 
 #if CHIP_HAS_WH64()
-        /* No need to prefetch dst, we'll just do the wh64
-         * right before we copy a line.
+	/* No need to prefetch dst, we'll just do the wh64
+	 * right before we copy a line.
 	 */
 #endif
 
 EX:	{ lw r5, r3; addi r3, r3, 64; movei r4, 1 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, .; move r27, lr }
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bnzt zero, .; move r27, lr }
 EX:	{ lw r6, r3; addi r3, r3, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bnzt zero, . }
 EX:	{ lw r7, r3; addi r3, r3, 64 }
 #if !CHIP_HAS_WH64()
-        /* Prefetch the dest */
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        /* Use a real load to cause a TLB miss if necessary.  We aren't using
-         * r28, so this should be fine.
-         */
+	/* Prefetch the dest */
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bnzt zero, . }
+	/* Use a real load to cause a TLB miss if necessary.  We aren't using
+	 * r28, so this should be fine.
+	 */
 EX:	{ lw r28, r9; addi r9, r9, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        { prefetch r9; addi r9, r9, 64 }
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bnzt zero, . }
-        { prefetch r9; addi r9, r9, 64 }
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bnzt zero, . }
+	{ prefetch r9; addi r9, r9, 64 }
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bnzt zero, . }
+	{ prefetch r9; addi r9, r9, 64 }
 #endif
-        /* Intentionally stall for a few cycles to leave L2 cache alone. */
-        { bz zero, .Lbig_loop2 }
+	/* Intentionally stall for a few cycles to leave L2 cache alone. */
+	{ bz zero, .Lbig_loop2 }
 
 	/* On entry to this loop:
 	 * - r0 points to the start of dst line 0
@@ -197,7 +199,7 @@
 	 *   to some "safe" recently loaded address.
 	 * - r5 contains *(r1 + 60)       [i.e. last word of source line 0]
 	 * - r6 contains *(r1 + 64 + 60)  [i.e. last word of source line 1]
-         * - r9 contains ((r0 + 63) & -64)
+	 * - r9 contains ((r0 + 63) & -64)
 	 *     [start of next dst cache line.]
 	 */
 
@@ -208,137 +210,137 @@
 	/* Copy line 0, first stalling until r5 is ready. */
 EX:	{ move r12, r5; lw r16, r1 }
 	{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+	/* Prefetch several lines ahead. */
 EX:	{ lw r5, r3; addi r3, r3, 64 }
-        { jal .Lcopy_line }
+	{ jal .Lcopy_line }
 
 	/* Copy line 1, first stalling until r6 is ready. */
 EX:	{ move r12, r6; lw r16, r1 }
 	{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+	/* Prefetch several lines ahead. */
 EX:	{ lw r6, r3; addi r3, r3, 64 }
 	{ jal .Lcopy_line }
 
 	/* Copy line 2, first stalling until r7 is ready. */
 EX:	{ move r12, r7; lw r16, r1 }
 	{ bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
-        /* Prefetch several lines ahead. */
+	/* Prefetch several lines ahead. */
 EX:	{ lw r7, r3; addi r3, r3, 64 }
-        /* Use up a caches-busy cycle by jumping back to the top of the
-         * loop. Might as well get it out of the way now.
-         */
-        { j .Lbig_loop }
+	/* Use up a caches-busy cycle by jumping back to the top of the
+	 * loop. Might as well get it out of the way now.
+	 */
+	{ j .Lbig_loop }
 
 
 	/* On entry:
 	 * - r0 points to the destination line.
 	 * - r1 points to the source line.
-         * - r3 is the next prefetch address.
+	 * - r3 is the next prefetch address.
 	 * - r9 holds the last address used for wh64.
 	 * - r12 = WORD_15
-         * - r16 = WORD_0.
-         * - r17 == r1 + 16.
-         * - r27 holds saved lr to restore.
+	 * - r16 = WORD_0.
+	 * - r17 == r1 + 16.
+	 * - r27 holds saved lr to restore.
 	 *
 	 * On exit:
 	 * - r0 is incremented by 64.
 	 * - r1 is incremented by 64, unless that would point to a word
-         *   beyond the end of the source array, in which case it is redirected
-         *   to point to an arbitrary word already in the cache.
+	 *   beyond the end of the source array, in which case it is redirected
+	 *   to point to an arbitrary word already in the cache.
 	 * - r2 is decremented by 64.
-         * - r3 is unchanged, unless it points to a word beyond the
-         *   end of the source array, in which case it is redirected
-         *   to point to an arbitrary word already in the cache.
-         *   Redirecting is OK since if we are that close to the end
-         *   of the array we will not come back to this subroutine
-         *   and use the contents of the prefetched address.
+	 * - r3 is unchanged, unless it points to a word beyond the
+	 *   end of the source array, in which case it is redirected
+	 *   to point to an arbitrary word already in the cache.
+	 *   Redirecting is OK since if we are that close to the end
+	 *   of the array we will not come back to this subroutine
+	 *   and use the contents of the prefetched address.
 	 * - r4 is nonzero iff r2 >= 64.
-         * - r9 is incremented by 64, unless it points beyond the
-         *   end of the last full destination cache line, in which
-         *   case it is redirected to a "safe address" that can be
-         *   clobbered (sp - 64)
+	 * - r9 is incremented by 64, unless it points beyond the
+	 *   end of the last full destination cache line, in which
+	 *   case it is redirected to a "safe address" that can be
+	 *   clobbered (sp - 64)
 	 * - lr contains the value in r27.
 	 */
 
 /* r26 unused */
 
 .Lcopy_line:
-        /* TODO: when r3 goes past the end, we would like to redirect it
-         * to prefetch the last partial cache line (if any) just once, for the
-         * benefit of the final cleanup loop. But we don't want to
-         * prefetch that line more than once, or subsequent prefetches
-         * will go into the RTF. But then .Lbig_loop should unconditionally
-         * branch to top of loop to execute final prefetch, and its
-         * nop should become a conditional branch.
-         */
+	/* TODO: when r3 goes past the end, we would like to redirect it
+	 * to prefetch the last partial cache line (if any) just once, for the
+	 * benefit of the final cleanup loop. But we don't want to
+	 * prefetch that line more than once, or subsequent prefetches
+	 * will go into the RTF. But then .Lbig_loop should unconditionally
+	 * branch to top of loop to execute final prefetch, and its
+	 * nop should become a conditional branch.
+	 */
 
-        /* We need two non-memory cycles here to cover the resources
-         * used by the loads initiated by the caller.
-         */
-        { add r15, r1, r2 }
+	/* We need two non-memory cycles here to cover the resources
+	 * used by the loads initiated by the caller.
+	 */
+	{ add r15, r1, r2 }
 .Lcopy_line2:
-        { slt_u r13, r3, r15; addi r17, r1, 16 }
+	{ slt_u r13, r3, r15; addi r17, r1, 16 }
 
-        /* NOTE: this will stall for one cycle as L1 is busy. */
+	/* NOTE: this will stall for one cycle as L1 is busy. */
 
-        /* Fill second L1D line. */
+	/* Fill second L1D line. */
 EX:	{ lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */
 
 #if CHIP_HAS_WH64()
-        /* Prepare destination line for writing. */
+	/* Prepare destination line for writing. */
 EX:	{ wh64 r9; addi r9, r9, 64 }
 #else
-        /* Prefetch dest line */
+	/* Prefetch dest line */
 	{ prefetch r9; addi r9, r9, 64 }
 #endif
-        /* Load seven words that are L1D hits to cover wh64 L2 usage. */
+	/* Load seven words that are L1D hits to cover wh64 L2 usage. */
 
-        /* Load the three remaining words from the last L1D line, which
-         * we know has already filled the L1D.
-         */
+	/* Load the three remaining words from the last L1D line, which
+	 * we know has already filled the L1D.
+	 */
 EX:	{ lw r4, r1;  addi r1, r1, 4;   addi r20, r1, 16 }   /* r4 = WORD_12 */
 EX:	{ lw r8, r1;  addi r1, r1, 4;   slt_u r13, r20, r15 }/* r8 = WORD_13 */
 EX:	{ lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 }  /* r11 = WORD_14 */
 
-        /* Load the three remaining words from the first L1D line, first
-         * stalling until it has filled by "looking at" r16.
-         */
+	/* Load the three remaining words from the first L1D line, first
+	 * stalling until it has filled by "looking at" r16.
+	 */
 EX:	{ lw r13, r1; addi r1, r1, 4; move zero, r16 }   /* r13 = WORD_1 */
 EX:	{ lw r14, r1; addi r1, r1, 4 }                   /* r14 = WORD_2 */
 EX:	{ lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */
 
-        /* Load second word from the second L1D line, first
-         * stalling until it has filled by "looking at" r17.
-         */
+	/* Load second word from the second L1D line, first
+	 * stalling until it has filled by "looking at" r17.
+	 */
 EX:	{ lw r19, r1; addi r1, r1, 4; move zero, r17 }  /* r19 = WORD_5 */
 
-        /* Store last word to the destination line, potentially dirtying it
-         * for the first time, which keeps the L2 busy for two cycles.
-         */
+	/* Store last word to the destination line, potentially dirtying it
+	 * for the first time, which keeps the L2 busy for two cycles.
+	 */
 EX:	{ sw r10, r12 }                                 /* store(WORD_15) */
 
-        /* Use two L1D hits to cover the sw L2 access above. */
+	/* Use two L1D hits to cover the sw L2 access above. */
 EX:	{ lw r10, r1; addi r1, r1, 4 }                  /* r10 = WORD_6 */
 EX:	{ lw r12, r1; addi r1, r1, 4 }                  /* r12 = WORD_7 */
 
-        /* Fill third L1D line. */
+	/* Fill third L1D line. */
 EX:	{ lw r18, r1; addi r1, r1, 4 }                  /* r18 = WORD_8 */
 
-        /* Store first L1D line. */
+	/* Store first L1D line. */
 EX:	{ sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */
 EX:	{ sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */
 EX:	{ sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */
 #if CHIP_HAS_WH64()
 EX:	{ sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */
 #else
-        /* Back up the r9 to a cache line we are already storing to
+	/* Back up the r9 to a cache line we are already storing to
 	 * if it gets past the end of the dest vector.  Strictly speaking,
 	 * we don't need to back up to the start of a cache line, but it's free
 	 * and tidy, so why not?
-         */
+	 */
 EX:	{ sw r0, r15; addi r0, r0, 4; andi r13, r0, -64 } /* store(WORD_3) */
 #endif
-        /* Store second L1D line. */
+	/* Store second L1D line. */
 EX:	{ sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */
 EX:	{ sw r0, r19; addi r0, r0, 4 }                  /* store(WORD_5) */
 EX:	{ sw r0, r10; addi r0, r0, 4 }                  /* store(WORD_6) */
@@ -348,30 +350,30 @@
 EX:	{ lw r14, r1; addi r1, r1, 4 }                  /* r14 = WORD_10 */
 EX:	{ lw r15, r1; move r1, r20   }                  /* r15 = WORD_11 */
 
-        /* Store third L1D line. */
+	/* Store third L1D line. */
 EX:	{ sw r0, r18; addi r0, r0, 4 }                  /* store(WORD_8) */
 EX:	{ sw r0, r13; addi r0, r0, 4 }                  /* store(WORD_9) */
 EX:	{ sw r0, r14; addi r0, r0, 4 }                  /* store(WORD_10) */
 EX:	{ sw r0, r15; addi r0, r0, 4 }                  /* store(WORD_11) */
 
-        /* Store rest of fourth L1D line. */
+	/* Store rest of fourth L1D line. */
 EX:	{ sw r0, r4;  addi r0, r0, 4 }                  /* store(WORD_12) */
-        {
+	{
 EX:	sw r0, r8                                       /* store(WORD_13) */
-        addi r0, r0, 4
+	addi r0, r0, 4
 	/* Will r2 be > 64 after we subtract 64 below? */
-        shri r4, r2, 7
-        }
-        {
+	shri r4, r2, 7
+	}
+	{
 EX:	sw r0, r11                                      /* store(WORD_14) */
-        addi r0, r0, 8
-        /* Record 64 bytes successfully copied. */
-        addi r2, r2, -64
-        }
+	addi r0, r0, 8
+	/* Record 64 bytes successfully copied. */
+	addi r2, r2, -64
+	}
 
 	{ jrp lr; move lr, r27 }
 
-        /* Convey to the backtrace library that the stack frame is size
+	/* Convey to the backtrace library that the stack frame is size
 	 * zero, and the real return address is on the stack rather than
 	 * in 'lr'.
 	 */
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memcpy_tile64.c linux-libre-2.6.37-gnu/arch/tile/lib/memcpy_tile64.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/memcpy_tile64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memcpy_tile64.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,7 @@
  * we must run with interrupts disabled to avoid the risk of some
  * other code seeing the incoherent data in our cache.  (Recall that
  * our cache is indexed by PA, so even if the other code doesn't use
- * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * our kmap_atomic virtual addresses, they'll still hit in cache using
  * the normal VAs that aren't supposed to hit in cache.)
  */
 static void memcpy_multicache(void *dest, const void *source,
@@ -64,6 +64,7 @@
 	unsigned long flags, newsrc, newdst;
 	pmd_t *pmdp;
 	pte_t *ptep;
+	int type0, type1;
 	int cpu = get_cpu();
 
 	/*
@@ -77,7 +78,8 @@
 	sim_allow_multiple_caching(1);
 
 	/* Set up the new dest mapping */
-	idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+	type0 = kmap_atomic_idx_push();
+	idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0;
 	newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
 	pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
 	ptep = pte_offset_kernel(pmdp, newdst);
@@ -87,7 +89,8 @@
 	}
 
 	/* Set up the new source mapping */
-	idx += (KM_MEMCPY0 - KM_MEMCPY1);
+	type1 = kmap_atomic_idx_push();
+	idx += (type0 - type1);
 	src_pte = hv_pte_set_nc(src_pte);
 	src_pte = hv_pte_clear_writable(src_pte);  /* be paranoid */
 	newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
@@ -119,6 +122,8 @@
 	 * We're done: notify the simulator that all is back to normal,
 	 * and re-enable interrupts and pre-emption.
 	 */
+	kmap_atomic_idx_pop();
+	kmap_atomic_idx_pop();
 	sim_allow_multiple_caching(0);
 	local_irq_restore(flags);
 	put_cpu();
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memmove_32.c linux-libre-2.6.37-gnu/arch/tile/lib/memmove_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/memmove_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memmove_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,63 +0,0 @@
-/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/module.h>
-
-void *memmove(void *dest, const void *src, size_t n)
-{
-	if ((const char *)src >= (char *)dest + n
-	    || (char *)dest >= (const char *)src + n) {
-		/* We found no overlap, so let memcpy do all the heavy
-		 * lifting (prefetching, etc.)
-		 */
-		return memcpy(dest, src, n);
-	}
-
-	if (n != 0) {
-		const uint8_t *in;
-		uint8_t x;
-		uint8_t *out;
-		int stride;
-
-		if (src < dest) {
-			/* copy backwards */
-			in = (const uint8_t *)src + n - 1;
-			out = (uint8_t *)dest + n - 1;
-			stride = -1;
-		} else {
-			/* copy forwards */
-			in = (const uint8_t *)src;
-			out = (uint8_t *)dest;
-			stride = 1;
-		}
-
-		/* Manually software-pipeline this loop. */
-		x = *in;
-		in += stride;
-
-		while (--n != 0) {
-			*out = x;
-			out += stride;
-			x = *in;
-			in += stride;
-		}
-
-		*out = x;
-	}
-
-	return dest;
-}
-EXPORT_SYMBOL(memmove);
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memmove.c linux-libre-2.6.37-gnu/arch/tile/lib/memmove.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/memmove.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memmove.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+	if ((const char *)src >= (char *)dest + n
+	    || (char *)dest >= (const char *)src + n) {
+		/* We found no overlap, so let memcpy do all the heavy
+		 * lifting (prefetching, etc.)
+		 */
+		return memcpy(dest, src, n);
+	}
+
+	if (n != 0) {
+		const uint8_t *in;
+		uint8_t x;
+		uint8_t *out;
+		int stride;
+
+		if (src < dest) {
+			/* copy backwards */
+			in = (const uint8_t *)src + n - 1;
+			out = (uint8_t *)dest + n - 1;
+			stride = -1;
+		} else {
+			/* copy forwards */
+			in = (const uint8_t *)src;
+			out = (uint8_t *)dest;
+			stride = 1;
+		}
+
+		/* Manually software-pipeline this loop. */
+		x = *in;
+		in += stride;
+
+		while (--n != 0) {
+			*out = x;
+			out += stride;
+			x = *in;
+			in += stride;
+		}
+
+		*out = x;
+	}
+
+	return dest;
+}
+EXPORT_SYMBOL(memmove);
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/memset_32.c linux-libre-2.6.37-gnu/arch/tile/lib/memset_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/memset_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/memset_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#undef memset
 
 void *memset(void *s, int c, size_t n)
 {
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/spinlock_32.c linux-libre-2.6.37-gnu/arch/tile/lib/spinlock_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/spinlock_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/spinlock_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -167,23 +167,30 @@
 	 * when we compare them.
 	 */
 	u32 my_ticket_;
+	u32 iterations = 0;
 
-	/* Take out the next ticket; this will also stop would-be readers. */
-	if (val & 1)
-		val = get_rwlock(rwlock);
-	rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
+	/*
+	 * Wait until there are no readers, then bump up the next
+	 * field and capture the ticket value.
+	 */
+	for (;;) {
+		if (!(val & 1)) {
+			if ((val >> RD_COUNT_SHIFT) == 0)
+				break;
+			rwlock->lock = val;
+		}
+		delay_backoff(iterations++);
+		val = __insn_tns((int *)&rwlock->lock);
+	}
 
-	/* Extract my ticket value from the original word. */
+	/* Take out the next ticket and extract my ticket value. */
+	rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
 	my_ticket_ = val >> WR_NEXT_SHIFT;
 
-	/*
-	 * Wait until the "current" field matches our ticket, and
-	 * there are no remaining readers.
-	 */
+	/* Wait until the "current" field matches our ticket. */
 	for (;;) {
 		u32 curr_ = val >> WR_CURR_SHIFT;
-		u32 readers = val >> RD_COUNT_SHIFT;
-		u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers;
+		u32 delta = ((my_ticket_ - curr_) & WR_MASK);
 		if (likely(delta == 0))
 			break;
 
diff -druN linux-libre-2.6.36-gnu/arch/tile/lib/strlen_32.c linux-libre-2.6.37-gnu/arch/tile/lib/strlen_32.c
--- linux-libre-2.6.36-gnu/arch/tile/lib/strlen_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/lib/strlen_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,8 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
+#undef strlen
+
 size_t strlen(const char *s)
 {
 	/* Get an aligned pointer. */
diff -druN linux-libre-2.6.36-gnu/arch/tile/Makefile linux-libre-2.6.37-gnu/arch/tile/Makefile
--- linux-libre-2.6.36-gnu/arch/tile/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -26,8 +26,9 @@
   endif
 endif
 
-
+ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"")
 KBUILD_CFLAGS   += $(CONFIG_DEBUG_EXTRA_FLAGS)
+endif
 
 LIBGCC_PATH     := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
@@ -49,6 +50,20 @@
 libs-y		+= arch/tile/lib/
 libs-y		+= $(LIBGCC_PATH)
 
-
 # See arch/tile/Kbuild for content of core part of the kernel
 core-y		+= arch/tile/
+
+core-$(CONFIG_KVM) += arch/tile/kvm/
+
+ifdef TILERA_ROOT
+INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot
+endif
+
+install:
+	install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
+	install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
+	install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
+
+define archhelp
+	echo '  install         - install kernel into $(INSTALL_PATH)'
+endef
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/fault.c linux-libre-2.6.37-gnu/arch/tile/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,6 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/tty.h>
@@ -66,10 +65,10 @@
 #ifndef __tilegx__
 /*
  * Synthesize the fault a PL0 process would get by doing a word-load of
- * an unaligned address or a high kernel address.  Called indirectly
- * from sys_cmpxchg() in kernel/intvec.S.
+ * an unaligned address or a high kernel address.
  */
-int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *regs)
+SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
+		struct pt_regs *, regs)
 {
 	if (address >= PAGE_OFFSET)
 		force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
@@ -563,10 +562,10 @@
 /*
  * When we take an ITLB or DTLB fault or access violation in the
  * supervisor while the critical section bit is set, the hypervisor is
- * reluctant to write new values into the EX_CONTEXT_1_x registers,
+ * reluctant to write new values into the EX_CONTEXT_K_x registers,
  * since that might indicate we have not yet squirreled the SPR
  * contents away and can thus safely take a recursive interrupt.
- * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_1_2.
+ * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_K_2.
  *
  * Note that this routine is called before homecache_tlb_defer_enter(),
  * which means that we can properly unlock any atomics that might
@@ -610,7 +609,7 @@
 	 * fault.  We didn't set up a kernel stack on initial entry to
 	 * sys_cmpxchg, but instead had one set up by the fault, which
 	 * (because sys_cmpxchg never releases ICS) came to us via the
-	 * SYSTEM_SAVE_1_2 mechanism, and thus EX_CONTEXT_1_[01] are
+	 * SYSTEM_SAVE_K_2 mechanism, and thus EX_CONTEXT_K_[01] are
 	 * still referencing the original user code.  We release the
 	 * atomic lock and rewrite pt_regs so that it appears that we
 	 * came from user-space directly, and after we finish the
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/highmem.c linux-libre-2.6.37-gnu/arch/tile/mm/highmem.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/highmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/highmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,50 +56,6 @@
 }
 EXPORT_SYMBOL(kunmap);
 
-static void debug_kmap_atomic_prot(enum km_type type)
-{
-#ifdef CONFIG_DEBUG_HIGHMEM
-	static unsigned warn_count = 10;
-
-	if (unlikely(warn_count == 0))
-		return;
-
-	if (unlikely(in_interrupt())) {
-		if (in_irq()) {
-			if (type != KM_IRQ0 && type != KM_IRQ1 &&
-			    type != KM_BIO_SRC_IRQ &&
-			    /* type != KM_BIO_DST_IRQ && */
-			    type != KM_BOUNCE_READ) {
-				WARN_ON(1);
-				warn_count--;
-			}
-		} else if (!irqs_disabled()) {	/* softirq */
-			if (type != KM_IRQ0 && type != KM_IRQ1 &&
-			    type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
-			    type != KM_SKB_SUNRPC_DATA &&
-			    type != KM_SKB_DATA_SOFTIRQ &&
-			    type != KM_BOUNCE_READ) {
-				WARN_ON(1);
-				warn_count--;
-			}
-		}
-	}
-
-	if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
-	    type == KM_BIO_SRC_IRQ /* || type == KM_BIO_DST_IRQ */) {
-		if (!irqs_disabled()) {
-			WARN_ON(1);
-			warn_count--;
-		}
-	} else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
-		if (irq_count() == 0 && !irqs_disabled()) {
-			WARN_ON(1);
-			warn_count--;
-		}
-	}
-#endif
-}
-
 /*
  * Describe a single atomic mapping of a page on a given cpu at a
  * given address, and allow it to be linked into a list.
@@ -240,10 +196,10 @@
  * When holding an atomic kmap is is not legal to sleep, so atomic
  * kmaps are appropriate for short, tight code paths only.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 	pte_t *pte;
 
 	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
@@ -255,8 +211,7 @@
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic_prot(type);
-
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 	pte = kmap_get_pte(vaddr);
@@ -269,28 +224,35 @@
 }
 EXPORT_SYMBOL(kmap_atomic_prot);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
 	/* PAGE_NONE is a magic value that tells us to check immutability. */
-	return kmap_atomic_prot(page, type, PAGE_NONE);
+	return kmap_atomic_prot(page, PAGE_NONE);
 }
-EXPORT_SYMBOL(kmap_atomic);
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+void __kunmap_atomic(void *kvaddr)
 {
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
-	/*
-	 * Force other mappings to Oops if they try to access this pte without
-	 * first remapping it.  Keeping stale mappings around is a bad idea.
-	 */
-	if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) {
+	if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+	    vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
 		pte_t *pte = kmap_get_pte(vaddr);
 		pte_t pteval = *pte;
+		int idx, type;
+
+		type = kmap_atomic_idx();
+		idx = type + KM_TYPE_NR*smp_processor_id();
+
+		/*
+		 * Force other mappings to Oops if they try to access this pte
+		 * without first remapping it.  Keeping stale mappings around
+		 * is a bad idea.
+		 */
 		BUG_ON(!pte_present(pteval) && !pte_migrating(pteval));
 		kmap_atomic_unregister(pte_page(pteval), vaddr);
 		kpte_clear_flush(pte, vaddr);
+		kmap_atomic_idx_pop();
 	} else {
 		/* Must be a lowmem page */
 		BUG_ON(vaddr < PAGE_OFFSET);
@@ -300,19 +262,19 @@
 	arch_flush_lazy_mmu_mode();
 	pagefault_enable();
 }
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
+EXPORT_SYMBOL(__kunmap_atomic);
 
 /*
  * This API is supposed to allow us to map memory without a "struct page".
  * Currently we don't support this, though this may change in the future.
  */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+void *kmap_atomic_pfn(unsigned long pfn)
 {
-	return kmap_atomic(pfn_to_page(pfn), type);
+	return kmap_atomic(pfn_to_page(pfn));
 }
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
-	return kmap_atomic_prot(pfn_to_page(pfn), type, prot);
+	return kmap_atomic_prot(pfn_to_page(pfn), prot);
 }
 
 struct page *kmap_atomic_to_page(void *ptr)
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/homecache.c linux-libre-2.6.37-gnu/arch/tile/mm/homecache.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/homecache.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/homecache.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,6 +37,8 @@
 #include <asm/pgalloc.h>
 #include <asm/homecache.h>
 
+#include <arch/sim.h>
+
 #include "migrate.h"
 
 
@@ -217,13 +219,6 @@
 	return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
 }
 
-/* On the simulator, confirm lines have been evicted everywhere. */
-static void validate_lines_evicted(unsigned long pfn, size_t length)
-{
-	sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
-		    (HV_PhysAddr)pfn << PAGE_SHIFT, length);
-}
-
 /* Flush a page out of whatever cache(s) it is in. */
 void homecache_flush_cache(struct page *page, int order)
 {
@@ -234,7 +229,7 @@
 
 	homecache_mask(page, pages, &home_mask);
 	flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
-	validate_lines_evicted(pfn, pages * PAGE_SIZE);
+	sim_validate_lines_evicted(PFN_PHYS(pfn), pages * PAGE_SIZE);
 }
 
 
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/hugetlbpage.c linux-libre-2.6.37-gnu/arch/tile/mm/hugetlbpage.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/hugetlbpage.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/hugetlbpage.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/sysctl.h>
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/init.c linux-libre-2.6.37-gnu/arch/tile/mm/init.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -988,8 +988,12 @@
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
 {
-	strict_strtol(str, 0, &initfree);
-	pr_info("initfree: %s free init pages\n", initfree ? "will" : "won't");
+	long val;
+	if (strict_strtol(str, 0, &val)) {
+		initfree = val;
+		pr_info("initfree: %s free init pages\n",
+			initfree ? "will" : "won't");
+	}
 	return 1;
 }
 __setup("initfree=", set_initfree);
@@ -1060,7 +1064,7 @@
 
 	/*
 	 * Free the pages mapped from 0xc0000000 that correspond to code
-	 * pages from 0xfd000000 that we won't use again after init.
+	 * pages from MEM_SV_INTRPT that we won't use again after init.
 	 */
 	free_init_pages("unused kernel text",
 			(unsigned long)_sinittext - text_delta,
diff -druN linux-libre-2.6.36-gnu/arch/tile/mm/pgtable.c linux-libre-2.6.37-gnu/arch/tile/mm/pgtable.c
--- linux-libre-2.6.36-gnu/arch/tile/mm/pgtable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/tile/mm/pgtable.c	2011-01-04 19:50:19.000000000 -0500
@@ -134,9 +134,9 @@
 }
 
 #if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
 {
-	pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+	pte_t *pte = kmap_atomic(pmd_page(*dir)) +
 		(pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
 	return &pte[pte_index(address)];
 }
diff -druN linux-libre-2.6.36-gnu/arch/um/defconfig linux-libre-2.6.37-gnu/arch/um/defconfig
--- linux-libre-2.6.36-gnu/arch/um/defconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/defconfig	2011-01-04 19:50:19.000000000 -0500
@@ -566,7 +566,6 @@
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
-CONFIG_HAS_DMA=y
 
 #
 # SCSI device support
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/harddog_kern.c linux-libre-2.6.37-gnu/arch/um/drivers/harddog_kern.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/harddog_kern.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/harddog_kern.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,7 @@
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
@@ -50,6 +50,7 @@
 
 MODULE_LICENSE("GPL");
 
+static DEFINE_MUTEX(harddog_mutex);
 static DEFINE_SPINLOCK(lock);
 static int timer_alive;
 static int harddog_in_fd = -1;
@@ -66,7 +67,7 @@
 	int err = -EBUSY;
 	char *sock = NULL;
 
-	lock_kernel();
+	mutex_lock(&harddog_mutex);
 	spin_lock(&lock);
 	if(timer_alive)
 		goto err;
@@ -83,11 +84,11 @@
 
 	timer_alive = 1;
 	spin_unlock(&lock);
-	unlock_kernel();
+	mutex_unlock(&harddog_mutex);
 	return nonseekable_open(inode, file);
 err:
 	spin_unlock(&lock);
-	unlock_kernel();
+	mutex_unlock(&harddog_mutex);
 	return err;
 }
 
@@ -153,9 +154,9 @@
 {
 	long ret;
 
-	lock_kernel();
+	mutex_lock(&harddog_mutex);
 	ret = harddog_ioctl_unlocked(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&harddog_mutex);
 
 	return ret;
 }
@@ -166,6 +167,7 @@
 	.unlocked_ioctl	= harddog_ioctl,
 	.open		= harddog_open,
 	.release	= harddog_release,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice harddog_miscdev = {
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/hostaudio_kern.c linux-libre-2.6.37-gnu/arch/um/drivers/hostaudio_kern.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/hostaudio_kern.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/hostaudio_kern.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
 #include "linux/slab.h"
 #include "linux/sound.h"
 #include "linux/soundcard.h"
-#include "linux/smp_lock.h"
+#include "linux/mutex.h"
 #include "asm/uaccess.h"
 #include "init.h"
 #include "os.h"
@@ -63,6 +63,8 @@
 __uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
 #endif
 
+static DEFINE_MUTEX(hostaudio_mutex);
+
 /* /dev/dsp file operations */
 
 static ssize_t hostaudio_read(struct file *file, char __user *buffer,
@@ -198,9 +200,9 @@
 		w = 1;
 
 	kparam_block_sysfs_write(dsp);
-	lock_kernel();
+	mutex_lock(&hostaudio_mutex);
 	ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
-	unlock_kernel();
+	mutex_unlock(&hostaudio_mutex);
 	kparam_unblock_sysfs_write(dsp);
 
 	if (ret < 0) {
@@ -259,9 +261,9 @@
 		w = 1;
 
 	kparam_block_sysfs_write(mixer);
-	lock_kernel();
+	mutex_lock(&hostaudio_mutex);
 	ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
-	unlock_kernel();
+	mutex_unlock(&hostaudio_mutex);
 	kparam_unblock_sysfs_write(mixer);
 
 	if (ret < 0) {
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/line.c linux-libre-2.6.37-gnu/arch/um/drivers/line.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/line.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/line.c	2011-01-04 19:50:19.000000000 -0500
@@ -727,6 +727,9 @@
 
 static void free_winch(struct winch *winch, int free_irq_ok)
 {
+	if (free_irq_ok)
+		free_irq(WINCH_IRQ, winch);
+
 	list_del(&winch->list);
 
 	if (winch->pid != -1)
@@ -735,8 +738,6 @@
 		os_close_file(winch->fd);
 	if (winch->stack != 0)
 		free_stack(winch->stack, 0);
-	if (free_irq_ok)
-		free_irq(WINCH_IRQ, winch);
 	kfree(winch);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/mconsole_kern.c linux-libre-2.6.37-gnu/arch/um/drivers/mconsole_kern.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/mconsole_kern.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/mconsole_kern.c	2011-01-04 19:50:19.000000000 -0500
@@ -843,6 +843,7 @@
 static const struct file_operations mconsole_proc_fops = {
 	.owner		= THIS_MODULE,
 	.write		= mconsole_proc_write,
+	.llseek		= noop_llseek,
 };
 
 static int create_proc_mconsole(void)
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/mmapper_kern.c linux-libre-2.6.37-gnu/arch/um/drivers/mmapper_kern.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/mmapper_kern.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/mmapper_kern.c	2011-01-04 19:50:19.000000000 -0500
@@ -93,6 +93,7 @@
 	.mmap		= mmapper_mmap,
 	.open		= mmapper_open,
 	.release	= mmapper_release,
+	.llseek		= default_llseek,
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/random.c linux-libre-2.6.37-gnu/arch/um/drivers/random.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/random.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/random.c	2011-01-04 19:50:19.000000000 -0500
@@ -100,6 +100,7 @@
 	.owner		= THIS_MODULE,
 	.open		= rng_dev_open,
 	.read		= rng_dev_read,
+	.llseek		= noop_llseek,
 };
 
 /* rng_init shouldn't be called more than once at boot time */
diff -druN linux-libre-2.6.36-gnu/arch/um/drivers/ubd_kern.c linux-libre-2.6.37-gnu/arch/um/drivers/ubd_kern.c
--- linux-libre-2.6.36-gnu/arch/um/drivers/ubd_kern.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/drivers/ubd_kern.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,7 @@
 #include "linux/mm.h"
 #include "linux/slab.h"
 #include "linux/vmalloc.h"
-#include "linux/smp_lock.h"
+#include "linux/mutex.h"
 #include "linux/blkpg.h"
 #include "linux/genhd.h"
 #include "linux/spinlock.h"
@@ -100,6 +100,7 @@
 #define DRIVER_NAME "uml-blkdev"
 
 static DEFINE_MUTEX(ubd_lock);
+static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
 
 static int ubd_open(struct block_device *bdev, fmode_t mode);
 static int ubd_release(struct gendisk *disk, fmode_t mode);
@@ -1101,7 +1102,7 @@
 	struct ubd *ubd_dev = disk->private_data;
 	int err = 0;
 
-	lock_kernel();
+	mutex_lock(&ubd_mutex);
 	if(ubd_dev->count == 0){
 		err = ubd_open_dev(ubd_dev);
 		if(err){
@@ -1120,7 +1121,7 @@
 	        err = -EROFS;
 	}*/
 out:
-	unlock_kernel();
+	mutex_unlock(&ubd_mutex);
 	return err;
 }
 
@@ -1128,10 +1129,10 @@
 {
 	struct ubd *ubd_dev = disk->private_data;
 
-	lock_kernel();
+	mutex_lock(&ubd_mutex);
 	if(--ubd_dev->count == 0)
 		ubd_close_dev(ubd_dev);
-	unlock_kernel();
+	mutex_unlock(&ubd_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/um/include/asm/dma-mapping.h linux-libre-2.6.37-gnu/arch/um/include/asm/dma-mapping.h
--- linux-libre-2.6.36-gnu/arch/um/include/asm/dma-mapping.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/include/asm/dma-mapping.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,112 +0,0 @@
-#ifndef _ASM_DMA_MAPPING_H
-#define _ASM_DMA_MAPPING_H
-
-#include <asm/scatterlist.h>
-
-static inline int
-dma_supported(struct device *dev, u64 mask)
-{
-	BUG();
-	return(0);
-}
-
-static inline int
-dma_set_mask(struct device *dev, u64 dma_mask)
-{
-	BUG();
-	return(0);
-}
-
-static inline void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-		   gfp_t flag)
-{
-	BUG();
-	return((void *) 0);
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		  dma_addr_t dma_handle)
-{
-	BUG();
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG();
-	return(0);
-}
-
-static inline void
-dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		 enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
-	     unsigned long offset, size_t size,
-	     enum dma_data_direction direction)
-{
-	BUG();
-	return(0);
-}
-
-static inline void
-dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-	   enum dma_data_direction direction)
-{
-	BUG();
-	return(0);
-}
-
-static inline void
-dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-	     enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-		enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline void
-dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-	    enum dma_data_direction direction)
-{
-	BUG();
-}
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-
-static inline void
-dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-	       enum dma_data_direction direction)
-{
-	BUG();
-}
-
-static inline int
-dma_mapping_error(struct device *dev, dma_addr_t dma_handle)
-{
-	BUG();
-	return 0;
-}
-
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/um/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/um/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/um/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -338,9 +338,7 @@
 	((pte_t *) pmd_page_vaddr(*(dir)) +  pte_index(address))
 #define pte_offset_map(dir, address) \
 	((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address))
-#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 
 struct mm_struct;
 extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
diff -druN linux-libre-2.6.36-gnu/arch/um/include/asm/ptrace-generic.h linux-libre-2.6.37-gnu/arch/um/include/asm/ptrace-generic.h
--- linux-libre-2.6.36-gnu/arch/um/include/asm/ptrace-generic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/include/asm/ptrace-generic.h	2011-01-04 19:50:19.000000000 -0500
@@ -38,8 +38,8 @@
 
 struct task_struct;
 
-extern long subarch_ptrace(struct task_struct *child, long request, long addr,
-			   long data);
+extern long subarch_ptrace(struct task_struct *child, long request,
+	unsigned long addr, unsigned long data);
 extern unsigned long getreg(struct task_struct *child, int regno);
 extern int putreg(struct task_struct *child, int regno, unsigned long value);
 extern int get_fpregs(struct user_i387_struct __user *buf,
diff -druN linux-libre-2.6.36-gnu/arch/um/include/asm/system.h linux-libre-2.6.37-gnu/arch/um/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/um/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,23 +8,38 @@
 extern void block_signals(void);
 extern void unblock_signals(void);
 
-#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
-				     (flags) = get_signals(); } while(0)
-#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
-				      set_signals(flags); } while(0)
+static inline unsigned long arch_local_save_flags(void)
+{
+	return get_signals();
+}
 
-#define local_irq_save(flags) do { local_save_flags(flags); \
-                                   local_irq_disable(); } while(0)
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	set_signals(flags);
+}
 
-#define local_irq_enable() unblock_signals()
-#define local_irq_disable() block_signals()
+static inline void arch_local_irq_enable(void)
+{
+	unblock_signals();
+}
 
-#define irqs_disabled()                 \
-({                                      \
-        unsigned long flags;            \
-        local_save_flags(flags);        \
-        (flags == 0);                   \
-})
+static inline void arch_local_irq_disable(void)
+{
+	block_signals();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	flags = arch_local_save_flags();
+	arch_local_irq_disable();
+	return flags;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_local_save_flags() == 0;
+}
 
 extern void *_switch_to(void *prev, void *next, void *last);
 #define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
diff -druN linux-libre-2.6.36-gnu/arch/um/Kconfig.common linux-libre-2.6.37-gnu/arch/um/Kconfig.common
--- linux-libre-2.6.36-gnu/arch/um/Kconfig.common	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/Kconfig.common	2011-01-04 19:50:19.000000000 -0500
@@ -19,8 +19,6 @@
 config NO_IOMEM
 	def_bool y
 
-mainmenu "Linux/Usermode Kernel Configuration"
-
 config ISA
 	bool
 
diff -druN linux-libre-2.6.36-gnu/arch/um/Kconfig.um linux-libre-2.6.37-gnu/arch/um/Kconfig.um
--- linux-libre-2.6.36-gnu/arch/um/Kconfig.um	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/Kconfig.um	2011-01-04 19:50:19.000000000 -0500
@@ -120,6 +120,9 @@
 
 	  If you don't know what to do, say N.
 
+config GENERIC_HARDIRQS_NO__DO_IRQ
+	def_bool y
+
 config NR_CPUS
 	int "Maximum number of CPUs (2-32)"
 	range 2 32
@@ -147,3 +150,6 @@
 	  This option determines the size of UML kernel stacks.  They will
 	  be 1 << order pages.  The default is OK unless you're running Valgrind
 	  on UML, in which case, set this to 3.
+
+config NO_DMA
+	def_bool y
diff -druN linux-libre-2.6.36-gnu/arch/um/kernel/dyn.lds.S linux-libre-2.6.37-gnu/arch/um/kernel/dyn.lds.S
--- linux-libre-2.6.36-gnu/arch/um/kernel/dyn.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/kernel/dyn.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -50,8 +50,18 @@
   .rela.got       : { *(.rela.got) }
   .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
   .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
-  .rel.plt        : { *(.rel.plt) }
-  .rela.plt       : { *(.rela.plt) }
+  .rel.plt : {
+	*(.rel.plt)
+	PROVIDE_HIDDEN(__rel_iplt_start = .);
+	*(.rel.iplt)
+	PROVIDE_HIDDEN(__rel_iplt_end = .);
+  }
+  .rela.plt : {
+	*(.rela.plt)
+	PROVIDE_HIDDEN(__rela_iplt_start = .);
+	*(.rela.iplt)
+	PROVIDE_HIDDEN(__rela_iplt_end = .);
+  }
   .init           : {
     KEEP (*(.init))
   } =0x90909090
diff -druN linux-libre-2.6.36-gnu/arch/um/kernel/exec.c linux-libre-2.6.37-gnu/arch/um/kernel/exec.c
--- linux-libre-2.6.36-gnu/arch/um/kernel/exec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/kernel/exec.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 
 #include "linux/stddef.h"
 #include "linux/fs.h"
-#include "linux/smp_lock.h"
 #include "linux/ptrace.h"
 #include "linux/sched.h"
 #include "linux/slab.h"
@@ -78,13 +77,11 @@
 	long error;
 	char *filename;
 
-	lock_kernel();
 	filename = getname(file);
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename)) goto out;
 	error = execve1(filename, argv, env);
 	putname(filename);
  out:
-	unlock_kernel();
 	return error;
 }
diff -druN linux-libre-2.6.36-gnu/arch/um/kernel/irq.c linux-libre-2.6.37-gnu/arch/um/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/um/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %14s", irq_desc[i].chip->name);
 		seq_printf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
@@ -334,7 +334,7 @@
 {
 	struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
 	irq_enter();
-	__do_IRQ(irq);
+	generic_handle_irq(irq);
 	irq_exit();
 	set_irq_regs(old_regs);
 	return 1;
@@ -369,7 +369,7 @@
 
 /* This is used for everything else than the timer. */
 static struct irq_chip normal_irq_type = {
-	.typename = "SIGIO",
+	.name = "SIGIO",
 	.release = free_irq_by_irq_and_dev,
 	.disable = dummy,
 	.enable = dummy,
@@ -378,7 +378,7 @@
 };
 
 static struct irq_chip SIGVTALRM_irq_type = {
-	.typename = "SIGVTALRM",
+	.name = "SIGVTALRM",
 	.release = free_irq_by_irq_and_dev,
 	.shutdown = dummy, /* never called */
 	.disable = dummy,
@@ -391,17 +391,10 @@
 {
 	int i;
 
-	irq_desc[TIMER_IRQ].status = IRQ_DISABLED;
-	irq_desc[TIMER_IRQ].action = NULL;
-	irq_desc[TIMER_IRQ].depth = 1;
-	irq_desc[TIMER_IRQ].chip = &SIGVTALRM_irq_type;
-	enable_irq(TIMER_IRQ);
+	set_irq_chip_and_handler(TIMER_IRQ, &SIGVTALRM_irq_type, handle_edge_irq);
+
 	for (i = 1; i < NR_IRQS; i++) {
-		irq_desc[i].status = IRQ_DISABLED;
-		irq_desc[i].action = NULL;
-		irq_desc[i].depth = 1;
-		irq_desc[i].chip = &normal_irq_type;
-		enable_irq(i);
+		set_irq_chip_and_handler(i, &normal_irq_type, handle_edge_irq);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/um/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/um/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/um/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,10 +42,12 @@
 extern int peek_user(struct task_struct * child, long addr, long data);
 extern int poke_user(struct task_struct * child, long addr, long data);
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int i, ret;
-	unsigned long __user *p = (void __user *)(unsigned long)data;
+	unsigned long __user *p = (void __user *)data;
+	void __user *vp = p;
 
 	switch (request) {
 	/* read word at location addr. */
@@ -107,24 +109,20 @@
 #endif
 #ifdef PTRACE_GETFPREGS
 	case PTRACE_GETFPREGS: /* Get the child FPU state. */
-		ret = get_fpregs((struct user_i387_struct __user *) data,
-				 child);
+		ret = get_fpregs(vp, child);
 		break;
 #endif
 #ifdef PTRACE_SETFPREGS
 	case PTRACE_SETFPREGS: /* Set the child FPU state. */
-	        ret = set_fpregs((struct user_i387_struct __user *) data,
-				 child);
+		ret = set_fpregs(vp, child);
 		break;
 #endif
 	case PTRACE_GET_THREAD_AREA:
-		ret = ptrace_get_thread_area(child, addr,
-					     (struct user_desc __user *) data);
+		ret = ptrace_get_thread_area(child, addr, vp);
 		break;
 
 	case PTRACE_SET_THREAD_AREA:
-		ret = ptrace_set_thread_area(child, addr,
-					     (struct user_desc __user *) data);
+		ret = ptrace_set_thread_area(child, addr, vp);
 		break;
 
 	case PTRACE_FAULTINFO: {
@@ -134,7 +132,8 @@
 		 * On i386, ptrace_faultinfo is smaller!
 		 */
 		ret = copy_to_user(p, &child->thread.arch.faultinfo,
-				   sizeof(struct ptrace_faultinfo));
+				   sizeof(struct ptrace_faultinfo)) ?
+			-EIO : 0;
 		break;
 	}
 
@@ -158,7 +157,7 @@
 #ifdef PTRACE_ARCH_PRCTL
 	case PTRACE_ARCH_PRCTL:
 		/* XXX Calls ptrace on the host - needs some SMP thinking */
-		ret = arch_prctl(child, data, (void *) addr);
+		ret = arch_prctl(child, data, (void __user *) addr);
 		break;
 #endif
 	default:
diff -druN linux-libre-2.6.36-gnu/arch/um/kernel/uml.lds.S linux-libre-2.6.37-gnu/arch/um/kernel/uml.lds.S
--- linux-libre-2.6.36-gnu/arch/um/kernel/uml.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/kernel/uml.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -22,7 +22,7 @@
   _text = .;
   _stext = .;
   __init_begin = .;
-  INIT_TEXT_SECTION(PAGE_SIZE)
+  INIT_TEXT_SECTION(0)
   . = ALIGN(PAGE_SIZE);
 
   .text      :
@@ -43,6 +43,23 @@
 	__syscall_stub_end = .;
   }
 
+  /*
+   * These are needed even in a static link, even if they wind up being empty.
+   * Newer glibc needs these __rel{,a}_iplt_{start,end} symbols.
+   */
+  .rel.plt : {
+	*(.rel.plt)
+	PROVIDE_HIDDEN(__rel_iplt_start = .);
+	*(.rel.iplt)
+	PROVIDE_HIDDEN(__rel_iplt_end = .);
+  }
+  .rela.plt : {
+	*(.rela.plt)
+	PROVIDE_HIDDEN(__rela_iplt_start = .);
+	*(.rela.iplt)
+	PROVIDE_HIDDEN(__rela_iplt_end = .);
+  }
+
   #include "asm/common.lds.S"
 
   init.data : { INIT_DATA }
diff -druN linux-libre-2.6.36-gnu/arch/um/os-Linux/time.c linux-libre-2.6.37-gnu/arch/um/os-Linux/time.c
--- linux-libre-2.6.36-gnu/arch/um/os-Linux/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/os-Linux/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 long long disable_timer(void)
 {
 	struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
-	int remain, max = UM_NSEC_PER_SEC / UM_HZ;
+	long long remain, max = UM_NSEC_PER_SEC / UM_HZ;
 
 	if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
 		printk(UM_KERN_ERR "disable_timer - setitimer failed, "
diff -druN linux-libre-2.6.36-gnu/arch/um/sys-i386/ptrace.c linux-libre-2.6.37-gnu/arch/um/sys-i386/ptrace.c
--- linux-libre-2.6.36-gnu/arch/um/sys-i386/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/sys-i386/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -203,8 +203,8 @@
 				     (unsigned long *) &fpregs);
 }
 
-long subarch_ptrace(struct task_struct *child, long request, long addr,
-		    long data)
+long subarch_ptrace(struct task_struct *child, long request,
+		    unsigned long addr, unsigned long data)
 {
 	return -EIO;
 }
diff -druN linux-libre-2.6.36-gnu/arch/um/sys-x86_64/ptrace.c linux-libre-2.6.37-gnu/arch/um/sys-x86_64/ptrace.c
--- linux-libre-2.6.36-gnu/arch/um/sys-x86_64/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/um/sys-x86_64/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -175,19 +175,18 @@
 	return restore_fp_registers(userspace_pid[cpu], fpregs);
 }
 
-long subarch_ptrace(struct task_struct *child, long request, long addr,
-		    long data)
+long subarch_ptrace(struct task_struct *child, long request,
+		    unsigned long addr, unsigned long data)
 {
 	int ret = -EIO;
+	void __user *datap = (void __user *) data;
 
 	switch (request) {
 	case PTRACE_GETFPXREGS: /* Get the child FPU state. */
-		ret = get_fpregs((struct user_i387_struct __user *) data,
-				 child);
+		ret = get_fpregs(datap, child);
 		break;
 	case PTRACE_SETFPXREGS: /* Set the child FPU state. */
-		ret = set_fpregs((struct user_i387_struct __user *) data,
-				 child);
+		ret = set_fpregs(datap, child);
 		break;
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/boot/compressed/misc.c linux-libre-2.6.37-gnu/arch/x86/boot/compressed/misc.c
--- linux-libre-2.6.36-gnu/arch/x86/boot/compressed/misc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/boot/compressed/misc.c	2011-01-04 19:50:19.000000000 -0500
@@ -229,18 +229,35 @@
 		ss[i] = c;
 	return s;
 }
-
+#ifdef CONFIG_X86_32
 void *memcpy(void *dest, const void *src, size_t n)
 {
-	int i;
-	const char *s = src;
-	char *d = dest;
+	int d0, d1, d2;
+	asm volatile(
+		"rep ; movsl\n\t"
+		"movl %4,%%ecx\n\t"
+		"rep ; movsb\n\t"
+		: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+		: "0" (n >> 2), "g" (n & 3), "1" (dest), "2" (src)
+		: "memory");
 
-	for (i = 0; i < n; i++)
-		d[i] = s[i];
 	return dest;
 }
+#else
+void *memcpy(void *dest, const void *src, size_t n)
+{
+	long d0, d1, d2;
+	asm volatile(
+		"rep ; movsq\n\t"
+		"movq %4,%%rcx\n\t"
+		"rep ; movsb\n\t"
+		: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+		: "0" (n >> 3), "g" (n & 7), "1" (dest), "2" (src)
+		: "memory");
 
+	return dest;
+}
+#endif
 
 static void error(char *x)
 {
@@ -338,7 +355,7 @@
 	if (heap > 0x3fffffffffffUL)
 		error("Destination address too large");
 #else
-	if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff))
+	if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
 		error("Destination address too large");
 #endif
 #ifndef CONFIG_RELOCATABLE
diff -druN linux-libre-2.6.36-gnu/arch/x86/crypto/ghash-clmulni-intel_glue.c linux-libre-2.6.37-gnu/arch/x86/crypto/ghash-clmulni-intel_glue.c
--- linux-libre-2.6.36-gnu/arch/x86/crypto/ghash-clmulni-intel_glue.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/crypto/ghash-clmulni-intel_glue.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
  * by the Free Software Foundation.
  */
 
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
diff -druN linux-libre-2.6.36-gnu/arch/x86/ia32/sys_ia32.c linux-libre-2.6.37-gnu/arch/x86/ia32/sys_ia32.c
--- linux-libre-2.6.36-gnu/arch/x86/ia32/sys_ia32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/ia32/sys_ia32.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,6 @@
 #include <linux/syscalls.h>
 #include <linux/times.h>
 #include <linux/utsname.h>
-#include <linux/smp_lock.h>
 #include <linux/mm.h>
 #include <linux/uio.h>
 #include <linux/poll.h>
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/acpi.h linux-libre-2.6.37-gnu/arch/x86/include/asm/acpi.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/acpi.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/acpi.h	2011-01-04 19:50:19.000000000 -0500
@@ -93,6 +93,9 @@
 extern int acpi_sci_override_gsi;
 void acpi_pic_sci_set_trigger(unsigned int, u16);
 
+extern int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
+				  int trigger, int polarity);
+
 static inline void disable_acpi(void)
 {
 	acpi_disabled = 1;
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/alternative.h linux-libre-2.6.37-gnu/arch/x86/include/asm/alternative.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/alternative.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/alternative.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/stringify.h>
+#include <linux/jump_label.h>
 #include <asm/asm.h>
 
 /*
@@ -160,6 +161,8 @@
 #define __parainstructions_end	NULL
 #endif
 
+extern void *text_poke_early(void *addr, const void *opcode, size_t len);
+
 /*
  * Clear and restore the kernel write-protection flag on the local CPU.
  * Allows the kernel to edit read-only pages.
@@ -180,4 +183,12 @@
 extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
 
+#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
+#define IDEAL_NOP_SIZE_5 5
+extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
+extern void arch_init_ideal_nop5(void);
+#else
+static inline void arch_init_ideal_nop5(void) {}
+#endif
+
 #endif /* _ASM_X86_ALTERNATIVE_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu.h linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
@@ -24,11 +24,11 @@
 
 #ifdef CONFIG_AMD_IOMMU
 
-extern void amd_iommu_detect(void);
+extern int amd_iommu_detect(void);
 
 #else
 
-static inline void amd_iommu_detect(void) { }
+static inline int amd_iommu_detect(void) { return -ENODEV; }
 
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu_proto.h linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu_proto.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu_proto.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu_proto.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *
  * This program is free software; you can redistribute it and/or modify it
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu_types.h linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu_types.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_iommu_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_iommu_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
@@ -416,13 +416,22 @@
 	struct dma_ops_domain *default_dom;
 
 	/*
-	 * This array is required to work around a potential BIOS bug.
-	 * The BIOS may miss to restore parts of the PCI configuration
-	 * space when the system resumes from S3. The result is that the
-	 * IOMMU does not execute commands anymore which leads to system
-	 * failure.
+	 * We can't rely on the BIOS to restore all values on reinit, so we
+	 * need to stash them
 	 */
-	u32 cache_cfg[4];
+
+	/* The iommu BAR */
+	u32 stored_addr_lo;
+	u32 stored_addr_hi;
+
+	/*
+	 * Each iommu has 6 l1s, each of which is documented as having 0x12
+	 * registers
+	 */
+	u32 stored_l1[6][0x12];
+
+	/* The l2 indirect registers */
+	u32 stored_l2[0x83];
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_nb.h linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_nb.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/amd_nb.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/amd_nb.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,39 @@
+#ifndef _ASM_X86_AMD_NB_H
+#define _ASM_X86_AMD_NB_H
+
+#include <linux/pci.h>
+
+extern struct pci_device_id k8_nb_ids[];
+struct bootnode;
+
+extern int early_is_k8_nb(u32 value);
+extern int cache_k8_northbridges(void);
+extern void k8_flush_garts(void);
+extern int k8_get_nodes(struct bootnode *nodes);
+extern int k8_numa_init(unsigned long start_pfn, unsigned long end_pfn);
+extern int k8_scan_nodes(void);
+
+struct k8_northbridge_info {
+	u16 num;
+	u8 gart_supported;
+	struct pci_dev **nb_misc;
+};
+extern struct k8_northbridge_info k8_northbridges;
+
+#ifdef CONFIG_AMD_NB
+
+static inline struct pci_dev *node_to_k8_nb_misc(int node)
+{
+	return (node < k8_northbridges.num) ? k8_northbridges.nb_misc[node] : NULL;
+}
+
+#else
+
+static inline struct pci_dev *node_to_k8_nb_misc(int node)
+{
+	return NULL;
+}
+#endif
+
+
+#endif /* _ASM_X86_AMD_NB_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/apb_timer.h linux-libre-2.6.37-gnu/arch/x86/include/asm/apb_timer.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/apb_timer.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/apb_timer.h	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,6 @@
 extern unsigned long apbt_quick_calibrate(void);
 extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu);
 extern void apbt_setup_secondary_clock(void);
-extern unsigned int boot_cpu_id;
 
 extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint);
 extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/apicdef.h linux-libre-2.6.37-gnu/arch/x86/include/asm/apicdef.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/apicdef.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/apicdef.h	2011-01-04 19:50:19.000000000 -0500
@@ -131,6 +131,7 @@
 #define APIC_EILVTn(n)	(0x500 + 0x10 * n)
 #define		APIC_EILVT_NR_AMD_K8	1	/* # of extended interrupts */
 #define		APIC_EILVT_NR_AMD_10H	4
+#define		APIC_EILVT_NR_MAX	APIC_EILVT_NR_AMD_10H
 #define		APIC_EILVT_LVTOFF(x)	(((x) >> 4) & 0xF)
 #define		APIC_EILVT_MSG_FIX	0x0
 #define		APIC_EILVT_MSG_SMI	0x2
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/apic.h linux-libre-2.6.37-gnu/arch/x86/include/asm/apic.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/apic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/apic.h	2011-01-04 19:50:19.000000000 -0500
@@ -141,13 +141,13 @@
 
 static inline u32 native_apic_msr_read(u32 reg)
 {
-	u32 low, high;
+	u64 msr;
 
 	if (reg == APIC_DFR)
 		return -1;
 
-	rdmsr(APIC_BASE_MSR + (reg >> 4), low, high);
-	return low;
+	rdmsrl(APIC_BASE_MSR + (reg >> 4), msr);
+	return (u32)msr;
 }
 
 static inline void native_x2apic_wait_icr_idle(void)
@@ -181,12 +181,12 @@
 extern void x2apic_icr_write(u32 low, u32 id);
 static inline int x2apic_enabled(void)
 {
-	int msr, msr2;
+	u64 msr;
 
 	if (!cpu_has_x2apic)
 		return 0;
 
-	rdmsr(MSR_IA32_APICBASE, msr, msr2);
+	rdmsrl(MSR_IA32_APICBASE, msr);
 	if (msr & X2APIC_ENABLE)
 		return 1;
 	return 0;
@@ -252,9 +252,7 @@
 }
 #endif
 
-extern u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask);
-extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask);
-
+extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
 
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/bitops.h linux-libre-2.6.37-gnu/arch/x86/include/asm/bitops.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/bitops.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/bitops.h	2011-01-04 19:50:19.000000000 -0500
@@ -440,6 +440,8 @@
 
 #ifdef __KERNEL__
 
+#include <asm-generic/bitops/find.h>
+
 #include <asm-generic/bitops/sched.h>
 
 #define ARCH_HAS_FAST_MULTIPLIER 1
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/calgary.h linux-libre-2.6.37-gnu/arch/x86/include/asm/calgary.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/calgary.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/calgary.h	2011-01-04 19:50:19.000000000 -0500
@@ -62,9 +62,9 @@
 extern int use_calgary;
 
 #ifdef CONFIG_CALGARY_IOMMU
-extern void detect_calgary(void);
+extern int detect_calgary(void);
 #else
-static inline void detect_calgary(void) { return; }
+static inline int detect_calgary(void) { return -ENODEV; }
 #endif
 
 #endif /* _ASM_X86_CALGARY_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/calling.h linux-libre-2.6.37-gnu/arch/x86/include/asm/calling.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/calling.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/calling.h	2011-01-04 19:50:19.000000000 -0500
@@ -48,36 +48,38 @@
 
 
 /*
- * 64-bit system call stack frame layout defines and helpers,
- * for assembly code:
+ * 64-bit system call stack frame layout defines and helpers, for
+ * assembly code (note that the seemingly unnecessary parentheses
+ * are to prevent cpp from inserting spaces in expressions that get
+ * passed to macros):
  */
 
-#define R15		  0
-#define R14		  8
-#define R13		 16
-#define R12		 24
-#define RBP		 32
-#define RBX		 40
+#define R15		  (0)
+#define R14		  (8)
+#define R13		 (16)
+#define R12		 (24)
+#define RBP		 (32)
+#define RBX		 (40)
 
 /* arguments: interrupts/non tracing syscalls only save up to here: */
-#define R11		 48
-#define R10		 56
-#define R9		 64
-#define R8		 72
-#define RAX		 80
-#define RCX		 88
-#define RDX		 96
-#define RSI		104
-#define RDI		112
-#define ORIG_RAX	120       /* + error_code */
+#define R11		 (48)
+#define R10		 (56)
+#define R9		 (64)
+#define R8		 (72)
+#define RAX		 (80)
+#define RCX		 (88)
+#define RDX		 (96)
+#define RSI		(104)
+#define RDI		(112)
+#define ORIG_RAX	(120)       /* + error_code */
 /* end of arguments */
 
 /* cpu exception frame or undefined in case of fast syscall: */
-#define RIP		128
-#define CS		136
-#define EFLAGS		144
-#define RSP		152
-#define SS		160
+#define RIP		(128)
+#define CS		(136)
+#define EFLAGS		(144)
+#define RSP		(152)
+#define SS		(160)
 
 #define ARGOFFSET	R11
 #define SWFRAME		ORIG_RAX
@@ -111,7 +113,7 @@
 	.endif
 	.endm
 
-#define ARG_SKIP	9*8
+#define ARG_SKIP	(9*8)
 
 	.macro RESTORE_ARGS skiprax=0, addskip=0, skiprcx=0, skipr11=0, \
 			    skipr8910=0, skiprdx=0
@@ -169,7 +171,7 @@
 	.endif
 	.endm
 
-#define REST_SKIP	6*8
+#define REST_SKIP	(6*8)
 
 	.macro SAVE_REST
 	subq $REST_SKIP, %rsp
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/cpufeature.h linux-libre-2.6.37-gnu/arch/x86/include/asm/cpufeature.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/cpufeature.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/cpufeature.h	2011-01-04 19:50:19.000000000 -0500
@@ -152,10 +152,14 @@
 #define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */
 #define X86_FEATURE_OSVW	(6*32+ 9) /* OS Visible Workaround */
 #define X86_FEATURE_IBS		(6*32+10) /* Instruction Based Sampling */
-#define X86_FEATURE_SSE5	(6*32+11) /* SSE-5 */
+#define X86_FEATURE_XOP		(6*32+11) /* extended AVX instructions */
 #define X86_FEATURE_SKINIT	(6*32+12) /* SKINIT/STGI instructions */
 #define X86_FEATURE_WDT		(6*32+13) /* Watchdog timer */
+#define X86_FEATURE_LWP		(6*32+15) /* Light Weight Profiling */
+#define X86_FEATURE_FMA4	(6*32+16) /* 4 operands MAC instructions */
 #define X86_FEATURE_NODEID_MSR	(6*32+19) /* NodeId MSR */
+#define X86_FEATURE_TBM		(6*32+21) /* trailing bit manipulations */
+#define X86_FEATURE_TOPOEXT	(6*32+22) /* topology extensions CPUID leafs */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
@@ -180,6 +184,13 @@
 #define X86_FEATURE_LBRV	(8*32+ 6) /* AMD LBR Virtualization support */
 #define X86_FEATURE_SVML	(8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
 #define X86_FEATURE_NRIPS	(8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR  (8*32+ 9) /* "tsc_scale" AMD TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN   (8*32+10) /* "vmcb_clean" AMD VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID (8*32+11) /* AMD flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS (8*32+12) /* AMD Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER (8*32+13) /* AMD filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD (8*32+14) /* AMD pause filter threshold */
+
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE	(9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/cpu.h linux-libre-2.6.37-gnu/arch/x86/include/asm/cpu.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,5 @@
 
 DECLARE_PER_CPU(int, cpu_state);
 
-extern unsigned int boot_cpu_id;
 
 #endif /* _ASM_X86_CPU_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/dwarf2.h linux-libre-2.6.37-gnu/arch/x86/include/asm/dwarf2.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/dwarf2.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/dwarf2.h	2011-01-04 19:50:19.000000000 -0500
@@ -89,6 +89,16 @@
 	CFI_ADJUST_CFA_OFFSET -8
 	.endm
 
+	.macro pushfq_cfi
+	pushfq
+	CFI_ADJUST_CFA_OFFSET 8
+	.endm
+
+	.macro popfq_cfi
+	popfq
+	CFI_ADJUST_CFA_OFFSET -8
+	.endm
+
 	.macro movq_cfi reg offset=0
 	movq %\reg, \offset(%rsp)
 	CFI_REL_OFFSET \reg, \offset
@@ -109,6 +119,16 @@
 	CFI_ADJUST_CFA_OFFSET -4
 	.endm
 
+	.macro pushfl_cfi
+	pushfl
+	CFI_ADJUST_CFA_OFFSET 4
+	.endm
+
+	.macro popfl_cfi
+	popfl
+	CFI_ADJUST_CFA_OFFSET -4
+	.endm
+
 	.macro movl_cfi reg offset=0
 	movl %\reg, \offset(%esp)
 	CFI_REL_OFFSET \reg, \offset
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/e820.h linux-libre-2.6.37-gnu/arch/x86/include/asm/e820.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/e820.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/e820.h	2011-01-04 19:50:19.000000000 -0500
@@ -72,6 +72,9 @@
 #define BIOS_BEGIN		0x000a0000
 #define BIOS_END		0x00100000
 
+#define BIOS_ROM_BASE		0xffe00000
+#define BIOS_ROM_END		0xffffffff
+
 #ifdef __KERNEL__
 /* see comment in arch/x86/kernel/e820.c */
 extern struct e820map e820;
@@ -112,23 +115,13 @@
 }
 #endif
 
-extern unsigned long end_user_pfn;
-
-extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
-extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
-extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
-#include <linux/early_res.h>
-
 extern unsigned long e820_end_of_ram_pfn(void);
 extern unsigned long e820_end_of_low_ram_pfn(void);
-extern int e820_find_active_region(const struct e820entry *ei,
-				  unsigned long start_pfn,
-				  unsigned long last_pfn,
-				  unsigned long *ei_startpfn,
-				  unsigned long *ei_endpfn);
-extern void e820_register_active_regions(int nid, unsigned long start_pfn,
-					 unsigned long end_pfn);
-extern u64 e820_hole_size(u64 start, u64 end);
+extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
+
+void memblock_x86_fill(void);
+void memblock_find_dma_reserve(void);
+
 extern void finish_e820_parsing(void);
 extern void e820_reserve_resources(void);
 extern void e820_reserve_resources_late(void);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/efi.h linux-libre-2.6.37-gnu/arch/x86/include/asm/efi.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/efi.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/efi.h	2011-01-04 19:50:19.000000000 -0500
@@ -90,7 +90,7 @@
 #endif /* CONFIG_X86_32 */
 
 extern int add_efi_memmap;
-extern void efi_reserve_early(void);
+extern void efi_memblock_x86_reserve_range(void);
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/entry_arch.h linux-libre-2.6.37-gnu/arch/x86/include/asm/entry_arch.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/entry_arch.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/entry_arch.h	2011-01-04 19:50:19.000000000 -0500
@@ -16,22 +16,11 @@
 BUILD_INTERRUPT(irq_move_cleanup_interrupt,IRQ_MOVE_CLEANUP_VECTOR)
 BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR)
 
-BUILD_INTERRUPT3(invalidate_interrupt0,INVALIDATE_TLB_VECTOR_START+0,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt1,INVALIDATE_TLB_VECTOR_START+1,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt2,INVALIDATE_TLB_VECTOR_START+2,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt3,INVALIDATE_TLB_VECTOR_START+3,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt4,INVALIDATE_TLB_VECTOR_START+4,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt5,INVALIDATE_TLB_VECTOR_START+5,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt6,INVALIDATE_TLB_VECTOR_START+6,
-		 smp_invalidate_interrupt)
-BUILD_INTERRUPT3(invalidate_interrupt7,INVALIDATE_TLB_VECTOR_START+7,
+.irpc idx, "01234567"
+BUILD_INTERRUPT3(invalidate_interrupt\idx,
+		 (INVALIDATE_TLB_VECTOR_START)+\idx,
 		 smp_invalidate_interrupt)
+.endr
 #endif
 
 BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR)
@@ -49,8 +38,8 @@
 BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
 BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
 
-#ifdef CONFIG_PERF_EVENTS
-BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
+#ifdef CONFIG_IRQ_WORK
+BUILD_INTERRUPT(irq_work_interrupt, IRQ_WORK_VECTOR)
 #endif
 
 #ifdef CONFIG_X86_THERMAL_VECTOR
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/fixmap.h linux-libre-2.6.37-gnu/arch/x86/include/asm/fixmap.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/fixmap.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/fixmap.h	2011-01-04 19:50:19.000000000 -0500
@@ -214,5 +214,20 @@
 	BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
 	return __virt_to_fix(vaddr);
 }
+
+/* Return an pointer with offset calculated */
+static __always_inline unsigned long
+__set_fixmap_offset(enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
+{
+	__set_fixmap(idx, phys, flags);
+	return fix_to_virt(idx) + (phys & (PAGE_SIZE - 1));
+}
+
+#define set_fixmap_offset(idx, phys)			\
+	__set_fixmap_offset(idx, phys, PAGE_KERNEL)
+
+#define set_fixmap_offset_nocache(idx, phys)			\
+	__set_fixmap_offset(idx, phys, PAGE_KERNEL_NOCACHE)
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_X86_FIXMAP_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/gart.h linux-libre-2.6.37-gnu/arch/x86/include/asm/gart.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/gart.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/gart.h	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
 #define GARTEN		(1<<0)
 #define DISGARTCPU	(1<<4)
 #define DISGARTIO	(1<<5)
+#define DISTLBWALKPRB	(1<<6)
 
 /* GART cache control register bits. */
 #define INVGART		(1<<0)
@@ -27,7 +28,6 @@
 #define AMD64_GARTAPERTUREBASE	0x94
 #define AMD64_GARTTABLEBASE	0x98
 #define AMD64_GARTCACHECTL	0x9c
-#define AMD64_GARTEN		(1<<0)
 
 #ifdef CONFIG_GART_IOMMU
 extern int gart_iommu_aperture;
@@ -37,7 +37,7 @@
 extern void early_gart_iommu_check(void);
 extern int gart_iommu_init(void);
 extern void __init gart_parse_options(char *);
-extern void gart_iommu_hole_init(void);
+extern int gart_iommu_hole_init(void);
 
 #else
 #define gart_iommu_aperture            0
@@ -50,13 +50,27 @@
 static inline void gart_parse_options(char *options)
 {
 }
-static inline void gart_iommu_hole_init(void)
+static inline int gart_iommu_hole_init(void)
 {
+	return -ENODEV;
 }
 #endif
 
 extern int agp_amd64_init(void);
 
+static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order)
+{
+	u32 ctl;
+
+	/*
+	 * Don't enable translation but enable GART IO and CPU accesses.
+	 * Also, set DISTLBWALKPRB since GART tables memory is UC.
+	 */
+	ctl = DISTLBWALKPRB | order << 1;
+
+	pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
+}
+
 static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
 {
 	u32 tmp, ctl;
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/hardirq.h linux-libre-2.6.37-gnu/arch/x86/include/asm/hardirq.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/hardirq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/hardirq.h	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,7 @@
 #endif
 	unsigned int x86_platform_ipis;	/* arch dependent */
 	unsigned int apic_perf_irqs;
-	unsigned int apic_pending_irqs;
+	unsigned int apic_irq_work_irqs;
 #ifdef CONFIG_SMP
 	unsigned int irq_resched_count;
 	unsigned int irq_call_count;
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/highmem.h linux-libre-2.6.37-gnu/arch/x86/include/asm/highmem.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/highmem.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/highmem.h	2011-01-04 19:50:19.000000000 -0500
@@ -59,11 +59,12 @@
 
 void *kmap(struct page *page);
 void kunmap(struct page *page);
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
-void *kmap_atomic(struct page *page, enum km_type type);
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type);
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+
+void *kmap_atomic_prot(struct page *page, pgprot_t prot);
+void *__kmap_atomic(struct page *page);
+void __kunmap_atomic(void *kvaddr);
+void *kmap_atomic_pfn(unsigned long pfn);
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
 
 #define flush_cache_kmaps()	do { } while (0)
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/hpet.h linux-libre-2.6.37-gnu/arch/x86/include/asm/hpet.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/hpet.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/hpet.h	2011-01-04 19:50:19.000000000 -0500
@@ -74,10 +74,12 @@
 extern unsigned int hpet_readl(unsigned int a);
 extern void force_hpet_resume(void);
 
-extern void hpet_msi_unmask(unsigned int irq);
-extern void hpet_msi_mask(unsigned int irq);
-extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
-extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
+struct irq_data;
+extern void hpet_msi_unmask(struct irq_data *data);
+extern void hpet_msi_mask(struct irq_data *data);
+struct hpet_dev;
+extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
+extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
 
 #ifdef CONFIG_PCI_MSI
 extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/hw_irq.h linux-libre-2.6.37-gnu/arch/x86/include/asm/hw_irq.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/hw_irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/hw_irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -29,7 +29,7 @@
 extern void apic_timer_interrupt(void);
 extern void x86_platform_ipi(void);
 extern void error_interrupt(void);
-extern void perf_pending_interrupt(void);
+extern void irq_work_interrupt(void);
 
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
@@ -78,6 +78,13 @@
 	irq_attr->polarity	= polarity;
 }
 
+struct irq_2_iommu {
+	struct intel_iommu *iommu;
+	u16 irte_index;
+	u16 sub_handle;
+	u8  irte_mask;
+};
+
 /*
  * This is performance-critical, we want to do it O(1)
  *
@@ -89,15 +96,17 @@
 	cpumask_var_t		old_domain;
 	u8			vector;
 	u8			move_in_progress : 1;
+#ifdef CONFIG_INTR_REMAP
+	struct irq_2_iommu	irq_2_iommu;
+#endif
 };
 
-extern struct irq_cfg *irq_cfg(unsigned int);
 extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
 extern void send_cleanup_vector(struct irq_cfg *);
 
-struct irq_desc;
-extern unsigned int set_desc_affinity(struct irq_desc *, const struct cpumask *,
-				      unsigned int *dest_id);
+struct irq_data;
+int __ioapic_set_affinity(struct irq_data *, const struct cpumask *,
+			  unsigned int *dest_id);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin, struct io_apic_irq_attr *irq_attr);
 extern void setup_ioapic_dest(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/i387.h linux-libre-2.6.37-gnu/arch/x86/include/asm/i387.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/i387.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/i387.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,6 +55,12 @@
 extern int restore_i387_xstate_ia32(void __user *buf);
 #endif
 
+#ifdef CONFIG_MATH_EMULATION
+extern void finit_soft_fpu(struct i387_soft_struct *soft);
+#else
+static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
+#endif
+
 #define X87_FSW_ES (1 << 7)	/* Exception Summary */
 
 static __always_inline __pure bool use_xsaveopt(void)
@@ -67,6 +73,11 @@
 	return static_cpu_has(X86_FEATURE_XSAVE);
 }
 
+static __always_inline __pure bool use_fxsr(void)
+{
+        return static_cpu_has(X86_FEATURE_FXSR);
+}
+
 extern void __sanitize_i387_state(struct task_struct *);
 
 static inline void sanitize_i387_state(struct task_struct *tsk)
@@ -77,19 +88,11 @@
 }
 
 #ifdef CONFIG_X86_64
-
-/* Ignore delayed exceptions from user space */
-static inline void tolerant_fwait(void)
-{
-	asm volatile("1: fwait\n"
-		     "2:\n"
-		     _ASM_EXTABLE(1b, 2b));
-}
-
 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
 	int err;
 
+	/* See comment in fxsave() below. */
 	asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
 		     "2:\n"
 		     ".section .fixup,\"ax\"\n"
@@ -98,44 +101,10 @@
 		     ".previous\n"
 		     _ASM_EXTABLE(1b, 3b)
 		     : [err] "=r" (err)
-#if 0 /* See comment in fxsave() below. */
-		     : [fx] "r" (fx), "m" (*fx), "0" (0));
-#else
-		     : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
-#endif
+		     : [fx] "R" (fx), "m" (*fx), "0" (0));
 	return err;
 }
 
-/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
-   is pending. Clear the x87 state here by setting it to fixed
-   values. The kernel data segment can be sometimes 0 and sometimes
-   new user value. Both should be ok.
-   Use the PDA as safe address because it should be already in L1. */
-static inline void fpu_clear(struct fpu *fpu)
-{
-	struct xsave_struct *xstate = &fpu->state->xsave;
-	struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-
-	/*
-	 * xsave header may indicate the init state of the FP.
-	 */
-	if (use_xsave() &&
-	    !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-		return;
-
-	if (unlikely(fx->swd & X87_FSW_ES))
-		asm volatile("fnclex");
-	alternative_input(ASM_NOP8 ASM_NOP2,
-			  "    emms\n"		/* clear stack tags */
-			  "    fildl %%gs:0",	/* load to clear state */
-			  X86_FEATURE_FXSAVE_LEAK);
-}
-
-static inline void clear_fpu_state(struct task_struct *tsk)
-{
-	fpu_clear(&tsk->thread.fpu);
-}
-
 static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
 	int err;
@@ -149,6 +118,7 @@
 	if (unlikely(err))
 		return -EFAULT;
 
+	/* See comment in fxsave() below. */
 	asm volatile("1:  rex64/fxsave (%[fx])\n\t"
 		     "2:\n"
 		     ".section .fixup,\"ax\"\n"
@@ -157,11 +127,7 @@
 		     ".previous\n"
 		     _ASM_EXTABLE(1b, 3b)
 		     : [err] "=r" (err), "=m" (*fx)
-#if 0 /* See comment in fxsave() below. */
-		     : [fx] "r" (fx), "0" (0));
-#else
-		     : [fx] "cdaSDb" (fx), "0" (0));
-#endif
+		     : [fx] "R" (fx), "0" (0));
 	if (unlikely(err) &&
 	    __clear_user(fx, sizeof(struct i387_fxsave_struct)))
 		err = -EFAULT;
@@ -175,56 +141,29 @@
 	   uses any extended registers for addressing, a second REX prefix
 	   will be generated (to the assembler, rex64 followed by semicolon
 	   is a separate instruction), and hence the 64-bitness is lost. */
-#if 0
+
+#ifdef CONFIG_AS_FXSAVEQ
 	/* Using "fxsaveq %0" would be the ideal choice, but is only supported
 	   starting with gas 2.16. */
 	__asm__ __volatile__("fxsaveq %0"
 			     : "=m" (fpu->state->fxsave));
-#elif 0
+#else
 	/* Using, as a workaround, the properly prefixed form below isn't
 	   accepted by any binutils version so far released, complaining that
 	   the same type of prefix is used twice if an extended register is
-	   needed for addressing (fix submitted to mainline 2005-11-21). */
-	__asm__ __volatile__("rex64/fxsave %0"
-			     : "=m" (fpu->state->fxsave));
-#else
-	/* This, however, we can work around by forcing the compiler to select
+	   needed for addressing (fix submitted to mainline 2005-11-21).
+	asm volatile("rex64/fxsave %0"
+		     : "=m" (fpu->state->fxsave));
+	   This, however, we can work around by forcing the compiler to select
 	   an addressing mode that doesn't require extended registers. */
-	__asm__ __volatile__("rex64/fxsave (%1)"
-			     : "=m" (fpu->state->fxsave)
-			     : "cdaSDb" (&fpu->state->fxsave));
+	asm volatile("rex64/fxsave (%[fx])"
+		     : "=m" (fpu->state->fxsave)
+		     : [fx] "R" (&fpu->state->fxsave));
 #endif
 }
 
-static inline void fpu_save_init(struct fpu *fpu)
-{
-	if (use_xsave())
-		fpu_xsave(fpu);
-	else
-		fpu_fxsave(fpu);
-
-	fpu_clear(fpu);
-}
-
-static inline void __save_init_fpu(struct task_struct *tsk)
-{
-	fpu_save_init(&tsk->thread.fpu);
-	task_thread_info(tsk)->status &= ~TS_USEDFPU;
-}
-
 #else  /* CONFIG_X86_32 */
 
-#ifdef CONFIG_MATH_EMULATION
-extern void finit_soft_fpu(struct i387_soft_struct *soft);
-#else
-static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
-#endif
-
-static inline void tolerant_fwait(void)
-{
-	asm volatile("fnclex ; fwait");
-}
-
 /* perform fxrstor iff the processor has extended states, otherwise frstor */
 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
@@ -241,6 +180,14 @@
 	return 0;
 }
 
+static inline void fpu_fxsave(struct fpu *fpu)
+{
+	asm volatile("fxsave %[fx]"
+		     : [fx] "=m" (fpu->state->fxsave));
+}
+
+#endif	/* CONFIG_X86_64 */
+
 /* We need a safe address that is cheap to find and that is already
    in L1 during context switch. The best choices are unfortunately
    different for UP and SMP */
@@ -256,47 +203,33 @@
 static inline void fpu_save_init(struct fpu *fpu)
 {
 	if (use_xsave()) {
-		struct xsave_struct *xstate = &fpu->state->xsave;
-		struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-
 		fpu_xsave(fpu);
 
 		/*
 		 * xsave header may indicate the init state of the FP.
 		 */
-		if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-			goto end;
-
-		if (unlikely(fx->swd & X87_FSW_ES))
-			asm volatile("fnclex");
-
-		/*
-		 * we can do a simple return here or be paranoid :)
-		 */
-		goto clear_state;
+		if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
+			return;
+	} else if (use_fxsr()) {
+		fpu_fxsave(fpu);
+	} else {
+		asm volatile("fsave %[fx]; fwait"
+			     : [fx] "=m" (fpu->state->fsave));
+		return;
 	}
 
-	/* Use more nops than strictly needed in case the compiler
-	   varies code */
-	alternative_input(
-		"fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
-		"fxsave %[fx]\n"
-		"bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
-		X86_FEATURE_FXSR,
-		[fx] "m" (fpu->state->fxsave),
-		[fsw] "m" (fpu->state->fxsave.swd) : "memory");
-clear_state:
+	if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES))
+		asm volatile("fnclex");
+
 	/* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
 	   is pending.  Clear the x87 state here by setting it to fixed
 	   values. safe_address is a random variable that should be in L1 */
 	alternative_input(
-		GENERIC_NOP8 GENERIC_NOP2,
+		ASM_NOP8 ASM_NOP2,
 		"emms\n\t"	  	/* clear stack tags */
-		"fildl %[addr]", 	/* set F?P to defined value */
+		"fildl %P[addr]",	/* set F?P to defined value */
 		X86_FEATURE_FXSAVE_LEAK,
 		[addr] "m" (safe_address));
-end:
-	;
 }
 
 static inline void __save_init_fpu(struct task_struct *tsk)
@@ -305,9 +238,6 @@
 	task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
-
-#endif	/* CONFIG_X86_64 */
-
 static inline int fpu_fxrstor_checking(struct fpu *fpu)
 {
 	return fxrstor_checking(&fpu->state->fxsave);
@@ -344,7 +274,10 @@
 static inline void __clear_fpu(struct task_struct *tsk)
 {
 	if (task_thread_info(tsk)->status & TS_USEDFPU) {
-		tolerant_fwait();
+		/* Ignore delayed exceptions from user space */
+		asm volatile("1: fwait\n"
+			     "2:\n"
+			     _ASM_EXTABLE(1b, 2b));
 		task_thread_info(tsk)->status &= ~TS_USEDFPU;
 		stts();
 	}
@@ -405,19 +338,6 @@
 		stts();
 }
 
-#ifdef CONFIG_X86_64
-
-static inline void save_init_fpu(struct task_struct *tsk)
-{
-	__save_init_fpu(tsk);
-	stts();
-}
-
-#define unlazy_fpu	__unlazy_fpu
-#define clear_fpu	__clear_fpu
-
-#else  /* CONFIG_X86_32 */
-
 /*
  * These disable preemption on their own and are safe
  */
@@ -443,8 +363,6 @@
 	preempt_enable();
 }
 
-#endif	/* CONFIG_X86_64 */
-
 /*
  * i387 state interaction
  */
@@ -508,7 +426,4 @@
 
 #endif /* __ASSEMBLY__ */
 
-#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
-#define PSHUFB_XMM5_XMM6 .byte 0x66, 0x0f, 0x38, 0x00, 0xf5
-
 #endif /* _ASM_X86_I387_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/i8259.h linux-libre-2.6.37-gnu/arch/x86/include/asm/i8259.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/i8259.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/i8259.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,6 +55,8 @@
 struct legacy_pic {
 	int nr_legacy_irqs;
 	struct irq_chip *chip;
+	void (*mask)(unsigned int irq);
+	void (*unmask)(unsigned int irq);
 	void (*mask_all)(void);
 	void (*restore_mask)(void);
 	void (*init)(int auto_eoi);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/io_apic.h linux-libre-2.6.37-gnu/arch/x86/include/asm/io_apic.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/io_apic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/io_apic.h	2011-01-04 19:50:19.000000000 -0500
@@ -169,13 +169,8 @@
 extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
 
 extern void probe_nr_irqs_gsi(void);
+extern int get_nr_irqs_gsi(void);
 
-extern int setup_ioapic_entry(int apic, int irq,
-			      struct IO_APIC_route_entry *entry,
-			      unsigned int destination, int trigger,
-			      int polarity, int vector, int pin);
-extern void ioapic_write_entry(int apic, int pin,
-			       struct IO_APIC_route_entry e);
 extern void setup_ioapic_ids_from_mpc(void);
 
 struct mp_ioapic_gsi{
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/io.h linux-libre-2.6.37-gnu/arch/x86/include/asm/io.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/io.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/io.h	2011-01-04 19:50:19.000000000 -0500
@@ -41,6 +41,8 @@
 #include <asm-generic/int-ll64.h>
 #include <asm/page.h>
 
+#include <xen/xen.h>
+
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
 { type ret; asm volatile("mov" size " %1,%0":reg (ret) \
@@ -206,6 +208,7 @@
 
 extern void iounmap(volatile void __iomem *addr);
 
+extern void set_iounmap_nonlazy(void);
 
 #ifdef __KERNEL__
 
@@ -348,6 +351,18 @@
 				    unsigned long size);
 extern void early_iounmap(void __iomem *addr, unsigned long size);
 extern void fixup_early_ioremap(void);
+extern bool is_early_ioremap_ptep(pte_t *ptep);
+
+#ifdef CONFIG_XEN
+struct bio_vec;
+
+extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
+				      const struct bio_vec *vec2);
+
+#define BIOVEC_PHYS_MERGEABLE(vec1, vec2)				\
+	(__BIOVEC_PHYS_MERGEABLE(vec1, vec2) &&				\
+	 (!xen_domain() || xen_biovec_phys_mergeable(vec1, vec2)))
+#endif	/* CONFIG_XEN */
 
 #define IO_SPACE_LIMIT 0xffff
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/iomap.h linux-libre-2.6.37-gnu/arch/x86/include/asm/iomap.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/iomap.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/iomap.h	2011-01-04 19:50:19.000000000 -0500
@@ -27,10 +27,10 @@
 #include <asm/tlbflush.h>
 
 void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot);
 
 void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type);
+iounmap_atomic(void __iomem *kvaddr);
 
 int
 iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/iommu_table.h linux-libre-2.6.37-gnu/arch/x86/include/asm/iommu_table.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/iommu_table.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/iommu_table.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,100 @@
+#ifndef _ASM_X86_IOMMU_TABLE_H
+#define _ASM_X86_IOMMU_TABLE_H
+
+#include <asm/swiotlb.h>
+
+/*
+ * History lesson:
+ * The execution chain of IOMMUs in 2.6.36 looks as so:
+ *
+ *            [xen-swiotlb]
+ *                 |
+ *         +----[swiotlb *]--+
+ *        /         |         \
+ *       /          |          \
+ *    [GART]     [Calgary]  [Intel VT-d]
+ *     /
+ *    /
+ * [AMD-Vi]
+ *
+ * *: if SWIOTLB detected 'iommu=soft'/'swiotlb=force' it would skip
+ * over the rest of IOMMUs and unconditionally initialize the SWIOTLB.
+ * Also it would surreptitiously initialize set the swiotlb=1 if there were
+ * more than 4GB and if the user did not pass in 'iommu=off'. The swiotlb
+ * flag would be turned off by all IOMMUs except the Calgary one.
+ *
+ * The IOMMU_INIT* macros allow a similar tree (or more complex if desired)
+ * to be built by defining who we depend on.
+ *
+ * And all that needs to be done is to use one of the macros in the IOMMU
+ * and the pci-dma.c will take care of the rest.
+ */
+
+struct iommu_table_entry {
+	initcall_t	detect;
+	initcall_t	depend;
+	void		(*early_init)(void); /* No memory allocate available. */
+	void		(*late_init)(void); /* Yes, can allocate memory. */
+#define IOMMU_FINISH_IF_DETECTED (1<<0)
+#define IOMMU_DETECTED		 (1<<1)
+	int		flags;
+};
+/*
+ * Macro fills out an entry in the .iommu_table that is equivalent
+ * to the fields that 'struct iommu_table_entry' has. The entries
+ * that are put in the .iommu_table section are not put in any order
+ * hence during boot-time we will have to resort them based on
+ * dependency. */
+
+
+#define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
+	static const struct iommu_table_entry const			\
+		__iommu_entry_##_detect __used				\
+	__attribute__ ((unused, __section__(".iommu_table"),		\
+			aligned((sizeof(void *)))))	\
+	= {_detect, _depend, _early_init, _late_init,			\
+	   _finish ? IOMMU_FINISH_IF_DETECTED : 0}
+/*
+ * The simplest IOMMU definition. Provide the detection routine
+ * and it will be run after the SWIOTLB and the other IOMMUs
+ * that utilize this macro. If the IOMMU is detected (ie, the
+ * detect routine returns a positive value), the other IOMMUs
+ * are also checked. You can use IOMMU_INIT_POST_FINISH if you prefer
+ * to stop detecting the other IOMMUs after yours has been detected.
+ */
+#define IOMMU_INIT_POST(_detect)					\
+	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 0)
+
+#define IOMMU_INIT_POST_FINISH(detect)					\
+	__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 1)
+
+/*
+ * A more sophisticated version of IOMMU_INIT. This variant requires:
+ *  a). A detection routine function.
+ *  b). The name of the detection routine we depend on to get called
+ *      before us.
+ *  c). The init routine which gets called if the detection routine
+ *      returns a positive value from the pci_iommu_alloc. This means
+ *      no presence of a memory allocator.
+ *  d). Similar to the 'init', except that this gets called from pci_iommu_init
+ *      where we do have a memory allocator.
+ *
+ * The standard vs the _FINISH differs in that the _FINISH variant will
+ * continue detecting other IOMMUs in the call list after the
+ * the detection routine returns a positive number. The _FINISH will
+ * stop the execution chain. Both will still call the 'init' and
+ * 'late_init' functions if they are set.
+ */
+#define IOMMU_INIT_FINISH(_detect, _depend, _init, _late_init)		\
+	__IOMMU_INIT(_detect, _depend, _init, _late_init, 1)
+
+#define IOMMU_INIT(_detect, _depend, _init, _late_init)			\
+	__IOMMU_INIT(_detect, _depend, _init, _late_init, 0)
+
+void sort_iommu_table(struct iommu_table_entry *start,
+		      struct iommu_table_entry *finish);
+
+void check_iommu_entries(struct iommu_table_entry *start,
+			 struct iommu_table_entry *finish);
+
+#endif /* _ASM_X86_IOMMU_TABLE_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/x86/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/irqflags.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -61,22 +61,22 @@
 #else
 #ifndef __ASSEMBLY__
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
 	return native_save_fl();
 }
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
 	native_restore_fl(flags);
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
 	native_irq_disable();
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
 	native_irq_enable();
 }
@@ -85,7 +85,7 @@
  * Used in the idle loop; sti takes one instruction cycle
  * to complete:
  */
-static inline void raw_safe_halt(void)
+static inline void arch_safe_halt(void)
 {
 	native_safe_halt();
 }
@@ -102,12 +102,10 @@
 /*
  * For spinlocks, etc:
  */
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-	unsigned long flags = __raw_local_save_flags();
-
-	raw_local_irq_disable();
-
+	unsigned long flags = arch_local_save_flags();
+	arch_local_irq_disable();
 	return flags;
 }
 #else
@@ -153,22 +151,16 @@
 #endif /* CONFIG_PARAVIRT */
 
 #ifndef __ASSEMBLY__
-#define raw_local_save_flags(flags)				\
-	do { (flags) = __raw_local_save_flags(); } while (0)
-
-#define raw_local_irq_save(flags)				\
-	do { (flags) = __raw_local_irq_save(); } while (0)
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
 	return !(flags & X86_EFLAGS_IF);
 }
 
-static inline int raw_irqs_disabled(void)
+static inline int arch_irqs_disabled(void)
 {
-	unsigned long flags = __raw_local_save_flags();
+	unsigned long flags = arch_local_save_flags();
 
-	return raw_irqs_disabled_flags(flags);
+	return arch_irqs_disabled_flags(flags);
 }
 
 #else
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/irq.h linux-libre-2.6.37-gnu/arch/x86/include/asm/irq.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,18 +19,14 @@
 # define ARCH_HAS_NMI_WATCHDOG
 #endif
 
-#ifdef CONFIG_4KSTACKS
-  extern void irq_ctx_init(int cpu);
-  extern void irq_ctx_exit(int cpu);
-# define __ARCH_HAS_DO_SOFTIRQ
+#ifdef CONFIG_X86_32
+extern void irq_ctx_init(int cpu);
 #else
 # define irq_ctx_init(cpu) do { } while (0)
-# define irq_ctx_exit(cpu) do { } while (0)
-# ifdef CONFIG_X86_64
-#  define __ARCH_HAS_DO_SOFTIRQ
-# endif
 #endif
 
+#define __ARCH_HAS_DO_SOFTIRQ
+
 #ifdef CONFIG_HOTPLUG_CPU
 #include <linux/cpumask.h>
 extern void fixup_irqs(void);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/irq_remapping.h linux-libre-2.6.37-gnu/arch/x86/include/asm/irq_remapping.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/irq_remapping.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/irq_remapping.h	2011-01-04 19:50:19.000000000 -0500
@@ -3,4 +3,39 @@
 
 #define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
 
+#ifdef CONFIG_INTR_REMAP
+static inline void prepare_irte(struct irte *irte, int vector,
+			        unsigned int dest)
+{
+	memset(irte, 0, sizeof(*irte));
+
+	irte->present = 1;
+	irte->dst_mode = apic->irq_dest_mode;
+	/*
+	 * Trigger mode in the IRTE will always be edge, and for IO-APIC, the
+	 * actual level or edge trigger will be setup in the IO-APIC
+	 * RTE. This will help simplify level triggered irq migration.
+	 * For more details, see the comments (in io_apic.c) explainig IO-APIC
+	 * irq migration in the presence of interrupt-remapping.
+	*/
+	irte->trigger_mode = 0;
+	irte->dlvry_mode = apic->irq_delivery_mode;
+	irte->vector = vector;
+	irte->dest_id = IRTE_DEST(dest);
+	irte->redir_hint = 1;
+}
+static inline bool irq_remapped(struct irq_cfg *cfg)
+{
+	return cfg->irq_2_iommu.iommu != NULL;
+}
+#else
+static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
+{
+}
+static inline bool irq_remapped(struct irq_cfg *cfg)
+{
+	return false;
+}
+#endif
+
 #endif	/* _ASM_X86_IRQ_REMAPPING_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/irq_vectors.h linux-libre-2.6.37-gnu/arch/x86/include/asm/irq_vectors.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/irq_vectors.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/irq_vectors.h	2011-01-04 19:50:19.000000000 -0500
@@ -114,9 +114,9 @@
 #define X86_PLATFORM_IPI_VECTOR		0xed
 
 /*
- * Performance monitoring pending work vector:
+ * IRQ work vector:
  */
-#define LOCAL_PENDING_VECTOR		0xec
+#define IRQ_WORK_VECTOR			0xec
 
 #define UV_BAU_MESSAGE			0xea
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/jump_label.h linux-libre-2.6.37-gnu/arch/x86/include/asm/jump_label.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/jump_label.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/jump_label.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,37 @@
+#ifndef _ASM_X86_JUMP_LABEL_H
+#define _ASM_X86_JUMP_LABEL_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm/nops.h>
+
+#define JUMP_LABEL_NOP_SIZE 5
+
+# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
+
+# define JUMP_LABEL(key, label)					\
+	do {							\
+		asm goto("1:"					\
+			JUMP_LABEL_INITIAL_NOP			\
+			".pushsection __jump_table,  \"a\" \n\t"\
+			_ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
+			".popsection \n\t"			\
+			: :  "i" (key) :  : label);		\
+	} while (0)
+
+#endif /* __KERNEL__ */
+
+#ifdef CONFIG_X86_64
+typedef u64 jump_label_t;
+#else
+typedef u32 jump_label_t;
+#endif
+
+struct jump_entry {
+	jump_label_t code;
+	jump_label_t target;
+	jump_label_t key;
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/k8.h linux-libre-2.6.37-gnu/arch/x86/include/asm/k8.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/k8.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/k8.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,36 +0,0 @@
-#ifndef _ASM_X86_K8_H
-#define _ASM_X86_K8_H
-
-#include <linux/pci.h>
-
-extern struct pci_device_id k8_nb_ids[];
-struct bootnode;
-
-extern int early_is_k8_nb(u32 value);
-extern struct pci_dev **k8_northbridges;
-extern int num_k8_northbridges;
-extern int cache_k8_northbridges(void);
-extern void k8_flush_garts(void);
-extern int k8_get_nodes(struct bootnode *nodes);
-extern int k8_numa_init(unsigned long start_pfn, unsigned long end_pfn);
-extern int k8_scan_nodes(void);
-
-#ifdef CONFIG_K8_NB
-extern int num_k8_northbridges;
-
-static inline struct pci_dev *node_to_k8_nb_misc(int node)
-{
-	return (node < num_k8_northbridges) ? k8_northbridges[node] : NULL;
-}
-
-#else
-#define num_k8_northbridges 0
-
-static inline struct pci_dev *node_to_k8_nb_misc(int node)
-{
-	return NULL;
-}
-#endif
-
-
-#endif /* _ASM_X86_K8_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_emulate.h linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_emulate.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_emulate.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_emulate.h	2011-01-04 19:50:19.000000000 -0500
@@ -139,6 +139,7 @@
 	void (*set_segment_selector)(u16 sel, int seg, struct kvm_vcpu *vcpu);
 	unsigned long (*get_cached_segment_base)(int seg, struct kvm_vcpu *vcpu);
 	void (*get_gdt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
+	void (*get_idt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
 	ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
 	int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
 	int (*cpl)(struct kvm_vcpu *vcpu);
@@ -156,7 +157,10 @@
 		unsigned long orig_val;
 		u64 orig_val64;
 	};
-	unsigned long *ptr;
+	union {
+		unsigned long *reg;
+		unsigned long mem;
+	} addr;
 	union {
 		unsigned long val;
 		u64 val64;
@@ -190,6 +194,7 @@
 	bool has_seg_override;
 	u8 seg_override;
 	unsigned int d;
+	int (*execute)(struct x86_emulate_ctxt *ctxt);
 	unsigned long regs[NR_VCPU_REGS];
 	unsigned long eip;
 	/* modrm */
@@ -197,17 +202,16 @@
 	u8 modrm_mod;
 	u8 modrm_reg;
 	u8 modrm_rm;
-	u8 use_modrm_ea;
+	u8 modrm_seg;
 	bool rip_relative;
-	unsigned long modrm_ea;
-	void *modrm_ptr;
-	unsigned long modrm_val;
 	struct fetch_cache fetch;
 	struct read_cache io_read;
 	struct read_cache mem_read;
 };
 
 struct x86_emulate_ctxt {
+	struct x86_emulate_ops *ops;
+
 	/* Register state before/after emulation. */
 	struct kvm_vcpu *vcpu;
 
@@ -220,12 +224,11 @@
 	/* interruptibility state, as a result of execution of STI or MOV SS */
 	int interruptibility;
 
-	bool restart; /* restart string instruction after writeback */
+	bool perm_ok; /* do not check permissions if true */
 
 	int exception; /* exception that happens during emulation or -1 */
 	u32 error_code; /* error code for exception */
 	bool error_code_valid;
-	unsigned long cr2; /* faulted address in case of #PF */
 
 	/* decode cache */
 	struct decode_cache decode;
@@ -249,13 +252,14 @@
 #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
 #endif
 
-int x86_decode_insn(struct x86_emulate_ctxt *ctxt,
-		    struct x86_emulate_ops *ops);
-int x86_emulate_insn(struct x86_emulate_ctxt *ctxt,
-		     struct x86_emulate_ops *ops);
+int x86_decode_insn(struct x86_emulate_ctxt *ctxt);
+#define EMULATION_FAILED -1
+#define EMULATION_OK 0
+#define EMULATION_RESTART 1
+int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-			 struct x86_emulate_ops *ops,
 			 u16 tss_selector, int reason,
 			 bool has_error_code, u32 error_code);
-
+int emulate_int_real(struct x86_emulate_ctxt *ctxt,
+		     struct x86_emulate_ops *ops, int irq);
 #endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_host.h linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_host.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_host.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_host.h	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 #define KVM_NUM_MMU_PAGES (1 << KVM_MMU_HASH_SHIFT)
 #define KVM_MIN_FREE_MMU_PAGES 5
 #define KVM_REFILL_PAGES 25
-#define KVM_MAX_CPUID_ENTRIES 40
+#define KVM_MAX_CPUID_ENTRIES 80
 #define KVM_NR_FIXED_MTRR_REGION 88
 #define KVM_NR_VAR_MTRR 8
 
@@ -236,10 +236,14 @@
  */
 struct kvm_mmu {
 	void (*new_cr3)(struct kvm_vcpu *vcpu);
+	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long root);
+	unsigned long (*get_cr3)(struct kvm_vcpu *vcpu);
 	int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
+	void (*inject_page_fault)(struct kvm_vcpu *vcpu);
 	void (*free)(struct kvm_vcpu *vcpu);
 	gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva, u32 access,
 			    u32 *error);
+	gpa_t (*translate_gpa)(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access);
 	void (*prefetch_page)(struct kvm_vcpu *vcpu,
 			      struct kvm_mmu_page *page);
 	int (*sync_page)(struct kvm_vcpu *vcpu,
@@ -249,13 +253,18 @@
 	int root_level;
 	int shadow_root_level;
 	union kvm_mmu_page_role base_role;
+	bool direct_map;
 
 	u64 *pae_root;
+	u64 *lm_root;
 	u64 rsvd_bits_mask[2][4];
+
+	bool nx;
+
+	u64 pdptrs[4]; /* pae */
 };
 
 struct kvm_vcpu_arch {
-	u64 host_tsc;
 	/*
 	 * rip and regs accesses must go through
 	 * kvm_{register,rip}_{read,write} functions.
@@ -272,7 +281,6 @@
 	unsigned long cr4_guest_owned_bits;
 	unsigned long cr8;
 	u32 hflags;
-	u64 pdptrs[4]; /* pae */
 	u64 efer;
 	u64 apic_base;
 	struct kvm_lapic *apic;    /* kernel irqchip context */
@@ -282,7 +290,41 @@
 	u64 ia32_misc_enable_msr;
 	bool tpr_access_reporting;
 
+	/*
+	 * Paging state of the vcpu
+	 *
+	 * If the vcpu runs in guest mode with two level paging this still saves
+	 * the paging mode of the l1 guest. This context is always used to
+	 * handle faults.
+	 */
 	struct kvm_mmu mmu;
+
+	/*
+	 * Paging state of an L2 guest (used for nested npt)
+	 *
+	 * This context will save all necessary information to walk page tables
+	 * of the an L2 guest. This context is only initialized for page table
+	 * walking and not for faulting since we never handle l2 page faults on
+	 * the host.
+	 */
+	struct kvm_mmu nested_mmu;
+
+	/*
+	 * Pointer to the mmu context currently used for
+	 * gva_to_gpa translations.
+	 */
+	struct kvm_mmu *walk_mmu;
+
+	/*
+	 * This struct is filled with the necessary information to propagate a
+	 * page fault into the guest
+	 */
+	struct {
+		u64      address;
+		unsigned error_code;
+		bool     nested;
+	} fault;
+
 	/* only needed in kvm_pv_mmu_op() path, but it's hot so
 	 * put it here to avoid allocation */
 	struct kvm_pv_mmu_op_buffer mmu_op_buffer;
@@ -336,9 +378,15 @@
 
 	gpa_t time;
 	struct pvclock_vcpu_time_info hv_clock;
-	unsigned int hv_clock_tsc_khz;
+	unsigned int hw_tsc_khz;
 	unsigned int time_offset;
 	struct page *time_page;
+	u64 last_host_tsc;
+	u64 last_guest_tsc;
+	u64 last_kernel_ns;
+	u64 last_tsc_nsec;
+	u64 last_tsc_write;
+	bool tsc_catchup;
 
 	bool nmi_pending;
 	bool nmi_injected;
@@ -367,9 +415,9 @@
 };
 
 struct kvm_arch {
-	unsigned int n_free_mmu_pages;
+	unsigned int n_used_mmu_pages;
 	unsigned int n_requested_mmu_pages;
-	unsigned int n_alloc_mmu_pages;
+	unsigned int n_max_mmu_pages;
 	atomic_t invlpg_counter;
 	struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
 	/*
@@ -394,8 +442,14 @@
 	gpa_t ept_identity_map_addr;
 
 	unsigned long irq_sources_bitmap;
-	u64 vm_init_tsc;
 	s64 kvmclock_offset;
+	spinlock_t tsc_write_lock;
+	u64 last_tsc_nsec;
+	u64 last_tsc_offset;
+	u64 last_tsc_write;
+	u32 virtual_tsc_khz;
+	u32 virtual_tsc_mult;
+	s8 virtual_tsc_shift;
 
 	struct kvm_xen_hvm_config xen_hvm_config;
 
@@ -505,6 +559,7 @@
 	void (*queue_exception)(struct kvm_vcpu *vcpu, unsigned nr,
 				bool has_error_code, u32 error_code,
 				bool reinject);
+	void (*cancel_injection)(struct kvm_vcpu *vcpu);
 	int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
 	int (*nmi_allowed)(struct kvm_vcpu *vcpu);
 	bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
@@ -517,11 +572,16 @@
 	u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio);
 	int (*get_lpage_level)(void);
 	bool (*rdtscp_supported)(void);
+	void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment);
+
+	void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
 
 	void (*set_supported_cpuid)(u32 func, struct kvm_cpuid_entry2 *entry);
 
 	bool (*has_wbinvd_exit)(void);
 
+	void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+
 	const struct trace_print_flags *exit_reasons_str;
 };
 
@@ -544,7 +604,7 @@
 unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm);
 void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages);
 
-int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3);
+int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3);
 
 int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
 			  const void *val, int bytes);
@@ -608,8 +668,11 @@
 void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
 void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr);
 void kvm_requeue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code);
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
-			   u32 error_code);
+void kvm_inject_page_fault(struct kvm_vcpu *vcpu);
+int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+			    gfn_t gfn, void *data, int offset, int len,
+			    u32 access);
+void kvm_propagate_fault(struct kvm_vcpu *vcpu);
 bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl);
 
 int kvm_pic_set_irq(void *opaque, int irq, int level);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_para.h linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_para.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/kvm_para.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/kvm_para.h	2011-01-04 19:50:19.000000000 -0500
@@ -158,6 +158,12 @@
 	return cpuid_eax(KVM_CPUID_FEATURES);
 }
 
+#ifdef CONFIG_KVM_GUEST
+void __init kvm_guest_init(void);
+#else
+#define kvm_guest_init() do { } while (0)
 #endif
 
+#endif /* __KERNEL__ */
+
 #endif /* _ASM_X86_KVM_PARA_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/memblock.h linux-libre-2.6.37-gnu/arch/x86/include/asm/memblock.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/memblock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/memblock.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,23 @@
+#ifndef _X86_MEMBLOCK_H
+#define _X86_MEMBLOCK_H
+
+#define ARCH_DISCARD_MEMBLOCK
+
+u64 memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align);
+void memblock_x86_to_bootmem(u64 start, u64 end);
+
+void memblock_x86_reserve_range(u64 start, u64 end, char *name);
+void memblock_x86_free_range(u64 start, u64 end);
+struct range;
+int __get_free_all_memory_range(struct range **range, int nodeid,
+			 unsigned long start_pfn, unsigned long end_pfn);
+int get_free_all_memory_range(struct range **rangep, int nodeid);
+
+void memblock_x86_register_active_regions(int nid, unsigned long start_pfn,
+					 unsigned long last_pfn);
+u64 memblock_x86_hole_size(u64 start, u64 end);
+u64 memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align);
+u64 memblock_x86_free_memory_in_range(u64 addr, u64 limit);
+u64 memblock_x86_memory_in_range(u64 addr, u64 limit);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/module.h linux-libre-2.6.37-gnu/arch/x86/include/asm/module.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/module.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/module.h	2011-01-04 19:50:19.000000000 -0500
@@ -60,12 +60,7 @@
 #endif
 
 #ifdef CONFIG_X86_32
-# ifdef CONFIG_4KSTACKS
-#  define MODULE_STACKSIZE "4KSTACKS "
-# else
-#  define MODULE_STACKSIZE ""
-# endif
-# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE
+# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
 #endif
 
 #endif /* _ASM_X86_MODULE_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/mrst.h linux-libre-2.6.37-gnu/arch/x86/include/asm/mrst.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/mrst.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/mrst.h	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,9 @@
  */
 #ifndef _ASM_X86_MRST_H
 #define _ASM_X86_MRST_H
+
+#include <linux/sfi.h>
+
 extern int pci_mrst_init(void);
 int __init sfi_parse_mrtc(struct sfi_table_header *table);
 
@@ -26,7 +29,7 @@
 };
 
 extern enum mrst_cpu_type __mrst_cpu_chip;
-static enum mrst_cpu_type mrst_identify_cpu(void)
+static inline enum mrst_cpu_type mrst_identify_cpu(void)
 {
 	return __mrst_cpu_chip;
 }
@@ -42,4 +45,9 @@
 #define SFI_MTMR_MAX_NUM 8
 #define SFI_MRTC_MAX	8
 
+extern struct console early_mrst_console;
+extern void mrst_early_console_init(void);
+
+extern struct console early_hsu_console;
+extern void hsu_early_console_init(void);
 #endif /* _ASM_X86_MRST_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/msr-index.h linux-libre-2.6.37-gnu/arch/x86/include/asm/msr-index.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/msr-index.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/msr-index.h	2011-01-04 19:50:19.000000000 -0500
@@ -121,13 +121,14 @@
 #define MSR_AMD64_IBSDCLINAD		0xc0011038
 #define MSR_AMD64_IBSDCPHYSAD		0xc0011039
 #define MSR_AMD64_IBSCTL		0xc001103a
+#define MSR_AMD64_IBSBRTARGET		0xc001103b
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE	0xc0010058
 #define FAM10H_MMIO_CONF_ENABLE		(1<<0)
 #define FAM10H_MMIO_CONF_BUSRANGE_MASK	0xf
 #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
-#define FAM10H_MMIO_CONF_BASE_MASK	0xfffffff
+#define FAM10H_MMIO_CONF_BASE_MASK	0xfffffffULL
 #define FAM10H_MMIO_CONF_BASE_SHIFT	20
 #define MSR_FAM10H_NODE_ID		0xc001100c
 
@@ -198,6 +199,7 @@
 #define MSR_IA32_TSC			0x00000010
 #define MSR_IA32_PLATFORM_ID		0x00000017
 #define MSR_IA32_EBL_CR_POWERON		0x0000002a
+#define MSR_EBC_FREQUENCY_ID		0x0000002c
 #define MSR_IA32_FEATURE_CONTROL        0x0000003a
 
 #define FEATURE_CONTROL_LOCKED				(1<<0)
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/mwait.h linux-libre-2.6.37-gnu/arch/x86/include/asm/mwait.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/mwait.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/mwait.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,15 @@
+#ifndef _ASM_X86_MWAIT_H
+#define _ASM_X86_MWAIT_H
+
+#define MWAIT_SUBSTATE_MASK		0xf
+#define MWAIT_CSTATE_MASK		0xf
+#define MWAIT_SUBSTATE_SIZE		4
+#define MWAIT_MAX_NUM_CSTATES		8
+
+#define CPUID_MWAIT_LEAF		5
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1
+#define CPUID5_ECX_INTERRUPT_BREAK	0x2
+
+#define MWAIT_ECX_INTERRUPT_BREAK	0x1
+
+#endif /* _ASM_X86_MWAIT_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/olpc.h linux-libre-2.6.37-gnu/arch/x86/include/asm/olpc.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/olpc.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/olpc.h	2011-01-04 19:50:19.000000000 -0500
@@ -89,6 +89,8 @@
 /* EC commands */
 
 #define EC_FIRMWARE_REV		0x08
+#define EC_WLAN_ENTER_RESET	0x35
+#define EC_WLAN_LEAVE_RESET	0x25
 
 /* SCI source values */
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/olpc_ofw.h linux-libre-2.6.37-gnu/arch/x86/include/asm/olpc_ofw.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/olpc_ofw.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/olpc_ofw.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,10 +21,14 @@
 /* install OFW's pde permanently into the kernel's pgtable */
 extern void setup_olpc_ofw_pgd(void);
 
+/* check if OFW was detected during boot */
+extern bool olpc_ofw_present(void);
+
 #else /* !CONFIG_OLPC_OPENFIRMWARE */
 
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
+static inline bool olpc_ofw_present(void) { return false; }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/page_32_types.h linux-libre-2.6.37-gnu/arch/x86/include/asm/page_32_types.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/page_32_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/page_32_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,11 +15,7 @@
  */
 #define __PAGE_OFFSET		_AC(CONFIG_PAGE_OFFSET, UL)
 
-#ifdef CONFIG_4KSTACKS
-#define THREAD_ORDER	0
-#else
 #define THREAD_ORDER	1
-#endif
 #define THREAD_SIZE 	(PAGE_SIZE << THREAD_ORDER)
 
 #define STACKFAULT_STACK 0
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/page_types.h linux-libre-2.6.37-gnu/arch/x86/include/asm/page_types.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/page_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/page_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
 #define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
-#define __PHYSICAL_MASK		((phys_addr_t)(1ULL << __PHYSICAL_MASK_SHIFT) - 1)
+#define __PHYSICAL_MASK		((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1))
 #define __VIRTUAL_MASK		((1UL << __VIRTUAL_MASK_SHIFT) - 1)
 
 /* Cast PAGE_MASK to a signed type so that it is sign-extended if
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/paravirt.h linux-libre-2.6.37-gnu/arch/x86/include/asm/paravirt.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/paravirt.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/paravirt.h	2011-01-04 19:50:19.000000000 -0500
@@ -105,7 +105,7 @@
 }
 #endif
 
-static inline void raw_safe_halt(void)
+static inline void arch_safe_halt(void)
 {
 	PVOP_VCALL0(pv_irq_ops.safe_halt);
 }
@@ -416,11 +416,6 @@
 	PVOP_VCALL2(pv_mmu_ops.alloc_pmd, mm, pfn);
 }
 
-static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,
-					    unsigned long start, unsigned long count)
-{
-	PVOP_VCALL4(pv_mmu_ops.alloc_pmd_clone, pfn, clonepfn, start, count);
-}
 static inline void paravirt_release_pmd(unsigned long pfn)
 {
 	PVOP_VCALL1(pv_mmu_ops.release_pmd, pfn);
@@ -829,32 +824,32 @@
 #define __PV_IS_CALLEE_SAVE(func)			\
 	((struct paravirt_callee_save) { func })
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline notrace unsigned long arch_local_save_flags(void)
 {
 	return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl);
 }
 
-static inline void raw_local_irq_restore(unsigned long f)
+static inline notrace void arch_local_irq_restore(unsigned long f)
 {
 	PVOP_VCALLEE1(pv_irq_ops.restore_fl, f);
 }
 
-static inline void raw_local_irq_disable(void)
+static inline notrace void arch_local_irq_disable(void)
 {
 	PVOP_VCALLEE0(pv_irq_ops.irq_disable);
 }
 
-static inline void raw_local_irq_enable(void)
+static inline notrace void arch_local_irq_enable(void)
 {
 	PVOP_VCALLEE0(pv_irq_ops.irq_enable);
 }
 
-static inline unsigned long __raw_local_irq_save(void)
+static inline notrace unsigned long arch_local_irq_save(void)
 {
 	unsigned long f;
 
-	f = __raw_local_save_flags();
-	raw_local_irq_disable();
+	f = arch_local_save_flags();
+	arch_local_irq_disable();
 	return f;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/paravirt_types.h linux-libre-2.6.37-gnu/arch/x86/include/asm/paravirt_types.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/paravirt_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/paravirt_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -255,7 +255,6 @@
 	 */
 	void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn);
 	void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn);
-	void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count);
 	void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn);
 	void (*release_pte)(unsigned long pfn);
 	void (*release_pmd)(unsigned long pfn);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pci.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pci.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
+#include <asm/x86_init.h>
 
 #ifdef __KERNEL__
 
@@ -94,8 +95,36 @@
 
 extern void pci_iommu_alloc(void);
 
-/* MSI arch hook */
-#define arch_setup_msi_irqs arch_setup_msi_irqs
+#ifdef CONFIG_PCI_MSI
+/* MSI arch specific hooks */
+static inline int x86_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	return x86_msi.setup_msi_irqs(dev, nvec, type);
+}
+
+static inline void x86_teardown_msi_irqs(struct pci_dev *dev)
+{
+	x86_msi.teardown_msi_irqs(dev);
+}
+
+static inline void x86_teardown_msi_irq(unsigned int irq)
+{
+	x86_msi.teardown_msi_irq(irq);
+}
+#define arch_setup_msi_irqs x86_setup_msi_irqs
+#define arch_teardown_msi_irqs x86_teardown_msi_irqs
+#define arch_teardown_msi_irq x86_teardown_msi_irq
+/* implemented in arch/x86/kernel/apic/io_apic. */
+int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+void native_teardown_msi_irq(unsigned int irq);
+/* default to the implementation in drivers/lib/msi.c */
+#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
+void default_teardown_msi_irqs(struct pci_dev *dev);
+#else
+#define native_setup_msi_irqs		NULL
+#define native_teardown_msi_irq		NULL
+#define default_teardown_msi_irqs	NULL
+#endif
 
 #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pci_x86.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pci_x86.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pci_x86.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pci_x86.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
+void pcibios_set_cache_line_size(void);
 
 /* pci-pc.c */
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/percpu.h linux-libre-2.6.37-gnu/arch/x86/include/asm/percpu.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/percpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/percpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,20 @@
 #ifdef CONFIG_SMP
 #define __percpu_arg(x)		"%%"__stringify(__percpu_seg)":%P" #x
 #define __my_cpu_offset		percpu_read(this_cpu_off)
+
+/*
+ * Compared to the generic __my_cpu_offset version, the following
+ * saves one instruction and avoids clobbering a temp register.
+ */
+#define __this_cpu_ptr(ptr)				\
+({							\
+	unsigned long tcp_ptr__;			\
+	__verify_pcpu_ptr(ptr);				\
+	asm volatile("add " __percpu_arg(1) ", %0"	\
+		     : "=r" (tcp_ptr__)			\
+		     : "m" (this_cpu_off), "0" (ptr));	\
+	(typeof(*(ptr)) __kernel __force *)tcp_ptr__;	\
+})
 #else
 #define __percpu_arg(x)		"%P" #x
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/perf_event.h linux-libre-2.6.37-gnu/arch/x86/include/asm/perf_event.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/perf_event.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/perf_event.h	2011-01-04 19:50:19.000000000 -0500
@@ -111,17 +111,18 @@
 #define X86_PMC_IDX_FIXED_BTS				(X86_PMC_IDX_FIXED + 16)
 
 /* IbsFetchCtl bits/masks */
-#define IBS_FETCH_RAND_EN		(1ULL<<57)
-#define IBS_FETCH_VAL			(1ULL<<49)
-#define IBS_FETCH_ENABLE		(1ULL<<48)
-#define IBS_FETCH_CNT			0xFFFF0000ULL
-#define IBS_FETCH_MAX_CNT		0x0000FFFFULL
+#define IBS_FETCH_RAND_EN	(1ULL<<57)
+#define IBS_FETCH_VAL		(1ULL<<49)
+#define IBS_FETCH_ENABLE	(1ULL<<48)
+#define IBS_FETCH_CNT		0xFFFF0000ULL
+#define IBS_FETCH_MAX_CNT	0x0000FFFFULL
 
 /* IbsOpCtl bits */
-#define IBS_OP_CNT_CTL			(1ULL<<19)
-#define IBS_OP_VAL			(1ULL<<18)
-#define IBS_OP_ENABLE			(1ULL<<17)
-#define IBS_OP_MAX_CNT			0x0000FFFFULL
+#define IBS_OP_CNT_CTL		(1ULL<<19)
+#define IBS_OP_VAL		(1ULL<<18)
+#define IBS_OP_ENABLE		(1ULL<<17)
+#define IBS_OP_MAX_CNT		0x0000FFFFULL
+#define IBS_OP_MAX_CNT_EXT	0x007FFFFFULL	/* not a register bit mask */
 
 #ifdef CONFIG_PERF_EVENTS
 extern void init_hw_perf_events(void);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/perf_event_p4.h linux-libre-2.6.37-gnu/arch/x86/include/asm/perf_event_p4.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/perf_event_p4.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/perf_event_p4.h	2011-01-04 19:50:19.000000000 -0500
@@ -36,19 +36,6 @@
 #define P4_ESCR_EMASK(v)	((v) << P4_ESCR_EVENTMASK_SHIFT)
 #define P4_ESCR_TAG(v)		((v) << P4_ESCR_TAG_SHIFT)
 
-/* Non HT mask */
-#define P4_ESCR_MASK			\
-	(P4_ESCR_EVENT_MASK	|	\
-	P4_ESCR_EVENTMASK_MASK	|	\
-	P4_ESCR_TAG_MASK	|	\
-	P4_ESCR_TAG_ENABLE	|	\
-	P4_ESCR_T0_OS		|	\
-	P4_ESCR_T0_USR)
-
-/* HT mask */
-#define P4_ESCR_MASK_HT			\
-	(P4_ESCR_MASK |	P4_ESCR_T1_OS | P4_ESCR_T1_USR)
-
 #define P4_CCCR_OVF			0x80000000U
 #define P4_CCCR_CASCADE			0x40000000U
 #define P4_CCCR_OVF_PMI_T0		0x04000000U
@@ -70,23 +57,6 @@
 #define P4_CCCR_THRESHOLD(v)		((v) << P4_CCCR_THRESHOLD_SHIFT)
 #define P4_CCCR_ESEL(v)			((v) << P4_CCCR_ESCR_SELECT_SHIFT)
 
-/* Non HT mask */
-#define P4_CCCR_MASK				\
-	(P4_CCCR_OVF			|	\
-	P4_CCCR_CASCADE			|	\
-	P4_CCCR_OVF_PMI_T0		|	\
-	P4_CCCR_FORCE_OVF		|	\
-	P4_CCCR_EDGE			|	\
-	P4_CCCR_THRESHOLD_MASK		|	\
-	P4_CCCR_COMPLEMENT		|	\
-	P4_CCCR_COMPARE			|	\
-	P4_CCCR_ESCR_SELECT_MASK	|	\
-	P4_CCCR_ENABLE)
-
-/* HT mask */
-#define P4_CCCR_MASK_HT				\
-	(P4_CCCR_MASK | P4_CCCR_OVF_PMI_T1 | P4_CCCR_THREAD_ANY)
-
 #define P4_GEN_ESCR_EMASK(class, name, bit)	\
 	class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT)
 #define P4_ESCR_EMASK_BIT(class, name)		class##__##name
@@ -127,6 +97,28 @@
 #define P4_CONFIG_HT_SHIFT		63
 #define P4_CONFIG_HT			(1ULL << P4_CONFIG_HT_SHIFT)
 
+/*
+ * The bits we allow to pass for RAW events
+ */
+#define P4_CONFIG_MASK_ESCR		\
+	P4_ESCR_EVENT_MASK	|	\
+	P4_ESCR_EVENTMASK_MASK	|	\
+	P4_ESCR_TAG_MASK	|	\
+	P4_ESCR_TAG_ENABLE
+
+#define P4_CONFIG_MASK_CCCR		\
+	P4_CCCR_EDGE		|	\
+	P4_CCCR_THRESHOLD_MASK	|	\
+	P4_CCCR_COMPLEMENT	|	\
+	P4_CCCR_COMPARE		|	\
+	P4_CCCR_THREAD_ANY	|	\
+	P4_CCCR_RESERVED
+
+/* some dangerous bits are reserved for kernel internals */
+#define P4_CONFIG_MASK				  	  \
+	(p4_config_pack_escr(P4_CONFIG_MASK_ESCR))	| \
+	(p4_config_pack_cccr(P4_CONFIG_MASK_CCCR))
+
 static inline bool p4_is_event_cascaded(u64 config)
 {
 	u32 cccr = p4_config_unpack_cccr(config);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable_32.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable_32.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,7 @@
 struct vm_area_struct;
 
 extern pgd_t swapper_pg_dir[1024];
-extern pgd_t trampoline_pg_dir[1024];
+extern pgd_t initial_page_table[1024];
 
 static inline void pgtable_cache_init(void) { }
 static inline void check_pgt_cache(void) { }
@@ -49,24 +49,14 @@
 #endif
 
 #if defined(CONFIG_HIGHPTE)
-#define __KM_PTE			\
-	(in_nmi() ? KM_NMI_PTE : 	\
-	 in_irq() ? KM_IRQ_PTE :	\
-	 KM_PTE0)
 #define pte_offset_map(dir, address)					\
-	((pte_t *)kmap_atomic(pmd_page(*(dir)), __KM_PTE) +		\
-	 pte_index((address)))
-#define pte_offset_map_nested(dir, address)				\
-	((pte_t *)kmap_atomic(pmd_page(*(dir)), KM_PTE1) +		\
+	((pte_t *)kmap_atomic(pmd_page(*(dir))) +		\
 	 pte_index((address)))
-#define pte_unmap(pte) kunmap_atomic((pte), __KM_PTE)
-#define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic((pte))
 #else
 #define pte_offset_map(dir, address)					\
 	((pte_t *)page_address(pmd_page(*(dir))) + pte_index((address)))
-#define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
 #define pte_unmap(pte) do { } while (0)
-#define pte_unmap_nested(pte) do { } while (0)
 #endif
 
 /* Clear a kernel PTE and flush it from the TLB */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable_64.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable_64.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -102,6 +102,8 @@
 	native_set_pgd(pgd, native_make_pgd(0));
 }
 
+extern void sync_global_pgds(unsigned long start, unsigned long end);
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -125,9 +127,7 @@
 
 /* x86-64 always has all page tables mapped. */
 #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
-#define pte_offset_map_nested(dir, address) pte_offset_kernel((dir), (address))
 #define pte_unmap(pte) ((void)(pte))/* NOP */
-#define pte_unmap_nested(pte) ((void)(pte)) /* NOP */
 
 #define update_mmu_cache(vma, address, ptep) do { } while (0)
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,8 @@
 extern spinlock_t pgd_lock;
 extern struct list_head pgd_list;
 
+extern struct mm_struct *pgd_page_get_mm(struct page *page);
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else  /* !CONFIG_PARAVIRT */
@@ -603,6 +605,8 @@
 	pte_update(mm, addr, ptep);
 }
 
+#define flush_tlb_fix_spurious_fault(vma, address)
+
 /*
  * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
  *
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/processor.h linux-libre-2.6.37-gnu/arch/x86/include/asm/processor.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/processor.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/processor.h	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,8 @@
 	u16			phys_proc_id;
 	/* Core id: */
 	u16			cpu_core_id;
+	/* Compute unit id */
+	u8			compute_unit_id;
 	/* Index into per_cpu list: */
 	u16			cpu_index;
 #endif
@@ -602,7 +604,7 @@
 
 static inline void set_in_cr4(unsigned long mask)
 {
-	unsigned cr4;
+	unsigned long cr4;
 
 	mmu_cr4_features |= mask;
 	cr4 = read_cr4();
@@ -612,7 +614,7 @@
 
 static inline void clear_in_cr4(unsigned long mask)
 {
-	unsigned cr4;
+	unsigned long cr4;
 
 	mmu_cr4_features &= ~mask;
 	cr4 = read_cr4();
@@ -764,29 +766,6 @@
 extern unsigned long		idle_nomwait;
 extern bool			c1e_detected;
 
-/*
- * on systems with caches, caches must be flashed as the absolute
- * last instruction before going into a suspended halt.  Otherwise,
- * dirty data can linger in the cache and become stale on resume,
- * leading to strange errors.
- *
- * perform a variety of operations to guarantee that the compiler
- * will not reorder instructions.  wbinvd itself is serializing
- * so the processor will not reorder.
- *
- * Systems without cache can just go into halt.
- */
-static inline void wbinvd_halt(void)
-{
-	mb();
-	/* check for clflush to determine if wbinvd is legal */
-	if (cpu_has_clflush)
-		asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory");
-	else
-		while (1)
-			halt();
-}
-
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/pvclock.h linux-libre-2.6.37-gnu/arch/x86/include/asm/pvclock.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/pvclock.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/pvclock.h	2011-01-04 19:50:19.000000000 -0500
@@ -11,5 +11,44 @@
 void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
 			    struct pvclock_vcpu_time_info *vcpu,
 			    struct timespec *ts);
+void pvclock_resume(void);
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+	u64 product;
+#ifdef __i386__
+	u32 tmp1, tmp2;
+#endif
+
+	if (shift < 0)
+		delta >>= -shift;
+	else
+		delta <<= shift;
+
+#ifdef __i386__
+	__asm__ (
+		"mul  %5       ; "
+		"mov  %4,%%eax ; "
+		"mov  %%edx,%4 ; "
+		"mul  %5       ; "
+		"xor  %5,%5    ; "
+		"add  %4,%%eax ; "
+		"adc  %5,%%edx ; "
+		: "=A" (product), "=r" (tmp1), "=r" (tmp2)
+		: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif defined(__x86_64__)
+	__asm__ (
+		"mul %%rdx ; shrd $32,%%rdx,%%rax"
+		: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+	return product;
+}
 
 #endif /* _ASM_X86_PVCLOCK_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/segment.h linux-libre-2.6.37-gnu/arch/x86/include/asm/segment.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/segment.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/segment.h	2011-01-04 19:50:19.000000000 -0500
@@ -73,31 +73,31 @@
 
 #define GDT_ENTRY_DEFAULT_USER_DS	15
 
-#define GDT_ENTRY_KERNEL_BASE	12
+#define GDT_ENTRY_KERNEL_BASE		(12)
 
-#define GDT_ENTRY_KERNEL_CS		(GDT_ENTRY_KERNEL_BASE + 0)
+#define GDT_ENTRY_KERNEL_CS		(GDT_ENTRY_KERNEL_BASE+0)
 
-#define GDT_ENTRY_KERNEL_DS		(GDT_ENTRY_KERNEL_BASE + 1)
+#define GDT_ENTRY_KERNEL_DS		(GDT_ENTRY_KERNEL_BASE+1)
 
-#define GDT_ENTRY_TSS			(GDT_ENTRY_KERNEL_BASE + 4)
-#define GDT_ENTRY_LDT			(GDT_ENTRY_KERNEL_BASE + 5)
+#define GDT_ENTRY_TSS			(GDT_ENTRY_KERNEL_BASE+4)
+#define GDT_ENTRY_LDT			(GDT_ENTRY_KERNEL_BASE+5)
 
-#define GDT_ENTRY_PNPBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 6)
-#define GDT_ENTRY_APMBIOS_BASE		(GDT_ENTRY_KERNEL_BASE + 11)
+#define GDT_ENTRY_PNPBIOS_BASE		(GDT_ENTRY_KERNEL_BASE+6)
+#define GDT_ENTRY_APMBIOS_BASE		(GDT_ENTRY_KERNEL_BASE+11)
 
-#define GDT_ENTRY_ESPFIX_SS		(GDT_ENTRY_KERNEL_BASE + 14)
-#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
+#define GDT_ENTRY_ESPFIX_SS		(GDT_ENTRY_KERNEL_BASE+14)
+#define __ESPFIX_SS			(GDT_ENTRY_ESPFIX_SS*8)
 
-#define GDT_ENTRY_PERCPU			(GDT_ENTRY_KERNEL_BASE + 15)
+#define GDT_ENTRY_PERCPU		(GDT_ENTRY_KERNEL_BASE+15)
 #ifdef CONFIG_SMP
 #define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
 #else
 #define __KERNEL_PERCPU 0
 #endif
 
-#define GDT_ENTRY_STACK_CANARY		(GDT_ENTRY_KERNEL_BASE + 16)
+#define GDT_ENTRY_STACK_CANARY		(GDT_ENTRY_KERNEL_BASE+16)
 #ifdef CONFIG_CC_STACKPROTECTOR
-#define __KERNEL_STACK_CANARY		(GDT_ENTRY_STACK_CANARY * 8)
+#define __KERNEL_STACK_CANARY		(GDT_ENTRY_STACK_CANARY*8)
 #else
 #define __KERNEL_STACK_CANARY		0
 #endif
@@ -182,10 +182,10 @@
 
 #endif
 
-#define __KERNEL_CS	(GDT_ENTRY_KERNEL_CS * 8)
-#define __KERNEL_DS	(GDT_ENTRY_KERNEL_DS * 8)
-#define __USER_DS     (GDT_ENTRY_DEFAULT_USER_DS* 8 + 3)
-#define __USER_CS     (GDT_ENTRY_DEFAULT_USER_CS* 8 + 3)
+#define __KERNEL_CS	(GDT_ENTRY_KERNEL_CS*8)
+#define __KERNEL_DS	(GDT_ENTRY_KERNEL_DS*8)
+#define __USER_DS	(GDT_ENTRY_DEFAULT_USER_DS*8+3)
+#define __USER_CS	(GDT_ENTRY_DEFAULT_USER_CS*8+3)
 #ifndef CONFIG_PARAVIRT
 #define get_kernel_rpl()  0
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/setup.h linux-libre-2.6.37-gnu/arch/x86/include/asm/setup.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/setup.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/setup.h	2011-01-04 19:50:19.000000000 -0500
@@ -93,6 +93,11 @@
 			: : "i" (sz));					\
 	}
 
+/* Helper for reserving space for arrays of things */
+#define RESERVE_BRK_ARRAY(type, name, entries)		\
+	type *name;					\
+	RESERVE_BRK(name, sizeof(type) * entries)
+
 #ifdef __i386__
 
 void __init i386_start_kernel(void);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/smp.h linux-libre-2.6.37-gnu/arch/x86/include/asm/smp.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/smp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/smp.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,7 +50,7 @@
 	void (*smp_prepare_cpus)(unsigned max_cpus);
 	void (*smp_cpus_done)(unsigned max_cpus);
 
-	void (*smp_send_stop)(void);
+	void (*stop_other_cpus)(int wait);
 	void (*smp_send_reschedule)(int cpu);
 
 	int (*cpu_up)(unsigned cpu);
@@ -73,7 +73,12 @@
 
 static inline void smp_send_stop(void)
 {
-	smp_ops.smp_send_stop();
+	smp_ops.stop_other_cpus(0);
+}
+
+static inline void stop_other_cpus(void)
+{
+	smp_ops.stop_other_cpus(1);
 }
 
 static inline void smp_prepare_boot_cpu(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/swiotlb.h linux-libre-2.6.37-gnu/arch/x86/include/asm/swiotlb.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/swiotlb.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/swiotlb.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,17 +5,26 @@
 
 #ifdef CONFIG_SWIOTLB
 extern int swiotlb;
-extern int __init pci_swiotlb_detect(void);
+extern int __init pci_swiotlb_detect_override(void);
+extern int __init pci_swiotlb_detect_4gb(void);
 extern void __init pci_swiotlb_init(void);
+extern void __init pci_swiotlb_late_init(void);
 #else
 #define swiotlb 0
-static inline int pci_swiotlb_detect(void)
+static inline int pci_swiotlb_detect_override(void)
+{
+	return 0;
+}
+static inline int pci_swiotlb_detect_4gb(void)
 {
 	return 0;
 }
 static inline void pci_swiotlb_init(void)
 {
 }
+static inline void pci_swiotlb_late_init(void)
+{
+}
 #endif
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/tlbflush.h linux-libre-2.6.37-gnu/arch/x86/include/asm/tlbflush.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/tlbflush.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/tlbflush.h	2011-01-04 19:50:19.000000000 -0500
@@ -172,6 +172,4 @@
 	flush_tlb_all();
 }
 
-extern void zap_low_mappings(bool early);
-
 #endif /* _ASM_X86_TLBFLUSH_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/trampoline.h linux-libre-2.6.37-gnu/arch/x86/include/asm/trampoline.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/trampoline.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/trampoline.h	2011-01-04 19:50:19.000000000 -0500
@@ -13,16 +13,13 @@
 
 extern unsigned long init_rsp;
 extern unsigned long initial_code;
-extern unsigned long initial_page_table;
 extern unsigned long initial_gs;
 
 #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE)
 
 extern unsigned long setup_trampoline(void);
-extern void __init setup_trampoline_page_table(void);
 extern void __init reserve_trampoline_memory(void);
 #else
-static inline void setup_trampoline_page_table(void) {}
 static inline void reserve_trampoline_memory(void) {}
 #endif /* CONFIG_X86_TRAMPOLINE */
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/uv/uv_hub.h linux-libre-2.6.37-gnu/arch/x86/include/asm/uv/uv_hub.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/uv/uv_hub.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/uv/uv_hub.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -77,7 +77,8 @@
  *
  *		1111110000000000
  *		5432109876543210
- *		pppppppppplc0cch
+ *		pppppppppplc0cch	Nehalem-EX
+ *		ppppppppplcc0cch	Westmere-EX
  *		sssssssssss
  *
  *			p  = pnode bits
@@ -148,12 +149,25 @@
 	unsigned char		m_val;
 	unsigned char		n_val;
 	struct uv_scir_s	scir;
+	unsigned char		apic_pnode_shift;
 };
 
 DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define uv_hub_info		(&__get_cpu_var(__uv_hub_info))
 #define uv_cpu_hub_info(cpu)	(&per_cpu(__uv_hub_info, cpu))
 
+union uvh_apicid {
+    unsigned long       v;
+    struct uvh_apicid_s {
+        unsigned long   local_apic_mask  : 24;
+        unsigned long   local_apic_shift :  5;
+        unsigned long   unused1          :  3;
+        unsigned long   pnode_mask       : 24;
+        unsigned long   pnode_shift      :  5;
+        unsigned long   unused2          :  3;
+    } s;
+};
+
 /*
  * Local & Global MMR space macros.
  *	Note: macros are intended to be used ONLY by inline functions
@@ -182,8 +196,11 @@
 #define UV_GLOBAL_MMR64_PNODE_BITS(p)					\
 	(((unsigned long)(p)) << UV_GLOBAL_MMR64_PNODE_SHIFT)
 
+#define UVH_APICID		0x002D0E00L
 #define UV_APIC_PNODE_SHIFT	6
 
+#define UV_APICID_HIBIT_MASK	0xffff0000
+
 /* Local Bus from cpu's perspective */
 #define LOCAL_BUS_BASE		0x1c00000
 #define LOCAL_BUS_SIZE		(4 * 1024 * 1024)
@@ -280,7 +297,7 @@
  */
 static inline int uv_apicid_to_pnode(int apicid)
 {
-	return (apicid >> UV_APIC_PNODE_SHIFT);
+	return (apicid >> uv_hub_info->apic_pnode_shift);
 }
 
 /*
@@ -476,8 +493,10 @@
 	}
 }
 
+extern unsigned int uv_apicid_hibits;
 static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
 {
+	apicid |= uv_apicid_hibits;
 	return (1UL << UVH_IPI_INT_SEND_SHFT) |
 			((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
 			(mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/uv/uv_mmrs.h linux-libre-2.6.37-gnu/arch/x86/include/asm/uv/uv_mmrs.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/uv/uv_mmrs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/uv/uv_mmrs.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  * SGI UV MMR definitions
  *
- * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_MMRS_H
@@ -754,6 +754,23 @@
 };
 
 /* ========================================================================= */
+/*                   UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK                     */
+/* ========================================================================= */
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x009f0
+
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0
+#define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL
+
+union uvh_lb_target_physical_apic_id_mask_u {
+	unsigned long v;
+	struct uvh_lb_target_physical_apic_id_mask_s {
+		unsigned long bit_enables : 32;  /* RW */
+		unsigned long rsvd_32_63  : 32;  /*    */
+	} s;
+};
+
+/* ========================================================================= */
 /*                               UVH_NODE_ID                                 */
 /* ========================================================================= */
 #define UVH_NODE_ID 0x0UL
@@ -806,6 +823,78 @@
 };
 
 /* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_0_mmr_u {
+    unsigned long	v;
+    struct uvh_rh_gam_alias210_overlay_config_0_mmr_s {
+	unsigned long	rsvd_0_23: 24;  /*    */
+	unsigned long	base    :  8;  /* RW */
+	unsigned long	rsvd_32_47: 16;  /*    */
+	unsigned long	m_alias :  5;  /* RW */
+	unsigned long	rsvd_53_62: 10;  /*    */
+	unsigned long	enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_1_mmr_u {
+    unsigned long	v;
+    struct uvh_rh_gam_alias210_overlay_config_1_mmr_s {
+	unsigned long	rsvd_0_23: 24;  /*    */
+	unsigned long	base    :  8;  /* RW */
+	unsigned long	rsvd_32_47: 16;  /*    */
+	unsigned long	m_alias :  5;  /* RW */
+	unsigned long	rsvd_53_62: 10;  /*    */
+	unsigned long	enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
+/*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR                  */
+/* ========================================================================= */
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
+
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_MASK 0x00000000ff000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_MASK 0x001f000000000000UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_SHFT 63
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uvh_rh_gam_alias210_overlay_config_2_mmr_u {
+    unsigned long	v;
+    struct uvh_rh_gam_alias210_overlay_config_2_mmr_s {
+	unsigned long	rsvd_0_23: 24;  /*    */
+	unsigned long	base    :  8;  /* RW */
+	unsigned long	rsvd_32_47: 16;  /*    */
+	unsigned long	m_alias :  5;  /* RW */
+	unsigned long	rsvd_53_62: 10;  /*    */
+	unsigned long	enable  :  1;  /* RW */
+    } s;
+};
+
+/* ========================================================================= */
 /*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR                  */
 /* ========================================================================= */
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
@@ -857,6 +946,29 @@
 };
 
 /* ========================================================================= */
+/*                          UVH_RH_GAM_CONFIG_MMR                            */
+/* ========================================================================= */
+#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL
+
+#define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT 0
+#define UVH_RH_GAM_CONFIG_MMR_M_SKT_MASK 0x000000000000003fUL
+#define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT 6
+#define UVH_RH_GAM_CONFIG_MMR_N_SKT_MASK 0x00000000000003c0UL
+#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_SHFT 12
+#define UVH_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK 0x0000000000001000UL
+
+union uvh_rh_gam_config_mmr_u {
+    unsigned long	v;
+    struct uvh_rh_gam_config_mmr_s {
+	unsigned long	m_skt     :  6;  /* RW */
+	unsigned long	n_skt     :  4;  /* RW */
+	unsigned long	rsvd_10_11:  2;  /*    */
+	unsigned long	mmiol_cfg :  1;  /* RW */
+	unsigned long	rsvd_13_63: 51;  /*    */
+    } s;
+};
+
+/* ========================================================================= */
 /*                    UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
@@ -987,97 +1099,5 @@
     } s;
 };
 
-/* ========================================================================= */
-/*                          UVH_SI_ADDR_MAP_CONFIG                           */
-/* ========================================================================= */
-#define UVH_SI_ADDR_MAP_CONFIG 0xc80000UL
-
-#define UVH_SI_ADDR_MAP_CONFIG_M_SKT_SHFT 0
-#define UVH_SI_ADDR_MAP_CONFIG_M_SKT_MASK 0x000000000000003fUL
-#define UVH_SI_ADDR_MAP_CONFIG_N_SKT_SHFT 8
-#define UVH_SI_ADDR_MAP_CONFIG_N_SKT_MASK 0x0000000000000f00UL
-
-union uvh_si_addr_map_config_u {
-    unsigned long	v;
-    struct uvh_si_addr_map_config_s {
-	unsigned long	m_skt :  6;  /* RW */
-	unsigned long	rsvd_6_7:  2;  /*    */
-	unsigned long	n_skt :  4;  /* RW */
-	unsigned long	rsvd_12_63: 52;  /*    */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS0_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG 0xc80008UL
-
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS0_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias0_overlay_config_u {
-    unsigned long	v;
-    struct uvh_si_alias0_overlay_config_s {
-	unsigned long	rsvd_0_23: 24;  /*    */
-	unsigned long	base    :  8;  /* RW */
-	unsigned long	rsvd_32_47: 16;  /*    */
-	unsigned long	m_alias :  5;  /* RW */
-	unsigned long	rsvd_53_62: 10;  /*    */
-	unsigned long	enable  :  1;  /* RW */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS1_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG 0xc80010UL
-
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS1_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias1_overlay_config_u {
-    unsigned long	v;
-    struct uvh_si_alias1_overlay_config_s {
-	unsigned long	rsvd_0_23: 24;  /*    */
-	unsigned long	base    :  8;  /* RW */
-	unsigned long	rsvd_32_47: 16;  /*    */
-	unsigned long	m_alias :  5;  /* RW */
-	unsigned long	rsvd_53_62: 10;  /*    */
-	unsigned long	enable  :  1;  /* RW */
-    } s;
-};
-
-/* ========================================================================= */
-/*                       UVH_SI_ALIAS2_OVERLAY_CONFIG                        */
-/* ========================================================================= */
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG 0xc80018UL
-
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_SHFT 24
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_BASE_MASK 0x00000000ff000000UL
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_SHFT 48
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_M_ALIAS_MASK 0x001f000000000000UL
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_SHFT 63
-#define UVH_SI_ALIAS2_OVERLAY_CONFIG_ENABLE_MASK 0x8000000000000000UL
-
-union uvh_si_alias2_overlay_config_u {
-    unsigned long	v;
-    struct uvh_si_alias2_overlay_config_s {
-	unsigned long	rsvd_0_23: 24;  /*    */
-	unsigned long	base    :  8;  /* RW */
-	unsigned long	rsvd_32_47: 16;  /*    */
-	unsigned long	m_alias :  5;  /* RW */
-	unsigned long	rsvd_53_62: 10;  /*    */
-	unsigned long	enable  :  1;  /* RW */
-    } s;
-};
 
-
-#endif /* _ASM_X86_UV_UV_MMRS_H */
+#endif /* __ASM_UV_MMRS_X86_H__ */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/vmi.h linux-libre-2.6.37-gnu/arch/x86/include/asm/vmi.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/vmi.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/vmi.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,269 +0,0 @@
-/*
- * VMI interface definition
- *
- * Copyright (C) 2005, VMware, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Maintained by: Zachary Amsden zach@vmware.com
- *
- */
-#include <linux/types.h>
-
-/*
- *---------------------------------------------------------------------
- *
- *  VMI Option ROM API
- *
- *---------------------------------------------------------------------
- */
-#define VMI_SIGNATURE 0x696d5663   /* "cVmi" */
-
-#define PCI_VENDOR_ID_VMWARE            0x15AD
-#define PCI_DEVICE_ID_VMWARE_VMI        0x0801
-
-/*
- * We use two version numbers for compatibility, with the major
- * number signifying interface breakages, and the minor number
- * interface extensions.
- */
-#define VMI_API_REV_MAJOR       3
-#define VMI_API_REV_MINOR       0
-
-#define VMI_CALL_CPUID			0
-#define VMI_CALL_WRMSR			1
-#define VMI_CALL_RDMSR			2
-#define VMI_CALL_SetGDT			3
-#define VMI_CALL_SetLDT			4
-#define VMI_CALL_SetIDT			5
-#define VMI_CALL_SetTR			6
-#define VMI_CALL_GetGDT			7
-#define VMI_CALL_GetLDT			8
-#define VMI_CALL_GetIDT			9
-#define VMI_CALL_GetTR			10
-#define VMI_CALL_WriteGDTEntry		11
-#define VMI_CALL_WriteLDTEntry		12
-#define VMI_CALL_WriteIDTEntry		13
-#define VMI_CALL_UpdateKernelStack	14
-#define VMI_CALL_SetCR0			15
-#define VMI_CALL_SetCR2			16
-#define VMI_CALL_SetCR3			17
-#define VMI_CALL_SetCR4			18
-#define VMI_CALL_GetCR0			19
-#define VMI_CALL_GetCR2			20
-#define VMI_CALL_GetCR3			21
-#define VMI_CALL_GetCR4			22
-#define VMI_CALL_WBINVD			23
-#define VMI_CALL_SetDR			24
-#define VMI_CALL_GetDR			25
-#define VMI_CALL_RDPMC			26
-#define VMI_CALL_RDTSC			27
-#define VMI_CALL_CLTS			28
-#define VMI_CALL_EnableInterrupts	29
-#define VMI_CALL_DisableInterrupts	30
-#define VMI_CALL_GetInterruptMask	31
-#define VMI_CALL_SetInterruptMask	32
-#define VMI_CALL_IRET			33
-#define VMI_CALL_SYSEXIT		34
-#define VMI_CALL_Halt			35
-#define VMI_CALL_Reboot			36
-#define VMI_CALL_Shutdown		37
-#define VMI_CALL_SetPxE			38
-#define VMI_CALL_SetPxELong		39
-#define VMI_CALL_UpdatePxE		40
-#define VMI_CALL_UpdatePxELong		41
-#define VMI_CALL_MachineToPhysical	42
-#define VMI_CALL_PhysicalToMachine	43
-#define VMI_CALL_AllocatePage		44
-#define VMI_CALL_ReleasePage		45
-#define VMI_CALL_InvalPage		46
-#define VMI_CALL_FlushTLB		47
-#define VMI_CALL_SetLinearMapping	48
-
-#define VMI_CALL_SetIOPLMask		61
-#define VMI_CALL_SetInitialAPState	62
-#define VMI_CALL_APICWrite		63
-#define VMI_CALL_APICRead		64
-#define VMI_CALL_IODelay		65
-#define VMI_CALL_SetLazyMode		73
-
-/*
- *---------------------------------------------------------------------
- *
- * MMU operation flags
- *
- *---------------------------------------------------------------------
- */
-
-/* Flags used by VMI_{Allocate|Release}Page call */
-#define VMI_PAGE_PAE             0x10  /* Allocate PAE shadow */
-#define VMI_PAGE_CLONE           0x20  /* Clone from another shadow */
-#define VMI_PAGE_ZEROED          0x40  /* Page is pre-zeroed */
-
-
-/* Flags shared by Allocate|Release Page and PTE updates */
-#define VMI_PAGE_PT              0x01
-#define VMI_PAGE_PD              0x02
-#define VMI_PAGE_PDP             0x04
-#define VMI_PAGE_PML4            0x08
-
-#define VMI_PAGE_NORMAL          0x00 /* for debugging */
-
-/* Flags used by PTE updates */
-#define VMI_PAGE_CURRENT_AS      0x10 /* implies VMI_PAGE_VA_MASK is valid */
-#define VMI_PAGE_DEFER           0x20 /* may queue update until TLB inval */
-#define VMI_PAGE_VA_MASK         0xfffff000
-
-#ifdef CONFIG_X86_PAE
-#define VMI_PAGE_L1		(VMI_PAGE_PT | VMI_PAGE_PAE | VMI_PAGE_ZEROED)
-#define VMI_PAGE_L2		(VMI_PAGE_PD | VMI_PAGE_PAE | VMI_PAGE_ZEROED)
-#else
-#define VMI_PAGE_L1		(VMI_PAGE_PT | VMI_PAGE_ZEROED)
-#define VMI_PAGE_L2		(VMI_PAGE_PD | VMI_PAGE_ZEROED)
-#endif
-
-/* Flags used by VMI_FlushTLB call */
-#define VMI_FLUSH_TLB            0x01
-#define VMI_FLUSH_GLOBAL         0x02
-
-/*
- *---------------------------------------------------------------------
- *
- *  VMI relocation definitions for ROM call get_reloc
- *
- *---------------------------------------------------------------------
- */
-
-/* VMI Relocation types */
-#define VMI_RELOCATION_NONE     0
-#define VMI_RELOCATION_CALL_REL 1
-#define VMI_RELOCATION_JUMP_REL 2
-#define VMI_RELOCATION_NOP	3
-
-#ifndef __ASSEMBLY__
-struct vmi_relocation_info {
-	unsigned char           *eip;
-	unsigned char           type;
-	unsigned char           reserved[3];
-};
-#endif
-
-
-/*
- *---------------------------------------------------------------------
- *
- *  Generic ROM structures and definitions
- *
- *---------------------------------------------------------------------
- */
-
-#ifndef __ASSEMBLY__
-
-struct vrom_header {
-	u16     rom_signature;  /* option ROM signature */
-	u8      rom_length;     /* ROM length in 512 byte chunks */
-	u8      rom_entry[4];   /* 16-bit code entry point */
-	u8      rom_pad0;       /* 4-byte align pad */
-	u32     vrom_signature; /* VROM identification signature */
-	u8      api_version_min;/* Minor version of API */
-	u8      api_version_maj;/* Major version of API */
-	u8      jump_slots;     /* Number of jump slots */
-	u8      reserved1;      /* Reserved for expansion */
-	u32     virtual_top;    /* Hypervisor virtual address start */
-	u16     reserved2;      /* Reserved for expansion */
-	u16	license_offs;	/* Offset to License string */
-	u16     pci_header_offs;/* Offset to PCI OPROM header */
-	u16     pnp_header_offs;/* Offset to PnP OPROM header */
-	u32     rom_pad3;       /* PnP reserverd / VMI reserved */
-	u8      reserved[96];   /* Reserved for headers */
-	char    vmi_init[8];    /* VMI_Init jump point */
-	char    get_reloc[8];   /* VMI_GetRelocationInfo jump point */
-} __attribute__((packed));
-
-struct pnp_header {
-	char sig[4];
-	char rev;
-	char size;
-	short next;
-	short res;
-	long devID;
-	unsigned short manufacturer_offset;
-	unsigned short product_offset;
-} __attribute__((packed));
-
-struct pci_header {
-	char sig[4];
-	short vendorID;
-	short deviceID;
-	short vpdData;
-	short size;
-	char rev;
-	char class;
-	char subclass;
-	char interface;
-	short chunks;
-	char rom_version_min;
-	char rom_version_maj;
-	char codetype;
-	char lastRom;
-	short reserved;
-} __attribute__((packed));
-
-/* Function prototypes for bootstrapping */
-#ifdef CONFIG_VMI
-extern void vmi_init(void);
-extern void vmi_activate(void);
-extern void vmi_bringup(void);
-#else
-static inline void vmi_init(void) {}
-static inline void vmi_activate(void) {}
-static inline void vmi_bringup(void) {}
-#endif
-
-/* State needed to start an application processor in an SMP system. */
-struct vmi_ap_state {
-	u32 cr0;
-	u32 cr2;
-	u32 cr3;
-	u32 cr4;
-
-	u64 efer;
-
-	u32 eip;
-	u32 eflags;
-	u32 eax;
-	u32 ebx;
-	u32 ecx;
-	u32 edx;
-	u32 esp;
-	u32 ebp;
-	u32 esi;
-	u32 edi;
-	u16 cs;
-	u16 ss;
-	u16 ds;
-	u16 es;
-	u16 fs;
-	u16 gs;
-	u16 ldtr;
-
-	u16 gdtr_limit;
-	u32 gdtr_base;
-	u32 idtr_base;
-	u16 idtr_limit;
-};
-
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/vmi_time.h linux-libre-2.6.37-gnu/arch/x86/include/asm/vmi_time.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/vmi_time.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/vmi_time.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,98 +0,0 @@
-/*
- * VMI Time wrappers
- *
- * Copyright (C) 2006, VMware, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to dhecht@vmware.com
- *
- */
-
-#ifndef _ASM_X86_VMI_TIME_H
-#define _ASM_X86_VMI_TIME_H
-
-/*
- * Raw VMI call indices for timer functions
- */
-#define VMI_CALL_GetCycleFrequency	66
-#define VMI_CALL_GetCycleCounter	67
-#define VMI_CALL_SetAlarm		68
-#define VMI_CALL_CancelAlarm		69
-#define VMI_CALL_GetWallclockTime	70
-#define VMI_CALL_WallclockUpdated	71
-
-/* Cached VMI timer operations */
-extern struct vmi_timer_ops {
-	u64 (*get_cycle_frequency)(void);
-	u64 (*get_cycle_counter)(int);
-	u64 (*get_wallclock)(void);
-	int (*wallclock_updated)(void);
-	void (*set_alarm)(u32 flags, u64 expiry, u64 period);
-	void (*cancel_alarm)(u32 flags);
-} vmi_timer_ops;
-
-/* Prototypes */
-extern void __init vmi_time_init(void);
-extern unsigned long vmi_get_wallclock(void);
-extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_sched_clock(void);
-extern unsigned long vmi_tsc_khz(void);
-
-#ifdef CONFIG_X86_LOCAL_APIC
-extern void __devinit vmi_time_bsp_init(void);
-extern void __devinit vmi_time_ap_init(void);
-#endif
-
-/*
- * When run under a hypervisor, a vcpu is always in one of three states:
- * running, halted, or ready.  The vcpu is in the 'running' state if it
- * is executing.  When the vcpu executes the halt interface, the vcpu
- * enters the 'halted' state and remains halted until there is some work
- * pending for the vcpu (e.g. an alarm expires, host I/O completes on
- * behalf of virtual I/O).  At this point, the vcpu enters the 'ready'
- * state (waiting for the hypervisor to reschedule it).  Finally, at any
- * time when the vcpu is not in the 'running' state nor the 'halted'
- * state, it is in the 'ready' state.
- *
- * Real time is advances while the vcpu is 'running', 'ready', or
- * 'halted'.  Stolen time is the time in which the vcpu is in the
- * 'ready' state.  Available time is the remaining time -- the vcpu is
- * either 'running' or 'halted'.
- *
- * All three views of time are accessible through the VMI cycle
- * counters.
- */
-
-/* The cycle counters. */
-#define VMI_CYCLES_REAL         0
-#define VMI_CYCLES_AVAILABLE    1
-#define VMI_CYCLES_STOLEN       2
-
-/* The alarm interface 'flags' bits */
-#define VMI_ALARM_COUNTERS      2
-
-#define VMI_ALARM_COUNTER_MASK  0x000000ff
-
-#define VMI_ALARM_WIRED_IRQ0    0x00000000
-#define VMI_ALARM_WIRED_LVTT    0x00010000
-
-#define VMI_ALARM_IS_ONESHOT    0x00000000
-#define VMI_ALARM_IS_PERIODIC   0x00000100
-
-#define CONFIG_VMI_ALARM_HZ	100
-
-#endif /* _ASM_X86_VMI_TIME_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/x86_init.h linux-libre-2.6.37-gnu/arch/x86/include/asm/x86_init.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/x86_init.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/x86_init.h	2011-01-04 19:50:19.000000000 -0500
@@ -154,9 +154,18 @@
 	int (*i8042_detect)(void);
 };
 
+struct pci_dev;
+
+struct x86_msi_ops {
+	int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
+	void (*teardown_msi_irq)(unsigned int irq);
+	void (*teardown_msi_irqs)(struct pci_dev *dev);
+};
+
 extern struct x86_init_ops x86_init;
 extern struct x86_cpuinit_ops x86_cpuinit;
 extern struct x86_platform_ops x86_platform;
+extern struct x86_msi_ops x86_msi;
 
 extern void x86_init_noop(void);
 extern void x86_init_uint_noop(unsigned int unused);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/hypercall.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/hypercall.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/hypercall.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/hypercall.h	2011-01-04 19:50:19.000000000 -0500
@@ -200,6 +200,23 @@
 	(type)__res;							\
 })
 
+static inline long
+privcmd_call(unsigned call,
+	     unsigned long a1, unsigned long a2,
+	     unsigned long a3, unsigned long a4,
+	     unsigned long a5)
+{
+	__HYPERCALL_DECLS;
+	__HYPERCALL_5ARG(a1, a2, a3, a4, a5);
+
+	asm volatile("call *%[call]"
+		     : __HYPERCALL_5PARAM
+		     : [call] "a" (&hypercall_page[call])
+		     : __HYPERCALL_CLOBBER5);
+
+	return (long)__res;
+}
+
 static inline int
 HYPERVISOR_set_trap_table(struct trap_info *table)
 {
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface_32.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface_32.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface_32.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface_32.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,11 @@
 /* And the trap vector is... */
 #define TRAP_INSTR "int $0x82"
 
+#define __MACH2PHYS_VIRT_START 0xF5800000
+#define __MACH2PHYS_VIRT_END   0xF6800000
+
+#define __MACH2PHYS_SHIFT      2
+
 /*
  * Virtual addresses beyond this are not modifiable by guest OSes. The
  * machine->physical mapping table starts at this address, read-only.
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface_64.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface_64.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface_64.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface_64.h	2011-01-04 19:50:19.000000000 -0500
@@ -39,18 +39,7 @@
 #define __HYPERVISOR_VIRT_END   0xFFFF880000000000
 #define __MACH2PHYS_VIRT_START  0xFFFF800000000000
 #define __MACH2PHYS_VIRT_END    0xFFFF804000000000
-
-#ifndef HYPERVISOR_VIRT_START
-#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
-#define HYPERVISOR_VIRT_END   mk_unsigned_long(__HYPERVISOR_VIRT_END)
-#endif
-
-#define MACH2PHYS_VIRT_START  mk_unsigned_long(__MACH2PHYS_VIRT_START)
-#define MACH2PHYS_VIRT_END    mk_unsigned_long(__MACH2PHYS_VIRT_END)
-#define MACH2PHYS_NR_ENTRIES  ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>3)
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define __MACH2PHYS_SHIFT       3
 
 /*
  * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/interface.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/interface.h	2011-01-04 19:50:19.000000000 -0500
@@ -61,9 +61,9 @@
 #define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
 #endif
 
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
+#define MACH2PHYS_VIRT_START  mk_unsigned_long(__MACH2PHYS_VIRT_START)
+#define MACH2PHYS_VIRT_END    mk_unsigned_long(__MACH2PHYS_VIRT_END)
+#define MACH2PHYS_NR_ENTRIES  ((MACH2PHYS_VIRT_END-MACH2PHYS_VIRT_START)>>__MACH2PHYS_SHIFT)
 
 /* Maximum number of virtual CPUs in multi-processor guests. */
 #define MAX_VIRT_CPUS 32
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/page.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/page.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/page.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/page.h	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/pfn.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -35,16 +36,25 @@
 #define MAX_DOMAIN_PAGES						\
     ((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
 
+extern unsigned long *machine_to_phys_mapping;
+extern unsigned int   machine_to_phys_order;
 
 extern unsigned long get_phys_to_machine(unsigned long pfn);
-extern void set_phys_to_machine(unsigned long pfn, unsigned long mfn);
+extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
 
 static inline unsigned long pfn_to_mfn(unsigned long pfn)
 {
+	unsigned long mfn;
+
 	if (xen_feature(XENFEAT_auto_translated_physmap))
 		return pfn;
 
-	return get_phys_to_machine(pfn) & ~FOREIGN_FRAME_BIT;
+	mfn = get_phys_to_machine(pfn);
+
+	if (mfn != INVALID_P2M_ENTRY)
+		mfn &= ~FOREIGN_FRAME_BIT;
+
+	return mfn;
 }
 
 static inline int phys_to_machine_mapping_valid(unsigned long pfn)
@@ -62,10 +72,8 @@
 	if (xen_feature(XENFEAT_auto_translated_physmap))
 		return mfn;
 
-#if 0
 	if (unlikely((mfn >> machine_to_phys_order) != 0))
-		return max_mapnr;
-#endif
+		return ~0;
 
 	pfn = 0;
 	/*
@@ -159,6 +167,7 @@
 
 #define pgd_val_ma(x)	((x).pgd)
 
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid);
 
 xmaddr_t arbitrary_virt_to_machine(void *address);
 unsigned long arbitrary_virt_to_mfn(void *vaddr);
diff -druN linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/pci.h linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/pci.h
--- linux-libre-2.6.36-gnu/arch/x86/include/asm/xen/pci.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/include/asm/xen/pci.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,65 @@
+#ifndef _ASM_X86_XEN_PCI_H
+#define _ASM_X86_XEN_PCI_H
+
+#if defined(CONFIG_PCI_XEN)
+extern int __init pci_xen_init(void);
+extern int __init pci_xen_hvm_init(void);
+#define pci_xen 1
+#else
+#define pci_xen 0
+#define pci_xen_init (0)
+static inline int pci_xen_hvm_init(void)
+{
+	return -1;
+}
+#endif
+#if defined(CONFIG_XEN_DOM0)
+void __init xen_setup_pirqs(void);
+#else
+static inline void __init xen_setup_pirqs(void)
+{
+}
+#endif
+
+#if defined(CONFIG_PCI_MSI)
+#if defined(CONFIG_PCI_XEN)
+/* The drivers/pci/xen-pcifront.c sets this structure to
+ * its own functions.
+ */
+struct xen_pci_frontend_ops {
+	int (*enable_msi)(struct pci_dev *dev, int **vectors);
+	void (*disable_msi)(struct pci_dev *dev);
+	int (*enable_msix)(struct pci_dev *dev, int **vectors, int nvec);
+	void (*disable_msix)(struct pci_dev *dev);
+};
+
+extern struct xen_pci_frontend_ops *xen_pci_frontend;
+
+static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
+					      int **vectors)
+{
+	if (xen_pci_frontend && xen_pci_frontend->enable_msi)
+		return xen_pci_frontend->enable_msi(dev, vectors);
+	return -ENODEV;
+}
+static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
+{
+	if (xen_pci_frontend && xen_pci_frontend->disable_msi)
+			xen_pci_frontend->disable_msi(dev);
+}
+static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
+					       int **vectors, int nvec)
+{
+	if (xen_pci_frontend && xen_pci_frontend->enable_msix)
+		return xen_pci_frontend->enable_msix(dev, vectors, nvec);
+	return -ENODEV;
+}
+static inline void xen_pci_frontend_disable_msix(struct pci_dev *dev)
+{
+	if (xen_pci_frontend && xen_pci_frontend->disable_msix)
+			xen_pci_frontend->disable_msix(dev);
+}
+#endif /* CONFIG_PCI_XEN */
+#endif /* CONFIG_PCI_MSI */
+
+#endif	/* _ASM_X86_XEN_PCI_H */
diff -druN linux-libre-2.6.36-gnu/arch/x86/Kbuild linux-libre-2.6.37-gnu/arch/x86/Kbuild
--- linux-libre-2.6.36-gnu/arch/x86/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -14,3 +14,4 @@
 obj-y += vdso/
 obj-$(CONFIG_IA32_EMULATION) += ia32/
 
+obj-y += platform/
diff -druN linux-libre-2.6.36-gnu/arch/x86/Kconfig linux-libre-2.6.37-gnu/arch/x86/Kconfig
--- linux-libre-2.6.36-gnu/arch/x86/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,3 @@
-# x86 configuration
-mainmenu "Linux Kernel Configuration for x86"
-
 # Select 32 or 64 bit
 config 64BIT
 	bool "64-bit kernel" if ARCH = "x86"
@@ -24,15 +21,18 @@
 	select HAVE_UNSTABLE_SCHED_CLOCK
 	select HAVE_IDE
 	select HAVE_OPROFILE
-	select HAVE_PERF_EVENTS if (!M386 && !M486)
+	select HAVE_PERF_EVENTS
+	select HAVE_IRQ_WORK
 	select HAVE_IOREMAP_PROT
 	select HAVE_KPROBES
+	select HAVE_MEMBLOCK
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_WANT_FRAME_POINTERS
 	select HAVE_DMA_ATTRS
 	select HAVE_KRETPROBES
 	select HAVE_OPTPROBES
 	select HAVE_FTRACE_MCOUNT_RECORD
+	select HAVE_C_RECORDMCOUNT
 	select HAVE_DYNAMIC_FTRACE
 	select HAVE_FUNCTION_TRACER
 	select HAVE_FUNCTION_GRAPH_TRACER
@@ -59,6 +59,12 @@
 	select ANON_INODES
 	select HAVE_ARCH_KMEMCHECK
 	select HAVE_USER_RETURN_NOTIFIER
+	select HAVE_ARCH_JUMP_LABEL
+	select HAVE_TEXT_POKE_SMP
+	select HAVE_GENERIC_HARDIRQS
+	select HAVE_SPARSE_IRQ
+	select GENERIC_IRQ_PROBE
+	select GENERIC_PENDING_IRQ if SMP
 
 config INSTRUCTION_DECODER
 	def_bool (KPROBES || PERF_EVENTS)
@@ -193,27 +199,10 @@
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 	def_bool y
 
-config HAVE_EARLY_RES
-	def_bool y
-
 config HAVE_INTEL_TXT
 	def_bool y
 	depends on EXPERIMENTAL && DMAR && ACPI
 
-# Use the generic interrupt handling code in kernel/irq/:
-config GENERIC_HARDIRQS
-	def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-	def_bool y
-
-config GENERIC_PENDING_IRQ
-	def_bool y
-	depends on GENERIC_HARDIRQS && SMP
-
 config USE_GENERIC_SMP_HELPERS
 	def_bool y
 	depends on SMP
@@ -296,23 +285,6 @@
 
 	  If you don't know what to do here, say N.
 
-config SPARSE_IRQ
-	bool "Support sparse irq numbering"
-	depends on PCI_MSI || HT_IRQ
-	---help---
-	  This enables support for sparse irqs. This is useful for distro
-	  kernels that want to define a high CONFIG_NR_CPUS value but still
-	  want to have low kernel memory footprint on smaller machines.
-
-	  ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
-	    out the irq_desc[] array in a more NUMA-friendly way. )
-
-	  If you don't know what to do here, say N.
-
-config NUMA_IRQ_DESC
-	def_bool y
-	depends on SPARSE_IRQ && NUMA
-
 config X86_MPPARSE
 	bool "Enable MPS table" if ACPI
 	default y
@@ -372,6 +344,7 @@
 
 config X86_VSMP
 	bool "ScaleMP vSMP"
+	select PARAVIRT_GUEST
 	select PARAVIRT
 	depends on X86_64 && PCI
 	depends on X86_EXTENDED_PLATFORM
@@ -517,25 +490,6 @@
 
 source "arch/x86/xen/Kconfig"
 
-config VMI
-	bool "VMI Guest support (DEPRECATED)"
-	select PARAVIRT
-	depends on X86_32
-	---help---
-	  VMI provides a paravirtualized interface to the VMware ESX server
-	  (it could be used by other hypervisors in theory too, but is not
-	  at the moment), by linking the kernel to a GPL-ed ROM module
-	  provided by the hypervisor.
-
-	  As of September 2009, VMware has started a phased retirement
-	  of this feature from VMware's products. Please see
-	  feature-removal-schedule.txt for details.  If you are
-	  planning to enable this option, please note that you cannot
-	  live migrate a VMI enabled VM to a future VMware product,
-	  which doesn't support VMI. So if you expect your kernel to
-	  seamlessly migrate to newer VMware products, keep this
-	  disabled.
-
 config KVM_CLOCK
 	bool "KVM paravirtualized clock"
 	select PARAVIRT
@@ -590,16 +544,7 @@
 	  a paravirt_op is missing when it is called.
 
 config NO_BOOTMEM
-	default y
-	bool "Disable Bootmem code"
-	---help---
-	  Use early_res directly instead of bootmem before slab is ready.
-		- allocator (buddy) [generic]
-		- early allocator (bootmem) [generic]
-		- very early allocator (reserve_early*()) [x86]
-		- very very early allocator (early brk model) [x86]
-	  So reduce one layer between early allocator to final allocator
-
+	def_bool y
 
 config MEMTEST
 	bool "Memtest"
@@ -670,7 +615,7 @@
 	bool "GART IOMMU support" if EMBEDDED
 	default y
 	select SWIOTLB
-	depends on X86_64 && PCI && K8_NB
+	depends on X86_64 && PCI && AMD_NB
 	---help---
 	  Support for full DMA access of devices with 32bit memory access only
 	  on systems with more than 3GB. This is usually needed for USB,
@@ -795,6 +740,17 @@
 	  making when dealing with multi-core CPU chips at a cost of slightly
 	  increased overhead in some places. If unsure say N here.
 
+config IRQ_TIME_ACCOUNTING
+	bool "Fine granularity task level IRQ time accounting"
+	default n
+	---help---
+	  Select this option to enable fine granularity task irq time
+	  accounting. This is done by reading a timestamp on each
+	  transitions between softirq and hardirq state, so there can be a
+	  small performance impact.
+
+	  If in doubt, say N here.
+
 source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
@@ -1148,6 +1104,9 @@
 config ARCH_PHYS_ADDR_T_64BIT
 	def_bool X86_64 || X86_PAE
 
+config ARCH_DMA_ADDR_T_64BIT
+	def_bool X86_64 || HIGHMEM64G
+
 config DIRECT_GBPAGES
 	bool "Enable 1GB pages for kernel pagetables" if EMBEDDED
 	default y
@@ -1326,25 +1285,34 @@
 	  Set whether the default state of memory_corruption_check is
 	  on or off.
 
-config X86_RESERVE_LOW_64K
-	bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
-	default y
+config X86_RESERVE_LOW
+	int "Amount of low memory, in kilobytes, to reserve for the BIOS"
+	default 64
+	range 4 640
 	---help---
-	  Reserve the first 64K of physical RAM on BIOSes that are known
-	  to potentially corrupt that memory range. A numbers of BIOSes are
-	  known to utilize this area during suspend/resume, so it must not
-	  be used by the kernel.
+	  Specify the amount of low memory to reserve for the BIOS.
 
-	  Set this to N if you are absolutely sure that you trust the BIOS
-	  to get all its memory reservations and usages right.
+	  The first page contains BIOS data structures that the kernel
+	  must not use, so that page must always be reserved.
 
-	  If you have doubts about the BIOS (e.g. suspend/resume does not
-	  work or there's kernel crashes after certain hardware hotplug
-	  events) and it's not AMI or Phoenix, then you might want to enable
-	  X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
-	  corruption patterns.
+	  By default we reserve the first 64K of physical RAM, as a
+	  number of BIOSes are known to corrupt that memory range
+	  during events such as suspend/resume or monitor cable
+	  insertion, so it must not be used by the kernel.
 
-	  Say Y if unsure.
+	  You can set this to 4 if you are absolutely sure that you
+	  trust the BIOS to get all its memory reservations and usages
+	  right.  If you know your BIOS have problems beyond the
+	  default 64K area, you can set this to 640 to avoid using the
+	  entire low memory range.
+
+	  If you have doubts about the BIOS (e.g. suspend/resume does
+	  not work or there's kernel crashes after certain hardware
+	  hotplug events) then you might want to enable
+	  X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check
+	  typical corruption patterns.
+
+	  Leave this to the default value of 64 if you are unsure.
 
 config MATH_EMULATION
 	bool
@@ -1900,7 +1868,7 @@
 	bool "Direct"
 
 config PCI_GOOLPC
-	bool "OLPC"
+	bool "OLPC XO-1"
 	depends on OLPC
 
 config PCI_GOANY
@@ -1925,6 +1893,11 @@
 	def_bool y
 	depends on PCI && OLPC && (PCI_GOOLPC || PCI_GOANY)
 
+config PCI_XEN
+	def_bool y
+	depends on PCI && XEN
+	select SWIOTLB_XEN
+
 config PCI_DOMAINS
 	def_bool y
 	depends on PCI
@@ -2061,14 +2034,21 @@
 config OLPC
 	bool "One Laptop Per Child support"
 	select GPIOLIB
+	select OLPC_OPENFIRMWARE
 	---help---
 	  Add support for detecting the unique features of the OLPC
 	  XO hardware.
 
+config OLPC_XO1
+	tristate "OLPC XO-1 support"
+	depends on OLPC && PCI
+	---help---
+	  Add support for non-essential features of the OLPC XO-1 laptop.
+
 config OLPC_OPENFIRMWARE
 	bool "Support for OLPC's Open Firmware"
 	depends on !X86_64 && !X86_PAE
-	default y if OLPC
+	default n
 	help
 	  This option adds support for the implementation of Open Firmware
 	  that is used on the OLPC XO-1 Children's Machine.
@@ -2076,7 +2056,7 @@
 
 endif # X86_32
 
-config K8_NB
+config AMD_NB
 	def_bool y
 	depends on CPU_SUP_AMD && PCI
 
@@ -2125,6 +2105,10 @@
 	def_bool y
 	depends on X86_32
 
+config HAVE_TEXT_POKE_SMP
+	bool
+	select STOP_MACHINE if SMP
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
diff -druN linux-libre-2.6.36-gnu/arch/x86/Kconfig.debug linux-libre-2.6.37-gnu/arch/x86/Kconfig.debug
--- linux-libre-2.6.36-gnu/arch/x86/Kconfig.debug	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/Kconfig.debug	2011-01-04 19:50:19.000000000 -0500
@@ -43,6 +43,10 @@
 	  with klogd/syslogd or the X server. You should normally N here,
 	  unless you want to debug such a crash.
 
+config EARLY_PRINTK_MRST
+	bool "Early printk for MRST platform support"
+	depends on EARLY_PRINTK && X86_MRST
+
 config EARLY_PRINTK_DBGP
 	bool "Early printk via EHCI debug port"
 	depends on EARLY_PRINTK && PCI
@@ -121,16 +125,6 @@
 	  and the software setup of this feature.
 	  If in doubt, say "N"
 
-config 4KSTACKS
-	bool "Use 4Kb for kernel stacks instead of 8Kb"
-	depends on X86_32
-	---help---
-	  If you say Y here the kernel will use a 4Kb stacksize for the
-	  kernel stack attached to each process/thread. This facilitates
-	  running more threads on a system and also reduces the pressure
-	  on the VM subsystem for higher order allocations. This option
-	  will also use IRQ stacks to compensate for the reduced stackspace.
-
 config DOUBLEFAULT
 	default y
 	bool "Enable doublefault exception handler" if EMBEDDED
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/boot.c linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/boot.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/boot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/boot.c	2011-01-04 19:50:19.000000000 -0500
@@ -513,35 +513,62 @@
 	return 0;
 }
 
-/*
- * success: return IRQ number (>=0)
- * failure: return < 0
- */
-int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
+				 int trigger, int polarity)
 {
-	unsigned int irq;
-	unsigned int plat_gsi = gsi;
-
 #ifdef CONFIG_PCI
 	/*
 	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
 	 */
-	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
-		if (trigger == ACPI_LEVEL_SENSITIVE)
-			eisa_set_level_irq(gsi);
-	}
+	if (trigger == ACPI_LEVEL_SENSITIVE)
+		eisa_set_level_irq(gsi);
 #endif
 
+	return gsi;
+}
+
+static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
+				    int trigger, int polarity)
+{
 #ifdef CONFIG_X86_IO_APIC
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
-		plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
-	}
+	gsi = mp_register_gsi(dev, gsi, trigger, polarity);
 #endif
+
+	return gsi;
+}
+
+int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
+			   int trigger, int polarity) = acpi_register_gsi_pic;
+
+/*
+ * success: return IRQ number (>=0)
+ * failure: return < 0
+ */
+int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
+{
+	unsigned int irq;
+	unsigned int plat_gsi = gsi;
+
+	plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
 	irq = gsi_to_irq(plat_gsi);
 
 	return irq;
 }
 
+void __init acpi_set_irq_model_pic(void)
+{
+	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
+	__acpi_register_gsi = acpi_register_gsi_pic;
+	acpi_ioapic = 0;
+}
+
+void __init acpi_set_irq_model_ioapic(void)
+{
+	acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+	__acpi_register_gsi = acpi_register_gsi_ioapic;
+	acpi_ioapic = 1;
+}
+
 /*
  *  ACPI based hotplug support for CPU
  */
@@ -1259,8 +1286,7 @@
 			 */
 			error = acpi_parse_madt_ioapic_entries();
 			if (!error) {
-				acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
-				acpi_ioapic = 1;
+				acpi_set_irq_model_ioapic();
 
 				smp_found_config = 1;
 			}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/cstate.c linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/cstate.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/cstate.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/cstate.c	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 
 #include <acpi/processor.h>
 #include <asm/acpi.h>
+#include <asm/mwait.h>
 
 /*
  * Initialize bm_flags based on the CPU cache properties
@@ -65,16 +66,6 @@
 
 static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
 
-#define MWAIT_SUBSTATE_MASK	(0xf)
-#define MWAIT_CSTATE_MASK	(0xf)
-#define MWAIT_SUBSTATE_SIZE	(4)
-
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK	(0x2)
-
-#define MWAIT_ECX_INTERRUPT_BREAK	(0x1)
-
 #define NATIVE_CSTATE_BEYOND_HALT	(2)
 
 static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/sleep.c linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/sleep.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/acpi/sleep.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/acpi/sleep.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,11 +7,16 @@
 
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/dmi.h>
 #include <linux/cpumask.h>
 #include <asm/segment.h>
 #include <asm/desc.h>
 
+#ifdef CONFIG_X86_32
+#include <asm/pgtable.h>
+#endif
+
 #include "realmode/wakeup.h"
 #include "sleep.h"
 
@@ -90,7 +95,7 @@
 
 #ifndef CONFIG_64BIT
 	header->pmode_entry = (u32)&wakeup_pmode_return;
-	header->pmode_cr3 = (u32)(swsusp_pg_dir - __PAGE_OFFSET);
+	header->pmode_cr3 = (u32)__pa(&initial_page_table);
 	saved_magic = 0x12345678;
 #else /* CONFIG_64BIT */
 	header->trampoline_segment = setup_trampoline() >> 4;
@@ -125,7 +130,7 @@
  */
 void __init acpi_reserve_wakeup_memory(void)
 {
-	unsigned long mem;
+	phys_addr_t mem;
 
 	if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
 		printk(KERN_ERR
@@ -133,15 +138,15 @@
 		return;
 	}
 
-	mem = find_e820_area(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
+	mem = memblock_find_in_range(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
 
-	if (mem == -1L) {
+	if (mem == MEMBLOCK_ERROR) {
 		printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
 		return;
 	}
 	acpi_realmode = (unsigned long) phys_to_virt(mem);
 	acpi_wakeup_address = mem;
-	reserve_early(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
+	memblock_x86_reserve_range(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
 }
 
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/alternative.c linux-libre-2.6.37-gnu/arch/x86/kernel/alternative.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/alternative.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/alternative.c	2011-01-04 19:50:19.000000000 -0500
@@ -195,7 +195,7 @@
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
-static void *text_poke_early(void *addr, const void *opcode, size_t len);
+void *text_poke_early(void *addr, const void *opcode, size_t len);
 
 /* Replace instructions with better alternatives for this CPU type.
    This runs before SMP is initialized to avoid SMP problems with
@@ -522,7 +522,7 @@
  * instructions. And on the local CPU you need to be protected again NMI or MCE
  * handlers seeing an inconsistent instruction while you patch.
  */
-static void *__init_or_module text_poke_early(void *addr, const void *opcode,
+void *__init_or_module text_poke_early(void *addr, const void *opcode,
 					      size_t len)
 {
 	unsigned long flags;
@@ -637,7 +637,33 @@
 	tpp.len = len;
 	atomic_set(&stop_machine_first, 1);
 	wrote_text = 0;
-	stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
+	/* Use __stop_machine() because the caller already got online_cpus. */
+	__stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
 	return addr;
 }
 
+#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
+
+#ifdef CONFIG_X86_64
+unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 };
+#else
+unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
+#endif
+
+void __init arch_init_ideal_nop5(void)
+{
+	/*
+	 * There is no good nop for all x86 archs.  This selection
+	 * algorithm should be unified with the one in find_nop_table(),
+	 * but this should be good enough for now.
+	 *
+	 * For cases other than the ones below, use the safe (as in
+	 * always functional) defaults above.
+	 */
+#ifdef CONFIG_X86_64
+	/* Don't use these on 32 bits due to broken virtualizers */
+	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+		memcpy(ideal_nop5, p6_nops[5], 5);
+#endif
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/amd_iommu.c linux-libre-2.6.37-gnu/arch/x86/kernel/amd_iommu.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/amd_iommu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/amd_iommu.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/amd_iommu_init.c linux-libre-2.6.37-gnu/arch/x86/kernel/amd_iommu_init.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/amd_iommu_init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/amd_iommu_init.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
@@ -31,7 +31,7 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/x86_init.h>
-
+#include <asm/iommu_table.h>
 /*
  * definitions for the ACPI scanning code
  */
@@ -194,6 +194,39 @@
 	return 1UL << shift;
 }
 
+/* Access to l1 and l2 indexed register spaces */
+
+static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
+{
+	u32 val;
+
+	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
+	pci_read_config_dword(iommu->dev, 0xfc, &val);
+	return val;
+}
+
+static void iommu_write_l1(struct amd_iommu *iommu, u16 l1, u8 address, u32 val)
+{
+	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16 | 1 << 31));
+	pci_write_config_dword(iommu->dev, 0xfc, val);
+	pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
+}
+
+static u32 iommu_read_l2(struct amd_iommu *iommu, u8 address)
+{
+	u32 val;
+
+	pci_write_config_dword(iommu->dev, 0xf0, address);
+	pci_read_config_dword(iommu->dev, 0xf4, &val);
+	return val;
+}
+
+static void iommu_write_l2(struct amd_iommu *iommu, u8 address, u32 val)
+{
+	pci_write_config_dword(iommu->dev, 0xf0, (address | 1 << 8));
+	pci_write_config_dword(iommu->dev, 0xf4, val);
+}
+
 /****************************************************************************
  *
  * AMD IOMMU MMIO register space handling functions
@@ -619,6 +652,7 @@
 {
 	int cap_ptr = iommu->cap_ptr;
 	u32 range, misc;
+	int i, j;
 
 	pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
 			      &iommu->cap);
@@ -633,12 +667,29 @@
 					MMIO_GET_LD(range));
 	iommu->evt_msi_num = MMIO_MSI_NUM(misc);
 
-	if (is_rd890_iommu(iommu->dev)) {
-		pci_read_config_dword(iommu->dev, 0xf0, &iommu->cache_cfg[0]);
-		pci_read_config_dword(iommu->dev, 0xf4, &iommu->cache_cfg[1]);
-		pci_read_config_dword(iommu->dev, 0xf8, &iommu->cache_cfg[2]);
-		pci_read_config_dword(iommu->dev, 0xfc, &iommu->cache_cfg[3]);
-	}
+	if (!is_rd890_iommu(iommu->dev))
+		return;
+
+	/*
+	 * Some rd890 systems may not be fully reconfigured by the BIOS, so
+	 * it's necessary for us to store this information so it can be
+	 * reprogrammed on resume
+	 */
+
+	pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4,
+			      &iommu->stored_addr_lo);
+	pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8,
+			      &iommu->stored_addr_hi);
+
+	/* Low bit locks writes to configuration space */
+	iommu->stored_addr_lo &= ~1;
+
+	for (i = 0; i < 6; i++)
+		for (j = 0; j < 0x12; j++)
+			iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j);
+
+	for (i = 0; i < 0x83; i++)
+		iommu->stored_l2[i] = iommu_read_l2(iommu, i);
 }
 
 /*
@@ -1127,14 +1178,53 @@
 	iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
 }
 
-static void iommu_apply_quirks(struct amd_iommu *iommu)
+static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
 {
-	if (is_rd890_iommu(iommu->dev)) {
-		pci_write_config_dword(iommu->dev, 0xf0, iommu->cache_cfg[0]);
-		pci_write_config_dword(iommu->dev, 0xf4, iommu->cache_cfg[1]);
-		pci_write_config_dword(iommu->dev, 0xf8, iommu->cache_cfg[2]);
-		pci_write_config_dword(iommu->dev, 0xfc, iommu->cache_cfg[3]);
-	}
+	int i, j;
+	u32 ioc_feature_control;
+	struct pci_dev *pdev = NULL;
+
+	/* RD890 BIOSes may not have completely reconfigured the iommu */
+	if (!is_rd890_iommu(iommu->dev))
+		return;
+
+	/*
+	 * First, we need to ensure that the iommu is enabled. This is
+	 * controlled by a register in the northbridge
+	 */
+	pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0));
+
+	if (!pdev)
+		return;
+
+	/* Select Northbridge indirect register 0x75 and enable writing */
+	pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7));
+	pci_read_config_dword(pdev, 0x64, &ioc_feature_control);
+
+	/* Enable the iommu */
+	if (!(ioc_feature_control & 0x1))
+		pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1);
+
+	pci_dev_put(pdev);
+
+	/* Restore the iommu BAR */
+	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
+			       iommu->stored_addr_lo);
+	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 8,
+			       iommu->stored_addr_hi);
+
+	/* Restore the l1 indirect regs for each of the 6 l1s */
+	for (i = 0; i < 6; i++)
+		for (j = 0; j < 0x12; j++)
+			iommu_write_l1(iommu, i, j, iommu->stored_l1[i][j]);
+
+	/* Restore the l2 indirect regs */
+	for (i = 0; i < 0x83; i++)
+		iommu_write_l2(iommu, i, iommu->stored_l2[i]);
+
+	/* Lock PCI setup registers */
+	pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
+			       iommu->stored_addr_lo | 1);
 }
 
 /*
@@ -1147,7 +1237,6 @@
 
 	for_each_iommu(iommu) {
 		iommu_disable(iommu);
-		iommu_apply_quirks(iommu);
 		iommu_init_flags(iommu);
 		iommu_set_device_table(iommu);
 		iommu_enable_command_buffer(iommu);
@@ -1173,6 +1262,11 @@
 
 static int amd_iommu_resume(struct sys_device *dev)
 {
+	struct amd_iommu *iommu;
+
+	for_each_iommu(iommu)
+		iommu_apply_resume_quirks(iommu);
+
 	/* re-load the hardware */
 	enable_iommus();
 
@@ -1405,13 +1499,13 @@
 	return 0;
 }
 
-void __init amd_iommu_detect(void)
+int __init amd_iommu_detect(void)
 {
 	if (no_iommu || (iommu_detected && !gart_iommu_aperture))
-		return;
+		return -ENODEV;
 
 	if (amd_iommu_disabled)
-		return;
+		return -ENODEV;
 
 	if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) {
 		iommu_detected = 1;
@@ -1420,7 +1514,9 @@
 
 		/* Make sure ACS will be enabled */
 		pci_request_acs();
+		return 1;
 	}
+	return -ENODEV;
 }
 
 /****************************************************************************
@@ -1451,3 +1547,8 @@
 
 __setup("amd_iommu_dump", parse_amd_iommu_dump);
 __setup("amd_iommu=", parse_amd_iommu_options);
+
+IOMMU_INIT_FINISH(amd_iommu_detect,
+		  gart_iommu_hole_init,
+		  0,
+		  0);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/amd_nb.c linux-libre-2.6.37-gnu/arch/x86/kernel/amd_nb.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/amd_nb.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/amd_nb.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,147 @@
+/*
+ * Shared support code for AMD K8 northbridges and derivates.
+ * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/amd_nb.h>
+
+static u32 *flush_words;
+
+struct pci_device_id k8_nb_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
+	{}
+};
+EXPORT_SYMBOL(k8_nb_ids);
+
+struct k8_northbridge_info k8_northbridges;
+EXPORT_SYMBOL(k8_northbridges);
+
+static struct pci_dev *next_k8_northbridge(struct pci_dev *dev)
+{
+	do {
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+		if (!dev)
+			break;
+	} while (!pci_match_id(&k8_nb_ids[0], dev));
+	return dev;
+}
+
+int cache_k8_northbridges(void)
+{
+	int i;
+	struct pci_dev *dev;
+
+	if (k8_northbridges.num)
+		return 0;
+
+	dev = NULL;
+	while ((dev = next_k8_northbridge(dev)) != NULL)
+		k8_northbridges.num++;
+
+	/* some CPU families (e.g. family 0x11) do not support GART */
+	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
+	    boot_cpu_data.x86 == 0x15)
+		k8_northbridges.gart_supported = 1;
+
+	k8_northbridges.nb_misc = kmalloc((k8_northbridges.num + 1) *
+					  sizeof(void *), GFP_KERNEL);
+	if (!k8_northbridges.nb_misc)
+		return -ENOMEM;
+
+	if (!k8_northbridges.num) {
+		k8_northbridges.nb_misc[0] = NULL;
+		return 0;
+	}
+
+	if (k8_northbridges.gart_supported) {
+		flush_words = kmalloc(k8_northbridges.num * sizeof(u32),
+				      GFP_KERNEL);
+		if (!flush_words) {
+			kfree(k8_northbridges.nb_misc);
+			return -ENOMEM;
+		}
+	}
+
+	dev = NULL;
+	i = 0;
+	while ((dev = next_k8_northbridge(dev)) != NULL) {
+		k8_northbridges.nb_misc[i] = dev;
+		if (k8_northbridges.gart_supported)
+			pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
+	}
+	k8_northbridges.nb_misc[i] = NULL;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cache_k8_northbridges);
+
+/* Ignores subdevice/subvendor but as far as I can figure out
+   they're useless anyways */
+int __init early_is_k8_nb(u32 device)
+{
+	struct pci_device_id *id;
+	u32 vendor = device & 0xffff;
+	device >>= 16;
+	for (id = k8_nb_ids; id->vendor; id++)
+		if (vendor == id->vendor && device == id->device)
+			return 1;
+	return 0;
+}
+
+void k8_flush_garts(void)
+{
+	int flushed, i;
+	unsigned long flags;
+	static DEFINE_SPINLOCK(gart_lock);
+
+	if (!k8_northbridges.gart_supported)
+		return;
+
+	/* Avoid races between AGP and IOMMU. In theory it's not needed
+	   but I'm not sure if the hardware won't lose flush requests
+	   when another is pending. This whole thing is so expensive anyways
+	   that it doesn't matter to serialize more. -AK */
+	spin_lock_irqsave(&gart_lock, flags);
+	flushed = 0;
+	for (i = 0; i < k8_northbridges.num; i++) {
+		pci_write_config_dword(k8_northbridges.nb_misc[i], 0x9c,
+				       flush_words[i]|1);
+		flushed++;
+	}
+	for (i = 0; i < k8_northbridges.num; i++) {
+		u32 w;
+		/* Make sure the hardware actually executed the flush*/
+		for (;;) {
+			pci_read_config_dword(k8_northbridges.nb_misc[i],
+					      0x9c, &w);
+			if (!(w & 1))
+				break;
+			cpu_relax();
+		}
+	}
+	spin_unlock_irqrestore(&gart_lock, flags);
+	if (!flushed)
+		printk("nothing to flush?\n");
+}
+EXPORT_SYMBOL_GPL(k8_flush_garts);
+
+static __init int init_k8_nbs(void)
+{
+	int err = 0;
+
+	err = cache_k8_northbridges();
+
+	if (err < 0)
+		printk(KERN_NOTICE "K8 NB: Cannot enumerate AMD northbridges.\n");
+
+	return err;
+}
+
+/* This has to go after the PCI subsystem */
+fs_initcall(init_k8_nbs);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apb_timer.c linux-libre-2.6.37-gnu/arch/x86/kernel/apb_timer.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apb_timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apb_timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -231,34 +231,6 @@
 	apbt_start_counter(phy_cs_timer_id);
 }
 
-/* Setup IRQ routing via IOAPIC */
-#ifdef CONFIG_SMP
-static void apbt_setup_irq(struct apbt_dev *adev)
-{
-	struct irq_chip *chip;
-	struct irq_desc *desc;
-
-	/* timer0 irq has been setup early */
-	if (adev->irq == 0)
-		return;
-	desc = irq_to_desc(adev->irq);
-	chip = get_irq_chip(adev->irq);
-	disable_irq(adev->irq);
-	desc->status |= IRQ_MOVE_PCNTXT;
-	irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
-	/* APB timer irqs are set up as mp_irqs, timer is edge triggerred */
-	set_irq_chip_and_handler_name(adev->irq, chip, handle_edge_irq, "edge");
-	enable_irq(adev->irq);
-	if (system_state == SYSTEM_BOOTING)
-		if (request_irq(adev->irq, apbt_interrupt_handler,
-				IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
-				adev->name, adev)) {
-			printk(KERN_ERR "Failed request IRQ for APBT%d\n",
-			       adev->num);
-		}
-}
-#endif
-
 static void apbt_enable_int(int n)
 {
 	unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL);
@@ -334,6 +306,27 @@
 }
 
 #ifdef CONFIG_SMP
+
+static void apbt_setup_irq(struct apbt_dev *adev)
+{
+	/* timer0 irq has been setup early */
+	if (adev->irq == 0)
+		return;
+
+	if (system_state == SYSTEM_BOOTING) {
+		irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
+		/* APB timer irqs are set up as mp_irqs, timer is edge type */
+		__set_irq_handler(adev->irq, handle_edge_irq, 0, "edge");
+		if (request_irq(adev->irq, apbt_interrupt_handler,
+				IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
+				adev->name, adev)) {
+			printk(KERN_ERR "Failed request IRQ for APBT%d\n",
+			       adev->num);
+		}
+	} else
+		enable_irq(adev->irq);
+}
+
 /* Should be called with per cpu */
 void apbt_setup_secondary_clock(void)
 {
@@ -343,7 +336,7 @@
 
 	/* Don't register boot CPU clockevent */
 	cpu = smp_processor_id();
-	if (cpu == boot_cpu_id)
+	if (!cpu)
 		return;
 	/*
 	 * We need to calculate the scaled math multiplication factor for
@@ -389,16 +382,17 @@
 
 	switch (action & 0xf) {
 	case CPU_DEAD:
+		disable_irq(adev->irq);
 		apbt_disable_int(cpu);
-		if (system_state == SYSTEM_RUNNING)
+		if (system_state == SYSTEM_RUNNING) {
 			pr_debug("skipping APBT CPU %lu offline\n", cpu);
-		else if (adev) {
+		} else if (adev) {
 			pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
 			free_irq(adev->irq, adev);
 		}
 		break;
 	default:
-		pr_debug(KERN_INFO "APBT notified %lu, no action\n", action);
+		pr_debug("APBT notified %lu, no action\n", action);
 	}
 	return NOTIFY_OK;
 }
@@ -552,7 +546,7 @@
 		pr_debug("APB CS going back %lx:%lx:%lx ",
 			 t2, last_read, t2 - last_read);
 bad_count_x3:
-		pr_debug(KERN_INFO "tripple check enforced\n");
+		pr_debug("triple check enforced\n");
 		t0 = apbt_readl(phy_cs_timer_id,
 				APBTMR_N_CURRENT_VALUE);
 		udelay(1);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/aperture_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/aperture_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/aperture_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/aperture_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,7 @@
 #include <asm/gart.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/x86_init.h>
 
 int gart_iommu_aperture;
@@ -307,7 +307,7 @@
 				continue;
 
 			ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
-			aper_enabled = ctl & AMD64_GARTEN;
+			aper_enabled = ctl & GARTEN;
 			aper_order = (ctl >> 1) & 7;
 			aper_size = (32 * 1024 * 1024) << aper_order;
 			aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
@@ -362,7 +362,7 @@
 				continue;
 
 			ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
-			ctl &= ~AMD64_GARTEN;
+			ctl &= ~GARTEN;
 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
 		}
 	}
@@ -371,7 +371,7 @@
 
 static int __initdata printed_gart_size_msg;
 
-void __init gart_iommu_hole_init(void)
+int __init gart_iommu_hole_init(void)
 {
 	u32 agp_aper_base = 0, agp_aper_order = 0;
 	u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
@@ -381,7 +381,7 @@
 
 	if (gart_iommu_aperture_disabled || !fix_aperture ||
 	    !early_pci_allowed())
-		return;
+		return -ENODEV;
 
 	printk(KERN_INFO  "Checking aperture...\n");
 
@@ -463,8 +463,9 @@
 			unsigned long n = (32 * 1024 * 1024) << last_aper_order;
 
 			insert_aperture_resource((u32)last_aper_base, n);
+			return 1;
 		}
-		return;
+		return 0;
 	}
 
 	if (!fallback_aper_force) {
@@ -500,13 +501,18 @@
 			panic("Not enough memory for aperture");
 		}
 	} else {
-		return;
+		return 0;
 	}
 
 	/* Fix up the north bridges */
 	for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
-		int bus;
-		int dev_base, dev_limit;
+		int bus, dev_base, dev_limit;
+
+		/*
+		 * Don't enable translation yet but enable GART IO and CPU
+		 * accesses and set DISTLBWALKPRB since GART table memory is UC.
+		 */
+		u32 ctl = DISTLBWALKPRB | aper_order << 1;
 
 		bus = bus_dev_ranges[i].bus;
 		dev_base = bus_dev_ranges[i].dev_base;
@@ -515,13 +521,12 @@
 			if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
 				continue;
 
-			/* Don't enable translation yet. That is done later.
-			   Assume this BIOS didn't initialise the GART so
-			   just overwrite all previous bits */
-			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1);
+			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
 		}
 	}
 
 	set_up_gart_resume(aper_order, aper_alloc);
+
+	return 1;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/apic.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/apic.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/apic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/apic.c	2011-01-04 19:50:19.000000000 -0500
@@ -370,38 +370,87 @@
 }
 
 /*
- * Setup extended LVT, AMD specific (K8, family 10h)
+ * Setup extended LVT, AMD specific
  *
- * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
- * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ * Software should use the LVT offsets the BIOS provides.  The offsets
+ * are determined by the subsystems using it like those for MCE
+ * threshold or IBS.  On K8 only offset 0 (APIC500) and MCE interrupts
+ * are supported. Beginning with family 10h at least 4 offsets are
+ * available.
  *
- * If mask=1, the LVT entry does not generate interrupts while mask=0
- * enables the vector. See also the BKDGs.
+ * Since the offsets must be consistent for all cores, we keep track
+ * of the LVT offsets in software and reserve the offset for the same
+ * vector also to be used on other cores. An offset is freed by
+ * setting the entry to APIC_EILVT_MASKED.
+ *
+ * If the BIOS is right, there should be no conflicts. Otherwise a
+ * "[Firmware Bug]: ..." error message is generated. However, if
+ * software does not properly determines the offsets, it is not
+ * necessarily a BIOS bug.
  */
 
-#define APIC_EILVT_LVTOFF_MCE 0
-#define APIC_EILVT_LVTOFF_IBS 1
+static atomic_t eilvt_offsets[APIC_EILVT_NR_MAX];
 
-static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
+static inline int eilvt_entry_is_changeable(unsigned int old, unsigned int new)
 {
-	unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0);
-	unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
-
-	apic_write(reg, v);
+	return (old & APIC_EILVT_MASKED)
+		|| (new == APIC_EILVT_MASKED)
+		|| ((new & ~APIC_EILVT_MASKED) == old);
 }
 
-u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
+static unsigned int reserve_eilvt_offset(int offset, unsigned int new)
 {
-	setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
-	return APIC_EILVT_LVTOFF_MCE;
+	unsigned int rsvd;			/* 0: uninitialized */
+
+	if (offset >= APIC_EILVT_NR_MAX)
+		return ~0;
+
+	rsvd = atomic_read(&eilvt_offsets[offset]) & ~APIC_EILVT_MASKED;
+	do {
+		if (rsvd &&
+		    !eilvt_entry_is_changeable(rsvd, new))
+			/* may not change if vectors are different */
+			return rsvd;
+		rsvd = atomic_cmpxchg(&eilvt_offsets[offset], rsvd, new);
+	} while (rsvd != new);
+
+	return new;
 }
 
-u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
+/*
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
+ */
+
+int setup_APIC_eilvt(u8 offset, u8 vector, u8 msg_type, u8 mask)
 {
-	setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
-	return APIC_EILVT_LVTOFF_IBS;
+	unsigned long reg = APIC_EILVTn(offset);
+	unsigned int new, old, reserved;
+
+	new = (mask << 16) | (msg_type << 8) | vector;
+	old = apic_read(reg);
+	reserved = reserve_eilvt_offset(offset, new);
+
+	if (reserved != new) {
+		pr_err(FW_BUG "cpu %d, try to setup vector 0x%x, but "
+		       "vector 0x%x was already reserved by another core, "
+		       "APIC%lX=0x%x\n",
+		       smp_processor_id(), new, reserved, reg, old);
+		return -EINVAL;
+	}
+
+	if (!eilvt_entry_is_changeable(old, new)) {
+		pr_err(FW_BUG "cpu %d, try to setup vector 0x%x but "
+		       "register already in use, APIC%lX=0x%x\n",
+		       smp_processor_id(), new, reg, old);
+		return -EBUSY;
+	}
+
+	apic_write(reg, new);
+
+	return 0;
 }
-EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt);
 
 /*
  * Program the next event, relative to now
@@ -1340,6 +1389,14 @@
 
 	setup_apic_nmi_watchdog(NULL);
 	apic_pm_activate();
+
+	/*
+	 * Now that local APIC setup is completed for BP, configure the fault
+	 * handling for interrupt remapping.
+	 */
+	if (!smp_processor_id() && intr_remapping_enabled)
+		enable_drhd_fault_handling();
+
 }
 
 #ifdef CONFIG_X86_X2APIC
@@ -1665,10 +1722,7 @@
 	}
 #endif
 
-#ifndef CONFIG_SMP
-	enable_IR_x2apic();
 	default_setup_apic_routing();
-#endif
 
 	verify_local_APIC();
 	connect_bsp_APIC();
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/hw_nmi.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/hw_nmi.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/hw_nmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/hw_nmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,15 +17,16 @@
 #include <linux/nmi.h>
 #include <linux/module.h>
 
-/* For reliability, we're prepared to waste bits here. */
-static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
-
 u64 hw_nmi_get_sample_period(void)
 {
 	return (u64)(cpu_khz) * 1000 * 60;
 }
 
 #ifdef ARCH_HAS_NMI_WATCHDOG
+
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
 void arch_trigger_all_cpu_backtrace(void)
 {
 	int i;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/io_apic.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/io_apic.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/io_apic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/io_apic.c	2011-01-04 19:50:19.000000000 -0500
@@ -131,13 +131,9 @@
 	struct irq_pin_list *next;
 };
 
-static struct irq_pin_list *get_one_free_irq_2_pin(int node)
+static struct irq_pin_list *alloc_irq_pin_list(int node)
 {
-	struct irq_pin_list *pin;
-
-	pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
-
-	return pin;
+	return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
 }
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
@@ -150,10 +146,7 @@
 int __init arch_early_irq_init(void)
 {
 	struct irq_cfg *cfg;
-	struct irq_desc *desc;
-	int count;
-	int node;
-	int i;
+	int count, node, i;
 
 	if (!legacy_pic->nr_legacy_irqs) {
 		nr_irqs_gsi = 0;
@@ -162,13 +155,15 @@
 
 	cfg = irq_cfgx;
 	count = ARRAY_SIZE(irq_cfgx);
-	node= cpu_to_node(boot_cpu_id);
+	node = cpu_to_node(0);
+
+	/* Make sure the legacy interrupts are marked in the bitmap */
+	irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
 
 	for (i = 0; i < count; i++) {
-		desc = irq_to_desc(i);
-		desc->chip_data = &cfg[i];
-		zalloc_cpumask_var_node(&cfg[i].domain, GFP_NOWAIT, node);
-		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_NOWAIT, node);
+		set_irq_chip_data(i, &cfg[i]);
+		zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
+		zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
 		/*
 		 * For legacy IRQ's, start with assigning irq0 to irq15 to
 		 * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0.
@@ -183,170 +178,88 @@
 }
 
 #ifdef CONFIG_SPARSE_IRQ
-struct irq_cfg *irq_cfg(unsigned int irq)
+static struct irq_cfg *irq_cfg(unsigned int irq)
 {
-	struct irq_cfg *cfg = NULL;
-	struct irq_desc *desc;
-
-	desc = irq_to_desc(irq);
-	if (desc)
-		cfg = desc->chip_data;
-
-	return cfg;
+	return get_irq_chip_data(irq);
 }
 
-static struct irq_cfg *get_one_free_irq_cfg(int node)
+static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 {
 	struct irq_cfg *cfg;
 
-	cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
-	if (cfg) {
-		if (!zalloc_cpumask_var_node(&cfg->domain, GFP_ATOMIC, node)) {
-			kfree(cfg);
-			cfg = NULL;
-		} else if (!zalloc_cpumask_var_node(&cfg->old_domain,
-							  GFP_ATOMIC, node)) {
-			free_cpumask_var(cfg->domain);
-			kfree(cfg);
-			cfg = NULL;
-		}
-	}
-
+	cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
+	if (!cfg)
+		return NULL;
+	if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
+		goto out_cfg;
+	if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
+		goto out_domain;
 	return cfg;
+out_domain:
+	free_cpumask_var(cfg->domain);
+out_cfg:
+	kfree(cfg);
+	return NULL;
 }
 
-int arch_init_chip_data(struct irq_desc *desc, int node)
-{
-	struct irq_cfg *cfg;
-
-	cfg = desc->chip_data;
-	if (!cfg) {
-		desc->chip_data = get_one_free_irq_cfg(node);
-		if (!desc->chip_data) {
-			printk(KERN_ERR "can not alloc irq_cfg\n");
-			BUG_ON(1);
-		}
-	}
-
-	return 0;
-}
-
-/* for move_irq_desc */
-static void
-init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node)
+static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
 {
-	struct irq_pin_list *old_entry, *head, *tail, *entry;
-
-	cfg->irq_2_pin = NULL;
-	old_entry = old_cfg->irq_2_pin;
-	if (!old_entry)
-		return;
-
-	entry = get_one_free_irq_2_pin(node);
-	if (!entry)
+	if (!cfg)
 		return;
+	set_irq_chip_data(at, NULL);
+	free_cpumask_var(cfg->domain);
+	free_cpumask_var(cfg->old_domain);
+	kfree(cfg);
+}
 
-	entry->apic	= old_entry->apic;
-	entry->pin	= old_entry->pin;
-	head		= entry;
-	tail		= entry;
-	old_entry	= old_entry->next;
-	while (old_entry) {
-		entry = get_one_free_irq_2_pin(node);
-		if (!entry) {
-			entry = head;
-			while (entry) {
-				head = entry->next;
-				kfree(entry);
-				entry = head;
-			}
-			/* still use the old one */
-			return;
-		}
-		entry->apic	= old_entry->apic;
-		entry->pin	= old_entry->pin;
-		tail->next	= entry;
-		tail		= entry;
-		old_entry	= old_entry->next;
-	}
+#else
 
-	tail->next = NULL;
-	cfg->irq_2_pin = head;
+struct irq_cfg *irq_cfg(unsigned int irq)
+{
+	return irq < nr_irqs ? irq_cfgx + irq : NULL;
 }
 
-static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
+static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 {
-	struct irq_pin_list *entry, *next;
-
-	if (old_cfg->irq_2_pin == cfg->irq_2_pin)
-		return;
+	return irq_cfgx + irq;
+}
 
-	entry = old_cfg->irq_2_pin;
+static inline void free_irq_cfg(unsigned int at, struct irq_cfg *cfg) { }
 
-	while (entry) {
-		next = entry->next;
-		kfree(entry);
-		entry = next;
-	}
-	old_cfg->irq_2_pin = NULL;
-}
+#endif
 
-void arch_init_copy_chip_data(struct irq_desc *old_desc,
-				 struct irq_desc *desc, int node)
+static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
 {
+	int res = irq_alloc_desc_at(at, node);
 	struct irq_cfg *cfg;
-	struct irq_cfg *old_cfg;
-
-	cfg = get_one_free_irq_cfg(node);
-
-	if (!cfg)
-		return;
-
-	desc->chip_data = cfg;
-
-	old_cfg = old_desc->chip_data;
-
-	cfg->vector = old_cfg->vector;
-	cfg->move_in_progress = old_cfg->move_in_progress;
-	cpumask_copy(cfg->domain, old_cfg->domain);
-	cpumask_copy(cfg->old_domain, old_cfg->old_domain);
 
-	init_copy_irq_2_pin(old_cfg, cfg, node);
-}
+	if (res < 0) {
+		if (res != -EEXIST)
+			return NULL;
+		cfg = get_irq_chip_data(at);
+		if (cfg)
+			return cfg;
+	}
 
-static void free_irq_cfg(struct irq_cfg *cfg)
-{
-	free_cpumask_var(cfg->domain);
-	free_cpumask_var(cfg->old_domain);
-	kfree(cfg);
+	cfg = alloc_irq_cfg(at, node);
+	if (cfg)
+		set_irq_chip_data(at, cfg);
+	else
+		irq_free_desc(at);
+	return cfg;
 }
 
-void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
+static int alloc_irq_from(unsigned int from, int node)
 {
-	struct irq_cfg *old_cfg, *cfg;
-
-	old_cfg = old_desc->chip_data;
-	cfg = desc->chip_data;
-
-	if (old_cfg == cfg)
-		return;
-
-	if (old_cfg) {
-		free_irq_2_pin(old_cfg, cfg);
-		free_irq_cfg(old_cfg);
-		old_desc->chip_data = NULL;
-	}
+	return irq_alloc_desc_from(from, node);
 }
-/* end for move_irq_desc */
 
-#else
-struct irq_cfg *irq_cfg(unsigned int irq)
+static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
 {
-	return irq < nr_irqs ? irq_cfgx + irq : NULL;
+	free_irq_cfg(at, cfg);
+	irq_free_desc(at);
 }
 
-#endif
-
 struct io_apic {
 	unsigned int index;
 	unsigned int unused[3];
@@ -451,7 +364,7 @@
 	io_apic_write(apic, 0x10 + 2*pin, eu.w1);
 }
 
-void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
+static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
 {
 	unsigned long flags;
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
@@ -481,7 +394,7 @@
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
 static int
-add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
+__add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
 	struct irq_pin_list **last, *entry;
 
@@ -493,7 +406,7 @@
 		last = &entry->next;
 	}
 
-	entry = get_one_free_irq_2_pin(node);
+	entry = alloc_irq_pin_list(node);
 	if (!entry) {
 		printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
 				node, apic, pin);
@@ -508,7 +421,7 @@
 
 static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
-	if (add_pin_to_irq_node_nopanic(cfg, node, apic, pin))
+	if (__add_pin_to_irq_node(cfg, node, apic, pin))
 		panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
 }
 
@@ -571,11 +484,6 @@
 			     IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
 }
 
-static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
-{
-	io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
-}
-
 static void io_apic_sync(struct irq_pin_list *entry)
 {
 	/*
@@ -587,44 +495,37 @@
 	readl(&io_apic->data);
 }
 
-static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
+static void mask_ioapic(struct irq_cfg *cfg)
 {
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
+static void mask_ioapic_irq(struct irq_data *data)
 {
-	struct irq_cfg *cfg = desc->chip_data;
-	unsigned long flags;
-
-	BUG_ON(!cfg);
+	mask_ioapic(data->chip_data);
+}
 
-	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	__mask_IO_APIC_irq(cfg);
-	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+static void __unmask_ioapic(struct irq_cfg *cfg)
+{
+	io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
 }
 
-static void unmask_IO_APIC_irq_desc(struct irq_desc *desc)
+static void unmask_ioapic(struct irq_cfg *cfg)
 {
-	struct irq_cfg *cfg = desc->chip_data;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	__unmask_IO_APIC_irq(cfg);
+	__unmask_ioapic(cfg);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void mask_IO_APIC_irq(unsigned int irq)
-{
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	mask_IO_APIC_irq_desc(desc);
-}
-static void unmask_IO_APIC_irq(unsigned int irq)
+static void unmask_ioapic_irq(struct irq_data *data)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	unmask_IO_APIC_irq_desc(desc);
+	unmask_ioapic(data->chip_data);
 }
 
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
@@ -694,14 +595,14 @@
 	struct IO_APIC_route_entry **ioapic_entries;
 
 	ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-				GFP_ATOMIC);
+				GFP_KERNEL);
 	if (!ioapic_entries)
 		return 0;
 
 	for (apic = 0; apic < nr_ioapics; apic++) {
 		ioapic_entries[apic] =
 			kzalloc(sizeof(struct IO_APIC_route_entry) *
-				nr_ioapic_registers[apic], GFP_ATOMIC);
+				nr_ioapic_registers[apic], GFP_KERNEL);
 		if (!ioapic_entries[apic])
 			goto nomem;
 	}
@@ -1259,7 +1160,6 @@
 	/* Initialize vector_irq on a new cpu */
 	int irq, vector;
 	struct irq_cfg *cfg;
-	struct irq_desc *desc;
 
 	/*
 	 * vector_lock will make sure that we don't run into irq vector
@@ -1268,9 +1168,10 @@
 	 */
 	raw_spin_lock(&vector_lock);
 	/* Mark the inuse vectors */
-	for_each_irq_desc(irq, desc) {
-		cfg = desc->chip_data;
-
+	for_each_active_irq(irq) {
+		cfg = get_irq_chip_data(irq);
+		if (!cfg)
+			continue;
 		/*
 		 * If it is a legacy IRQ handled by the legacy PIC, this cpu
 		 * will be part of the irq_cfg's domain.
@@ -1327,17 +1228,17 @@
 }
 #endif
 
-static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long trigger)
+static void ioapic_register_intr(unsigned int irq, unsigned long trigger)
 {
 
 	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
 	    trigger == IOAPIC_LEVEL)
-		desc->status |= IRQ_LEVEL;
+		irq_set_status_flags(irq, IRQ_LEVEL);
 	else
-		desc->status &= ~IRQ_LEVEL;
+		irq_clear_status_flags(irq, IRQ_LEVEL);
 
-	if (irq_remapped(irq)) {
-		desc->status |= IRQ_MOVE_PCNTXT;
+	if (irq_remapped(get_irq_chip_data(irq))) {
+		irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
 		if (trigger)
 			set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
 						      handle_fasteoi_irq,
@@ -1358,10 +1259,10 @@
 					      handle_edge_irq, "edge");
 }
 
-int setup_ioapic_entry(int apic_id, int irq,
-		       struct IO_APIC_route_entry *entry,
-		       unsigned int destination, int trigger,
-		       int polarity, int vector, int pin)
+static int setup_ioapic_entry(int apic_id, int irq,
+			      struct IO_APIC_route_entry *entry,
+			      unsigned int destination, int trigger,
+			      int polarity, int vector, int pin)
 {
 	/*
 	 * add it to the IO-APIC irq-routing table:
@@ -1382,21 +1283,7 @@
 		if (index < 0)
 			panic("Failed to allocate IRTE for ioapic %d\n", apic_id);
 
-		memset(&irte, 0, sizeof(irte));
-
-		irte.present = 1;
-		irte.dst_mode = apic->irq_dest_mode;
-		/*
-		 * Trigger mode in the IRTE will always be edge, and the
-		 * actual level or edge trigger will be setup in the IO-APIC
-		 * RTE. This will help simplify level triggered irq migration.
-		 * For more details, see the comments above explainig IO-APIC
-		 * irq migration in the presence of interrupt-remapping.
-		 */
-		irte.trigger_mode = 0;
-		irte.dlvry_mode = apic->irq_delivery_mode;
-		irte.vector = vector;
-		irte.dest_id = IRTE_DEST(destination);
+		prepare_irte(&irte, vector, destination);
 
 		/* Set source-id of interrupt request */
 		set_ioapic_sid(&irte, apic_id);
@@ -1431,18 +1318,14 @@
 	return 0;
 }
 
-static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq_desc *desc,
-			      int trigger, int polarity)
+static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
+			     struct irq_cfg *cfg, int trigger, int polarity)
 {
-	struct irq_cfg *cfg;
 	struct IO_APIC_route_entry entry;
 	unsigned int dest;
 
 	if (!IO_APIC_IRQ(irq))
 		return;
-
-	cfg = desc->chip_data;
-
 	/*
 	 * For legacy irqs, cfg->domain starts with cpu 0 for legacy
 	 * controllers like 8259. Now that IO-APIC can handle this irq, update
@@ -1471,9 +1354,9 @@
 		return;
 	}
 
-	ioapic_register_intr(irq, desc, trigger);
+	ioapic_register_intr(irq, trigger);
 	if (irq < legacy_pic->nr_legacy_irqs)
-		legacy_pic->chip->mask(irq);
+		legacy_pic->mask(irq);
 
 	ioapic_write_entry(apic_id, pin, entry);
 }
@@ -1484,11 +1367,9 @@
 
 static void __init setup_IO_APIC_irqs(void)
 {
-	int apic_id, pin, idx, irq;
-	int notcon = 0;
-	struct irq_desc *desc;
+	int apic_id, pin, idx, irq, notcon = 0;
+	int node = cpu_to_node(0);
 	struct irq_cfg *cfg;
-	int node = cpu_to_node(boot_cpu_id);
 
 	apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
 
@@ -1525,19 +1406,17 @@
 				apic->multi_timer_check(apic_id, irq))
 			continue;
 
-		desc = irq_to_desc_alloc_node(irq, node);
-		if (!desc) {
-			printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+		cfg = alloc_irq_and_cfg_at(irq, node);
+		if (!cfg)
 			continue;
-		}
-		cfg = desc->chip_data;
+
 		add_pin_to_irq_node(cfg, node, apic_id, pin);
 		/*
 		 * don't mark it in pin_programmed, so later acpi could
 		 * set it correctly when irq < 16
 		 */
-		setup_IO_APIC_irq(apic_id, pin, irq, desc,
-				irq_trigger(idx), irq_polarity(idx));
+		setup_ioapic_irq(apic_id, pin, irq, cfg, irq_trigger(idx),
+				  irq_polarity(idx));
 	}
 
 	if (notcon)
@@ -1552,9 +1431,7 @@
  */
 void setup_IO_APIC_irq_extra(u32 gsi)
 {
-	int apic_id = 0, pin, idx, irq;
-	int node = cpu_to_node(boot_cpu_id);
-	struct irq_desc *desc;
+	int apic_id = 0, pin, idx, irq, node = cpu_to_node(0);
 	struct irq_cfg *cfg;
 
 	/*
@@ -1570,18 +1447,15 @@
 		return;
 
 	irq = pin_2_irq(idx, apic_id, pin);
-#ifdef CONFIG_SPARSE_IRQ
-	desc = irq_to_desc(irq);
-	if (desc)
+
+	/* Only handle the non legacy irqs on secondary ioapics */
+	if (apic_id == 0 || irq < NR_IRQS_LEGACY)
 		return;
-#endif
-	desc = irq_to_desc_alloc_node(irq, node);
-	if (!desc) {
-		printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+
+	cfg = alloc_irq_and_cfg_at(irq, node);
+	if (!cfg)
 		return;
-	}
 
-	cfg = desc->chip_data;
 	add_pin_to_irq_node(cfg, node, apic_id, pin);
 
 	if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
@@ -1591,7 +1465,7 @@
 	}
 	set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
 
-	setup_IO_APIC_irq(apic_id, pin, irq, desc,
+	setup_ioapic_irq(apic_id, pin, irq, cfg,
 			irq_trigger(idx), irq_polarity(idx));
 }
 
@@ -1642,7 +1516,6 @@
 	union IO_APIC_reg_03 reg_03;
 	unsigned long flags;
 	struct irq_cfg *cfg;
-	struct irq_desc *desc;
 	unsigned int irq;
 
 	printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
@@ -1729,10 +1602,10 @@
 	}
 	}
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
-	for_each_irq_desc(irq, desc) {
+	for_each_active_irq(irq) {
 		struct irq_pin_list *entry;
 
-		cfg = desc->chip_data;
+		cfg = get_irq_chip_data(irq);
 		if (!cfg)
 			continue;
 		entry = cfg->irq_2_pin;
@@ -2239,29 +2112,26 @@
  * an edge even if it isn't on the 8259A...
  */
 
-static unsigned int startup_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(struct irq_data *data)
 {
-	int was_pending = 0;
+	int was_pending = 0, irq = data->irq;
 	unsigned long flags;
-	struct irq_cfg *cfg;
 
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	if (irq < legacy_pic->nr_legacy_irqs) {
-		legacy_pic->chip->mask(irq);
+		legacy_pic->mask(irq);
 		if (legacy_pic->irq_pending(irq))
 			was_pending = 1;
 	}
-	cfg = irq_cfg(irq);
-	__unmask_IO_APIC_irq(cfg);
+	__unmask_ioapic(data->chip_data);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
 	return was_pending;
 }
 
-static int ioapic_retrigger_irq(unsigned int irq)
+static int ioapic_retrigger_irq(struct irq_data *data)
 {
-
-	struct irq_cfg *cfg = irq_cfg(irq);
+	struct irq_cfg *cfg = data->chip_data;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&vector_lock, flags);
@@ -2312,7 +2182,7 @@
 		 * With interrupt-remapping, destination information comes
 		 * from interrupt-remapping table entry.
 		 */
-		if (!irq_remapped(irq))
+		if (!irq_remapped(cfg))
 			io_apic_write(apic, 0x11 + pin*2, dest);
 		reg = io_apic_read(apic, 0x10 + pin*2);
 		reg &= ~IO_APIC_REDIR_VECTOR_MASK;
@@ -2322,65 +2192,46 @@
 }
 
 /*
- * Either sets desc->affinity to a valid value, and returns
+ * Either sets data->affinity to a valid value, and returns
  * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves desc->affinity untouched.
+ * leaves data->affinity untouched.
  */
-unsigned int
-set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask,
-		  unsigned int *dest_id)
+int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+			  unsigned int *dest_id)
 {
-	struct irq_cfg *cfg;
-	unsigned int irq;
+	struct irq_cfg *cfg = data->chip_data;
 
 	if (!cpumask_intersects(mask, cpu_online_mask))
 		return -1;
 
-	irq = desc->irq;
-	cfg = desc->chip_data;
-	if (assign_irq_vector(irq, cfg, mask))
+	if (assign_irq_vector(data->irq, data->chip_data, mask))
 		return -1;
 
-	cpumask_copy(desc->affinity, mask);
+	cpumask_copy(data->affinity, mask);
 
-	*dest_id = apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
+	*dest_id = apic->cpu_mask_to_apicid_and(mask, cfg->domain);
 	return 0;
 }
 
 static int
-set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
+ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		    bool force)
 {
-	struct irq_cfg *cfg;
+	unsigned int dest, irq = data->irq;
 	unsigned long flags;
-	unsigned int dest;
-	unsigned int irq;
-	int ret = -1;
-
-	irq = desc->irq;
-	cfg = desc->chip_data;
+	int ret;
 
 	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	ret = set_desc_affinity(desc, mask, &dest);
+	ret = __ioapic_set_affinity(data, mask, &dest);
 	if (!ret) {
 		/* Only the high 8 bits are valid. */
 		dest = SET_APIC_LOGICAL_ID(dest);
-		__target_IO_APIC_irq(irq, dest, cfg);
+		__target_IO_APIC_irq(irq, dest, data->chip_data);
 	}
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-
 	return ret;
 }
 
-static int
-set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
-{
-	struct irq_desc *desc;
-
-	desc = irq_to_desc(irq);
-
-	return set_ioapic_affinity_irq_desc(desc, mask);
-}
-
 #ifdef CONFIG_INTR_REMAP
 
 /*
@@ -2395,24 +2246,21 @@
  * the interrupt-remapping table entry.
  */
 static int
-migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
+ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		       bool force)
 {
-	struct irq_cfg *cfg;
+	struct irq_cfg *cfg = data->chip_data;
+	unsigned int dest, irq = data->irq;
 	struct irte irte;
-	unsigned int dest;
-	unsigned int irq;
-	int ret = -1;
 
 	if (!cpumask_intersects(mask, cpu_online_mask))
-		return ret;
+		return -EINVAL;
 
-	irq = desc->irq;
 	if (get_irte(irq, &irte))
-		return ret;
+		return -EBUSY;
 
-	cfg = desc->chip_data;
 	if (assign_irq_vector(irq, cfg, mask))
-		return ret;
+		return -EBUSY;
 
 	dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
 
@@ -2427,29 +2275,14 @@
 	if (cfg->move_in_progress)
 		send_cleanup_vector(cfg);
 
-	cpumask_copy(desc->affinity, mask);
-
+	cpumask_copy(data->affinity, mask);
 	return 0;
 }
 
-/*
- * Migrates the IRQ destination in the process context.
- */
-static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
-					    const struct cpumask *mask)
-{
-	return migrate_ioapic_irq_desc(desc, mask);
-}
-static int set_ir_ioapic_affinity_irq(unsigned int irq,
-				       const struct cpumask *mask)
-{
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	return set_ir_ioapic_affinity_irq_desc(desc, mask);
-}
 #else
-static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
-						   const struct cpumask *mask)
+static inline int
+ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		       bool force)
 {
 	return 0;
 }
@@ -2511,10 +2344,8 @@
 	irq_exit();
 }
 
-static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
+static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
 {
-	struct irq_desc *desc = *descp;
-	struct irq_cfg *cfg = desc->chip_data;
 	unsigned me;
 
 	if (likely(!cfg->move_in_progress))
@@ -2526,31 +2357,28 @@
 		send_cleanup_vector(cfg);
 }
 
-static void irq_complete_move(struct irq_desc **descp)
+static void irq_complete_move(struct irq_cfg *cfg)
 {
-	__irq_complete_move(descp, ~get_irq_regs()->orig_ax);
+	__irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
 }
 
 void irq_force_complete_move(int irq)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg = desc->chip_data;
+	struct irq_cfg *cfg = get_irq_chip_data(irq);
 
 	if (!cfg)
 		return;
 
-	__irq_complete_move(&desc, cfg->vector);
+	__irq_complete_move(cfg, cfg->vector);
 }
 #else
-static inline void irq_complete_move(struct irq_desc **descp) {}
+static inline void irq_complete_move(struct irq_cfg *cfg) { }
 #endif
 
-static void ack_apic_edge(unsigned int irq)
+static void ack_apic_edge(struct irq_data *data)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	irq_complete_move(&desc);
-	move_native_irq(irq);
+	irq_complete_move(data->chip_data);
+	move_native_irq(data->irq);
 	ack_APIC_irq();
 }
 
@@ -2572,10 +2400,12 @@
  * Otherwise, we simulate the EOI message manually by changing the trigger
  * mode to edge and then back to level, with RTE being masked during this.
 */
-static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
 {
 	struct irq_pin_list *entry;
+	unsigned long flags;
 
+	raw_spin_lock_irqsave(&ioapic_lock, flags);
 	for_each_irq_pin(entry, cfg->irq_2_pin) {
 		if (mp_ioapics[entry->apic].apicver >= 0x20) {
 			/*
@@ -2584,7 +2414,7 @@
 			 * intr-remapping table entry. Hence for the io-apic
 			 * EOI we use the pin number.
 			 */
-			if (irq_remapped(irq))
+			if (irq_remapped(cfg))
 				io_apic_eoi(entry->apic, entry->pin);
 			else
 				io_apic_eoi(entry->apic, cfg->vector);
@@ -2593,36 +2423,21 @@
 			__unmask_and_level_IO_APIC_irq(entry);
 		}
 	}
-}
-
-static void eoi_ioapic_irq(struct irq_desc *desc)
-{
-	struct irq_cfg *cfg;
-	unsigned long flags;
-	unsigned int irq;
-
-	irq = desc->irq;
-	cfg = desc->chip_data;
-
-	raw_spin_lock_irqsave(&ioapic_lock, flags);
-	__eoi_ioapic_irq(irq, cfg);
 	raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void ack_apic_level(unsigned int irq)
+static void ack_apic_level(struct irq_data *data)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
+	struct irq_cfg *cfg = data->chip_data;
+	int i, do_unmask_irq = 0, irq = data->irq;
 	unsigned long v;
-	int i;
-	struct irq_cfg *cfg;
-	int do_unmask_irq = 0;
 
-	irq_complete_move(&desc);
+	irq_complete_move(cfg);
 #ifdef CONFIG_GENERIC_PENDING_IRQ
 	/* If we are moving the irq we need to mask it */
-	if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
+	if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) {
 		do_unmask_irq = 1;
-		mask_IO_APIC_irq_desc(desc);
+		mask_ioapic(cfg);
 	}
 #endif
 
@@ -2658,7 +2473,6 @@
 	 * we use the above logic (mask+edge followed by unmask+level) from
 	 * Manfred Spraul to clear the remote IRR.
 	 */
-	cfg = desc->chip_data;
 	i = cfg->vector;
 	v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 
@@ -2678,7 +2492,7 @@
 	if (!(v & (1 << (i & 0x1f)))) {
 		atomic_inc(&irq_mis_count);
 
-		eoi_ioapic_irq(desc);
+		eoi_ioapic_irq(irq, cfg);
 	}
 
 	/* Now we can move and renable the irq */
@@ -2709,61 +2523,57 @@
 		 * accurate and is causing problems then it is a hardware bug
 		 * and you can go talk to the chipset vendor about it.
 		 */
-		cfg = desc->chip_data;
 		if (!io_apic_level_ack_pending(cfg))
 			move_masked_irq(irq);
-		unmask_IO_APIC_irq_desc(desc);
+		unmask_ioapic(cfg);
 	}
 }
 
 #ifdef CONFIG_INTR_REMAP
-static void ir_ack_apic_edge(unsigned int irq)
+static void ir_ack_apic_edge(struct irq_data *data)
 {
 	ack_APIC_irq();
 }
 
-static void ir_ack_apic_level(unsigned int irq)
+static void ir_ack_apic_level(struct irq_data *data)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-
 	ack_APIC_irq();
-	eoi_ioapic_irq(desc);
+	eoi_ioapic_irq(data->irq, data->chip_data);
 }
 #endif /* CONFIG_INTR_REMAP */
 
 static struct irq_chip ioapic_chip __read_mostly = {
-	.name		= "IO-APIC",
-	.startup	= startup_ioapic_irq,
-	.mask		= mask_IO_APIC_irq,
-	.unmask		= unmask_IO_APIC_irq,
-	.ack		= ack_apic_edge,
-	.eoi		= ack_apic_level,
+	.name			= "IO-APIC",
+	.irq_startup		= startup_ioapic_irq,
+	.irq_mask		= mask_ioapic_irq,
+	.irq_unmask		= unmask_ioapic_irq,
+	.irq_ack		= ack_apic_edge,
+	.irq_eoi		= ack_apic_level,
 #ifdef CONFIG_SMP
-	.set_affinity	= set_ioapic_affinity_irq,
+	.irq_set_affinity	= ioapic_set_affinity,
 #endif
-	.retrigger	= ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 static struct irq_chip ir_ioapic_chip __read_mostly = {
-	.name		= "IR-IO-APIC",
-	.startup	= startup_ioapic_irq,
-	.mask		= mask_IO_APIC_irq,
-	.unmask		= unmask_IO_APIC_irq,
+	.name			= "IR-IO-APIC",
+	.irq_startup		= startup_ioapic_irq,
+	.irq_mask		= mask_ioapic_irq,
+	.irq_unmask		= unmask_ioapic_irq,
 #ifdef CONFIG_INTR_REMAP
-	.ack		= ir_ack_apic_edge,
-	.eoi		= ir_ack_apic_level,
+	.irq_ack		= ir_ack_apic_edge,
+	.irq_eoi		= ir_ack_apic_level,
 #ifdef CONFIG_SMP
-	.set_affinity	= set_ir_ioapic_affinity_irq,
+	.irq_set_affinity	= ir_ioapic_set_affinity,
 #endif
 #endif
-	.retrigger	= ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 static inline void init_IO_APIC_traps(void)
 {
-	int irq;
-	struct irq_desc *desc;
 	struct irq_cfg *cfg;
+	unsigned int irq;
 
 	/*
 	 * NOTE! The local APIC isn't very good at handling
@@ -2776,8 +2586,8 @@
 	 * Also, we've got to be careful not to trash gate
 	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
 	 */
-	for_each_irq_desc(irq, desc) {
-		cfg = desc->chip_data;
+	for_each_active_irq(irq) {
+		cfg = get_irq_chip_data(irq);
 		if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
 			/*
 			 * Hmm.. We don't have an entry for this,
@@ -2788,7 +2598,7 @@
 				legacy_pic->make_irq(irq);
 			else
 				/* Strange. Oh, well.. */
-				desc->chip = &no_irq_chip;
+				set_irq_chip(irq, &no_irq_chip);
 		}
 	}
 }
@@ -2797,7 +2607,7 @@
  * The local APIC irq-chip implementation:
  */
 
-static void mask_lapic_irq(unsigned int irq)
+static void mask_lapic_irq(struct irq_data *data)
 {
 	unsigned long v;
 
@@ -2805,7 +2615,7 @@
 	apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
 }
 
-static void unmask_lapic_irq(unsigned int irq)
+static void unmask_lapic_irq(struct irq_data *data)
 {
 	unsigned long v;
 
@@ -2813,21 +2623,21 @@
 	apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
 }
 
-static void ack_lapic_irq(unsigned int irq)
+static void ack_lapic_irq(struct irq_data *data)
 {
 	ack_APIC_irq();
 }
 
 static struct irq_chip lapic_chip __read_mostly = {
 	.name		= "local-APIC",
-	.mask		= mask_lapic_irq,
-	.unmask		= unmask_lapic_irq,
-	.ack		= ack_lapic_irq,
+	.irq_mask	= mask_lapic_irq,
+	.irq_unmask	= unmask_lapic_irq,
+	.irq_ack	= ack_lapic_irq,
 };
 
-static void lapic_register_intr(int irq, struct irq_desc *desc)
+static void lapic_register_intr(int irq)
 {
-	desc->status &= ~IRQ_LEVEL;
+	irq_clear_status_flags(irq, IRQ_LEVEL);
 	set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
 				      "edge");
 }
@@ -2930,9 +2740,8 @@
  */
 static inline void __init check_timer(void)
 {
-	struct irq_desc *desc = irq_to_desc(0);
-	struct irq_cfg *cfg = desc->chip_data;
-	int node = cpu_to_node(boot_cpu_id);
+	struct irq_cfg *cfg = get_irq_chip_data(0);
+	int node = cpu_to_node(0);
 	int apic1, pin1, apic2, pin2;
 	unsigned long flags;
 	int no_pin1 = 0;
@@ -2942,7 +2751,7 @@
 	/*
 	 * get/set the timer IRQ vector:
 	 */
-	legacy_pic->chip->mask(0);
+	legacy_pic->mask(0);
 	assign_irq_vector(0, cfg, apic->target_cpus());
 
 	/*
@@ -3001,7 +2810,7 @@
 			add_pin_to_irq_node(cfg, node, apic1, pin1);
 			setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
 		} else {
-			/* for edge trigger, setup_IO_APIC_irq already
+			/* for edge trigger, setup_ioapic_irq already
 			 * leave it unmasked.
 			 * so only need to unmask if it is level-trigger
 			 * do we really have level trigger timer?
@@ -3009,12 +2818,12 @@
 			int idx;
 			idx = find_irq_entry(apic1, pin1, mp_INT);
 			if (idx != -1 && irq_trigger(idx))
-				unmask_IO_APIC_irq_desc(desc);
+				unmask_ioapic(cfg);
 		}
 		if (timer_irq_works()) {
 			if (nmi_watchdog == NMI_IO_APIC) {
 				setup_nmi();
-				legacy_pic->chip->unmask(0);
+				legacy_pic->unmask(0);
 			}
 			if (disable_timer_pin_1 > 0)
 				clear_IO_APIC_pin(0, pin1);
@@ -3037,14 +2846,14 @@
 		 */
 		replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
 		setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
-		legacy_pic->chip->unmask(0);
+		legacy_pic->unmask(0);
 		if (timer_irq_works()) {
 			apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
 			timer_through_8259 = 1;
 			if (nmi_watchdog == NMI_IO_APIC) {
-				legacy_pic->chip->mask(0);
+				legacy_pic->mask(0);
 				setup_nmi();
-				legacy_pic->chip->unmask(0);
+				legacy_pic->unmask(0);
 			}
 			goto out;
 		}
@@ -3052,7 +2861,7 @@
 		 * Cleanup, just in case ...
 		 */
 		local_irq_disable();
-		legacy_pic->chip->mask(0);
+		legacy_pic->mask(0);
 		clear_IO_APIC_pin(apic2, pin2);
 		apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
 	}
@@ -3069,16 +2878,16 @@
 	apic_printk(APIC_QUIET, KERN_INFO
 		    "...trying to set up timer as Virtual Wire IRQ...\n");
 
-	lapic_register_intr(0, desc);
+	lapic_register_intr(0);
 	apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);	/* Fixed mode */
-	legacy_pic->chip->unmask(0);
+	legacy_pic->unmask(0);
 
 	if (timer_irq_works()) {
 		apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
 		goto out;
 	}
 	local_irq_disable();
-	legacy_pic->chip->mask(0);
+	legacy_pic->mask(0);
 	apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
 	apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n");
 
@@ -3244,49 +3053,42 @@
 /*
  * Dynamic irq allocate and deallocation
  */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
+unsigned int create_irq_nr(unsigned int from, int node)
 {
-	/* Allocate an unused irq */
-	unsigned int irq;
-	unsigned int new;
+	struct irq_cfg *cfg;
 	unsigned long flags;
-	struct irq_cfg *cfg_new = NULL;
-	struct irq_desc *desc_new = NULL;
-
-	irq = 0;
-	if (irq_want < nr_irqs_gsi)
-		irq_want = nr_irqs_gsi;
-
-	raw_spin_lock_irqsave(&vector_lock, flags);
-	for (new = irq_want; new < nr_irqs; new++) {
-		desc_new = irq_to_desc_alloc_node(new, node);
-		if (!desc_new) {
-			printk(KERN_INFO "can not get irq_desc for %d\n", new);
-			continue;
-		}
-		cfg_new = desc_new->chip_data;
-
-		if (cfg_new->vector != 0)
-			continue;
+	unsigned int ret = 0;
+	int irq;
 
-		desc_new = move_irq_desc(desc_new, node);
-		cfg_new = desc_new->chip_data;
+	if (from < nr_irqs_gsi)
+		from = nr_irqs_gsi;
 
-		if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
-			irq = new;
-		break;
+	irq = alloc_irq_from(from, node);
+	if (irq < 0)
+		return 0;
+	cfg = alloc_irq_cfg(irq, node);
+	if (!cfg) {
+		free_irq_at(irq, NULL);
+		return 0;
 	}
-	raw_spin_unlock_irqrestore(&vector_lock, flags);
 
-	if (irq > 0)
-		dynamic_irq_init_keep_chip_data(irq);
+	raw_spin_lock_irqsave(&vector_lock, flags);
+	if (!__assign_irq_vector(irq, cfg, apic->target_cpus()))
+		ret = irq;
+	raw_spin_unlock_irqrestore(&vector_lock, flags);
 
-	return irq;
+	if (ret) {
+		set_irq_chip_data(irq, cfg);
+		irq_clear_status_flags(irq, IRQ_NOREQUEST);
+	} else {
+		free_irq_at(irq, cfg);
+	}
+	return ret;
 }
 
 int create_irq(void)
 {
-	int node = cpu_to_node(boot_cpu_id);
+	int node = cpu_to_node(0);
 	unsigned int irq_want;
 	int irq;
 
@@ -3301,14 +3103,17 @@
 
 void destroy_irq(unsigned int irq)
 {
+	struct irq_cfg *cfg = get_irq_chip_data(irq);
 	unsigned long flags;
 
-	dynamic_irq_cleanup_keep_chip_data(irq);
+	irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
 
-	free_irte(irq);
+	if (irq_remapped(cfg))
+		free_irte(irq);
 	raw_spin_lock_irqsave(&vector_lock, flags);
-	__clear_irq_vector(irq, get_irq_chip_data(irq));
+	__clear_irq_vector(irq, cfg);
 	raw_spin_unlock_irqrestore(&vector_lock, flags);
+	free_irq_at(irq, cfg);
 }
 
 /*
@@ -3332,7 +3137,7 @@
 
 	dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
 
-	if (irq_remapped(irq)) {
+	if (irq_remapped(get_irq_chip_data(irq))) {
 		struct irte irte;
 		int ir_index;
 		u16 sub_handle;
@@ -3340,14 +3145,7 @@
 		ir_index = map_irq_to_irte_handle(irq, &sub_handle);
 		BUG_ON(ir_index == -1);
 
-		memset (&irte, 0, sizeof(irte));
-
-		irte.present = 1;
-		irte.dst_mode = apic->irq_dest_mode;
-		irte.trigger_mode = 0; /* edge */
-		irte.dlvry_mode = apic->irq_delivery_mode;
-		irte.vector = cfg->vector;
-		irte.dest_id = IRTE_DEST(dest);
+		prepare_irte(&irte, cfg->vector, dest);
 
 		/* Set source-id of interrupt request */
 		if (pdev)
@@ -3392,26 +3190,24 @@
 }
 
 #ifdef CONFIG_SMP
-static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg;
+	struct irq_cfg *cfg = data->chip_data;
 	struct msi_msg msg;
 	unsigned int dest;
 
-	if (set_desc_affinity(desc, mask, &dest))
+	if (__ioapic_set_affinity(data, mask, &dest))
 		return -1;
 
-	cfg = desc->chip_data;
-
-	get_cached_msi_msg_desc(desc, &msg);
+	__get_cached_msi_msg(data->msi_desc, &msg);
 
 	msg.data &= ~MSI_DATA_VECTOR_MASK;
 	msg.data |= MSI_DATA_VECTOR(cfg->vector);
 	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
 	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-	write_msi_msg_desc(desc, &msg);
+	__write_msi_msg(data->msi_desc, &msg);
 
 	return 0;
 }
@@ -3421,17 +3217,17 @@
  * done in the process context using interrupt-remapping hardware.
  */
 static int
-ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
+ir_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		    bool force)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg = desc->chip_data;
-	unsigned int dest;
+	struct irq_cfg *cfg = data->chip_data;
+	unsigned int dest, irq = data->irq;
 	struct irte irte;
 
 	if (get_irte(irq, &irte))
 		return -1;
 
-	if (set_desc_affinity(desc, mask, &dest))
+	if (__ioapic_set_affinity(data, mask, &dest))
 		return -1;
 
 	irte.vector = cfg->vector;
@@ -3461,27 +3257,27 @@
  * which implement the MSI or MSI-X Capability Structure.
  */
 static struct irq_chip msi_chip = {
-	.name		= "PCI-MSI",
-	.unmask		= unmask_msi_irq,
-	.mask		= mask_msi_irq,
-	.ack		= ack_apic_edge,
+	.name			= "PCI-MSI",
+	.irq_unmask		= unmask_msi_irq,
+	.irq_mask		= mask_msi_irq,
+	.irq_ack		= ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity	= set_msi_irq_affinity,
+	.irq_set_affinity	= msi_set_affinity,
 #endif
-	.retrigger	= ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 static struct irq_chip msi_ir_chip = {
-	.name		= "IR-PCI-MSI",
-	.unmask		= unmask_msi_irq,
-	.mask		= mask_msi_irq,
+	.name			= "IR-PCI-MSI",
+	.irq_unmask		= unmask_msi_irq,
+	.irq_mask		= mask_msi_irq,
 #ifdef CONFIG_INTR_REMAP
-	.ack		= ir_ack_apic_edge,
+	.irq_ack		= ir_ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity	= ir_set_msi_irq_affinity,
+	.irq_set_affinity	= ir_msi_set_affinity,
 #endif
 #endif
-	.retrigger	= ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 /*
@@ -3513,8 +3309,8 @@
 
 static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 {
-	int ret;
 	struct msi_msg msg;
+	int ret;
 
 	ret = msi_compose_msg(dev, irq, &msg, -1);
 	if (ret < 0)
@@ -3523,12 +3319,8 @@
 	set_irq_msi(irq, msidesc);
 	write_msi_msg(irq, &msg);
 
-	if (irq_remapped(irq)) {
-		struct irq_desc *desc = irq_to_desc(irq);
-		/*
-		 * irq migration in process context
-		 */
-		desc->status |= IRQ_MOVE_PCNTXT;
+	if (irq_remapped(get_irq_chip_data(irq))) {
+		irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
 		set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
 	} else
 		set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
@@ -3538,15 +3330,12 @@
 	return 0;
 }
 
-int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-	unsigned int irq;
-	int ret, sub_handle;
+	int node, ret, sub_handle, index = 0;
+	unsigned int irq, irq_want;
 	struct msi_desc *msidesc;
-	unsigned int irq_want;
 	struct intel_iommu *iommu = NULL;
-	int index = 0;
-	int node;
 
 	/* x86 doesn't support multiple MSI yet */
 	if (type == PCI_CAP_ID_MSI && nvec > 1)
@@ -3599,31 +3388,31 @@
 	return ret;
 }
 
-void arch_teardown_msi_irq(unsigned int irq)
+void native_teardown_msi_irq(unsigned int irq)
 {
 	destroy_irq(irq);
 }
 
 #if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
 #ifdef CONFIG_SMP
-static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
+		      bool force)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg;
+	struct irq_cfg *cfg = data->chip_data;
+	unsigned int dest, irq = data->irq;
 	struct msi_msg msg;
-	unsigned int dest;
 
-	if (set_desc_affinity(desc, mask, &dest))
+	if (__ioapic_set_affinity(data, mask, &dest))
 		return -1;
 
-	cfg = desc->chip_data;
-
 	dmar_msi_read(irq, &msg);
 
 	msg.data &= ~MSI_DATA_VECTOR_MASK;
 	msg.data |= MSI_DATA_VECTOR(cfg->vector);
 	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
 	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+	msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
 
 	dmar_msi_write(irq, &msg);
 
@@ -3633,14 +3422,14 @@
 #endif /* CONFIG_SMP */
 
 static struct irq_chip dmar_msi_type = {
-	.name = "DMAR_MSI",
-	.unmask = dmar_msi_unmask,
-	.mask = dmar_msi_mask,
-	.ack = ack_apic_edge,
+	.name			= "DMAR_MSI",
+	.irq_unmask		= dmar_msi_unmask,
+	.irq_mask		= dmar_msi_mask,
+	.irq_ack		= ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity = dmar_msi_set_affinity,
+	.irq_set_affinity	= dmar_msi_set_affinity,
 #endif
-	.retrigger = ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 int arch_setup_dmar_msi(unsigned int irq)
@@ -3661,26 +3450,24 @@
 #ifdef CONFIG_HPET_TIMER
 
 #ifdef CONFIG_SMP
-static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int hpet_msi_set_affinity(struct irq_data *data,
+				 const struct cpumask *mask, bool force)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg;
+	struct irq_cfg *cfg = data->chip_data;
 	struct msi_msg msg;
 	unsigned int dest;
 
-	if (set_desc_affinity(desc, mask, &dest))
+	if (__ioapic_set_affinity(data, mask, &dest))
 		return -1;
 
-	cfg = desc->chip_data;
-
-	hpet_msi_read(irq, &msg);
+	hpet_msi_read(data->handler_data, &msg);
 
 	msg.data &= ~MSI_DATA_VECTOR_MASK;
 	msg.data |= MSI_DATA_VECTOR(cfg->vector);
 	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
 	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-	hpet_msi_write(irq, &msg);
+	hpet_msi_write(data->handler_data, &msg);
 
 	return 0;
 }
@@ -3688,34 +3475,33 @@
 #endif /* CONFIG_SMP */
 
 static struct irq_chip ir_hpet_msi_type = {
-	.name = "IR-HPET_MSI",
-	.unmask = hpet_msi_unmask,
-	.mask = hpet_msi_mask,
+	.name			= "IR-HPET_MSI",
+	.irq_unmask		= hpet_msi_unmask,
+	.irq_mask		= hpet_msi_mask,
 #ifdef CONFIG_INTR_REMAP
-	.ack = ir_ack_apic_edge,
+	.irq_ack		= ir_ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity = ir_set_msi_irq_affinity,
+	.irq_set_affinity	= ir_msi_set_affinity,
 #endif
 #endif
-	.retrigger = ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 static struct irq_chip hpet_msi_type = {
 	.name = "HPET_MSI",
-	.unmask = hpet_msi_unmask,
-	.mask = hpet_msi_mask,
-	.ack = ack_apic_edge,
+	.irq_unmask = hpet_msi_unmask,
+	.irq_mask = hpet_msi_mask,
+	.irq_ack = ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity = hpet_msi_set_affinity,
+	.irq_set_affinity = hpet_msi_set_affinity,
 #endif
-	.retrigger = ioapic_retrigger_irq,
+	.irq_retrigger = ioapic_retrigger_irq,
 };
 
 int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
 {
-	int ret;
 	struct msi_msg msg;
-	struct irq_desc *desc = irq_to_desc(irq);
+	int ret;
 
 	if (intr_remapping_enabled) {
 		struct intel_iommu *iommu = map_hpet_to_ir(id);
@@ -3733,9 +3519,9 @@
 	if (ret < 0)
 		return ret;
 
-	hpet_msi_write(irq, &msg);
-	desc->status |= IRQ_MOVE_PCNTXT;
-	if (irq_remapped(irq))
+	hpet_msi_write(get_irq_data(irq), &msg);
+	irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+	if (irq_remapped(get_irq_chip_data(irq)))
 		set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
 					      handle_edge_irq, "edge");
 	else
@@ -3768,33 +3554,30 @@
 	write_ht_irq_msg(irq, &msg);
 }
 
-static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg;
+	struct irq_cfg *cfg = data->chip_data;
 	unsigned int dest;
 
-	if (set_desc_affinity(desc, mask, &dest))
+	if (__ioapic_set_affinity(data, mask, &dest))
 		return -1;
 
-	cfg = desc->chip_data;
-
-	target_ht_irq(irq, dest, cfg->vector);
-
+	target_ht_irq(data->irq, dest, cfg->vector);
 	return 0;
 }
 
 #endif
 
 static struct irq_chip ht_irq_chip = {
-	.name		= "PCI-HT",
-	.mask		= mask_ht_irq,
-	.unmask		= unmask_ht_irq,
-	.ack		= ack_apic_edge,
+	.name			= "PCI-HT",
+	.irq_mask		= mask_ht_irq,
+	.irq_unmask		= unmask_ht_irq,
+	.irq_ack		= ack_apic_edge,
 #ifdef CONFIG_SMP
-	.set_affinity	= set_ht_irq_affinity,
+	.irq_set_affinity	= ht_set_affinity,
 #endif
-	.retrigger	= ioapic_retrigger_irq,
+	.irq_retrigger		= ioapic_retrigger_irq,
 };
 
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
@@ -3867,6 +3650,11 @@
 	printk(KERN_DEBUG "nr_irqs_gsi: %d\n", nr_irqs_gsi);
 }
 
+int get_nr_irqs_gsi(void)
+{
+	return nr_irqs_gsi;
+}
+
 #ifdef CONFIG_SPARSE_IRQ
 int __init arch_probe_nr_irqs(void)
 {
@@ -3885,14 +3673,13 @@
 	if (nr < nr_irqs)
 		nr_irqs = nr;
 
-	return 0;
+	return NR_IRQS_LEGACY;
 }
 #endif
 
 static int __io_apic_set_pci_routing(struct device *dev, int irq,
 				struct io_apic_irq_attr *irq_attr)
 {
-	struct irq_desc *desc;
 	struct irq_cfg *cfg;
 	int node;
 	int ioapic, pin;
@@ -3908,13 +3695,11 @@
 	if (dev)
 		node = dev_to_node(dev);
 	else
-		node = cpu_to_node(boot_cpu_id);
+		node = cpu_to_node(0);
 
-	desc = irq_to_desc_alloc_node(irq, node);
-	if (!desc) {
-		printk(KERN_INFO "can not get irq_desc %d\n", irq);
+	cfg = alloc_irq_and_cfg_at(irq, node);
+	if (!cfg)
 		return 0;
-	}
 
 	pin = irq_attr->ioapic_pin;
 	trigger = irq_attr->trigger;
@@ -3924,15 +3709,14 @@
 	 * IRQs < 16 are already in the irq_2_pin[] map
 	 */
 	if (irq >= legacy_pic->nr_legacy_irqs) {
-		cfg = desc->chip_data;
-		if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) {
+		if (__add_pin_to_irq_node(cfg, node, ioapic, pin)) {
 			printk(KERN_INFO "can not add pin %d for irq %d\n",
 				pin, irq);
 			return 0;
 		}
 	}
 
-	setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
+	setup_ioapic_irq(ioapic, pin, irq, cfg, trigger, polarity);
 
 	return 0;
 }
@@ -4125,14 +3909,14 @@
 		 */
 		if (desc->status &
 		    (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
-			mask = desc->affinity;
+			mask = desc->irq_data.affinity;
 		else
 			mask = apic->target_cpus();
 
 		if (intr_remapping_enabled)
-			set_ir_ioapic_affinity_irq_desc(desc, mask);
+			ir_ioapic_set_affinity(&desc->irq_data, mask, false);
 		else
-			set_ioapic_affinity_irq_desc(desc, mask);
+			ioapic_set_affinity(&desc->irq_data, mask, false);
 	}
 
 }
@@ -4316,19 +4100,18 @@
 void __init pre_init_apic_IRQ0(void)
 {
 	struct irq_cfg *cfg;
-	struct irq_desc *desc;
 
 	printk(KERN_INFO "Early APIC setup for system timer0\n");
 #ifndef CONFIG_SMP
 	phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
 #endif
-	desc = irq_to_desc_alloc_node(0, 0);
+	/* Make sure the irq descriptor is set up */
+	cfg = alloc_irq_and_cfg_at(0, 0);
 
 	setup_local_APIC();
 
-	cfg = irq_cfg(0);
 	add_pin_to_irq_node(cfg, 0, 0, 0);
 	set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
 
-	setup_IO_APIC_irq(0, 0, 0, desc, 0, 0);
+	setup_ioapic_irq(0, 0, 0, cfg, 0, 0);
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/nmi.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/nmi.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/nmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/nmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -178,7 +178,7 @@
 error:
 	if (nmi_watchdog == NMI_IO_APIC) {
 		if (!timer_through_8259)
-			legacy_pic->chip->mask(0);
+			legacy_pic->mask(0);
 		on_each_cpu(__acpi_nmi_disable, NULL, 1);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/numaq_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/numaq_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/numaq_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/numaq_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,6 +26,7 @@
 #include <linux/nodemask.h>
 #include <linux/topology.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/kernel.h>
@@ -88,7 +89,7 @@
 	node_end_pfn[node] =
 		 MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
 
-	e820_register_active_regions(node, node_start_pfn[node],
+	memblock_x86_register_active_regions(node, node_start_pfn[node],
 						node_end_pfn[node]);
 
 	memory_present(node, node_start_pfn[node], node_end_pfn[node]);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/probe_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/probe_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/probe_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/probe_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,6 +54,9 @@
  */
 void __init default_setup_apic_routing(void)
 {
+
+	enable_IR_x2apic();
+
 #ifdef CONFIG_X86_X2APIC
 	if (x2apic_mode
 #ifdef CONFIG_X86_UV
@@ -76,13 +79,6 @@
 		/* need to update phys_pkg_id */
 		apic->phys_pkg_id = apicid_phys_pkg_id;
 	}
-
-	/*
-	 * Now that apic routing model is selected, configure the
-	 * fault handling for intr remapping.
-	 */
-	if (intr_remapping_enabled)
-		enable_drhd_fault_handling();
 }
 
 /* Same for both flat and physical. */
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apic/x2apic_uv_x.c linux-libre-2.6.37-gnu/arch/x86/kernel/apic/x2apic_uv_x.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apic/x2apic_uv_x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apic/x2apic_uv_x.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2009 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -41,8 +41,11 @@
 
 static enum uv_system_type uv_system_type;
 static u64 gru_start_paddr, gru_end_paddr;
+static union uvh_apicid uvh_apicid;
 int uv_min_hub_revision_id;
 EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
+unsigned int uv_apicid_hibits;
+EXPORT_SYMBOL_GPL(uv_apicid_hibits);
 static DEFINE_SPINLOCK(uv_nmi_lock);
 
 static inline bool is_GRU_range(u64 start, u64 end)
@@ -70,12 +73,44 @@
 	return node_id.s.node_id;
 }
 
+static void __init early_get_apic_pnode_shift(void)
+{
+	unsigned long *mmr;
+
+	mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_APICID, sizeof(*mmr));
+	uvh_apicid.v = *mmr;
+	early_iounmap(mmr, sizeof(*mmr));
+	if (!uvh_apicid.v)
+		/*
+		 * Old bios, use default value
+		 */
+		uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT;
+}
+
+/*
+ * Add an extra bit as dictated by bios to the destination apicid of
+ * interrupts potentially passing through the UV HUB.  This prevents
+ * a deadlock between interrupts and IO port operations.
+ */
+static void __init uv_set_apicid_hibit(void)
+{
+	union uvh_lb_target_physical_apic_id_mask_u apicid_mask;
+	unsigned long *mmr;
+
+	mmr = early_ioremap(UV_LOCAL_MMR_BASE |
+		UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK, sizeof(*mmr));
+	apicid_mask.v = *mmr;
+	early_iounmap(mmr, sizeof(*mmr));
+	uv_apicid_hibits = apicid_mask.s.bit_enables & UV_APICID_HIBIT_MASK;
+}
+
 static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
 	int nodeid;
 
 	if (!strcmp(oem_id, "SGI")) {
 		nodeid = early_get_nodeid();
+		early_get_apic_pnode_shift();
 		x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
 		x86_platform.nmi_init = uv_nmi_init;
 		if (!strcmp(oem_table_id, "UVL"))
@@ -84,8 +119,9 @@
 			uv_system_type = UV_X2APIC;
 		else if (!strcmp(oem_table_id, "UVH")) {
 			__get_cpu_var(x2apic_extra_bits) =
-				nodeid << (UV_APIC_PNODE_SHIFT - 1);
+				nodeid << (uvh_apicid.s.pnode_shift - 1);
 			uv_system_type = UV_NON_UNIQUE_APIC;
+			uv_set_apicid_hibit();
 			return 1;
 		}
 	}
@@ -139,6 +175,7 @@
 	int pnode;
 
 	pnode = uv_apicid_to_pnode(phys_apicid);
+	phys_apicid |= uv_apicid_hibits;
 	val = (1UL << UVH_IPI_INT_SEND_SHFT) |
 	    (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
 	    ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
@@ -220,7 +257,7 @@
 	int cpu = cpumask_first(cpumask);
 
 	if ((unsigned)cpu < nr_cpu_ids)
-		return per_cpu(x86_cpu_to_apicid, cpu);
+		return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
 	else
 		return BAD_APICID;
 }
@@ -239,7 +276,7 @@
 		if (cpumask_test_cpu(cpu, cpu_online_mask))
 			break;
 	}
-	return per_cpu(x86_cpu_to_apicid, cpu);
+	return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits;
 }
 
 static unsigned int x2apic_get_apic_id(unsigned long x)
@@ -363,14 +400,14 @@
 #define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
 
 static __initdata struct redir_addr redir_addrs[] = {
-	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG},
-	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG},
-	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG},
+	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR},
+	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR},
+	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR},
 };
 
 static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 {
-	union uvh_si_alias0_overlay_config_u alias;
+	union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias;
 	union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect;
 	int i;
 
@@ -644,7 +681,7 @@
 
 void __init uv_system_init(void)
 {
-	union uvh_si_addr_map_config_u m_n_config;
+	union uvh_rh_gam_config_mmr_u  m_n_config;
 	union uvh_node_id_u node_id;
 	unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
 	int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
@@ -654,7 +691,7 @@
 
 	map_low_mmrs();
 
-	m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
+	m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
 	mmr_base =
@@ -716,6 +753,10 @@
 		int apicid = per_cpu(x86_cpu_to_apicid, cpu);
 
 		nid = cpu_to_node(cpu);
+		/*
+		 * apic_pnode_shift must be set before calling uv_apicid_to_pnode();
+		 */
+		uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift;
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);
 		lcpu = uv_blade_info[blade].nr_possible_cpus;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/apm_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/apm_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/apm_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/apm_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -189,8 +189,8 @@
  *   Intel Order Number 241704-001.  Microsoft Part Number 781-110-X01.
  *
  * [This document is available free from Intel by calling 800.628.8686 (fax
- * 916.356.6100) or 800.548.4725; or via anonymous ftp from
- * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc.  It is also
+ * 916.356.6100) or 800.548.4725; or from
+ * http://www.microsoft.com/whdc/archive/amp_12.mspx  It is also
  * available from Microsoft by calling 206.882.8080.]
  *
  * APM 1.2 Reference:
@@ -1926,6 +1926,7 @@
 	.unlocked_ioctl	= do_ioctl,
 	.open		= do_open,
 	.release	= do_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice apm_device = {
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/asm-offsets_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/asm-offsets_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/asm-offsets_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/asm-offsets_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -99,9 +99,7 @@
 
 	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
 	DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
-	DEFINE(PTRS_PER_PTE, PTRS_PER_PTE);
-	DEFINE(PTRS_PER_PMD, PTRS_PER_PMD);
-	DEFINE(PTRS_PER_PGD, PTRS_PER_PGD);
+	DEFINE(THREAD_SIZE_asm, THREAD_SIZE);
 
 	OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/bios_uv.c linux-libre-2.6.37-gnu/arch/x86/kernel/bios_uv.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/bios_uv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/bios_uv.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,215 +0,0 @@
-/*
- * BIOS run time interface routines.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Russ Anderson <rja@sgi.com>
- */
-
-#include <linux/efi.h>
-#include <asm/efi.h>
-#include <linux/io.h>
-#include <asm/uv/bios.h>
-#include <asm/uv/uv_hub.h>
-
-static struct uv_systab uv_systab;
-
-s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
-{
-	struct uv_systab *tab = &uv_systab;
-	s64 ret;
-
-	if (!tab->function)
-		/*
-		 * BIOS does not support UV systab
-		 */
-		return BIOS_STATUS_UNIMPLEMENTED;
-
-	ret = efi_call6((void *)__va(tab->function), (u64)which,
-			a1, a2, a3, a4, a5);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(uv_bios_call);
-
-s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
-					u64 a4, u64 a5)
-{
-	unsigned long bios_flags;
-	s64 ret;
-
-	local_irq_save(bios_flags);
-	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
-	local_irq_restore(bios_flags);
-
-	return ret;
-}
-
-s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
-					u64 a4, u64 a5)
-{
-	s64 ret;
-
-	preempt_disable();
-	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
-	preempt_enable();
-
-	return ret;
-}
-
-
-long sn_partition_id;
-EXPORT_SYMBOL_GPL(sn_partition_id);
-long sn_coherency_id;
-EXPORT_SYMBOL_GPL(sn_coherency_id);
-long sn_region_size;
-EXPORT_SYMBOL_GPL(sn_region_size);
-long system_serial_number;
-EXPORT_SYMBOL_GPL(system_serial_number);
-int uv_type;
-EXPORT_SYMBOL_GPL(uv_type);
-
-
-s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
-		long *region, long *ssn)
-{
-	s64 ret;
-	u64 v0, v1;
-	union partition_info_u part;
-
-	ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc,
-				(u64)(&v0), (u64)(&v1), 0, 0);
-	if (ret != BIOS_STATUS_SUCCESS)
-		return ret;
-
-	part.val = v0;
-	if (uvtype)
-		*uvtype = part.hub_version;
-	if (partid)
-		*partid = part.partition_id;
-	if (coher)
-		*coher = part.coherence_id;
-	if (region)
-		*region = part.region_size;
-	if (ssn)
-		*ssn = v1;
-	return ret;
-}
-EXPORT_SYMBOL_GPL(uv_bios_get_sn_info);
-
-int
-uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
-			   unsigned long *intr_mmr_offset)
-{
-	u64 watchlist;
-	s64 ret;
-
-	/*
-	 * bios returns watchlist number or negative error number.
-	 */
-	ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
-			mq_size, (u64)intr_mmr_offset,
-			(u64)&watchlist, 0);
-	if (ret < BIOS_STATUS_SUCCESS)
-		return ret;
-
-	return watchlist;
-}
-EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
-
-int
-uv_bios_mq_watchlist_free(int blade, int watchlist_num)
-{
-	return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
-				blade, watchlist_num, 0, 0, 0);
-}
-EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
-
-s64
-uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
-{
-	return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
-					perms, 0, 0);
-}
-EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
-
-s64
-uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
-{
-	s64 ret;
-
-	ret = uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
-					(u64)addr, buf, (u64)len, 0);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
-
-s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
-{
-	return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
-			   (u64)ticks_per_second, 0, 0, 0);
-}
-EXPORT_SYMBOL_GPL(uv_bios_freq_base);
-
-/*
- * uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target
- * @decode: true to enable target, false to disable target
- * @domain: PCI domain number
- * @bus: PCI bus number
- *
- * Returns:
- *    0: Success
- *    -EINVAL: Invalid domain or bus number
- *    -ENOSYS: Capability not available
- *    -EBUSY: Legacy VGA I/O cannot be retargeted at this time
- */
-int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
-{
-	return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
-				(u64)decode, (u64)domain, (u64)bus, 0, 0);
-}
-EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
-
-
-#ifdef CONFIG_EFI
-void uv_bios_init(void)
-{
-	struct uv_systab *tab;
-
-	if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) ||
-	    (efi.uv_systab == (unsigned long)NULL)) {
-		printk(KERN_CRIT "No EFI UV System Table.\n");
-		uv_systab.function = (unsigned long)NULL;
-		return;
-	}
-
-	tab = (struct uv_systab *)ioremap(efi.uv_systab,
-					sizeof(struct uv_systab));
-	if (strncmp(tab->signature, "UVST", 4) != 0)
-		printk(KERN_ERR "bad signature in UV system table!");
-
-	/*
-	 * Copy table to permanent spot for later use.
-	 */
-	memcpy(&uv_systab, tab, sizeof(struct uv_systab));
-	iounmap(tab);
-
-	printk(KERN_INFO "EFI UV System Table Revision %d\n",
-					uv_systab.revision);
-}
-#else	/* !CONFIG_EFI */
-
-void uv_bios_init(void) { }
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/check.c linux-libre-2.6.37-gnu/arch/x86/kernel/check.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/check.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/check.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,8 @@
 #include <linux/sched.h>
 #include <linux/kthread.h>
 #include <linux/workqueue.h>
-#include <asm/e820.h>
+#include <linux/memblock.h>
+
 #include <asm/proto.h>
 
 /*
@@ -18,10 +19,12 @@
 static unsigned __read_mostly corruption_check_size = 64*1024;
 static unsigned __read_mostly corruption_check_period = 60; /* seconds */
 
-static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static struct scan_area {
+	u64 addr;
+	u64 size;
+} scan_areas[MAX_SCAN_AREAS];
 static int num_scan_areas;
 
-
 static __init int set_corruption_check(char *arg)
 {
 	char *end;
@@ -81,9 +84,9 @@
 
 	while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
 		u64 size;
-		addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+		addr = memblock_x86_find_in_range_size(addr, &size, PAGE_SIZE);
 
-		if (!(addr + 1))
+		if (addr == MEMBLOCK_ERROR)
 			break;
 
 		if (addr >= corruption_check_size)
@@ -92,7 +95,7 @@
 		if ((addr + size) > corruption_check_size)
 			size = corruption_check_size - addr;
 
-		e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+		memblock_x86_reserve_range(addr, addr + size, "SCAN RAM");
 		scan_areas[num_scan_areas].addr = addr;
 		scan_areas[num_scan_areas].size = size;
 		num_scan_areas++;
@@ -105,7 +108,6 @@
 
 	printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
 	       num_scan_areas);
-	update_e820();
 }
 
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/amd.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/amd.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/amd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/amd.c	2011-01-04 19:50:19.000000000 -0500
@@ -148,7 +148,7 @@
 {
 #ifdef CONFIG_SMP
 	/* calling is from identify_secondary_cpu() ? */
-	if (c->cpu_index == boot_cpu_id)
+	if (!c->cpu_index)
 		return;
 
 	/*
@@ -253,37 +253,51 @@
 #endif
 
 /*
- * Fixup core topology information for AMD multi-node processors.
- * Assumption: Number of cores in each internal node is the same.
+ * Fixup core topology information for
+ * (1) AMD multi-node processors
+ *     Assumption: Number of cores in each internal node is the same.
+ * (2) AMD processors supporting compute units
  */
 #ifdef CONFIG_X86_HT
-static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
+static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
 {
-	unsigned long long value;
-	u32 nodes, cores_per_node;
+	u32 nodes;
+	u8 node_id;
 	int cpu = smp_processor_id();
 
-	if (!cpu_has(c, X86_FEATURE_NODEID_MSR))
-		return;
+	/* get information required for multi-node processors */
+	if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+		u32 eax, ebx, ecx, edx;
 
-	/* fixup topology information only once for a core */
-	if (cpu_has(c, X86_FEATURE_AMD_DCM))
-		return;
+		cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+		nodes = ((ecx >> 8) & 7) + 1;
+		node_id = ecx & 7;
 
-	rdmsrl(MSR_FAM10H_NODE_ID, value);
+		/* get compute unit information */
+		smp_num_siblings = ((ebx >> 8) & 3) + 1;
+		c->compute_unit_id = ebx & 0xff;
+	} else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
+		u64 value;
 
-	nodes = ((value >> 3) & 7) + 1;
-	if (nodes == 1)
+		rdmsrl(MSR_FAM10H_NODE_ID, value);
+		nodes = ((value >> 3) & 7) + 1;
+		node_id = value & 7;
+	} else
 		return;
 
-	set_cpu_cap(c, X86_FEATURE_AMD_DCM);
-	cores_per_node = c->x86_max_cores / nodes;
+	/* fixup multi-node processor information */
+	if (nodes > 1) {
+		u32 cores_per_node;
 
-	/* store NodeID, use llc_shared_map to store sibling info */
-	per_cpu(cpu_llc_id, cpu) = value & 7;
+		set_cpu_cap(c, X86_FEATURE_AMD_DCM);
+		cores_per_node = c->x86_max_cores / nodes;
 
-	/* fixup core id to be in range from 0 to (cores_per_node - 1) */
-	c->cpu_core_id = c->cpu_core_id % cores_per_node;
+		/* store NodeID, use llc_shared_map to store sibling info */
+		per_cpu(cpu_llc_id, cpu) = node_id;
+
+		/* core id to be in range from 0 to (cores_per_node - 1) */
+		c->cpu_core_id = c->cpu_core_id % cores_per_node;
+	}
 }
 #endif
 
@@ -304,9 +318,7 @@
 	c->phys_proc_id = c->initial_apicid >> bits;
 	/* use socket ID also for last level cache */
 	per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
-	/* fixup topology information on multi-node processors */
-	if ((c->x86 == 0x10) && (c->x86_model == 9))
-		amd_fixup_dcm(c);
+	amd_get_topology(c);
 #endif
 }
 
@@ -412,6 +424,23 @@
 			set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
 	}
 #endif
+
+	/* We need to do the following only once */
+	if (c != &boot_cpu_data)
+		return;
+
+	if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
+
+		if (c->x86 > 0x10 ||
+		    (c->x86 == 0x10 && c->x86_model >= 0x2)) {
+			u64 val;
+
+			rdmsrl(MSR_K7_HWCR, val);
+			if (!(val & BIT(24)))
+				printk(KERN_WARNING FW_BUG "TSC doesn't count "
+					"with P0 frequency!\n");
+		}
+	}
 }
 
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
@@ -523,7 +552,7 @@
 #endif
 
 	if (c->extended_cpuid_level >= 0x80000006) {
-		if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000))
+		if (cpuid_edx(0x80000006) & 0xf000)
 			num_cache_leaves = 4;
 		else
 			num_cache_leaves = 3;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/common.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/common.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -665,7 +665,7 @@
 		this_cpu->c_early_init(c);
 
 #ifdef CONFIG_SMP
-	c->cpu_index = boot_cpu_id;
+	c->cpu_index = 0;
 #endif
 	filter_cpuid_features(c, false);
 }
@@ -704,16 +704,21 @@
 }
 
 /*
- * The NOPL instruction is supposed to exist on all CPUs with
- * family >= 6; unfortunately, that's not true in practice because
- * of early VIA chips and (more importantly) broken virtualizers that
- * are not easy to detect.  In the latter case it doesn't even *fail*
- * reliably, so probing for it doesn't even work.  Disable it completely
+ * The NOPL instruction is supposed to exist on all CPUs of family >= 6;
+ * unfortunately, that's not true in practice because of early VIA
+ * chips and (more importantly) broken virtualizers that are not easy
+ * to detect. In the latter case it doesn't even *fail* reliably, so
+ * probing for it doesn't even work. Disable it completely on 32-bit
  * unless we can find a reliable way to detect all the broken cases.
+ * Enable it explicitly on 64-bit for non-constant inputs of cpu_has().
  */
 static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
 {
+#ifdef CONFIG_X86_32
 	clear_cpu_cap(c, X86_FEATURE_NOPL);
+#else
+	set_cpu_cap(c, X86_FEATURE_NOPL);
+#endif
 }
 
 static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
@@ -1264,13 +1269,6 @@
 	clear_all_debug_regs();
 	dbg_restore_debug_regs();
 
-	/*
-	 * Force FPU initialization:
-	 */
-	current_thread_info()->status = 0;
-	clear_used_math();
-	mxcsr_feature_mask_init();
-
 	fpu_init();
 	xsave_init();
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -701,6 +701,7 @@
 		per_cpu(acfreq_data, policy->cpu) = NULL;
 		acpi_processor_unregister_performance(data->acpi_data,
 						      policy->cpu);
+		kfree(data->freq_table);
 		kfree(data);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c	2011-01-04 19:50:19.000000000 -0500
@@ -393,7 +393,7 @@
  * Detects nForce2 A2 and C1 stepping
  *
  */
-static unsigned int nforce2_detect_chipset(void)
+static int nforce2_detect_chipset(void)
 {
 	nforce2_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
 					PCI_DEVICE_ID_NVIDIA_NFORCE2,
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/longrun.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/longrun.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpufreq/longrun.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpufreq/longrun.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,7 @@
  * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
  * and MSR_TMTA_LONGRUN_CTRL
  */
-static void __init longrun_get_policy(struct cpufreq_policy *policy)
+static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy)
 {
 	u32 msr_lo, msr_hi;
 
@@ -165,7 +165,7 @@
  * TMTA rules:
  * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
  */
-static unsigned int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
+static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
 						      unsigned int *high_freq)
 {
 	u32 msr_lo, msr_hi;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpu.h linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpu.h
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/cpu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/cpu.h	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 extern const struct cpu_dev *const __x86_cpu_dev_start[],
 			    *const __x86_cpu_dev_end[];
 
+extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/intel.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/intel.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/intel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/intel.c	2011-01-04 19:50:19.000000000 -0500
@@ -170,7 +170,7 @@
 {
 #ifdef CONFIG_SMP
 	/* calling is from identify_secondary_cpu() ? */
-	if (c->cpu_index == boot_cpu_id)
+	if (!c->cpu_index)
 		return;
 
 	/*
@@ -284,9 +284,7 @@
 	/* Don't do the funky fallback heuristics the AMD version employs
 	   for now. */
 	node = apicid_to_node[apicid];
-	if (node == NUMA_NO_NODE)
-		node = first_node(node_online_map);
-	else if (!node_online(node)) {
+	if (node == NUMA_NO_NODE || !node_online(node)) {
 		/* reuse the value from init_cpu_to_node() */
 		node = cpu_to_node(cpu);
 	}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/intel_cacheinfo.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/intel_cacheinfo.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/intel_cacheinfo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/intel_cacheinfo.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,7 +17,7 @@
 
 #include <asm/processor.h>
 #include <linux/smp.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/smp.h>
 
 #define LVL_1_INST	1
@@ -306,7 +306,7 @@
 	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
 };
 
-#ifdef CONFIG_CPU_SUP_AMD
+#ifdef CONFIG_AMD_NB
 
 /*
  * L3 cache descriptors
@@ -327,6 +327,7 @@
 	l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
 
 	l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
 }
 
 static struct amd_l3_cache * __cpuinit amd_init_l3_cache(int node)
@@ -369,7 +370,7 @@
 			return;
 
 	/* not in virtualized environments */
-	if (num_k8_northbridges == 0)
+	if (k8_northbridges.num == 0)
 		return;
 
 	/*
@@ -377,7 +378,7 @@
 	 * never freed but this is done only on shutdown so it doesn't matter.
 	 */
 	if (!l3_caches) {
-		int size = num_k8_northbridges * sizeof(struct amd_l3_cache *);
+		int size = k8_northbridges.num * sizeof(struct amd_l3_cache *);
 
 		l3_caches = kzalloc(size, GFP_ATOMIC);
 		if (!l3_caches)
@@ -556,12 +557,12 @@
 static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
 		show_cache_disable_1, store_cache_disable_1);
 
-#else	/* CONFIG_CPU_SUP_AMD */
+#else	/* CONFIG_AMD_NB */
 static void __cpuinit
 amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf, int index)
 {
 };
-#endif /* CONFIG_CPU_SUP_AMD */
+#endif /* CONFIG_AMD_NB */
 
 static int
 __cpuinit cpuid4_cache_lookup_regs(int index,
@@ -1000,7 +1001,7 @@
 
 static struct attribute *default_l3_attrs[] = {
 	DEFAULT_SYSFS_CACHE_ATTRS,
-#ifdef CONFIG_CPU_SUP_AMD
+#ifdef CONFIG_AMD_NB
 	&cache_disable_0.attr,
 	&cache_disable_1.attr,
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce_amd.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce_amd.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce_amd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce_amd.c	2011-01-04 19:50:19.000000000 -0500
@@ -131,7 +131,8 @@
 	u32 low = 0, high = 0, address = 0;
 	unsigned int bank, block;
 	struct thresh_restart tr;
-	u8 lvt_off;
+	int lvt_off = -1;
+	u8 offset;
 
 	for (bank = 0; bank < NR_BANKS; ++bank) {
 		for (block = 0; block < NR_BLOCKS; ++block) {
@@ -162,8 +163,28 @@
 			if (shared_bank[bank] && c->cpu_core_id)
 				break;
 #endif
-			lvt_off = setup_APIC_eilvt_mce(THRESHOLD_APIC_VECTOR,
-						       APIC_EILVT_MSG_FIX, 0);
+			offset = (high & MASK_LVTOFF_HI) >> 20;
+			if (lvt_off < 0) {
+				if (setup_APIC_eilvt(offset,
+						     THRESHOLD_APIC_VECTOR,
+						     APIC_EILVT_MSG_FIX, 0)) {
+					pr_err(FW_BUG "cpu %d, failed to "
+					       "setup threshold interrupt "
+					       "for bank %d, block %d "
+					       "(MSR%08X=0x%x%08x)",
+					       smp_processor_id(), bank, block,
+					       address, high, low);
+					continue;
+				}
+				lvt_off = offset;
+			} else if (lvt_off != offset) {
+				pr_err(FW_BUG "cpu %d, invalid threshold "
+				       "interrupt offset %d for bank %d,"
+				       "block %d (MSR%08X=0x%x%08x)",
+				       smp_processor_id(), lvt_off, bank,
+				       block, address, high, low);
+				continue;
+			}
 
 			high &= ~MASK_LVTOFF_HI;
 			high |= lvt_off << 20;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce.c	2011-01-04 19:50:19.000000000 -0500
@@ -1665,6 +1665,7 @@
 	.read			= mce_read,
 	.poll			= mce_poll,
 	.unlocked_ioctl		= mce_ioctl,
+	.llseek		= no_llseek,
 };
 EXPORT_SYMBOL_GPL(mce_chrdev_ops);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce-severity.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce-severity.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/mce-severity.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/mce-severity.c	2011-01-04 19:50:19.000000000 -0500
@@ -192,6 +192,7 @@
 	.release	= seq_release,
 	.read		= seq_read,
 	.write		= severities_coverage_write,
+	.llseek		= seq_lseek,
 };
 
 static int __init severities_debugfs_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/therm_throt.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/therm_throt.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mcheck/therm_throt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mcheck/therm_throt.c	2011-01-04 19:50:19.000000000 -0500
@@ -350,7 +350,7 @@
 
 static void unexpected_thermal_interrupt(void)
 {
-	printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
+	printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n",
 			smp_processor_id());
 	add_taint(TAINT_MACHINE_CHECK);
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mtrr/cleanup.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mtrr/cleanup.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mtrr/cleanup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mtrr/cleanup.c	2011-01-04 19:50:19.000000000 -0500
@@ -827,7 +827,7 @@
 
 	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
 		return 0;
-	if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
+	if (boot_cpu_data.x86 < 0xf)
 		return 0;
 	/* In case some hypervisor doesn't pass SYSCFG through: */
 	if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mtrr/generic.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mtrr/generic.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/mtrr/generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/mtrr/generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,18 +64,59 @@
 	}
 }
 
+/* Get the size of contiguous MTRR range */
+static u64 get_mtrr_size(u64 mask)
+{
+	u64 size;
+
+	mask >>= PAGE_SHIFT;
+	mask |= size_or_mask;
+	size = -mask;
+	size <<= PAGE_SHIFT;
+	return size;
+}
+
 /*
- * Returns the effective MTRR type for the region
- * Error returns:
- * - 0xFE - when the range is "not entirely covered" by _any_ var range MTRR
- * - 0xFF - when MTRR is not enabled
+ * Check and return the effective type for MTRR-MTRR type overlap.
+ * Returns 1 if the effective type is UNCACHEABLE, else returns 0
  */
-u8 mtrr_type_lookup(u64 start, u64 end)
+static int check_type_overlap(u8 *prev, u8 *curr)
+{
+	if (*prev == MTRR_TYPE_UNCACHABLE || *curr == MTRR_TYPE_UNCACHABLE) {
+		*prev = MTRR_TYPE_UNCACHABLE;
+		*curr = MTRR_TYPE_UNCACHABLE;
+		return 1;
+	}
+
+	if ((*prev == MTRR_TYPE_WRBACK && *curr == MTRR_TYPE_WRTHROUGH) ||
+	    (*prev == MTRR_TYPE_WRTHROUGH && *curr == MTRR_TYPE_WRBACK)) {
+		*prev = MTRR_TYPE_WRTHROUGH;
+		*curr = MTRR_TYPE_WRTHROUGH;
+	}
+
+	if (*prev != *curr) {
+		*prev = MTRR_TYPE_UNCACHABLE;
+		*curr = MTRR_TYPE_UNCACHABLE;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Error/Semi-error returns:
+ * 0xFF - when MTRR is not enabled
+ * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
+ *		corresponds only to [start:*partial_end].
+ *		Caller has to lookup again for [*partial_end:end].
+ */
+static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 {
 	int i;
 	u64 base, mask;
 	u8 prev_match, curr_match;
 
+	*repeat = 0;
 	if (!mtrr_state_set)
 		return 0xFF;
 
@@ -126,8 +167,34 @@
 
 		start_state = ((start & mask) == (base & mask));
 		end_state = ((end & mask) == (base & mask));
-		if (start_state != end_state)
-			return 0xFE;
+
+		if (start_state != end_state) {
+			/*
+			 * We have start:end spanning across an MTRR.
+			 * We split the region into
+			 * either
+			 * (start:mtrr_end) (mtrr_end:end)
+			 * or
+			 * (start:mtrr_start) (mtrr_start:end)
+			 * depending on kind of overlap.
+			 * Return the type for first region and a pointer to
+			 * the start of second region so that caller will
+			 * lookup again on the second region.
+			 * Note: This way we handle multiple overlaps as well.
+			 */
+			if (start_state)
+				*partial_end = base + get_mtrr_size(mask);
+			else
+				*partial_end = base;
+
+			if (unlikely(*partial_end <= start)) {
+				WARN_ON(1);
+				*partial_end = start + PAGE_SIZE;
+			}
+
+			end = *partial_end - 1; /* end is inclusive */
+			*repeat = 1;
+		}
 
 		if ((start & mask) != (base & mask))
 			continue;
@@ -138,21 +205,8 @@
 			continue;
 		}
 
-		if (prev_match == MTRR_TYPE_UNCACHABLE ||
-		    curr_match == MTRR_TYPE_UNCACHABLE) {
-			return MTRR_TYPE_UNCACHABLE;
-		}
-
-		if ((prev_match == MTRR_TYPE_WRBACK &&
-		     curr_match == MTRR_TYPE_WRTHROUGH) ||
-		    (prev_match == MTRR_TYPE_WRTHROUGH &&
-		     curr_match == MTRR_TYPE_WRBACK)) {
-			prev_match = MTRR_TYPE_WRTHROUGH;
-			curr_match = MTRR_TYPE_WRTHROUGH;
-		}
-
-		if (prev_match != curr_match)
-			return MTRR_TYPE_UNCACHABLE;
+		if (check_type_overlap(&prev_match, &curr_match))
+			return curr_match;
 	}
 
 	if (mtrr_tom2) {
@@ -166,6 +220,36 @@
 	return mtrr_state.def_type;
 }
 
+/*
+ * Returns the effective MTRR type for the region
+ * Error return:
+ * 0xFF - when MTRR is not enabled
+ */
+u8 mtrr_type_lookup(u64 start, u64 end)
+{
+	u8 type, prev_type;
+	int repeat;
+	u64 partial_end;
+
+	type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+
+	/*
+	 * Common path is with repeat = 0.
+	 * However, we can have cases where [start:end] spans across some
+	 * MTRR range. Do repeated lookups for that case here.
+	 */
+	while (repeat) {
+		prev_type = type;
+		start = partial_end;
+		type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+
+		if (check_type_overlap(&prev_type, &type))
+			return type;
+	}
+
+	return type;
+}
+
 /* Get the MSR pair relating to a var range */
 static void
 get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perfctr-watchdog.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perfctr-watchdog.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perfctr-watchdog.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perfctr-watchdog.c	2011-01-04 19:50:19.000000000 -0500
@@ -700,11 +700,10 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
-		    boot_cpu_data.x86 != 16 && boot_cpu_data.x86 != 17)
-			return;
-		wd_ops = &k7_wd_ops;
-		break;
+		if (boot_cpu_data.x86 == 6 ||
+		    (boot_cpu_data.x86 >= 0xf && boot_cpu_data.x86 <= 0x15))
+			wd_ops = &k7_wd_ops;
+		return;
 	case X86_VENDOR_INTEL:
 		/* Work around where perfctr1 doesn't have a working enable
 		 * bit as described in the following errata:
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_amd.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_amd.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_amd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_amd.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
  [ C(DTLB) ] = {
 	[ C(OP_READ) ] = {
 		[ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses        */
-		[ C(RESULT_MISS)   ] = 0x0046, /* L1 DTLB and L2 DLTB Miss   */
+		[ C(RESULT_MISS)   ] = 0x0746, /* L1_DTLB_AND_L2_DLTB_MISS.ALL */
 	},
 	[ C(OP_WRITE) ] = {
 		[ C(RESULT_ACCESS) ] = 0,
@@ -66,7 +66,7 @@
  [ C(ITLB) ] = {
 	[ C(OP_READ) ] = {
 		[ C(RESULT_ACCESS) ] = 0x0080, /* Instruction fecthes        */
-		[ C(RESULT_MISS)   ] = 0x0085, /* Instr. fetch ITLB misses   */
+		[ C(RESULT_MISS)   ] = 0x0385, /* L1_ITLB_AND_L2_ITLB_MISS.ALL */
 	},
 	[ C(OP_WRITE) ] = {
 		[ C(RESULT_ACCESS) ] = -1,
@@ -280,11 +280,11 @@
 	struct amd_nb *nb;
 	int i;
 
-	nb = kmalloc(sizeof(struct amd_nb), GFP_KERNEL);
+	nb = kmalloc_node(sizeof(struct amd_nb), GFP_KERNEL | __GFP_ZERO,
+			  cpu_to_node(cpu));
 	if (!nb)
 		return NULL;
 
-	memset(nb, 0, sizeof(*nb));
 	nb->nb_id = nb_id;
 
 	/*
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,7 +49,6 @@
 copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
 {
 	unsigned long offset, addr = (unsigned long)from;
-	int type = in_nmi() ? KM_NMI : KM_IRQ0;
 	unsigned long size, len = 0;
 	struct page *page;
 	void *map;
@@ -63,9 +62,9 @@
 		offset = addr & (PAGE_SIZE - 1);
 		size = min(PAGE_SIZE - offset, n - len);
 
-		map = kmap_atomic(page, type);
+		map = kmap_atomic(page);
 		memcpy(to, map+offset, size);
-		kunmap_atomic(map, type);
+		kunmap_atomic(map);
 		put_page(page);
 
 		len  += size;
@@ -238,6 +237,7 @@
 	 * Intel DebugStore bits
 	 */
 	int		bts, pebs;
+	int		bts_active, pebs_active;
 	int		pebs_record_size;
 	void		(*drain_pebs)(struct pt_regs *regs);
 	struct event_constraint *pebs_constraints;
@@ -381,7 +381,21 @@
 
 #endif
 
-static int reserve_ds_buffers(void);
+static bool check_hw_exists(void)
+{
+	u64 val, val_new = 0;
+	int ret = 0;
+
+	val = 0xabcdUL;
+	ret |= checking_wrmsrl(x86_pmu.perfctr, val);
+	ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new);
+	if (ret || val != val_new)
+		return false;
+
+	return true;
+}
+
+static void reserve_ds_buffers(void);
 static void release_ds_buffers(void);
 
 static void hw_perf_event_destroy(struct perf_event *event)
@@ -478,7 +492,7 @@
 	if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
 	    (hwc->sample_period == 1)) {
 		/* BTS is not supported by this architecture. */
-		if (!x86_pmu.bts)
+		if (!x86_pmu.bts_active)
 			return -EOPNOTSUPP;
 
 		/* BTS is currently only allowed for user-mode. */
@@ -497,12 +511,13 @@
 		int precise = 0;
 
 		/* Support for constant skid */
-		if (x86_pmu.pebs)
+		if (x86_pmu.pebs_active) {
 			precise++;
 
-		/* Support for IP fixup */
-		if (x86_pmu.lbr_nr)
-			precise++;
+			/* Support for IP fixup */
+			if (x86_pmu.lbr_nr)
+				precise++;
+		}
 
 		if (event->attr.precise_ip > precise)
 			return -EOPNOTSUPP;
@@ -531,7 +546,7 @@
 /*
  * Setup the hardware configuration for a given attr_type
  */
-static int __hw_perf_event_init(struct perf_event *event)
+static int __x86_pmu_event_init(struct perf_event *event)
 {
 	int err;
 
@@ -544,11 +559,8 @@
 		if (atomic_read(&active_events) == 0) {
 			if (!reserve_pmc_hardware())
 				err = -EBUSY;
-			else {
-				err = reserve_ds_buffers();
-				if (err)
-					release_pmc_hardware();
-			}
+			else
+				reserve_ds_buffers();
 		}
 		if (!err)
 			atomic_inc(&active_events);
@@ -584,7 +596,7 @@
 	}
 }
 
-void hw_perf_disable(void)
+static void x86_pmu_disable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -619,7 +631,7 @@
 	}
 }
 
-static const struct pmu pmu;
+static struct pmu pmu;
 
 static inline int is_x86_event(struct perf_event *event)
 {
@@ -801,10 +813,10 @@
 		hwc->last_tag == cpuc->tags[i];
 }
 
-static int x86_pmu_start(struct perf_event *event);
-static void x86_pmu_stop(struct perf_event *event);
+static void x86_pmu_start(struct perf_event *event, int flags);
+static void x86_pmu_stop(struct perf_event *event, int flags);
 
-void hw_perf_enable(void)
+static void x86_pmu_enable(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct perf_event *event;
@@ -840,7 +852,14 @@
 			    match_prev_assignment(hwc, cpuc, i))
 				continue;
 
-			x86_pmu_stop(event);
+			/*
+			 * Ensure we don't accidentally enable a stopped
+			 * counter simply because we rescheduled.
+			 */
+			if (hwc->state & PERF_HES_STOPPED)
+				hwc->state |= PERF_HES_ARCH;
+
+			x86_pmu_stop(event, PERF_EF_UPDATE);
 		}
 
 		for (i = 0; i < cpuc->n_events; i++) {
@@ -852,7 +871,10 @@
 			else if (i < n_running)
 				continue;
 
-			x86_pmu_start(event);
+			if (hwc->state & PERF_HES_ARCH)
+				continue;
+
+			x86_pmu_start(event, PERF_EF_RELOAD);
 		}
 		cpuc->n_added = 0;
 		perf_events_lapic_init();
@@ -953,15 +975,12 @@
 }
 
 /*
- * activate a single event
+ * Add a single event to the PMU.
  *
  * The event is added to the group of enabled events
  * but only if it can be scehduled with existing events.
- *
- * Called with PMU disabled. If successful and return value 1,
- * then guaranteed to call perf_enable() and hw_perf_enable()
  */
-static int x86_pmu_enable(struct perf_event *event)
+static int x86_pmu_add(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc;
@@ -970,58 +989,67 @@
 
 	hwc = &event->hw;
 
+	perf_pmu_disable(event->pmu);
 	n0 = cpuc->n_events;
-	n = collect_events(cpuc, event, false);
-	if (n < 0)
-		return n;
+	ret = n = collect_events(cpuc, event, false);
+	if (ret < 0)
+		goto out;
+
+	hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+	if (!(flags & PERF_EF_START))
+		hwc->state |= PERF_HES_ARCH;
 
 	/*
 	 * If group events scheduling transaction was started,
 	 * skip the schedulability test here, it will be peformed
-	 * at commit time(->commit_txn) as a whole
+	 * at commit time (->commit_txn) as a whole
 	 */
 	if (cpuc->group_flag & PERF_EVENT_TXN)
-		goto out;
+		goto done_collect;
 
 	ret = x86_pmu.schedule_events(cpuc, n, assign);
 	if (ret)
-		return ret;
+		goto out;
 	/*
 	 * copy new assignment, now we know it is possible
 	 * will be used by hw_perf_enable()
 	 */
 	memcpy(cpuc->assign, assign, n*sizeof(int));
 
-out:
+done_collect:
 	cpuc->n_events = n;
 	cpuc->n_added += n - n0;
 	cpuc->n_txn += n - n0;
 
-	return 0;
+	ret = 0;
+out:
+	perf_pmu_enable(event->pmu);
+	return ret;
 }
 
-static int x86_pmu_start(struct perf_event *event)
+static void x86_pmu_start(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int idx = event->hw.idx;
 
-	if (idx == -1)
-		return -EAGAIN;
+	if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+		return;
+
+	if (WARN_ON_ONCE(idx == -1))
+		return;
+
+	if (flags & PERF_EF_RELOAD) {
+		WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+		x86_perf_event_set_period(event);
+	}
+
+	event->hw.state = 0;
 
-	x86_perf_event_set_period(event);
 	cpuc->events[idx] = event;
 	__set_bit(idx, cpuc->active_mask);
 	__set_bit(idx, cpuc->running);
 	x86_pmu.enable(event);
 	perf_event_update_userpage(event);
-
-	return 0;
-}
-
-static void x86_pmu_unthrottle(struct perf_event *event)
-{
-	int ret = x86_pmu_start(event);
-	WARN_ON_ONCE(ret);
 }
 
 void perf_event_print_debug(void)
@@ -1078,27 +1106,29 @@
 	local_irq_restore(flags);
 }
 
-static void x86_pmu_stop(struct perf_event *event)
+static void x86_pmu_stop(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-
-	if (!__test_and_clear_bit(idx, cpuc->active_mask))
-		return;
 
-	x86_pmu.disable(event);
-
-	/*
-	 * Drain the remaining delta count out of a event
-	 * that we are disabling:
-	 */
-	x86_perf_event_update(event);
+	if (__test_and_clear_bit(hwc->idx, cpuc->active_mask)) {
+		x86_pmu.disable(event);
+		cpuc->events[hwc->idx] = NULL;
+		WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+		hwc->state |= PERF_HES_STOPPED;
+	}
 
-	cpuc->events[idx] = NULL;
+	if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+		/*
+		 * Drain the remaining delta count out of a event
+		 * that we are disabling:
+		 */
+		x86_perf_event_update(event);
+		hwc->state |= PERF_HES_UPTODATE;
+	}
 }
 
-static void x86_pmu_disable(struct perf_event *event)
+static void x86_pmu_del(struct perf_event *event, int flags)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int i;
@@ -1111,7 +1141,7 @@
 	if (cpuc->group_flag & PERF_EVENT_TXN)
 		return;
 
-	x86_pmu_stop(event);
+	x86_pmu_stop(event, PERF_EF_UPDATE);
 
 	for (i = 0; i < cpuc->n_events; i++) {
 		if (event == cpuc->event_list[i]) {
@@ -1134,7 +1164,6 @@
 	struct perf_sample_data data;
 	struct cpu_hw_events *cpuc;
 	struct perf_event *event;
-	struct hw_perf_event *hwc;
 	int idx, handled = 0;
 	u64 val;
 
@@ -1155,7 +1184,6 @@
 		}
 
 		event = cpuc->events[idx];
-		hwc = &event->hw;
 
 		val = x86_perf_event_update(event);
 		if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
@@ -1171,7 +1199,7 @@
 			continue;
 
 		if (perf_event_overflow(event, 1, &data, regs))
-			x86_pmu_stop(event);
+			x86_pmu_stop(event, 0);
 	}
 
 	if (handled)
@@ -1180,25 +1208,6 @@
 	return handled;
 }
 
-void smp_perf_pending_interrupt(struct pt_regs *regs)
-{
-	irq_enter();
-	ack_APIC_irq();
-	inc_irq_stat(apic_pending_irqs);
-	perf_event_do_pending();
-	irq_exit();
-}
-
-void set_perf_event_pending(void)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	if (!x86_pmu.apic || !x86_pmu_initialized())
-		return;
-
-	apic->send_IPI_self(LOCAL_PENDING_VECTOR);
-#endif
-}
-
 void perf_events_lapic_init(void)
 {
 	if (!x86_pmu.apic || !x86_pmu_initialized())
@@ -1377,6 +1386,12 @@
 
 	pmu_check_apic();
 
+	/* sanity check that the hardware exists or is emulated */
+	if (!check_hw_exists()) {
+		pr_cont("Broken PMU hardware detected, software events only.\n");
+		return;
+	}
+
 	pr_cont("%s PMU driver.\n", x86_pmu.name);
 
 	if (x86_pmu.quirks)
@@ -1388,7 +1403,6 @@
 		x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
 	}
 	x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
-	perf_max_events = x86_pmu.num_counters;
 
 	if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) {
 		WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
@@ -1424,6 +1438,7 @@
 	pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_counters_fixed);
 	pr_info("... event mask:             %016Lx\n", x86_pmu.intel_ctrl);
 
+	perf_pmu_register(&pmu);
 	perf_cpu_notifier(x86_pmu_notifier);
 }
 
@@ -1437,10 +1452,11 @@
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-static void x86_pmu_start_txn(const struct pmu *pmu)
+static void x86_pmu_start_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
+	perf_pmu_disable(pmu);
 	cpuc->group_flag |= PERF_EVENT_TXN;
 	cpuc->n_txn = 0;
 }
@@ -1450,7 +1466,7 @@
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-static void x86_pmu_cancel_txn(const struct pmu *pmu)
+static void x86_pmu_cancel_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -1460,6 +1476,7 @@
 	 */
 	cpuc->n_added -= cpuc->n_txn;
 	cpuc->n_events -= cpuc->n_txn;
+	perf_pmu_enable(pmu);
 }
 
 /*
@@ -1467,7 +1484,7 @@
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-static int x86_pmu_commit_txn(const struct pmu *pmu)
+static int x86_pmu_commit_txn(struct pmu *pmu)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	int assign[X86_PMC_IDX_MAX];
@@ -1489,22 +1506,10 @@
 	memcpy(cpuc->assign, assign, n*sizeof(int));
 
 	cpuc->group_flag &= ~PERF_EVENT_TXN;
-
+	perf_pmu_enable(pmu);
 	return 0;
 }
 
-static const struct pmu pmu = {
-	.enable		= x86_pmu_enable,
-	.disable	= x86_pmu_disable,
-	.start		= x86_pmu_start,
-	.stop		= x86_pmu_stop,
-	.read		= x86_pmu_read,
-	.unthrottle	= x86_pmu_unthrottle,
-	.start_txn	= x86_pmu_start_txn,
-	.cancel_txn	= x86_pmu_cancel_txn,
-	.commit_txn	= x86_pmu_commit_txn,
-};
-
 /*
  * validate that we can schedule this event
  */
@@ -1579,12 +1584,22 @@
 	return ret;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+int x86_pmu_event_init(struct perf_event *event)
 {
-	const struct pmu *tmp;
+	struct pmu *tmp;
 	int err;
 
-	err = __hw_perf_event_init(event);
+	switch (event->attr.type) {
+	case PERF_TYPE_RAW:
+	case PERF_TYPE_HARDWARE:
+	case PERF_TYPE_HW_CACHE:
+		break;
+
+	default:
+		return -ENOENT;
+	}
+
+	err = __x86_pmu_event_init(event);
 	if (!err) {
 		/*
 		 * we temporarily connect event to its pmu
@@ -1604,26 +1619,31 @@
 	if (err) {
 		if (event->destroy)
 			event->destroy(event);
-		return ERR_PTR(err);
 	}
 
-	return &pmu;
+	return err;
 }
 
-/*
- * callchain support
- */
+static struct pmu pmu = {
+	.pmu_enable	= x86_pmu_enable,
+	.pmu_disable	= x86_pmu_disable,
 
-static inline
-void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-	if (entry->nr < PERF_MAX_STACK_DEPTH)
-		entry->ip[entry->nr++] = ip;
-}
+	.event_init	= x86_pmu_event_init,
 
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry);
+	.add		= x86_pmu_add,
+	.del		= x86_pmu_del,
+	.start		= x86_pmu_start,
+	.stop		= x86_pmu_stop,
+	.read		= x86_pmu_read,
 
+	.start_txn	= x86_pmu_start_txn,
+	.cancel_txn	= x86_pmu_cancel_txn,
+	.commit_txn	= x86_pmu_commit_txn,
+};
+
+/*
+ * callchain support
+ */
 
 static void
 backtrace_warning_symbol(void *data, char *msg, unsigned long symbol)
@@ -1645,7 +1665,7 @@
 {
 	struct perf_callchain_entry *entry = data;
 
-	callchain_store(entry, addr);
+	perf_callchain_store(entry, addr);
 }
 
 static const struct stacktrace_ops backtrace_ops = {
@@ -1656,11 +1676,15 @@
 	.walk_stack		= print_context_stack_bp,
 };
 
-static void
-perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-	callchain_store(entry, PERF_CONTEXT_KERNEL);
-	callchain_store(entry, regs->ip);
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		/* TODO: We don't support guest os callchain now */
+		return;
+	}
+
+	perf_callchain_store(entry, regs->ip);
 
 	dump_trace(NULL, regs, NULL, regs->bp, &backtrace_ops, entry);
 }
@@ -1689,7 +1713,7 @@
 		if (fp < compat_ptr(regs->sp))
 			break;
 
-		callchain_store(entry, frame.return_address);
+		perf_callchain_store(entry, frame.return_address);
 		fp = compat_ptr(frame.next_frame);
 	}
 	return 1;
@@ -1702,19 +1726,20 @@
 }
 #endif
 
-static void
-perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
 	struct stack_frame frame;
 	const void __user *fp;
 
-	if (!user_mode(regs))
-		regs = task_pt_regs(current);
+	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+		/* TODO: We don't support guest os callchain now */
+		return;
+	}
 
 	fp = (void __user *)regs->bp;
 
-	callchain_store(entry, PERF_CONTEXT_USER);
-	callchain_store(entry, regs->ip);
+	perf_callchain_store(entry, regs->ip);
 
 	if (perf_callchain_user32(regs, entry))
 		return;
@@ -1731,52 +1756,11 @@
 		if ((unsigned long)fp < regs->sp)
 			break;
 
-		callchain_store(entry, frame.return_address);
+		perf_callchain_store(entry, frame.return_address);
 		fp = frame.next_frame;
 	}
 }
 
-static void
-perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
-{
-	int is_user;
-
-	if (!regs)
-		return;
-
-	is_user = user_mode(regs);
-
-	if (is_user && current->state != TASK_RUNNING)
-		return;
-
-	if (!is_user)
-		perf_callchain_kernel(regs, entry);
-
-	if (current->mm)
-		perf_callchain_user(regs, entry);
-}
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-	struct perf_callchain_entry *entry;
-
-	if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-		/* TODO: We don't support guest os callchain now */
-		return NULL;
-	}
-
-	if (in_nmi())
-		entry = &__get_cpu_var(pmc_nmi_entry);
-	else
-		entry = &__get_cpu_var(pmc_irq_entry);
-
-	entry->nr = 0;
-
-	perf_do_callchain(regs, entry);
-
-	return entry;
-}
-
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
 	unsigned long ip;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_intel.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_intel.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_intel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_intel.c	2011-01-04 19:50:19.000000000 -0500
@@ -713,18 +713,18 @@
 	struct cpu_hw_events *cpuc;
 	int bit, loops;
 	u64 status;
-	int handled = 0;
+	int handled;
 
 	perf_sample_data_init(&data, 0);
 
 	cpuc = &__get_cpu_var(cpu_hw_events);
 
 	intel_pmu_disable_all();
-	intel_pmu_drain_bts_buffer();
+	handled = intel_pmu_drain_bts_buffer();
 	status = intel_pmu_get_status();
 	if (!status) {
 		intel_pmu_enable_all(0);
-		return 0;
+		return handled;
 	}
 
 	loops = 0;
@@ -763,7 +763,7 @@
 		data.period = event->hw.last_period;
 
 		if (perf_event_overflow(event, 1, &data, regs))
-			x86_pmu_stop(event);
+			x86_pmu_stop(event, 0);
 	}
 
 	/*
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_intel_ds.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_intel_ds.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_intel_ds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_intel_ds.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,6 +74,107 @@
 	wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
 }
 
+static int alloc_pebs_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	int node = cpu_to_node(cpu);
+	int max, thresh = 1; /* always use a single PEBS record */
+	void *buffer;
+
+	if (!x86_pmu.pebs)
+		return 0;
+
+	buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+	if (unlikely(!buffer))
+		return -ENOMEM;
+
+	max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
+
+	ds->pebs_buffer_base = (u64)(unsigned long)buffer;
+	ds->pebs_index = ds->pebs_buffer_base;
+	ds->pebs_absolute_maximum = ds->pebs_buffer_base +
+		max * x86_pmu.pebs_record_size;
+
+	ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
+		thresh * x86_pmu.pebs_record_size;
+
+	return 0;
+}
+
+static void release_pebs_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds || !x86_pmu.pebs)
+		return;
+
+	kfree((void *)(unsigned long)ds->pebs_buffer_base);
+	ds->pebs_buffer_base = 0;
+}
+
+static int alloc_bts_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+	int node = cpu_to_node(cpu);
+	int max, thresh;
+	void *buffer;
+
+	if (!x86_pmu.bts)
+		return 0;
+
+	buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+	if (unlikely(!buffer))
+		return -ENOMEM;
+
+	max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
+	thresh = max / 16;
+
+	ds->bts_buffer_base = (u64)(unsigned long)buffer;
+	ds->bts_index = ds->bts_buffer_base;
+	ds->bts_absolute_maximum = ds->bts_buffer_base +
+		max * BTS_RECORD_SIZE;
+	ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
+		thresh * BTS_RECORD_SIZE;
+
+	return 0;
+}
+
+static void release_bts_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds || !x86_pmu.bts)
+		return;
+
+	kfree((void *)(unsigned long)ds->bts_buffer_base);
+	ds->bts_buffer_base = 0;
+}
+
+static int alloc_ds_buffer(int cpu)
+{
+	int node = cpu_to_node(cpu);
+	struct debug_store *ds;
+
+	ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
+	if (unlikely(!ds))
+		return -ENOMEM;
+
+	per_cpu(cpu_hw_events, cpu).ds = ds;
+
+	return 0;
+}
+
+static void release_ds_buffer(int cpu)
+{
+	struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+	if (!ds)
+		return;
+
+	per_cpu(cpu_hw_events, cpu).ds = NULL;
+	kfree(ds);
+}
+
 static void release_ds_buffers(void)
 {
 	int cpu;
@@ -82,93 +183,77 @@
 		return;
 
 	get_online_cpus();
-
 	for_each_online_cpu(cpu)
 		fini_debug_store_on_cpu(cpu);
 
 	for_each_possible_cpu(cpu) {
-		struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
-
-		if (!ds)
-			continue;
-
-		per_cpu(cpu_hw_events, cpu).ds = NULL;
-
-		kfree((void *)(unsigned long)ds->pebs_buffer_base);
-		kfree((void *)(unsigned long)ds->bts_buffer_base);
-		kfree(ds);
+		release_pebs_buffer(cpu);
+		release_bts_buffer(cpu);
+		release_ds_buffer(cpu);
 	}
-
 	put_online_cpus();
 }
 
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
 {
-	int cpu, err = 0;
+	int bts_err = 0, pebs_err = 0;
+	int cpu;
+
+	x86_pmu.bts_active = 0;
+	x86_pmu.pebs_active = 0;
 
 	if (!x86_pmu.bts && !x86_pmu.pebs)
-		return 0;
+		return;
+
+	if (!x86_pmu.bts)
+		bts_err = 1;
+
+	if (!x86_pmu.pebs)
+		pebs_err = 1;
 
 	get_online_cpus();
 
 	for_each_possible_cpu(cpu) {
-		struct debug_store *ds;
-		void *buffer;
-		int max, thresh;
-
-		err = -ENOMEM;
-		ds = kzalloc(sizeof(*ds), GFP_KERNEL);
-		if (unlikely(!ds))
-			break;
-		per_cpu(cpu_hw_events, cpu).ds = ds;
+		if (alloc_ds_buffer(cpu)) {
+			bts_err = 1;
+			pebs_err = 1;
+		}
 
-		if (x86_pmu.bts) {
-			buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
-			if (unlikely(!buffer))
-				break;
+		if (!bts_err && alloc_bts_buffer(cpu))
+			bts_err = 1;
 
-			max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
-			thresh = max / 16;
+		if (!pebs_err && alloc_pebs_buffer(cpu))
+			pebs_err = 1;
 
-			ds->bts_buffer_base = (u64)(unsigned long)buffer;
-			ds->bts_index = ds->bts_buffer_base;
-			ds->bts_absolute_maximum = ds->bts_buffer_base +
-				max * BTS_RECORD_SIZE;
-			ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
-				thresh * BTS_RECORD_SIZE;
-		}
+		if (bts_err && pebs_err)
+			break;
+	}
 
-		if (x86_pmu.pebs) {
-			buffer = kzalloc(PEBS_BUFFER_SIZE, GFP_KERNEL);
-			if (unlikely(!buffer))
-				break;
+	if (bts_err) {
+		for_each_possible_cpu(cpu)
+			release_bts_buffer(cpu);
+	}
 
-			max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
+	if (pebs_err) {
+		for_each_possible_cpu(cpu)
+			release_pebs_buffer(cpu);
+	}
 
-			ds->pebs_buffer_base = (u64)(unsigned long)buffer;
-			ds->pebs_index = ds->pebs_buffer_base;
-			ds->pebs_absolute_maximum = ds->pebs_buffer_base +
-				max * x86_pmu.pebs_record_size;
-			/*
-			 * Always use single record PEBS
-			 */
-			ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
-				x86_pmu.pebs_record_size;
-		}
+	if (bts_err && pebs_err) {
+		for_each_possible_cpu(cpu)
+			release_ds_buffer(cpu);
+	} else {
+		if (x86_pmu.bts && !bts_err)
+			x86_pmu.bts_active = 1;
 
-		err = 0;
-	}
+		if (x86_pmu.pebs && !pebs_err)
+			x86_pmu.pebs_active = 1;
 
-	if (err)
-		release_ds_buffers();
-	else {
 		for_each_online_cpu(cpu)
 			init_debug_store_on_cpu(cpu);
 	}
 
 	put_online_cpus();
-
-	return err;
 }
 
 /*
@@ -214,7 +299,7 @@
 	update_debugctlmsr(debugctlmsr);
 }
 
-static void intel_pmu_drain_bts_buffer(void)
+static int intel_pmu_drain_bts_buffer(void)
 {
 	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 	struct debug_store *ds = cpuc->ds;
@@ -231,16 +316,16 @@
 	struct pt_regs regs;
 
 	if (!event)
-		return;
+		return 0;
 
-	if (!ds)
-		return;
+	if (!x86_pmu.bts_active)
+		return 0;
 
 	at  = (struct bts_record *)(unsigned long)ds->bts_buffer_base;
 	top = (struct bts_record *)(unsigned long)ds->bts_index;
 
 	if (top <= at)
-		return;
+		return 0;
 
 	ds->bts_index = ds->bts_buffer_base;
 
@@ -256,7 +341,7 @@
 	perf_prepare_sample(&header, &data, event, &regs);
 
 	if (perf_output_begin(&handle, event, header.size * (top - at), 1, 1))
-		return;
+		return 1;
 
 	for (; at < top; at++) {
 		data.ip		= at->from;
@@ -270,6 +355,7 @@
 	/* There's new data available. */
 	event->hw.interrupts++;
 	event->pending_kill = POLL_IN;
+	return 1;
 }
 
 /*
@@ -491,7 +577,7 @@
 		regs.flags &= ~PERF_EFLAGS_EXACT;
 
 	if (perf_event_overflow(event, 1, &data, &regs))
-		x86_pmu_stop(event);
+		x86_pmu_stop(event, 0);
 }
 
 static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
@@ -502,7 +588,7 @@
 	struct pebs_record_core *at, *top;
 	int n;
 
-	if (!ds || !x86_pmu.pebs)
+	if (!x86_pmu.pebs_active)
 		return;
 
 	at  = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base;
@@ -544,7 +630,7 @@
 	u64 status = 0;
 	int bit, n;
 
-	if (!ds || !x86_pmu.pebs)
+	if (!x86_pmu.pebs_active)
 		return;
 
 	at  = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
@@ -629,9 +715,8 @@
 
 #else /* CONFIG_CPU_SUP_INTEL */
 
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
 {
-	return 0;
 }
 
 static void release_ds_buffers(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_p4.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_p4.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/perf_event_p4.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/perf_event_p4.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,6 +18,8 @@
 struct p4_event_bind {
 	unsigned int opcode;			/* Event code and ESCR selector */
 	unsigned int escr_msr[2];		/* ESCR MSR for this event */
+	unsigned int escr_emask;		/* valid ESCR EventMask bits */
+	unsigned int shared;			/* event is shared across threads */
 	char cntr[2][P4_CNTR_LIMIT];		/* counter index (offset), -1 on abscence */
 };
 
@@ -66,231 +68,435 @@
 	[P4_EVENT_TC_DELIVER_MODE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_TC_DELIVER_MODE),
 		.escr_msr	= { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DD)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DB)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DI)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BD)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BB)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BI)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, ID),
+		.shared		= 1,
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_BPU_FETCH_REQUEST] = {
 		.opcode		= P4_OPCODE(P4_EVENT_BPU_FETCH_REQUEST),
 		.escr_msr	= { MSR_P4_BPU_ESCR0, MSR_P4_BPU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BPU_FETCH_REQUEST, TCMISS),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_ITLB_REFERENCE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_ITLB_REFERENCE),
 		.escr_msr	= { MSR_P4_ITLB_ESCR0, MSR_P4_ITLB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, MISS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT_UK),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_MEMORY_CANCEL] = {
 		.opcode		= P4_OPCODE(P4_EVENT_MEMORY_CANCEL),
 		.escr_msr	= { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, ST_RB_FULL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, 64K_CONF),
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_MEMORY_COMPLETE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_MEMORY_COMPLETE),
 		.escr_msr	= { MSR_P4_SAAT_ESCR0 , MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, LSC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, SSC),
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_LOAD_PORT_REPLAY] = {
 		.opcode		= P4_OPCODE(P4_EVENT_LOAD_PORT_REPLAY),
 		.escr_msr	= { MSR_P4_SAAT_ESCR0, MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_LOAD_PORT_REPLAY, SPLIT_LD),
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_STORE_PORT_REPLAY] = {
 		.opcode		= P4_OPCODE(P4_EVENT_STORE_PORT_REPLAY),
 		.escr_msr	= { MSR_P4_SAAT_ESCR0 ,  MSR_P4_SAAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_STORE_PORT_REPLAY, SPLIT_ST),
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_MOB_LOAD_REPLAY] = {
 		.opcode		= P4_OPCODE(P4_EVENT_MOB_LOAD_REPLAY),
 		.escr_msr	= { MSR_P4_MOB_ESCR0, MSR_P4_MOB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STA)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STD)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, PARTIAL_DATA)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, UNALGN_ADDR),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_PAGE_WALK_TYPE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_PAGE_WALK_TYPE),
 		.escr_msr	= { MSR_P4_PMH_ESCR0, MSR_P4_PMH_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, DTMISS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, ITMISS),
+		.shared		= 1,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_BSQ_CACHE_REFERENCE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_BSQ_CACHE_REFERENCE),
 		.escr_msr	= { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITM)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITM)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_MISS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_MISS)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, WR_2ndL_MISS),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_IOQ_ALLOCATION] = {
 		.opcode		= P4_OPCODE(P4_EVENT_IOQ_ALLOCATION),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, DEFAULT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_READ)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_WRITE)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_UC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WB)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OWN)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OTHER)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, PREFETCH),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_IOQ_ACTIVE_ENTRIES] = {	/* shared ESCR */
 		.opcode		= P4_OPCODE(P4_EVENT_IOQ_ACTIVE_ENTRIES),
 		.escr_msr	= { MSR_P4_FSB_ESCR1,  MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, DEFAULT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_READ)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_WRITE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_UC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WC)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WT)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WB)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OTHER)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, PREFETCH),
 		.cntr		= { {2, -1, -1}, {3, -1, -1} },
 	},
 	[P4_EVENT_FSB_DATA_ACTIVITY] = {
 		.opcode		= P4_OPCODE(P4_EVENT_FSB_DATA_ACTIVITY),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_DRV)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OTHER)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_DRV)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OWN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OTHER),
+		.shared		= 1,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_BSQ_ALLOCATION] = {		/* shared ESCR, broken CCCR1 */
 		.opcode		= P4_OPCODE(P4_EVENT_BSQ_ALLOCATION),
 		.escr_msr	= { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR0 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_IO_TYPE)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LOCK_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_CACHE_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_SPLIT_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_DEM_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_ORD_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE2),
 		.cntr		= { {0, -1, -1}, {1, -1, -1} },
 	},
 	[P4_EVENT_BSQ_ACTIVE_ENTRIES] = {	/* shared ESCR */
 		.opcode		= P4_OPCODE(P4_EVENT_BSQ_ACTIVE_ENTRIES),
 		.escr_msr	= { MSR_P4_BSU_ESCR1 , MSR_P4_BSU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_IO_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LOCK_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_CACHE_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_SPLIT_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_DEM_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_ORD_TYPE)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE0)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE1)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE2),
 		.cntr		= { {2, -1, -1}, {3, -1, -1} },
 	},
 	[P4_EVENT_SSE_INPUT_ASSIST] = {
 		.opcode		= P4_OPCODE(P4_EVENT_SSE_INPUT_ASSIST),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SSE_INPUT_ASSIST, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_PACKED_SP_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_PACKED_SP_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_SP_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_PACKED_DP_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_PACKED_DP_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_DP_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_SCALAR_SP_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_SCALAR_SP_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_SP_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_SCALAR_DP_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_SCALAR_DP_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_DP_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_64BIT_MMX_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_64BIT_MMX_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_64BIT_MMX_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_128BIT_MMX_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_128BIT_MMX_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_128BIT_MMX_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_X87_FP_UOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_X87_FP_UOP),
 		.escr_msr	= { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_FP_UOP, ALL),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_TC_MISC] = {
 		.opcode		= P4_OPCODE(P4_EVENT_TC_MISC),
 		.escr_msr	= { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_MISC, FLUSH),
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_GLOBAL_POWER_EVENTS] = {
 		.opcode		= P4_OPCODE(P4_EVENT_GLOBAL_POWER_EVENTS),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING),
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_TC_MS_XFER] = {
 		.opcode		= P4_OPCODE(P4_EVENT_TC_MS_XFER),
 		.escr_msr	= { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_TC_MS_XFER, CISC),
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_UOP_QUEUE_WRITES] = {
 		.opcode		= P4_OPCODE(P4_EVENT_UOP_QUEUE_WRITES),
 		.escr_msr	= { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_BUILD)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_DELIVER)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_ROM),
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE),
 		.escr_msr	= { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR0 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CONDITIONAL)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CALL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, RETURN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, INDIRECT),
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_RETIRED_BRANCH_TYPE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_RETIRED_BRANCH_TYPE),
 		.escr_msr	= { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CONDITIONAL)	|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CALL)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, RETURN)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, INDIRECT),
 		.cntr		= { {4, 5, -1}, {6, 7, -1} },
 	},
 	[P4_EVENT_RESOURCE_STALL] = {
 		.opcode		= P4_OPCODE(P4_EVENT_RESOURCE_STALL),
 		.escr_msr	= { MSR_P4_ALF_ESCR0, MSR_P4_ALF_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_RESOURCE_STALL, SBFULL),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_WC_BUFFER] = {
 		.opcode		= P4_OPCODE(P4_EVENT_WC_BUFFER),
 		.escr_msr	= { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_EVICTS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_FULL_EVICTS),
+		.shared		= 1,
 		.cntr		= { {8, 9, -1}, {10, 11, -1} },
 	},
 	[P4_EVENT_B2B_CYCLES] = {
 		.opcode		= P4_OPCODE(P4_EVENT_B2B_CYCLES),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_BNR] = {
 		.opcode		= P4_OPCODE(P4_EVENT_BNR),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_SNOOP] = {
 		.opcode		= P4_OPCODE(P4_EVENT_SNOOP),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_RESPONSE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_RESPONSE),
 		.escr_msr	= { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+		.escr_emask	= 0,
 		.cntr		= { {0, -1, -1}, {2, -1, -1} },
 	},
 	[P4_EVENT_FRONT_END_EVENT] = {
 		.opcode		= P4_OPCODE(P4_EVENT_FRONT_END_EVENT),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, BOGUS),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_EXECUTION_EVENT] = {
 		.opcode		= P4_OPCODE(P4_EVENT_EXECUTION_EVENT),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_REPLAY_EVENT] = {
 		.opcode		= P4_OPCODE(P4_EVENT_REPLAY_EVENT),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, BOGUS),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_INSTR_RETIRED] = {
 		.opcode		= P4_OPCODE(P4_EVENT_INSTR_RETIRED),
 		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSNTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSNTAG)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSTAG),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_UOPS_RETIRED] = {
 		.opcode		= P4_OPCODE(P4_EVENT_UOPS_RETIRED),
 		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, BOGUS),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_UOP_TYPE] = {
 		.opcode		= P4_OPCODE(P4_EVENT_UOP_TYPE),
 		.escr_msr	= { MSR_P4_RAT_ESCR0, MSR_P4_RAT_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGLOADS)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGSTORES),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_BRANCH_RETIRED] = {
 		.opcode		= P4_OPCODE(P4_EVENT_BRANCH_RETIRED),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNM)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTP)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTM),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_MISPRED_BRANCH_RETIRED] = {
 		.opcode		= P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED),
 		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+		P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_X87_ASSIST] = {
 		.opcode		= P4_OPCODE(P4_EVENT_X87_ASSIST),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSU)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSO)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAO)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAU)			|
+			P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, PREA),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_MACHINE_CLEAR] = {
 		.opcode		= P4_OPCODE(P4_EVENT_MACHINE_CLEAR),
 		.escr_msr	= { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, CLEAR)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, MOCLEAR)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, SMCLEAR),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 	[P4_EVENT_INSTR_COMPLETED] = {
 		.opcode		= P4_OPCODE(P4_EVENT_INSTR_COMPLETED),
 		.escr_msr	= { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+		.escr_emask	=
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, NBOGUS)		|
+			P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, BOGUS),
 		.cntr		= { {12, 13, 16}, {14, 15, 17} },
 	},
 };
@@ -428,29 +634,73 @@
 	return config;
 }
 
+/* check cpu model specifics */
+static bool p4_event_match_cpu_model(unsigned int event_idx)
+{
+	/* INSTR_COMPLETED event only exist for model 3, 4, 6 (Prescott) */
+	if (event_idx == P4_EVENT_INSTR_COMPLETED) {
+		if (boot_cpu_data.x86_model != 3 &&
+			boot_cpu_data.x86_model != 4 &&
+			boot_cpu_data.x86_model != 6)
+			return false;
+	}
+
+	/*
+	 * For info
+	 * - IQ_ESCR0, IQ_ESCR1 only for models 1 and 2
+	 */
+
+	return true;
+}
+
 static int p4_validate_raw_event(struct perf_event *event)
 {
-	unsigned int v;
+	unsigned int v, emask;
 
-	/* user data may have out-of-bound event index */
+	/* User data may have out-of-bound event index */
 	v = p4_config_unpack_event(event->attr.config);
-	if (v >= ARRAY_SIZE(p4_event_bind_map)) {
-		pr_warning("P4 PMU: Unknown event code: %d\n", v);
+	if (v >= ARRAY_SIZE(p4_event_bind_map))
 		return -EINVAL;
+
+	/* It may be unsupported: */
+	if (!p4_event_match_cpu_model(v))
+		return -EINVAL;
+
+	/*
+	 * NOTE: P4_CCCR_THREAD_ANY has not the same meaning as
+	 * in Architectural Performance Monitoring, it means not
+	 * on _which_ logical cpu to count but rather _when_, ie it
+	 * depends on logical cpu state -- count event if one cpu active,
+	 * none, both or any, so we just allow user to pass any value
+	 * desired.
+	 *
+	 * In turn we always set Tx_OS/Tx_USR bits bound to logical
+	 * cpu without their propagation to another cpu
+	 */
+
+	/*
+	 * if an event is shared accross the logical threads
+	 * the user needs special permissions to be able to use it
+	 */
+	if (p4_event_bind_map[v].shared) {
+		if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+			return -EACCES;
 	}
 
+	/* ESCR EventMask bits may be invalid */
+	emask = p4_config_unpack_escr(event->attr.config) & P4_ESCR_EVENTMASK_MASK;
+	if (emask & ~p4_event_bind_map[v].escr_emask)
+		return -EINVAL;
+
 	/*
-	 * it may have some screwed PEBS bits
+	 * it may have some invalid PEBS bits
 	 */
-	if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE)) {
-		pr_warning("P4 PMU: PEBS are not supported yet\n");
+	if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE))
 		return -EINVAL;
-	}
+
 	v = p4_config_unpack_metric(event->attr.config);
-	if (v >= ARRAY_SIZE(p4_pebs_bind_map)) {
-		pr_warning("P4 PMU: Unknown metric code: %d\n", v);
+	if (v >= ARRAY_SIZE(p4_pebs_bind_map))
 		return -EINVAL;
-	}
 
 	return 0;
 }
@@ -478,27 +728,21 @@
 
 	if (event->attr.type == PERF_TYPE_RAW) {
 
+		/*
+		 * Clear bits we reserve to be managed by kernel itself
+		 * and never allowed from a user space
+		 */
+		 event->attr.config &= P4_CONFIG_MASK;
+
 		rc = p4_validate_raw_event(event);
 		if (rc)
 			goto out;
 
 		/*
-		 * We don't control raw events so it's up to the caller
-		 * to pass sane values (and we don't count the thread number
-		 * on HT machine but allow HT-compatible specifics to be
-		 * passed on)
-		 *
 		 * Note that for RAW events we allow user to use P4_CCCR_RESERVED
 		 * bits since we keep additional info here (for cache events and etc)
-		 *
-		 * XXX: HT wide things should check perf_paranoid_cpu() &&
-		 *      CAP_SYS_ADMIN
 		 */
-		event->hw.config |= event->attr.config &
-			(p4_config_pack_escr(P4_ESCR_MASK_HT) |
-			 p4_config_pack_cccr(P4_CCCR_MASK_HT | P4_CCCR_RESERVED));
-
-		event->hw.config &= ~P4_CCCR_FORCE_OVF;
+		event->hw.config |= event->attr.config;
 	}
 
 	rc = x86_setup_perfctr(event);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/scattered.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/scattered.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpu/scattered.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpu/scattered.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,12 @@
 		{ X86_FEATURE_LBRV,		CR_EDX, 1, 0x8000000a, 0 },
 		{ X86_FEATURE_SVML,		CR_EDX, 2, 0x8000000a, 0 },
 		{ X86_FEATURE_NRIPS,		CR_EDX, 3, 0x8000000a, 0 },
+		{ X86_FEATURE_TSCRATEMSR,	CR_EDX, 4, 0x8000000a, 0 },
+		{ X86_FEATURE_VMCBCLEAN,	CR_EDX, 5, 0x8000000a, 0 },
+		{ X86_FEATURE_FLUSHBYASID,	CR_EDX, 6, 0x8000000a, 0 },
+		{ X86_FEATURE_DECODEASSISTS,	CR_EDX, 7, 0x8000000a, 0 },
+		{ X86_FEATURE_PAUSEFILTER,	CR_EDX,10, 0x8000000a, 0 },
+		{ X86_FEATURE_PFTHRESHOLD,	CR_EDX,12, 0x8000000a, 0 },
 		{ 0, 0, 0, 0, 0 }
 	};
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/cpuid.c linux-libre-2.6.37-gnu/arch/x86/kernel/cpuid.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/cpuid.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/cpuid.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/device.h>
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/crash_dump_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/crash_dump_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/crash_dump_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/crash_dump_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,7 +61,7 @@
 	if (!is_crashed_pfn_valid(pfn))
 		return -EFAULT;
 
-	vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
+	vaddr = kmap_atomic_pfn(pfn);
 
 	if (!userbuf) {
 		memcpy(buf, (vaddr + offset), csize);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/crash_dump_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/crash_dump_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/crash_dump_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/crash_dump_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 	if (!csize)
 		return 0;
 
-	vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+	vaddr = ioremap_cache(pfn << PAGE_SHIFT, PAGE_SIZE);
 	if (!vaddr)
 		return -ENOMEM;
 
@@ -46,6 +46,7 @@
 	} else
 		memcpy(buf, vaddr + offset, csize);
 
+	set_iounmap_nonlazy();
 	iounmap(vaddr);
 	return csize;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/dumpstack_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/dumpstack_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/dumpstack_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/dumpstack_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -82,11 +82,11 @@
 		if (kstack_end(stack))
 			break;
 		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-			printk("\n%s", log_lvl);
-		printk(" %08lx", *stack++);
+			printk(KERN_CONT "\n");
+		printk(KERN_CONT " %08lx", *stack++);
 		touch_nmi_watchdog();
 	}
-	printk("\n");
+	printk(KERN_CONT "\n");
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/dumpstack_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/dumpstack_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/dumpstack_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/dumpstack_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -265,20 +265,20 @@
 		if (stack >= irq_stack && stack <= irq_stack_end) {
 			if (stack == irq_stack_end) {
 				stack = (unsigned long *) (irq_stack_end[-1]);
-				printk(" <EOI> ");
+				printk(KERN_CONT " <EOI> ");
 			}
 		} else {
 		if (((long) stack & (THREAD_SIZE-1)) == 0)
 			break;
 		}
 		if (i && ((i % STACKSLOTS_PER_LINE) == 0))
-			printk("\n%s", log_lvl);
-		printk(" %016lx", *stack++);
+			printk(KERN_CONT "\n");
+		printk(KERN_CONT " %016lx", *stack++);
 		touch_nmi_watchdog();
 	}
 	preempt_enable();
 
-	printk("\n");
+	printk(KERN_CONT "\n");
 	show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/e820.c linux-libre-2.6.37-gnu/arch/x86/kernel/e820.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/e820.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/e820.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/pfn.h>
 #include <linux/suspend.h>
 #include <linux/firmware-map.h>
+#include <linux/memblock.h>
 
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -738,73 +739,7 @@
 #endif
 
 /*
- * Find a free area with specified alignment in a specific range.
- */
-u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align)
-{
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		u64 addr;
-		u64 ei_start, ei_last;
-
-		if (ei->type != E820_RAM)
-			continue;
-
-		ei_last = ei->addr + ei->size;
-		ei_start = ei->addr;
-		addr = find_early_area(ei_start, ei_last, start, end,
-					 size, align);
-
-		if (addr != -1ULL)
-			return addr;
-	}
-	return -1ULL;
-}
-
-u64 __init find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align)
-{
-	return find_e820_area(start, end, size, align);
-}
-
-u64 __init get_max_mapped(void)
-{
-	u64 end = max_pfn_mapped;
-
-	end <<= PAGE_SHIFT;
-
-	return end;
-}
-/*
- * Find next free range after *start
- */
-u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
-{
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++) {
-		struct e820entry *ei = &e820.map[i];
-		u64 addr;
-		u64 ei_start, ei_last;
-
-		if (ei->type != E820_RAM)
-			continue;
-
-		ei_last = ei->addr + ei->size;
-		ei_start = ei->addr;
-		addr = find_early_area_size(ei_start, ei_last, start,
-					 sizep, align);
-
-		if (addr != -1ULL)
-			return addr;
-	}
-
-	return -1ULL;
-}
-
-/*
- * pre allocated 4k and reserved it in e820
+ * pre allocated 4k and reserved it in memblock and e820_saved
  */
 u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
 {
@@ -813,8 +748,8 @@
 	u64 start;
 
 	for (start = startt; ; start += size) {
-		start = find_e820_area_size(start, &size, align);
-		if (!(start + 1))
+		start = memblock_x86_find_in_range_size(start, &size, align);
+		if (start == MEMBLOCK_ERROR)
 			return 0;
 		if (size >= sizet)
 			break;
@@ -830,10 +765,9 @@
 	addr = round_down(start + size - sizet, align);
 	if (addr < start)
 		return 0;
-	e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
+	memblock_x86_reserve_range(addr, addr + sizet, "new next");
 	e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
-	printk(KERN_INFO "update e820 for early_reserve_e820\n");
-	update_e820();
+	printk(KERN_INFO "update e820_saved for early_reserve_e820\n");
 	update_e820_saved();
 
 	return addr;
@@ -895,74 +829,6 @@
 {
 	return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
 }
-/*
- * Finds an active region in the address range from start_pfn to last_pfn and
- * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
- */
-int __init e820_find_active_region(const struct e820entry *ei,
-				  unsigned long start_pfn,
-				  unsigned long last_pfn,
-				  unsigned long *ei_startpfn,
-				  unsigned long *ei_endpfn)
-{
-	u64 align = PAGE_SIZE;
-
-	*ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT;
-	*ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT;
-
-	/* Skip map entries smaller than a page */
-	if (*ei_startpfn >= *ei_endpfn)
-		return 0;
-
-	/* Skip if map is outside the node */
-	if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
-				    *ei_startpfn >= last_pfn)
-		return 0;
-
-	/* Check for overlaps */
-	if (*ei_startpfn < start_pfn)
-		*ei_startpfn = start_pfn;
-	if (*ei_endpfn > last_pfn)
-		*ei_endpfn = last_pfn;
-
-	return 1;
-}
-
-/* Walk the e820 map and register active regions within a node */
-void __init e820_register_active_regions(int nid, unsigned long start_pfn,
-					 unsigned long last_pfn)
-{
-	unsigned long ei_startpfn;
-	unsigned long ei_endpfn;
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++)
-		if (e820_find_active_region(&e820.map[i],
-					    start_pfn, last_pfn,
-					    &ei_startpfn, &ei_endpfn))
-			add_active_range(nid, ei_startpfn, ei_endpfn);
-}
-
-/*
- * Find the hole size (in bytes) in the memory range.
- * @start: starting address of the memory range to scan
- * @end: ending address of the memory range to scan
- */
-u64 __init e820_hole_size(u64 start, u64 end)
-{
-	unsigned long start_pfn = start >> PAGE_SHIFT;
-	unsigned long last_pfn = end >> PAGE_SHIFT;
-	unsigned long ei_startpfn, ei_endpfn, ram = 0;
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++) {
-		if (e820_find_active_region(&e820.map[i],
-					    start_pfn, last_pfn,
-					    &ei_startpfn, &ei_endpfn))
-			ram += ei_endpfn - ei_startpfn;
-	}
-	return end - start - ((u64)ram << PAGE_SHIFT);
-}
 
 static void early_panic(char *msg)
 {
@@ -1210,3 +1076,48 @@
 	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
 	e820_print_map(who);
 }
+
+void __init memblock_x86_fill(void)
+{
+	int i;
+	u64 end;
+
+	/*
+	 * EFI may have more than 128 entries
+	 * We are safe to enable resizing, beause memblock_x86_fill()
+	 * is rather later for x86
+	 */
+	memblock_can_resize = 1;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i];
+
+		end = ei->addr + ei->size;
+		if (end != (resource_size_t)end)
+			continue;
+
+		if (ei->type != E820_RAM && ei->type != E820_RESERVED_KERN)
+			continue;
+
+		memblock_add(ei->addr, ei->size);
+	}
+
+	memblock_analyze();
+	memblock_dump_all();
+}
+
+void __init memblock_find_dma_reserve(void)
+{
+#ifdef CONFIG_X86_64
+	u64 free_size_pfn;
+	u64 mem_size_pfn;
+	/*
+	 * need to find out used area below MAX_DMA_PFN
+	 * need to use memblock to get free size in [0, MAX_DMA_PFN]
+	 * at first, and assume boot_mem will not take below MAX_DMA_PFN
+	 */
+	mem_size_pfn = memblock_x86_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
+	free_size_pfn = memblock_x86_free_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
+	set_dma_reserve(mem_size_pfn - free_size_pfn);
+#endif
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/early_printk.c linux-libre-2.6.37-gnu/arch/x86/kernel/early_printk.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/early_printk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/early_printk.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <xen/hvc-console.h>
 #include <asm/pci-direct.h>
 #include <asm/fixmap.h>
+#include <asm/mrst.h>
 #include <asm/pgtable.h>
 #include <linux/usb/ehci_def.h>
 
@@ -239,6 +240,18 @@
 		if (!strncmp(buf, "xen", 3))
 			early_console_register(&xenboot_console, keep);
 #endif
+#ifdef CONFIG_X86_MRST_EARLY_PRINTK
+		if (!strncmp(buf, "mrst", 4)) {
+			mrst_early_console_init();
+			early_console_register(&early_mrst_console, keep);
+		}
+
+		if (!strncmp(buf, "hsu", 3)) {
+			hsu_early_console_init();
+			early_console_register(&early_hsu_console, keep);
+		}
+
+#endif
 		buf++;
 	}
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/early_printk_mrst.c linux-libre-2.6.37-gnu/arch/x86/kernel/early_printk_mrst.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/early_printk_mrst.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/early_printk_mrst.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,319 @@
+/*
+ * early_printk_mrst.c - early consoles for Intel MID platforms
+ *
+ * Copyright (c) 2008-2010, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+/*
+ * This file implements two early consoles named mrst and hsu.
+ * mrst is based on Maxim3110 spi-uart device, it exists in both
+ * Moorestown and Medfield platforms, while hsu is based on a High
+ * Speed UART device which only exists in the Medfield platform
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/serial_mfd.h>
+#include <linux/kmsg_dump.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/fixmap.h>
+#include <asm/pgtable.h>
+#include <asm/mrst.h>
+
+#define MRST_SPI_TIMEOUT		0x200000
+#define MRST_REGBASE_SPI0		0xff128000
+#define MRST_REGBASE_SPI1		0xff128400
+#define MRST_CLK_SPI0_REG		0xff11d86c
+
+/* Bit fields in CTRLR0 */
+#define SPI_DFS_OFFSET			0
+
+#define SPI_FRF_OFFSET			4
+#define SPI_FRF_SPI			0x0
+#define SPI_FRF_SSP			0x1
+#define SPI_FRF_MICROWIRE		0x2
+#define SPI_FRF_RESV			0x3
+
+#define SPI_MODE_OFFSET			6
+#define SPI_SCPH_OFFSET			6
+#define SPI_SCOL_OFFSET			7
+#define SPI_TMOD_OFFSET			8
+#define	SPI_TMOD_TR			0x0		/* xmit & recv */
+#define SPI_TMOD_TO			0x1		/* xmit only */
+#define SPI_TMOD_RO			0x2		/* recv only */
+#define SPI_TMOD_EPROMREAD		0x3		/* eeprom read mode */
+
+#define SPI_SLVOE_OFFSET		10
+#define SPI_SRL_OFFSET			11
+#define SPI_CFS_OFFSET			12
+
+/* Bit fields in SR, 7 bits */
+#define SR_MASK				0x7f		/* cover 7 bits */
+#define SR_BUSY				(1 << 0)
+#define SR_TF_NOT_FULL			(1 << 1)
+#define SR_TF_EMPT			(1 << 2)
+#define SR_RF_NOT_EMPT			(1 << 3)
+#define SR_RF_FULL			(1 << 4)
+#define SR_TX_ERR			(1 << 5)
+#define SR_DCOL				(1 << 6)
+
+struct dw_spi_reg {
+	u32	ctrl0;
+	u32	ctrl1;
+	u32	ssienr;
+	u32	mwcr;
+	u32	ser;
+	u32	baudr;
+	u32	txfltr;
+	u32	rxfltr;
+	u32	txflr;
+	u32	rxflr;
+	u32	sr;
+	u32	imr;
+	u32	isr;
+	u32	risr;
+	u32	txoicr;
+	u32	rxoicr;
+	u32	rxuicr;
+	u32	msticr;
+	u32	icr;
+	u32	dmacr;
+	u32	dmatdlr;
+	u32	dmardlr;
+	u32	idr;
+	u32	version;
+
+	/* Currently operates as 32 bits, though only the low 16 bits matter */
+	u32	dr;
+} __packed;
+
+#define dw_readl(dw, name)		__raw_readl(&(dw)->name)
+#define dw_writel(dw, name, val)	__raw_writel((val), &(dw)->name)
+
+/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
+static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
+
+static u32 *pclk_spi0;
+/* Always contains an accessable address, start with 0 */
+static struct dw_spi_reg *pspi;
+
+static struct kmsg_dumper dw_dumper;
+static int dumper_registered;
+
+static void dw_kmsg_dump(struct kmsg_dumper *dumper,
+			enum kmsg_dump_reason reason,
+			const char *s1, unsigned long l1,
+			const char *s2, unsigned long l2)
+{
+	int i;
+
+	/* When run to this, we'd better re-init the HW */
+	mrst_early_console_init();
+
+	for (i = 0; i < l1; i++)
+		early_mrst_console.write(&early_mrst_console, s1 + i, 1);
+	for (i = 0; i < l2; i++)
+		early_mrst_console.write(&early_mrst_console, s2 + i, 1);
+}
+
+/* Set the ratio rate to 115200, 8n1, IRQ disabled */
+static void max3110_write_config(void)
+{
+	u16 config;
+
+	config = 0xc001;
+	dw_writel(pspi, dr, config);
+}
+
+/* Translate char to a eligible word and send to max3110 */
+static void max3110_write_data(char c)
+{
+	u16 data;
+
+	data = 0x8000 | c;
+	dw_writel(pspi, dr, data);
+}
+
+void mrst_early_console_init(void)
+{
+	u32 ctrlr0 = 0;
+	u32 spi0_cdiv;
+	u32 freq; /* Freqency info only need be searched once */
+
+	/* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
+	pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+							MRST_CLK_SPI0_REG);
+	spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
+	freq = 100000000 / (spi0_cdiv + 1);
+
+	if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
+		mrst_spi_paddr = MRST_REGBASE_SPI1;
+
+	pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+						mrst_spi_paddr);
+
+	/* Disable SPI controller */
+	dw_writel(pspi, ssienr, 0);
+
+	/* Set control param, 8 bits, transmit only mode */
+	ctrlr0 = dw_readl(pspi, ctrl0);
+
+	ctrlr0 &= 0xfcc0;
+	ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
+		      | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
+	dw_writel(pspi, ctrl0, ctrlr0);
+
+	/*
+	 * Change the spi0 clk to comply with 115200 bps, use 100000 to
+	 * calculate the clk dividor to make the clock a little slower
+	 * than real baud rate.
+	 */
+	dw_writel(pspi, baudr, freq/100000);
+
+	/* Disable all INT for early phase */
+	dw_writel(pspi, imr, 0x0);
+
+	/* Set the cs to spi-uart */
+	dw_writel(pspi, ser, 0x2);
+
+	/* Enable the HW, the last step for HW init */
+	dw_writel(pspi, ssienr, 0x1);
+
+	/* Set the default configuration */
+	max3110_write_config();
+
+	/* Register the kmsg dumper */
+	if (!dumper_registered) {
+		dw_dumper.dump = dw_kmsg_dump;
+		kmsg_dump_register(&dw_dumper);
+		dumper_registered = 1;
+	}
+}
+
+/* Slave select should be called in the read/write function */
+static void early_mrst_spi_putc(char c)
+{
+	unsigned int timeout;
+	u32 sr;
+
+	timeout = MRST_SPI_TIMEOUT;
+	/* Early putc needs to make sure the TX FIFO is not full */
+	while (--timeout) {
+		sr = dw_readl(pspi, sr);
+		if (!(sr & SR_TF_NOT_FULL))
+			cpu_relax();
+		else
+			break;
+	}
+
+	if (!timeout)
+		pr_warning("MRST earlycon: timed out\n");
+	else
+		max3110_write_data(c);
+}
+
+/* Early SPI only uses polling mode */
+static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
+{
+	int i;
+
+	for (i = 0; i < n && *str; i++) {
+		if (*str == '\n')
+			early_mrst_spi_putc('\r');
+		early_mrst_spi_putc(*str);
+		str++;
+	}
+}
+
+struct console early_mrst_console = {
+	.name =		"earlymrst",
+	.write =	early_mrst_spi_write,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
+};
+
+/*
+ * Following is the early console based on Medfield HSU (High
+ * Speed UART) device.
+ */
+#define HSU_PORT2_PADDR		0xffa28180
+
+static void __iomem *phsu;
+
+void hsu_early_console_init(void)
+{
+	u8 lcr;
+
+	phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+							HSU_PORT2_PADDR);
+
+	/* Disable FIFO */
+	writeb(0x0, phsu + UART_FCR);
+
+	/* Set to default 115200 bps, 8n1 */
+	lcr = readb(phsu + UART_LCR);
+	writeb((0x80 | lcr), phsu + UART_LCR);
+	writeb(0x18, phsu + UART_DLL);
+	writeb(lcr,  phsu + UART_LCR);
+	writel(0x3600, phsu + UART_MUL*4);
+
+	writeb(0x8, phsu + UART_MCR);
+	writeb(0x7, phsu + UART_FCR);
+	writeb(0x3, phsu + UART_LCR);
+
+	/* Clear IRQ status */
+	readb(phsu + UART_LSR);
+	readb(phsu + UART_RX);
+	readb(phsu + UART_IIR);
+	readb(phsu + UART_MSR);
+
+	/* Enable FIFO */
+	writeb(0x7, phsu + UART_FCR);
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void early_hsu_putc(char ch)
+{
+	unsigned int timeout = 10000; /* 10ms */
+	u8 status;
+
+	while (--timeout) {
+		status = readb(phsu + UART_LSR);
+		if (status & BOTH_EMPTY)
+			break;
+		udelay(1);
+	}
+
+	/* Only write the char when there was no timeout */
+	if (timeout)
+		writeb(ch, phsu + UART_TX);
+}
+
+static void early_hsu_write(struct console *con, const char *str, unsigned n)
+{
+	int i;
+
+	for (i = 0; i < n && *str; i++) {
+		if (*str == '\n')
+			early_hsu_putc('\r');
+		early_hsu_putc(*str);
+		str++;
+	}
+}
+
+struct console early_hsu_console = {
+	.name =		"earlyhsu",
+	.write =	early_hsu_write,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
+};
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/early-quirks.c linux-libre-2.6.37-gnu/arch/x86/kernel/early-quirks.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/early-quirks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/early-quirks.c	2011-01-04 19:50:19.000000000 -0500
@@ -97,7 +97,6 @@
 }
 
 #if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
-#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
 static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
 {
 	u32 d;
@@ -115,7 +114,6 @@
 	d &= 0xff;
 	return d;
 }
-#endif
 
 static void __init ati_bugs(int num, int slot, int func)
 {
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/efi_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/efi_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/efi_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/efi_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,112 +0,0 @@
-/*
- * Extensible Firmware Interface
- *
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2002 Hewlett-Packard Co.
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- *	Stephane Eranian <eranian@hpl.hp.com>
- *
- * All EFI Runtime Services are not implemented yet as EFI only
- * supports physical mode addressing on SoftSDV. This is to be fixed
- * in a future version.  --drummond 1999-07-20
- *
- * Implemented EFI runtime services and virtual mode calls.  --davidm
- *
- * Goutham Rao: <goutham.rao@intel.com>
- *	Skip non-WB memory and ignore empty memory ranges.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/efi.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <asm/efi.h>
-
-/*
- * To make EFI call EFI runtime service in physical addressing mode we need
- * prelog/epilog before/after the invocation to disable interrupt, to
- * claim EFI runtime service handler exclusively and to duplicate a memory in
- * low memory space say 0 - 3G.
- */
-
-static unsigned long efi_rt_eflags;
-static pgd_t efi_bak_pg_dir_pointer[2];
-
-void efi_call_phys_prelog(void)
-{
-	unsigned long cr4;
-	unsigned long temp;
-	struct desc_ptr gdt_descr;
-
-	local_irq_save(efi_rt_eflags);
-
-	/*
-	 * If I don't have PAE, I should just duplicate two entries in page
-	 * directory. If I have PAE, I just need to duplicate one entry in
-	 * page directory.
-	 */
-	cr4 = read_cr4_safe();
-
-	if (cr4 & X86_CR4_PAE) {
-		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
-		swapper_pg_dir[0].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-	} else {
-		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
-		efi_bak_pg_dir_pointer[1].pgd =
-		    swapper_pg_dir[pgd_index(0x400000)].pgd;
-		swapper_pg_dir[pgd_index(0)].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-		temp = PAGE_OFFSET + 0x400000;
-		swapper_pg_dir[pgd_index(0x400000)].pgd =
-		    swapper_pg_dir[pgd_index(temp)].pgd;
-	}
-
-	/*
-	 * After the lock is released, the original page table is restored.
-	 */
-	__flush_tlb_all();
-
-	gdt_descr.address = __pa(get_cpu_gdt_table(0));
-	gdt_descr.size = GDT_SIZE - 1;
-	load_gdt(&gdt_descr);
-}
-
-void efi_call_phys_epilog(void)
-{
-	unsigned long cr4;
-	struct desc_ptr gdt_descr;
-
-	gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
-	gdt_descr.size = GDT_SIZE - 1;
-	load_gdt(&gdt_descr);
-
-	cr4 = read_cr4_safe();
-
-	if (cr4 & X86_CR4_PAE) {
-		swapper_pg_dir[pgd_index(0)].pgd =
-		    efi_bak_pg_dir_pointer[0].pgd;
-	} else {
-		swapper_pg_dir[pgd_index(0)].pgd =
-		    efi_bak_pg_dir_pointer[0].pgd;
-		swapper_pg_dir[pgd_index(0x400000)].pgd =
-		    efi_bak_pg_dir_pointer[1].pgd;
-	}
-
-	/*
-	 * After the lock is released, the original page table is restored.
-	 */
-	__flush_tlb_all();
-
-	local_irq_restore(efi_rt_eflags);
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/efi_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/efi_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/efi_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/efi_64.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,114 +0,0 @@
-/*
- * x86_64 specific EFI support functions
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 2005-2008 Intel Co.
- *	Fenghua Yu <fenghua.yu@intel.com>
- *	Bibo Mao <bibo.mao@intel.com>
- *	Chandramouli Narayanan <mouli@linux.intel.com>
- *	Huang Ying <ying.huang@intel.com>
- *
- * Code to convert EFI to E820 map has been implemented in elilo bootloader
- * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
- * is setup appropriately for EFI runtime code.
- * - mouli 06/14/2007.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/bootmem.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/efi.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/reboot.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/e820.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <asm/proto.h>
-#include <asm/efi.h>
-#include <asm/cacheflush.h>
-#include <asm/fixmap.h>
-
-static pgd_t save_pgd __initdata;
-static unsigned long efi_flags __initdata;
-
-static void __init early_mapping_set_exec(unsigned long start,
-					  unsigned long end,
-					  int executable)
-{
-	unsigned long num_pages;
-
-	start &= PMD_MASK;
-	end = (end + PMD_SIZE - 1) & PMD_MASK;
-	num_pages = (end - start) >> PAGE_SHIFT;
-	if (executable)
-		set_memory_x((unsigned long)__va(start), num_pages);
-	else
-		set_memory_nx((unsigned long)__va(start), num_pages);
-}
-
-static void __init early_runtime_code_mapping_set_exec(int executable)
-{
-	efi_memory_desc_t *md;
-	void *p;
-
-	if (!(__supported_pte_mask & _PAGE_NX))
-		return;
-
-	/* Make EFI runtime service code area executable */
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		md = p;
-		if (md->type == EFI_RUNTIME_SERVICES_CODE) {
-			unsigned long end;
-			end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
-			early_mapping_set_exec(md->phys_addr, end, executable);
-		}
-	}
-}
-
-void __init efi_call_phys_prelog(void)
-{
-	unsigned long vaddress;
-
-	early_runtime_code_mapping_set_exec(1);
-	local_irq_save(efi_flags);
-	vaddress = (unsigned long)__va(0x0UL);
-	save_pgd = *pgd_offset_k(0x0UL);
-	set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
-	__flush_tlb_all();
-}
-
-void __init efi_call_phys_epilog(void)
-{
-	/*
-	 * After the lock is released, the original page table is restored.
-	 */
-	set_pgd(pgd_offset_k(0x0UL), save_pgd);
-	__flush_tlb_all();
-	local_irq_restore(efi_flags);
-	early_runtime_code_mapping_set_exec(0);
-}
-
-void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
-				 u32 type)
-{
-	unsigned long last_map_pfn;
-
-	if (type == EFI_MEMORY_MAPPED_IO)
-		return ioremap(phys_addr, size);
-
-	last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
-	if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
-		return NULL;
-
-	return (void __iomem *)__va(phys_addr);
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/efi.c linux-libre-2.6.37-gnu/arch/x86/kernel/efi.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/efi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/efi.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,612 +0,0 @@
-/*
- * Common EFI (Extensible Firmware Interface) support functions
- * Based on Extensible Firmware Interface Specification version 1.0
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999-2002 Hewlett-Packard Co.
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- *	Stephane Eranian <eranian@hpl.hp.com>
- * Copyright (C) 2005-2008 Intel Co.
- *	Fenghua Yu <fenghua.yu@intel.com>
- *	Bibo Mao <bibo.mao@intel.com>
- *	Chandramouli Narayanan <mouli@linux.intel.com>
- *	Huang Ying <ying.huang@intel.com>
- *
- * Copied from efi_32.c to eliminate the duplicated code between EFI
- * 32/64 support code. --ying 2007-10-26
- *
- * All EFI Runtime Services are not implemented yet as EFI only
- * supports physical mode addressing on SoftSDV. This is to be fixed
- * in a future version.  --drummond 1999-07-20
- *
- * Implemented EFI runtime services and virtual mode calls.  --davidm
- *
- * Goutham Rao: <goutham.rao@intel.com>
- *	Skip non-WB memory and ignore empty memory ranges.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/efi.h>
-#include <linux/bootmem.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/reboot.h>
-#include <linux/bcd.h>
-
-#include <asm/setup.h>
-#include <asm/efi.h>
-#include <asm/time.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#include <asm/x86_init.h>
-
-#define EFI_DEBUG	1
-#define PFX 		"EFI: "
-
-int efi_enabled;
-EXPORT_SYMBOL(efi_enabled);
-
-struct efi efi;
-EXPORT_SYMBOL(efi);
-
-struct efi_memory_map memmap;
-
-static struct efi efi_phys __initdata;
-static efi_system_table_t efi_systab __initdata;
-
-static int __init setup_noefi(char *arg)
-{
-	efi_enabled = 0;
-	return 0;
-}
-early_param("noefi", setup_noefi);
-
-int add_efi_memmap;
-EXPORT_SYMBOL(add_efi_memmap);
-
-static int __init setup_add_efi_memmap(char *arg)
-{
-	add_efi_memmap = 1;
-	return 0;
-}
-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)
-{
-	return efi_call_virt2(get_time, tm, tc);
-}
-
-static efi_status_t virt_efi_set_time(efi_time_t *tm)
-{
-	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)
-{
-	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)
-{
-	return efi_call_virt2(set_wakeup_time,
-			      enabled, tm);
-}
-
-static efi_status_t virt_efi_get_variable(efi_char16_t *name,
-					  efi_guid_t *vendor,
-					  u32 *attr,
-					  unsigned long *data_size,
-					  void *data)
-{
-	return efi_call_virt5(get_variable,
-			      name, vendor, attr,
-			      data_size, data);
-}
-
-static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
-					       efi_char16_t *name,
-					       efi_guid_t *vendor)
-{
-	return efi_call_virt3(get_next_variable,
-			      name_size, name, vendor);
-}
-
-static efi_status_t virt_efi_set_variable(efi_char16_t *name,
-					  efi_guid_t *vendor,
-					  unsigned long attr,
-					  unsigned long data_size,
-					  void *data)
-{
-	return efi_call_virt5(set_variable,
-			      name, vendor, attr,
-			      data_size, data);
-}
-
-static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
-{
-	return efi_call_virt1(get_next_high_mono_count, count);
-}
-
-static void virt_efi_reset_system(int reset_type,
-				  efi_status_t status,
-				  unsigned long data_size,
-				  efi_char16_t *data)
-{
-	efi_call_virt4(reset_system, reset_type, status,
-		       data_size, data);
-}
-
-static efi_status_t virt_efi_set_virtual_address_map(
-	unsigned long memory_map_size,
-	unsigned long descriptor_size,
-	u32 descriptor_version,
-	efi_memory_desc_t *virtual_map)
-{
-	return efi_call_virt4(set_virtual_address_map,
-			      memory_map_size, descriptor_size,
-			      descriptor_version, virtual_map);
-}
-
-static efi_status_t __init phys_efi_set_virtual_address_map(
-	unsigned long memory_map_size,
-	unsigned long descriptor_size,
-	u32 descriptor_version,
-	efi_memory_desc_t *virtual_map)
-{
-	efi_status_t status;
-
-	efi_call_phys_prelog();
-	status = efi_call_phys4(efi_phys.set_virtual_address_map,
-				memory_map_size, descriptor_size,
-				descriptor_version, virtual_map);
-	efi_call_phys_epilog();
-	return status;
-}
-
-static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
-					     efi_time_cap_t *tc)
-{
-	efi_status_t status;
-
-	efi_call_phys_prelog();
-	status = efi_call_phys2(efi_phys.get_time, tm, tc);
-	efi_call_phys_epilog();
-	return status;
-}
-
-int efi_set_rtc_mmss(unsigned long nowtime)
-{
-	int real_seconds, real_minutes;
-	efi_status_t 	status;
-	efi_time_t 	eft;
-	efi_time_cap_t 	cap;
-
-	status = efi.get_time(&eft, &cap);
-	if (status != EFI_SUCCESS) {
-		printk(KERN_ERR "Oops: efitime: can't read time!\n");
-		return -1;
-	}
-
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
-		real_minutes += 30;
-	real_minutes %= 60;
-	eft.minute = real_minutes;
-	eft.second = real_seconds;
-
-	status = efi.set_time(&eft);
-	if (status != EFI_SUCCESS) {
-		printk(KERN_ERR "Oops: efitime: can't write time!\n");
-		return -1;
-	}
-	return 0;
-}
-
-unsigned long efi_get_time(void)
-{
-	efi_status_t status;
-	efi_time_t eft;
-	efi_time_cap_t cap;
-
-	status = efi.get_time(&eft, &cap);
-	if (status != EFI_SUCCESS)
-		printk(KERN_ERR "Oops: efitime: can't read time!\n");
-
-	return mktime(eft.year, eft.month, eft.day, eft.hour,
-		      eft.minute, eft.second);
-}
-
-/*
- * Tell the kernel about the EFI memory map.  This might include
- * more than the max 128 entries that can fit in the e820 legacy
- * (zeropage) memory map.
- */
-
-static void __init do_add_efi_memmap(void)
-{
-	void *p;
-
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		efi_memory_desc_t *md = p;
-		unsigned long long start = md->phys_addr;
-		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
-		int e820_type;
-
-		switch (md->type) {
-		case EFI_LOADER_CODE:
-		case EFI_LOADER_DATA:
-		case EFI_BOOT_SERVICES_CODE:
-		case EFI_BOOT_SERVICES_DATA:
-		case EFI_CONVENTIONAL_MEMORY:
-			if (md->attribute & EFI_MEMORY_WB)
-				e820_type = E820_RAM;
-			else
-				e820_type = E820_RESERVED;
-			break;
-		case EFI_ACPI_RECLAIM_MEMORY:
-			e820_type = E820_ACPI;
-			break;
-		case EFI_ACPI_MEMORY_NVS:
-			e820_type = E820_NVS;
-			break;
-		case EFI_UNUSABLE_MEMORY:
-			e820_type = E820_UNUSABLE;
-			break;
-		default:
-			/*
-			 * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE
-			 * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO
-			 * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE
-			 */
-			e820_type = E820_RESERVED;
-			break;
-		}
-		e820_add_region(start, size, e820_type);
-	}
-	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-}
-
-void __init efi_reserve_early(void)
-{
-	unsigned long pmap;
-
-#ifdef CONFIG_X86_32
-	pmap = boot_params.efi_info.efi_memmap;
-#else
-	pmap = (boot_params.efi_info.efi_memmap |
-		((__u64)boot_params.efi_info.efi_memmap_hi<<32));
-#endif
-	memmap.phys_map = (void *)pmap;
-	memmap.nr_map = boot_params.efi_info.efi_memmap_size /
-		boot_params.efi_info.efi_memdesc_size;
-	memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
-	memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
-	reserve_early(pmap, pmap + memmap.nr_map * memmap.desc_size,
-		      "EFI memmap");
-}
-
-#if EFI_DEBUG
-static void __init print_efi_memmap(void)
-{
-	efi_memory_desc_t *md;
-	void *p;
-	int i;
-
-	for (p = memmap.map, i = 0;
-	     p < memmap.map_end;
-	     p += memmap.desc_size, i++) {
-		md = p;
-		printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
-			"range=[0x%016llx-0x%016llx) (%lluMB)\n",
-			i, md->type, md->attribute, md->phys_addr,
-			md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
-			(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
-	}
-}
-#endif  /*  EFI_DEBUG  */
-
-void __init efi_init(void)
-{
-	efi_config_table_t *config_tables;
-	efi_runtime_services_t *runtime;
-	efi_char16_t *c16;
-	char vendor[100] = "unknown";
-	int i = 0;
-	void *tmp;
-
-#ifdef CONFIG_X86_32
-	efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
-#else
-	efi_phys.systab = (efi_system_table_t *)
-		(boot_params.efi_info.efi_systab |
-		 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
-#endif
-
-	efi.systab = early_ioremap((unsigned long)efi_phys.systab,
-				   sizeof(efi_system_table_t));
-	if (efi.systab == NULL)
-		printk(KERN_ERR "Couldn't map the EFI system table!\n");
-	memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
-	early_iounmap(efi.systab, sizeof(efi_system_table_t));
-	efi.systab = &efi_systab;
-
-	/*
-	 * Verify the EFI Table
-	 */
-	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-		printk(KERN_ERR "EFI system table signature incorrect!\n");
-	if ((efi.systab->hdr.revision >> 16) == 0)
-		printk(KERN_ERR "Warning: EFI system table version "
-		       "%d.%02d, expected 1.00 or greater!\n",
-		       efi.systab->hdr.revision >> 16,
-		       efi.systab->hdr.revision & 0xffff);
-
-	/*
-	 * Show what we know for posterity
-	 */
-	c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
-	if (c16) {
-		for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
-			vendor[i] = *c16++;
-		vendor[i] = '\0';
-	} else
-		printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
-	early_iounmap(tmp, 2);
-
-	printk(KERN_INFO "EFI v%u.%.02u by %s\n",
-	       efi.systab->hdr.revision >> 16,
-	       efi.systab->hdr.revision & 0xffff, vendor);
-
-	/*
-	 * Let's see what config tables the firmware passed to us.
-	 */
-	config_tables = early_ioremap(
-		efi.systab->tables,
-		efi.systab->nr_tables * sizeof(efi_config_table_t));
-	if (config_tables == NULL)
-		printk(KERN_ERR "Could not map EFI Configuration Table!\n");
-
-	printk(KERN_INFO);
-	for (i = 0; i < efi.systab->nr_tables; i++) {
-		if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
-			efi.mps = config_tables[i].table;
-			printk(" MPS=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					ACPI_20_TABLE_GUID)) {
-			efi.acpi20 = config_tables[i].table;
-			printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					ACPI_TABLE_GUID)) {
-			efi.acpi = config_tables[i].table;
-			printk(" ACPI=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					SMBIOS_TABLE_GUID)) {
-			efi.smbios = config_tables[i].table;
-			printk(" SMBIOS=0x%lx ", config_tables[i].table);
-#ifdef CONFIG_X86_UV
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					UV_SYSTEM_TABLE_GUID)) {
-			efi.uv_systab = config_tables[i].table;
-			printk(" UVsystab=0x%lx ", config_tables[i].table);
-#endif
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					HCDP_TABLE_GUID)) {
-			efi.hcdp = config_tables[i].table;
-			printk(" HCDP=0x%lx ", config_tables[i].table);
-		} else if (!efi_guidcmp(config_tables[i].guid,
-					UGA_IO_PROTOCOL_GUID)) {
-			efi.uga = config_tables[i].table;
-			printk(" UGA=0x%lx ", config_tables[i].table);
-		}
-	}
-	printk("\n");
-	early_iounmap(config_tables,
-			  efi.systab->nr_tables * sizeof(efi_config_table_t));
-
-	/*
-	 * Check out the runtime services table. We need to map
-	 * the runtime services table so that we can grab the physical
-	 * address of several of the EFI runtime functions, needed to
-	 * set the firmware into virtual mode.
-	 */
-	runtime = early_ioremap((unsigned long)efi.systab->runtime,
-				sizeof(efi_runtime_services_t));
-	if (runtime != NULL) {
-		/*
-		 * We will only need *early* access to the following
-		 * two EFI runtime services before set_virtual_address_map
-		 * is invoked.
-		 */
-		efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
-		efi_phys.set_virtual_address_map =
-			(efi_set_virtual_address_map_t *)
-			runtime->set_virtual_address_map;
-		/*
-		 * Make efi_get_time can be called before entering
-		 * virtual mode.
-		 */
-		efi.get_time = phys_efi_get_time;
-	} else
-		printk(KERN_ERR "Could not map the EFI runtime service "
-		       "table!\n");
-	early_iounmap(runtime, sizeof(efi_runtime_services_t));
-
-	/* Map the EFI memory map */
-	memmap.map = early_ioremap((unsigned long)memmap.phys_map,
-				   memmap.nr_map * memmap.desc_size);
-	if (memmap.map == NULL)
-		printk(KERN_ERR "Could not map the EFI memory map!\n");
-	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
-
-	if (memmap.desc_size != sizeof(efi_memory_desc_t))
-		printk(KERN_WARNING
-		  "Kernel-defined memdesc doesn't match the one from EFI!\n");
-
-	if (add_efi_memmap)
-		do_add_efi_memmap();
-
-#ifdef CONFIG_X86_32
-	x86_platform.get_wallclock = efi_get_time;
-	x86_platform.set_wallclock = efi_set_rtc_mmss;
-#endif
-
-	/* Setup for EFI runtime service */
-	reboot_type = BOOT_EFI;
-
-#if EFI_DEBUG
-	print_efi_memmap();
-#endif
-}
-
-static void __init runtime_code_page_mkexec(void)
-{
-	efi_memory_desc_t *md;
-	void *p;
-	u64 addr, npages;
-
-	/* Make EFI runtime service code area executable */
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		md = p;
-
-		if (md->type != EFI_RUNTIME_SERVICES_CODE)
-			continue;
-
-		addr = md->virt_addr;
-		npages = md->num_pages;
-		memrange_efi_to_native(&addr, &npages);
-		set_memory_x(addr, npages);
-	}
-}
-
-/*
- * This function will switch the EFI runtime services to virtual mode.
- * Essentially, look through the EFI memmap and map every region that
- * has the runtime attribute bit set in its memory descriptor and update
- * that memory descriptor with the virtual address obtained from ioremap().
- * This enables the runtime services to be called without having to
- * thunk back into physical mode for every invocation.
- */
-void __init efi_enter_virtual_mode(void)
-{
-	efi_memory_desc_t *md;
-	efi_status_t status;
-	unsigned long size;
-	u64 end, systab, addr, npages, end_pfn;
-	void *p, *va;
-
-	efi.systab = NULL;
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		md = p;
-		if (!(md->attribute & EFI_MEMORY_RUNTIME))
-			continue;
-
-		size = md->num_pages << EFI_PAGE_SHIFT;
-		end = md->phys_addr + size;
-
-		end_pfn = PFN_UP(end);
-		if (end_pfn <= max_low_pfn_mapped
-		    || (end_pfn > (1UL << (32 - PAGE_SHIFT))
-			&& end_pfn <= max_pfn_mapped))
-			va = __va(md->phys_addr);
-		else
-			va = efi_ioremap(md->phys_addr, size, md->type);
-
-		md->virt_addr = (u64) (unsigned long) va;
-
-		if (!va) {
-			printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
-			       (unsigned long long)md->phys_addr);
-			continue;
-		}
-
-		if (!(md->attribute & EFI_MEMORY_WB)) {
-			addr = md->virt_addr;
-			npages = md->num_pages;
-			memrange_efi_to_native(&addr, &npages);
-			set_memory_uc(addr, npages);
-		}
-
-		systab = (u64) (unsigned long) efi_phys.systab;
-		if (md->phys_addr <= systab && systab < end) {
-			systab += md->virt_addr - md->phys_addr;
-			efi.systab = (efi_system_table_t *) (unsigned long) systab;
-		}
-	}
-
-	BUG_ON(!efi.systab);
-
-	status = phys_efi_set_virtual_address_map(
-		memmap.desc_size * memmap.nr_map,
-		memmap.desc_size,
-		memmap.desc_version,
-		memmap.phys_map);
-
-	if (status != EFI_SUCCESS) {
-		printk(KERN_ALERT "Unable to switch EFI into virtual mode "
-		       "(status=%lx)!\n", status);
-		panic("EFI call to SetVirtualAddressMap() failed!");
-	}
-
-	/*
-	 * Now that EFI is in virtual mode, update the function
-	 * pointers in the runtime service table to the new virtual addresses.
-	 *
-	 * Call EFI services through wrapper functions.
-	 */
-	efi.get_time = virt_efi_get_time;
-	efi.set_time = virt_efi_set_time;
-	efi.get_wakeup_time = virt_efi_get_wakeup_time;
-	efi.set_wakeup_time = virt_efi_set_wakeup_time;
-	efi.get_variable = virt_efi_get_variable;
-	efi.get_next_variable = virt_efi_get_next_variable;
-	efi.set_variable = virt_efi_set_variable;
-	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
-	efi.reset_system = virt_efi_reset_system;
-	efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
-	if (__supported_pte_mask & _PAGE_NX)
-		runtime_code_page_mkexec();
-	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
-	memmap.map = NULL;
-}
-
-/*
- * Convenience functions to obtain memory types and attributes
- */
-u32 efi_mem_type(unsigned long phys_addr)
-{
-	efi_memory_desc_t *md;
-	void *p;
-
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		md = p;
-		if ((md->phys_addr <= phys_addr) &&
-		    (phys_addr < (md->phys_addr +
-				  (md->num_pages << EFI_PAGE_SHIFT))))
-			return md->type;
-	}
-	return 0;
-}
-
-u64 efi_mem_attributes(unsigned long phys_addr)
-{
-	efi_memory_desc_t *md;
-	void *p;
-
-	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
-		md = p;
-		if ((md->phys_addr <= phys_addr) &&
-		    (phys_addr < (md->phys_addr +
-				  (md->num_pages << EFI_PAGE_SHIFT))))
-			return md->attribute;
-	}
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/efi_stub_32.S linux-libre-2.6.37-gnu/arch/x86/kernel/efi_stub_32.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/efi_stub_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/efi_stub_32.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,123 +0,0 @@
-/*
- * EFI call stub for IA32.
- *
- * This stub allows us to make EFI calls in physical mode with interrupts
- * turned off.
- */
-
-#include <linux/linkage.h>
-#include <asm/page_types.h>
-
-/*
- * efi_call_phys(void *, ...) is a function with variable parameters.
- * All the callers of this function assure that all the parameters are 4-bytes.
- */
-
-/*
- * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
- * So we'd better save all of them at the beginning of this function and restore
- * at the end no matter how many we use, because we can not assure EFI runtime
- * service functions will comply with gcc calling convention, too.
- */
-
-.text
-ENTRY(efi_call_phys)
-	/*
-	 * 0. The function can only be called in Linux kernel. So CS has been
-	 * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
-	 * the values of these registers are the same. And, the corresponding
-	 * GDT entries are identical. So I will do nothing about segment reg
-	 * and GDT, but change GDT base register in prelog and epilog.
-	 */
-
-	/*
-	 * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
-	 * But to make it smoothly switch from virtual mode to flat mode.
-	 * The mapping of lower virtual memory has been created in prelog and
-	 * epilog.
-	 */
-	movl	$1f, %edx
-	subl	$__PAGE_OFFSET, %edx
-	jmp	*%edx
-1:
-
-	/*
-	 * 2. Now on the top of stack is the return
-	 * address in the caller of efi_call_phys(), then parameter 1,
-	 * parameter 2, ..., param n. To make things easy, we save the return
-	 * address of efi_call_phys in a global variable.
-	 */
-	popl	%edx
-	movl	%edx, saved_return_addr
-	/* get the function pointer into ECX*/
-	popl	%ecx
-	movl	%ecx, efi_rt_function_ptr
-	movl	$2f, %edx
-	subl	$__PAGE_OFFSET, %edx
-	pushl	%edx
-
-	/*
-	 * 3. Clear PG bit in %CR0.
-	 */
-	movl	%cr0, %edx
-	andl	$0x7fffffff, %edx
-	movl	%edx, %cr0
-	jmp	1f
-1:
-
-	/*
-	 * 4. Adjust stack pointer.
-	 */
-	subl	$__PAGE_OFFSET, %esp
-
-	/*
-	 * 5. Call the physical function.
-	 */
-	jmp	*%ecx
-
-2:
-	/*
-	 * 6. After EFI runtime service returns, control will return to
-	 * following instruction. We'd better readjust stack pointer first.
-	 */
-	addl	$__PAGE_OFFSET, %esp
-
-	/*
-	 * 7. Restore PG bit
-	 */
-	movl	%cr0, %edx
-	orl	$0x80000000, %edx
-	movl	%edx, %cr0
-	jmp	1f
-1:
-	/*
-	 * 8. Now restore the virtual mode from flat mode by
-	 * adding EIP with PAGE_OFFSET.
-	 */
-	movl	$1f, %edx
-	jmp	*%edx
-1:
-
-	/*
-	 * 9. Balance the stack. And because EAX contain the return value,
-	 * we'd better not clobber it.
-	 */
-	leal	efi_rt_function_ptr, %edx
-	movl	(%edx), %ecx
-	pushl	%ecx
-
-	/*
-	 * 10. Push the saved return address onto the stack and return.
-	 */
-	leal	saved_return_addr, %edx
-	movl	(%edx), %ecx
-	pushl	%ecx
-	ret
-ENDPROC(efi_call_phys)
-.previous
-
-.data
-saved_return_addr:
-	.long 0
-efi_rt_function_ptr:
-	.long 0
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/efi_stub_64.S linux-libre-2.6.37-gnu/arch/x86/kernel/efi_stub_64.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/efi_stub_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/efi_stub_64.S	1969-12-31 19:00:00.000000000 -0500
@@ -1,116 +0,0 @@
-/*
- * Function calling ABI conversion from Linux to EFI for x86_64
- *
- * Copyright (C) 2007 Intel Corp
- *	Bibo Mao <bibo.mao@intel.com>
- *	Huang Ying <ying.huang@intel.com>
- */
-
-#include <linux/linkage.h>
-
-#define SAVE_XMM			\
-	mov %rsp, %rax;			\
-	subq $0x70, %rsp;		\
-	and $~0xf, %rsp;		\
-	mov %rax, (%rsp);		\
-	mov %cr0, %rax;			\
-	clts;				\
-	mov %rax, 0x8(%rsp);		\
-	movaps %xmm0, 0x60(%rsp);	\
-	movaps %xmm1, 0x50(%rsp);	\
-	movaps %xmm2, 0x40(%rsp);	\
-	movaps %xmm3, 0x30(%rsp);	\
-	movaps %xmm4, 0x20(%rsp);	\
-	movaps %xmm5, 0x10(%rsp)
-
-#define RESTORE_XMM			\
-	movaps 0x60(%rsp), %xmm0;	\
-	movaps 0x50(%rsp), %xmm1;	\
-	movaps 0x40(%rsp), %xmm2;	\
-	movaps 0x30(%rsp), %xmm3;	\
-	movaps 0x20(%rsp), %xmm4;	\
-	movaps 0x10(%rsp), %xmm5;	\
-	mov 0x8(%rsp), %rsi;		\
-	mov %rsi, %cr0;			\
-	mov (%rsp), %rsp
-
-ENTRY(efi_call0)
-	SAVE_XMM
-	subq $32, %rsp
-	call *%rdi
-	addq $32, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call0)
-
-ENTRY(efi_call1)
-	SAVE_XMM
-	subq $32, %rsp
-	mov  %rsi, %rcx
-	call *%rdi
-	addq $32, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call1)
-
-ENTRY(efi_call2)
-	SAVE_XMM
-	subq $32, %rsp
-	mov  %rsi, %rcx
-	call *%rdi
-	addq $32, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call2)
-
-ENTRY(efi_call3)
-	SAVE_XMM
-	subq $32, %rsp
-	mov  %rcx, %r8
-	mov  %rsi, %rcx
-	call *%rdi
-	addq $32, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call3)
-
-ENTRY(efi_call4)
-	SAVE_XMM
-	subq $32, %rsp
-	mov %r8, %r9
-	mov %rcx, %r8
-	mov %rsi, %rcx
-	call *%rdi
-	addq $32, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call4)
-
-ENTRY(efi_call5)
-	SAVE_XMM
-	subq $48, %rsp
-	mov %r9, 32(%rsp)
-	mov %r8, %r9
-	mov %rcx, %r8
-	mov %rsi, %rcx
-	call *%rdi
-	addq $48, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call5)
-
-ENTRY(efi_call6)
-	SAVE_XMM
-	mov (%rsp), %rax
-	mov 8(%rax), %rax
-	subq $48, %rsp
-	mov %r9, 32(%rsp)
-	mov %rax, 40(%rsp)
-	mov %r8, %r9
-	mov %rcx, %r8
-	mov %rsi, %rcx
-	call *%rdi
-	addq $48, %rsp
-	RESTORE_XMM
-	ret
-ENDPROC(efi_call6)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/entry_32.S linux-libre-2.6.37-gnu/arch/x86/kernel/entry_32.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/entry_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/entry_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -115,8 +115,7 @@
 
  /* unfortunately push/pop can't be no-op */
 .macro PUSH_GS
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
 .endm
 .macro POP_GS pop=0
 	addl $(4 + \pop), %esp
@@ -140,14 +139,12 @@
 #else	/* CONFIG_X86_32_LAZY_GS */
 
 .macro PUSH_GS
-	pushl %gs
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %gs
 	/*CFI_REL_OFFSET gs, 0*/
 .endm
 
 .macro POP_GS pop=0
-98:	popl %gs
-	CFI_ADJUST_CFA_OFFSET -4
+98:	popl_cfi %gs
 	/*CFI_RESTORE gs*/
   .if \pop <> 0
 	add $\pop, %esp
@@ -195,35 +192,25 @@
 .macro SAVE_ALL
 	cld
 	PUSH_GS
-	pushl %fs
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %fs
 	/*CFI_REL_OFFSET fs, 0;*/
-	pushl %es
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %es
 	/*CFI_REL_OFFSET es, 0;*/
-	pushl %ds
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ds
 	/*CFI_REL_OFFSET ds, 0;*/
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	CFI_REL_OFFSET eax, 0
-	pushl %ebp
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebp
 	CFI_REL_OFFSET ebp, 0
-	pushl %edi
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %edi
 	CFI_REL_OFFSET edi, 0
-	pushl %esi
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %esi
 	CFI_REL_OFFSET esi, 0
-	pushl %edx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %edx
 	CFI_REL_OFFSET edx, 0
-	pushl %ecx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ecx
 	CFI_REL_OFFSET ecx, 0
-	pushl %ebx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebx
 	CFI_REL_OFFSET ebx, 0
 	movl $(__USER_DS), %edx
 	movl %edx, %ds
@@ -234,39 +221,29 @@
 .endm
 
 .macro RESTORE_INT_REGS
-	popl %ebx
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %ebx
 	CFI_RESTORE ebx
-	popl %ecx
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %ecx
 	CFI_RESTORE ecx
-	popl %edx
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %edx
 	CFI_RESTORE edx
-	popl %esi
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %esi
 	CFI_RESTORE esi
-	popl %edi
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %edi
 	CFI_RESTORE edi
-	popl %ebp
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %ebp
 	CFI_RESTORE ebp
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %eax
 	CFI_RESTORE eax
 .endm
 
 .macro RESTORE_REGS pop=0
 	RESTORE_INT_REGS
-1:	popl %ds
-	CFI_ADJUST_CFA_OFFSET -4
+1:	popl_cfi %ds
 	/*CFI_RESTORE ds;*/
-2:	popl %es
-	CFI_ADJUST_CFA_OFFSET -4
+2:	popl_cfi %es
 	/*CFI_RESTORE es;*/
-3:	popl %fs
-	CFI_ADJUST_CFA_OFFSET -4
+3:	popl_cfi %fs
 	/*CFI_RESTORE fs;*/
 	POP_GS \pop
 .pushsection .fixup, "ax"
@@ -320,16 +297,12 @@
 
 ENTRY(ret_from_fork)
 	CFI_STARTPROC
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	call schedule_tail
 	GET_THREAD_INFO(%ebp)
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
-	pushl $0x0202			# Reset kernel eflags
-	CFI_ADJUST_CFA_OFFSET 4
-	popfl
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %eax
+	pushl_cfi $0x0202		# Reset kernel eflags
+	popfl_cfi
 	jmp syscall_exit
 	CFI_ENDPROC
 END(ret_from_fork)
@@ -409,29 +382,23 @@
 	 * enough kernel state to call TRACE_IRQS_OFF can be called - but
 	 * we immediately enable interrupts at that point anyway.
 	 */
-	pushl $(__USER_DS)
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $__USER_DS
 	/*CFI_REL_OFFSET ss, 0*/
-	pushl %ebp
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebp
 	CFI_REL_OFFSET esp, 0
-	pushfl
+	pushfl_cfi
 	orl $X86_EFLAGS_IF, (%esp)
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $(__USER_CS)
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $__USER_CS
 	/*CFI_REL_OFFSET cs, 0*/
 	/*
 	 * Push current_thread_info()->sysenter_return to the stack.
 	 * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
 	 * pushed above; +8 corresponds to copy_thread's esp0 setting.
 	 */
-	pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi ((TI_sysenter_return)-THREAD_SIZE_asm+8+4*4)(%esp)
 	CFI_REL_OFFSET eip, 0
 
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	SAVE_ALL
 	ENABLE_INTERRUPTS(CLBR_NONE)
 
@@ -486,8 +453,7 @@
 	movl %eax,%edx			/* 2nd arg: syscall number */
 	movl $AUDIT_ARCH_I386,%eax	/* 1st arg: audit arch */
 	call audit_syscall_entry
-	pushl %ebx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebx
 	movl PT_EAX(%esp),%eax		/* reload syscall number */
 	jmp sysenter_do_call
 
@@ -529,8 +495,7 @@
 	# system call handler stub
 ENTRY(system_call)
 	RING0_INT_FRAME			# can't unwind into user space anyway
-	pushl %eax			# save orig_eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
 					# system call tracing in operation / emulation
@@ -566,7 +531,6 @@
 	je ldt_ss			# returning to user-space with LDT SS
 restore_nocheck:
 	RESTORE_REGS 4			# skip orig_eax/error_code
-	CFI_ADJUST_CFA_OFFSET -4
 irq_return:
 	INTERRUPT_RETURN
 .section .fixup,"ax"
@@ -619,10 +583,8 @@
 	shr $16, %edx
 	mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
 	mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
-	pushl $__ESPFIX_SS
-	CFI_ADJUST_CFA_OFFSET 4
-	push %eax			/* new kernel esp */
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $__ESPFIX_SS
+	pushl_cfi %eax			/* new kernel esp */
 	/* Disable interrupts, but do not irqtrace this section: we
 	 * will soon execute iret and the tracer was already set to
 	 * the irqstate after the iret */
@@ -666,11 +628,9 @@
 
 	ALIGN
 work_notifysig_v86:
-	pushl %ecx			# save ti_flags for do_notify_resume
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ecx			# save ti_flags for do_notify_resume
 	call save_v86_state		# %eax contains pt_regs pointer
-	popl %ecx
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %ecx
 	movl %eax, %esp
 #else
 	movl %esp, %eax
@@ -750,14 +710,18 @@
 #define PTREGSCALL3(name) \
 	ALIGN; \
 ptregs_##name: \
+	CFI_STARTPROC; \
 	leal 4(%esp),%eax; \
-	pushl %eax; \
+	pushl_cfi %eax; \
 	movl PT_EDX(%eax),%ecx; \
 	movl PT_ECX(%eax),%edx; \
 	movl PT_EBX(%eax),%eax; \
 	call sys_##name; \
 	addl $4,%esp; \
-	ret
+	CFI_ADJUST_CFA_OFFSET -4; \
+	ret; \
+	CFI_ENDPROC; \
+ENDPROC(ptregs_##name)
 
 PTREGSCALL1(iopl)
 PTREGSCALL0(fork)
@@ -772,15 +736,19 @@
 /* Clone is an oddball.  The 4th arg is in %edi */
 	ALIGN;
 ptregs_clone:
+	CFI_STARTPROC
 	leal 4(%esp),%eax
-	pushl %eax
-	pushl PT_EDI(%eax)
+	pushl_cfi %eax
+	pushl_cfi PT_EDI(%eax)
 	movl PT_EDX(%eax),%ecx
 	movl PT_ECX(%eax),%edx
 	movl PT_EBX(%eax),%eax
 	call sys_clone
 	addl $8,%esp
+	CFI_ADJUST_CFA_OFFSET -8
 	ret
+	CFI_ENDPROC
+ENDPROC(ptregs_clone)
 
 .macro FIXUP_ESPFIX_STACK
 /*
@@ -795,10 +763,8 @@
 	mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
 	shl $16, %eax
 	addl %esp, %eax			/* the adjusted stack pointer */
-	pushl $__KERNEL_DS
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $__KERNEL_DS
+	pushl_cfi %eax
 	lss (%esp), %esp		/* switch to the normal stack segment */
 	CFI_ADJUST_CFA_OFFSET -8
 .endm
@@ -835,8 +801,7 @@
       .if vector <> FIRST_EXTERNAL_VECTOR
 	CFI_ADJUST_CFA_OFFSET -4
       .endif
-1:	pushl $(~vector+0x80)	/* Note: always in signed byte range */
-	CFI_ADJUST_CFA_OFFSET 4
+1:	pushl_cfi $(~vector+0x80)	/* Note: always in signed byte range */
       .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
 	jmp 2f
       .endif
@@ -876,8 +841,7 @@
 #define BUILD_INTERRUPT3(name, nr, fn)	\
 ENTRY(name)				\
 	RING0_INT_FRAME;		\
-	pushl $~(nr);			\
-	CFI_ADJUST_CFA_OFFSET 4;	\
+	pushl_cfi $~(nr);		\
 	SAVE_ALL;			\
 	TRACE_IRQS_OFF			\
 	movl %esp,%eax;			\
@@ -893,21 +857,18 @@
 
 ENTRY(coprocessor_error)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_coprocessor_error
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_coprocessor_error
 	jmp error_code
 	CFI_ENDPROC
 END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
 #ifdef CONFIG_X86_INVD_BUG
 	/* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
-661:	pushl $do_general_protection
+661:	pushl_cfi $do_general_protection
 662:
 .section .altinstructions,"a"
 	.balign 4
@@ -922,19 +883,16 @@
 664:
 .previous
 #else
-	pushl $do_simd_coprocessor_error
+	pushl_cfi $do_simd_coprocessor_error
 #endif
-	CFI_ADJUST_CFA_OFFSET 4
 	jmp error_code
 	CFI_ENDPROC
 END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
 	RING0_INT_FRAME
-	pushl $-1			# mark this as an int
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_device_not_available
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $-1			# mark this as an int
+	pushl_cfi $do_device_not_available
 	jmp error_code
 	CFI_ENDPROC
 END(device_not_available)
@@ -956,82 +914,68 @@
 
 ENTRY(overflow)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_overflow
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_overflow
 	jmp error_code
 	CFI_ENDPROC
 END(overflow)
 
 ENTRY(bounds)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_bounds
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_bounds
 	jmp error_code
 	CFI_ENDPROC
 END(bounds)
 
 ENTRY(invalid_op)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_invalid_op
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_invalid_op
 	jmp error_code
 	CFI_ENDPROC
 END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_coprocessor_segment_overrun
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_coprocessor_segment_overrun
 	jmp error_code
 	CFI_ENDPROC
 END(coprocessor_segment_overrun)
 
 ENTRY(invalid_TSS)
 	RING0_EC_FRAME
-	pushl $do_invalid_TSS
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_invalid_TSS
 	jmp error_code
 	CFI_ENDPROC
 END(invalid_TSS)
 
 ENTRY(segment_not_present)
 	RING0_EC_FRAME
-	pushl $do_segment_not_present
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_segment_not_present
 	jmp error_code
 	CFI_ENDPROC
 END(segment_not_present)
 
 ENTRY(stack_segment)
 	RING0_EC_FRAME
-	pushl $do_stack_segment
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_stack_segment
 	jmp error_code
 	CFI_ENDPROC
 END(stack_segment)
 
 ENTRY(alignment_check)
 	RING0_EC_FRAME
-	pushl $do_alignment_check
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_alignment_check
 	jmp error_code
 	CFI_ENDPROC
 END(alignment_check)
 
 ENTRY(divide_error)
 	RING0_INT_FRAME
-	pushl $0			# no error code
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_divide_error
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0			# no error code
+	pushl_cfi $do_divide_error
 	jmp error_code
 	CFI_ENDPROC
 END(divide_error)
@@ -1039,10 +983,8 @@
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl machine_check_vector
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi machine_check_vector
 	jmp error_code
 	CFI_ENDPROC
 END(machine_check)
@@ -1050,10 +992,8 @@
 
 ENTRY(spurious_interrupt_bug)
 	RING0_INT_FRAME
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $do_spurious_interrupt_bug
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
+	pushl_cfi $do_spurious_interrupt_bug
 	jmp error_code
 	CFI_ENDPROC
 END(spurious_interrupt_bug)
@@ -1084,8 +1024,7 @@
 
 ENTRY(xen_hypervisor_callback)
 	CFI_STARTPROC
-	pushl $0
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $0
 	SAVE_ALL
 	TRACE_IRQS_OFF
 
@@ -1121,23 +1060,20 @@
 # We distinguish between categories by maintaining a status value in EAX.
 ENTRY(xen_failsafe_callback)
 	CFI_STARTPROC
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	movl $1,%eax
 1:	mov 4(%esp),%ds
 2:	mov 8(%esp),%es
 3:	mov 12(%esp),%fs
 4:	mov 16(%esp),%gs
 	testl %eax,%eax
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %eax
 	lea 16(%esp),%esp
 	CFI_ADJUST_CFA_OFFSET -16
 	jz 5f
 	addl $16,%esp
 	jmp iret_exc		# EAX != 0 => Category 2 (Bad IRET)
-5:	pushl $0		# EAX == 0 => Category 1 (Bad segment)
-	CFI_ADJUST_CFA_OFFSET 4
+5:	pushl_cfi $0		# EAX == 0 => Category 1 (Bad segment)
 	SAVE_ALL
 	jmp ret_from_exception
 	CFI_ENDPROC
@@ -1287,40 +1223,29 @@
 
 ENTRY(page_fault)
 	RING0_EC_FRAME
-	pushl $do_page_fault
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_page_fault
 	ALIGN
 error_code:
 	/* the function address is in %gs's slot on the stack */
-	pushl %fs
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %fs
 	/*CFI_REL_OFFSET fs, 0*/
-	pushl %es
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %es
 	/*CFI_REL_OFFSET es, 0*/
-	pushl %ds
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ds
 	/*CFI_REL_OFFSET ds, 0*/
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	CFI_REL_OFFSET eax, 0
-	pushl %ebp
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebp
 	CFI_REL_OFFSET ebp, 0
-	pushl %edi
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %edi
 	CFI_REL_OFFSET edi, 0
-	pushl %esi
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %esi
 	CFI_REL_OFFSET esi, 0
-	pushl %edx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %edx
 	CFI_REL_OFFSET edx, 0
-	pushl %ecx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ecx
 	CFI_REL_OFFSET ecx, 0
-	pushl %ebx
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ebx
 	CFI_REL_OFFSET ebx, 0
 	cld
 	movl $(__KERNEL_PERCPU), %ecx
@@ -1362,12 +1287,9 @@
 	movl TSS_sysenter_sp0 + \offset(%esp), %esp
 	CFI_DEF_CFA esp, 0
 	CFI_UNDEFINED eip
-	pushfl
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $__KERNEL_CS
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl $sysenter_past_esp
-	CFI_ADJUST_CFA_OFFSET 4
+	pushfl_cfi
+	pushl_cfi $__KERNEL_CS
+	pushl_cfi $sysenter_past_esp
 	CFI_REL_OFFSET eip, 0
 .endm
 
@@ -1377,8 +1299,7 @@
 	jne debug_stack_correct
 	FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
 debug_stack_correct:
-	pushl $-1			# mark this as an int
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $-1			# mark this as an int
 	SAVE_ALL
 	TRACE_IRQS_OFF
 	xorl %edx,%edx			# error code 0
@@ -1398,32 +1319,27 @@
  */
 ENTRY(nmi)
 	RING0_INT_FRAME
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	movl %ss, %eax
 	cmpw $__ESPFIX_SS, %ax
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %eax
 	je nmi_espfix_stack
 	cmpl $ia32_sysenter_target,(%esp)
 	je nmi_stack_fixup
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	movl %esp,%eax
 	/* Do not access memory above the end of our stack page,
 	 * it might not exist.
 	 */
 	andl $(THREAD_SIZE-1),%eax
 	cmpl $(THREAD_SIZE-20),%eax
-	popl %eax
-	CFI_ADJUST_CFA_OFFSET -4
+	popl_cfi %eax
 	jae nmi_stack_correct
 	cmpl $ia32_sysenter_target,12(%esp)
 	je nmi_debug_stack_check
 nmi_stack_correct:
 	/* We have a RING0_INT_FRAME here */
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	SAVE_ALL
 	xorl %edx,%edx		# zero error code
 	movl %esp,%eax		# pt_regs pointer
@@ -1452,18 +1368,14 @@
 	 *
 	 * create the pointer to lss back
 	 */
-	pushl %ss
-	CFI_ADJUST_CFA_OFFSET 4
-	pushl %esp
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %ss
+	pushl_cfi %esp
 	addl $4, (%esp)
 	/* copy the iret frame of 12 bytes */
 	.rept 3
-	pushl 16(%esp)
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi 16(%esp)
 	.endr
-	pushl %eax
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi %eax
 	SAVE_ALL
 	FIXUP_ESPFIX_STACK		# %eax == %esp
 	xorl %edx,%edx			# zero error code
@@ -1477,8 +1389,7 @@
 
 ENTRY(int3)
 	RING0_INT_FRAME
-	pushl $-1			# mark this as an int
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $-1			# mark this as an int
 	SAVE_ALL
 	TRACE_IRQS_OFF
 	xorl %edx,%edx		# zero error code
@@ -1490,8 +1401,7 @@
 
 ENTRY(general_protection)
 	RING0_EC_FRAME
-	pushl $do_general_protection
-	CFI_ADJUST_CFA_OFFSET 4
+	pushl_cfi $do_general_protection
 	jmp error_code
 	CFI_ENDPROC
 END(general_protection)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/entry_64.S linux-libre-2.6.37-gnu/arch/x86/kernel/entry_64.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/entry_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/entry_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -213,23 +213,17 @@
 	.macro FAKE_STACK_FRAME child_rip
 	/* push in order ss, rsp, eflags, cs, rip */
 	xorl %eax, %eax
-	pushq $__KERNEL_DS /* ss */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi $__KERNEL_DS /* ss */
 	/*CFI_REL_OFFSET	ss,0*/
-	pushq %rax /* rsp */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi %rax /* rsp */
 	CFI_REL_OFFSET	rsp,0
-	pushq $X86_EFLAGS_IF /* eflags - interrupts on */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi $X86_EFLAGS_IF /* eflags - interrupts on */
 	/*CFI_REL_OFFSET	rflags,0*/
-	pushq $__KERNEL_CS /* cs */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi $__KERNEL_CS /* cs */
 	/*CFI_REL_OFFSET	cs,0*/
-	pushq \child_rip /* rip */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi \child_rip /* rip */
 	CFI_REL_OFFSET	rip,0
-	pushq	%rax /* orig rax */
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi %rax /* orig rax */
 	.endm
 
 	.macro UNFAKE_STACK_FRAME
@@ -301,6 +295,7 @@
 	.endm
 
 /* save partial stack frame */
+	.pushsection .kprobes.text, "ax"
 ENTRY(save_args)
 	XCPT_FRAME
 	cld
@@ -340,6 +335,7 @@
 	ret
 	CFI_ENDPROC
 END(save_args)
+	.popsection
 
 ENTRY(save_rest)
 	PARTIAL_FRAME 1 REST_SKIP+8
@@ -398,10 +394,8 @@
 
 	LOCK ; btr $TIF_FORK,TI_flags(%r8)
 
-	push kernel_eflags(%rip)
-	CFI_ADJUST_CFA_OFFSET 8
-	popf					# reset kernel eflags
-	CFI_ADJUST_CFA_OFFSET -8
+	pushq_cfi kernel_eflags(%rip)
+	popfq_cfi				# reset kernel eflags
 
 	call schedule_tail			# rdi: 'prev' task parameter
 
@@ -521,11 +515,9 @@
 	jnc sysret_signal
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
-	pushq %rdi
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi %rdi
 	call schedule
-	popq  %rdi
-	CFI_ADJUST_CFA_OFFSET -8
+	popq_cfi %rdi
 	jmp sysret_check
 
 	/* Handle a signal */
@@ -634,11 +626,9 @@
 	jnc  int_very_careful
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
-	pushq %rdi
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi %rdi
 	call schedule
-	popq %rdi
-	CFI_ADJUST_CFA_OFFSET -8
+	popq_cfi %rdi
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
 	jmp int_with_check
@@ -652,12 +642,10 @@
 	/* Check for syscall exit trace */
 	testl $_TIF_WORK_SYSCALL_EXIT,%edx
 	jz int_signal
-	pushq %rdi
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi %rdi
 	leaq 8(%rsp),%rdi	# &ptregs -> arg1
 	call syscall_trace_leave
-	popq %rdi
-	CFI_ADJUST_CFA_OFFSET -8
+	popq_cfi %rdi
 	andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi
 	jmp int_restore_rest
 
@@ -714,9 +702,8 @@
 
 ENTRY(stub_execve)
 	CFI_STARTPROC
-	popq %r11
-	CFI_ADJUST_CFA_OFFSET -8
-	CFI_REGISTER rip, r11
+	addq $8, %rsp
+	PARTIAL_FRAME 0
 	SAVE_REST
 	FIXUP_TOP_OF_STACK %r11
 	movq %rsp, %rcx
@@ -735,7 +722,7 @@
 ENTRY(stub_rt_sigreturn)
 	CFI_STARTPROC
 	addq $8, %rsp
-	CFI_ADJUST_CFA_OFFSET	-8
+	PARTIAL_FRAME 0
 	SAVE_REST
 	movq %rsp,%rdi
 	FIXUP_TOP_OF_STACK %r11
@@ -766,8 +753,7 @@
       .if vector <> FIRST_EXTERNAL_VECTOR
 	CFI_ADJUST_CFA_OFFSET -8
       .endif
-1:	pushq $(~vector+0x80)	/* Note: always in signed byte range */
-	CFI_ADJUST_CFA_OFFSET 8
+1:	pushq_cfi $(~vector+0x80)	/* Note: always in signed byte range */
       .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
 	jmp 2f
       .endif
@@ -796,8 +782,8 @@
 
 /* 0(%rsp): ~(interrupt number) */
 	.macro interrupt func
-	subq $10*8, %rsp
-	CFI_ADJUST_CFA_OFFSET 10*8
+	subq $ORIG_RAX-ARGOFFSET+8, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-ARGOFFSET+8
 	call save_args
 	PARTIAL_FRAME 0
 	call \func
@@ -822,6 +808,7 @@
 	TRACE_IRQS_OFF
 	decl PER_CPU_VAR(irq_count)
 	leaveq
+	CFI_RESTORE		rbp
 	CFI_DEF_CFA_REGISTER	rsp
 	CFI_ADJUST_CFA_OFFSET	-8
 exit_intr:
@@ -903,11 +890,9 @@
 	jnc   retint_signal
 	TRACE_IRQS_ON
 	ENABLE_INTERRUPTS(CLBR_NONE)
-	pushq %rdi
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi %rdi
 	call  schedule
-	popq %rdi
-	CFI_ADJUST_CFA_OFFSET	-8
+	popq_cfi %rdi
 	GET_THREAD_INFO(%rcx)
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
@@ -956,8 +941,7 @@
 .macro apicinterrupt num sym do_sym
 ENTRY(\sym)
 	INTR_FRAME
-	pushq $~(\num)
-	CFI_ADJUST_CFA_OFFSET 8
+	pushq_cfi $~(\num)
 	interrupt \do_sym
 	jmp ret_from_intr
 	CFI_ENDPROC
@@ -981,22 +965,10 @@
 	x86_platform_ipi smp_x86_platform_ipi
 
 #ifdef CONFIG_SMP
-apicinterrupt INVALIDATE_TLB_VECTOR_START+0 \
-	invalidate_interrupt0 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+1 \
-	invalidate_interrupt1 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+2 \
-	invalidate_interrupt2 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+3 \
-	invalidate_interrupt3 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+4 \
-	invalidate_interrupt4 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+5 \
-	invalidate_interrupt5 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+6 \
-	invalidate_interrupt6 smp_invalidate_interrupt
-apicinterrupt INVALIDATE_TLB_VECTOR_START+7 \
-	invalidate_interrupt7 smp_invalidate_interrupt
+.irpc idx, "01234567"
+apicinterrupt (INVALIDATE_TLB_VECTOR_START)+\idx \
+	invalidate_interrupt\idx smp_invalidate_interrupt
+.endr
 #endif
 
 apicinterrupt THRESHOLD_APIC_VECTOR \
@@ -1023,9 +995,9 @@
 apicinterrupt SPURIOUS_APIC_VECTOR \
 	spurious_interrupt smp_spurious_interrupt
 
-#ifdef CONFIG_PERF_EVENTS
-apicinterrupt LOCAL_PENDING_VECTOR \
-	perf_pending_interrupt smp_perf_pending_interrupt
+#ifdef CONFIG_IRQ_WORK
+apicinterrupt IRQ_WORK_VECTOR \
+	irq_work_interrupt smp_irq_work_interrupt
 #endif
 
 /*
@@ -1036,8 +1008,8 @@
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
-	subq $15*8,%rsp
-	CFI_ADJUST_CFA_OFFSET 15*8
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call error_entry
 	DEFAULT_FRAME 0
 	movq %rsp,%rdi		/* pt_regs pointer */
@@ -1052,9 +1024,9 @@
 ENTRY(\sym)
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $-1		/* ORIG_RAX: no syscall to restart */
-	CFI_ADJUST_CFA_OFFSET 8
-	subq $15*8, %rsp
+	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call save_paranoid
 	TRACE_IRQS_OFF
 	movq %rsp,%rdi		/* pt_regs pointer */
@@ -1070,9 +1042,9 @@
 ENTRY(\sym)
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	pushq $-1		/* ORIG_RAX: no syscall to restart */
-	CFI_ADJUST_CFA_OFFSET 8
-	subq $15*8, %rsp
+	pushq_cfi $-1		/* ORIG_RAX: no syscall to restart */
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call save_paranoid
 	TRACE_IRQS_OFF
 	movq %rsp,%rdi		/* pt_regs pointer */
@@ -1089,8 +1061,8 @@
 ENTRY(\sym)
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	subq $15*8,%rsp
-	CFI_ADJUST_CFA_OFFSET 15*8
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call error_entry
 	DEFAULT_FRAME 0
 	movq %rsp,%rdi			/* pt_regs pointer */
@@ -1107,8 +1079,8 @@
 ENTRY(\sym)
 	XCPT_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
-	subq $15*8,%rsp
-	CFI_ADJUST_CFA_OFFSET 15*8
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call save_paranoid
 	DEFAULT_FRAME 0
 	TRACE_IRQS_OFF
@@ -1139,16 +1111,14 @@
 	/* edi:  new selector */
 ENTRY(native_load_gs_index)
 	CFI_STARTPROC
-	pushf
-	CFI_ADJUST_CFA_OFFSET 8
+	pushfq_cfi
 	DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI)
 	SWAPGS
 gs_change:
 	movl %edi,%gs
 2:	mfence		/* workaround */
 	SWAPGS
-	popf
-	CFI_ADJUST_CFA_OFFSET -8
+	popfq_cfi
 	ret
 	CFI_ENDPROC
 END(native_load_gs_index)
@@ -1215,8 +1185,7 @@
 /* Call softirq on interrupt stack. Interrupts are off. */
 ENTRY(call_softirq)
 	CFI_STARTPROC
-	push %rbp
-	CFI_ADJUST_CFA_OFFSET	8
+	pushq_cfi %rbp
 	CFI_REL_OFFSET rbp,0
 	mov  %rsp,%rbp
 	CFI_DEF_CFA_REGISTER rbp
@@ -1225,6 +1194,7 @@
 	push  %rbp			# backlink for old unwinder
 	call __do_softirq
 	leaveq
+	CFI_RESTORE		rbp
 	CFI_DEF_CFA_REGISTER	rsp
 	CFI_ADJUST_CFA_OFFSET   -8
 	decl PER_CPU_VAR(irq_count)
@@ -1368,7 +1338,7 @@
 
 	/* ebx:	no swapgs flag */
 ENTRY(paranoid_exit)
-	INTR_FRAME
+	DEFAULT_FRAME
 	DISABLE_INTERRUPTS(CLBR_NONE)
 	TRACE_IRQS_OFF
 	testl %ebx,%ebx				/* swapgs needed? */
@@ -1445,7 +1415,6 @@
 error_sti:
 	TRACE_IRQS_OFF
 	ret
-	CFI_ENDPROC
 
 /*
  * There are two places in the kernel that can potentially fault with
@@ -1470,6 +1439,7 @@
 	/* Fix truncated RIP */
 	movq %rcx,RIP+8(%rsp)
 	jmp error_swapgs
+	CFI_ENDPROC
 END(error_entry)
 
 
@@ -1498,8 +1468,8 @@
 	INTR_FRAME
 	PARAVIRT_ADJUST_EXCEPTION_FRAME
 	pushq_cfi $-1
-	subq $15*8, %rsp
-	CFI_ADJUST_CFA_OFFSET 15*8
+	subq $ORIG_RAX-R15, %rsp
+	CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
 	call save_paranoid
 	DEFAULT_FRAME 0
 	/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/ftrace.c linux-libre-2.6.37-gnu/arch/x86/kernel/ftrace.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/ftrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/ftrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -257,14 +257,9 @@
 	return mod_code_status;
 }
 
-
-
-
-static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
-
 static unsigned char *ftrace_nop_replace(void)
 {
-	return ftrace_nop;
+	return ideal_nop5;
 }
 
 static int
@@ -338,62 +333,6 @@
 
 int __init ftrace_dyn_arch_init(void *data)
 {
-	extern const unsigned char ftrace_test_p6nop[];
-	extern const unsigned char ftrace_test_nop5[];
-	extern const unsigned char ftrace_test_jmp[];
-	int faulted = 0;
-
-	/*
-	 * There is no good nop for all x86 archs.
-	 * We will default to using the P6_NOP5, but first we
-	 * will test to make sure that the nop will actually
-	 * work on this CPU. If it faults, we will then
-	 * go to a lesser efficient 5 byte nop. If that fails
-	 * we then just use a jmp as our nop. This isn't the most
-	 * efficient nop, but we can not use a multi part nop
-	 * since we would then risk being preempted in the middle
-	 * of that nop, and if we enabled tracing then, it might
-	 * cause a system crash.
-	 *
-	 * TODO: check the cpuid to determine the best nop.
-	 */
-	asm volatile (
-		"ftrace_test_jmp:"
-		"jmp ftrace_test_p6nop\n"
-		"nop\n"
-		"nop\n"
-		"nop\n"  /* 2 byte jmp + 3 bytes */
-		"ftrace_test_p6nop:"
-		P6_NOP5
-		"jmp 1f\n"
-		"ftrace_test_nop5:"
-		".byte 0x66,0x66,0x66,0x66,0x90\n"
-		"1:"
-		".section .fixup, \"ax\"\n"
-		"2:	movl $1, %0\n"
-		"	jmp ftrace_test_nop5\n"
-		"3:	movl $2, %0\n"
-		"	jmp 1b\n"
-		".previous\n"
-		_ASM_EXTABLE(ftrace_test_p6nop, 2b)
-		_ASM_EXTABLE(ftrace_test_nop5, 3b)
-		: "=r"(faulted) : "0" (faulted));
-
-	switch (faulted) {
-	case 0:
-		pr_info("converting mcount calls to 0f 1f 44 00 00\n");
-		memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
-		break;
-	case 1:
-		pr_info("converting mcount calls to 66 66 66 66 90\n");
-		memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
-		break;
-	case 2:
-		pr_info("converting mcount calls to jmp . + 5\n");
-		memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
-		break;
-	}
-
 	/* The return code is retured via data */
 	*(unsigned long *)data = 0;
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/head32.c linux-libre-2.6.37-gnu/arch/x86/kernel/head32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/head32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/head32.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/start_kernel.h>
 #include <linux/mm.h>
+#include <linux/memblock.h>
 
 #include <asm/setup.h>
 #include <asm/sections.h>
@@ -17,6 +18,7 @@
 #include <asm/apic.h>
 #include <asm/io_apic.h>
 #include <asm/bios_ebda.h>
+#include <asm/tlbflush.h>
 
 static void __init i386_default_early_setup(void)
 {
@@ -30,17 +32,18 @@
 
 void __init i386_start_kernel(void)
 {
+	memblock_init();
+
 #ifdef CONFIG_X86_TRAMPOLINE
 	/*
 	 * But first pinch a few for the stack/trampoline stuff
 	 * FIXME: Don't need the extra page at 4K, but need to fix
 	 * trampoline before removing it. (see the GDT stuff)
 	 */
-	reserve_early_overlap_ok(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE,
-					 "EX TRAMPOLINE");
+	memblock_x86_reserve_range(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
 #endif
 
-	reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
+	memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* Reserve INITRD */
@@ -49,7 +52,7 @@
 		u64 ramdisk_image = boot_params.hdr.ramdisk_image;
 		u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
 		u64 ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
-		reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
+		memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK");
 	}
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/head_32.S linux-libre-2.6.37-gnu/arch/x86/kernel/head_32.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/head_32.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/head_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -60,16 +60,18 @@
 #define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
 #endif
 
+/* Number of possible pages in the lowmem region */
+LOWMEM_PAGES = (((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT)
+	
 /* Enough space to fit pagetables for the low memory linear map */
-MAPPING_BEYOND_END = \
-	PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT
+MAPPING_BEYOND_END = PAGE_TABLE_SIZE(LOWMEM_PAGES) << PAGE_SHIFT
 
 /*
  * Worst-case size of the kernel mapping we need to make:
- * the worst-case size of the kernel itself, plus the extra we need
- * to map for the linear map.
+ * a relocatable kernel can live anywhere in lowmem, so we need to be able
+ * to map all of lowmem.
  */
-KERNEL_PAGES = (KERNEL_IMAGE_SIZE + MAPPING_BEYOND_END)>>PAGE_SHIFT
+KERNEL_PAGES = LOWMEM_PAGES
 
 INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm
 RESERVE_BRK(pagetables, INIT_MAP_SIZE)
@@ -183,13 +185,12 @@
 #ifdef CONFIG_X86_PAE
 
 	/*
-	 * In PAE mode swapper_pg_dir is statically defined to contain enough
-	 * entries to cover the VMSPLIT option (that is the top 1, 2 or 3
-	 * entries). The identity mapping is handled by pointing two PGD
-	 * entries to the first kernel PMD.
+	 * In PAE mode initial_page_table is statically defined to contain
+	 * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
+	 * entries). The identity mapping is handled by pointing two PGD entries
+	 * to the first kernel PMD.
 	 *
-	 * Note the upper half of each PMD or PTE are always zero at
-	 * this stage.
+	 * Note the upper half of each PMD or PTE are always zero at this stage.
 	 */
 
 #define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
@@ -197,7 +198,7 @@
 	xorl %ebx,%ebx				/* %ebx is kept at zero */
 
 	movl $pa(__brk_base), %edi
-	movl $pa(swapper_pg_pmd), %edx
+	movl $pa(initial_pg_pmd), %edx
 	movl $PTE_IDENT_ATTR, %eax
 10:
 	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PMD entry */
@@ -226,14 +227,14 @@
 	movl %eax, pa(max_pfn_mapped)
 
 	/* Do early initialization of the fixmap area */
-	movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
-	movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8)
+	movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+	movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)
 #else	/* Not PAE */
 
 page_pde_offset = (__PAGE_OFFSET >> 20);
 
 	movl $pa(__brk_base), %edi
-	movl $pa(swapper_pg_dir), %edx
+	movl $pa(initial_page_table), %edx
 	movl $PTE_IDENT_ATTR, %eax
 10:
 	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PDE entry */
@@ -257,8 +258,8 @@
 	movl %eax, pa(max_pfn_mapped)
 
 	/* Do early initialization of the fixmap area */
-	movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
-	movl %eax,pa(swapper_pg_dir+0xffc)
+	movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+	movl %eax,pa(initial_page_table+0xffc)
 #endif
 	jmp 3f
 /*
@@ -334,7 +335,7 @@
 /*
  * Enable paging
  */
-	movl pa(initial_page_table), %eax
+	movl $pa(initial_page_table), %eax
 	movl %eax,%cr3		/* set the page table pointer.. */
 	movl %cr0,%eax
 	orl  $X86_CR0_PG,%eax
@@ -614,8 +615,6 @@
 .align 4
 ENTRY(initial_code)
 	.long i386_start_kernel
-ENTRY(initial_page_table)
-	.long pa(swapper_pg_dir)
 
 /*
  * BSS section
@@ -623,20 +622,18 @@
 __PAGE_ALIGNED_BSS
 	.align PAGE_SIZE_asm
 #ifdef CONFIG_X86_PAE
-swapper_pg_pmd:
+ENTRY(initial_pg_pmd)
 	.fill 1024*KPMDS,4,0
 #else
-ENTRY(swapper_pg_dir)
+ENTRY(initial_page_table)
 	.fill 1024,4,0
 #endif
-swapper_pg_fixmap:
-	.fill 1024,4,0
-#ifdef CONFIG_X86_TRAMPOLINE
-ENTRY(trampoline_pg_dir)
+ENTRY(initial_pg_fixmap)
 	.fill 1024,4,0
-#endif
 ENTRY(empty_zero_page)
 	.fill 4096,1,0
+ENTRY(swapper_pg_dir)
+	.fill 1024,4,0
 
 /*
  * This starts the data section.
@@ -645,20 +642,20 @@
 __PAGE_ALIGNED_DATA
 	/* Page-aligned for the benefit of paravirt? */
 	.align PAGE_SIZE_asm
-ENTRY(swapper_pg_dir)
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0	/* low identity map */
+ENTRY(initial_page_table)
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR),0	/* low identity map */
 # if KPMDS == 3
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x2000),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR+0x2000),0
 # elif KPMDS == 2
 	.long	0,0
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR+0x1000),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR+0x1000),0
 # elif KPMDS == 1
 	.long	0,0
 	.long	0,0
-	.long	pa(swapper_pg_pmd+PGD_IDENT_ATTR),0
+	.long	pa(initial_pg_pmd+PGD_IDENT_ATTR),0
 # else
 #  error "Kernel PMDs should be 1, 2 or 3"
 # endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/head64.c linux-libre-2.6.37-gnu/arch/x86/kernel/head64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/head64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/head64.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/percpu.h>
 #include <linux/start_kernel.h>
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/processor.h>
 #include <asm/proto.h>
@@ -79,6 +80,8 @@
 	/* Cleanup the over mapped high alias */
 	cleanup_highmap();
 
+	max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
+
 	for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) {
 #ifdef CONFIG_EARLY_PRINTK
 		set_intr_gate(i, &early_idt_handlers[i]);
@@ -98,7 +101,9 @@
 {
 	copy_bootdata(__va(real_mode_data));
 
-	reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
+	memblock_init();
+
+	memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* Reserve INITRD */
@@ -107,7 +112,7 @@
 		unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
 		unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
 		unsigned long ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
-		reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
+		memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK");
 	}
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/head.c linux-libre-2.6.37-gnu/arch/x86/kernel/head.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/head.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/head.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/memblock.h>
 
 #include <asm/setup.h>
 #include <asm/bios_ebda.h>
@@ -51,5 +52,5 @@
 		lowmem = 0x9f000;
 
 	/* reserve all memory between lowmem and the 1MB mark */
-	reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved");
+	memblock_x86_reserve_range(lowmem, 0x100000, "* BIOS reserved");
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/hpet.c linux-libre-2.6.37-gnu/arch/x86/kernel/hpet.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/hpet.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/hpet.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,9 @@
 #define HPET_DEV_FSB_CAP		0x1000
 #define HPET_DEV_PERI_CAP		0x2000
 
+#define HPET_MIN_CYCLES			128
+#define HPET_MIN_PROG_DELTA		(HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1))
+
 #define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt)
 
 /*
@@ -299,8 +302,9 @@
 	/* Calculate the min / max delta */
 	hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
 							   &hpet_clockevent);
-	/* 5 usec minimum reprogramming delta. */
-	hpet_clockevent.min_delta_ns = 5000;
+	/* Setup minimum reprogramming delta. */
+	hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA,
+							   &hpet_clockevent);
 
 	/*
 	 * Start hpet with the boot cpu mask and make it
@@ -380,44 +384,37 @@
 			   struct clock_event_device *evt, int timer)
 {
 	u32 cnt;
+	s32 res;
 
 	cnt = hpet_readl(HPET_COUNTER);
 	cnt += (u32) delta;
 	hpet_writel(cnt, HPET_Tn_CMP(timer));
 
 	/*
-	 * We need to read back the CMP register on certain HPET
-	 * implementations (ATI chipsets) which seem to delay the
-	 * transfer of the compare register into the internal compare
-	 * logic. With small deltas this might actually be too late as
-	 * the counter could already be higher than the compare value
-	 * at that point and we would wait for the next hpet interrupt
-	 * forever. We found out that reading the CMP register back
-	 * forces the transfer so we can rely on the comparison with
-	 * the counter register below. If the read back from the
-	 * compare register does not match the value we programmed
-	 * then we might have a real hardware problem. We can not do
-	 * much about it here, but at least alert the user/admin with
-	 * a prominent warning.
-	 *
-	 * An erratum on some chipsets (ICH9,..), results in
-	 * comparator read immediately following a write returning old
-	 * value. Workaround for this is to read this value second
-	 * time, when first read returns old value.
-	 *
-	 * In fact the write to the comparator register is delayed up
-	 * to two HPET cycles so the workaround we tried to restrict
-	 * the readback to those known to be borked ATI chipsets
-	 * failed miserably. So we give up on optimizations forever
-	 * and penalize all HPET incarnations unconditionally.
+	 * HPETs are a complete disaster. The compare register is
+	 * based on a equal comparison and neither provides a less
+	 * than or equal functionality (which would require to take
+	 * the wraparound into account) nor a simple count down event
+	 * mode. Further the write to the comparator register is
+	 * delayed internally up to two HPET clock cycles in certain
+	 * chipsets (ATI, ICH9,10). Some newer AMD chipsets have even
+	 * longer delays. We worked around that by reading back the
+	 * compare register, but that required another workaround for
+	 * ICH9,10 chips where the first readout after write can
+	 * return the old stale value. We already had a minimum
+	 * programming delta of 5us enforced, but a NMI or SMI hitting
+	 * between the counter readout and the comparator write can
+	 * move us behind that point easily. Now instead of reading
+	 * the compare register back several times, we make the ETIME
+	 * decision based on the following: Return ETIME if the
+	 * counter value after the write is less than HPET_MIN_CYCLES
+	 * away from the event or if the counter is already ahead of
+	 * the event. The minimum programming delta for the generic
+	 * clockevents code is set to 1.5 * HPET_MIN_CYCLES.
 	 */
-	if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) {
-		if (hpet_readl(HPET_Tn_CMP(timer)) != cnt)
-			printk_once(KERN_WARNING
-				"hpet: compare register read back failed.\n");
-	}
+	res = (s32)(cnt - hpet_readl(HPET_COUNTER));
 
-	return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;
+	return res < HPET_MIN_CYCLES ? -ETIME : 0;
 }
 
 static void hpet_legacy_set_mode(enum clock_event_mode mode,
@@ -440,9 +437,9 @@
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev	*hpet_devs;
 
-void hpet_msi_unmask(unsigned int irq)
+void hpet_msi_unmask(struct irq_data *data)
 {
-	struct hpet_dev *hdev = get_irq_data(irq);
+	struct hpet_dev *hdev = data->handler_data;
 	unsigned int cfg;
 
 	/* unmask it */
@@ -451,10 +448,10 @@
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_mask(unsigned int irq)
+void hpet_msi_mask(struct irq_data *data)
 {
+	struct hpet_dev *hdev = data->handler_data;
 	unsigned int cfg;
-	struct hpet_dev *hdev = get_irq_data(irq);
 
 	/* mask it */
 	cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -462,18 +459,14 @@
 	hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
+void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg)
 {
-	struct hpet_dev *hdev = get_irq_data(irq);
-
 	hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num));
 	hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4);
 }
 
-void hpet_msi_read(unsigned int irq, struct msi_msg *msg)
+void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg)
 {
-	struct hpet_dev *hdev = get_irq_data(irq);
-
 	msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num));
 	msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4);
 	msg->address_hi = 0;
@@ -726,7 +719,7 @@
 
 	switch (action & 0xf) {
 	case CPU_ONLINE:
-		INIT_DELAYED_WORK_ON_STACK(&work.work, hpet_work);
+		INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work);
 		init_completion(&work.complete);
 		/* FIXME: add schedule_work_on() */
 		schedule_delayed_work_on(cpu, &work.work, 0);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/hw_breakpoint.c linux-libre-2.6.37-gnu/arch/x86/kernel/hw_breakpoint.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/hw_breakpoint.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/hw_breakpoint.c	2011-01-04 19:50:19.000000000 -0500
@@ -433,6 +433,10 @@
 	dr6_p = (unsigned long *)ERR_PTR(args->err);
 	dr6 = *dr6_p;
 
+	/* If it's a single step, TRAP bits are random */
+	if (dr6 & DR_STEP)
+		return NOTIFY_DONE;
+
 	/* Do an early return if no trap bits are set in DR6 */
 	if ((dr6 & DR_TRAP_BITS) == 0)
 		return NOTIFY_DONE;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/i387.c linux-libre-2.6.37-gnu/arch/x86/kernel/i387.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/i387.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/i387.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,19 +68,22 @@
 	 */
 
 	if (!HAVE_HWFP) {
+		/*
+		 * Disable xsave as we do not support it if i387
+		 * emulation is enabled.
+		 */
+		setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+		setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
 		xstate_size = sizeof(struct i387_soft_struct);
 		return;
 	}
 
 	if (cpu_has_fxsr)
 		xstate_size = sizeof(struct i387_fxsave_struct);
-#ifdef CONFIG_X86_32
 	else
 		xstate_size = sizeof(struct i387_fsave_struct);
-#endif
 }
 
-#ifdef CONFIG_X86_64
 /*
  * Called at bootup to set up the initial FPU state that is later cloned
  * into all processes.
@@ -88,12 +91,21 @@
 
 void __cpuinit fpu_init(void)
 {
-	unsigned long oldcr0 = read_cr0();
+	unsigned long cr0;
+	unsigned long cr4_mask = 0;
 
-	set_in_cr4(X86_CR4_OSFXSR);
-	set_in_cr4(X86_CR4_OSXMMEXCPT);
+	if (cpu_has_fxsr)
+		cr4_mask |= X86_CR4_OSFXSR;
+	if (cpu_has_xmm)
+		cr4_mask |= X86_CR4_OSXMMEXCPT;
+	if (cr4_mask)
+		set_in_cr4(cr4_mask);
 
-	write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
+	cr0 = read_cr0();
+	cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
+	if (!HAVE_HWFP)
+		cr0 |= X86_CR0_EM;
+	write_cr0(cr0);
 
 	if (!smp_processor_id())
 		init_thread_xstate();
@@ -104,24 +116,12 @@
 	clear_used_math();
 }
 
-#else	/* CONFIG_X86_64 */
-
-void __cpuinit fpu_init(void)
-{
-	if (!smp_processor_id())
-		init_thread_xstate();
-}
-
-#endif	/* CONFIG_X86_32 */
-
 void fpu_finit(struct fpu *fpu)
 {
-#ifdef CONFIG_X86_32
 	if (!HAVE_HWFP) {
 		finit_soft_fpu(&fpu->state->soft);
 		return;
 	}
-#endif
 
 	if (cpu_has_fxsr) {
 		struct i387_fxsave_struct *fx = &fpu->state->fxsave;
@@ -386,19 +386,17 @@
 #ifdef CONFIG_X86_64
 	env->fip = fxsave->rip;
 	env->foo = fxsave->rdp;
+	/*
+	 * should be actually ds/cs at fpu exception time, but
+	 * that information is not available in 64bit mode.
+	 */
+	env->fcs = task_pt_regs(tsk)->cs;
 	if (tsk == current) {
-		/*
-		 * should be actually ds/cs at fpu exception time, but
-		 * that information is not available in 64bit mode.
-		 */
-		asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos));
-		asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs));
+		savesegment(ds, env->fos);
 	} else {
-		struct pt_regs *regs = task_pt_regs(tsk);
-
-		env->fos = 0xffff0000 | tsk->thread.ds;
-		env->fcs = regs->cs;
+		env->fos = tsk->thread.ds;
 	}
+	env->fos |= 0xffff0000;
 #else
 	env->fip = fxsave->fip;
 	env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/i8259.c linux-libre-2.6.37-gnu/arch/x86/kernel/i8259.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/i8259.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/i8259.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,24 +29,10 @@
  * plus some generic x86 specific things if generic specifics makes
  * any sense at all.
  */
+static void init_8259A(int auto_eoi);
 
 static int i8259A_auto_eoi;
 DEFINE_RAW_SPINLOCK(i8259A_lock);
-static void mask_and_ack_8259A(unsigned int);
-static void mask_8259A(void);
-static void unmask_8259A(void);
-static void disable_8259A_irq(unsigned int irq);
-static void enable_8259A_irq(unsigned int irq);
-static void init_8259A(int auto_eoi);
-static int i8259A_irq_pending(unsigned int irq);
-
-struct irq_chip i8259A_chip = {
-	.name		= "XT-PIC",
-	.mask		= disable_8259A_irq,
-	.disable	= disable_8259A_irq,
-	.unmask		= enable_8259A_irq,
-	.mask_ack	= mask_and_ack_8259A,
-};
 
 /*
  * 8259A PIC functions to handle ISA devices:
@@ -68,7 +54,7 @@
  */
 unsigned long io_apic_irqs;
 
-static void disable_8259A_irq(unsigned int irq)
+static void mask_8259A_irq(unsigned int irq)
 {
 	unsigned int mask = 1 << irq;
 	unsigned long flags;
@@ -82,7 +68,12 @@
 	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
-static void enable_8259A_irq(unsigned int irq)
+static void disable_8259A_irq(struct irq_data *data)
+{
+	mask_8259A_irq(data->irq);
+}
+
+static void unmask_8259A_irq(unsigned int irq)
 {
 	unsigned int mask = ~(1 << irq);
 	unsigned long flags;
@@ -96,6 +87,11 @@
 	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
+static void enable_8259A_irq(struct irq_data *data)
+{
+	unmask_8259A_irq(data->irq);
+}
+
 static int i8259A_irq_pending(unsigned int irq)
 {
 	unsigned int mask = 1<<irq;
@@ -117,7 +113,7 @@
 	disable_irq_nosync(irq);
 	io_apic_irqs &= ~(1<<irq);
 	set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
-				      "XT");
+				      i8259A_chip.name);
 	enable_irq(irq);
 }
 
@@ -150,8 +146,9 @@
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-static void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(struct irq_data *data)
 {
+	unsigned int irq = data->irq;
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
 
@@ -223,6 +220,14 @@
 	}
 }
 
+struct irq_chip i8259A_chip = {
+	.name		= "XT-PIC",
+	.irq_mask	= disable_8259A_irq,
+	.irq_disable	= disable_8259A_irq,
+	.irq_unmask	= enable_8259A_irq,
+	.irq_mask_ack	= mask_and_ack_8259A,
+};
+
 static char irq_trigger[2];
 /**
  * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
@@ -342,9 +347,9 @@
 		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_chip.mask_ack = disable_8259A_irq;
+		i8259A_chip.irq_mask_ack = disable_8259A_irq;
 	else
-		i8259A_chip.mask_ack = mask_and_ack_8259A;
+		i8259A_chip.irq_mask_ack = mask_and_ack_8259A;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
@@ -363,14 +368,6 @@
 static void legacy_pic_noop(void) { };
 static void legacy_pic_uint_noop(unsigned int unused) { };
 static void legacy_pic_int_noop(int unused) { };
-
-static struct irq_chip dummy_pic_chip  = {
-	.name = "dummy pic",
-	.mask = legacy_pic_uint_noop,
-	.unmask = legacy_pic_uint_noop,
-	.disable = legacy_pic_uint_noop,
-	.mask_ack = legacy_pic_uint_noop,
-};
 static int legacy_pic_irq_pending_noop(unsigned int irq)
 {
 	return 0;
@@ -378,7 +375,9 @@
 
 struct legacy_pic null_legacy_pic = {
 	.nr_legacy_irqs = 0,
-	.chip = &dummy_pic_chip,
+	.chip = &dummy_irq_chip,
+	.mask = legacy_pic_uint_noop,
+	.unmask = legacy_pic_uint_noop,
 	.mask_all = legacy_pic_noop,
 	.restore_mask = legacy_pic_noop,
 	.init = legacy_pic_int_noop,
@@ -389,7 +388,9 @@
 struct legacy_pic default_legacy_pic = {
 	.nr_legacy_irqs = NR_IRQS_LEGACY,
 	.chip  = &i8259A_chip,
-	.mask_all  = mask_8259A,
+	.mask = mask_8259A_irq,
+	.unmask = unmask_8259A_irq,
+	.mask_all = mask_8259A,
 	.restore_mask = unmask_8259A,
 	.init = init_8259A,
 	.irq_pending = i8259A_irq_pending,
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/irq_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/irq_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/irq_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/irq_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/uaccess.h>
 #include <linux/percpu.h>
+#include <linux/mm.h>
 
 #include <asm/apic.h>
 
@@ -49,21 +50,17 @@
 static inline void print_stack_overflow(void) { }
 #endif
 
-#ifdef CONFIG_4KSTACKS
 /*
  * per-CPU IRQ handling contexts (thread information and stack)
  */
 union irq_ctx {
 	struct thread_info      tinfo;
 	u32                     stack[THREAD_SIZE/sizeof(u32)];
-} __attribute__((aligned(PAGE_SIZE)));
+} __attribute__((aligned(THREAD_SIZE)));
 
 static DEFINE_PER_CPU(union irq_ctx *, hardirq_ctx);
 static DEFINE_PER_CPU(union irq_ctx *, softirq_ctx);
 
-static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, hardirq_stack);
-static DEFINE_PER_CPU_PAGE_ALIGNED(union irq_ctx, softirq_stack);
-
 static void call_on_stack(void *func, void *stack)
 {
 	asm volatile("xchgl	%%ebx,%%esp	\n"
@@ -129,7 +126,9 @@
 	if (per_cpu(hardirq_ctx, cpu))
 		return;
 
-	irqctx = &per_cpu(hardirq_stack, cpu);
+	irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+					       THREAD_FLAGS,
+					       THREAD_ORDER));
 	irqctx->tinfo.task		= NULL;
 	irqctx->tinfo.exec_domain	= NULL;
 	irqctx->tinfo.cpu		= cpu;
@@ -138,7 +137,9 @@
 
 	per_cpu(hardirq_ctx, cpu) = irqctx;
 
-	irqctx = &per_cpu(softirq_stack, cpu);
+	irqctx = page_address(alloc_pages_node(cpu_to_node(cpu),
+					       THREAD_FLAGS,
+					       THREAD_ORDER));
 	irqctx->tinfo.task		= NULL;
 	irqctx->tinfo.exec_domain	= NULL;
 	irqctx->tinfo.cpu		= cpu;
@@ -151,11 +152,6 @@
 	       cpu, per_cpu(hardirq_ctx, cpu),  per_cpu(softirq_ctx, cpu));
 }
 
-void irq_ctx_exit(int cpu)
-{
-	per_cpu(hardirq_ctx, cpu) = NULL;
-}
-
 asmlinkage void do_softirq(void)
 {
 	unsigned long flags;
@@ -187,11 +183,6 @@
 	local_irq_restore(flags);
 }
 
-#else
-static inline int
-execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) { return 0; }
-#endif
-
 bool handle_irq(unsigned irq, struct pt_regs *regs)
 {
 	struct irq_desc *desc;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/irq.c linux-libre-2.6.37-gnu/arch/x86/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,10 +67,10 @@
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
 	seq_printf(p, "  Performance monitoring interrupts\n");
-	seq_printf(p, "%*s: ", prec, "PND");
+	seq_printf(p, "%*s: ", prec, "IWI");
 	for_each_online_cpu(j)
-		seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
-	seq_printf(p, "  Performance pending work\n");
+		seq_printf(p, "%10u ", irq_stats(j)->apic_irq_work_irqs);
+	seq_printf(p, "  IRQ work interrupts\n");
 #endif
 	if (x86_platform_ipi_callback) {
 		seq_printf(p, "%*s: ", prec, "PLT");
@@ -159,7 +159,7 @@
 	seq_printf(p, "%*d: ", prec, i);
 	for_each_online_cpu(j)
 		seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-	seq_printf(p, " %8s", desc->chip->name);
+	seq_printf(p, " %8s", desc->irq_data.chip->name);
 	seq_printf(p, "-%-8s", desc->name);
 
 	if (action) {
@@ -185,7 +185,7 @@
 	sum += irq_stats(cpu)->apic_timer_irqs;
 	sum += irq_stats(cpu)->irq_spurious_count;
 	sum += irq_stats(cpu)->apic_perf_irqs;
-	sum += irq_stats(cpu)->apic_pending_irqs;
+	sum += irq_stats(cpu)->apic_irq_work_irqs;
 #endif
 	if (x86_platform_ipi_callback)
 		sum += irq_stats(cpu)->x86_platform_ipis;
@@ -282,6 +282,7 @@
 	unsigned int irq, vector;
 	static int warned;
 	struct irq_desc *desc;
+	struct irq_data *data;
 
 	for_each_irq_desc(irq, desc) {
 		int break_affinity = 0;
@@ -296,7 +297,8 @@
 		/* interrupt's are disabled at this point */
 		raw_spin_lock(&desc->lock);
 
-		affinity = desc->affinity;
+		data = &desc->irq_data;
+		affinity = data->affinity;
 		if (!irq_has_action(irq) ||
 		    cpumask_equal(affinity, cpu_online_mask)) {
 			raw_spin_unlock(&desc->lock);
@@ -315,16 +317,16 @@
 			affinity = cpu_all_mask;
 		}
 
-		if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->mask)
-			desc->chip->mask(irq);
+		if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_mask)
+			data->chip->irq_mask(data);
 
-		if (desc->chip->set_affinity)
-			desc->chip->set_affinity(irq, affinity);
+		if (data->chip->irq_set_affinity)
+			data->chip->irq_set_affinity(data, affinity, true);
 		else if (!(warned++))
 			set_affinity = 0;
 
-		if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->unmask)
-			desc->chip->unmask(irq);
+		if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_unmask)
+			data->chip->irq_unmask(data);
 
 		raw_spin_unlock(&desc->lock);
 
@@ -355,10 +357,10 @@
 		if (irr  & (1 << (vector % 32))) {
 			irq = __get_cpu_var(vector_irq)[vector];
 
-			desc = irq_to_desc(irq);
+			data = irq_get_irq_data(irq);
 			raw_spin_lock(&desc->lock);
-			if (desc->chip->retrigger)
-				desc->chip->retrigger(irq);
+			if (data->chip->irq_retrigger)
+				data->chip->irq_retrigger(data);
 			raw_spin_unlock(&desc->lock);
 		}
 	}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/irqinit.c linux-libre-2.6.37-gnu/arch/x86/kernel/irqinit.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/irqinit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/irqinit.c	2011-01-04 19:50:19.000000000 -0500
@@ -100,6 +100,8 @@
 
 void __init init_ISA_irqs(void)
 {
+	struct irq_chip *chip = legacy_pic->chip;
+	const char *name = chip->name;
 	int i;
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
@@ -107,19 +109,8 @@
 #endif
 	legacy_pic->init(0);
 
-	/*
-	 * 16 old-style INTA-cycle interrupts:
-	 */
-	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) {
-		struct irq_desc *desc = irq_to_desc(i);
-
-		desc->status = IRQ_DISABLED;
-		desc->action = NULL;
-		desc->depth = 1;
-
-		set_irq_chip_and_handler_name(i, &i8259A_chip,
-					      handle_level_irq, "XT");
-	}
+	for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
+		set_irq_chip_and_handler_name(i, chip, handle_level_irq, name);
 }
 
 void __init init_IRQ(void)
@@ -224,9 +215,9 @@
 	alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
 	alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
-	/* Performance monitoring interrupts: */
-# ifdef CONFIG_PERF_EVENTS
-	alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
+	/* IRQ work interrupts: */
+# ifdef CONFIG_IRQ_WORK
+	alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt);
 # endif
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/irq_work.c linux-libre-2.6.37-gnu/arch/x86/kernel/irq_work.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/irq_work.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/irq_work.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,30 @@
+/*
+ * x86 specific code for irq_work
+ *
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq_work.h>
+#include <linux/hardirq.h>
+#include <asm/apic.h>
+
+void smp_irq_work_interrupt(struct pt_regs *regs)
+{
+	irq_enter();
+	ack_APIC_irq();
+	inc_irq_stat(apic_irq_work_irqs);
+	irq_work_run();
+	irq_exit();
+}
+
+void arch_irq_work_raise(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	if (!cpu_has_apic)
+		return;
+
+	apic->send_IPI_self(IRQ_WORK_VECTOR);
+	apic_wait_icr_idle();
+#endif
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/jump_label.c linux-libre-2.6.37-gnu/arch/x86/kernel/jump_label.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/jump_label.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/jump_label.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,50 @@
+/*
+ * jump label x86 support
+ *
+ * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
+ *
+ */
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/cpu.h>
+#include <asm/kprobes.h>
+#include <asm/alternative.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+union jump_code_union {
+	char code[JUMP_LABEL_NOP_SIZE];
+	struct {
+		char jump;
+		int offset;
+	} __attribute__((packed));
+};
+
+void arch_jump_label_transform(struct jump_entry *entry,
+			       enum jump_label_type type)
+{
+	union jump_code_union code;
+
+	if (type == JUMP_LABEL_ENABLE) {
+		code.jump = 0xe9;
+		code.offset = entry->target -
+				(entry->code + JUMP_LABEL_NOP_SIZE);
+	} else
+		memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+	get_online_cpus();
+	mutex_lock(&text_mutex);
+	text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+	mutex_unlock(&text_mutex);
+	put_online_cpus();
+}
+
+void arch_jump_label_text_poke_early(jump_label_t addr)
+{
+	text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+}
+
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/k8.c linux-libre-2.6.37-gnu/arch/x86/kernel/k8.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/k8.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/k8.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,137 +0,0 @@
-/*
- * Shared support code for AMD K8 northbridges and derivates.
- * Copyright 2006 Andi Kleen, SUSE Labs. Subject to GPLv2.
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <asm/k8.h>
-
-int num_k8_northbridges;
-EXPORT_SYMBOL(num_k8_northbridges);
-
-static u32 *flush_words;
-
-struct pci_device_id k8_nb_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
-	{}
-};
-EXPORT_SYMBOL(k8_nb_ids);
-
-struct pci_dev **k8_northbridges;
-EXPORT_SYMBOL(k8_northbridges);
-
-static struct pci_dev *next_k8_northbridge(struct pci_dev *dev)
-{
-	do {
-		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
-		if (!dev)
-			break;
-	} while (!pci_match_id(&k8_nb_ids[0], dev));
-	return dev;
-}
-
-int cache_k8_northbridges(void)
-{
-	int i;
-	struct pci_dev *dev;
-
-	if (num_k8_northbridges)
-		return 0;
-
-	dev = NULL;
-	while ((dev = next_k8_northbridge(dev)) != NULL)
-		num_k8_northbridges++;
-
-	k8_northbridges = kmalloc((num_k8_northbridges + 1) * sizeof(void *),
-				  GFP_KERNEL);
-	if (!k8_northbridges)
-		return -ENOMEM;
-
-	if (!num_k8_northbridges) {
-		k8_northbridges[0] = NULL;
-		return 0;
-	}
-
-	flush_words = kmalloc(num_k8_northbridges * sizeof(u32), GFP_KERNEL);
-	if (!flush_words) {
-		kfree(k8_northbridges);
-		return -ENOMEM;
-	}
-
-	dev = NULL;
-	i = 0;
-	while ((dev = next_k8_northbridge(dev)) != NULL) {
-		k8_northbridges[i] = dev;
-		pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
-	}
-	k8_northbridges[i] = NULL;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(cache_k8_northbridges);
-
-/* Ignores subdevice/subvendor but as far as I can figure out
-   they're useless anyways */
-int __init early_is_k8_nb(u32 device)
-{
-	struct pci_device_id *id;
-	u32 vendor = device & 0xffff;
-	device >>= 16;
-	for (id = k8_nb_ids; id->vendor; id++)
-		if (vendor == id->vendor && device == id->device)
-			return 1;
-	return 0;
-}
-
-void k8_flush_garts(void)
-{
-	int flushed, i;
-	unsigned long flags;
-	static DEFINE_SPINLOCK(gart_lock);
-
-	/* Avoid races between AGP and IOMMU. In theory it's not needed
-	   but I'm not sure if the hardware won't lose flush requests
-	   when another is pending. This whole thing is so expensive anyways
-	   that it doesn't matter to serialize more. -AK */
-	spin_lock_irqsave(&gart_lock, flags);
-	flushed = 0;
-	for (i = 0; i < num_k8_northbridges; i++) {
-		pci_write_config_dword(k8_northbridges[i], 0x9c,
-				       flush_words[i]|1);
-		flushed++;
-	}
-	for (i = 0; i < num_k8_northbridges; i++) {
-		u32 w;
-		/* Make sure the hardware actually executed the flush*/
-		for (;;) {
-			pci_read_config_dword(k8_northbridges[i],
-					      0x9c, &w);
-			if (!(w & 1))
-				break;
-			cpu_relax();
-		}
-	}
-	spin_unlock_irqrestore(&gart_lock, flags);
-	if (!flushed)
-		printk("nothing to flush?\n");
-}
-EXPORT_SYMBOL_GPL(k8_flush_garts);
-
-static __init int init_k8_nbs(void)
-{
-	int err = 0;
-
-	err = cache_k8_northbridges();
-
-	if (err < 0)
-		printk(KERN_NOTICE "K8 NB: Cannot enumerate AMD northbridges.\n");
-
-	return err;
-}
-
-/* This has to go after the PCI subsystem */
-fs_initcall(init_k8_nbs);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/kdebugfs.c linux-libre-2.6.37-gnu/arch/x86/kernel/kdebugfs.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/kdebugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/kdebugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,6 +78,7 @@
 static const struct file_operations fops_setup_data = {
 	.read		= setup_data_read,
 	.open		= setup_data_open,
+	.llseek		= default_llseek,
 };
 
 static int __init
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/kgdb.c linux-libre-2.6.37-gnu/arch/x86/kernel/kgdb.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/kgdb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/kgdb.c	2011-01-04 19:50:19.000000000 -0500
@@ -315,14 +315,18 @@
 		if (!breakinfo[i].enabled)
 			continue;
 		bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
-		if (bp->attr.disabled == 1)
+		if (!bp->attr.disabled) {
+			arch_uninstall_hw_breakpoint(bp);
+			bp->attr.disabled = 1;
 			continue;
+		}
 		if (dbg_is_early)
 			early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
 						 breakinfo[i].type);
-		else
-			arch_uninstall_hw_breakpoint(bp);
-		bp->attr.disabled = 1;
+		else if (hw_break_release_slot(i))
+			printk(KERN_ERR "KGDB: hw bpt remove failed %lx\n",
+			       breakinfo[i].addr);
+		breakinfo[i].enabled = 0;
 	}
 }
 
@@ -387,7 +391,7 @@
  *	disable hardware debugging while it is processing gdb packets or
  *	handling exception.
  */
-void kgdb_disable_hw_debug(struct pt_regs *regs)
+static void kgdb_disable_hw_debug(struct pt_regs *regs)
 {
 	int i;
 	int cpu = raw_smp_processor_id();
@@ -477,8 +481,6 @@
 				   raw_smp_processor_id());
 		}
 
-		kgdb_correct_hw_break();
-
 		return 0;
 	}
 
@@ -621,7 +623,12 @@
 static void kgdb_hw_overflow_handler(struct perf_event *event, int nmi,
 		struct perf_sample_data *data, struct pt_regs *regs)
 {
-	kgdb_ll_trap(DIE_DEBUG, "debug", regs, 0, 0, SIGTRAP);
+	struct task_struct *tsk = current;
+	int i;
+
+	for (i = 0; i < 4; i++)
+		if (breakinfo[i].enabled)
+			tsk->thread.debugreg6 |= (DR_TRAP0 << i);
 }
 
 void kgdb_arch_late(void)
@@ -644,7 +651,7 @@
 		if (breakinfo[i].pev)
 			continue;
 		breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL);
-		if (IS_ERR(breakinfo[i].pev)) {
+		if (IS_ERR((void * __force)breakinfo[i].pev)) {
 			printk(KERN_ERR "kgdb: Could not allocate hw"
 			       "breakpoints\nDisabling the kernel debugger\n");
 			breakinfo[i].pev = NULL;
@@ -721,6 +728,7 @@
 	.flags			= KGDB_HW_BREAKPOINT,
 	.set_hw_breakpoint	= kgdb_set_hw_break,
 	.remove_hw_breakpoint	= kgdb_remove_hw_break,
+	.disable_hw_break	= kgdb_disable_hw_debug,
 	.remove_all_hw_break	= kgdb_remove_all_hw_break,
 	.correct_hw_break	= kgdb_correct_hw_break,
 };
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/kprobes.c linux-libre-2.6.37-gnu/arch/x86/kernel/kprobes.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/kprobes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/kprobes.c	2011-01-04 19:50:19.000000000 -0500
@@ -230,9 +230,6 @@
 	return 0;
 }
 
-/* Dummy buffers for kallsyms_lookup */
-static char __dummy_buf[KSYM_NAME_LEN];
-
 /* Check if paddr is at an instruction boundary */
 static int __kprobes can_probe(unsigned long paddr)
 {
@@ -241,7 +238,7 @@
 	struct insn insn;
 	kprobe_opcode_t buf[MAX_INSN_SIZE];
 
-	if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
+	if (!kallsyms_lookup_size_offset(paddr, NULL, &offset))
 		return 0;
 
 	/* Decode instructions */
@@ -1129,7 +1126,7 @@
 	*(unsigned long *)addr = val;
 }
 
-void __kprobes kprobes_optinsn_template_holder(void)
+static void __used __kprobes kprobes_optinsn_template_holder(void)
 {
 	asm volatile (
 			".global optprobe_template_entry\n"
@@ -1221,7 +1218,8 @@
 	}
 	/* Check whether the address range is reserved */
 	if (ftrace_text_reserved(src, src + len - 1) ||
-	    alternatives_text_reserved(src, src + len - 1))
+	    alternatives_text_reserved(src, src + len - 1) ||
+	    jump_label_text_reserved(src, src + len - 1))
 		return -EBUSY;
 
 	return len;
@@ -1269,11 +1267,9 @@
 	unsigned long addr, size = 0, offset = 0;
 	struct insn insn;
 	kprobe_opcode_t buf[MAX_INSN_SIZE];
-	/* Dummy buffers for lookup_symbol_attrs */
-	static char __dummy_buf[KSYM_NAME_LEN];
 
 	/* Lookup symbol including addr */
-	if (!kallsyms_lookup(paddr, &size, &offset, NULL, __dummy_buf))
+	if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
 		return 0;
 
 	/* Check there is enough space for a relative jump. */
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/kvmclock.c linux-libre-2.6.37-gnu/arch/x86/kernel/kvmclock.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/kvmclock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/kvmclock.c	2011-01-04 19:50:19.000000000 -0500
@@ -128,13 +128,15 @@
 static int kvm_register_clock(char *txt)
 {
 	int cpu = smp_processor_id();
-	int low, high;
+	int low, high, ret;
+
 	low = (int)__pa(&per_cpu(hv_clock, cpu)) | 1;
 	high = ((u64)__pa(&per_cpu(hv_clock, cpu)) >> 32);
+	ret = native_write_msr_safe(msr_kvm_system_time, low, high);
 	printk(KERN_INFO "kvm-clock: cpu %d, msr %x:%x, %s\n",
 	       cpu, high, low, txt);
 
-	return native_write_msr_safe(msr_kvm_system_time, low, high);
+	return ret;
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/machine_kexec_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/machine_kexec_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/machine_kexec_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/machine_kexec_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,7 +36,7 @@
 		if (!page)
 			goto out;
 		pud = (pud_t *)page_address(page);
-		memset(pud, 0, PAGE_SIZE);
+		clear_page(pud);
 		set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
 	}
 	pud = pud_offset(pgd, addr);
@@ -45,7 +45,7 @@
 		if (!page)
 			goto out;
 		pmd = (pmd_t *)page_address(page);
-		memset(pmd, 0, PAGE_SIZE);
+		clear_page(pmd);
 		set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
 	}
 	pmd = pmd_offset(pud, addr);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/Makefile linux-libre-2.6.37-gnu/arch/x86/kernel/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/kernel/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -34,8 +34,8 @@
 obj-y			:= process_$(BITS).o signal.o entry_$(BITS).o
 obj-y			+= traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y			+= time.o ioport.o ldt.o dumpstack.o
-obj-y			+= setup.o x86_init.o i8259.o irqinit.o
-obj-$(CONFIG_X86_VISWS)	+= visws_quirks.o
+obj-y			+= setup.o x86_init.o i8259.o irqinit.o jump_label.o
+obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-$(CONFIG_X86_32)	+= probe_roms_32.o
 obj-$(CONFIG_X86_32)	+= sys_i386_32.o i386_ksyms_32.o
 obj-$(CONFIG_X86_64)	+= sys_x86_64.o x8664_ksyms_64.o
@@ -44,6 +44,8 @@
 obj-y			+= pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
 obj-y			+= alternative.o i8253.o pci-nommu.o hw_breakpoint.o
 obj-y			+= tsc.o io_delay.o rtc.o
+obj-y			+= pci-iommu_table.o
+obj-y			+= resource.o
 
 obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
 obj-y				+= process.o
@@ -56,7 +58,6 @@
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
 obj-y				+= acpi/
-obj-$(CONFIG_SFI)		+= sfi.o
 obj-y				+= reboot.o
 obj-$(CONFIG_MCA)		+= mca_32.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
@@ -80,20 +81,19 @@
 obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_MODULES)		+= module.o
-obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
 obj-$(CONFIG_KGDB)		+= kgdb.o
 obj-$(CONFIG_VM86)		+= vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_EARLY_PRINTK_MRST)	+= early_printk_mrst.o
 
 obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_APB_TIMER)		+= apb_timer.o
 
-obj-$(CONFIG_K8_NB)		+= k8.o
+obj-$(CONFIG_AMD_NB)		+= amd_nb.o
 obj-$(CONFIG_DEBUG_RODATA_TEST)	+= test_rodata.o
 obj-$(CONFIG_DEBUG_NX_TEST)	+= test_nx.o
 
-obj-$(CONFIG_VMI)		+= vmi_32.o vmiclock_32.o
 obj-$(CONFIG_KVM_GUEST)		+= kvm.o
 obj-$(CONFIG_KVM_CLOCK)		+= kvmclock.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o paravirt_patch_$(BITS).o
@@ -102,13 +102,6 @@
 
 obj-$(CONFIG_PCSPKR_PLATFORM)	+= pcspeaker.o
 
-obj-$(CONFIG_SCx200)		+= scx200.o
-scx200-y			+= scx200_32.o
-
-obj-$(CONFIG_OLPC)		+= olpc.o
-obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
-obj-$(CONFIG_X86_MRST)		+= mrst.o
-
 microcode-y				:= microcode_core.o
 microcode-$(CONFIG_MICROCODE_INTEL)	+= microcode_intel.o
 microcode-$(CONFIG_MICROCODE_AMD)	+= microcode_amd.o
@@ -121,8 +114,6 @@
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
-	obj-$(CONFIG_X86_UV)		+= tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o
-	obj-$(CONFIG_X86_PM_TIMER)	+= pmtimer_64.o
 	obj-$(CONFIG_AUDIT)		+= audit_64.o
 
 	obj-$(CONFIG_GART_IOMMU)	+= pci-gart_64.o aperture_64.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_amd.c linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_amd.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_amd.c	2012-03-23 21:38:11.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_amd.c	2012-03-23 23:29:15.000000000 -0400
@@ -212,7 +212,7 @@
 		return 0;
 	}
 
-	equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+	equiv_cpu_table = vmalloc(size);
 	if (!equiv_cpu_table) {
 		pr_err("failed to allocate equivalent CPU table\n");
 		return 0;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_core.c linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_core.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_core.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
  *	Software Developer's Manual
  *	Order Number 253668 or free download from:
  *
- *	http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *	http://developer.intel.com/Assets/PDF/manual/253668.pdf	
  *
  *	For more information, go to http://www.urbanmyth.org/microcode
  *
@@ -232,6 +232,7 @@
 	.owner			= THIS_MODULE,
 	.write			= microcode_write,
 	.open			= microcode_open,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice microcode_dev = {
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_intel.c linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_intel.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/microcode_intel.c	2012-03-23 21:38:15.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/microcode_intel.c	2012-03-23 23:29:19.000000000 -0400
@@ -12,7 +12,7 @@
  *	Software Developer's Manual
  *	Order Number 253668 or free download from:
  *
- *	http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *	http://developer.intel.com/Assets/PDF/manual/253668.pdf	
  *
  *	For more information, go to http://www.urbanmyth.org/microcode
  *
@@ -364,8 +364,7 @@
 
 		/* For performance reasons, reuse mc area when possible */
 		if (!mc || mc_size > curr_mc_size) {
-			if (mc)
-				vfree(mc);
+			vfree(mc);
 			mc = vmalloc(mc_size);
 			if (!mc)
 				break;
@@ -374,13 +373,11 @@
 
 		if (get_ucode_data(mc, ucode_ptr, mc_size) ||
 		    microcode_sanity_check(mc) < 0) {
-			vfree(mc);
 			break;
 		}
 
 		if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
-			if (new_mc)
-				vfree(new_mc);
+			vfree(new_mc);
 			new_rev = mc_header.rev;
 			new_mc  = mc;
 			mc = NULL;	/* trigger new vmalloc */
@@ -390,12 +387,10 @@
 		leftover  -= mc_size;
 	}
 
-	if (mc)
-		vfree(mc);
+	vfree(mc);
 
 	if (leftover) {
-		if (new_mc)
-			vfree(new_mc);
+		vfree(new_mc);
 		state = UCODE_ERROR;
 		goto out;
 	}
@@ -405,8 +400,7 @@
 		goto out;
 	}
 
-	if (uci->mc)
-		vfree(uci->mc);
+	vfree(uci->mc);
 	uci->mc = (struct microcode_intel *)new_mc;
 
 	pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/mmconf-fam10h_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/mmconf-fam10h_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/mmconf-fam10h_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/mmconf-fam10h_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,6 @@
 };
 
 static u64 __cpuinitdata fam10h_pci_mmconf_base;
-static int __cpuinitdata fam10h_pci_mmconf_base_status;
 
 static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = {
 	{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
@@ -44,10 +43,12 @@
 	return start1 - start2;
 }
 
-/*[47:0] */
-/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
+#define MMCONF_UNIT (1ULL << FAM10H_MMIO_CONF_BASE_SHIFT)
+#define MMCONF_MASK (~(MMCONF_UNIT - 1))
+#define MMCONF_SIZE (MMCONF_UNIT << 8)
+/* need to avoid (0xfd<<32), (0xfe<<32), and (0xff<<32), ht used space */
 #define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
-#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
+#define BASE_VALID(b) ((b) + MMCONF_SIZE <= (0xfdULL<<32) || (b) >= (1ULL<<40))
 static void __cpuinit get_fam10h_pci_mmconf_base(void)
 {
 	int i;
@@ -64,12 +65,11 @@
 	struct range range[8];
 
 	/* only try to get setting from BSP */
-	/* -1 or 1 */
-	if (fam10h_pci_mmconf_base_status)
+	if (fam10h_pci_mmconf_base)
 		return;
 
 	if (!early_pci_allowed())
-		goto fail;
+		return;
 
 	found = 0;
 	for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
@@ -91,7 +91,7 @@
 	}
 
 	if (!found)
-		goto fail;
+		return;
 
 	/* SYS_CFG */
 	address = MSR_K8_SYSCFG;
@@ -99,16 +99,16 @@
 
 	/* TOP_MEM2 is not enabled? */
 	if (!(val & (1<<21))) {
-		tom2 = 0;
+		tom2 = 1ULL << 32;
 	} else {
 		/* TOP_MEM2 */
 		address = MSR_K8_TOP_MEM2;
 		rdmsrl(address, val);
-		tom2 = val & (0xffffULL<<32);
+		tom2 = max(val & 0xffffff800000ULL, 1ULL << 32);
 	}
 
 	if (base <= tom2)
-		base = tom2 + (1ULL<<32);
+		base = (tom2 + 2 * MMCONF_UNIT - 1) & MMCONF_MASK;
 
 	/*
 	 * need to check if the range is in the high mmio range that is
@@ -123,11 +123,11 @@
 		if (!(reg & 3))
 			continue;
 
-		start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+		start = (u64)(reg & 0xffffff00) << 8; /* 39:16 on 31:8*/
 		reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
-		end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+		end = ((u64)(reg & 0xffffff00) << 8) | 0xffff; /* 39:16 on 31:8*/
 
-		if (!end)
+		if (end < tom2)
 			continue;
 
 		range[hi_mmio_num].start = start;
@@ -143,32 +143,27 @@
 
 	if (range[hi_mmio_num - 1].end < base)
 		goto out;
-	if (range[0].start > base)
+	if (range[0].start > base + MMCONF_SIZE)
 		goto out;
 
 	/* need to find one window */
-	base = range[0].start - (1ULL << 32);
+	base = (range[0].start & MMCONF_MASK) - MMCONF_UNIT;
 	if ((base > tom2) && BASE_VALID(base))
 		goto out;
-	base = range[hi_mmio_num - 1].end + (1ULL << 32);
-	if ((base > tom2) && BASE_VALID(base))
+	base = (range[hi_mmio_num - 1].end + MMCONF_UNIT) & MMCONF_MASK;
+	if (BASE_VALID(base))
 		goto out;
 	/* need to find window between ranges */
-	if (hi_mmio_num > 1)
-	for (i = 0; i < hi_mmio_num - 1; i++) {
-		if (range[i + 1].start > (range[i].end + (1ULL << 32))) {
-			base = range[i].end + (1ULL << 32);
-			if ((base > tom2) && BASE_VALID(base))
-				goto out;
-		}
+	for (i = 1; i < hi_mmio_num; i++) {
+		base = (range[i - 1].end + MMCONF_UNIT) & MMCONF_MASK;
+		val = range[i].start & MMCONF_MASK;
+		if (val >= base + MMCONF_SIZE && BASE_VALID(base))
+			goto out;
 	}
-
-fail:
-	fam10h_pci_mmconf_base_status = -1;
 	return;
+
 out:
 	fam10h_pci_mmconf_base = base;
-	fam10h_pci_mmconf_base_status = 1;
 }
 
 void __cpuinit fam10h_check_enable_mmcfg(void)
@@ -190,11 +185,10 @@
 
 		/* only trust the one handle 256 buses, if acpi=off */
 		if (!acpi_pci_disabled || busnbits >= 8) {
-			u64 base;
-			base = val & (0xffffULL << 32);
-			if (fam10h_pci_mmconf_base_status <= 0) {
+			u64 base = val & MMCONF_MASK;
+
+			if (!fam10h_pci_mmconf_base) {
 				fam10h_pci_mmconf_base = base;
-				fam10h_pci_mmconf_base_status = 1;
 				return;
 			} else if (fam10h_pci_mmconf_base ==  base)
 				return;
@@ -206,8 +200,10 @@
 	 * with 256 buses
 	 */
 	get_fam10h_pci_mmconf_base();
-	if (fam10h_pci_mmconf_base_status <= 0)
+	if (!fam10h_pci_mmconf_base) {
+		pci_probe &= ~PCI_CHECK_ENABLE_AMD_MMCONF;
 		return;
+	}
 
 	printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
 	val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
@@ -217,13 +213,13 @@
 	wrmsrl(address, val);
 }
 
-static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d)
+static int __init set_check_enable_amd_mmconf(const struct dmi_system_id *d)
 {
         pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
         return 0;
 }
 
-static const struct dmi_system_id __cpuinitconst mmconf_dmi_table[] = {
+static const struct dmi_system_id __initconst mmconf_dmi_table[] = {
         {
                 .callback = set_check_enable_amd_mmconf,
                 .ident = "Sun Microsystems Machine",
@@ -234,7 +230,8 @@
 	{}
 };
 
-void __cpuinit check_enable_amd_mmconf_dmi(void)
+/* Called from a __cpuinit function, but only on the BSP. */
+void __ref check_enable_amd_mmconf_dmi(void)
 {
 	dmi_check_system(mmconf_dmi_table);
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/module.c linux-libre-2.6.37-gnu/arch/x86/kernel/module.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/module.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/module.c	2011-01-04 19:50:19.000000000 -0500
@@ -239,6 +239,9 @@
 		apply_paravirt(pseg, pseg + para->sh_size);
 	}
 
+	/* make jump label nops */
+	jump_label_apply_nops(me);
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/mpparse.c linux-libre-2.6.37-gnu/arch/x86/kernel/mpparse.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/mpparse.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/mpparse.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/bitops.h>
@@ -657,7 +658,7 @@
 {
 	unsigned long size = get_mpc_size(mpf->physptr);
 
-	reserve_early_overlap_ok(mpf->physptr, mpf->physptr+size, "MP-table mpc");
+	memblock_x86_reserve_range(mpf->physptr, mpf->physptr+size, "* MP-table mpc");
 }
 
 static int __init smp_scan_config(unsigned long base, unsigned long length)
@@ -686,7 +687,7 @@
 			       mpf, (u64)virt_to_phys(mpf));
 
 			mem = virt_to_phys(mpf);
-			reserve_early_overlap_ok(mem, mem + sizeof(*mpf), "MP-table mpf");
+			memblock_x86_reserve_range(mem, mem + sizeof(*mpf), "* MP-table mpf");
 			if (mpf->physptr)
 				smp_reserve_memory(mpf);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/mrst.c linux-libre-2.6.37-gnu/arch/x86/kernel/mrst.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/mrst.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/mrst.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,311 +0,0 @@
-/*
- * mrst.c: Intel Moorestown platform specific setup code
- *
- * (C) Copyright 2008 Intel Corporation
- * Author: Jacob Pan (jacob.jun.pan@intel.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sfi.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-
-#include <asm/setup.h>
-#include <asm/mpspec_def.h>
-#include <asm/hw_irq.h>
-#include <asm/apic.h>
-#include <asm/io_apic.h>
-#include <asm/mrst.h>
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include <asm/apb_timer.h>
-
-/*
- * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
- * cmdline option x86_mrst_timer can be used to override the configuration
- * to prefer one or the other.
- * at runtime, there are basically three timer configurations:
- * 1. per cpu apbt clock only
- * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
- * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
- *
- * by default (without cmdline option), platform code first detects cpu type
- * to see if we are on lincroft or penwell, then set up both lapic or apbt
- * clocks accordingly.
- * i.e. by default, medfield uses configuration #2, moorestown uses #1.
- * config #3 is supported but not recommended on medfield.
- *
- * rating and feature summary:
- * lapic (with C3STOP) --------- 100
- * apbt (always-on) ------------ 110
- * lapic (always-on,ARAT) ------ 150
- */
-
-__cpuinitdata enum mrst_timer_options mrst_timer_options;
-
-static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
-static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
-enum mrst_cpu_type __mrst_cpu_chip;
-EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
-
-int sfi_mtimer_num;
-
-struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
-EXPORT_SYMBOL_GPL(sfi_mrtc_array);
-int sfi_mrtc_num;
-
-static inline void assign_to_mp_irq(struct mpc_intsrc *m,
-				    struct mpc_intsrc *mp_irq)
-{
-	memcpy(mp_irq, m, sizeof(struct mpc_intsrc));
-}
-
-static inline int mp_irq_cmp(struct mpc_intsrc *mp_irq,
-				struct mpc_intsrc *m)
-{
-	return memcmp(mp_irq, m, sizeof(struct mpc_intsrc));
-}
-
-static void save_mp_irq(struct mpc_intsrc *m)
-{
-	int i;
-
-	for (i = 0; i < mp_irq_entries; i++) {
-		if (!mp_irq_cmp(&mp_irqs[i], m))
-			return;
-	}
-
-	assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
-		panic("Max # of irq sources exceeded!!\n");
-}
-
-/* parse all the mtimer info to a static mtimer array */
-static int __init sfi_parse_mtmr(struct sfi_table_header *table)
-{
-	struct sfi_table_simple *sb;
-	struct sfi_timer_table_entry *pentry;
-	struct mpc_intsrc mp_irq;
-	int totallen;
-
-	sb = (struct sfi_table_simple *)table;
-	if (!sfi_mtimer_num) {
-		sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb,
-					struct sfi_timer_table_entry);
-		pentry = (struct sfi_timer_table_entry *) sb->pentry;
-		totallen = sfi_mtimer_num * sizeof(*pentry);
-		memcpy(sfi_mtimer_array, pentry, totallen);
-	}
-
-	printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num);
-	pentry = sfi_mtimer_array;
-	for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) {
-		printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz,"
-			" irq = %d\n", totallen, (u32)pentry->phys_addr,
-			pentry->freq_hz, pentry->irq);
-			if (!pentry->irq)
-				continue;
-			mp_irq.type = MP_IOAPIC;
-			mp_irq.irqtype = mp_INT;
-/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
-			mp_irq.irqflag = 5;
-			mp_irq.srcbus = 0;
-			mp_irq.srcbusirq = pentry->irq;	/* IRQ */
-			mp_irq.dstapic = MP_APIC_ALL;
-			mp_irq.dstirq = pentry->irq;
-			save_mp_irq(&mp_irq);
-	}
-
-	return 0;
-}
-
-struct sfi_timer_table_entry *sfi_get_mtmr(int hint)
-{
-	int i;
-	if (hint < sfi_mtimer_num) {
-		if (!sfi_mtimer_usage[hint]) {
-			pr_debug("hint taken for timer %d irq %d\n",\
-				hint, sfi_mtimer_array[hint].irq);
-			sfi_mtimer_usage[hint] = 1;
-			return &sfi_mtimer_array[hint];
-		}
-	}
-	/* take the first timer available */
-	for (i = 0; i < sfi_mtimer_num;) {
-		if (!sfi_mtimer_usage[i]) {
-			sfi_mtimer_usage[i] = 1;
-			return &sfi_mtimer_array[i];
-		}
-		i++;
-	}
-	return NULL;
-}
-
-void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr)
-{
-	int i;
-	for (i = 0; i < sfi_mtimer_num;) {
-		if (mtmr->irq == sfi_mtimer_array[i].irq) {
-			sfi_mtimer_usage[i] = 0;
-			return;
-		}
-		i++;
-	}
-}
-
-/* parse all the mrtc info to a global mrtc array */
-int __init sfi_parse_mrtc(struct sfi_table_header *table)
-{
-	struct sfi_table_simple *sb;
-	struct sfi_rtc_table_entry *pentry;
-	struct mpc_intsrc mp_irq;
-
-	int totallen;
-
-	sb = (struct sfi_table_simple *)table;
-	if (!sfi_mrtc_num) {
-		sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb,
-						struct sfi_rtc_table_entry);
-		pentry = (struct sfi_rtc_table_entry *)sb->pentry;
-		totallen = sfi_mrtc_num * sizeof(*pentry);
-		memcpy(sfi_mrtc_array, pentry, totallen);
-	}
-
-	printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num);
-	pentry = sfi_mrtc_array;
-	for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
-		printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n",
-			totallen, (u32)pentry->phys_addr, pentry->irq);
-		mp_irq.type = MP_IOAPIC;
-		mp_irq.irqtype = mp_INT;
-		mp_irq.irqflag = 0;
-		mp_irq.srcbus = 0;
-		mp_irq.srcbusirq = pentry->irq;	/* IRQ */
-		mp_irq.dstapic = MP_APIC_ALL;
-		mp_irq.dstirq = pentry->irq;
-		save_mp_irq(&mp_irq);
-	}
-	return 0;
-}
-
-static unsigned long __init mrst_calibrate_tsc(void)
-{
-	unsigned long flags, fast_calibrate;
-
-	local_irq_save(flags);
-	fast_calibrate = apbt_quick_calibrate();
-	local_irq_restore(flags);
-
-	if (fast_calibrate)
-		return fast_calibrate;
-
-	return 0;
-}
-
-void __init mrst_time_init(void)
-{
-	switch (mrst_timer_options) {
-	case MRST_TIMER_APBT_ONLY:
-		break;
-	case MRST_TIMER_LAPIC_APBT:
-		x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
-		x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
-		break;
-	default:
-		if (!boot_cpu_has(X86_FEATURE_ARAT))
-			break;
-		x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
-		x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
-		return;
-	}
-	/* we need at least one APB timer */
-	sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
-	pre_init_apic_IRQ0();
-	apbt_time_init();
-}
-
-void __init mrst_rtc_init(void)
-{
-	sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
-}
-
-void __cpuinit mrst_arch_setup(void)
-{
-	if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
-		__mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
-	else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
-		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
-	else {
-		pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
-			boot_cpu_data.x86, boot_cpu_data.x86_model);
-		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
-	}
-	pr_debug("Moorestown CPU %s identified\n",
-		(__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
-		"Lincroft" : "Penwell");
-}
-
-/* MID systems don't have i8042 controller */
-static int mrst_i8042_detect(void)
-{
-	return 0;
-}
-
-/*
- * Moorestown specific x86_init function overrides and early setup
- * calls.
- */
-void __init x86_mrst_early_setup(void)
-{
-	x86_init.resources.probe_roms = x86_init_noop;
-	x86_init.resources.reserve_resources = x86_init_noop;
-
-	x86_init.timers.timer_init = mrst_time_init;
-	x86_init.timers.setup_percpu_clockev = x86_init_noop;
-
-	x86_init.irqs.pre_vector_init = x86_init_noop;
-
-	x86_init.oem.arch_setup = mrst_arch_setup;
-
-	x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
-
-	x86_platform.calibrate_tsc = mrst_calibrate_tsc;
-	x86_platform.i8042_detect = mrst_i8042_detect;
-	x86_init.pci.init = pci_mrst_init;
-	x86_init.pci.fixup_irqs = x86_init_noop;
-
-	legacy_pic = &null_legacy_pic;
-
-	/* Avoid searching for BIOS MP tables */
-	x86_init.mpparse.find_smp_config = x86_init_noop;
-	x86_init.mpparse.get_smp_config = x86_init_uint_noop;
-
-}
-
-/*
- * if user does not want to use per CPU apb timer, just give it a lower rating
- * than local apic timer and skip the late per cpu timer init.
- */
-static inline int __init setup_x86_mrst_timer(char *arg)
-{
-	if (!arg)
-		return -EINVAL;
-
-	if (strcmp("apbt_only", arg) == 0)
-		mrst_timer_options = MRST_TIMER_APBT_ONLY;
-	else if (strcmp("lapic_and_apbt", arg) == 0)
-		mrst_timer_options = MRST_TIMER_LAPIC_APBT;
-	else {
-		pr_warning("X86 MRST timer option %s not recognised"
-			   " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
-			   arg);
-		return -EINVAL;
-	}
-	return 0;
-}
-__setup("x86_mrst_timer=", setup_x86_mrst_timer);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/msr.c linux-libre-2.6.37-gnu/arch/x86/kernel/msr.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/msr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/msr.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,6 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/device.h>
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/olpc.c linux-libre-2.6.37-gnu/arch/x86/kernel/olpc.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/olpc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/olpc.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,260 +0,0 @@
-/*
- * Support for the OLPC DCON and OLPC EC access
- *
- * Copyright Â© 2006  Advanced Micro Devices, Inc.
- * Copyright Â© 2007-2008  Andres Salomon <dilinger@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/string.h>
-
-#include <asm/geode.h>
-#include <asm/setup.h>
-#include <asm/olpc.h>
-#include <asm/olpc_ofw.h>
-
-struct olpc_platform_t olpc_platform_info;
-EXPORT_SYMBOL_GPL(olpc_platform_info);
-
-static DEFINE_SPINLOCK(ec_lock);
-
-/* what the timeout *should* be (in ms) */
-#define EC_BASE_TIMEOUT 20
-
-/* the timeout that bugs in the EC might force us to actually use */
-static int ec_timeout = EC_BASE_TIMEOUT;
-
-static int __init olpc_ec_timeout_set(char *str)
-{
-	if (get_option(&str, &ec_timeout) != 1) {
-		ec_timeout = EC_BASE_TIMEOUT;
-		printk(KERN_ERR "olpc-ec:  invalid argument to "
-				"'olpc_ec_timeout=', ignoring!\n");
-	}
-	printk(KERN_DEBUG "olpc-ec:  using %d ms delay for EC commands.\n",
-			ec_timeout);
-	return 1;
-}
-__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
-
-/*
- * These {i,o}bf_status functions return whether the buffers are full or not.
- */
-
-static inline unsigned int ibf_status(unsigned int port)
-{
-	return !!(inb(port) & 0x02);
-}
-
-static inline unsigned int obf_status(unsigned int port)
-{
-	return inb(port) & 0x01;
-}
-
-#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
-static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
-{
-	unsigned int timeo;
-	int state = ibf_status(port);
-
-	for (timeo = ec_timeout; state != desired && timeo; timeo--) {
-		mdelay(1);
-		state = ibf_status(port);
-	}
-
-	if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
-			timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
-		printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for IBF!\n",
-				line, ec_timeout - timeo);
-	}
-
-	return !(state == desired);
-}
-
-#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
-static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
-{
-	unsigned int timeo;
-	int state = obf_status(port);
-
-	for (timeo = ec_timeout; state != desired && timeo; timeo--) {
-		mdelay(1);
-		state = obf_status(port);
-	}
-
-	if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
-			timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
-		printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for OBF!\n",
-				line, ec_timeout - timeo);
-	}
-
-	return !(state == desired);
-}
-
-/*
- * This allows the kernel to run Embedded Controller commands.  The EC is
- * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
- * available EC commands are here:
- * <http://wiki.laptop.org/go/Ec_specification>.  Unfortunately, while
- * OpenFirmware's source is available, the EC's is not.
- */
-int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
-		unsigned char *outbuf,  size_t outlen)
-{
-	unsigned long flags;
-	int ret = -EIO;
-	int i;
-
-	spin_lock_irqsave(&ec_lock, flags);
-
-	/* Clear OBF */
-	for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
-		inb(0x68);
-	if (i == 10) {
-		printk(KERN_ERR "olpc-ec:  timeout while attempting to "
-				"clear OBF flag!\n");
-		goto err;
-	}
-
-	if (wait_on_ibf(0x6c, 0)) {
-		printk(KERN_ERR "olpc-ec:  timeout waiting for EC to "
-				"quiesce!\n");
-		goto err;
-	}
-
-restart:
-	/*
-	 * Note that if we time out during any IBF checks, that's a failure;
-	 * we have to return.  There's no way for the kernel to clear that.
-	 *
-	 * If we time out during an OBF check, we can restart the command;
-	 * reissuing it will clear the OBF flag, and we should be alright.
-	 * The OBF flag will sometimes misbehave due to what we believe
-	 * is a hardware quirk..
-	 */
-	pr_devel("olpc-ec:  running cmd 0x%x\n", cmd);
-	outb(cmd, 0x6c);
-
-	if (wait_on_ibf(0x6c, 0)) {
-		printk(KERN_ERR "olpc-ec:  timeout waiting for EC to read "
-				"command!\n");
-		goto err;
-	}
-
-	if (inbuf && inlen) {
-		/* write data to EC */
-		for (i = 0; i < inlen; i++) {
-			if (wait_on_ibf(0x6c, 0)) {
-				printk(KERN_ERR "olpc-ec:  timeout waiting for"
-						" EC accept data!\n");
-				goto err;
-			}
-			pr_devel("olpc-ec:  sending cmd arg 0x%x\n", inbuf[i]);
-			outb(inbuf[i], 0x68);
-		}
-	}
-	if (outbuf && outlen) {
-		/* read data from EC */
-		for (i = 0; i < outlen; i++) {
-			if (wait_on_obf(0x6c, 1)) {
-				printk(KERN_ERR "olpc-ec:  timeout waiting for"
-						" EC to provide data!\n");
-				goto restart;
-			}
-			outbuf[i] = inb(0x68);
-			pr_devel("olpc-ec:  received 0x%x\n", outbuf[i]);
-		}
-	}
-
-	ret = 0;
-err:
-	spin_unlock_irqrestore(&ec_lock, flags);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(olpc_ec_cmd);
-
-#ifdef CONFIG_OLPC_OPENFIRMWARE
-static void __init platform_detect(void)
-{
-	size_t propsize;
-	__be32 rev;
-	const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 };
-	void *res[] = { &propsize };
-
-	if (olpc_ofw("getprop", args, res) || propsize != 4) {
-		printk(KERN_ERR "ofw: getprop call failed!\n");
-		rev = cpu_to_be32(0);
-	}
-	olpc_platform_info.boardrev = be32_to_cpu(rev);
-}
-#else
-static void __init platform_detect(void)
-{
-	/* stopgap until OFW support is added to the kernel */
-	olpc_platform_info.boardrev = olpc_board(0xc2);
-}
-#endif
-
-static int __init olpc_init(void)
-{
-	unsigned char *romsig;
-
-	/* The ioremap check is dangerous; limit what we run it on */
-	if (!is_geode() || cs5535_has_vsa2())
-		return 0;
-
-	spin_lock_init(&ec_lock);
-
-	romsig = ioremap(0xffffffc0, 16);
-	if (!romsig)
-		return 0;
-
-	if (strncmp(romsig, "CL1   Q", 7))
-		goto unmap;
-	if (strncmp(romsig+6, romsig+13, 3)) {
-		printk(KERN_INFO "OLPC BIOS signature looks invalid.  "
-				"Assuming not OLPC\n");
-		goto unmap;
-	}
-
-	printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig);
-	olpc_platform_info.flags |= OLPC_F_PRESENT;
-
-	/* get the platform revision */
-	platform_detect();
-
-	/* assume B1 and above models always have a DCON */
-	if (olpc_board_at_least(olpc_board(0xb1)))
-		olpc_platform_info.flags |= OLPC_F_DCON;
-
-	/* get the EC revision */
-	olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
-			(unsigned char *) &olpc_platform_info.ecver, 1);
-
-#ifdef CONFIG_PCI_OLPC
-	/* If the VSA exists let it emulate PCI, if not emulate in kernel */
-	if (!cs5535_has_vsa2())
-		x86_init.pci.arch_init = pci_olpc_init;
-#endif
-
-	printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
-			((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
-			olpc_platform_info.boardrev >> 4,
-			olpc_platform_info.ecver);
-
-unmap:
-	iounmap(romsig);
-	return 0;
-}
-
-postcore_initcall(olpc_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/olpc_ofw.c linux-libre-2.6.37-gnu/arch/x86/kernel/olpc_ofw.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/olpc_ofw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/olpc_ofw.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,106 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/olpc_ofw.h>
-
-/* address of OFW callback interface; will be NULL if OFW isn't found */
-static int (*olpc_ofw_cif)(int *);
-
-/* page dir entry containing OFW's pgdir table; filled in by head_32.S */
-u32 olpc_ofw_pgd __initdata;
-
-static DEFINE_SPINLOCK(ofw_lock);
-
-#define MAXARGS 10
-
-void __init setup_olpc_ofw_pgd(void)
-{
-	pgd_t *base, *ofw_pde;
-
-	if (!olpc_ofw_cif)
-		return;
-
-	/* fetch OFW's PDE */
-	base = early_ioremap(olpc_ofw_pgd, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
-	if (!base) {
-		printk(KERN_ERR "failed to remap OFW's pgd - disabling OFW!\n");
-		olpc_ofw_cif = NULL;
-		return;
-	}
-	ofw_pde = &base[OLPC_OFW_PDE_NR];
-
-	/* install OFW's PDE permanently into the kernel's pgtable */
-	set_pgd(&swapper_pg_dir[OLPC_OFW_PDE_NR], *ofw_pde);
-	/* implicit optimization barrier here due to uninline function return */
-
-	early_iounmap(base, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
-}
-
-int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
-		void **res)
-{
-	int ofw_args[MAXARGS + 3];
-	unsigned long flags;
-	int ret, i, *p;
-
-	BUG_ON(nr_args + nr_res > MAXARGS);
-
-	if (!olpc_ofw_cif)
-		return -EIO;
-
-	ofw_args[0] = (int)name;
-	ofw_args[1] = nr_args;
-	ofw_args[2] = nr_res;
-
-	p = &ofw_args[3];
-	for (i = 0; i < nr_args; i++, p++)
-		*p = (int)args[i];
-
-	/* call into ofw */
-	spin_lock_irqsave(&ofw_lock, flags);
-	ret = olpc_ofw_cif(ofw_args);
-	spin_unlock_irqrestore(&ofw_lock, flags);
-
-	if (!ret) {
-		for (i = 0; i < nr_res; i++, p++)
-			*((int *)res[i]) = *p;
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(__olpc_ofw);
-
-/* OFW cif _should_ be above this address */
-#define OFW_MIN 0xff000000
-
-/* OFW starts on a 1MB boundary */
-#define OFW_BOUND (1<<20)
-
-void __init olpc_ofw_detect(void)
-{
-	struct olpc_ofw_header *hdr = &boot_params.olpc_ofw_header;
-	unsigned long start;
-
-	/* ensure OFW booted us by checking for "OFW " string */
-	if (hdr->ofw_magic != OLPC_OFW_SIG)
-		return;
-
-	olpc_ofw_cif = (int (*)(int *))hdr->cif_handler;
-
-	if ((unsigned long)olpc_ofw_cif < OFW_MIN) {
-		printk(KERN_ERR "OFW detected, but cif has invalid address 0x%lx - disabling.\n",
-				(unsigned long)olpc_ofw_cif);
-		olpc_ofw_cif = NULL;
-		return;
-	}
-
-	/* determine where OFW starts in memory */
-	start = round_down((unsigned long)olpc_ofw_cif, OFW_BOUND);
-	printk(KERN_INFO "OFW detected in memory, cif @ 0x%lx (reserving top %ldMB)\n",
-			(unsigned long)olpc_ofw_cif, (-start) >> 20);
-	reserve_top_address(-start);
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/paravirt.c linux-libre-2.6.37-gnu/arch/x86/kernel/paravirt.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/paravirt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/paravirt.c	2011-01-04 19:50:19.000000000 -0500
@@ -413,7 +413,6 @@
 
 	.alloc_pte = paravirt_nop,
 	.alloc_pmd = paravirt_nop,
-	.alloc_pmd_clone = paravirt_nop,
 	.alloc_pud = paravirt_nop,
 	.release_pte = paravirt_nop,
 	.release_pmd = paravirt_nop,
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pci-calgary_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/pci-calgary_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pci-calgary_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pci-calgary_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 #include <asm/rio.h>
 #include <asm/bios_ebda.h>
 #include <asm/x86_init.h>
+#include <asm/iommu_table.h>
 
 #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT
 int use_calgary __read_mostly = 1;
@@ -1364,7 +1365,7 @@
 	return 0;
 }
 
-void __init detect_calgary(void)
+int __init detect_calgary(void)
 {
 	int bus;
 	void *tbl;
@@ -1378,13 +1379,13 @@
 	 * another HW IOMMU already, bail out.
 	 */
 	if (no_iommu || iommu_detected)
-		return;
+		return -ENODEV;
 
 	if (!use_calgary)
-		return;
+		return -ENODEV;
 
 	if (!early_pci_allowed())
-		return;
+		return -ENODEV;
 
 	printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n");
 
@@ -1410,13 +1411,13 @@
 	if (!rio_table_hdr) {
 		printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table "
 		       "in EBDA - bailing!\n");
-		return;
+		return -ENODEV;
 	}
 
 	ret = build_detail_arrays();
 	if (ret) {
 		printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret);
-		return;
+		return -ENOMEM;
 	}
 
 	specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
@@ -1464,7 +1465,7 @@
 
 		x86_init.iommu.iommu_init = calgary_iommu_init;
 	}
-	return;
+	return calgary_found;
 
 cleanup:
 	for (--bus; bus >= 0; --bus) {
@@ -1473,6 +1474,7 @@
 		if (info->tce_space)
 			free_tce_table(info->tce_space);
 	}
+	return -ENOMEM;
 }
 
 static int __init calgary_parse_options(char *p)
@@ -1594,3 +1596,5 @@
  * and before device_initcall.
  */
 rootfs_initcall(calgary_fixup_tce_spaces);
+
+IOMMU_INIT_POST(detect_calgary);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pci-dma.c linux-libre-2.6.37-gnu/arch/x86/kernel/pci-dma.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pci-dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pci-dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,9 +11,8 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/calgary.h>
-#include <asm/amd_iommu.h>
 #include <asm/x86_init.h>
-#include <asm/xen/swiotlb-xen.h>
+#include <asm/iommu_table.h>
 
 static int forbid_dac __read_mostly;
 
@@ -45,6 +44,8 @@
  */
 int iommu_pass_through __read_mostly;
 
+extern struct iommu_table_entry __iommu_table[], __iommu_table_end[];
+
 /* Dummy device used for NULL arguments (normally ISA). */
 struct device x86_dma_fallback_dev = {
 	.init_name = "fallback device",
@@ -130,26 +131,24 @@
 
 void __init pci_iommu_alloc(void)
 {
+	struct iommu_table_entry *p;
+
 	/* free the range so iommu could get some range less than 4G */
 	dma32_free_bootmem();
 
-	if (pci_xen_swiotlb_detect() || pci_swiotlb_detect())
-		goto out;
-
-	gart_iommu_hole_init();
-
-	detect_calgary();
-
-	detect_intel_iommu();
-
-	/* needs to be called after gart_iommu_hole_init */
-	amd_iommu_detect();
-out:
-	pci_xen_swiotlb_init();
+	sort_iommu_table(__iommu_table, __iommu_table_end);
+	check_iommu_entries(__iommu_table, __iommu_table_end);
 
-	pci_swiotlb_init();
+	for (p = __iommu_table; p < __iommu_table_end; p++) {
+		if (p && p->detect && p->detect() > 0) {
+			p->flags |= IOMMU_DETECTED;
+			if (p->early_init)
+				p->early_init();
+			if (p->flags & IOMMU_FINISH_IF_DETECTED)
+				break;
+		}
+	}
 }
-
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
 				 dma_addr_t *dma_addr, gfp_t flag)
 {
@@ -292,6 +291,7 @@
 
 static int __init pci_iommu_init(void)
 {
+	struct iommu_table_entry *p;
 	dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
 
 #ifdef CONFIG_PCI
@@ -299,12 +299,10 @@
 #endif
 	x86_init.iommu.iommu_init();
 
-	if (swiotlb || xen_swiotlb) {
-		printk(KERN_INFO "PCI-DMA: "
-		       "Using software bounce buffering for IO (SWIOTLB)\n");
-		swiotlb_print_info();
-	} else
-		swiotlb_free();
+	for (p = __iommu_table; p < __iommu_table_end; p++) {
+		if (p && (p->flags & IOMMU_DETECTED) && p->late_init)
+			p->late_init();
+	}
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pci-gart_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/pci-gart_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pci-gart_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pci-gart_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,8 +39,9 @@
 #include <asm/cacheflush.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/x86_init.h>
+#include <asm/iommu_table.h>
 
 static unsigned long iommu_bus_base;	/* GART remapping area (physical) */
 static unsigned long iommu_size;	/* size of remapping area bytes */
@@ -560,8 +561,11 @@
 {
 	int i;
 
-	for (i = 0; i < num_k8_northbridges; i++) {
-		struct pci_dev *dev = k8_northbridges[i];
+	if (!k8_northbridges.gart_supported)
+		return;
+
+	for (i = 0; i < k8_northbridges.num; i++) {
+		struct pci_dev *dev = k8_northbridges.nb_misc[i];
 
 		enable_gart_translation(dev, __pa(agp_gatt_table));
 	}
@@ -592,16 +596,19 @@
 	if (!fix_up_north_bridges)
 		return;
 
+	if (!k8_northbridges.gart_supported)
+		return;
+
 	pr_info("PCI-DMA: Restoring GART aperture settings\n");
 
-	for (i = 0; i < num_k8_northbridges; i++) {
-		struct pci_dev *dev = k8_northbridges[i];
+	for (i = 0; i < k8_northbridges.num; i++) {
+		struct pci_dev *dev = k8_northbridges.nb_misc[i];
 
 		/*
 		 * Don't enable translations just yet.  That is the next
 		 * step.  Restore the pre-suspend aperture settings.
 		 */
-		pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, aperture_order << 1);
+		gart_set_size_and_enable(dev, aperture_order);
 		pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25);
 	}
 }
@@ -649,8 +656,8 @@
 
 	aper_size = aper_base = info->aper_size = 0;
 	dev = NULL;
-	for (i = 0; i < num_k8_northbridges; i++) {
-		dev = k8_northbridges[i];
+	for (i = 0; i < k8_northbridges.num; i++) {
+		dev = k8_northbridges.nb_misc[i];
 		new_aper_base = read_aperture(dev, &new_aper_size);
 		if (!new_aper_base)
 			goto nommu;
@@ -718,10 +725,13 @@
 	if (!no_agp)
 		return;
 
-	for (i = 0; i < num_k8_northbridges; i++) {
+	if (!k8_northbridges.gart_supported)
+		return;
+
+	for (i = 0; i < k8_northbridges.num; i++) {
 		u32 ctl;
 
-		dev = k8_northbridges[i];
+		dev = k8_northbridges.nb_misc[i];
 		pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
 
 		ctl &= ~GARTEN;
@@ -739,7 +749,7 @@
 	unsigned long scratch;
 	long i;
 
-	if (num_k8_northbridges == 0)
+	if (!k8_northbridges.gart_supported)
 		return 0;
 
 #ifndef CONFIG_AGP_AMD64
@@ -896,3 +906,4 @@
 		}
 	}
 }
+IOMMU_INIT_POST(gart_iommu_hole_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pci-iommu_table.c linux-libre-2.6.37-gnu/arch/x86/kernel/pci-iommu_table.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pci-iommu_table.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pci-iommu_table.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,89 @@
+#include <linux/dma-mapping.h>
+#include <asm/iommu_table.h>
+#include <linux/string.h>
+#include <linux/kallsyms.h>
+
+
+#define DEBUG 1
+
+static struct iommu_table_entry * __init
+find_dependents_of(struct iommu_table_entry *start,
+		   struct iommu_table_entry *finish,
+		   struct iommu_table_entry *q)
+{
+	struct iommu_table_entry *p;
+
+	if (!q)
+		return NULL;
+
+	for (p = start; p < finish; p++)
+		if (p->detect == q->depend)
+			return p;
+
+	return NULL;
+}
+
+
+void __init sort_iommu_table(struct iommu_table_entry *start,
+			     struct iommu_table_entry *finish) {
+
+	struct iommu_table_entry *p, *q, tmp;
+
+	for (p = start; p < finish; p++) {
+again:
+		q = find_dependents_of(start, finish, p);
+		/* We are bit sneaky here. We use the memory address to figure
+		 * out if the node we depend on is past our point, if so, swap.
+		 */
+		if (q > p) {
+			tmp = *p;
+			memmove(p, q, sizeof(*p));
+			*q = tmp;
+			goto again;
+		}
+	}
+
+}
+
+#ifdef DEBUG
+void __init check_iommu_entries(struct iommu_table_entry *start,
+				struct iommu_table_entry *finish)
+{
+	struct iommu_table_entry *p, *q, *x;
+	char sym_p[KSYM_SYMBOL_LEN];
+	char sym_q[KSYM_SYMBOL_LEN];
+
+	/* Simple cyclic dependency checker. */
+	for (p = start; p < finish; p++) {
+		q = find_dependents_of(start, finish, p);
+		x = find_dependents_of(start, finish, q);
+		if (p == x) {
+			sprint_symbol(sym_p, (unsigned long)p->detect);
+			sprint_symbol(sym_q, (unsigned long)q->detect);
+
+			printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \
+					" on %s and vice-versa. BREAKING IT.\n",
+					sym_p, sym_q);
+			/* Heavy handed way..*/
+			x->depend = 0;
+		}
+	}
+
+	for (p = start; p < finish; p++) {
+		q = find_dependents_of(p, finish, p);
+		if (q && q > p) {
+			sprint_symbol(sym_p, (unsigned long)p->detect);
+			sprint_symbol(sym_q, (unsigned long)q->detect);
+
+			printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\
+					"should be called before %s!\n",
+					sym_p, sym_q);
+		}
+	}
+}
+#else
+inline void check_iommu_entries(struct iommu_table_entry *start,
+				       struct iommu_table_entry *finish)
+{
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pci-swiotlb.c linux-libre-2.6.37-gnu/arch/x86/kernel/pci-swiotlb.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pci-swiotlb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pci-swiotlb.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,8 @@
 #include <asm/iommu.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
-
+#include <asm/xen/swiotlb-xen.h>
+#include <asm/iommu_table.h>
 int swiotlb __read_mostly;
 
 static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -41,25 +42,42 @@
 };
 
 /*
- * pci_swiotlb_detect - set swiotlb to 1 if necessary
+ * pci_swiotlb_detect_override - set swiotlb to 1 if necessary
  *
  * This returns non-zero if we are forced to use swiotlb (by the boot
  * option).
  */
-int __init pci_swiotlb_detect(void)
+int __init pci_swiotlb_detect_override(void)
 {
 	int use_swiotlb = swiotlb | swiotlb_force;
 
+	if (swiotlb_force)
+		swiotlb = 1;
+
+	return use_swiotlb;
+}
+IOMMU_INIT_FINISH(pci_swiotlb_detect_override,
+		  pci_xen_swiotlb_detect,
+		  pci_swiotlb_init,
+		  pci_swiotlb_late_init);
+
+/*
+ * if 4GB or more detected (and iommu=off not set) return 1
+ * and set swiotlb to 1.
+ */
+int __init pci_swiotlb_detect_4gb(void)
+{
 	/* don't initialize swiotlb if iommu=off (no_iommu=1) */
 #ifdef CONFIG_X86_64
 	if (!no_iommu && max_pfn > MAX_DMA32_PFN)
 		swiotlb = 1;
 #endif
-	if (swiotlb_force)
-		swiotlb = 1;
-
-	return use_swiotlb;
+	return swiotlb;
 }
+IOMMU_INIT(pci_swiotlb_detect_4gb,
+	   pci_swiotlb_detect_override,
+	   pci_swiotlb_init,
+	   pci_swiotlb_late_init);
 
 void __init pci_swiotlb_init(void)
 {
@@ -68,3 +86,15 @@
 		dma_ops = &swiotlb_dma_ops;
 	}
 }
+
+void __init pci_swiotlb_late_init(void)
+{
+	/* An IOMMU turned us off. */
+	if (!swiotlb)
+		swiotlb_free();
+	else {
+		printk(KERN_INFO "PCI-DMA: "
+		       "Using software bounce buffering for IO (SWIOTLB)\n");
+		swiotlb_print_info();
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pmtimer_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/pmtimer_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pmtimer_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pmtimer_64.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,69 +0,0 @@
-/* Ported over from i386 by AK, original copyright was:
- *
- * (C) Dominik Brodowski <linux@brodo.de> 2003
- *
- * Driver to use the Power Management Timer (PMTMR) available in some
- * southbridges as primary timing source for the Linux kernel.
- *
- * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
- * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
- *
- * This file is licensed under the GPL v2.
- *
- * Dropped all the hardware bug workarounds for now. Hopefully they
- * are not needed on 64bit chipsets.
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/init.h>
-#include <linux/cpumask.h>
-#include <linux/acpi_pmtmr.h>
-
-#include <asm/io.h>
-#include <asm/proto.h>
-#include <asm/msr.h>
-#include <asm/vsyscall.h>
-
-static inline u32 cyc2us(u32 cycles)
-{
-	/* The Power Management Timer ticks at 3.579545 ticks per microsecond.
-	 * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
-	 *
-	 * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
-	 * easily be multiplied with 286 (=0x11E) without having to fear
-	 * u32 overflows.
-	 */
-	cycles *= 286;
-	return (cycles >> 10);
-}
-
-static unsigned pmtimer_wait_tick(void)
-{
-	u32 a, b;
-	for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK;
-	     a == b;
-	     b = inl(pmtmr_ioport) & ACPI_PM_MASK)
-		cpu_relax();
-	return b;
-}
-
-/* note: wait time is rounded up to one tick */
-void pmtimer_wait(unsigned us)
-{
-	u32 a, b;
-	a = pmtimer_wait_tick();
-	do {
-		b = inl(pmtmr_ioport);
-		cpu_relax();
-	} while (cyc2us(b - a) < us);
-}
-
-static int __init nopmtimer_setup(char *s)
-{
-	pmtmr_ioport = 0;
-	return 1;
-}
-
-__setup("nopmtimer", nopmtimer_setup);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/process_64.c linux-libre-2.6.37-gnu/arch/x86/kernel/process_64.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/process_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/process_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -424,7 +424,7 @@
 	load_TLS(next, cpu);
 
 	/* Must be after DS reload */
-	unlazy_fpu(prev_p);
+	__unlazy_fpu(prev_p);
 
 	/* Make sure cpu is ready for new context */
 	if (preload_fpu)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/x86/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -801,7 +801,8 @@
 static const struct user_regset_view user_x86_32_view; /* Initialized below. */
 #endif
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret;
 	unsigned long __user *datap = (unsigned long __user *)data;
@@ -812,8 +813,7 @@
 		unsigned long tmp;
 
 		ret = -EIO;
-		if ((addr & (sizeof(data) - 1)) || addr < 0 ||
-		    addr >= sizeof(struct user))
+		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
 			break;
 
 		tmp = 0;  /* Default return condition */
@@ -830,8 +830,7 @@
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 		ret = -EIO;
-		if ((addr & (sizeof(data) - 1)) || addr < 0 ||
-		    addr >= sizeof(struct user))
+		if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user))
 			break;
 
 		if (addr < sizeof(struct user_regs_struct))
@@ -888,17 +887,17 @@
 
 #if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
 	case PTRACE_GET_THREAD_AREA:
-		if (addr < 0)
+		if ((int) addr < 0)
 			return -EIO;
 		ret = do_get_thread_area(child, addr,
-					 (struct user_desc __user *) data);
+					(struct user_desc __user *)data);
 		break;
 
 	case PTRACE_SET_THREAD_AREA:
-		if (addr < 0)
+		if ((int) addr < 0)
 			return -EIO;
 		ret = do_set_thread_area(child, addr,
-					 (struct user_desc __user *) data, 0);
+					(struct user_desc __user *)data, 0);
 		break;
 #endif
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/pvclock.c linux-libre-2.6.37-gnu/arch/x86/kernel/pvclock.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/pvclock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/pvclock.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,48 +41,11 @@
 	valid_flags = flags;
 }
 
-/*
- * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
- * yielding a 64-bit result.
- */
-static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
-{
-	u64 product;
-#ifdef __i386__
-	u32 tmp1, tmp2;
-#endif
-
-	if (shift < 0)
-		delta >>= -shift;
-	else
-		delta <<= shift;
-
-#ifdef __i386__
-	__asm__ (
-		"mul  %5       ; "
-		"mov  %4,%%eax ; "
-		"mov  %%edx,%4 ; "
-		"mul  %5       ; "
-		"xor  %5,%5    ; "
-		"add  %4,%%eax ; "
-		"adc  %5,%%edx ; "
-		: "=A" (product), "=r" (tmp1), "=r" (tmp2)
-		: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
-#elif defined(__x86_64__)
-	__asm__ (
-		"mul %%rdx ; shrd $32,%%rdx,%%rax"
-		: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
-#else
-#error implement me!
-#endif
-
-	return product;
-}
-
 static u64 pvclock_get_nsec_offset(struct pvclock_shadow_time *shadow)
 {
 	u64 delta = native_read_tsc() - shadow->tsc_timestamp;
-	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+	return pvclock_scale_delta(delta, shadow->tsc_to_nsec_mul,
+				   shadow->tsc_shift);
 }
 
 /*
@@ -120,6 +83,11 @@
 
 static atomic64_t last_value = ATOMIC64_INIT(0);
 
+void pvclock_resume(void)
+{
+	atomic64_set(&last_value, 0);
+}
+
 cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
 {
 	struct pvclock_shadow_time shadow;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/quirks.c linux-libre-2.6.37-gnu/arch/x86/kernel/quirks.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/quirks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/quirks.c	2011-01-04 19:50:19.000000000 -0500
@@ -344,6 +344,8 @@
 			 vt8237_force_enable_hpet);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
 			 vt8237_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700,
+			 vt8237_force_enable_hpet);
 
 static void ati_force_hpet_resume(void)
 {
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/reboot.c linux-libre-2.6.37-gnu/arch/x86/kernel/reboot.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/reboot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/reboot.c	2011-01-04 19:50:19.000000000 -0500
@@ -84,7 +84,7 @@
 			}
 				/* we will leave sorting out the final value
 				   when we are ready to reboot, since we might not
-				   have set up boot_cpu_id or smp_num_cpu */
+				   have detected BSP APIC ID or smp_num_cpu */
 			break;
 #endif /* CONFIG_SMP */
 
@@ -371,16 +371,10 @@
 	CMOS_WRITE(0x00, 0x8f);
 	spin_unlock(&rtc_lock);
 
-	/* Remap the kernel at virtual address zero, as well as offset zero
-	   from the kernel segment.  This assumes the kernel segment starts at
-	   virtual address PAGE_OFFSET. */
-	memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY,
-		sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
-
 	/*
-	 * Use `swapper_pg_dir' as our page directory.
+	 * Switch back to the initial page table.
 	 */
-	load_cr3(swapper_pg_dir);
+	load_cr3(initial_page_table);
 
 	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
 	   this on booting to tell it to "Bypass memory test (also warm
@@ -641,7 +635,7 @@
 	/* O.K Now that I'm on the appropriate processor,
 	 * stop all of the others.
 	 */
-	smp_send_stop();
+	stop_other_cpus();
 #endif
 
 	lapic_shutdown();
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/resource.c linux-libre-2.6.37-gnu/arch/x86/kernel/resource.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/resource.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/resource.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+#include <linux/ioport.h>
+#include <asm/e820.h>
+
+static void resource_clip(struct resource *res, resource_size_t start,
+			  resource_size_t end)
+{
+	resource_size_t low = 0, high = 0;
+
+	if (res->end < start || res->start > end)
+		return;		/* no conflict */
+
+	if (res->start < start)
+		low = start - res->start;
+
+	if (res->end > end)
+		high = res->end - end;
+
+	/* Keep the area above or below the conflict, whichever is larger */
+	if (low > high)
+		res->end = start - 1;
+	else
+		res->start = end + 1;
+}
+
+static void remove_e820_regions(struct resource *avail)
+{
+	int i;
+	struct e820entry *entry;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		entry = &e820.map[i];
+
+		resource_clip(avail, entry->addr,
+			      entry->addr + entry->size - 1);
+	}
+}
+
+void arch_remove_reservations(struct resource *avail)
+{
+	/* Trim out BIOS areas (low 1MB and high 2MB) and E820 regions */
+	if (avail->flags & IORESOURCE_MEM) {
+		if (avail->start < BIOS_END)
+			avail->start = BIOS_END;
+		resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);
+
+		remove_e820_regions(avail);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/scx200_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/scx200_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/scx200_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/scx200_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,131 +0,0 @@
-/*
- *  Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
- *
- *  National Semiconductor SCx200 support.
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/pci.h>
-
-#include <linux/scx200.h>
-#include <linux/scx200_gpio.h>
-
-/* Verify that the configuration block really is there */
-#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
-
-#define NAME "scx200"
-
-MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 Driver");
-MODULE_LICENSE("GPL");
-
-unsigned scx200_gpio_base = 0;
-unsigned long scx200_gpio_shadow[2];
-
-unsigned scx200_cb_base = 0;
-
-static struct pci_device_id scx200_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS)   },
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS)   },
-	{ },
-};
-MODULE_DEVICE_TABLE(pci,scx200_tbl);
-
-static int __devinit scx200_probe(struct pci_dev *, const struct pci_device_id *);
-
-static struct pci_driver scx200_pci_driver = {
-	.name = "scx200",
-	.id_table = scx200_tbl,
-	.probe = scx200_probe,
-};
-
-static DEFINE_MUTEX(scx200_gpio_config_lock);
-
-static void __devinit scx200_init_shadow(void)
-{
-	int bank;
-
-	/* read the current values driven on the GPIO signals */
-	for (bank = 0; bank < 2; ++bank)
-		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
-}
-
-static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	unsigned base;
-
-	if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
-	    pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) {
-		base = pci_resource_start(pdev, 0);
-		printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
-
-		if (!request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) {
-			printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
-			return -EBUSY;
-		}
-
-		scx200_gpio_base = base;
-		scx200_init_shadow();
-
-	} else {
-		/* find the base of the Configuration Block */
-		if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) {
-			scx200_cb_base = SCx200_CB_BASE_FIXED;
-		} else {
-			pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base);
-			if (scx200_cb_probe(base)) {
-				scx200_cb_base = base;
-			} else {
-				printk(KERN_WARNING NAME ": Configuration Block not found\n");
-				return -ENODEV;
-			}
-		}
-		printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base);
-	}
-
-	return 0;
-}
-
-u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)
-{
-	u32 config, new_config;
-
-	mutex_lock(&scx200_gpio_config_lock);
-
-	outl(index, scx200_gpio_base + 0x20);
-	config = inl(scx200_gpio_base + 0x24);
-
-	new_config = (config & mask) | bits;
-	outl(new_config, scx200_gpio_base + 0x24);
-
-	mutex_unlock(&scx200_gpio_config_lock);
-
-	return config;
-}
-
-static int __init scx200_init(void)
-{
-	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
-
-	return pci_register_driver(&scx200_pci_driver);
-}
-
-static void __exit scx200_cleanup(void)
-{
-	pci_unregister_driver(&scx200_pci_driver);
-	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
-}
-
-module_init(scx200_init);
-module_exit(scx200_cleanup);
-
-EXPORT_SYMBOL(scx200_gpio_base);
-EXPORT_SYMBOL(scx200_gpio_shadow);
-EXPORT_SYMBOL(scx200_gpio_configure);
-EXPORT_SYMBOL(scx200_cb_base);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/setup.c linux-libre-2.6.37-gnu/arch/x86/kernel/setup.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 #include <linux/apm_bios.h>
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
 #include <linux/mca.h>
@@ -83,7 +84,6 @@
 #include <asm/dmi.h>
 #include <asm/io_apic.h>
 #include <asm/ist.h>
-#include <asm/vmi.h>
 #include <asm/setup_arch.h>
 #include <asm/bios_ebda.h>
 #include <asm/cacheflush.h>
@@ -107,11 +107,12 @@
 #include <asm/percpu.h>
 #include <asm/topology.h>
 #include <asm/apicdef.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #ifdef CONFIG_X86_64
 #include <asm/numa_64.h>
 #endif
 #include <asm/mce.h>
+#include <asm/alternative.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -125,7 +126,6 @@
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
 
-unsigned int boot_cpu_id __read_mostly;
 
 static __initdata unsigned long _brk_start = (unsigned long)__brk_base;
 unsigned long _brk_end = (unsigned long)__brk_base;
@@ -302,7 +302,7 @@
 static void __init reserve_brk(void)
 {
 	if (_brk_end > _brk_start)
-		reserve_early(__pa(_brk_start), __pa(_brk_end), "BRK");
+		memblock_x86_reserve_range(__pa(_brk_start), __pa(_brk_end), "BRK");
 
 	/* Mark brk area as locked down and no longer taking any
 	   new allocations */
@@ -324,17 +324,16 @@
 	char *p, *q;
 
 	/* We need to move the initrd down into lowmem */
-	ramdisk_here = find_e820_area(0, end_of_lowmem, area_size,
+	ramdisk_here = memblock_find_in_range(0, end_of_lowmem, area_size,
 					 PAGE_SIZE);
 
-	if (ramdisk_here == -1ULL)
+	if (ramdisk_here == MEMBLOCK_ERROR)
 		panic("Cannot find place for new RAMDISK of size %lld\n",
 			 ramdisk_size);
 
 	/* Note: this includes all the lowmem currently occupied by
 	   the initrd, we rely on that fact to keep the data intact. */
-	reserve_early(ramdisk_here, ramdisk_here + area_size,
-			 "NEW RAMDISK");
+	memblock_x86_reserve_range(ramdisk_here, ramdisk_here + area_size, "NEW RAMDISK");
 	initrd_start = ramdisk_here + PAGE_OFFSET;
 	initrd_end   = initrd_start + ramdisk_size;
 	printk(KERN_INFO "Allocated new RAMDISK: %08llx - %08llx\n",
@@ -390,7 +389,7 @@
 	initrd_start = 0;
 
 	if (ramdisk_size >= (end_of_lowmem>>1)) {
-		free_early(ramdisk_image, ramdisk_end);
+		memblock_x86_free_range(ramdisk_image, ramdisk_end);
 		printk(KERN_ERR "initrd too large to handle, "
 		       "disabling initrd\n");
 		return;
@@ -413,7 +412,7 @@
 
 	relocate_initrd();
 
-	free_early(ramdisk_image, ramdisk_end);
+	memblock_x86_free_range(ramdisk_image, ramdisk_end);
 }
 #else
 static void __init reserve_initrd(void)
@@ -469,7 +468,7 @@
 	e820_print_map("reserve setup_data");
 }
 
-static void __init reserve_early_setup_data(void)
+static void __init memblock_x86_reserve_range_setup_data(void)
 {
 	struct setup_data *data;
 	u64 pa_data;
@@ -481,7 +480,7 @@
 	while (pa_data) {
 		data = early_memremap(pa_data, sizeof(*data));
 		sprintf(buf, "setup data %x", data->type);
-		reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
+		memblock_x86_reserve_range(pa_data, pa_data+sizeof(*data)+data->len, buf);
 		pa_data = data->next;
 		early_iounmap(data, sizeof(*data));
 	}
@@ -502,6 +501,18 @@
 	return total << PAGE_SHIFT;
 }
 
+/*
+ * Keep the crash kernel below this limit.  On 32 bits earlier kernels
+ * would limit the kernel to the low 512 MiB due to mapping restrictions.
+ * On 64 bits, kexec-tools currently limits us to 896 MiB; increase this
+ * limit once kexec-tools are fixed.
+ */
+#ifdef CONFIG_X86_32
+# define CRASH_KERNEL_ADDR_MAX	(512 << 20)
+#else
+# define CRASH_KERNEL_ADDR_MAX	(896 << 20)
+#endif
+
 static void __init reserve_crashkernel(void)
 {
 	unsigned long long total_mem;
@@ -519,23 +530,27 @@
 	if (crash_base <= 0) {
 		const unsigned long long alignment = 16<<20;	/* 16M */
 
-		crash_base = find_e820_area(alignment, ULONG_MAX, crash_size,
-				 alignment);
-		if (crash_base == -1ULL) {
+		/*
+		 *  kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
+		 */
+		crash_base = memblock_find_in_range(alignment,
+			       CRASH_KERNEL_ADDR_MAX, crash_size, alignment);
+
+		if (crash_base == MEMBLOCK_ERROR) {
 			pr_info("crashkernel reservation failed - No suitable area found.\n");
 			return;
 		}
 	} else {
 		unsigned long long start;
 
-		start = find_e820_area(crash_base, ULONG_MAX, crash_size,
-				 1<<20);
+		start = memblock_find_in_range(crash_base,
+				 crash_base + crash_size, crash_size, 1<<20);
 		if (start != crash_base) {
 			pr_info("crashkernel reservation failed - memory is in use.\n");
 			return;
 		}
 	}
-	reserve_early(crash_base, crash_base + crash_size, "CRASH KERNEL");
+	memblock_x86_reserve_range(crash_base, crash_base + crash_size, "CRASH KERNEL");
 
 	printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
 			"for crashkernel (System RAM: %ldMB)\n",
@@ -615,82 +630,10 @@
 	addr = find_ibft_region(&size);
 
 	if (size)
-		reserve_early_overlap_ok(addr, addr + size, "ibft");
-}
-
-#ifdef CONFIG_X86_RESERVE_LOW_64K
-static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
-{
-	printk(KERN_NOTICE
-		"%s detected: BIOS may corrupt low RAM, working around it.\n",
-		d->ident);
-
-	e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
-	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-
-	return 0;
+		memblock_x86_reserve_range(addr, addr + size, "* ibft");
 }
-#endif
 
-/* List of systems that have known low memory corruption BIOS problems */
-static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
-#ifdef CONFIG_X86_RESERVE_LOW_64K
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "AMI BIOS",
-		.matches = {
-			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
-		},
-	},
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "Phoenix BIOS",
-		.matches = {
-			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
-		},
-	},
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "Phoenix/MSC BIOS",
-		.matches = {
-			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix/MSC"),
-		},
-	},
-	/*
-	 * AMI BIOS with low memory corruption was found on Intel DG45ID and
-	 * DG45FC boards.
-	 * It has a different DMI_BIOS_VENDOR = "Intel Corp.", for now we will
-	 * match only DMI_BOARD_NAME and see if there is more bad products
-	 * with this vendor.
-	 */
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "AMI BIOS",
-		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "DG45ID"),
-		},
-	},
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "AMI BIOS",
-		.matches = {
-			DMI_MATCH(DMI_BOARD_NAME, "DG45FC"),
-		},
-	},
-	/*
-	 * The Dell Inspiron Mini 1012 has DMI_BIOS_VENDOR = "Dell Inc.", so
-	 * match on the product name.
-	 */
-	{
-		.callback = dmi_low_memory_corruption,
-		.ident = "Phoenix BIOS",
-		.matches = {
-			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
-		},
-	},
-#endif
-	{}
-};
+static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
 
 static void __init trim_bios_range(void)
 {
@@ -698,8 +641,14 @@
 	 * A special case is the first 4Kb of memory;
 	 * This is a BIOS owned area, not kernel ram, but generally
 	 * not listed as such in the E820 table.
+	 *
+	 * This typically reserves additional memory (64KiB by default)
+	 * since some BIOSes are known to corrupt low memory.  See the
+	 * Kconfig help text for X86_RESERVE_LOW.
 	 */
-	e820_update_range(0, PAGE_SIZE, E820_RAM, E820_RESERVED);
+	e820_update_range(0, ALIGN(reserve_low, PAGE_SIZE),
+			  E820_RAM, E820_RESERVED);
+
 	/*
 	 * special case: Some BIOSen report the PC BIOS
 	 * area (640->1Mb) as ram even though it is not.
@@ -709,6 +658,37 @@
 	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
 
+static int __init parse_reservelow(char *p)
+{
+	unsigned long long size;
+
+	if (!p)
+		return -EINVAL;
+
+	size = memparse(p, &p);
+
+	if (size < 4096)
+		size = 4096;
+
+	if (size > 640*1024)
+		size = 640*1024;
+
+	reserve_low = size;
+
+	return 0;
+}
+
+early_param("reservelow", parse_reservelow);
+
+static u64 __init get_max_mapped(void)
+{
+	u64 end = max_pfn_mapped;
+
+	end <<= PAGE_SHIFT;
+
+	return end;
+}
+
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -726,18 +706,30 @@
 {
 	int acpi = 0;
 	int k8 = 0;
+	unsigned long flags;
 
 #ifdef CONFIG_X86_32
 	memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
 	visws_early_detect();
+
+	/*
+	 * copy kernel address range established so far and switch
+	 * to the proper swapper page table
+	 */
+	clone_pgd_range(swapper_pg_dir     + KERNEL_PGD_BOUNDARY,
+			initial_page_table + KERNEL_PGD_BOUNDARY,
+			KERNEL_PGD_PTRS);
+
+	load_cr3(swapper_pg_dir);
+	__flush_tlb_all();
 #else
 	printk(KERN_INFO "Command line: %s\n", boot_command_line);
 #endif
 
-	/* VMI may relocate the fixmap; do this before touching ioremap area */
-	vmi_init();
-
-	/* OFW also may relocate the fixmap */
+	/*
+	 * If we have OLPC OFW, we might end up relocating the fixmap due to
+	 * reserve_top(), so do this before touching the ioremap area.
+	 */
 	olpc_ofw_detect();
 
 	early_trap_init();
@@ -782,12 +774,13 @@
 #endif
 	 4)) {
 		efi_enabled = 1;
-		efi_reserve_early();
+		efi_memblock_x86_reserve_range();
 	}
 #endif
 
 	x86_init.oem.arch_setup();
 
+	iomem_resource.end = (1ULL << boot_cpu_data.x86_phys_bits) - 1;
 	setup_memory_map();
 	parse_setup_data();
 	/* update the e820_saved too */
@@ -838,11 +831,8 @@
 
 	x86_report_nx();
 
-	/* Must be before kernel pagetables are setup */
-	vmi_activate();
-
 	/* after early param, so could get panic from serial */
-	reserve_early_setup_data();
+	memblock_x86_reserve_range_setup_data();
 
 	if (acpi_mps_check()) {
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -863,8 +853,6 @@
 
 	dmi_scan_machine();
 
-	dmi_check_system(bad_bios_dmi_table);
-
 	/*
 	 * VMware detection requires dmi to be available, so this
 	 * needs to be done after dmi_scan_machine, for the BP.
@@ -897,8 +885,6 @@
 	 */
 	max_pfn = e820_end_of_ram_pfn();
 
-	/* preallocate 4k for mptable mpc */
-	early_reserve_e820_mpc_new();
 	/* update e820 for memory not covered by WB MTRRs */
 	mtrr_bp_init();
 	if (mtrr_trim_uncached_memory(max_pfn))
@@ -920,18 +906,8 @@
 		max_low_pfn = max_pfn;
 
 	high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
-	max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
 #endif
 
-#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
-	setup_bios_corruption_check();
-#endif
-
-	printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
-			max_pfn_mapped<<PAGE_SHIFT);
-
-	reserve_brk();
-
 	/*
 	 * Find and reserve possible boot-time SMP configuration:
 	 */
@@ -939,6 +915,26 @@
 
 	reserve_ibft_region();
 
+	/*
+	 * Need to conclude brk, before memblock_x86_fill()
+	 *  it could use memblock_find_in_range, could overlap with
+	 *  brk area.
+	 */
+	reserve_brk();
+
+	memblock.current_limit = get_max_mapped();
+	memblock_x86_fill();
+
+	/* preallocate 4k for mptable mpc */
+	early_reserve_e820_mpc_new();
+
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+	setup_bios_corruption_check();
+#endif
+
+	printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
+			max_pfn_mapped<<PAGE_SHIFT);
+
 	reserve_trampoline_memory();
 
 #ifdef CONFIG_ACPI_SLEEP
@@ -962,6 +958,7 @@
 		max_low_pfn = max_pfn;
 	}
 #endif
+	memblock.current_limit = get_max_mapped();
 
 	/*
 	 * NOTE: On x86-32, only from this point on, fixmaps are ready for use.
@@ -1000,10 +997,7 @@
 #endif
 
 	initmem_init(0, max_pfn, acpi, k8);
-#ifndef CONFIG_NO_BOOTMEM
-	early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
-#endif
-
+	memblock_find_dma_reserve();
 	dma32_reserve_bootmem();
 
 #ifdef CONFIG_KVM_CLOCK
@@ -1014,7 +1008,12 @@
 	paging_init();
 	x86_init.paging.pagetable_setup_done(swapper_pg_dir);
 
-	setup_trampoline_page_table();
+#ifdef CONFIG_X86_32
+	/* sync back kernel address range */
+	clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY,
+			swapper_pg_dir     + KERNEL_PGD_BOUNDARY,
+			KERNEL_PGD_PTRS);
+#endif
 
 	tboot_probe();
 
@@ -1071,6 +1070,10 @@
 	x86_init.oem.banner();
 
 	mcheck_init();
+
+	local_irq_save(flags);
+	arch_init_ideal_nop5();
+	local_irq_restore(flags);
 }
 
 #ifdef CONFIG_X86_32
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/setup_percpu.c linux-libre-2.6.37-gnu/arch/x86/kernel/setup_percpu.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/setup_percpu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/setup_percpu.c	2011-01-04 19:50:19.000000000 -0500
@@ -131,13 +131,7 @@
 
 static void __init pcpu_fc_free(void *ptr, size_t size)
 {
-#ifdef CONFIG_NO_BOOTMEM
-	u64 start = __pa(ptr);
-	u64 end = start + size;
-	free_early_partial(start, end);
-#else
 	free_bootmem(__pa(ptr), size);
-#endif
 }
 
 static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
@@ -253,7 +247,7 @@
 		 * Up to this point, the boot CPU has been using .init.data
 		 * area.  Reload any changed state for the boot CPU.
 		 */
-		if (cpu == boot_cpu_id)
+		if (!cpu)
 			switch_to_new_gdt(cpu);
 	}
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/sfi.c linux-libre-2.6.37-gnu/arch/x86/kernel/sfi.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/sfi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/sfi.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,120 +0,0 @@
-/*
- * sfi.c - x86 architecture SFI support.
- *
- * Copyright (c) 2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#define KMSG_COMPONENT "SFI"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/acpi.h>
-#include <linux/init.h>
-#include <linux/sfi.h>
-#include <linux/io.h>
-
-#include <asm/io_apic.h>
-#include <asm/mpspec.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-
-#ifdef CONFIG_X86_LOCAL_APIC
-static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
-
-void __init mp_sfi_register_lapic_address(unsigned long address)
-{
-	mp_lapic_addr = address;
-
-	set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
-	if (boot_cpu_physical_apicid == -1U)
-		boot_cpu_physical_apicid = read_apic_id();
-
-	pr_info("Boot CPU = %d\n", boot_cpu_physical_apicid);
-}
-
-/* All CPUs enumerated by SFI must be present and enabled */
-void __cpuinit mp_sfi_register_lapic(u8 id)
-{
-	if (MAX_APICS - id <= 0) {
-		pr_warning("Processor #%d invalid (max %d)\n",
-			id, MAX_APICS);
-		return;
-	}
-
-	pr_info("registering lapic[%d]\n", id);
-
-	generic_processor_info(id, GET_APIC_VERSION(apic_read(APIC_LVR)));
-}
-
-static int __init sfi_parse_cpus(struct sfi_table_header *table)
-{
-	struct sfi_table_simple *sb;
-	struct sfi_cpu_table_entry *pentry;
-	int i;
-	int cpu_num;
-
-	sb = (struct sfi_table_simple *)table;
-	cpu_num = SFI_GET_NUM_ENTRIES(sb, struct sfi_cpu_table_entry);
-	pentry = (struct sfi_cpu_table_entry *)sb->pentry;
-
-	for (i = 0; i < cpu_num; i++) {
-		mp_sfi_register_lapic(pentry->apic_id);
-		pentry++;
-	}
-
-	smp_found_config = 1;
-	return 0;
-}
-#endif /* CONFIG_X86_LOCAL_APIC */
-
-#ifdef CONFIG_X86_IO_APIC
-
-static int __init sfi_parse_ioapic(struct sfi_table_header *table)
-{
-	struct sfi_table_simple *sb;
-	struct sfi_apic_table_entry *pentry;
-	int i, num;
-
-	sb = (struct sfi_table_simple *)table;
-	num = SFI_GET_NUM_ENTRIES(sb, struct sfi_apic_table_entry);
-	pentry = (struct sfi_apic_table_entry *)sb->pentry;
-
-	for (i = 0; i < num; i++) {
-		mp_register_ioapic(i, pentry->phys_addr, gsi_top);
-		pentry++;
-	}
-
-	WARN(pic_mode, KERN_WARNING
-		"SFI: pic_mod shouldn't be 1 when IOAPIC table is present\n");
-	pic_mode = 0;
-	return 0;
-}
-#endif /* CONFIG_X86_IO_APIC */
-
-/*
- * sfi_platform_init(): register lapics & io-apics
- */
-int __init sfi_platform_init(void)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	mp_sfi_register_lapic_address(sfi_lapic_addr);
-	sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, sfi_parse_cpus);
-#endif
-#ifdef CONFIG_X86_IO_APIC
-	sfi_table_parse(SFI_SIG_APIC, NULL, NULL, sfi_parse_ioapic);
-#endif
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/smpboot.c linux-libre-2.6.37-gnu/arch/x86/kernel/smpboot.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/smpboot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/smpboot.c	2011-01-04 19:50:19.000000000 -0500
@@ -62,7 +62,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>
-#include <asm/vmi.h>
+#include <asm/mwait.h>
 #include <asm/apic.h>
 #include <asm/setup.h>
 #include <asm/uv/uv.h>
@@ -299,23 +299,16 @@
 	 * fragile that we want to limit the things done here to the
 	 * most necessary things.
 	 */
+	cpu_init();
+	preempt_disable();
+	smp_callin();
 
 #ifdef CONFIG_X86_32
-	/*
-	 * Switch away from the trampoline page-table
-	 *
-	 * Do this before cpu_init() because it needs to access per-cpu
-	 * data which may not be mapped in the trampoline page-table.
-	 */
+	/* switch away from the initial page table */
 	load_cr3(swapper_pg_dir);
 	__flush_tlb_all();
 #endif
 
-	vmi_bringup();
-	cpu_init();
-	preempt_disable();
-	smp_callin();
-
 	/* otherwise gcc will move up smp_processor_id before the cpu_init */
 	barrier();
 	/*
@@ -324,9 +317,9 @@
 	check_tsc_sync_target();
 
 	if (nmi_watchdog == NMI_IO_APIC) {
-		legacy_pic->chip->mask(0);
+		legacy_pic->mask(0);
 		enable_NMI_through_LVT0();
-		legacy_pic->chip->unmask(0);
+		legacy_pic->unmask(0);
 	}
 
 	/* This must be done before setting cpu_online_mask */
@@ -397,6 +390,19 @@
 		identify_secondary_cpu(c);
 }
 
+static void __cpuinit link_thread_siblings(int cpu1, int cpu2)
+{
+	struct cpuinfo_x86 *c1 = &cpu_data(cpu1);
+	struct cpuinfo_x86 *c2 = &cpu_data(cpu2);
+
+	cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2));
+	cpumask_set_cpu(cpu2, cpu_sibling_mask(cpu1));
+	cpumask_set_cpu(cpu1, cpu_core_mask(cpu2));
+	cpumask_set_cpu(cpu2, cpu_core_mask(cpu1));
+	cpumask_set_cpu(cpu1, c2->llc_shared_map);
+	cpumask_set_cpu(cpu2, c1->llc_shared_map);
+}
+
 
 void __cpuinit set_cpu_sibling_map(int cpu)
 {
@@ -409,14 +415,13 @@
 		for_each_cpu(i, cpu_sibling_setup_mask) {
 			struct cpuinfo_x86 *o = &cpu_data(i);
 
-			if (c->phys_proc_id == o->phys_proc_id &&
-			    c->cpu_core_id == o->cpu_core_id) {
-				cpumask_set_cpu(i, cpu_sibling_mask(cpu));
-				cpumask_set_cpu(cpu, cpu_sibling_mask(i));
-				cpumask_set_cpu(i, cpu_core_mask(cpu));
-				cpumask_set_cpu(cpu, cpu_core_mask(i));
-				cpumask_set_cpu(i, c->llc_shared_map);
-				cpumask_set_cpu(cpu, o->llc_shared_map);
+			if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+				if (c->phys_proc_id == o->phys_proc_id &&
+				    c->compute_unit_id == o->compute_unit_id)
+					link_thread_siblings(cpu, i);
+			} else if (c->phys_proc_id == o->phys_proc_id &&
+				   c->cpu_core_id == o->cpu_core_id) {
+				link_thread_siblings(cpu, i);
 			}
 		}
 	} else {
@@ -742,7 +747,7 @@
 		.done	= COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
 	};
 
-	INIT_WORK_ON_STACK(&c_idle.work, do_fork_idle);
+	INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
 
 	alternatives_smp_switch(1);
 
@@ -774,7 +779,6 @@
 #ifdef CONFIG_X86_32
 	/* Stack for startup_32 can be just as for start_secondary onwards */
 	irq_ctx_init(cpu);
-	initial_page_table = __pa(&trampoline_pg_dir);
 #else
 	clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
 	initial_gs = per_cpu_offset(cpu);
@@ -923,7 +927,6 @@
 	per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
 
 	err = do_boot_cpu(apicid, cpu);
-
 	if (err) {
 		pr_debug("do_boot_cpu failed %d\n", err);
 		return -EIO;
@@ -1109,8 +1112,6 @@
 	}
 	set_cpu_sibling_map(0);
 
-	enable_IR_x2apic();
-	default_setup_apic_routing();
 
 	if (smp_sanity_check(max_cpus) < 0) {
 		printk(KERN_INFO "SMP disabled\n");
@@ -1118,6 +1119,8 @@
 		goto out;
 	}
 
+	default_setup_apic_routing();
+
 	preempt_disable();
 	if (read_apic_id() != boot_cpu_physical_apicid) {
 		panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
@@ -1370,7 +1373,6 @@
 {
 	idle_task_exit();
 	reset_lazy_tlbstate();
-	irq_ctx_exit(raw_smp_processor_id());
 	c1e_remove_cpu(raw_smp_processor_id());
 
 	mb();
@@ -1383,11 +1385,88 @@
 	local_irq_disable();
 }
 
+/*
+ * We need to flush the caches before going to sleep, lest we have
+ * dirty data in our caches when we come back up.
+ */
+static inline void mwait_play_dead(void)
+{
+	unsigned int eax, ebx, ecx, edx;
+	unsigned int highest_cstate = 0;
+	unsigned int highest_subcstate = 0;
+	int i;
+	void *mwait_ptr;
+
+	if (!cpu_has(&current_cpu_data, X86_FEATURE_MWAIT))
+		return;
+	if (!cpu_has(&current_cpu_data, X86_FEATURE_CLFLSH))
+		return;
+	if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+		return;
+
+	eax = CPUID_MWAIT_LEAF;
+	ecx = 0;
+	native_cpuid(&eax, &ebx, &ecx, &edx);
+
+	/*
+	 * eax will be 0 if EDX enumeration is not valid.
+	 * Initialized below to cstate, sub_cstate value when EDX is valid.
+	 */
+	if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) {
+		eax = 0;
+	} else {
+		edx >>= MWAIT_SUBSTATE_SIZE;
+		for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+			if (edx & MWAIT_SUBSTATE_MASK) {
+				highest_cstate = i;
+				highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+			}
+		}
+		eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+			(highest_subcstate - 1);
+	}
+
+	/*
+	 * This should be a memory location in a cache line which is
+	 * unlikely to be touched by other processors.  The actual
+	 * content is immaterial as it is not actually modified in any way.
+	 */
+	mwait_ptr = &current_thread_info()->flags;
+
+	wbinvd();
+
+	while (1) {
+		/*
+		 * The CLFLUSH is a workaround for erratum AAI65 for
+		 * the Xeon 7400 series.  It's not clear it is actually
+		 * needed, but it should be harmless in either case.
+		 * The WBINVD is insufficient due to the spurious-wakeup
+		 * case where we return around the loop.
+		 */
+		clflush(mwait_ptr);
+		__monitor(mwait_ptr, 0, 0);
+		mb();
+		__mwait(eax, 0);
+	}
+}
+
+static inline void hlt_play_dead(void)
+{
+	if (current_cpu_data.x86 >= 4)
+		wbinvd();
+
+	while (1) {
+		native_halt();
+	}
+}
+
 void native_play_dead(void)
 {
 	play_dead_common();
 	tboot_shutdown(TB_SHUTDOWN_WFS);
-	wbinvd_halt();
+
+	mwait_play_dead();	/* Only returns on failure */
+	hlt_play_dead();
 }
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/smp.c linux-libre-2.6.37-gnu/arch/x86/kernel/smp.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -159,10 +159,10 @@
 	irq_exit();
 }
 
-static void native_smp_send_stop(void)
+static void native_stop_other_cpus(int wait)
 {
 	unsigned long flags;
-	unsigned long wait;
+	unsigned long timeout;
 
 	if (reboot_force)
 		return;
@@ -179,9 +179,12 @@
 	if (num_online_cpus() > 1) {
 		apic->send_IPI_allbutself(REBOOT_VECTOR);
 
-		/* Don't wait longer than a second */
-		wait = USEC_PER_SEC;
-		while (num_online_cpus() > 1 && wait--)
+		/*
+		 * Don't wait longer than a second if the caller
+		 * didn't ask us to wait.
+		 */
+		timeout = USEC_PER_SEC;
+		while (num_online_cpus() > 1 && (wait || timeout--))
 			udelay(1);
 	}
 
@@ -227,7 +230,7 @@
 	.smp_prepare_cpus	= native_smp_prepare_cpus,
 	.smp_cpus_done		= native_smp_cpus_done,
 
-	.smp_send_stop		= native_smp_send_stop,
+	.stop_other_cpus	= native_stop_other_cpus,
 	.smp_send_reschedule	= native_smp_send_reschedule,
 
 	.cpu_up			= native_cpu_up,
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/sys_i386_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/sys_i386_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/sys_i386_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/sys_i386_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,8 +33,8 @@
 		  const char *const envp[])
 {
 	long __res;
-	asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
+	asm volatile ("int $0x80"
 	: "=a" (__res)
-	: "0" (__NR_execve), "ri" (filename), "c" (argv), "d" (envp) : "memory");
+	: "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory");
 	return __res;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/tlb_uv.c linux-libre-2.6.37-gnu/arch/x86/kernel/tlb_uv.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/tlb_uv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/tlb_uv.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1655 +0,0 @@
-/*
- *	SGI UltraViolet TLB flush routines.
- *
- *	(c) 2008-2010 Cliff Wickman <cpw@sgi.com>, SGI.
- *
- *	This code is released under the GNU General Public License version 2 or
- *	later.
- */
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/debugfs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <asm/mmu_context.h>
-#include <asm/uv/uv.h>
-#include <asm/uv/uv_mmrs.h>
-#include <asm/uv/uv_hub.h>
-#include <asm/uv/uv_bau.h>
-#include <asm/apic.h>
-#include <asm/idle.h>
-#include <asm/tsc.h>
-#include <asm/irq_vectors.h>
-#include <asm/timer.h>
-
-/* timeouts in nanoseconds (indexed by UVH_AGING_PRESCALE_SEL urgency7 30:28) */
-static int timeout_base_ns[] = {
-		20,
-		160,
-		1280,
-		10240,
-		81920,
-		655360,
-		5242880,
-		167772160
-};
-static int timeout_us;
-static int nobau;
-static int baudisabled;
-static spinlock_t disable_lock;
-static cycles_t congested_cycles;
-
-/* tunables: */
-static int max_bau_concurrent = MAX_BAU_CONCURRENT;
-static int max_bau_concurrent_constant = MAX_BAU_CONCURRENT;
-static int plugged_delay = PLUGGED_DELAY;
-static int plugsb4reset = PLUGSB4RESET;
-static int timeoutsb4reset = TIMEOUTSB4RESET;
-static int ipi_reset_limit = IPI_RESET_LIMIT;
-static int complete_threshold = COMPLETE_THRESHOLD;
-static int congested_response_us = CONGESTED_RESPONSE_US;
-static int congested_reps = CONGESTED_REPS;
-static int congested_period = CONGESTED_PERIOD;
-static struct dentry *tunables_dir;
-static struct dentry *tunables_file;
-
-static int __init setup_nobau(char *arg)
-{
-	nobau = 1;
-	return 0;
-}
-early_param("nobau", setup_nobau);
-
-/* base pnode in this partition */
-static int uv_partition_base_pnode __read_mostly;
-/* position of pnode (which is nasid>>1): */
-static int uv_nshift __read_mostly;
-static unsigned long uv_mmask __read_mostly;
-
-static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
-static DEFINE_PER_CPU(struct bau_control, bau_control);
-static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
-
-/*
- * Determine the first node on a uvhub. 'Nodes' are used for kernel
- * memory allocation.
- */
-static int __init uvhub_to_first_node(int uvhub)
-{
-	int node, b;
-
-	for_each_online_node(node) {
-		b = uv_node_to_blade_id(node);
-		if (uvhub == b)
-			return node;
-	}
-	return -1;
-}
-
-/*
- * Determine the apicid of the first cpu on a uvhub.
- */
-static int __init uvhub_to_first_apicid(int uvhub)
-{
-	int cpu;
-
-	for_each_present_cpu(cpu)
-		if (uvhub == uv_cpu_to_blade_id(cpu))
-			return per_cpu(x86_cpu_to_apicid, cpu);
-	return -1;
-}
-
-/*
- * Free a software acknowledge hardware resource by clearing its Pending
- * bit. This will return a reply to the sender.
- * If the message has timed out, a reply has already been sent by the
- * hardware but the resource has not been released. In that case our
- * clear of the Timeout bit (as well) will free the resource. No reply will
- * be sent (the hardware will only do one reply per message).
- */
-static inline void uv_reply_to_message(struct msg_desc *mdp,
-				       struct bau_control *bcp)
-{
-	unsigned long dw;
-	struct bau_payload_queue_entry *msg;
-
-	msg = mdp->msg;
-	if (!msg->canceled) {
-		dw = (msg->sw_ack_vector << UV_SW_ACK_NPENDING) |
-						msg->sw_ack_vector;
-		uv_write_local_mmr(
-				UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, dw);
-	}
-	msg->replied_to = 1;
-	msg->sw_ack_vector = 0;
-}
-
-/*
- * Process the receipt of a RETRY message
- */
-static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
-					    struct bau_control *bcp)
-{
-	int i;
-	int cancel_count = 0;
-	int slot2;
-	unsigned long msg_res;
-	unsigned long mmr = 0;
-	struct bau_payload_queue_entry *msg;
-	struct bau_payload_queue_entry *msg2;
-	struct ptc_stats *stat;
-
-	msg = mdp->msg;
-	stat = bcp->statp;
-	stat->d_retries++;
-	/*
-	 * cancel any message from msg+1 to the retry itself
-	 */
-	for (msg2 = msg+1, i = 0; i < DEST_Q_SIZE; msg2++, i++) {
-		if (msg2 > mdp->va_queue_last)
-			msg2 = mdp->va_queue_first;
-		if (msg2 == msg)
-			break;
-
-		/* same conditions for cancellation as uv_do_reset */
-		if ((msg2->replied_to == 0) && (msg2->canceled == 0) &&
-		    (msg2->sw_ack_vector) && ((msg2->sw_ack_vector &
-			msg->sw_ack_vector) == 0) &&
-		    (msg2->sending_cpu == msg->sending_cpu) &&
-		    (msg2->msg_type != MSG_NOOP)) {
-			slot2 = msg2 - mdp->va_queue_first;
-			mmr = uv_read_local_mmr
-				(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-			msg_res = msg2->sw_ack_vector;
-			/*
-			 * This is a message retry; clear the resources held
-			 * by the previous message only if they timed out.
-			 * If it has not timed out we have an unexpected
-			 * situation to report.
-			 */
-			if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
-				/*
-				 * is the resource timed out?
-				 * make everyone ignore the cancelled message.
-				 */
-				msg2->canceled = 1;
-				stat->d_canceled++;
-				cancel_count++;
-				uv_write_local_mmr(
-				    UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
-					(msg_res << UV_SW_ACK_NPENDING) |
-					 msg_res);
-			}
-		}
-	}
-	if (!cancel_count)
-		stat->d_nocanceled++;
-}
-
-/*
- * Do all the things a cpu should do for a TLB shootdown message.
- * Other cpu's may come here at the same time for this message.
- */
-static void uv_bau_process_message(struct msg_desc *mdp,
-				   struct bau_control *bcp)
-{
-	int msg_ack_count;
-	short socket_ack_count = 0;
-	struct ptc_stats *stat;
-	struct bau_payload_queue_entry *msg;
-	struct bau_control *smaster = bcp->socket_master;
-
-	/*
-	 * This must be a normal message, or retry of a normal message
-	 */
-	msg = mdp->msg;
-	stat = bcp->statp;
-	if (msg->address == TLB_FLUSH_ALL) {
-		local_flush_tlb();
-		stat->d_alltlb++;
-	} else {
-		__flush_tlb_one(msg->address);
-		stat->d_onetlb++;
-	}
-	stat->d_requestee++;
-
-	/*
-	 * One cpu on each uvhub has the additional job on a RETRY
-	 * of releasing the resource held by the message that is
-	 * being retried.  That message is identified by sending
-	 * cpu number.
-	 */
-	if (msg->msg_type == MSG_RETRY && bcp == bcp->uvhub_master)
-		uv_bau_process_retry_msg(mdp, bcp);
-
-	/*
-	 * This is a sw_ack message, so we have to reply to it.
-	 * Count each responding cpu on the socket. This avoids
-	 * pinging the count's cache line back and forth between
-	 * the sockets.
-	 */
-	socket_ack_count = atomic_add_short_return(1, (struct atomic_short *)
-			&smaster->socket_acknowledge_count[mdp->msg_slot]);
-	if (socket_ack_count == bcp->cpus_in_socket) {
-		/*
-		 * Both sockets dump their completed count total into
-		 * the message's count.
-		 */
-		smaster->socket_acknowledge_count[mdp->msg_slot] = 0;
-		msg_ack_count = atomic_add_short_return(socket_ack_count,
-				(struct atomic_short *)&msg->acknowledge_count);
-
-		if (msg_ack_count == bcp->cpus_in_uvhub) {
-			/*
-			 * All cpus in uvhub saw it; reply
-			 */
-			uv_reply_to_message(mdp, bcp);
-		}
-	}
-
-	return;
-}
-
-/*
- * Determine the first cpu on a uvhub.
- */
-static int uvhub_to_first_cpu(int uvhub)
-{
-	int cpu;
-	for_each_present_cpu(cpu)
-		if (uvhub == uv_cpu_to_blade_id(cpu))
-			return cpu;
-	return -1;
-}
-
-/*
- * Last resort when we get a large number of destination timeouts is
- * to clear resources held by a given cpu.
- * Do this with IPI so that all messages in the BAU message queue
- * can be identified by their nonzero sw_ack_vector field.
- *
- * This is entered for a single cpu on the uvhub.
- * The sender want's this uvhub to free a specific message's
- * sw_ack resources.
- */
-static void
-uv_do_reset(void *ptr)
-{
-	int i;
-	int slot;
-	int count = 0;
-	unsigned long mmr;
-	unsigned long msg_res;
-	struct bau_control *bcp;
-	struct reset_args *rap;
-	struct bau_payload_queue_entry *msg;
-	struct ptc_stats *stat;
-
-	bcp = &per_cpu(bau_control, smp_processor_id());
-	rap = (struct reset_args *)ptr;
-	stat = bcp->statp;
-	stat->d_resets++;
-
-	/*
-	 * We're looking for the given sender, and
-	 * will free its sw_ack resource.
-	 * If all cpu's finally responded after the timeout, its
-	 * message 'replied_to' was set.
-	 */
-	for (msg = bcp->va_queue_first, i = 0; i < DEST_Q_SIZE; msg++, i++) {
-		/* uv_do_reset: same conditions for cancellation as
-		   uv_bau_process_retry_msg() */
-		if ((msg->replied_to == 0) &&
-		    (msg->canceled == 0) &&
-		    (msg->sending_cpu == rap->sender) &&
-		    (msg->sw_ack_vector) &&
-		    (msg->msg_type != MSG_NOOP)) {
-			/*
-			 * make everyone else ignore this message
-			 */
-			msg->canceled = 1;
-			slot = msg - bcp->va_queue_first;
-			count++;
-			/*
-			 * only reset the resource if it is still pending
-			 */
-			mmr = uv_read_local_mmr
-					(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
-			msg_res = msg->sw_ack_vector;
-			if (mmr & msg_res) {
-				stat->d_rcanceled++;
-				uv_write_local_mmr(
-				    UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
-					(msg_res << UV_SW_ACK_NPENDING) |
-					 msg_res);
-			}
-		}
-	}
-	return;
-}
-
-/*
- * Use IPI to get all target uvhubs to release resources held by
- * a given sending cpu number.
- */
-static void uv_reset_with_ipi(struct bau_target_uvhubmask *distribution,
-			      int sender)
-{
-	int uvhub;
-	int cpu;
-	cpumask_t mask;
-	struct reset_args reset_args;
-
-	reset_args.sender = sender;
-
-	cpus_clear(mask);
-	/* find a single cpu for each uvhub in this distribution mask */
-	for (uvhub = 0;
-		    uvhub < sizeof(struct bau_target_uvhubmask) * BITSPERBYTE;
-		    uvhub++) {
-		if (!bau_uvhub_isset(uvhub, distribution))
-			continue;
-		/* find a cpu for this uvhub */
-		cpu = uvhub_to_first_cpu(uvhub);
-		cpu_set(cpu, mask);
-	}
-	/* IPI all cpus; Preemption is already disabled */
-	smp_call_function_many(&mask, uv_do_reset, (void *)&reset_args, 1);
-	return;
-}
-
-static inline unsigned long
-cycles_2_us(unsigned long long cyc)
-{
-	unsigned long long ns;
-	unsigned long us;
-	ns =  (cyc * per_cpu(cyc2ns, smp_processor_id()))
-						>> CYC2NS_SCALE_FACTOR;
-	us = ns / 1000;
-	return us;
-}
-
-/*
- * wait for all cpus on this hub to finish their sends and go quiet
- * leaves uvhub_quiesce set so that no new broadcasts are started by
- * bau_flush_send_and_wait()
- */
-static inline void
-quiesce_local_uvhub(struct bau_control *hmaster)
-{
-	atomic_add_short_return(1, (struct atomic_short *)
-		 &hmaster->uvhub_quiesce);
-}
-
-/*
- * mark this quiet-requestor as done
- */
-static inline void
-end_uvhub_quiesce(struct bau_control *hmaster)
-{
-	atomic_add_short_return(-1, (struct atomic_short *)
-		&hmaster->uvhub_quiesce);
-}
-
-/*
- * Wait for completion of a broadcast software ack message
- * return COMPLETE, RETRY(PLUGGED or TIMEOUT) or GIVEUP
- */
-static int uv_wait_completion(struct bau_desc *bau_desc,
-	unsigned long mmr_offset, int right_shift, int this_cpu,
-	struct bau_control *bcp, struct bau_control *smaster, long try)
-{
-	unsigned long descriptor_status;
-	cycles_t ttime;
-	struct ptc_stats *stat = bcp->statp;
-	struct bau_control *hmaster;
-
-	hmaster = bcp->uvhub_master;
-
-	/* spin on the status MMR, waiting for it to go idle */
-	while ((descriptor_status = (((unsigned long)
-		uv_read_local_mmr(mmr_offset) >>
-			right_shift) & UV_ACT_STATUS_MASK)) !=
-			DESC_STATUS_IDLE) {
-		/*
-		 * Our software ack messages may be blocked because there are
-		 * no swack resources available.  As long as none of them
-		 * has timed out hardware will NACK our message and its
-		 * state will stay IDLE.
-		 */
-		if (descriptor_status == DESC_STATUS_SOURCE_TIMEOUT) {
-			stat->s_stimeout++;
-			return FLUSH_GIVEUP;
-		} else if (descriptor_status ==
-					DESC_STATUS_DESTINATION_TIMEOUT) {
-			stat->s_dtimeout++;
-			ttime = get_cycles();
-
-			/*
-			 * Our retries may be blocked by all destination
-			 * swack resources being consumed, and a timeout
-			 * pending.  In that case hardware returns the
-			 * ERROR that looks like a destination timeout.
-			 */
-			if (cycles_2_us(ttime - bcp->send_message) <
-							timeout_us) {
-				bcp->conseccompletes = 0;
-				return FLUSH_RETRY_PLUGGED;
-			}
-
-			bcp->conseccompletes = 0;
-			return FLUSH_RETRY_TIMEOUT;
-		} else {
-			/*
-			 * descriptor_status is still BUSY
-			 */
-			cpu_relax();
-		}
-	}
-	bcp->conseccompletes++;
-	return FLUSH_COMPLETE;
-}
-
-static inline cycles_t
-sec_2_cycles(unsigned long sec)
-{
-	unsigned long ns;
-	cycles_t cyc;
-
-	ns = sec * 1000000000;
-	cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
-	return cyc;
-}
-
-/*
- * conditionally add 1 to *v, unless *v is >= u
- * return 0 if we cannot add 1 to *v because it is >= u
- * return 1 if we can add 1 to *v because it is < u
- * the add is atomic
- *
- * This is close to atomic_add_unless(), but this allows the 'u' value
- * to be lowered below the current 'v'.  atomic_add_unless can only stop
- * on equal.
- */
-static inline int atomic_inc_unless_ge(spinlock_t *lock, atomic_t *v, int u)
-{
-	spin_lock(lock);
-	if (atomic_read(v) >= u) {
-		spin_unlock(lock);
-		return 0;
-	}
-	atomic_inc(v);
-	spin_unlock(lock);
-	return 1;
-}
-
-/*
- * Our retries are blocked by all destination swack resources being
- * in use, and a timeout is pending. In that case hardware immediately
- * returns the ERROR that looks like a destination timeout.
- */
-static void
-destination_plugged(struct bau_desc *bau_desc, struct bau_control *bcp,
-			struct bau_control *hmaster, struct ptc_stats *stat)
-{
-	udelay(bcp->plugged_delay);
-	bcp->plugged_tries++;
-	if (bcp->plugged_tries >= bcp->plugsb4reset) {
-		bcp->plugged_tries = 0;
-		quiesce_local_uvhub(hmaster);
-		spin_lock(&hmaster->queue_lock);
-		uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
-		spin_unlock(&hmaster->queue_lock);
-		end_uvhub_quiesce(hmaster);
-		bcp->ipi_attempts++;
-		stat->s_resets_plug++;
-	}
-}
-
-static void
-destination_timeout(struct bau_desc *bau_desc, struct bau_control *bcp,
-			struct bau_control *hmaster, struct ptc_stats *stat)
-{
-	hmaster->max_bau_concurrent = 1;
-	bcp->timeout_tries++;
-	if (bcp->timeout_tries >= bcp->timeoutsb4reset) {
-		bcp->timeout_tries = 0;
-		quiesce_local_uvhub(hmaster);
-		spin_lock(&hmaster->queue_lock);
-		uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
-		spin_unlock(&hmaster->queue_lock);
-		end_uvhub_quiesce(hmaster);
-		bcp->ipi_attempts++;
-		stat->s_resets_timeout++;
-	}
-}
-
-/*
- * Completions are taking a very long time due to a congested numalink
- * network.
- */
-static void
-disable_for_congestion(struct bau_control *bcp, struct ptc_stats *stat)
-{
-	int tcpu;
-	struct bau_control *tbcp;
-
-	/* let only one cpu do this disabling */
-	spin_lock(&disable_lock);
-	if (!baudisabled && bcp->period_requests &&
-	    ((bcp->period_time / bcp->period_requests) > congested_cycles)) {
-		/* it becomes this cpu's job to turn on the use of the
-		   BAU again */
-		baudisabled = 1;
-		bcp->set_bau_off = 1;
-		bcp->set_bau_on_time = get_cycles() +
-			sec_2_cycles(bcp->congested_period);
-		stat->s_bau_disabled++;
-		for_each_present_cpu(tcpu) {
-			tbcp = &per_cpu(bau_control, tcpu);
-				tbcp->baudisabled = 1;
-		}
-	}
-	spin_unlock(&disable_lock);
-}
-
-/**
- * uv_flush_send_and_wait
- *
- * Send a broadcast and wait for it to complete.
- *
- * The flush_mask contains the cpus the broadcast is to be sent to including
- * cpus that are on the local uvhub.
- *
- * Returns 0 if all flushing represented in the mask was done.
- * Returns 1 if it gives up entirely and the original cpu mask is to be
- * returned to the kernel.
- */
-int uv_flush_send_and_wait(struct bau_desc *bau_desc,
-			   struct cpumask *flush_mask, struct bau_control *bcp)
-{
-	int right_shift;
-	int completion_status = 0;
-	int seq_number = 0;
-	long try = 0;
-	int cpu = bcp->uvhub_cpu;
-	int this_cpu = bcp->cpu;
-	unsigned long mmr_offset;
-	unsigned long index;
-	cycles_t time1;
-	cycles_t time2;
-	cycles_t elapsed;
-	struct ptc_stats *stat = bcp->statp;
-	struct bau_control *smaster = bcp->socket_master;
-	struct bau_control *hmaster = bcp->uvhub_master;
-
-	if (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
-			&hmaster->active_descriptor_count,
-			hmaster->max_bau_concurrent)) {
-		stat->s_throttles++;
-		do {
-			cpu_relax();
-		} while (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
-			&hmaster->active_descriptor_count,
-			hmaster->max_bau_concurrent));
-	}
-	while (hmaster->uvhub_quiesce)
-		cpu_relax();
-
-	if (cpu < UV_CPUS_PER_ACT_STATUS) {
-		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
-		right_shift = cpu * UV_ACT_STATUS_SIZE;
-	} else {
-		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
-		right_shift =
-		    ((cpu - UV_CPUS_PER_ACT_STATUS) * UV_ACT_STATUS_SIZE);
-	}
-	time1 = get_cycles();
-	do {
-		if (try == 0) {
-			bau_desc->header.msg_type = MSG_REGULAR;
-			seq_number = bcp->message_number++;
-		} else {
-			bau_desc->header.msg_type = MSG_RETRY;
-			stat->s_retry_messages++;
-		}
-		bau_desc->header.sequence = seq_number;
-		index = (1UL << UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT) |
-			bcp->uvhub_cpu;
-		bcp->send_message = get_cycles();
-		uv_write_local_mmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
-		try++;
-		completion_status = uv_wait_completion(bau_desc, mmr_offset,
-			right_shift, this_cpu, bcp, smaster, try);
-
-		if (completion_status == FLUSH_RETRY_PLUGGED) {
-			destination_plugged(bau_desc, bcp, hmaster, stat);
-		} else if (completion_status == FLUSH_RETRY_TIMEOUT) {
-			destination_timeout(bau_desc, bcp, hmaster, stat);
-		}
-		if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
-			bcp->ipi_attempts = 0;
-			completion_status = FLUSH_GIVEUP;
-			break;
-		}
-		cpu_relax();
-	} while ((completion_status == FLUSH_RETRY_PLUGGED) ||
-		 (completion_status == FLUSH_RETRY_TIMEOUT));
-	time2 = get_cycles();
-	bcp->plugged_tries = 0;
-	bcp->timeout_tries = 0;
-	if ((completion_status == FLUSH_COMPLETE) &&
-	    (bcp->conseccompletes > bcp->complete_threshold) &&
-	    (hmaster->max_bau_concurrent <
-					hmaster->max_bau_concurrent_constant))
-			hmaster->max_bau_concurrent++;
-	while (hmaster->uvhub_quiesce)
-		cpu_relax();
-	atomic_dec(&hmaster->active_descriptor_count);
-	if (time2 > time1) {
-		elapsed = time2 - time1;
-		stat->s_time += elapsed;
-		if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
-			bcp->period_requests++;
-			bcp->period_time += elapsed;
-			if ((elapsed > congested_cycles) &&
-			    (bcp->period_requests > bcp->congested_reps)) {
-				disable_for_congestion(bcp, stat);
-			}
-		}
-	} else
-		stat->s_requestor--;
-	if (completion_status == FLUSH_COMPLETE && try > 1)
-		stat->s_retriesok++;
-	else if (completion_status == FLUSH_GIVEUP) {
-		stat->s_giveup++;
-		return 1;
-	}
-	return 0;
-}
-
-/**
- * uv_flush_tlb_others - globally purge translation cache of a virtual
- * address or all TLB's
- * @cpumask: mask of all cpu's in which the address is to be removed
- * @mm: mm_struct containing virtual address range
- * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
- * @cpu: the current cpu
- *
- * This is the entry point for initiating any UV global TLB shootdown.
- *
- * Purges the translation caches of all specified processors of the given
- * virtual address, or purges all TLB's on specified processors.
- *
- * The caller has derived the cpumask from the mm_struct.  This function
- * is called only if there are bits set in the mask. (e.g. flush_tlb_page())
- *
- * The cpumask is converted into a uvhubmask of the uvhubs containing
- * those cpus.
- *
- * Note that this function should be called with preemption disabled.
- *
- * Returns NULL if all remote flushing was done.
- * Returns pointer to cpumask if some remote flushing remains to be
- * done.  The returned pointer is valid till preemption is re-enabled.
- */
-const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
-					  struct mm_struct *mm,
-					  unsigned long va, unsigned int cpu)
-{
-	int tcpu;
-	int uvhub;
-	int locals = 0;
-	int remotes = 0;
-	int hubs = 0;
-	struct bau_desc *bau_desc;
-	struct cpumask *flush_mask;
-	struct ptc_stats *stat;
-	struct bau_control *bcp;
-	struct bau_control *tbcp;
-
-	/* kernel was booted 'nobau' */
-	if (nobau)
-		return cpumask;
-
-	bcp = &per_cpu(bau_control, cpu);
-	stat = bcp->statp;
-
-	/* bau was disabled due to slow response */
-	if (bcp->baudisabled) {
-		/* the cpu that disabled it must re-enable it */
-		if (bcp->set_bau_off) {
-			if (get_cycles() >= bcp->set_bau_on_time) {
-				stat->s_bau_reenabled++;
-				baudisabled = 0;
-				for_each_present_cpu(tcpu) {
-					tbcp = &per_cpu(bau_control, tcpu);
-					tbcp->baudisabled = 0;
-					tbcp->period_requests = 0;
-					tbcp->period_time = 0;
-				}
-			}
-		}
-		return cpumask;
-	}
-
-	/*
-	 * Each sending cpu has a per-cpu mask which it fills from the caller's
-	 * cpu mask.  All cpus are converted to uvhubs and copied to the
-	 * activation descriptor.
-	 */
-	flush_mask = (struct cpumask *)per_cpu(uv_flush_tlb_mask, cpu);
-	/* don't actually do a shootdown of the local cpu */
-	cpumask_andnot(flush_mask, cpumask, cpumask_of(cpu));
-	if (cpu_isset(cpu, *cpumask))
-		stat->s_ntargself++;
-
-	bau_desc = bcp->descriptor_base;
-	bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu;
-	bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
-
-	/* cpu statistics */
-	for_each_cpu(tcpu, flush_mask) {
-		uvhub = uv_cpu_to_blade_id(tcpu);
-		bau_uvhub_set(uvhub, &bau_desc->distribution);
-		if (uvhub == bcp->uvhub)
-			locals++;
-		else
-			remotes++;
-	}
-	if ((locals + remotes) == 0)
-		return NULL;
-	stat->s_requestor++;
-	stat->s_ntargcpu += remotes + locals;
-	stat->s_ntargremotes += remotes;
-	stat->s_ntarglocals += locals;
-	remotes = bau_uvhub_weight(&bau_desc->distribution);
-
-	/* uvhub statistics */
-	hubs = bau_uvhub_weight(&bau_desc->distribution);
-	if (locals) {
-		stat->s_ntarglocaluvhub++;
-		stat->s_ntargremoteuvhub += (hubs - 1);
-	} else
-		stat->s_ntargremoteuvhub += hubs;
-	stat->s_ntarguvhub += hubs;
-	if (hubs >= 16)
-		stat->s_ntarguvhub16++;
-	else if (hubs >= 8)
-		stat->s_ntarguvhub8++;
-	else if (hubs >= 4)
-		stat->s_ntarguvhub4++;
-	else if (hubs >= 2)
-		stat->s_ntarguvhub2++;
-	else
-		stat->s_ntarguvhub1++;
-
-	bau_desc->payload.address = va;
-	bau_desc->payload.sending_cpu = cpu;
-
-	/*
-	 * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
-	 * or 1 if it gave up and the original cpumask should be returned.
-	 */
-	if (!uv_flush_send_and_wait(bau_desc, flush_mask, bcp))
-		return NULL;
-	else
-		return cpumask;
-}
-
-/*
- * The BAU message interrupt comes here. (registered by set_intr_gate)
- * See entry_64.S
- *
- * We received a broadcast assist message.
- *
- * Interrupts are disabled; this interrupt could represent
- * the receipt of several messages.
- *
- * All cores/threads on this hub get this interrupt.
- * The last one to see it does the software ack.
- * (the resource will not be freed until noninterruptable cpus see this
- *  interrupt; hardware may timeout the s/w ack and reply ERROR)
- */
-void uv_bau_message_interrupt(struct pt_regs *regs)
-{
-	int count = 0;
-	cycles_t time_start;
-	struct bau_payload_queue_entry *msg;
-	struct bau_control *bcp;
-	struct ptc_stats *stat;
-	struct msg_desc msgdesc;
-
-	time_start = get_cycles();
-	bcp = &per_cpu(bau_control, smp_processor_id());
-	stat = bcp->statp;
-	msgdesc.va_queue_first = bcp->va_queue_first;
-	msgdesc.va_queue_last = bcp->va_queue_last;
-	msg = bcp->bau_msg_head;
-	while (msg->sw_ack_vector) {
-		count++;
-		msgdesc.msg_slot = msg - msgdesc.va_queue_first;
-		msgdesc.sw_ack_slot = ffs(msg->sw_ack_vector) - 1;
-		msgdesc.msg = msg;
-		uv_bau_process_message(&msgdesc, bcp);
-		msg++;
-		if (msg > msgdesc.va_queue_last)
-			msg = msgdesc.va_queue_first;
-		bcp->bau_msg_head = msg;
-	}
-	stat->d_time += (get_cycles() - time_start);
-	if (!count)
-		stat->d_nomsg++;
-	else if (count > 1)
-		stat->d_multmsg++;
-	ack_APIC_irq();
-}
-
-/*
- * uv_enable_timeouts
- *
- * Each target uvhub (i.e. a uvhub that has no cpu's) needs to have
- * shootdown message timeouts enabled.  The timeout does not cause
- * an interrupt, but causes an error message to be returned to
- * the sender.
- */
-static void uv_enable_timeouts(void)
-{
-	int uvhub;
-	int nuvhubs;
-	int pnode;
-	unsigned long mmr_image;
-
-	nuvhubs = uv_num_possible_blades();
-
-	for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-		if (!uv_blade_nr_possible_cpus(uvhub))
-			continue;
-
-		pnode = uv_blade_to_pnode(uvhub);
-		mmr_image =
-		    uv_read_global_mmr64(pnode, UVH_LB_BAU_MISC_CONTROL);
-		/*
-		 * Set the timeout period and then lock it in, in three
-		 * steps; captures and locks in the period.
-		 *
-		 * To program the period, the SOFT_ACK_MODE must be off.
-		 */
-		mmr_image &= ~((unsigned long)1 <<
-		    UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
-		uv_write_global_mmr64
-		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
-		/*
-		 * Set the 4-bit period.
-		 */
-		mmr_image &= ~((unsigned long)0xf <<
-		     UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
-		mmr_image |= (UV_INTD_SOFT_ACK_TIMEOUT_PERIOD <<
-		     UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
-		uv_write_global_mmr64
-		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
-		/*
-		 * Subsequent reversals of the timebase bit (3) cause an
-		 * immediate timeout of one or all INTD resources as
-		 * indicated in bits 2:0 (7 causes all of them to timeout).
-		 */
-		mmr_image |= ((unsigned long)1 <<
-		    UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
-		uv_write_global_mmr64
-		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
-	}
-}
-
-static void *uv_ptc_seq_start(struct seq_file *file, loff_t *offset)
-{
-	if (*offset < num_possible_cpus())
-		return offset;
-	return NULL;
-}
-
-static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
-{
-	(*offset)++;
-	if (*offset < num_possible_cpus())
-		return offset;
-	return NULL;
-}
-
-static void uv_ptc_seq_stop(struct seq_file *file, void *data)
-{
-}
-
-static inline unsigned long long
-microsec_2_cycles(unsigned long microsec)
-{
-	unsigned long ns;
-	unsigned long long cyc;
-
-	ns = microsec * 1000;
-	cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
-	return cyc;
-}
-
-/*
- * Display the statistics thru /proc.
- * 'data' points to the cpu number
- */
-static int uv_ptc_seq_show(struct seq_file *file, void *data)
-{
-	struct ptc_stats *stat;
-	int cpu;
-
-	cpu = *(loff_t *)data;
-
-	if (!cpu) {
-		seq_printf(file,
-			"# cpu sent stime self locals remotes ncpus localhub ");
-		seq_printf(file,
-			"remotehub numuvhubs numuvhubs16 numuvhubs8 ");
-		seq_printf(file,
-			"numuvhubs4 numuvhubs2 numuvhubs1 dto ");
-		seq_printf(file,
-			"retries rok resetp resett giveup sto bz throt ");
-		seq_printf(file,
-			"sw_ack recv rtime all ");
-		seq_printf(file,
-			"one mult none retry canc nocan reset rcan ");
-		seq_printf(file,
-			"disable enable\n");
-	}
-	if (cpu < num_possible_cpus() && cpu_online(cpu)) {
-		stat = &per_cpu(ptcstats, cpu);
-		/* source side statistics */
-		seq_printf(file,
-			"cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-			   cpu, stat->s_requestor, cycles_2_us(stat->s_time),
-			   stat->s_ntargself, stat->s_ntarglocals,
-			   stat->s_ntargremotes, stat->s_ntargcpu,
-			   stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
-			   stat->s_ntarguvhub, stat->s_ntarguvhub16);
-		seq_printf(file, "%ld %ld %ld %ld %ld ",
-			   stat->s_ntarguvhub8, stat->s_ntarguvhub4,
-			   stat->s_ntarguvhub2, stat->s_ntarguvhub1,
-			   stat->s_dtimeout);
-		seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ",
-			   stat->s_retry_messages, stat->s_retriesok,
-			   stat->s_resets_plug, stat->s_resets_timeout,
-			   stat->s_giveup, stat->s_stimeout,
-			   stat->s_busy, stat->s_throttles);
-
-		/* destination side statistics */
-		seq_printf(file,
-			   "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
-			   uv_read_global_mmr64(uv_cpu_to_pnode(cpu),
-					UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE),
-			   stat->d_requestee, cycles_2_us(stat->d_time),
-			   stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
-			   stat->d_nomsg, stat->d_retries, stat->d_canceled,
-			   stat->d_nocanceled, stat->d_resets,
-			   stat->d_rcanceled);
-		seq_printf(file, "%ld %ld\n",
-			stat->s_bau_disabled, stat->s_bau_reenabled);
-	}
-
-	return 0;
-}
-
-/*
- * Display the tunables thru debugfs
- */
-static ssize_t tunables_read(struct file *file, char __user *userbuf,
-						size_t count, loff_t *ppos)
-{
-	char buf[300];
-	int ret;
-
-	ret = snprintf(buf, 300, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
-		"max_bau_concurrent plugged_delay plugsb4reset",
-		"timeoutsb4reset ipi_reset_limit complete_threshold",
-		"congested_response_us congested_reps congested_period",
-		max_bau_concurrent, plugged_delay, plugsb4reset,
-		timeoutsb4reset, ipi_reset_limit, complete_threshold,
-		congested_response_us, congested_reps, congested_period);
-
-	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-/*
- * -1: resetf the statistics
- *  0: display meaning of the statistics
- */
-static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
-				 size_t count, loff_t *data)
-{
-	int cpu;
-	long input_arg;
-	char optstr[64];
-	struct ptc_stats *stat;
-
-	if (count == 0 || count > sizeof(optstr))
-		return -EINVAL;
-	if (copy_from_user(optstr, user, count))
-		return -EFAULT;
-	optstr[count - 1] = '\0';
-	if (strict_strtol(optstr, 10, &input_arg) < 0) {
-		printk(KERN_DEBUG "%s is invalid\n", optstr);
-		return -EINVAL;
-	}
-
-	if (input_arg == 0) {
-		printk(KERN_DEBUG "# cpu:      cpu number\n");
-		printk(KERN_DEBUG "Sender statistics:\n");
-		printk(KERN_DEBUG
-		"sent:     number of shootdown messages sent\n");
-		printk(KERN_DEBUG
-		"stime:    time spent sending messages\n");
-		printk(KERN_DEBUG
-		"numuvhubs: number of hubs targeted with shootdown\n");
-		printk(KERN_DEBUG
-		"numuvhubs16: number times 16 or more hubs targeted\n");
-		printk(KERN_DEBUG
-		"numuvhubs8: number times 8 or more hubs targeted\n");
-		printk(KERN_DEBUG
-		"numuvhubs4: number times 4 or more hubs targeted\n");
-		printk(KERN_DEBUG
-		"numuvhubs2: number times 2 or more hubs targeted\n");
-		printk(KERN_DEBUG
-		"numuvhubs1: number times 1 hub targeted\n");
-		printk(KERN_DEBUG
-		"numcpus:  number of cpus targeted with shootdown\n");
-		printk(KERN_DEBUG
-		"dto:      number of destination timeouts\n");
-		printk(KERN_DEBUG
-		"retries:  destination timeout retries sent\n");
-		printk(KERN_DEBUG
-		"rok:   :  destination timeouts successfully retried\n");
-		printk(KERN_DEBUG
-		"resetp:   ipi-style resource resets for plugs\n");
-		printk(KERN_DEBUG
-		"resett:   ipi-style resource resets for timeouts\n");
-		printk(KERN_DEBUG
-		"giveup:   fall-backs to ipi-style shootdowns\n");
-		printk(KERN_DEBUG
-		"sto:      number of source timeouts\n");
-		printk(KERN_DEBUG
-		"bz:       number of stay-busy's\n");
-		printk(KERN_DEBUG
-		"throt:    number times spun in throttle\n");
-		printk(KERN_DEBUG "Destination side statistics:\n");
-		printk(KERN_DEBUG
-		"sw_ack:   image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE\n");
-		printk(KERN_DEBUG
-		"recv:     shootdown messages received\n");
-		printk(KERN_DEBUG
-		"rtime:    time spent processing messages\n");
-		printk(KERN_DEBUG
-		"all:      shootdown all-tlb messages\n");
-		printk(KERN_DEBUG
-		"one:      shootdown one-tlb messages\n");
-		printk(KERN_DEBUG
-		"mult:     interrupts that found multiple messages\n");
-		printk(KERN_DEBUG
-		"none:     interrupts that found no messages\n");
-		printk(KERN_DEBUG
-		"retry:    number of retry messages processed\n");
-		printk(KERN_DEBUG
-		"canc:     number messages canceled by retries\n");
-		printk(KERN_DEBUG
-		"nocan:    number retries that found nothing to cancel\n");
-		printk(KERN_DEBUG
-		"reset:    number of ipi-style reset requests processed\n");
-		printk(KERN_DEBUG
-		"rcan:     number messages canceled by reset requests\n");
-		printk(KERN_DEBUG
-		"disable:  number times use of the BAU was disabled\n");
-		printk(KERN_DEBUG
-		"enable:   number times use of the BAU was re-enabled\n");
-	} else if (input_arg == -1) {
-		for_each_present_cpu(cpu) {
-			stat = &per_cpu(ptcstats, cpu);
-			memset(stat, 0, sizeof(struct ptc_stats));
-		}
-	}
-
-	return count;
-}
-
-static int local_atoi(const char *name)
-{
-	int val = 0;
-
-	for (;; name++) {
-		switch (*name) {
-		case '0' ... '9':
-			val = 10*val+(*name-'0');
-			break;
-		default:
-			return val;
-		}
-	}
-}
-
-/*
- * set the tunables
- * 0 values reset them to defaults
- */
-static ssize_t tunables_write(struct file *file, const char __user *user,
-				 size_t count, loff_t *data)
-{
-	int cpu;
-	int cnt = 0;
-	int val;
-	char *p;
-	char *q;
-	char instr[64];
-	struct bau_control *bcp;
-
-	if (count == 0 || count > sizeof(instr)-1)
-		return -EINVAL;
-	if (copy_from_user(instr, user, count))
-		return -EFAULT;
-
-	instr[count] = '\0';
-	/* count the fields */
-	p = instr + strspn(instr, WHITESPACE);
-	q = p;
-	for (; *p; p = q + strspn(q, WHITESPACE)) {
-		q = p + strcspn(p, WHITESPACE);
-		cnt++;
-		if (q == p)
-			break;
-	}
-	if (cnt != 9) {
-		printk(KERN_INFO "bau tunable error: should be 9 numbers\n");
-		return -EINVAL;
-	}
-
-	p = instr + strspn(instr, WHITESPACE);
-	q = p;
-	for (cnt = 0; *p; p = q + strspn(q, WHITESPACE), cnt++) {
-		q = p + strcspn(p, WHITESPACE);
-		val = local_atoi(p);
-		switch (cnt) {
-		case 0:
-			if (val == 0) {
-				max_bau_concurrent = MAX_BAU_CONCURRENT;
-				max_bau_concurrent_constant =
-							MAX_BAU_CONCURRENT;
-				continue;
-			}
-			bcp = &per_cpu(bau_control, smp_processor_id());
-			if (val < 1 || val > bcp->cpus_in_uvhub) {
-				printk(KERN_DEBUG
-				"Error: BAU max concurrent %d is invalid\n",
-				val);
-				return -EINVAL;
-			}
-			max_bau_concurrent = val;
-			max_bau_concurrent_constant = val;
-			continue;
-		case 1:
-			if (val == 0)
-				plugged_delay = PLUGGED_DELAY;
-			else
-				plugged_delay = val;
-			continue;
-		case 2:
-			if (val == 0)
-				plugsb4reset = PLUGSB4RESET;
-			else
-				plugsb4reset = val;
-			continue;
-		case 3:
-			if (val == 0)
-				timeoutsb4reset = TIMEOUTSB4RESET;
-			else
-				timeoutsb4reset = val;
-			continue;
-		case 4:
-			if (val == 0)
-				ipi_reset_limit = IPI_RESET_LIMIT;
-			else
-				ipi_reset_limit = val;
-			continue;
-		case 5:
-			if (val == 0)
-				complete_threshold = COMPLETE_THRESHOLD;
-			else
-				complete_threshold = val;
-			continue;
-		case 6:
-			if (val == 0)
-				congested_response_us = CONGESTED_RESPONSE_US;
-			else
-				congested_response_us = val;
-			continue;
-		case 7:
-			if (val == 0)
-				congested_reps = CONGESTED_REPS;
-			else
-				congested_reps = val;
-			continue;
-		case 8:
-			if (val == 0)
-				congested_period = CONGESTED_PERIOD;
-			else
-				congested_period = val;
-			continue;
-		}
-		if (q == p)
-			break;
-	}
-	for_each_present_cpu(cpu) {
-		bcp = &per_cpu(bau_control, cpu);
-		bcp->max_bau_concurrent = max_bau_concurrent;
-		bcp->max_bau_concurrent_constant = max_bau_concurrent;
-		bcp->plugged_delay = plugged_delay;
-		bcp->plugsb4reset = plugsb4reset;
-		bcp->timeoutsb4reset = timeoutsb4reset;
-		bcp->ipi_reset_limit = ipi_reset_limit;
-		bcp->complete_threshold = complete_threshold;
-		bcp->congested_response_us = congested_response_us;
-		bcp->congested_reps = congested_reps;
-		bcp->congested_period = congested_period;
-	}
-	return count;
-}
-
-static const struct seq_operations uv_ptc_seq_ops = {
-	.start		= uv_ptc_seq_start,
-	.next		= uv_ptc_seq_next,
-	.stop		= uv_ptc_seq_stop,
-	.show		= uv_ptc_seq_show
-};
-
-static int uv_ptc_proc_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &uv_ptc_seq_ops);
-}
-
-static int tunables_open(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static const struct file_operations proc_uv_ptc_operations = {
-	.open		= uv_ptc_proc_open,
-	.read		= seq_read,
-	.write		= uv_ptc_proc_write,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-static const struct file_operations tunables_fops = {
-	.open		= tunables_open,
-	.read		= tunables_read,
-	.write		= tunables_write,
-};
-
-static int __init uv_ptc_init(void)
-{
-	struct proc_dir_entry *proc_uv_ptc;
-
-	if (!is_uv_system())
-		return 0;
-
-	proc_uv_ptc = proc_create(UV_PTC_BASENAME, 0444, NULL,
-				  &proc_uv_ptc_operations);
-	if (!proc_uv_ptc) {
-		printk(KERN_ERR "unable to create %s proc entry\n",
-		       UV_PTC_BASENAME);
-		return -EINVAL;
-	}
-
-	tunables_dir = debugfs_create_dir(UV_BAU_TUNABLES_DIR, NULL);
-	if (!tunables_dir) {
-		printk(KERN_ERR "unable to create debugfs directory %s\n",
-		       UV_BAU_TUNABLES_DIR);
-		return -EINVAL;
-	}
-	tunables_file = debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600,
-			tunables_dir, NULL, &tunables_fops);
-	if (!tunables_file) {
-		printk(KERN_ERR "unable to create debugfs file %s\n",
-		       UV_BAU_TUNABLES_FILE);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-/*
- * initialize the sending side's sending buffers
- */
-static void
-uv_activation_descriptor_init(int node, int pnode)
-{
-	int i;
-	int cpu;
-	unsigned long pa;
-	unsigned long m;
-	unsigned long n;
-	struct bau_desc *bau_desc;
-	struct bau_desc *bd2;
-	struct bau_control *bcp;
-
-	/*
-	 * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR)
-	 * per cpu; and up to 32 (UV_ADP_SIZE) cpu's per uvhub
-	 */
-	bau_desc = (struct bau_desc *)kmalloc_node(sizeof(struct bau_desc)*
-		UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
-	BUG_ON(!bau_desc);
-
-	pa = uv_gpa(bau_desc); /* need the real nasid*/
-	n = pa >> uv_nshift;
-	m = pa & uv_mmask;
-
-	uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
-			      (n << UV_DESC_BASE_PNODE_SHIFT | m));
-
-	/*
-	 * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
-	 * cpu even though we only use the first one; one descriptor can
-	 * describe a broadcast to 256 uv hubs.
-	 */
-	for (i = 0, bd2 = bau_desc; i < (UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR);
-		i++, bd2++) {
-		memset(bd2, 0, sizeof(struct bau_desc));
-		bd2->header.sw_ack_flag = 1;
-		/*
-		 * base_dest_nodeid is the nasid (pnode<<1) of the first uvhub
-		 * in the partition. The bit map will indicate uvhub numbers,
-		 * which are 0-N in a partition. Pnodes are unique system-wide.
-		 */
-		bd2->header.base_dest_nodeid = uv_partition_base_pnode << 1;
-		bd2->header.dest_subnodeid = 0x10; /* the LB */
-		bd2->header.command = UV_NET_ENDPOINT_INTD;
-		bd2->header.int_both = 1;
-		/*
-		 * all others need to be set to zero:
-		 *   fairness chaining multilevel count replied_to
-		 */
-	}
-	for_each_present_cpu(cpu) {
-		if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu)))
-			continue;
-		bcp = &per_cpu(bau_control, cpu);
-		bcp->descriptor_base = bau_desc;
-	}
-}
-
-/*
- * initialize the destination side's receiving buffers
- * entered for each uvhub in the partition
- * - node is first node (kernel memory notion) on the uvhub
- * - pnode is the uvhub's physical identifier
- */
-static void
-uv_payload_queue_init(int node, int pnode)
-{
-	int pn;
-	int cpu;
-	char *cp;
-	unsigned long pa;
-	struct bau_payload_queue_entry *pqp;
-	struct bau_payload_queue_entry *pqp_malloc;
-	struct bau_control *bcp;
-
-	pqp = (struct bau_payload_queue_entry *) kmalloc_node(
-		(DEST_Q_SIZE + 1) * sizeof(struct bau_payload_queue_entry),
-		GFP_KERNEL, node);
-	BUG_ON(!pqp);
-	pqp_malloc = pqp;
-
-	cp = (char *)pqp + 31;
-	pqp = (struct bau_payload_queue_entry *)(((unsigned long)cp >> 5) << 5);
-
-	for_each_present_cpu(cpu) {
-		if (pnode != uv_cpu_to_pnode(cpu))
-			continue;
-		/* for every cpu on this pnode: */
-		bcp = &per_cpu(bau_control, cpu);
-		bcp->va_queue_first = pqp;
-		bcp->bau_msg_head = pqp;
-		bcp->va_queue_last = pqp + (DEST_Q_SIZE - 1);
-	}
-	/*
-	 * need the pnode of where the memory was really allocated
-	 */
-	pa = uv_gpa(pqp);
-	pn = pa >> uv_nshift;
-	uv_write_global_mmr64(pnode,
-			      UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
-			      ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) |
-			      uv_physnodeaddr(pqp));
-	uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL,
-			      uv_physnodeaddr(pqp));
-	uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST,
-			      (unsigned long)
-			      uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1)));
-	/* in effect, all msg_type's are set to MSG_NOOP */
-	memset(pqp, 0, sizeof(struct bau_payload_queue_entry) * DEST_Q_SIZE);
-}
-
-/*
- * Initialization of each UV hub's structures
- */
-static void __init uv_init_uvhub(int uvhub, int vector)
-{
-	int node;
-	int pnode;
-	unsigned long apicid;
-
-	node = uvhub_to_first_node(uvhub);
-	pnode = uv_blade_to_pnode(uvhub);
-	uv_activation_descriptor_init(node, pnode);
-	uv_payload_queue_init(node, pnode);
-	/*
-	 * the below initialization can't be in firmware because the
-	 * messaging IRQ will be determined by the OS
-	 */
-	apicid = uvhub_to_first_apicid(uvhub);
-	uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
-				      ((apicid << 32) | vector));
-}
-
-/*
- * We will set BAU_MISC_CONTROL with a timeout period.
- * But the BIOS has set UVH_AGING_PRESCALE_SEL and UVH_TRANSACTION_TIMEOUT.
- * So the destination timeout period has be be calculated from them.
- */
-static int
-calculate_destination_timeout(void)
-{
-	unsigned long mmr_image;
-	int mult1;
-	int mult2;
-	int index;
-	int base;
-	int ret;
-	unsigned long ts_ns;
-
-	mult1 = UV_INTD_SOFT_ACK_TIMEOUT_PERIOD & BAU_MISC_CONTROL_MULT_MASK;
-	mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
-	index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
-	mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
-	mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
-	base = timeout_base_ns[index];
-	ts_ns = base * mult1 * mult2;
-	ret = ts_ns / 1000;
-	return ret;
-}
-
-/*
- * initialize the bau_control structure for each cpu
- */
-static void __init uv_init_per_cpu(int nuvhubs)
-{
-	int i;
-	int cpu;
-	int pnode;
-	int uvhub;
-	int have_hmaster;
-	short socket = 0;
-	unsigned short socket_mask;
-	unsigned char *uvhub_mask;
-	struct bau_control *bcp;
-	struct uvhub_desc *bdp;
-	struct socket_desc *sdp;
-	struct bau_control *hmaster = NULL;
-	struct bau_control *smaster = NULL;
-	struct socket_desc {
-		short num_cpus;
-		short cpu_number[16];
-	};
-	struct uvhub_desc {
-		unsigned short socket_mask;
-		short num_cpus;
-		short uvhub;
-		short pnode;
-		struct socket_desc socket[2];
-	};
-	struct uvhub_desc *uvhub_descs;
-
-	timeout_us = calculate_destination_timeout();
-
-	uvhub_descs = (struct uvhub_desc *)
-		kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
-	memset(uvhub_descs, 0, nuvhubs * sizeof(struct uvhub_desc));
-	uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
-	for_each_present_cpu(cpu) {
-		bcp = &per_cpu(bau_control, cpu);
-		memset(bcp, 0, sizeof(struct bau_control));
-		pnode = uv_cpu_hub_info(cpu)->pnode;
-		uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
-		*(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8));
-		bdp = &uvhub_descs[uvhub];
-		bdp->num_cpus++;
-		bdp->uvhub = uvhub;
-		bdp->pnode = pnode;
-		/* kludge: 'assuming' one node per socket, and assuming that
-		   disabling a socket just leaves a gap in node numbers */
-		socket = (cpu_to_node(cpu) & 1);
-		bdp->socket_mask |= (1 << socket);
-		sdp = &bdp->socket[socket];
-		sdp->cpu_number[sdp->num_cpus] = cpu;
-		sdp->num_cpus++;
-	}
-	for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
-		if (!(*(uvhub_mask + (uvhub/8)) & (1 << (uvhub%8))))
-			continue;
-		have_hmaster = 0;
-		bdp = &uvhub_descs[uvhub];
-		socket_mask = bdp->socket_mask;
-		socket = 0;
-		while (socket_mask) {
-			if (!(socket_mask & 1))
-				goto nextsocket;
-			sdp = &bdp->socket[socket];
-			for (i = 0; i < sdp->num_cpus; i++) {
-				cpu = sdp->cpu_number[i];
-				bcp = &per_cpu(bau_control, cpu);
-				bcp->cpu = cpu;
-				if (i == 0) {
-					smaster = bcp;
-					if (!have_hmaster) {
-						have_hmaster++;
-						hmaster = bcp;
-					}
-				}
-				bcp->cpus_in_uvhub = bdp->num_cpus;
-				bcp->cpus_in_socket = sdp->num_cpus;
-				bcp->socket_master = smaster;
-				bcp->uvhub = bdp->uvhub;
-				bcp->uvhub_master = hmaster;
-				bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->
-						blade_processor_id;
-			}
-nextsocket:
-			socket++;
-			socket_mask = (socket_mask >> 1);
-		}
-	}
-	kfree(uvhub_descs);
-	kfree(uvhub_mask);
-	for_each_present_cpu(cpu) {
-		bcp = &per_cpu(bau_control, cpu);
-		bcp->baudisabled = 0;
-		bcp->statp = &per_cpu(ptcstats, cpu);
-		/* time interval to catch a hardware stay-busy bug */
-		bcp->timeout_interval = microsec_2_cycles(2*timeout_us);
-		bcp->max_bau_concurrent = max_bau_concurrent;
-		bcp->max_bau_concurrent_constant = max_bau_concurrent;
-		bcp->plugged_delay = plugged_delay;
-		bcp->plugsb4reset = plugsb4reset;
-		bcp->timeoutsb4reset = timeoutsb4reset;
-		bcp->ipi_reset_limit = ipi_reset_limit;
-		bcp->complete_threshold = complete_threshold;
-		bcp->congested_response_us = congested_response_us;
-		bcp->congested_reps = congested_reps;
-		bcp->congested_period = congested_period;
-	}
-}
-
-/*
- * Initialization of BAU-related structures
- */
-static int __init uv_bau_init(void)
-{
-	int uvhub;
-	int pnode;
-	int nuvhubs;
-	int cur_cpu;
-	int vector;
-	unsigned long mmr;
-
-	if (!is_uv_system())
-		return 0;
-
-	if (nobau)
-		return 0;
-
-	for_each_possible_cpu(cur_cpu)
-		zalloc_cpumask_var_node(&per_cpu(uv_flush_tlb_mask, cur_cpu),
-				       GFP_KERNEL, cpu_to_node(cur_cpu));
-
-	uv_nshift = uv_hub_info->m_val;
-	uv_mmask = (1UL << uv_hub_info->m_val) - 1;
-	nuvhubs = uv_num_possible_blades();
-	spin_lock_init(&disable_lock);
-	congested_cycles = microsec_2_cycles(congested_response_us);
-
-	uv_init_per_cpu(nuvhubs);
-
-	uv_partition_base_pnode = 0x7fffffff;
-	for (uvhub = 0; uvhub < nuvhubs; uvhub++)
-		if (uv_blade_nr_possible_cpus(uvhub) &&
-			(uv_blade_to_pnode(uvhub) < uv_partition_base_pnode))
-			uv_partition_base_pnode = uv_blade_to_pnode(uvhub);
-
-	vector = UV_BAU_MESSAGE;
-	for_each_possible_blade(uvhub)
-		if (uv_blade_nr_possible_cpus(uvhub))
-			uv_init_uvhub(uvhub, vector);
-
-	uv_enable_timeouts();
-	alloc_intr_gate(vector, uv_bau_message_intr1);
-
-	for_each_possible_blade(uvhub) {
-		if (uv_blade_nr_possible_cpus(uvhub)) {
-			pnode = uv_blade_to_pnode(uvhub);
-			/* INIT the bau */
-			uv_write_global_mmr64(pnode,
-					UVH_LB_BAU_SB_ACTIVATION_CONTROL,
-					((unsigned long)1 << 63));
-			mmr = 1; /* should be 1 to broadcast to both sockets */
-			uv_write_global_mmr64(pnode, UVH_BAU_DATA_BROADCAST,
-						mmr);
-		}
-	}
-
-	return 0;
-}
-core_initcall(uv_bau_init);
-fs_initcall(uv_ptc_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/trampoline.c linux-libre-2.6.37-gnu/arch/x86/kernel/trampoline.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/trampoline.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/trampoline.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/trampoline.h>
 #include <asm/pgtable.h>
-#include <asm/e820.h>
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP)
 #define __trampinit
@@ -17,15 +17,15 @@
 
 void __init reserve_trampoline_memory(void)
 {
-	unsigned long mem;
+	phys_addr_t mem;
 
 	/* Has to be in very low memory so we can execute real-mode AP code. */
-	mem = find_e820_area(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
-	if (mem == -1L)
+	mem = memblock_find_in_range(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
+	if (mem == MEMBLOCK_ERROR)
 		panic("Cannot allocate trampoline\n");
 
 	trampoline_base = __va(mem);
-	reserve_early(mem, mem + TRAMPOLINE_SIZE, "TRAMPOLINE");
+	memblock_x86_reserve_range(mem, mem + TRAMPOLINE_SIZE, "TRAMPOLINE");
 }
 
 /*
@@ -38,19 +38,3 @@
 	memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE);
 	return virt_to_phys(trampoline_base);
 }
-
-void __init setup_trampoline_page_table(void)
-{
-#ifdef CONFIG_X86_32
-	/* Copy kernel address range */
-	clone_pgd_range(trampoline_pg_dir + KERNEL_PGD_BOUNDARY,
-			swapper_pg_dir + KERNEL_PGD_BOUNDARY,
-			KERNEL_PGD_PTRS);
-
-	/* Initialize low mappings */
-	clone_pgd_range(trampoline_pg_dir,
-			swapper_pg_dir + KERNEL_PGD_BOUNDARY,
-			min_t(unsigned long, KERNEL_PGD_PTRS,
-			      KERNEL_PGD_BOUNDARY));
-#endif
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/traps.c linux-libre-2.6.37-gnu/arch/x86/kernel/traps.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/traps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/traps.c	2011-01-04 19:50:19.000000000 -0500
@@ -575,6 +575,7 @@
 	if (regs->flags & X86_VM_MASK) {
 		handle_vm86_trap((struct kernel_vm86_regs *) regs,
 				error_code, 1);
+		preempt_conditional_cli(regs);
 		return;
 	}
 
@@ -776,21 +777,10 @@
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
-#ifndef CONFIG_MATH_EMULATION
-void math_emulate(struct math_emu_info *info)
-{
-	printk(KERN_EMERG
-		"math-emulation not enabled and no coprocessor found.\n");
-	printk(KERN_EMERG "killing %s.\n", current->comm);
-	force_sig(SIGFPE, current);
-	schedule();
-}
-#endif /* CONFIG_MATH_EMULATION */
-
 dotraplinkage void __kprobes
 do_device_not_available(struct pt_regs *regs, long error_code)
 {
-#ifdef CONFIG_X86_32
+#ifdef CONFIG_MATH_EMULATION
 	if (read_cr0() & X86_CR0_EM) {
 		struct math_emu_info info = { };
 
@@ -798,12 +788,12 @@
 
 		info.regs = regs;
 		math_emulate(&info);
-	} else {
-		math_state_restore(); /* interrupts still off */
-		conditional_sti(regs);
+		return;
 	}
-#else
-	math_state_restore();
+#endif
+	math_state_restore(); /* interrupts still off */
+#ifdef CONFIG_X86_32
+	conditional_sti(regs);
 #endif
 }
 
@@ -881,18 +871,6 @@
 #endif
 
 #ifdef CONFIG_X86_32
-	if (cpu_has_fxsr) {
-		printk(KERN_INFO "Enabling fast FPU save and restore... ");
-		set_in_cr4(X86_CR4_OSFXSR);
-		printk("done.\n");
-	}
-	if (cpu_has_xmm) {
-		printk(KERN_INFO
-			"Enabling unmasked SIMD FPU exception support... ");
-		set_in_cr4(X86_CR4_OSXMMEXCPT);
-		printk("done.\n");
-	}
-
 	set_system_trap_gate(SYSCALL_VECTOR, &system_call);
 	set_bit(SYSCALL_VECTOR, used_vectors);
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/tsc.c linux-libre-2.6.37-gnu/arch/x86/kernel/tsc.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/tsc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/tsc.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,10 +104,14 @@
 
 __setup("notsc", notsc_setup);
 
+static int no_sched_irq_time;
+
 static int __init tsc_setup(char *str)
 {
 	if (!strcmp(str, "reliable"))
 		tsc_clocksource_reliable = 1;
+	if (!strncmp(str, "noirqtime", 9))
+		no_sched_irq_time = 1;
 	return 1;
 }
 
@@ -801,6 +805,7 @@
 	if (!tsc_unstable) {
 		tsc_unstable = 1;
 		sched_clock_stable = 0;
+		disable_sched_clock_irqtime();
 		printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
 		/* Change only the rating, when not registered */
 		if (clocksource_tsc.mult)
@@ -892,60 +897,6 @@
 	clocksource_register_khz(&clocksource_tsc, tsc_khz);
 }
 
-#ifdef CONFIG_X86_64
-/*
- * calibrate_cpu is used on systems with fixed rate TSCs to determine
- * processor frequency
- */
-#define TICK_COUNT 100000000
-static unsigned long __init calibrate_cpu(void)
-{
-	int tsc_start, tsc_now;
-	int i, no_ctr_free;
-	unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
-	unsigned long flags;
-
-	for (i = 0; i < 4; i++)
-		if (avail_to_resrv_perfctr_nmi_bit(i))
-			break;
-	no_ctr_free = (i == 4);
-	if (no_ctr_free) {
-		WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... "
-		     "cpu_khz value may be incorrect.\n");
-		i = 3;
-		rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
-		wrmsrl(MSR_K7_EVNTSEL3, 0);
-		rdmsrl(MSR_K7_PERFCTR3, pmc3);
-	} else {
-		reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-		reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-	}
-	local_irq_save(flags);
-	/* start measuring cycles, incrementing from 0 */
-	wrmsrl(MSR_K7_PERFCTR0 + i, 0);
-	wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
-	rdtscl(tsc_start);
-	do {
-		rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
-		tsc_now = get_cycles();
-	} while ((tsc_now - tsc_start) < TICK_COUNT);
-
-	local_irq_restore(flags);
-	if (no_ctr_free) {
-		wrmsrl(MSR_K7_EVNTSEL3, 0);
-		wrmsrl(MSR_K7_PERFCTR3, pmc3);
-		wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
-	} else {
-		release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-		release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-	}
-
-	return pmc_now * tsc_khz / (tsc_now - tsc_start);
-}
-#else
-static inline unsigned long calibrate_cpu(void) { return cpu_khz; }
-#endif
-
 void __init tsc_init(void)
 {
 	u64 lpj;
@@ -964,10 +915,6 @@
 		return;
 	}
 
-	if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
-			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD))
-		cpu_khz = calibrate_cpu();
-
 	printk("Detected %lu.%03lu MHz processor.\n",
 			(unsigned long)cpu_khz / 1000,
 			(unsigned long)cpu_khz % 1000);
@@ -987,6 +934,9 @@
 	/* now allow native_sched_clock() to use rdtsc */
 	tsc_disabled = 0;
 
+	if (!no_sched_irq_time)
+		enable_sched_clock_irqtime();
+
 	lpj = ((u64)tsc_khz * 1000);
 	do_div(lpj, HZ);
 	lpj_fine = lpj;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/uv_irq.c linux-libre-2.6.37-gnu/arch/x86/kernel/uv_irq.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/uv_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/uv_irq.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,302 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * SGI UV IRQ functions
- *
- * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/module.h>
-#include <linux/rbtree.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <asm/apic.h>
-#include <asm/uv/uv_irq.h>
-#include <asm/uv/uv_hub.h>
-
-/* MMR offset and pnode of hub sourcing interrupts for a given irq */
-struct uv_irq_2_mmr_pnode{
-	struct rb_node		list;
-	unsigned long		offset;
-	int			pnode;
-	int			irq;
-};
-
-static spinlock_t		uv_irq_lock;
-static struct rb_root		uv_irq_root;
-
-static int uv_set_irq_affinity(unsigned int, const struct cpumask *);
-
-static void uv_noop(unsigned int irq)
-{
-}
-
-static unsigned int uv_noop_ret(unsigned int irq)
-{
-	return 0;
-}
-
-static void uv_ack_apic(unsigned int irq)
-{
-	ack_APIC_irq();
-}
-
-static struct irq_chip uv_irq_chip = {
-	.name		= "UV-CORE",
-	.startup	= uv_noop_ret,
-	.shutdown	= uv_noop,
-	.enable		= uv_noop,
-	.disable	= uv_noop,
-	.ack		= uv_noop,
-	.mask		= uv_noop,
-	.unmask		= uv_noop,
-	.eoi		= uv_ack_apic,
-	.end		= uv_noop,
-	.set_affinity	= uv_set_irq_affinity,
-};
-
-/*
- * Add offset and pnode information of the hub sourcing interrupts to the
- * rb tree for a specific irq.
- */
-static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
-{
-	struct rb_node **link = &uv_irq_root.rb_node;
-	struct rb_node *parent = NULL;
-	struct uv_irq_2_mmr_pnode *n;
-	struct uv_irq_2_mmr_pnode *e;
-	unsigned long irqflags;
-
-	n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
-				uv_blade_to_memory_nid(blade));
-	if (!n)
-		return -ENOMEM;
-
-	n->irq = irq;
-	n->offset = offset;
-	n->pnode = uv_blade_to_pnode(blade);
-	spin_lock_irqsave(&uv_irq_lock, irqflags);
-	/* Find the right place in the rbtree: */
-	while (*link) {
-		parent = *link;
-		e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
-
-		if (unlikely(irq == e->irq)) {
-			/* irq entry exists */
-			e->pnode = uv_blade_to_pnode(blade);
-			e->offset = offset;
-			spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-			kfree(n);
-			return 0;
-		}
-
-		if (irq < e->irq)
-			link = &(*link)->rb_left;
-		else
-			link = &(*link)->rb_right;
-	}
-
-	/* Insert the node into the rbtree. */
-	rb_link_node(&n->list, parent, link);
-	rb_insert_color(&n->list, &uv_irq_root);
-
-	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-	return 0;
-}
-
-/* Retrieve offset and pnode information from the rb tree for a specific irq */
-int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
-{
-	struct uv_irq_2_mmr_pnode *e;
-	struct rb_node *n;
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&uv_irq_lock, irqflags);
-	n = uv_irq_root.rb_node;
-	while (n) {
-		e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
-
-		if (e->irq == irq) {
-			*offset = e->offset;
-			*pnode = e->pnode;
-			spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-			return 0;
-		}
-
-		if (irq < e->irq)
-			n = n->rb_left;
-		else
-			n = n->rb_right;
-	}
-	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-	return -1;
-}
-
-/*
- * Re-target the irq to the specified CPU and enable the specified MMR located
- * on the specified blade to allow the sending of MSIs to the specified CPU.
- */
-static int
-arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
-		       unsigned long mmr_offset, int limit)
-{
-	const struct cpumask *eligible_cpu = cpumask_of(cpu);
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg;
-	int mmr_pnode;
-	unsigned long mmr_value;
-	struct uv_IO_APIC_route_entry *entry;
-	int err;
-
-	BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
-			sizeof(unsigned long));
-
-	cfg = irq_cfg(irq);
-
-	err = assign_irq_vector(irq, cfg, eligible_cpu);
-	if (err != 0)
-		return err;
-
-	if (limit == UV_AFFINITY_CPU)
-		desc->status |= IRQ_NO_BALANCING;
-	else
-		desc->status |= IRQ_MOVE_PCNTXT;
-
-	set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
-				      irq_name);
-
-	mmr_value = 0;
-	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-	entry->vector		= cfg->vector;
-	entry->delivery_mode	= apic->irq_delivery_mode;
-	entry->dest_mode	= apic->irq_dest_mode;
-	entry->polarity		= 0;
-	entry->trigger		= 0;
-	entry->mask		= 0;
-	entry->dest		= apic->cpu_mask_to_apicid(eligible_cpu);
-
-	mmr_pnode = uv_blade_to_pnode(mmr_blade);
-	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
-	if (cfg->move_in_progress)
-		send_cleanup_vector(cfg);
-
-	return irq;
-}
-
-/*
- * Disable the specified MMR located on the specified blade so that MSIs are
- * longer allowed to be sent.
- */
-static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
-{
-	unsigned long mmr_value;
-	struct uv_IO_APIC_route_entry *entry;
-
-	BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
-			sizeof(unsigned long));
-
-	mmr_value = 0;
-	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-	entry->mask = 1;
-
-	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-}
-
-static int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
-{
-	struct irq_desc *desc = irq_to_desc(irq);
-	struct irq_cfg *cfg = desc->chip_data;
-	unsigned int dest;
-	unsigned long mmr_value;
-	struct uv_IO_APIC_route_entry *entry;
-	unsigned long mmr_offset;
-	int mmr_pnode;
-
-	if (set_desc_affinity(desc, mask, &dest))
-		return -1;
-
-	mmr_value = 0;
-	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-
-	entry->vector		= cfg->vector;
-	entry->delivery_mode	= apic->irq_delivery_mode;
-	entry->dest_mode	= apic->irq_dest_mode;
-	entry->polarity		= 0;
-	entry->trigger		= 0;
-	entry->mask		= 0;
-	entry->dest		= dest;
-
-	/* Get previously stored MMR and pnode of hub sourcing interrupts */
-	if (uv_irq_2_mmr_info(irq, &mmr_offset, &mmr_pnode))
-		return -1;
-
-	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
-	if (cfg->move_in_progress)
-		send_cleanup_vector(cfg);
-
-	return 0;
-}
-
-/*
- * Set up a mapping of an available irq and vector, and enable the specified
- * MMR that defines the MSI that is to be sent to the specified CPU when an
- * interrupt is raised.
- */
-int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
-		 unsigned long mmr_offset, int limit)
-{
-	int irq, ret;
-
-	irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade));
-
-	if (irq <= 0)
-		return -EBUSY;
-
-	ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
-		limit);
-	if (ret == irq)
-		uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
-	else
-		destroy_irq(irq);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(uv_setup_irq);
-
-/*
- * Tear down a mapping of an irq and vector, and disable the specified MMR that
- * defined the MSI that was to be sent to the specified CPU when an interrupt
- * was raised.
- *
- * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
- */
-void uv_teardown_irq(unsigned int irq)
-{
-	struct uv_irq_2_mmr_pnode *e;
-	struct rb_node *n;
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&uv_irq_lock, irqflags);
-	n = uv_irq_root.rb_node;
-	while (n) {
-		e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
-		if (e->irq == irq) {
-			arch_disable_uv_irq(e->pnode, e->offset);
-			rb_erase(n, &uv_irq_root);
-			kfree(e);
-			break;
-		}
-		if (irq < e->irq)
-			n = n->rb_left;
-		else
-			n = n->rb_right;
-	}
-	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-	destroy_irq(irq);
-}
-EXPORT_SYMBOL_GPL(uv_teardown_irq);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/uv_sysfs.c linux-libre-2.6.37-gnu/arch/x86/kernel/uv_sysfs.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/uv_sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/uv_sysfs.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,76 +0,0 @@
-/*
- * This file supports the /sys/firmware/sgi_uv interfaces for SGI UV.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Russ Anderson
- */
-
-#include <linux/sysdev.h>
-#include <asm/uv/bios.h>
-#include <asm/uv/uv.h>
-
-struct kobject *sgi_uv_kobj;
-
-static ssize_t partition_id_show(struct kobject *kobj,
-			struct kobj_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%ld\n", sn_partition_id);
-}
-
-static ssize_t coherence_id_show(struct kobject *kobj,
-			struct kobj_attribute *attr, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, "%ld\n", partition_coherence_id());
-}
-
-static struct kobj_attribute partition_id_attr =
-	__ATTR(partition_id, S_IRUGO, partition_id_show, NULL);
-
-static struct kobj_attribute coherence_id_attr =
-	__ATTR(coherence_id, S_IRUGO, coherence_id_show, NULL);
-
-
-static int __init sgi_uv_sysfs_init(void)
-{
-	unsigned long ret;
-
-	if (!is_uv_system())
-		return -ENODEV;
-
-	if (!sgi_uv_kobj)
-		sgi_uv_kobj = kobject_create_and_add("sgi_uv", firmware_kobj);
-	if (!sgi_uv_kobj) {
-		printk(KERN_WARNING "kobject_create_and_add sgi_uv failed\n");
-		return -EINVAL;
-	}
-
-	ret = sysfs_create_file(sgi_uv_kobj, &partition_id_attr.attr);
-	if (ret) {
-		printk(KERN_WARNING "sysfs_create_file partition_id failed\n");
-		return ret;
-	}
-
-	ret = sysfs_create_file(sgi_uv_kobj, &coherence_id_attr.attr);
-	if (ret) {
-		printk(KERN_WARNING "sysfs_create_file coherence_id failed\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-device_initcall(sgi_uv_sysfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/uv_time.c linux-libre-2.6.37-gnu/arch/x86/kernel/uv_time.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/uv_time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/uv_time.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,423 +0,0 @@
-/*
- * SGI RTC clock/timer routines.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- *  Copyright (c) 2009 Silicon Graphics, Inc.  All Rights Reserved.
- *  Copyright (c) Dimitri Sivanich
- */
-#include <linux/clockchips.h>
-#include <linux/slab.h>
-
-#include <asm/uv/uv_mmrs.h>
-#include <asm/uv/uv_hub.h>
-#include <asm/uv/bios.h>
-#include <asm/uv/uv.h>
-#include <asm/apic.h>
-#include <asm/cpu.h>
-
-#define RTC_NAME		"sgi_rtc"
-
-static cycle_t uv_read_rtc(struct clocksource *cs);
-static int uv_rtc_next_event(unsigned long, struct clock_event_device *);
-static void uv_rtc_timer_setup(enum clock_event_mode,
-				struct clock_event_device *);
-
-static struct clocksource clocksource_uv = {
-	.name		= RTC_NAME,
-	.rating		= 400,
-	.read		= uv_read_rtc,
-	.mask		= (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
-	.shift		= 10,
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct clock_event_device clock_event_device_uv = {
-	.name		= RTC_NAME,
-	.features	= CLOCK_EVT_FEAT_ONESHOT,
-	.shift		= 20,
-	.rating		= 400,
-	.irq		= -1,
-	.set_next_event	= uv_rtc_next_event,
-	.set_mode	= uv_rtc_timer_setup,
-	.event_handler	= NULL,
-};
-
-static DEFINE_PER_CPU(struct clock_event_device, cpu_ced);
-
-/* There is one of these allocated per node */
-struct uv_rtc_timer_head {
-	spinlock_t	lock;
-	/* next cpu waiting for timer, local node relative: */
-	int		next_cpu;
-	/* number of cpus on this node: */
-	int		ncpus;
-	struct {
-		int	lcpu;		/* systemwide logical cpu number */
-		u64	expires;	/* next timer expiration for this cpu */
-	} cpu[1];
-};
-
-/*
- * Access to uv_rtc_timer_head via blade id.
- */
-static struct uv_rtc_timer_head		**blade_info __read_mostly;
-
-static int				uv_rtc_evt_enable;
-
-/*
- * Hardware interface routines
- */
-
-/* Send IPIs to another node */
-static void uv_rtc_send_IPI(int cpu)
-{
-	unsigned long apicid, val;
-	int pnode;
-
-	apicid = cpu_physical_id(cpu);
-	pnode = uv_apicid_to_pnode(apicid);
-	val = (1UL << UVH_IPI_INT_SEND_SHFT) |
-	      (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
-	      (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
-
-	uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
-}
-
-/* Check for an RTC interrupt pending */
-static int uv_intr_pending(int pnode)
-{
-	return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
-		UVH_EVENT_OCCURRED0_RTC1_MASK;
-}
-
-/* Setup interrupt and return non-zero if early expiration occurred. */
-static int uv_setup_intr(int cpu, u64 expires)
-{
-	u64 val;
-	int pnode = uv_cpu_to_pnode(cpu);
-
-	uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
-		UVH_RTC1_INT_CONFIG_M_MASK);
-	uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L);
-
-	uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
-		UVH_EVENT_OCCURRED0_RTC1_MASK);
-
-	val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
-		((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
-
-	/* Set configuration */
-	uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val);
-	/* Initialize comparator value */
-	uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires);
-
-	if (uv_read_rtc(NULL) <= expires)
-		return 0;
-
-	return !uv_intr_pending(pnode);
-}
-
-/*
- * Per-cpu timer tracking routines
- */
-
-static __init void uv_rtc_deallocate_timers(void)
-{
-	int bid;
-
-	for_each_possible_blade(bid) {
-		kfree(blade_info[bid]);
-	}
-	kfree(blade_info);
-}
-
-/* Allocate per-node list of cpu timer expiration times. */
-static __init int uv_rtc_allocate_timers(void)
-{
-	int cpu;
-
-	blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL);
-	if (!blade_info)
-		return -ENOMEM;
-	memset(blade_info, 0, uv_possible_blades * sizeof(void *));
-
-	for_each_present_cpu(cpu) {
-		int nid = cpu_to_node(cpu);
-		int bid = uv_cpu_to_blade_id(cpu);
-		int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
-		struct uv_rtc_timer_head *head = blade_info[bid];
-
-		if (!head) {
-			head = kmalloc_node(sizeof(struct uv_rtc_timer_head) +
-				(uv_blade_nr_possible_cpus(bid) *
-					2 * sizeof(u64)),
-				GFP_KERNEL, nid);
-			if (!head) {
-				uv_rtc_deallocate_timers();
-				return -ENOMEM;
-			}
-			spin_lock_init(&head->lock);
-			head->ncpus = uv_blade_nr_possible_cpus(bid);
-			head->next_cpu = -1;
-			blade_info[bid] = head;
-		}
-
-		head->cpu[bcpu].lcpu = cpu;
-		head->cpu[bcpu].expires = ULLONG_MAX;
-	}
-
-	return 0;
-}
-
-/* Find and set the next expiring timer.  */
-static void uv_rtc_find_next_timer(struct uv_rtc_timer_head *head, int pnode)
-{
-	u64 lowest = ULLONG_MAX;
-	int c, bcpu = -1;
-
-	head->next_cpu = -1;
-	for (c = 0; c < head->ncpus; c++) {
-		u64 exp = head->cpu[c].expires;
-		if (exp < lowest) {
-			bcpu = c;
-			lowest = exp;
-		}
-	}
-	if (bcpu >= 0) {
-		head->next_cpu = bcpu;
-		c = head->cpu[bcpu].lcpu;
-		if (uv_setup_intr(c, lowest))
-			/* If we didn't set it up in time, trigger */
-			uv_rtc_send_IPI(c);
-	} else {
-		uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
-			UVH_RTC1_INT_CONFIG_M_MASK);
-	}
-}
-
-/*
- * Set expiration time for current cpu.
- *
- * Returns 1 if we missed the expiration time.
- */
-static int uv_rtc_set_timer(int cpu, u64 expires)
-{
-	int pnode = uv_cpu_to_pnode(cpu);
-	int bid = uv_cpu_to_blade_id(cpu);
-	struct uv_rtc_timer_head *head = blade_info[bid];
-	int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
-	u64 *t = &head->cpu[bcpu].expires;
-	unsigned long flags;
-	int next_cpu;
-
-	spin_lock_irqsave(&head->lock, flags);
-
-	next_cpu = head->next_cpu;
-	*t = expires;
-
-	/* Will this one be next to go off? */
-	if (next_cpu < 0 || bcpu == next_cpu ||
-			expires < head->cpu[next_cpu].expires) {
-		head->next_cpu = bcpu;
-		if (uv_setup_intr(cpu, expires)) {
-			*t = ULLONG_MAX;
-			uv_rtc_find_next_timer(head, pnode);
-			spin_unlock_irqrestore(&head->lock, flags);
-			return -ETIME;
-		}
-	}
-
-	spin_unlock_irqrestore(&head->lock, flags);
-	return 0;
-}
-
-/*
- * Unset expiration time for current cpu.
- *
- * Returns 1 if this timer was pending.
- */
-static int uv_rtc_unset_timer(int cpu, int force)
-{
-	int pnode = uv_cpu_to_pnode(cpu);
-	int bid = uv_cpu_to_blade_id(cpu);
-	struct uv_rtc_timer_head *head = blade_info[bid];
-	int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
-	u64 *t = &head->cpu[bcpu].expires;
-	unsigned long flags;
-	int rc = 0;
-
-	spin_lock_irqsave(&head->lock, flags);
-
-	if ((head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t) || force)
-		rc = 1;
-
-	if (rc) {
-		*t = ULLONG_MAX;
-		/* Was the hardware setup for this timer? */
-		if (head->next_cpu == bcpu)
-			uv_rtc_find_next_timer(head, pnode);
-	}
-
-	spin_unlock_irqrestore(&head->lock, flags);
-
-	return rc;
-}
-
-
-/*
- * Kernel interface routines.
- */
-
-/*
- * Read the RTC.
- *
- * Starting with HUB rev 2.0, the UV RTC register is replicated across all
- * cachelines of it's own page.  This allows faster simultaneous reads
- * from a given socket.
- */
-static cycle_t uv_read_rtc(struct clocksource *cs)
-{
-	unsigned long offset;
-
-	if (uv_get_min_hub_revision_id() == 1)
-		offset = 0;
-	else
-		offset = (uv_blade_processor_id() * L1_CACHE_BYTES) % PAGE_SIZE;
-
-	return (cycle_t)uv_read_local_mmr(UVH_RTC | offset);
-}
-
-/*
- * Program the next event, relative to now
- */
-static int uv_rtc_next_event(unsigned long delta,
-			     struct clock_event_device *ced)
-{
-	int ced_cpu = cpumask_first(ced->cpumask);
-
-	return uv_rtc_set_timer(ced_cpu, delta + uv_read_rtc(NULL));
-}
-
-/*
- * Setup the RTC timer in oneshot mode
- */
-static void uv_rtc_timer_setup(enum clock_event_mode mode,
-			       struct clock_event_device *evt)
-{
-	int ced_cpu = cpumask_first(evt->cpumask);
-
-	switch (mode) {
-	case CLOCK_EVT_MODE_PERIODIC:
-	case CLOCK_EVT_MODE_ONESHOT:
-	case CLOCK_EVT_MODE_RESUME:
-		/* Nothing to do here yet */
-		break;
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-		uv_rtc_unset_timer(ced_cpu, 1);
-		break;
-	}
-}
-
-static void uv_rtc_interrupt(void)
-{
-	int cpu = smp_processor_id();
-	struct clock_event_device *ced = &per_cpu(cpu_ced, cpu);
-
-	if (!ced || !ced->event_handler)
-		return;
-
-	if (uv_rtc_unset_timer(cpu, 0) != 1)
-		return;
-
-	ced->event_handler(ced);
-}
-
-static int __init uv_enable_evt_rtc(char *str)
-{
-	uv_rtc_evt_enable = 1;
-
-	return 1;
-}
-__setup("uvrtcevt", uv_enable_evt_rtc);
-
-static __init void uv_rtc_register_clockevents(struct work_struct *dummy)
-{
-	struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
-
-	*ced = clock_event_device_uv;
-	ced->cpumask = cpumask_of(smp_processor_id());
-	clockevents_register_device(ced);
-}
-
-static __init int uv_rtc_setup_clock(void)
-{
-	int rc;
-
-	if (!is_uv_system())
-		return -ENODEV;
-
-	clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
-				clocksource_uv.shift);
-
-	/* If single blade, prefer tsc */
-	if (uv_num_possible_blades() == 1)
-		clocksource_uv.rating = 250;
-
-	rc = clocksource_register(&clocksource_uv);
-	if (rc)
-		printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
-	else
-		printk(KERN_INFO "UV RTC clocksource registered freq %lu MHz\n",
-			sn_rtc_cycles_per_second/(unsigned long)1E6);
-
-	if (rc || !uv_rtc_evt_enable || x86_platform_ipi_callback)
-		return rc;
-
-	/* Setup and register clockevents */
-	rc = uv_rtc_allocate_timers();
-	if (rc)
-		goto error;
-
-	x86_platform_ipi_callback = uv_rtc_interrupt;
-
-	clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
-				NSEC_PER_SEC, clock_event_device_uv.shift);
-
-	clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
-						sn_rtc_cycles_per_second;
-
-	clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
-				(NSEC_PER_SEC / sn_rtc_cycles_per_second);
-
-	rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
-	if (rc) {
-		x86_platform_ipi_callback = NULL;
-		uv_rtc_deallocate_timers();
-		goto error;
-	}
-
-	printk(KERN_INFO "UV RTC clockevents registered\n");
-
-	return 0;
-
-error:
-	clocksource_unregister(&clocksource_uv);
-	printk(KERN_INFO "UV RTC clockevents failed rc %d\n", rc);
-
-	return rc;
-}
-arch_initcall(uv_rtc_setup_clock);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/visws_quirks.c linux-libre-2.6.37-gnu/arch/x86/kernel/visws_quirks.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/visws_quirks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/visws_quirks.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,666 +0,0 @@
-/*
- *  SGI Visual Workstation support and quirks, unmaintained.
- *
- *  Split out from setup.c by davej@suse.de
- *
- *	Copyright (C) 1999 Bent Hagemark, Ingo Molnar
- *
- *  SGI Visual Workstation interrupt controller
- *
- *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
- *  which serves as the main interrupt controller in the system.  Non-legacy
- *  hardware in the system uses this controller directly.  Legacy devices
- *  are connected to the PIIX4 which in turn has its 8259(s) connected to
- *  a of the Cobalt APIC entry.
- *
- *  09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
- *
- *  25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
- */
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/visws/cobalt.h>
-#include <asm/visws/piix4.h>
-#include <asm/io_apic.h>
-#include <asm/fixmap.h>
-#include <asm/reboot.h>
-#include <asm/setup.h>
-#include <asm/apic.h>
-#include <asm/e820.h>
-#include <asm/time.h>
-#include <asm/io.h>
-
-#include <linux/kernel_stat.h>
-
-#include <asm/i8259.h>
-#include <asm/irq_vectors.h>
-#include <asm/visws/lithium.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-
-extern int no_broadcast;
-
-char visws_board_type	= -1;
-char visws_board_rev	= -1;
-
-static void __init visws_time_init(void)
-{
-	printk(KERN_INFO "Starting Cobalt Timer system clock\n");
-
-	/* Set the countdown value */
-	co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
-
-	/* Start the timer */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
-
-	/* Enable (unmask) the timer interrupt */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
-
-	setup_default_timer_irq();
-}
-
-/* Replaces the default init_ISA_irqs in the generic setup */
-static void __init visws_pre_intr_init(void)
-{
-	init_VISWS_APIC_irqs();
-}
-
-/* Quirk for machine specific memory setup. */
-
-#define MB (1024 * 1024)
-
-unsigned long sgivwfb_mem_phys;
-unsigned long sgivwfb_mem_size;
-EXPORT_SYMBOL(sgivwfb_mem_phys);
-EXPORT_SYMBOL(sgivwfb_mem_size);
-
-long long mem_size __initdata = 0;
-
-static char * __init visws_memory_setup(void)
-{
-	long long gfx_mem_size = 8 * MB;
-
-	mem_size = boot_params.alt_mem_k;
-
-	if (!mem_size) {
-		printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
-		mem_size = 128 * MB;
-	}
-
-	/*
-	 * this hardcodes the graphics memory to 8 MB
-	 * it really should be sized dynamically (or at least
-	 * set as a boot param)
-	 */
-	if (!sgivwfb_mem_size) {
-		printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
-		sgivwfb_mem_size = 8 * MB;
-	}
-
-	/*
-	 * Trim to nearest MB
-	 */
-	sgivwfb_mem_size &= ~((1 << 20) - 1);
-	sgivwfb_mem_phys = mem_size - gfx_mem_size;
-
-	e820_add_region(0, LOWMEMSIZE(), E820_RAM);
-	e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
-	e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
-
-	return "PROM";
-}
-
-static void visws_machine_emergency_restart(void)
-{
-	/*
-	 * Visual Workstations restart after this
-	 * register is poked on the PIIX4
-	 */
-	outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
-}
-
-static void visws_machine_power_off(void)
-{
-	unsigned short pm_status;
-/*	extern unsigned int pci_bus0; */
-
-	while ((pm_status = inw(PMSTS_PORT)) & 0x100)
-		outw(pm_status, PMSTS_PORT);
-
-	outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
-
-	mdelay(10);
-
-#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
-	(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
-
-/*	outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
-	outl(PIIX_SPECIAL_STOP, 0xCFC);
-}
-
-static void __init visws_get_smp_config(unsigned int early)
-{
-}
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesn't have a BIOS(-configuration table).
- * No problem for Linux.
- */
-
-static void __init MP_processor_info(struct mpc_cpu *m)
-{
-	int ver, logical_apicid;
-	physid_mask_t apic_cpus;
-
-	if (!(m->cpuflag & CPU_ENABLED))
-		return;
-
-	logical_apicid = m->apicid;
-	printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
-	       m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
-	       m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
-	       (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver);
-
-	if (m->cpuflag & CPU_BOOTPROCESSOR)
-		boot_cpu_physical_apicid = m->apicid;
-
-	ver = m->apicver;
-	if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) {
-		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
-			m->apicid, MAX_APICS);
-		return;
-	}
-
-	apic->apicid_to_cpu_present(m->apicid, &apic_cpus);
-	physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
-	/*
-	 * Validate version
-	 */
-	if (ver == 0x0) {
-		printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
-			"fixing up to 0x10. (tell your hw vendor)\n",
-			m->apicid);
-		ver = 0x10;
-	}
-	apic_version[m->apicid] = ver;
-}
-
-static void __init visws_find_smp_config(void)
-{
-	struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS);
-	unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
-
-	if (ncpus > CO_CPU_MAX) {
-		printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
-			ncpus, mp);
-
-		ncpus = CO_CPU_MAX;
-	}
-
-	if (ncpus > setup_max_cpus)
-		ncpus = setup_max_cpus;
-
-#ifdef CONFIG_X86_LOCAL_APIC
-	smp_found_config = 1;
-#endif
-	while (ncpus--)
-		MP_processor_info(mp++);
-
-	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-static void visws_trap_init(void);
-
-void __init visws_early_detect(void)
-{
-	int raw;
-
-	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
-							 >> PIIX_GPI_BD_SHIFT;
-
-	if (visws_board_type < 0)
-		return;
-
-	/*
-	 * Override the default platform setup functions
-	 */
-	x86_init.resources.memory_setup = visws_memory_setup;
-	x86_init.mpparse.get_smp_config = visws_get_smp_config;
-	x86_init.mpparse.find_smp_config = visws_find_smp_config;
-	x86_init.irqs.pre_vector_init = visws_pre_intr_init;
-	x86_init.irqs.trap_init = visws_trap_init;
-	x86_init.timers.timer_init = visws_time_init;
-	x86_init.pci.init = pci_visws_init;
-	x86_init.pci.init_irq = x86_init_noop;
-
-	/*
-	 * Install reboot quirks:
-	 */
-	pm_power_off			= visws_machine_power_off;
-	machine_ops.emergency_restart	= visws_machine_emergency_restart;
-
-	/*
-	 * Do not use broadcast IPIs:
-	 */
-	no_broadcast = 0;
-
-#ifdef CONFIG_X86_IO_APIC
-	/*
-	 * Turn off IO-APIC detection and initialization:
-	 */
-	skip_ioapic_setup		= 1;
-#endif
-
-	/*
-	 * Get Board rev.
-	 * First, we have to initialize the 307 part to allow us access
-	 * to the GPIO registers.  Let's map them at 0x0fc0 which is right
-	 * after the PIIX4 PM section.
-	 */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
-
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
-
-	/*
-	 * Now, we have to map the power management section to write
-	 * a bit which enables access to the GPIO registers.
-	 * What lunatic came up with this shit?
-	 */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
-
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable PM registers. */
-
-	/*
-	 * Now, write the PM register which enables the GPIO registers.
-	 */
-	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
-	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-
-	/*
-	 * Now, initialize the GPIO registers.
-	 * We want them all to be inputs which is the
-	 * power on default, so let's leave them alone.
-	 * So, let's just read the board rev!
-	 */
-	raw = inb_p(SIO_GP_DATA1);
-	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
-
-	if (visws_board_type == VISWS_320) {
-		if (raw < 0x6) {
-			visws_board_rev = 4;
-		} else if (raw < 0xc) {
-			visws_board_rev = 5;
-		} else {
-			visws_board_rev = 6;
-		}
-	} else if (visws_board_type == VISWS_540) {
-			visws_board_rev = 2;
-		} else {
-			visws_board_rev = raw;
-		}
-
-	printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
-	       (visws_board_type == VISWS_320 ? "320" :
-	       (visws_board_type == VISWS_540 ? "540" :
-		"unknown")), visws_board_rev);
-}
-
-#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
-#define BCD (LI_INTB | LI_INTC | LI_INTD)
-#define ALLDEVS (A01234 | BCD)
-
-static __init void lithium_init(void)
-{
-	set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
-	set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
-
-	if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
-	    (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
-		printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
-/*		panic("This machine is not SGI Visual Workstation 320/540"); */
-	}
-
-	if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
-	    (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
-		printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
-/*		panic("This machine is not SGI Visual Workstation 320/540"); */
-	}
-
-	li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
-	li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
-}
-
-static __init void cobalt_init(void)
-{
-	/*
-	 * On normal SMP PC this is used only with SMP, but we have to
-	 * use it and set it up here to start the Cobalt clock
-	 */
-	set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
-	setup_local_APIC();
-	printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
-		(unsigned int)apic_read(APIC_LVR),
-		(unsigned int)apic_read(APIC_ID));
-
-	set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
-	set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
-	printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
-		co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
-
-	/* Enable Cobalt APIC being careful to NOT change the ID! */
-	co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
-
-	printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
-		co_apic_read(CO_APIC_ID));
-}
-
-static void __init visws_trap_init(void)
-{
-	lithium_init();
-	cobalt_init();
-}
-
-/*
- * IRQ controller / APIC support:
- */
-
-static DEFINE_SPINLOCK(cobalt_lock);
-
-/*
- * Set the given Cobalt APIC Redirection Table entry to point
- * to the given IDT vector/index.
- */
-static inline void co_apic_set(int entry, int irq)
-{
-	co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
-	co_apic_write(CO_APIC_HI(entry), 0);
-}
-
-/*
- * Cobalt (IO)-APIC functions to handle PCI devices.
- */
-static inline int co_apic_ide0_hack(void)
-{
-	extern char visws_board_type;
-	extern char visws_board_rev;
-
-	if (visws_board_type == VISWS_320 && visws_board_rev == 5)
-		return 5;
-	return CO_APIC_IDE0;
-}
-
-static int is_co_apic(unsigned int irq)
-{
-	if (IS_CO_APIC(irq))
-		return CO_APIC(irq);
-
-	switch (irq) {
-		case 0: return CO_APIC_CPU;
-		case CO_IRQ_IDE0: return co_apic_ide0_hack();
-		case CO_IRQ_IDE1: return CO_APIC_IDE1;
-		default: return -1;
-	}
-}
-
-
-/*
- * This is the SGI Cobalt (IO-)APIC:
- */
-
-static void enable_cobalt_irq(unsigned int irq)
-{
-	co_apic_set(is_co_apic(irq), irq);
-}
-
-static void disable_cobalt_irq(unsigned int irq)
-{
-	int entry = is_co_apic(irq);
-
-	co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
-	co_apic_read(CO_APIC_LO(entry));
-}
-
-/*
- * "irq" really just serves to identify the device.  Here is where we
- * map this to the Cobalt APIC entry where it's physically wired.
- * This is called via request_irq -> setup_irq -> irq_desc->startup()
- */
-static unsigned int startup_cobalt_irq(unsigned int irq)
-{
-	unsigned long flags;
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	spin_lock_irqsave(&cobalt_lock, flags);
-	if ((desc->status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
-		desc->status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
-	enable_cobalt_irq(irq);
-	spin_unlock_irqrestore(&cobalt_lock, flags);
-	return 0;
-}
-
-static void ack_cobalt_irq(unsigned int irq)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cobalt_lock, flags);
-	disable_cobalt_irq(irq);
-	apic_write(APIC_EOI, APIC_EIO_ACK);
-	spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static void end_cobalt_irq(unsigned int irq)
-{
-	unsigned long flags;
-	struct irq_desc *desc = irq_to_desc(irq);
-
-	spin_lock_irqsave(&cobalt_lock, flags);
-	if (!(desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-		enable_cobalt_irq(irq);
-	spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip cobalt_irq_type = {
-	.name =		"Cobalt-APIC",
-	.startup =	startup_cobalt_irq,
-	.shutdown =	disable_cobalt_irq,
-	.enable =	enable_cobalt_irq,
-	.disable =	disable_cobalt_irq,
-	.ack =		ack_cobalt_irq,
-	.end =		end_cobalt_irq,
-};
-
-
-/*
- * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
- * -- not the manner expected by the code in i8259.c.
- *
- * there is a 'master' physical interrupt source that gets sent to
- * the CPU. But in the chipset there are various 'virtual' interrupts
- * waiting to be handled. We represent this to Linux through a 'master'
- * interrupt controller type, and through a special virtual interrupt-
- * controller. Device drivers only see the virtual interrupt sources.
- */
-static unsigned int startup_piix4_master_irq(unsigned int irq)
-{
-	legacy_pic->init(0);
-
-	return startup_cobalt_irq(irq);
-}
-
-static void end_piix4_master_irq(unsigned int irq)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&cobalt_lock, flags);
-	enable_cobalt_irq(irq);
-	spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
-static struct irq_chip piix4_master_irq_type = {
-	.name =		"PIIX4-master",
-	.startup =	startup_piix4_master_irq,
-	.ack =		ack_cobalt_irq,
-	.end =		end_piix4_master_irq,
-};
-
-
-static struct irq_chip piix4_virtual_irq_type = {
-	.name =		"PIIX4-virtual",
-};
-
-
-/*
- * PIIX4-8259 master/virtual functions to handle interrupt requests
- * from legacy devices: floppy, parallel, serial, rtc.
- *
- * None of these get Cobalt APIC entries, neither do they have IDT
- * entries. These interrupts are purely virtual and distributed from
- * the 'master' interrupt source: CO_IRQ_8259.
- *
- * When the 8259 interrupts its handler figures out which of these
- * devices is interrupting and dispatches to its handler.
- *
- * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
- * enable_irq gets the right irq. This 'master' irq is never directly
- * manipulated by any driver.
- */
-static irqreturn_t piix4_master_intr(int irq, void *dev_id)
-{
-	int realirq;
-	struct irq_desc *desc;
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&i8259A_lock, flags);
-
-	/* Find out what's interrupting in the PIIX4 master 8259 */
-	outb(0x0c, 0x20);		/* OCW3 Poll command */
-	realirq = inb(0x20);
-
-	/*
-	 * Bit 7 == 0 means invalid/spurious
-	 */
-	if (unlikely(!(realirq & 0x80)))
-		goto out_unlock;
-
-	realirq &= 7;
-
-	if (unlikely(realirq == 2)) {
-		outb(0x0c, 0xa0);
-		realirq = inb(0xa0);
-
-		if (unlikely(!(realirq & 0x80)))
-			goto out_unlock;
-
-		realirq = (realirq & 7) + 8;
-	}
-
-	/* mask and ack interrupt */
-	cached_irq_mask |= 1 << realirq;
-	if (unlikely(realirq > 7)) {
-		inb(0xa1);
-		outb(cached_slave_mask, 0xa1);
-		outb(0x60 + (realirq & 7), 0xa0);
-		outb(0x60 + 2, 0x20);
-	} else {
-		inb(0x21);
-		outb(cached_master_mask, 0x21);
-		outb(0x60 + realirq, 0x20);
-	}
-
-	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
-
-	desc = irq_to_desc(realirq);
-
-	/*
-	 * handle this 'virtual interrupt' as a Cobalt one now.
-	 */
-	kstat_incr_irqs_this_cpu(realirq, desc);
-
-	if (likely(desc->action != NULL))
-		handle_IRQ_event(realirq, desc->action);
-
-	if (!(desc->status & IRQ_DISABLED))
-		legacy_pic->chip->unmask(realirq);
-
-	return IRQ_HANDLED;
-
-out_unlock:
-	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
-	return IRQ_NONE;
-}
-
-static struct irqaction master_action = {
-	.handler =	piix4_master_intr,
-	.name =		"PIIX4-8259",
-};
-
-static struct irqaction cascade_action = {
-	.handler = 	no_action,
-	.name =		"cascade",
-};
-
-static inline void set_piix4_virtual_irq_type(void)
-{
-	piix4_virtual_irq_type.shutdown = i8259A_chip.mask;
-	piix4_virtual_irq_type.enable =	i8259A_chip.unmask;
-	piix4_virtual_irq_type.disable = i8259A_chip.mask;
-}
-
-void init_VISWS_APIC_irqs(void)
-{
-	int i;
-
-	for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
-		struct irq_desc *desc = irq_to_desc(i);
-
-		desc->status = IRQ_DISABLED;
-		desc->action = 0;
-		desc->depth = 1;
-
-		if (i == 0) {
-			desc->chip = &cobalt_irq_type;
-		}
-		else if (i == CO_IRQ_IDE0) {
-			desc->chip = &cobalt_irq_type;
-		}
-		else if (i == CO_IRQ_IDE1) {
-			desc->chip = &cobalt_irq_type;
-		}
-		else if (i == CO_IRQ_8259) {
-			desc->chip = &piix4_master_irq_type;
-		}
-		else if (i < CO_IRQ_APIC0) {
-			set_piix4_virtual_irq_type();
-			desc->chip = &piix4_virtual_irq_type;
-		}
-		else if (IS_CO_APIC(i)) {
-			desc->chip = &cobalt_irq_type;
-		}
-	}
-
-	setup_irq(CO_IRQ_8259, &master_action);
-	setup_irq(2, &cascade_action);
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/vm86_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/vm86_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/vm86_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/vm86_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -551,8 +551,14 @@
 int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno)
 {
 	if (VMPI.is_vm86pus) {
-		if ((trapno == 3) || (trapno == 1))
-			return_to_32bit(regs, VM86_TRAP + (trapno << 8));
+		if ((trapno == 3) || (trapno == 1)) {
+			KVM86->regs32->ax = VM86_TRAP + (trapno << 8);
+			/* setting this flag forces the code in entry_32.S to
+			   call save_v86_state() and change the stack pointer
+			   to KVM86->regs32 */
+			set_thread_flag(TIF_IRET);
+			return 0;
+		}
 		do_int(regs, trapno, (unsigned char __user *) (regs->pt.ss << 4), SP(regs));
 		return 0;
 	}
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/vmi_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/vmi_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/vmi_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/vmi_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,893 +0,0 @@
-/*
- * VMI specific paravirt-ops implementation
- *
- * Copyright (C) 2005, VMware, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to zach@vmware.com
- *
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/sched.h>
-#include <linux/gfp.h>
-#include <asm/vmi.h>
-#include <asm/io.h>
-#include <asm/fixmap.h>
-#include <asm/apicdef.h>
-#include <asm/apic.h>
-#include <asm/pgalloc.h>
-#include <asm/processor.h>
-#include <asm/timer.h>
-#include <asm/vmi_time.h>
-#include <asm/kmap_types.h>
-#include <asm/setup.h>
-
-/* Convenient for calling VMI functions indirectly in the ROM */
-typedef u32 __attribute__((regparm(1))) (VROMFUNC)(void);
-typedef u64 __attribute__((regparm(2))) (VROMLONGFUNC)(int);
-
-#define call_vrom_func(rom,func) \
-   (((VROMFUNC *)(rom->func))())
-
-#define call_vrom_long_func(rom,func,arg) \
-   (((VROMLONGFUNC *)(rom->func)) (arg))
-
-static struct vrom_header *vmi_rom;
-static int disable_pge;
-static int disable_pse;
-static int disable_sep;
-static int disable_tsc;
-static int disable_mtrr;
-static int disable_noidle;
-static int disable_vmi_timer;
-
-/* Cached VMI operations */
-static struct {
-	void (*cpuid)(void /* non-c */);
-	void (*_set_ldt)(u32 selector);
-	void (*set_tr)(u32 selector);
-	void (*write_idt_entry)(struct desc_struct *, int, u32, u32);
-	void (*write_gdt_entry)(struct desc_struct *, int, u32, u32);
-	void (*write_ldt_entry)(struct desc_struct *, int, u32, u32);
-	void (*set_kernel_stack)(u32 selector, u32 sp0);
-	void (*allocate_page)(u32, u32, u32, u32, u32);
-	void (*release_page)(u32, u32);
-	void (*set_pte)(pte_t, pte_t *, unsigned);
-	void (*update_pte)(pte_t *, unsigned);
-	void (*set_linear_mapping)(int, void *, u32, u32);
-	void (*_flush_tlb)(int);
-	void (*set_initial_ap_state)(int, int);
-	void (*halt)(void);
-  	void (*set_lazy_mode)(int mode);
-} vmi_ops;
-
-/* Cached VMI operations */
-struct vmi_timer_ops vmi_timer_ops;
-
-/*
- * VMI patching routines.
- */
-#define MNEM_CALL 0xe8
-#define MNEM_JMP  0xe9
-#define MNEM_RET  0xc3
-
-#define IRQ_PATCH_INT_MASK 0
-#define IRQ_PATCH_DISABLE  5
-
-static inline void patch_offset(void *insnbuf,
-				unsigned long ip, unsigned long dest)
-{
-        *(unsigned long *)(insnbuf+1) = dest-ip-5;
-}
-
-static unsigned patch_internal(int call, unsigned len, void *insnbuf,
-			       unsigned long ip)
-{
-	u64 reloc;
-	struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc;
-	reloc = call_vrom_long_func(vmi_rom, get_reloc,	call);
-	switch(rel->type) {
-		case VMI_RELOCATION_CALL_REL:
-			BUG_ON(len < 5);
-			*(char *)insnbuf = MNEM_CALL;
-			patch_offset(insnbuf, ip, (unsigned long)rel->eip);
-			return 5;
-
-		case VMI_RELOCATION_JUMP_REL:
-			BUG_ON(len < 5);
-			*(char *)insnbuf = MNEM_JMP;
-			patch_offset(insnbuf, ip, (unsigned long)rel->eip);
-			return 5;
-
-		case VMI_RELOCATION_NOP:
-			/* obliterate the whole thing */
-			return 0;
-
-		case VMI_RELOCATION_NONE:
-			/* leave native code in place */
-			break;
-
-		default:
-			BUG();
-	}
-	return len;
-}
-
-/*
- * Apply patch if appropriate, return length of new instruction
- * sequence.  The callee does nop padding for us.
- */
-static unsigned vmi_patch(u8 type, u16 clobbers, void *insns,
-			  unsigned long ip, unsigned len)
-{
-	switch (type) {
-		case PARAVIRT_PATCH(pv_irq_ops.irq_disable):
-			return patch_internal(VMI_CALL_DisableInterrupts, len,
-					      insns, ip);
-		case PARAVIRT_PATCH(pv_irq_ops.irq_enable):
-			return patch_internal(VMI_CALL_EnableInterrupts, len,
-					      insns, ip);
-		case PARAVIRT_PATCH(pv_irq_ops.restore_fl):
-			return patch_internal(VMI_CALL_SetInterruptMask, len,
-					      insns, ip);
-		case PARAVIRT_PATCH(pv_irq_ops.save_fl):
-			return patch_internal(VMI_CALL_GetInterruptMask, len,
-					      insns, ip);
-		case PARAVIRT_PATCH(pv_cpu_ops.iret):
-			return patch_internal(VMI_CALL_IRET, len, insns, ip);
-		case PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit):
-			return patch_internal(VMI_CALL_SYSEXIT, len, insns, ip);
-		default:
-			break;
-	}
-	return len;
-}
-
-/* CPUID has non-C semantics, and paravirt-ops API doesn't match hardware ISA */
-static void vmi_cpuid(unsigned int *ax, unsigned int *bx,
-                               unsigned int *cx, unsigned int *dx)
-{
-	int override = 0;
-	if (*ax == 1)
-		override = 1;
-        asm volatile ("call *%6"
-                      : "=a" (*ax),
-                        "=b" (*bx),
-                        "=c" (*cx),
-                        "=d" (*dx)
-                      : "0" (*ax), "2" (*cx), "r" (vmi_ops.cpuid));
-	if (override) {
-		if (disable_pse)
-			*dx &= ~X86_FEATURE_PSE;
-		if (disable_pge)
-			*dx &= ~X86_FEATURE_PGE;
-		if (disable_sep)
-			*dx &= ~X86_FEATURE_SEP;
-		if (disable_tsc)
-			*dx &= ~X86_FEATURE_TSC;
-		if (disable_mtrr)
-			*dx &= ~X86_FEATURE_MTRR;
-	}
-}
-
-static inline void vmi_maybe_load_tls(struct desc_struct *gdt, int nr, struct desc_struct *new)
-{
-	if (gdt[nr].a != new->a || gdt[nr].b != new->b)
-		write_gdt_entry(gdt, nr, new, 0);
-}
-
-static void vmi_load_tls(struct thread_struct *t, unsigned int cpu)
-{
-	struct desc_struct *gdt = get_cpu_gdt_table(cpu);
-	vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 0, &t->tls_array[0]);
-	vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 1, &t->tls_array[1]);
-	vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 2, &t->tls_array[2]);
-}
-
-static void vmi_set_ldt(const void *addr, unsigned entries)
-{
-	unsigned cpu = smp_processor_id();
-	struct desc_struct desc;
-
-	pack_descriptor(&desc, (unsigned long)addr,
-			entries * sizeof(struct desc_struct) - 1,
-			DESC_LDT, 0);
-	write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, &desc, DESC_LDT);
-	vmi_ops._set_ldt(entries ? GDT_ENTRY_LDT*sizeof(struct desc_struct) : 0);
-}
-
-static void vmi_set_tr(void)
-{
-	vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct));
-}
-
-static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
-{
-	u32 *idt_entry = (u32 *)g;
-	vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
-}
-
-static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
-				const void *desc, int type)
-{
-	u32 *gdt_entry = (u32 *)desc;
-	vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[1]);
-}
-
-static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
-				const void *desc)
-{
-	u32 *ldt_entry = (u32 *)desc;
-	vmi_ops.write_ldt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
-}
-
-static void vmi_load_sp0(struct tss_struct *tss,
-				   struct thread_struct *thread)
-{
-	tss->x86_tss.sp0 = thread->sp0;
-
-	/* This can only happen when SEP is enabled, no need to test "SEP"arately */
-	if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
-		tss->x86_tss.ss1 = thread->sysenter_cs;
-		wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
-	}
-	vmi_ops.set_kernel_stack(__KERNEL_DS, tss->x86_tss.sp0);
-}
-
-static void vmi_flush_tlb_user(void)
-{
-	vmi_ops._flush_tlb(VMI_FLUSH_TLB);
-}
-
-static void vmi_flush_tlb_kernel(void)
-{
-	vmi_ops._flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
-}
-
-/* Stub to do nothing at all; used for delays and unimplemented calls */
-static void vmi_nop(void)
-{
-}
-
-static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn)
-{
-	vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
-}
-
-static void vmi_allocate_pmd(struct mm_struct *mm, unsigned long pfn)
-{
- 	/*
-	 * This call comes in very early, before mem_map is setup.
-	 * It is called only for swapper_pg_dir, which already has
-	 * data on it.
-	 */
-	vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0);
-}
-
-static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count)
-{
-	vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count);
-}
-
-static void vmi_release_pte(unsigned long pfn)
-{
-	vmi_ops.release_page(pfn, VMI_PAGE_L1);
-}
-
-static void vmi_release_pmd(unsigned long pfn)
-{
-	vmi_ops.release_page(pfn, VMI_PAGE_L2);
-}
-
-/*
- * We use the pgd_free hook for releasing the pgd page:
- */
-static void vmi_pgd_free(struct mm_struct *mm, pgd_t *pgd)
-{
-	unsigned long pfn = __pa(pgd) >> PAGE_SHIFT;
-
-	vmi_ops.release_page(pfn, VMI_PAGE_L2);
-}
-
-/*
- * Helper macros for MMU update flags.  We can defer updates until a flush
- * or page invalidation only if the update is to the current address space
- * (otherwise, there is no flush).  We must check against init_mm, since
- * this could be a kernel update, which usually passes init_mm, although
- * sometimes this check can be skipped if we know the particular function
- * is only called on user mode PTEs.  We could change the kernel to pass
- * current->active_mm here, but in particular, I was unsure if changing
- * mm/highmem.c to do this would still be correct on other architectures.
- */
-#define is_current_as(mm, mustbeuser) ((mm) == current->active_mm ||    \
-                                       (!mustbeuser && (mm) == &init_mm))
-#define vmi_flags_addr(mm, addr, level, user)                           \
-        ((level) | (is_current_as(mm, user) ?                           \
-                (VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
-#define vmi_flags_addr_defer(mm, addr, level, user)                     \
-        ((level) | (is_current_as(mm, user) ?                           \
-                (VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
-
-static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-	vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-	vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_set_pte(pte_t *ptep, pte_t pte)
-{
-	/* XXX because of set_pmd_pte, this can be called on PT or PD layers */
-	vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT);
-}
-
-static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
-{
-	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
-#ifdef CONFIG_X86_PAE
-	const pte_t pte = { .pte = pmdval.pmd };
-#else
-	const pte_t pte = { pmdval.pud.pgd.pgd };
-#endif
-	vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD);
-}
-
-#ifdef CONFIG_X86_PAE
-
-static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval)
-{
-	/*
-	 * XXX This is called from set_pmd_pte, but at both PT
-	 * and PD layers so the VMI_PAGE_PT flag is wrong.  But
-	 * it is only called for large page mapping changes,
-	 * the Xen backend, doesn't support large pages, and the
-	 * ESX backend doesn't depend on the flag.
-	 */
-	set_64bit((unsigned long long *)ptep,pte_val(pteval));
-	vmi_ops.update_pte(ptep, VMI_PAGE_PT);
-}
-
-static void vmi_set_pud(pud_t *pudp, pud_t pudval)
-{
-	/* Um, eww */
-	const pte_t pte = { .pte = pudval.pgd.pgd };
-	vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP);
-}
-
-static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-	const pte_t pte = { .pte = 0 };
-	vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_pmd_clear(pmd_t *pmd)
-{
-	const pte_t pte = { .pte = 0 };
-	vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD);
-}
-#endif
-
-#ifdef CONFIG_SMP
-static void __devinit
-vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
-		     unsigned long start_esp)
-{
-	struct vmi_ap_state ap;
-
-	/* Default everything to zero.  This is fine for most GPRs. */
-	memset(&ap, 0, sizeof(struct vmi_ap_state));
-
-	ap.gdtr_limit = GDT_SIZE - 1;
-	ap.gdtr_base = (unsigned long) get_cpu_gdt_table(phys_apicid);
-
-	ap.idtr_limit = IDT_ENTRIES * 8 - 1;
-	ap.idtr_base = (unsigned long) idt_table;
-
-	ap.ldtr = 0;
-
-	ap.cs = __KERNEL_CS;
-	ap.eip = (unsigned long) start_eip;
-	ap.ss = __KERNEL_DS;
-	ap.esp = (unsigned long) start_esp;
-
-	ap.ds = __USER_DS;
-	ap.es = __USER_DS;
-	ap.fs = __KERNEL_PERCPU;
-	ap.gs = __KERNEL_STACK_CANARY;
-
-	ap.eflags = 0;
-
-#ifdef CONFIG_X86_PAE
-	/* efer should match BSP efer. */
-	if (cpu_has_nx) {
-		unsigned l, h;
-		rdmsr(MSR_EFER, l, h);
-		ap.efer = (unsigned long long) h << 32 | l;
-	}
-#endif
-
-	ap.cr3 = __pa(swapper_pg_dir);
-	/* Protected mode, paging, AM, WP, NE, MP. */
-	ap.cr0 = 0x80050023;
-	ap.cr4 = mmu_cr4_features;
-	vmi_ops.set_initial_ap_state((u32)&ap, phys_apicid);
-}
-#endif
-
-static void vmi_start_context_switch(struct task_struct *prev)
-{
-	paravirt_start_context_switch(prev);
-	vmi_ops.set_lazy_mode(2);
-}
-
-static void vmi_end_context_switch(struct task_struct *next)
-{
-	vmi_ops.set_lazy_mode(0);
-	paravirt_end_context_switch(next);
-}
-
-static void vmi_enter_lazy_mmu(void)
-{
-	paravirt_enter_lazy_mmu();
-	vmi_ops.set_lazy_mode(1);
-}
-
-static void vmi_leave_lazy_mmu(void)
-{
-	vmi_ops.set_lazy_mode(0);
-	paravirt_leave_lazy_mmu();
-}
-
-static inline int __init check_vmi_rom(struct vrom_header *rom)
-{
-	struct pci_header *pci;
-	struct pnp_header *pnp;
-	const char *manufacturer = "UNKNOWN";
-	const char *product = "UNKNOWN";
-	const char *license = "unspecified";
-
-	if (rom->rom_signature != 0xaa55)
-		return 0;
-	if (rom->vrom_signature != VMI_SIGNATURE)
-		return 0;
-	if (rom->api_version_maj != VMI_API_REV_MAJOR ||
-	    rom->api_version_min+1 < VMI_API_REV_MINOR+1) {
-		printk(KERN_WARNING "VMI: Found mismatched rom version %d.%d\n",
-				rom->api_version_maj,
-				rom->api_version_min);
-		return 0;
-	}
-
-	/*
-	 * Relying on the VMI_SIGNATURE field is not 100% safe, so check
-	 * the PCI header and device type to make sure this is really a
-	 * VMI device.
-	 */
-	if (!rom->pci_header_offs) {
-		printk(KERN_WARNING "VMI: ROM does not contain PCI header.\n");
-		return 0;
-	}
-
-	pci = (struct pci_header *)((char *)rom+rom->pci_header_offs);
-	if (pci->vendorID != PCI_VENDOR_ID_VMWARE ||
-	    pci->deviceID != PCI_DEVICE_ID_VMWARE_VMI) {
-		/* Allow it to run... anyways, but warn */
-		printk(KERN_WARNING "VMI: ROM from unknown manufacturer\n");
-	}
-
-	if (rom->pnp_header_offs) {
-		pnp = (struct pnp_header *)((char *)rom+rom->pnp_header_offs);
-		if (pnp->manufacturer_offset)
-			manufacturer = (const char *)rom+pnp->manufacturer_offset;
-		if (pnp->product_offset)
-			product = (const char *)rom+pnp->product_offset;
-	}
-
-	if (rom->license_offs)
-		license = (char *)rom+rom->license_offs;
-
-	printk(KERN_INFO "VMI: Found %s %s, API version %d.%d, ROM version %d.%d\n",
-		manufacturer, product,
-		rom->api_version_maj, rom->api_version_min,
-		pci->rom_version_maj, pci->rom_version_min);
-
-	/* Don't allow BSD/MIT here for now because we don't want to end up
-	   with any binary only shim layers */
-	if (strcmp(license, "GPL") && strcmp(license, "GPL v2")) {
-		printk(KERN_WARNING "VMI: Non GPL license `%s' found for ROM. Not used.\n",
-			license);
-		return 0;
-	}
-
-	return 1;
-}
-
-/*
- * Probe for the VMI option ROM
- */
-static inline int __init probe_vmi_rom(void)
-{
-	unsigned long base;
-
-	/* VMI ROM is in option ROM area, check signature */
-	for (base = 0xC0000; base < 0xE0000; base += 2048) {
-		struct vrom_header *romstart;
-		romstart = (struct vrom_header *)isa_bus_to_virt(base);
-		if (check_vmi_rom(romstart)) {
-			vmi_rom = romstart;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * VMI setup common to all processors
- */
-void vmi_bringup(void)
-{
- 	/* We must establish the lowmem mapping for MMU ops to work */
-	if (vmi_ops.set_linear_mapping)
-		vmi_ops.set_linear_mapping(0, (void *)__PAGE_OFFSET, MAXMEM_PFN, 0);
-}
-
-/*
- * Return a pointer to a VMI function or NULL if unimplemented
- */
-static void *vmi_get_function(int vmicall)
-{
-	u64 reloc;
-	const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc;
-	reloc = call_vrom_long_func(vmi_rom, get_reloc,	vmicall);
-	BUG_ON(rel->type == VMI_RELOCATION_JUMP_REL);
-	if (rel->type == VMI_RELOCATION_CALL_REL)
-		return (void *)rel->eip;
-	else
-		return NULL;
-}
-
-/*
- * Helper macro for making the VMI paravirt-ops fill code readable.
- * For unimplemented operations, fall back to default, unless nop
- * is returned by the ROM.
- */
-#define para_fill(opname, vmicall)				\
-do {								\
-	reloc = call_vrom_long_func(vmi_rom, get_reloc,		\
-				    VMI_CALL_##vmicall);	\
-	if (rel->type == VMI_RELOCATION_CALL_REL) 		\
-		opname = (void *)rel->eip;			\
-	else if (rel->type == VMI_RELOCATION_NOP) 		\
-		opname = (void *)vmi_nop;			\
-	else if (rel->type != VMI_RELOCATION_NONE)		\
-		printk(KERN_WARNING "VMI: Unknown relocation "	\
-				    "type %d for " #vmicall"\n",\
-					rel->type);		\
-} while (0)
-
-/*
- * Helper macro for making the VMI paravirt-ops fill code readable.
- * For cached operations which do not match the VMI ROM ABI and must
- * go through a tranlation stub.  Ignore NOPs, since it is not clear
- * a NOP * VMI function corresponds to a NOP paravirt-op when the
- * functions are not in 1-1 correspondence.
- */
-#define para_wrap(opname, wrapper, cache, vmicall)		\
-do {								\
-	reloc = call_vrom_long_func(vmi_rom, get_reloc,		\
-				    VMI_CALL_##vmicall);	\
-	BUG_ON(rel->type == VMI_RELOCATION_JUMP_REL);		\
-	if (rel->type == VMI_RELOCATION_CALL_REL) {		\
-		opname = wrapper;				\
-		vmi_ops.cache = (void *)rel->eip;		\
-	}							\
-} while (0)
-
-/*
- * Activate the VMI interface and switch into paravirtualized mode
- */
-static inline int __init activate_vmi(void)
-{
-	short kernel_cs;
-	u64 reloc;
-	const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc;
-
-	/*
-	 * Prevent page tables from being allocated in highmem, even if
-	 * CONFIG_HIGHPTE is enabled.
-	 */
-	__userpte_alloc_gfp &= ~__GFP_HIGHMEM;
-
-	if (call_vrom_func(vmi_rom, vmi_init) != 0) {
-		printk(KERN_ERR "VMI ROM failed to initialize!");
-		return 0;
-	}
-	savesegment(cs, kernel_cs);
-
-	pv_info.paravirt_enabled = 1;
-	pv_info.kernel_rpl = kernel_cs & SEGMENT_RPL_MASK;
-	pv_info.name = "vmi [deprecated]";
-
-	pv_init_ops.patch = vmi_patch;
-
-	/*
-	 * Many of these operations are ABI compatible with VMI.
-	 * This means we can fill in the paravirt-ops with direct
-	 * pointers into the VMI ROM.  If the calling convention for
-	 * these operations changes, this code needs to be updated.
-	 *
-	 * Exceptions
-	 *  CPUID paravirt-op uses pointers, not the native ISA
-	 *  halt has no VMI equivalent; all VMI halts are "safe"
-	 *  no MSR support yet - just trap and emulate.  VMI uses the
-	 *    same ABI as the native ISA, but Linux wants exceptions
-	 *    from bogus MSR read / write handled
-	 *  rdpmc is not yet used in Linux
-	 */
-
-	/* CPUID is special, so very special it gets wrapped like a present */
-	para_wrap(pv_cpu_ops.cpuid, vmi_cpuid, cpuid, CPUID);
-
-	para_fill(pv_cpu_ops.clts, CLTS);
-	para_fill(pv_cpu_ops.get_debugreg, GetDR);
-	para_fill(pv_cpu_ops.set_debugreg, SetDR);
-	para_fill(pv_cpu_ops.read_cr0, GetCR0);
-	para_fill(pv_mmu_ops.read_cr2, GetCR2);
-	para_fill(pv_mmu_ops.read_cr3, GetCR3);
-	para_fill(pv_cpu_ops.read_cr4, GetCR4);
-	para_fill(pv_cpu_ops.write_cr0, SetCR0);
-	para_fill(pv_mmu_ops.write_cr2, SetCR2);
-	para_fill(pv_mmu_ops.write_cr3, SetCR3);
-	para_fill(pv_cpu_ops.write_cr4, SetCR4);
-
-	para_fill(pv_irq_ops.save_fl.func, GetInterruptMask);
-	para_fill(pv_irq_ops.restore_fl.func, SetInterruptMask);
-	para_fill(pv_irq_ops.irq_disable.func, DisableInterrupts);
-	para_fill(pv_irq_ops.irq_enable.func, EnableInterrupts);
-
-	para_fill(pv_cpu_ops.wbinvd, WBINVD);
-	para_fill(pv_cpu_ops.read_tsc, RDTSC);
-
-	/* The following we emulate with trap and emulate for now */
-	/* paravirt_ops.read_msr = vmi_rdmsr */
-	/* paravirt_ops.write_msr = vmi_wrmsr */
-	/* paravirt_ops.rdpmc = vmi_rdpmc */
-
-	/* TR interface doesn't pass TR value, wrap */
-	para_wrap(pv_cpu_ops.load_tr_desc, vmi_set_tr, set_tr, SetTR);
-
-	/* LDT is special, too */
-	para_wrap(pv_cpu_ops.set_ldt, vmi_set_ldt, _set_ldt, SetLDT);
-
-	para_fill(pv_cpu_ops.load_gdt, SetGDT);
-	para_fill(pv_cpu_ops.load_idt, SetIDT);
-	para_fill(pv_cpu_ops.store_gdt, GetGDT);
-	para_fill(pv_cpu_ops.store_idt, GetIDT);
-	para_fill(pv_cpu_ops.store_tr, GetTR);
-	pv_cpu_ops.load_tls = vmi_load_tls;
-	para_wrap(pv_cpu_ops.write_ldt_entry, vmi_write_ldt_entry,
-		  write_ldt_entry, WriteLDTEntry);
-	para_wrap(pv_cpu_ops.write_gdt_entry, vmi_write_gdt_entry,
-		  write_gdt_entry, WriteGDTEntry);
-	para_wrap(pv_cpu_ops.write_idt_entry, vmi_write_idt_entry,
-		  write_idt_entry, WriteIDTEntry);
-	para_wrap(pv_cpu_ops.load_sp0, vmi_load_sp0, set_kernel_stack, UpdateKernelStack);
-	para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask);
-	para_fill(pv_cpu_ops.io_delay, IODelay);
-
-	para_wrap(pv_cpu_ops.start_context_switch, vmi_start_context_switch,
-		  set_lazy_mode, SetLazyMode);
-	para_wrap(pv_cpu_ops.end_context_switch, vmi_end_context_switch,
-		  set_lazy_mode, SetLazyMode);
-
-	para_wrap(pv_mmu_ops.lazy_mode.enter, vmi_enter_lazy_mmu,
-		  set_lazy_mode, SetLazyMode);
-	para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy_mmu,
-		  set_lazy_mode, SetLazyMode);
-
-	/* user and kernel flush are just handled with different flags to FlushTLB */
-	para_wrap(pv_mmu_ops.flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB);
-	para_wrap(pv_mmu_ops.flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB);
-	para_fill(pv_mmu_ops.flush_tlb_single, InvalPage);
-
-	/*
-	 * Until a standard flag format can be agreed on, we need to
-	 * implement these as wrappers in Linux.  Get the VMI ROM
-	 * function pointers for the two backend calls.
-	 */
-#ifdef CONFIG_X86_PAE
-	vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxELong);
-	vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxELong);
-#else
-	vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxE);
-	vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxE);
-#endif
-
-	if (vmi_ops.set_pte) {
-		pv_mmu_ops.set_pte = vmi_set_pte;
-		pv_mmu_ops.set_pte_at = vmi_set_pte_at;
-		pv_mmu_ops.set_pmd = vmi_set_pmd;
-#ifdef CONFIG_X86_PAE
-		pv_mmu_ops.set_pte_atomic = vmi_set_pte_atomic;
-		pv_mmu_ops.set_pud = vmi_set_pud;
-		pv_mmu_ops.pte_clear = vmi_pte_clear;
-		pv_mmu_ops.pmd_clear = vmi_pmd_clear;
-#endif
-	}
-
-	if (vmi_ops.update_pte) {
-		pv_mmu_ops.pte_update = vmi_update_pte;
-		pv_mmu_ops.pte_update_defer = vmi_update_pte_defer;
-	}
-
-	vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage);
-	if (vmi_ops.allocate_page) {
-		pv_mmu_ops.alloc_pte = vmi_allocate_pte;
-		pv_mmu_ops.alloc_pmd = vmi_allocate_pmd;
-		pv_mmu_ops.alloc_pmd_clone = vmi_allocate_pmd_clone;
-	}
-
-	vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage);
-	if (vmi_ops.release_page) {
-		pv_mmu_ops.release_pte = vmi_release_pte;
-		pv_mmu_ops.release_pmd = vmi_release_pmd;
-		pv_mmu_ops.pgd_free = vmi_pgd_free;
-	}
-
-	/* Set linear is needed in all cases */
-	vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping);
-
-	/*
-	 * These MUST always be patched.  Don't support indirect jumps
-	 * through these operations, as the VMI interface may use either
-	 * a jump or a call to get to these operations, depending on
-	 * the backend.  They are performance critical anyway, so requiring
-	 * a patch is not a big problem.
-	 */
-	pv_cpu_ops.irq_enable_sysexit = (void *)0xfeedbab0;
-	pv_cpu_ops.iret = (void *)0xbadbab0;
-
-#ifdef CONFIG_SMP
-	para_wrap(pv_apic_ops.startup_ipi_hook, vmi_startup_ipi_hook, set_initial_ap_state, SetInitialAPState);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-       para_fill(apic->read, APICRead);
-       para_fill(apic->write, APICWrite);
-#endif
-
-	/*
-	 * Check for VMI timer functionality by probing for a cycle frequency method
-	 */
-	reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_GetCycleFrequency);
-	if (!disable_vmi_timer && rel->type != VMI_RELOCATION_NONE) {
-		vmi_timer_ops.get_cycle_frequency = (void *)rel->eip;
-		vmi_timer_ops.get_cycle_counter =
-			vmi_get_function(VMI_CALL_GetCycleCounter);
-		vmi_timer_ops.get_wallclock =
-			vmi_get_function(VMI_CALL_GetWallclockTime);
-		vmi_timer_ops.wallclock_updated =
-			vmi_get_function(VMI_CALL_WallclockUpdated);
-		vmi_timer_ops.set_alarm = vmi_get_function(VMI_CALL_SetAlarm);
-		vmi_timer_ops.cancel_alarm =
-			 vmi_get_function(VMI_CALL_CancelAlarm);
-		x86_init.timers.timer_init = vmi_time_init;
-#ifdef CONFIG_X86_LOCAL_APIC
-		x86_init.timers.setup_percpu_clockev = vmi_time_bsp_init;
-		x86_cpuinit.setup_percpu_clockev = vmi_time_ap_init;
-#endif
-		pv_time_ops.sched_clock = vmi_sched_clock;
-		x86_platform.calibrate_tsc = vmi_tsc_khz;
-		x86_platform.get_wallclock = vmi_get_wallclock;
-		x86_platform.set_wallclock = vmi_set_wallclock;
-
-		/* We have true wallclock functions; disable CMOS clock sync */
-		no_sync_cmos_clock = 1;
-	} else {
-		disable_noidle = 1;
-		disable_vmi_timer = 1;
-	}
-
-	para_fill(pv_irq_ops.safe_halt, Halt);
-
-	/*
-	 * Alternative instruction rewriting doesn't happen soon enough
-	 * to convert VMI_IRET to a call instead of a jump; so we have
-	 * to do this before IRQs get reenabled.  Fortunately, it is
-	 * idempotent.
-	 */
-	apply_paravirt(__parainstructions, __parainstructions_end);
-
-	vmi_bringup();
-
-	return 1;
-}
-
-#undef para_fill
-
-void __init vmi_init(void)
-{
-	if (!vmi_rom)
-		probe_vmi_rom();
-	else
-		check_vmi_rom(vmi_rom);
-
-	/* In case probing for or validating the ROM failed, basil */
-	if (!vmi_rom)
-		return;
-
-	reserve_top_address(-vmi_rom->virtual_top);
-
-#ifdef CONFIG_X86_IO_APIC
-	/* This is virtual hardware; timer routing is wired correctly */
-	no_timer_check = 1;
-#endif
-}
-
-void __init vmi_activate(void)
-{
-	unsigned long flags;
-
-	if (!vmi_rom)
-		return;
-
-	local_irq_save(flags);
-	activate_vmi();
-	local_irq_restore(flags & X86_EFLAGS_IF);
-}
-
-static int __init parse_vmi(char *arg)
-{
-	if (!arg)
-		return -EINVAL;
-
-	if (!strcmp(arg, "disable_pge")) {
-		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE);
-		disable_pge = 1;
-	} else if (!strcmp(arg, "disable_pse")) {
-		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PSE);
-		disable_pse = 1;
-	} else if (!strcmp(arg, "disable_sep")) {
-		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP);
-		disable_sep = 1;
-	} else if (!strcmp(arg, "disable_tsc")) {
-		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC);
-		disable_tsc = 1;
-	} else if (!strcmp(arg, "disable_mtrr")) {
-		clear_cpu_cap(&boot_cpu_data, X86_FEATURE_MTRR);
-		disable_mtrr = 1;
-	} else if (!strcmp(arg, "disable_timer")) {
-		disable_vmi_timer = 1;
-		disable_noidle = 1;
-	} else if (!strcmp(arg, "disable_noidle"))
-		disable_noidle = 1;
-	return 0;
-}
-
-early_param("vmi", parse_vmi);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/vmiclock_32.c linux-libre-2.6.37-gnu/arch/x86/kernel/vmiclock_32.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/vmiclock_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/vmiclock_32.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,317 +0,0 @@
-/*
- * VMI paravirtual timer support routines.
- *
- * Copyright (C) 2007, VMware, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/cpumask.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-
-#include <asm/vmi.h>
-#include <asm/vmi_time.h>
-#include <asm/apicdef.h>
-#include <asm/apic.h>
-#include <asm/timer.h>
-#include <asm/i8253.h>
-#include <asm/irq_vectors.h>
-
-#define VMI_ONESHOT  (VMI_ALARM_IS_ONESHOT  | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
-#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
-
-static DEFINE_PER_CPU(struct clock_event_device, local_events);
-
-static inline u32 vmi_counter(u32 flags)
-{
-	/* Given VMI_ONESHOT or VMI_PERIODIC, return the corresponding
-	 * cycle counter. */
-	return flags & VMI_ALARM_COUNTER_MASK;
-}
-
-/* paravirt_ops.get_wallclock = vmi_get_wallclock */
-unsigned long vmi_get_wallclock(void)
-{
-	unsigned long long wallclock;
-	wallclock = vmi_timer_ops.get_wallclock(); // nsec
-	(void)do_div(wallclock, 1000000000);       // sec
-
-	return wallclock;
-}
-
-/* paravirt_ops.set_wallclock = vmi_set_wallclock */
-int vmi_set_wallclock(unsigned long now)
-{
-	return 0;
-}
-
-/* paravirt_ops.sched_clock = vmi_sched_clock */
-unsigned long long vmi_sched_clock(void)
-{
-	return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
-}
-
-/* x86_platform.calibrate_tsc = vmi_tsc_khz */
-unsigned long vmi_tsc_khz(void)
-{
-	unsigned long long khz;
-	khz = vmi_timer_ops.get_cycle_frequency();
-	(void)do_div(khz, 1000);
-	return khz;
-}
-
-static inline unsigned int vmi_get_timer_vector(void)
-{
-	return IRQ0_VECTOR;
-}
-
-/** vmi clockchip */
-#ifdef CONFIG_X86_LOCAL_APIC
-static unsigned int startup_timer_irq(unsigned int irq)
-{
-	unsigned long val = apic_read(APIC_LVTT);
-	apic_write(APIC_LVTT, vmi_get_timer_vector());
-
-	return (val & APIC_SEND_PENDING);
-}
-
-static void mask_timer_irq(unsigned int irq)
-{
-	unsigned long val = apic_read(APIC_LVTT);
-	apic_write(APIC_LVTT, val | APIC_LVT_MASKED);
-}
-
-static void unmask_timer_irq(unsigned int irq)
-{
-	unsigned long val = apic_read(APIC_LVTT);
-	apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED);
-}
-
-static void ack_timer_irq(unsigned int irq)
-{
-	ack_APIC_irq();
-}
-
-static struct irq_chip vmi_chip __read_mostly = {
-	.name 		= "VMI-LOCAL",
-	.startup 	= startup_timer_irq,
-	.mask	 	= mask_timer_irq,
-	.unmask	 	= unmask_timer_irq,
-	.ack 		= ack_timer_irq
-};
-#endif
-
-/** vmi clockevent */
-#define VMI_ALARM_WIRED_IRQ0    0x00000000
-#define VMI_ALARM_WIRED_LVTT    0x00010000
-static int vmi_wiring = VMI_ALARM_WIRED_IRQ0;
-
-static inline int vmi_get_alarm_wiring(void)
-{
-	return vmi_wiring;
-}
-
-static void vmi_timer_set_mode(enum clock_event_mode mode,
-			       struct clock_event_device *evt)
-{
-	cycle_t now, cycles_per_hz;
-	BUG_ON(!irqs_disabled());
-
-	switch (mode) {
-	case CLOCK_EVT_MODE_ONESHOT:
-	case CLOCK_EVT_MODE_RESUME:
-		break;
-	case CLOCK_EVT_MODE_PERIODIC:
-		cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
-		(void)do_div(cycles_per_hz, HZ);
-		now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC));
-		vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz);
-		break;
-	case CLOCK_EVT_MODE_UNUSED:
-	case CLOCK_EVT_MODE_SHUTDOWN:
-		switch (evt->mode) {
-		case CLOCK_EVT_MODE_ONESHOT:
-			vmi_timer_ops.cancel_alarm(VMI_ONESHOT);
-			break;
-		case CLOCK_EVT_MODE_PERIODIC:
-			vmi_timer_ops.cancel_alarm(VMI_PERIODIC);
-			break;
-		default:
-			break;
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-static int vmi_timer_next_event(unsigned long delta,
-				struct clock_event_device *evt)
-{
-	/* Unfortunately, set_next_event interface only passes relative
-	 * expiry, but we want absolute expiry.  It'd be better if were
-	 * were passed an absolute expiry, since a bunch of time may
-	 * have been stolen between the time the delta is computed and
-	 * when we set the alarm below. */
-	cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT));
-
-	BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
-	vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0);
-	return 0;
-}
-
-static struct clock_event_device vmi_clockevent = {
-	.name		= "vmi-timer",
-	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-	.shift		= 22,
-	.set_mode	= vmi_timer_set_mode,
-	.set_next_event = vmi_timer_next_event,
-	.rating         = 1000,
-	.irq		= 0,
-};
-
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
-{
-	struct clock_event_device *evt = &__get_cpu_var(local_events);
-	evt->event_handler(evt);
-	return IRQ_HANDLED;
-}
-
-static struct irqaction vmi_clock_action  = {
-	.name 		= "vmi-timer",
-	.handler 	= vmi_timer_interrupt,
-	.flags 		= IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
-};
-
-static void __devinit vmi_time_init_clockevent(void)
-{
-	cycle_t cycles_per_msec;
-	struct clock_event_device *evt;
-
-	int cpu = smp_processor_id();
-	evt = &__get_cpu_var(local_events);
-
-	/* Use cycles_per_msec since div_sc params are 32-bits. */
-	cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
-	(void)do_div(cycles_per_msec, 1000);
-
-	memcpy(evt, &vmi_clockevent, sizeof(*evt));
-	/* Must pick .shift such that .mult fits in 32-bits.  Choosing
-	 * .shift to be 22 allows 2^(32-22) cycles per nano-seconds
-	 * before overflow. */
-	evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift);
-	/* Upper bound is clockevent's use of ulong for cycle deltas. */
-	evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt);
-	evt->min_delta_ns = clockevent_delta2ns(1, evt);
-	evt->cpumask = cpumask_of(cpu);
-
-	printk(KERN_WARNING "vmi: registering clock event %s. mult=%u shift=%u\n",
-	       evt->name, evt->mult, evt->shift);
-	clockevents_register_device(evt);
-}
-
-void __init vmi_time_init(void)
-{
-	unsigned int cpu;
-	/* Disable PIT: BIOSes start PIT CH0 with 18.2hz peridic. */
-	outb_pit(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
-
-	vmi_time_init_clockevent();
-	setup_irq(0, &vmi_clock_action);
-	for_each_possible_cpu(cpu)
-		per_cpu(vector_irq, cpu)[vmi_get_timer_vector()] = 0;
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-void __devinit vmi_time_bsp_init(void)
-{
-	/*
-	 * On APIC systems, we want local timers to fire on each cpu.  We do
-	 * this by programming LVTT to deliver timer events to the IRQ handler
-	 * for IRQ-0, since we can't re-use the APIC local timer handler
-	 * without interfering with that code.
-	 */
-	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
-	local_irq_disable();
-#ifdef CONFIG_SMP
-	/*
-	 * XXX handle_percpu_irq only defined for SMP; we need to switch over
-	 * to using it, since this is a local interrupt, which each CPU must
-	 * handle individually without locking out or dropping simultaneous
-	 * local timers on other CPUs.  We also don't want to trigger the
-	 * quirk workaround code for interrupts which gets invoked from
-	 * handle_percpu_irq via eoi, so we use our own IRQ chip.
-	 */
-	set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt");
-#else
-	set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt");
-#endif
-	vmi_wiring = VMI_ALARM_WIRED_LVTT;
-	apic_write(APIC_LVTT, vmi_get_timer_vector());
-	local_irq_enable();
-	clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
-}
-
-void __devinit vmi_time_ap_init(void)
-{
-	vmi_time_init_clockevent();
-	apic_write(APIC_LVTT, vmi_get_timer_vector());
-}
-#endif
-
-/** vmi clocksource */
-static struct clocksource clocksource_vmi;
-
-static cycle_t read_real_cycles(struct clocksource *cs)
-{
-	cycle_t ret = (cycle_t)vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
-	return max(ret, clocksource_vmi.cycle_last);
-}
-
-static struct clocksource clocksource_vmi = {
-	.name			= "vmi-timer",
-	.rating			= 450,
-	.read			= read_real_cycles,
-	.mask			= CLOCKSOURCE_MASK(64),
-	.mult			= 0, /* to be set */
-	.shift			= 22,
-	.flags			= CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init init_vmi_clocksource(void)
-{
-	cycle_t cycles_per_msec;
-
-	if (!vmi_timer_ops.get_cycle_frequency)
-		return 0;
-	/* Use khz2mult rather than hz2mult since hz arg is only 32-bits. */
-	cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
-	(void)do_div(cycles_per_msec, 1000);
-
-	/* Note that clocksource.{mult, shift} converts in the opposite direction
-	 * as clockevents.  */
-	clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
-						    clocksource_vmi.shift);
-
-	printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec);
-	return clocksource_register(&clocksource_vmi);
-
-}
-module_init(init_vmi_clocksource);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/vmlinux.lds.S linux-libre-2.6.37-gnu/arch/x86/kernel/vmlinux.lds.S
--- linux-libre-2.6.36-gnu/arch/x86/kernel/vmlinux.lds.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/vmlinux.lds.S	2011-01-04 19:50:19.000000000 -0500
@@ -242,6 +242,12 @@
 		__x86_cpu_dev_end = .;
 	}
 
+	/*
+	 * start address and size of operations which during runtime
+	 * can be patched with virtualization friendly instructions or
+	 * baremetal native ones. Think page table operations.
+	 * Details in paravirt_types.h
+	 */
 	. = ALIGN(8);
 	.parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
 		__parainstructions = .;
@@ -249,6 +255,11 @@
 		__parainstructions_end = .;
 	}
 
+	/*
+	 * struct alt_inst entries. From the header (alternative.h):
+	 * "Alternative instructions for different CPU types or capabilities"
+	 * Think locking instructions on spinlocks.
+	 */
 	. = ALIGN(8);
 	.altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
 		__alt_instructions = .;
@@ -256,11 +267,28 @@
 		__alt_instructions_end = .;
 	}
 
+	/*
+	 * And here are the replacement instructions. The linker sticks
+	 * them as binary blobs. The .altinstructions has enough data to
+	 * get the address and the length of them to patch the kernel safely.
+	 */
 	.altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
 		*(.altinstr_replacement)
 	}
 
 	/*
+	 * struct iommu_table_entry entries are injected in this section.
+	 * It is an array of IOMMUs which during run time gets sorted depending
+	 * on its dependency order. After rootfs_initcall is complete
+	 * this section can be safely removed.
+	 */
+	.iommu_table : AT(ADDR(.iommu_table) - LOAD_OFFSET) {
+		__iommu_table = .;
+		*(.iommu_table)
+		__iommu_table_end = .;
+	}
+	. = ALIGN(8);
+	/*
 	 * .exit.text is discard at runtime, not link time, to deal with
 	 *  references from .altinstructions and .eh_frame
 	 */
@@ -273,7 +301,7 @@
 	}
 
 #if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
-	PERCPU(PAGE_SIZE)
+	PERCPU(THREAD_SIZE)
 #endif
 
 	. = ALIGN(PAGE_SIZE);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/x86_init.c linux-libre-2.6.37-gnu/arch/x86/kernel/x86_init.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/x86_init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/x86_init.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,10 +6,12 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 
 #include <asm/bios_ebda.h>
 #include <asm/paravirt.h>
 #include <asm/pci_x86.h>
+#include <asm/pci.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
 #include <asm/apic.h>
@@ -99,3 +101,8 @@
 };
 
 EXPORT_SYMBOL_GPL(x86_platform);
+struct x86_msi_ops x86_msi = {
+	.setup_msi_irqs = native_setup_msi_irqs,
+	.teardown_msi_irq = native_teardown_msi_irq,
+	.teardown_msi_irqs = default_teardown_msi_irqs,
+};
diff -druN linux-libre-2.6.36-gnu/arch/x86/kernel/xsave.c linux-libre-2.6.37-gnu/arch/x86/kernel/xsave.c
--- linux-libre-2.6.36-gnu/arch/x86/kernel/xsave.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kernel/xsave.c	2011-01-04 19:50:19.000000000 -0500
@@ -394,7 +394,8 @@
 	 * Setup init_xstate_buf to represent the init state of
 	 * all the features managed by the xsave
 	 */
-	init_xstate_buf = alloc_bootmem(xstate_size);
+	init_xstate_buf = alloc_bootmem_align(xstate_size,
+					      __alignof__(struct xsave_struct));
 	init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
 
 	clts();
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/emulate.c linux-libre-2.6.37-gnu/arch/x86/kvm/emulate.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/emulate.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/emulate.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,7 @@
  * privileged instructions:
  *
  * Copyright (C) 2006 Qumranet
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  *   Avi Kivity <avi@qumranet.com>
  *   Yaniv Kamay <yaniv@qumranet.com>
@@ -51,13 +51,13 @@
 #define ImplicitOps (1<<1)	/* Implicit in opcode. No generic decode. */
 #define DstReg      (2<<1)	/* Register operand. */
 #define DstMem      (3<<1)	/* Memory operand. */
-#define DstAcc      (4<<1)      /* Destination Accumulator */
+#define DstAcc      (4<<1)	/* Destination Accumulator */
 #define DstDI       (5<<1)	/* Destination is in ES:(E)DI */
 #define DstMem64    (6<<1)	/* 64bit memory operand */
+#define DstImmUByte (7<<1)	/* 8-bit unsigned immediate operand */
 #define DstMask     (7<<1)
 /* Source operand type. */
 #define SrcNone     (0<<4)	/* No source operand. */
-#define SrcImplicit (0<<4)	/* Source operand is implicit in the opcode. */
 #define SrcReg      (1<<4)	/* Register operand. */
 #define SrcMem      (2<<4)	/* Memory operand. */
 #define SrcMem16    (3<<4)	/* Memory operand (16-bit). */
@@ -71,6 +71,7 @@
 #define SrcImmFAddr (0xb<<4)	/* Source is immediate far address */
 #define SrcMemFAddr (0xc<<4)	/* Source is far address in memory */
 #define SrcAcc      (0xd<<4)	/* Source Accumulator */
+#define SrcImmU16   (0xe<<4)    /* Immediate operand, unsigned, 16 bits */
 #define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
 #define ModRM       (1<<8)
@@ -82,8 +83,10 @@
 #define Stack       (1<<13)     /* Stack instruction (push/pop) */
 #define Group       (1<<14)     /* Bits 3:5 of modrm byte extend opcode */
 #define GroupDual   (1<<15)     /* Alternate decoding of mod == 3 */
-#define GroupMask   0xff        /* Group number stored in bits 0:7 */
 /* Misc flags */
+#define NoAccess    (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
+#define Op3264      (1<<24) /* Operand is 64b in long mode, 32b otherwise */
+#define Undefined   (1<<25) /* No Such Instruction */
 #define Lock        (1<<26) /* lock prefix is allowed for the instruction */
 #define Priv        (1<<27) /* instruction generates #GP if current CPL != 0 */
 #define No64	    (1<<28)
@@ -92,285 +95,30 @@
 #define Src2CL      (1<<29)
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
+#define Src2Imm     (4<<29)
 #define Src2Mask    (7<<29)
 
-enum {
-	Group1_80, Group1_81, Group1_82, Group1_83,
-	Group1A, Group3_Byte, Group3, Group4, Group5, Group7,
-	Group8, Group9,
-};
-
-static u32 opcode_table[256] = {
-	/* 0x00 - 0x07 */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
-	ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
-	/* 0x08 - 0x0F */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
-	ImplicitOps | Stack | No64, 0,
-	/* 0x10 - 0x17 */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
-	ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
-	/* 0x18 - 0x1F */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
-	ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
-	/* 0x20 - 0x27 */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
-	/* 0x28 - 0x2F */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
-	/* 0x30 - 0x37 */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
-	/* 0x38 - 0x3F */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
-	0, 0,
-	/* 0x40 - 0x47 */
-	DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
-	/* 0x48 - 0x4F */
-	DstReg, DstReg, DstReg, DstReg,	DstReg, DstReg, DstReg, DstReg,
-	/* 0x50 - 0x57 */
-	SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack,
-	SrcReg | Stack, SrcReg | Stack, SrcReg | Stack, SrcReg | Stack,
-	/* 0x58 - 0x5F */
-	DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
-	DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
-	/* 0x60 - 0x67 */
-	ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
-	0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
-	0, 0, 0, 0,
-	/* 0x68 - 0x6F */
-	SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
-	DstDI | ByteOp | Mov | String, DstDI | Mov | String, /* insb, insw/insd */
-	SrcSI | ByteOp | ImplicitOps | String, SrcSI | ImplicitOps | String, /* outsb, outsw/outsd */
-	/* 0x70 - 0x77 */
-	SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
-	SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
-	/* 0x78 - 0x7F */
-	SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
-	SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
-	/* 0x80 - 0x87 */
-	Group | Group1_80, Group | Group1_81,
-	Group | Group1_82, Group | Group1_83,
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	/* 0x88 - 0x8F */
-	ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
-	ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstMem | SrcNone | ModRM | Mov, ModRM | DstReg,
-	ImplicitOps | SrcMem16 | ModRM, Group | Group1A,
-	/* 0x90 - 0x97 */
-	DstReg, DstReg, DstReg, DstReg,	DstReg, DstReg, DstReg, DstReg,
-	/* 0x98 - 0x9F */
-	0, 0, SrcImmFAddr | No64, 0,
-	ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
-	/* 0xA0 - 0xA7 */
-	ByteOp | DstAcc | SrcMem | Mov | MemAbs, DstAcc | SrcMem | Mov | MemAbs,
-	ByteOp | DstMem | SrcAcc | Mov | MemAbs, DstMem | SrcAcc | Mov | MemAbs,
-	ByteOp | SrcSI | DstDI | Mov | String, SrcSI | DstDI | Mov | String,
-	ByteOp | SrcSI | DstDI | String, SrcSI | DstDI | String,
-	/* 0xA8 - 0xAF */
-	DstAcc | SrcImmByte | ByteOp, DstAcc | SrcImm, ByteOp | DstDI | Mov | String, DstDI | Mov | String,
-	ByteOp | SrcSI | DstAcc | Mov | String, SrcSI | DstAcc | Mov | String,
-	ByteOp | DstDI | String, DstDI | String,
-	/* 0xB0 - 0xB7 */
-	ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
-	ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
-	ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
-	ByteOp | DstReg | SrcImm | Mov, ByteOp | DstReg | SrcImm | Mov,
-	/* 0xB8 - 0xBF */
-	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
-	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
-	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
-	DstReg | SrcImm | Mov, DstReg | SrcImm | Mov,
-	/* 0xC0 - 0xC7 */
-	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
-	0, ImplicitOps | Stack, 0, 0,
-	ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
-	/* 0xC8 - 0xCF */
-	0, 0, 0, ImplicitOps | Stack,
-	ImplicitOps, SrcImmByte, ImplicitOps | No64, ImplicitOps,
-	/* 0xD0 - 0xD7 */
-	ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
-	ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
-	0, 0, 0, 0,
-	/* 0xD8 - 0xDF */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xE0 - 0xE7 */
-	0, 0, 0, 0,
-	ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
-	ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
-	/* 0xE8 - 0xEF */
-	SrcImm | Stack, SrcImm | ImplicitOps,
-	SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
-	SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
-	SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
-	/* 0xF0 - 0xF7 */
-	0, 0, 0, 0,
-	ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
-	/* 0xF8 - 0xFF */
-	ImplicitOps, 0, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, Group | Group4, Group | Group5,
-};
-
-static u32 twobyte_table[256] = {
-	/* 0x00 - 0x0F */
-	0, Group | GroupDual | Group7, 0, 0,
-	0, ImplicitOps, ImplicitOps | Priv, 0,
-	ImplicitOps | Priv, ImplicitOps | Priv, 0, 0,
-	0, ImplicitOps | ModRM, 0, 0,
-	/* 0x10 - 0x1F */
-	0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x20 - 0x2F */
-	ModRM | ImplicitOps | Priv, ModRM | Priv,
-	ModRM | ImplicitOps | Priv, ModRM | Priv,
-	0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x30 - 0x3F */
-	ImplicitOps | Priv, 0, ImplicitOps | Priv, 0,
-	ImplicitOps, ImplicitOps | Priv, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x40 - 0x47 */
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	/* 0x48 - 0x4F */
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	/* 0x50 - 0x5F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x60 - 0x6F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x70 - 0x7F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x80 - 0x8F */
-	SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
-	SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm, SrcImm,
-	/* 0x90 - 0x9F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xA0 - 0xA7 */
-	ImplicitOps | Stack, ImplicitOps | Stack,
-	0, DstMem | SrcReg | ModRM | BitOp,
-	DstMem | SrcReg | Src2ImmByte | ModRM,
-	DstMem | SrcReg | Src2CL | ModRM, 0, 0,
-	/* 0xA8 - 0xAF */
-	ImplicitOps | Stack, ImplicitOps | Stack,
-	0, DstMem | SrcReg | ModRM | BitOp | Lock,
-	DstMem | SrcReg | Src2ImmByte | ModRM,
-	DstMem | SrcReg | Src2CL | ModRM,
-	ModRM, 0,
-	/* 0xB0 - 0xB7 */
-	ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
-	0, DstMem | SrcReg | ModRM | BitOp | Lock,
-	0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
-	    DstReg | SrcMem16 | ModRM | Mov,
-	/* 0xB8 - 0xBF */
-	0, 0,
-	Group | Group8, DstMem | SrcReg | ModRM | BitOp | Lock,
-	0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
-	    DstReg | SrcMem16 | ModRM | Mov,
-	/* 0xC0 - 0xCF */
-	0, 0, 0, DstMem | SrcReg | ModRM | Mov,
-	0, 0, 0, Group | GroupDual | Group9,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xD0 - 0xDF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xE0 - 0xEF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xF0 - 0xFF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
+#define X2(x...) x, x
+#define X3(x...) X2(x), x
+#define X4(x...) X2(x), X2(x)
+#define X5(x...) X4(x), x
+#define X6(x...) X4(x), X2(x)
+#define X7(x...) X4(x), X3(x)
+#define X8(x...) X4(x), X4(x)
+#define X16(x...) X8(x), X8(x)
 
-static u32 group_table[] = {
-	[Group1_80*8] =
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | Lock,
-	ByteOp | DstMem | SrcImm | ModRM,
-	[Group1_81*8] =
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM | Lock,
-	DstMem | SrcImm | ModRM,
-	[Group1_82*8] =
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
-	ByteOp | DstMem | SrcImm | ModRM | No64,
-	[Group1_83*8] =
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM,
-	[Group1A*8] =
-	DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
-	[Group3_Byte*8] =
-	ByteOp | SrcImm | DstMem | ModRM, ByteOp | SrcImm | DstMem | ModRM,
-	ByteOp | DstMem | SrcNone | ModRM, ByteOp | DstMem | SrcNone | ModRM,
-	0, 0, 0, 0,
-	[Group3*8] =
-	DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
-	DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
-	0, 0, 0, 0,
-	[Group4*8] =
-	ByteOp | DstMem | SrcNone | ModRM | Lock, ByteOp | DstMem | SrcNone | ModRM | Lock,
-	0, 0, 0, 0, 0, 0,
-	[Group5*8] =
-	DstMem | SrcNone | ModRM | Lock, DstMem | SrcNone | ModRM | Lock,
-	SrcMem | ModRM | Stack, 0,
-	SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
-	SrcMem | ModRM | Stack, 0,
-	[Group7*8] =
-	0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
-	SrcNone | ModRM | DstMem | Mov, 0,
-	SrcMem16 | ModRM | Mov | Priv, SrcMem | ModRM | ByteOp | Priv,
-	[Group8*8] =
-	0, 0, 0, 0,
-	DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
-	DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
-	[Group9*8] =
-	0, DstMem64 | ModRM | Lock, 0, 0, 0, 0, 0, 0,
+struct opcode {
+	u32 flags;
+	union {
+		int (*execute)(struct x86_emulate_ctxt *ctxt);
+		struct opcode *group;
+		struct group_dual *gdual;
+	} u;
 };
 
-static u32 group2_table[] = {
-	[Group7*8] =
-	SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM | Priv,
-	SrcNone | ModRM | DstMem | Mov, 0,
-	SrcMem16 | ModRM | Mov | Priv, 0,
-	[Group9*8] =
-	0, 0, 0, 0, 0, 0, 0, 0,
+struct group_dual {
+	struct opcode mod012[8];
+	struct opcode mod3[8];
 };
 
 /* EFLAGS bit definitions. */
@@ -392,6 +140,9 @@
 #define EFLG_PF (1<<2)
 #define EFLG_CF (1<<0)
 
+#define EFLG_RESERVED_ZEROS_MASK 0xffc0802a
+#define EFLG_RESERVED_ONE_MASK 2
+
 /*
  * Instruction emulation:
  * Most instructions are emulated directly via a fragment of inline assembly
@@ -444,13 +195,13 @@
 #define ON64(x)
 #endif
 
-#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix)	\
+#define ____emulate_2op(_op, _src, _dst, _eflags, _x, _y, _suffix, _dsttype) \
 	do {								\
 		__asm__ __volatile__ (					\
 			_PRE_EFLAGS("0", "4", "2")			\
 			_op _suffix " %"_x"3,%1; "			\
 			_POST_EFLAGS("0", "4", "2")			\
-			: "=m" (_eflags), "=m" ((_dst).val),		\
+			: "=m" (_eflags), "+q" (*(_dsttype*)&(_dst).val),\
 			  "=&r" (_tmp)					\
 			: _y ((_src).val), "i" (EFLAGS_MASK));		\
 	} while (0)
@@ -463,13 +214,13 @@
 									\
 		switch ((_dst).bytes) {					\
 		case 2:							\
-			____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w"); \
+			____emulate_2op(_op,_src,_dst,_eflags,_wx,_wy,"w",u16);\
 			break;						\
 		case 4:							\
-			____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l"); \
+			____emulate_2op(_op,_src,_dst,_eflags,_lx,_ly,"l",u32);\
 			break;						\
 		case 8:							\
-			ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q")); \
+			ON64(____emulate_2op(_op,_src,_dst,_eflags,_qx,_qy,"q",u64)); \
 			break;						\
 		}							\
 	} while (0)
@@ -479,7 +230,7 @@
 		unsigned long _tmp;					     \
 		switch ((_dst).bytes) {				             \
 		case 1:							     \
-			____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b");  \
+			____emulate_2op(_op,_src,_dst,_eflags,_bx,_by,"b",u8); \
 			break;						     \
 		default:						     \
 			__emulate_2op_nobyte(_op, _src, _dst, _eflags,	     \
@@ -566,6 +317,74 @@
 		}							\
 	} while (0)
 
+#define __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, _suffix)		\
+	do {								\
+		unsigned long _tmp;					\
+									\
+		__asm__ __volatile__ (					\
+			_PRE_EFLAGS("0", "4", "1")			\
+			_op _suffix " %5; "				\
+			_POST_EFLAGS("0", "4", "1")			\
+			: "=m" (_eflags), "=&r" (_tmp),			\
+			  "+a" (_rax), "+d" (_rdx)			\
+			: "i" (EFLAGS_MASK), "m" ((_src).val),		\
+			  "a" (_rax), "d" (_rdx));			\
+	} while (0)
+
+#define __emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _suffix, _ex) \
+	do {								\
+		unsigned long _tmp;					\
+									\
+		__asm__ __volatile__ (					\
+			_PRE_EFLAGS("0", "5", "1")			\
+			"1: \n\t"					\
+			_op _suffix " %6; "				\
+			"2: \n\t"					\
+			_POST_EFLAGS("0", "5", "1")			\
+			".pushsection .fixup,\"ax\" \n\t"		\
+			"3: movb $1, %4 \n\t"				\
+			"jmp 2b \n\t"					\
+			".popsection \n\t"				\
+			_ASM_EXTABLE(1b, 3b)				\
+			: "=m" (_eflags), "=&r" (_tmp),			\
+			  "+a" (_rax), "+d" (_rdx), "+qm"(_ex)		\
+			: "i" (EFLAGS_MASK), "m" ((_src).val),		\
+			  "a" (_rax), "d" (_rdx));			\
+	} while (0)
+
+/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
+#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags)			\
+	do {									\
+		switch((_src).bytes) {						\
+		case 1: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "b"); break; \
+		case 2: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx,  _eflags, "w"); break; \
+		case 4: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "l"); break; \
+		case 8: ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "q")); break; \
+		}							\
+	} while (0)
+
+#define emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, _eflags, _ex)	\
+	do {								\
+		switch((_src).bytes) {					\
+		case 1:							\
+			__emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx,	\
+						 _eflags, "b", _ex);	\
+			break;						\
+		case 2:							\
+			__emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+						 _eflags, "w", _ex);	\
+			break;						\
+		case 4:							\
+			__emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+						 _eflags, "l", _ex);	\
+			break;						\
+		case 8: ON64(						\
+			__emulate_1op_rax_rdx_ex(_op, _src, _rax, _rdx, \
+						 _eflags, "q", _ex));	\
+			break;						\
+		}							\
+	} while (0)
+
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch(_type, _size, _eip)                                  \
 ({	unsigned long _x;						\
@@ -661,7 +480,6 @@
 	ctxt->exception = vec;
 	ctxt->error_code = error;
 	ctxt->error_code_valid = valid;
-	ctxt->restart = false;
 }
 
 static void emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
@@ -669,11 +487,9 @@
 	emulate_exception(ctxt, GP_VECTOR, err, true);
 }
 
-static void emulate_pf(struct x86_emulate_ctxt *ctxt, unsigned long addr,
-		       int err)
+static void emulate_pf(struct x86_emulate_ctxt *ctxt)
 {
-	ctxt->cr2 = addr;
-	emulate_exception(ctxt, PF_VECTOR, err, true);
+	emulate_exception(ctxt, PF_VECTOR, 0, true);
 }
 
 static void emulate_ud(struct x86_emulate_ctxt *ctxt)
@@ -686,6 +502,12 @@
 	emulate_exception(ctxt, TS_VECTOR, err, true);
 }
 
+static int emulate_de(struct x86_emulate_ctxt *ctxt)
+{
+	emulate_exception(ctxt, DE_VECTOR, 0, false);
+	return X86EMUL_PROPAGATE_FAULT;
+}
+
 static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
 			      struct x86_emulate_ops *ops,
 			      unsigned long eip, u8 *dest)
@@ -742,7 +564,7 @@
 
 static int read_descriptor(struct x86_emulate_ctxt *ctxt,
 			   struct x86_emulate_ops *ops,
-			   void *ptr,
+			   ulong addr,
 			   u16 *size, unsigned long *address, int op_bytes)
 {
 	int rc;
@@ -750,12 +572,10 @@
 	if (op_bytes == 2)
 		op_bytes = 3;
 	*address = 0;
-	rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
-			   ctxt->vcpu, NULL);
+	rc = ops->read_std(addr, (unsigned long *)size, 2, ctxt->vcpu, NULL);
 	if (rc != X86EMUL_CONTINUE)
 		return rc;
-	rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
-			   ctxt->vcpu, NULL);
+	rc = ops->read_std(addr + 2, address, op_bytes, ctxt->vcpu, NULL);
 	return rc;
 }
 
@@ -794,6 +614,24 @@
 	return (!!rc ^ (condition & 1));
 }
 
+static void fetch_register_operand(struct operand *op)
+{
+	switch (op->bytes) {
+	case 1:
+		op->val = *(u8 *)op->addr.reg;
+		break;
+	case 2:
+		op->val = *(u16 *)op->addr.reg;
+		break;
+	case 4:
+		op->val = *(u32 *)op->addr.reg;
+		break;
+	case 8:
+		op->val = *(u64 *)op->addr.reg;
+		break;
+	}
+}
+
 static void decode_register_operand(struct operand *op,
 				    struct decode_cache *c,
 				    int inhibit_bytereg)
@@ -805,34 +643,25 @@
 		reg = (c->b & 7) | ((c->rex_prefix & 1) << 3);
 	op->type = OP_REG;
 	if ((c->d & ByteOp) && !inhibit_bytereg) {
-		op->ptr = decode_register(reg, c->regs, highbyte_regs);
-		op->val = *(u8 *)op->ptr;
+		op->addr.reg = decode_register(reg, c->regs, highbyte_regs);
 		op->bytes = 1;
 	} else {
-		op->ptr = decode_register(reg, c->regs, 0);
+		op->addr.reg = decode_register(reg, c->regs, 0);
 		op->bytes = c->op_bytes;
-		switch (op->bytes) {
-		case 2:
-			op->val = *(u16 *)op->ptr;
-			break;
-		case 4:
-			op->val = *(u32 *)op->ptr;
-			break;
-		case 8:
-			op->val = *(u64 *) op->ptr;
-			break;
-		}
 	}
+	fetch_register_operand(op);
 	op->orig_val = op->val;
 }
 
 static int decode_modrm(struct x86_emulate_ctxt *ctxt,
-			struct x86_emulate_ops *ops)
+			struct x86_emulate_ops *ops,
+			struct operand *op)
 {
 	struct decode_cache *c = &ctxt->decode;
 	u8 sib;
 	int index_reg = 0, base_reg = 0, scale;
 	int rc = X86EMUL_CONTINUE;
+	ulong modrm_ea = 0;
 
 	if (c->rex_prefix) {
 		c->modrm_reg = (c->rex_prefix & 4) << 1;	/* REX.R */
@@ -844,16 +673,19 @@
 	c->modrm_mod |= (c->modrm & 0xc0) >> 6;
 	c->modrm_reg |= (c->modrm & 0x38) >> 3;
 	c->modrm_rm |= (c->modrm & 0x07);
-	c->modrm_ea = 0;
-	c->use_modrm_ea = 1;
+	c->modrm_seg = VCPU_SREG_DS;
 
 	if (c->modrm_mod == 3) {
-		c->modrm_ptr = decode_register(c->modrm_rm,
+		op->type = OP_REG;
+		op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		op->addr.reg = decode_register(c->modrm_rm,
 					       c->regs, c->d & ByteOp);
-		c->modrm_val = *(unsigned long *)c->modrm_ptr;
+		fetch_register_operand(op);
 		return rc;
 	}
 
+	op->type = OP_MEM;
+
 	if (c->ad_bytes == 2) {
 		unsigned bx = c->regs[VCPU_REGS_RBX];
 		unsigned bp = c->regs[VCPU_REGS_RBP];
@@ -864,47 +696,46 @@
 		switch (c->modrm_mod) {
 		case 0:
 			if (c->modrm_rm == 6)
-				c->modrm_ea += insn_fetch(u16, 2, c->eip);
+				modrm_ea += insn_fetch(u16, 2, c->eip);
 			break;
 		case 1:
-			c->modrm_ea += insn_fetch(s8, 1, c->eip);
+			modrm_ea += insn_fetch(s8, 1, c->eip);
 			break;
 		case 2:
-			c->modrm_ea += insn_fetch(u16, 2, c->eip);
+			modrm_ea += insn_fetch(u16, 2, c->eip);
 			break;
 		}
 		switch (c->modrm_rm) {
 		case 0:
-			c->modrm_ea += bx + si;
+			modrm_ea += bx + si;
 			break;
 		case 1:
-			c->modrm_ea += bx + di;
+			modrm_ea += bx + di;
 			break;
 		case 2:
-			c->modrm_ea += bp + si;
+			modrm_ea += bp + si;
 			break;
 		case 3:
-			c->modrm_ea += bp + di;
+			modrm_ea += bp + di;
 			break;
 		case 4:
-			c->modrm_ea += si;
+			modrm_ea += si;
 			break;
 		case 5:
-			c->modrm_ea += di;
+			modrm_ea += di;
 			break;
 		case 6:
 			if (c->modrm_mod != 0)
-				c->modrm_ea += bp;
+				modrm_ea += bp;
 			break;
 		case 7:
-			c->modrm_ea += bx;
+			modrm_ea += bx;
 			break;
 		}
 		if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
 		    (c->modrm_rm == 6 && c->modrm_mod != 0))
-			if (!c->has_seg_override)
-				set_seg_override(c, VCPU_SREG_SS);
-		c->modrm_ea = (u16)c->modrm_ea;
+			c->modrm_seg = VCPU_SREG_SS;
+		modrm_ea = (u16)modrm_ea;
 	} else {
 		/* 32/64-bit ModR/M decode. */
 		if ((c->modrm_rm & 7) == 4) {
@@ -914,410 +745,74 @@
 			scale = sib >> 6;
 
 			if ((base_reg & 7) == 5 && c->modrm_mod == 0)
-				c->modrm_ea += insn_fetch(s32, 4, c->eip);
+				modrm_ea += insn_fetch(s32, 4, c->eip);
 			else
-				c->modrm_ea += c->regs[base_reg];
+				modrm_ea += c->regs[base_reg];
 			if (index_reg != 4)
-				c->modrm_ea += c->regs[index_reg] << scale;
+				modrm_ea += c->regs[index_reg] << scale;
 		} else if ((c->modrm_rm & 7) == 5 && c->modrm_mod == 0) {
 			if (ctxt->mode == X86EMUL_MODE_PROT64)
 				c->rip_relative = 1;
 		} else
-			c->modrm_ea += c->regs[c->modrm_rm];
+			modrm_ea += c->regs[c->modrm_rm];
 		switch (c->modrm_mod) {
 		case 0:
 			if (c->modrm_rm == 5)
-				c->modrm_ea += insn_fetch(s32, 4, c->eip);
+				modrm_ea += insn_fetch(s32, 4, c->eip);
 			break;
 		case 1:
-			c->modrm_ea += insn_fetch(s8, 1, c->eip);
+			modrm_ea += insn_fetch(s8, 1, c->eip);
 			break;
 		case 2:
-			c->modrm_ea += insn_fetch(s32, 4, c->eip);
+			modrm_ea += insn_fetch(s32, 4, c->eip);
 			break;
 		}
 	}
+	op->addr.mem = modrm_ea;
 done:
 	return rc;
 }
 
 static int decode_abs(struct x86_emulate_ctxt *ctxt,
-		      struct x86_emulate_ops *ops)
+		      struct x86_emulate_ops *ops,
+		      struct operand *op)
 {
 	struct decode_cache *c = &ctxt->decode;
 	int rc = X86EMUL_CONTINUE;
 
+	op->type = OP_MEM;
 	switch (c->ad_bytes) {
 	case 2:
-		c->modrm_ea = insn_fetch(u16, 2, c->eip);
+		op->addr.mem = insn_fetch(u16, 2, c->eip);
 		break;
 	case 4:
-		c->modrm_ea = insn_fetch(u32, 4, c->eip);
+		op->addr.mem = insn_fetch(u32, 4, c->eip);
 		break;
 	case 8:
-		c->modrm_ea = insn_fetch(u64, 8, c->eip);
+		op->addr.mem = insn_fetch(u64, 8, c->eip);
 		break;
 	}
 done:
 	return rc;
 }
 
-int
-x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+static void fetch_bit_operand(struct decode_cache *c)
 {
-	struct decode_cache *c = &ctxt->decode;
-	int rc = X86EMUL_CONTINUE;
-	int mode = ctxt->mode;
-	int def_op_bytes, def_ad_bytes, group;
-
-
-	/* we cannot decode insn before we complete previous rep insn */
-	WARN_ON(ctxt->restart);
-
-	c->eip = ctxt->eip;
-	c->fetch.start = c->fetch.end = c->eip;
-	ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
-
-	switch (mode) {
-	case X86EMUL_MODE_REAL:
-	case X86EMUL_MODE_VM86:
-	case X86EMUL_MODE_PROT16:
-		def_op_bytes = def_ad_bytes = 2;
-		break;
-	case X86EMUL_MODE_PROT32:
-		def_op_bytes = def_ad_bytes = 4;
-		break;
-#ifdef CONFIG_X86_64
-	case X86EMUL_MODE_PROT64:
-		def_op_bytes = 4;
-		def_ad_bytes = 8;
-		break;
-#endif
-	default:
-		return -1;
-	}
-
-	c->op_bytes = def_op_bytes;
-	c->ad_bytes = def_ad_bytes;
-
-	/* Legacy prefixes. */
-	for (;;) {
-		switch (c->b = insn_fetch(u8, 1, c->eip)) {
-		case 0x66:	/* operand-size override */
-			/* switch between 2/4 bytes */
-			c->op_bytes = def_op_bytes ^ 6;
-			break;
-		case 0x67:	/* address-size override */
-			if (mode == X86EMUL_MODE_PROT64)
-				/* switch between 4/8 bytes */
-				c->ad_bytes = def_ad_bytes ^ 12;
-			else
-				/* switch between 2/4 bytes */
-				c->ad_bytes = def_ad_bytes ^ 6;
-			break;
-		case 0x26:	/* ES override */
-		case 0x2e:	/* CS override */
-		case 0x36:	/* SS override */
-		case 0x3e:	/* DS override */
-			set_seg_override(c, (c->b >> 3) & 3);
-			break;
-		case 0x64:	/* FS override */
-		case 0x65:	/* GS override */
-			set_seg_override(c, c->b & 7);
-			break;
-		case 0x40 ... 0x4f: /* REX */
-			if (mode != X86EMUL_MODE_PROT64)
-				goto done_prefixes;
-			c->rex_prefix = c->b;
-			continue;
-		case 0xf0:	/* LOCK */
-			c->lock_prefix = 1;
-			break;
-		case 0xf2:	/* REPNE/REPNZ */
-			c->rep_prefix = REPNE_PREFIX;
-			break;
-		case 0xf3:	/* REP/REPE/REPZ */
-			c->rep_prefix = REPE_PREFIX;
-			break;
-		default:
-			goto done_prefixes;
-		}
-
-		/* Any legacy prefix after a REX prefix nullifies its effect. */
-
-		c->rex_prefix = 0;
-	}
-
-done_prefixes:
-
-	/* REX prefix. */
-	if (c->rex_prefix)
-		if (c->rex_prefix & 8)
-			c->op_bytes = 8;	/* REX.W */
-
-	/* Opcode byte(s). */
-	c->d = opcode_table[c->b];
-	if (c->d == 0) {
-		/* Two-byte opcode? */
-		if (c->b == 0x0f) {
-			c->twobyte = 1;
-			c->b = insn_fetch(u8, 1, c->eip);
-			c->d = twobyte_table[c->b];
-		}
-	}
-
-	if (c->d & Group) {
-		group = c->d & GroupMask;
-		c->modrm = insn_fetch(u8, 1, c->eip);
-		--c->eip;
-
-		group = (group << 3) + ((c->modrm >> 3) & 7);
-		if ((c->d & GroupDual) && (c->modrm >> 6) == 3)
-			c->d = group2_table[group];
-		else
-			c->d = group_table[group];
-	}
-
-	/* Unrecognised? */
-	if (c->d == 0) {
-		DPRINTF("Cannot emulate %02x\n", c->b);
-		return -1;
-	}
-
-	if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
-		c->op_bytes = 8;
-
-	/* ModRM and SIB bytes. */
-	if (c->d & ModRM)
-		rc = decode_modrm(ctxt, ops);
-	else if (c->d & MemAbs)
-		rc = decode_abs(ctxt, ops);
-	if (rc != X86EMUL_CONTINUE)
-		goto done;
-
-	if (!c->has_seg_override)
-		set_seg_override(c, VCPU_SREG_DS);
-
-	if (!(!c->twobyte && c->b == 0x8d))
-		c->modrm_ea += seg_override_base(ctxt, ops, c);
-
-	if (c->ad_bytes != 8)
-		c->modrm_ea = (u32)c->modrm_ea;
-
-	if (c->rip_relative)
-		c->modrm_ea += c->eip;
-
-	/*
-	 * Decode and fetch the source operand: register, memory
-	 * or immediate.
-	 */
-	switch (c->d & SrcMask) {
-	case SrcNone:
-		break;
-	case SrcReg:
-		decode_register_operand(&c->src, c, 0);
-		break;
-	case SrcMem16:
-		c->src.bytes = 2;
-		goto srcmem_common;
-	case SrcMem32:
-		c->src.bytes = 4;
-		goto srcmem_common;
-	case SrcMem:
-		c->src.bytes = (c->d & ByteOp) ? 1 :
-							   c->op_bytes;
-		/* Don't fetch the address for invlpg: it could be unmapped. */
-		if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
-			break;
-	srcmem_common:
-		/*
-		 * For instructions with a ModR/M byte, switch to register
-		 * access if Mod = 3.
-		 */
-		if ((c->d & ModRM) && c->modrm_mod == 3) {
-			c->src.type = OP_REG;
-			c->src.val = c->modrm_val;
-			c->src.ptr = c->modrm_ptr;
-			break;
-		}
-		c->src.type = OP_MEM;
-		c->src.ptr = (unsigned long *)c->modrm_ea;
-		c->src.val = 0;
-		break;
-	case SrcImm:
-	case SrcImmU:
-		c->src.type = OP_IMM;
-		c->src.ptr = (unsigned long *)c->eip;
-		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		if (c->src.bytes == 8)
-			c->src.bytes = 4;
-		/* NB. Immediates are sign-extended as necessary. */
-		switch (c->src.bytes) {
-		case 1:
-			c->src.val = insn_fetch(s8, 1, c->eip);
-			break;
-		case 2:
-			c->src.val = insn_fetch(s16, 2, c->eip);
-			break;
-		case 4:
-			c->src.val = insn_fetch(s32, 4, c->eip);
-			break;
-		}
-		if ((c->d & SrcMask) == SrcImmU) {
-			switch (c->src.bytes) {
-			case 1:
-				c->src.val &= 0xff;
-				break;
-			case 2:
-				c->src.val &= 0xffff;
-				break;
-			case 4:
-				c->src.val &= 0xffffffff;
-				break;
-			}
-		}
-		break;
-	case SrcImmByte:
-	case SrcImmUByte:
-		c->src.type = OP_IMM;
-		c->src.ptr = (unsigned long *)c->eip;
-		c->src.bytes = 1;
-		if ((c->d & SrcMask) == SrcImmByte)
-			c->src.val = insn_fetch(s8, 1, c->eip);
-		else
-			c->src.val = insn_fetch(u8, 1, c->eip);
-		break;
-	case SrcAcc:
-		c->src.type = OP_REG;
-		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		c->src.ptr = &c->regs[VCPU_REGS_RAX];
-		switch (c->src.bytes) {
-			case 1:
-				c->src.val = *(u8 *)c->src.ptr;
-				break;
-			case 2:
-				c->src.val = *(u16 *)c->src.ptr;
-				break;
-			case 4:
-				c->src.val = *(u32 *)c->src.ptr;
-				break;
-			case 8:
-				c->src.val = *(u64 *)c->src.ptr;
-				break;
-		}
-		break;
-	case SrcOne:
-		c->src.bytes = 1;
-		c->src.val = 1;
-		break;
-	case SrcSI:
-		c->src.type = OP_MEM;
-		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		c->src.ptr = (unsigned long *)
-			register_address(c,  seg_override_base(ctxt, ops, c),
-					 c->regs[VCPU_REGS_RSI]);
-		c->src.val = 0;
-		break;
-	case SrcImmFAddr:
-		c->src.type = OP_IMM;
-		c->src.ptr = (unsigned long *)c->eip;
-		c->src.bytes = c->op_bytes + 2;
-		insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
-		break;
-	case SrcMemFAddr:
-		c->src.type = OP_MEM;
-		c->src.ptr = (unsigned long *)c->modrm_ea;
-		c->src.bytes = c->op_bytes + 2;
-		break;
-	}
+	long sv = 0, mask;
 
-	/*
-	 * Decode and fetch the second source operand: register, memory
-	 * or immediate.
-	 */
-	switch (c->d & Src2Mask) {
-	case Src2None:
-		break;
-	case Src2CL:
-		c->src2.bytes = 1;
-		c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
-		break;
-	case Src2ImmByte:
-		c->src2.type = OP_IMM;
-		c->src2.ptr = (unsigned long *)c->eip;
-		c->src2.bytes = 1;
-		c->src2.val = insn_fetch(u8, 1, c->eip);
-		break;
-	case Src2One:
-		c->src2.bytes = 1;
-		c->src2.val = 1;
-		break;
-	}
+	if (c->dst.type == OP_MEM && c->src.type == OP_REG) {
+		mask = ~(c->dst.bytes * 8 - 1);
 
-	/* Decode and fetch the destination operand: register or memory. */
-	switch (c->d & DstMask) {
-	case ImplicitOps:
-		/* Special instructions do their own operand decoding. */
-		return 0;
-	case DstReg:
-		decode_register_operand(&c->dst, c,
-			 c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
-		break;
-	case DstMem:
-	case DstMem64:
-		if ((c->d & ModRM) && c->modrm_mod == 3) {
-			c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-			c->dst.type = OP_REG;
-			c->dst.val = c->dst.orig_val = c->modrm_val;
-			c->dst.ptr = c->modrm_ptr;
-			break;
-		}
-		c->dst.type = OP_MEM;
-		c->dst.ptr = (unsigned long *)c->modrm_ea;
-		if ((c->d & DstMask) == DstMem64)
-			c->dst.bytes = 8;
-		else
-			c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		c->dst.val = 0;
-		if (c->d & BitOp) {
-			unsigned long mask = ~(c->dst.bytes * 8 - 1);
+		if (c->src.bytes == 2)
+			sv = (s16)c->src.val & (s16)mask;
+		else if (c->src.bytes == 4)
+			sv = (s32)c->src.val & (s32)mask;
 
-			c->dst.ptr = (void *)c->dst.ptr +
-						   (c->src.val & mask) / 8;
-		}
-		break;
-	case DstAcc:
-		c->dst.type = OP_REG;
-		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		c->dst.ptr = &c->regs[VCPU_REGS_RAX];
-		switch (c->dst.bytes) {
-			case 1:
-				c->dst.val = *(u8 *)c->dst.ptr;
-				break;
-			case 2:
-				c->dst.val = *(u16 *)c->dst.ptr;
-				break;
-			case 4:
-				c->dst.val = *(u32 *)c->dst.ptr;
-				break;
-			case 8:
-				c->dst.val = *(u64 *)c->dst.ptr;
-				break;
-		}
-		c->dst.orig_val = c->dst.val;
-		break;
-	case DstDI:
-		c->dst.type = OP_MEM;
-		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-		c->dst.ptr = (unsigned long *)
-			register_address(c, es_base(ctxt, ops),
-					 c->regs[VCPU_REGS_RDI]);
-		c->dst.val = 0;
-		break;
+		c->dst.addr.mem += (sv >> 3);
 	}
 
-done:
-	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+	/* only subword offset */
+	c->src.val &= (c->dst.bytes << 3) - 1;
 }
 
 static int read_emulated(struct x86_emulate_ctxt *ctxt,
@@ -1337,7 +832,7 @@
 		rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
 					ctxt->vcpu);
 		if (rc == X86EMUL_PROPAGATE_FAULT)
-			emulate_pf(ctxt, addr, err);
+			emulate_pf(ctxt);
 		if (rc != X86EMUL_CONTINUE)
 			return rc;
 		mc->end += n;
@@ -1424,7 +919,7 @@
 	addr = dt.address + index * 8;
 	ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,  &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT)
-		emulate_pf(ctxt, addr, err);
+		emulate_pf(ctxt);
 
        return ret;
 }
@@ -1450,7 +945,7 @@
 	addr = dt.address + index * 8;
 	ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT)
-		emulate_pf(ctxt, addr, err);
+		emulate_pf(ctxt);
 
 	return ret;
 }
@@ -1573,6 +1068,25 @@
 	return X86EMUL_PROPAGATE_FAULT;
 }
 
+static void write_register_operand(struct operand *op)
+{
+	/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
+	switch (op->bytes) {
+	case 1:
+		*(u8 *)op->addr.reg = (u8)op->val;
+		break;
+	case 2:
+		*(u16 *)op->addr.reg = (u16)op->val;
+		break;
+	case 4:
+		*op->addr.reg = (u32)op->val;
+		break;	/* 64b: zero-extend */
+	case 8:
+		*op->addr.reg = op->val;
+		break;
+	}
+}
+
 static inline int writeback(struct x86_emulate_ctxt *ctxt,
 			    struct x86_emulate_ops *ops)
 {
@@ -1582,28 +1096,12 @@
 
 	switch (c->dst.type) {
 	case OP_REG:
-		/* The 4-byte case *is* correct:
-		 * in 64-bit mode we zero-extend.
-		 */
-		switch (c->dst.bytes) {
-		case 1:
-			*(u8 *)c->dst.ptr = (u8)c->dst.val;
-			break;
-		case 2:
-			*(u16 *)c->dst.ptr = (u16)c->dst.val;
-			break;
-		case 4:
-			*c->dst.ptr = (u32)c->dst.val;
-			break;	/* 64b: zero-ext */
-		case 8:
-			*c->dst.ptr = c->dst.val;
-			break;
-		}
+		write_register_operand(&c->dst);
 		break;
 	case OP_MEM:
 		if (c->lock_prefix)
 			rc = ops->cmpxchg_emulated(
-					(unsigned long)c->dst.ptr,
+					c->dst.addr.mem,
 					&c->dst.orig_val,
 					&c->dst.val,
 					c->dst.bytes,
@@ -1611,14 +1109,13 @@
 					ctxt->vcpu);
 		else
 			rc = ops->write_emulated(
-					(unsigned long)c->dst.ptr,
+					c->dst.addr.mem,
 					&c->dst.val,
 					c->dst.bytes,
 					&err,
 					ctxt->vcpu);
 		if (rc == X86EMUL_PROPAGATE_FAULT)
-			emulate_pf(ctxt,
-					      (unsigned long)c->dst.ptr, err);
+			emulate_pf(ctxt);
 		if (rc != X86EMUL_CONTINUE)
 			return rc;
 		break;
@@ -1640,8 +1137,8 @@
 	c->dst.bytes = c->op_bytes;
 	c->dst.val = c->src.val;
 	register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
-	c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
-					       c->regs[VCPU_REGS_RSP]);
+	c->dst.addr.mem = register_address(c, ss_base(ctxt, ops),
+					   c->regs[VCPU_REGS_RSP]);
 }
 
 static int emulate_pop(struct x86_emulate_ctxt *ctxt,
@@ -1701,6 +1198,9 @@
 	*(unsigned long *)dest =
 		(ctxt->eflags & ~change_mask) | (val & change_mask);
 
+	if (rc == X86EMUL_PROPAGATE_FAULT)
+		emulate_pf(ctxt);
+
 	return rc;
 }
 
@@ -1778,6 +1278,150 @@
 	return rc;
 }
 
+int emulate_int_real(struct x86_emulate_ctxt *ctxt,
+			       struct x86_emulate_ops *ops, int irq)
+{
+	struct decode_cache *c = &ctxt->decode;
+	int rc;
+	struct desc_ptr dt;
+	gva_t cs_addr;
+	gva_t eip_addr;
+	u16 cs, eip;
+	u32 err;
+
+	/* TODO: Add limit checks */
+	c->src.val = ctxt->eflags;
+	emulate_push(ctxt, ops);
+	rc = writeback(ctxt, ops);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC);
+
+	c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+	emulate_push(ctxt, ops);
+	rc = writeback(ctxt, ops);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->src.val = c->eip;
+	emulate_push(ctxt, ops);
+	rc = writeback(ctxt, ops);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->dst.type = OP_NONE;
+
+	ops->get_idt(&dt, ctxt->vcpu);
+
+	eip_addr = dt.address + (irq << 2);
+	cs_addr = dt.address + (irq << 2) + 2;
+
+	rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &err);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &err);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	rc = load_segment_descriptor(ctxt, ops, cs, VCPU_SREG_CS);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->eip = eip;
+
+	return rc;
+}
+
+static int emulate_int(struct x86_emulate_ctxt *ctxt,
+		       struct x86_emulate_ops *ops, int irq)
+{
+	switch(ctxt->mode) {
+	case X86EMUL_MODE_REAL:
+		return emulate_int_real(ctxt, ops, irq);
+	case X86EMUL_MODE_VM86:
+	case X86EMUL_MODE_PROT16:
+	case X86EMUL_MODE_PROT32:
+	case X86EMUL_MODE_PROT64:
+	default:
+		/* Protected mode interrupts unimplemented yet */
+		return X86EMUL_UNHANDLEABLE;
+	}
+}
+
+static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
+			     struct x86_emulate_ops *ops)
+{
+	struct decode_cache *c = &ctxt->decode;
+	int rc = X86EMUL_CONTINUE;
+	unsigned long temp_eip = 0;
+	unsigned long temp_eflags = 0;
+	unsigned long cs = 0;
+	unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF |
+			     EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF |
+			     EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */
+	unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP;
+
+	/* TODO: Add stack limit check */
+
+	rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);
+
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	if (temp_eip & ~0xffff) {
+		emulate_gp(ctxt, 0);
+		return X86EMUL_PROPAGATE_FAULT;
+	}
+
+	rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
+
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
+
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
+
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->eip = temp_eip;
+
+
+	if (c->op_bytes == 4)
+		ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask));
+	else if (c->op_bytes == 2) {
+		ctxt->eflags &= ~0xffff;
+		ctxt->eflags |= temp_eflags;
+	}
+
+	ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */
+	ctxt->eflags |= EFLG_RESERVED_ONE_MASK;
+
+	return rc;
+}
+
+static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
+				    struct x86_emulate_ops* ops)
+{
+	switch(ctxt->mode) {
+	case X86EMUL_MODE_REAL:
+		return emulate_iret_real(ctxt, ops);
+	case X86EMUL_MODE_VM86:
+	case X86EMUL_MODE_PROT16:
+	case X86EMUL_MODE_PROT32:
+	case X86EMUL_MODE_PROT64:
+	default:
+		/* iret from protected mode unimplemented yet */
+		return X86EMUL_UNHANDLEABLE;
+	}
+}
+
 static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
 				struct x86_emulate_ops *ops)
 {
@@ -1819,6 +1463,9 @@
 			       struct x86_emulate_ops *ops)
 {
 	struct decode_cache *c = &ctxt->decode;
+	unsigned long *rax = &c->regs[VCPU_REGS_RAX];
+	unsigned long *rdx = &c->regs[VCPU_REGS_RDX];
+	u8 de = 0;
 
 	switch (c->modrm_reg) {
 	case 0 ... 1:	/* test */
@@ -1830,10 +1477,26 @@
 	case 3:	/* neg */
 		emulate_1op("neg", c->dst, ctxt->eflags);
 		break;
+	case 4: /* mul */
+		emulate_1op_rax_rdx("mul", c->src, *rax, *rdx, ctxt->eflags);
+		break;
+	case 5: /* imul */
+		emulate_1op_rax_rdx("imul", c->src, *rax, *rdx, ctxt->eflags);
+		break;
+	case 6: /* div */
+		emulate_1op_rax_rdx_ex("div", c->src, *rax, *rdx,
+				       ctxt->eflags, de);
+		break;
+	case 7: /* idiv */
+		emulate_1op_rax_rdx_ex("idiv", c->src, *rax, *rdx,
+				       ctxt->eflags, de);
+		break;
 	default:
-		return 0;
+		return X86EMUL_UNHANDLEABLE;
 	}
-	return 1;
+	if (de)
+		return emulate_de(ctxt);
+	return X86EMUL_CONTINUE;
 }
 
 static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
@@ -1905,6 +1568,23 @@
 	return rc;
 }
 
+static int emulate_load_segment(struct x86_emulate_ctxt *ctxt,
+			   struct x86_emulate_ops *ops, int seg)
+{
+	struct decode_cache *c = &ctxt->decode;
+	unsigned short sel;
+	int rc;
+
+	memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+	rc = load_segment_descriptor(ctxt, ops, sel, seg);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->dst.val = c->src.val;
+	return rc;
+}
+
 static inline void
 setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 			struct x86_emulate_ops *ops, struct desc_struct *cs,
@@ -2160,9 +1840,15 @@
 				 struct x86_emulate_ops *ops,
 				 u16 port, u16 len)
 {
+	if (ctxt->perm_ok)
+		return true;
+
 	if (emulator_bad_iopl(ctxt, ops))
 		if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
 			return false;
+
+	ctxt->perm_ok = true;
+
 	return true;
 }
 
@@ -2254,7 +1940,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, old_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2264,7 +1950,7 @@
 			     &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, old_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2272,7 +1958,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, new_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2285,7 +1971,7 @@
 				     ctxt->vcpu, &err);
 		if (ret == X86EMUL_PROPAGATE_FAULT) {
 			/* FIXME: need to provide precise fault address */
-			emulate_pf(ctxt, new_tss_base, err);
+			emulate_pf(ctxt);
 			return ret;
 		}
 	}
@@ -2396,7 +2082,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, old_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2406,7 +2092,7 @@
 			     &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, old_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2414,7 +2100,7 @@
 			    &err);
 	if (ret == X86EMUL_PROPAGATE_FAULT) {
 		/* FIXME: need to provide precise fault address */
-		emulate_pf(ctxt, new_tss_base, err);
+		emulate_pf(ctxt);
 		return ret;
 	}
 
@@ -2427,7 +2113,7 @@
 				     ctxt->vcpu, &err);
 		if (ret == X86EMUL_PROPAGATE_FAULT) {
 			/* FIXME: need to provide precise fault address */
-			emulate_pf(ctxt, new_tss_base, err);
+			emulate_pf(ctxt);
 			return ret;
 		}
 	}
@@ -2523,10 +2209,10 @@
 }
 
 int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
-			 struct x86_emulate_ops *ops,
 			 u16 tss_selector, int reason,
 			 bool has_error_code, u32 error_code)
 {
+	struct x86_emulate_ops *ops = ctxt->ops;
 	struct decode_cache *c = &ctxt->decode;
 	int rc;
 
@@ -2552,16 +2238,784 @@
 	int df = (ctxt->eflags & EFLG_DF) ? -1 : 1;
 
 	register_address_increment(c, &c->regs[reg], df * op->bytes);
-	op->ptr = (unsigned long *)register_address(c,  base, c->regs[reg]);
+	op->addr.mem = register_address(c,  base, c->regs[reg]);
+}
+
+static int em_push(struct x86_emulate_ctxt *ctxt)
+{
+	emulate_push(ctxt, ctxt->ops);
+	return X86EMUL_CONTINUE;
+}
+
+static int em_das(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+	u8 al, old_al;
+	bool af, cf, old_cf;
+
+	cf = ctxt->eflags & X86_EFLAGS_CF;
+	al = c->dst.val;
+
+	old_al = al;
+	old_cf = cf;
+	cf = false;
+	af = ctxt->eflags & X86_EFLAGS_AF;
+	if ((al & 0x0f) > 9 || af) {
+		al -= 6;
+		cf = old_cf | (al >= 250);
+		af = true;
+	} else {
+		af = false;
+	}
+	if (old_al > 0x99 || old_cf) {
+		al -= 0x60;
+		cf = true;
+	}
+
+	c->dst.val = al;
+	/* Set PF, ZF, SF */
+	c->src.type = OP_IMM;
+	c->src.val = 0;
+	c->src.bytes = 1;
+	emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
+	ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF);
+	if (cf)
+		ctxt->eflags |= X86_EFLAGS_CF;
+	if (af)
+		ctxt->eflags |= X86_EFLAGS_AF;
+	return X86EMUL_CONTINUE;
+}
+
+static int em_call_far(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+	u16 sel, old_cs;
+	ulong old_eip;
+	int rc;
+
+	old_cs = ctxt->ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+	old_eip = c->eip;
+
+	memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+	if (load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS))
+		return X86EMUL_CONTINUE;
+
+	c->eip = 0;
+	memcpy(&c->eip, c->src.valptr, c->op_bytes);
+
+	c->src.val = old_cs;
+	emulate_push(ctxt, ctxt->ops);
+	rc = writeback(ctxt, ctxt->ops);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->src.val = old_eip;
+	emulate_push(ctxt, ctxt->ops);
+	rc = writeback(ctxt, ctxt->ops);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+
+	c->dst.type = OP_NONE;
+
+	return X86EMUL_CONTINUE;
+}
+
+static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+	int rc;
+
+	c->dst.type = OP_REG;
+	c->dst.addr.reg = &c->eip;
+	c->dst.bytes = c->op_bytes;
+	rc = emulate_pop(ctxt, ctxt->ops, &c->dst.val, c->op_bytes);
+	if (rc != X86EMUL_CONTINUE)
+		return rc;
+	register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->src.val);
+	return X86EMUL_CONTINUE;
+}
+
+static int em_imul(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+
+	emulate_2op_SrcV_nobyte("imul", c->src, c->dst, ctxt->eflags);
+	return X86EMUL_CONTINUE;
+}
+
+static int em_imul_3op(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+
+	c->dst.val = c->src2.val;
+	return em_imul(ctxt);
+}
+
+static int em_cwd(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+
+	c->dst.type = OP_REG;
+	c->dst.bytes = c->src.bytes;
+	c->dst.addr.reg = &c->regs[VCPU_REGS_RDX];
+	c->dst.val = ~((c->src.val >> (c->src.bytes * 8 - 1)) - 1);
+
+	return X86EMUL_CONTINUE;
+}
+
+static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
+{
+	unsigned cpl = ctxt->ops->cpl(ctxt->vcpu);
+	struct decode_cache *c = &ctxt->decode;
+	u64 tsc = 0;
+
+	if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD)) {
+		emulate_gp(ctxt, 0);
+		return X86EMUL_PROPAGATE_FAULT;
+	}
+	ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc);
+	c->regs[VCPU_REGS_RAX] = (u32)tsc;
+	c->regs[VCPU_REGS_RDX] = tsc >> 32;
+	return X86EMUL_CONTINUE;
+}
+
+static int em_mov(struct x86_emulate_ctxt *ctxt)
+{
+	struct decode_cache *c = &ctxt->decode;
+	c->dst.val = c->src.val;
+	return X86EMUL_CONTINUE;
+}
+
+#define D(_y) { .flags = (_y) }
+#define N    D(0)
+#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
+#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
+#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
+
+#define D2bv(_f)      D((_f) | ByteOp), D(_f)
+#define I2bv(_f, _e)  I((_f) | ByteOp, _e), I(_f, _e)
+
+#define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM),			\
+		D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock),		\
+		D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
+
+
+static struct opcode group1[] = {
+	X7(D(Lock)), N
+};
+
+static struct opcode group1A[] = {
+	D(DstMem | SrcNone | ModRM | Mov | Stack), N, N, N, N, N, N, N,
+};
+
+static struct opcode group3[] = {
+	D(DstMem | SrcImm | ModRM), D(DstMem | SrcImm | ModRM),
+	D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
+	X4(D(SrcMem | ModRM)),
+};
+
+static struct opcode group4[] = {
+	D(ByteOp | DstMem | SrcNone | ModRM | Lock), D(ByteOp | DstMem | SrcNone | ModRM | Lock),
+	N, N, N, N, N, N,
+};
+
+static struct opcode group5[] = {
+	D(DstMem | SrcNone | ModRM | Lock), D(DstMem | SrcNone | ModRM | Lock),
+	D(SrcMem | ModRM | Stack),
+	I(SrcMemFAddr | ModRM | ImplicitOps | Stack, em_call_far),
+	D(SrcMem | ModRM | Stack), D(SrcMemFAddr | ModRM | ImplicitOps),
+	D(SrcMem | ModRM | Stack), N,
+};
+
+static struct group_dual group7 = { {
+	N, N, D(ModRM | SrcMem | Priv), D(ModRM | SrcMem | Priv),
+	D(SrcNone | ModRM | DstMem | Mov), N,
+	D(SrcMem16 | ModRM | Mov | Priv),
+	D(SrcMem | ModRM | ByteOp | Priv | NoAccess),
+}, {
+	D(SrcNone | ModRM | Priv), N, N, D(SrcNone | ModRM | Priv),
+	D(SrcNone | ModRM | DstMem | Mov), N,
+	D(SrcMem16 | ModRM | Mov | Priv), N,
+} };
+
+static struct opcode group8[] = {
+	N, N, N, N,
+	D(DstMem | SrcImmByte | ModRM), D(DstMem | SrcImmByte | ModRM | Lock),
+	D(DstMem | SrcImmByte | ModRM | Lock), D(DstMem | SrcImmByte | ModRM | Lock),
+};
+
+static struct group_dual group9 = { {
+	N, D(DstMem64 | ModRM | Lock), N, N, N, N, N, N,
+}, {
+	N, N, N, N, N, N, N, N,
+} };
+
+static struct opcode group11[] = {
+	I(DstMem | SrcImm | ModRM | Mov, em_mov), X7(D(Undefined)),
+};
+
+static struct opcode opcode_table[256] = {
+	/* 0x00 - 0x07 */
+	D6ALU(Lock),
+	D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+	/* 0x08 - 0x0F */
+	D6ALU(Lock),
+	D(ImplicitOps | Stack | No64), N,
+	/* 0x10 - 0x17 */
+	D6ALU(Lock),
+	D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+	/* 0x18 - 0x1F */
+	D6ALU(Lock),
+	D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+	/* 0x20 - 0x27 */
+	D6ALU(Lock), N, N,
+	/* 0x28 - 0x2F */
+	D6ALU(Lock), N, I(ByteOp | DstAcc | No64, em_das),
+	/* 0x30 - 0x37 */
+	D6ALU(Lock), N, N,
+	/* 0x38 - 0x3F */
+	D6ALU(0), N, N,
+	/* 0x40 - 0x4F */
+	X16(D(DstReg)),
+	/* 0x50 - 0x57 */
+	X8(I(SrcReg | Stack, em_push)),
+	/* 0x58 - 0x5F */
+	X8(D(DstReg | Stack)),
+	/* 0x60 - 0x67 */
+	D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+	N, D(DstReg | SrcMem32 | ModRM | Mov) /* movsxd (x86/64) */ ,
+	N, N, N, N,
+	/* 0x68 - 0x6F */
+	I(SrcImm | Mov | Stack, em_push),
+	I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
+	I(SrcImmByte | Mov | Stack, em_push),
+	I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
+	D2bv(DstDI | Mov | String), /* insb, insw/insd */
+	D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
+	/* 0x70 - 0x7F */
+	X16(D(SrcImmByte)),
+	/* 0x80 - 0x87 */
+	G(ByteOp | DstMem | SrcImm | ModRM | Group, group1),
+	G(DstMem | SrcImm | ModRM | Group, group1),
+	G(ByteOp | DstMem | SrcImm | ModRM | No64 | Group, group1),
+	G(DstMem | SrcImmByte | ModRM | Group, group1),
+	D2bv(DstMem | SrcReg | ModRM), D2bv(DstMem | SrcReg | ModRM | Lock),
+	/* 0x88 - 0x8F */
+	I2bv(DstMem | SrcReg | ModRM | Mov, em_mov),
+	I2bv(DstReg | SrcMem | ModRM | Mov, em_mov),
+	D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg),
+	D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A),
+	/* 0x90 - 0x97 */
+	X8(D(SrcAcc | DstReg)),
+	/* 0x98 - 0x9F */
+	D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd),
+	I(SrcImmFAddr | No64, em_call_far), N,
+	D(ImplicitOps | Stack), D(ImplicitOps | Stack), N, N,
+	/* 0xA0 - 0xA7 */
+	I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
+	I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov),
+	I2bv(SrcSI | DstDI | Mov | String, em_mov),
+	D2bv(SrcSI | DstDI | String),
+	/* 0xA8 - 0xAF */
+	D2bv(DstAcc | SrcImm),
+	I2bv(SrcAcc | DstDI | Mov | String, em_mov),
+	I2bv(SrcSI | DstAcc | Mov | String, em_mov),
+	D2bv(SrcAcc | DstDI | String),
+	/* 0xB0 - 0xB7 */
+	X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)),
+	/* 0xB8 - 0xBF */
+	X8(I(DstReg | SrcImm | Mov, em_mov)),
+	/* 0xC0 - 0xC7 */
+	D2bv(DstMem | SrcImmByte | ModRM),
+	I(ImplicitOps | Stack | SrcImmU16, em_ret_near_imm),
+	D(ImplicitOps | Stack),
+	D(DstReg | SrcMemFAddr | ModRM | No64), D(DstReg | SrcMemFAddr | ModRM | No64),
+	G(ByteOp, group11), G(0, group11),
+	/* 0xC8 - 0xCF */
+	N, N, N, D(ImplicitOps | Stack),
+	D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps),
+	/* 0xD0 - 0xD7 */
+	D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
+	N, N, N, N,
+	/* 0xD8 - 0xDF */
+	N, N, N, N, N, N, N, N,
+	/* 0xE0 - 0xE7 */
+	X4(D(SrcImmByte)),
+	D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte),
+	/* 0xE8 - 0xEF */
+	D(SrcImm | Stack), D(SrcImm | ImplicitOps),
+	D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
+	D2bv(SrcNone | DstAcc),	D2bv(SrcAcc | ImplicitOps),
+	/* 0xF0 - 0xF7 */
+	N, N, N, N,
+	D(ImplicitOps | Priv), D(ImplicitOps), G(ByteOp, group3), G(0, group3),
+	/* 0xF8 - 0xFF */
+	D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps),
+	D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5),
+};
+
+static struct opcode twobyte_table[256] = {
+	/* 0x00 - 0x0F */
+	N, GD(0, &group7), N, N,
+	N, D(ImplicitOps), D(ImplicitOps | Priv), N,
+	D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N,
+	N, D(ImplicitOps | ModRM), N, N,
+	/* 0x10 - 0x1F */
+	N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
+	/* 0x20 - 0x2F */
+	D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264),
+	D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264),
+	N, N, N, N,
+	N, N, N, N, N, N, N, N,
+	/* 0x30 - 0x3F */
+	D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
+	D(ImplicitOps | Priv), N,
+	D(ImplicitOps), D(ImplicitOps | Priv), N, N,
+	N, N, N, N, N, N, N, N,
+	/* 0x40 - 0x4F */
+	X16(D(DstReg | SrcMem | ModRM | Mov)),
+	/* 0x50 - 0x5F */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+	/* 0x60 - 0x6F */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+	/* 0x70 - 0x7F */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+	/* 0x80 - 0x8F */
+	X16(D(SrcImm)),
+	/* 0x90 - 0x9F */
+	X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
+	/* 0xA0 - 0xA7 */
+	D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+	N, D(DstMem | SrcReg | ModRM | BitOp),
+	D(DstMem | SrcReg | Src2ImmByte | ModRM),
+	D(DstMem | SrcReg | Src2CL | ModRM), N, N,
+	/* 0xA8 - 0xAF */
+	D(ImplicitOps | Stack), D(ImplicitOps | Stack),
+	N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
+	D(DstMem | SrcReg | Src2ImmByte | ModRM),
+	D(DstMem | SrcReg | Src2CL | ModRM),
+	D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
+	/* 0xB0 - 0xB7 */
+	D2bv(DstMem | SrcReg | ModRM | Lock),
+	D(DstReg | SrcMemFAddr | ModRM), D(DstMem | SrcReg | ModRM | BitOp | Lock),
+	D(DstReg | SrcMemFAddr | ModRM), D(DstReg | SrcMemFAddr | ModRM),
+	D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+	/* 0xB8 - 0xBF */
+	N, N,
+	G(BitOp, group8), D(DstMem | SrcReg | ModRM | BitOp | Lock),
+	D(DstReg | SrcMem | ModRM), D(DstReg | SrcMem | ModRM),
+	D(ByteOp | DstReg | SrcMem | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
+	/* 0xC0 - 0xCF */
+	D2bv(DstMem | SrcReg | ModRM | Lock),
+	N, D(DstMem | SrcReg | ModRM | Mov),
+	N, N, N, GD(0, &group9),
+	N, N, N, N, N, N, N, N,
+	/* 0xD0 - 0xDF */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+	/* 0xE0 - 0xEF */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+	/* 0xF0 - 0xFF */
+	N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N
+};
+
+#undef D
+#undef N
+#undef G
+#undef GD
+#undef I
+
+#undef D2bv
+#undef I2bv
+#undef D6ALU
+
+static unsigned imm_size(struct decode_cache *c)
+{
+	unsigned size;
+
+	size = (c->d & ByteOp) ? 1 : c->op_bytes;
+	if (size == 8)
+		size = 4;
+	return size;
+}
+
+static int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op,
+		      unsigned size, bool sign_extension)
+{
+	struct decode_cache *c = &ctxt->decode;
+	struct x86_emulate_ops *ops = ctxt->ops;
+	int rc = X86EMUL_CONTINUE;
+
+	op->type = OP_IMM;
+	op->bytes = size;
+	op->addr.mem = c->eip;
+	/* NB. Immediates are sign-extended as necessary. */
+	switch (op->bytes) {
+	case 1:
+		op->val = insn_fetch(s8, 1, c->eip);
+		break;
+	case 2:
+		op->val = insn_fetch(s16, 2, c->eip);
+		break;
+	case 4:
+		op->val = insn_fetch(s32, 4, c->eip);
+		break;
+	}
+	if (!sign_extension) {
+		switch (op->bytes) {
+		case 1:
+			op->val &= 0xff;
+			break;
+		case 2:
+			op->val &= 0xffff;
+			break;
+		case 4:
+			op->val &= 0xffffffff;
+			break;
+		}
+	}
+done:
+	return rc;
 }
 
 int
-x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
+x86_decode_insn(struct x86_emulate_ctxt *ctxt)
+{
+	struct x86_emulate_ops *ops = ctxt->ops;
+	struct decode_cache *c = &ctxt->decode;
+	int rc = X86EMUL_CONTINUE;
+	int mode = ctxt->mode;
+	int def_op_bytes, def_ad_bytes, dual, goffset;
+	struct opcode opcode, *g_mod012, *g_mod3;
+	struct operand memop = { .type = OP_NONE };
+
+	c->eip = ctxt->eip;
+	c->fetch.start = c->fetch.end = c->eip;
+	ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
+
+	switch (mode) {
+	case X86EMUL_MODE_REAL:
+	case X86EMUL_MODE_VM86:
+	case X86EMUL_MODE_PROT16:
+		def_op_bytes = def_ad_bytes = 2;
+		break;
+	case X86EMUL_MODE_PROT32:
+		def_op_bytes = def_ad_bytes = 4;
+		break;
+#ifdef CONFIG_X86_64
+	case X86EMUL_MODE_PROT64:
+		def_op_bytes = 4;
+		def_ad_bytes = 8;
+		break;
+#endif
+	default:
+		return -1;
+	}
+
+	c->op_bytes = def_op_bytes;
+	c->ad_bytes = def_ad_bytes;
+
+	/* Legacy prefixes. */
+	for (;;) {
+		switch (c->b = insn_fetch(u8, 1, c->eip)) {
+		case 0x66:	/* operand-size override */
+			/* switch between 2/4 bytes */
+			c->op_bytes = def_op_bytes ^ 6;
+			break;
+		case 0x67:	/* address-size override */
+			if (mode == X86EMUL_MODE_PROT64)
+				/* switch between 4/8 bytes */
+				c->ad_bytes = def_ad_bytes ^ 12;
+			else
+				/* switch between 2/4 bytes */
+				c->ad_bytes = def_ad_bytes ^ 6;
+			break;
+		case 0x26:	/* ES override */
+		case 0x2e:	/* CS override */
+		case 0x36:	/* SS override */
+		case 0x3e:	/* DS override */
+			set_seg_override(c, (c->b >> 3) & 3);
+			break;
+		case 0x64:	/* FS override */
+		case 0x65:	/* GS override */
+			set_seg_override(c, c->b & 7);
+			break;
+		case 0x40 ... 0x4f: /* REX */
+			if (mode != X86EMUL_MODE_PROT64)
+				goto done_prefixes;
+			c->rex_prefix = c->b;
+			continue;
+		case 0xf0:	/* LOCK */
+			c->lock_prefix = 1;
+			break;
+		case 0xf2:	/* REPNE/REPNZ */
+			c->rep_prefix = REPNE_PREFIX;
+			break;
+		case 0xf3:	/* REP/REPE/REPZ */
+			c->rep_prefix = REPE_PREFIX;
+			break;
+		default:
+			goto done_prefixes;
+		}
+
+		/* Any legacy prefix after a REX prefix nullifies its effect. */
+
+		c->rex_prefix = 0;
+	}
+
+done_prefixes:
+
+	/* REX prefix. */
+	if (c->rex_prefix & 8)
+		c->op_bytes = 8;	/* REX.W */
+
+	/* Opcode byte(s). */
+	opcode = opcode_table[c->b];
+	/* Two-byte opcode? */
+	if (c->b == 0x0f) {
+		c->twobyte = 1;
+		c->b = insn_fetch(u8, 1, c->eip);
+		opcode = twobyte_table[c->b];
+	}
+	c->d = opcode.flags;
+
+	if (c->d & Group) {
+		dual = c->d & GroupDual;
+		c->modrm = insn_fetch(u8, 1, c->eip);
+		--c->eip;
+
+		if (c->d & GroupDual) {
+			g_mod012 = opcode.u.gdual->mod012;
+			g_mod3 = opcode.u.gdual->mod3;
+		} else
+			g_mod012 = g_mod3 = opcode.u.group;
+
+		c->d &= ~(Group | GroupDual);
+
+		goffset = (c->modrm >> 3) & 7;
+
+		if ((c->modrm >> 6) == 3)
+			opcode = g_mod3[goffset];
+		else
+			opcode = g_mod012[goffset];
+		c->d |= opcode.flags;
+	}
+
+	c->execute = opcode.u.execute;
+
+	/* Unrecognised? */
+	if (c->d == 0 || (c->d & Undefined)) {
+		DPRINTF("Cannot emulate %02x\n", c->b);
+		return -1;
+	}
+
+	if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
+		c->op_bytes = 8;
+
+	if (c->d & Op3264) {
+		if (mode == X86EMUL_MODE_PROT64)
+			c->op_bytes = 8;
+		else
+			c->op_bytes = 4;
+	}
+
+	/* ModRM and SIB bytes. */
+	if (c->d & ModRM) {
+		rc = decode_modrm(ctxt, ops, &memop);
+		if (!c->has_seg_override)
+			set_seg_override(c, c->modrm_seg);
+	} else if (c->d & MemAbs)
+		rc = decode_abs(ctxt, ops, &memop);
+	if (rc != X86EMUL_CONTINUE)
+		goto done;
+
+	if (!c->has_seg_override)
+		set_seg_override(c, VCPU_SREG_DS);
+
+	if (memop.type == OP_MEM && !(!c->twobyte && c->b == 0x8d))
+		memop.addr.mem += seg_override_base(ctxt, ops, c);
+
+	if (memop.type == OP_MEM && c->ad_bytes != 8)
+		memop.addr.mem = (u32)memop.addr.mem;
+
+	if (memop.type == OP_MEM && c->rip_relative)
+		memop.addr.mem += c->eip;
+
+	/*
+	 * Decode and fetch the source operand: register, memory
+	 * or immediate.
+	 */
+	switch (c->d & SrcMask) {
+	case SrcNone:
+		break;
+	case SrcReg:
+		decode_register_operand(&c->src, c, 0);
+		break;
+	case SrcMem16:
+		memop.bytes = 2;
+		goto srcmem_common;
+	case SrcMem32:
+		memop.bytes = 4;
+		goto srcmem_common;
+	case SrcMem:
+		memop.bytes = (c->d & ByteOp) ? 1 :
+							   c->op_bytes;
+	srcmem_common:
+		c->src = memop;
+		break;
+	case SrcImmU16:
+		rc = decode_imm(ctxt, &c->src, 2, false);
+		break;
+	case SrcImm:
+		rc = decode_imm(ctxt, &c->src, imm_size(c), true);
+		break;
+	case SrcImmU:
+		rc = decode_imm(ctxt, &c->src, imm_size(c), false);
+		break;
+	case SrcImmByte:
+		rc = decode_imm(ctxt, &c->src, 1, true);
+		break;
+	case SrcImmUByte:
+		rc = decode_imm(ctxt, &c->src, 1, false);
+		break;
+	case SrcAcc:
+		c->src.type = OP_REG;
+		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		c->src.addr.reg = &c->regs[VCPU_REGS_RAX];
+		fetch_register_operand(&c->src);
+		break;
+	case SrcOne:
+		c->src.bytes = 1;
+		c->src.val = 1;
+		break;
+	case SrcSI:
+		c->src.type = OP_MEM;
+		c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		c->src.addr.mem =
+			register_address(c,  seg_override_base(ctxt, ops, c),
+					 c->regs[VCPU_REGS_RSI]);
+		c->src.val = 0;
+		break;
+	case SrcImmFAddr:
+		c->src.type = OP_IMM;
+		c->src.addr.mem = c->eip;
+		c->src.bytes = c->op_bytes + 2;
+		insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+		break;
+	case SrcMemFAddr:
+		memop.bytes = c->op_bytes + 2;
+		goto srcmem_common;
+		break;
+	}
+
+	if (rc != X86EMUL_CONTINUE)
+		goto done;
+
+	/*
+	 * Decode and fetch the second source operand: register, memory
+	 * or immediate.
+	 */
+	switch (c->d & Src2Mask) {
+	case Src2None:
+		break;
+	case Src2CL:
+		c->src2.bytes = 1;
+		c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
+		break;
+	case Src2ImmByte:
+		rc = decode_imm(ctxt, &c->src2, 1, true);
+		break;
+	case Src2One:
+		c->src2.bytes = 1;
+		c->src2.val = 1;
+		break;
+	case Src2Imm:
+		rc = decode_imm(ctxt, &c->src2, imm_size(c), true);
+		break;
+	}
+
+	if (rc != X86EMUL_CONTINUE)
+		goto done;
+
+	/* Decode and fetch the destination operand: register or memory. */
+	switch (c->d & DstMask) {
+	case DstReg:
+		decode_register_operand(&c->dst, c,
+			 c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
+		break;
+	case DstImmUByte:
+		c->dst.type = OP_IMM;
+		c->dst.addr.mem = c->eip;
+		c->dst.bytes = 1;
+		c->dst.val = insn_fetch(u8, 1, c->eip);
+		break;
+	case DstMem:
+	case DstMem64:
+		c->dst = memop;
+		if ((c->d & DstMask) == DstMem64)
+			c->dst.bytes = 8;
+		else
+			c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		if (c->d & BitOp)
+			fetch_bit_operand(c);
+		c->dst.orig_val = c->dst.val;
+		break;
+	case DstAcc:
+		c->dst.type = OP_REG;
+		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		c->dst.addr.reg = &c->regs[VCPU_REGS_RAX];
+		fetch_register_operand(&c->dst);
+		c->dst.orig_val = c->dst.val;
+		break;
+	case DstDI:
+		c->dst.type = OP_MEM;
+		c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+		c->dst.addr.mem =
+			register_address(c, es_base(ctxt, ops),
+					 c->regs[VCPU_REGS_RDI]);
+		c->dst.val = 0;
+		break;
+	case ImplicitOps:
+		/* Special instructions do their own operand decoding. */
+	default:
+		c->dst.type = OP_NONE; /* Disable writeback. */
+		return 0;
+	}
+
+done:
+	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+}
+
+static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
 {
+	struct decode_cache *c = &ctxt->decode;
+
+	/* The second termination condition only applies for REPE
+	 * and REPNE. Test if the repeat string operation prefix is
+	 * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the
+	 * corresponding termination condition according to:
+	 * 	- if REPE/REPZ and ZF = 0 then done
+	 * 	- if REPNE/REPNZ and ZF = 1 then done
+	 */
+	if (((c->b == 0xa6) || (c->b == 0xa7) ||
+	     (c->b == 0xae) || (c->b == 0xaf))
+	    && (((c->rep_prefix == REPE_PREFIX) &&
+		 ((ctxt->eflags & EFLG_ZF) == 0))
+		|| ((c->rep_prefix == REPNE_PREFIX) &&
+		    ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))))
+		return true;
+
+	return false;
+}
+
+int
+x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
+{
+	struct x86_emulate_ops *ops = ctxt->ops;
 	u64 msr_data;
 	struct decode_cache *c = &ctxt->decode;
 	int rc = X86EMUL_CONTINUE;
 	int saved_dst_type = c->dst.type;
+	int irq; /* Used for int 3, int, and into */
 
 	ctxt->decode.mem_read.pos = 0;
 
@@ -2576,6 +3030,11 @@
 		goto done;
 	}
 
+	if ((c->d & SrcMask) == SrcMemFAddr && c->src.type != OP_MEM) {
+		emulate_ud(ctxt);
+		goto done;
+	}
+
 	/* Privileged instruction can be executed only in CPL=0 */
 	if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
 		emulate_gp(ctxt, 0);
@@ -2583,35 +3042,15 @@
 	}
 
 	if (c->rep_prefix && (c->d & String)) {
-		ctxt->restart = true;
 		/* All REP prefixes have the same first termination condition */
 		if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
-		string_done:
-			ctxt->restart = false;
 			ctxt->eip = c->eip;
 			goto done;
 		}
-		/* The second termination condition only applies for REPE
-		 * and REPNE. Test if the repeat string operation prefix is
-		 * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the
-		 * corresponding termination condition according to:
-		 * 	- if REPE/REPZ and ZF = 0 then done
-		 * 	- if REPNE/REPNZ and ZF = 1 then done
-		 */
-		if ((c->b == 0xa6) || (c->b == 0xa7) ||
-		    (c->b == 0xae) || (c->b == 0xaf)) {
-			if ((c->rep_prefix == REPE_PREFIX) &&
-			    ((ctxt->eflags & EFLG_ZF) == 0))
-				goto string_done;
-			if ((c->rep_prefix == REPNE_PREFIX) &&
-			    ((ctxt->eflags & EFLG_ZF) == EFLG_ZF))
-				goto string_done;
-		}
-		c->eip = ctxt->eip;
 	}
 
-	if (c->src.type == OP_MEM) {
-		rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
+	if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) {
+		rc = read_emulated(ctxt, ops, c->src.addr.mem,
 					c->src.valptr, c->src.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
@@ -2619,7 +3058,7 @@
 	}
 
 	if (c->src2.type == OP_MEM) {
-		rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr,
+		rc = read_emulated(ctxt, ops, c->src2.addr.mem,
 					&c->src2.val, c->src2.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
@@ -2631,7 +3070,7 @@
 
 	if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
 		/* optimisation - avoid slow emulated read if Mov */
-		rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr,
+		rc = read_emulated(ctxt, ops, c->dst.addr.mem,
 				   &c->dst.val, c->dst.bytes);
 		if (rc != X86EMUL_CONTINUE)
 			goto done;
@@ -2640,6 +3079,13 @@
 
 special_insn:
 
+	if (c->execute) {
+		rc = c->execute(ctxt);
+		if (rc != X86EMUL_CONTINUE)
+			goto done;
+		goto writeback;
+	}
+
 	if (c->twobyte)
 		goto twobyte_insn;
 
@@ -2653,8 +3099,6 @@
 		break;
 	case 0x07:		/* pop es */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x08 ... 0x0d:
 	      or:		/* or */
@@ -2672,8 +3116,6 @@
 		break;
 	case 0x17:		/* pop ss */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x18 ... 0x1d:
 	      sbb:		/* sbb */
@@ -2684,8 +3126,6 @@
 		break;
 	case 0x1f:		/* pop ds */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x20 ... 0x25:
 	      and:		/* and */
@@ -2709,58 +3149,29 @@
 	case 0x48 ... 0x4f: /* dec r16/r32 */
 		emulate_1op("dec", c->dst, ctxt->eflags);
 		break;
-	case 0x50 ... 0x57:  /* push reg */
-		emulate_push(ctxt, ops);
-		break;
 	case 0x58 ... 0x5f: /* pop reg */
 	pop_instruction:
 		rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x60:	/* pusha */
 		rc = emulate_pusha(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x61:	/* popa */
 		rc = emulate_popa(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0x63:		/* movsxd */
 		if (ctxt->mode != X86EMUL_MODE_PROT64)
 			goto cannot_emulate;
 		c->dst.val = (s32) c->src.val;
 		break;
-	case 0x68: /* push imm */
-	case 0x6a: /* push imm8 */
-		emulate_push(ctxt, ops);
-		break;
 	case 0x6c:		/* insb */
 	case 0x6d:		/* insw/insd */
-		c->dst.bytes = min(c->dst.bytes, 4u);
-		if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
-					  c->dst.bytes)) {
-			emulate_gp(ctxt, 0);
-			goto done;
-		}
-		if (!pio_in_emulated(ctxt, ops, c->dst.bytes,
-				     c->regs[VCPU_REGS_RDX], &c->dst.val))
-			goto done; /* IO is needed, skip writeback */
-		break;
+		c->src.val = c->regs[VCPU_REGS_RDX];
+		goto do_io_in;
 	case 0x6e:		/* outsb */
 	case 0x6f:		/* outsw/outsd */
-		c->src.bytes = min(c->src.bytes, 4u);
-		if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
-					  c->src.bytes)) {
-			emulate_gp(ctxt, 0);
-			goto done;
-		}
-		ops->pio_out_emulated(c->src.bytes, c->regs[VCPU_REGS_RDX],
-				      &c->src.val, 1, ctxt->vcpu);
-
-		c->dst.type = OP_NONE; /* nothing to writeback */
+		c->dst.val = c->regs[VCPU_REGS_RDX];
+		goto do_io_out;
 		break;
 	case 0x70 ... 0x7f: /* jcc (short) */
 		if (test_cc(c->b, ctxt->eflags))
@@ -2793,29 +3204,15 @@
 	case 0x86 ... 0x87:	/* xchg */
 	xchg:
 		/* Write back the register source. */
-		switch (c->dst.bytes) {
-		case 1:
-			*(u8 *) c->src.ptr = (u8) c->dst.val;
-			break;
-		case 2:
-			*(u16 *) c->src.ptr = (u16) c->dst.val;
-			break;
-		case 4:
-			*c->src.ptr = (u32) c->dst.val;
-			break;	/* 64b reg: zero-extend */
-		case 8:
-			*c->src.ptr = c->dst.val;
-			break;
-		}
+		c->src.val = c->dst.val;
+		write_register_operand(&c->src);
 		/*
 		 * Write back the memory destination with implicit LOCK
 		 * prefix.
 		 */
-		c->dst.val = c->src.val;
+		c->dst.val = c->src.orig_val;
 		c->lock_prefix = 1;
 		break;
-	case 0x88 ... 0x8b:	/* mov */
-		goto mov;
 	case 0x8c:  /* mov r/m, sreg */
 		if (c->modrm_reg > VCPU_SREG_GS) {
 			emulate_ud(ctxt);
@@ -2824,7 +3221,7 @@
 		c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu);
 		break;
 	case 0x8d: /* lea r16/r32, m */
-		c->dst.val = c->modrm_ea;
+		c->dst.val = c->src.addr.mem;
 		break;
 	case 0x8e: { /* mov seg, r/m16 */
 		uint16_t sel;
@@ -2847,76 +3244,87 @@
 	}
 	case 0x8f:		/* pop (sole member of Grp1a) */
 		rc = emulate_grp1a(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
-	case 0x90: /* nop / xchg r8,rax */
-		if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) {
-			c->dst.type = OP_NONE;  /* nop */
+	case 0x90 ... 0x97: /* nop / xchg reg, rax */
+		if (c->dst.addr.reg == &c->regs[VCPU_REGS_RAX])
 			break;
-		}
-	case 0x91 ... 0x97: /* xchg reg,rax */
-		c->src.type = OP_REG;
-		c->src.bytes = c->op_bytes;
-		c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
-		c->src.val = *(c->src.ptr);
 		goto xchg;
+	case 0x98: /* cbw/cwde/cdqe */
+		switch (c->op_bytes) {
+		case 2: c->dst.val = (s8)c->dst.val; break;
+		case 4: c->dst.val = (s16)c->dst.val; break;
+		case 8: c->dst.val = (s32)c->dst.val; break;
+		}
+		break;
 	case 0x9c: /* pushf */
 		c->src.val =  (unsigned long) ctxt->eflags;
 		emulate_push(ctxt, ops);
 		break;
 	case 0x9d: /* popf */
 		c->dst.type = OP_REG;
-		c->dst.ptr = (unsigned long *) &ctxt->eflags;
+		c->dst.addr.reg = &ctxt->eflags;
 		c->dst.bytes = c->op_bytes;
 		rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
-	case 0xa0 ... 0xa3:	/* mov */
-	case 0xa4 ... 0xa5:	/* movs */
-		goto mov;
 	case 0xa6 ... 0xa7:	/* cmps */
 		c->dst.type = OP_NONE; /* Disable writeback. */
-		DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
+		DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.addr.mem, c->dst.addr.mem);
 		goto cmp;
 	case 0xa8 ... 0xa9:	/* test ax, imm */
 		goto test;
-	case 0xaa ... 0xab:	/* stos */
-		c->dst.val = c->regs[VCPU_REGS_RAX];
-		break;
-	case 0xac ... 0xad:	/* lods */
-		goto mov;
 	case 0xae ... 0xaf:	/* scas */
-		DPRINTF("Urk! I don't handle SCAS.\n");
-		goto cannot_emulate;
-	case 0xb0 ... 0xbf: /* mov r, imm */
-		goto mov;
+		goto cmp;
 	case 0xc0 ... 0xc1:
 		emulate_grp2(ctxt);
 		break;
 	case 0xc3: /* ret */
 		c->dst.type = OP_REG;
-		c->dst.ptr = &c->eip;
+		c->dst.addr.reg = &c->eip;
 		c->dst.bytes = c->op_bytes;
 		goto pop_instruction;
-	case 0xc6 ... 0xc7:	/* mov (sole member of Grp11) */
-	mov:
-		c->dst.val = c->src.val;
+	case 0xc4:		/* les */
+		rc = emulate_load_segment(ctxt, ops, VCPU_SREG_ES);
+		break;
+	case 0xc5:		/* lds */
+		rc = emulate_load_segment(ctxt, ops, VCPU_SREG_DS);
 		break;
 	case 0xcb:		/* ret far */
 		rc = emulate_ret_far(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
+		break;
+	case 0xcc:		/* int3 */
+		irq = 3;
+		goto do_interrupt;
+	case 0xcd:		/* int n */
+		irq = c->src.val;
+	do_interrupt:
+		rc = emulate_int(ctxt, ops, irq);
+		break;
+	case 0xce:		/* into */
+		if (ctxt->eflags & EFLG_OF) {
+			irq = 4;
+			goto do_interrupt;
+		}
+		break;
+	case 0xcf:		/* iret */
+		rc = emulate_iret(ctxt, ops);
 		break;
 	case 0xd0 ... 0xd1:	/* Grp2 */
-		c->src.val = 1;
 		emulate_grp2(ctxt);
 		break;
 	case 0xd2 ... 0xd3:	/* Grp2 */
 		c->src.val = c->regs[VCPU_REGS_RCX];
 		emulate_grp2(ctxt);
 		break;
+	case 0xe0 ... 0xe2:	/* loop/loopz/loopnz */
+		register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
+		if (address_mask(c, c->regs[VCPU_REGS_RCX]) != 0 &&
+		    (c->b == 0xe2 || test_cc(c->b ^ 0x5, ctxt->eflags)))
+			jmp_rel(c, c->src.val);
+		break;
+	case 0xe3:	/* jcxz/jecxz/jrcxz */
+		if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0)
+			jmp_rel(c, c->src.val);
+		break;
 	case 0xe4: 	/* inb */
 	case 0xe5: 	/* in */
 		goto do_io_in;
@@ -2964,15 +3372,16 @@
 		break;
 	case 0xee: /* out dx,al */
 	case 0xef: /* out dx,(e/r)ax */
-		c->src.val = c->regs[VCPU_REGS_RDX];
+		c->dst.val = c->regs[VCPU_REGS_RDX];
 	do_io_out:
-		c->dst.bytes = min(c->dst.bytes, 4u);
-		if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
+		c->src.bytes = min(c->src.bytes, 4u);
+		if (!emulator_io_permited(ctxt, ops, c->dst.val,
+					  c->src.bytes)) {
 			emulate_gp(ctxt, 0);
 			goto done;
 		}
-		ops->pio_out_emulated(c->dst.bytes, c->src.val, &c->dst.val, 1,
-				      ctxt->vcpu);
+		ops->pio_out_emulated(c->src.bytes, c->dst.val,
+				      &c->src.val, 1, ctxt->vcpu);
 		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xf4:              /* hlt */
@@ -2981,24 +3390,22 @@
 	case 0xf5:	/* cmc */
 		/* complement carry flag from eflags reg */
 		ctxt->eflags ^= EFLG_CF;
-		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xf6 ... 0xf7:	/* Grp3 */
-		if (!emulate_grp3(ctxt, ops))
-			goto cannot_emulate;
+		rc = emulate_grp3(ctxt, ops);
 		break;
 	case 0xf8: /* clc */
 		ctxt->eflags &= ~EFLG_CF;
-		c->dst.type = OP_NONE;	/* Disable writeback. */
+		break;
+	case 0xf9: /* stc */
+		ctxt->eflags |= EFLG_CF;
 		break;
 	case 0xfa: /* cli */
 		if (emulator_bad_iopl(ctxt, ops)) {
 			emulate_gp(ctxt, 0);
 			goto done;
-		} else {
+		} else
 			ctxt->eflags &= ~X86_EFLAGS_IF;
-			c->dst.type = OP_NONE;	/* Disable writeback. */
-		}
 		break;
 	case 0xfb: /* sti */
 		if (emulator_bad_iopl(ctxt, ops)) {
@@ -3007,29 +3414,29 @@
 		} else {
 			ctxt->interruptibility = KVM_X86_SHADOW_INT_STI;
 			ctxt->eflags |= X86_EFLAGS_IF;
-			c->dst.type = OP_NONE;	/* Disable writeback. */
 		}
 		break;
 	case 0xfc: /* cld */
 		ctxt->eflags &= ~EFLG_DF;
-		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xfd: /* std */
 		ctxt->eflags |= EFLG_DF;
-		c->dst.type = OP_NONE;	/* Disable writeback. */
 		break;
 	case 0xfe: /* Grp4 */
 	grp45:
 		rc = emulate_grp45(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0xff: /* Grp5 */
 		if (c->modrm_reg == 5)
 			goto jump_far;
 		goto grp45;
+	default:
+		goto cannot_emulate;
 	}
 
+	if (rc != X86EMUL_CONTINUE)
+		goto done;
+
 writeback:
 	rc = writeback(ctxt, ops);
 	if (rc != X86EMUL_CONTINUE)
@@ -3050,25 +3457,32 @@
 				&c->dst);
 
 	if (c->rep_prefix && (c->d & String)) {
-		struct read_cache *rc = &ctxt->decode.io_read;
+		struct read_cache *r = &ctxt->decode.io_read;
 		register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
-		/*
-		 * Re-enter guest when pio read ahead buffer is empty or,
-		 * if it is not used, after each 1024 iteration.
-		 */
-		if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) ||
-		    (rc->end != 0 && rc->end == rc->pos))
-			ctxt->restart = false;
+
+		if (!string_insn_completed(ctxt)) {
+			/*
+			 * Re-enter guest when pio read ahead buffer is empty
+			 * or, if it is not used, after each 1024 iteration.
+			 */
+			if ((r->end != 0 || c->regs[VCPU_REGS_RCX] & 0x3ff) &&
+			    (r->end == 0 || r->end != r->pos)) {
+				/*
+				 * Reset read cache. Usually happens before
+				 * decode, but since instruction is restarted
+				 * we have to do it here.
+				 */
+				ctxt->decode.mem_read.end = 0;
+				return EMULATION_RESTART;
+			}
+			goto done; /* skip rip writeback */
+		}
 	}
-	/*
-	 * reset read cache here in case string instruction is restared
-	 * without decoding
-	 */
-	ctxt->decode.mem_read.end = 0;
+
 	ctxt->eip = c->eip;
 
 done:
-	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+	return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
 
 twobyte_insn:
 	switch (c->b) {
@@ -3091,7 +3505,7 @@
 			c->dst.type = OP_NONE;
 			break;
 		case 2: /* lgdt */
-			rc = read_descriptor(ctxt, ops, c->src.ptr,
+			rc = read_descriptor(ctxt, ops, c->src.addr.mem,
 					     &size, &address, c->op_bytes);
 			if (rc != X86EMUL_CONTINUE)
 				goto done;
@@ -3104,14 +3518,12 @@
 				switch (c->modrm_rm) {
 				case 1:
 					rc = kvm_fix_hypercall(ctxt->vcpu);
-					if (rc != X86EMUL_CONTINUE)
-						goto done;
 					break;
 				default:
 					goto cannot_emulate;
 				}
 			} else {
-				rc = read_descriptor(ctxt, ops, c->src.ptr,
+				rc = read_descriptor(ctxt, ops, c->src.addr.mem,
 						     &size, &address,
 						     c->op_bytes);
 				if (rc != X86EMUL_CONTINUE)
@@ -3126,7 +3538,7 @@
 			c->dst.val = ops->get_cr(0, ctxt->vcpu);
 			break;
 		case 6: /* lmsw */
-			ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
+			ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0eul) |
 				    (c->src.val & 0x0f), ctxt->vcpu);
 			c->dst.type = OP_NONE;
 			break;
@@ -3134,7 +3546,7 @@
 			emulate_ud(ctxt);
 			goto done;
 		case 7: /* invlpg*/
-			emulate_invlpg(ctxt->vcpu, c->modrm_ea);
+			emulate_invlpg(ctxt->vcpu, c->src.addr.mem);
 			/* Disable writeback. */
 			c->dst.type = OP_NONE;
 			break;
@@ -3144,23 +3556,16 @@
 		break;
 	case 0x05: 		/* syscall */
 		rc = emulate_syscall(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
-		else
-			goto writeback;
 		break;
 	case 0x06:
 		emulate_clts(ctxt->vcpu);
-		c->dst.type = OP_NONE;
 		break;
 	case 0x09:		/* wbinvd */
 		kvm_emulate_wbinvd(ctxt->vcpu);
-		c->dst.type = OP_NONE;
 		break;
 	case 0x08:		/* invd */
 	case 0x0d:		/* GrpP (prefetch) */
 	case 0x18:		/* Grp16 (prefetch/nop) */
-		c->dst.type = OP_NONE;
 		break;
 	case 0x20: /* mov cr, reg */
 		switch (c->modrm_reg) {
@@ -3170,8 +3575,7 @@
 			emulate_ud(ctxt);
 			goto done;
 		}
-		c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
-		c->dst.type = OP_NONE;	/* no writeback */
+		c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
 		break;
 	case 0x21: /* mov from dr to reg */
 		if ((ops->get_cr(4, ctxt->vcpu) & X86_CR4_DE) &&
@@ -3179,11 +3583,10 @@
 			emulate_ud(ctxt);
 			goto done;
 		}
-		ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu);
-		c->dst.type = OP_NONE;	/* no writeback */
+		ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
 		break;
 	case 0x22: /* mov reg, cr */
-		if (ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu)) {
+		if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) {
 			emulate_gp(ctxt, 0);
 			goto done;
 		}
@@ -3196,7 +3599,7 @@
 			goto done;
 		}
 
-		if (ops->set_dr(c->modrm_reg, c->regs[c->modrm_rm] &
+		if (ops->set_dr(c->modrm_reg, c->src.val &
 				((ctxt->mode == X86EMUL_MODE_PROT64) ?
 				 ~0ULL : ~0U), ctxt->vcpu) < 0) {
 			/* #UD condition is already handled by the code above */
@@ -3215,7 +3618,6 @@
 			goto done;
 		}
 		rc = X86EMUL_CONTINUE;
-		c->dst.type = OP_NONE;
 		break;
 	case 0x32:
 		/* rdmsr */
@@ -3227,21 +3629,12 @@
 			c->regs[VCPU_REGS_RDX] = msr_data >> 32;
 		}
 		rc = X86EMUL_CONTINUE;
-		c->dst.type = OP_NONE;
 		break;
 	case 0x34:		/* sysenter */
 		rc = emulate_sysenter(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
-		else
-			goto writeback;
 		break;
 	case 0x35:		/* sysexit */
 		rc = emulate_sysexit(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
-		else
-			goto writeback;
 		break;
 	case 0x40 ... 0x4f:	/* cmov */
 		c->dst.val = c->dst.orig_val = c->src.val;
@@ -3251,15 +3644,15 @@
 	case 0x80 ... 0x8f: /* jnz rel, etc*/
 		if (test_cc(c->b, ctxt->eflags))
 			jmp_rel(c, c->src.val);
-		c->dst.type = OP_NONE;
+		break;
+	case 0x90 ... 0x9f:     /* setcc r/m8 */
+		c->dst.val = test_cc(c->b, ctxt->eflags);
 		break;
 	case 0xa0:	  /* push fs */
 		emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
 		break;
 	case 0xa1:	 /* pop fs */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0xa3:
 	      bt:		/* bt */
@@ -3277,13 +3670,9 @@
 		break;
 	case 0xa9:	/* pop gs */
 		rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
 	case 0xab:
 	      bts:		/* bts */
-		/* only subword offset */
-		c->src.val &= (c->dst.bytes << 3) - 1;
 		emulate_2op_SrcV_nobyte("bts", c->src, c->dst, ctxt->eflags);
 		break;
 	case 0xac: /* shrd imm8, r, r/m */
@@ -3306,15 +3695,22 @@
 		} else {
 			/* Failure: write the value we saw to EAX. */
 			c->dst.type = OP_REG;
-			c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
+			c->dst.addr.reg = (unsigned long *)&c->regs[VCPU_REGS_RAX];
 		}
 		break;
+	case 0xb2:		/* lss */
+		rc = emulate_load_segment(ctxt, ops, VCPU_SREG_SS);
+		break;
 	case 0xb3:
 	      btr:		/* btr */
-		/* only subword offset */
-		c->src.val &= (c->dst.bytes << 3) - 1;
 		emulate_2op_SrcV_nobyte("btr", c->src, c->dst, ctxt->eflags);
 		break;
+	case 0xb4:		/* lfs */
+		rc = emulate_load_segment(ctxt, ops, VCPU_SREG_FS);
+		break;
+	case 0xb5:		/* lgs */
+		rc = emulate_load_segment(ctxt, ops, VCPU_SREG_GS);
+		break;
 	case 0xb6 ... 0xb7:	/* movzx */
 		c->dst.bytes = c->op_bytes;
 		c->dst.val = (c->d & ByteOp) ? (u8) c->src.val
@@ -3334,15 +3730,43 @@
 		break;
 	case 0xbb:
 	      btc:		/* btc */
-		/* only subword offset */
-		c->src.val &= (c->dst.bytes << 3) - 1;
 		emulate_2op_SrcV_nobyte("btc", c->src, c->dst, ctxt->eflags);
 		break;
+	case 0xbc: {		/* bsf */
+		u8 zf;
+		__asm__ ("bsf %2, %0; setz %1"
+			 : "=r"(c->dst.val), "=q"(zf)
+			 : "r"(c->src.val));
+		ctxt->eflags &= ~X86_EFLAGS_ZF;
+		if (zf) {
+			ctxt->eflags |= X86_EFLAGS_ZF;
+			c->dst.type = OP_NONE;	/* Disable writeback. */
+		}
+		break;
+	}
+	case 0xbd: {		/* bsr */
+		u8 zf;
+		__asm__ ("bsr %2, %0; setz %1"
+			 : "=r"(c->dst.val), "=q"(zf)
+			 : "r"(c->src.val));
+		ctxt->eflags &= ~X86_EFLAGS_ZF;
+		if (zf) {
+			ctxt->eflags |= X86_EFLAGS_ZF;
+			c->dst.type = OP_NONE;	/* Disable writeback. */
+		}
+		break;
+	}
 	case 0xbe ... 0xbf:	/* movsx */
 		c->dst.bytes = c->op_bytes;
 		c->dst.val = (c->d & ByteOp) ? (s8) c->src.val :
 							(s16) c->src.val;
 		break;
+	case 0xc0 ... 0xc1:	/* xadd */
+		emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
+		/* Write back the register source. */
+		c->src.val = c->dst.orig_val;
+		write_register_operand(&c->src);
+		break;
 	case 0xc3:		/* movnti */
 		c->dst.bytes = c->op_bytes;
 		c->dst.val = (c->op_bytes == 4) ? (u32) c->src.val :
@@ -3350,10 +3774,14 @@
 		break;
 	case 0xc7:		/* Grp9 (cmpxchg8b) */
 		rc = emulate_grp9(ctxt, ops);
-		if (rc != X86EMUL_CONTINUE)
-			goto done;
 		break;
+	default:
+		goto cannot_emulate;
 	}
+
+	if (rc != X86EMUL_CONTINUE)
+		goto done;
+
 	goto writeback;
 
 cannot_emulate:
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/i8254.c linux-libre-2.6.37-gnu/arch/x86/kvm/i8254.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/i8254.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/i8254.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  * Copyright (c) 2006 Intel Corporation
  * Copyright (c) 2007 Keir Fraser, XenSource Inc
  * Copyright (c) 2008 Intel Corporation
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -232,15 +232,6 @@
 	}
 }
 
-int pit_has_pending_timer(struct kvm_vcpu *vcpu)
-{
-	struct kvm_pit *pit = vcpu->kvm->arch.vpit;
-
-	if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack)
-		return atomic_read(&pit->pit_state.pit_timer.pending);
-	return 0;
-}
-
 static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
 {
 	struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state,
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/i8259.c linux-libre-2.6.37-gnu/arch/x86/kvm/i8259.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/i8259.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/i8259.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2003-2004 Fabrice Bellard
  * Copyright (c) 2007 Intel Corporation
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -39,7 +39,7 @@
 static void pic_lock(struct kvm_pic *s)
 	__acquires(&s->lock)
 {
-	raw_spin_lock(&s->lock);
+	spin_lock(&s->lock);
 }
 
 static void pic_unlock(struct kvm_pic *s)
@@ -51,7 +51,7 @@
 
 	s->wakeup_needed = false;
 
-	raw_spin_unlock(&s->lock);
+	spin_unlock(&s->lock);
 
 	if (wakeup) {
 		kvm_for_each_vcpu(i, vcpu, s->kvm) {
@@ -67,6 +67,7 @@
 		if (!found)
 			return;
 
+		kvm_make_request(KVM_REQ_EVENT, found);
 		kvm_vcpu_kick(found);
 	}
 }
@@ -308,13 +309,17 @@
 	addr &= 1;
 	if (addr == 0) {
 		if (val & 0x10) {
-			kvm_pic_reset(s);	/* init */
-			/*
-			 * deassert a pending interrupt
-			 */
-			pic_irq_request(s->pics_state->kvm, 0);
-			s->init_state = 1;
 			s->init4 = val & 1;
+			s->last_irr = 0;
+			s->imr = 0;
+			s->priority_add = 0;
+			s->special_mask = 0;
+			s->read_reg_select = 0;
+			if (!s->init4) {
+				s->special_fully_nested_mode = 0;
+				s->auto_eoi = 0;
+			}
+			s->init_state = 1;
 			if (val & 0x02)
 				printk(KERN_ERR "single mode not supported");
 			if (val & 0x08)
@@ -564,12 +569,14 @@
 	s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
 	if (!s)
 		return NULL;
-	raw_spin_lock_init(&s->lock);
+	spin_lock_init(&s->lock);
 	s->kvm = kvm;
 	s->pics[0].elcr_mask = 0xf8;
 	s->pics[1].elcr_mask = 0xde;
 	s->pics[0].pics_state = s;
 	s->pics[1].pics_state = s;
+	s->pics[0].isr_ack = 0xff;
+	s->pics[1].isr_ack = 0xff;
 
 	/*
 	 * Initialize PIO device
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/irq.c linux-libre-2.6.37-gnu/arch/x86/kvm/irq.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * irq.c: API for in kernel interrupt controller
  * Copyright (c) 2007, Intel Corporation.
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -33,12 +33,7 @@
  */
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-	int ret;
-
-	ret = pit_has_pending_timer(vcpu);
-	ret |= apic_has_pending_timer(vcpu);
-
-	return ret;
+	return apic_has_pending_timer(vcpu);
 }
 EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/irq.h linux-libre-2.6.37-gnu/arch/x86/kvm/irq.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/irq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/irq.h	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 };
 
 struct kvm_pic {
-	raw_spinlock_t lock;
+	spinlock_t lock;
 	bool wakeup_needed;
 	unsigned pending_acks;
 	struct kvm *kvm;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/Kconfig linux-libre-2.6.37-gnu/arch/x86/kvm/Kconfig
--- linux-libre-2.6.36-gnu/arch/x86/kvm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -64,6 +64,13 @@
 	  To compile this as a module, choose M here: the module
 	  will be called kvm-amd.
 
+config KVM_MMU_AUDIT
+	bool "Audit KVM MMU"
+	depends on KVM && TRACEPOINTS
+	---help---
+	 This option adds a R/W kVM module parameter 'mmu_audit', which allows
+	 audit  KVM MMU at runtime.
+
 # OK, it's a little counter-intuitive to do this, but it puts it neatly under
 # the virtualization menu.
 source drivers/vhost/Kconfig
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/kvm_cache_regs.h linux-libre-2.6.37-gnu/arch/x86/kvm/kvm_cache_regs.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/kvm_cache_regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/kvm_cache_regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,14 @@
 		      (unsigned long *)&vcpu->arch.regs_avail))
 		kvm_x86_ops->cache_reg(vcpu, VCPU_EXREG_PDPTR);
 
-	return vcpu->arch.pdptrs[index];
+	return vcpu->arch.walk_mmu->pdptrs[index];
+}
+
+static inline u64 kvm_pdptr_read_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, int index)
+{
+	load_pdptrs(vcpu, mmu, mmu->get_cr3(vcpu));
+
+	return mmu->pdptrs[index];
 }
 
 static inline ulong kvm_read_cr0_bits(struct kvm_vcpu *vcpu, ulong mask)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/lapic.c linux-libre-2.6.37-gnu/arch/x86/kvm/lapic.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/lapic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/lapic.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  * Copyright (C) 2006 Qumranet, Inc.
  * Copyright (C) 2007 Novell
  * Copyright (C) 2007 Intel
- * Copyright 2009 Red Hat, Inc. and/or its affilates.
+ * Copyright 2009 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Dor Laor <dor.laor@qumranet.com>
@@ -259,9 +259,10 @@
 
 static void apic_update_ppr(struct kvm_lapic *apic)
 {
-	u32 tpr, isrv, ppr;
+	u32 tpr, isrv, ppr, old_ppr;
 	int isr;
 
+	old_ppr = apic_get_reg(apic, APIC_PROCPRI);
 	tpr = apic_get_reg(apic, APIC_TASKPRI);
 	isr = apic_find_highest_isr(apic);
 	isrv = (isr != -1) ? isr : 0;
@@ -274,7 +275,10 @@
 	apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
 		   apic, ppr, isr, isrv);
 
-	apic_set_reg(apic, APIC_PROCPRI, ppr);
+	if (old_ppr != ppr) {
+		apic_set_reg(apic, APIC_PROCPRI, ppr);
+		kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
+	}
 }
 
 static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
@@ -391,6 +395,7 @@
 			break;
 		}
 
+		kvm_make_request(KVM_REQ_EVENT, vcpu);
 		kvm_vcpu_kick(vcpu);
 		break;
 
@@ -416,6 +421,7 @@
 				       "INIT on a runnable vcpu %d\n",
 				       vcpu->vcpu_id);
 			vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
+			kvm_make_request(KVM_REQ_EVENT, vcpu);
 			kvm_vcpu_kick(vcpu);
 		} else {
 			apic_debug("Ignoring de-assert INIT to vcpu %d\n",
@@ -430,6 +436,7 @@
 			result = 1;
 			vcpu->arch.sipi_vector = vector;
 			vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED;
+			kvm_make_request(KVM_REQ_EVENT, vcpu);
 			kvm_vcpu_kick(vcpu);
 		}
 		break;
@@ -475,6 +482,7 @@
 		trigger_mode = IOAPIC_EDGE_TRIG;
 	if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
 		kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
+	kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
 }
 
 static void apic_send_ipi(struct kvm_lapic *apic)
@@ -1056,14 +1064,13 @@
 
 	vcpu->arch.apic = apic;
 
-	apic->regs_page = alloc_page(GFP_KERNEL);
+	apic->regs_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
 	if (apic->regs_page == NULL) {
 		printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
 		       vcpu->vcpu_id);
 		goto nomem_free_apic;
 	}
 	apic->regs = page_address(apic->regs_page);
-	memset(apic->regs, 0, PAGE_SIZE);
 	apic->vcpu = vcpu;
 
 	hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
@@ -1152,6 +1159,7 @@
 	update_divide_count(apic);
 	start_apic_timer(apic);
 	apic->irr_pending = true;
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 }
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/mmu_audit.c linux-libre-2.6.37-gnu/arch/x86/kvm/mmu_audit.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/mmu_audit.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/mmu_audit.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,299 @@
+/*
+ * mmu_audit.c:
+ *
+ * Audit code for KVM MMU
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
+ *
+ * Authors:
+ *   Yaniv Kamay  <yaniv@qumranet.com>
+ *   Avi Kivity   <avi@qumranet.com>
+ *   Marcelo Tosatti <mtosatti@redhat.com>
+ *   Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/ratelimit.h>
+
+static int audit_point;
+
+#define audit_printk(fmt, args...)		\
+	printk(KERN_ERR "audit: (%s) error: "	\
+		fmt, audit_point_name[audit_point], ##args)
+
+typedef void (*inspect_spte_fn) (struct kvm_vcpu *vcpu, u64 *sptep, int level);
+
+static void __mmu_spte_walk(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
+			    inspect_spte_fn fn, int level)
+{
+	int i;
+
+	for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+		u64 *ent = sp->spt;
+
+		fn(vcpu, ent + i, level);
+
+		if (is_shadow_present_pte(ent[i]) &&
+		      !is_last_spte(ent[i], level)) {
+			struct kvm_mmu_page *child;
+
+			child = page_header(ent[i] & PT64_BASE_ADDR_MASK);
+			__mmu_spte_walk(vcpu, child, fn, level - 1);
+		}
+	}
+}
+
+static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
+{
+	int i;
+	struct kvm_mmu_page *sp;
+
+	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
+		return;
+
+	if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
+		hpa_t root = vcpu->arch.mmu.root_hpa;
+
+		sp = page_header(root);
+		__mmu_spte_walk(vcpu, sp, fn, PT64_ROOT_LEVEL);
+		return;
+	}
+
+	for (i = 0; i < 4; ++i) {
+		hpa_t root = vcpu->arch.mmu.pae_root[i];
+
+		if (root && VALID_PAGE(root)) {
+			root &= PT64_BASE_ADDR_MASK;
+			sp = page_header(root);
+			__mmu_spte_walk(vcpu, sp, fn, 2);
+		}
+	}
+
+	return;
+}
+
+typedef void (*sp_handler) (struct kvm *kvm, struct kvm_mmu_page *sp);
+
+static void walk_all_active_sps(struct kvm *kvm, sp_handler fn)
+{
+	struct kvm_mmu_page *sp;
+
+	list_for_each_entry(sp, &kvm->arch.active_mmu_pages, link)
+		fn(kvm, sp);
+}
+
+static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+	struct kvm_mmu_page *sp;
+	gfn_t gfn;
+	pfn_t pfn;
+	hpa_t hpa;
+
+	sp = page_header(__pa(sptep));
+
+	if (sp->unsync) {
+		if (level != PT_PAGE_TABLE_LEVEL) {
+			audit_printk("unsync sp: %p level = %d\n", sp, level);
+			return;
+		}
+
+		if (*sptep == shadow_notrap_nonpresent_pte) {
+			audit_printk("notrap spte in unsync sp: %p\n", sp);
+			return;
+		}
+	}
+
+	if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) {
+		audit_printk("notrap spte in direct sp: %p\n", sp);
+		return;
+	}
+
+	if (!is_shadow_present_pte(*sptep) || !is_last_spte(*sptep, level))
+		return;
+
+	gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
+	pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
+
+	if (is_error_pfn(pfn)) {
+		kvm_release_pfn_clean(pfn);
+		return;
+	}
+
+	hpa =  pfn << PAGE_SHIFT;
+	if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
+		audit_printk("levels %d pfn %llx hpa %llx ent %llxn",
+				   vcpu->arch.mmu.root_level, pfn, hpa, *sptep);
+}
+
+static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
+{
+	unsigned long *rmapp;
+	struct kvm_mmu_page *rev_sp;
+	gfn_t gfn;
+
+
+	rev_sp = page_header(__pa(sptep));
+	gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
+
+	if (!gfn_to_memslot(kvm, gfn)) {
+		if (!printk_ratelimit())
+			return;
+		audit_printk("no memslot for gfn %llx\n", gfn);
+		audit_printk("index %ld of sp (gfn=%llx)\n",
+		       (long int)(sptep - rev_sp->spt), rev_sp->gfn);
+		dump_stack();
+		return;
+	}
+
+	rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
+	if (!*rmapp) {
+		if (!printk_ratelimit())
+			return;
+		audit_printk("no rmap for writable spte %llx\n", *sptep);
+		dump_stack();
+	}
+}
+
+static void audit_sptes_have_rmaps(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+	if (is_shadow_present_pte(*sptep) && is_last_spte(*sptep, level))
+		inspect_spte_has_rmap(vcpu->kvm, sptep);
+}
+
+static void audit_spte_after_sync(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+	struct kvm_mmu_page *sp = page_header(__pa(sptep));
+
+	if (audit_point == AUDIT_POST_SYNC && sp->unsync)
+		audit_printk("meet unsync sp(%p) after sync root.\n", sp);
+}
+
+static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+	int i;
+
+	if (sp->role.level != PT_PAGE_TABLE_LEVEL)
+		return;
+
+	for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
+		if (!is_rmap_spte(sp->spt[i]))
+			continue;
+
+		inspect_spte_has_rmap(kvm, sp->spt + i);
+	}
+}
+
+static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+	struct kvm_memory_slot *slot;
+	unsigned long *rmapp;
+	u64 *spte;
+
+	if (sp->role.direct || sp->unsync || sp->role.invalid)
+		return;
+
+	slot = gfn_to_memslot(kvm, sp->gfn);
+	rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
+
+	spte = rmap_next(kvm, rmapp, NULL);
+	while (spte) {
+		if (is_writable_pte(*spte))
+			audit_printk("shadow page has writable mappings: gfn "
+				     "%llx role %x\n", sp->gfn, sp->role.word);
+		spte = rmap_next(kvm, rmapp, spte);
+	}
+}
+
+static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+	check_mappings_rmap(kvm, sp);
+	audit_write_protection(kvm, sp);
+}
+
+static void audit_all_active_sps(struct kvm *kvm)
+{
+	walk_all_active_sps(kvm, audit_sp);
+}
+
+static void audit_spte(struct kvm_vcpu *vcpu, u64 *sptep, int level)
+{
+	audit_sptes_have_rmaps(vcpu, sptep, level);
+	audit_mappings(vcpu, sptep, level);
+	audit_spte_after_sync(vcpu, sptep, level);
+}
+
+static void audit_vcpu_spte(struct kvm_vcpu *vcpu)
+{
+	mmu_spte_walk(vcpu, audit_spte);
+}
+
+static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int point)
+{
+	static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
+
+	if (!__ratelimit(&ratelimit_state))
+		return;
+
+	audit_point = point;
+	audit_all_active_sps(vcpu->kvm);
+	audit_vcpu_spte(vcpu);
+}
+
+static bool mmu_audit;
+
+static void mmu_audit_enable(void)
+{
+	int ret;
+
+	if (mmu_audit)
+		return;
+
+	ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
+	WARN_ON(ret);
+
+	mmu_audit = true;
+}
+
+static void mmu_audit_disable(void)
+{
+	if (!mmu_audit)
+		return;
+
+	unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
+	tracepoint_synchronize_unregister();
+	mmu_audit = false;
+}
+
+static int mmu_audit_set(const char *val, const struct kernel_param *kp)
+{
+	int ret;
+	unsigned long enable;
+
+	ret = strict_strtoul(val, 10, &enable);
+	if (ret < 0)
+		return -EINVAL;
+
+	switch (enable) {
+	case 0:
+		mmu_audit_disable();
+		break;
+	case 1:
+		mmu_audit_enable();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct kernel_param_ops audit_param_ops = {
+	.set = mmu_audit_set,
+	.get = param_get_bool,
+};
+
+module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644);
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/mmu.c linux-libre-2.6.37-gnu/arch/x86/kvm/mmu.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
  * MMU support
  *
  * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -49,15 +49,25 @@
  */
 bool tdp_enabled = false;
 
-#undef MMU_DEBUG
+enum {
+	AUDIT_PRE_PAGE_FAULT,
+	AUDIT_POST_PAGE_FAULT,
+	AUDIT_PRE_PTE_WRITE,
+	AUDIT_POST_PTE_WRITE,
+	AUDIT_PRE_SYNC,
+	AUDIT_POST_SYNC
+};
 
-#undef AUDIT
+char *audit_point_name[] = {
+	"pre page fault",
+	"post page fault",
+	"pre pte write",
+	"post pte write",
+	"pre sync",
+	"post sync"
+};
 
-#ifdef AUDIT
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
-#else
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
-#endif
+#undef MMU_DEBUG
 
 #ifdef MMU_DEBUG
 
@@ -71,7 +81,7 @@
 
 #endif
 
-#if defined(MMU_DEBUG) || defined(AUDIT)
+#ifdef MMU_DEBUG
 static int dbg = 0;
 module_param(dbg, bool, 0644);
 #endif
@@ -89,6 +99,8 @@
 	}
 #endif
 
+#define PTE_PREFETCH_NUM		8
+
 #define PT_FIRST_AVAIL_BITS_SHIFT 9
 #define PT64_SECOND_AVAIL_BITS_SHIFT 52
 
@@ -178,6 +190,7 @@
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
 static struct kmem_cache *mmu_page_header_cache;
+static struct percpu_counter kvm_total_used_mmu_pages;
 
 static u64 __read_mostly shadow_trap_nonpresent_pte;
 static u64 __read_mostly shadow_notrap_nonpresent_pte;
@@ -299,18 +312,50 @@
 #endif
 }
 
+static bool spte_has_volatile_bits(u64 spte)
+{
+	if (!shadow_accessed_mask)
+		return false;
+
+	if (!is_shadow_present_pte(spte))
+		return false;
+
+	if ((spte & shadow_accessed_mask) &&
+	      (!is_writable_pte(spte) || (spte & shadow_dirty_mask)))
+		return false;
+
+	return true;
+}
+
+static bool spte_is_bit_cleared(u64 old_spte, u64 new_spte, u64 bit_mask)
+{
+	return (old_spte & bit_mask) && !(new_spte & bit_mask);
+}
+
 static void update_spte(u64 *sptep, u64 new_spte)
 {
-	u64 old_spte;
+	u64 mask, old_spte = *sptep;
 
-	if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) ||
-	      !is_rmap_spte(*sptep))
+	WARN_ON(!is_rmap_spte(new_spte));
+
+	new_spte |= old_spte & shadow_dirty_mask;
+
+	mask = shadow_accessed_mask;
+	if (is_writable_pte(old_spte))
+		mask |= shadow_dirty_mask;
+
+	if (!spte_has_volatile_bits(old_spte) || (new_spte & mask) == mask)
 		__set_spte(sptep, new_spte);
-	else {
+	else
 		old_spte = __xchg_spte(sptep, new_spte);
-		if (old_spte & shadow_accessed_mask)
-			mark_page_accessed(pfn_to_page(spte_to_pfn(old_spte)));
-	}
+
+	if (!shadow_accessed_mask)
+		return;
+
+	if (spte_is_bit_cleared(old_spte, new_spte, shadow_accessed_mask))
+		kvm_set_pfn_accessed(spte_to_pfn(old_spte));
+	if (spte_is_bit_cleared(old_spte, new_spte, shadow_dirty_mask))
+		kvm_set_pfn_dirty(spte_to_pfn(old_spte));
 }
 
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
@@ -367,7 +412,7 @@
 	if (r)
 		goto out;
 	r = mmu_topup_memory_cache(&vcpu->arch.mmu_rmap_desc_cache,
-				   rmap_desc_cache, 4);
+				   rmap_desc_cache, 4 + PTE_PREFETCH_NUM);
 	if (r)
 		goto out;
 	r = mmu_topup_memory_cache_page(&vcpu->arch.mmu_page_cache, 8);
@@ -591,6 +636,7 @@
 		desc->sptes[0] = (u64 *)*rmapp;
 		desc->sptes[1] = spte;
 		*rmapp = (unsigned long)desc | 1;
+		++count;
 	} else {
 		rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
 		desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
@@ -603,7 +649,7 @@
 			desc = desc->more;
 		}
 		for (i = 0; desc->sptes[i]; ++i)
-			;
+			++count;
 		desc->sptes[i] = spte;
 	}
 	return count;
@@ -645,18 +691,17 @@
 	gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
 	rmapp = gfn_to_rmap(kvm, gfn, sp->role.level);
 	if (!*rmapp) {
-		printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
+		printk(KERN_ERR "rmap_remove: %p 0->BUG\n", spte);
 		BUG();
 	} else if (!(*rmapp & 1)) {
-		rmap_printk("rmap_remove:  %p %llx 1->0\n", spte, *spte);
+		rmap_printk("rmap_remove:  %p 1->0\n", spte);
 		if ((u64 *)*rmapp != spte) {
-			printk(KERN_ERR "rmap_remove:  %p %llx 1->BUG\n",
-			       spte, *spte);
+			printk(KERN_ERR "rmap_remove:  %p 1->BUG\n", spte);
 			BUG();
 		}
 		*rmapp = 0;
 	} else {
-		rmap_printk("rmap_remove:  %p %llx many->many\n", spte, *spte);
+		rmap_printk("rmap_remove:  %p many->many\n", spte);
 		desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
 		prev_desc = NULL;
 		while (desc) {
@@ -670,35 +715,36 @@
 			prev_desc = desc;
 			desc = desc->more;
 		}
-		pr_err("rmap_remove: %p %llx many->many\n", spte, *spte);
+		pr_err("rmap_remove: %p many->many\n", spte);
 		BUG();
 	}
 }
 
-static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+static int set_spte_track_bits(u64 *sptep, u64 new_spte)
 {
 	pfn_t pfn;
 	u64 old_spte = *sptep;
 
-	if (!shadow_accessed_mask || !is_shadow_present_pte(old_spte) ||
-	      old_spte & shadow_accessed_mask) {
+	if (!spte_has_volatile_bits(old_spte))
 		__set_spte(sptep, new_spte);
-	} else
+	else
 		old_spte = __xchg_spte(sptep, new_spte);
 
 	if (!is_rmap_spte(old_spte))
-		return;
+		return 0;
+
 	pfn = spte_to_pfn(old_spte);
 	if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
 		kvm_set_pfn_accessed(pfn);
-	if (is_writable_pte(old_spte))
+	if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
 		kvm_set_pfn_dirty(pfn);
+	return 1;
 }
 
 static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
 {
-	set_spte_track_bits(sptep, new_spte);
-	rmap_remove(kvm, sptep);
+	if (set_spte_track_bits(sptep, new_spte))
+		rmap_remove(kvm, sptep);
 }
 
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
@@ -746,13 +792,6 @@
 		}
 		spte = rmap_next(kvm, rmapp, spte);
 	}
-	if (write_protected) {
-		pfn_t pfn;
-
-		spte = rmap_next(kvm, rmapp, NULL);
-		pfn = spte_to_pfn(*spte);
-		kvm_set_pfn_dirty(pfn);
-	}
 
 	/* check for huge page mappings */
 	for (i = PT_DIRECTORY_LEVEL;
@@ -947,6 +986,18 @@
 }
 #endif
 
+/*
+ * This value is the sum of all of the kvm instances's
+ * kvm->arch.n_used_mmu_pages values.  We need a global,
+ * aggregate version in order to make the slab shrinker
+ * faster
+ */
+static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, int nr)
+{
+	kvm->arch.n_used_mmu_pages += nr;
+	percpu_counter_add(&kvm_total_used_mmu_pages, nr);
+}
+
 static void kvm_mmu_free_page(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
 	ASSERT(is_empty_shadow_page(sp->spt));
@@ -956,7 +1007,7 @@
 	if (!sp->role.direct)
 		__free_page(virt_to_page(sp->gfns));
 	kmem_cache_free(mmu_page_header_cache, sp);
-	++kvm->arch.n_free_mmu_pages;
+	kvm_mod_used_mmu_pages(kvm, -1);
 }
 
 static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -979,7 +1030,7 @@
 	bitmap_zero(sp->slot_bitmap, KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS);
 	sp->multimapped = 0;
 	sp->parent_pte = parent_pte;
-	--vcpu->kvm->arch.n_free_mmu_pages;
+	kvm_mod_used_mmu_pages(vcpu->kvm, +1);
 	return sp;
 }
 
@@ -1403,7 +1454,8 @@
 	if (role.direct)
 		role.cr4_pae = 0;
 	role.access = access;
-	if (!tdp_enabled && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
+	if (!vcpu->arch.mmu.direct_map
+	    && vcpu->arch.mmu.root_level <= PT32_ROOT_LEVEL) {
 		quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
 		quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
 		role.quadrant = quadrant;
@@ -1458,6 +1510,12 @@
 	iterator->addr = addr;
 	iterator->shadow_addr = vcpu->arch.mmu.root_hpa;
 	iterator->level = vcpu->arch.mmu.shadow_root_level;
+
+	if (iterator->level == PT64_ROOT_LEVEL &&
+	    vcpu->arch.mmu.root_level < PT64_ROOT_LEVEL &&
+	    !vcpu->arch.mmu.direct_map)
+		--iterator->level;
+
 	if (iterator->level == PT32E_ROOT_LEVEL) {
 		iterator->shadow_addr
 			= vcpu->arch.mmu.pae_root[(addr >> 30) & 3];
@@ -1665,41 +1723,31 @@
 
 /*
  * Changing the number of mmu pages allocated to the vm
- * Note: if kvm_nr_mmu_pages is too small, you will get dead lock
+ * Note: if goal_nr_mmu_pages is too small, you will get dead lock
  */
-void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages)
+void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int goal_nr_mmu_pages)
 {
-	int used_pages;
 	LIST_HEAD(invalid_list);
-
-	used_pages = kvm->arch.n_alloc_mmu_pages - kvm->arch.n_free_mmu_pages;
-	used_pages = max(0, used_pages);
-
 	/*
 	 * If we set the number of mmu pages to be smaller be than the
 	 * number of actived pages , we must to free some mmu pages before we
 	 * change the value
 	 */
 
-	if (used_pages > kvm_nr_mmu_pages) {
-		while (used_pages > kvm_nr_mmu_pages &&
+	if (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages) {
+		while (kvm->arch.n_used_mmu_pages > goal_nr_mmu_pages &&
 			!list_empty(&kvm->arch.active_mmu_pages)) {
 			struct kvm_mmu_page *page;
 
 			page = container_of(kvm->arch.active_mmu_pages.prev,
 					    struct kvm_mmu_page, link);
-			used_pages -= kvm_mmu_prepare_zap_page(kvm, page,
-							       &invalid_list);
+			kvm_mmu_prepare_zap_page(kvm, page, &invalid_list);
+			kvm_mmu_commit_zap_page(kvm, &invalid_list);
 		}
-		kvm_mmu_commit_zap_page(kvm, &invalid_list);
-		kvm_nr_mmu_pages = used_pages;
-		kvm->arch.n_free_mmu_pages = 0;
+		goal_nr_mmu_pages = kvm->arch.n_used_mmu_pages;
 	}
-	else
-		kvm->arch.n_free_mmu_pages += kvm_nr_mmu_pages
-					 - kvm->arch.n_alloc_mmu_pages;
 
-	kvm->arch.n_alloc_mmu_pages = kvm_nr_mmu_pages;
+	kvm->arch.n_max_mmu_pages = goal_nr_mmu_pages;
 }
 
 static int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
@@ -1709,11 +1757,11 @@
 	LIST_HEAD(invalid_list);
 	int r;
 
-	pgprintk("%s: looking for gfn %lx\n", __func__, gfn);
+	pgprintk("%s: looking for gfn %llx\n", __func__, gfn);
 	r = 0;
 
 	for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
-		pgprintk("%s: gfn %lx role %x\n", __func__, gfn,
+		pgprintk("%s: gfn %llx role %x\n", __func__, gfn,
 			 sp->role.word);
 		r = 1;
 		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
@@ -1729,7 +1777,7 @@
 	LIST_HEAD(invalid_list);
 
 	for_each_gfn_indirect_valid_sp(kvm, sp, gfn, node) {
-		pgprintk("%s: zap %lx %x\n",
+		pgprintk("%s: zap %llx %x\n",
 			 __func__, gfn, sp->role.word);
 		kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list);
 	}
@@ -1925,7 +1973,7 @@
 	 * whether the guest actually used the pte (in order to detect
 	 * demand paging).
 	 */
-	spte = shadow_base_present_pte | shadow_dirty_mask;
+	spte = shadow_base_present_pte;
 	if (!speculative)
 		spte |= shadow_accessed_mask;
 	if (!dirty)
@@ -1948,8 +1996,8 @@
 	spte |= (u64)pfn << PAGE_SHIFT;
 
 	if ((pte_access & ACC_WRITE_MASK)
-	    || (!tdp_enabled && write_fault && !is_write_protection(vcpu)
-		&& !user_fault)) {
+	    || (!vcpu->arch.mmu.direct_map && write_fault
+		&& !is_write_protection(vcpu) && !user_fault)) {
 
 		if (level > PT_PAGE_TABLE_LEVEL &&
 		    has_wrprotected_page(vcpu->kvm, gfn, level)) {
@@ -1960,7 +2008,8 @@
 
 		spte |= PT_WRITABLE_MASK;
 
-		if (!tdp_enabled && !(pte_access & ACC_WRITE_MASK))
+		if (!vcpu->arch.mmu.direct_map
+		    && !(pte_access & ACC_WRITE_MASK))
 			spte &= ~PT_USER_MASK;
 
 		/*
@@ -1973,7 +2022,7 @@
 			goto set_pte;
 
 		if (mmu_need_write_protect(vcpu, gfn, can_unsync)) {
-			pgprintk("%s: found shadow page for %lx, marking ro\n",
+			pgprintk("%s: found shadow page for %llx, marking ro\n",
 				 __func__, gfn);
 			ret = 1;
 			pte_access &= ~ACC_WRITE_MASK;
@@ -1986,8 +2035,6 @@
 		mark_page_dirty(vcpu->kvm, gfn);
 
 set_pte:
-	if (is_writable_pte(*sptep) && !is_writable_pte(spte))
-		kvm_set_pfn_dirty(pfn);
 	update_spte(sptep, spte);
 done:
 	return ret;
@@ -2004,7 +2051,7 @@
 	int rmap_count;
 
 	pgprintk("%s: spte %llx access %x write_fault %d"
-		 " user_fault %d gfn %lx\n",
+		 " user_fault %d gfn %llx\n",
 		 __func__, *sptep, pt_access,
 		 write_fault, user_fault, gfn);
 
@@ -2023,7 +2070,7 @@
 			__set_spte(sptep, shadow_trap_nonpresent_pte);
 			kvm_flush_remote_tlbs(vcpu->kvm);
 		} else if (pfn != spte_to_pfn(*sptep)) {
-			pgprintk("hfn old %lx new %lx\n",
+			pgprintk("hfn old %llx new %llx\n",
 				 spte_to_pfn(*sptep), pfn);
 			drop_spte(vcpu->kvm, sptep, shadow_trap_nonpresent_pte);
 			kvm_flush_remote_tlbs(vcpu->kvm);
@@ -2040,7 +2087,7 @@
 	}
 
 	pgprintk("%s: setting spte %llx\n", __func__, *sptep);
-	pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n",
+	pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
 		 is_large_pte(*sptep)? "2MB" : "4kB",
 		 *sptep & PT_PRESENT_MASK ?"RW":"R", gfn,
 		 *sptep, sptep);
@@ -2064,6 +2111,105 @@
 {
 }
 
+static struct kvm_memory_slot *
+pte_prefetch_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn, bool no_dirty_log)
+{
+	struct kvm_memory_slot *slot;
+
+	slot = gfn_to_memslot(vcpu->kvm, gfn);
+	if (!slot || slot->flags & KVM_MEMSLOT_INVALID ||
+	      (no_dirty_log && slot->dirty_bitmap))
+		slot = NULL;
+
+	return slot;
+}
+
+static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
+				     bool no_dirty_log)
+{
+	struct kvm_memory_slot *slot;
+	unsigned long hva;
+
+	slot = pte_prefetch_gfn_to_memslot(vcpu, gfn, no_dirty_log);
+	if (!slot) {
+		get_page(bad_page);
+		return page_to_pfn(bad_page);
+	}
+
+	hva = gfn_to_hva_memslot(slot, gfn);
+
+	return hva_to_pfn_atomic(vcpu->kvm, hva);
+}
+
+static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
+				    struct kvm_mmu_page *sp,
+				    u64 *start, u64 *end)
+{
+	struct page *pages[PTE_PREFETCH_NUM];
+	unsigned access = sp->role.access;
+	int i, ret;
+	gfn_t gfn;
+
+	gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt);
+	if (!pte_prefetch_gfn_to_memslot(vcpu, gfn, access & ACC_WRITE_MASK))
+		return -1;
+
+	ret = gfn_to_page_many_atomic(vcpu->kvm, gfn, pages, end - start);
+	if (ret <= 0)
+		return -1;
+
+	for (i = 0; i < ret; i++, gfn++, start++)
+		mmu_set_spte(vcpu, start, ACC_ALL,
+			     access, 0, 0, 1, NULL,
+			     sp->role.level, gfn,
+			     page_to_pfn(pages[i]), true, true);
+
+	return 0;
+}
+
+static void __direct_pte_prefetch(struct kvm_vcpu *vcpu,
+				  struct kvm_mmu_page *sp, u64 *sptep)
+{
+	u64 *spte, *start = NULL;
+	int i;
+
+	WARN_ON(!sp->role.direct);
+
+	i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1);
+	spte = sp->spt + i;
+
+	for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) {
+		if (*spte != shadow_trap_nonpresent_pte || spte == sptep) {
+			if (!start)
+				continue;
+			if (direct_pte_prefetch_many(vcpu, sp, start, spte) < 0)
+				break;
+			start = NULL;
+		} else if (!start)
+			start = spte;
+	}
+}
+
+static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
+{
+	struct kvm_mmu_page *sp;
+
+	/*
+	 * Since it's no accessed bit on EPT, it's no way to
+	 * distinguish between actually accessed translations
+	 * and prefetched, so disable pte prefetch if EPT is
+	 * enabled.
+	 */
+	if (!shadow_accessed_mask)
+		return;
+
+	sp = page_header(__pa(sptep));
+	if (sp->role.level > PT_PAGE_TABLE_LEVEL)
+		return;
+
+	__direct_pte_prefetch(vcpu, sp, sptep);
+}
+
 static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
 			int level, gfn_t gfn, pfn_t pfn)
 {
@@ -2077,6 +2223,7 @@
 			mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL,
 				     0, write, 1, &pt_write,
 				     level, gfn, pfn, false, true);
+			direct_pte_prefetch(vcpu, iterator.sptep);
 			++vcpu->stat.pf_fixed;
 			break;
 		}
@@ -2098,28 +2245,31 @@
 			__set_spte(iterator.sptep,
 				   __pa(sp->spt)
 				   | PT_PRESENT_MASK | PT_WRITABLE_MASK
-				   | shadow_user_mask | shadow_x_mask);
+				   | shadow_user_mask | shadow_x_mask
+				   | shadow_accessed_mask);
 		}
 	}
 	return pt_write;
 }
 
-static void kvm_send_hwpoison_signal(struct kvm *kvm, gfn_t gfn)
+static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *tsk)
 {
-	char buf[1];
-	void __user *hva;
-	int r;
+	siginfo_t info;
 
-	/* Touch the page, so send SIGBUS */
-	hva = (void __user *)gfn_to_hva(kvm, gfn);
-	r = copy_from_user(buf, hva, 1);
+	info.si_signo	= SIGBUS;
+	info.si_errno	= 0;
+	info.si_code	= BUS_MCEERR_AR;
+	info.si_addr	= (void __user *)address;
+	info.si_addr_lsb = PAGE_SHIFT;
+
+	send_sig_info(SIGBUS, &info, tsk);
 }
 
 static int kvm_handle_bad_page(struct kvm *kvm, gfn_t gfn, pfn_t pfn)
 {
 	kvm_release_pfn_clean(pfn);
 	if (is_hwpoison_pfn(pfn)) {
-		kvm_send_hwpoison_signal(kvm, gfn);
+		kvm_send_hwpoison_signal(gfn_to_hva(kvm, gfn), current);
 		return 0;
 	} else if (is_fault_pfn(pfn))
 		return -EFAULT;
@@ -2179,7 +2329,9 @@
 	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
 		return;
 	spin_lock(&vcpu->kvm->mmu_lock);
-	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL &&
+	    (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL ||
+	     vcpu->arch.mmu.direct_map)) {
 		hpa_t root = vcpu->arch.mmu.root_hpa;
 
 		sp = page_header(root);
@@ -2222,80 +2374,159 @@
 	return ret;
 }
 
-static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
+static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
 {
-	int i;
-	gfn_t root_gfn;
 	struct kvm_mmu_page *sp;
-	int direct = 0;
-	u64 pdptr;
-
-	root_gfn = vcpu->arch.cr3 >> PAGE_SHIFT;
+	unsigned i;
 
 	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+		spin_lock(&vcpu->kvm->mmu_lock);
+		kvm_mmu_free_some_pages(vcpu);
+		sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL,
+				      1, ACC_ALL, NULL);
+		++sp->root_count;
+		spin_unlock(&vcpu->kvm->mmu_lock);
+		vcpu->arch.mmu.root_hpa = __pa(sp->spt);
+	} else if (vcpu->arch.mmu.shadow_root_level == PT32E_ROOT_LEVEL) {
+		for (i = 0; i < 4; ++i) {
+			hpa_t root = vcpu->arch.mmu.pae_root[i];
+
+			ASSERT(!VALID_PAGE(root));
+			spin_lock(&vcpu->kvm->mmu_lock);
+			kvm_mmu_free_some_pages(vcpu);
+			sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
+					      i << 30,
+					      PT32_ROOT_LEVEL, 1, ACC_ALL,
+					      NULL);
+			root = __pa(sp->spt);
+			++sp->root_count;
+			spin_unlock(&vcpu->kvm->mmu_lock);
+			vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
+		}
+		vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
+	} else
+		BUG();
+
+	return 0;
+}
+
+static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
+{
+	struct kvm_mmu_page *sp;
+	u64 pdptr, pm_mask;
+	gfn_t root_gfn;
+	int i;
+
+	root_gfn = vcpu->arch.mmu.get_cr3(vcpu) >> PAGE_SHIFT;
+
+	if (mmu_check_root(vcpu, root_gfn))
+		return 1;
+
+	/*
+	 * Do we shadow a long mode page table? If so we need to
+	 * write-protect the guests page table root.
+	 */
+	if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
 		hpa_t root = vcpu->arch.mmu.root_hpa;
 
 		ASSERT(!VALID_PAGE(root));
-		if (mmu_check_root(vcpu, root_gfn))
-			return 1;
-		if (tdp_enabled) {
-			direct = 1;
-			root_gfn = 0;
-		}
+
 		spin_lock(&vcpu->kvm->mmu_lock);
 		kvm_mmu_free_some_pages(vcpu);
-		sp = kvm_mmu_get_page(vcpu, root_gfn, 0,
-				      PT64_ROOT_LEVEL, direct,
-				      ACC_ALL, NULL);
+		sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL,
+				      0, ACC_ALL, NULL);
 		root = __pa(sp->spt);
 		++sp->root_count;
 		spin_unlock(&vcpu->kvm->mmu_lock);
 		vcpu->arch.mmu.root_hpa = root;
 		return 0;
 	}
-	direct = !is_paging(vcpu);
+
+	/*
+	 * We shadow a 32 bit page table. This may be a legacy 2-level
+	 * or a PAE 3-level page table. In either case we need to be aware that
+	 * the shadow page table may be a PAE or a long mode page table.
+	 */
+	pm_mask = PT_PRESENT_MASK;
+	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL)
+		pm_mask |= PT_ACCESSED_MASK | PT_WRITABLE_MASK | PT_USER_MASK;
+
 	for (i = 0; i < 4; ++i) {
 		hpa_t root = vcpu->arch.mmu.pae_root[i];
 
 		ASSERT(!VALID_PAGE(root));
 		if (vcpu->arch.mmu.root_level == PT32E_ROOT_LEVEL) {
-			pdptr = kvm_pdptr_read(vcpu, i);
+			pdptr = kvm_pdptr_read_mmu(vcpu, &vcpu->arch.mmu, i);
 			if (!is_present_gpte(pdptr)) {
 				vcpu->arch.mmu.pae_root[i] = 0;
 				continue;
 			}
 			root_gfn = pdptr >> PAGE_SHIFT;
-		} else if (vcpu->arch.mmu.root_level == 0)
-			root_gfn = 0;
-		if (mmu_check_root(vcpu, root_gfn))
-			return 1;
-		if (tdp_enabled) {
-			direct = 1;
-			root_gfn = i << 30;
+			if (mmu_check_root(vcpu, root_gfn))
+				return 1;
 		}
 		spin_lock(&vcpu->kvm->mmu_lock);
 		kvm_mmu_free_some_pages(vcpu);
 		sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
-				      PT32_ROOT_LEVEL, direct,
+				      PT32_ROOT_LEVEL, 0,
 				      ACC_ALL, NULL);
 		root = __pa(sp->spt);
 		++sp->root_count;
 		spin_unlock(&vcpu->kvm->mmu_lock);
 
-		vcpu->arch.mmu.pae_root[i] = root | PT_PRESENT_MASK;
+		vcpu->arch.mmu.pae_root[i] = root | pm_mask;
 	}
 	vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.pae_root);
+
+	/*
+	 * If we shadow a 32 bit page table with a long mode page
+	 * table we enter this path.
+	 */
+	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+		if (vcpu->arch.mmu.lm_root == NULL) {
+			/*
+			 * The additional page necessary for this is only
+			 * allocated on demand.
+			 */
+
+			u64 *lm_root;
+
+			lm_root = (void*)get_zeroed_page(GFP_KERNEL);
+			if (lm_root == NULL)
+				return 1;
+
+			lm_root[0] = __pa(vcpu->arch.mmu.pae_root) | pm_mask;
+
+			vcpu->arch.mmu.lm_root = lm_root;
+		}
+
+		vcpu->arch.mmu.root_hpa = __pa(vcpu->arch.mmu.lm_root);
+	}
+
 	return 0;
 }
 
+static int mmu_alloc_roots(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.mmu.direct_map)
+		return mmu_alloc_direct_roots(vcpu);
+	else
+		return mmu_alloc_shadow_roots(vcpu);
+}
+
 static void mmu_sync_roots(struct kvm_vcpu *vcpu)
 {
 	int i;
 	struct kvm_mmu_page *sp;
 
+	if (vcpu->arch.mmu.direct_map)
+		return;
+
 	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
 		return;
-	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
+
+	trace_kvm_mmu_audit(vcpu, AUDIT_PRE_SYNC);
+	if (vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL) {
 		hpa_t root = vcpu->arch.mmu.root_hpa;
 		sp = page_header(root);
 		mmu_sync_children(vcpu, sp);
@@ -2310,6 +2541,7 @@
 			mmu_sync_children(vcpu, sp);
 		}
 	}
+	trace_kvm_mmu_audit(vcpu, AUDIT_POST_SYNC);
 }
 
 void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu)
@@ -2327,6 +2559,14 @@
 	return vaddr;
 }
 
+static gpa_t nonpaging_gva_to_gpa_nested(struct kvm_vcpu *vcpu, gva_t vaddr,
+					 u32 access, u32 *error)
+{
+	if (error)
+		*error = 0;
+	return vcpu->arch.nested_mmu.translate_gpa(vcpu, vaddr, access);
+}
+
 static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
 				u32 error_code)
 {
@@ -2393,10 +2633,9 @@
 	mmu_free_roots(vcpu);
 }
 
-static int nonpaging_init_context(struct kvm_vcpu *vcpu)
+static int nonpaging_init_context(struct kvm_vcpu *vcpu,
+				  struct kvm_mmu *context)
 {
-	struct kvm_mmu *context = &vcpu->arch.mmu;
-
 	context->new_cr3 = nonpaging_new_cr3;
 	context->page_fault = nonpaging_page_fault;
 	context->gva_to_gpa = nonpaging_gva_to_gpa;
@@ -2407,6 +2646,8 @@
 	context->root_level = 0;
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->root_hpa = INVALID_PAGE;
+	context->direct_map = true;
+	context->nx = false;
 	return 0;
 }
 
@@ -2422,11 +2663,14 @@
 	mmu_free_roots(vcpu);
 }
 
-static void inject_page_fault(struct kvm_vcpu *vcpu,
-			      u64 addr,
-			      u32 err_code)
+static unsigned long get_cr3(struct kvm_vcpu *vcpu)
 {
-	kvm_inject_page_fault(vcpu, addr, err_code);
+	return vcpu->arch.cr3;
+}
+
+static void inject_page_fault(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.mmu.inject_page_fault(vcpu);
 }
 
 static void paging_free(struct kvm_vcpu *vcpu)
@@ -2434,12 +2678,12 @@
 	nonpaging_free(vcpu);
 }
 
-static bool is_rsvd_bits_set(struct kvm_vcpu *vcpu, u64 gpte, int level)
+static bool is_rsvd_bits_set(struct kvm_mmu *mmu, u64 gpte, int level)
 {
 	int bit7;
 
 	bit7 = (gpte >> 7) & 1;
-	return (gpte & vcpu->arch.mmu.rsvd_bits_mask[bit7][level-1]) != 0;
+	return (gpte & mmu->rsvd_bits_mask[bit7][level-1]) != 0;
 }
 
 #define PTTYPE 64
@@ -2450,13 +2694,14 @@
 #include "paging_tmpl.h"
 #undef PTTYPE
 
-static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu, int level)
+static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
+				  struct kvm_mmu *context,
+				  int level)
 {
-	struct kvm_mmu *context = &vcpu->arch.mmu;
 	int maxphyaddr = cpuid_maxphyaddr(vcpu);
 	u64 exb_bit_rsvd = 0;
 
-	if (!is_nx(vcpu))
+	if (!context->nx)
 		exb_bit_rsvd = rsvd_bits(63, 63);
 	switch (level) {
 	case PT32_ROOT_LEVEL:
@@ -2511,9 +2756,13 @@
 	}
 }
 
-static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
+static int paging64_init_context_common(struct kvm_vcpu *vcpu,
+					struct kvm_mmu *context,
+					int level)
 {
-	struct kvm_mmu *context = &vcpu->arch.mmu;
+	context->nx = is_nx(vcpu);
+
+	reset_rsvds_bits_mask(vcpu, context, level);
 
 	ASSERT(is_pae(vcpu));
 	context->new_cr3 = paging_new_cr3;
@@ -2526,20 +2775,23 @@
 	context->root_level = level;
 	context->shadow_root_level = level;
 	context->root_hpa = INVALID_PAGE;
+	context->direct_map = false;
 	return 0;
 }
 
-static int paging64_init_context(struct kvm_vcpu *vcpu)
+static int paging64_init_context(struct kvm_vcpu *vcpu,
+				 struct kvm_mmu *context)
 {
-	reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
-	return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL);
+	return paging64_init_context_common(vcpu, context, PT64_ROOT_LEVEL);
 }
 
-static int paging32_init_context(struct kvm_vcpu *vcpu)
+static int paging32_init_context(struct kvm_vcpu *vcpu,
+				 struct kvm_mmu *context)
 {
-	struct kvm_mmu *context = &vcpu->arch.mmu;
+	context->nx = false;
+
+	reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
 
-	reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
 	context->new_cr3 = paging_new_cr3;
 	context->page_fault = paging32_page_fault;
 	context->gva_to_gpa = paging32_gva_to_gpa;
@@ -2550,18 +2802,19 @@
 	context->root_level = PT32_ROOT_LEVEL;
 	context->shadow_root_level = PT32E_ROOT_LEVEL;
 	context->root_hpa = INVALID_PAGE;
+	context->direct_map = false;
 	return 0;
 }
 
-static int paging32E_init_context(struct kvm_vcpu *vcpu)
+static int paging32E_init_context(struct kvm_vcpu *vcpu,
+				  struct kvm_mmu *context)
 {
-	reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
-	return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
+	return paging64_init_context_common(vcpu, context, PT32E_ROOT_LEVEL);
 }
 
 static int init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
 {
-	struct kvm_mmu *context = &vcpu->arch.mmu;
+	struct kvm_mmu *context = vcpu->arch.walk_mmu;
 
 	context->new_cr3 = nonpaging_new_cr3;
 	context->page_fault = tdp_page_fault;
@@ -2571,20 +2824,29 @@
 	context->invlpg = nonpaging_invlpg;
 	context->shadow_root_level = kvm_x86_ops->get_tdp_level();
 	context->root_hpa = INVALID_PAGE;
+	context->direct_map = true;
+	context->set_cr3 = kvm_x86_ops->set_tdp_cr3;
+	context->get_cr3 = get_cr3;
+	context->inject_page_fault = kvm_inject_page_fault;
+	context->nx = is_nx(vcpu);
 
 	if (!is_paging(vcpu)) {
+		context->nx = false;
 		context->gva_to_gpa = nonpaging_gva_to_gpa;
 		context->root_level = 0;
 	} else if (is_long_mode(vcpu)) {
-		reset_rsvds_bits_mask(vcpu, PT64_ROOT_LEVEL);
+		context->nx = is_nx(vcpu);
+		reset_rsvds_bits_mask(vcpu, context, PT64_ROOT_LEVEL);
 		context->gva_to_gpa = paging64_gva_to_gpa;
 		context->root_level = PT64_ROOT_LEVEL;
 	} else if (is_pae(vcpu)) {
-		reset_rsvds_bits_mask(vcpu, PT32E_ROOT_LEVEL);
+		context->nx = is_nx(vcpu);
+		reset_rsvds_bits_mask(vcpu, context, PT32E_ROOT_LEVEL);
 		context->gva_to_gpa = paging64_gva_to_gpa;
 		context->root_level = PT32E_ROOT_LEVEL;
 	} else {
-		reset_rsvds_bits_mask(vcpu, PT32_ROOT_LEVEL);
+		context->nx = false;
+		reset_rsvds_bits_mask(vcpu, context, PT32_ROOT_LEVEL);
 		context->gva_to_gpa = paging32_gva_to_gpa;
 		context->root_level = PT32_ROOT_LEVEL;
 	}
@@ -2592,33 +2854,83 @@
 	return 0;
 }
 
-static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
+int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
 {
 	int r;
-
 	ASSERT(vcpu);
 	ASSERT(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
 
 	if (!is_paging(vcpu))
-		r = nonpaging_init_context(vcpu);
+		r = nonpaging_init_context(vcpu, context);
 	else if (is_long_mode(vcpu))
-		r = paging64_init_context(vcpu);
+		r = paging64_init_context(vcpu, context);
 	else if (is_pae(vcpu))
-		r = paging32E_init_context(vcpu);
+		r = paging32E_init_context(vcpu, context);
 	else
-		r = paging32_init_context(vcpu);
+		r = paging32_init_context(vcpu, context);
 
 	vcpu->arch.mmu.base_role.cr4_pae = !!is_pae(vcpu);
-	vcpu->arch.mmu.base_role.cr0_wp = is_write_protection(vcpu);
+	vcpu->arch.mmu.base_role.cr0_wp  = is_write_protection(vcpu);
 
 	return r;
 }
+EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
+
+static int init_kvm_softmmu(struct kvm_vcpu *vcpu)
+{
+	int r = kvm_init_shadow_mmu(vcpu, vcpu->arch.walk_mmu);
+
+	vcpu->arch.walk_mmu->set_cr3           = kvm_x86_ops->set_cr3;
+	vcpu->arch.walk_mmu->get_cr3           = get_cr3;
+	vcpu->arch.walk_mmu->inject_page_fault = kvm_inject_page_fault;
+
+	return r;
+}
+
+static int init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
+{
+	struct kvm_mmu *g_context = &vcpu->arch.nested_mmu;
+
+	g_context->get_cr3           = get_cr3;
+	g_context->inject_page_fault = kvm_inject_page_fault;
+
+	/*
+	 * Note that arch.mmu.gva_to_gpa translates l2_gva to l1_gpa. The
+	 * translation of l2_gpa to l1_gpa addresses is done using the
+	 * arch.nested_mmu.gva_to_gpa function. Basically the gva_to_gpa
+	 * functions between mmu and nested_mmu are swapped.
+	 */
+	if (!is_paging(vcpu)) {
+		g_context->nx = false;
+		g_context->root_level = 0;
+		g_context->gva_to_gpa = nonpaging_gva_to_gpa_nested;
+	} else if (is_long_mode(vcpu)) {
+		g_context->nx = is_nx(vcpu);
+		reset_rsvds_bits_mask(vcpu, g_context, PT64_ROOT_LEVEL);
+		g_context->root_level = PT64_ROOT_LEVEL;
+		g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
+	} else if (is_pae(vcpu)) {
+		g_context->nx = is_nx(vcpu);
+		reset_rsvds_bits_mask(vcpu, g_context, PT32E_ROOT_LEVEL);
+		g_context->root_level = PT32E_ROOT_LEVEL;
+		g_context->gva_to_gpa = paging64_gva_to_gpa_nested;
+	} else {
+		g_context->nx = false;
+		reset_rsvds_bits_mask(vcpu, g_context, PT32_ROOT_LEVEL);
+		g_context->root_level = PT32_ROOT_LEVEL;
+		g_context->gva_to_gpa = paging32_gva_to_gpa_nested;
+	}
+
+	return 0;
+}
 
 static int init_kvm_mmu(struct kvm_vcpu *vcpu)
 {
 	vcpu->arch.update_pte.pfn = bad_pfn;
 
-	if (tdp_enabled)
+	if (mmu_is_nested(vcpu))
+		return init_kvm_nested_mmu(vcpu);
+	else if (tdp_enabled)
 		return init_kvm_tdp_mmu(vcpu);
 	else
 		return init_kvm_softmmu(vcpu);
@@ -2653,7 +2965,7 @@
 	if (r)
 		goto out;
 	/* set_cr3() should ensure TLB has been flushed */
-	kvm_x86_ops->set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
+	vcpu->arch.mmu.set_cr3(vcpu, vcpu->arch.mmu.root_hpa);
 out:
 	return r;
 }
@@ -2663,6 +2975,7 @@
 {
 	mmu_free_roots(vcpu);
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_unload);
 
 static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
 				  struct kvm_mmu_page *sp,
@@ -2695,7 +3008,7 @@
 		return;
         }
 
-	if (is_rsvd_bits_set(vcpu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
+	if (is_rsvd_bits_set(&vcpu->arch.mmu, *(u64 *)new, PT_PAGE_TABLE_LEVEL))
 		return;
 
 	++vcpu->kvm->stat.mmu_pte_updated;
@@ -2837,7 +3150,7 @@
 	kvm_mmu_access_page(vcpu, gfn);
 	kvm_mmu_free_some_pages(vcpu);
 	++vcpu->kvm->stat.mmu_pte_write;
-	kvm_mmu_audit(vcpu, "pre pte write");
+	trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
 	if (guest_initiated) {
 		if (gfn == vcpu->arch.last_pt_write_gfn
 		    && !last_updated_pte_accessed(vcpu)) {
@@ -2910,7 +3223,7 @@
 	}
 	mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
 	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
-	kvm_mmu_audit(vcpu, "post pte write");
+	trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE);
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
 		kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
@@ -2923,7 +3236,7 @@
 	gpa_t gpa;
 	int r;
 
-	if (tdp_enabled)
+	if (vcpu->arch.mmu.direct_map)
 		return 0;
 
 	gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, NULL);
@@ -2937,21 +3250,18 @@
 
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
-	int free_pages;
 	LIST_HEAD(invalid_list);
 
-	free_pages = vcpu->kvm->arch.n_free_mmu_pages;
-	while (free_pages < KVM_REFILL_PAGES &&
+	while (kvm_mmu_available_pages(vcpu->kvm) < KVM_REFILL_PAGES &&
 	       !list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
 		struct kvm_mmu_page *sp;
 
 		sp = container_of(vcpu->kvm->arch.active_mmu_pages.prev,
 				  struct kvm_mmu_page, link);
-		free_pages += kvm_mmu_prepare_zap_page(vcpu->kvm, sp,
-						       &invalid_list);
+		kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
+		kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 		++vcpu->kvm->stat.mmu_recycled;
 	}
-	kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
 }
 
 int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code)
@@ -3013,6 +3323,8 @@
 static void free_mmu_pages(struct kvm_vcpu *vcpu)
 {
 	free_page((unsigned long)vcpu->arch.mmu.pae_root);
+	if (vcpu->arch.mmu.lm_root != NULL)
+		free_page((unsigned long)vcpu->arch.mmu.lm_root);
 }
 
 static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
@@ -3054,15 +3366,6 @@
 	return init_kvm_mmu(vcpu);
 }
 
-void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-
-	destroy_kvm_mmu(vcpu);
-	free_mmu_pages(vcpu);
-	mmu_free_memory_caches(vcpu);
-}
-
 void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
 	struct kvm_mmu_page *sp;
@@ -3112,23 +3415,22 @@
 {
 	struct kvm *kvm;
 	struct kvm *kvm_freed = NULL;
-	int cache_count = 0;
+
+	if (nr_to_scan == 0)
+		goto out;
 
 	spin_lock(&kvm_lock);
 
 	list_for_each_entry(kvm, &vm_list, vm_list) {
-		int npages, idx, freed_pages;
+		int idx, freed_pages;
 		LIST_HEAD(invalid_list);
 
 		idx = srcu_read_lock(&kvm->srcu);
 		spin_lock(&kvm->mmu_lock);
-		npages = kvm->arch.n_alloc_mmu_pages -
-			 kvm->arch.n_free_mmu_pages;
-		cache_count += npages;
-		if (!kvm_freed && nr_to_scan > 0 && npages > 0) {
+		if (!kvm_freed && nr_to_scan > 0 &&
+		    kvm->arch.n_used_mmu_pages > 0) {
 			freed_pages = kvm_mmu_remove_some_alloc_mmu_pages(kvm,
 							  &invalid_list);
-			cache_count -= freed_pages;
 			kvm_freed = kvm;
 		}
 		nr_to_scan--;
@@ -3142,7 +3444,8 @@
 
 	spin_unlock(&kvm_lock);
 
-	return cache_count;
+out:
+	return percpu_counter_read_positive(&kvm_total_used_mmu_pages);
 }
 
 static struct shrinker mmu_shrinker = {
@@ -3163,6 +3466,7 @@
 void kvm_mmu_module_exit(void)
 {
 	mmu_destroy_caches();
+	percpu_counter_destroy(&kvm_total_used_mmu_pages);
 	unregister_shrinker(&mmu_shrinker);
 }
 
@@ -3185,6 +3489,9 @@
 	if (!mmu_page_header_cache)
 		goto nomem;
 
+	if (percpu_counter_init(&kvm_total_used_mmu_pages, 0))
+		goto nomem;
+
 	register_shrinker(&mmu_shrinker);
 
 	return 0;
@@ -3355,271 +3662,18 @@
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
 
-#ifdef AUDIT
-
-static const char *audit_msg;
-
-static gva_t canonicalize(gva_t gva)
-{
-#ifdef CONFIG_X86_64
-	gva = (long long)(gva << 16) >> 16;
+#ifdef CONFIG_KVM_MMU_AUDIT
+#include "mmu_audit.c"
+#else
+static void mmu_audit_disable(void) { }
 #endif
-	return gva;
-}
-
-
-typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
-
-static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
-			    inspect_spte_fn fn)
-{
-	int i;
-
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-		u64 ent = sp->spt[i];
-
-		if (is_shadow_present_pte(ent)) {
-			if (!is_last_spte(ent, sp->role.level)) {
-				struct kvm_mmu_page *child;
-				child = page_header(ent & PT64_BASE_ADDR_MASK);
-				__mmu_spte_walk(kvm, child, fn);
-			} else
-				fn(kvm, &sp->spt[i]);
-		}
-	}
-}
-
-static void mmu_spte_walk(struct kvm_vcpu *vcpu, inspect_spte_fn fn)
-{
-	int i;
-	struct kvm_mmu_page *sp;
 
-	if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
-		return;
-	if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
-		hpa_t root = vcpu->arch.mmu.root_hpa;
-		sp = page_header(root);
-		__mmu_spte_walk(vcpu->kvm, sp, fn);
-		return;
-	}
-	for (i = 0; i < 4; ++i) {
-		hpa_t root = vcpu->arch.mmu.pae_root[i];
-
-		if (root && VALID_PAGE(root)) {
-			root &= PT64_BASE_ADDR_MASK;
-			sp = page_header(root);
-			__mmu_spte_walk(vcpu->kvm, sp, fn);
-		}
-	}
-	return;
-}
-
-static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
-				gva_t va, int level)
-{
-	u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
-	int i;
-	gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
-
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
-		u64 ent = pt[i];
-
-		if (ent == shadow_trap_nonpresent_pte)
-			continue;
-
-		va = canonicalize(va);
-		if (is_shadow_present_pte(ent) && !is_last_spte(ent, level))
-			audit_mappings_page(vcpu, ent, va, level - 1);
-		else {
-			gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL);
-			gfn_t gfn = gpa >> PAGE_SHIFT;
-			pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
-			hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
-
-			if (is_error_pfn(pfn)) {
-				kvm_release_pfn_clean(pfn);
-				continue;
-			}
-
-			if (is_shadow_present_pte(ent)
-			    && (ent & PT64_BASE_ADDR_MASK) != hpa)
-				printk(KERN_ERR "xx audit error: (%s) levels %d"
-				       " gva %lx gpa %llx hpa %llx ent %llx %d\n",
-				       audit_msg, vcpu->arch.mmu.root_level,
-				       va, gpa, hpa, ent,
-				       is_shadow_present_pte(ent));
-			else if (ent == shadow_notrap_nonpresent_pte
-				 && !is_error_hpa(hpa))
-				printk(KERN_ERR "audit: (%s) notrap shadow,"
-				       " valid guest gva %lx\n", audit_msg, va);
-			kvm_release_pfn_clean(pfn);
-
-		}
-	}
-}
-
-static void audit_mappings(struct kvm_vcpu *vcpu)
-{
-	unsigned i;
-
-	if (vcpu->arch.mmu.root_level == 4)
-		audit_mappings_page(vcpu, vcpu->arch.mmu.root_hpa, 0, 4);
-	else
-		for (i = 0; i < 4; ++i)
-			if (vcpu->arch.mmu.pae_root[i] & PT_PRESENT_MASK)
-				audit_mappings_page(vcpu,
-						    vcpu->arch.mmu.pae_root[i],
-						    i << 30,
-						    2);
-}
-
-static int count_rmaps(struct kvm_vcpu *vcpu)
-{
-	struct kvm *kvm = vcpu->kvm;
-	struct kvm_memslots *slots;
-	int nmaps = 0;
-	int i, j, k, idx;
-
-	idx = srcu_read_lock(&kvm->srcu);
-	slots = kvm_memslots(kvm);
-	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
-		struct kvm_memory_slot *m = &slots->memslots[i];
-		struct kvm_rmap_desc *d;
-
-		for (j = 0; j < m->npages; ++j) {
-			unsigned long *rmapp = &m->rmap[j];
-
-			if (!*rmapp)
-				continue;
-			if (!(*rmapp & 1)) {
-				++nmaps;
-				continue;
-			}
-			d = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
-			while (d) {
-				for (k = 0; k < RMAP_EXT; ++k)
-					if (d->sptes[k])
-						++nmaps;
-					else
-						break;
-				d = d->more;
-			}
-		}
-	}
-	srcu_read_unlock(&kvm->srcu, idx);
-	return nmaps;
-}
-
-void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
-{
-	unsigned long *rmapp;
-	struct kvm_mmu_page *rev_sp;
-	gfn_t gfn;
-
-	if (is_writable_pte(*sptep)) {
-		rev_sp = page_header(__pa(sptep));
-		gfn = kvm_mmu_page_get_gfn(rev_sp, sptep - rev_sp->spt);
-
-		if (!gfn_to_memslot(kvm, gfn)) {
-			if (!printk_ratelimit())
-				return;
-			printk(KERN_ERR "%s: no memslot for gfn %ld\n",
-					 audit_msg, gfn);
-			printk(KERN_ERR "%s: index %ld of sp (gfn=%lx)\n",
-			       audit_msg, (long int)(sptep - rev_sp->spt),
-					rev_sp->gfn);
-			dump_stack();
-			return;
-		}
-
-		rmapp = gfn_to_rmap(kvm, gfn, rev_sp->role.level);
-		if (!*rmapp) {
-			if (!printk_ratelimit())
-				return;
-			printk(KERN_ERR "%s: no rmap for writable spte %llx\n",
-					 audit_msg, *sptep);
-			dump_stack();
-		}
-	}
-
-}
-
-void audit_writable_sptes_have_rmaps(struct kvm_vcpu *vcpu)
-{
-	mmu_spte_walk(vcpu, inspect_spte_has_rmap);
-}
-
-static void check_writable_mappings_rmap(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu_page *sp;
-	int i;
-
-	list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) {
-		u64 *pt = sp->spt;
-
-		if (sp->role.level != PT_PAGE_TABLE_LEVEL)
-			continue;
-
-		for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-			u64 ent = pt[i];
-
-			if (!(ent & PT_PRESENT_MASK))
-				continue;
-			if (!is_writable_pte(ent))
-				continue;
-			inspect_spte_has_rmap(vcpu->kvm, &pt[i]);
-		}
-	}
-	return;
-}
-
-static void audit_rmap(struct kvm_vcpu *vcpu)
-{
-	check_writable_mappings_rmap(vcpu);
-	count_rmaps(vcpu);
-}
-
-static void audit_write_protection(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu_page *sp;
-	struct kvm_memory_slot *slot;
-	unsigned long *rmapp;
-	u64 *spte;
-	gfn_t gfn;
-
-	list_for_each_entry(sp, &vcpu->kvm->arch.active_mmu_pages, link) {
-		if (sp->role.direct)
-			continue;
-		if (sp->unsync)
-			continue;
-
-		slot = gfn_to_memslot(vcpu->kvm, sp->gfn);
-		rmapp = &slot->rmap[gfn - slot->base_gfn];
-
-		spte = rmap_next(vcpu->kvm, rmapp, NULL);
-		while (spte) {
-			if (is_writable_pte(*spte))
-				printk(KERN_ERR "%s: (%s) shadow page has "
-				"writable mappings: gfn %lx role %x\n",
-			       __func__, audit_msg, sp->gfn,
-			       sp->role.word);
-			spte = rmap_next(vcpu->kvm, rmapp, spte);
-		}
-	}
-}
-
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
+void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
 {
-	int olddbg = dbg;
+	ASSERT(vcpu);
 
-	dbg = 0;
-	audit_msg = msg;
-	audit_rmap(vcpu);
-	audit_write_protection(vcpu);
-	if (strcmp("pre pte write", audit_msg) != 0)
-		audit_mappings(vcpu);
-	audit_writable_sptes_have_rmaps(vcpu);
-	dbg = olddbg;
+	destroy_kvm_mmu(vcpu);
+	free_mmu_pages(vcpu);
+	mmu_free_memory_caches(vcpu);
+	mmu_audit_disable();
 }
-
-#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/mmu.h linux-libre-2.6.37-gnu/arch/x86/kvm/mmu.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/mmu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/mmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -49,10 +49,17 @@
 #define PFERR_FETCH_MASK (1U << 4)
 
 int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
+int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
+
+static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
+{
+	return kvm->arch.n_max_mmu_pages -
+		kvm->arch.n_used_mmu_pages;
+}
 
 static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(vcpu->kvm->arch.n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+	if (unlikely(kvm_mmu_available_pages(vcpu->kvm)< KVM_MIN_FREE_MMU_PAGES))
 		__kvm_mmu_free_some_pages(vcpu);
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/mmutrace.h linux-libre-2.6.37-gnu/arch/x86/kvm/mmutrace.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/mmutrace.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/mmutrace.h	2011-01-04 19:50:19.000000000 -0500
@@ -195,6 +195,25 @@
 
 	TP_ARGS(sp)
 );
+
+TRACE_EVENT(
+	kvm_mmu_audit,
+	TP_PROTO(struct kvm_vcpu *vcpu, int audit_point),
+	TP_ARGS(vcpu, audit_point),
+
+	TP_STRUCT__entry(
+		__field(struct kvm_vcpu *, vcpu)
+		__field(int, audit_point)
+	),
+
+	TP_fast_assign(
+		__entry->vcpu = vcpu;
+		__entry->audit_point = audit_point;
+	),
+
+	TP_printk("vcpu:%d %s", __entry->vcpu->cpu,
+		  audit_point_name[__entry->audit_point])
+);
 #endif /* _TRACE_KVMMMU_H */
 
 #undef TRACE_INCLUDE_PATH
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/paging_tmpl.h linux-libre-2.6.37-gnu/arch/x86/kvm/paging_tmpl.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/paging_tmpl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/paging_tmpl.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
  * MMU support
  *
  * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -67,6 +67,7 @@
 	int level;
 	gfn_t table_gfn[PT_MAX_FULL_LEVELS];
 	pt_element_t ptes[PT_MAX_FULL_LEVELS];
+	pt_element_t prefetch_ptes[PTE_PREFETCH_NUM];
 	gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
 	unsigned pt_access;
 	unsigned pte_access;
@@ -104,7 +105,7 @@
 
 	access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
 #if PTTYPE == 64
-	if (is_nx(vcpu))
+	if (vcpu->arch.mmu.nx)
 		access &= ~(gpte >> PT64_NX_SHIFT);
 #endif
 	return access;
@@ -113,26 +114,32 @@
 /*
  * Fetch a guest pte for a guest virtual address
  */
-static int FNAME(walk_addr)(struct guest_walker *walker,
-			    struct kvm_vcpu *vcpu, gva_t addr,
-			    int write_fault, int user_fault, int fetch_fault)
+static int FNAME(walk_addr_generic)(struct guest_walker *walker,
+				    struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+				    gva_t addr, u32 access)
 {
 	pt_element_t pte;
 	gfn_t table_gfn;
 	unsigned index, pt_access, uninitialized_var(pte_access);
 	gpa_t pte_gpa;
 	bool eperm, present, rsvd_fault;
+	int offset, write_fault, user_fault, fetch_fault;
+
+	write_fault = access & PFERR_WRITE_MASK;
+	user_fault = access & PFERR_USER_MASK;
+	fetch_fault = access & PFERR_FETCH_MASK;
 
 	trace_kvm_mmu_pagetable_walk(addr, write_fault, user_fault,
 				     fetch_fault);
 walk:
 	present = true;
 	eperm = rsvd_fault = false;
-	walker->level = vcpu->arch.mmu.root_level;
-	pte = vcpu->arch.cr3;
+	walker->level = mmu->root_level;
+	pte           = mmu->get_cr3(vcpu);
+
 #if PTTYPE == 64
-	if (!is_long_mode(vcpu)) {
-		pte = kvm_pdptr_read(vcpu, (addr >> 30) & 3);
+	if (walker->level == PT32E_ROOT_LEVEL) {
+		pte = kvm_pdptr_read_mmu(vcpu, mmu, (addr >> 30) & 3);
 		trace_kvm_mmu_paging_element(pte, walker->level);
 		if (!is_present_gpte(pte)) {
 			present = false;
@@ -142,7 +149,7 @@
 	}
 #endif
 	ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
-	       (vcpu->arch.cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
+	       (mmu->get_cr3(vcpu) & CR3_NONPAE_RESERVED_BITS) == 0);
 
 	pt_access = ACC_ALL;
 
@@ -150,12 +157,14 @@
 		index = PT_INDEX(addr, walker->level);
 
 		table_gfn = gpte_to_gfn(pte);
-		pte_gpa = gfn_to_gpa(table_gfn);
-		pte_gpa += index * sizeof(pt_element_t);
+		offset    = index * sizeof(pt_element_t);
+		pte_gpa   = gfn_to_gpa(table_gfn) + offset;
 		walker->table_gfn[walker->level - 1] = table_gfn;
 		walker->pte_gpa[walker->level - 1] = pte_gpa;
 
-		if (kvm_read_guest(vcpu->kvm, pte_gpa, &pte, sizeof(pte))) {
+		if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte,
+					    offset, sizeof(pte),
+					    PFERR_USER_MASK|PFERR_WRITE_MASK)) {
 			present = false;
 			break;
 		}
@@ -167,7 +176,7 @@
 			break;
 		}
 
-		if (is_rsvd_bits_set(vcpu, pte, walker->level)) {
+		if (is_rsvd_bits_set(&vcpu->arch.mmu, pte, walker->level)) {
 			rsvd_fault = true;
 			break;
 		}
@@ -204,17 +213,28 @@
 				(PTTYPE == 64 || is_pse(vcpu))) ||
 		    ((walker->level == PT_PDPE_LEVEL) &&
 				is_large_pte(pte) &&
-				is_long_mode(vcpu))) {
+				mmu->root_level == PT64_ROOT_LEVEL)) {
 			int lvl = walker->level;
+			gpa_t real_gpa;
+			gfn_t gfn;
+			u32 ac;
 
-			walker->gfn = gpte_to_gfn_lvl(pte, lvl);
-			walker->gfn += (addr & PT_LVL_OFFSET_MASK(lvl))
-					>> PAGE_SHIFT;
+			gfn = gpte_to_gfn_lvl(pte, lvl);
+			gfn += (addr & PT_LVL_OFFSET_MASK(lvl)) >> PAGE_SHIFT;
 
 			if (PTTYPE == 32 &&
 			    walker->level == PT_DIRECTORY_LEVEL &&
 			    is_cpuid_PSE36())
-				walker->gfn += pse36_gfn_delta(pte);
+				gfn += pse36_gfn_delta(pte);
+
+			ac = write_fault | fetch_fault | user_fault;
+
+			real_gpa = mmu->translate_gpa(vcpu, gfn_to_gpa(gfn),
+						      ac);
+			if (real_gpa == UNMAPPED_GVA)
+				return 0;
+
+			walker->gfn = real_gpa >> PAGE_SHIFT;
 
 			break;
 		}
@@ -249,18 +269,36 @@
 	walker->error_code = 0;
 	if (present)
 		walker->error_code |= PFERR_PRESENT_MASK;
-	if (write_fault)
-		walker->error_code |= PFERR_WRITE_MASK;
-	if (user_fault)
-		walker->error_code |= PFERR_USER_MASK;
-	if (fetch_fault && is_nx(vcpu))
+
+	walker->error_code |= write_fault | user_fault;
+
+	if (fetch_fault && mmu->nx)
 		walker->error_code |= PFERR_FETCH_MASK;
 	if (rsvd_fault)
 		walker->error_code |= PFERR_RSVD_MASK;
+
+	vcpu->arch.fault.address    = addr;
+	vcpu->arch.fault.error_code = walker->error_code;
+
 	trace_kvm_mmu_walker_error(walker->error_code);
 	return 0;
 }
 
+static int FNAME(walk_addr)(struct guest_walker *walker,
+			    struct kvm_vcpu *vcpu, gva_t addr, u32 access)
+{
+	return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.mmu, addr,
+					access);
+}
+
+static int FNAME(walk_addr_nested)(struct guest_walker *walker,
+				   struct kvm_vcpu *vcpu, gva_t addr,
+				   u32 access)
+{
+	return FNAME(walk_addr_generic)(walker, vcpu, &vcpu->arch.nested_mmu,
+					addr, access);
+}
+
 static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
 			      u64 *spte, const void *pte)
 {
@@ -302,14 +340,87 @@
 static bool FNAME(gpte_changed)(struct kvm_vcpu *vcpu,
 				struct guest_walker *gw, int level)
 {
-	int r;
 	pt_element_t curr_pte;
+	gpa_t base_gpa, pte_gpa = gw->pte_gpa[level - 1];
+	u64 mask;
+	int r, index;
 
-	r = kvm_read_guest_atomic(vcpu->kvm, gw->pte_gpa[level - 1],
+	if (level == PT_PAGE_TABLE_LEVEL) {
+		mask = PTE_PREFETCH_NUM * sizeof(pt_element_t) - 1;
+		base_gpa = pte_gpa & ~mask;
+		index = (pte_gpa - base_gpa) / sizeof(pt_element_t);
+
+		r = kvm_read_guest_atomic(vcpu->kvm, base_gpa,
+				gw->prefetch_ptes, sizeof(gw->prefetch_ptes));
+		curr_pte = gw->prefetch_ptes[index];
+	} else
+		r = kvm_read_guest_atomic(vcpu->kvm, pte_gpa,
 				  &curr_pte, sizeof(curr_pte));
+
 	return r || curr_pte != gw->ptes[level - 1];
 }
 
+static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
+				u64 *sptep)
+{
+	struct kvm_mmu_page *sp;
+	struct kvm_mmu *mmu = &vcpu->arch.mmu;
+	pt_element_t *gptep = gw->prefetch_ptes;
+	u64 *spte;
+	int i;
+
+	sp = page_header(__pa(sptep));
+
+	if (sp->role.level > PT_PAGE_TABLE_LEVEL)
+		return;
+
+	if (sp->role.direct)
+		return __direct_pte_prefetch(vcpu, sp, sptep);
+
+	i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1);
+	spte = sp->spt + i;
+
+	for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) {
+		pt_element_t gpte;
+		unsigned pte_access;
+		gfn_t gfn;
+		pfn_t pfn;
+		bool dirty;
+
+		if (spte == sptep)
+			continue;
+
+		if (*spte != shadow_trap_nonpresent_pte)
+			continue;
+
+		gpte = gptep[i];
+
+		if (!is_present_gpte(gpte) ||
+		      is_rsvd_bits_set(mmu, gpte, PT_PAGE_TABLE_LEVEL)) {
+			if (!sp->unsync)
+				__set_spte(spte, shadow_notrap_nonpresent_pte);
+			continue;
+		}
+
+		if (!(gpte & PT_ACCESSED_MASK))
+			continue;
+
+		pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+		gfn = gpte_to_gfn(gpte);
+		dirty = is_dirty_gpte(gpte);
+		pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
+				      (pte_access & ACC_WRITE_MASK) && dirty);
+		if (is_error_pfn(pfn)) {
+			kvm_release_pfn_clean(pfn);
+			break;
+		}
+
+		mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
+			     dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn,
+			     pfn, true, true);
+	}
+}
+
 /*
  * Fetch a shadow pte for a specific level in the paging hierarchy.
  */
@@ -391,6 +502,7 @@
 	mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
 		     user_fault, write_fault, dirty, ptwrite, it.level,
 		     gw->gfn, pfn, false, true);
+	FNAME(pte_prefetch)(vcpu, gw, it.sptep);
 
 	return it.sptep;
 
@@ -420,7 +532,6 @@
 {
 	int write_fault = error_code & PFERR_WRITE_MASK;
 	int user_fault = error_code & PFERR_USER_MASK;
-	int fetch_fault = error_code & PFERR_FETCH_MASK;
 	struct guest_walker walker;
 	u64 *sptep;
 	int write_pt = 0;
@@ -430,7 +541,6 @@
 	unsigned long mmu_seq;
 
 	pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
-	kvm_mmu_audit(vcpu, "pre page fault");
 
 	r = mmu_topup_memory_caches(vcpu);
 	if (r)
@@ -439,15 +549,14 @@
 	/*
 	 * Look up the guest pte for the faulting address.
 	 */
-	r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault,
-			     fetch_fault);
+	r = FNAME(walk_addr)(&walker, vcpu, addr, error_code);
 
 	/*
 	 * The page is not mapped by the guest.  Let the guest handle it.
 	 */
 	if (!r) {
 		pgprintk("%s: guest page fault\n", __func__);
-		inject_page_fault(vcpu, addr, walker.error_code);
+		inject_page_fault(vcpu);
 		vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
 		return 0;
 	}
@@ -468,6 +577,8 @@
 	spin_lock(&vcpu->kvm->mmu_lock);
 	if (mmu_notifier_retry(vcpu, mmu_seq))
 		goto out_unlock;
+
+	trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT);
 	kvm_mmu_free_some_pages(vcpu);
 	sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
 			     level, &write_pt, pfn);
@@ -479,7 +590,7 @@
 		vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
 
 	++vcpu->stat.pf_fixed;
-	kvm_mmu_audit(vcpu, "post page fault (fixed)");
+	trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
 	spin_unlock(&vcpu->kvm->mmu_lock);
 
 	return write_pt;
@@ -556,10 +667,25 @@
 	gpa_t gpa = UNMAPPED_GVA;
 	int r;
 
-	r = FNAME(walk_addr)(&walker, vcpu, vaddr,
-			     !!(access & PFERR_WRITE_MASK),
-			     !!(access & PFERR_USER_MASK),
-			     !!(access & PFERR_FETCH_MASK));
+	r = FNAME(walk_addr)(&walker, vcpu, vaddr, access);
+
+	if (r) {
+		gpa = gfn_to_gpa(walker.gfn);
+		gpa |= vaddr & ~PAGE_MASK;
+	} else if (error)
+		*error = walker.error_code;
+
+	return gpa;
+}
+
+static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr,
+				      u32 access, u32 *error)
+{
+	struct guest_walker walker;
+	gpa_t gpa = UNMAPPED_GVA;
+	int r;
+
+	r = FNAME(walk_addr_nested)(&walker, vcpu, vaddr, access);
 
 	if (r) {
 		gpa = gfn_to_gpa(walker.gfn);
@@ -638,7 +764,7 @@
 			return -EINVAL;
 
 		gfn = gpte_to_gfn(gpte);
-		if (is_rsvd_bits_set(vcpu, gpte, PT_PAGE_TABLE_LEVEL)
+		if (is_rsvd_bits_set(&vcpu->arch.mmu, gpte, PT_PAGE_TABLE_LEVEL)
 		      || gfn != sp->gfns[i] || !is_present_gpte(gpte)
 		      || !(gpte & PT_ACCESSED_MASK)) {
 			u64 nonpresent;
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/svm.c linux-libre-2.6.37-gnu/arch/x86/kvm/svm.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/svm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/svm.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * AMD SVM support
  *
  * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Yaniv Kamay  <yaniv@qumranet.com>
@@ -88,6 +88,14 @@
 	/* A VMEXIT is required but not yet emulated */
 	bool exit_required;
 
+	/*
+	 * If we vmexit during an instruction emulation we need this to restore
+	 * the l1 guest rip after the emulation
+	 */
+	unsigned long vmexit_rip;
+	unsigned long vmexit_rsp;
+	unsigned long vmexit_rax;
+
 	/* cache for intercepts of the guest */
 	u16 intercept_cr_read;
 	u16 intercept_cr_write;
@@ -96,6 +104,8 @@
 	u32 intercept_exceptions;
 	u64 intercept;
 
+	/* Nested Paging related state */
+	u64 nested_cr3;
 };
 
 #define MSRPM_OFFSETS	16
@@ -284,6 +294,15 @@
 	force_new_asid(vcpu);
 }
 
+static int get_npt_level(void)
+{
+#ifdef CONFIG_X86_64
+	return PT64_ROOT_LEVEL;
+#else
+	return PT32E_ROOT_LEVEL;
+#endif
+}
+
 static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
 	vcpu->arch.efer = efer;
@@ -701,6 +720,29 @@
 	seg->base = 0;
 }
 
+static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	u64 g_tsc_offset = 0;
+
+	if (is_nested(svm)) {
+		g_tsc_offset = svm->vmcb->control.tsc_offset -
+			       svm->nested.hsave->control.tsc_offset;
+		svm->nested.hsave->control.tsc_offset = offset;
+	}
+
+	svm->vmcb->control.tsc_offset = offset + g_tsc_offset;
+}
+
+static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	svm->vmcb->control.tsc_offset += adjustment;
+	if (is_nested(svm))
+		svm->nested.hsave->control.tsc_offset += adjustment;
+}
+
 static void init_vmcb(struct vcpu_svm *svm)
 {
 	struct vmcb_control_area *control = &svm->vmcb->control;
@@ -793,7 +835,7 @@
 	init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
 	init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
 
-	save->efer = EFER_SVME;
+	svm_set_efer(&svm->vcpu, 0);
 	save->dr6 = 0xffff0ff0;
 	save->dr7 = 0x400;
 	save->rflags = 2;
@@ -804,8 +846,8 @@
 	 * This is the guest-visible cr0 value.
 	 * svm_set_cr0() sets PG and WP and clears NW and CD on save->cr0.
 	 */
-	svm->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET;
-	(void)kvm_set_cr0(&svm->vcpu, svm->vcpu.arch.cr0);
+	svm->vcpu.arch.cr0 = 0;
+	(void)kvm_set_cr0(&svm->vcpu, X86_CR0_NW | X86_CR0_CD | X86_CR0_ET);
 
 	save->cr4 = X86_CR4_PAE;
 	/* rdx = ?? */
@@ -901,7 +943,7 @@
 	svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
 	svm->asid_generation = 0;
 	init_vmcb(svm);
-	svm->vmcb->control.tsc_offset = 0-native_read_tsc();
+	kvm_write_tsc(&svm->vcpu, 0);
 
 	err = fx_init(&svm->vcpu);
 	if (err)
@@ -947,20 +989,6 @@
 	int i;
 
 	if (unlikely(cpu != vcpu->cpu)) {
-		u64 delta;
-
-		if (check_tsc_unstable()) {
-			/*
-			 * Make sure that the guest sees a monotonically
-			 * increasing TSC.
-			 */
-			delta = vcpu->arch.host_tsc - native_read_tsc();
-			svm->vmcb->control.tsc_offset += delta;
-			if (is_nested(svm))
-				svm->nested.hsave->control.tsc_offset += delta;
-		}
-		vcpu->cpu = cpu;
-		kvm_migrate_timers(vcpu);
 		svm->asid_generation = 0;
 	}
 
@@ -976,8 +1004,6 @@
 	++vcpu->stat.host_state_reload;
 	for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
 		wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
-
-	vcpu->arch.host_tsc = native_read_tsc();
 }
 
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
@@ -995,7 +1021,7 @@
 	switch (reg) {
 	case VCPU_EXREG_PDPTR:
 		BUG_ON(!npt_enabled);
-		load_pdptrs(vcpu, vcpu->arch.cr3);
+		load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3);
 		break;
 	default:
 		BUG();
@@ -1206,8 +1232,12 @@
 		if (old == new) {
 			/* cr0 write with ts and mp unchanged */
 			svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
-			if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE)
+			if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) {
+				svm->nested.vmexit_rip = kvm_rip_read(vcpu);
+				svm->nested.vmexit_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
+				svm->nested.vmexit_rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
 				return;
+			}
 		}
 	}
 
@@ -1581,6 +1611,54 @@
 	return 1;
 }
 
+static unsigned long nested_svm_get_tdp_cr3(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	return svm->nested.nested_cr3;
+}
+
+static void nested_svm_set_tdp_cr3(struct kvm_vcpu *vcpu,
+				   unsigned long root)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	svm->vmcb->control.nested_cr3 = root;
+	force_new_asid(vcpu);
+}
+
+static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	svm->vmcb->control.exit_code = SVM_EXIT_NPF;
+	svm->vmcb->control.exit_code_hi = 0;
+	svm->vmcb->control.exit_info_1 = vcpu->arch.fault.error_code;
+	svm->vmcb->control.exit_info_2 = vcpu->arch.fault.address;
+
+	nested_svm_vmexit(svm);
+}
+
+static int nested_svm_init_mmu_context(struct kvm_vcpu *vcpu)
+{
+	int r;
+
+	r = kvm_init_shadow_mmu(vcpu, &vcpu->arch.mmu);
+
+	vcpu->arch.mmu.set_cr3           = nested_svm_set_tdp_cr3;
+	vcpu->arch.mmu.get_cr3           = nested_svm_get_tdp_cr3;
+	vcpu->arch.mmu.inject_page_fault = nested_svm_inject_npf_exit;
+	vcpu->arch.mmu.shadow_root_level = get_npt_level();
+	vcpu->arch.walk_mmu              = &vcpu->arch.nested_mmu;
+
+	return r;
+}
+
+static void nested_svm_uninit_mmu_context(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.walk_mmu = &vcpu->arch.mmu;
+}
+
 static int nested_svm_check_permissions(struct vcpu_svm *svm)
 {
 	if (!(svm->vcpu.arch.efer & EFER_SVME)
@@ -1629,6 +1707,14 @@
 	if (!(svm->vcpu.arch.hflags & HF_HIF_MASK))
 		return false;
 
+	/*
+	 * if vmexit was already requested (by intercepted exception
+	 * for instance) do not overwrite it with "external interrupt"
+	 * vmexit.
+	 */
+	if (svm->nested.exit_required)
+		return false;
+
 	svm->vmcb->control.exit_code   = SVM_EXIT_INTR;
 	svm->vmcb->control.exit_info_1 = 0;
 	svm->vmcb->control.exit_info_2 = 0;
@@ -1896,6 +1982,7 @@
 	nested_vmcb->save.ds     = vmcb->save.ds;
 	nested_vmcb->save.gdtr   = vmcb->save.gdtr;
 	nested_vmcb->save.idtr   = vmcb->save.idtr;
+	nested_vmcb->save.efer   = svm->vcpu.arch.efer;
 	nested_vmcb->save.cr0    = kvm_read_cr0(&svm->vcpu);
 	nested_vmcb->save.cr3    = svm->vcpu.arch.cr3;
 	nested_vmcb->save.cr2    = vmcb->save.cr2;
@@ -1917,6 +2004,7 @@
 	nested_vmcb->control.exit_info_2       = vmcb->control.exit_info_2;
 	nested_vmcb->control.exit_int_info     = vmcb->control.exit_int_info;
 	nested_vmcb->control.exit_int_info_err = vmcb->control.exit_int_info_err;
+	nested_vmcb->control.next_rip          = vmcb->control.next_rip;
 
 	/*
 	 * If we emulate a VMRUN/#VMEXIT in the same host #vmexit cycle we have
@@ -1947,6 +2035,8 @@
 	kvm_clear_exception_queue(&svm->vcpu);
 	kvm_clear_interrupt_queue(&svm->vcpu);
 
+	svm->nested.nested_cr3 = 0;
+
 	/* Restore selected save entries */
 	svm->vmcb->save.es = hsave->save.es;
 	svm->vmcb->save.cs = hsave->save.cs;
@@ -1973,6 +2063,7 @@
 
 	nested_svm_unmap(page);
 
+	nested_svm_uninit_mmu_context(&svm->vcpu);
 	kvm_mmu_reset_context(&svm->vcpu);
 	kvm_mmu_load(&svm->vcpu);
 
@@ -2012,6 +2103,20 @@
 	return true;
 }
 
+static bool nested_vmcb_checks(struct vmcb *vmcb)
+{
+	if ((vmcb->control.intercept & (1ULL << INTERCEPT_VMRUN)) == 0)
+		return false;
+
+	if (vmcb->control.asid == 0)
+		return false;
+
+	if (vmcb->control.nested_ctl && !npt_enabled)
+		return false;
+
+	return true;
+}
+
 static bool nested_svm_vmrun(struct vcpu_svm *svm)
 {
 	struct vmcb *nested_vmcb;
@@ -2026,7 +2131,18 @@
 	if (!nested_vmcb)
 		return false;
 
-	trace_kvm_nested_vmrun(svm->vmcb->save.rip - 3, vmcb_gpa,
+	if (!nested_vmcb_checks(nested_vmcb)) {
+		nested_vmcb->control.exit_code    = SVM_EXIT_ERR;
+		nested_vmcb->control.exit_code_hi = 0;
+		nested_vmcb->control.exit_info_1  = 0;
+		nested_vmcb->control.exit_info_2  = 0;
+
+		nested_svm_unmap(page);
+
+		return false;
+	}
+
+	trace_kvm_nested_vmrun(svm->vmcb->save.rip, vmcb_gpa,
 			       nested_vmcb->save.rip,
 			       nested_vmcb->control.int_ctl,
 			       nested_vmcb->control.event_inj,
@@ -2055,7 +2171,7 @@
 	hsave->save.cr0    = kvm_read_cr0(&svm->vcpu);
 	hsave->save.cr4    = svm->vcpu.arch.cr4;
 	hsave->save.rflags = vmcb->save.rflags;
-	hsave->save.rip    = svm->next_rip;
+	hsave->save.rip    = kvm_rip_read(&svm->vcpu);
 	hsave->save.rsp    = vmcb->save.rsp;
 	hsave->save.rax    = vmcb->save.rax;
 	if (npt_enabled)
@@ -2070,6 +2186,12 @@
 	else
 		svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
 
+	if (nested_vmcb->control.nested_ctl) {
+		kvm_mmu_unload(&svm->vcpu);
+		svm->nested.nested_cr3 = nested_vmcb->control.nested_cr3;
+		nested_svm_init_mmu_context(&svm->vcpu);
+	}
+
 	/* Load the nested guest state */
 	svm->vmcb->save.es = nested_vmcb->save.es;
 	svm->vmcb->save.cs = nested_vmcb->save.cs;
@@ -2227,8 +2349,8 @@
 	if (nested_svm_check_permissions(svm))
 		return 1;
 
-	svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
-	skip_emulated_instruction(&svm->vcpu);
+	/* Save rip after vmrun instruction */
+	kvm_rip_write(&svm->vcpu, kvm_rip_read(&svm->vcpu) + 3);
 
 	if (!nested_svm_vmrun(svm))
 		return 1;
@@ -2257,6 +2379,7 @@
 
 	svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
 	skip_emulated_instruction(&svm->vcpu);
+	kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 
 	enable_gif(svm);
 
@@ -2399,6 +2522,23 @@
 	return emulate_instruction(&svm->vcpu, 0, 0, 0) == EMULATE_DONE;
 }
 
+static int cr0_write_interception(struct vcpu_svm *svm)
+{
+	struct kvm_vcpu *vcpu = &svm->vcpu;
+	int r;
+
+	r = emulate_instruction(&svm->vcpu, 0, 0, 0);
+
+	if (svm->nested.vmexit_rip) {
+		kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip);
+		kvm_register_write(vcpu, VCPU_REGS_RSP, svm->nested.vmexit_rsp);
+		kvm_register_write(vcpu, VCPU_REGS_RAX, svm->nested.vmexit_rax);
+		svm->nested.vmexit_rip = 0;
+	}
+
+	return r == EMULATE_DONE;
+}
+
 static int cr8_write_interception(struct vcpu_svm *svm)
 {
 	struct kvm_run *kvm_run = svm->vcpu.run;
@@ -2542,20 +2682,9 @@
 	struct vcpu_svm *svm = to_svm(vcpu);
 
 	switch (ecx) {
-	case MSR_IA32_TSC: {
-		u64 tsc_offset = data - native_read_tsc();
-		u64 g_tsc_offset = 0;
-
-		if (is_nested(svm)) {
-			g_tsc_offset = svm->vmcb->control.tsc_offset -
-				       svm->nested.hsave->control.tsc_offset;
-			svm->nested.hsave->control.tsc_offset = tsc_offset;
-		}
-
-		svm->vmcb->control.tsc_offset = tsc_offset + g_tsc_offset;
-
+	case MSR_IA32_TSC:
+		kvm_write_tsc(vcpu, data);
 		break;
-	}
 	case MSR_STAR:
 		svm->vmcb->save.star = data;
 		break;
@@ -2643,6 +2772,7 @@
 {
 	struct kvm_run *kvm_run = svm->vcpu.run;
 
+	kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
 	svm_clear_vintr(svm);
 	svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
 	/*
@@ -2672,7 +2802,7 @@
 	[SVM_EXIT_READ_CR4]			= emulate_on_interception,
 	[SVM_EXIT_READ_CR8]			= emulate_on_interception,
 	[SVM_EXIT_CR0_SEL_WRITE]		= emulate_on_interception,
-	[SVM_EXIT_WRITE_CR0]			= emulate_on_interception,
+	[SVM_EXIT_WRITE_CR0]			= cr0_write_interception,
 	[SVM_EXIT_WRITE_CR3]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_CR4]			= emulate_on_interception,
 	[SVM_EXIT_WRITE_CR8]			= cr8_write_interception,
@@ -2871,7 +3001,8 @@
 
 	if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
 	    exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
-	    exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH)
+	    exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
+	    exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
 		printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
 		       "exit_code 0x%x\n",
 		       __func__, svm->vmcb->control.exit_int_info,
@@ -3088,8 +3219,10 @@
 
 	svm->int3_injected = 0;
 
-	if (svm->vcpu.arch.hflags & HF_IRET_MASK)
+	if (svm->vcpu.arch.hflags & HF_IRET_MASK) {
 		svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
+		kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+	}
 
 	svm->vcpu.arch.nmi_injected = false;
 	kvm_clear_exception_queue(&svm->vcpu);
@@ -3098,6 +3231,8 @@
 	if (!(exitintinfo & SVM_EXITINTINFO_VALID))
 		return;
 
+	kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
+
 	vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK;
 	type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK;
 
@@ -3134,6 +3269,17 @@
 	}
 }
 
+static void svm_cancel_injection(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	struct vmcb_control_area *control = &svm->vmcb->control;
+
+	control->exit_int_info = control->event_inj;
+	control->exit_int_info_err = control->event_inj_err;
+	control->event_inj = 0;
+	svm_complete_interrupts(svm);
+}
+
 #ifdef CONFIG_X86_64
 #define R "r"
 #else
@@ -3167,9 +3313,6 @@
 	savesegment(gs, gs_selector);
 	ldt_selector = kvm_read_ldt();
 	svm->vmcb->save.cr2 = vcpu->arch.cr2;
-	/* required for live migration with NPT */
-	if (npt_enabled)
-		svm->vmcb->save.cr3 = vcpu->arch.cr3;
 
 	clgi();
 
@@ -3252,6 +3395,7 @@
 	vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
 	load_host_msrs(vcpu);
+	kvm_load_ldt(ldt_selector);
 	loadsegment(fs, fs_selector);
 #ifdef CONFIG_X86_64
 	load_gs_index(gs_selector);
@@ -3259,7 +3403,6 @@
 #else
 	loadsegment(gs, gs_selector);
 #endif
-	kvm_load_ldt(ldt_selector);
 
 	reload_tss(vcpu);
 
@@ -3291,16 +3434,22 @@
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
-	if (npt_enabled) {
-		svm->vmcb->control.nested_cr3 = root;
-		force_new_asid(vcpu);
-		return;
-	}
-
 	svm->vmcb->save.cr3 = root;
 	force_new_asid(vcpu);
 }
 
+static void set_tdp_cr3(struct kvm_vcpu *vcpu, unsigned long root)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	svm->vmcb->control.nested_cr3 = root;
+
+	/* Also sync guest cr3 here in case we live migrate */
+	svm->vmcb->save.cr3 = vcpu->arch.cr3;
+
+	force_new_asid(vcpu);
+}
+
 static int is_disabled(void)
 {
 	u64 vm_cr;
@@ -3333,15 +3482,6 @@
 	return false;
 }
 
-static int get_npt_level(void)
-{
-#ifdef CONFIG_X86_64
-	return PT64_ROOT_LEVEL;
-#else
-	return PT32E_ROOT_LEVEL;
-#endif
-}
-
 static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 {
 	return 0;
@@ -3354,12 +3494,29 @@
 static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
 {
 	switch (func) {
+	case 0x00000001:
+		/* Mask out xsave bit as long as it is not supported by SVM */
+		entry->ecx &= ~(bit(X86_FEATURE_XSAVE));
+		break;
+	case 0x80000001:
+		if (nested)
+			entry->ecx |= (1 << 2); /* Set SVM bit */
+		break;
 	case 0x8000000A:
 		entry->eax = 1; /* SVM revision 1 */
 		entry->ebx = 8; /* Lets support 8 ASIDs in case we add proper
 				   ASID emulation to nested SVM */
 		entry->ecx = 0; /* Reserved */
-		entry->edx = 0; /* Do not support any additional features */
+		entry->edx = 0; /* Per default do not support any
+				   additional features */
+
+		/* Support next_rip if host supports it */
+		if (svm_has(SVM_FEATURE_NRIP))
+			entry->edx |= SVM_FEATURE_NRIP;
+
+		/* Support NPT for the guest if enabled */
+		if (npt_enabled)
+			entry->edx |= SVM_FEATURE_NPT;
 
 		break;
 	}
@@ -3497,6 +3654,7 @@
 	.set_irq = svm_set_irq,
 	.set_nmi = svm_inject_nmi,
 	.queue_exception = svm_queue_exception,
+	.cancel_injection = svm_cancel_injection,
 	.interrupt_allowed = svm_interrupt_allowed,
 	.nmi_allowed = svm_nmi_allowed,
 	.get_nmi_mask = svm_get_nmi_mask,
@@ -3519,6 +3677,11 @@
 	.set_supported_cpuid = svm_set_supported_cpuid,
 
 	.has_wbinvd_exit = svm_has_wbinvd_exit,
+
+	.write_tsc_offset = svm_write_tsc_offset,
+	.adjust_tsc_offset = svm_adjust_tsc_offset,
+
+	.set_tdp_cr3 = set_tdp_cr3,
 };
 
 static int __init svm_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/timer.c linux-libre-2.6.37-gnu/arch/x86/kvm/timer.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/timer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/timer.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,7 @@
  *
  * timer support
  *
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * This work is licensed under the terms of the GNU GPL, version 2.  See
  * the COPYING file in the top-level directory.
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/vmx.c linux-libre-2.6.37-gnu/arch/x86/kvm/vmx.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/vmx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/vmx.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
  * machines without emulation or binary translation.
  *
  * Copyright (C) 2006 Qumranet, Inc.
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -125,6 +125,7 @@
 	unsigned long         host_rsp;
 	int                   launched;
 	u8                    fail;
+	u32                   exit_intr_info;
 	u32                   idt_vectoring_info;
 	struct shared_msr_entry *guest_msrs;
 	int                   nmsrs;
@@ -154,11 +155,6 @@
 			u32 limit;
 			u32 ar;
 		} tr, es, ds, fs, gs;
-		struct {
-			bool pending;
-			u8 vector;
-			unsigned rip;
-		} irq;
 	} rmode;
 	int vpid;
 	bool emulation_required;
@@ -505,7 +501,6 @@
 		vmcs_clear(vmx->vmcs);
 	if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
 		per_cpu(current_vmcs, cpu) = NULL;
-	rdtscll(vmx->vcpu.arch.host_tsc);
 	list_del(&vmx->local_vcpus_link);
 	vmx->vcpu.cpu = -1;
 	vmx->launched = 0;
@@ -706,11 +701,10 @@
 	/*
 	 * VT restores TR but not its size.  Useless.
 	 */
-	struct desc_ptr gdt;
+	struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
 	struct desc_struct *descs;
 
-	native_store_gdt(&gdt);
-	descs = (void *)gdt.address;
+	descs = (void *)gdt->address;
 	descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
 	load_TR_desc();
 }
@@ -753,7 +747,7 @@
 
 static unsigned long segment_base(u16 selector)
 {
-	struct desc_ptr gdt;
+	struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
 	struct desc_struct *d;
 	unsigned long table_base;
 	unsigned long v;
@@ -761,8 +755,7 @@
 	if (!(selector & ~3))
 		return 0;
 
-	native_store_gdt(&gdt);
-	table_base = gdt.address;
+	table_base = gdt->address;
 
 	if (selector & 4) {           /* from ldt */
 		u16 ldt_selector = kvm_read_ldt();
@@ -828,10 +821,9 @@
 #endif
 
 #ifdef CONFIG_X86_64
-	if (is_long_mode(&vmx->vcpu)) {
-		rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+	rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
+	if (is_long_mode(&vmx->vcpu))
 		wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
-	}
 #endif
 	for (i = 0; i < vmx->save_nmsrs; ++i)
 		kvm_set_shared_msr(vmx->guest_msrs[i].index,
@@ -846,23 +838,23 @@
 
 	++vmx->vcpu.stat.host_state_reload;
 	vmx->host_state.loaded = 0;
-	if (vmx->host_state.fs_reload_needed)
-		loadsegment(fs, vmx->host_state.fs_sel);
+#ifdef CONFIG_X86_64
+	if (is_long_mode(&vmx->vcpu))
+		rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
+#endif
 	if (vmx->host_state.gs_ldt_reload_needed) {
 		kvm_load_ldt(vmx->host_state.ldt_sel);
 #ifdef CONFIG_X86_64
 		load_gs_index(vmx->host_state.gs_sel);
-		wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
 #else
 		loadsegment(gs, vmx->host_state.gs_sel);
 #endif
 	}
+	if (vmx->host_state.fs_reload_needed)
+		loadsegment(fs, vmx->host_state.fs_sel);
 	reload_tss();
 #ifdef CONFIG_X86_64
-	if (is_long_mode(&vmx->vcpu)) {
-		rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
-		wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
-	}
+	wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
 #endif
 	if (current_thread_info()->status & TS_USEDFPU)
 		clts();
@@ -883,7 +875,6 @@
 static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u64 tsc_this, delta, new_offset;
 	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
 
 	if (!vmm_exclusive)
@@ -897,37 +888,24 @@
 	}
 
 	if (vcpu->cpu != cpu) {
-		struct desc_ptr dt;
+		struct desc_ptr *gdt = &__get_cpu_var(host_gdt);
 		unsigned long sysenter_esp;
 
-		kvm_migrate_timers(vcpu);
 		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
 		local_irq_disable();
 		list_add(&vmx->local_vcpus_link,
 			 &per_cpu(vcpus_on_cpu, cpu));
 		local_irq_enable();
 
-		vcpu->cpu = cpu;
 		/*
 		 * Linux uses per-cpu TSS and GDT, so set these when switching
 		 * processors.
 		 */
 		vmcs_writel(HOST_TR_BASE, kvm_read_tr_base()); /* 22.2.4 */
-		native_store_gdt(&dt);
-		vmcs_writel(HOST_GDTR_BASE, dt.address);   /* 22.2.4 */
+		vmcs_writel(HOST_GDTR_BASE, gdt->address);   /* 22.2.4 */
 
 		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
 		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
-
-		/*
-		 * Make sure the time stamp counter is monotonous.
-		 */
-		rdtscll(tsc_this);
-		if (tsc_this < vcpu->arch.host_tsc) {
-			delta = vcpu->arch.host_tsc - tsc_this;
-			new_offset = vmcs_read64(TSC_OFFSET) + delta;
-			vmcs_write64(TSC_OFFSET, new_offset);
-		}
 	}
 }
 
@@ -1044,16 +1022,8 @@
 	}
 
 	if (vmx->rmode.vm86_active) {
-		vmx->rmode.irq.pending = true;
-		vmx->rmode.irq.vector = nr;
-		vmx->rmode.irq.rip = kvm_rip_read(vcpu);
-		if (kvm_exception_is_soft(nr))
-			vmx->rmode.irq.rip +=
-				vmx->vcpu.arch.event_exit_inst_len;
-		intr_info |= INTR_TYPE_SOFT_INTR;
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
-		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
-		kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+		if (kvm_inject_realmode_interrupt(vcpu, nr) != EMULATE_DONE)
+			kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		return;
 	}
 
@@ -1149,12 +1119,17 @@
 }
 
 /*
- * writes 'guest_tsc' into guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
+ * writes 'offset' into guest's timestamp counter offset register
  */
-static void guest_write_tsc(u64 guest_tsc, u64 host_tsc)
+static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
 {
-	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
+	vmcs_write64(TSC_OFFSET, offset);
+}
+
+static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+	u64 offset = vmcs_read64(TSC_OFFSET);
+	vmcs_write64(TSC_OFFSET, offset + adjustment);
 }
 
 /*
@@ -1227,7 +1202,6 @@
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	struct shared_msr_entry *msr;
-	u64 host_tsc;
 	int ret = 0;
 
 	switch (msr_index) {
@@ -1257,8 +1231,7 @@
 		vmcs_writel(GUEST_SYSENTER_ESP, data);
 		break;
 	case MSR_IA32_TSC:
-		rdtscll(host_tsc);
-		guest_write_tsc(data, host_tsc);
+		kvm_write_tsc(vcpu, data);
 		break;
 	case MSR_IA32_CR_PAT:
 		if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) {
@@ -1856,20 +1829,20 @@
 		return;
 
 	if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-		vmcs_write64(GUEST_PDPTR0, vcpu->arch.pdptrs[0]);
-		vmcs_write64(GUEST_PDPTR1, vcpu->arch.pdptrs[1]);
-		vmcs_write64(GUEST_PDPTR2, vcpu->arch.pdptrs[2]);
-		vmcs_write64(GUEST_PDPTR3, vcpu->arch.pdptrs[3]);
+		vmcs_write64(GUEST_PDPTR0, vcpu->arch.mmu.pdptrs[0]);
+		vmcs_write64(GUEST_PDPTR1, vcpu->arch.mmu.pdptrs[1]);
+		vmcs_write64(GUEST_PDPTR2, vcpu->arch.mmu.pdptrs[2]);
+		vmcs_write64(GUEST_PDPTR3, vcpu->arch.mmu.pdptrs[3]);
 	}
 }
 
 static void ept_save_pdptrs(struct kvm_vcpu *vcpu)
 {
 	if (is_paging(vcpu) && is_pae(vcpu) && !is_long_mode(vcpu)) {
-		vcpu->arch.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
-		vcpu->arch.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
-		vcpu->arch.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
-		vcpu->arch.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
+		vcpu->arch.mmu.pdptrs[0] = vmcs_read64(GUEST_PDPTR0);
+		vcpu->arch.mmu.pdptrs[1] = vmcs_read64(GUEST_PDPTR1);
+		vcpu->arch.mmu.pdptrs[2] = vmcs_read64(GUEST_PDPTR2);
+		vcpu->arch.mmu.pdptrs[3] = vmcs_read64(GUEST_PDPTR3);
 	}
 
 	__set_bit(VCPU_EXREG_PDPTR,
@@ -2515,7 +2488,7 @@
 {
 	u32 host_sysenter_cs, msr_low, msr_high;
 	u32 junk;
-	u64 host_pat, tsc_this, tsc_base;
+	u64 host_pat;
 	unsigned long a;
 	struct desc_ptr dt;
 	int i;
@@ -2656,12 +2629,7 @@
 		vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE;
 	vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits);
 
-	tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc;
-	rdtscll(tsc_this);
-	if (tsc_this < vmx->vcpu.kvm->arch.vm_init_tsc)
-		tsc_base = tsc_this;
-
-	guest_write_tsc(0, tsc_base);
+	kvm_write_tsc(&vmx->vcpu, 0);
 
 	return 0;
 }
@@ -2834,16 +2802,8 @@
 
 	++vcpu->stat.irq_injections;
 	if (vmx->rmode.vm86_active) {
-		vmx->rmode.irq.pending = true;
-		vmx->rmode.irq.vector = irq;
-		vmx->rmode.irq.rip = kvm_rip_read(vcpu);
-		if (vcpu->arch.interrupt.soft)
-			vmx->rmode.irq.rip +=
-				vmx->vcpu.arch.event_exit_inst_len;
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			     irq | INTR_TYPE_SOFT_INTR | INTR_INFO_VALID_MASK);
-		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
-		kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+		if (kvm_inject_realmode_interrupt(vcpu, irq) != EMULATE_DONE)
+			kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		return;
 	}
 	intr = irq | INTR_INFO_VALID_MASK;
@@ -2875,14 +2835,8 @@
 
 	++vcpu->stat.nmi_injections;
 	if (vmx->rmode.vm86_active) {
-		vmx->rmode.irq.pending = true;
-		vmx->rmode.irq.vector = NMI_VECTOR;
-		vmx->rmode.irq.rip = kvm_rip_read(vcpu);
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			     NMI_VECTOR | INTR_TYPE_SOFT_INTR |
-			     INTR_INFO_VALID_MASK);
-		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, 1);
-		kvm_rip_write(vcpu, vmx->rmode.irq.rip - 1);
+		if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR) != EMULATE_DONE)
+			kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
 		return;
 	}
 	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
@@ -3346,6 +3300,7 @@
 
 static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu)
 {
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 	return 1;
 }
 
@@ -3358,6 +3313,8 @@
 	cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
 	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	++vcpu->stat.irq_window_exits;
 
 	/*
@@ -3614,6 +3571,7 @@
 	cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_NMI_PENDING;
 	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
 	++vcpu->stat.nmi_window_exits;
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 
 	return 1;
 }
@@ -3623,8 +3581,17 @@
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
 	enum emulation_result err = EMULATE_DONE;
 	int ret = 1;
+	u32 cpu_exec_ctrl;
+	bool intr_window_requested;
+
+	cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+	intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
 
 	while (!guest_state_valid(vcpu)) {
+		if (intr_window_requested
+		    && (kvm_get_rflags(&vmx->vcpu) & X86_EFLAGS_IF))
+			return handle_interrupt_window(&vmx->vcpu);
+
 		err = emulate_instruction(vcpu, 0, 0, 0);
 
 		if (err == EMULATE_DO_MMIO) {
@@ -3790,18 +3757,9 @@
 	vmcs_write32(TPR_THRESHOLD, irr);
 }
 
-static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
+static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
 {
-	u32 exit_intr_info;
-	u32 idt_vectoring_info = vmx->idt_vectoring_info;
-	bool unblock_nmi;
-	u8 vector;
-	int type;
-	bool idtv_info_valid;
-
-	exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-	vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+	u32 exit_intr_info = vmx->exit_intr_info;
 
 	/* Handle machine checks before interrupts are enabled */
 	if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
@@ -3816,8 +3774,16 @@
 		asm("int $2");
 		kvm_after_handle_nmi(&vmx->vcpu);
 	}
+}
 
-	idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
+static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
+{
+	u32 exit_intr_info = vmx->exit_intr_info;
+	bool unblock_nmi;
+	u8 vector;
+	bool idtv_info_valid;
+
+	idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
 
 	if (cpu_has_virtual_nmis()) {
 		unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
@@ -3839,6 +3805,18 @@
 	} else if (unlikely(vmx->soft_vnmi_blocked))
 		vmx->vnmi_blocked_time +=
 			ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
+}
+
+static void __vmx_complete_interrupts(struct vcpu_vmx *vmx,
+				      u32 idt_vectoring_info,
+				      int instr_len_field,
+				      int error_code_field)
+{
+	u8 vector;
+	int type;
+	bool idtv_info_valid;
+
+	idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
 
 	vmx->vcpu.arch.nmi_injected = false;
 	kvm_clear_exception_queue(&vmx->vcpu);
@@ -3847,6 +3825,8 @@
 	if (!idtv_info_valid)
 		return;
 
+	kvm_make_request(KVM_REQ_EVENT, &vmx->vcpu);
+
 	vector = idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
 	type = idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
 
@@ -3863,18 +3843,18 @@
 		break;
 	case INTR_TYPE_SOFT_EXCEPTION:
 		vmx->vcpu.arch.event_exit_inst_len =
-			vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+			vmcs_read32(instr_len_field);
 		/* fall through */
 	case INTR_TYPE_HARD_EXCEPTION:
 		if (idt_vectoring_info & VECTORING_INFO_DELIVER_CODE_MASK) {
-			u32 err = vmcs_read32(IDT_VECTORING_ERROR_CODE);
+			u32 err = vmcs_read32(error_code_field);
 			kvm_queue_exception_e(&vmx->vcpu, vector, err);
 		} else
 			kvm_queue_exception(&vmx->vcpu, vector);
 		break;
 	case INTR_TYPE_SOFT_INTR:
 		vmx->vcpu.arch.event_exit_inst_len =
-			vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+			vmcs_read32(instr_len_field);
 		/* fall through */
 	case INTR_TYPE_EXT_INTR:
 		kvm_queue_interrupt(&vmx->vcpu, vector,
@@ -3885,27 +3865,21 @@
 	}
 }
 
-/*
- * Failure to inject an interrupt should give us the information
- * in IDT_VECTORING_INFO_FIELD.  However, if the failure occurs
- * when fetching the interrupt redirection bitmap in the real-mode
- * tss, this doesn't happen.  So we do it ourselves.
- */
-static void fixup_rmode_irq(struct vcpu_vmx *vmx)
+static void vmx_complete_interrupts(struct vcpu_vmx *vmx)
 {
-	vmx->rmode.irq.pending = 0;
-	if (kvm_rip_read(&vmx->vcpu) + 1 != vmx->rmode.irq.rip)
-		return;
-	kvm_rip_write(&vmx->vcpu, vmx->rmode.irq.rip);
-	if (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK) {
-		vmx->idt_vectoring_info &= ~VECTORING_INFO_TYPE_MASK;
-		vmx->idt_vectoring_info |= INTR_TYPE_EXT_INTR;
-		return;
-	}
-	vmx->idt_vectoring_info =
-		VECTORING_INFO_VALID_MASK
-		| INTR_TYPE_EXT_INTR
-		| vmx->rmode.irq.vector;
+	__vmx_complete_interrupts(vmx, vmx->idt_vectoring_info,
+				  VM_EXIT_INSTRUCTION_LEN,
+				  IDT_VECTORING_ERROR_CODE);
+}
+
+static void vmx_cancel_injection(struct kvm_vcpu *vcpu)
+{
+	__vmx_complete_interrupts(to_vmx(vcpu),
+				  vmcs_read32(VM_ENTRY_INTR_INFO_FIELD),
+				  VM_ENTRY_INSTRUCTION_LEN,
+				  VM_ENTRY_EXCEPTION_ERROR_CODE);
+
+	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);
 }
 
 #ifdef CONFIG_X86_64
@@ -4032,7 +4006,7 @@
 #endif
 		[cr2]"i"(offsetof(struct vcpu_vmx, vcpu.arch.cr2))
 	      : "cc", "memory"
-		, R"bx", R"di", R"si"
+		, R"ax", R"bx", R"di", R"si"
 #ifdef CONFIG_X86_64
 		, "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
 #endif
@@ -4043,12 +4017,15 @@
 	vcpu->arch.regs_dirty = 0;
 
 	vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-	if (vmx->rmode.irq.pending)
-		fixup_rmode_irq(vmx);
 
 	asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
 	vmx->launched = 1;
 
+	vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
+	vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+
+	vmx_complete_atomic_exit(vmx);
+	vmx_recover_nmi_blocking(vmx);
 	vmx_complete_interrupts(vmx);
 }
 
@@ -4119,6 +4096,7 @@
 
 	cpu = get_cpu();
 	vmx_vcpu_load(&vmx->vcpu, cpu);
+	vmx->vcpu.cpu = cpu;
 	err = vmx_vcpu_setup(vmx);
 	vmx_vcpu_put(&vmx->vcpu);
 	put_cpu();
@@ -4249,11 +4227,6 @@
 		return PT_PDPE_LEVEL;
 }
 
-static inline u32 bit(int bitno)
-{
-	return 1 << (bitno & 31);
-}
-
 static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpuid_entry2 *best;
@@ -4334,6 +4307,7 @@
 	.set_irq = vmx_inject_irq,
 	.set_nmi = vmx_inject_nmi,
 	.queue_exception = vmx_queue_exception,
+	.cancel_injection = vmx_cancel_injection,
 	.interrupt_allowed = vmx_interrupt_allowed,
 	.nmi_allowed = vmx_nmi_allowed,
 	.get_nmi_mask = vmx_get_nmi_mask,
@@ -4356,6 +4330,11 @@
 	.set_supported_cpuid = vmx_set_supported_cpuid,
 
 	.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
+
+	.write_tsc_offset = vmx_write_tsc_offset,
+	.adjust_tsc_offset = vmx_adjust_tsc_offset,
+
+	.set_tdp_cr3 = vmx_set_cr3,
 };
 
 static int __init vmx_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/x86.c linux-libre-2.6.37-gnu/arch/x86/kvm/x86.c
--- linux-libre-2.6.36-gnu/arch/x86/kvm/x86.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/x86.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,7 @@
  * Copyright (C) 2006 Qumranet, Inc.
  * Copyright (C) 2008 Qumranet, Inc.
  * Copyright IBM Corporation, 2008
- * Copyright 2010 Red Hat, Inc. and/or its affilates.
+ * Copyright 2010 Red Hat, Inc. and/or its affiliates.
  *
  * Authors:
  *   Avi Kivity   <avi@qumranet.com>
@@ -55,6 +55,8 @@
 #include <asm/mce.h>
 #include <asm/i387.h>
 #include <asm/xcr.h>
+#include <asm/pvclock.h>
+#include <asm/div64.h>
 
 #define MAX_IO_MSRS 256
 #define CR0_RESERVED_BITS						\
@@ -71,7 +73,7 @@
 #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
 
 #define KVM_MAX_MCE_BANKS 32
-#define KVM_MCE_CAP_SUPPORTED MCG_CTL_P
+#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
 
 /* EFER defaults:
  * - enable syscall per default because its emulated by KVM
@@ -153,11 +155,6 @@
 
 u64 __read_mostly host_xcr0;
 
-static inline u32 bit(int bitno)
-{
-	return 1 << (bitno & 31);
-}
-
 static void kvm_on_user_return(struct user_return_notifier *urn)
 {
 	unsigned slot;
@@ -282,6 +279,8 @@
 	u32 prev_nr;
 	int class1, class2;
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	if (!vcpu->arch.exception.pending) {
 	queue:
 		vcpu->arch.exception.pending = true;
@@ -327,16 +326,28 @@
 }
 EXPORT_SYMBOL_GPL(kvm_requeue_exception);
 
-void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long addr,
-			   u32 error_code)
+void kvm_inject_page_fault(struct kvm_vcpu *vcpu)
 {
+	unsigned error_code = vcpu->arch.fault.error_code;
+
 	++vcpu->stat.pf_guest;
-	vcpu->arch.cr2 = addr;
+	vcpu->arch.cr2 = vcpu->arch.fault.address;
 	kvm_queue_exception_e(vcpu, PF_VECTOR, error_code);
 }
 
+void kvm_propagate_fault(struct kvm_vcpu *vcpu)
+{
+	if (mmu_is_nested(vcpu) && !vcpu->arch.fault.nested)
+		vcpu->arch.nested_mmu.inject_page_fault(vcpu);
+	else
+		vcpu->arch.mmu.inject_page_fault(vcpu);
+
+	vcpu->arch.fault.nested = false;
+}
+
 void kvm_inject_nmi(struct kvm_vcpu *vcpu)
 {
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 	vcpu->arch.nmi_pending = 1;
 }
 EXPORT_SYMBOL_GPL(kvm_inject_nmi);
@@ -367,18 +378,49 @@
 EXPORT_SYMBOL_GPL(kvm_require_cpl);
 
 /*
+ * This function will be used to read from the physical memory of the currently
+ * running guest. The difference to kvm_read_guest_page is that this function
+ * can read from guest physical or from the guest's guest physical memory.
+ */
+int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+			    gfn_t ngfn, void *data, int offset, int len,
+			    u32 access)
+{
+	gfn_t real_gfn;
+	gpa_t ngpa;
+
+	ngpa     = gfn_to_gpa(ngfn);
+	real_gfn = mmu->translate_gpa(vcpu, ngpa, access);
+	if (real_gfn == UNMAPPED_GVA)
+		return -EFAULT;
+
+	real_gfn = gpa_to_gfn(real_gfn);
+
+	return kvm_read_guest_page(vcpu->kvm, real_gfn, data, offset, len);
+}
+EXPORT_SYMBOL_GPL(kvm_read_guest_page_mmu);
+
+int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn,
+			       void *data, int offset, int len, u32 access)
+{
+	return kvm_read_guest_page_mmu(vcpu, vcpu->arch.walk_mmu, gfn,
+				       data, offset, len, access);
+}
+
+/*
  * Load the pae pdptrs.  Return true is they are all valid.
  */
-int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
+int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3)
 {
 	gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
 	unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
 	int i;
 	int ret;
-	u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
+	u64 pdpte[ARRAY_SIZE(mmu->pdptrs)];
 
-	ret = kvm_read_guest_page(vcpu->kvm, pdpt_gfn, pdpte,
-				  offset * sizeof(u64), sizeof(pdpte));
+	ret = kvm_read_guest_page_mmu(vcpu, mmu, pdpt_gfn, pdpte,
+				      offset * sizeof(u64), sizeof(pdpte),
+				      PFERR_USER_MASK|PFERR_WRITE_MASK);
 	if (ret < 0) {
 		ret = 0;
 		goto out;
@@ -392,7 +434,7 @@
 	}
 	ret = 1;
 
-	memcpy(vcpu->arch.pdptrs, pdpte, sizeof(vcpu->arch.pdptrs));
+	memcpy(mmu->pdptrs, pdpte, sizeof(mmu->pdptrs));
 	__set_bit(VCPU_EXREG_PDPTR,
 		  (unsigned long *)&vcpu->arch.regs_avail);
 	__set_bit(VCPU_EXREG_PDPTR,
@@ -405,8 +447,10 @@
 
 static bool pdptrs_changed(struct kvm_vcpu *vcpu)
 {
-	u64 pdpte[ARRAY_SIZE(vcpu->arch.pdptrs)];
+	u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)];
 	bool changed = true;
+	int offset;
+	gfn_t gfn;
 	int r;
 
 	if (is_long_mode(vcpu) || !is_pae(vcpu))
@@ -416,10 +460,13 @@
 		      (unsigned long *)&vcpu->arch.regs_avail))
 		return true;
 
-	r = kvm_read_guest(vcpu->kvm, vcpu->arch.cr3 & ~31u, pdpte, sizeof(pdpte));
+	gfn = (vcpu->arch.cr3 & ~31u) >> PAGE_SHIFT;
+	offset = (vcpu->arch.cr3 & ~31u) & (PAGE_SIZE - 1);
+	r = kvm_read_nested_guest_page(vcpu, gfn, pdpte, offset, sizeof(pdpte),
+				       PFERR_USER_MASK | PFERR_WRITE_MASK);
 	if (r < 0)
 		goto out;
-	changed = memcmp(pdpte, vcpu->arch.pdptrs, sizeof(pdpte)) != 0;
+	changed = memcmp(pdpte, vcpu->arch.walk_mmu->pdptrs, sizeof(pdpte)) != 0;
 out:
 
 	return changed;
@@ -458,7 +505,8 @@
 				return 1;
 		} else
 #endif
-		if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3))
+		if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.walk_mmu,
+						 vcpu->arch.cr3))
 			return 1;
 	}
 
@@ -547,7 +595,7 @@
 			return 1;
 	} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
 		   && ((cr4 ^ old_cr4) & pdptr_bits)
-		   && !load_pdptrs(vcpu, vcpu->arch.cr3))
+		   && !load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3))
 		return 1;
 
 	if (cr4 & X86_CR4_VMXE)
@@ -580,7 +628,8 @@
 		if (is_pae(vcpu)) {
 			if (cr3 & CR3_PAE_RESERVED_BITS)
 				return 1;
-			if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3))
+			if (is_paging(vcpu) &&
+			    !load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3))
 				return 1;
 		}
 		/*
@@ -737,7 +786,7 @@
 #ifdef CONFIG_X86_64
 	MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
-	MSR_IA32_TSC, MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
+	MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
 };
 
 static unsigned num_msrs_to_save;
@@ -838,7 +887,7 @@
 
 	/*
 	 * The guest calculates current wall clock time by adding
-	 * system time (updated by kvm_write_guest_time below) to the
+	 * system time (updated by kvm_guest_time_update below) to the
 	 * wall clock specified here.  guest system time equals host
 	 * system time for us, thus we must fill in host boot time here.
 	 */
@@ -866,65 +915,229 @@
 	return quotient;
 }
 
-static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock)
+static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz,
+			       s8 *pshift, u32 *pmultiplier)
 {
-	uint64_t nsecs = 1000000000LL;
+	uint64_t scaled64;
 	int32_t  shift = 0;
 	uint64_t tps64;
 	uint32_t tps32;
 
-	tps64 = tsc_khz * 1000LL;
-	while (tps64 > nsecs*2) {
+	tps64 = base_khz * 1000LL;
+	scaled64 = scaled_khz * 1000LL;
+	while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) {
 		tps64 >>= 1;
 		shift--;
 	}
 
 	tps32 = (uint32_t)tps64;
-	while (tps32 <= (uint32_t)nsecs) {
-		tps32 <<= 1;
+	while (tps32 <= scaled64 || scaled64 & 0xffffffff00000000ULL) {
+		if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000)
+			scaled64 >>= 1;
+		else
+			tps32 <<= 1;
 		shift++;
 	}
 
-	hv_clock->tsc_shift = shift;
-	hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
+	*pshift = shift;
+	*pmultiplier = div_frac(scaled64, tps32);
 
-	pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
-		 __func__, tsc_khz, hv_clock->tsc_shift,
-		 hv_clock->tsc_to_system_mul);
+	pr_debug("%s: base_khz %u => %u, shift %d, mul %u\n",
+		 __func__, base_khz, scaled_khz, shift, *pmultiplier);
+}
+
+static inline u64 get_kernel_ns(void)
+{
+	struct timespec ts;
+
+	WARN_ON(preemptible());
+	ktime_get_ts(&ts);
+	monotonic_to_bootbased(&ts);
+	return timespec_to_ns(&ts);
 }
 
 static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
+unsigned long max_tsc_khz;
 
-static void kvm_write_guest_time(struct kvm_vcpu *v)
+static inline int kvm_tsc_changes_freq(void)
+{
+	int cpu = get_cpu();
+	int ret = !boot_cpu_has(X86_FEATURE_CONSTANT_TSC) &&
+		  cpufreq_quick_get(cpu) != 0;
+	put_cpu();
+	return ret;
+}
+
+static inline u64 nsec_to_cycles(u64 nsec)
+{
+	u64 ret;
+
+	WARN_ON(preemptible());
+	if (kvm_tsc_changes_freq())
+		printk_once(KERN_WARNING
+		 "kvm: unreliable cycle conversion on adjustable rate TSC\n");
+	ret = nsec * __get_cpu_var(cpu_tsc_khz);
+	do_div(ret, USEC_PER_SEC);
+	return ret;
+}
+
+static void kvm_arch_set_tsc_khz(struct kvm *kvm, u32 this_tsc_khz)
+{
+	/* Compute a scale to convert nanoseconds in TSC cycles */
+	kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
+			   &kvm->arch.virtual_tsc_shift,
+			   &kvm->arch.virtual_tsc_mult);
+	kvm->arch.virtual_tsc_khz = this_tsc_khz;
+}
+
+static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
+{
+	u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec,
+				      vcpu->kvm->arch.virtual_tsc_mult,
+				      vcpu->kvm->arch.virtual_tsc_shift);
+	tsc += vcpu->arch.last_tsc_write;
+	return tsc;
+}
+
+void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
+{
+	struct kvm *kvm = vcpu->kvm;
+	u64 offset, ns, elapsed;
+	unsigned long flags;
+	s64 sdiff;
+
+	spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
+	offset = data - native_read_tsc();
+	ns = get_kernel_ns();
+	elapsed = ns - kvm->arch.last_tsc_nsec;
+	sdiff = data - kvm->arch.last_tsc_write;
+	if (sdiff < 0)
+		sdiff = -sdiff;
+
+	/*
+	 * Special case: close write to TSC within 5 seconds of
+	 * another CPU is interpreted as an attempt to synchronize
+	 * The 5 seconds is to accomodate host load / swapping as
+	 * well as any reset of TSC during the boot process.
+	 *
+	 * In that case, for a reliable TSC, we can match TSC offsets,
+	 * or make a best guest using elapsed value.
+	 */
+	if (sdiff < nsec_to_cycles(5ULL * NSEC_PER_SEC) &&
+	    elapsed < 5ULL * NSEC_PER_SEC) {
+		if (!check_tsc_unstable()) {
+			offset = kvm->arch.last_tsc_offset;
+			pr_debug("kvm: matched tsc offset for %llu\n", data);
+		} else {
+			u64 delta = nsec_to_cycles(elapsed);
+			offset += delta;
+			pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
+		}
+		ns = kvm->arch.last_tsc_nsec;
+	}
+	kvm->arch.last_tsc_nsec = ns;
+	kvm->arch.last_tsc_write = data;
+	kvm->arch.last_tsc_offset = offset;
+	kvm_x86_ops->write_tsc_offset(vcpu, offset);
+	spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags);
+
+	/* Reset of TSC must disable overshoot protection below */
+	vcpu->arch.hv_clock.tsc_timestamp = 0;
+	vcpu->arch.last_tsc_write = data;
+	vcpu->arch.last_tsc_nsec = ns;
+}
+EXPORT_SYMBOL_GPL(kvm_write_tsc);
+
+static int kvm_guest_time_update(struct kvm_vcpu *v)
 {
-	struct timespec ts;
 	unsigned long flags;
 	struct kvm_vcpu_arch *vcpu = &v->arch;
 	void *shared_kaddr;
 	unsigned long this_tsc_khz;
+	s64 kernel_ns, max_kernel_ns;
+	u64 tsc_timestamp;
 
-	if ((!vcpu->time_page))
-		return;
+	/* Keep irq disabled to prevent changes to the clock */
+	local_irq_save(flags);
+	kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
+	kernel_ns = get_kernel_ns();
+	this_tsc_khz = __get_cpu_var(cpu_tsc_khz);
 
-	this_tsc_khz = get_cpu_var(cpu_tsc_khz);
-	if (unlikely(vcpu->hv_clock_tsc_khz != this_tsc_khz)) {
-		kvm_set_time_scale(this_tsc_khz, &vcpu->hv_clock);
-		vcpu->hv_clock_tsc_khz = this_tsc_khz;
+	if (unlikely(this_tsc_khz == 0)) {
+		local_irq_restore(flags);
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
+		return 1;
+	}
+
+	/*
+	 * We may have to catch up the TSC to match elapsed wall clock
+	 * time for two reasons, even if kvmclock is used.
+	 *   1) CPU could have been running below the maximum TSC rate
+	 *   2) Broken TSC compensation resets the base at each VCPU
+	 *      entry to avoid unknown leaps of TSC even when running
+	 *      again on the same CPU.  This may cause apparent elapsed
+	 *      time to disappear, and the guest to stand still or run
+	 *	very slowly.
+	 */
+	if (vcpu->tsc_catchup) {
+		u64 tsc = compute_guest_tsc(v, kernel_ns);
+		if (tsc > tsc_timestamp) {
+			kvm_x86_ops->adjust_tsc_offset(v, tsc - tsc_timestamp);
+			tsc_timestamp = tsc;
+		}
 	}
-	put_cpu_var(cpu_tsc_khz);
 
-	/* Keep irq disabled to prevent changes to the clock */
-	local_irq_save(flags);
-	kvm_get_msr(v, MSR_IA32_TSC, &vcpu->hv_clock.tsc_timestamp);
-	ktime_get_ts(&ts);
-	monotonic_to_bootbased(&ts);
 	local_irq_restore(flags);
 
-	/* With all the info we got, fill in the values */
+	if (!vcpu->time_page)
+		return 0;
 
-	vcpu->hv_clock.system_time = ts.tv_nsec +
-				     (NSEC_PER_SEC * (u64)ts.tv_sec) + v->kvm->arch.kvmclock_offset;
+	/*
+	 * Time as measured by the TSC may go backwards when resetting the base
+	 * tsc_timestamp.  The reason for this is that the TSC resolution is
+	 * higher than the resolution of the other clock scales.  Thus, many
+	 * possible measurments of the TSC correspond to one measurement of any
+	 * other clock, and so a spread of values is possible.  This is not a
+	 * problem for the computation of the nanosecond clock; with TSC rates
+	 * around 1GHZ, there can only be a few cycles which correspond to one
+	 * nanosecond value, and any path through this code will inevitably
+	 * take longer than that.  However, with the kernel_ns value itself,
+	 * the precision may be much lower, down to HZ granularity.  If the
+	 * first sampling of TSC against kernel_ns ends in the low part of the
+	 * range, and the second in the high end of the range, we can get:
+	 *
+	 * (TSC - offset_low) * S + kns_old > (TSC - offset_high) * S + kns_new
+	 *
+	 * As the sampling errors potentially range in the thousands of cycles,
+	 * it is possible such a time value has already been observed by the
+	 * guest.  To protect against this, we must compute the system time as
+	 * observed by the guest and ensure the new system time is greater.
+	 */
+	max_kernel_ns = 0;
+	if (vcpu->hv_clock.tsc_timestamp && vcpu->last_guest_tsc) {
+		max_kernel_ns = vcpu->last_guest_tsc -
+				vcpu->hv_clock.tsc_timestamp;
+		max_kernel_ns = pvclock_scale_delta(max_kernel_ns,
+				    vcpu->hv_clock.tsc_to_system_mul,
+				    vcpu->hv_clock.tsc_shift);
+		max_kernel_ns += vcpu->last_kernel_ns;
+	}
 
+	if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) {
+		kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz,
+				   &vcpu->hv_clock.tsc_shift,
+				   &vcpu->hv_clock.tsc_to_system_mul);
+		vcpu->hw_tsc_khz = this_tsc_khz;
+	}
+
+	if (max_kernel_ns > kernel_ns)
+		kernel_ns = max_kernel_ns;
+
+	/* With all the info we got, fill in the values */
+	vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
+	vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
+	vcpu->last_kernel_ns = kernel_ns;
+	vcpu->last_guest_tsc = tsc_timestamp;
 	vcpu->hv_clock.flags = 0;
 
 	/*
@@ -942,16 +1155,7 @@
 	kunmap_atomic(shared_kaddr, KM_USER0);
 
 	mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT);
-}
-
-static int kvm_request_guest_time_update(struct kvm_vcpu *v)
-{
-	struct kvm_vcpu_arch *vcpu = &v->arch;
-
-	if (!vcpu->time_page)
-		return 0;
-	kvm_make_request(KVM_REQ_KVMCLOCK_UPDATE, v);
-	return 1;
+	return 0;
 }
 
 static bool msr_mtrr_valid(unsigned msr)
@@ -1277,6 +1481,7 @@
 		}
 
 		vcpu->arch.time = data;
+		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
 		/* we verify if the enable bit is set... */
 		if (!(data & 1))
@@ -1292,8 +1497,6 @@
 			kvm_release_page_clean(vcpu->arch.time_page);
 			vcpu->arch.time_page = NULL;
 		}
-
-		kvm_request_guest_time_update(vcpu);
 		break;
 	}
 	case MSR_IA32_MCG_CTL:
@@ -1330,6 +1533,16 @@
 		pr_unimpl(vcpu, "unimplemented perfctr wrmsr: "
 			"0x%x data 0x%llx\n", msr, data);
 		break;
+	case MSR_K7_CLK_CTL:
+		/*
+		 * Ignore all writes to this no longer documented MSR.
+		 * Writes are only relevant for old K7 processors,
+		 * all pre-dating SVM, but a recommended workaround from
+		 * AMD for these chips. It is possible to speicify the
+		 * affected processor models on the command line, hence
+		 * the need to ignore the workaround.
+		 */
+		break;
 	case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
 		if (kvm_hv_msr_partition_wide(msr)) {
 			int r;
@@ -1522,6 +1735,20 @@
 	case 0xcd: /* fsb frequency */
 		data = 3;
 		break;
+		/*
+		 * MSR_EBC_FREQUENCY_ID
+		 * Conservative value valid for even the basic CPU models.
+		 * Models 0,1: 000 in bits 23:21 indicating a bus speed of
+		 * 100MHz, model 2 000 in bits 18:16 indicating 100MHz,
+		 * and 266MHz for model 3, or 4. Set Core Clock
+		 * Frequency to System Bus Frequency Ratio to 1 (bits
+		 * 31:24) even though these are only valid for CPU
+		 * models > 2, however guests may end up dividing or
+		 * multiplying by zero otherwise.
+		 */
+	case MSR_EBC_FREQUENCY_ID:
+		data = 1 << 24;
+		break;
 	case MSR_IA32_APICBASE:
 		data = kvm_get_apic_base(vcpu);
 		break;
@@ -1555,6 +1782,18 @@
 	case MSR_IA32_MCG_STATUS:
 	case MSR_IA32_MC0_CTL ... MSR_IA32_MC0_CTL + 4 * KVM_MAX_MCE_BANKS - 1:
 		return get_msr_mce(vcpu, msr, pdata);
+	case MSR_K7_CLK_CTL:
+		/*
+		 * Provide expected ramp-up count for K7. All other
+		 * are set to zero, indicating minimum divisors for
+		 * every field.
+		 *
+		 * This prevents guest kernels on AMD host with CPU
+		 * type 6, model 8 and higher from exploding due to
+		 * the rdmsr failing.
+		 */
+		data = 0x20000000;
+		break;
 	case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
 		if (kvm_hv_msr_partition_wide(msr)) {
 			int r;
@@ -1808,19 +2047,28 @@
 	}
 
 	kvm_x86_ops->vcpu_load(vcpu, cpu);
-	if (unlikely(per_cpu(cpu_tsc_khz, cpu) == 0)) {
-		unsigned long khz = cpufreq_quick_get(cpu);
-		if (!khz)
-			khz = tsc_khz;
-		per_cpu(cpu_tsc_khz, cpu) = khz;
+	if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
+		/* Make sure TSC doesn't go backwards */
+		s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
+				native_read_tsc() - vcpu->arch.last_host_tsc;
+		if (tsc_delta < 0)
+			mark_tsc_unstable("KVM discovered backwards TSC");
+		if (check_tsc_unstable()) {
+			kvm_x86_ops->adjust_tsc_offset(vcpu, -tsc_delta);
+			vcpu->arch.tsc_catchup = 1;
+			kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+		}
+		if (vcpu->cpu != cpu)
+			kvm_migrate_timers(vcpu);
+		vcpu->cpu = cpu;
 	}
-	kvm_request_guest_time_update(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	kvm_x86_ops->vcpu_put(vcpu);
 	kvm_put_guest_fpu(vcpu);
+	vcpu->arch.last_host_tsc = native_read_tsc();
 }
 
 static int is_efer_nx(void)
@@ -1991,13 +2239,14 @@
 		0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
 		0 /* Reserved, DCA */ | F(XMM4_1) |
 		F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
-		0 /* Reserved, AES */ | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX);
+		0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |
+		F(F16C);
 	/* cpuid 0x80000001.ecx */
 	const u32 kvm_supported_word6_x86_features =
-		F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
+		F(LAHF_LM) | F(CMP_LEGACY) | 0 /*SVM*/ | 0 /* ExtApicSpace */ |
 		F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
-		F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(SSE5) |
-		0 /* SKINIT */ | 0 /* WDT */;
+		F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
+		0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
 	/* all calls to cpuid_count() should be made on the same cpu */
 	get_cpu();
@@ -2203,6 +2452,7 @@
 		return -ENXIO;
 
 	kvm_queue_interrupt(vcpu, irq->irq, false);
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 
 	return 0;
 }
@@ -2305,6 +2555,7 @@
 		!kvm_exception_is_soft(vcpu->arch.exception.nr);
 	events->exception.nr = vcpu->arch.exception.nr;
 	events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+	events->exception.pad = 0;
 	events->exception.error_code = vcpu->arch.exception.error_code;
 
 	events->interrupt.injected =
@@ -2318,12 +2569,14 @@
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
 	events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+	events->nmi.pad = 0;
 
 	events->sipi_vector = vcpu->arch.sipi_vector;
 
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
 			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
 			 | KVM_VCPUEVENT_VALID_SHADOW);
+	memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2356,6 +2609,8 @@
 	if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR)
 		vcpu->arch.sipi_vector = events->sipi_vector;
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	return 0;
 }
 
@@ -2366,6 +2621,7 @@
 	dbgregs->dr6 = vcpu->arch.dr6;
 	dbgregs->dr7 = vcpu->arch.dr7;
 	dbgregs->flags = 0;
+	memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -2759,7 +3015,7 @@
 
 static int kvm_vm_ioctl_get_nr_mmu_pages(struct kvm *kvm)
 {
-	return kvm->arch.n_alloc_mmu_pages;
+	return kvm->arch.n_max_mmu_pages;
 }
 
 static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
@@ -2795,18 +3051,18 @@
 	r = 0;
 	switch (chip->chip_id) {
 	case KVM_IRQCHIP_PIC_MASTER:
-		raw_spin_lock(&pic_irqchip(kvm)->lock);
+		spin_lock(&pic_irqchip(kvm)->lock);
 		memcpy(&pic_irqchip(kvm)->pics[0],
 			&chip->chip.pic,
 			sizeof(struct kvm_pic_state));
-		raw_spin_unlock(&pic_irqchip(kvm)->lock);
+		spin_unlock(&pic_irqchip(kvm)->lock);
 		break;
 	case KVM_IRQCHIP_PIC_SLAVE:
-		raw_spin_lock(&pic_irqchip(kvm)->lock);
+		spin_lock(&pic_irqchip(kvm)->lock);
 		memcpy(&pic_irqchip(kvm)->pics[1],
 			&chip->chip.pic,
 			sizeof(struct kvm_pic_state));
-		raw_spin_unlock(&pic_irqchip(kvm)->lock);
+		spin_unlock(&pic_irqchip(kvm)->lock);
 		break;
 	case KVM_IRQCHIP_IOAPIC:
 		r = kvm_set_ioapic(kvm, &chip->chip.ioapic);
@@ -2849,6 +3105,7 @@
 		sizeof(ps->channels));
 	ps->flags = kvm->arch.vpit->pit_state.flags;
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+	memset(&ps->reserved, 0, sizeof(ps->reserved));
 	return r;
 }
 
@@ -2912,10 +3169,6 @@
 		struct kvm_memslots *slots, *old_slots;
 		unsigned long *dirty_bitmap;
 
-		spin_lock(&kvm->mmu_lock);
-		kvm_mmu_slot_remove_write_access(kvm, log->slot);
-		spin_unlock(&kvm->mmu_lock);
-
 		r = -ENOMEM;
 		dirty_bitmap = vmalloc(n);
 		if (!dirty_bitmap)
@@ -2937,6 +3190,10 @@
 		dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
 		kfree(old_slots);
 
+		spin_lock(&kvm->mmu_lock);
+		kvm_mmu_slot_remove_write_access(kvm, log->slot);
+		spin_unlock(&kvm->mmu_lock);
+
 		r = -EFAULT;
 		if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
 			vfree(dirty_bitmap);
@@ -3200,7 +3457,6 @@
 		break;
 	}
 	case KVM_SET_CLOCK: {
-		struct timespec now;
 		struct kvm_clock_data user_ns;
 		u64 now_ns;
 		s64 delta;
@@ -3214,21 +3470,23 @@
 			goto out;
 
 		r = 0;
-		ktime_get_ts(&now);
-		now_ns = timespec_to_ns(&now);
+		local_irq_disable();
+		now_ns = get_kernel_ns();
 		delta = user_ns.clock - now_ns;
+		local_irq_enable();
 		kvm->arch.kvmclock_offset = delta;
 		break;
 	}
 	case KVM_GET_CLOCK: {
-		struct timespec now;
 		struct kvm_clock_data user_ns;
 		u64 now_ns;
 
-		ktime_get_ts(&now);
-		now_ns = timespec_to_ns(&now);
+		local_irq_disable();
+		now_ns = get_kernel_ns();
 		user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
+		local_irq_enable();
 		user_ns.flags = 0;
+		memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
 		r = -EFAULT;
 		if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
@@ -3291,30 +3549,51 @@
 	kvm_x86_ops->get_segment(vcpu, var, seg);
 }
 
+static gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access)
+{
+	return gpa;
+}
+
+static gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access)
+{
+	gpa_t t_gpa;
+	u32 error;
+
+	BUG_ON(!mmu_is_nested(vcpu));
+
+	/* NPT walks are always user-walks */
+	access |= PFERR_USER_MASK;
+	t_gpa  = vcpu->arch.mmu.gva_to_gpa(vcpu, gpa, access, &error);
+	if (t_gpa == UNMAPPED_GVA)
+		vcpu->arch.fault.nested = true;
+
+	return t_gpa;
+}
+
 gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
 {
 	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
-	return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
 }
 
  gpa_t kvm_mmu_gva_to_gpa_fetch(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
 {
 	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
 	access |= PFERR_FETCH_MASK;
-	return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
 }
 
 gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
 {
 	u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
 	access |= PFERR_WRITE_MASK;
-	return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, access, error);
+	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, access, error);
 }
 
 /* uses this to access any guest's mapped memory without checking CPL */
 gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, u32 *error)
 {
-	return vcpu->arch.mmu.gva_to_gpa(vcpu, gva, 0, error);
+	return vcpu->arch.walk_mmu->gva_to_gpa(vcpu, gva, 0, error);
 }
 
 static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes,
@@ -3325,7 +3604,8 @@
 	int r = X86EMUL_CONTINUE;
 
 	while (bytes) {
-		gpa_t gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, addr, access, error);
+		gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, access,
+							    error);
 		unsigned offset = addr & (PAGE_SIZE-1);
 		unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset);
 		int ret;
@@ -3380,8 +3660,9 @@
 	int r = X86EMUL_CONTINUE;
 
 	while (bytes) {
-		gpa_t gpa =  vcpu->arch.mmu.gva_to_gpa(vcpu, addr,
-						       PFERR_WRITE_MASK, error);
+		gpa_t gpa =  vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr,
+							     PFERR_WRITE_MASK,
+							     error);
 		unsigned offset = addr & (PAGE_SIZE-1);
 		unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset);
 		int ret;
@@ -3623,7 +3904,7 @@
 	if (vcpu->arch.pio.count)
 		goto data_avail;
 
-	trace_kvm_pio(1, port, size, 1);
+	trace_kvm_pio(0, port, size, 1);
 
 	vcpu->arch.pio.port = port;
 	vcpu->arch.pio.in = 1;
@@ -3651,7 +3932,7 @@
 			      const void *val, unsigned int count,
 			      struct kvm_vcpu *vcpu)
 {
-	trace_kvm_pio(0, port, size, 1);
+	trace_kvm_pio(1, port, size, 1);
 
 	vcpu->arch.pio.port = port;
 	vcpu->arch.pio.in = 0;
@@ -3692,8 +3973,10 @@
 		return X86EMUL_CONTINUE;
 
 	if (kvm_x86_ops->has_wbinvd_exit()) {
+		preempt_disable();
 		smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
 				wbinvd_ipi, NULL, 1);
+		preempt_enable();
 		cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
 	}
 	wbinvd();
@@ -3790,6 +4073,11 @@
 	kvm_x86_ops->get_gdt(vcpu, dt);
 }
 
+static void emulator_get_idt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+{
+	kvm_x86_ops->get_idt(vcpu, dt);
+}
+
 static unsigned long emulator_get_cached_segment_base(int seg,
 						      struct kvm_vcpu *vcpu)
 {
@@ -3883,6 +4171,7 @@
 	.set_segment_selector = emulator_set_segment_selector,
 	.get_cached_segment_base = emulator_get_cached_segment_base,
 	.get_gdt             = emulator_get_gdt,
+	.get_idt	     = emulator_get_idt,
 	.get_cr              = emulator_get_cr,
 	.set_cr              = emulator_set_cr,
 	.cpl                 = emulator_get_cpl,
@@ -3918,13 +4207,64 @@
 {
 	struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
 	if (ctxt->exception == PF_VECTOR)
-		kvm_inject_page_fault(vcpu, ctxt->cr2, ctxt->error_code);
+		kvm_propagate_fault(vcpu);
 	else if (ctxt->error_code_valid)
 		kvm_queue_exception_e(vcpu, ctxt->exception, ctxt->error_code);
 	else
 		kvm_queue_exception(vcpu, ctxt->exception);
 }
 
+static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
+{
+	struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+	int cs_db, cs_l;
+
+	cache_all_regs(vcpu);
+
+	kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+
+	vcpu->arch.emulate_ctxt.vcpu = vcpu;
+	vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+	vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
+	vcpu->arch.emulate_ctxt.mode =
+		(!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
+		(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
+		? X86EMUL_MODE_VM86 : cs_l
+		? X86EMUL_MODE_PROT64 :	cs_db
+		? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+	memset(c, 0, sizeof(struct decode_cache));
+	memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+}
+
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq)
+{
+	struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+	int ret;
+
+	init_emulate_ctxt(vcpu);
+
+	vcpu->arch.emulate_ctxt.decode.op_bytes = 2;
+	vcpu->arch.emulate_ctxt.decode.ad_bytes = 2;
+	vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip;
+	ret = emulate_int_real(&vcpu->arch.emulate_ctxt, &emulate_ops, irq);
+
+	if (ret != X86EMUL_CONTINUE)
+		return EMULATE_FAIL;
+
+	vcpu->arch.emulate_ctxt.eip = c->eip;
+	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+
+	if (irq == NMI_VECTOR)
+		vcpu->arch.nmi_pending = false;
+	else
+		vcpu->arch.interrupt.pending = false;
+
+	return EMULATE_DONE;
+}
+EXPORT_SYMBOL_GPL(kvm_inject_realmode_interrupt);
+
 static int handle_emulation_failure(struct kvm_vcpu *vcpu)
 {
 	++vcpu->stat.insn_emulation_fail;
@@ -3981,24 +4321,15 @@
 	cache_all_regs(vcpu);
 
 	if (!(emulation_type & EMULTYPE_NO_DECODE)) {
-		int cs_db, cs_l;
-		kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-
-		vcpu->arch.emulate_ctxt.vcpu = vcpu;
-		vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
-		vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
-		vcpu->arch.emulate_ctxt.mode =
-			(!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
-			(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
-			? X86EMUL_MODE_VM86 : cs_l
-			? X86EMUL_MODE_PROT64 :	cs_db
-			? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
-		memset(c, 0, sizeof(struct decode_cache));
-		memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+		init_emulate_ctxt(vcpu);
 		vcpu->arch.emulate_ctxt.interruptibility = 0;
 		vcpu->arch.emulate_ctxt.exception = -1;
+		vcpu->arch.emulate_ctxt.perm_ok = false;
+
+		r = x86_decode_insn(&vcpu->arch.emulate_ctxt);
+		if (r == X86EMUL_PROPAGATE_FAULT)
+			goto done;
 
-		r = x86_decode_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
 		trace_kvm_emulate_insn_start(vcpu);
 
 		/* Only allow emulation of specific instructions on #UD
@@ -4048,41 +4379,39 @@
 	memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
 
 restart:
-	r = x86_emulate_insn(&vcpu->arch.emulate_ctxt, &emulate_ops);
+	r = x86_emulate_insn(&vcpu->arch.emulate_ctxt);
 
-	if (r) { /* emulation failed */
+	if (r == EMULATION_FAILED) {
 		if (reexecute_instruction(vcpu, cr2))
 			return EMULATE_DONE;
 
 		return handle_emulation_failure(vcpu);
 	}
 
-	toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
-	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
-	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
-	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
-
+done:
 	if (vcpu->arch.emulate_ctxt.exception >= 0) {
 		inject_emulated_exception(vcpu);
-		return EMULATE_DONE;
-	}
-
-	if (vcpu->arch.pio.count) {
+		r = EMULATE_DONE;
+	} else if (vcpu->arch.pio.count) {
 		if (!vcpu->arch.pio.in)
 			vcpu->arch.pio.count = 0;
-		return EMULATE_DO_MMIO;
-	}
-
-	if (vcpu->mmio_needed) {
+		r = EMULATE_DO_MMIO;
+	} else if (vcpu->mmio_needed) {
 		if (vcpu->mmio_is_write)
 			vcpu->mmio_needed = 0;
-		return EMULATE_DO_MMIO;
-	}
-
-	if (vcpu->arch.emulate_ctxt.restart)
+		r = EMULATE_DO_MMIO;
+	} else if (r == EMULATION_RESTART)
 		goto restart;
+	else
+		r = EMULATE_DONE;
 
-	return EMULATE_DONE;
+	toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
+	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+
+	return r;
 }
 EXPORT_SYMBOL_GPL(emulate_instruction);
 
@@ -4096,9 +4425,23 @@
 }
 EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
 
-static void bounce_off(void *info)
+static void tsc_bad(void *info)
 {
-	/* nothing */
+	__get_cpu_var(cpu_tsc_khz) = 0;
+}
+
+static void tsc_khz_changed(void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	unsigned long khz = 0;
+
+	if (data)
+		khz = freq->new;
+	else if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+		khz = cpufreq_quick_get(raw_smp_processor_id());
+	if (!khz)
+		khz = tsc_khz;
+	__get_cpu_var(cpu_tsc_khz) = khz;
 }
 
 static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -4109,21 +4452,60 @@
 	struct kvm_vcpu *vcpu;
 	int i, send_ipi = 0;
 
+	/*
+	 * We allow guests to temporarily run on slowing clocks,
+	 * provided we notify them after, or to run on accelerating
+	 * clocks, provided we notify them before.  Thus time never
+	 * goes backwards.
+	 *
+	 * However, we have a problem.  We can't atomically update
+	 * the frequency of a given CPU from this function; it is
+	 * merely a notifier, which can be called from any CPU.
+	 * Changing the TSC frequency at arbitrary points in time
+	 * requires a recomputation of local variables related to
+	 * the TSC for each VCPU.  We must flag these local variables
+	 * to be updated and be sure the update takes place with the
+	 * new frequency before any guests proceed.
+	 *
+	 * Unfortunately, the combination of hotplug CPU and frequency
+	 * change creates an intractable locking scenario; the order
+	 * of when these callouts happen is undefined with respect to
+	 * CPU hotplug, and they can race with each other.  As such,
+	 * merely setting per_cpu(cpu_tsc_khz) = X during a hotadd is
+	 * undefined; you can actually have a CPU frequency change take
+	 * place in between the computation of X and the setting of the
+	 * variable.  To protect against this problem, all updates of
+	 * the per_cpu tsc_khz variable are done in an interrupt
+	 * protected IPI, and all callers wishing to update the value
+	 * must wait for a synchronous IPI to complete (which is trivial
+	 * if the caller is on the CPU already).  This establishes the
+	 * necessary total order on variable updates.
+	 *
+	 * Note that because a guest time update may take place
+	 * anytime after the setting of the VCPU's request bit, the
+	 * correct TSC value must be set before the request.  However,
+	 * to ensure the update actually makes it to any guest which
+	 * starts running in hardware virtualization between the set
+	 * and the acquisition of the spinlock, we must also ping the
+	 * CPU after setting the request bit.
+	 *
+	 */
+
 	if (val == CPUFREQ_PRECHANGE && freq->old > freq->new)
 		return 0;
 	if (val == CPUFREQ_POSTCHANGE && freq->old < freq->new)
 		return 0;
-	per_cpu(cpu_tsc_khz, freq->cpu) = freq->new;
+
+	smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
 
 	spin_lock(&kvm_lock);
 	list_for_each_entry(kvm, &vm_list, vm_list) {
 		kvm_for_each_vcpu(i, vcpu, kvm) {
 			if (vcpu->cpu != freq->cpu)
 				continue;
-			if (!kvm_request_guest_time_update(vcpu))
-				continue;
+			kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 			if (vcpu->cpu != smp_processor_id())
-				send_ipi++;
+				send_ipi = 1;
 		}
 	}
 	spin_unlock(&kvm_lock);
@@ -4141,32 +4523,59 @@
 		 * guest context is entered kvmclock will be updated,
 		 * so the guest will not see stale values.
 		 */
-		smp_call_function_single(freq->cpu, bounce_off, NULL, 1);
+		smp_call_function_single(freq->cpu, tsc_khz_changed, freq, 1);
 	}
 	return 0;
 }
 
 static struct notifier_block kvmclock_cpufreq_notifier_block = {
-        .notifier_call  = kvmclock_cpufreq_notifier
+	.notifier_call  = kvmclock_cpufreq_notifier
+};
+
+static int kvmclock_cpu_notifier(struct notifier_block *nfb,
+					unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch (action) {
+		case CPU_ONLINE:
+		case CPU_DOWN_FAILED:
+			smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
+			break;
+		case CPU_DOWN_PREPARE:
+			smp_call_function_single(cpu, tsc_bad, NULL, 1);
+			break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block kvmclock_cpu_notifier_block = {
+	.notifier_call  = kvmclock_cpu_notifier,
+	.priority = -INT_MAX
 };
 
 static void kvm_timer_init(void)
 {
 	int cpu;
 
+	max_tsc_khz = tsc_khz;
+	register_hotcpu_notifier(&kvmclock_cpu_notifier_block);
 	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
+#ifdef CONFIG_CPU_FREQ
+		struct cpufreq_policy policy;
+		memset(&policy, 0, sizeof(policy));
+		cpu = get_cpu();
+		cpufreq_get_policy(&policy, cpu);
+		if (policy.cpuinfo.max_freq)
+			max_tsc_khz = policy.cpuinfo.max_freq;
+		put_cpu();
+#endif
 		cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
 					  CPUFREQ_TRANSITION_NOTIFIER);
-		for_each_online_cpu(cpu) {
-			unsigned long khz = cpufreq_get(cpu);
-			if (!khz)
-				khz = tsc_khz;
-			per_cpu(cpu_tsc_khz, cpu) = khz;
-		}
-	} else {
-		for_each_possible_cpu(cpu)
-			per_cpu(cpu_tsc_khz, cpu) = tsc_khz;
 	}
+	pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
+	for_each_online_cpu(cpu)
+		smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
 }
 
 static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
@@ -4268,6 +4677,7 @@
 	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
 		cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block,
 					    CPUFREQ_TRANSITION_NOTIFIER);
+	unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block);
 	kvm_x86_ops = NULL;
 	kvm_mmu_module_exit();
 }
@@ -4683,8 +5093,11 @@
 			kvm_mmu_unload(vcpu);
 		if (kvm_check_request(KVM_REQ_MIGRATE_TIMER, vcpu))
 			__kvm_migrate_timers(vcpu);
-		if (kvm_check_request(KVM_REQ_KVMCLOCK_UPDATE, vcpu))
-			kvm_write_guest_time(vcpu);
+		if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
+			r = kvm_guest_time_update(vcpu);
+			if (unlikely(r))
+				goto out;
+		}
 		if (kvm_check_request(KVM_REQ_MMU_SYNC, vcpu))
 			kvm_mmu_sync_roots(vcpu);
 		if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
@@ -4709,6 +5122,21 @@
 	if (unlikely(r))
 		goto out;
 
+	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
+		inject_pending_event(vcpu);
+
+		/* enable NMI/IRQ window open exits if needed */
+		if (vcpu->arch.nmi_pending)
+			kvm_x86_ops->enable_nmi_window(vcpu);
+		else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
+			kvm_x86_ops->enable_irq_window(vcpu);
+
+		if (kvm_lapic_enabled(vcpu)) {
+			update_cr8_intercept(vcpu);
+			kvm_lapic_sync_to_vapic(vcpu);
+		}
+	}
+
 	preempt_disable();
 
 	kvm_x86_ops->prepare_guest_switch(vcpu);
@@ -4727,23 +5155,11 @@
 		smp_wmb();
 		local_irq_enable();
 		preempt_enable();
+		kvm_x86_ops->cancel_injection(vcpu);
 		r = 1;
 		goto out;
 	}
 
-	inject_pending_event(vcpu);
-
-	/* enable NMI/IRQ window open exits if needed */
-	if (vcpu->arch.nmi_pending)
-		kvm_x86_ops->enable_nmi_window(vcpu);
-	else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
-		kvm_x86_ops->enable_irq_window(vcpu);
-
-	if (kvm_lapic_enabled(vcpu)) {
-		update_cr8_intercept(vcpu);
-		kvm_lapic_sync_to_vapic(vcpu);
-	}
-
 	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
 
 	kvm_guest_enter();
@@ -4769,6 +5185,8 @@
 	if (hw_breakpoint_active())
 		hw_breakpoint_restore();
 
+	kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
+
 	atomic_set(&vcpu->guest_mode, 0);
 	smp_wmb();
 	local_irq_enable();
@@ -4898,8 +5316,7 @@
 	if (!irqchip_in_kernel(vcpu->kvm))
 		kvm_set_cr8(vcpu, kvm_run->cr8);
 
-	if (vcpu->arch.pio.count || vcpu->mmio_needed ||
-	    vcpu->arch.emulate_ctxt.restart) {
+	if (vcpu->arch.pio.count || vcpu->mmio_needed) {
 		if (vcpu->mmio_needed) {
 			memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
 			vcpu->mmio_read_completed = 1;
@@ -4980,6 +5397,8 @@
 
 	vcpu->arch.exception.pending = false;
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	return 0;
 }
 
@@ -5043,6 +5462,7 @@
 				    struct kvm_mp_state *mp_state)
 {
 	vcpu->arch.mp_state = mp_state->mp_state;
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 	return 0;
 }
 
@@ -5050,24 +5470,11 @@
 		    bool has_error_code, u32 error_code)
 {
 	struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
-	int cs_db, cs_l, ret;
-	cache_all_regs(vcpu);
-
-	kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+	int ret;
 
-	vcpu->arch.emulate_ctxt.vcpu = vcpu;
-	vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
-	vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
-	vcpu->arch.emulate_ctxt.mode =
-		(!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
-		(vcpu->arch.emulate_ctxt.eflags & X86_EFLAGS_VM)
-		? X86EMUL_MODE_VM86 : cs_l
-		? X86EMUL_MODE_PROT64 :	cs_db
-		? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
-	memset(c, 0, sizeof(struct decode_cache));
-	memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+	init_emulate_ctxt(vcpu);
 
-	ret = emulator_task_switch(&vcpu->arch.emulate_ctxt, &emulate_ops,
+	ret = emulator_task_switch(&vcpu->arch.emulate_ctxt,
 				   tss_selector, reason, has_error_code,
 				   error_code);
 
@@ -5077,6 +5484,7 @@
 	memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
 	kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
 	kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 	return EMULATE_DONE;
 }
 EXPORT_SYMBOL_GPL(kvm_task_switch);
@@ -5111,8 +5519,10 @@
 
 	mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
 	kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
+	if (sregs->cr4 & X86_CR4_OSXSAVE)
+		update_cpuid(vcpu);
 	if (!is_long_mode(vcpu) && is_pae(vcpu)) {
-		load_pdptrs(vcpu, vcpu->arch.cr3);
+		load_pdptrs(vcpu, vcpu->arch.walk_mmu, vcpu->arch.cr3);
 		mmu_reset_needed = 1;
 	}
 
@@ -5147,6 +5557,8 @@
 	    !is_protmode(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	return 0;
 }
 
@@ -5333,6 +5745,10 @@
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 						unsigned int id)
 {
+	if (check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0)
+		printk_once(KERN_WARNING
+		"kvm: SMP vm created on host with unstable TSC; "
+		"guest TSC will not be reliable\n");
 	return kvm_x86_ops->vcpu_create(kvm, id);
 }
 
@@ -5375,22 +5791,22 @@
 	vcpu->arch.dr6 = DR6_FIXED_1;
 	vcpu->arch.dr7 = DR7_FIXED_1;
 
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+
 	return kvm_x86_ops->vcpu_reset(vcpu);
 }
 
 int kvm_arch_hardware_enable(void *garbage)
 {
-	/*
-	 * Since this may be called from a hotplug notifcation,
-	 * we can't get the CPU frequency directly.
-	 */
-	if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
-		int cpu = raw_smp_processor_id();
-		per_cpu(cpu_tsc_khz, cpu) = 0;
-	}
+	struct kvm *kvm;
+	struct kvm_vcpu *vcpu;
+	int i;
 
 	kvm_shared_msr_cpu_online();
-
+	list_for_each_entry(kvm, &vm_list, vm_list)
+		kvm_for_each_vcpu(i, vcpu, kvm)
+			if (vcpu->cpu == smp_processor_id())
+				kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 	return kvm_x86_ops->hardware_enable(garbage);
 }
 
@@ -5424,7 +5840,11 @@
 	BUG_ON(vcpu->kvm == NULL);
 	kvm = vcpu->kvm;
 
+	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
+	vcpu->arch.walk_mmu = &vcpu->arch.mmu;
 	vcpu->arch.mmu.root_hpa = INVALID_PAGE;
+	vcpu->arch.mmu.translate_gpa = translate_gpa;
+	vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa;
 	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 	else
@@ -5437,6 +5857,9 @@
 	}
 	vcpu->arch.pio_data = page_address(page);
 
+	if (!kvm->arch.virtual_tsc_khz)
+		kvm_arch_set_tsc_khz(kvm, max_tsc_khz);
+
 	r = kvm_mmu_create(vcpu);
 	if (r < 0)
 		goto fail_free_pio_data;
@@ -5496,7 +5919,7 @@
 	/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
 	set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
 
-	rdtscll(kvm->arch.vm_init_tsc);
+	spin_lock_init(&kvm->arch.tsc_write_lock);
 
 	return kvm;
 }
@@ -5683,6 +6106,7 @@
 	    kvm_is_linear_rip(vcpu, vcpu->arch.singlestep_rip))
 		rflags |= X86_EFLAGS_TF;
 	kvm_x86_ops->set_rflags(vcpu, rflags);
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
 }
 EXPORT_SYMBOL_GPL(kvm_set_rflags);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/kvm/x86.h linux-libre-2.6.37-gnu/arch/x86/kvm/x86.h
--- linux-libre-2.6.36-gnu/arch/x86/kvm/x86.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/kvm/x86.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,6 +50,11 @@
 #endif
 }
 
+static inline bool mmu_is_nested(struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.walk_mmu == &vcpu->arch.nested_mmu;
+}
+
 static inline int is_pae(struct kvm_vcpu *vcpu)
 {
 	return kvm_read_cr4_bits(vcpu, X86_CR4_PAE);
@@ -65,7 +70,15 @@
 	return kvm_read_cr0_bits(vcpu, X86_CR0_PG);
 }
 
+static inline u32 bit(int bitno)
+{
+	return 1 << (bitno & 31);
+}
+
 void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
 void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq);
+
+void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data);
 
 #endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/lguest/boot.c linux-libre-2.6.37-gnu/arch/x86/lguest/boot.c
--- linux-libre-2.6.36-gnu/arch/x86/lguest/boot.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/lguest/boot.c	2011-01-04 19:50:19.000000000 -0500
@@ -531,7 +531,10 @@
 {
 	lguest_data.pgdir = cr3;
 	lazy_hcall1(LHCALL_NEW_PGTABLE, cr3);
-	cr3_changed = true;
+
+	/* These two page tables are simple, linear, and used during boot */
+	if (cr3 != __pa(swapper_pg_dir) && cr3 != __pa(initial_page_table))
+		cr3_changed = true;
 }
 
 static unsigned long lguest_read_cr3(void)
@@ -703,9 +706,9 @@
  * to forget all of them.  Fortunately, this is very rare.
  *
  * ... except in early boot when the kernel sets up the initial pagetables,
- * which makes booting astonishingly slow: 1.83 seconds!  So we don't even tell
- * the Host anything changed until we've done the first page table switch,
- * which brings boot back to 0.25 seconds.
+ * which makes booting astonishingly slow: 48 seconds!  So we don't even tell
+ * the Host anything changed until we've done the first real page table switch,
+ * which brings boot back to 4.3 seconds.
  */
 static void lguest_set_pte(pte_t *ptep, pte_t pteval)
 {
@@ -791,22 +794,22 @@
  * simple as setting a bit.  We don't actually "ack" interrupts as such, we
  * just mask and unmask them.  I wonder if we should be cleverer?
  */
-static void disable_lguest_irq(unsigned int irq)
+static void disable_lguest_irq(struct irq_data *data)
 {
-	set_bit(irq, lguest_data.blocked_interrupts);
+	set_bit(data->irq, lguest_data.blocked_interrupts);
 }
 
-static void enable_lguest_irq(unsigned int irq)
+static void enable_lguest_irq(struct irq_data *data)
 {
-	clear_bit(irq, lguest_data.blocked_interrupts);
+	clear_bit(data->irq, lguest_data.blocked_interrupts);
 }
 
 /* This structure describes the lguest IRQ controller. */
 static struct irq_chip lguest_irq_controller = {
 	.name		= "lguest",
-	.mask		= disable_lguest_irq,
-	.mask_ack	= disable_lguest_irq,
-	.unmask		= enable_lguest_irq,
+	.irq_mask	= disable_lguest_irq,
+	.irq_mask_ack	= disable_lguest_irq,
+	.irq_unmask	= enable_lguest_irq,
 };
 
 /*
@@ -838,12 +841,12 @@
  * rather than set them in lguest_init_IRQ we are called here every time an
  * lguest device needs an interrupt.
  *
- * FIXME: irq_to_desc_alloc_node() can fail due to lack of memory, we should
+ * FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should
  * pass that up!
  */
 void lguest_setup_irq(unsigned int irq)
 {
-	irq_to_desc_alloc_node(irq, 0);
+	irq_alloc_desc_at(irq, 0);
 	set_irq_chip_and_handler_name(irq, &lguest_irq_controller,
 				      handle_level_irq, "level");
 }
@@ -1002,7 +1005,7 @@
 	clockevents_register_device(&lguest_clockevent);
 
 	/* Finally, we unblock the timer interrupt. */
-	enable_lguest_irq(0);
+	clear_bit(0, lguest_data.blocked_interrupts);
 }
 
 /*
@@ -1349,9 +1352,6 @@
 	 */
 	switch_to_new_gdt(0);
 
-	/* We actually boot with all memory mapped, but let's say 128MB. */
-	max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT;
-
 	/*
 	 * The Host<->Guest Switcher lives at the top of our address space, and
 	 * the Host told us how big it is when we made LGUEST_INIT hypercall:
diff -druN linux-libre-2.6.36-gnu/arch/x86/lguest/i386_head.S linux-libre-2.6.37-gnu/arch/x86/lguest/i386_head.S
--- linux-libre-2.6.36-gnu/arch/x86/lguest/i386_head.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/lguest/i386_head.S	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
 #include <asm/processor-flags.h>
+#include <asm/pgtable.h>
 
 /*G:020
  * Our story starts with the kernel booting into startup_32 in
@@ -37,9 +38,113 @@
 	/* Set up the initial stack so we can run C code. */
 	movl $(init_thread_union+THREAD_SIZE),%esp
 
+	call init_pagetables
+
 	/* Jumps are relative: we're running __PAGE_OFFSET too low. */
 	jmp lguest_init+__PAGE_OFFSET
 
+/*
+ * Initialize page tables.  This creates a PDE and a set of page
+ * tables, which are located immediately beyond __brk_base.  The variable
+ * _brk_end is set up to point to the first "safe" location.
+ * Mappings are created both at virtual address 0 (identity mapping)
+ * and PAGE_OFFSET for up to _end.
+ *
+ * FIXME: This code is taken verbatim from arch/x86/kernel/head_32.S: they
+ * don't have a stack at this point, so we can't just use call and ret.
+ */
+init_pagetables:
+#if PTRS_PER_PMD > 1
+#define PAGE_TABLE_SIZE(pages) (((pages) / PTRS_PER_PMD) + PTRS_PER_PGD)
+#else
+#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)
+#endif
+#define pa(X) ((X) - __PAGE_OFFSET)
+
+/* Enough space to fit pagetables for the low memory linear map */
+MAPPING_BEYOND_END = \
+	PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT
+#ifdef CONFIG_X86_PAE
+
+	/*
+	 * In PAE mode initial_page_table is statically defined to contain
+	 * enough entries to cover the VMSPLIT option (that is the top 1, 2 or 3
+	 * entries). The identity mapping is handled by pointing two PGD entries
+	 * to the first kernel PMD.
+	 *
+	 * Note the upper half of each PMD or PTE are always zero at this stage.
+	 */
+
+#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */
+
+	xorl %ebx,%ebx				/* %ebx is kept at zero */
+
+	movl $pa(__brk_base), %edi
+	movl $pa(initial_pg_pmd), %edx
+	movl $PTE_IDENT_ATTR, %eax
+10:
+	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PMD entry */
+	movl %ecx,(%edx)			/* Store PMD entry */
+						/* Upper half already zero */
+	addl $8,%edx
+	movl $512,%ecx
+11:
+	stosl
+	xchgl %eax,%ebx
+	stosl
+	xchgl %eax,%ebx
+	addl $0x1000,%eax
+	loop 11b
+
+	/*
+	 * End condition: we must map up to the end + MAPPING_BEYOND_END.
+	 */
+	movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
+	cmpl %ebp,%eax
+	jb 10b
+1:
+	addl $__PAGE_OFFSET, %edi
+	movl %edi, pa(_brk_end)
+	shrl $12, %eax
+	movl %eax, pa(max_pfn_mapped)
+
+	/* Do early initialization of the fixmap area */
+	movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+	movl %eax,pa(initial_pg_pmd+0x1000*KPMDS-8)
+#else	/* Not PAE */
+
+page_pde_offset = (__PAGE_OFFSET >> 20);
+
+	movl $pa(__brk_base), %edi
+	movl $pa(initial_page_table), %edx
+	movl $PTE_IDENT_ATTR, %eax
+10:
+	leal PDE_IDENT_ATTR(%edi),%ecx		/* Create PDE entry */
+	movl %ecx,(%edx)			/* Store identity PDE entry */
+	movl %ecx,page_pde_offset(%edx)		/* Store kernel PDE entry */
+	addl $4,%edx
+	movl $1024, %ecx
+11:
+	stosl
+	addl $0x1000,%eax
+	loop 11b
+	/*
+	 * End condition: we must map up to the end + MAPPING_BEYOND_END.
+	 */
+	movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
+	cmpl %ebp,%eax
+	jb 10b
+	addl $__PAGE_OFFSET, %edi
+	movl %edi, pa(_brk_end)
+	shrl $12, %eax
+	movl %eax, pa(max_pfn_mapped)
+
+	/* Do early initialization of the fixmap area */
+	movl $pa(initial_pg_fixmap)+PDE_IDENT_ATTR,%eax
+	movl %eax,pa(initial_page_table+0xffc)
+#endif
+	ret
+
 /*G:055
  * We create a macro which puts the assembler code between lgstart_ and lgend_
  * markers.  These templates are put in the .text section: they can't be
diff -druN linux-libre-2.6.36-gnu/arch/x86/lib/memcpy_32.c linux-libre-2.6.37-gnu/arch/x86/lib/memcpy_32.c
--- linux-libre-2.6.36-gnu/arch/x86/lib/memcpy_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/lib/memcpy_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,22 +22,187 @@
 
 void *memmove(void *dest, const void *src, size_t n)
 {
-	int d0, d1, d2;
+	int d0,d1,d2,d3,d4,d5;
+	char *ret = dest;
+
+	__asm__ __volatile__(
+		/* Handle more 16bytes in loop */
+		"cmp $0x10, %0\n\t"
+		"jb	1f\n\t"
+
+		/* Decide forward/backward copy mode */
+		"cmp %2, %1\n\t"
+		"jb	2f\n\t"
+
+		/*
+		 * movs instruction have many startup latency
+		 * so we handle small size by general register.
+		 */
+		"cmp  $680, %0\n\t"
+		"jb 3f\n\t"
+		/*
+		 * movs instruction is only good for aligned case.
+		 */
+		"mov %1, %3\n\t"
+		"xor %2, %3\n\t"
+		"and $0xff, %3\n\t"
+		"jz 4f\n\t"
+		"3:\n\t"
+		"sub $0x10, %0\n\t"
+
+		/*
+		 * We gobble 16byts forward in each loop.
+		 */
+		"3:\n\t"
+		"sub $0x10, %0\n\t"
+		"mov 0*4(%1), %3\n\t"
+		"mov 1*4(%1), %4\n\t"
+		"mov  %3, 0*4(%2)\n\t"
+		"mov  %4, 1*4(%2)\n\t"
+		"mov 2*4(%1), %3\n\t"
+		"mov 3*4(%1), %4\n\t"
+		"mov  %3, 2*4(%2)\n\t"
+		"mov  %4, 3*4(%2)\n\t"
+		"lea  0x10(%1), %1\n\t"
+		"lea  0x10(%2), %2\n\t"
+		"jae 3b\n\t"
+		"add $0x10, %0\n\t"
+		"jmp 1f\n\t"
+
+		/*
+		 * Handle data forward by movs.
+		 */
+		".p2align 4\n\t"
+		"4:\n\t"
+		"mov -4(%1, %0), %3\n\t"
+		"lea -4(%2, %0), %4\n\t"
+		"shr $2, %0\n\t"
+		"rep movsl\n\t"
+		"mov %3, (%4)\n\t"
+		"jmp 11f\n\t"
+		/*
+		 * Handle data backward by movs.
+		 */
+		".p2align 4\n\t"
+		"6:\n\t"
+		"mov (%1), %3\n\t"
+		"mov %2, %4\n\t"
+		"lea -4(%1, %0), %1\n\t"
+		"lea -4(%2, %0), %2\n\t"
+		"shr $2, %0\n\t"
+		"std\n\t"
+		"rep movsl\n\t"
+		"mov %3,(%4)\n\t"
+		"cld\n\t"
+		"jmp 11f\n\t"
+
+		/*
+		 * Start to prepare for backward copy.
+		 */
+		".p2align 4\n\t"
+		"2:\n\t"
+		"cmp  $680, %0\n\t"
+		"jb 5f\n\t"
+		"mov %1, %3\n\t"
+		"xor %2, %3\n\t"
+		"and $0xff, %3\n\t"
+		"jz 6b\n\t"
+
+		/*
+		 * Calculate copy position to tail.
+		 */
+		"5:\n\t"
+		"add %0, %1\n\t"
+		"add %0, %2\n\t"
+		"sub $0x10, %0\n\t"
+
+		/*
+		 * We gobble 16byts backward in each loop.
+		 */
+		"7:\n\t"
+		"sub $0x10, %0\n\t"
+
+		"mov -1*4(%1), %3\n\t"
+		"mov -2*4(%1), %4\n\t"
+		"mov  %3, -1*4(%2)\n\t"
+		"mov  %4, -2*4(%2)\n\t"
+		"mov -3*4(%1), %3\n\t"
+		"mov -4*4(%1), %4\n\t"
+		"mov  %3, -3*4(%2)\n\t"
+		"mov  %4, -4*4(%2)\n\t"
+		"lea  -0x10(%1), %1\n\t"
+		"lea  -0x10(%2), %2\n\t"
+		"jae 7b\n\t"
+		/*
+		 * Calculate copy position to head.
+		 */
+		"add $0x10, %0\n\t"
+		"sub %0, %1\n\t"
+		"sub %0, %2\n\t"
+
+		/*
+		 * Move data from 8 bytes to 15 bytes.
+		 */
+		".p2align 4\n\t"
+		"1:\n\t"
+		"cmp $8, %0\n\t"
+		"jb 8f\n\t"
+		"mov 0*4(%1), %3\n\t"
+		"mov 1*4(%1), %4\n\t"
+		"mov -2*4(%1, %0), %5\n\t"
+		"mov -1*4(%1, %0), %1\n\t"
+
+		"mov  %3, 0*4(%2)\n\t"
+		"mov  %4, 1*4(%2)\n\t"
+		"mov  %5, -2*4(%2, %0)\n\t"
+		"mov  %1, -1*4(%2, %0)\n\t"
+		"jmp 11f\n\t"
+
+		/*
+		 * Move data from 4 bytes to 7 bytes.
+		 */
+		".p2align 4\n\t"
+		"8:\n\t"
+		"cmp $4, %0\n\t"
+		"jb 9f\n\t"
+		"mov 0*4(%1), %3\n\t"
+		"mov -1*4(%1, %0), %4\n\t"
+		"mov  %3, 0*4(%2)\n\t"
+		"mov  %4, -1*4(%2, %0)\n\t"
+		"jmp 11f\n\t"
+
+		/*
+		 * Move data from 2 bytes to 3 bytes.
+		 */
+		".p2align 4\n\t"
+		"9:\n\t"
+		"cmp $2, %0\n\t"
+		"jb 10f\n\t"
+		"movw 0*2(%1), %%dx\n\t"
+		"movw -1*2(%1, %0), %%bx\n\t"
+		"movw %%dx, 0*2(%2)\n\t"
+		"movw %%bx, -1*2(%2, %0)\n\t"
+		"jmp 11f\n\t"
+
+		/*
+		 * Move data for 1 byte.
+		 */
+		".p2align 4\n\t"
+		"10:\n\t"
+		"cmp $1, %0\n\t"
+		"jb 11f\n\t"
+		"movb (%1), %%cl\n\t"
+		"movb %%cl, (%2)\n\t"
+		".p2align 4\n\t"
+		"11:"
+		: "=&c" (d0), "=&S" (d1), "=&D" (d2),
+		  "=r" (d3),"=r" (d4), "=r"(d5)
+		:"0" (n),
+		 "1" (src),
+		 "2" (dest)
+		:"memory");
+
+	return ret;
 
-	if (dest < src) {
-		memcpy(dest, src, n);
-	} else {
-		__asm__ __volatile__(
-			"std\n\t"
-			"rep\n\t"
-			"movsb\n\t"
-			"cld"
-			: "=&c" (d0), "=&S" (d1), "=&D" (d2)
-			:"0" (n),
-			 "1" (n-1+src),
-			 "2" (n-1+dest)
-			:"memory");
-	}
-	return dest;
 }
 EXPORT_SYMBOL(memmove);
diff -druN linux-libre-2.6.36-gnu/arch/x86/lib/memcpy_64.S linux-libre-2.6.37-gnu/arch/x86/lib/memcpy_64.S
--- linux-libre-2.6.36-gnu/arch/x86/lib/memcpy_64.S	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/lib/memcpy_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -40,84 +40,132 @@
 ENTRY(__memcpy)
 ENTRY(memcpy)
 	CFI_STARTPROC
+	movq %rdi, %rax
 
 	/*
-	 * Put the number of full 64-byte blocks into %ecx.
-	 * Tail portion is handled at the end:
+	 * Use 32bit CMP here to avoid long NOP padding.
 	 */
-	movq %rdi, %rax
-	movl %edx, %ecx
-	shrl   $6, %ecx
-	jz .Lhandle_tail
+	cmp  $0x20, %edx
+	jb .Lhandle_tail
 
-	.p2align 4
-.Lloop_64:
 	/*
-	 * We decrement the loop index here - and the zero-flag is
-	 * checked at the end of the loop (instructions inbetween do
-	 * not change the zero flag):
+	 * We check whether memory false dependece could occur,
+	 * then jump to corresponding copy mode.
 	 */
-	decl %ecx
+	cmp  %dil, %sil
+	jl .Lcopy_backward
+	subl $0x20, %edx
+.Lcopy_forward_loop:
+	subq $0x20,	%rdx
 
 	/*
-	 * Move in blocks of 4x16 bytes:
+	 * Move in blocks of 4x8 bytes:
 	 */
-	movq 0*8(%rsi),		%r11
-	movq 1*8(%rsi),		%r8
-	movq %r11,		0*8(%rdi)
-	movq %r8,		1*8(%rdi)
-
-	movq 2*8(%rsi),		%r9
-	movq 3*8(%rsi),		%r10
-	movq %r9,		2*8(%rdi)
-	movq %r10,		3*8(%rdi)
-
-	movq 4*8(%rsi),		%r11
-	movq 5*8(%rsi),		%r8
-	movq %r11,		4*8(%rdi)
-	movq %r8,		5*8(%rdi)
-
-	movq 6*8(%rsi),		%r9
-	movq 7*8(%rsi),		%r10
-	movq %r9,		6*8(%rdi)
-	movq %r10,		7*8(%rdi)
+	movq 0*8(%rsi),	%r8
+	movq 1*8(%rsi),	%r9
+	movq 2*8(%rsi),	%r10
+	movq 3*8(%rsi),	%r11
+	leaq 4*8(%rsi),	%rsi
 
-	leaq 64(%rsi), %rsi
-	leaq 64(%rdi), %rdi
+	movq %r8,	0*8(%rdi)
+	movq %r9,	1*8(%rdi)
+	movq %r10,	2*8(%rdi)
+	movq %r11,	3*8(%rdi)
+	leaq 4*8(%rdi),	%rdi
+	jae  .Lcopy_forward_loop
+	addq $0x20,	%rdx
+	jmp  .Lhandle_tail
 
-	jnz  .Lloop_64
+.Lcopy_backward:
+	/*
+	 * Calculate copy position to tail.
+	 */
+	addq %rdx,	%rsi
+	addq %rdx,	%rdi
+	subq $0x20,	%rdx
+	/*
+	 * At most 3 ALU operations in one cycle,
+	 * so append NOPS in the same 16bytes trunk.
+	 */
+	.p2align 4
+.Lcopy_backward_loop:
+	subq $0x20,	%rdx
+	movq -1*8(%rsi),	%r8
+	movq -2*8(%rsi),	%r9
+	movq -3*8(%rsi),	%r10
+	movq -4*8(%rsi),	%r11
+	leaq -4*8(%rsi),	%rsi
+	movq %r8,		-1*8(%rdi)
+	movq %r9,		-2*8(%rdi)
+	movq %r10,		-3*8(%rdi)
+	movq %r11,		-4*8(%rdi)
+	leaq -4*8(%rdi),	%rdi
+	jae  .Lcopy_backward_loop
 
+	/*
+	 * Calculate copy position to head.
+	 */
+	addq $0x20,	%rdx
+	subq %rdx,	%rsi
+	subq %rdx,	%rdi
 .Lhandle_tail:
-	movl %edx, %ecx
-	andl  $63, %ecx
-	shrl   $3, %ecx
-	jz   .Lhandle_7
+	cmpq $16,	%rdx
+	jb   .Lless_16bytes
 
+	/*
+	 * Move data from 16 bytes to 31 bytes.
+	 */
+	movq 0*8(%rsi), %r8
+	movq 1*8(%rsi),	%r9
+	movq -2*8(%rsi, %rdx),	%r10
+	movq -1*8(%rsi, %rdx),	%r11
+	movq %r8,	0*8(%rdi)
+	movq %r9,	1*8(%rdi)
+	movq %r10,	-2*8(%rdi, %rdx)
+	movq %r11,	-1*8(%rdi, %rdx)
+	retq
 	.p2align 4
-.Lloop_8:
-	decl %ecx
-	movq (%rsi),		%r8
-	movq %r8,		(%rdi)
-	leaq 8(%rdi),		%rdi
-	leaq 8(%rsi),		%rsi
-	jnz  .Lloop_8
-
-.Lhandle_7:
-	movl %edx, %ecx
-	andl $7, %ecx
-	jz .Lend
+.Lless_16bytes:
+	cmpq $8,	%rdx
+	jb   .Lless_8bytes
+	/*
+	 * Move data from 8 bytes to 15 bytes.
+	 */
+	movq 0*8(%rsi),	%r8
+	movq -1*8(%rsi, %rdx),	%r9
+	movq %r8,	0*8(%rdi)
+	movq %r9,	-1*8(%rdi, %rdx)
+	retq
+	.p2align 4
+.Lless_8bytes:
+	cmpq $4,	%rdx
+	jb   .Lless_3bytes
 
+	/*
+	 * Move data from 4 bytes to 7 bytes.
+	 */
+	movl (%rsi), %ecx
+	movl -4(%rsi, %rdx), %r8d
+	movl %ecx, (%rdi)
+	movl %r8d, -4(%rdi, %rdx)
+	retq
 	.p2align 4
+.Lless_3bytes:
+	cmpl $0, %edx
+	je .Lend
+	/*
+	 * Move data from 1 bytes to 3 bytes.
+	 */
 .Lloop_1:
 	movb (%rsi), %r8b
 	movb %r8b, (%rdi)
 	incq %rdi
 	incq %rsi
-	decl %ecx
+	decl %edx
 	jnz .Lloop_1
 
 .Lend:
-	ret
+	retq
 	CFI_ENDPROC
 ENDPROC(memcpy)
 ENDPROC(__memcpy)
diff -druN linux-libre-2.6.36-gnu/arch/x86/lib/memmove_64.c linux-libre-2.6.37-gnu/arch/x86/lib/memmove_64.c
--- linux-libre-2.6.36-gnu/arch/x86/lib/memmove_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/lib/memmove_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,14 +8,185 @@
 #undef memmove
 void *memmove(void *dest, const void *src, size_t count)
 {
-	if (dest < src) {
-		return memcpy(dest, src, count);
-	} else {
-		char *p = dest + count;
-		const char *s = src + count;
-		while (count--)
-			*--p = *--s;
-	}
-	return dest;
+	unsigned long d0,d1,d2,d3,d4,d5,d6,d7;
+	char *ret;
+
+	__asm__ __volatile__(
+		/* Handle more 32bytes in loop */
+		"mov %2, %3\n\t"
+		"cmp $0x20, %0\n\t"
+		"jb	1f\n\t"
+
+		/* Decide forward/backward copy mode */
+		"cmp %2, %1\n\t"
+		"jb	2f\n\t"
+
+		/*
+		 * movsq instruction have many startup latency
+		 * so we handle small size by general register.
+		 */
+		"cmp  $680, %0\n\t"
+		"jb 3f\n\t"
+		/*
+		 * movsq instruction is only good for aligned case.
+		 */
+		"cmpb %%dil, %%sil\n\t"
+		"je 4f\n\t"
+		"3:\n\t"
+		"sub $0x20, %0\n\t"
+		/*
+		 * We gobble 32byts forward in each loop.
+		 */
+		"5:\n\t"
+		"sub $0x20, %0\n\t"
+		"movq 0*8(%1), %4\n\t"
+		"movq 1*8(%1), %5\n\t"
+		"movq 2*8(%1), %6\n\t"
+		"movq 3*8(%1), %7\n\t"
+		"leaq 4*8(%1), %1\n\t"
+
+		"movq %4, 0*8(%2)\n\t"
+		"movq %5, 1*8(%2)\n\t"
+		"movq %6, 2*8(%2)\n\t"
+		"movq %7, 3*8(%2)\n\t"
+		"leaq 4*8(%2), %2\n\t"
+		"jae 5b\n\t"
+		"addq $0x20, %0\n\t"
+		"jmp 1f\n\t"
+		/*
+		 * Handle data forward by movsq.
+		 */
+		".p2align 4\n\t"
+		"4:\n\t"
+		"movq %0, %8\n\t"
+		"movq -8(%1, %0), %4\n\t"
+		"lea -8(%2, %0), %5\n\t"
+		"shrq $3, %8\n\t"
+		"rep movsq\n\t"
+		"movq %4, (%5)\n\t"
+		"jmp 13f\n\t"
+		/*
+		 * Handle data backward by movsq.
+		 */
+		".p2align 4\n\t"
+		"7:\n\t"
+		"movq %0, %8\n\t"
+		"movq (%1), %4\n\t"
+		"movq %2, %5\n\t"
+		"leaq -8(%1, %0), %1\n\t"
+		"leaq -8(%2, %0), %2\n\t"
+		"shrq $3, %8\n\t"
+		"std\n\t"
+		"rep movsq\n\t"
+		"cld\n\t"
+		"movq %4, (%5)\n\t"
+		"jmp 13f\n\t"
+
+		/*
+		 * Start to prepare for backward copy.
+		 */
+		".p2align 4\n\t"
+		"2:\n\t"
+		"cmp $680, %0\n\t"
+		"jb 6f \n\t"
+		"cmp %%dil, %%sil\n\t"
+		"je 7b \n\t"
+		"6:\n\t"
+		/*
+		 * Calculate copy position to tail.
+		 */
+		"addq %0, %1\n\t"
+		"addq %0, %2\n\t"
+		"subq $0x20, %0\n\t"
+		/*
+		 * We gobble 32byts backward in each loop.
+		 */
+		"8:\n\t"
+		"subq $0x20, %0\n\t"
+		"movq -1*8(%1), %4\n\t"
+		"movq -2*8(%1), %5\n\t"
+		"movq -3*8(%1), %6\n\t"
+		"movq -4*8(%1), %7\n\t"
+		"leaq -4*8(%1), %1\n\t"
+
+		"movq %4, -1*8(%2)\n\t"
+		"movq %5, -2*8(%2)\n\t"
+		"movq %6, -3*8(%2)\n\t"
+		"movq %7, -4*8(%2)\n\t"
+		"leaq -4*8(%2), %2\n\t"
+		"jae 8b\n\t"
+		/*
+		 * Calculate copy position to head.
+		 */
+		"addq $0x20, %0\n\t"
+		"subq %0, %1\n\t"
+		"subq %0, %2\n\t"
+		"1:\n\t"
+		"cmpq $16, %0\n\t"
+		"jb 9f\n\t"
+		/*
+		 * Move data from 16 bytes to 31 bytes.
+		 */
+		"movq 0*8(%1), %4\n\t"
+		"movq 1*8(%1), %5\n\t"
+		"movq -2*8(%1, %0), %6\n\t"
+		"movq -1*8(%1, %0), %7\n\t"
+		"movq %4, 0*8(%2)\n\t"
+		"movq %5, 1*8(%2)\n\t"
+		"movq %6, -2*8(%2, %0)\n\t"
+		"movq %7, -1*8(%2, %0)\n\t"
+		"jmp 13f\n\t"
+		".p2align 4\n\t"
+		"9:\n\t"
+		"cmpq $8, %0\n\t"
+		"jb 10f\n\t"
+		/*
+		 * Move data from 8 bytes to 15 bytes.
+		 */
+		"movq 0*8(%1), %4\n\t"
+		"movq -1*8(%1, %0), %5\n\t"
+		"movq %4, 0*8(%2)\n\t"
+		"movq %5, -1*8(%2, %0)\n\t"
+		"jmp 13f\n\t"
+		"10:\n\t"
+		"cmpq $4, %0\n\t"
+		"jb 11f\n\t"
+		/*
+		 * Move data from 4 bytes to 7 bytes.
+		 */
+		"movl (%1), %4d\n\t"
+		"movl -4(%1, %0), %5d\n\t"
+		"movl %4d, (%2)\n\t"
+		"movl %5d, -4(%2, %0)\n\t"
+		"jmp 13f\n\t"
+		"11:\n\t"
+		"cmp $2, %0\n\t"
+		"jb 12f\n\t"
+		/*
+		 * Move data from 2 bytes to 3 bytes.
+		 */
+		"movw (%1), %4w\n\t"
+		"movw -2(%1, %0), %5w\n\t"
+		"movw %4w, (%2)\n\t"
+		"movw %5w, -2(%2, %0)\n\t"
+		"jmp 13f\n\t"
+		"12:\n\t"
+		"cmp $1, %0\n\t"
+		"jb 13f\n\t"
+		/*
+		 * Move data for 1 byte.
+		 */
+		"movb (%1), %4b\n\t"
+		"movb %4b, (%2)\n\t"
+		"13:\n\t"
+		: "=&d" (d0), "=&S" (d1), "=&D" (d2), "=&a" (ret) ,
+		  "=r"(d3), "=r"(d4), "=r"(d5), "=r"(d6), "=&c" (d7)
+		:"0" (count),
+		 "1" (src),
+		 "2" (dest)
+		:"memory");
+
+		return ret;
+
 }
 EXPORT_SYMBOL(memmove);
diff -druN linux-libre-2.6.36-gnu/arch/x86/Makefile linux-libre-2.6.37-gnu/arch/x86/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -96,8 +96,12 @@
 # is .cfi_signal_frame supported too?
 cfi-sigframe := $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1)
 cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTIONS=1)
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections)
+
+# does binutils support specific instructions?
+asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/Makefile_32.cpu linux-libre-2.6.37-gnu/arch/x86/Makefile_32.cpu
--- linux-libre-2.6.36-gnu/arch/x86/Makefile_32.cpu	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/Makefile_32.cpu	2011-01-04 19:50:19.000000000 -0500
@@ -51,7 +51,18 @@
 # prologue (push %ebp, mov %esp, %ebp) which breaks the function graph
 # tracer assumptions. For i686, generic, core2 this is set by the
 # compiler anyway
-cflags-$(CONFIG_FUNCTION_GRAPH_TRACER) += $(call cc-option,-maccumulate-outgoing-args)
+ifeq ($(CONFIG_FUNCTION_GRAPH_TRACER), y)
+ADD_ACCUMULATE_OUTGOING_ARGS := y
+endif
+
+# Work around to a bug with asm goto with first implementations of it
+# in gcc causing gcc to mess up the push and pop of the stack in some
+# uses of asm goto.
+ifeq ($(CONFIG_JUMP_LABEL), y)
+ADD_ACCUMULATE_OUTGOING_ARGS := y
+endif
+
+cflags-$(ADD_ACCUMULATE_OUTGOING_ARGS) += $(call cc-option,-maccumulate-outgoing-args)
 
 # Bug fix for binutils: this option is required in order to keep
 # binutils from generating NOPL instructions against our will.
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/fault.c linux-libre-2.6.37-gnu/arch/x86/mm/fault.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/fault.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/fault.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/kprobes.h>		/* __kprobes, ...		*/
 #include <linux/mmiotrace.h>		/* kmmio_handler, ...		*/
 #include <linux/perf_event.h>		/* perf_sw_event		*/
+#include <linux/hugetlb.h>		/* hstate_index_to_shift	*/
 
 #include <asm/traps.h>			/* dotraplinkage, ...		*/
 #include <asm/pgalloc.h>		/* pgd_*(), ...			*/
@@ -160,15 +161,20 @@
 
 static void
 force_sig_info_fault(int si_signo, int si_code, unsigned long address,
-		     struct task_struct *tsk)
+		     struct task_struct *tsk, int fault)
 {
+	unsigned lsb = 0;
 	siginfo_t info;
 
 	info.si_signo	= si_signo;
 	info.si_errno	= 0;
 	info.si_code	= si_code;
 	info.si_addr	= (void __user *)address;
-	info.si_addr_lsb = si_code == BUS_MCEERR_AR ? PAGE_SHIFT : 0;
+	if (fault & VM_FAULT_HWPOISON_LARGE)
+		lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); 
+	if (fault & VM_FAULT_HWPOISON)
+		lsb = PAGE_SHIFT;
+	info.si_addr_lsb = lsb;
 
 	force_sig_info(si_signo, &info, tsk);
 }
@@ -229,7 +235,16 @@
 
 		spin_lock_irqsave(&pgd_lock, flags);
 		list_for_each_entry(page, &pgd_list, lru) {
-			if (!vmalloc_sync_one(page_address(page), address))
+			spinlock_t *pgt_lock;
+			pmd_t *ret;
+
+			pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
+
+			spin_lock(pgt_lock);
+			ret = vmalloc_sync_one(page_address(page), address);
+			spin_unlock(pgt_lock);
+
+			if (!ret)
 				break;
 		}
 		spin_unlock_irqrestore(&pgd_lock, flags);
@@ -251,6 +266,8 @@
 	if (!(address >= VMALLOC_START && address < VMALLOC_END))
 		return -1;
 
+	WARN_ON_ONCE(in_nmi());
+
 	/*
 	 * Synchronize this task's top level page-table
 	 * with the 'reference' page table.
@@ -326,29 +343,7 @@
 
 void vmalloc_sync_all(void)
 {
-	unsigned long address;
-
-	for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
-	     address += PGDIR_SIZE) {
-
-		const pgd_t *pgd_ref = pgd_offset_k(address);
-		unsigned long flags;
-		struct page *page;
-
-		if (pgd_none(*pgd_ref))
-			continue;
-
-		spin_lock_irqsave(&pgd_lock, flags);
-		list_for_each_entry(page, &pgd_list, lru) {
-			pgd_t *pgd;
-			pgd = (pgd_t *)page_address(page) + pgd_index(address);
-			if (pgd_none(*pgd))
-				set_pgd(pgd, *pgd_ref);
-			else
-				BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
-		}
-		spin_unlock_irqrestore(&pgd_lock, flags);
-	}
+	sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
 }
 
 /*
@@ -369,6 +364,8 @@
 	if (!(address >= VMALLOC_START && address < VMALLOC_END))
 		return -1;
 
+	WARN_ON_ONCE(in_nmi());
+
 	/*
 	 * Copy kernel mappings over when needed. This can also
 	 * happen within a race in page table update. In the later
@@ -731,7 +728,7 @@
 		tsk->thread.error_code	= error_code | (address >= TASK_SIZE);
 		tsk->thread.trap_no	= 14;
 
-		force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+		force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
 
 		return;
 	}
@@ -816,14 +813,14 @@
 	tsk->thread.trap_no	= 14;
 
 #ifdef CONFIG_MEMORY_FAILURE
-	if (fault & VM_FAULT_HWPOISON) {
+	if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
 		printk(KERN_ERR
 	"MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",
 			tsk->comm, tsk->pid, address);
 		code = BUS_MCEERR_AR;
 	}
 #endif
-	force_sig_info_fault(SIGBUS, code, address, tsk);
+	force_sig_info_fault(SIGBUS, code, address, tsk, fault);
 }
 
 static noinline void
@@ -833,7 +830,8 @@
 	if (fault & VM_FAULT_OOM) {
 		out_of_memory(regs, error_code, address);
 	} else {
-		if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON))
+		if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+			     VM_FAULT_HWPOISON_LARGE))
 			do_sigbus(regs, error_code, address, fault);
 		else
 			BUG();
@@ -894,8 +892,14 @@
 	if (pmd_large(*pmd))
 		return spurious_fault_check(error_code, (pte_t *) pmd);
 
+	/*
+	 * Note: don't use pte_present() here, since it returns true
+	 * if the _PAGE_PROTNONE bit is set.  However, this aliases the
+	 * _PAGE_GLOBAL bit, which for kernel pages give false positives
+	 * when CONFIG_DEBUG_PAGEALLOC is used.
+	 */
 	pte = pte_offset_kernel(pmd, address);
-	if (!pte_present(*pte))
+	if (!(pte_flags(*pte) & _PAGE_PRESENT))
 		return 0;
 
 	ret = spurious_fault_check(error_code, pte);
@@ -915,9 +919,9 @@
 int show_unhandled_signals = 1;
 
 static inline int
-access_error(unsigned long error_code, int write, struct vm_area_struct *vma)
+access_error(unsigned long error_code, struct vm_area_struct *vma)
 {
-	if (write) {
+	if (error_code & PF_WRITE) {
 		/* write, present and write, not present: */
 		if (unlikely(!(vma->vm_flags & VM_WRITE)))
 			return 1;
@@ -952,8 +956,10 @@
 	struct task_struct *tsk;
 	unsigned long address;
 	struct mm_struct *mm;
-	int write;
 	int fault;
+	int write = error_code & PF_WRITE;
+	unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+					(write ? FAULT_FLAG_WRITE : 0);
 
 	tsk = current;
 	mm = tsk->mm;
@@ -1064,6 +1070,7 @@
 			bad_area_nosemaphore(regs, error_code, address);
 			return;
 		}
+retry:
 		down_read(&mm->mmap_sem);
 	} else {
 		/*
@@ -1107,9 +1114,7 @@
 	 * we can handle it..
 	 */
 good_area:
-	write = error_code & PF_WRITE;
-
-	if (unlikely(access_error(error_code, write, vma))) {
+	if (unlikely(access_error(error_code, vma))) {
 		bad_area_access_error(regs, error_code, address);
 		return;
 	}
@@ -1119,21 +1124,34 @@
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault:
 	 */
-	fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0);
+	fault = handle_mm_fault(mm, vma, address, flags);
 
 	if (unlikely(fault & VM_FAULT_ERROR)) {
 		mm_fault_error(regs, error_code, address, fault);
 		return;
 	}
 
-	if (fault & VM_FAULT_MAJOR) {
-		tsk->maj_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
-				     regs, address);
-	} else {
-		tsk->min_flt++;
-		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
-				     regs, address);
+	/*
+	 * Major/minor page fault accounting is only done on the
+	 * initial attempt. If we go through a retry, it is extremely
+	 * likely that the page will be found in page cache at that point.
+	 */
+	if (flags & FAULT_FLAG_ALLOW_RETRY) {
+		if (fault & VM_FAULT_MAJOR) {
+			tsk->maj_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+				      regs, address);
+		} else {
+			tsk->min_flt++;
+			perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+				      regs, address);
+		}
+		if (fault & VM_FAULT_RETRY) {
+			/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+			 * of starvation. */
+			flags &= ~FAULT_FLAG_ALLOW_RETRY;
+			goto retry;
+		}
 	}
 
 	check_v8086_mode(regs, address, tsk);
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/highmem_32.c linux-libre-2.6.37-gnu/arch/x86/mm/highmem_32.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/highmem_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/highmem_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,7 @@
 		return page_address(page);
 	return kmap_high(page);
 }
+EXPORT_SYMBOL(kmap);
 
 void kunmap(struct page *page)
 {
@@ -18,6 +19,7 @@
 		return;
 	kunmap_high(page);
 }
+EXPORT_SYMBOL(kunmap);
 
 /*
  * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because
@@ -27,10 +29,10 @@
  * However when holding an atomic kmap it is not legal to sleep, so atomic
  * kmaps are appropriate for short, tight code paths only.
  */
-void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot(struct page *page, pgprot_t prot)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	/* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
 	pagefault_disable();
@@ -38,8 +40,7 @@
 	if (!PageHighMem(page))
 		return page_address(page);
 
-	debug_kmap_atomic(type);
-
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 	BUG_ON(!pte_none(*(kmap_pte-idx)));
@@ -47,44 +48,57 @@
 
 	return (void *)vaddr;
 }
+EXPORT_SYMBOL(kmap_atomic_prot);
 
-void *kmap_atomic(struct page *page, enum km_type type)
+void *__kmap_atomic(struct page *page)
 {
-	return kmap_atomic_prot(page, type, kmap_prot);
+	return kmap_atomic_prot(page, kmap_prot);
 }
+EXPORT_SYMBOL(__kmap_atomic);
 
-void kunmap_atomic_notypecheck(void *kvaddr, enum km_type type)
+/*
+ * This is the same as kmap_atomic() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_pfn(unsigned long pfn)
+{
+	return kmap_atomic_prot_pfn(pfn, kmap_prot);
+}
+EXPORT_SYMBOL_GPL(kmap_atomic_pfn);
+
+void __kunmap_atomic(void *kvaddr)
 {
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
-	/*
-	 * Force other mappings to Oops if they'll try to access this pte
-	 * without first remap it.  Keeping stale mappings around is a bad idea
-	 * also, in case the page changes cacheability attributes or becomes
-	 * a protected page in a hypervisor.
-	 */
-	if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+	if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+	    vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+		int idx, type;
+
+		type = kmap_atomic_idx();
+		idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+		WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+		/*
+		 * Force other mappings to Oops if they'll try to access this
+		 * pte without first remap it.  Keeping stale mappings around
+		 * is a bad idea also, in case the page changes cacheability
+		 * attributes or becomes a protected page in a hypervisor.
+		 */
 		kpte_clear_flush(kmap_pte-idx, vaddr);
-	else {
+		kmap_atomic_idx_pop();
+	}
 #ifdef CONFIG_DEBUG_HIGHMEM
+	else {
 		BUG_ON(vaddr < PAGE_OFFSET);
 		BUG_ON(vaddr >= (unsigned long)high_memory);
-#endif
 	}
+#endif
 
 	pagefault_enable();
 }
-
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
-{
-	return kmap_atomic_prot_pfn(pfn, type, kmap_prot);
-}
-EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
+EXPORT_SYMBOL(__kunmap_atomic);
 
 struct page *kmap_atomic_to_page(void *ptr)
 {
@@ -98,12 +112,6 @@
 	pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
 	return pte_page(*pte);
 }
-
-EXPORT_SYMBOL(kmap);
-EXPORT_SYMBOL(kunmap);
-EXPORT_SYMBOL(kmap_atomic);
-EXPORT_SYMBOL(kunmap_atomic_notypecheck);
-EXPORT_SYMBOL(kmap_atomic_prot);
 EXPORT_SYMBOL(kmap_atomic_to_page);
 
 void __init set_highmem_pages_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/init_32.c linux-libre-2.6.37-gnu/arch/x86/mm/init_32.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/init_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/init_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/proc_fs.h>
 #include <linux/memory_hotplug.h>
 #include <linux/initrd.h>
@@ -67,7 +68,7 @@
 		panic("alloc_low_page: ran out of memory");
 
 	adr = __va(pfn * PAGE_SIZE);
-	memset(adr, 0, PAGE_SIZE);
+	clear_page(adr);
 	return adr;
 }
 
@@ -422,49 +423,28 @@
 	totalhigh_pages++;
 }
 
-struct add_highpages_data {
-	unsigned long start_pfn;
-	unsigned long end_pfn;
-};
-
-static int __init add_highpages_work_fn(unsigned long start_pfn,
-					 unsigned long end_pfn, void *datax)
+void __init add_highpages_with_active_regions(int nid,
+			 unsigned long start_pfn, unsigned long end_pfn)
 {
-	int node_pfn;
-	struct page *page;
-	unsigned long final_start_pfn, final_end_pfn;
-	struct add_highpages_data *data;
+	struct range *range;
+	int nr_range;
+	int i;
 
-	data = (struct add_highpages_data *)datax;
+	nr_range = __get_free_all_memory_range(&range, nid, start_pfn, end_pfn);
 
-	final_start_pfn = max(start_pfn, data->start_pfn);
-	final_end_pfn = min(end_pfn, data->end_pfn);
-	if (final_start_pfn >= final_end_pfn)
-		return 0;
+	for (i = 0; i < nr_range; i++) {
+		struct page *page;
+		int node_pfn;
 
-	for (node_pfn = final_start_pfn; node_pfn < final_end_pfn;
-	     node_pfn++) {
-		if (!pfn_valid(node_pfn))
-			continue;
-		page = pfn_to_page(node_pfn);
-		add_one_highpage_init(page);
+		for (node_pfn = range[i].start; node_pfn < range[i].end;
+		     node_pfn++) {
+			if (!pfn_valid(node_pfn))
+				continue;
+			page = pfn_to_page(node_pfn);
+			add_one_highpage_init(page);
+		}
 	}
-
-	return 0;
-
 }
-
-void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn,
-					      unsigned long end_pfn)
-{
-	struct add_highpages_data data;
-
-	data.start_pfn = start_pfn;
-	data.end_pfn = end_pfn;
-
-	work_with_active_regions(nid, add_highpages_work_fn, &data);
-}
-
 #else
 static inline void permanent_kmaps_init(pgd_t *pgd_base)
 {
@@ -548,48 +528,6 @@
 	permanent_kmaps_init(pgd_base);
 }
 
-#ifdef CONFIG_ACPI_SLEEP
-/*
- * ACPI suspend needs this for resume, because things like the intel-agp
- * driver might have split up a kernel 4MB mapping.
- */
-char swsusp_pg_dir[PAGE_SIZE]
-	__attribute__ ((aligned(PAGE_SIZE)));
-
-static inline void save_pg_dir(void)
-{
-	memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
-}
-#else /* !CONFIG_ACPI_SLEEP */
-static inline void save_pg_dir(void)
-{
-}
-#endif /* !CONFIG_ACPI_SLEEP */
-
-void zap_low_mappings(bool early)
-{
-	int i;
-
-	/*
-	 * Zap initial low-memory mappings.
-	 *
-	 * Note that "pgd_clear()" doesn't do it for
-	 * us, because pgd_clear() is a no-op on i386.
-	 */
-	for (i = 0; i < KERNEL_PGD_BOUNDARY; i++) {
-#ifdef CONFIG_X86_PAE
-		set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
-#else
-		set_pgd(swapper_pg_dir+i, __pgd(0));
-#endif
-	}
-
-	if (early)
-		__flush_tlb();
-	else
-		flush_tlb_all();
-}
-
 pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL | _PAGE_IOMAP);
 EXPORT_SYMBOL_GPL(__supported_pte_mask);
 
@@ -712,14 +650,14 @@
 	highstart_pfn = highend_pfn = max_pfn;
 	if (max_pfn > max_low_pfn)
 		highstart_pfn = max_low_pfn;
-	e820_register_active_regions(0, 0, highend_pfn);
+	memblock_x86_register_active_regions(0, 0, highend_pfn);
 	sparse_memory_present_with_active_regions(0);
 	printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
 		pages_to_mb(highend_pfn - highstart_pfn));
 	num_physpages = highend_pfn;
 	high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-	e820_register_active_regions(0, 0, max_low_pfn);
+	memblock_x86_register_active_regions(0, 0, max_low_pfn);
 	sparse_memory_present_with_active_regions(0);
 	num_physpages = max_low_pfn;
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
@@ -750,68 +688,12 @@
 	free_area_init_nodes(max_zone_pfns);
 }
 
-#ifndef CONFIG_NO_BOOTMEM
-static unsigned long __init setup_node_bootmem(int nodeid,
-				 unsigned long start_pfn,
-				 unsigned long end_pfn,
-				 unsigned long bootmap)
-{
-	unsigned long bootmap_size;
-
-	/* don't touch min_low_pfn */
-	bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
-					 bootmap >> PAGE_SHIFT,
-					 start_pfn, end_pfn);
-	printk(KERN_INFO "  node %d low ram: %08lx - %08lx\n",
-		nodeid, start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
-	printk(KERN_INFO "  node %d bootmap %08lx - %08lx\n",
-		 nodeid, bootmap, bootmap + bootmap_size);
-	free_bootmem_with_active_regions(nodeid, end_pfn);
-
-	return bootmap + bootmap_size;
-}
-#endif
-
 void __init setup_bootmem_allocator(void)
 {
-#ifndef CONFIG_NO_BOOTMEM
-	int nodeid;
-	unsigned long bootmap_size, bootmap;
-	/*
-	 * Initialize the boot-time allocator (with low memory only):
-	 */
-	bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT;
-	bootmap = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
-				 PAGE_SIZE);
-	if (bootmap == -1L)
-		panic("Cannot find bootmem map of size %ld\n", bootmap_size);
-	reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
-#endif
-
 	printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
 		 max_pfn_mapped<<PAGE_SHIFT);
 	printk(KERN_INFO "  low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
 
-#ifndef CONFIG_NO_BOOTMEM
-	for_each_online_node(nodeid) {
-		 unsigned long start_pfn, end_pfn;
-
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-		start_pfn = node_start_pfn[nodeid];
-		end_pfn = node_end_pfn[nodeid];
-		if (start_pfn > max_low_pfn)
-			continue;
-		if (end_pfn > max_low_pfn)
-			end_pfn = max_low_pfn;
-#else
-		start_pfn = 0;
-		end_pfn = max_low_pfn;
-#endif
-		bootmap = setup_node_bootmem(nodeid, start_pfn, end_pfn,
-						 bootmap);
-	}
-#endif
-
 	after_bootmem = 1;
 }
 
@@ -958,9 +840,6 @@
 
 	if (boot_cpu_data.wp_works_ok < 0)
 		test_wp_bit();
-
-	save_pg_dir();
-	zap_low_mappings(true);
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
@@ -1070,8 +949,3 @@
 }
 #endif
 
-int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
-				   int flags)
-{
-	return reserve_bootmem(phys, len, flags);
-}
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/init_64.c linux-libre-2.6.37-gnu/arch/x86/mm/init_64.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/init_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/init_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/initrd.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include <linux/pfn.h>
@@ -50,9 +51,6 @@
 #include <asm/numa.h>
 #include <asm/cacheflush.h>
 #include <asm/init.h>
-#include <linux/bootmem.h>
-
-static unsigned long dma_reserve __initdata;
 
 static int __init parse_direct_gbpages_off(char *arg)
 {
@@ -98,6 +96,43 @@
 __setup("noexec32=", nonx32_setup);
 
 /*
+ * When memory was added/removed make sure all the processes MM have
+ * suitable PGD entries in the local PGD level page.
+ */
+void sync_global_pgds(unsigned long start, unsigned long end)
+{
+	unsigned long address;
+
+	for (address = start; address <= end; address += PGDIR_SIZE) {
+		const pgd_t *pgd_ref = pgd_offset_k(address);
+		unsigned long flags;
+		struct page *page;
+
+		if (pgd_none(*pgd_ref))
+			continue;
+
+		spin_lock_irqsave(&pgd_lock, flags);
+		list_for_each_entry(page, &pgd_list, lru) {
+			pgd_t *pgd;
+			spinlock_t *pgt_lock;
+
+			pgd = (pgd_t *)page_address(page) + pgd_index(address);
+			pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
+			spin_lock(pgt_lock);
+
+			if (pgd_none(*pgd))
+				set_pgd(pgd, *pgd_ref);
+			else
+				BUG_ON(pgd_page_vaddr(*pgd)
+				       != pgd_page_vaddr(*pgd_ref));
+
+			spin_unlock(pgt_lock);
+		}
+		spin_unlock_irqrestore(&pgd_lock, flags);
+	}
+}
+
+/*
  * NOTE: This function is marked __ref because it calls __init function
  * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0.
  */
@@ -293,7 +328,7 @@
 		panic("alloc_low_page: ran out of memory");
 
 	adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
-	memset(adr, 0, PAGE_SIZE);
+	clear_page(adr);
 	*phys  = pfn * PAGE_SIZE;
 	return adr;
 }
@@ -534,11 +569,13 @@
 			     unsigned long end,
 			     unsigned long page_size_mask)
 {
-
+	bool pgd_changed = false;
 	unsigned long next, last_map_addr = end;
+	unsigned long addr;
 
 	start = (unsigned long)__va(start);
 	end = (unsigned long)__va(end);
+	addr = start;
 
 	for (; start < end; start = next) {
 		pgd_t *pgd = pgd_offset_k(start);
@@ -563,7 +600,12 @@
 		spin_lock(&init_mm.page_table_lock);
 		pgd_populate(&init_mm, pgd, __va(pud_phys));
 		spin_unlock(&init_mm.page_table_lock);
+		pgd_changed = true;
 	}
+
+	if (pgd_changed)
+		sync_global_pgds(addr, end);
+
 	__flush_tlb_all();
 
 	return last_map_addr;
@@ -573,23 +615,7 @@
 void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
 				int acpi, int k8)
 {
-#ifndef CONFIG_NO_BOOTMEM
-	unsigned long bootmap_size, bootmap;
-
-	bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
-	bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
-				 PAGE_SIZE);
-	if (bootmap == -1L)
-		panic("Cannot find bootmem map of size %ld\n", bootmap_size);
-	reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
-	/* don't touch min_low_pfn */
-	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
-					 0, end_pfn);
-	e820_register_active_regions(0, start_pfn, end_pfn);
-	free_bootmem_with_active_regions(0, end_pfn);
-#else
-	e820_register_active_regions(0, start_pfn, end_pfn);
-#endif
+	memblock_x86_register_active_regions(0, start_pfn, end_pfn);
 }
 #endif
 
@@ -799,52 +825,6 @@
 
 #endif
 
-int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
-				   int flags)
-{
-#ifdef CONFIG_NUMA
-	int nid, next_nid;
-	int ret;
-#endif
-	unsigned long pfn = phys >> PAGE_SHIFT;
-
-	if (pfn >= max_pfn) {
-		/*
-		 * This can happen with kdump kernels when accessing
-		 * firmware tables:
-		 */
-		if (pfn < max_pfn_mapped)
-			return -EFAULT;
-
-		printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %lu\n",
-				phys, len);
-		return -EFAULT;
-	}
-
-	/* Should check here against the e820 map to avoid double free */
-#ifdef CONFIG_NUMA
-	nid = phys_to_nid(phys);
-	next_nid = phys_to_nid(phys + len - 1);
-	if (nid == next_nid)
-		ret = reserve_bootmem_node(NODE_DATA(nid), phys, len, flags);
-	else
-		ret = reserve_bootmem(phys, len, flags);
-
-	if (ret != 0)
-		return ret;
-
-#else
-	reserve_bootmem(phys, len, flags);
-#endif
-
-	if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
-		dma_reserve += len / PAGE_SIZE;
-		set_dma_reserve(dma_reserve);
-	}
-
-	return 0;
-}
-
 int kern_addr_valid(unsigned long addr)
 {
 	unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
@@ -1003,6 +983,7 @@
 		}
 
 	}
+	sync_global_pgds((unsigned long)start_page, end);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/init.c linux-libre-2.6.37-gnu/arch/x86/mm/init.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/init.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/init.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,7 @@
 #include <linux/initrd.h>
 #include <linux/ioport.h>
 #include <linux/swap.h>
+#include <linux/memblock.h>
 
 #include <asm/cacheflush.h>
 #include <asm/e820.h>
@@ -33,6 +34,7 @@
 					  int use_gbpages)
 {
 	unsigned long puds, pmds, ptes, tables, start;
+	phys_addr_t base;
 
 	puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
 	tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
@@ -75,12 +77,12 @@
 #else
 	start = 0x8000;
 #endif
-	e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+	base = memblock_find_in_range(start, max_pfn_mapped<<PAGE_SHIFT,
 					tables, PAGE_SIZE);
-	if (e820_table_start == -1UL)
+	if (base == MEMBLOCK_ERROR)
 		panic("Cannot find space for the kernel page tables");
 
-	e820_table_start >>= PAGE_SHIFT;
+	e820_table_start = base >> PAGE_SHIFT;
 	e820_table_end = e820_table_start;
 	e820_table_top = e820_table_start + (tables >> PAGE_SHIFT);
 
@@ -299,7 +301,7 @@
 	__flush_tlb_all();
 
 	if (!after_bootmem && e820_table_end > e820_table_start)
-		reserve_early(e820_table_start << PAGE_SHIFT,
+		memblock_x86_reserve_range(e820_table_start << PAGE_SHIFT,
 				 e820_table_end << PAGE_SHIFT, "PGTABLE");
 
 	if (!after_bootmem)
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/iomap_32.c linux-libre-2.6.37-gnu/arch/x86/mm/iomap_32.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/iomap_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/iomap_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,21 +48,20 @@
 }
 EXPORT_SYMBOL_GPL(iomap_create_wc);
 
-void
-iomap_free(resource_size_t base, unsigned long size)
+void iomap_free(resource_size_t base, unsigned long size)
 {
 	io_free_memtype(base, base + size);
 }
 EXPORT_SYMBOL_GPL(iomap_free);
 
-void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
-	enum fixed_addresses idx;
 	unsigned long vaddr;
+	int idx, type;
 
 	pagefault_disable();
 
-	debug_kmap_atomic(type);
+	type = kmap_atomic_idx_push();
 	idx = type + KM_TYPE_NR * smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 	set_pte(kmap_pte - idx, pfn_pte(pfn, prot));
@@ -72,10 +71,10 @@
 }
 
 /*
- * Map 'pfn' using fixed map 'type' and protections 'prot'
+ * Map 'pfn' using protections 'prot'
  */
 void __iomem *
-iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
 {
 	/*
 	 * For non-PAT systems, promote PAGE_KERNEL_WC to PAGE_KERNEL_UC_MINUS.
@@ -86,24 +85,34 @@
 	if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC))
 		prot = PAGE_KERNEL_UC_MINUS;
 
-	return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, type, prot);
+	return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot);
 }
 EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn);
 
 void
-iounmap_atomic(void __iomem *kvaddr, enum km_type type)
+iounmap_atomic(void __iomem *kvaddr)
 {
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
-	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
-	/*
-	 * Force other mappings to Oops if they'll try to access this pte
-	 * without first remap it.  Keeping stale mappings around is a bad idea
-	 * also, in case the page changes cacheability attributes or becomes
-	 * a protected page in a hypervisor.
-	 */
-	if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx))
+	if (vaddr >= __fix_to_virt(FIX_KMAP_END) &&
+	    vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) {
+		int idx, type;
+
+		type = kmap_atomic_idx();
+		idx = type + KM_TYPE_NR * smp_processor_id();
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+		WARN_ON_ONCE(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+#endif
+		/*
+		 * Force other mappings to Oops if they'll try to access this
+		 * pte without first remap it.  Keeping stale mappings around
+		 * is a bad idea also, in case the page changes cacheability
+		 * attributes or becomes a protected page in a hypervisor.
+		 */
 		kpte_clear_flush(kmap_pte-idx, vaddr);
+		kmap_atomic_idx_pop();
+	}
 
 	pagefault_enable();
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/ioremap.c linux-libre-2.6.37-gnu/arch/x86/mm/ioremap.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/ioremap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/ioremap.c	2011-01-04 19:50:19.000000000 -0500
@@ -362,6 +362,11 @@
 	return &bm_pte[pte_index(addr)];
 }
 
+bool __init is_early_ioremap_ptep(pte_t *ptep)
+{
+	return ptep >= &bm_pte[0] && ptep < &bm_pte[PAGE_SIZE/sizeof(pte_t)];
+}
+
 static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;
 
 void __init early_ioremap_init(void)
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/k8topology_64.c linux-libre-2.6.37-gnu/arch/x86/mm/k8topology_64.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/k8topology_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/k8topology_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,8 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/nodemask.h>
+#include <linux/memblock.h>
+
 #include <asm/io.h>
 #include <linux/pci_ids.h>
 #include <linux/acpi.h>
@@ -22,7 +24,7 @@
 #include <asm/numa.h>
 #include <asm/mpspec.h>
 #include <asm/apic.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 static struct bootnode __initdata nodes[8];
 static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
@@ -54,8 +56,8 @@
 static __init void early_get_boot_cpu_id(void)
 {
 	/*
-	 * need to get boot_cpu_id so can use that to create apicid_to_node
-	 * in k8_scan_nodes()
+	 * need to get the APIC ID of the BSP so can use that to
+	 * create apicid_to_node in k8_scan_nodes()
 	 */
 #ifdef CONFIG_X86_MPPARSE
 	/*
@@ -212,7 +214,7 @@
 	bits = boot_cpu_data.x86_coreid_bits;
 	cores = (1<<bits);
 	apicid_base = 0;
-	/* need to get boot_cpu_id early for system with apicid lifting */
+	/* get the APIC ID of the BSP early for systems with apicid lifting */
 	early_get_boot_cpu_id();
 	if (boot_cpu_physical_apicid > 0) {
 		pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
@@ -222,7 +224,7 @@
 	for_each_node_mask(i, node_possible_map) {
 		int j;
 
-		e820_register_active_regions(i,
+		memblock_x86_register_active_regions(i,
 				nodes[i].start >> PAGE_SHIFT,
 				nodes[i].end >> PAGE_SHIFT);
 		for (j = apicid_base; j < cores + apicid_base; j++)
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/kmemcheck/kmemcheck.c linux-libre-2.6.37-gnu/arch/x86/mm/kmemcheck/kmemcheck.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/kmemcheck/kmemcheck.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/kmemcheck/kmemcheck.c	2011-01-04 19:50:19.000000000 -0500
@@ -631,6 +631,8 @@
 	if (!pte)
 		return false;
 
+	WARN_ON_ONCE(in_nmi());
+
 	if (error_code & 2)
 		kmemcheck_access(regs, address, KMEMCHECK_WRITE);
 	else
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/kmemcheck/opcode.c linux-libre-2.6.37-gnu/arch/x86/mm/kmemcheck/opcode.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/kmemcheck/opcode.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/kmemcheck/opcode.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,7 @@
 		b == 0xf0 || b == 0xf2 || b == 0xf3
 		/* Group 2 */
 		|| b == 0x2e || b == 0x36 || b == 0x3e || b == 0x26
-		|| b == 0x64 || b == 0x65 || b == 0x2e || b == 0x3e
+		|| b == 0x64 || b == 0x65
 		/* Group 3 */
 		|| b == 0x66
 		/* Group 4 */
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/Makefile linux-libre-2.6.37-gnu/arch/x86/mm/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/mm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -26,4 +26,6 @@
 obj-$(CONFIG_K8_NUMA)		+= k8topology_64.o
 obj-$(CONFIG_ACPI_NUMA)		+= srat_$(BITS).o
 
+obj-$(CONFIG_HAVE_MEMBLOCK)		+= memblock.o
+
 obj-$(CONFIG_MEMTEST)		+= memtest.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/memblock.c linux-libre-2.6.37-gnu/arch/x86/mm/memblock.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/memblock.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/mm/memblock.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,348 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/memblock.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/range.h>
+
+/* Check for already reserved areas */
+static bool __init check_with_memblock_reserved_size(u64 *addrp, u64 *sizep, u64 align)
+{
+	struct memblock_region *r;
+	u64 addr = *addrp, last;
+	u64 size = *sizep;
+	bool changed = false;
+
+again:
+	last = addr + size;
+	for_each_memblock(reserved, r) {
+		if (last > r->base && addr < r->base) {
+			size = r->base - addr;
+			changed = true;
+			goto again;
+		}
+		if (last > (r->base + r->size) && addr < (r->base + r->size)) {
+			addr = round_up(r->base + r->size, align);
+			size = last - addr;
+			changed = true;
+			goto again;
+		}
+		if (last <= (r->base + r->size) && addr >= r->base) {
+			*sizep = 0;
+			return false;
+		}
+	}
+	if (changed) {
+		*addrp = addr;
+		*sizep = size;
+	}
+	return changed;
+}
+
+/*
+ * Find next free range after start, and size is returned in *sizep
+ */
+u64 __init memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align)
+{
+	struct memblock_region *r;
+
+	for_each_memblock(memory, r) {
+		u64 ei_start = r->base;
+		u64 ei_last = ei_start + r->size;
+		u64 addr;
+
+		addr = round_up(ei_start, align);
+		if (addr < start)
+			addr = round_up(start, align);
+		if (addr >= ei_last)
+			continue;
+		*sizep = ei_last - addr;
+		while (check_with_memblock_reserved_size(&addr, sizep, align))
+			;
+
+		if (*sizep)
+			return addr;
+	}
+
+	return MEMBLOCK_ERROR;
+}
+
+static __init struct range *find_range_array(int count)
+{
+	u64 end, size, mem;
+	struct range *range;
+
+	size = sizeof(struct range) * count;
+	end = memblock.current_limit;
+
+	mem = memblock_find_in_range(0, end, size, sizeof(struct range));
+	if (mem == MEMBLOCK_ERROR)
+		panic("can not find more space for range array");
+
+	/*
+	 * This range is tempoaray, so don't reserve it, it will not be
+	 * overlapped because We will not alloccate new buffer before
+	 * We discard this one
+	 */
+	range = __va(mem);
+	memset(range, 0, size);
+
+	return range;
+}
+
+static void __init memblock_x86_subtract_reserved(struct range *range, int az)
+{
+	u64 final_start, final_end;
+	struct memblock_region *r;
+
+	/* Take out region array itself at first*/
+	memblock_free_reserved_regions();
+
+	memblock_dbg("Subtract (%ld early reservations)\n", memblock.reserved.cnt);
+
+	for_each_memblock(reserved, r) {
+		memblock_dbg("  [%010llx-%010llx]\n", (u64)r->base, (u64)r->base + r->size - 1);
+		final_start = PFN_DOWN(r->base);
+		final_end = PFN_UP(r->base + r->size);
+		if (final_start >= final_end)
+			continue;
+		subtract_range(range, az, final_start, final_end);
+	}
+
+	/* Put region array back ? */
+	memblock_reserve_reserved_regions();
+}
+
+struct count_data {
+	int nr;
+};
+
+static int __init count_work_fn(unsigned long start_pfn,
+				unsigned long end_pfn, void *datax)
+{
+	struct count_data *data = datax;
+
+	data->nr++;
+
+	return 0;
+}
+
+static int __init count_early_node_map(int nodeid)
+{
+	struct count_data data;
+
+	data.nr = 0;
+	work_with_active_regions(nodeid, count_work_fn, &data);
+
+	return data.nr;
+}
+
+int __init __get_free_all_memory_range(struct range **rangep, int nodeid,
+			 unsigned long start_pfn, unsigned long end_pfn)
+{
+	int count;
+	struct range *range;
+	int nr_range;
+
+	count = (memblock.reserved.cnt + count_early_node_map(nodeid)) * 2;
+
+	range = find_range_array(count);
+	nr_range = 0;
+
+	/*
+	 * Use early_node_map[] and memblock.reserved.region to get range array
+	 * at first
+	 */
+	nr_range = add_from_early_node_map(range, count, nr_range, nodeid);
+	subtract_range(range, count, 0, start_pfn);
+	subtract_range(range, count, end_pfn, -1ULL);
+
+	memblock_x86_subtract_reserved(range, count);
+	nr_range = clean_sort_range(range, count);
+
+	*rangep = range;
+	return nr_range;
+}
+
+int __init get_free_all_memory_range(struct range **rangep, int nodeid)
+{
+	unsigned long end_pfn = -1UL;
+
+#ifdef CONFIG_X86_32
+	end_pfn = max_low_pfn;
+#endif
+	return __get_free_all_memory_range(rangep, nodeid, 0, end_pfn);
+}
+
+static u64 __init __memblock_x86_memory_in_range(u64 addr, u64 limit, bool get_free)
+{
+	int i, count;
+	struct range *range;
+	int nr_range;
+	u64 final_start, final_end;
+	u64 free_size;
+	struct memblock_region *r;
+
+	count = (memblock.reserved.cnt + memblock.memory.cnt) * 2;
+
+	range = find_range_array(count);
+	nr_range = 0;
+
+	addr = PFN_UP(addr);
+	limit = PFN_DOWN(limit);
+
+	for_each_memblock(memory, r) {
+		final_start = PFN_UP(r->base);
+		final_end = PFN_DOWN(r->base + r->size);
+		if (final_start >= final_end)
+			continue;
+		if (final_start >= limit || final_end <= addr)
+			continue;
+
+		nr_range = add_range(range, count, nr_range, final_start, final_end);
+	}
+	subtract_range(range, count, 0, addr);
+	subtract_range(range, count, limit, -1ULL);
+
+	/* Subtract memblock.reserved.region in range ? */
+	if (!get_free)
+		goto sort_and_count_them;
+	for_each_memblock(reserved, r) {
+		final_start = PFN_DOWN(r->base);
+		final_end = PFN_UP(r->base + r->size);
+		if (final_start >= final_end)
+			continue;
+		if (final_start >= limit || final_end <= addr)
+			continue;
+
+		subtract_range(range, count, final_start, final_end);
+	}
+
+sort_and_count_them:
+	nr_range = clean_sort_range(range, count);
+
+	free_size = 0;
+	for (i = 0; i < nr_range; i++)
+		free_size += range[i].end - range[i].start;
+
+	return free_size << PAGE_SHIFT;
+}
+
+u64 __init memblock_x86_free_memory_in_range(u64 addr, u64 limit)
+{
+	return __memblock_x86_memory_in_range(addr, limit, true);
+}
+
+u64 __init memblock_x86_memory_in_range(u64 addr, u64 limit)
+{
+	return __memblock_x86_memory_in_range(addr, limit, false);
+}
+
+void __init memblock_x86_reserve_range(u64 start, u64 end, char *name)
+{
+	if (start == end)
+		return;
+
+	if (WARN_ONCE(start > end, "memblock_x86_reserve_range: wrong range [%#llx, %#llx)\n", start, end))
+		return;
+
+	memblock_dbg("    memblock_x86_reserve_range: [%#010llx-%#010llx] %16s\n", start, end - 1, name);
+
+	memblock_reserve(start, end - start);
+}
+
+void __init memblock_x86_free_range(u64 start, u64 end)
+{
+	if (start == end)
+		return;
+
+	if (WARN_ONCE(start > end, "memblock_x86_free_range: wrong range [%#llx, %#llx)\n", start, end))
+		return;
+
+	memblock_dbg("       memblock_x86_free_range: [%#010llx-%#010llx]\n", start, end - 1);
+
+	memblock_free(start, end - start);
+}
+
+/*
+ * Need to call this function after memblock_x86_register_active_regions,
+ * so early_node_map[] is filled already.
+ */
+u64 __init memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align)
+{
+	u64 addr;
+	addr = find_memory_core_early(nid, size, align, start, end);
+	if (addr != MEMBLOCK_ERROR)
+		return addr;
+
+	/* Fallback, should already have start end within node range */
+	return memblock_find_in_range(start, end, size, align);
+}
+
+/*
+ * Finds an active region in the address range from start_pfn to last_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the memblock entry.
+ */
+static int __init memblock_x86_find_active_region(const struct memblock_region *ei,
+				  unsigned long start_pfn,
+				  unsigned long last_pfn,
+				  unsigned long *ei_startpfn,
+				  unsigned long *ei_endpfn)
+{
+	u64 align = PAGE_SIZE;
+
+	*ei_startpfn = round_up(ei->base, align) >> PAGE_SHIFT;
+	*ei_endpfn = round_down(ei->base + ei->size, align) >> PAGE_SHIFT;
+
+	/* Skip map entries smaller than a page */
+	if (*ei_startpfn >= *ei_endpfn)
+		return 0;
+
+	/* Skip if map is outside the node */
+	if (*ei_endpfn <= start_pfn || *ei_startpfn >= last_pfn)
+		return 0;
+
+	/* Check for overlaps */
+	if (*ei_startpfn < start_pfn)
+		*ei_startpfn = start_pfn;
+	if (*ei_endpfn > last_pfn)
+		*ei_endpfn = last_pfn;
+
+	return 1;
+}
+
+/* Walk the memblock.memory map and register active regions within a node */
+void __init memblock_x86_register_active_regions(int nid, unsigned long start_pfn,
+					 unsigned long last_pfn)
+{
+	unsigned long ei_startpfn;
+	unsigned long ei_endpfn;
+	struct memblock_region *r;
+
+	for_each_memblock(memory, r)
+		if (memblock_x86_find_active_region(r, start_pfn, last_pfn,
+					   &ei_startpfn, &ei_endpfn))
+			add_active_range(nid, ei_startpfn, ei_endpfn);
+}
+
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+u64 __init memblock_x86_hole_size(u64 start, u64 end)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long last_pfn = end >> PAGE_SHIFT;
+	unsigned long ei_startpfn, ei_endpfn, ram = 0;
+	struct memblock_region *r;
+
+	for_each_memblock(memory, r)
+		if (memblock_x86_find_active_region(r, start_pfn, last_pfn,
+					   &ei_startpfn, &ei_endpfn))
+			ram += ei_endpfn - ei_startpfn;
+
+	return end - start - ((u64)ram << PAGE_SHIFT);
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/memtest.c linux-libre-2.6.37-gnu/arch/x86/mm/memtest.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/memtest.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/memtest.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,8 +6,7 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/pfn.h>
-
-#include <asm/e820.h>
+#include <linux/memblock.h>
 
 static u64 patterns[] __initdata = {
 	0,
@@ -35,7 +34,7 @@
 	       (unsigned long long) pattern,
 	       (unsigned long long) start_bad,
 	       (unsigned long long) end_bad);
-	reserve_early(start_bad, end_bad, "BAD RAM");
+	memblock_x86_reserve_range(start_bad, end_bad, "BAD RAM");
 }
 
 static void __init memtest(u64 pattern, u64 start_phys, u64 size)
@@ -74,7 +73,7 @@
 	u64 size = 0;
 
 	while (start < end) {
-		start = find_e820_area_size(start, &size, 1);
+		start = memblock_x86_find_in_range_size(start, &size, 1);
 
 		/* done ? */
 		if (start >= end)
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/numa_32.c linux-libre-2.6.37-gnu/arch/x86/mm/numa_32.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/numa_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/numa_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
 
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/highmem.h>
 #include <linux/initrd.h>
@@ -120,7 +121,7 @@
 
 	node_start_pfn[0] = 0;
 	node_end_pfn[0] = max_pfn;
-	e820_register_active_regions(0, 0, max_pfn);
+	memblock_x86_register_active_regions(0, 0, max_pfn);
 	memory_present(0, 0, max_pfn);
 	node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
 
@@ -161,14 +162,14 @@
 		NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
 	else {
 		unsigned long pgdat_phys;
-		pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+		pgdat_phys = memblock_find_in_range(min_low_pfn<<PAGE_SHIFT,
 				 max_pfn_mapped<<PAGE_SHIFT,
 				 sizeof(pg_data_t),
 				 PAGE_SIZE);
 		NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
 		memset(buf, 0, sizeof(buf));
 		sprintf(buf, "NODE_DATA %d",  nid);
-		reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
+		memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
 	}
 	printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
 		nid, (unsigned long)NODE_DATA(nid));
@@ -291,15 +292,15 @@
 						 PTRS_PER_PTE);
 		node_kva_target <<= PAGE_SHIFT;
 		do {
-			node_kva_final = find_e820_area(node_kva_target,
+			node_kva_final = memblock_find_in_range(node_kva_target,
 					((u64)node_end_pfn[nid])<<PAGE_SHIFT,
 						((u64)size)<<PAGE_SHIFT,
 						LARGE_PAGE_BYTES);
 			node_kva_target -= LARGE_PAGE_BYTES;
-		} while (node_kva_final == -1ULL &&
+		} while (node_kva_final == MEMBLOCK_ERROR &&
 			 (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
 
-		if (node_kva_final == -1ULL)
+		if (node_kva_final == MEMBLOCK_ERROR)
 			panic("Can not get kva ram\n");
 
 		node_remap_size[nid] = size;
@@ -318,15 +319,13 @@
 		 *  but we could have some hole in high memory, and it will only
 		 *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
 		 *  to use it as free.
-		 *  So reserve_early here, hope we don't run out of that array
+		 *  So memblock_x86_reserve_range here, hope we don't run out of that array
 		 */
-		reserve_early(node_kva_final,
+		memblock_x86_reserve_range(node_kva_final,
 			      node_kva_final+(((u64)size)<<PAGE_SHIFT),
 			      "KVA RAM");
 
 		node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
-		remove_active_range(nid, node_remap_start_pfn[nid],
-					 node_remap_start_pfn[nid] + size);
 	}
 	printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
 			reserve_pages);
@@ -367,14 +366,14 @@
 
 	kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
 	do {
-		kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
+		kva_start_pfn = memblock_find_in_range(kva_target_pfn<<PAGE_SHIFT,
 					max_low_pfn<<PAGE_SHIFT,
 					kva_pages<<PAGE_SHIFT,
 					PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
 		kva_target_pfn -= PTRS_PER_PTE;
-	} while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn);
+	} while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn);
 
-	if (kva_start_pfn == -1UL)
+	if (kva_start_pfn == MEMBLOCK_ERROR)
 		panic("Can not get kva space\n");
 
 	printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
@@ -382,7 +381,7 @@
 	printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
 
 	/* avoid clash with initrd */
-	reserve_early(kva_start_pfn<<PAGE_SHIFT,
+	memblock_x86_reserve_range(kva_start_pfn<<PAGE_SHIFT,
 		      (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
 		     "KVA PG");
 #ifdef CONFIG_HIGHMEM
@@ -419,9 +418,6 @@
 	for_each_online_node(nid) {
 		memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
 		NODE_DATA(nid)->node_id = nid;
-#ifndef CONFIG_NO_BOOTMEM
-		NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
-#endif
 	}
 
 	setup_bootmem_allocator();
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/numa_64.c linux-libre-2.6.37-gnu/arch/x86/mm/numa_64.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/numa_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/numa_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
@@ -18,7 +19,7 @@
 #include <asm/dma.h>
 #include <asm/numa.h>
 #include <asm/acpi.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
@@ -86,16 +87,16 @@
 
 	addr = 0x8000;
 	nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
-	nodemap_addr = find_e820_area(addr, max_pfn<<PAGE_SHIFT,
+	nodemap_addr = memblock_find_in_range(addr, max_pfn<<PAGE_SHIFT,
 				      nodemap_size, L1_CACHE_BYTES);
-	if (nodemap_addr == -1UL) {
+	if (nodemap_addr == MEMBLOCK_ERROR) {
 		printk(KERN_ERR
 		       "NUMA: Unable to allocate Memory to Node hash map\n");
 		nodemap_addr = nodemap_size = 0;
 		return -1;
 	}
 	memnodemap = phys_to_virt(nodemap_addr);
-	reserve_early(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
+	memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
 
 	printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
 	       nodemap_addr, nodemap_addr + nodemap_size);
@@ -171,18 +172,15 @@
 	if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
 	    end > (MAX_DMA32_PFN<<PAGE_SHIFT))
 		start = MAX_DMA32_PFN<<PAGE_SHIFT;
-	mem = find_e820_area(start, end, size, align);
-	if (mem != -1L)
+	mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align);
+	if (mem != MEMBLOCK_ERROR)
 		return __va(mem);
 
 	/* extend the search scope */
 	end = max_pfn_mapped << PAGE_SHIFT;
-	if (end > (MAX_DMA32_PFN<<PAGE_SHIFT))
-		start = MAX_DMA32_PFN<<PAGE_SHIFT;
-	else
-		start = MAX_DMA_PFN<<PAGE_SHIFT;
-	mem = find_e820_area(start, end, size, align);
-	if (mem != -1L)
+	start = MAX_DMA_PFN << PAGE_SHIFT;
+	mem = memblock_find_in_range(start, end, size, align);
+	if (mem != MEMBLOCK_ERROR)
 		return __va(mem);
 
 	printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
@@ -198,10 +196,6 @@
 	unsigned long start_pfn, last_pfn, nodedata_phys;
 	const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
 	int nid;
-#ifndef CONFIG_NO_BOOTMEM
-	unsigned long bootmap_start, bootmap_pages, bootmap_size;
-	void *bootmap;
-#endif
 
 	if (!end)
 		return;
@@ -226,7 +220,7 @@
 	if (node_data[nodeid] == NULL)
 		return;
 	nodedata_phys = __pa(node_data[nodeid]);
-	reserve_early(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
+	memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
 	printk(KERN_INFO "  NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
 		nodedata_phys + pgdat_size - 1);
 	nid = phys_to_nid(nodedata_phys);
@@ -238,47 +232,6 @@
 	NODE_DATA(nodeid)->node_start_pfn = start_pfn;
 	NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn;
 
-#ifndef CONFIG_NO_BOOTMEM
-	NODE_DATA(nodeid)->bdata = &bootmem_node_data[nodeid];
-
-	/*
-	 * Find a place for the bootmem map
-	 * nodedata_phys could be on other nodes by alloc_bootmem,
-	 * so need to sure bootmap_start not to be small, otherwise
-	 * early_node_mem will get that with find_e820_area instead
-	 * of alloc_bootmem, that could clash with reserved range
-	 */
-	bootmap_pages = bootmem_bootmap_pages(last_pfn - start_pfn);
-	bootmap_start = roundup(nodedata_phys + pgdat_size, PAGE_SIZE);
-	/*
-	 * SMP_CACHE_BYTES could be enough, but init_bootmem_node like
-	 * to use that to align to PAGE_SIZE
-	 */
-	bootmap = early_node_mem(nodeid, bootmap_start, end,
-				 bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
-	if (bootmap == NULL)  {
-		free_early(nodedata_phys, nodedata_phys + pgdat_size);
-		node_data[nodeid] = NULL;
-		return;
-	}
-	bootmap_start = __pa(bootmap);
-	reserve_early(bootmap_start, bootmap_start+(bootmap_pages<<PAGE_SHIFT),
-			"BOOTMAP");
-
-	bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
-					 bootmap_start >> PAGE_SHIFT,
-					 start_pfn, last_pfn);
-
-	printk(KERN_INFO "  bootmap [%016lx -  %016lx] pages %lx\n",
-		 bootmap_start, bootmap_start + bootmap_size - 1,
-		 bootmap_pages);
-	nid = phys_to_nid(bootmap_start);
-	if (nid != nodeid)
-		printk(KERN_INFO "    bootmap(%d) on node %d\n", nodeid, nid);
-
-	free_bootmem_with_active_regions(nodeid, end);
-#endif
-
 	node_set_online(nodeid);
 }
 
@@ -416,7 +369,7 @@
 		nr_nodes = MAX_NUMNODES;
 	}
 
-	size = (max_addr - addr - e820_hole_size(addr, max_addr)) / nr_nodes;
+	size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
 	/*
 	 * Calculate the number of big nodes that can be allocated as a result
 	 * of consolidating the remainder.
@@ -452,7 +405,7 @@
 			 * non-reserved memory is less than the per-node size.
 			 */
 			while (end - physnodes[i].start -
-				e820_hole_size(physnodes[i].start, end) < size) {
+				memblock_x86_hole_size(physnodes[i].start, end) < size) {
 				end += FAKE_NODE_MIN_SIZE;
 				if (end > physnodes[i].end) {
 					end = physnodes[i].end;
@@ -466,7 +419,7 @@
 			 * this one must extend to the boundary.
 			 */
 			if (end < dma32_end && dma32_end - end -
-			    e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+			    memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
 				end = dma32_end;
 
 			/*
@@ -475,7 +428,7 @@
 			 * physical node.
 			 */
 			if (physnodes[i].end - end -
-			    e820_hole_size(end, physnodes[i].end) < size)
+			    memblock_x86_hole_size(end, physnodes[i].end) < size)
 				end = physnodes[i].end;
 
 			/*
@@ -503,7 +456,7 @@
 {
 	u64 end = start + size;
 
-	while (end - start - e820_hole_size(start, end) < size) {
+	while (end - start - memblock_x86_hole_size(start, end) < size) {
 		end += FAKE_NODE_MIN_SIZE;
 		if (end > max_addr) {
 			end = max_addr;
@@ -532,7 +485,7 @@
 	 * creates a uniform distribution of node sizes across the entire
 	 * machine (but not necessarily over physical nodes).
 	 */
-	min_size = (max_addr - addr - e820_hole_size(addr, max_addr)) /
+	min_size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) /
 						MAX_NUMNODES;
 	min_size = max(min_size, FAKE_NODE_MIN_SIZE);
 	if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
@@ -565,7 +518,7 @@
 			 * this one must extend to the boundary.
 			 */
 			if (end < dma32_end && dma32_end - end -
-			    e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+			    memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
 				end = dma32_end;
 
 			/*
@@ -574,7 +527,7 @@
 			 * physical node.
 			 */
 			if (physnodes[i].end - end -
-			    e820_hole_size(end, physnodes[i].end) < size)
+			    memblock_x86_hole_size(end, physnodes[i].end) < size)
 				end = physnodes[i].end;
 
 			/*
@@ -638,7 +591,7 @@
 	 */
 	remove_all_active_ranges();
 	for_each_node_mask(i, node_possible_map) {
-		e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+		memblock_x86_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
 						nodes[i].end >> PAGE_SHIFT);
 		setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 	}
@@ -691,7 +644,7 @@
 	node_set(0, node_possible_map);
 	for (i = 0; i < nr_cpu_ids; i++)
 		numa_set_node(i, 0);
-	e820_register_active_regions(0, start_pfn, last_pfn);
+	memblock_x86_register_active_regions(0, start_pfn, last_pfn);
 	setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
 }
 
@@ -703,9 +656,7 @@
 	for_each_online_node(i)
 		pages += free_all_bootmem_node(NODE_DATA(i));
 
-#ifdef CONFIG_NO_BOOTMEM
 	pages += free_all_memory_core_early(MAX_NUMNODES);
-#endif
 
 	return pages;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/pgtable.c linux-libre-2.6.37-gnu/arch/x86/mm/pgtable.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/pgtable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/pgtable.c	2011-01-04 19:50:19.000000000 -0500
@@ -87,7 +87,19 @@
 #define UNSHARED_PTRS_PER_PGD				\
 	(SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
 
-static void pgd_ctor(pgd_t *pgd)
+
+static void pgd_set_mm(pgd_t *pgd, struct mm_struct *mm)
+{
+	BUILD_BUG_ON(sizeof(virt_to_page(pgd)->index) < sizeof(mm));
+	virt_to_page(pgd)->index = (pgoff_t)mm;
+}
+
+struct mm_struct *pgd_page_get_mm(struct page *page)
+{
+	return (struct mm_struct *)page->index;
+}
+
+static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd)
 {
 	/* If the pgd points to a shared pagetable level (either the
 	   ptes in non-PAE, or shared PMD in PAE), then just copy the
@@ -98,15 +110,13 @@
 		clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
 				swapper_pg_dir + KERNEL_PGD_BOUNDARY,
 				KERNEL_PGD_PTRS);
-		paravirt_alloc_pmd_clone(__pa(pgd) >> PAGE_SHIFT,
-					 __pa(swapper_pg_dir) >> PAGE_SHIFT,
-					 KERNEL_PGD_BOUNDARY,
-					 KERNEL_PGD_PTRS);
 	}
 
 	/* list required to sync kernel mapping updates */
-	if (!SHARED_KERNEL_PMD)
+	if (!SHARED_KERNEL_PMD) {
+		pgd_set_mm(pgd, mm);
 		pgd_list_add(pgd);
+	}
 }
 
 static void pgd_dtor(pgd_t *pgd)
@@ -272,7 +282,7 @@
 	 */
 	spin_lock_irqsave(&pgd_lock, flags);
 
-	pgd_ctor(pgd);
+	pgd_ctor(mm, pgd);
 	pgd_prepopulate_pmd(mm, pgd, pmds);
 
 	spin_unlock_irqrestore(&pgd_lock, flags);
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/srat_32.c linux-libre-2.6.37-gnu/arch/x86/mm/srat_32.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/srat_32.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/srat_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
  */
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/acpi.h>
 #include <linux/nodemask.h>
@@ -264,7 +265,7 @@
 		if (node_read_chunk(chunk->nid, chunk))
 			continue;
 
-		e820_register_active_regions(chunk->nid, chunk->start_pfn,
+		memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn,
 					     min(chunk->end_pfn, max_pfn));
 	}
 	/* for out of order entries in SRAT */
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/srat_64.c linux-libre-2.6.37-gnu/arch/x86/mm/srat_64.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/srat_64.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/srat_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/topology.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
 #include <asm/proto.h>
 #include <asm/numa.h>
@@ -98,15 +99,15 @@
 	unsigned long phys;
 
 	length = slit->header.length;
-	phys = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, length,
+	phys = memblock_find_in_range(0, max_pfn_mapped<<PAGE_SHIFT, length,
 		 PAGE_SIZE);
 
-	if (phys == -1L)
+	if (phys == MEMBLOCK_ERROR)
 		panic(" Can not save slit!\n");
 
 	acpi_slit = __va(phys);
 	memcpy(acpi_slit, slit, length);
-	reserve_early(phys, phys + length, "ACPI SLIT");
+	memblock_x86_reserve_range(phys, phys + length, "ACPI SLIT");
 }
 
 /* Callback for Proximity Domain -> x2APIC mapping */
@@ -324,7 +325,7 @@
 			pxmram = 0;
 	}
 
-	e820ram = max_pfn - (e820_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
+	e820ram = max_pfn - (memblock_x86_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
 	/* We seem to lose 3 pages somewhere. Allow 1M of slack. */
 	if ((long)(e820ram - pxmram) >= (1<<(20 - PAGE_SHIFT))) {
 		printk(KERN_ERR
@@ -421,7 +422,7 @@
 	}
 
 	for (i = 0; i < num_node_memblks; i++)
-		e820_register_active_regions(memblk_nodeid[i],
+		memblock_x86_register_active_regions(memblk_nodeid[i],
 				node_memblk_range[i].start >> PAGE_SHIFT,
 				node_memblk_range[i].end >> PAGE_SHIFT);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/mm/tlb.c linux-libre-2.6.37-gnu/arch/x86/mm/tlb.c
--- linux-libre-2.6.36-gnu/arch/x86/mm/tlb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/mm/tlb.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,7 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/cpu.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -52,6 +53,8 @@
    want false sharing in the per cpu data segment. */
 static union smp_flush_state flush_state[NUM_INVALIDATE_TLB_VECTORS];
 
+static DEFINE_PER_CPU_READ_MOSTLY(int, tlb_vector_offset);
+
 /*
  * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
@@ -173,7 +176,7 @@
 	union smp_flush_state *f;
 
 	/* Caller has disabled preemption */
-	sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
+	sender = this_cpu_read(tlb_vector_offset);
 	f = &flush_state[sender];
 
 	/*
@@ -218,6 +221,48 @@
 	flush_tlb_others_ipi(cpumask, mm, va);
 }
 
+static void __cpuinit calculate_tlb_offset(void)
+{
+	int cpu, node, nr_node_vecs, idx = 0;
+	/*
+	 * we are changing tlb_vector_offset for each CPU in runtime, but this
+	 * will not cause inconsistency, as the write is atomic under X86. we
+	 * might see more lock contentions in a short time, but after all CPU's
+	 * tlb_vector_offset are changed, everything should go normal
+	 *
+	 * Note: if NUM_INVALIDATE_TLB_VECTORS % nr_online_nodes !=0, we might
+	 * waste some vectors.
+	 **/
+	if (nr_online_nodes > NUM_INVALIDATE_TLB_VECTORS)
+		nr_node_vecs = 1;
+	else
+		nr_node_vecs = NUM_INVALIDATE_TLB_VECTORS/nr_online_nodes;
+
+	for_each_online_node(node) {
+		int node_offset = (idx % NUM_INVALIDATE_TLB_VECTORS) *
+			nr_node_vecs;
+		int cpu_offset = 0;
+		for_each_cpu(cpu, cpumask_of_node(node)) {
+			per_cpu(tlb_vector_offset, cpu) = node_offset +
+				cpu_offset;
+			cpu_offset++;
+			cpu_offset = cpu_offset % nr_node_vecs;
+		}
+		idx++;
+	}
+}
+
+static int __cpuinit tlb_cpuhp_notify(struct notifier_block *n,
+		unsigned long action, void *hcpu)
+{
+	switch (action & 0xf) {
+	case CPU_ONLINE:
+	case CPU_DEAD:
+		calculate_tlb_offset();
+	}
+	return NOTIFY_OK;
+}
+
 static int __cpuinit init_smp_flush(void)
 {
 	int i;
@@ -225,6 +270,8 @@
 	for (i = 0; i < ARRAY_SIZE(flush_state); i++)
 		raw_spin_lock_init(&flush_state[i].tlbstate_lock);
 
+	calculate_tlb_offset();
+	hotcpu_notifier(tlb_cpuhp_notify, 0);
 	return 0;
 }
 core_initcall(init_smp_flush);
diff -druN linux-libre-2.6.36-gnu/arch/x86/oprofile/backtrace.c linux-libre-2.6.37-gnu/arch/x86/oprofile/backtrace.c
--- linux-libre-2.6.36-gnu/arch/x86/oprofile/backtrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/oprofile/backtrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/stacktrace.h>
+#include <linux/compat.h>
 
 static void backtrace_warning_symbol(void *data, char *msg,
 				     unsigned long symbol)
@@ -48,14 +49,12 @@
 	.walk_stack	= print_context_stack,
 };
 
-struct frame_head {
-	struct frame_head *bp;
-	unsigned long ret;
-} __attribute__((packed));
-
-static struct frame_head *dump_user_backtrace(struct frame_head *head)
+#ifdef CONFIG_COMPAT
+static struct stack_frame_ia32 *
+dump_user_backtrace_32(struct stack_frame_ia32 *head)
 {
-	struct frame_head bufhead[2];
+	struct stack_frame_ia32 bufhead[2];
+	struct stack_frame_ia32 *fp;
 
 	/* Also check accessibility of one struct frame_head beyond */
 	if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
@@ -63,20 +62,66 @@
 	if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
 		return NULL;
 
-	oprofile_add_trace(bufhead[0].ret);
+	fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
+
+	oprofile_add_trace(bufhead[0].return_address);
+
+	/* frame pointers should strictly progress back up the stack
+	* (towards higher addresses) */
+	if (head >= fp)
+		return NULL;
+
+	return fp;
+}
+
+static inline int
+x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
+{
+	struct stack_frame_ia32 *head;
+
+	/* User process is 32-bit */
+	if (!current || !test_thread_flag(TIF_IA32))
+		return 0;
+
+	head = (struct stack_frame_ia32 *) regs->bp;
+	while (depth-- && head)
+		head = dump_user_backtrace_32(head);
+
+	return 1;
+}
+
+#else
+static inline int
+x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
+{
+	return 0;
+}
+#endif /* CONFIG_COMPAT */
+
+static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
+{
+	struct stack_frame bufhead[2];
+
+	/* Also check accessibility of one struct stack_frame beyond */
+	if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+		return NULL;
+	if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+		return NULL;
+
+	oprofile_add_trace(bufhead[0].return_address);
 
 	/* frame pointers should strictly progress back up the stack
 	 * (towards higher addresses) */
-	if (head >= bufhead[0].bp)
+	if (head >= bufhead[0].next_frame)
 		return NULL;
 
-	return bufhead[0].bp;
+	return bufhead[0].next_frame;
 }
 
 void
 x86_backtrace(struct pt_regs * const regs, unsigned int depth)
 {
-	struct frame_head *head = (struct frame_head *)frame_pointer(regs);
+	struct stack_frame *head = (struct stack_frame *)frame_pointer(regs);
 
 	if (!user_mode_vm(regs)) {
 		unsigned long stack = kernel_stack_pointer(regs);
@@ -86,6 +131,9 @@
 		return;
 	}
 
+	if (x86_backtrace_32(regs, depth))
+		return;
+
 	while (depth-- && head)
 		head = dump_user_backtrace(head);
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/oprofile/nmi_int.c linux-libre-2.6.37-gnu/arch/x86/oprofile/nmi_int.c
--- linux-libre-2.6.36-gnu/arch/x86/oprofile/nmi_int.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/oprofile/nmi_int.c	2011-01-04 19:50:19.000000000 -0500
@@ -695,9 +695,6 @@
 	return 1;
 }
 
-/* in order to get sysfs right */
-static int using_nmi;
-
 int __init op_nmi_init(struct oprofile_operations *ops)
 {
 	__u8 vendor = boot_cpu_data.x86_vendor;
@@ -705,8 +702,6 @@
 	char *cpu_type = NULL;
 	int ret = 0;
 
-	using_nmi = 0;
-
 	if (!cpu_has_apic)
 		return -ENODEV;
 
@@ -731,6 +726,12 @@
 		case 0x11:
 			cpu_type = "x86-64/family11h";
 			break;
+		case 0x12:
+			cpu_type = "x86-64/family12h";
+			break;
+		case 0x14:
+			cpu_type = "x86-64/family14h";
+			break;
 		default:
 			return -ENODEV;
 		}
@@ -790,13 +791,11 @@
 	if (ret)
 		return ret;
 
-	using_nmi = 1;
 	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
 	return 0;
 }
 
 void op_nmi_exit(void)
 {
-	if (using_nmi)
-		exit_sysfs();
+	exit_sysfs();
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/oprofile/op_model_amd.c linux-libre-2.6.37-gnu/arch/x86/oprofile/op_model_amd.c
--- linux-libre-2.6.36-gnu/arch/x86/oprofile/op_model_amd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/oprofile/op_model_amd.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,31 +48,53 @@
 
 static u32 ibs_caps;
 
-struct op_ibs_config {
+struct ibs_config {
 	unsigned long op_enabled;
 	unsigned long fetch_enabled;
 	unsigned long max_cnt_fetch;
 	unsigned long max_cnt_op;
 	unsigned long rand_en;
 	unsigned long dispatched_ops;
+	unsigned long branch_target;
 };
 
-static struct op_ibs_config ibs_config;
-static u64 ibs_op_ctl;
+struct ibs_state {
+	u64		ibs_op_ctl;
+	int		branch_target;
+	unsigned long	sample_size;
+};
+
+static struct ibs_config ibs_config;
+static struct ibs_state ibs_state;
 
 /*
  * IBS cpuid feature detection
  */
 
-#define IBS_CPUID_FEATURES      0x8000001b
+#define IBS_CPUID_FEATURES		0x8000001b
 
 /*
  * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
  * bit 0 is used to indicate the existence of IBS.
  */
-#define IBS_CAPS_AVAIL			(1LL<<0)
-#define IBS_CAPS_RDWROPCNT		(1LL<<3)
-#define IBS_CAPS_OPCNT			(1LL<<4)
+#define IBS_CAPS_AVAIL			(1U<<0)
+#define IBS_CAPS_FETCHSAM		(1U<<1)
+#define IBS_CAPS_OPSAM			(1U<<2)
+#define IBS_CAPS_RDWROPCNT		(1U<<3)
+#define IBS_CAPS_OPCNT			(1U<<4)
+#define IBS_CAPS_BRNTRGT		(1U<<5)
+#define IBS_CAPS_OPCNTEXT		(1U<<6)
+
+#define IBS_CAPS_DEFAULT		(IBS_CAPS_AVAIL		\
+					 | IBS_CAPS_FETCHSAM	\
+					 | IBS_CAPS_OPSAM)
+
+/*
+ * IBS APIC setup
+ */
+#define IBSCTL				0x1cc
+#define IBSCTL_LVT_OFFSET_VALID		(1ULL<<8)
+#define IBSCTL_LVT_OFFSET_MASK		0x0F
 
 /*
  * IBS randomization macros
@@ -92,12 +114,12 @@
 	/* check IBS cpuid feature flags */
 	max_level = cpuid_eax(0x80000000);
 	if (max_level < IBS_CPUID_FEATURES)
-		return IBS_CAPS_AVAIL;
+		return IBS_CAPS_DEFAULT;
 
 	ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
 	if (!(ibs_caps & IBS_CAPS_AVAIL))
 		/* cpuid flags not valid */
-		return IBS_CAPS_AVAIL;
+		return IBS_CAPS_DEFAULT;
 
 	return ibs_caps;
 }
@@ -190,8 +212,8 @@
 		rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
 		if (ctl & IBS_OP_VAL) {
 			rdmsrl(MSR_AMD64_IBSOPRIP, val);
-			oprofile_write_reserve(&entry, regs, val,
-					       IBS_OP_CODE, IBS_OP_SIZE);
+			oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
+					       ibs_state.sample_size);
 			oprofile_add_data64(&entry, val);
 			rdmsrl(MSR_AMD64_IBSOPDATA, val);
 			oprofile_add_data64(&entry, val);
@@ -203,10 +225,14 @@
 			oprofile_add_data64(&entry, val);
 			rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
 			oprofile_add_data64(&entry, val);
+			if (ibs_state.branch_target) {
+				rdmsrl(MSR_AMD64_IBSBRTARGET, val);
+				oprofile_add_data(&entry, (unsigned long)val);
+			}
 			oprofile_write_commit(&entry);
 
 			/* reenable the IRQ */
-			ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
+			ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
 			wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
 		}
 	}
@@ -219,21 +245,32 @@
 	if (!ibs_caps)
 		return;
 
+	memset(&ibs_state, 0, sizeof(ibs_state));
+
+	/*
+	 * Note: Since the max count settings may out of range we
+	 * write back the actual used values so that userland can read
+	 * it.
+	 */
+
 	if (ibs_config.fetch_enabled) {
-		val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
+		val = ibs_config.max_cnt_fetch >> 4;
+		val = min(val, IBS_FETCH_MAX_CNT);
+		ibs_config.max_cnt_fetch = val << 4;
 		val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
 		val |= IBS_FETCH_ENABLE;
 		wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
 	}
 
 	if (ibs_config.op_enabled) {
-		ibs_op_ctl = ibs_config.max_cnt_op >> 4;
+		val = ibs_config.max_cnt_op >> 4;
 		if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
 			/*
 			 * IbsOpCurCnt not supported.  See
 			 * op_amd_randomize_ibs_op() for details.
 			 */
-			ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL);
+			val = clamp(val, 0x0081ULL, 0xFF80ULL);
+			ibs_config.max_cnt_op = val << 4;
 		} else {
 			/*
 			 * The start value is randomized with a
@@ -241,13 +278,24 @@
 			 * with the half of the randomized range. Also
 			 * avoid underflows.
 			 */
-			ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
-					 IBS_OP_MAX_CNT);
+			val += IBS_RANDOM_MAXCNT_OFFSET;
+			if (ibs_caps & IBS_CAPS_OPCNTEXT)
+				val = min(val, IBS_OP_MAX_CNT_EXT);
+			else
+				val = min(val, IBS_OP_MAX_CNT);
+			ibs_config.max_cnt_op =
+				(val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
 		}
-		if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
-			ibs_op_ctl |= IBS_OP_CNT_CTL;
-		ibs_op_ctl |= IBS_OP_ENABLE;
-		val = op_amd_randomize_ibs_op(ibs_op_ctl);
+		val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
+		val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
+		val |= IBS_OP_ENABLE;
+		ibs_state.ibs_op_ctl = val;
+		ibs_state.sample_size = IBS_OP_SIZE;
+		if (ibs_config.branch_target) {
+			ibs_state.branch_target = 1;
+			ibs_state.sample_size++;
+		}
+		val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
 		wrmsrl(MSR_AMD64_IBSOPCTL, val);
 	}
 }
@@ -266,6 +314,70 @@
 		wrmsrl(MSR_AMD64_IBSOPCTL, 0);
 }
 
+static inline int eilvt_is_available(int offset)
+{
+	/* check if we may assign a vector */
+	return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
+}
+
+static inline int ibs_eilvt_valid(void)
+{
+	int offset;
+	u64 val;
+
+	rdmsrl(MSR_AMD64_IBSCTL, val);
+	offset = val & IBSCTL_LVT_OFFSET_MASK;
+
+	if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
+		pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
+		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+		return 0;
+	}
+
+	if (!eilvt_is_available(offset)) {
+		pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
+		       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+		return 0;
+	}
+
+	return 1;
+}
+
+static inline int get_ibs_offset(void)
+{
+	u64 val;
+
+	rdmsrl(MSR_AMD64_IBSCTL, val);
+	if (!(val & IBSCTL_LVT_OFFSET_VALID))
+		return -EINVAL;
+
+	return val & IBSCTL_LVT_OFFSET_MASK;
+}
+
+static void setup_APIC_ibs(void)
+{
+	int offset;
+
+	offset = get_ibs_offset();
+	if (offset < 0)
+		goto failed;
+
+	if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
+		return;
+failed:
+	pr_warn("oprofile: IBS APIC setup failed on cpu #%d\n",
+		smp_processor_id());
+}
+
+static void clear_APIC_ibs(void)
+{
+	int offset;
+
+	offset = get_ibs_offset();
+	if (offset >= 0)
+		setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
+}
+
 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
 
 static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
@@ -376,13 +488,13 @@
 	}
 
 	if (ibs_caps)
-		setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+		setup_APIC_ibs();
 }
 
 static void op_amd_cpu_shutdown(void)
 {
 	if (ibs_caps)
-		setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+		clear_APIC_ibs();
 }
 
 static int op_amd_check_ctrs(struct pt_regs * const regs,
@@ -445,16 +557,11 @@
 	op_amd_stop_ibs();
 }
 
-static int __init_ibs_nmi(void)
+static int setup_ibs_ctl(int ibs_eilvt_off)
 {
-#define IBSCTL_LVTOFFSETVAL		(1 << 8)
-#define IBSCTL				0x1cc
 	struct pci_dev *cpu_cfg;
 	int nodes;
 	u32 value = 0;
-	u8 ibs_eilvt_off;
-
-	ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
 
 	nodes = 0;
 	cpu_cfg = NULL;
@@ -466,39 +573,86 @@
 			break;
 		++nodes;
 		pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
-				       | IBSCTL_LVTOFFSETVAL);
+				       | IBSCTL_LVT_OFFSET_VALID);
 		pci_read_config_dword(cpu_cfg, IBSCTL, &value);
-		if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+		if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
 			pci_dev_put(cpu_cfg);
 			printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
-				"IBSCTL = 0x%08x", value);
-			return 1;
+			       "IBSCTL = 0x%08x\n", value);
+			return -EINVAL;
 		}
 	} while (1);
 
 	if (!nodes) {
-		printk(KERN_DEBUG "No CPU node configured for IBS");
-		return 1;
+		printk(KERN_DEBUG "No CPU node configured for IBS\n");
+		return -ENODEV;
 	}
 
 	return 0;
 }
 
-/* initialize the APIC for the IBS interrupts if available */
+static int force_ibs_eilvt_setup(void)
+{
+	int i;
+	int ret;
+
+	/* find the next free available EILVT entry */
+	for (i = 1; i < 4; i++) {
+		if (!eilvt_is_available(i))
+			continue;
+		ret = setup_ibs_ctl(i);
+		if (ret)
+			return ret;
+		return 0;
+	}
+
+	printk(KERN_DEBUG "No EILVT entry available\n");
+
+	return -EBUSY;
+}
+
+static int __init_ibs_nmi(void)
+{
+	int ret;
+
+	if (ibs_eilvt_valid())
+		return 0;
+
+	ret = force_ibs_eilvt_setup();
+	if (ret)
+		return ret;
+
+	if (!ibs_eilvt_valid())
+		return -EFAULT;
+
+	pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
+
+	return 0;
+}
+
+/*
+ * check and reserve APIC extended interrupt LVT offset for IBS if
+ * available
+ *
+ * init_ibs() preforms implicitly cpu-local operations, so pin this
+ * thread to its current CPU
+ */
+
 static void init_ibs(void)
 {
-	ibs_caps = get_ibs_caps();
+	preempt_disable();
 
+	ibs_caps = get_ibs_caps();
 	if (!ibs_caps)
-		return;
+		goto out;
 
-	if (__init_ibs_nmi()) {
+	if (__init_ibs_nmi() < 0)
 		ibs_caps = 0;
-		return;
-	}
+	else
+		printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
 
-	printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n",
-	       (unsigned)ibs_caps);
+out:
+	preempt_enable();
 }
 
 static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
@@ -521,28 +675,33 @@
 	/* model specific files */
 
 	/* setup some reasonable defaults */
+	memset(&ibs_config, 0, sizeof(ibs_config));
 	ibs_config.max_cnt_fetch = 250000;
-	ibs_config.fetch_enabled = 0;
 	ibs_config.max_cnt_op = 250000;
-	ibs_config.op_enabled = 0;
-	ibs_config.dispatched_ops = 0;
 
-	dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
-	oprofilefs_create_ulong(sb, dir, "enable",
-				&ibs_config.fetch_enabled);
-	oprofilefs_create_ulong(sb, dir, "max_count",
-				&ibs_config.max_cnt_fetch);
-	oprofilefs_create_ulong(sb, dir, "rand_enable",
-				&ibs_config.rand_en);
+	if (ibs_caps & IBS_CAPS_FETCHSAM) {
+		dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
+		oprofilefs_create_ulong(sb, dir, "enable",
+					&ibs_config.fetch_enabled);
+		oprofilefs_create_ulong(sb, dir, "max_count",
+					&ibs_config.max_cnt_fetch);
+		oprofilefs_create_ulong(sb, dir, "rand_enable",
+					&ibs_config.rand_en);
+	}
 
-	dir = oprofilefs_mkdir(sb, root, "ibs_op");
-	oprofilefs_create_ulong(sb, dir, "enable",
-				&ibs_config.op_enabled);
-	oprofilefs_create_ulong(sb, dir, "max_count",
-				&ibs_config.max_cnt_op);
-	if (ibs_caps & IBS_CAPS_OPCNT)
-		oprofilefs_create_ulong(sb, dir, "dispatched_ops",
-					&ibs_config.dispatched_ops);
+	if (ibs_caps & IBS_CAPS_OPSAM) {
+		dir = oprofilefs_mkdir(sb, root, "ibs_op");
+		oprofilefs_create_ulong(sb, dir, "enable",
+					&ibs_config.op_enabled);
+		oprofilefs_create_ulong(sb, dir, "max_count",
+					&ibs_config.max_cnt_op);
+		if (ibs_caps & IBS_CAPS_OPCNT)
+			oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+						&ibs_config.dispatched_ops);
+		if (ibs_caps & IBS_CAPS_BRNTRGT)
+			oprofilefs_create_ulong(sb, dir, "branch_target",
+						&ibs_config.branch_target);
+	}
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/acpi.c linux-libre-2.6.37-gnu/arch/x86/pci/acpi.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/acpi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/acpi.c	2011-01-04 19:50:19.000000000 -0500
@@ -138,7 +138,6 @@
 	struct acpi_resource_address64 addr;
 	acpi_status status;
 	unsigned long flags;
-	struct resource *root, *conflict;
 	u64 start, end;
 
 	status = resource_to_addr(acpi_res, &addr);
@@ -146,12 +145,10 @@
 		return AE_OK;
 
 	if (addr.resource_type == ACPI_MEMORY_RANGE) {
-		root = &iomem_resource;
 		flags = IORESOURCE_MEM;
 		if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
 			flags |= IORESOURCE_PREFETCH;
 	} else if (addr.resource_type == ACPI_IO_RANGE) {
-		root = &ioport_resource;
 		flags = IORESOURCE_IO;
 	} else
 		return AE_OK;
@@ -172,25 +169,90 @@
 		return AE_OK;
 	}
 
-	conflict = insert_resource_conflict(root, res);
-	if (conflict) {
-		dev_err(&info->bridge->dev,
-			"address space collision: host bridge window %pR "
-			"conflicts with %s %pR\n",
-			res, conflict->name, conflict);
-	} else {
-		pci_bus_add_resource(info->bus, res, 0);
-		info->res_num++;
-		if (addr.translation_offset)
-			dev_info(&info->bridge->dev, "host bridge window %pR "
-				 "(PCI address [%#llx-%#llx])\n",
-				 res, res->start - addr.translation_offset,
-				 res->end - addr.translation_offset);
+	info->res_num++;
+	if (addr.translation_offset)
+		dev_info(&info->bridge->dev, "host bridge window %pR "
+			 "(PCI address [%#llx-%#llx])\n",
+			 res, res->start - addr.translation_offset,
+			 res->end - addr.translation_offset);
+	else
+		dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
+
+	return AE_OK;
+}
+
+static bool resource_contains(struct resource *res, resource_size_t point)
+{
+	if (res->start <= point && point <= res->end)
+		return true;
+	return false;
+}
+
+static void coalesce_windows(struct pci_root_info *info, int type)
+{
+	int i, j;
+	struct resource *res1, *res2;
+
+	for (i = 0; i < info->res_num; i++) {
+		res1 = &info->res[i];
+		if (!(res1->flags & type))
+			continue;
+
+		for (j = i + 1; j < info->res_num; j++) {
+			res2 = &info->res[j];
+			if (!(res2->flags & type))
+				continue;
+
+			/*
+			 * I don't like throwing away windows because then
+			 * our resources no longer match the ACPI _CRS, but
+			 * the kernel resource tree doesn't allow overlaps.
+			 */
+			if (resource_contains(res1, res2->start) ||
+			    resource_contains(res1, res2->end) ||
+			    resource_contains(res2, res1->start) ||
+			    resource_contains(res2, res1->end)) {
+				res1->start = min(res1->start, res2->start);
+				res1->end = max(res1->end, res2->end);
+				dev_info(&info->bridge->dev,
+					 "host bridge window expanded to %pR; %pR ignored\n",
+					 res1, res2);
+				res2->flags = 0;
+			}
+		}
+	}
+}
+
+static void add_resources(struct pci_root_info *info)
+{
+	int i;
+	struct resource *res, *root, *conflict;
+
+	if (!pci_use_crs)
+		return;
+
+	coalesce_windows(info, IORESOURCE_MEM);
+	coalesce_windows(info, IORESOURCE_IO);
+
+	for (i = 0; i < info->res_num; i++) {
+		res = &info->res[i];
+
+		if (res->flags & IORESOURCE_MEM)
+			root = &iomem_resource;
+		else if (res->flags & IORESOURCE_IO)
+			root = &ioport_resource;
 		else
-			dev_info(&info->bridge->dev,
-				 "host bridge window %pR\n", res);
+			continue;
+
+		conflict = insert_resource_conflict(root, res);
+		if (conflict)
+			dev_err(&info->bridge->dev,
+				"address space collision: host bridge window %pR "
+				"conflicts with %s %pR\n",
+				res, conflict->name, conflict);
+		else
+			pci_bus_add_resource(info->bus, res, 0);
 	}
-	return AE_OK;
 }
 
 static void
@@ -224,6 +286,7 @@
 	acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
 				&info);
 
+	add_resources(&info);
 	return;
 
 name_alloc_fail:
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/common.c linux-libre-2.6.37-gnu/arch/x86/pci/common.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/common.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/common.c	2011-01-04 19:50:19.000000000 -0500
@@ -421,16 +421,10 @@
 
 	return bus;
 }
-
-int __init pcibios_init(void)
+void __init pcibios_set_cache_line_size(void)
 {
 	struct cpuinfo_x86 *c = &boot_cpu_data;
 
-	if (!raw_pci_ops) {
-		printk(KERN_WARNING "PCI: System does not support PCI\n");
-		return 0;
-	}
-
 	/*
 	 * Set PCI cacheline size to that of the CPU if the CPU has reported it.
 	 * (For older CPUs that don't support cpuid, we se it to 32 bytes
@@ -445,7 +439,16 @@
  		pci_dfl_cache_line_size = 32 >> 2;
 		printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n");
 	}
+}
 
+int __init pcibios_init(void)
+{
+	if (!raw_pci_ops) {
+		printk(KERN_WARNING "PCI: System does not support PCI\n");
+		return 0;
+	}
+
+	pcibios_set_cache_line_size();
 	pcibios_resource_survey();
 
 	if (pci_bf_sort >= pci_force_bf)
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/i386.c linux-libre-2.6.37-gnu/arch/x86/pci/i386.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/i386.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/i386.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,9 +72,6 @@
 			return start;
 		if (start & 0x300)
 			start = (start + 0x3ff) & ~0x3ff;
-	} else if (res->flags & IORESOURCE_MEM) {
-		if (start < BIOS_END)
-			start = BIOS_END;
 	}
 	return start;
 }
@@ -311,6 +308,8 @@
 		 */
 		prot |= _PAGE_CACHE_UC_MINUS;
 
+	prot |= _PAGE_IOMAP;	/* creating a mapping for IO */
+
 	vma->vm_page_prot = __pgprot(prot);
 
 	if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/irq.c linux-libre-2.6.37-gnu/arch/x86/pci/irq.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -584,27 +584,28 @@
 	case PCI_DEVICE_ID_INTEL_ICH9_3:
 	case PCI_DEVICE_ID_INTEL_ICH9_4:
 	case PCI_DEVICE_ID_INTEL_ICH9_5:
-	case PCI_DEVICE_ID_INTEL_TOLAPAI_0:
+	case PCI_DEVICE_ID_INTEL_EP80579_0:
 	case PCI_DEVICE_ID_INTEL_ICH10_0:
 	case PCI_DEVICE_ID_INTEL_ICH10_1:
 	case PCI_DEVICE_ID_INTEL_ICH10_2:
 	case PCI_DEVICE_ID_INTEL_ICH10_3:
+	case PCI_DEVICE_ID_INTEL_PATSBURG_LPC:
 		r->name = "PIIX/ICH";
 		r->get = pirq_piix_get;
 		r->set = pirq_piix_set;
 		return 1;
 	}
 
-	if ((device >= PCI_DEVICE_ID_INTEL_PCH_LPC_MIN) && 
-		(device <= PCI_DEVICE_ID_INTEL_PCH_LPC_MAX)) {
+	if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN) && 
+		(device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)) {
 		r->name = "PIIX/ICH";
 		r->get = pirq_piix_get;
 		r->set = pirq_piix_set;
 		return 1;
 	}
 
-	if ((device >= PCI_DEVICE_ID_INTEL_CPT_LPC_MIN) && 
-		(device <= PCI_DEVICE_ID_INTEL_CPT_LPC_MAX)) {
+	if ((device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN) && 
+		(device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)) {
 		r->name = "PIIX/ICH";
 		r->get = pirq_piix_get;
 		r->set = pirq_piix_set;
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/Makefile linux-libre-2.6.37-gnu/arch/x86/pci/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/pci/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,7 @@
 obj-$(CONFIG_PCI_MMCONFIG)	+= mmconfig_$(BITS).o direct.o mmconfig-shared.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
 obj-$(CONFIG_PCI_OLPC)		+= olpc.o
+obj-$(CONFIG_PCI_XEN)		+= xen.o
 
 obj-y				+= fixup.o
 obj-$(CONFIG_ACPI)		+= acpi.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/mmconfig-shared.c linux-libre-2.6.37-gnu/arch/x86/pci/mmconfig-shared.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/mmconfig-shared.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/mmconfig-shared.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,6 @@
 							int end, u64 addr)
 {
 	struct pci_mmcfg_region *new;
-	int num_buses;
 	struct resource *res;
 
 	if (addr == 0)
@@ -82,10 +81,9 @@
 
 	list_add_sorted(new);
 
-	num_buses = end - start + 1;
 	res = &new->res;
 	res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
-	res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
+	res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
 	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 	snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
 		 "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/olpc.c linux-libre-2.6.37-gnu/arch/x86/pci/olpc.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/olpc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/pci/olpc.c	2011-01-04 19:50:19.000000000 -0500
@@ -304,7 +304,7 @@
 
 int __init pci_olpc_init(void)
 {
-	printk(KERN_INFO "PCI: Using configuration type OLPC\n");
+	printk(KERN_INFO "PCI: Using configuration type OLPC XO-1\n");
 	raw_pci_ops = &pci_olpc_conf;
 	is_lx = is_geode_lx();
 	return 0;
diff -druN linux-libre-2.6.36-gnu/arch/x86/pci/xen.c linux-libre-2.6.37-gnu/arch/x86/pci/xen.c
--- linux-libre-2.6.36-gnu/arch/x86/pci/xen.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/pci/xen.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,429 @@
+/*
+ * Xen PCI Frontend Stub - puts some "dummy" functions in to the Linux
+ *			   x86 PCI core to support the Xen PCI Frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+
+#include <linux/io.h>
+#include <asm/io_apic.h>
+#include <asm/pci_x86.h>
+
+#include <asm/xen/hypervisor.h>
+
+#include <xen/features.h>
+#include <xen/events.h>
+#include <asm/xen/pci.h>
+
+#ifdef CONFIG_ACPI
+static int xen_hvm_register_pirq(u32 gsi, int triggering)
+{
+	int rc, irq;
+	struct physdev_map_pirq map_irq;
+	int shareable = 0;
+	char *name;
+
+	if (!xen_hvm_domain())
+		return -1;
+
+	map_irq.domid = DOMID_SELF;
+	map_irq.type = MAP_PIRQ_TYPE_GSI;
+	map_irq.index = gsi;
+	map_irq.pirq = -1;
+
+	rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+	if (rc) {
+		printk(KERN_WARNING "xen map irq failed %d\n", rc);
+		return -1;
+	}
+
+	if (triggering == ACPI_EDGE_SENSITIVE) {
+		shareable = 0;
+		name = "ioapic-edge";
+	} else {
+		shareable = 1;
+		name = "ioapic-level";
+	}
+
+	irq = xen_map_pirq_gsi(map_irq.pirq, gsi, shareable, name);
+
+	printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq);
+
+	return irq;
+}
+
+static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
+				 int trigger, int polarity)
+{
+	return xen_hvm_register_pirq(gsi, trigger);
+}
+#endif
+
+#if defined(CONFIG_PCI_MSI)
+#include <linux/msi.h>
+#include <asm/msidef.h>
+
+struct xen_pci_frontend_ops *xen_pci_frontend;
+EXPORT_SYMBOL_GPL(xen_pci_frontend);
+
+#define XEN_PIRQ_MSI_DATA  (MSI_DATA_TRIGGER_EDGE | \
+		MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0))
+
+static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
+		struct msi_msg *msg)
+{
+	/* We set vector == 0 to tell the hypervisor we don't care about it,
+	 * but we want a pirq setup instead.
+	 * We use the dest_id field to pass the pirq that we want. */
+	msg->address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(pirq);
+	msg->address_lo =
+		MSI_ADDR_BASE_LO |
+		MSI_ADDR_DEST_MODE_PHYSICAL |
+		MSI_ADDR_REDIRECTION_CPU |
+		MSI_ADDR_DEST_ID(pirq);
+
+	msg->data = XEN_PIRQ_MSI_DATA;
+}
+
+static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	int irq, pirq, ret = 0;
+	struct msi_desc *msidesc;
+	struct msi_msg msg;
+
+	list_for_each_entry(msidesc, &dev->msi_list, list) {
+		__read_msi_msg(msidesc, &msg);
+		pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+			((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+		if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+			xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+					"msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ);
+			if (irq < 0)
+				goto error;
+			ret = set_irq_msi(irq, msidesc);
+			if (ret < 0)
+				goto error_while;
+			printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d"
+					" pirq=%d\n", irq, pirq);
+			return 0;
+		}
+		xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+				"msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ));
+		if (irq < 0 || pirq < 0)
+			goto error;
+		printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
+		xen_msi_compose_msg(dev, pirq, &msg);
+		ret = set_irq_msi(irq, msidesc);
+		if (ret < 0)
+			goto error_while;
+		write_msi_msg(irq, &msg);
+	}
+	return 0;
+
+error_while:
+	unbind_from_irqhandler(irq, NULL);
+error:
+	if (ret == -ENODEV)
+		dev_err(&dev->dev, "Xen PCI frontend has not registered" \
+				" MSI/MSI-X support!\n");
+
+	return ret;
+}
+
+/*
+ * For MSI interrupts we have to use drivers/xen/event.s functions to
+ * allocate an irq_desc and setup the right */
+
+
+static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	int irq, ret, i;
+	struct msi_desc *msidesc;
+	int *v;
+
+	v = kzalloc(sizeof(int) * max(1, nvec), GFP_KERNEL);
+	if (!v)
+		return -ENOMEM;
+
+	if (type == PCI_CAP_ID_MSIX)
+		ret = xen_pci_frontend_enable_msix(dev, &v, nvec);
+	else
+		ret = xen_pci_frontend_enable_msi(dev, &v);
+	if (ret)
+		goto error;
+	i = 0;
+	list_for_each_entry(msidesc, &dev->msi_list, list) {
+		irq = xen_allocate_pirq(v[i], 0, /* not sharable */
+			(type == PCI_CAP_ID_MSIX) ?
+			"pcifront-msi-x" : "pcifront-msi");
+		if (irq < 0) {
+			ret = -1;
+			goto free;
+		}
+
+		ret = set_irq_msi(irq, msidesc);
+		if (ret)
+			goto error_while;
+		i++;
+	}
+	kfree(v);
+	return 0;
+
+error_while:
+	unbind_from_irqhandler(irq, NULL);
+error:
+	if (ret == -ENODEV)
+		dev_err(&dev->dev, "Xen PCI frontend has not registered" \
+			" MSI/MSI-X support!\n");
+free:
+	kfree(v);
+	return ret;
+}
+
+static void xen_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *msidesc;
+
+	msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
+	if (msidesc->msi_attrib.is_msix)
+		xen_pci_frontend_disable_msix(dev);
+	else
+		xen_pci_frontend_disable_msi(dev);
+}
+
+static void xen_teardown_msi_irq(unsigned int irq)
+{
+	xen_destroy_irq(irq);
+}
+
+static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	int irq, ret;
+	struct msi_desc *msidesc;
+
+	list_for_each_entry(msidesc, &dev->msi_list, list) {
+		irq = xen_create_msi_irq(dev, msidesc, type);
+		if (irq < 0)
+			return -1;
+
+		ret = set_irq_msi(irq, msidesc);
+		if (ret)
+			goto error;
+	}
+	return 0;
+
+error:
+	xen_destroy_irq(irq);
+	return ret;
+}
+#endif
+
+static int xen_pcifront_enable_irq(struct pci_dev *dev)
+{
+	int rc;
+	int share = 1;
+
+	dev_info(&dev->dev, "Xen PCI enabling IRQ: %d\n", dev->irq);
+
+	if (dev->irq < 0)
+		return -EINVAL;
+
+	if (dev->irq < NR_IRQS_LEGACY)
+		share = 0;
+
+	rc = xen_allocate_pirq(dev->irq, share, "pcifront");
+	if (rc < 0) {
+		dev_warn(&dev->dev, "Xen PCI IRQ: %d, failed to register:%d\n",
+			 dev->irq, rc);
+		return rc;
+	}
+	return 0;
+}
+
+int __init pci_xen_init(void)
+{
+	if (!xen_pv_domain() || xen_initial_domain())
+		return -ENODEV;
+
+	printk(KERN_INFO "PCI: setting up Xen PCI frontend stub\n");
+
+	pcibios_set_cache_line_size();
+
+	pcibios_enable_irq = xen_pcifront_enable_irq;
+	pcibios_disable_irq = NULL;
+
+#ifdef CONFIG_ACPI
+	/* Keep ACPI out of the picture */
+	acpi_noirq = 1;
+#endif
+
+#ifdef CONFIG_PCI_MSI
+	x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
+	x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+	x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
+#endif
+	return 0;
+}
+
+int __init pci_xen_hvm_init(void)
+{
+	if (!xen_feature(XENFEAT_hvm_pirqs))
+		return 0;
+
+#ifdef CONFIG_ACPI
+	/*
+	 * We don't want to change the actual ACPI delivery model,
+	 * just how GSIs get registered.
+	 */
+	__acpi_register_gsi = acpi_register_gsi_xen_hvm;
+#endif
+
+#ifdef CONFIG_PCI_MSI
+	x86_msi.setup_msi_irqs = xen_hvm_setup_msi_irqs;
+	x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_XEN_DOM0
+static int xen_register_pirq(u32 gsi, int triggering)
+{
+	int rc, irq;
+	struct physdev_map_pirq map_irq;
+	int shareable = 0;
+	char *name;
+
+	if (!xen_pv_domain())
+		return -1;
+
+	if (triggering == ACPI_EDGE_SENSITIVE) {
+		shareable = 0;
+		name = "ioapic-edge";
+	} else {
+		shareable = 1;
+		name = "ioapic-level";
+	}
+
+	irq = xen_allocate_pirq(gsi, shareable, name);
+
+	printk(KERN_DEBUG "xen: --> irq=%d\n", irq);
+
+	if (irq < 0)
+		goto out;
+
+	map_irq.domid = DOMID_SELF;
+	map_irq.type = MAP_PIRQ_TYPE_GSI;
+	map_irq.index = gsi;
+	map_irq.pirq = irq;
+
+	rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+	if (rc) {
+		printk(KERN_WARNING "xen map irq failed %d\n", rc);
+		return -1;
+	}
+
+out:
+	return irq;
+}
+
+static int xen_register_gsi(u32 gsi, int triggering, int polarity)
+{
+	int rc, irq;
+	struct physdev_setup_gsi setup_gsi;
+
+	if (!xen_pv_domain())
+		return -1;
+
+	printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n",
+			gsi, triggering, polarity);
+
+	irq = xen_register_pirq(gsi, triggering);
+
+	setup_gsi.gsi = gsi;
+	setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1);
+	setup_gsi.polarity = (polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
+
+	rc = HYPERVISOR_physdev_op(PHYSDEVOP_setup_gsi, &setup_gsi);
+	if (rc == -EEXIST)
+		printk(KERN_INFO "Already setup the GSI :%d\n", gsi);
+	else if (rc) {
+		printk(KERN_ERR "Failed to setup GSI :%d, err_code:%d\n",
+				gsi, rc);
+	}
+
+	return irq;
+}
+
+static __init void xen_setup_acpi_sci(void)
+{
+	int rc;
+	int trigger, polarity;
+	int gsi = acpi_sci_override_gsi;
+
+	if (!gsi)
+		return;
+
+	rc = acpi_get_override_irq(gsi, &trigger, &polarity);
+	if (rc) {
+		printk(KERN_WARNING "xen: acpi_get_override_irq failed for acpi"
+				" sci, rc=%d\n", rc);
+		return;
+	}
+	trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+	polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
+	
+	printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
+			"polarity=%d\n", gsi, trigger, polarity);
+
+	gsi = xen_register_gsi(gsi, trigger, polarity);
+	printk(KERN_INFO "xen: acpi sci %d\n", gsi);
+
+	return;
+}
+
+static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
+				 int trigger, int polarity)
+{
+	return xen_register_gsi(gsi, trigger, polarity);
+}
+
+static int __init pci_xen_initial_domain(void)
+{
+#ifdef CONFIG_PCI_MSI
+	x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
+	x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
+#endif
+	xen_setup_acpi_sci();
+	__acpi_register_gsi = acpi_register_gsi_xen;
+
+	return 0;
+}
+
+void __init xen_setup_pirqs(void)
+{
+	int irq;
+
+	pci_xen_initial_domain();
+
+	if (0 == nr_ioapics) {
+		for (irq = 0; irq < NR_IRQS_LEGACY; irq++)
+			xen_allocate_pirq(irq, 0, "xt-pic");
+		return;
+	}
+
+	/* Pre-allocate legacy irqs */
+	for (irq = 0; irq < NR_IRQS_LEGACY; irq++) {
+		int trigger, polarity;
+
+		if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
+			continue;
+
+		xen_register_pirq(irq,
+			trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE);
+	}
+}
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_32.c linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_32.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_32.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,112 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version.  --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls.  --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ *	Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/efi.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/efi.h>
+
+/*
+ * To make EFI call EFI runtime service in physical addressing mode we need
+ * prelog/epilog before/after the invocation to disable interrupt, to
+ * claim EFI runtime service handler exclusively and to duplicate a memory in
+ * low memory space say 0 - 3G.
+ */
+
+static unsigned long efi_rt_eflags;
+static pgd_t efi_bak_pg_dir_pointer[2];
+
+void efi_call_phys_prelog(void)
+{
+	unsigned long cr4;
+	unsigned long temp;
+	struct desc_ptr gdt_descr;
+
+	local_irq_save(efi_rt_eflags);
+
+	/*
+	 * If I don't have PAE, I should just duplicate two entries in page
+	 * directory. If I have PAE, I just need to duplicate one entry in
+	 * page directory.
+	 */
+	cr4 = read_cr4_safe();
+
+	if (cr4 & X86_CR4_PAE) {
+		efi_bak_pg_dir_pointer[0].pgd =
+		    swapper_pg_dir[pgd_index(0)].pgd;
+		swapper_pg_dir[0].pgd =
+		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+	} else {
+		efi_bak_pg_dir_pointer[0].pgd =
+		    swapper_pg_dir[pgd_index(0)].pgd;
+		efi_bak_pg_dir_pointer[1].pgd =
+		    swapper_pg_dir[pgd_index(0x400000)].pgd;
+		swapper_pg_dir[pgd_index(0)].pgd =
+		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+		temp = PAGE_OFFSET + 0x400000;
+		swapper_pg_dir[pgd_index(0x400000)].pgd =
+		    swapper_pg_dir[pgd_index(temp)].pgd;
+	}
+
+	/*
+	 * After the lock is released, the original page table is restored.
+	 */
+	__flush_tlb_all();
+
+	gdt_descr.address = __pa(get_cpu_gdt_table(0));
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
+}
+
+void efi_call_phys_epilog(void)
+{
+	unsigned long cr4;
+	struct desc_ptr gdt_descr;
+
+	gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
+	gdt_descr.size = GDT_SIZE - 1;
+	load_gdt(&gdt_descr);
+
+	cr4 = read_cr4_safe();
+
+	if (cr4 & X86_CR4_PAE) {
+		swapper_pg_dir[pgd_index(0)].pgd =
+		    efi_bak_pg_dir_pointer[0].pgd;
+	} else {
+		swapper_pg_dir[pgd_index(0)].pgd =
+		    efi_bak_pg_dir_pointer[0].pgd;
+		swapper_pg_dir[pgd_index(0x400000)].pgd =
+		    efi_bak_pg_dir_pointer[1].pgd;
+	}
+
+	/*
+	 * After the lock is released, the original page table is restored.
+	 */
+	__flush_tlb_all();
+
+	local_irq_restore(efi_rt_eflags);
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_64.c linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_64.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_64.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_64.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,114 @@
+/*
+ * x86_64 specific EFI support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 2005-2008 Intel Co.
+ *	Fenghua Yu <fenghua.yu@intel.com>
+ *	Bibo Mao <bibo.mao@intel.com>
+ *	Chandramouli Narayanan <mouli@linux.intel.com>
+ *	Huang Ying <ying.huang@intel.com>
+ *
+ * Code to convert EFI to E820 map has been implemented in elilo bootloader
+ * based on a EFI patch by Edgar Hucek. Based on the E820 map, the page table
+ * is setup appropriately for EFI runtime code.
+ * - mouli 06/14/2007.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/efi.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/reboot.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/proto.h>
+#include <asm/efi.h>
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+
+static pgd_t save_pgd __initdata;
+static unsigned long efi_flags __initdata;
+
+static void __init early_mapping_set_exec(unsigned long start,
+					  unsigned long end,
+					  int executable)
+{
+	unsigned long num_pages;
+
+	start &= PMD_MASK;
+	end = (end + PMD_SIZE - 1) & PMD_MASK;
+	num_pages = (end - start) >> PAGE_SHIFT;
+	if (executable)
+		set_memory_x((unsigned long)__va(start), num_pages);
+	else
+		set_memory_nx((unsigned long)__va(start), num_pages);
+}
+
+static void __init early_runtime_code_mapping_set_exec(int executable)
+{
+	efi_memory_desc_t *md;
+	void *p;
+
+	if (!(__supported_pte_mask & _PAGE_NX))
+		return;
+
+	/* Make EFI runtime service code area executable */
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if (md->type == EFI_RUNTIME_SERVICES_CODE) {
+			unsigned long end;
+			end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+			early_mapping_set_exec(md->phys_addr, end, executable);
+		}
+	}
+}
+
+void __init efi_call_phys_prelog(void)
+{
+	unsigned long vaddress;
+
+	early_runtime_code_mapping_set_exec(1);
+	local_irq_save(efi_flags);
+	vaddress = (unsigned long)__va(0x0UL);
+	save_pgd = *pgd_offset_k(0x0UL);
+	set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+	__flush_tlb_all();
+}
+
+void __init efi_call_phys_epilog(void)
+{
+	/*
+	 * After the lock is released, the original page table is restored.
+	 */
+	set_pgd(pgd_offset_k(0x0UL), save_pgd);
+	__flush_tlb_all();
+	local_irq_restore(efi_flags);
+	early_runtime_code_mapping_set_exec(0);
+}
+
+void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
+				 u32 type)
+{
+	unsigned long last_map_pfn;
+
+	if (type == EFI_MEMORY_MAPPED_IO)
+		return ioremap(phys_addr, size);
+
+	last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
+	if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
+		return NULL;
+
+	return (void __iomem *)__va(phys_addr);
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi.c linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,613 @@
+/*
+ * Common EFI (Extensible Firmware Interface) support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2005-2008 Intel Co.
+ *	Fenghua Yu <fenghua.yu@intel.com>
+ *	Bibo Mao <bibo.mao@intel.com>
+ *	Chandramouli Narayanan <mouli@linux.intel.com>
+ *	Huang Ying <ying.huang@intel.com>
+ *
+ * Copied from efi_32.c to eliminate the duplicated code between EFI
+ * 32/64 support code. --ying 2007-10-26
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version.  --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls.  --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ *	Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/bootmem.h>
+#include <linux/memblock.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/reboot.h>
+#include <linux/bcd.h>
+
+#include <asm/setup.h>
+#include <asm/efi.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/x86_init.h>
+
+#define EFI_DEBUG	1
+#define PFX 		"EFI: "
+
+int efi_enabled;
+EXPORT_SYMBOL(efi_enabled);
+
+struct efi efi;
+EXPORT_SYMBOL(efi);
+
+struct efi_memory_map memmap;
+
+static struct efi efi_phys __initdata;
+static efi_system_table_t efi_systab __initdata;
+
+static int __init setup_noefi(char *arg)
+{
+	efi_enabled = 0;
+	return 0;
+}
+early_param("noefi", setup_noefi);
+
+int add_efi_memmap;
+EXPORT_SYMBOL(add_efi_memmap);
+
+static int __init setup_add_efi_memmap(char *arg)
+{
+	add_efi_memmap = 1;
+	return 0;
+}
+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)
+{
+	return efi_call_virt2(get_time, tm, tc);
+}
+
+static efi_status_t virt_efi_set_time(efi_time_t *tm)
+{
+	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)
+{
+	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)
+{
+	return efi_call_virt2(set_wakeup_time,
+			      enabled, tm);
+}
+
+static efi_status_t virt_efi_get_variable(efi_char16_t *name,
+					  efi_guid_t *vendor,
+					  u32 *attr,
+					  unsigned long *data_size,
+					  void *data)
+{
+	return efi_call_virt5(get_variable,
+			      name, vendor, attr,
+			      data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
+					       efi_char16_t *name,
+					       efi_guid_t *vendor)
+{
+	return efi_call_virt3(get_next_variable,
+			      name_size, name, vendor);
+}
+
+static efi_status_t virt_efi_set_variable(efi_char16_t *name,
+					  efi_guid_t *vendor,
+					  unsigned long attr,
+					  unsigned long data_size,
+					  void *data)
+{
+	return efi_call_virt5(set_variable,
+			      name, vendor, attr,
+			      data_size, data);
+}
+
+static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
+{
+	return efi_call_virt1(get_next_high_mono_count, count);
+}
+
+static void virt_efi_reset_system(int reset_type,
+				  efi_status_t status,
+				  unsigned long data_size,
+				  efi_char16_t *data)
+{
+	efi_call_virt4(reset_system, reset_type, status,
+		       data_size, data);
+}
+
+static efi_status_t virt_efi_set_virtual_address_map(
+	unsigned long memory_map_size,
+	unsigned long descriptor_size,
+	u32 descriptor_version,
+	efi_memory_desc_t *virtual_map)
+{
+	return efi_call_virt4(set_virtual_address_map,
+			      memory_map_size, descriptor_size,
+			      descriptor_version, virtual_map);
+}
+
+static efi_status_t __init phys_efi_set_virtual_address_map(
+	unsigned long memory_map_size,
+	unsigned long descriptor_size,
+	u32 descriptor_version,
+	efi_memory_desc_t *virtual_map)
+{
+	efi_status_t status;
+
+	efi_call_phys_prelog();
+	status = efi_call_phys4(efi_phys.set_virtual_address_map,
+				memory_map_size, descriptor_size,
+				descriptor_version, virtual_map);
+	efi_call_phys_epilog();
+	return status;
+}
+
+static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
+					     efi_time_cap_t *tc)
+{
+	efi_status_t status;
+
+	efi_call_phys_prelog();
+	status = efi_call_phys2(efi_phys.get_time, tm, tc);
+	efi_call_phys_epilog();
+	return status;
+}
+
+int efi_set_rtc_mmss(unsigned long nowtime)
+{
+	int real_seconds, real_minutes;
+	efi_status_t 	status;
+	efi_time_t 	eft;
+	efi_time_cap_t 	cap;
+
+	status = efi.get_time(&eft, &cap);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+		return -1;
+	}
+
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
+		real_minutes += 30;
+	real_minutes %= 60;
+	eft.minute = real_minutes;
+	eft.second = real_seconds;
+
+	status = efi.set_time(&eft);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR "Oops: efitime: can't write time!\n");
+		return -1;
+	}
+	return 0;
+}
+
+unsigned long efi_get_time(void)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t cap;
+
+	status = efi.get_time(&eft, &cap);
+	if (status != EFI_SUCCESS)
+		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+
+	return mktime(eft.year, eft.month, eft.day, eft.hour,
+		      eft.minute, eft.second);
+}
+
+/*
+ * Tell the kernel about the EFI memory map.  This might include
+ * more than the max 128 entries that can fit in the e820 legacy
+ * (zeropage) memory map.
+ */
+
+static void __init do_add_efi_memmap(void)
+{
+	void *p;
+
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		efi_memory_desc_t *md = p;
+		unsigned long long start = md->phys_addr;
+		unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+		int e820_type;
+
+		switch (md->type) {
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+			if (md->attribute & EFI_MEMORY_WB)
+				e820_type = E820_RAM;
+			else
+				e820_type = E820_RESERVED;
+			break;
+		case EFI_ACPI_RECLAIM_MEMORY:
+			e820_type = E820_ACPI;
+			break;
+		case EFI_ACPI_MEMORY_NVS:
+			e820_type = E820_NVS;
+			break;
+		case EFI_UNUSABLE_MEMORY:
+			e820_type = E820_UNUSABLE;
+			break;
+		default:
+			/*
+			 * EFI_RESERVED_TYPE EFI_RUNTIME_SERVICES_CODE
+			 * EFI_RUNTIME_SERVICES_DATA EFI_MEMORY_MAPPED_IO
+			 * EFI_MEMORY_MAPPED_IO_PORT_SPACE EFI_PAL_CODE
+			 */
+			e820_type = E820_RESERVED;
+			break;
+		}
+		e820_add_region(start, size, e820_type);
+	}
+	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+}
+
+void __init efi_memblock_x86_reserve_range(void)
+{
+	unsigned long pmap;
+
+#ifdef CONFIG_X86_32
+	pmap = boot_params.efi_info.efi_memmap;
+#else
+	pmap = (boot_params.efi_info.efi_memmap |
+		((__u64)boot_params.efi_info.efi_memmap_hi<<32));
+#endif
+	memmap.phys_map = (void *)pmap;
+	memmap.nr_map = boot_params.efi_info.efi_memmap_size /
+		boot_params.efi_info.efi_memdesc_size;
+	memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
+	memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
+	memblock_x86_reserve_range(pmap, pmap + memmap.nr_map * memmap.desc_size,
+		      "EFI memmap");
+}
+
+#if EFI_DEBUG
+static void __init print_efi_memmap(void)
+{
+	efi_memory_desc_t *md;
+	void *p;
+	int i;
+
+	for (p = memmap.map, i = 0;
+	     p < memmap.map_end;
+	     p += memmap.desc_size, i++) {
+		md = p;
+		printk(KERN_INFO PFX "mem%02u: type=%u, attr=0x%llx, "
+			"range=[0x%016llx-0x%016llx) (%lluMB)\n",
+			i, md->type, md->attribute, md->phys_addr,
+			md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT),
+			(md->num_pages >> (20 - EFI_PAGE_SHIFT)));
+	}
+}
+#endif  /*  EFI_DEBUG  */
+
+void __init efi_init(void)
+{
+	efi_config_table_t *config_tables;
+	efi_runtime_services_t *runtime;
+	efi_char16_t *c16;
+	char vendor[100] = "unknown";
+	int i = 0;
+	void *tmp;
+
+#ifdef CONFIG_X86_32
+	efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
+#else
+	efi_phys.systab = (efi_system_table_t *)
+		(boot_params.efi_info.efi_systab |
+		 ((__u64)boot_params.efi_info.efi_systab_hi<<32));
+#endif
+
+	efi.systab = early_ioremap((unsigned long)efi_phys.systab,
+				   sizeof(efi_system_table_t));
+	if (efi.systab == NULL)
+		printk(KERN_ERR "Couldn't map the EFI system table!\n");
+	memcpy(&efi_systab, efi.systab, sizeof(efi_system_table_t));
+	early_iounmap(efi.systab, sizeof(efi_system_table_t));
+	efi.systab = &efi_systab;
+
+	/*
+	 * Verify the EFI Table
+	 */
+	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+		printk(KERN_ERR "EFI system table signature incorrect!\n");
+	if ((efi.systab->hdr.revision >> 16) == 0)
+		printk(KERN_ERR "Warning: EFI system table version "
+		       "%d.%02d, expected 1.00 or greater!\n",
+		       efi.systab->hdr.revision >> 16,
+		       efi.systab->hdr.revision & 0xffff);
+
+	/*
+	 * Show what we know for posterity
+	 */
+	c16 = tmp = early_ioremap(efi.systab->fw_vendor, 2);
+	if (c16) {
+		for (i = 0; i < sizeof(vendor) - 1 && *c16; ++i)
+			vendor[i] = *c16++;
+		vendor[i] = '\0';
+	} else
+		printk(KERN_ERR PFX "Could not map the firmware vendor!\n");
+	early_iounmap(tmp, 2);
+
+	printk(KERN_INFO "EFI v%u.%.02u by %s\n",
+	       efi.systab->hdr.revision >> 16,
+	       efi.systab->hdr.revision & 0xffff, vendor);
+
+	/*
+	 * Let's see what config tables the firmware passed to us.
+	 */
+	config_tables = early_ioremap(
+		efi.systab->tables,
+		efi.systab->nr_tables * sizeof(efi_config_table_t));
+	if (config_tables == NULL)
+		printk(KERN_ERR "Could not map EFI Configuration Table!\n");
+
+	printk(KERN_INFO);
+	for (i = 0; i < efi.systab->nr_tables; i++) {
+		if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
+			efi.mps = config_tables[i].table;
+			printk(" MPS=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					ACPI_20_TABLE_GUID)) {
+			efi.acpi20 = config_tables[i].table;
+			printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					ACPI_TABLE_GUID)) {
+			efi.acpi = config_tables[i].table;
+			printk(" ACPI=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					SMBIOS_TABLE_GUID)) {
+			efi.smbios = config_tables[i].table;
+			printk(" SMBIOS=0x%lx ", config_tables[i].table);
+#ifdef CONFIG_X86_UV
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					UV_SYSTEM_TABLE_GUID)) {
+			efi.uv_systab = config_tables[i].table;
+			printk(" UVsystab=0x%lx ", config_tables[i].table);
+#endif
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					HCDP_TABLE_GUID)) {
+			efi.hcdp = config_tables[i].table;
+			printk(" HCDP=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					UGA_IO_PROTOCOL_GUID)) {
+			efi.uga = config_tables[i].table;
+			printk(" UGA=0x%lx ", config_tables[i].table);
+		}
+	}
+	printk("\n");
+	early_iounmap(config_tables,
+			  efi.systab->nr_tables * sizeof(efi_config_table_t));
+
+	/*
+	 * Check out the runtime services table. We need to map
+	 * the runtime services table so that we can grab the physical
+	 * address of several of the EFI runtime functions, needed to
+	 * set the firmware into virtual mode.
+	 */
+	runtime = early_ioremap((unsigned long)efi.systab->runtime,
+				sizeof(efi_runtime_services_t));
+	if (runtime != NULL) {
+		/*
+		 * We will only need *early* access to the following
+		 * two EFI runtime services before set_virtual_address_map
+		 * is invoked.
+		 */
+		efi_phys.get_time = (efi_get_time_t *)runtime->get_time;
+		efi_phys.set_virtual_address_map =
+			(efi_set_virtual_address_map_t *)
+			runtime->set_virtual_address_map;
+		/*
+		 * Make efi_get_time can be called before entering
+		 * virtual mode.
+		 */
+		efi.get_time = phys_efi_get_time;
+	} else
+		printk(KERN_ERR "Could not map the EFI runtime service "
+		       "table!\n");
+	early_iounmap(runtime, sizeof(efi_runtime_services_t));
+
+	/* Map the EFI memory map */
+	memmap.map = early_ioremap((unsigned long)memmap.phys_map,
+				   memmap.nr_map * memmap.desc_size);
+	if (memmap.map == NULL)
+		printk(KERN_ERR "Could not map the EFI memory map!\n");
+	memmap.map_end = memmap.map + (memmap.nr_map * memmap.desc_size);
+
+	if (memmap.desc_size != sizeof(efi_memory_desc_t))
+		printk(KERN_WARNING
+		  "Kernel-defined memdesc doesn't match the one from EFI!\n");
+
+	if (add_efi_memmap)
+		do_add_efi_memmap();
+
+#ifdef CONFIG_X86_32
+	x86_platform.get_wallclock = efi_get_time;
+	x86_platform.set_wallclock = efi_set_rtc_mmss;
+#endif
+
+	/* Setup for EFI runtime service */
+	reboot_type = BOOT_EFI;
+
+#if EFI_DEBUG
+	print_efi_memmap();
+#endif
+}
+
+static void __init runtime_code_page_mkexec(void)
+{
+	efi_memory_desc_t *md;
+	void *p;
+	u64 addr, npages;
+
+	/* Make EFI runtime service code area executable */
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+
+		if (md->type != EFI_RUNTIME_SERVICES_CODE)
+			continue;
+
+		addr = md->virt_addr;
+		npages = md->num_pages;
+		memrange_efi_to_native(&addr, &npages);
+		set_memory_x(addr, npages);
+	}
+}
+
+/*
+ * This function will switch the EFI runtime services to virtual mode.
+ * Essentially, look through the EFI memmap and map every region that
+ * has the runtime attribute bit set in its memory descriptor and update
+ * that memory descriptor with the virtual address obtained from ioremap().
+ * This enables the runtime services to be called without having to
+ * thunk back into physical mode for every invocation.
+ */
+void __init efi_enter_virtual_mode(void)
+{
+	efi_memory_desc_t *md;
+	efi_status_t status;
+	unsigned long size;
+	u64 end, systab, addr, npages, end_pfn;
+	void *p, *va;
+
+	efi.systab = NULL;
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if (!(md->attribute & EFI_MEMORY_RUNTIME))
+			continue;
+
+		size = md->num_pages << EFI_PAGE_SHIFT;
+		end = md->phys_addr + size;
+
+		end_pfn = PFN_UP(end);
+		if (end_pfn <= max_low_pfn_mapped
+		    || (end_pfn > (1UL << (32 - PAGE_SHIFT))
+			&& end_pfn <= max_pfn_mapped))
+			va = __va(md->phys_addr);
+		else
+			va = efi_ioremap(md->phys_addr, size, md->type);
+
+		md->virt_addr = (u64) (unsigned long) va;
+
+		if (!va) {
+			printk(KERN_ERR PFX "ioremap of 0x%llX failed!\n",
+			       (unsigned long long)md->phys_addr);
+			continue;
+		}
+
+		if (!(md->attribute & EFI_MEMORY_WB)) {
+			addr = md->virt_addr;
+			npages = md->num_pages;
+			memrange_efi_to_native(&addr, &npages);
+			set_memory_uc(addr, npages);
+		}
+
+		systab = (u64) (unsigned long) efi_phys.systab;
+		if (md->phys_addr <= systab && systab < end) {
+			systab += md->virt_addr - md->phys_addr;
+			efi.systab = (efi_system_table_t *) (unsigned long) systab;
+		}
+	}
+
+	BUG_ON(!efi.systab);
+
+	status = phys_efi_set_virtual_address_map(
+		memmap.desc_size * memmap.nr_map,
+		memmap.desc_size,
+		memmap.desc_version,
+		memmap.phys_map);
+
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ALERT "Unable to switch EFI into virtual mode "
+		       "(status=%lx)!\n", status);
+		panic("EFI call to SetVirtualAddressMap() failed!");
+	}
+
+	/*
+	 * Now that EFI is in virtual mode, update the function
+	 * pointers in the runtime service table to the new virtual addresses.
+	 *
+	 * Call EFI services through wrapper functions.
+	 */
+	efi.get_time = virt_efi_get_time;
+	efi.set_time = virt_efi_set_time;
+	efi.get_wakeup_time = virt_efi_get_wakeup_time;
+	efi.set_wakeup_time = virt_efi_set_wakeup_time;
+	efi.get_variable = virt_efi_get_variable;
+	efi.get_next_variable = virt_efi_get_next_variable;
+	efi.set_variable = virt_efi_set_variable;
+	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
+	efi.reset_system = virt_efi_reset_system;
+	efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
+	if (__supported_pte_mask & _PAGE_NX)
+		runtime_code_page_mkexec();
+	early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
+	memmap.map = NULL;
+}
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+u32 efi_mem_type(unsigned long phys_addr)
+{
+	efi_memory_desc_t *md;
+	void *p;
+
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if ((md->phys_addr <= phys_addr) &&
+		    (phys_addr < (md->phys_addr +
+				  (md->num_pages << EFI_PAGE_SHIFT))))
+			return md->type;
+	}
+	return 0;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+	efi_memory_desc_t *md;
+	void *p;
+
+	for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+		md = p;
+		if ((md->phys_addr <= phys_addr) &&
+		    (phys_addr < (md->phys_addr +
+				  (md->num_pages << EFI_PAGE_SHIFT))))
+			return md->attribute;
+	}
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_stub_32.S linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_stub_32.S
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_stub_32.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_stub_32.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,123 @@
+/*
+ * EFI call stub for IA32.
+ *
+ * This stub allows us to make EFI calls in physical mode with interrupts
+ * turned off.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+/*
+ * efi_call_phys(void *, ...) is a function with variable parameters.
+ * All the callers of this function assure that all the parameters are 4-bytes.
+ */
+
+/*
+ * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save.
+ * So we'd better save all of them at the beginning of this function and restore
+ * at the end no matter how many we use, because we can not assure EFI runtime
+ * service functions will comply with gcc calling convention, too.
+ */
+
+.text
+ENTRY(efi_call_phys)
+	/*
+	 * 0. The function can only be called in Linux kernel. So CS has been
+	 * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found
+	 * the values of these registers are the same. And, the corresponding
+	 * GDT entries are identical. So I will do nothing about segment reg
+	 * and GDT, but change GDT base register in prelog and epilog.
+	 */
+
+	/*
+	 * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET.
+	 * But to make it smoothly switch from virtual mode to flat mode.
+	 * The mapping of lower virtual memory has been created in prelog and
+	 * epilog.
+	 */
+	movl	$1f, %edx
+	subl	$__PAGE_OFFSET, %edx
+	jmp	*%edx
+1:
+
+	/*
+	 * 2. Now on the top of stack is the return
+	 * address in the caller of efi_call_phys(), then parameter 1,
+	 * parameter 2, ..., param n. To make things easy, we save the return
+	 * address of efi_call_phys in a global variable.
+	 */
+	popl	%edx
+	movl	%edx, saved_return_addr
+	/* get the function pointer into ECX*/
+	popl	%ecx
+	movl	%ecx, efi_rt_function_ptr
+	movl	$2f, %edx
+	subl	$__PAGE_OFFSET, %edx
+	pushl	%edx
+
+	/*
+	 * 3. Clear PG bit in %CR0.
+	 */
+	movl	%cr0, %edx
+	andl	$0x7fffffff, %edx
+	movl	%edx, %cr0
+	jmp	1f
+1:
+
+	/*
+	 * 4. Adjust stack pointer.
+	 */
+	subl	$__PAGE_OFFSET, %esp
+
+	/*
+	 * 5. Call the physical function.
+	 */
+	jmp	*%ecx
+
+2:
+	/*
+	 * 6. After EFI runtime service returns, control will return to
+	 * following instruction. We'd better readjust stack pointer first.
+	 */
+	addl	$__PAGE_OFFSET, %esp
+
+	/*
+	 * 7. Restore PG bit
+	 */
+	movl	%cr0, %edx
+	orl	$0x80000000, %edx
+	movl	%edx, %cr0
+	jmp	1f
+1:
+	/*
+	 * 8. Now restore the virtual mode from flat mode by
+	 * adding EIP with PAGE_OFFSET.
+	 */
+	movl	$1f, %edx
+	jmp	*%edx
+1:
+
+	/*
+	 * 9. Balance the stack. And because EAX contain the return value,
+	 * we'd better not clobber it.
+	 */
+	leal	efi_rt_function_ptr, %edx
+	movl	(%edx), %ecx
+	pushl	%ecx
+
+	/*
+	 * 10. Push the saved return address onto the stack and return.
+	 */
+	leal	saved_return_addr, %edx
+	movl	(%edx), %ecx
+	pushl	%ecx
+	ret
+ENDPROC(efi_call_phys)
+.previous
+
+.data
+saved_return_addr:
+	.long 0
+efi_rt_function_ptr:
+	.long 0
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_stub_64.S linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_stub_64.S
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/efi_stub_64.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/efi_stub_64.S	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,116 @@
+/*
+ * Function calling ABI conversion from Linux to EFI for x86_64
+ *
+ * Copyright (C) 2007 Intel Corp
+ *	Bibo Mao <bibo.mao@intel.com>
+ *	Huang Ying <ying.huang@intel.com>
+ */
+
+#include <linux/linkage.h>
+
+#define SAVE_XMM			\
+	mov %rsp, %rax;			\
+	subq $0x70, %rsp;		\
+	and $~0xf, %rsp;		\
+	mov %rax, (%rsp);		\
+	mov %cr0, %rax;			\
+	clts;				\
+	mov %rax, 0x8(%rsp);		\
+	movaps %xmm0, 0x60(%rsp);	\
+	movaps %xmm1, 0x50(%rsp);	\
+	movaps %xmm2, 0x40(%rsp);	\
+	movaps %xmm3, 0x30(%rsp);	\
+	movaps %xmm4, 0x20(%rsp);	\
+	movaps %xmm5, 0x10(%rsp)
+
+#define RESTORE_XMM			\
+	movaps 0x60(%rsp), %xmm0;	\
+	movaps 0x50(%rsp), %xmm1;	\
+	movaps 0x40(%rsp), %xmm2;	\
+	movaps 0x30(%rsp), %xmm3;	\
+	movaps 0x20(%rsp), %xmm4;	\
+	movaps 0x10(%rsp), %xmm5;	\
+	mov 0x8(%rsp), %rsi;		\
+	mov %rsi, %cr0;			\
+	mov (%rsp), %rsp
+
+ENTRY(efi_call0)
+	SAVE_XMM
+	subq $32, %rsp
+	call *%rdi
+	addq $32, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call0)
+
+ENTRY(efi_call1)
+	SAVE_XMM
+	subq $32, %rsp
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $32, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call1)
+
+ENTRY(efi_call2)
+	SAVE_XMM
+	subq $32, %rsp
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $32, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call2)
+
+ENTRY(efi_call3)
+	SAVE_XMM
+	subq $32, %rsp
+	mov  %rcx, %r8
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $32, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call3)
+
+ENTRY(efi_call4)
+	SAVE_XMM
+	subq $32, %rsp
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $32, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call4)
+
+ENTRY(efi_call5)
+	SAVE_XMM
+	subq $48, %rsp
+	mov %r9, 32(%rsp)
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $48, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call5)
+
+ENTRY(efi_call6)
+	SAVE_XMM
+	mov (%rsp), %rax
+	mov 8(%rax), %rax
+	subq $48, %rsp
+	mov %r9, 32(%rsp)
+	mov %rax, 40(%rsp)
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $48, %rsp
+	RESTORE_XMM
+	ret
+ENDPROC(efi_call6)
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/efi/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/efi/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/efi/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/efi/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,8 @@
+# Platform specific code goes here
+obj-y	+= efi/
+obj-y	+= mrst/
+obj-y	+= olpc/
+obj-y	+= scx200/
+obj-y	+= sfi/
+obj-y	+= visws/
+obj-y	+= uv/
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/mrst/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/mrst/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/mrst/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/mrst/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_X86_MRST)		+= mrst.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/mrst/mrst.c linux-libre-2.6.37-gnu/arch/x86/platform/mrst/mrst.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/mrst/mrst.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/mrst/mrst.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,311 @@
+/*
+ * mrst.c: Intel Moorestown platform specific setup code
+ *
+ * (C) Copyright 2008 Intel Corporation
+ * Author: Jacob Pan (jacob.jun.pan@intel.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sfi.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+
+#include <asm/setup.h>
+#include <asm/mpspec_def.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
+#include <asm/io_apic.h>
+#include <asm/mrst.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+#include <asm/apb_timer.h>
+
+/*
+ * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
+ * cmdline option x86_mrst_timer can be used to override the configuration
+ * to prefer one or the other.
+ * at runtime, there are basically three timer configurations:
+ * 1. per cpu apbt clock only
+ * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
+ * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
+ *
+ * by default (without cmdline option), platform code first detects cpu type
+ * to see if we are on lincroft or penwell, then set up both lapic or apbt
+ * clocks accordingly.
+ * i.e. by default, medfield uses configuration #2, moorestown uses #1.
+ * config #3 is supported but not recommended on medfield.
+ *
+ * rating and feature summary:
+ * lapic (with C3STOP) --------- 100
+ * apbt (always-on) ------------ 110
+ * lapic (always-on,ARAT) ------ 150
+ */
+
+__cpuinitdata enum mrst_timer_options mrst_timer_options;
+
+static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
+static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
+enum mrst_cpu_type __mrst_cpu_chip;
+EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
+
+int sfi_mtimer_num;
+
+struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
+EXPORT_SYMBOL_GPL(sfi_mrtc_array);
+int sfi_mrtc_num;
+
+static inline void assign_to_mp_irq(struct mpc_intsrc *m,
+				    struct mpc_intsrc *mp_irq)
+{
+	memcpy(mp_irq, m, sizeof(struct mpc_intsrc));
+}
+
+static inline int mp_irq_cmp(struct mpc_intsrc *mp_irq,
+				struct mpc_intsrc *m)
+{
+	return memcmp(mp_irq, m, sizeof(struct mpc_intsrc));
+}
+
+static void save_mp_irq(struct mpc_intsrc *m)
+{
+	int i;
+
+	for (i = 0; i < mp_irq_entries; i++) {
+		if (!mp_irq_cmp(&mp_irqs[i], m))
+			return;
+	}
+
+	assign_to_mp_irq(m, &mp_irqs[mp_irq_entries]);
+	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+		panic("Max # of irq sources exceeded!!\n");
+}
+
+/* parse all the mtimer info to a static mtimer array */
+static int __init sfi_parse_mtmr(struct sfi_table_header *table)
+{
+	struct sfi_table_simple *sb;
+	struct sfi_timer_table_entry *pentry;
+	struct mpc_intsrc mp_irq;
+	int totallen;
+
+	sb = (struct sfi_table_simple *)table;
+	if (!sfi_mtimer_num) {
+		sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb,
+					struct sfi_timer_table_entry);
+		pentry = (struct sfi_timer_table_entry *) sb->pentry;
+		totallen = sfi_mtimer_num * sizeof(*pentry);
+		memcpy(sfi_mtimer_array, pentry, totallen);
+	}
+
+	printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num);
+	pentry = sfi_mtimer_array;
+	for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) {
+		printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz,"
+			" irq = %d\n", totallen, (u32)pentry->phys_addr,
+			pentry->freq_hz, pentry->irq);
+			if (!pentry->irq)
+				continue;
+			mp_irq.type = MP_IOAPIC;
+			mp_irq.irqtype = mp_INT;
+/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
+			mp_irq.irqflag = 5;
+			mp_irq.srcbus = 0;
+			mp_irq.srcbusirq = pentry->irq;	/* IRQ */
+			mp_irq.dstapic = MP_APIC_ALL;
+			mp_irq.dstirq = pentry->irq;
+			save_mp_irq(&mp_irq);
+	}
+
+	return 0;
+}
+
+struct sfi_timer_table_entry *sfi_get_mtmr(int hint)
+{
+	int i;
+	if (hint < sfi_mtimer_num) {
+		if (!sfi_mtimer_usage[hint]) {
+			pr_debug("hint taken for timer %d irq %d\n",\
+				hint, sfi_mtimer_array[hint].irq);
+			sfi_mtimer_usage[hint] = 1;
+			return &sfi_mtimer_array[hint];
+		}
+	}
+	/* take the first timer available */
+	for (i = 0; i < sfi_mtimer_num;) {
+		if (!sfi_mtimer_usage[i]) {
+			sfi_mtimer_usage[i] = 1;
+			return &sfi_mtimer_array[i];
+		}
+		i++;
+	}
+	return NULL;
+}
+
+void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr)
+{
+	int i;
+	for (i = 0; i < sfi_mtimer_num;) {
+		if (mtmr->irq == sfi_mtimer_array[i].irq) {
+			sfi_mtimer_usage[i] = 0;
+			return;
+		}
+		i++;
+	}
+}
+
+/* parse all the mrtc info to a global mrtc array */
+int __init sfi_parse_mrtc(struct sfi_table_header *table)
+{
+	struct sfi_table_simple *sb;
+	struct sfi_rtc_table_entry *pentry;
+	struct mpc_intsrc mp_irq;
+
+	int totallen;
+
+	sb = (struct sfi_table_simple *)table;
+	if (!sfi_mrtc_num) {
+		sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb,
+						struct sfi_rtc_table_entry);
+		pentry = (struct sfi_rtc_table_entry *)sb->pentry;
+		totallen = sfi_mrtc_num * sizeof(*pentry);
+		memcpy(sfi_mrtc_array, pentry, totallen);
+	}
+
+	printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num);
+	pentry = sfi_mrtc_array;
+	for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
+		printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n",
+			totallen, (u32)pentry->phys_addr, pentry->irq);
+		mp_irq.type = MP_IOAPIC;
+		mp_irq.irqtype = mp_INT;
+		mp_irq.irqflag = 0;
+		mp_irq.srcbus = 0;
+		mp_irq.srcbusirq = pentry->irq;	/* IRQ */
+		mp_irq.dstapic = MP_APIC_ALL;
+		mp_irq.dstirq = pentry->irq;
+		save_mp_irq(&mp_irq);
+	}
+	return 0;
+}
+
+static unsigned long __init mrst_calibrate_tsc(void)
+{
+	unsigned long flags, fast_calibrate;
+
+	local_irq_save(flags);
+	fast_calibrate = apbt_quick_calibrate();
+	local_irq_restore(flags);
+
+	if (fast_calibrate)
+		return fast_calibrate;
+
+	return 0;
+}
+
+void __init mrst_time_init(void)
+{
+	switch (mrst_timer_options) {
+	case MRST_TIMER_APBT_ONLY:
+		break;
+	case MRST_TIMER_LAPIC_APBT:
+		x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+		x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+		break;
+	default:
+		if (!boot_cpu_has(X86_FEATURE_ARAT))
+			break;
+		x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+		x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+		return;
+	}
+	/* we need at least one APB timer */
+	sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
+	pre_init_apic_IRQ0();
+	apbt_time_init();
+}
+
+void __init mrst_rtc_init(void)
+{
+	sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
+}
+
+void __cpuinit mrst_arch_setup(void)
+{
+	if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
+		__mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
+	else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
+		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+	else {
+		pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
+			boot_cpu_data.x86, boot_cpu_data.x86_model);
+		__mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+	}
+	pr_debug("Moorestown CPU %s identified\n",
+		(__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
+		"Lincroft" : "Penwell");
+}
+
+/* MID systems don't have i8042 controller */
+static int mrst_i8042_detect(void)
+{
+	return 0;
+}
+
+/*
+ * Moorestown specific x86_init function overrides and early setup
+ * calls.
+ */
+void __init x86_mrst_early_setup(void)
+{
+	x86_init.resources.probe_roms = x86_init_noop;
+	x86_init.resources.reserve_resources = x86_init_noop;
+
+	x86_init.timers.timer_init = mrst_time_init;
+	x86_init.timers.setup_percpu_clockev = x86_init_noop;
+
+	x86_init.irqs.pre_vector_init = x86_init_noop;
+
+	x86_init.oem.arch_setup = mrst_arch_setup;
+
+	x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
+
+	x86_platform.calibrate_tsc = mrst_calibrate_tsc;
+	x86_platform.i8042_detect = mrst_i8042_detect;
+	x86_init.pci.init = pci_mrst_init;
+	x86_init.pci.fixup_irqs = x86_init_noop;
+
+	legacy_pic = &null_legacy_pic;
+
+	/* Avoid searching for BIOS MP tables */
+	x86_init.mpparse.find_smp_config = x86_init_noop;
+	x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+
+}
+
+/*
+ * if user does not want to use per CPU apb timer, just give it a lower rating
+ * than local apic timer and skip the late per cpu timer init.
+ */
+static inline int __init setup_x86_mrst_timer(char *arg)
+{
+	if (!arg)
+		return -EINVAL;
+
+	if (strcmp("apbt_only", arg) == 0)
+		mrst_timer_options = MRST_TIMER_APBT_ONLY;
+	else if (strcmp("lapic_and_apbt", arg) == 0)
+		mrst_timer_options = MRST_TIMER_LAPIC_APBT;
+	else {
+		pr_warning("X86 MRST timer option %s not recognised"
+			   " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
+			   arg);
+		return -EINVAL;
+	}
+	return 0;
+}
+__setup("x86_mrst_timer=", setup_x86_mrst_timer);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/olpc/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/olpc/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/olpc/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/olpc/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,3 @@
+obj-$(CONFIG_OLPC)		+= olpc.o
+obj-$(CONFIG_OLPC_XO1)		+= olpc-xo1.o
+obj-$(CONFIG_OLPC_OPENFIRMWARE)	+= olpc_ofw.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc.c linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,281 @@
+/*
+ * Support for the OLPC DCON and OLPC EC access
+ *
+ * Copyright Â© 2006  Advanced Micro Devices, Inc.
+ * Copyright Â© 2007-2008  Andres Salomon <dilinger@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <asm/geode.h>
+#include <asm/setup.h>
+#include <asm/olpc.h>
+#include <asm/olpc_ofw.h>
+
+struct olpc_platform_t olpc_platform_info;
+EXPORT_SYMBOL_GPL(olpc_platform_info);
+
+static DEFINE_SPINLOCK(ec_lock);
+
+/* what the timeout *should* be (in ms) */
+#define EC_BASE_TIMEOUT 20
+
+/* the timeout that bugs in the EC might force us to actually use */
+static int ec_timeout = EC_BASE_TIMEOUT;
+
+static int __init olpc_ec_timeout_set(char *str)
+{
+	if (get_option(&str, &ec_timeout) != 1) {
+		ec_timeout = EC_BASE_TIMEOUT;
+		printk(KERN_ERR "olpc-ec:  invalid argument to "
+				"'olpc_ec_timeout=', ignoring!\n");
+	}
+	printk(KERN_DEBUG "olpc-ec:  using %d ms delay for EC commands.\n",
+			ec_timeout);
+	return 1;
+}
+__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
+
+/*
+ * These {i,o}bf_status functions return whether the buffers are full or not.
+ */
+
+static inline unsigned int ibf_status(unsigned int port)
+{
+	return !!(inb(port) & 0x02);
+}
+
+static inline unsigned int obf_status(unsigned int port)
+{
+	return inb(port) & 0x01;
+}
+
+#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
+static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
+{
+	unsigned int timeo;
+	int state = ibf_status(port);
+
+	for (timeo = ec_timeout; state != desired && timeo; timeo--) {
+		mdelay(1);
+		state = ibf_status(port);
+	}
+
+	if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
+			timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
+		printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for IBF!\n",
+				line, ec_timeout - timeo);
+	}
+
+	return !(state == desired);
+}
+
+#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
+static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
+{
+	unsigned int timeo;
+	int state = obf_status(port);
+
+	for (timeo = ec_timeout; state != desired && timeo; timeo--) {
+		mdelay(1);
+		state = obf_status(port);
+	}
+
+	if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
+			timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
+		printk(KERN_WARNING "olpc-ec:  %d: waited %u ms for OBF!\n",
+				line, ec_timeout - timeo);
+	}
+
+	return !(state == desired);
+}
+
+/*
+ * This allows the kernel to run Embedded Controller commands.  The EC is
+ * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
+ * available EC commands are here:
+ * <http://wiki.laptop.org/go/Ec_specification>.  Unfortunately, while
+ * OpenFirmware's source is available, the EC's is not.
+ */
+int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
+		unsigned char *outbuf,  size_t outlen)
+{
+	unsigned long flags;
+	int ret = -EIO;
+	int i;
+	int restarts = 0;
+
+	spin_lock_irqsave(&ec_lock, flags);
+
+	/* Clear OBF */
+	for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
+		inb(0x68);
+	if (i == 10) {
+		printk(KERN_ERR "olpc-ec:  timeout while attempting to "
+				"clear OBF flag!\n");
+		goto err;
+	}
+
+	if (wait_on_ibf(0x6c, 0)) {
+		printk(KERN_ERR "olpc-ec:  timeout waiting for EC to "
+				"quiesce!\n");
+		goto err;
+	}
+
+restart:
+	/*
+	 * Note that if we time out during any IBF checks, that's a failure;
+	 * we have to return.  There's no way for the kernel to clear that.
+	 *
+	 * If we time out during an OBF check, we can restart the command;
+	 * reissuing it will clear the OBF flag, and we should be alright.
+	 * The OBF flag will sometimes misbehave due to what we believe
+	 * is a hardware quirk..
+	 */
+	pr_devel("olpc-ec:  running cmd 0x%x\n", cmd);
+	outb(cmd, 0x6c);
+
+	if (wait_on_ibf(0x6c, 0)) {
+		printk(KERN_ERR "olpc-ec:  timeout waiting for EC to read "
+				"command!\n");
+		goto err;
+	}
+
+	if (inbuf && inlen) {
+		/* write data to EC */
+		for (i = 0; i < inlen; i++) {
+			if (wait_on_ibf(0x6c, 0)) {
+				printk(KERN_ERR "olpc-ec:  timeout waiting for"
+						" EC accept data!\n");
+				goto err;
+			}
+			pr_devel("olpc-ec:  sending cmd arg 0x%x\n", inbuf[i]);
+			outb(inbuf[i], 0x68);
+		}
+	}
+	if (outbuf && outlen) {
+		/* read data from EC */
+		for (i = 0; i < outlen; i++) {
+			if (wait_on_obf(0x6c, 1)) {
+				printk(KERN_ERR "olpc-ec:  timeout waiting for"
+						" EC to provide data!\n");
+				if (restarts++ < 10)
+					goto restart;
+				goto err;
+			}
+			outbuf[i] = inb(0x68);
+			pr_devel("olpc-ec:  received 0x%x\n", outbuf[i]);
+		}
+	}
+
+	ret = 0;
+err:
+	spin_unlock_irqrestore(&ec_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_cmd);
+
+static bool __init check_ofw_architecture(void)
+{
+	size_t propsize;
+	char olpc_arch[5];
+	const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 };
+	void *res[] = { &propsize };
+
+	if (olpc_ofw("getprop", args, res)) {
+		printk(KERN_ERR "ofw: getprop call failed!\n");
+		return false;
+	}
+	return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
+}
+
+static u32 __init get_board_revision(void)
+{
+	size_t propsize;
+	__be32 rev;
+	const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 };
+	void *res[] = { &propsize };
+
+	if (olpc_ofw("getprop", args, res) || propsize != 4) {
+		printk(KERN_ERR "ofw: getprop call failed!\n");
+		return cpu_to_be32(0);
+	}
+	return be32_to_cpu(rev);
+}
+
+static bool __init platform_detect(void)
+{
+	if (!check_ofw_architecture())
+		return false;
+	olpc_platform_info.flags |= OLPC_F_PRESENT;
+	olpc_platform_info.boardrev = get_board_revision();
+	return true;
+}
+
+static int __init add_xo1_platform_devices(void)
+{
+	struct platform_device *pdev;
+
+	pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	return 0;
+}
+
+static int __init olpc_init(void)
+{
+	int r = 0;
+
+	if (!olpc_ofw_present() || !platform_detect())
+		return 0;
+
+	spin_lock_init(&ec_lock);
+
+	/* assume B1 and above models always have a DCON */
+	if (olpc_board_at_least(olpc_board(0xb1)))
+		olpc_platform_info.flags |= OLPC_F_DCON;
+
+	/* get the EC revision */
+	olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
+			(unsigned char *) &olpc_platform_info.ecver, 1);
+
+#ifdef CONFIG_PCI_OLPC
+	/* If the VSA exists let it emulate PCI, if not emulate in kernel.
+	 * XO-1 only. */
+	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
+			!cs5535_has_vsa2())
+		x86_init.pci.arch_init = pci_olpc_init;
+#endif
+
+	printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
+			((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
+			olpc_platform_info.boardrev >> 4,
+			olpc_platform_info.ecver);
+
+	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
+		r = add_xo1_platform_devices();
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+postcore_initcall(olpc_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc_ofw.c linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc_ofw.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc_ofw.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc_ofw.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,112 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/olpc_ofw.h>
+
+/* address of OFW callback interface; will be NULL if OFW isn't found */
+static int (*olpc_ofw_cif)(int *);
+
+/* page dir entry containing OFW's pgdir table; filled in by head_32.S */
+u32 olpc_ofw_pgd __initdata;
+
+static DEFINE_SPINLOCK(ofw_lock);
+
+#define MAXARGS 10
+
+void __init setup_olpc_ofw_pgd(void)
+{
+	pgd_t *base, *ofw_pde;
+
+	if (!olpc_ofw_cif)
+		return;
+
+	/* fetch OFW's PDE */
+	base = early_ioremap(olpc_ofw_pgd, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
+	if (!base) {
+		printk(KERN_ERR "failed to remap OFW's pgd - disabling OFW!\n");
+		olpc_ofw_cif = NULL;
+		return;
+	}
+	ofw_pde = &base[OLPC_OFW_PDE_NR];
+
+	/* install OFW's PDE permanently into the kernel's pgtable */
+	set_pgd(&swapper_pg_dir[OLPC_OFW_PDE_NR], *ofw_pde);
+	/* implicit optimization barrier here due to uninline function return */
+
+	early_iounmap(base, sizeof(olpc_ofw_pgd) * PTRS_PER_PGD);
+}
+
+int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
+		void **res)
+{
+	int ofw_args[MAXARGS + 3];
+	unsigned long flags;
+	int ret, i, *p;
+
+	BUG_ON(nr_args + nr_res > MAXARGS);
+
+	if (!olpc_ofw_cif)
+		return -EIO;
+
+	ofw_args[0] = (int)name;
+	ofw_args[1] = nr_args;
+	ofw_args[2] = nr_res;
+
+	p = &ofw_args[3];
+	for (i = 0; i < nr_args; i++, p++)
+		*p = (int)args[i];
+
+	/* call into ofw */
+	spin_lock_irqsave(&ofw_lock, flags);
+	ret = olpc_ofw_cif(ofw_args);
+	spin_unlock_irqrestore(&ofw_lock, flags);
+
+	if (!ret) {
+		for (i = 0; i < nr_res; i++, p++)
+			*((int *)res[i]) = *p;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__olpc_ofw);
+
+bool olpc_ofw_present(void)
+{
+	return olpc_ofw_cif != NULL;
+}
+EXPORT_SYMBOL_GPL(olpc_ofw_present);
+
+/* OFW cif _should_ be above this address */
+#define OFW_MIN 0xff000000
+
+/* OFW starts on a 1MB boundary */
+#define OFW_BOUND (1<<20)
+
+void __init olpc_ofw_detect(void)
+{
+	struct olpc_ofw_header *hdr = &boot_params.olpc_ofw_header;
+	unsigned long start;
+
+	/* ensure OFW booted us by checking for "OFW " string */
+	if (hdr->ofw_magic != OLPC_OFW_SIG)
+		return;
+
+	olpc_ofw_cif = (int (*)(int *))hdr->cif_handler;
+
+	if ((unsigned long)olpc_ofw_cif < OFW_MIN) {
+		printk(KERN_ERR "OFW detected, but cif has invalid address 0x%lx - disabling.\n",
+				(unsigned long)olpc_ofw_cif);
+		olpc_ofw_cif = NULL;
+		return;
+	}
+
+	/* determine where OFW starts in memory */
+	start = round_down((unsigned long)olpc_ofw_cif, OFW_BOUND);
+	printk(KERN_INFO "OFW detected in memory, cif @ 0x%lx (reserving top %ldMB)\n",
+			(unsigned long)olpc_ofw_cif, (-start) >> 20);
+	reserve_top_address(-start);
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc-xo1.c linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc-xo1.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/olpc/olpc-xo1.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/olpc/olpc-xo1.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,140 @@
+/*
+ * Support for features of the OLPC XO-1 laptop
+ *
+ * Copyright (C) 2010 One Laptop per Child
+ * Copyright (C) 2006 Red Hat, Inc.
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/olpc.h>
+
+#define DRV_NAME "olpc-xo1"
+
+#define PMS_BAR		4
+#define ACPI_BAR	5
+
+/* PMC registers (PMS block) */
+#define PM_SCLK		0x10
+#define PM_IN_SLPCTL	0x20
+#define PM_WKXD		0x34
+#define PM_WKD		0x30
+#define PM_SSC		0x54
+
+/* PM registers (ACPI block) */
+#define PM1_CNT		0x08
+#define PM_GPE0_STS	0x18
+
+static unsigned long acpi_base;
+static unsigned long pms_base;
+
+static void xo1_power_off(void)
+{
+	printk(KERN_INFO "OLPC XO-1 power off sequence...\n");
+
+	/* Enable all of these controls with 0 delay */
+	outl(0x40000000, pms_base + PM_SCLK);
+	outl(0x40000000, pms_base + PM_IN_SLPCTL);
+	outl(0x40000000, pms_base + PM_WKXD);
+	outl(0x40000000, pms_base + PM_WKD);
+
+	/* Clear status bits (possibly unnecessary) */
+	outl(0x0002ffff, pms_base  + PM_SSC);
+	outl(0xffffffff, acpi_base + PM_GPE0_STS);
+
+	/* Write SLP_EN bit to start the machinery */
+	outl(0x00002000, acpi_base + PM1_CNT);
+}
+
+/* Read the base addresses from the PCI BAR info */
+static int __devinit setup_bases(struct pci_dev *pdev)
+{
+	int r;
+
+	r = pci_enable_device_io(pdev);
+	if (r) {
+		dev_err(&pdev->dev, "can't enable device IO\n");
+		return r;
+	}
+
+	r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
+	if (r) {
+		dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
+		return r;
+	}
+
+	r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
+	if (r) {
+		dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
+		pci_release_region(pdev, ACPI_BAR);
+		return r;
+	}
+
+	acpi_base = pci_resource_start(pdev, ACPI_BAR);
+	pms_base = pci_resource_start(pdev, PMS_BAR);
+
+	return 0;
+}
+
+static int __devinit olpc_xo1_probe(struct platform_device *pdev)
+{
+	struct pci_dev *pcidev;
+	int r;
+
+	pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
+				NULL);
+	if (!pdev)
+		return -ENODEV;
+
+	r = setup_bases(pcidev);
+	if (r)
+		return r;
+
+	pm_power_off = xo1_power_off;
+
+	printk(KERN_INFO "OLPC XO-1 support registered\n");
+	return 0;
+}
+
+static int __devexit olpc_xo1_remove(struct platform_device *pdev)
+{
+	pm_power_off = NULL;
+	return 0;
+}
+
+static struct platform_driver olpc_xo1_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = olpc_xo1_probe,
+	.remove = __devexit_p(olpc_xo1_remove),
+};
+
+static int __init olpc_xo1_init(void)
+{
+	return platform_driver_register(&olpc_xo1_driver);
+}
+
+static void __exit olpc_xo1_exit(void)
+{
+	platform_driver_unregister(&olpc_xo1_driver);
+}
+
+MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:olpc-xo1");
+
+module_init(olpc_xo1_init);
+module_exit(olpc_xo1_exit);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/scx200/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/scx200/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/scx200/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/scx200/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SCx200)		+= scx200.o
+scx200-y			+= scx200_32.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/scx200/scx200_32.c linux-libre-2.6.37-gnu/arch/x86/platform/scx200/scx200_32.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/scx200/scx200_32.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/scx200/scx200_32.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,131 @@
+/*
+ *  Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+ *
+ *  National Semiconductor SCx200 support.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+
+#include <linux/scx200.h>
+#include <linux/scx200_gpio.h>
+
+/* Verify that the configuration block really is there */
+#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+
+#define NAME "scx200"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Driver");
+MODULE_LICENSE("GPL");
+
+unsigned scx200_gpio_base = 0;
+unsigned long scx200_gpio_shadow[2];
+
+unsigned scx200_cb_base = 0;
+
+static struct pci_device_id scx200_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_XBUS)   },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_XBUS)   },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci,scx200_tbl);
+
+static int __devinit scx200_probe(struct pci_dev *, const struct pci_device_id *);
+
+static struct pci_driver scx200_pci_driver = {
+	.name = "scx200",
+	.id_table = scx200_tbl,
+	.probe = scx200_probe,
+};
+
+static DEFINE_MUTEX(scx200_gpio_config_lock);
+
+static void __devinit scx200_init_shadow(void)
+{
+	int bank;
+
+	/* read the current values driven on the GPIO signals */
+	for (bank = 0; bank < 2; ++bank)
+		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+}
+
+static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	unsigned base;
+
+	if (pdev->device == PCI_DEVICE_ID_NS_SCx200_BRIDGE ||
+	    pdev->device == PCI_DEVICE_ID_NS_SC1100_BRIDGE) {
+		base = pci_resource_start(pdev, 0);
+		printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+		if (!request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO")) {
+			printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+			return -EBUSY;
+		}
+
+		scx200_gpio_base = base;
+		scx200_init_shadow();
+
+	} else {
+		/* find the base of the Configuration Block */
+		if (scx200_cb_probe(SCx200_CB_BASE_FIXED)) {
+			scx200_cb_base = SCx200_CB_BASE_FIXED;
+		} else {
+			pci_read_config_dword(pdev, SCx200_CBA_SCRATCH, &base);
+			if (scx200_cb_probe(base)) {
+				scx200_cb_base = base;
+			} else {
+				printk(KERN_WARNING NAME ": Configuration Block not found\n");
+				return -ENODEV;
+			}
+		}
+		printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base);
+	}
+
+	return 0;
+}
+
+u32 scx200_gpio_configure(unsigned index, u32 mask, u32 bits)
+{
+	u32 config, new_config;
+
+	mutex_lock(&scx200_gpio_config_lock);
+
+	outl(index, scx200_gpio_base + 0x20);
+	config = inl(scx200_gpio_base + 0x24);
+
+	new_config = (config & mask) | bits;
+	outl(new_config, scx200_gpio_base + 0x24);
+
+	mutex_unlock(&scx200_gpio_config_lock);
+
+	return config;
+}
+
+static int __init scx200_init(void)
+{
+	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
+
+	return pci_register_driver(&scx200_pci_driver);
+}
+
+static void __exit scx200_cleanup(void)
+{
+	pci_unregister_driver(&scx200_pci_driver);
+	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_cleanup);
+
+EXPORT_SYMBOL(scx200_gpio_base);
+EXPORT_SYMBOL(scx200_gpio_shadow);
+EXPORT_SYMBOL(scx200_gpio_configure);
+EXPORT_SYMBOL(scx200_cb_base);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/sfi/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/sfi/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/sfi/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/sfi/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_SFI)		+= sfi.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/sfi/sfi.c linux-libre-2.6.37-gnu/arch/x86/platform/sfi/sfi.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/sfi/sfi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/sfi/sfi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,120 @@
+/*
+ * sfi.c - x86 architecture SFI support.
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#define KMSG_COMPONENT "SFI"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/sfi.h>
+#include <linux/io.h>
+
+#include <asm/io_apic.h>
+#include <asm/mpspec.h>
+#include <asm/setup.h>
+#include <asm/apic.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+
+static void __init mp_sfi_register_lapic_address(unsigned long address)
+{
+	mp_lapic_addr = address;
+
+	set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
+	if (boot_cpu_physical_apicid == -1U)
+		boot_cpu_physical_apicid = read_apic_id();
+
+	pr_info("Boot CPU = %d\n", boot_cpu_physical_apicid);
+}
+
+/* All CPUs enumerated by SFI must be present and enabled */
+static void __cpuinit mp_sfi_register_lapic(u8 id)
+{
+	if (MAX_APICS - id <= 0) {
+		pr_warning("Processor #%d invalid (max %d)\n",
+			id, MAX_APICS);
+		return;
+	}
+
+	pr_info("registering lapic[%d]\n", id);
+
+	generic_processor_info(id, GET_APIC_VERSION(apic_read(APIC_LVR)));
+}
+
+static int __init sfi_parse_cpus(struct sfi_table_header *table)
+{
+	struct sfi_table_simple *sb;
+	struct sfi_cpu_table_entry *pentry;
+	int i;
+	int cpu_num;
+
+	sb = (struct sfi_table_simple *)table;
+	cpu_num = SFI_GET_NUM_ENTRIES(sb, struct sfi_cpu_table_entry);
+	pentry = (struct sfi_cpu_table_entry *)sb->pentry;
+
+	for (i = 0; i < cpu_num; i++) {
+		mp_sfi_register_lapic(pentry->apic_id);
+		pentry++;
+	}
+
+	smp_found_config = 1;
+	return 0;
+}
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+
+static int __init sfi_parse_ioapic(struct sfi_table_header *table)
+{
+	struct sfi_table_simple *sb;
+	struct sfi_apic_table_entry *pentry;
+	int i, num;
+
+	sb = (struct sfi_table_simple *)table;
+	num = SFI_GET_NUM_ENTRIES(sb, struct sfi_apic_table_entry);
+	pentry = (struct sfi_apic_table_entry *)sb->pentry;
+
+	for (i = 0; i < num; i++) {
+		mp_register_ioapic(i, pentry->phys_addr, gsi_top);
+		pentry++;
+	}
+
+	WARN(pic_mode, KERN_WARNING
+		"SFI: pic_mod shouldn't be 1 when IOAPIC table is present\n");
+	pic_mode = 0;
+	return 0;
+}
+#endif /* CONFIG_X86_IO_APIC */
+
+/*
+ * sfi_platform_init(): register lapics & io-apics
+ */
+int __init sfi_platform_init(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	mp_sfi_register_lapic_address(sfi_lapic_addr);
+	sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, sfi_parse_cpus);
+#endif
+#ifdef CONFIG_X86_IO_APIC
+	sfi_table_parse(SFI_SIG_APIC, NULL, NULL, sfi_parse_ioapic);
+#endif
+	return 0;
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/bios_uv.c linux-libre-2.6.37-gnu/arch/x86/platform/uv/bios_uv.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/bios_uv.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/bios_uv.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,215 @@
+/*
+ * BIOS run time interface routines.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (c) Russ Anderson <rja@sgi.com>
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <linux/io.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv_hub.h>
+
+static struct uv_systab uv_systab;
+
+s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
+{
+	struct uv_systab *tab = &uv_systab;
+	s64 ret;
+
+	if (!tab->function)
+		/*
+		 * BIOS does not support UV systab
+		 */
+		return BIOS_STATUS_UNIMPLEMENTED;
+
+	ret = efi_call6((void *)__va(tab->function), (u64)which,
+			a1, a2, a3, a4, a5);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uv_bios_call);
+
+s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
+					u64 a4, u64 a5)
+{
+	unsigned long bios_flags;
+	s64 ret;
+
+	local_irq_save(bios_flags);
+	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
+	local_irq_restore(bios_flags);
+
+	return ret;
+}
+
+s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
+					u64 a4, u64 a5)
+{
+	s64 ret;
+
+	preempt_disable();
+	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
+	preempt_enable();
+
+	return ret;
+}
+
+
+long sn_partition_id;
+EXPORT_SYMBOL_GPL(sn_partition_id);
+long sn_coherency_id;
+EXPORT_SYMBOL_GPL(sn_coherency_id);
+long sn_region_size;
+EXPORT_SYMBOL_GPL(sn_region_size);
+long system_serial_number;
+EXPORT_SYMBOL_GPL(system_serial_number);
+int uv_type;
+EXPORT_SYMBOL_GPL(uv_type);
+
+
+s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
+		long *region, long *ssn)
+{
+	s64 ret;
+	u64 v0, v1;
+	union partition_info_u part;
+
+	ret = uv_bios_call_irqsave(UV_BIOS_GET_SN_INFO, fc,
+				(u64)(&v0), (u64)(&v1), 0, 0);
+	if (ret != BIOS_STATUS_SUCCESS)
+		return ret;
+
+	part.val = v0;
+	if (uvtype)
+		*uvtype = part.hub_version;
+	if (partid)
+		*partid = part.partition_id;
+	if (coher)
+		*coher = part.coherence_id;
+	if (region)
+		*region = part.region_size;
+	if (ssn)
+		*ssn = v1;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uv_bios_get_sn_info);
+
+int
+uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
+			   unsigned long *intr_mmr_offset)
+{
+	u64 watchlist;
+	s64 ret;
+
+	/*
+	 * bios returns watchlist number or negative error number.
+	 */
+	ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
+			mq_size, (u64)intr_mmr_offset,
+			(u64)&watchlist, 0);
+	if (ret < BIOS_STATUS_SUCCESS)
+		return ret;
+
+	return watchlist;
+}
+EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_alloc);
+
+int
+uv_bios_mq_watchlist_free(int blade, int watchlist_num)
+{
+	return (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_FREE,
+				blade, watchlist_num, 0, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_mq_watchlist_free);
+
+s64
+uv_bios_change_memprotect(u64 paddr, u64 len, enum uv_memprotect perms)
+{
+	return uv_bios_call_irqsave(UV_BIOS_MEMPROTECT, paddr, len,
+					perms, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_change_memprotect);
+
+s64
+uv_bios_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len)
+{
+	s64 ret;
+
+	ret = uv_bios_call_irqsave(UV_BIOS_GET_PARTITION_ADDR, (u64)cookie,
+					(u64)addr, buf, (u64)len, 0);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uv_bios_reserved_page_pa);
+
+s64 uv_bios_freq_base(u64 clock_type, u64 *ticks_per_second)
+{
+	return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
+			   (u64)ticks_per_second, 0, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_freq_base);
+
+/*
+ * uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target
+ * @decode: true to enable target, false to disable target
+ * @domain: PCI domain number
+ * @bus: PCI bus number
+ *
+ * Returns:
+ *    0: Success
+ *    -EINVAL: Invalid domain or bus number
+ *    -ENOSYS: Capability not available
+ *    -EBUSY: Legacy VGA I/O cannot be retargeted at this time
+ */
+int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
+{
+	return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
+				(u64)decode, (u64)domain, (u64)bus, 0, 0);
+}
+EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
+
+
+#ifdef CONFIG_EFI
+void uv_bios_init(void)
+{
+	struct uv_systab *tab;
+
+	if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) ||
+	    (efi.uv_systab == (unsigned long)NULL)) {
+		printk(KERN_CRIT "No EFI UV System Table.\n");
+		uv_systab.function = (unsigned long)NULL;
+		return;
+	}
+
+	tab = (struct uv_systab *)ioremap(efi.uv_systab,
+					sizeof(struct uv_systab));
+	if (strncmp(tab->signature, "UVST", 4) != 0)
+		printk(KERN_ERR "bad signature in UV system table!");
+
+	/*
+	 * Copy table to permanent spot for later use.
+	 */
+	memcpy(&uv_systab, tab, sizeof(struct uv_systab));
+	iounmap(tab);
+
+	printk(KERN_INFO "EFI UV System Table Revision %d\n",
+					uv_systab.revision);
+}
+#else	/* !CONFIG_EFI */
+
+void uv_bios_init(void) { }
+#endif
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/uv/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_X86_UV)		+= tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/tlb_uv.c linux-libre-2.6.37-gnu/arch/x86/platform/uv/tlb_uv.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/tlb_uv.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/tlb_uv.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1660 @@
+/*
+ *	SGI UltraViolet TLB flush routines.
+ *
+ *	(c) 2008-2010 Cliff Wickman <cpw@sgi.com>, SGI.
+ *
+ *	This code is released under the GNU General Public License version 2 or
+ *	later.
+ */
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <asm/mmu_context.h>
+#include <asm/uv/uv.h>
+#include <asm/uv/uv_mmrs.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/uv_bau.h>
+#include <asm/apic.h>
+#include <asm/idle.h>
+#include <asm/tsc.h>
+#include <asm/irq_vectors.h>
+#include <asm/timer.h>
+
+/* timeouts in nanoseconds (indexed by UVH_AGING_PRESCALE_SEL urgency7 30:28) */
+static int timeout_base_ns[] = {
+		20,
+		160,
+		1280,
+		10240,
+		81920,
+		655360,
+		5242880,
+		167772160
+};
+static int timeout_us;
+static int nobau;
+static int baudisabled;
+static spinlock_t disable_lock;
+static cycles_t congested_cycles;
+
+/* tunables: */
+static int max_bau_concurrent = MAX_BAU_CONCURRENT;
+static int max_bau_concurrent_constant = MAX_BAU_CONCURRENT;
+static int plugged_delay = PLUGGED_DELAY;
+static int plugsb4reset = PLUGSB4RESET;
+static int timeoutsb4reset = TIMEOUTSB4RESET;
+static int ipi_reset_limit = IPI_RESET_LIMIT;
+static int complete_threshold = COMPLETE_THRESHOLD;
+static int congested_response_us = CONGESTED_RESPONSE_US;
+static int congested_reps = CONGESTED_REPS;
+static int congested_period = CONGESTED_PERIOD;
+static struct dentry *tunables_dir;
+static struct dentry *tunables_file;
+
+static int __init setup_nobau(char *arg)
+{
+	nobau = 1;
+	return 0;
+}
+early_param("nobau", setup_nobau);
+
+/* base pnode in this partition */
+static int uv_partition_base_pnode __read_mostly;
+/* position of pnode (which is nasid>>1): */
+static int uv_nshift __read_mostly;
+static unsigned long uv_mmask __read_mostly;
+
+static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
+static DEFINE_PER_CPU(struct bau_control, bau_control);
+static DEFINE_PER_CPU(cpumask_var_t, uv_flush_tlb_mask);
+
+/*
+ * Determine the first node on a uvhub. 'Nodes' are used for kernel
+ * memory allocation.
+ */
+static int __init uvhub_to_first_node(int uvhub)
+{
+	int node, b;
+
+	for_each_online_node(node) {
+		b = uv_node_to_blade_id(node);
+		if (uvhub == b)
+			return node;
+	}
+	return -1;
+}
+
+/*
+ * Determine the apicid of the first cpu on a uvhub.
+ */
+static int __init uvhub_to_first_apicid(int uvhub)
+{
+	int cpu;
+
+	for_each_present_cpu(cpu)
+		if (uvhub == uv_cpu_to_blade_id(cpu))
+			return per_cpu(x86_cpu_to_apicid, cpu);
+	return -1;
+}
+
+/*
+ * Free a software acknowledge hardware resource by clearing its Pending
+ * bit. This will return a reply to the sender.
+ * If the message has timed out, a reply has already been sent by the
+ * hardware but the resource has not been released. In that case our
+ * clear of the Timeout bit (as well) will free the resource. No reply will
+ * be sent (the hardware will only do one reply per message).
+ */
+static inline void uv_reply_to_message(struct msg_desc *mdp,
+				       struct bau_control *bcp)
+{
+	unsigned long dw;
+	struct bau_payload_queue_entry *msg;
+
+	msg = mdp->msg;
+	if (!msg->canceled) {
+		dw = (msg->sw_ack_vector << UV_SW_ACK_NPENDING) |
+						msg->sw_ack_vector;
+		uv_write_local_mmr(
+				UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS, dw);
+	}
+	msg->replied_to = 1;
+	msg->sw_ack_vector = 0;
+}
+
+/*
+ * Process the receipt of a RETRY message
+ */
+static inline void uv_bau_process_retry_msg(struct msg_desc *mdp,
+					    struct bau_control *bcp)
+{
+	int i;
+	int cancel_count = 0;
+	int slot2;
+	unsigned long msg_res;
+	unsigned long mmr = 0;
+	struct bau_payload_queue_entry *msg;
+	struct bau_payload_queue_entry *msg2;
+	struct ptc_stats *stat;
+
+	msg = mdp->msg;
+	stat = bcp->statp;
+	stat->d_retries++;
+	/*
+	 * cancel any message from msg+1 to the retry itself
+	 */
+	for (msg2 = msg+1, i = 0; i < DEST_Q_SIZE; msg2++, i++) {
+		if (msg2 > mdp->va_queue_last)
+			msg2 = mdp->va_queue_first;
+		if (msg2 == msg)
+			break;
+
+		/* same conditions for cancellation as uv_do_reset */
+		if ((msg2->replied_to == 0) && (msg2->canceled == 0) &&
+		    (msg2->sw_ack_vector) && ((msg2->sw_ack_vector &
+			msg->sw_ack_vector) == 0) &&
+		    (msg2->sending_cpu == msg->sending_cpu) &&
+		    (msg2->msg_type != MSG_NOOP)) {
+			slot2 = msg2 - mdp->va_queue_first;
+			mmr = uv_read_local_mmr
+				(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
+			msg_res = msg2->sw_ack_vector;
+			/*
+			 * This is a message retry; clear the resources held
+			 * by the previous message only if they timed out.
+			 * If it has not timed out we have an unexpected
+			 * situation to report.
+			 */
+			if (mmr & (msg_res << UV_SW_ACK_NPENDING)) {
+				/*
+				 * is the resource timed out?
+				 * make everyone ignore the cancelled message.
+				 */
+				msg2->canceled = 1;
+				stat->d_canceled++;
+				cancel_count++;
+				uv_write_local_mmr(
+				    UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
+					(msg_res << UV_SW_ACK_NPENDING) |
+					 msg_res);
+			}
+		}
+	}
+	if (!cancel_count)
+		stat->d_nocanceled++;
+}
+
+/*
+ * Do all the things a cpu should do for a TLB shootdown message.
+ * Other cpu's may come here at the same time for this message.
+ */
+static void uv_bau_process_message(struct msg_desc *mdp,
+				   struct bau_control *bcp)
+{
+	int msg_ack_count;
+	short socket_ack_count = 0;
+	struct ptc_stats *stat;
+	struct bau_payload_queue_entry *msg;
+	struct bau_control *smaster = bcp->socket_master;
+
+	/*
+	 * This must be a normal message, or retry of a normal message
+	 */
+	msg = mdp->msg;
+	stat = bcp->statp;
+	if (msg->address == TLB_FLUSH_ALL) {
+		local_flush_tlb();
+		stat->d_alltlb++;
+	} else {
+		__flush_tlb_one(msg->address);
+		stat->d_onetlb++;
+	}
+	stat->d_requestee++;
+
+	/*
+	 * One cpu on each uvhub has the additional job on a RETRY
+	 * of releasing the resource held by the message that is
+	 * being retried.  That message is identified by sending
+	 * cpu number.
+	 */
+	if (msg->msg_type == MSG_RETRY && bcp == bcp->uvhub_master)
+		uv_bau_process_retry_msg(mdp, bcp);
+
+	/*
+	 * This is a sw_ack message, so we have to reply to it.
+	 * Count each responding cpu on the socket. This avoids
+	 * pinging the count's cache line back and forth between
+	 * the sockets.
+	 */
+	socket_ack_count = atomic_add_short_return(1, (struct atomic_short *)
+			&smaster->socket_acknowledge_count[mdp->msg_slot]);
+	if (socket_ack_count == bcp->cpus_in_socket) {
+		/*
+		 * Both sockets dump their completed count total into
+		 * the message's count.
+		 */
+		smaster->socket_acknowledge_count[mdp->msg_slot] = 0;
+		msg_ack_count = atomic_add_short_return(socket_ack_count,
+				(struct atomic_short *)&msg->acknowledge_count);
+
+		if (msg_ack_count == bcp->cpus_in_uvhub) {
+			/*
+			 * All cpus in uvhub saw it; reply
+			 */
+			uv_reply_to_message(mdp, bcp);
+		}
+	}
+
+	return;
+}
+
+/*
+ * Determine the first cpu on a uvhub.
+ */
+static int uvhub_to_first_cpu(int uvhub)
+{
+	int cpu;
+	for_each_present_cpu(cpu)
+		if (uvhub == uv_cpu_to_blade_id(cpu))
+			return cpu;
+	return -1;
+}
+
+/*
+ * Last resort when we get a large number of destination timeouts is
+ * to clear resources held by a given cpu.
+ * Do this with IPI so that all messages in the BAU message queue
+ * can be identified by their nonzero sw_ack_vector field.
+ *
+ * This is entered for a single cpu on the uvhub.
+ * The sender want's this uvhub to free a specific message's
+ * sw_ack resources.
+ */
+static void
+uv_do_reset(void *ptr)
+{
+	int i;
+	int slot;
+	int count = 0;
+	unsigned long mmr;
+	unsigned long msg_res;
+	struct bau_control *bcp;
+	struct reset_args *rap;
+	struct bau_payload_queue_entry *msg;
+	struct ptc_stats *stat;
+
+	bcp = &per_cpu(bau_control, smp_processor_id());
+	rap = (struct reset_args *)ptr;
+	stat = bcp->statp;
+	stat->d_resets++;
+
+	/*
+	 * We're looking for the given sender, and
+	 * will free its sw_ack resource.
+	 * If all cpu's finally responded after the timeout, its
+	 * message 'replied_to' was set.
+	 */
+	for (msg = bcp->va_queue_first, i = 0; i < DEST_Q_SIZE; msg++, i++) {
+		/* uv_do_reset: same conditions for cancellation as
+		   uv_bau_process_retry_msg() */
+		if ((msg->replied_to == 0) &&
+		    (msg->canceled == 0) &&
+		    (msg->sending_cpu == rap->sender) &&
+		    (msg->sw_ack_vector) &&
+		    (msg->msg_type != MSG_NOOP)) {
+			/*
+			 * make everyone else ignore this message
+			 */
+			msg->canceled = 1;
+			slot = msg - bcp->va_queue_first;
+			count++;
+			/*
+			 * only reset the resource if it is still pending
+			 */
+			mmr = uv_read_local_mmr
+					(UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE);
+			msg_res = msg->sw_ack_vector;
+			if (mmr & msg_res) {
+				stat->d_rcanceled++;
+				uv_write_local_mmr(
+				    UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS,
+					(msg_res << UV_SW_ACK_NPENDING) |
+					 msg_res);
+			}
+		}
+	}
+	return;
+}
+
+/*
+ * Use IPI to get all target uvhubs to release resources held by
+ * a given sending cpu number.
+ */
+static void uv_reset_with_ipi(struct bau_target_uvhubmask *distribution,
+			      int sender)
+{
+	int uvhub;
+	int cpu;
+	cpumask_t mask;
+	struct reset_args reset_args;
+
+	reset_args.sender = sender;
+
+	cpus_clear(mask);
+	/* find a single cpu for each uvhub in this distribution mask */
+	for (uvhub = 0;
+		    uvhub < sizeof(struct bau_target_uvhubmask) * BITSPERBYTE;
+		    uvhub++) {
+		if (!bau_uvhub_isset(uvhub, distribution))
+			continue;
+		/* find a cpu for this uvhub */
+		cpu = uvhub_to_first_cpu(uvhub);
+		cpu_set(cpu, mask);
+	}
+	/* IPI all cpus; Preemption is already disabled */
+	smp_call_function_many(&mask, uv_do_reset, (void *)&reset_args, 1);
+	return;
+}
+
+static inline unsigned long
+cycles_2_us(unsigned long long cyc)
+{
+	unsigned long long ns;
+	unsigned long us;
+	ns =  (cyc * per_cpu(cyc2ns, smp_processor_id()))
+						>> CYC2NS_SCALE_FACTOR;
+	us = ns / 1000;
+	return us;
+}
+
+/*
+ * wait for all cpus on this hub to finish their sends and go quiet
+ * leaves uvhub_quiesce set so that no new broadcasts are started by
+ * bau_flush_send_and_wait()
+ */
+static inline void
+quiesce_local_uvhub(struct bau_control *hmaster)
+{
+	atomic_add_short_return(1, (struct atomic_short *)
+		 &hmaster->uvhub_quiesce);
+}
+
+/*
+ * mark this quiet-requestor as done
+ */
+static inline void
+end_uvhub_quiesce(struct bau_control *hmaster)
+{
+	atomic_add_short_return(-1, (struct atomic_short *)
+		&hmaster->uvhub_quiesce);
+}
+
+/*
+ * Wait for completion of a broadcast software ack message
+ * return COMPLETE, RETRY(PLUGGED or TIMEOUT) or GIVEUP
+ */
+static int uv_wait_completion(struct bau_desc *bau_desc,
+	unsigned long mmr_offset, int right_shift, int this_cpu,
+	struct bau_control *bcp, struct bau_control *smaster, long try)
+{
+	unsigned long descriptor_status;
+	cycles_t ttime;
+	struct ptc_stats *stat = bcp->statp;
+	struct bau_control *hmaster;
+
+	hmaster = bcp->uvhub_master;
+
+	/* spin on the status MMR, waiting for it to go idle */
+	while ((descriptor_status = (((unsigned long)
+		uv_read_local_mmr(mmr_offset) >>
+			right_shift) & UV_ACT_STATUS_MASK)) !=
+			DESC_STATUS_IDLE) {
+		/*
+		 * Our software ack messages may be blocked because there are
+		 * no swack resources available.  As long as none of them
+		 * has timed out hardware will NACK our message and its
+		 * state will stay IDLE.
+		 */
+		if (descriptor_status == DESC_STATUS_SOURCE_TIMEOUT) {
+			stat->s_stimeout++;
+			return FLUSH_GIVEUP;
+		} else if (descriptor_status ==
+					DESC_STATUS_DESTINATION_TIMEOUT) {
+			stat->s_dtimeout++;
+			ttime = get_cycles();
+
+			/*
+			 * Our retries may be blocked by all destination
+			 * swack resources being consumed, and a timeout
+			 * pending.  In that case hardware returns the
+			 * ERROR that looks like a destination timeout.
+			 */
+			if (cycles_2_us(ttime - bcp->send_message) <
+							timeout_us) {
+				bcp->conseccompletes = 0;
+				return FLUSH_RETRY_PLUGGED;
+			}
+
+			bcp->conseccompletes = 0;
+			return FLUSH_RETRY_TIMEOUT;
+		} else {
+			/*
+			 * descriptor_status is still BUSY
+			 */
+			cpu_relax();
+		}
+	}
+	bcp->conseccompletes++;
+	return FLUSH_COMPLETE;
+}
+
+static inline cycles_t
+sec_2_cycles(unsigned long sec)
+{
+	unsigned long ns;
+	cycles_t cyc;
+
+	ns = sec * 1000000000;
+	cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
+	return cyc;
+}
+
+/*
+ * conditionally add 1 to *v, unless *v is >= u
+ * return 0 if we cannot add 1 to *v because it is >= u
+ * return 1 if we can add 1 to *v because it is < u
+ * the add is atomic
+ *
+ * This is close to atomic_add_unless(), but this allows the 'u' value
+ * to be lowered below the current 'v'.  atomic_add_unless can only stop
+ * on equal.
+ */
+static inline int atomic_inc_unless_ge(spinlock_t *lock, atomic_t *v, int u)
+{
+	spin_lock(lock);
+	if (atomic_read(v) >= u) {
+		spin_unlock(lock);
+		return 0;
+	}
+	atomic_inc(v);
+	spin_unlock(lock);
+	return 1;
+}
+
+/*
+ * Our retries are blocked by all destination swack resources being
+ * in use, and a timeout is pending. In that case hardware immediately
+ * returns the ERROR that looks like a destination timeout.
+ */
+static void
+destination_plugged(struct bau_desc *bau_desc, struct bau_control *bcp,
+			struct bau_control *hmaster, struct ptc_stats *stat)
+{
+	udelay(bcp->plugged_delay);
+	bcp->plugged_tries++;
+	if (bcp->plugged_tries >= bcp->plugsb4reset) {
+		bcp->plugged_tries = 0;
+		quiesce_local_uvhub(hmaster);
+		spin_lock(&hmaster->queue_lock);
+		uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
+		spin_unlock(&hmaster->queue_lock);
+		end_uvhub_quiesce(hmaster);
+		bcp->ipi_attempts++;
+		stat->s_resets_plug++;
+	}
+}
+
+static void
+destination_timeout(struct bau_desc *bau_desc, struct bau_control *bcp,
+			struct bau_control *hmaster, struct ptc_stats *stat)
+{
+	hmaster->max_bau_concurrent = 1;
+	bcp->timeout_tries++;
+	if (bcp->timeout_tries >= bcp->timeoutsb4reset) {
+		bcp->timeout_tries = 0;
+		quiesce_local_uvhub(hmaster);
+		spin_lock(&hmaster->queue_lock);
+		uv_reset_with_ipi(&bau_desc->distribution, bcp->cpu);
+		spin_unlock(&hmaster->queue_lock);
+		end_uvhub_quiesce(hmaster);
+		bcp->ipi_attempts++;
+		stat->s_resets_timeout++;
+	}
+}
+
+/*
+ * Completions are taking a very long time due to a congested numalink
+ * network.
+ */
+static void
+disable_for_congestion(struct bau_control *bcp, struct ptc_stats *stat)
+{
+	int tcpu;
+	struct bau_control *tbcp;
+
+	/* let only one cpu do this disabling */
+	spin_lock(&disable_lock);
+	if (!baudisabled && bcp->period_requests &&
+	    ((bcp->period_time / bcp->period_requests) > congested_cycles)) {
+		/* it becomes this cpu's job to turn on the use of the
+		   BAU again */
+		baudisabled = 1;
+		bcp->set_bau_off = 1;
+		bcp->set_bau_on_time = get_cycles() +
+			sec_2_cycles(bcp->congested_period);
+		stat->s_bau_disabled++;
+		for_each_present_cpu(tcpu) {
+			tbcp = &per_cpu(bau_control, tcpu);
+				tbcp->baudisabled = 1;
+		}
+	}
+	spin_unlock(&disable_lock);
+}
+
+/**
+ * uv_flush_send_and_wait
+ *
+ * Send a broadcast and wait for it to complete.
+ *
+ * The flush_mask contains the cpus the broadcast is to be sent to including
+ * cpus that are on the local uvhub.
+ *
+ * Returns 0 if all flushing represented in the mask was done.
+ * Returns 1 if it gives up entirely and the original cpu mask is to be
+ * returned to the kernel.
+ */
+int uv_flush_send_and_wait(struct bau_desc *bau_desc,
+			   struct cpumask *flush_mask, struct bau_control *bcp)
+{
+	int right_shift;
+	int completion_status = 0;
+	int seq_number = 0;
+	long try = 0;
+	int cpu = bcp->uvhub_cpu;
+	int this_cpu = bcp->cpu;
+	unsigned long mmr_offset;
+	unsigned long index;
+	cycles_t time1;
+	cycles_t time2;
+	cycles_t elapsed;
+	struct ptc_stats *stat = bcp->statp;
+	struct bau_control *smaster = bcp->socket_master;
+	struct bau_control *hmaster = bcp->uvhub_master;
+
+	if (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
+			&hmaster->active_descriptor_count,
+			hmaster->max_bau_concurrent)) {
+		stat->s_throttles++;
+		do {
+			cpu_relax();
+		} while (!atomic_inc_unless_ge(&hmaster->uvhub_lock,
+			&hmaster->active_descriptor_count,
+			hmaster->max_bau_concurrent));
+	}
+	while (hmaster->uvhub_quiesce)
+		cpu_relax();
+
+	if (cpu < UV_CPUS_PER_ACT_STATUS) {
+		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_0;
+		right_shift = cpu * UV_ACT_STATUS_SIZE;
+	} else {
+		mmr_offset = UVH_LB_BAU_SB_ACTIVATION_STATUS_1;
+		right_shift =
+		    ((cpu - UV_CPUS_PER_ACT_STATUS) * UV_ACT_STATUS_SIZE);
+	}
+	time1 = get_cycles();
+	do {
+		if (try == 0) {
+			bau_desc->header.msg_type = MSG_REGULAR;
+			seq_number = bcp->message_number++;
+		} else {
+			bau_desc->header.msg_type = MSG_RETRY;
+			stat->s_retry_messages++;
+		}
+		bau_desc->header.sequence = seq_number;
+		index = (1UL << UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT) |
+			bcp->uvhub_cpu;
+		bcp->send_message = get_cycles();
+		uv_write_local_mmr(UVH_LB_BAU_SB_ACTIVATION_CONTROL, index);
+		try++;
+		completion_status = uv_wait_completion(bau_desc, mmr_offset,
+			right_shift, this_cpu, bcp, smaster, try);
+
+		if (completion_status == FLUSH_RETRY_PLUGGED) {
+			destination_plugged(bau_desc, bcp, hmaster, stat);
+		} else if (completion_status == FLUSH_RETRY_TIMEOUT) {
+			destination_timeout(bau_desc, bcp, hmaster, stat);
+		}
+		if (bcp->ipi_attempts >= bcp->ipi_reset_limit) {
+			bcp->ipi_attempts = 0;
+			completion_status = FLUSH_GIVEUP;
+			break;
+		}
+		cpu_relax();
+	} while ((completion_status == FLUSH_RETRY_PLUGGED) ||
+		 (completion_status == FLUSH_RETRY_TIMEOUT));
+	time2 = get_cycles();
+	bcp->plugged_tries = 0;
+	bcp->timeout_tries = 0;
+	if ((completion_status == FLUSH_COMPLETE) &&
+	    (bcp->conseccompletes > bcp->complete_threshold) &&
+	    (hmaster->max_bau_concurrent <
+					hmaster->max_bau_concurrent_constant))
+			hmaster->max_bau_concurrent++;
+	while (hmaster->uvhub_quiesce)
+		cpu_relax();
+	atomic_dec(&hmaster->active_descriptor_count);
+	if (time2 > time1) {
+		elapsed = time2 - time1;
+		stat->s_time += elapsed;
+		if ((completion_status == FLUSH_COMPLETE) && (try == 1)) {
+			bcp->period_requests++;
+			bcp->period_time += elapsed;
+			if ((elapsed > congested_cycles) &&
+			    (bcp->period_requests > bcp->congested_reps)) {
+				disable_for_congestion(bcp, stat);
+			}
+		}
+	} else
+		stat->s_requestor--;
+	if (completion_status == FLUSH_COMPLETE && try > 1)
+		stat->s_retriesok++;
+	else if (completion_status == FLUSH_GIVEUP) {
+		stat->s_giveup++;
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * uv_flush_tlb_others - globally purge translation cache of a virtual
+ * address or all TLB's
+ * @cpumask: mask of all cpu's in which the address is to be removed
+ * @mm: mm_struct containing virtual address range
+ * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
+ * @cpu: the current cpu
+ *
+ * This is the entry point for initiating any UV global TLB shootdown.
+ *
+ * Purges the translation caches of all specified processors of the given
+ * virtual address, or purges all TLB's on specified processors.
+ *
+ * The caller has derived the cpumask from the mm_struct.  This function
+ * is called only if there are bits set in the mask. (e.g. flush_tlb_page())
+ *
+ * The cpumask is converted into a uvhubmask of the uvhubs containing
+ * those cpus.
+ *
+ * Note that this function should be called with preemption disabled.
+ *
+ * Returns NULL if all remote flushing was done.
+ * Returns pointer to cpumask if some remote flushing remains to be
+ * done.  The returned pointer is valid till preemption is re-enabled.
+ */
+const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
+					  struct mm_struct *mm,
+					  unsigned long va, unsigned int cpu)
+{
+	int tcpu;
+	int uvhub;
+	int locals = 0;
+	int remotes = 0;
+	int hubs = 0;
+	struct bau_desc *bau_desc;
+	struct cpumask *flush_mask;
+	struct ptc_stats *stat;
+	struct bau_control *bcp;
+	struct bau_control *tbcp;
+
+	/* kernel was booted 'nobau' */
+	if (nobau)
+		return cpumask;
+
+	bcp = &per_cpu(bau_control, cpu);
+	stat = bcp->statp;
+
+	/* bau was disabled due to slow response */
+	if (bcp->baudisabled) {
+		/* the cpu that disabled it must re-enable it */
+		if (bcp->set_bau_off) {
+			if (get_cycles() >= bcp->set_bau_on_time) {
+				stat->s_bau_reenabled++;
+				baudisabled = 0;
+				for_each_present_cpu(tcpu) {
+					tbcp = &per_cpu(bau_control, tcpu);
+					tbcp->baudisabled = 0;
+					tbcp->period_requests = 0;
+					tbcp->period_time = 0;
+				}
+			}
+		}
+		return cpumask;
+	}
+
+	/*
+	 * Each sending cpu has a per-cpu mask which it fills from the caller's
+	 * cpu mask.  All cpus are converted to uvhubs and copied to the
+	 * activation descriptor.
+	 */
+	flush_mask = (struct cpumask *)per_cpu(uv_flush_tlb_mask, cpu);
+	/* don't actually do a shootdown of the local cpu */
+	cpumask_andnot(flush_mask, cpumask, cpumask_of(cpu));
+	if (cpu_isset(cpu, *cpumask))
+		stat->s_ntargself++;
+
+	bau_desc = bcp->descriptor_base;
+	bau_desc += UV_ITEMS_PER_DESCRIPTOR * bcp->uvhub_cpu;
+	bau_uvhubs_clear(&bau_desc->distribution, UV_DISTRIBUTION_SIZE);
+
+	/* cpu statistics */
+	for_each_cpu(tcpu, flush_mask) {
+		uvhub = uv_cpu_to_blade_id(tcpu);
+		bau_uvhub_set(uvhub, &bau_desc->distribution);
+		if (uvhub == bcp->uvhub)
+			locals++;
+		else
+			remotes++;
+	}
+	if ((locals + remotes) == 0)
+		return NULL;
+	stat->s_requestor++;
+	stat->s_ntargcpu += remotes + locals;
+	stat->s_ntargremotes += remotes;
+	stat->s_ntarglocals += locals;
+	remotes = bau_uvhub_weight(&bau_desc->distribution);
+
+	/* uvhub statistics */
+	hubs = bau_uvhub_weight(&bau_desc->distribution);
+	if (locals) {
+		stat->s_ntarglocaluvhub++;
+		stat->s_ntargremoteuvhub += (hubs - 1);
+	} else
+		stat->s_ntargremoteuvhub += hubs;
+	stat->s_ntarguvhub += hubs;
+	if (hubs >= 16)
+		stat->s_ntarguvhub16++;
+	else if (hubs >= 8)
+		stat->s_ntarguvhub8++;
+	else if (hubs >= 4)
+		stat->s_ntarguvhub4++;
+	else if (hubs >= 2)
+		stat->s_ntarguvhub2++;
+	else
+		stat->s_ntarguvhub1++;
+
+	bau_desc->payload.address = va;
+	bau_desc->payload.sending_cpu = cpu;
+
+	/*
+	 * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
+	 * or 1 if it gave up and the original cpumask should be returned.
+	 */
+	if (!uv_flush_send_and_wait(bau_desc, flush_mask, bcp))
+		return NULL;
+	else
+		return cpumask;
+}
+
+/*
+ * The BAU message interrupt comes here. (registered by set_intr_gate)
+ * See entry_64.S
+ *
+ * We received a broadcast assist message.
+ *
+ * Interrupts are disabled; this interrupt could represent
+ * the receipt of several messages.
+ *
+ * All cores/threads on this hub get this interrupt.
+ * The last one to see it does the software ack.
+ * (the resource will not be freed until noninterruptable cpus see this
+ *  interrupt; hardware may timeout the s/w ack and reply ERROR)
+ */
+void uv_bau_message_interrupt(struct pt_regs *regs)
+{
+	int count = 0;
+	cycles_t time_start;
+	struct bau_payload_queue_entry *msg;
+	struct bau_control *bcp;
+	struct ptc_stats *stat;
+	struct msg_desc msgdesc;
+
+	time_start = get_cycles();
+	bcp = &per_cpu(bau_control, smp_processor_id());
+	stat = bcp->statp;
+	msgdesc.va_queue_first = bcp->va_queue_first;
+	msgdesc.va_queue_last = bcp->va_queue_last;
+	msg = bcp->bau_msg_head;
+	while (msg->sw_ack_vector) {
+		count++;
+		msgdesc.msg_slot = msg - msgdesc.va_queue_first;
+		msgdesc.sw_ack_slot = ffs(msg->sw_ack_vector) - 1;
+		msgdesc.msg = msg;
+		uv_bau_process_message(&msgdesc, bcp);
+		msg++;
+		if (msg > msgdesc.va_queue_last)
+			msg = msgdesc.va_queue_first;
+		bcp->bau_msg_head = msg;
+	}
+	stat->d_time += (get_cycles() - time_start);
+	if (!count)
+		stat->d_nomsg++;
+	else if (count > 1)
+		stat->d_multmsg++;
+	ack_APIC_irq();
+}
+
+/*
+ * uv_enable_timeouts
+ *
+ * Each target uvhub (i.e. a uvhub that has no cpu's) needs to have
+ * shootdown message timeouts enabled.  The timeout does not cause
+ * an interrupt, but causes an error message to be returned to
+ * the sender.
+ */
+static void uv_enable_timeouts(void)
+{
+	int uvhub;
+	int nuvhubs;
+	int pnode;
+	unsigned long mmr_image;
+
+	nuvhubs = uv_num_possible_blades();
+
+	for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
+		if (!uv_blade_nr_possible_cpus(uvhub))
+			continue;
+
+		pnode = uv_blade_to_pnode(uvhub);
+		mmr_image =
+		    uv_read_global_mmr64(pnode, UVH_LB_BAU_MISC_CONTROL);
+		/*
+		 * Set the timeout period and then lock it in, in three
+		 * steps; captures and locks in the period.
+		 *
+		 * To program the period, the SOFT_ACK_MODE must be off.
+		 */
+		mmr_image &= ~((unsigned long)1 <<
+		    UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
+		uv_write_global_mmr64
+		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+		/*
+		 * Set the 4-bit period.
+		 */
+		mmr_image &= ~((unsigned long)0xf <<
+		     UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
+		mmr_image |= (UV_INTD_SOFT_ACK_TIMEOUT_PERIOD <<
+		     UVH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT);
+		uv_write_global_mmr64
+		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+		/*
+		 * Subsequent reversals of the timebase bit (3) cause an
+		 * immediate timeout of one or all INTD resources as
+		 * indicated in bits 2:0 (7 causes all of them to timeout).
+		 */
+		mmr_image |= ((unsigned long)1 <<
+		    UVH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT);
+		uv_write_global_mmr64
+		    (pnode, UVH_LB_BAU_MISC_CONTROL, mmr_image);
+	}
+}
+
+static void *uv_ptc_seq_start(struct seq_file *file, loff_t *offset)
+{
+	if (*offset < num_possible_cpus())
+		return offset;
+	return NULL;
+}
+
+static void *uv_ptc_seq_next(struct seq_file *file, void *data, loff_t *offset)
+{
+	(*offset)++;
+	if (*offset < num_possible_cpus())
+		return offset;
+	return NULL;
+}
+
+static void uv_ptc_seq_stop(struct seq_file *file, void *data)
+{
+}
+
+static inline unsigned long long
+microsec_2_cycles(unsigned long microsec)
+{
+	unsigned long ns;
+	unsigned long long cyc;
+
+	ns = microsec * 1000;
+	cyc = (ns << CYC2NS_SCALE_FACTOR)/(per_cpu(cyc2ns, smp_processor_id()));
+	return cyc;
+}
+
+/*
+ * Display the statistics thru /proc.
+ * 'data' points to the cpu number
+ */
+static int uv_ptc_seq_show(struct seq_file *file, void *data)
+{
+	struct ptc_stats *stat;
+	int cpu;
+
+	cpu = *(loff_t *)data;
+
+	if (!cpu) {
+		seq_printf(file,
+			"# cpu sent stime self locals remotes ncpus localhub ");
+		seq_printf(file,
+			"remotehub numuvhubs numuvhubs16 numuvhubs8 ");
+		seq_printf(file,
+			"numuvhubs4 numuvhubs2 numuvhubs1 dto ");
+		seq_printf(file,
+			"retries rok resetp resett giveup sto bz throt ");
+		seq_printf(file,
+			"sw_ack recv rtime all ");
+		seq_printf(file,
+			"one mult none retry canc nocan reset rcan ");
+		seq_printf(file,
+			"disable enable\n");
+	}
+	if (cpu < num_possible_cpus() && cpu_online(cpu)) {
+		stat = &per_cpu(ptcstats, cpu);
+		/* source side statistics */
+		seq_printf(file,
+			"cpu %d %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+			   cpu, stat->s_requestor, cycles_2_us(stat->s_time),
+			   stat->s_ntargself, stat->s_ntarglocals,
+			   stat->s_ntargremotes, stat->s_ntargcpu,
+			   stat->s_ntarglocaluvhub, stat->s_ntargremoteuvhub,
+			   stat->s_ntarguvhub, stat->s_ntarguvhub16);
+		seq_printf(file, "%ld %ld %ld %ld %ld ",
+			   stat->s_ntarguvhub8, stat->s_ntarguvhub4,
+			   stat->s_ntarguvhub2, stat->s_ntarguvhub1,
+			   stat->s_dtimeout);
+		seq_printf(file, "%ld %ld %ld %ld %ld %ld %ld %ld ",
+			   stat->s_retry_messages, stat->s_retriesok,
+			   stat->s_resets_plug, stat->s_resets_timeout,
+			   stat->s_giveup, stat->s_stimeout,
+			   stat->s_busy, stat->s_throttles);
+
+		/* destination side statistics */
+		seq_printf(file,
+			   "%lx %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld ",
+			   uv_read_global_mmr64(uv_cpu_to_pnode(cpu),
+					UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE),
+			   stat->d_requestee, cycles_2_us(stat->d_time),
+			   stat->d_alltlb, stat->d_onetlb, stat->d_multmsg,
+			   stat->d_nomsg, stat->d_retries, stat->d_canceled,
+			   stat->d_nocanceled, stat->d_resets,
+			   stat->d_rcanceled);
+		seq_printf(file, "%ld %ld\n",
+			stat->s_bau_disabled, stat->s_bau_reenabled);
+	}
+
+	return 0;
+}
+
+/*
+ * Display the tunables thru debugfs
+ */
+static ssize_t tunables_read(struct file *file, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	char *buf;
+	int ret;
+
+	buf = kasprintf(GFP_KERNEL, "%s %s %s\n%d %d %d %d %d %d %d %d %d\n",
+		"max_bau_concurrent plugged_delay plugsb4reset",
+		"timeoutsb4reset ipi_reset_limit complete_threshold",
+		"congested_response_us congested_reps congested_period",
+		max_bau_concurrent, plugged_delay, plugsb4reset,
+		timeoutsb4reset, ipi_reset_limit, complete_threshold,
+		congested_response_us, congested_reps, congested_period);
+
+	if (!buf)
+		return -ENOMEM;
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+	kfree(buf);
+	return ret;
+}
+
+/*
+ * -1: resetf the statistics
+ *  0: display meaning of the statistics
+ */
+static ssize_t uv_ptc_proc_write(struct file *file, const char __user *user,
+				 size_t count, loff_t *data)
+{
+	int cpu;
+	long input_arg;
+	char optstr[64];
+	struct ptc_stats *stat;
+
+	if (count == 0 || count > sizeof(optstr))
+		return -EINVAL;
+	if (copy_from_user(optstr, user, count))
+		return -EFAULT;
+	optstr[count - 1] = '\0';
+	if (strict_strtol(optstr, 10, &input_arg) < 0) {
+		printk(KERN_DEBUG "%s is invalid\n", optstr);
+		return -EINVAL;
+	}
+
+	if (input_arg == 0) {
+		printk(KERN_DEBUG "# cpu:      cpu number\n");
+		printk(KERN_DEBUG "Sender statistics:\n");
+		printk(KERN_DEBUG
+		"sent:     number of shootdown messages sent\n");
+		printk(KERN_DEBUG
+		"stime:    time spent sending messages\n");
+		printk(KERN_DEBUG
+		"numuvhubs: number of hubs targeted with shootdown\n");
+		printk(KERN_DEBUG
+		"numuvhubs16: number times 16 or more hubs targeted\n");
+		printk(KERN_DEBUG
+		"numuvhubs8: number times 8 or more hubs targeted\n");
+		printk(KERN_DEBUG
+		"numuvhubs4: number times 4 or more hubs targeted\n");
+		printk(KERN_DEBUG
+		"numuvhubs2: number times 2 or more hubs targeted\n");
+		printk(KERN_DEBUG
+		"numuvhubs1: number times 1 hub targeted\n");
+		printk(KERN_DEBUG
+		"numcpus:  number of cpus targeted with shootdown\n");
+		printk(KERN_DEBUG
+		"dto:      number of destination timeouts\n");
+		printk(KERN_DEBUG
+		"retries:  destination timeout retries sent\n");
+		printk(KERN_DEBUG
+		"rok:   :  destination timeouts successfully retried\n");
+		printk(KERN_DEBUG
+		"resetp:   ipi-style resource resets for plugs\n");
+		printk(KERN_DEBUG
+		"resett:   ipi-style resource resets for timeouts\n");
+		printk(KERN_DEBUG
+		"giveup:   fall-backs to ipi-style shootdowns\n");
+		printk(KERN_DEBUG
+		"sto:      number of source timeouts\n");
+		printk(KERN_DEBUG
+		"bz:       number of stay-busy's\n");
+		printk(KERN_DEBUG
+		"throt:    number times spun in throttle\n");
+		printk(KERN_DEBUG "Destination side statistics:\n");
+		printk(KERN_DEBUG
+		"sw_ack:   image of UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE\n");
+		printk(KERN_DEBUG
+		"recv:     shootdown messages received\n");
+		printk(KERN_DEBUG
+		"rtime:    time spent processing messages\n");
+		printk(KERN_DEBUG
+		"all:      shootdown all-tlb messages\n");
+		printk(KERN_DEBUG
+		"one:      shootdown one-tlb messages\n");
+		printk(KERN_DEBUG
+		"mult:     interrupts that found multiple messages\n");
+		printk(KERN_DEBUG
+		"none:     interrupts that found no messages\n");
+		printk(KERN_DEBUG
+		"retry:    number of retry messages processed\n");
+		printk(KERN_DEBUG
+		"canc:     number messages canceled by retries\n");
+		printk(KERN_DEBUG
+		"nocan:    number retries that found nothing to cancel\n");
+		printk(KERN_DEBUG
+		"reset:    number of ipi-style reset requests processed\n");
+		printk(KERN_DEBUG
+		"rcan:     number messages canceled by reset requests\n");
+		printk(KERN_DEBUG
+		"disable:  number times use of the BAU was disabled\n");
+		printk(KERN_DEBUG
+		"enable:   number times use of the BAU was re-enabled\n");
+	} else if (input_arg == -1) {
+		for_each_present_cpu(cpu) {
+			stat = &per_cpu(ptcstats, cpu);
+			memset(stat, 0, sizeof(struct ptc_stats));
+		}
+	}
+
+	return count;
+}
+
+static int local_atoi(const char *name)
+{
+	int val = 0;
+
+	for (;; name++) {
+		switch (*name) {
+		case '0' ... '9':
+			val = 10*val+(*name-'0');
+			break;
+		default:
+			return val;
+		}
+	}
+}
+
+/*
+ * set the tunables
+ * 0 values reset them to defaults
+ */
+static ssize_t tunables_write(struct file *file, const char __user *user,
+				 size_t count, loff_t *data)
+{
+	int cpu;
+	int cnt = 0;
+	int val;
+	char *p;
+	char *q;
+	char instr[64];
+	struct bau_control *bcp;
+
+	if (count == 0 || count > sizeof(instr)-1)
+		return -EINVAL;
+	if (copy_from_user(instr, user, count))
+		return -EFAULT;
+
+	instr[count] = '\0';
+	/* count the fields */
+	p = instr + strspn(instr, WHITESPACE);
+	q = p;
+	for (; *p; p = q + strspn(q, WHITESPACE)) {
+		q = p + strcspn(p, WHITESPACE);
+		cnt++;
+		if (q == p)
+			break;
+	}
+	if (cnt != 9) {
+		printk(KERN_INFO "bau tunable error: should be 9 numbers\n");
+		return -EINVAL;
+	}
+
+	p = instr + strspn(instr, WHITESPACE);
+	q = p;
+	for (cnt = 0; *p; p = q + strspn(q, WHITESPACE), cnt++) {
+		q = p + strcspn(p, WHITESPACE);
+		val = local_atoi(p);
+		switch (cnt) {
+		case 0:
+			if (val == 0) {
+				max_bau_concurrent = MAX_BAU_CONCURRENT;
+				max_bau_concurrent_constant =
+							MAX_BAU_CONCURRENT;
+				continue;
+			}
+			bcp = &per_cpu(bau_control, smp_processor_id());
+			if (val < 1 || val > bcp->cpus_in_uvhub) {
+				printk(KERN_DEBUG
+				"Error: BAU max concurrent %d is invalid\n",
+				val);
+				return -EINVAL;
+			}
+			max_bau_concurrent = val;
+			max_bau_concurrent_constant = val;
+			continue;
+		case 1:
+			if (val == 0)
+				plugged_delay = PLUGGED_DELAY;
+			else
+				plugged_delay = val;
+			continue;
+		case 2:
+			if (val == 0)
+				plugsb4reset = PLUGSB4RESET;
+			else
+				plugsb4reset = val;
+			continue;
+		case 3:
+			if (val == 0)
+				timeoutsb4reset = TIMEOUTSB4RESET;
+			else
+				timeoutsb4reset = val;
+			continue;
+		case 4:
+			if (val == 0)
+				ipi_reset_limit = IPI_RESET_LIMIT;
+			else
+				ipi_reset_limit = val;
+			continue;
+		case 5:
+			if (val == 0)
+				complete_threshold = COMPLETE_THRESHOLD;
+			else
+				complete_threshold = val;
+			continue;
+		case 6:
+			if (val == 0)
+				congested_response_us = CONGESTED_RESPONSE_US;
+			else
+				congested_response_us = val;
+			continue;
+		case 7:
+			if (val == 0)
+				congested_reps = CONGESTED_REPS;
+			else
+				congested_reps = val;
+			continue;
+		case 8:
+			if (val == 0)
+				congested_period = CONGESTED_PERIOD;
+			else
+				congested_period = val;
+			continue;
+		}
+		if (q == p)
+			break;
+	}
+	for_each_present_cpu(cpu) {
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->max_bau_concurrent = max_bau_concurrent;
+		bcp->max_bau_concurrent_constant = max_bau_concurrent;
+		bcp->plugged_delay = plugged_delay;
+		bcp->plugsb4reset = plugsb4reset;
+		bcp->timeoutsb4reset = timeoutsb4reset;
+		bcp->ipi_reset_limit = ipi_reset_limit;
+		bcp->complete_threshold = complete_threshold;
+		bcp->congested_response_us = congested_response_us;
+		bcp->congested_reps = congested_reps;
+		bcp->congested_period = congested_period;
+	}
+	return count;
+}
+
+static const struct seq_operations uv_ptc_seq_ops = {
+	.start		= uv_ptc_seq_start,
+	.next		= uv_ptc_seq_next,
+	.stop		= uv_ptc_seq_stop,
+	.show		= uv_ptc_seq_show
+};
+
+static int uv_ptc_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &uv_ptc_seq_ops);
+}
+
+static int tunables_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations proc_uv_ptc_operations = {
+	.open		= uv_ptc_proc_open,
+	.read		= seq_read,
+	.write		= uv_ptc_proc_write,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static const struct file_operations tunables_fops = {
+	.open		= tunables_open,
+	.read		= tunables_read,
+	.write		= tunables_write,
+	.llseek		= default_llseek,
+};
+
+static int __init uv_ptc_init(void)
+{
+	struct proc_dir_entry *proc_uv_ptc;
+
+	if (!is_uv_system())
+		return 0;
+
+	proc_uv_ptc = proc_create(UV_PTC_BASENAME, 0444, NULL,
+				  &proc_uv_ptc_operations);
+	if (!proc_uv_ptc) {
+		printk(KERN_ERR "unable to create %s proc entry\n",
+		       UV_PTC_BASENAME);
+		return -EINVAL;
+	}
+
+	tunables_dir = debugfs_create_dir(UV_BAU_TUNABLES_DIR, NULL);
+	if (!tunables_dir) {
+		printk(KERN_ERR "unable to create debugfs directory %s\n",
+		       UV_BAU_TUNABLES_DIR);
+		return -EINVAL;
+	}
+	tunables_file = debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600,
+			tunables_dir, NULL, &tunables_fops);
+	if (!tunables_file) {
+		printk(KERN_ERR "unable to create debugfs file %s\n",
+		       UV_BAU_TUNABLES_FILE);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * initialize the sending side's sending buffers
+ */
+static void
+uv_activation_descriptor_init(int node, int pnode)
+{
+	int i;
+	int cpu;
+	unsigned long pa;
+	unsigned long m;
+	unsigned long n;
+	struct bau_desc *bau_desc;
+	struct bau_desc *bd2;
+	struct bau_control *bcp;
+
+	/*
+	 * each bau_desc is 64 bytes; there are 8 (UV_ITEMS_PER_DESCRIPTOR)
+	 * per cpu; and up to 32 (UV_ADP_SIZE) cpu's per uvhub
+	 */
+	bau_desc = kmalloc_node(sizeof(struct bau_desc) * UV_ADP_SIZE
+				* UV_ITEMS_PER_DESCRIPTOR, GFP_KERNEL, node);
+	BUG_ON(!bau_desc);
+
+	pa = uv_gpa(bau_desc); /* need the real nasid*/
+	n = pa >> uv_nshift;
+	m = pa & uv_mmask;
+
+	uv_write_global_mmr64(pnode, UVH_LB_BAU_SB_DESCRIPTOR_BASE,
+			      (n << UV_DESC_BASE_PNODE_SHIFT | m));
+
+	/*
+	 * initializing all 8 (UV_ITEMS_PER_DESCRIPTOR) descriptors for each
+	 * cpu even though we only use the first one; one descriptor can
+	 * describe a broadcast to 256 uv hubs.
+	 */
+	for (i = 0, bd2 = bau_desc; i < (UV_ADP_SIZE*UV_ITEMS_PER_DESCRIPTOR);
+		i++, bd2++) {
+		memset(bd2, 0, sizeof(struct bau_desc));
+		bd2->header.sw_ack_flag = 1;
+		/*
+		 * base_dest_nodeid is the nasid (pnode<<1) of the first uvhub
+		 * in the partition. The bit map will indicate uvhub numbers,
+		 * which are 0-N in a partition. Pnodes are unique system-wide.
+		 */
+		bd2->header.base_dest_nodeid = uv_partition_base_pnode << 1;
+		bd2->header.dest_subnodeid = 0x10; /* the LB */
+		bd2->header.command = UV_NET_ENDPOINT_INTD;
+		bd2->header.int_both = 1;
+		/*
+		 * all others need to be set to zero:
+		 *   fairness chaining multilevel count replied_to
+		 */
+	}
+	for_each_present_cpu(cpu) {
+		if (pnode != uv_blade_to_pnode(uv_cpu_to_blade_id(cpu)))
+			continue;
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->descriptor_base = bau_desc;
+	}
+}
+
+/*
+ * initialize the destination side's receiving buffers
+ * entered for each uvhub in the partition
+ * - node is first node (kernel memory notion) on the uvhub
+ * - pnode is the uvhub's physical identifier
+ */
+static void
+uv_payload_queue_init(int node, int pnode)
+{
+	int pn;
+	int cpu;
+	char *cp;
+	unsigned long pa;
+	struct bau_payload_queue_entry *pqp;
+	struct bau_payload_queue_entry *pqp_malloc;
+	struct bau_control *bcp;
+
+	pqp = kmalloc_node((DEST_Q_SIZE + 1)
+			   * sizeof(struct bau_payload_queue_entry),
+			   GFP_KERNEL, node);
+	BUG_ON(!pqp);
+	pqp_malloc = pqp;
+
+	cp = (char *)pqp + 31;
+	pqp = (struct bau_payload_queue_entry *)(((unsigned long)cp >> 5) << 5);
+
+	for_each_present_cpu(cpu) {
+		if (pnode != uv_cpu_to_pnode(cpu))
+			continue;
+		/* for every cpu on this pnode: */
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->va_queue_first = pqp;
+		bcp->bau_msg_head = pqp;
+		bcp->va_queue_last = pqp + (DEST_Q_SIZE - 1);
+	}
+	/*
+	 * need the pnode of where the memory was really allocated
+	 */
+	pa = uv_gpa(pqp);
+	pn = pa >> uv_nshift;
+	uv_write_global_mmr64(pnode,
+			      UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST,
+			      ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) |
+			      uv_physnodeaddr(pqp));
+	uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL,
+			      uv_physnodeaddr(pqp));
+	uv_write_global_mmr64(pnode, UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST,
+			      (unsigned long)
+			      uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1)));
+	/* in effect, all msg_type's are set to MSG_NOOP */
+	memset(pqp, 0, sizeof(struct bau_payload_queue_entry) * DEST_Q_SIZE);
+}
+
+/*
+ * Initialization of each UV hub's structures
+ */
+static void __init uv_init_uvhub(int uvhub, int vector)
+{
+	int node;
+	int pnode;
+	unsigned long apicid;
+
+	node = uvhub_to_first_node(uvhub);
+	pnode = uv_blade_to_pnode(uvhub);
+	uv_activation_descriptor_init(node, pnode);
+	uv_payload_queue_init(node, pnode);
+	/*
+	 * the below initialization can't be in firmware because the
+	 * messaging IRQ will be determined by the OS
+	 */
+	apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits;
+	uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG,
+				      ((apicid << 32) | vector));
+}
+
+/*
+ * We will set BAU_MISC_CONTROL with a timeout period.
+ * But the BIOS has set UVH_AGING_PRESCALE_SEL and UVH_TRANSACTION_TIMEOUT.
+ * So the destination timeout period has be be calculated from them.
+ */
+static int
+calculate_destination_timeout(void)
+{
+	unsigned long mmr_image;
+	int mult1;
+	int mult2;
+	int index;
+	int base;
+	int ret;
+	unsigned long ts_ns;
+
+	mult1 = UV_INTD_SOFT_ACK_TIMEOUT_PERIOD & BAU_MISC_CONTROL_MULT_MASK;
+	mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL);
+	index = (mmr_image >> BAU_URGENCY_7_SHIFT) & BAU_URGENCY_7_MASK;
+	mmr_image = uv_read_local_mmr(UVH_TRANSACTION_TIMEOUT);
+	mult2 = (mmr_image >> BAU_TRANS_SHIFT) & BAU_TRANS_MASK;
+	base = timeout_base_ns[index];
+	ts_ns = base * mult1 * mult2;
+	ret = ts_ns / 1000;
+	return ret;
+}
+
+/*
+ * initialize the bau_control structure for each cpu
+ */
+static void __init uv_init_per_cpu(int nuvhubs)
+{
+	int i;
+	int cpu;
+	int pnode;
+	int uvhub;
+	int have_hmaster;
+	short socket = 0;
+	unsigned short socket_mask;
+	unsigned char *uvhub_mask;
+	struct bau_control *bcp;
+	struct uvhub_desc *bdp;
+	struct socket_desc *sdp;
+	struct bau_control *hmaster = NULL;
+	struct bau_control *smaster = NULL;
+	struct socket_desc {
+		short num_cpus;
+		short cpu_number[16];
+	};
+	struct uvhub_desc {
+		unsigned short socket_mask;
+		short num_cpus;
+		short uvhub;
+		short pnode;
+		struct socket_desc socket[2];
+	};
+	struct uvhub_desc *uvhub_descs;
+
+	timeout_us = calculate_destination_timeout();
+
+	uvhub_descs = kmalloc(nuvhubs * sizeof(struct uvhub_desc), GFP_KERNEL);
+	memset(uvhub_descs, 0, nuvhubs * sizeof(struct uvhub_desc));
+	uvhub_mask = kzalloc((nuvhubs+7)/8, GFP_KERNEL);
+	for_each_present_cpu(cpu) {
+		bcp = &per_cpu(bau_control, cpu);
+		memset(bcp, 0, sizeof(struct bau_control));
+		pnode = uv_cpu_hub_info(cpu)->pnode;
+		uvhub = uv_cpu_hub_info(cpu)->numa_blade_id;
+		*(uvhub_mask + (uvhub/8)) |= (1 << (uvhub%8));
+		bdp = &uvhub_descs[uvhub];
+		bdp->num_cpus++;
+		bdp->uvhub = uvhub;
+		bdp->pnode = pnode;
+		/* kludge: 'assuming' one node per socket, and assuming that
+		   disabling a socket just leaves a gap in node numbers */
+		socket = (cpu_to_node(cpu) & 1);
+		bdp->socket_mask |= (1 << socket);
+		sdp = &bdp->socket[socket];
+		sdp->cpu_number[sdp->num_cpus] = cpu;
+		sdp->num_cpus++;
+	}
+	for (uvhub = 0; uvhub < nuvhubs; uvhub++) {
+		if (!(*(uvhub_mask + (uvhub/8)) & (1 << (uvhub%8))))
+			continue;
+		have_hmaster = 0;
+		bdp = &uvhub_descs[uvhub];
+		socket_mask = bdp->socket_mask;
+		socket = 0;
+		while (socket_mask) {
+			if (!(socket_mask & 1))
+				goto nextsocket;
+			sdp = &bdp->socket[socket];
+			for (i = 0; i < sdp->num_cpus; i++) {
+				cpu = sdp->cpu_number[i];
+				bcp = &per_cpu(bau_control, cpu);
+				bcp->cpu = cpu;
+				if (i == 0) {
+					smaster = bcp;
+					if (!have_hmaster) {
+						have_hmaster++;
+						hmaster = bcp;
+					}
+				}
+				bcp->cpus_in_uvhub = bdp->num_cpus;
+				bcp->cpus_in_socket = sdp->num_cpus;
+				bcp->socket_master = smaster;
+				bcp->uvhub = bdp->uvhub;
+				bcp->uvhub_master = hmaster;
+				bcp->uvhub_cpu = uv_cpu_hub_info(cpu)->
+						blade_processor_id;
+			}
+nextsocket:
+			socket++;
+			socket_mask = (socket_mask >> 1);
+		}
+	}
+	kfree(uvhub_descs);
+	kfree(uvhub_mask);
+	for_each_present_cpu(cpu) {
+		bcp = &per_cpu(bau_control, cpu);
+		bcp->baudisabled = 0;
+		bcp->statp = &per_cpu(ptcstats, cpu);
+		/* time interval to catch a hardware stay-busy bug */
+		bcp->timeout_interval = microsec_2_cycles(2*timeout_us);
+		bcp->max_bau_concurrent = max_bau_concurrent;
+		bcp->max_bau_concurrent_constant = max_bau_concurrent;
+		bcp->plugged_delay = plugged_delay;
+		bcp->plugsb4reset = plugsb4reset;
+		bcp->timeoutsb4reset = timeoutsb4reset;
+		bcp->ipi_reset_limit = ipi_reset_limit;
+		bcp->complete_threshold = complete_threshold;
+		bcp->congested_response_us = congested_response_us;
+		bcp->congested_reps = congested_reps;
+		bcp->congested_period = congested_period;
+	}
+}
+
+/*
+ * Initialization of BAU-related structures
+ */
+static int __init uv_bau_init(void)
+{
+	int uvhub;
+	int pnode;
+	int nuvhubs;
+	int cur_cpu;
+	int vector;
+	unsigned long mmr;
+
+	if (!is_uv_system())
+		return 0;
+
+	if (nobau)
+		return 0;
+
+	for_each_possible_cpu(cur_cpu)
+		zalloc_cpumask_var_node(&per_cpu(uv_flush_tlb_mask, cur_cpu),
+				       GFP_KERNEL, cpu_to_node(cur_cpu));
+
+	uv_nshift = uv_hub_info->m_val;
+	uv_mmask = (1UL << uv_hub_info->m_val) - 1;
+	nuvhubs = uv_num_possible_blades();
+	spin_lock_init(&disable_lock);
+	congested_cycles = microsec_2_cycles(congested_response_us);
+
+	uv_init_per_cpu(nuvhubs);
+
+	uv_partition_base_pnode = 0x7fffffff;
+	for (uvhub = 0; uvhub < nuvhubs; uvhub++)
+		if (uv_blade_nr_possible_cpus(uvhub) &&
+			(uv_blade_to_pnode(uvhub) < uv_partition_base_pnode))
+			uv_partition_base_pnode = uv_blade_to_pnode(uvhub);
+
+	vector = UV_BAU_MESSAGE;
+	for_each_possible_blade(uvhub)
+		if (uv_blade_nr_possible_cpus(uvhub))
+			uv_init_uvhub(uvhub, vector);
+
+	uv_enable_timeouts();
+	alloc_intr_gate(vector, uv_bau_message_intr1);
+
+	for_each_possible_blade(uvhub) {
+		if (uv_blade_nr_possible_cpus(uvhub)) {
+			pnode = uv_blade_to_pnode(uvhub);
+			/* INIT the bau */
+			uv_write_global_mmr64(pnode,
+					UVH_LB_BAU_SB_ACTIVATION_CONTROL,
+					((unsigned long)1 << 63));
+			mmr = 1; /* should be 1 to broadcast to both sockets */
+			uv_write_global_mmr64(pnode, UVH_BAU_DATA_BROADCAST,
+						mmr);
+		}
+	}
+
+	return 0;
+}
+core_initcall(uv_bau_init);
+fs_initcall(uv_ptc_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_irq.c linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_irq.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_irq.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,285 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * SGI UV IRQ functions
+ *
+ * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#include <asm/apic.h>
+#include <asm/uv/uv_irq.h>
+#include <asm/uv/uv_hub.h>
+
+/* MMR offset and pnode of hub sourcing interrupts for a given irq */
+struct uv_irq_2_mmr_pnode{
+	struct rb_node		list;
+	unsigned long		offset;
+	int			pnode;
+	int			irq;
+};
+
+static spinlock_t		uv_irq_lock;
+static struct rb_root		uv_irq_root;
+
+static int uv_set_irq_affinity(struct irq_data *, const struct cpumask *, bool);
+
+static void uv_noop(struct irq_data *data) { }
+
+static void uv_ack_apic(struct irq_data *data)
+{
+	ack_APIC_irq();
+}
+
+static struct irq_chip uv_irq_chip = {
+	.name			= "UV-CORE",
+	.irq_mask		= uv_noop,
+	.irq_unmask		= uv_noop,
+	.irq_eoi		= uv_ack_apic,
+	.irq_set_affinity	= uv_set_irq_affinity,
+};
+
+/*
+ * Add offset and pnode information of the hub sourcing interrupts to the
+ * rb tree for a specific irq.
+ */
+static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
+{
+	struct rb_node **link = &uv_irq_root.rb_node;
+	struct rb_node *parent = NULL;
+	struct uv_irq_2_mmr_pnode *n;
+	struct uv_irq_2_mmr_pnode *e;
+	unsigned long irqflags;
+
+	n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
+				uv_blade_to_memory_nid(blade));
+	if (!n)
+		return -ENOMEM;
+
+	n->irq = irq;
+	n->offset = offset;
+	n->pnode = uv_blade_to_pnode(blade);
+	spin_lock_irqsave(&uv_irq_lock, irqflags);
+	/* Find the right place in the rbtree: */
+	while (*link) {
+		parent = *link;
+		e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
+
+		if (unlikely(irq == e->irq)) {
+			/* irq entry exists */
+			e->pnode = uv_blade_to_pnode(blade);
+			e->offset = offset;
+			spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+			kfree(n);
+			return 0;
+		}
+
+		if (irq < e->irq)
+			link = &(*link)->rb_left;
+		else
+			link = &(*link)->rb_right;
+	}
+
+	/* Insert the node into the rbtree. */
+	rb_link_node(&n->list, parent, link);
+	rb_insert_color(&n->list, &uv_irq_root);
+
+	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+	return 0;
+}
+
+/* Retrieve offset and pnode information from the rb tree for a specific irq */
+int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
+{
+	struct uv_irq_2_mmr_pnode *e;
+	struct rb_node *n;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&uv_irq_lock, irqflags);
+	n = uv_irq_root.rb_node;
+	while (n) {
+		e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+
+		if (e->irq == irq) {
+			*offset = e->offset;
+			*pnode = e->pnode;
+			spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+			return 0;
+		}
+
+		if (irq < e->irq)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+	return -1;
+}
+
+/*
+ * Re-target the irq to the specified CPU and enable the specified MMR located
+ * on the specified blade to allow the sending of MSIs to the specified CPU.
+ */
+static int
+arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
+		       unsigned long mmr_offset, int limit)
+{
+	const struct cpumask *eligible_cpu = cpumask_of(cpu);
+	struct irq_cfg *cfg = get_irq_chip_data(irq);
+	unsigned long mmr_value;
+	struct uv_IO_APIC_route_entry *entry;
+	int mmr_pnode, err;
+
+	BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+			sizeof(unsigned long));
+
+	err = assign_irq_vector(irq, cfg, eligible_cpu);
+	if (err != 0)
+		return err;
+
+	if (limit == UV_AFFINITY_CPU)
+		irq_set_status_flags(irq, IRQ_NO_BALANCING);
+	else
+		irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+
+	set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
+				      irq_name);
+
+	mmr_value = 0;
+	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+	entry->vector		= cfg->vector;
+	entry->delivery_mode	= apic->irq_delivery_mode;
+	entry->dest_mode	= apic->irq_dest_mode;
+	entry->polarity		= 0;
+	entry->trigger		= 0;
+	entry->mask		= 0;
+	entry->dest		= apic->cpu_mask_to_apicid(eligible_cpu);
+
+	mmr_pnode = uv_blade_to_pnode(mmr_blade);
+	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+	if (cfg->move_in_progress)
+		send_cleanup_vector(cfg);
+
+	return irq;
+}
+
+/*
+ * Disable the specified MMR located on the specified blade so that MSIs are
+ * longer allowed to be sent.
+ */
+static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
+{
+	unsigned long mmr_value;
+	struct uv_IO_APIC_route_entry *entry;
+
+	BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+			sizeof(unsigned long));
+
+	mmr_value = 0;
+	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+	entry->mask = 1;
+
+	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+}
+
+static int
+uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
+		    bool force)
+{
+	struct irq_cfg *cfg = data->chip_data;
+	unsigned int dest;
+	unsigned long mmr_value, mmr_offset;
+	struct uv_IO_APIC_route_entry *entry;
+	int mmr_pnode;
+
+	if (__ioapic_set_affinity(data, mask, &dest))
+		return -1;
+
+	mmr_value = 0;
+	entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+
+	entry->vector		= cfg->vector;
+	entry->delivery_mode	= apic->irq_delivery_mode;
+	entry->dest_mode	= apic->irq_dest_mode;
+	entry->polarity		= 0;
+	entry->trigger		= 0;
+	entry->mask		= 0;
+	entry->dest		= dest;
+
+	/* Get previously stored MMR and pnode of hub sourcing interrupts */
+	if (uv_irq_2_mmr_info(data->irq, &mmr_offset, &mmr_pnode))
+		return -1;
+
+	uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+	if (cfg->move_in_progress)
+		send_cleanup_vector(cfg);
+
+	return 0;
+}
+
+/*
+ * Set up a mapping of an available irq and vector, and enable the specified
+ * MMR that defines the MSI that is to be sent to the specified CPU when an
+ * interrupt is raised.
+ */
+int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
+		 unsigned long mmr_offset, int limit)
+{
+	int irq, ret;
+
+	irq = create_irq_nr(NR_IRQS_LEGACY, uv_blade_to_memory_nid(mmr_blade));
+
+	if (irq <= 0)
+		return -EBUSY;
+
+	ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
+		limit);
+	if (ret == irq)
+		uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
+	else
+		destroy_irq(irq);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(uv_setup_irq);
+
+/*
+ * Tear down a mapping of an irq and vector, and disable the specified MMR that
+ * defined the MSI that was to be sent to the specified CPU when an interrupt
+ * was raised.
+ *
+ * Set mmr_blade and mmr_offset to what was passed in on uv_setup_irq().
+ */
+void uv_teardown_irq(unsigned int irq)
+{
+	struct uv_irq_2_mmr_pnode *e;
+	struct rb_node *n;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&uv_irq_lock, irqflags);
+	n = uv_irq_root.rb_node;
+	while (n) {
+		e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
+		if (e->irq == irq) {
+			arch_disable_uv_irq(e->pnode, e->offset);
+			rb_erase(n, &uv_irq_root);
+			kfree(e);
+			break;
+		}
+		if (irq < e->irq)
+			n = n->rb_left;
+		else
+			n = n->rb_right;
+	}
+	spin_unlock_irqrestore(&uv_irq_lock, irqflags);
+	destroy_irq(irq);
+}
+EXPORT_SYMBOL_GPL(uv_teardown_irq);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_sysfs.c linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_sysfs.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_sysfs.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,76 @@
+/*
+ * This file supports the /sys/firmware/sgi_uv interfaces for SGI UV.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (c) Russ Anderson
+ */
+
+#include <linux/sysdev.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv.h>
+
+struct kobject *sgi_uv_kobj;
+
+static ssize_t partition_id_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%ld\n", sn_partition_id);
+}
+
+static ssize_t coherence_id_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%ld\n", partition_coherence_id());
+}
+
+static struct kobj_attribute partition_id_attr =
+	__ATTR(partition_id, S_IRUGO, partition_id_show, NULL);
+
+static struct kobj_attribute coherence_id_attr =
+	__ATTR(coherence_id, S_IRUGO, coherence_id_show, NULL);
+
+
+static int __init sgi_uv_sysfs_init(void)
+{
+	unsigned long ret;
+
+	if (!is_uv_system())
+		return -ENODEV;
+
+	if (!sgi_uv_kobj)
+		sgi_uv_kobj = kobject_create_and_add("sgi_uv", firmware_kobj);
+	if (!sgi_uv_kobj) {
+		printk(KERN_WARNING "kobject_create_and_add sgi_uv failed\n");
+		return -EINVAL;
+	}
+
+	ret = sysfs_create_file(sgi_uv_kobj, &partition_id_attr.attr);
+	if (ret) {
+		printk(KERN_WARNING "sysfs_create_file partition_id failed\n");
+		return ret;
+	}
+
+	ret = sysfs_create_file(sgi_uv_kobj, &coherence_id_attr.attr);
+	if (ret) {
+		printk(KERN_WARNING "sysfs_create_file coherence_id failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+device_initcall(sgi_uv_sysfs_init);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_time.c linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_time.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/uv/uv_time.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/uv/uv_time.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,425 @@
+/*
+ * SGI RTC clock/timer routines.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *  Copyright (c) 2009 Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (c) Dimitri Sivanich
+ */
+#include <linux/clockchips.h>
+#include <linux/slab.h>
+
+#include <asm/uv/uv_mmrs.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv.h>
+#include <asm/apic.h>
+#include <asm/cpu.h>
+
+#define RTC_NAME		"sgi_rtc"
+
+static cycle_t uv_read_rtc(struct clocksource *cs);
+static int uv_rtc_next_event(unsigned long, struct clock_event_device *);
+static void uv_rtc_timer_setup(enum clock_event_mode,
+				struct clock_event_device *);
+
+static struct clocksource clocksource_uv = {
+	.name		= RTC_NAME,
+	.rating		= 400,
+	.read		= uv_read_rtc,
+	.mask		= (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
+	.shift		= 10,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct clock_event_device clock_event_device_uv = {
+	.name		= RTC_NAME,
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 20,
+	.rating		= 400,
+	.irq		= -1,
+	.set_next_event	= uv_rtc_next_event,
+	.set_mode	= uv_rtc_timer_setup,
+	.event_handler	= NULL,
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, cpu_ced);
+
+/* There is one of these allocated per node */
+struct uv_rtc_timer_head {
+	spinlock_t	lock;
+	/* next cpu waiting for timer, local node relative: */
+	int		next_cpu;
+	/* number of cpus on this node: */
+	int		ncpus;
+	struct {
+		int	lcpu;		/* systemwide logical cpu number */
+		u64	expires;	/* next timer expiration for this cpu */
+	} cpu[1];
+};
+
+/*
+ * Access to uv_rtc_timer_head via blade id.
+ */
+static struct uv_rtc_timer_head		**blade_info __read_mostly;
+
+static int				uv_rtc_evt_enable;
+
+/*
+ * Hardware interface routines
+ */
+
+/* Send IPIs to another node */
+static void uv_rtc_send_IPI(int cpu)
+{
+	unsigned long apicid, val;
+	int pnode;
+
+	apicid = cpu_physical_id(cpu);
+	pnode = uv_apicid_to_pnode(apicid);
+	apicid |= uv_apicid_hibits;
+	val = (1UL << UVH_IPI_INT_SEND_SHFT) |
+	      (apicid << UVH_IPI_INT_APIC_ID_SHFT) |
+	      (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT);
+
+	uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+}
+
+/* Check for an RTC interrupt pending */
+static int uv_intr_pending(int pnode)
+{
+	return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
+		UVH_EVENT_OCCURRED0_RTC1_MASK;
+}
+
+/* Setup interrupt and return non-zero if early expiration occurred. */
+static int uv_setup_intr(int cpu, u64 expires)
+{
+	u64 val;
+	unsigned long apicid = cpu_physical_id(cpu) | uv_apicid_hibits;
+	int pnode = uv_cpu_to_pnode(cpu);
+
+	uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
+		UVH_RTC1_INT_CONFIG_M_MASK);
+	uv_write_global_mmr64(pnode, UVH_INT_CMPB, -1L);
+
+	uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
+		UVH_EVENT_OCCURRED0_RTC1_MASK);
+
+	val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
+		((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
+
+	/* Set configuration */
+	uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val);
+	/* Initialize comparator value */
+	uv_write_global_mmr64(pnode, UVH_INT_CMPB, expires);
+
+	if (uv_read_rtc(NULL) <= expires)
+		return 0;
+
+	return !uv_intr_pending(pnode);
+}
+
+/*
+ * Per-cpu timer tracking routines
+ */
+
+static __init void uv_rtc_deallocate_timers(void)
+{
+	int bid;
+
+	for_each_possible_blade(bid) {
+		kfree(blade_info[bid]);
+	}
+	kfree(blade_info);
+}
+
+/* Allocate per-node list of cpu timer expiration times. */
+static __init int uv_rtc_allocate_timers(void)
+{
+	int cpu;
+
+	blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL);
+	if (!blade_info)
+		return -ENOMEM;
+	memset(blade_info, 0, uv_possible_blades * sizeof(void *));
+
+	for_each_present_cpu(cpu) {
+		int nid = cpu_to_node(cpu);
+		int bid = uv_cpu_to_blade_id(cpu);
+		int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+		struct uv_rtc_timer_head *head = blade_info[bid];
+
+		if (!head) {
+			head = kmalloc_node(sizeof(struct uv_rtc_timer_head) +
+				(uv_blade_nr_possible_cpus(bid) *
+					2 * sizeof(u64)),
+				GFP_KERNEL, nid);
+			if (!head) {
+				uv_rtc_deallocate_timers();
+				return -ENOMEM;
+			}
+			spin_lock_init(&head->lock);
+			head->ncpus = uv_blade_nr_possible_cpus(bid);
+			head->next_cpu = -1;
+			blade_info[bid] = head;
+		}
+
+		head->cpu[bcpu].lcpu = cpu;
+		head->cpu[bcpu].expires = ULLONG_MAX;
+	}
+
+	return 0;
+}
+
+/* Find and set the next expiring timer.  */
+static void uv_rtc_find_next_timer(struct uv_rtc_timer_head *head, int pnode)
+{
+	u64 lowest = ULLONG_MAX;
+	int c, bcpu = -1;
+
+	head->next_cpu = -1;
+	for (c = 0; c < head->ncpus; c++) {
+		u64 exp = head->cpu[c].expires;
+		if (exp < lowest) {
+			bcpu = c;
+			lowest = exp;
+		}
+	}
+	if (bcpu >= 0) {
+		head->next_cpu = bcpu;
+		c = head->cpu[bcpu].lcpu;
+		if (uv_setup_intr(c, lowest))
+			/* If we didn't set it up in time, trigger */
+			uv_rtc_send_IPI(c);
+	} else {
+		uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG,
+			UVH_RTC1_INT_CONFIG_M_MASK);
+	}
+}
+
+/*
+ * Set expiration time for current cpu.
+ *
+ * Returns 1 if we missed the expiration time.
+ */
+static int uv_rtc_set_timer(int cpu, u64 expires)
+{
+	int pnode = uv_cpu_to_pnode(cpu);
+	int bid = uv_cpu_to_blade_id(cpu);
+	struct uv_rtc_timer_head *head = blade_info[bid];
+	int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+	u64 *t = &head->cpu[bcpu].expires;
+	unsigned long flags;
+	int next_cpu;
+
+	spin_lock_irqsave(&head->lock, flags);
+
+	next_cpu = head->next_cpu;
+	*t = expires;
+
+	/* Will this one be next to go off? */
+	if (next_cpu < 0 || bcpu == next_cpu ||
+			expires < head->cpu[next_cpu].expires) {
+		head->next_cpu = bcpu;
+		if (uv_setup_intr(cpu, expires)) {
+			*t = ULLONG_MAX;
+			uv_rtc_find_next_timer(head, pnode);
+			spin_unlock_irqrestore(&head->lock, flags);
+			return -ETIME;
+		}
+	}
+
+	spin_unlock_irqrestore(&head->lock, flags);
+	return 0;
+}
+
+/*
+ * Unset expiration time for current cpu.
+ *
+ * Returns 1 if this timer was pending.
+ */
+static int uv_rtc_unset_timer(int cpu, int force)
+{
+	int pnode = uv_cpu_to_pnode(cpu);
+	int bid = uv_cpu_to_blade_id(cpu);
+	struct uv_rtc_timer_head *head = blade_info[bid];
+	int bcpu = uv_cpu_hub_info(cpu)->blade_processor_id;
+	u64 *t = &head->cpu[bcpu].expires;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&head->lock, flags);
+
+	if ((head->next_cpu == bcpu && uv_read_rtc(NULL) >= *t) || force)
+		rc = 1;
+
+	if (rc) {
+		*t = ULLONG_MAX;
+		/* Was the hardware setup for this timer? */
+		if (head->next_cpu == bcpu)
+			uv_rtc_find_next_timer(head, pnode);
+	}
+
+	spin_unlock_irqrestore(&head->lock, flags);
+
+	return rc;
+}
+
+
+/*
+ * Kernel interface routines.
+ */
+
+/*
+ * Read the RTC.
+ *
+ * Starting with HUB rev 2.0, the UV RTC register is replicated across all
+ * cachelines of it's own page.  This allows faster simultaneous reads
+ * from a given socket.
+ */
+static cycle_t uv_read_rtc(struct clocksource *cs)
+{
+	unsigned long offset;
+
+	if (uv_get_min_hub_revision_id() == 1)
+		offset = 0;
+	else
+		offset = (uv_blade_processor_id() * L1_CACHE_BYTES) % PAGE_SIZE;
+
+	return (cycle_t)uv_read_local_mmr(UVH_RTC | offset);
+}
+
+/*
+ * Program the next event, relative to now
+ */
+static int uv_rtc_next_event(unsigned long delta,
+			     struct clock_event_device *ced)
+{
+	int ced_cpu = cpumask_first(ced->cpumask);
+
+	return uv_rtc_set_timer(ced_cpu, delta + uv_read_rtc(NULL));
+}
+
+/*
+ * Setup the RTC timer in oneshot mode
+ */
+static void uv_rtc_timer_setup(enum clock_event_mode mode,
+			       struct clock_event_device *evt)
+{
+	int ced_cpu = cpumask_first(evt->cpumask);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here yet */
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		uv_rtc_unset_timer(ced_cpu, 1);
+		break;
+	}
+}
+
+static void uv_rtc_interrupt(void)
+{
+	int cpu = smp_processor_id();
+	struct clock_event_device *ced = &per_cpu(cpu_ced, cpu);
+
+	if (!ced || !ced->event_handler)
+		return;
+
+	if (uv_rtc_unset_timer(cpu, 0) != 1)
+		return;
+
+	ced->event_handler(ced);
+}
+
+static int __init uv_enable_evt_rtc(char *str)
+{
+	uv_rtc_evt_enable = 1;
+
+	return 1;
+}
+__setup("uvrtcevt", uv_enable_evt_rtc);
+
+static __init void uv_rtc_register_clockevents(struct work_struct *dummy)
+{
+	struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
+
+	*ced = clock_event_device_uv;
+	ced->cpumask = cpumask_of(smp_processor_id());
+	clockevents_register_device(ced);
+}
+
+static __init int uv_rtc_setup_clock(void)
+{
+	int rc;
+
+	if (!is_uv_system())
+		return -ENODEV;
+
+	clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+				clocksource_uv.shift);
+
+	/* If single blade, prefer tsc */
+	if (uv_num_possible_blades() == 1)
+		clocksource_uv.rating = 250;
+
+	rc = clocksource_register(&clocksource_uv);
+	if (rc)
+		printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
+	else
+		printk(KERN_INFO "UV RTC clocksource registered freq %lu MHz\n",
+			sn_rtc_cycles_per_second/(unsigned long)1E6);
+
+	if (rc || !uv_rtc_evt_enable || x86_platform_ipi_callback)
+		return rc;
+
+	/* Setup and register clockevents */
+	rc = uv_rtc_allocate_timers();
+	if (rc)
+		goto error;
+
+	x86_platform_ipi_callback = uv_rtc_interrupt;
+
+	clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
+				NSEC_PER_SEC, clock_event_device_uv.shift);
+
+	clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
+						sn_rtc_cycles_per_second;
+
+	clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
+				(NSEC_PER_SEC / sn_rtc_cycles_per_second);
+
+	rc = schedule_on_each_cpu(uv_rtc_register_clockevents);
+	if (rc) {
+		x86_platform_ipi_callback = NULL;
+		uv_rtc_deallocate_timers();
+		goto error;
+	}
+
+	printk(KERN_INFO "UV RTC clockevents registered\n");
+
+	return 0;
+
+error:
+	clocksource_unregister(&clocksource_uv);
+	printk(KERN_INFO "UV RTC clockevents failed rc %d\n", rc);
+
+	return rc;
+}
+arch_initcall(uv_rtc_setup_clock);
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/visws/Makefile linux-libre-2.6.37-gnu/arch/x86/platform/visws/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/platform/visws/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/visws/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_X86_VISWS)	+= visws_quirks.o
diff -druN linux-libre-2.6.36-gnu/arch/x86/platform/visws/visws_quirks.c linux-libre-2.6.37-gnu/arch/x86/platform/visws/visws_quirks.c
--- linux-libre-2.6.36-gnu/arch/x86/platform/visws/visws_quirks.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/x86/platform/visws/visws_quirks.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,614 @@
+/*
+ *  SGI Visual Workstation support and quirks, unmaintained.
+ *
+ *  Split out from setup.c by davej@suse.de
+ *
+ *	Copyright (C) 1999 Bent Hagemark, Ingo Molnar
+ *
+ *  SGI Visual Workstation interrupt controller
+ *
+ *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
+ *  which serves as the main interrupt controller in the system.  Non-legacy
+ *  hardware in the system uses this controller directly.  Legacy devices
+ *  are connected to the PIIX4 which in turn has its 8259(s) connected to
+ *  a of the Cobalt APIC entry.
+ *
+ *  09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
+ *
+ *  25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/visws/cobalt.h>
+#include <asm/visws/piix4.h>
+#include <asm/io_apic.h>
+#include <asm/fixmap.h>
+#include <asm/reboot.h>
+#include <asm/setup.h>
+#include <asm/apic.h>
+#include <asm/e820.h>
+#include <asm/time.h>
+#include <asm/io.h>
+
+#include <linux/kernel_stat.h>
+
+#include <asm/i8259.h>
+#include <asm/irq_vectors.h>
+#include <asm/visws/lithium.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+extern int no_broadcast;
+
+char visws_board_type	= -1;
+char visws_board_rev	= -1;
+
+static void __init visws_time_init(void)
+{
+	printk(KERN_INFO "Starting Cobalt Timer system clock\n");
+
+	/* Set the countdown value */
+	co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
+
+	/* Start the timer */
+	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
+
+	/* Enable (unmask) the timer interrupt */
+	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
+
+	setup_default_timer_irq();
+}
+
+/* Replaces the default init_ISA_irqs in the generic setup */
+static void __init visws_pre_intr_init(void);
+
+/* Quirk for machine specific memory setup. */
+
+#define MB (1024 * 1024)
+
+unsigned long sgivwfb_mem_phys;
+unsigned long sgivwfb_mem_size;
+EXPORT_SYMBOL(sgivwfb_mem_phys);
+EXPORT_SYMBOL(sgivwfb_mem_size);
+
+long long mem_size __initdata = 0;
+
+static char * __init visws_memory_setup(void)
+{
+	long long gfx_mem_size = 8 * MB;
+
+	mem_size = boot_params.alt_mem_k;
+
+	if (!mem_size) {
+		printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
+		mem_size = 128 * MB;
+	}
+
+	/*
+	 * this hardcodes the graphics memory to 8 MB
+	 * it really should be sized dynamically (or at least
+	 * set as a boot param)
+	 */
+	if (!sgivwfb_mem_size) {
+		printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
+		sgivwfb_mem_size = 8 * MB;
+	}
+
+	/*
+	 * Trim to nearest MB
+	 */
+	sgivwfb_mem_size &= ~((1 << 20) - 1);
+	sgivwfb_mem_phys = mem_size - gfx_mem_size;
+
+	e820_add_region(0, LOWMEMSIZE(), E820_RAM);
+	e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
+	e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
+
+	return "PROM";
+}
+
+static void visws_machine_emergency_restart(void)
+{
+	/*
+	 * Visual Workstations restart after this
+	 * register is poked on the PIIX4
+	 */
+	outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
+}
+
+static void visws_machine_power_off(void)
+{
+	unsigned short pm_status;
+/*	extern unsigned int pci_bus0; */
+
+	while ((pm_status = inw(PMSTS_PORT)) & 0x100)
+		outw(pm_status, PMSTS_PORT);
+
+	outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
+
+	mdelay(10);
+
+#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
+	(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
+
+/*	outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
+	outl(PIIX_SPECIAL_STOP, 0xCFC);
+}
+
+static void __init visws_get_smp_config(unsigned int early)
+{
+}
+
+/*
+ * The Visual Workstation is Intel MP compliant in the hardware
+ * sense, but it doesn't have a BIOS(-configuration table).
+ * No problem for Linux.
+ */
+
+static void __init MP_processor_info(struct mpc_cpu *m)
+{
+	int ver, logical_apicid;
+	physid_mask_t apic_cpus;
+
+	if (!(m->cpuflag & CPU_ENABLED))
+		return;
+
+	logical_apicid = m->apicid;
+	printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
+	       m->cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
+	       m->apicid, (m->cpufeature & CPU_FAMILY_MASK) >> 8,
+	       (m->cpufeature & CPU_MODEL_MASK) >> 4, m->apicver);
+
+	if (m->cpuflag & CPU_BOOTPROCESSOR)
+		boot_cpu_physical_apicid = m->apicid;
+
+	ver = m->apicver;
+	if ((ver >= 0x14 && m->apicid >= 0xff) || m->apicid >= 0xf) {
+		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
+			m->apicid, MAX_APICS);
+		return;
+	}
+
+	apic->apicid_to_cpu_present(m->apicid, &apic_cpus);
+	physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
+	/*
+	 * Validate version
+	 */
+	if (ver == 0x0) {
+		printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
+			"fixing up to 0x10. (tell your hw vendor)\n",
+			m->apicid);
+		ver = 0x10;
+	}
+	apic_version[m->apicid] = ver;
+}
+
+static void __init visws_find_smp_config(void)
+{
+	struct mpc_cpu *mp = phys_to_virt(CO_CPU_TAB_PHYS);
+	unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
+
+	if (ncpus > CO_CPU_MAX) {
+		printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
+			ncpus, mp);
+
+		ncpus = CO_CPU_MAX;
+	}
+
+	if (ncpus > setup_max_cpus)
+		ncpus = setup_max_cpus;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	smp_found_config = 1;
+#endif
+	while (ncpus--)
+		MP_processor_info(mp++);
+
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+}
+
+static void visws_trap_init(void);
+
+void __init visws_early_detect(void)
+{
+	int raw;
+
+	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
+							 >> PIIX_GPI_BD_SHIFT;
+
+	if (visws_board_type < 0)
+		return;
+
+	/*
+	 * Override the default platform setup functions
+	 */
+	x86_init.resources.memory_setup = visws_memory_setup;
+	x86_init.mpparse.get_smp_config = visws_get_smp_config;
+	x86_init.mpparse.find_smp_config = visws_find_smp_config;
+	x86_init.irqs.pre_vector_init = visws_pre_intr_init;
+	x86_init.irqs.trap_init = visws_trap_init;
+	x86_init.timers.timer_init = visws_time_init;
+	x86_init.pci.init = pci_visws_init;
+	x86_init.pci.init_irq = x86_init_noop;
+
+	/*
+	 * Install reboot quirks:
+	 */
+	pm_power_off			= visws_machine_power_off;
+	machine_ops.emergency_restart	= visws_machine_emergency_restart;
+
+	/*
+	 * Do not use broadcast IPIs:
+	 */
+	no_broadcast = 0;
+
+#ifdef CONFIG_X86_IO_APIC
+	/*
+	 * Turn off IO-APIC detection and initialization:
+	 */
+	skip_ioapic_setup		= 1;
+#endif
+
+	/*
+	 * Get Board rev.
+	 * First, we have to initialize the 307 part to allow us access
+	 * to the GPIO registers.  Let's map them at 0x0fc0 which is right
+	 * after the PIIX4 PM section.
+	 */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
+
+	/*
+	 * Now, we have to map the power management section to write
+	 * a bit which enables access to the GPIO registers.
+	 * What lunatic came up with this shit?
+	 */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable PM registers. */
+
+	/*
+	 * Now, write the PM register which enables the GPIO registers.
+	 */
+	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
+	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
+
+	/*
+	 * Now, initialize the GPIO registers.
+	 * We want them all to be inputs which is the
+	 * power on default, so let's leave them alone.
+	 * So, let's just read the board rev!
+	 */
+	raw = inb_p(SIO_GP_DATA1);
+	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
+
+	if (visws_board_type == VISWS_320) {
+		if (raw < 0x6) {
+			visws_board_rev = 4;
+		} else if (raw < 0xc) {
+			visws_board_rev = 5;
+		} else {
+			visws_board_rev = 6;
+		}
+	} else if (visws_board_type == VISWS_540) {
+			visws_board_rev = 2;
+		} else {
+			visws_board_rev = raw;
+		}
+
+	printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
+	       (visws_board_type == VISWS_320 ? "320" :
+	       (visws_board_type == VISWS_540 ? "540" :
+		"unknown")), visws_board_rev);
+}
+
+#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
+#define BCD (LI_INTB | LI_INTC | LI_INTD)
+#define ALLDEVS (A01234 | BCD)
+
+static __init void lithium_init(void)
+{
+	set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
+	set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
+
+	if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
+	    (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
+		printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
+/*		panic("This machine is not SGI Visual Workstation 320/540"); */
+	}
+
+	if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
+	    (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
+		printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
+/*		panic("This machine is not SGI Visual Workstation 320/540"); */
+	}
+
+	li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
+	li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
+}
+
+static __init void cobalt_init(void)
+{
+	/*
+	 * On normal SMP PC this is used only with SMP, but we have to
+	 * use it and set it up here to start the Cobalt clock
+	 */
+	set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
+	setup_local_APIC();
+	printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
+		(unsigned int)apic_read(APIC_LVR),
+		(unsigned int)apic_read(APIC_ID));
+
+	set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
+	set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
+	printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
+		co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
+
+	/* Enable Cobalt APIC being careful to NOT change the ID! */
+	co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
+
+	printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
+		co_apic_read(CO_APIC_ID));
+}
+
+static void __init visws_trap_init(void)
+{
+	lithium_init();
+	cobalt_init();
+}
+
+/*
+ * IRQ controller / APIC support:
+ */
+
+static DEFINE_SPINLOCK(cobalt_lock);
+
+/*
+ * Set the given Cobalt APIC Redirection Table entry to point
+ * to the given IDT vector/index.
+ */
+static inline void co_apic_set(int entry, int irq)
+{
+	co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
+	co_apic_write(CO_APIC_HI(entry), 0);
+}
+
+/*
+ * Cobalt (IO)-APIC functions to handle PCI devices.
+ */
+static inline int co_apic_ide0_hack(void)
+{
+	extern char visws_board_type;
+	extern char visws_board_rev;
+
+	if (visws_board_type == VISWS_320 && visws_board_rev == 5)
+		return 5;
+	return CO_APIC_IDE0;
+}
+
+static int is_co_apic(unsigned int irq)
+{
+	if (IS_CO_APIC(irq))
+		return CO_APIC(irq);
+
+	switch (irq) {
+		case 0: return CO_APIC_CPU;
+		case CO_IRQ_IDE0: return co_apic_ide0_hack();
+		case CO_IRQ_IDE1: return CO_APIC_IDE1;
+		default: return -1;
+	}
+}
+
+
+/*
+ * This is the SGI Cobalt (IO-)APIC:
+ */
+static void enable_cobalt_irq(struct irq_data *data)
+{
+	co_apic_set(is_co_apic(data->irq), data->irq);
+}
+
+static void disable_cobalt_irq(struct irq_data *data)
+{
+	int entry = is_co_apic(data->irq);
+
+	co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
+	co_apic_read(CO_APIC_LO(entry));
+}
+
+static void ack_cobalt_irq(struct irq_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cobalt_lock, flags);
+	disable_cobalt_irq(data);
+	apic_write(APIC_EOI, APIC_EIO_ACK);
+	spin_unlock_irqrestore(&cobalt_lock, flags);
+}
+
+static struct irq_chip cobalt_irq_type = {
+	.name		= "Cobalt-APIC",
+	.irq_enable	= enable_cobalt_irq,
+	.irq_disable	= disable_cobalt_irq,
+	.irq_ack	= ack_cobalt_irq,
+};
+
+
+/*
+ * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
+ * -- not the manner expected by the code in i8259.c.
+ *
+ * there is a 'master' physical interrupt source that gets sent to
+ * the CPU. But in the chipset there are various 'virtual' interrupts
+ * waiting to be handled. We represent this to Linux through a 'master'
+ * interrupt controller type, and through a special virtual interrupt-
+ * controller. Device drivers only see the virtual interrupt sources.
+ */
+static unsigned int startup_piix4_master_irq(struct irq_data *data)
+{
+	legacy_pic->init(0);
+	enable_cobalt_irq(data);
+}
+
+static void end_piix4_master_irq(struct irq_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&cobalt_lock, flags);
+	enable_cobalt_irq(data);
+	spin_unlock_irqrestore(&cobalt_lock, flags);
+}
+
+static struct irq_chip piix4_master_irq_type = {
+	.name		= "PIIX4-master",
+	.irq_startup	= startup_piix4_master_irq,
+	.irq_ack	= ack_cobalt_irq,
+};
+
+static void pii4_mask(struct irq_data *data) { }
+
+static struct irq_chip piix4_virtual_irq_type = {
+	.name		= "PIIX4-virtual",
+	.mask		= pii4_mask,
+};
+
+/*
+ * PIIX4-8259 master/virtual functions to handle interrupt requests
+ * from legacy devices: floppy, parallel, serial, rtc.
+ *
+ * None of these get Cobalt APIC entries, neither do they have IDT
+ * entries. These interrupts are purely virtual and distributed from
+ * the 'master' interrupt source: CO_IRQ_8259.
+ *
+ * When the 8259 interrupts its handler figures out which of these
+ * devices is interrupting and dispatches to its handler.
+ *
+ * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
+ * enable_irq gets the right irq. This 'master' irq is never directly
+ * manipulated by any driver.
+ */
+static irqreturn_t piix4_master_intr(int irq, void *dev_id)
+{
+	unsigned long flags;
+	int realirq;
+
+	raw_spin_lock_irqsave(&i8259A_lock, flags);
+
+	/* Find out what's interrupting in the PIIX4 master 8259 */
+	outb(0x0c, 0x20);		/* OCW3 Poll command */
+	realirq = inb(0x20);
+
+	/*
+	 * Bit 7 == 0 means invalid/spurious
+	 */
+	if (unlikely(!(realirq & 0x80)))
+		goto out_unlock;
+
+	realirq &= 7;
+
+	if (unlikely(realirq == 2)) {
+		outb(0x0c, 0xa0);
+		realirq = inb(0xa0);
+
+		if (unlikely(!(realirq & 0x80)))
+			goto out_unlock;
+
+		realirq = (realirq & 7) + 8;
+	}
+
+	/* mask and ack interrupt */
+	cached_irq_mask |= 1 << realirq;
+	if (unlikely(realirq > 7)) {
+		inb(0xa1);
+		outb(cached_slave_mask, 0xa1);
+		outb(0x60 + (realirq & 7), 0xa0);
+		outb(0x60 + 2, 0x20);
+	} else {
+		inb(0x21);
+		outb(cached_master_mask, 0x21);
+		outb(0x60 + realirq, 0x20);
+	}
+
+	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
+
+	/*
+	 * handle this 'virtual interrupt' as a Cobalt one now.
+	 */
+	generic_handle_irq(realirq);
+
+	return IRQ_HANDLED;
+
+out_unlock:
+	raw_spin_unlock_irqrestore(&i8259A_lock, flags);
+	return IRQ_NONE;
+}
+
+static struct irqaction master_action = {
+	.handler =	piix4_master_intr,
+	.name =		"PIIX4-8259",
+};
+
+static struct irqaction cascade_action = {
+	.handler = 	no_action,
+	.name =		"cascade",
+};
+
+static inline void set_piix4_virtual_irq_type(void)
+{
+	piix4_virtual_irq_type.enable =	i8259A_chip.unmask;
+	piix4_virtual_irq_type.disable = i8259A_chip.mask;
+	piix4_virtual_irq_type.unmask =	i8259A_chip.unmask;
+}
+
+static void __init visws_pre_intr_init(void)
+{
+	int i;
+
+	set_piix4_virtual_irq_type();
+
+	for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
+		struct irq_chip *chip = NULL;
+
+		if (i == 0)
+			chip = &cobalt_irq_type;
+		else if (i == CO_IRQ_IDE0)
+			chip = &cobalt_irq_type;
+		else if (i == CO_IRQ_IDE1)
+			>chip = &cobalt_irq_type;
+		else if (i == CO_IRQ_8259)
+			chip = &piix4_master_irq_type;
+		else if (i < CO_IRQ_APIC0)
+			chip = &piix4_virtual_irq_type;
+		else if (IS_CO_APIC(i))
+			chip = &cobalt_irq_type;
+
+		if (chip)
+			set_irq_chip(i, chip);
+	}
+
+	setup_irq(CO_IRQ_8259, &master_action);
+	setup_irq(2, &cascade_action);
+}
diff -druN linux-libre-2.6.36-gnu/arch/x86/vdso/Makefile linux-libre-2.6.37-gnu/arch/x86/vdso/Makefile
--- linux-libre-2.6.36-gnu/arch/x86/vdso/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/vdso/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 
 export CPPFLAGS_vdso.lds += -P -C
 
-VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -Wl,-soname=linux-vdso.so.1 \
+VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \
 		      	-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
 
 $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
@@ -69,7 +69,7 @@
 vdso32-images			= $(vdso32.so-y:%=vdso32-%.so)
 
 CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds)
-VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -Wl,-soname=linux-gate.so.1
+VDSO_LDFLAGS_vdso32.lds = -m32 -Wl,-soname=linux-gate.so.1
 
 # This makes sure the $(obj) subdirectory exists even though vdso32/
 # is not a kbuild sub-make subdirectory.
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/debugfs.c linux-libre-2.6.37-gnu/arch/x86/xen/debugfs.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -106,6 +106,7 @@
 	.open	= u32_array_open,
 	.release= xen_array_release,
 	.read	= u32_array_read,
+	.llseek = no_llseek,
 };
 
 struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/enlighten.c linux-libre-2.6.37-gnu/arch/x86/xen/enlighten.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/enlighten.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/enlighten.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 #include <linux/console.h>
 #include <linux/pci.h>
 #include <linux/gfp.h>
+#include <linux/memblock.h>
 
 #include <xen/xen.h>
 #include <xen/interface/xen.h>
@@ -45,6 +46,7 @@
 #include <asm/paravirt.h>
 #include <asm/apic.h>
 #include <asm/page.h>
+#include <asm/xen/pci.h>
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 #include <asm/fixmap.h>
@@ -58,7 +60,6 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/reboot.h>
-#include <asm/setup.h>
 #include <asm/stackprotector.h>
 #include <asm/hypervisor.h>
 
@@ -74,6 +75,11 @@
 enum xen_domain_type xen_domain_type = XEN_NATIVE;
 EXPORT_SYMBOL_GPL(xen_domain_type);
 
+unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
+EXPORT_SYMBOL(machine_to_phys_mapping);
+unsigned int   machine_to_phys_order;
+EXPORT_SYMBOL(machine_to_phys_order);
+
 struct start_info *xen_start_info;
 EXPORT_SYMBOL_GPL(xen_start_info);
 
@@ -135,9 +141,6 @@
 	info.mfn = arbitrary_virt_to_mfn(vcpup);
 	info.offset = offset_in_page(vcpup);
 
-	printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %llx, offset %d\n",
-	       cpu, vcpup, info.mfn, info.offset);
-
 	/* Check to see if the hypervisor will put the vcpu_info
 	   structure where we want it, which allows direct access via
 	   a percpu-variable. */
@@ -151,9 +154,6 @@
 		/* This cpu is using the registered vcpu info, even if
 		   later ones fail to. */
 		per_cpu(xen_vcpu, cpu) = vcpup;
-
-		printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
-		       cpu, vcpup);
 	}
 }
 
@@ -242,6 +242,7 @@
 	cpuid_leaf1_edx_mask =
 		~((1 << X86_FEATURE_MCE)  |  /* disable MCE */
 		  (1 << X86_FEATURE_MCA)  |  /* disable MCA */
+		  (1 << X86_FEATURE_MTRR) |  /* disable MTRR */
 		  (1 << X86_FEATURE_ACC));   /* thermal monitoring */
 
 	if (!xen_initial_domain())
@@ -835,6 +836,11 @@
 		   Xen console noise. */
 		break;
 
+	case MSR_IA32_CR_PAT:
+		if (smp_processor_id() == 0)
+			xen_set_pat(((u64)high << 32) | low);
+		break;
+
 	default:
 		ret = native_write_msr_safe(msr, low, high);
 	}
@@ -873,8 +879,6 @@
 	/* xen_vcpu_setup managed to place the vcpu_info within the
 	   percpu area for all cpus, so make use of it */
 	if (have_vcpu_info_placement) {
-		printk(KERN_INFO "Xen: using vcpu_info placement\n");
-
 		pv_irq_ops.save_fl = __PV_IS_CALLEE_SAVE(xen_save_fl_direct);
 		pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(xen_restore_fl_direct);
 		pv_irq_ops.irq_disable = __PV_IS_CALLEE_SAVE(xen_irq_disable_direct);
@@ -1017,10 +1021,6 @@
 {
 	struct sched_shutdown r = { .reason = reason };
 
-#ifdef CONFIG_SMP
-	smp_send_stop();
-#endif
-
 	if (HYPERVISOR_sched_op(SCHEDOP_shutdown, &r))
 		BUG();
 }
@@ -1091,6 +1091,8 @@
 /* First C function to be called on Xen boot */
 asmlinkage void __init xen_start_kernel(void)
 {
+	struct physdev_set_iopl set_iopl;
+	int rc;
 	pgd_t *pgd;
 
 	if (!xen_start_info)
@@ -1098,6 +1100,8 @@
 
 	xen_domain_type = XEN_PV_DOMAIN;
 
+	xen_setup_machphys_mapping();
+
 	/* Install Xen paravirt ops */
 	pv_info = xen_info;
 	pv_init_ops = xen_init_ops;
@@ -1183,10 +1187,14 @@
 	local_irq_disable();
 	early_boot_irqs_off();
 
+	memblock_init();
+
 	xen_raw_console_write("mapping kernel into physical memory\n");
 	pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
+	xen_ident_map_ISA();
 
-	init_mm.pgd = pgd;
+	/* Allocate and initialize top and mid mfn levels for p2m structure */
+	xen_build_mfn_list_list();
 
 	/* keep using Xen gdt for now; no urgent need to change it */
 
@@ -1197,10 +1205,18 @@
 #else
 	pv_info.kernel_rpl = 0;
 #endif
-
 	/* set the limit of our address space */
 	xen_reserve_top();
 
+	/* We used to do this in xen_arch_setup, but that is too late on AMD
+	 * were early_cpu_init (run before ->arch_setup()) calls early_amd_init
+	 * which pokes 0xcf8 port.
+	 */
+	set_iopl.iopl = 1;
+	rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+	if (rc != 0)
+		xen_raw_printk("physdev_op failed %d\n", rc);
+
 #ifdef CONFIG_X86_32
 	/* set up basic CPUID stuff */
 	cpu_detect(&new_cpu_data);
@@ -1220,6 +1236,8 @@
 		add_preferred_console("xenboot", 0, NULL);
 		add_preferred_console("tty", 0, NULL);
 		add_preferred_console("hvc", 0, NULL);
+		if (pci_xen)
+			x86_init.pci.arch_init = pci_xen_init;
 	} else {
 		/* Make sure ACS will be enabled */
 		pci_request_acs();
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/Kconfig linux-libre-2.6.37-gnu/arch/x86/xen/Kconfig
--- linux-libre-2.6.36-gnu/arch/x86/xen/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -13,21 +13,28 @@
 	  kernel to boot in a paravirtualized environment under the
 	  Xen hypervisor.
 
+config XEN_DOM0
+	def_bool y
+	depends on XEN && PCI_XEN && SWIOTLB_XEN
+	depends on X86_LOCAL_APIC && X86_IO_APIC && ACPI && PCI
+
+# Dummy symbol since people have come to rely on the PRIVILEGED_GUEST
+# name in tools.
+config XEN_PRIVILEGED_GUEST
+	def_bool XEN_DOM0
+
 config XEN_PVHVM
 	def_bool y
 	depends on XEN
 	depends on X86_LOCAL_APIC
 
 config XEN_MAX_DOMAIN_MEMORY
-       int "Maximum allowed size of a domain in gigabytes"
-       default 8 if X86_32
-       default 32 if X86_64
+       int
+       default 128
        depends on XEN
        help
-         The pseudo-physical to machine address array is sized
-         according to the maximum possible memory size of a Xen
-         domain.  This array uses 1 page per gigabyte, so there's no
-         need to be too stingy here.
+         This only affects the sizing of some bss arrays, the unused
+         portions of which are freed.
 
 config XEN_SAVE_RESTORE
        bool
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/mmu.c linux-libre-2.6.37-gnu/arch/x86/xen/mmu.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/mmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/mmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,6 +45,7 @@
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/memblock.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -55,6 +56,8 @@
 #include <asm/e820.h>
 #include <asm/linkage.h>
 #include <asm/page.h>
+#include <asm/init.h>
+#include <asm/pat.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -138,7 +141,8 @@
  * large enough to allocate page table pages to allocate the rest.
  * Each page can map 2MB.
  */
-static pte_t level1_ident_pgt[PTRS_PER_PTE * 4] __page_aligned_bss;
+#define LEVEL1_IDENT_ENTRIES	(PTRS_PER_PTE * 4)
+static RESERVE_BRK_ARRAY(pte_t, level1_ident_pgt, LEVEL1_IDENT_ENTRIES);
 
 #ifdef CONFIG_X86_64
 /* l3 pud for userspace vsyscall mapping */
@@ -169,49 +173,182 @@
  */
 #define USER_LIMIT	((STACK_TOP_MAX + PGDIR_SIZE - 1) & PGDIR_MASK)
 
+/*
+ * Xen leaves the responsibility for maintaining p2m mappings to the
+ * guests themselves, but it must also access and update the p2m array
+ * during suspend/resume when all the pages are reallocated.
+ *
+ * The p2m table is logically a flat array, but we implement it as a
+ * three-level tree to allow the address space to be sparse.
+ *
+ *                               Xen
+ *                                |
+ *     p2m_top              p2m_top_mfn
+ *       /  \                   /   \
+ * p2m_mid p2m_mid	p2m_mid_mfn p2m_mid_mfn
+ *    / \      / \         /           /
+ *  p2m p2m p2m p2m p2m p2m p2m ...
+ *
+ * The p2m_mid_mfn pages are mapped by p2m_top_mfn_p.
+ *
+ * The p2m_top and p2m_top_mfn levels are limited to 1 page, so the
+ * maximum representable pseudo-physical address space is:
+ *  P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE pages
+ *
+ * P2M_PER_PAGE depends on the architecture, as a mfn is always
+ * unsigned long (8 bytes on 64-bit, 4 bytes on 32), leading to
+ * 512 and 1024 entries respectively. 
+ */
 
-#define P2M_ENTRIES_PER_PAGE	(PAGE_SIZE / sizeof(unsigned long))
-#define TOP_ENTRIES		(MAX_DOMAIN_PAGES / P2M_ENTRIES_PER_PAGE)
+unsigned long xen_max_p2m_pfn __read_mostly;
 
-/* Placeholder for holes in the address space */
-static unsigned long p2m_missing[P2M_ENTRIES_PER_PAGE] __page_aligned_data =
-		{ [ 0 ... P2M_ENTRIES_PER_PAGE-1 ] = ~0UL };
+#define P2M_PER_PAGE		(PAGE_SIZE / sizeof(unsigned long))
+#define P2M_MID_PER_PAGE	(PAGE_SIZE / sizeof(unsigned long *))
+#define P2M_TOP_PER_PAGE	(PAGE_SIZE / sizeof(unsigned long **))
 
- /* Array of pointers to pages containing p2m entries */
-static unsigned long *p2m_top[TOP_ENTRIES] __page_aligned_data =
-		{ [ 0 ... TOP_ENTRIES - 1] = &p2m_missing[0] };
+#define MAX_P2M_PFN		(P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE)
 
-/* Arrays of p2m arrays expressed in mfns used for save/restore */
-static unsigned long p2m_top_mfn[TOP_ENTRIES] __page_aligned_bss;
+/* Placeholders for holes in the address space */
+static RESERVE_BRK_ARRAY(unsigned long, p2m_missing, P2M_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_mid_missing, P2M_MID_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_missing_mfn, P2M_MID_PER_PAGE);
 
-static unsigned long p2m_top_mfn_list[TOP_ENTRIES / P2M_ENTRIES_PER_PAGE]
-	__page_aligned_bss;
+static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
+static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
+
+RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
+RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
 
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
-	BUG_ON(pfn >= MAX_DOMAIN_PAGES);
-	return pfn / P2M_ENTRIES_PER_PAGE;
+	BUG_ON(pfn >= MAX_P2M_PFN);
+	return pfn / (P2M_MID_PER_PAGE * P2M_PER_PAGE);
+}
+
+static inline unsigned p2m_mid_index(unsigned long pfn)
+{
+	return (pfn / P2M_PER_PAGE) % P2M_MID_PER_PAGE;
 }
 
 static inline unsigned p2m_index(unsigned long pfn)
 {
-	return pfn % P2M_ENTRIES_PER_PAGE;
+	return pfn % P2M_PER_PAGE;
 }
 
-/* Build the parallel p2m_top_mfn structures */
+static void p2m_top_init(unsigned long ***top)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+		top[i] = p2m_mid_missing;
+}
+
+static void p2m_top_mfn_init(unsigned long *top)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+		top[i] = virt_to_mfn(p2m_mid_missing_mfn);
+}
+
+static void p2m_top_mfn_p_init(unsigned long **top)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_TOP_PER_PAGE; i++)
+		top[i] = p2m_mid_missing_mfn;
+}
+
+static void p2m_mid_init(unsigned long **mid)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_MID_PER_PAGE; i++)
+		mid[i] = p2m_missing;
+}
+
+static void p2m_mid_mfn_init(unsigned long *mid)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_MID_PER_PAGE; i++)
+		mid[i] = virt_to_mfn(p2m_missing);
+}
+
+static void p2m_init(unsigned long *p2m)
+{
+	unsigned i;
+
+	for (i = 0; i < P2M_MID_PER_PAGE; i++)
+		p2m[i] = INVALID_P2M_ENTRY;
+}
+
+/*
+ * Build the parallel p2m_top_mfn and p2m_mid_mfn structures
+ *
+ * This is called both at boot time, and after resuming from suspend:
+ * - At boot time we're called very early, and must use extend_brk()
+ *   to allocate memory.
+ *
+ * - After resume we're called from within stop_machine, but the mfn
+ *   tree should alreay be completely allocated.
+ */
 void xen_build_mfn_list_list(void)
 {
-	unsigned pfn, idx;
+	unsigned long pfn;
 
-	for (pfn = 0; pfn < MAX_DOMAIN_PAGES; pfn += P2M_ENTRIES_PER_PAGE) {
-		unsigned topidx = p2m_top_index(pfn);
+	/* Pre-initialize p2m_top_mfn to be completely missing */
+	if (p2m_top_mfn == NULL) {
+		p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+		p2m_mid_mfn_init(p2m_mid_missing_mfn);
 
-		p2m_top_mfn[topidx] = virt_to_mfn(p2m_top[topidx]);
+		p2m_top_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+		p2m_top_mfn_p_init(p2m_top_mfn_p);
+
+		p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
+		p2m_top_mfn_init(p2m_top_mfn);
+	} else {
+		/* Reinitialise, mfn's all change after migration */
+		p2m_mid_mfn_init(p2m_mid_missing_mfn);
 	}
 
-	for (idx = 0; idx < ARRAY_SIZE(p2m_top_mfn_list); idx++) {
-		unsigned topidx = idx * P2M_ENTRIES_PER_PAGE;
-		p2m_top_mfn_list[idx] = virt_to_mfn(&p2m_top_mfn[topidx]);
+	for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) {
+		unsigned topidx = p2m_top_index(pfn);
+		unsigned mididx = p2m_mid_index(pfn);
+		unsigned long **mid;
+		unsigned long *mid_mfn_p;
+
+		mid = p2m_top[topidx];
+		mid_mfn_p = p2m_top_mfn_p[topidx];
+
+		/* Don't bother allocating any mfn mid levels if
+		 * they're just missing, just update the stored mfn,
+		 * since all could have changed over a migrate.
+		 */
+		if (mid == p2m_mid_missing) {
+			BUG_ON(mididx);
+			BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
+			p2m_top_mfn[topidx] = virt_to_mfn(p2m_mid_missing_mfn);
+			pfn += (P2M_MID_PER_PAGE - 1) * P2M_PER_PAGE;
+			continue;
+		}
+
+		if (mid_mfn_p == p2m_mid_missing_mfn) {
+			/*
+			 * XXX boot-time only!  We should never find
+			 * missing parts of the mfn tree after
+			 * runtime.  extend_brk() will BUG if we call
+			 * it too late.
+			 */
+			mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+			p2m_mid_mfn_init(mid_mfn_p);
+
+			p2m_top_mfn_p[topidx] = mid_mfn_p;
+		}
+
+		p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
+		mid_mfn_p[mididx] = virt_to_mfn(mid[mididx]);
 	}
 }
 
@@ -220,8 +357,8 @@
 	BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
 
 	HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
-		virt_to_mfn(p2m_top_mfn_list);
-	HYPERVISOR_shared_info->arch.max_pfn = xen_start_info->nr_pages;
+		virt_to_mfn(p2m_top_mfn);
+	HYPERVISOR_shared_info->arch.max_pfn = xen_max_p2m_pfn;
 }
 
 /* Set up p2m_top to point to the domain-builder provided p2m pages */
@@ -229,98 +366,176 @@
 {
 	unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
 	unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
-	unsigned pfn;
+	unsigned long pfn;
 
-	for (pfn = 0; pfn < max_pfn; pfn += P2M_ENTRIES_PER_PAGE) {
+	xen_max_p2m_pfn = max_pfn;
+
+	p2m_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+	p2m_init(p2m_missing);
+
+	p2m_mid_missing = extend_brk(PAGE_SIZE, PAGE_SIZE);
+	p2m_mid_init(p2m_mid_missing);
+
+	p2m_top = extend_brk(PAGE_SIZE, PAGE_SIZE);
+	p2m_top_init(p2m_top);
+
+	/*
+	 * The domain builder gives us a pre-constructed p2m array in
+	 * mfn_list for all the pages initially given to us, so we just
+	 * need to graft that into our tree structure.
+	 */
+	for (pfn = 0; pfn < max_pfn; pfn += P2M_PER_PAGE) {
 		unsigned topidx = p2m_top_index(pfn);
+		unsigned mididx = p2m_mid_index(pfn);
 
-		p2m_top[topidx] = &mfn_list[pfn];
-	}
+		if (p2m_top[topidx] == p2m_mid_missing) {
+			unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+			p2m_mid_init(mid);
 
-	xen_build_mfn_list_list();
+			p2m_top[topidx] = mid;
+		}
+
+		p2m_top[topidx][mididx] = &mfn_list[pfn];
+	}
 }
 
 unsigned long get_phys_to_machine(unsigned long pfn)
 {
-	unsigned topidx, idx;
+	unsigned topidx, mididx, idx;
 
-	if (unlikely(pfn >= MAX_DOMAIN_PAGES))
+	if (unlikely(pfn >= MAX_P2M_PFN))
 		return INVALID_P2M_ENTRY;
 
 	topidx = p2m_top_index(pfn);
+	mididx = p2m_mid_index(pfn);
 	idx = p2m_index(pfn);
-	return p2m_top[topidx][idx];
+
+	return p2m_top[topidx][mididx][idx];
 }
 EXPORT_SYMBOL_GPL(get_phys_to_machine);
 
-/* install a  new p2m_top page */
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p)
+static void *alloc_p2m_page(void)
 {
-	unsigned topidx = p2m_top_index(pfn);
-	unsigned long **pfnp, *mfnp;
-	unsigned i;
+	return (void *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
+}
 
-	pfnp = &p2m_top[topidx];
-	mfnp = &p2m_top_mfn[topidx];
+static void free_p2m_page(void *p)
+{
+	free_page((unsigned long)p);
+}
 
-	for (i = 0; i < P2M_ENTRIES_PER_PAGE; i++)
-		p[i] = INVALID_P2M_ENTRY;
+/* 
+ * Fully allocate the p2m structure for a given pfn.  We need to check
+ * that both the top and mid levels are allocated, and make sure the
+ * parallel mfn tree is kept in sync.  We may race with other cpus, so
+ * the new pages are installed with cmpxchg; if we lose the race then
+ * simply free the page we allocated and use the one that's there.
+ */
+static bool alloc_p2m(unsigned long pfn)
+{
+	unsigned topidx, mididx;
+	unsigned long ***top_p, **mid;
+	unsigned long *top_mfn_p, *mid_mfn;
 
-	if (cmpxchg(pfnp, p2m_missing, p) == p2m_missing) {
-		*mfnp = virt_to_mfn(p);
-		return true;
+	topidx = p2m_top_index(pfn);
+	mididx = p2m_mid_index(pfn);
+
+	top_p = &p2m_top[topidx];
+	mid = *top_p;
+
+	if (mid == p2m_mid_missing) {
+		/* Mid level is missing, allocate a new one */
+		mid = alloc_p2m_page();
+		if (!mid)
+			return false;
+
+		p2m_mid_init(mid);
+
+		if (cmpxchg(top_p, p2m_mid_missing, mid) != p2m_mid_missing)
+			free_p2m_page(mid);
 	}
 
-	return false;
-}
+	top_mfn_p = &p2m_top_mfn[topidx];
+	mid_mfn = p2m_top_mfn_p[topidx];
 
-static void alloc_p2m(unsigned long pfn)
-{
-	unsigned long *p;
+	BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
 
-	p = (void *)__get_free_page(GFP_KERNEL | __GFP_NOFAIL);
-	BUG_ON(p == NULL);
+	if (mid_mfn == p2m_mid_missing_mfn) {
+		/* Separately check the mid mfn level */
+		unsigned long missing_mfn;
+		unsigned long mid_mfn_mfn;
 
-	if (!install_p2mtop_page(pfn, p))
-		free_page((unsigned long)p);
+		mid_mfn = alloc_p2m_page();
+		if (!mid_mfn)
+			return false;
+
+		p2m_mid_mfn_init(mid_mfn);
+
+		missing_mfn = virt_to_mfn(p2m_mid_missing_mfn);
+		mid_mfn_mfn = virt_to_mfn(mid_mfn);
+		if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn)
+			free_p2m_page(mid_mfn);
+		else
+			p2m_top_mfn_p[topidx] = mid_mfn;
+	}
+
+	if (p2m_top[topidx][mididx] == p2m_missing) {
+		/* p2m leaf page is missing */
+		unsigned long *p2m;
+
+		p2m = alloc_p2m_page();
+		if (!p2m)
+			return false;
+
+		p2m_init(p2m);
+
+		if (cmpxchg(&mid[mididx], p2m_missing, p2m) != p2m_missing)
+			free_p2m_page(p2m);
+		else
+			mid_mfn[mididx] = virt_to_mfn(p2m);
+	}
+
+	return true;
 }
 
 /* Try to install p2m mapping; fail if intermediate bits missing */
 bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
-	unsigned topidx, idx;
+	unsigned topidx, mididx, idx;
 
-	if (unlikely(pfn >= MAX_DOMAIN_PAGES)) {
+	if (unlikely(pfn >= MAX_P2M_PFN)) {
 		BUG_ON(mfn != INVALID_P2M_ENTRY);
 		return true;
 	}
 
 	topidx = p2m_top_index(pfn);
-	if (p2m_top[topidx] == p2m_missing) {
-		if (mfn == INVALID_P2M_ENTRY)
-			return true;
-		return false;
-	}
-
+	mididx = p2m_mid_index(pfn);
 	idx = p2m_index(pfn);
-	p2m_top[topidx][idx] = mfn;
+
+	if (p2m_top[topidx][mididx] == p2m_missing)
+		return mfn == INVALID_P2M_ENTRY;
+
+	p2m_top[topidx][mididx][idx] = mfn;
 
 	return true;
 }
 
-void set_phys_to_machine(unsigned long pfn, unsigned long mfn)
+bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
 {
 	if (unlikely(xen_feature(XENFEAT_auto_translated_physmap))) {
 		BUG_ON(pfn != mfn && mfn != INVALID_P2M_ENTRY);
-		return;
+		return true;
 	}
 
 	if (unlikely(!__set_phys_to_machine(pfn, mfn)))  {
-		alloc_p2m(pfn);
+		if (!alloc_p2m(pfn))
+			return false;
 
 		if (!__set_phys_to_machine(pfn, mfn))
-			BUG();
+			return false;
 	}
+
+	return true;
 }
 
 unsigned long arbitrary_virt_to_mfn(void *vaddr)
@@ -359,7 +574,8 @@
 	unsigned int level;
 
 	pte = lookup_address(address, &level);
-	BUG_ON(pte == NULL);
+	if (pte == NULL)
+		return;		/* vaddr missing */
 
 	ptev = pte_wrprotect(*pte);
 
@@ -374,7 +590,8 @@
 	unsigned int level;
 
 	pte = lookup_address(address, &level);
-	BUG_ON(pte == NULL);
+	if (pte == NULL)
+		return;		/* vaddr missing */
 
 	ptev = pte_mkwrite(*pte);
 
@@ -395,7 +612,7 @@
 	return pte_flags(pte) & _PAGE_IOMAP;
 }
 
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
 {
 	struct multicall_space mcs;
 	struct mmu_update *u;
@@ -407,10 +624,16 @@
 	u->ptr = arbitrary_virt_to_machine(ptep).maddr;
 	u->val = pte_val_ma(pteval);
 
-	MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_IO);
+	MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
 
 	xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
+EXPORT_SYMBOL_GPL(xen_set_domain_pte);
+
+static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+{
+	xen_set_domain_pte(ptep, pteval, DOMID_IO);
+}
 
 static void xen_extend_mmu_update(const struct mmu_update *update)
 {
@@ -557,7 +780,20 @@
 	if (val & _PAGE_PRESENT) {
 		unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
 		pteval_t flags = val & PTE_FLAGS_MASK;
-		val = ((pteval_t)pfn_to_mfn(pfn) << PAGE_SHIFT) | flags;
+		unsigned long mfn = pfn_to_mfn(pfn);
+
+		/*
+		 * If there's no mfn for the pfn, then just create an
+		 * empty non-present pte.  Unfortunately this loses
+		 * information about the original pfn, so
+		 * pte_mfn_to_pfn is asymmetric.
+		 */
+		if (unlikely(mfn == INVALID_P2M_ENTRY)) {
+			mfn = 0;
+			flags = 0;
+		}
+
+		val = ((pteval_t)mfn << PAGE_SHIFT) | flags;
 	}
 
 	return val;
@@ -579,10 +815,18 @@
 
 pteval_t xen_pte_val(pte_t pte)
 {
-	if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP))
-		return pte.pte;
+	pteval_t pteval = pte.pte;
 
-	return pte_mfn_to_pfn(pte.pte);
+	/* If this is a WC pte, convert back from Xen WC to Linux WC */
+	if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
+		WARN_ON(!pat_enabled);
+		pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
+	}
+
+	if (xen_initial_domain() && (pteval & _PAGE_IOMAP))
+		return pteval;
+
+	return pte_mfn_to_pfn(pteval);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
 
@@ -592,10 +836,48 @@
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val);
 
+/*
+ * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7
+ * are reserved for now, to correspond to the Intel-reserved PAT
+ * types.
+ *
+ * We expect Linux's PAT set as follows:
+ *
+ * Idx  PTE flags        Linux    Xen    Default
+ * 0                     WB       WB     WB
+ * 1            PWT      WC       WT     WT
+ * 2        PCD          UC-      UC-    UC-
+ * 3        PCD PWT      UC       UC     UC
+ * 4    PAT              WB       WC     WB
+ * 5    PAT     PWT      WC       WP     WT
+ * 6    PAT PCD          UC-      UC     UC-
+ * 7    PAT PCD PWT      UC       UC     UC
+ */
+
+void xen_set_pat(u64 pat)
+{
+	/* We expect Linux to use a PAT setting of
+	 * UC UC- WC WB (ignoring the PAT flag) */
+	WARN_ON(pat != 0x0007010600070106ull);
+}
+
 pte_t xen_make_pte(pteval_t pte)
 {
 	phys_addr_t addr = (pte & PTE_PFN_MASK);
 
+	/* If Linux is trying to set a WC pte, then map to the Xen WC.
+	 * If _PAGE_PAT is set, then it probably means it is really
+	 * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
+	 * things work out OK...
+	 *
+	 * (We should never see kernel mappings with _PAGE_PSE set,
+	 * but we could see hugetlbfs mappings, I think.).
+	 */
+	if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) {
+		if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
+			pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
+	}
+
 	/*
 	 * Unprivileged domains are allowed to do IOMAPpings for
 	 * PCI passthrough, but not map ISA space.  The ISA
@@ -1508,13 +1790,25 @@
 #endif
 }
 
-#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
+	unsigned long pfn = pte_pfn(pte);
+
+#ifdef CONFIG_X86_32
 	/* If there's an existing pte, then don't allow _PAGE_RW to be set */
 	if (pte_val_ma(*ptep) & _PAGE_PRESENT)
 		pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
 			       pte_val_ma(pte));
+#endif
+
+	/*
+	 * If the new pfn is within the range of the newly allocated
+	 * kernel pagetable, and it isn't being mapped into an
+	 * early_ioremap fixmap slot, make sure it is RO.
+	 */
+	if (!is_early_ioremap_ptep(ptep) &&
+	    pfn >= e820_table_start && pfn < e820_table_end)
+		pte = pte_wrprotect(pte);
 
 	return pte;
 }
@@ -1527,7 +1821,6 @@
 
 	xen_set_pte(ptep, pte);
 }
-#endif
 
 static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
 {
@@ -1682,6 +1975,7 @@
 	return __ka(m2p(maddr));
 }
 
+/* Set the page permissions on an identity-mapped pages */
 static void set_page_prot(void *addr, pgprot_t prot)
 {
 	unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
@@ -1697,6 +1991,9 @@
 	unsigned ident_pte;
 	unsigned long pfn;
 
+	level1_ident_pgt = extend_brk(sizeof(pte_t) * LEVEL1_IDENT_ENTRIES,
+				      PAGE_SIZE);
+
 	ident_pte = 0;
 	pfn = 0;
 	for (pmdidx = 0; pmdidx < PTRS_PER_PMD && pfn < max_pfn; pmdidx++) {
@@ -1707,7 +2004,7 @@
 			pte_page = m2v(pmd[pmdidx].pmd);
 		else {
 			/* Check for free pte pages */
-			if (ident_pte == ARRAY_SIZE(level1_ident_pgt))
+			if (ident_pte == LEVEL1_IDENT_ENTRIES)
 				break;
 
 			pte_page = &level1_ident_pgt[ident_pte];
@@ -1737,6 +2034,20 @@
 	set_page_prot(pmd, PAGE_KERNEL_RO);
 }
 
+void __init xen_setup_machphys_mapping(void)
+{
+	struct xen_machphys_mapping mapping;
+	unsigned long machine_to_phys_nr_ents;
+
+	if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
+		machine_to_phys_mapping = (unsigned long *)mapping.v_start;
+		machine_to_phys_nr_ents = mapping.max_mfn + 1;
+	} else {
+		machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
+	}
+	machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
+}
+
 #ifdef CONFIG_X86_64
 static void convert_pfn_mfn(void *v)
 {
@@ -1814,7 +2125,7 @@
 	__xen_write_cr3(true, __pa(pgd));
 	xen_mc_issue(PARAVIRT_LAZY_CPU);
 
-	reserve_early(__pa(xen_start_info->pt_base),
+	memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
 		      __pa(xen_start_info->pt_base +
 			   xen_start_info->nr_pt_frames * PAGE_SIZE),
 		      "XEN PAGETABLES");
@@ -1822,45 +2133,88 @@
 	return pgd;
 }
 #else	/* !CONFIG_X86_64 */
-static pmd_t level2_kernel_pgt[PTRS_PER_PMD] __page_aligned_bss;
+static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
+static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
+
+static __init void xen_write_cr3_init(unsigned long cr3)
+{
+	unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
+
+	BUG_ON(read_cr3() != __pa(initial_page_table));
+	BUG_ON(cr3 != __pa(swapper_pg_dir));
+
+	/*
+	 * We are switching to swapper_pg_dir for the first time (from
+	 * initial_page_table) and therefore need to mark that page
+	 * read-only and then pin it.
+	 *
+	 * Xen disallows sharing of kernel PMDs for PAE
+	 * guests. Therefore we must copy the kernel PMD from
+	 * initial_page_table into a new kernel PMD to be used in
+	 * swapper_pg_dir.
+	 */
+	swapper_kernel_pmd =
+		extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
+	memcpy(swapper_kernel_pmd, initial_kernel_pmd,
+	       sizeof(pmd_t) * PTRS_PER_PMD);
+	swapper_pg_dir[KERNEL_PGD_BOUNDARY] =
+		__pgd(__pa(swapper_kernel_pmd) | _PAGE_PRESENT);
+	set_page_prot(swapper_kernel_pmd, PAGE_KERNEL_RO);
+
+	set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
+	xen_write_cr3(cr3);
+	pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, pfn);
+
+	pin_pagetable_pfn(MMUEXT_UNPIN_TABLE,
+			  PFN_DOWN(__pa(initial_page_table)));
+	set_page_prot(initial_page_table, PAGE_KERNEL);
+	set_page_prot(initial_kernel_pmd, PAGE_KERNEL);
+
+	pv_mmu_ops.write_cr3 = &xen_write_cr3;
+}
 
 __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 					 unsigned long max_pfn)
 {
 	pmd_t *kernel_pmd;
 
+	initial_kernel_pmd =
+		extend_brk(sizeof(pmd_t) * PTRS_PER_PMD, PAGE_SIZE);
+
 	max_pfn_mapped = PFN_DOWN(__pa(xen_start_info->pt_base) +
 				  xen_start_info->nr_pt_frames * PAGE_SIZE +
 				  512*1024);
 
 	kernel_pmd = m2v(pgd[KERNEL_PGD_BOUNDARY].pgd);
-	memcpy(level2_kernel_pgt, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
+	memcpy(initial_kernel_pmd, kernel_pmd, sizeof(pmd_t) * PTRS_PER_PMD);
 
-	xen_map_identity_early(level2_kernel_pgt, max_pfn);
+	xen_map_identity_early(initial_kernel_pmd, max_pfn);
 
-	memcpy(swapper_pg_dir, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
-	set_pgd(&swapper_pg_dir[KERNEL_PGD_BOUNDARY],
-			__pgd(__pa(level2_kernel_pgt) | _PAGE_PRESENT));
+	memcpy(initial_page_table, pgd, sizeof(pgd_t) * PTRS_PER_PGD);
+	initial_page_table[KERNEL_PGD_BOUNDARY] =
+		__pgd(__pa(initial_kernel_pmd) | _PAGE_PRESENT);
 
-	set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO);
-	set_page_prot(swapper_pg_dir, PAGE_KERNEL_RO);
+	set_page_prot(initial_kernel_pmd, PAGE_KERNEL_RO);
+	set_page_prot(initial_page_table, PAGE_KERNEL_RO);
 	set_page_prot(empty_zero_page, PAGE_KERNEL_RO);
 
 	pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(pgd)));
 
-	xen_write_cr3(__pa(swapper_pg_dir));
-
-	pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir)));
+	pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE,
+			  PFN_DOWN(__pa(initial_page_table)));
+	xen_write_cr3(__pa(initial_page_table));
 
-	reserve_early(__pa(xen_start_info->pt_base),
+	memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
 		      __pa(xen_start_info->pt_base +
 			   xen_start_info->nr_pt_frames * PAGE_SIZE),
 		      "XEN PAGETABLES");
 
-	return swapper_pg_dir;
+	return initial_page_table;
 }
 #endif	/* CONFIG_X86_64 */
 
+static unsigned char dummy_mapping[PAGE_SIZE] __page_aligned_bss;
+
 static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
 {
 	pte_t pte;
@@ -1881,15 +2235,28 @@
 #else
 	case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE:
 #endif
-#ifdef CONFIG_X86_LOCAL_APIC
-	case FIX_APIC_BASE:	/* maps dummy local APIC */
-#endif
 	case FIX_TEXT_POKE0:
 	case FIX_TEXT_POKE1:
 		/* All local page mappings */
 		pte = pfn_pte(phys, prot);
 		break;
 
+#ifdef CONFIG_X86_LOCAL_APIC
+	case FIX_APIC_BASE:	/* maps dummy local APIC */
+		pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
+		break;
+#endif
+
+#ifdef CONFIG_X86_IO_APIC
+	case FIX_IO_APIC_BASE_0 ... FIX_IO_APIC_BASE_END:
+		/*
+		 * We just don't map the IO APIC - all access is via
+		 * hypercalls.  Keep the address in the pte for reference.
+		 */
+		pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
+		break;
+#endif
+
 	case FIX_PARAVIRT_BOOTMAP:
 		/* This is an MFN, but it isn't an IO mapping from the
 		   IO domain */
@@ -1914,6 +2281,29 @@
 #endif
 }
 
+__init void xen_ident_map_ISA(void)
+{
+	unsigned long pa;
+
+	/*
+	 * If we're dom0, then linear map the ISA machine addresses into
+	 * the kernel's address space.
+	 */
+	if (!xen_initial_domain())
+		return;
+
+	xen_raw_printk("Xen: setup ISA identity maps\n");
+
+	for (pa = ISA_START_ADDRESS; pa < ISA_END_ADDRESS; pa += PAGE_SIZE) {
+		pte_t pte = mfn_pte(PFN_DOWN(pa), PAGE_KERNEL_IO);
+
+		if (HYPERVISOR_update_va_mapping(PAGE_OFFSET + pa, pte, 0))
+			BUG();
+	}
+
+	xen_flush_tlb();
+}
+
 static __init void xen_post_allocator_init(void)
 {
 	pv_mmu_ops.set_pte = xen_set_pte;
@@ -1953,7 +2343,11 @@
 	.write_cr2 = xen_write_cr2,
 
 	.read_cr3 = xen_read_cr3,
+#ifdef CONFIG_X86_32
+	.write_cr3 = xen_write_cr3_init,
+#else
 	.write_cr3 = xen_write_cr3,
+#endif
 
 	.flush_tlb_user = xen_flush_tlb,
 	.flush_tlb_kernel = xen_flush_tlb,
@@ -1969,14 +2363,9 @@
 	.alloc_pte = xen_alloc_pte_init,
 	.release_pte = xen_release_pte_init,
 	.alloc_pmd = xen_alloc_pmd_init,
-	.alloc_pmd_clone = paravirt_nop,
 	.release_pmd = xen_release_pmd_init,
 
-#ifdef CONFIG_X86_64
-	.set_pte = xen_set_pte,
-#else
 	.set_pte = xen_set_pte_init,
-#endif
 	.set_pte_at = xen_set_pte_at,
 	.set_pmd = xen_set_pmd_hyper,
 
@@ -2026,7 +2415,7 @@
 	x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
 	pv_mmu_ops = xen_mmu_ops;
 
-	vmap_lazy_unmap = false;
+	memset(dummy_mapping, 0xff, PAGE_SIZE);
 }
 
 /* Protected by xen_reservation_lock. */
@@ -2259,6 +2648,73 @@
 }
 #endif
 
+#define REMAP_BATCH_SIZE 16
+
+struct remap_data {
+	unsigned long mfn;
+	pgprot_t prot;
+	struct mmu_update *mmu_update;
+};
+
+static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
+				 unsigned long addr, void *data)
+{
+	struct remap_data *rmd = data;
+	pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
+
+	rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+	rmd->mmu_update->val = pte_val_ma(pte);
+	rmd->mmu_update++;
+
+	return 0;
+}
+
+int xen_remap_domain_mfn_range(struct vm_area_struct *vma,
+			       unsigned long addr,
+			       unsigned long mfn, int nr,
+			       pgprot_t prot, unsigned domid)
+{
+	struct remap_data rmd;
+	struct mmu_update mmu_update[REMAP_BATCH_SIZE];
+	int batch;
+	unsigned long range;
+	int err = 0;
+
+	prot = __pgprot(pgprot_val(prot) | _PAGE_IOMAP);
+
+	BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_RESERVED | VM_IO)) ==
+				(VM_PFNMAP | VM_RESERVED | VM_IO)));
+
+	rmd.mfn = mfn;
+	rmd.prot = prot;
+
+	while (nr) {
+		batch = min(REMAP_BATCH_SIZE, nr);
+		range = (unsigned long)batch << PAGE_SHIFT;
+
+		rmd.mmu_update = mmu_update;
+		err = apply_to_page_range(vma->vm_mm, addr, range,
+					  remap_area_mfn_pte_fn, &rmd);
+		if (err)
+			goto out;
+
+		err = -EFAULT;
+		if (HYPERVISOR_mmu_update(mmu_update, batch, NULL, domid) < 0)
+			goto out;
+
+		nr -= batch;
+		addr += range;
+	}
+
+	err = 0;
+out:
+
+	flush_tlb_all();
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
+
 #ifdef CONFIG_XEN_DEBUG_FS
 
 static struct dentry *d_mmu_debug;
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/mmu.h linux-libre-2.6.37-gnu/arch/x86/xen/mmu.h
--- linux-libre-2.6.36-gnu/arch/x86/xen/mmu.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/mmu.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,6 @@
 
 
 bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
-bool install_p2mtop_page(unsigned long pfn, unsigned long *p);
 
 void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/pci-swiotlb-xen.c linux-libre-2.6.37-gnu/arch/x86/xen/pci-swiotlb-xen.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/pci-swiotlb-xen.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/pci-swiotlb-xen.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,12 @@
 /* Glue code to lib/swiotlb-xen.c */
 
 #include <linux/dma-mapping.h>
+#include <linux/pci.h>
 #include <xen/swiotlb-xen.h>
 
 #include <asm/xen/hypervisor.h>
 #include <xen/xen.h>
+#include <asm/iommu_table.h>
 
 int xen_swiotlb __read_mostly;
 
@@ -54,5 +56,12 @@
 	if (xen_swiotlb) {
 		xen_swiotlb_init(1);
 		dma_ops = &xen_swiotlb_dma_ops;
+
+		/* Make sure ACS will be enabled */
+		pci_request_acs();
 	}
 }
+IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
+		  0,
+		  pci_xen_swiotlb_init,
+		  0);
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/platform-pci-unplug.c linux-libre-2.6.37-gnu/arch/x86/xen/platform-pci-unplug.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/platform-pci-unplug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/platform-pci-unplug.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,7 +68,7 @@
 	return 0;
 }
 
-void __init xen_unplug_emulated_devices(void)
+void xen_unplug_emulated_devices(void)
 {
 	int r;
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/setup.c linux-libre-2.6.37-gnu/arch/x86/xen/setup.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/setup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/setup.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
+#include <linux/memblock.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -17,10 +18,11 @@
 #include <asm/xen/hypervisor.h>
 #include <asm/xen/hypercall.h>
 
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/interface/callback.h>
-#include <xen/interface/physdev.h>
 #include <xen/interface/memory.h>
+#include <xen/interface/physdev.h>
 #include <xen/features.h>
 
 #include "xen-ops.h"
@@ -33,6 +35,39 @@
 extern void xen_syscall_target(void);
 extern void xen_syscall32_target(void);
 
+/* Amount of extra memory space we add to the e820 ranges */
+phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
+
+/* 
+ * The maximum amount of extra memory compared to the base size.  The
+ * main scaling factor is the size of struct page.  At extreme ratios
+ * of base:extra, all the base memory can be filled with page
+ * structures for the extra memory, leaving no space for anything
+ * else.
+ * 
+ * 10x seems like a reasonable balance between scaling flexibility and
+ * leaving a practically usable system.
+ */
+#define EXTRA_MEM_RATIO		(10)
+
+static __init void xen_add_extra_mem(unsigned long pages)
+{
+	u64 size = (u64)pages * PAGE_SIZE;
+	u64 extra_start = xen_extra_mem_start + xen_extra_mem_size;
+
+	if (!pages)
+		return;
+
+	e820_add_region(extra_start, size, E820_RAM);
+	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+	memblock_x86_reserve_range(extra_start, extra_start + size, "XEN EXTRA");
+
+	xen_extra_mem_size += size;
+
+	xen_max_p2m_pfn = PFN_DOWN(extra_start + size);
+}
+
 static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
 					      phys_addr_t end_addr)
 {
@@ -82,16 +117,18 @@
 						     const struct e820map *e820)
 {
 	phys_addr_t max_addr = PFN_PHYS(max_pfn);
-	phys_addr_t last_end = 0;
+	phys_addr_t last_end = ISA_END_ADDRESS;
 	unsigned long released = 0;
 	int i;
 
+	/* Free any unused memory above the low 1Mbyte. */
 	for (i = 0; i < e820->nr_map && last_end < max_addr; i++) {
 		phys_addr_t end = e820->map[i].addr;
 		end = min(max_addr, end);
 
-		released += xen_release_chunk(last_end, end);
-		last_end = e820->map[i].addr + e820->map[i].size;
+		if (last_end < end)
+			released += xen_release_chunk(last_end, end);
+		last_end = max(last_end, e820->map[i].addr + e820->map[i].size);
 	}
 
 	if (last_end < max_addr)
@@ -104,21 +141,72 @@
 /**
  * machine_specific_memory_setup - Hook for machine specific memory setup.
  **/
-
 char * __init xen_memory_setup(void)
 {
+	static struct e820entry map[E820MAX] __initdata;
+
 	unsigned long max_pfn = xen_start_info->nr_pages;
+	unsigned long long mem_end;
+	int rc;
+	struct xen_memory_map memmap;
+	unsigned long extra_pages = 0;
+	unsigned long extra_limit;
+	int i;
+	int op;
 
 	max_pfn = min(MAX_DOMAIN_PAGES, max_pfn);
+	mem_end = PFN_PHYS(max_pfn);
+
+	memmap.nr_entries = E820MAX;
+	set_xen_guest_handle(memmap.buffer, map);
+
+	op = xen_initial_domain() ?
+		XENMEM_machine_memory_map :
+		XENMEM_memory_map;
+	rc = HYPERVISOR_memory_op(op, &memmap);
+	if (rc == -ENOSYS) {
+		BUG_ON(xen_initial_domain());
+		memmap.nr_entries = 1;
+		map[0].addr = 0ULL;
+		map[0].size = mem_end;
+		/* 8MB slack (to balance backend allocations). */
+		map[0].size += 8ULL << 20;
+		map[0].type = E820_RAM;
+		rc = 0;
+	}
+	BUG_ON(rc);
 
 	e820.nr_map = 0;
+	xen_extra_mem_start = mem_end;
+	for (i = 0; i < memmap.nr_entries; i++) {
+		unsigned long long end = map[i].addr + map[i].size;
 
-	e820_add_region(0, PFN_PHYS((u64)max_pfn), E820_RAM);
+		if (map[i].type == E820_RAM && end > mem_end) {
+			/* RAM off the end - may be partially included */
+			u64 delta = min(map[i].size, end - mem_end);
+
+			map[i].size -= delta;
+			end -= delta;
+
+			extra_pages += PFN_DOWN(delta);
+		}
+
+		if (map[i].size > 0 && end > xen_extra_mem_start)
+			xen_extra_mem_start = end;
+
+		/* Add region if any remains */
+		if (map[i].size > 0)
+			e820_add_region(map[i].addr, map[i].size, map[i].type);
+	}
 
 	/*
-	 * Even though this is normal, usable memory under Xen, reserve
-	 * ISA memory anyway because too many things think they can poke
+	 * In domU, the ISA region is normal, usable memory, but we
+	 * reserve ISA memory anyway because too many things poke
 	 * about in there.
+	 *
+	 * In Dom0, the host E820 information can leave gaps in the
+	 * ISA range, which would cause us to release those pages.  To
+	 * avoid this, we unconditionally reserve them here.
 	 */
 	e820_add_region(ISA_START_ADDRESS, ISA_END_ADDRESS - ISA_START_ADDRESS,
 			E820_RESERVED);
@@ -129,29 +217,36 @@
 	 *  - xen_start_info
 	 * See comment above "struct start_info" in <xen/interface/xen.h>
 	 */
-	reserve_early(__pa(xen_start_info->mfn_list),
+	memblock_x86_reserve_range(__pa(xen_start_info->mfn_list),
 		      __pa(xen_start_info->pt_base),
 			"XEN START INFO");
 
 	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 
-	xen_return_unused_memory(xen_start_info->nr_pages, &e820);
+	extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
 
-	return "Xen";
-}
+	/*
+	 * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
+	 * factor the base size.  On non-highmem systems, the base
+	 * size is the full initial memory allocation; on highmem it
+	 * is limited to the max size of lowmem, so that it doesn't
+	 * get completely filled.
+	 *
+	 * In principle there could be a problem in lowmem systems if
+	 * the initial memory is also very large with respect to
+	 * lowmem, but we won't try to deal with that here.
+	 */
+	extra_limit = min(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)),
+			  max_pfn + extra_pages);
 
-static void xen_idle(void)
-{
-	local_irq_disable();
+	if (extra_limit >= max_pfn)
+		extra_pages = extra_limit - max_pfn;
+	else
+		extra_pages = 0;
 
-	if (need_resched())
-		local_irq_enable();
-	else {
-		current_thread_info()->status &= ~TS_POLLING;
-		smp_mb__after_clear_bit();
-		safe_halt();
-		current_thread_info()->status |= TS_POLLING;
-	}
+	xen_add_extra_mem(extra_pages);
+
+	return "Xen";
 }
 
 /*
@@ -223,9 +318,6 @@
 
 void __init xen_arch_setup(void)
 {
-	struct physdev_set_iopl set_iopl;
-	int rc;
-
 	xen_panic_handler_init();
 
 	HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
@@ -242,11 +334,6 @@
 	xen_enable_sysenter();
 	xen_enable_syscall();
 
-	set_iopl.iopl = 1;
-	rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
-	if (rc != 0)
-		printk(KERN_INFO "physdev_op failed %d\n", rc);
-
 #ifdef CONFIG_ACPI
 	if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
 		printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
@@ -258,9 +345,11 @@
 	       MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
 	       COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
 
-	pm_idle = xen_idle;
-
-	paravirt_disable_iospace();
+	/* Set up idle, making sure it calls safe_halt() pvop */
+#ifdef CONFIG_X86_32
+	boot_cpu_data.hlt_works_ok = 1;
+#endif
+	pm_idle = default_idle;
 
 	fiddle_vdso();
 }
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/smp.c linux-libre-2.6.37-gnu/arch/x86/xen/smp.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/smp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/smp.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 #include <asm/xen/interface.h>
 #include <asm/xen/hypercall.h>
 
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/events.h>
 
@@ -156,11 +157,35 @@
 {
 	int i, rc;
 
+	if (xen_initial_domain())
+		return;
+
+	for (i = 0; i < nr_cpu_ids; i++) {
+		rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
+		if (rc >= 0) {
+			num_processors++;
+			set_cpu_possible(i, true);
+		}
+	}
+}
+
+static void __init xen_filter_cpu_maps(void)
+{
+	int i, rc;
+
+	if (!xen_initial_domain())
+		return;
+
+	num_processors = 0;
+	disabled_cpus = 0;
 	for (i = 0; i < nr_cpu_ids; i++) {
 		rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
 		if (rc >= 0) {
 			num_processors++;
 			set_cpu_possible(i, true);
+		} else {
+			set_cpu_possible(i, false);
+			set_cpu_present(i, false);
 		}
 	}
 }
@@ -174,6 +199,7 @@
 	   old memory can be recycled */
 	make_lowmem_page_readwrite(xen_initial_gdt);
 
+	xen_filter_cpu_maps();
 	xen_setup_vcpu_info_placement();
 }
 
@@ -400,9 +426,9 @@
 	BUG();
 }
 
-static void xen_smp_send_stop(void)
+static void xen_stop_other_cpus(int wait)
 {
-	smp_call_function(stop_self, NULL, 0);
+	smp_call_function(stop_self, NULL, wait);
 }
 
 static void xen_smp_send_reschedule(int cpu)
@@ -470,7 +496,7 @@
 	.cpu_disable = xen_cpu_disable,
 	.play_dead = xen_play_dead,
 
-	.smp_send_stop = xen_smp_send_stop,
+	.stop_other_cpus = xen_stop_other_cpus,
 	.smp_send_reschedule = xen_smp_send_reschedule,
 
 	.send_call_func_ipi = xen_smp_send_call_function_ipi,
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/spinlock.c linux-libre-2.6.37-gnu/arch/x86/xen/spinlock.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/spinlock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/spinlock.c	2011-01-04 19:50:19.000000000 -0500
@@ -224,7 +224,7 @@
 			goto out;
 		}
 
-		flags = __raw_local_save_flags();
+		flags = arch_local_save_flags();
 		if (irq_enable) {
 			ADD_STATS(taken_slow_irqenable, 1);
 			raw_local_irq_enable();
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/suspend.c linux-libre-2.6.37-gnu/arch/x86/xen/suspend.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/suspend.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/suspend.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
 	int cpu;
 	xen_hvm_init_shared_info();
 	xen_callback_vector();
+	xen_unplug_emulated_devices();
 	if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
 		for_each_online_cpu(cpu) {
 			xen_setup_runstate_info(cpu);
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/time.c linux-libre-2.6.37-gnu/arch/x86/xen/time.c
--- linux-libre-2.6.36-gnu/arch/x86/xen/time.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/time.c	2011-01-04 19:50:19.000000000 -0500
@@ -426,6 +426,8 @@
 {
 	int cpu;
 
+	pvclock_resume();
+
 	if (xen_clockevent != &xen_vcpuop_clockevent)
 		return;
 
diff -druN linux-libre-2.6.36-gnu/arch/x86/xen/xen-ops.h linux-libre-2.6.37-gnu/arch/x86/xen/xen-ops.h
--- linux-libre-2.6.36-gnu/arch/x86/xen/xen-ops.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/x86/xen/xen-ops.h	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,9 @@
 pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
 void xen_ident_map_ISA(void);
 void xen_reserve_top(void);
+extern unsigned long xen_max_p2m_pfn;
+
+void xen_set_pat(u64);
 
 char * __init xen_memory_setup(void);
 void __init xen_arch_setup(void);
@@ -40,7 +43,7 @@
 
 void xen_callback_vector(void);
 void xen_hvm_init_shared_info(void);
-void __init xen_unplug_emulated_devices(void);
+void xen_unplug_emulated_devices(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
 
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/include/asm/irqflags.h linux-libre-2.6.37-gnu/arch/xtensa/include/asm/irqflags.h
--- linux-libre-2.6.36-gnu/arch/xtensa/include/asm/irqflags.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/arch/xtensa/include/asm/irqflags.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,58 @@
+/*
+ * Xtensa IRQ flags handling functions
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IRQFLAGS_H
+#define _XTENSA_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+	unsigned long flags;
+	asm volatile("rsr %0,"__stringify(PS) : "=a" (flags));
+	return flags;
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+	unsigned long flags;
+	asm volatile("rsil %0, "__stringify(LOCKLEVEL)
+		     : "=a" (flags) :: "memory");
+	return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+	arch_local_irq_save();
+}
+
+static inline void arch_local_irq_enable(void)
+{
+	unsigned long flags;
+	asm volatile("rsil %0, 0" : "=a" (flags) :: "memory");
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+	asm volatile("wsr %0, "__stringify(PS)" ; rsync"
+		     :: "a" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+	return (flags & 0xf) != 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+	return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _XTENSA_IRQFLAGS_H */
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/include/asm/pgtable.h linux-libre-2.6.37-gnu/arch/xtensa/include/asm/pgtable.h
--- linux-libre-2.6.36-gnu/arch/xtensa/include/asm/pgtable.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/include/asm/pgtable.h	2011-01-04 19:50:19.000000000 -0500
@@ -324,10 +324,7 @@
 #define pte_offset_kernel(dir,addr) 					\
 	((pte_t*) pmd_page_vaddr(*(dir)) + pte_index(addr))
 #define pte_offset_map(dir,addr)	pte_offset_kernel((dir),(addr))
-#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir),(addr))
-
 #define pte_unmap(pte)		do { } while (0)
-#define pte_unmap_nested(pte)	do { } while (0)
 
 
 /*
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/include/asm/system.h linux-libre-2.6.37-gnu/arch/xtensa/include/asm/system.h
--- linux-libre-2.6.36-gnu/arch/xtensa/include/asm/system.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/include/asm/system.h	2011-01-04 19:50:19.000000000 -0500
@@ -12,41 +12,10 @@
 #define _XTENSA_SYSTEM_H
 
 #include <linux/stringify.h>
+#include <linux/irqflags.h>
 
 #include <asm/processor.h>
 
-/* interrupt control */
-
-#define local_save_flags(x)						\
-	__asm__ __volatile__ ("rsr %0,"__stringify(PS) : "=a" (x));
-#define local_irq_restore(x)	do {					\
-	__asm__ __volatile__ ("wsr %0, "__stringify(PS)" ; rsync" 	\
-	    		      :: "a" (x) : "memory"); } while(0);
-#define local_irq_save(x)	do {					\
-	__asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL) 	\
-	    		      : "=a" (x) :: "memory");} while(0);
-
-static inline void local_irq_disable(void)
-{
-	unsigned long flags;
-	__asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)
-	    		      : "=a" (flags) :: "memory");
-}
-static inline void local_irq_enable(void)
-{
-	unsigned long flags;
-	__asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
-
-}
-
-static inline int irqs_disabled(void)
-{
-	unsigned long flags;
-	local_save_flags(flags);
-	return flags & 0xf;
-}
-
-
 #define smp_read_barrier_depends() do { } while(0)
 #define read_barrier_depends() do { } while(0)
 
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/include/asm/uaccess.h linux-libre-2.6.37-gnu/arch/xtensa/include/asm/uaccess.h
--- linux-libre-2.6.36-gnu/arch/xtensa/include/asm/uaccess.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/include/asm/uaccess.h	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
  * User space memory access functions
  *
  * These routines provide basic accessing functions to the user memory
- * space for the kernel. This header file provides fuctions such as:
+ * space for the kernel. This header file provides functions such as:
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/Kconfig linux-libre-2.6.37-gnu/arch/xtensa/Kconfig
--- linux-libre-2.6.36-gnu/arch/xtensa/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,3 @@
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-
-mainmenu "Linux/Xtensa Kernel Configuration"
-
 config FRAME_POINTER
 	def_bool n
 
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/kernel/irq.c linux-libre-2.6.37-gnu/arch/xtensa/kernel/irq.c
--- linux-libre-2.6.36-gnu/arch/xtensa/kernel/irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/kernel/irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,7 +92,7 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %14s", irq_desc[i].chip->name);
 		seq_printf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
diff -druN linux-libre-2.6.36-gnu/arch/xtensa/kernel/ptrace.c linux-libre-2.6.37-gnu/arch/xtensa/kernel/ptrace.c
--- linux-libre-2.6.36-gnu/arch/xtensa/kernel/ptrace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/arch/xtensa/kernel/ptrace.c	2011-01-04 19:50:19.000000000 -0500
@@ -256,9 +256,11 @@
 	return 0;
 }
 
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request,
+		 unsigned long addr, unsigned long data)
 {
 	int ret = -EPERM;
+	void __user *datap = (void __user *) data;
 
 	switch (request) {
 	case PTRACE_PEEKTEXT:	/* read word at location addr. */
@@ -267,7 +269,7 @@
 		break;
 
 	case PTRACE_PEEKUSR:	/* read register specified by addr. */
-		ret = ptrace_peekusr(child, addr, (void __user *) data);
+		ret = ptrace_peekusr(child, addr, datap);
 		break;
 
 	case PTRACE_POKETEXT:	/* write the word at location addr. */
@@ -280,19 +282,19 @@
 		break;
 
 	case PTRACE_GETREGS:
-		ret = ptrace_getregs(child, (void __user *) data);
+		ret = ptrace_getregs(child, datap);
 		break;
 
 	case PTRACE_SETREGS:
-		ret = ptrace_setregs(child, (void __user *) data);
+		ret = ptrace_setregs(child, datap);
 		break;
 
 	case PTRACE_GETXTREGS:
-		ret = ptrace_getxregs(child, (void __user *) data);
+		ret = ptrace_getxregs(child, datap);
 		break;
 
 	case PTRACE_SETXTREGS:
-		ret = ptrace_setxregs(child, (void __user *) data);
+		ret = ptrace_setxregs(child, datap);
 		break;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/block/blk-barrier.c linux-libre-2.6.37-gnu/block/blk-barrier.c
--- linux-libre-2.6.36-gnu/block/blk-barrier.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-barrier.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,350 +0,0 @@
-/*
- * Functions related to barrier IO handling
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/bio.h>
-#include <linux/blkdev.h>
-#include <linux/gfp.h>
-
-#include "blk.h"
-
-/**
- * blk_queue_ordered - does this queue support ordered writes
- * @q:        the request queue
- * @ordered:  one of QUEUE_ORDERED_*
- *
- * Description:
- *   For journalled file systems, doing ordered writes on a commit
- *   block instead of explicitly doing wait_on_buffer (which is bad
- *   for performance) can be a big win. Block drivers supporting this
- *   feature should call this function and indicate so.
- *
- **/
-int blk_queue_ordered(struct request_queue *q, unsigned ordered)
-{
-	if (ordered != QUEUE_ORDERED_NONE &&
-	    ordered != QUEUE_ORDERED_DRAIN &&
-	    ordered != QUEUE_ORDERED_DRAIN_FLUSH &&
-	    ordered != QUEUE_ORDERED_DRAIN_FUA &&
-	    ordered != QUEUE_ORDERED_TAG &&
-	    ordered != QUEUE_ORDERED_TAG_FLUSH &&
-	    ordered != QUEUE_ORDERED_TAG_FUA) {
-		printk(KERN_ERR "blk_queue_ordered: bad value %d\n", ordered);
-		return -EINVAL;
-	}
-
-	q->ordered = ordered;
-	q->next_ordered = ordered;
-
-	return 0;
-}
-EXPORT_SYMBOL(blk_queue_ordered);
-
-/*
- * Cache flushing for ordered writes handling
- */
-unsigned blk_ordered_cur_seq(struct request_queue *q)
-{
-	if (!q->ordseq)
-		return 0;
-	return 1 << ffz(q->ordseq);
-}
-
-unsigned blk_ordered_req_seq(struct request *rq)
-{
-	struct request_queue *q = rq->q;
-
-	BUG_ON(q->ordseq == 0);
-
-	if (rq == &q->pre_flush_rq)
-		return QUEUE_ORDSEQ_PREFLUSH;
-	if (rq == &q->bar_rq)
-		return QUEUE_ORDSEQ_BAR;
-	if (rq == &q->post_flush_rq)
-		return QUEUE_ORDSEQ_POSTFLUSH;
-
-	/*
-	 * !fs requests don't need to follow barrier ordering.  Always
-	 * put them at the front.  This fixes the following deadlock.
-	 *
-	 * http://thread.gmane.org/gmane.linux.kernel/537473
-	 */
-	if (rq->cmd_type != REQ_TYPE_FS)
-		return QUEUE_ORDSEQ_DRAIN;
-
-	if ((rq->cmd_flags & REQ_ORDERED_COLOR) ==
-	    (q->orig_bar_rq->cmd_flags & REQ_ORDERED_COLOR))
-		return QUEUE_ORDSEQ_DRAIN;
-	else
-		return QUEUE_ORDSEQ_DONE;
-}
-
-bool blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error)
-{
-	struct request *rq;
-
-	if (error && !q->orderr)
-		q->orderr = error;
-
-	BUG_ON(q->ordseq & seq);
-	q->ordseq |= seq;
-
-	if (blk_ordered_cur_seq(q) != QUEUE_ORDSEQ_DONE)
-		return false;
-
-	/*
-	 * Okay, sequence complete.
-	 */
-	q->ordseq = 0;
-	rq = q->orig_bar_rq;
-	__blk_end_request_all(rq, q->orderr);
-	return true;
-}
-
-static void pre_flush_end_io(struct request *rq, int error)
-{
-	elv_completed_request(rq->q, rq);
-	blk_ordered_complete_seq(rq->q, QUEUE_ORDSEQ_PREFLUSH, error);
-}
-
-static void bar_end_io(struct request *rq, int error)
-{
-	elv_completed_request(rq->q, rq);
-	blk_ordered_complete_seq(rq->q, QUEUE_ORDSEQ_BAR, error);
-}
-
-static void post_flush_end_io(struct request *rq, int error)
-{
-	elv_completed_request(rq->q, rq);
-	blk_ordered_complete_seq(rq->q, QUEUE_ORDSEQ_POSTFLUSH, error);
-}
-
-static void queue_flush(struct request_queue *q, unsigned which)
-{
-	struct request *rq;
-	rq_end_io_fn *end_io;
-
-	if (which == QUEUE_ORDERED_DO_PREFLUSH) {
-		rq = &q->pre_flush_rq;
-		end_io = pre_flush_end_io;
-	} else {
-		rq = &q->post_flush_rq;
-		end_io = post_flush_end_io;
-	}
-
-	blk_rq_init(q, rq);
-	rq->cmd_type = REQ_TYPE_FS;
-	rq->cmd_flags = REQ_HARDBARRIER | REQ_FLUSH;
-	rq->rq_disk = q->orig_bar_rq->rq_disk;
-	rq->end_io = end_io;
-
-	elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
-}
-
-static inline bool start_ordered(struct request_queue *q, struct request **rqp)
-{
-	struct request *rq = *rqp;
-	unsigned skip = 0;
-
-	q->orderr = 0;
-	q->ordered = q->next_ordered;
-	q->ordseq |= QUEUE_ORDSEQ_STARTED;
-
-	/*
-	 * For an empty barrier, there's no actual BAR request, which
-	 * in turn makes POSTFLUSH unnecessary.  Mask them off.
-	 */
-	if (!blk_rq_sectors(rq)) {
-		q->ordered &= ~(QUEUE_ORDERED_DO_BAR |
-				QUEUE_ORDERED_DO_POSTFLUSH);
-		/*
-		 * Empty barrier on a write-through device w/ ordered
-		 * tag has no command to issue and without any command
-		 * to issue, ordering by tag can't be used.  Drain
-		 * instead.
-		 */
-		if ((q->ordered & QUEUE_ORDERED_BY_TAG) &&
-		    !(q->ordered & QUEUE_ORDERED_DO_PREFLUSH)) {
-			q->ordered &= ~QUEUE_ORDERED_BY_TAG;
-			q->ordered |= QUEUE_ORDERED_BY_DRAIN;
-		}
-	}
-
-	/* stash away the original request */
-	blk_dequeue_request(rq);
-	q->orig_bar_rq = rq;
-	rq = NULL;
-
-	/*
-	 * Queue ordered sequence.  As we stack them at the head, we
-	 * need to queue in reverse order.  Note that we rely on that
-	 * no fs request uses ELEVATOR_INSERT_FRONT and thus no fs
-	 * request gets inbetween ordered sequence.
-	 */
-	if (q->ordered & QUEUE_ORDERED_DO_POSTFLUSH) {
-		queue_flush(q, QUEUE_ORDERED_DO_POSTFLUSH);
-		rq = &q->post_flush_rq;
-	} else
-		skip |= QUEUE_ORDSEQ_POSTFLUSH;
-
-	if (q->ordered & QUEUE_ORDERED_DO_BAR) {
-		rq = &q->bar_rq;
-
-		/* initialize proxy request and queue it */
-		blk_rq_init(q, rq);
-		if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
-			rq->cmd_flags |= REQ_WRITE;
-		if (q->ordered & QUEUE_ORDERED_DO_FUA)
-			rq->cmd_flags |= REQ_FUA;
-		init_request_from_bio(rq, q->orig_bar_rq->bio);
-		rq->end_io = bar_end_io;
-
-		elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
-	} else
-		skip |= QUEUE_ORDSEQ_BAR;
-
-	if (q->ordered & QUEUE_ORDERED_DO_PREFLUSH) {
-		queue_flush(q, QUEUE_ORDERED_DO_PREFLUSH);
-		rq = &q->pre_flush_rq;
-	} else
-		skip |= QUEUE_ORDSEQ_PREFLUSH;
-
-	if ((q->ordered & QUEUE_ORDERED_BY_DRAIN) && queue_in_flight(q))
-		rq = NULL;
-	else
-		skip |= QUEUE_ORDSEQ_DRAIN;
-
-	*rqp = rq;
-
-	/*
-	 * Complete skipped sequences.  If whole sequence is complete,
-	 * return false to tell elevator that this request is gone.
-	 */
-	return !blk_ordered_complete_seq(q, skip, 0);
-}
-
-bool blk_do_ordered(struct request_queue *q, struct request **rqp)
-{
-	struct request *rq = *rqp;
-	const int is_barrier = rq->cmd_type == REQ_TYPE_FS &&
-				(rq->cmd_flags & REQ_HARDBARRIER);
-
-	if (!q->ordseq) {
-		if (!is_barrier)
-			return true;
-
-		if (q->next_ordered != QUEUE_ORDERED_NONE)
-			return start_ordered(q, rqp);
-		else {
-			/*
-			 * Queue ordering not supported.  Terminate
-			 * with prejudice.
-			 */
-			blk_dequeue_request(rq);
-			__blk_end_request_all(rq, -EOPNOTSUPP);
-			*rqp = NULL;
-			return false;
-		}
-	}
-
-	/*
-	 * Ordered sequence in progress
-	 */
-
-	/* Special requests are not subject to ordering rules. */
-	if (rq->cmd_type != REQ_TYPE_FS &&
-	    rq != &q->pre_flush_rq && rq != &q->post_flush_rq)
-		return true;
-
-	if (q->ordered & QUEUE_ORDERED_BY_TAG) {
-		/* Ordered by tag.  Blocking the next barrier is enough. */
-		if (is_barrier && rq != &q->bar_rq)
-			*rqp = NULL;
-	} else {
-		/* Ordered by draining.  Wait for turn. */
-		WARN_ON(blk_ordered_req_seq(rq) < blk_ordered_cur_seq(q));
-		if (blk_ordered_req_seq(rq) > blk_ordered_cur_seq(q))
-			*rqp = NULL;
-	}
-
-	return true;
-}
-
-static void bio_end_empty_barrier(struct bio *bio, int err)
-{
-	if (err) {
-		if (err == -EOPNOTSUPP)
-			set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-		clear_bit(BIO_UPTODATE, &bio->bi_flags);
-	}
-	if (bio->bi_private)
-		complete(bio->bi_private);
-	bio_put(bio);
-}
-
-/**
- * blkdev_issue_flush - queue a flush
- * @bdev:	blockdev to issue flush for
- * @gfp_mask:	memory allocation flags (for bio_alloc)
- * @error_sector:	error sector
- * @flags:	BLKDEV_IFL_* flags to control behaviour
- *
- * Description:
- *    Issue a flush for the block device in question. Caller can supply
- *    room for storing the error offset in case of a flush error, if they
- *    wish to. If WAIT flag is not passed then caller may check only what
- *    request was pushed in some internal queue for later handling.
- */
-int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
-		sector_t *error_sector, unsigned long flags)
-{
-	DECLARE_COMPLETION_ONSTACK(wait);
-	struct request_queue *q;
-	struct bio *bio;
-	int ret = 0;
-
-	if (bdev->bd_disk == NULL)
-		return -ENXIO;
-
-	q = bdev_get_queue(bdev);
-	if (!q)
-		return -ENXIO;
-
-	/*
-	 * some block devices may not have their queue correctly set up here
-	 * (e.g. loop device without a backing file) and so issuing a flush
-	 * here will panic. Ensure there is a request function before issuing
-	 * the barrier.
-	 */
-	if (!q->make_request_fn)
-		return -ENXIO;
-
-	bio = bio_alloc(gfp_mask, 0);
-	bio->bi_end_io = bio_end_empty_barrier;
-	bio->bi_bdev = bdev;
-	if (test_bit(BLKDEV_WAIT, &flags))
-		bio->bi_private = &wait;
-
-	bio_get(bio);
-	submit_bio(WRITE_BARRIER, bio);
-	if (test_bit(BLKDEV_WAIT, &flags)) {
-		wait_for_completion(&wait);
-		/*
-		 * The driver must store the error location in ->bi_sector, if
-		 * it supports it. For non-stacked drivers, this should be
-		 * copied from blk_rq_pos(rq).
-		 */
-		if (error_sector)
-			*error_sector = bio->bi_sector;
-	}
-
-	if (bio_flagged(bio, BIO_EOPNOTSUPP))
-		ret = -EOPNOTSUPP;
-	else if (!bio_flagged(bio, BIO_UPTODATE))
-		ret = -EIO;
-
-	bio_put(bio);
-	return ret;
-}
-EXPORT_SYMBOL(blkdev_issue_flush);
diff -druN linux-libre-2.6.36-gnu/block/blk-cgroup.c linux-libre-2.6.37-gnu/block/blk-cgroup.c
--- linux-libre-2.6.36-gnu/block/blk-cgroup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-cgroup.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,6 +37,12 @@
 static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
 static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
 
+/* for encoding cft->private value on file */
+#define BLKIOFILE_PRIVATE(x, val)	(((x) << 16) | (val))
+/* What policy owns the file, proportional or throttle */
+#define BLKIOFILE_POLICY(val)		(((val) >> 16) & 0xffff)
+#define BLKIOFILE_ATTR(val)		((val) & 0xffff)
+
 struct cgroup_subsys blkio_subsys = {
 	.name = "blkio",
 	.create = blkiocg_create,
@@ -59,6 +65,27 @@
 	list_add(&pn->node, &blkcg->policy_list);
 }
 
+static inline bool cftype_blkg_same_policy(struct cftype *cft,
+			struct blkio_group *blkg)
+{
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+
+	if (blkg->plid == plid)
+		return 1;
+
+	return 0;
+}
+
+/* Determines if policy node matches cgroup file being accessed */
+static inline bool pn_matches_cftype(struct cftype *cft,
+			struct blkio_policy_node *pn)
+{
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int fileid = BLKIOFILE_ATTR(cft->private);
+
+	return (plid == pn->plid && fileid == pn->fileid);
+}
+
 /* Must be called with blkcg->lock held */
 static inline void blkio_policy_delete_node(struct blkio_policy_node *pn)
 {
@@ -67,12 +94,13 @@
 
 /* Must be called with blkcg->lock held */
 static struct blkio_policy_node *
-blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev)
+blkio_policy_search_node(const struct blkio_cgroup *blkcg, dev_t dev,
+		enum blkio_policy_id plid, int fileid)
 {
 	struct blkio_policy_node *pn;
 
 	list_for_each_entry(pn, &blkcg->policy_list, node) {
-		if (pn->dev == dev)
+		if (pn->dev == dev && pn->plid == plid && pn->fileid == fileid)
 			return pn;
 	}
 
@@ -86,6 +114,67 @@
 }
 EXPORT_SYMBOL_GPL(cgroup_to_blkio_cgroup);
 
+static inline void
+blkio_update_group_weight(struct blkio_group *blkg, unsigned int weight)
+{
+	struct blkio_policy_type *blkiop;
+
+	list_for_each_entry(blkiop, &blkio_list, list) {
+		/* If this policy does not own the blkg, do not send updates */
+		if (blkiop->plid != blkg->plid)
+			continue;
+		if (blkiop->ops.blkio_update_group_weight_fn)
+			blkiop->ops.blkio_update_group_weight_fn(blkg->key,
+							blkg, weight);
+	}
+}
+
+static inline void blkio_update_group_bps(struct blkio_group *blkg, u64 bps,
+				int fileid)
+{
+	struct blkio_policy_type *blkiop;
+
+	list_for_each_entry(blkiop, &blkio_list, list) {
+
+		/* If this policy does not own the blkg, do not send updates */
+		if (blkiop->plid != blkg->plid)
+			continue;
+
+		if (fileid == BLKIO_THROTL_read_bps_device
+		    && blkiop->ops.blkio_update_group_read_bps_fn)
+			blkiop->ops.blkio_update_group_read_bps_fn(blkg->key,
+								blkg, bps);
+
+		if (fileid == BLKIO_THROTL_write_bps_device
+		    && blkiop->ops.blkio_update_group_write_bps_fn)
+			blkiop->ops.blkio_update_group_write_bps_fn(blkg->key,
+								blkg, bps);
+	}
+}
+
+static inline void blkio_update_group_iops(struct blkio_group *blkg,
+			unsigned int iops, int fileid)
+{
+	struct blkio_policy_type *blkiop;
+
+	list_for_each_entry(blkiop, &blkio_list, list) {
+
+		/* If this policy does not own the blkg, do not send updates */
+		if (blkiop->plid != blkg->plid)
+			continue;
+
+		if (fileid == BLKIO_THROTL_read_iops_device
+		    && blkiop->ops.blkio_update_group_read_iops_fn)
+			blkiop->ops.blkio_update_group_read_iops_fn(blkg->key,
+								blkg, iops);
+
+		if (fileid == BLKIO_THROTL_write_iops_device
+		    && blkiop->ops.blkio_update_group_write_iops_fn)
+			blkiop->ops.blkio_update_group_write_iops_fn(blkg->key,
+								blkg,iops);
+	}
+}
+
 /*
  * Add to the appropriate stat variable depending on the request type.
  * This should be called with the blkg->stats_lock held.
@@ -341,7 +430,8 @@
 EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
 
 void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
-			struct blkio_group *blkg, void *key, dev_t dev)
+		struct blkio_group *blkg, void *key, dev_t dev,
+		enum blkio_policy_id plid)
 {
 	unsigned long flags;
 
@@ -350,6 +440,7 @@
 	rcu_assign_pointer(blkg->key, key);
 	blkg->blkcg_id = css_id(&blkcg->css);
 	hlist_add_head_rcu(&blkg->blkcg_node, &blkcg->blkg_list);
+	blkg->plid = plid;
 	spin_unlock_irqrestore(&blkcg->lock, flags);
 	/* Need to take css reference ? */
 	cgroup_path(blkcg->css.cgroup, blkg->path, sizeof(blkg->path));
@@ -408,51 +499,6 @@
 }
 EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
 
-#define SHOW_FUNCTION(__VAR)						\
-static u64 blkiocg_##__VAR##_read(struct cgroup *cgroup,		\
-				       struct cftype *cftype)		\
-{									\
-	struct blkio_cgroup *blkcg;					\
-									\
-	blkcg = cgroup_to_blkio_cgroup(cgroup);				\
-	return (u64)blkcg->__VAR;					\
-}
-
-SHOW_FUNCTION(weight);
-#undef SHOW_FUNCTION
-
-static int
-blkiocg_weight_write(struct cgroup *cgroup, struct cftype *cftype, u64 val)
-{
-	struct blkio_cgroup *blkcg;
-	struct blkio_group *blkg;
-	struct hlist_node *n;
-	struct blkio_policy_type *blkiop;
-	struct blkio_policy_node *pn;
-
-	if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
-		return -EINVAL;
-
-	blkcg = cgroup_to_blkio_cgroup(cgroup);
-	spin_lock(&blkio_list_lock);
-	spin_lock_irq(&blkcg->lock);
-	blkcg->weight = (unsigned int)val;
-
-	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
-		pn = blkio_policy_search_node(blkcg, blkg->dev);
-
-		if (pn)
-			continue;
-
-		list_for_each_entry(blkiop, &blkio_list, list)
-			blkiop->ops.blkio_update_group_weight_fn(blkg,
-					blkcg->weight);
-	}
-	spin_unlock_irq(&blkcg->lock);
-	spin_unlock(&blkio_list_lock);
-	return 0;
-}
-
 static int
 blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
 {
@@ -593,52 +639,6 @@
 	return disk_total;
 }
 
-#define SHOW_FUNCTION_PER_GROUP(__VAR, type, show_total)		\
-static int blkiocg_##__VAR##_read(struct cgroup *cgroup,		\
-		struct cftype *cftype, struct cgroup_map_cb *cb)	\
-{									\
-	struct blkio_cgroup *blkcg;					\
-	struct blkio_group *blkg;					\
-	struct hlist_node *n;						\
-	uint64_t cgroup_total = 0;					\
-									\
-	if (!cgroup_lock_live_group(cgroup))				\
-		return -ENODEV;						\
-									\
-	blkcg = cgroup_to_blkio_cgroup(cgroup);				\
-	rcu_read_lock();						\
-	hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {\
-		if (blkg->dev) {					\
-			spin_lock_irq(&blkg->stats_lock);		\
-			cgroup_total += blkio_get_stat(blkg, cb,	\
-						blkg->dev, type);	\
-			spin_unlock_irq(&blkg->stats_lock);		\
-		}							\
-	}								\
-	if (show_total)							\
-		cb->fill(cb, "Total", cgroup_total);			\
-	rcu_read_unlock();						\
-	cgroup_unlock();						\
-	return 0;							\
-}
-
-SHOW_FUNCTION_PER_GROUP(time, BLKIO_STAT_TIME, 0);
-SHOW_FUNCTION_PER_GROUP(sectors, BLKIO_STAT_SECTORS, 0);
-SHOW_FUNCTION_PER_GROUP(io_service_bytes, BLKIO_STAT_SERVICE_BYTES, 1);
-SHOW_FUNCTION_PER_GROUP(io_serviced, BLKIO_STAT_SERVICED, 1);
-SHOW_FUNCTION_PER_GROUP(io_service_time, BLKIO_STAT_SERVICE_TIME, 1);
-SHOW_FUNCTION_PER_GROUP(io_wait_time, BLKIO_STAT_WAIT_TIME, 1);
-SHOW_FUNCTION_PER_GROUP(io_merged, BLKIO_STAT_MERGED, 1);
-SHOW_FUNCTION_PER_GROUP(io_queued, BLKIO_STAT_QUEUED, 1);
-#ifdef CONFIG_DEBUG_BLK_CGROUP
-SHOW_FUNCTION_PER_GROUP(dequeue, BLKIO_STAT_DEQUEUE, 0);
-SHOW_FUNCTION_PER_GROUP(avg_queue_size, BLKIO_STAT_AVG_QUEUE_SIZE, 0);
-SHOW_FUNCTION_PER_GROUP(group_wait_time, BLKIO_STAT_GROUP_WAIT_TIME, 0);
-SHOW_FUNCTION_PER_GROUP(idle_time, BLKIO_STAT_IDLE_TIME, 0);
-SHOW_FUNCTION_PER_GROUP(empty_time, BLKIO_STAT_EMPTY_TIME, 0);
-#endif
-#undef SHOW_FUNCTION_PER_GROUP
-
 static int blkio_check_dev_num(dev_t dev)
 {
 	int part = 0;
@@ -652,13 +652,14 @@
 }
 
 static int blkio_policy_parse_and_set(char *buf,
-				      struct blkio_policy_node *newpn)
+	struct blkio_policy_node *newpn, enum blkio_policy_id plid, int fileid)
 {
 	char *s[4], *p, *major_s = NULL, *minor_s = NULL;
 	int ret;
 	unsigned long major, minor, temp;
 	int i = 0;
 	dev_t dev;
+	u64 bps, iops;
 
 	memset(s, 0, sizeof(s));
 
@@ -705,12 +706,47 @@
 	if (s[1] == NULL)
 		return -EINVAL;
 
-	ret = strict_strtoul(s[1], 10, &temp);
-	if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
-	    temp > BLKIO_WEIGHT_MAX)
-		return -EINVAL;
+	switch (plid) {
+	case BLKIO_POLICY_PROP:
+		ret = strict_strtoul(s[1], 10, &temp);
+		if (ret || (temp < BLKIO_WEIGHT_MIN && temp > 0) ||
+			temp > BLKIO_WEIGHT_MAX)
+			return -EINVAL;
 
-	newpn->weight =  temp;
+		newpn->plid = plid;
+		newpn->fileid = fileid;
+		newpn->val.weight = temp;
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(fileid) {
+		case BLKIO_THROTL_read_bps_device:
+		case BLKIO_THROTL_write_bps_device:
+			ret = strict_strtoull(s[1], 10, &bps);
+			if (ret)
+				return -EINVAL;
+
+			newpn->plid = plid;
+			newpn->fileid = fileid;
+			newpn->val.bps = bps;
+			break;
+		case BLKIO_THROTL_read_iops_device:
+		case BLKIO_THROTL_write_iops_device:
+			ret = strict_strtoull(s[1], 10, &iops);
+			if (ret)
+				return -EINVAL;
+
+			if (iops > THROTL_IOPS_MAX)
+				return -EINVAL;
+
+			newpn->plid = plid;
+			newpn->fileid = fileid;
+			newpn->val.iops = (unsigned int)iops;
+			break;
+		}
+		break;
+	default:
+		BUG();
+	}
 
 	return 0;
 }
@@ -720,26 +756,180 @@
 {
 	struct blkio_policy_node *pn;
 
-	pn = blkio_policy_search_node(blkcg, dev);
+	pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_PROP,
+				BLKIO_PROP_weight_device);
 	if (pn)
-		return pn->weight;
+		return pn->val.weight;
 	else
 		return blkcg->weight;
 }
 EXPORT_SYMBOL_GPL(blkcg_get_weight);
 
+uint64_t blkcg_get_read_bps(struct blkio_cgroup *blkcg, dev_t dev)
+{
+	struct blkio_policy_node *pn;
 
-static int blkiocg_weight_device_write(struct cgroup *cgrp, struct cftype *cft,
-				       const char *buffer)
+	pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_read_bps_device);
+	if (pn)
+		return pn->val.bps;
+	else
+		return -1;
+}
+
+uint64_t blkcg_get_write_bps(struct blkio_cgroup *blkcg, dev_t dev)
+{
+	struct blkio_policy_node *pn;
+	pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_write_bps_device);
+	if (pn)
+		return pn->val.bps;
+	else
+		return -1;
+}
+
+unsigned int blkcg_get_read_iops(struct blkio_cgroup *blkcg, dev_t dev)
+{
+	struct blkio_policy_node *pn;
+
+	pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_read_iops_device);
+	if (pn)
+		return pn->val.iops;
+	else
+		return -1;
+}
+
+unsigned int blkcg_get_write_iops(struct blkio_cgroup *blkcg, dev_t dev)
+{
+	struct blkio_policy_node *pn;
+	pn = blkio_policy_search_node(blkcg, dev, BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_write_iops_device);
+	if (pn)
+		return pn->val.iops;
+	else
+		return -1;
+}
+
+/* Checks whether user asked for deleting a policy rule */
+static bool blkio_delete_rule_command(struct blkio_policy_node *pn)
+{
+	switch(pn->plid) {
+	case BLKIO_POLICY_PROP:
+		if (pn->val.weight == 0)
+			return 1;
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(pn->fileid) {
+		case BLKIO_THROTL_read_bps_device:
+		case BLKIO_THROTL_write_bps_device:
+			if (pn->val.bps == 0)
+				return 1;
+			break;
+		case BLKIO_THROTL_read_iops_device:
+		case BLKIO_THROTL_write_iops_device:
+			if (pn->val.iops == 0)
+				return 1;
+		}
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+}
+
+static void blkio_update_policy_rule(struct blkio_policy_node *oldpn,
+					struct blkio_policy_node *newpn)
+{
+	switch(oldpn->plid) {
+	case BLKIO_POLICY_PROP:
+		oldpn->val.weight = newpn->val.weight;
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(newpn->fileid) {
+		case BLKIO_THROTL_read_bps_device:
+		case BLKIO_THROTL_write_bps_device:
+			oldpn->val.bps = newpn->val.bps;
+			break;
+		case BLKIO_THROTL_read_iops_device:
+		case BLKIO_THROTL_write_iops_device:
+			oldpn->val.iops = newpn->val.iops;
+		}
+		break;
+	default:
+		BUG();
+	}
+}
+
+/*
+ * Some rules/values in blkg have changed. Propogate those to respective
+ * policies.
+ */
+static void blkio_update_blkg_policy(struct blkio_cgroup *blkcg,
+		struct blkio_group *blkg, struct blkio_policy_node *pn)
+{
+	unsigned int weight, iops;
+	u64 bps;
+
+	switch(pn->plid) {
+	case BLKIO_POLICY_PROP:
+		weight = pn->val.weight ? pn->val.weight :
+				blkcg->weight;
+		blkio_update_group_weight(blkg, weight);
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(pn->fileid) {
+		case BLKIO_THROTL_read_bps_device:
+		case BLKIO_THROTL_write_bps_device:
+			bps = pn->val.bps ? pn->val.bps : (-1);
+			blkio_update_group_bps(blkg, bps, pn->fileid);
+			break;
+		case BLKIO_THROTL_read_iops_device:
+		case BLKIO_THROTL_write_iops_device:
+			iops = pn->val.iops ? pn->val.iops : (-1);
+			blkio_update_group_iops(blkg, iops, pn->fileid);
+			break;
+		}
+		break;
+	default:
+		BUG();
+	}
+}
+
+/*
+ * A policy node rule has been updated. Propogate this update to all the
+ * block groups which might be affected by this update.
+ */
+static void blkio_update_policy_node_blkg(struct blkio_cgroup *blkcg,
+				struct blkio_policy_node *pn)
+{
+	struct blkio_group *blkg;
+	struct hlist_node *n;
+
+	spin_lock(&blkio_list_lock);
+	spin_lock_irq(&blkcg->lock);
+
+	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
+		if (pn->dev != blkg->dev || pn->plid != blkg->plid)
+			continue;
+		blkio_update_blkg_policy(blkcg, blkg, pn);
+	}
+
+	spin_unlock_irq(&blkcg->lock);
+	spin_unlock(&blkio_list_lock);
+}
+
+static int blkiocg_file_write(struct cgroup *cgrp, struct cftype *cft,
+ 				       const char *buffer)
 {
 	int ret = 0;
 	char *buf;
 	struct blkio_policy_node *newpn, *pn;
 	struct blkio_cgroup *blkcg;
-	struct blkio_group *blkg;
 	int keep_newpn = 0;
-	struct hlist_node *n;
-	struct blkio_policy_type *blkiop;
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int fileid = BLKIOFILE_ATTR(cft->private);
 
 	buf = kstrdup(buffer, GFP_KERNEL);
 	if (!buf)
@@ -751,7 +941,7 @@
 		goto free_buf;
 	}
 
-	ret = blkio_policy_parse_and_set(buf, newpn);
+	ret = blkio_policy_parse_and_set(buf, newpn, plid, fileid);
 	if (ret)
 		goto free_newpn;
 
@@ -759,9 +949,9 @@
 
 	spin_lock_irq(&blkcg->lock);
 
-	pn = blkio_policy_search_node(blkcg, newpn->dev);
+	pn = blkio_policy_search_node(blkcg, newpn->dev, plid, fileid);
 	if (!pn) {
-		if (newpn->weight != 0) {
+		if (!blkio_delete_rule_command(newpn)) {
 			blkio_policy_insert_node(blkcg, newpn);
 			keep_newpn = 1;
 		}
@@ -769,33 +959,17 @@
 		goto update_io_group;
 	}
 
-	if (newpn->weight == 0) {
-		/* weight == 0 means deleteing a specific weight */
+	if (blkio_delete_rule_command(newpn)) {
 		blkio_policy_delete_node(pn);
 		spin_unlock_irq(&blkcg->lock);
 		goto update_io_group;
 	}
 	spin_unlock_irq(&blkcg->lock);
 
-	pn->weight = newpn->weight;
+	blkio_update_policy_rule(pn, newpn);
 
 update_io_group:
-	/* update weight for each cfqg */
-	spin_lock(&blkio_list_lock);
-	spin_lock_irq(&blkcg->lock);
-
-	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
-		if (newpn->dev == blkg->dev) {
-			list_for_each_entry(blkiop, &blkio_list, list)
-				blkiop->ops.blkio_update_group_weight_fn(blkg,
-							 newpn->weight ?
-							 newpn->weight :
-							 blkcg->weight);
-		}
-	}
-
-	spin_unlock_irq(&blkcg->lock);
-	spin_unlock(&blkio_list_lock);
+	blkio_update_policy_node_blkg(blkcg, newpn);
 
 free_newpn:
 	if (!keep_newpn)
@@ -805,23 +979,256 @@
 	return ret;
 }
 
-static int blkiocg_weight_device_read(struct cgroup *cgrp, struct cftype *cft,
-				      struct seq_file *m)
+static void
+blkio_print_policy_node(struct seq_file *m, struct blkio_policy_node *pn)
 {
-	struct blkio_cgroup *blkcg;
-	struct blkio_policy_node *pn;
+	switch(pn->plid) {
+		case BLKIO_POLICY_PROP:
+			if (pn->fileid == BLKIO_PROP_weight_device)
+				seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev),
+					MINOR(pn->dev), pn->val.weight);
+			break;
+		case BLKIO_POLICY_THROTL:
+			switch(pn->fileid) {
+			case BLKIO_THROTL_read_bps_device:
+			case BLKIO_THROTL_write_bps_device:
+				seq_printf(m, "%u:%u\t%llu\n", MAJOR(pn->dev),
+					MINOR(pn->dev), pn->val.bps);
+				break;
+			case BLKIO_THROTL_read_iops_device:
+			case BLKIO_THROTL_write_iops_device:
+				seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev),
+					MINOR(pn->dev), pn->val.iops);
+				break;
+			}
+			break;
+		default:
+			BUG();
+	}
+}
 
-	seq_printf(m, "dev\tweight\n");
+/* cgroup files which read their data from policy nodes end up here */
+static void blkio_read_policy_node_files(struct cftype *cft,
+			struct blkio_cgroup *blkcg, struct seq_file *m)
+{
+	struct blkio_policy_node *pn;
 
-	blkcg = cgroup_to_blkio_cgroup(cgrp);
 	if (!list_empty(&blkcg->policy_list)) {
 		spin_lock_irq(&blkcg->lock);
 		list_for_each_entry(pn, &blkcg->policy_list, node) {
-			seq_printf(m, "%u:%u\t%u\n", MAJOR(pn->dev),
-				   MINOR(pn->dev), pn->weight);
+			if (!pn_matches_cftype(cft, pn))
+				continue;
+			blkio_print_policy_node(m, pn);
 		}
 		spin_unlock_irq(&blkcg->lock);
 	}
+}
+
+static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
+				struct seq_file *m)
+{
+	struct blkio_cgroup *blkcg;
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int name = BLKIOFILE_ATTR(cft->private);
+
+	blkcg = cgroup_to_blkio_cgroup(cgrp);
+
+	switch(plid) {
+	case BLKIO_POLICY_PROP:
+		switch(name) {
+		case BLKIO_PROP_weight_device:
+			blkio_read_policy_node_files(cft, blkcg, m);
+			return 0;
+		default:
+			BUG();
+		}
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(name){
+		case BLKIO_THROTL_read_bps_device:
+		case BLKIO_THROTL_write_bps_device:
+		case BLKIO_THROTL_read_iops_device:
+		case BLKIO_THROTL_write_iops_device:
+			blkio_read_policy_node_files(cft, blkcg, m);
+			return 0;
+		default:
+			BUG();
+		}
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+}
+
+static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
+		struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type,
+		bool show_total)
+{
+	struct blkio_group *blkg;
+	struct hlist_node *n;
+	uint64_t cgroup_total = 0;
+
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(blkg, n, &blkcg->blkg_list, blkcg_node) {
+		if (blkg->dev) {
+			if (!cftype_blkg_same_policy(cft, blkg))
+				continue;
+			spin_lock_irq(&blkg->stats_lock);
+			cgroup_total += blkio_get_stat(blkg, cb, blkg->dev,
+						type);
+			spin_unlock_irq(&blkg->stats_lock);
+		}
+	}
+	if (show_total)
+		cb->fill(cb, "Total", cgroup_total);
+	rcu_read_unlock();
+	return 0;
+}
+
+/* All map kind of cgroup file get serviced by this function */
+static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
+				struct cgroup_map_cb *cb)
+{
+	struct blkio_cgroup *blkcg;
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int name = BLKIOFILE_ATTR(cft->private);
+
+	blkcg = cgroup_to_blkio_cgroup(cgrp);
+
+	switch(plid) {
+	case BLKIO_POLICY_PROP:
+		switch(name) {
+		case BLKIO_PROP_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_TIME, 0);
+		case BLKIO_PROP_sectors:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SECTORS, 0);
+		case BLKIO_PROP_io_service_bytes:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SERVICE_BYTES, 1);
+		case BLKIO_PROP_io_serviced:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SERVICED, 1);
+		case BLKIO_PROP_io_service_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SERVICE_TIME, 1);
+		case BLKIO_PROP_io_wait_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_WAIT_TIME, 1);
+		case BLKIO_PROP_io_merged:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_MERGED, 1);
+		case BLKIO_PROP_io_queued:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_QUEUED, 1);
+#ifdef CONFIG_DEBUG_BLK_CGROUP
+		case BLKIO_PROP_dequeue:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_DEQUEUE, 0);
+		case BLKIO_PROP_avg_queue_size:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_AVG_QUEUE_SIZE, 0);
+		case BLKIO_PROP_group_wait_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_GROUP_WAIT_TIME, 0);
+		case BLKIO_PROP_idle_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_IDLE_TIME, 0);
+		case BLKIO_PROP_empty_time:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_EMPTY_TIME, 0);
+#endif
+		default:
+			BUG();
+		}
+		break;
+	case BLKIO_POLICY_THROTL:
+		switch(name){
+		case BLKIO_THROTL_io_service_bytes:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SERVICE_BYTES, 1);
+		case BLKIO_THROTL_io_serviced:
+			return blkio_read_blkg_stats(blkcg, cft, cb,
+						BLKIO_STAT_SERVICED, 1);
+		default:
+			BUG();
+		}
+		break;
+	default:
+		BUG();
+	}
+
+	return 0;
+}
+
+static int blkio_weight_write(struct blkio_cgroup *blkcg, u64 val)
+{
+	struct blkio_group *blkg;
+	struct hlist_node *n;
+	struct blkio_policy_node *pn;
+
+	if (val < BLKIO_WEIGHT_MIN || val > BLKIO_WEIGHT_MAX)
+		return -EINVAL;
+
+	spin_lock(&blkio_list_lock);
+	spin_lock_irq(&blkcg->lock);
+	blkcg->weight = (unsigned int)val;
+
+	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
+		pn = blkio_policy_search_node(blkcg, blkg->dev,
+				BLKIO_POLICY_PROP, BLKIO_PROP_weight_device);
+		if (pn)
+			continue;
+
+		blkio_update_group_weight(blkg, blkcg->weight);
+	}
+	spin_unlock_irq(&blkcg->lock);
+	spin_unlock(&blkio_list_lock);
+	return 0;
+}
+
+static u64 blkiocg_file_read_u64 (struct cgroup *cgrp, struct cftype *cft) {
+	struct blkio_cgroup *blkcg;
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int name = BLKIOFILE_ATTR(cft->private);
+
+	blkcg = cgroup_to_blkio_cgroup(cgrp);
+
+	switch(plid) {
+	case BLKIO_POLICY_PROP:
+		switch(name) {
+		case BLKIO_PROP_weight:
+			return (u64)blkcg->weight;
+		}
+		break;
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+static int
+blkiocg_file_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
+{
+	struct blkio_cgroup *blkcg;
+	enum blkio_policy_id plid = BLKIOFILE_POLICY(cft->private);
+	int name = BLKIOFILE_ATTR(cft->private);
+
+	blkcg = cgroup_to_blkio_cgroup(cgrp);
+
+	switch(plid) {
+	case BLKIO_POLICY_PROP:
+		switch(name) {
+		case BLKIO_PROP_weight:
+			return blkio_weight_write(blkcg, val);
+		}
+		break;
+	default:
+		BUG();
+	}
 
 	return 0;
 }
@@ -829,71 +1236,151 @@
 struct cftype blkio_files[] = {
 	{
 		.name = "weight_device",
-		.read_seq_string = blkiocg_weight_device_read,
-		.write_string = blkiocg_weight_device_write,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_weight_device),
+		.read_seq_string = blkiocg_file_read,
+		.write_string = blkiocg_file_write,
 		.max_write_len = 256,
 	},
 	{
 		.name = "weight",
-		.read_u64 = blkiocg_weight_read,
-		.write_u64 = blkiocg_weight_write,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_weight),
+		.read_u64 = blkiocg_file_read_u64,
+		.write_u64 = blkiocg_file_write_u64,
 	},
 	{
 		.name = "time",
-		.read_map = blkiocg_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "sectors",
-		.read_map = blkiocg_sectors_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_sectors),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_service_bytes",
-		.read_map = blkiocg_io_service_bytes_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_service_bytes),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_serviced",
-		.read_map = blkiocg_io_serviced_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_serviced),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_service_time",
-		.read_map = blkiocg_io_service_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_service_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_wait_time",
-		.read_map = blkiocg_io_wait_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_wait_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_merged",
-		.read_map = blkiocg_io_merged_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_merged),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "io_queued",
-		.read_map = blkiocg_io_queued_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_io_queued),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "reset_stats",
 		.write_u64 = blkiocg_reset_stats,
 	},
+#ifdef CONFIG_BLK_DEV_THROTTLING
+	{
+		.name = "throttle.read_bps_device",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_read_bps_device),
+		.read_seq_string = blkiocg_file_read,
+		.write_string = blkiocg_file_write,
+		.max_write_len = 256,
+	},
+
+	{
+		.name = "throttle.write_bps_device",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_write_bps_device),
+		.read_seq_string = blkiocg_file_read,
+		.write_string = blkiocg_file_write,
+		.max_write_len = 256,
+	},
+
+	{
+		.name = "throttle.read_iops_device",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_read_iops_device),
+		.read_seq_string = blkiocg_file_read,
+		.write_string = blkiocg_file_write,
+		.max_write_len = 256,
+	},
+
+	{
+		.name = "throttle.write_iops_device",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_write_iops_device),
+		.read_seq_string = blkiocg_file_read,
+		.write_string = blkiocg_file_write,
+		.max_write_len = 256,
+	},
+	{
+		.name = "throttle.io_service_bytes",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_io_service_bytes),
+		.read_map = blkiocg_file_read_map,
+	},
+	{
+		.name = "throttle.io_serviced",
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_THROTL,
+				BLKIO_THROTL_io_serviced),
+		.read_map = blkiocg_file_read_map,
+	},
+#endif /* CONFIG_BLK_DEV_THROTTLING */
+
 #ifdef CONFIG_DEBUG_BLK_CGROUP
 	{
 		.name = "avg_queue_size",
-		.read_map = blkiocg_avg_queue_size_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_avg_queue_size),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "group_wait_time",
-		.read_map = blkiocg_group_wait_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_group_wait_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "idle_time",
-		.read_map = blkiocg_idle_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_idle_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "empty_time",
-		.read_map = blkiocg_empty_time_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_empty_time),
+		.read_map = blkiocg_file_read_map,
 	},
 	{
 		.name = "dequeue",
-		.read_map = blkiocg_dequeue_read,
+		.private = BLKIOFILE_PRIVATE(BLKIO_POLICY_PROP,
+				BLKIO_PROP_dequeue),
+		.read_map = blkiocg_file_read_map,
 	},
 #endif
 };
@@ -932,13 +1419,14 @@
 		/*
 		 * This blkio_group is being unlinked as associated cgroup is
 		 * going away. Let all the IO controlling policies know about
-		 * this event. Currently this is static call to one io
-		 * controlling policy. Once we have more policies in place, we
-		 * need some dynamic registration of callback function.
+		 * this event.
 		 */
 		spin_lock(&blkio_list_lock);
-		list_for_each_entry(blkiop, &blkio_list, list)
+		list_for_each_entry(blkiop, &blkio_list, list) {
+			if (blkiop->plid != blkg->plid)
+				continue;
 			blkiop->ops.blkio_unlink_group_fn(key, blkg);
+		}
 		spin_unlock(&blkio_list_lock);
 	} while (1);
 
diff -druN linux-libre-2.6.36-gnu/block/blk-cgroup.h linux-libre-2.6.37-gnu/block/blk-cgroup.h
--- linux-libre-2.6.36-gnu/block/blk-cgroup.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-cgroup.h	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,14 @@
 
 #include <linux/cgroup.h>
 
+enum blkio_policy_id {
+	BLKIO_POLICY_PROP = 0,		/* Proportional Bandwidth division */
+	BLKIO_POLICY_THROTL,		/* Throttling */
+};
+
+/* Max limits for throttle policy */
+#define THROTL_IOPS_MAX		UINT_MAX
+
 #if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
 
 #ifndef CONFIG_BLK_CGROUP
@@ -65,6 +73,35 @@
 	BLKG_empty,
 };
 
+/* cgroup files owned by proportional weight policy */
+enum blkcg_file_name_prop {
+	BLKIO_PROP_weight = 1,
+	BLKIO_PROP_weight_device,
+	BLKIO_PROP_io_service_bytes,
+	BLKIO_PROP_io_serviced,
+	BLKIO_PROP_time,
+	BLKIO_PROP_sectors,
+	BLKIO_PROP_io_service_time,
+	BLKIO_PROP_io_wait_time,
+	BLKIO_PROP_io_merged,
+	BLKIO_PROP_io_queued,
+	BLKIO_PROP_avg_queue_size,
+	BLKIO_PROP_group_wait_time,
+	BLKIO_PROP_idle_time,
+	BLKIO_PROP_empty_time,
+	BLKIO_PROP_dequeue,
+};
+
+/* cgroup files owned by throttle policy */
+enum blkcg_file_name_throtl {
+	BLKIO_THROTL_read_bps_device,
+	BLKIO_THROTL_write_bps_device,
+	BLKIO_THROTL_read_iops_device,
+	BLKIO_THROTL_write_iops_device,
+	BLKIO_THROTL_io_service_bytes,
+	BLKIO_THROTL_io_serviced,
+};
+
 struct blkio_cgroup {
 	struct cgroup_subsys_state css;
 	unsigned int weight;
@@ -112,6 +149,8 @@
 	char path[128];
 	/* The device MKDEV(major, minor), this group has been created for */
 	dev_t dev;
+	/* policy which owns this blk group */
+	enum blkio_policy_id plid;
 
 	/* Need to serialize the stats in the case of reset/update */
 	spinlock_t stats_lock;
@@ -121,24 +160,60 @@
 struct blkio_policy_node {
 	struct list_head node;
 	dev_t dev;
-	unsigned int weight;
+	/* This node belongs to max bw policy or porportional weight policy */
+	enum blkio_policy_id plid;
+	/* cgroup file to which this rule belongs to */
+	int fileid;
+
+	union {
+		unsigned int weight;
+		/*
+		 * Rate read/write in terms of byptes per second
+		 * Whether this rate represents read or write is determined
+		 * by file type "fileid".
+		 */
+		u64 bps;
+		unsigned int iops;
+	} val;
 };
 
 extern unsigned int blkcg_get_weight(struct blkio_cgroup *blkcg,
 				     dev_t dev);
+extern uint64_t blkcg_get_read_bps(struct blkio_cgroup *blkcg,
+				     dev_t dev);
+extern uint64_t blkcg_get_write_bps(struct blkio_cgroup *blkcg,
+				     dev_t dev);
+extern unsigned int blkcg_get_read_iops(struct blkio_cgroup *blkcg,
+				     dev_t dev);
+extern unsigned int blkcg_get_write_iops(struct blkio_cgroup *blkcg,
+				     dev_t dev);
 
 typedef void (blkio_unlink_group_fn) (void *key, struct blkio_group *blkg);
-typedef void (blkio_update_group_weight_fn) (struct blkio_group *blkg,
-						unsigned int weight);
+
+typedef void (blkio_update_group_weight_fn) (void *key,
+			struct blkio_group *blkg, unsigned int weight);
+typedef void (blkio_update_group_read_bps_fn) (void * key,
+			struct blkio_group *blkg, u64 read_bps);
+typedef void (blkio_update_group_write_bps_fn) (void *key,
+			struct blkio_group *blkg, u64 write_bps);
+typedef void (blkio_update_group_read_iops_fn) (void *key,
+			struct blkio_group *blkg, unsigned int read_iops);
+typedef void (blkio_update_group_write_iops_fn) (void *key,
+			struct blkio_group *blkg, unsigned int write_iops);
 
 struct blkio_policy_ops {
 	blkio_unlink_group_fn *blkio_unlink_group_fn;
 	blkio_update_group_weight_fn *blkio_update_group_weight_fn;
+	blkio_update_group_read_bps_fn *blkio_update_group_read_bps_fn;
+	blkio_update_group_write_bps_fn *blkio_update_group_write_bps_fn;
+	blkio_update_group_read_iops_fn *blkio_update_group_read_iops_fn;
+	blkio_update_group_write_iops_fn *blkio_update_group_write_iops_fn;
 };
 
 struct blkio_policy_type {
 	struct list_head list;
 	struct blkio_policy_ops ops;
+	enum blkio_policy_id plid;
 };
 
 /* Blkio controller policy registration */
@@ -212,7 +287,8 @@
 extern struct blkio_cgroup blkio_root_cgroup;
 extern struct blkio_cgroup *cgroup_to_blkio_cgroup(struct cgroup *cgroup);
 extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
-			struct blkio_group *blkg, void *key, dev_t dev);
+	struct blkio_group *blkg, void *key, dev_t dev,
+	enum blkio_policy_id plid);
 extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
 extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
 						void *key);
@@ -234,7 +310,8 @@
 cgroup_to_blkio_cgroup(struct cgroup *cgroup) { return NULL; }
 
 static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
-			struct blkio_group *blkg, void *key, dev_t dev) {}
+		struct blkio_group *blkg, void *key, dev_t dev,
+		enum blkio_policy_id plid) {}
 
 static inline int
 blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
diff -druN linux-libre-2.6.36-gnu/block/blk-core.c linux-libre-2.6.37-gnu/block/blk-core.c
--- linux-libre-2.6.36-gnu/block/blk-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-core.c	2011-01-04 19:50:19.000000000 -0500
@@ -136,7 +136,7 @@
 {
 	struct request_queue *q = rq->q;
 
-	if (&q->bar_rq != rq) {
+	if (&q->flush_rq != rq) {
 		if (error)
 			clear_bit(BIO_UPTODATE, &bio->bi_flags);
 		else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
@@ -160,13 +160,12 @@
 		if (bio->bi_size == 0)
 			bio_endio(bio, error);
 	} else {
-
 		/*
-		 * Okay, this is the barrier request in progress, just
-		 * record the error;
+		 * Okay, this is the sequenced flush request in
+		 * progress, just record the error;
 		 */
-		if (error && !q->orderr)
-			q->orderr = error;
+		if (error && !q->flush_err)
+			q->flush_err = error;
 	}
 }
 
@@ -382,6 +381,7 @@
 	del_timer_sync(&q->unplug_timer);
 	del_timer_sync(&q->timeout);
 	cancel_work_sync(&q->unplug_work);
+	throtl_shutdown_timer_wq(q);
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -515,11 +515,17 @@
 		return NULL;
 	}
 
+	if (blk_throtl_init(q)) {
+		kmem_cache_free(blk_requestq_cachep, q);
+		return NULL;
+	}
+
 	setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
 		    laptop_mode_timer_fn, (unsigned long) q);
 	init_timer(&q->unplug_timer);
 	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
 	INIT_LIST_HEAD(&q->timeout_list);
+	INIT_LIST_HEAD(&q->pending_flushes);
 	INIT_WORK(&q->unplug_work, blk_unplug_work);
 
 	kobject_init(&q->kobj, &blk_queue_ktype);
@@ -1037,22 +1043,6 @@
 }
 EXPORT_SYMBOL(blk_insert_request);
 
-/*
- * add-request adds a request to the linked list.
- * queue lock is held and interrupts disabled, as we muck with the
- * request queue list.
- */
-static inline void add_request(struct request_queue *q, struct request *req)
-{
-	drive_stat_acct(req, 1);
-
-	/*
-	 * elevator indicated where it wants this request to be
-	 * inserted at elevator_merge time
-	 */
-	__elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0);
-}
-
 static void part_round_stats_single(int cpu, struct hd_struct *part,
 				    unsigned long now)
 {
@@ -1201,13 +1191,9 @@
 	const bool sync = !!(bio->bi_rw & REQ_SYNC);
 	const bool unplug = !!(bio->bi_rw & REQ_UNPLUG);
 	const unsigned long ff = bio->bi_rw & REQ_FAILFAST_MASK;
+	int where = ELEVATOR_INSERT_SORT;
 	int rw_flags;
 
-	if ((bio->bi_rw & REQ_HARDBARRIER) &&
-	    (q->next_ordered == QUEUE_ORDERED_NONE)) {
-		bio_endio(bio, -EOPNOTSUPP);
-		return 0;
-	}
 	/*
 	 * low level driver can indicate that it wants pages above a
 	 * certain limit bounced to low memory (ie for highmem, or even
@@ -1217,7 +1203,12 @@
 
 	spin_lock_irq(q->queue_lock);
 
-	if (unlikely((bio->bi_rw & REQ_HARDBARRIER)) || elv_queue_empty(q))
+	if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
+		where = ELEVATOR_INSERT_FRONT;
+		goto get_rq;
+	}
+
+	if (elv_queue_empty(q))
 		goto get_rq;
 
 	el_ret = elv_merge(q, &req, bio);
@@ -1314,7 +1305,10 @@
 		req->cpu = blk_cpu_to_group(smp_processor_id());
 	if (queue_should_plug(q) && elv_queue_empty(q))
 		blk_plug_device(q);
-	add_request(q, req);
+
+	/* insert the request into the elevator */
+	drive_stat_acct(req, 1);
+	__elv_add_request(q, req, where, 0);
 out:
 	if (unplug || !queue_should_plug(q))
 		__generic_unplug_device(q);
@@ -1350,7 +1344,7 @@
 			bdevname(bio->bi_bdev, b),
 			bio->bi_rw,
 			(unsigned long long)bio->bi_sector + bio_sectors(bio),
-			(long long)(bio->bi_bdev->bd_inode->i_size >> 9));
+			(long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9));
 
 	set_bit(BIO_EOF, &bio->bi_flags);
 }
@@ -1403,7 +1397,7 @@
 		return 0;
 
 	/* Test device or partition size, when known. */
-	maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+	maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
 	if (maxsector) {
 		sector_t sector = bio->bi_sector;
 
@@ -1514,6 +1508,19 @@
 		if (bio_check_eod(bio, nr_sectors))
 			goto end_io;
 
+		/*
+		 * Filter flush bio's early so that make_request based
+		 * drivers without flush support don't have to worry
+		 * about them.
+		 */
+		if ((bio->bi_rw & (REQ_FLUSH | REQ_FUA)) && !q->flush_flags) {
+			bio->bi_rw &= ~(REQ_FLUSH | REQ_FUA);
+			if (!nr_sectors) {
+				err = 0;
+				goto end_io;
+			}
+		}
+
 		if ((bio->bi_rw & REQ_DISCARD) &&
 		    (!blk_queue_discard(q) ||
 		     ((bio->bi_rw & REQ_SECURE) &&
@@ -1522,6 +1529,15 @@
 			goto end_io;
 		}
 
+		blk_throtl_bio(q, &bio);
+
+		/*
+		 * If bio = NULL, bio has been throttled and will be submitted
+		 * later.
+		 */
+		if (!bio)
+			break;
+
 		trace_block_bio_queue(q, bio);
 
 		ret = q->make_request_fn(q, bio);
@@ -1612,11 +1628,12 @@
 
 		if (unlikely(block_dump)) {
 			char b[BDEVNAME_SIZE];
-			printk(KERN_DEBUG "%s(%d): %s block %Lu on %s\n",
+			printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n",
 			current->comm, task_pid_nr(current),
 				(rw & WRITE) ? "WRITE" : "READ",
 				(unsigned long long)bio->bi_sector,
-				bdevname(bio->bi_bdev, b));
+				bdevname(bio->bi_bdev, b),
+				count);
 		}
 	}
 
@@ -1637,7 +1654,7 @@
  *    the insertion using this generic function.
  *
  *    This function should also be useful for request stacking drivers
- *    in some cases below, so export this fuction.
+ *    in some cases below, so export this function.
  *    Request stacking drivers like request-based dm may change the queue
  *    limits while requests are in the queue (e.g. dm's table swapping).
  *    Such request stacking drivers should check those requests agaist
@@ -1768,11 +1785,11 @@
 static void blk_account_io_done(struct request *req)
 {
 	/*
-	 * Account IO completion.  bar_rq isn't accounted as a normal
-	 * IO on queueing nor completion.  Accounting the containing
-	 * request is enough.
+	 * Account IO completion.  flush_rq isn't accounted as a
+	 * normal IO on queueing nor completion.  Accounting the
+	 * containing request is enough.
 	 */
-	if (blk_do_io_stat(req) && req != &req->q->bar_rq) {
+	if (blk_do_io_stat(req) && req != &req->q->flush_rq) {
 		unsigned long duration = jiffies - req->start_time;
 		const int rw = rq_data_dir(req);
 		struct hd_struct *part;
@@ -2497,9 +2514,7 @@
 static void __blk_rq_prep_clone(struct request *dst, struct request *src)
 {
 	dst->cpu = src->cpu;
-	dst->cmd_flags = (rq_data_dir(src) | REQ_NOMERGE);
-	if (src->cmd_flags & REQ_DISCARD)
-		dst->cmd_flags |= REQ_DISCARD;
+	dst->cmd_flags = (src->cmd_flags & REQ_CLONE_MASK) | REQ_NOMERGE;
 	dst->cmd_type = src->cmd_type;
 	dst->__sector = blk_rq_pos(src);
 	dst->__data_len = blk_rq_bytes(src);
@@ -2579,6 +2594,13 @@
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
+int kblockd_schedule_delayed_work(struct request_queue *q,
+			struct delayed_work *dwork, unsigned long delay)
+{
+	return queue_delayed_work(kblockd_workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(kblockd_schedule_delayed_work);
+
 int __init blk_dev_init(void)
 {
 	BUILD_BUG_ON(__REQ_NR_BITS > 8 *
diff -druN linux-libre-2.6.36-gnu/block/blk-exec.c linux-libre-2.6.37-gnu/block/blk-exec.c
--- linux-libre-2.6.36-gnu/block/blk-exec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-exec.c	2011-01-04 19:50:19.000000000 -0500
@@ -80,6 +80,7 @@
 	DECLARE_COMPLETION_ONSTACK(wait);
 	char sense[SCSI_SENSE_BUFFERSIZE];
 	int err = 0;
+	unsigned long hang_check;
 
 	/*
 	 * we need an extra reference to the request, so we can look at
@@ -95,7 +96,13 @@
 
 	rq->end_io_data = &wait;
 	blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
-	wait_for_completion(&wait);
+
+	/* Prevent hang_check timer from firing at us during very long I/O */
+	hang_check = sysctl_hung_task_timeout_secs;
+	if (hang_check)
+		while (!wait_for_completion_timeout(&wait, hang_check * (HZ/2)));
+	else
+		wait_for_completion(&wait);
 
 	if (rq->errors)
 		err = -EIO;
diff -druN linux-libre-2.6.36-gnu/block/blk-flush.c linux-libre-2.6.37-gnu/block/blk-flush.c
--- linux-libre-2.6.36-gnu/block/blk-flush.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/block/blk-flush.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,262 @@
+/*
+ * Functions to sequence FLUSH and FUA writes.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/gfp.h>
+
+#include "blk.h"
+
+/* FLUSH/FUA sequences */
+enum {
+	QUEUE_FSEQ_STARTED	= (1 << 0), /* flushing in progress */
+	QUEUE_FSEQ_PREFLUSH	= (1 << 1), /* pre-flushing in progress */
+	QUEUE_FSEQ_DATA		= (1 << 2), /* data write in progress */
+	QUEUE_FSEQ_POSTFLUSH	= (1 << 3), /* post-flushing in progress */
+	QUEUE_FSEQ_DONE		= (1 << 4),
+};
+
+static struct request *queue_next_fseq(struct request_queue *q);
+
+unsigned blk_flush_cur_seq(struct request_queue *q)
+{
+	if (!q->flush_seq)
+		return 0;
+	return 1 << ffz(q->flush_seq);
+}
+
+static struct request *blk_flush_complete_seq(struct request_queue *q,
+					      unsigned seq, int error)
+{
+	struct request *next_rq = NULL;
+
+	if (error && !q->flush_err)
+		q->flush_err = error;
+
+	BUG_ON(q->flush_seq & seq);
+	q->flush_seq |= seq;
+
+	if (blk_flush_cur_seq(q) != QUEUE_FSEQ_DONE) {
+		/* not complete yet, queue the next flush sequence */
+		next_rq = queue_next_fseq(q);
+	} else {
+		/* complete this flush request */
+		__blk_end_request_all(q->orig_flush_rq, q->flush_err);
+		q->orig_flush_rq = NULL;
+		q->flush_seq = 0;
+
+		/* dispatch the next flush if there's one */
+		if (!list_empty(&q->pending_flushes)) {
+			next_rq = list_entry_rq(q->pending_flushes.next);
+			list_move(&next_rq->queuelist, &q->queue_head);
+		}
+	}
+	return next_rq;
+}
+
+static void blk_flush_complete_seq_end_io(struct request_queue *q,
+					  unsigned seq, int error)
+{
+	bool was_empty = elv_queue_empty(q);
+	struct request *next_rq;
+
+	next_rq = blk_flush_complete_seq(q, seq, error);
+
+	/*
+	 * Moving a request silently to empty queue_head may stall the
+	 * queue.  Kick the queue in those cases.
+	 */
+	if (was_empty && next_rq)
+		__blk_run_queue(q);
+}
+
+static void pre_flush_end_io(struct request *rq, int error)
+{
+	elv_completed_request(rq->q, rq);
+	blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_PREFLUSH, error);
+}
+
+static void flush_data_end_io(struct request *rq, int error)
+{
+	elv_completed_request(rq->q, rq);
+	blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_DATA, error);
+}
+
+static void post_flush_end_io(struct request *rq, int error)
+{
+	elv_completed_request(rq->q, rq);
+	blk_flush_complete_seq_end_io(rq->q, QUEUE_FSEQ_POSTFLUSH, error);
+}
+
+static void init_flush_request(struct request *rq, struct gendisk *disk)
+{
+	rq->cmd_type = REQ_TYPE_FS;
+	rq->cmd_flags = WRITE_FLUSH;
+	rq->rq_disk = disk;
+}
+
+static struct request *queue_next_fseq(struct request_queue *q)
+{
+	struct request *orig_rq = q->orig_flush_rq;
+	struct request *rq = &q->flush_rq;
+
+	blk_rq_init(q, rq);
+
+	switch (blk_flush_cur_seq(q)) {
+	case QUEUE_FSEQ_PREFLUSH:
+		init_flush_request(rq, orig_rq->rq_disk);
+		rq->end_io = pre_flush_end_io;
+		break;
+	case QUEUE_FSEQ_DATA:
+		init_request_from_bio(rq, orig_rq->bio);
+		/*
+		 * orig_rq->rq_disk may be different from
+		 * bio->bi_bdev->bd_disk if orig_rq got here through
+		 * remapping drivers.  Make sure rq->rq_disk points
+		 * to the same one as orig_rq.
+		 */
+		rq->rq_disk = orig_rq->rq_disk;
+		rq->cmd_flags &= ~(REQ_FLUSH | REQ_FUA);
+		rq->cmd_flags |= orig_rq->cmd_flags & (REQ_FLUSH | REQ_FUA);
+		rq->end_io = flush_data_end_io;
+		break;
+	case QUEUE_FSEQ_POSTFLUSH:
+		init_flush_request(rq, orig_rq->rq_disk);
+		rq->end_io = post_flush_end_io;
+		break;
+	default:
+		BUG();
+	}
+
+	elv_insert(q, rq, ELEVATOR_INSERT_FRONT);
+	return rq;
+}
+
+struct request *blk_do_flush(struct request_queue *q, struct request *rq)
+{
+	unsigned int fflags = q->flush_flags; /* may change, cache it */
+	bool has_flush = fflags & REQ_FLUSH, has_fua = fflags & REQ_FUA;
+	bool do_preflush = has_flush && (rq->cmd_flags & REQ_FLUSH);
+	bool do_postflush = has_flush && !has_fua && (rq->cmd_flags & REQ_FUA);
+	unsigned skip = 0;
+
+	/*
+	 * Special case.  If there's data but flush is not necessary,
+	 * the request can be issued directly.
+	 *
+	 * Flush w/o data should be able to be issued directly too but
+	 * currently some drivers assume that rq->bio contains
+	 * non-zero data if it isn't NULL and empty FLUSH requests
+	 * getting here usually have bio's without data.
+	 */
+	if (blk_rq_sectors(rq) && !do_preflush && !do_postflush) {
+		rq->cmd_flags &= ~REQ_FLUSH;
+		if (!has_fua)
+			rq->cmd_flags &= ~REQ_FUA;
+		return rq;
+	}
+
+	/*
+	 * Sequenced flushes can't be processed in parallel.  If
+	 * another one is already in progress, queue for later
+	 * processing.
+	 */
+	if (q->flush_seq) {
+		list_move_tail(&rq->queuelist, &q->pending_flushes);
+		return NULL;
+	}
+
+	/*
+	 * Start a new flush sequence
+	 */
+	q->flush_err = 0;
+	q->flush_seq |= QUEUE_FSEQ_STARTED;
+
+	/* adjust FLUSH/FUA of the original request and stash it away */
+	rq->cmd_flags &= ~REQ_FLUSH;
+	if (!has_fua)
+		rq->cmd_flags &= ~REQ_FUA;
+	blk_dequeue_request(rq);
+	q->orig_flush_rq = rq;
+
+	/* skip unneded sequences and return the first one */
+	if (!do_preflush)
+		skip |= QUEUE_FSEQ_PREFLUSH;
+	if (!blk_rq_sectors(rq))
+		skip |= QUEUE_FSEQ_DATA;
+	if (!do_postflush)
+		skip |= QUEUE_FSEQ_POSTFLUSH;
+	return blk_flush_complete_seq(q, skip, 0);
+}
+
+static void bio_end_flush(struct bio *bio, int err)
+{
+	if (err)
+		clear_bit(BIO_UPTODATE, &bio->bi_flags);
+	if (bio->bi_private)
+		complete(bio->bi_private);
+	bio_put(bio);
+}
+
+/**
+ * blkdev_issue_flush - queue a flush
+ * @bdev:	blockdev to issue flush for
+ * @gfp_mask:	memory allocation flags (for bio_alloc)
+ * @error_sector:	error sector
+ *
+ * Description:
+ *    Issue a flush for the block device in question. Caller can supply
+ *    room for storing the error offset in case of a flush error, if they
+ *    wish to. If WAIT flag is not passed then caller may check only what
+ *    request was pushed in some internal queue for later handling.
+ */
+int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
+		sector_t *error_sector)
+{
+	DECLARE_COMPLETION_ONSTACK(wait);
+	struct request_queue *q;
+	struct bio *bio;
+	int ret = 0;
+
+	if (bdev->bd_disk == NULL)
+		return -ENXIO;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+
+	/*
+	 * some block devices may not have their queue correctly set up here
+	 * (e.g. loop device without a backing file) and so issuing a flush
+	 * here will panic. Ensure there is a request function before issuing
+	 * the flush.
+	 */
+	if (!q->make_request_fn)
+		return -ENXIO;
+
+	bio = bio_alloc(gfp_mask, 0);
+	bio->bi_end_io = bio_end_flush;
+	bio->bi_bdev = bdev;
+	bio->bi_private = &wait;
+
+	bio_get(bio);
+	submit_bio(WRITE_FLUSH, bio);
+	wait_for_completion(&wait);
+
+	/*
+	 * The driver must store the error location in ->bi_sector, if
+	 * it supports it. For non-stacked drivers, this should be
+	 * copied from blk_rq_pos(rq).
+	 */
+	if (error_sector)
+               *error_sector = bio->bi_sector;
+
+	if (!bio_flagged(bio, BIO_UPTODATE))
+		ret = -EIO;
+
+	bio_put(bio);
+	return ret;
+}
+EXPORT_SYMBOL(blkdev_issue_flush);
diff -druN linux-libre-2.6.36-gnu/block/blk.h linux-libre-2.6.37-gnu/block/blk.h
--- linux-libre-2.6.36-gnu/block/blk.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk.h	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,8 @@
  */
 #define ELV_ON_HASH(rq)		(!hlist_unhashed(&(rq)->hash))
 
+struct request *blk_do_flush(struct request_queue *q, struct request *rq);
+
 static inline struct request *__elv_next_request(struct request_queue *q)
 {
 	struct request *rq;
@@ -58,7 +60,11 @@
 	while (1) {
 		while (!list_empty(&q->queue_head)) {
 			rq = list_entry_rq(q->queue_head.next);
-			if (blk_do_ordered(q, &rq))
+			if (!(rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) ||
+			    rq == &q->flush_rq)
+				return rq;
+			rq = blk_do_flush(q, rq);
+			if (rq)
 				return rq;
 		}
 
@@ -132,14 +138,6 @@
 	return q->nr_congestion_off;
 }
 
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-
-#define rq_for_each_integrity_segment(bvl, _rq, _iter)		\
-	__rq_for_each_bio(_iter.bio, _rq)			\
-		bip_for_each_vec(bvl, _iter.bio->bi_integrity, _iter.i)
-
-#endif /* BLK_DEV_INTEGRITY */
-
 static inline int blk_cpu_to_group(int cpu)
 {
 	int group = NR_CPUS;
diff -druN linux-libre-2.6.36-gnu/block/blk-integrity.c linux-libre-2.6.37-gnu/block/blk-integrity.c
--- linux-libre-2.6.36-gnu/block/blk-integrity.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-integrity.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,24 +32,37 @@
 
 /**
  * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
- * @rq:		request with integrity metadata attached
+ * @q:		request queue
+ * @bio:	bio with integrity metadata attached
  *
  * Description: Returns the number of elements required in a
- * scatterlist corresponding to the integrity metadata in a request.
+ * scatterlist corresponding to the integrity metadata in a bio.
  */
-int blk_rq_count_integrity_sg(struct request *rq)
+int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio)
 {
-	struct bio_vec *iv, *ivprv;
-	struct req_iterator iter;
-	unsigned int segments;
+	struct bio_vec *iv, *ivprv = NULL;
+	unsigned int segments = 0;
+	unsigned int seg_size = 0;
+	unsigned int i = 0;
 
-	ivprv = NULL;
-	segments = 0;
+	bio_for_each_integrity_vec(iv, bio, i) {
 
-	rq_for_each_integrity_segment(iv, rq, iter) {
+		if (ivprv) {
+			if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+				goto new_segment;
 
-		if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+			if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
+				goto new_segment;
+
+			if (seg_size + iv->bv_len > queue_max_segment_size(q))
+				goto new_segment;
+
+			seg_size += iv->bv_len;
+		} else {
+new_segment:
 			segments++;
+			seg_size = iv->bv_len;
+		}
 
 		ivprv = iv;
 	}
@@ -60,30 +73,34 @@
 
 /**
  * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
- * @rq:		request with integrity metadata attached
+ * @q:		request queue
+ * @bio:	bio with integrity metadata attached
  * @sglist:	target scatterlist
  *
  * Description: Map the integrity vectors in request into a
  * scatterlist.  The scatterlist must be big enough to hold all
  * elements.  I.e. sized using blk_rq_count_integrity_sg().
  */
-int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)
+int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
+			    struct scatterlist *sglist)
 {
-	struct bio_vec *iv, *ivprv;
-	struct req_iterator iter;
-	struct scatterlist *sg;
-	unsigned int segments;
-
-	ivprv = NULL;
-	sg = NULL;
-	segments = 0;
+	struct bio_vec *iv, *ivprv = NULL;
+	struct scatterlist *sg = NULL;
+	unsigned int segments = 0;
+	unsigned int i = 0;
 
-	rq_for_each_integrity_segment(iv, rq, iter) {
+	bio_for_each_integrity_vec(iv, bio, i) {
 
 		if (ivprv) {
 			if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
 				goto new_segment;
 
+			if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
+				goto new_segment;
+
+			if (sg->length + iv->bv_len > queue_max_segment_size(q))
+				goto new_segment;
+
 			sg->length += iv->bv_len;
 		} else {
 new_segment:
@@ -162,6 +179,40 @@
 }
 EXPORT_SYMBOL(blk_integrity_compare);
 
+int blk_integrity_merge_rq(struct request_queue *q, struct request *req,
+			   struct request *next)
+{
+	if (blk_integrity_rq(req) != blk_integrity_rq(next))
+		return -1;
+
+	if (req->nr_integrity_segments + next->nr_integrity_segments >
+	    q->limits.max_integrity_segments)
+		return -1;
+
+	return 0;
+}
+EXPORT_SYMBOL(blk_integrity_merge_rq);
+
+int blk_integrity_merge_bio(struct request_queue *q, struct request *req,
+			    struct bio *bio)
+{
+	int nr_integrity_segs;
+	struct bio *next = bio->bi_next;
+
+	bio->bi_next = NULL;
+	nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
+	bio->bi_next = next;
+
+	if (req->nr_integrity_segments + nr_integrity_segs >
+	    q->limits.max_integrity_segments)
+		return -1;
+
+	req->nr_integrity_segments += nr_integrity_segs;
+
+	return 0;
+}
+EXPORT_SYMBOL(blk_integrity_merge_bio);
+
 struct integrity_sysfs_entry {
 	struct attribute attr;
 	ssize_t (*show)(struct blk_integrity *, char *);
@@ -381,7 +432,6 @@
 	kobject_uevent(&bi->kobj, KOBJ_REMOVE);
 	kobject_del(&bi->kobj);
 	kobject_put(&bi->kobj);
-	kmem_cache_free(integrity_cachep, bi);
 	disk->integrity = NULL;
 }
 EXPORT_SYMBOL(blk_integrity_unregister);
diff -druN linux-libre-2.6.36-gnu/block/blk-ioc.c linux-libre-2.6.37-gnu/block/blk-ioc.c
--- linux-libre-2.6.36-gnu/block/blk-ioc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-ioc.c	2011-01-04 19:50:19.000000000 -0500
@@ -153,20 +153,6 @@
 }
 EXPORT_SYMBOL(get_io_context);
 
-void copy_io_context(struct io_context **pdst, struct io_context **psrc)
-{
-	struct io_context *src = *psrc;
-	struct io_context *dst = *pdst;
-
-	if (src) {
-		BUG_ON(atomic_long_read(&src->refcount) == 0);
-		atomic_long_inc(&src->refcount);
-		put_io_context(dst);
-		*pdst = src;
-	}
-}
-EXPORT_SYMBOL(copy_io_context);
-
 static int __init blk_ioc_init(void)
 {
 	iocontext_cachep = kmem_cache_create("blkdev_ioc",
diff -druN linux-libre-2.6.36-gnu/block/blk-lib.c linux-libre-2.6.37-gnu/block/blk-lib.c
--- linux-libre-2.6.36-gnu/block/blk-lib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-lib.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,8 +39,7 @@
 {
 	DECLARE_COMPLETION_ONSTACK(wait);
 	struct request_queue *q = bdev_get_queue(bdev);
-	int type = flags & BLKDEV_IFL_BARRIER ?
-		DISCARD_BARRIER : DISCARD_NOBARRIER;
+	int type = REQ_WRITE | REQ_DISCARD;
 	unsigned int max_discard_sectors;
 	struct bio *bio;
 	int ret = 0;
@@ -62,10 +61,10 @@
 		max_discard_sectors &= ~(disc_sects - 1);
 	}
 
-	if (flags & BLKDEV_IFL_SECURE) {
+	if (flags & BLKDEV_DISCARD_SECURE) {
 		if (!blk_queue_secdiscard(q))
 			return -EOPNOTSUPP;
-		type |= DISCARD_SECURE;
+		type |= REQ_SECURE;
 	}
 
 	while (nr_sects && !ret) {
@@ -78,8 +77,7 @@
 		bio->bi_sector = sector;
 		bio->bi_end_io = blkdev_discard_end_io;
 		bio->bi_bdev = bdev;
-		if (flags & BLKDEV_IFL_WAIT)
-			bio->bi_private = &wait;
+		bio->bi_private = &wait;
 
 		if (nr_sects > max_discard_sectors) {
 			bio->bi_size = max_discard_sectors << 9;
@@ -93,8 +91,7 @@
 		bio_get(bio);
 		submit_bio(type, bio);
 
-		if (flags & BLKDEV_IFL_WAIT)
-			wait_for_completion(&wait);
+		wait_for_completion(&wait);
 
 		if (bio_flagged(bio, BIO_EOPNOTSUPP))
 			ret = -EOPNOTSUPP;
@@ -140,7 +137,6 @@
  * @sector:	start sector
  * @nr_sects:	number of sectors to write
  * @gfp_mask:	memory allocation flags (for bio_alloc)
- * @flags:	BLKDEV_IFL_* flags to control behaviour
  *
  * Description:
  *  Generate and issue number of bios with zerofiled pages.
@@ -149,7 +145,7 @@
  */
 
 int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
-			sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
+			sector_t nr_sects, gfp_t gfp_mask)
 {
 	int ret;
 	struct bio *bio;
@@ -162,12 +158,6 @@
 	bb.wait = &wait;
 	bb.end_io = NULL;
 
-	if (flags & BLKDEV_IFL_BARRIER) {
-		/* issue async barrier before the data */
-		ret = blkdev_issue_flush(bdev, gfp_mask, NULL, 0);
-		if (ret)
-			return ret;
-	}
 submit:
 	ret = 0;
 	while (nr_sects != 0) {
@@ -181,8 +171,7 @@
 		bio->bi_sector = sector;
 		bio->bi_bdev   = bdev;
 		bio->bi_end_io = bio_batch_end_io;
-		if (flags & BLKDEV_IFL_WAIT)
-			bio->bi_private = &bb;
+		bio->bi_private = &bb;
 
 		while (nr_sects != 0) {
 			sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
@@ -199,18 +188,10 @@
 		issued++;
 		submit_bio(WRITE, bio);
 	}
-	/*
-	 * When all data bios are in flight. Send final barrier if requeted.
-	 */
-	if (nr_sects == 0 && flags & BLKDEV_IFL_BARRIER)
-		ret = blkdev_issue_flush(bdev, gfp_mask, NULL,
-					flags & BLKDEV_IFL_WAIT);
-
 
-	if (flags & BLKDEV_IFL_WAIT)
-		/* Wait for bios in-flight */
-		while ( issued != atomic_read(&bb.done))
-			wait_for_completion(&wait);
+	/* Wait for bios in-flight */
+	while (issued != atomic_read(&bb.done))
+		wait_for_completion(&wait);
 
 	if (!test_bit(BIO_UPTODATE, &bb.flags))
 		/* One of bios in the batch was completed with error.*/
diff -druN linux-libre-2.6.36-gnu/block/blk-map.c linux-libre-2.6.37-gnu/block/blk-map.c
--- linux-libre-2.6.36-gnu/block/blk-map.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-map.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,7 +54,7 @@
 	 * direct dma. else, set up kernel bounce buffers
 	 */
 	uaddr = (unsigned long) ubuf;
-	if (blk_rq_aligned(q, ubuf, len) && !map_data)
+	if (blk_rq_aligned(q, uaddr, len) && !map_data)
 		bio = bio_map_user(q, NULL, uaddr, len, reading, gfp_mask);
 	else
 		bio = bio_copy_user(q, map_data, uaddr, len, reading, gfp_mask);
@@ -201,6 +201,9 @@
 	for (i = 0; i < iov_count; i++) {
 		unsigned long uaddr = (unsigned long)iov[i].iov_base;
 
+		if (!iov[i].iov_len)
+			return -EINVAL;
+
 		if (uaddr & queue_dma_alignment(q)) {
 			unaligned = 1;
 			break;
@@ -288,6 +291,7 @@
 		    unsigned int len, gfp_t gfp_mask)
 {
 	int reading = rq_data_dir(rq) == READ;
+	unsigned long addr = (unsigned long) kbuf;
 	int do_copy = 0;
 	struct bio *bio;
 	int ret;
@@ -297,7 +301,7 @@
 	if (!len || !kbuf)
 		return -EINVAL;
 
-	do_copy = !blk_rq_aligned(q, kbuf, len) || object_is_on_stack(kbuf);
+	do_copy = !blk_rq_aligned(q, addr, len) || object_is_on_stack(kbuf);
 	if (do_copy)
 		bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading);
 	else
diff -druN linux-libre-2.6.36-gnu/block/blk-merge.c linux-libre-2.6.37-gnu/block/blk-merge.c
--- linux-libre-2.6.36-gnu/block/blk-merge.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-merge.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,7 @@
 		return 0;
 
 	fbio = bio;
-	cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+	cluster = blk_queue_cluster(q);
 	seg_size = 0;
 	nr_phys_segs = 0;
 	for_each_bio(bio) {
@@ -87,7 +87,7 @@
 static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
 				   struct bio *nxt)
 {
-	if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
+	if (!blk_queue_cluster(q))
 		return 0;
 
 	if (bio->bi_seg_back_size + nxt->bi_seg_front_size >
@@ -123,7 +123,7 @@
 	int nsegs, cluster;
 
 	nsegs = 0;
-	cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+	cluster = blk_queue_cluster(q);
 
 	/*
 	 * for each bio in rq
@@ -205,12 +205,11 @@
 {
 	int nr_phys_segs = bio_phys_segments(q, bio);
 
-	if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q)) {
-		req->cmd_flags |= REQ_NOMERGE;
-		if (req == q->last_merge)
-			q->last_merge = NULL;
-		return 0;
-	}
+	if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q))
+		goto no_merge;
+
+	if (bio_integrity(bio) && blk_integrity_merge_bio(q, req, bio))
+		goto no_merge;
 
 	/*
 	 * This will form the start of a new hw segment.  Bump both
@@ -218,6 +217,12 @@
 	 */
 	req->nr_phys_segments += nr_phys_segs;
 	return 1;
+
+no_merge:
+	req->cmd_flags |= REQ_NOMERGE;
+	if (req == q->last_merge)
+		q->last_merge = NULL;
+	return 0;
 }
 
 int ll_back_merge_fn(struct request_queue *q, struct request *req,
@@ -301,6 +306,9 @@
 	if (total_phys_segments > queue_max_segments(q))
 		return 0;
 
+	if (blk_integrity_rq(req) && blk_integrity_merge_rq(q, req, next))
+		return 0;
+
 	/* Merge is OK... */
 	req->nr_phys_segments = total_phys_segments;
 	return 1;
@@ -384,9 +392,6 @@
 	    || next->special)
 		return 0;
 
-	if (blk_integrity_rq(req) != blk_integrity_rq(next))
-		return 0;
-
 	/*
 	 * If we are allowed to merge, then append bio list
 	 * from next to rq and release next. merge_requests_fn
diff -druN linux-libre-2.6.36-gnu/block/blk-settings.c linux-libre-2.6.37-gnu/block/blk-settings.c
--- linux-libre-2.6.36-gnu/block/blk-settings.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-settings.c	2011-01-04 19:50:19.000000000 -0500
@@ -111,6 +111,7 @@
 void blk_set_default_limits(struct queue_limits *lim)
 {
 	lim->max_segments = BLK_MAX_SEGMENTS;
+	lim->max_integrity_segments = 0;
 	lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
 	lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
 	lim->max_sectors = BLK_DEF_MAX_SECTORS;
@@ -125,7 +126,7 @@
 	lim->alignment_offset = 0;
 	lim->io_opt = 0;
 	lim->misaligned = 0;
-	lim->no_cluster = 0;
+	lim->cluster = 1;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -213,7 +214,7 @@
 	 */
 	if (b_pfn < (min_t(u64, 0xffffffffUL, BLK_BOUNCE_HIGH) >> PAGE_SHIFT))
 		dma = 1;
-	q->limits.bounce_pfn = max_low_pfn;
+	q->limits.bounce_pfn = max(max_low_pfn, b_pfn);
 #else
 	if (b_pfn < blk_max_low_pfn)
 		dma = 1;
@@ -228,8 +229,8 @@
 EXPORT_SYMBOL(blk_queue_bounce_limit);
 
 /**
- * blk_queue_max_hw_sectors - set max sectors for a request for this queue
- * @q:  the request queue for the device
+ * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request
+ * @limits: the queue limits
  * @max_hw_sectors:  max hardware sectors in the usual 512b unit
  *
  * Description:
@@ -243,7 +244,7 @@
  *    per-device basis in /sys/block/<device>/queue/max_sectors_kb.
  *    The soft limit can not exceed max_hw_sectors.
  **/
-void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
+void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors)
 {
 	if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) {
 		max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
@@ -251,9 +252,23 @@
 		       __func__, max_hw_sectors);
 	}
 
-	q->limits.max_hw_sectors = max_hw_sectors;
-	q->limits.max_sectors = min_t(unsigned int, max_hw_sectors,
-				      BLK_DEF_MAX_SECTORS);
+	limits->max_hw_sectors = max_hw_sectors;
+	limits->max_sectors = min_t(unsigned int, max_hw_sectors,
+				    BLK_DEF_MAX_SECTORS);
+}
+EXPORT_SYMBOL(blk_limits_max_hw_sectors);
+
+/**
+ * blk_queue_max_hw_sectors - set max sectors for a request for this queue
+ * @q:  the request queue for the device
+ * @max_hw_sectors:  max hardware sectors in the usual 512b unit
+ *
+ * Description:
+ *    See description for blk_limits_max_hw_sectors().
+ **/
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
+{
+	blk_limits_max_hw_sectors(&q->limits, max_hw_sectors);
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
 
@@ -343,7 +358,7 @@
  *   hardware can operate on without reverting to read-modify-write
  *   operations.
  */
-void blk_queue_physical_block_size(struct request_queue *q, unsigned short size)
+void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
 {
 	q->limits.physical_block_size = size;
 
@@ -455,11 +470,6 @@
 }
 EXPORT_SYMBOL(blk_queue_io_opt);
 
-/*
- * Returns the minimum that is _not_ zero, unless both are zero.
- */
-#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
-
 /**
  * blk_queue_stack_limits - inherit underlying queue limits for stacked drivers
  * @t:	the stacking driver (top)
@@ -468,15 +478,6 @@
 void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 {
 	blk_stack_limits(&t->limits, &b->limits, 0);
-
-	if (!t->queue_lock)
-		WARN_ON_ONCE(1);
-	else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
-		unsigned long flags;
-		spin_lock_irqsave(t->queue_lock, flags);
-		queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
-		spin_unlock_irqrestore(t->queue_lock, flags);
-	}
 }
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
@@ -514,6 +515,8 @@
 					    b->seg_boundary_mask);
 
 	t->max_segments = min_not_zero(t->max_segments, b->max_segments);
+	t->max_integrity_segments = min_not_zero(t->max_integrity_segments,
+						 b->max_integrity_segments);
 
 	t->max_segment_size = min_not_zero(t->max_segment_size,
 					   b->max_segment_size);
@@ -547,7 +550,7 @@
 	t->io_min = max(t->io_min, b->io_min);
 	t->io_opt = lcm(t->io_opt, b->io_opt);
 
-	t->no_cluster |= b->no_cluster;
+	t->cluster &= b->cluster;
 	t->discard_zeroes_data &= b->discard_zeroes_data;
 
 	/* Physical block size a multiple of the logical block size? */
@@ -643,7 +646,6 @@
 		       sector_t offset)
 {
 	struct request_queue *t = disk->queue;
-	struct request_queue *b = bdev_get_queue(bdev);
 
 	if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) {
 		char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE];
@@ -654,17 +656,6 @@
 		printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n",
 		       top, bottom);
 	}
-
-	if (!t->queue_lock)
-		WARN_ON_ONCE(1);
-	else if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags)) {
-		unsigned long flags;
-
-		spin_lock_irqsave(t->queue_lock, flags);
-		if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
-			queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
-		spin_unlock_irqrestore(t->queue_lock, flags);
-	}
 }
 EXPORT_SYMBOL(disk_stack_limits);
 
@@ -794,6 +785,26 @@
 }
 EXPORT_SYMBOL(blk_queue_update_dma_alignment);
 
+/**
+ * blk_queue_flush - configure queue's cache flush capability
+ * @q:		the request queue for the device
+ * @flush:	0, REQ_FLUSH or REQ_FLUSH | REQ_FUA
+ *
+ * Tell block layer cache flush capability of @q.  If it supports
+ * flushing, REQ_FLUSH should be set.  If it supports bypassing
+ * write cache for individual writes, REQ_FUA should be set.
+ */
+void blk_queue_flush(struct request_queue *q, unsigned int flush)
+{
+	WARN_ON_ONCE(flush & ~(REQ_FLUSH | REQ_FUA));
+
+	if (WARN_ON_ONCE(!(flush & REQ_FLUSH) && (flush & REQ_FUA)))
+		flush &= ~REQ_FUA;
+
+	q->flush_flags = flush & (REQ_FLUSH | REQ_FUA);
+}
+EXPORT_SYMBOL_GPL(blk_queue_flush);
+
 static int __init blk_settings_init(void)
 {
 	blk_max_low_pfn = max_low_pfn - 1;
diff -druN linux-libre-2.6.36-gnu/block/blk-sysfs.c linux-libre-2.6.37-gnu/block/blk-sysfs.c
--- linux-libre-2.6.36-gnu/block/blk-sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/blk-sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -112,9 +112,14 @@
 	return queue_var_show(queue_max_segments(q), (page));
 }
 
+static ssize_t queue_max_integrity_segments_show(struct request_queue *q, char *page)
+{
+	return queue_var_show(q->limits.max_integrity_segments, (page));
+}
+
 static ssize_t queue_max_segment_size_show(struct request_queue *q, char *page)
 {
-	if (test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
+	if (blk_queue_cluster(q))
 		return queue_var_show(queue_max_segment_size(q), (page));
 
 	return queue_var_show(PAGE_CACHE_SIZE, (page));
@@ -288,6 +293,11 @@
 	.show = queue_max_segments_show,
 };
 
+static struct queue_sysfs_entry queue_max_integrity_segments_entry = {
+	.attr = {.name = "max_integrity_segments", .mode = S_IRUGO },
+	.show = queue_max_integrity_segments_show,
+};
+
 static struct queue_sysfs_entry queue_max_segment_size_entry = {
 	.attr = {.name = "max_segment_size", .mode = S_IRUGO },
 	.show = queue_max_segment_size_show,
@@ -375,6 +385,7 @@
 	&queue_max_hw_sectors_entry.attr,
 	&queue_max_sectors_entry.attr,
 	&queue_max_segments_entry.attr,
+	&queue_max_integrity_segments_entry.attr,
 	&queue_max_segment_size_entry.attr,
 	&queue_iosched_entry.attr,
 	&queue_hw_sector_size_entry.attr,
@@ -460,6 +471,8 @@
 
 	blk_sync_queue(q);
 
+	blk_throtl_exit(q);
+
 	if (rl->rq_pool)
 		mempool_destroy(rl->rq_pool);
 
diff -druN linux-libre-2.6.36-gnu/block/blk-throttle.c linux-libre-2.6.37-gnu/block/blk-throttle.c
--- linux-libre-2.6.36-gnu/block/blk-throttle.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/block/blk-throttle.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1134 @@
+/*
+ * Interface for controlling IO bandwidth on a request queue
+ *
+ * Copyright (C) 2010 Vivek Goyal <vgoyal@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/blktrace_api.h>
+#include "blk-cgroup.h"
+
+/* Max dispatch from a group in 1 round */
+static int throtl_grp_quantum = 8;
+
+/* Total max dispatch from all groups in one round */
+static int throtl_quantum = 32;
+
+/* Throttling is performed over 100ms slice and after that slice is renewed */
+static unsigned long throtl_slice = HZ/10;	/* 100 ms */
+
+struct throtl_rb_root {
+	struct rb_root rb;
+	struct rb_node *left;
+	unsigned int count;
+	unsigned long min_disptime;
+};
+
+#define THROTL_RB_ROOT	(struct throtl_rb_root) { .rb = RB_ROOT, .left = NULL, \
+			.count = 0, .min_disptime = 0}
+
+#define rb_entry_tg(node)	rb_entry((node), struct throtl_grp, rb_node)
+
+struct throtl_grp {
+	/* List of throtl groups on the request queue*/
+	struct hlist_node tg_node;
+
+	/* active throtl group service_tree member */
+	struct rb_node rb_node;
+
+	/*
+	 * Dispatch time in jiffies. This is the estimated time when group
+	 * will unthrottle and is ready to dispatch more bio. It is used as
+	 * key to sort active groups in service tree.
+	 */
+	unsigned long disptime;
+
+	struct blkio_group blkg;
+	atomic_t ref;
+	unsigned int flags;
+
+	/* Two lists for READ and WRITE */
+	struct bio_list bio_lists[2];
+
+	/* Number of queued bios on READ and WRITE lists */
+	unsigned int nr_queued[2];
+
+	/* bytes per second rate limits */
+	uint64_t bps[2];
+
+	/* IOPS limits */
+	unsigned int iops[2];
+
+	/* Number of bytes disptached in current slice */
+	uint64_t bytes_disp[2];
+	/* Number of bio's dispatched in current slice */
+	unsigned int io_disp[2];
+
+	/* When did we start a new slice */
+	unsigned long slice_start[2];
+	unsigned long slice_end[2];
+
+	/* Some throttle limits got updated for the group */
+	bool limits_changed;
+};
+
+struct throtl_data
+{
+	/* List of throtl groups */
+	struct hlist_head tg_list;
+
+	/* service tree for active throtl groups */
+	struct throtl_rb_root tg_service_tree;
+
+	struct throtl_grp root_tg;
+	struct request_queue *queue;
+
+	/* Total Number of queued bios on READ and WRITE lists */
+	unsigned int nr_queued[2];
+
+	/*
+	 * number of total undestroyed groups
+	 */
+	unsigned int nr_undestroyed_grps;
+
+	/* Work for dispatching throttled bios */
+	struct delayed_work throtl_work;
+
+	atomic_t limits_changed;
+};
+
+enum tg_state_flags {
+	THROTL_TG_FLAG_on_rr = 0,	/* on round-robin busy list */
+};
+
+#define THROTL_TG_FNS(name)						\
+static inline void throtl_mark_tg_##name(struct throtl_grp *tg)		\
+{									\
+	(tg)->flags |= (1 << THROTL_TG_FLAG_##name);			\
+}									\
+static inline void throtl_clear_tg_##name(struct throtl_grp *tg)	\
+{									\
+	(tg)->flags &= ~(1 << THROTL_TG_FLAG_##name);			\
+}									\
+static inline int throtl_tg_##name(const struct throtl_grp *tg)		\
+{									\
+	return ((tg)->flags & (1 << THROTL_TG_FLAG_##name)) != 0;	\
+}
+
+THROTL_TG_FNS(on_rr);
+
+#define throtl_log_tg(td, tg, fmt, args...)				\
+	blk_add_trace_msg((td)->queue, "throtl %s " fmt,		\
+				blkg_path(&(tg)->blkg), ##args);      	\
+
+#define throtl_log(td, fmt, args...)	\
+	blk_add_trace_msg((td)->queue, "throtl " fmt, ##args)
+
+static inline struct throtl_grp *tg_of_blkg(struct blkio_group *blkg)
+{
+	if (blkg)
+		return container_of(blkg, struct throtl_grp, blkg);
+
+	return NULL;
+}
+
+static inline int total_nr_queued(struct throtl_data *td)
+{
+	return (td->nr_queued[0] + td->nr_queued[1]);
+}
+
+static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg)
+{
+	atomic_inc(&tg->ref);
+	return tg;
+}
+
+static void throtl_put_tg(struct throtl_grp *tg)
+{
+	BUG_ON(atomic_read(&tg->ref) <= 0);
+	if (!atomic_dec_and_test(&tg->ref))
+		return;
+	kfree(tg);
+}
+
+static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
+			struct cgroup *cgroup)
+{
+	struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
+	struct throtl_grp *tg = NULL;
+	void *key = td;
+	struct backing_dev_info *bdi = &td->queue->backing_dev_info;
+	unsigned int major, minor;
+
+	/*
+	 * TODO: Speed up blkiocg_lookup_group() by maintaining a radix
+	 * tree of blkg (instead of traversing through hash list all
+	 * the time.
+	 */
+	tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+	/* Fill in device details for root group */
+	if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+		sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+		tg->blkg.dev = MKDEV(major, minor);
+		goto done;
+	}
+
+	if (tg)
+		goto done;
+
+	tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
+	if (!tg)
+		goto done;
+
+	INIT_HLIST_NODE(&tg->tg_node);
+	RB_CLEAR_NODE(&tg->rb_node);
+	bio_list_init(&tg->bio_lists[0]);
+	bio_list_init(&tg->bio_lists[1]);
+
+	/*
+	 * Take the initial reference that will be released on destroy
+	 * This can be thought of a joint reference by cgroup and
+	 * request queue which will be dropped by either request queue
+	 * exit or cgroup deletion path depending on who is exiting first.
+	 */
+	atomic_set(&tg->ref, 1);
+
+	/* Add group onto cgroup list */
+	sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+	blkiocg_add_blkio_group(blkcg, &tg->blkg, (void *)td,
+				MKDEV(major, minor), BLKIO_POLICY_THROTL);
+
+	tg->bps[READ] = blkcg_get_read_bps(blkcg, tg->blkg.dev);
+	tg->bps[WRITE] = blkcg_get_write_bps(blkcg, tg->blkg.dev);
+	tg->iops[READ] = blkcg_get_read_iops(blkcg, tg->blkg.dev);
+	tg->iops[WRITE] = blkcg_get_write_iops(blkcg, tg->blkg.dev);
+
+	hlist_add_head(&tg->tg_node, &td->tg_list);
+	td->nr_undestroyed_grps++;
+done:
+	return tg;
+}
+
+static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+{
+	struct cgroup *cgroup;
+	struct throtl_grp *tg = NULL;
+
+	rcu_read_lock();
+	cgroup = task_cgroup(current, blkio_subsys_id);
+	tg = throtl_find_alloc_tg(td, cgroup);
+	if (!tg)
+		tg = &td->root_tg;
+	rcu_read_unlock();
+	return tg;
+}
+
+static struct throtl_grp *throtl_rb_first(struct throtl_rb_root *root)
+{
+	/* Service tree is empty */
+	if (!root->count)
+		return NULL;
+
+	if (!root->left)
+		root->left = rb_first(&root->rb);
+
+	if (root->left)
+		return rb_entry_tg(root->left);
+
+	return NULL;
+}
+
+static void rb_erase_init(struct rb_node *n, struct rb_root *root)
+{
+	rb_erase(n, root);
+	RB_CLEAR_NODE(n);
+}
+
+static void throtl_rb_erase(struct rb_node *n, struct throtl_rb_root *root)
+{
+	if (root->left == n)
+		root->left = NULL;
+	rb_erase_init(n, &root->rb);
+	--root->count;
+}
+
+static void update_min_dispatch_time(struct throtl_rb_root *st)
+{
+	struct throtl_grp *tg;
+
+	tg = throtl_rb_first(st);
+	if (!tg)
+		return;
+
+	st->min_disptime = tg->disptime;
+}
+
+static void
+tg_service_tree_add(struct throtl_rb_root *st, struct throtl_grp *tg)
+{
+	struct rb_node **node = &st->rb.rb_node;
+	struct rb_node *parent = NULL;
+	struct throtl_grp *__tg;
+	unsigned long key = tg->disptime;
+	int left = 1;
+
+	while (*node != NULL) {
+		parent = *node;
+		__tg = rb_entry_tg(parent);
+
+		if (time_before(key, __tg->disptime))
+			node = &parent->rb_left;
+		else {
+			node = &parent->rb_right;
+			left = 0;
+		}
+	}
+
+	if (left)
+		st->left = &tg->rb_node;
+
+	rb_link_node(&tg->rb_node, parent, node);
+	rb_insert_color(&tg->rb_node, &st->rb);
+}
+
+static void __throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+{
+	struct throtl_rb_root *st = &td->tg_service_tree;
+
+	tg_service_tree_add(st, tg);
+	throtl_mark_tg_on_rr(tg);
+	st->count++;
+}
+
+static void throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+{
+	if (!throtl_tg_on_rr(tg))
+		__throtl_enqueue_tg(td, tg);
+}
+
+static void __throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+{
+	throtl_rb_erase(&tg->rb_node, &td->tg_service_tree);
+	throtl_clear_tg_on_rr(tg);
+}
+
+static void throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+{
+	if (throtl_tg_on_rr(tg))
+		__throtl_dequeue_tg(td, tg);
+}
+
+static void throtl_schedule_next_dispatch(struct throtl_data *td)
+{
+	struct throtl_rb_root *st = &td->tg_service_tree;
+
+	/*
+	 * If there are more bios pending, schedule more work.
+	 */
+	if (!total_nr_queued(td))
+		return;
+
+	BUG_ON(!st->count);
+
+	update_min_dispatch_time(st);
+
+	if (time_before_eq(st->min_disptime, jiffies))
+		throtl_schedule_delayed_work(td->queue, 0);
+	else
+		throtl_schedule_delayed_work(td->queue,
+				(st->min_disptime - jiffies));
+}
+
+static inline void
+throtl_start_new_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+{
+	tg->bytes_disp[rw] = 0;
+	tg->io_disp[rw] = 0;
+	tg->slice_start[rw] = jiffies;
+	tg->slice_end[rw] = jiffies + throtl_slice;
+	throtl_log_tg(td, tg, "[%c] new slice start=%lu end=%lu jiffies=%lu",
+			rw == READ ? 'R' : 'W', tg->slice_start[rw],
+			tg->slice_end[rw], jiffies);
+}
+
+static inline void throtl_set_slice_end(struct throtl_data *td,
+		struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+{
+	tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
+}
+
+static inline void throtl_extend_slice(struct throtl_data *td,
+		struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+{
+	tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
+	throtl_log_tg(td, tg, "[%c] extend slice start=%lu end=%lu jiffies=%lu",
+			rw == READ ? 'R' : 'W', tg->slice_start[rw],
+			tg->slice_end[rw], jiffies);
+}
+
+/* Determine if previously allocated or extended slice is complete or not */
+static bool
+throtl_slice_used(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+{
+	if (time_in_range(jiffies, tg->slice_start[rw], tg->slice_end[rw]))
+		return 0;
+
+	return 1;
+}
+
+/* Trim the used slices and adjust slice start accordingly */
+static inline void
+throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+{
+	unsigned long nr_slices, time_elapsed, io_trim;
+	u64 bytes_trim, tmp;
+
+	BUG_ON(time_before(tg->slice_end[rw], tg->slice_start[rw]));
+
+	/*
+	 * If bps are unlimited (-1), then time slice don't get
+	 * renewed. Don't try to trim the slice if slice is used. A new
+	 * slice will start when appropriate.
+	 */
+	if (throtl_slice_used(td, tg, rw))
+		return;
+
+	/*
+	 * A bio has been dispatched. Also adjust slice_end. It might happen
+	 * that initially cgroup limit was very low resulting in high
+	 * slice_end, but later limit was bumped up and bio was dispached
+	 * sooner, then we need to reduce slice_end. A high bogus slice_end
+	 * is bad because it does not allow new slice to start.
+	 */
+
+	throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice);
+
+	time_elapsed = jiffies - tg->slice_start[rw];
+
+	nr_slices = time_elapsed / throtl_slice;
+
+	if (!nr_slices)
+		return;
+	tmp = tg->bps[rw] * throtl_slice * nr_slices;
+	do_div(tmp, HZ);
+	bytes_trim = tmp;
+
+	io_trim = (tg->iops[rw] * throtl_slice * nr_slices)/HZ;
+
+	if (!bytes_trim && !io_trim)
+		return;
+
+	if (tg->bytes_disp[rw] >= bytes_trim)
+		tg->bytes_disp[rw] -= bytes_trim;
+	else
+		tg->bytes_disp[rw] = 0;
+
+	if (tg->io_disp[rw] >= io_trim)
+		tg->io_disp[rw] -= io_trim;
+	else
+		tg->io_disp[rw] = 0;
+
+	tg->slice_start[rw] += nr_slices * throtl_slice;
+
+	throtl_log_tg(td, tg, "[%c] trim slice nr=%lu bytes=%llu io=%lu"
+			" start=%lu end=%lu jiffies=%lu",
+			rw == READ ? 'R' : 'W', nr_slices, bytes_trim, io_trim,
+			tg->slice_start[rw], tg->slice_end[rw], jiffies);
+}
+
+static bool tg_with_in_iops_limit(struct throtl_data *td, struct throtl_grp *tg,
+		struct bio *bio, unsigned long *wait)
+{
+	bool rw = bio_data_dir(bio);
+	unsigned int io_allowed;
+	unsigned long jiffy_elapsed, jiffy_wait, jiffy_elapsed_rnd;
+	u64 tmp;
+
+	jiffy_elapsed = jiffy_elapsed_rnd = jiffies - tg->slice_start[rw];
+
+	/* Slice has just started. Consider one slice interval */
+	if (!jiffy_elapsed)
+		jiffy_elapsed_rnd = throtl_slice;
+
+	jiffy_elapsed_rnd = roundup(jiffy_elapsed_rnd, throtl_slice);
+
+	/*
+	 * jiffy_elapsed_rnd should not be a big value as minimum iops can be
+	 * 1 then at max jiffy elapsed should be equivalent of 1 second as we
+	 * will allow dispatch after 1 second and after that slice should
+	 * have been trimmed.
+	 */
+
+	tmp = (u64)tg->iops[rw] * jiffy_elapsed_rnd;
+	do_div(tmp, HZ);
+
+	if (tmp > UINT_MAX)
+		io_allowed = UINT_MAX;
+	else
+		io_allowed = tmp;
+
+	if (tg->io_disp[rw] + 1 <= io_allowed) {
+		if (wait)
+			*wait = 0;
+		return 1;
+	}
+
+	/* Calc approx time to dispatch */
+	jiffy_wait = ((tg->io_disp[rw] + 1) * HZ)/tg->iops[rw] + 1;
+
+	if (jiffy_wait > jiffy_elapsed)
+		jiffy_wait = jiffy_wait - jiffy_elapsed;
+	else
+		jiffy_wait = 1;
+
+	if (wait)
+		*wait = jiffy_wait;
+	return 0;
+}
+
+static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
+		struct bio *bio, unsigned long *wait)
+{
+	bool rw = bio_data_dir(bio);
+	u64 bytes_allowed, extra_bytes, tmp;
+	unsigned long jiffy_elapsed, jiffy_wait, jiffy_elapsed_rnd;
+
+	jiffy_elapsed = jiffy_elapsed_rnd = jiffies - tg->slice_start[rw];
+
+	/* Slice has just started. Consider one slice interval */
+	if (!jiffy_elapsed)
+		jiffy_elapsed_rnd = throtl_slice;
+
+	jiffy_elapsed_rnd = roundup(jiffy_elapsed_rnd, throtl_slice);
+
+	tmp = tg->bps[rw] * jiffy_elapsed_rnd;
+	do_div(tmp, HZ);
+	bytes_allowed = tmp;
+
+	if (tg->bytes_disp[rw] + bio->bi_size <= bytes_allowed) {
+		if (wait)
+			*wait = 0;
+		return 1;
+	}
+
+	/* Calc approx time to dispatch */
+	extra_bytes = tg->bytes_disp[rw] + bio->bi_size - bytes_allowed;
+	jiffy_wait = div64_u64(extra_bytes * HZ, tg->bps[rw]);
+
+	if (!jiffy_wait)
+		jiffy_wait = 1;
+
+	/*
+	 * This wait time is without taking into consideration the rounding
+	 * up we did. Add that time also.
+	 */
+	jiffy_wait = jiffy_wait + (jiffy_elapsed_rnd - jiffy_elapsed);
+	if (wait)
+		*wait = jiffy_wait;
+	return 0;
+}
+
+/*
+ * Returns whether one can dispatch a bio or not. Also returns approx number
+ * of jiffies to wait before this bio is with-in IO rate and can be dispatched
+ */
+static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
+				struct bio *bio, unsigned long *wait)
+{
+	bool rw = bio_data_dir(bio);
+	unsigned long bps_wait = 0, iops_wait = 0, max_wait = 0;
+
+	/*
+ 	 * Currently whole state machine of group depends on first bio
+	 * queued in the group bio list. So one should not be calling
+	 * this function with a different bio if there are other bios
+	 * queued.
+	 */
+	BUG_ON(tg->nr_queued[rw] && bio != bio_list_peek(&tg->bio_lists[rw]));
+
+	/* If tg->bps = -1, then BW is unlimited */
+	if (tg->bps[rw] == -1 && tg->iops[rw] == -1) {
+		if (wait)
+			*wait = 0;
+		return 1;
+	}
+
+	/*
+	 * If previous slice expired, start a new one otherwise renew/extend
+	 * existing slice to make sure it is at least throtl_slice interval
+	 * long since now.
+	 */
+	if (throtl_slice_used(td, tg, rw))
+		throtl_start_new_slice(td, tg, rw);
+	else {
+		if (time_before(tg->slice_end[rw], jiffies + throtl_slice))
+			throtl_extend_slice(td, tg, rw, jiffies + throtl_slice);
+	}
+
+	if (tg_with_in_bps_limit(td, tg, bio, &bps_wait)
+	    && tg_with_in_iops_limit(td, tg, bio, &iops_wait)) {
+		if (wait)
+			*wait = 0;
+		return 1;
+	}
+
+	max_wait = max(bps_wait, iops_wait);
+
+	if (wait)
+		*wait = max_wait;
+
+	if (time_before(tg->slice_end[rw], jiffies + max_wait))
+		throtl_extend_slice(td, tg, rw, jiffies + max_wait);
+
+	return 0;
+}
+
+static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
+{
+	bool rw = bio_data_dir(bio);
+	bool sync = bio->bi_rw & REQ_SYNC;
+
+	/* Charge the bio to the group */
+	tg->bytes_disp[rw] += bio->bi_size;
+	tg->io_disp[rw]++;
+
+	/*
+	 * TODO: This will take blkg->stats_lock. Figure out a way
+	 * to avoid this cost.
+	 */
+	blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, rw, sync);
+}
+
+static void throtl_add_bio_tg(struct throtl_data *td, struct throtl_grp *tg,
+			struct bio *bio)
+{
+	bool rw = bio_data_dir(bio);
+
+	bio_list_add(&tg->bio_lists[rw], bio);
+	/* Take a bio reference on tg */
+	throtl_ref_get_tg(tg);
+	tg->nr_queued[rw]++;
+	td->nr_queued[rw]++;
+	throtl_enqueue_tg(td, tg);
+}
+
+static void tg_update_disptime(struct throtl_data *td, struct throtl_grp *tg)
+{
+	unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime;
+	struct bio *bio;
+
+	if ((bio = bio_list_peek(&tg->bio_lists[READ])))
+		tg_may_dispatch(td, tg, bio, &read_wait);
+
+	if ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
+		tg_may_dispatch(td, tg, bio, &write_wait);
+
+	min_wait = min(read_wait, write_wait);
+	disptime = jiffies + min_wait;
+
+	/* Update dispatch time */
+	throtl_dequeue_tg(td, tg);
+	tg->disptime = disptime;
+	throtl_enqueue_tg(td, tg);
+}
+
+static void tg_dispatch_one_bio(struct throtl_data *td, struct throtl_grp *tg,
+				bool rw, struct bio_list *bl)
+{
+	struct bio *bio;
+
+	bio = bio_list_pop(&tg->bio_lists[rw]);
+	tg->nr_queued[rw]--;
+	/* Drop bio reference on tg */
+	throtl_put_tg(tg);
+
+	BUG_ON(td->nr_queued[rw] <= 0);
+	td->nr_queued[rw]--;
+
+	throtl_charge_bio(tg, bio);
+	bio_list_add(bl, bio);
+	bio->bi_rw |= REQ_THROTTLED;
+
+	throtl_trim_slice(td, tg, rw);
+}
+
+static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
+				struct bio_list *bl)
+{
+	unsigned int nr_reads = 0, nr_writes = 0;
+	unsigned int max_nr_reads = throtl_grp_quantum*3/4;
+	unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads;
+	struct bio *bio;
+
+	/* Try to dispatch 75% READS and 25% WRITES */
+
+	while ((bio = bio_list_peek(&tg->bio_lists[READ]))
+		&& tg_may_dispatch(td, tg, bio, NULL)) {
+
+		tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+		nr_reads++;
+
+		if (nr_reads >= max_nr_reads)
+			break;
+	}
+
+	while ((bio = bio_list_peek(&tg->bio_lists[WRITE]))
+		&& tg_may_dispatch(td, tg, bio, NULL)) {
+
+		tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+		nr_writes++;
+
+		if (nr_writes >= max_nr_writes)
+			break;
+	}
+
+	return nr_reads + nr_writes;
+}
+
+static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
+{
+	unsigned int nr_disp = 0;
+	struct throtl_grp *tg;
+	struct throtl_rb_root *st = &td->tg_service_tree;
+
+	while (1) {
+		tg = throtl_rb_first(st);
+
+		if (!tg)
+			break;
+
+		if (time_before(jiffies, tg->disptime))
+			break;
+
+		throtl_dequeue_tg(td, tg);
+
+		nr_disp += throtl_dispatch_tg(td, tg, bl);
+
+		if (tg->nr_queued[0] || tg->nr_queued[1]) {
+			tg_update_disptime(td, tg);
+			throtl_enqueue_tg(td, tg);
+		}
+
+		if (nr_disp >= throtl_quantum)
+			break;
+	}
+
+	return nr_disp;
+}
+
+static void throtl_process_limit_change(struct throtl_data *td)
+{
+	struct throtl_grp *tg;
+	struct hlist_node *pos, *n;
+
+	if (!atomic_read(&td->limits_changed))
+		return;
+
+	throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed));
+
+	/*
+	 * Make sure updates from throtl_update_blkio_group_read_bps() group
+	 * of functions to tg->limits_changed are visible. We do not
+	 * want update td->limits_changed to be visible but update to
+	 * tg->limits_changed not being visible yet on this cpu. Hence
+	 * the read barrier.
+	 */
+	smp_rmb();
+
+	hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
+		if (throtl_tg_on_rr(tg) && tg->limits_changed) {
+			throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
+				" riops=%u wiops=%u", tg->bps[READ],
+				tg->bps[WRITE], tg->iops[READ],
+				tg->iops[WRITE]);
+			tg_update_disptime(td, tg);
+			tg->limits_changed = false;
+		}
+	}
+
+	smp_mb__before_atomic_dec();
+	atomic_dec(&td->limits_changed);
+	smp_mb__after_atomic_dec();
+}
+
+/* Dispatch throttled bios. Should be called without queue lock held. */
+static int throtl_dispatch(struct request_queue *q)
+{
+	struct throtl_data *td = q->td;
+	unsigned int nr_disp = 0;
+	struct bio_list bio_list_on_stack;
+	struct bio *bio;
+
+	spin_lock_irq(q->queue_lock);
+
+	throtl_process_limit_change(td);
+
+	if (!total_nr_queued(td))
+		goto out;
+
+	bio_list_init(&bio_list_on_stack);
+
+	throtl_log(td, "dispatch nr_queued=%lu read=%u write=%u",
+			total_nr_queued(td), td->nr_queued[READ],
+			td->nr_queued[WRITE]);
+
+	nr_disp = throtl_select_dispatch(td, &bio_list_on_stack);
+
+	if (nr_disp)
+		throtl_log(td, "bios disp=%u", nr_disp);
+
+	throtl_schedule_next_dispatch(td);
+out:
+	spin_unlock_irq(q->queue_lock);
+
+	/*
+	 * If we dispatched some requests, unplug the queue to make sure
+	 * immediate dispatch
+	 */
+	if (nr_disp) {
+		while((bio = bio_list_pop(&bio_list_on_stack)))
+			generic_make_request(bio);
+		blk_unplug(q);
+	}
+	return nr_disp;
+}
+
+void blk_throtl_work(struct work_struct *work)
+{
+	struct throtl_data *td = container_of(work, struct throtl_data,
+					throtl_work.work);
+	struct request_queue *q = td->queue;
+
+	throtl_dispatch(q);
+}
+
+/* Call with queue lock held */
+void throtl_schedule_delayed_work(struct request_queue *q, unsigned long delay)
+{
+
+	struct throtl_data *td = q->td;
+	struct delayed_work *dwork = &td->throtl_work;
+
+	if (total_nr_queued(td) > 0) {
+		/*
+		 * We might have a work scheduled to be executed in future.
+		 * Cancel that and schedule a new one.
+		 */
+		__cancel_delayed_work(dwork);
+		kblockd_schedule_delayed_work(q, dwork, delay);
+		throtl_log(td, "schedule work. delay=%lu jiffies=%lu",
+				delay, jiffies);
+	}
+}
+EXPORT_SYMBOL(throtl_schedule_delayed_work);
+
+static void
+throtl_destroy_tg(struct throtl_data *td, struct throtl_grp *tg)
+{
+	/* Something wrong if we are trying to remove same group twice */
+	BUG_ON(hlist_unhashed(&tg->tg_node));
+
+	hlist_del_init(&tg->tg_node);
+
+	/*
+	 * Put the reference taken at the time of creation so that when all
+	 * queues are gone, group can be destroyed.
+	 */
+	throtl_put_tg(tg);
+	td->nr_undestroyed_grps--;
+}
+
+static void throtl_release_tgs(struct throtl_data *td)
+{
+	struct hlist_node *pos, *n;
+	struct throtl_grp *tg;
+
+	hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
+		/*
+		 * If cgroup removal path got to blk_group first and removed
+		 * it from cgroup list, then it will take care of destroying
+		 * cfqg also.
+		 */
+		if (!blkiocg_del_blkio_group(&tg->blkg))
+			throtl_destroy_tg(td, tg);
+	}
+}
+
+static void throtl_td_free(struct throtl_data *td)
+{
+	kfree(td);
+}
+
+/*
+ * Blk cgroup controller notification saying that blkio_group object is being
+ * delinked as associated cgroup object is going away. That also means that
+ * no new IO will come in this group. So get rid of this group as soon as
+ * any pending IO in the group is finished.
+ *
+ * This function is called under rcu_read_lock(). key is the rcu protected
+ * pointer. That means "key" is a valid throtl_data pointer as long as we are
+ * rcu read lock.
+ *
+ * "key" was fetched from blkio_group under blkio_cgroup->lock. That means
+ * it should not be NULL as even if queue was going away, cgroup deltion
+ * path got to it first.
+ */
+void throtl_unlink_blkio_group(void *key, struct blkio_group *blkg)
+{
+	unsigned long flags;
+	struct throtl_data *td = key;
+
+	spin_lock_irqsave(td->queue->queue_lock, flags);
+	throtl_destroy_tg(td, tg_of_blkg(blkg));
+	spin_unlock_irqrestore(td->queue->queue_lock, flags);
+}
+
+/*
+ * For all update functions, key should be a valid pointer because these
+ * update functions are called under blkcg_lock, that means, blkg is
+ * valid and in turn key is valid. queue exit path can not race becuase
+ * of blkcg_lock
+ *
+ * Can not take queue lock in update functions as queue lock under blkcg_lock
+ * is not allowed. Under other paths we take blkcg_lock under queue_lock.
+ */
+static void throtl_update_blkio_group_read_bps(void *key,
+				struct blkio_group *blkg, u64 read_bps)
+{
+	struct throtl_data *td = key;
+
+	tg_of_blkg(blkg)->bps[READ] = read_bps;
+	/* Make sure read_bps is updated before setting limits_changed */
+	smp_wmb();
+	tg_of_blkg(blkg)->limits_changed = true;
+
+	/* Make sure tg->limits_changed is updated before td->limits_changed */
+	smp_mb__before_atomic_inc();
+	atomic_inc(&td->limits_changed);
+	smp_mb__after_atomic_inc();
+
+	/* Schedule a work now to process the limit change */
+	throtl_schedule_delayed_work(td->queue, 0);
+}
+
+static void throtl_update_blkio_group_write_bps(void *key,
+				struct blkio_group *blkg, u64 write_bps)
+{
+	struct throtl_data *td = key;
+
+	tg_of_blkg(blkg)->bps[WRITE] = write_bps;
+	smp_wmb();
+	tg_of_blkg(blkg)->limits_changed = true;
+	smp_mb__before_atomic_inc();
+	atomic_inc(&td->limits_changed);
+	smp_mb__after_atomic_inc();
+	throtl_schedule_delayed_work(td->queue, 0);
+}
+
+static void throtl_update_blkio_group_read_iops(void *key,
+			struct blkio_group *blkg, unsigned int read_iops)
+{
+	struct throtl_data *td = key;
+
+	tg_of_blkg(blkg)->iops[READ] = read_iops;
+	smp_wmb();
+	tg_of_blkg(blkg)->limits_changed = true;
+	smp_mb__before_atomic_inc();
+	atomic_inc(&td->limits_changed);
+	smp_mb__after_atomic_inc();
+	throtl_schedule_delayed_work(td->queue, 0);
+}
+
+static void throtl_update_blkio_group_write_iops(void *key,
+			struct blkio_group *blkg, unsigned int write_iops)
+{
+	struct throtl_data *td = key;
+
+	tg_of_blkg(blkg)->iops[WRITE] = write_iops;
+	smp_wmb();
+	tg_of_blkg(blkg)->limits_changed = true;
+	smp_mb__before_atomic_inc();
+	atomic_inc(&td->limits_changed);
+	smp_mb__after_atomic_inc();
+	throtl_schedule_delayed_work(td->queue, 0);
+}
+
+void throtl_shutdown_timer_wq(struct request_queue *q)
+{
+	struct throtl_data *td = q->td;
+
+	cancel_delayed_work_sync(&td->throtl_work);
+}
+
+static struct blkio_policy_type blkio_policy_throtl = {
+	.ops = {
+		.blkio_unlink_group_fn = throtl_unlink_blkio_group,
+		.blkio_update_group_read_bps_fn =
+					throtl_update_blkio_group_read_bps,
+		.blkio_update_group_write_bps_fn =
+					throtl_update_blkio_group_write_bps,
+		.blkio_update_group_read_iops_fn =
+					throtl_update_blkio_group_read_iops,
+		.blkio_update_group_write_iops_fn =
+					throtl_update_blkio_group_write_iops,
+	},
+	.plid = BLKIO_POLICY_THROTL,
+};
+
+int blk_throtl_bio(struct request_queue *q, struct bio **biop)
+{
+	struct throtl_data *td = q->td;
+	struct throtl_grp *tg;
+	struct bio *bio = *biop;
+	bool rw = bio_data_dir(bio), update_disptime = true;
+
+	if (bio->bi_rw & REQ_THROTTLED) {
+		bio->bi_rw &= ~REQ_THROTTLED;
+		return 0;
+	}
+
+	spin_lock_irq(q->queue_lock);
+	tg = throtl_get_tg(td);
+
+	if (tg->nr_queued[rw]) {
+		/*
+		 * There is already another bio queued in same dir. No
+		 * need to update dispatch time.
+		 * Still update the disptime if rate limits on this group
+		 * were changed.
+		 */
+		if (!tg->limits_changed)
+			update_disptime = false;
+		else
+			tg->limits_changed = false;
+
+		goto queue_bio;
+	}
+
+	/* Bio is with-in rate limit of group */
+	if (tg_may_dispatch(td, tg, bio, NULL)) {
+		throtl_charge_bio(tg, bio);
+		goto out;
+	}
+
+queue_bio:
+	throtl_log_tg(td, tg, "[%c] bio. bdisp=%u sz=%u bps=%llu"
+			" iodisp=%u iops=%u queued=%d/%d",
+			rw == READ ? 'R' : 'W',
+			tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
+			tg->io_disp[rw], tg->iops[rw],
+			tg->nr_queued[READ], tg->nr_queued[WRITE]);
+
+	throtl_add_bio_tg(q->td, tg, bio);
+	*biop = NULL;
+
+	if (update_disptime) {
+		tg_update_disptime(td, tg);
+		throtl_schedule_next_dispatch(td);
+	}
+
+out:
+	spin_unlock_irq(q->queue_lock);
+	return 0;
+}
+
+int blk_throtl_init(struct request_queue *q)
+{
+	struct throtl_data *td;
+	struct throtl_grp *tg;
+
+	td = kzalloc_node(sizeof(*td), GFP_KERNEL, q->node);
+	if (!td)
+		return -ENOMEM;
+
+	INIT_HLIST_HEAD(&td->tg_list);
+	td->tg_service_tree = THROTL_RB_ROOT;
+	atomic_set(&td->limits_changed, 0);
+
+	/* Init root group */
+	tg = &td->root_tg;
+	INIT_HLIST_NODE(&tg->tg_node);
+	RB_CLEAR_NODE(&tg->rb_node);
+	bio_list_init(&tg->bio_lists[0]);
+	bio_list_init(&tg->bio_lists[1]);
+
+	/* Practically unlimited BW */
+	tg->bps[0] = tg->bps[1] = -1;
+	tg->iops[0] = tg->iops[1] = -1;
+
+	/*
+	 * Set root group reference to 2. One reference will be dropped when
+	 * all groups on tg_list are being deleted during queue exit. Other
+	 * reference will remain there as we don't want to delete this group
+	 * as it is statically allocated and gets destroyed when throtl_data
+	 * goes away.
+	 */
+	atomic_set(&tg->ref, 2);
+	hlist_add_head(&tg->tg_node, &td->tg_list);
+	td->nr_undestroyed_grps++;
+
+	INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+
+	rcu_read_lock();
+	blkiocg_add_blkio_group(&blkio_root_cgroup, &tg->blkg, (void *)td,
+					0, BLKIO_POLICY_THROTL);
+	rcu_read_unlock();
+
+	/* Attach throtl data to request queue */
+	td->queue = q;
+	q->td = td;
+	return 0;
+}
+
+void blk_throtl_exit(struct request_queue *q)
+{
+	struct throtl_data *td = q->td;
+	bool wait = false;
+
+	BUG_ON(!td);
+
+	throtl_shutdown_timer_wq(q);
+
+	spin_lock_irq(q->queue_lock);
+	throtl_release_tgs(td);
+
+	/* If there are other groups */
+	if (td->nr_undestroyed_grps > 0)
+		wait = true;
+
+	spin_unlock_irq(q->queue_lock);
+
+	/*
+	 * Wait for tg->blkg->key accessors to exit their grace periods.
+	 * Do this wait only if there are other undestroyed groups out
+	 * there (other than root group). This can happen if cgroup deletion
+	 * path claimed the responsibility of cleaning up a group before
+	 * queue cleanup code get to the group.
+	 *
+	 * Do not call synchronize_rcu() unconditionally as there are drivers
+	 * which create/delete request queue hundreds of times during scan/boot
+	 * and synchronize_rcu() can take significant time and slow down boot.
+	 */
+	if (wait)
+		synchronize_rcu();
+
+	/*
+	 * Just being safe to make sure after previous flush if some body did
+	 * update limits through cgroup and another work got queued, cancel
+	 * it.
+	 */
+	throtl_shutdown_timer_wq(q);
+	throtl_td_free(td);
+}
+
+static int __init throtl_init(void)
+{
+	blkio_policy_register(&blkio_policy_throtl);
+	return 0;
+}
+
+module_init(throtl_init);
diff -druN linux-libre-2.6.36-gnu/block/bsg.c linux-libre-2.6.37-gnu/block/bsg.c
--- linux-libre-2.6.36-gnu/block/bsg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/bsg.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,6 @@
 #include <linux/uio.h>
 #include <linux/idr.h>
 #include <linux/bsg.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 
 #include <scsi/scsi.h>
@@ -251,6 +250,14 @@
 	int ret, rw;
 	unsigned int dxfer_len;
 	void *dxferp = NULL;
+	struct bsg_class_device *bcd = &q->bsg_dev;
+
+	/* if the LLD has been removed then the bsg_unregister_queue will
+	 * eventually be called and the class_dev was freed, so we can no
+	 * longer use this request_queue. Return no such address.
+	 */
+	if (!bcd->class_dev)
+		return ERR_PTR(-ENXIO);
 
 	dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp,
 		hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
@@ -843,9 +850,7 @@
 {
 	struct bsg_device *bd;
 
-	lock_kernel();
 	bd = bsg_get_device(inode, file);
-	unlock_kernel();
 
 	if (IS_ERR(bd))
 		return PTR_ERR(bd);
@@ -968,6 +973,7 @@
 	.release	=	bsg_release,
 	.unlocked_ioctl	=	bsg_ioctl,
 	.owner		=	THIS_MODULE,
+	.llseek		=	default_llseek,
 };
 
 void bsg_unregister_queue(struct request_queue *q)
diff -druN linux-libre-2.6.36-gnu/block/cfq.h linux-libre-2.6.37-gnu/block/cfq.h
--- linux-libre-2.6.36-gnu/block/cfq.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/cfq.h	2011-01-04 19:50:19.000000000 -0500
@@ -69,7 +69,7 @@
 
 static inline void cfq_blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
 			struct blkio_group *blkg, void *key, dev_t dev) {
-	blkiocg_add_blkio_group(blkcg, blkg, key, dev);
+	blkiocg_add_blkio_group(blkcg, blkg, key, dev, BLKIO_POLICY_PROP);
 }
 
 static inline int cfq_blkiocg_del_blkio_group(struct blkio_group *blkg)
diff -druN linux-libre-2.6.36-gnu/block/cfq-iosched.c linux-libre-2.6.37-gnu/block/cfq-iosched.c
--- linux-libre-2.6.36-gnu/block/cfq-iosched.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/cfq-iosched.c	2011-01-04 19:50:19.000000000 -0500
@@ -160,6 +160,7 @@
 	BE_WORKLOAD = 0,
 	RT_WORKLOAD = 1,
 	IDLE_WORKLOAD = 2,
+	CFQ_PRIO_NR,
 };
 
 /*
@@ -184,10 +185,19 @@
 	/* number of cfqq currently on this group */
 	int nr_cfqq;
 
-	/* Per group busy queus average. Useful for workload slice calc. */
-	unsigned int busy_queues_avg[2];
 	/*
-	 * rr lists of queues with requests, onle rr for each priority class.
+	 * Per group busy queus average. Useful for workload slice calc. We
+	 * create the array for each prio class but at run time it is used
+	 * only for RT and BE class and slot for IDLE class remains unused.
+	 * This is primarily done to avoid confusion and a gcc warning.
+	 */
+	unsigned int busy_queues_avg[CFQ_PRIO_NR];
+	/*
+	 * rr lists of queues with requests. We maintain service trees for
+	 * RT and BE classes. These trees are subdivided in subclasses
+	 * of SYNC, SYNC_NOIDLE and ASYNC based on workload type. For IDLE
+	 * class there is no subclassification and all the cfq queues go on
+	 * a single tree service_tree_idle.
 	 * Counts are embedded in the cfq_rb_root
 	 */
 	struct cfq_rb_root service_trees[2][3];
@@ -221,7 +231,6 @@
 	enum wl_type_t serving_type;
 	unsigned long workload_expires;
 	struct cfq_group *serving_group;
-	bool noidle_tree_requires_idle;
 
 	/*
 	 * Each priority tree is sorted by next_request position.  These
@@ -977,8 +986,8 @@
 	return NULL;
 }
 
-void
-cfq_update_blkio_group_weight(struct blkio_group *blkg, unsigned int weight)
+void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
+					unsigned int weight)
 {
 	cfqg_of_blkg(blkg)->weight = weight;
 }
@@ -2180,7 +2189,6 @@
 	slice = max_t(unsigned, slice, CFQ_MIN_TT);
 	cfq_log(cfqd, "workload slice:%d", slice);
 	cfqd->workload_expires = jiffies + slice;
-	cfqd->noidle_tree_requires_idle = false;
 }
 
 static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd)
@@ -3177,7 +3185,9 @@
 	if (cfqq->queued[0] + cfqq->queued[1] >= 4)
 		cfq_mark_cfqq_deep(cfqq);
 
-	if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
+	if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE))
+		enable_idle = 0;
+	else if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
 	    (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq)))
 		enable_idle = 0;
 	else if (sample_valid(cic->ttime_samples)) {
@@ -3494,17 +3504,7 @@
 			cfq_slice_expired(cfqd, 1);
 		else if (sync && cfqq_empty &&
 			 !cfq_close_cooperator(cfqd, cfqq)) {
-			cfqd->noidle_tree_requires_idle |=
-				!(rq->cmd_flags & REQ_NOIDLE);
-			/*
-			 * Idling is enabled for SYNC_WORKLOAD.
-			 * SYNC_NOIDLE_WORKLOAD idles at the end of the tree
-			 * only if we processed at least one !REQ_NOIDLE request
-			 */
-			if (cfqd->serving_type == SYNC_WORKLOAD
-			    || cfqd->noidle_tree_requires_idle
-			    || cfqq->cfqg->nr_cfqq == 1)
-				cfq_arm_slice_timer(cfqd);
+			cfq_arm_slice_timer(cfqd);
 		}
 	}
 
@@ -4090,6 +4090,7 @@
 		.blkio_unlink_group_fn =	cfq_unlink_blkio_group,
 		.blkio_update_group_weight_fn =	cfq_update_blkio_group_weight,
 	},
+	.plid = BLKIO_POLICY_PROP,
 };
 #else
 static struct blkio_policy_type blkio_policy_cfq;
diff -druN linux-libre-2.6.36-gnu/block/compat_ioctl.c linux-libre-2.6.37-gnu/block/compat_ioctl.c
--- linux-libre-2.6.36-gnu/block/compat_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/compat_ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,6 @@
 #include <linux/hdreg.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/uaccess.h>
 
@@ -744,13 +743,13 @@
 		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
 		return 0;
 	case BLKGETSIZE:
-		size = bdev->bd_inode->i_size;
+		size = i_size_read(bdev->bd_inode);
 		if ((size >> 9) > ~0UL)
 			return -EFBIG;
 		return compat_put_ulong(arg, size >> 9);
 
 	case BLKGETSIZE64_32:
-		return compat_put_u64(arg, bdev->bd_inode->i_size);
+		return compat_put_u64(arg, i_size_read(bdev->bd_inode));
 
 	case BLKTRACESETUP32:
 	case BLKTRACESTART: /* compatible */
diff -druN linux-libre-2.6.36-gnu/block/elevator.c linux-libre-2.6.37-gnu/block/elevator.c
--- linux-libre-2.6.36-gnu/block/elevator.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/elevator.c	2011-01-04 19:50:19.000000000 -0500
@@ -429,7 +429,7 @@
 	q->nr_sorted--;
 
 	boundary = q->end_sector;
-	stop_flags = REQ_SOFTBARRIER | REQ_HARDBARRIER | REQ_STARTED;
+	stop_flags = REQ_SOFTBARRIER | REQ_STARTED;
 	list_for_each_prev(entry, &q->queue_head) {
 		struct request *pos = list_entry_rq(entry);
 
@@ -617,8 +617,6 @@
 
 void elv_insert(struct request_queue *q, struct request *rq, int where)
 {
-	struct list_head *pos;
-	unsigned ordseq;
 	int unplug_it = 1;
 
 	trace_block_rq_insert(q, rq);
@@ -626,9 +624,16 @@
 	rq->q = q;
 
 	switch (where) {
+	case ELEVATOR_INSERT_REQUEUE:
+		/*
+		 * Most requeues happen because of a busy condition,
+		 * don't force unplug of the queue for that case.
+		 * Clear unplug_it and fall through.
+		 */
+		unplug_it = 0;
+
 	case ELEVATOR_INSERT_FRONT:
 		rq->cmd_flags |= REQ_SOFTBARRIER;
-
 		list_add(&rq->queuelist, &q->queue_head);
 		break;
 
@@ -668,36 +673,6 @@
 		q->elevator->ops->elevator_add_req_fn(q, rq);
 		break;
 
-	case ELEVATOR_INSERT_REQUEUE:
-		/*
-		 * If ordered flush isn't in progress, we do front
-		 * insertion; otherwise, requests should be requeued
-		 * in ordseq order.
-		 */
-		rq->cmd_flags |= REQ_SOFTBARRIER;
-
-		/*
-		 * Most requeues happen because of a busy condition,
-		 * don't force unplug of the queue for that case.
-		 */
-		unplug_it = 0;
-
-		if (q->ordseq == 0) {
-			list_add(&rq->queuelist, &q->queue_head);
-			break;
-		}
-
-		ordseq = blk_ordered_req_seq(rq);
-
-		list_for_each(pos, &q->queue_head) {
-			struct request *pos_rq = list_entry_rq(pos);
-			if (ordseq <= blk_ordered_req_seq(pos_rq))
-				break;
-		}
-
-		list_add_tail(&rq->queuelist, pos);
-		break;
-
 	default:
 		printk(KERN_ERR "%s: bad insertion point %d\n",
 		       __func__, where);
@@ -716,26 +691,8 @@
 void __elv_add_request(struct request_queue *q, struct request *rq, int where,
 		       int plug)
 {
-	if (q->ordcolor)
-		rq->cmd_flags |= REQ_ORDERED_COLOR;
-
-	if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
-		/*
-		 * toggle ordered color
-		 */
-		if (rq->cmd_flags & REQ_HARDBARRIER)
-			q->ordcolor ^= 1;
-
-		/*
-		 * barriers implicitly indicate back insertion
-		 */
-		if (where == ELEVATOR_INSERT_SORT)
-			where = ELEVATOR_INSERT_BACK;
-
-		/*
-		 * this request is scheduling boundary, update
-		 * end_sector
-		 */
+	if (rq->cmd_flags & REQ_SOFTBARRIER) {
+		/* barriers are scheduling boundary, update end_sector */
 		if (rq->cmd_type == REQ_TYPE_FS ||
 		    (rq->cmd_flags & REQ_DISCARD)) {
 			q->end_sector = rq_end_sector(rq);
@@ -855,24 +812,6 @@
 		    e->ops->elevator_completed_req_fn)
 			e->ops->elevator_completed_req_fn(q, rq);
 	}
-
-	/*
-	 * Check if the queue is waiting for fs requests to be
-	 * drained for flush sequence.
-	 */
-	if (unlikely(q->ordseq)) {
-		struct request *next = NULL;
-
-		if (!list_empty(&q->queue_head))
-			next = list_entry_rq(q->queue_head.next);
-
-		if (!queue_in_flight(q) &&
-		    blk_ordered_cur_seq(q) == QUEUE_ORDSEQ_DRAIN &&
-		    (!next || blk_ordered_req_seq(next) > QUEUE_ORDSEQ_DRAIN)) {
-			blk_ordered_complete_seq(q, QUEUE_ORDSEQ_DRAIN, 0);
-			__blk_run_queue(q);
-		}
-	}
 }
 
 #define to_elv(atr) container_of((atr), struct elv_fs_entry, attr)
diff -druN linux-libre-2.6.36-gnu/block/genhd.c linux-libre-2.6.37-gnu/block/genhd.c
--- linux-libre-2.6.36-gnu/block/genhd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/genhd.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,9 +22,7 @@
 #include "blk.h"
 
 static DEFINE_MUTEX(block_class_lock);
-#ifndef CONFIG_SYSFS_DEPRECATED
 struct kobject *block_depr;
-#endif
 
 /* for extended dynamic devt allocation, currently only one major is used */
 #define MAX_EXT_DEVT		(1 << MINORBITS)
@@ -541,13 +539,15 @@
 	disk->major = MAJOR(devt);
 	disk->first_minor = MINOR(devt);
 
+	/* Register BDI before referencing it from bdev */ 
+	bdi = &disk->queue->backing_dev_info;
+	bdi_register_dev(bdi, disk_devt(disk));
+
 	blk_register_region(disk_devt(disk), disk->minors, NULL,
 			    exact_match, exact_lock, disk);
 	register_disk(disk);
 	blk_register_queue(disk);
 
-	bdi = &disk->queue->backing_dev_info;
-	bdi_register_dev(bdi, disk_devt(disk));
 	retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj,
 				   "bdi");
 	WARN_ON(retval);
@@ -642,6 +642,7 @@
 		struct hd_struct *part;
 		char name_buf[BDEVNAME_SIZE];
 		char devt_buf[BDEVT_SIZE];
+		u8 uuid[PARTITION_META_INFO_UUIDLTH * 2 + 1];
 
 		/*
 		 * Don't show empty devices or things that have been
@@ -660,10 +661,14 @@
 		while ((part = disk_part_iter_next(&piter))) {
 			bool is_part0 = part == &disk->part0;
 
-			printk("%s%s %10llu %s", is_part0 ? "" : "  ",
+			uuid[0] = 0;
+			if (part->info)
+				part_unpack_uuid(part->info->uuid, uuid);
+
+			printk("%s%s %10llu %s %s", is_part0 ? "" : "  ",
 			       bdevt_str(part_devt(part), devt_buf),
 			       (unsigned long long)part->nr_sects >> 1,
-			       disk_name(disk, part->partno, name_buf));
+			       disk_name(disk, part->partno, name_buf), uuid);
 			if (is_part0) {
 				if (disk->driverfs_dev != NULL &&
 				    disk->driverfs_dev->driver != NULL)
@@ -803,10 +808,9 @@
 
 	register_blkdev(BLOCK_EXT_MAJOR, "blkext");
 
-#ifndef CONFIG_SYSFS_DEPRECATED
 	/* create top-level block dir */
-	block_depr = kobject_create_and_add("block", NULL);
-#endif
+	if (!sysfs_deprecated)
+		block_depr = kobject_create_and_add("block", NULL);
 	return 0;
 }
 
@@ -1004,6 +1008,7 @@
 	kfree(disk->random);
 	disk_replace_part_tbl(disk, NULL);
 	free_part_stats(&disk->part0);
+	free_part_info(&disk->part0);
 	kfree(disk);
 }
 struct class block_class = {
diff -druN linux-libre-2.6.36-gnu/block/ioctl.c linux-libre-2.6.37-gnu/block/ioctl.c
--- linux-libre-2.6.36-gnu/block/ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,6 @@
 #include <linux/hdreg.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
 #include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 
@@ -62,7 +61,7 @@
 
 			/* all seems OK */
 			part = add_partition(disk, partno, start, length,
-					     ADDPART_FLAG_NONE);
+					     ADDPART_FLAG_NONE, NULL);
 			mutex_unlock(&bdev->bd_mutex);
 			return IS_ERR(part) ? PTR_ERR(part) : 0;
 		case BLKPG_DEL_PARTITION:
@@ -116,7 +115,7 @@
 static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
 			     uint64_t len, int secure)
 {
-	unsigned long flags = BLKDEV_IFL_WAIT;
+	unsigned long flags = 0;
 
 	if (start & 511)
 		return -EINVAL;
@@ -125,10 +124,10 @@
 	start >>= 9;
 	len >>= 9;
 
-	if (start + len > (bdev->bd_inode->i_size >> 9))
+	if (start + len > (i_size_read(bdev->bd_inode) >> 9))
 		return -EINVAL;
 	if (secure)
-		flags |= BLKDEV_IFL_SECURE;
+		flags |= BLKDEV_DISCARD_SECURE;
 	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
 }
 
@@ -242,6 +241,7 @@
 		 * We need to set the startsect first, the driver may
 		 * want to override it.
 		 */
+		memset(&geo, 0, sizeof(geo));
 		geo.start = get_start_sect(bdev);
 		ret = disk->fops->getgeo(bdev, &geo);
 		if (ret)
@@ -307,12 +307,12 @@
 		ret = blkdev_reread_part(bdev);
 		break;
 	case BLKGETSIZE:
-		size = bdev->bd_inode->i_size;
+		size = i_size_read(bdev->bd_inode);
 		if ((size >> 9) > ~0UL)
 			return -EFBIG;
 		return put_ulong(arg, size >> 9);
 	case BLKGETSIZE64:
-		return put_u64(arg, bdev->bd_inode->i_size);
+		return put_u64(arg, i_size_read(bdev->bd_inode));
 	case BLKTRACESTART:
 	case BLKTRACESTOP:
 	case BLKTRACESETUP:
diff -druN linux-libre-2.6.36-gnu/block/Kconfig linux-libre-2.6.37-gnu/block/Kconfig
--- linux-libre-2.6.36-gnu/block/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -77,6 +77,18 @@
 	T10/SCSI Data Integrity Field or the T13/ATA External Path
 	Protection.  If in doubt, say N.
 
+config BLK_DEV_THROTTLING
+	bool "Block layer bio throttling support"
+	depends on BLK_CGROUP=y && EXPERIMENTAL
+	default n
+	---help---
+	Block layer bio throttling support. It can be used to limit
+	the IO rate to a device. IO rate policies are per cgroup and
+	one needs to mount and use blkio cgroup controller for creating
+	cgroups and specifying per device IO rate policies.
+
+	See Documentation/cgroups/blkio-controller.txt for more information.
+
 endif # BLOCK
 
 config BLOCK_COMPAT
diff -druN linux-libre-2.6.36-gnu/block/Makefile linux-libre-2.6.37-gnu/block/Makefile
--- linux-libre-2.6.36-gnu/block/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,12 +3,13 @@
 #
 
 obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \
-			blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \
+			blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
 			blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
 			blk-iopoll.o blk-lib.o ioctl.o genhd.o scsi_ioctl.o
 
 obj-$(CONFIG_BLK_DEV_BSG)	+= bsg.o
 obj-$(CONFIG_BLK_CGROUP)	+= blk-cgroup.o
+obj-$(CONFIG_BLK_DEV_THROTTLING)	+= blk-throttle.o
 obj-$(CONFIG_IOSCHED_NOOP)	+= noop-iosched.o
 obj-$(CONFIG_IOSCHED_DEADLINE)	+= deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
diff -druN linux-libre-2.6.36-gnu/block/scsi_ioctl.c linux-libre-2.6.37-gnu/block/scsi_ioctl.c
--- linux-libre-2.6.36-gnu/block/scsi_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/block/scsi_ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -321,33 +321,47 @@
 	if (hdr->iovec_count) {
 		const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
 		size_t iov_data_len;
-		struct sg_iovec *iov;
+		struct sg_iovec *sg_iov;
+		struct iovec *iov;
+		int i;
 
-		iov = kmalloc(size, GFP_KERNEL);
-		if (!iov) {
+		sg_iov = kmalloc(size, GFP_KERNEL);
+		if (!sg_iov) {
 			ret = -ENOMEM;
 			goto out;
 		}
 
-		if (copy_from_user(iov, hdr->dxferp, size)) {
-			kfree(iov);
+		if (copy_from_user(sg_iov, hdr->dxferp, size)) {
+			kfree(sg_iov);
 			ret = -EFAULT;
 			goto out;
 		}
 
+		/*
+		 * Sum up the vecs, making sure they don't overflow
+		 */
+		iov = (struct iovec *) sg_iov;
+		iov_data_len = 0;
+		for (i = 0; i < hdr->iovec_count; i++) {
+			if (iov_data_len + iov[i].iov_len < iov_data_len) {
+				kfree(sg_iov);
+				ret = -EINVAL;
+				goto out;
+			}
+			iov_data_len += iov[i].iov_len;
+		}
+
 		/* SG_IO howto says that the shorter of the two wins */
-		iov_data_len = iov_length((struct iovec *)iov,
-					  hdr->iovec_count);
 		if (hdr->dxfer_len < iov_data_len) {
-			hdr->iovec_count = iov_shorten((struct iovec *)iov,
+			hdr->iovec_count = iov_shorten(iov,
 						       hdr->iovec_count,
 						       hdr->dxfer_len);
 			iov_data_len = hdr->dxfer_len;
 		}
 
-		ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count,
+		ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count,
 					  iov_data_len, GFP_KERNEL);
-		kfree(iov);
+		kfree(sg_iov);
 	} else if (hdr->dxfer_len)
 		ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len,
 				      GFP_KERNEL);
diff -druN linux-libre-2.6.36-gnu/crypto/async_tx/async_memcpy.c linux-libre-2.6.37-gnu/crypto/async_tx/async_memcpy.c
--- linux-libre-2.6.36-gnu/crypto/async_tx/async_memcpy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/async_tx/async_memcpy.c	2011-01-04 19:50:19.000000000 -0500
@@ -83,8 +83,8 @@
 
 		memcpy(dest_buf, src_buf, len);
 
-		kunmap_atomic(dest_buf, KM_USER0);
 		kunmap_atomic(src_buf, KM_USER1);
+		kunmap_atomic(dest_buf, KM_USER0);
 
 		async_tx_sync_epilog(submit);
 	}
diff -druN linux-libre-2.6.36-gnu/crypto/async_tx/Kconfig linux-libre-2.6.37-gnu/crypto/async_tx/Kconfig
--- linux-libre-2.6.36-gnu/crypto/async_tx/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/async_tx/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -24,19 +24,6 @@
 	select ASYNC_PQ
 	select ASYNC_XOR
 
-config ASYNC_RAID6_TEST
-	tristate "Self test for hardware accelerated raid6 recovery"
-	depends on ASYNC_RAID6_RECOV
-	select ASYNC_MEMCPY
-	---help---
-	  This is a one-shot self test that permutes through the
-	  recovery of all the possible two disk failure scenarios for a
-	  N-disk array.  Recovery is performed with the asynchronous
-	  raid6 recovery routines, and will optionally use an offload
-	  engine if one is available.
-
-	  If unsure, say N.
-
 config ASYNC_TX_DISABLE_PQ_VAL_DMA
 	bool
 
diff -druN linux-libre-2.6.36-gnu/crypto/blkcipher.c linux-libre-2.6.37-gnu/crypto/blkcipher.c
--- linux-libre-2.6.36-gnu/crypto/blkcipher.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/blkcipher.c	2011-01-04 19:50:19.000000000 -0500
@@ -89,9 +89,9 @@
 		memcpy(walk->dst.virt.addr, walk->page, n);
 		blkcipher_unmap_dst(walk);
 	} else if (!(walk->flags & BLKCIPHER_WALK_PHYS)) {
-		blkcipher_unmap_src(walk);
 		if (walk->flags & BLKCIPHER_WALK_DIFF)
 			blkcipher_unmap_dst(walk);
+		blkcipher_unmap_src(walk);
 	}
 
 	scatterwalk_advance(&walk->in, n);
diff -druN linux-libre-2.6.36-gnu/crypto/cryptd.c linux-libre-2.6.37-gnu/crypto/cryptd.c
--- linux-libre-2.6.36-gnu/crypto/cryptd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/cryptd.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,13 @@
  *
  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
  *
+ * Added AEAD support to cryptd.
+ *    Authors: Tadeusz Struk (tadeusz.struk@intel.com)
+ *             Adrian Hoban <adrian.hoban@intel.com>
+ *             Gabriele Paoloni <gabriele.paoloni@intel.com>
+ *             Aidan O'Mahony (aidan.o.mahony@intel.com)
+ *    Copyright (c) 2010, Intel Corporation.
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, or (at your option)
@@ -12,6 +19,7 @@
 
 #include <crypto/algapi.h>
 #include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
 #include <crypto/cryptd.h>
 #include <crypto/crypto_wq.h>
 #include <linux/err.h>
@@ -44,6 +52,11 @@
 	struct cryptd_queue *queue;
 };
 
+struct aead_instance_ctx {
+	struct crypto_aead_spawn aead_spawn;
+	struct cryptd_queue *queue;
+};
+
 struct cryptd_blkcipher_ctx {
 	struct crypto_blkcipher *child;
 };
@@ -61,6 +74,14 @@
 	struct shash_desc desc;
 };
 
+struct cryptd_aead_ctx {
+	struct crypto_aead *child;
+};
+
+struct cryptd_aead_request_ctx {
+	crypto_completion_t complete;
+};
+
 static void cryptd_queue_worker(struct work_struct *work);
 
 static int cryptd_init_queue(struct cryptd_queue *queue,
@@ -601,6 +622,144 @@
 	return err;
 }
 
+static void cryptd_aead_crypt(struct aead_request *req,
+			struct crypto_aead *child,
+			int err,
+			int (*crypt)(struct aead_request *req))
+{
+	struct cryptd_aead_request_ctx *rctx;
+	rctx = aead_request_ctx(req);
+
+	if (unlikely(err == -EINPROGRESS))
+		goto out;
+	aead_request_set_tfm(req, child);
+	err = crypt( req );
+	req->base.complete = rctx->complete;
+out:
+	local_bh_disable();
+	rctx->complete(&req->base, err);
+	local_bh_enable();
+}
+
+static void cryptd_aead_encrypt(struct crypto_async_request *areq, int err)
+{
+	struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm);
+	struct crypto_aead *child = ctx->child;
+	struct aead_request *req;
+
+	req = container_of(areq, struct aead_request, base);
+	cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->encrypt);
+}
+
+static void cryptd_aead_decrypt(struct crypto_async_request *areq, int err)
+{
+	struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(areq->tfm);
+	struct crypto_aead *child = ctx->child;
+	struct aead_request *req;
+
+	req = container_of(areq, struct aead_request, base);
+	cryptd_aead_crypt(req, child, err, crypto_aead_crt(child)->decrypt);
+}
+
+static int cryptd_aead_enqueue(struct aead_request *req,
+				    crypto_completion_t complete)
+{
+	struct cryptd_aead_request_ctx *rctx = aead_request_ctx(req);
+	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+	struct cryptd_queue *queue = cryptd_get_queue(crypto_aead_tfm(tfm));
+
+	rctx->complete = req->base.complete;
+	req->base.complete = complete;
+	return cryptd_enqueue_request(queue, &req->base);
+}
+
+static int cryptd_aead_encrypt_enqueue(struct aead_request *req)
+{
+	return cryptd_aead_enqueue(req, cryptd_aead_encrypt );
+}
+
+static int cryptd_aead_decrypt_enqueue(struct aead_request *req)
+{
+	return cryptd_aead_enqueue(req, cryptd_aead_decrypt );
+}
+
+static int cryptd_aead_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct aead_instance_ctx *ictx = crypto_instance_ctx(inst);
+	struct crypto_aead_spawn *spawn = &ictx->aead_spawn;
+	struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_aead *cipher;
+
+	cipher = crypto_spawn_aead(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	crypto_aead_set_flags(cipher, CRYPTO_TFM_REQ_MAY_SLEEP);
+	ctx->child = cipher;
+	tfm->crt_aead.reqsize = sizeof(struct cryptd_aead_request_ctx);
+	return 0;
+}
+
+static void cryptd_aead_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct cryptd_aead_ctx *ctx = crypto_tfm_ctx(tfm);
+	crypto_free_aead(ctx->child);
+}
+
+static int cryptd_create_aead(struct crypto_template *tmpl,
+		              struct rtattr **tb,
+			      struct cryptd_queue *queue)
+{
+	struct aead_instance_ctx *ctx;
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+	int err;
+
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_AEAD,
+				CRYPTO_ALG_TYPE_MASK);
+        if (IS_ERR(alg))
+		return PTR_ERR(alg);
+
+	inst = cryptd_alloc_instance(alg, 0, sizeof(*ctx));
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	ctx = crypto_instance_ctx(inst);
+	ctx->queue = queue;
+
+	err = crypto_init_spawn(&ctx->aead_spawn.base, alg, inst,
+			CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+	if (err)
+		goto out_free_inst;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+	inst->alg.cra_type = alg->cra_type;
+	inst->alg.cra_ctxsize = sizeof(struct cryptd_aead_ctx);
+	inst->alg.cra_init = cryptd_aead_init_tfm;
+	inst->alg.cra_exit = cryptd_aead_exit_tfm;
+	inst->alg.cra_aead.setkey      = alg->cra_aead.setkey;
+	inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize;
+	inst->alg.cra_aead.geniv       = alg->cra_aead.geniv;
+	inst->alg.cra_aead.ivsize      = alg->cra_aead.ivsize;
+	inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize;
+	inst->alg.cra_aead.encrypt     = cryptd_aead_encrypt_enqueue;
+	inst->alg.cra_aead.decrypt     = cryptd_aead_decrypt_enqueue;
+	inst->alg.cra_aead.givencrypt  = alg->cra_aead.givencrypt;
+	inst->alg.cra_aead.givdecrypt  = alg->cra_aead.givdecrypt;
+
+	err = crypto_register_instance(tmpl, inst);
+	if (err) {
+		crypto_drop_spawn(&ctx->aead_spawn.base);
+out_free_inst:
+		kfree(inst);
+	}
+out_put_alg:
+	crypto_mod_put(alg);
+	return err;
+}
+
 static struct cryptd_queue queue;
 
 static int cryptd_create(struct crypto_template *tmpl, struct rtattr **tb)
@@ -616,6 +775,8 @@
 		return cryptd_create_blkcipher(tmpl, tb, &queue);
 	case CRYPTO_ALG_TYPE_DIGEST:
 		return cryptd_create_hash(tmpl, tb, &queue);
+	case CRYPTO_ALG_TYPE_AEAD:
+		return cryptd_create_aead(tmpl, tb, &queue);
 	}
 
 	return -EINVAL;
@@ -625,16 +786,21 @@
 {
 	struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst);
 	struct hashd_instance_ctx *hctx = crypto_instance_ctx(inst);
+	struct aead_instance_ctx *aead_ctx = crypto_instance_ctx(inst);
 
 	switch (inst->alg.cra_flags & CRYPTO_ALG_TYPE_MASK) {
 	case CRYPTO_ALG_TYPE_AHASH:
 		crypto_drop_shash(&hctx->spawn);
 		kfree(ahash_instance(inst));
 		return;
+	case CRYPTO_ALG_TYPE_AEAD:
+		crypto_drop_spawn(&aead_ctx->aead_spawn.base);
+		kfree(inst);
+		return;
+	default:
+		crypto_drop_spawn(&ctx->spawn);
+		kfree(inst);
 	}
-
-	crypto_drop_spawn(&ctx->spawn);
-	kfree(inst);
 }
 
 static struct crypto_template cryptd_tmpl = {
@@ -724,6 +890,40 @@
 }
 EXPORT_SYMBOL_GPL(cryptd_free_ahash);
 
+struct cryptd_aead *cryptd_alloc_aead(const char *alg_name,
+						  u32 type, u32 mask)
+{
+	char cryptd_alg_name[CRYPTO_MAX_ALG_NAME];
+	struct crypto_aead *tfm;
+
+	if (snprintf(cryptd_alg_name, CRYPTO_MAX_ALG_NAME,
+		     "cryptd(%s)", alg_name) >= CRYPTO_MAX_ALG_NAME)
+		return ERR_PTR(-EINVAL);
+	tfm = crypto_alloc_aead(cryptd_alg_name, type, mask);
+	if (IS_ERR(tfm))
+		return ERR_CAST(tfm);
+	if (tfm->base.__crt_alg->cra_module != THIS_MODULE) {
+		crypto_free_aead(tfm);
+		return ERR_PTR(-EINVAL);
+	}
+	return __cryptd_aead_cast(tfm);
+}
+EXPORT_SYMBOL_GPL(cryptd_alloc_aead);
+
+struct crypto_aead *cryptd_aead_child(struct cryptd_aead *tfm)
+{
+	struct cryptd_aead_ctx *ctx;
+	ctx = crypto_aead_ctx(&tfm->base);
+	return ctx->child;
+}
+EXPORT_SYMBOL_GPL(cryptd_aead_child);
+
+void cryptd_free_aead(struct cryptd_aead *tfm)
+{
+	crypto_free_aead(&tfm->base);
+}
+EXPORT_SYMBOL_GPL(cryptd_free_aead);
+
 static int __init cryptd_init(void)
 {
 	int err;
diff -druN linux-libre-2.6.36-gnu/crypto/des_generic.c linux-libre-2.6.37-gnu/crypto/des_generic.c
--- linux-libre-2.6.36-gnu/crypto/des_generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/des_generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -614,7 +614,7 @@
 #define T3(x) pt[2 * (x) + 2]
 #define T4(x) pt[2 * (x) + 3]
 
-#define PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
+#define DES_PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
 
 /*
  * Encryption key expansion
@@ -639,22 +639,22 @@
 	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
 	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
 
-	pe[15 * 2 + 0] = PC2(a, b, c, d); d = rs[d];
-	pe[14 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[13 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[12 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[11 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[10 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 9 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 8 * 2 + 0] = PC2(d, a, b, c); c = rs[c];
-	pe[ 7 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 6 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 5 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 4 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 3 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 2 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 1 * 2 + 0] = PC2(c, d, a, b); b = rs[b];
-	pe[ 0 * 2 + 0] = PC2(b, c, d, a);
+	pe[15 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d];
+	pe[14 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[13 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[12 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[11 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[10 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 9 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 8 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c];
+	pe[ 7 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 6 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 5 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 4 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 3 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 2 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 1 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b];
+	pe[ 0 * 2 + 0] = DES_PC2(b, c, d, a);
 
 	/* Check if first half is weak */
 	w  = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
@@ -670,22 +670,22 @@
 	/* Check if second half is weak */
 	w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
 
-	pe[15 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
-	pe[14 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[13 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[12 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[11 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[10 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 9 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 8 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
-	pe[ 7 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 6 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 5 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 4 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 3 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 2 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[ 1 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
-	pe[ 0 * 2 + 1] = PC2(b, c, d, a);
+	pe[15 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
+	pe[14 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[13 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[12 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[11 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[10 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 9 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 8 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
+	pe[ 7 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 6 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 5 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 4 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 3 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 2 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[ 1 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
+	pe[ 0 * 2 + 1] = DES_PC2(b, c, d, a);
 
 	/* Fixup: 2413 5768 -> 1357 2468 */
 	for (d = 0; d < 16; ++d) {
@@ -722,22 +722,22 @@
 	b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
 	a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
 
-	pe[ 0 * 2] = PC2(a, b, c, d); d = rs[d];
-	pe[ 1 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 2 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 3 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 4 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 5 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 6 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 7 * 2] = PC2(d, a, b, c); c = rs[c];
-	pe[ 8 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 9 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[10 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[11 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[12 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[13 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[14 * 2] = PC2(c, d, a, b); b = rs[b];
-	pe[15 * 2] = PC2(b, c, d, a);
+	pe[ 0 * 2] = DES_PC2(a, b, c, d); d = rs[d];
+	pe[ 1 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 2 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 3 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 4 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 5 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 6 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 7 * 2] = DES_PC2(d, a, b, c); c = rs[c];
+	pe[ 8 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 9 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[10 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[11 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[12 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[13 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[14 * 2] = DES_PC2(c, d, a, b); b = rs[b];
+	pe[15 * 2] = DES_PC2(b, c, d, a);
 
 	/* Skip to next table set */
 	pt += 512;
@@ -747,22 +747,22 @@
 	b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
 	a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
 
-	pe[ 0 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
-	pe[ 1 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 2 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 3 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 4 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 5 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-	pe[ 6 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-	pe[ 7 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
-	pe[ 8 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[ 9 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[10 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[11 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[12 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-	pe[13 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-	pe[14 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
-	pe[15 * 2 + 1] = PC2(b, c, d, a);
+	pe[ 0 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
+	pe[ 1 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 2 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 3 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 4 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 5 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+	pe[ 6 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+	pe[ 7 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
+	pe[ 8 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[ 9 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[10 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[11 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[12 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+	pe[13 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+	pe[14 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
+	pe[15 * 2 + 1] = DES_PC2(b, c, d, a);
 
 	/* Fixup: 2413 5768 -> 1357 2468 */
 	for (d = 0; d < 16; ++d) {
diff -druN linux-libre-2.6.36-gnu/crypto/Kconfig linux-libre-2.6.37-gnu/crypto/Kconfig
--- linux-libre-2.6.36-gnu/crypto/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -23,13 +23,12 @@
 
 config CRYPTO_FIPS
 	bool "FIPS 200 compliance"
-	depends on CRYPTO_ANSI_CPRNG
+	depends on CRYPTO_ANSI_CPRNG && !CRYPTO_MANAGER_DISABLE_TESTS
 	help
 	  This options enables the fips boot option which is
 	  required if you want to system to operate in a FIPS 200
 	  certification.  You should say no unless you know what
-	  this is. Note that CRYPTO_ANSI_CPRNG is required if this
-	  option is selected
+	  this is.
 
 config CRYPTO_ALGAPI
 	tristate
@@ -365,7 +364,7 @@
 	  RIPEMD-160 should be used.
 
 	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD160
 	tristate "RIPEMD-160 digest algorithm"
@@ -382,7 +381,7 @@
 	  against RIPEMD-160.
 
 	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD256
 	tristate "RIPEMD-256 digest algorithm"
@@ -394,7 +393,7 @@
 	  (than RIPEMD-128).
 
 	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_RMD320
 	tristate "RIPEMD-320 digest algorithm"
@@ -406,7 +405,7 @@
 	  (than RIPEMD-160).
 
 	  Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
-	  See <http://home.esat.kuleuven.be/~bosselae/ripemd160.html>
+	  See <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
 
 config CRYPTO_SHA1
 	tristate "SHA1 digest algorithm"
@@ -461,7 +460,7 @@
 	  Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard
 
 	  See also:
-	  <http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html>
+	  <http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html>
 
 config CRYPTO_GHASH_CLMUL_NI_INTEL
 	tristate "GHASH digest algorithm (CLMUL-NI accelerated)"
@@ -579,8 +578,8 @@
 	  in the NESSIE competition.
 
 	  See also:
-	  <https://www.cosic.esat.kuleuven.ac.be/nessie/reports/>
-	  <http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html>
+	  <https://www.cosic.esat.kuleuven.be/nessie/reports/>
+	  <http://www.larc.usp.br/~pbarreto/AnubisPage.html>
 
 config CRYPTO_ARC4
 	tristate "ARC4 cipher algorithm"
@@ -659,7 +658,7 @@
 	  on 32-bit processors.  Khazad uses an 128 bit key size.
 
 	  See also:
-	  <http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html>
+	  <http://www.larc.usp.br/~pbarreto/KhazadPage.html>
 
 config CRYPTO_SALSA20
 	tristate "Salsa20 stream cipher algorithm (EXPERIMENTAL)"
diff -druN linux-libre-2.6.36-gnu/crypto/pcrypt.c linux-libre-2.6.37-gnu/crypto/pcrypt.c
--- linux-libre-2.6.36-gnu/crypto/pcrypt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/crypto/pcrypt.c	2011-01-04 19:50:19.000000000 -0500
@@ -504,7 +504,6 @@
 
 static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
 {
-	kobject_put(&pcrypt->pinst->kobj);
 	free_cpumask_var(pcrypt->cb_cpumask->mask);
 	kfree(pcrypt->cb_cpumask);
 
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/obsolete/dv1394 linux-libre-2.6.37-gnu/Documentation/ABI/obsolete/dv1394
--- linux-libre-2.6.36-gnu/Documentation/ABI/obsolete/dv1394	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ABI/obsolete/dv1394	1969-12-31 19:00:00.000000000 -0500
@@ -1,9 +0,0 @@
-What:		dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
-Contact:	linux1394-devel@lists.sourceforge.net
-Description:
-	New application development should use raw1394 + userspace libraries
-	instead, notably libiec61883 which is functionally equivalent.
-
-Users:
-	ffmpeg/libavformat (used by a variety of media players)
-	dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/obsolete/proc-pid-oom_adj linux-libre-2.6.37-gnu/Documentation/ABI/obsolete/proc-pid-oom_adj
--- linux-libre-2.6.36-gnu/Documentation/ABI/obsolete/proc-pid-oom_adj	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/obsolete/proc-pid-oom_adj	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,22 @@
+What:	/proc/<pid>/oom_adj
+When:	August 2012
+Why:	/proc/<pid>/oom_adj allows userspace to influence the oom killer's
+	badness heuristic used to determine which task to kill when the kernel
+	is out of memory.
+
+	The badness heuristic has since been rewritten since the introduction of
+	this tunable such that its meaning is deprecated.  The value was
+	implemented as a bitshift on a score generated by the badness()
+	function that did not have any precise units of measure.  With the
+	rewrite, the score is given as a proportion of available memory to the
+	task allocating pages, so using a bitshift which grows the score
+	exponentially is, thus, impossible to tune with fine granularity.
+
+	A much more powerful interface, /proc/<pid>/oom_score_adj, was
+	introduced with the oom killer rewrite that allows users to increase or
+	decrease the badness() score linearly.  This interface will replace
+	/proc/<pid>/oom_adj.
+
+	A warning will be emitted to the kernel log if an application uses this
+	deprecated interface.  After it is printed once, future warnings will be
+	suppressed until the kernel is rebooted.
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/removed/dv1394 linux-libre-2.6.37-gnu/Documentation/ABI/removed/dv1394
--- linux-libre-2.6.36-gnu/Documentation/ABI/removed/dv1394	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/removed/dv1394	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,14 @@
+What:		dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
+Date:		May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:	linux1394-devel@lists.sourceforge.net
+Description:
+	/dev/dv1394/* were character device files, one for each FireWire
+	controller and for NTSC and PAL respectively, from which DV data
+	could be received by read() or transmitted by write().  A few
+	ioctl()s allowed limited control.
+	This special-purpose interface has been superseded by libraw1394 +
+	libiec61883 which are functionally equivalent, support HDV, and
+	transparently work on top of the newer firewire kernel drivers.
+
+Users:
+	ffmpeg/libavformat (if configured for DV1394)
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/removed/raw1394 linux-libre-2.6.37-gnu/Documentation/ABI/removed/raw1394
--- linux-libre-2.6.36-gnu/Documentation/ABI/removed/raw1394	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/removed/raw1394	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,15 @@
+What:		raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
+Date:		May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:	linux1394-devel@lists.sourceforge.net
+Description:
+	/dev/raw1394 was a character device file that allowed low-level
+	access to FireWire buses.  Its major drawbacks were its inability
+	to implement sensible device security policies, and its low level
+	of abstraction that required userspace clients do duplicate much
+	of the kernel's ieee1394 core functionality.
+	Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+	firewire-core.
+
+Users:
+	libraw1394 (works with firewire-cdev too, transparent to library ABI
+	users)
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/removed/raw1394_legacy_isochronous linux-libre-2.6.37-gnu/Documentation/ABI/removed/raw1394_legacy_isochronous
--- linux-libre-2.6.36-gnu/Documentation/ABI/removed/raw1394_legacy_isochronous	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ABI/removed/raw1394_legacy_isochronous	1969-12-31 19:00:00.000000000 -0500
@@ -1,16 +0,0 @@
-What:		legacy isochronous ABI of raw1394 (1st generation iso ABI)
-Date:		June 2007 (scheduled), removed in kernel v2.6.23
-Contact:	linux1394-devel@lists.sourceforge.net
-Description:
-	The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
-	been deprecated for quite some time.  They are very inefficient as they
-	come with high interrupt load and several layers of callbacks for each
-	packet.  Because of these deficiencies, the video1394 and dv1394 drivers
-	and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
-
-Users:
-	libraw1394 users via the long deprecated API raw1394_iso_write,
-	raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
-
-	libdc1394, which optionally uses these old libraw1394 calls
-	alternatively to the more efficient video1394 ABI
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/removed/video1394 linux-libre-2.6.37-gnu/Documentation/ABI/removed/video1394
--- linux-libre-2.6.36-gnu/Documentation/ABI/removed/video1394	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/removed/video1394	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+What:		video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
+Date:		May 2010 (scheduled), finally removed in kernel v2.6.37
+Contact:	linux1394-devel@lists.sourceforge.net
+Description:
+	/dev/video1394/* were character device files, one for each FireWire
+	controller, which were used for isochronous I/O.  It was added as an
+	alternative to raw1394's isochronous I/O functionality which had
+	performance issues in its first generation.  Any video1394 user had
+	to use raw1394 + libraw1394 too because video1394 did not provide
+	asynchronous I/O for device discovery and configuration.
+	Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
+	firewire-core.
+
+Users:
+	libdc1394 (works with firewire-cdev too, transparent to library ABI
+	users)
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-ata linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-ata
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-ata	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-ata	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,99 @@
+What:		/sys/class/ata_...
+Date:		August 2008
+Contact:	Gwendal Grignou<gwendal@google.com>
+Description:
+
+Provide a place in sysfs for storing the ATA topology of the system.  This allows
+retrieving various information about ATA objects.
+
+Files under /sys/class/ata_port
+-------------------------------
+
+	For each port, a directory ataX is created where X is the ata_port_id of
+	the port. The device parent is the ata host device.
+
+idle_irq (read)
+
+	Number of IRQ received by the port while idle [some ata HBA only].
+
+nr_pmp_links (read)
+
+	If a SATA Port Multiplier (PM) is connected, number of link behind it.
+
+Files under /sys/class/ata_link
+-------------------------------
+
+	Behind each port, there is a ata_link. If there is a SATA PM in the
+	topology, 15 ata_link objects are created.
+
+	If a link is behind a port, the directory name is linkX, where X is
+	ata_port_id of the port.
+	If a link is behind a PM, its name is linkX.Y where X is ata_port_id
+	of the parent port and Y the PM port.
+
+hw_sata_spd_limit
+
+	Maximum speed supported by the connected SATA device.
+
+sata_spd_limit
+
+	Maximum speed imposed by libata.
+
+sata_spd
+
+	Current speed of the link [1.5, 3Gps,...].
+
+Files under /sys/class/ata_device
+---------------------------------
+
+	Behind each link, up to two ata device are created.
+	The name of the directory is devX[.Y].Z where:
+	- X is ata_port_id of the port where the device is connected,
+	- Y the port of the PM if any, and
+	- Z the device id: for PATA, there is usually 2 devices [0,1],
+	only 1 for SATA.
+
+class
+	Device class. Can be "ata" for disk, "atapi" for packet device,
+	"pmp" for PM, or "none" if no device was found behind the link.
+
+dma_mode
+
+	Transfer modes supported by the device when in DMA mode.
+	Mostly used by PATA device.
+
+pio_mode
+
+	Transfer modes supported by the device when in PIO mode.
+	Mostly used by PATA device.
+
+xfer_mode
+
+	Current transfer mode.
+
+id
+
+	Cached result of IDENTIFY command, as described in ATA8 7.16 and 7.17.
+	Only valid if the device is not a PM.
+
+gscr
+
+	Cached result of the dump of PM GSCR register.
+	Valid registers are:
+	0: 	SATA_PMP_GSCR_PROD_ID,
+	1: 	SATA_PMP_GSCR_REV,
+	2: 	SATA_PMP_GSCR_PORT_INFO,
+	32:	SATA_PMP_GSCR_ERROR,
+	33:	SATA_PMP_GSCR_ERROR_EN,
+	64:	SATA_PMP_GSCR_FEAT,
+	96:	SATA_PMP_GSCR_FEAT_EN,
+	130:	SATA_PMP_GSCR_SII_GPIO
+	Only valid if the device is a PM.
+
+spdn_cnt
+
+	Number of time libata decided to lower the speed of link due to errors.
+
+ering
+
+	Formatted output of the error ring of the device.
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-block-zram linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-block-zram
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-block-zram	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-block-zram	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,99 @@
+What:		/sys/block/zram<id>/disksize
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The disksize file is read-write and specifies the disk size
+		which represents the limit on the *uncompressed* worth of data
+		that can be stored in this disk.
+
+What:		/sys/block/zram<id>/initstate
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The disksize file is read-only and shows the initialization
+		state of the device.
+
+What:		/sys/block/zram<id>/reset
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The disksize file is write-only and allows resetting the
+		device. The reset operation frees all the memory assocaited
+		with this device.
+
+What:		/sys/block/zram<id>/num_reads
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The num_reads file is read-only and specifies the number of
+		reads (failed or successful) done on this device.
+
+What:		/sys/block/zram<id>/num_writes
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The num_writes file is read-only and specifies the number of
+		writes (failed or successful) done on this device.
+
+What:		/sys/block/zram<id>/invalid_io
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The invalid_io file is read-only and specifies the number of
+		non-page-size-aligned I/O requests issued to this device.
+
+What:		/sys/block/zram<id>/notify_free
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The notify_free file is read-only and specifies the number of
+		swap slot free notifications received by this device. These
+		notifications are send to a swap block device when a swap slot
+		is freed. This statistic is applicable only when this disk is
+		being used as a swap disk.
+
+What:		/sys/block/zram<id>/discard
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The discard file is read-only and specifies the number of
+		discard requests received by this device. These requests
+		provide information to block device regarding blocks which are
+		no longer used by filesystem.
+
+What:		/sys/block/zram<id>/zero_pages
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The zero_pages file is read-only and specifies number of zero
+		filled pages written to this disk. No memory is allocated for
+		such pages.
+
+What:		/sys/block/zram<id>/orig_data_size
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The orig_data_size file is read-only and specifies uncompressed
+		size of data stored in this disk. This excludes zero-filled
+		pages (zero_pages) since no memory is allocated for them.
+		Unit: bytes
+
+What:		/sys/block/zram<id>/compr_data_size
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The compr_data_size file is read-only and specifies compressed
+		size of data stored in this disk. So, compression ratio can be
+		calculated using orig_data_size and this statistic.
+		Unit: bytes
+
+What:		/sys/block/zram<id>/mem_used_total
+Date:		August 2010
+Contact:	Nitin Gupta <ngupta@vflare.org>
+Description:
+		The mem_used_total file is read-only and specifies the amount
+		of memory, including allocator fragmentation and metadata
+		overhead, allocated for this disk. So, allocator space
+		efficiency can be calculated using compr_data_size and this
+		statistic.
+		Unit: bytes
\ No newline at end of file
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-bus-rbd linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-bus-rbd
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-bus-rbd	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-bus-rbd	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,83 @@
+What:		/sys/bus/rbd/
+Date:		November 2010
+Contact:	Yehuda Sadeh <yehuda@hq.newdream.net>,
+		Sage Weil <sage@newdream.net>
+Description:
+
+Being used for adding and removing rbd block devices.
+
+Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
+
+ $ echo "192.168.0.1 name=admin rbd foo" > /sys/bus/rbd/add
+
+The snapshot name can be "-" or omitted to map the image read/write. A <dev-id>
+will be assigned for any registered block device. If snapshot is used, it will
+be mapped read-only.
+
+Removal of a device:
+
+  $ echo <dev-id> > /sys/bus/rbd/remove
+
+Entries under /sys/bus/rbd/devices/<dev-id>/
+--------------------------------------------
+
+client_id
+
+	The ceph unique client id that was assigned for this specific session.
+
+major
+
+	The block device major number.
+
+name
+
+	The name of the rbd image.
+
+pool
+
+	The pool where this rbd image resides. The pool-name pair is unique
+	per rados system.
+
+size
+
+	The size (in bytes) of the mapped block device.
+
+refresh
+
+	Writing to this file will reread the image header data and set
+	all relevant datastructures accordingly.
+
+current_snap
+
+	The current snapshot for which the device is mapped.
+
+create_snap
+
+	Create a snapshot:
+
+	 $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_create
+
+rollback_snap
+
+	Rolls back data to the specified snapshot. This goes over the entire
+	list of rados blocks and sends a rollback command to each.
+
+	 $ echo <snap-name> > /sys/bus/rbd/devices/<dev-id>/snap_rollback
+
+snap_*
+
+	A directory per each snapshot
+
+
+Entries under /sys/bus/rbd/devices/<dev-id>/snap_<snap-name>
+-------------------------------------------------------------
+
+id
+
+	The rados internal snapshot id assigned for this snapshot
+
+size
+
+	The size of the image when this snapshot was taken.
+
+
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-devices-power linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-devices-power
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-devices-power	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-devices-power	2011-01-04 19:50:19.000000000 -0500
@@ -77,3 +77,91 @@
 		devices this attribute is set to "enabled" by bus type code or
 		device drivers and in that cases it should be safe to leave the
 		default value.
+
+What:		/sys/devices/.../power/wakeup_count
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_count attribute contains the number
+		of signaled wakeup events associated with the device.  This
+		attribute is read-only.  If the device is not enabled to wake up
+		the system from sleep states, this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_active_count
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_active_count attribute contains the
+		number of times the processing of wakeup events associated with
+		the device was completed (at the kernel level).  This attribute
+		is read-only.  If the device is not enabled to wake up the
+		system from sleep states, this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_hit_count
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_hit_count attribute contains the
+		number of times the processing of a wakeup event associated with
+		the device might prevent the system from entering a sleep state.
+		This attribute is read-only.  If the device is not enabled to
+		wake up the system from sleep states, this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_active
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_active attribute contains either 1,
+		or 0, depending on whether or not a wakeup event associated with
+		the device is being processed (1).  This attribute is read-only.
+		If the device is not enabled to wake up the system from sleep
+		states, this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_total_time_ms
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_total_time_ms attribute contains
+		the total time of processing wakeup events associated with the
+		device, in milliseconds.  This attribute is read-only.  If the
+		device is not enabled to wake up the system from sleep states,
+		this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_max_time_ms
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_max_time_ms attribute contains
+		the maximum time of processing a single wakeup event associated
+		with the device, in milliseconds.  This attribute is read-only.
+		If the device is not enabled to wake up the system from sleep
+		states, this attribute is empty.
+
+What:		/sys/devices/.../power/wakeup_last_time_ms
+Date:		September 2010
+Contact:	Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+		The /sys/devices/.../wakeup_last_time_ms attribute contains
+		the value of the monotonic clock corresponding to the time of
+		signaling the last wakeup event associated with the device, in
+		milliseconds.  This attribute is read-only.  If the device is
+		not enabled to wake up the system from sleep states, this
+		attribute is empty.
+
+What:		/sys/devices/.../power/autosuspend_delay_ms
+Date:		September 2010
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		The /sys/devices/.../power/autosuspend_delay_ms attribute
+		contains the autosuspend delay value (in milliseconds).  Some
+		drivers do not want their device to suspend as soon as it
+		becomes idle at run time; they want the device to remain
+		inactive for a certain minimum period of time first.  That
+		period is called the autosuspend delay.  Negative values will
+		prevent the device from being suspended at run time (similar
+		to writing "on" to the power/control attribute).  Values >=
+		1000 will cause the autosuspend timer expiration to be rounded
+		up to the nearest second.
+
+		Not all drivers support this attribute.  If it isn't supported,
+		attempts to read or write it will yield I/O errors.
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-devices-system-ibm-rtl	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,22 @@
+What:           state
+Date:           Sep 2010
+KernelVersion:  2.6.37
+Contact:        Vernon Mauery <vernux@us.ibm.com>
+Description:    The state file allows a means by which to change in and
+                out of Premium Real-Time Mode (PRTM), as well as the
+                ability to query the current state.
+                    0 => PRTM off
+                    1 => PRTM enabled
+Users:          The ibm-prtm userspace daemon uses this interface.
+
+
+What:           version
+Date:           Sep 2010
+KernelVersion:  2.6.37
+Contact:        Vernon Mauery <vernux@us.ibm.com>
+Description:    The version file provides a means by which to query
+                the RTL table version that lives in the Extended
+                BIOS Data Area (EBDA).
+Users:          The ibm-prtm userspace daemon uses this interface.
+
+
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-driver-hid-roccat-pyra	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,98 @@
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_cpi
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	It is possible to switch the cpi setting of the mouse with the
+		press of a button.
+		When read, this file returns the raw number of the actual cpi
+		setting reported by the mouse. This number has to be further
+		processed to receive the real dpi value.
+
+		VALUE DPI
+		1     400
+		2     800
+		4     1600
+
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/actual_profile
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	When read, this file returns the number of the actual profile in
+		range 0-4.
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/firmware_version
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	When read, this file returns the raw integer version number of the
+		firmware reported by the mouse. Using the integer value eases
+		further usage in other programs. To receive the real version
+		number the decimal point has to be shifted 2 positions to the
+		left. E.g. a returned value of 138 means 1.38
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_settings
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	The mouse can store 5 profiles which can be switched by the
+		press of a button. A profile is split in settings and buttons.
+		profile_settings holds informations like resolution, sensitivity
+		and light effects.
+		When written, this file lets one write the respective profile
+		settings back to the mouse. The data has to be 13 bytes long.
+		The mouse will reject invalid data.
+		Which profile to write is determined by the profile number
+		contained in the data.
+		This file is writeonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_settings
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	The mouse can store 5 profiles which can be switched by the
+		press of a button. A profile is split in settings and buttons.
+		profile_settings holds informations like resolution, sensitivity
+		and light effects.
+		When read, these files return the respective profile settings.
+		The returned data is 13 bytes in size.
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile_buttons
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	The mouse can store 5 profiles which can be switched by the
+		press of a button. A profile is split in settings and buttons.
+		profile_buttons holds informations about button layout.
+		When written, this file lets one write the respective profile
+		buttons back to the mouse. The data has to be 19 bytes long.
+		The mouse will reject invalid data.
+		Which profile to write is determined by the profile number
+		contained in the data.
+		This file is writeonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]_buttons
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	The mouse can store 5 profiles which can be switched by the
+		press of a button. A profile is split in settings and buttons.
+		profile_buttons holds informations about button layout.
+		When read, these files return the respective profile buttons.
+		The returned data is 19 bytes in size.
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/startup_profile
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	The integer value of this attribute ranges from 0-4.
+                When read, this attribute returns the number of the profile
+                that's active when the mouse is powered on.
+		This file is readonly.
+
+What:		/sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/settings
+Date:		August 2010
+Contact:	Stefan Achatz <erazor_de@users.sourceforge.net>
+Description:	When read, this file returns the settings stored in the mouse.
+		The size of the data is 3 bytes and holds information on the
+		startup_profile.
+		When written, this file lets write settings back to the mouse.
+		The data has to be 3 bytes long. The mouse will reject invalid
+		data.
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-module linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-module
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-module	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-module	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,12 @@
+What:		/sys/module/pch_phub/drivers/.../pch_mac
+Date:		August 2010
+KernelVersion:	2.6.35
+Contact:	masa-korg@dsn.okisemi.com
+Description:	Write/read GbE MAC address.
+
+What:		/sys/module/pch_phub/drivers/.../pch_firmware
+Date:		August 2010
+KernelVersion:	2.6.35
+Contact:	masa-korg@dsn.okisemi.com
+Description:	Write/read Option ROM data.
+
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-platform-asus-laptop linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-platform-asus-laptop
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-platform-asus-laptop	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-platform-asus-laptop	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,20 @@
 KernelVersion:	2.6.20
 Contact:	"Corentin Chary" <corentincj@iksaif.net>
 Description:
-		Control the bluetooth device. 1 means on, 0 means off.
+		Control the wlan device. 1 means on, 0 means off.
 		This may control the led, the device or both.
 Users:		Lapsus
+
+What:		/sys/devices/platform/asus_laptop/wimax
+Date:		October 2010
+KernelVersion:	2.6.37
+Contact:	"Corentin Chary" <corentincj@iksaif.net>
+Description:
+		Control the wimax device. 1 means on, 0 means off.
+
+What:		/sys/devices/platform/asus_laptop/wwan
+Date:		October 2010
+KernelVersion:	2.6.37
+Contact:	"Corentin Chary" <corentincj@iksaif.net>
+Description:
+		Control the wwan (3G) device. 1 means on, 0 means off.
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-platform-eeepc-wmi linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-platform-eeepc-wmi
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-platform-eeepc-wmi	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-platform-eeepc-wmi	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,10 @@
+What:		/sys/devices/platform/eeepc-wmi/cpufv
+Date:		Oct 2010
+KernelVersion:	2.6.37
+Contact:	"Corentin Chary" <corentincj@iksaif.net>
+Description:
+		Change CPU clock configuration (write-only).
+		There are three available clock configuration:
+		    * 0 -> Super Performance Mode
+		    * 1 -> High Performance Mode
+		    * 2 -> Power Saving Mode
diff -druN linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-power linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-power
--- linux-libre-2.6.36-gnu/Documentation/ABI/testing/sysfs-power	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ABI/testing/sysfs-power	2011-01-04 19:50:19.000000000 -0500
@@ -99,9 +99,38 @@
 
 		dmesg -s 1000000 | grep 'hash matches'
 
+		If you do not get any matches (or they appear to be false
+		positives), it is possible that the last PM event point
+		referred to a device created by a loadable kernel module.  In
+		this case cat /sys/power/pm_trace_dev_match (see below) after
+		your system is started up and the kernel modules are loaded.
+
 		CAUTION: Using it will cause your machine's real-time (CMOS)
 		clock to be set to a random invalid time after a resume.
 
+What;		/sys/power/pm_trace_dev_match
+Date:		October 2010
+Contact:	James Hogan <james@albanarts.com>
+Description:
+		The /sys/power/pm_trace_dev_match file contains the name of the
+		device associated with the last PM event point saved in the RTC
+		across reboots when pm_trace has been used.  More precisely it
+		contains the list of current devices (including those
+		registered by loadable kernel modules since boot) which match
+		the device hash in the RTC at boot, with a newline after each
+		one.
+
+		The advantage of this file over the hash matches printed to the
+		kernel log (see /sys/power/pm_trace), is that it includes
+		devices created after boot by loadable kernel modules.
+
+		Due to the small hash size necessary to fit in the RTC, it is
+		possible that more than one device matches the hash, in which
+		case further investigation is required to determine which
+		device is causing the problem.  Note that genuine RTC clock
+		values (such as when pm_trace has not been used), can still
+		match a device and output it's name here.
+
 What:		/sys/power/pm_async
 Date:		January 2009
 Contact:	Rafael J. Wysocki <rjw@sisk.pl>
diff -druN linux-libre-2.6.36-gnu/Documentation/accounting/getdelays.c linux-libre-2.6.37-gnu/Documentation/accounting/getdelays.c
--- linux-libre-2.6.36-gnu/Documentation/accounting/getdelays.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/accounting/getdelays.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 #include <signal.h>
 
 #include <linux/genetlink.h>
@@ -266,11 +267,13 @@
 	int containerset = 0;
 	char containerpath[1024];
 	int cfd = 0;
+	int forking = 0;
+	sigset_t sigset;
 
 	struct msgtemplate msg;
 
-	while (1) {
-		c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:");
+	while (!forking) {
+		c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
 		if (c < 0)
 			break;
 
@@ -319,6 +322,28 @@
 				err(1, "Invalid pid\n");
 			cmd_type = TASKSTATS_CMD_ATTR_PID;
 			break;
+		case 'c':
+
+			/* Block SIGCHLD for sigwait() later */
+			if (sigemptyset(&sigset) == -1)
+				err(1, "Failed to empty sigset");
+			if (sigaddset(&sigset, SIGCHLD))
+				err(1, "Failed to set sigchld in sigset");
+			sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+			/* fork/exec a child */
+			tid = fork();
+			if (tid < 0)
+				err(1, "Fork failed\n");
+			if (tid == 0)
+				if (execvp(argv[optind - 1],
+				    &argv[optind - 1]) < 0)
+					exit(-1);
+
+			/* Set the command type and avoid further processing */
+			cmd_type = TASKSTATS_CMD_ATTR_PID;
+			forking = 1;
+			break;
 		case 'v':
 			printf("debug on\n");
 			dbg = 1;
@@ -370,6 +395,15 @@
 		goto err;
 	}
 
+	/*
+	 * If we forked a child, wait for it to exit. Cannot use waitpid()
+	 * as all the delicious data would be reaped as part of the wait
+	 */
+	if (tid && forking) {
+		int sig_received;
+		sigwait(&sigset, &sig_received);
+	}
+
 	if (tid) {
 		rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
 			      cmd_type, &tid, sizeof(__u32));
@@ -482,6 +516,7 @@
 			default:
 				fprintf(stderr, "Unknown nla_type %d\n",
 					na->nla_type);
+			case TASKSTATS_TYPE_NULL:
 				break;
 			}
 			na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
diff -druN linux-libre-2.6.36-gnu/Documentation/arm/00-INDEX linux-libre-2.6.37-gnu/Documentation/arm/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/arm/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/arm/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -6,6 +6,8 @@
 	- ARM Interrupt subsystem documentation
 IXP2000
 	- Release Notes for Linux on Intel's IXP2000 Network Processor
+msm
+	- MSM specific documentation
 Netwinder
 	- Netwinder specific documentation
 Porting
diff -druN linux-libre-2.6.36-gnu/Documentation/arm/msm/gpiomux.txt linux-libre-2.6.37-gnu/Documentation/arm/msm/gpiomux.txt
--- linux-libre-2.6.36-gnu/Documentation/arm/msm/gpiomux.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/arm/msm/gpiomux.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,176 @@
+This document provides an overview of the msm_gpiomux interface, which
+is used to provide gpio pin multiplexing and configuration on mach-msm
+targets.
+
+History
+=======
+
+The first-generation API for gpio configuration & multiplexing on msm
+is the function gpio_tlmm_config().  This function has a few notable
+shortcomings, which led to its deprecation and replacement by gpiomux:
+
+The 'disable' parameter:  Setting the second parameter to
+gpio_tlmm_config to GPIO_CFG_DISABLE tells the peripheral
+processor in charge of the subsystem to perform a look-up into a
+low-power table and apply the low-power/sleep setting for the pin.
+As the msm family evolved this became problematic. Not all pins
+have sleep settings, not all peripheral processors will accept requests
+to apply said sleep settings, and not all msm targets have their gpio
+subsystems managed by a peripheral processor. In order to get consistent
+behavior on all targets, drivers are forced to ignore this parameter,
+rendering it useless.
+
+The 'direction' flag: for all mux-settings other than raw-gpio (0),
+the output-enable bit of a gpio is hard-wired to a known
+input (usually VDD or ground).  For those settings, the direction flag
+is meaningless at best, and deceptive at worst.  In addition, using the
+direction flag to change output-enable (OE) directly can cause trouble in
+gpiolib, which has no visibility into gpio direction changes made
+in this way.  Direction control in gpio mode should be made through gpiolib.
+
+Key Features of gpiomux
+=======================
+
+- A consistent interface across all generations of msm.  Drivers can expect
+the same results on every target.
+- gpiomux plays nicely with gpiolib.  Functions that should belong to gpiolib
+are left to gpiolib and not duplicated here.  gpiomux is written with the
+intent that gpio_chips will call gpiomux reference-counting methods
+from their request() and free() hooks, providing full integration.
+- Tabular configuration.  Instead of having to call gpio_tlmm_config
+hundreds of times, gpio configuration is placed in a single table.
+- Per-gpio sleep.  Each gpio is individually reference counted, allowing only
+those lines which are in use to be put in high-power states.
+- 0 means 'do nothing': all flags are designed so that the default memset-zero
+equates to a sensible default of 'no configuration', preventing users
+from having to provide hundreds of 'no-op' configs for unused or
+unwanted lines.
+
+Usage
+=====
+
+To use gpiomux, provide configuration information for relevant gpio lines
+in the msm_gpiomux_configs table.  Since a 0 equates to "unconfigured",
+only those lines to be managed by gpiomux need to be specified.  Here
+is a completely fictional example:
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+	[12] = {
+		.active = GPIOMUX_VALID | GPIOMUX_DRV_8MA | GPIOMUX_FUNC_1,
+		.suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+	},
+	[34] = {
+		.suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+	},
+};
+
+To indicate that a gpio is in use, call msm_gpiomux_get() to increase
+its reference count.  To decrease the reference count, call msm_gpiomux_put().
+
+The effect of this configuration is as follows:
+
+When the system boots, gpios 12 and 34 will be initialized with their
+'suspended' configurations.  All other gpios, which were left unconfigured,
+will not be touched.
+
+When msm_gpiomux_get() is called on gpio 12 to raise its reference count
+above 0, its active configuration will be applied.  Since no other gpio
+line has a valid active configuration, msm_gpiomux_get() will have no
+effect on any other line.
+
+When msm_gpiomux_put() is called on gpio 12 or 34 to drop their reference
+count to 0, their suspended configurations will be applied.
+Since no other gpio line has a valid suspended configuration, no other
+gpio line will be effected by msm_gpiomux_put().  Since gpio 34 has no valid
+active configuration, this is effectively a no-op for gpio 34 as well,
+with one small caveat, see the section "About Output-Enable Settings".
+
+All of the GPIOMUX_VALID flags may seem like unnecessary overhead, but
+they address some important issues.  As unused entries (all those
+except 12 and 34) are zero-filled, gpiomux needs a way to distinguish
+the used fields from the unused.  In addition, the all-zero pattern
+is a valid configuration!  Therefore, gpiomux defines an additional bit
+which is used to indicate when a field is used.  This has the pleasant
+side-effect of allowing calls to msm_gpiomux_write to use '0' to indicate
+that a value should not be changed:
+
+  msm_gpiomux_write(0, GPIOMUX_VALID, 0);
+
+replaces the active configuration of gpio 0 with an all-zero configuration,
+but leaves the suspended configuration as it was.
+
+Static Configurations
+=====================
+
+To install a static configuration, which is applied at boot and does
+not change after that, install a configuration with a suspended component
+but no active component, as in the previous example:
+
+	[34] = {
+		.suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+	},
+
+The suspended setting is applied during boot, and the lack of any valid
+active setting prevents any other setting from being applied at runtime.
+If other subsystems attempting to access the line is a concern, one could
+*really* anchor the configuration down by calling msm_gpiomux_get on the
+line at initialization to move the line into active mode.  With the line
+held, it will never be re-suspended, and with no valid active configuration,
+no new configurations will be applied.
+
+But then, if having other subsystems grabbing for the line is truly a concern,
+it should be reserved with gpio_request instead, which carries an implicit
+msm_gpiomux_get.
+
+gpiomux and gpiolib
+===================
+
+It is expected that msm gpio_chips will call msm_gpiomux_get() and
+msm_gpiomux_put() from their request and free hooks, like this fictional
+example:
+
+static int request(struct gpio_chip *chip, unsigned offset)
+{
+        return msm_gpiomux_get(chip->base + offset);
+}
+
+static void free(struct gpio_chip *chip, unsigned offset)
+{
+        msm_gpiomux_put(chip->base + offset);
+}
+
+	...somewhere in a gpio_chip declaration...
+	.request = request,
+	.free    = free,
+
+This provides important functionality:
+- It guarantees that a gpio line will have its 'active' config applied
+  when the line is requested, and will not be suspended while the line
+  remains requested; and
+- It guarantees that gpio-direction settings from gpiolib behave sensibly.
+  See "About Output-Enable Settings."
+
+This mechanism allows for "auto-request" of gpiomux lines via gpiolib
+when it is suitable.  Drivers wishing more exact control are, of course,
+free to also use msm_gpiomux_set and msm_gpiomux_get.
+
+About Output-Enable Settings
+============================
+
+Some msm targets do not have the ability to query the current gpio
+configuration setting.  This means that changes made to the output-enable
+(OE) bit by gpiolib cannot be consistently detected and preserved by gpiomux.
+Therefore, when gpiomux applies a configuration setting, any direction
+settings which may have been applied by gpiolib are lost and the default
+input settings are re-applied.
+
+For this reason, drivers should not assume that gpio direction settings
+continue to hold if they free and then re-request a gpio.  This seems like
+common sense - after all, anybody could have obtained the line in the
+meantime - but it needs saying.
+
+This also means that calls to msm_gpiomux_write will reset the OE bit,
+which means that if the gpio line is held by a client of gpiolib and
+msm_gpiomux_write is called, the direction setting has been lost and
+gpiolib's internal state has been broken.
+Release gpio lines before reconfiguring them.
diff -druN linux-libre-2.6.36-gnu/Documentation/arm/OMAP/DSS linux-libre-2.6.37-gnu/Documentation/arm/OMAP/DSS
--- linux-libre-2.6.36-gnu/Documentation/arm/OMAP/DSS	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/arm/OMAP/DSS	2011-01-04 19:50:19.000000000 -0500
@@ -255,9 +255,10 @@
 Kernel boot arguments
 ---------------------
 
-vram=<size>
-	- Amount of total VRAM to preallocate. For example, "10M". omapfb
-	  allocates memory for framebuffers from VRAM.
+vram=<size>[,<physaddr>]
+	- Amount of total VRAM to preallocate and optionally a physical start
+	  memory address. For example, "10M". omapfb allocates memory for
+	  framebuffers from VRAM.
 
 omapfb.mode=<display>:<mode>[,...]
 	- Default video mode for specified displays. For example,
diff -druN linux-libre-2.6.36-gnu/Documentation/arm/SA1100/FreeBird linux-libre-2.6.37-gnu/Documentation/arm/SA1100/FreeBird
--- linux-libre-2.6.36-gnu/Documentation/arm/SA1100/FreeBird	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/arm/SA1100/FreeBird	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,6 @@
-Freebird-1.1 is produced by Legned(C) ,Inc.
+Freebird-1.1 is produced by Legend(C), Inc.
 http://web.archive.org/web/*/http://www.legend.com.cn
-and software/linux mainatined by Coventive(C),Inc.
+and software/linux maintained by Coventive(C), Inc.
 (http://www.coventive.com)
 
 Based on the Nicolas's strongarm kernel tree.
diff -druN linux-libre-2.6.36-gnu/Documentation/block/00-INDEX linux-libre-2.6.37-gnu/Documentation/block/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/block/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/block/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,5 @@
 00-INDEX
 	- This file
-barrier.txt
-	- I/O Barriers
 biodoc.txt
 	- Notes on the Generic Block Layer Rewrite in Linux 2.5
 capability.txt
@@ -16,3 +14,5 @@
 	- Block layer statistics in /sys/block/<dev>/stat
 switching-sched.txt
 	- Switching I/O schedulers at runtime
+writeback_cache_control.txt
+	- Control of volatile write back caches
diff -druN linux-libre-2.6.36-gnu/Documentation/block/barrier.txt linux-libre-2.6.37-gnu/Documentation/block/barrier.txt
--- linux-libre-2.6.36-gnu/Documentation/block/barrier.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/block/barrier.txt	1969-12-31 19:00:00.000000000 -0500
@@ -1,261 +0,0 @@
-I/O Barriers
-============
-Tejun Heo <htejun@gmail.com>, July 22 2005
-
-I/O barrier requests are used to guarantee ordering around the barrier
-requests.  Unless you're crazy enough to use disk drives for
-implementing synchronization constructs (wow, sounds interesting...),
-the ordering is meaningful only for write requests for things like
-journal checkpoints.  All requests queued before a barrier request
-must be finished (made it to the physical medium) before the barrier
-request is started, and all requests queued after the barrier request
-must be started only after the barrier request is finished (again,
-made it to the physical medium).
-
-In other words, I/O barrier requests have the following two properties.
-
-1. Request ordering
-
-Requests cannot pass the barrier request.  Preceding requests are
-processed before the barrier and following requests after.
-
-Depending on what features a drive supports, this can be done in one
-of the following three ways.
-
-i. For devices which have queue depth greater than 1 (TCQ devices) and
-support ordered tags, block layer can just issue the barrier as an
-ordered request and the lower level driver, controller and drive
-itself are responsible for making sure that the ordering constraint is
-met.  Most modern SCSI controllers/drives should support this.
-
-NOTE: SCSI ordered tag isn't currently used due to limitation in the
-      SCSI midlayer, see the following random notes section.
-
-ii. For devices which have queue depth greater than 1 but don't
-support ordered tags, block layer ensures that the requests preceding
-a barrier request finishes before issuing the barrier request.  Also,
-it defers requests following the barrier until the barrier request is
-finished.  Older SCSI controllers/drives and SATA drives fall in this
-category.
-
-iii. Devices which have queue depth of 1.  This is a degenerate case
-of ii.  Just keeping issue order suffices.  Ancient SCSI
-controllers/drives and IDE drives are in this category.
-
-2. Forced flushing to physical medium
-
-Again, if you're not gonna do synchronization with disk drives (dang,
-it sounds even more appealing now!), the reason you use I/O barriers
-is mainly to protect filesystem integrity when power failure or some
-other events abruptly stop the drive from operating and possibly make
-the drive lose data in its cache.  So, I/O barriers need to guarantee
-that requests actually get written to non-volatile medium in order.
-
-There are four cases,
-
-i. No write-back cache.  Keeping requests ordered is enough.
-
-ii. Write-back cache but no flush operation.  There's no way to
-guarantee physical-medium commit order.  This kind of devices can't to
-I/O barriers.
-
-iii. Write-back cache and flush operation but no FUA (forced unit
-access).  We need two cache flushes - before and after the barrier
-request.
-
-iv. Write-back cache, flush operation and FUA.  We still need one
-flush to make sure requests preceding a barrier are written to medium,
-but post-barrier flush can be avoided by using FUA write on the
-barrier itself.
-
-
-How to support barrier requests in drivers
-------------------------------------------
-
-All barrier handling is done inside block layer proper.  All low level
-drivers have to are implementing its prepare_flush_fn and using one
-the following two functions to indicate what barrier type it supports
-and how to prepare flush requests.  Note that the term 'ordered' is
-used to indicate the whole sequence of performing barrier requests
-including draining and flushing.
-
-typedef void (prepare_flush_fn)(struct request_queue *q, struct request *rq);
-
-int blk_queue_ordered(struct request_queue *q, unsigned ordered,
-		      prepare_flush_fn *prepare_flush_fn);
-
-@q			: the queue in question
-@ordered		: the ordered mode the driver/device supports
-@prepare_flush_fn	: this function should prepare @rq such that it
-			  flushes cache to physical medium when executed
-
-For example, SCSI disk driver's prepare_flush_fn looks like the
-following.
-
-static void sd_prepare_flush(struct request_queue *q, struct request *rq)
-{
-	memset(rq->cmd, 0, sizeof(rq->cmd));
-	rq->cmd_type = REQ_TYPE_BLOCK_PC;
-	rq->timeout = SD_TIMEOUT;
-	rq->cmd[0] = SYNCHRONIZE_CACHE;
-	rq->cmd_len = 10;
-}
-
-The following seven ordered modes are supported.  The following table
-shows which mode should be used depending on what features a
-device/driver supports.  In the leftmost column of table,
-QUEUE_ORDERED_ prefix is omitted from the mode names to save space.
-
-The table is followed by description of each mode.  Note that in the
-descriptions of QUEUE_ORDERED_DRAIN*, '=>' is used whereas '->' is
-used for QUEUE_ORDERED_TAG* descriptions.  '=>' indicates that the
-preceding step must be complete before proceeding to the next step.
-'->' indicates that the next step can start as soon as the previous
-step is issued.
-
-	    write-back cache	ordered tag	flush		FUA
------------------------------------------------------------------------
-NONE		yes/no		N/A		no		N/A
-DRAIN		no		no		N/A		N/A
-DRAIN_FLUSH	yes		no		yes		no
-DRAIN_FUA	yes		no		yes		yes
-TAG		no		yes		N/A		N/A
-TAG_FLUSH	yes		yes		yes		no
-TAG_FUA		yes		yes		yes		yes
-
-
-QUEUE_ORDERED_NONE
-	I/O barriers are not needed and/or supported.
-
-	Sequence: N/A
-
-QUEUE_ORDERED_DRAIN
-	Requests are ordered by draining the request queue and cache
-	flushing isn't needed.
-
-	Sequence: drain => barrier
-
-QUEUE_ORDERED_DRAIN_FLUSH
-	Requests are ordered by draining the request queue and both
-	pre-barrier and post-barrier cache flushings are needed.
-
-	Sequence: drain => preflush => barrier => postflush
-
-QUEUE_ORDERED_DRAIN_FUA
-	Requests are ordered by draining the request queue and
-	pre-barrier cache flushing is needed.  By using FUA on barrier
-	request, post-barrier flushing can be skipped.
-
-	Sequence: drain => preflush => barrier
-
-QUEUE_ORDERED_TAG
-	Requests are ordered by ordered tag and cache flushing isn't
-	needed.
-
-	Sequence: barrier
-
-QUEUE_ORDERED_TAG_FLUSH
-	Requests are ordered by ordered tag and both pre-barrier and
-	post-barrier cache flushings are needed.
-
-	Sequence: preflush -> barrier -> postflush
-
-QUEUE_ORDERED_TAG_FUA
-	Requests are ordered by ordered tag and pre-barrier cache
-	flushing is needed.  By using FUA on barrier request,
-	post-barrier flushing can be skipped.
-
-	Sequence: preflush -> barrier
-
-
-Random notes/caveats
---------------------
-
-* SCSI layer currently can't use TAG ordering even if the drive,
-controller and driver support it.  The problem is that SCSI midlayer
-request dispatch function is not atomic.  It releases queue lock and
-switch to SCSI host lock during issue and it's possible and likely to
-happen in time that requests change their relative positions.  Once
-this problem is solved, TAG ordering can be enabled.
-
-* Currently, no matter which ordered mode is used, there can be only
-one barrier request in progress.  All I/O barriers are held off by
-block layer until the previous I/O barrier is complete.  This doesn't
-make any difference for DRAIN ordered devices, but, for TAG ordered
-devices with very high command latency, passing multiple I/O barriers
-to low level *might* be helpful if they are very frequent.  Well, this
-certainly is a non-issue.  I'm writing this just to make clear that no
-two I/O barrier is ever passed to low-level driver.
-
-* Completion order.  Requests in ordered sequence are issued in order
-but not required to finish in order.  Barrier implementation can
-handle out-of-order completion of ordered sequence.  IOW, the requests
-MUST be processed in order but the hardware/software completion paths
-are allowed to reorder completion notifications - eg. current SCSI
-midlayer doesn't preserve completion order during error handling.
-
-* Requeueing order.  Low-level drivers are free to requeue any request
-after they removed it from the request queue with
-blkdev_dequeue_request().  As barrier sequence should be kept in order
-when requeued, generic elevator code takes care of putting requests in
-order around barrier.  See blk_ordered_req_seq() and
-ELEVATOR_INSERT_REQUEUE handling in __elv_add_request() for details.
-
-Note that block drivers must not requeue preceding requests while
-completing latter requests in an ordered sequence.  Currently, no
-error checking is done against this.
-
-* Error handling.  Currently, block layer will report error to upper
-layer if any of requests in an ordered sequence fails.  Unfortunately,
-this doesn't seem to be enough.  Look at the following request flow.
-QUEUE_ORDERED_TAG_FLUSH is in use.
-
- [0] [1] [2] [3] [pre] [barrier] [post] < [4] [5] [6] ... >
-					  still in elevator
-
-Let's say request [2], [3] are write requests to update file system
-metadata (journal or whatever) and [barrier] is used to mark that
-those updates are valid.  Consider the following sequence.
-
- i.	Requests [0] ~ [post] leaves the request queue and enters
-	low-level driver.
- ii.	After a while, unfortunately, something goes wrong and the
-	drive fails [2].  Note that any of [0], [1] and [3] could have
-	completed by this time, but [pre] couldn't have been finished
-	as the drive must process it in order and it failed before
-	processing that command.
- iii.	Error handling kicks in and determines that the error is
-	unrecoverable and fails [2], and resumes operation.
- iv.	[pre] [barrier] [post] gets processed.
- v.	*BOOM* power fails
-
-The problem here is that the barrier request is *supposed* to indicate
-that filesystem update requests [2] and [3] made it safely to the
-physical medium and, if the machine crashes after the barrier is
-written, filesystem recovery code can depend on that.  Sadly, that
-isn't true in this case anymore.  IOW, the success of a I/O barrier
-should also be dependent on success of some of the preceding requests,
-where only upper layer (filesystem) knows what 'some' is.
-
-This can be solved by implementing a way to tell the block layer which
-requests affect the success of the following barrier request and
-making lower lever drivers to resume operation on error only after
-block layer tells it to do so.
-
-As the probability of this happening is very low and the drive should
-be faulty, implementing the fix is probably an overkill.  But, still,
-it's there.
-
-* In previous drafts of barrier implementation, there was fallback
-mechanism such that, if FUA or ordered TAG fails, less fancy ordered
-mode can be selected and the failed barrier request is retried
-automatically.  The rationale for this feature was that as FUA is
-pretty new in ATA world and ordered tag was never used widely, there
-could be devices which report to support those features but choke when
-actually given such requests.
-
- This was removed for two reasons 1. it's an overkill 2. it's
-impossible to implement properly when TAG ordering is used as low
-level drivers resume after an error automatically.  If it's ever
-needed adding it back and modifying low level drivers accordingly
-shouldn't be difficult.
diff -druN linux-libre-2.6.36-gnu/Documentation/block/switching-sched.txt linux-libre-2.6.37-gnu/Documentation/block/switching-sched.txt
--- linux-libre-2.6.36-gnu/Documentation/block/switching-sched.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/block/switching-sched.txt	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 As of the Linux 2.6.10 kernel, it is now possible to change the
 IO scheduler for a given block device on the fly (thus making it possible,
 for instance, to set the CFQ scheduler for the system default, but
-set a specific device to use the anticipatory or noop schedulers - which
+set a specific device to use the deadline or noop schedulers - which
 can improve that device's throughput).
 
 To set a specific scheduler, simply do this:
@@ -31,7 +31,7 @@
 will be displayed, with the currently selected scheduler in brackets:
 
 # cat /sys/block/hda/queue/scheduler
-noop anticipatory deadline [cfq]
-# echo anticipatory > /sys/block/hda/queue/scheduler
+noop deadline [cfq]
+# echo deadline > /sys/block/hda/queue/scheduler
 # cat /sys/block/hda/queue/scheduler
-noop [anticipatory] deadline cfq
+noop [deadline] cfq
diff -druN linux-libre-2.6.36-gnu/Documentation/block/writeback_cache_control.txt linux-libre-2.6.37-gnu/Documentation/block/writeback_cache_control.txt
--- linux-libre-2.6.36-gnu/Documentation/block/writeback_cache_control.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/block/writeback_cache_control.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,86 @@
+
+Explicit volatile write back cache control
+=====================================
+
+Introduction
+------------
+
+Many storage devices, especially in the consumer market, come with volatile
+write back caches.  That means the devices signal I/O completion to the
+operating system before data actually has hit the non-volatile storage.  This
+behavior obviously speeds up various workloads, but it means the operating
+system needs to force data out to the non-volatile storage when it performs
+a data integrity operation like fsync, sync or an unmount.
+
+The Linux block layer provides two simple mechanisms that let filesystems
+control the caching behavior of the storage device.  These mechanisms are
+a forced cache flush, and the Force Unit Access (FUA) flag for requests.
+
+
+Explicit cache flushes
+----------------------
+
+The REQ_FLUSH flag can be OR ed into the r/w flags of a bio submitted from
+the filesystem and will make sure the volatile cache of the storage device
+has been flushed before the actual I/O operation is started.  This explicitly
+guarantees that previously completed write requests are on non-volatile
+storage before the flagged bio starts. In addition the REQ_FLUSH flag can be
+set on an otherwise empty bio structure, which causes only an explicit cache
+flush without any dependent I/O.  It is recommend to use
+the blkdev_issue_flush() helper for a pure cache flush.
+
+
+Forced Unit Access
+-----------------
+
+The REQ_FUA flag can be OR ed into the r/w flags of a bio submitted from the
+filesystem and will make sure that I/O completion for this request is only
+signaled after the data has been committed to non-volatile storage.
+
+
+Implementation details for filesystems
+--------------------------------------
+
+Filesystems can simply set the REQ_FLUSH and REQ_FUA bits and do not have to
+worry if the underlying devices need any explicit cache flushing and how
+the Forced Unit Access is implemented.  The REQ_FLUSH and REQ_FUA flags
+may both be set on a single bio.
+
+
+Implementation details for make_request_fn based block drivers
+--------------------------------------------------------------
+
+These drivers will always see the REQ_FLUSH and REQ_FUA bits as they sit
+directly below the submit_bio interface.  For remapping drivers the REQ_FUA
+bits need to be propagated to underlying devices, and a global flush needs
+to be implemented for bios with the REQ_FLUSH bit set.  For real device
+drivers that do not have a volatile cache the REQ_FLUSH and REQ_FUA bits
+on non-empty bios can simply be ignored, and REQ_FLUSH requests without
+data can be completed successfully without doing any work.  Drivers for
+devices with volatile caches need to implement the support for these
+flags themselves without any help from the block layer.
+
+
+Implementation details for request_fn based block drivers
+--------------------------------------------------------------
+
+For devices that do not support volatile write caches there is no driver
+support required, the block layer completes empty REQ_FLUSH requests before
+entering the driver and strips off the REQ_FLUSH and REQ_FUA bits from
+requests that have a payload.  For devices with volatile write caches the
+driver needs to tell the block layer that it supports flushing caches by
+doing:
+
+	blk_queue_flush(sdkp->disk->queue, REQ_FLUSH);
+
+and handle empty REQ_FLUSH requests in its prep_fn/request_fn.  Note that
+REQ_FLUSH requests with a payload are automatically turned into a sequence
+of an empty REQ_FLUSH request followed by the actual write by the block
+layer.  For devices that also support the FUA bit the block layer needs
+to be told to pass through the REQ_FUA bit using:
+
+	blk_queue_flush(sdkp->disk->queue, REQ_FLUSH | REQ_FUA);
+
+and the driver must handle write requests that have the REQ_FUA bit set
+in prep_fn/request_fn.  If the FUA bit is not natively supported the block
+layer turns it into an empty REQ_FLUSH request after the actual write.
diff -druN linux-libre-2.6.36-gnu/Documentation/cgroups/blkio-controller.txt linux-libre-2.6.37-gnu/Documentation/cgroups/blkio-controller.txt
--- linux-libre-2.6.36-gnu/Documentation/cgroups/blkio-controller.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/cgroups/blkio-controller.txt	2011-01-04 19:50:19.000000000 -0500
@@ -8,12 +8,17 @@
 Plan is to use the same cgroup based management interface for blkio controller
 and based on user options switch IO policies in the background.
 
-In the first phase, this patchset implements proportional weight time based
-division of disk policy. It is implemented in CFQ. Hence this policy takes
-effect only on leaf nodes when CFQ is being used.
+Currently two IO control policies are implemented. First one is proportional
+weight time based division of disk policy. It is implemented in CFQ. Hence
+this policy takes effect only on leaf nodes when CFQ is being used. The second
+one is throttling policy which can be used to specify upper IO rate limits
+on devices. This policy is implemented in generic block layer and can be
+used on leaf nodes as well as higher level logical devices like device mapper.
 
 HOWTO
 =====
+Proportional Weight division of bandwidth
+-----------------------------------------
 You can do a very simple testing of running two dd threads in two different
 cgroups. Here is what you can do.
 
@@ -55,6 +60,35 @@
   group dispatched to the disk. We provide fairness in terms of disk time, so
   ideally io.disk_time of cgroups should be in proportion to the weight.
 
+Throttling/Upper Limit policy
+-----------------------------
+- Enable Block IO controller
+	CONFIG_BLK_CGROUP=y
+
+- Enable throttling in block layer
+	CONFIG_BLK_DEV_THROTTLING=y
+
+- Mount blkio controller
+        mount -t cgroup -o blkio none /cgroup/blkio
+
+- Specify a bandwidth rate on particular device for root group. The format
+  for policy is "<major>:<minor>  <byes_per_second>".
+
+        echo "8:16  1048576" > /cgroup/blkio/blkio.read_bps_device
+
+  Above will put a limit of 1MB/second on reads happening for root group
+  on device having major/minor number 8:16.
+
+- Run dd to read a file and see if rate is throttled to 1MB/s or not.
+
+		# dd if=/mnt/common/zerofile of=/dev/null bs=4K count=1024
+		# iflag=direct
+        1024+0 records in
+        1024+0 records out
+        4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s
+
+ Limits for writes can be put using blkio.write_bps_device file.
+
 Various user visible config options
 ===================================
 CONFIG_BLK_CGROUP
@@ -68,8 +102,13 @@
 	- Enables group scheduling in CFQ. Currently only 1 level of group
 	  creation is allowed.
 
+CONFIG_BLK_DEV_THROTTLING
+	- Enable block device throttling support in block layer.
+
 Details of cgroup files
 =======================
+Proportional weight policy files
+--------------------------------
 - blkio.weight
 	- Specifies per cgroup weight. This is default weight of the group
 	  on all the devices until and unless overridden by per device rule.
@@ -210,6 +249,67 @@
 	  and minor number of the device and third field specifies the number
 	  of times a group was dequeued from a particular device.
 
+Throttling/Upper limit policy files
+-----------------------------------
+- blkio.throttle.read_bps_device
+	- Specifies upper limit on READ rate from the device. IO rate is
+	  specified in bytes per second. Rules are per deivce. Following is
+	  the format.
+
+  echo "<major>:<minor>  <rate_bytes_per_second>" > /cgrp/blkio.read_bps_device
+
+- blkio.throttle.write_bps_device
+	- Specifies upper limit on WRITE rate to the device. IO rate is
+	  specified in bytes per second. Rules are per deivce. Following is
+	  the format.
+
+  echo "<major>:<minor>  <rate_bytes_per_second>" > /cgrp/blkio.write_bps_device
+
+- blkio.throttle.read_iops_device
+	- Specifies upper limit on READ rate from the device. IO rate is
+	  specified in IO per second. Rules are per deivce. Following is
+	  the format.
+
+  echo "<major>:<minor>  <rate_io_per_second>" > /cgrp/blkio.read_iops_device
+
+- blkio.throttle.write_iops_device
+	- Specifies upper limit on WRITE rate to the device. IO rate is
+	  specified in io per second. Rules are per deivce. Following is
+	  the format.
+
+  echo "<major>:<minor>  <rate_io_per_second>" > /cgrp/blkio.write_iops_device
+
+Note: If both BW and IOPS rules are specified for a device, then IO is
+      subjectd to both the constraints.
+
+- blkio.throttle.io_serviced
+	- Number of IOs (bio) completed to/from the disk by the group (as
+	  seen by throttling policy). These are further divided by the type
+	  of operation - read or write, sync or async. First two fields specify
+	  the major and minor number of the device, third field specifies the
+	  operation type and the fourth field specifies the number of IOs.
+
+	  blkio.io_serviced does accounting as seen by CFQ and counts are in
+	  number of requests (struct request). On the other hand,
+	  blkio.throttle.io_serviced counts number of IO in terms of number
+	  of bios as seen by throttling policy.  These bios can later be
+	  merged by elevator and total number of requests completed can be
+	  lesser.
+
+- blkio.throttle.io_service_bytes
+	- Number of bytes transferred to/from the disk by the group. These
+	  are further divided by the type of operation - read or write, sync
+	  or async. First two fields specify the major and minor number of the
+	  device, third field specifies the operation type and the fourth field
+	  specifies the number of bytes.
+
+	  These numbers should roughly be same as blkio.io_service_bytes as
+	  updated by CFQ. The difference between two is that
+	  blkio.io_service_bytes will not be updated if CFQ is not operating
+	  on request queue.
+
+Common files among various policies
+-----------------------------------
 - blkio.reset_stats
 	- Writing an int to this file will result in resetting all the stats
 	  for that cgroup.
diff -druN linux-libre-2.6.36-gnu/Documentation/cgroups/cgroups.txt linux-libre-2.6.37-gnu/Documentation/cgroups/cgroups.txt
--- linux-libre-2.6.36-gnu/Documentation/cgroups/cgroups.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/cgroups/cgroups.txt	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,8 @@
   1.2 Why are cgroups needed ?
   1.3 How are cgroups implemented ?
   1.4 What does notify_on_release do ?
-  1.5 How do I use cgroups ?
+  1.5 What does clone_children do ?
+  1.6 How do I use cgroups ?
 2. Usage Examples and Syntax
   2.1 Basic Usage
   2.2 Attaching processes
@@ -293,7 +294,16 @@
 value of their parents notify_on_release setting. The default value of
 a cgroup hierarchy's release_agent path is empty.
 
-1.5 How do I use cgroups ?
+1.5 What does clone_children do ?
+---------------------------------
+
+If the clone_children flag is enabled (1) in a cgroup, then all
+cgroups created beneath will call the post_clone callbacks for each
+subsystem of the newly created cgroup. Usually when this callback is
+implemented for a subsystem, it copies the values of the parent
+subsystem, this is the case for the cpuset.
+
+1.6 How do I use cgroups ?
 --------------------------
 
 To start a new job that is to be contained within a cgroup, using
diff -druN linux-libre-2.6.36-gnu/Documentation/coccinelle.txt linux-libre-2.6.37-gnu/Documentation/coccinelle.txt
--- linux-libre-2.6.36-gnu/Documentation/coccinelle.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/coccinelle.txt	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,9 @@
 You can get the latest version released from the Coccinelle homepage at
 http://coccinelle.lip6.fr/
 
+Information and tips about Coccinelle are also provided on the wiki
+pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
+
 Once you have it, run the following command:
 
      	./configure
@@ -41,20 +44,22 @@
 Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
 front-end in the 'scripts' directory.
 
-Four modes are defined: report, patch, context, and org. The mode to
+Four modes are defined: patch, report, context, and org. The mode to
 use is specified by setting the MODE variable with 'MODE=<mode>'.
 
+'patch' proposes a fix, when possible.
+
 'report' generates a list in the following format:
   file:line:column-column: message
 
-'patch' proposes a fix, when possible.
-
 'context' highlights lines of interest and their context in a
 diff-like style.Lines of interest are indicated with '-'.
 
 'org' generates a report in the Org mode format of Emacs.
 
-Note that not all semantic patches implement all modes.
+Note that not all semantic patches implement all modes. For easy use
+of Coccinelle, the default mode is "chain" which tries the previous
+modes in the order above until one succeeds.
 
 To make a report for every semantic patch, run the following command:
 
@@ -68,9 +73,9 @@
 
 
 The coccicheck target applies every semantic patch available in the
-subdirectories of 'scripts/coccinelle' to the entire Linux kernel.
+sub-directories of 'scripts/coccinelle' to the entire Linux kernel.
 
-For each semantic patch, a changelog message is proposed.  It gives a
+For each semantic patch, a commit message is proposed.  It gives a
 description of the problem being checked by the semantic patch, and
 includes a reference to Coccinelle.
 
@@ -93,12 +98,35 @@
 	make coccicheck COCCI=<my_SP.cocci> MODE=report
 
 
+ Using Coccinelle on (modified) files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To apply Coccinelle on a file basis, instead of a directory basis, the
+following command may be used:
+
+    make C=1 CHECK="scripts/coccicheck"
+
+To check only newly edited code, use the value 2 for the C flag, i.e.
+
+    make C=2 CHECK="scripts/coccicheck"
+
+This runs every semantic patch in scripts/coccinelle by default. The
+COCCI variable may additionally be used to only apply a single
+semantic patch as shown in the previous section.
+
+The "chain" mode is the default. You can select another one with the
+MODE variable explained above.
+
+In this mode, there is no information about semantic patches
+displayed, and no commit message proposed.
+
+
  Proposing new semantic patches
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 New semantic patches can be proposed and submitted by kernel
 developers. For sake of clarity, they should be organized in the
-subdirectories of 'scripts/coccinelle/'.
+sub-directories of 'scripts/coccinelle/'.
 
 
  Detailed description of the 'report' mode
@@ -111,7 +139,7 @@
 
 Running
 
-	make coccicheck MODE=report COCCI=scripts/coccinelle/err_cast.cocci
+	make coccicheck MODE=report COCCI=scripts/coccinelle/api/err_cast.cocci
 
 will execute the following part of the SmPL script.
 
@@ -149,7 +177,7 @@
 Example:
 
 Running
-	make coccicheck MODE=patch COCCI=scripts/coccinelle/err_cast.cocci
+	make coccicheck MODE=patch COCCI=scripts/coccinelle/api/err_cast.cocci
 
 will execute the following part of the SmPL script.
 
@@ -193,7 +221,7 @@
 Example:
 
 Running
-	make coccicheck MODE=context COCCI=scripts/coccinelle/err_cast.cocci
+	make coccicheck MODE=context COCCI=scripts/coccinelle/api/err_cast.cocci
 
 will execute the following part of the SmPL script.
 
@@ -228,7 +256,7 @@
 Example:
 
 Running
-	make coccicheck MODE=org COCCI=scripts/coccinelle/err_cast.cocci
+	make coccicheck MODE=org COCCI=scripts/coccinelle/api/err_cast.cocci
 
 will execute the following part of the SmPL script.
 
diff -druN linux-libre-2.6.36-gnu/Documentation/cputopology.txt linux-libre-2.6.37-gnu/Documentation/cputopology.txt
--- linux-libre-2.6.36-gnu/Documentation/cputopology.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/cputopology.txt	2011-01-04 19:50:19.000000000 -0500
@@ -14,25 +14,39 @@
 	identifier (rather than the kernel's).  The actual value is
 	architecture and platform dependent.
 
-3) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
+3) /sys/devices/system/cpu/cpuX/topology/book_id:
+
+	the book ID of cpuX. Typically it is the hardware platform's
+	identifier (rather than the kernel's).	The actual value is
+	architecture and platform dependent.
+
+4) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
 
 	internel kernel map of cpuX's hardware threads within the same
 	core as cpuX
 
-4) /sys/devices/system/cpu/cpuX/topology/core_siblings:
+5) /sys/devices/system/cpu/cpuX/topology/core_siblings:
 
 	internal kernel map of cpuX's hardware threads within the same
 	physical_package_id.
 
+6) /sys/devices/system/cpu/cpuX/topology/book_siblings:
+
+	internal kernel map of cpuX's hardware threads within the same
+	book_id.
+
 To implement it in an architecture-neutral way, a new source file,
-drivers/base/topology.c, is to export the 4 attributes.
+drivers/base/topology.c, is to export the 4 or 6 attributes. The two book
+related sysfs files will only be created if CONFIG_SCHED_BOOK is selected.
 
 For an architecture to support this feature, it must define some of
 these macros in include/asm-XXX/topology.h:
 #define topology_physical_package_id(cpu)
 #define topology_core_id(cpu)
+#define topology_book_id(cpu)
 #define topology_thread_cpumask(cpu)
 #define topology_core_cpumask(cpu)
+#define topology_book_cpumask(cpu)
 
 The type of **_id is int.
 The type of siblings is (const) struct cpumask *.
@@ -45,6 +59,9 @@
 3) thread_siblings: just the given CPU
 4) core_siblings: just the given CPU
 
+For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
+default definitions for topology_book_id() and topology_book_cpumask().
+
 Additionally, CPU topology information is provided under
 /sys/devices/system/cpu and includes these files.  The internal
 source for the output is in brackets ("[]").
diff -druN linux-libre-2.6.36-gnu/Documentation/development-process/2.Process linux-libre-2.6.37-gnu/Documentation/development-process/2.Process
--- linux-libre-2.6.36-gnu/Documentation/development-process/2.Process	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/development-process/2.Process	2011-01-04 19:50:19.000000000 -0500
@@ -154,7 +154,7 @@
    inclusion, it should be accepted by a relevant subsystem maintainer -
    though this acceptance is not a guarantee that the patch will make it
    all the way to the mainline.  The patch will show up in the maintainer's
-   subsystem tree and into the staging trees (described below).  When the
+   subsystem tree and into the -next trees (described below).  When the
    process works, this step leads to more extensive review of the patch and
    the discovery of any problems resulting from the integration of this
    patch with work being done by others.
@@ -236,7 +236,7 @@
 normally the right way to go.
 
 
-2.4: STAGING TREES
+2.4: NEXT TREES
 
 The chain of subsystem trees guides the flow of patches into the kernel,
 but it also raises an interesting question: what if somebody wants to look
@@ -250,7 +250,7 @@
 the interesting subsystem trees, but that would be a big and error-prone
 job.
 
-The answer comes in the form of staging trees, where subsystem trees are
+The answer comes in the form of -next trees, where subsystem trees are
 collected for testing and review.  The older of these trees, maintained by
 Andrew Morton, is called "-mm" (for memory management, which is how it got
 started).  The -mm tree integrates patches from a long list of subsystem
@@ -275,7 +275,7 @@
 Use of the MMOTM tree is likely to be a frustrating experience, though;
 there is a definite chance that it will not even compile.
 
-The other staging tree, started more recently, is linux-next, maintained by
+The other -next tree, started more recently, is linux-next, maintained by
 Stephen Rothwell.  The linux-next tree is, by design, a snapshot of what
 the mainline is expected to look like after the next merge window closes.
 Linux-next trees are announced on the linux-kernel and linux-next mailing
@@ -303,12 +303,25 @@
 See http://lwn.net/Articles/289013/ for more information on this topic, and
 stay tuned; much is still in flux where linux-next is involved.
 
-Besides the mmotm and linux-next trees, the kernel source tree now contains
-the drivers/staging/ directory and many sub-directories for drivers or
-filesystems that are on their way to being added to the kernel tree
-proper, but they remain in drivers/staging/ while they still need more
-work.
+2.4.1: STAGING TREES
 
+The kernel source tree now contains the drivers/staging/ directory, where
+many sub-directories for drivers or filesystems that are on their way to
+being added to the kernel tree live.  They remain in drivers/staging while
+they still need more work; once complete, they can be moved into the
+kernel proper.  This is a way to keep track of drivers that aren't
+up to Linux kernel coding or quality standards, but people may want to use
+them and track development.
+
+Greg Kroah-Hartman currently (as of 2.6.36) maintains the staging tree.
+Drivers that still need work are sent to him, with each driver having
+its own subdirectory in drivers/staging/.  Along with the driver source
+files, a TODO file should be present in the directory as well.  The TODO
+file lists the pending work that the driver needs for acceptance into
+the kernel proper, as well as a list of people that should be Cc'd for any
+patches to the driver.  Staging drivers that don't currently build should
+have their config entries depend upon CONFIG_BROKEN.  Once they can
+be successfully built without outside patches, CONFIG_BROKEN can be removed.
 
 2.5: TOOLS
 
diff -druN linux-libre-2.6.36-gnu/Documentation/devices.txt linux-libre-2.6.37-gnu/Documentation/devices.txt
--- linux-libre-2.6.36-gnu/Documentation/devices.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/devices.txt	2011-01-04 19:50:19.000000000 -0500
@@ -239,6 +239,7 @@
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
 		  2 = /dev/ptmx		PTY master multiplex
+		  3 = /dev/ttyprintk	User messages via printk TTY device
 		 64 = /dev/cua0		Callout device for ttyS0
 		    ...
 		255 = /dev/cua191	Callout device for ttyS191
@@ -1495,9 +1496,6 @@
 		 64 = /dev/radio0	Radio device
 		    ...
 		127 = /dev/radio63	Radio device
-		192 = /dev/vtx0		Teletext device
-		    ...
-		223 = /dev/vtx31	Teletext device
 		224 = /dev/vbi0		Vertical blank interrupt
 		    ...
 		255 = /dev/vbi31	Vertical blank interrupt
@@ -2519,6 +2517,12 @@
 		  8 = /dev/mmcblk1      Second SD/MMC card
 		    ...
 
+		The start of next SD/MMC card can be configured with
+		CONFIG_MMC_BLOCK_MINORS, or overridden at boot/modprobe
+		time using the mmcblk.perdev_minors option. That would
+		bump the offset between each card to be the configured
+		value instead of the default 8.
+
 179 char	CCube DVXChip-based PCI products
 		  0 = /dev/dvxirq0	First DVX device
 		  1 = /dev/dvxirq1	Second DVX device
@@ -2553,7 +2557,10 @@
 		175 = /dev/usb/legousbtower15	16th USB Legotower device
 		176 = /dev/usb/usbtmc1	First USB TMC device
 		   ...
-		192 = /dev/usb/usbtmc16	16th USB TMC device
+		191 = /dev/usb/usbtmc16	16th USB TMC device
+		192 = /dev/usb/yurex1	First USB Yurex device
+		   ...
+		209 = /dev/usb/yurex16	16th USB Yurex device
 		240 = /dev/usb/dabusb0	First daubusb device
 		    ...
 		243 = /dev/usb/dabusb3	Fourth dabusb device
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/80211.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/80211.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/80211.tmpl	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/80211.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,495 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE set PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+<set>
+  <setinfo>
+    <title>The 802.11 subsystems &ndash; for kernel developers</title>
+    <subtitle>
+      Explaining wireless 802.11 networking in the Linux kernel
+    </subtitle>
+
+    <copyright>
+      <year>2007-2009</year>
+      <holder>Johannes Berg</holder>
+    </copyright>
+
+    <authorgroup>
+      <author>
+        <firstname>Johannes</firstname>
+        <surname>Berg</surname>
+        <affiliation>
+          <address><email>johannes@sipsolutions.net</email></address>
+        </affiliation>
+      </author>
+    </authorgroup>
+
+    <legalnotice>
+      <para>
+        This documentation is free software; you can redistribute
+        it and/or modify it under the terms of the GNU General Public
+        License version 2 as published by the Free Software Foundation.
+      </para>
+      <para>
+        This documentation is distributed in the hope that it will be
+        useful, but WITHOUT ANY WARRANTY; without even the implied
+        warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+        See the GNU General Public License for more details.
+      </para>
+      <para>
+        You should have received a copy of the GNU General Public
+        License along with this documentation; if not, write to the Free
+        Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+        MA 02111-1307 USA
+      </para>
+      <para>
+        For more details see the file COPYING in the source
+        distribution of Linux.
+      </para>
+    </legalnotice>
+
+    <abstract>
+      <para>
+        These books attempt to give a description of the
+        various subsystems that play a role in 802.11 wireless
+        networking in Linux. Since these books are for kernel
+        developers they attempts to document the structures
+        and functions used in the kernel as well as giving a
+        higher-level overview.
+      </para>
+      <para>
+	The reader is expected to be familiar with the 802.11
+	standard as published by the IEEE in 802.11-2007 (or
+	possibly later versions). References to this standard
+	will be given as "802.11-2007 8.1.5".
+      </para>
+    </abstract>
+  </setinfo>
+  <book id="cfg80211-developers-guide">
+    <bookinfo>
+      <title>The cfg80211 subsystem</title>
+
+      <abstract>
+!Pinclude/net/cfg80211.h Introduction
+      </abstract>
+    </bookinfo>
+      <chapter>
+      <title>Device registration</title>
+!Pinclude/net/cfg80211.h Device registration
+!Finclude/net/cfg80211.h ieee80211_band
+!Finclude/net/cfg80211.h ieee80211_channel_flags
+!Finclude/net/cfg80211.h ieee80211_channel
+!Finclude/net/cfg80211.h ieee80211_rate_flags
+!Finclude/net/cfg80211.h ieee80211_rate
+!Finclude/net/cfg80211.h ieee80211_sta_ht_cap
+!Finclude/net/cfg80211.h ieee80211_supported_band
+!Finclude/net/cfg80211.h cfg80211_signal_type
+!Finclude/net/cfg80211.h wiphy_params_flags
+!Finclude/net/cfg80211.h wiphy_flags
+!Finclude/net/cfg80211.h wiphy
+!Finclude/net/cfg80211.h wireless_dev
+!Finclude/net/cfg80211.h wiphy_new
+!Finclude/net/cfg80211.h wiphy_register
+!Finclude/net/cfg80211.h wiphy_unregister
+!Finclude/net/cfg80211.h wiphy_free
+
+!Finclude/net/cfg80211.h wiphy_name
+!Finclude/net/cfg80211.h wiphy_dev
+!Finclude/net/cfg80211.h wiphy_priv
+!Finclude/net/cfg80211.h priv_to_wiphy
+!Finclude/net/cfg80211.h set_wiphy_dev
+!Finclude/net/cfg80211.h wdev_priv
+      </chapter>
+      <chapter>
+      <title>Actions and configuration</title>
+!Pinclude/net/cfg80211.h Actions and configuration
+!Finclude/net/cfg80211.h cfg80211_ops
+!Finclude/net/cfg80211.h vif_params
+!Finclude/net/cfg80211.h key_params
+!Finclude/net/cfg80211.h survey_info_flags
+!Finclude/net/cfg80211.h survey_info
+!Finclude/net/cfg80211.h beacon_parameters
+!Finclude/net/cfg80211.h plink_actions
+!Finclude/net/cfg80211.h station_parameters
+!Finclude/net/cfg80211.h station_info_flags
+!Finclude/net/cfg80211.h rate_info_flags
+!Finclude/net/cfg80211.h rate_info
+!Finclude/net/cfg80211.h station_info
+!Finclude/net/cfg80211.h monitor_flags
+!Finclude/net/cfg80211.h mpath_info_flags
+!Finclude/net/cfg80211.h mpath_info
+!Finclude/net/cfg80211.h bss_parameters
+!Finclude/net/cfg80211.h ieee80211_txq_params
+!Finclude/net/cfg80211.h cfg80211_crypto_settings
+!Finclude/net/cfg80211.h cfg80211_auth_request
+!Finclude/net/cfg80211.h cfg80211_assoc_request
+!Finclude/net/cfg80211.h cfg80211_deauth_request
+!Finclude/net/cfg80211.h cfg80211_disassoc_request
+!Finclude/net/cfg80211.h cfg80211_ibss_params
+!Finclude/net/cfg80211.h cfg80211_connect_params
+!Finclude/net/cfg80211.h cfg80211_pmksa
+!Finclude/net/cfg80211.h cfg80211_send_rx_auth
+!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
+!Finclude/net/cfg80211.h __cfg80211_auth_canceled
+!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
+!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
+!Finclude/net/cfg80211.h cfg80211_send_deauth
+!Finclude/net/cfg80211.h __cfg80211_send_deauth
+!Finclude/net/cfg80211.h cfg80211_send_disassoc
+!Finclude/net/cfg80211.h __cfg80211_send_disassoc
+!Finclude/net/cfg80211.h cfg80211_ibss_joined
+!Finclude/net/cfg80211.h cfg80211_connect_result
+!Finclude/net/cfg80211.h cfg80211_roamed
+!Finclude/net/cfg80211.h cfg80211_disconnected
+!Finclude/net/cfg80211.h cfg80211_ready_on_channel
+!Finclude/net/cfg80211.h cfg80211_remain_on_channel_expired
+!Finclude/net/cfg80211.h cfg80211_new_sta
+!Finclude/net/cfg80211.h cfg80211_rx_mgmt
+!Finclude/net/cfg80211.h cfg80211_mgmt_tx_status
+!Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify
+!Finclude/net/cfg80211.h cfg80211_michael_mic_failure
+      </chapter>
+      <chapter>
+      <title>Scanning and BSS list handling</title>
+!Pinclude/net/cfg80211.h Scanning and BSS list handling
+!Finclude/net/cfg80211.h cfg80211_ssid
+!Finclude/net/cfg80211.h cfg80211_scan_request
+!Finclude/net/cfg80211.h cfg80211_scan_done
+!Finclude/net/cfg80211.h cfg80211_bss
+!Finclude/net/cfg80211.h cfg80211_inform_bss_frame
+!Finclude/net/cfg80211.h cfg80211_inform_bss
+!Finclude/net/cfg80211.h cfg80211_unlink_bss
+!Finclude/net/cfg80211.h cfg80211_find_ie
+!Finclude/net/cfg80211.h ieee80211_bss_get_ie
+      </chapter>
+      <chapter>
+      <title>Utility functions</title>
+!Pinclude/net/cfg80211.h Utility functions
+!Finclude/net/cfg80211.h ieee80211_channel_to_frequency
+!Finclude/net/cfg80211.h ieee80211_frequency_to_channel
+!Finclude/net/cfg80211.h ieee80211_get_channel
+!Finclude/net/cfg80211.h ieee80211_get_response_rate
+!Finclude/net/cfg80211.h ieee80211_hdrlen
+!Finclude/net/cfg80211.h ieee80211_get_hdrlen_from_skb
+!Finclude/net/cfg80211.h ieee80211_radiotap_iterator
+      </chapter>
+      <chapter>
+      <title>Data path helpers</title>
+!Pinclude/net/cfg80211.h Data path helpers
+!Finclude/net/cfg80211.h ieee80211_data_to_8023
+!Finclude/net/cfg80211.h ieee80211_data_from_8023
+!Finclude/net/cfg80211.h ieee80211_amsdu_to_8023s
+!Finclude/net/cfg80211.h cfg80211_classify8021d
+      </chapter>
+      <chapter>
+      <title>Regulatory enforcement infrastructure</title>
+!Pinclude/net/cfg80211.h Regulatory enforcement infrastructure
+!Finclude/net/cfg80211.h regulatory_hint
+!Finclude/net/cfg80211.h wiphy_apply_custom_regulatory
+!Finclude/net/cfg80211.h freq_reg_info
+      </chapter>
+      <chapter>
+      <title>RFkill integration</title>
+!Pinclude/net/cfg80211.h RFkill integration
+!Finclude/net/cfg80211.h wiphy_rfkill_set_hw_state
+!Finclude/net/cfg80211.h wiphy_rfkill_start_polling
+!Finclude/net/cfg80211.h wiphy_rfkill_stop_polling
+      </chapter>
+      <chapter>
+      <title>Test mode</title>
+!Pinclude/net/cfg80211.h Test mode
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_reply_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_reply
+!Finclude/net/cfg80211.h cfg80211_testmode_alloc_event_skb
+!Finclude/net/cfg80211.h cfg80211_testmode_event
+      </chapter>
+  </book>
+  <book id="mac80211-developers-guide">
+    <bookinfo>
+      <title>The mac80211 subsystem</title>
+      <abstract>
+!Pinclude/net/mac80211.h Introduction
+!Pinclude/net/mac80211.h Warning
+      </abstract>
+    </bookinfo>
+
+    <toc></toc>
+
+  <!--
+  Generally, this document shall be ordered by increasing complexity.
+  It is important to note that readers should be able to read only
+  the first few sections to get a working driver and only advanced
+  usage should require reading the full document.
+  -->
+
+    <part>
+      <title>The basic mac80211 driver interface</title>
+      <partintro>
+        <para>
+          You should read and understand the information contained
+          within this part of the book while implementing a driver.
+          In some chapters, advanced usage is noted, that may be
+          skipped at first.
+        </para>
+        <para>
+          This part of the book only covers station and monitor mode
+          functionality, additional information required to implement
+          the other modes is covered in the second part of the book.
+        </para>
+      </partintro>
+
+      <chapter id="basics">
+        <title>Basic hardware handling</title>
+        <para>TBD</para>
+        <para>
+          This chapter shall contain information on getting a hw
+          struct allocated and registered with mac80211.
+        </para>
+        <para>
+          Since it is required to allocate rates/modes before registering
+          a hw struct, this chapter shall also contain information on setting
+          up the rate/mode structs.
+        </para>
+        <para>
+          Additionally, some discussion about the callbacks and
+          the general programming model should be in here, including
+          the definition of ieee80211_ops which will be referred to
+          a lot.
+        </para>
+        <para>
+          Finally, a discussion of hardware capabilities should be done
+          with references to other parts of the book.
+        </para>
+  <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h ieee80211_hw
+!Finclude/net/mac80211.h ieee80211_hw_flags
+!Finclude/net/mac80211.h SET_IEEE80211_DEV
+!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
+!Finclude/net/mac80211.h ieee80211_ops
+!Finclude/net/mac80211.h ieee80211_alloc_hw
+!Finclude/net/mac80211.h ieee80211_register_hw
+!Finclude/net/mac80211.h ieee80211_get_tx_led_name
+!Finclude/net/mac80211.h ieee80211_get_rx_led_name
+!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
+!Finclude/net/mac80211.h ieee80211_get_radio_led_name
+!Finclude/net/mac80211.h ieee80211_unregister_hw
+!Finclude/net/mac80211.h ieee80211_free_hw
+      </chapter>
+
+      <chapter id="phy-handling">
+        <title>PHY configuration</title>
+        <para>TBD</para>
+        <para>
+          This chapter should describe PHY handling including
+          start/stop callbacks and the various structures used.
+        </para>
+!Finclude/net/mac80211.h ieee80211_conf
+!Finclude/net/mac80211.h ieee80211_conf_flags
+      </chapter>
+
+      <chapter id="iface-handling">
+        <title>Virtual interfaces</title>
+        <para>TBD</para>
+        <para>
+          This chapter should describe virtual interface basics
+          that are relevant to the driver (VLANs, MGMT etc are not.)
+          It should explain the use of the add_iface/remove_iface
+          callbacks as well as the interface configuration callbacks.
+        </para>
+        <para>Things related to AP mode should be discussed there.</para>
+        <para>
+          Things related to supporting multiple interfaces should be
+          in the appropriate chapter, a BIG FAT note should be here about
+          this though and the recommendation to allow only a single
+          interface in STA mode at first!
+        </para>
+!Finclude/net/mac80211.h ieee80211_vif
+      </chapter>
+
+      <chapter id="rx-tx">
+        <title>Receive and transmit processing</title>
+        <sect1>
+          <title>what should be here</title>
+          <para>TBD</para>
+          <para>
+            This should describe the receive and transmit
+            paths in mac80211/the drivers as well as
+            transmit status handling.
+          </para>
+        </sect1>
+        <sect1>
+          <title>Frame format</title>
+!Pinclude/net/mac80211.h Frame format
+        </sect1>
+        <sect1>
+          <title>Packet alignment</title>
+!Pnet/mac80211/rx.c Packet alignment
+        </sect1>
+        <sect1>
+          <title>Calling into mac80211 from interrupts</title>
+!Pinclude/net/mac80211.h Calling mac80211 from interrupts
+        </sect1>
+        <sect1>
+          <title>functions/definitions</title>
+!Finclude/net/mac80211.h ieee80211_rx_status
+!Finclude/net/mac80211.h mac80211_rx_flags
+!Finclude/net/mac80211.h ieee80211_tx_info
+!Finclude/net/mac80211.h ieee80211_rx
+!Finclude/net/mac80211.h ieee80211_rx_irqsafe
+!Finclude/net/mac80211.h ieee80211_tx_status
+!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
+!Finclude/net/mac80211.h ieee80211_rts_get
+!Finclude/net/mac80211.h ieee80211_rts_duration
+!Finclude/net/mac80211.h ieee80211_ctstoself_get
+!Finclude/net/mac80211.h ieee80211_ctstoself_duration
+!Finclude/net/mac80211.h ieee80211_generic_frame_duration
+!Finclude/net/mac80211.h ieee80211_wake_queue
+!Finclude/net/mac80211.h ieee80211_stop_queue
+!Finclude/net/mac80211.h ieee80211_wake_queues
+!Finclude/net/mac80211.h ieee80211_stop_queues
+        </sect1>
+      </chapter>
+
+      <chapter id="filters">
+        <title>Frame filtering</title>
+!Pinclude/net/mac80211.h Frame filtering
+!Finclude/net/mac80211.h ieee80211_filter_flags
+      </chapter>
+    </part>
+
+    <part id="advanced">
+      <title>Advanced driver interface</title>
+      <partintro>
+        <para>
+         Information contained within this part of the book is
+         of interest only for advanced interaction of mac80211
+         with drivers to exploit more hardware capabilities and
+         improve performance.
+        </para>
+      </partintro>
+
+      <chapter id="hardware-crypto-offload">
+        <title>Hardware crypto acceleration</title>
+!Pinclude/net/mac80211.h Hardware crypto acceleration
+  <!-- intentionally multiple !F lines to get proper order -->
+!Finclude/net/mac80211.h set_key_cmd
+!Finclude/net/mac80211.h ieee80211_key_conf
+!Finclude/net/mac80211.h ieee80211_key_flags
+      </chapter>
+
+      <chapter id="powersave">
+        <title>Powersave support</title>
+!Pinclude/net/mac80211.h Powersave support
+      </chapter>
+
+      <chapter id="beacon-filter">
+        <title>Beacon filter support</title>
+!Pinclude/net/mac80211.h Beacon filter support
+!Finclude/net/mac80211.h ieee80211_beacon_loss
+      </chapter>
+
+      <chapter id="qos">
+        <title>Multiple queues and QoS support</title>
+        <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_tx_queue_params
+      </chapter>
+
+      <chapter id="AP">
+        <title>Access point mode support</title>
+        <para>TBD</para>
+        <para>Some parts of the if_conf should be discussed here instead</para>
+        <para>
+          Insert notes about VLAN interfaces with hw crypto here or
+          in the hw crypto chapter.
+        </para>
+!Finclude/net/mac80211.h ieee80211_get_buffered_bc
+!Finclude/net/mac80211.h ieee80211_beacon_get
+      </chapter>
+
+      <chapter id="multi-iface">
+        <title>Supporting multiple virtual interfaces</title>
+        <para>TBD</para>
+        <para>
+          Note: WDS with identical MAC address should almost always be OK
+        </para>
+        <para>
+          Insert notes about having multiple virtual interfaces with
+          different MAC addresses here, note which configurations are
+          supported by mac80211, add notes about supporting hw crypto
+          with it.
+        </para>
+      </chapter>
+
+      <chapter id="hardware-scan-offload">
+        <title>Hardware scan offload</title>
+        <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_scan_completed
+      </chapter>
+    </part>
+
+    <part id="rate-control">
+      <title>Rate control interface</title>
+      <partintro>
+        <para>TBD</para>
+        <para>
+         This part of the book describes the rate control algorithm
+         interface and how it relates to mac80211 and drivers.
+        </para>
+      </partintro>
+      <chapter id="dummy">
+        <title>dummy chapter</title>
+        <para>TBD</para>
+      </chapter>
+    </part>
+
+    <part id="internal">
+      <title>Internals</title>
+      <partintro>
+        <para>TBD</para>
+        <para>
+         This part of the book describes mac80211 internals.
+        </para>
+      </partintro>
+
+      <chapter id="key-handling">
+        <title>Key handling</title>
+        <sect1>
+          <title>Key handling basics</title>
+!Pnet/mac80211/key.c Key handling basics
+        </sect1>
+        <sect1>
+          <title>MORE TBD</title>
+          <para>TBD</para>
+        </sect1>
+      </chapter>
+
+      <chapter id="rx-processing">
+        <title>Receive processing</title>
+        <para>TBD</para>
+      </chapter>
+
+      <chapter id="tx-processing">
+        <title>Transmit processing</title>
+        <para>TBD</para>
+      </chapter>
+
+      <chapter id="sta-info">
+        <title>Station info handling</title>
+        <sect1>
+          <title>Programming information</title>
+!Fnet/mac80211/sta_info.h sta_info
+!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
+        </sect1>
+        <sect1>
+          <title>STA information lifetime rules</title>
+!Pnet/mac80211/sta_info.c STA information lifetime rules
+        </sect1>
+      </chapter>
+
+      <chapter id="synchronisation">
+        <title>Synchronisation</title>
+        <para>TBD</para>
+        <para>Locking, lots of RCU</para>
+      </chapter>
+    </part>
+  </book>
+</set>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/device-drivers.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/device-drivers.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/device-drivers.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/device-drivers.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -51,8 +51,13 @@
      <sect1><title>Delaying, scheduling, and timer routines</title>
 !Iinclude/linux/sched.h
 !Ekernel/sched.c
+!Iinclude/linux/completion.h
 !Ekernel/timer.c
      </sect1>
+     <sect1><title>Wait queues and Wake events</title>
+!Iinclude/linux/wait.h
+!Ekernel/wait.c
+     </sect1>
      <sect1><title>High-resolution timers</title>
 !Iinclude/linux/ktime.h
 !Iinclude/linux/hrtimer.h
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/drm.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/drm.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/drm.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/drm.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -136,6 +136,7 @@
 #ifdef CONFIG_COMPAT
 		.compat_ioctl = i915_compat_ioctl,
 #endif
+		.llseek = noop_llseek,
 		},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/genericirq.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/genericirq.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/genericirq.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/genericirq.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2005-2006</year>
+   <year>2005-2010</year>
    <holder>Thomas Gleixner</holder>
   </copyright>
   <copyright>
@@ -100,6 +100,10 @@
 	  <listitem><para>Edge type</para></listitem>
 	  <listitem><para>Simple type</para></listitem>
 	</itemizedlist>
+	During the implementation we identified another type:
+	<itemizedlist>
+	  <listitem><para>Fast EOI type</para></listitem>
+	</itemizedlist>
 	In the SMP world of the __do_IRQ() super-handler another type
 	was identified:
 	<itemizedlist>
@@ -153,6 +157,7 @@
 	is still available. This leads to a kind of duality for the time
 	being. Over time the new model should be used in more and more
 	architectures, as it enables smaller and cleaner IRQ subsystems.
+	It's deprecated for three years now and about to be removed.
 	</para>
   </chapter>
   <chapter id="bugs">
@@ -217,6 +222,7 @@
 	  <itemizedlist>
 	  <listitem><para>handle_level_irq</para></listitem>
 	  <listitem><para>handle_edge_irq</para></listitem>
+	  <listitem><para>handle_fasteoi_irq</para></listitem>
 	  <listitem><para>handle_simple_irq</para></listitem>
 	  <listitem><para>handle_percpu_irq</para></listitem>
 	  </itemizedlist>
@@ -233,33 +239,33 @@
 		are used by the default flow implementations.
 		The following helper functions are implemented (simplified excerpt):
 		<programlisting>
-default_enable(irq)
+default_enable(struct irq_data *data)
 {
-	desc->chip->unmask(irq);
+	desc->chip->irq_unmask(data);
 }
 
-default_disable(irq)
+default_disable(struct irq_data *data)
 {
-	if (!delay_disable(irq))
-		desc->chip->mask(irq);
+	if (!delay_disable(data))
+		desc->chip->irq_mask(data);
 }
 
-default_ack(irq)
+default_ack(struct irq_data *data)
 {
-	chip->ack(irq);
+	chip->irq_ack(data);
 }
 
-default_mask_ack(irq)
+default_mask_ack(struct irq_data *data)
 {
-	if (chip->mask_ack) {
-		chip->mask_ack(irq);
+	if (chip->irq_mask_ack) {
+		chip->irq_mask_ack(data);
 	} else {
-		chip->mask(irq);
-		chip->ack(irq);
+		chip->irq_mask(data);
+		chip->irq_ack(data);
 	}
 }
 
-noop(irq)
+noop(struct irq_data *data))
 {
 }
 
@@ -278,12 +284,27 @@
 		<para>
 		The following control flow is implemented (simplified excerpt):
 		<programlisting>
-desc->chip->start();
+desc->chip->irq_mask();
 handle_IRQ_event(desc->action);
-desc->chip->end();
+desc->chip->irq_unmask();
 		</programlisting>
 		</para>
-   	    </sect3>
+	    </sect3>
+	    <sect3 id="Default_FASTEOI_IRQ_flow_handler">
+		<title>Default Fast EOI IRQ flow handler</title>
+		<para>
+		handle_fasteoi_irq provides a generic implementation
+		for interrupts, which only need an EOI at the end of
+		the handler
+		</para>
+		<para>
+		The following control flow is implemented (simplified excerpt):
+		<programlisting>
+handle_IRQ_event(desc->action);
+desc->chip->irq_eoi();
+		</programlisting>
+		</para>
+	    </sect3>
 	    <sect3 id="Default_Edge_IRQ_flow_handler">
 	 	<title>Default Edge IRQ flow handler</title>
 		<para>
@@ -294,20 +315,19 @@
 		The following control flow is implemented (simplified excerpt):
 		<programlisting>
 if (desc->status &amp; running) {
-	desc->chip->hold();
+	desc->chip->irq_mask();
 	desc->status |= pending | masked;
 	return;
 }
-desc->chip->start();
+desc->chip->irq_ack();
 desc->status |= running;
 do {
 	if (desc->status &amp; masked)
-		desc->chip->enable();
+		desc->chip->irq_unmask();
 	desc->status &amp;= ~pending;
 	handle_IRQ_event(desc->action);
 } while (status &amp; pending);
 desc->status &amp;= ~running;
-desc->chip->end();
 		</programlisting>
 		</para>
    	    </sect3>
@@ -342,9 +362,9 @@
 		<para>
 		The following control flow is implemented (simplified excerpt):
 		<programlisting>
-desc->chip->start();
 handle_IRQ_event(desc->action);
-desc->chip->end();
+if (desc->chip->irq_eoi)
+        desc->chip->irq_eoi();
 		</programlisting>
 		</para>
    	    </sect3>
@@ -375,8 +395,7 @@
 	mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when
 	you want to use the delayed interrupt disable feature and your
 	hardware is not capable of retriggering	an interrupt.)
-	The delayed interrupt disable can be runtime enabled, per interrupt,
-	by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
+	The delayed interrupt disable is not configurable.
 	</para>
 	</sect2>
     </sect1>
@@ -387,13 +406,13 @@
 	contains all the direct chip relevant functions, which
 	can be utilized by the irq flow implementations.
 	  <itemizedlist>
-	  <listitem><para>ack()</para></listitem>
-	  <listitem><para>mask_ack() - Optional, recommended for performance</para></listitem>
-	  <listitem><para>mask()</para></listitem>
-	  <listitem><para>unmask()</para></listitem>
-	  <listitem><para>retrigger() - Optional</para></listitem>
-	  <listitem><para>set_type() - Optional</para></listitem>
-	  <listitem><para>set_wake() - Optional</para></listitem>
+	  <listitem><para>irq_ack()</para></listitem>
+	  <listitem><para>irq_mask_ack() - Optional, recommended for performance</para></listitem>
+	  <listitem><para>irq_mask()</para></listitem>
+	  <listitem><para>irq_unmask()</para></listitem>
+	  <listitem><para>irq_retrigger() - Optional</para></listitem>
+	  <listitem><para>irq_set_type() - Optional</para></listitem>
+	  <listitem><para>irq_set_wake() - Optional</para></listitem>
 	  </itemizedlist>
 	These primitives are strictly intended to mean what they say: ack means
 	ACK, masking means masking of an IRQ line, etc. It is up to the flow
@@ -458,6 +477,7 @@
      <para>
      This chapter contains the autogenerated documentation of the internal functions.
      </para>
+!Ikernel/irq/irqdesc.c
 !Ikernel/irq/handle.c
 !Ikernel/irq/chip.c
   </chapter>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/kernel-api.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/kernel-api.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/kernel-api.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/kernel-api.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -93,6 +93,12 @@
 !Elib/crc32.c
 !Elib/crc-ccitt.c
      </sect1>
+
+     <sect1 id="idr"><title>idr/ida Functions</title>
+!Pinclude/linux/idr.h idr sync
+!Plib/idr.c IDA description
+!Elib/idr.c
+     </sect1>
   </chapter>
 
   <chapter id="mm">
@@ -257,7 +263,8 @@
 !Iblock/blk-sysfs.c
 !Eblock/blk-settings.c
 !Eblock/blk-exec.c
-!Eblock/blk-barrier.c
+!Eblock/blk-flush.c
+!Eblock/blk-lib.c
 !Eblock/blk-tag.c
 !Iblock/blk-tag.c
 !Eblock/blk-integrity.c
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/kernel-locking.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/kernel-locking.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/kernel-locking.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/kernel-locking.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -1645,7 +1645,9 @@
       all the readers who were traversing the list when we deleted the
       element are finished.  We use <function>call_rcu()</function> to
       register a callback which will actually destroy the object once
-      the readers are finished.
+      all pre-existing readers are finished.  Alternatively,
+      <function>synchronize_rcu()</function> may be used to block until
+      all pre-existing are finished.
     </para>
     <para>
       But how does Read Copy Update know when the readers are
@@ -1714,7 +1716,7 @@
 -        object_put(obj);
 +        list_del_rcu(&amp;obj-&gt;list);
          cache_num--;
-+        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu, obj);
++        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu);
  }
 
  /* Must be holding cache_lock */
@@ -1725,14 +1727,6 @@
          if (++cache_num > MAX_CACHE_SIZE) {
                  struct object *i, *outcast = NULL;
                  list_for_each_entry(i, &amp;cache, list) {
-@@ -85,6 +94,7 @@
-         obj-&gt;popularity = 0;
-         atomic_set(&amp;obj-&gt;refcnt, 1); /* The cache holds a reference */
-         spin_lock_init(&amp;obj-&gt;lock);
-+        INIT_RCU_HEAD(&amp;obj-&gt;rcu);
-
-         spin_lock_irqsave(&amp;cache_lock, flags);
-         __cache_add(obj);
 @@ -104,12 +114,11 @@
  struct object *cache_find(int id)
  {
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/kgdb.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/kgdb.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/kgdb.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/kgdb.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -710,7 +710,18 @@
         <listitem><para>A simple shell</para></listitem>
         <listitem><para>The kdb core command set</para></listitem>
         <listitem><para>A registration API to register additional kdb shell commands.</para>
-        <para>A good example of a self-contained kdb module is the "ftdump" command for dumping the ftrace buffer.  See: kernel/trace/trace_kdb.c</para></listitem>
+	<itemizedlist>
+        <listitem><para>A good example of a self-contained kdb module
+        is the "ftdump" command for dumping the ftrace buffer.  See:
+        kernel/trace/trace_kdb.c</para></listitem>
+        <listitem><para>For an example of how to dynamically register
+        a new kdb command you can build the kdb_hello.ko kernel module
+        from samples/kdb/kdb_hello.c.  To build this example you can
+        set CONFIG_SAMPLES=y and CONFIG_SAMPLE_KDB=m in your kernel
+        config.  Later run "modprobe kdb_hello" and the next time you
+        enter the kdb shell, you can run the "hello"
+        command.</para></listitem>
+	</itemizedlist></listitem>
         <listitem><para>The implementation for kdb_printf() which
         emits messages directly to I/O drivers, bypassing the kernel
         log.</para></listitem>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/mac80211.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/mac80211.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/mac80211.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/mac80211.tmpl	1969-12-31 19:00:00.000000000 -0500
@@ -1,337 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="mac80211-developers-guide">
-  <bookinfo>
-    <title>The mac80211 subsystem for kernel developers</title>
-
-    <authorgroup>
-      <author>
-        <firstname>Johannes</firstname>
-        <surname>Berg</surname>
-        <affiliation>
-          <address><email>johannes@sipsolutions.net</email></address>
-        </affiliation>
-      </author>
-    </authorgroup>
-
-    <copyright>
-      <year>2007-2009</year>
-      <holder>Johannes Berg</holder>
-    </copyright>
-
-    <legalnotice>
-      <para>
-        This documentation is free software; you can redistribute
-        it and/or modify it under the terms of the GNU General Public
-        License version 2 as published by the Free Software Foundation.
-      </para>
-
-      <para>
-        This documentation is distributed in the hope that it will be
-        useful, but WITHOUT ANY WARRANTY; without even the implied
-        warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-        See the GNU General Public License for more details.
-      </para>
-
-      <para>
-        You should have received a copy of the GNU General Public
-        License along with this documentation; if not, write to the Free
-        Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-        MA 02111-1307 USA
-      </para>
-
-      <para>
-        For more details see the file COPYING in the source
-        distribution of Linux.
-      </para>
-    </legalnotice>
-
-    <abstract>
-!Pinclude/net/mac80211.h Introduction
-!Pinclude/net/mac80211.h Warning
-    </abstract>
-  </bookinfo>
-
-  <toc></toc>
-
-<!--
-Generally, this document shall be ordered by increasing complexity.
-It is important to note that readers should be able to read only
-the first few sections to get a working driver and only advanced
-usage should require reading the full document.
--->
-
-  <part>
-    <title>The basic mac80211 driver interface</title>
-    <partintro>
-      <para>
-        You should read and understand the information contained
-        within this part of the book while implementing a driver.
-        In some chapters, advanced usage is noted, that may be
-        skipped at first.
-      </para>
-      <para>
-        This part of the book only covers station and monitor mode
-        functionality, additional information required to implement
-        the other modes is covered in the second part of the book.
-      </para>
-    </partintro>
-
-    <chapter id="basics">
-      <title>Basic hardware handling</title>
-      <para>TBD</para>
-      <para>
-        This chapter shall contain information on getting a hw
-        struct allocated and registered with mac80211.
-      </para>
-      <para>
-        Since it is required to allocate rates/modes before registering
-        a hw struct, this chapter shall also contain information on setting
-        up the rate/mode structs.
-      </para>
-      <para>
-        Additionally, some discussion about the callbacks and
-        the general programming model should be in here, including
-        the definition of ieee80211_ops which will be referred to
-        a lot.
-      </para>
-      <para>
-        Finally, a discussion of hardware capabilities should be done
-        with references to other parts of the book.
-      </para>
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h ieee80211_hw
-!Finclude/net/mac80211.h ieee80211_hw_flags
-!Finclude/net/mac80211.h SET_IEEE80211_DEV
-!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR
-!Finclude/net/mac80211.h ieee80211_ops
-!Finclude/net/mac80211.h ieee80211_alloc_hw
-!Finclude/net/mac80211.h ieee80211_register_hw
-!Finclude/net/mac80211.h ieee80211_get_tx_led_name
-!Finclude/net/mac80211.h ieee80211_get_rx_led_name
-!Finclude/net/mac80211.h ieee80211_get_assoc_led_name
-!Finclude/net/mac80211.h ieee80211_get_radio_led_name
-!Finclude/net/mac80211.h ieee80211_unregister_hw
-!Finclude/net/mac80211.h ieee80211_free_hw
-    </chapter>
-
-    <chapter id="phy-handling">
-      <title>PHY configuration</title>
-      <para>TBD</para>
-      <para>
-        This chapter should describe PHY handling including
-        start/stop callbacks and the various structures used.
-      </para>
-!Finclude/net/mac80211.h ieee80211_conf
-!Finclude/net/mac80211.h ieee80211_conf_flags
-    </chapter>
-
-    <chapter id="iface-handling">
-      <title>Virtual interfaces</title>
-      <para>TBD</para>
-      <para>
-        This chapter should describe virtual interface basics
-        that are relevant to the driver (VLANs, MGMT etc are not.)
-        It should explain the use of the add_iface/remove_iface
-        callbacks as well as the interface configuration callbacks.
-      </para>
-      <para>Things related to AP mode should be discussed there.</para>
-      <para>
-        Things related to supporting multiple interfaces should be
-        in the appropriate chapter, a BIG FAT note should be here about
-        this though and the recommendation to allow only a single
-        interface in STA mode at first!
-      </para>
-!Finclude/net/mac80211.h ieee80211_vif
-    </chapter>
-
-    <chapter id="rx-tx">
-      <title>Receive and transmit processing</title>
-      <sect1>
-        <title>what should be here</title>
-        <para>TBD</para>
-        <para>
-          This should describe the receive and transmit
-          paths in mac80211/the drivers as well as
-          transmit status handling.
-        </para>
-      </sect1>
-      <sect1>
-        <title>Frame format</title>
-!Pinclude/net/mac80211.h Frame format
-      </sect1>
-      <sect1>
-        <title>Packet alignment</title>
-!Pnet/mac80211/rx.c Packet alignment
-      </sect1>
-      <sect1>
-        <title>Calling into mac80211 from interrupts</title>
-!Pinclude/net/mac80211.h Calling mac80211 from interrupts
-      </sect1>
-      <sect1>
-        <title>functions/definitions</title>
-!Finclude/net/mac80211.h ieee80211_rx_status
-!Finclude/net/mac80211.h mac80211_rx_flags
-!Finclude/net/mac80211.h ieee80211_tx_info
-!Finclude/net/mac80211.h ieee80211_rx
-!Finclude/net/mac80211.h ieee80211_rx_irqsafe
-!Finclude/net/mac80211.h ieee80211_tx_status
-!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
-!Finclude/net/mac80211.h ieee80211_rts_get
-!Finclude/net/mac80211.h ieee80211_rts_duration
-!Finclude/net/mac80211.h ieee80211_ctstoself_get
-!Finclude/net/mac80211.h ieee80211_ctstoself_duration
-!Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_wake_queue
-!Finclude/net/mac80211.h ieee80211_stop_queue
-!Finclude/net/mac80211.h ieee80211_wake_queues
-!Finclude/net/mac80211.h ieee80211_stop_queues
-      </sect1>
-    </chapter>
-
-    <chapter id="filters">
-      <title>Frame filtering</title>
-!Pinclude/net/mac80211.h Frame filtering
-!Finclude/net/mac80211.h ieee80211_filter_flags
-    </chapter>
-  </part>
-
-  <part id="advanced">
-    <title>Advanced driver interface</title>
-    <partintro>
-      <para>
-       Information contained within this part of the book is
-       of interest only for advanced interaction of mac80211
-       with drivers to exploit more hardware capabilities and
-       improve performance.
-      </para>
-    </partintro>
-
-    <chapter id="hardware-crypto-offload">
-      <title>Hardware crypto acceleration</title>
-!Pinclude/net/mac80211.h Hardware crypto acceleration
-<!-- intentionally multiple !F lines to get proper order -->
-!Finclude/net/mac80211.h set_key_cmd
-!Finclude/net/mac80211.h ieee80211_key_conf
-!Finclude/net/mac80211.h ieee80211_key_alg
-!Finclude/net/mac80211.h ieee80211_key_flags
-    </chapter>
-
-    <chapter id="powersave">
-      <title>Powersave support</title>
-!Pinclude/net/mac80211.h Powersave support
-    </chapter>
-
-    <chapter id="beacon-filter">
-      <title>Beacon filter support</title>
-!Pinclude/net/mac80211.h Beacon filter support
-!Finclude/net/mac80211.h ieee80211_beacon_loss
-    </chapter>
-
-    <chapter id="qos">
-      <title>Multiple queues and QoS support</title>
-      <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_tx_queue_params
-    </chapter>
-
-    <chapter id="AP">
-      <title>Access point mode support</title>
-      <para>TBD</para>
-      <para>Some parts of the if_conf should be discussed here instead</para>
-      <para>
-        Insert notes about VLAN interfaces with hw crypto here or
-        in the hw crypto chapter.
-      </para>
-!Finclude/net/mac80211.h ieee80211_get_buffered_bc
-!Finclude/net/mac80211.h ieee80211_beacon_get
-    </chapter>
-
-    <chapter id="multi-iface">
-      <title>Supporting multiple virtual interfaces</title>
-      <para>TBD</para>
-      <para>
-        Note: WDS with identical MAC address should almost always be OK
-      </para>
-      <para>
-        Insert notes about having multiple virtual interfaces with
-        different MAC addresses here, note which configurations are
-        supported by mac80211, add notes about supporting hw crypto
-        with it.
-      </para>
-    </chapter>
-
-    <chapter id="hardware-scan-offload">
-      <title>Hardware scan offload</title>
-      <para>TBD</para>
-!Finclude/net/mac80211.h ieee80211_scan_completed
-    </chapter>
-  </part>
-
-  <part id="rate-control">
-    <title>Rate control interface</title>
-    <partintro>
-      <para>TBD</para>
-      <para>
-       This part of the book describes the rate control algorithm
-       interface and how it relates to mac80211 and drivers.
-      </para>
-    </partintro>
-    <chapter id="dummy">
-      <title>dummy chapter</title>
-      <para>TBD</para>
-    </chapter>
-  </part>
-
-  <part id="internal">
-    <title>Internals</title>
-    <partintro>
-      <para>TBD</para>
-      <para>
-       This part of the book describes mac80211 internals.
-      </para>
-    </partintro>
-
-    <chapter id="key-handling">
-      <title>Key handling</title>
-      <sect1>
-        <title>Key handling basics</title>
-!Pnet/mac80211/key.c Key handling basics
-      </sect1>
-      <sect1>
-        <title>MORE TBD</title>
-        <para>TBD</para>
-      </sect1>
-    </chapter>
-
-    <chapter id="rx-processing">
-      <title>Receive processing</title>
-      <para>TBD</para>
-    </chapter>
-
-    <chapter id="tx-processing">
-      <title>Transmit processing</title>
-      <para>TBD</para>
-    </chapter>
-
-    <chapter id="sta-info">
-      <title>Station info handling</title>
-      <sect1>
-        <title>Programming information</title>
-!Fnet/mac80211/sta_info.h sta_info
-!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags
-      </sect1>
-      <sect1>
-        <title>STA information lifetime rules</title>
-!Pnet/mac80211/sta_info.c STA information lifetime rules
-      </sect1>
-    </chapter>
-
-    <chapter id="synchronisation">
-      <title>Synchronisation</title>
-      <para>TBD</para>
-      <para>Locking, lots of RCU</para>
-    </chapter>
-  </part>
-</book>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/Makefile linux-libre-2.6.37-gnu/Documentation/DocBook/Makefile
--- linux-libre-2.6.36-gnu/Documentation/DocBook/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
 	    kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
 	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
 	    genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
-	    mac80211.xml debugobjects.xml sh.xml regulator.xml \
+	    80211.xml debugobjects.xml sh.xml regulator.xml \
 	    alsa-driver-api.xml writing-an-alsa-driver.xml \
 	    tracepoint.xml media.xml drm.xml
 
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/media-entities.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/media-entities.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/media-entities.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/media-entities.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -250,6 +250,9 @@
 <!ENTITY sub-yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
+<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
+<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
 <!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
@@ -347,6 +350,9 @@
 <!ENTITY yuv422p SYSTEM "v4l/pixfmt-yuv422p.xml">
 <!ENTITY yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
 <!ENTITY yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
+<!ENTITY srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
+<!ENTITY y10 SYSTEM "v4l/pixfmt-y10.xml">
 <!ENTITY cropcap SYSTEM "v4l/vidioc-cropcap.xml">
 <!ENTITY dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
 <!ENTITY encoder-cmd SYSTEM "v4l/vidioc-encoder-cmd.xml">
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/sh.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/sh.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/sh.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/sh.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -79,10 +79,6 @@
       </sect2>
     </sect1>
   </chapter>
-  <chapter id="clk">
-    <title>Clock Framework Extensions</title>
-!Iinclude/linux/sh_clk.h
-  </chapter>
   <chapter id="mach">
     <title>Machine Specific Interfaces</title>
     <sect1 id="dreamcast">
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/uio-howto.tmpl linux-libre-2.6.37-gnu/Documentation/DocBook/uio-howto.tmpl
--- linux-libre-2.6.36-gnu/Documentation/DocBook/uio-howto.tmpl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/uio-howto.tmpl	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 	</orgname>
 
 	<address>
-	   <email>hjk@linutronix.de</email>
+	   <email>hjk@hansjkoch.de</email>
 	</address>
     </affiliation>
 </author>
@@ -114,7 +114,7 @@
 
 <para>If you know of any translations for this document, or you are
 interested in translating it, please email me
-<email>hjk@linutronix.de</email>.
+<email>hjk@hansjkoch.de</email>.
 </para>
 </sect1>
 
@@ -171,7 +171,7 @@
 <title>Feedback</title>
 	<para>Find something wrong with this document? (Or perhaps something
 	right?) I would love to hear from you. Please email me at
-	<email>hjk@linutronix.de</email>.</para>
+	<email>hjk@hansjkoch.de</email>.</para>
 </sect1>
 </chapter>
 
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/compat.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/compat.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/compat.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/compat.xml	2011-01-04 19:50:19.000000000 -0500
@@ -21,11 +21,15 @@
       <title>Opening and Closing Devices</title>
 
       <para>For compatibility reasons the character device file names
-recommended for V4L2 video capture, overlay, radio, teletext and raw
+recommended for V4L2 video capture, overlay, radio and raw
 vbi capture devices did not change from those used by V4L. They are
 listed in <xref linkend="devices" /> and below in <xref
 	  linkend="v4l-dev" />.</para>
 
+      <para>The teletext devices (minor range 192-223) have been removed in
+V4L2 and no longer exist. There is no hardware available anymore for handling
+pure teletext. Instead raw or sliced VBI is used.</para>
+
       <para>The V4L <filename>videodev</filename> module automatically
 assigns minor numbers to drivers in load order, depending on the
 registered device type. We recommend that V4L2 drivers by default
@@ -66,13 +70,6 @@
 	      <entry>64-127</entry>
 	    </row>
 	    <row>
-	      <entry>Teletext decoder</entry>
-	      <entry><para><filename>/dev/vtx</filename>,
-<filename>/dev/vtx0</filename> to
-<filename>/dev/vtx31</filename></para></entry>
-	      <entry>192-223</entry>
-	    </row>
-	    <row>
 	      <entry>Raw VBI capture</entry>
 	      <entry><para><filename>/dev/vbi</filename>,
 <filename>/dev/vbi0</filename> to
@@ -2344,6 +2341,17 @@
 	  </para>
 	</listitem>
       </orderedlist>
+    </section>
+    <section>
+      <title>V4L2 in Linux 2.6.37</title>
+      <orderedlist>
+	<listitem>
+	  <para>Remove the vtx (videotext/teletext) API. This API was no longer
+used and no hardware exists to verify the API. Nor were any userspace applications found
+that used it. It was originally scheduled for removal in 2.6.35.
+	  </para>
+	</listitem>
+      </orderedlist>
     </section>
 
     <section id="other">
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/controls.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/controls.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/controls.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/controls.xml	2011-01-04 19:50:19.000000000 -0500
@@ -312,10 +312,17 @@
 	    information and bits 24-31 must be zero.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
+		<constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Switch on or off the illuminator 1 or 2 of the device
+		(usually a microscope).</entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CID_LASTP1</constant></entry>
 	    <entry></entry>
 	    <entry>End of the predefined control IDs (currently
-<constant>V4L2_CID_BG_COLOR</constant> + 1).</entry>
+<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
@@ -357,9 +364,6 @@
 	      querymenu.index++) {
 		if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
 			printf ("  %s\n", querymenu.name);
-		} else {
-			perror ("VIDIOC_QUERYMENU");
-			exit (EXIT_FAILURE);
 		}
 	}
 }
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/dev-rds.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/dev-rds.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/dev-rds.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/dev-rds.xml	2011-01-04 19:50:19.000000000 -0500
@@ -3,15 +3,16 @@
       <para>The Radio Data System transmits supplementary
 information in binary format, for example the station name or travel
 information, on an inaudible audio subcarrier of a radio program. This
-interface is aimed at devices capable of receiving and decoding RDS
+interface is aimed at devices capable of receiving and/or transmitting RDS
 information.</para>
 
       <para>For more information see the core RDS standard <xref linkend="en50067" />
 and the RBDS standard <xref linkend="nrsc4" />.</para>
 
       <para>Note that the RBDS standard as is used in the USA is almost identical
-to the RDS standard. Any RDS decoder can also handle RBDS. Only some of the fields
-have slightly different meanings. See the RBDS standard for more information.</para>
+to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
+fields have slightly different meanings. See the RBDS standard for more
+information.</para>
 
       <para>The RBDS standard also specifies support for MMBS (Modified Mobile Search).
 This is a proprietary format which seems to be discontinued. The RDS interface does not
@@ -21,16 +22,25 @@
   <section>
     <title>Querying Capabilities</title>
 
-    <para>Devices supporting the RDS capturing API
-set the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
+    <para>Devices supporting the RDS capturing API set
+the <constant>V4L2_CAP_RDS_CAPTURE</constant> flag in
 the <structfield>capabilities</structfield> field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.
-Any tuner that supports RDS will set the
-<constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
-field of &v4l2-tuner;.
-Whether an RDS signal is present can be detected by looking at
-the <structfield>rxsubchans</structfield> field of &v4l2-tuner;: the
-<constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data was detected.</para>
+returned by the &VIDIOC-QUERYCAP; ioctl.  Any tuner that supports RDS
+will set the <constant>V4L2_TUNER_CAP_RDS</constant> flag in
+the <structfield>capability</structfield> field of &v4l2-tuner;.  If
+the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be
+set, see <link linkend="reading-rds-data">Reading RDS data</link>.
+For future use the
+flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> has also been
+defined. However, a driver for a radio tuner with this capability does
+not yet exist, so if you are planning to write such a driver you
+should discuss this on the linux-media mailing list: &v4l-ml;.</para>
+
+    <para> Whether an RDS signal is present can be detected by looking
+at the <structfield>rxsubchans</structfield> field of &v4l2-tuner;:
+the <constant>V4L2_TUNER_SUB_RDS</constant> will be set if RDS data
+was detected.</para>
 
     <para>Devices supporting the RDS output API
 set the <constant>V4L2_CAP_RDS_OUTPUT</constant> flag in
@@ -40,16 +50,31 @@
 <constant>V4L2_TUNER_CAP_RDS</constant> flag in the <structfield>capability</structfield>
 field of &v4l2-modulator;.
 In order to enable the RDS transmission one must set the <constant>V4L2_TUNER_SUB_RDS</constant>
-bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.</para>
-
+bit in the <structfield>txsubchans</structfield> field of &v4l2-modulator;.
+If the driver only passes RDS blocks without interpreting the data
+the <constant>V4L2_TUNER_SUB_RDS_BLOCK_IO</constant> flag has to be set. If the
+tuner is capable of handling RDS entities like program identification codes and radio
+text, the flag <constant>V4L2_TUNER_SUB_RDS_CONTROLS</constant> should be set,
+see <link linkend="writing-rds-data">Writing RDS data</link> and
+<link linkend="fm-tx-controls">FM Transmitter Control Reference</link>.</para>
   </section>
 
-  <section>
+  <section  id="reading-rds-data">
     <title>Reading RDS data</title>
 
       <para>RDS data can be read from the radio device
-with the &func-read; function. The data is packed in groups of three bytes,
+with the &func-read; function. The data is packed in groups of three bytes.</para>
+  </section>
+
+  <section  id="writing-rds-data">
+    <title>Writing RDS data</title>
+
+      <para>RDS data can be written to the radio device
+with the &func-write; function. The data is packed in groups of three bytes,
 as follows:</para>
+  </section>
+
+  <section>
     <table frame="none" pgwide="1" id="v4l2-rds-data">
       <title>struct
 <structname>v4l2_rds_data</structname></title>
@@ -111,48 +136,57 @@
 	<tbody valign="top">
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_MSK</entry>
+	    <entry> </entry>
 	    <entry>7</entry>
 	    <entry>Mask for bits 0-2 to get the block ID.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_A</entry>
+	    <entry> </entry>
 	    <entry>0</entry>
 	    <entry>Block A.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_B</entry>
+	    <entry> </entry>
 	    <entry>1</entry>
 	    <entry>Block B.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_C</entry>
+	    <entry> </entry>
 	    <entry>2</entry>
 	    <entry>Block C.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_D</entry>
+	    <entry> </entry>
 	    <entry>3</entry>
 	    <entry>Block D.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_C_ALT</entry>
+	    <entry> </entry>
 	    <entry>4</entry>
 	    <entry>Block C'.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_INVALID</entry>
+	    <entry>read-only</entry>
 	    <entry>7</entry>
 	    <entry>An invalid block.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_CORRECTED</entry>
+	    <entry>read-only</entry>
 	    <entry>0x40</entry>
 	    <entry>A bit error was detected but corrected.</entry>
 	  </row>
 	  <row>
 	    <entry>V4L2_RDS_BLOCK_ERROR</entry>
+	    <entry>read-only</entry>
 	    <entry>0x80</entry>
-	    <entry>An incorrectable error occurred.</entry>
+	    <entry>An uncorrectable error occurred.</entry>
 	  </row>
 	</tbody>
       </tgroup>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/dev-teletext.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/dev-teletext.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/dev-teletext.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/dev-teletext.xml	2011-01-04 19:50:19.000000000 -0500
@@ -1,35 +1,32 @@
   <title>Teletext Interface</title>
 
-  <para>This interface aims at devices receiving and demodulating
+  <para>This interface was aimed at devices receiving and demodulating
 Teletext data [<xref linkend="ets300706" />, <xref linkend="itu653" />], evaluating the
 Teletext packages and storing formatted pages in cache memory. Such
 devices are usually implemented as microcontrollers with serial
-interface (I<superscript>2</superscript>C) and can be found on older
+interface (I<superscript>2</superscript>C) and could be found on old
 TV cards, dedicated Teletext decoding cards and home-brew devices
 connected to the PC parallel port.</para>
 
-  <para>The Teletext API was designed by Martin Buck. It is defined in
+  <para>The Teletext API was designed by Martin Buck. It was defined in
 the kernel header file <filename>linux/videotext.h</filename>, the
 specification is available from <ulink url="ftp://ftp.gwdg.de/pub/linux/misc/videotext/">
 ftp://ftp.gwdg.de/pub/linux/misc/videotext/</ulink>. (Videotext is the name of
-the German public television Teletext service.) Conventional character
-device file names are <filename>/dev/vtx</filename> and
-<filename>/dev/vttuner</filename>, with device number 83, 0 and 83, 16
-respectively. A similar interface exists for the Philips SAA5249
-Teletext decoder [specification?] with character device file names
-<filename>/dev/tlkN</filename>, device number 102, N.</para>
+the German public television Teletext service.)</para>
 
   <para>Eventually the Teletext API was integrated into the V4L API
 with character device file names <filename>/dev/vtx0</filename> to
 <filename>/dev/vtx31</filename>, device major number 81, minor numbers
-192 to 223. For reference the V4L Teletext API specification is
-reproduced here in full: "Teletext interfaces talk the existing VTX
-API." Teletext devices with major number 83 and 102 will be removed in
-Linux 2.6.</para>
+192 to 223.</para>
 
-  <para>There are no plans to replace the Teletext API or to integrate
-it into V4L2. Please write to the linux-media mailing list: &v4l-ml;
-when the need arises.</para>
+  <para>However, teletext decoders were quickly replaced by more
+generic VBI demodulators and those dedicated teletext decoders no longer exist.
+For many years the vtx devices were still around, even though nobody used
+them. So the decision was made to finally remove support for the Teletext API in
+kernel 2.6.37.</para>
+
+  <para>Modern devices all use the <link linkend="raw-vbi">raw</link> or
+<link linkend="sliced">sliced</link> VBI API.</para>
 
   <!--
 Local Variables:
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-packed-rgb.xml	2011-01-04 19:50:19.000000000 -0500
@@ -739,7 +739,7 @@
 	    <entry>b<subscript>1</subscript></entry>
 	    <entry>b<subscript>0</subscript></entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-BGR666">
+	  <row><!-- id="V4L2-PIX-FMT-BGR666" -->
 	    <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry>
 	    <entry>'BGRH'</entry>
 	    <entry></entry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-srggb10.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-srggb10.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-srggb10.xml	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-srggb10.xml	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,90 @@
+    <refentry>
+      <refmeta>
+	<refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
+	 V4L2_PIX_FMT_SGRBG10 ('BA10'),
+	 V4L2_PIX_FMT_SGBRG10 ('GB10'),
+	 V4L2_PIX_FMT_SBGGR10 ('BG10'),
+	 </refentrytitle>
+	&manvol;
+      </refmeta>
+      <refnamediv>
+	<refname id="V4L2-PIX-FMT-SRGGB10"><constant>V4L2_PIX_FMT_SRGGB10</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGRBG10"><constant>V4L2_PIX_FMT_SGRBG10</constant></refname>
+	<refname id="V4L2-PIX-FMT-SGBRG10"><constant>V4L2_PIX_FMT_SGBRG10</constant></refname>
+	<refname id="V4L2-PIX-FMT-SBGGR10"><constant>V4L2_PIX_FMT_SBGGR10</constant></refname>
+	<refpurpose>10-bit Bayer formats expanded to 16 bits</refpurpose>
+      </refnamediv>
+      <refsect1>
+	<title>Description</title>
+
+	<para>The following four pixel formats are raw sRGB / Bayer formats with
+10 bits per colour. Each colour component is stored in a 16-bit word, with 6
+unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes are
+stored in memory in little endian order. They are conventionally described
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_SBGGR10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+	<title>Byte Order.</title>
+	<para>Each cell is one byte, high 6 bits in high bytes are 0.
+	  <informaltable frame="none">
+	    <tgroup cols="5" align="center">
+	      <colspec align="left" colwidth="2*" />
+	      <tbody valign="top">
+		<row>
+		  <entry>start&nbsp;+&nbsp;0:</entry>
+		  <entry>B<subscript>00low</subscript></entry>
+		  <entry>B<subscript>00high</subscript></entry>
+		  <entry>G<subscript>01low</subscript></entry>
+		  <entry>G<subscript>01high</subscript></entry>
+		  <entry>B<subscript>02low</subscript></entry>
+		  <entry>B<subscript>02high</subscript></entry>
+		  <entry>G<subscript>03low</subscript></entry>
+		  <entry>G<subscript>03high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;8:</entry>
+		  <entry>G<subscript>10low</subscript></entry>
+		  <entry>G<subscript>10high</subscript></entry>
+		  <entry>R<subscript>11low</subscript></entry>
+		  <entry>R<subscript>11high</subscript></entry>
+		  <entry>G<subscript>12low</subscript></entry>
+		  <entry>G<subscript>12high</subscript></entry>
+		  <entry>R<subscript>13low</subscript></entry>
+		  <entry>R<subscript>13high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;16:</entry>
+		  <entry>B<subscript>20low</subscript></entry>
+		  <entry>B<subscript>20high</subscript></entry>
+		  <entry>G<subscript>21low</subscript></entry>
+		  <entry>G<subscript>21high</subscript></entry>
+		  <entry>B<subscript>22low</subscript></entry>
+		  <entry>B<subscript>22high</subscript></entry>
+		  <entry>G<subscript>23low</subscript></entry>
+		  <entry>G<subscript>23high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;24:</entry>
+		  <entry>G<subscript>30low</subscript></entry>
+		  <entry>G<subscript>30high</subscript></entry>
+		  <entry>R<subscript>31low</subscript></entry>
+		  <entry>R<subscript>31high</subscript></entry>
+		  <entry>G<subscript>32low</subscript></entry>
+		  <entry>G<subscript>32high</subscript></entry>
+		  <entry>R<subscript>33low</subscript></entry>
+		  <entry>R<subscript>33high</subscript></entry>
+		</row>
+	      </tbody>
+	    </tgroup>
+	  </informaltable>
+	</para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-srggb8.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-srggb8.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-srggb8.xml	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-srggb8.xml	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+    <refentry id="V4L2-PIX-FMT-SRGGB8">
+      <refmeta>
+	<refentrytitle>V4L2_PIX_FMT_SRGGB8 ('RGGB')</refentrytitle>
+	&manvol;
+      </refmeta>
+      <refnamediv>
+	<refname><constant>V4L2_PIX_FMT_SRGGB8</constant></refname>
+	<refpurpose>Bayer RGB format</refpurpose>
+      </refnamediv>
+      <refsect1>
+	<title>Description</title>
+
+	<para>This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a red and green value, the second row of a green and
+blue value. This scheme repeats to the right and down for every two
+columns and rows.</para>
+
+	<example>
+	  <title><constant>V4L2_PIX_FMT_SRGGB8</constant> 4 &times; 4
+pixel image</title>
+
+	  <formalpara>
+	    <title>Byte Order.</title>
+	    <para>Each cell is one byte.
+	      <informaltable frame="none">
+		<tgroup cols="5" align="center">
+		  <colspec align="left" colwidth="2*" />
+		  <tbody valign="top">
+		    <row>
+		      <entry>start&nbsp;+&nbsp;0:</entry>
+		      <entry>R<subscript>00</subscript></entry>
+		      <entry>G<subscript>01</subscript></entry>
+		      <entry>R<subscript>02</subscript></entry>
+		      <entry>G<subscript>03</subscript></entry>
+		    </row>
+		    <row>
+		      <entry>start&nbsp;+&nbsp;4:</entry>
+		      <entry>G<subscript>10</subscript></entry>
+		      <entry>B<subscript>11</subscript></entry>
+		      <entry>G<subscript>12</subscript></entry>
+		      <entry>B<subscript>13</subscript></entry>
+		    </row>
+		    <row>
+		      <entry>start&nbsp;+&nbsp;8:</entry>
+		      <entry>R<subscript>20</subscript></entry>
+		      <entry>G<subscript>21</subscript></entry>
+		      <entry>R<subscript>22</subscript></entry>
+		      <entry>G<subscript>23</subscript></entry>
+		    </row>
+		    <row>
+		      <entry>start&nbsp;+&nbsp;12:</entry>
+		      <entry>G<subscript>30</subscript></entry>
+		      <entry>B<subscript>31</subscript></entry>
+		      <entry>G<subscript>32</subscript></entry>
+		      <entry>B<subscript>33</subscript></entry>
+		    </row>
+		  </tbody>
+		</tgroup>
+	      </informaltable>
+	    </para>
+	  </formalpara>
+	</example>
+      </refsect1>
+    </refentry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt.xml	2011-01-04 19:50:19.000000000 -0500
@@ -566,7 +566,9 @@
     &sub-sbggr8;
     &sub-sgbrg8;
     &sub-sgrbg8;
+    &sub-srggb8;
     &sub-sbggr16;
+    &sub-srggb10;
   </section>
 
   <section id="yuv-formats">
@@ -589,6 +591,7 @@
 
     &sub-packed-yuv;
     &sub-grey;
+    &sub-y10;
     &sub-y16;
     &sub-yuyv;
     &sub-uyvy;
@@ -685,6 +688,11 @@
 kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm12</filename>
 </para></entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-CPIA1">
+	    <entry><constant>V4L2_PIX_FMT_CPIA1</constant></entry>
+	    <entry>'CPIA'</entry>
+	    <entry>YUV format used by the gspca cpia1 driver.</entry>
+	  </row>
 	  <row id="V4L2-PIX-FMT-SPCA501">
 	    <entry><constant>V4L2_PIX_FMT_SPCA501</constant></entry>
 	    <entry>'S501'</entry>
@@ -705,11 +713,6 @@
 	    <entry>'S561'</entry>
 	    <entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
 	  </row>
-	  <row id="V4L2-PIX-FMT-SGRBG10">
-	    <entry><constant>V4L2_PIX_FMT_SGRBG10</constant></entry>
-	    <entry>'DA10'</entry>
-	    <entry>10 bit raw Bayer, expanded to 16 bits.</entry>
-	  </row>
 	  <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
 	    <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
 	    <entry>'DB10'</entry>
@@ -770,6 +773,11 @@
 	    <entry>'S920'</entry>
 	    <entry>YUV 4:2:0 format of the gspca sn9c20x driver.</entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-SN9C2028">
+	    <entry><constant>V4L2_PIX_FMT_SN9C2028</constant></entry>
+	    <entry>'SONX'</entry>
+	    <entry>Compressed GBRG bayer format of the gspca sn9c2028 driver.</entry>
+	  </row>
 	  <row id="V4L2-PIX-FMT-STV0680">
 	    <entry><constant>V4L2_PIX_FMT_STV0680</constant></entry>
 	    <entry>'S680'</entry>
@@ -787,6 +795,20 @@
 	    <entry>'TM60'</entry>
 	    <entry><para>Used by Trident tm6000</para></entry>
 	  </row>
+	  <row id="V4L2-PIX-FMT-CIT-YYVYUY">
+	    <entry><constant>V4L2_PIX_FMT_CIT_YYVYUY</constant></entry>
+	    <entry>'CITV'</entry>
+	    <entry><para>Used by xirlink CIT, found at IBM webcams.</para>
+	           <para>Uses one line of Y then 1 line of VYUY</para>
+	    </entry>
+	  </row>
+	  <row id="V4L2-PIX-FMT-KONICA420">
+	    <entry><constant>V4L2_PIX_FMT_KONICA420</constant></entry>
+	    <entry>'KONI'</entry>
+	    <entry><para>Used by Konica webcams.</para>
+	           <para>YUV420 planar in blocks of 256 pixels.</para>
+	    </entry>
+	  </row>
 	  <row id="V4L2-PIX-FMT-YYUV">
 	    <entry><constant>V4L2_PIX_FMT_YYUV</constant></entry>
 	    <entry>'YYUV'</entry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-y10.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-y10.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/pixfmt-y10.xml	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/pixfmt-y10.xml	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,79 @@
+<refentry id="V4L2-PIX-FMT-Y10">
+  <refmeta>
+    <refentrytitle>V4L2_PIX_FMT_Y10 ('Y10 ')</refentrytitle>
+    &manvol;
+  </refmeta>
+  <refnamediv>
+    <refname><constant>V4L2_PIX_FMT_Y10</constant></refname>
+    <refpurpose>Grey-scale image</refpurpose>
+  </refnamediv>
+  <refsect1>
+    <title>Description</title>
+
+    <para>This is a grey-scale image with a depth of 10 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).</para>
+
+    <example>
+      <title><constant>V4L2_PIX_FMT_Y10</constant> 4 &times; 4
+pixel image</title>
+
+      <formalpara>
+	<title>Byte Order.</title>
+	<para>Each cell is one byte.
+	  <informaltable frame="none">
+	    <tgroup cols="9" align="center">
+	      <colspec align="left" colwidth="2*" />
+	      <tbody valign="top">
+		<row>
+		  <entry>start&nbsp;+&nbsp;0:</entry>
+		  <entry>Y'<subscript>00low</subscript></entry>
+		  <entry>Y'<subscript>00high</subscript></entry>
+		  <entry>Y'<subscript>01low</subscript></entry>
+		  <entry>Y'<subscript>01high</subscript></entry>
+		  <entry>Y'<subscript>02low</subscript></entry>
+		  <entry>Y'<subscript>02high</subscript></entry>
+		  <entry>Y'<subscript>03low</subscript></entry>
+		  <entry>Y'<subscript>03high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;8:</entry>
+		  <entry>Y'<subscript>10low</subscript></entry>
+		  <entry>Y'<subscript>10high</subscript></entry>
+		  <entry>Y'<subscript>11low</subscript></entry>
+		  <entry>Y'<subscript>11high</subscript></entry>
+		  <entry>Y'<subscript>12low</subscript></entry>
+		  <entry>Y'<subscript>12high</subscript></entry>
+		  <entry>Y'<subscript>13low</subscript></entry>
+		  <entry>Y'<subscript>13high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;16:</entry>
+		  <entry>Y'<subscript>20low</subscript></entry>
+		  <entry>Y'<subscript>20high</subscript></entry>
+		  <entry>Y'<subscript>21low</subscript></entry>
+		  <entry>Y'<subscript>21high</subscript></entry>
+		  <entry>Y'<subscript>22low</subscript></entry>
+		  <entry>Y'<subscript>22high</subscript></entry>
+		  <entry>Y'<subscript>23low</subscript></entry>
+		  <entry>Y'<subscript>23high</subscript></entry>
+		</row>
+		<row>
+		  <entry>start&nbsp;+&nbsp;24:</entry>
+		  <entry>Y'<subscript>30low</subscript></entry>
+		  <entry>Y'<subscript>30high</subscript></entry>
+		  <entry>Y'<subscript>31low</subscript></entry>
+		  <entry>Y'<subscript>31high</subscript></entry>
+		  <entry>Y'<subscript>32low</subscript></entry>
+		  <entry>Y'<subscript>32high</subscript></entry>
+		  <entry>Y'<subscript>33low</subscript></entry>
+		  <entry>Y'<subscript>33high</subscript></entry>
+		</row>
+	      </tbody>
+	    </tgroup>
+	  </informaltable>
+	</para>
+      </formalpara>
+    </example>
+  </refsect1>
+</refentry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/v4l2.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/v4l2.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/v4l2.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/v4l2.xml	2011-01-04 19:50:19.000000000 -0500
@@ -99,6 +99,7 @@
       <year>2007</year>
       <year>2008</year>
       <year>2009</year>
+      <year>2010</year>
       <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
 Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab</holder>
     </copyright>
@@ -110,10 +111,17 @@
       <!-- Put document revisions here, newest first. -->
       <!-- API revisions (changes and additions of defines, enums,
 structs, ioctls) must be noted in more detail in the history chapter
-(compat.sgml), along with the possible impact on existing drivers and
+(compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
       <revision>
+	<revnumber>2.6.37</revnumber>
+	<date>2010-08-06</date>
+	<authorinitials>hv</authorinitials>
+	<revremark>Removed obsolete vtx (videotext) API.</revremark>
+      </revision>
+
+      <revision>
 	<revnumber>2.6.33</revnumber>
 	<date>2009-12-03</date>
 	<authorinitials>mk</authorinitials>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/videodev2.h.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/videodev2.h.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/videodev2.h.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/videodev2.h.xml	2011-01-04 19:50:19.000000000 -0500
@@ -154,23 +154,13 @@
         V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
         V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
         V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
-#if 1 /*KEEP*/
+#if 1
         /* Experimental */
         V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
 #endif
         V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
 
-enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
-        V4L2_CTRL_TYPE_INTEGER       = 1,
-        V4L2_CTRL_TYPE_BOOLEAN       = 2,
-        V4L2_CTRL_TYPE_MENU          = 3,
-        V4L2_CTRL_TYPE_BUTTON        = 4,
-        V4L2_CTRL_TYPE_INTEGER64     = 5,
-        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
-        V4L2_CTRL_TYPE_STRING        = 7,
-};
-
 enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link> {
         V4L2_TUNER_RADIO             = 1,
         V4L2_TUNER_ANALOG_TV         = 2,
@@ -288,6 +278,7 @@
 #define <link linkend="V4L2-PIX-FMT-RGB565">V4L2_PIX_FMT_RGB565</link>  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
 #define <link linkend="V4L2-PIX-FMT-RGB555X">V4L2_PIX_FMT_RGB555X</link> v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
 #define <link linkend="V4L2-PIX-FMT-RGB565X">V4L2_PIX_FMT_RGB565X</link> v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
+#define <link linkend="V4L2-PIX-FMT-BGR666">V4L2_PIX_FMT_BGR666</link>  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6     */
 #define <link linkend="V4L2-PIX-FMT-BGR24">V4L2_PIX_FMT_BGR24</link>   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
 #define <link linkend="V4L2-PIX-FMT-RGB24">V4L2_PIX_FMT_RGB24</link>   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
 #define <link linkend="V4L2-PIX-FMT-BGR32">V4L2_PIX_FMT_BGR32</link>   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
@@ -295,6 +286,9 @@
 
 /* Grey formats */
 #define <link linkend="V4L2-PIX-FMT-GREY">V4L2_PIX_FMT_GREY</link>    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y4">V4L2_PIX_FMT_Y4</link>      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y6">V4L2_PIX_FMT_Y6</link>      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
+#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link>     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
 #define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link>     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 
 /* Palette formats */
@@ -330,7 +324,11 @@
 #define <link linkend="V4L2-PIX-FMT-SBGGR8">V4L2_PIX_FMT_SBGGR8</link>  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
 #define <link linkend="V4L2-PIX-FMT-SGBRG8">V4L2_PIX_FMT_SGBRG8</link>  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
 #define <link linkend="V4L2-PIX-FMT-SGRBG8">V4L2_PIX_FMT_SGRBG8</link>  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
-#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */
+#define <link linkend="V4L2-PIX-FMT-SRGGB8">V4L2_PIX_FMT_SRGGB8</link>  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
+#define <link linkend="V4L2-PIX-FMT-SBGGR10">V4L2_PIX_FMT_SBGGR10</link> v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
+#define <link linkend="V4L2-PIX-FMT-SGBRG10">V4L2_PIX_FMT_SGBRG10</link> v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
+#define <link linkend="V4L2-PIX-FMT-SGRBG10">V4L2_PIX_FMT_SGRBG10</link> v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
+#define <link linkend="V4L2-PIX-FMT-SRGGB10">V4L2_PIX_FMT_SRGGB10</link> v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
         /* 10bit raw bayer DPCM compressed to 8 bits */
 #define <link linkend="V4L2-PIX-FMT-SGRBG10DPCM8">V4L2_PIX_FMT_SGRBG10DPCM8</link> v4l2_fourcc('B', 'D', '1', '0')
         /*
@@ -346,6 +344,7 @@
 #define <link linkend="V4L2-PIX-FMT-MPEG">V4L2_PIX_FMT_MPEG</link>     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4    */
 
 /*  Vendor-specific formats   */
+#define <link linkend="V4L2-PIX-FMT-CPIA1">V4L2_PIX_FMT_CPIA1</link>    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
 #define <link linkend="V4L2-PIX-FMT-WNVA">V4L2_PIX_FMT_WNVA</link>     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
 #define <link linkend="V4L2-PIX-FMT-SN9C10X">V4L2_PIX_FMT_SN9C10X</link>  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
 #define <link linkend="V4L2-PIX-FMT-SN9C20X-I420">V4L2_PIX_FMT_SN9C20X_I420</link> v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
@@ -358,12 +357,15 @@
 #define <link linkend="V4L2-PIX-FMT-SPCA561">V4L2_PIX_FMT_SPCA561</link>  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
 #define <link linkend="V4L2-PIX-FMT-PAC207">V4L2_PIX_FMT_PAC207</link>   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
 #define <link linkend="V4L2-PIX-FMT-MR97310A">V4L2_PIX_FMT_MR97310A</link> v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define <link linkend="V4L2-PIX-FMT-SN9C2028">V4L2_PIX_FMT_SN9C2028</link> v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
 #define <link linkend="V4L2-PIX-FMT-SQ905C">V4L2_PIX_FMT_SQ905C</link>   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define <link linkend="V4L2-PIX-FMT-PJPG">V4L2_PIX_FMT_PJPG</link>     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
 #define <link linkend="V4L2-PIX-FMT-OV511">V4L2_PIX_FMT_OV511</link>    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
 #define <link linkend="V4L2-PIX-FMT-OV518">V4L2_PIX_FMT_OV518</link>    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
-#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
 #define <link linkend="V4L2-PIX-FMT-STV0680">V4L2_PIX_FMT_STV0680</link>  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define <link linkend="V4L2-PIX-FMT-TM6000">V4L2_PIX_FMT_TM6000</link>   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define <link linkend="V4L2-PIX-FMT-CIT-YYVYUY">V4L2_PIX_FMT_CIT_YYVYUY</link> v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define <link linkend="V4L2-PIX-FMT-KONICA420">V4L2_PIX_FMT_KONICA420</link>  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
 
 /*
  *      F O R M A T   E N U M E R A T I O N
@@ -380,7 +382,7 @@
 #define V4L2_FMT_FLAG_COMPRESSED 0x0001
 #define V4L2_FMT_FLAG_EMULATED   0x0002
 
-#if 1 /*KEEP*/
+#if 1
         /* Experimental Frame Size and frame rate enumeration */
 /*
  *      F R A M E   S I Z E   E N U M E R A T I O N
@@ -544,6 +546,8 @@
 #define V4L2_BUF_FLAG_KEYFRAME  0x0008  /* Image is a keyframe (I-frame) */
 #define V4L2_BUF_FLAG_PFRAME    0x0010  /* Image is a P-frame */
 #define V4L2_BUF_FLAG_BFRAME    0x0020  /* Image is a B-frame */
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR     0x0040
 #define V4L2_BUF_FLAG_TIMECODE  0x0100  /* timecode field is valid */
 #define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
 
@@ -934,6 +938,16 @@
 #define V4L2_CTRL_ID2CLASS(id)    ((id) &amp; 0x0fff0000UL)
 #define V4L2_CTRL_DRIVER_PRIV(id) (((id) &amp; 0xffff) &gt;= 0x1000)
 
+enum <link linkend="v4l2-ctrl-type">v4l2_ctrl_type</link> {
+        V4L2_CTRL_TYPE_INTEGER       = 1,
+        V4L2_CTRL_TYPE_BOOLEAN       = 2,
+        V4L2_CTRL_TYPE_MENU          = 3,
+        V4L2_CTRL_TYPE_BUTTON        = 4,
+        V4L2_CTRL_TYPE_INTEGER64     = 5,
+        V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+        V4L2_CTRL_TYPE_STRING        = 7,
+};
+
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
 struct <link linkend="v4l2-queryctrl">v4l2_queryctrl</link> {
         __u32                id;
@@ -1018,21 +1032,27 @@
         V4L2_COLORFX_NONE       = 0,
         V4L2_COLORFX_BW         = 1,
         V4L2_COLORFX_SEPIA      = 2,
-        V4L2_COLORFX_NEGATIVE   = 3,
-        V4L2_COLORFX_EMBOSS     = 4,
-        V4L2_COLORFX_SKETCH     = 5,
-        V4L2_COLORFX_SKY_BLUE   = 6,
+        V4L2_COLORFX_NEGATIVE = 3,
+        V4L2_COLORFX_EMBOSS = 4,
+        V4L2_COLORFX_SKETCH = 5,
+        V4L2_COLORFX_SKY_BLUE = 6,
         V4L2_COLORFX_GRASS_GREEN = 7,
         V4L2_COLORFX_SKIN_WHITEN = 8,
-        V4L2_COLORFX_VIVID      = 9.
+        V4L2_COLORFX_VIVID = 9,
 };
 #define V4L2_CID_AUTOBRIGHTNESS                 (V4L2_CID_BASE+32)
 #define V4L2_CID_BAND_STOP_FILTER               (V4L2_CID_BASE+33)
 
 #define V4L2_CID_ROTATE                         (V4L2_CID_BASE+34)
 #define V4L2_CID_BG_COLOR                       (V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
+
+#define V4L2_CID_ILLUMINATORS_1                 (V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2                 (V4L2_CID_BASE+38)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+36)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE                      (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1349,6 +1369,8 @@
 #define V4L2_TUNER_CAP_SAP              0x0020
 #define V4L2_TUNER_CAP_LANG1            0x0040
 #define V4L2_TUNER_CAP_RDS              0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO     0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS     0x0200
 
 /*  Flags for the 'rxsubchans' field */
 #define V4L2_TUNER_SUB_MONO             0x0001
@@ -1378,7 +1400,8 @@
         enum <link linkend="v4l2-tuner-type">v4l2_tuner_type</link>  type;
         __u32                 seek_upward;
         __u32                 wrap_around;
-        __u32                 reserved[8];
+        __u32                 spacing;
+        __u32                 reserved[7];
 };
 
 /*
@@ -1433,7 +1456,7 @@
  *
  *      NOTE: EXPERIMENTAL API
  */
-#if 1 /*KEEP*/
+#if 1
 #define V4L2_ENC_IDX_FRAME_I    (0)
 #define V4L2_ENC_IDX_FRAME_P    (1)
 #define V4L2_ENC_IDX_FRAME_B    (2)
@@ -1626,6 +1649,38 @@
 };
 
 /*
+ *      E V E N T S
+ */
+
+#define V4L2_EVENT_ALL                          0
+#define V4L2_EVENT_VSYNC                        1
+#define V4L2_EVENT_EOS                          2
+#define V4L2_EVENT_PRIVATE_START                0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> {
+        /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+        __u8 field;
+} __attribute__ ((packed));
+
+struct <link linkend="v4l2-event">v4l2_event</link> {
+        __u32                           type;
+        union {
+                struct <link linkend="v4l2-event-vsync">v4l2_event_vsync</link> vsync;
+                __u8                    data[64];
+        } u;
+        __u32                           pending;
+        __u32                           sequence;
+        struct timespec                 timestamp;
+        __u32                           reserved[9];
+};
+
+struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link> {
+        __u32                           type;
+        __u32                           reserved[7];
+};
+
+/*
  *      A D V A N C E D   D E B U G G I N G
  *
  *      NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
@@ -1720,7 +1775,7 @@
 #define VIDIOC_G_EXT_CTRLS      _IOWR('V', 71, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
 #define VIDIOC_S_EXT_CTRLS      _IOWR('V', 72, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
 #define VIDIOC_TRY_EXT_CTRLS    _IOWR('V', 73, struct <link linkend="v4l2-ext-controls">v4l2_ext_controls</link>)
-#if 1 /*KEEP*/
+#if 1
 #define VIDIOC_ENUM_FRAMESIZES  _IOWR('V', 74, struct <link linkend="v4l2-frmsizeenum">v4l2_frmsizeenum</link>)
 #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct <link linkend="v4l2-frmivalenum">v4l2_frmivalenum</link>)
 #define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct <link linkend="v4l2-enc-idx">v4l2_enc_idx</link>)
@@ -1728,7 +1783,7 @@
 #define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct <link linkend="v4l2-encoder-cmd">v4l2_encoder_cmd</link>)
 #endif
 
-#if 1 /*KEEP*/
+#if 1
 /* Experimental, meant for debugging, testing and internal use.
    Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
    You must be root to use these ioctls. Never use these in applications! */
@@ -1747,6 +1802,9 @@
 #define VIDIOC_QUERY_DV_PRESET  _IOR('V',  86, struct <link linkend="v4l2-dv-preset">v4l2_dv_preset</link>)
 #define VIDIOC_S_DV_TIMINGS     _IOWR('V', 87, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
 #define VIDIOC_G_DV_TIMINGS     _IOWR('V', 88, struct <link linkend="v4l2-dv-timings">v4l2_dv_timings</link>)
+#define VIDIOC_DQEVENT           _IOR('V', 89, struct <link linkend="v4l2-event">v4l2_event</link>)
+#define VIDIOC_SUBSCRIBE_EVENT   _IOW('V', 90, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct <link linkend="v4l2-event-subscription">v4l2_event_subscription</link>)
 
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml	2011-01-04 19:50:19.000000000 -0500
@@ -16,8 +16,7 @@
 	<funcdef>int <function>ioctl</function></funcdef>
 	<paramdef>int <parameter>fd</parameter></paramdef>
 	<paramdef>int <parameter>request</parameter></paramdef>
-	<paramdef>&v4l2-dv-preset;
-*<parameter>argp</parameter></paramdef>
+	<paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml	2011-01-04 19:50:19.000000000 -0500
@@ -16,8 +16,7 @@
 	<funcdef>int <function>ioctl</function></funcdef>
 	<paramdef>int <parameter>fd</parameter></paramdef>
 	<paramdef>int <parameter>request</parameter></paramdef>
-	<paramdef>&v4l2-dv-timings;
-*<parameter>argp</parameter></paramdef>
+	<paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-querycap.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-querycap.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-querycap.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-querycap.xml	2011-01-04 19:50:19.000000000 -0500
@@ -184,7 +184,7 @@
 	  <row>
 	    <entry><constant>V4L2_CAP_RDS_CAPTURE</constant></entry>
 	    <entry>0x00000100</entry>
-	    <entry>The device supports the <link linkend="rds">RDS</link> interface.</entry>
+	    <entry>The device supports the <link linkend="rds">RDS</link> capture interface.</entry>
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CAP_VIDEO_OUTPUT_OVERLAY</constant></entry>
@@ -206,6 +206,11 @@
 hardware frequency seeking.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CAP_RDS_OUTPUT</constant></entry>
+	    <entry>0x00000800</entry>
+	    <entry>The device supports the <link linkend="rds">RDS</link> output interface.</entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CAP_TUNER</constant></entry>
 	    <entry>0x00010000</entry>
 	    <entry>The device has some sort of tuner to
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-queryctrl.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-queryctrl.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-queryctrl.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-queryctrl.xml	2011-01-04 19:50:19.000000000 -0500
@@ -103,8 +103,12 @@
 <structfield>index</structfield> is invalid. Menu items are enumerated
 by calling <constant>VIDIOC_QUERYMENU</constant> with successive
 <structfield>index</structfield> values from &v4l2-queryctrl;
-<structfield>minimum</structfield> (0) to
-<structfield>maximum</structfield>, inclusive.</para>
+<structfield>minimum</structfield> to
+<structfield>maximum</structfield>, inclusive. Note that it is possible
+for <constant>VIDIOC_QUERYMENU</constant> to return an &EINVAL; for some
+indices between <structfield>minimum</structfield> and <structfield>maximum</structfield>.
+In that case that particular menu item is not supported by this driver. Also note that
+the <structfield>minimum</structfield> value is not necessarily 0.</para>
 
     <para>See also the examples in <xref linkend="control" />.</para>
 
@@ -139,7 +143,7 @@
 	    <entry><structfield>minimum</structfield></entry>
 	    <entry>Minimum value, inclusive. This field gives a lower
 bound for <constant>V4L2_CTRL_TYPE_INTEGER</constant> controls and the
-lowest valid index (always 0) for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
+lowest valid index for <constant>V4L2_CTRL_TYPE_MENU</constant> controls.
 For <constant>V4L2_CTRL_TYPE_STRING</constant> controls the minimum value
 gives the minimum length of the string. This length <emphasis>does not include the terminating
 zero</emphasis>. It may not be valid for any other type of control, including
@@ -279,7 +283,7 @@
 	  </row>
 	  <row>
 	    <entry><constant>V4L2_CTRL_TYPE_MENU</constant></entry>
-	    <entry>0</entry>
+	    <entry>&ge; 0</entry>
 	    <entry>1</entry>
 	    <entry>N-1</entry>
 	    <entry>The control has a menu of N choices. The names of
@@ -405,8 +409,10 @@
 	<term><errorcode>EINVAL</errorcode></term>
 	<listitem>
 	  <para>The &v4l2-queryctrl; <structfield>id</structfield>
-is invalid. The &v4l2-querymenu; <structfield>id</structfield> or
-<structfield>index</structfield> is invalid.</para>
+is invalid. The &v4l2-querymenu; <structfield>id</structfield> is
+invalid or <structfield>index</structfield> is out of range (less than
+<structfield>minimum</structfield> or greater than <structfield>maximum</structfield>)
+or this particular menu item is not supported by the driver.</para>
 	</listitem>
       </varlistentry>
       <varlistentry>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,7 @@
 	<funcdef>int <function>ioctl</function></funcdef>
 	<paramdef>int <parameter>fd</parameter></paramdef>
 	<paramdef>int <parameter>request</parameter></paramdef>
-	<paramdef>&v4l2-dv-preset; *<parameter>argp</parameter></paramdef>
+	<paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
diff -druN linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
--- linux-libre-2.6.36-gnu/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml	2011-01-04 19:50:19.000000000 -0500
@@ -51,7 +51,8 @@
 
     <para>Start a hardware frequency seek from the current frequency.
 To do this applications initialize the <structfield>tuner</structfield>,
-<structfield>type</structfield>, <structfield>seek_upward</structfield> and
+<structfield>type</structfield>, <structfield>seek_upward</structfield>,
+<structfield>spacing</structfield> and
 <structfield>wrap_around</structfield> fields, and zero out the
 <structfield>reserved</structfield> array of a &v4l2-hw-freq-seek; and
 call the <constant>VIDIOC_S_HW_FREQ_SEEK</constant> ioctl with a pointer
@@ -89,7 +90,12 @@
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry><structfield>spacing</structfield></entry>
+	    <entry>If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[7]</entry>
 	    <entry>Reserved for future extensions. Drivers and
 	    applications must set the array to zero.</entry>
 	  </row>
diff -druN linux-libre-2.6.36-gnu/Documentation/driver-model/interface.txt linux-libre-2.6.37-gnu/Documentation/driver-model/interface.txt
--- linux-libre-2.6.36-gnu/Documentation/driver-model/interface.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/driver-model/interface.txt	1969-12-31 19:00:00.000000000 -0500
@@ -1,129 +0,0 @@
-
-Device Interfaces
-
-Introduction
-~~~~~~~~~~~~
-
-Device interfaces are the logical interfaces of device classes that correlate
-directly to userspace interfaces, like device nodes. 
-   
-Each device class may have multiple interfaces through which you can 
-access the same device. An input device may support the mouse interface, 
-the 'evdev' interface, and the touchscreen interface. A SCSI disk would 
-support the disk interface, the SCSI generic interface, and possibly a raw 
-device interface. 
-
-Device interfaces are registered with the class they belong to. As devices
-are added to the class, they are added to each interface registered with
-the class. The interface is responsible for determining whether the device
-supports the interface or not. 
-
-
-Programming Interface
-~~~~~~~~~~~~~~~~~~~~~
-
-struct device_interface {
-	char			* name;
-	rwlock_t		lock;
-	u32			devnum;
-	struct device_class	* devclass;
-
-	struct list_head	node;
-	struct driver_dir_entry	dir;
-
-	int (*add_device)(struct device *);
-	int (*add_device)(struct intf_data *);
-};
-
-int interface_register(struct device_interface *);
-void interface_unregister(struct device_interface *);
-
-
-An interface must specify the device class it belongs to. It is added
-to that class's list of interfaces on registration.
-
-
-Interfaces can be added to a device class at any time. Whenever it is
-added, each device in the class is passed to the interface's
-add_device callback. When an interface is removed, each device is
-removed from the interface.
-
-
-Devices
-~~~~~~~
-Once a device is added to a device class, it is added to each
-interface that is registered with the device class. The class
-is expected to place a class-specific data structure in 
-struct device::class_data. The interface can use that (along with
-other fields of struct device) to determine whether or not the driver
-and/or device support that particular interface.
-
-
-Data
-~~~~
-
-struct intf_data {
-	struct list_head	node;
-	struct device_interface	* intf;
-	struct device 		* dev;
-	u32			intf_num;
-};
-
-int interface_add_data(struct interface_data *);
-
-The interface is responsible for allocating and initializing a struct 
-intf_data and calling interface_add_data() to add it to the device's list
-of interfaces it belongs to. This list will be iterated over when the device
-is removed from the class (instead of all possible interfaces for a class).
-This structure should probably be embedded in whatever per-device data 
-structure the interface is allocating anyway.
-   
-Devices are enumerated within the interface. This happens in interface_add_data()
-and the enumerated value is stored in the struct intf_data for that device. 
-
-sysfs
-~~~~~
-Each interface is given a directory in the directory of the device
-class it belongs to:
-
-Interfaces get a directory in the class's directory as well:
-
-   class/
-   `-- input
-       |-- devices
-       |-- drivers
-       |-- mouse
-       `-- evdev
-
-When a device is added to the interface, a symlink is created that points 
-to the device's directory in the physical hierarchy:
-
-   class/
-   `-- input
-       |-- devices
-       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
-       |-- drivers
-       |   `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
-       |-- mouse
-       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
-       `-- evdev
-           `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
-
-
-Future Plans
-~~~~~~~~~~~~
-A device interface is correlated directly with a userspace interface
-for a device, specifically a device node. For instance, a SCSI disk
-exposes at least two interfaces to userspace: the standard SCSI disk
-interface and the SCSI generic interface. It might also export a raw
-device interface. 
-
-Many interfaces have a major number associated with them and each
-device gets a minor number. Or, multiple interfaces might share one
-major number, and each will receive a range of minor numbers (like in
-the case of input devices).
-
-These major and minor numbers could be stored in the interface
-structure. Major and minor allocations could happen when the interface
-is registered with the class, or via a helper function. 
-
diff -druN linux-libre-2.6.36-gnu/Documentation/dynamic-debug-howto.txt linux-libre-2.6.37-gnu/Documentation/dynamic-debug-howto.txt
--- linux-libre-2.6.36-gnu/Documentation/dynamic-debug-howto.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/dynamic-debug-howto.txt	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,7 @@
    read to display the complete list of known debug statements, to help guide you
 
 Controlling dynamic debug Behaviour
-===============================
+===================================
 
 The behaviour of pr_debug()/dev_debug()s are controlled via writing to a
 control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs
@@ -212,6 +212,26 @@
 Note also that there is no convenient syntax to remove all
 the flags at once, you need to use "-psc".
 
+
+Debug messages during boot process
+==================================
+
+To be able to activate debug messages during the boot process,
+even before userspace and debugfs exists, use the boot parameter:
+ddebug_query="QUERY"
+
+QUERY follows the syntax described above, but must not exceed 1023
+characters. The enablement of debug messages is done as an arch_initcall.
+Thus you can enable debug messages in all code processed after this
+arch_initcall via this boot parameter.
+On an x86 system for example ACPI enablement is a subsys_initcall and
+ddebug_query="file ec.c +p"
+will show early Embedded Controller transactions during ACPI setup if
+your machine (typically a laptop) has an Embedded Controller.
+PCI (or other devices) initialization also is a hot candidate for using
+this boot parameter for debugging purposes.
+
+
 Examples
 ========
 
diff -druN linux-libre-2.6.36-gnu/Documentation/edac.txt linux-libre-2.6.37-gnu/Documentation/edac.txt
--- linux-libre-2.6.36-gnu/Documentation/edac.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/edac.txt	2011-01-04 19:50:19.000000000 -0500
@@ -196,7 +196,7 @@
 The representation of the above is reflected in the directory tree
 in EDAC's sysfs interface. Starting in directory
 /sys/devices/system/edac/mc each memory controller will be represented
-by its own 'mcX' directory, where 'X" is the index of the MC.
+by its own 'mcX' directory, where 'X' is the index of the MC.
 
 
 	..../edac/mc/
@@ -207,7 +207,7 @@
 		   ....
 
 Under each 'mcX' directory each 'csrowX' is again represented by a
-'csrowX', where 'X" is the csrow index:
+'csrowX', where 'X' is the csrow index:
 
 
 	.../mc/mc0/
@@ -232,7 +232,7 @@
 
 
 In 'mcX' directories are EDAC control and attribute files for
-this 'X" instance of the memory controllers:
+this 'X' instance of the memory controllers:
 
 
 Counter reset control file:
@@ -343,7 +343,7 @@
 'csrowX' DIRECTORIES
 
 In the 'csrowX' directories are EDAC control and attribute files for
-this 'X" instance of csrow:
+this 'X' instance of csrow:
 
 
 Total Uncorrectable Errors count attribute file:
diff -druN linux-libre-2.6.36-gnu/Documentation/fb/00-INDEX linux-libre-2.6.37-gnu/Documentation/fb/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/fb/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/fb/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -4,33 +4,41 @@
 				    Geert Uytterhoeven <geert@linux-m68k.org>
 
 00-INDEX
-	- this file
+	- this file.
 arkfb.txt
 	- info on the fbdev driver for ARK Logic chips.
 aty128fb.txt
 	- info on the ATI Rage128 frame buffer driver.
 cirrusfb.txt
 	- info on the driver for Cirrus Logic chipsets.
+cmap_xfbdev.txt
+	- an introduction to fbdev's cmap structures.
 deferred_io.txt
 	- an introduction to deferred IO.
+efifb.txt
+	- info on the EFI platform driver for Intel based Apple computers.
+ep93xx-fb.txt
+	- info on the driver for EP93xx LCD controller.
 fbcon.txt
 	- intro to and usage guide for the framebuffer console (fbcon).
 framebuffer.txt
 	- introduction to frame buffer devices.
-imacfb.txt
-	- info on the generic EFI platform driver for Intel based Macs.
+gxfb.txt
+	- info on the framebuffer driver for AMD Geode GX2 based processors.
 intel810.txt
 	- documentation for the Intel 810/815 framebuffer driver.
 intelfb.txt
 	- docs for Intel 830M/845G/852GM/855GM/865G/915G/945G fb driver.
 internals.txt
 	- quick overview of frame buffer device internals.
+lxfb.txt
+	- info on the framebuffer driver for AMD Geode LX based processors.
 matroxfb.txt
 	- info on the Matrox framebuffer driver for Alpha, Intel and PPC.
+metronomefb.txt
+	- info on the driver for the Metronome display controller.
 modedb.txt
 	- info on the video mode database.
-matroxfb.txt
-	- info on the Matrox frame buffer driver.
 pvr2fb.txt
 	- info on the PowerVR 2 frame buffer driver.
 pxafb.txt
@@ -39,13 +47,23 @@
 	- info on the fbdev driver for S3 Trio/Virge chips.
 sa1100fb.txt
 	- information about the driver for the SA-1100 LCD controller.
+sh7760fb.txt
+	- info on the SH7760/SH7763 integrated LCDC Framebuffer driver.
 sisfb.txt
 	- info on the framebuffer device driver for various SiS chips.
 sstfb.txt
 	- info on the frame buffer driver for 3dfx' Voodoo Graphics boards.
 tgafb.txt
-	- info on the TGA (DECChip 21030) frame buffer driver
+	- info on the TGA (DECChip 21030) frame buffer driver.
+tridentfb.txt
+	info on the framebuffer driver for some Trident chip based cards.
+uvesafb.txt
+	- info on the userspace VESA (VBE2+ compliant) frame buffer device.
 vesafb.txt
-	- info on the VESA frame buffer device
+	- info on the VESA frame buffer device.
+viafb.modes
+	- list of modes for VIA Integration Graphic Chip.
+viafb.txt
+	- info on the VIA Integration Graphic Chip console framebuffer driver.
 vt8623fb.txt
 	- info on the fb driver for the graphics core in VIA VT8623 chipsets.
diff -druN linux-libre-2.6.36-gnu/Documentation/fb/viafb.txt linux-libre-2.6.37-gnu/Documentation/fb/viafb.txt
--- linux-libre-2.6.36-gnu/Documentation/fb/viafb.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/fb/viafb.txt	2011-01-04 19:50:19.000000000 -0500
@@ -197,6 +197,54 @@
        example,
            # fbset -depth 16
 
+
+[Configure viafb via /proc]
+---------------------------
+    The following files exist in /proc/viafb
+
+    supported_output_devices
+
+        This read-only file contains a full ',' seperated list containing all
+        output devices that could be available on your platform. It is likely
+        that not all of those have a connector on your hardware but it should
+        provide a good starting point to figure out which of those names match
+        a real connector.
+        Example:
+        # cat /proc/viafb/supported_output_devices
+
+    iga1/output_devices
+    iga2/output_devices
+
+        These two files are readable and writable. iga1 and iga2 are the two
+        independent units that produce the screen image. Those images can be
+        forwarded to one or more output devices. Reading those files is a way
+        to query which output devices are currently used by an iga.
+        Example:
+        # cat /proc/viafb/iga1/output_devices
+        If there are no output devices printed the output of this iga is lost.
+        This can happen for example if only one (the other) iga is used.
+        Writing to these files allows adjusting the output devices during
+        runtime. One can add new devices, remove existing ones or switch
+        between igas. Essentially you can write a ',' seperated list of device
+        names (or a single one) in the same format as the output to those
+        files. You can add a '+' or '-' as a prefix allowing simple addition
+        and removal of devices. So a prefix '+' adds the devices from your list
+        to the already existing ones, '-' removes the listed devices from the
+        existing ones and if no prefix is given it replaces all existing ones
+        with the listed ones. If you remove devices they are expected to turn
+        off. If you add devices that are already part of the other iga they are
+        removed there and added to the new one.
+        Examples:
+        Add CRT as output device to iga1
+        # echo +CRT > /proc/viafb/iga1/output_devices
+
+        Remove (turn off) DVP1 and LVDS1 as output devices of iga2
+        # echo -DVP1,LVDS1 > /proc/viafb/iga2/output_devices
+
+        Replace all iga1 output devices by CRT
+        # echo CRT > /proc/viafb/iga1/output_devices
+
+
 [Bootup with viafb]:
 --------------------
     Add the following line to your grub.conf:
diff -druN linux-libre-2.6.36-gnu/Documentation/feature-removal-schedule.txt linux-libre-2.6.37-gnu/Documentation/feature-removal-schedule.txt
--- linux-libre-2.6.36-gnu/Documentation/feature-removal-schedule.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/feature-removal-schedule.txt	2011-01-04 19:50:19.000000000 -0500
@@ -98,7 +98,7 @@
 ---------------------------
 
 What:	Video4Linux API 1 ioctls and from Video devices.
-When:	July 2009
+When:	kernel 2.6.38
 Files:	include/linux/videodev.h
 Check:	include/linux/videodev.h
 Why:	V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
@@ -116,6 +116,21 @@
 
 ---------------------------
 
+What:	Video4Linux obsolete drivers using V4L1 API
+When:	kernel 2.6.38
+Files:	drivers/staging/cpia/* drivers/staging/stradis/*
+Check:	drivers/staging/cpia/cpia.c drivers/staging/stradis/stradis.c
+Why:	There are some drivers still using V4L1 API, despite all efforts we've done
+	to migrate. Those drivers are for obsolete hardware that the old maintainer
+	didn't care (or not have the hardware anymore), and that no other developer
+	could find any hardware to buy. They probably have no practical usage today,
+	and people with such old hardware could probably keep using an older version
+	of the kernel. Those drivers will be moved to staging on 2.6.37 and, if nobody
+	care enough to port and test them with V4L2 API, they'll be removed on 2.6.38.
+Who:	Mauro Carvalho Chehab <mchehab@infradead.org>
+
+---------------------------
+
 What:	sys_sysctl
 When:	September 2010
 Option: CONFIG_SYSCTL_SYSCALL
@@ -386,34 +401,6 @@
 
 ----------------------------
 
-What:	Support for VMware's guest paravirtuliazation technique [VMI] will be
-	dropped.
-When:	2.6.37 or earlier.
-Why:	With the recent innovations in CPU hardware acceleration technologies
-	from Intel and AMD, VMware ran a few experiments to compare these
-	techniques to guest paravirtualization technique on VMware's platform.
-	These hardware assisted virtualization techniques have outperformed the
-	performance benefits provided by VMI in most of the workloads. VMware
-	expects that these hardware features will be ubiquitous in a couple of
-	years, as a result, VMware has started a phased retirement of this
-	feature from the hypervisor. We will be removing this feature from the
-	Kernel too. Right now we are targeting 2.6.37 but can retire earlier if
-	technical reasons (read opportunity to remove major chunk of pvops)
-	arise.
-
-	Please note that VMI has always been an optimization and non-VMI kernels
-	still work fine on VMware's platform.
-	Latest versions of VMware's product which support VMI are,
-	Workstation 7.0 and VSphere 4.0 on ESX side, future maintainence
-	releases for these products will continue supporting VMI.
-
-	For more details about VMI retirement take a look at this,
-	http://blogs.vmware.com/guestosguide/2009/09/vmi-retirement.html
-
-Who:	Alok N Kataria <akataria@vmware.com>
-
-----------------------------
-
 What:	Support for lcd_switch and display_get in asus-laptop driver
 When:	March 2010
 Why:	These two features use non-standard interfaces. There are the
@@ -498,29 +485,6 @@
 Why:	Superseded by xt_CT
 Who:	Netfilter developer team <netfilter-devel@vger.kernel.org>
 
----------------------------
-
-What:	video4linux /dev/vtx teletext API support
-When:	2.6.35
-Files:	drivers/media/video/saa5246a.c drivers/media/video/saa5249.c
-	include/linux/videotext.h
-Why:	The vtx device nodes have been superseded by vbi device nodes
-	for many years. No applications exist that use the vtx support.
-	Of the two i2c drivers that actually support this API the saa5249
-	has been impossible to use for a year now and no known hardware
-	that supports this device exists. The saa5246a is theoretically
-	supported by the old mxb boards, but it never actually worked.
-
-	In summary: there is no hardware that can use this API and there
-	are no applications actually implementing this API.
-
-	The vtx support still reserves minors 192-223 and we would really
-	like to reuse those for upcoming new functionality. In the unlikely
-	event that new hardware appears that wants to use the functionality
-	provided by the vtx API, then that functionality should be build
-	around the sliced VBI API instead.
-Who:	Hans Verkuil <hverkuil@xs4all.nl>
-
 ----------------------------
 
 What:	IRQF_DISABLED
@@ -530,16 +494,6 @@
 
 ----------------------------
 
-What:	old ieee1394 subsystem (CONFIG_IEEE1394)
-When:	2.6.37
-Files:	drivers/ieee1394/ except init_ohci1394_dma.c
-Why:	superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
-	features, better performance, and better security, all with smaller
-	and more modern code base
-Who:	Stefan Richter <stefanr@s5r6.in-berlin.de>
-
-----------------------------
-
 What:	The acpi_sleep=s4_nonvs command line option
 When:	2.6.37
 Files:	arch/x86/kernel/acpi/sleep.c
@@ -564,3 +518,49 @@
 
 ----------------------------
 
+What:   namespace cgroup (ns_cgroup)
+When:   2.6.38
+Why:    The ns_cgroup leads to some problems:
+	* cgroup creation is out-of-control
+	* cgroup name can conflict when pids are looping
+	* it is not possible to have a single process handling
+	a lot of namespaces without falling in a exponential creation time
+	* we may want to create a namespace without creating a cgroup
+
+	The ns_cgroup is replaced by a compatibility flag 'clone_children',
+	where a newly created cgroup will copy the parent cgroup values.
+	The userspace has to manually create a cgroup and add a task to
+	the 'tasks' file.
+Who:    Daniel Lezcano <daniel.lezcano@free.fr>
+
+----------------------------
+
+What:	iwlwifi disable_hw_scan module parameters
+When:	2.6.40
+Why:	Hareware scan is the prefer method for iwlwifi devices for
+	scanning operation. Remove software scan support for all the
+	iwlwifi devices.
+
+Who:	Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+----------------------------
+
+What:   access to nfsd auth cache through sys_nfsservctl or '.' files
+        in the 'nfsd' filesystem.
+When:   2.6.40
+Why:    This is a legacy interface which have been replaced by a more
+        dynamic cache.  Continuing to maintain this interface is an
+        unnecessary burden.
+Who:    NeilBrown <neilb@suse.de>
+
+----------------------------
+
+What:	i2c_adapter.id
+When:	June 2011
+Why:	This field is deprecated. I2C device drivers shouldn't change their
+	behavior based on the underlying I2C adapter. Instead, the I2C
+	adapter driver should instantiate the I2C devices and provide the
+	needed platform-specific information.
+Who:	Jean Delvare <khali@linux-fr.org>
+
+----------------------------
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/00-INDEX linux-libre-2.6.37-gnu/Documentation/filesystems/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/filesystems/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -96,8 +96,6 @@
 	- how to use the seq_file API
 sharedsubtree.txt
 	- a description of shared subtrees for namespaces.
-smbfs.txt
-	- info on using filesystems with the SMB protocol (Win 3.11 and NT).
 spufs.txt
 	- info and mount options for the SPU filesystem used on Cell.
 sysfs-pci.txt
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/9p.txt linux-libre-2.6.37-gnu/Documentation/filesystems/9p.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/9p.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/9p.txt	2011-01-04 19:50:19.000000000 -0500
@@ -111,7 +111,7 @@
   		This can be used to share devices/named pipes/sockets between
 		hosts.  This functionality will be expanded in later versions.
 
-  access	there are three access modes.
+  access	there are four access modes.
 			user  = if a user tries to access a file on v9fs
 			        filesystem for the first time, v9fs sends an
 			        attach command (Tattach) for that user.
@@ -120,6 +120,8 @@
 				the files on the mounted filesystem
 			any   = v9fs does single attach and performs all
 				operations as one user
+			client = ACL based access check on the 9p client
+			         side for access validation
 
   cachetag	cache tag to use the specified persistent cache.
 		cache tags for existing cache sessions can be listed at
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/configfs/configfs_example_explicit.c linux-libre-2.6.37-gnu/Documentation/filesystems/configfs/configfs_example_explicit.c
--- linux-libre-2.6.36-gnu/Documentation/filesystems/configfs/configfs_example_explicit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/configfs/configfs_example_explicit.c	2011-01-04 19:50:19.000000000 -0500
@@ -89,7 +89,7 @@
 	char *p = (char *) page;
 
 	tmp = simple_strtoul(p, &p, 10);
-	if (!p || (*p && (*p != '\n')))
+	if ((*p != '\0') && (*p != '\n'))
 		return -EINVAL;
 
 	if (tmp > INT_MAX)
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/ext4.txt linux-libre-2.6.37-gnu/Documentation/filesystems/ext4.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/ext4.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/ext4.txt	2011-01-04 19:50:19.000000000 -0500
@@ -353,6 +353,20 @@
 			system crashes before the delayed allocation
 			blocks are forced to disk.
 
+noinit_itable		Do not initialize any uninitialized inode table
+			blocks in the background.  This feature may be
+			used by installation CD's so that the install
+			process can complete as quickly as possible; the
+			inode table initialization process would then be
+			deferred until the next time the  file system
+			is unmounted.
+
+init_itable=n		The lazy itable init code will wait n times the
+			number of milliseconds it took to zero out the
+			previous block group's inode table.  This
+			minimizes the impact on the systme performance
+			while file system's inode table is being initialized.
+
 discard		Controls whether ext4 should issue discard/TRIM
 nodiscard(*)		commands to the underlying block device when
 			blocks are freed.  This is useful for SSD devices
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/Locking linux-libre-2.6.37-gnu/Documentation/filesystems/Locking
--- linux-libre-2.6.36-gnu/Documentation/filesystems/Locking	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/Locking	2011-01-04 19:50:19.000000000 -0500
@@ -18,7 +18,6 @@
 	char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
 
 locking rules:
-	none have BKL
 		dcache_lock	rename_lock	->d_lock	may block
 d_revalidate:	no		no		no		yes
 d_hash		no		no		no		yes
@@ -42,18 +41,23 @@
 	int (*rename) (struct inode *, struct dentry *,
 			struct inode *, struct dentry *);
 	int (*readlink) (struct dentry *, char __user *,int);
-	int (*follow_link) (struct dentry *, struct nameidata *);
+	void * (*follow_link) (struct dentry *, struct nameidata *);
+	void (*put_link) (struct dentry *, struct nameidata *, void *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, struct nameidata *);
+	int (*check_acl)(struct inode *, int);
 	int (*setattr) (struct dentry *, struct iattr *);
 	int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
 	int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
 	ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
 	ssize_t (*listxattr) (struct dentry *, char *, size_t);
 	int (*removexattr) (struct dentry *, const char *);
+	void (*truncate_range)(struct inode *, loff_t, loff_t);
+	long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len);
+	int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
 
 locking rules:
-	all may block, none have BKL
+	all may block
 		i_mutex(inode)
 lookup:		yes
 create:		yes
@@ -66,19 +70,24 @@
 rename:		yes (all)	(see below)
 readlink:	no
 follow_link:	no
+put_link:	no
 truncate:	yes		(see below)
 setattr:	yes
 permission:	no
+check_acl:	no
 getattr:	no
 setxattr:	yes
 getxattr:	no
 listxattr:	no
 removexattr:	yes
+truncate_range:	yes
+fallocate:	no
+fiemap:		no
 	Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
 	cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
 	->truncate() is never called directly - it's a callback, not a
-method. It's called by vmtruncate() - library function normally used by
+method. It's called by vmtruncate() - deprecated library function used by
 ->setattr(). Locking information above applies to that call (i.e. is
 inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been
 passed).
@@ -91,7 +100,7 @@
 	struct inode *(*alloc_inode)(struct super_block *sb);
 	void (*destroy_inode)(struct inode *);
 	void (*dirty_inode) (struct inode *);
-	int (*write_inode) (struct inode *, int);
+	int (*write_inode) (struct inode *, struct writeback_control *wbc);
 	int (*drop_inode) (struct inode *);
 	void (*evict_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
@@ -105,10 +114,10 @@
 	int (*show_options)(struct seq_file *, struct vfsmount *);
 	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
 	ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
+	int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
 
 locking rules:
 	All may block [not true, see below]
-	None have BKL
 			s_umount
 alloc_inode:
 destroy_inode:
@@ -127,6 +136,7 @@
 show_options:		no		(namespace_sem)
 quota_read:		no		(see below)
 quota_write:		no		(see below)
+bdev_try_to_free_page:	no		(see below)
 
 ->statfs() has s_umount (shared) when called by ustat(2) (native or
 compat), but that's an accident of bad API; s_umount is used to pin
@@ -139,19 +149,25 @@
 dqio_sem) (unless an admin really wants to screw up something and
 writes to quota files with quotas on). For other details about locking
 see also dquot_operations section.
+->bdev_try_to_free_page is called from the ->releasepage handler of
+the block device inode.  See there for more details.
 
 --------------------------- file_system_type ---------------------------
 prototypes:
 	int (*get_sb) (struct file_system_type *, int,
 		       const char *, void *, struct vfsmount *);
+	struct dentry *(*mount) (struct file_system_type *, int,
+		       const char *, void *);
 	void (*kill_sb) (struct super_block *);
 locking rules:
-		may block	BKL
-get_sb		yes		no
-kill_sb		yes		no
+		may block
+get_sb		yes
+mount		yes
+kill_sb		yes
 
 ->get_sb() returns error or 0 with locked superblock attached to the vfsmount
 (exclusive on ->s_umount).
+->mount() returns ERR_PTR or the root dentry.
 ->kill_sb() takes a write-locked superblock, does all shutdown work on it,
 unlocks and drops the reference.
 
@@ -173,28 +189,38 @@
 	sector_t (*bmap)(struct address_space *, sector_t);
 	int (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
+	void (*freepage)(struct page *);
 	int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
-	int (*launder_page) (struct page *);
+	int (*get_xip_mem)(struct address_space *, pgoff_t, int, void **,
+				unsigned long *);
+	int (*migratepage)(struct address_space *, struct page *, struct page *);
+	int (*launder_page)(struct page *);
+	int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long);
+	int (*error_remove_page)(struct address_space *, struct page *);
 
 locking rules:
-	All except set_page_dirty may block
+	All except set_page_dirty and freepage may block
 
-			BKL	PageLocked(page)	i_mutex
-writepage:		no	yes, unlocks (see below)
-readpage:		no	yes, unlocks
-sync_page:		no	maybe
-writepages:		no
-set_page_dirty		no	no
-readpages:		no
-write_begin:		no	locks the page		yes
-write_end:		no	yes, unlocks		yes
-perform_write:		no	n/a			yes
-bmap:			no
-invalidatepage:		no	yes
-releasepage:		no	yes
-direct_IO:		no
-launder_page:		no	yes
+			PageLocked(page)	i_mutex
+writepage:		yes, unlocks (see below)
+readpage:		yes, unlocks
+sync_page:		maybe
+writepages:
+set_page_dirty		no
+readpages:
+write_begin:		locks the page		yes
+write_end:		yes, unlocks		yes
+bmap:
+invalidatepage:		yes
+releasepage:		yes
+freepage:		yes
+direct_IO:
+get_xip_mem:					maybe
+migratepage:		yes (both)
+launder_page:		yes
+is_partially_uptodate:	yes
+error_remove_page:	yes
 
 	->write_begin(), ->write_end(), ->sync_page() and ->readpage()
 may be called from the request handler (/dev/loop).
@@ -274,9 +300,8 @@
 not locked.
 
 	->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some
-filesystems and by the swapper. The latter will eventually go away. All
-instances do not actually need the BKL. Please, keep it that way and don't
-breed new callers.
+filesystems and by the swapper. The latter will eventually go away.  Please,
+keep it that way and don't breed new callers.
 
 	->invalidatepage() is called when the filesystem must attempt to drop
 some or all of the buffers from the page when it is being truncated.  It
@@ -288,55 +313,46 @@
 indicate that the buffers are (or may be) freeable.  If ->releasepage is zero,
 the kernel assumes that the fs has no private interest in the buffers.
 
+	->freepage() is called when the kernel is done dropping the page
+from the page cache.
+
 	->launder_page() may be called prior to releasing a page if
 it is still found to be dirty. It returns zero if the page was successfully
 cleaned, or an error value if not. Note that in order to prevent the page
 getting mapped back in and redirtied, it needs to be kept locked
 across the entire operation.
 
-	Note: currently almost all instances of address_space methods are
-using BKL for internal serialization and that's one of the worst sources
-of contention. Normally they are calling library functions (in fs/buffer.c)
-and pass foo_get_block() as a callback (on local block-based filesystems,
-indeed). BKL is not needed for library stuff and is usually taken by
-foo_get_block(). It's an overkill, since block bitmaps can be protected by
-internal fs locking and real critical areas are much smaller than the areas
-filesystems protect now.
-
 ----------------------- file_lock_operations ------------------------------
 prototypes:
-	void (*fl_insert)(struct file_lock *);	/* lock insertion callback */
-	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
 	void (*fl_release_private)(struct file_lock *);
 
 
 locking rules:
-			BKL	may block
-fl_insert:		yes	no
-fl_remove:		yes	no
-fl_copy_lock:		yes	no
-fl_release_private:	yes	yes
+			file_lock_lock	may block
+fl_copy_lock:		yes		no
+fl_release_private:	maybe		no
 
 ----------------------- lock_manager_operations ---------------------------
 prototypes:
 	int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
 	void (*fl_notify)(struct file_lock *);  /* unblock callback */
-	void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
+	int (*fl_grant)(struct file_lock *, struct file_lock *, int);
 	void (*fl_release_private)(struct file_lock *);
 	void (*fl_break)(struct file_lock *); /* break_lease callback */
+	int (*fl_mylease)(struct file_lock *, struct file_lock *);
+	int (*fl_change)(struct file_lock **, int);
 
 locking rules:
-			BKL	may block
-fl_compare_owner:	yes	no
-fl_notify:		yes	no
-fl_copy_lock:		yes	no
-fl_release_private:	yes	yes
-fl_break:		yes	no
+			file_lock_lock	may block
+fl_compare_owner:	yes		no
+fl_notify:		yes		no
+fl_grant:		no		no
+fl_release_private:	maybe		no
+fl_break:		yes		no
+fl_mylease:		yes		no
+fl_change		yes		no
 
-	Currently only NFSD and NLM provide instances of this class. None of the
-them block. If you have out-of-tree instances - please, show up. Locking
-in that area will change.
 --------------------------- buffer_head -----------------------------------
 prototypes:
 	void (*b_end_io)(struct buffer_head *bh, int uptodate);
@@ -349,21 +365,36 @@
 
 --------------------------- block_device_operations -----------------------
 prototypes:
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+	int (*open) (struct block_device *, fmode_t);
+	int (*release) (struct gendisk *, fmode_t);
+	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+	int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
+	int (*direct_access) (struct block_device *, sector_t, void **, unsigned long *);
 	int (*media_changed) (struct gendisk *);
+	void (*unlock_native_capacity) (struct gendisk *);
 	int (*revalidate_disk) (struct gendisk *);
+	int (*getgeo)(struct block_device *, struct hd_geometry *);
+	void (*swap_slot_free_notify) (struct block_device *, unsigned long);
 
 locking rules:
-			BKL	bd_sem
-open:			yes	yes
-release:		yes	yes
-ioctl:			yes	no
-media_changed:		no	no
-revalidate_disk:	no	no
+			bd_mutex
+open:			yes
+release:		yes
+ioctl:			no
+compat_ioctl:		no
+direct_access:		no
+media_changed:		no
+unlock_native_capacity:	no
+revalidate_disk:	no
+getgeo:			no
+swap_slot_free_notify:	no	(see below)
+
+media_changed, unlock_native_capacity and revalidate_disk are called only from
+check_disk_change().
+
+swap_slot_free_notify is called with swap_lock and sometimes the page lock
+held.
 
-The last two are called only from check_disk_change().
 
 --------------------------- file_operations -------------------------------
 prototypes:
@@ -395,34 +426,21 @@
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long,
 			unsigned long, unsigned long, unsigned long);
 	int (*check_flags)(int);
+	int (*flock) (struct file *, int, struct file_lock *);
+	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *,
+			size_t, unsigned int);
+	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *,
+			size_t, unsigned int);
+	int (*setlease)(struct file *, long, struct file_lock **);
 };
 
 locking rules:
-	All may block.
-			BKL
-llseek:			no	(see below)
-read:			no
-aio_read:		no
-write:			no
-aio_write:		no
-readdir: 		no
-poll:			no
-unlocked_ioctl:		no
-compat_ioctl:		no
-mmap:			no
-open:			no
-flush:			no
-release:		no
-fsync:			no	(see below)
-aio_fsync:		no
-fasync:			no
-lock:			yes
-readv:			no
-writev:			no
-sendfile:		no
-sendpage:		no
-get_unmapped_area:	no
-check_flags:		no
+	All may block except for ->setlease.
+	No VFS locks held on entry except for ->fsync and ->setlease.
+
+->fsync() has i_mutex on inode.
+
+->setlease has the file_list_lock held and must not sleep.
 
 ->llseek() locking has moved from llseek to the individual llseek
 implementations.  If your fs is not using generic_file_llseek, you
@@ -432,17 +450,10 @@
 Note: this does not protect the file->f_pos against concurrent modifications
 since this is something the userspace has to take care about.
 
-Note: ext2_release() was *the* source of contention on fs-intensive
-loads and dropping BKL on ->release() helps to get rid of that (we still
-grab BKL for cases when we close a file that had been opened r/w, but that
-can and should be done using the internal locking with smaller critical areas).
-Current worst offender is ext2_get_block()...
-
-->fasync() is called without BKL protection, and is responsible for
-maintaining the FASYNC bit in filp->f_flags.  Most instances call
-fasync_helper(), which does that maintenance, so it's not normally
-something one needs to worry about.  Return values > 0 will be mapped to
-zero in the VFS layer.
+->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags.
+Most instances call fasync_helper(), which does that maintenance, so it's
+not normally something one needs to worry about.  Return values > 0 will be
+mapped to zero in the VFS layer.
 
 ->readdir() and ->ioctl() on directories must be changed. Ideally we would
 move ->readdir() to inode_operations and use a separate method for directory
@@ -453,8 +464,6 @@
 ->read on directories probably must go away - we should just enforce -EISDIR
 in sys_read() and friends.
 
-->fsync() has i_mutex on inode.
-
 --------------------------- dquot_operations -------------------------------
 prototypes:
 	int (*write_dquot) (struct dquot *);
@@ -489,12 +498,12 @@
 	int (*access)(struct vm_area_struct *, unsigned long, void*, int, int);
 
 locking rules:
-		BKL	mmap_sem	PageLocked(page)
-open:		no	yes
-close:		no	yes
-fault:		no	yes		can return with page locked
-page_mkwrite:	no	yes		can return with page locked
-access:		no	yes
+		mmap_sem	PageLocked(page)
+open:		yes
+close:		yes
+fault:		yes		can return with page locked
+page_mkwrite:	yes		can return with page locked
+access:		yes
 
 	->fault() is called when a previously not present pte is about
 to be faulted in. The filesystem must find and return the page associated
@@ -521,6 +530,3 @@
 
 (if you break something or notice that it is broken and do not fix it yourself
 - at least put it here)
-
-ipc/shm.c::shm_delete() - may need BKL.
-->read() and ->write() in many drivers are (probably) missing BKL.
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/00-INDEX linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -12,5 +12,9 @@
 	- how to install and setup the Linux NFS/RDMA client and server software
 nfsroot.txt
 	- short guide on setting up a diskless box with NFS root filesystem.
+pnfs.txt
+	- short explanation of some of the internals of the pnfs client code
 rpc-cache.txt
 	- introduction to the caching mechanisms in the sunrpc layer.
+idmapper.txt
+	- information for configuring request-keys to be used by idmapper
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/idmapper.txt linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/idmapper.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/idmapper.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/idmapper.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,67 @@
+
+=========
+ID Mapper
+=========
+Id mapper is used by NFS to translate user and group ids into names, and to
+translate user and group names into ids.  Part of this translation involves
+performing an upcall to userspace to request the information.  Id mapper will
+user request-key to perform this upcall and cache the result.  The program
+/usr/sbin/nfs.idmap should be called by request-key, and will perform the
+translation and initialize a key with the resulting information.
+
+ NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
+ feature.
+
+===========
+Configuring
+===========
+The file /etc/request-key.conf will need to be modified so /sbin/request-key can
+direct the upcall.  The following line should be added:
+
+#OP	TYPE	DESCRIPTION	CALLOUT INFO	PROGRAM ARG1 ARG2 ARG3 ...
+#======	=======	===============	===============	===============================
+create	id_resolver	*	*		/usr/sbin/nfs.idmap %k %d 600
+
+This will direct all id_resolver requests to the program /usr/sbin/nfs.idmap.
+The last parameter, 600, defines how many seconds into the future the key will
+expire.  This parameter is optional for /usr/sbin/nfs.idmap.  When the timeout
+is not specified, nfs.idmap will default to 600 seconds.
+
+id mapper uses for key descriptions:
+	  uid:  Find the UID for the given user
+	  gid:  Find the GID for the given group
+	 user:  Find the user  name for the given UID
+	group:  Find the group name for the given GID
+
+You can handle any of these individually, rather than using the generic upcall
+program.  If you would like to use your own program for a uid lookup then you
+would edit your request-key.conf so it look similar to this:
+
+#OP	TYPE	DESCRIPTION	CALLOUT INFO	PROGRAM ARG1 ARG2 ARG3 ...
+#======	=======	===============	===============	===============================
+create	id_resolver	uid:*	*		/some/other/program %k %d 600
+create	id_resolver	*	*		/usr/sbin/nfs.idmap %k %d 600
+
+Notice that the new line was added above the line for the generic program.
+request-key will find the first matching line and corresponding program.  In
+this case, /some/other/program will handle all uid lookups and
+/usr/sbin/nfs.idmap will handle gid, user, and group lookups.
+
+See <file:Documentation/keys-request-keys.txt> for more information about the
+request-key function.
+
+
+=========
+nfs.idmap
+=========
+nfs.idmap is designed to be called by request-key, and should not be run "by
+hand".  This program takes two arguments, a serialized key and a key
+description.  The serialized key is first converted into a key_serial_t, and
+then passed as an argument to keyctl_instantiate (both are part of keyutils.h).
+
+The actual lookups are performed by functions found in nfsidmap.h.  nfs.idmap
+determines the correct function to call by looking at the first part of the
+description string.  For example, a uid lookup description will appear as
+"uid:user@domain".
+
+nfs.idmap will return 0 if the key was instantiated, and non-zero otherwise.
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/nfsroot.txt linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/nfsroot.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/nfsroot.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/nfsroot.txt	2011-01-04 19:50:19.000000000 -0500
@@ -159,6 +159,28 @@
                 Default: any
 
 
+nfsrootdebug
+
+  This parameter enables debugging messages to appear in the kernel
+  log at boot time so that administrators can verify that the correct
+  NFS mount options, server address, and root path are passed to the
+  NFS client.
+
+
+rdinit=<executable file>
+
+  To specify which file contains the program that starts system
+  initialization, administrators can use this command line parameter.
+  The default value of this parameter is "/init".  If the specified
+  file exists and the kernel can execute it, root filesystem related
+  kernel command line parameters, including `nfsroot=', are ignored.
+
+  A description of the process of mounting the root file system can be
+  found in:
+
+    Documentation/early-userspace/README
+
+
 
 
 3.) Boot Loader
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/pnfs.txt linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/pnfs.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/nfs/pnfs.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/nfs/pnfs.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,48 @@
+Reference counting in pnfs:
+==========================
+
+The are several inter-related caches.  We have layouts which can
+reference multiple devices, each of which can reference multiple data servers.
+Each data server can be referenced by multiple devices.  Each device
+can be referenced by multiple layouts.  To keep all of this straight,
+we need to reference count.
+
+
+struct pnfs_layout_hdr
+----------------------
+The on-the-wire command LAYOUTGET corresponds to struct
+pnfs_layout_segment, usually referred to by the variable name lseg.
+Each nfs_inode may hold a pointer to a cache of of these layout
+segments in nfsi->layout, of type struct pnfs_layout_hdr.
+
+We reference the header for the inode pointing to it, across each
+outstanding RPC call that references it (LAYOUTGET, LAYOUTRETURN,
+LAYOUTCOMMIT), and for each lseg held within.
+
+Each header is also (when non-empty) put on a list associated with
+struct nfs_client (cl_layouts).  Being put on this list does not bump
+the reference count, as the layout is kept around by the lseg that
+keeps it in the list.
+
+deviceid_cache
+--------------
+lsegs reference device ids, which are resolved per nfs_client and
+layout driver type.  The device ids are held in a RCU cache (struct
+nfs4_deviceid_cache).  The cache itself is referenced across each
+mount.  The entries (struct nfs4_deviceid) themselves are held across
+the lifetime of each lseg referencing them.
+
+RCU is used because the deviceid is basically a write once, read many
+data structure.  The hlist size of 32 buckets needs better
+justification, but seems reasonable given that we can have multiple
+deviceid's per filesystem, and multiple filesystems per nfs_client.
+
+The hash code is copied from the nfsd code base.  A discussion of
+hashing and variations of this algorithm can be found at:
+http://groups.google.com/group/comp.lang.c/browse_thread/thread/9522965e2b8d3809
+
+data server cache
+-----------------
+file driver devices refer to data servers, which are kept in a module
+level cache.  Its reference is held over the lifetime of the deviceid
+pointing to it.
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/ocfs2.txt linux-libre-2.6.37-gnu/Documentation/filesystems/ocfs2.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/ocfs2.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/ocfs2.txt	2011-01-04 19:50:19.000000000 -0500
@@ -87,3 +87,10 @@
 			reservations - users should rarely need to change this
 			value. If allocation reservations are turned off, this
 			option will have no effect.
+coherency=full  (*)	Disallow concurrent O_DIRECT writes, cluster inode
+			lock will be taken to force other nodes drop cache,
+			therefore full cluster coherency is guaranteed even
+			for O_DIRECT writes.
+coherency=buffered	Allow concurrent O_DIRECT writes without EX lock among
+			nodes, which gains high performance at risk of getting
+			stale data on other nodes.
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/proc.txt linux-libre-2.6.37-gnu/Documentation/filesystems/proc.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/proc.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/proc.txt	2011-01-04 19:50:19.000000000 -0500
@@ -136,6 +136,7 @@
  statm		Process memory status information
  status		Process status in human readable form
  wchan		If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ pagemap	Page table
  stack		Report full stack trace, enable via CONFIG_STACKTRACE
  smaps		a extension based on maps, showing the memory consumption of
 		each mapping
@@ -370,17 +371,24 @@
 Private_Clean:         0 kB
 Private_Dirty:         0 kB
 Referenced:          892 kB
+Anonymous:             0 kB
 Swap:                  0 kB
 KernelPageSize:        4 kB
 MMUPageSize:           4 kB
 
-The first  of these lines shows  the same information  as is displayed for the
-mapping in /proc/PID/maps.  The remaining lines show  the size of the mapping,
-the amount of the mapping that is currently resident in RAM, the "proportional
-set sizeâ€� (divide each shared page by the number of processes sharing it), the
-number of clean and dirty shared pages in the mapping, and the number of clean
-and dirty private pages in the mapping.  The "Referenced" indicates the amount
-of memory currently marked as referenced or accessed.
+The first of these lines shows the same information as is displayed for the
+mapping in /proc/PID/maps.  The remaining lines show the size of the mapping
+(size), the amount of the mapping that is currently resident in RAM (RSS), the
+process' proportional share of this mapping (PSS), the number of clean and
+dirty private pages in the mapping.  Note that even a page which is part of a
+MAP_SHARED mapping, but has only a single pte mapped, i.e.  is currently used
+by only one process, is accounted as private and not as shared.  "Referenced"
+indicates the amount of memory currently marked as referenced or accessed.
+"Anonymous" shows the amount of memory that does not belong to any file.  Even
+a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
+and a page is modified, the file page is replaced by a private anonymous copy.
+"Swap" shows how much would-be-anonymous memory is also used, but out on
+swap.
 
 This file is only present if the CONFIG_MMU kernel configuration option is
 enabled.
@@ -397,6 +405,9 @@
     > echo 3 > /proc/PID/clear_refs
 Any other value written to /proc/PID/clear_refs will have no effect.
 
+The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
+using /proc/kpageflags and number of times a page is mapped using
+/proc/kpagecount. For detailed explanation, see Documentation/vm/pagemap.txt.
 
 1.2 Kernel data
 ---------------
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/sharedsubtree.txt linux-libre-2.6.37-gnu/Documentation/filesystems/sharedsubtree.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/sharedsubtree.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/sharedsubtree.txt	2011-01-04 19:50:19.000000000 -0500
@@ -62,10 +62,10 @@
 	# mount /dev/sd0  /tmp/a
 
 	#ls /tmp/a
-	t1 t2 t2
+	t1 t2 t3
 
 	#ls /mnt/a
-	t1 t2 t2
+	t1 t2 t3
 
 	Note that the mount has propagated to the mount at /mnt as well.
 
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/smbfs.txt linux-libre-2.6.37-gnu/Documentation/filesystems/smbfs.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/smbfs.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/smbfs.txt	1969-12-31 19:00:00.000000000 -0500
@@ -1,8 +0,0 @@
-Smbfs is a filesystem that implements the SMB protocol, which is the
-protocol used by Windows for Workgroups, Windows 95 and Windows NT.
-Smbfs was inspired by Samba, the program written by Andrew Tridgell
-that turns any Unix host into a file server for DOS or Windows clients.
-
-Smbfs is a SMB client, but uses parts of samba for its operation. For
-more info on samba, including documentation, please go to
-http://www.samba.org/ and then on to your nearest mirror.
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/vfs.txt linux-libre-2.6.37-gnu/Documentation/filesystems/vfs.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/vfs.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/vfs.txt	2011-01-04 19:50:19.000000000 -0500
@@ -534,6 +534,7 @@
 	sector_t (*bmap)(struct address_space *, sector_t);
 	int (*invalidatepage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
+	void (*freepage)(struct page *);
 	ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
 			loff_t offset, unsigned long nr_segs);
 	struct page* (*get_xip_page)(struct address_space *, sector_t,
@@ -660,11 +661,10 @@
   releasepage: releasepage is called on PagePrivate pages to indicate
         that the page should be freed if possible.  ->releasepage
         should remove any private data from the page and clear the
-        PagePrivate flag.  It may also remove the page from the
-        address_space.  If this fails for some reason, it may indicate
-        failure with a 0 return value.
-	This is used in two distinct though related cases.  The first
-        is when the VM finds a clean page with no active users and
+        PagePrivate flag. If releasepage() fails for some reason, it must
+	indicate failure with a 0 return value.
+	releasepage() is used in two distinct though related cases.  The
+	first is when the VM finds a clean page with no active users and
         wants to make it a free page.  If ->releasepage succeeds, the
         page will be removed from the address_space and become free.
 
@@ -679,6 +679,12 @@
         need to ensure this.  Possibly it can clear the PageUptodate
         bit if it cannot free private data yet.
 
+  freepage: freepage is called once the page is no longer visible in
+        the page cache in order to allow the cleanup of any private
+	data. Since it may be called by the memory reclaimer, it
+	should not assume that the original address_space mapping still
+	exists, and it should not block.
+
   direct_IO: called by the generic read/write routines to perform
         direct_IO - that is IO requests which bypass the page cache
         and transfer data directly between the storage and the
diff -druN linux-libre-2.6.36-gnu/Documentation/filesystems/xfs-delayed-logging-design.txt linux-libre-2.6.37-gnu/Documentation/filesystems/xfs-delayed-logging-design.txt
--- linux-libre-2.6.36-gnu/Documentation/filesystems/xfs-delayed-logging-design.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/filesystems/xfs-delayed-logging-design.txt	2011-01-04 19:50:19.000000000 -0500
@@ -794,17 +794,6 @@
 
 Roadmap:
 
-2.6.37 Remove experimental tag from mount option
-	=> should be roughly 6 months after initial merge
-	=> enough time to:
-		=> gain confidence and fix problems reported by early
-		   adopters (a.k.a. guinea pigs)
-		=> address worst performance regressions and undesired
-		   behaviours
-		=> start tuning/optimising code for parallelism
-		=> start tuning/optimising algorithms consuming
-		   excessive CPU time
-
 2.6.39 Switch default mount option to use delayed logging
 	=> should be roughly 12 months after initial merge
 	=> enough time to shake out remaining problems before next round of
diff -druN linux-libre-2.6.36-gnu/Documentation/gpio.txt linux-libre-2.6.37-gnu/Documentation/gpio.txt
--- linux-libre-2.6.36-gnu/Documentation/gpio.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/gpio.txt	2011-01-04 19:50:19.000000000 -0500
@@ -617,6 +617,16 @@
 		is configured as an output, this value may be written;
 		any nonzero value is treated as high.
 
+		If the pin can be configured as interrupt-generating interrupt
+		and if it has been configured to generate interrupts (see the
+		description of "edge"), you can poll(2) on that file and
+		poll(2) will return whenever the interrupt was triggered. If
+		you use poll(2), set the events POLLPRI and POLLERR. If you
+		use select(2), set the file descriptor in exceptfds. After
+		poll(2) returns, either lseek(2) to the beginning of the sysfs
+		file and read the new value or close the file and re-open it
+		to read the value.
+
 	"edge" ... reads as either "none", "rising", "falling", or
 		"both". Write these strings to select the signal edge(s)
 		that will make poll(2) on the "value" file return.
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/it87 linux-libre-2.6.37-gnu/Documentation/hwmon/it87
--- linux-libre-2.6.36-gnu/Documentation/hwmon/it87	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/it87	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,10 @@
     Prefix: 'it8720'
     Addresses scanned: from Super I/O config space (8 I/O ports)
     Datasheet: Not publicly available
+  * IT8721F/IT8758E
+    Prefix: 'it8721'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * SiS950   [clone of IT8705F]
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -67,7 +71,7 @@
 -----------
 
 This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8726F and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8758E and SiS950 chips.
 
 These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
 joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -86,14 +90,15 @@
 upper VID bits share their pins with voltage inputs (in5 and in6) so you
 can't have both on a given board.
 
-The IT8716F, IT8718F, IT8720F and later IT8712F revisions have support for
-2 additional fans. The additional fans are supported by the driver.
+The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions
+have support for 2 additional fans. The additional fans are supported by the
+driver.
 
-The IT8716F, IT8718F and IT8720F, and late IT8712F and IT8705F also have
-optional 16-bit tachometer counters for fans 1 to 3. This is better (no more
-fan clock divider mess) but not compatible with the older chips and
-revisions. The 16-bit tachometer mode is enabled by the driver when one
-of the above chips is detected.
+The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and
+IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This
+is better (no more fan clock divider mess) but not compatible with the older
+chips and revisions. The 16-bit tachometer mode is enabled by the driver when
+one of the above chips is detected.
 
 The IT8726F is just bit enhanced IT8716F with additional hardware
 for AMD power sequencing. Therefore the chip will appear as IT8716F
@@ -115,7 +120,12 @@
 maximum limit. Note that minimum in this case always means 'closest to
 zero'; this is important for negative voltage measurements. All voltage
 inputs can measure voltages between 0 and 4.08 volts, with a resolution of
-0.016 volt. The battery voltage in8 does not have limit registers.
+0.016 volt (except IT8721F/IT8758E: 0.012 volt.) The battery voltage in8 does
+not have limit registers.
+
+On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
+the chip (in7, in8 and optionally in3). The driver handles this transparently
+so user-space doesn't have to care.
 
 The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
 the voltage level your processor should work with. This is hardcoded by
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/lm85 linux-libre-2.6.37-gnu/Documentation/hwmon/lm85
--- linux-libre-2.6.36-gnu/Documentation/hwmon/lm85	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/lm85	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,10 @@
     Prefix: 'adt7463'
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
     Datasheet: http://www.onsemi.com/PowerSolutions/product.do?id=ADT7463
+  * Analog Devices ADT7468
+    Prefix: 'adt7468'
+    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+    Datasheet: http://www.onsemi.com/PowerSolutions/product.do?id=ADT7468
   * SMSC EMC6D100, SMSC EMC6D101
     Prefix: 'emc6d100'
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
@@ -34,7 +38,7 @@
 -----------
 
 This driver implements support for the National Semiconductor LM85 and
-compatible chips including the Analog Devices ADM1027, ADT7463 and
+compatible chips including the Analog Devices ADM1027, ADT7463, ADT7468 and
 SMSC EMC6D10x chips family.
 
 The LM85 uses the 2-wire interface compatible with the SMBUS 2.0
@@ -87,14 +91,22 @@
 optional filter for smoothing temperatures. The ADM1027 has the same
 config option but uses it to rate limit the changes to fan speed instead.
 
-The ADM1027 and ADT7463 have a 10-bit ADC and can therefore measure
-temperatures with 0.25 degC resolution. They also provide an offset to the
-temperature readings that is automatically applied during measurement.
-This offset can be used to zero out any errors due to traces and placement.
-The documentation says that the offset is in 0.25 degC steps, but in
-initial testing of the ADM1027 it was 1.00 degC steps. Analog Devices has
-confirmed this "bug". The ADT7463 is reported to work as described in the
-documentation. The current lm85 driver does not show the offset register.
+The ADM1027, ADT7463 and ADT7468 have a 10-bit ADC and can therefore
+measure temperatures with 0.25 degC resolution. They also provide an offset
+to the temperature readings that is automatically applied during
+measurement. This offset can be used to zero out any errors due to traces
+and placement. The documentation says that the offset is in 0.25 degC
+steps, but in initial testing of the ADM1027 it was 1.00 degC steps. Analog
+Devices has confirmed this "bug". The ADT7463 is reported to work as
+described in the documentation. The current lm85 driver does not show the
+offset register.
+
+The ADT7468 has a high-frequency PWM mode, where all PWM outputs are
+driven by a 22.5 kHz clock. This is a global mode, not per-PWM output,
+which means that setting any PWM frequency above 11.3 kHz will switch
+all 3 PWM outputs to a 22.5 kHz frequency. Conversely, setting any PWM
+frequency below 11.3 kHz will switch all 3 PWM outputs to a frequency
+between 10 and 100 Hz, which can then be tuned separately.
 
 See the vendor datasheets for more information. There is application note
 from National (AN-1260) with some additional information about the LM85.
@@ -125,17 +137,17 @@
 identifying the chip, the driver behaves no differently with regard to
 these two chips. The LM85B is recommended for new designs.
 
-The ADM1027 and ADT7463 chips have an optional SMBALERT output that can be
-used to signal the chipset in case a limit is exceeded or the temperature
-sensors fail. Individual sensor interrupts can be masked so they won't
-trigger SMBALERT. The SMBALERT output if configured replaces one of the other
-functions (PWM2 or IN0). This functionality is not implemented in current
-driver.
+The ADM1027, ADT7463 and ADT7468 chips have an optional SMBALERT output
+that can be used to signal the chipset in case a limit is exceeded or the
+temperature sensors fail. Individual sensor interrupts can be masked so
+they won't trigger SMBALERT. The SMBALERT output if configured replaces one
+of the other functions (PWM2 or IN0). This functionality is not implemented
+in current driver.
 
-The ADT7463 also has an optional THERM output/input which can be connected
-to the processor PROC_HOT output. If available, the autofan control
-dynamic Tmin feature can be enabled to keep the system temperature within
-spec (just?!) with the least possible fan noise.
+The ADT7463 and ADT7468 also have an optional THERM output/input which can
+be connected to the processor PROC_HOT output. If available, the autofan
+control dynamic Tmin feature can be enabled to keep the system temperature
+within spec (just?!) with the least possible fan noise.
 
 Configuration Notes
 -------------------
@@ -201,8 +213,8 @@
 measurements. These features are not currently supported by the lm85
 driver.
 
-In addition to the ADM1027 features, the ADT7463 also has Tmin control
-and THERM asserted counts. Automatic Tmin control acts to adjust the
-Tmin value to maintain the measured temperature sensor at a specified
-temperature. There isn't much documentation on this feature in the
-ADT7463 data sheet. This is not supported by current driver.
+In addition to the ADM1027 features, the ADT7463 and ADT7468 also have
+Tmin control and THERM asserted counts. Automatic Tmin control acts to
+adjust the Tmin value to maintain the measured temperature sensor at a
+specified temperature. There isn't much documentation on this feature in
+the ADT7463 data sheet. This is not supported by current driver.
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/lm90 linux-libre-2.6.37-gnu/Documentation/hwmon/lm90
--- linux-libre-2.6.36-gnu/Documentation/hwmon/lm90	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/lm90	2011-01-04 19:50:19.000000000 -0500
@@ -63,8 +63,8 @@
     Datasheet: Publicly available at the Maxim website
                http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
   * Maxim MAX6659
-    Prefix: 'max6657'
-    Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e)
+    Prefix: 'max6659'
+    Addresses scanned: I2C 0x4c, 0x4d, 0x4e
     Datasheet: Publicly available at the Maxim website
                http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
   * Maxim MAX6680
@@ -84,6 +84,21 @@
     Addresses scanned: I2C 0x4c
     Datasheet: Publicly available at the Maxim website
                http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3500
+  * Maxim MAX6695
+    Prefix: 'max6695'
+    Addresses scanned: I2C 0x18
+    Datasheet: Publicly available at the Maxim website
+               http://www.maxim-ic.com/datasheet/index.mvp/id/4199
+  * Maxim MAX6696
+    Prefix: 'max6695'
+    Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+                           0x4c, 0x4d and 0x4e
+    Datasheet: Publicly available at the Maxim website
+               http://www.maxim-ic.com/datasheet/index.mvp/id/4199
+  * Winbond/Nuvoton W83L771W/G
+    Prefix: 'w83l771'
+    Addresses scanned: I2C 0x4c
+    Datasheet: No longer available
   * Winbond/Nuvoton W83L771AWG/ASG
     Prefix: 'w83l771'
     Addresses scanned: I2C 0x4c
@@ -101,10 +116,11 @@
 with many other devices, many of which are supported by this driver.
 
 Note that there is no easy way to differentiate between the MAX6657,
-MAX6658 and MAX6659 variants. The extra address and features of the
-MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
-differ in their pinout, therefore they obviously can't (and don't need to)
-be distinguished.
+MAX6658 and MAX6659 variants. The extra features of the MAX6659 are only
+supported by this driver if the chip is located at address 0x4d or 0x4e,
+or if the chip type is explicitly selected as max6659.
+The MAX6680 and MAX6681 only differ in their pinout, therefore they obviously
+can't (and don't need to) be distinguished.
 
 The specificity of this family of chipsets over the ADM1021/LM84
 family is that it features critical limits with hysteresis, and an
@@ -151,11 +167,21 @@
   * Selectable address
   * Remote sensor type selection
 
+MAX6695 and MAX6696:
+  * Better local resolution
+  * Selectable address (max6696)
+  * Second critical temperature limit
+  * Two remote sensors
+
+W83L771W/G
+  * The G variant is lead-free, otherwise similar to the W.
+  * Filter and alert configuration register at 0xBF
+  * Moving average (depending on conversion rate)
+
 W83L771AWG/ASG
+  * Successor of the W83L771W/G, same features.
   * The AWG and ASG variants only differ in package format.
-  * Filter and alert configuration register at 0xBF
   * Diode ideality factor configuration (remote sensor) at 0xE3
-  * Moving average (depending on conversion rate)
 
 All temperature values are given in degrees Celsius. Resolution
 is 1.0 degree for the local temperature, 0.125 degree for the remote
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/lm93 linux-libre-2.6.37-gnu/Documentation/hwmon/lm93
--- linux-libre-2.6.36-gnu/Documentation/hwmon/lm93	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/lm93	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,7 @@
 	Mark M. Hoffman <mhoffman@lightlink.com>
 	Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
 	Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
-	Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+	Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
 
 Module Parameters
 -----------------
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/ltc4261 linux-libre-2.6.37-gnu/Documentation/hwmon/ltc4261
--- linux-libre-2.6.36-gnu/Documentation/hwmon/ltc4261	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/ltc4261	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,63 @@
+Kernel driver ltc4261
+=====================
+
+Supported chips:
+  * Linear Technology LTC4261
+    Prefix: 'ltc4261'
+    Addresses scanned: -
+    Datasheet:
+        http://cds.linear.com/docs/Datasheet/42612fb.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+The LTC4261/LTC4261-2 negative voltage Hot Swap controllers allow a board
+to be safely inserted and removed from a live backplane.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for LTC4261 devices, since there is no register
+which can be safely used to identify the chip. You will have to instantiate
+the devices explicitly.
+
+Example: the following will load the driver for an LTC4261 at address 0x10
+on I2C bus #1:
+$ modprobe ltc4261
+$ echo ltc4261 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs entries
+-------------
+
+Voltage readings provided by this driver are reported as obtained from the ADC
+registers. If a set of voltage divider resistors is installed, calculate the
+real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
+value of the divider resistor against the measured voltage and R2 is the value
+of the divider resistor against Ground.
+
+Current reading provided by this driver is reported as obtained from the ADC
+Current Sense register. The reported value assumes that a 1 mOhm sense resistor
+is installed. If a different sense resistor is installed, calculate the real
+current by dividing the reported value by the sense resistor value in mOhm.
+
+The chip has two voltage sensors, but only one set of voltage alarm status bits.
+In many many designs, those alarms are associated with the ADIN2 sensor, due to
+the proximity of the ADIN2 pin to the OV pin. ADIN2 is, however, not available
+on all chip variants. To ensure that the alarm condition is reported to the user,
+report it with both voltage sensors.
+
+in1_input		ADIN2 voltage (mV)
+in1_min_alarm		ADIN/ADIN2 Undervoltage alarm
+in1_max_alarm		ADIN/ADIN2 Overvoltage alarm
+
+in2_input		ADIN voltage (mV)
+in2_min_alarm		ADIN/ADIN2 Undervoltage alarm
+in2_max_alarm		ADIN/ADIN2 Overvoltage alarm
+
+curr1_input		SENSE current (mA)
+curr1_alarm		SENSE overcurrent alarm
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/max6650 linux-libre-2.6.37-gnu/Documentation/hwmon/max6650
--- linux-libre-2.6.36-gnu/Documentation/hwmon/max6650	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/max6650	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
     Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
 
 Authors:
-    Hans J. Koch <hjk@linutronix.de>
+    Hans J. Koch <hjk@hansjkoch.de>
     John Morris <john.morris@spirentcom.com>
     Claus Gindhart <claus.gindhart@kontron.com>
 
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/pcf8591 linux-libre-2.6.37-gnu/Documentation/hwmon/pcf8591
--- linux-libre-2.6.36-gnu/Documentation/hwmon/pcf8591	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/pcf8591	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
 Supported chips:
   * Philips/NXP PCF8591
     Prefix: 'pcf8591'
-    Addresses scanned: I2C 0x48 - 0x4f
+    Addresses scanned: none
     Datasheet: Publicly available at the NXP website
                http://www.nxp.com/pip/PCF8591_6.html
 
@@ -58,18 +58,16 @@
 Accessing PCF8591 via /sys interface
 -------------------------------------
 
-! Be careful !
-The PCF8591 is plainly impossible to detect! Stupid chip.
-So every chip with address in the interval [0x48..0x4f] is
-detected as PCF8591. If you have other chips in this address
-range, the workaround is to load this module after the one
-for your others chips.
+The PCF8591 is plainly impossible to detect! Thus the driver won't even
+try. You have to explicitly instantiate the device at the relevant
+address (in the interval [0x48..0x4f]) either through platform data, or
+using the sysfs interface. See Documentation/i2c/instantiating-devices
+for details.
 
-On detection (i.e. insmod, modprobe et al.), directories are being
-created for each detected PCF8591:
+Directories are being created for each instantiated PCF8591:
 
 /sys/bus/i2c/devices/<0>-<1>/
-where <0> is the bus the chip was detected on (e. g. i2c-0)
+where <0> is the bus the chip is connected to (e. g. i2c-0)
 and <1> the chip address ([48..4f])
 
 Inside these directories, there are such files:
diff -druN linux-libre-2.6.36-gnu/Documentation/hwmon/sysfs-interface linux-libre-2.6.37-gnu/Documentation/hwmon/sysfs-interface
--- linux-libre-2.6.36-gnu/Documentation/hwmon/sysfs-interface	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/hwmon/sysfs-interface	2011-01-04 19:50:19.000000000 -0500
@@ -309,6 +309,20 @@
 		from the critical value.
 		RW
 
+temp[1-*]_emergency
+		Temperature emergency max value, for chips supporting more than
+		two upper temperature limits. Must be equal or greater than
+		corresponding temp_crit values.
+		Unit: millidegree Celsius
+		RW
+
+temp[1-*]_emergency_hyst
+		Temperature hysteresis value for emergency limit.
+		Unit: millidegree Celsius
+		Must be reported as an absolute temperature, NOT a delta
+		from the emergency value.
+		RW
+
 temp[1-*]_lcrit	Temperature critical min value, typically lower than
 		corresponding temp_min values.
 		Unit: millidegree Celsius
@@ -505,6 +519,7 @@
 temp[1-*]_min_alarm
 temp[1-*]_max_alarm
 temp[1-*]_crit_alarm
+temp[1-*]_emergency_alarm
 		Limit alarm
 		0: no alarm
 		1: alarm
diff -druN linux-libre-2.6.36-gnu/Documentation/i2c/busses/i2c-i801 linux-libre-2.6.37-gnu/Documentation/i2c/busses/i2c-i801
--- linux-libre-2.6.36-gnu/Documentation/i2c/busses/i2c-i801	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/i2c/busses/i2c-i801	2011-01-04 19:50:19.000000000 -0500
@@ -15,10 +15,14 @@
   * Intel 82801I (ICH9)
   * Intel EP80579 (Tolapai)
   * Intel 82801JI (ICH10)
-  * Intel 3400/5 Series (PCH)
+  * Intel 5/3400 Series (PCH)
   * Intel Cougar Point (PCH)
+  * Intel Patsburg (PCH)
    Datasheets: Publicly available at the Intel website
 
+On Intel Patsburg and later chipsets, both the normal host SMBus controller
+and the additional 'Integrated Device Function' controllers are supported.
+
 Authors: 
 	Mark Studebaker <mdsxyz123@yahoo.com>
 	Jean Delvare <khali@linux-fr.org>
diff -druN linux-libre-2.6.36-gnu/Documentation/input/ntrig.txt linux-libre-2.6.37-gnu/Documentation/input/ntrig.txt
--- linux-libre-2.6.36-gnu/Documentation/input/ntrig.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/input/ntrig.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,126 @@
+N-Trig touchscreen Driver
+-------------------------
+	Copyright (c) 2008-2010 Rafi Rubin <rafi@seas.upenn.edu>
+	Copyright (c) 2009-2010 Stephane Chatty
+
+This driver provides support for N-Trig pen and multi-touch sensors.  Single
+and multi-touch events are translated to the appropriate protocols for
+the hid and input systems.  Pen events are sufficiently hid compliant and
+are left to the hid core.  The driver also provides additional filtering
+and utility functions accessible with sysfs and module parameters.
+
+This driver has been reported to work properly with multiple N-Trig devices
+attached.
+
+
+Parameters
+----------
+
+Note: values set at load time are global and will apply to all applicable
+devices.  Adjusting parameters with sysfs will override the load time values,
+but only for that one device.
+
+The following parameters are used to configure filters to reduce noise:
+
+activate_slack		number of fingers to ignore before processing events
+
+activation_height	size threshold to activate immediately
+activation_width
+
+min_height		size threshold bellow which fingers are ignored
+min_width		both to decide activation and during activity
+
+deactivate_slack	the number of "no contact" frames to ignore before
+			propagating the end of activity events
+
+When the last finger is removed from the device, it sends a number of empty
+frames.  By holding off on deactivation for a few frames we can tolerate false
+erroneous disconnects, where the sensor may mistakenly not detect a finger that
+is still present.  Thus deactivate_slack addresses problems where a users might
+see breaks in lines during drawing, or drop an object during a long drag.
+
+
+Additional sysfs items
+----------------------
+
+These nodes just provide easy access to the ranges reported by the device.
+sensor_logical_height	the range for positions reported during activity
+sensor_logical_width
+
+sensor_physical_height	internal ranges not used for normal events but
+sensor_physical_width	useful for tuning
+
+All N-Trig devices with product id of 1 report events in the ranges of
+X: 0-9600
+Y: 0-7200
+However not all of these devices have the same physical dimensions.  Most
+seem to be 12" sensors (Dell Latitude XT and XT2 and the HP TX2), and
+at least one model (Dell Studio 17) has a 17" sensor.  The ratio of physical
+to logical sizes is used to adjust the size based filter parameters.
+
+
+Filtering
+---------
+
+With the release of the early multi-touch firmwares it became increasingly
+obvious that these sensors were prone to erroneous events.  Users reported
+seeing both inappropriately dropped contact and ghosts, contacts reported
+where no finger was actually touching the screen.
+
+Deactivation slack helps prevent dropped contact for single touch use, but does
+not address the problem of dropping one of more contacts while other contacts
+are still active.  Drops in the multi-touch context require additional
+processing and should be handled in tandem with tacking.
+
+As observed ghost contacts are similar to actual use of the sensor, but they
+seem to have different profiles.  Ghost activity typically shows up as small
+short lived touches.  As such, I assume that the longer the continuous stream
+of events the more likely those events are from a real contact, and that the
+larger the size of each contact the more likely it is real.  Balancing the
+goals of preventing ghosts and accepting real events quickly (to minimize
+user observable latency), the filter accumulates confidence for incoming
+events until it hits thresholds and begins propagating.  In the interest in
+minimizing stored state as well as the cost of operations to make a decision,
+I've kept that decision simple.
+
+Time is measured in terms of the number of fingers reported, not frames since
+the probability of multiple simultaneous ghosts is expected to drop off
+dramatically with increasing numbers.  Rather than accumulate weight as a
+function of size, I just use it as a binary threshold.  A sufficiently large
+contact immediately overrides the waiting period and leads to activation.
+
+Setting the activation size thresholds to large values will result in deciding
+primarily on activation slack.  If you see longer lived ghosts, turning up the
+activation slack while reducing the size thresholds may suffice to eliminate
+the ghosts while keeping the screen quite responsive to firm taps.
+
+Contacts continue to be filtered with min_height and min_width even after
+the initial activation filter is satisfied.  The intent is to provide
+a mechanism for filtering out ghosts in the form of an extra finger while
+you actually are using the screen.  In practice this sort of ghost has
+been far less problematic or relatively rare and I've left the defaults
+set to 0 for both parameters, effectively turning off that filter.
+
+I don't know what the optimal values are for these filters.  If the defaults
+don't work for you, please play with the parameters.  If you do find other
+values more comfortable, I would appreciate feedback.
+
+The calibration of these devices does drift over time.  If ghosts or contact
+dropping worsen and interfere with the normal usage of your device, try
+recalibrating it.
+
+
+Calibration
+-----------
+
+The N-Trig windows tools provide calibration and testing routines.  Also an
+unofficial unsupported set of user space tools including a calibrator is
+available at:
+http://code.launchpad.net/~rafi-seas/+junk/ntrig_calib
+
+
+Tracking
+--------
+
+As of yet, all tested N-Trig firmwares do not track fingers.  When multiple
+contacts are active they seem to be sorted primarily by Y position.
diff -druN linux-libre-2.6.36-gnu/Documentation/ioctl/ioctl-number.txt linux-libre-2.6.37-gnu/Documentation/ioctl/ioctl-number.txt
--- linux-libre-2.6.36-gnu/Documentation/ioctl/ioctl-number.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/ioctl/ioctl-number.txt	2011-01-04 19:50:19.000000000 -0500
@@ -259,7 +259,7 @@
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
 't'	90	linux/toshiba.h
-'u'	00-1F	linux/smb_fs.h
+'u'	00-1F	linux/smb_fs.h		gone
 'v'	all	linux/videodev.h	conflict!
 'v'	00-1F	linux/ext2_fs.h		conflict!
 'v'	00-1F	linux/fs.h		conflict!
@@ -278,7 +278,6 @@
 					<mailto:oe@port.de>
 'z'	10-4F	drivers/s390/crypto/zcrypt_api.h	conflict!
 0x80	00-1F	linux/fb.h
-0x81	00-1F	linux/videotext.h
 0x88	00-3F	media/ovcamchip.h
 0x89	00-06	arch/x86/include/asm/sockios.h
 0x89	0B-DF	linux/sockios.h
diff -druN linux-libre-2.6.36-gnu/Documentation/kbuild/kconfig-language.txt linux-libre-2.6.37-gnu/Documentation/kbuild/kconfig-language.txt
--- linux-libre-2.6.36-gnu/Documentation/kbuild/kconfig-language.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kbuild/kconfig-language.txt	2011-01-04 19:50:19.000000000 -0500
@@ -322,7 +322,8 @@
 	"mainmenu" <prompt>
 
 This sets the config program's title bar if the config program chooses
-to use it.
+to use it. It should be placed at the top of the configuration, before any
+other statement.
 
 
 Kconfig hints
diff -druN linux-libre-2.6.36-gnu/Documentation/kbuild/makefiles.txt linux-libre-2.6.37-gnu/Documentation/kbuild/makefiles.txt
--- linux-libre-2.6.36-gnu/Documentation/kbuild/makefiles.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kbuild/makefiles.txt	2011-01-04 19:50:19.000000000 -0500
@@ -776,6 +776,13 @@
 Kbuild will assume the directories to be in the same relative path as the
 Makefile if no absolute path is specified (path does not start with '/').
 
+To exclude certain files from make clean, use the $(no-clean-files) variable.
+This is only a special case used in the top level Kbuild file:
+
+	Example:
+		#Kbuild
+		no-clean-files := $(bounds-file) $(offsets-file)
+
 Usually kbuild descends down in subdirectories due to "obj-* := dir/",
 but in the architecture makefiles where the kbuild infrastructure
 is not sufficient this sometimes needs to be explicit.
diff -druN linux-libre-2.6.36-gnu/Documentation/kbuild/modules.txt linux-libre-2.6.37-gnu/Documentation/kbuild/modules.txt
--- linux-libre-2.6.36-gnu/Documentation/kbuild/modules.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kbuild/modules.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,215 +1,185 @@
+Building External Modules
 
-In this document you will find information about:
-- how to build external modules
-- how to make your module use the kbuild infrastructure
-- how kbuild will install a kernel
-- how to install modules in a non-standard location
+This document describes how to build an out-of-tree kernel module.
 
 === Table of Contents
 
 	=== 1 Introduction
-	=== 2 How to build external modules
-	   --- 2.1 Building external modules
-	   --- 2.2 Available targets
-	   --- 2.3 Available options
-	   --- 2.4 Preparing the kernel tree for module build
-	   --- 2.5 Building separate files for a module
-	=== 3. Example commands
-	=== 4. Creating a kbuild file for an external module
-	=== 5. Include files
-	   --- 5.1 How to include files from the kernel include dir
-	   --- 5.2 External modules using an include/ dir
-	   --- 5.3 External modules using several directories
-	=== 6. Module installation
-	   --- 6.1 INSTALL_MOD_PATH
-	   --- 6.2 INSTALL_MOD_DIR
-	=== 7. Module versioning & Module.symvers
-	   --- 7.1 Symbols from the kernel (vmlinux + modules)
-	   --- 7.2 Symbols and external modules
-	   --- 7.3 Symbols from another external module
-	=== 8. Tips & Tricks
-	   --- 8.1 Testing for CONFIG_FOO_BAR
+	=== 2 How to Build External Modules
+	   --- 2.1 Command Syntax
+	   --- 2.2 Options
+	   --- 2.3 Targets
+	   --- 2.4 Building Separate Files
+	=== 3. Creating a Kbuild File for an External Module
+	   --- 3.1 Shared Makefile
+	   --- 3.2 Separate Kbuild file and Makefile
+	   --- 3.3 Binary Blobs
+	   --- 3.4 Building Multiple Modules
+	=== 4. Include Files
+	   --- 4.1 Kernel Includes
+	   --- 4.2 Single Subdirectory
+	   --- 4.3 Several Subdirectories
+	=== 5. Module Installation
+	   --- 5.1 INSTALL_MOD_PATH
+	   --- 5.2 INSTALL_MOD_DIR
+	=== 6. Module Versioning
+	   --- 6.1 Symbols From the Kernel (vmlinux + modules)
+	   --- 6.2 Symbols and External Modules
+	   --- 6.3 Symbols From Another External Module
+	=== 7. Tips & Tricks
+	   --- 7.1 Testing for CONFIG_FOO_BAR
 
 
 
 === 1. Introduction
 
-kbuild includes functionality for building modules both
-within the kernel source tree and outside the kernel source tree.
-The latter is usually referred to as external or "out-of-tree"
-modules and is used both during development and for modules that
-are not planned to be included in the kernel tree.
-
-What is covered within this file is mainly information to authors
-of modules. The author of an external module should supply
-a makefile that hides most of the complexity, so one only has to type
-'make' to build the module. A complete example will be presented in
-chapter 4, "Creating a kbuild file for an external module".
-
-
-=== 2. How to build external modules
-
-kbuild offers functionality to build external modules, with the
-prerequisite that there is a pre-built kernel available with full source.
-A subset of the targets available when building the kernel is available
-when building an external module.
-
---- 2.1 Building external modules
+"kbuild" is the build system used by the Linux kernel. Modules must use
+kbuild to stay compatible with changes in the build infrastructure and
+to pick up the right flags to "gcc." Functionality for building modules
+both in-tree and out-of-tree is provided. The method for building
+either is similar, and all modules are initially developed and built
+out-of-tree.
 
-	Use the following command to build an external module:
+Covered in this document is information aimed at developers interested
+in building out-of-tree (or "external") modules. The author of an
+external module should supply a makefile that hides most of the
+complexity, so one only has to type "make" to build the module. This is
+easily accomplished, and a complete example will be presented in
+section 3.
 
-		make -C <path-to-kernel> M=`pwd`
 
-	For the running kernel use:
+=== 2. How to Build External Modules
 
-		make -C /lib/modules/`uname -r`/build M=`pwd`
+To build external modules, you must have a prebuilt kernel available
+that contains the configuration and header files used in the build.
+Also, the kernel must have been built with modules enabled. If you are
+using a distribution kernel, there will be a package for the kernel you
+are running provided by your distribution.
 
-	For the above command to succeed, the kernel must have been
-	built with modules enabled.
+An alternative is to use the "make" target "modules_prepare." This will
+make sure the kernel contains the information required. The target
+exists solely as a simple way to prepare a kernel source tree for
+building external modules.
 
-	To install the modules that were just built:
+NOTE: "modules_prepare" will not build Module.symvers even if
+CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be
+executed to make module versioning work.
 
-		make -C <path-to-kernel> M=`pwd` modules_install
+--- 2.1 Command Syntax
 
-	More complex examples will be shown later, the above should
-	be enough to get you started.
+	The command to build an external module is:
 
---- 2.2 Available targets
+		$ make -C <path_to_kernel_src> M=$PWD
 
-	$KDIR refers to the path to the kernel source top-level directory
+	The kbuild system knows that an external module is being built
+	due to the "M=<dir>" option given in the command.
 
-	make -C $KDIR M=`pwd`
-		Will build the module(s) located in current directory.
-		All output files will be located in the same directory
-		as the module source.
-		No attempts are made to update the kernel source, and it is
-		a precondition that a successful make has been executed
-		for the kernel.
+	To build against the running kernel use:
 
-	make -C $KDIR M=`pwd` modules
-		The modules target is implied when no target is given.
-		Same functionality as if no target was specified.
-		See description above.
+		$ make -C /lib/modules/`uname -r`/build M=$PWD
 
-	make -C $KDIR M=`pwd` modules_install
-		Install the external module(s).
-		Installation default is in /lib/modules/<kernel-version>/extra,
-		but may be prefixed with INSTALL_MOD_PATH - see separate
-		chapter.
+	Then to install the module(s) just built, add the target
+	"modules_install" to the command:
 
-	make -C $KDIR M=`pwd` clean
-		Remove all generated files for the module - the kernel
-		source directory is not modified.
+		$ make -C /lib/modules/`uname -r`/build M=$PWD modules_install
 
-	make -C $KDIR M=`pwd` help
-		help will list the available target when building external
-		modules.
+--- 2.2 Options
 
---- 2.3 Available options:
+	($KDIR refers to the path of the kernel source directory.)
 
-	$KDIR refers to the path to the kernel source top-level directory
+	make -C $KDIR M=$PWD
 
-	make -C $KDIR
-		Used to specify where to find the kernel source.
-		'$KDIR' represent the directory where the kernel source is.
-		Make will actually change directory to the specified directory
-		when executed but change back when finished.
+	-C $KDIR
+		The directory where the kernel source is located.
+		"make" will actually change to the specified directory
+		when executing and will change back when finished.
 
-	make -C $KDIR M=`pwd`
-		M= is used to tell kbuild that an external module is
-		being built.
-		The option given to M= is the directory where the external
-		module (kbuild file) is located.
-		When an external module is being built only a subset of the
-		usual targets are available.
+	M=$PWD
+		Informs kbuild that an external module is being built.
+		The value given to "M" is the absolute path of the
+		directory where the external module (kbuild file) is
+		located.
 
-	make -C $KDIR SUBDIRS=`pwd`
-		Same as M=. The SUBDIRS= syntax is kept for backwards
-		compatibility.
+--- 2.3 Targets
 
---- 2.4 Preparing the kernel tree for module build
+	When building an external module, only a subset of the "make"
+	targets are available.
 
-	To make sure the kernel contains the information required to
-	build external modules the target 'modules_prepare' must be used.
-	'modules_prepare' exists solely as a simple way to prepare
-	a kernel source tree for building external modules.
-	Note: modules_prepare will not build Module.symvers even if
-	CONFIG_MODVERSIONS is set. Therefore a full kernel build
-	needs to be executed to make module versioning work.
+	make -C $KDIR M=$PWD [target]
 
---- 2.5 Building separate files for a module
-	It is possible to build single files which are part of a module.
-	This works equally well for the kernel, a module and even for
-	external modules.
-	Examples (module foo.ko, consist of bar.o, baz.o):
-		make -C $KDIR M=`pwd` bar.lst
-		make -C $KDIR M=`pwd` bar.o
-		make -C $KDIR M=`pwd` foo.ko
-		make -C $KDIR M=`pwd` /
+	The default will build the module(s) located in the current
+	directory, so a target does not need to be specified. All
+	output files will also be generated in this directory. No
+	attempts are made to update the kernel source, and it is a
+	precondition that a successful "make" has been executed for the
+	kernel.
 
+	modules
+		The default target for external modules. It has the
+		same functionality as if no target was specified. See
+		description above.
 
-=== 3. Example commands
+	modules_install
+		Install the external module(s). The default location is
+		/lib/modules/<kernel_release>/extra/, but a prefix may
+		be added with INSTALL_MOD_PATH (discussed in section 5).
 
-This example shows the actual commands to be executed when building
-an external module for the currently running kernel.
-In the example below, the distribution is supposed to use the
-facility to locate output files for a kernel compile in a different
-directory than the kernel source - but the examples will also work
-when the source and the output files are mixed in the same directory.
+	clean
+		Remove all generated files in the module directory only.
 
-# Kernel source
-/lib/modules/<kernel-version>/source -> /usr/src/linux-<version>
+	help
+		List the available targets for external modules.
 
-# Output from kernel compile
-/lib/modules/<kernel-version>/build -> /usr/src/linux-<version>-up
+--- 2.4 Building Separate Files
 
-Change to the directory where the kbuild file is located and execute
-the following commands to build the module:
+	It is possible to build single files that are part of a module.
+	This works equally well for the kernel, a module, and even for
+	external modules.
 
-	cd /home/user/src/module
-	make -C /usr/src/`uname -r`/source            \
-	        O=/lib/modules/`uname-r`/build        \
-	        M=`pwd`
+	Example (The module foo.ko, consist of bar.o and baz.o):
+		make -C $KDIR M=$PWD bar.lst
+		make -C $KDIR M=$PWD baz.o
+		make -C $KDIR M=$PWD foo.ko
+		make -C $KDIR M=$PWD /
 
-Then, to install the module use the following command:
 
-	make -C /usr/src/`uname -r`/source            \
-	        O=/lib/modules/`uname-r`/build        \
-	        M=`pwd`                               \
-		modules_install
+=== 3. Creating a Kbuild File for an External Module
 
-If you look closely you will see that this is the same command as
-listed before - with the directories spelled out.
+In the last section we saw the command to build a module for the
+running kernel. The module is not actually built, however, because a
+build file is required. Contained in this file will be the name of
+the module(s) being built, along with the list of requisite source
+files. The file may be as simple as a single line:
 
-The above are rather long commands, and the following chapter
-lists a few tricks to make it all easier.
+	obj-m := <module_name>.o
 
+The kbuild system will build <module_name>.o from <module_name>.c,
+and, after linking, will result in the kernel module <module_name>.ko.
+The above line can be put in either a "Kbuild" file or a "Makefile."
+When the module is built from multiple sources, an additional line is
+needed listing the files:
 
-=== 4. Creating a kbuild file for an external module
+	<module_name>-y := <src1>.o <src2>.o ...
 
-kbuild is the build system for the kernel, and external modules
-must use kbuild to stay compatible with changes in the build system
-and to pick up the right flags to gcc etc.
+NOTE: Further documentation describing the syntax used by kbuild is
+located in Documentation/kbuild/makefiles.txt.
 
-The kbuild file used as input shall follow the syntax described
-in Documentation/kbuild/makefiles.txt. This chapter will introduce a few
-more tricks to be used when dealing with external modules.
+The examples below demonstrate how to create a build file for the
+module 8123.ko, which is built from the following files:
 
-In the following a Makefile will be created for a module with the
-following files:
 	8123_if.c
 	8123_if.h
 	8123_pci.c
 	8123_bin.o_shipped	<= Binary blob
 
---- 4.1 Shared Makefile for module and kernel
+--- 3.1 Shared Makefile
 
-	An external module always includes a wrapper Makefile supporting
-	building the module using 'make' with no arguments.
-	The Makefile provided will most likely include additional
-	functionality such as test targets etc. and this part shall
-	be filtered away from kbuild since it may impact kbuild if
-	name clashes occurs.
+	An external module always includes a wrapper makefile that
+	supports building the module using "make" with no arguments.
+	This target is not used by kbuild; it is only for convenience.
+	Additional functionality, such as test targets, can be included
+	but should be filtered out from kbuild due to possible name
+	clashes.
 
 	Example 1:
 		--> filename: Makefile
@@ -219,11 +189,11 @@
 		8123-y := 8123_if.o 8123_pci.o 8123_bin.o
 
 		else
-		# Normal Makefile
+		# normal makefile
+		KDIR ?= /lib/modules/`uname -r`/build
 
-		KERNELDIR := /lib/modules/`uname -r`/build
-		all::
-			$(MAKE) -C $(KERNELDIR) M=`pwd` $@
+		default:
+			$(MAKE) -C $(KDIR) M=$$PWD
 
 		# Module specific targets
 		genbin:
@@ -231,15 +201,20 @@
 
 		endif
 
-	In example 1, the check for KERNELRELEASE is used to separate
-	the two parts of the Makefile. kbuild will only see the two
-	assignments whereas make will see everything except the two
-	kbuild assignments.
+	The check for KERNELRELEASE is used to separate the two parts
+	of the makefile. In the example, kbuild will only see the two
+	assignments, whereas "make" will see everything except these
+	two assignments. This is due to two passes made on the file:
+	the first pass is by the "make" instance run on the command
+	line; the second pass is by the kbuild system, which is
+	initiated by the parameterized "make" in the default target.
 
-	In recent versions of the kernel, kbuild will look for a file named
-	Kbuild and as second option look for a file named Makefile.
-	Utilising the Kbuild file makes us split up the Makefile in example 1
-	into two files as shown in example 2:
+--- 3.2 Separate Kbuild File and Makefile
+
+	In newer versions of the kernel, kbuild will first look for a
+	file named "Kbuild," and only if that is not found, will it
+	then look for a makefile. Utilizing a "Kbuild" file allows us
+	to split up the makefile from example 1 into two files:
 
 	Example 2:
 		--> filename: Kbuild
@@ -247,20 +222,21 @@
 		8123-y := 8123_if.o 8123_pci.o 8123_bin.o
 
 		--> filename: Makefile
-		KERNELDIR := /lib/modules/`uname -r`/build
-		all::
-			$(MAKE) -C $(KERNELDIR) M=`pwd` $@
+		KDIR ?= /lib/modules/`uname -r`/build
+
+		default:
+			$(MAKE) -C $(KDIR) M=$$PWD
 
 		# Module specific targets
 		genbin:
 			echo "X" > 8123_bin.o_shipped
 
+	The split in example 2 is questionable due to the simplicity of
+	each file; however, some external modules use makefiles
+	consisting of several hundred lines, and here it really pays
+	off to separate the kbuild part from the rest.
 
-	In example 2, we are down to two fairly simple files and for simple
-	files as used in this example the split is questionable. But some
-	external modules use Makefiles of several hundred lines and here it
-	really pays off to separate the kbuild part from the rest.
-	Example 3 shows a backward compatible version.
+	The next example shows a backward compatible version.
 
 	Example 3:
 		--> filename: Kbuild
@@ -269,13 +245,15 @@
 
 		--> filename: Makefile
 		ifneq ($(KERNELRELEASE),)
+		# kbuild part of makefile
 		include Kbuild
+
 		else
-		# Normal Makefile
+		# normal makefile
+		KDIR ?= /lib/modules/`uname -r`/build
 
-		KERNELDIR := /lib/modules/`uname -r`/build
-		all::
-			$(MAKE) -C $(KERNELDIR) M=`pwd` $@
+		default:
+			$(MAKE) -C $(KDIR) M=$$PWD
 
 		# Module specific targets
 		genbin:
@@ -283,260 +261,271 @@
 
 		endif
 
-	The trick here is to include the Kbuild file from Makefile, so
-	if an older version of kbuild picks up the Makefile, the Kbuild
-	file will be included.
+	Here the "Kbuild" file is included from the makefile. This
+	allows an older version of kbuild, which only knows of
+	makefiles, to be used when the "make" and kbuild parts are
+	split into separate files.
 
---- 4.2 Binary blobs included in a module
+--- 3.3 Binary Blobs
 
-	Some external modules needs to include a .o as a blob. kbuild
-	has support for this, but requires the blob file to be named
-	<filename>_shipped. In our example the blob is named
-	8123_bin.o_shipped and when the kbuild rules kick in the file
-	8123_bin.o is created as a simple copy off the 8213_bin.o_shipped file
-	with the _shipped part stripped of the filename.
-	This allows the 8123_bin.o filename to be used in the assignment to
-	the module.
+	Some external modules need to include an object file as a blob.
+	kbuild has support for this, but requires the blob file to be
+	named <filename>_shipped. When the kbuild rules kick in, a copy
+	of <filename>_shipped is created with _shipped stripped off,
+	giving us <filename>. This shortened filename can be used in
+	the assignment to the module.
+
+	Throughout this section, 8123_bin.o_shipped has been used to
+	build the kernel module 8123.ko; it has been included as
+	8123_bin.o.
 
-	Example 4:
-		obj-m  := 8123.o
 		8123-y := 8123_if.o 8123_pci.o 8123_bin.o
 
-	In example 4, there is no distinction between the ordinary .c/.h files
-	and the binary file. But kbuild will pick up different rules to create
-	the .o file.
+	Although there is no distinction between the ordinary source
+	files and the binary file, kbuild will pick up different rules
+	when creating the object file for the module.
 
+--- 3.4 Building Multiple Modules
 
-=== 5. Include files
+	kbuild supports building multiple modules with a single build
+	file. For example, if you wanted to build two modules, foo.ko
+	and bar.ko, the kbuild lines would be:
 
-Include files are a necessity when a .c file uses something from other .c
-files (not strictly in the sense of C, but if good programming practice is
-used). Any module that consists of more than one .c file will have a .h file
-for one of the .c files.
+		obj-m := foo.o bar.o
+		foo-y := <foo_srcs>
+		bar-y := <bar_srcs>
 
-- If the .h file only describes a module internal interface, then the .h file
-  shall be placed in the same directory as the .c files.
-- If the .h files describe an interface used by other parts of the kernel
-  located in different directories, the .h files shall be located in
-  include/linux/ or other include/ directories as appropriate.
+	It is that simple!
 
-One exception for this rule is larger subsystems that have their own directory
-under include/ such as include/scsi. Another exception is arch-specific
-.h files which are located under include/asm-$(ARCH)/*.
 
-External modules have a tendency to locate include files in a separate include/
-directory and therefore need to deal with this in their kbuild file.
+=== 4. Include Files
 
---- 5.1 How to include files from the kernel include dir
+Within the kernel, header files are kept in standard locations
+according to the following rule:
 
-	When a module needs to include a file from include/linux/, then one
-	just uses:
+	* If the header file only describes the internal interface of a
+	  module, then the file is placed in the same directory as the
+	  source files.
+	* If the header file describes an interface used by other parts
+	  of the kernel that are located in different directories, then
+	  the file is placed in include/linux/.
 
-		#include <linux/modules.h>
+	  NOTE: There are two notable exceptions to this rule: larger
+	  subsystems have their own directory under include/, such as
+	  include/scsi; and architecture specific headers are located
+	  under arch/$(ARCH)/include/.
 
-	kbuild will make sure to add options to gcc so the relevant
-	directories are searched.
-	Likewise for .h files placed in the same directory as the .c file.
+--- 4.1 Kernel Includes
 
-		#include "8123_if.h"
+	To include a header file located under include/linux/, simply
+	use:
 
-	will do the job.
+		#include <linux/module.h>
 
---- 5.2 External modules using an include/ dir
+	kbuild will add options to "gcc" so the relevant directories
+	are searched.
 
-	External modules often locate their .h files in a separate include/
-	directory although this is not usual kernel style. When an external
-	module uses an include/ dir then kbuild needs to be told so.
-	The trick here is to use either EXTRA_CFLAGS (take effect for all .c
-	files) or CFLAGS_$F.o (take effect only for a single file).
+--- 4.2 Single Subdirectory
 
-	In our example, if we move 8123_if.h to a subdirectory named include/
-	the resulting Kbuild file would look like:
+	External modules tend to place header files in a separate
+	include/ directory where their source is located, although this
+	is not the usual kernel style. To inform kbuild of the
+	directory, use either ccflags-y or CFLAGS_<filename>.o.
+
+	Using the example from section 3, if we moved 8123_if.h to a
+	subdirectory named include, the resulting kbuild file would
+	look like:
 
 		--> filename: Kbuild
-		obj-m  := 8123.o
+		obj-m := 8123.o
 
-		EXTRA_CFLAGS := -Iinclude
+		ccflags-y := -Iinclude
 		8123-y := 8123_if.o 8123_pci.o 8123_bin.o
 
-	Note that in the assignment there is no space between -I and the path.
-	This is a kbuild limitation:  there must be no space present.
-
---- 5.3 External modules using several directories
+	Note that in the assignment there is no space between -I and
+	the path. This is a limitation of kbuild: there must be no
+	space present.
 
-	If an external module does not follow the usual kernel style, but
-	decides to spread files over several directories, then kbuild can
-	handle this too.
+--- 4.3 Several Subdirectories
 
+	kbuild can handle files that are spread over several directories.
 	Consider the following example:
 
-	|
-	+- src/complex_main.c
-	|   +- hal/hardwareif.c
-	|   +- hal/include/hardwareif.h
-	+- include/complex.h
+	.
+	|__ src
+	|   |__ complex_main.c
+	|   |__ hal
+	|	|__ hardwareif.c
+	|	|__ include
+	|	    |__ hardwareif.h
+	|__ include
+	    |__ complex.h
 
-	To build a single module named complex.ko, we then need the following
+	To build the module complex.ko, we then need the following
 	kbuild file:
 
-	Kbuild:
+		--> filename: Kbuild
 		obj-m := complex.o
 		complex-y := src/complex_main.o
 		complex-y += src/hal/hardwareif.o
 
-		EXTRA_CFLAGS := -I$(src)/include
-		EXTRA_CFLAGS += -I$(src)src/hal/include
+		ccflags-y := -I$(src)/include
+		ccflags-y += -I$(src)/src/hal/include
 
+	As you can see, kbuild knows how to handle object files located
+	in other directories. The trick is to specify the directory
+	relative to the kbuild file's location. That being said, this
+	is NOT recommended practice.
 
-	kbuild knows how to handle .o files located in another directory -
-	although this is NOT recommended practice. The syntax is to specify
-	the directory relative to the directory where the Kbuild file is
-	located.
+	For the header files, kbuild must be explicitly told where to
+	look. When kbuild executes, the current directory is always the
+	root of the kernel tree (the argument to "-C") and therefore an
+	absolute path is needed. $(src) provides the absolute path by
+	pointing to the directory where the currently executing kbuild
+	file is located.
 
-	To find the .h files, we have to explicitly tell kbuild where to look
-	for the .h files. When kbuild executes, the current directory is always
-	the root of the kernel tree (argument to -C) and therefore we have to
-	tell kbuild how to find the .h files using absolute paths.
-	$(src) will specify the absolute path to the directory where the
-	Kbuild file are located when being build as an external module.
-	Therefore -I$(src)/ is used to point out the directory of the Kbuild
-	file and any additional path are just appended.
 
-=== 6. Module installation
+=== 5. Module Installation
 
-Modules which are included in the kernel are installed in the directory:
+Modules which are included in the kernel are installed in the
+directory:
 
-	/lib/modules/$(KERNELRELEASE)/kernel
+	/lib/modules/$(KERNELRELEASE)/kernel/
 
-External modules are installed in the directory:
+And external modules are installed in:
 
-	/lib/modules/$(KERNELRELEASE)/extra
+	/lib/modules/$(KERNELRELEASE)/extra/
 
---- 6.1 INSTALL_MOD_PATH
+--- 5.1 INSTALL_MOD_PATH
 
-	Above are the default directories, but as always, some level of
-	customization is possible. One can prefix the path using the variable
-	INSTALL_MOD_PATH:
+	Above are the default directories but as always some level of
+	customization is possible. A prefix can be added to the
+	installation path using the variable INSTALL_MOD_PATH:
 
 		$ make INSTALL_MOD_PATH=/frodo modules_install
-		=> Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel
-
-	INSTALL_MOD_PATH may be set as an ordinary shell variable or as in the
-	example above, can be specified on the command line when calling make.
-	INSTALL_MOD_PATH has effect both when installing modules included in
-	the kernel as well as when installing external modules.
+		=> Install dir: /frodo/lib/modules/$(KERNELRELEASE)/kernel/
 
---- 6.2 INSTALL_MOD_DIR
+	INSTALL_MOD_PATH may be set as an ordinary shell variable or,
+	as shown above, can be specified on the command line when
+	calling "make." This has effect when installing both in-tree
+	and out-of-tree modules.
 
-	When installing external modules they are by default installed to a
-	directory under /lib/modules/$(KERNELRELEASE)/extra, but one may wish
-	to locate modules for a specific functionality in a separate
-	directory. For this purpose, one can use INSTALL_MOD_DIR to specify an
-	alternative name to 'extra'.
+--- 5.2 INSTALL_MOD_DIR
 
-		$ make INSTALL_MOD_DIR=gandalf -C KERNELDIR \
-			M=`pwd` modules_install
-		=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
+	External modules are by default installed to a directory under
+	/lib/modules/$(KERNELRELEASE)/extra/, but you may wish to
+	locate modules for a specific functionality in a separate
+	directory. For this purpose, use INSTALL_MOD_DIR to specify an
+	alternative name to "extra."
 
+		$ make INSTALL_MOD_DIR=gandalf -C $KDIR \
+		       M=$PWD modules_install
+		=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf/
 
-=== 7. Module versioning & Module.symvers
 
-Module versioning is enabled by the CONFIG_MODVERSIONS tag.
+=== 6. Module Versioning
 
-Module versioning is used as a simple ABI consistency check. The Module
-versioning creates a CRC value of the full prototype for an exported symbol and
-when a module is loaded/used then the CRC values contained in the kernel are
-compared with similar values in the module. If they are not equal, then the
-kernel refuses to load the module.
+Module versioning is enabled by the CONFIG_MODVERSIONS tag, and is used
+as a simple ABI consistency check. A CRC value of the full prototype
+for an exported symbol is created. When a module is loaded/used, the
+CRC values contained in the kernel are compared with similar values in
+the module; if they are not equal, the kernel refuses to load the
+module.
 
-Module.symvers contains a list of all exported symbols from a kernel build.
+Module.symvers contains a list of all exported symbols from a kernel
+build.
 
---- 7.1 Symbols from the kernel (vmlinux + modules)
+--- 6.1 Symbols From the Kernel (vmlinux + modules)
 
-	During a kernel build, a file named Module.symvers will be generated.
-	Module.symvers contains all exported symbols from the kernel and
-	compiled modules. For each symbols, the corresponding CRC value
-	is stored too.
+	During a kernel build, a file named Module.symvers will be
+	generated. Module.symvers contains all exported symbols from
+	the kernel and compiled modules. For each symbol, the
+	corresponding CRC value is also stored.
 
 	The syntax of the Module.symvers file is:
-		<CRC>       <Symbol>           <module>
-	Sample:
+		<CRC>	    <Symbol>	       <module>
+
 		0x2d036834  scsi_remove_host   drivers/scsi/scsi_mod
 
-	For a kernel build without CONFIG_MODVERSIONS enabled, the crc
-	would read: 0x00000000
+	For a kernel build without CONFIG_MODVERSIONS enabled, the CRC
+	would read 0x00000000.
 
 	Module.symvers serves two purposes:
-	1) It lists all exported symbols both from vmlinux and all modules
-	2) It lists the CRC if CONFIG_MODVERSIONS is enabled
+	1) It lists all exported symbols from vmlinux and all modules.
+	2) It lists the CRC if CONFIG_MODVERSIONS is enabled.
 
---- 7.2 Symbols and external modules
+--- 6.2 Symbols and External Modules
 
-	When building an external module, the build system needs access to
-	the symbols from the kernel to check if all external symbols are
-	defined. This is done in the MODPOST step and to obtain all
-	symbols, modpost reads Module.symvers from the kernel.
-	If a Module.symvers file is present in the directory where
-	the external module is being built, this file will be read too.
-	During the MODPOST step, a new Module.symvers file will be written
-	containing all exported symbols that were not defined in the kernel.
+	When building an external module, the build system needs access
+	to the symbols from the kernel to check if all external symbols
+	are defined. This is done in the MODPOST step. modpost obtains
+	the symbols by reading Module.symvers from the kernel source
+	tree. If a Module.symvers file is present in the directory
+	where the external module is being built, this file will be
+	read too. During the MODPOST step, a new Module.symvers file
+	will be written containing all exported symbols that were not
+	defined in the kernel.
 
---- 7.3 Symbols from another external module
+--- 6.3 Symbols From Another External Module
 
-	Sometimes, an external module uses exported symbols from another
-	external module. Kbuild needs to have full knowledge on all symbols
-	to avoid spitting out warnings about undefined symbols.
-	Three solutions exist to let kbuild know all symbols of more than
-	one external module.
-	The method with a top-level kbuild file is recommended but may be
-	impractical in certain situations.
+	Sometimes, an external module uses exported symbols from
+	another external module. kbuild needs to have full knowledge of
+	all symbols to avoid spitting out warnings about undefined
+	symbols. Three solutions exist for this situation.
 
-	Use a top-level Kbuild file
-		If you have two modules: 'foo' and 'bar', and 'foo' needs
-		symbols from 'bar', then one can use a common top-level kbuild
-		file so both modules are compiled in same build.
+	NOTE: The method with a top-level kbuild file is recommended
+	but may be impractical in certain situations.
 
-		Consider following directory layout:
-		./foo/ <= contains the foo module
-		./bar/ <= contains the bar module
-		The top-level Kbuild file would then look like:
+	Use a top-level kbuild file
+		If you have two modules, foo.ko and bar.ko, where
+		foo.ko needs symbols from bar.ko, you can use a
+		common top-level kbuild file so both modules are
+		compiled in the same build. Consider the following
+		directory layout:
 
-		#./Kbuild: (this file may also be named Makefile)
+		./foo/ <= contains foo.ko
+		./bar/ <= contains bar.ko
+
+		The top-level kbuild file would then look like:
+
+		#./Kbuild (or ./Makefile):
 			obj-y := foo/ bar/
 
-		Executing:
-			make -C $KDIR M=`pwd`
+		And executing
 
-		will then do the expected and compile both modules with full
-		knowledge on symbols from both modules.
+			$ make -C $KDIR M=$PWD
+
+		will then do the expected and compile both modules with
+		full knowledge of symbols from either module.
 
 	Use an extra Module.symvers file
-		When an external module is built, a Module.symvers file is
-		generated containing all exported symbols which are not
-		defined in the kernel.
-		To get access to symbols from module 'bar', one can copy the
-		Module.symvers file from the compilation of the 'bar' module
-		to the directory where the 'foo' module is built.
-		During the module build, kbuild will read the Module.symvers
-		file in the directory of the external module and when the
-		build is finished, a new Module.symvers file is created
-		containing the sum of all symbols defined and not part of the
-		kernel.
+		When an external module is built, a Module.symvers file
+		is generated containing all exported symbols which are
+		not defined in the kernel. To get access to symbols
+		from bar.ko, copy the Module.symvers file from the
+		compilation of bar.ko to the directory where foo.ko is
+		built. During the module build, kbuild will read the
+		Module.symvers file in the directory of the external
+		module, and when the build is finished, a new
+		Module.symvers file is created containing the sum of
+		all symbols defined and not part of the kernel.
 
-	Use make variable KBUILD_EXTRA_SYMBOLS in the Makefile
-		If it is impractical to copy Module.symvers from another
-		module, you can assign a space separated list of files to
-		KBUILD_EXTRA_SYMBOLS in your Makfile. These files will be
-		loaded by modpost during the initialisation of its symbol
-		tables.
+	Use "make" variable KBUILD_EXTRA_SYMBOLS
+		If it is impractical to copy Module.symvers from
+		another module, you can assign a space separated list
+		of files to KBUILD_EXTRA_SYMBOLS in your build file.
+		These files will be loaded by modpost during the
+		initialization of its symbol tables.
 
-=== 8. Tips & Tricks
 
---- 8.1 Testing for CONFIG_FOO_BAR
+=== 7. Tips & Tricks
 
-	Modules often need to check for certain CONFIG_ options to decide if
-	a specific feature shall be included in the module. When kbuild is used
-	this is done by referencing the CONFIG_ variable directly.
+--- 7.1 Testing for CONFIG_FOO_BAR
+
+	Modules often need to check for certain CONFIG_ options to
+	decide if a specific feature is included in the module. In
+	kbuild this is done by referencing the CONFIG_ variable
+	directly.
 
 		#fs/ext2/Makefile
 		obj-$(CONFIG_EXT2_FS) += ext2.o
@@ -544,9 +533,9 @@
 		ext2-y := balloc.o bitmap.o dir.o
 		ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
 
-	External modules have traditionally used grep to check for specific
-	CONFIG_ settings directly in .config. This usage is broken.
-	As introduced before, external modules shall use kbuild when building
-	and therefore can use the same methods as in-kernel modules when
-	testing for CONFIG_ definitions.
+	External modules have traditionally used "grep" to check for
+	specific CONFIG_ settings directly in .config. This usage is
+	broken. As introduced before, external modules should use
+	kbuild for building and can therefore use the same methods as
+	in-tree modules when testing for CONFIG_ definitions.
 
diff -druN linux-libre-2.6.36-gnu/Documentation/kernel-parameters.txt linux-libre-2.6.37-gnu/Documentation/kernel-parameters.txt
--- linux-libre-2.6.36-gnu/Documentation/kernel-parameters.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kernel-parameters.txt	2011-01-04 19:50:19.000000000 -0500
@@ -43,10 +43,11 @@
 	AVR32	AVR32 architecture is enabled.
 	AX25	Appropriate AX.25 support is enabled.
 	BLACKFIN Blackfin architecture is enabled.
-	DRM	Direct Rendering Management support is enabled.
 	EDD	BIOS Enhanced Disk Drive Services (EDD) is enabled
 	EFI	EFI Partitioning (GPT) is enabled
 	EIDE	EIDE/ATAPI support is enabled.
+	DRM	Direct Rendering Management support is enabled.
+	DYNAMIC_DEBUG Build in debug messages and enable them at runtime
 	FB	The frame buffer device is enabled.
 	GCOV	GCOV profiling is enabled.
 	HW	Appropriate hardware is enabled.
@@ -455,7 +456,7 @@
 			[ARM] imx_timer1,OSTS,netx_timer,mpu_timer2,
 				pxa_timer,timer3,32k_counter,timer0_1
 			[AVR32] avr32
-			[X86-32] pit,hpet,tsc,vmi-timer;
+			[X86-32] pit,hpet,tsc;
 				scx200_hrt on Geode; cyclone on IBM x440
 			[MIPS] MIPS
 			[PARISC] cr16
@@ -570,6 +571,10 @@
 			Format: <port#>,<type>
 			See also Documentation/input/joystick-parport.txt
 
+	ddebug_query=   [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot
+			time. See Documentation/dynamic-debug-howto.txt for
+			details.
+
 	debug		[KNL] Enable kernel debugging (events log level).
 
 	debug_locks_verbose=
@@ -701,7 +706,7 @@
 			arch/x86/kernel/cpu/cpufreq/elanfreq.c.
 
 	elevator=	[IOSCHED]
-			Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
+			Format: {"cfq" | "deadline" | "noop"}
 			See Documentation/block/as-iosched.txt and
 			Documentation/block/deadline-iosched.txt for details.
 
@@ -1126,9 +1131,13 @@
 	kvm.oos_shadow=	[KVM] Disable out-of-sync shadow paging.
 			Default is 1 (enabled)
 
-	kvm-amd.nested=	[KVM,AMD] Allow nested virtualization in KVM/SVM.
+	kvm.mmu_audit=	[KVM] This is a R/W parameter which allows audit
+			KVM MMU at runtime.
 			Default is 0 (off)
 
+	kvm-amd.nested=	[KVM,AMD] Allow nested virtualization in KVM/SVM.
+			Default is 1 (enabled)
+
 	kvm-amd.npt=	[KVM,AMD] Disable nested paging (virtualized MMU)
 			for all guests.
 			Default is 1 (enabled) if in 64bit or 32bit-PAE mode
@@ -1532,12 +1541,15 @@
 			1 to enable accounting
 			Default value is 0.
 
-	nfsaddrs=	[NFS]
+	nfsaddrs=	[NFS] Deprecated.  Use ip= instead.
 			See Documentation/filesystems/nfs/nfsroot.txt.
 
 	nfsroot=	[NFS] nfs root filesystem for disk-less boxes.
 			See Documentation/filesystems/nfs/nfsroot.txt.
 
+	nfsrootdebug	[NFS] enable nfsroot debugging messages.
+			See Documentation/filesystems/nfs/nfsroot.txt.
+
 	nfs.callback_tcpport=
 			[NFS] set the TCP port on which the NFSv4 callback
 			channel should listen.
@@ -1693,6 +1705,8 @@
 
 	nojitter	[IA64] Disables jitter checking for ITC timers.
 
+	no-kvmclock	[X86,KVM] Disable paravirtualized KVM clock driver
+
 	nolapic		[X86-32,APIC] Do not enable or use the local APIC.
 
 	nolapic_timer	[X86-32,APIC] Do not use the local APIC timer.
@@ -1713,7 +1727,7 @@
 	norandmaps	Don't use address space randomization.  Equivalent to
 			echo 0 > /proc/sys/kernel/randomize_va_space
 
-	noreplace-paravirt	[X86-32,PV_OPS] Don't patch paravirt_ops
+	noreplace-paravirt	[X86,IA-64,PV_OPS] Don't patch paravirt_ops
 
 	noreplace-smp	[X86-32,SMP] Don't replace SMP instructions
 			with UP alternatives
@@ -1745,7 +1759,7 @@
 
 	nousb		[USB] Disable the USB subsystem
 
-	nowatchdog	[KNL] Disable the lockup detector.
+	nowatchdog	[KNL] Disable the lockup detector (NMI watchdog).
 
 	nowb		[ARM]
 
@@ -2153,6 +2167,11 @@
 			Reserves a hole at the top of the kernel virtual
 			address space.
 
+	reservelow=	[X86]
+			Format: nn[K]
+			Set the amount of memory to reserve for BIOS at
+			the bottom of the address space.
+
 	reset_devices	[KNL] Force drivers to reset the underlying device
 			during initialization.
 
@@ -2165,6 +2184,11 @@
 			in <PAGE_SIZE> units (needed only for swap files).
 			See  Documentation/power/swsusp-and-swap-files.txt
 
+	hibernate=	[HIBERNATION]
+		noresume	Don't check if there's a hibernation image
+				present during boot.
+		nocompress	Don't compress/decompress hibernation images.
+
 	retain_initrd	[RAM] Keep initrd memory after extraction
 
 	rhash_entries=	[KNL,NET]
@@ -2356,10 +2380,24 @@
 			improve throughput, but will also increase the
 			amount of memory reserved for use by the client.
 
+	swapaccount[=0|1]
+			[KNL] Enable accounting of swap in memory resource
+			controller if no parameter or 1 is given or disable
+			it if 0 is given (See Documentation/cgroups/memory.txt)
+
 	swiotlb=	[IA-64] Number of I/O TLB slabs
 
 	switches=	[HW,M68k]
 
+	sysfs.deprecated=0|1 [KNL]
+			Enable/disable old style sysfs layout for old udev
+			on older distributions. When this option is enabled
+			very new udev will not work anymore. When this option
+			is disabled (or CONFIG_SYSFS_DEPRECATED not compiled)
+			in older udev will not work anymore.
+			Default depends on CONFIG_SYSFS_DEPRECATED_V2 set in
+			the kernel configuration.
+
 	sysrq_always_enabled
 			[KNL]
 			Ignore sysrq setting - this boot parameter will
@@ -2408,7 +2446,7 @@
 			topology informations if the hardware supports these.
 			The scheduler will make use of these informations and
 			e.g. base its process migration decisions on it.
-			Default is off.
+			Default is on.
 
 	tp720=		[HW,PS2]
 
@@ -2435,6 +2473,10 @@
 			disables clocksource verification at runtime.
 			Used to enable high-resolution timer mode on older
 			hardware, and in virtualized environment.
+			[x86] noirqtime: Do not use TSC to do irq accounting.
+			Used to run time disable IRQ_TIME_ACCOUNTING on any
+			platforms where RDTSC is slow and this accounting
+			can add overhead.
 
 	turbografx.map[2|3]=	[HW,JOY]
 			TurboGraFX parallel port interface
diff -druN linux-libre-2.6.36-gnu/Documentation/kprobes.txt linux-libre-2.6.37-gnu/Documentation/kprobes.txt
--- linux-libre-2.6.36-gnu/Documentation/kprobes.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kprobes.txt	2011-01-04 19:50:19.000000000 -0500
@@ -542,9 +542,11 @@
 registration and unregistration.
 
 Probe handlers are run with preemption disabled.  Depending on the
-architecture, handlers may also run with interrupts disabled.  In any
-case, your handler should not yield the CPU (e.g., by attempting to
-acquire a semaphore).
+architecture and optimization state, handlers may also run with
+interrupts disabled (e.g., kretprobe handlers and optimized kprobe
+handlers run without interrupt disabled on x86/x86-64).  In any case,
+your handler should not yield the CPU (e.g., by attempting to acquire
+a semaphore).
 
 Since a return probe is implemented by replacing the return
 address with the trampoline's address, stack backtraces and calls
diff -druN linux-libre-2.6.36-gnu/Documentation/kvm/api.txt linux-libre-2.6.37-gnu/Documentation/kvm/api.txt
--- linux-libre-2.6.36-gnu/Documentation/kvm/api.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/kvm/api.txt	2011-01-04 19:50:19.000000000 -0500
@@ -320,13 +320,13 @@
 4.15 KVM_INTERRUPT
 
 Capability: basic
-Architectures: x86
+Architectures: x86, ppc
 Type: vcpu ioctl
 Parameters: struct kvm_interrupt (in)
 Returns: 0 on success, -1 on error
 
 Queues a hardware interrupt vector to be injected.  This is only
-useful if in-kernel local APIC is not used.
+useful if in-kernel local APIC or equivalent is not used.
 
 /* for KVM_INTERRUPT */
 struct kvm_interrupt {
@@ -334,8 +334,37 @@
 	__u32 irq;
 };
 
+X86:
+
 Note 'irq' is an interrupt vector, not an interrupt pin or line.
 
+PPC:
+
+Queues an external interrupt to be injected. This ioctl is overleaded
+with 3 different irq values:
+
+a) KVM_INTERRUPT_SET
+
+  This injects an edge type external interrupt into the guest once it's ready
+  to receive interrupts. When injected, the interrupt is done.
+
+b) KVM_INTERRUPT_UNSET
+
+  This unsets any pending interrupt.
+
+  Only available with KVM_CAP_PPC_UNSET_IRQ.
+
+c) KVM_INTERRUPT_SET_LEVEL
+
+  This injects a level type external interrupt into the guest context. The
+  interrupt stays pending until a specific ioctl with KVM_INTERRUPT_UNSET
+  is triggered.
+
+  Only available with KVM_CAP_PPC_IRQ_LEVEL.
+
+Note that any value for 'irq' other than the ones stated above is invalid
+and incurs unexpected behavior.
+
 4.16 KVM_DEBUG_GUEST
 
 Capability: basic
@@ -1013,8 +1042,9 @@
 entries in the 'entries' array, which is then filled.
 
 The entries returned are the host cpuid as returned by the cpuid instruction,
-with unknown or unsupported features masked out.  The fields in each entry
-are defined as follows:
+with unknown or unsupported features masked out.  Some features (for example,
+x2apic), may not be present in the host cpu, but are exposed by kvm if it can
+emulate them efficiently. The fields in each entry are defined as follows:
 
   function: the eax value used to obtain the entry
   index: the ecx value used to obtain the entry (for entries that are
@@ -1032,6 +1062,29 @@
    eax, ebx, ecx, edx: the values returned by the cpuid instruction for
          this function/index combination
 
+4.46 KVM_PPC_GET_PVINFO
+
+Capability: KVM_CAP_PPC_GET_PVINFO
+Architectures: ppc
+Type: vm ioctl
+Parameters: struct kvm_ppc_pvinfo (out)
+Returns: 0 on success, !0 on error
+
+struct kvm_ppc_pvinfo {
+	__u32 flags;
+	__u32 hcall[4];
+	__u8  pad[108];
+};
+
+This ioctl fetches PV specific information that need to be passed to the guest
+using the device tree or other means from vm context.
+
+For now the only implemented piece of information distributed here is an array
+of 4 instructions that make up a hypercall.
+
+If any additional field gets added to this structure later on, a bit for that
+additional piece of information will be set in the flags bitmap.
+
 5. The kvm_run structure
 
 Application code obtains a pointer to the kvm_run structure by
diff -druN linux-libre-2.6.36-gnu/Documentation/kvm/ppc-pv.txt linux-libre-2.6.37-gnu/Documentation/kvm/ppc-pv.txt
--- linux-libre-2.6.36-gnu/Documentation/kvm/ppc-pv.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/kvm/ppc-pv.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,196 @@
+The PPC KVM paravirtual interface
+=================================
+
+The basic execution principle by which KVM on PowerPC works is to run all kernel
+space code in PR=1 which is user space. This way we trap all privileged
+instructions and can emulate them accordingly.
+
+Unfortunately that is also the downfall. There are quite some privileged
+instructions that needlessly return us to the hypervisor even though they
+could be handled differently.
+
+This is what the PPC PV interface helps with. It takes privileged instructions
+and transforms them into unprivileged ones with some help from the hypervisor.
+This cuts down virtualization costs by about 50% on some of my benchmarks.
+
+The code for that interface can be found in arch/powerpc/kernel/kvm*
+
+Querying for existence
+======================
+
+To find out if we're running on KVM or not, we leverage the device tree. When
+Linux is running on KVM, a node /hypervisor exists. That node contains a
+compatible property with the value "linux,kvm".
+
+Once you determined you're running under a PV capable KVM, you can now use
+hypercalls as described below.
+
+KVM hypercalls
+==============
+
+Inside the device tree's /hypervisor node there's a property called
+'hypercall-instructions'. This property contains at most 4 opcodes that make
+up the hypercall. To call a hypercall, just call these instructions.
+
+The parameters are as follows:
+
+	Register	IN			OUT
+
+	r0		-			volatile
+	r3		1st parameter		Return code
+	r4		2nd parameter		1st output value
+	r5		3rd parameter		2nd output value
+	r6		4th parameter		3rd output value
+	r7		5th parameter		4th output value
+	r8		6th parameter		5th output value
+	r9		7th parameter		6th output value
+	r10		8th parameter		7th output value
+	r11		hypercall number	8th output value
+	r12		-			volatile
+
+Hypercall definitions are shared in generic code, so the same hypercall numbers
+apply for x86 and powerpc alike with the exception that each KVM hypercall
+also needs to be ORed with the KVM vendor code which is (42 << 16).
+
+Return codes can be as follows:
+
+	Code		Meaning
+
+	0		Success
+	12		Hypercall not implemented
+	<0		Error
+
+The magic page
+==============
+
+To enable communication between the hypervisor and guest there is a new shared
+page that contains parts of supervisor visible register state. The guest can
+map this shared page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE.
+
+With this hypercall issued the guest always gets the magic page mapped at the
+desired location in effective and physical address space. For now, we always
+map the page to -4096. This way we can access it using absolute load and store
+functions. The following instruction reads the first field of the magic page:
+
+	ld	rX, -4096(0)
+
+The interface is designed to be extensible should there be need later to add
+additional registers to the magic page. If you add fields to the magic page,
+also define a new hypercall feature to indicate that the host can give you more
+registers. Only if the host supports the additional features, make use of them.
+
+The magic page has the following layout as described in
+arch/powerpc/include/asm/kvm_para.h:
+
+struct kvm_vcpu_arch_shared {
+	__u64 scratch1;
+	__u64 scratch2;
+	__u64 scratch3;
+	__u64 critical;		/* Guest may not get interrupts if == r1 */
+	__u64 sprg0;
+	__u64 sprg1;
+	__u64 sprg2;
+	__u64 sprg3;
+	__u64 srr0;
+	__u64 srr1;
+	__u64 dar;
+	__u64 msr;
+	__u32 dsisr;
+	__u32 int_pending;	/* Tells the guest if we have an interrupt */
+};
+
+Additions to the page must only occur at the end. Struct fields are always 32
+or 64 bit aligned, depending on them being 32 or 64 bit wide respectively.
+
+Magic page features
+===================
+
+When mapping the magic page using the KVM hypercall KVM_HC_PPC_MAP_MAGIC_PAGE,
+a second return value is passed to the guest. This second return value contains
+a bitmap of available features inside the magic page.
+
+The following enhancements to the magic page are currently available:
+
+  KVM_MAGIC_FEAT_SR		Maps SR registers r/w in the magic page
+
+For enhanced features in the magic page, please check for the existence of the
+feature before using them!
+
+MSR bits
+========
+
+The MSR contains bits that require hypervisor intervention and bits that do
+not require direct hypervisor intervention because they only get interpreted
+when entering the guest or don't have any impact on the hypervisor's behavior.
+
+The following bits are safe to be set inside the guest:
+
+  MSR_EE
+  MSR_RI
+  MSR_CR
+  MSR_ME
+
+If any other bit changes in the MSR, please still use mtmsr(d).
+
+Patched instructions
+====================
+
+The "ld" and "std" instructions are transormed to "lwz" and "stw" instructions
+respectively on 32 bit systems with an added offset of 4 to accomodate for big
+endianness.
+
+The following is a list of mapping the Linux kernel performs when running as
+guest. Implementing any of those mappings is optional, as the instruction traps
+also act on the shared page. So calling privileged instructions still works as
+before.
+
+From			To
+====			==
+
+mfmsr	rX		ld	rX, magic_page->msr
+mfsprg	rX, 0		ld	rX, magic_page->sprg0
+mfsprg	rX, 1		ld	rX, magic_page->sprg1
+mfsprg	rX, 2		ld	rX, magic_page->sprg2
+mfsprg	rX, 3		ld	rX, magic_page->sprg3
+mfsrr0	rX		ld	rX, magic_page->srr0
+mfsrr1	rX		ld	rX, magic_page->srr1
+mfdar	rX		ld	rX, magic_page->dar
+mfdsisr	rX		lwz	rX, magic_page->dsisr
+
+mtmsr	rX		std	rX, magic_page->msr
+mtsprg	0, rX		std	rX, magic_page->sprg0
+mtsprg	1, rX		std	rX, magic_page->sprg1
+mtsprg	2, rX		std	rX, magic_page->sprg2
+mtsprg	3, rX		std	rX, magic_page->sprg3
+mtsrr0	rX		std	rX, magic_page->srr0
+mtsrr1	rX		std	rX, magic_page->srr1
+mtdar	rX		std	rX, magic_page->dar
+mtdsisr	rX		stw	rX, magic_page->dsisr
+
+tlbsync			nop
+
+mtmsrd	rX, 0		b	<special mtmsr section>
+mtmsr	rX		b	<special mtmsr section>
+
+mtmsrd	rX, 1		b	<special mtmsrd section>
+
+[Book3S only]
+mtsrin	rX, rY		b	<special mtsrin section>
+
+[BookE only]
+wrteei	[0|1]		b	<special wrteei section>
+
+
+Some instructions require more logic to determine what's going on than a load
+or store instruction can deliver. To enable patching of those, we keep some
+RAM around where we can live translate instructions to. What happens is the
+following:
+
+	1) copy emulation code to memory
+	2) patch that code to fit the emulated instruction
+	3) patch that code to return to the original pc + 4
+	4) patch the original instruction to branch to the new code
+
+That way we can inject an arbitrary amount of code as replacement for a single
+instruction. This allows us to check for pending interrupts when setting EE=1
+for example.
diff -druN linux-libre-2.6.36-gnu/Documentation/kvm/timekeeping.txt linux-libre-2.6.37-gnu/Documentation/kvm/timekeeping.txt
--- linux-libre-2.6.36-gnu/Documentation/kvm/timekeeping.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/kvm/timekeeping.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,612 @@
+
+	Timekeeping Virtualization for X86-Based Architectures
+
+	Zachary Amsden <zamsden@redhat.com>
+	Copyright (c) 2010, Red Hat.  All rights reserved.
+
+1) Overview
+2) Timing Devices
+3) TSC Hardware
+4) Virtualization Problems
+
+=========================================================================
+
+1) Overview
+
+One of the most complicated parts of the X86 platform, and specifically,
+the virtualization of this platform is the plethora of timing devices available
+and the complexity of emulating those devices.  In addition, virtualization of
+time introduces a new set of challenges because it introduces a multiplexed
+division of time beyond the control of the guest CPU.
+
+First, we will describe the various timekeeping hardware available, then
+present some of the problems which arise and solutions available, giving
+specific recommendations for certain classes of KVM guests.
+
+The purpose of this document is to collect data and information relevant to
+timekeeping which may be difficult to find elsewhere, specifically,
+information relevant to KVM and hardware-based virtualization.
+
+=========================================================================
+
+2) Timing Devices
+
+First we discuss the basic hardware devices available.  TSC and the related
+KVM clock are special enough to warrant a full exposition and are described in
+the following section.
+
+2.1) i8254 - PIT
+
+One of the first timer devices available is the programmable interrupt timer,
+or PIT.  The PIT has a fixed frequency 1.193182 MHz base clock and three
+channels which can be programmed to deliver periodic or one-shot interrupts.
+These three channels can be configured in different modes and have individual
+counters.  Channel 1 and 2 were not available for general use in the original
+IBM PC, and historically were connected to control RAM refresh and the PC
+speaker.  Now the PIT is typically integrated as part of an emulated chipset
+and a separate physical PIT is not used.
+
+The PIT uses I/O ports 0x40 - 0x43.  Access to the 16-bit counters is done
+using single or multiple byte access to the I/O ports.  There are 6 modes
+available, but not all modes are available to all timers, as only timer 2
+has a connected gate input, required for modes 1 and 5.  The gate line is
+controlled by port 61h, bit 0, as illustrated in the following diagram.
+
+ --------------             ----------------
+|              |           |                |
+|  1.1932 MHz  |---------->| CLOCK      OUT | ---------> IRQ 0
+|    Clock     |   |       |                |
+ --------------    |    +->| GATE  TIMER 0  |
+                   |        ----------------
+                   |
+                   |        ----------------
+                   |       |                |
+                   |------>| CLOCK      OUT | ---------> 66.3 KHZ DRAM
+                   |       |                |            (aka /dev/null)
+                   |    +->| GATE  TIMER 1  |
+                   |        ----------------
+                   |
+                   |        ----------------
+                   |       |                |
+                   |------>| CLOCK      OUT | ---------> Port 61h, bit 5
+                           |                |      |
+Port 61h, bit 0 ---------->| GATE  TIMER 2  |       \_.----   ____
+                            ----------------         _|    )--|LPF|---Speaker
+                                                    / *----   \___/
+Port 61h, bit 1 -----------------------------------/
+
+The timer modes are now described.
+
+Mode 0: Single Timeout.   This is a one-shot software timeout that counts down
+ when the gate is high (always true for timers 0 and 1).  When the count
+ reaches zero, the output goes high.
+
+Mode 1: Triggered One-shot.  The output is intially set high.  When the gate
+ line is set high, a countdown is initiated (which does not stop if the gate is
+ lowered), during which the output is set low.  When the count reaches zero,
+ the output goes high.
+
+Mode 2: Rate Generator.  The output is initially set high.  When the countdown
+ reaches 1, the output goes low for one count and then returns high.  The value
+ is reloaded and the countdown automatically resumes.  If the gate line goes
+ low, the count is halted.  If the output is low when the gate is lowered, the
+ output automatically goes high (this only affects timer 2).
+
+Mode 3: Square Wave.   This generates a high / low square wave.  The count
+ determines the length of the pulse, which alternates between high and low
+ when zero is reached.  The count only proceeds when gate is high and is
+ automatically reloaded on reaching zero.  The count is decremented twice at
+ each clock to generate a full high / low cycle at the full periodic rate.
+ If the count is even, the clock remains high for N/2 counts and low for N/2
+ counts; if the clock is odd, the clock is high for (N+1)/2 counts and low
+ for (N-1)/2 counts.  Only even values are latched by the counter, so odd
+ values are not observed when reading.  This is the intended mode for timer 2,
+ which generates sine-like tones by low-pass filtering the square wave output.
+
+Mode 4: Software Strobe.  After programming this mode and loading the counter,
+ the output remains high until the counter reaches zero.  Then the output
+ goes low for 1 clock cycle and returns high.  The counter is not reloaded.
+ Counting only occurs when gate is high.
+
+Mode 5: Hardware Strobe.  After programming and loading the counter, the
+ output remains high.  When the gate is raised, a countdown is initiated
+ (which does not stop if the gate is lowered).  When the counter reaches zero,
+ the output goes low for 1 clock cycle and then returns high.  The counter is
+ not reloaded.
+
+In addition to normal binary counting, the PIT supports BCD counting.  The
+command port, 0x43 is used to set the counter and mode for each of the three
+timers.
+
+PIT commands, issued to port 0x43, using the following bit encoding:
+
+Bit 7-4: Command (See table below)
+Bit 3-1: Mode (000 = Mode 0, 101 = Mode 5, 11X = undefined)
+Bit 0  : Binary (0) / BCD (1)
+
+Command table:
+
+0000 - Latch Timer 0 count for port 0x40
+	sample and hold the count to be read in port 0x40;
+	additional commands ignored until counter is read;
+	mode bits ignored.
+
+0001 - Set Timer 0 LSB mode for port 0x40
+	set timer to read LSB only and force MSB to zero;
+	mode bits set timer mode
+
+0010 - Set Timer 0 MSB mode for port 0x40
+	set timer to read MSB only and force LSB to zero;
+	mode bits set timer mode
+
+0011 - Set Timer 0 16-bit mode for port 0x40
+	set timer to read / write LSB first, then MSB;
+	mode bits set timer mode
+
+0100 - Latch Timer 1 count for port 0x41 - as described above
+0101 - Set Timer 1 LSB mode for port 0x41 - as described above
+0110 - Set Timer 1 MSB mode for port 0x41 - as described above
+0111 - Set Timer 1 16-bit mode for port 0x41 - as described above
+
+1000 - Latch Timer 2 count for port 0x42 - as described above
+1001 - Set Timer 2 LSB mode for port 0x42 - as described above
+1010 - Set Timer 2 MSB mode for port 0x42 - as described above
+1011 - Set Timer 2 16-bit mode for port 0x42 as described above
+
+1101 - General counter latch
+	Latch combination of counters into corresponding ports
+	Bit 3 = Counter 2
+	Bit 2 = Counter 1
+	Bit 1 = Counter 0
+	Bit 0 = Unused
+
+1110 - Latch timer status
+	Latch combination of counter mode into corresponding ports
+	Bit 3 = Counter 2
+	Bit 2 = Counter 1
+	Bit 1 = Counter 0
+
+	The output of ports 0x40-0x42 following this command will be:
+
+	Bit 7 = Output pin
+	Bit 6 = Count loaded (0 if timer has expired)
+	Bit 5-4 = Read / Write mode
+	    01 = MSB only
+	    10 = LSB only
+	    11 = LSB / MSB (16-bit)
+	Bit 3-1 = Mode
+	Bit 0 = Binary (0) / BCD mode (1)
+
+2.2) RTC
+
+The second device which was available in the original PC was the MC146818 real
+time clock.  The original device is now obsolete, and usually emulated by the
+system chipset, sometimes by an HPET and some frankenstein IRQ routing.
+
+The RTC is accessed through CMOS variables, which uses an index register to
+control which bytes are read.  Since there is only one index register, read
+of the CMOS and read of the RTC require lock protection (in addition, it is
+dangerous to allow userspace utilities such as hwclock to have direct RTC
+access, as they could corrupt kernel reads and writes of CMOS memory).
+
+The RTC generates an interrupt which is usually routed to IRQ 8.  The interrupt
+can function as a periodic timer, an additional once a day alarm, and can issue
+interrupts after an update of the CMOS registers by the MC146818 is complete.
+The type of interrupt is signalled in the RTC status registers.
+
+The RTC will update the current time fields by battery power even while the
+system is off.  The current time fields should not be read while an update is
+in progress, as indicated in the status register.
+
+The clock uses a 32.768kHz crystal, so bits 6-4 of register A should be
+programmed to a 32kHz divider if the RTC is to count seconds.
+
+This is the RAM map originally used for the RTC/CMOS:
+
+Location    Size    Description
+------------------------------------------
+00h         byte    Current second (BCD)
+01h         byte    Seconds alarm (BCD)
+02h         byte    Current minute (BCD)
+03h         byte    Minutes alarm (BCD)
+04h         byte    Current hour (BCD)
+05h         byte    Hours alarm (BCD)
+06h         byte    Current day of week (BCD)
+07h         byte    Current day of month (BCD)
+08h         byte    Current month (BCD)
+09h         byte    Current year (BCD)
+0Ah         byte    Register A
+                       bit 7   = Update in progress
+                       bit 6-4 = Divider for clock
+                                  000 = 4.194 MHz
+                                  001 = 1.049 MHz
+                                  010 = 32 kHz
+                                  10X = test modes
+                                  110 = reset / disable
+                                  111 = reset / disable
+                       bit 3-0 = Rate selection for periodic interrupt
+                                  000 = periodic timer disabled
+                                  001 = 3.90625 uS
+                                  010 = 7.8125 uS
+                                  011 = .122070 mS
+                                  100 = .244141 mS
+                                     ...
+                                 1101 = 125 mS
+                                 1110 = 250 mS
+                                 1111 = 500 mS
+0Bh         byte    Register B
+                       bit 7   = Run (0) / Halt (1)
+                       bit 6   = Periodic interrupt enable
+                       bit 5   = Alarm interrupt enable
+                       bit 4   = Update-ended interrupt enable
+                       bit 3   = Square wave interrupt enable
+                       bit 2   = BCD calendar (0) / Binary (1)
+                       bit 1   = 12-hour mode (0) / 24-hour mode (1)
+                       bit 0   = 0 (DST off) / 1 (DST enabled)
+OCh         byte    Register C (read only)
+                       bit 7   = interrupt request flag (IRQF)
+                       bit 6   = periodic interrupt flag (PF)
+                       bit 5   = alarm interrupt flag (AF)
+                       bit 4   = update interrupt flag (UF)
+                       bit 3-0 = reserved
+ODh         byte    Register D (read only)
+                       bit 7   = RTC has power
+                       bit 6-0 = reserved
+32h         byte    Current century BCD (*)
+  (*) location vendor specific and now determined from ACPI global tables
+
+2.3) APIC
+
+On Pentium and later processors, an on-board timer is available to each CPU
+as part of the Advanced Programmable Interrupt Controller.  The APIC is
+accessed through memory-mapped registers and provides interrupt service to each
+CPU, used for IPIs and local timer interrupts.
+
+Although in theory the APIC is a safe and stable source for local interrupts,
+in practice, many bugs and glitches have occurred due to the special nature of
+the APIC CPU-local memory-mapped hardware.  Beware that CPU errata may affect
+the use of the APIC and that workarounds may be required.  In addition, some of
+these workarounds pose unique constraints for virtualization - requiring either
+extra overhead incurred from extra reads of memory-mapped I/O or additional
+functionality that may be more computationally expensive to implement.
+
+Since the APIC is documented quite well in the Intel and AMD manuals, we will
+avoid repetition of the detail here.  It should be pointed out that the APIC
+timer is programmed through the LVT (local vector timer) register, is capable
+of one-shot or periodic operation, and is based on the bus clock divided down
+by the programmable divider register.
+
+2.4) HPET
+
+HPET is quite complex, and was originally intended to replace the PIT / RTC
+support of the X86 PC.  It remains to be seen whether that will be the case, as
+the de facto standard of PC hardware is to emulate these older devices.  Some
+systems designated as legacy free may support only the HPET as a hardware timer
+device.
+
+The HPET spec is rather loose and vague, requiring at least 3 hardware timers,
+but allowing implementation freedom to support many more.  It also imposes no
+fixed rate on the timer frequency, but does impose some extremal values on
+frequency, error and slew.
+
+In general, the HPET is recommended as a high precision (compared to PIT /RTC)
+time source which is independent of local variation (as there is only one HPET
+in any given system).  The HPET is also memory-mapped, and its presence is
+indicated through ACPI tables by the BIOS.
+
+Detailed specification of the HPET is beyond the current scope of this
+document, as it is also very well documented elsewhere.
+
+2.5) Offboard Timers
+
+Several cards, both proprietary (watchdog boards) and commonplace (e1000) have
+timing chips built into the cards which may have registers which are accessible
+to kernel or user drivers.  To the author's knowledge, using these to generate
+a clocksource for a Linux or other kernel has not yet been attempted and is in
+general frowned upon as not playing by the agreed rules of the game.  Such a
+timer device would require additional support to be virtualized properly and is
+not considered important at this time as no known operating system does this.
+
+=========================================================================
+
+3) TSC Hardware
+
+The TSC or time stamp counter is relatively simple in theory; it counts
+instruction cycles issued by the processor, which can be used as a measure of
+time.  In practice, due to a number of problems, it is the most complicated
+timekeeping device to use.
+
+The TSC is represented internally as a 64-bit MSR which can be read with the
+RDMSR, RDTSC, or RDTSCP (when available) instructions.  In the past, hardware
+limitations made it possible to write the TSC, but generally on old hardware it
+was only possible to write the low 32-bits of the 64-bit counter, and the upper
+32-bits of the counter were cleared.  Now, however, on Intel processors family
+0Fh, for models 3, 4 and 6, and family 06h, models e and f, this restriction
+has been lifted and all 64-bits are writable.  On AMD systems, the ability to
+write the TSC MSR is not an architectural guarantee.
+
+The TSC is accessible from CPL-0 and conditionally, for CPL > 0 software by
+means of the CR4.TSD bit, which when enabled, disables CPL > 0 TSC access.
+
+Some vendors have implemented an additional instruction, RDTSCP, which returns
+atomically not just the TSC, but an indicator which corresponds to the
+processor number.  This can be used to index into an array of TSC variables to
+determine offset information in SMP systems where TSCs are not synchronized.
+The presence of this instruction must be determined by consulting CPUID feature
+bits.
+
+Both VMX and SVM provide extension fields in the virtualization hardware which
+allows the guest visible TSC to be offset by a constant.  Newer implementations
+promise to allow the TSC to additionally be scaled, but this hardware is not
+yet widely available.
+
+3.1) TSC synchronization
+
+The TSC is a CPU-local clock in most implementations.  This means, on SMP
+platforms, the TSCs of different CPUs may start at different times depending
+on when the CPUs are powered on.  Generally, CPUs on the same die will share
+the same clock, however, this is not always the case.
+
+The BIOS may attempt to resynchronize the TSCs during the poweron process and
+the operating system or other system software may attempt to do this as well.
+Several hardware limitations make the problem worse - if it is not possible to
+write the full 64-bits of the TSC, it may be impossible to match the TSC in
+newly arriving CPUs to that of the rest of the system, resulting in
+unsynchronized TSCs.  This may be done by BIOS or system software, but in
+practice, getting a perfectly synchronized TSC will not be possible unless all
+values are read from the same clock, which generally only is possible on single
+socket systems or those with special hardware support.
+
+3.2) TSC and CPU hotplug
+
+As touched on already, CPUs which arrive later than the boot time of the system
+may not have a TSC value that is synchronized with the rest of the system.
+Either system software, BIOS, or SMM code may actually try to establish the TSC
+to a value matching the rest of the system, but a perfect match is usually not
+a guarantee.  This can have the effect of bringing a system from a state where
+TSC is synchronized back to a state where TSC synchronization flaws, however
+small, may be exposed to the OS and any virtualization environment.
+
+3.3) TSC and multi-socket / NUMA
+
+Multi-socket systems, especially large multi-socket systems are likely to have
+individual clocksources rather than a single, universally distributed clock.
+Since these clocks are driven by different crystals, they will not have
+perfectly matched frequency, and temperature and electrical variations will
+cause the CPU clocks, and thus the TSCs to drift over time.  Depending on the
+exact clock and bus design, the drift may or may not be fixed in absolute
+error, and may accumulate over time.
+
+In addition, very large systems may deliberately slew the clocks of individual
+cores.  This technique, known as spread-spectrum clocking, reduces EMI at the
+clock frequency and harmonics of it, which may be required to pass FCC
+standards for telecommunications and computer equipment.
+
+It is recommended not to trust the TSCs to remain synchronized on NUMA or
+multiple socket systems for these reasons.
+
+3.4) TSC and C-states
+
+C-states, or idling states of the processor, especially C1E and deeper sleep
+states may be problematic for TSC as well.  The TSC may stop advancing in such
+a state, resulting in a TSC which is behind that of other CPUs when execution
+is resumed.  Such CPUs must be detected and flagged by the operating system
+based on CPU and chipset identifications.
+
+The TSC in such a case may be corrected by catching it up to a known external
+clocksource.
+
+3.5) TSC frequency change / P-states
+
+To make things slightly more interesting, some CPUs may change frequency.  They
+may or may not run the TSC at the same rate, and because the frequency change
+may be staggered or slewed, at some points in time, the TSC rate may not be
+known other than falling within a range of values.  In this case, the TSC will
+not be a stable time source, and must be calibrated against a known, stable,
+external clock to be a usable source of time.
+
+Whether the TSC runs at a constant rate or scales with the P-state is model
+dependent and must be determined by inspecting CPUID, chipset or vendor
+specific MSR fields.
+
+In addition, some vendors have known bugs where the P-state is actually
+compensated for properly during normal operation, but when the processor is
+inactive, the P-state may be raised temporarily to service cache misses from
+other processors.  In such cases, the TSC on halted CPUs could advance faster
+than that of non-halted processors.  AMD Turion processors are known to have
+this problem.
+
+3.6) TSC and STPCLK / T-states
+
+External signals given to the processor may also have the effect of stopping
+the TSC.  This is typically done for thermal emergency power control to prevent
+an overheating condition, and typically, there is no way to detect that this
+condition has happened.
+
+3.7) TSC virtualization - VMX
+
+VMX provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP
+instructions, which is enough for full virtualization of TSC in any manner.  In
+addition, VMX allows passing through the host TSC plus an additional TSC_OFFSET
+field specified in the VMCS.  Special instructions must be used to read and
+write the VMCS field.
+
+3.8) TSC virtualization - SVM
+
+SVM provides conditional trapping of RDTSC, RDMSR, WRMSR and RDTSCP
+instructions, which is enough for full virtualization of TSC in any manner.  In
+addition, SVM allows passing through the host TSC plus an additional offset
+field specified in the SVM control block.
+
+3.9) TSC feature bits in Linux
+
+In summary, there is no way to guarantee the TSC remains in perfect
+synchronization unless it is explicitly guaranteed by the architecture.  Even
+if so, the TSCs in multi-sockets or NUMA systems may still run independently
+despite being locally consistent.
+
+The following feature bits are used by Linux to signal various TSC attributes,
+but they can only be taken to be meaningful for UP or single node systems.
+
+X86_FEATURE_TSC 		: The TSC is available in hardware
+X86_FEATURE_RDTSCP		: The RDTSCP instruction is available
+X86_FEATURE_CONSTANT_TSC 	: The TSC rate is unchanged with P-states
+X86_FEATURE_NONSTOP_TSC		: The TSC does not stop in C-states
+X86_FEATURE_TSC_RELIABLE	: TSC sync checks are skipped (VMware)
+
+4) Virtualization Problems
+
+Timekeeping is especially problematic for virtualization because a number of
+challenges arise.  The most obvious problem is that time is now shared between
+the host and, potentially, a number of virtual machines.  Thus the virtual
+operating system does not run with 100% usage of the CPU, despite the fact that
+it may very well make that assumption.  It may expect it to remain true to very
+exacting bounds when interrupt sources are disabled, but in reality only its
+virtual interrupt sources are disabled, and the machine may still be preempted
+at any time.  This causes problems as the passage of real time, the injection
+of machine interrupts and the associated clock sources are no longer completely
+synchronized with real time.
+
+This same problem can occur on native harware to a degree, as SMM mode may
+steal cycles from the naturally on X86 systems when SMM mode is used by the
+BIOS, but not in such an extreme fashion.  However, the fact that SMM mode may
+cause similar problems to virtualization makes it a good justification for
+solving many of these problems on bare metal.
+
+4.1) Interrupt clocking
+
+One of the most immediate problems that occurs with legacy operating systems
+is that the system timekeeping routines are often designed to keep track of
+time by counting periodic interrupts.  These interrupts may come from the PIT
+or the RTC, but the problem is the same: the host virtualization engine may not
+be able to deliver the proper number of interrupts per second, and so guest
+time may fall behind.  This is especially problematic if a high interrupt rate
+is selected, such as 1000 HZ, which is unfortunately the default for many Linux
+guests.
+
+There are three approaches to solving this problem; first, it may be possible
+to simply ignore it.  Guests which have a separate time source for tracking
+'wall clock' or 'real time' may not need any adjustment of their interrupts to
+maintain proper time.  If this is not sufficient, it may be necessary to inject
+additional interrupts into the guest in order to increase the effective
+interrupt rate.  This approach leads to complications in extreme conditions,
+where host load or guest lag is too much to compensate for, and thus another
+solution to the problem has risen: the guest may need to become aware of lost
+ticks and compensate for them internally.  Although promising in theory, the
+implementation of this policy in Linux has been extremely error prone, and a
+number of buggy variants of lost tick compensation are distributed across
+commonly used Linux systems.
+
+Windows uses periodic RTC clocking as a means of keeping time internally, and
+thus requires interrupt slewing to keep proper time.  It does use a low enough
+rate (ed: is it 18.2 Hz?) however that it has not yet been a problem in
+practice.
+
+4.2) TSC sampling and serialization
+
+As the highest precision time source available, the cycle counter of the CPU
+has aroused much interest from developers.  As explained above, this timer has
+many problems unique to its nature as a local, potentially unstable and
+potentially unsynchronized source.  One issue which is not unique to the TSC,
+but is highlighted because of its very precise nature is sampling delay.  By
+definition, the counter, once read is already old.  However, it is also
+possible for the counter to be read ahead of the actual use of the result.
+This is a consequence of the superscalar execution of the instruction stream,
+which may execute instructions out of order.  Such execution is called
+non-serialized.  Forcing serialized execution is necessary for precise
+measurement with the TSC, and requires a serializing instruction, such as CPUID
+or an MSR read.
+
+Since CPUID may actually be virtualized by a trap and emulate mechanism, this
+serialization can pose a performance issue for hardware virtualization.  An
+accurate time stamp counter reading may therefore not always be available, and
+it may be necessary for an implementation to guard against "backwards" reads of
+the TSC as seen from other CPUs, even in an otherwise perfectly synchronized
+system.
+
+4.3) Timespec aliasing
+
+Additionally, this lack of serialization from the TSC poses another challenge
+when using results of the TSC when measured against another time source.  As
+the TSC is much higher precision, many possible values of the TSC may be read
+while another clock is still expressing the same value.
+
+That is, you may read (T,T+10) while external clock C maintains the same value.
+Due to non-serialized reads, you may actually end up with a range which
+fluctuates - from (T-1.. T+10).  Thus, any time calculated from a TSC, but
+calibrated against an external value may have a range of valid values.
+Re-calibrating this computation may actually cause time, as computed after the
+calibration, to go backwards, compared with time computed before the
+calibration.
+
+This problem is particularly pronounced with an internal time source in Linux,
+the kernel time, which is expressed in the theoretically high resolution
+timespec - but which advances in much larger granularity intervals, sometimes
+at the rate of jiffies, and possibly in catchup modes, at a much larger step.
+
+This aliasing requires care in the computation and recalibration of kvmclock
+and any other values derived from TSC computation (such as TSC virtualization
+itself).
+
+4.4) Migration
+
+Migration of a virtual machine raises problems for timekeeping in two ways.
+First, the migration itself may take time, during which interrupts cannot be
+delivered, and after which, the guest time may need to be caught up.  NTP may
+be able to help to some degree here, as the clock correction required is
+typically small enough to fall in the NTP-correctable window.
+
+An additional concern is that timers based off the TSC (or HPET, if the raw bus
+clock is exposed) may now be running at different rates, requiring compensation
+in some way in the hypervisor by virtualizing these timers.  In addition,
+migrating to a faster machine may preclude the use of a passthrough TSC, as a
+faster clock cannot be made visible to a guest without the potential of time
+advancing faster than usual.  A slower clock is less of a problem, as it can
+always be caught up to the original rate.  KVM clock avoids these problems by
+simply storing multipliers and offsets against the TSC for the guest to convert
+back into nanosecond resolution values.
+
+4.5) Scheduling
+
+Since scheduling may be based on precise timing and firing of interrupts, the
+scheduling algorithms of an operating system may be adversely affected by
+virtualization.  In theory, the effect is random and should be universally
+distributed, but in contrived as well as real scenarios (guest device access,
+causes of virtualization exits, possible context switch), this may not always
+be the case.  The effect of this has not been well studied.
+
+In an attempt to work around this, several implementations have provided a
+paravirtualized scheduler clock, which reveals the true amount of CPU time for
+which a virtual machine has been running.
+
+4.6) Watchdogs
+
+Watchdog timers, such as the lock detector in Linux may fire accidentally when
+running under hardware virtualization due to timer interrupts being delayed or
+misinterpretation of the passage of real time.  Usually, these warnings are
+spurious and can be ignored, but in some circumstances it may be necessary to
+disable such detection.
+
+4.7) Delays and precision timing
+
+Precise timing and delays may not be possible in a virtualized system.  This
+can happen if the system is controlling physical hardware, or issues delays to
+compensate for slower I/O to and from devices.  The first issue is not solvable
+in general for a virtualized system; hardware control software can't be
+adequately virtualized without a full real-time operating system, which would
+require an RT aware virtualization platform.
+
+The second issue may cause performance problems, but this is unlikely to be a
+significant issue.  In many cases these delays may be eliminated through
+configuration or paravirtualization.
+
+4.8) Covert channels and leaks
+
+In addition to the above problems, time information will inevitably leak to the
+guest about the host in anything but a perfect implementation of virtualized
+time.  This may allow the guest to infer the presence of a hypervisor (as in a
+red-pill type detection), and it may allow information to leak between guests
+by using CPU utilization itself as a signalling channel.  Preventing such
+problems would require completely isolated virtual time which may not track
+real time any longer.  This may be useful in certain security or QA contexts,
+but in general isn't recommended for real-world deployment scenarios.
diff -druN linux-libre-2.6.36-gnu/Documentation/leds/leds-lp5521.txt linux-libre-2.6.37-gnu/Documentation/leds/leds-lp5521.txt
--- linux-libre-2.6.36-gnu/Documentation/leds/leds-lp5521.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/leds/leds-lp5521.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,88 @@
+Kernel driver for lp5521
+========================
+
+* National Semiconductor LP5521 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5521.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+
+LP5521 can drive up to 3 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5521:channelx, where x is 0 .. 2
+
+All three channels can be also controlled using the engine micro programs.
+More details of the instructions can be found from the public data sheet.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : store program (visible only in engine load mode)
+
+Example (start to blink the channel 2 led):
+cd   /sys/class/leds/lp5521:channel2/device
+echo "load" > engine3_mode
+echo "037f4d0003ff6000" > engine3_load
+echo "run" > engine3_mode
+
+stop the engine:
+echo "disabled" > engine3_mode
+
+sysfs contains a selftest entry.
+The test communicates with the chip and checks that
+the clock mode is automatically set to the requested one.
+
+Each channel has its own led current settings.
+/sys/class/leds/lp5521:channel0/led_current - RW
+/sys/class/leds/lp5521:channel0/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+example platform data:
+
+Note: chan_nr can have values between 0 and 2.
+
+static struct lp5521_led_config lp5521_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+		.max_current    = 130,
+        }, {
+                .chan_nr        = 1,
+                .led_current    = 0,
+		.max_current    = 130,
+        }, {
+                .chan_nr        = 2,
+                .led_current    = 0,
+		.max_current    = 130,
+        }
+};
+
+static int lp5521_setup(void)
+{
+	/* setup HW resources */
+}
+
+static void lp5521_release(void)
+{
+	/* Release HW resources */
+}
+
+static void lp5521_enable(bool state)
+{
+	/* Control of chip enable signal */
+}
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+        .setup_resources   = lp5521_setup,
+        .release_resources = lp5521_release,
+        .enable            = lp5521_enable,
+};
+
+If the current is set to 0 in the platform data, that channel is
+disabled and it is not visible in the sysfs.
diff -druN linux-libre-2.6.36-gnu/Documentation/leds/leds-lp5523.txt linux-libre-2.6.37-gnu/Documentation/leds/leds-lp5523.txt
--- linux-libre-2.6.36-gnu/Documentation/leds/leds-lp5523.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/leds/leds-lp5523.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,83 @@
+Kernel driver for lp5523
+========================
+
+* National Semiconductor LP5523 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5523.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+LP5523 can drive up to 9 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5523:channelx where x is 0...8
+
+The chip provides 3 engines. Each engine can control channels without
+interaction from the main CPU. Details of the micro engine code can be found
+from the public data sheet. Leds can be muxed to different channels.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : microcode load (visible only in load mode)
+enginex_leds : led mux control (visible only in load mode)
+
+cd /sys/class/leds/lp5523:channel2/device
+echo "load" > engine3_mode
+echo "9d80400004ff05ff437f0000" > engine3_load
+echo "111111111" > engine3_leds
+echo "run" > engine3_mode
+
+sysfs contains a selftest entry. It measures each channel
+voltage level and checks if it looks reasonable. If the level is too high,
+the led is missing; if the level is too low, there is a short circuit.
+
+Selftest uses always the current from the platform data.
+
+Each channel contains led current settings.
+/sys/class/leds/lp5523:channel2/led_current - RW
+/sys/class/leds/lp5523:channel2/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+Example platform data:
+
+Note - chan_nr can have values between 0 and 8.
+
+static struct lp5523_led_config lp5523_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+		.max_current    = 130,
+        },
+...
+        }, {
+                .chan_nr        = 8,
+                .led_current    = 50,
+		.max_current    = 130,
+        }
+};
+
+static int lp5523_setup(void)
+{
+	/* Setup HW resources */
+}
+
+static void lp5523_release(void)
+{
+	/* Release HW resources */
+}
+
+static void lp5523_enable(bool state)
+{
+	/* Control chip enable signal */
+}
+
+static struct lp5523_platform_data lp5523_platform_data = {
+        .led_config     = lp5523_led_config,
+        .num_channels   = ARRAY_SIZE(lp5523_led_config),
+        .clock_mode     = LP5523_CLOCK_EXT,
+        .setup_resources   = lp5523_setup,
+        .release_resources = lp5523_release,
+        .enable            = lp5523_enable,
+};
diff -druN linux-libre-2.6.36-gnu/Documentation/leds-class.txt linux-libre-2.6.37-gnu/Documentation/leds-class.txt
--- linux-libre-2.6.36-gnu/Documentation/leds-class.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/leds-class.txt	2011-01-04 19:50:19.000000000 -0500
@@ -60,15 +60,18 @@
 
 Some LEDs can be programmed to blink without any CPU interaction. To
 support this feature, a LED driver can optionally implement the
-blink_set() function (see <linux/leds.h>). If implemented, triggers can
-attempt to use it before falling back to software timers. The blink_set()
-function should return 0 if the blink setting is supported, or -EINVAL
-otherwise, which means that LED blinking will be handled by software.
+blink_set() function (see <linux/leds.h>). To set an LED to blinking,
+however, it is better to use use the API function led_blink_set(),
+as it will check and implement software fallback if necessary.
 
-The blink_set() function should choose a user friendly blinking
-value if it is called with *delay_on==0 && *delay_off==0 parameters. In
-this case the driver should give back the chosen value through delay_on
-and delay_off parameters to the leds subsystem.
+To turn off blinking again, use the API function led_brightness_set()
+as that will not just set the LED brightness but also stop any software
+timers that may have been required for blinking.
+
+The blink_set() function should choose a user friendly blinking value
+if it is called with *delay_on==0 && *delay_off==0 parameters. In this
+case the driver should give back the chosen value through delay_on and
+delay_off parameters to the leds subsystem.
 
 Setting the brightness to zero with brightness_set() callback function
 should completely turn off the LED and cancel the previously programmed
diff -druN linux-libre-2.6.36-gnu/Documentation/lguest/lguest.c linux-libre-2.6.37-gnu/Documentation/lguest/lguest.c
--- linux-libre-2.6.36-gnu/Documentation/lguest/lguest.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/lguest/lguest.c	2011-01-04 19:50:19.000000000 -0500
@@ -1640,15 +1640,6 @@
 	off = out->sector * 512;
 
 	/*
-	 * The block device implements "barriers", where the Guest indicates
-	 * that it wants all previous writes to occur before this write.  We
-	 * don't have a way of asking our kernel to do a barrier, so we just
-	 * synchronize all the data in the file.  Pretty poor, no?
-	 */
-	if (out->type & VIRTIO_BLK_T_BARRIER)
-		fdatasync(vblk->fd);
-
-	/*
 	 * In general the virtio block driver is allowed to try SCSI commands.
 	 * It'd be nice if we supported eject, for example, but we don't.
 	 */
@@ -1680,6 +1671,13 @@
 			/* Die, bad Guest, die. */
 			errx(1, "Write past end %llu+%u", off, ret);
 		}
+
+		wlen = sizeof(*in);
+		*in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+	} else if (out->type & VIRTIO_BLK_T_FLUSH) {
+		/* Flush */
+		ret = fdatasync(vblk->fd);
+		verbose("FLUSH fdatasync: %i\n", ret);
 		wlen = sizeof(*in);
 		*in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
 	} else {
@@ -1703,15 +1701,6 @@
 		}
 	}
 
-	/*
-	 * OK, so we noted that it was pretty poor to use an fdatasync as a
-	 * barrier.  But Christoph Hellwig points out that we need a sync
-	 * *afterwards* as well: "Barriers specify no reordering to the front
-	 * or the back."  And Jens Axboe confirmed it, so here we are:
-	 */
-	if (out->type & VIRTIO_BLK_T_BARRIER)
-		fdatasync(vblk->fd);
-
 	/* Finished that request. */
 	add_used(vq, head, wlen);
 }
@@ -1736,8 +1725,8 @@
 	vblk->fd = open_or_die(filename, O_RDWR|O_LARGEFILE);
 	vblk->len = lseek64(vblk->fd, 0, SEEK_END);
 
-	/* We support barriers. */
-	add_feature(dev, VIRTIO_BLK_F_BARRIER);
+	/* We support FLUSH. */
+	add_feature(dev, VIRTIO_BLK_F_FLUSH);
 
 	/* Tell Guest how many sectors this device has. */
 	conf.capacity = cpu_to_le64(vblk->len / 512);
diff -druN linux-libre-2.6.36-gnu/Documentation/misc-devices/apds990x.txt linux-libre-2.6.37-gnu/Documentation/misc-devices/apds990x.txt
--- linux-libre-2.6.36-gnu/Documentation/misc-devices/apds990x.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/misc-devices/apds990x.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,111 @@
+Kernel driver apds990x
+======================
+
+Supported chips:
+Avago APDS990X
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+
+APDS990x is a combined ambient light and proximity sensor. ALS and proximity
+functionality are highly connected. ALS measurement path must be running
+while the proximity functionality is enabled.
+
+ALS produces raw measurement values for two channels: Clear channel
+(infrared + visible light) and IR only. However, threshold comparisons happen
+using clear channel only. Lux value and the threshold level on the HW
+might vary quite much depending the spectrum of the light source.
+
+Driver makes necessary conversions to both directions so that user handles
+only lux values. Lux value is calculated using information from the both
+channels. HW threshold level is calculated from the given lux value to match
+with current type of the lightning. Sometimes inaccuracy of the estimations
+lead to false interrupt, but that doesn't harm.
+
+ALS contains 4 different gain steps. Driver automatically
+selects suitable gain step. After each measurement, reliability of the results
+is estimated and new measurement is trigged if necessary.
+
+Platform data can provide tuned values to the conversion formulas if
+values are known. Otherwise plain sensor default values are used.
+
+Proximity side is little bit simpler. There is no need for complex conversions.
+It produces directly usable values.
+
+Driver controls chip operational state using pm_runtime framework.
+Voltage regulators are controlled based on chip operational state.
+
+SYSFS
+-----
+
+
+chip_id
+	RO - shows detected chip type and version
+
+power_state
+	RW - enable / disable chip. Uses counting logic
+	     1 enables the chip
+	     0 disables the chip
+lux0_input
+	RO - measured lux value
+	     sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+	RO - lux0_input max value. Actually never reaches since sensor tends
+	     to saturate much before that. Real max value varies depending
+	     on the light spectrum etc.
+
+lux0_rate
+	RW - measurement rate in Hz
+
+lux0_rate_avail
+	RO - supported measurement rates
+
+lux0_calibscale
+	RW - calibration value. Set to neutral value by default.
+	     Output results are multiplied with calibscale / calibscale_default
+	     value.
+
+lux0_calibscale_default
+	RO - neutral calibration value
+
+lux0_thresh_above_value
+	RW - HI level threshold value. All results above the value
+	     trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+	     interrupt.
+
+lux0_thresh_below_value
+	RW - LO level threshold value. All results below the value
+	     trigs an interrupt. 0 disables the below interrupt.
+
+prox0_raw
+	RO - measured proximity value
+	     sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+	RO - prox0_raw max value (1023)
+
+prox0_raw_en
+	RW - enable / disable proximity - uses counting logic
+	     1 enables the proximity
+	     0 disables the proximity
+
+prox0_reporting_mode
+	RW - trigger / periodic. In "trigger" mode the driver tells two possible
+	     values: 0 or prox0_sensor_range value. 0 means no proximity,
+	     1023 means proximity. This causes minimal number of interrupts.
+	     In "periodic" mode the driver reports all values above
+	     prox0_thresh_above. This causes more interrupts, but it can give
+	     _rough_ estimate about the distance.
+
+prox0_reporting_mode_avail
+	RO - accepted values to prox0_reporting_mode (trigger, periodic)
+
+prox0_thresh_above_value
+	RW - threshold level which trigs proximity events.
diff -druN linux-libre-2.6.36-gnu/Documentation/misc-devices/bh1770glc.txt linux-libre-2.6.37-gnu/Documentation/misc-devices/bh1770glc.txt
--- linux-libre-2.6.36-gnu/Documentation/misc-devices/bh1770glc.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/misc-devices/bh1770glc.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,116 @@
+Kernel driver bh1770glc
+=======================
+
+Supported chips:
+ROHM BH1770GLC
+OSRAM SFH7770
+
+Data sheet:
+Not freely available
+
+Author:
+Samu Onkalo <samu.p.onkalo@nokia.com>
+
+Description
+-----------
+BH1770GLC and SFH7770 are combined ambient light and proximity sensors.
+ALS and proximity parts operates on their own, but they shares common I2C
+interface and interrupt logic. In principle they can run on their own,
+but ALS side results are used to estimate reliability of the proximity sensor.
+
+ALS produces 16 bit lux values. The chip contains interrupt logic to produce
+low and high threshold interrupts.
+
+Proximity part contains IR-led driver up to 3 IR leds. The chip measures
+amount of reflected IR light and produces proximity result. Resolution is
+8 bit. Driver supports only one channel. Driver uses ALS results to estimate
+reliability of the proximity results. Thus ALS is always running while
+proximity detection is needed.
+
+Driver uses threshold interrupts to avoid need for polling the values.
+Proximity low interrupt doesn't exists in the chip. This is simulated
+by using a delayed work. As long as there is proximity threshold above
+interrupts the delayed work is pushed forward. So, when proximity level goes
+below the threshold value, there is no interrupt and the delayed work will
+finally run. This is handled as no proximity indication.
+
+Chip state is controlled via runtime pm framework when enabled in config.
+
+Calibscale factor is used to hide differences between the chips. By default
+value set to neutral state meaning factor of 1.00. To get proper values,
+calibrated source of light is needed as a reference. Calibscale factor is set
+so that measurement produces about the expected lux value.
+
+SYSFS
+-----
+
+chip_id
+	RO - shows detected chip type and version
+
+power_state
+	RW - enable / disable chip. Uses counting logic
+	     1 enables the chip
+	     0 disables the chip
+
+lux0_input
+	RO - measured lux value
+	     sysfs_notify called when threshold interrupt occurs
+
+lux0_sensor_range
+	RO - lux0_input max value
+
+lux0_rate
+	RW - measurement rate in Hz
+
+lux0_rate_avail
+	RO - supported measurement rates
+
+lux0_thresh_above_value
+	RW - HI level threshold value. All results above the value
+	     trigs an interrupt. 65535 (i.e. sensor_range) disables the above
+	     interrupt.
+
+lux0_thresh_below_value
+	RW - LO level threshold value. All results below the value
+	     trigs an interrupt. 0 disables the below interrupt.
+
+lux0_calibscale
+	RW - calibration value. Set to neutral value by default.
+	     Output results are multiplied with calibscale / calibscale_default
+	     value.
+
+lux0_calibscale_default
+	RO - neutral calibration value
+
+prox0_raw
+	RO - measured proximity value
+	     sysfs_notify called when threshold interrupt occurs
+
+prox0_sensor_range
+	RO - prox0_raw max value
+
+prox0_raw_en
+	RW - enable / disable proximity - uses counting logic
+	     1 enables the proximity
+	     0 disables the proximity
+
+prox0_thresh_above_count
+	RW - number of proximity interrupts needed before triggering the event
+
+prox0_rate_above
+	RW - Measurement rate (in Hz) when the level is above threshold
+	     i.e. when proximity on has been reported.
+
+prox0_rate_below
+	RW - Measurement rate (in Hz) when the level is below threshold
+	     i.e. when proximity off has been reported.
+
+prox0_rate_avail
+	RO - Supported proximity measurement rates in Hz
+
+prox0_thresh_above0_value
+	RW - threshold level which trigs proximity events.
+	     Filtered by persistence filter (prox0_thresh_above_count)
+
+prox0_thresh_above1_value
+	RW - threshold level which trigs event immediately
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/bonding.txt linux-libre-2.6.37-gnu/Documentation/networking/bonding.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/bonding.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/bonding.txt	2011-01-04 19:50:19.000000000 -0500
@@ -765,6 +765,14 @@
 	does not exist, and the layer2 policy is the only policy.  The
 	layer2+3 value was added for bonding version 3.2.2.
 
+resend_igmp
+
+	Specifies the number of IGMP membership reports to be issued after
+	a failover event. One membership report is issued immediately after
+	the failover, subsequent packets are sent in each 200ms interval.
+
+	The valid range is 0 - 255; the default value is 1. This option
+	was added for bonding version 3.7.0.
 
 3. Configuring Bonding Devices
 ==============================
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/can.txt linux-libre-2.6.37-gnu/Documentation/networking/can.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/can.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/can.txt	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,7 @@
       4.1.2 RAW socket option CAN_RAW_ERR_FILTER
       4.1.3 RAW socket option CAN_RAW_LOOPBACK
       4.1.4 RAW socket option CAN_RAW_RECV_OWN_MSGS
+      4.1.5 RAW socket returned message flags
     4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
     4.3 connected transport protocols (SOCK_SEQPACKET)
     4.4 unconnected transport protocols (SOCK_DGRAM)
@@ -471,6 +472,17 @@
     setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
                &recv_own_msgs, sizeof(recv_own_msgs));
 
+  4.1.5 RAW socket returned message flags
+
+  When using recvmsg() call, the msg->msg_flags may contain following flags:
+
+    MSG_DONTROUTE: set when the received frame was created on the local host.
+
+    MSG_CONFIRM: set when the frame was sent via the socket it is received on.
+      This flag can be interpreted as a 'transmission confirmation' when the
+      CAN driver supports the echo of frames on driver level, see 3.2 and 6.2.
+      In order to receive such messages, CAN_RAW_RECV_OWN_MSGS must be set.
+
   4.2 Broadcast Manager protocol sockets (SOCK_DGRAM)
   4.3 connected transport protocols (SOCK_SEQPACKET)
   4.4 unconnected transport protocols (SOCK_DGRAM)
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/dccp.txt linux-libre-2.6.37-gnu/Documentation/networking/dccp.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/dccp.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/dccp.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,18 +1,20 @@
 DCCP protocol
-============
+=============
 
 
 Contents
 ========
-
 - Introduction
 - Missing features
 - Socket options
+- Sysctl variables
+- IOCTLs
+- Other tunables
 - Notes
 
+
 Introduction
 ============
-
 Datagram Congestion Control Protocol (DCCP) is an unreliable, connection
 oriented protocol designed to solve issues present in UDP and TCP, particularly
 for real-time and multimedia (streaming) traffic.
@@ -29,9 +31,9 @@
 DCCP is a Proposed Standard (RFC 2026), and the homepage for DCCP as a protocol
 is at http://www.ietf.org/html.charters/dccp-charter.html
 
+
 Missing features
 ================
-
 The Linux DCCP implementation does not currently support all the features that are
 specified in RFCs 4340...42.
 
@@ -45,7 +47,6 @@
 
 Socket options
 ==============
-
 DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
 service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
 the socket will fall back to 0 (which means that no meaningful service code
@@ -112,6 +113,7 @@
 On unidirectional connections it is useful to close the unused half-connection
 via shutdown (SHUT_WR or SHUT_RD): this will reduce per-packet processing costs.
 
+
 Sysctl variables
 ================
 Several DCCP default parameters can be managed by the following sysctls
@@ -155,15 +157,30 @@
 	sequence-invalid packets on the same socket (RFC 4340, 7.5.4). The unit
 	of this parameter is milliseconds; a value of 0 disables rate-limiting.
 
+
 IOCTLS
 ======
 FIONREAD
 	Works as in udp(7): returns in the `int' argument pointer the size of
 	the next pending datagram in bytes, or 0 when no datagram is pending.
 
+
+Other tunables
+==============
+Per-route rto_min support
+	CCID-2 supports the RTAX_RTO_MIN per-route setting for the minimum value
+	of the RTO timer. This setting can be modified via the 'rto_min' option
+	of iproute2; for example:
+		> ip route change 10.0.0.0/24   rto_min 250j dev wlan0
+		> ip route add    10.0.0.254/32 rto_min 800j dev wlan0
+		> ip route show dev wlan0
+	CCID-3 also supports the rto_min setting: it is used to define the lower
+	bound for the expiry of the nofeedback timer. This can be useful on LANs
+	with very low RTTs (e.g., loopback, Gbit ethernet).
+
+
 Notes
 =====
-
 DCCP does not travel through NAT successfully at present on many boxes. This is
 because the checksum covers the pseudo-header as per TCP and UDP. Linux NAT
 support for DCCP has been added.
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/ip-sysctl.txt linux-libre-2.6.37-gnu/Documentation/networking/ip-sysctl.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/ip-sysctl.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/ip-sysctl.txt	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,15 @@
 min_pmtu - INTEGER
 	default 562 - minimum discovered Path MTU
 
+route/max_size - INTEGER
+	Maximum number of routes allowed in the kernel.  Increase
+	this when using large numbers of interfaces and/or routes.
+
+neigh/default/gc_thresh3 - INTEGER
+	Maximum number of neighbor entries allowed.  Increase this
+	when using large numbers of interfaces and when communicating
+	with large numbers of directly-connected peers.
+
 mtu_expires - INTEGER
 	Time, in seconds, that cached PMTU information is kept.
 
@@ -135,6 +144,7 @@
 	Count buffering overhead as bytes/2^tcp_adv_win_scale
 	(if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
 	if it is <= 0.
+	Possible values are [-31, 31], inclusive.
 	Default: 2
 
 tcp_allowed_congestion_control - STRING
@@ -1014,6 +1024,12 @@
 accept_ra - BOOLEAN
 	Accept Router Advertisements; autoconfigure using them.
 
+	Possible values are:
+		0 Do not accept Router Advertisements.
+		1 Accept Router Advertisements if forwarding is disabled.
+		2 Overrule forwarding behaviour. Accept Router Advertisements
+		  even if forwarding is enabled.
+
 	Functional default: enabled if local forwarding is disabled.
 			    disabled if local forwarding is enabled.
 
@@ -1075,7 +1091,12 @@
 	Note: It is recommended to have the same setting on all
 	interfaces; mixed router/host scenarios are rather uncommon.
 
-	FALSE:
+	Possible values are:
+		0 Forwarding disabled
+		1 Forwarding enabled
+		2 Forwarding enabled (Hybrid Mode)
+
+	FALSE (0):
 
 	By default, Host behaviour is assumed.  This means:
 
@@ -1085,18 +1106,24 @@
 	   Advertisements (and do autoconfiguration).
 	4. If accept_redirects is TRUE (default), accept Redirects.
 
-	TRUE:
+	TRUE (1):
 
 	If local forwarding is enabled, Router behaviour is assumed.
 	This means exactly the reverse from the above:
 
 	1. IsRouter flag is set in Neighbour Advertisements.
 	2. Router Solicitations are not sent.
-	3. Router Advertisements are ignored.
+	3. Router Advertisements are ignored unless accept_ra is 2.
 	4. Redirects are ignored.
 
-	Default: FALSE if global forwarding is disabled (default),
-		 otherwise TRUE.
+	TRUE (2):
+
+	Hybrid mode. Same behaviour as TRUE, except for:
+
+	2. Router Solicitations are being sent when necessary.
+
+	Default: 0 (disabled) if global forwarding is disabled (default),
+		 otherwise 1 (enabled).
 
 hop_limit - INTEGER
 	Default Hop Limit to set.
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/phonet.txt linux-libre-2.6.37-gnu/Documentation/networking/phonet.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/phonet.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/phonet.txt	2011-01-04 19:50:19.000000000 -0500
@@ -112,6 +112,22 @@
 not seem useful with Phonet usages (could be added easily).
 
 
+Resource subscription
+---------------------
+
+A Phonet datagram socket can be subscribed to any number of 8-bits
+Phonet resources, as follow:
+
+  uint32_t res = 0xXX;
+  ioctl(fd, SIOCPNADDRESOURCE, &res);
+
+Subscription is similarly cancelled using the SIOCPNDELRESOURCE I/O
+control request, or when the socket is closed.
+
+Note that no more than one socket can be subcribed to any given
+resource at a time. If not, ioctl() will return EBUSY.
+
+
 Phonet Pipe protocol
 --------------------
 
@@ -166,6 +182,46 @@
     or zero if encapsulation is off.
 
 
+Phonet Pipe-controller Implementation
+-------------------------------------
+
+Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig
+option. It is useful when communicating with those Nokia Modems which do not
+implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
+U8500 platform.
+
+The implementation is based on the Data Connection Establishment Sequence
+depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
+document.
+
+It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
+between itself and a remote pipe-end point (e.g. modem).
+
+The implementation adds socket options at SOL_PNPIPE level:
+
+ PNPIPE_PIPE_HANDLE
+	It accepts an integer argument for setting value of pipe handle.
+
+  PNPIPE_ENABLE accepts one integer value (int). If set to zero, the pipe
+    is disabled. If the value is non-zero, the pipe is enabled. If the pipe
+    is not (yet) connected, ENOTCONN is error is returned.
+
+The implementation also adds socket 'connect'. On calling the 'connect', pipe
+will be created between the source socket and the destination, and the pipe
+state will be set to PIPE_DISABLED.
+
+After a pipe has been created and enabled successfully, the Pipe data can be
+exchanged between the host-pep and remote-pep (modem).
+
+User-space would typically follow below sequence with Pipe controller:-
+-socket
+-bind
+-setsockopt for PNPIPE_PIPE_HANDLE
+-connect
+-setsockopt for PNPIPE_ENCAP_IP
+-setsockopt for PNPIPE_ENABLE
+
+
 Authors
 -------
 
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/phy.txt linux-libre-2.6.37-gnu/Documentation/networking/phy.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/phy.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/phy.txt	2011-01-04 19:50:19.000000000 -0500
@@ -177,18 +177,6 @@
  
    A convenience function to print out the PHY status neatly.
 
- int phy_clear_interrupt(struct phy_device *phydev);
- int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
-   
-   Clear the PHY's interrupt, and configure which ones are allowed,
-   respectively.  Currently only supports all on, or all off.
- 
- int phy_enable_interrupts(struct phy_device *phydev);
- int phy_disable_interrupts(struct phy_device *phydev);
-
-   Functions which enable/disable PHY interrupts, clearing them
-   before and after, respectively.
-
  int phy_start_interrupts(struct phy_device *phydev);
  int phy_stop_interrupts(struct phy_device *phydev);
 
@@ -213,12 +201,6 @@
    Fills the phydev structure with up-to-date information about the current
    settings in the PHY.
 
- void phy_sanitize_settings(struct phy_device *phydev)
-   
-   Resolves differences between currently desired settings, and
-   supported settings for the given PHY device.  Does not make
-   the changes in the hardware, though.
-
  int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
  int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
 
diff -druN linux-libre-2.6.36-gnu/Documentation/networking/timestamping.txt linux-libre-2.6.37-gnu/Documentation/networking/timestamping.txt
--- linux-libre-2.6.36-gnu/Documentation/networking/timestamping.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/networking/timestamping.txt	2011-01-04 19:50:19.000000000 -0500
@@ -172,15 +172,19 @@
 };
 
 Time stamps for outgoing packets are to be generated as follows:
-- In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero.
-  If yes, then the driver is expected to do hardware time stamping.
+- In hard_start_xmit(), check if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
+  is set no-zero. If yes, then the driver is expected to do hardware time
+  stamping.
 - If this is possible for the skb and requested, then declare
-  that the driver is doing the time stamping by setting the field
-  skb_tx(skb)->in_progress non-zero. You might want to keep a pointer
-  to the associated skb for the next step and not free the skb. A driver
-  not supporting hardware time stamping doesn't do that. A driver must
-  never touch sk_buff::tstamp! It is used to store software generated
-  time stamps by the network subsystem.
+  that the driver is doing the time stamping by setting the flag
+  SKBTX_IN_PROGRESS in skb_shinfo(skb)->tx_flags , e.g. with
+
+      skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+
+  You might want to keep a pointer to the associated skb for the next step
+  and not free the skb. A driver not supporting hardware time stamping doesn't
+  do that. A driver must never touch sk_buff::tstamp! It is used to store
+  software generated time stamps by the network subsystem.
 - As soon as the driver has sent the packet and/or obtained a
   hardware time stamp for it, it passes the time stamp back by
   calling skb_hwtstamp_tx() with the original skb, the raw
@@ -191,6 +195,6 @@
   this would occur at a later time in the processing pipeline than other
   software time stamping and therefore could lead to unexpected deltas
   between time stamps.
-- If the driver did not call set skb_tx(skb)->in_progress, then
+- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then
   dev_hard_start_xmit() checks whether software time stamping
   is wanted as fallback and potentially generates the time stamp.
diff -druN linux-libre-2.6.36-gnu/Documentation/pcmcia/driver-changes.txt linux-libre-2.6.37-gnu/Documentation/pcmcia/driver-changes.txt
--- linux-libre-2.6.36-gnu/Documentation/pcmcia/driver-changes.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/pcmcia/driver-changes.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,29 @@
 This file details changes in 2.6 which affect PCMCIA card driver authors:
+* pcmcia_loop_config() and autoconfiguration (as of 2.6.36)
+   If struct pcmcia_device *p_dev->config_flags is set accordingly,
+   pcmcia_loop_config() now sets up certain configuration values
+   automatically, though the driver may still override the settings
+   in the callback function. The following autoconfiguration options
+   are provided at the moment:
+	CONF_AUTO_CHECK_VCC : check for matching Vcc
+	CONF_AUTO_SET_VPP   : set Vpp
+	CONF_AUTO_AUDIO     : auto-enable audio line, if required
+	CONF_AUTO_SET_IO    : set ioport resources (->resource[0,1])
+	CONF_AUTO_SET_IOMEM : set first iomem resource (->resource[2])
+
+* pcmcia_request_configuration -> pcmcia_enable_device (as of 2.6.36)
+   pcmcia_request_configuration() got renamed to pcmcia_enable_device(),
+   as it mirrors pcmcia_disable_device(). Configuration settings are now
+   stored in struct pcmcia_device, e.g. in the fields config_flags,
+   config_index, config_base, vpp.
+
+* pcmcia_request_window changes (as of 2.6.36)
+   Instead of win_req_t, drivers are now requested to fill out
+   struct pcmcia_device *p_dev->resource[2,3,4,5] for up to four ioport
+   ranges. After a call to pcmcia_request_window(), the regions found there
+   are reserved and may be used immediately -- until pcmcia_release_window()
+   is called.
+
 * pcmcia_request_io changes (as of 2.6.36)
    Instead of io_req_t, drivers are now requested to fill out
    struct pcmcia_device *p_dev->resource[0,1] for up to two ioport
diff -druN linux-libre-2.6.36-gnu/Documentation/power/00-INDEX linux-libre-2.6.37-gnu/Documentation/power/00-INDEX
--- linux-libre-2.6.36-gnu/Documentation/power/00-INDEX	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/power/00-INDEX	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,8 @@
 	- Power management user interface in /sys/power
 notifiers.txt
 	- Registering suspend notifiers in device drivers
+opp.txt
+	- Operating Performance Point library
 pci.txt
 	- How the PCI Subsystem Does Power Management
 pm_qos_interface.txt
diff -druN linux-libre-2.6.36-gnu/Documentation/power/interface.txt linux-libre-2.6.37-gnu/Documentation/power/interface.txt
--- linux-libre-2.6.36-gnu/Documentation/power/interface.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/power/interface.txt	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,7 @@
 suspend image will be as small as possible.
 
 Reading from this file will display the current image size limit, which
-is set to 500 MB by default.
+is set to 2/5 of available RAM by default.
 
 /sys/power/pm_trace controls the code which saves the last PM event point in
 the RTC across reboots, so that you can debug a machine that just hangs
diff -druN linux-libre-2.6.36-gnu/Documentation/power/opp.txt linux-libre-2.6.37-gnu/Documentation/power/opp.txt
--- linux-libre-2.6.36-gnu/Documentation/power/opp.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/power/opp.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,378 @@
+*=============*
+* OPP Library *
+*=============*
+
+(C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated
+
+Contents
+--------
+1. Introduction
+2. Initial OPP List Registration
+3. OPP Search Functions
+4. OPP Availability Control Functions
+5. OPP Data Retrieval Functions
+6. Cpufreq Table Generation
+7. Data Structures
+
+1. Introduction
+===============
+Complex SoCs of today consists of a multiple sub-modules working in conjunction.
+In an operational system executing varied use cases, not all modules in the SoC
+need to function at their highest performing frequency all the time. To
+facilitate this, sub-modules in a SoC are grouped into domains, allowing some
+domains to run at lower voltage and frequency while other domains are loaded
+more. The set of discrete tuples consisting of frequency and voltage pairs that
+the device will support per domain are called Operating Performance Points or
+OPPs.
+
+OPP library provides a set of helper functions to organize and query the OPP
+information. The library is located in drivers/base/power/opp.c and the header
+is located in include/linux/opp.h. OPP library can be enabled by enabling
+CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
+CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
+optionally boot at a certain OPP without needing cpufreq.
+
+Typical usage of the OPP library is as follows:
+(users)		-> registers a set of default OPPs		-> (library)
+SoC framework	-> modifies on required cases certain OPPs	-> OPP layer
+		-> queries to search/retrieve information	->
+
+Architectures that provide a SoC framework for OPP should select ARCH_HAS_OPP
+to make the OPP layer available.
+
+OPP layer expects each domain to be represented by a unique device pointer. SoC
+framework registers a set of initial OPPs per device with the OPP layer. This
+list is expected to be an optimally small number typically around 5 per device.
+This initial list contains a set of OPPs that the framework expects to be safely
+enabled by default in the system.
+
+Note on OPP Availability:
+------------------------
+As the system proceeds to operate, SoC framework may choose to make certain
+OPPs available or not available on each device based on various external
+factors. Example usage: Thermal management or other exceptional situations where
+SoC framework might choose to disable a higher frequency OPP to safely continue
+operations until that OPP could be re-enabled if possible.
+
+OPP library facilitates this concept in it's implementation. The following
+operational functions operate only on available opps:
+opp_find_freq_{ceil, floor}, opp_get_voltage, opp_get_freq, opp_get_opp_count
+and opp_init_cpufreq_table
+
+opp_find_freq_exact is meant to be used to find the opp pointer which can then
+be used for opp_enable/disable functions to make an opp available as required.
+
+WARNING: Users of OPP library should refresh their availability count using
+get_opp_count if opp_enable/disable functions are invoked for a device, the
+exact mechanism to trigger these or the notification mechanism to other
+dependent subsystems such as cpufreq are left to the discretion of the SoC
+specific framework which uses the OPP library. Similar care needs to be taken
+care to refresh the cpufreq table in cases of these operations.
+
+WARNING on OPP List locking mechanism:
+-------------------------------------------------
+OPP library uses RCU for exclusivity. RCU allows the query functions to operate
+in multiple contexts and this synchronization mechanism is optimal for a read
+intensive operations on data structure as the OPP library caters to.
+
+To ensure that the data retrieved are sane, the users such as SoC framework
+should ensure that the section of code operating on OPP queries are locked
+using RCU read locks. The opp_find_freq_{exact,ceil,floor},
+opp_get_{voltage, freq, opp_count} fall into this category.
+
+opp_{add,enable,disable} are updaters which use mutex and implement it's own
+RCU locking mechanisms. opp_init_cpufreq_table acts as an updater and uses
+mutex to implment RCU updater strategy. These functions should *NOT* be called
+under RCU locks and other contexts that prevent blocking functions in RCU or
+mutex operations from working.
+
+2. Initial OPP List Registration
+================================
+The SoC implementation calls opp_add function iteratively to add OPPs per
+device. It is expected that the SoC framework will register the OPP entries
+optimally- typical numbers range to be less than 5. The list generated by
+registering the OPPs is maintained by OPP library throughout the device
+operation. The SoC framework can subsequently control the availability of the
+OPPs dynamically using the opp_enable / disable functions.
+
+opp_add - Add a new OPP for a specific domain represented by the device pointer.
+	The OPP is defined using the frequency and voltage. Once added, the OPP
+	is assumed to be available and control of it's availability can be done
+	with the opp_enable/disable functions. OPP library internally stores
+	and manages this information in the opp struct. This function may be
+	used by SoC framework to define a optimal list as per the demands of
+	SoC usage environment.
+
+	WARNING: Do not use this function in interrupt context.
+
+	Example:
+	 soc_pm_init()
+	 {
+		/* Do things */
+		r = opp_add(mpu_dev, 1000000, 900000);
+		if (!r) {
+			pr_err("%s: unable to register mpu opp(%d)\n", r);
+			goto no_cpufreq;
+		}
+		/* Do cpufreq things */
+	 no_cpufreq:
+		/* Do remaining things */
+	 }
+
+3. OPP Search Functions
+=======================
+High level framework such as cpufreq operates on frequencies. To map the
+frequency back to the corresponding OPP, OPP library provides handy functions
+to search the OPP list that OPP library internally manages. These search
+functions return the matching pointer representing the opp if a match is
+found, else returns error. These errors are expected to be handled by standard
+error checks such as IS_ERR() and appropriate actions taken by the caller.
+
+opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
+	availability. This function is especially useful to enable an OPP which
+	is not available by default.
+	Example: In a case when SoC framework detects a situation where a
+	higher frequency could be made available, it can use this function to
+	find the OPP prior to call the opp_enable to actually make it available.
+	 rcu_read_lock();
+	 opp = opp_find_freq_exact(dev, 1000000000, false);
+	 rcu_read_unlock();
+	 /* dont operate on the pointer.. just do a sanity check.. */
+	 if (IS_ERR(opp)) {
+		pr_err("frequency not disabled!\n");
+		/* trigger appropriate actions.. */
+	 } else {
+		opp_enable(dev,1000000000);
+	 }
+
+	NOTE: This is the only search function that operates on OPPs which are
+	not available.
+
+opp_find_freq_floor - Search for an available OPP which is *at most* the
+	provided frequency. This function is useful while searching for a lesser
+	match OR operating on OPP information in the order of decreasing
+	frequency.
+	Example: To find the highest opp for a device:
+	 freq = ULONG_MAX;
+	 rcu_read_lock();
+	 opp_find_freq_floor(dev, &freq);
+	 rcu_read_unlock();
+
+opp_find_freq_ceil - Search for an available OPP which is *at least* the
+	provided frequency. This function is useful while searching for a
+	higher match OR operating on OPP information in the order of increasing
+	frequency.
+	Example 1: To find the lowest opp for a device:
+	 freq = 0;
+	 rcu_read_lock();
+	 opp_find_freq_ceil(dev, &freq);
+	 rcu_read_unlock();
+	Example 2: A simplified implementation of a SoC cpufreq_driver->target:
+	 soc_cpufreq_target(..)
+	 {
+		/* Do stuff like policy checks etc. */
+		/* Find the best frequency match for the req */
+		rcu_read_lock();
+		opp = opp_find_freq_ceil(dev, &freq);
+		rcu_read_unlock();
+		if (!IS_ERR(opp))
+			soc_switch_to_freq_voltage(freq);
+		else
+			/* do something when we cant satisfy the req */
+		/* do other stuff */
+	 }
+
+4. OPP Availability Control Functions
+=====================================
+A default OPP list registered with the OPP library may not cater to all possible
+situation. The OPP library provides a set of functions to modify the
+availability of a OPP within the OPP list. This allows SoC frameworks to have
+fine grained dynamic control of which sets of OPPs are operationally available.
+These functions are intended to *temporarily* remove an OPP in conditions such
+as thermal considerations (e.g. don't use OPPx until the temperature drops).
+
+WARNING: Do not use these functions in interrupt context.
+
+opp_enable - Make a OPP available for operation.
+	Example: Lets say that 1GHz OPP is to be made available only if the
+	SoC temperature is lower than a certain threshold. The SoC framework
+	implementation might choose to do something as follows:
+	 if (cur_temp < temp_low_thresh) {
+		/* Enable 1GHz if it was disabled */
+		rcu_read_lock();
+		opp = opp_find_freq_exact(dev, 1000000000, false);
+		rcu_read_unlock();
+		/* just error check */
+		if (!IS_ERR(opp))
+			ret = opp_enable(dev, 1000000000);
+		else
+			goto try_something_else;
+	 }
+
+opp_disable - Make an OPP to be not available for operation
+	Example: Lets say that 1GHz OPP is to be disabled if the temperature
+	exceeds a threshold value. The SoC framework implementation might
+	choose to do something as follows:
+	 if (cur_temp > temp_high_thresh) {
+		/* Disable 1GHz if it was enabled */
+		rcu_read_lock();
+		opp = opp_find_freq_exact(dev, 1000000000, true);
+		rcu_read_unlock();
+		/* just error check */
+		if (!IS_ERR(opp))
+			ret = opp_disable(dev, 1000000000);
+		else
+			goto try_something_else;
+	 }
+
+5. OPP Data Retrieval Functions
+===============================
+Since OPP library abstracts away the OPP information, a set of functions to pull
+information from the OPP structure is necessary. Once an OPP pointer is
+retrieved using the search functions, the following functions can be used by SoC
+framework to retrieve the information represented inside the OPP layer.
+
+opp_get_voltage - Retrieve the voltage represented by the opp pointer.
+	Example: At a cpufreq transition to a different frequency, SoC
+	framework requires to set the voltage represented by the OPP using
+	the regulator framework to the Power Management chip providing the
+	voltage.
+	 soc_switch_to_freq_voltage(freq)
+	 {
+		/* do things */
+		rcu_read_lock();
+		opp = opp_find_freq_ceil(dev, &freq);
+		v = opp_get_voltage(opp);
+		rcu_read_unlock();
+		if (v)
+			regulator_set_voltage(.., v);
+		/* do other things */
+	 }
+
+opp_get_freq - Retrieve the freq represented by the opp pointer.
+	Example: Lets say the SoC framework uses a couple of helper functions
+	we could pass opp pointers instead of doing additional parameters to
+	handle quiet a bit of data parameters.
+	 soc_cpufreq_target(..)
+	 {
+		/* do things.. */
+		 max_freq = ULONG_MAX;
+		 rcu_read_lock();
+		 max_opp = opp_find_freq_floor(dev,&max_freq);
+		 requested_opp = opp_find_freq_ceil(dev,&freq);
+		 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
+			r = soc_test_validity(max_opp, requested_opp);
+		 rcu_read_unlock();
+		/* do other things */
+	 }
+	 soc_test_validity(..)
+	 {
+		 if(opp_get_voltage(max_opp) < opp_get_voltage(requested_opp))
+			 return -EINVAL;
+		 if(opp_get_freq(max_opp) < opp_get_freq(requested_opp))
+			 return -EINVAL;
+		/* do things.. */
+	 }
+
+opp_get_opp_count - Retrieve the number of available opps for a device
+	Example: Lets say a co-processor in the SoC needs to know the available
+	frequencies in a table, the main processor can notify as following:
+	 soc_notify_coproc_available_frequencies()
+	 {
+		/* Do things */
+		rcu_read_lock();
+		num_available = opp_get_opp_count(dev);
+		speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
+		/* populate the table in increasing order */
+		freq = 0;
+		while (!IS_ERR(opp = opp_find_freq_ceil(dev, &freq))) {
+			speeds[i] = freq;
+			freq++;
+			i++;
+		}
+		rcu_read_unlock();
+
+		soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
+		/* Do other things */
+	 }
+
+6. Cpufreq Table Generation
+===========================
+opp_init_cpufreq_table - cpufreq framework typically is initialized with
+	cpufreq_frequency_table_cpuinfo which is provided with the list of
+	frequencies that are available for operation. This function provides
+	a ready to use conversion routine to translate the OPP layer's internal
+	information about the available frequencies into a format readily
+	providable to cpufreq.
+
+	WARNING: Do not use this function in interrupt context.
+
+	Example:
+	 soc_pm_init()
+	 {
+		/* Do things */
+		r = opp_init_cpufreq_table(dev, &freq_table);
+		if (!r)
+			cpufreq_frequency_table_cpuinfo(policy, freq_table);
+		/* Do other things */
+	 }
+
+	NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
+	addition to CONFIG_PM as power management feature is required to
+	dynamically scale voltage and frequency in a system.
+
+7. Data Structures
+==================
+Typically an SoC contains multiple voltage domains which are variable. Each
+domain is represented by a device pointer. The relationship to OPP can be
+represented as follows:
+SoC
+ |- device 1
+ |	|- opp 1 (availability, freq, voltage)
+ |	|- opp 2 ..
+ ...	...
+ |	`- opp n ..
+ |- device 2
+ ...
+ `- device m
+
+OPP library maintains a internal list that the SoC framework populates and
+accessed by various functions as described above. However, the structures
+representing the actual OPPs and domains are internal to the OPP library itself
+to allow for suitable abstraction reusable across systems.
+
+struct opp - The internal data structure of OPP library which is used to
+	represent an OPP. In addition to the freq, voltage, availability
+	information, it also contains internal book keeping information required
+	for the OPP library to operate on.  Pointer to this structure is
+	provided back to the users such as SoC framework to be used as a
+	identifier for OPP in the interactions with OPP layer.
+
+	WARNING: The struct opp pointer should not be parsed or modified by the
+	users. The defaults of for an instance is populated by opp_add, but the
+	availability of the OPP can be modified by opp_enable/disable functions.
+
+struct device - This is used to identify a domain to the OPP layer. The
+	nature of the device and it's implementation is left to the user of
+	OPP library such as the SoC framework.
+
+Overall, in a simplistic view, the data structure operations is represented as
+following:
+
+Initialization / modification:
+            +-----+        /- opp_enable
+opp_add --> | opp | <-------
+  |         +-----+        \- opp_disable
+  \-------> domain_info(device)
+
+Search functions:
+             /-- opp_find_freq_ceil  ---\   +-----+
+domain_info<---- opp_find_freq_exact -----> | opp |
+             \-- opp_find_freq_floor ---/   +-----+
+
+Retrieval functions:
++-----+     /- opp_get_voltage
+| opp | <---
++-----+     \- opp_get_freq
+
+domain_info <- opp_get_opp_count
diff -druN linux-libre-2.6.36-gnu/Documentation/power/runtime_pm.txt linux-libre-2.6.37-gnu/Documentation/power/runtime_pm.txt
--- linux-libre-2.6.36-gnu/Documentation/power/runtime_pm.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/power/runtime_pm.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,7 @@
 Run-time Power Management Framework for I/O Devices
 
 (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+(C) 2010 Alan Stern <stern@rowland.harvard.edu>
 
 1. Introduction
 
@@ -157,7 +158,8 @@
     to execute it, the other callbacks will not be executed for the same device.
 
   * A request to execute ->runtime_resume() will cancel any pending or
-    scheduled requests to execute the other callbacks for the same device.
+    scheduled requests to execute the other callbacks for the same device,
+    except for scheduled autosuspends.
 
 3. Run-time PM Device Fields
 
@@ -165,7 +167,7 @@
 defined in include/linux/pm.h:
 
   struct timer_list suspend_timer;
-    - timer used for scheduling (delayed) suspend request
+    - timer used for scheduling (delayed) suspend and autosuspend requests
 
   unsigned long timer_expires;
     - timer expiration time, in jiffies (if this is different from zero, the
@@ -230,6 +232,28 @@
       interface; it may only be modified with the help of the pm_runtime_allow()
       and pm_runtime_forbid() helper functions
 
+  unsigned int no_callbacks;
+    - indicates that the device does not use the run-time PM callbacks (see
+      Section 8); it may be modified only by the pm_runtime_no_callbacks()
+      helper function
+
+  unsigned int use_autosuspend;
+    - indicates that the device's driver supports delayed autosuspend (see
+      Section 9); it may be modified only by the
+      pm_runtime{_dont}_use_autosuspend() helper functions
+
+  unsigned int timer_autosuspends;
+    - indicates that the PM core should attempt to carry out an autosuspend
+      when the timer expires rather than a normal suspend
+
+  int autosuspend_delay;
+    - the delay time (in milliseconds) to be used for autosuspend
+
+  unsigned long last_busy;
+    - the time (in jiffies) when the pm_runtime_mark_last_busy() helper
+      function was last called for this device; used in calculating inactivity
+      periods for autosuspend
+
 All of the above fields are members of the 'power' member of 'struct device'.
 
 4. Run-time PM Device Helper Functions
@@ -255,6 +279,12 @@
       error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
       to suspend the device again in future
 
+  int pm_runtime_autosuspend(struct device *dev);
+    - same as pm_runtime_suspend() except that the autosuspend delay is taken
+      into account; if pm_runtime_autosuspend_expiration() says the delay has
+      not yet expired then an autosuspend is scheduled for the appropriate time
+      and 0 is returned
+
   int pm_runtime_resume(struct device *dev);
     - execute the subsystem-level resume callback for the device; returns 0 on
       success, 1 if the device's run-time PM status was already 'active' or
@@ -267,6 +297,11 @@
       device (the request is represented by a work item in pm_wq); returns 0 on
       success or error code if the request has not been queued up
 
+  int pm_request_autosuspend(struct device *dev);
+    - schedule the execution of the subsystem-level suspend callback for the
+      device when the autosuspend delay has expired; if the delay has already
+      expired then the work item is queued up immediately
+
   int pm_schedule_suspend(struct device *dev, unsigned int delay);
     - schedule the execution of the subsystem-level suspend callback for the
       device in future, where 'delay' is the time to wait before queuing up a
@@ -298,12 +333,20 @@
     - decrement the device's usage counter
 
   int pm_runtime_put(struct device *dev);
-    - decrement the device's usage counter, run pm_request_idle(dev) and return
-      its result
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_request_idle(dev) and return its result
+
+  int pm_runtime_put_autosuspend(struct device *dev);
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_request_autosuspend(dev) and return its result
 
   int pm_runtime_put_sync(struct device *dev);
-    - decrement the device's usage counter, run pm_runtime_idle(dev) and return
-      its result
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_runtime_idle(dev) and return its result
+
+  int pm_runtime_put_sync_autosuspend(struct device *dev);
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_runtime_autosuspend(dev) and return its result
 
   void pm_runtime_enable(struct device *dev);
     - enable the run-time PM helper functions to run the device bus type's
@@ -336,8 +379,8 @@
       zero)
 
   bool pm_runtime_suspended(struct device *dev);
-    - return true if the device's runtime PM status is 'suspended', or false
-      otherwise
+    - return true if the device's runtime PM status is 'suspended' and its
+      'power.disable_depth' field is equal to zero, or false otherwise
 
   void pm_runtime_allow(struct device *dev);
     - set the power.runtime_auto flag for the device and decrease its usage
@@ -349,19 +392,51 @@
       counter (used by the /sys/devices/.../power/control interface to
       effectively prevent the device from being power managed at run time)
 
+  void pm_runtime_no_callbacks(struct device *dev);
+    - set the power.no_callbacks flag for the device and remove the run-time
+      PM attributes from /sys/devices/.../power (or prevent them from being
+      added when the device is registered)
+
+  void pm_runtime_mark_last_busy(struct device *dev);
+    - set the power.last_busy field to the current time
+
+  void pm_runtime_use_autosuspend(struct device *dev);
+    - set the power.use_autosuspend flag, enabling autosuspend delays
+
+  void pm_runtime_dont_use_autosuspend(struct device *dev);
+    - clear the power.use_autosuspend flag, disabling autosuspend delays
+
+  void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
+    - set the power.autosuspend_delay value to 'delay' (expressed in
+      milliseconds); if 'delay' is negative then run-time suspends are
+      prevented
+
+  unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
+    - calculate the time when the current autosuspend delay period will expire,
+      based on power.last_busy and power.autosuspend_delay; if the delay time
+      is 1000 ms or larger then the expiration time is rounded up to the
+      nearest second; returns 0 if the delay period has already expired or
+      power.use_autosuspend isn't set, otherwise returns the expiration time
+      in jiffies
+
 It is safe to execute the following helper functions from interrupt context:
 
 pm_request_idle()
+pm_request_autosuspend()
 pm_schedule_suspend()
 pm_request_resume()
 pm_runtime_get_noresume()
 pm_runtime_get()
 pm_runtime_put_noidle()
 pm_runtime_put()
+pm_runtime_put_autosuspend()
+pm_runtime_enable()
 pm_suspend_ignore_children()
 pm_runtime_set_active()
 pm_runtime_set_suspended()
-pm_runtime_enable()
+pm_runtime_suspended()
+pm_runtime_mark_last_busy()
+pm_runtime_autosuspend_expiration()
 
 5. Run-time PM Initialization, Device Probing and Removal
 
@@ -524,3 +599,141 @@
 restore, and run-time resume, can achieve this with the help of the
 UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
 last argument to NULL).
+
+8. "No-Callback" Devices
+
+Some "devices" are only logical sub-devices of their parent and cannot be
+power-managed on their own.  (The prototype example is a USB interface.  Entire
+USB devices can go into low-power mode or send wake-up requests, but neither is
+possible for individual interfaces.)  The drivers for these devices have no
+need of run-time PM callbacks; if the callbacks did exist, ->runtime_suspend()
+and ->runtime_resume() would always return 0 without doing anything else and
+->runtime_idle() would always call pm_runtime_suspend().
+
+Subsystems can tell the PM core about these devices by calling
+pm_runtime_no_callbacks().  This should be done after the device structure is
+initialized and before it is registered (although after device registration is
+also okay).  The routine will set the device's power.no_callbacks flag and
+prevent the non-debugging run-time PM sysfs attributes from being created.
+
+When power.no_callbacks is set, the PM core will not invoke the
+->runtime_idle(), ->runtime_suspend(), or ->runtime_resume() callbacks.
+Instead it will assume that suspends and resumes always succeed and that idle
+devices should be suspended.
+
+As a consequence, the PM core will never directly inform the device's subsystem
+or driver about run-time power changes.  Instead, the driver for the device's
+parent must take responsibility for telling the device's driver when the
+parent's power state changes.
+
+9. Autosuspend, or automatically-delayed suspends
+
+Changing a device's power state isn't free; it requires both time and energy.
+A device should be put in a low-power state only when there's some reason to
+think it will remain in that state for a substantial time.  A common heuristic
+says that a device which hasn't been used for a while is liable to remain
+unused; following this advice, drivers should not allow devices to be suspended
+at run-time until they have been inactive for some minimum period.  Even when
+the heuristic ends up being non-optimal, it will still prevent devices from
+"bouncing" too rapidly between low-power and full-power states.
+
+The term "autosuspend" is an historical remnant.  It doesn't mean that the
+device is automatically suspended (the subsystem or driver still has to call
+the appropriate PM routines); rather it means that run-time suspends will
+automatically be delayed until the desired period of inactivity has elapsed.
+
+Inactivity is determined based on the power.last_busy field.  Drivers should
+call pm_runtime_mark_last_busy() to update this field after carrying out I/O,
+typically just before calling pm_runtime_put_autosuspend().  The desired length
+of the inactivity period is a matter of policy.  Subsystems can set this length
+initially by calling pm_runtime_set_autosuspend_delay(), but after device
+registration the length should be controlled by user space, using the
+/sys/devices/.../power/autosuspend_delay_ms attribute.
+
+In order to use autosuspend, subsystems or drivers must call
+pm_runtime_use_autosuspend() (preferably before registering the device), and
+thereafter they should use the various *_autosuspend() helper functions instead
+of the non-autosuspend counterparts:
+
+	Instead of: pm_runtime_suspend    use: pm_runtime_autosuspend;
+	Instead of: pm_schedule_suspend   use: pm_request_autosuspend;
+	Instead of: pm_runtime_put        use: pm_runtime_put_autosuspend;
+	Instead of: pm_runtime_put_sync   use: pm_runtime_put_sync_autosuspend.
+
+Drivers may also continue to use the non-autosuspend helper functions; they
+will behave normally, not taking the autosuspend delay into account.
+Similarly, if the power.use_autosuspend field isn't set then the autosuspend
+helper functions will behave just like the non-autosuspend counterparts.
+
+The implementation is well suited for asynchronous use in interrupt contexts.
+However such use inevitably involves races, because the PM core can't
+synchronize ->runtime_suspend() callbacks with the arrival of I/O requests.
+This synchronization must be handled by the driver, using its private lock.
+Here is a schematic pseudo-code example:
+
+	foo_read_or_write(struct foo_priv *foo, void *data)
+	{
+		lock(&foo->private_lock);
+		add_request_to_io_queue(foo, data);
+		if (foo->num_pending_requests++ == 0)
+			pm_runtime_get(&foo->dev);
+		if (!foo->is_suspended)
+			foo_process_next_request(foo);
+		unlock(&foo->private_lock);
+	}
+
+	foo_io_completion(struct foo_priv *foo, void *req)
+	{
+		lock(&foo->private_lock);
+		if (--foo->num_pending_requests == 0) {
+			pm_runtime_mark_last_busy(&foo->dev);
+			pm_runtime_put_autosuspend(&foo->dev);
+		} else {
+			foo_process_next_request(foo);
+		}
+		unlock(&foo->private_lock);
+		/* Send req result back to the user ... */
+	}
+
+	int foo_runtime_suspend(struct device *dev)
+	{
+		struct foo_priv foo = container_of(dev, ...);
+		int ret = 0;
+
+		lock(&foo->private_lock);
+		if (foo->num_pending_requests > 0) {
+			ret = -EBUSY;
+		} else {
+			/* ... suspend the device ... */
+			foo->is_suspended = 1;
+		}
+		unlock(&foo->private_lock);
+		return ret;
+	}
+
+	int foo_runtime_resume(struct device *dev)
+	{
+		struct foo_priv foo = container_of(dev, ...);
+
+		lock(&foo->private_lock);
+		/* ... resume the device ... */
+		foo->is_suspended = 0;
+		pm_runtime_mark_last_busy(&foo->dev);
+		if (foo->num_pending_requests > 0)
+			foo_process_requests(foo);
+		unlock(&foo->private_lock);
+		return 0;
+	}
+
+The important point is that after foo_io_completion() asks for an autosuspend,
+the foo_runtime_suspend() callback may race with foo_read_or_write().
+Therefore foo_runtime_suspend() has to check whether there are any pending I/O
+requests (while holding the private lock) before allowing the suspend to
+proceed.
+
+In addition, the power.autosuspend_delay field can be changed by user space at
+any time.  If a driver cares about this, it can call
+pm_runtime_autosuspend_expiration() from within the ->runtime_suspend()
+callback while holding its private lock.  If the function returns a nonzero
+value then the delay has not yet expired and the callback should return
+-EAGAIN.
diff -druN linux-libre-2.6.36-gnu/Documentation/power/s2ram.txt linux-libre-2.6.37-gnu/Documentation/power/s2ram.txt
--- linux-libre-2.6.36-gnu/Documentation/power/s2ram.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/power/s2ram.txt	2011-01-04 19:50:19.000000000 -0500
@@ -49,6 +49,13 @@
    device (lspci and /sys/devices/pci* is your friend), and see if you can
    fix it, disable it, or trace into its resume function.
 
+   If no device matches the hash (or any matches appear to be false positives),
+   the culprit may be a device from a loadable kernel module that is not loaded
+   until after the hash is checked. You can check the hash against the current
+   devices again after more modules are loaded using sysfs:
+
+	cat /sys/power/pm_trace_dev_match
+
 For example, the above happens to be the VGA device on my EVO, which I
 used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out
 that "radeonfb" simply cannot resume that device - it tries to set the
diff -druN linux-libre-2.6.36-gnu/Documentation/power/swsusp.txt linux-libre-2.6.37-gnu/Documentation/power/swsusp.txt
--- linux-libre-2.6.36-gnu/Documentation/power/swsusp.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/power/swsusp.txt	2011-01-04 19:50:19.000000000 -0500
@@ -66,7 +66,8 @@
 powerdowns.  You must explicitly specify the swap partition to resume from with
 ``resume='' kernel option. If signature is found it loads and restores saved
 state. If the option ``noresume'' is specified as a boot parameter, it skips
-the resuming.
+the resuming.  If the option ``hibernate=nocompress'' is specified as a boot
+parameter, it saves hibernation image without compression.
 
 In the meantime while the system is suspended you should not add/remove any
 of the hardware, write to the filesystems, etc.
diff -druN linux-libre-2.6.36-gnu/Documentation/powerpc/dts-bindings/fsl/spi.txt linux-libre-2.6.37-gnu/Documentation/powerpc/dts-bindings/fsl/spi.txt
--- linux-libre-2.6.36-gnu/Documentation/powerpc/dts-bindings/fsl/spi.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/powerpc/dts-bindings/fsl/spi.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,9 @@
 * SPI (Serial Peripheral Interface)
 
 Required properties:
-- cell-index : SPI controller index.
+- cell-index : QE SPI subblock index.
+		0: QE subblock SPI1
+		1: QE subblock SPI2
 - compatible : should be "fsl,spi".
 - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
 - reg : Offset and length of the register set for the device
@@ -29,3 +31,23 @@
 		gpios = <&gpio 18 1	// device reg=<0>
 			 &gpio 19 1>;	// device reg=<1>
 	};
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+	spi@110000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "fsl,mpc8536-espi";
+		reg = <0x110000 0x1000>;
+		interrupts = <53 0x2>;
+		interrupt-parent = <&mpic>;
+		fsl,espi-num-chipselects = <4>;
+	};
diff -druN linux-libre-2.6.36-gnu/Documentation/powerpc/dts-bindings/fsl/usb.txt linux-libre-2.6.37-gnu/Documentation/powerpc/dts-bindings/fsl/usb.txt
--- linux-libre-2.6.36-gnu/Documentation/powerpc/dts-bindings/fsl/usb.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/powerpc/dts-bindings/fsl/usb.txt	2011-01-04 19:50:19.000000000 -0500
@@ -8,6 +8,7 @@
 Required properties :
  - compatible : Should be "fsl-usb2-mph" for multi port host USB
    controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
  - phy_type : For multi port host USB controllers, should be one of
    "ulpi", or "serial". For dual role USB controllers, should be
    one of "ulpi", "utmi", "utmi_wide", or "serial".
@@ -33,6 +34,12 @@
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the
+   port power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates
+   the PWR_FAULT signal polarity is inverted.
+
 Example multi port host USB controller device node :
 	usb@22000 {
 		compatible = "fsl-usb2-mph";
@@ -57,3 +64,18 @@
 		dr_mode = "otg";
 		phy = "ulpi";
 	};
+
+Example dual role USB controller device node for MPC5121ADS:
+
+	usb@4000 {
+		compatible = "fsl,mpc5121-usb2-dr";
+		reg = <0x4000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = < &ipic >;
+		interrupts = <44 0x8>;
+		dr_mode = "otg";
+		phy_type = "utmi_wide";
+		fsl,invert-drvvbus;
+		fsl,invert-pwr-fault;
+	};
diff -druN linux-libre-2.6.36-gnu/Documentation/rbtree.txt linux-libre-2.6.37-gnu/Documentation/rbtree.txt
--- linux-libre-2.6.36-gnu/Documentation/rbtree.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/rbtree.txt	2011-01-04 19:50:19.000000000 -0500
@@ -21,8 +21,8 @@
 To quote Linux Weekly News:
 
     There are a number of red-black trees in use in the kernel.
-    The anticipatory, deadline, and CFQ I/O schedulers all employ
-    rbtrees to track requests; the packet CD/DVD driver does the same.
+    The deadline and CFQ I/O schedulers employ rbtrees to
+    track requests; the packet CD/DVD driver does the same.
     The high-resolution timer code uses an rbtree to organize outstanding
     timer requests.  The ext3 filesystem tracks directory entries in a
     red-black tree.  Virtual memory areas (VMAs) are tracked with red-black
diff -druN linux-libre-2.6.36-gnu/Documentation/RCU/checklist.txt linux-libre-2.6.37-gnu/Documentation/RCU/checklist.txt
--- linux-libre-2.6.36-gnu/Documentation/RCU/checklist.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/RCU/checklist.txt	2011-01-04 19:50:19.000000000 -0500
@@ -218,13 +218,22 @@
 	include:
 
 	a.	Keeping a count of the number of data-structure elements
-		used by the RCU-protected data structure, including those
-		waiting for a grace period to elapse.  Enforce a limit
-		on this number, stalling updates as needed to allow
-		previously deferred frees to complete.
+		used by the RCU-protected data structure, including
+		those waiting for a grace period to elapse.  Enforce a
+		limit on this number, stalling updates as needed to allow
+		previously deferred frees to complete.	Alternatively,
+		limit only the number awaiting deferred free rather than
+		the total number of elements.
 
-		Alternatively, limit only the number awaiting deferred
-		free rather than the total number of elements.
+		One way to stall the updates is to acquire the update-side
+		mutex.	(Don't try this with a spinlock -- other CPUs
+		spinning on the lock could prevent the grace period
+		from ever ending.)  Another way to stall the updates
+		is for the updates to use a wrapper function around
+		the memory allocator, so that this wrapper function
+		simulates OOM when there is too much memory awaiting an
+		RCU grace period.  There are of course many other
+		variations on this theme.
 
 	b.	Limiting update rate.  For example, if updates occur only
 		once per hour, then no explicit rate limiting is required,
@@ -365,3 +374,26 @@
 	and the compiler to freely reorder code into and out of RCU
 	read-side critical sections.  It is the responsibility of the
 	RCU update-side primitives to deal with this.
+
+17.	Use CONFIG_PROVE_RCU, CONFIG_DEBUG_OBJECTS_RCU_HEAD, and
+	the __rcu sparse checks to validate your RCU code.  These
+	can help find problems as follows:
+
+	CONFIG_PROVE_RCU: check that accesses to RCU-protected data
+		structures are carried out under the proper RCU
+		read-side critical section, while holding the right
+		combination of locks, or whatever other conditions
+		are appropriate.
+
+	CONFIG_DEBUG_OBJECTS_RCU_HEAD: check that you don't pass the
+		same object to call_rcu() (or friends) before an RCU
+		grace period has elapsed since the last time that you
+		passed that same object to call_rcu() (or friends).
+
+	__rcu sparse checks: tag the pointer to the RCU-protected data
+		structure with __rcu, and sparse will warn you if you
+		access that pointer without the services of one of the
+		variants of rcu_dereference().
+
+	These debugging aids can help you find problems that are
+	otherwise extremely difficult to spot.
diff -druN linux-libre-2.6.36-gnu/Documentation/RCU/stallwarn.txt linux-libre-2.6.37-gnu/Documentation/RCU/stallwarn.txt
--- linux-libre-2.6.36-gnu/Documentation/RCU/stallwarn.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/RCU/stallwarn.txt	2011-01-04 19:50:19.000000000 -0500
@@ -80,6 +80,24 @@
 o	For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel
 	without invoking schedule().
 
+o	A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
+	happen to preempt a low-priority task in the middle of an RCU
+	read-side critical section.   This is especially damaging if
+	that low-priority task is not permitted to run on any other CPU,
+	in which case the next RCU grace period can never complete, which
+	will eventually cause the system to run out of memory and hang.
+	While the system is in the process of running itself out of
+	memory, you might see stall-warning messages.
+
+o	A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that
+	is running at a higher priority than the RCU softirq threads.
+	This will prevent RCU callbacks from ever being invoked,
+	and in a CONFIG_TREE_PREEMPT_RCU kernel will further prevent
+	RCU grace periods from ever completing.  Either way, the
+	system will eventually run out of memory and hang.  In the
+	CONFIG_TREE_PREEMPT_RCU case, you might see stall-warning
+	messages.
+
 o	A bug in the RCU implementation.
 
 o	A hardware failure.  This is quite unlikely, but has occurred
diff -druN linux-libre-2.6.36-gnu/Documentation/RCU/trace.txt linux-libre-2.6.37-gnu/Documentation/RCU/trace.txt
--- linux-libre-2.6.36-gnu/Documentation/RCU/trace.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/RCU/trace.txt	2011-01-04 19:50:19.000000000 -0500
@@ -125,6 +125,17 @@
 	of RCU callbacks is ready to invoke, then the remainder will
 	be deferred.
 
+o	"ci" is the number of RCU callbacks that have been invoked for
+	this CPU.  Note that ci+ql is the number of callbacks that have
+	been registered in absence of CPU-hotplug activity.
+
+o	"co" is the number of RCU callbacks that have been orphaned due to
+	this CPU going offline.
+
+o	"ca" is the number of RCU callbacks that have been adopted due to
+	other CPUs going offline.  Note that ci+co-ca+ql is the number of
+	RCU callbacks registered on this CPU.
+
 There is also an rcu/rcudata.csv file with the same information in
 comma-separated-variable spreadsheet format.
 
@@ -180,7 +191,7 @@
 
 o	"jfq" is the number of jiffies remaining for this grace period
 	before force_quiescent_state() is invoked to help push things
-	along.  Note that CPUs in dyntick-idle mode thoughout the grace
+	along.  Note that CPUs in dyntick-idle mode throughout the grace
 	period will not report on their own, but rather must be check by
 	some other CPU via force_quiescent_state().
 
diff -druN linux-libre-2.6.36-gnu/Documentation/scsi/ChangeLog.megaraid_sas linux-libre-2.6.37-gnu/Documentation/scsi/ChangeLog.megaraid_sas
--- linux-libre-2.6.36-gnu/Documentation/scsi/ChangeLog.megaraid_sas	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/scsi/ChangeLog.megaraid_sas	2011-01-04 19:50:19.000000000 -0500
@@ -1,3 +1,50 @@
+1 Release Date    : Thur.  May 03, 2010 09:12:45 PST 2009 -
+			(emaild-id:megaraidlinux@lsi.com)
+			Bo Yang
+
+2 Current Version : 00.00.04.31-rc1
+3 Older Version   : 00.00.04.17.1-rc1
+
+1.	Add the Online Controller Reset (OCR) to the Driver.
+	OCR is the new feature for megaraid_sas driver which
+	will allow the fw to do the chip reset which will not
+	affact the OS behavious.
+
+	To add the OCR support, driver need to do:
+		a). reset the controller chips -- Xscale and Gen2 which
+		will change the function calls and add the reset function
+		related to this two chips.
+
+		b). during the reset, driver will store the pending cmds
+		which not returned by FW to driver's pending queue.  Driver
+		will re-issue those pending cmds again to FW after the OCR
+		finished.
+
+		c). In driver's timeout routine, driver will report to
+		OS as reset. Also driver's queue routine will block the
+		cmds until the OCR finished.
+
+		d). in Driver's ISR routine, if driver get the FW state as
+		state change, FW in Failure status and FW support online controller
+		reset (OCR), driver will start to do the controller reset.
+
+		e). In driver's IOCTL routine, the application cmds will wait for the
+		OCR to finish, then issue the cmds to FW.
+
+		f). Before driver kill adapter, driver will do last chance of
+		OCR to see if driver can bring back the FW.
+
+2.	Add the support update flag to the driver to tell LSI megaraid_sas
+	application which driver will support the device update.  So application
+	will not need to do the device update after application add/del the device
+	from the system.
+3.	In driver's timeout routine, driver will do three time reset if fw is in
+	failed state.  Driver will kill adapter if can't bring back FW after the
+	this three times reset.
+4.	Add the input parameter max_sectors to 1MB support to our GEN2 controller.
+	customer can use the input paramenter max_sectors to add 1MB support to GEN2
+	controller.
+
 1 Release Date    : Thur.  Oct 29, 2009 09:12:45 PST 2009 -
 			(emaild-id:megaraidlinux@lsi.com)
 			Bo Yang
diff -druN linux-libre-2.6.36-gnu/Documentation/scsi/scsi_mid_low_api.txt linux-libre-2.6.37-gnu/Documentation/scsi/scsi_mid_low_api.txt
--- linux-libre-2.6.36-gnu/Documentation/scsi/scsi_mid_low_api.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/scsi/scsi_mid_low_api.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1044,9 +1044,9 @@
 
 
 /**
- *      queuecommand - queue scsi command, invoke 'done' on completion
+ *      queuecommand - queue scsi command, invoke scp->scsi_done on completion
+ *      @shost: pointer to the scsi host object
  *      @scp: pointer to scsi command object
- *      @done: function pointer to be invoked on completion
  *
  *      Returns 0 on success.
  *
@@ -1074,42 +1074,45 @@
  *
  *      Other types of errors that are detected immediately may be
  *      flagged by setting scp->result to an appropriate value,
- *      invoking the 'done' callback, and then returning 0 from this
- *      function. If the command is not performed immediately (and the
- *      LLD is starting (or will start) the given command) then this
- *      function should place 0 in scp->result and return 0.
+ *      invoking the scp->scsi_done callback, and then returning 0
+ *      from this function. If the command is not performed
+ *      immediately (and the LLD is starting (or will start) the given
+ *      command) then this function should place 0 in scp->result and
+ *      return 0.
  *
  *      Command ownership.  If the driver returns zero, it owns the
- *      command and must take responsibility for ensuring the 'done'
- *      callback is executed.  Note: the driver may call done before
- *      returning zero, but after it has called done, it may not
- *      return any value other than zero.  If the driver makes a
- *      non-zero return, it must not execute the command's done
- *      callback at any time.
+ *      command and must take responsibility for ensuring the
+ *      scp->scsi_done callback is executed.  Note: the driver may
+ *      call scp->scsi_done before returning zero, but after it has
+ *      called scp->scsi_done, it may not return any value other than
+ *      zero.  If the driver makes a non-zero return, it must not
+ *      execute the command's scsi_done callback at any time.
  *
- *      Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
- *             and is expected to be held on return.
+ *      Locks: up to and including 2.6.36, struct Scsi_Host::host_lock
+ *             held on entry (with "irqsave") and is expected to be
+ *             held on return. From 2.6.37 onwards, queuecommand is
+ *             called without any locks held.
  *
  *      Calling context: in interrupt (soft irq) or process context
  *
- *      Notes: This function should be relatively fast. Normally it will
- *      not wait for IO to complete. Hence the 'done' callback is invoked 
- *      (often directly from an interrupt service routine) some time after
- *      this function has returned. In some cases (e.g. pseudo adapter 
- *      drivers that manufacture the response to a SCSI INQUIRY)
- *      the 'done' callback may be invoked before this function returns.
- *      If the 'done' callback is not invoked within a certain period
- *      the SCSI mid level will commence error processing.
- *      If a status of CHECK CONDITION is placed in "result" when the
- *      'done' callback is invoked, then the LLD driver should 
- *      perform autosense and fill in the struct scsi_cmnd::sense_buffer
+ *      Notes: This function should be relatively fast. Normally it
+ *      will not wait for IO to complete. Hence the scp->scsi_done
+ *      callback is invoked (often directly from an interrupt service
+ *      routine) some time after this function has returned. In some
+ *      cases (e.g. pseudo adapter drivers that manufacture the
+ *      response to a SCSI INQUIRY) the scp->scsi_done callback may be
+ *      invoked before this function returns.  If the scp->scsi_done
+ *      callback is not invoked within a certain period the SCSI mid
+ *      level will commence error processing.  If a status of CHECK
+ *      CONDITION is placed in "result" when the scp->scsi_done
+ *      callback is invoked, then the LLD driver should perform
+ *      autosense and fill in the struct scsi_cmnd::sense_buffer
  *      array. The scsi_cmnd::sense_buffer array is zeroed prior to
  *      the mid level queuing a command to an LLD.
  *
  *      Defined in: LLD
  **/
-    int queuecommand(struct scsi_cmnd * scp, 
-                     void (*done)(struct scsi_cmnd *))
+    int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp)
 
 
 /**
diff -druN linux-libre-2.6.36-gnu/Documentation/scsi/st.txt linux-libre-2.6.37-gnu/Documentation/scsi/st.txt
--- linux-libre-2.6.36-gnu/Documentation/scsi/st.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/scsi/st.txt	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai MÃ¤kisara (email
 Kai.Makisara@kolumbus.fi)
 
-Last modified: Sun Feb 24 21:59:07 2008 by kai.makisara
+Last modified: Sun Aug 29 18:25:47 2010 by kai.makisara
 
 
 BASICS
@@ -85,6 +85,17 @@
 optionally written. In both cases end of data is signified by
 returning zero bytes for two consecutive reads.
 
+Writing filemarks without the immediate bit set in the SCSI command block acts
+as a synchronization point, i.e., all remaining data form the drive buffers is
+written to tape before the command returns. This makes sure that write errors
+are caught at that point, but this takes time. In some applications, several
+consecutive files must be written fast. The MTWEOFI operation can be used to
+write the filemarks without flushing the drive buffer. Writing filemark at
+close() is always flushing the drive buffers. However, if the previous
+operation is MTWEOFI, close() does not write a filemark. This can be used if
+the program wants to close/open the tape device between files and wants to
+skip waiting.
+
 If rewind, offline, bsf, or seek is done and previous tape operation was
 write, a filemark is written before moving tape.
 
@@ -301,6 +312,8 @@
 MTFSS   Space forward over count setmarks.
 MTBSS   Space backward over count setmarks.
 MTWEOF  Write count filemarks.
+MTWEOFI	Write count filemarks with immediate bit set (i.e., does not
+	wait until data is on tape)
 MTWSM   Write count setmarks.
 MTREW   Rewind tape.
 MTOFFL  Set device off line (often rewind plus eject).
diff -druN linux-libre-2.6.36-gnu/Documentation/sh/clk.txt linux-libre-2.6.37-gnu/Documentation/sh/clk.txt
--- linux-libre-2.6.36-gnu/Documentation/sh/clk.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sh/clk.txt	1969-12-31 19:00:00.000000000 -0500
@@ -1,32 +0,0 @@
-Clock framework on SuperH architecture
-
-The framework on SH extends existing API by the function clk_set_rate_ex,
-which prototype is as follows:
-
-    clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
-
-The algo_id parameter is used to specify algorithm used to recalculate clocks,
-adjanced to clock, specified as first argument. It is assumed that algo_id==0
-means no changes to adjanced clock
-
-Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
-if it is present in ops structure. The method should set the clock rate and adjust
-all needed clocks according to the passed algo_id.
-Exact values for algo_id are machine-dependent. For the sh7722, the following
-values are defined:
-
-	NO_CHANGE	= 0,
-	IUS_N1_N1,	/* I:U = N:1, U:Sh = N:1 */
-	IUS_322,	/* I:U:Sh = 3:2:2	 */
-	IUS_522,	/* I:U:Sh = 5:2:2 	 */
-	IUS_N11,	/* I:U:Sh = N:1:1	 */
-	SB_N1,		/* Sh:B = N:1		 */
-	SB3_N1,		/* Sh:B3 = N:1		 */
-	SB3_32,		/* Sh:B3 = 3:2		 */
-	SB3_43,		/* Sh:B3 = 4:3		 */
-	SB3_54,		/* Sh:B3 = 5:4		 */
-	BP_N1,		/* B:P	 = N:1		 */
-	IP_N1		/* I:P	 = N:1		 */
-
-Each of these constants means relation between clocks that can be set via the FRQCR
-register
diff -druN linux-libre-2.6.36-gnu/Documentation/sound/alsa/ALSA-Configuration.txt linux-libre-2.6.37-gnu/Documentation/sound/alsa/ALSA-Configuration.txt
--- linux-libre-2.6.36-gnu/Documentation/sound/alsa/ALSA-Configuration.txt	2012-03-23 22:02:50.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sound/alsa/ALSA-Configuration.txt	2012-03-23 23:53:31.000000000 -0400
@@ -300,6 +300,74 @@
            control correctly. If you have problems regarding this, try
            another ALSA compliant mixer (alsamixer works).
 
+  Module snd-azt1605
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT1605
+    chipset.
+
+    port	- port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port	- port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq		- IRQ # for WSS (7,9,10,11)
+    dma1	- DMA # for WSS playback (0,1,3)
+    dma2	- DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port	- port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq	- IRQ # for MPU-401 UART (3,5,7,9), -1 = disabled (default)
+    fm_port	- port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
+  Module snd-azt2316
+  ------------------
+
+    Module for Aztech Sound Galaxy soundcards based on the Aztech AZT2316
+    chipset.
+
+    port	- port # for BASE (0x220,0x240,0x260,0x280)
+    wss_port	- port # for WSS (0x530,0x604,0xe80,0xf40)
+    irq		- IRQ # for WSS (7,9,10,11)
+    dma1	- DMA # for WSS playback (0,1,3)
+    dma2	- DMA # for WSS capture (0,1), -1 = disabled (default)
+    mpu_port	- port # for MPU-401 UART (0x300,0x330), -1 = disabled (default)
+    mpu_irq	- IRQ # for MPU-401 UART (5,7,9,10), -1 = disabled (default)
+    fm_port	- port # for OPL3 (0x388), -1 = disabled (default)
+
+    This module supports multiple cards. It does not support autoprobe: port,
+    wss_port, irq and dma1 have to be specified. The other values are
+    optional.
+
+    "port" needs to match the BASE ADDRESS jumper on the card (0x220 or 0x240)
+    or the value stored in the card's EEPROM for cards that have an EEPROM and
+    their "CONFIG MODE" jumper set to "EEPROM SETTING". The other values can
+    be choosen freely from the options enumerated above.
+
+    If dma2 is specified and different from dma1, the card will operate in
+    full-duplex mode. When dma1=3, only dma2=0 is valid and the only way to
+    enable capture since only channels 0 and 1 are available for capture.
+
+    Generic settings are "port=0x220 wss_port=0x530 irq=10 dma1=1 dma2=0
+    mpu_port=0x330 mpu_irq=9 fm_port=0x388".
+
+    Whatever IRQ and DMA channels you pick, be sure to reserve them for
+    legacy ISA in your BIOS.
+
   Module snd-aw2
   --------------
 
@@ -1641,20 +1709,6 @@
 
     This card is also known as Audio Excel DSP 16 or Zoltrix AV302.
 
-  Module snd-sgalaxy
-  ------------------
-
-    Module for Aztech Sound Galaxy sound card.
-
-    sbport	- Port # for SB16 interface (0x220,0x240)
-    wssport	- Port # for WSS interface (0x530,0xe80,0xf40,0x604)
-    irq		- IRQ # (7,9,10,11)
-    dma1	- DMA #
-
-    This module supports multiple cards.
-
-    The power-management is supported.
-
   Module snd-sscape
   -----------------
 
diff -druN linux-libre-2.6.36-gnu/Documentation/sound/alsa/HD-Audio.txt linux-libre-2.6.37-gnu/Documentation/sound/alsa/HD-Audio.txt
--- linux-libre-2.6.36-gnu/Documentation/sound/alsa/HD-Audio.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sound/alsa/HD-Audio.txt	2011-01-04 19:50:19.000000000 -0500
@@ -57,9 +57,11 @@
 a case, you can change the default method via `position_fix` option.
 
 `position_fix=1` means to use LPIB method explicitly.
-`position_fix=2` means to use the position-buffer.  0 is the default
-value, the automatic check and fallback to LPIB as described in the
-above.  If you get a problem of repeated sounds, this option might
+`position_fix=2` means to use the position-buffer.
+`position_fix=3` means to use a combination of both methods, needed
+for some VIA and ATI controllers.  0 is the default value for all other
+controllers, the automatic check and fallback to LPIB as described in
+the above.  If you get a problem of repeated sounds, this option might
 help.
 
 In addition to that, every controller is known to be broken regarding
diff -druN linux-libre-2.6.36-gnu/Documentation/sysctl/kernel.txt linux-libre-2.6.37-gnu/Documentation/sysctl/kernel.txt
--- linux-libre-2.6.36-gnu/Documentation/sysctl/kernel.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sysctl/kernel.txt	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 - core_uses_pid
 - ctrl-alt-del
 - dentry-state
+- dmesg_restrict
 - domainname
 - hostname
 - hotplug
@@ -213,6 +214,19 @@
 
 ==============================================================
 
+dmesg_restrict:
+
+This toggle indicates whether unprivileged users are prevented from using
+dmesg(8) to view messages from the kernel's log buffer.  When
+dmesg_restrict is set to (0) there are no restrictions.  When
+dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use
+dmesg(8).
+
+The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default
+value of dmesg_restrict.
+
+==============================================================
+
 domainname & hostname:
 
 These files can be used to set the NIS/YP domainname and the
diff -druN linux-libre-2.6.36-gnu/Documentation/sysctl/vm.txt linux-libre-2.6.37-gnu/Documentation/sysctl/vm.txt
--- linux-libre-2.6.36-gnu/Documentation/sysctl/vm.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sysctl/vm.txt	2011-01-04 19:50:19.000000000 -0500
@@ -80,8 +80,10 @@
 Contains the amount of dirty memory at which the pdflush background writeback
 daemon will start writeback.
 
-If dirty_background_bytes is written, dirty_background_ratio becomes a function
-of its value (dirty_background_bytes / the amount of dirtyable system memory).
+Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only
+one of them may be specified at a time. When one sysctl is written it is
+immediately taken into account to evaluate the dirty memory limits and the
+other appears as 0 when read.
 
 ==============================================================
 
@@ -97,8 +99,10 @@
 Contains the amount of dirty memory at which a process generating disk writes
 will itself start writeback.
 
-If dirty_bytes is written, dirty_ratio becomes a function of its value
-(dirty_bytes / the amount of dirtyable system memory).
+Note: dirty_bytes is the counterpart of dirty_ratio. Only one of them may be
+specified at a time. When one sysctl is written it is immediately taken into
+account to evaluate the dirty memory limits and the other appears as 0 when
+read.
 
 Note: the minimum value allowed for dirty_bytes is two pages (in bytes); any
 value lower than this limit will be ignored and the old configuration will be
diff -druN linux-libre-2.6.36-gnu/Documentation/sysrq.txt linux-libre-2.6.37-gnu/Documentation/sysrq.txt
--- linux-libre-2.6.36-gnu/Documentation/sysrq.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/sysrq.txt	2011-01-04 19:50:19.000000000 -0500
@@ -75,7 +75,7 @@
 
 'f'	- Will call oom_kill to kill a memory hog process.
 
-'g'	- Used by kgdb on ppc and sh platforms.
+'g'	- Used by kgdb (kernel debugger)
 
 'h'     - Will display help (actually any other key than those listed
           here will display help. but 'h' is easy to remember :-)
@@ -110,12 +110,15 @@
 
 'u'     - Will attempt to remount all mounted filesystems read-only.
 
-'v'	- Dumps Voyager SMP processor info to your console.
+'v'	- Forcefully restores framebuffer console
+'v'	- Causes ETM buffer dump [ARM-specific]
 
 'w'	- Dumps tasks that are in uninterruptable (blocked) state.
 
 'x'	- Used by xmon interface on ppc/powerpc platforms.
 
+'y'	- Show global CPU Registers [SPARC-64 specific]
+
 'z'	- Dump the ftrace buffer
 
 '0'-'9' - Sets the console log level, controlling which kernel messages
diff -druN linux-libre-2.6.36-gnu/Documentation/timers/hpet_example.c linux-libre-2.6.37-gnu/Documentation/timers/hpet_example.c
--- linux-libre-2.6.36-gnu/Documentation/timers/hpet_example.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/timers/hpet_example.c	2011-01-04 19:50:19.000000000 -0500
@@ -97,6 +97,33 @@
 void
 hpet_info(int argc, const char **argv)
 {
+	struct hpet_info	info;
+	int			fd;
+
+	if (argc != 1) {
+		fprintf(stderr, "hpet_info: device-name\n");
+		return;
+	}
+
+	fd = open(argv[0], O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]);
+		return;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_info: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ",
+		info.hi_ireqfreq, info.hi_flags);
+	fprintf(stderr, "hi_hpet %d hi_timer %d\n",
+		info.hi_hpet, info.hi_timer);
+
+out:
+	close(fd);
+	return;
 }
 
 void
diff -druN linux-libre-2.6.36-gnu/Documentation/trace/postprocess/trace-vmscan-postprocess.pl linux-libre-2.6.37-gnu/Documentation/trace/postprocess/trace-vmscan-postprocess.pl
--- linux-libre-2.6.36-gnu/Documentation/trace/postprocess/trace-vmscan-postprocess.pl	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/trace/postprocess/trace-vmscan-postprocess.pl	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 use constant HIGH_KSWAPD_REWAKEUP		=> 21;
 use constant HIGH_NR_SCANNED			=> 22;
 use constant HIGH_NR_TAKEN			=> 23;
-use constant HIGH_NR_RECLAIM			=> 24;
+use constant HIGH_NR_RECLAIMED			=> 24;
 use constant HIGH_NR_CONTIG_DIRTY		=> 25;
 
 my %perprocesspid;
@@ -58,11 +58,13 @@
 my $total_wakeup_kswapd;
 my ($total_direct_reclaim, $total_direct_nr_scanned);
 my ($total_direct_latency, $total_kswapd_latency);
+my ($total_direct_nr_reclaimed);
 my ($total_direct_writepage_file_sync, $total_direct_writepage_file_async);
 my ($total_direct_writepage_anon_sync, $total_direct_writepage_anon_async);
 my ($total_kswapd_nr_scanned, $total_kswapd_wake);
 my ($total_kswapd_writepage_file_sync, $total_kswapd_writepage_file_async);
 my ($total_kswapd_writepage_anon_sync, $total_kswapd_writepage_anon_async);
+my ($total_kswapd_nr_reclaimed);
 
 # Catch sigint and exit on request
 my $sigint_report = 0;
@@ -104,7 +106,7 @@
 my $regex_kswapd_sleep_default = 'nid=([0-9]*)';
 my $regex_wakeup_kswapd_default = 'nid=([0-9]*) zid=([0-9]*) order=([0-9]*)';
 my $regex_lru_isolate_default = 'isolate_mode=([0-9]*) order=([0-9]*) nr_requested=([0-9]*) nr_scanned=([0-9]*) nr_taken=([0-9]*) contig_taken=([0-9]*) contig_dirty=([0-9]*) contig_failed=([0-9]*)';
-my $regex_lru_shrink_inactive_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*)';
+my $regex_lru_shrink_inactive_default = 'nid=([0-9]*) zid=([0-9]*) nr_scanned=([0-9]*) nr_reclaimed=([0-9]*) priority=([0-9]*) flags=([A-Z_|]*)';
 my $regex_lru_shrink_active_default = 'lru=([A-Z_]*) nr_scanned=([0-9]*) nr_rotated=([0-9]*) priority=([0-9]*)';
 my $regex_writepage_default = 'page=([0-9a-f]*) pfn=([0-9]*) flags=([A-Z_|]*)';
 
@@ -203,8 +205,8 @@
 			"vmscan/mm_vmscan_lru_shrink_inactive",
 			$regex_lru_shrink_inactive_default,
 			"nid", "zid",
-			"lru",
-			"nr_scanned", "nr_reclaimed", "priority");
+			"nr_scanned", "nr_reclaimed", "priority",
+			"flags");
 $regex_lru_shrink_active = generate_traceevent_regex(
 			"vmscan/mm_vmscan_lru_shrink_active",
 			$regex_lru_shrink_active_default,
@@ -371,10 +373,29 @@
 				print "         $regex_lru_isolate/o\n";
 				next;
 			}
+			my $isolate_mode = $1;
 			my $nr_scanned = $4;
 			my $nr_contig_dirty = $7;
-			$perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
+
+			# To closer match vmstat scanning statistics, only count isolate_both
+			# and isolate_inactive as scanning. isolate_active is rotation
+			# isolate_inactive == 0
+			# isolate_active   == 1
+			# isolate_both     == 2
+			if ($isolate_mode != 1) {
+				$perprocesspid{$process_pid}->{HIGH_NR_SCANNED} += $nr_scanned;
+			}
 			$perprocesspid{$process_pid}->{HIGH_NR_CONTIG_DIRTY} += $nr_contig_dirty;
+		} elsif ($tracepoint eq "mm_vmscan_lru_shrink_inactive") {
+			$details = $5;
+			if ($details !~ /$regex_lru_shrink_inactive/o) {
+				print "WARNING: Failed to parse mm_vmscan_lru_shrink_inactive as expected\n";
+				print "         $details\n";
+				print "         $regex_lru_shrink_inactive/o\n";
+				next;
+			}
+			my $nr_reclaimed = $4;
+			$perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED} += $nr_reclaimed;
 		} elsif ($tracepoint eq "mm_vmscan_writepage") {
 			$details = $5;
 			if ($details !~ /$regex_writepage/o) {
@@ -464,8 +485,8 @@
 
 	# Print out process activity
 	printf("\n");
-	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s %8s\n", "Process", "Direct",  "Wokeup", "Pages",   "Pages",   "Pages",     "Time");
-	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s %8s\n", "details", "Rclms",   "Kswapd", "Scanned", "Sync-IO", "ASync-IO",  "Stalled");
+	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s  %8s %8s %8s %8s\n", "Process", "Direct",  "Wokeup", "Pages",   "Pages",   "Pages",   "Pages",     "Time");
+	printf("%-" . $max_strlen . "s %8s %10s   %8s %8s  %8s %8s %8s %8s\n", "details", "Rclms",   "Kswapd", "Scanned", "Rclmed",  "Sync-IO", "ASync-IO",  "Stalled");
 	foreach $process_pid (keys %stats) {
 
 		if (!$stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN}) {
@@ -475,6 +496,7 @@
 		$total_direct_reclaim += $stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN};
 		$total_wakeup_kswapd += $stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
 		$total_direct_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+		$total_direct_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
 		$total_direct_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
 		$total_direct_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
 		$total_direct_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
@@ -489,11 +511,12 @@
 			$index++;
 		}
 
-		printf("%-" . $max_strlen . "s %8d %10d   %8u   %8u %8u %8.3f",
+		printf("%-" . $max_strlen . "s %8d %10d   %8u %8u  %8u %8u %8.3f",
 			$process_pid,
 			$stats{$process_pid}->{MM_VMSCAN_DIRECT_RECLAIM_BEGIN},
 			$stats{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD},
 			$stats{$process_pid}->{HIGH_NR_SCANNED},
+			$stats{$process_pid}->{HIGH_NR_RECLAIMED},
 			$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
 			$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC},
 			$this_reclaim_delay / 1000);
@@ -529,8 +552,8 @@
 
 	# Print out kswapd activity
 	printf("\n");
-	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Kswapd",   "Kswapd",  "Order",     "Pages",   "Pages",  "Pages");
-	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Sync-IO", "ASync-IO");
+	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Kswapd",   "Kswapd",  "Order",     "Pages",   "Pages",   "Pages",  "Pages");
+	printf("%-" . $max_strlen . "s %8s %10s   %8s   %8s %8s %8s\n", "Instance", "Wakeups", "Re-wakeup", "Scanned", "Rclmed",  "Sync-IO", "ASync-IO");
 	foreach $process_pid (keys %stats) {
 
 		if (!$stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE}) {
@@ -539,16 +562,18 @@
 
 		$total_kswapd_wake += $stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE};
 		$total_kswapd_nr_scanned += $stats{$process_pid}->{HIGH_NR_SCANNED};
+		$total_kswapd_nr_reclaimed += $stats{$process_pid}->{HIGH_NR_RECLAIMED};
 		$total_kswapd_writepage_file_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
 		$total_kswapd_writepage_anon_sync += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
 		$total_kswapd_writepage_file_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
 		$total_kswapd_writepage_anon_async += $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC};
 
-		printf("%-" . $max_strlen . "s %8d %10d   %8u   %8i %8u",
+		printf("%-" . $max_strlen . "s %8d %10d   %8u %8u  %8i %8u",
 			$process_pid,
 			$stats{$process_pid}->{MM_VMSCAN_KSWAPD_WAKE},
 			$stats{$process_pid}->{HIGH_KSWAPD_REWAKEUP},
 			$stats{$process_pid}->{HIGH_NR_SCANNED},
+			$stats{$process_pid}->{HIGH_NR_RECLAIMED},
 			$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC},
 			$stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} + $stats{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_ASYNC});
 
@@ -579,6 +604,7 @@
 	print "\nSummary\n";
 	print "Direct reclaims:     			$total_direct_reclaim\n";
 	print "Direct reclaim pages scanned:		$total_direct_nr_scanned\n";
+	print "Direct reclaim pages reclaimed:		$total_direct_nr_reclaimed\n";
 	print "Direct reclaim write file sync I/O:	$total_direct_writepage_file_sync\n";
 	print "Direct reclaim write anon sync I/O:	$total_direct_writepage_anon_sync\n";
 	print "Direct reclaim write file async I/O:	$total_direct_writepage_file_async\n";
@@ -588,6 +614,7 @@
 	print "\n";
 	print "Kswapd wakeups:				$total_kswapd_wake\n";
 	print "Kswapd pages scanned:			$total_kswapd_nr_scanned\n";
+	print "Kswapd pages reclaimed:			$total_kswapd_nr_reclaimed\n";
 	print "Kswapd reclaim write file sync I/O:	$total_kswapd_writepage_file_sync\n";
 	print "Kswapd reclaim write anon sync I/O:	$total_kswapd_writepage_anon_sync\n";
 	print "Kswapd reclaim write file async I/O:	$total_kswapd_writepage_file_async\n";
@@ -612,6 +639,7 @@
 		$perprocess{$process}->{MM_VMSCAN_WAKEUP_KSWAPD} += $perprocesspid{$process_pid}->{MM_VMSCAN_WAKEUP_KSWAPD};
 		$perprocess{$process}->{HIGH_KSWAPD_REWAKEUP} += $perprocesspid{$process_pid}->{HIGH_KSWAPD_REWAKEUP};
 		$perprocess{$process}->{HIGH_NR_SCANNED} += $perprocesspid{$process_pid}->{HIGH_NR_SCANNED};
+		$perprocess{$process}->{HIGH_NR_RECLAIMED} += $perprocesspid{$process_pid}->{HIGH_NR_RECLAIMED};
 		$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_SYNC};
 		$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_ANON_SYNC};
 		$perprocess{$process}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC} += $perprocesspid{$process_pid}->{MM_VMSCAN_WRITEPAGE_FILE_ASYNC};
diff -druN linux-libre-2.6.36-gnu/Documentation/usb/proc_usb_info.txt linux-libre-2.6.37-gnu/Documentation/usb/proc_usb_info.txt
--- linux-libre-2.6.36-gnu/Documentation/usb/proc_usb_info.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/usb/proc_usb_info.txt	2011-01-04 19:50:19.000000000 -0500
@@ -1,12 +1,17 @@
 /proc/bus/usb filesystem output
 ===============================
-(version 2003.05.30)
+(version 2010.09.13)
 
 
 The usbfs filesystem for USB devices is traditionally mounted at
 /proc/bus/usb.  It provides the /proc/bus/usb/devices file, as well as
 the /proc/bus/usb/BBB/DDD files.
 
+In many modern systems the usbfs filsystem isn't used at all.  Instead
+USB device nodes are created under /dev/usb/ or someplace similar.  The
+"devices" file is available in debugfs, typically as
+/sys/kernel/debug/usb/devices.
+
 
 **NOTE**: If /proc/bus/usb appears empty, and a host controller
 	  driver has been linked, then you need to mount the
@@ -106,8 +111,8 @@
 
 Topology info:
 
-T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
-|   |      |      |       |       |      |        |       |__MaxChildren
+T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd
+|   |      |      |       |       |      |        |        |__MaxChildren
 |   |      |      |       |       |      |        |__Device Speed in Mbps
 |   |      |      |       |       |      |__DeviceNumber
 |   |      |      |       |       |__Count of devices at this level
@@ -120,8 +125,13 @@
     Speed may be:
     	1.5	Mbit/s for low speed USB
 	12	Mbit/s for full speed USB
-	480	Mbit/s for high speed USB (added for USB 2.0)
+	480	Mbit/s for high speed USB (added for USB 2.0);
+		  also used for Wireless USB, which has no fixed speed
+	5000	Mbit/s for SuperSpeed USB (added for USB 3.0)
 
+    For reasons lost in the mists of time, the Port number is always
+    too low by 1.  For example, a device plugged into port 4 will
+    show up with "Port=03".
 
 Bandwidth info:
 B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
@@ -291,7 +301,7 @@
 an external hub connected to the root hub, and a mouse and
 a serial converter connected to the external hub.
 
-T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 2
 B:  Alloc= 28/900 us ( 3%), #Int=  2, #Iso=  0
 D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0000 ProdID=0000 Rev= 0.00
@@ -301,21 +311,21 @@
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
 E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
 
-T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 4
 D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0451 ProdID=1446 Rev= 1.00
 C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
 E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
 
-T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5  MxCh= 0
 D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=04b4 ProdID=0001 Rev= 0.00
 C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
 E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
 
-T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
 D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
 P:  Vendor=0565 ProdID=0001 Rev= 1.08
 S:  Manufacturer=Peracom Networks, Inc.
@@ -330,12 +340,12 @@
 Selecting only the "T:" and "I:" lines from this (for example, by using
 "procusb ti"), we have:
 
-T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
-T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12   MxCh= 2
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12   MxCh= 4
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
-T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5  MxCh= 0
 I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
-T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12   MxCh= 0
 I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
 
 
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/bttv/MAKEDEV linux-libre-2.6.37-gnu/Documentation/video4linux/bttv/MAKEDEV
--- linux-libre-2.6.36-gnu/Documentation/video4linux/bttv/MAKEDEV	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/bttv/MAKEDEV	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,6 @@
 echo "*** new device names ***"
 makedev video 0
 makedev radio 64
-makedev vtx 192
 makedev vbi 224
 
 #echo "*** old device names (for compatibility only) ***"
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.cx88 linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.cx88
--- linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.cx88	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.cx88	2011-01-04 19:50:19.000000000 -0500
@@ -83,3 +83,4 @@
  82 -> WinFast DTV2000 H rev. J                            [107d:6f2b]
  83 -> Prof 7301 DVB-S/S2                                  [b034:3034]
  84 -> Samsung SMT 7020 DVB-S                              [18ac:dc00,18ac:dccd]
+ 85 -> Twinhan VP-1027 DVB-S                               [1822:0023]
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.em28xx linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.em28xx
--- linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.em28xx	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.em28xx	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
  30 -> Videology 20K14XUSB USB2.0               (em2820/em2840)
  31 -> Usbgear VD204v9                          (em2821)
  32 -> Supercomp USB 2.0 TV                     (em2821)
+ 33 -> Elgato Video Capture                     (em2860)        [0fd9:0033]
  34 -> Terratec Cinergy A Hybrid XS             (em2860)        [0ccd:004f]
  35 -> Typhoon DVD Maker                        (em2860)
  36 -> NetGMBH Cam                              (em2860)
@@ -45,7 +46,7 @@
  45 -> Pinnacle PCTV DVB-T                      (em2870)
  46 -> Compro, VideoMate U3                     (em2870)        [185b:2870]
  47 -> KWorld DVB-T 305U                        (em2880)        [eb1a:e305]
- 48 -> KWorld DVB-T 310U                        (em2880)        [eb1a:e310]
+ 48 -> KWorld DVB-T 310U                        (em2880)
  49 -> MSI DigiVox A/D                          (em2880)        [eb1a:e310]
  50 -> MSI DigiVox A/D II                       (em2880)        [eb1a:e320]
  51 -> Terratec Hybrid XS Secam                 (em2880)        [0ccd:004c]
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.saa7134 linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.saa7134
--- linux-libre-2.6.36-gnu/Documentation/video4linux/CARDLIST.saa7134	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/CARDLIST.saa7134	2011-01-04 19:50:19.000000000 -0500
@@ -126,7 +126,7 @@
 125 -> Beholder BeholdTV 409                    [0000:4090]
 126 -> Beholder BeholdTV 505 FM                 [5ace:5050]
 127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
-128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
+128 -> Beholder BeholdTV Columbus TV/FM         [0000:5201]
 129 -> Beholder BeholdTV 607 FM                 [5ace:6070]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/gspca.txt linux-libre-2.6.37-gnu/Documentation/video4linux/gspca.txt
--- linux-libre-2.6.36-gnu/Documentation/video4linux/gspca.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/gspca.txt	2011-01-04 19:50:19.000000000 -0500
@@ -302,12 +302,14 @@
 sonixj		0c45:60fc	LG-LIC300
 sonixj		0c45:60fe	Microdia Audio
 sonixj		0c45:6100	PC Camera (SN9C128)
+sonixj		0c45:6102	PC Camera (SN9C128)
 sonixj		0c45:610a	PC Camera (SN9C128)
 sonixj		0c45:610b	PC Camera (SN9C128)
 sonixj		0c45:610c	PC Camera (SN9C128)
 sonixj		0c45:610e	PC Camera (SN9C128)
 sonixj		0c45:6128	Microdia/Sonix SNP325
 sonixj		0c45:612a	Avant Camera
+sonixj		0c45:612b	Speed-Link REFLECT2
 sonixj		0c45:612c	Typhoon Rasy Cam 1.3MPix
 sonixj		0c45:6130	Sonix Pccam
 sonixj		0c45:6138	Sn9c120 Mo4000
diff -druN linux-libre-2.6.36-gnu/Documentation/video4linux/v4l2-framework.txt linux-libre-2.6.37-gnu/Documentation/video4linux/v4l2-framework.txt
--- linux-libre-2.6.36-gnu/Documentation/video4linux/v4l2-framework.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/video4linux/v4l2-framework.txt	2011-01-04 19:50:19.000000000 -0500
@@ -44,8 +44,8 @@
 
 2) A way of initializing and commanding sub-devices (if any).
 
-3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
-   /dev/vtxX) and keeping track of device-node specific data.
+3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX and /dev/radioX)
+   and keeping track of device-node specific data.
 
 4) Filehandle-specific structs containing per-filehandle data;
 
@@ -192,6 +192,11 @@
 common i2c_client struct the i2c_set_clientdata() call is used to store a
 v4l2_subdev pointer, for other busses you may have to use other methods.
 
+Bridges might also need to store per-subdev private data, such as a pointer to
+bridge-specific per-subdev private data. The v4l2_subdev structure provides
+host private data for that purpose that can be accessed with
+v4l2_get_subdev_hostdata() and v4l2_set_subdev_hostdata().
+
 From the bridge driver perspective you load the sub-device module and somehow
 obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
 i2c_get_clientdata(). For other busses something similar needs to be done.
@@ -448,6 +453,10 @@
 - ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
   (highly recommended to use this and it might become compulsory in the
   future!), then set this to your v4l2_ioctl_ops struct.
+- lock: leave to NULL if you want to do all the locking in the driver.
+  Otherwise you give it a pointer to a struct mutex_lock and before any
+  of the v4l2_file_operations is called this lock will be taken by the
+  core and released afterwards.
 - parent: you only set this if v4l2_device was registered with NULL as
   the parent device struct. This only happens in cases where one hardware
   device has multiple PCI devices that all share the same v4l2_device core.
@@ -464,6 +473,22 @@
 The v4l2_file_operations struct is a subset of file_operations. The main
 difference is that the inode argument is omitted since it is never used.
 
+v4l2_file_operations and locking
+--------------------------------
+
+You can set a pointer to a mutex_lock in struct video_device. Usually this
+will be either a top-level mutex or a mutex per device node. If you want
+finer-grained locking then you have to set it to NULL and do you own locking.
+
+If a lock is specified then all file operations will be serialized on that
+lock. If you use videobuf then you must pass the same lock to the videobuf
+queue initialize function: if videobuf has to wait for a frame to arrive, then
+it will temporarily unlock the lock and relock it afterwards. If your driver
+also waits in the code, then you should do the same to allow other processes
+to access the device node while the first process is waiting for something.
+
+The implementation of a hotplug disconnect should also take the lock before
+calling v4l2_device_disconnect.
 
 video_device registration
 -------------------------
@@ -483,7 +508,6 @@
 VFL_TYPE_GRABBER: videoX for video input/output devices
 VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
 VFL_TYPE_RADIO: radioX for radio tuners
-VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
 
 The last argument gives you a certain amount of control over the device
 device node number used (i.e. the X in videoX). Normally you will pass -1
@@ -547,9 +571,8 @@
 
 After video_unregister_device() returns no new opens can be done. However,
 in the case of USB devices some application might still have one of these
-device nodes open. So after the unregister all file operations will return
-an error as well, except for the ioctl and unlocked_ioctl file operations:
-those will still be passed on since some buffer ioctls may still be needed.
+device nodes open. So after the unregister all file operations (except
+release, of course) will return an error as well.
 
 When the last user of the video device node exits, then the vdev->release()
 callback is called and you can do the final cleanup there.
diff -druN linux-libre-2.6.36-gnu/Documentation/vm/highmem.txt linux-libre-2.6.37-gnu/Documentation/vm/highmem.txt
--- linux-libre-2.6.36-gnu/Documentation/vm/highmem.txt	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/Documentation/vm/highmem.txt	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,162 @@
+
+			     ====================
+			     HIGH MEMORY HANDLING
+			     ====================
+
+By: Peter Zijlstra <a.p.zijlstra@chello.nl>
+
+Contents:
+
+ (*) What is high memory?
+
+ (*) Temporary virtual mappings.
+
+ (*) Using kmap_atomic.
+
+ (*) Cost of temporary mappings.
+
+ (*) i386 PAE.
+
+
+====================
+WHAT IS HIGH MEMORY?
+====================
+
+High memory (highmem) is used when the size of physical memory approaches or
+exceeds the maximum size of virtual memory.  At that point it becomes
+impossible for the kernel to keep all of the available physical memory mapped
+at all times.  This means the kernel needs to start using temporary mappings of
+the pieces of physical memory that it wants to access.
+
+The part of (physical) memory not covered by a permanent mapping is what we
+refer to as 'highmem'.  There are various architecture dependent constraints on
+where exactly that border lies.
+
+In the i386 arch, for example, we choose to map the kernel into every process's
+VM space so that we don't have to pay the full TLB invalidation costs for
+kernel entry/exit.  This means the available virtual memory space (4GiB on
+i386) has to be divided between user and kernel space.
+
+The traditional split for architectures using this approach is 3:1, 3GiB for
+userspace and the top 1GiB for kernel space:
+
+		+--------+ 0xffffffff
+		| Kernel |
+		+--------+ 0xc0000000
+		|        |
+		| User   |
+		|        |
+		+--------+ 0x00000000
+
+This means that the kernel can at most map 1GiB of physical memory at any one
+time, but because we need virtual address space for other things - including
+temporary maps to access the rest of the physical memory - the actual direct
+map will typically be less (usually around ~896MiB).
+
+Other architectures that have mm context tagged TLBs can have separate kernel
+and user maps.  Some hardware (like some ARMs), however, have limited virtual
+space when they use mm context tags.
+
+
+==========================
+TEMPORARY VIRTUAL MAPPINGS
+==========================
+
+The kernel contains several ways of creating temporary mappings:
+
+ (*) vmap().  This can be used to make a long duration mapping of multiple
+     physical pages into a contiguous virtual space.  It needs global
+     synchronization to unmap.
+
+ (*) kmap().  This permits a short duration mapping of a single page.  It needs
+     global synchronization, but is amortized somewhat.  It is also prone to
+     deadlocks when using in a nested fashion, and so it is not recommended for
+     new code.
+
+ (*) kmap_atomic().  This permits a very short duration mapping of a single
+     page.  Since the mapping is restricted to the CPU that issued it, it
+     performs well, but the issuing task is therefore required to stay on that
+     CPU until it has finished, lest some other task displace its mappings.
+
+     kmap_atomic() may also be used by interrupt contexts, since it is does not
+     sleep and the caller may not sleep until after kunmap_atomic() is called.
+
+     It may be assumed that k[un]map_atomic() won't fail.
+
+
+=================
+USING KMAP_ATOMIC
+=================
+
+When and where to use kmap_atomic() is straightforward.  It is used when code
+wants to access the contents of a page that might be allocated from high memory
+(see __GFP_HIGHMEM), for example a page in the pagecache.  The API has two
+functions, and they can be used in a manner similar to the following:
+
+	/* Find the page of interest. */
+	struct page *page = find_get_page(mapping, offset);
+
+	/* Gain access to the contents of that page. */
+	void *vaddr = kmap_atomic(page);
+
+	/* Do something to the contents of that page. */
+	memset(vaddr, 0, PAGE_SIZE);
+
+	/* Unmap that page. */
+	kunmap_atomic(vaddr);
+
+Note that the kunmap_atomic() call takes the result of the kmap_atomic() call
+not the argument.
+
+If you need to map two pages because you want to copy from one page to
+another you need to keep the kmap_atomic calls strictly nested, like:
+
+	vaddr1 = kmap_atomic(page1);
+	vaddr2 = kmap_atomic(page2);
+
+	memcpy(vaddr1, vaddr2, PAGE_SIZE);
+
+	kunmap_atomic(vaddr2);
+	kunmap_atomic(vaddr1);
+
+
+==========================
+COST OF TEMPORARY MAPPINGS
+==========================
+
+The cost of creating temporary mappings can be quite high.  The arch has to
+manipulate the kernel's page tables, the data TLB and/or the MMU's registers.
+
+If CONFIG_HIGHMEM is not set, then the kernel will try and create a mapping
+simply with a bit of arithmetic that will convert the page struct address into
+a pointer to the page contents rather than juggling mappings about.  In such a
+case, the unmap operation may be a null operation.
+
+If CONFIG_MMU is not set, then there can be no temporary mappings and no
+highmem.  In such a case, the arithmetic approach will also be used.
+
+
+========
+i386 PAE
+========
+
+The i386 arch, under some circumstances, will permit you to stick up to 64GiB
+of RAM into your 32-bit machine.  This has a number of consequences:
+
+ (*) Linux needs a page-frame structure for each page in the system and the
+     pageframes need to live in the permanent mapping, which means:
+
+ (*) you can have 896M/sizeof(struct page) page-frames at most; with struct
+     page being 32-bytes that would end up being something in the order of 112G
+     worth of pages; the kernel, however, needs to store more than just
+     page-frames in that memory...
+
+ (*) PAE makes your page tables larger - which slows the system down as more
+     data has to be accessed to traverse in TLB fills and the like.  One
+     advantage is that PAE has more PTE bits and can provide advanced features
+     like NX and PAT.
+
+The general recommendation is that you don't use more than 8GiB on a 32-bit
+machine - although more might work for you and your workload, you're pretty
+much on your own - don't expect kernel developers to really care much if things
+come apart.
diff -druN linux-libre-2.6.36-gnu/Documentation/vm/numa_memory_policy.txt linux-libre-2.6.37-gnu/Documentation/vm/numa_memory_policy.txt
--- linux-libre-2.6.36-gnu/Documentation/vm/numa_memory_policy.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/vm/numa_memory_policy.txt	2011-01-04 19:50:19.000000000 -0500
@@ -424,7 +424,7 @@
 
 + set the shared policy for a shared memory segment via mbind(2)
 
-The numactl(8) tool is packages with the run-time version of the library
+The numactl(8) tool is packaged with the run-time version of the library
 containing the memory policy system call wrappers.  Some distributions
 package the headers and compile-time libraries in a separate development
 package.
diff -druN linux-libre-2.6.36-gnu/Documentation/workqueue.txt linux-libre-2.6.37-gnu/Documentation/workqueue.txt
--- linux-libre-2.6.36-gnu/Documentation/workqueue.txt	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/workqueue.txt	2011-01-04 19:50:19.000000000 -0500
@@ -196,11 +196,11 @@
 	suspend operations.  Work items on the wq are drained and no
 	new work item starts execution until thawed.
 
-  WQ_RESCUER
+  WQ_MEM_RECLAIM
 
 	All wq which might be used in the memory reclaim paths _MUST_
-	have this flag set.  This reserves one worker exclusively for
-	the execution of this wq under memory pressure.
+	have this flag set.  The wq is guaranteed to have at least one
+	execution context regardless of memory pressure.
 
   WQ_HIGHPRI
 
@@ -356,11 +356,11 @@
 
 6. Guidelines
 
-* Do not forget to use WQ_RESCUER if a wq may process work items which
-  are used during memory reclaim.  Each wq with WQ_RESCUER set has one
-  rescuer thread reserved for it.  If there is dependency among
-  multiple work items used during memory reclaim, they should be
-  queued to separate wq each with WQ_RESCUER.
+* Do not forget to use WQ_MEM_RECLAIM if a wq may process work items
+  which are used during memory reclaim.  Each wq with WQ_MEM_RECLAIM
+  set has an execution context reserved for it.  If there is
+  dependency among multiple work items used during memory reclaim,
+  they should be queued to separate wq each with WQ_MEM_RECLAIM.
 
 * Unless strict ordering is required, there is no need to use ST wq.
 
@@ -368,12 +368,13 @@
   recommended.  In most use cases, concurrency level usually stays
   well under the default limit.
 
-* A wq serves as a domain for forward progress guarantee (WQ_RESCUER),
-  flush and work item attributes.  Work items which are not involved
-  in memory reclaim and don't need to be flushed as a part of a group
-  of work items, and don't require any special attribute, can use one
-  of the system wq.  There is no difference in execution
-  characteristics between using a dedicated wq and a system wq.
+* A wq serves as a domain for forward progress guarantee
+  (WQ_MEM_RECLAIM, flush and work item attributes.  Work items which
+  are not involved in memory reclaim and don't need to be flushed as a
+  part of a group of work items, and don't require any special
+  attribute, can use one of the system wq.  There is no difference in
+  execution characteristics between using a dedicated wq and a system
+  wq.
 
 * Unless work items are expected to consume a huge amount of CPU
   cycles, using a bound wq is usually beneficial due to the increased
diff -druN linux-libre-2.6.36-gnu/Documentation/x86/x86_64/kernel-stacks linux-libre-2.6.37-gnu/Documentation/x86/x86_64/kernel-stacks
--- linux-libre-2.6.36-gnu/Documentation/x86/x86_64/kernel-stacks	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/Documentation/x86/x86_64/kernel-stacks	2011-01-04 19:50:19.000000000 -0500
@@ -18,9 +18,9 @@
   Used for external hardware interrupts.  If this is the first external
   hardware interrupt (i.e. not a nested hardware interrupt) then the
   kernel switches from the current task to the interrupt stack.  Like
-  the split thread and interrupt stacks on i386 (with CONFIG_4KSTACKS),
-  this gives more room for kernel interrupt processing without having
-  to increase the size of every per thread stack.
+  the split thread and interrupt stacks on i386, this gives more room
+  for kernel interrupt processing without having to increase the size
+  of every per thread stack.
 
   The interrupt stack is also used when processing a softirq.
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/ac.c linux-libre-2.6.37-gnu/drivers/acpi/ac.c
--- linux-libre-2.6.36-gnu/drivers/acpi/ac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/ac.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,9 +32,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -86,9 +84,7 @@
 };
 
 struct acpi_ac {
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	struct power_supply charger;
-#endif
 	struct acpi_device * device;
 	unsigned long long state;
 };
@@ -104,26 +100,7 @@
 	.release = single_release,
 };
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
-static int get_ac_property(struct power_supply *psy,
-			   enum power_supply_property psp,
-			   union power_supply_propval *val)
-{
-	struct acpi_ac *ac = to_acpi_ac(psy);
-	switch (psp) {
-	case POWER_SUPPLY_PROP_ONLINE:
-		val->intval = ac->state;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
 
-static enum power_supply_property ac_props[] = {
-	POWER_SUPPLY_PROP_ONLINE,
-};
-#endif
 /* --------------------------------------------------------------------------
                                AC Adapter Management
    -------------------------------------------------------------------------- */
@@ -146,6 +123,35 @@
 	return 0;
 }
 
+/* --------------------------------------------------------------------------
+                            sysfs I/F
+   -------------------------------------------------------------------------- */
+static int get_ac_property(struct power_supply *psy,
+			   enum power_supply_property psp,
+			   union power_supply_propval *val)
+{
+	struct acpi_ac *ac = to_acpi_ac(psy);
+
+	if (!ac)
+		return -ENODEV;
+
+	if (acpi_ac_get_state(ac))
+		return -ENODEV;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = ac->state;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static enum power_supply_property ac_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
 #ifdef CONFIG_ACPI_PROCFS_POWER
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
@@ -247,9 +253,7 @@
 						  dev_name(&device->dev), event,
 						  (u32) ac->state);
 		acpi_notifier_call_chain(device, event, (u32) ac->state);
-#ifdef CONFIG_ACPI_SYSFS_POWER
 		kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
 	}
 
 	return;
@@ -282,14 +286,12 @@
 #endif
 	if (result)
 		goto end;
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	ac->charger.name = acpi_device_bid(device);
 	ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
 	ac->charger.properties = ac_props;
 	ac->charger.num_properties = ARRAY_SIZE(ac_props);
 	ac->charger.get_property = get_ac_property;
 	power_supply_register(&ac->device->dev, &ac->charger);
-#endif
 
 	printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
 	       acpi_device_name(device), acpi_device_bid(device),
@@ -316,10 +318,8 @@
 	old_state = ac->state;
 	if (acpi_ac_get_state(ac))
 		return 0;
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (old_state != ac->state)
 		kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
-#endif
 	return 0;
 }
 
@@ -333,10 +333,8 @@
 
 	ac = acpi_driver_data(device);
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (ac->charger.dev)
 		power_supply_unregister(&ac->charger);
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
 	acpi_ac_remove_fs(device);
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acdebug.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acdebug.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acdebug.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acdebug.h	2011-01-04 19:50:19.000000000 -0500
@@ -105,6 +105,8 @@
 acpi_status
 acpi_db_display_objects(char *obj_type_arg, char *display_count_arg);
 
+void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg);
+
 acpi_status acpi_db_find_name_in_namespace(char *name_arg);
 
 void acpi_db_set_scope(char *name);
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acevents.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acevents.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acevents.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acevents.h	2011-01-04 19:50:19.000000000 -0500
@@ -105,8 +105,9 @@
 			 struct acpi_gpe_block_info **return_gpe_block);
 
 acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
-			     struct acpi_gpe_block_info *gpe_block);
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+			     struct acpi_gpe_block_info *gpe_block,
+			     void *ignored);
 
 acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acglobal.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acglobal.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acglobal.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acglobal.h	2011-01-04 19:50:19.000000000 -0500
@@ -132,6 +132,7 @@
 u32 acpi_current_gpe_count;
 u32 acpi_gbl_trace_flags;
 acpi_name acpi_gbl_trace_method_name;
+u8 acpi_gbl_system_awake_and_running;
 
 #endif
 
@@ -187,6 +188,10 @@
 ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
 
+/* Mutex for _OSI support */
+
+ACPI_EXTERN acpi_mutex acpi_gbl_osi_mutex;
+
 /* Reader/Writer lock is used for namespace walk and dynamic table unload */
 
 ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock;
@@ -255,6 +260,7 @@
 ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
 ACPI_EXTERN void *acpi_gbl_table_handler_context;
 ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+ACPI_EXTERN acpi_interface_handler acpi_gbl_interface_handler;
 
 /* Owner ID support */
 
@@ -273,8 +279,8 @@
 ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
 ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
 ACPI_EXTERN u8 acpi_gbl_events_initialized;
-ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
 ACPI_EXTERN u8 acpi_gbl_osi_data;
+ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces;
 
 #ifndef DEFINE_ACPI_GLOBALS
 
@@ -364,6 +370,7 @@
 ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
 ACPI_EXTERN struct acpi_gpe_block_info
 *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+ACPI_EXTERN u8 acpi_all_gpes_initialized;
 
 /*****************************************************************************
  *
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/achware.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/achware.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/achware.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/achware.h	2011-01-04 19:50:19.000000000 -0500
@@ -121,6 +121,13 @@
 				 struct acpi_gpe_block_info *gpe_block,
 				 void *context);
 
+/*
+ * hwpci - PCI configuration support
+ */
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+		      acpi_handle root_pci_device, acpi_handle pci_region);
+
 #ifdef	ACPI_FUTURE_USAGE
 /*
  * hwtimer - ACPI Timer prototypes
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/aclocal.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/aclocal.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/aclocal.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/aclocal.h	2011-01-04 19:50:19.000000000 -0500
@@ -413,6 +413,7 @@
 	void *context;		/* Context to be passed to handler */
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
 	u8 orig_flags;		/* Original misc info about this GPE */
+	u8 orig_enabled;	/* Set if the GPE was originally enabled */
 };
 
 union acpi_gpe_dispatch_info {
@@ -457,6 +458,7 @@
 	u32 register_count;	/* Number of register pairs in block */
 	u16 gpe_count;		/* Number of individual GPEs in block */
 	u8 block_base_number;	/* Base GPE number for this block */
+	u8 initialized;         /* If set, the GPE block has been initialized */
 };
 
 /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
@@ -473,7 +475,6 @@
 	struct acpi_gpe_block_info *gpe_block;
 	u16 count;
 	acpi_owner_id owner_id;
-	u8 enable_this_gpe;
 	u8 execute_by_owner_id;
 };
 
@@ -854,7 +855,7 @@
 	ACPI_BITMASK_POWER_BUTTON_STATUS   | \
 	ACPI_BITMASK_SLEEP_BUTTON_STATUS   | \
 	ACPI_BITMASK_RT_CLOCK_STATUS       | \
-	ACPI_BITMASK_PCIEXP_WAKE_DISABLE   | \
+	ACPI_BITMASK_PCIEXP_WAKE_STATUS    | \
 	ACPI_BITMASK_WAKE_STATUS)
 
 #define ACPI_BITMASK_TIMER_ENABLE               0x0001
@@ -909,15 +910,21 @@
 #define ACPI_OSI_WIN_VISTA              0x07
 #define ACPI_OSI_WINSRV_2008            0x08
 #define ACPI_OSI_WIN_VISTA_SP1          0x09
-#define ACPI_OSI_WIN_7                  0x0A
+#define ACPI_OSI_WIN_VISTA_SP2          0x0A
+#define ACPI_OSI_WIN_7                  0x0B
 
 #define ACPI_ALWAYS_ILLEGAL             0x00
 
 struct acpi_interface_info {
 	char *name;
+	struct acpi_interface_info *next;
+	u8 flags;
 	u8 value;
 };
 
+#define ACPI_OSI_INVALID                0x01
+#define ACPI_OSI_DYNAMIC                0x02
+
 struct acpi_port_info {
 	char *name;
 	u16 start;
@@ -997,7 +1004,7 @@
 struct acpi_db_method_info {
 	acpi_handle main_thread_gate;
 	acpi_handle thread_complete_gate;
-	u32 *threads;
+	acpi_thread_id *threads;
 	u32 num_threads;
 	u32 num_created;
 	u32 num_completed;
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acmacros.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acmacros.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acmacros.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acmacros.h	2011-01-04 19:50:19.000000000 -0500
@@ -338,8 +338,8 @@
  * the plist contains a set of parens to allow variable-length lists.
  * These macros are used for both the debug and non-debug versions of the code.
  */
-#define ACPI_ERROR_NAMESPACE(s, e)      acpi_ns_report_error (AE_INFO, s, e);
-#define ACPI_ERROR_METHOD(s, n, p, e)   acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+#define ACPI_ERROR_NAMESPACE(s, e)      acpi_ut_namespace_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e)   acpi_ut_method_error (AE_INFO, s, n, p, e);
 #define ACPI_WARN_PREDEFINED(plist)     acpi_ut_predefined_warning plist
 #define ACPI_INFO_PREDEFINED(plist)     acpi_ut_predefined_info plist
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acnamesp.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acnamesp.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acnamesp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acnamesp.h	2011-01-04 19:50:19.000000000 -0500
@@ -339,18 +339,6 @@
 u32 acpi_ns_local(acpi_object_type type);
 
 void
-acpi_ns_report_error(const char *module_name,
-		     u32 line_number,
-		     const char *internal_name, acpi_status lookup_status);
-
-void
-acpi_ns_report_method_error(const char *module_name,
-			    u32 line_number,
-			    const char *message,
-			    struct acpi_namespace_node *node,
-			    const char *path, acpi_status lookup_status);
-
-void
 acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg);
 
 acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info);
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acobject.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acobject.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acobject.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acobject.h	2011-01-04 19:50:19.000000000 -0500
@@ -248,7 +248,7 @@
 	u32                             base_byte_offset;   /* Byte offset within containing object */\
 	u32                             value;              /* Value to store into the Bank or Index register */\
 	u8                              start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
-	u8                              access_bit_width;	/* Read/Write size in bits (8-64) */
+
 
 struct acpi_object_field_common {	/* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
 	ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj;	/* Parent Operation Region object (REGION/BANK fields only) */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/acutils.h linux-libre-2.6.37-gnu/drivers/acpi/acpica/acutils.h
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/acutils.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/acutils.h	2011-01-04 19:50:19.000000000 -0500
@@ -312,8 +312,6 @@
 /*
  * uteval - object evaluation
  */
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
-
 acpi_status
 acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
 			char *path,
@@ -395,6 +393,21 @@
 acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
 
 /*
+ * utosi - Support for the _OSI predefined control method
+ */
+acpi_status acpi_ut_initialize_interfaces(void);
+
+void acpi_ut_interface_terminate(void);
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name);
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
+
+/*
  * utstate - Generic state creation/cache routines
  */
 void
@@ -473,17 +486,6 @@
 
 acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer);
 
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
-			   u32 line_number,
-			   char *pathname,
-			   u8 node_flags, const char *format, ...);
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
-			u32 line_number,
-			char *pathname, u8 node_flags, const char *format, ...);
-
 /* Values for Base above (16=Hex, 10=Decimal) */
 
 #define ACPI_ANY_BASE        0
@@ -574,6 +576,32 @@
 acpi_ut_create_list(char *list_name,
 		    u16 object_size, struct acpi_memory_list **return_cache);
 
-#endif
+#endif				/* ACPI_DBG_TRACK_ALLOCATIONS */
+
+/*
+ * utxferror - various error/warning output functions
+ */
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+			   u32 line_number,
+			   char *pathname,
+			   u8 node_flags, const char *format, ...);
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+			u32 line_number,
+			char *pathname, u8 node_flags, const char *format, ...);
+
+void
+acpi_ut_namespace_error(const char *module_name,
+			u32 line_number,
+			const char *internal_name, acpi_status lookup_status);
+
+void
+acpi_ut_method_error(const char *module_name,
+		     u32 line_number,
+		     const char *message,
+		     struct acpi_namespace_node *node,
+		     const char *path, acpi_status lookup_status);
 
 #endif				/* _ACUTILS_H */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/dsmethod.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/dsmethod.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/dsmethod.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/dsmethod.c	2011-01-04 19:50:19.000000000 -0500
@@ -573,7 +573,7 @@
 
 				acpi_os_release_mutex(method_desc->method.
 						      mutex->mutex.os_mutex);
-				method_desc->method.mutex->mutex.thread_id = NULL;
+				method_desc->method.mutex->mutex.thread_id = 0;
 			}
 		}
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/dswexec.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/dswexec.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/dswexec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/dswexec.c	2011-01-04 19:50:19.000000000 -0500
@@ -300,10 +300,25 @@
 			 * we must enter this object into the namespace.  The created
 			 * object is temporary and will be deleted upon completion of
 			 * the execution of this method.
+			 *
+			 * Note 10/2010: Except for the Scope() op. This opcode does
+			 * not actually create a new object, it refers to an existing
+			 * object. However, for Scope(), we want to indeed open a
+			 * new scope.
 			 */
-			status = acpi_ds_load2_begin_op(walk_state, NULL);
+			if (op->common.aml_opcode != AML_SCOPE_OP) {
+				status =
+				    acpi_ds_load2_begin_op(walk_state, NULL);
+			} else {
+				status =
+				    acpi_ds_scope_stack_push(op->named.node,
+							     op->named.node->
+							     type, walk_state);
+				if (ACPI_FAILURE(status)) {
+					return_ACPI_STATUS(status);
+				}
+			}
 		}
-
 		break;
 
 	case AML_CLASS_EXECUTE:
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evevent.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evevent.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evevent.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evevent.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,47 +95,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ev_install_fadt_gpes
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
- *              (0 and 1). The HW must be fully initialized at this point,
- *              including global lock support.
- *
- ******************************************************************************/
-
-acpi_status acpi_ev_install_fadt_gpes(void)
-{
-	acpi_status status;
-
-	ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
-
-	/* Namespace must be locked */
-
-	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-	if (ACPI_FAILURE(status)) {
-		return (status);
-	}
-
-	/* FADT GPE Block 0 */
-
-	(void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
-					   acpi_gbl_gpe_fadt_blocks[0]);
-
-	/* FADT GPE Block 1 */
-
-	(void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
-					   acpi_gbl_gpe_fadt_blocks[1]);
-
-	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-	return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ev_install_xrupt_handlers
  *
  * PARAMETERS:  None
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evgpeblk.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evgpeblk.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evgpeblk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evgpeblk.c	2011-01-04 19:50:19.000000000 -0500
@@ -363,6 +363,7 @@
 	gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
 	gpe_block->register_count = register_count;
 	gpe_block->block_base_number = gpe_block_base_number;
+	gpe_block->initialized = FALSE;
 
 	ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
 		    sizeof(struct acpi_generic_address));
@@ -385,11 +386,12 @@
 		return_ACPI_STATUS(status);
 	}
 
+	acpi_all_gpes_initialized = FALSE;
+
 	/* Find all GPE methods (_Lxx or_Exx) for this block */
 
 	walk_info.gpe_block = gpe_block;
 	walk_info.gpe_device = gpe_device;
-	walk_info.enable_this_gpe = FALSE;
 	walk_info.execute_by_owner_id = FALSE;
 
 	status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
@@ -434,35 +436,34 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
-			     struct acpi_gpe_block_info *gpe_block)
+acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+			     struct acpi_gpe_block_info *gpe_block,
+			     void *ignored)
 {
 	acpi_status status;
 	struct acpi_gpe_event_info *gpe_event_info;
 	u32 gpe_enabled_count;
 	u32 gpe_index;
-	u32 gpe_number;
 	u32 i;
 	u32 j;
 
 	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
 
-	/* Ignore a null GPE block (e.g., if no GPE block 1 exists) */
-
-	if (!gpe_block) {
+	/*
+	 * Ignore a null GPE block (e.g., if no GPE block 1 exists) and
+	 * GPE blocks that have been initialized already.
+	 */
+	if (!gpe_block || gpe_block->initialized) {
 		return_ACPI_STATUS(AE_OK);
 	}
 
 	/*
-	 * Enable all GPEs that have a corresponding method.  Any other GPEs
-	 * within this block must be enabled via the acpi_enable_gpe interface.
+	 * Enable all GPEs that have a corresponding method and have the
+	 * ACPI_GPE_CAN_WAKE flag unset.  Any other GPEs within this block must
+	 * be enabled via the acpi_enable_gpe() interface.
 	 */
 	gpe_enabled_count = 0;
 
-	if (gpe_device == acpi_gbl_fadt_gpe_device) {
-		gpe_device = NULL;
-	}
-
 	for (i = 0; i < gpe_block->register_count; i++) {
 		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
 
@@ -470,27 +471,19 @@
 
 			gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
 			gpe_event_info = &gpe_block->event_info[gpe_index];
-			gpe_number = gpe_index + gpe_block->block_base_number;
 
 			/* Ignore GPEs that have no corresponding _Lxx/_Exx method */
 
-			if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) {
+			if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
 				continue;
 			}
 
-			/*
-			 * If the GPE has already been enabled for runtime
-			 * signaling, make sure it remains enabled, but do not
-			 * increment its reference counter.
-			 */
-			status = gpe_event_info->runtime_count ?
-				acpi_ev_enable_gpe(gpe_event_info) :
-				acpi_enable_gpe(gpe_device, gpe_number);
-
+			status = acpi_raw_enable_gpe(gpe_event_info);
 			if (ACPI_FAILURE(status)) {
 				ACPI_EXCEPTION((AE_INFO, status,
-						"Could not enable GPE 0x%02X",
-						gpe_number));
+					"Could not enable GPE 0x%02X",
+					gpe_index + gpe_block->block_base_number));
 				continue;
 			}
 
@@ -504,5 +497,7 @@
 				  gpe_enabled_count));
 	}
 
+	gpe_block->initialized = TRUE;
+
 	return_ACPI_STATUS(AE_OK);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evgpeinit.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evgpeinit.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evgpeinit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evgpeinit.c	2011-01-04 19:50:19.000000000 -0500
@@ -210,8 +210,7 @@
  *
  * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
  *              result of a Load() or load_table() operation. If new GPE
- *              methods have been installed, register the new methods and
- *              enable and runtime GPEs that are associated with them.
+ *              methods have been installed, register the new methods.
  *
  ******************************************************************************/
 
@@ -239,7 +238,6 @@
 	walk_info.owner_id = table_owner_id;
 	walk_info.execute_by_owner_id = TRUE;
 	walk_info.count = 0;
-	walk_info.enable_this_gpe = TRUE;
 
 	/* Walk the interrupt level descriptor list */
 
@@ -301,8 +299,6 @@
  *
  * If walk_info->execute_by_owner_id is TRUE, we only execute examine GPE methods
  *    with that owner.
- * If walk_info->enable_this_gpe is TRUE, the GPE that is referred to by a GPE
- *    method is immediately enabled (Used for Load/load_table operators)
  *
  ******************************************************************************/
 
@@ -315,8 +311,6 @@
 	struct acpi_gpe_walk_info *walk_info =
 	    ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
 	struct acpi_gpe_event_info *gpe_event_info;
-	struct acpi_namespace_node *gpe_device;
-	acpi_status status;
 	u32 gpe_number;
 	char name[ACPI_NAME_SIZE + 1];
 	u8 type;
@@ -414,6 +408,9 @@
 		return_ACPI_STATUS(AE_OK);
 	}
 
+	/* Disable the GPE in case it's been enabled already. */
+	(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+
 	/*
 	 * Add the GPE information from above to the gpe_event_info block for
 	 * use during dispatch of this GPE.
@@ -421,29 +418,6 @@
 	gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_METHOD);
 	gpe_event_info->dispatch.method_node = method_node;
 
-	/*
-	 * Enable this GPE if requested. This only happens when during the
-	 * execution of a Load or load_table operator. We have found a new
-	 * GPE method and want to immediately enable the GPE if it is a
-	 * runtime GPE.
-	 */
-	if (walk_info->enable_this_gpe) {
-
-		walk_info->count++;
-		gpe_device = walk_info->gpe_device;
-
-		if (gpe_device == acpi_gbl_fadt_gpe_device) {
-			gpe_device = NULL;
-		}
-
-		status = acpi_enable_gpe(gpe_device, gpe_number);
-		if (ACPI_FAILURE(status)) {
-			ACPI_EXCEPTION((AE_INFO, status,
-					"Could not enable GPE 0x%02X",
-					gpe_number));
-		}
-	}
-
 	ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
 			  "Registered GPE method %s as GPE number 0x%.2X\n",
 			  name, gpe_number));
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evmisc.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evmisc.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evmisc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evmisc.c	2011-01-04 19:50:19.000000000 -0500
@@ -553,7 +553,7 @@
 	acpi_gbl_global_lock_acquired = FALSE;
 
 	/* Release the local GL mutex */
-	acpi_ev_global_lock_thread_id = NULL;
+	acpi_ev_global_lock_thread_id = 0;
 	acpi_ev_global_lock_acquired = 0;
 	acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
 	return_ACPI_STATUS(status);
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evrgnini.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evrgnini.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evrgnini.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evrgnini.c	2011-01-04 19:50:19.000000000 -0500
@@ -289,8 +289,8 @@
 	}
 
 	/*
-	 * Get the PCI device and function numbers from the _ADR object contained
-	 * in the parent's scope.
+	 * Get the PCI device and function numbers from the _ADR object
+	 * contained in the parent's scope.
 	 */
 	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
 						 pci_device_node, &pci_value);
@@ -320,9 +320,15 @@
 		pci_id->bus = ACPI_LOWORD(pci_value);
 	}
 
-	/* Complete this device's pci_id */
+	/* Complete/update the PCI ID for this device */
 
-	acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id);
+	status =
+	    acpi_hw_derive_pci_id(pci_id, pci_root_node,
+				  region_obj->region.node);
+	if (ACPI_FAILURE(status)) {
+		ACPI_FREE(pci_id);
+		return_ACPI_STATUS(status);
+	}
 
 	*region_context = pci_id;
 	return_ACPI_STATUS(AE_OK);
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxface.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxface.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxface.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxface.c	2011-01-04 19:50:19.000000000 -0500
@@ -726,15 +726,16 @@
 			(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 
 	/*
-	 * If the GPE is associated with a method and it cannot wake up the
-	 * system from sleep states, it was enabled automatically during
-	 * initialization, so it has to be disabled now to avoid spurious
-	 * execution of the handler.
+	 * If the GPE is associated with a method, it might have been enabled
+	 * automatically during initialization, in which case it has to be
+	 * disabled now to avoid spurious execution of the handler.
 	 */
 
 	if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
-	    && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+	    && gpe_event_info->runtime_count) {
+		handler->orig_enabled = 1;
 		(void)acpi_raw_disable_gpe(gpe_event_info);
+	}
 
 	/* Install the handler */
 
@@ -837,13 +838,13 @@
 	gpe_event_info->flags |= handler->orig_flags;
 
 	/*
-	 * If the GPE was previously associated with a method and it cannot wake
-	 * up the system from sleep states, it should be enabled at this point
-	 * to restore the post-initialization configuration.
+	 * If the GPE was previously associated with a method and it was
+	 * enabled, it should be enabled at this point to restore the
+	 * post-initialization configuration.
 	 */
 
 	if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
-	    && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
+	    && handler->orig_enabled)
 		(void)acpi_raw_enable_gpe(gpe_event_info);
 
 	/* Now we can free the handler object */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxfevnt.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxfevnt.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxfevnt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxfevnt.c	2011-01-04 19:50:19.000000000 -0500
@@ -379,21 +379,12 @@
 	/* Ensure that we have a valid GPE number */
 
 	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-	if (!gpe_event_info) {
+	if (gpe_event_info) {
+		gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+	} else {
 		status = AE_BAD_PARAMETER;
-		goto unlock_and_exit;
-	}
-
-	if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
-		goto unlock_and_exit;
-	}
-
-	gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
-	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
-		(void)acpi_raw_disable_gpe(gpe_event_info);
 	}
 
-unlock_and_exit:
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 	return_ACPI_STATUS(status);
 }
@@ -651,7 +642,7 @@
 		       struct acpi_generic_address *gpe_block_address,
 		       u32 register_count, u32 interrupt_number)
 {
-	acpi_status status;
+	acpi_status status = AE_OK;
 	union acpi_operand_object *obj_desc;
 	struct acpi_namespace_node *node;
 	struct acpi_gpe_block_info *gpe_block;
@@ -715,10 +706,6 @@
 
 	obj_desc->device.gpe_block = gpe_block;
 
-	/* Enable the runtime GPEs in the new block */
-
-	status = acpi_ev_initialize_gpe_block(node, gpe_block);
-
       unlock_and_exit:
 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 	return_ACPI_STATUS(status);
@@ -923,4 +910,44 @@
 	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
 	return_ACPI_STATUS(status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_update_gpes
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Enable all GPEs that have associated _Lxx or _Exx methods and
+ *              are not pointed to by any device _PRW methods indicating that
+ *              these GPEs are generally intended for system or device wakeup
+ *              (such GPEs have to be enabled directly when the devices whose
+ *              _PRW methods point to them are set up for wakeup signaling).
+ *
+ ******************************************************************************/
+
+acpi_status acpi_update_gpes(void)
+{
+	acpi_status status;
+
+	ACPI_FUNCTION_TRACE(acpi_update_gpes);
+
+	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	} else if (acpi_all_gpes_initialized) {
+		goto unlock;
+	}
+
+	status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);
+	if (ACPI_SUCCESS(status)) {
+		acpi_all_gpes_initialized = TRUE;
+	}
+
+unlock:
+	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+	return_ACPI_STATUS(status);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxfregn.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxfregn.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/evxfregn.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/evxfregn.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,6 +64,12 @@
  *
  * DESCRIPTION: Install a handler for all op_regions of a given space_id.
  *
+ * NOTE: This function should only be called after acpi_enable_subsystem has
+ * been called. This is because any _REG methods associated with the Space ID
+ * are executed here, and these methods can only be safely executed after
+ * the default handlers have been installed and the hardware has been
+ * initialized (via acpi_enable_subsystem.)
+ *
  ******************************************************************************/
 acpi_status
 acpi_install_address_space_handler(acpi_handle device,
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/exfldio.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/exfldio.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/exfldio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/exfldio.c	2011-01-04 19:50:19.000000000 -0500
@@ -119,8 +119,8 @@
 	}
 
 	/*
-	 * Exit now for SMBus or IPMI address space, it has a non-linear address space
-	 * and the request cannot be directly validated
+	 * Exit now for SMBus or IPMI address space, it has a non-linear
+	 * address space and the request cannot be directly validated
 	 */
 	if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS ||
 	    rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) {
@@ -147,8 +147,7 @@
 	 * (Region length is specified in bytes)
 	 */
 	if (rgn_desc->region.length <
-	    (obj_desc->common_field.base_byte_offset +
-	     field_datum_byte_offset +
+	    (obj_desc->common_field.base_byte_offset + field_datum_byte_offset +
 	     obj_desc->common_field.access_byte_width)) {
 		if (acpi_gbl_enable_interpreter_slack) {
 			/*
@@ -680,6 +679,7 @@
 	u32 buffer_tail_bits;
 	u32 datum_count;
 	u32 field_datum_count;
+	u32 access_bit_width;
 	u32 i;
 
 	ACPI_FUNCTION_TRACE(ex_extract_from_field);
@@ -694,16 +694,36 @@
 
 		return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
 	}
+
 	ACPI_MEMSET(buffer, 0, buffer_length);
+	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
+	/* Handle the simple case here */
+
+	if ((obj_desc->common_field.start_field_bit_offset == 0) &&
+	    (obj_desc->common_field.bit_length == access_bit_width)) {
+		status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ);
+		return_ACPI_STATUS(status);
+	}
+
+/* TBD: Move to common setup code */
+
+	/* Field algorithm is limited to sizeof(u64), truncate if needed */
+
+	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+		obj_desc->common_field.access_byte_width = sizeof(u64);
+		access_bit_width = sizeof(u64) * 8;
+	}
 
 	/* Compute the number of datums (access width data items) */
 
-	datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
-				       obj_desc->common_field.access_bit_width);
+	datum_count =
+	    ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
+			     access_bit_width);
+
 	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
 					     obj_desc->common_field.
 					     start_field_bit_offset,
-					     obj_desc->common_field.
 					     access_bit_width);
 
 	/* Priming read from the field */
@@ -738,12 +758,11 @@
 		 * This avoids the differences in behavior between different compilers
 		 * concerning shift values larger than the target data width.
 		 */
-		if ((obj_desc->common_field.access_bit_width -
-		     obj_desc->common_field.start_field_bit_offset) <
+		if (access_bit_width -
+		    obj_desc->common_field.start_field_bit_offset <
 		    ACPI_INTEGER_BIT_SIZE) {
 			merged_datum |=
-			    raw_datum << (obj_desc->common_field.
-					  access_bit_width -
+			    raw_datum << (access_bit_width -
 					  obj_desc->common_field.
 					  start_field_bit_offset);
 		}
@@ -765,8 +784,7 @@
 
 	/* Mask off any extra bits in the last datum */
 
-	buffer_tail_bits = obj_desc->common_field.bit_length %
-	    obj_desc->common_field.access_bit_width;
+	buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
 	if (buffer_tail_bits) {
 		merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
 	}
@@ -798,6 +816,7 @@
 acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
 			  void *buffer, u32 buffer_length)
 {
+	void *new_buffer;
 	acpi_status status;
 	u64 mask;
 	u64 width_mask;
@@ -808,9 +827,9 @@
 	u32 buffer_tail_bits;
 	u32 datum_count;
 	u32 field_datum_count;
-	u32 i;
+	u32 access_bit_width;
 	u32 required_length;
-	void *new_buffer;
+	u32 i;
 
 	ACPI_FUNCTION_TRACE(ex_insert_into_field);
 
@@ -844,17 +863,24 @@
 		buffer_length = required_length;
 	}
 
+/* TBD: Move to common setup code */
+
+	/* Algo is limited to sizeof(u64), so cut the access_byte_width */
+	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
+		obj_desc->common_field.access_byte_width = sizeof(u64);
+	}
+
+	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);
+
 	/*
 	 * Create the bitmasks used for bit insertion.
 	 * Note: This if/else is used to bypass compiler differences with the
 	 * shift operator
 	 */
-	if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
+	if (access_bit_width == ACPI_INTEGER_BIT_SIZE) {
 		width_mask = ACPI_UINT64_MAX;
 	} else {
-		width_mask =
-		    ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
-					 access_bit_width);
+		width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width);
 	}
 
 	mask = width_mask &
@@ -863,12 +889,11 @@
 	/* Compute the number of datums (access width data items) */
 
 	datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
-				       obj_desc->common_field.access_bit_width);
+				       access_bit_width);
 
 	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
 					     obj_desc->common_field.
 					     start_field_bit_offset,
-					     obj_desc->common_field.
 					     access_bit_width);
 
 	/* Get initial Datum from the input buffer */
@@ -905,12 +930,11 @@
 		 * This avoids the differences in behavior between different compilers
 		 * concerning shift values larger than the target data width.
 		 */
-		if ((obj_desc->common_field.access_bit_width -
+		if ((access_bit_width -
 		     obj_desc->common_field.start_field_bit_offset) <
 		    ACPI_INTEGER_BIT_SIZE) {
 			merged_datum =
-			    raw_datum >> (obj_desc->common_field.
-					  access_bit_width -
+			    raw_datum >> (access_bit_width -
 					  obj_desc->common_field.
 					  start_field_bit_offset);
 		} else {
@@ -929,6 +953,7 @@
 		ACPI_MEMCPY(&raw_datum, ((char *)buffer) + buffer_offset,
 			    ACPI_MIN(obj_desc->common_field.access_byte_width,
 				     buffer_length - buffer_offset));
+
 		merged_datum |=
 		    raw_datum << obj_desc->common_field.start_field_bit_offset;
 	}
@@ -937,7 +962,7 @@
 
 	buffer_tail_bits = (obj_desc->common_field.bit_length +
 			    obj_desc->common_field.start_field_bit_offset) %
-	    obj_desc->common_field.access_bit_width;
+	    access_bit_width;
 	if (buffer_tail_bits) {
 		mask &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/exmutex.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/exmutex.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/exmutex.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/exmutex.c	2011-01-04 19:50:19.000000000 -0500
@@ -336,7 +336,7 @@
 
 	/* Clear mutex info */
 
-	obj_desc->mutex.thread_id = NULL;
+	obj_desc->mutex.thread_id = 0;
 	return_ACPI_STATUS(status);
 }
 
@@ -393,10 +393,10 @@
 	if ((owner_thread->thread_id != walk_state->thread->thread_id) &&
 	    (obj_desc != acpi_gbl_global_lock_mutex)) {
 		ACPI_ERROR((AE_INFO,
-			    "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
-			    ACPI_CAST_PTR(void, walk_state->thread->thread_id),
+			    "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
+			    (u32)walk_state->thread->thread_id,
 			    acpi_ut_get_node_name(obj_desc->mutex.node),
-			    ACPI_CAST_PTR(void, owner_thread->thread_id)));
+			    (u32)owner_thread->thread_id));
 		return_ACPI_STATUS(AE_AML_NOT_OWNER);
 	}
 
@@ -488,7 +488,7 @@
 		/* Mark mutex unowned */
 
 		obj_desc->mutex.owner_thread = NULL;
-		obj_desc->mutex.thread_id = NULL;
+		obj_desc->mutex.thread_id = 0;
 
 		/* Update Thread sync_level (Last mutex is the important one) */
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/exprep.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/exprep.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/exprep.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/exprep.c	2011-01-04 19:50:19.000000000 -0500
@@ -355,12 +355,10 @@
 		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
 	}
 
-	/* Setup width (access granularity) fields */
+	/* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
 
 	obj_desc->common_field.access_byte_width = (u8)
-	    ACPI_DIV_8(access_bit_width);	/* 1,  2,  4,  8 */
-
-	obj_desc->common_field.access_bit_width = (u8) access_bit_width;
+	    ACPI_DIV_8(access_bit_width);
 
 	/*
 	 * base_byte_offset is the address of the start of the field within the
@@ -405,8 +403,9 @@
 {
 	union acpi_operand_object *obj_desc;
 	union acpi_operand_object *second_desc = NULL;
-	u32 type;
 	acpi_status status;
+	u32 access_byte_width;
+	u32 type;
 
 	ACPI_FUNCTION_TRACE(ex_prep_field_value);
 
@@ -421,8 +420,8 @@
 		type = acpi_ns_get_type(info->region_node);
 		if (type != ACPI_TYPE_REGION) {
 			ACPI_ERROR((AE_INFO,
-				    "Needed Region, found type 0x%X (%s)",
-				    type, acpi_ut_get_type_name(type)));
+				    "Needed Region, found type 0x%X (%s)", type,
+				    acpi_ut_get_type_name(type)));
 
 			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 		}
@@ -438,7 +437,8 @@
 	/* Initialize areas of the object that are common to all fields */
 
 	obj_desc->common_field.node = info->field_node;
-	status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags,
+	status = acpi_ex_prep_common_field_object(obj_desc,
+						  info->field_flags,
 						  info->attribute,
 						  info->field_bit_position,
 						  info->field_bit_length);
@@ -455,26 +455,25 @@
 		obj_desc->field.region_obj =
 		    acpi_ns_get_attached_object(info->region_node);
 
-		/* An additional reference for the container */
+		/* Allow full data read from EC address space */
 
-		acpi_ut_add_reference(obj_desc->field.region_obj);
+		if ((obj_desc->field.region_obj->region.space_id ==
+		     ACPI_ADR_SPACE_EC)
+		    && (obj_desc->common_field.bit_length > 8)) {
+			access_byte_width =
+			    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
+							bit_length);
 
-		/* allow full data read from EC address space */
-		if (obj_desc->field.region_obj->region.space_id ==
-			ACPI_ADR_SPACE_EC) {
-			if (obj_desc->common_field.bit_length > 8) {
-				unsigned width =
-					ACPI_ROUND_BITS_UP_TO_BYTES(
-					obj_desc->common_field.bit_length);
-				// access_bit_width is u8, don't overflow it
-				if (width > 8)
-					width = 8;
+			/* Maximum byte width supported is 255 */
+
+			if (access_byte_width < 256) {
 				obj_desc->common_field.access_byte_width =
-							width;
-				obj_desc->common_field.access_bit_width =
-							8 * width;
+				    (u8)access_byte_width;
 			}
 		}
+		/* An additional reference for the container */
+
+		acpi_ut_add_reference(obj_desc->field.region_obj);
 
 		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
 				  "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/exregion.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/exregion.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/exregion.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/exregion.c	2011-01-04 19:50:19.000000000 -0500
@@ -353,7 +353,6 @@
 	acpi_status status = AE_OK;
 	struct acpi_pci_id *pci_id;
 	u16 pci_register;
-	u32 value32;
 
 	ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
 
@@ -381,8 +380,7 @@
 	case ACPI_READ:
 
 		status = acpi_os_read_pci_configuration(pci_id, pci_register,
-							&value32, bit_width);
-		*value = value32;
+							value, bit_width);
 		break;
 
 	case ACPI_WRITE:
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/hwpci.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/hwpci.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/hwpci.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/hwpci.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,412 @@
+/*******************************************************************************
+ *
+ * Module Name: hwpci - Obtain PCI bus, device, and function numbers
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_NAMESPACE
+ACPI_MODULE_NAME("hwpci")
+
+/* PCI configuration space values */
+#define PCI_CFG_HEADER_TYPE_REG             0x0E
+#define PCI_CFG_PRIMARY_BUS_NUMBER_REG      0x18
+#define PCI_CFG_SECONDARY_BUS_NUMBER_REG    0x19
+/* PCI header values */
+#define PCI_HEADER_TYPE_MASK                0x7F
+#define PCI_TYPE_BRIDGE                     0x01
+#define PCI_TYPE_CARDBUS_BRIDGE             0x02
+typedef struct acpi_pci_device {
+	acpi_handle device;
+	struct acpi_pci_device *next;
+
+} acpi_pci_device;
+
+/* Local prototypes */
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+		       acpi_handle pci_region,
+		       struct acpi_pci_device **return_list_head);
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+			 struct acpi_pci_device *list_head);
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head);
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+			    acpi_handle pci_device,
+			    u16 *bus_number, u8 *is_bridge);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_derive_pci_id
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              root_pci_device     - A handle to a PCI device object. This
+ *                                    object must be a PCI Root Bridge having a
+ *                                    _HID value of either PNP0A03 or PNP0A08
+ *              pci_region          - A handle to a PCI configuration space
+ *                                    Operation Region being initialized
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: This function derives a full PCI ID for a PCI device,
+ *              consisting of a Segment number, Bus number, Device number,
+ *              and function code.
+ *
+ *              The PCI hardware dynamically configures PCI bus numbers
+ *              depending on the bus topology discovered during system
+ *              initialization. This function is invoked during configuration
+ *              of a PCI_Config Operation Region in order to (possibly) update
+ *              the Bus/Device/Function numbers in the pci_id with the actual
+ *              values as determined by the hardware and operating system
+ *              configuration.
+ *
+ *              The pci_id parameter is initially populated during the Operation
+ *              Region initialization. This function is then called, and is
+ *              will make any necessary modifications to the Bus, Device, or
+ *              Function number PCI ID subfields as appropriate for the
+ *              current hardware and OS configuration.
+ *
+ * NOTE:        Created 08/2010. Replaces the previous OSL acpi_os_derive_pci_id
+ *              interface since this feature is OS-independent. This module
+ *              specifically avoids any use of recursion by building a local
+ *              temporary device list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
+		      acpi_handle root_pci_device, acpi_handle pci_region)
+{
+	acpi_status status;
+	struct acpi_pci_device *list_head = NULL;
+
+	ACPI_FUNCTION_TRACE(hw_derive_pci_id);
+
+	if (!pci_id) {
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
+	}
+
+	/* Build a list of PCI devices, from pci_region up to root_pci_device */
+
+	status =
+	    acpi_hw_build_pci_list(root_pci_device, pci_region, &list_head);
+	if (ACPI_SUCCESS(status)) {
+
+		/* Walk the list, updating the PCI device/function/bus numbers */
+
+		status = acpi_hw_process_pci_list(pci_id, list_head);
+	}
+
+	/* Always delete the list */
+
+	acpi_hw_delete_pci_list(list_head);
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_build_pci_list
+ *
+ * PARAMETERS:  root_pci_device     - A handle to a PCI device object. This
+ *                                    object is guaranteed to be a PCI Root
+ *                                    Bridge having a _HID value of either
+ *                                    PNP0A03 or PNP0A08
+ *              pci_region          - A handle to the PCI configuration space
+ *                                    Operation Region
+ *              return_list_head    - Where the PCI device list is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Builds a list of devices from the input PCI region up to the
+ *              Root PCI device for this namespace subtree.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_build_pci_list(acpi_handle root_pci_device,
+		       acpi_handle pci_region,
+		       struct acpi_pci_device **return_list_head)
+{
+	acpi_handle current_device;
+	acpi_handle parent_device;
+	acpi_status status;
+	struct acpi_pci_device *list_element;
+	struct acpi_pci_device *list_head = NULL;
+
+	/*
+	 * Ascend namespace branch until the root_pci_device is reached, building
+	 * a list of device nodes. Loop will exit when either the PCI device is
+	 * found, or the root of the namespace is reached.
+	 */
+	current_device = pci_region;
+	while (1) {
+		status = acpi_get_parent(current_device, &parent_device);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+
+		/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
+
+		if (parent_device == root_pci_device) {
+			*return_list_head = list_head;
+			return (AE_OK);
+		}
+
+		list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
+		if (!list_element) {
+			return (AE_NO_MEMORY);
+		}
+
+		/* Put new element at the head of the list */
+
+		list_element->next = list_head;
+		list_element->device = parent_device;
+		list_head = list_element;
+
+		current_device = parent_device;
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_process_pci_list
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              list_head           - Device list created by
+ *                                    acpi_hw_build_pci_list
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Walk downward through the PCI device list, getting the device
+ *              info for each, via the PCI configuration space and updating
+ *              the PCI ID as necessary. Deletes the list during traversal.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_process_pci_list(struct acpi_pci_id *pci_id,
+			 struct acpi_pci_device *list_head)
+{
+	acpi_status status = AE_OK;
+	struct acpi_pci_device *info;
+	u16 bus_number;
+	u8 is_bridge = TRUE;
+
+	ACPI_FUNCTION_NAME(hw_process_pci_list);
+
+	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+			  "Input PciId:  Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",
+			  pci_id->segment, pci_id->bus, pci_id->device,
+			  pci_id->function));
+
+	bus_number = pci_id->bus;
+
+	/*
+	 * Descend down the namespace tree, collecting PCI device, function,
+	 * and bus numbers. bus_number is only important for PCI bridges.
+	 * Algorithm: As we descend the tree, use the last valid PCI device,
+	 * function, and bus numbers that are discovered, and assign them
+	 * to the PCI ID for the target device.
+	 */
+	info = list_head;
+	while (info) {
+		status = acpi_hw_get_pci_device_info(pci_id, info->device,
+						     &bus_number, &is_bridge);
+		if (ACPI_FAILURE(status)) {
+			return_ACPI_STATUS(status);
+		}
+
+		info = info->next;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
+			  "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "
+			  "Status %X BusNumber %X IsBridge %X\n",
+			  pci_id->segment, pci_id->bus, pci_id->device,
+			  pci_id->function, status, bus_number, is_bridge));
+
+	return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_delete_pci_list
+ *
+ * PARAMETERS:  list_head           - Device list created by
+ *                                    acpi_hw_build_pci_list
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Free the entire PCI list.
+ *
+ ******************************************************************************/
+
+static void acpi_hw_delete_pci_list(struct acpi_pci_device *list_head)
+{
+	struct acpi_pci_device *next;
+	struct acpi_pci_device *previous;
+
+	next = list_head;
+	while (next) {
+		previous = next;
+		next = previous->next;
+		ACPI_FREE(previous);
+	}
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_hw_get_pci_device_info
+ *
+ * PARAMETERS:  pci_id              - Initial values for the PCI ID. May be
+ *                                    modified by this function.
+ *              pci_device          - Handle for the PCI device object
+ *              bus_number          - Where a PCI bridge bus number is returned
+ *              is_bridge           - Return value, indicates if this PCI
+ *                                    device is a PCI bridge
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get the device info for a single PCI device object. Get the
+ *              _ADR (contains PCI device and function numbers), and for PCI
+ *              bridge devices, get the bus number from PCI configuration
+ *              space.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_get_pci_device_info(struct acpi_pci_id *pci_id,
+			    acpi_handle pci_device,
+			    u16 *bus_number, u8 *is_bridge)
+{
+	acpi_status status;
+	acpi_object_type object_type;
+	u64 return_value;
+	u64 pci_value;
+
+	/* We only care about objects of type Device */
+
+	status = acpi_get_type(pci_device, &object_type);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	if (object_type != ACPI_TYPE_DEVICE) {
+		return (AE_OK);
+	}
+
+	/* We need an _ADR. Ignore device if not present */
+
+	status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR,
+						 pci_device, &return_value);
+	if (ACPI_FAILURE(status)) {
+		return (AE_OK);
+	}
+
+	/*
+	 * From _ADR, get the PCI Device and Function and
+	 * update the PCI ID.
+	 */
+	pci_id->device = ACPI_HIWORD(ACPI_LODWORD(return_value));
+	pci_id->function = ACPI_LOWORD(ACPI_LODWORD(return_value));
+
+	/*
+	 * If the previous device was a bridge, use the previous
+	 * device bus number
+	 */
+	if (*is_bridge) {
+		pci_id->bus = *bus_number;
+	}
+
+	/*
+	 * Get the bus numbers from PCI Config space:
+	 *
+	 * First, get the PCI header_type
+	 */
+	*is_bridge = FALSE;
+	status = acpi_os_read_pci_configuration(pci_id,
+						PCI_CFG_HEADER_TYPE_REG,
+						&pci_value, 8);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	/* We only care about bridges (1=pci_bridge, 2=card_bus_bridge) */
+
+	pci_value &= PCI_HEADER_TYPE_MASK;
+
+	if ((pci_value != PCI_TYPE_BRIDGE) &&
+	    (pci_value != PCI_TYPE_CARDBUS_BRIDGE)) {
+		return (AE_OK);
+	}
+
+	/* Bridge: Get the Primary bus_number */
+
+	status = acpi_os_read_pci_configuration(pci_id,
+						PCI_CFG_PRIMARY_BUS_NUMBER_REG,
+						&pci_value, 8);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	*is_bridge = TRUE;
+	pci_id->bus = (u16)pci_value;
+
+	/* Bridge: Get the Secondary bus_number */
+
+	status = acpi_os_read_pci_configuration(pci_id,
+						PCI_CFG_SECONDARY_BUS_NUMBER_REG,
+						&pci_value, 8);
+	if (ACPI_FAILURE(status)) {
+		return (status);
+	}
+
+	*bus_number = (u16)pci_value;
+	return (AE_OK);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/Makefile linux-libre-2.6.37-gnu/drivers/acpi/acpica/Makefile
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,7 @@
 	 excreate.o  exmisc.o   exoparg2.o  exregion.o  exstore.o   exutils.o \
 	 exdump.o    exmutex.o  exoparg3.o  exresnte.o  exstoren.o  exdebug.o
 
-acpi-y += hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o hwxface.o hwvalid.o
+acpi-y += hwacpi.o  hwgpe.o  hwregs.o  hwsleep.o hwxface.o hwvalid.o hwpci.o
 
 acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
 
@@ -44,4 +44,5 @@
 
 acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
 		utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
-		utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o
+		utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \
+		utosi.o utxferror.o
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/nsrepair2.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/nsrepair2.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/nsrepair2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/nsrepair2.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,10 +74,18 @@
 		   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+		   union acpi_operand_object **return_object_ptr);
+
+static acpi_status
 acpi_ns_repair_FDE(struct acpi_predefined_data *data,
 		   union acpi_operand_object **return_object_ptr);
 
 static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+		   union acpi_operand_object **return_object_ptr);
+
+static acpi_status
 acpi_ns_repair_PSS(struct acpi_predefined_data *data,
 		   union acpi_operand_object **return_object_ptr);
 
@@ -108,8 +116,10 @@
  * As necessary:
  *
  * _ALR: Sort the list ascending by ambient_illuminance
+ * _CID: Strings: uppercase all, remove any leading asterisk
  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
+ * _HID: Strings: uppercase all, remove any leading asterisk
  * _PSS: Sort the list descending by Power
  * _TSS: Sort the list descending by Power
  *
@@ -122,8 +132,10 @@
  */
 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
 	{"_ALR", acpi_ns_repair_ALR},
+	{"_CID", acpi_ns_repair_CID},
 	{"_FDE", acpi_ns_repair_FDE},
 	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
+	{"_HID", acpi_ns_repair_HID},
 	{"_PSS", acpi_ns_repair_PSS},
 	{"_TSS", acpi_ns_repair_TSS},
 	{{0, 0, 0, 0}, NULL}	/* Table terminator */
@@ -319,6 +331,157 @@
 	return (AE_OK);
 }
 
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_CID
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
+ *              letters are uppercase and that there is no leading asterisk.
+ *              If a Package, ensure same for all string elements.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_CID(struct acpi_predefined_data *data,
+		   union acpi_operand_object **return_object_ptr)
+{
+	acpi_status status;
+	union acpi_operand_object *return_object = *return_object_ptr;
+	union acpi_operand_object **element_ptr;
+	union acpi_operand_object *original_element;
+	u16 original_ref_count;
+	u32 i;
+
+	/* Check for _CID as a simple string */
+
+	if (return_object->common.type == ACPI_TYPE_STRING) {
+		status = acpi_ns_repair_HID(data, return_object_ptr);
+		return (status);
+	}
+
+	/* Exit if not a Package */
+
+	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
+		return (AE_OK);
+	}
+
+	/* Examine each element of the _CID package */
+
+	element_ptr = return_object->package.elements;
+	for (i = 0; i < return_object->package.count; i++) {
+		original_element = *element_ptr;
+		original_ref_count = original_element->common.reference_count;
+
+		status = acpi_ns_repair_HID(data, element_ptr);
+		if (ACPI_FAILURE(status)) {
+			return (status);
+		}
+
+		/* Take care with reference counts */
+
+		if (original_element != *element_ptr) {
+
+			/* Element was replaced */
+
+			(*element_ptr)->common.reference_count =
+			    original_ref_count;
+
+			acpi_ut_remove_reference(original_element);
+		}
+
+		element_ptr++;
+	}
+
+	return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_repair_HID
+ *
+ * PARAMETERS:  Data                - Pointer to validation data structure
+ *              return_object_ptr   - Pointer to the object returned from the
+ *                                    evaluation of a method or object
+ *
+ * RETURN:      Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
+ *              letters are uppercase and that there is no leading asterisk.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_HID(struct acpi_predefined_data *data,
+		   union acpi_operand_object **return_object_ptr)
+{
+	union acpi_operand_object *return_object = *return_object_ptr;
+	union acpi_operand_object *new_string;
+	char *source;
+	char *dest;
+
+	ACPI_FUNCTION_NAME(ns_repair_HID);
+
+	/* We only care about string _HID objects (not integers) */
+
+	if (return_object->common.type != ACPI_TYPE_STRING) {
+		return (AE_OK);
+	}
+
+	if (return_object->string.length == 0) {
+		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+				      "Invalid zero-length _HID or _CID string"));
+
+		/* Return AE_OK anyway, let driver handle it */
+
+		data->flags |= ACPI_OBJECT_REPAIRED;
+		return (AE_OK);
+	}
+
+	/* It is simplest to always create a new string object */
+
+	new_string = acpi_ut_create_string_object(return_object->string.length);
+	if (!new_string) {
+		return (AE_NO_MEMORY);
+	}
+
+	/*
+	 * Remove a leading asterisk if present. For some unknown reason, there
+	 * are many machines in the field that contains IDs like this.
+	 *
+	 * Examples: "*PNP0C03", "*ACPI0003"
+	 */
+	source = return_object->string.pointer;
+	if (*source == '*') {
+		source++;
+		new_string->string.length--;
+
+		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
+				  "%s: Removed invalid leading asterisk\n",
+				  data->pathname));
+	}
+
+	/*
+	 * Copy and uppercase the string. From the ACPI specification:
+	 *
+	 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
+	 * letter and # is a hex digit. A valid ACPI ID must be of the form
+	 * "ACPI####" where # is a hex digit.
+	 */
+	for (dest = new_string->string.pointer; *source; dest++, source++) {
+		*dest = (char)ACPI_TOUPPER(*source);
+	}
+
+	acpi_ut_remove_reference(return_object);
+	*return_object_ptr = new_string;
+	return (AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ns_repair_TSS
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/nsutils.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/nsutils.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/nsutils.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/nsutils.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,104 +60,6 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ns_report_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              internal_name       - Name or path of the namespace node
- *              lookup_status       - Exception code from NS lookup
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_error(const char *module_name,
-		     u32 line_number,
-		     const char *internal_name, acpi_status lookup_status)
-{
-	acpi_status status;
-	u32 bad_name;
-	char *name = NULL;
-
-	acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
-	if (lookup_status == AE_BAD_CHARACTER) {
-
-		/* There is a non-ascii character in the name */
-
-		ACPI_MOVE_32_TO_32(&bad_name,
-				   ACPI_CAST_PTR(u32, internal_name));
-		acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
-	} else {
-		/* Convert path to external format */
-
-		status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
-						  internal_name, NULL, &name);
-
-		/* Print target name */
-
-		if (ACPI_SUCCESS(status)) {
-			acpi_os_printf("[%s]", name);
-		} else {
-			acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
-		}
-
-		if (name) {
-			ACPI_FREE(name);
-		}
-	}
-
-	acpi_os_printf(" Namespace lookup failure, %s\n",
-		       acpi_format_exception(lookup_status));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_report_method_error
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              Message             - Error message to use on failure
- *              prefix_node         - Prefix relative to the path
- *              Path                - Path to the node (optional)
- *              method_status       - Execution status
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print warning message with full pathname
- *
- ******************************************************************************/
-
-void
-acpi_ns_report_method_error(const char *module_name,
-			    u32 line_number,
-			    const char *message,
-			    struct acpi_namespace_node *prefix_node,
-			    const char *path, acpi_status method_status)
-{
-	acpi_status status;
-	struct acpi_namespace_node *node = prefix_node;
-
-	acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
-
-	if (path) {
-		status =
-		    acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
-				     &node);
-		if (ACPI_FAILURE(status)) {
-			acpi_os_printf("[Could not get node by pathname]");
-		}
-	}
-
-	acpi_ns_print_node_pathname(node, message);
-	acpi_os_printf(", %s\n", acpi_format_exception(method_status));
-}
-
-/*******************************************************************************
- *
  * FUNCTION:    acpi_ns_print_node_pathname
  *
  * PARAMETERS:  Node            - Object
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/tbfadt.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/tbfadt.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/tbfadt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/tbfadt.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,7 +49,7 @@
 ACPI_MODULE_NAME("tbfadt")
 
 /* Local prototypes */
-static inline void
+static ACPI_INLINE void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
 			     u8 space_id, u8 byte_width, u64 address);
 
@@ -181,7 +181,7 @@
  *
  ******************************************************************************/
 
-static inline void
+static ACPI_INLINE void
 acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
 			     u8 space_id, u8 byte_width, u64 address)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utdebug.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utdebug.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utdebug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utdebug.c	2011-01-04 19:50:19.000000000 -0500
@@ -179,9 +179,8 @@
 	if (thread_id != acpi_gbl_prev_thread_id) {
 		if (ACPI_LV_THREADS & acpi_dbg_level) {
 			acpi_os_printf
-			    ("\n**** Context Switch from TID %p to TID %p ****\n\n",
-			     ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id),
-			     ACPI_CAST_PTR(void, thread_id));
+			    ("\n**** Context Switch from TID %u to TID %u ****\n\n",
+			     (u32)acpi_gbl_prev_thread_id, (u32)thread_id);
 		}
 
 		acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +193,7 @@
 	acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
 	if (ACPI_LV_THREADS & acpi_dbg_level) {
-		acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id));
+		acpi_os_printf("[%u] ", (u32)thread_id);
 	}
 
 	acpi_os_printf("[%02ld] %-22.22s: ",
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/uteval.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/uteval.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/uteval.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/uteval.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,153 +48,6 @@
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("uteval")
 
-/*
- * Strings supported by the _OSI predefined (internal) method.
- *
- * March 2009: Removed "Linux" as this host no longer wants to respond true
- * for this string. Basically, the only safe OS strings are windows-related
- * and in many or most cases represent the only test path within the
- * BIOS-provided ASL code.
- *
- * The second element of each entry is used to track the newest version of
- * Windows that the BIOS has requested.
- */
-static struct acpi_interface_info acpi_interfaces_supported[] = {
-	/* Operating System Vendor Strings */
-
-	{"Windows 2000", ACPI_OSI_WIN_2000},	/* Windows 2000 */
-	{"Windows 2001", ACPI_OSI_WIN_XP},	/* Windows XP */
-	{"Windows 2001 SP1", ACPI_OSI_WIN_XP_SP1},	/* Windows XP SP1 */
-	{"Windows 2001.1", ACPI_OSI_WINSRV_2003},	/* Windows Server 2003 */
-	{"Windows 2001 SP2", ACPI_OSI_WIN_XP_SP2},	/* Windows XP SP2 */
-	{"Windows 2001.1 SP1", ACPI_OSI_WINSRV_2003_SP1},	/* Windows Server 2003 SP1 - Added 03/2006 */
-	{"Windows 2006", ACPI_OSI_WIN_VISTA},	/* Windows Vista - Added 03/2006 */
-	{"Windows 2006.1", ACPI_OSI_WINSRV_2008},	/* Windows Server 2008 - Added 09/2009 */
-	{"Windows 2006 SP1", ACPI_OSI_WIN_VISTA_SP1},	/* Windows Vista SP1 - Added 09/2009 */
-	{"Windows 2009", ACPI_OSI_WIN_7},	/* Windows 7 and Server 2008 R2 - Added 09/2009 */
-
-	/* Feature Group Strings */
-
-	{"Extended Address Space Descriptor", 0}
-
-	/*
-	 * All "optional" feature group strings (features that are implemented
-	 * by the host) should be implemented in the host version of
-	 * acpi_os_validate_interface and should not be added here.
-	 */
-};
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_osi_implementation
- *
- * PARAMETERS:  walk_state          - Current walk state
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Implementation of the _OSI predefined control method
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
-{
-	acpi_status status;
-	union acpi_operand_object *string_desc;
-	union acpi_operand_object *return_desc;
-	u32 return_value;
-	u32 i;
-
-	ACPI_FUNCTION_TRACE(ut_osi_implementation);
-
-	/* Validate the string input argument */
-
-	string_desc = walk_state->arguments[0].object;
-	if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
-		return_ACPI_STATUS(AE_TYPE);
-	}
-
-	/* Create a return object */
-
-	return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
-	if (!return_desc) {
-		return_ACPI_STATUS(AE_NO_MEMORY);
-	}
-
-	/* Default return value is 0, NOT SUPPORTED */
-
-	return_value = 0;
-
-	/* Compare input string to static table of supported interfaces */
-
-	for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
-		if (!ACPI_STRCMP(string_desc->string.pointer,
-				 acpi_interfaces_supported[i].name)) {
-			/*
-			 * The interface is supported.
-			 * Update the osi_data if necessary. We keep track of the latest
-			 * version of Windows that has been requested by the BIOS.
-			 */
-			if (acpi_interfaces_supported[i].value >
-			    acpi_gbl_osi_data) {
-				acpi_gbl_osi_data =
-				    acpi_interfaces_supported[i].value;
-			}
-
-			return_value = ACPI_UINT32_MAX;
-			goto exit;
-		}
-	}
-
-	/*
-	 * Did not match the string in the static table, call the host OSL to
-	 * check for a match with one of the optional strings (such as
-	 * "Module Device", "3.0 Thermal Model", etc.)
-	 */
-	status = acpi_os_validate_interface(string_desc->string.pointer);
-	if (ACPI_SUCCESS(status)) {
-
-		/* The interface is supported */
-
-		return_value = ACPI_UINT32_MAX;
-	}
-
-exit:
-	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO,
-		"ACPI: BIOS _OSI(%s) is %ssupported\n",
-		string_desc->string.pointer, return_value == 0 ? "not " : ""));
-
-	/* Complete the return value */
-
-	return_desc->integer.value = return_value;
-	walk_state->return_desc = return_desc;
-	return_ACPI_STATUS (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_osi_invalidate
- *
- * PARAMETERS:  interface_string
- *
- * RETURN:      Status
- *
- * DESCRIPTION: invalidate string in pre-defiend _OSI string list
- *
- ******************************************************************************/
-
-acpi_status acpi_osi_invalidate(char *interface)
-{
-	int i;
-
-	for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) {
-		if (!ACPI_STRCMP(interface, acpi_interfaces_supported[i].name)) {
-			*acpi_interfaces_supported[i].name = '\0';
-			return AE_OK;
-		}
-	}
-	return AE_NOT_FOUND;
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_evaluate_object
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utglobal.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utglobal.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utglobal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utglobal.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,14 +154,16 @@
  * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run
  *    during the initialization sequence.
  * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to
- *    perform a Notify() operation on it.
+ *    perform a Notify() operation on it. 09/2010: Changed to type Device.
+ *    This still allows notifies, but does not confuse host code that
+ *    searches for valid thermal_zone objects.
  */
 const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = {
 	{"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL},
 	{"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL},
 	{"_SB_", ACPI_TYPE_DEVICE, NULL},
 	{"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
-	{"_TZ_", ACPI_TYPE_THERMAL, NULL},
+	{"_TZ_", ACPI_TYPE_DEVICE, NULL},
 	{"_REV", ACPI_TYPE_INTEGER, (char *)ACPI_CA_SUPPORT_LEVEL},
 	{"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
 	{"_GL_", ACPI_TYPE_MUTEX, (char *)1},
@@ -766,6 +768,7 @@
 	acpi_gbl_gpe_fadt_blocks[0] = NULL;
 	acpi_gbl_gpe_fadt_blocks[1] = NULL;
 	acpi_current_gpe_count = 0;
+	acpi_all_gpes_initialized = FALSE;
 
 	/* Global handlers */
 
@@ -774,6 +777,7 @@
 	acpi_gbl_exception_handler = NULL;
 	acpi_gbl_init_handler = NULL;
 	acpi_gbl_table_handler = NULL;
+	acpi_gbl_interface_handler = NULL;
 
 	/* Global Lock support */
 
@@ -800,6 +804,7 @@
 	acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
 	acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
 	acpi_gbl_osi_data = 0;
+	acpi_gbl_osi_mutex = NULL;
 
 	/* Hardware oriented */
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utids.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utids.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utids.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utids.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,42 +48,6 @@
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utids")
 
-/* Local prototypes */
-static void acpi_ut_copy_id_string(char *destination, char *source);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_copy_id_string
- *
- * PARAMETERS:  Destination         - Where to copy the string
- *              Source              - Source string
- *
- * RETURN:      None
- *
- * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
- *              Performs removal of a leading asterisk if present -- workaround
- *              for a known issue on a bunch of machines.
- *
- ******************************************************************************/
-
-static void acpi_ut_copy_id_string(char *destination, char *source)
-{
-
-	/*
-	 * Workaround for ID strings that have a leading asterisk. This construct
-	 * is not allowed by the ACPI specification  (ID strings must be
-	 * alphanumeric), but enough existing machines have this embedded in their
-	 * ID strings that the following code is useful.
-	 */
-	if (*source == '*') {
-		source++;
-	}
-
-	/* Do the actual copy */
-
-	ACPI_STRCPY(destination, source);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_execute_HID
@@ -101,7 +65,6 @@
  *              NOTE: Internal function, no parameter validation
  *
  ******************************************************************************/
-
 acpi_status
 acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
 		    struct acpica_device_id **return_id)
@@ -147,7 +110,7 @@
 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 		acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
 	} else {
-		acpi_ut_copy_id_string(hid->string, obj_desc->string.pointer);
+		ACPI_STRCPY(hid->string, obj_desc->string.pointer);
 	}
 
 	hid->length = length;
@@ -224,7 +187,7 @@
 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
 		acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
 	} else {
-		acpi_ut_copy_id_string(uid->string, obj_desc->string.pointer);
+		ACPI_STRCPY(uid->string, obj_desc->string.pointer);
 	}
 
 	uid->length = length;
@@ -357,8 +320,8 @@
 
 			/* Copy the String CID from the returned object */
 
-			acpi_ut_copy_id_string(next_id_string,
-					       cid_objects[i]->string.pointer);
+			ACPI_STRCPY(next_id_string,
+				    cid_objects[i]->string.pointer);
 			length = cid_objects[i]->string.length + 1;
 		}
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utinit.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utinit.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utinit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utinit.c	2011-01-04 19:50:19.000000000 -0500
@@ -117,6 +117,10 @@
 	/* Close the acpi_event Handling */
 
 	acpi_ev_terminate();
+
+	/* Delete any dynamic _OSI interfaces */
+
+	acpi_ut_interface_terminate();
 #endif
 
 	/* Close the Namespace */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmath.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmath.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmath.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmath.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,11 +48,27 @@
 ACPI_MODULE_NAME("utmath")
 
 /*
- * Support for double-precision integer divide.  This code is included here
- * in order to support kernel environments where the double-precision math
- * library is not available.
+ * Optional support for 64-bit double-precision integer divide. This code
+ * is configurable and is implemented in order to support 32-bit kernel
+ * environments where a 64-bit double-precision math library is not available.
+ *
+ * Support for a more normal 64-bit divide/modulo (with check for a divide-
+ * by-zero) appears after this optional section of code.
  */
 #ifndef ACPI_USE_NATIVE_DIVIDE
+/* Structures used only for 64-bit divide */
+typedef struct uint64_struct {
+	u32 lo;
+	u32 hi;
+
+} uint64_struct;
+
+typedef union uint64_overlay {
+	u64 full;
+	struct uint64_struct part;
+
+} uint64_overlay;
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_short_divide
@@ -69,6 +85,7 @@
  *              32-bit remainder.
  *
  ******************************************************************************/
+
 acpi_status
 acpi_ut_short_divide(u64 dividend,
 		     u32 divisor, u64 *out_quotient, u32 *out_remainder)
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmisc.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmisc.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmisc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmisc.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,11 +50,6 @@
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utmisc")
 
-/*
- * Common suffix for messages
- */
-#define ACPI_COMMON_MSG_SUFFIX \
-	acpi_os_printf(" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_validate_exception
@@ -1044,160 +1039,3 @@
 
 	return_ACPI_STATUS(AE_AML_INTERNAL);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_error, acpi_exception, acpi_warning, acpi_info
- *
- * PARAMETERS:  module_name         - Caller's module name (for error output)
- *              line_number         - Caller's line number (for error output)
- *              Format              - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Print message with module/line/version info
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_error(const char *module_name, u32 line_number, const char *format, ...)
-{
-	va_list args;
-
-	acpi_os_printf("ACPI Error: ");
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	ACPI_COMMON_MSG_SUFFIX;
-	va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_exception(const char *module_name,
-	       u32 line_number, acpi_status status, const char *format, ...)
-{
-	va_list args;
-
-	acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status));
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	ACPI_COMMON_MSG_SUFFIX;
-	va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
-{
-	va_list args;
-
-	acpi_os_printf("ACPI Warning: ");
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	ACPI_COMMON_MSG_SUFFIX;
-	va_end(args);
-}
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_info(const char *module_name, u32 line_number, const char *format, ...)
-{
-	va_list args;
-
-	acpi_os_printf("ACPI: ");
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	acpi_os_printf("\n");
-	va_end(args);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_error)
-ACPI_EXPORT_SYMBOL(acpi_exception)
-ACPI_EXPORT_SYMBOL(acpi_warning)
-ACPI_EXPORT_SYMBOL(acpi_info)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_warning
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              Pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              Format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Warnings for the predefined validation module. Messages are
- *              only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of error
- *              messages for methods that are repeatedly evaluated.
- *
-******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
-			   u32 line_number,
-			   char *pathname,
-			   u8 node_flags, const char *format, ...)
-{
-	va_list args;
-
-	/*
-	 * Warning messages for this method/object will be disabled after the
-	 * first time a validation fails or an object is successfully repaired.
-	 */
-	if (node_flags & ANOBJ_EVALUATED) {
-		return;
-	}
-
-	acpi_os_printf("ACPI Warning for %s: ", pathname);
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	ACPI_COMMON_MSG_SUFFIX;
-	va_end(args);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_predefined_info
- *
- * PARAMETERS:  module_name     - Caller's module name (for error output)
- *              line_number     - Caller's line number (for error output)
- *              Pathname        - Full pathname to the node
- *              node_flags      - From Namespace node for the method/object
- *              Format          - Printf format string + additional args
- *
- * RETURN:      None
- *
- * DESCRIPTION: Info messages for the predefined validation module. Messages
- *              are only emitted the first time a problem with a particular
- *              method/object is detected. This prevents a flood of
- *              messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
-			u32 line_number,
-			char *pathname, u8 node_flags, const char *format, ...)
-{
-	va_list args;
-
-	/*
-	 * Warning messages for this method/object will be disabled after the
-	 * first time a validation fails or an object is successfully repaired.
-	 */
-	if (node_flags & ANOBJ_EVALUATED) {
-		return;
-	}
-
-	acpi_os_printf("ACPI Info for %s: ", pathname);
-
-	va_start(args, format);
-	acpi_os_vprintf(format, args);
-	ACPI_COMMON_MSG_SUFFIX;
-	va_end(args);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmutex.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmutex.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utmutex.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utmutex.c	2011-01-04 19:50:19.000000000 -0500
@@ -86,6 +86,12 @@
 	spin_lock_init(acpi_gbl_gpe_lock);
 	spin_lock_init(acpi_gbl_hardware_lock);
 
+	/* Mutex for _OSI support */
+	status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
 	/* Create the reader/writer lock for namespace access */
 
 	status = acpi_ut_create_rw_lock(&acpi_gbl_namespace_rw_lock);
@@ -117,6 +123,8 @@
 		acpi_ut_delete_mutex(i);
 	}
 
+	acpi_os_delete_mutex(acpi_gbl_osi_mutex);
+
 	/* Delete the spinlocks */
 
 	acpi_os_delete_lock(acpi_gbl_gpe_lock);
@@ -220,18 +228,17 @@
 			if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
 				if (i == mutex_id) {
 					ACPI_ERROR((AE_INFO,
-						    "Mutex [%s] already acquired by this thread [%p]",
+						    "Mutex [%s] already acquired by this thread [%u]",
 						    acpi_ut_get_mutex_name
 						    (mutex_id),
-						    ACPI_CAST_PTR(void,
-								  this_thread_id)));
+						    (u32)this_thread_id));
 
 					return (AE_ALREADY_ACQUIRED);
 				}
 
 				ACPI_ERROR((AE_INFO,
-					    "Invalid acquire order: Thread %p owns [%s], wants [%s]",
-					    ACPI_CAST_PTR(void, this_thread_id),
+					    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
+					    (u32)this_thread_id,
 					    acpi_ut_get_mutex_name(i),
 					    acpi_ut_get_mutex_name(mutex_id)));
 
@@ -242,24 +249,24 @@
 #endif
 
 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-			  "Thread %p attempting to acquire Mutex [%s]\n",
-			  ACPI_CAST_PTR(void, this_thread_id),
+			  "Thread %u attempting to acquire Mutex [%s]\n",
+			  (u32)this_thread_id,
 			  acpi_ut_get_mutex_name(mutex_id)));
 
 	status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
 				       ACPI_WAIT_FOREVER);
 	if (ACPI_SUCCESS(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-				  "Thread %p acquired Mutex [%s]\n",
-				  ACPI_CAST_PTR(void, this_thread_id),
+				  "Thread %u acquired Mutex [%s]\n",
+				  (u32)this_thread_id,
 				  acpi_ut_get_mutex_name(mutex_id)));
 
 		acpi_gbl_mutex_info[mutex_id].use_count++;
 		acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
 	} else {
 		ACPI_EXCEPTION((AE_INFO, status,
-				"Thread %p could not acquire Mutex [0x%X]",
-				ACPI_CAST_PTR(void, this_thread_id), mutex_id));
+				"Thread %u could not acquire Mutex [0x%X]",
+				(u32)this_thread_id, mutex_id));
 	}
 
 	return (status);
@@ -279,10 +286,14 @@
 
 acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
 {
+	acpi_thread_id this_thread_id;
+
 	ACPI_FUNCTION_NAME(ut_release_mutex);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n",
-			  ACPI_CAST_PTR(void, acpi_os_get_thread_id()),
+	this_thread_id = acpi_os_get_thread_id();
+
+	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
+			  (u32)this_thread_id,
 			  acpi_ut_get_mutex_name(mutex_id)));
 
 	if (mutex_id > ACPI_MAX_MUTEX) {
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utosi.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utosi.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utosi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utosi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,380 @@
+/******************************************************************************
+ *
+ * Module Name: utosi - Support for the _OSI predefined control method
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utosi")
+
+/*
+ * Strings supported by the _OSI predefined control method (which is
+ * implemented internally within this module.)
+ *
+ * March 2009: Removed "Linux" as this host no longer wants to respond true
+ * for this string. Basically, the only safe OS strings are windows-related
+ * and in many or most cases represent the only test path within the
+ * BIOS-provided ASL code.
+ *
+ * The last element of each entry is used to track the newest version of
+ * Windows that the BIOS has requested.
+ */
+static struct acpi_interface_info acpi_default_supported_interfaces[] = {
+	/* Operating System Vendor Strings */
+
+	{"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000},	/* Windows 2000 */
+	{"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP},	/* Windows XP */
+	{"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1},	/* Windows XP SP1 */
+	{"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003},	/* Windows Server 2003 */
+	{"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2},	/* Windows XP SP2 */
+	{"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1},	/* Windows Server 2003 SP1 - Added 03/2006 */
+	{"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA},	/* Windows Vista - Added 03/2006 */
+	{"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008},	/* Windows Server 2008 - Added 09/2009 */
+	{"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1},	/* Windows Vista SP1 - Added 09/2009 */
+	{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},	/* Windows Vista SP2 - Added 09/2010 */
+	{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},	/* Windows 7 and Server 2008 R2 - Added 09/2009 */
+
+	/* Feature Group Strings */
+
+	{"Extended Address Space Descriptor", NULL, 0, 0}
+
+	/*
+	 * All "optional" feature group strings (features that are implemented
+	 * by the host) should be dynamically added by the host via
+	 * acpi_install_interface and should not be manually added here.
+	 *
+	 * Examples of optional feature group strings:
+	 *
+	 * "Module Device"
+	 * "Processor Device"
+	 * "3.0 Thermal Model"
+	 * "3.0 _SCP Extensions"
+	 * "Processor Aggregator Device"
+	 */
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_initialize_interfaces
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Initialize the global _OSI supported interfaces list
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_initialize_interfaces(void)
+{
+	u32 i;
+
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+	acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
+
+	/* Link the static list of supported interfaces */
+
+	for (i = 0;
+	     i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
+	     i++) {
+		acpi_default_supported_interfaces[i].next =
+		    &acpi_default_supported_interfaces[(acpi_size) i + 1];
+	}
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_interface_terminate
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete all interfaces in the global list. Sets
+ *              acpi_gbl_supported_interfaces to NULL.
+ *
+ ******************************************************************************/
+
+void acpi_ut_interface_terminate(void)
+{
+	struct acpi_interface_info *next_interface;
+
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+	next_interface = acpi_gbl_supported_interfaces;
+
+	while (next_interface) {
+		acpi_gbl_supported_interfaces = next_interface->next;
+
+		/* Only interfaces added at runtime can be freed */
+
+		if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+			ACPI_FREE(next_interface->name);
+			ACPI_FREE(next_interface);
+		}
+
+		next_interface = acpi_gbl_supported_interfaces;
+	}
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_install_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to install
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install the interface into the global interface list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_install_interface(acpi_string interface_name)
+{
+	struct acpi_interface_info *interface_info;
+
+	/* Allocate info block and space for the name string */
+
+	interface_info =
+	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
+	if (!interface_info) {
+		return (AE_NO_MEMORY);
+	}
+
+	interface_info->name =
+	    ACPI_ALLOCATE_ZEROED(ACPI_STRLEN(interface_name) + 1);
+	if (!interface_info->name) {
+		ACPI_FREE(interface_info);
+		return (AE_NO_MEMORY);
+	}
+
+	/* Initialize new info and insert at the head of the global list */
+
+	ACPI_STRCPY(interface_info->name, interface_name);
+	interface_info->flags = ACPI_OSI_DYNAMIC;
+	interface_info->next = acpi_gbl_supported_interfaces;
+
+	acpi_gbl_supported_interfaces = interface_info;
+	return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_remove_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to remove
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove the interface from the global interface list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_remove_interface(acpi_string interface_name)
+{
+	struct acpi_interface_info *previous_interface;
+	struct acpi_interface_info *next_interface;
+
+	previous_interface = next_interface = acpi_gbl_supported_interfaces;
+	while (next_interface) {
+		if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+
+			/* Found: name is in either the static list or was added at runtime */
+
+			if (next_interface->flags & ACPI_OSI_DYNAMIC) {
+
+				/* Interface was added dynamically, remove and free it */
+
+				if (previous_interface == next_interface) {
+					acpi_gbl_supported_interfaces =
+					    next_interface->next;
+				} else {
+					previous_interface->next =
+					    next_interface->next;
+				}
+
+				ACPI_FREE(next_interface->name);
+				ACPI_FREE(next_interface);
+			} else {
+				/*
+				 * Interface is in static list. If marked invalid, then it
+				 * does not actually exist. Else, mark it invalid.
+				 */
+				if (next_interface->flags & ACPI_OSI_INVALID) {
+					return (AE_NOT_EXIST);
+				}
+
+				next_interface->flags |= ACPI_OSI_INVALID;
+			}
+
+			return (AE_OK);
+		}
+
+		previous_interface = next_interface;
+		next_interface = next_interface->next;
+	}
+
+	/* Interface was not found */
+
+	return (AE_NOT_EXIST);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_get_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to find
+ *
+ * RETURN:      struct acpi_interface_info if found. NULL if not found.
+ *
+ * DESCRIPTION: Search for the specified interface name in the global list.
+ *              Caller MUST hold acpi_gbl_osi_mutex
+ *
+ ******************************************************************************/
+
+struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
+{
+	struct acpi_interface_info *next_interface;
+
+	next_interface = acpi_gbl_supported_interfaces;
+	while (next_interface) {
+		if (!ACPI_STRCMP(interface_name, next_interface->name)) {
+			return (next_interface);
+		}
+
+		next_interface = next_interface->next;
+	}
+
+	return (NULL);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_osi_implementation
+ *
+ * PARAMETERS:  walk_state          - Current walk state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Implementation of the _OSI predefined control method. When
+ *              an invocation of _OSI is encountered in the system AML,
+ *              control is transferred to this function.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
+{
+	union acpi_operand_object *string_desc;
+	union acpi_operand_object *return_desc;
+	struct acpi_interface_info *interface_info;
+	acpi_interface_handler interface_handler;
+	u32 return_value;
+
+	ACPI_FUNCTION_TRACE(ut_osi_implementation);
+
+	/* Validate the string input argument (from the AML caller) */
+
+	string_desc = walk_state->arguments[0].object;
+	if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
+		return_ACPI_STATUS(AE_TYPE);
+	}
+
+	/* Create a return object */
+
+	return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+	if (!return_desc) {
+		return_ACPI_STATUS(AE_NO_MEMORY);
+	}
+
+	/* Default return value is 0, NOT SUPPORTED */
+
+	return_value = 0;
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+	/* Lookup the interface in the global _OSI list */
+
+	interface_info = acpi_ut_get_interface(string_desc->string.pointer);
+	if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
+		/*
+		 * The interface is supported.
+		 * Update the osi_data if necessary. We keep track of the latest
+		 * version of Windows that has been requested by the BIOS.
+		 */
+		if (interface_info->value > acpi_gbl_osi_data) {
+			acpi_gbl_osi_data = interface_info->value;
+		}
+
+		return_value = ACPI_UINT32_MAX;
+	}
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+
+	/*
+	 * Invoke an optional _OSI interface handler. The host OS may wish
+	 * to do some interface-specific handling. For example, warn about
+	 * certain interfaces or override the true/false support value.
+	 */
+	interface_handler = acpi_gbl_interface_handler;
+	if (interface_handler) {
+		return_value =
+		    interface_handler(string_desc->string.pointer,
+				      return_value);
+	}
+
+	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
+			      "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
+			      string_desc->string.pointer,
+			      return_value == 0 ? "not " : ""));
+
+	/* Complete the return object */
+
+	return_desc->integer.value = return_value;
+	walk_state->return_desc = return_desc;
+	return_ACPI_STATUS(AE_OK);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utxface.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utxface.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utxface.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utxface.c	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,15 @@
 		return_ACPI_STATUS(status);
 	}
 
+	/* Initialize the global OSI interfaces list with the static names */
+
+	status = acpi_ut_initialize_interfaces();
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"During OSI interfaces initialization"));
+		return_ACPI_STATUS(status);
+	}
+
 	/* If configured, initialize the AML debugger */
 
 	ACPI_DEBUGGER_EXEC(status = acpi_db_initialize());
@@ -290,19 +299,6 @@
 	}
 
 	/*
-	 * Complete the GPE initialization for the GPE blocks defined in the FADT
-	 * (GPE block 0 and 1).
-	 *
-	 * NOTE: Currently, there seems to be no need to run the _REG methods
-	 * before enabling the GPEs.
-	 */
-	if (!(flags & ACPI_NO_EVENT_INIT)) {
-		status = acpi_ev_install_fadt_gpes();
-		if (ACPI_FAILURE(status))
-			return (status);
-	}
-
-	/*
 	 * Empty the caches (delete the cached objects) on the assumption that
 	 * the table load filled them up more than they will be at runtime --
 	 * thus wasting non-paged memory.
@@ -506,6 +502,7 @@
 
 ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
 #endif				/*  ACPI_FUTURE_USAGE  */
+
 /*****************************************************************************
  *
  * FUNCTION:    acpi_purge_cached_objects
@@ -529,4 +526,117 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
-#endif
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_install_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to install
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install an _OSI interface to the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface(acpi_string interface_name)
+{
+	acpi_status status;
+	struct acpi_interface_info *interface_info;
+
+	/* Parameter validation */
+
+	if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+	/* Check if the interface name is already in the global list */
+
+	interface_info = acpi_ut_get_interface(interface_name);
+	if (interface_info) {
+		/*
+		 * The interface already exists in the list. This is OK if the
+		 * interface has been marked invalid -- just clear the bit.
+		 */
+		if (interface_info->flags & ACPI_OSI_INVALID) {
+			interface_info->flags &= ~ACPI_OSI_INVALID;
+			status = AE_OK;
+		} else {
+			status = AE_ALREADY_EXISTS;
+		}
+	} else {
+		/* New interface name, install into the global list */
+
+		status = acpi_ut_install_interface(interface_name);
+	}
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+	return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_remove_interface
+ *
+ * PARAMETERS:  interface_name      - The interface to remove
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove an _OSI interface from the global list
+ *
+ ****************************************************************************/
+acpi_status acpi_remove_interface(acpi_string interface_name)
+{
+	acpi_status status;
+
+	/* Parameter validation */
+
+	if (!interface_name || (ACPI_STRLEN(interface_name) == 0)) {
+		return (AE_BAD_PARAMETER);
+	}
+
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+	status = acpi_ut_remove_interface(interface_name);
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+	return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_interface)
+
+/*****************************************************************************
+ *
+ * FUNCTION:    acpi_install_interface_handler
+ *
+ * PARAMETERS:  Handler             - The _OSI interface handler to install
+ *                                    NULL means "remove existing handler"
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a handler for the predefined _OSI ACPI method.
+ *              invoked during execution of the internal implementation of
+ *              _OSI. A NULL handler simply removes any existing handler.
+ *
+ ****************************************************************************/
+acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
+{
+	acpi_status status = AE_OK;
+
+	(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+
+	if (handler && acpi_gbl_interface_handler) {
+		status = AE_ALREADY_EXISTS;
+	} else {
+		acpi_gbl_interface_handler = handler;
+	}
+
+	acpi_os_release_mutex(acpi_gbl_osi_mutex);
+	return (status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
+#endif				/* !ACPI_ASL_COMPILER */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpica/utxferror.c linux-libre-2.6.37-gnu/drivers/acpi/acpica/utxferror.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpica/utxferror.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpica/utxferror.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,415 @@
+/*******************************************************************************
+ *
+ * Module Name: utxferror - Various error/warning output functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2010, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT          ACPI_UTILITIES
+ACPI_MODULE_NAME("utxferror")
+
+/*
+ * This module is used for the in-kernel ACPICA as well as the ACPICA
+ * tools/applications.
+ *
+ * For the i_aSL compiler case, the output is redirected to stderr so that
+ * any of the various ACPI errors and warnings do not appear in the output
+ * files, for either the compiler or disassembler portions of the tool.
+ */
+#ifdef ACPI_ASL_COMPILER
+#include <stdio.h>
+extern FILE *acpi_gbl_output_file;
+
+#define ACPI_MSG_REDIRECT_BEGIN \
+	FILE                            *output_file = acpi_gbl_output_file; \
+	acpi_os_redirect_output (stderr);
+
+#define ACPI_MSG_REDIRECT_END \
+	acpi_os_redirect_output (output_file);
+
+#else
+/*
+ * non-i_aSL case - no redirection, nothing to do
+ */
+#define ACPI_MSG_REDIRECT_BEGIN
+#define ACPI_MSG_REDIRECT_END
+#endif
+/*
+ * Common message prefixes
+ */
+#define ACPI_MSG_ERROR          "ACPI Error: "
+#define ACPI_MSG_EXCEPTION      "ACPI Exception: "
+#define ACPI_MSG_WARNING        "ACPI Warning: "
+#define ACPI_MSG_INFO           "ACPI: "
+/*
+ * Common message suffix
+ */
+#define ACPI_MSG_SUFFIX \
+	acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Error" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_error(const char *module_name, u32 line_number, const char *format, ...)
+{
+	va_list arg_list;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_ERROR);
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	ACPI_MSG_SUFFIX;
+	va_end(arg_list);
+
+	ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_error)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_exception
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Status              - Status to be formatted
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Exception" message with module/line/version info
+ *              and decoded acpi_status.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_exception(const char *module_name,
+	       u32 line_number, acpi_status status, const char *format, ...)
+{
+	va_list arg_list;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
+		       acpi_format_exception(status));
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	ACPI_MSG_SUFFIX;
+	va_end(arg_list);
+
+	ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_exception)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_warning
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print "ACPI Warning" message with module/line/version info
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
+{
+	va_list arg_list;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_WARNING);
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	ACPI_MSG_SUFFIX;
+	va_end(arg_list);
+
+	ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_warning)
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_info
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Format              - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print generic "ACPI:" information message. There is no
+ *              module/line/version info in order to keep the message simple.
+ *
+ * TBD: module_name and line_number args are not needed, should be removed.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_info(const char *module_name, u32 line_number, const char *format, ...)
+{
+	va_list arg_list;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_INFO);
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	acpi_os_printf("\n");
+	va_end(arg_list);
+
+	ACPI_MSG_REDIRECT_END;
+}
+
+ACPI_EXPORT_SYMBOL(acpi_info)
+
+/*
+ * The remainder of this module contains internal error functions that may
+ * be configured out.
+ */
+#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_warning
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              Pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              Format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ *              only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of error
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+			   u32 line_number,
+			   char *pathname,
+			   u8 node_flags, const char *format, ...)
+{
+	va_list arg_list;
+
+	/*
+	 * Warning messages for this method/object will be disabled after the
+	 * first time a validation fails or an object is successfully repaired.
+	 */
+	if (node_flags & ANOBJ_EVALUATED) {
+		return;
+	}
+
+	acpi_os_printf(ACPI_MSG_WARNING "For %s: ", pathname);
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	ACPI_MSG_SUFFIX;
+	va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_predefined_info
+ *
+ * PARAMETERS:  module_name     - Caller's module name (for error output)
+ *              line_number     - Caller's line number (for error output)
+ *              Pathname        - Full pathname to the node
+ *              node_flags      - From Namespace node for the method/object
+ *              Format          - Printf format string + additional args
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Info messages for the predefined validation module. Messages
+ *              are only emitted the first time a problem with a particular
+ *              method/object is detected. This prevents a flood of
+ *              messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+			u32 line_number,
+			char *pathname, u8 node_flags, const char *format, ...)
+{
+	va_list arg_list;
+
+	/*
+	 * Warning messages for this method/object will be disabled after the
+	 * first time a validation fails or an object is successfully repaired.
+	 */
+	if (node_flags & ANOBJ_EVALUATED) {
+		return;
+	}
+
+	acpi_os_printf(ACPI_MSG_INFO "For %s: ", pathname);
+
+	va_start(arg_list, format);
+	acpi_os_vprintf(format, arg_list);
+	ACPI_MSG_SUFFIX;
+	va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_namespace_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              internal_name       - Name or path of the namespace node
+ *              lookup_status       - Exception code from NS lookup
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the NS node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_namespace_error(const char *module_name,
+			u32 line_number,
+			const char *internal_name, acpi_status lookup_status)
+{
+	acpi_status status;
+	u32 bad_name;
+	char *name = NULL;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_ERROR);
+
+	if (lookup_status == AE_BAD_CHARACTER) {
+
+		/* There is a non-ascii character in the name */
+
+		ACPI_MOVE_32_TO_32(&bad_name,
+				   ACPI_CAST_PTR(u32, internal_name));
+		acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name);
+	} else {
+		/* Convert path to external format */
+
+		status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
+						  internal_name, NULL, &name);
+
+		/* Print target name */
+
+		if (ACPI_SUCCESS(status)) {
+			acpi_os_printf("[%s]", name);
+		} else {
+			acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
+		}
+
+		if (name) {
+			ACPI_FREE(name);
+		}
+	}
+
+	acpi_os_printf(" Namespace lookup failure, %s",
+		       acpi_format_exception(lookup_status));
+
+	ACPI_MSG_SUFFIX;
+	ACPI_MSG_REDIRECT_END;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_method_error
+ *
+ * PARAMETERS:  module_name         - Caller's module name (for error output)
+ *              line_number         - Caller's line number (for error output)
+ *              Message             - Error message to use on failure
+ *              prefix_node         - Prefix relative to the path
+ *              Path                - Path to the node (optional)
+ *              method_status       - Execution status
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_method_error(const char *module_name,
+		     u32 line_number,
+		     const char *message,
+		     struct acpi_namespace_node *prefix_node,
+		     const char *path, acpi_status method_status)
+{
+	acpi_status status;
+	struct acpi_namespace_node *node = prefix_node;
+
+	ACPI_MSG_REDIRECT_BEGIN;
+	acpi_os_printf(ACPI_MSG_ERROR);
+
+	if (path) {
+		status =
+		    acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+				     &node);
+		if (ACPI_FAILURE(status)) {
+			acpi_os_printf("[Could not get node by pathname]");
+		}
+	}
+
+	acpi_ns_print_node_pathname(node, message);
+	acpi_os_printf(", %s", acpi_format_exception(method_status));
+
+	ACPI_MSG_SUFFIX;
+	ACPI_MSG_REDIRECT_END;
+}
+
+#endif				/* ACPI_NO_ERROR_MESSAGES */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/acpi_pad.c linux-libre-2.6.37-gnu/drivers/acpi/acpi_pad.c
--- linux-libre-2.6.36-gnu/drivers/acpi/acpi_pad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/acpi_pad.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,18 +30,13 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <asm/mwait.h>
 
 #define ACPI_PROCESSOR_AGGREGATOR_CLASS	"acpi_pad"
 #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
 #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
 static DEFINE_MUTEX(isolated_cpus_lock);
 
-#define MWAIT_SUBSTATE_MASK	(0xf)
-#define MWAIT_CSTATE_MASK	(0xf)
-#define MWAIT_SUBSTATE_SIZE	(4)
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK	(0x2)
 static unsigned long power_saving_mwait_eax;
 
 static unsigned char tsc_detected_unstable;
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/apei/erst.c linux-libre-2.6.37-gnu/drivers/acpi/apei/erst.c
--- linux-libre-2.6.36-gnu/drivers/acpi/apei/erst.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/apei/erst.c	2011-01-04 19:50:19.000000000 -0500
@@ -86,7 +86,7 @@
  * It is used to provide exclusive accessing for ERST Error Log
  * Address Range too.
  */
-static DEFINE_SPINLOCK(erst_lock);
+static DEFINE_RAW_SPINLOCK(erst_lock);
 
 static inline int erst_errno(int command_status)
 {
@@ -421,9 +421,9 @@
 	if (erst_disable)
 		return -ENODEV;
 
-	spin_lock_irqsave(&erst_lock, flags);
+	raw_spin_lock_irqsave(&erst_lock, flags);
 	count = __erst_get_record_count();
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 
 	return count;
 }
@@ -456,9 +456,9 @@
 	if (erst_disable)
 		return -ENODEV;
 
-	spin_lock_irqsave(&erst_lock, flags);
+	raw_spin_lock_irqsave(&erst_lock, flags);
 	rc = __erst_get_next_record_id(record_id);
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 
 	return rc;
 }
@@ -624,17 +624,17 @@
 		return -EINVAL;
 
 	if (erst_erange.attr & ERST_RANGE_NVRAM) {
-		if (!spin_trylock_irqsave(&erst_lock, flags))
+		if (!raw_spin_trylock_irqsave(&erst_lock, flags))
 			return -EBUSY;
 		rc = __erst_write_to_nvram(record);
-		spin_unlock_irqrestore(&erst_lock, flags);
+		raw_spin_unlock_irqrestore(&erst_lock, flags);
 		return rc;
 	}
 
 	if (record->record_length > erst_erange.size)
 		return -EINVAL;
 
-	if (!spin_trylock_irqsave(&erst_lock, flags))
+	if (!raw_spin_trylock_irqsave(&erst_lock, flags))
 		return -EBUSY;
 	memcpy(erst_erange.vaddr, record, record->record_length);
 	rcd_erange = erst_erange.vaddr;
@@ -642,7 +642,7 @@
 	memcpy(&rcd_erange->persistence_information, "ER", 2);
 
 	rc = __erst_write_to_storage(0);
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 
 	return rc;
 }
@@ -696,9 +696,9 @@
 	if (erst_disable)
 		return -ENODEV;
 
-	spin_lock_irqsave(&erst_lock, flags);
+	raw_spin_lock_irqsave(&erst_lock, flags);
 	len = __erst_read(record_id, record, buflen);
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 	return len;
 }
 EXPORT_SYMBOL_GPL(erst_read);
@@ -719,20 +719,20 @@
 	if (erst_disable)
 		return -ENODEV;
 
-	spin_lock_irqsave(&erst_lock, flags);
+	raw_spin_lock_irqsave(&erst_lock, flags);
 	rc = __erst_get_next_record_id(&record_id);
 	if (rc) {
-		spin_unlock_irqrestore(&erst_lock, flags);
+		raw_spin_unlock_irqrestore(&erst_lock, flags);
 		return rc;
 	}
 	/* no more record */
 	if (record_id == APEI_ERST_INVALID_RECORD_ID) {
-		spin_unlock_irqrestore(&erst_lock, flags);
+		raw_spin_unlock_irqrestore(&erst_lock, flags);
 		return 0;
 	}
 
 	len = __erst_read(record_id, record, buflen);
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 
 	return len;
 }
@@ -746,12 +746,12 @@
 	if (erst_disable)
 		return -ENODEV;
 
-	spin_lock_irqsave(&erst_lock, flags);
+	raw_spin_lock_irqsave(&erst_lock, flags);
 	if (erst_erange.attr & ERST_RANGE_NVRAM)
 		rc = __erst_clear_from_nvram(record_id);
 	else
 		rc = __erst_clear_from_storage(record_id);
-	spin_unlock_irqrestore(&erst_lock, flags);
+	raw_spin_unlock_irqrestore(&erst_lock, flags);
 
 	return rc;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/apei/erst-dbg.c linux-libre-2.6.37-gnu/drivers/acpi/apei/erst-dbg.c
--- linux-libre-2.6.36-gnu/drivers/acpi/apei/erst-dbg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/apei/erst-dbg.c	2011-01-04 19:50:19.000000000 -0500
@@ -184,6 +184,7 @@
 	.read		= erst_dbg_read,
 	.write		= erst_dbg_write,
 	.unlocked_ioctl	= erst_dbg_ioctl,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice erst_dbg_dev = {
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/apei/hest.c linux-libre-2.6.37-gnu/drivers/acpi/apei/hest.c
--- linux-libre-2.6.36-gnu/drivers/acpi/apei/hest.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/apei/hest.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,9 +46,9 @@
 
 /* HEST table parsing */
 
-static struct acpi_table_hest *hest_tab;
+static struct acpi_table_hest *__read_mostly hest_tab;
 
-static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
+static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
 	[ACPI_HEST_TYPE_IA32_CHECK] = -1,	/* need further calculation */
 	[ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
 	[ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
@@ -126,7 +126,7 @@
 	unsigned int count;
 };
 
-static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
 {
 	int *count = data;
 
@@ -135,7 +135,7 @@
 	return 0;
 }
 
-static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
+static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
 {
 	struct platform_device *ghes_dev;
 	struct ghes_arr *ghes_arr = data;
@@ -165,7 +165,7 @@
 	return rc;
 }
 
-static int hest_ghes_dev_register(unsigned int ghes_count)
+static int __init hest_ghes_dev_register(unsigned int ghes_count)
 {
 	int rc, i;
 	struct ghes_arr ghes_arr;
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/battery.c linux-libre-2.6.37-gnu/drivers/acpi/battery.c
--- linux-libre-2.6.36-gnu/drivers/acpi/battery.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/battery.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,10 +42,7 @@
 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 
 #define PREFIX "ACPI: "
 
@@ -98,13 +95,12 @@
 	 * due to bad math.
 	 */
 	ACPI_BATTERY_QUIRK_SIGNED16_CURRENT,
+	ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY,
 };
 
 struct acpi_battery {
 	struct mutex lock;
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	struct power_supply bat;
-#endif
 	struct acpi_device *device;
 	unsigned long update_time;
 	int rate_now;
@@ -141,7 +137,6 @@
 	return battery->device->status.battery_present;
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int acpi_battery_technology(struct acpi_battery *battery)
 {
 	if (!strcasecmp("NiCd", battery->type))
@@ -186,6 +181,7 @@
 				     enum power_supply_property psp,
 				     union power_supply_propval *val)
 {
+	int ret = 0;
 	struct acpi_battery *battery = to_acpi_battery(psy);
 
 	if (acpi_battery_present(battery)) {
@@ -214,26 +210,44 @@
 		val->intval = battery->cycle_count;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
-		val->intval = battery->design_voltage * 1000;
+		if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->design_voltage * 1000;
 		break;
 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
-		val->intval = battery->voltage_now * 1000;
+		if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->voltage_now * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CURRENT_NOW:
 	case POWER_SUPPLY_PROP_POWER_NOW:
-		val->intval = battery->rate_now * 1000;
+		if (battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->rate_now * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
 	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
-		val->intval = battery->design_capacity * 1000;
+		if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->design_capacity * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_FULL:
 	case POWER_SUPPLY_PROP_ENERGY_FULL:
-		val->intval = battery->full_charge_capacity * 1000;
+		if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->full_charge_capacity * 1000;
 		break;
 	case POWER_SUPPLY_PROP_CHARGE_NOW:
 	case POWER_SUPPLY_PROP_ENERGY_NOW:
-		val->intval = battery->capacity_now * 1000;
+		if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
+			ret = -ENODEV;
+		else
+			val->intval = battery->capacity_now * 1000;
 		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = battery->model_number;
@@ -245,9 +259,9 @@
 		val->strval = battery->serial_number;
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
 	}
-	return 0;
+	return ret;
 }
 
 static enum power_supply_property charge_battery_props[] = {
@@ -281,7 +295,6 @@
 	POWER_SUPPLY_PROP_MANUFACTURER,
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
-#endif
 
 #ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -412,6 +425,8 @@
 		result = extract_package(battery, buffer.pointer,
 				info_offsets, ARRAY_SIZE(info_offsets));
 	kfree(buffer.pointer);
+	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+		battery->full_charge_capacity = battery->design_capacity;
 	return result;
 }
 
@@ -448,6 +463,10 @@
 	    battery->rate_now != -1)
 		battery->rate_now = abs((s16)battery->rate_now);
 
+	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)
+	    && battery->capacity_now >= 0 && battery->capacity_now <= 100)
+		battery->capacity_now = (battery->capacity_now *
+				battery->full_charge_capacity) / 100;
 	return result;
 }
 
@@ -492,7 +511,6 @@
 	return acpi_battery_set_alarm(battery);
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
@@ -552,7 +570,6 @@
 	power_supply_unregister(&battery->bat);
 	battery->bat.dev = NULL;
 }
-#endif
 
 static void acpi_battery_quirks(struct acpi_battery *battery)
 {
@@ -561,6 +578,33 @@
 	}
 }
 
+/*
+ * According to the ACPI spec, some kinds of primary batteries can
+ * report percentage battery remaining capacity directly to OS.
+ * In this case, it reports the Last Full Charged Capacity == 100
+ * and BatteryPresentRate == 0xFFFFFFFF.
+ *
+ * Now we found some battery reports percentage remaining capacity
+ * even if it's rechargeable.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15979
+ *
+ * Handle this correctly so that they won't break userspace.
+ */
+static void acpi_battery_quirks2(struct acpi_battery *battery)
+{
+	if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
+		return ;
+
+        if (battery->full_charge_capacity == 100 &&
+            battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+            battery->capacity_now >=0 && battery->capacity_now <= 100) {
+		set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
+		battery->full_charge_capacity = battery->design_capacity;
+		battery->capacity_now = (battery->capacity_now *
+				battery->full_charge_capacity) / 100;
+	}
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
 	int result, old_present = acpi_battery_present(battery);
@@ -568,9 +612,7 @@
 	if (result)
 		return result;
 	if (!acpi_battery_present(battery)) {
-#ifdef CONFIG_ACPI_SYSFS_POWER
 		sysfs_remove_battery(battery);
-#endif
 		battery->update_time = 0;
 		return 0;
 	}
@@ -582,11 +624,11 @@
 		acpi_battery_quirks(battery);
 		acpi_battery_init_alarm(battery);
 	}
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (!battery->bat.dev)
 		sysfs_add_battery(battery);
-#endif
-	return acpi_battery_get_state(battery);
+	result = acpi_battery_get_state(battery);
+	acpi_battery_quirks2(battery);
+	return result;
 }
 
 /* --------------------------------------------------------------------------
@@ -867,26 +909,20 @@
 static void acpi_battery_notify(struct acpi_device *device, u32 event)
 {
 	struct acpi_battery *battery = acpi_driver_data(device);
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	struct device *old;
-#endif
 
 	if (!battery)
 		return;
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	old = battery->bat.dev;
-#endif
 	acpi_battery_update(battery);
 	acpi_bus_generate_proc_event(device, event,
 				     acpi_battery_present(battery));
 	acpi_bus_generate_netlink_event(device->pnp.device_class,
 					dev_name(&device->dev), event,
 					acpi_battery_present(battery));
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	/* acpi_battery_update could remove power_supply object */
 	if (old && battery->bat.dev)
 		power_supply_changed(&battery->bat);
-#endif
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -934,9 +970,7 @@
 #ifdef CONFIG_ACPI_PROCFS_POWER
 	acpi_battery_remove_fs(device);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	sysfs_remove_battery(battery);
-#endif
 	mutex_destroy(&battery->lock);
 	kfree(battery);
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/bus.c linux-libre-2.6.37-gnu/drivers/acpi/bus.c
--- linux-libre-2.6.36-gnu/drivers/acpi/bus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/bus.c	2011-01-04 19:50:19.000000000 -0500
@@ -935,6 +935,12 @@
 		goto error1;
 	}
 
+	/*
+	 * _PDC control method may load dynamic SSDT tables,
+	 * and we need to install the table handler before that.
+	 */
+	acpi_sysfs_init();
+
 	acpi_early_processor_set_pdc();
 
 	/*
@@ -1026,7 +1032,6 @@
 	acpi_scan_init();
 	acpi_ec_init();
 	acpi_power_init();
-	acpi_sysfs_init();
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/button.c linux-libre-2.6.37-gnu/drivers/acpi/button.c
--- linux-libre-2.6.36-gnu/drivers/acpi/button.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/button.c	2011-01-04 19:50:19.000000000 -0500
@@ -338,7 +338,8 @@
 {
 	struct acpi_button *button;
 	struct input_dev *input;
-	char *hid, *name, *class;
+	const char *hid = acpi_device_hid(device);
+	char *name, *class;
 	int error;
 
 	button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
@@ -353,7 +354,6 @@
 		goto err_free_button;
 	}
 
-	hid = acpi_device_hid(device);
 	name = acpi_device_name(device);
 	class = acpi_device_class(device);
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/debugfs.c linux-libre-2.6.37-gnu/drivers/acpi/debugfs.c
--- linux-libre-2.6.36-gnu/drivers/acpi/debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -69,6 +69,7 @@
 
 static const struct file_operations cm_fops = {
 	.write = cm_write,
+	.llseek = default_llseek,
 };
 
 int __init acpi_debugfs_init(void)
@@ -79,7 +80,7 @@
 	if (!acpi_dir)
 		goto err;
 
-	cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
+	cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
 					acpi_dir, NULL, &cm_fops);
 	if (!cm_dentry)
 		goto err;
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/dock.c linux-libre-2.6.37-gnu/drivers/acpi/dock.c
--- linux-libre-2.6.36-gnu/drivers/acpi/dock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/dock.c	2011-01-04 19:50:19.000000000 -0500
@@ -725,6 +725,7 @@
 			complete_dock(ds);
 			dock_event(ds, event, DOCK_EVENT);
 			dock_lock(ds, 1);
+			acpi_update_gpes();
 			break;
 		}
 		if (dock_present(ds) || dock_in_progress(ds))
@@ -929,7 +930,7 @@
  * allocated and initialize a new dock station device.  Find all devices
  * that are on the dock station, and register for dock event notifications.
  */
-static int dock_add(acpi_handle handle)
+static int __init dock_add(acpi_handle handle)
 {
 	int ret, id;
 	struct dock_station ds, *dock_station;
@@ -1023,7 +1024,7 @@
  *
  * This is called by acpi_walk_namespace to look for dock stations.
  */
-static acpi_status
+static __init acpi_status
 find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
 	if (is_dock(handle))
@@ -1032,7 +1033,7 @@
 	return AE_OK;
 }
 
-static acpi_status
+static __init acpi_status
 find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
 	/* If bay is a dock, it's already handled */
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/ec.c linux-libre-2.6.37-gnu/drivers/acpi/ec.c
--- linux-libre-2.6.36-gnu/drivers/acpi/ec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/ec.c	2011-01-04 19:50:19.000000000 -0500
@@ -83,6 +83,11 @@
 	EC_FLAGS_BLOCKED,		/* Transactions are blocked */
 };
 
+/* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
+static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
+module_param(ec_delay, uint, 0644);
+MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
+
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
 typedef int (*acpi_ec_query_func) (void *data);
@@ -210,7 +215,7 @@
 	int repeat = 2; /* number of command restarts */
 	while (repeat--) {
 		unsigned long delay = jiffies +
-			msecs_to_jiffies(ACPI_EC_DELAY);
+			msecs_to_jiffies(ec_delay);
 		do {
 			/* don't sleep with disabled interrupts */
 			if (EC_FLAGS_MSI || irqs_disabled()) {
@@ -265,7 +270,7 @@
 
 static int ec_wait_ibf0(struct acpi_ec *ec)
 {
-	unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+	unsigned long delay = jiffies + msecs_to_jiffies(ec_delay);
 	/* interrupt wait manually if GPE mode is not active */
 	while (time_before(jiffies, delay))
 		if (wait_event_timeout(ec->wait, ec_check_ibf0(ec),
@@ -929,6 +934,9 @@
 	ec_flag_msi, "MSI hardware", {
 	DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
 	{
+	ec_flag_msi, "MSI hardware", {
+	DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
+	{
 	ec_validate_ecdt, "ASUS hardware", {
 	DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
 	{},
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/ec_sys.c linux-libre-2.6.37-gnu/drivers/acpi/ec_sys.c
--- linux-libre-2.6.36-gnu/drivers/acpi/ec_sys.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/ec_sys.c	2011-01-04 19:50:19.000000000 -0500
@@ -101,6 +101,7 @@
 	.open  = acpi_ec_open_io,
 	.read  = acpi_ec_read_io,
 	.write = acpi_ec_write_io,
+	.llseek = default_llseek,
 };
 
 int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count)
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/event.c linux-libre-2.6.37-gnu/drivers/acpi/event.c
--- linux-libre-2.6.36-gnu/drivers/acpi/event.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/event.c	2011-01-04 19:50:19.000000000 -0500
@@ -110,6 +110,7 @@
 	.read = acpi_system_read_event,
 	.release = acpi_system_close_event,
 	.poll = acpi_system_poll_event,
+	.llseek = default_llseek,
 };
 #endif	/* CONFIG_ACPI_PROC_EVENT */
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/fan.c linux-libre-2.6.37-gnu/drivers/acpi/fan.c
--- linux-libre-2.6.36-gnu/drivers/acpi/fan.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/fan.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,8 +27,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 #include <linux/thermal.h>
 #include <acpi/acpi_bus.h>
@@ -119,122 +117,6 @@
 };
 
 /* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_fan_dir;
-
-static int acpi_fan_read_state(struct seq_file *seq, void *offset)
-{
-	struct acpi_device *device = seq->private;
-	int state = 0;
-
-
-	if (device) {
-		if (acpi_bus_get_power(device->handle, &state))
-			seq_printf(seq, "status:                  ERROR\n");
-		else
-			seq_printf(seq, "status:                  %s\n",
-				   !state ? "on" : "off");
-	}
-	return 0;
-}
-
-static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_fan_read_state, PDE(inode)->data);
-}
-
-static ssize_t
-acpi_fan_write_state(struct file *file, const char __user * buffer,
-		     size_t count, loff_t * ppos)
-{
-	int result = 0;
-	struct seq_file *m = file->private_data;
-	struct acpi_device *device = m->private;
-	char state_string[3] = { '\0' };
-
-	if (count > sizeof(state_string) - 1)
-		return -EINVAL;
-
-	if (copy_from_user(state_string, buffer, count))
-		return -EFAULT;
-
-	state_string[count] = '\0';
-	if ((state_string[0] < '0') || (state_string[0] > '3'))
-		return -EINVAL;
-	if (state_string[1] == '\n')
-		state_string[1] = '\0';
-	if (state_string[1] != '\0')
-		return -EINVAL;
-
-	result = acpi_bus_set_power(device->handle,
-				    simple_strtoul(state_string, NULL, 0));
-	if (result)
-		return result;
-
-	return count;
-}
-
-static const struct file_operations acpi_fan_state_ops = {
-	.open = acpi_fan_state_open_fs,
-	.read = seq_read,
-	.write = acpi_fan_write_state,
-	.llseek = seq_lseek,
-	.release = single_release,
-	.owner = THIS_MODULE,
-};
-
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *entry = NULL;
-
-
-	if (!device)
-		return -EINVAL;
-
-	if (!acpi_device_dir(device)) {
-		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
-						     acpi_fan_dir);
-		if (!acpi_device_dir(device))
-			return -ENODEV;
-	}
-
-	/* 'status' [R/W] */
-	entry = proc_create_data(ACPI_FAN_FILE_STATE,
-				 S_IFREG | S_IRUGO | S_IWUSR,
-				 acpi_device_dir(device),
-				 &acpi_fan_state_ops,
-				 device);
-	if (!entry)
-		return -ENODEV;
-	return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
-
-	if (acpi_device_dir(device)) {
-		remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
-		remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
-		acpi_device_dir(device) = NULL;
-	}
-
-	return 0;
-}
-#else
-static int acpi_fan_add_fs(struct acpi_device *device)
-{
-	return 0;
-}
-
-static int acpi_fan_remove_fs(struct acpi_device *device)
-{
-	return 0;
-}
-#endif
-/* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
@@ -284,10 +166,6 @@
 		dev_err(&device->dev, "Failed to create sysfs link "
 			"'device'\n");
 
-	result = acpi_fan_add_fs(device);
-	if (result)
-		goto end;
-
 	printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
 	       acpi_device_name(device), acpi_device_bid(device),
 	       !device->power.state ? "on" : "off");
@@ -303,7 +181,6 @@
 	if (!device || !cdev)
 		return -EINVAL;
 
-	acpi_fan_remove_fs(device);
 	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
 	sysfs_remove_link(&cdev->device.kobj, "device");
 	thermal_cooling_device_unregister(cdev);
@@ -347,19 +224,9 @@
 {
 	int result = 0;
 
-#ifdef CONFIG_ACPI_PROCFS
-	acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
-	if (!acpi_fan_dir)
-		return -ENODEV;
-#endif
-
 	result = acpi_bus_register_driver(&acpi_fan_driver);
-	if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
-		remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
+	if (result < 0)
 		return -ENODEV;
-	}
 
 	return 0;
 }
@@ -369,10 +236,6 @@
 
 	acpi_bus_unregister_driver(&acpi_fan_driver);
 
-#ifdef CONFIG_ACPI_PROCFS
-	remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
-#endif
-
 	return;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/Kconfig linux-libre-2.6.37-gnu/drivers/acpi/Kconfig
--- linux-libre-2.6.36-gnu/drivers/acpi/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,6 @@
 	depends on PCI
 	depends on PM
 	select PNP
-	select CPU_IDLE
 	default y
 	help
 	  Advanced Configuration and Power Interface (ACPI) support for 
@@ -66,7 +65,6 @@
 config ACPI_PROCFS_POWER
 	bool "Deprecated power /proc/acpi directories"
 	depends on PROC_FS
-	default y
 	help
 	  For backwards compatibility, this option allows
           deprecated power /proc/acpi/ directories to exist, even when
@@ -90,13 +88,6 @@
 	  To compile this driver as a module, choose M here:
 	  the module will be called power-meter.
 
-config ACPI_SYSFS_POWER
-	bool "Future power /sys interface"
-	select POWER_SUPPLY
-	default y
-	help
-	  Say N to disable power /sys interface
-
 config ACPI_EC_DEBUGFS
 	tristate "EC read/write access through /sys/kernel/debug/ec"
 	default n
@@ -136,6 +127,7 @@
 config ACPI_AC
 	tristate "AC Adapter"
 	depends on X86
+	select POWER_SUPPLY
 	default y
 	help
 	  This driver supports the AC Adapter object, which indicates
@@ -148,6 +140,7 @@
 config ACPI_BATTERY
 	tristate "Battery"
 	depends on X86
+	select POWER_SUPPLY
 	default y
 	help
 	  This driver adds support for battery information through
@@ -206,6 +199,7 @@
 config ACPI_PROCESSOR
 	tristate "Processor"
 	select THERMAL
+	select CPU_IDLE
 	default y
 	help
 	  This driver installs ACPI as the idle handler for Linux and uses
@@ -364,6 +358,7 @@
 config ACPI_SBS
 	tristate "Smart Battery System"
 	depends on X86
+	select POWER_SUPPLY
 	help
 	  This driver supports the Smart Battery System, another
 	  type of access to battery information, found on some laptops.
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/osl.c linux-libre-2.6.37-gnu/drivers/acpi/osl.c
--- linux-libre-2.6.36-gnu/drivers/acpi/osl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/osl.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,8 +95,22 @@
 static LIST_HEAD(resource_list_head);
 static DEFINE_SPINLOCK(acpi_res_lock);
 
-#define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */
-static char osi_additional_string[OSI_STRING_LENGTH_MAX];
+/*
+ * This list of permanent mappings is for memory that may be accessed from
+ * interrupt context, where we can't do the ioremap().
+ */
+struct acpi_ioremap {
+	struct list_head list;
+	void __iomem *virt;
+	acpi_physical_address phys;
+	acpi_size size;
+	struct kref ref;
+};
+
+static LIST_HEAD(acpi_ioremaps);
+static DEFINE_SPINLOCK(acpi_ioremap_lock);
+
+static void __init acpi_osi_setup_late(void);
 
 /*
  * The story of _OSI(Linux)
@@ -135,8 +149,21 @@
 	unsigned int	enable:1;
 	unsigned int	dmi:1;
 	unsigned int	cmdline:1;
-	unsigned int	known:1;
-} osi_linux = { 0, 0, 0, 0};
+} osi_linux = {0, 0, 0};
+
+static u32 acpi_osi_handler(acpi_string interface, u32 supported)
+{
+	if (!strcmp("Linux", interface)) {
+
+		printk(KERN_NOTICE FW_BUG PREFIX
+			"BIOS _OSI(Linux) query %s%s\n",
+			osi_linux.enable ? "honored" : "ignored",
+			osi_linux.cmdline ? " via cmdline" :
+			osi_linux.dmi ? " via DMI" : "");
+	}
+
+	return supported;
+}
 
 static void __init acpi_request_region (struct acpi_generic_address *addr,
 	unsigned int length, char *desc)
@@ -185,36 +212,6 @@
 }
 device_initcall(acpi_reserve_resources);
 
-acpi_status __init acpi_os_initialize(void)
-{
-	return AE_OK;
-}
-
-acpi_status acpi_os_initialize1(void)
-{
-	kacpid_wq = create_workqueue("kacpid");
-	kacpi_notify_wq = create_workqueue("kacpi_notify");
-	kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
-	BUG_ON(!kacpid_wq);
-	BUG_ON(!kacpi_notify_wq);
-	BUG_ON(!kacpi_hotplug_wq);
-	return AE_OK;
-}
-
-acpi_status acpi_os_terminate(void)
-{
-	if (acpi_irq_handler) {
-		acpi_os_remove_interrupt_handler(acpi_irq_irq,
-						 acpi_irq_handler);
-	}
-
-	destroy_workqueue(kacpid_wq);
-	destroy_workqueue(kacpi_notify_wq);
-	destroy_workqueue(kacpi_hotplug_wq);
-
-	return AE_OK;
-}
-
 void acpi_os_printf(const char *fmt, ...)
 {
 	va_list args;
@@ -260,29 +257,135 @@
 	}
 }
 
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup(acpi_physical_address phys, acpi_size size)
+{
+	struct acpi_ioremap *map;
+
+	list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+		if (map->phys <= phys &&
+		    phys + size <= map->phys + map->size)
+			return map;
+
+	return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static void __iomem *
+acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
+{
+	struct acpi_ioremap *map;
+
+	map = acpi_map_lookup(phys, size);
+	if (map)
+		return map->virt + (phys - map->phys);
+
+	return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
+{
+	struct acpi_ioremap *map;
+
+	list_for_each_entry_rcu(map, &acpi_ioremaps, list)
+		if (map->virt <= virt &&
+		    virt + size <= map->virt + map->size)
+			return map;
+
+	return NULL;
+}
+
 void __iomem *__init_refok
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
+	struct acpi_ioremap *map, *tmp_map;
+	unsigned long flags, pg_sz;
+	void __iomem *virt;
+	phys_addr_t pg_off;
+
 	if (phys > ULONG_MAX) {
 		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
 		return NULL;
 	}
-	if (acpi_gbl_permanent_mmap)
-		/*
-		* ioremap checks to ensure this is in reserved space
-		*/
-		return ioremap((unsigned long)phys, size);
-	else
+
+	if (!acpi_gbl_permanent_mmap)
 		return __acpi_map_table((unsigned long)phys, size);
+
+	map = kzalloc(sizeof(*map), GFP_KERNEL);
+	if (!map)
+		return NULL;
+
+	pg_off = round_down(phys, PAGE_SIZE);
+	pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
+	virt = ioremap(pg_off, pg_sz);
+	if (!virt) {
+		kfree(map);
+		return NULL;
+	}
+
+	INIT_LIST_HEAD(&map->list);
+	map->virt = virt;
+	map->phys = pg_off;
+	map->size = pg_sz;
+	kref_init(&map->ref);
+
+	spin_lock_irqsave(&acpi_ioremap_lock, flags);
+	/* Check if page has already been mapped. */
+	tmp_map = acpi_map_lookup(phys, size);
+	if (tmp_map) {
+		kref_get(&tmp_map->ref);
+		spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+		iounmap(map->virt);
+		kfree(map);
+		return tmp_map->virt + (phys - tmp_map->phys);
+	}
+	list_add_tail_rcu(&map->list, &acpi_ioremaps);
+	spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+	return map->virt + (phys - map->phys);
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
+static void acpi_kref_del_iomap(struct kref *ref)
+{
+	struct acpi_ioremap *map;
+
+	map = container_of(ref, struct acpi_ioremap, ref);
+	list_del_rcu(&map->list);
+}
+
 void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
 {
-	if (acpi_gbl_permanent_mmap)
-		iounmap(virt);
-	else
+	struct acpi_ioremap *map;
+	unsigned long flags;
+	int del;
+
+	if (!acpi_gbl_permanent_mmap) {
 		__acpi_unmap_table(virt, size);
+		return;
+	}
+
+	spin_lock_irqsave(&acpi_ioremap_lock, flags);
+	map = acpi_map_lookup_virt(virt, size);
+	if (!map) {
+		spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+		printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
+		dump_stack();
+		return;
+	}
+
+	del = kref_put(&map->ref, acpi_kref_del_iomap);
+	spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+	if (!del)
+		return;
+
+	synchronize_rcu();
+	iounmap(map->virt);
+	kfree(map);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
@@ -292,6 +395,44 @@
 		__acpi_unmap_table(virt, size);
 }
 
+int acpi_os_map_generic_address(struct acpi_generic_address *addr)
+{
+	void __iomem *virt;
+
+	if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		return 0;
+
+	if (!addr->address || !addr->bit_width)
+		return -EINVAL;
+
+	virt = acpi_os_map_memory(addr->address, addr->bit_width / 8);
+	if (!virt)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
+
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
+{
+	void __iomem *virt;
+	unsigned long flags;
+	acpi_size size = addr->bit_width / 8;
+
+	if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
+		return;
+
+	if (!addr->address || !addr->bit_width)
+		return;
+
+	spin_lock_irqsave(&acpi_ioremap_lock, flags);
+	virt = acpi_map_vaddr_lookup(addr->address, size);
+	spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+	acpi_os_unmap_memory(virt, size);
+}
+EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
+
 #ifdef ACPI_FUTURE_USAGE
 acpi_status
 acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
@@ -495,8 +636,15 @@
 {
 	u32 dummy;
 	void __iomem *virt_addr;
+	int size = width / 8, unmap = 0;
 
-	virt_addr = ioremap(phys_addr, width);
+	rcu_read_lock();
+	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+	rcu_read_unlock();
+	if (!virt_addr) {
+		virt_addr = ioremap(phys_addr, size);
+		unmap = 1;
+	}
 	if (!value)
 		value = &dummy;
 
@@ -514,7 +662,8 @@
 		BUG();
 	}
 
-	iounmap(virt_addr);
+	if (unmap)
+		iounmap(virt_addr);
 
 	return AE_OK;
 }
@@ -523,8 +672,15 @@
 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
 {
 	void __iomem *virt_addr;
+	int size = width / 8, unmap = 0;
 
-	virt_addr = ioremap(phys_addr, width);
+	rcu_read_lock();
+	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+	rcu_read_unlock();
+	if (!virt_addr) {
+		virt_addr = ioremap(phys_addr, size);
+		unmap = 1;
+	}
 
 	switch (width) {
 	case 8:
@@ -540,16 +696,18 @@
 		BUG();
 	}
 
-	iounmap(virt_addr);
+	if (unmap)
+		iounmap(virt_addr);
 
 	return AE_OK;
 }
 
 acpi_status
 acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
-			       u32 *value, u32 width)
+			       u64 *value, u32 width)
 {
 	int result, size;
+	u32 value32;
 
 	if (!value)
 		return AE_BAD_PARAMETER;
@@ -570,7 +728,8 @@
 
 	result = raw_pci_read(pci_id->segment, pci_id->bus,
 				PCI_DEVFN(pci_id->device, pci_id->function),
-				reg, size, value);
+				reg, size, &value32);
+	*value = value32;
 
 	return (result ? AE_ERROR : AE_OK);
 }
@@ -602,74 +761,6 @@
 	return (result ? AE_ERROR : AE_OK);
 }
 
-/* TODO: Change code to take advantage of driver model more */
-static void acpi_os_derive_pci_id_2(acpi_handle rhandle,	/* upper bound  */
-				    acpi_handle chandle,	/* current node */
-				    struct acpi_pci_id **id,
-				    int *is_bridge, u8 * bus_number)
-{
-	acpi_handle handle;
-	struct acpi_pci_id *pci_id = *id;
-	acpi_status status;
-	unsigned long long temp;
-	acpi_object_type type;
-
-	acpi_get_parent(chandle, &handle);
-	if (handle != rhandle) {
-		acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
-					bus_number);
-
-		status = acpi_get_type(handle, &type);
-		if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
-			return;
-
-		status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
-					  &temp);
-		if (ACPI_SUCCESS(status)) {
-			u32 val;
-			pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
-			pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
-
-			if (*is_bridge)
-				pci_id->bus = *bus_number;
-
-			/* any nicer way to get bus number of bridge ? */
-			status =
-			    acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
-							   8);
-			if (ACPI_SUCCESS(status)
-			    && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
-				status =
-				    acpi_os_read_pci_configuration(pci_id, 0x18,
-								   &val, 8);
-				if (!ACPI_SUCCESS(status)) {
-					/* Certainly broken...  FIX ME */
-					return;
-				}
-				*is_bridge = 1;
-				pci_id->bus = val;
-				status =
-				    acpi_os_read_pci_configuration(pci_id, 0x19,
-								   &val, 8);
-				if (ACPI_SUCCESS(status)) {
-					*bus_number = val;
-				}
-			} else
-				*is_bridge = 0;
-		}
-	}
-}
-
-void acpi_os_derive_pci_id(acpi_handle rhandle,	/* upper bound  */
-			   acpi_handle chandle,	/* current node */
-			   struct acpi_pci_id **id)
-{
-	int is_bridge = 1;
-	u8 bus_number = (*id)->bus;
-
-	acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
-}
-
 static void acpi_os_execute_deferred(struct work_struct *work)
 {
 	struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
@@ -780,16 +871,6 @@
 EXPORT_SYMBOL(acpi_os_wait_events_complete);
 
 /*
- * Allocate the memory for a spinlock and initialize it.
- */
-acpi_status acpi_os_create_lock(acpi_spinlock * handle)
-{
-	spin_lock_init(*handle);
-
-	return AE_OK;
-}
-
-/*
  * Deallocate the memory for a spinlock.
  */
 void acpi_os_delete_lock(acpi_spinlock handle)
@@ -970,19 +1051,66 @@
 
 __setup("acpi_os_name=", acpi_os_name_setup);
 
+#define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */
+#define	OSI_STRING_ENTRIES_MAX 16	/* arbitrary */
+
+struct osi_setup_entry {
+	char string[OSI_STRING_LENGTH_MAX];
+	bool enable;
+};
+
+static struct osi_setup_entry __initdata osi_setup_entries[OSI_STRING_ENTRIES_MAX];
+
+void __init acpi_osi_setup(char *str)
+{
+	struct osi_setup_entry *osi;
+	bool enable = true;
+	int i;
+
+	if (!acpi_gbl_create_osi_method)
+		return;
+
+	if (str == NULL || *str == '\0') {
+		printk(KERN_INFO PREFIX "_OSI method disabled\n");
+		acpi_gbl_create_osi_method = FALSE;
+		return;
+	}
+
+	if (*str == '!') {
+		str++;
+		enable = false;
+	}
+
+	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+		osi = &osi_setup_entries[i];
+		if (!strcmp(osi->string, str)) {
+			osi->enable = enable;
+			break;
+		} else if (osi->string[0] == '\0') {
+			osi->enable = enable;
+			strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
+			break;
+		}
+	}
+}
+
 static void __init set_osi_linux(unsigned int enable)
 {
-	if (osi_linux.enable != enable) {
+	if (osi_linux.enable != enable)
 		osi_linux.enable = enable;
-		printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
-			enable ? "Add": "Delet");
-	}
+
+	if (osi_linux.enable)
+		acpi_osi_setup("Linux");
+	else
+		acpi_osi_setup("!Linux");
+
 	return;
 }
 
 static void __init acpi_cmdline_osi_linux(unsigned int enable)
 {
-	osi_linux.cmdline = 1;	/* cmdline set the default */
+	osi_linux.cmdline = 1;	/* cmdline set the default and override DMI */
+	osi_linux.dmi = 0;
 	set_osi_linux(enable);
 
 	return;
@@ -990,15 +1118,12 @@
 
 void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
 {
-	osi_linux.dmi = 1;	/* DMI knows that this box asks OSI(Linux) */
-
 	printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
 
 	if (enable == -1)
 		return;
 
-	osi_linux.known = 1;	/* DMI knows which OSI(Linux) default needed */
-
+	osi_linux.dmi = 1;	/* DMI knows that this box asks OSI(Linux) */
 	set_osi_linux(enable);
 
 	return;
@@ -1011,27 +1136,46 @@
  * string starting with '!' disables that string
  * otherwise string is added to list, augmenting built-in strings
  */
-int __init acpi_osi_setup(char *str)
+static void __init acpi_osi_setup_late(void)
 {
-	if (str == NULL || *str == '\0') {
-		printk(KERN_INFO PREFIX "_OSI method disabled\n");
-		acpi_gbl_create_osi_method = FALSE;
-	} else if (!strcmp("!Linux", str)) {
-		acpi_cmdline_osi_linux(0);	/* !enable */
-	} else if (*str == '!') {
-		if (acpi_osi_invalidate(++str) == AE_OK)
-			printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
-	} else if (!strcmp("Linux", str)) {
-		acpi_cmdline_osi_linux(1);	/* enable */
-	} else if (*osi_additional_string == '\0') {
-		strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
-		printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+	struct osi_setup_entry *osi;
+	char *str;
+	int i;
+	acpi_status status;
+
+	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
+		osi = &osi_setup_entries[i];
+		str = osi->string;
+
+		if (*str == '\0')
+			break;
+		if (osi->enable) {
+			status = acpi_install_interface(str);
+
+			if (ACPI_SUCCESS(status))
+				printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
+		} else {
+			status = acpi_remove_interface(str);
+
+			if (ACPI_SUCCESS(status))
+				printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
+		}
 	}
+}
+
+static int __init osi_setup(char *str)
+{
+	if (str && !strcmp("Linux", str))
+		acpi_cmdline_osi_linux(1);
+	else if (str && !strcmp("!Linux", str))
+		acpi_cmdline_osi_linux(0);
+	else
+		acpi_osi_setup(str);
 
 	return 1;
 }
 
-__setup("acpi_osi=", acpi_osi_setup);
+__setup("acpi_osi=", osi_setup);
 
 /* enable serialization to combat AE_ALREADY_EXISTS errors */
 static int __init acpi_serialize_setup(char *str)
@@ -1152,21 +1296,6 @@
 }
 EXPORT_SYMBOL(acpi_check_region);
 
-int acpi_check_mem_region(resource_size_t start, resource_size_t n,
-		      const char *name)
-{
-	struct resource res = {
-		.start = start,
-		.end   = start + n - 1,
-		.name  = name,
-		.flags = IORESOURCE_MEM,
-	};
-
-	return acpi_check_resource_conflict(&res);
-
-}
-EXPORT_SYMBOL(acpi_check_mem_region);
-
 /*
  * Let drivers know whether the resource checks are effective
  */
@@ -1282,38 +1411,6 @@
 	return (AE_OK);
 }
 
-/******************************************************************************
- *
- * FUNCTION:    acpi_os_validate_interface
- *
- * PARAMETERS:  interface           - Requested interface to be validated
- *
- * RETURN:      AE_OK if interface is supported, AE_SUPPORT otherwise
- *
- * DESCRIPTION: Match an interface string to the interfaces supported by the
- *              host. Strings originate from an AML call to the _OSI method.
- *
- *****************************************************************************/
-
-acpi_status
-acpi_os_validate_interface (char *interface)
-{
-	if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
-		return AE_OK;
-	if (!strcmp("Linux", interface)) {
-
-		printk(KERN_NOTICE PREFIX
-			"BIOS _OSI(Linux) query %s%s\n",
-			osi_linux.enable ? "honored" : "ignored",
-			osi_linux.cmdline ? " via cmdline" :
-			osi_linux.dmi ? " via DMI" : "");
-
-		if (osi_linux.enable)
-			return AE_OK;
-	}
-	return AE_SUPPORT;
-}
-
 static inline int acpi_res_list_add(struct acpi_res_list *res)
 {
 	struct acpi_res_list *res_list_elem;
@@ -1462,5 +1559,46 @@
 	}
 	return AE_OK;
 }
-
 #endif
+
+acpi_status __init acpi_os_initialize(void)
+{
+	acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+	acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+	acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
+	acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
+
+	return AE_OK;
+}
+
+acpi_status __init acpi_os_initialize1(void)
+{
+	kacpid_wq = create_workqueue("kacpid");
+	kacpi_notify_wq = create_workqueue("kacpi_notify");
+	kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
+	BUG_ON(!kacpid_wq);
+	BUG_ON(!kacpi_notify_wq);
+	BUG_ON(!kacpi_hotplug_wq);
+	acpi_install_interface_handler(acpi_osi_handler);
+	acpi_osi_setup_late();
+	return AE_OK;
+}
+
+acpi_status acpi_os_terminate(void)
+{
+	if (acpi_irq_handler) {
+		acpi_os_remove_interrupt_handler(acpi_irq_irq,
+						 acpi_irq_handler);
+	}
+
+	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block);
+	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);
+	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
+	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
+
+	destroy_workqueue(kacpid_wq);
+	destroy_workqueue(kacpi_notify_wq);
+	destroy_workqueue(kacpi_hotplug_wq);
+
+	return AE_OK;
+}
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/pci_irq.c linux-libre-2.6.37-gnu/drivers/acpi/pci_irq.c
--- linux-libre-2.6.36-gnu/drivers/acpi/pci_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/pci_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/pci_link.c linux-libre-2.6.37-gnu/drivers/acpi/pci_link.c
--- linux-libre-2.6.36-gnu/drivers/acpi/pci_link.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/pci_link.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/pci_root.c linux-libre-2.6.37-gnu/drivers/acpi/pci_root.c
--- linux-libre-2.6.36-gnu/drivers/acpi/pci_root.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/pci_root.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/power.c linux-libre-2.6.37-gnu/drivers/acpi/power.c
--- linux-libre-2.6.36-gnu/drivers/acpi/power.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/power.c	2011-01-04 19:50:19.000000000 -0500
@@ -80,18 +80,13 @@
 		},
 };
 
-struct acpi_power_reference {
-	struct list_head node;
-	struct acpi_device *device;
-};
-
 struct acpi_power_resource {
 	struct acpi_device * device;
 	acpi_bus_id name;
 	u32 system_level;
 	u32 order;
+	unsigned int ref_count;
 	struct mutex resource_lock;
-	struct list_head reference;
 };
 
 static struct list_head acpi_power_resource_list;
@@ -184,101 +179,91 @@
 	return result;
 }
 
-static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
+static int __acpi_power_on(struct acpi_power_resource *resource)
 {
-	int result = 0;
-	int found = 0;
 	acpi_status status = AE_OK;
-	struct acpi_power_resource *resource = NULL;
-	struct list_head *node, *next;
-	struct acpi_power_reference *ref;
 
+	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	/* Update the power resource's _device_ power state */
+	resource->device->power.state = ACPI_STATE_D0;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n",
+			  resource->name));
+
+	return 0;
+}
+
+static int acpi_power_on(acpi_handle handle)
+{
+	int result = 0;
+	struct acpi_power_resource *resource = NULL;
 
 	result = acpi_power_get_context(handle, &resource);
 	if (result)
 		return result;
 
 	mutex_lock(&resource->resource_lock);
-	list_for_each_safe(node, next, &resource->reference) {
-		ref = container_of(node, struct acpi_power_reference, node);
-		if (dev->handle == ref->device->handle) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already referenced by resource [%s]\n",
-				  dev->pnp.bus_id, resource->name));
-			found = 1;
-			break;
-		}
-	}
 
-	if (!found) {
-		ref = kmalloc(sizeof (struct acpi_power_reference),
-		    irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
-		if (!ref) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "kmalloc() failed\n"));
-			mutex_unlock(&resource->resource_lock);
-			return -ENOMEM;
-		}
-		list_add_tail(&ref->node, &resource->reference);
-		ref->device = dev;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] added to resource [%s] references\n",
-			  dev->pnp.bus_id, resource->name));
+	if (resource->ref_count++) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Power resource [%s] already on",
+				  resource->name));
+	} else {
+		result = __acpi_power_on(resource);
+		if (result)
+			resource->ref_count--;
 	}
-	mutex_unlock(&resource->resource_lock);
 
-	status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-
-	/* Update the power resource's _device_ power state */
-	resource->device->power.state = ACPI_STATE_D0;
+	mutex_unlock(&resource->resource_lock);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
-			  resource->name));
-	return 0;
+	return result;
 }
 
-static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
+static int acpi_power_off_device(acpi_handle handle)
 {
 	int result = 0;
 	acpi_status status = AE_OK;
 	struct acpi_power_resource *resource = NULL;
-	struct list_head *node, *next;
-	struct acpi_power_reference *ref;
 
 	result = acpi_power_get_context(handle, &resource);
 	if (result)
 		return result;
 
 	mutex_lock(&resource->resource_lock);
-	list_for_each_safe(node, next, &resource->reference) {
-		ref = container_of(node, struct acpi_power_reference, node);
-		if (dev->handle == ref->device->handle) {
-			list_del(&ref->node);
-			kfree(ref);
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] removed from resource [%s] references\n",
-			    dev->pnp.bus_id, resource->name));
-			break;
-		}
+
+	if (!resource->ref_count) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Power resource [%s] already off",
+				  resource->name));
+		goto unlock;
 	}
 
-	if (!list_empty(&resource->reference)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cannot turn resource [%s] off - resource is in use\n",
-		    resource->name));
-		mutex_unlock(&resource->resource_lock);
-		return 0;
+	if (--resource->ref_count) {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Power resource [%s] still in use\n",
+				  resource->name));
+		goto unlock;
 	}
-	mutex_unlock(&resource->resource_lock);
 
 	status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (ACPI_FAILURE(status)) {
+		result = -ENODEV;
+	} else {
+		/* Update the power resource's _device_ power state */
+		resource->device->power.state = ACPI_STATE_D3;
 
-	/* Update the power resource's _device_ power state */
-	resource->device->power.state = ACPI_STATE_D3;
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Power resource [%s] turned off\n",
+				  resource->name));
+	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
-			  resource->name));
+ unlock:
+	mutex_unlock(&resource->resource_lock);
 
-	return 0;
+	return result;
 }
 
 /**
@@ -364,7 +349,7 @@
 
 	/* Open power resource */
 	for (i = 0; i < dev->wakeup.resources.count; i++) {
-		int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev);
+		int ret = acpi_power_on(dev->wakeup.resources.handles[i]);
 		if (ret) {
 			printk(KERN_ERR PREFIX "Transition power state\n");
 			dev->wakeup.flags.valid = 0;
@@ -420,7 +405,7 @@
 	/* Close power resource */
 	for (i = 0; i < dev->wakeup.resources.count; i++) {
 		int ret = acpi_power_off_device(
-				dev->wakeup.resources.handles[i], dev);
+				dev->wakeup.resources.handles[i]);
 		if (ret) {
 			printk(KERN_ERR PREFIX "Transition power state\n");
 			dev->wakeup.flags.valid = 0;
@@ -482,10 +467,12 @@
 	struct acpi_handle_list *tl = NULL;	/* Target Resources */
 	int i = 0;
 
-
 	if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
 		return -EINVAL;
 
+	if (device->power.state == state)
+		return 0;
+
 	if ((device->power.state < ACPI_STATE_D0)
 	    || (device->power.state > ACPI_STATE_D3))
 		return -ENODEV;
@@ -500,20 +487,16 @@
 	 * (e.g. so the device doesn't lose power while transitioning).
 	 */
 	for (i = 0; i < tl->count; i++) {
-		result = acpi_power_on(tl->handles[i], device);
+		result = acpi_power_on(tl->handles[i]);
 		if (result)
 			goto end;
 	}
 
-	if (device->power.state == state) {
-		goto end;
-	}
-
 	/*
 	 * Then we dereference all power resources used in the current list.
 	 */
 	for (i = 0; i < cl->count; i++) {
-		result = acpi_power_off_device(cl->handles[i], device);
+		result = acpi_power_off_device(cl->handles[i]);
 		if (result)
 			goto end;
 	}
@@ -551,7 +534,6 @@
 
 	resource->device = device;
 	mutex_init(&resource->resource_lock);
-	INIT_LIST_HEAD(&resource->reference);
 	strcpy(resource->name, device->pnp.bus_id);
 	strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
@@ -594,22 +576,14 @@
 
 static int acpi_power_remove(struct acpi_device *device, int type)
 {
-	struct acpi_power_resource *resource = NULL;
-	struct list_head *node, *next;
-
+	struct acpi_power_resource *resource;
 
-	if (!device || !acpi_driver_data(device))
+	if (!device)
 		return -EINVAL;
 
 	resource = acpi_driver_data(device);
-
-	mutex_lock(&resource->resource_lock);
-	list_for_each_safe(node, next, &resource->reference) {
-		struct acpi_power_reference *ref = container_of(node, struct acpi_power_reference, node);
-		list_del(&ref->node);
-		kfree(ref);
-	}
-	mutex_unlock(&resource->resource_lock);
+	if (!resource)
+		return -EINVAL;
 
 	kfree(resource);
 
@@ -619,29 +593,28 @@
 static int acpi_power_resume(struct acpi_device *device)
 {
 	int result = 0, state;
-	struct acpi_power_resource *resource = NULL;
-	struct acpi_power_reference *ref;
+	struct acpi_power_resource *resource;
 
-	if (!device || !acpi_driver_data(device))
+	if (!device)
 		return -EINVAL;
 
 	resource = acpi_driver_data(device);
+	if (!resource)
+		return -EINVAL;
+
+	mutex_lock(&resource->resource_lock);
 
 	result = acpi_power_get_state(device->handle, &state);
 	if (result)
-		return result;
+		goto unlock;
 
-	mutex_lock(&resource->resource_lock);
-	if (state == ACPI_POWER_RESOURCE_STATE_OFF &&
-	    !list_empty(&resource->reference)) {
-		ref = container_of(resource->reference.next, struct acpi_power_reference, node);
-		mutex_unlock(&resource->resource_lock);
-		result = acpi_power_on(device->handle, ref->device);
-		return result;
-	}
+	if (state == ACPI_POWER_RESOURCE_STATE_OFF && resource->ref_count)
+		result = __acpi_power_on(resource);
 
+ unlock:
 	mutex_unlock(&resource->resource_lock);
-	return 0;
+
+	return result;
 }
 
 int __init acpi_power_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/processor_driver.c linux-libre-2.6.37-gnu/drivers/acpi/processor_driver.c
--- linux-libre-2.6.36-gnu/drivers/acpi/processor_driver.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/processor_driver.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,8 +40,10 @@
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
+#ifdef CONFIG_ACPI_PROCFS
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#endif
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/cpuidle.h>
@@ -244,6 +246,7 @@
 	return result;
 }
 
+#ifdef CONFIG_ACPI_PROCFS
 static struct proc_dir_entry *acpi_processor_dir = NULL;
 
 static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
@@ -280,7 +283,16 @@
 
 	return 0;
 }
-
+#else
+static inline int acpi_processor_add_fs(struct acpi_device *device)
+{
+	return 0;
+}
+static inline int acpi_processor_remove_fs(struct acpi_device *device)
+{
+	return 0;
+}
+#endif
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -842,9 +854,11 @@
 
 	memset(&errata, 0, sizeof(errata));
 
+#ifdef CONFIG_ACPI_PROCFS
 	acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
 	if (!acpi_processor_dir)
 		return -ENOMEM;
+#endif
 
 	if (!cpuidle_register_driver(&acpi_idle_driver)) {
 		printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
@@ -871,7 +885,9 @@
 out_cpuidle:
 	cpuidle_unregister_driver(&acpi_idle_driver);
 
+#ifdef CONFIG_ACPI_PROCFS
 	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
 
 	return result;
 }
@@ -891,7 +907,9 @@
 
 	cpuidle_unregister_driver(&acpi_idle_driver);
 
+#ifdef CONFIG_ACPI_PROCFS
 	remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+#endif
 
 	return;
 }
@@ -899,6 +917,4 @@
 module_init(acpi_processor_init);
 module_exit(acpi_processor_exit);
 
-EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
-
 MODULE_ALIAS("processor");
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/processor_idle.c linux-libre-2.6.37-gnu/drivers/acpi/processor_idle.c
--- linux-libre-2.6.36-gnu/drivers/acpi/processor_idle.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/processor_idle.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,7 +64,6 @@
 #define ACPI_PROCESSOR_CLASS            "processor"
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_idle");
-#define ACPI_PROCESSOR_FILE_POWER	"power"
 #define PM_TIMER_TICK_NS		(1000000000ULL/PM_TIMER_FREQUENCY)
 #define C2_OVERHEAD			1	/* 1us */
 #define C3_OVERHEAD			1	/* 1us */
@@ -1013,7 +1012,6 @@
 		strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
 		state->exit_latency = cx->latency;
 		state->target_residency = cx->latency * latency_factor;
-		state->power_usage = cx->power;
 
 		state->flags = 0;
 		switch (cx->type) {
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/processor_thermal.c linux-libre-2.6.37-gnu/drivers/acpi/processor_thermal.c
--- linux-libre-2.6.36-gnu/drivers/acpi/processor_thermal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/processor_thermal.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,47 +44,6 @@
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_thermal");
 
-/* --------------------------------------------------------------------------
-                                 Limit Interface
-   -------------------------------------------------------------------------- */
-static int acpi_processor_apply_limit(struct acpi_processor *pr)
-{
-	int result = 0;
-	u16 px = 0;
-	u16 tx = 0;
-
-
-	if (!pr)
-		return -EINVAL;
-
-	if (!pr->flags.limit)
-		return -ENODEV;
-
-	if (pr->flags.throttling) {
-		if (pr->limit.user.tx > tx)
-			tx = pr->limit.user.tx;
-		if (pr->limit.thermal.tx > tx)
-			tx = pr->limit.thermal.tx;
-
-		result = acpi_processor_set_throttling(pr, tx, false);
-		if (result)
-			goto end;
-	}
-
-	pr->limit.state.px = px;
-	pr->limit.state.tx = tx;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Processor [%d] limit set to (P%d:T%d)\n", pr->id,
-			  pr->limit.state.px, pr->limit.state.tx));
-
-      end:
-	if (result)
-		printk(KERN_ERR PREFIX "Unable to set limit\n");
-
-	return result;
-}
-
 #ifdef CONFIG_CPU_FREQ
 
 /* If a passive cooling situation is detected, primarily CPUfreq is used, as it
@@ -107,36 +66,6 @@
 	return 1;
 }
 
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
-	if (!cpu_has_cpufreq(cpu))
-		return -ENODEV;
-
-	if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) <
-		CPUFREQ_THERMAL_MAX_STEP) {
-		per_cpu(cpufreq_thermal_reduction_pctg, cpu)++;
-		cpufreq_update_policy(cpu);
-		return 0;
-	}
-
-	return -ERANGE;
-}
-
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
-	if (!cpu_has_cpufreq(cpu))
-		return -ENODEV;
-
-	if (per_cpu(cpufreq_thermal_reduction_pctg, cpu) >
-		(CPUFREQ_THERMAL_MIN_STEP + 1))
-		per_cpu(cpufreq_thermal_reduction_pctg, cpu)--;
-	else
-		per_cpu(cpufreq_thermal_reduction_pctg, cpu) = 0;
-	cpufreq_update_policy(cpu);
-	/* We reached max freq again and can leave passive mode */
-	return !per_cpu(cpufreq_thermal_reduction_pctg, cpu);
-}
-
 static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
 					 unsigned long event, void *data)
 {
@@ -227,124 +156,8 @@
 	return 0;
 }
 
-static int acpi_thermal_cpufreq_increase(unsigned int cpu)
-{
-	return -ENODEV;
-}
-static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
-{
-	return -ENODEV;
-}
-
 #endif
 
-int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
-{
-	int result = 0;
-	struct acpi_processor *pr = NULL;
-	struct acpi_device *device = NULL;
-	int tx = 0, max_tx_px = 0;
-
-
-	if ((type < ACPI_PROCESSOR_LIMIT_NONE)
-	    || (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
-		return -EINVAL;
-
-	result = acpi_bus_get_device(handle, &device);
-	if (result)
-		return result;
-
-	pr = acpi_driver_data(device);
-	if (!pr)
-		return -ENODEV;
-
-	/* Thermal limits are always relative to the current Px/Tx state. */
-	if (pr->flags.throttling)
-		pr->limit.thermal.tx = pr->throttling.state;
-
-	/*
-	 * Our default policy is to only use throttling at the lowest
-	 * performance state.
-	 */
-
-	tx = pr->limit.thermal.tx;
-
-	switch (type) {
-
-	case ACPI_PROCESSOR_LIMIT_NONE:
-		do {
-			result = acpi_thermal_cpufreq_decrease(pr->id);
-		} while (!result);
-		tx = 0;
-		break;
-
-	case ACPI_PROCESSOR_LIMIT_INCREMENT:
-		/* if going up: P-states first, T-states later */
-
-		result = acpi_thermal_cpufreq_increase(pr->id);
-		if (!result)
-			goto end;
-		else if (result == -ERANGE)
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "At maximum performance state\n"));
-
-		if (pr->flags.throttling) {
-			if (tx == (pr->throttling.state_count - 1))
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-						  "At maximum throttling state\n"));
-			else
-				tx++;
-		}
-		break;
-
-	case ACPI_PROCESSOR_LIMIT_DECREMENT:
-		/* if going down: T-states first, P-states later */
-
-		if (pr->flags.throttling) {
-			if (tx == 0) {
-				max_tx_px = 1;
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-						  "At minimum throttling state\n"));
-			} else {
-				tx--;
-				goto end;
-			}
-		}
-
-		result = acpi_thermal_cpufreq_decrease(pr->id);
-		if (result) {
-			/*
-			 * We only could get -ERANGE, 1 or 0.
-			 * In the first two cases we reached max freq again.
-			 */
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "At minimum performance state\n"));
-			max_tx_px = 1;
-		} else
-			max_tx_px = 0;
-
-		break;
-	}
-
-      end:
-	if (pr->flags.throttling) {
-		pr->limit.thermal.px = 0;
-		pr->limit.thermal.tx = tx;
-
-		result = acpi_processor_apply_limit(pr);
-		if (result)
-			printk(KERN_ERR PREFIX "Unable to set thermal limit\n");
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
-				  pr->limit.thermal.px, pr->limit.thermal.tx));
-	} else
-		result = 0;
-	if (max_tx_px)
-		return 1;
-	else
-		return result;
-}
-
 int acpi_processor_get_limit_info(struct acpi_processor *pr)
 {
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/processor_throttling.c linux-libre-2.6.37-gnu/drivers/acpi/processor_throttling.c
--- linux-libre-2.6.36-gnu/drivers/acpi/processor_throttling.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/processor_throttling.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,8 +32,10 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/cpufreq.h>
+#ifdef CONFIG_ACPI_PROCFS
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#endif
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -1214,6 +1216,7 @@
 	return result;
 }
 
+#ifdef CONFIG_ACPI_PROCFS
 /* proc interface */
 static int acpi_processor_throttling_seq_show(struct seq_file *seq,
 					      void *offset)
@@ -1322,3 +1325,4 @@
 	.llseek = seq_lseek,
 	.release = single_release,
 };
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/sbs.c linux-libre-2.6.37-gnu/drivers/acpi/sbs.c
--- linux-libre-2.6.36-gnu/drivers/acpi/sbs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/sbs.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,10 +40,7 @@
 #include <linux/timer.h>
 #include <linux/jiffies.h>
 #include <linux/delay.h>
-
-#ifdef CONFIG_ACPI_SYSFS_POWER
 #include <linux/power_supply.h>
-#endif
 
 #include "sbshc.h"
 
@@ -85,9 +82,7 @@
 MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
 
 struct acpi_battery {
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	struct power_supply bat;
-#endif
 	struct acpi_sbs *sbs;
 #ifdef CONFIG_ACPI_PROCFS_POWER
 	struct proc_dir_entry *proc_entry;
@@ -120,9 +115,7 @@
 #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
 
 struct acpi_sbs {
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	struct power_supply charger;
-#endif
 	struct acpi_device *device;
 	struct acpi_smb_hc *hc;
 	struct mutex lock;
@@ -166,7 +159,6 @@
 	    acpi_battery_ipscale(battery);
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static int sbs_get_ac_property(struct power_supply *psy,
 			       enum power_supply_property psp,
 			       union power_supply_propval *val)
@@ -313,7 +305,6 @@
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
-#endif
 
 /* --------------------------------------------------------------------------
                             Smart Battery System Management
@@ -449,7 +440,6 @@
 	return result;
 }
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 static ssize_t acpi_battery_alarm_show(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
@@ -479,7 +469,6 @@
 	.show = acpi_battery_alarm_show,
 	.store = acpi_battery_alarm_store,
 };
-#endif
 
 /* --------------------------------------------------------------------------
                               FS Interface (/proc/acpi)
@@ -798,7 +787,6 @@
 			&acpi_battery_state_fops, &acpi_battery_alarm_fops,
 			battery);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	battery->bat.name = battery->name;
 	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
 	if (!acpi_battery_mode(battery)) {
@@ -819,7 +807,6 @@
 		goto end;
 	battery->have_sysfs_alarm = 1;
       end:
-#endif
 	printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
 	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
 	       battery->name, battery->present ? "present" : "absent");
@@ -828,17 +815,13 @@
 
 static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
 {
-#if defined(CONFIG_ACPI_SYSFS_POWER) || defined(CONFIG_ACPI_PROCFS_POWER)
 	struct acpi_battery *battery = &sbs->battery[id];
-#endif
 
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (battery->bat.dev) {
 		if (battery->have_sysfs_alarm)
 			device_remove_file(battery->bat.dev, &alarm_attr);
 		power_supply_unregister(&battery->bat);
 	}
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
 	if (battery->proc_entry)
 		acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
@@ -859,14 +842,12 @@
 	if (result)
 		goto end;
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	sbs->charger.name = "sbs-charger";
 	sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
 	sbs->charger.properties = sbs_ac_props;
 	sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
 	sbs->charger.get_property = sbs_get_ac_property;
 	power_supply_register(&sbs->device->dev, &sbs->charger);
-#endif
 	printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
 	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
 	       ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
@@ -876,10 +857,8 @@
 
 static void acpi_charger_remove(struct acpi_sbs *sbs)
 {
-#ifdef CONFIG_ACPI_SYSFS_POWER
 	if (sbs->charger.dev)
 		power_supply_unregister(&sbs->charger);
-#endif
 #ifdef CONFIG_ACPI_PROCFS_POWER
 	if (sbs->charger_entry)
 		acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
@@ -900,9 +879,7 @@
 					      ACPI_SBS_NOTIFY_STATUS,
 					      sbs->charger_present);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 		kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
-#endif
 	}
 	if (sbs->manager_present) {
 		for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -919,9 +896,7 @@
 						      ACPI_SBS_NOTIFY_STATUS,
 						      bat->present);
 #endif
-#ifdef CONFIG_ACPI_SYSFS_POWER
 			kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
-#endif
 		}
 	}
 }
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/scan.c linux-libre-2.6.37-gnu/drivers/acpi/scan.c
--- linux-libre-2.6.36-gnu/drivers/acpi/scan.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/scan.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,6 +26,8 @@
 
 #define ACPI_IS_ROOT_DEVICE(device)    (!(device)->parent)
 
+static const char *dummy_hid = "device";
+
 static LIST_HEAD(acpi_device_list);
 static LIST_HEAD(acpi_bus_id_list);
 DEFINE_MUTEX(acpi_device_lock);
@@ -49,6 +51,9 @@
 	int count;
 	struct acpi_hardware_id *id;
 
+	if (list_empty(&acpi_dev->pnp.ids))
+		return 0;
+
 	len = snprintf(modalias, size, "acpi:");
 	size -= len;
 
@@ -202,13 +207,15 @@
 			goto end;
 	}
 
-	result = device_create_file(&dev->dev, &dev_attr_hid);
-	if (result)
-		goto end;
+	if (!list_empty(&dev->pnp.ids)) {
+		result = device_create_file(&dev->dev, &dev_attr_hid);
+		if (result)
+			goto end;
 
-	result = device_create_file(&dev->dev, &dev_attr_modalias);
-	if (result)
-		goto end;
+		result = device_create_file(&dev->dev, &dev_attr_modalias);
+		if (result)
+			goto end;
+	}
 
         /*
          * If device has _EJ0, 'eject' file is created that is used to trigger
@@ -316,6 +323,9 @@
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	int len;
 
+	if (list_empty(&acpi_dev->pnp.ids))
+		return 0;
+
 	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
 	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
@@ -695,54 +705,85 @@
 }
 
 static acpi_status
-acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
-					     union acpi_object *package)
+acpi_bus_extract_wakeup_device_power_package(acpi_handle handle,
+					     struct acpi_device_wakeup *wakeup)
 {
-	int i = 0;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *package = NULL;
 	union acpi_object *element = NULL;
+	acpi_status status;
+	int i = 0;
 
-	if (!device || !package || (package->package.count < 2))
+	if (!wakeup)
 		return AE_BAD_PARAMETER;
 
+	/* _PRW */
+	status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
+		return status;
+	}
+
+	package = (union acpi_object *)buffer.pointer;
+
+	if (!package || (package->package.count < 2)) {
+		status = AE_BAD_DATA;
+		goto out;
+	}
+
 	element = &(package->package.elements[0]);
-	if (!element)
-		return AE_BAD_PARAMETER;
+	if (!element) {
+		status = AE_BAD_DATA;
+		goto out;
+	}
 	if (element->type == ACPI_TYPE_PACKAGE) {
 		if ((element->package.count < 2) ||
 		    (element->package.elements[0].type !=
 		     ACPI_TYPE_LOCAL_REFERENCE)
-		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER))
-			return AE_BAD_DATA;
-		device->wakeup.gpe_device =
+		    || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) {
+			status = AE_BAD_DATA;
+			goto out;
+		}
+		wakeup->gpe_device =
 		    element->package.elements[0].reference.handle;
-		device->wakeup.gpe_number =
+		wakeup->gpe_number =
 		    (u32) element->package.elements[1].integer.value;
 	} else if (element->type == ACPI_TYPE_INTEGER) {
-		device->wakeup.gpe_number = element->integer.value;
-	} else
-		return AE_BAD_DATA;
+		wakeup->gpe_device = NULL;
+		wakeup->gpe_number = element->integer.value;
+	} else {
+		status = AE_BAD_DATA;
+		goto out;
+	}
 
 	element = &(package->package.elements[1]);
 	if (element->type != ACPI_TYPE_INTEGER) {
-		return AE_BAD_DATA;
+		status = AE_BAD_DATA;
+		goto out;
 	}
-	device->wakeup.sleep_state = element->integer.value;
+	wakeup->sleep_state = element->integer.value;
 
 	if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
-		return AE_NO_MEMORY;
+		status = AE_NO_MEMORY;
+		goto out;
 	}
-	device->wakeup.resources.count = package->package.count - 2;
-	for (i = 0; i < device->wakeup.resources.count; i++) {
+	wakeup->resources.count = package->package.count - 2;
+	for (i = 0; i < wakeup->resources.count; i++) {
 		element = &(package->package.elements[i + 2]);
-		if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
-			return AE_BAD_DATA;
+		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
+			status = AE_BAD_DATA;
+			goto out;
+		}
 
-		device->wakeup.resources.handles[i] = element->reference.handle;
+		wakeup->resources.handles[i] = element->reference.handle;
 	}
 
-	acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number);
+	acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number);
 
-	return AE_OK;
+ out:
+	kfree(buffer.pointer);
+
+	return status;
 }
 
 static void acpi_bus_set_run_wake_flags(struct acpi_device *device)
@@ -777,26 +818,15 @@
 static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 {
 	acpi_status status = 0;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *package = NULL;
 	int psw_error;
 
-	/* _PRW */
-	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
-		goto end;
-	}
-
-	package = (union acpi_object *)buffer.pointer;
-	status = acpi_bus_extract_wakeup_device_power_package(device, package);
+	status = acpi_bus_extract_wakeup_device_power_package(device->handle,
+							      &device->wakeup);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
 		goto end;
 	}
 
-	kfree(buffer.pointer);
-
 	device->wakeup.flags.valid = 1;
 	device->wakeup.prepare_count = 0;
 	acpi_bus_set_run_wake_flags(device);
@@ -1010,10 +1040,13 @@
 	return acpi_get_handle(device->handle, "_DCK", &tmp);
 }
 
-char *acpi_device_hid(struct acpi_device *device)
+const char *acpi_device_hid(struct acpi_device *device)
 {
 	struct acpi_hardware_id *hid;
 
+	if (list_empty(&device->pnp.ids))
+		return dummy_hid;
+
 	hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list);
 	return hid->id;
 }
@@ -1142,16 +1175,6 @@
 		acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
 		break;
 	}
-
-	/*
-	 * We build acpi_devices for some objects that don't have _HID or _CID,
-	 * e.g., PCI bridges and slots.  Drivers can't bind to these objects,
-	 * but we do use them indirectly by traversing the acpi_device tree.
-	 * This generic ID isn't useful for driver binding, but it provides
-	 * the useful property that "every acpi_device has an ID."
-	 */
-	if (list_empty(&device->pnp.ids))
-		acpi_add_id(device, "device");
 }
 
 static int acpi_device_set_context(struct acpi_device *device)
@@ -1348,6 +1371,7 @@
 	struct acpi_bus_ops *ops = context;
 	int type;
 	unsigned long long sta;
+	struct acpi_device_wakeup wakeup;
 	struct acpi_device *device;
 	acpi_status status;
 	int result;
@@ -1357,8 +1381,10 @@
 		return AE_OK;
 
 	if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
-	    !(sta & ACPI_STA_DEVICE_FUNCTIONING))
+	    !(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
+		acpi_bus_extract_wakeup_device_power_package(handle, &wakeup);
 		return AE_CTRL_DEPTH;
+	}
 
 	/*
 	 * We may already have an acpi_device from a previous enumeration.  If
@@ -1431,6 +1457,7 @@
 int acpi_bus_start(struct acpi_device *device)
 {
 	struct acpi_bus_ops ops;
+	int result;
 
 	if (!device)
 		return -EINVAL;
@@ -1438,7 +1465,11 @@
 	memset(&ops, 0, sizeof(ops));
 	ops.acpi_op_start = 1;
 
-	return acpi_bus_scan(device->handle, &ops, NULL);
+	result = acpi_bus_scan(device->handle, &ops, NULL);
+
+	acpi_update_gpes();
+
+	return result;
 }
 EXPORT_SYMBOL(acpi_bus_start);
 
@@ -1552,6 +1583,8 @@
 
 	if (result)
 		acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+	else
+		acpi_update_gpes();
 
 	return result;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/sleep.c linux-libre-2.6.37-gnu/drivers/acpi/sleep.c
--- linux-libre-2.6.36-gnu/drivers/acpi/sleep.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/sleep.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 #include "internal.h"
 #include "sleep.h"
 
-u8 sleep_states[ACPI_S_STATE_COUNT];
+static u8 sleep_states[ACPI_S_STATE_COUNT];
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
@@ -419,6 +419,22 @@
 		DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
 		},
 	},
+	{
+	.callback = init_nvs_nosave,
+	.ident = "Sony Vaio VPCEB1Z1E",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
+		},
+	},
+	{
+	.callback = init_nvs_nosave,
+	.ident = "Sony Vaio VGN-NW130D",
+	.matches = {
+		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+		DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
+		},
+	},
 	{},
 };
 #endif /* CONFIG_SUSPEND */
@@ -562,7 +578,7 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
 /**
  *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
  *		in the system sleep state given by %acpi_target_sleep_state
@@ -624,7 +640,7 @@
 	 * can wake the system.  _S0W may be valid, too.
 	 */
 	if (acpi_target_sleep_state == ACPI_STATE_S0 ||
-	    (device_may_wakeup(dev) && adev->wakeup.state.enabled &&
+	    (device_may_wakeup(dev) &&
 	     adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
 		acpi_status status;
 
@@ -632,7 +648,9 @@
 		status = acpi_evaluate_integer(handle, acpi_method, NULL,
 						&d_max);
 		if (ACPI_FAILURE(status)) {
-			d_max = d_min;
+			if (acpi_target_sleep_state != ACPI_STATE_S0 ||
+			    status != AE_NOT_FOUND)
+				d_max = d_min;
 		} else if (d_max < d_min) {
 			/* Warn the user of the broken DSDT */
 			printk(KERN_WARNING "ACPI: Wrong value from %s\n",
@@ -646,7 +664,9 @@
 		*d_min_p = d_min;
 	return d_max;
 }
+#endif /* CONFIG_PM_OPS */
 
+#ifdef CONFIG_PM_SLEEP
 /**
  *	acpi_pm_device_sleep_wake - enable or disable the system wake-up
  *                                  capability of given device
@@ -677,7 +697,7 @@
 
 	return error;
 }
-#endif
+#endif  /* CONFIG_PM_SLEEP */
 
 static void acpi_power_off_prepare(void)
 {
@@ -702,7 +722,7 @@
  * paths through the BIOS, so disable _GTS and _BFS by default,
  * but do speak up and offer the option to enable them.
  */
-void __init acpi_gts_bfs_check(void)
+static void __init acpi_gts_bfs_check(void)
 {
 	acpi_handle dummy;
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/sleep.h linux-libre-2.6.37-gnu/drivers/acpi/sleep.h
--- linux-libre-2.6.36-gnu/drivers/acpi/sleep.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/sleep.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,4 @@
 
-extern u8 sleep_states[];
 extern int acpi_suspend(u32 state);
 
 extern void acpi_enable_wakeup_devices(u8 sleep_state);
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/thermal.c linux-libre-2.6.37-gnu/drivers/acpi/thermal.c
--- linux-libre-2.6.36-gnu/drivers/acpi/thermal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/thermal.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,12 +37,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
-
-#ifdef CONFIG_ACPI_PROCFS
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#endif
-
 #include <linux/jiffies.h>
 #include <linux/kmod.h>
 #include <linux/reboot.h>
@@ -195,61 +189,6 @@
 	struct mutex lock;
 };
 
-#ifdef CONFIG_ACPI_PROCFS
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_cooling_mode(struct file *,
-					       const char __user *, size_t,
-					       loff_t *);
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
-					  size_t, loff_t *);
-
-static const struct file_operations acpi_thermal_state_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_thermal_state_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations acpi_thermal_temp_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_thermal_temp_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations acpi_thermal_trip_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_thermal_trip_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations acpi_thermal_cooling_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_thermal_cooling_open_fs,
-	.read = seq_read,
-	.write = acpi_thermal_write_cooling_mode,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static const struct file_operations acpi_thermal_polling_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_thermal_polling_open_fs,
-	.read = seq_read,
-	.write = acpi_thermal_write_polling,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS*/
-
 /* --------------------------------------------------------------------------
                              Thermal Zone Management
    -------------------------------------------------------------------------- */
@@ -958,358 +897,6 @@
 
 
 /* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-static struct proc_dir_entry *acpi_thermal_dir;
-
-static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_thermal *tz = seq->private;
-
-
-	if (!tz)
-		goto end;
-
-	seq_puts(seq, "state:                   ");
-
-	if (!tz->state.critical && !tz->state.hot && !tz->state.passive
-	    && !tz->state.active)
-		seq_puts(seq, "ok\n");
-	else {
-		if (tz->state.critical)
-			seq_puts(seq, "critical ");
-		if (tz->state.hot)
-			seq_puts(seq, "hot ");
-		if (tz->state.passive)
-			seq_puts(seq, "passive ");
-		if (tz->state.active)
-			seq_printf(seq, "active[%d]", tz->state.active_index);
-		seq_puts(seq, "\n");
-	}
-
-      end:
-	return 0;
-}
-
-static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
-{
-	int result = 0;
-	struct acpi_thermal *tz = seq->private;
-
-
-	if (!tz)
-		goto end;
-
-	result = acpi_thermal_get_temperature(tz);
-	if (result)
-		goto end;
-
-	seq_printf(seq, "temperature:             %ld C\n",
-		   KELVIN_TO_CELSIUS(tz->temperature));
-
-      end:
-	return 0;
-}
-
-static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_thermal *tz = seq->private;
-	struct acpi_device *device;
-	acpi_status status;
-
-	int i = 0;
-	int j = 0;
-
-
-	if (!tz)
-		goto end;
-
-	if (tz->trips.critical.flags.valid)
-		seq_printf(seq, "critical (S5):           %ld C%s",
-			   KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
-			   nocrt ? " <disabled>\n" : "\n");
-
-	if (tz->trips.hot.flags.valid)
-		seq_printf(seq, "hot (S4):                %ld C%s",
-			   KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
-			   nocrt ? " <disabled>\n" : "\n");
-
-	if (tz->trips.passive.flags.valid) {
-		seq_printf(seq,
-			   "passive:                 %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
-			   KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
-			   tz->trips.passive.tc1, tz->trips.passive.tc2,
-			   tz->trips.passive.tsp);
-		for (j = 0; j < tz->trips.passive.devices.count; j++) {
-			status = acpi_bus_get_device(tz->trips.passive.devices.
-						     handles[j], &device);
-			seq_printf(seq, "%4.4s ", status ? "" :
-				   acpi_device_bid(device));
-		}
-		seq_puts(seq, "\n");
-	} else {
-		seq_printf(seq, "passive (forced):");
-		if (tz->thermal_zone->forced_passive)
-			seq_printf(seq, "        %i C\n",
-				   tz->thermal_zone->forced_passive / 1000);
-		else
-			seq_printf(seq, "<not set>\n");
-	}
-
-	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-		if (!(tz->trips.active[i].flags.valid))
-			break;
-		seq_printf(seq, "active[%d]:               %ld C: devices=",
-			   i,
-			   KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
-		for (j = 0; j < tz->trips.active[i].devices.count; j++){
-			status = acpi_bus_get_device(tz->trips.active[i].
-						     devices.handles[j],
-						     &device);
-			seq_printf(seq, "%4.4s ", status ? "" :
-				   acpi_device_bid(device));
-		}
-		seq_puts(seq, "\n");
-	}
-
-      end:
-	return 0;
-}
-
-static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
-}
-
-static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_thermal *tz = seq->private;
-
-
-	if (!tz)
-		goto end;
-
-	if (!tz->flags.cooling_mode)
-		seq_puts(seq, "<setting not supported>\n");
-	else
-		seq_puts(seq, "0 - Active; 1 - Passive\n");
-
-      end:
-	return 0;
-}
-
-static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_thermal_cooling_seq_show,
-			   PDE(inode)->data);
-}
-
-static ssize_t
-acpi_thermal_write_cooling_mode(struct file *file,
-				const char __user * buffer,
-				size_t count, loff_t * ppos)
-{
-	struct seq_file *m = file->private_data;
-	struct acpi_thermal *tz = m->private;
-	int result = 0;
-	char mode_string[12] = { '\0' };
-
-
-	if (!tz || (count > sizeof(mode_string) - 1))
-		return -EINVAL;
-
-	if (!tz->flags.cooling_mode)
-		return -ENODEV;
-
-	if (copy_from_user(mode_string, buffer, count))
-		return -EFAULT;
-
-	mode_string[count] = '\0';
-
-	result = acpi_thermal_set_cooling_mode(tz,
-					       simple_strtoul(mode_string, NULL,
-							      0));
-	if (result)
-		return result;
-
-	acpi_thermal_check(tz);
-
-	return count;
-}
-
-static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_thermal *tz = seq->private;
-
-
-	if (!tz)
-		goto end;
-
-	if (!tz->thermal_zone->polling_delay) {
-		seq_puts(seq, "<polling disabled>\n");
-		goto end;
-	}
-
-	seq_printf(seq, "polling frequency:       %d seconds\n",
-		   (tz->thermal_zone->polling_delay / 1000));
-
-      end:
-	return 0;
-}
-
-static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_thermal_polling_seq_show,
-			   PDE(inode)->data);
-}
-
-static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
-{
-	if (!tz)
-		return -EINVAL;
-
-	/* Convert value to deci-seconds */
-	tz->polling_frequency = seconds * 10;
-
-	tz->thermal_zone->polling_delay = seconds * 1000;
-
-	if (tz->tz_enabled)
-		thermal_zone_device_update(tz->thermal_zone);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-			  "Polling frequency set to %lu seconds\n",
-			  tz->polling_frequency/10));
-
-	return 0;
-}
-
-static ssize_t
-acpi_thermal_write_polling(struct file *file,
-			   const char __user * buffer,
-			   size_t count, loff_t * ppos)
-{
-	struct seq_file *m = file->private_data;
-	struct acpi_thermal *tz = m->private;
-	int result = 0;
-	char polling_string[12] = { '\0' };
-	int seconds = 0;
-
-
-	if (!tz || (count > sizeof(polling_string) - 1))
-		return -EINVAL;
-
-	if (copy_from_user(polling_string, buffer, count))
-		return -EFAULT;
-
-	polling_string[count] = '\0';
-
-	seconds = simple_strtoul(polling_string, NULL, 0);
-
-	result = acpi_thermal_set_polling(tz, seconds);
-	if (result)
-		return result;
-
-	acpi_thermal_check(tz);
-
-	return count;
-}
-
-static int acpi_thermal_add_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *entry = NULL;
-
-
-	if (!acpi_device_dir(device)) {
-		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
-						     acpi_thermal_dir);
-		if (!acpi_device_dir(device))
-			return -ENODEV;
-	}
-
-	/* 'state' [R] */
-	entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
-				 S_IRUGO, acpi_device_dir(device),
-				 &acpi_thermal_state_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-
-	/* 'temperature' [R] */
-	entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
-				 S_IRUGO, acpi_device_dir(device),
-				 &acpi_thermal_temp_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-
-	/* 'trip_points' [R] */
-	entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
-				 S_IRUGO,
-				 acpi_device_dir(device),
-				 &acpi_thermal_trip_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-
-	/* 'cooling_mode' [R/W] */
-	entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
-				 S_IFREG | S_IRUGO | S_IWUSR,
-				 acpi_device_dir(device),
-				 &acpi_thermal_cooling_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-
-	/* 'polling_frequency' [R/W] */
-	entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
-				 S_IFREG | S_IRUGO | S_IWUSR,
-				 acpi_device_dir(device),
-				 &acpi_thermal_polling_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		return -ENODEV;
-	return 0;
-}
-
-static int acpi_thermal_remove_fs(struct acpi_device *device)
-{
-
-	if (acpi_device_dir(device)) {
-		remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_THERMAL_FILE_STATE,
-				  acpi_device_dir(device));
-		remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
-		acpi_device_dir(device) = NULL;
-	}
-
-	return 0;
-}
-#else
-static inline int acpi_thermal_add_fs(struct acpi_device *device) { return 0; }
-static inline int acpi_thermal_remove_fs(struct acpi_device *device)
-{
-	return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
-/* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
@@ -1428,17 +1015,11 @@
 	if (result)
 		goto free_memory;
 
-	result = acpi_thermal_add_fs(device);
-	if (result)
-		goto unregister_thermal_zone;
-
 	printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
 	       acpi_device_name(device), acpi_device_bid(device),
 	       KELVIN_TO_CELSIUS(tz->temperature));
 	goto end;
 
-unregister_thermal_zone:
-	thermal_zone_device_unregister(tz->thermal_zone);
 free_memory:
 	kfree(tz);
 end:
@@ -1454,7 +1035,6 @@
 
 	tz = acpi_driver_data(device);
 
-	acpi_thermal_remove_fs(device);
 	acpi_thermal_unregister_thermal_zone(tz);
 	mutex_destroy(&tz->lock);
 	kfree(tz);
@@ -1580,19 +1160,9 @@
 		return -ENODEV;
 	}
 
-#ifdef CONFIG_ACPI_PROCFS
-	acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
-	if (!acpi_thermal_dir)
-		return -ENODEV;
-#endif
-
 	result = acpi_bus_register_driver(&acpi_thermal_driver);
-	if (result < 0) {
-#ifdef CONFIG_ACPI_PROCFS
-		remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
+	if (result < 0)
 		return -ENODEV;
-	}
 
 	return 0;
 }
@@ -1602,10 +1172,6 @@
 
 	acpi_bus_unregister_driver(&acpi_thermal_driver);
 
-#ifdef CONFIG_ACPI_PROCFS
-	remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
-#endif
-
 	return;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/acpi/video.c linux-libre-2.6.37-gnu/drivers/acpi/video.c
--- linux-libre-2.6.36-gnu/drivers/acpi/video.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/acpi/video.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,6 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/input.h>
 #include <linux/backlight.h>
 #include <linux/thermal.h>
@@ -152,9 +150,6 @@
 	struct acpi_video_bus_flags flags;
 	struct list_head video_device_list;
 	struct mutex device_list_lock;	/* protects video_device_list */
-#ifdef CONFIG_ACPI_PROCFS
-	struct proc_dir_entry *dir;
-#endif
 	struct input_dev *input;
 	char phys[32];	/* for input device */
 	struct notifier_block pm_nb;
@@ -210,108 +205,6 @@
 	struct output_device *output_dev;
 };
 
-#ifdef CONFIG_ACPI_PROCFS
-/* bus */
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_info_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_bus_info_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
-static const struct file_operations acpi_video_bus_ROM_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_bus_ROM_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
-					    struct file *file);
-static const struct file_operations acpi_video_bus_POST_info_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_bus_POST_info_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_POST(struct file *file,
-	const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_POST_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_bus_POST_open_fs,
-	.read = seq_read,
-	.write = acpi_video_bus_write_POST,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_video_bus_write_DOS(struct file *file,
-	const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_bus_DOS_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_bus_DOS_open_fs,
-	.read = seq_read,
-	.write = acpi_video_bus_write_DOS,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-/* device */
-static int acpi_video_device_info_open_fs(struct inode *inode,
-					  struct file *file);
-static const struct file_operations acpi_video_device_info_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_device_info_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_device_state_open_fs(struct inode *inode,
-					   struct file *file);
-static ssize_t acpi_video_device_write_state(struct file *file,
-	const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_state_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_device_state_open_fs,
-	.read = seq_read,
-	.write = acpi_video_device_write_state,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_device_brightness_open_fs(struct inode *inode,
-						struct file *file);
-static ssize_t acpi_video_device_write_brightness(struct file *file,
-	const char __user *buffer, size_t count, loff_t *data);
-static const struct file_operations acpi_video_device_brightness_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_device_brightness_open_fs,
-	.read = seq_read,
-	.write = acpi_video_device_write_brightness,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-
-static int acpi_video_device_EDID_open_fs(struct inode *inode,
-					  struct file *file);
-static const struct file_operations acpi_video_device_EDID_fops = {
-	.owner = THIS_MODULE,
-	.open = acpi_video_device_EDID_open_fs,
-	.read = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
-};
-#endif /* CONFIG_ACPI_PROCFS */
-
 static const char device_decode[][30] = {
 	"motherboard VGA device",
 	"PCI VGA device",
@@ -1111,646 +1004,6 @@
 }
 
 /* --------------------------------------------------------------------------
-                              FS Interface (/proc)
-   -------------------------------------------------------------------------- */
-#ifdef CONFIG_ACPI_PROCFS
-
-static struct proc_dir_entry *acpi_video_dir;
-
-/* video devices */
-
-static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_device *dev = seq->private;
-
-
-	if (!dev)
-		goto end;
-
-	seq_printf(seq, "device_id:    0x%04x\n", (u32) dev->device_id);
-	seq_printf(seq, "type:         ");
-	if (dev->flags.crt)
-		seq_printf(seq, "CRT\n");
-	else if (dev->flags.lcd)
-		seq_printf(seq, "LCD\n");
-	else if (dev->flags.tvout)
-		seq_printf(seq, "TVOUT\n");
-	else if (dev->flags.dvi)
-		seq_printf(seq, "DVI\n");
-	else
-		seq_printf(seq, "UNKNOWN\n");
-
-	seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
-
-      end:
-	return 0;
-}
-
-static int
-acpi_video_device_info_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_device_info_seq_show,
-			   PDE(inode)->data);
-}
-
-static int
-acpi_video_device_query(struct acpi_video_device *device,
-			unsigned long long *state)
-{
-	int status;
-
-	status = acpi_evaluate_integer(device->dev->handle, "_DGS",
-				       NULL, state);
-
-	return status;
-}
-
-static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
-{
-	int status;
-	struct acpi_video_device *dev = seq->private;
-	unsigned long long state;
-
-
-	if (!dev)
-		goto end;
-
-	status = acpi_video_device_get_state(dev, &state);
-	seq_printf(seq, "state:     ");
-	if (ACPI_SUCCESS(status))
-		seq_printf(seq, "0x%02llx\n", state);
-	else
-		seq_printf(seq, "<not supported>\n");
-
-	status = acpi_video_device_query(dev, &state);
-	seq_printf(seq, "query:     ");
-	if (ACPI_SUCCESS(status))
-		seq_printf(seq, "0x%02llx\n", state);
-	else
-		seq_printf(seq, "<not supported>\n");
-
-      end:
-	return 0;
-}
-
-static int
-acpi_video_device_state_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_device_state_seq_show,
-			   PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_state(struct file *file,
-			      const char __user * buffer,
-			      size_t count, loff_t * data)
-{
-	int status;
-	struct seq_file *m = file->private_data;
-	struct acpi_video_device *dev = m->private;
-	char str[12] = { 0 };
-	u32 state = 0;
-
-
-	if (!dev || count >= sizeof(str))
-		return -EINVAL;
-
-	if (copy_from_user(str, buffer, count))
-		return -EFAULT;
-
-	str[count] = 0;
-	state = simple_strtoul(str, NULL, 0);
-	state &= ((1ul << 31) | (1ul << 30) | (1ul << 0));
-
-	status = acpi_video_device_set_state(dev, state);
-
-	if (status)
-		return -EFAULT;
-
-	return count;
-}
-
-static int
-acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_device *dev = seq->private;
-	int i;
-
-
-	if (!dev || !dev->brightness) {
-		seq_printf(seq, "<not supported>\n");
-		return 0;
-	}
-
-	seq_printf(seq, "levels: ");
-	for (i = 2; i < dev->brightness->count; i++)
-		seq_printf(seq, " %d", dev->brightness->levels[i]);
-	seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
-
-	return 0;
-}
-
-static int
-acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_device_brightness_seq_show,
-			   PDE(inode)->data);
-}
-
-static ssize_t
-acpi_video_device_write_brightness(struct file *file,
-				   const char __user * buffer,
-				   size_t count, loff_t * data)
-{
-	struct seq_file *m = file->private_data;
-	struct acpi_video_device *dev = m->private;
-	char str[5] = { 0 };
-	unsigned int level = 0;
-	int i;
-
-
-	if (!dev || !dev->brightness || count >= sizeof(str))
-		return -EINVAL;
-
-	if (copy_from_user(str, buffer, count))
-		return -EFAULT;
-
-	str[count] = 0;
-	level = simple_strtoul(str, NULL, 0);
-
-	if (level > 100)
-		return -EFAULT;
-
-	/* validate through the list of available levels */
-	for (i = 2; i < dev->brightness->count; i++)
-		if (level == dev->brightness->levels[i]) {
-			if (!acpi_video_device_lcd_set_level(dev, level))
-				return count;
-			break;
-		}
-
-	return -EINVAL;
-}
-
-static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_device *dev = seq->private;
-	int status;
-	int i;
-	union acpi_object *edid = NULL;
-
-
-	if (!dev)
-		goto out;
-
-	status = acpi_video_device_EDID(dev, &edid, 128);
-	if (ACPI_FAILURE(status)) {
-		status = acpi_video_device_EDID(dev, &edid, 256);
-	}
-
-	if (ACPI_FAILURE(status)) {
-		goto out;
-	}
-
-	if (edid && edid->type == ACPI_TYPE_BUFFER) {
-		for (i = 0; i < edid->buffer.length; i++)
-			seq_putc(seq, edid->buffer.pointer[i]);
-	}
-
-      out:
-	if (!edid)
-		seq_printf(seq, "<not supported>\n");
-	else
-		kfree(edid);
-
-	return 0;
-}
-
-static int
-acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_device_EDID_seq_show,
-			   PDE(inode)->data);
-}
-
-static int acpi_video_device_add_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *entry, *device_dir;
-	struct acpi_video_device *vid_dev;
-
-	vid_dev = acpi_driver_data(device);
-	if (!vid_dev)
-		return -ENODEV;
-
-	device_dir = proc_mkdir(acpi_device_bid(device),
-				vid_dev->video->dir);
-	if (!device_dir)
-		return -ENOMEM;
-
-	/* 'info' [R] */
-	entry = proc_create_data("info", S_IRUGO, device_dir,
-			&acpi_video_device_info_fops, acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_dir;
-
-	/* 'state' [R/W] */
-	entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
-				 device_dir,
-				 &acpi_video_device_state_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_info;
-
-	/* 'brightness' [R/W] */
-	entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
-				 device_dir,
-				 &acpi_video_device_brightness_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_state;
-
-	/* 'EDID' [R] */
-	entry = proc_create_data("EDID", S_IRUGO, device_dir,
-				 &acpi_video_device_EDID_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_brightness;
-
-	acpi_device_dir(device) = device_dir;
-
-	return 0;
-
- err_remove_brightness:
-	remove_proc_entry("brightness", device_dir);
- err_remove_state:
-	remove_proc_entry("state", device_dir);
- err_remove_info:
-	remove_proc_entry("info", device_dir);
- err_remove_dir:
-	remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
-	return -ENOMEM;
-}
-
-static int acpi_video_device_remove_fs(struct acpi_device *device)
-{
-	struct acpi_video_device *vid_dev;
-	struct proc_dir_entry *device_dir;
-
-	vid_dev = acpi_driver_data(device);
-	if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
-		return -ENODEV;
-
-	device_dir = acpi_device_dir(device);
-	if (device_dir) {
-		remove_proc_entry("info", device_dir);
-		remove_proc_entry("state", device_dir);
-		remove_proc_entry("brightness", device_dir);
-		remove_proc_entry("EDID", device_dir);
-		remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
-		acpi_device_dir(device) = NULL;
-	}
-
-	return 0;
-}
-
-/* video bus */
-static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_bus *video = seq->private;
-
-
-	if (!video)
-		goto end;
-
-	seq_printf(seq, "Switching heads:              %s\n",
-		   video->flags.multihead ? "yes" : "no");
-	seq_printf(seq, "Video ROM:                    %s\n",
-		   video->flags.rom ? "yes" : "no");
-	seq_printf(seq, "Device to be POSTed on boot:  %s\n",
-		   video->flags.post ? "yes" : "no");
-
-      end:
-	return 0;
-}
-
-static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_bus_info_seq_show,
-			   PDE(inode)->data);
-}
-
-static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_bus *video = seq->private;
-
-
-	if (!video)
-		goto end;
-
-	printk(KERN_INFO PREFIX "Please implement %s\n", __func__);
-	seq_printf(seq, "<TODO>\n");
-
-      end:
-	return 0;
-}
-
-static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_POST_options(struct acpi_video_bus *video,
-			    unsigned long long *options)
-{
-	int status;
-
-	status = acpi_evaluate_integer(video->device->handle, "_VPO",
-				       NULL, options);
-	*options &= 3;
-
-	return status;
-}
-
-static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_bus *video = seq->private;
-	unsigned long long options;
-	int status;
-
-
-	if (!video)
-		goto end;
-
-	status = acpi_video_bus_POST_options(video, &options);
-	if (ACPI_SUCCESS(status)) {
-		if (!(options & 1)) {
-			printk(KERN_WARNING PREFIX
-			       "The motherboard VGA device is not listed as a possible POST device.\n");
-			printk(KERN_WARNING PREFIX
-			       "This indicates a BIOS bug. Please contact the manufacturer.\n");
-		}
-		printk(KERN_WARNING "%llx\n", options);
-		seq_printf(seq, "can POST: <integrated video>");
-		if (options & 2)
-			seq_printf(seq, " <PCI video>");
-		if (options & 4)
-			seq_printf(seq, " <AGP video>");
-		seq_putc(seq, '\n');
-	} else
-		seq_printf(seq, "<not supported>\n");
-      end:
-	return 0;
-}
-
-static int
-acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_bus_POST_info_seq_show,
-			   PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
-{
-	int status;
-
-	status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
-
-	return status;
-}
-
-static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_bus *video = seq->private;
-	int status;
-	unsigned long long id;
-
-
-	if (!video)
-		goto end;
-
-	status = acpi_video_bus_get_POST(video, &id);
-	if (!ACPI_SUCCESS(status)) {
-		seq_printf(seq, "<not supported>\n");
-		goto end;
-	}
-	seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]);
-
-      end:
-	return 0;
-}
-
-static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
-{
-	struct acpi_video_bus *video = seq->private;
-
-
-	seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
-
-	return 0;
-}
-
-static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_bus_POST_seq_show,
-			   PDE(inode)->data);
-}
-
-static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
-{
-	int status;
-	unsigned long long tmp;
-	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
-	struct acpi_object_list args = { 1, &arg0 };
-
-
-	arg0.integer.value = option;
-
-	status = acpi_evaluate_integer(video->device->handle, "_SPD",
-				       &args, &tmp);
-	if (ACPI_SUCCESS(status))
-		status = tmp ? (-EINVAL) : (AE_OK);
-
-	return status;
-}
-
-static ssize_t
-acpi_video_bus_write_POST(struct file *file,
-			  const char __user * buffer,
-			  size_t count, loff_t * data)
-{
-	int status;
-	struct seq_file *m = file->private_data;
-	struct acpi_video_bus *video = m->private;
-	char str[12] = { 0 };
-	unsigned long long opt, options;
-
-
-	if (!video || count >= sizeof(str))
-		return -EINVAL;
-
-	status = acpi_video_bus_POST_options(video, &options);
-	if (!ACPI_SUCCESS(status))
-		return -EINVAL;
-
-	if (copy_from_user(str, buffer, count))
-		return -EFAULT;
-
-	str[count] = 0;
-	opt = strtoul(str, NULL, 0);
-	if (opt > 3)
-		return -EFAULT;
-
-	/* just in case an OEM 'forgot' the motherboard... */
-	options |= 1;
-
-	if (options & (1ul << opt)) {
-		status = acpi_video_bus_set_POST(video, opt);
-		if (!ACPI_SUCCESS(status))
-			return -EFAULT;
-
-	}
-
-	return count;
-}
-
-static ssize_t
-acpi_video_bus_write_DOS(struct file *file,
-			 const char __user * buffer,
-			 size_t count, loff_t * data)
-{
-	int status;
-	struct seq_file *m = file->private_data;
-	struct acpi_video_bus *video = m->private;
-	char str[12] = { 0 };
-	unsigned long opt;
-
-
-	if (!video || count >= sizeof(str))
-		return -EINVAL;
-
-	if (copy_from_user(str, buffer, count))
-		return -EFAULT;
-
-	str[count] = 0;
-	opt = strtoul(str, NULL, 0);
-	if (opt > 7)
-		return -EFAULT;
-
-	status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
-
-	if (!ACPI_SUCCESS(status))
-		return -EFAULT;
-
-	return count;
-}
-
-static int acpi_video_bus_add_fs(struct acpi_device *device)
-{
-	struct acpi_video_bus *video = acpi_driver_data(device);
-	struct proc_dir_entry *device_dir;
-	struct proc_dir_entry *entry;
-
-	device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
-	if (!device_dir)
-		return -ENOMEM;
-
-	/* 'info' [R] */
-	entry = proc_create_data("info", S_IRUGO, device_dir,
-				 &acpi_video_bus_info_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_dir;
-
-	/* 'ROM' [R] */
-	entry = proc_create_data("ROM", S_IRUGO, device_dir,
-				 &acpi_video_bus_ROM_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_info;
-
-	/* 'POST_info' [R] */
-	entry = proc_create_data("POST_info", S_IRUGO, device_dir,
-				 &acpi_video_bus_POST_info_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_rom;
-
-	/* 'POST' [R/W] */
-	entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
-				 device_dir,
-				 &acpi_video_bus_POST_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_post_info;
-
-	/* 'DOS' [R/W] */
-	entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
-				 device_dir,
-				 &acpi_video_bus_DOS_fops,
-				 acpi_driver_data(device));
-	if (!entry)
-		goto err_remove_post;
-
-	video->dir = acpi_device_dir(device) = device_dir;
-	return 0;
-
- err_remove_post:
-	remove_proc_entry("POST", device_dir);
- err_remove_post_info:
-	remove_proc_entry("POST_info", device_dir);
- err_remove_rom:
-	remove_proc_entry("ROM", device_dir);
- err_remove_info:
-	remove_proc_entry("info", device_dir);
- err_remove_dir:
-	remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
-	return -ENOMEM;
-}
-
-static int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
-	struct proc_dir_entry *device_dir = acpi_device_dir(device);
-
-	if (device_dir) {
-		remove_proc_entry("info", device_dir);
-		remove_proc_entry("ROM", device_dir);
-		remove_proc_entry("POST_info", device_dir);
-		remove_proc_entry("POST", device_dir);
-		remove_proc_entry("DOS", device_dir);
-		remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
-		acpi_device_dir(device) = NULL;
-	}
-
-	return 0;
-}
-#else
-static inline int acpi_video_device_add_fs(struct acpi_device *device)
-{
-	return 0;
-}
-static inline int acpi_video_device_remove_fs(struct acpi_device *device)
-{
-	return 0;
-}
-static inline int acpi_video_bus_add_fs(struct acpi_device *device)
-{
-	return 0;
-}
-static inline int acpi_video_bus_remove_fs(struct acpi_device *device)
-{
-	return 0;
-}
-#endif /* CONFIG_ACPI_PROCFS */
-
-/* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
@@ -1877,8 +1130,6 @@
 		list_add_tail(&data->entry, &video->video_device_list);
 		mutex_unlock(&video->device_list_lock);
 
-		acpi_video_device_add_fs(device);
-
 		return 0;
 	}
 
@@ -2181,8 +1432,6 @@
 	if (!device || !device->video)
 		return -ENOENT;
 
-	acpi_video_device_remove_fs(device->dev);
-
 	status = acpi_remove_notify_handler(device->dev->handle,
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
@@ -2466,10 +1715,6 @@
 	if (error)
 		goto err_free_video;
 
-	error = acpi_video_bus_add_fs(device);
-	if (error)
-		goto err_free_video;
-
 	mutex_init(&video->device_list_lock);
 	INIT_LIST_HEAD(&video->video_device_list);
 
@@ -2522,7 +1767,6 @@
 	acpi_video_bus_stop_devices(video);
 	acpi_video_bus_put_devices(video);
 	kfree(video->attached_array);
-	acpi_video_bus_remove_fs(device);
  err_free_video:
 	kfree(video);
 	device->driver_data = NULL;
@@ -2544,7 +1788,6 @@
 
 	acpi_video_bus_stop_devices(video);
 	acpi_video_bus_put_devices(video);
-	acpi_video_bus_remove_fs(device);
 
 	input_unregister_device(video->input);
 	kfree(video->attached_array);
@@ -2584,17 +1827,9 @@
 		return 0;
 	}
 
-#ifdef CONFIG_ACPI_PROCFS
-	acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
-	if (!acpi_video_dir)
-		return -ENODEV;
-#endif
-
 	result = acpi_bus_register_driver(&acpi_video_bus);
-	if (result < 0) {
-		remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+	if (result < 0)
 		return -ENODEV;
-	}
 
 	/*
 	 * When the acpi_video_bus is loaded successfully, increase
@@ -2617,10 +1852,6 @@
 	}
 	acpi_bus_unregister_driver(&acpi_video_bus);
 
-#ifdef CONFIG_ACPI_PROCFS
-	remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
-#endif
-
 	register_count = 0;
 
 	return;
diff -druN linux-libre-2.6.36-gnu/drivers/amba/bus.c linux-libre-2.6.37-gnu/drivers/amba/bus.c
--- linux-libre-2.6.36-gnu/drivers/amba/bus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/amba/bus.c	2011-01-04 19:50:19.000000000 -0500
@@ -298,7 +298,7 @@
 
 		amba_put_disable_pclk(dev);
 
-		if (cid == 0xb105f00d)
+		if (cid == AMBA_CID)
 			dev->periphid = pid;
 
 		if (!dev->periphid)
diff -druN linux-libre-2.6.36-gnu/drivers/ata/ahci.c linux-libre-2.6.37-gnu/drivers/ata/ahci.c
--- linux-libre-2.6.36-gnu/drivers/ata/ahci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/ahci.c	2011-01-04 19:50:19.000000000 -0500
@@ -1208,9 +1208,6 @@
 		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
 				   0x100 + ap->port_no * 0x80, "port");
 
-		/* set initial link pm policy */
-		ap->pm_policy = NOT_AVAILABLE;
-
 		/* set enclosure management message type */
 		if (ap->flags & ATA_FLAG_EM)
 			ap->em_message_type = hpriv->em_msg_type;
diff -druN linux-libre-2.6.36-gnu/drivers/ata/ahci.h linux-libre-2.6.37-gnu/drivers/ata/ahci.h
--- linux-libre-2.6.36-gnu/drivers/ata/ahci.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/ahci.h	2011-01-04 19:50:19.000000000 -0500
@@ -72,6 +72,7 @@
 	AHCI_CMD_RESET		= (1 << 8),
 	AHCI_CMD_CLR_BUSY	= (1 << 10),
 
+	RX_FIS_PIO_SETUP	= 0x20,	/* offset of PIO Setup FIS data */
 	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
 	RX_FIS_SDB		= 0x58, /* offset of SDB FIS data */
 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
@@ -201,7 +202,6 @@
 	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
 	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
 	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
-	AHCI_HFLAG_NO_HOTPLUG		= (1 << 7), /* ignore PxSERR.DIAG.N */
 	AHCI_HFLAG_SECT255		= (1 << 8), /* max 255 sectors */
 	AHCI_HFLAG_YES_NCQ		= (1 << 9), /* force NCQ cap on */
 	AHCI_HFLAG_NO_SUSPEND		= (1 << 10), /* don't suspend */
@@ -216,7 +216,7 @@
 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
 					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
-					  ATA_FLAG_IPM,
+					  ATA_FLAG_LPM,
 
 	ICH_MAP				= 0x90, /* ICH MAP register */
 
diff -druN linux-libre-2.6.36-gnu/drivers/ata/ahci_platform.c linux-libre-2.6.37-gnu/drivers/ata/ahci_platform.c
--- linux-libre-2.6.36-gnu/drivers/ata/ahci_platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/ahci_platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -129,9 +129,6 @@
 		ata_port_desc(ap, "mmio %pR", mem);
 		ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
 
-		/* set initial link pm policy */
-		ap->pm_policy = NOT_AVAILABLE;
-
 		/* set enclosure management message type */
 		if (ap->flags & ATA_FLAG_EM)
 			ap->em_message_type = hpriv->em_msg_type;
diff -druN linux-libre-2.6.36-gnu/drivers/ata/ata_generic.c linux-libre-2.6.37-gnu/drivers/ata/ata_generic.c
--- linux-libre-2.6.36-gnu/drivers/ata/ata_generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/ata_generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,7 @@
 enum {
 	ATA_GEN_CLASS_MATCH		= (1 << 0),
 	ATA_GEN_FORCE_DMA		= (1 << 1),
+	ATA_GEN_INTEL_IDER		= (1 << 2),
 };
 
 /**
@@ -109,6 +110,49 @@
 static int all_generic_ide;		/* Set to claim all devices */
 
 /**
+ *	is_intel_ider		-	identify intel IDE-R devices
+ *	@dev: PCI device
+ *
+ *	Distinguish Intel IDE-R controller devices from other Intel IDE
+ *	devices. IDE-R devices have no timing registers and are in
+ *	most respects virtual. They should be driven by the ata_generic
+ *	driver.
+ *
+ *	IDE-R devices have PCI offset 0xF8.L as zero, later Intel ATA has
+ *	it non zero. All Intel ATA has 0x40 writable (timing), but it is
+ *	not writable on IDE-R devices (this is guaranteed).
+ */
+
+static int is_intel_ider(struct pci_dev *dev)
+{
+	/* For Intel IDE the value at 0xF8 is only zero on IDE-R
+	   interfaces */
+	u32 r;
+	u16 t;
+
+	/* Check the manufacturing ID, it will be zero for IDE-R */
+	pci_read_config_dword(dev, 0xF8, &r);
+	/* Not IDE-R: punt so that ata_(old)piix gets it */
+	if (r != 0)
+		return 0;
+	/* 0xF8 will also be zero on some early Intel IDE devices
+	   but they will have a sane timing register */
+	pci_read_config_word(dev, 0x40, &t);
+	if (t != 0)
+		return 0;
+	/* Finally check if the timing register is writable so that
+	   we eliminate any early devices hot-docked in a docking
+	   station */
+	pci_write_config_word(dev, 0x40, 1);
+	pci_read_config_word(dev, 0x40, &t);
+	if (t) {
+		pci_write_config_word(dev, 0x40, 0);
+		return 0;
+	}
+	return 1;
+}
+
+/**
  *	ata_generic_init		-	attach generic IDE
  *	@dev: PCI device found
  *	@id: match entry
@@ -134,6 +178,10 @@
 	if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
 		return -ENODEV;
 
+	if (id->driver_data & ATA_GEN_INTEL_IDER)
+		if (!is_intel_ider(dev))
+			return -ENODEV;
+
 	/* Devices that need care */
 	if (dev->vendor == PCI_VENDOR_ID_UMC &&
 	    dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
@@ -186,7 +234,11 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),  },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),  },
-#endif	
+#endif
+	/* Intel, IDE class device */
+	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 
+	  .driver_data = ATA_GEN_INTEL_IDER },
 	/* Must come last. If you add entries adjust this table appropriately */
 	{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL),
 	  .driver_data = ATA_GEN_CLASS_MATCH },
diff -druN linux-libre-2.6.36-gnu/drivers/ata/ata_piix.c linux-libre-2.6.37-gnu/drivers/ata/ata_piix.c
--- linux-libre-2.6.36-gnu/drivers/ata/ata_piix.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/ata_piix.c	2011-01-04 19:50:19.000000000 -0500
@@ -158,7 +158,6 @@
 struct piix_host_priv {
 	const int *map;
 	u32 saved_iocfg;
-	spinlock_t sidpr_lock;	/* FIXME: remove once locking in EH is fixed */
 	void __iomem *sidpr;
 };
 
@@ -175,6 +174,8 @@
 			       unsigned int reg, u32 *val);
 static int piix_sidpr_scr_write(struct ata_link *link,
 				unsigned int reg, u32 val);
+static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			      unsigned hints);
 static bool piix_irq_check(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
@@ -209,6 +210,8 @@
 	{ 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* Intel ICH3 (E7500/1) UDMA 100 */
 	{ 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+	/* Intel ICH4-L */
+	{ 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
 	{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -348,11 +351,22 @@
 	.set_dmamode		= ich_set_dmamode,
 };
 
+static struct device_attribute *piix_sidpr_shost_attrs[] = {
+	&dev_attr_link_power_management_policy,
+	NULL
+};
+
+static struct scsi_host_template piix_sidpr_sht = {
+	ATA_BMDMA_SHT(DRV_NAME),
+	.shost_attrs		= piix_sidpr_shost_attrs,
+};
+
 static struct ata_port_operations piix_sidpr_sata_ops = {
 	.inherits		= &piix_sata_ops,
 	.hardreset		= sata_std_hardreset,
 	.scr_read		= piix_sidpr_scr_read,
 	.scr_write		= piix_sidpr_scr_write,
+	.set_lpm		= piix_sidpr_set_lpm,
 };
 
 static const struct piix_map_db ich5_map_db = {
@@ -956,15 +970,12 @@
 			       unsigned int reg, u32 *val)
 {
 	struct piix_host_priv *hpriv = link->ap->host->private_data;
-	unsigned long flags;
 
 	if (reg >= ARRAY_SIZE(piix_sidx_map))
 		return -EINVAL;
 
-	spin_lock_irqsave(&hpriv->sidpr_lock, flags);
 	piix_sidpr_sel(link, reg);
 	*val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
-	spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
 	return 0;
 }
 
@@ -972,18 +983,21 @@
 				unsigned int reg, u32 val)
 {
 	struct piix_host_priv *hpriv = link->ap->host->private_data;
-	unsigned long flags;
 
 	if (reg >= ARRAY_SIZE(piix_sidx_map))
 		return -EINVAL;
 
-	spin_lock_irqsave(&hpriv->sidpr_lock, flags);
 	piix_sidpr_sel(link, reg);
 	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
-	spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
 	return 0;
 }
 
+static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			      unsigned hints)
+{
+	return sata_link_scr_lpm(link, policy, false);
+}
+
 static bool piix_irq_check(struct ata_port *ap)
 {
 	if (unlikely(!ap->ioaddr.bmdma_addr))
@@ -1543,6 +1557,7 @@
 	struct device *dev = &pdev->dev;
 	struct ata_port_info port_info[2];
 	const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
+	struct scsi_host_template *sht = &piix_sht;
 	unsigned long port_flags;
 	struct ata_host *host;
 	struct piix_host_priv *hpriv;
@@ -1577,7 +1592,6 @@
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
-	spin_lock_init(&hpriv->sidpr_lock);
 
 	/* Save IOCFG, this will be used for cable detection, quirk
 	 * detection and restoration on detach.  This is necessary
@@ -1612,6 +1626,8 @@
 		rc = piix_init_sidpr(host);
 		if (rc)
 			return rc;
+		if (host->ports[0]->ops == &piix_sidpr_sata_ops)
+			sht = &piix_sidpr_sht;
 	}
 
 	/* apply IOCFG bit18 quirk */
@@ -1638,7 +1654,7 @@
 	host->flags |= ATA_HOST_PARALLEL_SCAN;
 
 	pci_set_master(pdev);
-	return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht);
+	return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
 }
 
 static void piix_remove_one(struct pci_dev *pdev)
diff -druN linux-libre-2.6.36-gnu/drivers/ata/Kconfig linux-libre-2.6.37-gnu/drivers/ata/Kconfig
--- linux-libre-2.6.36-gnu/drivers/ata/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -128,16 +128,6 @@
 
 	  If unsure, say N.
 
-config PATA_MPC52xx
-	tristate "Freescale MPC52xx SoC internal IDE"
-	depends on PPC_MPC52xx && PPC_BESTCOMM
-	select PPC_BESTCOMM_ATA
-	help
-	  This option enables support for integrated IDE controller
-	  of the Freescale MPC52xx SoC.
-
-	  If unsure, say N.
-
 config PATA_OCTEON_CF
 	tristate "OCTEON Boot Bus Compact Flash support"
 	depends on CPU_CAVIUM_OCTEON
@@ -366,7 +356,7 @@
 
 config PATA_CS5536
 	tristate "CS5536 PATA support"
-	depends on PCI && X86 && !X86_64
+	depends on PCI
 	help
 	  This option enables support for the AMD CS5536
 	  companion chip used with the Geode LX processor family.
@@ -491,6 +481,16 @@
 
 	  If unsure, say N.
 
+config PATA_MPC52xx
+	tristate "Freescale MPC52xx SoC internal IDE"
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select PPC_BESTCOMM_ATA
+	help
+	  This option enables support for integrated IDE controller
+	  of the Freescale MPC52xx SoC.
+
+	  If unsure, say N.
+
 config PATA_NETCELL
 	tristate "NETCELL Revolution RAID support"
 	depends on PCI
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libahci.c linux-libre-2.6.37-gnu/drivers/ata/libahci.c
--- linux-libre-2.6.36-gnu/drivers/ata/libahci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libahci.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,9 +56,8 @@
 module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
 MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
 
-static int ahci_enable_alpm(struct ata_port *ap,
-		enum link_pm policy);
-static void ahci_disable_alpm(struct ata_port *ap);
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			unsigned hints);
 static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
 static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
 			      size_t size);
@@ -164,8 +163,7 @@
 	.pmp_attach		= ahci_pmp_attach,
 	.pmp_detach		= ahci_pmp_detach,
 
-	.enable_pm		= ahci_enable_alpm,
-	.disable_pm		= ahci_disable_alpm,
+	.set_lpm		= ahci_set_lpm,
 	.em_show		= ahci_led_show,
 	.em_store		= ahci_led_store,
 	.sw_activity_show	= ahci_activity_show,
@@ -569,7 +567,7 @@
 	writel(tmp, port_mmio + PORT_CMD);
 
 	/* wait for engine to stop. This could be as long as 500 msec */
-	tmp = ata_wait_register(port_mmio + PORT_CMD,
+	tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
 				PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
 	if (tmp & PORT_CMD_LIST_ON)
 		return -EIO;
@@ -616,7 +614,7 @@
 	writel(tmp, port_mmio + PORT_CMD);
 
 	/* wait for completion, spec says 500ms, give it 1000 */
-	tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+	tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
 				PORT_CMD_FIS_ON, 10, 1000);
 	if (tmp & PORT_CMD_FIS_ON)
 		return -EBUSY;
@@ -642,127 +640,56 @@
 	writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
 }
 
-static void ahci_disable_alpm(struct ata_port *ap)
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			unsigned int hints)
 {
+	struct ata_port *ap = link->ap;
 	struct ahci_host_priv *hpriv = ap->host->private_data;
-	void __iomem *port_mmio = ahci_port_base(ap);
-	u32 cmd;
 	struct ahci_port_priv *pp = ap->private_data;
-
-	/* IPM bits should be disabled by libata-core */
-	/* get the existing command bits */
-	cmd = readl(port_mmio + PORT_CMD);
-
-	/* disable ALPM and ASP */
-	cmd &= ~PORT_CMD_ASP;
-	cmd &= ~PORT_CMD_ALPE;
-
-	/* force the interface back to active */
-	cmd |= PORT_CMD_ICC_ACTIVE;
-
-	/* write out new cmd value */
-	writel(cmd, port_mmio + PORT_CMD);
-	cmd = readl(port_mmio + PORT_CMD);
-
-	/* wait 10ms to be sure we've come out of any low power state */
-	msleep(10);
-
-	/* clear out any PhyRdy stuff from interrupt status */
-	writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
-
-	/* go ahead and clean out PhyRdy Change from Serror too */
-	ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
-
-	/*
-	 * Clear flag to indicate that we should ignore all PhyRdy
-	 * state changes
-	 */
-	hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
-
-	/*
-	 * Enable interrupts on Phy Ready.
-	 */
-	pp->intr_mask |= PORT_IRQ_PHYRDY;
-	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
-	/*
-	 * don't change the link pm policy - we can be called
-	 * just to turn of link pm temporarily
-	 */
-}
-
-static int ahci_enable_alpm(struct ata_port *ap,
-	enum link_pm policy)
-{
-	struct ahci_host_priv *hpriv = ap->host->private_data;
 	void __iomem *port_mmio = ahci_port_base(ap);
-	u32 cmd;
-	struct ahci_port_priv *pp = ap->private_data;
-	u32 asp;
-
-	/* Make sure the host is capable of link power management */
-	if (!(hpriv->cap & HOST_CAP_ALPM))
-		return -EINVAL;
 
-	switch (policy) {
-	case MAX_PERFORMANCE:
-	case NOT_AVAILABLE:
+	if (policy != ATA_LPM_MAX_POWER) {
 		/*
-		 * if we came here with NOT_AVAILABLE,
-		 * it just means this is the first time we
-		 * have tried to enable - default to max performance,
-		 * and let the user go to lower power modes on request.
+		 * Disable interrupts on Phy Ready. This keeps us from
+		 * getting woken up due to spurious phy ready
+		 * interrupts.
 		 */
-		ahci_disable_alpm(ap);
-		return 0;
-	case MIN_POWER:
-		/* configure HBA to enter SLUMBER */
-		asp = PORT_CMD_ASP;
-		break;
-	case MEDIUM_POWER:
-		/* configure HBA to enter PARTIAL */
-		asp = 0;
-		break;
-	default:
-		return -EINVAL;
+		pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+		sata_link_scr_lpm(link, policy, false);
 	}
 
-	/*
-	 * Disable interrupts on Phy Ready. This keeps us from
-	 * getting woken up due to spurious phy ready interrupts
-	 * TBD - Hot plug should be done via polling now, is
-	 * that even supported?
-	 */
-	pp->intr_mask &= ~PORT_IRQ_PHYRDY;
-	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+	if (hpriv->cap & HOST_CAP_ALPM) {
+		u32 cmd = readl(port_mmio + PORT_CMD);
 
-	/*
-	 * Set a flag to indicate that we should ignore all PhyRdy
-	 * state changes since these can happen now whenever we
-	 * change link state
-	 */
-	hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
+		if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
+			cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
+			cmd |= PORT_CMD_ICC_ACTIVE;
 
-	/* get the existing command bits */
-	cmd = readl(port_mmio + PORT_CMD);
+			writel(cmd, port_mmio + PORT_CMD);
+			readl(port_mmio + PORT_CMD);
 
-	/*
-	 * Set ASP based on Policy
-	 */
-	cmd |= asp;
+			/* wait 10ms to be sure we've come out of LPM state */
+			ata_msleep(ap, 10);
+		} else {
+			cmd |= PORT_CMD_ALPE;
+			if (policy == ATA_LPM_MIN_POWER)
+				cmd |= PORT_CMD_ASP;
 
-	/*
-	 * Setting this bit will instruct the HBA to aggressively
-	 * enter a lower power link state when it's appropriate and
-	 * based on the value set above for ASP
-	 */
-	cmd |= PORT_CMD_ALPE;
+			/* write out new cmd value */
+			writel(cmd, port_mmio + PORT_CMD);
+		}
+	}
 
-	/* write out new cmd value */
-	writel(cmd, port_mmio + PORT_CMD);
-	cmd = readl(port_mmio + PORT_CMD);
+	if (policy == ATA_LPM_MAX_POWER) {
+		sata_link_scr_lpm(link, policy, false);
+
+		/* turn PHYRDY IRQ back on */
+		pp->intr_mask |= PORT_IRQ_PHYRDY;
+		writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+	}
 
-	/* IPM bits should be set by libata-core */
 	return 0;
 }
 
@@ -813,7 +740,7 @@
 							       emp->led_state,
 							       4);
 				if (rc == -EBUSY)
-					msleep(1);
+					ata_msleep(ap, 1);
 				else
 					break;
 			}
@@ -872,7 +799,7 @@
 		 * reset must complete within 1 second, or
 		 * the hardware should be considered fried.
 		 */
-		tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
+		tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
 					HOST_RESET, 10, 1000);
 
 		if (tmp & HOST_RESET) {
@@ -1252,7 +1179,7 @@
 	writel(tmp, port_mmio + PORT_CMD);
 
 	rc = 0;
-	tmp = ata_wait_register(port_mmio + PORT_CMD,
+	tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
 	if (tmp & PORT_CMD_CLO)
 		rc = -EIO;
@@ -1282,8 +1209,8 @@
 	writel(1, port_mmio + PORT_CMD_ISSUE);
 
 	if (timeout_msec) {
-		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
-					1, timeout_msec);
+		tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
+					0x1, 0x1, 1, timeout_msec);
 		if (tmp & 0x1) {
 			ahci_kick_engine(ap);
 			return -EBUSY;
@@ -1330,7 +1257,7 @@
 	}
 
 	/* spec says at least 5us, but be generous and sleep for 1ms */
-	msleep(1);
+	ata_msleep(ap, 1);
 
 	/* issue the second D2H Register FIS */
 	tf.ctl &= ~ATA_SRST;
@@ -1660,15 +1587,10 @@
 	if (unlikely(resetting))
 		status &= ~PORT_IRQ_BAD_PMP;
 
-	/* If we are getting PhyRdy, this is
-	 * just a power state change, we should
-	 * clear out this, plus the PhyRdy/Comm
-	 * Wake bits from Serror
-	 */
-	if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
-		(status & PORT_IRQ_PHYRDY)) {
+	/* if LPM is enabled, PHYRDY doesn't mean anything */
+	if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
 		status &= ~PORT_IRQ_PHYRDY;
-		ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
+		ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
 	}
 
 	if (unlikely(status & PORT_IRQ_ERROR)) {
@@ -1830,12 +1752,24 @@
 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
 {
 	struct ahci_port_priv *pp = qc->ap->private_data;
-	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+	u8 *rx_fis = pp->rx_fis;
 
 	if (pp->fbs_enabled)
-		d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+		rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
+	/*
+	 * After a successful execution of an ATA PIO data-in command,
+	 * the device doesn't send D2H Reg FIS to update the TF and
+	 * the host should take TF and E_Status from the preceding PIO
+	 * Setup FIS.
+	 */
+	if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+	    !(qc->flags & ATA_QCFLAG_FAILED)) {
+		ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+		qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+	} else
+		ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
 
-	ata_tf_from_fis(d2h_fis, &qc->result_tf);
 	return true;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-core.c linux-libre-2.6.37-gnu/drivers/ata/libata-core.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-core.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,7 +68,7 @@
 #include <linux/ratelimit.h>
 
 #include "libata.h"
-
+#include "libata-transport.h"
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 const unsigned long sata_deb_timing_normal[]		= {   5,  100, 2000 };
@@ -91,8 +91,6 @@
 static unsigned int ata_dev_init_params(struct ata_device *dev,
 					u16 heads, u16 sectors);
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
-static unsigned int ata_dev_set_feature(struct ata_device *dev,
-					u8 enable, u8 feature);
 static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
@@ -1017,7 +1015,7 @@
 	return "<n/a>";
 }
 
-static const char *sata_spd_string(unsigned int spd)
+const char *sata_spd_string(unsigned int spd)
 {
 	static const char * const spd_str[] = {
 		"1.5 Gbps",
@@ -1030,182 +1028,6 @@
 	return spd_str[spd - 1];
 }
 
-static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy)
-{
-	struct ata_link *link = dev->link;
-	struct ata_port *ap = link->ap;
-	u32 scontrol;
-	unsigned int err_mask;
-	int rc;
-
-	/*
-	 * disallow DIPM for drivers which haven't set
-	 * ATA_FLAG_IPM.  This is because when DIPM is enabled,
-	 * phy ready will be set in the interrupt status on
-	 * state changes, which will cause some drivers to
-	 * think there are errors - additionally drivers will
-	 * need to disable hot plug.
-	 */
-	if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {
-		ap->pm_policy = NOT_AVAILABLE;
-		return -EINVAL;
-	}
-
-	/*
-	 * For DIPM, we will only enable it for the
-	 * min_power setting.
-	 *
-	 * Why?  Because Disks are too stupid to know that
-	 * If the host rejects a request to go to SLUMBER
-	 * they should retry at PARTIAL, and instead it
-	 * just would give up.  So, for medium_power to
-	 * work at all, we need to only allow HIPM.
-	 */
-	rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
-	if (rc)
-		return rc;
-
-	switch (policy) {
-	case MIN_POWER:
-		/* no restrictions on IPM transitions */
-		scontrol &= ~(0x3 << 8);
-		rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-		if (rc)
-			return rc;
-
-		/* enable DIPM */
-		if (dev->flags & ATA_DFLAG_DIPM)
-			err_mask = ata_dev_set_feature(dev,
-					SETFEATURES_SATA_ENABLE, SATA_DIPM);
-		break;
-	case MEDIUM_POWER:
-		/* allow IPM to PARTIAL */
-		scontrol &= ~(0x1 << 8);
-		scontrol |= (0x2 << 8);
-		rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-		if (rc)
-			return rc;
-
-		/*
-		 * we don't have to disable DIPM since IPM flags
-		 * disallow transitions to SLUMBER, which effectively
-		 * disable DIPM if it does not support PARTIAL
-		 */
-		break;
-	case NOT_AVAILABLE:
-	case MAX_PERFORMANCE:
-		/* disable all IPM transitions */
-		scontrol |= (0x3 << 8);
-		rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-		if (rc)
-			return rc;
-
-		/*
-		 * we don't have to disable DIPM since IPM flags
-		 * disallow all transitions which effectively
-		 * disable DIPM anyway.
-		 */
-		break;
-	}
-
-	/* FIXME: handle SET FEATURES failure */
-	(void) err_mask;
-
-	return 0;
-}
-
-/**
- *	ata_dev_enable_pm - enable SATA interface power management
- *	@dev:  device to enable power management
- *	@policy: the link power management policy
- *
- *	Enable SATA Interface power management.  This will enable
- *	Device Interface Power Management (DIPM) for min_power
- * 	policy, and then call driver specific callbacks for
- *	enabling Host Initiated Power management.
- *
- *	Locking: Caller.
- *	Returns: -EINVAL if IPM is not supported, 0 otherwise.
- */
-void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy)
-{
-	int rc = 0;
-	struct ata_port *ap = dev->link->ap;
-
-	/* set HIPM first, then DIPM */
-	if (ap->ops->enable_pm)
-		rc = ap->ops->enable_pm(ap, policy);
-	if (rc)
-		goto enable_pm_out;
-	rc = ata_dev_set_dipm(dev, policy);
-
-enable_pm_out:
-	if (rc)
-		ap->pm_policy = MAX_PERFORMANCE;
-	else
-		ap->pm_policy = policy;
-	return /* rc */;	/* hopefully we can use 'rc' eventually */
-}
-
-#ifdef CONFIG_PM
-/**
- *	ata_dev_disable_pm - disable SATA interface power management
- *	@dev: device to disable power management
- *
- *	Disable SATA Interface power management.  This will disable
- *	Device Interface Power Management (DIPM) without changing
- * 	policy,  call driver specific callbacks for disabling Host
- * 	Initiated Power management.
- *
- *	Locking: Caller.
- *	Returns: void
- */
-static void ata_dev_disable_pm(struct ata_device *dev)
-{
-	struct ata_port *ap = dev->link->ap;
-
-	ata_dev_set_dipm(dev, MAX_PERFORMANCE);
-	if (ap->ops->disable_pm)
-		ap->ops->disable_pm(ap);
-}
-#endif	/* CONFIG_PM */
-
-void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
-{
-	ap->pm_policy = policy;
-	ap->link.eh_info.action |= ATA_EH_LPM;
-	ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
-	ata_port_schedule_eh(ap);
-}
-
-#ifdef CONFIG_PM
-static void ata_lpm_enable(struct ata_host *host)
-{
-	struct ata_link *link;
-	struct ata_port *ap;
-	struct ata_device *dev;
-	int i;
-
-	for (i = 0; i < host->n_ports; i++) {
-		ap = host->ports[i];
-		ata_for_each_link(link, ap, EDGE) {
-			ata_for_each_dev(dev, link, ALL)
-				ata_dev_disable_pm(dev);
-		}
-	}
-}
-
-static void ata_lpm_disable(struct ata_host *host)
-{
-	int i;
-
-	for (i = 0; i < host->n_ports; i++) {
-		struct ata_port *ap = host->ports[i];
-		ata_lpm_schedule(ap, ap->pm_policy);
-	}
-}
-#endif	/* CONFIG_PM */
-
 /**
  *	ata_dev_classify - determine device type based on ATA-spec signature
  *	@tf: ATA taskfile register set for device to be identified
@@ -1806,8 +1628,14 @@
 		}
 	}
 
+	if (ap->ops->error_handler)
+		ata_eh_release(ap);
+
 	rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
 
+	if (ap->ops->error_handler)
+		ata_eh_acquire(ap);
+
 	ata_sff_flush_pio_task(ap);
 
 	if (!rc) {
@@ -2564,13 +2392,6 @@
 	if (dev->flags & ATA_DFLAG_LBA48)
 		dev->max_sectors = ATA_MAX_SECTORS_LBA48;
 
-	if (!(dev->horkage & ATA_HORKAGE_IPM)) {
-		if (ata_id_has_hipm(dev->id))
-			dev->flags |= ATA_DFLAG_HIPM;
-		if (ata_id_has_dipm(dev->id))
-			dev->flags |= ATA_DFLAG_DIPM;
-	}
-
 	/* Limit PATA drive on SATA cable bridge transfers to udma5,
 	   200 sectors */
 	if (ata_dev_knobble(dev)) {
@@ -2591,13 +2412,6 @@
 		dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
 					 dev->max_sectors);
 
-	if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
-		dev->horkage |= ATA_HORKAGE_IPM;
-
-		/* reset link pm_policy for this port to no pm */
-		ap->pm_policy = MAX_PERFORMANCE;
-	}
-
 	if (ap->ops->dev_config)
 		ap->ops->dev_config(dev);
 
@@ -3596,7 +3410,7 @@
 			warned = 1;
 		}
 
-		msleep(50);
+		ata_msleep(link->ap, 50);
 	}
 }
 
@@ -3617,7 +3431,7 @@
 int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
 				int (*check_ready)(struct ata_link *link))
 {
-	msleep(ATA_WAIT_AFTER_RESET);
+	ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
 
 	return ata_wait_ready(link, deadline, check_ready);
 }
@@ -3628,7 +3442,7 @@
  *	@params: timing parameters { interval, duratinon, timeout } in msec
  *	@deadline: deadline jiffies for the operation
  *
-*	Make sure SStatus of @link reaches stable state, determined by
+ *	Make sure SStatus of @link reaches stable state, determined by
  *	holding the same value where DET is not 1 for @duration polled
  *	every @interval, before @timeout.  Timeout constraints the
  *	beginning of the stable state.  Because DET gets stuck at 1 on
@@ -3665,7 +3479,7 @@
 	last_jiffies = jiffies;
 
 	while (1) {
-		msleep(interval);
+		ata_msleep(link->ap, interval);
 		if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
 			return rc;
 		cur &= 0xf;
@@ -3730,7 +3544,7 @@
 		 * immediately after resuming.  Delay 200ms before
 		 * debouncing.
 		 */
-		msleep(200);
+		ata_msleep(link->ap, 200);
 
 		/* is SControl restored correctly? */
 		if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
@@ -3760,6 +3574,72 @@
 }
 
 /**
+ *	sata_link_scr_lpm - manipulate SControl IPM and SPM fields
+ *	@link: ATA link to manipulate SControl for
+ *	@policy: LPM policy to configure
+ *	@spm_wakeup: initiate LPM transition to active state
+ *
+ *	Manipulate the IPM field of the SControl register of @link
+ *	according to @policy.  If @policy is ATA_LPM_MAX_POWER and
+ *	@spm_wakeup is %true, the SPM field is manipulated to wake up
+ *	the link.  This function also clears PHYRDY_CHG before
+ *	returning.
+ *
+ *	LOCKING:
+ *	EH context.
+ *
+ *	RETURNS:
+ *	0 on succes, -errno otherwise.
+ */
+int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+		      bool spm_wakeup)
+{
+	struct ata_eh_context *ehc = &link->eh_context;
+	bool woken_up = false;
+	u32 scontrol;
+	int rc;
+
+	rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+	if (rc)
+		return rc;
+
+	switch (policy) {
+	case ATA_LPM_MAX_POWER:
+		/* disable all LPM transitions */
+		scontrol |= (0x3 << 8);
+		/* initiate transition to active state */
+		if (spm_wakeup) {
+			scontrol |= (0x4 << 12);
+			woken_up = true;
+		}
+		break;
+	case ATA_LPM_MED_POWER:
+		/* allow LPM to PARTIAL */
+		scontrol &= ~(0x1 << 8);
+		scontrol |= (0x2 << 8);
+		break;
+	case ATA_LPM_MIN_POWER:
+		/* no restrictions on LPM transitions */
+		scontrol &= ~(0x3 << 8);
+		break;
+	default:
+		WARN_ON(1);
+	}
+
+	rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+	if (rc)
+		return rc;
+
+	/* give the link time to transit out of LPM state */
+	if (woken_up)
+		msleep(10);
+
+	/* clear PHYRDY_CHG from SError */
+	ehc->i.serror &= ~SERR_PHYRDY_CHG;
+	return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+}
+
+/**
  *	ata_std_prereset - prepare for reset
  *	@link: ATA link to be reset
  *	@deadline: deadline jiffies for the operation
@@ -3868,7 +3748,7 @@
 	/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
 	 * 10.4.2 says at least 1 ms.
 	 */
-	msleep(1);
+	ata_msleep(link->ap, 1);
 
 	/* bring link back */
 	rc = sata_link_resume(link, timing, deadline);
@@ -4551,6 +4431,7 @@
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
 }
+
 /**
  *	ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
  *	@dev: Device to which command will be sent
@@ -4566,8 +4447,7 @@
  *	RETURNS:
  *	0 on success, AC_ERR_* mask otherwise.
  */
-static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,
-					u8 feature)
+unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
 {
 	struct ata_taskfile tf;
 	unsigned int err_mask;
@@ -4927,9 +4807,6 @@
 {
 	struct ata_device *dev = qc->dev;
 
-	if (ata_tag_internal(qc->tag))
-		return;
-
 	if (ata_is_nodata(qc->tf.protocol))
 		return;
 
@@ -4943,8 +4820,13 @@
  *	ata_qc_complete - Complete an active ATA command
  *	@qc: Command to complete
  *
- *	Indicate to the mid and upper layers that an ATA
- *	command has completed, with either an ok or not-ok status.
+ *	Indicate to the mid and upper layers that an ATA command has
+ *	completed, with either an ok or not-ok status.
+ *
+ *	Refrain from calling this function multiple times when
+ *	successfully completing multiple NCQ commands.
+ *	ata_qc_complete_multiple() should be used instead, which will
+ *	properly update IRQ expect state.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
@@ -4973,14 +4855,23 @@
 		if (unlikely(qc->err_mask))
 			qc->flags |= ATA_QCFLAG_FAILED;
 
-		if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
-			/* always fill result TF for failed qc */
+		/*
+		 * Finish internal commands without any further processing
+		 * and always with the result TF filled.
+		 */
+		if (unlikely(ata_tag_internal(qc->tag))) {
 			fill_result_tf(qc);
+			__ata_qc_complete(qc);
+			return;
+		}
 
-			if (!ata_tag_internal(qc->tag))
-				ata_qc_schedule_eh(qc);
-			else
-				__ata_qc_complete(qc);
+		/*
+		 * Non-internal qc has failed.  Fill the result TF and
+		 * summon EH.
+		 */
+		if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
+			fill_result_tf(qc);
+			ata_qc_schedule_eh(qc);
 			return;
 		}
 
@@ -5037,6 +4928,10 @@
  *	requests normally.  ap->qc_active and @qc_active is compared
  *	and commands are completed accordingly.
  *
+ *	Always use this function when completing multiple NCQ commands
+ *	from IRQ handlers instead of calling ata_qc_complete()
+ *	multiple times to keep IRQ expect status properly in sync.
+ *
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
  *
@@ -5422,12 +5317,6 @@
 	int rc;
 
 	/*
-	 * disable link pm on all ports before requesting
-	 * any pm activity
-	 */
-	ata_lpm_enable(host);
-
-	/*
 	 * On some hardware, device fails to respond after spun down
 	 * for suspend.  As the device won't be used before being
 	 * resumed, we don't need to touch the device.  Ask EH to skip
@@ -5460,9 +5349,6 @@
 	ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
 			    ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
 	host->dev->power.power_state = PMSG_ON;
-
-	/* reenable link pm */
-	ata_lpm_disable(host);
 }
 #endif
 
@@ -5517,7 +5403,8 @@
 	int i;
 
 	/* clear everything except for devices */
-	memset(link, 0, offsetof(struct ata_link, device[0]));
+	memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0,
+	       ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN);
 
 	link->ap = ap;
 	link->pmp = pmp;
@@ -5591,7 +5478,7 @@
 	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
 	if (!ap)
 		return NULL;
-
+	
 	ap->pflags |= ATA_PFLAG_INITIALIZING;
 	ap->lock = &host->lock;
 	ap->print_id = -1;
@@ -5695,6 +5582,7 @@
 	dev_set_drvdata(dev, host);
 
 	spin_lock_init(&host->lock);
+	mutex_init(&host->eh_mutex);
 	host->dev = dev;
 	host->n_ports = max_ports;
 
@@ -5992,6 +5880,7 @@
 		   unsigned long flags, struct ata_port_operations *ops)
 {
 	spin_lock_init(&host->lock);
+	mutex_init(&host->eh_mutex);
 	host->dev = dev;
 	host->flags = flags;
 	host->ops = ops;
@@ -6022,7 +5911,7 @@
 		spin_lock_irqsave(ap->lock, flags);
 
 		ehi->probe_mask |= ATA_ALL_DEVICES;
-		ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
+		ehi->action |= ATA_EH_RESET;
 		ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
 		ap->pflags &= ~ATA_PFLAG_INITIALIZING;
@@ -6093,9 +5982,18 @@
 	for (i = 0; i < host->n_ports; i++)
 		host->ports[i]->print_id = ata_print_id++;
 
+	
+	/* Create associated sysfs transport objects  */
+	for (i = 0; i < host->n_ports; i++) {
+		rc = ata_tport_add(host->dev,host->ports[i]);
+		if (rc) {
+			goto err_tadd;
+		}
+	}
+
 	rc = ata_scsi_add_hosts(host, sht);
 	if (rc)
-		return rc;
+		goto err_tadd;
 
 	/* associate with ACPI nodes */
 	ata_acpi_associate(host);
@@ -6136,6 +6034,13 @@
 	}
 
 	return 0;
+
+ err_tadd:
+	while (--i >= 0) {
+		ata_tport_delete(host->ports[i]);
+	}
+	return rc;
+
 }
 
 /**
@@ -6226,6 +6131,13 @@
 	cancel_rearming_delayed_work(&ap->hotplug_task);
 
  skip_eh:
+	if (ap->pmp_link) {
+		int i;
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+			ata_tlink_delete(&ap->pmp_link[i]);
+	}
+	ata_tport_delete(ap);
+
 	/* remove the associated SCSI host */
 	scsi_remove_host(ap->scsi_host);
 }
@@ -6542,7 +6454,7 @@
 
 static int __init ata_init(void)
 {
-	int rc = -ENOMEM;
+	int rc;
 
 	ata_parse_force_param();
 
@@ -6552,12 +6464,25 @@
 		return rc;
 	}
 
+	libata_transport_init();
+	ata_scsi_transport_template = ata_attach_transport();
+	if (!ata_scsi_transport_template) {
+		ata_sff_exit();
+		rc = -ENOMEM;
+		goto err_out;
+	}		
+
 	printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
 	return 0;
+
+err_out:
+	return rc;
 }
 
 static void __exit ata_exit(void)
 {
+	ata_release_transport(ata_scsi_transport_template);
+	libata_transport_exit();
 	ata_sff_exit();
 	kfree(ata_force_tbl);
 }
@@ -6573,7 +6498,35 @@
 }
 
 /**
+ *	ata_msleep - ATA EH owner aware msleep
+ *	@ap: ATA port to attribute the sleep to
+ *	@msecs: duration to sleep in milliseconds
+ *
+ *	Sleeps @msecs.  If the current task is owner of @ap's EH, the
+ *	ownership is released before going to sleep and reacquired
+ *	after the sleep is complete.  IOW, other ports sharing the
+ *	@ap->host will be allowed to own the EH while this task is
+ *	sleeping.
+ *
+ *	LOCKING:
+ *	Might sleep.
+ */
+void ata_msleep(struct ata_port *ap, unsigned int msecs)
+{
+	bool owns_eh = ap && ap->host->eh_owner == current;
+
+	if (owns_eh)
+		ata_eh_release(ap);
+
+	msleep(msecs);
+
+	if (owns_eh)
+		ata_eh_acquire(ap);
+}
+
+/**
  *	ata_wait_register - wait until register value changes
+ *	@ap: ATA port to wait register for, can be NULL
  *	@reg: IO-mapped register
  *	@mask: Mask to apply to read register value
  *	@val: Wait condition
@@ -6595,7 +6548,7 @@
  *	RETURNS:
  *	The final register value.
  */
-u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
 		      unsigned long interval, unsigned long timeout)
 {
 	unsigned long deadline;
@@ -6610,7 +6563,7 @@
 	deadline = ata_deadline(jiffies, timeout);
 
 	while ((tmp & mask) == val && time_before(jiffies, deadline)) {
-		msleep(interval);
+		ata_msleep(ap, interval);
 		tmp = ioread32(reg);
 	}
 
@@ -6686,6 +6639,7 @@
 EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 EXPORT_SYMBOL_GPL(sata_link_debounce);
 EXPORT_SYMBOL_GPL(sata_link_resume);
+EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
 EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(sata_link_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
@@ -6693,6 +6647,7 @@
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_pair);
 EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_msleep);
 EXPORT_SYMBOL_GPL(ata_wait_register);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-eh.c linux-libre-2.6.37-gnu/drivers/ata/libata-eh.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-eh.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-eh.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,7 @@
 	/* error flags */
 	ATA_EFLAG_IS_IO			= (1 << 0),
 	ATA_EFLAG_DUBIOUS_XFER		= (1 << 1),
+	ATA_EFLAG_OLD_ER                = (1 << 31),
 
 	/* error categories */
 	ATA_ECAT_NONE			= 0,
@@ -396,14 +397,9 @@
 	return NULL;
 }
 
-static void ata_ering_clear(struct ata_ering *ering)
-{
-	memset(ering, 0, sizeof(*ering));
-}
-
-static int ata_ering_map(struct ata_ering *ering,
-			 int (*map_fn)(struct ata_ering_entry *, void *),
-			 void *arg)
+int ata_ering_map(struct ata_ering *ering,
+		  int (*map_fn)(struct ata_ering_entry *, void *),
+		  void *arg)
 {
 	int idx, rc = 0;
 	struct ata_ering_entry *ent;
@@ -422,6 +418,17 @@
 	return rc;
 }
 
+int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+	ent->eflags |= ATA_EFLAG_OLD_ER;
+	return 0;
+}
+
+static void ata_ering_clear(struct ata_ering *ering)
+{
+	ata_ering_map(ering, ata_ering_clear_cb, NULL);
+}
+
 static unsigned int ata_eh_dev_action(struct ata_device *dev)
 {
 	struct ata_eh_context *ehc = &dev->link->eh_context;
@@ -456,6 +463,41 @@
 }
 
 /**
+ *	ata_eh_acquire - acquire EH ownership
+ *	@ap: ATA port to acquire EH ownership for
+ *
+ *	Acquire EH ownership for @ap.  This is the basic exclusion
+ *	mechanism for ports sharing a host.  Only one port hanging off
+ *	the same host can claim the ownership of EH.
+ *
+ *	LOCKING:
+ *	EH context.
+ */
+void ata_eh_acquire(struct ata_port *ap)
+{
+	mutex_lock(&ap->host->eh_mutex);
+	WARN_ON_ONCE(ap->host->eh_owner);
+	ap->host->eh_owner = current;
+}
+
+/**
+ *	ata_eh_release - release EH ownership
+ *	@ap: ATA port to release EH ownership for
+ *
+ *	Release EH ownership for @ap if the caller.  The caller must
+ *	have acquired EH ownership using ata_eh_acquire() previously.
+ *
+ *	LOCKING:
+ *	EH context.
+ */
+void ata_eh_release(struct ata_port *ap)
+{
+	WARN_ON_ONCE(ap->host->eh_owner != current);
+	ap->host->eh_owner = NULL;
+	mutex_unlock(&ap->host->eh_mutex);
+}
+
+/**
  *	ata_scsi_timed_out - SCSI layer time out callback
  *	@cmd: timed out SCSI command
  *
@@ -572,19 +614,19 @@
 		int nr_timedout = 0;
 
 		spin_lock_irqsave(ap->lock, flags);
-		
+
 		/* This must occur under the ap->lock as we don't want
 		   a polled recovery to race the real interrupt handler
-		   
+
 		   The lost_interrupt handler checks for any completed but
 		   non-notified command and completes much like an IRQ handler.
-		   
+
 		   We then fall into the error recovery code which will treat
 		   this as if normal completion won the race */
 
 		if (ap->ops->lost_interrupt)
 			ap->ops->lost_interrupt(ap);
-			
+
 		list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
 			struct ata_queued_cmd *qc;
 
@@ -628,15 +670,17 @@
 		ap->eh_tries = ATA_EH_MAX_TRIES;
 	} else
 		spin_unlock_wait(ap->lock);
-		
+
 	/* If we timed raced normal completion and there is nothing to
 	   recover nr_timedout == 0 why exactly are we doing error recovery ? */
 
- repeat:
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
 		struct ata_link *link;
 
+		/* acquire EH ownership */
+		ata_eh_acquire(ap);
+ repeat:
 		/* kill fast drain timer */
 		del_timer_sync(&ap->fastdrain_timer);
 
@@ -711,6 +755,7 @@
 		host->host_eh_scheduled = 0;
 
 		spin_unlock_irqrestore(ap->lock, flags);
+		ata_eh_release(ap);
 	} else {
 		WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
 		ap->ops->eng_timeout(ap);
@@ -772,7 +817,7 @@
 
 	/* make sure SCSI EH is complete */
 	if (scsi_host_in_recovery(ap->scsi_host)) {
-		msleep(10);
+		ata_msleep(ap, 10);
 		goto retry;
 	}
 }
@@ -1573,9 +1618,9 @@
 	 * host links.  For disabled PMP links, only N bit is
 	 * considered as X bit is left at 1 for link plugging.
 	 */
-	hotplug_mask = 0;
-
-	if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+	if (link->lpm_policy != ATA_LPM_MAX_POWER)
+		hotplug_mask = 0;	/* hotplug doesn't work w/ LPM */
+	else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
 		hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
 	else
 		hotplug_mask = SERR_PHYRDY_CHG;
@@ -1755,7 +1800,7 @@
 	struct speed_down_verdict_arg *arg = void_arg;
 	int cat;
 
-	if (ent->timestamp < arg->since)
+	if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
 		return -1;
 
 	cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
@@ -2777,8 +2822,9 @@
 	ata_eh_done(link, NULL, ATA_EH_RESET);
 	if (slave)
 		ata_eh_done(slave, NULL, ATA_EH_RESET);
-	ehc->last_reset = jiffies;	/* update to completion time */
+	ehc->last_reset = jiffies;		/* update to completion time */
 	ehc->i.action |= ATA_EH_REVALIDATE;
+	link->lpm_policy = ATA_LPM_UNKNOWN;	/* reset LPM state */
 
 	rc = 0;
  out:
@@ -2810,8 +2856,10 @@
 			"reset failed (errno=%d), retrying in %u secs\n",
 			rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
 
+		ata_eh_release(ap);
 		while (delta)
 			delta = schedule_timeout_uninterruptible(delta);
+		ata_eh_acquire(ap);
 	}
 
 	if (try == max_tries - 1) {
@@ -3204,6 +3252,135 @@
 	return rc;
 }
 
+/**
+ *	ata_eh_set_lpm - configure SATA interface power management
+ *	@link: link to configure power management
+ *	@policy: the link power management policy
+ *	@r_failed_dev: out parameter for failed device
+ *
+ *	Enable SATA Interface power management.  This will enable
+ *	Device Interface Power Management (DIPM) for min_power
+ * 	policy, and then call driver specific callbacks for
+ *	enabling Host Initiated Power management.
+ *
+ *	LOCKING:
+ *	EH context.
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			  struct ata_device **r_failed_dev)
+{
+	struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
+	enum ata_lpm_policy old_policy = link->lpm_policy;
+	unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
+	unsigned int err_mask;
+	int rc;
+
+	/* if the link or host doesn't do LPM, noop */
+	if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
+		return 0;
+
+	/*
+	 * DIPM is enabled only for MIN_POWER as some devices
+	 * misbehave when the host NACKs transition to SLUMBER.  Order
+	 * device and link configurations such that the host always
+	 * allows DIPM requests.
+	 */
+	ata_for_each_dev(dev, link, ENABLED) {
+		bool hipm = ata_id_has_hipm(dev->id);
+		bool dipm = ata_id_has_dipm(dev->id);
+
+		/* find the first enabled and LPM enabled devices */
+		if (!link_dev)
+			link_dev = dev;
+
+		if (!lpm_dev && (hipm || dipm))
+			lpm_dev = dev;
+
+		hints &= ~ATA_LPM_EMPTY;
+		if (!hipm)
+			hints &= ~ATA_LPM_HIPM;
+
+		/* disable DIPM before changing link config */
+		if (policy != ATA_LPM_MIN_POWER && dipm) {
+			err_mask = ata_dev_set_feature(dev,
+					SETFEATURES_SATA_DISABLE, SATA_DIPM);
+			if (err_mask && err_mask != AC_ERR_DEV) {
+				ata_dev_printk(dev, KERN_WARNING,
+					"failed to disable DIPM, Emask 0x%x\n",
+					err_mask);
+				rc = -EIO;
+				goto fail;
+			}
+		}
+	}
+
+	if (ap) {
+		rc = ap->ops->set_lpm(link, policy, hints);
+		if (!rc && ap->slave_link)
+			rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
+	} else
+		rc = sata_pmp_set_lpm(link, policy, hints);
+
+	/*
+	 * Attribute link config failure to the first (LPM) enabled
+	 * device on the link.
+	 */
+	if (rc) {
+		if (rc == -EOPNOTSUPP) {
+			link->flags |= ATA_LFLAG_NO_LPM;
+			return 0;
+		}
+		dev = lpm_dev ? lpm_dev : link_dev;
+		goto fail;
+	}
+
+	/*
+	 * Low level driver acked the transition.  Issue DIPM command
+	 * with the new policy set.
+	 */
+	link->lpm_policy = policy;
+	if (ap && ap->slave_link)
+		ap->slave_link->lpm_policy = policy;
+
+	/* host config updated, enable DIPM if transitioning to MIN_POWER */
+	ata_for_each_dev(dev, link, ENABLED) {
+		if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
+			err_mask = ata_dev_set_feature(dev,
+					SETFEATURES_SATA_ENABLE, SATA_DIPM);
+			if (err_mask && err_mask != AC_ERR_DEV) {
+				ata_dev_printk(dev, KERN_WARNING,
+					"failed to enable DIPM, Emask 0x%x\n",
+					err_mask);
+				rc = -EIO;
+				goto fail;
+			}
+		}
+	}
+
+	return 0;
+
+fail:
+	/* restore the old policy */
+	link->lpm_policy = old_policy;
+	if (ap && ap->slave_link)
+		ap->slave_link->lpm_policy = old_policy;
+
+	/* if no device or only one more chance is left, disable LPM */
+	if (!dev || ehc->tries[dev->devno] <= 2) {
+		ata_link_printk(link, KERN_WARNING,
+				"disabling LPM on the link\n");
+		link->flags |= ATA_LFLAG_NO_LPM;
+	}
+	if (r_failed_dev)
+		*r_failed_dev = dev;
+	return rc;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -3288,6 +3465,16 @@
 	ehc->saved_xfer_mode[dev->devno] = 0;
 	ehc->saved_ncq_enabled &= ~(1 << dev->devno);
 
+	/* the link maybe in a deep sleep, wake it up */
+	if (link->lpm_policy > ATA_LPM_MAX_POWER) {
+		if (ata_is_host_link(link))
+			link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER,
+					       ATA_LPM_EMPTY);
+		else
+			sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER,
+					 ATA_LPM_EMPTY);
+	}
+
 	/* Record and count probe trials on the ering.  The specific
 	 * error mask used is irrelevant.  Because a successful device
 	 * detection clears the ering, this count accumulates only if
@@ -3389,8 +3576,7 @@
 {
 	struct ata_link *link;
 	struct ata_device *dev;
-	int nr_failed_devs;
-	int rc;
+	int rc, nr_fails;
 	unsigned long flags, deadline;
 
 	DPRINTK("ENTER\n");
@@ -3431,7 +3617,6 @@
 
  retry:
 	rc = 0;
-	nr_failed_devs = 0;
 
 	/* if UNLOADING, finish immediately */
 	if (ap->pflags & ATA_PFLAG_UNLOADING)
@@ -3501,8 +3686,10 @@
 		if (time_before_eq(deadline, now))
 			break;
 
+		ata_eh_release(ap);
 		deadline = wait_for_completion_timeout(&ap->park_req_pending,
 						       deadline - now);
+		ata_eh_acquire(ap);
 	} while (deadline);
 	ata_for_each_link(link, ap, EDGE) {
 		ata_for_each_dev(dev, link, ALL) {
@@ -3516,13 +3703,17 @@
 	}
 
 	/* the rest */
-	ata_for_each_link(link, ap, EDGE) {
+	nr_fails = 0;
+	ata_for_each_link(link, ap, PMP_FIRST) {
 		struct ata_eh_context *ehc = &link->eh_context;
 
+		if (sata_pmp_attached(ap) && ata_is_host_link(link))
+			goto config_lpm;
+
 		/* revalidate existing devices and attach new ones */
 		rc = ata_eh_revalidate_and_attach(link, &dev);
 		if (rc)
-			goto dev_fail;
+			goto rest_fail;
 
 		/* if PMP got attached, return, pmp EH will take care of it */
 		if (link->device->class == ATA_DEV_PMP) {
@@ -3534,7 +3725,7 @@
 		if (ehc->i.flags & ATA_EHI_SETMODE) {
 			rc = ata_set_mode(link, &dev);
 			if (rc)
-				goto dev_fail;
+				goto rest_fail;
 			ehc->i.flags &= ~ATA_EHI_SETMODE;
 		}
 
@@ -3547,7 +3738,7 @@
 					continue;
 				rc = atapi_eh_clear_ua(dev);
 				if (rc)
-					goto dev_fail;
+					goto rest_fail;
 			}
 		}
 
@@ -3557,21 +3748,25 @@
 				continue;
 			rc = ata_eh_maybe_retry_flush(dev);
 			if (rc)
-				goto dev_fail;
+				goto rest_fail;
 		}
 
+	config_lpm:
 		/* configure link power saving */
-		if (ehc->i.action & ATA_EH_LPM)
-			ata_for_each_dev(dev, link, ALL)
-				ata_dev_enable_pm(dev, ap->pm_policy);
+		if (link->lpm_policy != ap->target_lpm_policy) {
+			rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
+			if (rc)
+				goto rest_fail;
+		}
 
 		/* this link is okay now */
 		ehc->i.flags = 0;
 		continue;
 
-dev_fail:
-		nr_failed_devs++;
-		ata_eh_handle_dev_fail(dev, rc);
+	rest_fail:
+		nr_fails++;
+		if (dev)
+			ata_eh_handle_dev_fail(dev, rc);
 
 		if (ap->pflags & ATA_PFLAG_FROZEN) {
 			/* PMP reset requires working host port.
@@ -3583,7 +3778,7 @@
 		}
 	}
 
-	if (nr_failed_devs)
+	if (nr_fails)
 		goto retry;
 
  out:
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata.h linux-libre-2.6.37-gnu/drivers/ata/libata.h
--- linux-libre-2.6.36-gnu/drivers/ata/libata.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata.h	2011-01-04 19:50:19.000000000 -0500
@@ -86,6 +86,8 @@
 extern int ata_dev_configure(struct ata_device *dev);
 extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
+extern unsigned int ata_dev_set_feature(struct ata_device *dev,
+					u8 enable, u8 feature);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -100,8 +102,7 @@
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
-extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy);
-extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
+extern const char *sata_spd_string(unsigned int spd);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
@@ -137,10 +138,15 @@
 extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
 extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
+extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+			      unsigned int id, unsigned int lun);
+
 
 /* libata-eh.c */
 extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
 extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
+extern void ata_eh_acquire(struct ata_port *ap);
+extern void ata_eh_release(struct ata_port *ap);
 extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
@@ -164,11 +170,16 @@
 			  ata_postreset_fn_t postreset,
 			  struct ata_link **r_failed_disk);
 extern void ata_eh_finish(struct ata_port *ap);
+extern int ata_ering_map(struct ata_ering *ering,
+			 int (*map_fn)(struct ata_ering_entry *, void *),
+		  	 void *arg);
 
 /* libata-pmp.c */
 #ifdef CONFIG_SATA_PMP
 extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
 extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+			    unsigned hints);
 extern int sata_pmp_attach(struct ata_device *dev);
 #else /* CONFIG_SATA_PMP */
 static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val)
@@ -180,6 +191,12 @@
 {
 	return -EINVAL;
 }
+
+static inline int sata_pmp_set_lpm(struct ata_link *link,
+				   enum ata_lpm_policy policy, unsigned hints)
+{
+	return -EINVAL;
+}
 
 static inline int sata_pmp_attach(struct ata_device *dev)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-pmp.c linux-libre-2.6.37-gnu/drivers/ata/libata-pmp.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-pmp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-pmp.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 #include <linux/libata.h>
 #include <linux/slab.h>
 #include "libata.h"
+#include "libata-transport.h"
 
 const struct ata_port_operations sata_pmp_port_ops = {
 	.inherits		= &sata_port_ops,
@@ -185,6 +186,27 @@
 }
 
 /**
+ *	sata_pmp_set_lpm - configure LPM for a PMP link
+ *	@link: PMP link to configure LPM for
+ *	@policy: target LPM policy
+ *	@hints: LPM hints
+ *
+ *	Configure LPM for @link.  This function will contain any PMP
+ *	specific workarounds if necessary.
+ *
+ *	LOCKING:
+ *	EH context.
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+		     unsigned hints)
+{
+	return sata_link_scr_lpm(link, policy, true);
+}
+
+/**
  *	sata_pmp_read_gscr - read GSCR block of SATA PMP
  *	@dev: PMP device
  *	@gscr: buffer to read GSCR block into
@@ -312,10 +334,10 @@
 	return rc;
 }
 
-static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
 {
 	struct ata_link *pmp_link = ap->pmp_link;
-	int i;
+	int i, err;
 
 	if (!pmp_link) {
 		pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
@@ -327,6 +349,13 @@
 			ata_link_init(ap, &pmp_link[i], i);
 
 		ap->pmp_link = pmp_link;
+
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+			err = ata_tlink_add(&pmp_link[i]);
+			if (err) {
+				goto err_tlink;
+			}
+		}
 	}
 
 	for (i = 0; i < nr_ports; i++) {
@@ -339,6 +368,12 @@
 	}
 
 	return 0;
+  err_tlink:
+	while (--i >= 0)
+		ata_tlink_delete(&pmp_link[i]);
+	kfree(pmp_link);
+	ap->pmp_link = NULL;
+	return err;
 }
 
 static void sata_pmp_quirks(struct ata_port *ap)
@@ -351,6 +386,9 @@
 	if (vendor == 0x1095 && devid == 0x3726) {
 		/* sil3726 quirks */
 		ata_for_each_link(link, ap, EDGE) {
+			/* link reports offline after LPM */
+			link->flags |= ATA_LFLAG_NO_LPM;
+
 			/* Class code report is unreliable and SRST
 			 * times out under certain configurations.
 			 */
@@ -366,6 +404,9 @@
 	} else if (vendor == 0x1095 && devid == 0x4723) {
 		/* sil4723 quirks */
 		ata_for_each_link(link, ap, EDGE) {
+			/* link reports offline after LPM */
+			link->flags |= ATA_LFLAG_NO_LPM;
+
 			/* class code report is unreliable */
 			if (link->pmp < 2)
 				link->flags |= ATA_LFLAG_ASSUME_ATA;
@@ -378,6 +419,9 @@
 	} else if (vendor == 0x1095 && devid == 0x4726) {
 		/* sil4726 quirks */
 		ata_for_each_link(link, ap, EDGE) {
+			/* link reports offline after LPM */
+			link->flags |= ATA_LFLAG_NO_LPM;
+
 			/* Class code report is unreliable and SRST
 			 * times out under certain configurations.
 			 * Config device can be at port 0 or 5 and
@@ -938,15 +982,25 @@
 	if (rc)
 		goto link_fail;
 
-	/* Connection status might have changed while resetting other
-	 * links, check SATA_PMP_GSCR_ERROR before returning.
-	 */
-
 	/* clear SNotification */
 	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
 	if (rc == 0)
 		sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
 
+	/*
+	 * If LPM is active on any fan-out port, hotplug wouldn't
+	 * work.  Return w/ PHY event notification disabled.
+	 */
+	ata_for_each_link(link, ap, EDGE)
+		if (link->lpm_policy > ATA_LPM_MAX_POWER)
+			return 0;
+
+	/*
+	 * Connection status might have changed while resetting other
+	 * links, enable notification and check SATA_PMP_GSCR_ERROR
+	 * before returning.
+	 */
+
 	/* enable notification */
 	if (pmp_dev->flags & ATA_DFLAG_AN) {
 		gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-scsi.c linux-libre-2.6.37-gnu/drivers/ata/libata-scsi.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-scsi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-scsi.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,8 +51,8 @@
 #include <asm/unaligned.h>
 
 #include "libata.h"
+#include "libata-transport.h"
 
-#define SECTOR_SIZE		512
 #define ATA_SCSI_RBUF_SIZE	4096
 
 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
@@ -64,9 +64,6 @@
 					const struct scsi_device *scsidev);
 static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
 					    const struct scsi_device *scsidev);
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
-			      unsigned int id, unsigned int lun);
-
 
 #define RW_RECOVERY_MPAGE 0x1
 #define RW_RECOVERY_MPAGE_LEN 12
@@ -106,83 +103,55 @@
 	0, 30	/* extended self test time, see 05-359r1 */
 };
 
-/*
- * libata transport template.  libata doesn't do real transport stuff.
- * It just needs the eh_timed_out hook.
- */
-static struct scsi_transport_template ata_scsi_transport_template = {
-	.eh_strategy_handler	= ata_scsi_error,
-	.eh_timed_out		= ata_scsi_timed_out,
-	.user_scan		= ata_scsi_user_scan,
-};
-
-
-static const struct {
-	enum link_pm	value;
-	const char	*name;
-} link_pm_policy[] = {
-	{ NOT_AVAILABLE, "max_performance" },
-	{ MIN_POWER, "min_power" },
-	{ MAX_PERFORMANCE, "max_performance" },
-	{ MEDIUM_POWER, "medium_power" },
+static const char *ata_lpm_policy_names[] = {
+	[ATA_LPM_UNKNOWN]	= "max_performance",
+	[ATA_LPM_MAX_POWER]	= "max_performance",
+	[ATA_LPM_MED_POWER]	= "medium_power",
+	[ATA_LPM_MIN_POWER]	= "min_power",
 };
 
-static const char *ata_scsi_lpm_get(enum link_pm policy)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
-		if (link_pm_policy[i].value == policy)
-			return link_pm_policy[i].name;
-
-	return NULL;
-}
-
-static ssize_t ata_scsi_lpm_put(struct device *dev,
-				struct device_attribute *attr,
-				const char *buf, size_t count)
+static ssize_t ata_scsi_lpm_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
 {
 	struct Scsi_Host *shost = class_to_shost(dev);
 	struct ata_port *ap = ata_shost_to_port(shost);
-	enum link_pm policy = 0;
-	int i;
+	enum ata_lpm_policy policy;
+	unsigned long flags;
 
-	/*
-	 * we are skipping array location 0 on purpose - this
-	 * is because a value of NOT_AVAILABLE is displayed
-	 * to the user as max_performance, but when the user
-	 * writes "max_performance", they actually want the
-	 * value to match MAX_PERFORMANCE.
-	 */
-	for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
-		const int len = strlen(link_pm_policy[i].name);
-		if (strncmp(link_pm_policy[i].name, buf, len) == 0) {
-			policy = link_pm_policy[i].value;
+	/* UNKNOWN is internal state, iterate from MAX_POWER */
+	for (policy = ATA_LPM_MAX_POWER;
+	     policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
+		const char *name = ata_lpm_policy_names[policy];
+
+		if (strncmp(name, buf, strlen(name)) == 0)
 			break;
-		}
 	}
-	if (!policy)
+	if (policy == ARRAY_SIZE(ata_lpm_policy_names))
 		return -EINVAL;
 
-	ata_lpm_schedule(ap, policy);
+	spin_lock_irqsave(ap->lock, flags);
+	ap->target_lpm_policy = policy;
+	ata_port_schedule_eh(ap);
+	spin_unlock_irqrestore(ap->lock, flags);
+
 	return count;
 }
 
-static ssize_t
-ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ata_scsi_lpm_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(dev);
 	struct ata_port *ap = ata_shost_to_port(shost);
-	const char *policy =
-		ata_scsi_lpm_get(ap->pm_policy);
 
-	if (!policy)
+	if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
 		return -EINVAL;
 
-	return snprintf(buf, 23, "%s\n", policy);
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			ata_lpm_policy_names[ap->target_lpm_policy]);
 }
 DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
-		ata_scsi_lpm_show, ata_scsi_lpm_put);
+	    ata_scsi_lpm_show, ata_scsi_lpm_store);
 EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
 
 static ssize_t ata_scsi_park_show(struct device *device,
@@ -516,7 +485,7 @@
 	memset(scsi_cmd, 0, sizeof(scsi_cmd));
 
 	if (args[3]) {
-		argsize = SECTOR_SIZE * args[3];
+		argsize = ATA_SECT_SIZE * args[3];
 		argbuf = kmalloc(argsize, GFP_KERNEL);
 		if (argbuf == NULL) {
 			rc = -ENOMEM;
@@ -1150,8 +1119,9 @@
 		blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
 	} else {
 		/* ATA devices must be sector aligned */
+		sdev->sector_size = ata_id_logical_sector_size(dev->id);
 		blk_queue_update_dma_alignment(sdev->request_queue,
-					       ATA_SECT_SIZE - 1);
+					       sdev->sector_size - 1);
 		sdev->manage_start_stop = 1;
 	}
 
@@ -1166,6 +1136,7 @@
 		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
 	}
 
+	dev->sdev = sdev;
 	return 0;
 }
 
@@ -1696,7 +1667,7 @@
 		goto nothing_to_do;
 
 	qc->flags |= ATA_QCFLAG_IO;
-	qc->nbytes = n_block * ATA_SECT_SIZE;
+	qc->nbytes = n_block * scmd->device->sector_size;
 
 	rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
 			     qc->tag);
@@ -2001,6 +1972,7 @@
 		0x89,	/* page 0x89, ata info page */
 		0xb0,	/* page 0xb0, block limits page */
 		0xb1,	/* page 0xb1, block device characteristics page */
+		0xb2,	/* page 0xb2, thin provisioning page */
 	};
 
 	rbuf[3] = sizeof(pages);	/* number of supported VPD pages */
@@ -2123,7 +2095,7 @@
 
 static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
 {
-	u32 min_io_sectors;
+	u16 min_io_sectors;
 
 	rbuf[1] = 0xb0;
 	rbuf[3] = 0x3c;		/* required VPD size with unmap support */
@@ -2135,10 +2107,7 @@
 	 * logical than physical sector size we need to figure out what the
 	 * latter is.
 	 */
-	if (ata_id_has_large_logical_sectors(args->id))
-		min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
-	else
-		min_io_sectors = 1;
+	min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
 	put_unaligned_be16(min_io_sectors, &rbuf[6]);
 
 	/*
@@ -2172,6 +2141,16 @@
 	return 0;
 }
 
+static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)
+{
+	/* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */
+	rbuf[1] = 0xb2;
+	rbuf[3] = 0x4;
+	rbuf[5] = 1 << 6;	/* TPWS */
+
+	return 0;
+}
+
 /**
  *	ata_scsiop_noop - Command handler that simply returns success.
  *	@args: device IDENTIFY data / SCSI command of interest.
@@ -2397,21 +2376,13 @@
 {
 	struct ata_device *dev = args->dev;
 	u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
-	u8 log_per_phys = 0;
-	u16 lowest_aligned = 0;
-	u16 word_106 = dev->id[106];
-	u16 word_209 = dev->id[209];
+	u32 sector_size; /* physical sector size in bytes */
+	u8 log2_per_phys;
+	u16 lowest_aligned;
 
-	if ((word_106 & 0xc000) == 0x4000) {
-		/* Number and offset of logical sectors per physical sector */
-		if (word_106 & (1 << 13))
-			log_per_phys = word_106 & 0xf;
-		if ((word_209 & 0xc000) == 0x4000) {
-			u16 first = dev->id[209] & 0x3fff;
-			if (first > 0)
-				lowest_aligned = (1 << log_per_phys) - first;
-		}
-	}
+	sector_size = ata_id_logical_sector_size(dev->id);
+	log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
+	lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
 
 	VPRINTK("ENTER\n");
 
@@ -2426,8 +2397,10 @@
 		rbuf[3] = last_lba;
 
 		/* sector size */
-		rbuf[6] = ATA_SECT_SIZE >> 8;
-		rbuf[7] = ATA_SECT_SIZE & 0xff;
+		rbuf[4] = sector_size >> (8 * 3);
+		rbuf[5] = sector_size >> (8 * 2);
+		rbuf[6] = sector_size >> (8 * 1);
+		rbuf[7] = sector_size;
 	} else {
 		/* sector count, 64-bit */
 		rbuf[0] = last_lba >> (8 * 7);
@@ -2440,11 +2413,13 @@
 		rbuf[7] = last_lba;
 
 		/* sector size */
-		rbuf[10] = ATA_SECT_SIZE >> 8;
-		rbuf[11] = ATA_SECT_SIZE & 0xff;
+		rbuf[ 8] = sector_size >> (8 * 3);
+		rbuf[ 9] = sector_size >> (8 * 2);
+		rbuf[10] = sector_size >> (8 * 1);
+		rbuf[11] = sector_size;
 
 		rbuf[12] = 0;
-		rbuf[13] = log_per_phys;
+		rbuf[13] = log2_per_phys;
 		rbuf[14] = (lowest_aligned >> 8) & 0x3f;
 		rbuf[15] = lowest_aligned;
 
@@ -2577,8 +2552,11 @@
 		 *
 		 * If door lock fails, always clear sdev->locked to
 		 * avoid this infinite loop.
+		 *
+		 * This may happen before SCSI scan is complete.  Make
+		 * sure qc->dev->sdev isn't NULL before dereferencing.
 		 */
-		if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+		if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
 			qc->dev->sdev->locked = 0;
 
 		qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
@@ -2888,9 +2866,8 @@
 	tf->device = dev->devno ?
 		tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
 
-	/* READ/WRITE LONG use a non-standard sect_size */
-	qc->sect_size = ATA_SECT_SIZE;
 	switch (tf->command) {
+	/* READ/WRITE LONG use a non-standard sect_size */
 	case ATA_CMD_READ_LONG:
 	case ATA_CMD_READ_LONG_ONCE:
 	case ATA_CMD_WRITE_LONG:
@@ -2898,6 +2875,45 @@
 		if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
 			goto invalid_fld;
 		qc->sect_size = scsi_bufflen(scmd);
+		break;
+
+	/* commands using reported Logical Block size (e.g. 512 or 4K) */
+	case ATA_CMD_CFA_WRITE_NE:
+	case ATA_CMD_CFA_TRANS_SECT:
+	case ATA_CMD_CFA_WRITE_MULT_NE:
+	/* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
+	case ATA_CMD_READ:
+	case ATA_CMD_READ_EXT:
+	case ATA_CMD_READ_QUEUED:
+	/* XXX: case ATA_CMD_READ_QUEUED_EXT: */
+	case ATA_CMD_FPDMA_READ:
+	case ATA_CMD_READ_MULTI:
+	case ATA_CMD_READ_MULTI_EXT:
+	case ATA_CMD_PIO_READ:
+	case ATA_CMD_PIO_READ_EXT:
+	case ATA_CMD_READ_STREAM_DMA_EXT:
+	case ATA_CMD_READ_STREAM_EXT:
+	case ATA_CMD_VERIFY:
+	case ATA_CMD_VERIFY_EXT:
+	case ATA_CMD_WRITE:
+	case ATA_CMD_WRITE_EXT:
+	case ATA_CMD_WRITE_FUA_EXT:
+	case ATA_CMD_WRITE_QUEUED:
+	case ATA_CMD_WRITE_QUEUED_FUA_EXT:
+	case ATA_CMD_FPDMA_WRITE:
+	case ATA_CMD_WRITE_MULTI:
+	case ATA_CMD_WRITE_MULTI_EXT:
+	case ATA_CMD_WRITE_MULTI_FUA_EXT:
+	case ATA_CMD_PIO_WRITE:
+	case ATA_CMD_PIO_WRITE_EXT:
+	case ATA_CMD_WRITE_STREAM_DMA_EXT:
+	case ATA_CMD_WRITE_STREAM_EXT:
+		qc->sect_size = scmd->device->sector_size;
+		break;
+
+	/* Everything else uses 512 byte "sectors" */
+	default:
+		qc->sect_size = ATA_SECT_SIZE;
 	}
 
 	/*
@@ -3150,8 +3166,8 @@
 
 /**
  *	ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ *	@shost: SCSI host of command to be sent
  *	@cmd: SCSI command to be sent
- *	@done: Completion function, called when command is complete
  *
  *	In some cases, this function translates SCSI commands into
  *	ATA taskfiles, and queues the taskfiles to be sent to
@@ -3161,37 +3177,36 @@
  *	ATA and ATAPI devices appearing as SCSI devices.
  *
  *	LOCKING:
- *	Releases scsi-layer-held lock, and obtains host lock.
+ *	ATA host lock
  *
  *	RETURNS:
  *	Return value from __ata_scsi_queuecmd() if @cmd can be queued,
  *	0 otherwise.
  */
-int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 {
 	struct ata_port *ap;
 	struct ata_device *dev;
 	struct scsi_device *scsidev = cmd->device;
-	struct Scsi_Host *shost = scsidev->host;
 	int rc = 0;
+	unsigned long irq_flags;
 
 	ap = ata_shost_to_port(shost);
 
-	spin_unlock(shost->host_lock);
-	spin_lock(ap->lock);
+	spin_lock_irqsave(ap->lock, irq_flags);
 
 	ata_scsi_dump_cdb(ap, cmd);
 
 	dev = ata_scsi_find_dev(ap, scsidev);
 	if (likely(dev))
-		rc = __ata_scsi_queuecmd(cmd, done, dev);
+		rc = __ata_scsi_queuecmd(cmd, cmd->scsi_done, dev);
 	else {
 		cmd->result = (DID_BAD_TARGET << 16);
-		done(cmd);
+		cmd->scsi_done(cmd);
 	}
 
-	spin_unlock(ap->lock);
-	spin_lock(shost->host_lock);
+	spin_unlock_irqrestore(ap->lock, irq_flags);
+
 	return rc;
 }
 
@@ -3250,6 +3265,9 @@
 		case 0xb1:
 			ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
 			break;
+		case 0xb2:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
+			break;
 		default:
 			ata_scsi_invalid_field(cmd, done);
 			break;
@@ -3334,7 +3352,7 @@
 		*(struct ata_port **)&shost->hostdata[0] = ap;
 		ap->scsi_host = shost;
 
-		shost->transportt = &ata_scsi_transport_template;
+		shost->transportt = ata_scsi_transport_template;
 		shost->unique_id = ap->print_id;
 		shost->max_id = 16;
 		shost->max_lun = 1;
@@ -3393,6 +3411,8 @@
 			if (!IS_ERR(sdev)) {
 				dev->sdev = sdev;
 				scsi_device_put(sdev);
+			} else {
+				dev->sdev = NULL;
 			}
 		}
 	}
@@ -3616,8 +3636,8 @@
  *	RETURNS:
  *	Zero.
  */
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
-			      unsigned int id, unsigned int lun)
+int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+		       unsigned int id, unsigned int lun)
 {
 	struct ata_port *ap = ata_shost_to_port(shost);
 	unsigned long flags;
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-sff.c linux-libre-2.6.37-gnu/drivers/ata/libata-sff.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-sff.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-sff.c	2011-01-04 19:50:19.000000000 -0500
@@ -222,7 +222,7 @@
 	timeout = ata_deadline(timer_start, tmout_pat);
 	while (status != 0xff && (status & ATA_BUSY) &&
 	       time_before(jiffies, timeout)) {
-		msleep(50);
+		ata_msleep(ap, 50);
 		status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
 	}
 
@@ -234,7 +234,7 @@
 	timeout = ata_deadline(timer_start, tmout);
 	while (status != 0xff && (status & ATA_BUSY) &&
 	       time_before(jiffies, timeout)) {
-		msleep(50);
+		ata_msleep(ap, 50);
 		status = ap->ops->sff_check_status(ap);
 	}
 
@@ -360,7 +360,7 @@
 
 	if (wait) {
 		if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
-			msleep(150);
+			ata_msleep(ap, 150);
 		ata_wait_idle(ap);
 	}
 }
@@ -1356,7 +1356,7 @@
 	 */
 	status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
 	if (status & ATA_BUSY) {
-		msleep(2);
+		ata_msleep(ap, 2);
 		status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
 		if (status & ATA_BUSY) {
 			ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
@@ -1532,11 +1532,10 @@
 		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
 			return ata_sff_idle_irq(ap);
 		break;
-	case HSM_ST:
-	case HSM_ST_LAST:
-		break;
-	default:
+	case HSM_ST_IDLE:
 		return ata_sff_idle_irq(ap);
+	default:
+		break;
 	}
 
 	/* check main status, clearing INTRQ if needed */
@@ -1937,7 +1936,7 @@
 	unsigned int dev1 = devmask & (1 << 1);
 	int rc, ret = 0;
 
-	msleep(ATA_WAIT_AFTER_RESET);
+	ata_msleep(ap, ATA_WAIT_AFTER_RESET);
 
 	/* always check readiness of the master device */
 	rc = ata_sff_wait_ready(link, deadline);
@@ -1966,7 +1965,7 @@
 			lbal = ioread8(ioaddr->lbal_addr);
 			if ((nsect == 1) && (lbal == 1))
 				break;
-			msleep(50);	/* give drive a breather */
+			ata_msleep(ap, 50);	/* give drive a breather */
 		}
 
 		rc = ata_sff_wait_ready(link, deadline);
@@ -3335,14 +3334,14 @@
 
 int __init ata_sff_init(void)
 {
-	ata_sff_wq = alloc_workqueue("ata_sff", WQ_RESCUER, WQ_MAX_ACTIVE);
+	ata_sff_wq = alloc_workqueue("ata_sff", WQ_MEM_RECLAIM, WQ_MAX_ACTIVE);
 	if (!ata_sff_wq)
 		return -ENOMEM;
 
 	return 0;
 }
 
-void __exit ata_sff_exit(void)
+void ata_sff_exit(void)
 {
 	destroy_workqueue(ata_sff_wq);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-transport.c linux-libre-2.6.37-gnu/drivers/ata/libata-transport.c
--- linux-libre-2.6.36-gnu/drivers/ata/libata-transport.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-transport.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,774 @@
+/*
+ *  Copyright 2008 ioogle, Inc.  All rights reserved.
+ *	Released under GPL v2.
+ *
+ * Libata transport class.
+ *
+ * The ATA transport class contains common code to deal with ATA HBAs,
+ * an approximated representation of ATA topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and management
+ * interfaces to user-space.
+ *
+ * There are 3 objects defined in in this class:
+ * - ata_port
+ * - ata_link
+ * - ata_device
+ * Each port has a link object. Each link can have up to two devices for PATA
+ * and generally one for SATA.
+ * If there is SATA port multiplier [PMP], 15 additional ata_link object are
+ * created.
+ *
+ * These objects are created when the ata host is initialized and when a PMP is
+ * found. They are removed only when the HBA is removed, cleaned before the
+ * error handler runs.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <scsi/scsi_transport.h>
+#include <linux/libata.h>
+#include <linux/hdreg.h>
+#include <linux/uaccess.h>
+
+#include "libata.h"
+#include "libata-transport.h"
+
+#define ATA_PORT_ATTRS		2
+#define ATA_LINK_ATTRS		3
+#define ATA_DEV_ATTRS		9
+
+struct scsi_transport_template;
+struct scsi_transport_template *ata_scsi_transport_template;
+
+struct ata_internal {
+	struct scsi_transport_template t;
+
+	struct device_attribute private_port_attrs[ATA_PORT_ATTRS];
+	struct device_attribute private_link_attrs[ATA_LINK_ATTRS];
+	struct device_attribute private_dev_attrs[ATA_DEV_ATTRS];
+
+	struct transport_container link_attr_cont;
+	struct transport_container dev_attr_cont;
+
+	/*
+	 * The array of null terminated pointers to attributes
+	 * needed by scsi_sysfs.c
+	 */
+	struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1];
+	struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1];
+	struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1];
+};
+#define to_ata_internal(tmpl)	container_of(tmpl, struct ata_internal, t)
+
+
+#define tdev_to_device(d)					\
+	container_of((d), struct ata_device, tdev)
+#define transport_class_to_dev(dev)				\
+	tdev_to_device((dev)->parent)
+
+#define tdev_to_link(d)						\
+	container_of((d), struct ata_link, tdev)
+#define transport_class_to_link(dev)				\
+	tdev_to_link((dev)->parent)
+
+#define tdev_to_port(d)						\
+	container_of((d), struct ata_port, tdev)
+#define transport_class_to_port(dev)				\
+	tdev_to_port((dev)->parent)
+
+
+/* Device objects are always created whit link objects */
+static int ata_tdev_add(struct ata_device *dev);
+static void ata_tdev_delete(struct ata_device *dev);
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+	struct device_attribute device_attr_##_prefix##_##_name = \
+	__ATTR(_name,_mode,_show,_store)
+
+#define ata_bitfield_name_match(title, table)			\
+static ssize_t							\
+get_ata_##title##_names(u32 table_key, char *buf)		\
+{								\
+	char *prefix = "";					\
+	ssize_t len = 0;					\
+	int i;							\
+								\
+	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
+		if (table[i].value & table_key) {		\
+			len += sprintf(buf + len, "%s%s",	\
+				prefix, table[i].name);		\
+			prefix = ", ";				\
+		}						\
+	}							\
+	len += sprintf(buf + len, "\n");			\
+	return len;						\
+}
+
+#define ata_bitfield_name_search(title, table)			\
+static ssize_t							\
+get_ata_##title##_names(u32 table_key, char *buf)		\
+{								\
+	ssize_t len = 0;					\
+	int i;							\
+								\
+	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
+		if (table[i].value == table_key) {		\
+			len += sprintf(buf + len, "%s",		\
+				table[i].name);			\
+			break;					\
+		}						\
+	}							\
+	len += sprintf(buf + len, "\n");			\
+	return len;						\
+}
+
+static struct {
+	u32		value;
+	char		*name;
+} ata_class_names[] = {
+	{ ATA_DEV_UNKNOWN,		"unknown" },
+	{ ATA_DEV_ATA,			"ata" },
+	{ ATA_DEV_ATA_UNSUP,		"ata" },
+	{ ATA_DEV_ATAPI,		"atapi" },
+	{ ATA_DEV_ATAPI_UNSUP,		"atapi" },
+	{ ATA_DEV_PMP,			"pmp" },
+	{ ATA_DEV_PMP_UNSUP,		"pmp" },
+	{ ATA_DEV_SEMB,			"semb" },
+	{ ATA_DEV_SEMB_UNSUP,		"semb" },
+	{ ATA_DEV_NONE,			"none" }
+};
+ata_bitfield_name_search(class, ata_class_names)
+
+
+static struct {
+	u32		value;
+	char		*name;
+} ata_err_names[] = {
+	{ AC_ERR_DEV,			"DeviceError" },
+	{ AC_ERR_HSM,			"HostStateMachineError" },
+	{ AC_ERR_TIMEOUT,		"Timeout" },
+	{ AC_ERR_MEDIA,			"MediaError" },
+	{ AC_ERR_ATA_BUS,		"BusError" },
+	{ AC_ERR_HOST_BUS,		"HostBusError" },
+	{ AC_ERR_SYSTEM,		"SystemError" },
+	{ AC_ERR_INVALID,		"InvalidArg" },
+	{ AC_ERR_OTHER,			"Unknown" },
+	{ AC_ERR_NODEV_HINT,		"NoDeviceHint" },
+	{ AC_ERR_NCQ,		 	"NCQError" }
+};
+ata_bitfield_name_match(err, ata_err_names)
+
+static struct {
+	u32		value;
+	char		*name;
+} ata_xfer_names[] = {
+	{ XFER_UDMA_7,			"XFER_UDMA_7" },
+	{ XFER_UDMA_6,			"XFER_UDMA_6" },
+	{ XFER_UDMA_5,			"XFER_UDMA_5" },
+	{ XFER_UDMA_4,			"XFER_UDMA_4" },
+	{ XFER_UDMA_3,			"XFER_UDMA_3" },
+	{ XFER_UDMA_2,			"XFER_UDMA_2" },
+	{ XFER_UDMA_1,			"XFER_UDMA_1" },
+	{ XFER_UDMA_0,			"XFER_UDMA_0" },
+	{ XFER_MW_DMA_4,		"XFER_MW_DMA_4" },
+	{ XFER_MW_DMA_3,		"XFER_MW_DMA_3" },
+	{ XFER_MW_DMA_2,		"XFER_MW_DMA_2" },
+	{ XFER_MW_DMA_1,		"XFER_MW_DMA_1" },
+	{ XFER_MW_DMA_0,		"XFER_MW_DMA_0" },
+	{ XFER_SW_DMA_2,		"XFER_SW_DMA_2" },
+	{ XFER_SW_DMA_1,		"XFER_SW_DMA_1" },
+	{ XFER_SW_DMA_0,		"XFER_SW_DMA_0" },
+	{ XFER_PIO_6,			"XFER_PIO_6" },
+	{ XFER_PIO_5,			"XFER_PIO_5" },
+	{ XFER_PIO_4,			"XFER_PIO_4" },
+	{ XFER_PIO_3,			"XFER_PIO_3" },
+	{ XFER_PIO_2,			"XFER_PIO_2" },
+	{ XFER_PIO_1,			"XFER_PIO_1" },
+	{ XFER_PIO_0,			"XFER_PIO_0" },
+	{ XFER_PIO_SLOW,		"XFER_PIO_SLOW" }
+};
+ata_bitfield_name_match(xfer,ata_xfer_names)
+
+/*
+ * ATA Port attributes
+ */
+#define ata_port_show_simple(field, name, format_string, cast)		\
+static ssize_t								\
+show_ata_port_##name(struct device *dev,				\
+		     struct device_attribute *attr, char *buf)		\
+{									\
+	struct ata_port *ap = transport_class_to_port(dev);		\
+									\
+	return snprintf(buf, 20, format_string, cast ap->field);	\
+}
+
+#define ata_port_simple_attr(field, name, format_string, type)		\
+	ata_port_show_simple(field, name, format_string, (type))	\
+static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
+
+ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
+ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
+
+static DECLARE_TRANSPORT_CLASS(ata_port_class,
+			       "ata_port", NULL, NULL, NULL);
+
+static void ata_tport_release(struct device *dev)
+{
+	put_device(dev->parent);
+}
+
+/**
+ * ata_is_port --  check if a struct device represents a ATA port
+ * @dev:	device to check
+ *
+ * Returns:
+ *	%1 if the device represents a ATA Port, %0 else
+ */
+int ata_is_port(const struct device *dev)
+{
+	return dev->release == ata_tport_release;
+}
+
+static int ata_tport_match(struct attribute_container *cont,
+			   struct device *dev)
+{
+	if (!ata_is_port(dev))
+		return 0;
+	return &ata_scsi_transport_template->host_attrs.ac == cont;
+}
+
+/**
+ * ata_tport_delete  --  remove ATA PORT
+ * @port:	ATA PORT to remove
+ *
+ * Removes the specified ATA PORT.  Remove the associated link as well.
+ */
+void ata_tport_delete(struct ata_port *ap)
+{
+	struct device *dev = &ap->tdev;
+
+	ata_tlink_delete(&ap->link);
+
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
+	put_device(dev);
+}
+
+/** ata_tport_add - initialize a transport ATA port structure
+ *
+ * @parent:	parent device
+ * @ap:		existing ata_port structure
+ *
+ * Initialize a ATA port structure for sysfs.  It will be added to the device
+ * tree below the device specified by @parent which could be a PCI device.
+ *
+ * Returns %0 on success
+ */
+int ata_tport_add(struct device *parent,
+		  struct ata_port *ap)
+{
+	int error;
+	struct device *dev = &ap->tdev;
+
+	device_initialize(dev);
+
+	dev->parent = get_device(parent);
+	dev->release = ata_tport_release;
+	dev_set_name(dev, "ata%d", ap->print_id);
+	transport_setup_device(dev);
+	error = device_add(dev);
+	if (error) {
+		goto tport_err;
+	}
+
+	transport_add_device(dev);
+	transport_configure_device(dev);
+
+	error = ata_tlink_add(&ap->link);
+	if (error) {
+		goto tport_link_err;
+	}
+	return 0;
+
+ tport_link_err:
+	transport_remove_device(dev);
+	device_del(dev);
+
+ tport_err:
+	transport_destroy_device(dev);
+	put_device(dev);
+	return error;
+}
+
+
+/*
+ * ATA link attributes
+ */
+
+
+#define ata_link_show_linkspeed(field)					\
+static ssize_t								\
+show_ata_link_##field(struct device *dev,				\
+		      struct device_attribute *attr, char *buf)		\
+{									\
+	struct ata_link *link = transport_class_to_link(dev);		\
+									\
+	return sprintf(buf,"%s\n", sata_spd_string(fls(link->field)));	\
+}
+
+#define ata_link_linkspeed_attr(field)					\
+	ata_link_show_linkspeed(field)					\
+static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
+
+ata_link_linkspeed_attr(hw_sata_spd_limit);
+ata_link_linkspeed_attr(sata_spd_limit);
+ata_link_linkspeed_attr(sata_spd);
+
+
+static DECLARE_TRANSPORT_CLASS(ata_link_class,
+		"ata_link", NULL, NULL, NULL);
+
+static void ata_tlink_release(struct device *dev)
+{
+	put_device(dev->parent);
+}
+
+/**
+ * ata_is_link --  check if a struct device represents a ATA link
+ * @dev:	device to check
+ *
+ * Returns:
+ *	%1 if the device represents a ATA link, %0 else
+ */
+int ata_is_link(const struct device *dev)
+{
+	return dev->release == ata_tlink_release;
+}
+
+static int ata_tlink_match(struct attribute_container *cont,
+			   struct device *dev)
+{
+	struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+	if (!ata_is_link(dev))
+		return 0;
+	return &i->link_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tlink_delete  --  remove ATA LINK
+ * @port:	ATA LINK to remove
+ *
+ * Removes the specified ATA LINK.  remove associated ATA device(s) as well.
+ */
+void ata_tlink_delete(struct ata_link *link)
+{
+	struct device *dev = &link->tdev;
+	struct ata_device *ata_dev;
+
+	ata_for_each_dev(ata_dev, link, ALL) {
+		ata_tdev_delete(ata_dev);
+	}
+
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
+	put_device(dev);
+}
+
+/**
+ * ata_tlink_add  --  initialize a transport ATA link structure
+ * @link:	allocated ata_link structure.
+ *
+ * Initialize an ATA LINK structure for sysfs.  It will be added in the
+ * device tree below the ATA PORT it belongs to.
+ *
+ * Returns %0 on success
+ */
+int ata_tlink_add(struct ata_link *link)
+{
+	struct device *dev = &link->tdev;
+	struct ata_port *ap = link->ap;
+	struct ata_device *ata_dev;
+	int error;
+
+	device_initialize(dev);
+	dev->parent = get_device(&ap->tdev);
+	dev->release = ata_tlink_release;
+	if (ata_is_host_link(link))
+		dev_set_name(dev, "link%d", ap->print_id);
+        else
+		dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
+
+	transport_setup_device(dev);
+
+	error = device_add(dev);
+	if (error) {
+		goto tlink_err;
+	}
+
+	transport_add_device(dev);
+	transport_configure_device(dev);
+
+	ata_for_each_dev(ata_dev, link, ALL) {
+		error = ata_tdev_add(ata_dev);
+		if (error) {
+			goto tlink_dev_err;
+		}
+	}
+	return 0;
+  tlink_dev_err:
+	while (--ata_dev >= link->device) {
+		ata_tdev_delete(ata_dev);
+	}
+	transport_remove_device(dev);
+	device_del(dev);
+  tlink_err:
+	transport_destroy_device(dev);
+	put_device(dev);
+	return error;
+}
+
+/*
+ * ATA device attributes
+ */
+
+#define ata_dev_show_class(title, field)				\
+static ssize_t								\
+show_ata_dev_##field(struct device *dev,				\
+		     struct device_attribute *attr, char *buf)		\
+{									\
+	struct ata_device *ata_dev = transport_class_to_dev(dev);	\
+									\
+	return get_ata_##title##_names(ata_dev->field, buf);		\
+}
+
+#define ata_dev_attr(title, field)					\
+	ata_dev_show_class(title, field)				\
+static DEVICE_ATTR(field, S_IRUGO, show_ata_dev_##field, NULL)
+
+ata_dev_attr(class, class);
+ata_dev_attr(xfer, pio_mode);
+ata_dev_attr(xfer, dma_mode);
+ata_dev_attr(xfer, xfer_mode);
+
+
+#define ata_dev_show_simple(field, format_string, cast)		\
+static ssize_t								\
+show_ata_dev_##field(struct device *dev,				\
+		     struct device_attribute *attr, char *buf)		\
+{									\
+	struct ata_device *ata_dev = transport_class_to_dev(dev);	\
+									\
+	return snprintf(buf, 20, format_string, cast ata_dev->field);	\
+}
+
+#define ata_dev_simple_attr(field, format_string, type)	\
+	ata_dev_show_simple(field, format_string, (type))	\
+static DEVICE_ATTR(field, S_IRUGO, 			\
+		   show_ata_dev_##field, NULL)
+
+ata_dev_simple_attr(spdn_cnt, "%d\n", int);
+
+struct ata_show_ering_arg {
+	char* buf;
+	int written;
+};
+
+static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
+{
+	struct ata_show_ering_arg* arg = void_arg;
+	struct timespec time;
+
+	jiffies_to_timespec(ent->timestamp,&time);
+	arg->written += sprintf(arg->buf + arg->written,
+			       "[%5lu.%06lu]",
+			       time.tv_sec, time.tv_nsec);
+	arg->written += get_ata_err_names(ent->err_mask,
+					  arg->buf + arg->written);
+	return 0;
+}
+
+static ssize_t
+show_ata_dev_ering(struct device *dev,
+		   struct device_attribute *attr, char *buf)
+{
+	struct ata_device *ata_dev = transport_class_to_dev(dev);
+	struct ata_show_ering_arg arg = { buf, 0 };
+
+	ata_ering_map(&ata_dev->ering, ata_show_ering, &arg);
+	return arg.written;
+}
+
+
+static DEVICE_ATTR(ering, S_IRUGO, show_ata_dev_ering, NULL);
+
+static ssize_t
+show_ata_dev_id(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ata_device *ata_dev = transport_class_to_dev(dev);
+	int written = 0, i = 0;
+
+	if (ata_dev->class == ATA_DEV_PMP)
+		return 0;
+	for(i=0;i<ATA_ID_WORDS;i++)  {
+		written += snprintf(buf+written, 20, "%04x%c",
+				    ata_dev->id[i],
+				    ((i+1) & 7) ? ' ' : '\n');
+	}
+	return written;
+}
+
+static DEVICE_ATTR(id, S_IRUGO, show_ata_dev_id, NULL);
+
+static ssize_t
+show_ata_dev_gscr(struct device *dev,
+		  struct device_attribute *attr, char *buf)
+{
+	struct ata_device *ata_dev = transport_class_to_dev(dev);
+	int written = 0, i = 0;
+
+	if (ata_dev->class != ATA_DEV_PMP)
+		return 0;
+	for(i=0;i<SATA_PMP_GSCR_DWORDS;i++)  {
+		written += snprintf(buf+written, 20, "%08x%c",
+				    ata_dev->gscr[i],
+				    ((i+1) & 3) ? ' ' : '\n');
+	}
+	if (SATA_PMP_GSCR_DWORDS & 3)
+		buf[written-1] = '\n';
+	return written;
+}
+
+static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
+
+static DECLARE_TRANSPORT_CLASS(ata_dev_class,
+			       "ata_device", NULL, NULL, NULL);
+
+static void ata_tdev_release(struct device *dev)
+{
+	put_device(dev->parent);
+}
+
+/**
+ * ata_is_ata_dev  --  check if a struct device represents a ATA device
+ * @dev:	device to check
+ *
+ * Returns:
+ *	%1 if the device represents a ATA device, %0 else
+ */
+int ata_is_ata_dev(const struct device *dev)
+{
+	return dev->release == ata_tdev_release;
+}
+
+static int ata_tdev_match(struct attribute_container *cont,
+			  struct device *dev)
+{
+	struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+	if (!ata_is_ata_dev(dev))
+		return 0;
+	return &i->dev_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tdev_free  --  free a ATA LINK
+ * @dev:	ATA PHY to free
+ *
+ * Frees the specified ATA PHY.
+ *
+ * Note:
+ *   This function must only be called on a PHY that has not
+ *   successfully been added using ata_tdev_add().
+ */
+static void ata_tdev_free(struct ata_device *dev)
+{
+	transport_destroy_device(&dev->tdev);
+	put_device(&dev->tdev);
+}
+
+/**
+ * ata_tdev_delete  --  remove ATA device
+ * @port:	ATA PORT to remove
+ *
+ * Removes the specified ATA device.
+ */
+static void ata_tdev_delete(struct ata_device *ata_dev)
+{
+	struct device *dev = &ata_dev->tdev;
+
+	transport_remove_device(dev);
+	device_del(dev);
+	ata_tdev_free(ata_dev);
+}
+
+
+/**
+ * ata_tdev_add  --  initialize a transport ATA device structure.
+ * @ata_dev:	ata_dev structure.
+ *
+ * Initialize an ATA device structure for sysfs.  It will be added in the
+ * device tree below the ATA LINK device it belongs to.
+ *
+ * Returns %0 on success
+ */
+static int ata_tdev_add(struct ata_device *ata_dev)
+{
+	struct device *dev = &ata_dev->tdev;
+	struct ata_link *link = ata_dev->link;
+	struct ata_port *ap = link->ap;
+	int error;
+
+	device_initialize(dev);
+	dev->parent = get_device(&link->tdev);
+	dev->release = ata_tdev_release;
+	if (ata_is_host_link(link))
+		dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno);
+        else
+		dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp);
+
+	transport_setup_device(dev);
+	error = device_add(dev);
+	if (error) {
+		ata_tdev_free(ata_dev);
+		return error;
+	}
+
+	transport_add_device(dev);
+	transport_configure_device(dev);
+	return 0;
+}
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_TEMPLATE(attrb, field, perm, test)			\
+	i->private_##attrb[count] = dev_attr_##field;		       	\
+	i->private_##attrb[count].attr.mode = perm;			\
+	i->attrb[count] = &i->private_##attrb[count];			\
+	if (test)							\
+		count++
+
+#define SETUP_LINK_ATTRIBUTE(field)					\
+	SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
+
+#define SETUP_PORT_ATTRIBUTE(field)					\
+	SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+#define SETUP_DEV_ATTRIBUTE(field)					\
+	SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
+
+/**
+ * ata_attach_transport  --  instantiate ATA transport template
+ */
+struct scsi_transport_template *ata_attach_transport(void)
+{
+	struct ata_internal *i;
+	int count;
+
+	i = kzalloc(sizeof(struct ata_internal), GFP_KERNEL);
+	if (!i)
+		return NULL;
+
+	i->t.eh_strategy_handler	= ata_scsi_error;
+	i->t.eh_timed_out		= ata_scsi_timed_out;
+	i->t.user_scan			= ata_scsi_user_scan;
+
+	i->t.host_attrs.ac.attrs = &i->port_attrs[0];
+	i->t.host_attrs.ac.class = &ata_port_class.class;
+	i->t.host_attrs.ac.match = ata_tport_match;
+	transport_container_register(&i->t.host_attrs);
+
+	i->link_attr_cont.ac.class = &ata_link_class.class;
+	i->link_attr_cont.ac.attrs = &i->link_attrs[0];
+	i->link_attr_cont.ac.match = ata_tlink_match;
+	transport_container_register(&i->link_attr_cont);
+
+	i->dev_attr_cont.ac.class = &ata_dev_class.class;
+	i->dev_attr_cont.ac.attrs = &i->dev_attrs[0];
+	i->dev_attr_cont.ac.match = ata_tdev_match;
+	transport_container_register(&i->dev_attr_cont);
+
+	count = 0;
+	SETUP_PORT_ATTRIBUTE(nr_pmp_links);
+	SETUP_PORT_ATTRIBUTE(idle_irq);
+	BUG_ON(count > ATA_PORT_ATTRS);
+	i->port_attrs[count] = NULL;
+
+	count = 0;
+	SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit);
+	SETUP_LINK_ATTRIBUTE(sata_spd_limit);
+	SETUP_LINK_ATTRIBUTE(sata_spd);
+	BUG_ON(count > ATA_LINK_ATTRS);
+	i->link_attrs[count] = NULL;
+
+	count = 0;
+	SETUP_DEV_ATTRIBUTE(class);
+	SETUP_DEV_ATTRIBUTE(pio_mode);
+	SETUP_DEV_ATTRIBUTE(dma_mode);
+	SETUP_DEV_ATTRIBUTE(xfer_mode);
+	SETUP_DEV_ATTRIBUTE(spdn_cnt);
+	SETUP_DEV_ATTRIBUTE(ering);
+	SETUP_DEV_ATTRIBUTE(id);
+	SETUP_DEV_ATTRIBUTE(gscr);
+	BUG_ON(count > ATA_DEV_ATTRS);
+	i->dev_attrs[count] = NULL;
+
+	return &i->t;
+}
+
+/**
+ * ata_release_transport  --  release ATA transport template instance
+ * @t:		transport template instance
+ */
+void ata_release_transport(struct scsi_transport_template *t)
+{
+	struct ata_internal *i = to_ata_internal(t);
+
+	transport_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->link_attr_cont);
+	transport_container_unregister(&i->dev_attr_cont);
+
+	kfree(i);
+}
+
+__init int libata_transport_init(void)
+{
+	int error;
+
+	error = transport_class_register(&ata_link_class);
+	if (error)
+		goto out_unregister_transport;
+	error = transport_class_register(&ata_port_class);
+	if (error)
+		goto out_unregister_link;
+	error = transport_class_register(&ata_dev_class);
+	if (error)
+		goto out_unregister_port;
+	return 0;
+
+ out_unregister_port:
+	transport_class_unregister(&ata_port_class);
+ out_unregister_link:
+	transport_class_unregister(&ata_link_class);
+ out_unregister_transport:
+	return error;
+
+}
+
+void __exit libata_transport_exit(void)
+{
+	transport_class_unregister(&ata_link_class);
+	transport_class_unregister(&ata_port_class);
+	transport_class_unregister(&ata_dev_class);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/ata/libata-transport.h linux-libre-2.6.37-gnu/drivers/ata/libata-transport.h
--- linux-libre-2.6.36-gnu/drivers/ata/libata-transport.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/ata/libata-transport.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,18 @@
+#ifndef _LIBATA_TRANSPORT_H
+#define _LIBATA_TRANSPORT_H
+
+
+extern struct scsi_transport_template *ata_scsi_transport_template;
+
+int ata_tlink_add(struct ata_link *link);
+void ata_tlink_delete(struct ata_link *link);
+
+int ata_tport_add(struct device *parent, struct ata_port *ap);
+void ata_tport_delete(struct ata_port *ap);
+
+struct scsi_transport_template *ata_attach_transport(void);
+void ata_release_transport(struct scsi_transport_template *t);
+
+__init int libata_transport_init(void);
+void __exit libata_transport_exit(void);
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/ata/Makefile linux-libre-2.6.37-gnu/drivers/ata/Makefile
--- linux-libre-2.6.36-gnu/drivers/ata/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,6 @@
 
 # SFF w/ custom DMA
 obj-$(CONFIG_PDC_ADMA)		+= pdc_adma.o
-obj-$(CONFIG_PATA_MPC52xx)	+= pata_mpc52xx.o
 obj-$(CONFIG_PATA_OCTEON_CF)	+= pata_octeon_cf.o
 obj-$(CONFIG_SATA_QSTOR)	+= sata_qstor.o
 obj-$(CONFIG_SATA_SX4)		+= sata_sx4.o
@@ -52,6 +51,7 @@
 obj-$(CONFIG_PATA_JMICRON)	+= pata_jmicron.o
 obj-$(CONFIG_PATA_MACIO)	+= pata_macio.o
 obj-$(CONFIG_PATA_MARVELL)	+= pata_marvell.o
+obj-$(CONFIG_PATA_MPC52xx)	+= pata_mpc52xx.o
 obj-$(CONFIG_PATA_NETCELL)	+= pata_netcell.o
 obj-$(CONFIG_PATA_NINJA32)	+= pata_ninja32.o
 obj-$(CONFIG_PATA_NS87415)	+= pata_ns87415.o
@@ -99,7 +99,7 @@
 # Should be last libata driver
 obj-$(CONFIG_PATA_LEGACY)	+= pata_legacy.o
 
-libata-objs	:= libata-core.o libata-scsi.o libata-eh.o
+libata-y	:= libata-core.o libata-scsi.o libata-eh.o libata-transport.o
 libata-$(CONFIG_ATA_SFF)	+= libata-sff.o
 libata-$(CONFIG_SATA_PMP)	+= libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)	+= libata-acpi.o
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_bf54x.c linux-libre-2.6.37-gnu/drivers/ata/pata_bf54x.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_bf54x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_bf54x.c	2011-01-04 19:50:19.000000000 -0500
@@ -826,7 +826,7 @@
  *	@ctl: value to write
  */
 
-static u8 bfin_set_devctl(struct ata_port *ap, u8 ctl)
+static void bfin_set_devctl(struct ata_port *ap, u8 ctl)
 {
 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
 	write_atapi_register(base, ATA_REG_CTRL, ctl);
@@ -1046,7 +1046,7 @@
 			dev1 = 0;
 			break;
 		}
-		msleep(50);	/* give drive a breather */
+		ata_msleep(ap, 50);	/* give drive a breather */
 	}
 	if (dev1)
 		ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
@@ -1087,7 +1087,7 @@
 	 *
 	 * Old drivers/ide uses the 2mS rule and then waits for ready
 	 */
-	msleep(150);
+	ata_msleep(ap, 150);
 
 	/* Before we perform post reset processing we want to see if
 	 * the bus shows 0xFF because the odd clown forgets the D7
@@ -1588,7 +1588,7 @@
 	host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
 
 	if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
-		dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+		dev_err(&pdev->dev, "Requesting Peripherals failed\n");
 		return -EFAULT;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_cmd640.c linux-libre-2.6.37-gnu/drivers/ata/pata_cmd640.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_cmd640.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_cmd640.c	2011-01-04 19:50:19.000000000 -0500
@@ -161,6 +161,17 @@
 	return 0;
 }
 
+static bool cmd640_sff_irq_check(struct ata_port *ap)
+{
+	struct pci_dev *pdev	= to_pci_dev(ap->host->dev);
+	int irq_reg		= ap->port_no ? ARTIM23 : CFR;
+	u8  irq_stat, irq_mask	= ap->port_no ? 0x10 : 0x04;
+
+	pci_read_config_byte(pdev, irq_reg, &irq_stat);
+
+	return irq_stat & irq_mask;
+}
+
 static struct scsi_host_template cmd640_sht = {
 	ATA_PIO_SHT(DRV_NAME),
 };
@@ -169,6 +180,7 @@
 	.inherits	= &ata_sff_port_ops,
 	/* In theory xfer_noirq is not needed once we kill the prefetcher */
 	.sff_data_xfer	= ata_sff_data_xfer_noirq,
+	.sff_irq_check	= cmd640_sff_irq_check,
 	.qc_issue	= cmd640_qc_issue,
 	.cable_detect	= ata_cable_40wire,
 	.set_piomode	= cmd640_set_piomode,
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_cs5536.c linux-libre-2.6.37-gnu/drivers/ata/pata_cs5536.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_cs5536.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_cs5536.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,10 +37,22 @@
 #include <linux/delay.h>
 #include <linux/libata.h>
 #include <scsi/scsi_host.h>
+
+#ifdef CONFIG_X86_32
 #include <asm/msr.h>
+static int use_msr;
+module_param_named(msr, use_msr, int, 0644);
+MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
+#else
+#undef rdmsr	/* avoid accidental MSR usage on, e.g. x86-64 */
+#undef wrmsr
+#define rdmsr(x, y, z) do { } while (0)
+#define wrmsr(x, y, z) do { } while (0)
+#define use_msr 0
+#endif
 
 #define DRV_NAME	"pata_cs5536"
-#define DRV_VERSION	"0.0.7"
+#define DRV_VERSION	"0.0.8"
 
 enum {
 	CFG			= 0,
@@ -75,8 +87,6 @@
 	IDE_ETC_NODMA		= 0x03,
 };
 
-static int use_msr;
-
 static const u32 msr_reg[4] = {
 	MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC,
 };
@@ -88,7 +98,7 @@
 static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)
 {
 	if (unlikely(use_msr)) {
-		u32 dummy;
+		u32 dummy __maybe_unused;
 
 		rdmsr(msr_reg[reg], *val, dummy);
 		return 0;
@@ -294,8 +304,6 @@
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, cs5536);
 MODULE_VERSION(DRV_VERSION);
-module_param_named(msr, use_msr, int, 0644);
-MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");
 
 module_init(cs5536_init);
 module_exit(cs5536_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_it821x.c linux-libre-2.6.37-gnu/drivers/ata/pata_it821x.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_it821x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_it821x.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,8 +15,8 @@
  *  May be copied or modified under the terms of the GNU General Public License
  *  Based in part on the ITE vendor provided SCSI driver.
  *
- *  Documentation available from
- * 	http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ *  Documentation available from IT8212F_V04.pdf
+ * 	http://www.ite.com.tw/EN/products_more.aspx?CategoryID=3&ID=5,91
  *  Some other documents are NDA.
  *
  *  The ITE8212 isn't exactly a standard IDE controller. It has two
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_legacy.c linux-libre-2.6.37-gnu/drivers/ata/pata_legacy.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_legacy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_legacy.c	2011-01-04 19:50:19.000000000 -0500
@@ -142,7 +142,7 @@
 static int pio_mask = ATA_PIO4;	/* PIO range for autospeed devices */
 static int iordy_mask = 0xFFFFFFFF;	/* Use iordy if available */
 
-#ifdef PATA_WINBOND_VLB_MODULE
+#ifdef CONFIG_PATA_WINBOND_VLB_MODULE
 static int winbond = 1;		/* Set to probe Winbond controllers,
 					give I/O port if non standard */
 #else
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_octeon_cf.c linux-libre-2.6.37-gnu/drivers/ata/pata_octeon_cf.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_octeon_cf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_octeon_cf.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 	 * Compute # of eclock periods to get desired duration in
 	 * nanoseconds.
 	 */
-	val = DIV_ROUND_UP(nsecs * (octeon_get_clock_rate() / 1000000),
+	val = DIV_ROUND_UP(nsecs * (octeon_get_io_clock_rate() / 1000000),
 			  1000 * tim_mult);
 
 	return val;
@@ -653,8 +653,6 @@
 
 		ap = host->ports[i];
 		ocd = ap->dev->platform_data;
-
-		ocd = ap->dev->platform_data;
 		cf_port = ap->private_data;
 		dma_int.u64 =
 			cvmx_read_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine));
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_pcmcia.c linux-libre-2.6.37-gnu/drivers/ata/pata_pcmcia.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_pcmcia.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_pcmcia.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,6 @@
 #include <linux/ata.h>
 #include <linux/libata.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
@@ -168,63 +167,26 @@
 };
 
 
-struct pcmcia_config_check {
-	unsigned long ctl_base;
-	int skip_vcc;
-	int is_kme;
-};
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev,
-				   cistpl_cftable_entry_t *cfg,
-				   cistpl_cftable_entry_t *dflt,
-				   unsigned int vcc,
-				   void *priv_data)
+static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
 {
-	struct pcmcia_config_check *stk = priv_data;
+	int *is_kme = priv_data;
 
-	/* Check for matching Vcc, unless we're desperate */
-	if (!stk->skip_vcc) {
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-				return -ENODEV;
-		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
-				return -ENODEV;
-		}
+	if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) {
+		pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+		pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 	}
+	pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+	pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
 
-	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-		pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-		pdev->resource[0]->start = io->win[0].base;
-		if (!(io->flags & CISTPL_IO_16BIT)) {
-			pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-			pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-		}
-		if (io->nwin == 2) {
-			pdev->resource[0]->end = 8;
-			pdev->resource[1]->start = io->win[1].base;
-			pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
-			if (pcmcia_request_io(pdev) != 0)
-				return -ENODEV;
-			stk->ctl_base = pdev->resource[1]->start;
-		} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-			pdev->resource[0]->end = io->win[0].len;
-			pdev->resource[1]->end = 0;
-			if (pcmcia_request_io(pdev) != 0)
-				return -ENODEV;
-			stk->ctl_base = pdev->resource[0]->start + 0x0e;
-		} else
+	if (pdev->resource[1]->end) {
+		pdev->resource[0]->end = 8;
+		pdev->resource[1]->end = (*is_kme) ? 2 : 1;
+	} else {
+		if (pdev->resource[0]->end < 16)
 			return -ENODEV;
-		/* If we've got this far, we're done */
-		return 0;
 	}
-	return -ENODEV;
+
+	return pcmcia_request_io(pdev);
 }
 
 /**
@@ -239,7 +201,6 @@
 {
 	struct ata_host *host;
 	struct ata_port *ap;
-	struct pcmcia_config_check *stk = NULL;
 	int is_kme = 0, ret = -ENOMEM, p;
 	unsigned long io_base, ctl_base;
 	void __iomem *io_addr, *ctl_addr;
@@ -247,10 +208,8 @@
 	struct ata_port_operations *ops = &pcmcia_port_ops;
 
 	/* Set up attributes in order to probe card and get resources */
-	pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	pdev->conf.Attributes = CONF_ENABLE_IRQ;
-	pdev->conf.IntType = INT_MEMORY_AND_IO;
+	pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
+		CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
 
 	/* See if we have a manufacturer identifier. Use it to set is_kme for
 	   vendor quirks */
@@ -258,25 +217,21 @@
 		  ((pdev->card_id == PRODID_KME_KXLC005_A) ||
 		   (pdev->card_id == PRODID_KME_KXLC005_B)));
 
-	/* Allocate resoure probing structures */
-
-	stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-	if (!stk)
-		goto out1;
-	stk->is_kme = is_kme;
-	stk->skip_vcc = io_base = ctl_base = 0;
-
-	if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) {
-		stk->skip_vcc = 1;
-		if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
+	if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme)) {
+		pdev->config_flags &= ~CONF_AUTO_CHECK_VCC;
+		if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme))
 			goto failed; /* No suitable config found */
 	}
 	io_base = pdev->resource[0]->start;
-	ctl_base = stk->ctl_base;
+	if (pdev->resource[1]->end)
+		ctl_base = pdev->resource[1]->start;
+	else
+		ctl_base = pdev->resource[0]->start + 0x0e;
+
 	if (!pdev->irq)
 		goto failed;
 
-	ret = pcmcia_request_configuration(pdev, &pdev->conf);
+	ret = pcmcia_enable_device(pdev);
 	if (ret)
 		goto failed;
 
@@ -329,13 +284,10 @@
 		goto failed;
 
 	pdev->priv = host;
-	kfree(stk);
 	return 0;
 
 failed:
-	kfree(stk);
 	pcmcia_disable_device(pdev);
-out1:
 	return ret;
 }
 
@@ -430,9 +382,7 @@
 
 static struct pcmcia_driver pcmcia_driver = {
 	.owner		= THIS_MODULE,
-	.drv = {
-		.name		= DRV_NAME,
-	},
+	.name		= DRV_NAME,
 	.id_table	= pcmcia_devices,
 	.probe		= pcmcia_init_one,
 	.remove		= pcmcia_remove_one,
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_pdc202xx_old.c linux-libre-2.6.37-gnu/drivers/ata/pata_pdc202xx_old.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_pdc202xx_old.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_pdc202xx_old.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,6 +44,27 @@
 	ndelay(400);
 }
 
+static bool pdc202xx_irq_check(struct ata_port *ap)
+{
+	struct pci_dev *pdev	= to_pci_dev(ap->host->dev);
+	unsigned long master	= pci_resource_start(pdev, 4);
+	u8 sc1d			= inb(master + 0x1d);
+
+	if (ap->port_no) {
+		/*
+		 * bit 7: error, bit 6: interrupting,
+		 * bit 5: FIFO full, bit 4: FIFO empty
+		 */
+		return sc1d & 0x40;
+	} else	{
+		/*
+		 * bit 3: error, bit 2: interrupting,
+		 * bit 1: FIFO full, bit 0: FIFO empty
+		 */
+		return sc1d & 0x04;
+	}
+}
+
 /**
  *	pdc202xx_configure_piomode	-	set chip PIO timing
  *	@ap: ATA interface
@@ -282,6 +303,7 @@
 	.set_dmamode		= pdc202xx_set_dmamode,
 
 	.sff_exec_command	= pdc202xx_exec_command,
+	.sff_irq_check		= pdc202xx_irq_check,
 };
 
 static struct ata_port_operations pdc2026x_port_ops = {
@@ -297,6 +319,7 @@
 	.port_start		= pdc2026x_port_start,
 
 	.sff_exec_command	= pdc202xx_exec_command,
+	.sff_irq_check		= pdc202xx_irq_check,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_samsung_cf.c linux-libre-2.6.37-gnu/drivers/ata/pata_samsung_cf.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_samsung_cf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_samsung_cf.c	2011-01-04 19:50:19.000000000 -0500
@@ -322,7 +322,7 @@
 {
 	int rc;
 
-	msleep(ATA_WAIT_AFTER_RESET);
+	ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
 
 	/* always check readiness of the master device */
 	rc = ata_sff_wait_ready(link, deadline);
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_scc.c linux-libre-2.6.37-gnu/drivers/ata/pata_scc.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_scc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_scc.c	2011-01-04 19:50:19.000000000 -0500
@@ -530,7 +530,7 @@
 	 *
 	 * Old drivers/ide uses the 2mS rule and then waits for ready.
 	 */
-	msleep(150);
+	ata_msleep(ap, 150);
 
 	/* always check readiness of the master device */
 	rc = ata_sff_wait_ready(link, deadline);
@@ -559,7 +559,7 @@
 			lbal = in_be32(ioaddr->lbal_addr);
 			if ((nsect == 1) && (lbal == 1))
 				break;
-			msleep(50);	/* give drive a breather */
+			ata_msleep(ap, 50);	/* give drive a breather */
 		}
 
 		rc = ata_sff_wait_ready(link, deadline);
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_sil680.c linux-libre-2.6.37-gnu/drivers/ata/pata_sil680.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_sil680.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_sil680.c	2011-01-04 19:50:19.000000000 -0500
@@ -202,14 +202,25 @@
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
  */
-void sil680_sff_exec_command(struct ata_port *ap,
-					const struct ata_taskfile *tf)
+static void sil680_sff_exec_command(struct ata_port *ap,
+				    const struct ata_taskfile *tf)
 {
 	DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
 	iowrite8(tf->command, ap->ioaddr.command_addr);
 	ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+static bool sil680_sff_irq_check(struct ata_port *ap)
+{
+	struct pci_dev *pdev	= to_pci_dev(ap->host->dev);
+	unsigned long addr	= sil680_selreg(ap, 1);
+	u8 val;
+
+	pci_read_config_byte(pdev, addr, &val);
+
+	return val & 0x08;
+}
+
 static struct scsi_host_template sil680_sht = {
 	ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -218,6 +229,7 @@
 static struct ata_port_operations sil680_port_ops = {
 	.inherits		= &ata_bmdma32_port_ops,
 	.sff_exec_command	= sil680_sff_exec_command,
+	.sff_irq_check		= sil680_sff_irq_check,
 	.cable_detect		= sil680_cable_detect,
 	.set_piomode		= sil680_set_piomode,
 	.set_dmamode		= sil680_set_dmamode,
diff -druN linux-libre-2.6.36-gnu/drivers/ata/pata_sl82c105.c linux-libre-2.6.37-gnu/drivers/ata/pata_sl82c105.c
--- linux-libre-2.6.36-gnu/drivers/ata/pata_sl82c105.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/pata_sl82c105.c	2011-01-04 19:50:19.000000000 -0500
@@ -227,6 +227,16 @@
 	return 0;
 }
 
+static bool sl82c105_sff_irq_check(struct ata_port *ap)
+{
+	struct pci_dev *pdev	= to_pci_dev(ap->host->dev);
+	u32 val, mask		= ap->port_no ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+
+	pci_read_config_dword(pdev, 0x40, &val);
+
+	return val & mask;
+}
+
 static struct scsi_host_template sl82c105_sht = {
 	ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -239,6 +249,7 @@
 	.cable_detect	= ata_cable_40wire,
 	.set_piomode	= sl82c105_set_piomode,
 	.prereset	= sl82c105_pre_reset,
+	.sff_irq_check	= sl82c105_sff_irq_check,
 };
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_fsl.c linux-libre-2.6.37-gnu/drivers/ata/sata_fsl.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_fsl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_fsl.c	2011-01-04 19:50:19.000000000 -0500
@@ -678,7 +678,7 @@
 	iowrite32(temp, hcr_base + HCONTROL);
 
 	/* Poll for controller to go offline - should happen immediately */
-	ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
+	ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
 
 	ap->private_data = NULL;
 	dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
@@ -729,7 +729,8 @@
 	iowrite32(temp, hcr_base + HCONTROL);
 
 	/* Poll for controller to go offline */
-	temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500);
+	temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE,
+				 1, 500);
 
 	if (temp & ONLINE) {
 		ata_port_printk(ap, KERN_ERR,
@@ -752,7 +753,7 @@
 	/*
 	 * PHY reset should remain asserted for atleast 1ms
 	 */
-	msleep(1);
+	ata_msleep(ap, 1);
 
 	/*
 	 * Now, bring the host controller online again, this can take time
@@ -766,7 +767,7 @@
 	temp |= HCONTROL_PMP_ATTACHED;
 	iowrite32(temp, hcr_base + HCONTROL);
 
-	temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
+	temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500);
 
 	if (!(temp & ONLINE)) {
 		ata_port_printk(ap, KERN_ERR,
@@ -784,7 +785,7 @@
 	 * presence
 	 */
 
-	temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500);
+	temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500);
 	if ((!(temp & 0x10)) || ata_link_offline(link)) {
 		ata_port_printk(ap, KERN_WARNING,
 				"No Device OR PHYRDY change,Hstatus = 0x%x\n",
@@ -797,7 +798,7 @@
 	 * Wait for the first D2H from device,i.e,signature update notification
 	 */
 	start_jiffies = jiffies;
-	temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10,
+	temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0x10,
 			500, jiffies_to_msecs(deadline - start_jiffies));
 
 	if ((temp & 0xFF) != 0x18) {
@@ -880,7 +881,7 @@
 		iowrite32(pmp, CQPMP + hcr_base);
 	iowrite32(1, CQ + hcr_base);
 
-	temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
+	temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000);
 	if (temp & 0x1) {
 		ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n");
 
@@ -896,7 +897,7 @@
 		goto err;
 	}
 
-	msleep(1);
+	ata_msleep(ap, 1);
 
 	/*
 	 * SATA device enters reset state after receving a Control register
@@ -915,7 +916,7 @@
 	if (pmp != SATA_PMP_CTRL_PORT)
 		iowrite32(pmp, CQPMP + hcr_base);
 	iowrite32(1, CQ + hcr_base);
-	msleep(150);		/* ?? */
+	ata_msleep(ap, 150);		/* ?? */
 
 	/*
 	 * The above command would have signalled an interrupt on command
@@ -1137,17 +1138,13 @@
 			ioread32(hcr_base + CE));
 
 		for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
-			if (done_mask & (1 << i)) {
-				qc = ata_qc_from_tag(ap, i);
-				if (qc) {
-					ata_qc_complete(qc);
-				}
+			if (done_mask & (1 << i))
 				DPRINTK
 				    ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
 				     i, ioread32(hcr_base + CC),
 				     ioread32(hcr_base + CA));
-			}
 		}
+		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
 		return;
 
 	} else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_inic162x.c linux-libre-2.6.37-gnu/drivers/ata/sata_inic162x.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_inic162x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_inic162x.c	2011-01-04 19:50:19.000000000 -0500
@@ -614,7 +614,7 @@
 
 	writew(IDMA_CTL_RST_ATA, idma_ctl);
 	readw(idma_ctl);	/* flush */
-	msleep(1);
+	ata_msleep(ap, 1);
 	writew(0, idma_ctl);
 
 	rc = sata_link_resume(link, timing, deadline);
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_mv.c linux-libre-2.6.37-gnu/drivers/ata/sata_mv.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_mv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_mv.c	2011-01-04 19:50:19.000000000 -0500
@@ -2743,18 +2743,11 @@
 	}
 }
 
-static void mv_process_crpb_response(struct ata_port *ap,
+static bool mv_process_crpb_response(struct ata_port *ap,
 		struct mv_crpb *response, unsigned int tag, int ncq_enabled)
 {
 	u8 ata_status;
 	u16 edma_status = le16_to_cpu(response->flags);
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
-
-	if (unlikely(!qc)) {
-		ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
-				__func__, tag);
-		return;
-	}
 
 	/*
 	 * edma_status from a response queue entry:
@@ -2768,13 +2761,14 @@
 			 * Error will be seen/handled by
 			 * mv_err_intr().  So do nothing at all here.
 			 */
-			return;
+			return false;
 		}
 	}
 	ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
 	if (!ac_err_mask(ata_status))
-		ata_qc_complete(qc);
+		return true;
 	/* else: leave it for mv_err_intr() */
+	return false;
 }
 
 static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
@@ -2783,6 +2777,7 @@
 	struct mv_host_priv *hpriv = ap->host->private_data;
 	u32 in_index;
 	bool work_done = false;
+	u32 done_mask = 0;
 	int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
 
 	/* Get the hardware queue position index */
@@ -2803,15 +2798,19 @@
 			/* Gen II/IIE: get command tag from CRPB entry */
 			tag = le16_to_cpu(response->id) & 0x1f;
 		}
-		mv_process_crpb_response(ap, response, tag, ncq_enabled);
+		if (mv_process_crpb_response(ap, response, tag, ncq_enabled))
+			done_mask |= 1 << tag;
 		work_done = true;
 	}
 
-	/* Update the software queue position index in hardware */
-	if (work_done)
+	if (work_done) {
+		ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+
+		/* Update the software queue position index in hardware */
 		writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
 			 (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
 			 port_mmio + EDMA_RSP_Q_OUT_PTR);
+	}
 }
 
 static void mv_port_intr(struct ata_port *ap, u32 port_cause)
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_nv.c linux-libre-2.6.37-gnu/drivers/ata/sata_nv.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_nv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_nv.c	2011-01-04 19:50:19.000000000 -0500
@@ -873,29 +873,11 @@
 			ata_port_freeze(ap);
 		else
 			ata_port_abort(ap);
-		return 1;
+		return -1;
 	}
 
-	if (likely(flags & NV_CPB_RESP_DONE)) {
-		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
-		VPRINTK("CPB flags done, flags=0x%x\n", flags);
-		if (likely(qc)) {
-			DPRINTK("Completing qc from tag %d\n", cpb_num);
-			ata_qc_complete(qc);
-		} else {
-			struct ata_eh_info *ehi = &ap->link.eh_info;
-			/* Notifier bits set without a command may indicate the drive
-			   is misbehaving. Raise host state machine violation on this
-			   condition. */
-			ata_port_printk(ap, KERN_ERR,
-					"notifier for tag %d with no cmd?\n",
-					cpb_num);
-			ehi->err_mask |= AC_ERR_HSM;
-			ehi->action |= ATA_EH_RESET;
-			ata_port_freeze(ap);
-			return 1;
-		}
-	}
+	if (likely(flags & NV_CPB_RESP_DONE))
+		return 1;
 	return 0;
 }
 
@@ -1018,6 +1000,7 @@
 			      NV_ADMA_STAT_CPBERR |
 			      NV_ADMA_STAT_CMD_COMPLETE)) {
 			u32 check_commands = notifier_clears[i];
+			u32 done_mask = 0;
 			int pos, rc;
 
 			if (status & NV_ADMA_STAT_CPBERR) {
@@ -1034,10 +1017,13 @@
 				pos--;
 				rc = nv_adma_check_cpb(ap, pos,
 						notifier_error & (1 << pos));
-				if (unlikely(rc))
+				if (rc > 0)
+					done_mask |= 1 << pos;
+				else if (unlikely(rc < 0))
 					check_commands = 0;
 				check_commands &= ~(1 << pos);
 			}
+			ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
 		}
 	}
 
@@ -2132,7 +2118,6 @@
 	struct ata_eh_info *ehi = &ap->link.eh_info;
 	u32 sactive;
 	u32 done_mask;
-	int i;
 	u8 host_stat;
 	u8 lack_dhfis = 0;
 
@@ -2152,27 +2137,11 @@
 	sactive = readl(pp->sactive_block);
 	done_mask = pp->qc_active ^ sactive;
 
-	if (unlikely(done_mask & sactive)) {
-		ata_ehi_clear_desc(ehi);
-		ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
-				  "(%08x->%08x)", pp->qc_active, sactive);
-		ehi->err_mask |= AC_ERR_HSM;
-		ehi->action |= ATA_EH_RESET;
-		return -EINVAL;
-	}
-	for (i = 0; i < ATA_MAX_QUEUE; i++) {
-		if (!(done_mask & (1 << i)))
-			continue;
-
-		qc = ata_qc_from_tag(ap, i);
-		if (qc) {
-			ata_qc_complete(qc);
-			pp->qc_active &= ~(1 << i);
-			pp->dhfis_bits &= ~(1 << i);
-			pp->dmafis_bits &= ~(1 << i);
-			pp->sdbfis_bits |= (1 << i);
-		}
-	}
+	pp->qc_active &= ~done_mask;
+	pp->dhfis_bits &= ~done_mask;
+	pp->dmafis_bits &= ~done_mask;
+	pp->sdbfis_bits |= done_mask;
+	ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
 
 	if (!ap->qc_active) {
 		DPRINTK("over\n");
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_sil24.c linux-libre-2.6.37-gnu/drivers/ata/sata_sil24.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_sil24.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_sil24.c	2011-01-04 19:50:19.000000000 -0500
@@ -589,9 +589,9 @@
 		sil24_clear_pmp(ap);
 
 	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
-	ata_wait_register(port + PORT_CTRL_STAT,
+	ata_wait_register(ap, port + PORT_CTRL_STAT,
 			  PORT_CS_INIT, PORT_CS_INIT, 10, 100);
-	tmp = ata_wait_register(port + PORT_CTRL_STAT,
+	tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
 				PORT_CS_RDY, 0, 10, 100);
 
 	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
@@ -631,7 +631,7 @@
 	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
 
 	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+	irq_stat = ata_wait_register(ap, port + PORT_IRQ_STAT, irq_mask, 0x0,
 				     10, timeout_msec);
 
 	writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
@@ -719,9 +719,9 @@
 				"state, performing PORT_RST\n");
 
 		writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
-		msleep(10);
+		ata_msleep(ap, 10);
 		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
-		ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+		ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
 				  10, 5000);
 
 		/* restore port configuration */
@@ -740,7 +740,7 @@
 		tout_msec = 5000;
 
 	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
-	tmp = ata_wait_register(port + PORT_CTRL_STAT,
+	tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
 				PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,
 				tout_msec);
 
@@ -1253,7 +1253,7 @@
 		tmp = readl(port + PORT_CTRL_STAT);
 		if (tmp & PORT_CS_PORT_RST) {
 			writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
-			tmp = ata_wait_register(port + PORT_CTRL_STAT,
+			tmp = ata_wait_register(NULL, port + PORT_CTRL_STAT,
 						PORT_CS_PORT_RST,
 						PORT_CS_PORT_RST, 10, 100);
 			if (tmp & PORT_CS_PORT_RST)
diff -druN linux-libre-2.6.36-gnu/drivers/ata/sata_via.c linux-libre-2.6.37-gnu/drivers/ata/sata_via.c
--- linux-libre-2.6.36-gnu/drivers/ata/sata_via.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ata/sata_via.c	2011-01-04 19:50:19.000000000 -0500
@@ -349,7 +349,7 @@
 
 	/* wait for phy to become ready, if necessary */
 	do {
-		msleep(200);
+		ata_msleep(link->ap, 200);
 		svia_scr_read(link, SCR_STATUS, &sstatus);
 		if ((sstatus & 0xf) != 1)
 			break;
@@ -538,7 +538,7 @@
 	return 0;
 }
 
-static void svia_configure(struct pci_dev *pdev)
+static void svia_configure(struct pci_dev *pdev, int board_id)
 {
 	u8 tmp8;
 
@@ -577,7 +577,7 @@
 	}
 
 	/*
-	 * vt6421 has problems talking to some drives.  The following
+	 * vt6420/1 has problems talking to some drives.  The following
 	 * is the fix from Joseph Chan <JosephChan@via.com.tw>.
 	 *
 	 * When host issues HOLD, device may send up to 20DW of data
@@ -596,8 +596,9 @@
 	 *
 	 * https://bugzilla.kernel.org/show_bug.cgi?id=15173
 	 * http://article.gmane.org/gmane.linux.ide/46352
+	 * http://thread.gmane.org/gmane.linux.kernel/1062139
 	 */
-	if (pdev->device == 0x3249) {
+	if (board_id == vt6420 || board_id == vt6421) {
 		pci_read_config_byte(pdev, 0x52, &tmp8);
 		tmp8 |= 1 << 2;
 		pci_write_config_byte(pdev, 0x52, tmp8);
@@ -652,7 +653,7 @@
 	if (rc)
 		return rc;
 
-	svia_configure(pdev);
+	svia_configure(pdev, board_id);
 
 	pci_set_master(pdev);
 	return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
diff -druN linux-libre-2.6.36-gnu/drivers/atm/adummy.c linux-libre-2.6.37-gnu/drivers/atm/adummy.c
--- linux-libre-2.6.36-gnu/drivers/atm/adummy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/adummy.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,7 +154,7 @@
 		err = -ENOMEM;
 		goto out;
 	}
-	atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
+	atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL);
 	if (!atm_dev) {
 		printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
 		err = -ENODEV;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/ambassador.c linux-libre-2.6.37-gnu/drivers/atm/ambassador.c
--- linux-libre-2.6.36-gnu/drivers/atm/ambassador.c	2012-03-23 21:38:36.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/ambassador.c	2012-03-23 23:29:43.000000000 -0400
@@ -2244,7 +2244,8 @@
 		goto out_reset;
 	}
 
-	dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
+	dev->atm_dev = atm_dev_register (DEV_LABEL, &pci_dev->dev, &amb_ops, -1,
+					 NULL);
 	if (!dev->atm_dev) {
 		PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
 		err = -EINVAL;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/atmtcp.c linux-libre-2.6.37-gnu/drivers/atm/atmtcp.c
--- linux-libre-2.6.36-gnu/drivers/atm/atmtcp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/atmtcp.c	2011-01-04 19:50:19.000000000 -0500
@@ -366,7 +366,7 @@
 	if (!dev_data)
 		return -ENOMEM;
 
-	dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
+	dev = atm_dev_register(DEV_LABEL,NULL,&atmtcp_v_dev_ops,itf,NULL);
 	if (!dev) {
 		kfree(dev_data);
 		return itf == -1 ? -ENOMEM : -EBUSY;
@@ -392,7 +392,10 @@
 			atm_dev_put(dev);
 			return -EMEDIUMTYPE;
 		}
-		if (PRIV(dev)->vcc) return -EBUSY;
+		if (PRIV(dev)->vcc) {
+			atm_dev_put(dev);
+			return -EBUSY;
+		}
 	}
 	else {
 		int error;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/eni.c linux-libre-2.6.37-gnu/drivers/atm/eni.c
--- linux-libre-2.6.36-gnu/drivers/atm/eni.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/eni.c	2011-01-04 19:50:19.000000000 -0500
@@ -1736,9 +1736,10 @@
 		eprom = (base+EPROM_SIZE-sizeof(struct midway_eprom));
 		if (readl(&eprom->magic) != ENI155_MAGIC) {
 			printk("\n");
-			printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
-			    "magic - expected 0x%x, got 0x%x\n",dev->number,
-			    ENI155_MAGIC,(unsigned) readl(&eprom->magic));
+			printk(KERN_ERR DEV_LABEL
+			       "(itf %d): bad magic - expected 0x%x, got 0x%x\n",
+			       dev->number, ENI155_MAGIC,
+			       (unsigned)readl(&eprom->magic));
 			error = -EINVAL;
 			goto unmap;
 		}
@@ -2243,7 +2244,7 @@
 		    &zeroes);
 		if (!cpu_zeroes) goto out1;
 	}
-	dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
+	dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
 	if (!dev) goto out2;
 	pci_set_drvdata(pci_dev, dev);
 	eni_dev->pci_dev = pci_dev;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/firestream.c linux-libre-2.6.37-gnu/drivers/atm/firestream.c
--- linux-libre-2.6.36-gnu/drivers/atm/firestream.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/firestream.c	2011-01-04 19:50:19.000000000 -0500
@@ -444,8 +444,8 @@
 #define ROUND_NEAREST 3
 /********** make rate (not quite as much fun as Horizon) **********/
 
-static unsigned int make_rate (unsigned int rate, int r,
-			       u16 * bits, unsigned int * actual) 
+static int make_rate(unsigned int rate, int r,
+		      u16 *bits, unsigned int *actual)
 {
 	unsigned char exp = -1; /* hush gcc */
 	unsigned int man = -1;  /* hush gcc */
@@ -1911,7 +1911,7 @@
 		    fs_dev, sizeof (struct fs_dev));
 	if (!fs_dev)
 		goto err_out;
-	atm_dev = atm_dev_register("fs", &ops, -1, NULL);
+	atm_dev = atm_dev_register("fs", &pci_dev->dev, &ops, -1, NULL);
 	if (!atm_dev)
 		goto err_out_free_fs_dev;
   
diff -druN linux-libre-2.6.36-gnu/drivers/atm/fore200e.c linux-libre-2.6.37-gnu/drivers/atm/fore200e.c
--- linux-libre-2.6.36-gnu/drivers/atm/fore200e.c	2012-03-23 21:38:45.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/fore200e.c	2012-03-23 23:29:53.000000000 -0400
@@ -2563,14 +2563,14 @@
 
 
 static int __devinit
-fore200e_register(struct fore200e* fore200e)
+fore200e_register(struct fore200e* fore200e, struct device *parent)
 {
     struct atm_dev* atm_dev;
 
     DPRINTK(2, "device %s being registered\n", fore200e->name);
 
-    atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1,
-      NULL); 
+    atm_dev = atm_dev_register(fore200e->bus->proc_name, parent, &fore200e_ops,
+                               -1, NULL);
     if (atm_dev == NULL) {
 	printk(FORE200E "unable to register device %s\n", fore200e->name);
 	return -ENODEV;
@@ -2590,9 +2590,9 @@
 
 
 static int __devinit
-fore200e_init(struct fore200e* fore200e)
+fore200e_init(struct fore200e* fore200e, struct device *parent)
 {
-    if (fore200e_register(fore200e) < 0)
+    if (fore200e_register(fore200e, parent) < 0)
 	return -ENODEV;
     
     if (fore200e->bus->configure(fore200e) < 0)
@@ -2658,7 +2658,7 @@
 
 	sprintf(fore200e->name, "%s-%d", bus->model_name, index);
 
-	err = fore200e_init(fore200e);
+	err = fore200e_init(fore200e, &op->dev);
 	if (err < 0) {
 		fore200e_shutdown(fore200e);
 		kfree(fore200e);
@@ -2736,7 +2736,7 @@
 
     sprintf(fore200e->name, "%s-%d", bus->model_name, index);
 
-    err = fore200e_init(fore200e);
+    err = fore200e_init(fore200e, &pci_dev->dev);
     if (err < 0) {
 	fore200e_shutdown(fore200e);
 	goto out_free;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/he.c linux-libre-2.6.37-gnu/drivers/atm/he.c
--- linux-libre-2.6.36-gnu/drivers/atm/he.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/he.c	2011-01-04 19:50:19.000000000 -0500
@@ -366,7 +366,7 @@
 		goto init_one_failure;
 	}
 
-	atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, NULL);
+	atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL);
 	if (!atm_dev) {
 		err = -ENODEV;
 		goto init_one_failure;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/horizon.c linux-libre-2.6.37-gnu/drivers/atm/horizon.c
--- linux-libre-2.6.36-gnu/drivers/atm/horizon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/horizon.c	2011-01-04 19:50:19.000000000 -0500
@@ -1645,10 +1645,8 @@
     unsigned short d = 0;
     char * s = skb->data;
     if (*s++ == 'D') {
-      for (i = 0; i < 4; ++i) {
-	d = (d<<4) | ((*s <= '9') ? (*s - '0') : (*s - 'a' + 10));
-	++s;
-      }
+	for (i = 0; i < 4; ++i)
+		d = (d << 4) | hex_to_bin(*s++);
       PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d);
     }
   }
@@ -2735,7 +2733,8 @@
 	PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p",
 	       iobase, irq, membase);
 
-	dev->atm_dev = atm_dev_register(DEV_LABEL, &hrz_ops, -1, NULL);
+	dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1,
+					NULL);
 	if (!(dev->atm_dev)) {
 		PRINTD(DBG_ERR, "failed to register Madge ATM adapter");
 		err = -EINVAL;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/idt77252.c linux-libre-2.6.37-gnu/drivers/atm/idt77252.c
--- linux-libre-2.6.36-gnu/drivers/atm/idt77252.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/idt77252.c	2011-01-04 19:50:19.000000000 -0500
@@ -3152,7 +3152,7 @@
 }
 
 
-static int __devinit
+static void __devinit
 init_sram(struct idt77252_dev *card)
 {
 	int i;
@@ -3298,7 +3298,6 @@
 	       SAR_REG_RXFD);
 
 	IPRINTK("%s: SRAM initialization complete.\n", card->name);
-	return 0;
 }
 
 static int __devinit
@@ -3410,8 +3409,7 @@
 
 	writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG);
 
-	if (init_sram(card) < 0)
-		return -1;
+	init_sram(card);
 
 /********************************************************************/
 /*  A L L O C   R A M   A N D   S E T   V A R I O U S   T H I N G S */
@@ -3700,7 +3698,8 @@
 		goto err_out_iounmap;
 	}
 
-	dev = atm_dev_register("idt77252", &idt77252_ops, -1, NULL);
+	dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1,
+			       NULL);
 	if (!dev) {
 		printk("%s: can't register atm device\n", card->name);
 		err = -EIO;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/iphase.c linux-libre-2.6.37-gnu/drivers/atm/iphase.c
--- linux-libre-2.6.36-gnu/drivers/atm/iphase.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/iphase.c	2011-01-04 19:50:19.000000000 -0500
@@ -220,7 +220,7 @@
   while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) {
      dev->ffL.tcq_rd += 2;
      if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) 
-     dev->ffL.tcq_rd = dev->ffL.tcq_st;
+	dev->ffL.tcq_rd = dev->ffL.tcq_st;
      if (dev->ffL.tcq_rd == dev->host_tcq_wr) 
         return 0xFFFF; 
      desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd);
@@ -3172,7 +3172,7 @@
 		ret = -ENODEV;
 		goto err_out_free_iadev;
 	}
-	dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+	dev = atm_dev_register(DEV_LABEL, &pdev->dev, &ops, -1, NULL);
 	if (!dev) {
 		ret = -ENOMEM;
 		goto err_out_disable_dev;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/Kconfig linux-libre-2.6.37-gnu/drivers/atm/Kconfig
--- linux-libre-2.6.36-gnu/drivers/atm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -301,7 +301,7 @@
 	  control memory (128K-1KVC, 512K-4KVC), the size of the packet
 	  memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3,
 	  UTP155, UTP25, DS3 and E3). Go to:
-	  	<http://www.iphase.com/products/ClassSheet.cfm?ClassID=ATM>
+	  	<http://www.iphase.com/>
 	  for more info about the cards. Say Y (or M to compile as a module
 	  named iphase) here if you have one of these cards.
 
diff -druN linux-libre-2.6.36-gnu/drivers/atm/lanai.c linux-libre-2.6.37-gnu/drivers/atm/lanai.c
--- linux-libre-2.6.36-gnu/drivers/atm/lanai.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/lanai.c	2011-01-04 19:50:19.000000000 -0500
@@ -2591,7 +2591,7 @@
 		return -ENOMEM;
 	}
 
-	atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+	atmdev = atm_dev_register(DEV_LABEL, &pci->dev, &ops, -1, NULL);
 	if (atmdev == NULL) {
 		printk(KERN_ERR DEV_LABEL
 		    ": couldn't register atm device!\n");
diff -druN linux-libre-2.6.36-gnu/drivers/atm/Makefile linux-libre-2.6.37-gnu/drivers/atm/Makefile
--- linux-libre-2.6.36-gnu/drivers/atm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
 # Makefile for the Linux network (ATM) device drivers.
 #
 
-fore_200e-objs	:= fore200e.o
+fore_200e-y	:= fore200e.o
 
 obj-$(CONFIG_ATM_ZATM)		+= zatm.o uPD98402.o
 obj-$(CONFIG_ATM_NICSTAR)	+= nicstar.o
diff -druN linux-libre-2.6.36-gnu/drivers/atm/nicstar.c linux-libre-2.6.37-gnu/drivers/atm/nicstar.c
--- linux-libre-2.6.36-gnu/drivers/atm/nicstar.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/nicstar.c	2011-01-04 19:50:19.000000000 -0500
@@ -771,7 +771,8 @@
 	}
 
 	/* Register device */
-	card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+	card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops,
+					-1, NULL);
 	if (card->atmdev == NULL) {
 		printk("nicstar%d: can't register device.\n", i);
 		error = 17;
diff -druN linux-libre-2.6.36-gnu/drivers/atm/solos-attrlist.c linux-libre-2.6.37-gnu/drivers/atm/solos-attrlist.c
--- linux-libre-2.6.36-gnu/drivers/atm/solos-attrlist.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/solos-attrlist.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,7 @@
 SOLOS_ATTR_RO(DriverVersion)
 SOLOS_ATTR_RO(APIVersion)
 SOLOS_ATTR_RO(FirmwareVersion)
+SOLOS_ATTR_RO(Version)
 // SOLOS_ATTR_RO(DspVersion)
 // SOLOS_ATTR_RO(CommonHandshake)
 SOLOS_ATTR_RO(Connected)
diff -druN linux-libre-2.6.36-gnu/drivers/atm/solos-pci.c linux-libre-2.6.37-gnu/drivers/atm/solos-pci.c
--- linux-libre-2.6.36-gnu/drivers/atm/solos-pci.c	2012-03-23 21:39:00.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/solos-pci.c	2012-03-23 23:30:14.000000000 -0400
@@ -164,7 +164,7 @@
 static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
 static int list_vccs(int vci);
 static void release_vccs(struct atm_dev *dev);
-static int atm_init(struct solos_card *);
+static int atm_init(struct solos_card *, struct device *);
 static void atm_remove(struct solos_card *);
 static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
 static void solos_bh(unsigned long);
@@ -1159,6 +1159,14 @@
 	dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
 		 major_ver, minor_ver, fpga_ver);
 
+	if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade ||
+			      db_fpga_upgrade || db_firmware_upgrade)) {
+		dev_warn(&dev->dev,
+			 "FPGA too old; cannot upgrade flash. Use JTAG.\n");
+		fpga_upgrade = firmware_upgrade = 0;
+		db_fpga_upgrade = db_firmware_upgrade = 0;
+	}
+
 	if (card->fpga_version >= DMA_SUPPORTED){
 		card->using_dma = 1;
 	} else {
@@ -1200,7 +1208,7 @@
 	if (db_firmware_upgrade)
 		flash_upgrade(card, 3);
 
-	err = atm_init(card);
+	err = atm_init(card, &dev->dev);
 	if (err)
 		goto out_free_irq;
 
@@ -1223,7 +1231,7 @@
 	return err;
 }
 
-static int atm_init(struct solos_card *card)
+static int atm_init(struct solos_card *card, struct device *parent)
 {
 	int i;
 
@@ -1234,7 +1242,7 @@
 		skb_queue_head_init(&card->tx_queue[i]);
 		skb_queue_head_init(&card->cli_queue[i]);
 
-		card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL);
+		card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL);
 		if (!card->atmdev[i]) {
 			dev_err(&card->dev->dev, "Could not register ATM device %d\n", i);
 			atm_remove(card);
diff -druN linux-libre-2.6.36-gnu/drivers/atm/zatm.c linux-libre-2.6.37-gnu/drivers/atm/zatm.c
--- linux-libre-2.6.36-gnu/drivers/atm/zatm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/atm/zatm.c	2011-01-04 19:50:19.000000000 -0500
@@ -1597,7 +1597,7 @@
 		goto out;
 	}
 
-	dev = atm_dev_register(DEV_LABEL, &ops, -1, NULL);
+	dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL);
 	if (!dev)
 		goto out_free;
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/bus.c linux-libre-2.6.37-gnu/drivers/base/bus.c
--- linux-libre-2.6.36-gnu/drivers/base/bus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/bus.c	2011-01-04 19:50:19.000000000 -0500
@@ -440,22 +440,6 @@
 	}
 }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-static int make_deprecated_bus_links(struct device *dev)
-{
-	return sysfs_create_link(&dev->kobj,
-				 &dev->bus->p->subsys.kobj, "bus");
-}
-
-static void remove_deprecated_bus_links(struct device *dev)
-{
-	sysfs_remove_link(&dev->kobj, "bus");
-}
-#else
-static inline int make_deprecated_bus_links(struct device *dev) { return 0; }
-static inline void remove_deprecated_bus_links(struct device *dev) { }
-#endif
-
 /**
  * bus_add_device - add device to bus
  * @dev: device being added
@@ -482,15 +466,10 @@
 				&dev->bus->p->subsys.kobj, "subsystem");
 		if (error)
 			goto out_subsys;
-		error = make_deprecated_bus_links(dev);
-		if (error)
-			goto out_deprecated;
 		klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
 	}
 	return 0;
 
-out_deprecated:
-	sysfs_remove_link(&dev->kobj, "subsystem");
 out_subsys:
 	sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
 out_id:
@@ -530,7 +509,6 @@
 {
 	if (dev->bus) {
 		sysfs_remove_link(&dev->kobj, "subsystem");
-		remove_deprecated_bus_links(dev);
 		sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
 				  dev_name(dev));
 		device_remove_attrs(dev->bus, dev);
diff -druN linux-libre-2.6.36-gnu/drivers/base/class.c linux-libre-2.6.37-gnu/drivers/base/class.c
--- linux-libre-2.6.36-gnu/drivers/base/class.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/class.c	2011-01-04 19:50:19.000000000 -0500
@@ -184,9 +184,9 @@
 	if (!cls->dev_kobj)
 		cls->dev_kobj = sysfs_dev_char_kobj;
 
-#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
+#if defined(CONFIG_BLOCK)
 	/* let the block class directory show up in the root of sysfs */
-	if (cls != &block_class)
+	if (!sysfs_deprecated || cls != &block_class)
 		cp->class_subsys.kobj.kset = class_kset;
 #else
 	cp->class_subsys.kobj.kset = class_kset;
@@ -276,25 +276,6 @@
 	class_unregister(cls);
 }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-char *make_class_name(const char *name, struct kobject *kobj)
-{
-	char *class_name;
-	int size;
-
-	size = strlen(name) + strlen(kobject_name(kobj)) + 2;
-
-	class_name = kmalloc(size, GFP_KERNEL);
-	if (!class_name)
-		return NULL;
-
-	strcpy(class_name, name);
-	strcat(class_name, ":");
-	strcat(class_name, kobject_name(kobj));
-	return class_name;
-}
-#endif
-
 /**
  * class_dev_iter_init - initialize class device iterator
  * @iter: class iterator to initialize
diff -druN linux-libre-2.6.36-gnu/drivers/base/core.c linux-libre-2.6.37-gnu/drivers/base/core.c
--- linux-libre-2.6.36-gnu/drivers/base/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,6 +26,19 @@
 #include "base.h"
 #include "power/power.h"
 
+#ifdef CONFIG_SYSFS_DEPRECATED
+#ifdef CONFIG_SYSFS_DEPRECATED_V2
+long sysfs_deprecated = 1;
+#else
+long sysfs_deprecated = 0;
+#endif
+static __init int sysfs_deprecated_setup(char *arg)
+{
+	return strict_strtol(arg, 10, &sysfs_deprecated);
+}
+early_param("sysfs.deprecated", sysfs_deprecated_setup);
+#endif
+
 int (*platform_notify)(struct device *dev) = NULL;
 int (*platform_notify_remove)(struct device *dev) = NULL;
 static struct kobject *dev_kobj;
@@ -203,37 +216,6 @@
 	if (dev->driver)
 		add_uevent_var(env, "DRIVER=%s", dev->driver->name);
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	if (dev->class) {
-		struct device *parent = dev->parent;
-
-		/* find first bus device in parent chain */
-		while (parent && !parent->bus)
-			parent = parent->parent;
-		if (parent && parent->bus) {
-			const char *path;
-
-			path = kobject_get_path(&parent->kobj, GFP_KERNEL);
-			if (path) {
-				add_uevent_var(env, "PHYSDEVPATH=%s", path);
-				kfree(path);
-			}
-
-			add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
-
-			if (parent->driver)
-				add_uevent_var(env, "PHYSDEVDRIVER=%s",
-					       parent->driver->name);
-		}
-	} else if (dev->bus) {
-		add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
-		if (dev->driver)
-			add_uevent_var(env, "PHYSDEVDRIVER=%s",
-				       dev->driver->name);
-	}
-#endif
-
 	/* have the bus specific function add its stuff */
 	if (dev->bus && dev->bus->uevent) {
 		retval = dev->bus->uevent(dev, env);
@@ -251,7 +233,7 @@
 				 __func__, retval);
 	}
 
-	/* have the device type specific fuction add its stuff */
+	/* have the device type specific function add its stuff */
 	if (dev->type && dev->type->uevent) {
 		retval = dev->type->uevent(dev, env);
 		if (retval)
@@ -578,24 +560,6 @@
 	set_dev_node(dev, -1);
 }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject *get_device_parent(struct device *dev,
-					 struct device *parent)
-{
-	/* class devices without a parent live in /sys/class/<classname>/ */
-	if (dev->class && (!parent || parent->class != dev->class))
-		return &dev->class->p->class_subsys.kobj;
-	/* all other devices keep their parent */
-	else if (parent)
-		return &parent->kobj;
-
-	return NULL;
-}
-
-static inline void cleanup_device_parent(struct device *dev) {}
-static inline void cleanup_glue_dir(struct device *dev,
-				    struct kobject *glue_dir) {}
-#else
 static struct kobject *virtual_device_parent(struct device *dev)
 {
 	static struct kobject *virtual_dir = NULL;
@@ -666,6 +630,15 @@
 		struct kobject *parent_kobj;
 		struct kobject *k;
 
+#ifdef CONFIG_BLOCK
+		/* block disks show up in /sys/block */
+		if (sysfs_deprecated && dev->class == &block_class) {
+			if (parent && parent->class == &block_class)
+				return &parent->kobj;
+			return &block_class.p->class_subsys.kobj;
+		}
+#endif
+
 		/*
 		 * If we have no parent, we live in "virtual".
 		 * Class-devices with a non class-device as parent, live
@@ -719,7 +692,6 @@
 {
 	cleanup_glue_dir(dev, dev->kobj.parent);
 }
-#endif
 
 static void setup_parent(struct device *dev, struct device *parent)
 {
@@ -742,70 +714,29 @@
 	if (error)
 		goto out;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	/* stacked class devices need a symlink in the class directory */
-	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-	    device_is_not_partition(dev)) {
-		error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
-					  &dev->kobj, dev_name(dev));
-		if (error)
-			goto out_subsys;
-	}
-
 	if (dev->parent && device_is_not_partition(dev)) {
-		struct device *parent = dev->parent;
-		char *class_name;
-
-		/*
-		 * stacked class devices have the 'device' link
-		 * pointing to the bus device instead of the parent
-		 */
-		while (parent->class && !parent->bus && parent->parent)
-			parent = parent->parent;
-
-		error = sysfs_create_link(&dev->kobj,
-					  &parent->kobj,
+		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
 					  "device");
 		if (error)
-			goto out_busid;
-
-		class_name = make_class_name(dev->class->name,
-						&dev->kobj);
-		if (class_name)
-			error = sysfs_create_link(&dev->parent->kobj,
-						&dev->kobj, class_name);
-		kfree(class_name);
-		if (error)
-			goto out_device;
+			goto out_subsys;
 	}
-	return 0;
 
-out_device:
-	if (dev->parent && device_is_not_partition(dev))
-		sysfs_remove_link(&dev->kobj, "device");
-out_busid:
-	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-	    device_is_not_partition(dev))
-		sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
-				  dev_name(dev));
-#else
+#ifdef CONFIG_BLOCK
+	/* /sys/block has directories and does not need symlinks */
+	if (sysfs_deprecated && dev->class == &block_class)
+		return 0;
+#endif
+
 	/* link in the class directory pointing to the device */
 	error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
 				  &dev->kobj, dev_name(dev));
 	if (error)
-		goto out_subsys;
+		goto out_device;
 
-	if (dev->parent && device_is_not_partition(dev)) {
-		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
-					  "device");
-		if (error)
-			goto out_busid;
-	}
 	return 0;
 
-out_busid:
-	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
-#endif
+out_device:
+	sysfs_remove_link(&dev->kobj, "device");
 
 out_subsys:
 	sysfs_remove_link(&dev->kobj, "subsystem");
@@ -818,30 +749,14 @@
 	if (!dev->class)
 		return;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	if (dev->parent && device_is_not_partition(dev)) {
-		char *class_name;
-
-		class_name = make_class_name(dev->class->name, &dev->kobj);
-		if (class_name) {
-			sysfs_remove_link(&dev->parent->kobj, class_name);
-			kfree(class_name);
-		}
-		sysfs_remove_link(&dev->kobj, "device");
-	}
-
-	if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
-	    device_is_not_partition(dev))
-		sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj,
-				  dev_name(dev));
-#else
 	if (dev->parent && device_is_not_partition(dev))
 		sysfs_remove_link(&dev->kobj, "device");
-
-	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
-#endif
-
 	sysfs_remove_link(&dev->kobj, "subsystem");
+#ifdef CONFIG_BLOCK
+	if (sysfs_deprecated && dev->class == &block_class)
+		return;
+#endif
+	sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev));
 }
 
 /**
@@ -1613,41 +1528,23 @@
 	pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev),
 		 __func__, new_name);
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	if ((dev->class) && (dev->parent))
-		old_class_name = make_class_name(dev->class->name, &dev->kobj);
-#endif
-
 	old_device_name = kstrdup(dev_name(dev), GFP_KERNEL);
 	if (!old_device_name) {
 		error = -ENOMEM;
 		goto out;
 	}
 
-#ifndef CONFIG_SYSFS_DEPRECATED
 	if (dev->class) {
 		error = sysfs_rename_link(&dev->class->p->class_subsys.kobj,
 			&dev->kobj, old_device_name, new_name);
 		if (error)
 			goto out;
 	}
-#endif
+
 	error = kobject_rename(&dev->kobj, new_name);
 	if (error)
 		goto out;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-	if (old_class_name) {
-		new_class_name = make_class_name(dev->class->name, &dev->kobj);
-		if (new_class_name) {
-			error = sysfs_rename_link(&dev->parent->kobj,
-						  &dev->kobj,
-						  old_class_name,
-						  new_class_name);
-		}
-	}
-#endif
-
 out:
 	put_device(dev);
 
@@ -1664,40 +1561,13 @@
 				   struct device *new_parent)
 {
 	int error = 0;
-#ifdef CONFIG_SYSFS_DEPRECATED
-	char *class_name;
 
-	class_name = make_class_name(dev->class->name, &dev->kobj);
-	if (!class_name) {
-		error = -ENOMEM;
-		goto out;
-	}
-	if (old_parent) {
-		sysfs_remove_link(&dev->kobj, "device");
-		sysfs_remove_link(&old_parent->kobj, class_name);
-	}
-	if (new_parent) {
-		error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
-					  "device");
-		if (error)
-			goto out;
-		error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
-					  class_name);
-		if (error)
-			sysfs_remove_link(&dev->kobj, "device");
-	} else
-		error = 0;
-out:
-	kfree(class_name);
-	return error;
-#else
 	if (old_parent)
 		sysfs_remove_link(&dev->kobj, "device");
 	if (new_parent)
 		error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
 					  "device");
 	return error;
-#endif
 }
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/base/devtmpfs.c linux-libre-2.6.37-gnu/drivers/base/devtmpfs.c
--- linux-libre-2.6.36-gnu/drivers/base/devtmpfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/devtmpfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,33 +29,33 @@
 static struct vfsmount *dev_mnt;
 
 #if defined CONFIG_DEVTMPFS_MOUNT
-static int dev_mount = 1;
+static int mount_dev = 1;
 #else
-static int dev_mount;
+static int mount_dev;
 #endif
 
 static DEFINE_MUTEX(dirlock);
 
 static int __init mount_param(char *str)
 {
-	dev_mount = simple_strtoul(str, NULL, 0);
+	mount_dev = simple_strtoul(str, NULL, 0);
 	return 1;
 }
 __setup("devtmpfs.mount=", mount_param);
 
-static int dev_get_sb(struct file_system_type *fs_type, int flags,
-		      const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *dev_mount(struct file_system_type *fs_type, int flags,
+		      const char *dev_name, void *data)
 {
 #ifdef CONFIG_TMPFS
-	return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
+	return mount_single(fs_type, flags, data, shmem_fill_super);
 #else
-	return get_sb_single(fs_type, flags, data, ramfs_fill_super, mnt);
+	return mount_single(fs_type, flags, data, ramfs_fill_super);
 #endif
 }
 
 static struct file_system_type dev_fs_type = {
 	.name = "devtmpfs",
-	.get_sb = dev_get_sb,
+	.mount = dev_mount,
 	.kill_sb = kill_litter_super,
 };
 
@@ -351,7 +351,7 @@
 {
 	int err;
 
-	if (!dev_mount)
+	if (!mount_dev)
 		return 0;
 
 	if (!dev_mnt)
diff -druN linux-libre-2.6.36-gnu/drivers/base/Kconfig linux-libre-2.6.37-gnu/drivers/base/Kconfig
--- linux-libre-2.6.36-gnu/drivers/base/Kconfig	2012-03-23 22:03:10.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/Kconfig	2012-03-23 23:53:49.000000000 -0400
@@ -71,7 +71,6 @@
 
 config FW_LOADER
 	tristate "Userspace firmware loading support" if EMBEDDED
-	depends on HOTPLUG
 	default y
 	---help---
 	  This option is provided for the case where no in-kernel-tree modules
diff -druN linux-libre-2.6.36-gnu/drivers/base/Makefile linux-libre-2.6.37-gnu/drivers/base/Makefile
--- linux-libre-2.6.36-gnu/drivers/base/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,5 @@
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 
-ifeq ($(CONFIG_DEBUG_DRIVER),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/memory.c linux-libre-2.6.37-gnu/drivers/base/memory.c
--- linux-libre-2.6.36-gnu/drivers/base/memory.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/memory.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,6 +27,8 @@
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 
+static DEFINE_MUTEX(mem_sysfs_mutex);
+
 #define MEMORY_CLASS_NAME	"memory"
 
 static struct sysdev_class memory_sysdev_class = {
@@ -435,6 +437,45 @@
 	return 0;
 }
 
+struct memory_block *find_memory_block_hinted(struct mem_section *section,
+					      struct memory_block *hint)
+{
+	struct kobject *kobj;
+	struct sys_device *sysdev;
+	struct memory_block *mem;
+	char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
+
+	kobj = hint ? &hint->sysdev.kobj : NULL;
+
+	/*
+	 * This only works because we know that section == sysdev->id
+	 * slightly redundant with sysdev_register()
+	 */
+	sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section));
+
+	kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj);
+	if (!kobj)
+		return NULL;
+
+	sysdev = container_of(kobj, struct sys_device, kobj);
+	mem = container_of(sysdev, struct memory_block, sysdev);
+
+	return mem;
+}
+
+/*
+ * For now, we have a linear search to go find the appropriate
+ * memory_block corresponding to a particular phys_index. If
+ * this gets to be a real problem, we can always use a radix
+ * tree or something here.
+ *
+ * This could be made generic for all sysdev classes.
+ */
+struct memory_block *find_memory_block(struct mem_section *section)
+{
+	return find_memory_block_hinted(section, NULL);
+}
+
 static int add_memory_block(int nid, struct mem_section *section,
 			unsigned long state, enum mem_add_context context)
 {
@@ -445,8 +486,11 @@
 	if (!mem)
 		return -ENOMEM;
 
+	mutex_lock(&mem_sysfs_mutex);
+
 	mem->phys_index = __section_nr(section);
 	mem->state = state;
+	mem->section_count++;
 	mutex_init(&mem->state_mutex);
 	start_pfn = section_nr_to_pfn(mem->phys_index);
 	mem->phys_device = arch_get_memory_phys_device(start_pfn);
@@ -465,53 +509,29 @@
 			ret = register_mem_sect_under_node(mem, nid);
 	}
 
+	mutex_unlock(&mem_sysfs_mutex);
 	return ret;
 }
 
-/*
- * For now, we have a linear search to go find the appropriate
- * memory_block corresponding to a particular phys_index. If
- * this gets to be a real problem, we can always use a radix
- * tree or something here.
- *
- * This could be made generic for all sysdev classes.
- */
-struct memory_block *find_memory_block(struct mem_section *section)
-{
-	struct kobject *kobj;
-	struct sys_device *sysdev;
-	struct memory_block *mem;
-	char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
-
-	/*
-	 * This only works because we know that section == sysdev->id
-	 * slightly redundant with sysdev_register()
-	 */
-	sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section));
-
-	kobj = kset_find_obj(&memory_sysdev_class.kset, name);
-	if (!kobj)
-		return NULL;
-
-	sysdev = container_of(kobj, struct sys_device, kobj);
-	mem = container_of(sysdev, struct memory_block, sysdev);
-
-	return mem;
-}
-
 int remove_memory_block(unsigned long node_id, struct mem_section *section,
 		int phys_device)
 {
 	struct memory_block *mem;
 
+	mutex_lock(&mem_sysfs_mutex);
 	mem = find_memory_block(section);
-	unregister_mem_sect_under_nodes(mem);
-	mem_remove_simple_file(mem, phys_index);
-	mem_remove_simple_file(mem, state);
-	mem_remove_simple_file(mem, phys_device);
-	mem_remove_simple_file(mem, removable);
-	unregister_memory(mem, section);
 
+	mem->section_count--;
+	if (mem->section_count == 0) {
+		unregister_mem_sect_under_nodes(mem);
+		mem_remove_simple_file(mem, phys_index);
+		mem_remove_simple_file(mem, state);
+		mem_remove_simple_file(mem, phys_device);
+		mem_remove_simple_file(mem, removable);
+		unregister_memory(mem, section);
+	}
+
+	mutex_unlock(&mem_sysfs_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/node.c linux-libre-2.6.37-gnu/drivers/base/node.c
--- linux-libre-2.6.36-gnu/drivers/base/node.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/node.c	2011-01-04 19:50:19.000000000 -0500
@@ -160,6 +160,18 @@
 }
 static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
 
+static ssize_t node_read_vmstat(struct sys_device *dev,
+				struct sysdev_attribute *attr, char *buf)
+{
+	int nid = dev->id;
+	return sprintf(buf,
+		"nr_written %lu\n"
+		"nr_dirtied %lu\n",
+		node_page_state(nid, NR_WRITTEN),
+		node_page_state(nid, NR_DIRTIED));
+}
+static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
+
 static ssize_t node_read_distance(struct sys_device * dev,
 			struct sysdev_attribute *attr, char * buf)
 {
@@ -243,6 +255,7 @@
 		sysdev_create_file(&node->sysdev, &attr_meminfo);
 		sysdev_create_file(&node->sysdev, &attr_numastat);
 		sysdev_create_file(&node->sysdev, &attr_distance);
+		sysdev_create_file(&node->sysdev, &attr_vmstat);
 
 		scan_unevictable_register_node(node);
 
@@ -267,6 +280,7 @@
 	sysdev_remove_file(&node->sysdev, &attr_meminfo);
 	sysdev_remove_file(&node->sysdev, &attr_numastat);
 	sysdev_remove_file(&node->sysdev, &attr_distance);
+	sysdev_remove_file(&node->sysdev, &attr_vmstat);
 
 	scan_unevictable_unregister_node(node);
 	hugetlb_unregister_node(node);		/* no-op, if memoryless node */
@@ -409,25 +423,27 @@
 	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
 	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
 	unsigned long pfn;
+	struct memory_block *mem_blk = NULL;
 	int err = 0;
 
 	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
 		unsigned long section_nr = pfn_to_section_nr(pfn);
 		struct mem_section *mem_sect;
-		struct memory_block *mem_blk;
 		int ret;
 
 		if (!present_section_nr(section_nr))
 			continue;
 		mem_sect = __nr_to_section(section_nr);
-		mem_blk = find_memory_block(mem_sect);
+		mem_blk = find_memory_block_hinted(mem_sect, mem_blk);
 		ret = register_mem_sect_under_node(mem_blk, nid);
 		if (!err)
 			err = ret;
 
 		/* discard ref obtained in find_memory_block() */
-		kobject_put(&mem_blk->sysdev.kobj);
 	}
+
+	if (mem_blk)
+		kobject_put(&mem_blk->sysdev.kobj);
 	return err;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/platform.c linux-libre-2.6.37-gnu/drivers/base/platform.c
--- linux-libre-2.6.36-gnu/drivers/base/platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -147,6 +147,7 @@
 	struct platform_object *pa = container_of(dev, struct platform_object,
 						  pdev.dev);
 
+	of_device_node_put(&pa->pdev.dev);
 	kfree(pa->pdev.dev.platform_data);
 	kfree(pa->pdev.resource);
 	kfree(pa);
@@ -192,6 +193,9 @@
 {
 	struct resource *r;
 
+	if (!res)
+		return 0;
+
 	r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
 	if (r) {
 		pdev->resource = r;
@@ -215,8 +219,12 @@
 int platform_device_add_data(struct platform_device *pdev, const void *data,
 			     size_t size)
 {
-	void *d = kmemdup(data, size, GFP_KERNEL);
+	void *d;
 
+	if (!data)
+		return 0;
+
+	d = kmemdup(data, size, GFP_KERNEL);
 	if (d) {
 		pdev->dev.platform_data = d;
 		return 0;
@@ -373,17 +381,13 @@
 
 	pdev->dev.parent = parent;
 
-	if (res) {
-		ret = platform_device_add_resources(pdev, res, num);
-		if (ret)
-			goto err;
-	}
+	ret = platform_device_add_resources(pdev, res, num);
+	if (ret)
+		goto err;
 
-	if (data) {
-		ret = platform_device_add_data(pdev, data, size);
-		if (ret)
-			goto err;
-	}
+	ret = platform_device_add_data(pdev, data, size);
+	if (ret)
+		goto err;
 
 	ret = platform_device_add(pdev);
 	if (ret) {
@@ -488,12 +492,12 @@
 	 * if the probe was successful, and make sure any forced probes of
 	 * new devices fail.
 	 */
-	spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
+	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
 	drv->probe = NULL;
 	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
 		retval = -ENODEV;
 	drv->driver.probe = platform_drv_probe_fail;
-	spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
+	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
 
 	if (code != retval)
 		platform_driver_unregister(drv);
@@ -530,17 +534,13 @@
 		goto err_out;
 	}
 
-	if (res) {
-		error = platform_device_add_resources(pdev, res, n_res);
-		if (error)
-			goto err_pdev_put;
-	}
+	error = platform_device_add_resources(pdev, res, n_res);
+	if (error)
+		goto err_pdev_put;
 
-	if (data) {
-		error = platform_device_add_data(pdev, data, size);
-		if (error)
-			goto err_pdev_put;
-	}
+	error = platform_device_add_data(pdev, data, size);
+	if (error)
+		goto err_pdev_put;
 
 	error = platform_device_add(pdev);
 	if (error)
@@ -976,6 +976,41 @@
 };
 EXPORT_SYMBOL_GPL(platform_bus_type);
 
+/**
+ * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops
+ *
+ * This function can be used by platform code to get the current
+ * set of dev_pm_ops functions used by the platform_bus_type.
+ */
+const struct dev_pm_ops * __init platform_bus_get_pm_ops(void)
+{
+	return platform_bus_type.pm;
+}
+
+/**
+ * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type
+ *
+ * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type
+ *
+ * Platform code can override the dev_pm_ops methods of
+ * platform_bus_type by using this function.  It is expected that
+ * platform code will first do a platform_bus_get_pm_ops(), then
+ * kmemdup it, then customize selected methods and pass a pointer to
+ * the new struct dev_pm_ops to this function.
+ *
+ * Since platform-specific code is customizing methods for *all*
+ * devices (not just platform-specific devices) it is expected that
+ * any custom overrides of these functions will keep existing behavior
+ * and simply extend it.  For example, any customization of the
+ * runtime PM methods should continue to call the pm_generic_*
+ * functions as the default ones do in addition to the
+ * platform-specific behavior.
+ */
+void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm)
+{
+	platform_bus_type.pm = pm;
+}
+
 int __init platform_bus_init(void)
 {
 	int error;
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/generic_ops.c linux-libre-2.6.37-gnu/drivers/base/power/generic_ops.c
--- linux-libre-2.6.36-gnu/drivers/base/power/generic_ops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/generic_ops.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 	int ret;
 
-	ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;
+	ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0;
 
 	return ret;
 }
@@ -65,7 +65,7 @@
 	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
 	int ret;
 
-	ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL;
+	ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0;
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/main.c linux-libre-2.6.37-gnu/drivers/base/power/main.c
--- linux-libre-2.6.36-gnu/drivers/base/power/main.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/main.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,8 @@
  */
 static bool transition_started;
 
+static int async_error;
+
 /**
  * device_pm_init - Initialize the PM-related part of a device object.
  * @dev: Device object being initialized.
@@ -60,7 +62,8 @@
 	dev->power.status = DPM_ON;
 	init_completion(&dev->power.completion);
 	complete_all(&dev->power.completion);
-	dev->power.wakeup_count = 0;
+	dev->power.wakeup = NULL;
+	spin_lock_init(&dev->power.lock);
 	pm_runtime_init(dev);
 }
 
@@ -120,6 +123,7 @@
 	mutex_lock(&dpm_list_mtx);
 	list_del_init(&dev->power.entry);
 	mutex_unlock(&dpm_list_mtx);
+	device_wakeup_disable(dev);
 	pm_runtime_remove(dev);
 }
 
@@ -407,7 +411,7 @@
 static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
 {
 	ktime_t calltime;
-	s64 usecs64;
+	u64 usecs64;
 	int usecs;
 
 	calltime = ktime_get();
@@ -471,20 +475,33 @@
  */
 void dpm_resume_noirq(pm_message_t state)
 {
-	struct device *dev;
+	struct list_head list;
 	ktime_t starttime = ktime_get();
 
+	INIT_LIST_HEAD(&list);
 	mutex_lock(&dpm_list_mtx);
 	transition_started = false;
-	list_for_each_entry(dev, &dpm_list, power.entry)
+	while (!list_empty(&dpm_list)) {
+		struct device *dev = to_device(dpm_list.next);
+
+		get_device(dev);
 		if (dev->power.status > DPM_OFF) {
 			int error;
 
 			dev->power.status = DPM_OFF;
+			mutex_unlock(&dpm_list_mtx);
+
 			error = device_resume_noirq(dev, state);
+
+			mutex_lock(&dpm_list_mtx);
 			if (error)
 				pm_dev_err(dev, state, " early", error);
 		}
+		if (!list_empty(&dev->power.entry))
+			list_move_tail(&dev->power.entry, &list);
+		put_device(dev);
+	}
+	list_splice(&list, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
 	dpm_show_time(starttime, state, "early");
 	resume_device_irqs();
@@ -600,6 +617,7 @@
 	INIT_LIST_HEAD(&list);
 	mutex_lock(&dpm_list_mtx);
 	pm_transition = state;
+	async_error = 0;
 
 	list_for_each_entry(dev, &dpm_list, power.entry) {
 		if (dev->power.status < DPM_OFF)
@@ -784,20 +802,33 @@
  */
 int dpm_suspend_noirq(pm_message_t state)
 {
-	struct device *dev;
+	struct list_head list;
 	ktime_t starttime = ktime_get();
 	int error = 0;
 
+	INIT_LIST_HEAD(&list);
 	suspend_device_irqs();
 	mutex_lock(&dpm_list_mtx);
-	list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
+	while (!list_empty(&dpm_list)) {
+		struct device *dev = to_device(dpm_list.prev);
+
+		get_device(dev);
+		mutex_unlock(&dpm_list_mtx);
+
 		error = device_suspend_noirq(dev, state);
+
+		mutex_lock(&dpm_list_mtx);
 		if (error) {
 			pm_dev_err(dev, state, " late", error);
+			put_device(dev);
 			break;
 		}
 		dev->power.status = DPM_OFF_IRQ;
+		if (!list_empty(&dev->power.entry))
+			list_move(&dev->power.entry, &list);
+		put_device(dev);
 	}
+	list_splice_tail(&list, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
 	if (error)
 		dpm_resume_noirq(resume_event(state));
@@ -829,8 +860,6 @@
 	return error;
 }
 
-static int async_error;
-
 /**
  * device_suspend - Execute "suspend" callbacks for given device.
  * @dev: Device to handle.
@@ -885,6 +914,9 @@
 	device_unlock(dev);
 	complete_all(&dev->power.completion);
 
+	if (error)
+		async_error = error;
+
 	return error;
 }
 
@@ -894,10 +926,8 @@
 	int error;
 
 	error = __device_suspend(dev, pm_transition, true);
-	if (error) {
+	if (error)
 		pm_dev_err(dev, pm_transition, " async", error);
-		async_error = error;
-	}
 
 	put_device(dev);
 }
@@ -1085,8 +1115,9 @@
  * @dev: Device to wait for.
  * @subordinate: Device that needs to wait for @dev.
  */
-void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
+int device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
 {
 	dpm_wait(dev, subordinate->power.async_suspend);
+	return async_error;
 }
 EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/Makefile linux-libre-2.6.37-gnu/drivers/base/power/Makefile
--- linux-libre-2.6.36-gnu/drivers/base/power/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,7 @@
 obj-$(CONFIG_PM_RUNTIME)	+= runtime.o
 obj-$(CONFIG_PM_OPS)	+= generic_ops.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
+obj-$(CONFIG_PM_OPP)	+= opp.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 ccflags-$(CONFIG_PM_VERBOSE)   += -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/opp.c linux-libre-2.6.37-gnu/drivers/base/power/opp.c
--- linux-libre-2.6.36-gnu/drivers/base/power/opp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/base/power/opp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,628 @@
+/*
+ * Generic OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *	Nishanth Menon
+ *	Romit Dasgupta
+ *	Kevin Hilman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/list.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/opp.h>
+
+/*
+ * Internal data structure organization with the OPP layer library is as
+ * follows:
+ * dev_opp_list (root)
+ *	|- device 1 (represents voltage domain 1)
+ *	|	|- opp 1 (availability, freq, voltage)
+ *	|	|- opp 2 ..
+ *	...	...
+ *	|	`- opp n ..
+ *	|- device 2 (represents the next voltage domain)
+ *	...
+ *	`- device m (represents mth voltage domain)
+ * device 1, 2.. are represented by dev_opp structure while each opp
+ * is represented by the opp structure.
+ */
+
+/**
+ * struct opp - Generic OPP description structure
+ * @node:	opp list node. The nodes are maintained throughout the lifetime
+ *		of boot. It is expected only an optimal set of OPPs are
+ *		added to the library by the SoC framework.
+ *		RCU usage: opp list is traversed with RCU locks. node
+ *		modification is possible realtime, hence the modifications
+ *		are protected by the dev_opp_list_lock for integrity.
+ *		IMPORTANT: the opp nodes should be maintained in increasing
+ *		order.
+ * @available:	true/false - marks if this OPP as available or not
+ * @rate:	Frequency in hertz
+ * @u_volt:	Nominal voltage in microvolts corresponding to this OPP
+ * @dev_opp:	points back to the device_opp struct this opp belongs to
+ *
+ * This structure stores the OPP information for a given device.
+ */
+struct opp {
+	struct list_head node;
+
+	bool available;
+	unsigned long rate;
+	unsigned long u_volt;
+
+	struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:	list node - contains the devices with OPPs that
+ *		have been registered. Nodes once added are not modified in this
+ *		list.
+ *		RCU usage: nodes are not modified in the list of device_opp,
+ *		however addition is possible and is secured by dev_opp_list_lock
+ * @dev:	device pointer
+ * @opp_list:	list of opps
+ *
+ * This is an internal data structure maintaining the link to opps attached to
+ * a device. This structure is not meant to be shared to users as it is
+ * meant for book keeping and private to OPP library
+ */
+struct device_opp {
+	struct list_head node;
+
+	struct device *dev;
+	struct list_head opp_list;
+};
+
+/*
+ * The root of the list of all devices. All device_opp structures branch off
+ * from here, with each device_opp containing the list of opp it supports in
+ * various states of availability.
+ */
+static LIST_HEAD(dev_opp_list);
+/* Lock to allow exclusive modification to the device and opp lists */
+static DEFINE_MUTEX(dev_opp_list_lock);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:	device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device. Does a RCU
+ * reader operation to grab the pointer needed.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ *
+ * Locking: This function must be called under rcu_read_lock(). device_opp
+ * is a RCU protected pointer. This means that device_opp is valid as long
+ * as we are under RCU lock.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+	if (unlikely(IS_ERR_OR_NULL(dev))) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return ERR_PTR(-EINVAL);
+	}
+
+	list_for_each_entry_rcu(tmp_dev_opp, &dev_opp_list, node) {
+		if (tmp_dev_opp->dev == dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+
+	return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an available opp
+ * @opp:	opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. This means that opp which could have been fetched by
+ * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
+ * under RCU lock. The pointer returned by the opp_find_freq family must be
+ * used in the same section as the usage of this function with the pointer
+ * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
+ * pointer.
+ */
+unsigned long opp_get_voltage(struct opp *opp)
+{
+	struct opp *tmp_opp;
+	unsigned long v = 0;
+
+	tmp_opp = rcu_dereference(opp);
+	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
+		pr_err("%s: Invalid parameters\n", __func__);
+	else
+		v = tmp_opp->u_volt;
+
+	return v;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an available opp
+ * @opp:	opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. This means that opp which could have been fetched by
+ * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
+ * under RCU lock. The pointer returned by the opp_find_freq family must be
+ * used in the same section as the usage of this function with the pointer
+ * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
+ * pointer.
+ */
+unsigned long opp_get_freq(struct opp *opp)
+{
+	struct opp *tmp_opp;
+	unsigned long f = 0;
+
+	tmp_opp = rcu_dereference(opp);
+	if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
+		pr_err("%s: Invalid parameters\n", __func__);
+	else
+		f = tmp_opp->rate;
+
+	return f;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps available in the opp list
+ * @dev:	device for which we do this operation
+ *
+ * This function returns the number of available opps if there are any,
+ * else returns 0 if none or the corresponding error value.
+ *
+ * Locking: This function must be called under rcu_read_lock(). This function
+ * internally references two RCU protected structures: device_opp and opp which
+ * are safe as long as we are under a common RCU locked section.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+	struct device_opp *dev_opp;
+	struct opp *temp_opp;
+	int count = 0;
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		int r = PTR_ERR(dev_opp);
+		dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+		return r;
+	}
+
+	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->available)
+			count++;
+	}
+
+	return count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @dev:		device for which we do this operation
+ * @freq:		frequency to search for
+ * @is_available:	true/false - match for available opp
+ *
+ * Searches for exact match in the opp list and returns pointer to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note: available is a modifier for the search. if available=true, then the
+ * match is for exact matching frequency and is available in the stored OPP
+ * table. if false, the match is for exact frequency which is not available.
+ *
+ * This provides a mechanism to enable an opp which is not available currently
+ * or the opposite as well.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
+				bool available)
+{
+	struct device_opp *dev_opp;
+	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		int r = PTR_ERR(dev_opp);
+		dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+		return ERR_PTR(r);
+	}
+
+	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->available == available &&
+				temp_opp->rate == freq) {
+			opp = temp_opp;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @dev:	device for which we do this operation
+ * @freq:	Start frequency
+ *
+ * Search for the matching ceil *available* OPP from a starting freq
+ * for a device.
+ *
+ * Returns matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	if (!dev || !freq) {
+		dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
+		return ERR_PTR(-EINVAL);
+	}
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->available && temp_opp->rate >= *freq) {
+			opp = temp_opp;
+			*freq = opp->rate;
+			break;
+		}
+	}
+
+	return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for a rounded floor freq
+ * @dev:	device for which we do this operation
+ * @freq:	Start frequency
+ *
+ * Search for the matching floor *available* OPP from a starting freq
+ * for a device.
+ *
+ * Returns matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+	struct device_opp *dev_opp;
+	struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+	if (!dev || !freq) {
+		dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
+		return ERR_PTR(-EINVAL);
+	}
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp))
+		return opp;
+
+	list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+		if (temp_opp->available) {
+			/* go to the next node, before choosing prev */
+			if (temp_opp->rate > *freq)
+				break;
+			else
+				opp = temp_opp;
+		}
+	}
+	if (!IS_ERR(opp))
+		*freq = opp->rate;
+
+	return opp;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @dev:	device for which we do this operation
+ * @freq:	Frequency in Hz for this OPP
+ * @u_volt:	Voltage in uVolts for this OPP
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ * The opp is made available by default and it can be controlled using
+ * opp_enable/disable functions.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+{
+	struct device_opp *dev_opp = NULL;
+	struct opp *opp, *new_opp;
+	struct list_head *head;
+
+	/* allocate new OPP node */
+	new_opp = kzalloc(sizeof(struct opp), GFP_KERNEL);
+	if (!new_opp) {
+		dev_warn(dev, "%s: Unable to create new OPP node\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* Hold our list modification lock here */
+	mutex_lock(&dev_opp_list_lock);
+
+	/* Check for existing list for 'dev' */
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		/*
+		 * Allocate a new device OPP table. In the infrequent case
+		 * where a new device is needed to be added, we pay this
+		 * penalty.
+		 */
+		dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+		if (!dev_opp) {
+			mutex_unlock(&dev_opp_list_lock);
+			kfree(new_opp);
+			dev_warn(dev,
+				"%s: Unable to create device OPP structure\n",
+				__func__);
+			return -ENOMEM;
+		}
+
+		dev_opp->dev = dev;
+		INIT_LIST_HEAD(&dev_opp->opp_list);
+
+		/* Secure the device list modification */
+		list_add_rcu(&dev_opp->node, &dev_opp_list);
+	}
+
+	/* populate the opp table */
+	new_opp->dev_opp = dev_opp;
+	new_opp->rate = freq;
+	new_opp->u_volt = u_volt;
+	new_opp->available = true;
+
+	/* Insert new OPP in order of increasing frequency */
+	head = &dev_opp->opp_list;
+	list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
+		if (new_opp->rate < opp->rate)
+			break;
+		else
+			head = &opp->node;
+	}
+
+	list_add_rcu(&new_opp->node, head);
+	mutex_unlock(&dev_opp_list_lock);
+
+	return 0;
+}
+
+/**
+ * opp_set_availability() - helper to set the availability of an opp
+ * @dev:		device for which we do this operation
+ * @freq:		OPP frequency to modify availability
+ * @availability_req:	availability status requested for this opp
+ *
+ * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
+ * share a common logic which is isolated here.
+ *
+ * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * copy operation, returns 0 if no modifcation was done OR modification was
+ * successful.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks to
+ * keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+static int opp_set_availability(struct device *dev, unsigned long freq,
+		bool availability_req)
+{
+	struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+	struct opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
+	int r = 0;
+
+	/* keep the node allocated */
+	new_opp = kmalloc(sizeof(struct opp), GFP_KERNEL);
+	if (!new_opp) {
+		dev_warn(dev, "%s: Unable to create OPP\n", __func__);
+		return -ENOMEM;
+	}
+
+	mutex_lock(&dev_opp_list_lock);
+
+	/* Find the device_opp */
+	list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+		if (dev == tmp_dev_opp->dev) {
+			dev_opp = tmp_dev_opp;
+			break;
+		}
+	}
+	if (IS_ERR(dev_opp)) {
+		r = PTR_ERR(dev_opp);
+		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
+		goto unlock;
+	}
+
+	/* Do we have the frequency? */
+	list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) {
+		if (tmp_opp->rate == freq) {
+			opp = tmp_opp;
+			break;
+		}
+	}
+	if (IS_ERR(opp)) {
+		r = PTR_ERR(opp);
+		goto unlock;
+	}
+
+	/* Is update really needed? */
+	if (opp->available == availability_req)
+		goto unlock;
+	/* copy the old data over */
+	*new_opp = *opp;
+
+	/* plug in new node */
+	new_opp->available = availability_req;
+
+	list_replace_rcu(&opp->node, &new_opp->node);
+	mutex_unlock(&dev_opp_list_lock);
+	synchronize_rcu();
+
+	/* clean up old opp */
+	new_opp = opp;
+	goto out;
+
+unlock:
+	mutex_unlock(&dev_opp_list_lock);
+out:
+	kfree(new_opp);
+	return r;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @dev:	device for which we do this operation
+ * @freq:	OPP frequency to enable
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value. It is meant to be used for users an OPP available
+ * after being temporarily made unavailable with opp_disable.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly uses RCU and mutex locks to keep the
+ * integrity of the internal data structures. Callers should ensure that
+ * this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+int opp_enable(struct device *dev, unsigned long freq)
+{
+	return opp_set_availability(dev, freq, true);
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @dev:	device for which we do this operation
+ * @freq:	OPP frequency to disable
+ *
+ * Disables a provided opp. If the operation is valid, this returns
+ * 0, else the corresponding error value. It is meant to be a temporary
+ * control by users to make this OPP not available until the circumstances are
+ * right to make it available again (with a call to opp_enable).
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly uses RCU and mutex locks to keep the
+ * integrity of the internal data structures. Callers should ensure that
+ * this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+int opp_disable(struct device *dev, unsigned long freq)
+{
+	return opp_set_availability(dev, freq, false);
+}
+
+#ifdef CONFIG_CPU_FREQ
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a device
+ * @dev:	device for which we do this operation
+ * @table:	Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided device- this assumes that the
+ * opp list is already initialized and ready for usage.
+ *
+ * This function allocates required memory for the cpufreq table. It is
+ * expected that the caller does the required maintenance such as freeing
+ * the table as required.
+ *
+ * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
+ * if no memory available for the operation (table is not populated), returns 0
+ * if successful and table is populated.
+ *
+ * WARNING: It is  important for the callers to ensure refreshing their copy of
+ * the table if any of the mentioned functions have been invoked in the interim.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * To simplify the logic, we pretend we are updater and hold relevant mutex here
+ * Callers should ensure that this function is *NOT* called under RCU protection
+ * or in contexts where mutex locking cannot be used.
+ */
+int opp_init_cpufreq_table(struct device *dev,
+			    struct cpufreq_frequency_table **table)
+{
+	struct device_opp *dev_opp;
+	struct opp *opp;
+	struct cpufreq_frequency_table *freq_table;
+	int i = 0;
+
+	/* Pretend as if I am an updater */
+	mutex_lock(&dev_opp_list_lock);
+
+	dev_opp = find_device_opp(dev);
+	if (IS_ERR(dev_opp)) {
+		int r = PTR_ERR(dev_opp);
+		mutex_unlock(&dev_opp_list_lock);
+		dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
+		return r;
+	}
+
+	freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+			     (opp_get_opp_count(dev) + 1), GFP_KERNEL);
+	if (!freq_table) {
+		mutex_unlock(&dev_opp_list_lock);
+		dev_warn(dev, "%s: Unable to allocate frequency table\n",
+			__func__);
+		return -ENOMEM;
+	}
+
+	list_for_each_entry(opp, &dev_opp->opp_list, node) {
+		if (opp->available) {
+			freq_table[i].index = i;
+			freq_table[i].frequency = opp->rate / 1000;
+			i++;
+		}
+	}
+	mutex_unlock(&dev_opp_list_lock);
+
+	freq_table[i].index = i;
+	freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+	*table = &freq_table[0];
+
+	return 0;
+}
+#endif		/* CONFIG_CPU_FREQ */
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/power.h linux-libre-2.6.37-gnu/drivers/base/power/power.h
--- linux-libre-2.6.36-gnu/drivers/base/power/power.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/power.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,7 @@
 
 static inline void device_pm_init(struct device *dev)
 {
+	spin_lock_init(&dev->power.lock);
 	pm_runtime_init(dev);
 }
 
@@ -59,6 +60,7 @@
 
 extern int dpm_sysfs_add(struct device *);
 extern void dpm_sysfs_remove(struct device *);
+extern void rpm_sysfs_remove(struct device *);
 
 #else /* CONFIG_PM */
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/runtime.c linux-libre-2.6.37-gnu/drivers/base/power/runtime.c
--- linux-libre-2.6.36-gnu/drivers/base/power/runtime.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/runtime.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,17 +2,55 @@
  * drivers/base/power/runtime.c - Helper functions for device run-time PM
  *
  * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ * Copyright (C) 2010 Alan Stern <stern@rowland.harvard.edu>
  *
  * This file is released under the GPLv2.
  */
 
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
-#include <linux/jiffies.h>
+#include "power.h"
 
-static int __pm_runtime_resume(struct device *dev, bool from_wq);
-static int __pm_request_idle(struct device *dev);
-static int __pm_request_resume(struct device *dev);
+static int rpm_resume(struct device *dev, int rpmflags);
+static int rpm_suspend(struct device *dev, int rpmflags);
+
+/**
+ * update_pm_runtime_accounting - Update the time accounting of power states
+ * @dev: Device to update the accounting for
+ *
+ * In order to be able to have time accounting of the various power states
+ * (as used by programs such as PowerTOP to show the effectiveness of runtime
+ * PM), we need to track the time spent in each state.
+ * update_pm_runtime_accounting must be called each time before the
+ * runtime_status field is updated, to account the time in the old state
+ * correctly.
+ */
+void update_pm_runtime_accounting(struct device *dev)
+{
+	unsigned long now = jiffies;
+	int delta;
+
+	delta = now - dev->power.accounting_timestamp;
+
+	if (delta < 0)
+		delta = 0;
+
+	dev->power.accounting_timestamp = now;
+
+	if (dev->power.disable_depth > 0)
+		return;
+
+	if (dev->power.runtime_status == RPM_SUSPENDED)
+		dev->power.suspended_jiffies += delta;
+	else
+		dev->power.active_jiffies += delta;
+}
+
+static void __update_runtime_status(struct device *dev, enum rpm_status status)
+{
+	update_pm_runtime_accounting(dev);
+	dev->power.runtime_status = status;
+}
 
 /**
  * pm_runtime_deactivate_timer - Deactivate given device's suspend timer.
@@ -40,62 +78,154 @@
 	dev->power.request = RPM_REQ_NONE;
 }
 
-/**
- * __pm_runtime_idle - Notify device bus type if the device can be suspended.
- * @dev: Device to notify the bus type about.
+/*
+ * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time.
+ * @dev: Device to handle.
  *
- * This function must be called under dev->power.lock with interrupts disabled.
+ * Compute the autosuspend-delay expiration time based on the device's
+ * power.last_busy time.  If the delay has already expired or is disabled
+ * (negative) or the power.use_autosuspend flag isn't set, return 0.
+ * Otherwise return the expiration time in jiffies (adjusted to be nonzero).
+ *
+ * This function may be called either with or without dev->power.lock held.
+ * Either way it can be racy, since power.last_busy may be updated at any time.
  */
-static int __pm_runtime_idle(struct device *dev)
-	__releases(&dev->power.lock) __acquires(&dev->power.lock)
+unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
+{
+	int autosuspend_delay;
+	long elapsed;
+	unsigned long last_busy;
+	unsigned long expires = 0;
+
+	if (!dev->power.use_autosuspend)
+		goto out;
+
+	autosuspend_delay = ACCESS_ONCE(dev->power.autosuspend_delay);
+	if (autosuspend_delay < 0)
+		goto out;
+
+	last_busy = ACCESS_ONCE(dev->power.last_busy);
+	elapsed = jiffies - last_busy;
+	if (elapsed < 0)
+		goto out;	/* jiffies has wrapped around. */
+
+	/*
+	 * If the autosuspend_delay is >= 1 second, align the timer by rounding
+	 * up to the nearest second.
+	 */
+	expires = last_busy + msecs_to_jiffies(autosuspend_delay);
+	if (autosuspend_delay >= 1000)
+		expires = round_jiffies(expires);
+	expires += !expires;
+	if (elapsed >= expires - last_busy)
+		expires = 0;	/* Already expired. */
+
+ out:
+	return expires;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);
+
+/**
+ * rpm_check_suspend_allowed - Test whether a device may be suspended.
+ * @dev: Device to test.
+ */
+static int rpm_check_suspend_allowed(struct device *dev)
 {
 	int retval = 0;
 
 	if (dev->power.runtime_error)
 		retval = -EINVAL;
-	else if (dev->power.idle_notification)
-		retval = -EINPROGRESS;
 	else if (atomic_read(&dev->power.usage_count) > 0
-	    || dev->power.disable_depth > 0
-	    || dev->power.runtime_status != RPM_ACTIVE)
+	    || dev->power.disable_depth > 0)
 		retval = -EAGAIN;
 	else if (!pm_children_suspended(dev))
 		retval = -EBUSY;
+
+	/* Pending resume requests take precedence over suspends. */
+	else if ((dev->power.deferred_resume
+			&& dev->power.runtime_status == RPM_SUSPENDING)
+	    || (dev->power.request_pending
+			&& dev->power.request == RPM_REQ_RESUME))
+		retval = -EAGAIN;
+	else if (dev->power.runtime_status == RPM_SUSPENDED)
+		retval = 1;
+
+	return retval;
+}
+
+/**
+ * rpm_idle - Notify device bus type if the device can be suspended.
+ * @dev: Device to notify the bus type about.
+ * @rpmflags: Flag bits.
+ *
+ * Check if the device's run-time PM status allows it to be suspended.  If
+ * another idle notification has been started earlier, return immediately.  If
+ * the RPM_ASYNC flag is set then queue an idle-notification request; otherwise
+ * run the ->runtime_idle() callback directly.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int rpm_idle(struct device *dev, int rpmflags)
+{
+	int (*callback)(struct device *);
+	int retval;
+
+	retval = rpm_check_suspend_allowed(dev);
+	if (retval < 0)
+		;	/* Conditions are wrong. */
+
+	/* Idle notifications are allowed only in the RPM_ACTIVE state. */
+	else if (dev->power.runtime_status != RPM_ACTIVE)
+		retval = -EAGAIN;
+
+	/*
+	 * Any pending request other than an idle notification takes
+	 * precedence over us, except that the timer may be running.
+	 */
+	else if (dev->power.request_pending &&
+	    dev->power.request > RPM_REQ_IDLE)
+		retval = -EAGAIN;
+
+	/* Act as though RPM_NOWAIT is always set. */
+	else if (dev->power.idle_notification)
+		retval = -EINPROGRESS;
 	if (retval)
 		goto out;
 
-	if (dev->power.request_pending) {
-		/*
-		 * If an idle notification request is pending, cancel it.  Any
-		 * other pending request takes precedence over us.
-		 */
-		if (dev->power.request == RPM_REQ_IDLE) {
-			dev->power.request = RPM_REQ_NONE;
-		} else if (dev->power.request != RPM_REQ_NONE) {
-			retval = -EAGAIN;
-			goto out;
+	/* Pending requests need to be canceled. */
+	dev->power.request = RPM_REQ_NONE;
+
+	if (dev->power.no_callbacks) {
+		/* Assume ->runtime_idle() callback would have suspended. */
+		retval = rpm_suspend(dev, rpmflags);
+		goto out;
+	}
+
+	/* Carry out an asynchronous or a synchronous idle notification. */
+	if (rpmflags & RPM_ASYNC) {
+		dev->power.request = RPM_REQ_IDLE;
+		if (!dev->power.request_pending) {
+			dev->power.request_pending = true;
+			queue_work(pm_wq, &dev->power.work);
 		}
+		goto out;
 	}
 
 	dev->power.idle_notification = true;
 
-	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
-		spin_unlock_irq(&dev->power.lock);
-
-		dev->bus->pm->runtime_idle(dev);
-
-		spin_lock_irq(&dev->power.lock);
-	} else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
-		spin_unlock_irq(&dev->power.lock);
-
-		dev->type->pm->runtime_idle(dev);
+	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle)
+		callback = dev->bus->pm->runtime_idle;
+	else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
+		callback = dev->type->pm->runtime_idle;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_idle;
+	else
+		callback = NULL;
 
-		spin_lock_irq(&dev->power.lock);
-	} else if (dev->class && dev->class->pm
-	    && dev->class->pm->runtime_idle) {
+	if (callback) {
 		spin_unlock_irq(&dev->power.lock);
 
-		dev->class->pm->runtime_idle(dev);
+		callback(dev);
 
 		spin_lock_irq(&dev->power.lock);
 	}
@@ -108,113 +238,99 @@
 }
 
 /**
- * pm_runtime_idle - Notify device bus type if the device can be suspended.
- * @dev: Device to notify the bus type about.
+ * rpm_callback - Run a given runtime PM callback for a given device.
+ * @cb: Runtime PM callback to run.
+ * @dev: Device to run the callback for.
  */
-int pm_runtime_idle(struct device *dev)
+static int rpm_callback(int (*cb)(struct device *), struct device *dev)
+	__releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
 	int retval;
 
-	spin_lock_irq(&dev->power.lock);
-	retval = __pm_runtime_idle(dev);
-	spin_unlock_irq(&dev->power.lock);
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(pm_runtime_idle);
-
-
-/**
- * update_pm_runtime_accounting - Update the time accounting of power states
- * @dev: Device to update the accounting for
- *
- * In order to be able to have time accounting of the various power states
- * (as used by programs such as PowerTOP to show the effectiveness of runtime
- * PM), we need to track the time spent in each state.
- * update_pm_runtime_accounting must be called each time before the
- * runtime_status field is updated, to account the time in the old state
- * correctly.
- */
-void update_pm_runtime_accounting(struct device *dev)
-{
-	unsigned long now = jiffies;
-	int delta;
-
-	delta = now - dev->power.accounting_timestamp;
-
-	if (delta < 0)
-		delta = 0;
+	if (!cb)
+		return -ENOSYS;
 
-	dev->power.accounting_timestamp = now;
+	spin_unlock_irq(&dev->power.lock);
 
-	if (dev->power.disable_depth > 0)
-		return;
+	retval = cb(dev);
 
-	if (dev->power.runtime_status == RPM_SUSPENDED)
-		dev->power.suspended_jiffies += delta;
-	else
-		dev->power.active_jiffies += delta;
-}
+	spin_lock_irq(&dev->power.lock);
+	dev->power.runtime_error = retval;
 
-static void __update_runtime_status(struct device *dev, enum rpm_status status)
-{
-	update_pm_runtime_accounting(dev);
-	dev->power.runtime_status = status;
+	return retval;
 }
 
 /**
- * __pm_runtime_suspend - Carry out run-time suspend of given device.
+ * rpm_suspend - Carry out run-time suspend of given device.
  * @dev: Device to suspend.
- * @from_wq: If set, the function has been called via pm_wq.
+ * @rpmflags: Flag bits.
  *
- * Check if the device can be suspended and run the ->runtime_suspend() callback
- * provided by its bus type.  If another suspend has been started earlier, wait
- * for it to finish.  If an idle notification or suspend request is pending or
- * scheduled, cancel it.
+ * Check if the device's run-time PM status allows it to be suspended.  If
+ * another suspend has been started earlier, either return immediately or wait
+ * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags.  Cancel a
+ * pending idle notification.  If the RPM_ASYNC flag is set then queue a
+ * suspend request; otherwise run the ->runtime_suspend() callback directly.
+ * If a deferred resume was requested while the callback was running then carry
+ * it out; otherwise send an idle notification for the device (if the suspend
+ * failed) or for its parent (if the suspend succeeded).
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
-int __pm_runtime_suspend(struct device *dev, bool from_wq)
+static int rpm_suspend(struct device *dev, int rpmflags)
 	__releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
+	int (*callback)(struct device *);
 	struct device *parent = NULL;
-	bool notify = false;
-	int retval = 0;
+	int retval;
 
-	dev_dbg(dev, "__pm_runtime_suspend()%s!\n",
-		from_wq ? " from workqueue" : "");
+	dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
 
  repeat:
-	if (dev->power.runtime_error) {
-		retval = -EINVAL;
-		goto out;
-	}
+	retval = rpm_check_suspend_allowed(dev);
 
-	/* Pending resume requests take precedence over us. */
-	if (dev->power.request_pending
-	    && dev->power.request == RPM_REQ_RESUME) {
+	if (retval < 0)
+		;	/* Conditions are wrong. */
+
+	/* Synchronous suspends are not allowed in the RPM_RESUMING state. */
+	else if (dev->power.runtime_status == RPM_RESUMING &&
+	    !(rpmflags & RPM_ASYNC))
 		retval = -EAGAIN;
+	if (retval)
 		goto out;
+
+	/* If the autosuspend_delay time hasn't expired yet, reschedule. */
+	if ((rpmflags & RPM_AUTO)
+	    && dev->power.runtime_status != RPM_SUSPENDING) {
+		unsigned long expires = pm_runtime_autosuspend_expiration(dev);
+
+		if (expires != 0) {
+			/* Pending requests need to be canceled. */
+			dev->power.request = RPM_REQ_NONE;
+
+			/*
+			 * Optimization: If the timer is already running and is
+			 * set to expire at or before the autosuspend delay,
+			 * avoid the overhead of resetting it.  Just let it
+			 * expire; pm_suspend_timer_fn() will take care of the
+			 * rest.
+			 */
+			if (!(dev->power.timer_expires && time_before_eq(
+			    dev->power.timer_expires, expires))) {
+				dev->power.timer_expires = expires;
+				mod_timer(&dev->power.suspend_timer, expires);
+			}
+			dev->power.timer_autosuspends = 1;
+			goto out;
+		}
 	}
 
 	/* Other scheduled or pending requests need to be canceled. */
 	pm_runtime_cancel_pending(dev);
 
-	if (dev->power.runtime_status == RPM_SUSPENDED)
-		retval = 1;
-	else if (dev->power.runtime_status == RPM_RESUMING
-	    || dev->power.disable_depth > 0
-	    || atomic_read(&dev->power.usage_count) > 0)
-		retval = -EAGAIN;
-	else if (!pm_children_suspended(dev))
-		retval = -EBUSY;
-	if (retval)
-		goto out;
-
 	if (dev->power.runtime_status == RPM_SUSPENDING) {
 		DEFINE_WAIT(wait);
 
-		if (from_wq) {
+		if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
 			retval = -EINPROGRESS;
 			goto out;
 		}
@@ -236,46 +352,42 @@
 		goto repeat;
 	}
 
-	__update_runtime_status(dev, RPM_SUSPENDING);
 	dev->power.deferred_resume = false;
+	if (dev->power.no_callbacks)
+		goto no_callback;	/* Assume success. */
 
-	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
-		spin_unlock_irq(&dev->power.lock);
-
-		retval = dev->bus->pm->runtime_suspend(dev);
-
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else if (dev->type && dev->type->pm
-	    && dev->type->pm->runtime_suspend) {
-		spin_unlock_irq(&dev->power.lock);
-
-		retval = dev->type->pm->runtime_suspend(dev);
-
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else if (dev->class && dev->class->pm
-	    && dev->class->pm->runtime_suspend) {
-		spin_unlock_irq(&dev->power.lock);
+	/* Carry out an asynchronous or a synchronous suspend. */
+	if (rpmflags & RPM_ASYNC) {
+		dev->power.request = (rpmflags & RPM_AUTO) ?
+		    RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
+		if (!dev->power.request_pending) {
+			dev->power.request_pending = true;
+			queue_work(pm_wq, &dev->power.work);
+		}
+		goto out;
+	}
 
-		retval = dev->class->pm->runtime_suspend(dev);
+	__update_runtime_status(dev, RPM_SUSPENDING);
 
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else {
-		retval = -ENOSYS;
-	}
+	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+		callback = dev->bus->pm->runtime_suspend;
+	else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
+		callback = dev->type->pm->runtime_suspend;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_suspend;
+	else
+		callback = NULL;
 
+	retval = rpm_callback(callback, dev);
 	if (retval) {
 		__update_runtime_status(dev, RPM_ACTIVE);
-		if (retval == -EAGAIN || retval == -EBUSY) {
-			if (dev->power.timer_expires == 0)
-				notify = true;
+		dev->power.deferred_resume = 0;
+		if (retval == -EAGAIN || retval == -EBUSY)
 			dev->power.runtime_error = 0;
-		} else {
+		else
 			pm_runtime_cancel_pending(dev);
-		}
 	} else {
+ no_callback:
 		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_deactivate_timer(dev);
 
@@ -287,14 +399,11 @@
 	wake_up_all(&dev->power.wait_queue);
 
 	if (dev->power.deferred_resume) {
-		__pm_runtime_resume(dev, false);
+		rpm_resume(dev, 0);
 		retval = -EAGAIN;
 		goto out;
 	}
 
-	if (notify)
-		__pm_runtime_idle(dev);
-
 	if (parent && !parent->power.ignore_children) {
 		spin_unlock_irq(&dev->power.lock);
 
@@ -304,72 +413,69 @@
 	}
 
  out:
-	dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
-
-	return retval;
-}
-
-/**
- * pm_runtime_suspend - Carry out run-time suspend of given device.
- * @dev: Device to suspend.
- */
-int pm_runtime_suspend(struct device *dev)
-{
-	int retval;
-
-	spin_lock_irq(&dev->power.lock);
-	retval = __pm_runtime_suspend(dev, false);
-	spin_unlock_irq(&dev->power.lock);
+	dev_dbg(dev, "%s returns %d\n", __func__, retval);
 
 	return retval;
 }
-EXPORT_SYMBOL_GPL(pm_runtime_suspend);
 
 /**
- * __pm_runtime_resume - Carry out run-time resume of given device.
+ * rpm_resume - Carry out run-time resume of given device.
  * @dev: Device to resume.
- * @from_wq: If set, the function has been called via pm_wq.
+ * @rpmflags: Flag bits.
  *
- * Check if the device can be woken up and run the ->runtime_resume() callback
- * provided by its bus type.  If another resume has been started earlier, wait
- * for it to finish.  If there's a suspend running in parallel with this
- * function, wait for it to finish and resume the device.  Cancel any scheduled
- * or pending requests.
+ * Check if the device's run-time PM status allows it to be resumed.  Cancel
+ * any scheduled or pending requests.  If another resume has been started
+ * earlier, either return imediately or wait for it to finish, depending on the
+ * RPM_NOWAIT and RPM_ASYNC flags.  Similarly, if there's a suspend running in
+ * parallel with this function, either tell the other process to resume after
+ * suspending (deferred_resume) or wait for it to finish.  If the RPM_ASYNC
+ * flag is set then queue a resume request; otherwise run the
+ * ->runtime_resume() callback directly.  Queue an idle notification for the
+ * device if the resume succeeded.
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
-int __pm_runtime_resume(struct device *dev, bool from_wq)
+static int rpm_resume(struct device *dev, int rpmflags)
 	__releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
+	int (*callback)(struct device *);
 	struct device *parent = NULL;
 	int retval = 0;
 
-	dev_dbg(dev, "__pm_runtime_resume()%s!\n",
-		from_wq ? " from workqueue" : "");
+	dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
 
  repeat:
-	if (dev->power.runtime_error) {
+	if (dev->power.runtime_error)
 		retval = -EINVAL;
+	else if (dev->power.disable_depth > 0)
+		retval = -EAGAIN;
+	if (retval)
 		goto out;
-	}
 
-	pm_runtime_cancel_pending(dev);
+	/*
+	 * Other scheduled or pending requests need to be canceled.  Small
+	 * optimization: If an autosuspend timer is running, leave it running
+	 * rather than cancelling it now only to restart it again in the near
+	 * future.
+	 */
+	dev->power.request = RPM_REQ_NONE;
+	if (!dev->power.timer_autosuspends)
+		pm_runtime_deactivate_timer(dev);
 
-	if (dev->power.runtime_status == RPM_ACTIVE)
+	if (dev->power.runtime_status == RPM_ACTIVE) {
 		retval = 1;
-	else if (dev->power.disable_depth > 0)
-		retval = -EAGAIN;
-	if (retval)
 		goto out;
+	}
 
 	if (dev->power.runtime_status == RPM_RESUMING
 	    || dev->power.runtime_status == RPM_SUSPENDING) {
 		DEFINE_WAIT(wait);
 
-		if (from_wq) {
+		if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
 			if (dev->power.runtime_status == RPM_SUSPENDING)
 				dev->power.deferred_resume = true;
-			retval = -EINPROGRESS;
+			else
+				retval = -EINPROGRESS;
 			goto out;
 		}
 
@@ -391,6 +497,34 @@
 		goto repeat;
 	}
 
+	/*
+	 * See if we can skip waking up the parent.  This is safe only if
+	 * power.no_callbacks is set, because otherwise we don't know whether
+	 * the resume will actually succeed.
+	 */
+	if (dev->power.no_callbacks && !parent && dev->parent) {
+		spin_lock_nested(&dev->parent->power.lock, SINGLE_DEPTH_NESTING);
+		if (dev->parent->power.disable_depth > 0
+		    || dev->parent->power.ignore_children
+		    || dev->parent->power.runtime_status == RPM_ACTIVE) {
+			atomic_inc(&dev->parent->power.child_count);
+			spin_unlock(&dev->parent->power.lock);
+			goto no_callback;	/* Assume success. */
+		}
+		spin_unlock(&dev->parent->power.lock);
+	}
+
+	/* Carry out an asynchronous or a synchronous resume. */
+	if (rpmflags & RPM_ASYNC) {
+		dev->power.request = RPM_REQ_RESUME;
+		if (!dev->power.request_pending) {
+			dev->power.request_pending = true;
+			queue_work(pm_wq, &dev->power.work);
+		}
+		retval = 0;
+		goto out;
+	}
+
 	if (!parent && dev->parent) {
 		/*
 		 * Increment the parent's resume counter and resume it if
@@ -408,7 +542,7 @@
 		 */
 		if (!parent->power.disable_depth
 		    && !parent->power.ignore_children) {
-			__pm_runtime_resume(parent, false);
+			rpm_resume(parent, 0);
 			if (parent->power.runtime_status != RPM_ACTIVE)
 				retval = -EBUSY;
 		}
@@ -420,39 +554,26 @@
 		goto repeat;
 	}
 
-	__update_runtime_status(dev, RPM_RESUMING);
-
-	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
-		spin_unlock_irq(&dev->power.lock);
-
-		retval = dev->bus->pm->runtime_resume(dev);
-
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else if (dev->type && dev->type->pm
-	    && dev->type->pm->runtime_resume) {
-		spin_unlock_irq(&dev->power.lock);
-
-		retval = dev->type->pm->runtime_resume(dev);
-
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else if (dev->class && dev->class->pm
-	    && dev->class->pm->runtime_resume) {
-		spin_unlock_irq(&dev->power.lock);
+	if (dev->power.no_callbacks)
+		goto no_callback;	/* Assume success. */
 
-		retval = dev->class->pm->runtime_resume(dev);
+	__update_runtime_status(dev, RPM_RESUMING);
 
-		spin_lock_irq(&dev->power.lock);
-		dev->power.runtime_error = retval;
-	} else {
-		retval = -ENOSYS;
-	}
+	if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+		callback = dev->bus->pm->runtime_resume;
+	else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
+		callback = dev->type->pm->runtime_resume;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_resume;
+	else
+		callback = NULL;
 
+	retval = rpm_callback(callback, dev);
 	if (retval) {
 		__update_runtime_status(dev, RPM_SUSPENDED);
 		pm_runtime_cancel_pending(dev);
 	} else {
+ no_callback:
 		__update_runtime_status(dev, RPM_ACTIVE);
 		if (parent)
 			atomic_inc(&parent->power.child_count);
@@ -460,7 +581,7 @@
 	wake_up_all(&dev->power.wait_queue);
 
 	if (!retval)
-		__pm_request_idle(dev);
+		rpm_idle(dev, RPM_ASYNC);
 
  out:
 	if (parent) {
@@ -471,26 +592,10 @@
 		spin_lock_irq(&dev->power.lock);
 	}
 
-	dev_dbg(dev, "__pm_runtime_resume() returns %d!\n", retval);
-
-	return retval;
-}
-
-/**
- * pm_runtime_resume - Carry out run-time resume of given device.
- * @dev: Device to suspend.
- */
-int pm_runtime_resume(struct device *dev)
-{
-	int retval;
-
-	spin_lock_irq(&dev->power.lock);
-	retval = __pm_runtime_resume(dev, false);
-	spin_unlock_irq(&dev->power.lock);
+	dev_dbg(dev, "%s returns %d\n", __func__, retval);
 
 	return retval;
 }
-EXPORT_SYMBOL_GPL(pm_runtime_resume);
 
 /**
  * pm_runtime_work - Universal run-time PM work function.
@@ -517,13 +622,16 @@
 	case RPM_REQ_NONE:
 		break;
 	case RPM_REQ_IDLE:
-		__pm_runtime_idle(dev);
+		rpm_idle(dev, RPM_NOWAIT);
 		break;
 	case RPM_REQ_SUSPEND:
-		__pm_runtime_suspend(dev, true);
+		rpm_suspend(dev, RPM_NOWAIT);
+		break;
+	case RPM_REQ_AUTOSUSPEND:
+		rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);
 		break;
 	case RPM_REQ_RESUME:
-		__pm_runtime_resume(dev, true);
+		rpm_resume(dev, RPM_NOWAIT);
 		break;
 	}
 
@@ -532,117 +640,10 @@
 }
 
 /**
- * __pm_request_idle - Submit an idle notification request for given device.
- * @dev: Device to handle.
- *
- * Check if the device's run-time PM status is correct for suspending the device
- * and queue up a request to run __pm_runtime_idle() for it.
- *
- * This function must be called under dev->power.lock with interrupts disabled.
- */
-static int __pm_request_idle(struct device *dev)
-{
-	int retval = 0;
-
-	if (dev->power.runtime_error)
-		retval = -EINVAL;
-	else if (atomic_read(&dev->power.usage_count) > 0
-	    || dev->power.disable_depth > 0
-	    || dev->power.runtime_status == RPM_SUSPENDED
-	    || dev->power.runtime_status == RPM_SUSPENDING)
-		retval = -EAGAIN;
-	else if (!pm_children_suspended(dev))
-		retval = -EBUSY;
-	if (retval)
-		return retval;
-
-	if (dev->power.request_pending) {
-		/* Any requests other then RPM_REQ_IDLE take precedence. */
-		if (dev->power.request == RPM_REQ_NONE)
-			dev->power.request = RPM_REQ_IDLE;
-		else if (dev->power.request != RPM_REQ_IDLE)
-			retval = -EAGAIN;
-		return retval;
-	}
-
-	dev->power.request = RPM_REQ_IDLE;
-	dev->power.request_pending = true;
-	queue_work(pm_wq, &dev->power.work);
-
-	return retval;
-}
-
-/**
- * pm_request_idle - Submit an idle notification request for given device.
- * @dev: Device to handle.
- */
-int pm_request_idle(struct device *dev)
-{
-	unsigned long flags;
-	int retval;
-
-	spin_lock_irqsave(&dev->power.lock, flags);
-	retval = __pm_request_idle(dev);
-	spin_unlock_irqrestore(&dev->power.lock, flags);
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(pm_request_idle);
-
-/**
- * __pm_request_suspend - Submit a suspend request for given device.
- * @dev: Device to suspend.
- *
- * This function must be called under dev->power.lock with interrupts disabled.
- */
-static int __pm_request_suspend(struct device *dev)
-{
-	int retval = 0;
-
-	if (dev->power.runtime_error)
-		return -EINVAL;
-
-	if (dev->power.runtime_status == RPM_SUSPENDED)
-		retval = 1;
-	else if (atomic_read(&dev->power.usage_count) > 0
-	    || dev->power.disable_depth > 0)
-		retval = -EAGAIN;
-	else if (dev->power.runtime_status == RPM_SUSPENDING)
-		retval = -EINPROGRESS;
-	else if (!pm_children_suspended(dev))
-		retval = -EBUSY;
-	if (retval < 0)
-		return retval;
-
-	pm_runtime_deactivate_timer(dev);
-
-	if (dev->power.request_pending) {
-		/*
-		 * Pending resume requests take precedence over us, but we can
-		 * overtake any other pending request.
-		 */
-		if (dev->power.request == RPM_REQ_RESUME)
-			retval = -EAGAIN;
-		else if (dev->power.request != RPM_REQ_SUSPEND)
-			dev->power.request = retval ?
-						RPM_REQ_NONE : RPM_REQ_SUSPEND;
-		return retval;
-	} else if (retval) {
-		return retval;
-	}
-
-	dev->power.request = RPM_REQ_SUSPEND;
-	dev->power.request_pending = true;
-	queue_work(pm_wq, &dev->power.work);
-
-	return 0;
-}
-
-/**
  * pm_suspend_timer_fn - Timer function for pm_schedule_suspend().
  * @data: Device pointer passed by pm_schedule_suspend().
  *
- * Check if the time is right and execute __pm_request_suspend() in that case.
+ * Check if the time is right and queue a suspend request.
  */
 static void pm_suspend_timer_fn(unsigned long data)
 {
@@ -656,7 +657,8 @@
 	/* If 'expire' is after 'jiffies' we've been called too early. */
 	if (expires > 0 && !time_after(expires, jiffies)) {
 		dev->power.timer_expires = 0;
-		__pm_request_suspend(dev);
+		rpm_suspend(dev, dev->power.timer_autosuspends ?
+		    (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
 	}
 
 	spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -670,47 +672,25 @@
 int pm_schedule_suspend(struct device *dev, unsigned int delay)
 {
 	unsigned long flags;
-	int retval = 0;
+	int retval;
 
 	spin_lock_irqsave(&dev->power.lock, flags);
 
-	if (dev->power.runtime_error) {
-		retval = -EINVAL;
-		goto out;
-	}
-
 	if (!delay) {
-		retval = __pm_request_suspend(dev);
+		retval = rpm_suspend(dev, RPM_ASYNC);
 		goto out;
 	}
 
-	pm_runtime_deactivate_timer(dev);
-
-	if (dev->power.request_pending) {
-		/*
-		 * Pending resume requests take precedence over us, but any
-		 * other pending requests have to be canceled.
-		 */
-		if (dev->power.request == RPM_REQ_RESUME) {
-			retval = -EAGAIN;
-			goto out;
-		}
-		dev->power.request = RPM_REQ_NONE;
-	}
-
-	if (dev->power.runtime_status == RPM_SUSPENDED)
-		retval = 1;
-	else if (atomic_read(&dev->power.usage_count) > 0
-	    || dev->power.disable_depth > 0)
-		retval = -EAGAIN;
-	else if (!pm_children_suspended(dev))
-		retval = -EBUSY;
+	retval = rpm_check_suspend_allowed(dev);
 	if (retval)
 		goto out;
 
+	/* Other scheduled or pending requests need to be canceled. */
+	pm_runtime_cancel_pending(dev);
+
 	dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
-	if (!dev->power.timer_expires)
-		dev->power.timer_expires = 1;
+	dev->power.timer_expires += !dev->power.timer_expires;
+	dev->power.timer_autosuspends = 0;
 	mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
 
  out:
@@ -721,103 +701,88 @@
 EXPORT_SYMBOL_GPL(pm_schedule_suspend);
 
 /**
- * pm_request_resume - Submit a resume request for given device.
- * @dev: Device to resume.
+ * __pm_runtime_idle - Entry point for run-time idle operations.
+ * @dev: Device to send idle notification for.
+ * @rpmflags: Flag bits.
  *
- * This function must be called under dev->power.lock with interrupts disabled.
+ * If the RPM_GET_PUT flag is set, decrement the device's usage count and
+ * return immediately if it is larger than zero.  Then carry out an idle
+ * notification, either synchronous or asynchronous.
+ *
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-static int __pm_request_resume(struct device *dev)
+int __pm_runtime_idle(struct device *dev, int rpmflags)
 {
-	int retval = 0;
-
-	if (dev->power.runtime_error)
-		return -EINVAL;
-
-	if (dev->power.runtime_status == RPM_ACTIVE)
-		retval = 1;
-	else if (dev->power.runtime_status == RPM_RESUMING)
-		retval = -EINPROGRESS;
-	else if (dev->power.disable_depth > 0)
-		retval = -EAGAIN;
-	if (retval < 0)
-		return retval;
-
-	pm_runtime_deactivate_timer(dev);
+	unsigned long flags;
+	int retval;
 
-	if (dev->power.runtime_status == RPM_SUSPENDING) {
-		dev->power.deferred_resume = true;
-		return retval;
-	}
-	if (dev->power.request_pending) {
-		/* If non-resume request is pending, we can overtake it. */
-		dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME;
-		return retval;
+	if (rpmflags & RPM_GET_PUT) {
+		if (!atomic_dec_and_test(&dev->power.usage_count))
+			return 0;
 	}
-	if (retval)
-		return retval;
 
-	dev->power.request = RPM_REQ_RESUME;
-	dev->power.request_pending = true;
-	queue_work(pm_wq, &dev->power.work);
+	spin_lock_irqsave(&dev->power.lock, flags);
+	retval = rpm_idle(dev, rpmflags);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
 
 	return retval;
 }
+EXPORT_SYMBOL_GPL(__pm_runtime_idle);
 
 /**
- * pm_request_resume - Submit a resume request for given device.
- * @dev: Device to resume.
+ * __pm_runtime_suspend - Entry point for run-time put/suspend operations.
+ * @dev: Device to suspend.
+ * @rpmflags: Flag bits.
+ *
+ * If the RPM_GET_PUT flag is set, decrement the device's usage count and
+ * return immediately if it is larger than zero.  Then carry out a suspend,
+ * either synchronous or asynchronous.
+ *
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-int pm_request_resume(struct device *dev)
+int __pm_runtime_suspend(struct device *dev, int rpmflags)
 {
 	unsigned long flags;
 	int retval;
 
+	if (rpmflags & RPM_GET_PUT) {
+		if (!atomic_dec_and_test(&dev->power.usage_count))
+			return 0;
+	}
+
 	spin_lock_irqsave(&dev->power.lock, flags);
-	retval = __pm_request_resume(dev);
+	retval = rpm_suspend(dev, rpmflags);
 	spin_unlock_irqrestore(&dev->power.lock, flags);
 
 	return retval;
 }
-EXPORT_SYMBOL_GPL(pm_request_resume);
+EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
 
 /**
- * __pm_runtime_get - Reference count a device and wake it up, if necessary.
- * @dev: Device to handle.
- * @sync: If set and the device is suspended, resume it synchronously.
+ * __pm_runtime_resume - Entry point for run-time resume operations.
+ * @dev: Device to resume.
+ * @rpmflags: Flag bits.
  *
- * Increment the usage count of the device and resume it or submit a resume
- * request for it, depending on the value of @sync.
+ * If the RPM_GET_PUT flag is set, increment the device's usage count.  Then
+ * carry out a resume, either synchronous or asynchronous.
+ *
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-int __pm_runtime_get(struct device *dev, bool sync)
+int __pm_runtime_resume(struct device *dev, int rpmflags)
 {
+	unsigned long flags;
 	int retval;
 
-	atomic_inc(&dev->power.usage_count);
-	retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev);
-
-	return retval;
-}
-EXPORT_SYMBOL_GPL(__pm_runtime_get);
-
-/**
- * __pm_runtime_put - Decrement the device's usage counter and notify its bus.
- * @dev: Device to handle.
- * @sync: If the device's bus type is to be notified, do that synchronously.
- *
- * Decrement the usage count of the device and if it reaches zero, carry out a
- * synchronous idle notification or submit an idle notification request for it,
- * depending on the value of @sync.
- */
-int __pm_runtime_put(struct device *dev, bool sync)
-{
-	int retval = 0;
+	if (rpmflags & RPM_GET_PUT)
+		atomic_inc(&dev->power.usage_count);
 
-	if (atomic_dec_and_test(&dev->power.usage_count))
-		retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev);
+	spin_lock_irqsave(&dev->power.lock, flags);
+	retval = rpm_resume(dev, rpmflags);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
 
 	return retval;
 }
-EXPORT_SYMBOL_GPL(__pm_runtime_put);
+EXPORT_SYMBOL_GPL(__pm_runtime_resume);
 
 /**
  * __pm_runtime_set_status - Set run-time PM status of a device.
@@ -968,7 +933,7 @@
 
 	if (dev->power.request_pending
 	    && dev->power.request == RPM_REQ_RESUME) {
-		__pm_runtime_resume(dev, false);
+		rpm_resume(dev, 0);
 		retval = 1;
 	}
 
@@ -1017,7 +982,7 @@
 		 */
 		pm_runtime_get_noresume(dev);
 
-		__pm_runtime_resume(dev, false);
+		rpm_resume(dev, 0);
 
 		pm_runtime_put_noidle(dev);
 	}
@@ -1065,7 +1030,7 @@
 
 	dev->power.runtime_auto = false;
 	atomic_inc(&dev->power.usage_count);
-	__pm_runtime_resume(dev, false);
+	rpm_resume(dev, 0);
 
  out:
 	spin_unlock_irq(&dev->power.lock);
@@ -1086,7 +1051,7 @@
 
 	dev->power.runtime_auto = true;
 	if (atomic_dec_and_test(&dev->power.usage_count))
-		__pm_runtime_idle(dev);
+		rpm_idle(dev, RPM_AUTO);
 
  out:
 	spin_unlock_irq(&dev->power.lock);
@@ -1094,13 +1059,110 @@
 EXPORT_SYMBOL_GPL(pm_runtime_allow);
 
 /**
+ * pm_runtime_no_callbacks - Ignore run-time PM callbacks for a device.
+ * @dev: Device to handle.
+ *
+ * Set the power.no_callbacks flag, which tells the PM core that this
+ * device is power-managed through its parent and has no run-time PM
+ * callbacks of its own.  The run-time sysfs attributes will be removed.
+ *
+ */
+void pm_runtime_no_callbacks(struct device *dev)
+{
+	spin_lock_irq(&dev->power.lock);
+	dev->power.no_callbacks = 1;
+	spin_unlock_irq(&dev->power.lock);
+	if (device_is_registered(dev))
+		rpm_sysfs_remove(dev);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
+
+/**
+ * update_autosuspend - Handle a change to a device's autosuspend settings.
+ * @dev: Device to handle.
+ * @old_delay: The former autosuspend_delay value.
+ * @old_use: The former use_autosuspend value.
+ *
+ * Prevent runtime suspend if the new delay is negative and use_autosuspend is
+ * set; otherwise allow it.  Send an idle notification if suspends are allowed.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static void update_autosuspend(struct device *dev, int old_delay, int old_use)
+{
+	int delay = dev->power.autosuspend_delay;
+
+	/* Should runtime suspend be prevented now? */
+	if (dev->power.use_autosuspend && delay < 0) {
+
+		/* If it used to be allowed then prevent it. */
+		if (!old_use || old_delay >= 0) {
+			atomic_inc(&dev->power.usage_count);
+			rpm_resume(dev, 0);
+		}
+	}
+
+	/* Runtime suspend should be allowed now. */
+	else {
+
+		/* If it used to be prevented then allow it. */
+		if (old_use && old_delay < 0)
+			atomic_dec(&dev->power.usage_count);
+
+		/* Maybe we can autosuspend now. */
+		rpm_idle(dev, RPM_AUTO);
+	}
+}
+
+/**
+ * pm_runtime_set_autosuspend_delay - Set a device's autosuspend_delay value.
+ * @dev: Device to handle.
+ * @delay: Value of the new delay in milliseconds.
+ *
+ * Set the device's power.autosuspend_delay value.  If it changes to negative
+ * and the power.use_autosuspend flag is set, prevent run-time suspends.  If it
+ * changes the other way, allow run-time suspends.
+ */
+void pm_runtime_set_autosuspend_delay(struct device *dev, int delay)
+{
+	int old_delay, old_use;
+
+	spin_lock_irq(&dev->power.lock);
+	old_delay = dev->power.autosuspend_delay;
+	old_use = dev->power.use_autosuspend;
+	dev->power.autosuspend_delay = delay;
+	update_autosuspend(dev, old_delay, old_use);
+	spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_set_autosuspend_delay);
+
+/**
+ * __pm_runtime_use_autosuspend - Set a device's use_autosuspend flag.
+ * @dev: Device to handle.
+ * @use: New value for use_autosuspend.
+ *
+ * Set the device's power.use_autosuspend flag, and allow or prevent run-time
+ * suspends as needed.
+ */
+void __pm_runtime_use_autosuspend(struct device *dev, bool use)
+{
+	int old_delay, old_use;
+
+	spin_lock_irq(&dev->power.lock);
+	old_delay = dev->power.autosuspend_delay;
+	old_use = dev->power.use_autosuspend;
+	dev->power.use_autosuspend = use;
+	update_autosuspend(dev, old_delay, old_use);
+	spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
+
+/**
  * pm_runtime_init - Initialize run-time PM fields in given device object.
  * @dev: Device object to initialize.
  */
 void pm_runtime_init(struct device *dev)
 {
-	spin_lock_init(&dev->power.lock);
-
 	dev->power.runtime_status = RPM_SUSPENDED;
 	dev->power.idle_notification = false;
 
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/sysfs.c linux-libre-2.6.37-gnu/drivers/base/power/sysfs.c
--- linux-libre-2.6.36-gnu/drivers/base/power/sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -75,12 +75,27 @@
  *	attribute is set to "enabled" by bus type code or device drivers and in
  *	that cases it should be safe to leave the default value.
  *
+ *	autosuspend_delay_ms - Report/change a device's autosuspend_delay value
+ *
+ *	Some drivers don't want to carry out a runtime suspend as soon as a
+ *	device becomes idle; they want it always to remain idle for some period
+ *	of time before suspending it.  This period is the autosuspend_delay
+ *	value (expressed in milliseconds) and it can be controlled by the user.
+ *	If the value is negative then the device will never be runtime
+ *	suspended.
+ *
+ *	NOTE: The autosuspend_delay_ms attribute and the autosuspend_delay
+ *	value are used only if the driver calls pm_runtime_use_autosuspend().
+ *
  *	wakeup_count - Report the number of wakeup events related to the device
  */
 
 static const char enabled[] = "enabled";
 static const char disabled[] = "disabled";
 
+const char power_group_name[] = "power";
+EXPORT_SYMBOL_GPL(power_group_name);
+
 #ifdef CONFIG_PM_RUNTIME
 static const char ctrl_auto[] = "auto";
 static const char ctrl_on[] = "on";
@@ -170,6 +185,33 @@
 }
 
 static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
+
+static ssize_t autosuspend_delay_ms_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	if (!dev->power.use_autosuspend)
+		return -EIO;
+	return sprintf(buf, "%d\n", dev->power.autosuspend_delay);
+}
+
+static ssize_t autosuspend_delay_ms_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	long delay;
+
+	if (!dev->power.use_autosuspend)
+		return -EIO;
+
+	if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay)
+		return -EINVAL;
+
+	pm_runtime_set_autosuspend_delay(dev, delay);
+	return n;
+}
+
+static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
+		autosuspend_delay_ms_store);
+
 #endif
 
 static ssize_t
@@ -210,11 +252,122 @@
 static ssize_t wakeup_count_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%lu\n", dev->power.wakeup_count);
+	unsigned long count = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		count = dev->power.wakeup->event_count;
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
 }
 
 static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
-#endif
+
+static ssize_t wakeup_active_count_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	unsigned long count = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		count = dev->power.wakeup->active_count;
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
+
+static ssize_t wakeup_hit_count_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	unsigned long count = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		count = dev->power.wakeup->hit_count;
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+
+static ssize_t wakeup_active_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	unsigned int active = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		active = dev->power.wakeup->active;
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL);
+
+static ssize_t wakeup_total_time_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	s64 msec = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		msec = ktime_to_ms(dev->power.wakeup->total_time);
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL);
+
+static ssize_t wakeup_max_time_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	s64 msec = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		msec = ktime_to_ms(dev->power.wakeup->max_time);
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL);
+
+static ssize_t wakeup_last_time_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	s64 msec = 0;
+	bool enabled = false;
+
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		msec = ktime_to_ms(dev->power.wakeup->last_time);
+		enabled = true;
+	}
+	spin_unlock_irq(&dev->power.lock);
+	return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_RUNTIME
@@ -279,19 +432,20 @@
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
 static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
-	&dev_attr_control.attr,
-	&dev_attr_runtime_status.attr,
-	&dev_attr_runtime_suspended_time.attr,
-	&dev_attr_runtime_active_time.attr,
-#endif
 	&dev_attr_wakeup.attr,
 #ifdef CONFIG_PM_SLEEP
 	&dev_attr_wakeup_count.attr,
+	&dev_attr_wakeup_active_count.attr,
+	&dev_attr_wakeup_hit_count.attr,
+	&dev_attr_wakeup_active.attr,
+	&dev_attr_wakeup_total_time_ms.attr,
+	&dev_attr_wakeup_max_time_ms.attr,
+	&dev_attr_wakeup_last_time_ms.attr,
 #endif
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 	&dev_attr_async.attr,
 #ifdef CONFIG_PM_RUNTIME
+	&dev_attr_runtime_status.attr,
 	&dev_attr_runtime_usage.attr,
 	&dev_attr_runtime_active_kids.attr,
 	&dev_attr_runtime_enabled.attr,
@@ -300,10 +454,53 @@
 	NULL,
 };
 static struct attribute_group pm_attr_group = {
-	.name	= "power",
+	.name	= power_group_name,
 	.attrs	= power_attrs,
 };
 
+#ifdef CONFIG_PM_RUNTIME
+
+static struct attribute *runtime_attrs[] = {
+#ifndef CONFIG_PM_ADVANCED_DEBUG
+	&dev_attr_runtime_status.attr,
+#endif
+	&dev_attr_control.attr,
+	&dev_attr_runtime_suspended_time.attr,
+	&dev_attr_runtime_active_time.attr,
+	&dev_attr_autosuspend_delay_ms.attr,
+	NULL,
+};
+static struct attribute_group pm_runtime_attr_group = {
+	.name	= power_group_name,
+	.attrs	= runtime_attrs,
+};
+
+int dpm_sysfs_add(struct device *dev)
+{
+	int rc;
+
+	rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
+	if (rc == 0 && !dev->power.no_callbacks) {
+		rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
+		if (rc)
+			sysfs_remove_group(&dev->kobj, &pm_attr_group);
+	}
+	return rc;
+}
+
+void rpm_sysfs_remove(struct device *dev)
+{
+	sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
+}
+
+void dpm_sysfs_remove(struct device *dev)
+{
+	rpm_sysfs_remove(dev);
+	sysfs_remove_group(&dev->kobj, &pm_attr_group);
+}
+
+#else /* CONFIG_PM_RUNTIME */
+
 int dpm_sysfs_add(struct device * dev)
 {
 	return sysfs_create_group(&dev->kobj, &pm_attr_group);
@@ -313,3 +510,5 @@
 {
 	sysfs_remove_group(&dev->kobj, &pm_attr_group);
 }
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/trace.c linux-libre-2.6.37-gnu/drivers/base/power/trace.c
--- linux-libre-2.6.36-gnu/drivers/base/power/trace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/trace.c	2011-01-04 19:50:19.000000000 -0500
@@ -188,8 +188,10 @@
 static int show_dev_hash(unsigned int value)
 {
 	int match = 0;
-	struct list_head *entry = dpm_list.prev;
+	struct list_head *entry;
 
+	device_pm_lock();
+	entry = dpm_list.prev;
 	while (entry != &dpm_list) {
 		struct device * dev = to_device(entry);
 		unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
@@ -199,11 +201,43 @@
 		}
 		entry = entry->prev;
 	}
+	device_pm_unlock();
 	return match;
 }
 
 static unsigned int hash_value_early_read;
 
+int show_trace_dev_match(char *buf, size_t size)
+{
+	unsigned int value = hash_value_early_read / (USERHASH * FILEHASH);
+	int ret = 0;
+	struct list_head *entry;
+
+	/*
+	 * It's possible that multiple devices will match the hash and we can't
+	 * tell which is the culprit, so it's best to output them all.
+	 */
+	device_pm_lock();
+	entry = dpm_list.prev;
+	while (size && entry != &dpm_list) {
+		struct device *dev = to_device(entry);
+		unsigned int hash = hash_string(DEVSEED, dev_name(dev),
+						DEVHASH);
+		if (hash == value) {
+			int len = snprintf(buf, size, "%s\n",
+					    dev_driver_string(dev));
+			if (len > size)
+				len = size;
+			buf += len;
+			ret += len;
+			size -= len;
+		}
+		entry = entry->prev;
+	}
+	device_pm_unlock();
+	return ret;
+}
+
 static int early_resume_init(void)
 {
 	hash_value_early_read = read_magic_time();
diff -druN linux-libre-2.6.36-gnu/drivers/base/power/wakeup.c linux-libre-2.6.37-gnu/drivers/base/power/wakeup.c
--- linux-libre-2.6.36-gnu/drivers/base/power/wakeup.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/power/wakeup.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,7 +11,12 @@
 #include <linux/sched.h>
 #include <linux/capability.h>
 #include <linux/suspend.h>
-#include <linux/pm.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include "power.h"
+
+#define TIMEOUT		100
 
 /*
  * If set, the suspend/hibernate code will abort transitions to a sleep state
@@ -20,18 +25,244 @@
 bool events_check_enabled;
 
 /* The counter of registered wakeup events. */
-static unsigned long event_count;
+static atomic_t event_count = ATOMIC_INIT(0);
 /* A preserved old value of event_count. */
-static unsigned long saved_event_count;
+static unsigned int saved_count;
 /* The counter of wakeup events being processed. */
-static unsigned long events_in_progress;
+static atomic_t events_in_progress = ATOMIC_INIT(0);
 
 static DEFINE_SPINLOCK(events_lock);
 
 static void pm_wakeup_timer_fn(unsigned long data);
 
-static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0);
-static unsigned long events_timer_expires;
+static LIST_HEAD(wakeup_sources);
+
+/**
+ * wakeup_source_create - Create a struct wakeup_source object.
+ * @name: Name of the new wakeup source.
+ */
+struct wakeup_source *wakeup_source_create(const char *name)
+{
+	struct wakeup_source *ws;
+
+	ws = kzalloc(sizeof(*ws), GFP_KERNEL);
+	if (!ws)
+		return NULL;
+
+	spin_lock_init(&ws->lock);
+	if (name)
+		ws->name = kstrdup(name, GFP_KERNEL);
+
+	return ws;
+}
+EXPORT_SYMBOL_GPL(wakeup_source_create);
+
+/**
+ * wakeup_source_destroy - Destroy a struct wakeup_source object.
+ * @ws: Wakeup source to destroy.
+ */
+void wakeup_source_destroy(struct wakeup_source *ws)
+{
+	if (!ws)
+		return;
+
+	spin_lock_irq(&ws->lock);
+	while (ws->active) {
+		spin_unlock_irq(&ws->lock);
+
+		schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+
+		spin_lock_irq(&ws->lock);
+	}
+	spin_unlock_irq(&ws->lock);
+
+	kfree(ws->name);
+	kfree(ws);
+}
+EXPORT_SYMBOL_GPL(wakeup_source_destroy);
+
+/**
+ * wakeup_source_add - Add given object to the list of wakeup sources.
+ * @ws: Wakeup source object to add to the list.
+ */
+void wakeup_source_add(struct wakeup_source *ws)
+{
+	if (WARN_ON(!ws))
+		return;
+
+	setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
+	ws->active = false;
+
+	spin_lock_irq(&events_lock);
+	list_add_rcu(&ws->entry, &wakeup_sources);
+	spin_unlock_irq(&events_lock);
+	synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(wakeup_source_add);
+
+/**
+ * wakeup_source_remove - Remove given object from the wakeup sources list.
+ * @ws: Wakeup source object to remove from the list.
+ */
+void wakeup_source_remove(struct wakeup_source *ws)
+{
+	if (WARN_ON(!ws))
+		return;
+
+	spin_lock_irq(&events_lock);
+	list_del_rcu(&ws->entry);
+	spin_unlock_irq(&events_lock);
+	synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(wakeup_source_remove);
+
+/**
+ * wakeup_source_register - Create wakeup source and add it to the list.
+ * @name: Name of the wakeup source to register.
+ */
+struct wakeup_source *wakeup_source_register(const char *name)
+{
+	struct wakeup_source *ws;
+
+	ws = wakeup_source_create(name);
+	if (ws)
+		wakeup_source_add(ws);
+
+	return ws;
+}
+EXPORT_SYMBOL_GPL(wakeup_source_register);
+
+/**
+ * wakeup_source_unregister - Remove wakeup source from the list and remove it.
+ * @ws: Wakeup source object to unregister.
+ */
+void wakeup_source_unregister(struct wakeup_source *ws)
+{
+	wakeup_source_remove(ws);
+	wakeup_source_destroy(ws);
+}
+EXPORT_SYMBOL_GPL(wakeup_source_unregister);
+
+/**
+ * device_wakeup_attach - Attach a wakeup source object to a device object.
+ * @dev: Device to handle.
+ * @ws: Wakeup source object to attach to @dev.
+ *
+ * This causes @dev to be treated as a wakeup device.
+ */
+static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws)
+{
+	spin_lock_irq(&dev->power.lock);
+	if (dev->power.wakeup) {
+		spin_unlock_irq(&dev->power.lock);
+		return -EEXIST;
+	}
+	dev->power.wakeup = ws;
+	spin_unlock_irq(&dev->power.lock);
+	return 0;
+}
+
+/**
+ * device_wakeup_enable - Enable given device to be a wakeup source.
+ * @dev: Device to handle.
+ *
+ * Create a wakeup source object, register it and attach it to @dev.
+ */
+int device_wakeup_enable(struct device *dev)
+{
+	struct wakeup_source *ws;
+	int ret;
+
+	if (!dev || !dev->power.can_wakeup)
+		return -EINVAL;
+
+	ws = wakeup_source_register(dev_name(dev));
+	if (!ws)
+		return -ENOMEM;
+
+	ret = device_wakeup_attach(dev, ws);
+	if (ret)
+		wakeup_source_unregister(ws);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(device_wakeup_enable);
+
+/**
+ * device_wakeup_detach - Detach a device's wakeup source object from it.
+ * @dev: Device to detach the wakeup source object from.
+ *
+ * After it returns, @dev will not be treated as a wakeup device any more.
+ */
+static struct wakeup_source *device_wakeup_detach(struct device *dev)
+{
+	struct wakeup_source *ws;
+
+	spin_lock_irq(&dev->power.lock);
+	ws = dev->power.wakeup;
+	dev->power.wakeup = NULL;
+	spin_unlock_irq(&dev->power.lock);
+	return ws;
+}
+
+/**
+ * device_wakeup_disable - Do not regard a device as a wakeup source any more.
+ * @dev: Device to handle.
+ *
+ * Detach the @dev's wakeup source object from it, unregister this wakeup source
+ * object and destroy it.
+ */
+int device_wakeup_disable(struct device *dev)
+{
+	struct wakeup_source *ws;
+
+	if (!dev || !dev->power.can_wakeup)
+		return -EINVAL;
+
+	ws = device_wakeup_detach(dev);
+	if (ws)
+		wakeup_source_unregister(ws);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(device_wakeup_disable);
+
+/**
+ * device_init_wakeup - Device wakeup initialization.
+ * @dev: Device to handle.
+ * @enable: Whether or not to enable @dev as a wakeup device.
+ *
+ * By default, most devices should leave wakeup disabled.  The exceptions are
+ * devices that everyone expects to be wakeup sources: keyboards, power buttons,
+ * possibly network interfaces, etc.
+ */
+int device_init_wakeup(struct device *dev, bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		device_set_wakeup_capable(dev, true);
+		ret = device_wakeup_enable(dev);
+	} else {
+		device_set_wakeup_capable(dev, false);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(device_init_wakeup);
+
+/**
+ * device_set_wakeup_enable - Enable or disable a device to wake up the system.
+ * @dev: Device to handle.
+ */
+int device_set_wakeup_enable(struct device *dev, bool enable)
+{
+	if (!dev || !dev->power.can_wakeup)
+		return -EINVAL;
+
+	return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev);
+}
+EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
 
 /*
  * The functions below use the observation that each wakeup event starts a
@@ -55,118 +286,259 @@
  * knowledge, however, may not be available to it, so it can simply specify time
  * to wait before the system can be suspended and pass it as the second
  * argument of pm_wakeup_event().
+ *
+ * It is valid to call pm_relax() after pm_wakeup_event(), in which case the
+ * "no suspend" period will be ended either by the pm_relax(), or by the timer
+ * function executed when the timer expires, whichever comes first.
+ */
+
+/**
+ * wakup_source_activate - Mark given wakeup source as active.
+ * @ws: Wakeup source to handle.
+ *
+ * Update the @ws' statistics and, if @ws has just been activated, notify the PM
+ * core of the event by incrementing the counter of of wakeup events being
+ * processed.
+ */
+static void wakeup_source_activate(struct wakeup_source *ws)
+{
+	ws->active = true;
+	ws->active_count++;
+	ws->timer_expires = jiffies;
+	ws->last_time = ktime_get();
+
+	atomic_inc(&events_in_progress);
+}
+
+/**
+ * __pm_stay_awake - Notify the PM core of a wakeup event.
+ * @ws: Wakeup source object associated with the source of the event.
+ *
+ * It is safe to call this function from interrupt context.
  */
+void __pm_stay_awake(struct wakeup_source *ws)
+{
+	unsigned long flags;
+
+	if (!ws)
+		return;
+
+	spin_lock_irqsave(&ws->lock, flags);
+	ws->event_count++;
+	if (!ws->active)
+		wakeup_source_activate(ws);
+	spin_unlock_irqrestore(&ws->lock, flags);
+}
+EXPORT_SYMBOL_GPL(__pm_stay_awake);
 
 /**
  * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
  * @dev: Device the wakeup event is related to.
  *
- * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
- * counter of wakeup events being processed.  If @dev is not NULL, the counter
- * of wakeup events related to @dev is incremented too.
+ * Notify the PM core of a wakeup event (signaled by @dev) by calling
+ * __pm_stay_awake for the @dev's wakeup source object.
  *
  * Call this function after detecting of a wakeup event if pm_relax() is going
  * to be called directly after processing the event (and possibly passing it to
  * user space for further processing).
- *
- * It is safe to call this function from interrupt context.
  */
 void pm_stay_awake(struct device *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&events_lock, flags);
-	if (dev)
-		dev->power.wakeup_count++;
+	if (!dev)
+		return;
 
-	events_in_progress++;
-	spin_unlock_irqrestore(&events_lock, flags);
+	spin_lock_irqsave(&dev->power.lock, flags);
+	__pm_stay_awake(dev->power.wakeup);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
 }
+EXPORT_SYMBOL_GPL(pm_stay_awake);
 
 /**
- * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * wakup_source_deactivate - Mark given wakeup source as inactive.
+ * @ws: Wakeup source to handle.
  *
- * Notify the PM core that a wakeup event has been processed by decrementing
- * the counter of wakeup events being processed and incrementing the counter
- * of registered wakeup events.
+ * Update the @ws' statistics and notify the PM core that the wakeup source has
+ * become inactive by decrementing the counter of wakeup events being processed
+ * and incrementing the counter of registered wakeup events.
+ */
+static void wakeup_source_deactivate(struct wakeup_source *ws)
+{
+	ktime_t duration;
+	ktime_t now;
+
+	ws->relax_count++;
+	/*
+	 * __pm_relax() may be called directly or from a timer function.
+	 * If it is called directly right after the timer function has been
+	 * started, but before the timer function calls __pm_relax(), it is
+	 * possible that __pm_stay_awake() will be called in the meantime and
+	 * will set ws->active.  Then, ws->active may be cleared immediately
+	 * by the __pm_relax() called from the timer function, but in such a
+	 * case ws->relax_count will be different from ws->active_count.
+	 */
+	if (ws->relax_count != ws->active_count) {
+		ws->relax_count--;
+		return;
+	}
+
+	ws->active = false;
+
+	now = ktime_get();
+	duration = ktime_sub(now, ws->last_time);
+	ws->total_time = ktime_add(ws->total_time, duration);
+	if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
+		ws->max_time = duration;
+
+	del_timer(&ws->timer);
+
+	/*
+	 * event_count has to be incremented before events_in_progress is
+	 * modified, so that the callers of pm_check_wakeup_events() and
+	 * pm_save_wakeup_count() don't see the old value of event_count and
+	 * events_in_progress equal to zero at the same time.
+	 */
+	atomic_inc(&event_count);
+	smp_mb__before_atomic_dec();
+	atomic_dec(&events_in_progress);
+}
+
+/**
+ * __pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * @ws: Wakeup source object associated with the source of the event.
  *
  * Call this function for wakeup events whose processing started with calling
- * pm_stay_awake().
+ * __pm_stay_awake().
  *
  * It is safe to call it from interrupt context.
  */
-void pm_relax(void)
+void __pm_relax(struct wakeup_source *ws)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&events_lock, flags);
-	if (events_in_progress) {
-		events_in_progress--;
-		event_count++;
-	}
-	spin_unlock_irqrestore(&events_lock, flags);
+	if (!ws)
+		return;
+
+	spin_lock_irqsave(&ws->lock, flags);
+	if (ws->active)
+		wakeup_source_deactivate(ws);
+	spin_unlock_irqrestore(&ws->lock, flags);
 }
+EXPORT_SYMBOL_GPL(__pm_relax);
+
+/**
+ * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * @dev: Device that signaled the event.
+ *
+ * Execute __pm_relax() for the @dev's wakeup source object.
+ */
+void pm_relax(struct device *dev)
+{
+	unsigned long flags;
+
+	if (!dev)
+		return;
+
+	spin_lock_irqsave(&dev->power.lock, flags);
+	__pm_relax(dev->power.wakeup);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_relax);
 
 /**
  * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
+ * @data: Address of the wakeup source object associated with the event source.
  *
- * Decrease the counter of wakeup events being processed after it was increased
- * by pm_wakeup_event().
+ * Call __pm_relax() for the wakeup source whose address is stored in @data.
  */
 static void pm_wakeup_timer_fn(unsigned long data)
 {
+	__pm_relax((struct wakeup_source *)data);
+}
+
+/**
+ * __pm_wakeup_event - Notify the PM core of a wakeup event.
+ * @ws: Wakeup source object associated with the event source.
+ * @msec: Anticipated event processing time (in milliseconds).
+ *
+ * Notify the PM core of a wakeup event whose source is @ws that will take
+ * approximately @msec milliseconds to be processed by the kernel.  If @ws is
+ * not active, activate it.  If @msec is nonzero, set up the @ws' timer to
+ * execute pm_wakeup_timer_fn() in future.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
+{
 	unsigned long flags;
+	unsigned long expires;
 
-	spin_lock_irqsave(&events_lock, flags);
-	if (events_timer_expires
-	    && time_before_eq(events_timer_expires, jiffies)) {
-		events_in_progress--;
-		events_timer_expires = 0;
+	if (!ws)
+		return;
+
+	spin_lock_irqsave(&ws->lock, flags);
+
+	ws->event_count++;
+	if (!ws->active)
+		wakeup_source_activate(ws);
+
+	if (!msec) {
+		wakeup_source_deactivate(ws);
+		goto unlock;
 	}
-	spin_unlock_irqrestore(&events_lock, flags);
+
+	expires = jiffies + msecs_to_jiffies(msec);
+	if (!expires)
+		expires = 1;
+
+	if (time_after(expires, ws->timer_expires)) {
+		mod_timer(&ws->timer, expires);
+		ws->timer_expires = expires;
+	}
+
+ unlock:
+	spin_unlock_irqrestore(&ws->lock, flags);
 }
+EXPORT_SYMBOL_GPL(__pm_wakeup_event);
+
 
 /**
  * pm_wakeup_event - Notify the PM core of a wakeup event.
  * @dev: Device the wakeup event is related to.
  * @msec: Anticipated event processing time (in milliseconds).
  *
- * Notify the PM core of a wakeup event (signaled by @dev) that will take
- * approximately @msec milliseconds to be processed by the kernel.  Increment
- * the counter of registered wakeup events and (if @msec is nonzero) set up
- * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
- * timer has not been set up already, increment the counter of wakeup events
- * being processed).  If @dev is not NULL, the counter of wakeup events related
- * to @dev is incremented too.
- *
- * It is safe to call this function from interrupt context.
+ * Call __pm_wakeup_event() for the @dev's wakeup source object.
  */
 void pm_wakeup_event(struct device *dev, unsigned int msec)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&events_lock, flags);
-	event_count++;
-	if (dev)
-		dev->power.wakeup_count++;
-
-	if (msec) {
-		unsigned long expires;
+	if (!dev)
+		return;
 
-		expires = jiffies + msecs_to_jiffies(msec);
-		if (!expires)
-			expires = 1;
+	spin_lock_irqsave(&dev->power.lock, flags);
+	__pm_wakeup_event(dev->power.wakeup, msec);
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
-		if (!events_timer_expires
-		    || time_after(expires, events_timer_expires)) {
-			if (!events_timer_expires)
-				events_in_progress++;
+/**
+ * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
+ */
+static void pm_wakeup_update_hit_counts(void)
+{
+	unsigned long flags;
+	struct wakeup_source *ws;
 
-			mod_timer(&events_timer, expires);
-			events_timer_expires = expires;
-		}
+	rcu_read_lock();
+	list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+		spin_lock_irqsave(&ws->lock, flags);
+		if (ws->active)
+			ws->hit_count++;
+		spin_unlock_irqrestore(&ws->lock, flags);
 	}
-	spin_unlock_irqrestore(&events_lock, flags);
+	rcu_read_unlock();
 }
 
 /**
@@ -184,10 +556,13 @@
 
 	spin_lock_irqsave(&events_lock, flags);
 	if (events_check_enabled) {
-		ret = (event_count == saved_event_count) && !events_in_progress;
+		ret = ((unsigned int)atomic_read(&event_count) == saved_count)
+			&& !atomic_read(&events_in_progress);
 		events_check_enabled = ret;
 	}
 	spin_unlock_irqrestore(&events_lock, flags);
+	if (!ret)
+		pm_wakeup_update_hit_counts();
 	return ret;
 }
 
@@ -202,24 +577,20 @@
  * drop down to zero has been interrupted by a signal (and the current number
  * of wakeup events being processed is still nonzero).  Otherwise return true.
  */
-bool pm_get_wakeup_count(unsigned long *count)
+bool pm_get_wakeup_count(unsigned int *count)
 {
 	bool ret;
 
-	spin_lock_irq(&events_lock);
 	if (capable(CAP_SYS_ADMIN))
 		events_check_enabled = false;
 
-	while (events_in_progress && !signal_pending(current)) {
-		spin_unlock_irq(&events_lock);
-
-		schedule_timeout_interruptible(msecs_to_jiffies(100));
-
-		spin_lock_irq(&events_lock);
+	while (atomic_read(&events_in_progress) && !signal_pending(current)) {
+		pm_wakeup_update_hit_counts();
+		schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
 	}
-	*count = event_count;
-	ret = !events_in_progress;
-	spin_unlock_irq(&events_lock);
+
+	ret = !atomic_read(&events_in_progress);
+	*count = atomic_read(&event_count);
 	return ret;
 }
 
@@ -232,16 +603,102 @@
  * old number of registered wakeup events to be used by pm_check_wakeup_events()
  * and return true.  Otherwise return false.
  */
-bool pm_save_wakeup_count(unsigned long count)
+bool pm_save_wakeup_count(unsigned int count)
 {
 	bool ret = false;
 
 	spin_lock_irq(&events_lock);
-	if (count == event_count && !events_in_progress) {
-		saved_event_count = count;
+	if (count == (unsigned int)atomic_read(&event_count)
+	    && !atomic_read(&events_in_progress)) {
+		saved_count = count;
 		events_check_enabled = true;
 		ret = true;
 	}
 	spin_unlock_irq(&events_lock);
+	if (!ret)
+		pm_wakeup_update_hit_counts();
 	return ret;
 }
+
+static struct dentry *wakeup_sources_stats_dentry;
+
+/**
+ * print_wakeup_source_stats - Print wakeup source statistics information.
+ * @m: seq_file to print the statistics into.
+ * @ws: Wakeup source object to print the statistics for.
+ */
+static int print_wakeup_source_stats(struct seq_file *m,
+				     struct wakeup_source *ws)
+{
+	unsigned long flags;
+	ktime_t total_time;
+	ktime_t max_time;
+	unsigned long active_count;
+	ktime_t active_time;
+	int ret;
+
+	spin_lock_irqsave(&ws->lock, flags);
+
+	total_time = ws->total_time;
+	max_time = ws->max_time;
+	active_count = ws->active_count;
+	if (ws->active) {
+		active_time = ktime_sub(ktime_get(), ws->last_time);
+		total_time = ktime_add(total_time, active_time);
+		if (active_time.tv64 > max_time.tv64)
+			max_time = active_time;
+	} else {
+		active_time = ktime_set(0, 0);
+	}
+
+	ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
+			"%lld\t\t%lld\t\t%lld\t\t%lld\n",
+			ws->name, active_count, ws->event_count, ws->hit_count,
+			ktime_to_ms(active_time), ktime_to_ms(total_time),
+			ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+
+	spin_unlock_irqrestore(&ws->lock, flags);
+
+	return ret;
+}
+
+/**
+ * wakeup_sources_stats_show - Print wakeup sources statistics information.
+ * @m: seq_file to print the statistics into.
+ */
+static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
+{
+	struct wakeup_source *ws;
+
+	seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
+		"active_since\ttotal_time\tmax_time\tlast_change\n");
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+		print_wakeup_source_stats(m, ws);
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static int wakeup_sources_stats_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, wakeup_sources_stats_show, NULL);
+}
+
+static const struct file_operations wakeup_sources_stats_fops = {
+	.owner = THIS_MODULE,
+	.open = wakeup_sources_stats_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int __init wakeup_sources_debugfs_init(void)
+{
+	wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
+			S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);
+	return 0;
+}
+
+postcore_initcall(wakeup_sources_debugfs_init);
diff -druN linux-libre-2.6.36-gnu/drivers/base/sys.c linux-libre-2.6.37-gnu/drivers/base/sys.c
--- linux-libre-2.6.36-gnu/drivers/base/sys.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/sys.c	2011-01-04 19:50:19.000000000 -0500
@@ -432,13 +432,13 @@
 	/* resume current sysdev */
 cls_driver:
 	drv = NULL;
-	printk(KERN_ERR "Class suspend failed for %s\n",
-		kobject_name(&sysdev->kobj));
+	printk(KERN_ERR "Class suspend failed for %s: %d\n",
+		kobject_name(&sysdev->kobj), ret);
 
 aux_driver:
 	if (drv)
-		printk(KERN_ERR "Class driver suspend failed for %s\n",
-				kobject_name(&sysdev->kobj));
+		printk(KERN_ERR "Class driver suspend failed for %s: %d\n",
+				kobject_name(&sysdev->kobj), ret);
 	list_for_each_entry(err_drv, &cls->drivers, entry) {
 		if (err_drv == drv)
 			break;
diff -druN linux-libre-2.6.36-gnu/drivers/base/topology.c linux-libre-2.6.37-gnu/drivers/base/topology.c
--- linux-libre-2.6.36-gnu/drivers/base/topology.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/base/topology.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,7 +45,8 @@
 	return sprintf(buf, "%d\n", topology_##name(cpu));	\
 }
 
-#if defined(topology_thread_cpumask) || defined(topology_core_cpumask)
+#if defined(topology_thread_cpumask) || defined(topology_core_cpumask) || \
+    defined(topology_book_cpumask)
 static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf)
 {
 	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
@@ -114,6 +115,14 @@
 define_one_ro_named(core_siblings, show_core_cpumask);
 define_one_ro_named(core_siblings_list, show_core_cpumask_list);
 
+#ifdef CONFIG_SCHED_BOOK
+define_id_show_func(book_id);
+define_one_ro(book_id);
+define_siblings_show_func(book_cpumask);
+define_one_ro_named(book_siblings, show_book_cpumask);
+define_one_ro_named(book_siblings_list, show_book_cpumask_list);
+#endif
+
 static struct attribute *default_attrs[] = {
 	&attr_physical_package_id.attr,
 	&attr_core_id.attr,
@@ -121,6 +130,11 @@
 	&attr_thread_siblings_list.attr,
 	&attr_core_siblings.attr,
 	&attr_core_siblings_list.attr,
+#ifdef CONFIG_SCHED_BOOK
+	&attr_book_id.attr,
+	&attr_book_siblings.attr,
+	&attr_book_siblings_list.attr,
+#endif
 	NULL
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/amiflop.c linux-libre-2.6.37-gnu/drivers/block/amiflop.c
--- linux-libre-2.6.36-gnu/drivers/block/amiflop.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/amiflop.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 #include <linux/hdreg.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/amifdreg.h>
 #include <linux/amifd.h>
 #include <linux/buffer_head.h>
@@ -109,13 +109,12 @@
 #define FD_HD_3 	0x55555555  /* high-density 3.5" (1760K) drive */
 #define FD_DD_5 	0xaaaaaaaa  /* double-density 5.25" (440K) drive */
 
+static DEFINE_MUTEX(amiflop_mutex);
 static unsigned long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */
 
 module_param(fd_def_df0, ulong, 0);
 MODULE_LICENSE("GPL");
 
-static struct request_queue *floppy_queue;
-
 /*
  *  Macros
  */
@@ -164,6 +163,7 @@
 static int writepending;
 static int writefromint;
 static char *raw_buf;
+static int fdc_queue;
 
 static DEFINE_SPINLOCK(amiflop_lock);
 
@@ -1334,6 +1334,42 @@
 	return -1;
 }
 
+/*
+ * Round-robin between our available drives, doing one request from each
+ */
+static struct request *set_next_request(void)
+{
+	struct request_queue *q;
+	int cnt = FD_MAX_UNITS;
+	struct request *rq = NULL;
+
+	/* Find next queue we can dispatch from */
+	fdc_queue = fdc_queue + 1;
+	if (fdc_queue == FD_MAX_UNITS)
+		fdc_queue = 0;
+
+	for(cnt = FD_MAX_UNITS; cnt > 0; cnt--) {
+
+		if (unit[fdc_queue].type->code == FD_NODRIVE) {
+			if (++fdc_queue == FD_MAX_UNITS)
+				fdc_queue = 0;
+			continue;
+		}
+
+		q = unit[fdc_queue].gendisk->queue;
+		if (q) {
+			rq = blk_fetch_request(q);
+			if (rq)
+				break;
+		}
+
+		if (++fdc_queue == FD_MAX_UNITS)
+			fdc_queue = 0;
+	}
+
+	return rq;
+}
+
 static void redo_fd_request(void)
 {
 	struct request *rq;
@@ -1345,7 +1381,7 @@
 	int err;
 
 next_req:
-	rq = blk_fetch_request(floppy_queue);
+	rq = set_next_request();
 	if (!rq) {
 		/* Nothing left to do */
 		return;
@@ -1506,9 +1542,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&amiflop_mutex);
 	ret = fd_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
+	mutex_unlock(&amiflop_mutex);
 
 	return ret;
 }
@@ -1555,11 +1591,11 @@
 	int old_dev;
 	unsigned long flags;
 
-	lock_kernel();
+	mutex_lock(&amiflop_mutex);
 	old_dev = fd_device[drive];
 
 	if (fd_ref[drive] && old_dev != system) {
-		unlock_kernel();
+		mutex_unlock(&amiflop_mutex);
 		return -EBUSY;
 	}
 
@@ -1575,7 +1611,7 @@
 			rel_fdc();
 
 			if (wrprot) {
-				unlock_kernel();
+				mutex_unlock(&amiflop_mutex);
 				return -EROFS;
 			}
 		}
@@ -1594,7 +1630,7 @@
 	printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
 	       unit[drive].type->name, data_types[system].name);
 
-	unlock_kernel();
+	mutex_unlock(&amiflop_mutex);
 	return 0;
 }
 
@@ -1603,7 +1639,7 @@
 	struct amiga_floppy_struct *p = disk->private_data;
 	int drive = p - unit;
 
-	lock_kernel();
+	mutex_lock(&amiflop_mutex);
 	if (unit[drive].dirty == 1) {
 		del_timer (flush_track_timer + drive);
 		non_int_flush_track (drive);
@@ -1617,7 +1653,7 @@
 /* the mod_use counter is handled this way */
 	floppy_off (drive | 0x40000000);
 #endif
-	unlock_kernel();
+	mutex_unlock(&amiflop_mutex);
 	return 0;
 }
 
@@ -1682,6 +1718,13 @@
 			continue;
 		}
 		unit[drive].gendisk = disk;
+
+		disk->queue = blk_init_queue(do_fd_request, &amiflop_lock);
+		if (!disk->queue) {
+			unit[drive].type->code = FD_NODRIVE;
+			continue;
+		}
+
 		drives++;
 		if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
 			printk("no mem for ");
@@ -1695,7 +1738,6 @@
 		disk->fops = &floppy_fops;
 		sprintf(disk->disk_name, "fd%d", drive);
 		disk->private_data = &unit[drive];
-		disk->queue = floppy_queue;
 		set_capacity(disk, 880*2);
 		add_disk(disk);
 	}
@@ -1743,11 +1785,6 @@
 		goto out_irq2;
 	}
 
-	ret = -ENOMEM;
-	floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock);
-	if (!floppy_queue)
-		goto out_queue;
-
 	ret = -ENODEV;
 	if (fd_probe_drives() < 1) /* No usable drives */
 		goto out_probe;
@@ -1791,8 +1828,6 @@
 	return 0;
 
 out_probe:
-	blk_cleanup_queue(floppy_queue);
-out_queue:
 	free_irq(IRQ_AMIGA_CIAA_TB, NULL);
 out_irq2:
 	free_irq(IRQ_AMIGA_DSKBLK, NULL);
@@ -1810,9 +1845,12 @@
 
 	for( i = 0; i < FD_MAX_UNITS; i++) {
 		if (unit[i].type->code != FD_NODRIVE) {
+			struct request_queue *q = unit[i].gendisk->queue;
 			del_gendisk(unit[i].gendisk);
 			put_disk(unit[i].gendisk);
 			kfree(unit[i].trackbuf);
+			if (q)
+				blk_cleanup_queue(q);
 		}
 	}
 	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
@@ -1820,7 +1858,6 @@
 	free_irq(IRQ_AMIGA_DSKBLK, NULL);
 	custom.dmacon = DMAF_DISK; /* disable DMA */
 	amiga_chip_free(raw_buf);
-	blk_cleanup_queue(floppy_queue);
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 }
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/block/aoe/aoeblk.c linux-libre-2.6.37-gnu/drivers/block/aoe/aoeblk.c
--- linux-libre-2.6.36-gnu/drivers/block/aoe/aoeblk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/aoe/aoeblk.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,17 +4,20 @@
  * block device routines
  */
 
+#include <linux/kernel.h>
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/genhd.h>
 #include <linux/netdevice.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include "aoe.h"
 
+static DEFINE_MUTEX(aoeblk_mutex);
 static struct kmem_cache *buf_pool_cache;
 
 static ssize_t aoedisk_show_state(struct device *dev,
@@ -125,16 +128,16 @@
 	struct aoedev *d = bdev->bd_disk->private_data;
 	ulong flags;
 
-	lock_kernel();
+	mutex_lock(&aoeblk_mutex);
 	spin_lock_irqsave(&d->lock, flags);
 	if (d->flags & DEVFL_UP) {
 		d->nopen++;
 		spin_unlock_irqrestore(&d->lock, flags);
-		unlock_kernel();
+		mutex_unlock(&aoeblk_mutex);
 		return 0;
 	}
 	spin_unlock_irqrestore(&d->lock, flags);
-	unlock_kernel();
+	mutex_unlock(&aoeblk_mutex);
 	return -ENODEV;
 }
 
@@ -177,9 +180,6 @@
 		BUG();
 		bio_endio(bio, -ENXIO);
 		return 0;
-	} else if (bio->bi_rw & REQ_HARDBARRIER) {
-		bio_endio(bio, -EOPNOTSUPP);
-		return 0;
 	} else if (bio->bi_io_vec == NULL) {
 		printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
 		BUG();
@@ -206,7 +206,7 @@
 	spin_lock_irqsave(&d->lock, flags);
 
 	if ((d->flags & DEVFL_UP) == 0) {
-		printk(KERN_INFO "aoe: device %ld.%d is not up\n",
+		pr_info_ratelimited("aoe: device %ld.%d is not up\n",
 			d->aoemajor, d->aoeminor);
 		spin_unlock_irqrestore(&d->lock, flags);
 		mempool_free(buf, d->bufpool);
diff -druN linux-libre-2.6.36-gnu/drivers/block/aoe/aoechr.c linux-libre-2.6.37-gnu/drivers/block/aoe/aoechr.c
--- linux-libre-2.6.36-gnu/drivers/block/aoe/aoechr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/aoe/aoechr.c	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/skbuff.h>
 #include "aoe.h"
 
@@ -37,6 +37,7 @@
 	char *msg;
 };
 
+static DEFINE_MUTEX(aoechr_mutex);
 static struct ErrMsg emsgs[NMSG];
 static int emsgs_head_idx, emsgs_tail_idx;
 static struct completion emsgs_comp;
@@ -183,16 +184,16 @@
 {
 	int n, i;
 
-	lock_kernel();
+	mutex_lock(&aoechr_mutex);
 	n = iminor(inode);
 	filp->private_data = (void *) (unsigned long) n;
 
 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
 		if (chardevs[i].minor == n) {
-			unlock_kernel();
+			mutex_unlock(&aoechr_mutex);
 			return 0;
 		}
-	unlock_kernel();
+	mutex_unlock(&aoechr_mutex);
 	return -EINVAL;
 }
 
@@ -265,6 +266,7 @@
 	.open = aoechr_open,
 	.release = aoechr_rel,
 	.owner = THIS_MODULE,
+	.llseek = noop_llseek,
 };
 
 static char *aoe_devnode(struct device *dev, mode_t *mode)
diff -druN linux-libre-2.6.36-gnu/drivers/block/aoe/aoedev.c linux-libre-2.6.37-gnu/drivers/block/aoe/aoedev.c
--- linux-libre-2.6.36-gnu/drivers/block/aoe/aoedev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/aoe/aoedev.c	2011-01-04 19:50:19.000000000 -0500
@@ -102,6 +102,7 @@
 {
 	struct aoetgt **t, **e;
 
+	cancel_work_sync(&d->work);
 	if (d->gd) {
 		aoedisk_rm_sysfs(d);
 		del_gendisk(d->gd);
@@ -135,7 +136,6 @@
 		all = !strncmp(buf, "all", 3);
 	}
 
-	flush_scheduled_work();
 	spin_lock_irqsave(&devlist_lock, flags);
 	dd = &devlist;
 	while ((d = *dd)) {
@@ -257,8 +257,6 @@
 	struct aoedev *d;
 	ulong flags;
 
-	flush_scheduled_work();
-
 	while ((d = devlist)) {
 		devlist = d->next;
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/ataflop.c linux-libre-2.6.37-gnu/drivers/block/ataflop.c
--- linux-libre-2.6.36-gnu/drivers/block/ataflop.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/ataflop.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,7 +67,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/atafd.h>
 #include <asm/atafdreg.h>
@@ -79,8 +79,9 @@
 
 #undef DEBUG
 
-static struct request_queue *floppy_queue;
+static DEFINE_MUTEX(ataflop_mutex);
 static struct request *fd_request;
+static int fdc_queue;
 
 /* Disk types: DD, HD, ED */
 static struct atari_disk_type {
@@ -1391,6 +1392,29 @@
 			ReqTrack, ReqSector, (unsigned long)ReqData ));
 }
 
+/*
+ * Round-robin between our available drives, doing one request from each
+ */
+static struct request *set_next_request(void)
+{
+	struct request_queue *q;
+	int old_pos = fdc_queue;
+	struct request *rq = NULL;
+
+	do {
+		q = unit[fdc_queue].disk->queue;
+		if (++fdc_queue == FD_MAX_UNITS)
+			fdc_queue = 0;
+		if (q) {
+			rq = blk_fetch_request(q);
+			if (rq)
+				break;
+		}
+	} while (fdc_queue != old_pos);
+
+	return rq;
+}
+
 
 static void redo_fd_request(void)
 {
@@ -1405,7 +1429,7 @@
 
 repeat:
 	if (!fd_request) {
-		fd_request = blk_fetch_request(floppy_queue);
+		fd_request = set_next_request();
 		if (!fd_request)
 			goto the_end;
 	}
@@ -1671,9 +1695,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ataflop_mutex);
 	ret = fd_locked_ioctl(bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ataflop_mutex);
 
 	return ret;
 }
@@ -1854,9 +1878,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ataflop_mutex);
 	ret = floppy_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&ataflop_mutex);
 
 	return ret;
 }
@@ -1864,14 +1888,14 @@
 static int floppy_release(struct gendisk *disk, fmode_t mode)
 {
 	struct atari_floppy_struct *p = disk->private_data;
-	lock_kernel();
+	mutex_lock(&ataflop_mutex);
 	if (p->ref < 0)
 		p->ref = 0;
 	else if (!p->ref--) {
 		printk(KERN_ERR "floppy_release with fd_ref == 0");
 		p->ref = 0;
 	}
-	unlock_kernel();
+	mutex_unlock(&ataflop_mutex);
 	return 0;
 }
 
@@ -1932,10 +1956,6 @@
 	PhysTrackBuffer = virt_to_phys(TrackBuffer);
 	BufferDrive = BufferSide = BufferTrack = -1;
 
-	floppy_queue = blk_init_queue(do_fd_request, &ataflop_lock);
-	if (!floppy_queue)
-		goto Enomem;
-
 	for (i = 0; i < FD_MAX_UNITS; i++) {
 		unit[i].track = -1;
 		unit[i].flags = 0;
@@ -1944,7 +1964,10 @@
 		sprintf(unit[i].disk->disk_name, "fd%d", i);
 		unit[i].disk->fops = &floppy_fops;
 		unit[i].disk->private_data = &unit[i];
-		unit[i].disk->queue = floppy_queue;
+		unit[i].disk->queue = blk_init_queue(do_fd_request,
+					&ataflop_lock);
+		if (!unit[i].disk->queue)
+			goto Enomem;
 		set_capacity(unit[i].disk, MAX_DISK_SIZE * 2);
 		add_disk(unit[i].disk);
 	}
@@ -1959,10 +1982,14 @@
 
 	return 0;
 Enomem:
-	while (i--)
+	while (i--) {
+		struct request_queue *q = unit[i].disk->queue;
+
 		put_disk(unit[i].disk);
-	if (floppy_queue)
-		blk_cleanup_queue(floppy_queue);
+		if (q)
+			blk_cleanup_queue(q);
+	}
+
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 	return -ENOMEM;
 }
@@ -2011,12 +2038,14 @@
 	int i;
 	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
 	for (i = 0; i < FD_MAX_UNITS; i++) {
+		struct request_queue *q = unit[i].disk->queue;
+
 		del_gendisk(unit[i].disk);
 		put_disk(unit[i].disk);
+		blk_cleanup_queue(q);
 	}
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 
-	blk_cleanup_queue(floppy_queue);
 	del_timer_sync(&fd_timer);
 	atari_stram_free( DMABuffer );
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/brd.c linux-libre-2.6.37-gnu/drivers/block/brd.c
--- linux-libre-2.6.36-gnu/drivers/block/brd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/brd.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
 #include <linux/blkdev.h>
 #include <linux/bio.h>
 #include <linux/highmem.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/radix-tree.h>
 #include <linux/buffer_head.h> /* invalidate_bh_lrus() */
 #include <linux/slab.h>
@@ -55,6 +55,7 @@
 /*
  * Look up and return a brd's page for a given sector.
  */
+static DEFINE_MUTEX(brd_mutex);
 static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector)
 {
 	pgoff_t idx;
@@ -402,7 +403,7 @@
 	 * ram device BLKFLSBUF has special semantics, we want to actually
 	 * release and destroy the ramdisk data.
 	 */
-	lock_kernel();
+	mutex_lock(&brd_mutex);
 	mutex_lock(&bdev->bd_mutex);
 	error = -EBUSY;
 	if (bdev->bd_openers <= 1) {
@@ -419,7 +420,7 @@
 		error = 0;
 	}
 	mutex_unlock(&bdev->bd_mutex);
-	unlock_kernel();
+	mutex_unlock(&brd_mutex);
 
 	return error;
 }
@@ -482,7 +483,6 @@
 	if (!brd->brd_queue)
 		goto out_free_dev;
 	blk_queue_make_request(brd->brd_queue, brd_make_request);
-	blk_queue_ordered(brd->brd_queue, QUEUE_ORDERED_TAG);
 	blk_queue_max_hw_sectors(brd->brd_queue, 1024);
 	blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/cciss.c linux-libre-2.6.37-gnu/drivers/block/cciss.c
--- linux-libre-2.6.36-gnu/drivers/block/cciss.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/cciss.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,6 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/major.h>
 #include <linux/fs.h>
@@ -66,11 +65,8 @@
 MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
 
-static int cciss_allow_hpsa;
-module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(cciss_allow_hpsa,
-	"Prevent cciss driver from accessing hardware known to be "
-	" supported by the hpsa driver");
+static DEFINE_MUTEX(cciss_mutex);
+static struct proc_dir_entry *proc_cciss;
 
 #include "cciss_cmd.h"
 #include "cciss.h"
@@ -98,18 +94,6 @@
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSD,     0x103C, 0x3215},
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x3237},
 	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSC,     0x103C, 0x323D},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3241},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3243},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324A},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324B},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3250},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3251},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3252},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3253},
-	{PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3254},
 	{0,}
 };
 
@@ -130,6 +114,8 @@
 	{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
 	{0x40910E11, "Smart Array 6i", &SA5_access},
 	{0x3225103C, "Smart Array P600", &SA5_access},
+	{0x3223103C, "Smart Array P800", &SA5_access},
+	{0x3234103C, "Smart Array P400", &SA5_access},
 	{0x3235103C, "Smart Array P400i", &SA5_access},
 	{0x3211103C, "Smart Array E200i", &SA5_access},
 	{0x3212103C, "Smart Array E200", &SA5_access},
@@ -137,23 +123,9 @@
 	{0x3214103C, "Smart Array E200i", &SA5_access},
 	{0x3215103C, "Smart Array E200i", &SA5_access},
 	{0x3237103C, "Smart Array E500", &SA5_access},
-/* controllers below this line are also supported by the hpsa driver. */
-#define HPSA_BOUNDARY 0x3223103C
 	{0x3223103C, "Smart Array P800", &SA5_access},
 	{0x3234103C, "Smart Array P400", &SA5_access},
 	{0x323D103C, "Smart Array P700m", &SA5_access},
-	{0x3241103C, "Smart Array P212", &SA5_access},
-	{0x3243103C, "Smart Array P410", &SA5_access},
-	{0x3245103C, "Smart Array P410i", &SA5_access},
-	{0x3247103C, "Smart Array P411", &SA5_access},
-	{0x3249103C, "Smart Array P812", &SA5_access},
-	{0x324A103C, "Smart Array P712m", &SA5_access},
-	{0x324B103C, "Smart Array P711m", &SA5_access},
-	{0x3250103C, "Smart Array", &SA5_access},
-	{0x3251103C, "Smart Array", &SA5_access},
-	{0x3252103C, "Smart Array", &SA5_access},
-	{0x3253103C, "Smart Array", &SA5_access},
-	{0x3254103C, "Smart Array", &SA5_access},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -392,8 +364,6 @@
 #define ENG_GIG_FACTOR (ENG_GIG/512)
 #define ENGAGE_SCSI	"engage scsi"
 
-static struct proc_dir_entry *proc_cciss;
-
 static void cciss_seq_show_header(struct seq_file *seq)
 {
 	ctlr_info_t *h = seq->private;
@@ -1059,9 +1029,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&cciss_mutex);
 	ret = cciss_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&cciss_mutex);
 
 	return ret;
 }
@@ -1074,13 +1044,13 @@
 	ctlr_info_t *h;
 	drive_info_struct *drv;
 
-	lock_kernel();
+	mutex_lock(&cciss_mutex);
 	h = get_host(disk);
 	drv = get_drv(disk);
 	dev_dbg(&h->pdev->dev, "cciss_release %s\n", disk->disk_name);
 	drv->usage_count--;
 	h->usage_count--;
-	unlock_kernel();
+	mutex_unlock(&cciss_mutex);
 	return 0;
 }
 
@@ -1088,9 +1058,9 @@
 		    unsigned cmd, unsigned long arg)
 {
 	int ret;
-	lock_kernel();
+	mutex_lock(&cciss_mutex);
 	ret = cciss_ioctl(bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&cciss_mutex);
 	return ret;
 }
 
@@ -1182,6 +1152,7 @@
 	int err;
 	u32 cp;
 
+	memset(&arg64, 0, sizeof(arg64));
 	err = 0;
 	err |=
 	    copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
@@ -1232,470 +1203,452 @@
 			c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION)
 		(void)check_for_unit_attention(h, c);
 }
-/*
- * ioctl
- */
-static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
-		       unsigned int cmd, unsigned long arg)
+
+static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp)
 {
-	struct gendisk *disk = bdev->bd_disk;
-	ctlr_info_t *h = get_host(disk);
-	drive_info_struct *drv = get_drv(disk);
-	void __user *argp = (void __user *)arg;
+	cciss_pci_info_struct pciinfo;
 
-	dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n",
-		cmd, arg);
-	switch (cmd) {
-	case CCISS_GETPCIINFO:
-		{
-			cciss_pci_info_struct pciinfo;
+	if (!argp)
+		return -EINVAL;
+	pciinfo.domain = pci_domain_nr(h->pdev->bus);
+	pciinfo.bus = h->pdev->bus->number;
+	pciinfo.dev_fn = h->pdev->devfn;
+	pciinfo.board_id = h->board_id;
+	if (copy_to_user(argp, &pciinfo, sizeof(cciss_pci_info_struct)))
+		return -EFAULT;
+	return 0;
+}
 
-			if (!arg)
-				return -EINVAL;
-			pciinfo.domain = pci_domain_nr(h->pdev->bus);
-			pciinfo.bus = h->pdev->bus->number;
-			pciinfo.dev_fn = h->pdev->devfn;
-			pciinfo.board_id = h->board_id;
-			if (copy_to_user
-			    (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_GETINTINFO:
-		{
-			cciss_coalint_struct intinfo;
-			if (!arg)
-				return -EINVAL;
-			intinfo.delay =
-			    readl(&h->cfgtable->HostWrite.CoalIntDelay);
-			intinfo.count =
-			    readl(&h->cfgtable->HostWrite.CoalIntCount);
-			if (copy_to_user
-			    (argp, &intinfo, sizeof(cciss_coalint_struct)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_SETINTINFO:
-		{
-			cciss_coalint_struct intinfo;
-			unsigned long flags;
-			int i;
+static int cciss_getintinfo(ctlr_info_t *h, void __user *argp)
+{
+	cciss_coalint_struct intinfo;
 
-			if (!arg)
-				return -EINVAL;
-			if (!capable(CAP_SYS_ADMIN))
-				return -EPERM;
-			if (copy_from_user
-			    (&intinfo, argp, sizeof(cciss_coalint_struct)))
-				return -EFAULT;
-			if ((intinfo.delay == 0) && (intinfo.count == 0))
-				return -EINVAL;
-			spin_lock_irqsave(&h->lock, flags);
-			/* Update the field, and then ring the doorbell */
-			writel(intinfo.delay,
-			       &(h->cfgtable->HostWrite.CoalIntDelay));
-			writel(intinfo.count,
-			       &(h->cfgtable->HostWrite.CoalIntCount));
-			writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+	if (!argp)
+		return -EINVAL;
+	intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay);
+	intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount);
+	if (copy_to_user
+	    (argp, &intinfo, sizeof(cciss_coalint_struct)))
+		return -EFAULT;
+	return 0;
+}
 
-			for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-				if (!(readl(h->vaddr + SA5_DOORBELL)
-				      & CFGTBL_ChangeReq))
-					break;
-				/* delay and try again */
-				udelay(1000);
-			}
-			spin_unlock_irqrestore(&h->lock, flags);
-			if (i >= MAX_IOCTL_CONFIG_WAIT)
-				return -EAGAIN;
-			return 0;
-		}
-	case CCISS_GETNODENAME:
-		{
-			NodeName_type NodeName;
-			int i;
+static int cciss_setintinfo(ctlr_info_t *h, void __user *argp)
+{
+	cciss_coalint_struct intinfo;
+	unsigned long flags;
+	int i;
 
-			if (!arg)
-				return -EINVAL;
-			for (i = 0; i < 16; i++)
-				NodeName[i] =
-				    readb(&h->cfgtable->ServerName[i]);
-			if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_SETNODENAME:
-		{
-			NodeName_type NodeName;
-			unsigned long flags;
-			int i;
+	if (!argp)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (copy_from_user(&intinfo, argp, sizeof(intinfo)))
+		return -EFAULT;
+	if ((intinfo.delay == 0) && (intinfo.count == 0))
+		return -EINVAL;
+	spin_lock_irqsave(&h->lock, flags);
+	/* Update the field, and then ring the doorbell */
+	writel(intinfo.delay, &(h->cfgtable->HostWrite.CoalIntDelay));
+	writel(intinfo.count, &(h->cfgtable->HostWrite.CoalIntCount));
+	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
 
-			if (!arg)
-				return -EINVAL;
-			if (!capable(CAP_SYS_ADMIN))
-				return -EPERM;
+	for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+			break;
+		udelay(1000); /* delay and try again */
+	}
+	spin_unlock_irqrestore(&h->lock, flags);
+	if (i >= MAX_IOCTL_CONFIG_WAIT)
+		return -EAGAIN;
+	return 0;
+}
 
-			if (copy_from_user
-			    (NodeName, argp, sizeof(NodeName_type)))
-				return -EFAULT;
+static int cciss_getnodename(ctlr_info_t *h, void __user *argp)
+{
+	NodeName_type NodeName;
+	int i;
 
-			spin_lock_irqsave(&h->lock, flags);
+	if (!argp)
+		return -EINVAL;
+	for (i = 0; i < 16; i++)
+		NodeName[i] = readb(&h->cfgtable->ServerName[i]);
+	if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+		return -EFAULT;
+	return 0;
+}
 
-			/* Update the field, and then ring the doorbell */
-			for (i = 0; i < 16; i++)
-				writeb(NodeName[i],
-				       &h->cfgtable->ServerName[i]);
+static int cciss_setnodename(ctlr_info_t *h, void __user *argp)
+{
+	NodeName_type NodeName;
+	unsigned long flags;
+	int i;
 
-			writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+	if (!argp)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (copy_from_user(NodeName, argp, sizeof(NodeName_type)))
+		return -EFAULT;
+	spin_lock_irqsave(&h->lock, flags);
+	/* Update the field, and then ring the doorbell */
+	for (i = 0; i < 16; i++)
+		writeb(NodeName[i], &h->cfgtable->ServerName[i]);
+	writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+	for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+			break;
+		udelay(1000); /* delay and try again */
+	}
+	spin_unlock_irqrestore(&h->lock, flags);
+	if (i >= MAX_IOCTL_CONFIG_WAIT)
+		return -EAGAIN;
+	return 0;
+}
 
-			for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
-				if (!(readl(h->vaddr + SA5_DOORBELL)
-				      & CFGTBL_ChangeReq))
-					break;
-				/* delay and try again */
-				udelay(1000);
-			}
-			spin_unlock_irqrestore(&h->lock, flags);
-			if (i >= MAX_IOCTL_CONFIG_WAIT)
-				return -EAGAIN;
-			return 0;
-		}
+static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp)
+{
+	Heartbeat_type heartbeat;
 
-	case CCISS_GETHEARTBEAT:
-		{
-			Heartbeat_type heartbeat;
+	if (!argp)
+		return -EINVAL;
+	heartbeat = readl(&h->cfgtable->HeartBeat);
+	if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type)))
+		return -EFAULT;
+	return 0;
+}
 
-			if (!arg)
-				return -EINVAL;
-			heartbeat = readl(&h->cfgtable->HeartBeat);
-			if (copy_to_user
-			    (argp, &heartbeat, sizeof(Heartbeat_type)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_GETBUSTYPES:
-		{
-			BusTypes_type BusTypes;
+static int cciss_getbustypes(ctlr_info_t *h, void __user *argp)
+{
+	BusTypes_type BusTypes;
 
-			if (!arg)
-				return -EINVAL;
-			BusTypes = readl(&h->cfgtable->BusTypes);
-			if (copy_to_user
-			    (argp, &BusTypes, sizeof(BusTypes_type)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_GETFIRMVER:
-		{
-			FirmwareVer_type firmware;
+	if (!argp)
+		return -EINVAL;
+	BusTypes = readl(&h->cfgtable->BusTypes);
+	if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type)))
+		return -EFAULT;
+	return 0;
+}
 
-			if (!arg)
-				return -EINVAL;
-			memcpy(firmware, h->firm_ver, 4);
+static int cciss_getfirmver(ctlr_info_t *h, void __user *argp)
+{
+	FirmwareVer_type firmware;
 
-			if (copy_to_user
-			    (argp, firmware, sizeof(FirmwareVer_type)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_GETDRIVVER:
-		{
-			DriverVer_type DriverVer = DRIVER_VERSION;
+	if (!argp)
+		return -EINVAL;
+	memcpy(firmware, h->firm_ver, 4);
 
-			if (!arg)
-				return -EINVAL;
+	if (copy_to_user
+	    (argp, firmware, sizeof(FirmwareVer_type)))
+		return -EFAULT;
+	return 0;
+}
 
-			if (copy_to_user
-			    (argp, &DriverVer, sizeof(DriverVer_type)))
-				return -EFAULT;
-			return 0;
-		}
+static int cciss_getdrivver(ctlr_info_t *h, void __user *argp)
+{
+	DriverVer_type DriverVer = DRIVER_VERSION;
 
-	case CCISS_DEREGDISK:
-	case CCISS_REGNEWD:
-	case CCISS_REVALIDVOLS:
-		return rebuild_lun_table(h, 0, 1);
+	if (!argp)
+		return -EINVAL;
+	if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type)))
+		return -EFAULT;
+	return 0;
+}
 
-	case CCISS_GETLUNINFO:{
-			LogvolInfo_struct luninfo;
+static int cciss_getluninfo(ctlr_info_t *h,
+	struct gendisk *disk, void __user *argp)
+{
+	LogvolInfo_struct luninfo;
+	drive_info_struct *drv = get_drv(disk);
 
-			memcpy(&luninfo.LunID, drv->LunID,
-				sizeof(luninfo.LunID));
-			luninfo.num_opens = drv->usage_count;
-			luninfo.num_parts = 0;
-			if (copy_to_user(argp, &luninfo,
-					 sizeof(LogvolInfo_struct)))
-				return -EFAULT;
-			return 0;
-		}
-	case CCISS_PASSTHRU:
-		{
-			IOCTL_Command_struct iocommand;
-			CommandList_struct *c;
-			char *buff = NULL;
-			u64bit temp64;
-			DECLARE_COMPLETION_ONSTACK(wait);
+	if (!argp)
+		return -EINVAL;
+	memcpy(&luninfo.LunID, drv->LunID, sizeof(luninfo.LunID));
+	luninfo.num_opens = drv->usage_count;
+	luninfo.num_parts = 0;
+	if (copy_to_user(argp, &luninfo, sizeof(LogvolInfo_struct)))
+		return -EFAULT;
+	return 0;
+}
 
-			if (!arg)
-				return -EINVAL;
+static int cciss_passthru(ctlr_info_t *h, void __user *argp)
+{
+	IOCTL_Command_struct iocommand;
+	CommandList_struct *c;
+	char *buff = NULL;
+	u64bit temp64;
+	DECLARE_COMPLETION_ONSTACK(wait);
 
-			if (!capable(CAP_SYS_RAWIO))
-				return -EPERM;
+	if (!argp)
+		return -EINVAL;
 
-			if (copy_from_user
-			    (&iocommand, argp, sizeof(IOCTL_Command_struct)))
-				return -EFAULT;
-			if ((iocommand.buf_size < 1) &&
-			    (iocommand.Request.Type.Direction != XFER_NONE)) {
-				return -EINVAL;
-			}
-#if 0				/* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
-			/* Check kmalloc limits */
-			if (iocommand.buf_size > 128000)
-				return -EINVAL;
-#endif
-			if (iocommand.buf_size > 0) {
-				buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
-				if (buff == NULL)
-					return -EFAULT;
-			}
-			if (iocommand.Request.Type.Direction == XFER_WRITE) {
-				/* Copy the data into the buffer we created */
-				if (copy_from_user
-				    (buff, iocommand.buf, iocommand.buf_size)) {
-					kfree(buff);
-					return -EFAULT;
-				}
-			} else {
-				memset(buff, 0, iocommand.buf_size);
-			}
-			c = cmd_special_alloc(h);
-			if (!c) {
-				kfree(buff);
-				return -ENOMEM;
-			}
-			/* Fill in the command type */
-			c->cmd_type = CMD_IOCTL_PEND;
-			/* Fill in Command Header */
-			c->Header.ReplyQueue = 0;   /* unused in simple mode */
-			if (iocommand.buf_size > 0) /* buffer to fill */
-			{
-				c->Header.SGList = 1;
-				c->Header.SGTotal = 1;
-			} else /* no buffers to fill */
-			{
-				c->Header.SGList = 0;
-				c->Header.SGTotal = 0;
-			}
-			c->Header.LUN = iocommand.LUN_info;
-			/* use the kernel address the cmd block for tag */
-			c->Header.Tag.lower = c->busaddr;
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
 
-			/* Fill in Request block */
-			c->Request = iocommand.Request;
+	if (copy_from_user
+	    (&iocommand, argp, sizeof(IOCTL_Command_struct)))
+		return -EFAULT;
+	if ((iocommand.buf_size < 1) &&
+	    (iocommand.Request.Type.Direction != XFER_NONE)) {
+		return -EINVAL;
+	}
+	if (iocommand.buf_size > 0) {
+		buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+		if (buff == NULL)
+			return -EFAULT;
+	}
+	if (iocommand.Request.Type.Direction == XFER_WRITE) {
+		/* Copy the data into the buffer we created */
+		if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) {
+			kfree(buff);
+			return -EFAULT;
+		}
+	} else {
+		memset(buff, 0, iocommand.buf_size);
+	}
+	c = cmd_special_alloc(h);
+	if (!c) {
+		kfree(buff);
+		return -ENOMEM;
+	}
+	/* Fill in the command type */
+	c->cmd_type = CMD_IOCTL_PEND;
+	/* Fill in Command Header */
+	c->Header.ReplyQueue = 0;   /* unused in simple mode */
+	if (iocommand.buf_size > 0) { /* buffer to fill */
+		c->Header.SGList = 1;
+		c->Header.SGTotal = 1;
+	} else { /* no buffers to fill */
+		c->Header.SGList = 0;
+		c->Header.SGTotal = 0;
+	}
+	c->Header.LUN = iocommand.LUN_info;
+	/* use the kernel address the cmd block for tag */
+	c->Header.Tag.lower = c->busaddr;
 
-			/* Fill in the scatter gather information */
-			if (iocommand.buf_size > 0) {
-				temp64.val = pci_map_single(h->pdev, buff,
-					iocommand.buf_size,
-					PCI_DMA_BIDIRECTIONAL);
-				c->SG[0].Addr.lower = temp64.val32.lower;
-				c->SG[0].Addr.upper = temp64.val32.upper;
-				c->SG[0].Len = iocommand.buf_size;
-				c->SG[0].Ext = 0;  /* we are not chaining */
-			}
-			c->waiting = &wait;
+	/* Fill in Request block */
+	c->Request = iocommand.Request;
 
-			enqueue_cmd_and_start_io(h, c);
-			wait_for_completion(&wait);
+	/* Fill in the scatter gather information */
+	if (iocommand.buf_size > 0) {
+		temp64.val = pci_map_single(h->pdev, buff,
+			iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+		c->SG[0].Addr.lower = temp64.val32.lower;
+		c->SG[0].Addr.upper = temp64.val32.upper;
+		c->SG[0].Len = iocommand.buf_size;
+		c->SG[0].Ext = 0;  /* we are not chaining */
+	}
+	c->waiting = &wait;
 
-			/* unlock the buffers from DMA */
-			temp64.val32.lower = c->SG[0].Addr.lower;
-			temp64.val32.upper = c->SG[0].Addr.upper;
-			pci_unmap_single(h->pdev, (dma_addr_t) temp64.val,
-					 iocommand.buf_size,
-					 PCI_DMA_BIDIRECTIONAL);
+	enqueue_cmd_and_start_io(h, c);
+	wait_for_completion(&wait);
 
-			check_ioctl_unit_attention(h, c);
+	/* unlock the buffers from DMA */
+	temp64.val32.lower = c->SG[0].Addr.lower;
+	temp64.val32.upper = c->SG[0].Addr.upper;
+	pci_unmap_single(h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size,
+			 PCI_DMA_BIDIRECTIONAL);
+	check_ioctl_unit_attention(h, c);
 
-			/* Copy the error information out */
-			iocommand.error_info = *(c->err_info);
-			if (copy_to_user
-			    (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
-				kfree(buff);
-				cmd_special_free(h, c);
-				return -EFAULT;
-			}
+	/* Copy the error information out */
+	iocommand.error_info = *(c->err_info);
+	if (copy_to_user(argp, &iocommand, sizeof(IOCTL_Command_struct))) {
+		kfree(buff);
+		cmd_special_free(h, c);
+		return -EFAULT;
+	}
 
-			if (iocommand.Request.Type.Direction == XFER_READ) {
-				/* Copy the data out of the buffer we created */
-				if (copy_to_user
-				    (iocommand.buf, buff, iocommand.buf_size)) {
-					kfree(buff);
-					cmd_special_free(h, c);
-					return -EFAULT;
-				}
-			}
+	if (iocommand.Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+		if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
 			kfree(buff);
 			cmd_special_free(h, c);
-			return 0;
+			return -EFAULT;
 		}
-	case CCISS_BIG_PASSTHRU:{
-			BIG_IOCTL_Command_struct *ioc;
-			CommandList_struct *c;
-			unsigned char **buff = NULL;
-			int *buff_size = NULL;
-			u64bit temp64;
-			BYTE sg_used = 0;
-			int status = 0;
-			int i;
-			DECLARE_COMPLETION_ONSTACK(wait);
-			__u32 left;
-			__u32 sz;
-			BYTE __user *data_ptr;
+	}
+	kfree(buff);
+	cmd_special_free(h, c);
+	return 0;
+}
 
-			if (!arg)
-				return -EINVAL;
-			if (!capable(CAP_SYS_RAWIO))
-				return -EPERM;
-			ioc = (BIG_IOCTL_Command_struct *)
-			    kmalloc(sizeof(*ioc), GFP_KERNEL);
-			if (!ioc) {
-				status = -ENOMEM;
-				goto cleanup1;
-			}
-			if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp)
+{
+	BIG_IOCTL_Command_struct *ioc;
+	CommandList_struct *c;
+	unsigned char **buff = NULL;
+	int *buff_size = NULL;
+	u64bit temp64;
+	BYTE sg_used = 0;
+	int status = 0;
+	int i;
+	DECLARE_COMPLETION_ONSTACK(wait);
+	__u32 left;
+	__u32 sz;
+	BYTE __user *data_ptr;
+
+	if (!argp)
+		return -EINVAL;
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+	ioc = (BIG_IOCTL_Command_struct *)
+	    kmalloc(sizeof(*ioc), GFP_KERNEL);
+	if (!ioc) {
+		status = -ENOMEM;
+		goto cleanup1;
+	}
+	if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+		status = -EFAULT;
+		goto cleanup1;
+	}
+	if ((ioc->buf_size < 1) &&
+	    (ioc->Request.Type.Direction != XFER_NONE)) {
+		status = -EINVAL;
+		goto cleanup1;
+	}
+	/* Check kmalloc limits  using all SGs */
+	if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+		status = -EINVAL;
+		goto cleanup1;
+	}
+	if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+		status = -EINVAL;
+		goto cleanup1;
+	}
+	buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+	if (!buff) {
+		status = -ENOMEM;
+		goto cleanup1;
+	}
+	buff_size = kmalloc(MAXSGENTRIES * sizeof(int), GFP_KERNEL);
+	if (!buff_size) {
+		status = -ENOMEM;
+		goto cleanup1;
+	}
+	left = ioc->buf_size;
+	data_ptr = ioc->buf;
+	while (left) {
+		sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
+		buff_size[sg_used] = sz;
+		buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+		if (buff[sg_used] == NULL) {
+			status = -ENOMEM;
+			goto cleanup1;
+		}
+		if (ioc->Request.Type.Direction == XFER_WRITE) {
+			if (copy_from_user(buff[sg_used], data_ptr, sz)) {
 				status = -EFAULT;
 				goto cleanup1;
 			}
-			if ((ioc->buf_size < 1) &&
-			    (ioc->Request.Type.Direction != XFER_NONE)) {
-				status = -EINVAL;
-				goto cleanup1;
-			}
-			/* Check kmalloc limits  using all SGs */
-			if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
-				status = -EINVAL;
-				goto cleanup1;
-			}
-			if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
-				status = -EINVAL;
-				goto cleanup1;
-			}
-			buff =
-			    kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
-			if (!buff) {
-				status = -ENOMEM;
-				goto cleanup1;
-			}
-			buff_size = kmalloc(MAXSGENTRIES * sizeof(int),
-						   GFP_KERNEL);
-			if (!buff_size) {
-				status = -ENOMEM;
-				goto cleanup1;
-			}
-			left = ioc->buf_size;
-			data_ptr = ioc->buf;
-			while (left) {
-				sz = (left >
-				      ioc->malloc_size) ? ioc->
-				    malloc_size : left;
-				buff_size[sg_used] = sz;
-				buff[sg_used] = kmalloc(sz, GFP_KERNEL);
-				if (buff[sg_used] == NULL) {
-					status = -ENOMEM;
-					goto cleanup1;
-				}
-				if (ioc->Request.Type.Direction == XFER_WRITE) {
-					if (copy_from_user
-					    (buff[sg_used], data_ptr, sz)) {
-						status = -EFAULT;
-						goto cleanup1;
-					}
-				} else {
-					memset(buff[sg_used], 0, sz);
-				}
-				left -= sz;
-				data_ptr += sz;
-				sg_used++;
-			}
-			c = cmd_special_alloc(h);
-			if (!c) {
-				status = -ENOMEM;
-				goto cleanup1;
-			}
-			c->cmd_type = CMD_IOCTL_PEND;
-			c->Header.ReplyQueue = 0;
-
-			if (ioc->buf_size > 0) {
-				c->Header.SGList = sg_used;
-				c->Header.SGTotal = sg_used;
-			} else {
-				c->Header.SGList = 0;
-				c->Header.SGTotal = 0;
-			}
-			c->Header.LUN = ioc->LUN_info;
-			c->Header.Tag.lower = c->busaddr;
+		} else {
+			memset(buff[sg_used], 0, sz);
+		}
+		left -= sz;
+		data_ptr += sz;
+		sg_used++;
+	}
+	c = cmd_special_alloc(h);
+	if (!c) {
+		status = -ENOMEM;
+		goto cleanup1;
+	}
+	c->cmd_type = CMD_IOCTL_PEND;
+	c->Header.ReplyQueue = 0;
+	c->Header.SGList = sg_used;
+	c->Header.SGTotal = sg_used;
+	c->Header.LUN = ioc->LUN_info;
+	c->Header.Tag.lower = c->busaddr;
 
-			c->Request = ioc->Request;
-			if (ioc->buf_size > 0) {
-				for (i = 0; i < sg_used; i++) {
-					temp64.val =
-					    pci_map_single(h->pdev, buff[i],
-						    buff_size[i],
-						    PCI_DMA_BIDIRECTIONAL);
-					c->SG[i].Addr.lower =
-					    temp64.val32.lower;
-					c->SG[i].Addr.upper =
-					    temp64.val32.upper;
-					c->SG[i].Len = buff_size[i];
-					c->SG[i].Ext = 0;	/* we are not chaining */
-				}
-			}
-			c->waiting = &wait;
-			enqueue_cmd_and_start_io(h, c);
-			wait_for_completion(&wait);
-			/* unlock the buffers from DMA */
-			for (i = 0; i < sg_used; i++) {
-				temp64.val32.lower = c->SG[i].Addr.lower;
-				temp64.val32.upper = c->SG[i].Addr.upper;
-				pci_unmap_single(h->pdev,
-					(dma_addr_t) temp64.val, buff_size[i],
-					PCI_DMA_BIDIRECTIONAL);
-			}
-			check_ioctl_unit_attention(h, c);
-			/* Copy the error information out */
-			ioc->error_info = *(c->err_info);
-			if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+	c->Request = ioc->Request;
+	for (i = 0; i < sg_used; i++) {
+		temp64.val = pci_map_single(h->pdev, buff[i], buff_size[i],
+				    PCI_DMA_BIDIRECTIONAL);
+		c->SG[i].Addr.lower = temp64.val32.lower;
+		c->SG[i].Addr.upper = temp64.val32.upper;
+		c->SG[i].Len = buff_size[i];
+		c->SG[i].Ext = 0;	/* we are not chaining */
+	}
+	c->waiting = &wait;
+	enqueue_cmd_and_start_io(h, c);
+	wait_for_completion(&wait);
+	/* unlock the buffers from DMA */
+	for (i = 0; i < sg_used; i++) {
+		temp64.val32.lower = c->SG[i].Addr.lower;
+		temp64.val32.upper = c->SG[i].Addr.upper;
+		pci_unmap_single(h->pdev,
+			(dma_addr_t) temp64.val, buff_size[i],
+			PCI_DMA_BIDIRECTIONAL);
+	}
+	check_ioctl_unit_attention(h, c);
+	/* Copy the error information out */
+	ioc->error_info = *(c->err_info);
+	if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+		cmd_special_free(h, c);
+		status = -EFAULT;
+		goto cleanup1;
+	}
+	if (ioc->Request.Type.Direction == XFER_READ) {
+		/* Copy the data out of the buffer we created */
+		BYTE __user *ptr = ioc->buf;
+		for (i = 0; i < sg_used; i++) {
+			if (copy_to_user(ptr, buff[i], buff_size[i])) {
 				cmd_special_free(h, c);
 				status = -EFAULT;
 				goto cleanup1;
 			}
-			if (ioc->Request.Type.Direction == XFER_READ) {
-				/* Copy the data out of the buffer we created */
-				BYTE __user *ptr = ioc->buf;
-				for (i = 0; i < sg_used; i++) {
-					if (copy_to_user
-					    (ptr, buff[i], buff_size[i])) {
-						cmd_special_free(h, c);
-						status = -EFAULT;
-						goto cleanup1;
-					}
-					ptr += buff_size[i];
-				}
-			}
-			cmd_special_free(h, c);
-			status = 0;
-		      cleanup1:
-			if (buff) {
-				for (i = 0; i < sg_used; i++)
-					kfree(buff[i]);
-				kfree(buff);
-			}
-			kfree(buff_size);
-			kfree(ioc);
-			return status;
+			ptr += buff_size[i];
 		}
+	}
+	cmd_special_free(h, c);
+	status = 0;
+cleanup1:
+	if (buff) {
+		for (i = 0; i < sg_used; i++)
+			kfree(buff[i]);
+		kfree(buff);
+	}
+	kfree(buff_size);
+	kfree(ioc);
+	return status;
+}
+
+static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
+	unsigned int cmd, unsigned long arg)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	ctlr_info_t *h = get_host(disk);
+	void __user *argp = (void __user *)arg;
+
+	dev_dbg(&h->pdev->dev, "cciss_ioctl: Called with cmd=%x %lx\n",
+		cmd, arg);
+	switch (cmd) {
+	case CCISS_GETPCIINFO:
+		return cciss_getpciinfo(h, argp);
+	case CCISS_GETINTINFO:
+		return cciss_getintinfo(h, argp);
+	case CCISS_SETINTINFO:
+		return cciss_setintinfo(h, argp);
+	case CCISS_GETNODENAME:
+		return cciss_getnodename(h, argp);
+	case CCISS_SETNODENAME:
+		return cciss_setnodename(h, argp);
+	case CCISS_GETHEARTBEAT:
+		return cciss_getheartbeat(h, argp);
+	case CCISS_GETBUSTYPES:
+		return cciss_getbustypes(h, argp);
+	case CCISS_GETFIRMVER:
+		return cciss_getfirmver(h, argp);
+	case CCISS_GETDRIVVER:
+		return cciss_getdrivver(h, argp);
+	case CCISS_DEREGDISK:
+	case CCISS_REGNEWD:
+	case CCISS_REVALIDVOLS:
+		return rebuild_lun_table(h, 0, 1);
+	case CCISS_GETLUNINFO:
+		return cciss_getluninfo(h, disk, argp);
+	case CCISS_PASSTHRU:
+		return cciss_passthru(h, argp);
+	case CCISS_BIG_PASSTHRU:
+		return cciss_bigpassthru(h, argp);
 
 	/* scsi_cmd_ioctl handles these, below, though some are not */
 	/* very meaningful for cciss.  SG_IO is the main one people want. */
@@ -2881,6 +2834,8 @@
 	InquiryData_struct *inq_buff = NULL;
 
 	for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+		if (!h->drv[logvol])
+			continue;
 		if (memcmp(h->drv[logvol]->LunID, drv->LunID,
 			sizeof(drv->LunID)) == 0) {
 			FOUND = 1;
@@ -3801,7 +3756,7 @@
 	for (i = 0; i < MAX_CONFIG_WAIT; i++) {
 		if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
 			break;
-		msleep(10);
+		usleep_range(10000, 20000);
 	}
 }
 
@@ -3985,13 +3940,9 @@
 	*board_id = ((subsystem_device_id << 16) & 0xffff0000) |
 			subsystem_vendor_id;
 
-	for (i = 0; i < ARRAY_SIZE(products); i++) {
-		/* Stand aside for hpsa driver on request */
-		if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
-			return -ENODEV;
+	for (i = 0; i < ARRAY_SIZE(products); i++)
 		if (*board_id == products[i].board_id)
 			return i;
-	}
 	dev_warn(&pdev->dev, "unrecognized board ID: 0x%08x, ignoring.\n",
 		*board_id);
 	return -ENODEV;
@@ -4022,18 +3973,31 @@
 	return -ENODEV;
 }
 
-static int __devinit cciss_wait_for_board_ready(ctlr_info_t *h)
+static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
+	void __iomem *vaddr, int wait_for_ready)
+#define BOARD_READY 1
+#define BOARD_NOT_READY 0
 {
-	int i;
+	int i, iterations;
 	u32 scratchpad;
 
-	for (i = 0; i < CCISS_BOARD_READY_ITERATIONS; i++) {
-		scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
-		if (scratchpad == CCISS_FIRMWARE_READY)
-			return 0;
+	if (wait_for_ready)
+		iterations = CCISS_BOARD_READY_ITERATIONS;
+	else
+		iterations = CCISS_BOARD_NOT_READY_ITERATIONS;
+
+	for (i = 0; i < iterations; i++) {
+		scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET);
+		if (wait_for_ready) {
+			if (scratchpad == CCISS_FIRMWARE_READY)
+				return 0;
+		} else {
+			if (scratchpad != CCISS_FIRMWARE_READY)
+				return 0;
+		}
 		msleep(CCISS_BOARD_READY_POLL_INTERVAL_MSECS);
 	}
-	dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+	dev_warn(&pdev->dev, "board not ready, timed out.\n");
 	return -ENODEV;
 }
 
@@ -4082,6 +4046,11 @@
 static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
 	h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
+
+	/* Limit commands in memory limited kdump scenario. */
+	if (reset_devices && h->max_commands > 32)
+		h->max_commands = 32;
+
 	if (h->max_commands < 16) {
 		dev_warn(&h->pdev->dev, "Controller reports "
 			"max supported commands of %d, an obvious lie. "
@@ -4199,7 +4168,7 @@
 		err = -ENOMEM;
 		goto err_out_free_res;
 	}
-	err = cciss_wait_for_board_ready(h);
+	err = cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY);
 	if (err)
 		goto err_out_free_res;
 	err = cciss_find_cfgtables(h);
@@ -4364,36 +4333,6 @@
 #define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
 #define cciss_noop(p) cciss_message(p, 3, 0)
 
-static __devinit int cciss_reset_msi(struct pci_dev *pdev)
-{
-/* the #defines are stolen from drivers/pci/msi.h. */
-#define msi_control_reg(base)		(base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE		(1 << 15)
-
-	int pos;
-	u16 control = 0;
-
-	pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
-	if (pos) {
-		pci_read_config_word(pdev, msi_control_reg(pos), &control);
-		if (control & PCI_MSI_FLAGS_ENABLE) {
-			dev_info(&pdev->dev, "resetting MSI\n");
-			pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
-		}
-	}
-
-	pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-	if (pos) {
-		pci_read_config_word(pdev, msi_control_reg(pos), &control);
-		if (control & PCI_MSIX_FLAGS_ENABLE) {
-			dev_info(&pdev->dev, "resetting MSI-X\n");
-			pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
-		}
-	}
-
-	return 0;
-}
-
 static int cciss_controller_hard_reset(struct pci_dev *pdev,
 	void * __iomem vaddr, bool use_doorbell)
 {
@@ -4448,17 +4387,17 @@
  * states or using the doorbell register. */
 static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
-	u16 saved_config_space[32];
 	u64 cfg_offset;
 	u32 cfg_base_addr;
 	u64 cfg_base_addr_index;
 	void __iomem *vaddr;
 	unsigned long paddr;
 	u32 misc_fw_support, active_transport;
-	int rc, i;
+	int rc;
 	CfgTable_struct __iomem *cfgtable;
 	bool use_doorbell;
 	u32 board_id;
+	u16 command_register;
 
 	/* For controllers as old a the p600, this is very nearly
 	 * the same thing as
@@ -4468,14 +4407,6 @@
 	 * pci_set_power_state(pci_dev, PCI_D0);
 	 * pci_restore_state(pci_dev);
 	 *
-	 * but we can't use these nice canned kernel routines on
-	 * kexec, because they also check the MSI/MSI-X state in PCI
-	 * configuration space and do the wrong thing when it is
-	 * set/cleared.  Also, the pci_save/restore_state functions
-	 * violate the ordering requirements for restoring the
-	 * configuration space from the CCISS document (see the
-	 * comment below).  So we roll our own ....
-	 *
 	 * For controllers newer than the P600, the pci power state
 	 * method of resetting doesn't work so we have another way
 	 * using the doorbell register.
@@ -4494,8 +4425,13 @@
 		return -ENODEV;
 	}
 
-	for (i = 0; i < 32; i++)
-		pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+	/* Save the PCI command register */
+	pci_read_config_word(pdev, 4, &command_register);
+	/* Turn the board off.  This is so that later pci_restore_state()
+	 * won't turn the board on before the rest of config space is ready.
+	 */
+	pci_disable_device(pdev);
+	pci_save_state(pdev);
 
 	/* find the first memory BAR, so we can find the cfg table */
 	rc = cciss_pci_find_memory_BAR(pdev, &paddr);
@@ -4530,26 +4466,32 @@
 	rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
 	if (rc)
 		goto unmap_cfgtable;
-
-	/* Restore the PCI configuration space.  The Open CISS
-	 * Specification says, "Restore the PCI Configuration
-	 * Registers, offsets 00h through 60h. It is important to
-	 * restore the command register, 16-bits at offset 04h,
-	 * last. Do not restore the configuration status register,
-	 * 16-bits at offset 06h."  Note that the offset is 2*i.
-	 */
-	for (i = 0; i < 32; i++) {
-		if (i == 2 || i == 3)
-			continue;
-		pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+	pci_restore_state(pdev);
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		dev_warn(&pdev->dev, "failed to enable device.\n");
+		goto unmap_cfgtable;
 	}
-	wmb();
-	pci_write_config_word(pdev, 4, saved_config_space[2]);
+	pci_write_config_word(pdev, 4, command_register);
 
 	/* Some devices (notably the HP Smart Array 5i Controller)
 	   need a little pause here */
 	msleep(CCISS_POST_RESET_PAUSE_MSECS);
 
+	/* Wait for board to become not ready, then ready. */
+	dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+	rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
+	if (rc) /* Don't bail, might be E500, etc. which can't be reset */
+		dev_warn(&pdev->dev,
+			"failed waiting for board to become not ready\n");
+	rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
+	if (rc) {
+		dev_warn(&pdev->dev,
+			"failed waiting for board to become ready\n");
+		goto unmap_cfgtable;
+	}
+	dev_info(&pdev->dev, "board ready.\n");
+
 	/* Controller should be in simple mode at this point.  If it's not,
 	 * It means we're on one of those controllers which doesn't support
 	 * the doorbell reset method and on which the PCI power management reset
@@ -4590,8 +4532,6 @@
 		return 0; /* just try to do the kdump anyhow. */
 	if (rc)
 		return -ENODEV;
-	if (cciss_reset_msi(pdev))
-		return -ENODEV;
 
 	/* Now try to get the controller to respond to a no-op */
 	for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
@@ -4987,7 +4927,8 @@
 		}
 	}
 	kthread_stop(cciss_scan_thread);
-	remove_proc_entry("driver/cciss", NULL);
+	if (proc_cciss)
+		remove_proc_entry("driver/cciss", NULL);
 	bus_unregister(&cciss_bus_type);
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/cciss.h linux-libre-2.6.37-gnu/drivers/block/cciss.h
--- linux-libre-2.6.36-gnu/drivers/block/cciss.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/cciss.h	2011-01-04 19:50:19.000000000 -0500
@@ -200,10 +200,14 @@
  * the above.
  */
 #define CCISS_BOARD_READY_WAIT_SECS (120)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
 #define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
 #define CCISS_BOARD_READY_ITERATIONS \
 	((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
 		CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
+#define CCISS_BOARD_NOT_READY_ITERATIONS \
+	((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
+		CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
 #define CCISS_POST_RESET_PAUSE_MSECS (3000)
 #define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
 #define CCISS_POST_RESET_NOOP_RETRIES (12)
diff -druN linux-libre-2.6.36-gnu/drivers/block/cciss_scsi.c linux-libre-2.6.37-gnu/drivers/block/cciss_scsi.c
--- linux-libre-2.6.36-gnu/drivers/block/cciss_scsi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/cciss_scsi.c	2011-01-04 19:50:19.000000000 -0500
@@ -62,8 +62,8 @@
 		int length, 	   /* length of data in buffer */
 		int func);	   /* 0 == read, 1 == write */
 
-static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
-		void (* done)(struct scsi_cmnd *));
+static int cciss_scsi_queue_command (struct Scsi_Host *h,
+				     struct scsi_cmnd *cmd);
 static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
 static int cciss_eh_abort_handler(struct scsi_cmnd *);
 
@@ -1406,7 +1406,7 @@
 
 
 static int
-cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+cciss_scsi_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
 	ctlr_info_t *h;
 	int rc;
@@ -1504,6 +1504,8 @@
 	return 0;
 }
 
+static DEF_SCSI_QCMD(cciss_scsi_queue_command)
+
 static void cciss_unregister_scsi(ctlr_info_t *h)
 {
 	struct cciss_scsi_adapter_data_t *sa;
diff -druN linux-libre-2.6.36-gnu/drivers/block/cpqarray.c linux-libre-2.6.37-gnu/drivers/block/cpqarray.c
--- linux-libre-2.6.36-gnu/drivers/block/cpqarray.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/cpqarray.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,7 @@
 #include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
@@ -68,6 +68,7 @@
 
 #define CPQARRAY_DMA_MASK	0xFFFFFFFF	/* 32 bit DMA */
 
+static DEFINE_MUTEX(cpqarray_mutex);
 static int nr_ctlr;
 static ctlr_info_t *hba[MAX_CTLR];
 
@@ -845,9 +846,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&cpqarray_mutex);
 	ret = ida_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&cpqarray_mutex);
 
 	return ret;
 }
@@ -859,10 +860,10 @@
 {
 	ctlr_info_t *host;
 
-	lock_kernel();
+	mutex_lock(&cpqarray_mutex);
 	host = get_host(disk);
 	host->usage_count--;
-	unlock_kernel();
+	mutex_unlock(&cpqarray_mutex);
 
 	return 0;
 }
@@ -1217,9 +1218,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&cpqarray_mutex);
 	ret = ida_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
+	mutex_unlock(&cpqarray_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/DAC960.c linux-libre-2.6.37-gnu/drivers/block/DAC960.c
--- linux-libre-2.6.36-gnu/drivers/block/DAC960.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/DAC960.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,7 +36,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/reboot.h>
@@ -54,6 +54,7 @@
 #define DAC960_GAM_MINOR	252
 
 
+static DEFINE_MUTEX(DAC960_mutex);
 static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers];
 static int DAC960_ControllerCount;
 static struct proc_dir_entry *DAC960_ProcDirectoryEntry;
@@ -81,7 +82,7 @@
 	int drive_nr = (long)disk->private_data;
 	int ret = -ENXIO;
 
-	lock_kernel();
+	mutex_lock(&DAC960_mutex);
 	if (p->FirmwareType == DAC960_V1_Controller) {
 		if (p->V1.LogicalDriveInformation[drive_nr].
 		    LogicalDriveState == DAC960_V1_LogicalDrive_Offline)
@@ -99,7 +100,7 @@
 		goto out;
 	ret = 0;
 out:
-	unlock_kernel();
+	mutex_unlock(&DAC960_mutex);
 	return ret;
 }
 
@@ -6625,7 +6626,7 @@
   long ErrorCode = 0;
   if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 
-  lock_kernel();
+  mutex_lock(&DAC960_mutex);
   switch (Request)
     {
     case DAC960_IOCTL_GET_CONTROLLER_COUNT:
@@ -7056,13 +7057,14 @@
       default:
 	ErrorCode = -ENOTTY;
     }
-  unlock_kernel();
+  mutex_unlock(&DAC960_mutex);
   return ErrorCode;
 }
 
 static const struct file_operations DAC960_gam_fops = {
 	.owner		= THIS_MODULE,
-	.unlocked_ioctl	= DAC960_gam_ioctl
+	.unlocked_ioctl	= DAC960_gam_ioctl,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice DAC960_gam_dev = {
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_actlog.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_actlog.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_actlog.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_actlog.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,11 +78,10 @@
 	init_completion(&md_io.event);
 	md_io.error = 0;
 
-	if ((rw & WRITE) && !test_bit(MD_NO_BARRIER, &mdev->flags))
-		rw |= REQ_HARDBARRIER;
+	if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags))
+		rw |= REQ_FUA;
 	rw |= REQ_UNPLUG | REQ_SYNC;
 
- retry:
 	bio = bio_alloc(GFP_NOIO, 1);
 	bio->bi_bdev = bdev->md_bdev;
 	bio->bi_sector = sector;
@@ -100,17 +99,6 @@
 	wait_for_completion(&md_io.event);
 	ok = bio_flagged(bio, BIO_UPTODATE) && md_io.error == 0;
 
-	/* check for unsupported barrier op.
-	 * would rather check on EOPNOTSUPP, but that is not reliable.
-	 * don't try again for ANY return value != 0 */
-	if (unlikely((bio->bi_rw & REQ_HARDBARRIER) && !ok)) {
-		/* Try again with no barrier */
-		dev_warn(DEV, "Barriers not supported on meta data device - disabling\n");
-		set_bit(MD_NO_BARRIER, &mdev->flags);
-		rw &= ~REQ_HARDBARRIER;
-		bio_put(bio);
-		goto retry;
-	}
  out:
 	bio_put(bio);
 	return ok;
@@ -284,18 +272,32 @@
 	u32 xor_sum = 0;
 
 	if (!get_ldev(mdev)) {
-		dev_err(DEV, "get_ldev() failed in w_al_write_transaction\n");
+		dev_err(DEV,
+			"disk is %s, cannot start al transaction (-%d +%d)\n",
+			drbd_disk_str(mdev->state.disk), evicted, new_enr);
 		complete(&((struct update_al_work *)w)->event);
 		return 1;
 	}
 	/* do we have to do a bitmap write, first?
 	 * TODO reduce maximum latency:
 	 * submit both bios, then wait for both,
-	 * instead of doing two synchronous sector writes. */
+	 * instead of doing two synchronous sector writes.
+	 * For now, we must not write the transaction,
+	 * if we cannot write out the bitmap of the evicted extent. */
 	if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE)
 		drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT);
 
-	mutex_lock(&mdev->md_io_mutex); /* protects md_io_page, al_tr_cycle, ... */
+	/* The bitmap write may have failed, causing a state change. */
+	if (mdev->state.disk < D_INCONSISTENT) {
+		dev_err(DEV,
+			"disk is %s, cannot write al transaction (-%d +%d)\n",
+			drbd_disk_str(mdev->state.disk), evicted, new_enr);
+		complete(&((struct update_al_work *)w)->event);
+		put_ldev(mdev);
+		return 1;
+	}
+
+	mutex_lock(&mdev->md_io_mutex); /* protects md_io_buffer, al_tr_cycle, ... */
 	buffer = (struct al_transaction *)page_address(mdev->md_io_page);
 
 	buffer->magic = __constant_cpu_to_be32(DRBD_MAGIC);
@@ -739,7 +741,7 @@
 	unsigned int enr;
 	unsigned long add = 0;
 	char ppb[10];
-	int i;
+	int i, tmp;
 
 	wait_event(mdev->al_wait, lc_try_lock(mdev->act_log));
 
@@ -747,7 +749,9 @@
 		enr = lc_element_by_index(mdev->act_log, i)->lc_number;
 		if (enr == LC_FREE)
 			continue;
-		add += drbd_bm_ALe_set_all(mdev, enr);
+		tmp = drbd_bm_ALe_set_all(mdev, enr);
+		dynamic_dev_dbg(DEV, "AL: set %d bits in extent %u\n", tmp, enr);
+		add += tmp;
 	}
 
 	lc_unlock(mdev->act_log);
@@ -965,29 +969,30 @@
 	 * ok, (capacity & 7) != 0 sometimes, but who cares...
 	 * we count rs_{total,left} in bits, not sectors.
 	 */
-	spin_lock_irqsave(&mdev->al_lock, flags);
 	count = drbd_bm_clear_bits(mdev, sbnr, ebnr);
-	if (count) {
-		/* we need the lock for drbd_try_clear_on_disk_bm */
-		if (jiffies - mdev->rs_mark_time > HZ*10) {
-			/* should be rolling marks,
-			 * but we estimate only anyways. */
-			if (mdev->rs_mark_left != drbd_bm_total_weight(mdev) &&
+	if (count && get_ldev(mdev)) {
+		unsigned long now = jiffies;
+		unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark];
+		int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS;
+		if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) {
+			unsigned long tw = drbd_bm_total_weight(mdev);
+			if (mdev->rs_mark_left[mdev->rs_last_mark] != tw &&
 			    mdev->state.conn != C_PAUSED_SYNC_T &&
 			    mdev->state.conn != C_PAUSED_SYNC_S) {
-				mdev->rs_mark_time = jiffies;
-				mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+				mdev->rs_mark_time[next] = now;
+				mdev->rs_mark_left[next] = tw;
+				mdev->rs_last_mark = next;
 			}
 		}
-		if (get_ldev(mdev)) {
-			drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
-			put_ldev(mdev);
-		}
+		spin_lock_irqsave(&mdev->al_lock, flags);
+		drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE);
+		spin_unlock_irqrestore(&mdev->al_lock, flags);
+
 		/* just wake_up unconditional now, various lc_chaged(),
 		 * lc_put() in drbd_try_clear_on_disk_bm(). */
 		wake_up = 1;
+		put_ldev(mdev);
 	}
-	spin_unlock_irqrestore(&mdev->al_lock, flags);
 	if (wake_up)
 		wake_up(&mdev->al_wait);
 }
@@ -1118,7 +1123,7 @@
  * @mdev:	DRBD device.
  * @sector:	The sector number.
  *
- * This functions sleeps on al_wait. Returns 1 on success, 0 if interrupted.
+ * This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted.
  */
 int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector)
 {
@@ -1129,10 +1134,10 @@
 	sig = wait_event_interruptible(mdev->al_wait,
 			(bm_ext = _bme_get(mdev, enr)));
 	if (sig)
-		return 0;
+		return -EINTR;
 
 	if (test_bit(BME_LOCKED, &bm_ext->flags))
-		return 1;
+		return 0;
 
 	for (i = 0; i < AL_EXT_PER_BM_SECT; i++) {
 		sig = wait_event_interruptible(mdev->al_wait,
@@ -1145,13 +1150,11 @@
 				wake_up(&mdev->al_wait);
 			}
 			spin_unlock_irq(&mdev->al_lock);
-			return 0;
+			return -EINTR;
 		}
 	}
-
 	set_bit(BME_LOCKED, &bm_ext->flags);
-
-	return 1;
+	return 0;
 }
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_bitmap.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_bitmap.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_bitmap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_bitmap.c	2011-01-04 19:50:19.000000000 -0500
@@ -569,7 +569,7 @@
  *
  * maybe bm_set should be atomic_t ?
  */
-static unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
+unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev)
 {
 	struct drbd_bitmap *b = mdev->bitmap;
 	unsigned long s;
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_int.h linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_int.h
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_int.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_int.h	2011-01-04 19:50:19.000000000 -0500
@@ -114,11 +114,11 @@
 #define D_ASSERT(exp)	if (!(exp)) \
 	 dev_err(DEV, "ASSERT( " #exp " ) in %s:%d\n", __FILE__, __LINE__)
 
-#define ERR_IF(exp) if (({				\
-	int _b = (exp) != 0;				\
-	if (_b) dev_err(DEV, "%s: (%s) in %s:%d\n",	\
-		__func__, #exp, __FILE__, __LINE__);	\
-	 _b;						\
+#define ERR_IF(exp) if (({						\
+	int _b = (exp) != 0;						\
+	if (_b) dev_err(DEV, "ASSERT FAILED: %s: (%s) in %s:%d\n",	\
+			__func__, #exp, __FILE__, __LINE__);		\
+	_b;								\
 	}))
 
 /* Defines to control fault insertion */
@@ -337,13 +337,25 @@
  * NOTE that the payload starts at a long aligned offset,
  * regardless of 32 or 64 bit arch!
  */
-struct p_header {
+struct p_header80 {
 	u32	  magic;
 	u16	  command;
 	u16	  length;	/* bytes of data after this header */
 	u8	  payload[0];
 } __packed;
-/* 8 bytes. packet FIXED for the next century! */
+
+/* Header for big packets, Used for data packets exceeding 64kB */
+struct p_header95 {
+	u16	  magic;	/* use DRBD_MAGIC_BIG here */
+	u16	  command;
+	u32	  length;	/* Use only 24 bits of that. Ignore the highest 8 bit. */
+	u8	  payload[0];
+} __packed;
+
+union p_header {
+	struct p_header80 h80;
+	struct p_header95 h95;
+};
 
 /*
  * short commands, packets without payload, plain p_header:
@@ -362,12 +374,16 @@
  */
 
 /* these defines must not be changed without changing the protocol version */
-#define DP_HARDBARRIER	      1
-#define DP_RW_SYNC	      2
+#define DP_HARDBARRIER	      1 /* depricated */
+#define DP_RW_SYNC	      2 /* equals REQ_SYNC    */
 #define DP_MAY_SET_IN_SYNC    4
+#define DP_UNPLUG             8 /* equals REQ_UNPLUG  */
+#define DP_FUA               16 /* equals REQ_FUA     */
+#define DP_FLUSH             32 /* equals REQ_FLUSH   */
+#define DP_DISCARD           64 /* equals REQ_DISCARD */
 
 struct p_data {
-	struct p_header head;
+	union p_header head;
 	u64	    sector;    /* 64 bits sector number */
 	u64	    block_id;  /* to identify the request in protocol B&C */
 	u32	    seq_num;
@@ -383,7 +399,7 @@
  *   P_DATA_REQUEST, P_RS_DATA_REQUEST
  */
 struct p_block_ack {
-	struct p_header head;
+	struct p_header80 head;
 	u64	    sector;
 	u64	    block_id;
 	u32	    blksize;
@@ -392,7 +408,7 @@
 
 
 struct p_block_req {
-	struct p_header head;
+	struct p_header80 head;
 	u64 sector;
 	u64 block_id;
 	u32 blksize;
@@ -409,7 +425,7 @@
  */
 
 struct p_handshake {
-	struct p_header head;	/* 8 bytes */
+	struct p_header80 head;	/* 8 bytes */
 	u32 protocol_min;
 	u32 feature_flags;
 	u32 protocol_max;
@@ -424,19 +440,19 @@
 /* 80 bytes, FIXED for the next century */
 
 struct p_barrier {
-	struct p_header head;
+	struct p_header80 head;
 	u32 barrier;	/* barrier number _handle_ only */
 	u32 pad;	/* to multiple of 8 Byte */
 } __packed;
 
 struct p_barrier_ack {
-	struct p_header head;
+	struct p_header80 head;
 	u32 barrier;
 	u32 set_size;
 } __packed;
 
 struct p_rs_param {
-	struct p_header head;
+	struct p_header80 head;
 	u32 rate;
 
 	      /* Since protocol version 88 and higher. */
@@ -444,20 +460,31 @@
 } __packed;
 
 struct p_rs_param_89 {
-	struct p_header head;
+	struct p_header80 head;
 	u32 rate;
         /* protocol version 89: */
 	char verify_alg[SHARED_SECRET_MAX];
 	char csums_alg[SHARED_SECRET_MAX];
 } __packed;
 
+struct p_rs_param_95 {
+	struct p_header80 head;
+	u32 rate;
+	char verify_alg[SHARED_SECRET_MAX];
+	char csums_alg[SHARED_SECRET_MAX];
+	u32 c_plan_ahead;
+	u32 c_delay_target;
+	u32 c_fill_target;
+	u32 c_max_rate;
+} __packed;
+
 enum drbd_conn_flags {
 	CF_WANT_LOSE = 1,
 	CF_DRY_RUN = 2,
 };
 
 struct p_protocol {
-	struct p_header head;
+	struct p_header80 head;
 	u32 protocol;
 	u32 after_sb_0p;
 	u32 after_sb_1p;
@@ -471,17 +498,17 @@
 } __packed;
 
 struct p_uuids {
-	struct p_header head;
+	struct p_header80 head;
 	u64 uuid[UI_EXTENDED_SIZE];
 } __packed;
 
 struct p_rs_uuid {
-	struct p_header head;
+	struct p_header80 head;
 	u64	    uuid;
 } __packed;
 
 struct p_sizes {
-	struct p_header head;
+	struct p_header80 head;
 	u64	    d_size;  /* size of disk */
 	u64	    u_size;  /* user requested size */
 	u64	    c_size;  /* current exported size */
@@ -491,18 +518,18 @@
 } __packed;
 
 struct p_state {
-	struct p_header head;
+	struct p_header80 head;
 	u32	    state;
 } __packed;
 
 struct p_req_state {
-	struct p_header head;
+	struct p_header80 head;
 	u32	    mask;
 	u32	    val;
 } __packed;
 
 struct p_req_state_reply {
-	struct p_header head;
+	struct p_header80 head;
 	u32	    retcode;
 } __packed;
 
@@ -517,7 +544,7 @@
 } __packed;
 
 struct p_discard {
-	struct p_header head;
+	struct p_header80 head;
 	u64	    block_id;
 	u32	    seq_num;
 	u32	    pad;
@@ -533,7 +560,7 @@
 };
 
 struct p_compressed_bm {
-	struct p_header head;
+	struct p_header80 head;
 	/* (encoding & 0x0f): actual encoding, see enum drbd_bitmap_code
 	 * (encoding & 0x80): polarity (set/unset) of first runlength
 	 * ((encoding >> 4) & 0x07): pad_bits, number of trailing zero bits
@@ -544,10 +571,10 @@
 	u8 code[0];
 } __packed;
 
-struct p_delay_probe {
-	struct p_header head;
-	u32	seq_num; /* sequence number to match the two probe packets */
-	u32	offset;	 /* usecs the probe got sent after the reference time point */
+struct p_delay_probe93 {
+	struct p_header80 head;
+	u32     seq_num; /* sequence number to match the two probe packets */
+	u32     offset;  /* usecs the probe got sent after the reference time point */
 } __packed;
 
 /* DCBP: Drbd Compressed Bitmap Packet ... */
@@ -594,7 +621,7 @@
  * so we need to use the fixed size 4KiB page size
  * most architechtures have used for a long time.
  */
-#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header))
+#define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header80))
 #define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long))
 #define BM_PACKET_VLI_BYTES_MAX (4096 - sizeof(struct p_compressed_bm))
 #if (PAGE_SIZE < 4096)
@@ -603,13 +630,14 @@
 #endif
 
 union p_polymorph {
-        struct p_header          header;
+        union p_header           header;
         struct p_handshake       handshake;
         struct p_data            data;
         struct p_block_ack       block_ack;
         struct p_barrier         barrier;
         struct p_barrier_ack     barrier_ack;
         struct p_rs_param_89     rs_param_89;
+        struct p_rs_param_95     rs_param_95;
         struct p_protocol        protocol;
         struct p_sizes           sizes;
         struct p_uuids           uuids;
@@ -617,6 +645,8 @@
         struct p_req_state       req_state;
         struct p_req_state_reply req_state_reply;
         struct p_block_req       block_req;
+	struct p_delay_probe93   delay_probe93;
+	struct p_rs_uuid         rs_uuid;
 } __packed;
 
 /**********************************************************************/
@@ -697,7 +727,7 @@
 	struct list_head requests; /* requests before */
 	struct drbd_tl_epoch *next; /* pointer to the next barrier */
 	unsigned int br_number;  /* the barriers identifier. */
-	int n_req;	/* number of requests attached before this barrier */
+	int n_writes;	/* number of requests attached before this barrier */
 };
 
 struct drbd_request;
@@ -719,17 +749,12 @@
 
 /* drbd_epoch flag bits */
 enum {
-	DE_BARRIER_IN_NEXT_EPOCH_ISSUED,
-	DE_BARRIER_IN_NEXT_EPOCH_DONE,
-	DE_CONTAINS_A_BARRIER,
 	DE_HAVE_BARRIER_NUMBER,
-	DE_IS_FINISHING,
 };
 
 enum epoch_event {
 	EV_PUT,
 	EV_GOT_BARRIER_NR,
-	EV_BARRIER_DONE,
 	EV_BECAME_LAST,
 	EV_CLEANUP = 32, /* used as flag */
 };
@@ -747,7 +772,7 @@
 struct drbd_epoch_entry {
 	struct drbd_work w;
 	struct hlist_node colision;
-	struct drbd_epoch *epoch;
+	struct drbd_epoch *epoch; /* for writes */
 	struct drbd_conf *mdev;
 	struct page *pages;
 	atomic_t pending_bios;
@@ -755,7 +780,10 @@
 	/* see comments on ee flag bits below */
 	unsigned long flags;
 	sector_t sector;
-	u64 block_id;
+	union {
+		u64 block_id;
+		struct digest_info *digest;
+	};
 };
 
 /* ee flag bits.
@@ -768,11 +796,6 @@
 	__EE_CALL_AL_COMPLETE_IO,
 	__EE_MAY_SET_IN_SYNC,
 
-	/* This epoch entry closes an epoch using a barrier.
-	 * On sucessful completion, the epoch is released,
-	 * and the P_BARRIER_ACK send. */
-	__EE_IS_BARRIER,
-
 	/* In case a barrier failed,
 	 * we need to resubmit without the barrier flag. */
 	__EE_RESUBMITTED,
@@ -781,12 +804,15 @@
 	 * if any of those fail, we set this flag atomically
 	 * from the endio callback */
 	__EE_WAS_ERROR,
+
+	/* This ee has a pointer to a digest instead of a block id */
+	__EE_HAS_DIGEST,
 };
 #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO)
 #define EE_MAY_SET_IN_SYNC     (1<<__EE_MAY_SET_IN_SYNC)
-#define EE_IS_BARRIER          (1<<__EE_IS_BARRIER)
 #define	EE_RESUBMITTED         (1<<__EE_RESUBMITTED)
 #define EE_WAS_ERROR           (1<<__EE_WAS_ERROR)
+#define EE_HAS_DIGEST          (1<<__EE_HAS_DIGEST)
 
 /* global flag bits */
 enum {
@@ -794,7 +820,6 @@
 	SIGNAL_ASENDER,		/* whether asender wants to be interrupted */
 	SEND_PING,		/* whether asender should send a ping asap */
 
-	STOP_SYNC_TIMER,	/* tell timer to cancel itself */
 	UNPLUG_QUEUED,		/* only relevant with kernel 2.4 */
 	UNPLUG_REMOTE,		/* sending a "UnplugRemote" could help */
 	MD_DIRTY,		/* current uuids and flags not yet on disk */
@@ -807,15 +832,15 @@
 				 * Gets cleared when the state.conn
 				 * goes into C_CONNECTED state. */
 	WRITE_BM_AFTER_RESYNC,	/* A kmalloc() during resync failed */
-	NO_BARRIER_SUPP,	/* underlying block device doesn't implement barriers */
 	CONSIDER_RESYNC,
 
-	MD_NO_BARRIER,		/* meta data device does not support barriers,
-				   so don't even try */
+	MD_NO_FUA,		/* Users wants us to not use FUA/FLUSH on meta data dev */
 	SUSPEND_IO,		/* suspend application io */
 	BITMAP_IO,		/* suspend application io;
 				   once no more io in flight, start bitmap io */
 	BITMAP_IO_QUEUED,       /* Started bitmap IO */
+	GO_DISKLESS,		/* Disk is being detached, on io-error or admin request. */
+	WAS_IO_ERROR,		/* Local disk failed returned IO error */
 	RESYNC_AFTER_NEG,       /* Resync after online grow after the attach&negotiate finished. */
 	NET_CONGESTED,		/* The data socket is congested */
 
@@ -829,6 +854,8 @@
 				 * the peer, if it changed there as well. */
 	CONN_DRY_RUN,		/* Expect disconnect after resync handshake. */
 	GOT_PING_ACK,		/* set when we receive a ping_ack packet, misc wait gets woken */
+	NEW_CUR_UUID,		/* Create new current UUID when thawing IO */
+	AL_SUSPENDED,		/* Activity logging is currently suspended. */
 };
 
 struct drbd_bitmap; /* opaque for drbd_conf */
@@ -838,10 +865,6 @@
 
 /* THINK maybe we actually want to use the default "event/%s" worker threads
  * or similar in linux 2.6, which uses per cpu data and threads.
- *
- * To be general, this might need a spin_lock member.
- * For now, please use the mdev->req_lock to protect list_head,
- * see drbd_queue_work below.
  */
 struct drbd_work_queue {
 	struct list_head q;
@@ -912,7 +935,12 @@
 	WO_none,
 	WO_drain_io,
 	WO_bdev_flush,
-	WO_bio_barrier
+};
+
+struct fifo_buffer {
+	int *values;
+	unsigned int head_index;
+	unsigned int size;
 };
 
 struct drbd_conf {
@@ -936,9 +964,16 @@
 	unsigned int ko_count;
 	struct drbd_work  resync_work,
 			  unplug_work,
+			  go_diskless,
 			  md_sync_work;
 	struct timer_list resync_timer;
 	struct timer_list md_sync_timer;
+#ifdef DRBD_DEBUG_MD_SYNC
+	struct {
+		unsigned int line;
+		const char* func;
+	} last_md_mark_dirty;
+#endif
 
 	/* Used after attach while negotiating new disk state. */
 	union drbd_state new_state_tmp;
@@ -946,6 +981,7 @@
 	union drbd_state state;
 	wait_queue_head_t misc_wait;
 	wait_queue_head_t state_wait;  /* upon each state change. */
+	wait_queue_head_t net_cnt_wait;
 	unsigned int send_cnt;
 	unsigned int recv_cnt;
 	unsigned int read_cnt;
@@ -974,12 +1010,16 @@
 	unsigned long rs_start;
 	/* cumulated time in PausedSyncX state [unit jiffies] */
 	unsigned long rs_paused;
+	/* skipped because csum was equal [unit BM_BLOCK_SIZE] */
+	unsigned long rs_same_csum;
+#define DRBD_SYNC_MARKS 8
+#define DRBD_SYNC_MARK_STEP (3*HZ)
 	/* block not up-to-date at mark [unit BM_BLOCK_SIZE] */
-	unsigned long rs_mark_left;
+	unsigned long rs_mark_left[DRBD_SYNC_MARKS];
 	/* marks's time [unit jiffies] */
-	unsigned long rs_mark_time;
-	/* skipped because csum was equeal [unit BM_BLOCK_SIZE] */
-	unsigned long rs_same_csum;
+	unsigned long rs_mark_time[DRBD_SYNC_MARKS];
+	/* current index into rs_mark_{left,time} */
+	int rs_last_mark;
 
 	/* where does the admin want us to start? (sector) */
 	sector_t ov_start_sector;
@@ -1012,10 +1052,10 @@
 	spinlock_t epoch_lock;
 	unsigned int epochs;
 	enum write_ordering_e write_ordering;
-	struct list_head active_ee; /* IO in progress */
-	struct list_head sync_ee;   /* IO in progress */
+	struct list_head active_ee; /* IO in progress (P_DATA gets written to disk) */
+	struct list_head sync_ee;   /* IO in progress (P_RS_DATA_REPLY gets written to disk) */
 	struct list_head done_ee;   /* send ack */
-	struct list_head read_ee;   /* IO in progress */
+	struct list_head read_ee;   /* IO in progress (any read) */
 	struct list_head net_ee;    /* zero-copy network send in progress */
 	struct hlist_head *ee_hash; /* is proteced by req_lock! */
 	unsigned int ee_hash_s;
@@ -1026,7 +1066,8 @@
 	int next_barrier_nr;
 	struct hlist_head *app_reads_hash; /* is proteced by req_lock */
 	struct list_head resync_reads;
-	atomic_t pp_in_use;
+	atomic_t pp_in_use;		/* allocated from page pool */
+	atomic_t pp_in_use_by_net;	/* sendpage()d, still referenced by tcp */
 	wait_queue_head_t ee_wait;
 	struct page *md_io_page;	/* one page buffer for md_io */
 	struct page *md_io_tmpp;	/* for logical_block_size != 512 */
@@ -1054,6 +1095,15 @@
 	u64 ed_uuid; /* UUID of the exposed data */
 	struct mutex state_mutex;
 	char congestion_reason;  /* Why we where congested... */
+	atomic_t rs_sect_in; /* for incoming resync data rate, SyncTarget */
+	atomic_t rs_sect_ev; /* for submitted resync data rate, both */
+	int rs_last_sect_ev; /* counter to compare with */
+	int rs_last_events;  /* counter of read or write "events" (unit sectors)
+			      * on the lower level device when we last looked. */
+	int c_sync_rate; /* current resync rate after syncer throttle magic */
+	struct fifo_buffer rs_plan_s; /* correction values of resync planer */
+	int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
+	int rs_planed;    /* resync sectors already planed */
 };
 
 static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1138,6 +1188,8 @@
 extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
 		       unsigned int set_size);
 extern void tl_clear(struct drbd_conf *mdev);
+enum drbd_req_event;
+extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
 extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *);
 extern void drbd_free_sock(struct drbd_conf *mdev);
 extern int drbd_send(struct drbd_conf *mdev, struct socket *sock,
@@ -1150,12 +1202,12 @@
 extern int _drbd_send_state(struct drbd_conf *mdev);
 extern int drbd_send_state(struct drbd_conf *mdev);
 extern int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
-			enum drbd_packets cmd, struct p_header *h,
+			enum drbd_packets cmd, struct p_header80 *h,
 			size_t size, unsigned msg_flags);
 #define USE_DATA_SOCKET 1
 #define USE_META_SOCKET 0
 extern int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
-			enum drbd_packets cmd, struct p_header *h,
+			enum drbd_packets cmd, struct p_header80 *h,
 			size_t size);
 extern int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd,
 			char *data, size_t size);
@@ -1167,7 +1219,7 @@
 extern int drbd_send_ack_rp(struct drbd_conf *mdev, enum drbd_packets cmd,
 			struct p_block_req *rp);
 extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
-			struct p_data *dp);
+			struct p_data *dp, int data_size);
 extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd,
 			    sector_t sector, int blksize, u64 block_id);
 extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
@@ -1201,7 +1253,13 @@
 extern void drbd_md_set_flag(struct drbd_conf *mdev, int flags) __must_hold(local);
 extern void drbd_md_clear_flag(struct drbd_conf *mdev, int flags)__must_hold(local);
 extern int drbd_md_test_flag(struct drbd_backing_dev *, int);
+#ifndef DRBD_DEBUG_MD_SYNC
 extern void drbd_md_mark_dirty(struct drbd_conf *mdev);
+#else
+#define drbd_md_mark_dirty(m)	drbd_md_mark_dirty_(m, __LINE__ , __func__ )
+extern void drbd_md_mark_dirty_(struct drbd_conf *mdev,
+		unsigned int line, const char *func);
+#endif
 extern void drbd_queue_bitmap_io(struct drbd_conf *mdev,
 				 int (*io_fn)(struct drbd_conf *),
 				 void (*done)(struct drbd_conf *, int),
@@ -1209,6 +1267,8 @@
 extern int drbd_bmio_set_n_write(struct drbd_conf *mdev);
 extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
 extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why);
+extern void drbd_go_diskless(struct drbd_conf *mdev);
+extern void drbd_ldev_destroy(struct drbd_conf *mdev);
 
 
 /* Meta data layout
@@ -1264,6 +1324,8 @@
  * Bit 1 ==> local node thinks this block needs to be synced.
  */
 
+#define SLEEP_TIME (HZ/10)
+
 #define BM_BLOCK_SHIFT  12			 /* 4k per bit */
 #define BM_BLOCK_SIZE	 (1<<BM_BLOCK_SHIFT)
 /* (9+3) : 512 bytes @ 8 bits; representing 16M storage
@@ -1335,11 +1397,13 @@
 #endif
 
 /* Sector shift value for the "hash" functions of tl_hash and ee_hash tables.
- * With a value of 6 all IO in one 32K block make it to the same slot of the
+ * With a value of 8 all IO in one 128K block make it to the same slot of the
  * hash table. */
-#define HT_SHIFT 6
+#define HT_SHIFT 8
 #define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT))
 
+#define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */
+
 /* Number of elements in the app_reads_hash */
 #define APP_R_HSIZE 15
 
@@ -1369,6 +1433,7 @@
 /* bm_find_next variants for use while you hold drbd_bm_lock() */
 extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo);
 extern unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo);
+extern unsigned long _drbd_bm_total_weight(struct drbd_conf *mdev);
 extern unsigned long drbd_bm_total_weight(struct drbd_conf *mdev);
 extern int drbd_bm_rs_done(struct drbd_conf *mdev);
 /* for receive_bitmap */
@@ -1421,7 +1486,8 @@
 extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
 extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role,
 		int force);
-enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev);
+extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev);
+extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev);
 extern int drbd_khelper(struct drbd_conf *mdev, char *cmd);
 
 /* drbd_worker.c */
@@ -1467,10 +1533,12 @@
 extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int);
 extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int);
 extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int);
+extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int);
 
 extern void resync_timer_fn(unsigned long data);
 
 /* drbd_receiver.c */
+extern int drbd_rs_should_slow_down(struct drbd_conf *mdev);
 extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e,
 		const unsigned rw, const int fault_type);
 extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list);
@@ -1479,7 +1547,10 @@
 					    sector_t sector,
 					    unsigned int data_size,
 					    gfp_t gfp_mask) __must_hold(local);
-extern void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e);
+extern void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e,
+		int is_net);
+#define drbd_free_ee(m,e)	drbd_free_some_ee(m, e, 0)
+#define drbd_free_net_ee(m,e)	drbd_free_some_ee(m, e, 1)
 extern void drbd_wait_ee_list_empty(struct drbd_conf *mdev,
 		struct list_head *head);
 extern void _drbd_wait_ee_list_empty(struct drbd_conf *mdev,
@@ -1487,6 +1558,7 @@
 extern void drbd_set_recv_tcq(struct drbd_conf *mdev, int tcq_enabled);
 extern void _drbd_clear_done_ee(struct drbd_conf *mdev, struct list_head *to_be_freed);
 extern void drbd_flush_workqueue(struct drbd_conf *mdev);
+extern void drbd_free_tl_hash(struct drbd_conf *mdev);
 
 /* yes, there is kernel_setsockopt, but only since 2.6.18. we don't need to
  * mess with get_fs/set_fs, we know we are KERNEL_DS always. */
@@ -1600,6 +1672,8 @@
 #define susp_MASK 1
 #define user_isp_MASK 1
 #define aftr_isp_MASK 1
+#define susp_nod_MASK 1
+#define susp_fen_MASK 1
 
 #define NS(T, S) \
 	({ union drbd_state mask; mask.i = 0; mask.T = T##_MASK; mask; }), \
@@ -1712,17 +1786,17 @@
 	case EP_PASS_ON:
 		if (!forcedetach) {
 			if (__ratelimit(&drbd_ratelimit_state))
-				dev_err(DEV, "Local IO failed in %s."
-					     "Passing error on...\n", where);
+				dev_err(DEV, "Local IO failed in %s.\n", where);
 			break;
 		}
 		/* NOTE fall through to detach case if forcedetach set */
 	case EP_DETACH:
 	case EP_CALL_HELPER:
+		set_bit(WAS_IO_ERROR, &mdev->flags);
 		if (mdev->state.disk > D_FAILED) {
 			_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
-			dev_err(DEV, "Local IO failed in %s."
-				     "Detaching...\n", where);
+			dev_err(DEV,
+				"Local IO failed in %s. Detaching...\n", where);
 		}
 		break;
 	}
@@ -1788,7 +1862,7 @@
 static inline sector_t drbd_get_capacity(struct block_device *bdev)
 {
 	/* return bdev ? get_capacity(bdev->bd_disk) : 0; */
-	return bdev ? bdev->bd_inode->i_size >> 9 : 0;
+	return bdev ? i_size_read(bdev->bd_inode) >> 9 : 0;
 }
 
 /**
@@ -1856,13 +1930,6 @@
 }
 
 static inline void
-_drbd_queue_work(struct drbd_work_queue *q, struct drbd_work *w)
-{
-	list_add_tail(&w->list, &q->q);
-	up(&q->s);
-}
-
-static inline void
 drbd_queue_work_front(struct drbd_work_queue *q, struct drbd_work *w)
 {
 	unsigned long flags;
@@ -1899,19 +1966,19 @@
 static inline int drbd_send_short_cmd(struct drbd_conf *mdev,
 	enum drbd_packets cmd)
 {
-	struct p_header h;
+	struct p_header80 h;
 	return drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd, &h, sizeof(h));
 }
 
 static inline int drbd_send_ping(struct drbd_conf *mdev)
 {
-	struct p_header h;
+	struct p_header80 h;
 	return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING, &h, sizeof(h));
 }
 
 static inline int drbd_send_ping_ack(struct drbd_conf *mdev)
 {
-	struct p_header h;
+	struct p_header80 h;
 	return drbd_send_cmd(mdev, USE_META_SOCKET, P_PING_ACK, &h, sizeof(h));
 }
 
@@ -2013,7 +2080,7 @@
 static inline void put_net_conf(struct drbd_conf *mdev)
 {
 	if (atomic_dec_and_test(&mdev->net_cnt))
-		wake_up(&mdev->misc_wait);
+		wake_up(&mdev->net_cnt_wait);
 }
 
 /**
@@ -2044,10 +2111,18 @@
 
 static inline void put_ldev(struct drbd_conf *mdev)
 {
+	int i = atomic_dec_return(&mdev->local_cnt);
 	__release(local);
-	if (atomic_dec_and_test(&mdev->local_cnt))
+	D_ASSERT(i >= 0);
+	if (i == 0) {
+		if (mdev->state.disk == D_DISKLESS)
+			/* even internal references gone, safe to destroy */
+			drbd_ldev_destroy(mdev);
+		if (mdev->state.disk == D_FAILED)
+			/* all application IO references gone. */
+			drbd_go_diskless(mdev);
 		wake_up(&mdev->misc_wait);
-	D_ASSERT(atomic_read(&mdev->local_cnt) >= 0);
+	}
 }
 
 #ifndef __CHECKER__
@@ -2055,6 +2130,10 @@
 {
 	int io_allowed;
 
+	/* never get a reference while D_DISKLESS */
+	if (mdev->state.disk == D_DISKLESS)
+		return 0;
+
 	atomic_inc(&mdev->local_cnt);
 	io_allowed = (mdev->state.disk >= mins);
 	if (!io_allowed)
@@ -2179,11 +2258,16 @@
 	return 1;
 }
 
+static inline int is_susp(union drbd_state s)
+{
+	return s.susp || s.susp_nod || s.susp_fen;
+}
+
 static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
 {
 	int mxb = drbd_get_max_buffers(mdev);
 
-	if (mdev->state.susp)
+	if (is_susp(mdev->state))
 		return 0;
 	if (test_bit(SUSPEND_IO, &mdev->flags))
 		return 0;
@@ -2318,13 +2402,12 @@
 {
 	int r;
 
-	if (test_bit(MD_NO_BARRIER, &mdev->flags))
+	if (test_bit(MD_NO_FUA, &mdev->flags))
 		return;
 
-	r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL,
-			BLKDEV_IFL_WAIT);
+	r = blkdev_issue_flush(mdev->ldev->md_bdev, GFP_KERNEL, NULL);
 	if (r) {
-		set_bit(MD_NO_BARRIER, &mdev->flags);
+		set_bit(MD_NO_FUA, &mdev->flags);
 		dev_err(DEV, "meta data flush failed with status %d, disabling md-flushes\n", r);
 	}
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_main.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_main.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_main.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_main.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 #include <asm/types.h>
 #include <net/sock.h>
 #include <linux/ctype.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
@@ -64,6 +64,7 @@
 	struct completion *done;
 };
 
+static DEFINE_MUTEX(drbd_main_mutex);
 int drbdd_init(struct drbd_thread *);
 int drbd_worker(struct drbd_thread *);
 int drbd_asender(struct drbd_thread *);
@@ -77,6 +78,7 @@
 static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused);
 static void md_sync_timer_fn(unsigned long data);
 static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused);
+static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused);
 
 MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
 	      "Lars Ellenberg <lars@linbit.com>");
@@ -199,7 +201,7 @@
 	INIT_LIST_HEAD(&b->w.list);
 	b->next = NULL;
 	b->br_number = 4711;
-	b->n_req = 0;
+	b->n_writes = 0;
 	b->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
 
 	mdev->oldest_tle = b;
@@ -240,7 +242,7 @@
 	INIT_LIST_HEAD(&new->w.list);
 	new->w.cb = NULL; /* if this is != NULL, we need to dec_ap_pending in tl_clear */
 	new->next = NULL;
-	new->n_req = 0;
+	new->n_writes = 0;
 
 	newest_before = mdev->newest_tle;
 	/* never send a barrier number == 0, because that is special-cased
@@ -284,9 +286,9 @@
 			barrier_nr, b->br_number);
 		goto bail;
 	}
-	if (b->n_req != set_size) {
-		dev_err(DEV, "BAD! BarrierAck #%u received with n_req=%u, expected n_req=%u!\n",
-			barrier_nr, set_size, b->n_req);
+	if (b->n_writes != set_size) {
+		dev_err(DEV, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n",
+			barrier_nr, set_size, b->n_writes);
 		goto bail;
 	}
 
@@ -333,59 +335,99 @@
 	drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
 }
 
-
 /**
- * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
+ * _tl_restart() - Walks the transfer log, and applies an action to all requests
  * @mdev:	DRBD device.
+ * @what:       The action/event to perform with all request objects
  *
- * This is called after the connection to the peer was lost. The storage covered
- * by the requests on the transfer gets marked as our of sync. Called from the
- * receiver thread and the worker thread.
+ * @what might be one of connection_lost_while_pending, resend, fail_frozen_disk_io,
+ * restart_frozen_disk_io.
  */
-void tl_clear(struct drbd_conf *mdev)
+static void _tl_restart(struct drbd_conf *mdev, enum drbd_req_event what)
 {
-	struct drbd_tl_epoch *b, *tmp;
-	struct list_head *le, *tle;
-	struct drbd_request *r;
-	int new_initial_bnr = net_random();
-
-	spin_lock_irq(&mdev->req_lock);
+	struct drbd_tl_epoch *b, *tmp, **pn;
+	struct list_head *le, *tle, carry_reads;
+	struct drbd_request *req;
+	int rv, n_writes, n_reads;
 
 	b = mdev->oldest_tle;
+	pn = &mdev->oldest_tle;
 	while (b) {
+		n_writes = 0;
+		n_reads = 0;
+		INIT_LIST_HEAD(&carry_reads);
 		list_for_each_safe(le, tle, &b->requests) {
-			r = list_entry(le, struct drbd_request, tl_requests);
-			/* It would be nice to complete outside of spinlock.
-			 * But this is easier for now. */
-			_req_mod(r, connection_lost_while_pending);
+			req = list_entry(le, struct drbd_request, tl_requests);
+			rv = _req_mod(req, what);
+
+			n_writes += (rv & MR_WRITE) >> MR_WRITE_SHIFT;
+			n_reads  += (rv & MR_READ) >> MR_READ_SHIFT;
 		}
 		tmp = b->next;
 
-		/* there could still be requests on that ring list,
-		 * in case local io is still pending */
-		list_del(&b->requests);
+		if (n_writes) {
+			if (what == resend) {
+				b->n_writes = n_writes;
+				if (b->w.cb == NULL) {
+					b->w.cb = w_send_barrier;
+					inc_ap_pending(mdev);
+					set_bit(CREATE_BARRIER, &mdev->flags);
+				}
 
-		/* dec_ap_pending corresponding to queue_barrier.
-		 * the newest barrier may not have been queued yet,
-		 * in which case w.cb is still NULL. */
-		if (b->w.cb != NULL)
-			dec_ap_pending(mdev);
+				drbd_queue_work(&mdev->data.work, &b->w);
+			}
+			pn = &b->next;
+		} else {
+			if (n_reads)
+				list_add(&carry_reads, &b->requests);
+			/* there could still be requests on that ring list,
+			 * in case local io is still pending */
+			list_del(&b->requests);
 
-		if (b == mdev->newest_tle) {
-			/* recycle, but reinit! */
-			D_ASSERT(tmp == NULL);
-			INIT_LIST_HEAD(&b->requests);
-			INIT_LIST_HEAD(&b->w.list);
-			b->w.cb = NULL;
-			b->br_number = new_initial_bnr;
-			b->n_req = 0;
+			/* dec_ap_pending corresponding to queue_barrier.
+			 * the newest barrier may not have been queued yet,
+			 * in which case w.cb is still NULL. */
+			if (b->w.cb != NULL)
+				dec_ap_pending(mdev);
 
-			mdev->oldest_tle = b;
-			break;
+			if (b == mdev->newest_tle) {
+				/* recycle, but reinit! */
+				D_ASSERT(tmp == NULL);
+				INIT_LIST_HEAD(&b->requests);
+				list_splice(&carry_reads, &b->requests);
+				INIT_LIST_HEAD(&b->w.list);
+				b->w.cb = NULL;
+				b->br_number = net_random();
+				b->n_writes = 0;
+
+				*pn = b;
+				break;
+			}
+			*pn = tmp;
+			kfree(b);
 		}
-		kfree(b);
 		b = tmp;
+		list_splice(&carry_reads, &b->requests);
 	}
+}
+
+
+/**
+ * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL
+ * @mdev:	DRBD device.
+ *
+ * This is called after the connection to the peer was lost. The storage covered
+ * by the requests on the transfer gets marked as our of sync. Called from the
+ * receiver thread and the worker thread.
+ */
+void tl_clear(struct drbd_conf *mdev)
+{
+	struct list_head *le, *tle;
+	struct drbd_request *r;
+
+	spin_lock_irq(&mdev->req_lock);
+
+	_tl_restart(mdev, connection_lost_while_pending);
 
 	/* we expect this list to be empty. */
 	D_ASSERT(list_empty(&mdev->out_of_sequence_requests));
@@ -401,6 +443,15 @@
 	/* ensure bit indicating barrier is required is clear */
 	clear_bit(CREATE_BARRIER, &mdev->flags);
 
+	memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
+
+	spin_unlock_irq(&mdev->req_lock);
+}
+
+void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what)
+{
+	spin_lock_irq(&mdev->req_lock);
+	_tl_restart(mdev, what);
 	spin_unlock_irq(&mdev->req_lock);
 }
 
@@ -455,7 +506,7 @@
 static int is_valid_state_transition(struct drbd_conf *,
 				     union drbd_state, union drbd_state);
 static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
-				       union drbd_state ns, int *warn_sync_abort);
+				       union drbd_state ns, const char **warn_sync_abort);
 int drbd_send_state_req(struct drbd_conf *,
 			union drbd_state, union drbd_state);
 
@@ -605,7 +656,7 @@
 	    drbd_role_str(ns.peer),
 	    drbd_disk_str(ns.disk),
 	    drbd_disk_str(ns.pdsk),
-	    ns.susp ? 's' : 'r',
+	    is_susp(ns) ? 's' : 'r',
 	    ns.aftr_isp ? 'a' : '-',
 	    ns.peer_isp ? 'p' : '-',
 	    ns.user_isp ? 'u' : '-'
@@ -763,7 +814,7 @@
  * to D_UNKNOWN. This rule and many more along those lines are in this function.
  */
 static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os,
-				       union drbd_state ns, int *warn_sync_abort)
+				       union drbd_state ns, const char **warn_sync_abort)
 {
 	enum drbd_fencing_p fp;
 
@@ -778,11 +829,21 @@
 	    os.conn <= C_DISCONNECTING)
 		ns.conn = os.conn;
 
-	/* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow */
+	/* After a network error (+C_TEAR_DOWN) only C_UNCONNECTED or C_DISCONNECTING can follow.
+	 * If you try to go into some Sync* state, that shall fail (elsewhere). */
 	if (os.conn >= C_TIMEOUT && os.conn <= C_TEAR_DOWN &&
-	    ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING)
+	    ns.conn != C_UNCONNECTED && ns.conn != C_DISCONNECTING && ns.conn <= C_TEAR_DOWN)
 		ns.conn = os.conn;
 
+	/* we cannot fail (again) if we already detached */
+	if (ns.disk == D_FAILED && os.disk == D_DISKLESS)
+		ns.disk = D_DISKLESS;
+
+	/* if we are only D_ATTACHING yet,
+	 * we can (and should) go directly to D_DISKLESS. */
+	if (ns.disk == D_FAILED && os.disk == D_ATTACHING)
+		ns.disk = D_DISKLESS;
+
 	/* After C_DISCONNECTING only C_STANDALONE may follow */
 	if (os.conn == C_DISCONNECTING && ns.conn != C_STANDALONE)
 		ns.conn = os.conn;
@@ -798,14 +859,13 @@
 	if (ns.conn == C_STANDALONE && ns.disk == D_DISKLESS && ns.role == R_SECONDARY)
 		ns.aftr_isp = 0;
 
-	if (ns.conn <= C_DISCONNECTING && ns.disk == D_DISKLESS)
-		ns.pdsk = D_UNKNOWN;
-
 	/* Abort resync if a disk fails/detaches */
 	if (os.conn > C_CONNECTED && ns.conn > C_CONNECTED &&
 	    (ns.disk <= D_FAILED || ns.pdsk <= D_FAILED)) {
 		if (warn_sync_abort)
-			*warn_sync_abort = 1;
+			*warn_sync_abort =
+				os.conn == C_VERIFY_S || os.conn == C_VERIFY_T ?
+				"Online-verify" : "Resync";
 		ns.conn = C_CONNECTED;
 	}
 
@@ -876,7 +936,12 @@
 	if (fp == FP_STONITH &&
 	    (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) &&
 	    !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED))
-		ns.susp = 1;
+		ns.susp_fen = 1; /* Suspend IO while fence-peer handler runs (peer lost) */
+
+	if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO &&
+	    (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) &&
+	    !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE))
+		ns.susp_nod = 1; /* Suspend IO while no data available (no accessible data available) */
 
 	if (ns.aftr_isp || ns.peer_isp || ns.user_isp) {
 		if (ns.conn == C_SYNC_SOURCE)
@@ -912,6 +977,12 @@
 	}
 }
 
+static void drbd_resume_al(struct drbd_conf *mdev)
+{
+	if (test_and_clear_bit(AL_SUSPENDED, &mdev->flags))
+		dev_info(DEV, "Resumed AL updates\n");
+}
+
 /**
  * __drbd_set_state() - Set a new DRBD state
  * @mdev:	DRBD device.
@@ -927,7 +998,7 @@
 {
 	union drbd_state os;
 	int rv = SS_SUCCESS;
-	int warn_sync_abort = 0;
+	const char *warn_sync_abort = NULL;
 	struct after_state_chg_work *ascw;
 
 	os = mdev->state;
@@ -946,14 +1017,8 @@
 			/* If the old state was illegal as well, then let
 			   this happen...*/
 
-			if (is_valid_state(mdev, os) == rv) {
-				dev_err(DEV, "Considering state change from bad state. "
-				    "Error would be: '%s'\n",
-				    drbd_set_st_err_str(rv));
-				print_st(mdev, "old", os);
-				print_st(mdev, "new", ns);
+			if (is_valid_state(mdev, os) == rv)
 				rv = is_valid_state_transition(mdev, ns, os);
-			}
 		} else
 			rv = is_valid_state_transition(mdev, ns, os);
 	}
@@ -965,7 +1030,7 @@
 	}
 
 	if (warn_sync_abort)
-		dev_warn(DEV, "Resync aborted.\n");
+		dev_warn(DEV, "%s aborted.\n", warn_sync_abort);
 
 	{
 		char *pbp, pb[300];
@@ -976,7 +1041,10 @@
 		PSC(conn);
 		PSC(disk);
 		PSC(pdsk);
-		PSC(susp);
+		if (is_susp(ns) != is_susp(os))
+			pbp += sprintf(pbp, "susp( %s -> %s ) ",
+				       drbd_susp_str(is_susp(os)),
+				       drbd_susp_str(is_susp(ns)));
 		PSC(aftr_isp);
 		PSC(peer_isp);
 		PSC(user_isp);
@@ -997,16 +1065,18 @@
 	    !test_and_set_bit(CONFIG_PENDING, &mdev->flags))
 		set_bit(DEVICE_DYING, &mdev->flags);
 
-	mdev->state.i = ns.i;
+	/* if we are going -> D_FAILED or D_DISKLESS, grab one extra reference
+	 * on the ldev here, to be sure the transition -> D_DISKLESS resp.
+	 * drbd_ldev_destroy() won't happen before our corresponding
+	 * after_state_ch works run, where we put_ldev again. */
+	if ((os.disk != D_FAILED && ns.disk == D_FAILED) ||
+	    (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
+		atomic_inc(&mdev->local_cnt);
+
+	mdev->state = ns;
 	wake_up(&mdev->misc_wait);
 	wake_up(&mdev->state_wait);
 
-	/*   post-state-change actions   */
-	if (os.conn >= C_SYNC_SOURCE   && ns.conn <= C_CONNECTED) {
-		set_bit(STOP_SYNC_TIMER, &mdev->flags);
-		mod_timer(&mdev->resync_timer, jiffies);
-	}
-
 	/* aborted verify run. log the last position */
 	if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) &&
 	    ns.conn < C_CONNECTED) {
@@ -1019,41 +1089,42 @@
 	if ((os.conn == C_PAUSED_SYNC_T || os.conn == C_PAUSED_SYNC_S) &&
 	    (ns.conn == C_SYNC_TARGET  || ns.conn == C_SYNC_SOURCE)) {
 		dev_info(DEV, "Syncer continues.\n");
-		mdev->rs_paused += (long)jiffies-(long)mdev->rs_mark_time;
-		if (ns.conn == C_SYNC_TARGET) {
-			if (!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))
-				mod_timer(&mdev->resync_timer, jiffies);
-			/* This if (!test_bit) is only needed for the case
-			   that a device that has ceased to used its timer,
-			   i.e. it is already in drbd_resync_finished() gets
-			   paused and resumed. */
-		}
+		mdev->rs_paused += (long)jiffies
+				  -(long)mdev->rs_mark_time[mdev->rs_last_mark];
+		if (ns.conn == C_SYNC_TARGET)
+			mod_timer(&mdev->resync_timer, jiffies);
 	}
 
 	if ((os.conn == C_SYNC_TARGET  || os.conn == C_SYNC_SOURCE) &&
 	    (ns.conn == C_PAUSED_SYNC_T || ns.conn == C_PAUSED_SYNC_S)) {
 		dev_info(DEV, "Resync suspended\n");
-		mdev->rs_mark_time = jiffies;
-		if (ns.conn == C_PAUSED_SYNC_T)
-			set_bit(STOP_SYNC_TIMER, &mdev->flags);
+		mdev->rs_mark_time[mdev->rs_last_mark] = jiffies;
 	}
 
 	if (os.conn == C_CONNECTED &&
 	    (ns.conn == C_VERIFY_S || ns.conn == C_VERIFY_T)) {
+		unsigned long now = jiffies;
+		int i;
+
 		mdev->ov_position = 0;
-		mdev->rs_total =
-		mdev->rs_mark_left = drbd_bm_bits(mdev);
+		mdev->rs_total = drbd_bm_bits(mdev);
 		if (mdev->agreed_pro_version >= 90)
 			set_ov_position(mdev, ns.conn);
 		else
 			mdev->ov_start_sector = 0;
 		mdev->ov_left = mdev->rs_total
 			      - BM_SECT_TO_BIT(mdev->ov_position);
-		mdev->rs_start     =
-		mdev->rs_mark_time = jiffies;
+		mdev->rs_start = now;
+		mdev->rs_last_events = 0;
+		mdev->rs_last_sect_ev = 0;
 		mdev->ov_last_oos_size = 0;
 		mdev->ov_last_oos_start = 0;
 
+		for (i = 0; i < DRBD_SYNC_MARKS; i++) {
+			mdev->rs_mark_left[i] = mdev->rs_total;
+			mdev->rs_mark_time[i] = now;
+		}
+
 		if (ns.conn == C_VERIFY_S) {
 			dev_info(DEV, "Starting Online Verify from sector %llu\n",
 					(unsigned long long)mdev->ov_position);
@@ -1106,6 +1177,10 @@
 	    ns.conn <= C_TEAR_DOWN && ns.conn >= C_TIMEOUT)
 		drbd_thread_restart_nowait(&mdev->receiver);
 
+	/* Resume AL writing if we get a connection */
+	if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)
+		drbd_resume_al(mdev);
+
 	ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC);
 	if (ascw) {
 		ascw->os = os;
@@ -1164,6 +1239,8 @@
 			   union drbd_state ns, enum chg_state_flags flags)
 {
 	enum drbd_fencing_p fp;
+	enum drbd_req_event what = nothing;
+	union drbd_state nsm = (union drbd_state){ .i = -1 };
 
 	if (os.conn != C_CONNECTED && ns.conn == C_CONNECTED) {
 		clear_bit(CRASHED_PRIMARY, &mdev->flags);
@@ -1187,17 +1264,48 @@
 	/* Here we have the actions that are performed after a
 	   state change. This function might sleep */
 
-	if (fp == FP_STONITH && ns.susp) {
-		/* case1: The outdate peer handler is successful:
-		 * case2: The connection was established again: */
-		if ((os.pdsk > D_OUTDATED  && ns.pdsk <= D_OUTDATED) ||
-		    (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED)) {
+	nsm.i = -1;
+	if (ns.susp_nod) {
+		if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
+			if (ns.conn == C_CONNECTED)
+				what = resend, nsm.susp_nod = 0;
+			else /* ns.conn > C_CONNECTED */
+				dev_err(DEV, "Unexpected Resynd going on!\n");
+		}
+
+		if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING)
+			what = restart_frozen_disk_io, nsm.susp_nod = 0;
+
+	}
+
+	if (ns.susp_fen) {
+		/* case1: The outdate peer handler is successful: */
+		if (os.pdsk > D_OUTDATED  && ns.pdsk <= D_OUTDATED) {
 			tl_clear(mdev);
+			if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
+				drbd_uuid_new_current(mdev);
+				clear_bit(NEW_CUR_UUID, &mdev->flags);
+			}
 			spin_lock_irq(&mdev->req_lock);
-			_drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL);
+			_drbd_set_state(_NS(mdev, susp_fen, 0), CS_VERBOSE, NULL);
 			spin_unlock_irq(&mdev->req_lock);
 		}
+		/* case2: The connection was established again: */
+		if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) {
+			clear_bit(NEW_CUR_UUID, &mdev->flags);
+			what = resend;
+			nsm.susp_fen = 0;
+		}
 	}
+
+	if (what != nothing) {
+		spin_lock_irq(&mdev->req_lock);
+		_tl_restart(mdev, what);
+		nsm.i &= mdev->state.i;
+		_drbd_set_state(mdev, nsm, CS_VERBOSE, NULL);
+		spin_unlock_irq(&mdev->req_lock);
+	}
+
 	/* Do not change the order of the if above and the two below... */
 	if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) {      /* attach on the peer */
 		drbd_send_uuids(mdev);
@@ -1216,16 +1324,22 @@
 		if (get_ldev(mdev)) {
 			if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
 			    mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
-				drbd_uuid_new_current(mdev);
-				drbd_send_uuids(mdev);
+				if (is_susp(mdev->state)) {
+					set_bit(NEW_CUR_UUID, &mdev->flags);
+				} else {
+					drbd_uuid_new_current(mdev);
+					drbd_send_uuids(mdev);
+				}
 			}
 			put_ldev(mdev);
 		}
 	}
 
 	if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
-		if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0)
+		if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0) {
 			drbd_uuid_new_current(mdev);
+			drbd_send_uuids(mdev);
+		}
 
 		/* D_DISKLESS Peer becomes secondary */
 		if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
@@ -1267,52 +1381,64 @@
 	    os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT)
 		drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate");
 
-	if (os.disk > D_FAILED && ns.disk == D_FAILED) {
+	/* first half of local IO error, failure to attach,
+	 * or administrative detach */
+	if (os.disk != D_FAILED && ns.disk == D_FAILED) {
 		enum drbd_io_error_p eh;
+		int was_io_error;
+		/* corresponding get_ldev was in __drbd_set_state, to serialize
+		 * our cleanup here with the transition to D_DISKLESS,
+		 * so it is safe to dreference ldev here. */
+		eh = mdev->ldev->dc.on_io_error;
+		was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
 
-		eh = EP_PASS_ON;
-		if (get_ldev_if_state(mdev, D_FAILED)) {
-			eh = mdev->ldev->dc.on_io_error;
-			put_ldev(mdev);
-		}
+		/* current state still has to be D_FAILED,
+		 * there is only one way out: to D_DISKLESS,
+		 * and that may only happen after our put_ldev below. */
+		if (mdev->state.disk != D_FAILED)
+			dev_err(DEV,
+				"ASSERT FAILED: disk is %s during detach\n",
+				drbd_disk_str(mdev->state.disk));
+
+		if (drbd_send_state(mdev))
+			dev_warn(DEV, "Notified peer that I am detaching my disk\n");
+		else
+			dev_err(DEV, "Sending state for detaching disk failed\n");
 
 		drbd_rs_cancel_all(mdev);
-		/* since get_ldev() only works as long as disk>=D_INCONSISTENT,
-		   and it is D_DISKLESS here, local_cnt can only go down, it can
-		   not increase... It will reach zero */
-		wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
-		mdev->rs_total = 0;
-		mdev->rs_failed = 0;
-		atomic_set(&mdev->rs_pending_cnt, 0);
 
-		spin_lock_irq(&mdev->req_lock);
-		_drbd_set_state(_NS(mdev, disk, D_DISKLESS), CS_HARD, NULL);
-		spin_unlock_irq(&mdev->req_lock);
+		/* In case we want to get something to stable storage still,
+		 * this may be the last chance.
+		 * Following put_ldev may transition to D_DISKLESS. */
+		drbd_md_sync(mdev);
+		put_ldev(mdev);
 
-		if (eh == EP_CALL_HELPER)
+		if (was_io_error && eh == EP_CALL_HELPER)
 			drbd_khelper(mdev, "local-io-error");
 	}
 
-	if (os.disk > D_DISKLESS && ns.disk == D_DISKLESS) {
-
-		if (os.disk == D_FAILED) /* && ns.disk == D_DISKLESS*/ {
-			if (drbd_send_state(mdev))
-				dev_warn(DEV, "Notified peer that my disk is broken.\n");
-			else
-				dev_err(DEV, "Sending state in drbd_io_error() failed\n");
-		}
+        /* second half of local IO error, failure to attach,
+         * or administrative detach,
+         * after local_cnt references have reached zero again */
+        if (os.disk != D_DISKLESS && ns.disk == D_DISKLESS) {
+                /* We must still be diskless,
+                 * re-attach has to be serialized with this! */
+                if (mdev->state.disk != D_DISKLESS)
+                        dev_err(DEV,
+                                "ASSERT FAILED: disk is %s while going diskless\n",
+                                drbd_disk_str(mdev->state.disk));
 
-		wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
-		lc_destroy(mdev->resync);
-		mdev->resync = NULL;
-		lc_destroy(mdev->act_log);
-		mdev->act_log = NULL;
-		__no_warn(local,
-			drbd_free_bc(mdev->ldev);
-			mdev->ldev = NULL;);
+                mdev->rs_total = 0;
+                mdev->rs_failed = 0;
+                atomic_set(&mdev->rs_pending_cnt, 0);
 
-		if (mdev->md_io_tmpp)
-			__free_page(mdev->md_io_tmpp);
+		if (drbd_send_state(mdev))
+			dev_warn(DEV, "Notified peer that I'm now diskless.\n");
+		else
+			dev_err(DEV, "Sending state for being diskless failed\n");
+		/* corresponding get_ldev in __drbd_set_state
+		 * this may finaly trigger drbd_ldev_destroy. */
+		put_ldev(mdev);
 	}
 
 	/* Disks got bigger while they were detached */
@@ -1328,6 +1454,15 @@
 	    (os.user_isp && !ns.user_isp))
 		resume_next_sg(mdev);
 
+	/* sync target done with resync.  Explicitly notify peer, even though
+	 * it should (at least for non-empty resyncs) already know itself. */
+	if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED)
+		drbd_send_state(mdev);
+
+	/* free tl_hash if we Got thawed and are C_STANDALONE */
+	if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash)
+		drbd_free_tl_hash(mdev);
+
 	/* Upon network connection, we need to start the receiver */
 	if (os.conn == C_STANDALONE && ns.conn == C_UNCONNECTED)
 		drbd_thread_start(&mdev->receiver);
@@ -1554,7 +1689,7 @@
 
 /* the appropriate socket mutex must be held already */
 int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock,
-			  enum drbd_packets cmd, struct p_header *h,
+			  enum drbd_packets cmd, struct p_header80 *h,
 			  size_t size, unsigned msg_flags)
 {
 	int sent, ok;
@@ -1564,7 +1699,7 @@
 
 	h->magic   = BE_DRBD_MAGIC;
 	h->command = cpu_to_be16(cmd);
-	h->length  = cpu_to_be16(size-sizeof(struct p_header));
+	h->length  = cpu_to_be16(size-sizeof(struct p_header80));
 
 	sent = drbd_send(mdev, sock, h, size, msg_flags);
 
@@ -1579,7 +1714,7 @@
  * when we hold the appropriate socket mutex.
  */
 int drbd_send_cmd(struct drbd_conf *mdev, int use_data_socket,
-		  enum drbd_packets cmd, struct p_header *h, size_t size)
+		  enum drbd_packets cmd, struct p_header80 *h, size_t size)
 {
 	int ok = 0;
 	struct socket *sock;
@@ -1607,7 +1742,7 @@
 int drbd_send_cmd2(struct drbd_conf *mdev, enum drbd_packets cmd, char *data,
 		   size_t size)
 {
-	struct p_header h;
+	struct p_header80 h;
 	int ok;
 
 	h.magic   = BE_DRBD_MAGIC;
@@ -1629,7 +1764,7 @@
 
 int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc)
 {
-	struct p_rs_param_89 *p;
+	struct p_rs_param_95 *p;
 	struct socket *sock;
 	int size, rv;
 	const int apv = mdev->agreed_pro_version;
@@ -1637,7 +1772,8 @@
 	size = apv <= 87 ? sizeof(struct p_rs_param)
 		: apv == 88 ? sizeof(struct p_rs_param)
 			+ strlen(mdev->sync_conf.verify_alg) + 1
-		: /* 89 */    sizeof(struct p_rs_param_89);
+		: apv <= 94 ? sizeof(struct p_rs_param_89)
+		: /* apv >= 95 */ sizeof(struct p_rs_param_95);
 
 	/* used from admin command context and receiver/worker context.
 	 * to avoid kmalloc, grab the socket right here,
@@ -1648,12 +1784,16 @@
 	if (likely(sock != NULL)) {
 		enum drbd_packets cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM;
 
-		p = &mdev->data.sbuf.rs_param_89;
+		p = &mdev->data.sbuf.rs_param_95;
 
 		/* initialize verify_alg and csums_alg */
 		memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
 
 		p->rate = cpu_to_be32(sc->rate);
+		p->c_plan_ahead = cpu_to_be32(sc->c_plan_ahead);
+		p->c_delay_target = cpu_to_be32(sc->c_delay_target);
+		p->c_fill_target = cpu_to_be32(sc->c_fill_target);
+		p->c_max_rate = cpu_to_be32(sc->c_max_rate);
 
 		if (apv >= 88)
 			strcpy(p->verify_alg, mdev->sync_conf.verify_alg);
@@ -1709,7 +1849,7 @@
 		strcpy(p->integrity_alg, mdev->net_conf->integrity_alg);
 
 	rv = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_PROTOCOL,
-			   (struct p_header *)p, size);
+			   (struct p_header80 *)p, size);
 	kfree(p);
 	return rv;
 }
@@ -1735,7 +1875,7 @@
 	put_ldev(mdev);
 
 	return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_UUIDS,
-			     (struct p_header *)&p, sizeof(p));
+			     (struct p_header80 *)&p, sizeof(p));
 }
 
 int drbd_send_uuids(struct drbd_conf *mdev)
@@ -1756,7 +1896,7 @@
 	p.uuid = cpu_to_be64(val);
 
 	return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID,
-			     (struct p_header *)&p, sizeof(p));
+			     (struct p_header80 *)&p, sizeof(p));
 }
 
 int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags)
@@ -1786,7 +1926,7 @@
 	p.dds_flags = cpu_to_be16(flags);
 
 	ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SIZES,
-			   (struct p_header *)&p, sizeof(p));
+			   (struct p_header80 *)&p, sizeof(p));
 	return ok;
 }
 
@@ -1811,7 +1951,7 @@
 
 	if (likely(sock != NULL)) {
 		ok = _drbd_send_cmd(mdev, sock, P_STATE,
-				    (struct p_header *)&p, sizeof(p), 0);
+				    (struct p_header80 *)&p, sizeof(p), 0);
 	}
 
 	mutex_unlock(&mdev->data.mutex);
@@ -1829,7 +1969,7 @@
 	p.val     = cpu_to_be32(val.i);
 
 	return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_STATE_CHG_REQ,
-			     (struct p_header *)&p, sizeof(p));
+			     (struct p_header80 *)&p, sizeof(p));
 }
 
 int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode)
@@ -1839,7 +1979,7 @@
 	p.retcode    = cpu_to_be32(retcode);
 
 	return drbd_send_cmd(mdev, USE_META_SOCKET, P_STATE_CHG_REPLY,
-			     (struct p_header *)&p, sizeof(p));
+			     (struct p_header80 *)&p, sizeof(p));
 }
 
 int fill_bitmap_rle_bits(struct drbd_conf *mdev,
@@ -1938,7 +2078,7 @@
 
 enum { OK, FAILED, DONE }
 send_bitmap_rle_or_plain(struct drbd_conf *mdev,
-	struct p_header *h, struct bm_xfer_ctx *c)
+	struct p_header80 *h, struct bm_xfer_ctx *c)
 {
 	struct p_compressed_bm *p = (void*)h;
 	unsigned long num_words;
@@ -1968,12 +2108,12 @@
 		if (len)
 			drbd_bm_get_lel(mdev, c->word_offset, num_words, (unsigned long*)h->payload);
 		ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BITMAP,
-				   h, sizeof(struct p_header) + len, 0);
+				   h, sizeof(struct p_header80) + len, 0);
 		c->word_offset += num_words;
 		c->bit_offset = c->word_offset * BITS_PER_LONG;
 
 		c->packets[1]++;
-		c->bytes[1] += sizeof(struct p_header) + len;
+		c->bytes[1] += sizeof(struct p_header80) + len;
 
 		if (c->bit_offset > c->bm_bits)
 			c->bit_offset = c->bm_bits;
@@ -1989,14 +2129,14 @@
 int _drbd_send_bitmap(struct drbd_conf *mdev)
 {
 	struct bm_xfer_ctx c;
-	struct p_header *p;
+	struct p_header80 *p;
 	int ret;
 
 	ERR_IF(!mdev->bitmap) return FALSE;
 
 	/* maybe we should use some per thread scratch page,
 	 * and allocate that during initial device creation? */
-	p = (struct p_header *) __get_free_page(GFP_NOIO);
+	p = (struct p_header80 *) __get_free_page(GFP_NOIO);
 	if (!p) {
 		dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__);
 		return FALSE;
@@ -2054,7 +2194,7 @@
 	if (mdev->state.conn < C_CONNECTED)
 		return FALSE;
 	ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK,
-			(struct p_header *)&p, sizeof(p));
+			(struct p_header80 *)&p, sizeof(p));
 	return ok;
 }
 
@@ -2082,17 +2222,18 @@
 	if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED)
 		return FALSE;
 	ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd,
-				(struct p_header *)&p, sizeof(p));
+				(struct p_header80 *)&p, sizeof(p));
 	return ok;
 }
 
+/* dp->sector and dp->block_id already/still in network byte order,
+ * data_size is payload size according to dp->head,
+ * and may need to be corrected for digest size. */
 int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd,
-		     struct p_data *dp)
+		     struct p_data *dp, int data_size)
 {
-	const int header_size = sizeof(struct p_data)
-			      - sizeof(struct p_header);
-	int data_size  = ((struct p_header *)dp)->length - header_size;
-
+	data_size -= (mdev->agreed_pro_version >= 87 && mdev->integrity_r_tfm) ?
+		crypto_hash_digestsize(mdev->integrity_r_tfm) : 0;
 	return _drbd_send_ack(mdev, cmd, dp->sector, cpu_to_be32(data_size),
 			      dp->block_id);
 }
@@ -2140,7 +2281,7 @@
 	p.blksize  = cpu_to_be32(size);
 
 	ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, cmd,
-				(struct p_header *)&p, sizeof(p));
+				(struct p_header80 *)&p, sizeof(p));
 	return ok;
 }
 
@@ -2158,7 +2299,7 @@
 
 	p.head.magic   = BE_DRBD_MAGIC;
 	p.head.command = cpu_to_be16(cmd);
-	p.head.length  = cpu_to_be16(sizeof(p) - sizeof(struct p_header) + digest_size);
+	p.head.length  = cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + digest_size);
 
 	mutex_lock(&mdev->data.mutex);
 
@@ -2180,7 +2321,7 @@
 	p.blksize  = cpu_to_be32(size);
 
 	ok = drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OV_REQUEST,
-			   (struct p_header *)&p, sizeof(p));
+			   (struct p_header80 *)&p, sizeof(p));
 	return ok;
 }
 
@@ -2332,6 +2473,18 @@
 	return 1;
 }
 
+static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw)
+{
+	if (mdev->agreed_pro_version >= 95)
+		return  (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) |
+			(bi_rw & REQ_UNPLUG ? DP_UNPLUG : 0) |
+			(bi_rw & REQ_FUA ? DP_FUA : 0) |
+			(bi_rw & REQ_FLUSH ? DP_FLUSH : 0) |
+			(bi_rw & REQ_DISCARD ? DP_DISCARD : 0);
+	else
+		return bi_rw & (REQ_SYNC | REQ_UNPLUG) ? DP_RW_SYNC : 0;
+}
+
 /* Used to send write requests
  * R_PRIMARY -> Peer	(P_DATA)
  */
@@ -2349,30 +2502,25 @@
 	dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
 		crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
 
-	p.head.magic   = BE_DRBD_MAGIC;
-	p.head.command = cpu_to_be16(P_DATA);
-	p.head.length  =
-		cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + req->size);
+	if (req->size <= DRBD_MAX_SIZE_H80_PACKET) {
+		p.head.h80.magic   = BE_DRBD_MAGIC;
+		p.head.h80.command = cpu_to_be16(P_DATA);
+		p.head.h80.length  =
+			cpu_to_be16(sizeof(p) - sizeof(union p_header) + dgs + req->size);
+	} else {
+		p.head.h95.magic   = BE_DRBD_MAGIC_BIG;
+		p.head.h95.command = cpu_to_be16(P_DATA);
+		p.head.h95.length  =
+			cpu_to_be32(sizeof(p) - sizeof(union p_header) + dgs + req->size);
+	}
 
 	p.sector   = cpu_to_be64(req->sector);
 	p.block_id = (unsigned long)req;
 	p.seq_num  = cpu_to_be32(req->seq_num =
 				 atomic_add_return(1, &mdev->packet_seq));
-	dp_flags = 0;
 
-	/* NOTE: no need to check if barriers supported here as we would
-	 *       not pass the test in make_request_common in that case
-	 */
-	if (req->master_bio->bi_rw & REQ_HARDBARRIER) {
-		dev_err(DEV, "ASSERT FAILED would have set DP_HARDBARRIER\n");
-		/* dp_flags |= DP_HARDBARRIER; */
-	}
-	if (req->master_bio->bi_rw & REQ_SYNC)
-		dp_flags |= DP_RW_SYNC;
-	/* for now handle SYNCIO and UNPLUG
-	 * as if they still were one and the same flag */
-	if (req->master_bio->bi_rw & REQ_UNPLUG)
-		dp_flags |= DP_RW_SYNC;
+	dp_flags = bio_flags_to_wire(mdev, req->master_bio->bi_rw);
+
 	if (mdev->state.conn >= C_SYNC_SOURCE &&
 	    mdev->state.conn <= C_PAUSED_SYNC_T)
 		dp_flags |= DP_MAY_SET_IN_SYNC;
@@ -2413,10 +2561,17 @@
 	dgs = (mdev->agreed_pro_version >= 87 && mdev->integrity_w_tfm) ?
 		crypto_hash_digestsize(mdev->integrity_w_tfm) : 0;
 
-	p.head.magic   = BE_DRBD_MAGIC;
-	p.head.command = cpu_to_be16(cmd);
-	p.head.length  =
-		cpu_to_be16(sizeof(p) - sizeof(struct p_header) + dgs + e->size);
+	if (e->size <= DRBD_MAX_SIZE_H80_PACKET) {
+		p.head.h80.magic   = BE_DRBD_MAGIC;
+		p.head.h80.command = cpu_to_be16(cmd);
+		p.head.h80.length  =
+			cpu_to_be16(sizeof(p) - sizeof(struct p_header80) + dgs + e->size);
+	} else {
+		p.head.h95.magic   = BE_DRBD_MAGIC_BIG;
+		p.head.h95.command = cpu_to_be16(cmd);
+		p.head.h95.length  =
+			cpu_to_be32(sizeof(p) - sizeof(struct p_header80) + dgs + e->size);
+	}
 
 	p.sector   = cpu_to_be64(e->sector);
 	p.block_id = e->block_id;
@@ -2429,8 +2584,7 @@
 	if (!drbd_get_data_sock(mdev))
 		return 0;
 
-	ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
-					sizeof(p), dgs ? MSG_MORE : 0);
+	ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0);
 	if (ok && dgs) {
 		dgb = mdev->int_dig_out;
 		drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb);
@@ -2536,7 +2690,7 @@
 	unsigned long flags;
 	int rv = 0;
 
-	lock_kernel();
+	mutex_lock(&drbd_main_mutex);
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	/* to have a stable mdev->state.role
 	 * and no race with updating open_cnt */
@@ -2551,7 +2705,7 @@
 	if (!rv)
 		mdev->open_cnt++;
 	spin_unlock_irqrestore(&mdev->req_lock, flags);
-	unlock_kernel();
+	mutex_unlock(&drbd_main_mutex);
 
 	return rv;
 }
@@ -2559,9 +2713,9 @@
 static int drbd_release(struct gendisk *gd, fmode_t mode)
 {
 	struct drbd_conf *mdev = gd->private_data;
-	lock_kernel();
+	mutex_lock(&drbd_main_mutex);
 	mdev->open_cnt--;
-	unlock_kernel();
+	mutex_unlock(&drbd_main_mutex);
 	return 0;
 }
 
@@ -2605,7 +2759,13 @@
 		/* .verify_alg = */	{}, 0,
 		/* .cpu_mask = */	{}, 0,
 		/* .csums_alg = */	{}, 0,
-		/* .use_rle = */	0
+		/* .use_rle = */	0,
+		/* .on_no_data = */	DRBD_ON_NO_DATA_DEF,
+		/* .c_plan_ahead = */	DRBD_C_PLAN_AHEAD_DEF,
+		/* .c_delay_target = */	DRBD_C_DELAY_TARGET_DEF,
+		/* .c_fill_target = */	DRBD_C_FILL_TARGET_DEF,
+		/* .c_max_rate = */	DRBD_C_MAX_RATE_DEF,
+		/* .c_min_rate = */	DRBD_C_MIN_RATE_DEF
 	};
 
 	/* Have to use that way, because the layout differs between
@@ -2616,7 +2776,9 @@
 		  .conn = C_STANDALONE,
 		  .disk = D_DISKLESS,
 		  .pdsk = D_UNKNOWN,
-		  .susp = 0
+		  .susp = 0,
+		  .susp_nod = 0,
+		  .susp_fen = 0
 		} };
 }
 
@@ -2627,11 +2789,6 @@
 
 	drbd_set_defaults(mdev);
 
-	/* for now, we do NOT yet support it,
-	 * even though we start some framework
-	 * to eventually support barriers */
-	set_bit(NO_BARRIER_SUPP, &mdev->flags);
-
 	atomic_set(&mdev->ap_bio_cnt, 0);
 	atomic_set(&mdev->ap_pending_cnt, 0);
 	atomic_set(&mdev->rs_pending_cnt, 0);
@@ -2640,6 +2797,9 @@
 	atomic_set(&mdev->net_cnt, 0);
 	atomic_set(&mdev->packet_seq, 0);
 	atomic_set(&mdev->pp_in_use, 0);
+	atomic_set(&mdev->pp_in_use_by_net, 0);
+	atomic_set(&mdev->rs_sect_in, 0);
+	atomic_set(&mdev->rs_sect_ev, 0);
 
 	mutex_init(&mdev->md_io_mutex);
 	mutex_init(&mdev->data.mutex);
@@ -2666,11 +2826,13 @@
 	INIT_LIST_HEAD(&mdev->meta.work.q);
 	INIT_LIST_HEAD(&mdev->resync_work.list);
 	INIT_LIST_HEAD(&mdev->unplug_work.list);
+	INIT_LIST_HEAD(&mdev->go_diskless.list);
 	INIT_LIST_HEAD(&mdev->md_sync_work.list);
 	INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
 
 	mdev->resync_work.cb  = w_resync_inactive;
 	mdev->unplug_work.cb  = w_send_write_hint;
+	mdev->go_diskless.cb  = w_go_diskless;
 	mdev->md_sync_work.cb = w_md_sync;
 	mdev->bm_io_work.w.cb = w_bitmap_io;
 	init_timer(&mdev->resync_timer);
@@ -2682,6 +2844,7 @@
 
 	init_waitqueue_head(&mdev->misc_wait);
 	init_waitqueue_head(&mdev->state_wait);
+	init_waitqueue_head(&mdev->net_cnt_wait);
 	init_waitqueue_head(&mdev->ee_wait);
 	init_waitqueue_head(&mdev->al_wait);
 	init_waitqueue_head(&mdev->seq_wait);
@@ -2691,12 +2854,13 @@
 	drbd_thread_init(mdev, &mdev->asender, drbd_asender);
 
 	mdev->agreed_pro_version = PRO_VERSION_MAX;
-	mdev->write_ordering = WO_bio_barrier;
+	mdev->write_ordering = WO_bdev_flush;
 	mdev->resync_wenr = LC_FREE;
 }
 
 void drbd_mdev_cleanup(struct drbd_conf *mdev)
 {
+	int i;
 	if (mdev->receiver.t_state != None)
 		dev_err(DEV, "ASSERT FAILED: receiver t_state == %d expected 0.\n",
 				mdev->receiver.t_state);
@@ -2713,9 +2877,13 @@
 	mdev->p_size       =
 	mdev->rs_start     =
 	mdev->rs_total     =
-	mdev->rs_failed    =
-	mdev->rs_mark_left =
-	mdev->rs_mark_time = 0;
+	mdev->rs_failed    = 0;
+	mdev->rs_last_events = 0;
+	mdev->rs_last_sect_ev = 0;
+	for (i = 0; i < DRBD_SYNC_MARKS; i++) {
+		mdev->rs_mark_left[i] = 0;
+		mdev->rs_mark_time[i] = 0;
+	}
 	D_ASSERT(mdev->net_conf == NULL);
 
 	drbd_set_my_capacity(mdev, 0);
@@ -2726,6 +2894,7 @@
 	}
 
 	drbd_free_resources(mdev);
+	clear_bit(AL_SUSPENDED, &mdev->flags);
 
 	/*
 	 * currently we drbd_init_ee only on module load, so
@@ -2741,7 +2910,7 @@
 	D_ASSERT(list_empty(&mdev->meta.work.q));
 	D_ASSERT(list_empty(&mdev->resync_work.list));
 	D_ASSERT(list_empty(&mdev->unplug_work.list));
-
+	D_ASSERT(list_empty(&mdev->go_diskless.list));
 }
 
 
@@ -2824,7 +2993,7 @@
 
 	drbd_ee_mempool = mempool_create(number,
 		mempool_alloc_slab, mempool_free_slab, drbd_ee_cache);
-	if (drbd_request_mempool == NULL)
+	if (drbd_ee_mempool == NULL)
 		goto Enomem;
 
 	/* drbd's page pool */
@@ -3280,9 +3449,10 @@
 	sector_t sector;
 	int i;
 
+	del_timer(&mdev->md_sync_timer);
+	/* timer may be rearmed by drbd_md_mark_dirty() now. */
 	if (!test_and_clear_bit(MD_DIRTY, &mdev->flags))
 		return;
-	del_timer(&mdev->md_sync_timer);
 
 	/* We use here D_FAILED and not D_ATTACHING because we try to write
 	 * metadata even if we detach due to a disk failure! */
@@ -3310,12 +3480,9 @@
 	D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
 	sector = mdev->ldev->md.md_offset;
 
-	if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
-		clear_bit(MD_DIRTY, &mdev->flags);
-	} else {
+	if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
 		/* this was a try anyways ... */
 		dev_err(DEV, "meta data update failed!\n");
-
 		drbd_chk_io_error(mdev, 1, TRUE);
 	}
 
@@ -3402,6 +3569,28 @@
 	return rv;
 }
 
+static void debug_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index)
+{
+	static char *uuid_str[UI_EXTENDED_SIZE] = {
+		[UI_CURRENT] = "CURRENT",
+		[UI_BITMAP] = "BITMAP",
+		[UI_HISTORY_START] = "HISTORY_START",
+		[UI_HISTORY_END] = "HISTORY_END",
+		[UI_SIZE] = "SIZE",
+		[UI_FLAGS] = "FLAGS",
+	};
+
+	if (index >= UI_EXTENDED_SIZE) {
+		dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n");
+		return;
+	}
+
+	dynamic_dev_dbg(DEV, " uuid[%s] now %016llX\n",
+		 uuid_str[index],
+		 (unsigned long long)mdev->ldev->md.uuid[index]);
+}
+
+
 /**
  * drbd_md_mark_dirty() - Mark meta data super block as dirty
  * @mdev:	DRBD device.
@@ -3410,19 +3599,31 @@
  * the meta-data super block. This function sets MD_DIRTY, and starts a
  * timer that ensures that within five seconds you have to call drbd_md_sync().
  */
+#ifdef DEBUG
+void drbd_md_mark_dirty_(struct drbd_conf *mdev, unsigned int line, const char *func)
+{
+	if (!test_and_set_bit(MD_DIRTY, &mdev->flags)) {
+		mod_timer(&mdev->md_sync_timer, jiffies + HZ);
+		mdev->last_md_mark_dirty.line = line;
+		mdev->last_md_mark_dirty.func = func;
+	}
+}
+#else
 void drbd_md_mark_dirty(struct drbd_conf *mdev)
 {
-	set_bit(MD_DIRTY, &mdev->flags);
-	mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
+	if (!test_and_set_bit(MD_DIRTY, &mdev->flags))
+		mod_timer(&mdev->md_sync_timer, jiffies + 5*HZ);
 }
-
+#endif
 
 static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local)
 {
 	int i;
 
-	for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++)
+	for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) {
 		mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i];
+		debug_drbd_uuid(mdev, i+1);
+	}
 }
 
 void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local)
@@ -3437,6 +3638,7 @@
 	}
 
 	mdev->ldev->md.uuid[idx] = val;
+	debug_drbd_uuid(mdev, idx);
 	drbd_md_mark_dirty(mdev);
 }
 
@@ -3446,6 +3648,7 @@
 	if (mdev->ldev->md.uuid[idx]) {
 		drbd_uuid_move_history(mdev);
 		mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx];
+		debug_drbd_uuid(mdev, UI_HISTORY_START);
 	}
 	_drbd_uuid_set(mdev, idx, val);
 }
@@ -3464,9 +3667,12 @@
 	dev_info(DEV, "Creating new current UUID\n");
 	D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0);
 	mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT];
+	debug_drbd_uuid(mdev, UI_BITMAP);
 
 	get_random_bytes(&val, sizeof(u64));
 	_drbd_uuid_set(mdev, UI_CURRENT, val);
+	/* get it to stable storage _now_ */
+	drbd_md_sync(mdev);
 }
 
 void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local)
@@ -3478,6 +3684,8 @@
 		drbd_uuid_move_history(mdev);
 		mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP];
 		mdev->ldev->md.uuid[UI_BITMAP] = 0;
+		debug_drbd_uuid(mdev, UI_HISTORY_START);
+		debug_drbd_uuid(mdev, UI_BITMAP);
 	} else {
 		if (mdev->ldev->md.uuid[UI_BITMAP])
 			dev_warn(DEV, "bm UUID already set");
@@ -3485,6 +3693,7 @@
 		mdev->ldev->md.uuid[UI_BITMAP] = val;
 		mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1);
 
+		debug_drbd_uuid(mdev, UI_BITMAP);
 	}
 	drbd_md_mark_dirty(mdev);
 }
@@ -3527,6 +3736,7 @@
 {
 	int rv = -EIO;
 
+	drbd_resume_al(mdev);
 	if (get_ldev_if_state(mdev, D_ATTACHING)) {
 		drbd_bm_clear_all(mdev);
 		rv = drbd_bm_write(mdev);
@@ -3559,6 +3769,41 @@
 	return 1;
 }
 
+void drbd_ldev_destroy(struct drbd_conf *mdev)
+{
+	lc_destroy(mdev->resync);
+	mdev->resync = NULL;
+	lc_destroy(mdev->act_log);
+	mdev->act_log = NULL;
+	__no_warn(local,
+		drbd_free_bc(mdev->ldev);
+		mdev->ldev = NULL;);
+
+	if (mdev->md_io_tmpp) {
+		__free_page(mdev->md_io_tmpp);
+		mdev->md_io_tmpp = NULL;
+	}
+	clear_bit(GO_DISKLESS, &mdev->flags);
+}
+
+static int w_go_diskless(struct drbd_conf *mdev, struct drbd_work *w, int unused)
+{
+	D_ASSERT(mdev->state.disk == D_FAILED);
+	/* we cannot assert local_cnt == 0 here, as get_ldev_if_state will
+	 * inc/dec it frequently. Once we are D_DISKLESS, no one will touch
+	 * the protected members anymore, though, so once put_ldev reaches zero
+	 * again, it will be safe to free them. */
+	drbd_force_state(mdev, NS(disk, D_DISKLESS));
+	return 1;
+}
+
+void drbd_go_diskless(struct drbd_conf *mdev)
+{
+	D_ASSERT(mdev->state.disk == D_FAILED);
+	if (!test_and_set_bit(GO_DISKLESS, &mdev->flags))
+		drbd_queue_work(&mdev->data.work, &mdev->go_diskless);
+}
+
 /**
  * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap
  * @mdev:	DRBD device.
@@ -3655,8 +3900,11 @@
 static int w_md_sync(struct drbd_conf *mdev, struct drbd_work *w, int unused)
 {
 	dev_warn(DEV, "md_sync_timer expired! Worker calls drbd_md_sync().\n");
+#ifdef DEBUG
+	dev_warn(DEV, "last md_mark_dirty: %s:%u\n",
+		mdev->last_md_mark_dirty.func, mdev->last_md_mark_dirty.line);
+#endif
 	drbd_md_sync(mdev);
-
 	return 1;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_nl.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_nl.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_nl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_nl.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,10 +33,13 @@
 #include <linux/blkpg.h>
 #include <linux/cpumask.h>
 #include "drbd_int.h"
+#include "drbd_req.h"
 #include "drbd_wrappers.h"
 #include <asm/unaligned.h>
 #include <linux/drbd_tag_magic.h>
 #include <linux/drbd_limits.h>
+#include <linux/compiler.h>
+#include <linux/kthread.h>
 
 static unsigned short *tl_add_blob(unsigned short *, enum drbd_tags, const void *, int);
 static unsigned short *tl_add_str(unsigned short *, enum drbd_tags, const char *);
@@ -169,6 +172,10 @@
 		put_net_conf(mdev);
 	}
 
+	/* The helper may take some time.
+	 * write out any unsynced meta data changes now */
+	drbd_md_sync(mdev);
+
 	dev_info(DEV, "helper command: %s %s %s\n", usermode_helper, cmd, mb);
 
 	drbd_bcast_ev_helper(mdev, cmd);
@@ -202,12 +209,10 @@
 		put_ldev(mdev);
 	} else {
 		dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n");
-		return mdev->state.pdsk;
+		nps = mdev->state.pdsk;
+		goto out;
 	}
 
-	if (fp == FP_STONITH)
-		_drbd_request_state(mdev, NS(susp, 1), CS_WAIT_COMPLETE);
-
 	r = drbd_khelper(mdev, "fence-peer");
 
 	switch ((r>>8) & 0xff) {
@@ -252,9 +257,36 @@
 
 	dev_info(DEV, "fence-peer helper returned %d (%s)\n",
 			(r>>8) & 0xff, ex_to_string);
+
+out:
+	if (mdev->state.susp_fen && nps >= D_UNKNOWN) {
+		/* The handler was not successful... unfreeze here, the
+		   state engine can not unfreeze... */
+		_drbd_request_state(mdev, NS(susp_fen, 0), CS_VERBOSE);
+	}
+
 	return nps;
 }
 
+static int _try_outdate_peer_async(void *data)
+{
+	struct drbd_conf *mdev = (struct drbd_conf *)data;
+	enum drbd_disk_state nps;
+
+	nps = drbd_try_outdate_peer(mdev);
+	drbd_request_state(mdev, NS(pdsk, nps));
+
+	return 0;
+}
+
+void drbd_try_outdate_peer_async(struct drbd_conf *mdev)
+{
+	struct task_struct *opa;
+
+	opa = kthread_run(_try_outdate_peer_async, mdev, "drbd%d_a_helper", mdev_to_minor(mdev));
+	if (IS_ERR(opa))
+		dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n");
+}
 
 int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
 {
@@ -394,6 +426,39 @@
 	return r;
 }
 
+static struct drbd_conf *ensure_mdev(int minor, int create)
+{
+	struct drbd_conf *mdev;
+
+	if (minor >= minor_count)
+		return NULL;
+
+	mdev = minor_to_mdev(minor);
+
+	if (!mdev && create) {
+		struct gendisk *disk = NULL;
+		mdev = drbd_new_device(minor);
+
+		spin_lock_irq(&drbd_pp_lock);
+		if (minor_table[minor] == NULL) {
+			minor_table[minor] = mdev;
+			disk = mdev->vdisk;
+			mdev = NULL;
+		} /* else: we lost the race */
+		spin_unlock_irq(&drbd_pp_lock);
+
+		if (disk) /* we won the race above */
+			/* in case we ever add a drbd_delete_device(),
+			 * don't forget the del_gendisk! */
+			add_disk(disk);
+		else /* we lost the race above */
+			drbd_free_mdev(mdev);
+
+		mdev = minor_to_mdev(minor);
+	}
+
+	return mdev;
+}
 
 static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 			   struct drbd_nl_cfg_reply *reply)
@@ -494,6 +559,8 @@
 void drbd_suspend_io(struct drbd_conf *mdev)
 {
 	set_bit(SUSPEND_IO, &mdev->flags);
+	if (is_susp(mdev->state))
+		return;
 	wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
 }
 
@@ -713,9 +780,6 @@
 	blk_queue_segment_boundary(q, PAGE_SIZE-1);
 	blk_stack_limits(&q->limits, &b->limits, 0);
 
-	if (b->merge_bvec_fn)
-		dev_warn(DEV, "Backing device's merge_bvec_fn() = %p\n",
-		     b->merge_bvec_fn);
 	dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q));
 
 	if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
@@ -729,14 +793,16 @@
 /* serialize deconfig (worker exiting, doing cleanup)
  * and reconfig (drbdsetup disk, drbdsetup net)
  *
- * wait for a potentially exiting worker, then restart it,
- * or start a new one.
+ * Wait for a potentially exiting worker, then restart it,
+ * or start a new one.  Flush any pending work, there may still be an
+ * after_state_change queued.
  */
 static void drbd_reconfig_start(struct drbd_conf *mdev)
 {
 	wait_event(mdev->state_wait, !test_and_set_bit(CONFIG_PENDING, &mdev->flags));
 	wait_event(mdev->state_wait, !test_bit(DEVICE_DYING, &mdev->flags));
 	drbd_thread_start(&mdev->worker);
+	drbd_flush_workqueue(mdev);
 }
 
 /* if still unconfigured, stops worker again.
@@ -756,6 +822,29 @@
 	wake_up(&mdev->state_wait);
 }
 
+/* Make sure IO is suspended before calling this function(). */
+static void drbd_suspend_al(struct drbd_conf *mdev)
+{
+	int s = 0;
+
+	if (lc_try_lock(mdev->act_log)) {
+		drbd_al_shrink(mdev);
+		lc_unlock(mdev->act_log);
+	} else {
+		dev_warn(DEV, "Failed to lock al in drbd_suspend_al()\n");
+		return;
+	}
+
+	spin_lock_irq(&mdev->req_lock);
+	if (mdev->state.conn < C_CONNECTED)
+		s = !test_and_set_bit(AL_SUSPENDED, &mdev->flags);
+
+	spin_unlock_irq(&mdev->req_lock);
+
+	if (s)
+		dev_info(DEV, "Suspended AL updates\n");
+}
+
 /* does always return 0;
  * interesting return code is in reply->ret_code */
 static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
@@ -769,6 +858,7 @@
 	struct inode *inode, *inode2;
 	struct lru_cache *resync_lru = NULL;
 	union drbd_state ns, os;
+	unsigned int max_seg_s;
 	int rv;
 	int cp_discovered = 0;
 	int logical_block_size;
@@ -780,6 +870,11 @@
 		retcode = ERR_DISK_CONFIGURED;
 		goto fail;
 	}
+	/* It may just now have detached because of IO error.  Make sure
+	 * drbd_ldev_destroy is done already, we may end up here very fast,
+	 * e.g. if someone calls attach from the on-io-error handler,
+	 * to realize a "hot spare" feature (not that I'd recommend that) */
+	wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
 
 	/* allocation not in the IO path, cqueue thread context */
 	nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
@@ -803,6 +898,15 @@
 		goto fail;
 	}
 
+	if (get_net_conf(mdev)) {
+		int prot = mdev->net_conf->wire_protocol;
+		put_net_conf(mdev);
+		if (nbc->dc.fencing == FP_STONITH && prot == DRBD_PROT_A) {
+			retcode = ERR_STONITH_AND_PROT_A;
+			goto fail;
+		}
+	}
+
 	nbc->lo_file = filp_open(nbc->dc.backing_dev, O_RDWR, 0);
 	if (IS_ERR(nbc->lo_file)) {
 		dev_err(DEV, "open(\"%s\") failed with %ld\n", nbc->dc.backing_dev,
@@ -924,7 +1028,7 @@
 
 	drbd_suspend_io(mdev);
 	/* also wait for the last barrier ack. */
-	wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt));
+	wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_pending_cnt) || is_susp(mdev->state));
 	/* and for any other previously queued work */
 	drbd_flush_workqueue(mdev);
 
@@ -999,9 +1103,9 @@
 	/* Reset the "barriers don't work" bits here, then force meta data to
 	 * be written, to ensure we determine if barriers are supported. */
 	if (nbc->dc.no_md_flush)
-		set_bit(MD_NO_BARRIER, &mdev->flags);
+		set_bit(MD_NO_FUA, &mdev->flags);
 	else
-		clear_bit(MD_NO_BARRIER, &mdev->flags);
+		clear_bit(MD_NO_FUA, &mdev->flags);
 
 	/* Point of no return reached.
 	 * Devices and memory are no longer released by error cleanup below.
@@ -1013,15 +1117,16 @@
 	nbc = NULL;
 	resync_lru = NULL;
 
-	mdev->write_ordering = WO_bio_barrier;
-	drbd_bump_write_ordering(mdev, WO_bio_barrier);
+	mdev->write_ordering = WO_bdev_flush;
+	drbd_bump_write_ordering(mdev, WO_bdev_flush);
 
 	if (drbd_md_test_flag(mdev->ldev, MDF_CRASHED_PRIMARY))
 		set_bit(CRASHED_PRIMARY, &mdev->flags);
 	else
 		clear_bit(CRASHED_PRIMARY, &mdev->flags);
 
-	if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND)) {
+	if (drbd_md_test_flag(mdev->ldev, MDF_PRIMARY_IND) &&
+	    !(mdev->state.role == R_PRIMARY && mdev->state.susp_nod)) {
 		set_bit(CRASHED_PRIMARY, &mdev->flags);
 		cp_discovered = 1;
 	}
@@ -1031,7 +1136,20 @@
 	mdev->read_cnt = 0;
 	mdev->writ_cnt = 0;
 
-	drbd_setup_queue_param(mdev, DRBD_MAX_SEGMENT_SIZE);
+	max_seg_s = DRBD_MAX_SEGMENT_SIZE;
+	if (mdev->state.conn == C_CONNECTED) {
+		/* We are Primary, Connected, and now attach a new local
+		 * backing store. We must not increase the user visible maximum
+		 * bio size on this device to something the peer may not be
+		 * able to handle. */
+		if (mdev->agreed_pro_version < 94)
+			max_seg_s = queue_max_segment_size(mdev->rq_queue);
+		else if (mdev->agreed_pro_version == 94)
+			max_seg_s = DRBD_MAX_SIZE_H80_PACKET;
+		/* else: drbd 8.3.9 and later, stay with default */
+	}
+
+	drbd_setup_queue_param(mdev, max_seg_s);
 
 	/* If I am currently not R_PRIMARY,
 	 * but meta data primary indicator is set,
@@ -1079,6 +1197,9 @@
 		drbd_al_to_on_disk_bm(mdev);
 	}
 
+	if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev))
+		drbd_suspend_al(mdev); /* IO is still suspended here... */
+
 	spin_lock_irq(&mdev->req_lock);
 	os = mdev->state;
 	ns.i = os.i;
@@ -1146,7 +1267,7 @@
  force_diskless_dec:
 	put_ldev(mdev);
  force_diskless:
-	drbd_force_state(mdev, NS(disk, D_DISKLESS));
+	drbd_force_state(mdev, NS(disk, D_FAILED));
 	drbd_md_sync(mdev);
  release_bdev2_fail:
 	if (nbc)
@@ -1169,10 +1290,19 @@
 	return 0;
 }
 
+/* Detaching the disk is a process in multiple stages.  First we need to lock
+ * out application IO, in-flight IO, IO stuck in drbd_al_begin_io.
+ * Then we transition to D_DISKLESS, and wait for put_ldev() to return all
+ * internal references as well.
+ * Only then we have finally detached. */
 static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 			  struct drbd_nl_cfg_reply *reply)
 {
+	drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
 	reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
+	if (mdev->state.disk == D_DISKLESS)
+		wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+	drbd_resume_io(mdev);
 	return 0;
 }
 
@@ -1235,7 +1365,16 @@
 	    && (new_conf->wire_protocol != DRBD_PROT_C)) {
 		retcode = ERR_NOT_PROTO_C;
 		goto fail;
-	};
+	}
+
+	if (get_ldev(mdev)) {
+		enum drbd_fencing_p fp = mdev->ldev->dc.fencing;
+		put_ldev(mdev);
+		if (new_conf->wire_protocol == DRBD_PROT_A && fp == FP_STONITH) {
+			retcode = ERR_STONITH_AND_PROT_A;
+			goto fail;
+		}
+	}
 
 	if (mdev->state.role == R_PRIMARY && new_conf->want_lose) {
 		retcode = ERR_DISCARD;
@@ -1350,6 +1489,7 @@
 		}
 	}
 
+	drbd_flush_workqueue(mdev);
 	spin_lock_irq(&mdev->req_lock);
 	if (mdev->net_conf != NULL) {
 		retcode = ERR_NET_CONFIGURED;
@@ -1388,10 +1528,9 @@
 	mdev->int_dig_out=int_dig_out;
 	mdev->int_dig_in=int_dig_in;
 	mdev->int_dig_vv=int_dig_vv;
+	retcode = _drbd_set_state(_NS(mdev, conn, C_UNCONNECTED), CS_VERBOSE, NULL);
 	spin_unlock_irq(&mdev->req_lock);
 
-	retcode = _drbd_request_state(mdev, NS(conn, C_UNCONNECTED), CS_VERBOSE);
-
 	kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
 	reply->ret_code = retcode;
 	drbd_reconfig_done(mdev);
@@ -1546,6 +1685,8 @@
 	struct crypto_hash *csums_tfm = NULL;
 	struct syncer_conf sc;
 	cpumask_var_t new_cpu_mask;
+	int *rs_plan_s = NULL;
+	int fifo_size;
 
 	if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL)) {
 		retcode = ERR_NOMEM;
@@ -1557,6 +1698,12 @@
 		sc.rate       = DRBD_RATE_DEF;
 		sc.after      = DRBD_AFTER_DEF;
 		sc.al_extents = DRBD_AL_EXTENTS_DEF;
+		sc.on_no_data  = DRBD_ON_NO_DATA_DEF;
+		sc.c_plan_ahead = DRBD_C_PLAN_AHEAD_DEF;
+		sc.c_delay_target = DRBD_C_DELAY_TARGET_DEF;
+		sc.c_fill_target = DRBD_C_FILL_TARGET_DEF;
+		sc.c_max_rate = DRBD_C_MAX_RATE_DEF;
+		sc.c_min_rate = DRBD_C_MIN_RATE_DEF;
 	} else
 		memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf));
 
@@ -1634,6 +1781,12 @@
 	}
 #undef AL_MAX
 
+	/* to avoid spurious errors when configuring minors before configuring
+	 * the minors they depend on: if necessary, first create the minor we
+	 * depend on */
+	if (sc.after >= 0)
+		ensure_mdev(sc.after, 1);
+
 	/* most sanity checks done, try to assign the new sync-after
 	 * dependency.  need to hold the global lock in there,
 	 * to avoid a race in the dependency loop check. */
@@ -1641,6 +1794,16 @@
 	if (retcode != NO_ERROR)
 		goto fail;
 
+	fifo_size = (sc.c_plan_ahead * 10 * SLEEP_TIME) / HZ;
+	if (fifo_size != mdev->rs_plan_s.size && fifo_size > 0) {
+		rs_plan_s   = kzalloc(sizeof(int) * fifo_size, GFP_KERNEL);
+		if (!rs_plan_s) {
+			dev_err(DEV, "kmalloc of fifo_buffer failed");
+			retcode = ERR_NOMEM;
+			goto fail;
+		}
+	}
+
 	/* ok, assign the rest of it as well.
 	 * lock against receive_SyncParam() */
 	spin_lock(&mdev->peer_seq_lock);
@@ -1657,6 +1820,15 @@
 		mdev->verify_tfm = verify_tfm;
 		verify_tfm = NULL;
 	}
+
+	if (fifo_size != mdev->rs_plan_s.size) {
+		kfree(mdev->rs_plan_s.values);
+		mdev->rs_plan_s.values = rs_plan_s;
+		mdev->rs_plan_s.size   = fifo_size;
+		mdev->rs_planed = 0;
+		rs_plan_s = NULL;
+	}
+
 	spin_unlock(&mdev->peer_seq_lock);
 
 	if (get_ldev(mdev)) {
@@ -1688,6 +1860,7 @@
 
 	kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE);
 fail:
+	kfree(rs_plan_s);
 	free_cpumask_var(new_cpu_mask);
 	crypto_free_hash(csums_tfm);
 	crypto_free_hash(verify_tfm);
@@ -1721,12 +1894,38 @@
 	return 0;
 }
 
+static int drbd_bmio_set_susp_al(struct drbd_conf *mdev)
+{
+	int rv;
+
+	rv = drbd_bmio_set_n_write(mdev);
+	drbd_suspend_al(mdev);
+	return rv;
+}
+
 static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 				   struct drbd_nl_cfg_reply *reply)
 {
+	int retcode;
 
-	reply->ret_code = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
+	retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED);
 
+	if (retcode < SS_SUCCESS) {
+		if (retcode == SS_NEED_CONNECTION && mdev->state.role == R_PRIMARY) {
+			/* The peer will get a resync upon connect anyways. Just make that
+			   into a full resync. */
+			retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT));
+			if (retcode >= SS_SUCCESS) {
+				/* open coded drbd_bitmap_io() */
+				if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al,
+						   "set_n_write from invalidate_peer"))
+					retcode = ERR_IO_MD_DISK;
+			}
+		} else
+			retcode = drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S));
+	}
+
+	reply->ret_code = retcode;
 	return 0;
 }
 
@@ -1765,7 +1964,20 @@
 static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 			     struct drbd_nl_cfg_reply *reply)
 {
-	reply->ret_code = drbd_request_state(mdev, NS(susp, 0));
+	if (test_bit(NEW_CUR_UUID, &mdev->flags)) {
+		drbd_uuid_new_current(mdev);
+		clear_bit(NEW_CUR_UUID, &mdev->flags);
+	}
+	drbd_suspend_io(mdev);
+	reply->ret_code = drbd_request_state(mdev, NS3(susp, 0, susp_nod, 0, susp_fen, 0));
+	if (reply->ret_code == SS_SUCCESS) {
+		if (mdev->state.conn < C_CONNECTED)
+			tl_clear(mdev);
+		if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED)
+			tl_restart(mdev, fail_frozen_disk_io);
+	}
+	drbd_resume_io(mdev);
+
 	return 0;
 }
 
@@ -1941,40 +2153,6 @@
 	return 0;
 }
 
-static struct drbd_conf *ensure_mdev(struct drbd_nl_cfg_req *nlp)
-{
-	struct drbd_conf *mdev;
-
-	if (nlp->drbd_minor >= minor_count)
-		return NULL;
-
-	mdev = minor_to_mdev(nlp->drbd_minor);
-
-	if (!mdev && (nlp->flags & DRBD_NL_CREATE_DEVICE)) {
-		struct gendisk *disk = NULL;
-		mdev = drbd_new_device(nlp->drbd_minor);
-
-		spin_lock_irq(&drbd_pp_lock);
-		if (minor_table[nlp->drbd_minor] == NULL) {
-			minor_table[nlp->drbd_minor] = mdev;
-			disk = mdev->vdisk;
-			mdev = NULL;
-		} /* else: we lost the race */
-		spin_unlock_irq(&drbd_pp_lock);
-
-		if (disk) /* we won the race above */
-			/* in case we ever add a drbd_delete_device(),
-			 * don't forget the del_gendisk! */
-			add_disk(disk);
-		else /* we lost the race above */
-			drbd_free_mdev(mdev);
-
-		mdev = minor_to_mdev(nlp->drbd_minor);
-	}
-
-	return mdev;
-}
-
 struct cn_handler_struct {
 	int (*function)(struct drbd_conf *,
 			 struct drbd_nl_cfg_req *,
@@ -2035,7 +2213,8 @@
 		goto fail;
 	}
 
-	mdev = ensure_mdev(nlp);
+	mdev = ensure_mdev(nlp->drbd_minor,
+			(nlp->flags & DRBD_NL_CREATE_DEVICE));
 	if (!mdev) {
 		retcode = ERR_MINOR_INVALID;
 		goto fail;
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_proc.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_proc.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_proc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_proc.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,7 @@
 	unsigned long db, dt, dbdt, rt, rs_left;
 	unsigned int res;
 	int i, x, y;
+	int stalled = 0;
 
 	drbd_get_syncer_progress(mdev, &rs_left, &res);
 
@@ -90,18 +91,17 @@
 	 * db: blocks written from mark until now
 	 * rt: remaining time
 	 */
-	dt = (jiffies - mdev->rs_mark_time) / HZ;
-
-	if (dt > 20) {
-		/* if we made no update to rs_mark_time for too long,
-		 * we are stalled. show that. */
-		seq_printf(seq, "stalled\n");
-		return;
-	}
+	/* Rolling marks. last_mark+1 may just now be modified.  last_mark+2 is
+	 * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at
+	 * least DRBD_SYNC_MARK_STEP time before it will be modified. */
+	i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS;
+	dt = (jiffies - mdev->rs_mark_time[i]) / HZ;
+	if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS))
+		stalled = 1;
 
 	if (!dt)
 		dt++;
-	db = mdev->rs_mark_left - rs_left;
+	db = mdev->rs_mark_left[i] - rs_left;
 	rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */
 
 	seq_printf(seq, "finish: %lu:%02lu:%02lu",
@@ -118,7 +118,7 @@
 	/* mean speed since syncer started
 	 * we do account for PausedSync periods */
 	dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ;
-	if (dt <= 0)
+	if (dt == 0)
 		dt = 1;
 	db = mdev->rs_total - rs_left;
 	dbdt = Bit2KB(db/dt);
@@ -128,7 +128,14 @@
 	else
 		seq_printf(seq, " (%ld)", dbdt);
 
-	seq_printf(seq, " K/sec\n");
+	if (mdev->state.conn == C_SYNC_TARGET) {
+		if (mdev->c_sync_rate > 1000)
+			seq_printf(seq, " want: %d,%03d",
+				   mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000);
+		else
+			seq_printf(seq, " want: %d", mdev->c_sync_rate);
+	}
+	seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : "");
 }
 
 static void resync_dump_detail(struct seq_file *seq, struct lc_element *e)
@@ -151,7 +158,6 @@
 		[WO_none] = 'n',
 		[WO_drain_io] = 'd',
 		[WO_bdev_flush] = 'f',
-		[WO_bio_barrier] = 'b',
 	};
 
 	seq_printf(seq, "version: " REL_VERSION " (api:%d/proto:%d-%d)\n%s\n",
@@ -196,7 +202,7 @@
 			seq_printf(seq, "%2d: cs:Unconfigured\n", i);
 		} else {
 			seq_printf(seq,
-			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c\n"
+			   "%2d: cs:%s ro:%s/%s ds:%s/%s %c %c%c%c%c%c%c\n"
 			   "    ns:%u nr:%u dw:%u dr:%u al:%u bm:%u "
 			   "lo:%d pe:%d ua:%d ap:%d ep:%d wo:%c",
 			   i, sn,
@@ -206,11 +212,12 @@
 			   drbd_disk_str(mdev->state.pdsk),
 			   (mdev->net_conf == NULL ? ' ' :
 			    (mdev->net_conf->wire_protocol - DRBD_PROT_A+'A')),
-			   mdev->state.susp ? 's' : 'r',
+			   is_susp(mdev->state) ? 's' : 'r',
 			   mdev->state.aftr_isp ? 'a' : '-',
 			   mdev->state.peer_isp ? 'p' : '-',
 			   mdev->state.user_isp ? 'u' : '-',
 			   mdev->congestion_reason ?: '-',
+			   test_bit(AL_SUSPENDED, &mdev->flags) ? 's' : '-',
 			   mdev->send_cnt/2,
 			   mdev->recv_cnt/2,
 			   mdev->writ_cnt/2,
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_receiver.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_receiver.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_receiver.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_receiver.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,7 +36,6 @@
 #include <linux/memcontrol.h>
 #include <linux/mm_inline.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/pkt_sched.h>
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -49,11 +48,6 @@
 
 #include "drbd_vli.h"
 
-struct flush_work {
-	struct drbd_work w;
-	struct drbd_epoch *epoch;
-};
-
 enum finish_epoch {
 	FE_STILL_LIVE,
 	FE_DESTROYED,
@@ -66,16 +60,6 @@
 static enum finish_epoch drbd_may_finish_epoch(struct drbd_conf *, struct drbd_epoch *, enum epoch_event);
 static int e_end_block(struct drbd_conf *, struct drbd_work *, int);
 
-static struct drbd_epoch *previous_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
-{
-	struct drbd_epoch *prev;
-	spin_lock(&mdev->epoch_lock);
-	prev = list_entry(epoch->list.prev, struct drbd_epoch, list);
-	if (prev == epoch || prev == mdev->current_epoch)
-		prev = NULL;
-	spin_unlock(&mdev->epoch_lock);
-	return prev;
-}
 
 #define GFP_TRY	(__GFP_HIGHMEM | __GFP_NOWARN)
 
@@ -241,7 +225,7 @@
 	spin_unlock_irq(&mdev->req_lock);
 
 	list_for_each_entry_safe(e, t, &reclaimed, w.list)
-		drbd_free_ee(mdev, e);
+		drbd_free_net_ee(mdev, e);
 }
 
 /**
@@ -298,9 +282,11 @@
  * Is also used from inside an other spin_lock_irq(&mdev->req_lock);
  * Either links the page chain back to the global pool,
  * or returns all pages to the system. */
-static void drbd_pp_free(struct drbd_conf *mdev, struct page *page)
+static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net)
 {
+	atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use;
 	int i;
+
 	if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count)
 		i = page_chain_free(page);
 	else {
@@ -311,10 +297,10 @@
 		drbd_pp_vacant += i;
 		spin_unlock(&drbd_pp_lock);
 	}
-	atomic_sub(i, &mdev->pp_in_use);
-	i = atomic_read(&mdev->pp_in_use);
+	i = atomic_sub_return(i, a);
 	if (i < 0)
-		dev_warn(DEV, "ASSERTION FAILED: pp_in_use: %d < 0\n", i);
+		dev_warn(DEV, "ASSERTION FAILED: %s: %d < 0\n",
+			is_net ? "pp_in_use_by_net" : "pp_in_use", i);
 	wake_up(&drbd_pp_wait);
 }
 
@@ -365,7 +351,6 @@
 	e->size = data_size;
 	e->flags = 0;
 	e->sector = sector;
-	e->sector = sector;
 	e->block_id = id;
 
 	return e;
@@ -375,9 +360,11 @@
 	return NULL;
 }
 
-void drbd_free_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
+void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int is_net)
 {
-	drbd_pp_free(mdev, e->pages);
+	if (e->flags & EE_HAS_DIGEST)
+		kfree(e->digest);
+	drbd_pp_free(mdev, e->pages, is_net);
 	D_ASSERT(atomic_read(&e->pending_bios) == 0);
 	D_ASSERT(hlist_unhashed(&e->colision));
 	mempool_free(e, drbd_ee_mempool);
@@ -388,13 +375,14 @@
 	LIST_HEAD(work_list);
 	struct drbd_epoch_entry *e, *t;
 	int count = 0;
+	int is_net = list == &mdev->net_ee;
 
 	spin_lock_irq(&mdev->req_lock);
 	list_splice_init(list, &work_list);
 	spin_unlock_irq(&mdev->req_lock);
 
 	list_for_each_entry_safe(e, t, &work_list, w.list) {
-		drbd_free_ee(mdev, e);
+		drbd_free_some_ee(mdev, e, is_net);
 		count++;
 	}
 	return count;
@@ -423,7 +411,7 @@
 	spin_unlock_irq(&mdev->req_lock);
 
 	list_for_each_entry_safe(e, t, &reclaimed, w.list)
-		drbd_free_ee(mdev, e);
+		drbd_free_net_ee(mdev, e);
 
 	/* possible callbacks here:
 	 * e_end_block, and e_end_resync_block, e_send_discard_ack.
@@ -719,14 +707,14 @@
 static int drbd_send_fp(struct drbd_conf *mdev,
 	struct socket *sock, enum drbd_packets cmd)
 {
-	struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+	struct p_header80 *h = &mdev->data.sbuf.header.h80;
 
 	return _drbd_send_cmd(mdev, sock, cmd, h, sizeof(*h), 0);
 }
 
 static enum drbd_packets drbd_recv_fp(struct drbd_conf *mdev, struct socket *sock)
 {
-	struct p_header *h = (struct p_header *) &mdev->data.sbuf.header;
+	struct p_header80 *h = &mdev->data.rbuf.header.h80;
 	int rr;
 
 	rr = drbd_recv_short(mdev, sock, h, sizeof(*h), 0);
@@ -776,9 +764,6 @@
 
 	D_ASSERT(!mdev->data.socket);
 
-	if (test_and_clear_bit(CREATE_BARRIER, &mdev->flags))
-		dev_err(DEV, "CREATE_BARRIER flag was set in drbd_connect - now cleared!\n");
-
 	if (drbd_request_state(mdev, NS(conn, C_WF_CONNECTION)) < SS_SUCCESS)
 		return -2;
 
@@ -927,6 +912,11 @@
 
 	drbd_thread_start(&mdev->asender);
 
+	if (mdev->agreed_pro_version < 95 && get_ldev(mdev)) {
+		drbd_setup_queue_param(mdev, DRBD_MAX_SIZE_H80_PACKET);
+		put_ldev(mdev);
+	}
+
 	if (!drbd_send_protocol(mdev))
 		return -1;
 	drbd_send_sync_param(mdev, &mdev->sync_conf);
@@ -946,22 +936,28 @@
 	return -1;
 }
 
-static int drbd_recv_header(struct drbd_conf *mdev, struct p_header *h)
+static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsigned int *packet_size)
 {
+	union p_header *h = &mdev->data.rbuf.header;
 	int r;
 
 	r = drbd_recv(mdev, h, sizeof(*h));
-
 	if (unlikely(r != sizeof(*h))) {
 		dev_err(DEV, "short read expecting header on sock: r=%d\n", r);
 		return FALSE;
-	};
-	h->command = be16_to_cpu(h->command);
-	h->length  = be16_to_cpu(h->length);
-	if (unlikely(h->magic != BE_DRBD_MAGIC)) {
-		dev_err(DEV, "magic?? on data m: 0x%lx c: %d l: %d\n",
-		    (long)be32_to_cpu(h->magic),
-		    h->command, h->length);
+	}
+
+	if (likely(h->h80.magic == BE_DRBD_MAGIC)) {
+		*cmd = be16_to_cpu(h->h80.command);
+		*packet_size = be16_to_cpu(h->h80.length);
+	} else if (h->h95.magic == BE_DRBD_MAGIC_BIG) {
+		*cmd = be16_to_cpu(h->h95.command);
+		*packet_size = be32_to_cpu(h->h95.length);
+	} else {
+		dev_err(DEV, "magic?? on data m: 0x%08x c: %d l: %d\n",
+		    be32_to_cpu(h->h80.magic),
+		    be16_to_cpu(h->h80.command),
+		    be16_to_cpu(h->h80.length));
 		return FALSE;
 	}
 	mdev->last_received = jiffies;
@@ -969,13 +965,13 @@
 	return TRUE;
 }
 
-static enum finish_epoch drbd_flush_after_epoch(struct drbd_conf *mdev, struct drbd_epoch *epoch)
+static void drbd_flush(struct drbd_conf *mdev)
 {
 	int rv;
 
 	if (mdev->write_ordering >= WO_bdev_flush && get_ldev(mdev)) {
 		rv = blkdev_issue_flush(mdev->ldev->backing_bdev, GFP_KERNEL,
-					NULL, BLKDEV_IFL_WAIT);
+					NULL);
 		if (rv) {
 			dev_err(DEV, "local disk flush failed with status %d\n", rv);
 			/* would rather check on EOPNOTSUPP, but that is not reliable.
@@ -985,24 +981,6 @@
 		}
 		put_ldev(mdev);
 	}
-
-	return drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
-}
-
-static int w_flush(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
-	struct flush_work *fw = (struct flush_work *)w;
-	struct drbd_epoch *epoch = fw->epoch;
-
-	kfree(w);
-
-	if (!test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags))
-		drbd_flush_after_epoch(mdev, epoch);
-
-	drbd_may_finish_epoch(mdev, epoch, EV_PUT |
-			      (mdev->state.conn < C_CONNECTED ? EV_CLEANUP : 0));
-
-	return 1;
 }
 
 /**
@@ -1015,15 +993,13 @@
 					       struct drbd_epoch *epoch,
 					       enum epoch_event ev)
 {
-	int finish, epoch_size;
+	int epoch_size;
 	struct drbd_epoch *next_epoch;
-	int schedule_flush = 0;
 	enum finish_epoch rv = FE_STILL_LIVE;
 
 	spin_lock(&mdev->epoch_lock);
 	do {
 		next_epoch = NULL;
-		finish = 0;
 
 		epoch_size = atomic_read(&epoch->epoch_size);
 
@@ -1033,16 +1009,6 @@
 			break;
 		case EV_GOT_BARRIER_NR:
 			set_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags);
-
-			/* Special case: If we just switched from WO_bio_barrier to
-			   WO_bdev_flush we should not finish the current epoch */
-			if (test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags) && epoch_size == 1 &&
-			    mdev->write_ordering != WO_bio_barrier &&
-			    epoch == mdev->current_epoch)
-				clear_bit(DE_CONTAINS_A_BARRIER, &epoch->flags);
-			break;
-		case EV_BARRIER_DONE:
-			set_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags);
 			break;
 		case EV_BECAME_LAST:
 			/* nothing to do*/
@@ -1051,23 +1017,7 @@
 
 		if (epoch_size != 0 &&
 		    atomic_read(&epoch->active) == 0 &&
-		    test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags) &&
-		    epoch->list.prev == &mdev->current_epoch->list &&
-		    !test_bit(DE_IS_FINISHING, &epoch->flags)) {
-			/* Nearly all conditions are met to finish that epoch... */
-			if (test_bit(DE_BARRIER_IN_NEXT_EPOCH_DONE, &epoch->flags) ||
-			    mdev->write_ordering == WO_none ||
-			    (epoch_size == 1 && test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) ||
-			    ev & EV_CLEANUP) {
-				finish = 1;
-				set_bit(DE_IS_FINISHING, &epoch->flags);
-			} else if (!test_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags) &&
-				 mdev->write_ordering == WO_bio_barrier) {
-				atomic_inc(&epoch->active);
-				schedule_flush = 1;
-			}
-		}
-		if (finish) {
+		    test_bit(DE_HAVE_BARRIER_NUMBER, &epoch->flags)) {
 			if (!(ev & EV_CLEANUP)) {
 				spin_unlock(&mdev->epoch_lock);
 				drbd_send_b_ack(mdev, epoch->barrier_nr, epoch_size);
@@ -1090,6 +1040,7 @@
 				/* atomic_set(&epoch->active, 0); is already zero */
 				if (rv == FE_STILL_LIVE)
 					rv = FE_RECYCLED;
+				wake_up(&mdev->ee_wait);
 			}
 		}
 
@@ -1101,22 +1052,6 @@
 
 	spin_unlock(&mdev->epoch_lock);
 
-	if (schedule_flush) {
-		struct flush_work *fw;
-		fw = kmalloc(sizeof(*fw), GFP_ATOMIC);
-		if (fw) {
-			fw->w.cb = w_flush;
-			fw->epoch = epoch;
-			drbd_queue_work(&mdev->data.work, &fw->w);
-		} else {
-			dev_warn(DEV, "Could not kmalloc a flush_work obj\n");
-			set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
-			/* That is not a recursion, only one level */
-			drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE);
-			drbd_may_finish_epoch(mdev, epoch, EV_PUT);
-		}
-	}
-
 	return rv;
 }
 
@@ -1132,19 +1067,16 @@
 		[WO_none] = "none",
 		[WO_drain_io] = "drain",
 		[WO_bdev_flush] = "flush",
-		[WO_bio_barrier] = "barrier",
 	};
 
 	pwo = mdev->write_ordering;
 	wo = min(pwo, wo);
-	if (wo == WO_bio_barrier && mdev->ldev->dc.no_disk_barrier)
-		wo = WO_bdev_flush;
 	if (wo == WO_bdev_flush && mdev->ldev->dc.no_disk_flush)
 		wo = WO_drain_io;
 	if (wo == WO_drain_io && mdev->ldev->dc.no_disk_drain)
 		wo = WO_none;
 	mdev->write_ordering = wo;
-	if (pwo != mdev->write_ordering || wo == WO_bio_barrier)
+	if (pwo != mdev->write_ordering || wo == WO_bdev_flush)
 		dev_info(DEV, "Method to ensure write ordering: %s\n", write_ordering_str[mdev->write_ordering]);
 }
 
@@ -1180,7 +1112,7 @@
 	bio->bi_sector = sector;
 	bio->bi_bdev = mdev->ldev->backing_bdev;
 	/* we special case some flags in the multi-bio case, see below
-	 * (REQ_UNPLUG, REQ_HARDBARRIER) */
+	 * (REQ_UNPLUG) */
 	bio->bi_rw = rw;
 	bio->bi_private = e;
 	bio->bi_end_io = drbd_endio_sec;
@@ -1214,11 +1146,6 @@
 			bio->bi_rw &= ~REQ_UNPLUG;
 
 		drbd_generic_make_request(mdev, fault_type, bio);
-
-		/* strip off REQ_HARDBARRIER,
-		 * unless it is the first or last bio */
-		if (bios && bios->bi_next)
-			bios->bi_rw &= ~REQ_HARDBARRIER;
 	} while (bios);
 	maybe_kick_lo(mdev);
 	return 0;
@@ -1232,53 +1159,12 @@
 	return -ENOMEM;
 }
 
-/**
- * w_e_reissue() - Worker callback; Resubmit a bio, without REQ_HARDBARRIER set
- * @mdev:	DRBD device.
- * @w:		work object.
- * @cancel:	The connection will be closed anyways (unused in this callback)
- */
-int w_e_reissue(struct drbd_conf *mdev, struct drbd_work *w, int cancel) __releases(local)
-{
-	struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
-	/* We leave DE_CONTAINS_A_BARRIER and EE_IS_BARRIER in place,
-	   (and DE_BARRIER_IN_NEXT_EPOCH_ISSUED in the previous Epoch)
-	   so that we can finish that epoch in drbd_may_finish_epoch().
-	   That is necessary if we already have a long chain of Epochs, before
-	   we realize that REQ_HARDBARRIER is actually not supported */
-
-	/* As long as the -ENOTSUPP on the barrier is reported immediately
-	   that will never trigger. If it is reported late, we will just
-	   print that warning and continue correctly for all future requests
-	   with WO_bdev_flush */
-	if (previous_epoch(mdev, e->epoch))
-		dev_warn(DEV, "Write ordering was not enforced (one time event)\n");
-
-	/* we still have a local reference,
-	 * get_ldev was done in receive_Data. */
-
-	e->w.cb = e_end_block;
-	if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_DT_WR) != 0) {
-		/* drbd_submit_ee fails for one reason only:
-		 * if was not able to allocate sufficient bios.
-		 * requeue, try again later. */
-		e->w.cb = w_e_reissue;
-		drbd_queue_work(&mdev->data.work, &e->w);
-	}
-	return 1;
-}
-
-static int receive_Barrier(struct drbd_conf *mdev, struct p_header *h)
+static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	int rv, issue_flush;
-	struct p_barrier *p = (struct p_barrier *)h;
+	int rv;
+	struct p_barrier *p = &mdev->data.rbuf.barrier;
 	struct drbd_epoch *epoch;
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
-
-	rv = drbd_recv(mdev, h->payload, h->length);
-	ERR_IF(rv != h->length) return FALSE;
-
 	inc_unacked(mdev);
 
 	if (mdev->net_conf->wire_protocol != DRBD_PROT_C)
@@ -1293,44 +1179,40 @@
 	 * Therefore we must send the barrier_ack after the barrier request was
 	 * completed. */
 	switch (mdev->write_ordering) {
-	case WO_bio_barrier:
 	case WO_none:
 		if (rv == FE_RECYCLED)
 			return TRUE;
-		break;
+
+		/* receiver context, in the writeout path of the other node.
+		 * avoid potential distributed deadlock */
+		epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+		if (epoch)
+			break;
+		else
+			dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
+			/* Fall through */
 
 	case WO_bdev_flush:
 	case WO_drain_io:
-		if (rv == FE_STILL_LIVE) {
-			set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
-			drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
-			rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
-		}
-		if (rv == FE_RECYCLED)
-			return TRUE;
-
-		/* The asender will send all the ACKs and barrier ACKs out, since
-		   all EEs moved from the active_ee to the done_ee. We need to
-		   provide a new epoch object for the EEs that come in soon */
-		break;
-	}
-
-	/* receiver context, in the writeout path of the other node.
-	 * avoid potential distributed deadlock */
-	epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
-	if (!epoch) {
-		dev_warn(DEV, "Allocation of an epoch failed, slowing down\n");
-		issue_flush = !test_and_set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &mdev->current_epoch->flags);
 		drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
-		if (issue_flush) {
-			rv = drbd_flush_after_epoch(mdev, mdev->current_epoch);
-			if (rv == FE_RECYCLED)
-				return TRUE;
+		drbd_flush(mdev);
+
+		if (atomic_read(&mdev->current_epoch->epoch_size)) {
+			epoch = kmalloc(sizeof(struct drbd_epoch), GFP_NOIO);
+			if (epoch)
+				break;
 		}
 
-		drbd_wait_ee_list_empty(mdev, &mdev->done_ee);
+		epoch = mdev->current_epoch;
+		wait_event(mdev->ee_wait, atomic_read(&epoch->epoch_size) == 0);
+
+		D_ASSERT(atomic_read(&epoch->active) == 0);
+		D_ASSERT(epoch->flags == 0);
 
 		return TRUE;
+	default:
+		dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering);
+		return FALSE;
 	}
 
 	epoch->flags = 0;
@@ -1457,7 +1339,7 @@
 		data_size -= rr;
 	}
 	kunmap(page);
-	drbd_pp_free(mdev, page);
+	drbd_pp_free(mdev, page, 0);
 	return rv;
 }
 
@@ -1562,30 +1444,29 @@
 	list_add(&e->w.list, &mdev->sync_ee);
 	spin_unlock_irq(&mdev->req_lock);
 
+	atomic_add(data_size >> 9, &mdev->rs_sect_ev);
 	if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0)
 		return TRUE;
 
+	/* drbd_submit_ee currently fails for one reason only:
+	 * not being able to allocate enough bios.
+	 * Is dropping the connection going to help? */
+	spin_lock_irq(&mdev->req_lock);
+	list_del(&e->w.list);
+	spin_unlock_irq(&mdev->req_lock);
+
 	drbd_free_ee(mdev, e);
 fail:
 	put_ldev(mdev);
 	return FALSE;
 }
 
-static int receive_DataReply(struct drbd_conf *mdev, struct p_header *h)
+static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	struct drbd_request *req;
 	sector_t sector;
-	unsigned int header_size, data_size;
 	int ok;
-	struct p_data *p = (struct p_data *)h;
-
-	header_size = sizeof(*p) - sizeof(*h);
-	data_size   = h->length  - header_size;
-
-	ERR_IF(data_size == 0) return FALSE;
-
-	if (drbd_recv(mdev, h->payload, header_size) != header_size)
-		return FALSE;
+	struct p_data *p = &mdev->data.rbuf.data;
 
 	sector = be64_to_cpu(p->sector);
 
@@ -1611,20 +1492,11 @@
 	return ok;
 }
 
-static int receive_RSDataReply(struct drbd_conf *mdev, struct p_header *h)
+static int receive_RSDataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	sector_t sector;
-	unsigned int header_size, data_size;
 	int ok;
-	struct p_data *p = (struct p_data *)h;
-
-	header_size = sizeof(*p) - sizeof(*h);
-	data_size   = h->length  - header_size;
-
-	ERR_IF(data_size == 0) return FALSE;
-
-	if (drbd_recv(mdev, h->payload, header_size) != header_size)
-		return FALSE;
+	struct p_data *p = &mdev->data.rbuf.data;
 
 	sector = be64_to_cpu(p->sector);
 	D_ASSERT(p->block_id == ID_SYNCER);
@@ -1640,9 +1512,11 @@
 
 		ok = drbd_drain_block(mdev, data_size);
 
-		drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+		drbd_send_ack_dp(mdev, P_NEG_ACK, p, data_size);
 	}
 
+	atomic_add(data_size >> 9, &mdev->rs_sect_in);
+
 	return ok;
 }
 
@@ -1653,15 +1527,8 @@
 {
 	struct drbd_epoch_entry *e = (struct drbd_epoch_entry *)w;
 	sector_t sector = e->sector;
-	struct drbd_epoch *epoch;
 	int ok = 1, pcmd;
 
-	if (e->flags & EE_IS_BARRIER) {
-		epoch = previous_epoch(mdev, e->epoch);
-		if (epoch)
-			drbd_may_finish_epoch(mdev, epoch, EV_BARRIER_DONE + (cancel ? EV_CLEANUP : 0));
-	}
-
 	if (mdev->net_conf->wire_protocol == DRBD_PROT_C) {
 		if (likely((e->flags & EE_WAS_ERROR) == 0)) {
 			pcmd = (mdev->state.conn >= C_SYNC_SOURCE &&
@@ -1765,24 +1632,27 @@
 	return ret;
 }
 
+static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf)
+{
+	if (mdev->agreed_pro_version >= 95)
+		return  (dpf & DP_RW_SYNC ? REQ_SYNC : 0) |
+			(dpf & DP_UNPLUG ? REQ_UNPLUG : 0) |
+			(dpf & DP_FUA ? REQ_FUA : 0) |
+			(dpf & DP_FLUSH ? REQ_FUA : 0) |
+			(dpf & DP_DISCARD ? REQ_DISCARD : 0);
+	else
+		return dpf & DP_RW_SYNC ? (REQ_SYNC | REQ_UNPLUG) : 0;
+}
+
 /* mirrored write */
-static int receive_Data(struct drbd_conf *mdev, struct p_header *h)
+static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	sector_t sector;
 	struct drbd_epoch_entry *e;
-	struct p_data *p = (struct p_data *)h;
-	int header_size, data_size;
+	struct p_data *p = &mdev->data.rbuf.data;
 	int rw = WRITE;
 	u32 dp_flags;
 
-	header_size = sizeof(*p) - sizeof(*h);
-	data_size   = h->length  - header_size;
-
-	ERR_IF(data_size == 0) return FALSE;
-
-	if (drbd_recv(mdev, h->payload, header_size) != header_size)
-		return FALSE;
-
 	if (!get_ldev(mdev)) {
 		if (__ratelimit(&drbd_ratelimit_state))
 			dev_err(DEV, "Can not write mirrored data block "
@@ -1792,7 +1662,7 @@
 			mdev->peer_seq++;
 		spin_unlock(&mdev->peer_seq_lock);
 
-		drbd_send_ack_dp(mdev, P_NEG_ACK, p);
+		drbd_send_ack_dp(mdev, P_NEG_ACK, p, data_size);
 		atomic_inc(&mdev->current_epoch->epoch_size);
 		return drbd_drain_block(mdev, data_size);
 	}
@@ -1815,36 +1685,11 @@
 	e->epoch = mdev->current_epoch;
 	atomic_inc(&e->epoch->epoch_size);
 	atomic_inc(&e->epoch->active);
-
-	if (mdev->write_ordering == WO_bio_barrier && atomic_read(&e->epoch->epoch_size) == 1) {
-		struct drbd_epoch *epoch;
-		/* Issue a barrier if we start a new epoch, and the previous epoch
-		   was not a epoch containing a single request which already was
-		   a Barrier. */
-		epoch = list_entry(e->epoch->list.prev, struct drbd_epoch, list);
-		if (epoch == e->epoch) {
-			set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
-			rw |= REQ_HARDBARRIER;
-			e->flags |= EE_IS_BARRIER;
-		} else {
-			if (atomic_read(&epoch->epoch_size) > 1 ||
-			    !test_bit(DE_CONTAINS_A_BARRIER, &epoch->flags)) {
-				set_bit(DE_BARRIER_IN_NEXT_EPOCH_ISSUED, &epoch->flags);
-				set_bit(DE_CONTAINS_A_BARRIER, &e->epoch->flags);
-				rw |= REQ_HARDBARRIER;
-				e->flags |= EE_IS_BARRIER;
-			}
-		}
-	}
 	spin_unlock(&mdev->epoch_lock);
 
 	dp_flags = be32_to_cpu(p->dp_flags);
-	if (dp_flags & DP_HARDBARRIER) {
-		dev_err(DEV, "ASSERT FAILED would have submitted barrier request\n");
-		/* rw |= REQ_HARDBARRIER; */
-	}
-	if (dp_flags & DP_RW_SYNC)
-		rw |= REQ_SYNC | REQ_UNPLUG;
+	rw |= write_flags_to_bio(mdev, dp_flags);
+
 	if (dp_flags & DP_MAY_SET_IN_SYNC)
 		e->flags |= EE_MAY_SET_IN_SYNC;
 
@@ -1997,16 +1842,27 @@
 		break;
 	}
 
-	if (mdev->state.pdsk == D_DISKLESS) {
+	if (mdev->state.pdsk < D_INCONSISTENT) {
 		/* In case we have the only disk of the cluster, */
 		drbd_set_out_of_sync(mdev, e->sector, e->size);
 		e->flags |= EE_CALL_AL_COMPLETE_IO;
+		e->flags &= ~EE_MAY_SET_IN_SYNC;
 		drbd_al_begin_io(mdev, e->sector);
 	}
 
 	if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0)
 		return TRUE;
 
+	/* drbd_submit_ee currently fails for one reason only:
+	 * not being able to allocate enough bios.
+	 * Is dropping the connection going to help? */
+	spin_lock_irq(&mdev->req_lock);
+	list_del(&e->w.list);
+	hlist_del_init(&e->colision);
+	spin_unlock_irq(&mdev->req_lock);
+	if (e->flags & EE_CALL_AL_COMPLETE_IO)
+		drbd_al_complete_io(mdev, e->sector);
+
 out_interrupted:
 	/* yes, the epoch_size now is imbalanced.
 	 * but we drop the connection anyways, so we don't have a chance to
@@ -2016,20 +1872,64 @@
 	return FALSE;
 }
 
-static int receive_DataRequest(struct drbd_conf *mdev, struct p_header *h)
+/* We may throttle resync, if the lower device seems to be busy,
+ * and current sync rate is above c_min_rate.
+ *
+ * To decide whether or not the lower device is busy, we use a scheme similar
+ * to MD RAID is_mddev_idle(): if the partition stats reveal "significant"
+ * (more than 64 sectors) of activity we cannot account for with our own resync
+ * activity, it obviously is "busy".
+ *
+ * The current sync rate used here uses only the most recent two step marks,
+ * to have a short time average so we can react faster.
+ */
+int drbd_rs_should_slow_down(struct drbd_conf *mdev)
+{
+	struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk;
+	unsigned long db, dt, dbdt;
+	int curr_events;
+	int throttle = 0;
+
+	/* feature disabled? */
+	if (mdev->sync_conf.c_min_rate == 0)
+		return 0;
+
+	curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
+		      (int)part_stat_read(&disk->part0, sectors[1]) -
+			atomic_read(&mdev->rs_sect_ev);
+	if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) {
+		unsigned long rs_left;
+		int i;
+
+		mdev->rs_last_events = curr_events;
+
+		/* sync speed average over the last 2*DRBD_SYNC_MARK_STEP,
+		 * approx. */
+		i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-2) % DRBD_SYNC_MARKS;
+		rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed;
+
+		dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ;
+		if (!dt)
+			dt++;
+		db = mdev->rs_mark_left[i] - rs_left;
+		dbdt = Bit2KB(db/dt);
+
+		if (dbdt > mdev->sync_conf.c_min_rate)
+			throttle = 1;
+	}
+	return throttle;
+}
+
+
+static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int digest_size)
 {
 	sector_t sector;
 	const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
 	struct drbd_epoch_entry *e;
 	struct digest_info *di = NULL;
-	int size, digest_size;
+	int size, verb;
 	unsigned int fault_type;
-	struct p_block_req *p =
-		(struct p_block_req *)h;
-	const int brps = sizeof(*p)-sizeof(*h);
-
-	if (drbd_recv(mdev, h->payload, brps) != brps)
-		return FALSE;
+	struct p_block_req *p =	&mdev->data.rbuf.block_req;
 
 	sector = be64_to_cpu(p->sector);
 	size   = be32_to_cpu(p->blksize);
@@ -2046,12 +1946,31 @@
 	}
 
 	if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) {
-		if (__ratelimit(&drbd_ratelimit_state))
+		verb = 1;
+		switch (cmd) {
+		case P_DATA_REQUEST:
+			drbd_send_ack_rp(mdev, P_NEG_DREPLY, p);
+			break;
+		case P_RS_DATA_REQUEST:
+		case P_CSUM_RS_REQUEST:
+		case P_OV_REQUEST:
+			drbd_send_ack_rp(mdev, P_NEG_RS_DREPLY , p);
+			break;
+		case P_OV_REPLY:
+			verb = 0;
+			dec_rs_pending(mdev);
+			drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size, ID_IN_SYNC);
+			break;
+		default:
+			dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n",
+				cmdname(cmd));
+		}
+		if (verb && __ratelimit(&drbd_ratelimit_state))
 			dev_err(DEV, "Can not satisfy peer's read request, "
 			    "no local data.\n");
-		drbd_send_ack_rp(mdev, h->command == P_DATA_REQUEST ? P_NEG_DREPLY :
-				 P_NEG_RS_DREPLY , p);
-		return drbd_drain_block(mdev, h->length - brps);
+
+		/* drain possibly payload */
+		return drbd_drain_block(mdev, digest_size);
 	}
 
 	/* GFP_NOIO, because we must not cause arbitrary write-out: in a DRBD
@@ -2063,31 +1982,21 @@
 		return FALSE;
 	}
 
-	switch (h->command) {
+	switch (cmd) {
 	case P_DATA_REQUEST:
 		e->w.cb = w_e_end_data_req;
 		fault_type = DRBD_FAULT_DT_RD;
-		break;
+		/* application IO, don't drbd_rs_begin_io */
+		goto submit;
+
 	case P_RS_DATA_REQUEST:
 		e->w.cb = w_e_end_rsdata_req;
 		fault_type = DRBD_FAULT_RS_RD;
-		/* Eventually this should become asynchronously. Currently it
-		 * blocks the whole receiver just to delay the reading of a
-		 * resync data block.
-		 * the drbd_work_queue mechanism is made for this...
-		 */
-		if (!drbd_rs_begin_io(mdev, sector)) {
-			/* we have been interrupted,
-			 * probably connection lost! */
-			D_ASSERT(signal_pending(current));
-			goto out_free_e;
-		}
 		break;
 
 	case P_OV_REPLY:
 	case P_CSUM_RS_REQUEST:
 		fault_type = DRBD_FAULT_RS_RD;
-		digest_size = h->length - brps ;
 		di = kmalloc(sizeof(*di) + digest_size, GFP_NOIO);
 		if (!di)
 			goto out_free_e;
@@ -2095,31 +2004,25 @@
 		di->digest_size = digest_size;
 		di->digest = (((char *)di)+sizeof(struct digest_info));
 
+		e->digest = di;
+		e->flags |= EE_HAS_DIGEST;
+
 		if (drbd_recv(mdev, di->digest, digest_size) != digest_size)
 			goto out_free_e;
 
-		e->block_id = (u64)(unsigned long)di;
-		if (h->command == P_CSUM_RS_REQUEST) {
+		if (cmd == P_CSUM_RS_REQUEST) {
 			D_ASSERT(mdev->agreed_pro_version >= 89);
 			e->w.cb = w_e_end_csum_rs_req;
-		} else if (h->command == P_OV_REPLY) {
+		} else if (cmd == P_OV_REPLY) {
 			e->w.cb = w_e_end_ov_reply;
 			dec_rs_pending(mdev);
-			break;
-		}
-
-		if (!drbd_rs_begin_io(mdev, sector)) {
-			/* we have been interrupted, probably connection lost! */
-			D_ASSERT(signal_pending(current));
-			goto out_free_e;
+			/* drbd_rs_begin_io done when we sent this request,
+			 * but accounting still needs to be done. */
+			goto submit_for_resync;
 		}
 		break;
 
 	case P_OV_REQUEST:
-		if (mdev->state.conn >= C_CONNECTED &&
-		    mdev->state.conn != C_VERIFY_T)
-			dev_warn(DEV, "ASSERT FAILED: got P_OV_REQUEST while being %s\n",
-				drbd_conn_str(mdev->state.conn));
 		if (mdev->ov_start_sector == ~(sector_t)0 &&
 		    mdev->agreed_pro_version >= 90) {
 			mdev->ov_start_sector = sector;
@@ -2130,37 +2033,63 @@
 		}
 		e->w.cb = w_e_end_ov_req;
 		fault_type = DRBD_FAULT_RS_RD;
-		/* Eventually this should become asynchronous. Currently it
-		 * blocks the whole receiver just to delay the reading of a
-		 * resync data block.
-		 * the drbd_work_queue mechanism is made for this...
-		 */
-		if (!drbd_rs_begin_io(mdev, sector)) {
-			/* we have been interrupted,
-			 * probably connection lost! */
-			D_ASSERT(signal_pending(current));
-			goto out_free_e;
-		}
 		break;
 
-
 	default:
 		dev_err(DEV, "unexpected command (%s) in receive_DataRequest\n",
-		    cmdname(h->command));
+		    cmdname(cmd));
 		fault_type = DRBD_FAULT_MAX;
+		goto out_free_e;
 	}
 
-	spin_lock_irq(&mdev->req_lock);
-	list_add(&e->w.list, &mdev->read_ee);
-	spin_unlock_irq(&mdev->req_lock);
+	/* Throttle, drbd_rs_begin_io and submit should become asynchronous
+	 * wrt the receiver, but it is not as straightforward as it may seem.
+	 * Various places in the resync start and stop logic assume resync
+	 * requests are processed in order, requeuing this on the worker thread
+	 * introduces a bunch of new code for synchronization between threads.
+	 *
+	 * Unlimited throttling before drbd_rs_begin_io may stall the resync
+	 * "forever", throttling after drbd_rs_begin_io will lock that extent
+	 * for application writes for the same time.  For now, just throttle
+	 * here, where the rest of the code expects the receiver to sleep for
+	 * a while, anyways.
+	 */
 
+	/* Throttle before drbd_rs_begin_io, as that locks out application IO;
+	 * this defers syncer requests for some time, before letting at least
+	 * on request through.  The resync controller on the receiving side
+	 * will adapt to the incoming rate accordingly.
+	 *
+	 * We cannot throttle here if remote is Primary/SyncTarget:
+	 * we would also throttle its application reads.
+	 * In that case, throttling is done on the SyncTarget only.
+	 */
+	if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev))
+		msleep(100);
+	if (drbd_rs_begin_io(mdev, e->sector))
+		goto out_free_e;
+
+submit_for_resync:
+	atomic_add(size >> 9, &mdev->rs_sect_ev);
+
+submit:
 	inc_unacked(mdev);
+	spin_lock_irq(&mdev->req_lock);
+	list_add_tail(&e->w.list, &mdev->read_ee);
+	spin_unlock_irq(&mdev->req_lock);
 
 	if (drbd_submit_ee(mdev, e, READ, fault_type) == 0)
 		return TRUE;
 
+	/* drbd_submit_ee currently fails for one reason only:
+	 * not being able to allocate enough bios.
+	 * Is dropping the connection going to help? */
+	spin_lock_irq(&mdev->req_lock);
+	list_del(&e->w.list);
+	spin_unlock_irq(&mdev->req_lock);
+	/* no drbd_rs_complete_io(), we are dropping the connection anyways */
+
 out_free_e:
-	kfree(di);
 	put_ldev(mdev);
 	drbd_free_ee(mdev, e);
 	return FALSE;
@@ -2699,20 +2628,13 @@
 	return 1;
 }
 
-static int receive_protocol(struct drbd_conf *mdev, struct p_header *h)
+static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_protocol *p = (struct p_protocol *)h;
-	int header_size, data_size;
+	struct p_protocol *p = &mdev->data.rbuf.protocol;
 	int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
 	int p_want_lose, p_two_primaries, cf;
 	char p_integrity_alg[SHARED_SECRET_MAX] = "";
 
-	header_size = sizeof(*p) - sizeof(*h);
-	data_size   = h->length  - header_size;
-
-	if (drbd_recv(mdev, h->payload, header_size) != header_size)
-		return FALSE;
-
 	p_proto		= be32_to_cpu(p->protocol);
 	p_after_sb_0p	= be32_to_cpu(p->after_sb_0p);
 	p_after_sb_1p	= be32_to_cpu(p->after_sb_1p);
@@ -2805,39 +2727,46 @@
 	return tfm;
 }
 
-static int receive_SyncParam(struct drbd_conf *mdev, struct p_header *h)
+static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size)
 {
 	int ok = TRUE;
-	struct p_rs_param_89 *p = (struct p_rs_param_89 *)h;
+	struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95;
 	unsigned int header_size, data_size, exp_max_sz;
 	struct crypto_hash *verify_tfm = NULL;
 	struct crypto_hash *csums_tfm = NULL;
 	const int apv = mdev->agreed_pro_version;
+	int *rs_plan_s = NULL;
+	int fifo_size = 0;
 
 	exp_max_sz  = apv <= 87 ? sizeof(struct p_rs_param)
 		    : apv == 88 ? sizeof(struct p_rs_param)
 					+ SHARED_SECRET_MAX
-		    : /* 89 */    sizeof(struct p_rs_param_89);
+		    : apv <= 94 ? sizeof(struct p_rs_param_89)
+		    : /* apv >= 95 */ sizeof(struct p_rs_param_95);
 
-	if (h->length > exp_max_sz) {
+	if (packet_size > exp_max_sz) {
 		dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n",
-		    h->length, exp_max_sz);
+		    packet_size, exp_max_sz);
 		return FALSE;
 	}
 
 	if (apv <= 88) {
-		header_size = sizeof(struct p_rs_param) - sizeof(*h);
-		data_size   = h->length  - header_size;
-	} else /* apv >= 89 */ {
-		header_size = sizeof(struct p_rs_param_89) - sizeof(*h);
-		data_size   = h->length  - header_size;
+		header_size = sizeof(struct p_rs_param) - sizeof(struct p_header80);
+		data_size   = packet_size  - header_size;
+	} else if (apv <= 94) {
+		header_size = sizeof(struct p_rs_param_89) - sizeof(struct p_header80);
+		data_size   = packet_size  - header_size;
+		D_ASSERT(data_size == 0);
+	} else {
+		header_size = sizeof(struct p_rs_param_95) - sizeof(struct p_header80);
+		data_size   = packet_size  - header_size;
 		D_ASSERT(data_size == 0);
 	}
 
 	/* initialize verify_alg and csums_alg */
 	memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX);
 
-	if (drbd_recv(mdev, h->payload, header_size) != header_size)
+	if (drbd_recv(mdev, &p->head.payload, header_size) != header_size)
 		return FALSE;
 
 	mdev->sync_conf.rate	  = be32_to_cpu(p->rate);
@@ -2896,6 +2825,22 @@
 			}
 		}
 
+		if (apv > 94) {
+			mdev->sync_conf.rate	  = be32_to_cpu(p->rate);
+			mdev->sync_conf.c_plan_ahead = be32_to_cpu(p->c_plan_ahead);
+			mdev->sync_conf.c_delay_target = be32_to_cpu(p->c_delay_target);
+			mdev->sync_conf.c_fill_target = be32_to_cpu(p->c_fill_target);
+			mdev->sync_conf.c_max_rate = be32_to_cpu(p->c_max_rate);
+
+			fifo_size = (mdev->sync_conf.c_plan_ahead * 10 * SLEEP_TIME) / HZ;
+			if (fifo_size != mdev->rs_plan_s.size && fifo_size > 0) {
+				rs_plan_s   = kzalloc(sizeof(int) * fifo_size, GFP_KERNEL);
+				if (!rs_plan_s) {
+					dev_err(DEV, "kmalloc of fifo_buffer failed");
+					goto disconnect;
+				}
+			}
+		}
 
 		spin_lock(&mdev->peer_seq_lock);
 		/* lock against drbd_nl_syncer_conf() */
@@ -2913,6 +2858,12 @@
 			mdev->csums_tfm = csums_tfm;
 			dev_info(DEV, "using csums-alg: \"%s\"\n", p->csums_alg);
 		}
+		if (fifo_size != mdev->rs_plan_s.size) {
+			kfree(mdev->rs_plan_s.values);
+			mdev->rs_plan_s.values = rs_plan_s;
+			mdev->rs_plan_s.size   = fifo_size;
+			mdev->rs_planed = 0;
+		}
 		spin_unlock(&mdev->peer_seq_lock);
 	}
 
@@ -2946,19 +2897,15 @@
 		     (unsigned long long)a, (unsigned long long)b);
 }
 
-static int receive_sizes(struct drbd_conf *mdev, struct p_header *h)
+static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_sizes *p = (struct p_sizes *)h;
+	struct p_sizes *p = &mdev->data.rbuf.sizes;
 	enum determine_dev_size dd = unchanged;
 	unsigned int max_seg_s;
 	sector_t p_size, p_usize, my_usize;
 	int ldsc = 0; /* local disk size changed */
 	enum dds_flags ddsf;
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
-	if (drbd_recv(mdev, h->payload, h->length) != h->length)
-		return FALSE;
-
 	p_size = be64_to_cpu(p->d_size);
 	p_usize = be64_to_cpu(p->u_size);
 
@@ -2972,7 +2919,6 @@
 	 * we still need to figure out whether we accept that. */
 	mdev->p_size = p_size;
 
-#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
 	if (get_ldev(mdev)) {
 		warn_if_differ_considerably(mdev, "lower level device sizes",
 			   p_size, drbd_get_max_capacity(mdev->ldev));
@@ -3029,6 +2975,8 @@
 
 		if (mdev->agreed_pro_version < 94)
 			max_seg_s = be32_to_cpu(p->max_segment_size);
+		else if (mdev->agreed_pro_version == 94)
+			max_seg_s = DRBD_MAX_SIZE_H80_PACKET;
 		else /* drbd 8.3.8 onwards */
 			max_seg_s = DRBD_MAX_SEGMENT_SIZE;
 
@@ -3062,16 +3010,12 @@
 	return TRUE;
 }
 
-static int receive_uuids(struct drbd_conf *mdev, struct p_header *h)
+static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_uuids *p = (struct p_uuids *)h;
+	struct p_uuids *p = &mdev->data.rbuf.uuids;
 	u64 *p_uuid;
 	int i;
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
-	if (drbd_recv(mdev, h->payload, h->length) != h->length)
-		return FALSE;
-
 	p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO);
 
 	for (i = UI_CURRENT; i < UI_EXTENDED_SIZE; i++)
@@ -3107,6 +3051,11 @@
 			drbd_md_sync(mdev);
 		}
 		put_ldev(mdev);
+	} else if (mdev->state.disk < D_INCONSISTENT &&
+		   mdev->state.role == R_PRIMARY) {
+		/* I am a diskless primary, the peer just created a new current UUID
+		   for me. */
+		drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]);
 	}
 
 	/* Before we test for the disk state, we should wait until an eventually
@@ -3150,16 +3099,12 @@
 	return ms;
 }
 
-static int receive_req_state(struct drbd_conf *mdev, struct p_header *h)
+static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_req_state *p = (struct p_req_state *)h;
+	struct p_req_state *p = &mdev->data.rbuf.req_state;
 	union drbd_state mask, val;
 	int rv;
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
-	if (drbd_recv(mdev, h->payload, h->length) != h->length)
-		return FALSE;
-
 	mask.i = be32_to_cpu(p->mask);
 	val.i = be32_to_cpu(p->val);
 
@@ -3180,20 +3125,14 @@
 	return TRUE;
 }
 
-static int receive_state(struct drbd_conf *mdev, struct p_header *h)
+static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_state *p = (struct p_state *)h;
-	enum drbd_conns nconn, oconn;
-	union drbd_state ns, peer_state;
+	struct p_state *p = &mdev->data.rbuf.state;
+	union drbd_state os, ns, peer_state;
 	enum drbd_disk_state real_peer_disk;
+	enum chg_state_flags cs_flags;
 	int rv;
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h)))
-		return FALSE;
-
-	if (drbd_recv(mdev, h->payload, h->length) != h->length)
-		return FALSE;
-
 	peer_state.i = be32_to_cpu(p->state);
 
 	real_peer_disk = peer_state.disk;
@@ -3204,40 +3143,74 @@
 
 	spin_lock_irq(&mdev->req_lock);
  retry:
-	oconn = nconn = mdev->state.conn;
+	os = ns = mdev->state;
 	spin_unlock_irq(&mdev->req_lock);
 
-	if (nconn == C_WF_REPORT_PARAMS)
-		nconn = C_CONNECTED;
+	/* peer says his disk is uptodate, while we think it is inconsistent,
+	 * and this happens while we think we have a sync going on. */
+	if (os.pdsk == D_INCONSISTENT && real_peer_disk == D_UP_TO_DATE &&
+	    os.conn > C_CONNECTED && os.disk == D_UP_TO_DATE) {
+		/* If we are (becoming) SyncSource, but peer is still in sync
+		 * preparation, ignore its uptodate-ness to avoid flapping, it
+		 * will change to inconsistent once the peer reaches active
+		 * syncing states.
+		 * It may have changed syncer-paused flags, however, so we
+		 * cannot ignore this completely. */
+		if (peer_state.conn > C_CONNECTED &&
+		    peer_state.conn < C_SYNC_SOURCE)
+			real_peer_disk = D_INCONSISTENT;
+
+		/* if peer_state changes to connected at the same time,
+		 * it explicitly notifies us that it finished resync.
+		 * Maybe we should finish it up, too? */
+		else if (os.conn >= C_SYNC_SOURCE &&
+			 peer_state.conn == C_CONNECTED) {
+			if (drbd_bm_total_weight(mdev) <= mdev->rs_failed)
+				drbd_resync_finished(mdev);
+			return TRUE;
+		}
+	}
+
+	/* peer says his disk is inconsistent, while we think it is uptodate,
+	 * and this happens while the peer still thinks we have a sync going on,
+	 * but we think we are already done with the sync.
+	 * We ignore this to avoid flapping pdsk.
+	 * This should not happen, if the peer is a recent version of drbd. */
+	if (os.pdsk == D_UP_TO_DATE && real_peer_disk == D_INCONSISTENT &&
+	    os.conn == C_CONNECTED && peer_state.conn > C_SYNC_SOURCE)
+		real_peer_disk = D_UP_TO_DATE;
+
+	if (ns.conn == C_WF_REPORT_PARAMS)
+		ns.conn = C_CONNECTED;
 
 	if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING &&
 	    get_ldev_if_state(mdev, D_NEGOTIATING)) {
 		int cr; /* consider resync */
 
 		/* if we established a new connection */
-		cr  = (oconn < C_CONNECTED);
+		cr  = (os.conn < C_CONNECTED);
 		/* if we had an established connection
 		 * and one of the nodes newly attaches a disk */
-		cr |= (oconn == C_CONNECTED &&
+		cr |= (os.conn == C_CONNECTED &&
 		       (peer_state.disk == D_NEGOTIATING ||
-			mdev->state.disk == D_NEGOTIATING));
+			os.disk == D_NEGOTIATING));
 		/* if we have both been inconsistent, and the peer has been
 		 * forced to be UpToDate with --overwrite-data */
 		cr |= test_bit(CONSIDER_RESYNC, &mdev->flags);
 		/* if we had been plain connected, and the admin requested to
 		 * start a sync by "invalidate" or "invalidate-remote" */
-		cr |= (oconn == C_CONNECTED &&
+		cr |= (os.conn == C_CONNECTED &&
 				(peer_state.conn >= C_STARTING_SYNC_S &&
 				 peer_state.conn <= C_WF_BITMAP_T));
 
 		if (cr)
-			nconn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
+			ns.conn = drbd_sync_handshake(mdev, peer_state.role, real_peer_disk);
 
 		put_ldev(mdev);
-		if (nconn == C_MASK) {
-			nconn = C_CONNECTED;
+		if (ns.conn == C_MASK) {
+			ns.conn = C_CONNECTED;
 			if (mdev->state.disk == D_NEGOTIATING) {
-				drbd_force_state(mdev, NS(disk, D_DISKLESS));
+				drbd_force_state(mdev, NS(disk, D_FAILED));
 			} else if (peer_state.disk == D_NEGOTIATING) {
 				dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
 				peer_state.disk = D_DISKLESS;
@@ -3245,7 +3218,7 @@
 			} else {
 				if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags))
 					return FALSE;
-				D_ASSERT(oconn == C_WF_REPORT_PARAMS);
+				D_ASSERT(os.conn == C_WF_REPORT_PARAMS);
 				drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
 				return FALSE;
 			}
@@ -3253,18 +3226,28 @@
 	}
 
 	spin_lock_irq(&mdev->req_lock);
-	if (mdev->state.conn != oconn)
+	if (mdev->state.i != os.i)
 		goto retry;
 	clear_bit(CONSIDER_RESYNC, &mdev->flags);
-	ns.i = mdev->state.i;
-	ns.conn = nconn;
 	ns.peer = peer_state.role;
 	ns.pdsk = real_peer_disk;
 	ns.peer_isp = (peer_state.aftr_isp | peer_state.user_isp);
-	if ((nconn == C_CONNECTED || nconn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
+	if ((ns.conn == C_CONNECTED || ns.conn == C_WF_BITMAP_S) && ns.disk == D_NEGOTIATING)
 		ns.disk = mdev->new_state_tmp.disk;
-
-	rv = _drbd_set_state(mdev, ns, CS_VERBOSE | CS_HARD, NULL);
+	cs_flags = CS_VERBOSE + (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED ? 0 : CS_HARD);
+	if (ns.pdsk == D_CONSISTENT && is_susp(ns) && ns.conn == C_CONNECTED && os.conn < C_CONNECTED &&
+	    test_bit(NEW_CUR_UUID, &mdev->flags)) {
+		/* Do not allow tl_restart(resend) for a rebooted peer. We can only allow this
+		   for temporal network outages! */
+		spin_unlock_irq(&mdev->req_lock);
+		dev_err(DEV, "Aborting Connect, can not thaw IO with an only Consistent peer\n");
+		tl_clear(mdev);
+		drbd_uuid_new_current(mdev);
+		clear_bit(NEW_CUR_UUID, &mdev->flags);
+		drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0));
+		return FALSE;
+	}
+	rv = _drbd_set_state(mdev, ns, cs_flags, NULL);
 	ns = mdev->state;
 	spin_unlock_irq(&mdev->req_lock);
 
@@ -3273,8 +3256,8 @@
 		return FALSE;
 	}
 
-	if (oconn > C_WF_REPORT_PARAMS) {
-		if (nconn > C_CONNECTED && peer_state.conn <= C_CONNECTED &&
+	if (os.conn > C_WF_REPORT_PARAMS) {
+		if (ns.conn > C_CONNECTED && peer_state.conn <= C_CONNECTED &&
 		    peer_state.disk != D_NEGOTIATING ) {
 			/* we want resync, peer has not yet decided to sync... */
 			/* Nowadays only used when forcing a node into primary role and
@@ -3291,9 +3274,9 @@
 	return TRUE;
 }
 
-static int receive_sync_uuid(struct drbd_conf *mdev, struct p_header *h)
+static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
-	struct p_rs_uuid *p = (struct p_rs_uuid *)h;
+	struct p_rs_uuid *p = &mdev->data.rbuf.rs_uuid;
 
 	wait_event(mdev->misc_wait,
 		   mdev->state.conn == C_WF_SYNC_UUID ||
@@ -3302,10 +3285,6 @@
 
 	/* D_ASSERT( mdev->state.conn == C_WF_SYNC_UUID ); */
 
-	ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE;
-	if (drbd_recv(mdev, h->payload, h->length) != h->length)
-		return FALSE;
-
 	/* Here the _drbd_uuid_ functions are right, current should
 	   _not_ be rotated into the history */
 	if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
@@ -3324,14 +3303,14 @@
 enum receive_bitmap_ret { OK, DONE, FAILED };
 
 static enum receive_bitmap_ret
-receive_bitmap_plain(struct drbd_conf *mdev, struct p_header *h,
-	unsigned long *buffer, struct bm_xfer_ctx *c)
+receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size,
+		     unsigned long *buffer, struct bm_xfer_ctx *c)
 {
 	unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset);
 	unsigned want = num_words * sizeof(long);
 
-	if (want != h->length) {
-		dev_err(DEV, "%s:want (%u) != h->length (%u)\n", __func__, want, h->length);
+	if (want != data_size) {
+		dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size);
 		return FAILED;
 	}
 	if (want == 0)
@@ -3360,7 +3339,7 @@
 	u64 tmp;
 	unsigned long s = c->bit_offset;
 	unsigned long e;
-	int len = p->head.length - (sizeof(*p) - sizeof(p->head));
+	int len = be16_to_cpu(p->head.length) - (sizeof(*p) - sizeof(p->head));
 	int toggle = DCBP_get_start(p);
 	int have;
 	int bits;
@@ -3429,7 +3408,7 @@
 		const char *direction, struct bm_xfer_ctx *c)
 {
 	/* what would it take to transfer it "plaintext" */
-	unsigned plain = sizeof(struct p_header) *
+	unsigned plain = sizeof(struct p_header80) *
 		((c->bm_words+BM_PACKET_WORDS-1)/BM_PACKET_WORDS+1)
 		+ c->bm_words * sizeof(long);
 	unsigned total = c->bytes[0] + c->bytes[1];
@@ -3467,12 +3446,13 @@
    in order to be agnostic to the 32 vs 64 bits issue.
 
    returns 0 on failure, 1 if we successfully received it. */
-static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h)
+static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	struct bm_xfer_ctx c;
 	void *buffer;
 	enum receive_bitmap_ret ret;
 	int ok = FALSE;
+	struct p_header80 *h = &mdev->data.rbuf.header.h80;
 
 	wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
 
@@ -3492,39 +3472,39 @@
 	};
 
 	do {
-		if (h->command == P_BITMAP) {
-			ret = receive_bitmap_plain(mdev, h, buffer, &c);
-		} else if (h->command == P_COMPRESSED_BITMAP) {
+		if (cmd == P_BITMAP) {
+			ret = receive_bitmap_plain(mdev, data_size, buffer, &c);
+		} else if (cmd == P_COMPRESSED_BITMAP) {
 			/* MAYBE: sanity check that we speak proto >= 90,
 			 * and the feature is enabled! */
 			struct p_compressed_bm *p;
 
-			if (h->length > BM_PACKET_PAYLOAD_BYTES) {
+			if (data_size > BM_PACKET_PAYLOAD_BYTES) {
 				dev_err(DEV, "ReportCBitmap packet too large\n");
 				goto out;
 			}
 			/* use the page buff */
 			p = buffer;
 			memcpy(p, h, sizeof(*h));
-			if (drbd_recv(mdev, p->head.payload, h->length) != h->length)
+			if (drbd_recv(mdev, p->head.payload, data_size) != data_size)
 				goto out;
-			if (p->head.length <= (sizeof(*p) - sizeof(p->head))) {
-				dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", p->head.length);
+			if (data_size <= (sizeof(*p) - sizeof(p->head))) {
+				dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size);
 				return FAILED;
 			}
 			ret = decode_bitmap_c(mdev, p, &c);
 		} else {
-			dev_warn(DEV, "receive_bitmap: h->command neither ReportBitMap nor ReportCBitMap (is 0x%x)", h->command);
+			dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd);
 			goto out;
 		}
 
-		c.packets[h->command == P_BITMAP]++;
-		c.bytes[h->command == P_BITMAP] += sizeof(struct p_header) + h->length;
+		c.packets[cmd == P_BITMAP]++;
+		c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size;
 
 		if (ret != OK)
 			break;
 
-		if (!drbd_recv_header(mdev, h))
+		if (!drbd_recv_header(mdev, &cmd, &data_size))
 			goto out;
 	} while (ret == OK);
 	if (ret == FAILED)
@@ -3555,17 +3535,16 @@
 	return ok;
 }
 
-static int receive_skip_(struct drbd_conf *mdev, struct p_header *h, int silent)
+static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	/* TODO zero copy sink :) */
 	static char sink[128];
 	int size, want, r;
 
-	if (!silent)
-		dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
-		     h->command, h->length);
+	dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n",
+		 cmd, data_size);
 
-	size = h->length;
+	size = data_size;
 	while (size > 0) {
 		want = min_t(int, size, sizeof(sink));
 		r = drbd_recv(mdev, sink, want);
@@ -3575,17 +3554,7 @@
 	return size == 0;
 }
 
-static int receive_skip(struct drbd_conf *mdev, struct p_header *h)
-{
-	return receive_skip_(mdev, h, 0);
-}
-
-static int receive_skip_silent(struct drbd_conf *mdev, struct p_header *h)
-{
-	return receive_skip_(mdev, h, 1);
-}
-
-static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h)
+static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size)
 {
 	if (mdev->state.disk >= D_INCONSISTENT)
 		drbd_kick_lo(mdev);
@@ -3597,108 +3566,96 @@
 	return TRUE;
 }
 
-typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *);
+typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive);
 
-static drbd_cmd_handler_f drbd_default_handler[] = {
-	[P_DATA]	    = receive_Data,
-	[P_DATA_REPLY]	    = receive_DataReply,
-	[P_RS_DATA_REPLY]   = receive_RSDataReply,
-	[P_BARRIER]	    = receive_Barrier,
-	[P_BITMAP]	    = receive_bitmap,
-	[P_COMPRESSED_BITMAP]    = receive_bitmap,
-	[P_UNPLUG_REMOTE]   = receive_UnplugRemote,
-	[P_DATA_REQUEST]    = receive_DataRequest,
-	[P_RS_DATA_REQUEST] = receive_DataRequest,
-	[P_SYNC_PARAM]	    = receive_SyncParam,
-	[P_SYNC_PARAM89]	   = receive_SyncParam,
-	[P_PROTOCOL]        = receive_protocol,
-	[P_UUIDS]	    = receive_uuids,
-	[P_SIZES]	    = receive_sizes,
-	[P_STATE]	    = receive_state,
-	[P_STATE_CHG_REQ]   = receive_req_state,
-	[P_SYNC_UUID]       = receive_sync_uuid,
-	[P_OV_REQUEST]      = receive_DataRequest,
-	[P_OV_REPLY]        = receive_DataRequest,
-	[P_CSUM_RS_REQUEST]    = receive_DataRequest,
-	[P_DELAY_PROBE]     = receive_skip_silent,
+struct data_cmd {
+	int expect_payload;
+	size_t pkt_size;
+	drbd_cmd_handler_f function;
+};
+
+static struct data_cmd drbd_cmd_handler[] = {
+	[P_DATA]	    = { 1, sizeof(struct p_data), receive_Data },
+	[P_DATA_REPLY]	    = { 1, sizeof(struct p_data), receive_DataReply },
+	[P_RS_DATA_REPLY]   = { 1, sizeof(struct p_data), receive_RSDataReply } ,
+	[P_BARRIER]	    = { 0, sizeof(struct p_barrier), receive_Barrier } ,
+	[P_BITMAP]	    = { 1, sizeof(struct p_header80), receive_bitmap } ,
+	[P_COMPRESSED_BITMAP] = { 1, sizeof(struct p_header80), receive_bitmap } ,
+	[P_UNPLUG_REMOTE]   = { 0, sizeof(struct p_header80), receive_UnplugRemote },
+	[P_DATA_REQUEST]    = { 0, sizeof(struct p_block_req), receive_DataRequest },
+	[P_RS_DATA_REQUEST] = { 0, sizeof(struct p_block_req), receive_DataRequest },
+	[P_SYNC_PARAM]	    = { 1, sizeof(struct p_header80), receive_SyncParam },
+	[P_SYNC_PARAM89]    = { 1, sizeof(struct p_header80), receive_SyncParam },
+	[P_PROTOCOL]        = { 1, sizeof(struct p_protocol), receive_protocol },
+	[P_UUIDS]	    = { 0, sizeof(struct p_uuids), receive_uuids },
+	[P_SIZES]	    = { 0, sizeof(struct p_sizes), receive_sizes },
+	[P_STATE]	    = { 0, sizeof(struct p_state), receive_state },
+	[P_STATE_CHG_REQ]   = { 0, sizeof(struct p_req_state), receive_req_state },
+	[P_SYNC_UUID]       = { 0, sizeof(struct p_rs_uuid), receive_sync_uuid },
+	[P_OV_REQUEST]      = { 0, sizeof(struct p_block_req), receive_DataRequest },
+	[P_OV_REPLY]        = { 1, sizeof(struct p_block_req), receive_DataRequest },
+	[P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest },
+	[P_DELAY_PROBE]     = { 0, sizeof(struct p_delay_probe93), receive_skip },
 	/* anything missing from this table is in
 	 * the asender_tbl, see get_asender_cmd */
-	[P_MAX_CMD]	    = NULL,
+	[P_MAX_CMD]	    = { 0, 0, NULL },
 };
 
-static drbd_cmd_handler_f *drbd_cmd_handler = drbd_default_handler;
-static drbd_cmd_handler_f *drbd_opt_cmd_handler;
+/* All handler functions that expect a sub-header get that sub-heder in
+   mdev->data.rbuf.header.head.payload.
+
+   Usually in mdev->data.rbuf.header.head the callback can find the usual
+   p_header, but they may not rely on that. Since there is also p_header95 !
+ */
 
 static void drbdd(struct drbd_conf *mdev)
 {
-	drbd_cmd_handler_f handler;
-	struct p_header *header = &mdev->data.rbuf.header;
+	union p_header *header = &mdev->data.rbuf.header;
+	unsigned int packet_size;
+	enum drbd_packets cmd;
+	size_t shs; /* sub header size */
+	int rv;
 
 	while (get_t_state(&mdev->receiver) == Running) {
 		drbd_thread_current_set_cpu(mdev);
-		if (!drbd_recv_header(mdev, header)) {
-			drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
-			break;
-		}
+		if (!drbd_recv_header(mdev, &cmd, &packet_size))
+			goto err_out;
 
-		if (header->command < P_MAX_CMD)
-			handler = drbd_cmd_handler[header->command];
-		else if (P_MAY_IGNORE < header->command
-		     && header->command < P_MAX_OPT_CMD)
-			handler = drbd_opt_cmd_handler[header->command-P_MAY_IGNORE];
-		else if (header->command > P_MAX_OPT_CMD)
-			handler = receive_skip;
-		else
-			handler = NULL;
+		if (unlikely(cmd >= P_MAX_CMD || !drbd_cmd_handler[cmd].function)) {
+			dev_err(DEV, "unknown packet type %d, l: %d!\n", cmd, packet_size);
+			goto err_out;
+		}
 
-		if (unlikely(!handler)) {
-			dev_err(DEV, "unknown packet type %d, l: %d!\n",
-			    header->command, header->length);
-			drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
-			break;
+		shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header);
+		if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) {
+			dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size);
+			goto err_out;
 		}
-		if (unlikely(!handler(mdev, header))) {
-			dev_err(DEV, "error receiving %s, l: %d!\n",
-			    cmdname(header->command), header->length);
-			drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
-			break;
+
+		if (shs) {
+			rv = drbd_recv(mdev, &header->h80.payload, shs);
+			if (unlikely(rv != shs)) {
+				dev_err(DEV, "short read while reading sub header: rv=%d\n", rv);
+				goto err_out;
+			}
 		}
-	}
-}
 
-static void drbd_fail_pending_reads(struct drbd_conf *mdev)
-{
-	struct hlist_head *slot;
-	struct hlist_node *pos;
-	struct hlist_node *tmp;
-	struct drbd_request *req;
-	int i;
+		rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs);
 
-	/*
-	 * Application READ requests
-	 */
-	spin_lock_irq(&mdev->req_lock);
-	for (i = 0; i < APP_R_HSIZE; i++) {
-		slot = mdev->app_reads_hash+i;
-		hlist_for_each_entry_safe(req, pos, tmp, slot, colision) {
-			/* it may (but should not any longer!)
-			 * be on the work queue; if that assert triggers,
-			 * we need to also grab the
-			 * spin_lock_irq(&mdev->data.work.q_lock);
-			 * and list_del_init here. */
-			D_ASSERT(list_empty(&req->w.list));
-			/* It would be nice to complete outside of spinlock.
-			 * But this is easier for now. */
-			_req_mod(req, connection_lost_while_pending);
+		if (unlikely(!rv)) {
+			dev_err(DEV, "error receiving %s, l: %d!\n",
+			    cmdname(cmd), packet_size);
+			goto err_out;
 		}
 	}
-	for (i = 0; i < APP_R_HSIZE; i++)
-		if (!hlist_empty(mdev->app_reads_hash+i))
-			dev_warn(DEV, "ASSERT FAILED: app_reads_hash[%d].first: "
-				"%p, should be NULL\n", i, mdev->app_reads_hash[i].first);
 
-	memset(mdev->app_reads_hash, 0, APP_R_HSIZE*sizeof(void *));
-	spin_unlock_irq(&mdev->req_lock);
+	if (0) {
+	err_out:
+		drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR));
+	}
+	/* If we leave here, we probably want to update at least the
+	 * "Connected" indicator on stable storage. Do so explicitly here. */
+	drbd_md_sync(mdev);
 }
 
 void drbd_flush_workqueue(struct drbd_conf *mdev)
@@ -3711,6 +3668,36 @@
 	wait_for_completion(&barr.done);
 }
 
+void drbd_free_tl_hash(struct drbd_conf *mdev)
+{
+	struct hlist_head *h;
+
+	spin_lock_irq(&mdev->req_lock);
+
+	if (!mdev->tl_hash || mdev->state.conn != C_STANDALONE) {
+		spin_unlock_irq(&mdev->req_lock);
+		return;
+	}
+	/* paranoia code */
+	for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
+		if (h->first)
+			dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
+				(int)(h - mdev->ee_hash), h->first);
+	kfree(mdev->ee_hash);
+	mdev->ee_hash = NULL;
+	mdev->ee_hash_s = 0;
+
+	/* paranoia code */
+	for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
+		if (h->first)
+			dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
+				(int)(h - mdev->tl_hash), h->first);
+	kfree(mdev->tl_hash);
+	mdev->tl_hash = NULL;
+	mdev->tl_hash_s = 0;
+	spin_unlock_irq(&mdev->req_lock);
+}
+
 static void drbd_disconnect(struct drbd_conf *mdev)
 {
 	enum drbd_fencing_p fp;
@@ -3728,6 +3715,7 @@
 	drbd_thread_stop(&mdev->asender);
 	drbd_free_sock(mdev);
 
+	/* wait for current activity to cease. */
 	spin_lock_irq(&mdev->req_lock);
 	_drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
 	_drbd_wait_ee_list_empty(mdev, &mdev->sync_ee);
@@ -3752,7 +3740,6 @@
 
 	/* make sure syncer is stopped and w_resume_next_sg queued */
 	del_timer_sync(&mdev->resync_timer);
-	set_bit(STOP_SYNC_TIMER, &mdev->flags);
 	resync_timer_fn((unsigned long)mdev);
 
 	/* wait for all w_e_end_data_req, w_e_end_rsdata_req, w_send_barrier,
@@ -3767,11 +3754,9 @@
 	kfree(mdev->p_uuid);
 	mdev->p_uuid = NULL;
 
-	if (!mdev->state.susp)
+	if (!is_susp(mdev->state))
 		tl_clear(mdev);
 
-	drbd_fail_pending_reads(mdev);
-
 	dev_info(DEV, "Connection closed\n");
 
 	drbd_md_sync(mdev);
@@ -3782,12 +3767,8 @@
 		put_ldev(mdev);
 	}
 
-	if (mdev->state.role == R_PRIMARY) {
-		if (fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) {
-			enum drbd_disk_state nps = drbd_try_outdate_peer(mdev);
-			drbd_request_state(mdev, NS(pdsk, nps));
-		}
-	}
+	if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN)
+		drbd_try_outdate_peer_async(mdev);
 
 	spin_lock_irq(&mdev->req_lock);
 	os = mdev->state;
@@ -3800,32 +3781,14 @@
 	spin_unlock_irq(&mdev->req_lock);
 
 	if (os.conn == C_DISCONNECTING) {
-		struct hlist_head *h;
-		wait_event(mdev->misc_wait, atomic_read(&mdev->net_cnt) == 0);
-
-		/* we must not free the tl_hash
-		 * while application io is still on the fly */
-		wait_event(mdev->misc_wait, atomic_read(&mdev->ap_bio_cnt) == 0);
-
-		spin_lock_irq(&mdev->req_lock);
-		/* paranoia code */
-		for (h = mdev->ee_hash; h < mdev->ee_hash + mdev->ee_hash_s; h++)
-			if (h->first)
-				dev_err(DEV, "ASSERT FAILED ee_hash[%u].first == %p, expected NULL\n",
-						(int)(h - mdev->ee_hash), h->first);
-		kfree(mdev->ee_hash);
-		mdev->ee_hash = NULL;
-		mdev->ee_hash_s = 0;
+		wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0);
 
-		/* paranoia code */
-		for (h = mdev->tl_hash; h < mdev->tl_hash + mdev->tl_hash_s; h++)
-			if (h->first)
-				dev_err(DEV, "ASSERT FAILED tl_hash[%u] == %p, expected NULL\n",
-						(int)(h - mdev->tl_hash), h->first);
-		kfree(mdev->tl_hash);
-		mdev->tl_hash = NULL;
-		mdev->tl_hash_s = 0;
-		spin_unlock_irq(&mdev->req_lock);
+		if (!is_susp(mdev->state)) {
+			/* we must not free the tl_hash
+			 * while application io is still on the fly */
+			wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt));
+			drbd_free_tl_hash(mdev);
+		}
 
 		crypto_free_hash(mdev->cram_hmac_tfm);
 		mdev->cram_hmac_tfm = NULL;
@@ -3845,6 +3808,9 @@
 	i = drbd_release_ee(mdev, &mdev->net_ee);
 	if (i)
 		dev_info(DEV, "net_ee not empty, killed %u entries\n", i);
+	i = atomic_read(&mdev->pp_in_use_by_net);
+	if (i)
+		dev_info(DEV, "pp_in_use_by_net = %d, expected 0\n", i);
 	i = atomic_read(&mdev->pp_in_use);
 	if (i)
 		dev_info(DEV, "pp_in_use = %d, expected 0\n", i);
@@ -3888,7 +3854,7 @@
 	p->protocol_min = cpu_to_be32(PRO_VERSION_MIN);
 	p->protocol_max = cpu_to_be32(PRO_VERSION_MAX);
 	ok = _drbd_send_cmd( mdev, mdev->data.socket, P_HAND_SHAKE,
-			     (struct p_header *)p, sizeof(*p), 0 );
+			     (struct p_header80 *)p, sizeof(*p), 0 );
 	mutex_unlock(&mdev->data.mutex);
 	return ok;
 }
@@ -3904,27 +3870,28 @@
 {
 	/* ASSERT current == mdev->receiver ... */
 	struct p_handshake *p = &mdev->data.rbuf.handshake;
-	const int expect = sizeof(struct p_handshake)
-			  -sizeof(struct p_header);
+	const int expect = sizeof(struct p_handshake) - sizeof(struct p_header80);
+	unsigned int length;
+	enum drbd_packets cmd;
 	int rv;
 
 	rv = drbd_send_handshake(mdev);
 	if (!rv)
 		return 0;
 
-	rv = drbd_recv_header(mdev, &p->head);
+	rv = drbd_recv_header(mdev, &cmd, &length);
 	if (!rv)
 		return 0;
 
-	if (p->head.command != P_HAND_SHAKE) {
+	if (cmd != P_HAND_SHAKE) {
 		dev_err(DEV, "expected HandShake packet, received: %s (0x%04x)\n",
-		     cmdname(p->head.command), p->head.command);
+		     cmdname(cmd), cmd);
 		return -1;
 	}
 
-	if (p->head.length != expect) {
+	if (length != expect) {
 		dev_err(DEV, "expected HandShake length: %u, received: %u\n",
-		     expect, p->head.length);
+		     expect, length);
 		return -1;
 	}
 
@@ -3982,10 +3949,11 @@
 	char *response = NULL;
 	char *right_response = NULL;
 	char *peers_ch = NULL;
-	struct p_header p;
 	unsigned int key_len = strlen(mdev->net_conf->shared_secret);
 	unsigned int resp_size;
 	struct hash_desc desc;
+	enum drbd_packets cmd;
+	unsigned int length;
 	int rv;
 
 	desc.tfm = mdev->cram_hmac_tfm;
@@ -4005,33 +3973,33 @@
 	if (!rv)
 		goto fail;
 
-	rv = drbd_recv_header(mdev, &p);
+	rv = drbd_recv_header(mdev, &cmd, &length);
 	if (!rv)
 		goto fail;
 
-	if (p.command != P_AUTH_CHALLENGE) {
+	if (cmd != P_AUTH_CHALLENGE) {
 		dev_err(DEV, "expected AuthChallenge packet, received: %s (0x%04x)\n",
-		    cmdname(p.command), p.command);
+		    cmdname(cmd), cmd);
 		rv = 0;
 		goto fail;
 	}
 
-	if (p.length > CHALLENGE_LEN*2) {
+	if (length > CHALLENGE_LEN * 2) {
 		dev_err(DEV, "expected AuthChallenge payload too big.\n");
 		rv = -1;
 		goto fail;
 	}
 
-	peers_ch = kmalloc(p.length, GFP_NOIO);
+	peers_ch = kmalloc(length, GFP_NOIO);
 	if (peers_ch == NULL) {
 		dev_err(DEV, "kmalloc of peers_ch failed\n");
 		rv = -1;
 		goto fail;
 	}
 
-	rv = drbd_recv(mdev, peers_ch, p.length);
+	rv = drbd_recv(mdev, peers_ch, length);
 
-	if (rv != p.length) {
+	if (rv != length) {
 		dev_err(DEV, "short read AuthChallenge: l=%u\n", rv);
 		rv = 0;
 		goto fail;
@@ -4046,7 +4014,7 @@
 	}
 
 	sg_init_table(&sg, 1);
-	sg_set_buf(&sg, peers_ch, p.length);
+	sg_set_buf(&sg, peers_ch, length);
 
 	rv = crypto_hash_digest(&desc, &sg, sg.length, response);
 	if (rv) {
@@ -4059,18 +4027,18 @@
 	if (!rv)
 		goto fail;
 
-	rv = drbd_recv_header(mdev, &p);
+	rv = drbd_recv_header(mdev, &cmd, &length);
 	if (!rv)
 		goto fail;
 
-	if (p.command != P_AUTH_RESPONSE) {
+	if (cmd != P_AUTH_RESPONSE) {
 		dev_err(DEV, "expected AuthResponse packet, received: %s (0x%04x)\n",
-		    cmdname(p.command), p.command);
+			cmdname(cmd), cmd);
 		rv = 0;
 		goto fail;
 	}
 
-	if (p.length != resp_size) {
+	if (length != resp_size) {
 		dev_err(DEV, "expected AuthResponse payload of wrong size\n");
 		rv = 0;
 		goto fail;
@@ -4155,7 +4123,7 @@
 
 /* ********* acknowledge sender ******** */
 
-static int got_RqSReply(struct drbd_conf *mdev, struct p_header *h)
+static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_req_state_reply *p = (struct p_req_state_reply *)h;
 
@@ -4173,13 +4141,13 @@
 	return TRUE;
 }
 
-static int got_Ping(struct drbd_conf *mdev, struct p_header *h)
+static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	return drbd_send_ping_ack(mdev);
 
 }
 
-static int got_PingAck(struct drbd_conf *mdev, struct p_header *h)
+static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	/* restore idle timeout */
 	mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
@@ -4189,7 +4157,7 @@
 	return TRUE;
 }
 
-static int got_IsInSync(struct drbd_conf *mdev, struct p_header *h)
+static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_block_ack *p = (struct p_block_ack *)h;
 	sector_t sector = be64_to_cpu(p->sector);
@@ -4199,11 +4167,15 @@
 
 	update_peer_seq(mdev, be32_to_cpu(p->seq_num));
 
-	drbd_rs_complete_io(mdev, sector);
-	drbd_set_in_sync(mdev, sector, blksize);
-	/* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
-	mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+	if (get_ldev(mdev)) {
+		drbd_rs_complete_io(mdev, sector);
+		drbd_set_in_sync(mdev, sector, blksize);
+		/* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */
+		mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT);
+		put_ldev(mdev);
+	}
 	dec_rs_pending(mdev);
+	atomic_add(blksize >> 9, &mdev->rs_sect_in);
 
 	return TRUE;
 }
@@ -4259,7 +4231,7 @@
 	return TRUE;
 }
 
-static int got_BlockAck(struct drbd_conf *mdev, struct p_header *h)
+static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_block_ack *p = (struct p_block_ack *)h;
 	sector_t sector = be64_to_cpu(p->sector);
@@ -4299,7 +4271,7 @@
 		_ack_id_to_req, __func__ , what);
 }
 
-static int got_NegAck(struct drbd_conf *mdev, struct p_header *h)
+static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_block_ack *p = (struct p_block_ack *)h;
 	sector_t sector = be64_to_cpu(p->sector);
@@ -4319,7 +4291,7 @@
 		_ack_id_to_req, __func__ , neg_acked);
 }
 
-static int got_NegDReply(struct drbd_conf *mdev, struct p_header *h)
+static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_block_ack *p = (struct p_block_ack *)h;
 	sector_t sector = be64_to_cpu(p->sector);
@@ -4332,7 +4304,7 @@
 		_ar_id_to_req, __func__ , neg_acked);
 }
 
-static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header *h)
+static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	sector_t sector;
 	int size;
@@ -4354,7 +4326,7 @@
 	return TRUE;
 }
 
-static int got_BarrierAck(struct drbd_conf *mdev, struct p_header *h)
+static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_barrier_ack *p = (struct p_barrier_ack *)h;
 
@@ -4363,7 +4335,7 @@
 	return TRUE;
 }
 
-static int got_OVResult(struct drbd_conf *mdev, struct p_header *h)
+static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h)
 {
 	struct p_block_ack *p = (struct p_block_ack *)h;
 	struct drbd_work *w;
@@ -4380,6 +4352,9 @@
 	else
 		ov_oos_print(mdev);
 
+	if (!get_ldev(mdev))
+		return TRUE;
+
 	drbd_rs_complete_io(mdev, sector);
 	dec_rs_pending(mdev);
 
@@ -4394,18 +4369,18 @@
 			drbd_resync_finished(mdev);
 		}
 	}
+	put_ldev(mdev);
 	return TRUE;
 }
 
-static int got_something_to_ignore_m(struct drbd_conf *mdev, struct p_header *h)
+static int got_skip(struct drbd_conf *mdev, struct p_header80 *h)
 {
-	/* IGNORE */
 	return TRUE;
 }
 
 struct asender_cmd {
 	size_t pkt_size;
-	int (*process)(struct drbd_conf *mdev, struct p_header *h);
+	int (*process)(struct drbd_conf *mdev, struct p_header80 *h);
 };
 
 static struct asender_cmd *get_asender_cmd(int cmd)
@@ -4414,8 +4389,8 @@
 		/* anything missing from this table is in
 		 * the drbd_cmd_handler (drbd_default_handler) table,
 		 * see the beginning of drbdd() */
-	[P_PING]	    = { sizeof(struct p_header), got_Ping },
-	[P_PING_ACK]	    = { sizeof(struct p_header), got_PingAck },
+	[P_PING]	    = { sizeof(struct p_header80), got_Ping },
+	[P_PING_ACK]	    = { sizeof(struct p_header80), got_PingAck },
 	[P_RECV_ACK]	    = { sizeof(struct p_block_ack), got_BlockAck },
 	[P_WRITE_ACK]	    = { sizeof(struct p_block_ack), got_BlockAck },
 	[P_RS_WRITE_ACK]    = { sizeof(struct p_block_ack), got_BlockAck },
@@ -4427,7 +4402,7 @@
 	[P_BARRIER_ACK]	    = { sizeof(struct p_barrier_ack), got_BarrierAck },
 	[P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply },
 	[P_RS_IS_IN_SYNC]   = { sizeof(struct p_block_ack), got_IsInSync },
-	[P_DELAY_PROBE]     = { sizeof(struct p_delay_probe), got_something_to_ignore_m },
+	[P_DELAY_PROBE]     = { sizeof(struct p_delay_probe93), got_skip },
 	[P_MAX_CMD]	    = { 0, NULL },
 	};
 	if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL)
@@ -4438,13 +4413,13 @@
 int drbd_asender(struct drbd_thread *thi)
 {
 	struct drbd_conf *mdev = thi->mdev;
-	struct p_header *h = &mdev->meta.rbuf.header;
+	struct p_header80 *h = &mdev->meta.rbuf.header.h80;
 	struct asender_cmd *cmd = NULL;
 
 	int rv, len;
 	void *buf    = h;
 	int received = 0;
-	int expect   = sizeof(struct p_header);
+	int expect   = sizeof(struct p_header80);
 	int empty;
 
 	sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
@@ -4468,10 +4443,8 @@
 		while (1) {
 			clear_bit(SIGNAL_ASENDER, &mdev->flags);
 			flush_signals(current);
-			if (!drbd_process_done_ee(mdev)) {
-				dev_err(DEV, "process_done_ee() = NOT_OK\n");
+			if (!drbd_process_done_ee(mdev))
 				goto reconnect;
-			}
 			/* to avoid race with newly queued ACKs */
 			set_bit(SIGNAL_ASENDER, &mdev->flags);
 			spin_lock_irq(&mdev->req_lock);
@@ -4530,21 +4503,23 @@
 
 		if (received == expect && cmd == NULL) {
 			if (unlikely(h->magic != BE_DRBD_MAGIC)) {
-				dev_err(DEV, "magic?? on meta m: 0x%lx c: %d l: %d\n",
-				    (long)be32_to_cpu(h->magic),
-				    h->command, h->length);
+				dev_err(DEV, "magic?? on meta m: 0x%08x c: %d l: %d\n",
+				    be32_to_cpu(h->magic),
+				    be16_to_cpu(h->command),
+				    be16_to_cpu(h->length));
 				goto reconnect;
 			}
 			cmd = get_asender_cmd(be16_to_cpu(h->command));
 			len = be16_to_cpu(h->length);
 			if (unlikely(cmd == NULL)) {
-				dev_err(DEV, "unknown command?? on meta m: 0x%lx c: %d l: %d\n",
-				    (long)be32_to_cpu(h->magic),
-				    h->command, h->length);
+				dev_err(DEV, "unknown command?? on meta m: 0x%08x c: %d l: %d\n",
+				    be32_to_cpu(h->magic),
+				    be16_to_cpu(h->command),
+				    be16_to_cpu(h->length));
 				goto disconnect;
 			}
 			expect = cmd->pkt_size;
-			ERR_IF(len != expect-sizeof(struct p_header))
+			ERR_IF(len != expect-sizeof(struct p_header80))
 				goto reconnect;
 		}
 		if (received == expect) {
@@ -4554,7 +4529,7 @@
 
 			buf	 = h;
 			received = 0;
-			expect	 = sizeof(struct p_header);
+			expect	 = sizeof(struct p_header80);
 			cmd	 = NULL;
 		}
 	}
@@ -4562,10 +4537,12 @@
 	if (0) {
 reconnect:
 		drbd_force_state(mdev, NS(conn, C_NETWORK_FAILURE));
+		drbd_md_sync(mdev);
 	}
 	if (0) {
 disconnect:
 		drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+		drbd_md_sync(mdev);
 	}
 	clear_bit(SIGNAL_ASENDER, &mdev->flags);
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_req.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_req.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_req.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_req.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,17 +59,19 @@
 static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const int rw)
 {
 	const unsigned long s = req->rq_state;
+
+	/* remove it from the transfer log.
+	 * well, only if it had been there in the first
+	 * place... if it had not (local only or conflicting
+	 * and never sent), it should still be "empty" as
+	 * initialized in drbd_req_new(), so we can list_del() it
+	 * here unconditionally */
+	list_del(&req->tl_requests);
+
 	/* if it was a write, we may have to set the corresponding
 	 * bit(s) out-of-sync first. If it had a local part, we need to
 	 * release the reference to the activity log. */
 	if (rw == WRITE) {
-		/* remove it from the transfer log.
-		 * well, only if it had been there in the first
-		 * place... if it had not (local only or conflicting
-		 * and never sent), it should still be "empty" as
-		 * initialized in drbd_req_new(), so we can list_del() it
-		 * here unconditionally */
-		list_del(&req->tl_requests);
 		/* Set out-of-sync unless both OK flags are set
 		 * (local only or remote failed).
 		 * Other places where we set out-of-sync:
@@ -92,7 +94,8 @@
 		 */
 		if (s & RQ_LOCAL_MASK) {
 			if (get_ldev_if_state(mdev, D_FAILED)) {
-				drbd_al_complete_io(mdev, req->sector);
+				if (s & RQ_IN_ACT_LOG)
+					drbd_al_complete_io(mdev, req->sector);
 				put_ldev(mdev);
 			} else if (__ratelimit(&drbd_ratelimit_state)) {
 				dev_warn(DEV, "Should have called drbd_al_complete_io(, %llu), "
@@ -255,7 +258,7 @@
 		if (!hlist_unhashed(&req->colision))
 			hlist_del(&req->colision);
 		else
-			D_ASSERT((s & RQ_NET_MASK) == 0);
+			D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
 
 		/* for writes we need to do some extra housekeeping */
 		if (rw == WRITE)
@@ -280,6 +283,14 @@
 	 * protocol A or B, barrier ack still pending... */
 }
 
+static void _req_may_be_done_not_susp(struct drbd_request *req, struct bio_and_error *m)
+{
+	struct drbd_conf *mdev = req->mdev;
+
+	if (!is_susp(mdev->state))
+		_req_may_be_done(req, m);
+}
+
 /*
  * checks whether there was an overlapping request
  * or ee already registered.
@@ -380,10 +391,11 @@
  *  and it enforces that we have to think in a very structured manner
  *  about the "events" that may happen to a request during its life time ...
  */
-void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		struct bio_and_error *m)
 {
 	struct drbd_conf *mdev = req->mdev;
+	int rv = 0;
 	m->bio = NULL;
 
 	switch (what) {
@@ -420,7 +432,7 @@
 		req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK);
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		put_ldev(mdev);
 		break;
 
@@ -429,7 +441,7 @@
 		req->rq_state &= ~RQ_LOCAL_PENDING;
 
 		__drbd_chk_io_error(mdev, FALSE);
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		put_ldev(mdev);
 		break;
 
@@ -437,7 +449,7 @@
 		/* it is legal to fail READA */
 		req->rq_state |= RQ_LOCAL_COMPLETED;
 		req->rq_state &= ~RQ_LOCAL_PENDING;
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		put_ldev(mdev);
 		break;
 
@@ -455,7 +467,7 @@
 		/* no point in retrying if there is no good remote data,
 		 * or we have no connection. */
 		if (mdev->state.pdsk != D_UP_TO_DATE) {
-			_req_may_be_done(req, m);
+			_req_may_be_done_not_susp(req, m);
 			break;
 		}
 
@@ -517,11 +529,9 @@
 		D_ASSERT(test_bit(CREATE_BARRIER, &mdev->flags) == 0);
 
 		req->epoch = mdev->newest_tle->br_number;
-		list_add_tail(&req->tl_requests,
-				&mdev->newest_tle->requests);
 
 		/* increment size of current epoch */
-		mdev->newest_tle->n_req++;
+		mdev->newest_tle->n_writes++;
 
 		/* queue work item to send data */
 		D_ASSERT(req->rq_state & RQ_NET_PENDING);
@@ -530,7 +540,7 @@
 		drbd_queue_work(&mdev->data.work, &req->w);
 
 		/* close the epoch, in case it outgrew the limit */
-		if (mdev->newest_tle->n_req >= mdev->net_conf->max_epoch_size)
+		if (mdev->newest_tle->n_writes >= mdev->net_conf->max_epoch_size)
 			queue_barrier(mdev);
 
 		break;
@@ -543,7 +553,7 @@
 		req->rq_state &= ~RQ_NET_QUEUED;
 		/* if we did it right, tl_clear should be scheduled only after
 		 * this, so this should not be necessary! */
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		break;
 
 	case handed_over_to_network:
@@ -568,7 +578,7 @@
 		 * "completed_ok" events came in, once we return from
 		 * _drbd_send_zc_bio (drbd_send_dblock), we have to check
 		 * whether it is done already, and end it.  */
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		break;
 
 	case read_retry_remote_canceled:
@@ -584,7 +594,7 @@
 		/* if it is still queued, we may not complete it here.
 		 * it will be canceled soon. */
 		if (!(req->rq_state & RQ_NET_QUEUED))
-			_req_may_be_done(req, m);
+			_req_may_be_done(req, m); /* Allowed while state.susp */
 		break;
 
 	case write_acked_by_peer_and_sis:
@@ -619,7 +629,7 @@
 		D_ASSERT(req->rq_state & RQ_NET_PENDING);
 		dec_ap_pending(mdev);
 		req->rq_state &= ~RQ_NET_PENDING;
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		break;
 
 	case neg_acked:
@@ -629,11 +639,50 @@
 		req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING);
 
 		req->rq_state |= RQ_NET_DONE;
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		/* else: done by handed_over_to_network */
 		break;
 
+	case fail_frozen_disk_io:
+		if (!(req->rq_state & RQ_LOCAL_COMPLETED))
+			break;
+
+		_req_may_be_done(req, m); /* Allowed while state.susp */
+		break;
+
+	case restart_frozen_disk_io:
+		if (!(req->rq_state & RQ_LOCAL_COMPLETED))
+			break;
+
+		req->rq_state &= ~RQ_LOCAL_COMPLETED;
+
+		rv = MR_READ;
+		if (bio_data_dir(req->master_bio) == WRITE)
+			rv = MR_WRITE;
+
+		get_ldev(mdev);
+		req->w.cb = w_restart_disk_io;
+		drbd_queue_work(&mdev->data.work, &req->w);
+		break;
+
+	case resend:
+		/* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK
+		   before the connection loss (B&C only); only P_BARRIER_ACK was missing.
+		   Trowing them out of the TL here by pretending we got a BARRIER_ACK
+		   We ensure that the peer was not rebooted */
+		if (!(req->rq_state & RQ_NET_OK)) {
+			if (req->w.cb) {
+				drbd_queue_work(&mdev->data.work, &req->w);
+				rv = req->rq_state & RQ_WRITE ? MR_WRITE : MR_READ;
+			}
+			break;
+		}
+		/* else, fall through to barrier_acked */
+
 	case barrier_acked:
+		if (!(req->rq_state & RQ_WRITE))
+			break;
+
 		if (req->rq_state & RQ_NET_PENDING) {
 			/* barrier came in before all requests have been acked.
 			 * this is bad, because if the connection is lost now,
@@ -643,7 +692,7 @@
 		}
 		D_ASSERT(req->rq_state & RQ_NET_SENT);
 		req->rq_state |= RQ_NET_DONE;
-		_req_may_be_done(req, m);
+		_req_may_be_done(req, m); /* Allowed while state.susp */
 		break;
 
 	case data_received:
@@ -651,9 +700,11 @@
 		dec_ap_pending(mdev);
 		req->rq_state &= ~RQ_NET_PENDING;
 		req->rq_state |= (RQ_NET_OK|RQ_NET_DONE);
-		_req_may_be_done(req, m);
+		_req_may_be_done_not_susp(req, m);
 		break;
 	};
+
+	return rv;
 }
 
 /* we may do a local read if:
@@ -752,15 +803,18 @@
 	 * resync extent to finish, and, if necessary, pulls in the target
 	 * extent into the activity log, which involves further disk io because
 	 * of transactional on-disk meta data updates. */
-	if (rw == WRITE && local)
+	if (rw == WRITE && local && !test_bit(AL_SUSPENDED, &mdev->flags)) {
+		req->rq_state |= RQ_IN_ACT_LOG;
 		drbd_al_begin_io(mdev, sector);
+	}
 
 	remote = remote && (mdev->state.pdsk == D_UP_TO_DATE ||
 			    (mdev->state.pdsk == D_INCONSISTENT &&
 			     mdev->state.conn >= C_CONNECTED));
 
-	if (!(local || remote) && !mdev->state.susp) {
-		dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
+	if (!(local || remote) && !is_susp(mdev->state)) {
+		if (__ratelimit(&drbd_ratelimit_state))
+			dev_err(DEV, "IO ERROR: neither local nor remote disk\n");
 		goto fail_free_complete;
 	}
 
@@ -785,7 +839,7 @@
 	/* GOOD, everything prepared, grab the spin_lock */
 	spin_lock_irq(&mdev->req_lock);
 
-	if (mdev->state.susp) {
+	if (is_susp(mdev->state)) {
 		/* If we got suspended, use the retry mechanism of
 		   generic_make_request() to restart processing of this
 		   bio. In the next call to drbd_make_request_26
@@ -867,30 +921,10 @@
 	/* check this request on the collision detection hash tables.
 	 * if we have a conflict, just complete it here.
 	 * THINK do we want to check reads, too? (I don't think so...) */
-	if (rw == WRITE && _req_conflicts(req)) {
-		/* this is a conflicting request.
-		 * even though it may have been only _partially_
-		 * overlapping with one of the currently pending requests,
-		 * without even submitting or sending it, we will
-		 * pretend that it was successfully served right now.
-		 */
-		if (local) {
-			bio_put(req->private_bio);
-			req->private_bio = NULL;
-			drbd_al_complete_io(mdev, req->sector);
-			put_ldev(mdev);
-			local = 0;
-		}
-		if (remote)
-			dec_ap_pending(mdev);
-		_drbd_end_io_acct(mdev, req);
-		/* THINK: do we want to fail it (-EIO), or pretend success? */
-		bio_endio(req->master_bio, 0);
-		req->master_bio = NULL;
-		dec_ap_bio(mdev);
-		drbd_req_free(req);
-		remote = 0;
-	}
+	if (rw == WRITE && _req_conflicts(req))
+		goto fail_conflicting;
+
+	list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
 
 	/* NOTE remote first: to get the concurrent write detection right,
 	 * we must register the request before start of local IO.  */
@@ -909,12 +943,21 @@
 	if (local) {
 		req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
 
-		if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
-				     : rw == READ  ? DRBD_FAULT_DT_RD
-				     :               DRBD_FAULT_DT_RA))
+		/* State may have changed since we grabbed our reference on the
+		 * mdev->ldev member. Double check, and short-circuit to endio.
+		 * In case the last activity log transaction failed to get on
+		 * stable storage, and this is a WRITE, we may not even submit
+		 * this bio. */
+		if (get_ldev(mdev)) {
+			if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR
+					     : rw == READ  ? DRBD_FAULT_DT_RD
+					     :               DRBD_FAULT_DT_RA))
+				bio_endio(req->private_bio, -EIO);
+			else
+				generic_make_request(req->private_bio);
+			put_ldev(mdev);
+		} else
 			bio_endio(req->private_bio, -EIO);
-		else
-			generic_make_request(req->private_bio);
 	}
 
 	/* we need to plug ALWAYS since we possibly need to kick lo_dev.
@@ -923,6 +966,21 @@
 
 	return 0;
 
+fail_conflicting:
+	/* this is a conflicting request.
+	 * even though it may have been only _partially_
+	 * overlapping with one of the currently pending requests,
+	 * without even submitting or sending it, we will
+	 * pretend that it was successfully served right now.
+	 */
+	_drbd_end_io_acct(mdev, req);
+	spin_unlock_irq(&mdev->req_lock);
+	if (remote)
+		dec_ap_pending(mdev);
+	/* THINK: do we want to fail it (-EIO), or pretend success?
+	 * this pretends success. */
+	err = 0;
+
 fail_free_complete:
 	if (rw == WRITE && local)
 		drbd_al_complete_io(mdev, sector);
@@ -961,21 +1019,6 @@
 		return 1;
 	}
 
-	/*
-	 * Paranoia: we might have been primary, but sync target, or
-	 * even diskless, then lost the connection.
-	 * This should have been handled (panic? suspend?) somewhere
-	 * else. But maybe it was not, so check again here.
-	 * Caution: as long as we do not have a read/write lock on mdev,
-	 * to serialize state changes, this is racy, since we may lose
-	 * the connection *after* we test for the cstate.
-	 */
-	if (mdev->state.disk < D_UP_TO_DATE && mdev->state.pdsk < D_UP_TO_DATE) {
-		if (__ratelimit(&drbd_ratelimit_state))
-			dev_err(DEV, "Sorry, I have no access to good data anymore.\n");
-		return 1;
-	}
-
 	return 0;
 }
 
@@ -989,20 +1032,6 @@
 		return 0;
 	}
 
-	/* Reject barrier requests if we know the underlying device does
-	 * not support them.
-	 * XXX: Need to get this info from peer as well some how so we
-	 * XXX: reject if EITHER side/data/metadata area does not support them.
-	 *
-	 * because of those XXX, this is not yet enabled,
-	 * i.e. in drbd_init_set_defaults we set the NO_BARRIER_SUPP bit.
-	 */
-	if (unlikely(bio->bi_rw & REQ_HARDBARRIER) && test_bit(NO_BARRIER_SUPP, &mdev->flags)) {
-		/* dev_warn(DEV, "Rejecting barrier request as underlying device does not support\n"); */
-		bio_endio(bio, -EOPNOTSUPP);
-		return 0;
-	}
-
 	/*
 	 * what we "blindly" assume:
 	 */
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_req.h linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_req.h
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_req.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_req.h	2011-01-04 19:50:19.000000000 -0500
@@ -104,6 +104,9 @@
 	read_ahead_completed_with_error,
 	write_completed_with_error,
 	completed_ok,
+	resend,
+	fail_frozen_disk_io,
+	restart_frozen_disk_io,
 	nothing, /* for tracing only */
 };
 
@@ -183,6 +186,12 @@
 
 	/* keep this last, its for the RQ_NET_MASK */
 	__RQ_NET_MAX,
+
+	/* Set when this is a write, clear for a read */
+	__RQ_WRITE,
+
+	/* Should call drbd_al_complete_io() for this request... */
+	__RQ_IN_ACT_LOG,
 };
 
 #define RQ_LOCAL_PENDING   (1UL << __RQ_LOCAL_PENDING)
@@ -201,6 +210,16 @@
 /* 0x1f8 */
 #define RQ_NET_MASK        (((1UL << __RQ_NET_MAX)-1) & ~RQ_LOCAL_MASK)
 
+#define RQ_WRITE           (1UL << __RQ_WRITE)
+#define RQ_IN_ACT_LOG      (1UL << __RQ_IN_ACT_LOG)
+
+/* For waking up the frozen transfer log mod_req() has to return if the request
+   should be counted in the epoch object*/
+#define MR_WRITE_SHIFT 0
+#define MR_WRITE       (1 << MR_WRITE_SHIFT)
+#define MR_READ_SHIFT  1
+#define MR_READ        (1 << MR_READ_SHIFT)
+
 /* epoch entries */
 static inline
 struct hlist_head *ee_hash_slot(struct drbd_conf *mdev, sector_t sector)
@@ -244,30 +263,36 @@
 	return NULL;
 }
 
+static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bio *bio_src)
+{
+	struct bio *bio;
+	bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
+
+	req->private_bio = bio;
+
+	bio->bi_private  = req;
+	bio->bi_end_io   = drbd_endio_pri;
+	bio->bi_next     = NULL;
+}
+
 static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
 	struct bio *bio_src)
 {
-	struct bio *bio;
 	struct drbd_request *req =
 		mempool_alloc(drbd_request_mempool, GFP_NOIO);
 	if (likely(req)) {
-		bio = bio_clone(bio_src, GFP_NOIO); /* XXX cannot fail?? */
+		drbd_req_make_private_bio(req, bio_src);
 
-		req->rq_state    = 0;
+		req->rq_state    = bio_data_dir(bio_src) == WRITE ? RQ_WRITE : 0;
 		req->mdev        = mdev;
 		req->master_bio  = bio_src;
-		req->private_bio = bio;
 		req->epoch       = 0;
-		req->sector      = bio->bi_sector;
-		req->size        = bio->bi_size;
+		req->sector      = bio_src->bi_sector;
+		req->size        = bio_src->bi_size;
 		req->start_time  = jiffies;
 		INIT_HLIST_NODE(&req->colision);
 		INIT_LIST_HEAD(&req->tl_requests);
 		INIT_LIST_HEAD(&req->w.list);
-
-		bio->bi_private  = req;
-		bio->bi_end_io   = drbd_endio_pri;
-		bio->bi_next     = NULL;
 	}
 	return req;
 }
@@ -292,36 +317,44 @@
 
 extern void _req_may_be_done(struct drbd_request *req,
 		struct bio_and_error *m);
-extern void __req_mod(struct drbd_request *req, enum drbd_req_event what,
+extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 		struct bio_and_error *m);
 extern void complete_master_bio(struct drbd_conf *mdev,
 		struct bio_and_error *m);
 
 /* use this if you don't want to deal with calling complete_master_bio()
  * outside the spinlock, e.g. when walking some list on cleanup. */
-static inline void _req_mod(struct drbd_request *req, enum drbd_req_event what)
+static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what)
 {
 	struct drbd_conf *mdev = req->mdev;
 	struct bio_and_error m;
+	int rv;
 
 	/* __req_mod possibly frees req, do not touch req after that! */
-	__req_mod(req, what, &m);
+	rv = __req_mod(req, what, &m);
 	if (m.bio)
 		complete_master_bio(mdev, &m);
+
+	return rv;
 }
 
 /* completion of master bio is outside of spinlock.
- * If you need it irqsave, do it your self! */
-static inline void req_mod(struct drbd_request *req,
+ * If you need it irqsave, do it your self!
+ * Which means: don't use from bio endio callback. */
+static inline int req_mod(struct drbd_request *req,
 		enum drbd_req_event what)
 {
 	struct drbd_conf *mdev = req->mdev;
 	struct bio_and_error m;
+	int rv;
+
 	spin_lock_irq(&mdev->req_lock);
-	__req_mod(req, what, &m);
+	rv = __req_mod(req, what, &m);
 	spin_unlock_irq(&mdev->req_lock);
 
 	if (m.bio)
 		complete_master_bio(mdev, &m);
+
+	return rv;
 }
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_worker.c linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_worker.c
--- linux-libre-2.6.36-gnu/drivers/block/drbd/drbd_worker.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/drbd/drbd_worker.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/drbd.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
 #include <linux/memcontrol.h>
@@ -39,8 +38,6 @@
 #include "drbd_int.h"
 #include "drbd_req.h"
 
-#define SLEEP_TIME (HZ/10)
-
 static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel);
 
 
@@ -104,12 +101,6 @@
 	put_ldev(mdev);
 }
 
-static int is_failed_barrier(int ee_flags)
-{
-	return (ee_flags & (EE_IS_BARRIER|EE_WAS_ERROR|EE_RESUBMITTED))
-			== (EE_IS_BARRIER|EE_WAS_ERROR);
-}
-
 /* writes on behalf of the partner, or resync writes,
  * "submitted" by the receiver, final stage.  */
 static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(local)
@@ -121,21 +112,6 @@
 	int is_syncer_req;
 	int do_al_complete_io;
 
-	/* if this is a failed barrier request, disable use of barriers,
-	 * and schedule for resubmission */
-	if (is_failed_barrier(e->flags)) {
-		drbd_bump_write_ordering(mdev, WO_bdev_flush);
-		spin_lock_irqsave(&mdev->req_lock, flags);
-		list_del(&e->w.list);
-		e->flags = (e->flags & ~EE_WAS_ERROR) | EE_RESUBMITTED;
-		e->w.cb = w_e_reissue;
-		/* put_ldev actually happens below, once we come here again. */
-		__release(local);
-		spin_unlock_irqrestore(&mdev->req_lock, flags);
-		drbd_queue_work(&mdev->data.work, &e->w);
-		return;
-	}
-
 	D_ASSERT(e->block_id != ID_VACANT);
 
 	/* after we moved e to done_ee,
@@ -246,6 +222,7 @@
 	bio_put(req->private_bio);
 	req->private_bio = ERR_PTR(error);
 
+	/* not req_mod(), we need irqsave here! */
 	spin_lock_irqsave(&mdev->req_lock, flags);
 	__req_mod(req, what, &m);
 	spin_unlock_irqrestore(&mdev->req_lock, flags);
@@ -376,54 +353,145 @@
 	struct drbd_epoch_entry *e;
 
 	if (!get_ldev(mdev))
-		return 0;
+		return -EIO;
+
+	if (drbd_rs_should_slow_down(mdev))
+		goto defer;
 
 	/* GFP_TRY, because if there is no memory available right now, this may
 	 * be rescheduled for later. It is "only" background resync, after all. */
 	e = drbd_alloc_ee(mdev, DRBD_MAGIC+0xbeef, sector, size, GFP_TRY);
 	if (!e)
-		goto fail;
+		goto defer;
 
+	e->w.cb = w_e_send_csum;
 	spin_lock_irq(&mdev->req_lock);
 	list_add(&e->w.list, &mdev->read_ee);
 	spin_unlock_irq(&mdev->req_lock);
 
-	e->w.cb = w_e_send_csum;
+	atomic_add(size >> 9, &mdev->rs_sect_ev);
 	if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0)
-		return 1;
+		return 0;
+
+	/* drbd_submit_ee currently fails for one reason only:
+	 * not being able to allocate enough bios.
+	 * Is dropping the connection going to help? */
+	spin_lock_irq(&mdev->req_lock);
+	list_del(&e->w.list);
+	spin_unlock_irq(&mdev->req_lock);
 
 	drbd_free_ee(mdev, e);
-fail:
+defer:
 	put_ldev(mdev);
-	return 2;
+	return -EAGAIN;
 }
 
 void resync_timer_fn(unsigned long data)
 {
-	unsigned long flags;
 	struct drbd_conf *mdev = (struct drbd_conf *) data;
 	int queue;
 
-	spin_lock_irqsave(&mdev->req_lock, flags);
-
-	if (likely(!test_and_clear_bit(STOP_SYNC_TIMER, &mdev->flags))) {
-		queue = 1;
-		if (mdev->state.conn == C_VERIFY_S)
-			mdev->resync_work.cb = w_make_ov_request;
-		else
-			mdev->resync_work.cb = w_make_resync_request;
-	} else {
+	queue = 1;
+	switch (mdev->state.conn) {
+	case C_VERIFY_S:
+		mdev->resync_work.cb = w_make_ov_request;
+		break;
+	case C_SYNC_TARGET:
+		mdev->resync_work.cb = w_make_resync_request;
+		break;
+	default:
 		queue = 0;
 		mdev->resync_work.cb = w_resync_inactive;
 	}
 
-	spin_unlock_irqrestore(&mdev->req_lock, flags);
-
 	/* harmless race: list_empty outside data.work.q_lock */
 	if (list_empty(&mdev->resync_work.list) && queue)
 		drbd_queue_work(&mdev->data.work, &mdev->resync_work);
 }
 
+static void fifo_set(struct fifo_buffer *fb, int value)
+{
+	int i;
+
+	for (i = 0; i < fb->size; i++)
+		fb->values[i] = value;
+}
+
+static int fifo_push(struct fifo_buffer *fb, int value)
+{
+	int ov;
+
+	ov = fb->values[fb->head_index];
+	fb->values[fb->head_index++] = value;
+
+	if (fb->head_index >= fb->size)
+		fb->head_index = 0;
+
+	return ov;
+}
+
+static void fifo_add_val(struct fifo_buffer *fb, int value)
+{
+	int i;
+
+	for (i = 0; i < fb->size; i++)
+		fb->values[i] += value;
+}
+
+int drbd_rs_controller(struct drbd_conf *mdev)
+{
+	unsigned int sect_in;  /* Number of sectors that came in since the last turn */
+	unsigned int want;     /* The number of sectors we want in the proxy */
+	int req_sect; /* Number of sectors to request in this turn */
+	int correction; /* Number of sectors more we need in the proxy*/
+	int cps; /* correction per invocation of drbd_rs_controller() */
+	int steps; /* Number of time steps to plan ahead */
+	int curr_corr;
+	int max_sect;
+
+	sect_in = atomic_xchg(&mdev->rs_sect_in, 0); /* Number of sectors that came in */
+	mdev->rs_in_flight -= sect_in;
+
+	spin_lock(&mdev->peer_seq_lock); /* get an atomic view on mdev->rs_plan_s */
+
+	steps = mdev->rs_plan_s.size; /* (mdev->sync_conf.c_plan_ahead * 10 * SLEEP_TIME) / HZ; */
+
+	if (mdev->rs_in_flight + sect_in == 0) { /* At start of resync */
+		want = ((mdev->sync_conf.rate * 2 * SLEEP_TIME) / HZ) * steps;
+	} else { /* normal path */
+		want = mdev->sync_conf.c_fill_target ? mdev->sync_conf.c_fill_target :
+			sect_in * mdev->sync_conf.c_delay_target * HZ / (SLEEP_TIME * 10);
+	}
+
+	correction = want - mdev->rs_in_flight - mdev->rs_planed;
+
+	/* Plan ahead */
+	cps = correction / steps;
+	fifo_add_val(&mdev->rs_plan_s, cps);
+	mdev->rs_planed += cps * steps;
+
+	/* What we do in this step */
+	curr_corr = fifo_push(&mdev->rs_plan_s, 0);
+	spin_unlock(&mdev->peer_seq_lock);
+	mdev->rs_planed -= curr_corr;
+
+	req_sect = sect_in + curr_corr;
+	if (req_sect < 0)
+		req_sect = 0;
+
+	max_sect = (mdev->sync_conf.c_max_rate * 2 * SLEEP_TIME) / HZ;
+	if (req_sect > max_sect)
+		req_sect = max_sect;
+
+	/*
+	dev_warn(DEV, "si=%u if=%d wa=%u co=%d st=%d cps=%d pl=%d cc=%d rs=%d\n",
+		 sect_in, mdev->rs_in_flight, want, correction,
+		 steps, cps, mdev->rs_planed, curr_corr, req_sect);
+	*/
+
+	return req_sect;
+}
+
 int w_make_resync_request(struct drbd_conf *mdev,
 		struct drbd_work *w, int cancel)
 {
@@ -431,8 +499,9 @@
 	sector_t sector;
 	const sector_t capacity = drbd_get_capacity(mdev->this_bdev);
 	int max_segment_size;
-	int number, i, size, pe, mx;
+	int number, rollback_i, size, pe, mx;
 	int align, queued, sndbuf;
+	int i = 0;
 
 	if (unlikely(cancel))
 		return 1;
@@ -446,6 +515,12 @@
 		dev_err(DEV, "%s in w_make_resync_request\n",
 			drbd_conn_str(mdev->state.conn));
 
+	if (mdev->rs_total == 0) {
+		/* empty resync? */
+		drbd_resync_finished(mdev);
+		return 1;
+	}
+
 	if (!get_ldev(mdev)) {
 		/* Since we only need to access mdev->rsync a
 		   get_ldev_if_state(mdev,D_FAILED) would be sufficient, but
@@ -458,11 +533,25 @@
 
 	/* starting with drbd 8.3.8, we can handle multi-bio EEs,
 	 * if it should be necessary */
-	max_segment_size = mdev->agreed_pro_version < 94 ?
-		queue_max_segment_size(mdev->rq_queue) : DRBD_MAX_SEGMENT_SIZE;
+	max_segment_size =
+		mdev->agreed_pro_version < 94 ? queue_max_segment_size(mdev->rq_queue) :
+		mdev->agreed_pro_version < 95 ?	DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_SEGMENT_SIZE;
 
-	number = SLEEP_TIME * mdev->sync_conf.rate  / ((BM_BLOCK_SIZE / 1024) * HZ);
-	pe = atomic_read(&mdev->rs_pending_cnt);
+	if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */
+		number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9);
+		mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME;
+	} else {
+		mdev->c_sync_rate = mdev->sync_conf.rate;
+		number = SLEEP_TIME * mdev->c_sync_rate  / ((BM_BLOCK_SIZE / 1024) * HZ);
+	}
+
+	/* Throttle resync on lower level disk activity, which may also be
+	 * caused by application IO on Primary/SyncTarget.
+	 * Keep this after the call to drbd_rs_controller, as that assumes
+	 * to be called as precisely as possible every SLEEP_TIME,
+	 * and would be confused otherwise. */
+	if (drbd_rs_should_slow_down(mdev))
+		goto requeue;
 
 	mutex_lock(&mdev->data.mutex);
 	if (mdev->data.socket)
@@ -476,6 +565,7 @@
 		mx = number;
 
 	/* Limit the number of pending RS requests to no more than the peer's receive buffer */
+	pe = atomic_read(&mdev->rs_pending_cnt);
 	if ((pe + number) > mx) {
 		number = mx - pe;
 	}
@@ -526,6 +616,7 @@
 		 * be prepared for all stripe sizes of software RAIDs.
 		 */
 		align = 1;
+		rollback_i = i;
 		for (;;) {
 			if (size + BM_BLOCK_SIZE > max_segment_size)
 				break;
@@ -561,14 +652,19 @@
 			size = (capacity-sector)<<9;
 		if (mdev->agreed_pro_version >= 89 && mdev->csums_tfm) {
 			switch (read_for_csum(mdev, sector, size)) {
-			case 0: /* Disk failure*/
+			case -EIO: /* Disk failure */
 				put_ldev(mdev);
 				return 0;
-			case 2: /* Allocation failed */
+			case -EAGAIN: /* allocation failed, or ldev busy */
 				drbd_rs_complete_io(mdev, sector);
 				mdev->bm_resync_fo = BM_SECT_TO_BIT(sector);
+				i = rollback_i;
 				goto requeue;
-			/* case 1: everything ok */
+			case 0:
+				/* everything ok */
+				break;
+			default:
+				BUG();
 			}
 		} else {
 			inc_rs_pending(mdev);
@@ -595,6 +691,7 @@
 	}
 
  requeue:
+	mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9));
 	mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME);
 	put_ldev(mdev);
 	return 1;
@@ -670,6 +767,14 @@
 	return 1;
 }
 
+static void ping_peer(struct drbd_conf *mdev)
+{
+	clear_bit(GOT_PING_ACK, &mdev->flags);
+	request_ping(mdev);
+	wait_event(mdev->misc_wait,
+		   test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED);
+}
+
 int drbd_resync_finished(struct drbd_conf *mdev)
 {
 	unsigned long db, dt, dbdt;
@@ -709,6 +814,8 @@
 	if (!get_ldev(mdev))
 		goto out;
 
+	ping_peer(mdev);
+
 	spin_lock_irq(&mdev->req_lock);
 	os = mdev->state;
 
@@ -801,8 +908,10 @@
 	mdev->rs_paused = 0;
 	mdev->ov_start_sector = 0;
 
+	drbd_md_sync(mdev);
+
 	if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) {
-		dev_warn(DEV, "Writing the whole bitmap, due to failed kmalloc\n");
+		dev_info(DEV, "Writing the whole bitmap\n");
 		drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished");
 	}
 
@@ -817,9 +926,13 @@
 {
 	if (drbd_ee_has_active_page(e)) {
 		/* This might happen if sendpage() has not finished */
+		int i = (e->size + PAGE_SIZE -1) >> PAGE_SHIFT;
+		atomic_add(i, &mdev->pp_in_use_by_net);
+		atomic_sub(i, &mdev->pp_in_use);
 		spin_lock_irq(&mdev->req_lock);
 		list_add_tail(&e->w.list, &mdev->net_ee);
 		spin_unlock_irq(&mdev->req_lock);
+		wake_up(&drbd_pp_wait);
 	} else
 		drbd_free_ee(mdev, e);
 }
@@ -926,9 +1039,12 @@
 		return 1;
 	}
 
-	drbd_rs_complete_io(mdev, e->sector);
+	if (get_ldev(mdev)) {
+		drbd_rs_complete_io(mdev, e->sector);
+		put_ldev(mdev);
+	}
 
-	di = (struct digest_info *)(unsigned long)e->block_id;
+	di = e->digest;
 
 	if (likely((e->flags & EE_WAS_ERROR) == 0)) {
 		/* quick hack to try to avoid a race against reconfiguration.
@@ -952,7 +1068,9 @@
 			ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e);
 		} else {
 			inc_rs_pending(mdev);
-			e->block_id = ID_SYNCER;
+			e->block_id = ID_SYNCER; /* By setting block_id, digest pointer becomes invalid! */
+			e->flags &= ~EE_HAS_DIGEST; /* This e no longer has a digest pointer */
+			kfree(di);
 			ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e);
 		}
 	} else {
@@ -962,9 +1080,6 @@
 	}
 
 	dec_unacked(mdev);
-
-	kfree(di);
-
 	move_to_net_ee_or_free(mdev, e);
 
 	if (unlikely(!ok))
@@ -1034,9 +1149,12 @@
 
 	/* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all
 	 * the resync lru has been cleaned up already */
-	drbd_rs_complete_io(mdev, e->sector);
+	if (get_ldev(mdev)) {
+		drbd_rs_complete_io(mdev, e->sector);
+		put_ldev(mdev);
+	}
 
-	di = (struct digest_info *)(unsigned long)e->block_id;
+	di = e->digest;
 
 	if (likely((e->flags & EE_WAS_ERROR) == 0)) {
 		digest_size = crypto_hash_digestsize(mdev->verify_tfm);
@@ -1055,9 +1173,6 @@
 	}
 
 	dec_unacked(mdev);
-
-	kfree(di);
-
 	if (!eq)
 		drbd_ov_oos_found(mdev, e->sector, e->size);
 	else
@@ -1108,7 +1223,7 @@
 	 * dec_ap_pending will be done in got_BarrierAck
 	 * or (on connection loss) in w_clear_epoch.  */
 	ok = _drbd_send_cmd(mdev, mdev->data.socket, P_BARRIER,
-				(struct p_header *)p, sizeof(*p), 0);
+				(struct p_header80 *)p, sizeof(*p), 0);
 	drbd_put_data_sock(mdev);
 
 	return ok;
@@ -1173,6 +1288,24 @@
 	return ok;
 }
 
+int w_restart_disk_io(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+{
+	struct drbd_request *req = container_of(w, struct drbd_request, w);
+
+	if (bio_data_dir(req->master_bio) == WRITE && req->rq_state & RQ_IN_ACT_LOG)
+		drbd_al_begin_io(mdev, req->sector);
+	/* Calling drbd_al_begin_io() out of the worker might deadlocks
+	   theoretically. Practically it can not deadlock, since this is
+	   only used when unfreezing IOs. All the extents of the requests
+	   that made it into the TL are already active */
+
+	drbd_req_make_private_bio(req, req->master_bio);
+	req->private_bio->bi_bdev = mdev->ldev->backing_bdev;
+	generic_make_request(req->private_bio);
+
+	return 1;
+}
+
 static int _drbd_may_sync_now(struct drbd_conf *mdev)
 {
 	struct drbd_conf *odev = mdev;
@@ -1298,14 +1431,6 @@
 	return retcode;
 }
 
-static void ping_peer(struct drbd_conf *mdev)
-{
-	clear_bit(GOT_PING_ACK, &mdev->flags);
-	request_ping(mdev);
-	wait_event(mdev->misc_wait,
-		   test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED);
-}
-
 /**
  * drbd_start_resync() - Start the resync process
  * @mdev:	DRBD device.
@@ -1379,13 +1504,21 @@
 		r = SS_UNKNOWN_ERROR;
 
 	if (r == SS_SUCCESS) {
-		mdev->rs_total     =
-		mdev->rs_mark_left = drbd_bm_total_weight(mdev);
+		unsigned long tw = drbd_bm_total_weight(mdev);
+		unsigned long now = jiffies;
+		int i;
+
 		mdev->rs_failed    = 0;
 		mdev->rs_paused    = 0;
-		mdev->rs_start     =
-		mdev->rs_mark_time = jiffies;
 		mdev->rs_same_csum = 0;
+		mdev->rs_last_events = 0;
+		mdev->rs_last_sect_ev = 0;
+		mdev->rs_total     = tw;
+		mdev->rs_start     = now;
+		for (i = 0; i < DRBD_SYNC_MARKS; i++) {
+			mdev->rs_mark_left[i] = tw;
+			mdev->rs_mark_time[i] = now;
+		}
 		_drbd_pause_after(mdev);
 	}
 	write_unlock_irq(&global_state_lock);
@@ -1397,12 +1530,31 @@
 		     (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10),
 		     (unsigned long) mdev->rs_total);
 
-		if (mdev->rs_total == 0) {
-			/* Peer still reachable? Beware of failing before-resync-target handlers! */
-			ping_peer(mdev);
+		if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) {
+			/* This still has a race (about when exactly the peers
+			 * detect connection loss) that can lead to a full sync
+			 * on next handshake. In 8.3.9 we fixed this with explicit
+			 * resync-finished notifications, but the fix
+			 * introduces a protocol change.  Sleeping for some
+			 * time longer than the ping interval + timeout on the
+			 * SyncSource, to give the SyncTarget the chance to
+			 * detect connection loss, then waiting for a ping
+			 * response (implicit in drbd_resync_finished) reduces
+			 * the race considerably, but does not solve it. */
+			if (side == C_SYNC_SOURCE)
+				schedule_timeout_interruptible(
+					mdev->net_conf->ping_int * HZ +
+					mdev->net_conf->ping_timeo*HZ/9);
 			drbd_resync_finished(mdev);
 		}
 
+		atomic_set(&mdev->rs_sect_in, 0);
+		atomic_set(&mdev->rs_sect_ev, 0);
+		mdev->rs_in_flight = 0;
+		mdev->rs_planed = 0;
+		spin_lock(&mdev->peer_seq_lock);
+		fifo_set(&mdev->rs_plan_s, 0);
+		spin_unlock(&mdev->peer_seq_lock);
 		/* ns.conn may already be != mdev->state.conn,
 		 * we may have been paused in between, or become paused until
 		 * the timer triggers.
diff -druN linux-libre-2.6.36-gnu/drivers/block/floppy.c linux-libre-2.6.37-gnu/drivers/block/floppy.c
--- linux-libre-2.6.36-gnu/drivers/block/floppy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/floppy.c	2011-01-04 19:50:19.000000000 -0500
@@ -178,7 +178,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/bio.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <linux/fcntl.h>
@@ -199,6 +198,7 @@
  * It's been recommended that take about 1/4 of the default speed
  * in some more extreme cases.
  */
+static DEFINE_MUTEX(floppy_mutex);
 static int slow_floppy;
 
 #include <asm/dma.h>
@@ -258,8 +258,8 @@
 #include <linux/completion.h>
 
 static struct request *current_req;
-static struct request_queue *floppy_queue;
 static void do_fd_request(struct request_queue *q);
+static int set_next_request(void);
 
 #ifndef fd_get_dma_residue
 #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -413,6 +413,7 @@
 static struct block_device *opened_bdev[N_DRIVE];
 static DEFINE_MUTEX(open_lock);
 static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
+static int fdc_queue;
 
 /*
  * This struct defines the different floppy types.
@@ -890,8 +891,8 @@
 	del_timer(&fd_timeout);
 	cont = NULL;
 	clear_bit(0, &fdc_busy);
-	if (current_req || blk_peek_request(floppy_queue))
-		do_fd_request(floppy_queue);
+	if (current_req || set_next_request())
+		do_fd_request(current_req->q);
 	spin_unlock_irqrestore(&floppy_lock, flags);
 	wake_up(&fdc_wait);
 }
@@ -2243,8 +2244,8 @@
  * logical buffer */
 static void request_done(int uptodate)
 {
-	struct request_queue *q = floppy_queue;
 	struct request *req = current_req;
+	struct request_queue *q;
 	unsigned long flags;
 	int block;
 	char msg[sizeof("request done ") + sizeof(int) * 3];
@@ -2258,6 +2259,8 @@
 		return;
 	}
 
+	q = req->q;
+
 	if (uptodate) {
 		/* maintain values for invalidation on geometry
 		 * change */
@@ -2811,6 +2814,28 @@
 	return 2;
 }
 
+/*
+ * Round-robin between our available drives, doing one request from each
+ */
+static int set_next_request(void)
+{
+	struct request_queue *q;
+	int old_pos = fdc_queue;
+
+	do {
+		q = disks[fdc_queue]->queue;
+		if (++fdc_queue == N_DRIVE)
+			fdc_queue = 0;
+		if (q) {
+			current_req = blk_fetch_request(q);
+			if (current_req)
+				break;
+		}
+	} while (fdc_queue != old_pos);
+
+	return current_req != NULL;
+}
+
 static void redo_fd_request(void)
 {
 	int drive;
@@ -2822,17 +2847,17 @@
 
 do_request:
 	if (!current_req) {
-		struct request *req;
+		int pending;
 
-		spin_lock_irq(floppy_queue->queue_lock);
-		req = blk_fetch_request(floppy_queue);
-		spin_unlock_irq(floppy_queue->queue_lock);
-		if (!req) {
+		spin_lock_irq(&floppy_lock);
+		pending = set_next_request();
+		spin_unlock_irq(&floppy_lock);
+
+		if (!pending) {
 			do_floppy = NULL;
 			unlock_fdc();
 			return;
 		}
-		current_req = req;
 	}
 	drive = (long)current_req->rq_disk->private_data;
 	set_fdc(drive);
@@ -3553,9 +3578,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&floppy_mutex);
 	ret = fd_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
+	mutex_unlock(&floppy_mutex);
 
 	return ret;
 }
@@ -3616,7 +3641,7 @@
 {
 	int drive = (long)disk->private_data;
 
-	lock_kernel();
+	mutex_lock(&floppy_mutex);
 	mutex_lock(&open_lock);
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref = 0;
@@ -3627,7 +3652,7 @@
 	if (!UDRS->fd_ref)
 		opened_bdev[drive] = NULL;
 	mutex_unlock(&open_lock);
-	unlock_kernel();
+	mutex_unlock(&floppy_mutex);
 
 	return 0;
 }
@@ -3645,7 +3670,7 @@
 	int res = -EBUSY;
 	char *tmp;
 
-	lock_kernel();
+	mutex_lock(&floppy_mutex);
 	mutex_lock(&open_lock);
 	old_dev = UDRS->fd_device;
 	if (opened_bdev[drive] && opened_bdev[drive] != bdev)
@@ -3722,7 +3747,7 @@
 			goto out;
 	}
 	mutex_unlock(&open_lock);
-	unlock_kernel();
+	mutex_unlock(&floppy_mutex);
 	return 0;
 out:
 	if (UDRS->fd_ref < 0)
@@ -3733,7 +3758,7 @@
 		opened_bdev[drive] = NULL;
 out2:
 	mutex_unlock(&open_lock);
-	unlock_kernel();
+	mutex_unlock(&floppy_mutex);
 	return res;
 }
 
@@ -4165,6 +4190,13 @@
 			goto out_put_disk;
 		}
 
+		disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
+		if (!disks[dr]->queue) {
+			err = -ENOMEM;
+			goto out_put_disk;
+		}
+
+		blk_queue_max_hw_sectors(disks[dr]->queue, 64);
 		disks[dr]->major = FLOPPY_MAJOR;
 		disks[dr]->first_minor = TOMINOR(dr);
 		disks[dr]->fops = &floppy_fops;
@@ -4183,13 +4215,6 @@
 	if (err)
 		goto out_unreg_blkdev;
 
-	floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
-	if (!floppy_queue) {
-		err = -ENOMEM;
-		goto out_unreg_driver;
-	}
-	blk_queue_max_hw_sectors(floppy_queue, 64);
-
 	blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
 			    floppy_find, NULL, NULL);
 
@@ -4317,7 +4342,6 @@
 
 		/* to be cleaned up... */
 		disks[drive]->private_data = (void *)(long)drive;
-		disks[drive]->queue = floppy_queue;
 		disks[drive]->flags |= GENHD_FL_REMOVABLE;
 		disks[drive]->driverfs_dev = &floppy_device[drive].dev;
 		add_disk(disks[drive]);
@@ -4333,14 +4357,14 @@
 		floppy_release_irq_and_dma();
 out_unreg_region:
 	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
-	blk_cleanup_queue(floppy_queue);
-out_unreg_driver:
 	platform_driver_unregister(&floppy_driver);
 out_unreg_blkdev:
 	unregister_blkdev(FLOPPY_MAJOR, "fd");
 out_put_disk:
 	while (dr--) {
 		del_timer(&motor_off_timer[dr]);
+		if (disks[dr]->queue)
+			blk_cleanup_queue(disks[dr]->queue);
 		put_disk(disks[dr]);
 	}
 	return err;
@@ -4549,12 +4573,12 @@
 			device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
 			platform_device_unregister(&floppy_device[drive]);
 		}
+		blk_cleanup_queue(disks[drive]->queue);
 		put_disk(disks[drive]);
 	}
 
 	del_timer_sync(&fd_timeout);
 	del_timer_sync(&fd_timer);
-	blk_cleanup_queue(floppy_queue);
 
 	if (atomic_read(&usage_count))
 		floppy_release_irq_and_dma();
diff -druN linux-libre-2.6.36-gnu/drivers/block/Kconfig linux-libre-2.6.37-gnu/drivers/block/Kconfig
--- linux-libre-2.6.36-gnu/drivers/block/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -488,4 +488,21 @@
 
 	  If unsure, say N.
 
+config BLK_DEV_RBD
+	tristate "Rados block device (RBD)"
+	depends on INET && EXPERIMENTAL && BLOCK
+	select CEPH_LIB
+	select LIBCRC32C
+	select CRYPTO_AES
+	select CRYPTO
+	default n
+	help
+	  Say Y here if you want include the Rados block device, which stripes
+	  a block device over objects stored in the Ceph distributed object
+	  store.
+
+	  More information at http://ceph.newdream.net/.
+
+	  If unsure, say N.
+
 endif # BLK_DEV
diff -druN linux-libre-2.6.36-gnu/drivers/block/loop.c linux-libre-2.6.37-gnu/drivers/block/loop.c
--- linux-libre-2.6.36-gnu/drivers/block/loop.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/loop.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,16 +67,18 @@
 #include <linux/compat.h>
 #include <linux/suspend.h>
 #include <linux/freezer.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/writeback.h>
 #include <linux/buffer_head.h>		/* for invalidate_bdev() */
 #include <linux/completion.h>
 #include <linux/highmem.h>
 #include <linux/kthread.h>
 #include <linux/splice.h>
+#include <linux/sysfs.h>
 
 #include <asm/uaccess.h>
 
+static DEFINE_MUTEX(loop_mutex);
 static LIST_HEAD(loop_devices);
 static DEFINE_MUTEX(loop_devices_mutex);
 
@@ -99,8 +101,8 @@
 	else
 		memcpy(raw_buf, loop_buf, size);
 
-	kunmap_atomic(raw_buf, KM_USER0);
 	kunmap_atomic(loop_buf, KM_USER1);
+	kunmap_atomic(raw_buf, KM_USER0);
 	cond_resched();
 	return 0;
 }
@@ -128,8 +130,8 @@
 	for (i = 0; i < size; i++)
 		*out++ = *in++ ^ key[(i & 511) % keysize];
 
-	kunmap_atomic(raw_buf, KM_USER0);
 	kunmap_atomic(loop_buf, KM_USER1);
+	kunmap_atomic(raw_buf, KM_USER0);
 	cond_resched();
 	return 0;
 }
@@ -477,17 +479,11 @@
 	pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
 
 	if (bio_rw(bio) == WRITE) {
-		bool barrier = !!(bio->bi_rw & REQ_HARDBARRIER);
 		struct file *file = lo->lo_backing_file;
 
-		if (barrier) {
-			if (unlikely(!file->f_op->fsync)) {
-				ret = -EOPNOTSUPP;
-				goto out;
-			}
-
+		if (bio->bi_rw & REQ_FLUSH) {
 			ret = vfs_fsync(file, 0);
-			if (unlikely(ret)) {
+			if (unlikely(ret && ret != -EINVAL)) {
 				ret = -EIO;
 				goto out;
 			}
@@ -495,9 +491,9 @@
 
 		ret = lo_send(lo, bio, pos);
 
-		if (barrier && !ret) {
+		if ((bio->bi_rw & REQ_FUA) && !ret) {
 			ret = vfs_fsync(file, 0);
-			if (unlikely(ret))
+			if (unlikely(ret && ret != -EINVAL))
 				ret = -EIO;
 		}
 	} else
@@ -737,6 +733,103 @@
 	return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
 }
 
+/* loop sysfs attributes */
+
+static ssize_t loop_attr_show(struct device *dev, char *page,
+			      ssize_t (*callback)(struct loop_device *, char *))
+{
+	struct loop_device *l, *lo = NULL;
+
+	mutex_lock(&loop_devices_mutex);
+	list_for_each_entry(l, &loop_devices, lo_list)
+		if (disk_to_dev(l->lo_disk) == dev) {
+			lo = l;
+			break;
+		}
+	mutex_unlock(&loop_devices_mutex);
+
+	return lo ? callback(lo, page) : -EIO;
+}
+
+#define LOOP_ATTR_RO(_name)						\
+static ssize_t loop_attr_##_name##_show(struct loop_device *, char *);	\
+static ssize_t loop_attr_do_show_##_name(struct device *d,		\
+				struct device_attribute *attr, char *b)	\
+{									\
+	return loop_attr_show(d, b, loop_attr_##_name##_show);		\
+}									\
+static struct device_attribute loop_attr_##_name =			\
+	__ATTR(_name, S_IRUGO, loop_attr_do_show_##_name, NULL);
+
+static ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf)
+{
+	ssize_t ret;
+	char *p = NULL;
+
+	mutex_lock(&lo->lo_ctl_mutex);
+	if (lo->lo_backing_file)
+		p = d_path(&lo->lo_backing_file->f_path, buf, PAGE_SIZE - 1);
+	mutex_unlock(&lo->lo_ctl_mutex);
+
+	if (IS_ERR_OR_NULL(p))
+		ret = PTR_ERR(p);
+	else {
+		ret = strlen(p);
+		memmove(buf, p, ret);
+		buf[ret++] = '\n';
+		buf[ret] = 0;
+	}
+
+	return ret;
+}
+
+static ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf)
+{
+	return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_offset);
+}
+
+static ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf)
+{
+	return sprintf(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit);
+}
+
+static ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf)
+{
+	int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR);
+
+	return sprintf(buf, "%s\n", autoclear ? "1" : "0");
+}
+
+LOOP_ATTR_RO(backing_file);
+LOOP_ATTR_RO(offset);
+LOOP_ATTR_RO(sizelimit);
+LOOP_ATTR_RO(autoclear);
+
+static struct attribute *loop_attrs[] = {
+	&loop_attr_backing_file.attr,
+	&loop_attr_offset.attr,
+	&loop_attr_sizelimit.attr,
+	&loop_attr_autoclear.attr,
+	NULL,
+};
+
+static struct attribute_group loop_attribute_group = {
+	.name = "loop",
+	.attrs= loop_attrs,
+};
+
+static int loop_sysfs_init(struct loop_device *lo)
+{
+	return sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj,
+				  &loop_attribute_group);
+}
+
+static void loop_sysfs_exit(struct loop_device *lo)
+{
+	sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj,
+			   &loop_attribute_group);
+}
+
 static int loop_set_fd(struct loop_device *lo, fmode_t mode,
 		       struct block_device *bdev, unsigned int arg)
 {
@@ -832,10 +925,11 @@
 	lo->lo_queue->unplug_fn = loop_unplug;
 
 	if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
-		blk_queue_ordered(lo->lo_queue, QUEUE_ORDERED_DRAIN);
+		blk_queue_flush(lo->lo_queue, REQ_FLUSH);
 
 	set_capacity(lo->lo_disk, size);
 	bd_set_size(bdev, size << 9);
+	loop_sysfs_init(lo);
 	/* let user-space know about the new size */
 	kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
 
@@ -854,6 +948,7 @@
 	return 0;
 
 out_clr:
+	loop_sysfs_exit(lo);
 	lo->lo_thread = NULL;
 	lo->lo_device = NULL;
 	lo->lo_backing_file = NULL;
@@ -948,6 +1043,7 @@
 	if (bdev)
 		invalidate_bdev(bdev);
 	set_capacity(lo->lo_disk, 0);
+	loop_sysfs_exit(lo);
 	if (bdev) {
 		bd_set_size(bdev, 0);
 		/* let user-space know about this change */
@@ -1409,11 +1505,11 @@
 {
 	struct loop_device *lo = bdev->bd_disk->private_data;
 
-	lock_kernel();
+	mutex_lock(&loop_mutex);
 	mutex_lock(&lo->lo_ctl_mutex);
 	lo->lo_refcnt++;
 	mutex_unlock(&lo->lo_ctl_mutex);
-	unlock_kernel();
+	mutex_unlock(&loop_mutex);
 
 	return 0;
 }
@@ -1423,7 +1519,7 @@
 	struct loop_device *lo = disk->private_data;
 	int err;
 
-	lock_kernel();
+	mutex_lock(&loop_mutex);
 	mutex_lock(&lo->lo_ctl_mutex);
 
 	if (--lo->lo_refcnt)
@@ -1448,7 +1544,7 @@
 out:
 	mutex_unlock(&lo->lo_ctl_mutex);
 out_unlocked:
-	lock_kernel();
+	mutex_unlock(&loop_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/Makefile linux-libre-2.6.37-gnu/drivers/block/Makefile
--- linux-libre-2.6.36-gnu/drivers/block/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -37,5 +37,6 @@
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= xen-blkfront.o
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
+obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
 swim_mod-objs	:= swim.o swim_asm.o
diff -druN linux-libre-2.6.36-gnu/drivers/block/nbd.c linux-libre-2.6.37-gnu/drivers/block/nbd.c
--- linux-libre-2.6.36-gnu/drivers/block/nbd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/nbd.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,7 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/ioctl.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/compiler.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
@@ -53,6 +53,7 @@
 #define DBG_BLKDEV      0x0100
 #define DBG_RX          0x0200
 #define DBG_TX          0x0400
+static DEFINE_MUTEX(nbd_mutex);
 static unsigned int debugflags;
 #endif /* NDEBUG */
 
@@ -717,11 +718,11 @@
 	dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
 			lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
 
-	lock_kernel();
+	mutex_lock(&nbd_mutex);
 	mutex_lock(&lo->tx_lock);
 	error = __nbd_ioctl(bdev, lo, cmd, arg);
 	mutex_unlock(&lo->tx_lock);
-	unlock_kernel();
+	mutex_unlock(&nbd_mutex);
 
 	return error;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/osdblk.c linux-libre-2.6.37-gnu/drivers/block/osdblk.c
--- linux-libre-2.6.36-gnu/drivers/block/osdblk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/osdblk.c	2011-01-04 19:50:19.000000000 -0500
@@ -310,8 +310,7 @@
 			break;
 
 		/* filter out block requests we don't understand */
-		if (rq->cmd_type != REQ_TYPE_FS &&
-		    !(rq->cmd_flags & REQ_HARDBARRIER)) {
+		if (rq->cmd_type != REQ_TYPE_FS) {
 			blk_end_request_all(rq, 0);
 			continue;
 		}
@@ -439,7 +438,7 @@
 	blk_queue_stack_limits(q, osd_request_queue(osdev->osd));
 
 	blk_queue_prep_rq(q, blk_queue_start_tag);
-	blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH);
+	blk_queue_flush(q, REQ_FLUSH);
 
 	disk->queue = q;
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/paride/pcd.c linux-libre-2.6.37-gnu/drivers/block/paride/pcd.c
--- linux-libre-2.6.36-gnu/drivers/block/paride/pcd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/paride/pcd.c	2011-01-04 19:50:19.000000000 -0500
@@ -138,9 +138,10 @@
 #include <linux/cdrom.h>
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
+static DEFINE_MUTEX(pcd_mutex);
 static DEFINE_SPINLOCK(pcd_lock);
 
 module_param(verbose, bool, 0644);
@@ -227,9 +228,9 @@
 	struct pcd_unit *cd = bdev->bd_disk->private_data;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&pcd_mutex);
 	ret = cdrom_open(&cd->info, bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&pcd_mutex);
 
 	return ret;
 }
@@ -237,9 +238,9 @@
 static int pcd_block_release(struct gendisk *disk, fmode_t mode)
 {
 	struct pcd_unit *cd = disk->private_data;
-	lock_kernel();
+	mutex_lock(&pcd_mutex);
 	cdrom_release(&cd->info, mode);
-	unlock_kernel();
+	mutex_unlock(&pcd_mutex);
 	return 0;
 }
 
@@ -249,9 +250,9 @@
 	struct pcd_unit *cd = bdev->bd_disk->private_data;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&pcd_mutex);
 	ret = cdrom_ioctl(&cd->info, bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&pcd_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/paride/pd.c linux-libre-2.6.37-gnu/drivers/block/paride/pd.c
--- linux-libre-2.6.36-gnu/drivers/block/paride/pd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/paride/pd.c	2011-01-04 19:50:19.000000000 -0500
@@ -153,10 +153,11 @@
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/workqueue.h>
 
+static DEFINE_MUTEX(pd_mutex);
 static DEFINE_SPINLOCK(pd_lock);
 
 module_param(verbose, bool, 0);
@@ -736,14 +737,14 @@
 {
 	struct pd_unit *disk = bdev->bd_disk->private_data;
 
-	lock_kernel();
+	mutex_lock(&pd_mutex);
 	disk->access++;
 
 	if (disk->removable) {
 		pd_special_command(disk, pd_media_check);
 		pd_special_command(disk, pd_door_lock);
 	}
-	unlock_kernel();
+	mutex_unlock(&pd_mutex);
 	return 0;
 }
 
@@ -771,10 +772,10 @@
 
 	switch (cmd) {
 	case CDROMEJECT:
-		lock_kernel();
+		mutex_lock(&pd_mutex);
 		if (disk->access == 1)
 			pd_special_command(disk, pd_eject);
-		unlock_kernel();
+		mutex_unlock(&pd_mutex);
 		return 0;
 	default:
 		return -EINVAL;
@@ -785,10 +786,10 @@
 {
 	struct pd_unit *disk = p->private_data;
 
-	lock_kernel();
+	mutex_lock(&pd_mutex);
 	if (!--disk->access && disk->removable)
 		pd_special_command(disk, pd_door_unlock);
-	unlock_kernel();
+	mutex_unlock(&pd_mutex);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/paride/pf.c linux-libre-2.6.37-gnu/drivers/block/paride/pf.c
--- linux-libre-2.6.36-gnu/drivers/block/paride/pf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/paride/pf.c	2011-01-04 19:50:19.000000000 -0500
@@ -152,9 +152,10 @@
 #include <linux/spinlock.h>
 #include <linux/blkdev.h>
 #include <linux/blkpg.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
+static DEFINE_MUTEX(pf_mutex);
 static DEFINE_SPINLOCK(pf_spin_lock);
 
 module_param(verbose, bool, 0644);
@@ -302,7 +303,7 @@
 	struct pf_unit *pf = bdev->bd_disk->private_data;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&pf_mutex);
 	pf_identify(pf);
 
 	ret = -ENODEV;
@@ -318,7 +319,7 @@
 	if (pf->removable)
 		pf_lock(pf, 1);
 out:
-	unlock_kernel();
+	mutex_unlock(&pf_mutex);
 	return ret;
 }
 
@@ -349,9 +350,9 @@
 
 	if (pf->access != 1)
 		return -EBUSY;
-	lock_kernel();
+	mutex_lock(&pf_mutex);
 	pf_eject(pf);
-	unlock_kernel();
+	mutex_unlock(&pf_mutex);
 
 	return 0;
 }
@@ -360,9 +361,9 @@
 {
 	struct pf_unit *pf = disk->private_data;
 
-	lock_kernel();
+	mutex_lock(&pf_mutex);
 	if (pf->access <= 0) {
-		unlock_kernel();
+		mutex_unlock(&pf_mutex);
 		return -EINVAL;
 	}
 
@@ -371,7 +372,7 @@
 	if (!pf->access && pf->removable)
 		pf_lock(pf, 0);
 
-	unlock_kernel();
+	mutex_unlock(&pf_mutex);
 	return 0;
 
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/paride/pg.c linux-libre-2.6.37-gnu/drivers/block/paride/pg.c
--- linux-libre-2.6.36-gnu/drivers/block/paride/pg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/paride/pg.c	2011-01-04 19:50:19.000000000 -0500
@@ -162,7 +162,7 @@
 #include <linux/pg.h>
 #include <linux/device.h>
 #include <linux/sched.h>	/* current, TASK_* */
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/jiffies.h>
 
 #include <asm/uaccess.h>
@@ -193,6 +193,7 @@
 
 #define ATAPI_IDENTIFY		0x12
 
+static DEFINE_MUTEX(pg_mutex);
 static int pg_open(struct inode *inode, struct file *file);
 static int pg_release(struct inode *inode, struct file *file);
 static ssize_t pg_read(struct file *filp, char __user *buf,
@@ -234,6 +235,7 @@
 	.write = pg_write,
 	.open = pg_open,
 	.release = pg_release,
+	.llseek = noop_llseek,
 };
 
 static void pg_init_units(void)
@@ -518,7 +520,7 @@
 	struct pg *dev = &devices[unit];
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&pg_mutex);
 	if ((unit >= PG_UNITS) || (!dev->present)) {
 		ret = -ENODEV;
 		goto out;
@@ -547,7 +549,7 @@
 	file->private_data = dev;
 
 out:
-	unlock_kernel();
+	mutex_unlock(&pg_mutex);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/paride/pt.c linux-libre-2.6.37-gnu/drivers/block/paride/pt.c
--- linux-libre-2.6.36-gnu/drivers/block/paride/pt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/paride/pt.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,7 +146,7 @@
 #include <linux/mtio.h>
 #include <linux/device.h>
 #include <linux/sched.h>	/* current, TASK_*, schedule_timeout() */
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -189,6 +189,7 @@
 #define ATAPI_MODE_SENSE	0x1a
 #define ATAPI_LOG_SENSE		0x4d
 
+static DEFINE_MUTEX(pt_mutex);
 static int pt_open(struct inode *inode, struct file *file);
 static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 static int pt_release(struct inode *inode, struct file *file);
@@ -239,6 +240,7 @@
 	.unlocked_ioctl = pt_ioctl,
 	.open = pt_open,
 	.release = pt_release,
+	.llseek = noop_llseek,
 };
 
 /* sysfs class support */
@@ -650,9 +652,9 @@
 	struct pt_unit *tape = pt + unit;
 	int err;
 
-	lock_kernel();
+	mutex_lock(&pt_mutex);
 	if (unit >= PT_UNITS || (!tape->present)) {
-		unlock_kernel();
+		mutex_unlock(&pt_mutex);
 		return -ENODEV;
 	}
 
@@ -681,12 +683,12 @@
 	}
 
 	file->private_data = tape;
-	unlock_kernel();
+	mutex_unlock(&pt_mutex);
 	return 0;
 
 out:
 	atomic_inc(&tape->available);
-	unlock_kernel();
+	mutex_unlock(&pt_mutex);
 	return err;
 }
 
@@ -704,15 +706,15 @@
 		switch (mtop.mt_op) {
 
 		case MTREW:
-			lock_kernel();
+			mutex_lock(&pt_mutex);
 			pt_rewind(tape);
-			unlock_kernel();
+			mutex_unlock(&pt_mutex);
 			return 0;
 
 		case MTWEOF:
-			lock_kernel();
+			mutex_lock(&pt_mutex);
 			pt_write_fm(tape);
-			unlock_kernel();
+			mutex_unlock(&pt_mutex);
 			return 0;
 
 		default:
diff -druN linux-libre-2.6.36-gnu/drivers/block/pktcdvd.c linux-libre-2.6.37-gnu/drivers/block/pktcdvd.c
--- linux-libre-2.6.36-gnu/drivers/block/pktcdvd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/pktcdvd.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,6 @@
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
 #include <linux/freezer.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <scsi/scsi_cmnd.h>
@@ -86,6 +85,7 @@
 
 #define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1))
 
+static DEFINE_MUTEX(pktcdvd_mutex);
 static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
 static struct proc_dir_entry *pkt_proc;
 static int pktdev_major;
@@ -753,7 +753,6 @@
 
 	rq->timeout = 60*HZ;
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
-	rq->cmd_flags |= REQ_HARDBARRIER;
 	if (cgc->quiet)
 		rq->cmd_flags |= REQ_QUIET;
 
@@ -2383,7 +2382,7 @@
 
 	VPRINTK(DRIVER_NAME": entering open\n");
 
-	lock_kernel();
+	mutex_lock(&pktcdvd_mutex);
 	mutex_lock(&ctl_mutex);
 	pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
 	if (!pd) {
@@ -2411,7 +2410,7 @@
 	}
 
 	mutex_unlock(&ctl_mutex);
-	unlock_kernel();
+	mutex_unlock(&pktcdvd_mutex);
 	return 0;
 
 out_dec:
@@ -2419,7 +2418,7 @@
 out:
 	VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
 	mutex_unlock(&ctl_mutex);
-	unlock_kernel();
+	mutex_unlock(&pktcdvd_mutex);
 	return ret;
 }
 
@@ -2428,7 +2427,7 @@
 	struct pktcdvd_device *pd = disk->private_data;
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&pktcdvd_mutex);
 	mutex_lock(&ctl_mutex);
 	pd->refcnt--;
 	BUG_ON(pd->refcnt < 0);
@@ -2437,7 +2436,7 @@
 		pkt_release_dev(pd, flush);
 	}
 	mutex_unlock(&ctl_mutex);
-	unlock_kernel();
+	mutex_unlock(&pktcdvd_mutex);
 	return ret;
 }
 
@@ -2773,7 +2772,7 @@
 	VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd,
 		MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
 
-	lock_kernel();
+	mutex_lock(&pktcdvd_mutex);
 	switch (cmd) {
 	case CDROMEJECT:
 		/*
@@ -2798,7 +2797,7 @@
 		VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
 		ret = -ENOTTY;
 	}
-	unlock_kernel();
+	mutex_unlock(&pktcdvd_mutex);
 
 	return ret;
 }
@@ -3046,6 +3045,7 @@
 	.compat_ioctl	= pkt_ctl_compat_ioctl,
 #endif
 	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice pkt_misc = {
diff -druN linux-libre-2.6.36-gnu/drivers/block/ps3disk.c linux-libre-2.6.37-gnu/drivers/block/ps3disk.c
--- linux-libre-2.6.36-gnu/drivers/block/ps3disk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/ps3disk.c	2011-01-04 19:50:19.000000000 -0500
@@ -468,7 +468,7 @@
 	blk_queue_dma_alignment(queue, dev->blk_size-1);
 	blk_queue_logical_block_size(queue, dev->blk_size);
 
-	blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH);
+	blk_queue_flush(queue, REQ_FLUSH);
 
 	blk_queue_max_segments(queue, -1);
 	blk_queue_max_segment_size(queue, dev->bounce_size);
diff -druN linux-libre-2.6.36-gnu/drivers/block/rbd.c linux-libre-2.6.37-gnu/drivers/block/rbd.c
--- linux-libre-2.6.36-gnu/drivers/block/rbd.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/block/rbd.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2035 @@
+/*
+   rbd.c -- Export ceph rados objects as a Linux block device
+
+
+   based on drivers/block/osdblk.c:
+
+   Copyright 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+
+   For usage instructions, please refer to:
+
+                 Documentation/ABI/testing/sysfs-bus-rbd
+
+ */
+
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/osd_client.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/decode.h>
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+
+#include "rbd_types.h"
+
+#define DRV_NAME "rbd"
+#define DRV_NAME_LONG "rbd (rados block device)"
+
+#define RBD_MINORS_PER_MAJOR	256		/* max minors per blkdev */
+
+#define RBD_MAX_MD_NAME_LEN	(96 + sizeof(RBD_SUFFIX))
+#define RBD_MAX_POOL_NAME_LEN	64
+#define RBD_MAX_SNAP_NAME_LEN	32
+#define RBD_MAX_OPT_LEN		1024
+
+#define RBD_SNAP_HEAD_NAME	"-"
+
+#define DEV_NAME_LEN		32
+
+/*
+ * block device image metadata (in-memory version)
+ */
+struct rbd_image_header {
+	u64 image_size;
+	char block_name[32];
+	__u8 obj_order;
+	__u8 crypt_type;
+	__u8 comp_type;
+	struct rw_semaphore snap_rwsem;
+	struct ceph_snap_context *snapc;
+	size_t snap_names_len;
+	u64 snap_seq;
+	u32 total_snaps;
+
+	char *snap_names;
+	u64 *snap_sizes;
+};
+
+/*
+ * an instance of the client.  multiple devices may share a client.
+ */
+struct rbd_client {
+	struct ceph_client	*client;
+	struct kref		kref;
+	struct list_head	node;
+};
+
+/*
+ * a single io request
+ */
+struct rbd_request {
+	struct request		*rq;		/* blk layer request */
+	struct bio		*bio;		/* cloned bio */
+	struct page		**pages;	/* list of used pages */
+	u64			len;
+};
+
+struct rbd_snap {
+	struct	device		dev;
+	const char		*name;
+	size_t			size;
+	struct list_head	node;
+	u64			id;
+};
+
+/*
+ * a single device
+ */
+struct rbd_device {
+	int			id;		/* blkdev unique id */
+
+	int			major;		/* blkdev assigned major */
+	struct gendisk		*disk;		/* blkdev's gendisk and rq */
+	struct request_queue	*q;
+
+	struct ceph_client	*client;
+	struct rbd_client	*rbd_client;
+
+	char			name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
+
+	spinlock_t		lock;		/* queue lock */
+
+	struct rbd_image_header	header;
+	char			obj[RBD_MAX_OBJ_NAME_LEN]; /* rbd image name */
+	int			obj_len;
+	char			obj_md_name[RBD_MAX_MD_NAME_LEN]; /* hdr nm. */
+	char			pool_name[RBD_MAX_POOL_NAME_LEN];
+	int			poolid;
+
+	char                    snap_name[RBD_MAX_SNAP_NAME_LEN];
+	u32 cur_snap;	/* index+1 of current snapshot within snap context
+			   0 - for the head */
+	int read_only;
+
+	struct list_head	node;
+
+	/* list of snapshots */
+	struct list_head	snaps;
+
+	/* sysfs related */
+	struct device		dev;
+};
+
+static struct bus_type rbd_bus_type = {
+	.name		= "rbd",
+};
+
+static spinlock_t node_lock;      /* protects client get/put */
+
+static DEFINE_MUTEX(ctl_mutex);	  /* Serialize open/close/setup/teardown */
+static LIST_HEAD(rbd_dev_list);    /* devices */
+static LIST_HEAD(rbd_client_list);      /* clients */
+
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev);
+static void rbd_dev_release(struct device *dev);
+static ssize_t rbd_snap_rollback(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t size);
+static ssize_t rbd_snap_add(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf,
+			    size_t count);
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+				  struct rbd_snap *snap);;
+
+
+static struct rbd_device *dev_to_rbd(struct device *dev)
+{
+	return container_of(dev, struct rbd_device, dev);
+}
+
+static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
+{
+	return get_device(&rbd_dev->dev);
+}
+
+static void rbd_put_dev(struct rbd_device *rbd_dev)
+{
+	put_device(&rbd_dev->dev);
+}
+
+static int rbd_open(struct block_device *bdev, fmode_t mode)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	struct rbd_device *rbd_dev = disk->private_data;
+
+	rbd_get_dev(rbd_dev);
+
+	set_device_ro(bdev, rbd_dev->read_only);
+
+	if ((mode & FMODE_WRITE) && rbd_dev->read_only)
+		return -EROFS;
+
+	return 0;
+}
+
+static int rbd_release(struct gendisk *disk, fmode_t mode)
+{
+	struct rbd_device *rbd_dev = disk->private_data;
+
+	rbd_put_dev(rbd_dev);
+
+	return 0;
+}
+
+static const struct block_device_operations rbd_bd_ops = {
+	.owner			= THIS_MODULE,
+	.open			= rbd_open,
+	.release		= rbd_release,
+};
+
+/*
+ * Initialize an rbd client instance.
+ * We own *opt.
+ */
+static struct rbd_client *rbd_client_create(struct ceph_options *opt)
+{
+	struct rbd_client *rbdc;
+	int ret = -ENOMEM;
+
+	dout("rbd_client_create\n");
+	rbdc = kmalloc(sizeof(struct rbd_client), GFP_KERNEL);
+	if (!rbdc)
+		goto out_opt;
+
+	kref_init(&rbdc->kref);
+	INIT_LIST_HEAD(&rbdc->node);
+
+	rbdc->client = ceph_create_client(opt, rbdc);
+	if (IS_ERR(rbdc->client))
+		goto out_rbdc;
+	opt = NULL; /* Now rbdc->client is responsible for opt */
+
+	ret = ceph_open_session(rbdc->client);
+	if (ret < 0)
+		goto out_err;
+
+	spin_lock(&node_lock);
+	list_add_tail(&rbdc->node, &rbd_client_list);
+	spin_unlock(&node_lock);
+
+	dout("rbd_client_create created %p\n", rbdc);
+	return rbdc;
+
+out_err:
+	ceph_destroy_client(rbdc->client);
+out_rbdc:
+	kfree(rbdc);
+out_opt:
+	if (opt)
+		ceph_destroy_options(opt);
+	return ERR_PTR(ret);
+}
+
+/*
+ * Find a ceph client with specific addr and configuration.
+ */
+static struct rbd_client *__rbd_client_find(struct ceph_options *opt)
+{
+	struct rbd_client *client_node;
+
+	if (opt->flags & CEPH_OPT_NOSHARE)
+		return NULL;
+
+	list_for_each_entry(client_node, &rbd_client_list, node)
+		if (ceph_compare_options(opt, client_node->client) == 0)
+			return client_node;
+	return NULL;
+}
+
+/*
+ * Get a ceph client with specific addr and configuration, if one does
+ * not exist create it.
+ */
+static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
+			  char *options)
+{
+	struct rbd_client *rbdc;
+	struct ceph_options *opt;
+	int ret;
+
+	ret = ceph_parse_options(&opt, options, mon_addr,
+				 mon_addr + strlen(mon_addr), NULL, NULL);
+	if (ret < 0)
+		return ret;
+
+	spin_lock(&node_lock);
+	rbdc = __rbd_client_find(opt);
+	if (rbdc) {
+		ceph_destroy_options(opt);
+
+		/* using an existing client */
+		kref_get(&rbdc->kref);
+		rbd_dev->rbd_client = rbdc;
+		rbd_dev->client = rbdc->client;
+		spin_unlock(&node_lock);
+		return 0;
+	}
+	spin_unlock(&node_lock);
+
+	rbdc = rbd_client_create(opt);
+	if (IS_ERR(rbdc))
+		return PTR_ERR(rbdc);
+
+	rbd_dev->rbd_client = rbdc;
+	rbd_dev->client = rbdc->client;
+	return 0;
+}
+
+/*
+ * Destroy ceph client
+ */
+static void rbd_client_release(struct kref *kref)
+{
+	struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref);
+
+	dout("rbd_release_client %p\n", rbdc);
+	spin_lock(&node_lock);
+	list_del(&rbdc->node);
+	spin_unlock(&node_lock);
+
+	ceph_destroy_client(rbdc->client);
+	kfree(rbdc);
+}
+
+/*
+ * Drop reference to ceph client node. If it's not referenced anymore, release
+ * it.
+ */
+static void rbd_put_client(struct rbd_device *rbd_dev)
+{
+	kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
+	rbd_dev->rbd_client = NULL;
+	rbd_dev->client = NULL;
+}
+
+
+/*
+ * Create a new header structure, translate header format from the on-disk
+ * header.
+ */
+static int rbd_header_from_disk(struct rbd_image_header *header,
+				 struct rbd_image_header_ondisk *ondisk,
+				 int allocated_snaps,
+				 gfp_t gfp_flags)
+{
+	int i;
+	u32 snap_count = le32_to_cpu(ondisk->snap_count);
+	int ret = -ENOMEM;
+
+	init_rwsem(&header->snap_rwsem);
+	header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
+	header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
+				snap_count *
+				 sizeof(struct rbd_image_snap_ondisk),
+				gfp_flags);
+	if (!header->snapc)
+		return -ENOMEM;
+	if (snap_count) {
+		header->snap_names = kmalloc(header->snap_names_len,
+					     GFP_KERNEL);
+		if (!header->snap_names)
+			goto err_snapc;
+		header->snap_sizes = kmalloc(snap_count * sizeof(u64),
+					     GFP_KERNEL);
+		if (!header->snap_sizes)
+			goto err_names;
+	} else {
+		header->snap_names = NULL;
+		header->snap_sizes = NULL;
+	}
+	memcpy(header->block_name, ondisk->block_name,
+	       sizeof(ondisk->block_name));
+
+	header->image_size = le64_to_cpu(ondisk->image_size);
+	header->obj_order = ondisk->options.order;
+	header->crypt_type = ondisk->options.crypt_type;
+	header->comp_type = ondisk->options.comp_type;
+
+	atomic_set(&header->snapc->nref, 1);
+	header->snap_seq = le64_to_cpu(ondisk->snap_seq);
+	header->snapc->num_snaps = snap_count;
+	header->total_snaps = snap_count;
+
+	if (snap_count &&
+	    allocated_snaps == snap_count) {
+		for (i = 0; i < snap_count; i++) {
+			header->snapc->snaps[i] =
+				le64_to_cpu(ondisk->snaps[i].id);
+			header->snap_sizes[i] =
+				le64_to_cpu(ondisk->snaps[i].image_size);
+		}
+
+		/* copy snapshot names */
+		memcpy(header->snap_names, &ondisk->snaps[i],
+			header->snap_names_len);
+	}
+
+	return 0;
+
+err_names:
+	kfree(header->snap_names);
+err_snapc:
+	kfree(header->snapc);
+	return ret;
+}
+
+static int snap_index(struct rbd_image_header *header, int snap_num)
+{
+	return header->total_snaps - snap_num;
+}
+
+static u64 cur_snap_id(struct rbd_device *rbd_dev)
+{
+	struct rbd_image_header *header = &rbd_dev->header;
+
+	if (!rbd_dev->cur_snap)
+		return 0;
+
+	return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)];
+}
+
+static int snap_by_name(struct rbd_image_header *header, const char *snap_name,
+			u64 *seq, u64 *size)
+{
+	int i;
+	char *p = header->snap_names;
+
+	for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
+		if (strcmp(snap_name, p) == 0)
+			break;
+	}
+	if (i == header->total_snaps)
+		return -ENOENT;
+	if (seq)
+		*seq = header->snapc->snaps[i];
+
+	if (size)
+		*size = header->snap_sizes[i];
+
+	return i;
+}
+
+static int rbd_header_set_snap(struct rbd_device *dev,
+			       const char *snap_name,
+			       u64 *size)
+{
+	struct rbd_image_header *header = &dev->header;
+	struct ceph_snap_context *snapc = header->snapc;
+	int ret = -ENOENT;
+
+	down_write(&header->snap_rwsem);
+
+	if (!snap_name ||
+	    !*snap_name ||
+	    strcmp(snap_name, "-") == 0 ||
+	    strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) {
+		if (header->total_snaps)
+			snapc->seq = header->snap_seq;
+		else
+			snapc->seq = 0;
+		dev->cur_snap = 0;
+		dev->read_only = 0;
+		if (size)
+			*size = header->image_size;
+	} else {
+		ret = snap_by_name(header, snap_name, &snapc->seq, size);
+		if (ret < 0)
+			goto done;
+
+		dev->cur_snap = header->total_snaps - ret;
+		dev->read_only = 1;
+	}
+
+	ret = 0;
+done:
+	up_write(&header->snap_rwsem);
+	return ret;
+}
+
+static void rbd_header_free(struct rbd_image_header *header)
+{
+	kfree(header->snapc);
+	kfree(header->snap_names);
+	kfree(header->snap_sizes);
+}
+
+/*
+ * get the actual striped segment name, offset and length
+ */
+static u64 rbd_get_segment(struct rbd_image_header *header,
+			   const char *block_name,
+			   u64 ofs, u64 len,
+			   char *seg_name, u64 *segofs)
+{
+	u64 seg = ofs >> header->obj_order;
+
+	if (seg_name)
+		snprintf(seg_name, RBD_MAX_SEG_NAME_LEN,
+			 "%s.%012llx", block_name, seg);
+
+	ofs = ofs & ((1 << header->obj_order) - 1);
+	len = min_t(u64, len, (1 << header->obj_order) - ofs);
+
+	if (segofs)
+		*segofs = ofs;
+
+	return len;
+}
+
+/*
+ * bio helpers
+ */
+
+static void bio_chain_put(struct bio *chain)
+{
+	struct bio *tmp;
+
+	while (chain) {
+		tmp = chain;
+		chain = chain->bi_next;
+		bio_put(tmp);
+	}
+}
+
+/*
+ * zeros a bio chain, starting at specific offset
+ */
+static void zero_bio_chain(struct bio *chain, int start_ofs)
+{
+	struct bio_vec *bv;
+	unsigned long flags;
+	void *buf;
+	int i;
+	int pos = 0;
+
+	while (chain) {
+		bio_for_each_segment(bv, chain, i) {
+			if (pos + bv->bv_len > start_ofs) {
+				int remainder = max(start_ofs - pos, 0);
+				buf = bvec_kmap_irq(bv, &flags);
+				memset(buf + remainder, 0,
+				       bv->bv_len - remainder);
+				bvec_kunmap_irq(buf, &flags);
+			}
+			pos += bv->bv_len;
+		}
+
+		chain = chain->bi_next;
+	}
+}
+
+/*
+ * bio_chain_clone - clone a chain of bios up to a certain length.
+ * might return a bio_pair that will need to be released.
+ */
+static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
+				   struct bio_pair **bp,
+				   int len, gfp_t gfpmask)
+{
+	struct bio *tmp, *old_chain = *old, *new_chain = NULL, *tail = NULL;
+	int total = 0;
+
+	if (*bp) {
+		bio_pair_release(*bp);
+		*bp = NULL;
+	}
+
+	while (old_chain && (total < len)) {
+		tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
+		if (!tmp)
+			goto err_out;
+
+		if (total + old_chain->bi_size > len) {
+			struct bio_pair *bp;
+
+			/*
+			 * this split can only happen with a single paged bio,
+			 * split_bio will BUG_ON if this is not the case
+			 */
+			dout("bio_chain_clone split! total=%d remaining=%d"
+			     "bi_size=%d\n",
+			     (int)total, (int)len-total,
+			     (int)old_chain->bi_size);
+
+			/* split the bio. We'll release it either in the next
+			   call, or it will have to be released outside */
+			bp = bio_split(old_chain, (len - total) / 512ULL);
+			if (!bp)
+				goto err_out;
+
+			__bio_clone(tmp, &bp->bio1);
+
+			*next = &bp->bio2;
+		} else {
+			__bio_clone(tmp, old_chain);
+			*next = old_chain->bi_next;
+		}
+
+		tmp->bi_bdev = NULL;
+		gfpmask &= ~__GFP_WAIT;
+		tmp->bi_next = NULL;
+
+		if (!new_chain) {
+			new_chain = tail = tmp;
+		} else {
+			tail->bi_next = tmp;
+			tail = tmp;
+		}
+		old_chain = old_chain->bi_next;
+
+		total += tmp->bi_size;
+	}
+
+	BUG_ON(total < len);
+
+	if (tail)
+		tail->bi_next = NULL;
+
+	*old = old_chain;
+
+	return new_chain;
+
+err_out:
+	dout("bio_chain_clone with err\n");
+	bio_chain_put(new_chain);
+	return NULL;
+}
+
+/*
+ * helpers for osd request op vectors.
+ */
+static int rbd_create_rw_ops(struct ceph_osd_req_op **ops,
+			    int num_ops,
+			    int opcode,
+			    u32 payload_len)
+{
+	*ops = kzalloc(sizeof(struct ceph_osd_req_op) * (num_ops + 1),
+		       GFP_NOIO);
+	if (!*ops)
+		return -ENOMEM;
+	(*ops)[0].op = opcode;
+	/*
+	 * op extent offset and length will be set later on
+	 * in calc_raw_layout()
+	 */
+	(*ops)[0].payload_len = payload_len;
+	return 0;
+}
+
+static void rbd_destroy_ops(struct ceph_osd_req_op *ops)
+{
+	kfree(ops);
+}
+
+/*
+ * Send ceph osd request
+ */
+static int rbd_do_request(struct request *rq,
+			  struct rbd_device *dev,
+			  struct ceph_snap_context *snapc,
+			  u64 snapid,
+			  const char *obj, u64 ofs, u64 len,
+			  struct bio *bio,
+			  struct page **pages,
+			  int num_pages,
+			  int flags,
+			  struct ceph_osd_req_op *ops,
+			  int num_reply,
+			  void (*rbd_cb)(struct ceph_osd_request *req,
+					 struct ceph_msg *msg))
+{
+	struct ceph_osd_request *req;
+	struct ceph_file_layout *layout;
+	int ret;
+	u64 bno;
+	struct timespec mtime = CURRENT_TIME;
+	struct rbd_request *req_data;
+	struct ceph_osd_request_head *reqhead;
+	struct rbd_image_header *header = &dev->header;
+
+	ret = -ENOMEM;
+	req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
+	if (!req_data)
+		goto done;
+
+	dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs);
+
+	down_read(&header->snap_rwsem);
+
+	req = ceph_osdc_alloc_request(&dev->client->osdc, flags,
+				      snapc,
+				      ops,
+				      false,
+				      GFP_NOIO, pages, bio);
+	if (IS_ERR(req)) {
+		up_read(&header->snap_rwsem);
+		ret = PTR_ERR(req);
+		goto done_pages;
+	}
+
+	req->r_callback = rbd_cb;
+
+	req_data->rq = rq;
+	req_data->bio = bio;
+	req_data->pages = pages;
+	req_data->len = len;
+
+	req->r_priv = req_data;
+
+	reqhead = req->r_request->front.iov_base;
+	reqhead->snapid = cpu_to_le64(CEPH_NOSNAP);
+
+	strncpy(req->r_oid, obj, sizeof(req->r_oid));
+	req->r_oid_len = strlen(req->r_oid);
+
+	layout = &req->r_file_layout;
+	memset(layout, 0, sizeof(*layout));
+	layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
+	layout->fl_stripe_count = cpu_to_le32(1);
+	layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
+	layout->fl_pg_preferred = cpu_to_le32(-1);
+	layout->fl_pg_pool = cpu_to_le32(dev->poolid);
+	ceph_calc_raw_layout(&dev->client->osdc, layout, snapid,
+			     ofs, &len, &bno, req, ops);
+
+	ceph_osdc_build_request(req, ofs, &len,
+				ops,
+				snapc,
+				&mtime,
+				req->r_oid, req->r_oid_len);
+	up_read(&header->snap_rwsem);
+
+	ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
+	if (ret < 0)
+		goto done_err;
+
+	if (!rbd_cb) {
+		ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+		ceph_osdc_put_request(req);
+	}
+	return ret;
+
+done_err:
+	bio_chain_put(req_data->bio);
+	ceph_osdc_put_request(req);
+done_pages:
+	kfree(req_data);
+done:
+	if (rq)
+		blk_end_request(rq, ret, len);
+	return ret;
+}
+
+/*
+ * Ceph osd op callback
+ */
+static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
+{
+	struct rbd_request *req_data = req->r_priv;
+	struct ceph_osd_reply_head *replyhead;
+	struct ceph_osd_op *op;
+	__s32 rc;
+	u64 bytes;
+	int read_op;
+
+	/* parse reply */
+	replyhead = msg->front.iov_base;
+	WARN_ON(le32_to_cpu(replyhead->num_ops) == 0);
+	op = (void *)(replyhead + 1);
+	rc = le32_to_cpu(replyhead->result);
+	bytes = le64_to_cpu(op->extent.length);
+	read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ);
+
+	dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc);
+
+	if (rc == -ENOENT && read_op) {
+		zero_bio_chain(req_data->bio, 0);
+		rc = 0;
+	} else if (rc == 0 && read_op && bytes < req_data->len) {
+		zero_bio_chain(req_data->bio, bytes);
+		bytes = req_data->len;
+	}
+
+	blk_end_request(req_data->rq, rc, bytes);
+
+	if (req_data->bio)
+		bio_chain_put(req_data->bio);
+
+	ceph_osdc_put_request(req);
+	kfree(req_data);
+}
+
+/*
+ * Do a synchronous ceph osd operation
+ */
+static int rbd_req_sync_op(struct rbd_device *dev,
+			   struct ceph_snap_context *snapc,
+			   u64 snapid,
+			   int opcode,
+			   int flags,
+			   struct ceph_osd_req_op *orig_ops,
+			   int num_reply,
+			   const char *obj,
+			   u64 ofs, u64 len,
+			   char *buf)
+{
+	int ret;
+	struct page **pages;
+	int num_pages;
+	struct ceph_osd_req_op *ops = orig_ops;
+	u32 payload_len;
+
+	num_pages = calc_pages_for(ofs , len);
+	pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	if (!orig_ops) {
+		payload_len = (flags & CEPH_OSD_FLAG_WRITE ? len : 0);
+		ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
+		if (ret < 0)
+			goto done;
+
+		if ((flags & CEPH_OSD_FLAG_WRITE) && buf) {
+			ret = ceph_copy_to_page_vector(pages, buf, ofs, len);
+			if (ret < 0)
+				goto done_ops;
+		}
+	}
+
+	ret = rbd_do_request(NULL, dev, snapc, snapid,
+			  obj, ofs, len, NULL,
+			  pages, num_pages,
+			  flags,
+			  ops,
+			  2,
+			  NULL);
+	if (ret < 0)
+		goto done_ops;
+
+	if ((flags & CEPH_OSD_FLAG_READ) && buf)
+		ret = ceph_copy_from_page_vector(pages, buf, ofs, ret);
+
+done_ops:
+	if (!orig_ops)
+		rbd_destroy_ops(ops);
+done:
+	ceph_release_page_vector(pages, num_pages);
+	return ret;
+}
+
+/*
+ * Do an asynchronous ceph osd operation
+ */
+static int rbd_do_op(struct request *rq,
+		     struct rbd_device *rbd_dev ,
+		     struct ceph_snap_context *snapc,
+		     u64 snapid,
+		     int opcode, int flags, int num_reply,
+		     u64 ofs, u64 len,
+		     struct bio *bio)
+{
+	char *seg_name;
+	u64 seg_ofs;
+	u64 seg_len;
+	int ret;
+	struct ceph_osd_req_op *ops;
+	u32 payload_len;
+
+	seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+	if (!seg_name)
+		return -ENOMEM;
+
+	seg_len = rbd_get_segment(&rbd_dev->header,
+				  rbd_dev->header.block_name,
+				  ofs, len,
+				  seg_name, &seg_ofs);
+
+	payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0);
+
+	ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
+	if (ret < 0)
+		goto done;
+
+	/* we've taken care of segment sizes earlier when we
+	   cloned the bios. We should never have a segment
+	   truncated at this point */
+	BUG_ON(seg_len < len);
+
+	ret = rbd_do_request(rq, rbd_dev, snapc, snapid,
+			     seg_name, seg_ofs, seg_len,
+			     bio,
+			     NULL, 0,
+			     flags,
+			     ops,
+			     num_reply,
+			     rbd_req_cb);
+done:
+	kfree(seg_name);
+	return ret;
+}
+
+/*
+ * Request async osd write
+ */
+static int rbd_req_write(struct request *rq,
+			 struct rbd_device *rbd_dev,
+			 struct ceph_snap_context *snapc,
+			 u64 ofs, u64 len,
+			 struct bio *bio)
+{
+	return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP,
+			 CEPH_OSD_OP_WRITE,
+			 CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+			 2,
+			 ofs, len, bio);
+}
+
+/*
+ * Request async osd read
+ */
+static int rbd_req_read(struct request *rq,
+			 struct rbd_device *rbd_dev,
+			 u64 snapid,
+			 u64 ofs, u64 len,
+			 struct bio *bio)
+{
+	return rbd_do_op(rq, rbd_dev, NULL,
+			 (snapid ? snapid : CEPH_NOSNAP),
+			 CEPH_OSD_OP_READ,
+			 CEPH_OSD_FLAG_READ,
+			 2,
+			 ofs, len, bio);
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_read(struct rbd_device *dev,
+			  struct ceph_snap_context *snapc,
+			  u64 snapid,
+			  const char *obj,
+			  u64 ofs, u64 len,
+			  char *buf)
+{
+	return rbd_req_sync_op(dev, NULL,
+			       (snapid ? snapid : CEPH_NOSNAP),
+			       CEPH_OSD_OP_READ,
+			       CEPH_OSD_FLAG_READ,
+			       NULL,
+			       1, obj, ofs, len, buf);
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_rollback_obj(struct rbd_device *dev,
+				     u64 snapid,
+				     const char *obj)
+{
+	struct ceph_osd_req_op *ops;
+	int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_ROLLBACK, 0);
+	if (ret < 0)
+		return ret;
+
+	ops[0].snap.snapid = snapid;
+
+	ret = rbd_req_sync_op(dev, NULL,
+			       CEPH_NOSNAP,
+			       0,
+			       CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+			       ops,
+			       1, obj, 0, 0, NULL);
+
+	rbd_destroy_ops(ops);
+
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_exec(struct rbd_device *dev,
+			     const char *obj,
+			     const char *cls,
+			     const char *method,
+			     const char *data,
+			     int len)
+{
+	struct ceph_osd_req_op *ops;
+	int cls_len = strlen(cls);
+	int method_len = strlen(method);
+	int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_CALL,
+				    cls_len + method_len + len);
+	if (ret < 0)
+		return ret;
+
+	ops[0].cls.class_name = cls;
+	ops[0].cls.class_len = (__u8)cls_len;
+	ops[0].cls.method_name = method;
+	ops[0].cls.method_len = (__u8)method_len;
+	ops[0].cls.argc = 0;
+	ops[0].cls.indata = data;
+	ops[0].cls.indata_len = len;
+
+	ret = rbd_req_sync_op(dev, NULL,
+			       CEPH_NOSNAP,
+			       0,
+			       CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+			       ops,
+			       1, obj, 0, 0, NULL);
+
+	rbd_destroy_ops(ops);
+
+	dout("cls_exec returned %d\n", ret);
+	return ret;
+}
+
+/*
+ * block device queue callback
+ */
+static void rbd_rq_fn(struct request_queue *q)
+{
+	struct rbd_device *rbd_dev = q->queuedata;
+	struct request *rq;
+	struct bio_pair *bp = NULL;
+
+	rq = blk_fetch_request(q);
+
+	while (1) {
+		struct bio *bio;
+		struct bio *rq_bio, *next_bio = NULL;
+		bool do_write;
+		int size, op_size = 0;
+		u64 ofs;
+
+		/* peek at request from block layer */
+		if (!rq)
+			break;
+
+		dout("fetched request\n");
+
+		/* filter out block requests we don't understand */
+		if ((rq->cmd_type != REQ_TYPE_FS)) {
+			__blk_end_request_all(rq, 0);
+			goto next;
+		}
+
+		/* deduce our operation (read, write) */
+		do_write = (rq_data_dir(rq) == WRITE);
+
+		size = blk_rq_bytes(rq);
+		ofs = blk_rq_pos(rq) * 512ULL;
+		rq_bio = rq->bio;
+		if (do_write && rbd_dev->read_only) {
+			__blk_end_request_all(rq, -EROFS);
+			goto next;
+		}
+
+		spin_unlock_irq(q->queue_lock);
+
+		dout("%s 0x%x bytes at 0x%llx\n",
+		     do_write ? "write" : "read",
+		     size, blk_rq_pos(rq) * 512ULL);
+
+		do {
+			/* a bio clone to be passed down to OSD req */
+			dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt);
+			op_size = rbd_get_segment(&rbd_dev->header,
+						  rbd_dev->header.block_name,
+						  ofs, size,
+						  NULL, NULL);
+			bio = bio_chain_clone(&rq_bio, &next_bio, &bp,
+					      op_size, GFP_ATOMIC);
+			if (!bio) {
+				spin_lock_irq(q->queue_lock);
+				__blk_end_request_all(rq, -ENOMEM);
+				goto next;
+			}
+
+			/* init OSD command: write or read */
+			if (do_write)
+				rbd_req_write(rq, rbd_dev,
+					      rbd_dev->header.snapc,
+					      ofs,
+					      op_size, bio);
+			else
+				rbd_req_read(rq, rbd_dev,
+					     cur_snap_id(rbd_dev),
+					     ofs,
+					     op_size, bio);
+
+			size -= op_size;
+			ofs += op_size;
+
+			rq_bio = next_bio;
+		} while (size > 0);
+
+		if (bp)
+			bio_pair_release(bp);
+
+		spin_lock_irq(q->queue_lock);
+next:
+		rq = blk_fetch_request(q);
+	}
+}
+
+/*
+ * a queue callback. Makes sure that we don't create a bio that spans across
+ * multiple osd objects. One exception would be with a single page bios,
+ * which we handle later at bio_chain_clone
+ */
+static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
+			  struct bio_vec *bvec)
+{
+	struct rbd_device *rbd_dev = q->queuedata;
+	unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9);
+	sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
+	unsigned int bio_sectors = bmd->bi_size >> 9;
+	int max;
+
+	max =  (chunk_sectors - ((sector & (chunk_sectors - 1))
+				 + bio_sectors)) << 9;
+	if (max < 0)
+		max = 0; /* bio_add cannot handle a negative return */
+	if (max <= bvec->bv_len && bio_sectors == 0)
+		return bvec->bv_len;
+	return max;
+}
+
+static void rbd_free_disk(struct rbd_device *rbd_dev)
+{
+	struct gendisk *disk = rbd_dev->disk;
+
+	if (!disk)
+		return;
+
+	rbd_header_free(&rbd_dev->header);
+
+	if (disk->flags & GENHD_FL_UP)
+		del_gendisk(disk);
+	if (disk->queue)
+		blk_cleanup_queue(disk->queue);
+	put_disk(disk);
+}
+
+/*
+ * reload the ondisk the header 
+ */
+static int rbd_read_header(struct rbd_device *rbd_dev,
+			   struct rbd_image_header *header)
+{
+	ssize_t rc;
+	struct rbd_image_header_ondisk *dh;
+	int snap_count = 0;
+	u64 snap_names_len = 0;
+
+	while (1) {
+		int len = sizeof(*dh) +
+			  snap_count * sizeof(struct rbd_image_snap_ondisk) +
+			  snap_names_len;
+
+		rc = -ENOMEM;
+		dh = kmalloc(len, GFP_KERNEL);
+		if (!dh)
+			return -ENOMEM;
+
+		rc = rbd_req_sync_read(rbd_dev,
+				       NULL, CEPH_NOSNAP,
+				       rbd_dev->obj_md_name,
+				       0, len,
+				       (char *)dh);
+		if (rc < 0)
+			goto out_dh;
+
+		rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
+		if (rc < 0)
+			goto out_dh;
+
+		if (snap_count != header->total_snaps) {
+			snap_count = header->total_snaps;
+			snap_names_len = header->snap_names_len;
+			rbd_header_free(header);
+			kfree(dh);
+			continue;
+		}
+		break;
+	}
+
+out_dh:
+	kfree(dh);
+	return rc;
+}
+
+/*
+ * create a snapshot
+ */
+static int rbd_header_add_snap(struct rbd_device *dev,
+			       const char *snap_name,
+			       gfp_t gfp_flags)
+{
+	int name_len = strlen(snap_name);
+	u64 new_snapid;
+	int ret;
+	void *data, *data_start, *data_end;
+
+	/* we should create a snapshot only if we're pointing at the head */
+	if (dev->cur_snap)
+		return -EINVAL;
+
+	ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid,
+				      &new_snapid);
+	dout("created snapid=%lld\n", new_snapid);
+	if (ret < 0)
+		return ret;
+
+	data = kmalloc(name_len + 16, gfp_flags);
+	if (!data)
+		return -ENOMEM;
+
+	data_start = data;
+	data_end = data + name_len + 16;
+
+	ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad);
+	ceph_encode_64_safe(&data, data_end, new_snapid, bad);
+
+	ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
+				data_start, data - data_start);
+
+	kfree(data_start);
+
+	if (ret < 0)
+		return ret;
+
+	dev->header.snapc->seq =  new_snapid;
+
+	return 0;
+bad:
+	return -ERANGE;
+}
+
+static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev)
+{
+	struct rbd_snap *snap;
+
+	while (!list_empty(&rbd_dev->snaps)) {
+		snap = list_first_entry(&rbd_dev->snaps, struct rbd_snap, node);
+		__rbd_remove_snap_dev(rbd_dev, snap);
+	}
+}
+
+/*
+ * only read the first part of the ondisk header, without the snaps info
+ */
+static int __rbd_update_snaps(struct rbd_device *rbd_dev)
+{
+	int ret;
+	struct rbd_image_header h;
+	u64 snap_seq;
+
+	ret = rbd_read_header(rbd_dev, &h);
+	if (ret < 0)
+		return ret;
+
+	down_write(&rbd_dev->header.snap_rwsem);
+
+	snap_seq = rbd_dev->header.snapc->seq;
+
+	kfree(rbd_dev->header.snapc);
+	kfree(rbd_dev->header.snap_names);
+	kfree(rbd_dev->header.snap_sizes);
+
+	rbd_dev->header.total_snaps = h.total_snaps;
+	rbd_dev->header.snapc = h.snapc;
+	rbd_dev->header.snap_names = h.snap_names;
+	rbd_dev->header.snap_names_len = h.snap_names_len;
+	rbd_dev->header.snap_sizes = h.snap_sizes;
+	rbd_dev->header.snapc->seq = snap_seq;
+
+	ret = __rbd_init_snaps_header(rbd_dev);
+
+	up_write(&rbd_dev->header.snap_rwsem);
+
+	return ret;
+}
+
+static int rbd_init_disk(struct rbd_device *rbd_dev)
+{
+	struct gendisk *disk;
+	struct request_queue *q;
+	int rc;
+	u64 total_size = 0;
+
+	/* contact OSD, request size info about the object being mapped */
+	rc = rbd_read_header(rbd_dev, &rbd_dev->header);
+	if (rc)
+		return rc;
+
+	/* no need to lock here, as rbd_dev is not registered yet */
+	rc = __rbd_init_snaps_header(rbd_dev);
+	if (rc)
+		return rc;
+
+	rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
+	if (rc)
+		return rc;
+
+	/* create gendisk info */
+	rc = -ENOMEM;
+	disk = alloc_disk(RBD_MINORS_PER_MAJOR);
+	if (!disk)
+		goto out;
+
+	sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id);
+	disk->major = rbd_dev->major;
+	disk->first_minor = 0;
+	disk->fops = &rbd_bd_ops;
+	disk->private_data = rbd_dev;
+
+	/* init rq */
+	rc = -ENOMEM;
+	q = blk_init_queue(rbd_rq_fn, &rbd_dev->lock);
+	if (!q)
+		goto out_disk;
+	blk_queue_merge_bvec(q, rbd_merge_bvec);
+	disk->queue = q;
+
+	q->queuedata = rbd_dev;
+
+	rbd_dev->disk = disk;
+	rbd_dev->q = q;
+
+	/* finally, announce the disk to the world */
+	set_capacity(disk, total_size / 512ULL);
+	add_disk(disk);
+
+	pr_info("%s: added with size 0x%llx\n",
+		disk->disk_name, (unsigned long long)total_size);
+	return 0;
+
+out_disk:
+	put_disk(disk);
+out:
+	return rc;
+}
+
+/*
+  sysfs
+*/
+
+static ssize_t rbd_size_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "%llu\n", (unsigned long long)rbd_dev->header.image_size);
+}
+
+static ssize_t rbd_major_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "%d\n", rbd_dev->major);
+}
+
+static ssize_t rbd_client_id_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "client%lld\n", ceph_client_id(rbd_dev->client));
+}
+
+static ssize_t rbd_pool_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "%s\n", rbd_dev->pool_name);
+}
+
+static ssize_t rbd_name_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "%s\n", rbd_dev->obj);
+}
+
+static ssize_t rbd_snap_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+
+	return sprintf(buf, "%s\n", rbd_dev->snap_name);
+}
+
+static ssize_t rbd_image_refresh(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t size)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	int rc;
+	int ret = size;
+
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+	rc = __rbd_update_snaps(rbd_dev);
+	if (rc < 0)
+		ret = rc;
+
+	mutex_unlock(&ctl_mutex);
+	return ret;
+}
+
+static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
+static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
+static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
+static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
+static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
+static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
+static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
+static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add);
+static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback);
+
+static struct attribute *rbd_attrs[] = {
+	&dev_attr_size.attr,
+	&dev_attr_major.attr,
+	&dev_attr_client_id.attr,
+	&dev_attr_pool.attr,
+	&dev_attr_name.attr,
+	&dev_attr_current_snap.attr,
+	&dev_attr_refresh.attr,
+	&dev_attr_create_snap.attr,
+	&dev_attr_rollback_snap.attr,
+	NULL
+};
+
+static struct attribute_group rbd_attr_group = {
+	.attrs = rbd_attrs,
+};
+
+static const struct attribute_group *rbd_attr_groups[] = {
+	&rbd_attr_group,
+	NULL
+};
+
+static void rbd_sysfs_dev_release(struct device *dev)
+{
+}
+
+static struct device_type rbd_device_type = {
+	.name		= "rbd",
+	.groups		= rbd_attr_groups,
+	.release	= rbd_sysfs_dev_release,
+};
+
+
+/*
+  sysfs - snapshots
+*/
+
+static ssize_t rbd_snap_size_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *buf)
+{
+	struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+	return sprintf(buf, "%lld\n", (long long)snap->size);
+}
+
+static ssize_t rbd_snap_id_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+
+	return sprintf(buf, "%lld\n", (long long)snap->id);
+}
+
+static DEVICE_ATTR(snap_size, S_IRUGO, rbd_snap_size_show, NULL);
+static DEVICE_ATTR(snap_id, S_IRUGO, rbd_snap_id_show, NULL);
+
+static struct attribute *rbd_snap_attrs[] = {
+	&dev_attr_snap_size.attr,
+	&dev_attr_snap_id.attr,
+	NULL,
+};
+
+static struct attribute_group rbd_snap_attr_group = {
+	.attrs = rbd_snap_attrs,
+};
+
+static void rbd_snap_dev_release(struct device *dev)
+{
+	struct rbd_snap *snap = container_of(dev, struct rbd_snap, dev);
+	kfree(snap->name);
+	kfree(snap);
+}
+
+static const struct attribute_group *rbd_snap_attr_groups[] = {
+	&rbd_snap_attr_group,
+	NULL
+};
+
+static struct device_type rbd_snap_device_type = {
+	.groups		= rbd_snap_attr_groups,
+	.release	= rbd_snap_dev_release,
+};
+
+static void __rbd_remove_snap_dev(struct rbd_device *rbd_dev,
+				  struct rbd_snap *snap)
+{
+	list_del(&snap->node);
+	device_unregister(&snap->dev);
+}
+
+static int rbd_register_snap_dev(struct rbd_device *rbd_dev,
+				  struct rbd_snap *snap,
+				  struct device *parent)
+{
+	struct device *dev = &snap->dev;
+	int ret;
+
+	dev->type = &rbd_snap_device_type;
+	dev->parent = parent;
+	dev->release = rbd_snap_dev_release;
+	dev_set_name(dev, "snap_%s", snap->name);
+	ret = device_register(dev);
+
+	return ret;
+}
+
+static int __rbd_add_snap_dev(struct rbd_device *rbd_dev,
+			      int i, const char *name,
+			      struct rbd_snap **snapp)
+{
+	int ret;
+	struct rbd_snap *snap = kzalloc(sizeof(*snap), GFP_KERNEL);
+	if (!snap)
+		return -ENOMEM;
+	snap->name = kstrdup(name, GFP_KERNEL);
+	snap->size = rbd_dev->header.snap_sizes[i];
+	snap->id = rbd_dev->header.snapc->snaps[i];
+	if (device_is_registered(&rbd_dev->dev)) {
+		ret = rbd_register_snap_dev(rbd_dev, snap,
+					     &rbd_dev->dev);
+		if (ret < 0)
+			goto err;
+	}
+	*snapp = snap;
+	return 0;
+err:
+	kfree(snap->name);
+	kfree(snap);
+	return ret;
+}
+
+/*
+ * search for the previous snap in a null delimited string list
+ */
+const char *rbd_prev_snap_name(const char *name, const char *start)
+{
+	if (name < start + 2)
+		return NULL;
+
+	name -= 2;
+	while (*name) {
+		if (name == start)
+			return start;
+		name--;
+	}
+	return name + 1;
+}
+
+/*
+ * compare the old list of snapshots that we have to what's in the header
+ * and update it accordingly. Note that the header holds the snapshots
+ * in a reverse order (from newest to oldest) and we need to go from
+ * older to new so that we don't get a duplicate snap name when
+ * doing the process (e.g., removed snapshot and recreated a new
+ * one with the same name.
+ */
+static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
+{
+	const char *name, *first_name;
+	int i = rbd_dev->header.total_snaps;
+	struct rbd_snap *snap, *old_snap = NULL;
+	int ret;
+	struct list_head *p, *n;
+
+	first_name = rbd_dev->header.snap_names;
+	name = first_name + rbd_dev->header.snap_names_len;
+
+	list_for_each_prev_safe(p, n, &rbd_dev->snaps) {
+		u64 cur_id;
+
+		old_snap = list_entry(p, struct rbd_snap, node);
+
+		if (i)
+			cur_id = rbd_dev->header.snapc->snaps[i - 1];
+
+		if (!i || old_snap->id < cur_id) {
+			/* old_snap->id was skipped, thus was removed */
+			__rbd_remove_snap_dev(rbd_dev, old_snap);
+			continue;
+		}
+		if (old_snap->id == cur_id) {
+			/* we have this snapshot already */
+			i--;
+			name = rbd_prev_snap_name(name, first_name);
+			continue;
+		}
+		for (; i > 0;
+		     i--, name = rbd_prev_snap_name(name, first_name)) {
+			if (!name) {
+				WARN_ON(1);
+				return -EINVAL;
+			}
+			cur_id = rbd_dev->header.snapc->snaps[i];
+			/* snapshot removal? handle it above */
+			if (cur_id >= old_snap->id)
+				break;
+			/* a new snapshot */
+			ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+			if (ret < 0)
+				return ret;
+
+			/* note that we add it backward so using n and not p */
+			list_add(&snap->node, n);
+			p = &snap->node;
+		}
+	}
+	/* we're done going over the old snap list, just add what's left */
+	for (; i > 0; i--) {
+		name = rbd_prev_snap_name(name, first_name);
+		if (!name) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+		ret = __rbd_add_snap_dev(rbd_dev, i - 1, name, &snap);
+		if (ret < 0)
+			return ret;
+		list_add(&snap->node, &rbd_dev->snaps);
+	}
+
+	return 0;
+}
+
+
+static void rbd_root_dev_release(struct device *dev)
+{
+}
+
+static struct device rbd_root_dev = {
+	.init_name =    "rbd",
+	.release =      rbd_root_dev_release,
+};
+
+static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
+{
+	int ret = -ENOMEM;
+	struct device *dev;
+	struct rbd_snap *snap;
+
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+	dev = &rbd_dev->dev;
+
+	dev->bus = &rbd_bus_type;
+	dev->type = &rbd_device_type;
+	dev->parent = &rbd_root_dev;
+	dev->release = rbd_dev_release;
+	dev_set_name(dev, "%d", rbd_dev->id);
+	ret = device_register(dev);
+	if (ret < 0)
+		goto done_free;
+
+	list_for_each_entry(snap, &rbd_dev->snaps, node) {
+		ret = rbd_register_snap_dev(rbd_dev, snap,
+					     &rbd_dev->dev);
+		if (ret < 0)
+			break;
+	}
+
+	mutex_unlock(&ctl_mutex);
+	return 0;
+done_free:
+	mutex_unlock(&ctl_mutex);
+	return ret;
+}
+
+static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
+{
+	device_unregister(&rbd_dev->dev);
+}
+
+static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count)
+{
+	struct ceph_osd_client *osdc;
+	struct rbd_device *rbd_dev;
+	ssize_t rc = -ENOMEM;
+	int irc, new_id = 0;
+	struct list_head *tmp;
+	char *mon_dev_name;
+	char *options;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
+	if (!mon_dev_name)
+		goto err_out_mod;
+
+	options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
+	if (!options)
+		goto err_mon_dev;
+
+	/* new rbd_device object */
+	rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
+	if (!rbd_dev)
+		goto err_out_opt;
+
+	/* static rbd_device initialization */
+	spin_lock_init(&rbd_dev->lock);
+	INIT_LIST_HEAD(&rbd_dev->node);
+	INIT_LIST_HEAD(&rbd_dev->snaps);
+
+	/* generate unique id: find highest unique id, add one */
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+	list_for_each(tmp, &rbd_dev_list) {
+		struct rbd_device *rbd_dev;
+
+		rbd_dev = list_entry(tmp, struct rbd_device, node);
+		if (rbd_dev->id >= new_id)
+			new_id = rbd_dev->id + 1;
+	}
+
+	rbd_dev->id = new_id;
+
+	/* add to global list */
+	list_add_tail(&rbd_dev->node, &rbd_dev_list);
+
+	/* parse add command */
+	if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s "
+		   "%" __stringify(RBD_MAX_OPT_LEN) "s "
+		   "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s "
+		   "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s"
+		   "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
+		   mon_dev_name, options, rbd_dev->pool_name,
+		   rbd_dev->obj, rbd_dev->snap_name) < 4) {
+		rc = -EINVAL;
+		goto err_out_slot;
+	}
+
+	if (rbd_dev->snap_name[0] == 0)
+		rbd_dev->snap_name[0] = '-';
+
+	rbd_dev->obj_len = strlen(rbd_dev->obj);
+	snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
+		 rbd_dev->obj, RBD_SUFFIX);
+
+	/* initialize rest of new object */
+	snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id);
+	rc = rbd_get_client(rbd_dev, mon_dev_name, options);
+	if (rc < 0)
+		goto err_out_slot;
+
+	mutex_unlock(&ctl_mutex);
+
+	/* pick the pool */
+	osdc = &rbd_dev->client->osdc;
+	rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
+	if (rc < 0)
+		goto err_out_client;
+	rbd_dev->poolid = rc;
+
+	/* register our block device */
+	irc = register_blkdev(0, rbd_dev->name);
+	if (irc < 0) {
+		rc = irc;
+		goto err_out_client;
+	}
+	rbd_dev->major = irc;
+
+	rc = rbd_bus_add_dev(rbd_dev);
+	if (rc)
+		goto err_out_disk;
+	/* set up and announce blkdev mapping */
+	rc = rbd_init_disk(rbd_dev);
+	if (rc)
+		goto err_out_blkdev;
+
+	return count;
+
+err_out_blkdev:
+	unregister_blkdev(rbd_dev->major, rbd_dev->name);
+err_out_disk:
+	rbd_free_disk(rbd_dev);
+err_out_client:
+	rbd_put_client(rbd_dev);
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+err_out_slot:
+	list_del_init(&rbd_dev->node);
+	mutex_unlock(&ctl_mutex);
+
+	kfree(rbd_dev);
+err_out_opt:
+	kfree(options);
+err_mon_dev:
+	kfree(mon_dev_name);
+err_out_mod:
+	dout("Error adding device %s\n", buf);
+	module_put(THIS_MODULE);
+	return rc;
+}
+
+static struct rbd_device *__rbd_get_dev(unsigned long id)
+{
+	struct list_head *tmp;
+	struct rbd_device *rbd_dev;
+
+	list_for_each(tmp, &rbd_dev_list) {
+		rbd_dev = list_entry(tmp, struct rbd_device, node);
+		if (rbd_dev->id == id)
+			return rbd_dev;
+	}
+	return NULL;
+}
+
+static void rbd_dev_release(struct device *dev)
+{
+	struct rbd_device *rbd_dev =
+			container_of(dev, struct rbd_device, dev);
+
+	rbd_put_client(rbd_dev);
+
+	/* clean up and free blkdev */
+	rbd_free_disk(rbd_dev);
+	unregister_blkdev(rbd_dev->major, rbd_dev->name);
+	kfree(rbd_dev);
+
+	/* release module ref */
+	module_put(THIS_MODULE);
+}
+
+static ssize_t rbd_remove(struct bus_type *bus,
+			  const char *buf,
+			  size_t count)
+{
+	struct rbd_device *rbd_dev = NULL;
+	int target_id, rc;
+	unsigned long ul;
+	int ret = count;
+
+	rc = strict_strtoul(buf, 10, &ul);
+	if (rc)
+		return rc;
+
+	/* convert to int; abort if we lost anything in the conversion */
+	target_id = (int) ul;
+	if (target_id != ul)
+		return -EINVAL;
+
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+	rbd_dev = __rbd_get_dev(target_id);
+	if (!rbd_dev) {
+		ret = -ENOENT;
+		goto done;
+	}
+
+	list_del_init(&rbd_dev->node);
+
+	__rbd_remove_all_snaps(rbd_dev);
+	rbd_bus_del_dev(rbd_dev);
+
+done:
+	mutex_unlock(&ctl_mutex);
+	return ret;
+}
+
+static ssize_t rbd_snap_add(struct device *dev,
+			    struct device_attribute *attr,
+			    const char *buf,
+			    size_t count)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	int ret;
+	char *name = kmalloc(count + 1, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	snprintf(name, count, "%s", buf);
+
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+	ret = rbd_header_add_snap(rbd_dev,
+				  name, GFP_KERNEL);
+	if (ret < 0)
+		goto done_unlock;
+
+	ret = __rbd_update_snaps(rbd_dev);
+	if (ret < 0)
+		goto done_unlock;
+
+	ret = count;
+done_unlock:
+	mutex_unlock(&ctl_mutex);
+	kfree(name);
+	return ret;
+}
+
+static ssize_t rbd_snap_rollback(struct device *dev,
+				 struct device_attribute *attr,
+				 const char *buf,
+				 size_t count)
+{
+	struct rbd_device *rbd_dev = dev_to_rbd(dev);
+	int ret;
+	u64 snapid;
+	u64 cur_ofs;
+	char *seg_name = NULL;
+	char *snap_name = kmalloc(count + 1, GFP_KERNEL);
+	ret = -ENOMEM;
+	if (!snap_name)
+		return ret;
+
+	/* parse snaps add command */
+	snprintf(snap_name, count, "%s", buf);
+	seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+	if (!seg_name)
+		goto done;
+
+	mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+	ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL);
+	if (ret < 0)
+		goto done_unlock;
+
+	dout("snapid=%lld\n", snapid);
+
+	cur_ofs = 0;
+	while (cur_ofs < rbd_dev->header.image_size) {
+		cur_ofs += rbd_get_segment(&rbd_dev->header,
+					   rbd_dev->obj,
+					   cur_ofs, (u64)-1,
+					   seg_name, NULL);
+		dout("seg_name=%s\n", seg_name);
+
+		ret = rbd_req_sync_rollback_obj(rbd_dev, snapid, seg_name);
+		if (ret < 0)
+			pr_warning("could not roll back obj %s err=%d\n",
+				   seg_name, ret);
+	}
+
+	ret = __rbd_update_snaps(rbd_dev);
+	if (ret < 0)
+		goto done_unlock;
+
+	ret = count;
+
+done_unlock:
+	mutex_unlock(&ctl_mutex);
+done:
+	kfree(seg_name);
+	kfree(snap_name);
+
+	return ret;
+}
+
+static struct bus_attribute rbd_bus_attrs[] = {
+	__ATTR(add, S_IWUSR, NULL, rbd_add),
+	__ATTR(remove, S_IWUSR, NULL, rbd_remove),
+	__ATTR_NULL
+};
+
+/*
+ * create control files in sysfs
+ * /sys/bus/rbd/...
+ */
+static int rbd_sysfs_init(void)
+{
+	int ret;
+
+	rbd_bus_type.bus_attrs = rbd_bus_attrs;
+
+	ret = bus_register(&rbd_bus_type);
+	 if (ret < 0)
+		return ret;
+
+	ret = device_register(&rbd_root_dev);
+
+	return ret;
+}
+
+static void rbd_sysfs_cleanup(void)
+{
+	device_unregister(&rbd_root_dev);
+	bus_unregister(&rbd_bus_type);
+}
+
+int __init rbd_init(void)
+{
+	int rc;
+
+	rc = rbd_sysfs_init();
+	if (rc)
+		return rc;
+	spin_lock_init(&node_lock);
+	pr_info("loaded " DRV_NAME_LONG "\n");
+	return 0;
+}
+
+void __exit rbd_exit(void)
+{
+	rbd_sysfs_cleanup();
+}
+
+module_init(rbd_init);
+module_exit(rbd_exit);
+
+MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
+MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
+MODULE_DESCRIPTION("rados block device");
+
+/* following authorship retained from original osdblk.c */
+MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>");
+
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/block/rbd_types.h linux-libre-2.6.37-gnu/drivers/block/rbd_types.h
--- linux-libre-2.6.36-gnu/drivers/block/rbd_types.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/block/rbd_types.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,73 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2010 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef CEPH_RBD_TYPES_H
+#define CEPH_RBD_TYPES_H
+
+#include <linux/types.h>
+
+/*
+ * rbd image 'foo' consists of objects
+ *   foo.rbd      - image metadata
+ *   foo.00000000
+ *   foo.00000001
+ *   ...          - data
+ */
+
+#define RBD_SUFFIX		".rbd"
+#define RBD_DIRECTORY           "rbd_directory"
+#define RBD_INFO                "rbd_info"
+
+#define RBD_DEFAULT_OBJ_ORDER	22   /* 4MB */
+#define RBD_MIN_OBJ_ORDER       16
+#define RBD_MAX_OBJ_ORDER       30
+
+#define RBD_MAX_OBJ_NAME_LEN	96
+#define RBD_MAX_SEG_NAME_LEN	128
+
+#define RBD_COMP_NONE		0
+#define RBD_CRYPT_NONE		0
+
+#define RBD_HEADER_TEXT		"<<< Rados Block Device Image >>>\n"
+#define RBD_HEADER_SIGNATURE	"RBD"
+#define RBD_HEADER_VERSION	"001.005"
+
+struct rbd_info {
+	__le64 max_id;
+} __attribute__ ((packed));
+
+struct rbd_image_snap_ondisk {
+	__le64 id;
+	__le64 image_size;
+} __attribute__((packed));
+
+struct rbd_image_header_ondisk {
+	char text[40];
+	char block_name[24];
+	char signature[4];
+	char version[8];
+	struct {
+		__u8 order;
+		__u8 crypt_type;
+		__u8 comp_type;
+		__u8 unused;
+	} __attribute__((packed)) options;
+	__le64 image_size;
+	__le64 snap_seq;
+	__le32 snap_count;
+	__le32 reserved;
+	__le64 snap_names_len;
+	struct rbd_image_snap_ondisk snaps[0];
+} __attribute__((packed));
+
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/block/swim3.c linux-libre-2.6.37-gnu/drivers/block/swim3.c
--- linux-libre-2.6.36-gnu/drivers/block/swim3.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/swim3.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,7 @@
 #include <linux/ioctl.h>
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/io.h>
@@ -36,6 +36,7 @@
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 
+static DEFINE_MUTEX(swim3_mutex);
 static struct request_queue *swim3_queue;
 static struct gendisk *disks[2];
 static struct request *fd_req;
@@ -873,9 +874,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&swim3_mutex);
 	ret = floppy_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
+	mutex_unlock(&swim3_mutex);
 
 	return ret;
 }
@@ -953,9 +954,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&swim3_mutex);
 	ret = floppy_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&swim3_mutex);
 
 	return ret;
 }
@@ -964,13 +965,13 @@
 {
 	struct floppy_state *fs = disk->private_data;
 	struct swim3 __iomem *sw = fs->swim3;
-	lock_kernel();
+	mutex_lock(&swim3_mutex);
 	if (fs->ref_count > 0 && --fs->ref_count == 0) {
 		swim3_action(fs, MOTOR_OFF);
 		out_8(&sw->control_bic, 0xff);
 		swim3_select(fs, RELAX);
 	}
-	unlock_kernel();
+	mutex_unlock(&swim3_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/swim.c linux-libre-2.6.37-gnu/drivers/block/swim.c
--- linux-libre-2.6.36-gnu/drivers/block/swim.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/swim.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 #include <linux/fd.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/hdreg.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -222,6 +222,7 @@
 extern int swim_read_sector_data(struct swim __iomem *base,
 				 unsigned char *data);
 
+static DEFINE_MUTEX(swim_mutex);
 static inline void set_swim_mode(struct swim __iomem *base, int enable)
 {
 	struct iwm __iomem *iwm_base;
@@ -666,9 +667,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&swim_mutex);
 	ret = floppy_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&swim_mutex);
 
 	return ret;
 }
@@ -678,7 +679,7 @@
 	struct floppy_state *fs = disk->private_data;
 	struct swim __iomem *base = fs->swd->base;
 
-	lock_kernel();
+	mutex_lock(&swim_mutex);
 	if (fs->ref_count < 0)
 		fs->ref_count = 0;
 	else if (fs->ref_count > 0)
@@ -686,7 +687,7 @@
 
 	if (fs->ref_count == 0)
 		swim_motor(base, OFF);
-	unlock_kernel();
+	mutex_unlock(&swim_mutex);
 
 	return 0;
 }
@@ -704,9 +705,9 @@
 	case FDEJECT:
 		if (fs->ref_count != 1)
 			return -EBUSY;
-		lock_kernel();
+		mutex_lock(&swim_mutex);
 		err = floppy_eject(fs);
-		unlock_kernel();
+		mutex_unlock(&swim_mutex);
 		return err;
 
 	case FDGETPRM:
diff -druN linux-libre-2.6.36-gnu/drivers/block/ub.c linux-libre-2.6.37-gnu/drivers/block/ub.c
--- linux-libre-2.6.36-gnu/drivers/block/ub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/ub.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
 #include <linux/timer.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <scsi/scsi.h>
 
 #define DRV_NAME "ub"
@@ -248,6 +248,7 @@
 	spinlock_t lock;
 };
 
+static DEFINE_MUTEX(ub_mutex);
 static inline void ub_init_completion(struct ub_completion *x)
 {
 	x->done = 0;
@@ -396,7 +397,7 @@
 #else
 
 static const struct usb_device_id ub_usb_ids[] = {
-	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
+	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },
 	{ }
 };
 
@@ -1715,9 +1716,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ub_mutex);
 	ret = ub_bd_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&ub_mutex);
 
 	return ret;
 }
@@ -1730,9 +1731,9 @@
 	struct ub_lun *lun = disk->private_data;
 	struct ub_dev *sc = lun->udev;
 
-	lock_kernel();
+	mutex_lock(&ub_mutex);
 	ub_put(sc);
-	unlock_kernel();
+	mutex_unlock(&ub_mutex);
 
 	return 0;
 }
@@ -1747,9 +1748,9 @@
 	void __user *usermem = (void __user *) arg;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ub_mutex);
 	ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem);
-	unlock_kernel();
+	mutex_unlock(&ub_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/viodasd.c linux-libre-2.6.37-gnu/drivers/block/viodasd.c
--- linux-libre-2.6.36-gnu/drivers/block/viodasd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/viodasd.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
 #include <linux/device.h>
@@ -73,6 +73,7 @@
 	MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name)
 };
 
+static DEFINE_MUTEX(viodasd_mutex);
 static DEFINE_SPINLOCK(viodasd_spinlock);
 
 #define VIOMAXREQ		16
@@ -180,9 +181,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&viodasd_mutex);
 	ret = viodasd_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&viodasd_mutex);
 
 	return ret;
 }
@@ -196,7 +197,7 @@
 	struct viodasd_device *d = disk->private_data;
 	HvLpEvent_Rc hvrc;
 
-	lock_kernel();
+	mutex_lock(&viodasd_mutex);
 	/* Send the event to OS/400.  We DON'T expect a response */
 	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
 			HvLpEvent_Type_VirtualIo,
@@ -210,7 +211,7 @@
 	if (hvrc != 0)
 		pr_warning("HV close call failed %d\n", (int)hvrc);
 
-	unlock_kernel();
+	mutex_unlock(&viodasd_mutex);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/virtio_blk.c linux-libre-2.6.37-gnu/drivers/block/virtio_blk.c
--- linux-libre-2.6.36-gnu/drivers/block/virtio_blk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/virtio_blk.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,6 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
 #include <linux/hdreg.h>
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
@@ -128,9 +127,6 @@
 		}
 	}
 
-	if (vbr->req->cmd_flags & REQ_HARDBARRIER)
-		vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
-
 	sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr));
 
 	/*
@@ -222,8 +218,8 @@
 	return err;
 }
 
-static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode,
-			 unsigned cmd, unsigned long data)
+static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
+			     unsigned int cmd, unsigned long data)
 {
 	struct gendisk *disk = bdev->bd_disk;
 	struct virtio_blk *vblk = disk->private_data;
@@ -238,18 +234,6 @@
 			      (void __user *)data);
 }
 
-static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
-			     unsigned int cmd, unsigned long param)
-{
-	int ret;
-
-	lock_kernel();
-	ret = virtblk_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
-
-	return ret;
-}
-
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
@@ -392,31 +376,9 @@
 	vblk->disk->driverfs_dev = &vdev->dev;
 	index++;
 
-	if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) {
-		/*
-		 * If the FLUSH feature is supported we do have support for
-		 * flushing a volatile write cache on the host.  Use that
-		 * to implement write barrier support.
-		 */
-		blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH);
-	} else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) {
-		/*
-		 * If the BARRIER feature is supported the host expects us
-		 * to order request by tags.  This implies there is not
-		 * volatile write cache on the host, and that the host
-		 * never re-orders outstanding I/O.  This feature is not
-		 * useful for real life scenarious and deprecated.
-		 */
-		blk_queue_ordered(q, QUEUE_ORDERED_TAG);
-	} else {
-		/*
-		 * If the FLUSH feature is not supported we must assume that
-		 * the host does not perform any kind of volatile write
-		 * caching. We still need to drain the queue to provider
-		 * proper barrier semantics.
-		 */
-		blk_queue_ordered(q, QUEUE_ORDERED_DRAIN);
-	}
+	/* configure queue flush support */
+	if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
+		blk_queue_flush(q, REQ_FLUSH);
 
 	/* If disk is read-only in the host, the guest should obey */
 	if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -535,9 +497,9 @@
 };
 
 static unsigned int features[] = {
-	VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
-	VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
-	VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
+	VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
+	VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
+	VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/drivers/block/xd.c linux-libre-2.6.37-gnu/drivers/block/xd.c
--- linux-libre-2.6.36-gnu/drivers/block/xd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/xd.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/blkpg.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -58,6 +58,7 @@
 
 #include "xd.h"
 
+static DEFINE_MUTEX(xd_mutex);
 static void __init do_xd_setup (int *integers);
 #ifdef MODULE
 static int xd[5] = { -1,-1,-1,-1, };
@@ -381,9 +382,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&xd_mutex);
 	ret = xd_locked_ioctl(bdev, mode, cmd, param);
-	unlock_kernel();
+	mutex_unlock(&xd_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/block/xen-blkfront.c linux-libre-2.6.37-gnu/drivers/block/xen-blkfront.c
--- linux-libre-2.6.36-gnu/drivers/block/xen-blkfront.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/xen-blkfront.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 #include <linux/cdrom.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/scatterlist.h>
 
 #include <xen/xen.h>
@@ -65,13 +65,14 @@
 
 struct blk_shadow {
 	struct blkif_request req;
-	unsigned long request;
+	struct request *request;
 	unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 };
 
+static DEFINE_MUTEX(blkfront_mutex);
 static const struct block_device_operations xlvbd_block_fops;
 
-#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, PAGE_SIZE)
 
 /*
  * We have one of these per vbd, whether ide, scsi or 'other'.  They
@@ -95,7 +96,7 @@
 	struct gnttab_free_callback callback;
 	struct blk_shadow shadow[BLK_RING_SIZE];
 	unsigned long shadow_free;
-	int feature_barrier;
+	unsigned int feature_flush;
 	int is_ready;
 };
 
@@ -135,7 +136,7 @@
 			       unsigned long id)
 {
 	info->shadow[id].req.id  = info->shadow_free;
-	info->shadow[id].request = 0;
+	info->shadow[id].request = NULL;
 	info->shadow_free = id;
 }
 
@@ -244,14 +245,11 @@
 }
 
 /*
- * blkif_queue_request
- *
- * request block io
+ * Generate a Xen blkfront IO request from a blk layer request.  Reads
+ * and writes are handled as expected.  Since we lack a loose flush
+ * request, we map flushes into a full ordered barrier.
  *
- * id: for guest use only.
- * operation: BLKIF_OP_{READ,WRITE,PROBE}
- * buffer: buffer to read/write into. this should be a
- *   virtual address in the guest os.
+ * @req: a request struct
  */
 static int blkif_queue_request(struct request *req)
 {
@@ -280,7 +278,7 @@
 	/* Fill out a communications ring structure. */
 	ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
 	id = get_id_from_freelist(info);
-	info->shadow[id].request = (unsigned long)req;
+	info->shadow[id].request = req;
 
 	ring_req->id = id;
 	ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
@@ -288,8 +286,18 @@
 
 	ring_req->operation = rq_data_dir(req) ?
 		BLKIF_OP_WRITE : BLKIF_OP_READ;
-	if (req->cmd_flags & REQ_HARDBARRIER)
+
+	if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+		/*
+		 * Ideally we could just do an unordered
+		 * flush-to-disk, but all we have is a full write
+		 * barrier at the moment.  However, a barrier write is
+		 * a superset of FUA, so we can implement it the same
+		 * way.  (It's also a FLUSH+FUA, since it is
+		 * guaranteed ordered WRT previous writes.)
+		 */
 		ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+	}
 
 	ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
 	BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
@@ -418,26 +426,12 @@
 }
 
 
-static int xlvbd_barrier(struct blkfront_info *info)
+static void xlvbd_flush(struct blkfront_info *info)
 {
-	int err;
-	const char *barrier;
-
-	switch (info->feature_barrier) {
-	case QUEUE_ORDERED_DRAIN:	barrier = "enabled (drain)"; break;
-	case QUEUE_ORDERED_TAG:		barrier = "enabled (tag)"; break;
-	case QUEUE_ORDERED_NONE:	barrier = "disabled"; break;
-	default:			return -EINVAL;
-	}
-
-	err = blk_queue_ordered(info->rq, info->feature_barrier);
-
-	if (err)
-		return err;
-
+	blk_queue_flush(info->rq, info->feature_flush);
 	printk(KERN_INFO "blkfront: %s: barriers %s\n",
-	       info->gd->disk_name, barrier);
-	return 0;
+	       info->gd->disk_name,
+	       info->feature_flush ? "enabled" : "disabled");
 }
 
 
@@ -516,7 +510,7 @@
 	info->rq = gd->queue;
 	info->gd = gd;
 
-	xlvbd_barrier(info);
+	xlvbd_flush(info);
 
 	if (vdisk_info & VDISK_READONLY)
 		set_disk_ro(gd, 1);
@@ -649,7 +643,7 @@
 
 		bret = RING_GET_RESPONSE(&info->ring, i);
 		id   = bret->id;
-		req  = (struct request *)info->shadow[id].request;
+		req  = info->shadow[id].request;
 
 		blkif_completion(&info->shadow[id]);
 
@@ -662,8 +656,18 @@
 				printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
 				       info->gd->disk_name);
 				error = -EOPNOTSUPP;
-				info->feature_barrier = QUEUE_ORDERED_NONE;
-				xlvbd_barrier(info);
+			}
+			if (unlikely(bret->status == BLKIF_RSP_ERROR &&
+				     info->shadow[id].req.nr_segments == 0)) {
+				printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n",
+				       info->gd->disk_name);
+				error = -EOPNOTSUPP;
+			}
+			if (unlikely(error)) {
+				if (error == -EOPNOTSUPP)
+					error = 0;
+				info->feature_flush = 0;
+				xlvbd_flush(info);
 			}
 			/* fall through */
 		case BLKIF_OP_READ:
@@ -914,7 +918,7 @@
 	/* Stage 3: Find pending requests and requeue them. */
 	for (i = 0; i < BLK_RING_SIZE; i++) {
 		/* Not in use? */
-		if (copy[i].request == 0)
+		if (!copy[i].request)
 			continue;
 
 		/* Grab a request slot and copy shadow state into it. */
@@ -931,9 +935,7 @@
 				req->seg[j].gref,
 				info->xbdev->otherend_id,
 				pfn_to_mfn(info->shadow[req->id].frame[j]),
-				rq_data_dir(
-					(struct request *)
-					info->shadow[req->id].request));
+				rq_data_dir(info->shadow[req->id].request));
 		info->shadow[req->id].req = *req;
 
 		info->ring.req_prod_pvt++;
@@ -1076,20 +1078,14 @@
 	/*
 	 * If there's no "feature-barrier" defined, then it means
 	 * we're dealing with a very old backend which writes
-	 * synchronously; draining will do what needs to get done.
-	 *
-	 * If there are barriers, then we can do full queued writes
-	 * with tagged barriers.
+	 * synchronously; nothing to do.
 	 *
-	 * If barriers are not supported, then there's no much we can
-	 * do, so just set ordering to NONE.
+	 * If there are barriers, then we use flush.
 	 */
-	if (err)
-		info->feature_barrier = QUEUE_ORDERED_DRAIN;
-	else if (barrier)
-		info->feature_barrier = QUEUE_ORDERED_TAG;
-	else
-		info->feature_barrier = QUEUE_ORDERED_NONE;
+	info->feature_flush = 0;
+
+	if (!err && barrier)
+		info->feature_flush = REQ_FLUSH | REQ_FUA;
 
 	err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
 	if (err) {
@@ -1125,6 +1121,8 @@
 	case XenbusStateInitialising:
 	case XenbusStateInitWait:
 	case XenbusStateInitialised:
+	case XenbusStateReconfiguring:
+	case XenbusStateReconfigured:
 	case XenbusStateUnknown:
 	case XenbusStateClosed:
 		break;
@@ -1201,7 +1199,7 @@
 	struct blkfront_info *info;
 	int err = 0;
 
-	lock_kernel();
+	mutex_lock(&blkfront_mutex);
 
 	info = disk->private_data;
 	if (!info) {
@@ -1219,7 +1217,7 @@
 	mutex_unlock(&info->mutex);
 
 out:
-	unlock_kernel();
+	mutex_unlock(&blkfront_mutex);
 	return err;
 }
 
@@ -1229,7 +1227,7 @@
 	struct block_device *bdev;
 	struct xenbus_device *xbdev;
 
-	lock_kernel();
+	mutex_lock(&blkfront_mutex);
 
 	bdev = bdget_disk(disk, 0);
 	bdput(bdev);
@@ -1263,7 +1261,7 @@
 	}
 
 out:
-	unlock_kernel();
+	mutex_unlock(&blkfront_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/block/xsysace.c linux-libre-2.6.37-gnu/drivers/block/xsysace.c
--- linux-libre-2.6.36-gnu/drivers/block/xsysace.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/xsysace.c	2011-01-04 19:50:19.000000000 -0500
@@ -89,7 +89,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/ata.h>
 #include <linux/hdreg.h>
 #include <linux/platform_device.h>
@@ -214,6 +214,7 @@
 	u16 cf_id[ATA_ID_WORDS];
 };
 
+static DEFINE_MUTEX(xsysace_mutex);
 static int ace_major;
 
 /* ---------------------------------------------------------------------
@@ -903,13 +904,13 @@
 
 	dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1);
 
-	lock_kernel();
+	mutex_lock(&xsysace_mutex);
 	spin_lock_irqsave(&ace->lock, flags);
 	ace->users++;
 	spin_unlock_irqrestore(&ace->lock, flags);
 
 	check_disk_change(bdev);
-	unlock_kernel();
+	mutex_unlock(&xsysace_mutex);
 
 	return 0;
 }
@@ -922,7 +923,7 @@
 
 	dev_dbg(ace->dev, "ace_release() users=%i\n", ace->users - 1);
 
-	lock_kernel();
+	mutex_lock(&xsysace_mutex);
 	spin_lock_irqsave(&ace->lock, flags);
 	ace->users--;
 	if (ace->users == 0) {
@@ -930,7 +931,7 @@
 		ace_out(ace, ACE_CTRL, val & ~ACE_CTRL_LOCKREQ);
 	}
 	spin_unlock_irqrestore(&ace->lock, flags);
-	unlock_kernel();
+	mutex_unlock(&xsysace_mutex);
 	return 0;
 }
 
@@ -1224,7 +1225,8 @@
 		bus_width = ACE_BUS_WIDTH_8;
 
 	/* Call the bus-independant setup code */
-	return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+	return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0,
+						physaddr, irq, bus_width);
 }
 
 static int __devexit ace_of_remove(struct platform_device *op)
diff -druN linux-libre-2.6.36-gnu/drivers/block/z2ram.c linux-libre-2.6.37-gnu/drivers/block/z2ram.c
--- linux-libre-2.6.36-gnu/drivers/block/z2ram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/block/z2ram.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,7 @@
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/bitops.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 
 #include <asm/setup.h>
@@ -57,6 +57,7 @@
 
 #define Z2RAM_CHUNK1024       ( Z2RAM_CHUNKSIZE >> 10 )
 
+static DEFINE_MUTEX(z2ram_mutex);
 static u_long *z2ram_map    = NULL;
 static u_long z2ram_size    = 0;
 static int z2_count         = 0;
@@ -79,8 +80,10 @@
 		int err = 0;
 
 		if (start + len > z2ram_size) {
-			printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
-				blk_rq_pos(req), blk_rq_cur_sectors(req));
+			pr_err(DEVICE_NAME ": bad access: block=%llu, "
+			       "count=%u\n",
+			       (unsigned long long)blk_rq_pos(req),
+			       blk_rq_cur_sectors(req));
 			err = -EIO;
 			goto done;
 		}
@@ -154,7 +157,7 @@
 
     device = MINOR(bdev->bd_dev);
 
-    lock_kernel();
+    mutex_lock(&z2ram_mutex);
     if ( current_device != -1 && current_device != device )
     {
 	rc = -EBUSY;
@@ -296,25 +299,25 @@
 	set_capacity(z2ram_gendisk, z2ram_size >> 9);
     }
 
-    unlock_kernel();
+    mutex_unlock(&z2ram_mutex);
     return 0;
 
 err_out_kfree:
     kfree(z2ram_map);
 err_out:
-    unlock_kernel();
+    mutex_unlock(&z2ram_mutex);
     return rc;
 }
 
 static int
 z2_release(struct gendisk *disk, fmode_t mode)
 {
-    lock_kernel();
+    mutex_lock(&z2ram_mutex);
     if ( current_device == -1 ) {
-    	unlock_kernel();
+    	mutex_unlock(&z2ram_mutex);
     	return 0;
     }
-    unlock_kernel();
+    mutex_unlock(&z2ram_mutex);
     /*
      * FIXME: unmap memory
      */
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/ath3k.c linux-libre-2.6.37-gnu/drivers/bluetooth/ath3k.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/ath3k.c	2012-03-23 21:55:11.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/ath3k.c	2012-03-23 23:45:54.000000000 -0400
@@ -35,6 +35,10 @@
 static struct usb_device_id ath3k_table[] = {
 	/* Atheros AR3011 */
 	{ USB_DEVICE(0x0CF3, 0x3000) },
+
+	/* Atheros AR3011 with sflash firmware*/
+	{ USB_DEVICE(0x0CF3, 0x3002) },
+
 	{ }	/* Terminating entry */
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/bluecard_cs.c linux-libre-2.6.37-gnu/drivers/bluetooth/bluecard_cs.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/bluecard_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/bluecard_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,6 @@
 #include <linux/skbuff.h>
 #include <linux/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -865,8 +864,7 @@
 	info->p_dev = link;
 	link->priv = info;
 
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->config_flags |= CONF_ENABLE_IRQ;
 
 	return bluecard_config(link);
 }
@@ -886,7 +884,7 @@
 	bluecard_info_t *info = link->priv;
 	int i, n;
 
-	link->conf.ConfigIndex = 0x20;
+	link->config_index = 0x20;
 
 	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 	link->resource[0]->end = 64;
@@ -906,7 +904,7 @@
 	if (i != 0)
 		goto failed;
 
-	i = pcmcia_request_configuration(link, &link->conf);
+	i = pcmcia_enable_device(link);
 	if (i != 0)
 		goto failed;
 
@@ -942,9 +940,7 @@
 
 static struct pcmcia_driver bluecard_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "bluecard_cs",
-	},
+	.name		= "bluecard_cs",
 	.probe		= bluecard_probe,
 	.remove		= bluecard_detach,
 	.id_table	= bluecard_ids,
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/bt3c_cs.c linux-libre-2.6.37-gnu/drivers/bluetooth/bt3c_cs.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/bt3c_cs.c	2012-03-23 21:55:23.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/bt3c_cs.c	2012-03-23 23:46:07.000000000 -0400
@@ -45,7 +45,6 @@
 #include <linux/device.h>
 #include <linux/firmware.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -657,11 +656,8 @@
 	info->p_dev = link;
 	link->priv = info;
 
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[0]->end = 8;
-
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+		CONF_AUTO_SET_IO;
 
 	return bt3c_config(link);
 }
@@ -675,43 +671,41 @@
 	kfree(info);
 }
 
-static int bt3c_check_config(struct pcmcia_device *p_dev,
-			     cistpl_cftable_entry_t *cf,
-			     cistpl_cftable_entry_t *dflt,
-			     unsigned int vcc,
-			     void *priv_data)
+static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
 {
-	unsigned long try = (unsigned long) priv_data;
+	int *try = priv_data;
 
-	p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+	if (try == 0)
+		p_dev->io_lines = 16;
 
-	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
-	    (cf->io.win[0].base != 0)) {
-		p_dev->resource[0]->start = cf->io.win[0].base;
-		if (!pcmcia_request_io(p_dev))
-			return 0;
-	}
-	return -ENODEV;
+	if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
+		return -EINVAL;
+
+	p_dev->resource[0]->end = 8;
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+	return pcmcia_request_io(p_dev);
 }
 
 static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
-				      cistpl_cftable_entry_t *cf,
-				      cistpl_cftable_entry_t *dflt,
-				      unsigned int vcc,
 				      void *priv_data)
 {
 	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 	int j;
 
-	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-		for (j = 0; j < 5; j++) {
-			p_dev->resource[0]->start = base[j];
-			p_dev->io_lines = base[j] ? 16 : 3;
-			if (!pcmcia_request_io(p_dev))
-				return 0;
-		}
+	if (p_dev->io_lines > 3)
+		return -ENODEV;
+
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+	p_dev->resource[0]->end = 8;
+
+	for (j = 0; j < 5; j++) {
+		p_dev->resource[0]->start = base[j];
+		p_dev->io_lines = base[j] ? 16 : 3;
+		if (!pcmcia_request_io(p_dev))
+			return 0;
 	}
 	return -ENODEV;
 }
@@ -742,7 +736,7 @@
 	if (i != 0)
 		goto failed;
 
-	i = pcmcia_request_configuration(link, &link->conf);
+	i = pcmcia_enable_device(link);
 	if (i != 0)
 		goto failed;
 
@@ -775,9 +769,7 @@
 
 static struct pcmcia_driver bt3c_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "bt3c_cs",
-	},
+	.name		= "bt3c_cs",
 	.probe		= bt3c_probe,
 	.remove		= bt3c_detach,
 	.id_table	= bt3c_ids,
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/btmrvl_debugfs.c linux-libre-2.6.37-gnu/drivers/bluetooth/btmrvl_debugfs.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/btmrvl_debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/btmrvl_debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,6 +92,7 @@
 	.read	= btmrvl_hscfgcmd_read,
 	.write	= btmrvl_hscfgcmd_write,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
@@ -130,6 +131,7 @@
 	.read	= btmrvl_psmode_read,
 	.write	= btmrvl_psmode_write,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
@@ -173,6 +175,7 @@
 	.read = btmrvl_pscmd_read,
 	.write = btmrvl_pscmd_write,
 	.open = btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
@@ -211,6 +214,7 @@
 	.read	= btmrvl_gpiogap_read,
 	.write	= btmrvl_gpiogap_write,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
@@ -252,6 +256,7 @@
 	.read	= btmrvl_hscmd_read,
 	.write	= btmrvl_hscmd_write,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
@@ -289,6 +294,7 @@
 	.read	= btmrvl_hsmode_read,
 	.write	= btmrvl_hsmode_write,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
@@ -306,6 +312,7 @@
 static const struct file_operations btmrvl_curpsmode_fops = {
 	.read	= btmrvl_curpsmode_read,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
@@ -323,6 +330,7 @@
 static const struct file_operations btmrvl_psstate_fops = {
 	.read	= btmrvl_psstate_read,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
@@ -340,6 +348,7 @@
 static const struct file_operations btmrvl_hsstate_fops = {
 	.read	= btmrvl_hsstate_read,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
@@ -358,6 +367,7 @@
 static const struct file_operations btmrvl_txdnldready_fops = {
 	.read	= btmrvl_txdnldready_read,
 	.open	= btmrvl_open_generic,
+	.llseek = default_llseek,
 };
 
 void btmrvl_debugfs_init(struct hci_dev *hdev)
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/btmrvl_main.c linux-libre-2.6.37-gnu/drivers/bluetooth/btmrvl_main.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/btmrvl_main.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/btmrvl_main.c	2011-01-04 19:50:19.000000000 -0500
@@ -117,8 +117,8 @@
 				(event->data[2] == MODULE_ALREADY_UP)) ?
 				"Bring-up succeed" : "Bring-up failed");
 
-			if (event->length > 3)
-				priv->btmrvl_dev.dev_type = event->data[3];
+			if (event->length > 3 && event->data[3])
+				priv->btmrvl_dev.dev_type = HCI_AMP;
 			else
 				priv->btmrvl_dev.dev_type = HCI_BREDR;
 
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/btsdio.c linux-libre-2.6.37-gnu/drivers/bluetooth/btsdio.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/btsdio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/btsdio.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,6 +46,9 @@
 	/* Generic Bluetooth Type-B SDIO device */
 	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
 
+	/* Generic Bluetooth AMP controller */
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_AMP) },
+
 	{ }	/* Terminating entry */
 };
 
@@ -329,6 +332,11 @@
 	hdev->bus = HCI_SDIO;
 	hdev->driver_data = data;
 
+	if (id->class == SDIO_CLASS_BT_AMP)
+		hdev->dev_type = HCI_AMP;
+	else
+		hdev->dev_type = HCI_BREDR;
+
 	data->hdev = hdev;
 
 	SET_HCIDEV_DEV(hdev, &func->dev);
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/btuart_cs.c linux-libre-2.6.37-gnu/drivers/bluetooth/btuart_cs.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/btuart_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/btuart_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -586,11 +585,8 @@
 	info->p_dev = link;
 	link->priv = info;
 
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[0]->end = 8;
-
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+		CONF_AUTO_SET_IO;
 
 	return btuart_config(link);
 }
@@ -604,43 +600,41 @@
 	kfree(info);
 }
 
-static int btuart_check_config(struct pcmcia_device *p_dev,
-			       cistpl_cftable_entry_t *cf,
-			       cistpl_cftable_entry_t *dflt,
-			       unsigned int vcc,
-			       void *priv_data)
+static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
 {
 	int *try = priv_data;
 
-	p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+	if (try == 0)
+		p_dev->io_lines = 16;
 
-	if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
-	    (cf->io.win[0].base != 0)) {
-		p_dev->resource[0]->start = cf->io.win[0].base;
-		if (!pcmcia_request_io(p_dev))
-			return 0;
-	}
-	return -ENODEV;
+	if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
+		return -EINVAL;
+
+	p_dev->resource[0]->end = 8;
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+	return pcmcia_request_io(p_dev);
 }
 
 static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
-					cistpl_cftable_entry_t *cf,
-					cistpl_cftable_entry_t *dflt,
-					unsigned int vcc,
 					void *priv_data)
 {
 	static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 	int j;
 
-	if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-		for (j = 0; j < 5; j++) {
-			p_dev->resource[0]->start = base[j];
-			p_dev->io_lines = base[j] ? 16 : 3;
-			if (!pcmcia_request_io(p_dev))
-				return 0;
-		}
+	if (p_dev->io_lines > 3)
+		return -ENODEV;
+
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+	p_dev->resource[0]->end = 8;
+
+	for (j = 0; j < 5; j++) {
+		p_dev->resource[0]->start = base[j];
+		p_dev->io_lines = base[j] ? 16 : 3;
+		if (!pcmcia_request_io(p_dev))
+			return 0;
 	}
 	return -ENODEV;
 }
@@ -671,7 +665,7 @@
 	if (i != 0)
 		goto failed;
 
-	i = pcmcia_request_configuration(link, &link->conf);
+	i = pcmcia_enable_device(link);
 	if (i != 0)
 		goto failed;
 
@@ -703,9 +697,7 @@
 
 static struct pcmcia_driver btuart_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "btuart_cs",
-	},
+	.name		= "btuart_cs",
 	.probe		= btuart_probe,
 	.remove		= btuart_detach,
 	.id_table	= btuart_ids,
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/btusb.c linux-libre-2.6.37-gnu/drivers/bluetooth/btusb.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/btusb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/btusb.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,9 +59,18 @@
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
+	/* Apple MacBookPro 7,1 */
+	{ USB_DEVICE(0x05ac, 0x8213) },
+
 	/* Apple iMac11,1 */
 	{ USB_DEVICE(0x05ac, 0x8215) },
 
+	/* Apple MacBookPro6,2 */
+	{ USB_DEVICE(0x05ac, 0x8218) },
+
+	/* Apple MacBookAir3,1, MacBookAir3,2 */
+	{ USB_DEVICE(0x05ac, 0x821b) },
+
 	/* AVM BlueFRITZ! USB v2.0 */
 	{ USB_DEVICE(0x057c, 0x3800) },
 
@@ -90,6 +99,9 @@
 	/* Broadcom BCM2033 without firmware */
 	{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
+	/* Atheros 3011 with sflash firmware */
+	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
 	/* Broadcom BCM2035 */
 	{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -230,7 +242,8 @@
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err < 0) {
-		BT_ERR("%s urb %p failed to resubmit (%d)",
+		if (err != -EPERM)
+			BT_ERR("%s urb %p failed to resubmit (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
@@ -314,7 +327,8 @@
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err < 0) {
-		BT_ERR("%s urb %p failed to resubmit (%d)",
+		if (err != -EPERM)
+			BT_ERR("%s urb %p failed to resubmit (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
@@ -403,7 +417,8 @@
 
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err < 0) {
-		BT_ERR("%s urb %p failed to resubmit (%d)",
+		if (err != -EPERM)
+			BT_ERR("%s urb %p failed to resubmit (%d)",
 						hdev->name, urb, -err);
 		usb_unanchor_urb(urb);
 	}
@@ -1023,6 +1038,8 @@
 
 	usb_set_intfdata(intf, data);
 
+	usb_enable_autosuspend(interface_to_usbdev(intf));
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/dtl1_cs.c linux-libre-2.6.37-gnu/drivers/bluetooth/dtl1_cs.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/dtl1_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/dtl1_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -572,11 +571,7 @@
 	info->p_dev = link;
 	link->priv = info;
 
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[0]->end = 8;
-
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
 	return dtl1_config(link);
 }
@@ -591,18 +586,14 @@
 	kfree(info);
 }
 
-static int dtl1_confcheck(struct pcmcia_device *p_dev,
-			  cistpl_cftable_entry_t *cf,
-			  cistpl_cftable_entry_t *dflt,
-			  unsigned int vcc,
-			  void *priv_data)
+static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-	if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8))
+	if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8))
 		return -ENODEV;
 
-	p_dev->resource[0]->start = cf->io.win[0].base;
-	p_dev->resource[0]->end = cf->io.win[0].len;	/*yo */
-	p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
 	return pcmcia_request_io(p_dev);
 }
 
@@ -620,7 +611,7 @@
 	if (i != 0)
 		goto failed;
 
-	i = pcmcia_request_configuration(link, &link->conf);
+	i = pcmcia_enable_device(link);
 	if (i != 0)
 		goto failed;
 
@@ -656,9 +647,7 @@
 
 static struct pcmcia_driver dtl1_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "dtl1_cs",
-	},
+	.name		= "dtl1_cs",
 	.probe		= dtl1_probe,
 	.remove		= dtl1_detach,
 	.id_table	= dtl1_ids,
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/hci_ldisc.c linux-libre-2.6.37-gnu/drivers/bluetooth/hci_ldisc.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/hci_ldisc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/hci_ldisc.c	2011-01-04 19:50:19.000000000 -0500
@@ -101,7 +101,7 @@
 		break;
 
 	case HCI_SCODATA_PKT:
-		hdev->stat.cmd_tx++;
+		hdev->stat.sco_tx++;
 		break;
 	}
 }
@@ -256,9 +256,16 @@
 
 	BT_DBG("tty %p", tty);
 
+	/* FIXME: This btw is bogus, nothing requires the old ldisc to clear
+	   the pointer */
 	if (hu)
 		return -EEXIST;
 
+	/* Error if the tty has no write op instead of leaving an exploitable
+	   hole */
+	if (tty->ops->write == NULL)
+		return -EOPNOTSUPP;
+
 	if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
 		BT_ERR("Can't allocate control structure");
 		return -ENFILE;
@@ -304,8 +311,10 @@
 
 		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
 			hu->proto->close(hu);
-			hci_unregister_dev(hdev);
-			hci_free_dev(hdev);
+			if (hdev) {
+				hci_unregister_dev(hdev);
+				hci_free_dev(hdev);
+			}
 		}
 	}
 }
diff -druN linux-libre-2.6.36-gnu/drivers/bluetooth/hci_vhci.c linux-libre-2.6.37-gnu/drivers/bluetooth/hci_vhci.c
--- linux-libre-2.6.36-gnu/drivers/bluetooth/hci_vhci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/bluetooth/hci_vhci.c	2011-01-04 19:50:19.000000000 -0500
@@ -282,6 +282,7 @@
 	.poll		= vhci_poll,
 	.open		= vhci_open,
 	.release	= vhci_release,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice vhci_miscdev= {
diff -druN linux-libre-2.6.36-gnu/drivers/cdrom/gdrom.c linux-libre-2.6.37-gnu/drivers/cdrom/gdrom.c
--- linux-libre-2.6.36-gnu/drivers/cdrom/gdrom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/cdrom/gdrom.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
@@ -81,6 +81,7 @@
 
 #define GDROM_DEFAULT_TIMEOUT	(HZ * 7)
 
+static DEFINE_MUTEX(gdrom_mutex);
 static const struct {
 	int sense_key;
 	const char * const text;
@@ -141,18 +142,18 @@
 
 static bool gdrom_is_busy(void)
 {
-	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
+	return (__raw_readb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
 }
 
 static bool gdrom_data_request(void)
 {
-	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
+	return (__raw_readb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
 }
 
 static bool gdrom_wait_clrbusy(void)
 {
 	unsigned long timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
-	while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) &&
+	while ((__raw_readb(GDROM_ALTSTATUS_REG) & 0x80) &&
 		(time_before(jiffies, timeout)))
 		cpu_relax();
 	return time_before(jiffies, timeout + 1);
@@ -180,14 +181,14 @@
 		gdrom_getsense(NULL);
 		return;
 	}
-	ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+	__raw_writeb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
 	if (!gdrom_wait_busy_sleeps()) {
 		gdrom_getsense(NULL);
 		return;
 	}
 	/* now read in the data */
 	for (c = 0; c < 40; c++)
-		data[c] = ctrl_inw(GDROM_DATA_REG);
+		data[c] = __raw_readw(GDROM_DATA_REG);
 }
 
 static void gdrom_spicommand(void *spi_string, int buflen)
@@ -196,21 +197,21 @@
 	unsigned long timeout;
 
 	/* ensure IRQ_WAIT is set */
-	ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+	__raw_writeb(0x08, GDROM_ALTSTATUS_REG);
 	/* specify how many bytes we expect back */
-	ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
-	ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+	__raw_writeb(buflen & 0xFF, GDROM_BCL_REG);
+	__raw_writeb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
 	/* other parameters */
-	ctrl_outb(0, GDROM_INTSEC_REG);
-	ctrl_outb(0, GDROM_SECNUM_REG);
-	ctrl_outb(0, GDROM_ERROR_REG);
+	__raw_writeb(0, GDROM_INTSEC_REG);
+	__raw_writeb(0, GDROM_SECNUM_REG);
+	__raw_writeb(0, GDROM_ERROR_REG);
 	/* Wait until we can go */
 	if (!gdrom_wait_clrbusy()) {
 		gdrom_getsense(NULL);
 		return;
 	}
 	timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
-	ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+	__raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
 	while (!gdrom_data_request() && time_before(jiffies, timeout))
 		cpu_relax();
 	if (!time_before(jiffies, timeout + 1)) {
@@ -232,10 +233,10 @@
 	gdrom_hardreset(gd.cd_info);
 	if (!gdrom_wait_clrbusy())
 		return 0;
-	ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+	__raw_writeb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
 	if (!gdrom_wait_busy_sleeps())
 		return 0;
-	return ctrl_inb(GDROM_ERROR_REG);
+	return __raw_readb(GDROM_ERROR_REG);
 }
 
 /*
@@ -384,7 +385,7 @@
 static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
 {
 	/* read the sense key */
-	char sense = ctrl_inb(GDROM_ERROR_REG);
+	char sense = __raw_readb(GDROM_ERROR_REG);
 	sense &= 0xF0;
 	if (sense == 0)
 		return CDS_DISC_OK;
@@ -397,16 +398,16 @@
 static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
 {
 	/* check the sense key */
-	return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60;
+	return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60;
 }
 
 /* reset the G1 bus */
 static int gdrom_hardreset(struct cdrom_device_info *cd_info)
 {
 	int count;
-	ctrl_outl(0x1fffff, GDROM_RESET_REG);
+	__raw_writel(0x1fffff, GDROM_RESET_REG);
 	for (count = 0xa0000000; count < 0xa0200000; count += 4)
-		ctrl_inl(count);
+		__raw_readl(count);
 	return 0;
 }
 
@@ -494,17 +495,17 @@
 static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)
 {
 	int ret;
-	lock_kernel();
+	mutex_lock(&gdrom_mutex);
 	ret = cdrom_open(gd.cd_info, bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&gdrom_mutex);
 	return ret;
 }
 
 static int gdrom_bdops_release(struct gendisk *disk, fmode_t mode)
 {
-	lock_kernel();
+	mutex_lock(&gdrom_mutex);
 	cdrom_release(gd.cd_info, mode);
-	unlock_kernel();
+	mutex_unlock(&gdrom_mutex);
 	return 0;
 }
 
@@ -518,9 +519,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&gdrom_mutex);
 	ret = cdrom_ioctl(gd.cd_info, bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&gdrom_mutex);
 
 	return ret;
 }
@@ -535,7 +536,7 @@
 
 static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
 {
-	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+	gd.status = __raw_readb(GDROM_STATUSCOMMAND_REG);
 	if (gd.pending != 1)
 		return IRQ_HANDLED;
 	gd.pending = 0;
@@ -545,7 +546,7 @@
 
 static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
 {
-	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+	gd.status = __raw_readb(GDROM_STATUSCOMMAND_REG);
 	if (gd.transfer != 1)
 		return IRQ_HANDLED;
 	gd.transfer = 0;
@@ -599,10 +600,10 @@
 		spin_unlock(&gdrom_lock);
 		block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
 		block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
-		ctrl_outl(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
-		ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
-		ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
-		ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+		__raw_writel(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG);
+		__raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+		__raw_writel(1, GDROM_DMA_DIRECTION_REG);
+		__raw_writel(1, GDROM_DMA_ENABLE_REG);
 		read_command->cmd[2] = (block >> 16) & 0xFF;
 		read_command->cmd[3] = (block >> 8) & 0xFF;
 		read_command->cmd[4] = block & 0xFF;
@@ -610,18 +611,18 @@
 		read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
 		read_command->cmd[10] = block_cnt & 0xFF;
 		/* set for DMA */
-		ctrl_outb(1, GDROM_ERROR_REG);
+		__raw_writeb(1, GDROM_ERROR_REG);
 		/* other registers */
-		ctrl_outb(0, GDROM_SECNUM_REG);
-		ctrl_outb(0, GDROM_BCL_REG);
-		ctrl_outb(0, GDROM_BCH_REG);
-		ctrl_outb(0, GDROM_DSEL_REG);
-		ctrl_outb(0, GDROM_INTSEC_REG);
+		__raw_writeb(0, GDROM_SECNUM_REG);
+		__raw_writeb(0, GDROM_BCL_REG);
+		__raw_writeb(0, GDROM_BCH_REG);
+		__raw_writeb(0, GDROM_DSEL_REG);
+		__raw_writeb(0, GDROM_INTSEC_REG);
 		/* Wait for registers to reset after any previous activity */
 		timeout = jiffies + HZ / 2;
 		while (gdrom_is_busy() && time_before(jiffies, timeout))
 			cpu_relax();
-		ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+		__raw_writeb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
 		timeout = jiffies + HZ / 2;
 		/* Wait for packet command to finish */
 		while (gdrom_is_busy() && time_before(jiffies, timeout))
@@ -631,11 +632,11 @@
 		outsw(GDROM_DATA_REG, &read_command->cmd, 6);
 		timeout = jiffies + HZ / 2;
 		/* Wait for any pending DMA to finish */
-		while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
+		while (__raw_readb(GDROM_DMA_STATUS_REG) &&
 			time_before(jiffies, timeout))
 			cpu_relax();
 		/* start transfer */
-		ctrl_outb(1, GDROM_DMA_STATUS_REG);
+		__raw_writeb(1, GDROM_DMA_STATUS_REG);
 		wait_event_interruptible_timeout(request_queue,
 			gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
 		err = gd.transfer ? -EIO : 0;
@@ -713,11 +714,11 @@
 /* set the default mode for DMA transfer */
 static int __devinit gdrom_init_dma_mode(void)
 {
-	ctrl_outb(0x13, GDROM_ERROR_REG);
-	ctrl_outb(0x22, GDROM_INTSEC_REG);
+	__raw_writeb(0x13, GDROM_ERROR_REG);
+	__raw_writeb(0x22, GDROM_INTSEC_REG);
 	if (!gdrom_wait_clrbusy())
 		return -EBUSY;
-	ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+	__raw_writeb(0xEF, GDROM_STATUSCOMMAND_REG);
 	if (!gdrom_wait_busy_sleeps())
 		return -EBUSY;
 	/* Memory protection setting for GDROM DMA
@@ -727,8 +728,8 @@
 	* Bits 6 - 0 end of transfer range in 1 MB blocks OR'ed with 0x80
 	* (0x40 | 0x80) = start range at 0x0C000000
 	* (0x7F | 0x80) = end range at 0x0FFFFFFF */
-	ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
-	ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+	__raw_writel(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
+	__raw_writel(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/cdrom/viocd.c linux-libre-2.6.37-gnu/drivers/cdrom/viocd.c
--- linux-libre-2.6.36-gnu/drivers/cdrom/viocd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/cdrom/viocd.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,7 @@
 #include <linux/module.h>
 #include <linux/completion.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/seq_file.h>
 #include <linux/scatterlist.h>
 
@@ -61,6 +61,7 @@
  */
 #define VIOCD_MAX_CD	HVMAXARCHITECTEDVIRTUALCDROMS
 
+static DEFINE_MUTEX(viocd_mutex);
 static const struct vio_error_entry viocd_err_table[] = {
 	{0x0201, EINVAL, "Invalid Range"},
 	{0x0202, EINVAL, "Invalid Token"},
@@ -156,9 +157,9 @@
 	struct disk_info *di = bdev->bd_disk->private_data;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&viocd_mutex);
 	ret = cdrom_open(&di->viocd_info, bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&viocd_mutex);
 
 	return ret;
 }
@@ -166,9 +167,9 @@
 static int viocd_blk_release(struct gendisk *disk, fmode_t mode)
 {
 	struct disk_info *di = disk->private_data;
-	lock_kernel();
+	mutex_lock(&viocd_mutex);
 	cdrom_release(&di->viocd_info, mode);
-	unlock_kernel();
+	mutex_unlock(&viocd_mutex);
 	return 0;
 }
 
@@ -178,9 +179,9 @@
 	struct disk_info *di = bdev->bd_disk->private_data;
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&viocd_mutex);
 	ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&viocd_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/agp.h linux-libre-2.6.37-gnu/drivers/char/agp/agp.h
--- linux-libre-2.6.36-gnu/drivers/char/agp/agp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/agp.h	2011-01-04 19:50:19.000000000 -0500
@@ -121,11 +121,6 @@
 	void (*agp_destroy_pages)(struct agp_memory *);
 	int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
 	void (*chipset_flush)(struct agp_bridge_data *);
-
-	int (*agp_map_page)(struct page *page, dma_addr_t *ret);
-	void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
-	int (*agp_map_memory)(struct agp_memory *mem);
-	void (*agp_unmap_memory)(struct agp_memory *mem);
 };
 
 struct agp_bridge_data {
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/amd64-agp.c linux-libre-2.6.37-gnu/drivers/char/agp/amd64-agp.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/amd64-agp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/amd64-agp.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
 #include <linux/mmzone.h>
 #include <asm/page.h>		/* PAGE_SIZE */
 #include <asm/e820.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/gart.h>
 #include "agp.h"
 
@@ -124,7 +124,7 @@
 	u32 temp;
 	struct aper_size_info_32 *values;
 
-	dev = k8_northbridges[0];
+	dev = k8_northbridges.nb_misc[0];
 	if (dev==NULL)
 		return 0;
 
@@ -181,10 +181,14 @@
 	unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
 	int i;
 
+	if (!k8_northbridges.gart_supported)
+		return 0;
+
 	/* Configure AGP regs in each x86-64 host bridge. */
-        for (i = 0; i < num_k8_northbridges; i++) {
+	for (i = 0; i < k8_northbridges.num; i++) {
 		agp_bridge->gart_bus_addr =
-				amd64_configure(k8_northbridges[i], gatt_bus);
+				amd64_configure(k8_northbridges.nb_misc[i],
+						gatt_bus);
 	}
 	k8_flush_garts();
 	return 0;
@@ -195,11 +199,15 @@
 {
 	u32 tmp;
 	int i;
-        for (i = 0; i < num_k8_northbridges; i++) {
-		struct pci_dev *dev = k8_northbridges[i];
+
+	if (!k8_northbridges.gart_supported)
+		return;
+
+	for (i = 0; i < k8_northbridges.num; i++) {
+		struct pci_dev *dev = k8_northbridges.nb_misc[i];
 		/* disable gart translation */
 		pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
-		tmp &= ~AMD64_GARTEN;
+		tmp &= ~GARTEN;
 		pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp);
 	}
 }
@@ -313,22 +321,25 @@
 	if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
 		return -1;
 
-	pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1);
+	gart_set_size_and_enable(nb, order);
 	pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25);
 
 	return 0;
 }
 
-static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
+static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
 {
 	int i;
 
 	if (cache_k8_northbridges() < 0)
 		return -ENODEV;
 
+	if (!k8_northbridges.gart_supported)
+		return -ENODEV;
+
 	i = 0;
-	for (i = 0; i < num_k8_northbridges; i++) {
-		struct pci_dev *dev = k8_northbridges[i];
+	for (i = 0; i < k8_northbridges.num; i++) {
+		struct pci_dev *dev = k8_northbridges.nb_misc[i];
 		if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
 			dev_err(&dev->dev, "no usable aperture found\n");
 #ifdef __x86_64__
@@ -405,7 +416,8 @@
 	}
 
 	/* shadow x86-64 registers into ULi registers */
-	pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
+	pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+			       &httfea);
 
 	/* if x86-64 aperture base is beyond 4G, exit here */
 	if ((httfea & 0x7fff) >> (32 - 25)) {
@@ -472,7 +484,8 @@
 	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
 
 	/* shadow x86-64 registers into NVIDIA registers */
-	pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase);
+	pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+			       &apbase);
 
 	/* if x86-64 aperture base is beyond 4G, exit here */
 	if ( (apbase & 0x7fff) >> (32 - 25) ) {
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/amd-k7-agp.c linux-libre-2.6.37-gnu/drivers/char/agp/amd-k7-agp.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/amd-k7-agp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/amd-k7-agp.c	2011-01-04 19:50:19.000000000 -0500
@@ -309,7 +309,8 @@
 
 	num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 
-	if (type != 0 || mem->type != 0)
+	if (type != mem->type ||
+	    agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
 		return -EINVAL;
 
 	if ((pg_start + mem->page_count) > num_entries)
@@ -348,7 +349,8 @@
 	unsigned long __iomem *cur_gatt;
 	unsigned long addr;
 
-	if (type != 0 || mem->type != 0)
+	if (type != mem->type ||
+	    agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type))
 		return -EINVAL;
 
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/backend.c linux-libre-2.6.37-gnu/drivers/char/agp/backend.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/backend.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/backend.c	2011-01-04 19:50:19.000000000 -0500
@@ -151,17 +151,7 @@
 		}
 
 		bridge->scratch_page_page = page;
-		if (bridge->driver->agp_map_page) {
-			if (bridge->driver->agp_map_page(page,
-							 &bridge->scratch_page_dma)) {
-				dev_err(&bridge->dev->dev,
-					"unable to dma-map scratch page\n");
-				rc = -ENOMEM;
-				goto err_out_nounmap;
-			}
-		} else {
-			bridge->scratch_page_dma = page_to_phys(page);
-		}
+		bridge->scratch_page_dma = page_to_phys(page);
 
 		bridge->scratch_page = bridge->driver->mask_memory(bridge,
 						   bridge->scratch_page_dma, 0);
@@ -204,12 +194,6 @@
 	return 0;
 
 err_out:
-	if (bridge->driver->needs_scratch_page &&
-	    bridge->driver->agp_unmap_page) {
-		bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-					       bridge->scratch_page_dma);
-	}
-err_out_nounmap:
 	if (bridge->driver->needs_scratch_page) {
 		void *va = page_address(bridge->scratch_page_page);
 
@@ -240,10 +224,6 @@
 	    bridge->driver->needs_scratch_page) {
 		void *va = page_address(bridge->scratch_page_page);
 
-		if (bridge->driver->agp_unmap_page)
-			bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-						       bridge->scratch_page_dma);
-
 		bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
 		bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/frontend.c linux-libre-2.6.37-gnu/drivers/char/agp/frontend.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/frontend.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/frontend.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,6 @@
 #include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include "agp.h"
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/generic.c linux-libre-2.6.37-gnu/drivers/char/agp/generic.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/generic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/generic.c	2011-01-04 19:50:19.000000000 -0500
@@ -437,11 +437,6 @@
 		curr->is_flushed = true;
 	}
 
-	if (curr->bridge->driver->agp_map_memory) {
-		ret_val = curr->bridge->driver->agp_map_memory(curr);
-		if (ret_val)
-			return ret_val;
-	}
 	ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
 	if (ret_val != 0)
@@ -483,9 +478,6 @@
 	if (ret_val != 0)
 		return ret_val;
 
-	if (curr->bridge->driver->agp_unmap_memory)
-		curr->bridge->driver->agp_unmap_memory(curr);
-
 	curr->is_bound = false;
 	curr->pg_start = 0;
 	spin_lock(&curr->bridge->mapped_lock);
@@ -984,7 +976,9 @@
 
 	bridge->driver->cache_flush();
 #ifdef CONFIG_X86
-	set_memory_uc((unsigned long)table, 1 << page_order);
+	if (set_memory_uc((unsigned long)table, 1 << page_order))
+		printk(KERN_WARNING "Could not set GATT table memory to UC!");
+
 	bridge->gatt_table = (void *)table;
 #else
 	bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/i460-agp.c linux-libre-2.6.37-gnu/drivers/char/agp/i460-agp.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/i460-agp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/i460-agp.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * For documentation on the i460 AGP interface, see Chapter 7 (AGP Subsystem) of
  * the "Intel 460GTX Chipset Software Developer's Manual":
- * http://developer.intel.com/design/itanium/downloads/24870401s.htm
+ * http://www.intel.com/design/archives/itanium/downloads/248704.htm 
  */
 /*
  * 460GX support by Chris Ahna <christopher.j.ahna@intel.com>
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/intel-agp.c linux-libre-2.6.37-gnu/drivers/char/agp/intel-agp.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/intel-agp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/intel-agp.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,9 +12,6 @@
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
-#include <linux/intel-gtt.h>
-
-#include "intel-gtt.c"
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
@@ -703,179 +700,37 @@
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int find_gmch(u16 device)
-{
-	struct pci_dev *gmch_device;
-
-	gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
-	if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
-		gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
-					     device, gmch_device);
-	}
-
-	if (!gmch_device)
-		return 0;
-
-	intel_private.pcidev = gmch_device;
-	return 1;
-}
-
 /* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
  * driver and gmch_driver must be non-null, and find_gmch will determine
  * which one should be used if a gmch_chip_id is present.
  */
-static const struct intel_driver_description {
+static const struct intel_agp_driver_description {
 	unsigned int chip_id;
-	unsigned int gmch_chip_id;
 	char *name;
 	const struct agp_bridge_driver *driver;
-	const struct agp_bridge_driver *gmch_driver;
 } intel_agp_chipsets[] = {
-	{ PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
-		&intel_815_driver, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
-		&intel_830mp_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
-	    "GM45", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
-	    "Eaglelake", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
-	    "Q45/Q43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
-	    "G45/G43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
-	    "B43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
-	    "B43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
-	    "G41", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ 0, 0, NULL, NULL, NULL }
+	{ PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
+	{ PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
+	{ PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
+	{ PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
+	{ PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
+	{ PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
+	{ PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
+	{ PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
+	{ PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
+	{ 0, NULL, NULL }
 };
 
-static int __devinit intel_gmch_probe(struct pci_dev *pdev,
-				      struct agp_bridge_data *bridge)
-{
-	int i, mask;
-
-	bridge->driver = NULL;
-
-	for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
-		if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
-			find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
-			bridge->driver =
-				intel_agp_chipsets[i].gmch_driver;
-			break;
-		}
-	}
-
-	if (!bridge->driver)
-		return 0;
-
-	bridge->dev_private_data = &intel_private;
-	bridge->dev = pdev;
-
-	dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
-
-	if (bridge->driver->mask_memory == intel_gen6_mask_memory)
-		mask = 40;
-	else if (bridge->driver->mask_memory == intel_i965_mask_memory)
-		mask = 36;
-	else
-		mask = 32;
-
-	if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
-		dev_err(&intel_private.pcidev->dev,
-			"set gfx device dma mask %d-bit failed!\n", mask);
-	else
-		pci_set_consistent_dma_mask(intel_private.pcidev,
-					    DMA_BIT_MASK(mask));
-
-	return 1;
-}
-
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
@@ -905,7 +760,7 @@
 		}
 	}
 
-	if (intel_agp_chipsets[i].name == NULL) {
+	if (!bridge->driver) {
 		if (cap_ptr)
 			dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
 				 pdev->vendor, pdev->device);
@@ -913,14 +768,6 @@
 		return -ENODEV;
 	}
 
-	if (!bridge->driver) {
-		if (cap_ptr)
-			dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
-			    	 intel_agp_chipsets[i].gmch_chip_id);
-		agp_put_bridge(bridge);
-		return -ENODEV;
-	}
-
 	bridge->dev = pdev;
 	bridge->dev_private_data = NULL;
 
@@ -972,8 +819,7 @@
 
 	agp_remove_bridge(bridge);
 
-	if (intel_private.pcidev)
-		pci_dev_put(intel_private.pcidev);
+	intel_gmch_remove(pdev);
 
 	agp_put_bridge(bridge);
 }
@@ -1049,6 +895,7 @@
 	ID(PCI_DEVICE_ID_INTEL_G45_HB),
 	ID(PCI_DEVICE_ID_INTEL_G41_HB),
 	ID(PCI_DEVICE_ID_INTEL_B43_HB),
+	ID(PCI_DEVICE_ID_INTEL_B43_1_HB),
 	ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
 	ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
 	ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/intel-agp.h linux-libre-2.6.37-gnu/drivers/char/agp/intel-agp.h
--- linux-libre-2.6.36-gnu/drivers/char/agp/intel-agp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/intel-agp.h	2011-01-04 19:50:19.000000000 -0500
@@ -215,44 +215,7 @@
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB		0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG		0x010A
 
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
-		IS_SNB)
-
+int intel_gmch_probe(struct pci_dev *pdev,
+			       struct agp_bridge_data *bridge);
+void intel_gmch_remove(struct pci_dev *pdev);
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/intel-gtt.c linux-libre-2.6.37-gnu/drivers/char/agp/intel-gtt.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/intel-gtt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/intel-gtt.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,6 +15,18 @@
  * /fairy-tale-mode off
  */
 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/smp.h>
+#include "agp.h"
+#include "intel-agp.h"
+#include <linux/intel-gtt.h>
+#include <drm/intel-gtt.h>
+
 /*
  * If we have Intel graphics, we're not going to have anything other than
  * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
@@ -23,11 +35,12 @@
  */
 #ifdef CONFIG_DMAR
 #define USE_PCI_DMA_API 1
+#else
+#define USE_PCI_DMA_API 0
 #endif
 
 /* Max amount of stolen space, anything above will be returned to Linux */
 int intel_max_stolen = 32 * 1024 * 1024;
-EXPORT_SYMBOL(intel_max_stolen);
 
 static const struct aper_size_info_fixed intel_i810_sizes[] =
 {
@@ -55,32 +68,36 @@
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC        3
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT   4
 
-static struct gatt_mask intel_gen6_masks[] =
-{
-	{.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED,
-	 .type = INTEL_AGP_UNCACHED_MEMORY },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT },
+struct intel_gtt_driver {
+	unsigned int gen : 8;
+	unsigned int is_g33 : 1;
+	unsigned int is_pineview : 1;
+	unsigned int is_ironlake : 1;
+	unsigned int dma_mask_size : 8;
+	/* Chipset specific GTT setup */
+	int (*setup)(void);
+	/* This should undo anything done in ->setup() save the unmapping
+	 * of the mmio register file, that's done in the generic code. */
+	void (*cleanup)(void);
+	void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
+	/* Flags is a more or less chipset specific opaque value.
+	 * For chipsets that need to support old ums (non-gem) code, this
+	 * needs to be identical to the various supported agp memory types! */
+	bool (*check_flags)(unsigned int flags);
+	void (*chipset_flush)(void);
 };
 
 static struct _intel_private {
+	struct intel_gtt base;
+	const struct intel_gtt_driver *driver;
 	struct pci_dev *pcidev;	/* device one */
+	struct pci_dev *bridge_dev;
 	u8 __iomem *registers;
+	phys_addr_t gtt_bus_addr;
+	phys_addr_t gma_bus_addr;
+	phys_addr_t pte_bus_addr;
 	u32 __iomem *gtt;		/* I915G */
 	int num_dcache_entries;
-	/* gtt_entries is the number of gtt entries that are already mapped
-	 * to stolen memory.  Stolen memory is larger than the memory mapped
-	 * through gtt_entries, as it includes some reserved space for the BIOS
-	 * popup and for the GTT.
-	 */
-	int gtt_entries;			/* i830+ */
-	int gtt_total_size;
 	union {
 		void __iomem *i9xx_flush_page;
 		void *i8xx_flush_page;
@@ -88,23 +105,14 @@
 	struct page *i8xx_page;
 	struct resource ifp_resource;
 	int resource_valid;
+	struct page *scratch_page;
+	dma_addr_t scratch_page_dma;
 } intel_private;
 
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
-	*ret = pci_map_page(intel_private.pcidev, page, 0,
-			    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-	if (pci_dma_mapping_error(intel_private.pcidev, *ret))
-		return -EINVAL;
-	return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
-	pci_unmap_page(intel_private.pcidev, dma,
-		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
+#define INTEL_GTT_GEN	intel_private.driver->gen
+#define IS_G33		intel_private.driver->is_g33
+#define IS_PINEVIEW	intel_private.driver->is_pineview
+#define IS_IRONLAKE	intel_private.driver->is_ironlake
 
 static void intel_agp_free_sglist(struct agp_memory *mem)
 {
@@ -125,6 +133,9 @@
 	struct scatterlist *sg;
 	int i;
 
+	if (mem->sg_list)
+		return 0; /* already mapped (for e.g. resume */
+
 	DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
 
 	if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
@@ -156,70 +167,17 @@
 	intel_agp_free_sglist(mem);
 }
 
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-					off_t pg_start, int mask_type)
-{
-	struct scatterlist *sg;
-	int i, j;
-
-	j = pg_start;
-
-	WARN_ON(!mem->num_sg);
-
-	if (mem->num_sg == mem->page_count) {
-		for_each_sg(mem->sg_list, sg, mem->page_count, i) {
-			writel(agp_bridge->driver->mask_memory(agp_bridge,
-					sg_dma_address(sg), mask_type),
-					intel_private.gtt+j);
-			j++;
-		}
-	} else {
-		/* sg may merge pages, but we have to separate
-		 * per-page addr for GTT */
-		unsigned int len, m;
-
-		for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
-			len = sg_dma_len(sg) / PAGE_SIZE;
-			for (m = 0; m < len; m++) {
-				writel(agp_bridge->driver->mask_memory(agp_bridge,
-								       sg_dma_address(sg) + m * PAGE_SIZE,
-								       mask_type),
-				       intel_private.gtt+j);
-				j++;
-			}
-		}
-	}
-	readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-					off_t pg_start, int mask_type)
-{
-	int i, j;
-
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(agp_bridge,
-				page_to_phys(mem->pages[i]), mask_type),
-		       intel_private.gtt+j);
-	}
-
-	readl(intel_private.gtt+j-1);
-}
-
-#endif
-
 static int intel_i810_fetch_size(void)
 {
 	u32 smram_miscc;
 	struct aper_size_info_fixed *values;
 
-	pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+	pci_read_config_dword(intel_private.bridge_dev,
+			      I810_SMRAM_MISCC, &smram_miscc);
 	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
 
 	if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
-		dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+		dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
 		return 0;
 	}
 	if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
@@ -284,7 +242,7 @@
 	iounmap(intel_private.registers);
 }
 
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
 	return;
 }
@@ -319,34 +277,6 @@
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
 
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
-					int type)
-{
-	if (type < AGP_USER_TYPES)
-		return type;
-	else if (type == AGP_USER_CACHED_MEMORY)
-		return INTEL_AGP_CACHED_MEMORY;
-	else
-		return 0;
-}
-
-static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge,
-					int type)
-{
-	unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT;
-	unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT;
-
-	if (type_mask == AGP_USER_UNCACHED_MEMORY)
-		return INTEL_AGP_UNCACHED_MEMORY;
-	else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC)
-		return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT :
-			      INTEL_AGP_CACHED_MEMORY_LLC_MLC;
-	else /* set 'normal'/'cached' to LLC by default */
-		return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT :
-			      INTEL_AGP_CACHED_MEMORY_LLC;
-}
-
-
 static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
 				int type)
 {
@@ -514,8 +444,33 @@
 	return addr | bridge->driver->masks[type].mask;
 }
 
-static struct aper_size_info_fixed intel_i830_sizes[] =
+static int intel_gtt_setup_scratch_page(void)
 {
+	struct page *page;
+	dma_addr_t dma_addr;
+
+	page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+	if (page == NULL)
+		return -ENOMEM;
+	get_page(page);
+	set_pages_uc(page, 1);
+
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+		dma_addr = pci_map_page(intel_private.pcidev, page, 0,
+				    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+			return -EINVAL;
+
+		intel_private.scratch_page_dma = dma_addr;
+	} else
+		intel_private.scratch_page_dma = page_to_phys(page);
+
+	intel_private.scratch_page = page;
+
+	return 0;
+}
+
+static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
 	{128, 32768, 5},
 	/* The 64M mode still requires a 128k gatt */
 	{64, 16384, 5},
@@ -523,102 +478,49 @@
 	{512, 131072, 7},
 };
 
-static void intel_i830_init_gtt_entries(void)
+static unsigned int intel_gtt_stolen_entries(void)
 {
 	u16 gmch_ctrl;
-	int gtt_entries = 0;
 	u8 rdct;
 	int local = 0;
 	static const int ddt[4] = { 0, 16, 32, 64 };
-	int size; /* reserved space (in kb) at the top of stolen memory */
+	unsigned int overhead_entries, stolen_entries;
+	unsigned int stolen_size = 0;
 
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+	pci_read_config_word(intel_private.bridge_dev,
+			     I830_GMCH_CTRL, &gmch_ctrl);
 
-	if (IS_I965) {
-		u32 pgetbl_ctl;
-		pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+	if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
+		overhead_entries = 0;
+	else
+		overhead_entries = intel_private.base.gtt_mappable_entries
+			/ 1024;
 
-		/* The 965 has a field telling us the size of the GTT,
-		 * which may be larger than what is necessary to map the
-		 * aperture.
-		 */
-		switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-		case I965_PGETBL_SIZE_128KB:
-			size = 128;
-			break;
-		case I965_PGETBL_SIZE_256KB:
-			size = 256;
-			break;
-		case I965_PGETBL_SIZE_512KB:
-			size = 512;
-			break;
-		case I965_PGETBL_SIZE_1MB:
-			size = 1024;
-			break;
-		case I965_PGETBL_SIZE_2MB:
-			size = 2048;
-			break;
-		case I965_PGETBL_SIZE_1_5MB:
-			size = 1024 + 512;
-			break;
-		default:
-			dev_info(&intel_private.pcidev->dev,
-				 "unknown page table size, assuming 512KB\n");
-			size = 512;
-		}
-		size += 4; /* add in BIOS popup space */
-	} else if (IS_G33 && !IS_PINEVIEW) {
-	/* G33's GTT size defined in gmch_ctrl */
-		switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
-		case G33_PGETBL_SIZE_1M:
-			size = 1024;
-			break;
-		case G33_PGETBL_SIZE_2M:
-			size = 2048;
-			break;
-		default:
-			dev_info(&agp_bridge->dev->dev,
-				 "unknown page table size 0x%x, assuming 512KB\n",
-				(gmch_ctrl & G33_PGETBL_SIZE_MASK));
-			size = 512;
-		}
-		size += 4;
-	} else if (IS_G4X || IS_PINEVIEW) {
-		/* On 4 series hardware, GTT stolen is separate from graphics
-		 * stolen, ignore it in stolen gtt entries counting.  However,
-		 * 4KB of the stolen memory doesn't get mapped to the GTT.
-		 */
-		size = 4;
-	} else {
-		/* On previous hardware, the GTT size was just what was
-		 * required to map the aperture.
-		 */
-		size = agp_bridge->driver->fetch_size() + 4;
-	}
+	overhead_entries += 1; /* BIOS popup */
 
-	if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-	    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+	if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+	    intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
 		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
 		case I830_GMCH_GMS_STOLEN_512:
-			gtt_entries = KB(512) - KB(size);
+			stolen_size = KB(512);
 			break;
 		case I830_GMCH_GMS_STOLEN_1024:
-			gtt_entries = MB(1) - KB(size);
+			stolen_size = MB(1);
 			break;
 		case I830_GMCH_GMS_STOLEN_8192:
-			gtt_entries = MB(8) - KB(size);
+			stolen_size = MB(8);
 			break;
 		case I830_GMCH_GMS_LOCAL:
 			rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-			gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+			stolen_size = (I830_RDRAM_ND(rdct) + 1) *
 					MB(ddt[I830_RDRAM_DDT(rdct)]);
 			local = 1;
 			break;
 		default:
-			gtt_entries = 0;
+			stolen_size = 0;
 			break;
 		}
-	} else if (IS_SNB) {
+	} else if (INTEL_GTT_GEN == 6) {
 		/*
 		 * SandyBridge has new memory control reg at 0x50.w
 		 */
@@ -626,149 +528,294 @@
 		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 		switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
 		case SNB_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(size);
+			stolen_size = MB(32);
 			break;
 		case SNB_GMCH_GMS_STOLEN_64M:
-			gtt_entries = MB(64) - KB(size);
+			stolen_size = MB(64);
 			break;
 		case SNB_GMCH_GMS_STOLEN_96M:
-			gtt_entries = MB(96) - KB(size);
+			stolen_size = MB(96);
 			break;
 		case SNB_GMCH_GMS_STOLEN_128M:
-			gtt_entries = MB(128) - KB(size);
+			stolen_size = MB(128);
 			break;
 		case SNB_GMCH_GMS_STOLEN_160M:
-			gtt_entries = MB(160) - KB(size);
+			stolen_size = MB(160);
 			break;
 		case SNB_GMCH_GMS_STOLEN_192M:
-			gtt_entries = MB(192) - KB(size);
+			stolen_size = MB(192);
 			break;
 		case SNB_GMCH_GMS_STOLEN_224M:
-			gtt_entries = MB(224) - KB(size);
+			stolen_size = MB(224);
 			break;
 		case SNB_GMCH_GMS_STOLEN_256M:
-			gtt_entries = MB(256) - KB(size);
+			stolen_size = MB(256);
 			break;
 		case SNB_GMCH_GMS_STOLEN_288M:
-			gtt_entries = MB(288) - KB(size);
+			stolen_size = MB(288);
 			break;
 		case SNB_GMCH_GMS_STOLEN_320M:
-			gtt_entries = MB(320) - KB(size);
+			stolen_size = MB(320);
 			break;
 		case SNB_GMCH_GMS_STOLEN_352M:
-			gtt_entries = MB(352) - KB(size);
+			stolen_size = MB(352);
 			break;
 		case SNB_GMCH_GMS_STOLEN_384M:
-			gtt_entries = MB(384) - KB(size);
+			stolen_size = MB(384);
 			break;
 		case SNB_GMCH_GMS_STOLEN_416M:
-			gtt_entries = MB(416) - KB(size);
+			stolen_size = MB(416);
 			break;
 		case SNB_GMCH_GMS_STOLEN_448M:
-			gtt_entries = MB(448) - KB(size);
+			stolen_size = MB(448);
 			break;
 		case SNB_GMCH_GMS_STOLEN_480M:
-			gtt_entries = MB(480) - KB(size);
+			stolen_size = MB(480);
 			break;
 		case SNB_GMCH_GMS_STOLEN_512M:
-			gtt_entries = MB(512) - KB(size);
+			stolen_size = MB(512);
 			break;
 		}
 	} else {
 		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
 		case I855_GMCH_GMS_STOLEN_1M:
-			gtt_entries = MB(1) - KB(size);
+			stolen_size = MB(1);
 			break;
 		case I855_GMCH_GMS_STOLEN_4M:
-			gtt_entries = MB(4) - KB(size);
+			stolen_size = MB(4);
 			break;
 		case I855_GMCH_GMS_STOLEN_8M:
-			gtt_entries = MB(8) - KB(size);
+			stolen_size = MB(8);
 			break;
 		case I855_GMCH_GMS_STOLEN_16M:
-			gtt_entries = MB(16) - KB(size);
+			stolen_size = MB(16);
 			break;
 		case I855_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(size);
+			stolen_size = MB(32);
 			break;
 		case I915_GMCH_GMS_STOLEN_48M:
-			/* Check it's really I915G */
-			if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-				gtt_entries = MB(48) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(48);
 			break;
 		case I915_GMCH_GMS_STOLEN_64M:
-			/* Check it's really I915G */
-			if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-				gtt_entries = MB(64) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(64);
 			break;
 		case G33_GMCH_GMS_STOLEN_128M:
-			if (IS_G33 || IS_I965 || IS_G4X)
-				gtt_entries = MB(128) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(128);
 			break;
 		case G33_GMCH_GMS_STOLEN_256M:
-			if (IS_G33 || IS_I965 || IS_G4X)
-				gtt_entries = MB(256) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(256);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_96M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(96) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(96);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_160M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(160) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(160);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_224M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(224) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(224);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_352M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(352) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(352);
 			break;
 		default:
-			gtt_entries = 0;
+			stolen_size = 0;
 			break;
 		}
 	}
-	if (!local && gtt_entries > intel_max_stolen) {
-		dev_info(&agp_bridge->dev->dev,
+
+	if (!local && stolen_size > intel_max_stolen) {
+		dev_info(&intel_private.bridge_dev->dev,
 			 "detected %dK stolen memory, trimming to %dK\n",
-			 gtt_entries / KB(1), intel_max_stolen / KB(1));
-		gtt_entries = intel_max_stolen / KB(4);
-	} else if (gtt_entries > 0) {
-		dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
-		       gtt_entries / KB(1), local ? "local" : "stolen");
-		gtt_entries /= KB(4);
+			 stolen_size / KB(1), intel_max_stolen / KB(1));
+		stolen_size = intel_max_stolen;
+	} else if (stolen_size > 0) {
+		dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
+		       stolen_size / KB(1), local ? "local" : "stolen");
 	} else {
-		dev_info(&agp_bridge->dev->dev,
+		dev_info(&intel_private.bridge_dev->dev,
 		       "no pre-allocated video memory detected\n");
-		gtt_entries = 0;
+		stolen_size = 0;
 	}
 
-	intel_private.gtt_entries = gtt_entries;
+	stolen_entries = stolen_size/KB(4) - overhead_entries;
+
+	return stolen_entries;
 }
 
-static void intel_i830_fini_flush(void)
+static unsigned int intel_gtt_total_entries(void)
 {
-	kunmap(intel_private.i8xx_page);
-	intel_private.i8xx_flush_page = NULL;
-	unmap_page_from_agp(intel_private.i8xx_page);
+	int size;
+
+	if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
+		u32 pgetbl_ctl;
+		pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+		switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+		case I965_PGETBL_SIZE_128KB:
+			size = KB(128);
+			break;
+		case I965_PGETBL_SIZE_256KB:
+			size = KB(256);
+			break;
+		case I965_PGETBL_SIZE_512KB:
+			size = KB(512);
+			break;
+		case I965_PGETBL_SIZE_1MB:
+			size = KB(1024);
+			break;
+		case I965_PGETBL_SIZE_2MB:
+			size = KB(2048);
+			break;
+		case I965_PGETBL_SIZE_1_5MB:
+			size = KB(1024 + 512);
+			break;
+		default:
+			dev_info(&intel_private.pcidev->dev,
+				 "unknown page table size, assuming 512KB\n");
+			size = KB(512);
+		}
+
+		return size/4;
+	} else if (INTEL_GTT_GEN == 6) {
+		u16 snb_gmch_ctl;
+
+		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+		switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+		default:
+		case SNB_GTT_SIZE_0M:
+			printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+			size = MB(0);
+			break;
+		case SNB_GTT_SIZE_1M:
+			size = MB(1);
+			break;
+		case SNB_GTT_SIZE_2M:
+			size = MB(2);
+			break;
+		}
+		return size/4;
+	} else {
+		/* On previous hardware, the GTT size was just what was
+		 * required to map the aperture.
+		 */
+		return intel_private.base.gtt_mappable_entries;
+	}
+}
+
+static unsigned int intel_gtt_mappable_entries(void)
+{
+	unsigned int aperture_size;
+
+	if (INTEL_GTT_GEN == 2) {
+		u16 gmch_ctrl;
+
+		pci_read_config_word(intel_private.bridge_dev,
+				     I830_GMCH_CTRL, &gmch_ctrl);
+
+		if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
+			aperture_size = MB(64);
+		else
+			aperture_size = MB(128);
+	} else {
+		/* 9xx supports large sizes, just look at the length */
+		aperture_size = pci_resource_len(intel_private.pcidev, 2);
+	}
+
+	return aperture_size >> PAGE_SHIFT;
+}
+
+static void intel_gtt_teardown_scratch_page(void)
+{
+	set_pages_wb(intel_private.scratch_page, 1);
+	pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+	put_page(intel_private.scratch_page);
+	__free_page(intel_private.scratch_page);
+}
+
+static void intel_gtt_cleanup(void)
+{
+	intel_private.driver->cleanup();
+
+	iounmap(intel_private.gtt);
+	iounmap(intel_private.registers);
+	
+	intel_gtt_teardown_scratch_page();
+}
+
+static int intel_gtt_init(void)
+{
+	u32 gtt_map_size;
+	int ret;
+
+	ret = intel_private.driver->setup();
+	if (ret != 0)
+		return ret;
+
+	intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
+	intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+
+	dev_info(&intel_private.bridge_dev->dev,
+			"detected gtt size: %dK total, %dK mappable\n",
+			intel_private.base.gtt_total_entries * 4,
+			intel_private.base.gtt_mappable_entries * 4);
+
+	gtt_map_size = intel_private.base.gtt_total_entries * 4;
+
+	intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+				    gtt_map_size);
+	if (!intel_private.gtt) {
+		intel_private.driver->cleanup();
+		iounmap(intel_private.registers);
+		return -ENOMEM;
+	}
+
+	global_cache_flush();   /* FIXME: ? */
+
+	/* we have to call this as early as possible after the MMIO base address is known */
+	intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
+	if (intel_private.base.gtt_stolen_entries == 0) {
+		intel_private.driver->cleanup();
+		iounmap(intel_private.registers);
+		iounmap(intel_private.gtt);
+		return -ENOMEM;
+	}
+
+	ret = intel_gtt_setup_scratch_page();
+	if (ret != 0) {
+		intel_gtt_cleanup();
+		return ret;
+	}
+
+	return 0;
+}
+
+static int intel_fake_agp_fetch_size(void)
+{
+	int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
+	unsigned int aper_size;
+	int i;
+
+	aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
+		    / MB(1);
+
+	for (i = 0; i < num_sizes; i++) {
+		if (aper_size == intel_fake_agp_sizes[i].size) {
+			agp_bridge->current_size =
+				(void *) (intel_fake_agp_sizes + i);
+			return aper_size;
+		}
+	}
+
+	return 0;
+}
+
+static void i830_cleanup(void)
+{
+	if (intel_private.i8xx_flush_page) {
+		kunmap(intel_private.i8xx_flush_page);
+		intel_private.i8xx_flush_page = NULL;
+	}
 
 	__free_page(intel_private.i8xx_page);
 	intel_private.i8xx_page = NULL;
@@ -780,13 +827,13 @@
 	if (intel_private.i8xx_page)
 		return;
 
-	intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+	intel_private.i8xx_page = alloc_page(GFP_KERNEL);
 	if (!intel_private.i8xx_page)
 		return;
 
 	intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
 	if (!intel_private.i8xx_flush_page)
-		intel_i830_fini_flush();
+		i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -799,7 +846,7 @@
  * that buffer out, we just fill 1KB and clflush it out, on the assumption
  * that it'll push whatever was in there out.  It appears to work.
  */
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+static void i830_chipset_flush(void)
 {
 	unsigned int *pg = intel_private.i8xx_flush_page;
 
@@ -811,169 +858,184 @@
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
 }
 
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+static void i830_write_entry(dma_addr_t addr, unsigned int entry,
+			     unsigned int flags)
 {
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp;
+	u32 pte_flags = I810_PTE_VALID;
+	
+	switch (flags) {
+	case AGP_DCACHE_MEMORY:
+		pte_flags |= I810_PTE_LOCAL;
+		break;
+	case AGP_USER_CACHED_MEMORY:
+		pte_flags |= I830_PTE_SYSTEM_CACHED;
+		break;
+	}
 
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
+	writel(addr | pte_flags, intel_private.gtt + entry);
+}
 
-	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-	temp &= 0xfff80000;
+static void intel_enable_gtt(void)
+{
+	u32 gma_addr;
+	u16 gmch_ctrl;
 
-	intel_private.registers = ioremap(temp, 128 * 4096);
-	if (!intel_private.registers)
-		return -ENOMEM;
+	if (INTEL_GTT_GEN == 2)
+		pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
+				      &gma_addr);
+	else
+		pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
+				      &gma_addr);
 
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();	/* FIXME: ?? */
+	intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
 
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.registers);
+	pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
+	gmch_ctrl |= I830_GMCH_ENABLED;
+	pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+
+	writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
+	       intel_private.registers+I810_PGETBL_CTL);
+	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
+}
+
+static int i830_setup(void)
+{
+	u32 reg_addr;
+
+	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+	reg_addr &= 0xfff80000;
+
+	intel_private.registers = ioremap(reg_addr, KB(64));
+	if (!intel_private.registers)
 		return -ENOMEM;
-	}
 
-	agp_bridge->gatt_table = NULL;
+	intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+	intel_private.pte_bus_addr =
+		readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-	agp_bridge->gatt_bus_addr = temp;
+	intel_i830_setup_flush();
 
 	return 0;
 }
 
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
 {
+	agp_bridge->gatt_table_real = NULL;
+	agp_bridge->gatt_table = NULL;
+	agp_bridge->gatt_bus_addr = 0;
+
 	return 0;
 }
 
-static int intel_i830_fetch_size(void)
+static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
 {
-	u16 gmch_ctrl;
-	struct aper_size_info_fixed *values;
-
-	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-	if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-	    agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-		/* 855GM/852GM/865G has 128MB aperture size */
-		agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	}
-
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-	if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-		agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	} else {
-		agp_bridge->current_size = (void *) (values + 1);
-		agp_bridge->aperture_size_idx = 1;
-		return values[1].size;
-	}
-
 	return 0;
 }
 
-static int intel_i830_configure(void)
+static int intel_fake_agp_configure(void)
 {
-	struct aper_size_info_fixed *current_size;
-	u32 temp;
-	u16 gmch_ctrl;
 	int i;
 
-	current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-	pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-	gmch_ctrl |= I830_GMCH_ENABLED;
-	pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
+	intel_enable_gtt();
 
-	writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
+	agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
-	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
-			writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-		}
-		readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));	/* PCI Posting. */
+	for (i = intel_private.base.gtt_stolen_entries;
+			i < intel_private.base.gtt_total_entries; i++) {
+		intel_private.driver->write_entry(intel_private.scratch_page_dma,
+						  i, 0);
 	}
+	readl(intel_private.gtt+i-1);	/* PCI Posting. */
 
 	global_cache_flush();
 
-	intel_i830_setup_flush();
 	return 0;
 }
 
-static void intel_i830_cleanup(void)
+static bool i830_check_flags(unsigned int flags)
 {
-	iounmap(intel_private.registers);
+	switch (flags) {
+	case 0:
+	case AGP_PHYS_MEMORY:
+	case AGP_USER_CACHED_MEMORY:
+	case AGP_USER_MEMORY:
+		return true;
+	}
+
+	return false;
 }
 
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+					unsigned int sg_len,
+					unsigned int pg_start,
+					unsigned int flags)
 {
-	int i, j, num_entries;
-	void *temp;
+	struct scatterlist *sg;
+	unsigned int len, m;
+	int i, j;
+
+	j = pg_start;
+
+	/* sg may merge pages, but we have to separate
+	 * per-page addr for GTT */
+	for_each_sg(sg_list, sg, sg_len, i) {
+		len = sg_dma_len(sg) >> PAGE_SHIFT;
+		for (m = 0; m < len; m++) {
+			dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+			intel_private.driver->write_entry(addr,
+							  j, flags);
+			j++;
+		}
+	}
+	readl(intel_private.gtt+j-1);
+}
+
+static int intel_fake_agp_insert_entries(struct agp_memory *mem,
+					 off_t pg_start, int type)
+{
+	int i, j;
 	int ret = -EINVAL;
-	int mask_type;
 
 	if (mem->page_count == 0)
 		goto out;
 
-	temp = agp_bridge->current_size;
-	num_entries = A_SIZE_FIX(temp)->num_entries;
-
-	if (pg_start < intel_private.gtt_entries) {
+	if (pg_start < intel_private.base.gtt_stolen_entries) {
 		dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-			   "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-			   pg_start, intel_private.gtt_entries);
+			   "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
+			   pg_start, intel_private.base.gtt_stolen_entries);
 
 		dev_info(&intel_private.pcidev->dev,
 			 "trying to insert into local/stolen memory\n");
 		goto out_err;
 	}
 
-	if ((pg_start + mem->page_count) > num_entries)
+	if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
 		goto out_err;
 
-	/* The i830 can't check the GTT for entries since its read only,
-	 * depend on the caller to make the correct offset decisions.
-	 */
-
 	if (type != mem->type)
 		goto out_err;
 
-	mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-	if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-	    mask_type != INTEL_AGP_CACHED_MEMORY)
+	if (!intel_private.driver->check_flags(type))
 		goto out_err;
 
 	if (!mem->is_flushed)
 		global_cache_flush();
 
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(agp_bridge,
-				page_to_phys(mem->pages[i]), mask_type),
-		       intel_private.registers+I810_PTE_BASE+(j*4));
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+		ret = intel_agp_map_memory(mem);
+		if (ret != 0)
+			return ret;
+
+		intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+					    pg_start, type);
+	} else {
+		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+			dma_addr_t addr = page_to_phys(mem->pages[i]);
+			intel_private.driver->write_entry(addr,
+							  j, type);
+		}
+		readl(intel_private.gtt+j-1);
 	}
-	readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
 
 out:
 	ret = 0;
@@ -982,29 +1044,39 @@
 	return ret;
 }
 
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static int intel_fake_agp_remove_entries(struct agp_memory *mem,
+					 off_t pg_start, int type)
 {
 	int i;
 
 	if (mem->page_count == 0)
 		return 0;
 
-	if (pg_start < intel_private.gtt_entries) {
+	if (pg_start < intel_private.base.gtt_stolen_entries) {
 		dev_info(&intel_private.pcidev->dev,
 			 "trying to disable local/stolen memory\n");
 		return -EINVAL;
 	}
 
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
+		intel_agp_unmap_memory(mem);
+
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-		writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+		intel_private.driver->write_entry(intel_private.scratch_page_dma,
+						  i, 0);
 	}
-	readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+	readl(intel_private.gtt+i-1);
 
 	return 0;
 }
 
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
+{
+	intel_private.driver->chipset_flush();
+}
+
+static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
+						       int type)
 {
 	if (type == AGP_PHYS_MEMORY)
 		return alloc_agpphysmem_i8xx(pg_count, type);
@@ -1015,9 +1087,9 @@
 static int intel_alloc_chipset_flush_resource(void)
 {
 	int ret;
-	ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+	ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
 				     PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-				     pcibios_align_resource, agp_bridge->dev);
+				     pcibios_align_resource, intel_private.bridge_dev);
 
 	return ret;
 }
@@ -1027,11 +1099,11 @@
 	int ret;
 	u32 temp;
 
-	pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+	pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp);
 	if (!(temp & 0x1)) {
 		intel_alloc_chipset_flush_resource();
 		intel_private.resource_valid = 1;
-		pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+		pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
 	} else {
 		temp &= ~1;
 
@@ -1050,17 +1122,17 @@
 	u32 temp_hi, temp_lo;
 	int ret;
 
-	pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
-	pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
+	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo);
 
 	if (!(temp_lo & 0x1)) {
 
 		intel_alloc_chipset_flush_resource();
 
 		intel_private.resource_valid = 1;
-		pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4,
 			upper_32_bits(intel_private.ifp_resource.start));
-		pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
 	} else {
 		u64 l64;
 
@@ -1083,7 +1155,7 @@
 	if (intel_private.ifp_resource.start)
 		return;
 
-	if (IS_SNB)
+	if (INTEL_GTT_GEN == 6)
 		return;
 
 	/* setup a resource for this object */
@@ -1091,7 +1163,7 @@
 	intel_private.ifp_resource.flags = IORESOURCE_MEM;
 
 	/* Setup chipset flush for 915 */
-	if (IS_I965 || IS_G33 || IS_G4X) {
+	if (IS_G33 || INTEL_GTT_GEN >= 4) {
 		intel_i965_g33_setup_chipset_flush();
 	} else {
 		intel_i915_setup_chipset_flush();
@@ -1104,41 +1176,7 @@
 			"can't ioremap flush page - no chipset flushing\n");
 }
 
-static int intel_i9xx_configure(void)
-{
-	struct aper_size_info_fixed *current_size;
-	u32 temp;
-	u16 gmch_ctrl;
-	int i;
-
-	current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-	pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-	gmch_ctrl |= I830_GMCH_ENABLED;
-	pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-	writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
-
-	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
-			writel(agp_bridge->scratch_page, intel_private.gtt+i);
-		}
-		readl(intel_private.gtt+i-1);	/* PCI Posting. */
-	}
-
-	global_cache_flush();
-
-	intel_i9xx_setup_flush();
-
-	return 0;
-}
-
-static void intel_i915_cleanup(void)
+static void i9xx_cleanup(void)
 {
 	if (intel_private.i9xx_flush_page)
 		iounmap(intel_private.i9xx_flush_page);
@@ -1146,320 +1184,100 @@
 		release_resource(&intel_private.ifp_resource);
 	intel_private.ifp_resource.start = 0;
 	intel_private.resource_valid = 0;
-	iounmap(intel_private.gtt);
-	iounmap(intel_private.registers);
 }
 
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+static void i9xx_chipset_flush(void)
 {
 	if (intel_private.i9xx_flush_page)
 		writel(1, intel_private.i9xx_flush_page);
 }
 
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static void i965_write_entry(dma_addr_t addr,
+			     unsigned int entry,
+			     unsigned int flags)
 {
-	int num_entries;
-	void *temp;
-	int ret = -EINVAL;
-	int mask_type;
-
-	if (mem->page_count == 0)
-		goto out;
-
-	temp = agp_bridge->current_size;
-	num_entries = A_SIZE_FIX(temp)->num_entries;
-
-	if (pg_start < intel_private.gtt_entries) {
-		dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-			   "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-			   pg_start, intel_private.gtt_entries);
-
-		dev_info(&intel_private.pcidev->dev,
-			 "trying to insert into local/stolen memory\n");
-		goto out_err;
-	}
-
-	if ((pg_start + mem->page_count) > num_entries)
-		goto out_err;
-
-	/* The i915 can't check the GTT for entries since it's read only;
-	 * depend on the caller to make the correct offset decisions.
-	 */
-
-	if (type != mem->type)
-		goto out_err;
-
-	mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-	if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-	    mask_type != INTEL_AGP_CACHED_MEMORY)
-		goto out_err;
-
-	if (!mem->is_flushed)
-		global_cache_flush();
+	u32 pte_flags;
 
-	intel_agp_insert_sg_entries(mem, pg_start, mask_type);
+	pte_flags = I810_PTE_VALID;
+	if (flags == AGP_USER_CACHED_MEMORY)
+		pte_flags |= I830_PTE_SYSTEM_CACHED;
 
- out:
-	ret = 0;
- out_err:
-	mem->is_flushed = true;
-	return ret;
+	/* Shift high bits down */
+	addr |= (addr >> 28) & 0xf0;
+	writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static bool gen6_check_flags(unsigned int flags)
 {
-	int i;
-
-	if (mem->page_count == 0)
-		return 0;
-
-	if (pg_start < intel_private.gtt_entries) {
-		dev_info(&intel_private.pcidev->dev,
-			 "trying to disable local/stolen memory\n");
-		return -EINVAL;
-	}
-
-	for (i = pg_start; i < (mem->page_count + pg_start); i++)
-		writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
-	readl(intel_private.gtt+i-1);
-
-	return 0;
+	return true;
 }
 
-/* Return the aperture size by just checking the resource length.  The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
+static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
+			     unsigned int flags)
 {
-	int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-	int aper_size; /* size in megabytes */
-	int i;
-
-	aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
+	unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+	unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+	u32 pte_flags;
 
-	for (i = 0; i < num_sizes; i++) {
-		if (aper_size == intel_i830_sizes[i].size) {
-			agp_bridge->current_size = intel_i830_sizes + i;
-			return aper_size;
-		}
+	if (type_mask == AGP_USER_MEMORY)
+		pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
+	else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+		pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
+		if (gfdt)
+			pte_flags |= GEN6_PTE_GFDT;
+	} else { /* set 'normal'/'cached' to LLC by default */
+		pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
+		if (gfdt)
+			pte_flags |= GEN6_PTE_GFDT;
 	}
 
-	return 0;
+	/* gen6 has bit11-4 for physical addr bit39-32 */
+	addr |= (addr >> 28) & 0xff0;
+	writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static int intel_i915_get_gtt_size(void)
+static void gen6_cleanup(void)
 {
-	int size;
-
-	if (IS_G33) {
-		u16 gmch_ctrl;
-
-		/* G33's GTT size defined in gmch_ctrl */
-		pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-		case I830_GMCH_GMS_STOLEN_512:
-			size = 512;
-			break;
-		case I830_GMCH_GMS_STOLEN_1024:
-			size = 1024;
-			break;
-		case I830_GMCH_GMS_STOLEN_8192:
-			size = 8*1024;
-			break;
-		default:
-			dev_info(&agp_bridge->dev->dev,
-				 "unknown page table size 0x%x, assuming 512KB\n",
-				(gmch_ctrl & I830_GMCH_GMS_MASK));
-			size = 512;
-		}
-	} else {
-		/* On previous hardware, the GTT size was just what was
-		 * required to map the aperture.
-		 */
-		size = agp_bridge->driver->fetch_size();
-	}
-
-	return KB(size);
 }
 
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
+static int i9xx_setup(void)
 {
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp, temp2;
-	int gtt_map_size;
-
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
-
-	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-	pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
-
-	gtt_map_size = intel_i915_get_gtt_size();
-
-	intel_private.gtt = ioremap(temp2, gtt_map_size);
-	if (!intel_private.gtt)
-		return -ENOMEM;
-
-	intel_private.gtt_total_size = gtt_map_size / 4;
-
-	temp &= 0xfff80000;
+	u32 reg_addr;
 
-	intel_private.registers = ioremap(temp, 128 * 4096);
-	if (!intel_private.registers) {
-		iounmap(intel_private.gtt);
-		return -ENOMEM;
-	}
+	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
 
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();	/* FIXME: ? */
+	reg_addr &= 0xfff80000;
 
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.gtt);
-		iounmap(intel_private.registers);
+	intel_private.registers = ioremap(reg_addr, 128 * 4096);
+	if (!intel_private.registers)
 		return -ENOMEM;
-	}
-
-	agp_bridge->gatt_table = NULL;
-
-	agp_bridge->gatt_bus_addr = temp;
-
-	return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-					    dma_addr_t addr, int type)
-{
-	/* Shift high bits down */
-	addr |= (addr >> 28) & 0xf0;
 
-	/* Type checking must be done elsewhere */
-	return addr | bridge->driver->masks[type].mask;
-}
-
-static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
-					    dma_addr_t addr, int type)
-{
-	/* gen6 has bit11-4 for physical addr bit39-32 */
-	addr |= (addr >> 28) & 0xff0;
-
-	/* Type checking must be done elsewhere */
-	return addr | bridge->driver->masks[type].mask;
-}
-
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
-{
-	u16 snb_gmch_ctl;
+	if (INTEL_GTT_GEN == 3) {
+		u32 gtt_addr;
 
-	switch (agp_bridge->dev->device) {
-	case PCI_DEVICE_ID_INTEL_GM45_HB:
-	case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
-	case PCI_DEVICE_ID_INTEL_Q45_HB:
-	case PCI_DEVICE_ID_INTEL_G45_HB:
-	case PCI_DEVICE_ID_INTEL_G41_HB:
-	case PCI_DEVICE_ID_INTEL_B43_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
-		*gtt_offset = *gtt_size = MB(2);
-		break;
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB:
-		*gtt_offset = MB(2);
+		pci_read_config_dword(intel_private.pcidev,
+				      I915_PTEADDR, &gtt_addr);
+		intel_private.gtt_bus_addr = gtt_addr;
+	} else {
+		u32 gtt_offset;
 
-		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-		switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
-		default:
-		case SNB_GTT_SIZE_0M:
-			printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
-			*gtt_size = MB(0);
-			break;
-		case SNB_GTT_SIZE_1M:
-			*gtt_size = MB(1);
+		switch (INTEL_GTT_GEN) {
+		case 5:
+		case 6:
+			gtt_offset = MB(2);
 			break;
-		case SNB_GTT_SIZE_2M:
-			*gtt_size = MB(2);
+		case 4:
+		default:
+			gtt_offset =  KB(512);
 			break;
 		}
-		break;
-	default:
-		*gtt_offset = *gtt_size = KB(512);
-	}
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp;
-	int gtt_offset, gtt_size;
-
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
-
-	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
-	temp &= 0xfff00000;
-
-	intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
-
-	intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
-
-	if (!intel_private.gtt)
-		return -ENOMEM;
-
-	intel_private.gtt_total_size = gtt_size / 4;
-
-	intel_private.registers = ioremap(temp, 128 * 4096);
-	if (!intel_private.registers) {
-		iounmap(intel_private.gtt);
-		return -ENOMEM;
-	}
-
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();   /* FIXME: ? */
-
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.gtt);
-		iounmap(intel_private.registers);
-		return -ENOMEM;
+		intel_private.gtt_bus_addr = reg_addr + gtt_offset;
 	}
 
-	agp_bridge->gatt_table = NULL;
+	intel_private.pte_bus_addr =
+		readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-	agp_bridge->gatt_bus_addr = temp;
+	intel_i9xx_setup_flush();
 
 	return 0;
 }
@@ -1475,7 +1293,7 @@
 	.cleanup		= intel_i810_cleanup,
 	.mask_memory		= intel_i810_mask_memory,
 	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
+	.agp_enable		= intel_fake_agp_enable,
 	.cache_flush		= global_cache_flush,
 	.create_gatt_table	= agp_generic_create_gatt_table,
 	.free_gatt_table	= agp_generic_free_gatt_table,
@@ -1490,161 +1308,282 @@
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_fake_agp_driver = {
 	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
 	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i830_configure,
-	.fetch_size		= intel_i830_fetch_size,
-	.cleanup		= intel_i830_cleanup,
-	.mask_memory		= intel_i810_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
+	.aperture_sizes		= intel_fake_agp_sizes,
+	.num_aperture_sizes	= ARRAY_SIZE(intel_fake_agp_sizes),
+	.configure		= intel_fake_agp_configure,
+	.fetch_size		= intel_fake_agp_fetch_size,
+	.cleanup		= intel_gtt_cleanup,
+	.agp_enable		= intel_fake_agp_enable,
 	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i830_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i830_insert_entries,
-	.remove_memory		= intel_i830_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
+	.create_gatt_table	= intel_fake_agp_create_gatt_table,
+	.free_gatt_table	= intel_fake_agp_free_gatt_table,
+	.insert_memory		= intel_fake_agp_insert_entries,
+	.remove_memory		= intel_fake_agp_remove_entries,
+	.alloc_by_type		= intel_fake_agp_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
 	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
 	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i830_chipset_flush,
+	.chipset_flush		= intel_fake_agp_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_915_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i810_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i915_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i81x_gtt_driver = {
+	.gen = 1,
+	.dma_mask_size = 32,
 };
-
-static const struct agp_bridge_driver intel_i965_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i965_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i965_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i8xx_gtt_driver = {
+	.gen = 2,
+	.setup = i830_setup,
+	.cleanup = i830_cleanup,
+	.write_entry = i830_write_entry,
+	.dma_mask_size = 32,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i830_chipset_flush,
 };
-
-static const struct agp_bridge_driver intel_gen6_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_gen6_mask_memory,
-	.masks			= intel_gen6_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i965_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_gen6_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i915_gtt_driver = {
+	.gen = 3,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	/* i945 is the last gpu to need phys mem (for overlay and cursors). */
+	.write_entry = i830_write_entry, 
+	.dma_mask_size = 32,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g33_gtt_driver = {
+	.gen = 3,
+	.is_g33 = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver pineview_gtt_driver = {
+	.gen = 3,
+	.is_pineview = 1, .is_g33 = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver i965_gtt_driver = {
+	.gen = 4,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g4x_gtt_driver = {
+	.gen = 5,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver ironlake_gtt_driver = {
+	.gen = 5,
+	.is_ironlake = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver sandybridge_gtt_driver = {
+	.gen = 6,
+	.setup = i9xx_setup,
+	.cleanup = gen6_cleanup,
+	.write_entry = gen6_write_entry,
+	.dma_mask_size = 40,
+	.check_flags = gen6_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_g33_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i965_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i915_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+/* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
+ * driver and gmch_driver must be non-null, and find_gmch will determine
+ * which one should be used if a gmch_chip_id is present.
+ */
+static const struct intel_gtt_driver_description {
+	unsigned int gmch_chip_id;
+	char *name;
+	const struct agp_bridge_driver *gmch_driver;
+	const struct intel_gtt_driver *gtt_driver;
+} intel_gtt_chipsets[] = {
+	{ PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82865_IG, "865",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G33_IG, "G33",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
+		&intel_fake_agp_driver, &pineview_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
+		&intel_fake_agp_driver, &pineview_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_B43_IG, "B43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G41_IG, "G41",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
+	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
+	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ 0, NULL, NULL }
 };
+
+static int find_gmch(u16 device)
+{
+	struct pci_dev *gmch_device;
+
+	gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
+		gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
+					     device, gmch_device);
+	}
+
+	if (!gmch_device)
+		return 0;
+
+	intel_private.pcidev = gmch_device;
+	return 1;
+}
+
+int intel_gmch_probe(struct pci_dev *pdev,
+				      struct agp_bridge_data *bridge)
+{
+	int i, mask;
+	bridge->driver = NULL;
+
+	for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
+		if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+			bridge->driver =
+				intel_gtt_chipsets[i].gmch_driver;
+			intel_private.driver = 
+				intel_gtt_chipsets[i].gtt_driver;
+			break;
+		}
+	}
+
+	if (!bridge->driver)
+		return 0;
+
+	bridge->dev_private_data = &intel_private;
+	bridge->dev = pdev;
+
+	intel_private.bridge_dev = pci_dev_get(pdev);
+
+	dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+
+	mask = intel_private.driver->dma_mask_size;
+	if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
+		dev_err(&intel_private.pcidev->dev,
+			"set gfx device dma mask %d-bit failed!\n", mask);
+	else
+		pci_set_consistent_dma_mask(intel_private.pcidev,
+					    DMA_BIT_MASK(mask));
+
+	if (bridge->driver == &intel_810_driver)
+		return 1;
+
+	if (intel_gtt_init() != 0)
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(intel_gmch_probe);
+
+struct intel_gtt *intel_gtt_get(void)
+{
+	return &intel_private.base;
+}
+EXPORT_SYMBOL(intel_gtt_get);
+
+void intel_gmch_remove(struct pci_dev *pdev)
+{
+	if (intel_private.pcidev)
+		pci_dev_put(intel_private.pcidev);
+	if (intel_private.bridge_dev)
+		pci_dev_put(intel_private.bridge_dev);
+}
+EXPORT_SYMBOL(intel_gmch_remove);
+
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_LICENSE("GPL and additional rights");
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/Kconfig linux-libre-2.6.37-gnu/drivers/char/agp/Kconfig
--- linux-libre-2.6.36-gnu/drivers/char/agp/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,7 @@
 	  X on the following ALi chipsets.  The supported chipsets
 	  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
 	  For the ALi-chipset question, ALi suggests you refer to
-	  <http://www.ali.com.tw/eng/support/index.shtml>.
+	  <http://www.ali.com.tw/>.
 
 	  The M1541 chipset can do AGP 1x and 2x, but note that there is an
 	  acknowledged incompatibility with Matrox G200 cards. Due to
@@ -57,7 +57,7 @@
 
 config AGP_AMD64
 	tristate "AMD Opteron/Athlon64 on-CPU GART support"
-	depends on AGP && X86 && K8_NB
+	depends on AGP && X86 && AMD_NB
 	help
 	  This option gives you AGP support for the GLX component of
 	  X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/Makefile linux-libre-2.6.37-gnu/drivers/char/agp/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/agp/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -13,6 +13,7 @@
 obj-$(CONFIG_AGP_PARISC)	+= parisc-agp.o
 obj-$(CONFIG_AGP_I460)		+= i460-agp.o
 obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
+obj-$(CONFIG_AGP_INTEL)		+= intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
 obj-$(CONFIG_AGP_SGI_TIOCA)	+= sgi-agp.o
 obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
diff -druN linux-libre-2.6.36-gnu/drivers/char/agp/parisc-agp.c linux-libre-2.6.37-gnu/drivers/char/agp/parisc-agp.c
--- linux-libre-2.6.36-gnu/drivers/char/agp/parisc-agp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/agp/parisc-agp.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,6 +19,7 @@
 #include <linux/klist.h>
 #include <linux/agp_backend.h>
 #include <linux/log2.h>
+#include <linux/slab.h>
 
 #include <asm/parisc-device.h>
 #include <asm/ropes.h>
@@ -358,8 +359,12 @@
 	bridge->dev = fake_bridge_dev;
 
 	error = agp_add_bridge(bridge);
+	if (error)
+		goto fail;
+	return 0;
 
 fail:
+	kfree(fake_bridge_dev);
 	return error;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/amiserial.c linux-libre-2.6.37-gnu/drivers/char/amiserial.c
--- linux-libre-2.6.36-gnu/drivers/char/amiserial.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/amiserial.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,7 +81,6 @@
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
@@ -1263,13 +1262,42 @@
 	return 0;
 }
 
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int rs_get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
+{
+	struct async_struct *info = tty->driver_data;
+	struct async_icount cnow;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	cnow = info->state->icount;
+	local_irq_restore(flags);
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+
+	return 0;
+}
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
 	struct async_struct * info = tty->driver_data;
 	struct async_icount cprev, cnow;	/* kernel counter temps */
-	struct serial_icounter_struct icount;
 	void __user *argp = (void __user *)arg;
 	unsigned long flags;
 
@@ -1332,31 +1360,6 @@
 			}
 			/* NOTREACHED */
 
-		/* 
-		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-		 * Return: write counters to the user passed counter struct
-		 * NB: both 1->0 and 0->1 transitions are counted except for
-		 *     RI where only 0->1 is counted.
-		 */
-		case TIOCGICOUNT:
-			local_irq_save(flags);
-			cnow = info->state->icount;
-			local_irq_restore(flags);
-			icount.cts = cnow.cts;
-			icount.dsr = cnow.dsr;
-			icount.rng = cnow.rng;
-			icount.dcd = cnow.dcd;
-			icount.rx = cnow.rx;
-			icount.tx = cnow.tx;
-			icount.frame = cnow.frame;
-			icount.overrun = cnow.overrun;
-			icount.parity = cnow.parity;
-			icount.brk = cnow.brk;
-			icount.buf_overrun = cnow.buf_overrun;
-
-			if (copy_to_user(argp, &icount, sizeof(icount)))
-				return -EFAULT;
-			return 0;
 		case TIOCSERGWILD:
 		case TIOCSERSWILD:
 			/* "setserial -W" is called in Debian boot */
@@ -1958,6 +1961,7 @@
 	.wait_until_sent = rs_wait_until_sent,
 	.tiocmget = rs_tiocmget,
 	.tiocmset = rs_tiocmset,
+	.get_icount = rs_get_icount,
 	.proc_fops = &rs_proc_fops,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/apm-emulation.c linux-libre-2.6.37-gnu/drivers/char/apm-emulation.c
--- linux-libre-2.6.36-gnu/drivers/char/apm-emulation.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/apm-emulation.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,13 +7,13 @@
  *   Intel Corporation, Microsoft Corporation. Advanced Power Management
  *   (APM) BIOS Interface Specification, Revision 1.2, February 1996.
  *
- * [This document is available from Microsoft at:
- *    http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ * This document is available from Microsoft at:
+ *    http://www.microsoft.com/whdc/archive/amp_12.mspx
  */
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/miscdevice.h>
@@ -126,6 +126,7 @@
 /*
  * Local variables
  */
+static DEFINE_MUTEX(apm_mutex);
 static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
 static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
 static int apm_disabled;
@@ -274,7 +275,7 @@
 	if (!as->suser || !as->writer)
 		return -EPERM;
 
-	lock_kernel();
+	mutex_lock(&apm_mutex);
 	switch (cmd) {
 	case APM_IOC_SUSPEND:
 		mutex_lock(&state_lock);
@@ -335,7 +336,7 @@
 		mutex_unlock(&state_lock);
 		break;
 	}
-	unlock_kernel();
+	mutex_unlock(&apm_mutex);
 
 	return err;
 }
@@ -370,7 +371,7 @@
 {
 	struct apm_user *as;
 
-	lock_kernel();
+	mutex_lock(&apm_mutex);
 	as = kzalloc(sizeof(*as), GFP_KERNEL);
 	if (as) {
 		/*
@@ -390,7 +391,7 @@
 
 		filp->private_data = as;
 	}
-	unlock_kernel();
+	mutex_unlock(&apm_mutex);
 
 	return as ? 0 : -ENOMEM;
 }
@@ -402,6 +403,7 @@
 	.unlocked_ioctl	= apm_ioctl,
 	.open		= apm_open,
 	.release	= apm_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice apm_device = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/applicom.c linux-libre-2.6.37-gnu/drivers/char/applicom.c
--- linux-libre-2.6.36-gnu/drivers/char/applicom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/applicom.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,7 +26,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include <linux/wait.h>
@@ -60,6 +60,7 @@
 #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB     0x0003
 #endif
 
+static DEFINE_MUTEX(ac_mutex);
 static char *applicom_pci_devnames[] = {
 	"PCI board",
 	"PCI2000IBS / PCI2000CAN",
@@ -565,6 +566,7 @@
 				struct mailbox mailbox;
 
 				/* Got a packet for us */
+				memset(&st_loc, 0, sizeof(st_loc));
 				ret = do_ac_read(i, buf, &st_loc, &mailbox);
 				spin_unlock_irqrestore(&apbs[i].mutex, flags);
 				set_current_state(TASK_RUNNING);
@@ -707,7 +709,7 @@
 	if (IS_ERR(adgl))
 		return PTR_ERR(adgl);
 
-	lock_kernel();	
+	mutex_lock(&ac_mutex);	
 	IndexCard = adgl->num_card-1;
 	 
 	if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) {
@@ -717,7 +719,7 @@
 			warncount--;
 		}
 		kfree(adgl);
-		unlock_kernel();
+		mutex_unlock(&ac_mutex);
 		return -EINVAL;
 	}
 
@@ -835,7 +837,7 @@
 	}
 	Dummy = readb(apbs[IndexCard].RamIO + VERS);
 	kfree(adgl);
-	unlock_kernel();
+	mutex_unlock(&ac_mutex);
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/bfin-otp.c linux-libre-2.6.37-gnu/drivers/char/bfin-otp.c
--- linux-libre-2.6.36-gnu/drivers/char/bfin-otp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/bfin-otp.c	2011-01-04 19:50:19.000000000 -0500
@@ -222,6 +222,7 @@
 	.unlocked_ioctl = bfin_otp_ioctl,
 	.read           = bfin_otp_read,
 	.write          = bfin_otp_write,
+	.llseek		= default_llseek,
 };
 
 static struct miscdevice bfin_otp_misc_device = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/briq_panel.c linux-libre-2.6.37-gnu/drivers/char/briq_panel.c
--- linux-libre-2.6.36-gnu/drivers/char/briq_panel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/briq_panel.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,6 @@
 
 #include <linux/module.h>
 
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
@@ -186,6 +185,7 @@
 	.write		= briq_panel_write,
 	.open		= briq_panel_open,
 	.release	= briq_panel_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice briq_panel_miscdev = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/bsr.c linux-libre-2.6.37-gnu/drivers/char/bsr.c
--- linux-libre-2.6.36-gnu/drivers/char/bsr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/bsr.c	2011-01-04 19:50:19.000000000 -0500
@@ -155,6 +155,7 @@
 	.owner = THIS_MODULE,
 	.mmap  = bsr_mmap,
 	.open  = bsr_open,
+	.llseek = noop_llseek,
 };
 
 static void bsr_cleanup_devs(void)
diff -druN linux-libre-2.6.36-gnu/drivers/char/consolemap.c linux-libre-2.6.37-gnu/drivers/char/consolemap.c
--- linux-libre-2.6.36-gnu/drivers/char/consolemap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/consolemap.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,745 +0,0 @@
-/*
- * consolemap.c
- *
- * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
- * to font positions.
- *
- * aeb, 950210
- *
- * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
- *
- * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
- */
-
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <asm/uaccess.h>
-#include <linux/consolemap.h>
-#include <linux/vt_kern.h>
-
-static unsigned short translations[][256] = {
-  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  }, 
-  /* VT100 graphics mapped to Unicode */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
-    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
-    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
-    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
-    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
-    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  },
-  /* IBM Codepage 437 mapped to Unicode */
-  {
-    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
-    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
-    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
-    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
-    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
-    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
-    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
-    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
-    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
-    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
-    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
-    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
-  }, 
-  /* User mapping -- default to codes for direct font mapping */
-  {
-    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
-    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
-    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
-    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
-    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
-    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
-    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
-    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
-    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
-    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
-    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
-    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
-    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
-    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
-    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
-    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
-    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
-    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
-    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
-    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
-    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
-    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
-    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
-    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
-    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
-    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
-    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
-    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
-    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
-    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
-  }
-};
-
-/* The standard kernel character-to-font mappings are not invertible
-   -- this is just a best effort. */
-
-#define MAX_GLYPH 512		/* Max possible glyph value */
-
-static int inv_translate[MAX_NR_CONSOLES];
-
-struct uni_pagedir {
-	u16 		**uni_pgdir[32];
-	unsigned long	refcount;
-	unsigned long	sum;
-	unsigned char	*inverse_translations[4];
-	u16		*inverse_trans_unicode;
-	int		readonly;
-};
-
-static struct uni_pagedir *dflt;
-
-static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
-{
-	int j, glyph;
-	unsigned short *t = translations[i];
-	unsigned char *q;
-	
-	if (!p) return;
-	q = p->inverse_translations[i];
-
-	if (!q) {
-		q = p->inverse_translations[i] = (unsigned char *) 
-			kmalloc(MAX_GLYPH, GFP_KERNEL);
-		if (!q) return;
-	}
-	memset(q, 0, MAX_GLYPH);
-
-	for (j = 0; j < E_TABSZ; j++) {
-		glyph = conv_uni_to_pc(conp, t[j]);
-		if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
-			/* prefer '-' above SHY etc. */
-		  	q[glyph] = j;
-		}
-	}
-}
-
-static void set_inverse_trans_unicode(struct vc_data *conp,
-				      struct uni_pagedir *p)
-{
-	int i, j, k, glyph;
-	u16 **p1, *p2;
-	u16 *q;
-
-	if (!p) return;
-	q = p->inverse_trans_unicode;
-	if (!q) {
-		q = p->inverse_trans_unicode =
-			kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
-		if (!q)
-			return;
-	}
-	memset(q, 0, MAX_GLYPH * sizeof(u16));
-
-	for (i = 0; i < 32; i++) {
-		p1 = p->uni_pgdir[i];
-		if (!p1)
-			continue;
-		for (j = 0; j < 32; j++) {
-			p2 = p1[j];
-			if (!p2)
-				continue;
-			for (k = 0; k < 64; k++) {
-				glyph = p2[k];
-				if (glyph >= 0 && glyph < MAX_GLYPH
-					       && q[glyph] < 32)
-		  			q[glyph] = (i << 11) + (j << 6) + k;
-			}
-		}
-	}
-}
-
-unsigned short *set_translate(int m, struct vc_data *vc)
-{
-	inv_translate[vc->vc_num] = m;
-	return translations[m];
-}
-
-/*
- * Inverse translation is impossible for several reasons:
- * 1. The font<->character maps are not 1-1.
- * 2. The text may have been written while a different translation map
- *    was active.
- * Still, it is now possible to a certain extent to cut and paste non-ASCII.
- */
-u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
-{
-	struct uni_pagedir *p;
-	int m;
-	if (glyph < 0 || glyph >= MAX_GLYPH)
-		return 0;
-	else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
-		return glyph;
-	else if (use_unicode) {
-		if (!p->inverse_trans_unicode)
-			return glyph;
-		else
-			return p->inverse_trans_unicode[glyph];
-	} else {
-		m = inv_translate[conp->vc_num];
-		if (!p->inverse_translations[m])
-			return glyph;
-		else
-			return p->inverse_translations[m][glyph];
-	}
-}
-EXPORT_SYMBOL_GPL(inverse_translate);
-
-static void update_user_maps(void)
-{
-	int i;
-	struct uni_pagedir *p, *q = NULL;
-	
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		if (!vc_cons_allocated(i))
-			continue;
-		p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-		if (p && p != q) {
-			set_inverse_transl(vc_cons[i].d, p, USER_MAP);
-			set_inverse_trans_unicode(vc_cons[i].d, p);
-			q = p;
-		}
-	}
-}
-
-/*
- * Load customizable translation table
- * arg points to a 256 byte translation table.
- *
- * The "old" variants are for translation directly to font (using the
- * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
- * Unicodes explicitly.
- */
-int con_set_trans_old(unsigned char __user * arg)
-{
-	int i;
-	unsigned short *p = translations[USER_MAP];
-
-	if (!access_ok(VERIFY_READ, arg, E_TABSZ))
-		return -EFAULT;
-
-	for (i=0; i<E_TABSZ ; i++) {
-		unsigned char uc;
-		__get_user(uc, arg+i);
-		p[i] = UNI_DIRECT_BASE | uc;
-	}
-
-	update_user_maps();
-	return 0;
-}
-
-int con_get_trans_old(unsigned char __user * arg)
-{
-	int i, ch;
-	unsigned short *p = translations[USER_MAP];
-
-	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
-		return -EFAULT;
-
-	for (i=0; i<E_TABSZ ; i++)
-	  {
-	    ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-	    __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-	  }
-	return 0;
-}
-
-int con_set_trans_new(ushort __user * arg)
-{
-	int i;
-	unsigned short *p = translations[USER_MAP];
-
-	if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
-		return -EFAULT;
-
-	for (i=0; i<E_TABSZ ; i++) {
-		unsigned short us;
-		__get_user(us, arg+i);
-		p[i] = us;
-	}
-
-	update_user_maps();
-	return 0;
-}
-
-int con_get_trans_new(ushort __user * arg)
-{
-	int i;
-	unsigned short *p = translations[USER_MAP];
-
-	if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
-		return -EFAULT;
-
-	for (i=0; i<E_TABSZ ; i++)
-	  __put_user(p[i], arg+i);
-	
-	return 0;
-}
-
-/*
- * Unicode -> current font conversion 
- *
- * A font has at most 512 chars, usually 256.
- * But one font position may represent several Unicode chars.
- * A hashtable is somewhat of a pain to deal with, so use a
- * "paged table" instead.  Simulation has shown the memory cost of
- * this 3-level paged table scheme to be comparable to a hash table.
- */
-
-extern u8 dfont_unicount[];	/* Defined in console_defmap.c */
-extern u16 dfont_unitable[];
-
-static void con_release_unimap(struct uni_pagedir *p)
-{
-	u16 **p1;
-	int i, j;
-
-	if (p == dflt) dflt = NULL;  
-	for (i = 0; i < 32; i++) {
-		if ((p1 = p->uni_pgdir[i]) != NULL) {
-			for (j = 0; j < 32; j++)
-				kfree(p1[j]);
-			kfree(p1);
-		}
-		p->uni_pgdir[i] = NULL;
-	}
-	for (i = 0; i < 4; i++) {
-		kfree(p->inverse_translations[i]);
-		p->inverse_translations[i] = NULL;
-	}
-	if (p->inverse_trans_unicode) {
-		kfree(p->inverse_trans_unicode);
-		p->inverse_trans_unicode = NULL;
-	}
-}
-
-void con_free_unimap(struct vc_data *vc)
-{
-	struct uni_pagedir *p;
-
-	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (!p)
-		return;
-	*vc->vc_uni_pagedir_loc = 0;
-	if (--p->refcount)
-		return;
-	con_release_unimap(p);
-	kfree(p);
-}
-  
-static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
-{
-	int i, j, k;
-	struct uni_pagedir *q;
-	
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		if (!vc_cons_allocated(i))
-			continue;
-		q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-		if (!q || q == p || q->sum != p->sum)
-			continue;
-		for (j = 0; j < 32; j++) {
-			u16 **p1, **q1;
-			p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
-			if (!p1 && !q1)
-				continue;
-			if (!p1 || !q1)
-				break;
-			for (k = 0; k < 32; k++) {
-				if (!p1[k] && !q1[k])
-					continue;
-				if (!p1[k] || !q1[k])
-					break;
-				if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
-					break;
-			}
-			if (k < 32)
-				break;
-		}
-		if (j == 32) {
-			q->refcount++;
-			*conp->vc_uni_pagedir_loc = (unsigned long)q;
-			con_release_unimap(p);
-			kfree(p);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int
-con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
-{
-	int i, n;
-	u16 **p1, *p2;
-
-	if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
-		p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-		if (!p1) return -ENOMEM;
-		for (i = 0; i < 32; i++)
-			p1[i] = NULL;
-	}
-
-	if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
-		p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-		if (!p2) return -ENOMEM;
-		memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
-	}
-
-	p2[unicode & 0x3f] = fontpos;
-	
-	p->sum += (fontpos << 20) + unicode;
-
-	return 0;
-}
-
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
-{
-	struct uni_pagedir *p, *q;
-  
-	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p && p->readonly) return -EIO;
-	if (!p || --p->refcount) {
-		q = kzalloc(sizeof(*p), GFP_KERNEL);
-		if (!q) {
-			if (p) p->refcount++;
-			return -ENOMEM;
-		}
-		q->refcount=1;
-		*vc->vc_uni_pagedir_loc = (unsigned long)q;
-	} else {
-		if (p == dflt) dflt = NULL;
-		p->refcount++;
-		p->sum = 0;
-		con_release_unimap(p);
-	}
-	return 0;
-}
-
-int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
-{
-	int err = 0, err1, i;
-	struct uni_pagedir *p, *q;
-
-	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	if (p->readonly) return -EIO;
-	
-	if (!ct) return 0;
-	
-	if (p->refcount > 1) {
-		int j, k;
-		u16 **p1, *p2, l;
-		
-		err1 = con_clear_unimap(vc, NULL);
-		if (err1) return err1;
-		
-		q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		for (i = 0, l = 0; i < 32; i++)
-		if ((p1 = p->uni_pgdir[i]))
-			for (j = 0; j < 32; j++)
-			if ((p2 = p1[j]))
-				for (k = 0; k < 64; k++, l++)
-				if (p2[k] != 0xffff) {
-					err1 = con_insert_unipair(q, l, p2[k]);
-					if (err1) {
-						p->refcount++;
-						*vc->vc_uni_pagedir_loc = (unsigned long)p;
-						con_release_unimap(q);
-						kfree(q);
-						return err1; 
-					}
-              			}
-              	p = q;
-	} else if (p == dflt)
-		dflt = NULL;
-	
-	while (ct--) {
-		unsigned short unicode, fontpos;
-		__get_user(unicode, &list->unicode);
-		__get_user(fontpos, &list->fontpos);
-		if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
-			err = err1;
-		list++;
-	}
-	
-	if (con_unify_unimap(vc, p))
-		return err;
-
-	for (i = 0; i <= 3; i++)
-		set_inverse_transl(vc, p, i); /* Update all inverse translations */
-	set_inverse_trans_unicode(vc, p);
-  
-	return err;
-}
-
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
-int con_set_default_unimap(struct vc_data *vc)
-{
-	int i, j, err = 0, err1;
-	u16 *q;
-	struct uni_pagedir *p;
-
-	if (dflt) {
-		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		if (p == dflt)
-			return 0;
-		dflt->refcount++;
-		*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
-		if (p && --p->refcount) {
-			con_release_unimap(p);
-			kfree(p);
-		}
-		return 0;
-	}
-	
-	/* The default font is always 256 characters */
-
-	err = con_clear_unimap(vc, NULL);
-	if (err) return err;
-    
-	p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	q = dfont_unitable;
-	
-	for (i = 0; i < 256; i++)
-		for (j = dfont_unicount[i]; j; j--) {
-			err1 = con_insert_unipair(p, *(q++), i);
-			if (err1)
-				err = err1;
-		}
-			
-	if (con_unify_unimap(vc, p)) {
-		dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		return err;
-	}
-
-	for (i = 0; i <= 3; i++)
-		set_inverse_transl(vc, p, i);	/* Update all inverse translations */
-	set_inverse_trans_unicode(vc, p);
-	dflt = p;
-	return err;
-}
-EXPORT_SYMBOL(con_set_default_unimap);
-
-int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
-{
-	struct uni_pagedir *q;
-
-	if (!*src_vc->vc_uni_pagedir_loc)
-		return -EINVAL;
-	if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
-		return 0;
-	con_free_unimap(dst_vc);
-	q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
-	q->refcount++;
-	*dst_vc->vc_uni_pagedir_loc = (long)q;
-	return 0;
-}
-
-int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
-{
-	int i, j, k, ect;
-	u16 **p1, *p2;
-	struct uni_pagedir *p;
-
-	ect = 0;
-	if (*vc->vc_uni_pagedir_loc) {
-		p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-		for (i = 0; i < 32; i++)
-		if ((p1 = p->uni_pgdir[i]))
-			for (j = 0; j < 32; j++)
-			if ((p2 = *(p1++)))
-				for (k = 0; k < 64; k++) {
-					if (*p2 < MAX_GLYPH && ect++ < ct) {
-						__put_user((u_short)((i<<11)+(j<<6)+k),
-							   &list->unicode);
-						__put_user((u_short) *p2, 
-							   &list->fontpos);
-						list++;
-					}
-					p2++;
-				}
-	}
-	__put_user(ect, uct);
-	return ((ect <= ct) ? 0 : -ENOMEM);
-}
-
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-	struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-	
-	if (p)
-		p->readonly = rdonly;
-}
-
-/*
- * Always use USER_MAP. These functions are used by the keyboard,
- * which shouldn't be affected by G0/G1 switching, etc.
- * If the user map still contains default values, i.e. the
- * direct-to-font mapping, then assume user is using Latin1.
- */
-/* may be called during an interrupt */
-u32 conv_8bit_to_uni(unsigned char c)
-{
-	unsigned short uni = translations[USER_MAP][c];
-	return uni == (0xf000 | c) ? c : uni;
-}
-
-int conv_uni_to_8bit(u32 uni)
-{
-	int c;
-	for (c = 0; c < 0x100; c++)
-		if (translations[USER_MAP][c] == uni ||
-		   (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
-			return c;
-	return -1;
-}
-
-int
-conv_uni_to_pc(struct vc_data *conp, long ucs) 
-{
-	int h;
-	u16 **p1, *p2;
-	struct uni_pagedir *p;
-  
-	/* Only 16-bit codes supported at this time */
-	if (ucs > 0xffff)
-		return -4;		/* Not found */
-	else if (ucs < 0x20)
-		return -1;		/* Not a printable character */
-	else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
-		return -2;			/* Zero-width space */
-	/*
-	 * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-	 * which always has a 1:1 mapping to the currently loaded font.  The
-	 * UNI_DIRECT_MASK indicates the bit span of the region.
-	 */
-	else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
-		return ucs & UNI_DIRECT_MASK;
-  
-	if (!*conp->vc_uni_pagedir_loc)
-		return -3;
-
-	p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
-	if ((p1 = p->uni_pgdir[ucs >> 11]) &&
-	    (p2 = p1[(ucs >> 6) & 0x1f]) &&
-	    (h = p2[ucs & 0x3f]) < MAX_GLYPH)
-		return h;
-
-	return -4;		/* not found */
-}
-
-/*
- * This is called at sys_setup time, after memory and the console are
- * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
- * from this function, hence the call from sys_setup.
- */
-void __init 
-console_map_init(void)
-{
-	int i;
-	
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-		if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
-			con_set_default_unimap(vc_cons[i].d);
-}
-
-EXPORT_SYMBOL(con_copy_unimap);
diff -druN linux-libre-2.6.36-gnu/drivers/char/cp437.uni linux-libre-2.6.37-gnu/drivers/char/cp437.uni
--- linux-libre-2.6.36-gnu/drivers/char/cp437.uni	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/cp437.uni	1969-12-31 19:00:00.000000000 -0500
@@ -1,291 +0,0 @@
-#
-# Unicode table for IBM Codepage 437.  Note that there are many more
-# substitutions that could be conceived (for example, thick-line
-# graphs probably should be replaced with double-line ones, accented
-# Latin characters should replaced with their nonaccented versions,
-# and some upper case Greek characters could be replaced by Latin), however,
-# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
-# DEC VT, and IBM CP 437 tables.
-#
-# --------------------------------
-#
-# Basic IBM dingbats, some of which will never have a purpose clear
-# to mankind
-#
-0x00	U+0000
-0x01	U+263a
-0x02	U+263b
-0x03	U+2665
-0x04	U+2666 U+25c6
-0x05	U+2663
-0x06	U+2660
-0x07	U+2022
-0x08	U+25d8
-0x09	U+25cb
-0x0a	U+25d9
-0x0b	U+2642
-0x0c	U+2640
-0x0d	U+266a
-0x0e	U+266b
-0x0f	U+263c U+00a4
-0x10	U+25b6 U+25ba
-0x11	U+25c0 U+25c4
-0x12	U+2195
-0x13	U+203c
-0x14	U+00b6
-0x15	U+00a7
-0x16	U+25ac
-0x17	U+21a8
-0x18	U+2191
-0x19	U+2193
-0x1a	U+2192
-0x1b	U+2190
-0x1c	U+221f
-0x1d	U+2194
-0x1e	U+25b2
-0x1f	U+25bc
-#
-# The ASCII range is identity-mapped, but some of the characters also
-# have to act as substitutes, especially the upper-case characters.
-#
-0x20	U+0020
-0x21	U+0021
-0x22	U+0022 U+00a8
-0x23	U+0023
-0x24	U+0024
-0x25	U+0025
-0x26	U+0026
-0x27	U+0027 U+00b4
-0x28	U+0028
-0x29	U+0029
-0x2a	U+002a
-0x2b	U+002b
-0x2c	U+002c U+00b8
-0x2d	U+002d U+00ad
-0x2e	U+002e
-0x2f	U+002f
-0x30	U+0030
-0x31	U+0031
-0x32	U+0032
-0x33	U+0033
-0x34	U+0034
-0x35	U+0035
-0x36	U+0036
-0x37	U+0037
-0x38	U+0038
-0x39	U+0039
-0x3a	U+003a
-0x3b	U+003b
-0x3c	U+003c
-0x3d	U+003d
-0x3e	U+003e
-0x3f	U+003f
-0x40	U+0040
-0x41	U+0041 U+00c0 U+00c1 U+00c2 U+00c3
-0x42	U+0042
-0x43	U+0043 U+00a9
-0x44	U+0044 U+00d0
-0x45	U+0045 U+00c8 U+00ca U+00cb
-0x46	U+0046
-0x47	U+0047
-0x48	U+0048
-0x49	U+0049 U+00cc U+00cd U+00ce U+00cf
-0x4a	U+004a
-0x4b	U+004b U+212a
-0x4c	U+004c
-0x4d	U+004d
-0x4e	U+004e
-0x4f	U+004f U+00d2 U+00d3 U+00d4 U+00d5
-0x50	U+0050
-0x51	U+0051
-0x52	U+0052 U+00ae
-0x53	U+0053
-0x54	U+0054
-0x55	U+0055 U+00d9 U+00da U+00db
-0x56	U+0056
-0x57	U+0057
-0x58	U+0058
-0x59	U+0059 U+00dd
-0x5a	U+005a
-0x5b	U+005b
-0x5c	U+005c
-0x5d	U+005d
-0x5e	U+005e
-0x5f	U+005f U+23bd U+f804
-0x60	U+0060
-0x61	U+0061 U+00e3
-0x62	U+0062
-0x63	U+0063
-0x64	U+0064
-0x65	U+0065
-0x66	U+0066
-0x67	U+0067
-0x68	U+0068
-0x69	U+0069
-0x6a	U+006a
-0x6b	U+006b
-0x6c	U+006c
-0x6d	U+006d
-0x6e	U+006e
-0x6f	U+006f U+00f5
-0x70	U+0070
-0x71	U+0071
-0x72	U+0072
-0x73	U+0073
-0x74	U+0074
-0x75	U+0075
-0x76	U+0076
-0x77	U+0077
-0x78	U+0078 U+00d7
-0x79	U+0079 U+00fd
-0x7a	U+007a
-0x7b	U+007b
-0x7c	U+007c U+00a6
-0x7d	U+007d
-0x7e	U+007e
-#
-# Okay, what on Earth is this one supposed to be used for?
-#
-0x7f	U+2302
-#
-# Non-English characters, mostly lower case letters...
-#
-0x80	U+00c7
-0x81	U+00fc
-0x82	U+00e9
-0x83	U+00e2
-0x84	U+00e4
-0x85	U+00e0
-0x86	U+00e5
-0x87	U+00e7
-0x88	U+00ea
-0x89	U+00eb
-0x8a	U+00e8
-0x8b	U+00ef
-0x8c	U+00ee
-0x8d	U+00ec
-0x8e	U+00c4
-0x8f	U+00c5 U+212b
-0x90	U+00c9
-0x91	U+00e6
-0x92	U+00c6
-0x93	U+00f4
-0x94	U+00f6
-0x95	U+00f2
-0x96	U+00fb
-0x97	U+00f9
-0x98	U+00ff
-0x99	U+00d6
-0x9a	U+00dc
-0x9b	U+00a2
-0x9c	U+00a3
-0x9d	U+00a5
-0x9e	U+20a7
-0x9f	U+0192
-0xa0	U+00e1
-0xa1	U+00ed
-0xa2	U+00f3
-0xa3	U+00fa
-0xa4	U+00f1
-0xa5	U+00d1
-0xa6	U+00aa
-0xa7	U+00ba
-0xa8	U+00bf
-0xa9	U+2310
-0xaa	U+00ac
-0xab	U+00bd
-0xac	U+00bc
-0xad	U+00a1
-0xae	U+00ab
-0xaf	U+00bb
-#
-# Block graphics
-#
-0xb0	U+2591
-0xb1	U+2592
-0xb2	U+2593
-0xb3	U+2502
-0xb4	U+2524
-0xb5	U+2561
-0xb6	U+2562
-0xb7	U+2556
-0xb8	U+2555
-0xb9	U+2563
-0xba	U+2551
-0xbb	U+2557
-0xbc	U+255d
-0xbd	U+255c
-0xbe	U+255b
-0xbf	U+2510
-0xc0	U+2514
-0xc1	U+2534
-0xc2	U+252c
-0xc3	U+251c
-0xc4	U+2500
-0xc5	U+253c
-0xc6	U+255e
-0xc7	U+255f
-0xc8	U+255a
-0xc9	U+2554
-0xca	U+2569
-0xcb	U+2566
-0xcc	U+2560
-0xcd	U+2550
-0xce	U+256c
-0xcf	U+2567
-0xd0	U+2568
-0xd1	U+2564
-0xd2	U+2565
-0xd3	U+2559
-0xd4	U+2558
-0xd5	U+2552
-0xd6	U+2553
-0xd7	U+256b
-0xd8	U+256a
-0xd9	U+2518
-0xda	U+250c
-0xdb	U+2588
-0xdc	U+2584
-0xdd	U+258c
-0xde	U+2590
-0xdf	U+2580
-#
-# Greek letters and mathematical symbols
-#
-0xe0	U+03b1
-0xe1	U+03b2 U+00df
-0xe2	U+0393
-0xe3	U+03c0
-0xe4	U+03a3
-0xe5	U+03c3
-0xe6	U+00b5 U+03bc
-0xe7	U+03c4
-0xe8	U+03a6 U+00d8
-0xe9	U+0398
-0xea	U+03a9 U+2126
-0xeb	U+03b4 U+00f0
-0xec	U+221e
-0xed	U+03c6 U+00f8
-0xee	U+03b5 U+2208
-0xef	U+2229
-0xf0	U+2261
-0xf1	U+00b1
-0xf2	U+2265
-0xf3	U+2264
-0xf4	U+2320
-0xf5	U+2321
-0xf6	U+00f7
-0xf7	U+2248
-0xf8	U+00b0
-0xf9	U+2219
-0xfa	U+00b7
-0xfb	U+221a
-0xfc	U+207f
-0xfd	U+00b2
-#
-# Square bullet, non-spacing blank
-# Mapping U+fffd to the square bullet means it is the substitution
-# character
-# 
-0xfe	U+25a0 U+fffd
-0xff	U+00a0
diff -druN linux-libre-2.6.36-gnu/drivers/char/cs5535_gpio.c linux-libre-2.6.37-gnu/drivers/char/cs5535_gpio.c
--- linux-libre-2.6.36-gnu/drivers/char/cs5535_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/cs5535_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -169,7 +169,8 @@
 	.owner	= THIS_MODULE,
 	.write	= cs5535_gpio_write,
 	.read	= cs5535_gpio_read,
-	.open	= cs5535_gpio_open
+	.open	= cs5535_gpio_open,
+	.llseek = no_llseek,
 };
 
 static int __init cs5535_gpio_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/char/cyclades.c linux-libre-2.6.37-gnu/drivers/char/cyclades.c
--- linux-libre-2.6.36-gnu/drivers/char/cyclades.c	2012-03-23 21:39:16.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/cyclades.c	2012-03-23 23:30:30.000000000 -0400
@@ -2790,29 +2790,6 @@
 		 * NB: both 1->0 and 0->1 transitions are counted except for
 		 *     RI where only 0->1 is counted.
 		 */
-	case TIOCGICOUNT: {
-		struct serial_icounter_struct sic = { };
-
-		spin_lock_irqsave(&info->card->card_lock, flags);
-		cnow = info->icount;
-		spin_unlock_irqrestore(&info->card->card_lock, flags);
-
-		sic.cts = cnow.cts;
-		sic.dsr = cnow.dsr;
-		sic.rng = cnow.rng;
-		sic.dcd = cnow.dcd;
-		sic.rx = cnow.rx;
-		sic.tx = cnow.tx;
-		sic.frame = cnow.frame;
-		sic.overrun = cnow.overrun;
-		sic.parity = cnow.parity;
-		sic.brk = cnow.brk;
-		sic.buf_overrun = cnow.buf_overrun;
-
-		if (copy_to_user(argp, &sic, sizeof(sic)))
-			ret_val = -EFAULT;
-		break;
-	}
 	default:
 		ret_val = -ENOIOCTLCMD;
 	}
@@ -2823,6 +2800,31 @@
 	return ret_val;
 }				/* cy_ioctl */
 
+static int cy_get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *sic)
+{
+	struct cyclades_port *info = tty->driver_data;
+	struct cyclades_icount cnow;	/* Used to snapshot */
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->card->card_lock, flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->card->card_lock, flags);
+
+	sic->cts = cnow.cts;
+	sic->dsr = cnow.dsr;
+	sic->rng = cnow.rng;
+	sic->dcd = cnow.dcd;
+	sic->rx = cnow.rx;
+	sic->tx = cnow.tx;
+	sic->frame = cnow.frame;
+	sic->overrun = cnow.overrun;
+	sic->parity = cnow.parity;
+	sic->brk = cnow.brk;
+	sic->buf_overrun = cnow.buf_overrun;
+	return 0;
+}
+
 /*
  * This routine allows the tty driver to be notified when
  * device's termios settings have changed.  Note that a
@@ -4084,6 +4086,7 @@
 	.wait_until_sent = cy_wait_until_sent,
 	.tiocmget = cy_tiocmget,
 	.tiocmset = cy_tiocmset,
+	.get_icount = cy_get_icount,
 	.proc_fops = &cyclades_proc_fops,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/defkeymap.c_shipped linux-libre-2.6.37-gnu/drivers/char/defkeymap.c_shipped
--- linux-libre-2.6.36-gnu/drivers/char/defkeymap.c_shipped	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/defkeymap.c_shipped	1969-12-31 19:00:00.000000000 -0500
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-	0xf200,	0xf01b,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,
-	0xf037,	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf07f,	0xf009,
-	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
-	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf201,	0xf702,	0xfb61,	0xfb73,
-	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,
-	0xf027,	0xf060,	0xf700,	0xf05c,	0xfb7a,	0xfb78,	0xfb63,	0xfb76,
-	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf700,	0xf30c,
-	0xf703,	0xf020,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
-	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf209,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
-	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03c,	0xf10a,
-	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-	0xf200,	0xf01b,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,
-	0xf026,	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf07f,	0xf009,
-	0xfb51,	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,
-	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf201,	0xf702,	0xfb41,	0xfb53,
-	0xfb44,	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,
-	0xf022,	0xf07e,	0xf700,	0xf07c,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
-	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf30c,
-	0xf703,	0xf020,	0xf207,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,
-	0xf10f,	0xf110,	0xf111,	0xf112,	0xf113,	0xf213,	0xf203,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
-	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03e,	0xf10a,
-	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf20b,	0xf601,	0xf602,	0xf117,	0xf600,	0xf20a,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
-	0xf07b,	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,
-	0xfb71,	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
-	0xfb6f,	0xfb70,	0xf200,	0xf07e,	0xf201,	0xf702,	0xf914,	0xfb73,
-	0xf917,	0xf919,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,
-	0xf200,	0xf200,	0xf700,	0xf200,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
-	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
-	0xf703,	0xf200,	0xf207,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,
-	0xf511,	0xf512,	0xf513,	0xf514,	0xf515,	0xf208,	0xf202,	0xf911,
-	0xf912,	0xf913,	0xf30b,	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf90b,
-	0xf90c,	0xf90d,	0xf90a,	0xf310,	0xf206,	0xf200,	0xf07c,	0xf516,
-	0xf517,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,
-	0xf01f,	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf008,	0xf200,
-	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
-	0xf00f,	0xf010,	0xf01b,	0xf01d,	0xf201,	0xf702,	0xf001,	0xf013,
-	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
-	0xf007,	0xf000,	0xf700,	0xf01c,	0xf01a,	0xf018,	0xf003,	0xf016,
-	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf30c,
-	0xf703,	0xf000,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
-	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf204,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
-	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf10a,
-	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,
-	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
-	0xf00f,	0xf010,	0xf200,	0xf200,	0xf201,	0xf702,	0xf001,	0xf013,
-	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
-	0xf200,	0xf200,	0xf700,	0xf200,	0xf01a,	0xf018,	0xf003,	0xf016,
-	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
-	0xf703,	0xf200,	0xf207,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf208,	0xf200,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
-	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-	0xf200,	0xf81b,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,
-	0xf837,	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf87f,	0xf809,
-	0xf871,	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,
-	0xf86f,	0xf870,	0xf85b,	0xf85d,	0xf80d,	0xf702,	0xf861,	0xf873,
-	0xf864,	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,
-	0xf827,	0xf860,	0xf700,	0xf85c,	0xf87a,	0xf878,	0xf863,	0xf876,
-	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf30c,
-	0xf703,	0xf820,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
-	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf209,	0xf907,
-	0xf908,	0xf909,	0xf30b,	0xf904,	0xf905,	0xf906,	0xf30a,	0xf901,
-	0xf902,	0xf903,	0xf900,	0xf310,	0xf206,	0xf200,	0xf83c,	0xf50a,
-	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf210,	0xf211,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf811,	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,
-	0xf80f,	0xf810,	0xf200,	0xf200,	0xf201,	0xf702,	0xf801,	0xf813,
-	0xf804,	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,
-	0xf200,	0xf200,	0xf700,	0xf200,	0xf81a,	0xf818,	0xf803,	0xf816,
-	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
-	0xf703,	0xf200,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
-	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf200,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
-	0xf302,	0xf303,	0xf300,	0xf20c,	0xf206,	0xf200,	0xf200,	0xf50a,
-	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
-	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf20c,
-	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-	plain_map, shift_map, altgr_map, NULL,
-	ctrl_map, shift_ctrl_map, NULL, NULL,
-	alt_map, NULL, NULL, NULL,
-	ctrl_alt_map, NULL
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-	'\033', '[', '[', 'A', 0, 
-	'\033', '[', '[', 'B', 0, 
-	'\033', '[', '[', 'C', 0, 
-	'\033', '[', '[', 'D', 0, 
-	'\033', '[', '[', 'E', 0, 
-	'\033', '[', '1', '7', '~', 0, 
-	'\033', '[', '1', '8', '~', 0, 
-	'\033', '[', '1', '9', '~', 0, 
-	'\033', '[', '2', '0', '~', 0, 
-	'\033', '[', '2', '1', '~', 0, 
-	'\033', '[', '2', '3', '~', 0, 
-	'\033', '[', '2', '4', '~', 0, 
-	'\033', '[', '2', '5', '~', 0, 
-	'\033', '[', '2', '6', '~', 0, 
-	'\033', '[', '2', '8', '~', 0, 
-	'\033', '[', '2', '9', '~', 0, 
-	'\033', '[', '3', '1', '~', 0, 
-	'\033', '[', '3', '2', '~', 0, 
-	'\033', '[', '3', '3', '~', 0, 
-	'\033', '[', '3', '4', '~', 0, 
-	'\033', '[', '1', '~', 0, 
-	'\033', '[', '2', '~', 0, 
-	'\033', '[', '3', '~', 0, 
-	'\033', '[', '4', '~', 0, 
-	'\033', '[', '5', '~', 0, 
-	'\033', '[', '6', '~', 0, 
-	'\033', '[', 'M', 0, 
-	'\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-	func_buf + 0,
-	func_buf + 5,
-	func_buf + 10,
-	func_buf + 15,
-	func_buf + 20,
-	func_buf + 25,
-	func_buf + 31,
-	func_buf + 37,
-	func_buf + 43,
-	func_buf + 49,
-	func_buf + 55,
-	func_buf + 61,
-	func_buf + 67,
-	func_buf + 73,
-	func_buf + 79,
-	func_buf + 85,
-	func_buf + 91,
-	func_buf + 97,
-	func_buf + 103,
-	func_buf + 109,
-	func_buf + 115,
-	func_buf + 120,
-	func_buf + 125,
-	func_buf + 130,
-	func_buf + 135,
-	func_buf + 140,
-	func_buf + 145,
-	NULL,
-	NULL,
-	func_buf + 149,
-	NULL,
-};
-
-struct kbdiacruc accent_table[MAX_DIACR] = {
-	{'`', 'A', 0300},	{'`', 'a', 0340},
-	{'\'', 'A', 0301},	{'\'', 'a', 0341},
-	{'^', 'A', 0302},	{'^', 'a', 0342},
-	{'~', 'A', 0303},	{'~', 'a', 0343},
-	{'"', 'A', 0304},	{'"', 'a', 0344},
-	{'O', 'A', 0305},	{'o', 'a', 0345},
-	{'0', 'A', 0305},	{'0', 'a', 0345},
-	{'A', 'A', 0305},	{'a', 'a', 0345},
-	{'A', 'E', 0306},	{'a', 'e', 0346},
-	{',', 'C', 0307},	{',', 'c', 0347},
-	{'`', 'E', 0310},	{'`', 'e', 0350},
-	{'\'', 'E', 0311},	{'\'', 'e', 0351},
-	{'^', 'E', 0312},	{'^', 'e', 0352},
-	{'"', 'E', 0313},	{'"', 'e', 0353},
-	{'`', 'I', 0314},	{'`', 'i', 0354},
-	{'\'', 'I', 0315},	{'\'', 'i', 0355},
-	{'^', 'I', 0316},	{'^', 'i', 0356},
-	{'"', 'I', 0317},	{'"', 'i', 0357},
-	{'-', 'D', 0320},	{'-', 'd', 0360},
-	{'~', 'N', 0321},	{'~', 'n', 0361},
-	{'`', 'O', 0322},	{'`', 'o', 0362},
-	{'\'', 'O', 0323},	{'\'', 'o', 0363},
-	{'^', 'O', 0324},	{'^', 'o', 0364},
-	{'~', 'O', 0325},	{'~', 'o', 0365},
-	{'"', 'O', 0326},	{'"', 'o', 0366},
-	{'/', 'O', 0330},	{'/', 'o', 0370},
-	{'`', 'U', 0331},	{'`', 'u', 0371},
-	{'\'', 'U', 0332},	{'\'', 'u', 0372},
-	{'^', 'U', 0333},	{'^', 'u', 0373},
-	{'"', 'U', 0334},	{'"', 'u', 0374},
-	{'\'', 'Y', 0335},	{'\'', 'y', 0375},
-	{'T', 'H', 0336},	{'t', 'h', 0376},
-	{'s', 's', 0337},	{'"', 'y', 0377},
-	{'s', 'z', 0337},	{'i', 'j', 0377},
-};
-
-unsigned int accent_table_size = 68;
diff -druN linux-libre-2.6.36-gnu/drivers/char/defkeymap.map linux-libre-2.6.37-gnu/drivers/char/defkeymap.map
--- linux-libre-2.6.36-gnu/drivers/char/defkeymap.map	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/defkeymap.map	1969-12-31 19:00:00.000000000 -0500
@@ -1,357 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-#	keymaps 0-2,4-6,8,12
-# in case you want the entries
-#	altgr   control keycode  83 = Boot            
-#	altgr   control keycode 111 = Boot            
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode   1 = Escape           Escape          
-	alt     keycode   1 = Meta_Escape     
-keycode   2 = one              exclam          
-	alt     keycode   2 = Meta_one        
-keycode   3 = two              at               at              
-	control	keycode   3 = nul             
-	shift	control	keycode   3 = nul             
-	alt	keycode   3 = Meta_two        
-keycode   4 = three            numbersign      
-	control keycode   4 = Escape          
-	alt     keycode   4 = Meta_three      
-keycode   5 = four             dollar           dollar          
-	control keycode   5 = Control_backslash
-	alt     keycode   5 = Meta_four       
-keycode   6 = five             percent         
-	control keycode   6 = Control_bracketright
-	alt     keycode   6 = Meta_five       
-keycode   7 = six              asciicircum     
-	control keycode   7 = Control_asciicircum
-	alt     keycode   7 = Meta_six        
-keycode   8 = seven            ampersand        braceleft       
-	control keycode   8 = Control_underscore
-	alt     keycode   8 = Meta_seven      
-keycode   9 = eight            asterisk         bracketleft     
-	control keycode   9 = Delete          
-	alt     keycode   9 = Meta_eight      
-keycode  10 = nine             parenleft        bracketright    
-	alt     keycode  10 = Meta_nine       
-keycode  11 = zero             parenright       braceright      
-	alt     keycode  11 = Meta_zero       
-keycode  12 = minus            underscore       backslash       
-	control	keycode  12 = Control_underscore
-	shift	control	keycode  12 = Control_underscore
-	alt	keycode  12 = Meta_minus      
-keycode  13 = equal            plus            
-	alt     keycode  13 = Meta_equal      
-keycode  14 = Delete           Delete          
-	control keycode  14 = BackSpace
-	alt     keycode  14 = Meta_Delete     
-keycode  15 = Tab              Tab             
-	alt     keycode  15 = Meta_Tab        
-keycode  16 = q               
-keycode  17 = w               
-keycode  18 = e
-	altgr   keycode  18 = Hex_E   
-keycode  19 = r               
-keycode  20 = t               
-keycode  21 = y               
-keycode  22 = u               
-keycode  23 = i               
-keycode  24 = o               
-keycode  25 = p               
-keycode  26 = bracketleft      braceleft       
-	control keycode  26 = Escape          
-	alt     keycode  26 = Meta_bracketleft
-keycode  27 = bracketright     braceright       asciitilde      
-	control keycode  27 = Control_bracketright
-	alt     keycode  27 = Meta_bracketright
-keycode  28 = Return          
-	alt     keycode  28 = Meta_Control_m  
-keycode  29 = Control         
-keycode  30 = a
-	altgr   keycode  30 = Hex_A
-keycode  31 = s               
-keycode  32 = d
-	altgr   keycode  32 = Hex_D   
-keycode  33 = f
-	altgr   keycode  33 = Hex_F               
-keycode  34 = g               
-keycode  35 = h               
-keycode  36 = j               
-keycode  37 = k               
-keycode  38 = l               
-keycode  39 = semicolon        colon           
-	alt     keycode  39 = Meta_semicolon  
-keycode  40 = apostrophe       quotedbl        
-	control keycode  40 = Control_g       
-	alt     keycode  40 = Meta_apostrophe 
-keycode  41 = grave            asciitilde      
-	control keycode  41 = nul             
-	alt     keycode  41 = Meta_grave      
-keycode  42 = Shift           
-keycode  43 = backslash        bar             
-	control keycode  43 = Control_backslash
-	alt     keycode  43 = Meta_backslash  
-keycode  44 = z               
-keycode  45 = x               
-keycode  46 = c
-	altgr   keycode  46 = Hex_C   
-keycode  47 = v               
-keycode  48 = b
-	altgr   keycode  48 = Hex_B
-keycode  49 = n               
-keycode  50 = m               
-keycode  51 = comma            less            
-	alt     keycode  51 = Meta_comma      
-keycode  52 = period           greater         
-	control keycode  52 = Compose         
-	alt     keycode  52 = Meta_period     
-keycode  53 = slash            question        
-	control keycode  53 = Delete          
-	alt     keycode  53 = Meta_slash      
-keycode  54 = Shift           
-keycode  55 = KP_Multiply     
-keycode  56 = Alt             
-keycode  57 = space            space           
-	control keycode  57 = nul             
-	alt     keycode  57 = Meta_space      
-keycode  58 = Caps_Lock       
-keycode  59 = F1               F11              Console_13      
-	control keycode  59 = F1              
-	alt     keycode  59 = Console_1       
-	control alt     keycode  59 = Console_1       
-keycode  60 = F2               F12              Console_14      
-	control keycode  60 = F2              
-	alt     keycode  60 = Console_2       
-	control alt     keycode  60 = Console_2       
-keycode  61 = F3               F13              Console_15      
-	control keycode  61 = F3              
-	alt     keycode  61 = Console_3       
-	control alt     keycode  61 = Console_3       
-keycode  62 = F4               F14              Console_16      
-	control keycode  62 = F4              
-	alt     keycode  62 = Console_4       
-	control alt     keycode  62 = Console_4       
-keycode  63 = F5               F15              Console_17      
-	control keycode  63 = F5              
-	alt     keycode  63 = Console_5       
-	control alt     keycode  63 = Console_5       
-keycode  64 = F6               F16              Console_18      
-	control keycode  64 = F6              
-	alt     keycode  64 = Console_6       
-	control alt     keycode  64 = Console_6       
-keycode  65 = F7               F17              Console_19      
-	control keycode  65 = F7              
-	alt     keycode  65 = Console_7       
-	control alt     keycode  65 = Console_7       
-keycode  66 = F8               F18              Console_20      
-	control keycode  66 = F8              
-	alt     keycode  66 = Console_8       
-	control alt     keycode  66 = Console_8       
-keycode  67 = F9               F19              Console_21      
-	control keycode  67 = F9              
-	alt     keycode  67 = Console_9       
-	control alt     keycode  67 = Console_9       
-keycode  68 = F10              F20              Console_22      
-	control keycode  68 = F10             
-	alt     keycode  68 = Console_10      
-	control alt     keycode  68 = Console_10      
-keycode  69 = Num_Lock
-	shift   keycode  69 = Bare_Num_Lock
-keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
-	control keycode  70 = Show_State      
-	alt     keycode  70 = Scroll_Lock     
-keycode  71 = KP_7            
-	alt     keycode  71 = Ascii_7         
-	altgr   keycode  71 = Hex_7         
-keycode  72 = KP_8            
-	alt     keycode  72 = Ascii_8         
-	altgr   keycode  72 = Hex_8         
-keycode  73 = KP_9            
-	alt     keycode  73 = Ascii_9         
-	altgr   keycode  73 = Hex_9         
-keycode  74 = KP_Subtract     
-keycode  75 = KP_4            
-	alt     keycode  75 = Ascii_4         
-	altgr   keycode  75 = Hex_4         
-keycode  76 = KP_5            
-	alt     keycode  76 = Ascii_5         
-	altgr   keycode  76 = Hex_5         
-keycode  77 = KP_6            
-	alt     keycode  77 = Ascii_6         
-	altgr   keycode  77 = Hex_6         
-keycode  78 = KP_Add          
-keycode  79 = KP_1            
-	alt     keycode  79 = Ascii_1         
-	altgr   keycode  79 = Hex_1         
-keycode  80 = KP_2            
-	alt     keycode  80 = Ascii_2         
-	altgr   keycode  80 = Hex_2         
-keycode  81 = KP_3            
-	alt     keycode  81 = Ascii_3         
-	altgr   keycode  81 = Hex_3         
-keycode  82 = KP_0            
-	alt     keycode  82 = Ascii_0         
-	altgr   keycode  82 = Hex_0         
-keycode  83 = KP_Period       
-#	altgr   control keycode  83 = Boot            
-	control alt     keycode  83 = Boot            
-keycode  84 = Last_Console    
-keycode  85 =
-keycode  86 = less             greater          bar             
-	alt     keycode  86 = Meta_less       
-keycode  87 = F11              F11              Console_23      
-	control keycode  87 = F11             
-	alt     keycode  87 = Console_11      
-	control alt     keycode  87 = Console_11      
-keycode  88 = F12              F12              Console_24      
-	control keycode  88 = F12             
-	alt     keycode  88 = Console_12      
-	control alt     keycode  88 = Console_12      
-keycode  89 =
-keycode  90 =
-keycode  91 =
-keycode  92 =
-keycode  93 =
-keycode  94 =
-keycode  95 =
-keycode  96 = KP_Enter        
-keycode  97 = Control         
-keycode  98 = KP_Divide       
-keycode  99 = Control_backslash
-	control keycode  99 = Control_backslash
-	alt     keycode  99 = Control_backslash
-keycode 100 = AltGr           
-keycode 101 = Break           
-keycode 102 = Find            
-keycode 103 = Up              
-keycode 104 = Prior           
-	shift   keycode 104 = Scroll_Backward 
-keycode 105 = Left            
-	alt     keycode 105 = Decr_Console
-keycode 106 = Right           
-	alt     keycode 106 = Incr_Console
-keycode 107 = Select          
-keycode 108 = Down            
-keycode 109 = Next            
-	shift   keycode 109 = Scroll_Forward  
-keycode 110 = Insert          
-keycode 111 = Remove          
-#	altgr   control keycode 111 = Boot            
-	control alt     keycode 111 = Boot            
-keycode 112 = Macro           
-keycode 113 = F13             
-keycode 114 = F14             
-keycode 115 = Help            
-keycode 116 = Do              
-keycode 117 = F17             
-keycode 118 = KP_MinPlus      
-keycode 119 = Pause           
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff -druN linux-libre-2.6.36-gnu/drivers/char/ds1302.c linux-libre-2.6.37-gnu/drivers/char/ds1302.c
--- linux-libre-2.6.36-gnu/drivers/char/ds1302.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ds1302.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
@@ -32,6 +32,7 @@
 
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
+static DEFINE_MUTEX(rtc_mutex);
 static const char ds1302_name[] = "ds1302";
 
 /* Send 8 bits. */
@@ -164,9 +165,9 @@
 			struct rtc_time rtc_tm;
 
 			memset(&rtc_tm, 0, sizeof (struct rtc_time));
-			lock_kernel();
+			mutex_lock(&rtc_mutex);
 			get_rtc_time(&rtc_tm);
-			unlock_kernel();
+			mutex_unlock(&rtc_mutex);
 			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
 				return -EFAULT;
 			return 0;
@@ -218,7 +219,7 @@
 			mon = bin2bcd(mon);
 			yrs = bin2bcd(yrs);
 
-			lock_kernel();
+			mutex_lock(&rtc_mutex);
 			local_irq_save(flags);
 			CMOS_WRITE(yrs, RTC_YEAR);
 			CMOS_WRITE(mon, RTC_MONTH);
@@ -227,7 +228,7 @@
 			CMOS_WRITE(min, RTC_MINUTES);
 			CMOS_WRITE(sec, RTC_SECONDS);
 			local_irq_restore(flags);
-			unlock_kernel();
+			mutex_unlock(&rtc_mutex);
 
 			/* Notice that at this point, the RTC is updated but
 			 * the kernel is still running with the old time.
@@ -247,10 +248,10 @@
 			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
 				return -EFAULT;
 
-			lock_kernel();
+			mutex_lock(&rtc_mutex);
 			tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
 			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
-			unlock_kernel();
+			mutex_unlock(&rtc_mutex);
 			return 0;
 		}
 		default:
@@ -288,6 +289,7 @@
 static const struct file_operations rtc_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= rtc_ioctl,
+	.llseek		= noop_llseek,
 };
 
 /* Probe for the chip by writing something to its RAM and try reading it back. */
diff -druN linux-libre-2.6.36-gnu/drivers/char/ds1620.c linux-libre-2.6.37-gnu/drivers/char/ds1620.c
--- linux-libre-2.6.36-gnu/drivers/char/ds1620.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ds1620.c	2011-01-04 19:50:19.000000000 -0500
@@ -8,7 +8,7 @@
 #include <linux/proc_fs.h>
 #include <linux/capability.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -34,6 +34,7 @@
 #define CFG_CPU			2
 #define CFG_1SHOT		1
 
+static DEFINE_MUTEX(ds1620_mutex);
 static const char *fan_state[] = { "off", "on", "on (hardwired)" };
 
 /*
@@ -210,7 +211,6 @@
 
 static int ds1620_open(struct inode *inode, struct file *file)
 {
-	cycle_kernel_lock();
 	return nonseekable_open(inode, file);
 }
 
@@ -321,9 +321,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ds1620_mutex);
 	ret = ds1620_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ds1620_mutex);
 
 	return ret;
 }
@@ -357,6 +357,7 @@
 	.open		= ds1620_open,
 	.read		= ds1620_read,
 	.unlocked_ioctl	= ds1620_unlocked_ioctl,
+	.llseek		= no_llseek,
 };
 
 static struct miscdevice ds1620_miscdev = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/dsp56k.c linux-libre-2.6.37-gnu/drivers/char/dsp56k.c
--- linux-libre-2.6.36-gnu/drivers/char/dsp56k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/dsp56k.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/device.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
 #include <linux/uaccess.h>	/* For put_user and get_user */
@@ -94,6 +94,7 @@
 	} \
 }
 
+static DEFINE_MUTEX(dsp56k_mutex);
 static struct dsp56k_device {
 	unsigned long in_use;
 	long maxio, timeout;
@@ -330,9 +331,9 @@
 			if (len > DSP56K_MAX_BINARY_LENGTH) {
 				return -EINVAL;
 			}
-			lock_kernel();
+			mutex_lock(&dsp56k_mutex);
 			r = dsp56k_upload(bin, len);
-			unlock_kernel();
+			mutex_unlock(&dsp56k_mutex);
 			if (r < 0) {
 				return r;
 			}
@@ -342,16 +343,16 @@
 		case DSP56K_SET_TX_WSIZE:
 			if (arg > 4 || arg < 1)
 				return -EINVAL;
-			lock_kernel();
+			mutex_lock(&dsp56k_mutex);
 			dsp56k.tx_wsize = (int) arg;
-			unlock_kernel();
+			mutex_unlock(&dsp56k_mutex);
 			break;
 		case DSP56K_SET_RX_WSIZE:
 			if (arg > 4 || arg < 1)
 				return -EINVAL;
-			lock_kernel();
+			mutex_lock(&dsp56k_mutex);
 			dsp56k.rx_wsize = (int) arg;
-			unlock_kernel();
+			mutex_unlock(&dsp56k_mutex);
 			break;
 		case DSP56K_HOST_FLAGS:
 		{
@@ -363,7 +364,7 @@
 			if(get_user(out, &hf->out) < 0)
 				return -EFAULT;
 
-			lock_kernel();
+			mutex_lock(&dsp56k_mutex);
 			if ((dir & 0x1) && (out & 0x1))
 				dsp56k_host_interface.icr |= DSP56K_ICR_HF0;
 			else if (dir & 0x1)
@@ -378,16 +379,16 @@
 			if (dsp56k_host_interface.icr & DSP56K_ICR_HF1) status |= 0x2;
 			if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
 			if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
-			unlock_kernel();
+			mutex_unlock(&dsp56k_mutex);
 			return put_user(status, &hf->status);
 		}
 		case DSP56K_HOST_CMD:
 			if (arg > 31 || arg < 0)
 				return -EINVAL;
-			lock_kernel();
+			mutex_lock(&dsp56k_mutex);
 			dsp56k_host_interface.cvr = (u_char)((arg & DSP56K_CVR_HV_MASK) |
 							     DSP56K_CVR_HC);
-			unlock_kernel();
+			mutex_unlock(&dsp56k_mutex);
 			break;
 		default:
 			return -EINVAL;
@@ -427,7 +428,7 @@
 	int dev = iminor(inode) & 0x0f;
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&dsp56k_mutex);
 	switch(dev)
 	{
 	case DSP56K_DEV_56001:
@@ -454,7 +455,7 @@
 		ret = -ENODEV;
 	}
 out:
-	unlock_kernel();
+	mutex_unlock(&dsp56k_mutex);
 	return ret;
 }
 
@@ -482,6 +483,7 @@
 	.unlocked_ioctl	= dsp56k_ioctl,
 	.open		= dsp56k_open,
 	.release	= dsp56k_release,
+	.llseek		= noop_llseek,
 };
 
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/dtlk.c linux-libre-2.6.37-gnu/drivers/char/dtlk.c
--- linux-libre-2.6.36-gnu/drivers/char/dtlk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/dtlk.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,7 +57,7 @@
 #include <linux/ioport.h>	/* for request_region */
 #include <linux/delay.h>	/* for loops_per_jiffy */
 #include <linux/sched.h>
-#include <linux/smp_lock.h>	/* cycle_kernel_lock() */
+#include <linux/mutex.h>
 #include <asm/io.h>		/* for inb_p, outb_p, inb, outb, etc. */
 #include <asm/uaccess.h>	/* for get_user, etc. */
 #include <linux/wait.h>		/* for wait_queue */
@@ -73,6 +73,7 @@
 #define TRACE_RET ((void) 0)
 #endif				/* TRACING */
 
+static DEFINE_MUTEX(dtlk_mutex);
 static void dtlk_timer_tick(unsigned long data);
 
 static int dtlk_major;
@@ -105,6 +106,7 @@
 	.unlocked_ioctl	= dtlk_ioctl,
 	.open		= dtlk_open,
 	.release	= dtlk_release,
+	.llseek		= no_llseek,
 };
 
 /* local prototypes */
@@ -275,9 +277,9 @@
 	switch (cmd) {
 
 	case DTLK_INTERROGATE:
-		lock_kernel();
+		mutex_lock(&dtlk_mutex);
 		sp = dtlk_interrogate();
-		unlock_kernel();
+		mutex_unlock(&dtlk_mutex);
 		if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
 			return -EINVAL;
 		return 0;
@@ -296,7 +298,6 @@
 {
 	TRACE_TEXT("(dtlk_open");
 
-	cycle_kernel_lock();
 	nonseekable_open(inode, file);
 	switch (iminor(inode)) {
 	case DTLK_MINOR:
diff -druN linux-libre-2.6.36-gnu/drivers/char/generic_nvram.c linux-libre-2.6.37-gnu/drivers/char/generic_nvram.c
--- linux-libre-2.6.36-gnu/drivers/char/generic_nvram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/generic_nvram.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,7 +19,7 @@
 #include <linux/miscdevice.h>
 #include <linux/fcntl.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/nvram.h>
 #ifdef CONFIG_PPC_PMAC
@@ -28,6 +28,7 @@
 
 #define NVRAM_SIZE	8192
 
+static DEFINE_MUTEX(nvram_mutex);
 static ssize_t nvram_len;
 
 static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
@@ -120,9 +121,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&nvram_mutex);
 	ret = nvram_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&nvram_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/char/genrtc.c linux-libre-2.6.37-gnu/drivers/char/genrtc.c
--- linux-libre-2.6.36-gnu/drivers/char/genrtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/genrtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/workqueue.h>
 
 #include <asm/uaccess.h>
@@ -66,6 +66,7 @@
  *	ioctls.
  */
 
+static DEFINE_MUTEX(gen_rtc_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
 
 /*
@@ -337,9 +338,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&gen_rtc_mutex);
 	ret = gen_rtc_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&gen_rtc_mutex);
 
 	return ret;
 }
@@ -352,16 +353,16 @@
 
 static int gen_rtc_open(struct inode *inode, struct file *file)
 {
-	lock_kernel();
+	mutex_lock(&gen_rtc_mutex);
 	if (gen_rtc_status & RTC_IS_OPEN) {
-		unlock_kernel();
+		mutex_unlock(&gen_rtc_mutex);
 		return -EBUSY;
 	}
 
 	gen_rtc_status |= RTC_IS_OPEN;
 	gen_rtc_irq_data = 0;
 	irq_active = 0;
-	unlock_kernel();
+	mutex_unlock(&gen_rtc_mutex);
 
 	return 0;
 }
@@ -497,6 +498,7 @@
 	.unlocked_ioctl	= gen_rtc_unlocked_ioctl,
 	.open		= gen_rtc_open,
 	.release	= gen_rtc_release,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice rtc_gen_dev =
diff -druN linux-libre-2.6.36-gnu/drivers/char/.gitignore linux-libre-2.6.37-gnu/drivers/char/.gitignore
--- linux-libre-2.6.36-gnu/drivers/char/.gitignore	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/.gitignore	1969-12-31 19:00:00.000000000 -0500
@@ -1,2 +0,0 @@
-consolemap_deftbl.c
-defkeymap.c
diff -druN linux-libre-2.6.36-gnu/drivers/char/hpet.c linux-libre-2.6.37-gnu/drivers/char/hpet.c
--- linux-libre-2.6.36-gnu/drivers/char/hpet.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hpet.c	2011-01-04 19:50:19.000000000 -0500
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/types.h>
 #include <linux/miscdevice.h>
 #include <linux/major.h>
@@ -30,13 +29,14 @@
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include <linux/compat.h>
 #include <linux/clocksource.h>
+#include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/io.h>
 
 #include <asm/current.h>
-#include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/div64.h>
 
@@ -67,6 +67,7 @@
 #define	read_counter(MC)	readl(MC)
 #endif
 
+static DEFINE_MUTEX(hpet_mutex); /* replaces BKL */
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
 /* This clocksource driver currently only works on ia64 */
@@ -79,13 +80,13 @@
 }
 
 static struct clocksource clocksource_hpet = {
-        .name           = "hpet",
-        .rating         = 250,
-        .read           = read_hpet,
-        .mask           = CLOCKSOURCE_MASK(64),
-	.mult		= 0, /* to be calculated */
-        .shift          = 10,
-        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+	.name		= "hpet",
+	.rating		= 250,
+	.read		= read_hpet,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.mult		= 0,		/* to be calculated */
+	.shift		= 10,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 static struct clocksource *hpet_clocksource;
 #endif
@@ -250,7 +251,7 @@
 	if (file->f_mode & FMODE_WRITE)
 		return -EINVAL;
 
-	lock_kernel();
+	mutex_lock(&hpet_mutex);
 	spin_lock_irq(&hpet_lock);
 
 	for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
@@ -264,7 +265,7 @@
 
 	if (!devp) {
 		spin_unlock_irq(&hpet_lock);
-		unlock_kernel();
+		mutex_unlock(&hpet_mutex);
 		return -EBUSY;
 	}
 
@@ -272,7 +273,7 @@
 	devp->hd_irqdata = 0;
 	devp->hd_flags |= HPET_OPEN;
 	spin_unlock_irq(&hpet_lock);
-	unlock_kernel();
+	mutex_unlock(&hpet_mutex);
 
 	hpet_timer_set_irq(devp);
 
@@ -429,22 +430,6 @@
 	return 0;
 }
 
-static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
-
-static long hpet_ioctl(struct file *file, unsigned int cmd,
-			unsigned long arg)
-{
-	struct hpet_dev *devp;
-	int ret;
-
-	devp = file->private_data;
-	lock_kernel();
-	ret = hpet_ioctl_common(devp, cmd, arg, 0);
-	unlock_kernel();
-
-	return ret;
-}
-
 static int hpet_ioctl_ieon(struct hpet_dev *devp)
 {
 	struct hpet_timer __iomem *timer;
@@ -479,6 +464,21 @@
 	if (irq) {
 		unsigned long irq_flags;
 
+		if (devp->hd_flags & HPET_SHARED_IRQ) {
+			/*
+			 * To prevent the interrupt handler from seeing an
+			 * unwanted interrupt status bit, program the timer
+			 * so that it will not fire in the near future ...
+			 */
+			writel(readl(&timer->hpet_config) & ~Tn_TYPE_CNF_MASK,
+			       &timer->hpet_config);
+			write_counter(read_counter(&hpet->hpet_mc),
+				      &timer->hpet_compare);
+			/* ... and clear any left-over status. */
+			isr = 1 << (devp - devp->hd_hpets->hp_dev);
+			writel(isr, &hpet->hpet_isr);
+		}
+
 		sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
 		irq_flags = devp->hd_flags & HPET_SHARED_IRQ
 						? IRQF_SHARED : IRQF_DISABLED;
@@ -553,7 +553,8 @@
 }
 
 static int
-hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
+hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg,
+		  struct hpet_info *info)
 {
 	struct hpet_timer __iomem *timer;
 	struct hpet __iomem *hpet;
@@ -594,23 +595,14 @@
 		break;
 	case HPET_INFO:
 		{
-			struct hpet_info info;
-
+			memset(info, 0, sizeof(*info));
 			if (devp->hd_ireqfreq)
-				info.hi_ireqfreq =
+				info->hi_ireqfreq =
 					hpet_time_div(hpetp, devp->hd_ireqfreq);
-			else
-				info.hi_ireqfreq = 0;
-			info.hi_flags =
+			info->hi_flags =
 			    readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
-			info.hi_hpet = hpetp->hp_which;
-			info.hi_timer = devp - hpetp->hp_dev;
-			if (kernel)
-				memcpy((void *)arg, &info, sizeof(info));
-			else
-				if (copy_to_user((void __user *)arg, &info,
-						 sizeof(info)))
-					err = -EFAULT;
+			info->hi_hpet = hpetp->hp_which;
+			info->hi_timer = devp - hpetp->hp_dev;
 			break;
 		}
 	case HPET_EPI:
@@ -636,7 +628,7 @@
 		devp->hd_flags &= ~HPET_PERIODIC;
 		break;
 	case HPET_IRQFREQ:
-		if (!kernel && (arg > hpet_max_freq) &&
+		if ((arg > hpet_max_freq) &&
 		    !capable(CAP_SYS_RESOURCE)) {
 			err = -EACCES;
 			break;
@@ -653,12 +645,63 @@
 	return err;
 }
 
+static long
+hpet_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hpet_info info;
+	int err;
+
+	mutex_lock(&hpet_mutex);
+	err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
+	mutex_unlock(&hpet_mutex);
+
+	if ((cmd == HPET_INFO) && !err &&
+	    (copy_to_user((void __user *)arg, &info, sizeof(info))))
+		err = -EFAULT;
+
+	return err;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_hpet_info {
+	compat_ulong_t hi_ireqfreq;	/* Hz */
+	compat_ulong_t hi_flags;	/* information */
+	unsigned short hi_hpet;
+	unsigned short hi_timer;
+};
+
+static long
+hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct hpet_info info;
+	int err;
+
+	mutex_lock(&hpet_mutex);
+	err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
+	mutex_unlock(&hpet_mutex);
+
+	if ((cmd == HPET_INFO) && !err) {
+		struct compat_hpet_info __user *u = compat_ptr(arg);
+		if (put_user(info.hi_ireqfreq, &u->hi_ireqfreq) ||
+		    put_user(info.hi_flags, &u->hi_flags) ||
+		    put_user(info.hi_hpet, &u->hi_hpet) ||
+		    put_user(info.hi_timer, &u->hi_timer))
+			err = -EFAULT;
+	}
+
+	return err;
+}
+#endif
+
 static const struct file_operations hpet_fops = {
 	.owner = THIS_MODULE,
 	.llseek = no_llseek,
 	.read = hpet_read,
 	.poll = hpet_poll,
 	.unlocked_ioctl = hpet_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = hpet_compat_ioctl,
+#endif
 	.open = hpet_open,
 	.release = hpet_release,
 	.fasync = hpet_fasync,
@@ -781,7 +824,7 @@
 	struct hpets *hpetp;
 	size_t siz;
 	struct hpet __iomem *hpet;
-	static struct hpets *last = NULL;
+	static struct hpets *last;
 	unsigned long period;
 	unsigned long long temp;
 	u32 remainder;
@@ -970,6 +1013,8 @@
 		return -ENODEV;
 
 	if (!data.hd_address || !data.hd_nirqs) {
+		if (data.hd_address)
+			iounmap(data.hd_address);
 		printk("%s: no address or irqs in _CRS\n", __func__);
 		return -ENODEV;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/char/hvc_console.c linux-libre-2.6.37-gnu/drivers/char/hvc_console.c
--- linux-libre-2.6.36-gnu/drivers/char/hvc_console.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hvc_console.c	2011-01-04 19:50:19.000000000 -0500
@@ -713,7 +713,6 @@
 	struct hvc_struct *hp;
 
 	set_freezable();
-	__set_current_state(TASK_RUNNING);
 	do {
 		poll_mask = 0;
 		hvc_kicked = 0;
diff -druN linux-libre-2.6.36-gnu/drivers/char/hvc_iucv.c linux-libre-2.6.37-gnu/drivers/char/hvc_iucv.c
--- linux-libre-2.6.36-gnu/drivers/char/hvc_iucv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hvc_iucv.c	2011-01-04 19:50:19.000000000 -0500
@@ -1303,13 +1303,11 @@
 	if (rc) {
 		pr_err("Registering IUCV handlers failed with error code=%d\n",
 			rc);
-		goto out_error_iucv;
+		goto out_error_hvc;
 	}
 
 	return 0;
 
-out_error_iucv:
-	iucv_unregister(&hvc_iucv_handler, 0);
 out_error_hvc:
 	for (i = 0; i < hvc_iucv_devices; i++)
 		if (hvc_iucv_table[i])
diff -druN linux-libre-2.6.36-gnu/drivers/char/hvc_tile.c linux-libre-2.6.37-gnu/drivers/char/hvc_tile.c
--- linux-libre-2.6.36-gnu/drivers/char/hvc_tile.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hvc_tile.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,7 +61,8 @@
 
 static int __init hvc_tile_init(void)
 {
-	hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
-	return 0;
+	struct hvc_struct *s;
+	s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+	return IS_ERR(s) ? PTR_ERR(s) : 0;
 }
 device_initcall(hvc_tile_init);
diff -druN linux-libre-2.6.36-gnu/drivers/char/hvc_xen.c linux-libre-2.6.37-gnu/drivers/char/hvc_xen.c
--- linux-libre-2.6.36-gnu/drivers/char/hvc_xen.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hvc_xen.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,11 +74,12 @@
 	wmb();			/* write ring before updating pointer */
 	intf->out_prod = prod;
 
-	notify_daemon();
+	if (sent)
+		notify_daemon();
 	return sent;
 }
 
-static int write_console(uint32_t vtermno, const char *data, int len)
+static int domU_write_console(uint32_t vtermno, const char *data, int len)
 {
 	int ret = len;
 
@@ -101,7 +102,7 @@
 	return ret;
 }
 
-static int read_console(uint32_t vtermno, char *buf, int len)
+static int domU_read_console(uint32_t vtermno, char *buf, int len)
 {
 	struct xencons_interface *intf = xencons_interface();
 	XENCONS_RING_IDX cons, prod;
@@ -122,28 +123,62 @@
 	return recv;
 }
 
-static const struct hv_ops hvc_ops = {
-	.get_chars = read_console,
-	.put_chars = write_console,
+static struct hv_ops domU_hvc_ops = {
+	.get_chars = domU_read_console,
+	.put_chars = domU_write_console,
 	.notifier_add = notifier_add_irq,
 	.notifier_del = notifier_del_irq,
 	.notifier_hangup = notifier_hangup_irq,
 };
 
-static int __init xen_init(void)
+static int dom0_read_console(uint32_t vtermno, char *buf, int len)
+{
+	return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
+}
+
+/*
+ * Either for a dom0 to write to the system console, or a domU with a
+ * debug version of Xen
+ */
+static int dom0_write_console(uint32_t vtermno, const char *str, int len)
+{
+	int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
+	if (rc < 0)
+		return 0;
+
+	return len;
+}
+
+static struct hv_ops dom0_hvc_ops = {
+	.get_chars = dom0_read_console,
+	.put_chars = dom0_write_console,
+	.notifier_add = notifier_add_irq,
+	.notifier_del = notifier_del_irq,
+	.notifier_hangup = notifier_hangup_irq,
+};
+
+static int __init xen_hvc_init(void)
 {
 	struct hvc_struct *hp;
+	struct hv_ops *ops;
 
-	if (!xen_pv_domain() ||
-	    xen_initial_domain() ||
-	    !xen_start_info->console.domU.evtchn)
+	if (!xen_pv_domain())
 		return -ENODEV;
 
-	xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+	if (xen_initial_domain()) {
+		ops = &dom0_hvc_ops;
+		xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
+	} else {
+		if (!xen_start_info->console.domU.evtchn)
+			return -ENODEV;
+
+		ops = &domU_hvc_ops;
+		xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+	}
 	if (xencons_irq < 0)
 		xencons_irq = 0; /* NO_IRQ */
 
-	hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+	hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 
@@ -160,7 +195,7 @@
 		rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq);
 }
 
-static void __exit xen_fini(void)
+static void __exit xen_hvc_fini(void)
 {
 	if (hvc)
 		hvc_remove(hvc);
@@ -168,29 +203,24 @@
 
 static int xen_cons_init(void)
 {
+	struct hv_ops *ops;
+
 	if (!xen_pv_domain())
 		return 0;
 
-	hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+	if (xen_initial_domain())
+		ops = &dom0_hvc_ops;
+	else
+		ops = &domU_hvc_ops;
+
+	hvc_instantiate(HVC_COOKIE, 0, ops);
 	return 0;
 }
 
-module_init(xen_init);
-module_exit(xen_fini);
+module_init(xen_hvc_init);
+module_exit(xen_hvc_fini);
 console_initcall(xen_cons_init);
 
-static void raw_console_write(const char *str, int len)
-{
-	while(len > 0) {
-		int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
-		if (rc <= 0)
-			break;
-
-		str += rc;
-		len -= rc;
-	}
-}
-
 #ifdef CONFIG_EARLY_PRINTK
 static void xenboot_write_console(struct console *console, const char *string,
 				  unsigned len)
@@ -198,19 +228,22 @@
 	unsigned int linelen, off = 0;
 	const char *pos;
 
-	raw_console_write(string, len);
+	dom0_write_console(0, string, len);
 
-	write_console(0, "(early) ", 8);
+	if (xen_initial_domain())
+		return;
+
+	domU_write_console(0, "(early) ", 8);
 	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
 		linelen = pos-string+off;
 		if (off + linelen > len)
 			break;
-		write_console(0, string+off, linelen);
-		write_console(0, "\r\n", 2);
+		domU_write_console(0, string+off, linelen);
+		domU_write_console(0, "\r\n", 2);
 		off += linelen + 1;
 	}
 	if (off < len)
-		write_console(0, string+off, len-off);
+		domU_write_console(0, string+off, len-off);
 }
 
 struct console xenboot_console = {
@@ -222,7 +255,7 @@
 
 void xen_raw_console_write(const char *str)
 {
-	raw_console_write(str, strlen(str));
+	dom0_write_console(0, str, strlen(str));
 }
 
 void xen_raw_printk(const char *fmt, ...)
diff -druN linux-libre-2.6.36-gnu/drivers/char/hw_random/core.c linux-libre-2.6.37-gnu/drivers/char/hw_random/core.c
--- linux-libre-2.6.36-gnu/drivers/char/hw_random/core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/hw_random/core.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
@@ -170,6 +169,7 @@
 	.owner		= THIS_MODULE,
 	.open		= rng_dev_open,
 	.read		= rng_dev_read,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice rng_miscdev = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/i8k.c linux-libre-2.6.37-gnu/drivers/char/i8k.c
--- linux-libre-2.6.36-gnu/drivers/char/i8k.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/i8k.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,7 @@
 #include <linux/seq_file.h>
 #include <linux/dmi.h>
 #include <linux/capability.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -56,6 +56,7 @@
 
 #define I8K_TEMPERATURE_BUG	1
 
+static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
@@ -119,7 +120,7 @@
 	int eax = regs->eax;
 
 #if defined(CONFIG_X86_64)
-	asm("pushq %%rax\n\t"
+	asm volatile("pushq %%rax\n\t"
 		"movl 0(%%rax),%%edx\n\t"
 		"pushq %%rdx\n\t"
 		"movl 4(%%rax),%%ebx\n\t"
@@ -145,7 +146,7 @@
 		:    "a"(regs)
 		:    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 #else
-	asm("pushl %%eax\n\t"
+	asm volatile("pushl %%eax\n\t"
 	    "movl 0(%%eax),%%edx\n\t"
 	    "push %%edx\n\t"
 	    "movl 4(%%eax),%%ebx\n\t"
@@ -166,7 +167,8 @@
 	    "movl %%edx,0(%%eax)\n\t"
 	    "lahf\n\t"
 	    "shrl $8,%%eax\n\t"
-	    "andl $1,%%eax\n":"=a"(rc)
+	    "andl $1,%%eax\n"
+	    :"=a"(rc)
 	    :    "a"(regs)
 	    :    "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
 #endif
@@ -399,9 +401,9 @@
 {
 	long ret;
 
-	lock_kernel();
+	mutex_lock(&i8k_mutex);
 	ret = i8k_ioctl_unlocked(fp, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&i8k_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/char/ip2/ip2main.c linux-libre-2.6.37-gnu/drivers/char/ip2/ip2main.c
--- linux-libre-2.6.36-gnu/drivers/char/ip2/ip2main.c	2012-03-23 21:39:08.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ip2/ip2main.c	2012-03-23 23:30:22.000000000 -0400
@@ -98,7 +98,7 @@
 #include <linux/major.h>
 #include <linux/wait.h>
 #include <linux/device.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
 
@@ -138,6 +138,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+static DEFINE_MUTEX(ip2_mutex);
 static const struct file_operations ip2mem_proc_fops;
 static const struct file_operations ip2_proc_fops;
 
@@ -183,6 +184,8 @@
 static int  ip2_tiocmget(struct tty_struct *tty, struct file *file);
 static int  ip2_tiocmset(struct tty_struct *tty, struct file *file,
 			 unsigned int set, unsigned int clear);
+static int ip2_get_icount(struct tty_struct *tty,
+		struct serial_icounter_struct *icount);
 
 static void set_irq(int, int);
 static void ip2_interrupt_bh(struct work_struct *work);
@@ -236,6 +239,7 @@
 	.write		= ip2_ipl_write,
 	.unlocked_ioctl	= ip2_ipl_ioctl,
 	.open		= ip2_ipl_open,
+	.llseek		= noop_llseek,
 }; 
 
 static unsigned long irq_counter;
@@ -454,6 +458,7 @@
 	.hangup          = ip2_hangup,
 	.tiocmget	 = ip2_tiocmget,
 	.tiocmset	 = ip2_tiocmset,
+	.get_icount	 = ip2_get_icount,
 	.proc_fops	 = &ip2_proc_fops,
 };
 
@@ -2128,7 +2133,6 @@
 	i2ChanStrPtr pCh = DevTable[tty->index];
 	i2eBordStrPtr pB;
 	struct async_icount cprev, cnow;	/* kernel counter temps */
-	struct serial_icounter_struct __user *p_cuser;
 	int rc = 0;
 	unsigned long flags;
 	void __user *argp = (void __user *)arg;
@@ -2297,34 +2301,6 @@
 		break;
 
 	/*
-	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-	 * Return: write counters to the user passed counter struct
-	 * NB: both 1->0 and 0->1 transitions are counted except for RI where
-	 * only 0->1 is counted. The controller is quite capable of counting
-	 * both, but this done to preserve compatibility with the standard
-	 * serial driver.
-	 */
-	case TIOCGICOUNT:
-		ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
-
-		write_lock_irqsave(&pB->read_fifo_spinlock, flags);
-		cnow = pCh->icount;
-		write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
-		p_cuser = argp;
-		rc = put_user(cnow.cts, &p_cuser->cts);
-		rc = put_user(cnow.dsr, &p_cuser->dsr);
-		rc = put_user(cnow.rng, &p_cuser->rng);
-		rc = put_user(cnow.dcd, &p_cuser->dcd);
-		rc = put_user(cnow.rx, &p_cuser->rx);
-		rc = put_user(cnow.tx, &p_cuser->tx);
-		rc = put_user(cnow.frame, &p_cuser->frame);
-		rc = put_user(cnow.overrun, &p_cuser->overrun);
-		rc = put_user(cnow.parity, &p_cuser->parity);
-		rc = put_user(cnow.brk, &p_cuser->brk);
-		rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
-		break;
-
-	/*
 	 * The rest are not supported by this driver. By returning -ENOIOCTLCMD they
 	 * will be passed to the line discipline for it to handle.
 	 */
@@ -2348,6 +2324,46 @@
 	return rc;
 }
 
+static int ip2_get_icount(struct tty_struct *tty,
+		struct serial_icounter_struct *icount)
+{
+	i2ChanStrPtr pCh = DevTable[tty->index];
+	i2eBordStrPtr pB;
+	struct async_icount cnow;	/* kernel counter temp */
+	unsigned long flags;
+
+	if ( pCh == NULL )
+		return -ENODEV;
+
+	pB = pCh->pMyBord;
+
+	/*
+	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+	 * Return: write counters to the user passed counter struct
+	 * NB: both 1->0 and 0->1 transitions are counted except for RI where
+	 * only 0->1 is counted. The controller is quite capable of counting
+	 * both, but this done to preserve compatibility with the standard
+	 * serial driver.
+	 */
+
+	write_lock_irqsave(&pB->read_fifo_spinlock, flags);
+	cnow = pCh->icount;
+	write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+	return 0;
+}
+
 /******************************************************************************/
 /* Function:   GetSerialInfo()                                                */
 /* Parameters: Pointer to channel structure                                   */
@@ -2897,7 +2913,7 @@
 	printk (KERN_DEBUG "IP2IPL: ioctl cmd %d, arg %ld\n", cmd, arg );
 #endif
 
-	lock_kernel();
+	mutex_lock(&ip2_mutex);
 
 	switch ( iplminor ) {
 	case 0:	    // IPL device
@@ -2961,7 +2977,7 @@
 		rc = -ENODEV;
 		break;
 	}
-	unlock_kernel();
+	mutex_unlock(&ip2_mutex);
 	return rc;
 }
 
@@ -2982,7 +2998,6 @@
 #ifdef IP2DEBUG_IPL
 	printk (KERN_DEBUG "IP2IPL: open\n" );
 #endif
-	cycle_kernel_lock();
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/ip2/Makefile linux-libre-2.6.37-gnu/drivers/char/ip2/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/ip2/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ip2/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_COMPUTONE)         += ip2.o
 
-ip2-objs			:= ip2main.o
+ip2-y			:= ip2main.o
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_bt_sm.c linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_bt_sm.c
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_bt_sm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_bt_sm.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
  *  ipmi_bt_sm.c
  *
  *  The state machine for an Open IPMI BT sub-driver under ipmi_si.c, part
- *  of the driver architecture at http://sourceforge.net/project/openipmi
+ *  of the driver architecture at http://sourceforge.net/projects/openipmi 
  *
  *  Author:	Rocky Craig <first.last@hp.com>
  *
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_devintf.c linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_devintf.c
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_devintf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_devintf.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,7 +44,6 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/compat.h>
-#include <linux/smp_lock.h>
 
 struct ipmi_file_private
 {
@@ -59,6 +58,7 @@
 	unsigned int         default_retry_time_ms;
 };
 
+static DEFINE_MUTEX(ipmi_mutex);
 static void file_receive_handler(struct ipmi_recv_msg *msg,
 				 void                 *handler_data)
 {
@@ -102,9 +102,9 @@
 	struct ipmi_file_private *priv = file->private_data;
 	int                      result;
 
-	lock_kernel(); /* could race against open() otherwise */
+	mutex_lock(&ipmi_mutex); /* could race against open() otherwise */
 	result = fasync_helper(fd, file, on, &priv->fasync_queue);
-	unlock_kernel();
+	mutex_unlock(&ipmi_mutex);
 
 	return (result);
 }
@@ -125,7 +125,7 @@
 	if (!priv)
 		return -ENOMEM;
 
-	lock_kernel();
+	mutex_lock(&ipmi_mutex);
 	priv->file = file;
 
 	rv = ipmi_create_user(if_num,
@@ -150,7 +150,7 @@
 	priv->default_retry_time_ms = 0;
 
 out:
-	unlock_kernel();
+	mutex_unlock(&ipmi_mutex);
 	return rv;
 }
 
@@ -639,9 +639,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ipmi_mutex);
 	ret = ipmi_ioctl(file, cmd, data);
-	unlock_kernel();
+	mutex_unlock(&ipmi_mutex);
 
 	return ret;
 }
@@ -850,6 +850,7 @@
 	.release	= ipmi_release,
 	.fasync		= ipmi_fasync,
 	.poll		= ipmi_poll,
+	.llseek		= noop_llseek,
 };
 
 #define DEVICE_NAME     "ipmidev"
@@ -915,7 +916,7 @@
 	.smi_gone = ipmi_smi_gone,
 };
 
-static __init int init_ipmi_devintf(void)
+static int __init init_ipmi_devintf(void)
 {
 	int rv;
 
@@ -953,7 +954,7 @@
 }
 module_init(init_ipmi_devintf);
 
-static __exit void cleanup_ipmi(void)
+static void __exit cleanup_ipmi(void)
 {
 	struct ipmi_reg_list *entry, *entry2;
 	mutex_lock(&reg_list_mutex);
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_msghandler.c linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_msghandler.c
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_msghandler.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_msghandler.c	2011-01-04 19:50:19.000000000 -0500
@@ -4442,13 +4442,13 @@
 	return 0;
 }
 
-static __init int ipmi_init_msghandler_mod(void)
+static int __init ipmi_init_msghandler_mod(void)
 {
 	ipmi_init_msghandler();
 	return 0;
 }
 
-static __exit void cleanup_ipmi(void)
+static void __exit cleanup_ipmi(void)
 {
 	int count;
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_si_intf.c linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_si_intf.c
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_si_intf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_si_intf.c	2011-01-04 19:50:19.000000000 -0500
@@ -1665,6 +1665,17 @@
 	return 0;
 }
 
+static struct smi_info *smi_info_alloc(void)
+{
+	struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+	if (info) {
+		spin_lock_init(&info->si_lock);
+		spin_lock_init(&info->msg_lock);
+	}
+	return info;
+}
+
 static int hotmod_handler(const char *val, struct kernel_param *kp)
 {
 	char *str = kstrdup(val, GFP_KERNEL);
@@ -1779,7 +1790,7 @@
 		}
 
 		if (op == HM_ADD) {
-			info = kzalloc(sizeof(*info), GFP_KERNEL);
+			info = smi_info_alloc();
 			if (!info) {
 				rv = -ENOMEM;
 				goto out;
@@ -1835,7 +1846,7 @@
 	return rv;
 }
 
-static __devinit void hardcode_find_bmc(void)
+static void __devinit hardcode_find_bmc(void)
 {
 	int             i;
 	struct smi_info *info;
@@ -1844,7 +1855,7 @@
 		if (!ports[i] && !addrs[i])
 			continue;
 
-		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		info = smi_info_alloc();
 		if (!info)
 			return;
 
@@ -1974,8 +1985,7 @@
 
 /*
  * Defined at
- * http://h21007.www2.hp.com/portal/download/files
- * /unprot/hpspmi.pdf
+ * http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf
  */
 struct SPMITable {
 	s8	Signature[4];
@@ -2019,7 +2029,7 @@
 	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
 };
 
-static __devinit int try_init_spmi(struct SPMITable *spmi)
+static int __devinit try_init_spmi(struct SPMITable *spmi)
 {
 	struct smi_info  *info;
 
@@ -2028,7 +2038,7 @@
 		return -ENODEV;
 	}
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = smi_info_alloc();
 	if (!info) {
 		printk(KERN_ERR PFX "Could not allocate SI data (3)\n");
 		return -ENOMEM;
@@ -2102,7 +2112,7 @@
 	return 0;
 }
 
-static __devinit void spmi_find_bmc(void)
+static void __devinit spmi_find_bmc(void)
 {
 	acpi_status      status;
 	struct SPMITable *spmi;
@@ -2138,7 +2148,7 @@
 	if (!acpi_dev)
 		return -ENODEV;
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = smi_info_alloc();
 	if (!info)
 		return -ENOMEM;
 
@@ -2315,11 +2325,11 @@
 	return 0;
 }
 
-static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
+static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 {
 	struct smi_info *info;
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = smi_info_alloc();
 	if (!info) {
 		printk(KERN_ERR PFX "Could not allocate SI data\n");
 		return;
@@ -2426,7 +2436,7 @@
 	int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
 	struct smi_info *info;
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = smi_info_alloc();
 	if (!info)
 		return -ENOMEM;
 
@@ -2567,7 +2577,7 @@
 		return -EINVAL;
 	}
 
-	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	info = smi_info_alloc();
 
 	if (!info) {
 		dev_err(&dev->dev,
@@ -3002,7 +3012,7 @@
 	{ .port = 0 }
 };
 
-static __devinit void default_find_bmc(void)
+static void __devinit default_find_bmc(void)
 {
 	struct smi_info *info;
 	int             i;
@@ -3014,7 +3024,7 @@
 		if (check_legacy_ioport(ipmi_defaults[i].port))
 			continue;
 #endif
-		info = kzalloc(sizeof(*info), GFP_KERNEL);
+		info = smi_info_alloc();
 		if (!info)
 			return;
 
@@ -3139,9 +3149,6 @@
 		goto out_err;
 	}
 
-	spin_lock_init(&(new_smi->si_lock));
-	spin_lock_init(&(new_smi->msg_lock));
-
 	/* Do low-level detection first. */
 	if (new_smi->handlers->detect(new_smi->si_sm)) {
 		if (new_smi->addr_source)
@@ -3305,7 +3312,7 @@
 	return rv;
 }
 
-static __devinit int init_ipmi_si(void)
+static int __devinit init_ipmi_si(void)
 {
 	int  i;
 	char *str;
@@ -3518,7 +3525,7 @@
 	kfree(to_clean);
 }
 
-static __exit void cleanup_ipmi_si(void)
+static void __exit cleanup_ipmi_si(void)
 {
 	struct smi_info *e, *tmp_e;
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_watchdog.c linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_watchdog.c
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/ipmi_watchdog.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/ipmi_watchdog.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/ipmi.h>
 #include <linux/ipmi_smi.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/watchdog.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
@@ -149,6 +149,7 @@
 #define	WDIOC_GET_PRETIMEOUT     _IOW(WATCHDOG_IOCTL_BASE, 22, int)
 #endif
 
+static DEFINE_MUTEX(ipmi_watchdog_mutex);
 static int nowayout = WATCHDOG_NOWAYOUT;
 
 static ipmi_user_t watchdog_user;
@@ -748,9 +749,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ipmi_watchdog_mutex);
 	ret = ipmi_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ipmi_watchdog_mutex);
 
 	return ret;
 }
@@ -844,7 +845,6 @@
 		if (test_and_set_bit(0, &ipmi_wdog_open))
 			return -EBUSY;
 
-		cycle_kernel_lock();
 
 		/*
 		 * Don't start the timer now, let it start on the
@@ -909,6 +909,7 @@
 	.open    = ipmi_open,
 	.release = ipmi_close,
 	.fasync  = ipmi_fasync,
+	.llseek  = no_llseek,
 };
 
 static struct miscdevice ipmi_wdog_miscdev = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/ipmi/Makefile linux-libre-2.6.37-gnu/drivers/char/ipmi/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/ipmi/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ipmi/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
 # Makefile for the ipmi drivers.
 #
 
-ipmi_si-objs := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
+ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
 
 obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
 obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
diff -druN linux-libre-2.6.36-gnu/drivers/char/istallion.c linux-libre-2.6.37-gnu/drivers/char/istallion.c
--- linux-libre-2.6.36-gnu/drivers/char/istallion.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/istallion.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -704,6 +703,7 @@
 	.read		= stli_memread,
 	.write		= stli_memwrite,
 	.unlocked_ioctl	= stli_memioctl,
+	.llseek		= default_llseek,
 };
 
 /*****************************************************************************/
diff -druN linux-libre-2.6.36-gnu/drivers/char/Kconfig linux-libre-2.6.37-gnu/drivers/char/Kconfig
--- linux-libre-2.6.36-gnu/drivers/char/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -493,6 +493,21 @@
 	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
 	  architectures and 24 bytes on 64-bit architectures.
 
+config TTY_PRINTK
+	bool "TTY driver to output user messages via printk"
+	depends on EMBEDDED
+	default n
+	---help---
+	  If you say Y here, the support for writing user messages (i.e.
+	  console messages) via printk is available.
+
+	  The feature is useful to inline user messages with kernel
+	  messages.
+	  In order to use this feature, you should output user messages
+	  to /dev/ttyprintk or redirect console to this TTY.
+
+	  If unsure, say N.
+
 config BRIQ_PANEL
 	tristate 'Total Impact briQ front panel driver'
 	depends on PPC_CHRP
diff -druN linux-libre-2.6.36-gnu/drivers/char/keyboard.c linux-libre-2.6.37-gnu/drivers/char/keyboard.c
--- linux-libre-2.6.36-gnu/drivers/char/keyboard.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/keyboard.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1437 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
- * Modified to provide 'generic' keyboard support by Hamish Macdonald
- * Merge with the m68k keyboard driver and split-off of the PC low-level
- * parts by Geert Uytterhoeven, May 1997
- *
- * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
- * 30-07-98: Dead keys redone, aeb@cwi.nl.
- * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/consolemap.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-
-extern void ctrl_alt_del(void);
-
-/*
- * Exported functions/variables
- */
-
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
-#else
-#define KBD_DEFLEDS 0
-#endif
-
-#define KBD_DEFLOCK 0
-
-void compute_shiftstate(void);
-
-/*
- * Handler Tables.
- */
-
-#define K_HANDLERS\
-	k_self,		k_fn,		k_spec,		k_pad,\
-	k_dead,		k_cons,		k_cur,		k_shift,\
-	k_meta,		k_ascii,	k_lock,		k_lowercase,\
-	k_slock,	k_dead2,	k_brl,		k_ignore
-
-typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
-			    char up_flag);
-static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
-
-#define FN_HANDLERS\
-	fn_null,	fn_enter,	fn_show_ptregs,	fn_show_mem,\
-	fn_show_state,	fn_send_intr,	fn_lastcons,	fn_caps_toggle,\
-	fn_num,		fn_hold,	fn_scroll_forw,	fn_scroll_back,\
-	fn_boot_it,	fn_caps_on,	fn_compose,	fn_SAK,\
-	fn_dec_console, fn_inc_console, fn_spawn_con,	fn_bare_num
-
-typedef void (fn_handler_fn)(struct vc_data *vc);
-static fn_handler_fn FN_HANDLERS;
-static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
-
-/*
- * Variables exported for vt_ioctl.c
- */
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-	255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
-struct vt_spawn_console vt_spawn_con = {
-	.lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
-	.pid  = NULL,
-	.sig  = 0,
-};
-
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
-
-/*
- * Internal Data.
- */
-
-static struct input_handler kbd_handler;
-static DEFINE_SPINLOCK(kbd_event_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];	/* keyboard key bitmap */
-static unsigned char shift_down[NR_SHIFT];		/* shift state counters.. */
-static bool dead_key_next;
-static int npadch = -1;					/* -1 or number assembled on pad */
-static unsigned int diacr;
-static char rep;					/* flag telling character repeat */
-
-static unsigned char ledstate = 0xff;			/* undefined */
-static unsigned char ledioctl;
-
-static struct ledptr {
-	unsigned int *addr;
-	unsigned int mask;
-	unsigned char valid:1;
-} ledptrs[3];
-
-/*
- * Notifier list for console keyboard events
- */
-static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
-
-int register_keyboard_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_keyboard_notifier);
-
-int unregister_keyboard_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
-
-/*
- * Translation of scancodes to keycodes. We set them on only the first
- * keyboard in the list that accepts the scancode and keycode.
- * Explanation for not choosing the first attached keyboard anymore:
- *  USB keyboards for example have two event devices: one for all "normal"
- *  keys and one for extra function keys (like "volume up", "make coffee",
- *  etc.). So this means that scancodes for the extra function keys won't
- *  be valid for the first event device, but will be for the second.
- */
-
-struct getset_keycode_data {
-	unsigned int scancode;
-	unsigned int keycode;
-	int error;
-};
-
-static int getkeycode_helper(struct input_handle *handle, void *data)
-{
-	struct getset_keycode_data *d = data;
-
-	d->error = input_get_keycode(handle->dev, d->scancode, &d->keycode);
-
-	return d->error == 0; /* stop as soon as we successfully get one */
-}
-
-int getkeycode(unsigned int scancode)
-{
-	struct getset_keycode_data d = { scancode, 0, -ENODEV };
-
-	input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
-
-	return d.error ?: d.keycode;
-}
-
-static int setkeycode_helper(struct input_handle *handle, void *data)
-{
-	struct getset_keycode_data *d = data;
-
-	d->error = input_set_keycode(handle->dev, d->scancode, d->keycode);
-
-	return d->error == 0; /* stop as soon as we successfully set one */
-}
-
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	struct getset_keycode_data d = { scancode, keycode, -ENODEV };
-
-	input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
-
-	return d.error;
-}
-
-/*
- * Making beeps and bells. Note that we prefer beeps to bells, but when
- * shutting the sound off we do both.
- */
-
-static int kd_sound_helper(struct input_handle *handle, void *data)
-{
-	unsigned int *hz = data;
-	struct input_dev *dev = handle->dev;
-
-	if (test_bit(EV_SND, dev->evbit)) {
-		if (test_bit(SND_TONE, dev->sndbit)) {
-			input_inject_event(handle, EV_SND, SND_TONE, *hz);
-			if (*hz)
-				return 0;
-		}
-		if (test_bit(SND_BELL, dev->sndbit))
-			input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
-	}
-
-	return 0;
-}
-
-static void kd_nosound(unsigned long ignored)
-{
-	static unsigned int zero;
-
-	input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
-}
-
-static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
-
-void kd_mksound(unsigned int hz, unsigned int ticks)
-{
-	del_timer_sync(&kd_mksound_timer);
-
-	input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
-
-	if (hz && ticks)
-		mod_timer(&kd_mksound_timer, jiffies + ticks);
-}
-EXPORT_SYMBOL(kd_mksound);
-
-/*
- * Setting the keyboard rate.
- */
-
-static int kbd_rate_helper(struct input_handle *handle, void *data)
-{
-	struct input_dev *dev = handle->dev;
-	struct kbd_repeat *rep = data;
-
-	if (test_bit(EV_REP, dev->evbit)) {
-
-		if (rep[0].delay > 0)
-			input_inject_event(handle,
-					   EV_REP, REP_DELAY, rep[0].delay);
-		if (rep[0].period > 0)
-			input_inject_event(handle,
-					   EV_REP, REP_PERIOD, rep[0].period);
-
-		rep[1].delay = dev->rep[REP_DELAY];
-		rep[1].period = dev->rep[REP_PERIOD];
-	}
-
-	return 0;
-}
-
-int kbd_rate(struct kbd_repeat *rep)
-{
-	struct kbd_repeat data[2] = { *rep };
-
-	input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
-	*rep = data[1];	/* Copy currently used settings */
-
-	return 0;
-}
-
-/*
- * Helper Functions.
- */
-static void put_queue(struct vc_data *vc, int ch)
-{
-	struct tty_struct *tty = vc->port.tty;
-
-	if (tty) {
-		tty_insert_flip_char(tty, ch, 0);
-		con_schedule_flip(tty);
-	}
-}
-
-static void puts_queue(struct vc_data *vc, char *cp)
-{
-	struct tty_struct *tty = vc->port.tty;
-
-	if (!tty)
-		return;
-
-	while (*cp) {
-		tty_insert_flip_char(tty, *cp, 0);
-		cp++;
-	}
-	con_schedule_flip(tty);
-}
-
-static void applkey(struct vc_data *vc, int key, char mode)
-{
-	static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
-	buf[1] = (mode ? 'O' : '[');
-	buf[2] = key;
-	puts_queue(vc, buf);
-}
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-static void to_utf8(struct vc_data *vc, uint c)
-{
-	if (c < 0x80)
-		/*  0******* */
-		put_queue(vc, c);
-	else if (c < 0x800) {
-		/* 110***** 10****** */
-		put_queue(vc, 0xc0 | (c >> 6));
-		put_queue(vc, 0x80 | (c & 0x3f));
-	} else if (c < 0x10000) {
-		if (c >= 0xD800 && c < 0xE000)
-			return;
-		if (c == 0xFFFF)
-			return;
-		/* 1110**** 10****** 10****** */
-		put_queue(vc, 0xe0 | (c >> 12));
-		put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-		put_queue(vc, 0x80 | (c & 0x3f));
-	} else if (c < 0x110000) {
-		/* 11110*** 10****** 10****** 10****** */
-		put_queue(vc, 0xf0 | (c >> 18));
-		put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
-		put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-		put_queue(vc, 0x80 | (c & 0x3f));
-	}
-}
-
-/*
- * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
- */
-void compute_shiftstate(void)
-{
-	unsigned int i, j, k, sym, val;
-
-	shift_state = 0;
-	memset(shift_down, 0, sizeof(shift_down));
-
-	for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
-		if (!key_down[i])
-			continue;
-
-		k = i * BITS_PER_LONG;
-
-		for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
-			if (!test_bit(k, key_down))
-				continue;
-
-			sym = U(key_maps[0][k]);
-			if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
-				continue;
-
-			val = KVAL(sym);
-			if (val == KVAL(K_CAPSSHIFT))
-				val = KVAL(K_SHIFT);
-
-			shift_down[val]++;
-			shift_state |= (1 << val);
-		}
-	}
-}
-
-/*
- * We have a combining character DIACR here, followed by the character CH.
- * If the combination occurs in the table, return the corresponding value.
- * Otherwise, if CH is a space or equals DIACR, return DIACR.
- * Otherwise, conclude that DIACR was not combining after all,
- * queue it and return CH.
- */
-static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
-{
-	unsigned int d = diacr;
-	unsigned int i;
-
-	diacr = 0;
-
-	if ((d & ~0xff) == BRL_UC_ROW) {
-		if ((ch & ~0xff) == BRL_UC_ROW)
-			return d | ch;
-	} else {
-		for (i = 0; i < accent_table_size; i++)
-			if (accent_table[i].diacr == d && accent_table[i].base == ch)
-				return accent_table[i].result;
-	}
-
-	if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
-		return d;
-
-	if (kbd->kbdmode == VC_UNICODE)
-		to_utf8(vc, d);
-	else {
-		int c = conv_uni_to_8bit(d);
-		if (c != -1)
-			put_queue(vc, c);
-	}
-
-	return ch;
-}
-
-/*
- * Special function handlers
- */
-static void fn_enter(struct vc_data *vc)
-{
-	if (diacr) {
-		if (kbd->kbdmode == VC_UNICODE)
-			to_utf8(vc, diacr);
-		else {
-			int c = conv_uni_to_8bit(diacr);
-			if (c != -1)
-				put_queue(vc, c);
-		}
-		diacr = 0;
-	}
-
-	put_queue(vc, 13);
-	if (vc_kbd_mode(kbd, VC_CRLF))
-		put_queue(vc, 10);
-}
-
-static void fn_caps_toggle(struct vc_data *vc)
-{
-	if (rep)
-		return;
-
-	chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_caps_on(struct vc_data *vc)
-{
-	if (rep)
-		return;
-
-	set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_show_ptregs(struct vc_data *vc)
-{
-	struct pt_regs *regs = get_irq_regs();
-
-	if (regs)
-		show_regs(regs);
-}
-
-static void fn_hold(struct vc_data *vc)
-{
-	struct tty_struct *tty = vc->port.tty;
-
-	if (rep || !tty)
-		return;
-
-	/*
-	 * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
-	 * these routines are also activated by ^S/^Q.
-	 * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
-	 */
-	if (tty->stopped)
-		start_tty(tty);
-	else
-		stop_tty(tty);
-}
-
-static void fn_num(struct vc_data *vc)
-{
-	if (vc_kbd_mode(kbd, VC_APPLIC))
-		applkey(vc, 'P', 1);
-	else
-		fn_bare_num(vc);
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void fn_bare_num(struct vc_data *vc)
-{
-	if (!rep)
-		chg_vc_kbd_led(kbd, VC_NUMLOCK);
-}
-
-static void fn_lastcons(struct vc_data *vc)
-{
-	/* switch to the last used console, ChN */
-	set_console(last_console);
-}
-
-static void fn_dec_console(struct vc_data *vc)
-{
-	int i, cur = fg_console;
-
-	/* Currently switching?  Queue this next switch relative to that. */
-	if (want_console != -1)
-		cur = want_console;
-
-	for (i = cur - 1; i != cur; i--) {
-		if (i == -1)
-			i = MAX_NR_CONSOLES - 1;
-		if (vc_cons_allocated(i))
-			break;
-	}
-	set_console(i);
-}
-
-static void fn_inc_console(struct vc_data *vc)
-{
-	int i, cur = fg_console;
-
-	/* Currently switching?  Queue this next switch relative to that. */
-	if (want_console != -1)
-		cur = want_console;
-
-	for (i = cur+1; i != cur; i++) {
-		if (i == MAX_NR_CONSOLES)
-			i = 0;
-		if (vc_cons_allocated(i))
-			break;
-	}
-	set_console(i);
-}
-
-static void fn_send_intr(struct vc_data *vc)
-{
-	struct tty_struct *tty = vc->port.tty;
-
-	if (!tty)
-		return;
-	tty_insert_flip_char(tty, 0, TTY_BREAK);
-	con_schedule_flip(tty);
-}
-
-static void fn_scroll_forw(struct vc_data *vc)
-{
-	scrollfront(vc, 0);
-}
-
-static void fn_scroll_back(struct vc_data *vc)
-{
-	scrollback(vc, 0);
-}
-
-static void fn_show_mem(struct vc_data *vc)
-{
-	show_mem();
-}
-
-static void fn_show_state(struct vc_data *vc)
-{
-	show_state();
-}
-
-static void fn_boot_it(struct vc_data *vc)
-{
-	ctrl_alt_del();
-}
-
-static void fn_compose(struct vc_data *vc)
-{
-	dead_key_next = true;
-}
-
-static void fn_spawn_con(struct vc_data *vc)
-{
-	spin_lock(&vt_spawn_con.lock);
-	if (vt_spawn_con.pid)
-		if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
-			put_pid(vt_spawn_con.pid);
-			vt_spawn_con.pid = NULL;
-		}
-	spin_unlock(&vt_spawn_con.lock);
-}
-
-static void fn_SAK(struct vc_data *vc)
-{
-	struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-	schedule_work(SAK_work);
-}
-
-static void fn_null(struct vc_data *vc)
-{
-	compute_shiftstate();
-}
-
-/*
- * Special key handlers
- */
-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
-{
-}
-
-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-	if (value >= ARRAY_SIZE(fn_handler))
-		return;
-	if ((kbd->kbdmode == VC_RAW ||
-	     kbd->kbdmode == VC_MEDIUMRAW) &&
-	     value != KVAL(K_SAK))
-		return;		/* SAK is allowed even in raw mode */
-	fn_handler[value](vc);
-}
-
-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	pr_err("k_lowercase was called - impossible\n");
-}
-
-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-	if (up_flag)
-		return;		/* no action, if this is a key release */
-
-	if (diacr)
-		value = handle_diacr(vc, value);
-
-	if (dead_key_next) {
-		dead_key_next = false;
-		diacr = value;
-		return;
-	}
-	if (kbd->kbdmode == VC_UNICODE)
-		to_utf8(vc, value);
-	else {
-		int c = conv_uni_to_8bit(value);
-		if (c != -1)
-			put_queue(vc, c);
-	}
-}
-
-/*
- * Handle dead key. Note that we now may have several
- * dead keys modifying the same character. Very useful
- * for Vietnamese.
- */
-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-	diacr = (diacr ? handle_diacr(vc, value) : value);
-}
-
-static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	k_unicode(vc, conv_8bit_to_uni(value), up_flag);
-}
-
-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	k_deadunicode(vc, value, up_flag);
-}
-
-/*
- * Obsolete - for backwards compatibility only
- */
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
-
-	k_deadunicode(vc, ret_diacr[value], up_flag);
-}
-
-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-	set_console(value);
-}
-
-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-	if ((unsigned)value < ARRAY_SIZE(func_table)) {
-		if (func_table[value])
-			puts_queue(vc, func_table[value]);
-	} else
-		pr_err("k_fn called with value=%d\n", value);
-}
-
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	static const char cur_chars[] = "BDCA";
-
-	if (up_flag)
-		return;
-
-	applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
-}
-
-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	static const char pad_chars[] = "0123456789+-*/\015,.?()#";
-	static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
-
-	if (up_flag)
-		return;		/* no action, if this is a key release */
-
-	/* kludge... shift forces cursor/number keys */
-	if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
-		applkey(vc, app_map[value], 1);
-		return;
-	}
-
-	if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
-
-		switch (value) {
-		case KVAL(K_PCOMMA):
-		case KVAL(K_PDOT):
-			k_fn(vc, KVAL(K_REMOVE), 0);
-			return;
-		case KVAL(K_P0):
-			k_fn(vc, KVAL(K_INSERT), 0);
-			return;
-		case KVAL(K_P1):
-			k_fn(vc, KVAL(K_SELECT), 0);
-			return;
-		case KVAL(K_P2):
-			k_cur(vc, KVAL(K_DOWN), 0);
-			return;
-		case KVAL(K_P3):
-			k_fn(vc, KVAL(K_PGDN), 0);
-			return;
-		case KVAL(K_P4):
-			k_cur(vc, KVAL(K_LEFT), 0);
-			return;
-		case KVAL(K_P6):
-			k_cur(vc, KVAL(K_RIGHT), 0);
-			return;
-		case KVAL(K_P7):
-			k_fn(vc, KVAL(K_FIND), 0);
-			return;
-		case KVAL(K_P8):
-			k_cur(vc, KVAL(K_UP), 0);
-			return;
-		case KVAL(K_P9):
-			k_fn(vc, KVAL(K_PGUP), 0);
-			return;
-		case KVAL(K_P5):
-			applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
-			return;
-		}
-	}
-
-	put_queue(vc, pad_chars[value]);
-	if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-		put_queue(vc, 10);
-}
-
-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	int old_state = shift_state;
-
-	if (rep)
-		return;
-	/*
-	 * Mimic typewriter:
-	 * a CapsShift key acts like Shift but undoes CapsLock
-	 */
-	if (value == KVAL(K_CAPSSHIFT)) {
-		value = KVAL(K_SHIFT);
-		if (!up_flag)
-			clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-	}
-
-	if (up_flag) {
-		/*
-		 * handle the case that two shift or control
-		 * keys are depressed simultaneously
-		 */
-		if (shift_down[value])
-			shift_down[value]--;
-	} else
-		shift_down[value]++;
-
-	if (shift_down[value])
-		shift_state |= (1 << value);
-	else
-		shift_state &= ~(1 << value);
-
-	/* kludge */
-	if (up_flag && shift_state != old_state && npadch != -1) {
-		if (kbd->kbdmode == VC_UNICODE)
-			to_utf8(vc, npadch);
-		else
-			put_queue(vc, npadch & 0xff);
-		npadch = -1;
-	}
-}
-
-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	if (up_flag)
-		return;
-
-	if (vc_kbd_mode(kbd, VC_META)) {
-		put_queue(vc, '\033');
-		put_queue(vc, value);
-	} else
-		put_queue(vc, value | 0x80);
-}
-
-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	int base;
-
-	if (up_flag)
-		return;
-
-	if (value < 10) {
-		/* decimal input of code, while Alt depressed */
-		base = 10;
-	} else {
-		/* hexadecimal input of code, while AltGr depressed */
-		value -= 10;
-		base = 16;
-	}
-
-	if (npadch == -1)
-		npadch = value;
-	else
-		npadch = npadch * base + value;
-}
-
-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	if (up_flag || rep)
-		return;
-
-	chg_vc_kbd_lock(kbd, value);
-}
-
-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	k_shift(vc, value, up_flag);
-	if (up_flag || rep)
-		return;
-
-	chg_vc_kbd_slock(kbd, value);
-	/* try to make Alt, oops, AltGr and such work */
-	if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
-		kbd->slockstate = 0;
-		chg_vc_kbd_slock(kbd, value);
-	}
-}
-
-/* by default, 300ms interval for combination release */
-static unsigned brl_timeout = 300;
-MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
-module_param(brl_timeout, uint, 0644);
-
-static unsigned brl_nbchords = 1;
-MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
-module_param(brl_nbchords, uint, 0644);
-
-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
-{
-	static unsigned long chords;
-	static unsigned committed;
-
-	if (!brl_nbchords)
-		k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
-	else {
-		committed |= pattern;
-		chords++;
-		if (chords == brl_nbchords) {
-			k_unicode(vc, BRL_UC_ROW | committed, up_flag);
-			chords = 0;
-			committed = 0;
-		}
-	}
-}
-
-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
-{
-	static unsigned pressed, committing;
-	static unsigned long releasestart;
-
-	if (kbd->kbdmode != VC_UNICODE) {
-		if (!up_flag)
-			pr_warning("keyboard mode must be unicode for braille patterns\n");
-		return;
-	}
-
-	if (!value) {
-		k_unicode(vc, BRL_UC_ROW, up_flag);
-		return;
-	}
-
-	if (value > 8)
-		return;
-
-	if (!up_flag) {
-		pressed |= 1 << (value - 1);
-		if (!brl_timeout)
-			committing = pressed;
-	} else if (brl_timeout) {
-		if (!committing ||
-		    time_after(jiffies,
-			       releasestart + msecs_to_jiffies(brl_timeout))) {
-			committing = pressed;
-			releasestart = jiffies;
-		}
-		pressed &= ~(1 << (value - 1));
-		if (!pressed && committing) {
-			k_brlcommit(vc, committing, 0);
-			committing = 0;
-		}
-	} else {
-		if (committing) {
-			k_brlcommit(vc, committing, 0);
-			committing = 0;
-		}
-		pressed &= ~(1 << (value - 1));
-	}
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-unsigned char getledstate(void)
-{
-	return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led)
-{
-	if (!(led & ~7)) {
-		ledioctl = led;
-		kbd->ledmode = LED_SHOW_IOCTL;
-	} else
-		kbd->ledmode = LED_SHOW_FLAGS;
-
-	set_leds();
-}
-
-static inline unsigned char getleds(void)
-{
-	struct kbd_struct *kbd = kbd_table + fg_console;
-	unsigned char leds;
-	int i;
-
-	if (kbd->ledmode == LED_SHOW_IOCTL)
-		return ledioctl;
-
-	leds = kbd->ledflagstate;
-
-	if (kbd->ledmode == LED_SHOW_MEM) {
-		for (i = 0; i < 3; i++)
-			if (ledptrs[i].valid) {
-				if (*ledptrs[i].addr & ledptrs[i].mask)
-					leds |= (1 << i);
-				else
-					leds &= ~(1 << i);
-			}
-	}
-	return leds;
-}
-
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
-	unsigned char leds = *(unsigned char *)data;
-
-	if (test_bit(EV_LED, handle->dev->evbit)) {
-		input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-		input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-		input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-		input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-	}
-
-	return 0;
-}
-
-/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates form VT to
- * update led state.
- */
-static void kbd_bh(unsigned long dummy)
-{
-	unsigned char leds = getleds();
-
-	if (leds != ledstate) {
-		input_handler_for_each_handle(&kbd_handler, &leds,
-					      kbd_update_leds_helper);
-		ledstate = leds;
-	}
-}
-
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
-    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
-    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
-    defined(CONFIG_AVR32)
-
-#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
-			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
-
-static const unsigned short x86_keycodes[256] =
-	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-	 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
-	284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
-	367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
-	360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
-	103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
-	291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
-	264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
-	377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
-	308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
-	332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-
-#ifdef CONFIG_SPARC
-static int sparc_l1_a_state;
-extern void sun_do_break(void);
-#endif
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode,
-		       unsigned char up_flag)
-{
-	int code;
-
-	switch (keycode) {
-
-	case KEY_PAUSE:
-		put_queue(vc, 0xe1);
-		put_queue(vc, 0x1d | up_flag);
-		put_queue(vc, 0x45 | up_flag);
-		break;
-
-	case KEY_HANGEUL:
-		if (!up_flag)
-			put_queue(vc, 0xf2);
-		break;
-
-	case KEY_HANJA:
-		if (!up_flag)
-			put_queue(vc, 0xf1);
-		break;
-
-	case KEY_SYSRQ:
-		/*
-		 * Real AT keyboards (that's what we're trying
-		 * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
-		 * pressing PrtSc/SysRq alone, but simply 0x54
-		 * when pressing Alt+PrtSc/SysRq.
-		 */
-		if (test_bit(KEY_LEFTALT, key_down) ||
-		    test_bit(KEY_RIGHTALT, key_down)) {
-			put_queue(vc, 0x54 | up_flag);
-		} else {
-			put_queue(vc, 0xe0);
-			put_queue(vc, 0x2a | up_flag);
-			put_queue(vc, 0xe0);
-			put_queue(vc, 0x37 | up_flag);
-		}
-		break;
-
-	default:
-		if (keycode > 255)
-			return -1;
-
-		code = x86_keycodes[keycode];
-		if (!code)
-			return -1;
-
-		if (code & 0x100)
-			put_queue(vc, 0xe0);
-		put_queue(vc, (code & 0x7f) | up_flag);
-
-		break;
-	}
-
-	return 0;
-}
-
-#else
-
-#define HW_RAW(dev)	0
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
-{
-	if (keycode > 127)
-		return -1;
-
-	put_queue(vc, keycode | up_flag);
-	return 0;
-}
-#endif
-
-static void kbd_rawcode(unsigned char data)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-
-	kbd = kbd_table + vc->vc_num;
-	if (kbd->kbdmode == VC_RAW)
-		put_queue(vc, data);
-}
-
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-	unsigned short keysym, *key_map;
-	unsigned char type;
-	bool raw_mode;
-	struct tty_struct *tty;
-	int shift_final;
-	struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
-	int rc;
-
-	tty = vc->port.tty;
-
-	if (tty && (!tty->driver_data)) {
-		/* No driver data? Strange. Okay we fix it then. */
-		tty->driver_data = vc;
-	}
-
-	kbd = kbd_table + vc->vc_num;
-
-#ifdef CONFIG_SPARC
-	if (keycode == KEY_STOP)
-		sparc_l1_a_state = down;
-#endif
-
-	rep = (down == 2);
-
-	raw_mode = (kbd->kbdmode == VC_RAW);
-	if (raw_mode && !hw_raw)
-		if (emulate_raw(vc, keycode, !down << 7))
-			if (keycode < BTN_MISC && printk_ratelimit())
-				pr_warning("can't emulate rawmode for keycode %d\n",
-					   keycode);
-
-#ifdef CONFIG_SPARC
-	if (keycode == KEY_A && sparc_l1_a_state) {
-		sparc_l1_a_state = false;
-		sun_do_break();
-	}
-#endif
-
-	if (kbd->kbdmode == VC_MEDIUMRAW) {
-		/*
-		 * This is extended medium raw mode, with keys above 127
-		 * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
-		 * the 'up' flag if needed. 0 is reserved, so this shouldn't
-		 * interfere with anything else. The two bytes after 0 will
-		 * always have the up flag set not to interfere with older
-		 * applications. This allows for 16384 different keycodes,
-		 * which should be enough.
-		 */
-		if (keycode < 128) {
-			put_queue(vc, keycode | (!down << 7));
-		} else {
-			put_queue(vc, !down << 7);
-			put_queue(vc, (keycode >> 7) | 0x80);
-			put_queue(vc, keycode | 0x80);
-		}
-		raw_mode = true;
-	}
-
-	if (down)
-		set_bit(keycode, key_down);
-	else
-		clear_bit(keycode, key_down);
-
-	if (rep &&
-	    (!vc_kbd_mode(kbd, VC_REPEAT) ||
-	     (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
-		/*
-		 * Don't repeat a key if the input buffers are not empty and the
-		 * characters get aren't echoed locally. This makes key repeat
-		 * usable with slow applications and under heavy loads.
-		 */
-		return;
-	}
-
-	param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
-	param.ledstate = kbd->ledflagstate;
-	key_map = key_maps[shift_final];
-
-	rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-					KBD_KEYCODE, &param);
-	if (rc == NOTIFY_STOP || !key_map) {
-		atomic_notifier_call_chain(&keyboard_notifier_list,
-					   KBD_UNBOUND_KEYCODE, &param);
-		compute_shiftstate();
-		kbd->slockstate = 0;
-		return;
-	}
-
-	if (keycode < NR_KEYS)
-		keysym = key_map[keycode];
-	else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
-		keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
-	else
-		return;
-
-	type = KTYP(keysym);
-
-	if (type < 0xf0) {
-		param.value = keysym;
-		rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-						KBD_UNICODE, &param);
-		if (rc != NOTIFY_STOP)
-			if (down && !raw_mode)
-				to_utf8(vc, keysym);
-		return;
-	}
-
-	type -= 0xf0;
-
-	if (type == KT_LETTER) {
-		type = KT_LATIN;
-		if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-			key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
-			if (key_map)
-				keysym = key_map[keycode];
-		}
-	}
-
-	param.value = keysym;
-	rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-					KBD_KEYSYM, &param);
-	if (rc == NOTIFY_STOP)
-		return;
-
-	if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
-		return;
-
-	(*k_handler[type])(vc, keysym & 0xff, !down);
-
-	param.ledstate = kbd->ledflagstate;
-	atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
-
-	if (type != KT_SLOCK)
-		kbd->slockstate = 0;
-}
-
-static void kbd_event(struct input_handle *handle, unsigned int event_type,
-		      unsigned int event_code, int value)
-{
-	/* We are called with interrupts disabled, just take the lock */
-	spin_lock(&kbd_event_lock);
-
-	if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
-		kbd_rawcode(value);
-	if (event_type == EV_KEY)
-		kbd_keycode(event_code, value, HW_RAW(handle->dev));
-
-	spin_unlock(&kbd_event_lock);
-
-	tasklet_schedule(&keyboard_tasklet);
-	do_poke_blanked_console = 1;
-	schedule_console_callback();
-}
-
-static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
-{
-	int i;
-
-	if (test_bit(EV_SND, dev->evbit))
-		return true;
-
-	if (test_bit(EV_KEY, dev->evbit)) {
-		for (i = KEY_RESERVED; i < BTN_MISC; i++)
-			if (test_bit(i, dev->keybit))
-				return true;
-		for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
-			if (test_bit(i, dev->keybit))
-				return true;
-	}
-
-	return false;
-}
-
-/*
- * When a keyboard (or other input device) is found, the kbd_connect
- * function is called. The function then looks at the device, and if it
- * likes it, it can open it and get events from it. In this (kbd_connect)
- * function, we should decide which VT to bind that keyboard to initially.
- */
-static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
-			const struct input_device_id *id)
-{
-	struct input_handle *handle;
-	int error;
-
-	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-	if (!handle)
-		return -ENOMEM;
-
-	handle->dev = dev;
-	handle->handler = handler;
-	handle->name = "kbd";
-
-	error = input_register_handle(handle);
-	if (error)
-		goto err_free_handle;
-
-	error = input_open_device(handle);
-	if (error)
-		goto err_unregister_handle;
-
-	return 0;
-
- err_unregister_handle:
-	input_unregister_handle(handle);
- err_free_handle:
-	kfree(handle);
-	return error;
-}
-
-static void kbd_disconnect(struct input_handle *handle)
-{
-	input_close_device(handle);
-	input_unregister_handle(handle);
-	kfree(handle);
-}
-
-/*
- * Start keyboard handler on the new keyboard by refreshing LED state to
- * match the rest of the system.
- */
-static void kbd_start(struct input_handle *handle)
-{
-	tasklet_disable(&keyboard_tasklet);
-
-	if (ledstate != 0xff)
-		kbd_update_leds_helper(handle, &ledstate);
-
-	tasklet_enable(&keyboard_tasklet);
-}
-
-static const struct input_device_id kbd_ids[] = {
-	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
-
-	{
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
-
-	{ },    /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, kbd_ids);
-
-static struct input_handler kbd_handler = {
-	.event		= kbd_event,
-	.match		= kbd_match,
-	.connect	= kbd_connect,
-	.disconnect	= kbd_disconnect,
-	.start		= kbd_start,
-	.name		= "kbd",
-	.id_table	= kbd_ids,
-};
-
-int __init kbd_init(void)
-{
-	int i;
-	int error;
-
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		kbd_table[i].ledflagstate = KBD_DEFLEDS;
-		kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
-		kbd_table[i].ledmode = LED_SHOW_FLAGS;
-		kbd_table[i].lockstate = KBD_DEFLOCK;
-		kbd_table[i].slockstate = 0;
-		kbd_table[i].modeflags = KBD_DEFMODE;
-		kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-	}
-
-	error = input_register_handler(&kbd_handler);
-	if (error)
-		return error;
-
-	tasklet_enable(&keyboard_tasklet);
-	tasklet_schedule(&keyboard_tasklet);
-
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/char/lp.c linux-libre-2.6.37-gnu/drivers/char/lp.c
--- linux-libre-2.6.36-gnu/drivers/char/lp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/lp.c	2011-01-04 19:50:19.000000000 -0500
@@ -126,7 +126,7 @@
 #include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/jiffies.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/compat.h>
 
 #include <linux/parport.h>
@@ -140,6 +140,7 @@
 /* if you have more than 8 printers, remember to increase LP_NO */
 #define LP_NO 8
 
+static DEFINE_MUTEX(lp_mutex);
 static struct lp_struct lp_table[LP_NO];
 
 static unsigned int lp_count = 0;
@@ -493,7 +494,7 @@
 	unsigned int minor = iminor(inode);
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&lp_mutex);
 	if (minor >= LP_NO) {
 		ret = -ENXIO;
 		goto out;
@@ -554,7 +555,7 @@
 	lp_release_parport (&lp_table[minor]);
 	lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
 out:
-	unlock_kernel();
+	mutex_unlock(&lp_mutex);
 	return ret;
 }
 
@@ -680,7 +681,7 @@
 	int ret;
 
 	minor = iminor(file->f_path.dentry->d_inode);
-	lock_kernel();
+	mutex_lock(&lp_mutex);
 	switch (cmd) {
 	case LPSETTIMEOUT:
 		if (copy_from_user(&par_timeout, (void __user *)arg,
@@ -694,7 +695,7 @@
 		ret = lp_do_ioctl(minor, cmd, arg, (void __user *)arg);
 		break;
 	}
-	unlock_kernel();
+	mutex_unlock(&lp_mutex);
 
 	return ret;
 }
@@ -709,7 +710,7 @@
 	int ret;
 
 	minor = iminor(file->f_path.dentry->d_inode);
-	lock_kernel();
+	mutex_lock(&lp_mutex);
 	switch (cmd) {
 	case LPSETTIMEOUT:
 		tc = compat_ptr(arg);
@@ -730,7 +731,7 @@
 		ret = lp_do_ioctl(minor, cmd, arg, compat_ptr(arg));
 		break;
 	}
-	unlock_kernel();
+	mutex_unlock(&lp_mutex);
 
 	return ret;
 }
@@ -748,6 +749,7 @@
 #ifdef CONFIG_PARPORT_1284
 	.read		= lp_read,
 #endif
+	.llseek		= noop_llseek,
 };
 
 /* --- support for console on the line printer ----------------- */
diff -druN linux-libre-2.6.36-gnu/drivers/char/Makefile linux-libre-2.6.37-gnu/drivers/char/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,23 +2,10 @@
 # Makefile for the kernel character device drivers.
 #
 
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y	 += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y				+= tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
-obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
+obj-y				+= mem.o random.o
+obj-$(CONFIG_TTY_PRINTK)	+= ttyprintk.o
 obj-y				+= misc.o
-obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)	+= bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)	+= vt.o defkeymap.o
-obj-$(CONFIG_AUDIT)		+= tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ)	+= sysrq.o
 obj-$(CONFIG_MVME147_SCC)	+= generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)	+= generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)	+= generic_serial.o vme_scc.o
@@ -40,8 +27,6 @@
 obj-$(CONFIG_SYNCLINK)		+= synclink.o
 obj-$(CONFIG_SYNCLINKMP)	+= synclinkmp.o
 obj-$(CONFIG_SYNCLINK_GT)	+= synclink_gt.o
-obj-$(CONFIG_N_HDLC)		+= n_hdlc.o
-obj-$(CONFIG_N_GSM)		+= n_gsm.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)		+= sx.o generic_serial.o
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
@@ -73,7 +58,6 @@
 obj-$(CONFIG_APM_EMULATION)	+= apm-emulation.o
 
 obj-$(CONFIG_DTLK)		+= dtlk.o
-obj-$(CONFIG_R3964)		+= n_r3964.o
 obj-$(CONFIG_APPLICOM)		+= applicom.o
 obj-$(CONFIG_SONYPI)		+= sonypi.o
 obj-$(CONFIG_RTC)		+= rtc.o
@@ -114,28 +98,3 @@
 
 obj-$(CONFIG_JS_RTC)		+= js-rtc.o
 js-rtc-y = rtc.o
-
-# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
-
-quiet_cmd_conmk = CONMK   $@
-      cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
-	$(call cmd,conmk)
-
-$(obj)/defkeymap.o:  $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
-	loadkeys --mktable $< > $@.tmp
-	sed -e 's/^static *//' $@.tmp > $@
-	rm $@.tmp
-
-endif
diff -druN linux-libre-2.6.36-gnu/drivers/char/mbcs.c linux-libre-2.6.37-gnu/drivers/char/mbcs.c
--- linux-libre-2.6.36-gnu/drivers/char/mbcs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mbcs.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,6 @@
 #include <linux/mm.h>
 #include <linux/uio.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -42,6 +41,7 @@
 #else
 #define DBG(fmt...)
 #endif
+static DEFINE_MUTEX(mbcs_mutex);
 static int mbcs_major;
 
 static LIST_HEAD(soft_list);
@@ -385,19 +385,19 @@
 	struct mbcs_soft *soft;
 	int minor;
 
-	lock_kernel();
+	mutex_lock(&mbcs_mutex);
 	minor = iminor(ip);
 
 	/* Nothing protects access to this list... */
 	list_for_each_entry(soft, &soft_list, list) {
 		if (soft->nasid == minor) {
 			fp->private_data = soft->cxdev;
-			unlock_kernel();
+			mutex_unlock(&mbcs_mutex);
 			return 0;
 		}
 	}
 
-	unlock_kernel();
+	mutex_unlock(&mbcs_mutex);
 	return -ENODEV;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/mem.c linux-libre-2.6.37-gnu/drivers/char/mem.c
--- linux-libre-2.6.36-gnu/drivers/char/mem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mem.c	2011-01-04 19:50:19.000000000 -0500
@@ -805,6 +805,7 @@
 static const struct file_operations oldmem_fops = {
 	.read	= read_oldmem,
 	.open	= open_oldmem,
+	.llseek = default_llseek,
 };
 #endif
 
@@ -831,6 +832,7 @@
 
 static const struct file_operations kmsg_fops = {
 	.write = kmsg_write,
+	.llseek = noop_llseek,
 };
 
 static const struct memdev {
@@ -874,6 +876,10 @@
 	if (dev->dev_info)
 		filp->f_mapping->backing_dev_info = dev->dev_info;
 
+	/* Is /dev/mem or /dev/kmem ? */
+	if (dev->dev_info == &directly_mappable_cdev_bdi)
+		filp->f_mode |= FMODE_UNSIGNED_OFFSET;
+
 	if (dev->fops->open)
 		return dev->fops->open(inode, filp);
 
@@ -882,6 +888,7 @@
 
 static const struct file_operations memory_fops = {
 	.open = memory_open,
+	.llseek = noop_llseek,
 };
 
 static char *mem_devnode(struct device *dev, mode_t *mode)
diff -druN linux-libre-2.6.36-gnu/drivers/char/misc.c linux-libre-2.6.37-gnu/drivers/char/misc.c
--- linux-libre-2.6.36-gnu/drivers/char/misc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/misc.c	2011-01-04 19:50:19.000000000 -0500
@@ -162,6 +162,7 @@
 static const struct file_operations misc_fops = {
 	.owner		= THIS_MODULE,
 	.open		= misc_open,
+	.llseek		= noop_llseek,
 };
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/char/mmtimer.c linux-libre-2.6.37-gnu/drivers/char/mmtimer.c
--- linux-libre-2.6.36-gnu/drivers/char/mmtimer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mmtimer.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,7 @@
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/math64.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
@@ -59,6 +59,7 @@
 
 #define rtc_time()              (*RTC_COUNTER_ADDR)
 
+static DEFINE_MUTEX(mmtimer_mutex);
 static long mmtimer_ioctl(struct file *file, unsigned int cmd,
 						unsigned long arg);
 static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
@@ -72,6 +73,7 @@
 	.owner = THIS_MODULE,
 	.mmap =	mmtimer_mmap,
 	.unlocked_ioctl = mmtimer_ioctl,
+	.llseek = noop_llseek,
 };
 
 /*
@@ -174,9 +176,9 @@
  * in order to insure that the setup succeeds in a deterministic time frame.
  * It will check if the interrupt setup succeeded.
  */
-static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
+static int mmtimer_setup(int cpu, int comparator, unsigned long expires,
+	u64 *set_completion_time)
 {
-
 	switch (comparator) {
 	case 0:
 		mmtimer_setup_int_0(cpu, expires);
@@ -189,7 +191,8 @@
 		break;
 	}
 	/* We might've missed our expiration time */
-	if (rtc_time() <= expires)
+	*set_completion_time = rtc_time();
+	if (*set_completion_time <= expires)
 		return 1;
 
 	/*
@@ -225,6 +228,8 @@
 #define TIMER_OFF	0xbadcabLL	/* Timer is not setup */
 #define TIMER_SET	0		/* Comparator is set for this timer */
 
+#define MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT 40
+
 /* There is one of these for each timer */
 struct mmtimer {
 	struct rb_node list;
@@ -240,6 +245,11 @@
 };
 static struct mmtimer_node *timers;
 
+static unsigned mmtimer_interval_retry_increment =
+	MMTIMER_INTERVAL_RETRY_INCREMENT_DEFAULT;
+module_param(mmtimer_interval_retry_increment, uint, 0644);
+MODULE_PARM_DESC(mmtimer_interval_retry_increment,
+	"RTC ticks to add to expiration on interval retry (default 40)");
 
 /*
  * Add a new mmtimer struct to the node's mmtimer list.
@@ -287,7 +297,8 @@
 	struct mmtimer_node *n = &timers[nodeid];
 	struct mmtimer *x;
 	struct k_itimer *t;
-	int o;
+	u64 expires, exp, set_completion_time;
+	int i;
 
 restart:
 	if (n->next == NULL)
@@ -298,7 +309,8 @@
 	if (!t->it.mmtimer.incr) {
 		/* Not an interval timer */
 		if (!mmtimer_setup(x->cpu, COMPARATOR,
-					t->it.mmtimer.expires)) {
+					t->it.mmtimer.expires,
+					&set_completion_time)) {
 			/* Late setup, fire now */
 			tasklet_schedule(&n->tasklet);
 		}
@@ -306,14 +318,23 @@
 	}
 
 	/* Interval timer */
-	o = 0;
-	while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) {
-		unsigned long e, e1;
-		struct rb_node *next;
-		t->it.mmtimer.expires += t->it.mmtimer.incr << o;
-		t->it_overrun += 1 << o;
-		o++;
-		if (o > 20) {
+	i = 0;
+	expires = exp = t->it.mmtimer.expires;
+	while (!mmtimer_setup(x->cpu, COMPARATOR, expires,
+				&set_completion_time)) {
+		int to;
+
+		i++;
+		expires = set_completion_time +
+				mmtimer_interval_retry_increment + (1 << i);
+		/* Calculate overruns as we go. */
+		to = ((u64)(expires - exp) / t->it.mmtimer.incr);
+		if (to) {
+			t->it_overrun += to;
+			t->it.mmtimer.expires += t->it.mmtimer.incr * to;
+			exp = t->it.mmtimer.expires;
+		}
+		if (i > 20) {
 			printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
 			t->it.mmtimer.clock = TIMER_OFF;
 			n->next = rb_next(&x->list);
@@ -321,21 +342,6 @@
 			kfree(x);
 			goto restart;
 		}
-
-		e = t->it.mmtimer.expires;
-		next = rb_next(&x->list);
-
-		if (next == NULL)
-			continue;
-
-		e1 = rb_entry(next, struct mmtimer, list)->
-			timer->it.mmtimer.expires;
-		if (e > e1) {
-			n->next = next;
-			rb_erase(&x->list, &n->timer_head);
-			mmtimer_add_list(x);
-			goto restart;
-		}
 	}
 }
 
@@ -371,7 +377,7 @@
 {
 	int ret = 0;
 
-	lock_kernel();
+	mutex_lock(&mmtimer_mutex);
 
 	switch (cmd) {
 	case MMTIMER_GETOFFSET:	/* offset of the counter */
@@ -414,7 +420,7 @@
 		ret = -ENOTTY;
 		break;
 	}
-	unlock_kernel();
+	mutex_unlock(&mmtimer_mutex);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/mspec.c linux-libre-2.6.37-gnu/drivers/char/mspec.c
--- linux-libre-2.6.36-gnu/drivers/char/mspec.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mspec.c	2011-01-04 19:50:19.000000000 -0500
@@ -316,7 +316,8 @@
 
 static const struct file_operations fetchop_fops = {
 	.owner = THIS_MODULE,
-	.mmap = fetchop_mmap
+	.mmap = fetchop_mmap,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice fetchop_miscdev = {
@@ -327,7 +328,8 @@
 
 static const struct file_operations cached_fops = {
 	.owner = THIS_MODULE,
-	.mmap = cached_mmap
+	.mmap = cached_mmap,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice cached_miscdev = {
@@ -338,7 +340,8 @@
 
 static const struct file_operations uncached_fops = {
 	.owner = THIS_MODULE,
-	.mmap = uncached_mmap
+	.mmap = uncached_mmap,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice uncached_miscdev = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/mwave/Makefile linux-libre-2.6.37-gnu/drivers/char/mwave/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/mwave/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mwave/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,10 +6,10 @@
 
 obj-$(CONFIG_MWAVE) += mwave.o
 
-mwave-objs := mwavedd.o smapi.o tp3780i.o 3780i.o
+mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o
 
 # To have the mwave driver disable other uarts if necessary
 # EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES
 
 # To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
-EXTRA_CFLAGS += -DMW_TRACE
+ccflags-y := -DMW_TRACE
diff -druN linux-libre-2.6.36-gnu/drivers/char/mwave/mwavedd.c linux-libre-2.6.37-gnu/drivers/char/mwave/mwavedd.c
--- linux-libre-2.6.36-gnu/drivers/char/mwave/mwavedd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mwave/mwavedd.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,7 +56,7 @@
 #include <linux/serial.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/serial_8250.h>
 #include "smapi.h"
@@ -73,6 +73,7 @@
 * checks are made against other devices (ie. superio) for conflicts.
 * We'll depend on users using the tpctl utility to do that for now
 */
+static DEFINE_MUTEX(mwave_mutex);
 int mwave_debug = 0;
 int mwave_3780i_irq = 0;
 int mwave_3780i_io = 0;
@@ -101,7 +102,6 @@
 	PRINTK_2(TRACE_MWAVE,
 		"mwavedd::mwave_open, exit return retval %x\n", retval);
 
-	cycle_kernel_lock();
 	return retval;
 }
 
@@ -136,9 +136,9 @@
 			PRINTK_1(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
 				" calling tp3780I_ResetDSP\n");
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_ResetDSP(&pDrvData->rBDData);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 			PRINTK_2(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
 				" retval %x from tp3780I_ResetDSP\n",
@@ -149,9 +149,9 @@
 			PRINTK_1(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
 				" calling tp3780I_StartDSP\n");
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_StartDSP(&pDrvData->rBDData);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 			PRINTK_2(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
 				" retval %x from tp3780I_StartDSP\n",
@@ -165,10 +165,10 @@
 				"mwavedd::mwave_ioctl,"
 				" IOCTL_MW_DSP_ABILITIES calling"
 				" tp3780I_QueryAbilities\n");
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
 					&rAbilities);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 			PRINTK_2(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
 				" retval %x from tp3780I_QueryAbilities\n",
@@ -199,13 +199,13 @@
 				"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
 				" size %lx, ioarg %lx pusBuffer %p\n",
 				rReadData.ulDataLength, ioarg, pusBuffer);
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 					iocmd,
 					pusBuffer,
 					rReadData.ulDataLength,
 					rReadData.usDspAddress);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -223,12 +223,12 @@
 				" size %lx, ioarg %lx pusBuffer %p\n",
 				rReadData.ulDataLength / 2, ioarg,
 				pusBuffer);
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 				iocmd, pusBuffer,
 				rReadData.ulDataLength / 2,
 				rReadData.usDspAddress);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -246,12 +246,12 @@
 				" size %lx, ioarg %lx pusBuffer %p\n",
 				rWriteData.ulDataLength, ioarg,
 				pusBuffer);
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
 					iocmd, pusBuffer,
 					rWriteData.ulDataLength,
 					rWriteData.usDspAddress);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -269,12 +269,12 @@
 				" size %lx, ioarg %lx pusBuffer %p\n",
 				rWriteData.ulDataLength, ioarg,
 				pusBuffer);
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
 					iocmd, pusBuffer,
 					rWriteData.ulDataLength,
 					rWriteData.usDspAddress);
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -295,10 +295,10 @@
 				ipcnum,
 				pDrvData->IPCs[ipcnum].usIntCount);
 
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			pDrvData->IPCs[ipcnum].bIsHere = FALSE;
 			pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 	
 			PRINTK_2(TRACE_MWAVE,
 				"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
@@ -323,7 +323,7 @@
 				ipcnum,
 				pDrvData->IPCs[ipcnum].usIntCount);
 	
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
 				DECLARE_WAITQUEUE(wait, current);
 
@@ -364,7 +364,7 @@
 					" processing\n",
 					ipcnum);
 			}
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -383,14 +383,14 @@
 						ipcnum);
 				return -EINVAL;
 			}
-			lock_kernel();
+			mutex_lock(&mwave_mutex);
 			if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
 				pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
 				if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
 					wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
 				}
 			}
-			unlock_kernel();
+			mutex_unlock(&mwave_mutex);
 		}
 			break;
 	
@@ -479,7 +479,8 @@
 	.write		= mwave_write,
 	.unlocked_ioctl	= mwave_ioctl,
 	.open		= mwave_open,
-	.release	= mwave_close
+	.release	= mwave_close,
+	.llseek		= default_llseek,
 };
 
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/mxser.c linux-libre-2.6.37-gnu/drivers/char/mxser.c
--- linux-libre-2.6.36-gnu/drivers/char/mxser.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/mxser.c	2011-01-04 19:50:19.000000000 -0500
@@ -303,6 +303,7 @@
 	outb(oldlcr, baseio + UART_LCR);
 }
 
+#ifdef	CONFIG_PCI
 static void mxser_disable_must_enchance_mode(unsigned long baseio)
 {
 	u8 oldlcr;
@@ -317,6 +318,7 @@
 	outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
 	outb(oldlcr, baseio + UART_LCR);
 }
+#endif
 
 static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
 {
@@ -388,6 +390,7 @@
 	outb(oldlcr, baseio + UART_LCR);
 }
 
+#ifdef CONFIG_PCI
 static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
 {
 	u8 oldlcr;
@@ -404,6 +407,7 @@
 	*pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
 	outb(oldlcr, baseio + UART_LCR);
 }
+#endif
 
 static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
 {
@@ -1700,7 +1704,7 @@
 		return 0;
 	}
 
-	if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+	if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
 			test_bit(TTY_IO_ERROR, &tty->flags))
 		return -EIO;
 
@@ -1730,32 +1734,6 @@
 
 		return wait_event_interruptible(info->port.delta_msr_wait,
 				mxser_cflags_changed(info, arg, &cnow));
-	/*
-	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-	 * Return: write counters to the user passed counter struct
-	 * NB: both 1->0 and 0->1 transitions are counted except for
-	 *     RI where only 0->1 is counted.
-	 */
-	case TIOCGICOUNT: {
-		struct serial_icounter_struct icnt = { 0 };
-		spin_lock_irqsave(&info->slock, flags);
-		cnow = info->icount;
-		spin_unlock_irqrestore(&info->slock, flags);
-
-		icnt.frame = cnow.frame;
-		icnt.brk = cnow.brk;
-		icnt.overrun = cnow.overrun;
-		icnt.buf_overrun = cnow.buf_overrun;
-		icnt.parity = cnow.parity;
-		icnt.rx = cnow.rx;
-		icnt.tx = cnow.tx;
-		icnt.cts = cnow.cts;
-		icnt.dsr = cnow.dsr;
-		icnt.rng = cnow.rng;
-		icnt.dcd = cnow.dcd;
-
-		return copy_to_user(argp, &icnt, sizeof(icnt)) ? -EFAULT : 0;
-	}
 	case MOXA_HighSpeedOn:
 		return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
 	case MOXA_SDS_RSTICOUNTER:
@@ -1828,6 +1806,39 @@
 	return 0;
 }
 
+	/*
+	 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+	 * Return: write counters to the user passed counter struct
+	 * NB: both 1->0 and 0->1 transitions are counted except for
+	 *     RI where only 0->1 is counted.
+	 */
+
+static int mxser_get_icount(struct tty_struct *tty,
+		struct serial_icounter_struct *icount)
+
+{
+	struct mxser_port *info = tty->driver_data;
+	struct async_icount cnow;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->slock, flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->slock, flags);
+
+	icount->frame = cnow.frame;
+	icount->brk = cnow.brk;
+	icount->overrun = cnow.overrun;
+	icount->buf_overrun = cnow.buf_overrun;
+	icount->parity = cnow.parity;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	return 0;
+}
+
 static void mxser_stoprx(struct tty_struct *tty)
 {
 	struct mxser_port *info = tty->driver_data;
@@ -2326,6 +2337,7 @@
 	.wait_until_sent = mxser_wait_until_sent,
 	.tiocmget = mxser_tiocmget,
 	.tiocmset = mxser_tiocmset,
+	.get_icount = mxser_get_icount,
 };
 
 struct tty_port_operations mxser_port_ops = {
@@ -2339,20 +2351,11 @@
  * The MOXA Smartio/Industio serial driver boot-time initialization code!
  */
 
-static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
-		unsigned int irq)
+static void mxser_release_ISA_res(struct mxser_board *brd)
 {
-	if (irq)
-		free_irq(brd->irq, brd);
-	if (pdev != NULL) {	/* PCI */
-#ifdef CONFIG_PCI
-		pci_release_region(pdev, 2);
-		pci_release_region(pdev, 3);
-#endif
-	} else {
-		release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
-		release_region(brd->vector, 1);
-	}
+	free_irq(brd->irq, brd);
+	release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+	release_region(brd->vector, 1);
 }
 
 static int __devinit mxser_initbrd(struct mxser_board *brd,
@@ -2397,13 +2400,11 @@
 
 	retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser",
 			brd);
-	if (retval) {
+	if (retval)
 		printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
 			"conflict with another device.\n",
 			brd->info->name, brd->irq);
-		/* We hold resources, we need to release them. */
-		mxser_release_res(brd, pdev, 0);
-	}
+
 	return retval;
 }
 
@@ -2555,7 +2556,7 @@
 	ioaddress = pci_resource_start(pdev, 2);
 	retval = pci_request_region(pdev, 2, "mxser(IO)");
 	if (retval)
-		goto err;
+		goto err_dis;
 
 	brd->info = &mxser_cards[ent->driver_data];
 	for (i = 0; i < brd->info->nports; i++)
@@ -2565,7 +2566,7 @@
 	ioaddress = pci_resource_start(pdev, 3);
 	retval = pci_request_region(pdev, 3, "mxser(vector)");
 	if (retval)
-		goto err_relio;
+		goto err_zero;
 	brd->vector = ioaddress;
 
 	/* irq */
@@ -2608,7 +2609,7 @@
 	/* mxser_initbrd will hook ISR. */
 	retval = mxser_initbrd(brd, pdev);
 	if (retval)
-		goto err_null;
+		goto err_rel3;
 
 	for (i = 0; i < brd->info->nports; i++)
 		tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
@@ -2616,10 +2617,13 @@
 	pci_set_drvdata(pdev, brd);
 
 	return 0;
-err_relio:
-	pci_release_region(pdev, 2);
-err_null:
+err_rel3:
+	pci_release_region(pdev, 3);
+err_zero:
 	brd->info = NULL;
+	pci_release_region(pdev, 2);
+err_dis:
+	pci_disable_device(pdev);
 err:
 	return retval;
 #else
@@ -2629,14 +2633,19 @@
 
 static void __devexit mxser_remove(struct pci_dev *pdev)
 {
+#ifdef CONFIG_PCI
 	struct mxser_board *brd = pci_get_drvdata(pdev);
 	unsigned int i;
 
 	for (i = 0; i < brd->info->nports; i++)
 		tty_unregister_device(mxvar_sdriver, brd->idx + i);
 
-	mxser_release_res(brd, pdev, 1);
+	free_irq(pdev->irq, brd);
+	pci_release_region(pdev, 2);
+	pci_release_region(pdev, 3);
+	pci_disable_device(pdev);
 	brd->info = NULL;
+#endif
 }
 
 static struct pci_driver mxser_driver = {
@@ -2741,7 +2750,7 @@
 
 	for (i = 0; i < MXSER_BOARDS; i++)
 		if (mxser_boards[i].info != NULL)
-			mxser_release_res(&mxser_boards[i], NULL, 1);
+			mxser_release_ISA_res(&mxser_boards[i]);
 }
 
 module_init(mxser_module_init);
diff -druN linux-libre-2.6.36-gnu/drivers/char/n_gsm.c linux-libre-2.6.37-gnu/drivers/char/n_gsm.c
--- linux-libre-2.6.36-gnu/drivers/char/n_gsm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/n_gsm.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,2763 +0,0 @@
-/*
- * n_gsm.c GSM 0710 tty multiplexor
- * Copyright (c) 2009/10 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *	* THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
- *
- * TO DO:
- *	Mostly done:	ioctls for setting modes/timing
- *	Partly done: 	hooks so you can pull off frames to non tty devs
- *	Restart DLCI 0 when it closes ?
- *	Test basic encoding
- *	Improve the tx engine
- *	Resolve tx side locking by adding a queue_head and routing
- *		all control traffic via it
- *	General tidy/document
- *	Review the locking/move to refcounts more (mux now moved to an
- *		alloc/free model ready)
- *	Use newest tty open/close port helpers and install hooks
- *	What to do about power functions ?
- *	Termios setting and negotiation
- *	Do we need a 'which mux are you' ioctl to correlate mux and tty sets
- *
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/tty_flip.h>
-#include <linux/tty_driver.h>
-#include <linux/serial.h>
-#include <linux/kfifo.h>
-#include <linux/skbuff.h>
-#include <linux/gsmmux.h>
-
-static int debug;
-module_param(debug, int, 0600);
-
-#define T1	(HZ/10)
-#define T2	(HZ/3)
-#define N2	3
-
-/* Use long timers for testing at low speed with debug on */
-#ifdef DEBUG_TIMING
-#define T1	HZ
-#define T2	(2 * HZ)
-#endif
-
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
-   limits so this is plenty */
-#define MAX_MRU 512
-#define MAX_MTU 512
-
-/*
- *	Each block of data we have queued to go out is in the form of
- *	a gsm_msg which holds everything we need in a link layer independant
- *	format
- */
-
-struct gsm_msg {
-	struct gsm_msg *next;
-	u8 addr;		/* DLCI address + flags */
-	u8 ctrl;		/* Control byte + flags */
-	unsigned int len;	/* Length of data block (can be zero) */
-	unsigned char *data;	/* Points into buffer but not at the start */
-	unsigned char buffer[0];
-};
-
-/*
- *	Each active data link has a gsm_dlci structure associated which ties
- *	the link layer to an optional tty (if the tty side is open). To avoid
- *	complexity right now these are only ever freed up when the mux is
- *	shut down.
- *
- *	At the moment we don't free DLCI objects until the mux is torn down
- *	this avoid object life time issues but might be worth review later.
- */
-
-struct gsm_dlci {
-	struct gsm_mux *gsm;
-	int addr;
-	int state;
-#define DLCI_CLOSED		0
-#define DLCI_OPENING		1	/* Sending SABM not seen UA */
-#define DLCI_OPEN		2	/* SABM/UA complete */
-#define DLCI_CLOSING		3	/* Sending DISC not seen UA/DM */
-
-	/* Link layer */
-	spinlock_t lock;	/* Protects the internal state */
-	struct timer_list t1;	/* Retransmit timer for SABM and UA */
-	int retries;
-	/* Uplink tty if active */
-	struct tty_port port;	/* The tty bound to this DLCI if there is one */
-	struct kfifo *fifo;	/* Queue fifo for the DLCI */
-	struct kfifo _fifo;	/* For new fifo API porting only */
-	int adaption;		/* Adaption layer in use */
-	u32 modem_rx;		/* Our incoming virtual modem lines */
-	u32 modem_tx;		/* Our outgoing modem lines */
-	int dead;		/* Refuse re-open */
-	/* Flow control */
-	int throttled;		/* Private copy of throttle state */
-	int constipated;	/* Throttle status for outgoing */
-	/* Packetised I/O */
-	struct sk_buff *skb;	/* Frame being sent */
-	struct sk_buff_head skb_list;	/* Queued frames */
-	/* Data handling callback */
-	void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
-};
-
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
-
-#define NUM_DLCI		64
-
-/*
- *	DLCI 0 is used to pass control blocks out of band of the data
- *	flow (and with a higher link priority). One command can be outstanding
- *	at a time and we use this structure to manage them. They are created
- *	and destroyed by the user context, and updated by the receive paths
- *	and timers
- */
-
-struct gsm_control {
-	u8 cmd;		/* Command we are issuing */
-	u8 *data;	/* Data for the command in case we retransmit */
-	int len;	/* Length of block for retransmission */
-	int done;	/* Done flag */
-	int error;	/* Error if any */
-};
-
-/*
- *	Each GSM mux we have is represented by this structure. If we are
- *	operating as an ldisc then we use this structure as our ldisc
- *	state. We need to sort out lifetimes and locking with respect
- *	to the gsm mux array. For now we don't free DLCI objects that
- *	have been instantiated until the mux itself is terminated.
- *
- *	To consider further: tty open versus mux shutdown.
- */
-
-struct gsm_mux {
-	struct tty_struct *tty;		/* The tty our ldisc is bound to */
-	spinlock_t lock;
-
-	/* Events on the GSM channel */
-	wait_queue_head_t event;
-
-	/* Bits for GSM mode decoding */
-
-	/* Framing Layer */
-	unsigned char *buf;
-	int state;
-#define GSM_SEARCH		0
-#define GSM_START		1
-#define GSM_ADDRESS		2
-#define GSM_CONTROL		3
-#define GSM_LEN			4
-#define GSM_DATA		5
-#define GSM_FCS			6
-#define GSM_OVERRUN		7
-	unsigned int len;
-	unsigned int address;
-	unsigned int count;
-	int escape;
-	int encoding;
-	u8 control;
-	u8 fcs;
-	u8 *txframe;			/* TX framing buffer */
-
-	/* Methods for the receiver side */
-	void (*receive)(struct gsm_mux *gsm, u8 ch);
-	void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
-	/* And transmit side */
-	int (*output)(struct gsm_mux *mux, u8 *data, int len);
-
-	/* Link Layer */
-	unsigned int mru;
-	unsigned int mtu;
-	int initiator;			/* Did we initiate connection */
-	int dead;			/* Has the mux been shut down */
-	struct gsm_dlci *dlci[NUM_DLCI];
-	int constipated;		/* Asked by remote to shut up */
-
-	spinlock_t tx_lock;
-	unsigned int tx_bytes;		/* TX data outstanding */
-#define TX_THRESH_HI		8192
-#define TX_THRESH_LO		2048
-	struct gsm_msg *tx_head;	/* Pending data packets */
-	struct gsm_msg *tx_tail;
-
-	/* Control messages */
-	struct timer_list t2_timer;	/* Retransmit timer for commands */
-	int cretries;			/* Command retry counter */
-	struct gsm_control *pending_cmd;/* Our current pending command */
-	spinlock_t control_lock;	/* Protects the pending command */
-
-	/* Configuration */
-	int adaption;		/* 1 or 2 supported */
-	u8 ftype;		/* UI or UIH */
-	int t1, t2;		/* Timers in 1/100th of a sec */
-	int n2;			/* Retry count */
-
-	/* Statistics (not currently exposed) */
-	unsigned long bad_fcs;
-	unsigned long malformed;
-	unsigned long io_error;
-	unsigned long bad_size;
-	unsigned long unsupported;
-};
-
-
-/*
- *	Mux objects - needed so that we can translate a tty index into the
- *	relevant mux and DLCI.
- */
-
-#define MAX_MUX		4			/* 256 minors */
-static struct gsm_mux *gsm_mux[MAX_MUX];	/* GSM muxes */
-static spinlock_t gsm_mux_lock;
-
-/*
- *	This section of the driver logic implements the GSM encodings
- *	both the basic and the 'advanced'. Reliable transport is not
- *	supported.
- */
-
-#define CR			0x02
-#define EA			0x01
-#define	PF			0x10
-
-/* I is special: the rest are ..*/
-#define RR			0x01
-#define UI			0x03
-#define RNR			0x05
-#define REJ			0x09
-#define DM			0x0F
-#define SABM			0x2F
-#define DISC			0x43
-#define UA			0x63
-#define	UIH			0xEF
-
-/* Channel commands */
-#define CMD_NSC			0x09
-#define CMD_TEST		0x11
-#define CMD_PSC			0x21
-#define CMD_RLS			0x29
-#define CMD_FCOFF		0x31
-#define CMD_PN			0x41
-#define CMD_RPN			0x49
-#define CMD_FCON		0x51
-#define CMD_CLD			0x61
-#define CMD_SNC			0x69
-#define CMD_MSC			0x71
-
-/* Virtual modem bits */
-#define MDM_FC			0x01
-#define MDM_RTC			0x02
-#define MDM_RTR			0x04
-#define MDM_IC			0x20
-#define MDM_DV			0x40
-
-#define GSM0_SOF		0xF9
-#define GSM1_SOF 		0x7E
-#define GSM1_ESCAPE		0x7D
-#define GSM1_ESCAPE_BITS	0x20
-#define XON			0x11
-#define XOFF			0x13
-
-static const struct tty_port_operations gsm_port_ops;
-
-/*
- *	CRC table for GSM 0710
- */
-
-static const u8 gsm_fcs8[256] = {
-	0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
-	0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
-	0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
-	0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
-	0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
-	0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
-	0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
-	0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
-	0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
-	0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
-	0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
-	0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
-	0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
-	0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
-	0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
-	0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
-	0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
-	0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
-	0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
-	0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
-	0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
-	0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
-	0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
-	0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
-	0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
-	0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
-	0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
-	0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
-	0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
-	0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
-	0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
-	0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
-};
-
-#define INIT_FCS	0xFF
-#define GOOD_FCS	0xCF
-
-/**
- *	gsm_fcs_add	-	update FCS
- *	@fcs: Current FCS
- *	@c: Next data
- *
- *	Update the FCS to include c. Uses the algorithm in the specification
- *	notes.
- */
-
-static inline u8 gsm_fcs_add(u8 fcs, u8 c)
-{
-	return gsm_fcs8[fcs ^ c];
-}
-
-/**
- *	gsm_fcs_add_block	-	update FCS for a block
- *	@fcs: Current FCS
- *	@c: buffer of data
- *	@len: length of buffer
- *
- *	Update the FCS to include c. Uses the algorithm in the specification
- *	notes.
- */
-
-static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
-{
-	while (len--)
-		fcs = gsm_fcs8[fcs ^ *c++];
-	return fcs;
-}
-
-/**
- *	gsm_read_ea		-	read a byte into an EA
- *	@val: variable holding value
- *	c: byte going into the EA
- *
- *	Processes one byte of an EA. Updates the passed variable
- *	and returns 1 if the EA is now completely read
- */
-
-static int gsm_read_ea(unsigned int *val, u8 c)
-{
-	/* Add the next 7 bits into the value */
-	*val <<= 7;
-	*val |= c >> 1;
-	/* Was this the last byte of the EA 1 = yes*/
-	return c & EA;
-}
-
-/**
- *	gsm_encode_modem	-	encode modem data bits
- *	@dlci: DLCI to encode from
- *
- *	Returns the correct GSM encoded modem status bits (6 bit field) for
- *	the current status of the DLCI and attached tty object
- */
-
-static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
-{
-	u8 modembits = 0;
-	/* FC is true flow control not modem bits */
-	if (dlci->throttled)
-		modembits |= MDM_FC;
-	if (dlci->modem_tx & TIOCM_DTR)
-		modembits |= MDM_RTC;
-	if (dlci->modem_tx & TIOCM_RTS)
-		modembits |= MDM_RTR;
-	if (dlci->modem_tx & TIOCM_RI)
-		modembits |= MDM_IC;
-	if (dlci->modem_tx & TIOCM_CD)
-		modembits |= MDM_DV;
-	return modembits;
-}
-
-/**
- *	gsm_print_packet	-	display a frame for debug
- *	@hdr: header to print before decode
- *	@addr: address EA from the frame
- *	@cr: C/R bit from the frame
- *	@control: control including PF bit
- *	@data: following data bytes
- *	@dlen: length of data
- *
- *	Displays a packet in human readable format for debugging purposes. The
- *	style is based on amateur radio LAP-B dump display.
- */
-
-static void gsm_print_packet(const char *hdr, int addr, int cr,
-					u8 control, const u8 *data, int dlen)
-{
-	if (!(debug & 1))
-		return;
-
-	printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
-
-	switch (control & ~PF) {
-	case SABM:
-		printk(KERN_CONT "SABM");
-		break;
-	case UA:
-		printk(KERN_CONT "UA");
-		break;
-	case DISC:
-		printk(KERN_CONT "DISC");
-		break;
-	case DM:
-		printk(KERN_CONT "DM");
-		break;
-	case UI:
-		printk(KERN_CONT "UI");
-		break;
-	case UIH:
-		printk(KERN_CONT "UIH");
-		break;
-	default:
-		if (!(control & 0x01)) {
-			printk(KERN_CONT "I N(S)%d N(R)%d",
-				(control & 0x0E) >> 1, (control & 0xE)>> 5);
-		} else switch (control & 0x0F) {
-		case RR:
-			printk("RR(%d)", (control & 0xE0) >> 5);
-			break;
-		case RNR:
-			printk("RNR(%d)", (control & 0xE0) >> 5);
-			break;
-		case REJ:
-			printk("REJ(%d)", (control & 0xE0) >> 5);
-			break;
-		default:
-			printk(KERN_CONT "[%02X]", control);
-		}
-	}
-
-	if (control & PF)
-		printk(KERN_CONT "(P)");
-	else
-		printk(KERN_CONT "(F)");
-
-	if (dlen) {
-		int ct = 0;
-		while (dlen--) {
-			if (ct % 8 == 0)
-				printk(KERN_CONT "\n    ");
-			printk(KERN_CONT "%02X ", *data++);
-			ct++;
-		}
-	}
-	printk(KERN_CONT "\n");
-}
-
-
-/*
- *	Link level transmission side
- */
-
-/**
- *	gsm_stuff_packet	-	bytestuff a packet
- *	@ibuf: input
- *	@obuf: output
- *	@len: length of input
- *
- *	Expand a buffer by bytestuffing it. The worst case size change
- *	is doubling and the caller is responsible for handing out
- *	suitable sized buffers.
- */
-
-static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
-{
-	int olen = 0;
-	while (len--) {
-		if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-		    || *input == XON || *input == XOFF) {
-			*output++ = GSM1_ESCAPE;
-			*output++ = *input++ ^ GSM1_ESCAPE_BITS;
-			olen++;
-		} else
-			*output++ = *input++;
-		olen++;
-	}
-	return olen;
-}
-
-static void hex_packet(const unsigned char *p, int len)
-{
-	int i;
-	for (i = 0; i < len; i++) {
-		if (i && (i % 16) == 0)
-			printk("\n");
-		printk("%02X ", *p++);
-	}
-	printk("\n");
-}
-
-/**
- *	gsm_send	-	send a control frame
- *	@gsm: our GSM mux
- *	@addr: address for control frame
- *	@cr: command/response bit
- *	@control:  control byte including PF bit
- *
- *	Format up and transmit a control frame. These do not go via the
- *	queueing logic as they should be transmitted ahead of data when
- *	they are needed.
- *
- *	FIXME: Lock versus data TX path
- */
-
-static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
-{
-	int len;
-	u8 cbuf[10];
-	u8 ibuf[3];
-
-	switch (gsm->encoding) {
-	case 0:
-		cbuf[0] = GSM0_SOF;
-		cbuf[1] = (addr << 2) | (cr << 1) | EA;
-		cbuf[2] = control;
-		cbuf[3] = EA;	/* Length of data = 0 */
-		cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
-		cbuf[5] = GSM0_SOF;
-		len = 6;
-		break;
-	case 1:
-	case 2:
-		/* Control frame + packing (but not frame stuffing) in mode 1 */
-		ibuf[0] = (addr << 2) | (cr << 1) | EA;
-		ibuf[1] = control;
-		ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
-		/* Stuffing may double the size worst case */
-		len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
-		/* Now add the SOF markers */
-		cbuf[0] = GSM1_SOF;
-		cbuf[len + 1] = GSM1_SOF;
-		/* FIXME: we can omit the lead one in many cases */
-		len += 2;
-		break;
-	default:
-		WARN_ON(1);
-		return;
-	}
-	gsm->output(gsm, cbuf, len);
-	gsm_print_packet("-->", addr, cr, control, NULL, 0);
-}
-
-/**
- *	gsm_response	-	send a control response
- *	@gsm: our GSM mux
- *	@addr: address for control frame
- *	@control:  control byte including PF bit
- *
- *	Format up and transmit a link level response frame.
- */
-
-static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
-{
-	gsm_send(gsm, addr, 0, control);
-}
-
-/**
- *	gsm_command	-	send a control command
- *	@gsm: our GSM mux
- *	@addr: address for control frame
- *	@control:  control byte including PF bit
- *
- *	Format up and transmit a link level command frame.
- */
-
-static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
-{
-	gsm_send(gsm, addr, 1, control);
-}
-
-/* Data transmission */
-
-#define HDR_LEN		6	/* ADDR CTRL [LEN.2] DATA FCS */
-
-/**
- *	gsm_data_alloc		-	allocate data frame
- *	@gsm: GSM mux
- *	@addr: DLCI address
- *	@len: length excluding header and FCS
- *	@ctrl: control byte
- *
- *	Allocate a new data buffer for sending frames with data. Space is left
- *	at the front for header bytes but that is treated as an implementation
- *	detail and not for the high level code to use
- */
-
-static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
-								u8 ctrl)
-{
-	struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
-								GFP_ATOMIC);
-	if (m == NULL)
-		return NULL;
-	m->data = m->buffer + HDR_LEN - 1;	/* Allow for FCS */
-	m->len = len;
-	m->addr = addr;
-	m->ctrl = ctrl;
-	m->next = NULL;
-	return m;
-}
-
-/**
- *	gsm_data_kick		-	poke the queue
- *	@gsm: GSM Mux
- *
- *	The tty device has called us to indicate that room has appeared in
- *	the transmit queue. Ram more data into the pipe if we have any
- *
- *	FIXME: lock against link layer control transmissions
- */
-
-static void gsm_data_kick(struct gsm_mux *gsm)
-{
-	struct gsm_msg *msg = gsm->tx_head;
-	int len;
-	int skip_sof = 0;
-
-	/* FIXME: We need to apply this solely to data messages */
-	if (gsm->constipated)
-		return;
-
-	while (gsm->tx_head != NULL) {
-		msg = gsm->tx_head;
-		if (gsm->encoding != 0) {
-			gsm->txframe[0] = GSM1_SOF;
-			len = gsm_stuff_frame(msg->data,
-						gsm->txframe + 1, msg->len);
-			gsm->txframe[len + 1] = GSM1_SOF;
-			len += 2;
-		} else {
-			gsm->txframe[0] = GSM0_SOF;
-			memcpy(gsm->txframe + 1 , msg->data, msg->len);
-			gsm->txframe[msg->len + 1] = GSM0_SOF;
-			len = msg->len + 2;
-		}
-
-		if (debug & 4) {
-			printk("gsm_data_kick: \n");
-			hex_packet(gsm->txframe, len);
-		}
-
-		if (gsm->output(gsm, gsm->txframe + skip_sof,
-						len - skip_sof) < 0)
-			break;
-		/* FIXME: Can eliminate one SOF in many more cases */
-		gsm->tx_head = msg->next;
-		if (gsm->tx_head == NULL)
-			gsm->tx_tail = NULL;
-		gsm->tx_bytes -= msg->len;
-		kfree(msg);
-		/* For a burst of frames skip the extra SOF within the
-		   burst */
-		skip_sof = 1;
-	}
-}
-
-/**
- *	__gsm_data_queue		-	queue a UI or UIH frame
- *	@dlci: DLCI sending the data
- *	@msg: message queued
- *
- *	Add data to the transmit queue and try and get stuff moving
- *	out of the mux tty if not already doing so. The Caller must hold
- *	the gsm tx lock.
- */
-
-static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-	struct gsm_mux *gsm = dlci->gsm;
-	u8 *dp = msg->data;
-	u8 *fcs = dp + msg->len;
-
-	/* Fill in the header */
-	if (gsm->encoding == 0) {
-		if (msg->len < 128)
-			*--dp = (msg->len << 1) | EA;
-		else {
-			*--dp = (msg->len >> 6) | EA;
-			*--dp = (msg->len & 127) << 1;
-		}
-	}
-
-	*--dp = msg->ctrl;
-	if (gsm->initiator)
-		*--dp = (msg->addr << 2) | 2 | EA;
-	else
-		*--dp = (msg->addr << 2) | EA;
-	*fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
-	/* Ugly protocol layering violation */
-	if (msg->ctrl == UI || msg->ctrl == (UI|PF))
-		*fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
-	*fcs = 0xFF - *fcs;
-
-	gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
-							msg->data, msg->len);
-
-	/* Move the header back and adjust the length, also allow for the FCS
-	   now tacked on the end */
-	msg->len += (msg->data - dp) + 1;
-	msg->data = dp;
-
-	/* Add to the actual output queue */
-	if (gsm->tx_tail)
-		gsm->tx_tail->next = msg;
-	else
-		gsm->tx_head = msg;
-	gsm->tx_tail = msg;
-	gsm->tx_bytes += msg->len;
-	gsm_data_kick(gsm);
-}
-
-/**
- *	gsm_data_queue		-	queue a UI or UIH frame
- *	@dlci: DLCI sending the data
- *	@msg: message queued
- *
- *	Add data to the transmit queue and try and get stuff moving
- *	out of the mux tty if not already doing so. Take the
- *	the gsm tx lock and dlci lock.
- */
-
-static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-	__gsm_data_queue(dlci, msg);
-	spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/**
- *	gsm_dlci_data_output	-	try and push data out of a DLCI
- *	@gsm: mux
- *	@dlci: the DLCI to pull data from
- *
- *	Pull data from a DLCI and send it into the transmit queue if there
- *	is data. Keep to the MRU of the mux. This path handles the usual tty
- *	interface which is a byte stream with optional modem data.
- *
- *	Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
-{
-	struct gsm_msg *msg;
-	u8 *dp;
-	int len, size;
-	int h = dlci->adaption - 1;
-
-	len = kfifo_len(dlci->fifo);
-	if (len == 0)
-		return 0;
-
-	/* MTU/MRU count only the data bits */
-	if (len > gsm->mtu)
-		len = gsm->mtu;
-
-	size = len + h;
-
-	msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-	/* FIXME: need a timer or something to kick this so it can't
-	   get stuck with no work outstanding and no buffer free */
-	if (msg == NULL)
-		return -ENOMEM;
-	dp = msg->data;
-	switch (dlci->adaption) {
-	case 1:	/* Unstructured */
-		break;
-	case 2:	/* Unstructed with modem bits. Always one byte as we never
-		   send inline break data */
-		*dp += gsm_encode_modem(dlci);
-		len--;
-		break;
-	}
-	WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
-	__gsm_data_queue(dlci, msg);
-	/* Bytes of data we used up */
-	return size;
-}
-
-/**
- *	gsm_dlci_data_output_framed  -	try and push data out of a DLCI
- *	@gsm: mux
- *	@dlci: the DLCI to pull data from
- *
- *	Pull data from a DLCI and send it into the transmit queue if there
- *	is data. Keep to the MRU of the mux. This path handles framed data
- *	queued as skbuffs to the DLCI.
- *
- *	Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
-						struct gsm_dlci *dlci)
-{
-	struct gsm_msg *msg;
-	u8 *dp;
-	int len, size;
-	int last = 0, first = 0;
-	int overhead = 0;
-
-	/* One byte per frame is used for B/F flags */
-	if (dlci->adaption == 4)
-		overhead = 1;
-
-	/* dlci->skb is locked by tx_lock */
-	if (dlci->skb == NULL) {
-		dlci->skb = skb_dequeue(&dlci->skb_list);
-		if (dlci->skb == NULL)
-			return 0;
-		first = 1;
-	}
-	len = dlci->skb->len + overhead;
-
-	/* MTU/MRU count only the data bits */
-	if (len > gsm->mtu) {
-		if (dlci->adaption == 3) {
-			/* Over long frame, bin it */
-			kfree_skb(dlci->skb);
-			dlci->skb = NULL;
-			return 0;
-		}
-		len = gsm->mtu;
-	} else
-		last = 1;
-
-	size = len + overhead;
-	msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-
-	/* FIXME: need a timer or something to kick this so it can't
-	   get stuck with no work outstanding and no buffer free */
-	if (msg == NULL)
-		return -ENOMEM;
-	dp = msg->data;
-
-	if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
-		/* Flag byte to carry the start/end info */
-		*dp++ = last << 7 | first << 6 | 1;	/* EA */
-		len--;
-	}
-	memcpy(dp, skb_pull(dlci->skb, len), len);
-	__gsm_data_queue(dlci, msg);
-	if (last)
-		dlci->skb = NULL;
-	return size;
-}
-
-/**
- *	gsm_dlci_data_sweep		-	look for data to send
- *	@gsm: the GSM mux
- *
- *	Sweep the GSM mux channels in priority order looking for ones with
- *	data to send. We could do with optimising this scan a bit. We aim
- *	to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
- *	TX_THRESH_LO we get called again
- *
- *	FIXME: We should round robin between groups and in theory you can
- *	renegotiate DLCI priorities with optional stuff. Needs optimising.
- */
-
-static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
-{
-	int len;
-	/* Priority ordering: We should do priority with RR of the groups */
-	int i = 1;
-
-	while (i < NUM_DLCI) {
-		struct gsm_dlci *dlci;
-
-		if (gsm->tx_bytes > TX_THRESH_HI)
-			break;
-		dlci = gsm->dlci[i];
-		if (dlci == NULL || dlci->constipated) {
-			i++;
-			continue;
-		}
-		if (dlci->adaption < 3)
-			len = gsm_dlci_data_output(gsm, dlci);
-		else
-			len = gsm_dlci_data_output_framed(gsm, dlci);
-		if (len < 0)
-			break;
-		/* DLCI empty - try the next */
-		if (len == 0)
-			i++;
-	}
-}
-
-/**
- *	gsm_dlci_data_kick	-	transmit if possible
- *	@dlci: DLCI to kick
- *
- *	Transmit data from this DLCI if the queue is empty. We can't rely on
- *	a tty wakeup except when we filled the pipe so we need to fire off
- *	new data ourselves in other cases.
- */
-
-static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-	/* If we have nothing running then we need to fire up */
-	if (dlci->gsm->tx_bytes == 0)
-		gsm_dlci_data_output(dlci->gsm, dlci);
-	else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
-		gsm_dlci_data_sweep(dlci->gsm);
-	spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/*
- *	Control message processing
- */
-
-
-/**
- *	gsm_control_reply	-	send a response frame to a control
- *	@gsm: gsm channel
- *	@cmd: the command to use
- *	@data: data to follow encoded info
- *	@dlen: length of data
- *
- *	Encode up and queue a UI/UIH frame containing our response.
- */
-
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
-					int dlen)
-{
-	struct gsm_msg *msg;
-	msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
-	msg->data[0] = (cmd & 0xFE) << 1 | EA;	/* Clear C/R */
-	msg->data[1] = (dlen << 1) | EA;
-	memcpy(msg->data + 2, data, dlen);
-	gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *	gsm_process_modem	-	process received modem status
- *	@tty: virtual tty bound to the DLCI
- *	@dlci: DLCI to affect
- *	@modem: modem bits (full EA)
- *
- *	Used when a modem control message or line state inline in adaption
- *	layer 2 is processed. Sort out the local modem state and throttles
- */
-
-static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
-							u32 modem)
-{
-	int  mlines = 0;
-	u8 brk = modem >> 6;
-
-	/* Flow control/ready to communicate */
-	if (modem & MDM_FC) {
-		/* Need to throttle our output on this device */
-		dlci->constipated = 1;
-	}
-	if (modem & MDM_RTC) {
-		mlines |= TIOCM_DSR | TIOCM_DTR;
-		dlci->constipated = 0;
-		gsm_dlci_data_kick(dlci);
-	}
-	/* Map modem bits */
-	if (modem & MDM_RTR)
-		mlines |= TIOCM_RTS | TIOCM_CTS;
-	if (modem & MDM_IC)
-		mlines |= TIOCM_RI;
-	if (modem & MDM_DV)
-		mlines |= TIOCM_CD;
-
-	/* Carrier drop -> hangup */
-	if (tty) {
-		if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
-			if (!(tty->termios->c_cflag & CLOCAL))
-				tty_hangup(tty);
-		if (brk & 0x01)
-			tty_insert_flip_char(tty, 0, TTY_BREAK);
-	}
-	dlci->modem_rx = mlines;
-}
-
-/**
- *	gsm_control_modem	-	modem status received
- *	@gsm: GSM channel
- *	@data: data following command
- *	@clen: command length
- *
- *	We have received a modem status control message. This is used by
- *	the GSM mux protocol to pass virtual modem line status and optionally
- *	to indicate break signals. Unpack it, convert to Linux representation
- *	and if need be stuff a break message down the tty.
- */
-
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
-{
-	unsigned int addr = 0;
-	unsigned int modem = 0;
-	struct gsm_dlci *dlci;
-	int len = clen;
-	u8 *dp = data;
-	struct tty_struct *tty;
-
-	while (gsm_read_ea(&addr, *dp++) == 0) {
-		len--;
-		if (len == 0)
-			return;
-	}
-	/* Must be at least one byte following the EA */
-	len--;
-	if (len <= 0)
-		return;
-
-	addr >>= 1;
-	/* Closed port, or invalid ? */
-	if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-		return;
-	dlci = gsm->dlci[addr];
-
-	while (gsm_read_ea(&modem, *dp++) == 0) {
-		len--;
-		if (len == 0)
-			return;
-	}
-	tty = tty_port_tty_get(&dlci->port);
-	gsm_process_modem(tty, dlci, modem);
-	if (tty) {
-		tty_wakeup(tty);
-		tty_kref_put(tty);
-	}
-	gsm_control_reply(gsm, CMD_MSC, data, clen);
-}
-
-/**
- *	gsm_control_rls		-	remote line status
- *	@gsm: GSM channel
- *	@data: data bytes
- *	@clen: data length
- *
- *	The modem sends us a two byte message on the control channel whenever
- *	it wishes to send us an error state from the virtual link. Stuff
- *	this into the uplink tty if present
- */
-
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
-{
-	struct tty_struct *tty;
-	unsigned int addr = 0 ;
-	u8 bits;
-	int len = clen;
-	u8 *dp = data;
-
-	while (gsm_read_ea(&addr, *dp++) == 0) {
-		len--;
-		if (len == 0)
-			return;
-	}
-	/* Must be at least one byte following ea */
-	len--;
-	if (len <= 0)
-		return;
-	addr >>= 1;
-	/* Closed port, or invalid ? */
-	if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-		return;
-	/* No error ? */
-	bits = *dp;
-	if ((bits & 1) == 0)
-		return;
-	/* See if we have an uplink tty */
-	tty = tty_port_tty_get(&gsm->dlci[addr]->port);
-
-	if (tty) {
-		if (bits & 2)
-			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-		if (bits & 4)
-			tty_insert_flip_char(tty, 0, TTY_PARITY);
-		if (bits & 8)
-			tty_insert_flip_char(tty, 0, TTY_FRAME);
-		tty_flip_buffer_push(tty);
-		tty_kref_put(tty);
-	}
-	gsm_control_reply(gsm, CMD_RLS, data, clen);
-}
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
-
-/**
- *	gsm_control_message	-	DLCI 0 control processing
- *	@gsm: our GSM mux
- *	@command:  the command EA
- *	@data: data beyond the command/length EAs
- *	@clen: length
- *
- *	Input processor for control messages from the other end of the link.
- *	Processes the incoming request and queues a response frame or an
- *	NSC response if not supported
- */
-
-static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
-							u8 *data, int clen)
-{
-	u8 buf[1];
-	switch (command) {
-	case CMD_CLD: {
-		struct gsm_dlci *dlci = gsm->dlci[0];
-		/* Modem wishes to close down */
-		if (dlci) {
-			dlci->dead = 1;
-			gsm->dead = 1;
-			gsm_dlci_begin_close(dlci);
-		}
-		}
-		break;
-	case CMD_TEST:
-		/* Modem wishes to test, reply with the data */
-		gsm_control_reply(gsm, CMD_TEST, data, clen);
-		break;
-	case CMD_FCON:
-		/* Modem wants us to STFU */
-		gsm->constipated = 1;
-		gsm_control_reply(gsm, CMD_FCON, NULL, 0);
-		break;
-	case CMD_FCOFF:
-		/* Modem can accept data again */
-		gsm->constipated = 0;
-		gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
-		/* Kick the link in case it is idling */
-		gsm_data_kick(gsm);
-		break;
-	case CMD_MSC:
-		/* Out of band modem line change indicator for a DLCI */
-		gsm_control_modem(gsm, data, clen);
-		break;
-	case CMD_RLS:
-		/* Out of band error reception for a DLCI */
-		gsm_control_rls(gsm, data, clen);
-		break;
-	case CMD_PSC:
-		/* Modem wishes to enter power saving state */
-		gsm_control_reply(gsm, CMD_PSC, NULL, 0);
-		break;
-		/* Optional unsupported commands */
-	case CMD_PN:	/* Parameter negotiation */
-	case CMD_RPN:	/* Remote port negotation */
-	case CMD_SNC:	/* Service negotation command */
-	default:
-		/* Reply to bad commands with an NSC */
-		buf[0] = command;
-		gsm_control_reply(gsm, CMD_NSC, buf, 1);
-		break;
-	}
-}
-
-/**
- *	gsm_control_response	-	process a response to our control
- *	@gsm: our GSM mux
- *	@command: the command (response) EA
- *	@data: data beyond the command/length EA
- *	@clen: length
- *
- *	Process a response to an outstanding command. We only allow a single
- *	control message in flight so this is fairly easy. All the clean up
- *	is done by the caller, we just update the fields, flag it as done
- *	and return
- */
-
-static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
-							u8 *data, int clen)
-{
-	struct gsm_control *ctrl;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gsm->control_lock, flags);
-
-	ctrl = gsm->pending_cmd;
-	/* Does the reply match our command */
-	command |= 1;
-	if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
-		/* Our command was replied to, kill the retry timer */
-		del_timer(&gsm->t2_timer);
-		gsm->pending_cmd = NULL;
-		/* Rejected by the other end */
-		if (command == CMD_NSC)
-			ctrl->error = -EOPNOTSUPP;
-		ctrl->done = 1;
-		wake_up(&gsm->event);
-	}
-	spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *	gsm_control_transmit 	-	send control packet
- *	@gsm: gsm mux
- *	@ctrl: frame to send
- *
- *	Send out a pending control command (called under control lock)
- */
-
-static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
-{
-	struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
-							gsm->ftype|PF);
-	if (msg == NULL)
-		return;
-	msg->data[0] = (ctrl->cmd << 1) | 2 | EA;	/* command */
-	memcpy(msg->data + 1, ctrl->data, ctrl->len);
-	gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *	gsm_control_retransmit	-	retransmit a control frame
- *	@data: pointer to our gsm object
- *
- *	Called off the T2 timer expiry in order to retransmit control frames
- *	that have been lost in the system somewhere. The control_lock protects
- *	us from colliding with another sender or a receive completion event.
- *	In that situation the timer may still occur in a small window but
- *	gsm->pending_cmd will be NULL and we just let the timer expire.
- */
-
-static void gsm_control_retransmit(unsigned long data)
-{
-	struct gsm_mux *gsm = (struct gsm_mux *)data;
-	struct gsm_control *ctrl;
-	unsigned long flags;
-	spin_lock_irqsave(&gsm->control_lock, flags);
-	ctrl = gsm->pending_cmd;
-	if (ctrl) {
-		gsm->cretries--;
-		if (gsm->cretries == 0) {
-			gsm->pending_cmd = NULL;
-			ctrl->error = -ETIMEDOUT;
-			ctrl->done = 1;
-			spin_unlock_irqrestore(&gsm->control_lock, flags);
-			wake_up(&gsm->event);
-			return;
-		}
-		gsm_control_transmit(gsm, ctrl);
-		mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-	}
-	spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *	gsm_control_send	-	send a control frame on DLCI 0
- *	@gsm: the GSM channel
- *	@command: command  to send including CR bit
- *	@data: bytes of data (must be kmalloced)
- *	@len: length of the block to send
- *
- *	Queue and dispatch a control command. Only one command can be
- *	active at a time. In theory more can be outstanding but the matching
- *	gets really complicated so for now stick to one outstanding.
- */
-
-static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
-		unsigned int command, u8 *data, int clen)
-{
-	struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
-						GFP_KERNEL);
-	unsigned long flags;
-	if (ctrl == NULL)
-		return NULL;
-retry:
-	wait_event(gsm->event, gsm->pending_cmd == NULL);
-	spin_lock_irqsave(&gsm->control_lock, flags);
-	if (gsm->pending_cmd != NULL) {
-		spin_unlock_irqrestore(&gsm->control_lock, flags);
-		goto retry;
-	}
-	ctrl->cmd = command;
-	ctrl->data = data;
-	ctrl->len = clen;
-	gsm->pending_cmd = ctrl;
-	gsm->cretries = gsm->n2;
-	mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-	gsm_control_transmit(gsm, ctrl);
-	spin_unlock_irqrestore(&gsm->control_lock, flags);
-	return ctrl;
-}
-
-/**
- *	gsm_control_wait	-	wait for a control to finish
- *	@gsm: GSM mux
- *	@control: control we are waiting on
- *
- *	Waits for the control to complete or time out. Frees any used
- *	resources and returns 0 for success, or an error if the remote
- *	rejected or ignored the request.
- */
-
-static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
-{
-	int err;
-	wait_event(gsm->event, control->done == 1);
-	err = control->error;
-	kfree(control);
-	return err;
-}
-
-
-/*
- *	DLCI level handling: Needs krefs
- */
-
-/*
- *	State transitions and timers
- */
-
-/**
- *	gsm_dlci_close		-	a DLCI has closed
- *	@dlci: DLCI that closed
- *
- *	Perform processing when moving a DLCI into closed state. If there
- *	is an attached tty this is hung up
- */
-
-static void gsm_dlci_close(struct gsm_dlci *dlci)
-{
-	del_timer(&dlci->t1);
-	if (debug & 8)
-		printk("DLCI %d goes closed.\n", dlci->addr);
-	dlci->state = DLCI_CLOSED;
-	if (dlci->addr != 0) {
-		struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
-		if (tty) {
-			tty_hangup(tty);
-			tty_kref_put(tty);
-		}
-		kfifo_reset(dlci->fifo);
-	} else
-		dlci->gsm->dead = 1;
-	wake_up(&dlci->gsm->event);
-	/* A DLCI 0 close is a MUX termination so we need to kick that
-	   back to userspace somehow */
-}
-
-/**
- *	gsm_dlci_open		-	a DLCI has opened
- *	@dlci: DLCI that opened
- *
- *	Perform processing when moving a DLCI into open state.
- */
-
-static void gsm_dlci_open(struct gsm_dlci *dlci)
-{
-	/* Note that SABM UA .. SABM UA first UA lost can mean that we go
-	   open -> open */
-	del_timer(&dlci->t1);
-	/* This will let a tty open continue */
-	dlci->state = DLCI_OPEN;
-	if (debug & 8)
-		printk("DLCI %d goes open.\n", dlci->addr);
-	wake_up(&dlci->gsm->event);
-}
-
-/**
- *	gsm_dlci_t1		-	T1 timer expiry
- *	@dlci: DLCI that opened
- *
- *	The T1 timer handles retransmits of control frames (essentially of
- *	SABM and DISC). We resend the command until the retry count runs out
- *	in which case an opening port goes back to closed and a closing port
- *	is simply put into closed state (any further frames from the other
- *	end will get a DM response)
- */
-
-static void gsm_dlci_t1(unsigned long data)
-{
-	struct gsm_dlci *dlci = (struct gsm_dlci *)data;
-	struct gsm_mux *gsm = dlci->gsm;
-
-	switch (dlci->state) {
-	case DLCI_OPENING:
-		dlci->retries--;
-		if (dlci->retries) {
-			gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-			mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-		} else
-			gsm_dlci_close(dlci);
-		break;
-	case DLCI_CLOSING:
-		dlci->retries--;
-		if (dlci->retries) {
-			gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-			mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-		} else
-			gsm_dlci_close(dlci);
-		break;
-	}
-}
-
-/**
- *	gsm_dlci_begin_open	-	start channel open procedure
- *	@dlci: DLCI to open
- *
- *	Commence opening a DLCI from the Linux side. We issue SABM messages
- *	to the modem which should then reply with a UA, at which point we
- *	will move into open state. Opening is done asynchronously with retry
- *	running off timers and the responses.
- */
-
-static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
-{
-	struct gsm_mux *gsm = dlci->gsm;
-	if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
-		return;
-	dlci->retries = gsm->n2;
-	dlci->state = DLCI_OPENING;
-	gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-	mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *	gsm_dlci_begin_close	-	start channel open procedure
- *	@dlci: DLCI to open
- *
- *	Commence closing a DLCI from the Linux side. We issue DISC messages
- *	to the modem which should then reply with a UA, at which point we
- *	will move into closed state. Closing is done asynchronously with retry
- *	off timers. We may also receive a DM reply from the other end which
- *	indicates the channel was already closed.
- */
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
-{
-	struct gsm_mux *gsm = dlci->gsm;
-	if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
-		return;
-	dlci->retries = gsm->n2;
-	dlci->state = DLCI_CLOSING;
-	gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-	mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *	gsm_dlci_data		-	data arrived
- *	@dlci: channel
- *	@data: block of bytes received
- *	@len: length of received block
- *
- *	A UI or UIH frame has arrived which contains data for a channel
- *	other than the control channel. If the relevant virtual tty is
- *	open we shovel the bits down it, if not we drop them.
- */
-
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
-{
-	/* krefs .. */
-	struct tty_port *port = &dlci->port;
-	struct tty_struct *tty = tty_port_tty_get(port);
-	unsigned int modem = 0;
-
-	if (debug & 16)
-		printk("%d bytes for tty %p\n", len, tty);
-	if (tty) {
-		switch (dlci->adaption)  {
-			/* Unsupported types */
-			/* Packetised interruptible data */
-			case 4:
-				break;
-			/* Packetised uininterruptible voice/data */
-			case 3:
-				break;
-			/* Asynchronous serial with line state in each frame */
-			case 2:
-				while (gsm_read_ea(&modem, *data++) == 0) {
-					len--;
-					if (len == 0)
-						return;
-				}
-				gsm_process_modem(tty, dlci, modem);
-			/* Line state will go via DLCI 0 controls only */
-			case 1:
-			default:
-				tty_insert_flip_string(tty, data, len);
-				tty_flip_buffer_push(tty);
-		}
-		tty_kref_put(tty);
-	}
-}
-
-/**
- *	gsm_dlci_control	-	data arrived on control channel
- *	@dlci: channel
- *	@data: block of bytes received
- *	@len: length of received block
- *
- *	A UI or UIH frame has arrived which contains data for DLCI 0 the
- *	control channel. This should contain a command EA followed by
- *	control data bytes. The command EA contains a command/response bit
- *	and we divide up the work accordingly.
- */
-
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
-{
-	/* See what command is involved */
-	unsigned int command = 0;
-	while (len-- > 0) {
-		if (gsm_read_ea(&command, *data++) == 1) {
-			int clen = *data++;
-			len--;
-			/* FIXME: this is properly an EA */
-			clen >>= 1;
-			/* Malformed command ? */
-			if (clen > len)
-				return;
-			if (command & 1)
-				gsm_control_message(dlci->gsm, command,
-								data, clen);
-			else
-				gsm_control_response(dlci->gsm, command,
-								data, clen);
-			return;
-		}
-	}
-}
-
-/*
- *	Allocate/Free DLCI channels
- */
-
-/**
- *	gsm_dlci_alloc		-	allocate a DLCI
- *	@gsm: GSM mux
- *	@addr: address of the DLCI
- *
- *	Allocate and install a new DLCI object into the GSM mux.
- *
- *	FIXME: review locking races
- */
-
-static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
-{
-	struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
-	if (dlci == NULL)
-		return NULL;
-	spin_lock_init(&dlci->lock);
-	dlci->fifo = &dlci->_fifo;
-	if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
-		kfree(dlci);
-		return NULL;
-	}
-
-	skb_queue_head_init(&dlci->skb_list);
-	init_timer(&dlci->t1);
-	dlci->t1.function = gsm_dlci_t1;
-	dlci->t1.data = (unsigned long)dlci;
-	tty_port_init(&dlci->port);
-	dlci->port.ops = &gsm_port_ops;
-	dlci->gsm = gsm;
-	dlci->addr = addr;
-	dlci->adaption = gsm->adaption;
-	dlci->state = DLCI_CLOSED;
-	if (addr)
-		dlci->data = gsm_dlci_data;
-	else
-		dlci->data = gsm_dlci_command;
-	gsm->dlci[addr] = dlci;
-	return dlci;
-}
-
-/**
- *	gsm_dlci_free		-	release DLCI
- *	@dlci: DLCI to destroy
- *
- *	Free up a DLCI. Currently to keep the lifetime rules sane we only
- *	clean up DLCI objects when the MUX closes rather than as the port
- *	is closed down on both the tty and mux levels.
- *
- *	Can sleep.
- */
-static void gsm_dlci_free(struct gsm_dlci *dlci)
-{
-	struct tty_struct *tty = tty_port_tty_get(&dlci->port);
-	if (tty) {
-		tty_vhangup(tty);
-		tty_kref_put(tty);
-	}
-	del_timer_sync(&dlci->t1);
-	dlci->gsm->dlci[dlci->addr] = NULL;
-	kfifo_free(dlci->fifo);
-	kfree(dlci);
-}
-
-
-/*
- *	LAPBish link layer logic
- */
-
-/**
- *	gsm_queue		-	a GSM frame is ready to process
- *	@gsm: pointer to our gsm mux
- *
- *	At this point in time a frame has arrived and been demangled from
- *	the line encoding. All the differences between the encodings have
- *	been handled below us and the frame is unpacked into the structures.
- *	The fcs holds the header FCS but any data FCS must be added here.
- */
-
-static void gsm_queue(struct gsm_mux *gsm)
-{
-	struct gsm_dlci *dlci;
-	u8 cr;
-	int address;
-	/* We have to sneak a look at the packet body to do the FCS.
-	   A somewhat layering violation in the spec */
-
-	if ((gsm->control & ~PF) == UI)
-		gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-	if (gsm->fcs != GOOD_FCS) {
-		gsm->bad_fcs++;
-		if (debug & 4)
-			printk("BAD FCS %02x\n", gsm->fcs);
-		return;
-	}
-	address = gsm->address >> 1;
-	if (address >= NUM_DLCI)
-		goto invalid;
-
-	cr = gsm->address & 1;		/* C/R bit */
-
-	gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
-
-	cr ^= 1 - gsm->initiator;	/* Flip so 1 always means command */
-	dlci = gsm->dlci[address];
-
-	switch (gsm->control) {
-	case SABM|PF:
-		if (cr == 0)
-			goto invalid;
-		if (dlci == NULL)
-			dlci = gsm_dlci_alloc(gsm, address);
-		if (dlci == NULL)
-			return;
-		if (dlci->dead)
-			gsm_response(gsm, address, DM);
-		else {
-			gsm_response(gsm, address, UA);
-			gsm_dlci_open(dlci);
-		}
-		break;
-	case DISC|PF:
-		if (cr == 0)
-			goto invalid;
-		if (dlci == NULL || dlci->state == DLCI_CLOSED) {
-			gsm_response(gsm, address, DM);
-			return;
-		}
-		/* Real close complete */
-		gsm_response(gsm, address, UA);
-		gsm_dlci_close(dlci);
-		break;
-	case UA:
-	case UA|PF:
-		if (cr == 0 || dlci == NULL)
-			break;
-		switch (dlci->state) {
-		case DLCI_CLOSING:
-			gsm_dlci_close(dlci);
-			break;
-		case DLCI_OPENING:
-			gsm_dlci_open(dlci);
-			break;
-		}
-		break;
-	case DM:	/* DM can be valid unsolicited */
-	case DM|PF:
-		if (cr)
-			goto invalid;
-		if (dlci == NULL)
-			return;
-		gsm_dlci_close(dlci);
-		break;
-	case UI:
-	case UI|PF:
-	case UIH:
-	case UIH|PF:
-#if 0
-		if (cr)
-			goto invalid;
-#endif
-		if (dlci == NULL || dlci->state != DLCI_OPEN) {
-			gsm_command(gsm, address, DM|PF);
-			return;
-		}
-		dlci->data(dlci, gsm->buf, gsm->len);
-		break;
-	default:
-		goto invalid;
-	}
-	return;
-invalid:
-	gsm->malformed++;
-	return;
-}
-
-
-/**
- *	gsm0_receive	-	perform processing for non-transparency
- *	@gsm: gsm data for this ldisc instance
- *	@c: character
- *
- *	Receive bytes in gsm mode 0
- */
-
-static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
-{
-	switch (gsm->state) {
-	case GSM_SEARCH:	/* SOF marker */
-		if (c == GSM0_SOF) {
-			gsm->state = GSM_ADDRESS;
-			gsm->address = 0;
-			gsm->len = 0;
-			gsm->fcs = INIT_FCS;
-		}
-		break;		/* Address EA */
-	case GSM_ADDRESS:
-		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-		if (gsm_read_ea(&gsm->address, c))
-			gsm->state = GSM_CONTROL;
-		break;
-	case GSM_CONTROL:	/* Control Byte */
-		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-		gsm->control = c;
-		gsm->state = GSM_LEN;
-		break;
-	case GSM_LEN:		/* Length EA */
-		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-		if (gsm_read_ea(&gsm->len, c)) {
-			if (gsm->len > gsm->mru) {
-				gsm->bad_size++;
-				gsm->state = GSM_SEARCH;
-				break;
-			}
-			gsm->count = 0;
-			gsm->state = GSM_DATA;
-		}
-		break;
-	case GSM_DATA:		/* Data */
-		gsm->buf[gsm->count++] = c;
-		if (gsm->count == gsm->len)
-			gsm->state = GSM_FCS;
-		break;
-	case GSM_FCS:		/* FCS follows the packet */
-		gsm->fcs = c;
-		gsm_queue(gsm);
-		/* And then back for the next frame */
-		gsm->state = GSM_SEARCH;
-		break;
-	}
-}
-
-/**
- *	gsm0_receive	-	perform processing for non-transparency
- *	@gsm: gsm data for this ldisc instance
- *	@c: character
- *
- *	Receive bytes in mode 1 (Advanced option)
- */
-
-static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
-{
-	if (c == GSM1_SOF) {
-		/* EOF is only valid in frame if we have got to the data state
-		   and received at least one byte (the FCS) */
-		if (gsm->state == GSM_DATA && gsm->count) {
-			/* Extract the FCS */
-			gsm->count--;
-			gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
-			gsm->len = gsm->count;
-			gsm_queue(gsm);
-			gsm->state  = GSM_START;
-			return;
-		}
-		/* Any partial frame was a runt so go back to start */
-		if (gsm->state != GSM_START) {
-			gsm->malformed++;
-			gsm->state = GSM_START;
-		}
-		/* A SOF in GSM_START means we are still reading idling or
-		   framing bytes */
-		return;
-	}
-
-	if (c == GSM1_ESCAPE) {
-		gsm->escape = 1;
-		return;
-	}
-
-	/* Only an unescaped SOF gets us out of GSM search */
-	if (gsm->state == GSM_SEARCH)
-		return;
-
-	if (gsm->escape) {
-		c ^= GSM1_ESCAPE_BITS;
-		gsm->escape = 0;
-	}
-	switch (gsm->state) {
-	case GSM_START:		/* First byte after SOF */
-		gsm->address = 0;
-		gsm->state = GSM_ADDRESS;
-		gsm->fcs = INIT_FCS;
-		/* Drop through */
-	case GSM_ADDRESS:	/* Address continuation */
-		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-		if (gsm_read_ea(&gsm->address, c))
-			gsm->state = GSM_CONTROL;
-		break;
-	case GSM_CONTROL:	/* Control Byte */
-		gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-		gsm->control = c;
-		gsm->count = 0;
-		gsm->state = GSM_DATA;
-		break;
-	case GSM_DATA:		/* Data */
-		if (gsm->count > gsm->mru ) {	/* Allow one for the FCS */
-			gsm->state = GSM_OVERRUN;
-			gsm->bad_size++;
-		} else
-			gsm->buf[gsm->count++] = c;
-		break;
-	case GSM_OVERRUN:	/* Over-long - eg a dropped SOF */
-		break;
-	}
-}
-
-/**
- *	gsm_error		-	handle tty error
- *	@gsm: ldisc data
- *	@data: byte received (may be invalid)
- *	@flag: error received
- *
- *	Handle an error in the receipt of data for a frame. Currently we just
- *	go back to hunting for a SOF.
- *
- *	FIXME: better diagnostics ?
- */
-
-static void gsm_error(struct gsm_mux *gsm,
-				unsigned char data, unsigned char flag)
-{
-	gsm->state = GSM_SEARCH;
-	gsm->io_error++;
-}
-
-/**
- *	gsm_cleanup_mux		-	generic GSM protocol cleanup
- *	@gsm: our mux
- *
- *	Clean up the bits of the mux which are the same for all framing
- *	protocols. Remove the mux from the mux table, stop all the timers
- *	and then shut down each device hanging up the channels as we go.
- */
-
-void gsm_cleanup_mux(struct gsm_mux *gsm)
-{
-	int i;
-	struct gsm_dlci *dlci = gsm->dlci[0];
-	struct gsm_msg *txq;
-
-	gsm->dead = 1;
-
-	spin_lock(&gsm_mux_lock);
-	for (i = 0; i < MAX_MUX; i++) {
-		if (gsm_mux[i] == gsm) {
-			gsm_mux[i] = NULL;
-			break;
-		}
-	}
-	spin_unlock(&gsm_mux_lock);
-	WARN_ON(i == MAX_MUX);
-
-	del_timer_sync(&gsm->t2_timer);
-	/* Now we are sure T2 has stopped */
-	if (dlci) {
-		dlci->dead = 1;
-		gsm_dlci_begin_close(dlci);
-		wait_event_interruptible(gsm->event,
-					dlci->state == DLCI_CLOSED);
-	}
-	/* Free up any link layer users */
-	for (i = 0; i < NUM_DLCI; i++)
-		if (gsm->dlci[i])
-			gsm_dlci_free(gsm->dlci[i]);
-	/* Now wipe the queues */
-	for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
-		gsm->tx_head = txq->next;
-		kfree(txq);
-	}
-	gsm->tx_tail = NULL;
-}
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
-
-/**
- *	gsm_activate_mux	-	generic GSM setup
- *	@gsm: our mux
- *
- *	Set up the bits of the mux which are the same for all framing
- *	protocols. Add the mux to the mux table so it can be opened and
- *	finally kick off connecting to DLCI 0 on the modem.
- */
-
-int gsm_activate_mux(struct gsm_mux *gsm)
-{
-	struct gsm_dlci *dlci;
-	int i = 0;
-
-	init_timer(&gsm->t2_timer);
-	gsm->t2_timer.function = gsm_control_retransmit;
-	gsm->t2_timer.data = (unsigned long)gsm;
-	init_waitqueue_head(&gsm->event);
-	spin_lock_init(&gsm->control_lock);
-	spin_lock_init(&gsm->tx_lock);
-
-	if (gsm->encoding == 0)
-		gsm->receive = gsm0_receive;
-	else
-		gsm->receive = gsm1_receive;
-	gsm->error = gsm_error;
-
-	spin_lock(&gsm_mux_lock);
-	for (i = 0; i < MAX_MUX; i++) {
-		if (gsm_mux[i] == NULL) {
-			gsm_mux[i] = gsm;
-			break;
-		}
-	}
-	spin_unlock(&gsm_mux_lock);
-	if (i == MAX_MUX)
-		return -EBUSY;
-
-	dlci = gsm_dlci_alloc(gsm, 0);
-	if (dlci == NULL)
-		return -ENOMEM;
-	gsm->dead = 0;		/* Tty opens are now permissible */
-	return 0;
-}
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
-
-/**
- *	gsm_free_mux		-	free up a mux
- *	@mux: mux to free
- *
- *	Dispose of allocated resources for a dead mux. No refcounting
- *	at present so the mux must be truely dead.
- */
-void gsm_free_mux(struct gsm_mux *gsm)
-{
-	kfree(gsm->txframe);
-	kfree(gsm->buf);
-	kfree(gsm);
-}
-EXPORT_SYMBOL_GPL(gsm_free_mux);
-
-/**
- *	gsm_alloc_mux		-	allocate a mux
- *
- *	Creates a new mux ready for activation.
- */
-
-struct gsm_mux *gsm_alloc_mux(void)
-{
-	struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
-	if (gsm == NULL)
-		return NULL;
-	gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
-	if (gsm->buf == NULL) {
-		kfree(gsm);
-		return NULL;
-	}
-	gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
-	if (gsm->txframe == NULL) {
-		kfree(gsm->buf);
-		kfree(gsm);
-		return NULL;
-	}
-	spin_lock_init(&gsm->lock);
-
-	gsm->t1 = T1;
-	gsm->t2 = T2;
-	gsm->n2 = N2;
-	gsm->ftype = UIH;
-	gsm->initiator = 0;
-	gsm->adaption = 1;
-	gsm->encoding = 1;
-	gsm->mru = 64;	/* Default to encoding 1 so these should be 64 */
-	gsm->mtu = 64;
-	gsm->dead = 1;	/* Avoid early tty opens */
-
-	return gsm;
-}
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
-
-/**
- *	gsmld_output		-	write to link
- *	@gsm: our mux
- *	@data: bytes to output
- *	@len: size
- *
- *	Write a block of data from the GSM mux to the data channel. This
- *	will eventually be serialized from above but at the moment isn't.
- */
-
-static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
-{
-	if (tty_write_room(gsm->tty) < len) {
-		set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
-		return -ENOSPC;
-	}
-	if (debug & 4) {
-		printk("-->%d bytes out\n", len);
-		hex_packet(data, len);
-	}
-	gsm->tty->ops->write(gsm->tty, data, len);
-	return len;
-}
-
-/**
- *	gsmld_attach_gsm	-	mode set up
- *	@tty: our tty structure
- *	@gsm: our mux
- *
- *	Set up the MUX for basic mode and commence connecting to the
- *	modem. Currently called from the line discipline set up but
- *	will need moving to an ioctl path.
- */
-
-static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-	int ret;
-
-	gsm->tty = tty_kref_get(tty);
-	gsm->output = gsmld_output;
-	ret =  gsm_activate_mux(gsm);
-	if (ret != 0)
-		tty_kref_put(gsm->tty);
-	return ret;
-}
-
-
-/**
- *	gsmld_detach_gsm	-	stop doing 0710 mux
- *	@tty: tty atttached to the mux
- *	@gsm: mux
- *
- *	Shutdown and then clean up the resources used by the line discipline
- */
-
-static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-	WARN_ON(tty != gsm->tty);
-	gsm_cleanup_mux(gsm);
-	tty_kref_put(gsm->tty);
-	gsm->tty = NULL;
-}
-
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			      char *fp, int count)
-{
-	struct gsm_mux *gsm = tty->disc_data;
-	const unsigned char *dp;
-	char *f;
-	int i;
-	char buf[64];
-	char flags;
-
-	if (debug & 4) {
-		printk("Inbytes %dd\n", count);
-		hex_packet(cp, count);
-	}
-
-	for (i = count, dp = cp, f = fp; i; i--, dp++) {
-		flags = *f++;
-		switch (flags) {
-		case TTY_NORMAL:
-			gsm->receive(gsm, *dp);
-			break;
-		case TTY_OVERRUN:
-		case TTY_BREAK:
-		case TTY_PARITY:
-		case TTY_FRAME:
-			gsm->error(gsm, *dp, flags);
-			break;
-		default:
-			printk(KERN_ERR "%s: unknown flag %d\n",
-			       tty_name(tty, buf), flags);
-			break;
-		}
-	}
-	/* FASYNC if needed ? */
-	/* If clogged call tty_throttle(tty); */
-}
-
-/**
- *	gsmld_chars_in_buffer	-	report available bytes
- *	@tty: tty device
- *
- *	Report the number of characters buffered to be delivered to user
- *	at this instant in time.
- *
- *	Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
-	return 0;
-}
-
-/**
- *	gsmld_flush_buffer	-	clean input queue
- *	@tty:	terminal device
- *
- *	Flush the input buffer. Called when the line discipline is
- *	being closed, when the tty layer wants the buffer flushed (eg
- *	at hangup).
- */
-
-static void gsmld_flush_buffer(struct tty_struct *tty)
-{
-}
-
-/**
- *	gsmld_close		-	close the ldisc for this tty
- *	@tty: device
- *
- *	Called from the terminal layer when this line discipline is
- *	being shut down, either because of a close or becsuse of a
- *	discipline change. The function will not be called while other
- *	ldisc methods are in progress.
- */
-
-static void gsmld_close(struct tty_struct *tty)
-{
-	struct gsm_mux *gsm = tty->disc_data;
-
-	gsmld_detach_gsm(tty, gsm);
-
-	gsmld_flush_buffer(tty);
-	/* Do other clean up here */
-	gsm_free_mux(gsm);
-}
-
-/**
- *	gsmld_open		-	open an ldisc
- *	@tty: terminal to open
- *
- *	Called when this line discipline is being attached to the
- *	terminal device. Can sleep. Called serialized so that no
- *	other events will occur in parallel. No further open will occur
- *	until a close.
- */
-
-static int gsmld_open(struct tty_struct *tty)
-{
-	struct gsm_mux *gsm;
-
-	if (tty->ops->write == NULL)
-		return -EINVAL;
-
-	/* Attach our ldisc data */
-	gsm = gsm_alloc_mux();
-	if (gsm == NULL)
-		return -ENOMEM;
-
-	tty->disc_data = gsm;
-	tty->receive_room = 65536;
-
-	/* Attach the initial passive connection */
-	gsm->encoding = 1;
-	return gsmld_attach_gsm(tty, gsm);
-}
-
-/**
- *	gsmld_write_wakeup	-	asynchronous I/O notifier
- *	@tty: tty device
- *
- *	Required for the ptys, serial driver etc. since processes
- *	that attach themselves to the master and rely on ASYNC
- *	IO must be woken up
- */
-
-static void gsmld_write_wakeup(struct tty_struct *tty)
-{
-	struct gsm_mux *gsm = tty->disc_data;
-	unsigned long flags;
-
-	/* Queue poll */
-	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-	gsm_data_kick(gsm);
-	if (gsm->tx_bytes < TX_THRESH_LO) {
-		spin_lock_irqsave(&gsm->tx_lock, flags);
-		gsm_dlci_data_sweep(gsm);
-		spin_unlock_irqrestore(&gsm->tx_lock, flags);
-	}
-}
-
-/**
- *	gsmld_read		-	read function for tty
- *	@tty: tty device
- *	@file: file object
- *	@buf: userspace buffer pointer
- *	@nr: size of I/O
- *
- *	Perform reads for the line discipline. We are guaranteed that the
- *	line discipline will not be closed under us but we may get multiple
- *	parallel readers and must handle this ourselves. We may also get
- *	a hangup. Always called in user context, may sleep.
- *
- *	This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
-			 unsigned char __user *buf, size_t nr)
-{
-	return -EOPNOTSUPP;
-}
-
-/**
- *	gsmld_write		-	write function for tty
- *	@tty: tty device
- *	@file: file object
- *	@buf: userspace buffer pointer
- *	@nr: size of I/O
- *
- *	Called when the owner of the device wants to send a frame
- *	itself (or some other control data). The data is transferred
- *	as-is and must be properly framed and checksummed as appropriate
- *	by userspace. Frames are either sent whole or not at all as this
- *	avoids pain user side.
- */
-
-static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
-			   const unsigned char *buf, size_t nr)
-{
-	int space = tty_write_room(tty);
-	if (space >= nr)
-		return tty->ops->write(tty, buf, nr);
-	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-	return -ENOBUFS;
-}
-
-/**
- *	gsmld_poll		-	poll method for N_GSM0710
- *	@tty: terminal device
- *	@file: file accessing it
- *	@wait: poll table
- *
- *	Called when the line discipline is asked to poll() for data or
- *	for special events. This code is not serialized with respect to
- *	other events save open/close.
- *
- *	This code must be sure never to sleep through a hangup.
- *	Called without the kernel lock held - fine
- */
-
-static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
-							poll_table *wait)
-{
-	unsigned int mask = 0;
-	struct gsm_mux *gsm = tty->disc_data;
-
-	poll_wait(file, &tty->read_wait, wait);
-	poll_wait(file, &tty->write_wait, wait);
-	if (tty_hung_up_p(file))
-		mask |= POLLHUP;
-	if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
-		mask |= POLLOUT | POLLWRNORM;
-	if (gsm->dead)
-		mask |= POLLHUP;
-	return mask;
-}
-
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
-							struct gsm_config *c)
-{
-	int need_close = 0;
-	int need_restart = 0;
-
-	/* Stuff we don't support yet - UI or I frame transport, windowing */
-	if ((c->adaption !=1 && c->adaption != 2) || c->k)
-		return -EOPNOTSUPP;
-	/* Check the MRU/MTU range looks sane */
-	if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
-		return -EINVAL;
-	if (c->n2 < 3)
-		return -EINVAL;
-	if (c->encapsulation > 1)	/* Basic, advanced, no I */
-		return -EINVAL;
-	if (c->initiator > 1)
-		return -EINVAL;
-	if (c->i == 0 || c->i > 2)	/* UIH and UI only */
-		return -EINVAL;
-	/*
-	 *	See what is needed for reconfiguration
-	 */
-
-	/* Timing fields */
-	if (c->t1 != 0 && c->t1 != gsm->t1)
-		need_restart = 1;
-	if (c->t2 != 0 && c->t2 != gsm->t2)
-		need_restart = 1;
-	if (c->encapsulation != gsm->encoding)
-		need_restart = 1;
-	if (c->adaption != gsm->adaption)
-		need_restart = 1;
-	/* Requires care */
-	if (c->initiator != gsm->initiator)
-		need_close = 1;
-	if (c->mru != gsm->mru)
-		need_restart = 1;
-	if (c->mtu != gsm->mtu)
-		need_restart = 1;
-
-	/*
-	 *	Close down what is needed, restart and initiate the new
-	 *	configuration
-	 */
-
-	if (need_close || need_restart) {
-		gsm_dlci_begin_close(gsm->dlci[0]);
-		/* This will timeout if the link is down due to N2 expiring */
-		wait_event_interruptible(gsm->event,
-				gsm->dlci[0]->state == DLCI_CLOSED);
-		if (signal_pending(current))
-			return -EINTR;
-	}
-	if (need_restart)
-		gsm_cleanup_mux(gsm);
-
-	gsm->initiator = c->initiator;
-	gsm->mru = c->mru;
-	gsm->encoding = c->encapsulation;
-	gsm->adaption = c->adaption;
-
-	if (c->i == 1)
-		gsm->ftype = UIH;
-	else if (c->i == 2)
-		gsm->ftype = UI;
-
-	if (c->t1)
-		gsm->t1 = c->t1;
-	if (c->t2)
-		gsm->t2 = c->t2;
-
-	/* FIXME: We need to separate activation/deactivation from adding
-	   and removing from the mux array */
-	if (need_restart)
-		gsm_activate_mux(gsm);
-	if (gsm->initiator && need_close)
-		gsm_dlci_begin_open(gsm->dlci[0]);
-	return 0;
-}
-
-static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	struct gsm_config c;
-	struct gsm_mux *gsm = tty->disc_data;
-
-	switch (cmd) {
-	case GSMIOC_GETCONF:
-		memset(&c, 0, sizeof(c));
-		c.adaption = gsm->adaption;
-		c.encapsulation = gsm->encoding;
-		c.initiator = gsm->initiator;
-		c.t1 = gsm->t1;
-		c.t2 = gsm->t2;
-		c.t3 = 0;	/* Not supported */
-		c.n2 = gsm->n2;
-		if (gsm->ftype == UIH)
-			c.i = 1;
-		else
-			c.i = 2;
-		printk("Ftype %d i %d\n", gsm->ftype, c.i);
-		c.mru = gsm->mru;
-		c.mtu = gsm->mtu;
-		c.k = 0;
-		if (copy_to_user((void *)arg, &c, sizeof(c)))
-			return -EFAULT;
-		return 0;
-	case GSMIOC_SETCONF:
-		if (copy_from_user(&c, (void *)arg, sizeof(c)))
-			return -EFAULT;
-		return gsmld_config(tty, gsm, &c);
-	default:
-		return n_tty_ioctl_helper(tty, file, cmd, arg);
-	}
-}
-
-
-/* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
-	.owner		 = THIS_MODULE,
-	.magic           = TTY_LDISC_MAGIC,
-	.name            = "n_gsm",
-	.open            = gsmld_open,
-	.close           = gsmld_close,
-	.flush_buffer    = gsmld_flush_buffer,
-	.chars_in_buffer = gsmld_chars_in_buffer,
-	.read            = gsmld_read,
-	.write           = gsmld_write,
-	.ioctl           = gsmld_ioctl,
-	.poll            = gsmld_poll,
-	.receive_buf     = gsmld_receive_buf,
-	.write_wakeup    = gsmld_write_wakeup
-};
-
-/*
- *	Virtual tty side
- */
-
-#define TX_SIZE		512
-
-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
-{
-	u8 modembits[5];
-	struct gsm_control *ctrl;
-	int len = 2;
-
-	if (brk)
-		len++;
-
-	modembits[0] = len << 1 | EA;		/* Data bytes */
-	modembits[1] = dlci->addr << 2 | 3;	/* DLCI, EA, 1 */
-	modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
-	if (brk)
-		modembits[3] = brk << 4 | 2 | EA;	/* Valid, EA */
-	ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
-	if (ctrl == NULL)
-		return -ENOMEM;
-	return gsm_control_wait(dlci->gsm, ctrl);
-}
-
-static int gsm_carrier_raised(struct tty_port *port)
-{
-	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-	/* Not yet open so no carrier info */
-	if (dlci->state != DLCI_OPEN)
-		return 0;
-	if (debug & 2)
-		return 1;
-	return dlci->modem_rx & TIOCM_CD;
-}
-
-static void gsm_dtr_rts(struct tty_port *port, int onoff)
-{
-	struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-	unsigned int modem_tx = dlci->modem_tx;
-	if (onoff)
-		modem_tx |= TIOCM_DTR | TIOCM_RTS;
-	else
-		modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
-	if (modem_tx != dlci->modem_tx) {
-		dlci->modem_tx = modem_tx;
-		gsmtty_modem_update(dlci, 0);
-	}
-}
-
-static const struct tty_port_operations gsm_port_ops = {
-	.carrier_raised = gsm_carrier_raised,
-	.dtr_rts = gsm_dtr_rts,
-};
-
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
-{
-	struct gsm_mux *gsm;
-	struct gsm_dlci *dlci;
-	struct tty_port *port;
-	unsigned int line = tty->index;
-	unsigned int mux = line >> 6;
-
-	line = line & 0x3F;
-
-	if (mux >= MAX_MUX)
-		return -ENXIO;
-	/* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
-	if (gsm_mux[mux] == NULL)
-		return -EUNATCH;
-	if (line == 0 || line > 61)	/* 62/63 reserved */
-		return -ECHRNG;
-	gsm = gsm_mux[mux];
-	if (gsm->dead)
-		return -EL2HLT;
-	dlci = gsm->dlci[line];
-	if (dlci == NULL)
-		dlci = gsm_dlci_alloc(gsm, line);
-	if (dlci == NULL)
-		return -ENOMEM;
-	port = &dlci->port;
-	port->count++;
-	tty->driver_data = dlci;
-	tty_port_tty_set(port, tty);
-
-	dlci->modem_rx = 0;
-	/* We could in theory open and close before we wait - eg if we get
-	   a DM straight back. This is ok as that will have caused a hangup */
-	set_bit(ASYNCB_INITIALIZED, &port->flags);
-	/* Start sending off SABM messages */
-	gsm_dlci_begin_open(dlci);
-	/* And wait for virtual carrier */
-	return tty_port_block_til_ready(port, tty, filp);
-}
-
-static void gsmtty_close(struct tty_struct *tty, struct file *filp)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	if (dlci == NULL)
-		return;
-	if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-		return;
-	gsm_dlci_begin_close(dlci);
-	tty_port_close_end(&dlci->port, tty);
-	tty_port_tty_set(&dlci->port, NULL);
-}
-
-static void gsmtty_hangup(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	tty_port_hangup(&dlci->port);
-	gsm_dlci_begin_close(dlci);
-}
-
-static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
-								    int len)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	/* Stuff the bytes into the fifo queue */
-	int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
-	/* Need to kick the channel */
-	gsm_dlci_data_kick(dlci);
-	return sent;
-}
-
-static int gsmtty_write_room(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	return TX_SIZE - kfifo_len(dlci->fifo);
-}
-
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	return kfifo_len(dlci->fifo);
-}
-
-static void gsmtty_flush_buffer(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	/* Caution needed: If we implement reliable transport classes
-	   then the data being transmitted can't simply be junked once
-	   it has first hit the stack. Until then we can just blow it
-	   away */
-	kfifo_reset(dlci->fifo);
-	/* Need to unhook this DLCI from the transmit queue logic */
-}
-
-static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	/* The FIFO handles the queue so the kernel will do the right
-	   thing waiting on chars_in_buffer before calling us. No work
-	   to do here */
-}
-
-static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	return dlci->modem_rx;
-}
-
-static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
-	unsigned int set, unsigned int clear)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	unsigned int modem_tx = dlci->modem_tx;
-
-	modem_tx &= clear;
-	modem_tx |= set;
-
-	if (modem_tx != dlci->modem_tx) {
-		dlci->modem_tx = modem_tx;
-		return gsmtty_modem_update(dlci, 0);
-	}
-	return 0;
-}
-
-
-static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
-			unsigned int cmd, unsigned long arg)
-{
-	return -ENOIOCTLCMD;
-}
-
-static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-	/* For the moment its fixed. In actual fact the speed information
-	   for the virtual channel can be propogated in both directions by
-	   the RPN control message. This however rapidly gets nasty as we
-	   then have to remap modem signals each way according to whether
-	   our virtual cable is null modem etc .. */
-	tty_termios_copy_hw(tty->termios, old);
-}
-
-static void gsmtty_throttle(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	if (tty->termios->c_cflag & CRTSCTS)
-		dlci->modem_tx &= ~TIOCM_DTR;
-	dlci->throttled = 1;
-	/* Send an MSC with DTR cleared */
-	gsmtty_modem_update(dlci, 0);
-}
-
-static void gsmtty_unthrottle(struct tty_struct *tty)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	if (tty->termios->c_cflag & CRTSCTS)
-		dlci->modem_tx |= TIOCM_DTR;
-	dlci->throttled = 0;
-	/* Send an MSC with DTR set */
-	gsmtty_modem_update(dlci, 0);
-}
-
-static int gsmtty_break_ctl(struct tty_struct *tty, int state)
-{
-	struct gsm_dlci *dlci = tty->driver_data;
-	int encode = 0;	/* Off */
-
-	if (state == -1)	/* "On indefinitely" - we can't encode this
-				    properly */
-		encode = 0x0F;
-	else if (state > 0) {
-		encode = state / 200;	/* mS to encoding */
-		if (encode > 0x0F)
-			encode = 0x0F;	/* Best effort */
-	}
-	return gsmtty_modem_update(dlci, encode);
-}
-
-static struct tty_driver *gsm_tty_driver;
-
-/* Virtual ttys for the demux */
-static const struct tty_operations gsmtty_ops = {
-	.open			= gsmtty_open,
-	.close			= gsmtty_close,
-	.write			= gsmtty_write,
-	.write_room		= gsmtty_write_room,
-	.chars_in_buffer	= gsmtty_chars_in_buffer,
-	.flush_buffer		= gsmtty_flush_buffer,
-	.ioctl			= gsmtty_ioctl,
-	.throttle		= gsmtty_throttle,
-	.unthrottle		= gsmtty_unthrottle,
-	.set_termios		= gsmtty_set_termios,
-	.hangup			= gsmtty_hangup,
-	.wait_until_sent	= gsmtty_wait_until_sent,
-	.tiocmget		= gsmtty_tiocmget,
-	.tiocmset		= gsmtty_tiocmset,
-	.break_ctl		= gsmtty_break_ctl,
-};
-
-
-
-static int __init gsm_init(void)
-{
-	/* Fill in our line protocol discipline, and register it */
-	int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
-	if (status != 0) {
-		printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
-		return status;
-	}
-
-	gsm_tty_driver = alloc_tty_driver(256);
-	if (!gsm_tty_driver) {
-		tty_unregister_ldisc(N_GSM0710);
-		printk(KERN_ERR "gsm_init: tty allocation failed.\n");
-		return -EINVAL;
-	}
-	gsm_tty_driver->owner	= THIS_MODULE;
-	gsm_tty_driver->driver_name	= "gsmtty";
-	gsm_tty_driver->name		= "gsmtty";
-	gsm_tty_driver->major		= 0;	/* Dynamic */
-	gsm_tty_driver->minor_start	= 0;
-	gsm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
-	gsm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;
-	gsm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-							| TTY_DRIVER_HARDWARE_BREAK;
-	gsm_tty_driver->init_termios	= tty_std_termios;
-	/* Fixme */
-	gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
-	tty_set_operations(gsm_tty_driver, &gsmtty_ops);
-
-	spin_lock_init(&gsm_mux_lock);
-
-	if (tty_register_driver(gsm_tty_driver)) {
-		put_tty_driver(gsm_tty_driver);
-		tty_unregister_ldisc(N_GSM0710);
-		printk(KERN_ERR "gsm_init: tty registration failed.\n");
-		return -EBUSY;
-	}
-	printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
-	return 0;
-}
-
-static void __exit gsm_exit(void)
-{
-	int status = tty_unregister_ldisc(N_GSM0710);
-	if (status != 0)
-		printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
-	tty_unregister_driver(gsm_tty_driver);
-	put_tty_driver(gsm_tty_driver);
-	printk(KERN_INFO "gsm_init: unloaded.\n");
-}
-
-module_init(gsm_init);
-module_exit(gsm_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_GSM0710);
diff -druN linux-libre-2.6.36-gnu/drivers/char/n_hdlc.c linux-libre-2.6.37-gnu/drivers/char/n_hdlc.c
--- linux-libre-2.6.36-gnu/drivers/char/n_hdlc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/n_hdlc.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1007 +0,0 @@
-/* generic HDLC line discipline for Linux
- *
- * Written by Paul Fulghum paulkf@microgate.com
- * for Microgate Corporation
- *
- * Microgate and SyncLink are registered trademarks of Microgate Corporation
- *
- * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
- *	Al Longyear <longyear@netcom.com>,
- *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
- *
- * Original release 01/11/99
- *
- * This code is released under the GNU General Public License (GPL)
- *
- * This module implements the tty line discipline N_HDLC for use with
- * tty device drivers that support bit-synchronous HDLC communications.
- *
- * All HDLC data is frame oriented which means:
- *
- * 1. tty write calls represent one complete transmit frame of data
- *    The device driver should accept the complete frame or none of 
- *    the frame (busy) in the write method. Each write call should have
- *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
- *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
- *    should include any crc bytes required. For example, when using
- *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
- *    the application may transmit is limited to 65531 bytes. For CCITT
- *    CRC16, the maximum application frame size would be 65533.
- *
- *
- * 2. receive callbacks from the device driver represents
- *    one received frame. The device driver should bypass
- *    the tty flip buffer and call the line discipline receive
- *    callback directly to avoid fragmenting or concatenating
- *    multiple frames into a single receive callback.
- *
- *    The HDLC line discipline queues the receive frames in separate
- *    buffers so complete receive frames can be returned by the
- *    tty read calls.
- *
- * 3. tty read calls returns an entire frame of data or nothing.
- *    
- * 4. all send and receive data is considered raw. No processing
- *    or translation is performed by the line discipline, regardless
- *    of the tty flags
- *
- * 5. When line discipline is queried for the amount of receive
- *    data available (FIOC), 0 is returned if no data available,
- *    otherwise the count of the next available frame is returned.
- *    (instead of the sum of all received frame counts).
- *
- * These conventions allow the standard tty programming interface
- * to be used for synchronous HDLC applications when used with
- * this line discipline (or another line discipline that is frame
- * oriented such as N_PPP).
- *
- * The SyncLink driver (synclink.c) implements both asynchronous
- * (using standard line discipline N_TTY) and synchronous HDLC
- * (using N_HDLC) communications, with the latter using the above
- * conventions.
- *
- * This implementation is very basic and does not maintain
- * any statistics. The main point is to enforce the raw data
- * and frame orientation of HDLC communications.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define HDLC_MAGIC 0x239e
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-
-#undef VERSION
-#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-
-#include <linux/poll.h>
-#include <linux/in.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>	/* used in new tty drivers */
-#include <linux/signal.h>	/* used in new tty drivers */
-#include <linux/if.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/termios.h>
-#include <asm/uaccess.h>
-
-/*
- * Buffers for individual HDLC frames
- */
-#define MAX_HDLC_FRAME_SIZE 65535 
-#define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 3
-
-struct n_hdlc_buf {
-	struct n_hdlc_buf *link;
-	int		  count;
-	char		  buf[1];
-};
-
-#define	N_HDLC_BUF_SIZE	(sizeof(struct n_hdlc_buf) + maxframe)
-
-struct n_hdlc_buf_list {
-	struct n_hdlc_buf *head;
-	struct n_hdlc_buf *tail;
-	int		  count;
-	spinlock_t	  spinlock;
-};
-
-/**
- * struct n_hdlc - per device instance data structure
- * @magic - magic value for structure
- * @flags - miscellaneous control flags
- * @tty - ptr to TTY structure
- * @backup_tty - TTY to use if tty gets closed
- * @tbusy - reentrancy flag for tx wakeup code
- * @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
- * @tx_buf_list - list of pending transmit frame buffers
- * @rx_buf_list - list of received frame buffers
- * @tx_free_buf_list - list unused transmit frame buffers
- * @rx_free_buf_list - list unused received frame buffers
- */
-struct n_hdlc {
-	int			magic;
-	__u32			flags;
-	struct tty_struct	*tty;
-	struct tty_struct	*backup_tty;
-	int			tbusy;
-	int			woke_up;
-	struct n_hdlc_buf	*tbuf;
-	struct n_hdlc_buf_list	tx_buf_list;
-	struct n_hdlc_buf_list	rx_buf_list;
-	struct n_hdlc_buf_list	tx_free_buf_list;
-	struct n_hdlc_buf_list	rx_free_buf_list;
-};
-
-/*
- * HDLC buffer list manipulation functions
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-			   struct n_hdlc_buf *buf);
-static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
-
-/* Local functions */
-
-static struct n_hdlc *n_hdlc_alloc (void);
-
-/* debug level can be set by insmod for debugging purposes */
-#define DEBUG_LEVEL_INFO	1
-static int debuglevel;
-
-/* max frame size for memory allocations */
-static int maxframe = 4096;
-
-/* TTY callbacks */
-
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-			   __u8 __user *buf, size_t nr);
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-			    const unsigned char *buf, size_t nr);
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-			    unsigned int cmd, unsigned long arg);
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-				    poll_table *wait);
-static int n_hdlc_tty_open(struct tty_struct *tty);
-static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
-			       char *fp, int count);
-static void n_hdlc_tty_wakeup(struct tty_struct *tty);
-
-#define bset(p,b)	((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-#define tty2n_hdlc(tty)	((struct n_hdlc *) ((tty)->disc_data))
-#define n_hdlc2tty(n_hdlc)	((n_hdlc)->tty)
-
-static void flush_rx_queue(struct tty_struct *tty)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-	struct n_hdlc_buf *buf;
-
-	while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
-		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
-}
-
-static void flush_tx_queue(struct tty_struct *tty)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-	struct n_hdlc_buf *buf;
-	unsigned long flags;
-
-	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
-		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
- 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-	if (n_hdlc->tbuf) {
-		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
-		n_hdlc->tbuf = NULL;
-	}
-	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-}
-
-static struct tty_ldisc_ops n_hdlc_ldisc = {
-	.owner		= THIS_MODULE,
-	.magic		= TTY_LDISC_MAGIC,
-	.name		= "hdlc",
-	.open		= n_hdlc_tty_open,
-	.close		= n_hdlc_tty_close,
-	.read		= n_hdlc_tty_read,
-	.write		= n_hdlc_tty_write,
-	.ioctl		= n_hdlc_tty_ioctl,
-	.poll		= n_hdlc_tty_poll,
-	.receive_buf	= n_hdlc_tty_receive,
-	.write_wakeup	= n_hdlc_tty_wakeup,
-	.flush_buffer   = flush_rx_queue,
-};
-
-/**
- * n_hdlc_release - release an n_hdlc per device line discipline info structure
- * @n_hdlc - per device line discipline info structure
- */
-static void n_hdlc_release(struct n_hdlc *n_hdlc)
-{
-	struct tty_struct *tty = n_hdlc2tty (n_hdlc);
-	struct n_hdlc_buf *buf;
-	
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
-		
-	/* Ensure that the n_hdlcd process is not hanging on select()/poll() */
-	wake_up_interruptible (&tty->read_wait);
-	wake_up_interruptible (&tty->write_wait);
-
-	if (tty->disc_data == n_hdlc)
-		tty->disc_data = NULL;	/* Break the tty->n_hdlc link */
-
-	/* Release transmit and receive buffers */
-	for(;;) {
-		buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-		if (buf) {
-			kfree(buf);
-		} else
-			break;
-	}
-	for(;;) {
-		buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
-		if (buf) {
-			kfree(buf);
-		} else
-			break;
-	}
-	for(;;) {
-		buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-		if (buf) {
-			kfree(buf);
-		} else
-			break;
-	}
-	for(;;) {
-		buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-		if (buf) {
-			kfree(buf);
-		} else
-			break;
-	}
-	kfree(n_hdlc->tbuf);
-	kfree(n_hdlc);
-	
-}	/* end of n_hdlc_release() */
-
-/**
- * n_hdlc_tty_close - line discipline close
- * @tty - pointer to tty info structure
- *
- * Called when the line discipline is changed to something
- * else, the tty is closed, or the tty detects a hangup.
- */
-static void n_hdlc_tty_close(struct tty_struct *tty)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
-		
-	if (n_hdlc != NULL) {
-		if (n_hdlc->magic != HDLC_MAGIC) {
-			printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
-			return;
-		}
-#if defined(TTY_NO_WRITE_SPLIT)
-		clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-		tty->disc_data = NULL;
-		if (tty == n_hdlc->backup_tty)
-			n_hdlc->backup_tty = NULL;
-		if (tty != n_hdlc->tty)
-			return;
-		if (n_hdlc->backup_tty) {
-			n_hdlc->tty = n_hdlc->backup_tty;
-		} else {
-			n_hdlc_release (n_hdlc);
-		}
-	}
-	
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
-		
-}	/* end of n_hdlc_tty_close() */
-
-/**
- * n_hdlc_tty_open - called when line discipline changed to n_hdlc
- * @tty - pointer to tty info structure
- *
- * Returns 0 if success, otherwise error code
- */
-static int n_hdlc_tty_open (struct tty_struct *tty)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
-		__FILE__,__LINE__,
-		tty->name);
-		
-	/* There should not be an existing table for this slot. */
-	if (n_hdlc) {
-		printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
-		return -EEXIST;
-	}
-	
-	n_hdlc = n_hdlc_alloc();
-	if (!n_hdlc) {
-		printk (KERN_ERR "n_hdlc_alloc failed\n");
-		return -ENFILE;
-	}
-		
-	tty->disc_data = n_hdlc;
-	n_hdlc->tty    = tty;
-	tty->receive_room = 65536;
-	
-#if defined(TTY_NO_WRITE_SPLIT)
-	/* change tty_io write() to not split large writes into 8K chunks */
-	set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-	
-	/* flush receive data from driver */
-	tty_driver_flush_buffer(tty);
-		
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
-		
-	return 0;
-	
-}	/* end of n_tty_hdlc_open() */
-
-/**
- * n_hdlc_send_frames - send frames on pending send buffer list
- * @n_hdlc - pointer to ldisc instance data
- * @tty - pointer to tty instance data
- *
- * Send frames on pending send buffer list until the driver does not accept a
- * frame (busy) this function is called after adding a frame to the send buffer
- * list and by the tty wakeup callback.
- */
-static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
-{
-	register int actual;
-	unsigned long flags;
-	struct n_hdlc_buf *tbuf;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
- check_again:
-		
- 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-	if (n_hdlc->tbusy) {
-		n_hdlc->woke_up = 1;
- 		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-		return;
-	}
-	n_hdlc->tbusy = 1;
-	n_hdlc->woke_up = 0;
-	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-
-	/* get current transmit buffer or get new transmit */
-	/* buffer from list of pending transmit buffers */
-		
-	tbuf = n_hdlc->tbuf;
-	if (!tbuf)
-		tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-		
-	while (tbuf) {
-		if (debuglevel >= DEBUG_LEVEL_INFO)	
-			printk("%s(%d)sending frame %p, count=%d\n",
-				__FILE__,__LINE__,tbuf,tbuf->count);
-			
-		/* Send the next block of data to device */
-		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-		actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
-
-		/* rollback was possible and has been done */
-		if (actual == -ERESTARTSYS) {
-			n_hdlc->tbuf = tbuf;
-			break;
-		}
-		/* if transmit error, throw frame away by */
-		/* pretending it was accepted by driver */
-		if (actual < 0)
-			actual = tbuf->count;
-		
-		if (actual == tbuf->count) {
-			if (debuglevel >= DEBUG_LEVEL_INFO)	
-				printk("%s(%d)frame %p completed\n",
-					__FILE__,__LINE__,tbuf);
-					
-			/* free current transmit buffer */
-			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-			
-			/* this tx buffer is done */
-			n_hdlc->tbuf = NULL;
-			
-			/* wait up sleeping writers */
-			wake_up_interruptible(&tty->write_wait);
-	
-			/* get next pending transmit buffer */
-			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-		} else {
-			if (debuglevel >= DEBUG_LEVEL_INFO)	
-				printk("%s(%d)frame %p pending\n",
-					__FILE__,__LINE__,tbuf);
-					
-			/* buffer not accepted by driver */
-			/* set this buffer as pending buffer */
-			n_hdlc->tbuf = tbuf;
-			break;
-		}
-	}
-	
-	if (!tbuf)
-		tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
-	
-	/* Clear the re-entry flag */
-	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-	n_hdlc->tbusy = 0;
-	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
-	
-        if (n_hdlc->woke_up)
-	  goto check_again;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
-		
-}	/* end of n_hdlc_send_frames() */
-
-/**
- * n_hdlc_tty_wakeup - Callback for transmit wakeup
- * @tty	- pointer to associated tty instance data
- *
- * Called when low level device driver can accept more send data.
- */
-static void n_hdlc_tty_wakeup(struct tty_struct *tty)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
-		
-	if (!n_hdlc)
-		return;
-
-	if (tty != n_hdlc->tty) {
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-		return;
-	}
-
-	n_hdlc_send_frames (n_hdlc, tty);
-		
-}	/* end of n_hdlc_tty_wakeup() */
-
-/**
- * n_hdlc_tty_receive - Called by tty driver when receive data is available
- * @tty	- pointer to tty instance data
- * @data - pointer to received data
- * @flags - pointer to flags for data
- * @count - count of received data in bytes
- *
- * Called by tty low level driver when receive data is available. Data is
- * interpreted as one HDLC frame.
- */
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
-			       char *flags, int count)
-{
-	register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-	register struct n_hdlc_buf *buf;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
-			__FILE__,__LINE__, count);
-		
-	/* This can happen if stuff comes in on the backup tty */
-	if (!n_hdlc || tty != n_hdlc->tty)
-		return;
-		
-	/* verify line is using HDLC discipline */
-	if (n_hdlc->magic != HDLC_MAGIC) {
-		printk("%s(%d) line not using HDLC discipline\n",
-			__FILE__,__LINE__);
-		return;
-	}
-	
-	if ( count>maxframe ) {
-		if (debuglevel >= DEBUG_LEVEL_INFO)	
-			printk("%s(%d) rx count>maxframesize, data discarded\n",
-			       __FILE__,__LINE__);
-		return;
-	}
-
-	/* get a free HDLC buffer */	
-	buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-	if (!buf) {
-		/* no buffers in free list, attempt to allocate another rx buffer */
-		/* unless the maximum count has been reached */
-		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
-			buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
-	}
-	
-	if (!buf) {
-		if (debuglevel >= DEBUG_LEVEL_INFO)	
-			printk("%s(%d) no more rx buffers, data discarded\n",
-			       __FILE__,__LINE__);
-		return;
-	}
-		
-	/* copy received data to HDLC buffer */
-	memcpy(buf->buf,data,count);
-	buf->count=count;
-
-	/* add HDLC buffer to list of received frames */
-	n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
-	
-	/* wake up any blocked reads and perform async signalling */
-	wake_up_interruptible (&tty->read_wait);
-	if (n_hdlc->tty->fasync != NULL)
-		kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
-
-}	/* end of n_hdlc_tty_receive() */
-
-/**
- * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
- * @tty - pointer to tty instance data
- * @file - pointer to open file object
- * @buf - pointer to returned data buffer
- * @nr - size of returned data buffer
- * 	
- * Returns the number of bytes returned or error code.
- */
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-			   __u8 __user *buf, size_t nr)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-	int ret;
-	struct n_hdlc_buf *rbuf;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
-		
-	/* Validate the pointers */
-	if (!n_hdlc)
-		return -EIO;
-
-	/* verify user access to buffer */
-	if (!access_ok(VERIFY_WRITE, buf, nr)) {
-		printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
-		"buffer\n", __FILE__, __LINE__);
-		return -EFAULT;
-	}
-
-	tty_lock();
-
-	for (;;) {
-		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-			tty_unlock();
-			return -EIO;
-		}
-
-		n_hdlc = tty2n_hdlc (tty);
-		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-			 tty != n_hdlc->tty) {
-			tty_unlock();
-			return 0;
-		}
-
-		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-		if (rbuf)
-			break;
-			
-		/* no data */
-		if (file->f_flags & O_NONBLOCK) {
-			tty_unlock();
-			return -EAGAIN;
-		}
-			
-		interruptible_sleep_on (&tty->read_wait);
-		if (signal_pending(current)) {
-			tty_unlock();
-			return -EINTR;
-		}
-	}
-		
-	if (rbuf->count > nr)
-		/* frame too large for caller's buffer (discard frame) */
-		ret = -EOVERFLOW;
-	else {
-		/* Copy the data to the caller's buffer */
-		if (copy_to_user(buf, rbuf->buf, rbuf->count))
-			ret = -EFAULT;
-		else
-			ret = rbuf->count;
-	}
-	
-	/* return HDLC buffer to free list unless the free list */
-	/* count has exceeded the default value, in which case the */
-	/* buffer is freed back to the OS to conserve memory */
-	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
-		kfree(rbuf);
-	else	
-		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-	tty_unlock();
-	return ret;
-	
-}	/* end of n_hdlc_tty_read() */
-
-/**
- * n_hdlc_tty_write - write a single frame of data to device
- * @tty	- pointer to associated tty device instance data
- * @file - pointer to file object data
- * @data - pointer to transmit data (one frame)
- * @count - size of transmit frame in bytes
- * 		
- * Returns the number of bytes written (or error code).
- */
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-			    const unsigned char *data, size_t count)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-	int error = 0;
-	DECLARE_WAITQUEUE(wait, current);
-	struct n_hdlc_buf *tbuf;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
-			__FILE__,__LINE__,count);
-		
-	/* Verify pointers */
-	if (!n_hdlc)
-		return -EIO;
-
-	if (n_hdlc->magic != HDLC_MAGIC)
-		return -EIO;
-
-	/* verify frame size */
-	if (count > maxframe ) {
-		if (debuglevel & DEBUG_LEVEL_INFO)
-			printk (KERN_WARNING
-				"n_hdlc_tty_write: truncating user packet "
-				"from %lu to %d\n", (unsigned long) count,
-				maxframe );
-		count = maxframe;
-	}
-	
-	tty_lock();
-
-	add_wait_queue(&tty->write_wait, &wait);
-	set_current_state(TASK_INTERRUPTIBLE);
-	
-	/* Allocate transmit buffer */
-	/* sleep until transmit buffer available */		
-	while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
-		if (file->f_flags & O_NONBLOCK) {
-			error = -EAGAIN;
-			break;
-		}
-		schedule();
-			
-		n_hdlc = tty2n_hdlc (tty);
-		if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
-		    tty != n_hdlc->tty) {
-			printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
-			error = -EIO;
-			break;
-		}
-			
-		if (signal_pending(current)) {
-			error = -EINTR;
-			break;
-		}
-	}
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&tty->write_wait, &wait);
-
-	if (!error) {		
-		/* Retrieve the user's buffer */
-		memcpy(tbuf->buf, data, count);
-
-		/* Send the data */
-		tbuf->count = error = count;
-		n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
-		n_hdlc_send_frames(n_hdlc,tty);
-	}
-	tty_unlock();
-	return error;
-	
-}	/* end of n_hdlc_tty_write() */
-
-/**
- * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
- * @tty - pointer to tty instance data
- * @file - pointer to open file object for device
- * @cmd - IOCTL command code
- * @arg - argument for IOCTL call (cmd dependent)
- *
- * Returns command dependent result.
- */
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-			    unsigned int cmd, unsigned long arg)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-	int error = 0;
-	int count;
-	unsigned long flags;
-	
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
-			__FILE__,__LINE__,cmd);
-		
-	/* Verify the status of the device */
-	if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
-		return -EBADF;
-
-	switch (cmd) {
-	case FIONREAD:
-		/* report count of read data available */
-		/* in next available frame (if any) */
-		spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-		if (n_hdlc->rx_buf_list.head)
-			count = n_hdlc->rx_buf_list.head->count;
-		else
-			count = 0;
-		spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
-		error = put_user(count, (int __user *)arg);
-		break;
-
-	case TIOCOUTQ:
-		/* get the pending tx byte count in the driver */
-		count = tty_chars_in_buffer(tty);
-		/* add size of next output frame in queue */
-		spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
-		if (n_hdlc->tx_buf_list.head)
-			count += n_hdlc->tx_buf_list.head->count;
-		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
-		error = put_user(count, (int __user *)arg);
-		break;
-
-	case TCFLSH:
-		switch (arg) {
-		case TCIOFLUSH:
-		case TCOFLUSH:
-			flush_tx_queue(tty);
-		}
-		/* fall through to default */
-
-	default:
-		error = n_tty_ioctl_helper(tty, file, cmd, arg);
-		break;
-	}
-	return error;
-	
-}	/* end of n_hdlc_tty_ioctl() */
-
-/**
- * n_hdlc_tty_poll - TTY callback for poll system call
- * @tty - pointer to tty instance data
- * @filp - pointer to open file object for device
- * @poll_table - wait queue for operations
- * 
- * Determine which operations (read/write) will not block and return info
- * to caller.
- * Returns a bit mask containing info on which ops will not block.
- */
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-				    poll_table *wait)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-	unsigned int mask = 0;
-
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
-		
-	if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
-		/* queue current process into any wait queue that */
-		/* may awaken in the future (read and write) */
-
-		poll_wait(filp, &tty->read_wait, wait);
-		poll_wait(filp, &tty->write_wait, wait);
-
-		/* set bits for operations that won't block */
-		if (n_hdlc->rx_buf_list.head)
-			mask |= POLLIN | POLLRDNORM;	/* readable */
-		if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-			mask |= POLLHUP;
-		if (tty_hung_up_p(filp))
-			mask |= POLLHUP;
-		if (!tty_is_writelocked(tty) &&
-				n_hdlc->tx_free_buf_list.head)
-			mask |= POLLOUT | POLLWRNORM;	/* writable */
-	}
-	return mask;
-}	/* end of n_hdlc_tty_poll() */
-
-/**
- * n_hdlc_alloc - allocate an n_hdlc instance data structure
- *
- * Returns a pointer to newly created structure if success, otherwise %NULL
- */
-static struct n_hdlc *n_hdlc_alloc(void)
-{
-	struct n_hdlc_buf *buf;
-	int i;
-	struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
-
-	if (!n_hdlc)
-		return NULL;
-
-	memset(n_hdlc, 0, sizeof(*n_hdlc));
-
-	n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
-	n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-	
-	/* allocate free rx buffer list */
-	for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
-		buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-		if (buf)
-			n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
-		else if (debuglevel >= DEBUG_LEVEL_INFO)	
-			printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
-	}
-	
-	/* allocate free tx buffer list */
-	for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
-		buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-		if (buf)
-			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
-		else if (debuglevel >= DEBUG_LEVEL_INFO)	
-			printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
-	}
-	
-	/* Initialize the control block */
-	n_hdlc->magic  = HDLC_MAGIC;
-	n_hdlc->flags  = 0;
-	
-	return n_hdlc;
-	
-}	/* end of n_hdlc_alloc() */
-
-/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
-	memset(list, 0, sizeof(*list));
-	spin_lock_init(&list->spinlock);
-}	/* end of n_hdlc_buf_list_init() */
-
-/**
- * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
- * @buf	- pointer to buffer
- */
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-			   struct n_hdlc_buf *buf)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&list->spinlock,flags);
-	
-	buf->link=NULL;
-	if (list->tail)
-		list->tail->link = buf;
-	else
-		list->head = buf;
-	list->tail = buf;
-	(list->count)++;
-	
-	spin_unlock_irqrestore(&list->spinlock,flags);
-	
-}	/* end of n_hdlc_buf_put() */
-
-/**
- * n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
- * 
- * Remove and return an HDLC buffer from the head of the specified HDLC buffer
- * list.
- * Returns a pointer to HDLC buffer if available, otherwise %NULL.
- */
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
-{
-	unsigned long flags;
-	struct n_hdlc_buf *buf;
-	spin_lock_irqsave(&list->spinlock,flags);
-	
-	buf = list->head;
-	if (buf) {
-		list->head = buf->link;
-		(list->count)--;
-	}
-	if (!list->head)
-		list->tail = NULL;
-	
-	spin_unlock_irqrestore(&list->spinlock,flags);
-	return buf;
-	
-}	/* end of n_hdlc_buf_get() */
-
-static char hdlc_banner[] __initdata =
-	KERN_INFO "HDLC line discipline maxframe=%u\n";
-static char hdlc_register_ok[] __initdata =
-	KERN_INFO "N_HDLC line discipline registered.\n";
-static char hdlc_register_fail[] __initdata =
-	KERN_ERR "error registering line discipline: %d\n";
-static char hdlc_init_fail[] __initdata =
-	KERN_INFO "N_HDLC: init failure %d\n";
-
-static int __init n_hdlc_init(void)
-{
-	int status;
-
-	/* range check maxframe arg */
-	if (maxframe < 4096)
-		maxframe = 4096;
-	else if (maxframe > 65535)
-		maxframe = 65535;
-
-	printk(hdlc_banner, maxframe);
-
-	status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
-	if (!status)
-		printk(hdlc_register_ok);
-	else
-		printk(hdlc_register_fail, status);
-
-	if (status)
-		printk(hdlc_init_fail, status);
-	return status;
-	
-}	/* end of init_module() */
-
-static char hdlc_unregister_ok[] __exitdata =
-	KERN_INFO "N_HDLC: line discipline unregistered\n";
-static char hdlc_unregister_fail[] __exitdata =
-	KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
-
-static void __exit n_hdlc_exit(void)
-{
-	/* Release tty registration of line discipline */
-	int status = tty_unregister_ldisc(N_HDLC);
-
-	if (status)
-		printk(hdlc_unregister_fail, status);
-	else
-		printk(hdlc_unregister_ok);
-}
-
-module_init(n_hdlc_init);
-module_exit(n_hdlc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
-module_param(debuglevel, int, 0);
-module_param(maxframe, int, 0);
-MODULE_ALIAS_LDISC(N_HDLC);
diff -druN linux-libre-2.6.36-gnu/drivers/char/nozomi.c linux-libre-2.6.37-gnu/drivers/char/nozomi.c
--- linux-libre-2.6.36-gnu/drivers/char/nozomi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/nozomi.c	2011-01-04 19:50:19.000000000 -0500
@@ -1804,31 +1804,30 @@
 	return ret;
 }
 
-static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
+static int ntty_tiocgicount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
 {
+	struct port *port = tty->driver_data;
 	const struct async_icount cnow = port->tty_icount;
-	struct serial_icounter_struct icount;
-
-	icount.cts = cnow.cts;
-	icount.dsr = cnow.dsr;
-	icount.rng = cnow.rng;
-	icount.dcd = cnow.dcd;
-	icount.rx = cnow.rx;
-	icount.tx = cnow.tx;
-	icount.frame = cnow.frame;
-	icount.overrun = cnow.overrun;
-	icount.parity = cnow.parity;
-	icount.brk = cnow.brk;
-	icount.buf_overrun = cnow.buf_overrun;
 
-	return copy_to_user(argp, &icount, sizeof(icount)) ? -EFAULT : 0;
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+	return 0;
 }
 
 static int ntty_ioctl(struct tty_struct *tty, struct file *file,
 		      unsigned int cmd, unsigned long arg)
 {
 	struct port *port = tty->driver_data;
-	void __user *argp = (void __user *)arg;
 	int rval = -ENOIOCTLCMD;
 
 	DBG1("******** IOCTL, cmd: %d", cmd);
@@ -1840,9 +1839,7 @@
 		rval = wait_event_interruptible(port->tty_wait,
 				ntty_cflags_changed(port, arg, &cprev));
 		break;
-	} case TIOCGICOUNT:
-		rval = ntty_ioctl_tiocgicount(port, argp);
-		break;
+	}
 	default:
 		DBG1("ERR: 0x%08X, %d", cmd, cmd);
 		break;
@@ -1922,6 +1919,7 @@
 	.chars_in_buffer = ntty_chars_in_buffer,
 	.tiocmget = ntty_tiocmget,
 	.tiocmset = ntty_tiocmset,
+	.get_icount = ntty_tiocgicount,
 	.install = ntty_install,
 	.cleanup = ntty_cleanup,
 };
diff -druN linux-libre-2.6.36-gnu/drivers/char/n_r3964.c linux-libre-2.6.37-gnu/drivers/char/n_r3964.c
--- linux-libre-2.6.36-gnu/drivers/char/n_r3964.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/n_r3964.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1265 +0,0 @@
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by 
- * Philips Automation Projects
- * Kassel (Germany)
- * http://www.pap-philips.de
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10  2001/03/18 13:02:24  dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9  2001/03/18 12:52:14  dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8  2000/03/23 14:14:54  dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7  1999/28/08 11:41:50  dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6  1998/09/30 00:40:40  dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5  1998/09/04 21:57:36  dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4  1998/04/02 20:26:59  lhaag
- * select, blocking, ...
- *
- * Revision 1.3  1998/02/12 18:58:43  root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2  1998/02/07 13:03:34  root
- * ioctl read_telegram
- *
- * Revision 1.1  1998/02/06 19:21:03  root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>	/* used in new tty drivers */
-#include <linux/signal.h>	/* used in new tty drivers */
-#include <linux/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations  */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(unsigned long priv);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-		unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-		int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-		struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
-		struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-		unsigned char __user * buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-		const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-		unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-		struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-		char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
-	.owner = THIS_MODULE,
-	.magic = TTY_LDISC_MAGIC,
-	.name = "R3964",
-	.open = r3964_open,
-	.close = r3964_close,
-	.read = r3964_read,
-	.write = r3964_write,
-	.ioctl = r3964_ioctl,
-	.set_termios = r3964_set_termios,
-	.poll = r3964_poll,
-	.receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
-	unsigned int i, j;
-	char linebuf[16 * 3 + 1];
-
-	for (i = 0; i < length; i += 16) {
-		for (j = 0; (j < 16) && (j + i < length); j++) {
-			sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
-		}
-		linebuf[3 * j] = '\0';
-		TRACE_PS("%s", linebuf);
-	}
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
-	int status;
-
-	TRACE_M("cleanup_module()");
-
-	status = tty_unregister_ldisc(N_R3964);
-
-	if (status != 0) {
-		printk(KERN_ERR "r3964: error unregistering linediscipline: "
-				"%d\n", status);
-	} else {
-		TRACE_L("linediscipline successfully unregistered");
-	}
-}
-
-static int __init r3964_init(void)
-{
-	int status;
-
-	printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
-	/*
-	 * Register the tty line discipline
-	 */
-
-	status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
-	if (status == 0) {
-		TRACE_L("line discipline %d registered", N_R3964);
-		TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
-			tty_ldisc_N_R3964.num);
-		TRACE_L("open=%p", tty_ldisc_N_R3964.open);
-		TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
-	} else {
-		printk(KERN_ERR "r3964: error registering line discipline: "
-				"%d\n", status);
-	}
-	return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
-			 struct r3964_block_header *pHeader)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pInfo->lock, flags);
-
-	pHeader->next = NULL;
-
-	if (pInfo->tx_last == NULL) {
-		pInfo->tx_first = pInfo->tx_last = pHeader;
-	} else {
-		pInfo->tx_last->next = pHeader;
-		pInfo->tx_last = pHeader;
-	}
-
-	spin_unlock_irqrestore(&pInfo->lock, flags);
-
-	TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
-		pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
-	struct r3964_block_header *pHeader;
-	unsigned long flags;
-#ifdef DEBUG_QUEUE
-	struct r3964_block_header *pDump;
-#endif
-
-	pHeader = pInfo->tx_first;
-
-	if (pHeader == NULL)
-		return;
-
-#ifdef DEBUG_QUEUE
-	printk("r3964: remove_from_tx_queue: %p, length %u - ",
-		pHeader, pHeader->length);
-	for (pDump = pHeader; pDump; pDump = pDump->next)
-		printk("%p ", pDump);
-	printk("\n");
-#endif
-
-	if (pHeader->owner) {
-		if (error_code) {
-			add_msg(pHeader->owner, R3964_MSG_ACK, 0,
-				error_code, NULL);
-		} else {
-			add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
-				error_code, NULL);
-		}
-		wake_up_interruptible(&pInfo->read_wait);
-	}
-
-	spin_lock_irqsave(&pInfo->lock, flags);
-
-	pInfo->tx_first = pHeader->next;
-	if (pInfo->tx_first == NULL) {
-		pInfo->tx_last = NULL;
-	}
-
-	spin_unlock_irqrestore(&pInfo->lock, flags);
-
-	kfree(pHeader);
-	TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
-	TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
-		pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
-			 struct r3964_block_header *pHeader)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pInfo->lock, flags);
-
-	pHeader->next = NULL;
-
-	if (pInfo->rx_last == NULL) {
-		pInfo->rx_first = pInfo->rx_last = pHeader;
-	} else {
-		pInfo->rx_last->next = pHeader;
-		pInfo->rx_last = pHeader;
-	}
-	pInfo->blocks_in_rx_queue++;
-
-	spin_unlock_irqrestore(&pInfo->lock, flags);
-
-	TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
-		pHeader, pHeader->length,
-		pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
-				 struct r3964_block_header *pHeader)
-{
-	unsigned long flags;
-	struct r3964_block_header *pFind;
-
-	if (pHeader == NULL)
-		return;
-
-	TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-		pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-	TRACE_Q("remove_from_rx_queue: %p, length %u",
-		pHeader, pHeader->length);
-
-	spin_lock_irqsave(&pInfo->lock, flags);
-
-	if (pInfo->rx_first == pHeader) {
-		/* Remove the first block in the linked list: */
-		pInfo->rx_first = pHeader->next;
-
-		if (pInfo->rx_first == NULL) {
-			pInfo->rx_last = NULL;
-		}
-		pInfo->blocks_in_rx_queue--;
-	} else {
-		/* Find block to remove: */
-		for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
-			if (pFind->next == pHeader) {
-				/* Got it. */
-				pFind->next = pHeader->next;
-				pInfo->blocks_in_rx_queue--;
-				if (pFind->next == NULL) {
-					/* Oh, removed the last one! */
-					pInfo->rx_last = pFind;
-				}
-				break;
-			}
-		}
-	}
-
-	spin_unlock_irqrestore(&pInfo->lock, flags);
-
-	kfree(pHeader);
-	TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
-	TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-		pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
-	struct tty_struct *tty = pInfo->tty;
-	/* FIXME: put_char should not be called from an IRQ */
-	tty_put_char(tty, ch);
-	pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
-	struct tty_struct *tty = pInfo->tty;
-
-	if (tty == NULL || tty->ops->flush_chars == NULL)
-		return;
-	tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pInfo->lock, flags);
-
-	if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
-		pInfo->state = R3964_TX_REQUEST;
-		pInfo->nRetry = 0;
-		pInfo->flags &= ~R3964_ERROR;
-		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
-		spin_unlock_irqrestore(&pInfo->lock, flags);
-
-		TRACE_PS("trigger_transmit - sent STX");
-
-		put_char(pInfo, STX);
-		flush(pInfo);
-
-		pInfo->bcc = 0;
-	} else {
-		spin_unlock_irqrestore(&pInfo->lock, flags);
-	}
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
-	if (pInfo->nRetry < R3964_MAX_RETRIES) {
-		TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
-		pInfo->bcc = 0;
-		put_char(pInfo, STX);
-		flush(pInfo);
-		pInfo->state = R3964_TX_REQUEST;
-		pInfo->nRetry++;
-		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-	} else {
-		TRACE_PE("transmission failed after %d retries",
-			 R3964_MAX_RETRIES);
-
-		remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		pInfo->state = R3964_IDLE;
-
-		trigger_transmit(pInfo);
-	}
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
-	struct tty_struct *tty = pInfo->tty;
-	struct r3964_block_header *pBlock = pInfo->tx_first;
-	int room = 0;
-
-	if (tty == NULL || pBlock == NULL) {
-		return;
-	}
-
-	room = tty_write_room(tty);
-
-	TRACE_PS("transmit_block %p, room %d, length %d",
-		 pBlock, room, pBlock->length);
-
-	while (pInfo->tx_position < pBlock->length) {
-		if (room < 2)
-			break;
-
-		if (pBlock->data[pInfo->tx_position] == DLE) {
-			/* send additional DLE char: */
-			put_char(pInfo, DLE);
-		}
-		put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
-		room--;
-	}
-
-	if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
-		put_char(pInfo, DLE);
-		put_char(pInfo, ETX);
-		if (pInfo->flags & R3964_BCC) {
-			put_char(pInfo, pInfo->bcc);
-		}
-		pInfo->state = R3964_WAIT_FOR_TX_ACK;
-		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-	}
-	flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
-	unsigned int length;
-	struct r3964_client_info *pClient;
-	struct r3964_block_header *pBlock;
-
-	length = pInfo->rx_position;
-
-	/* compare byte checksum characters: */
-	if (pInfo->flags & R3964_BCC) {
-		if (pInfo->bcc != pInfo->last_rx) {
-			TRACE_PE("checksum error - got %x but expected %x",
-				 pInfo->last_rx, pInfo->bcc);
-			pInfo->flags |= R3964_CHECKSUM;
-		}
-	}
-
-	/* check for errors (parity, overrun,...): */
-	if (pInfo->flags & R3964_ERROR) {
-		TRACE_PE("on_receive_block - transmission failed error %x",
-			 pInfo->flags & R3964_ERROR);
-
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		if (pInfo->nRetry < R3964_MAX_RETRIES) {
-			pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
-			pInfo->nRetry++;
-			mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
-		} else {
-			TRACE_PE("on_receive_block - failed after max retries");
-			pInfo->state = R3964_IDLE;
-		}
-		return;
-	}
-
-	/* received block; submit DLE: */
-	put_char(pInfo, DLE);
-	flush(pInfo);
-	del_timer_sync(&pInfo->tmr);
-	TRACE_PS(" rx success: got %d chars", length);
-
-	/* prepare struct r3964_block_header: */
-	pBlock = kmalloc(length + sizeof(struct r3964_block_header),
-			GFP_KERNEL);
-	TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
-	if (pBlock == NULL)
-		return;
-
-	pBlock->length = length;
-	pBlock->data = ((unsigned char *)pBlock) +
-			sizeof(struct r3964_block_header);
-	pBlock->locks = 0;
-	pBlock->next = NULL;
-	pBlock->owner = NULL;
-
-	memcpy(pBlock->data, pInfo->rx_buf, length);
-
-	/* queue block into rx_queue: */
-	add_rx_queue(pInfo, pBlock);
-
-	/* notify attached client processes: */
-	for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-		if (pClient->sig_flags & R3964_SIG_DATA) {
-			add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
-				pBlock);
-		}
-	}
-	wake_up_interruptible(&pInfo->read_wait);
-
-	pInfo->state = R3964_IDLE;
-
-	trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
-	switch (pInfo->state) {
-	case R3964_TX_REQUEST:
-		if (c == DLE) {
-			TRACE_PS("TX_REQUEST - got DLE");
-
-			pInfo->state = R3964_TRANSMITTING;
-			pInfo->tx_position = 0;
-
-			transmit_block(pInfo);
-		} else if (c == STX) {
-			if (pInfo->nRetry == 0) {
-				TRACE_PE("TX_REQUEST - init conflict");
-				if (pInfo->priority == R3964_SLAVE) {
-					goto start_receiving;
-				}
-			} else {
-				TRACE_PE("TX_REQUEST - secondary init "
-					"conflict!? Switching to SLAVE mode "
-					"for next rx.");
-				goto start_receiving;
-			}
-		} else {
-			TRACE_PE("TX_REQUEST - char != DLE: %x", c);
-			retry_transmit(pInfo);
-		}
-		break;
-	case R3964_TRANSMITTING:
-		if (c == NAK) {
-			TRACE_PE("TRANSMITTING - got NAK");
-			retry_transmit(pInfo);
-		} else {
-			TRACE_PE("TRANSMITTING - got invalid char");
-
-			pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
-			mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-		}
-		break;
-	case R3964_WAIT_FOR_TX_ACK:
-		if (c == DLE) {
-			TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
-			remove_from_tx_queue(pInfo, R3964_OK);
-
-			pInfo->state = R3964_IDLE;
-			trigger_transmit(pInfo);
-		} else {
-			retry_transmit(pInfo);
-		}
-		break;
-	case R3964_WAIT_FOR_RX_REPEAT:
-		/* FALLTHROUGH */
-	case R3964_IDLE:
-		if (c == STX) {
-			/* Prevent rx_queue from overflow: */
-			if (pInfo->blocks_in_rx_queue >=
-			    R3964_MAX_BLOCKS_IN_RX_QUEUE) {
-				TRACE_PE("IDLE - got STX but no space in "
-						"rx_queue!");
-				pInfo->state = R3964_WAIT_FOR_RX_BUF;
-				mod_timer(&pInfo->tmr,
-					  jiffies + R3964_TO_NO_BUF);
-				break;
-			}
-start_receiving:
-			/* Ok, start receiving: */
-			TRACE_PS("IDLE - got STX");
-			pInfo->rx_position = 0;
-			pInfo->last_rx = 0;
-			pInfo->flags &= ~R3964_ERROR;
-			pInfo->state = R3964_RECEIVING;
-			mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-			pInfo->nRetry = 0;
-			put_char(pInfo, DLE);
-			flush(pInfo);
-			pInfo->bcc = 0;
-		}
-		break;
-	case R3964_RECEIVING:
-		if (pInfo->rx_position < RX_BUF_SIZE) {
-			pInfo->bcc ^= c;
-
-			if (c == DLE) {
-				if (pInfo->last_rx == DLE) {
-					pInfo->last_rx = 0;
-					goto char_to_buf;
-				}
-				pInfo->last_rx = DLE;
-				break;
-			} else if ((c == ETX) && (pInfo->last_rx == DLE)) {
-				if (pInfo->flags & R3964_BCC) {
-					pInfo->state = R3964_WAIT_FOR_BCC;
-					mod_timer(&pInfo->tmr,
-						  jiffies + R3964_TO_ZVZ);
-				} else {
-					on_receive_block(pInfo);
-				}
-			} else {
-				pInfo->last_rx = c;
-char_to_buf:
-				pInfo->rx_buf[pInfo->rx_position++] = c;
-				mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-			}
-		}
-		/* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
-		break;
-	case R3964_WAIT_FOR_BCC:
-		pInfo->last_rx = c;
-		on_receive_block(pInfo);
-		break;
-	}
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
-	switch (flag) {
-	case TTY_NORMAL:
-		break;
-	case TTY_BREAK:
-		TRACE_PE("received break");
-		pInfo->flags |= R3964_BREAK;
-		break;
-	case TTY_PARITY:
-		TRACE_PE("parity error");
-		pInfo->flags |= R3964_PARITY;
-		break;
-	case TTY_FRAME:
-		TRACE_PE("frame error");
-		pInfo->flags |= R3964_FRAME;
-		break;
-	case TTY_OVERRUN:
-		TRACE_PE("frame overrun");
-		pInfo->flags |= R3964_OVERRUN;
-		break;
-	default:
-		TRACE_PE("receive_error - unknown flag %d", flag);
-		pInfo->flags |= R3964_UNKNOWN;
-		break;
-	}
-}
-
-static void on_timeout(unsigned long priv)
-{
-	struct r3964_info *pInfo = (void *)priv;
-
-	switch (pInfo->state) {
-	case R3964_TX_REQUEST:
-		TRACE_PE("TX_REQUEST - timeout");
-		retry_transmit(pInfo);
-		break;
-	case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		retry_transmit(pInfo);
-		break;
-	case R3964_WAIT_FOR_TX_ACK:
-		TRACE_PE("WAIT_FOR_TX_ACK - timeout");
-		retry_transmit(pInfo);
-		break;
-	case R3964_WAIT_FOR_RX_BUF:
-		TRACE_PE("WAIT_FOR_RX_BUF - timeout");
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		pInfo->state = R3964_IDLE;
-		break;
-	case R3964_RECEIVING:
-		TRACE_PE("RECEIVING - timeout after %d chars",
-			 pInfo->rx_position);
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		pInfo->state = R3964_IDLE;
-		break;
-	case R3964_WAIT_FOR_RX_REPEAT:
-		TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
-		pInfo->state = R3964_IDLE;
-		break;
-	case R3964_WAIT_FOR_BCC:
-		TRACE_PE("WAIT_FOR_BCC - timeout");
-		put_char(pInfo, NAK);
-		flush(pInfo);
-		pInfo->state = R3964_IDLE;
-		break;
-	}
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
-		struct pid *pid)
-{
-	struct r3964_client_info *pClient;
-
-	for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-		if (pClient->pid == pid) {
-			return pClient;
-		}
-	}
-	return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
-	struct r3964_client_info *pClient;
-	struct r3964_client_info **ppClient;
-	struct r3964_message *pMsg;
-
-	if ((arg & R3964_SIG_ALL) == 0) {
-		/* Remove client from client list */
-		for (ppClient = &pInfo->firstClient; *ppClient;
-		     ppClient = &(*ppClient)->next) {
-			pClient = *ppClient;
-
-			if (pClient->pid == pid) {
-				TRACE_PS("removing client %d from client list",
-					 pid_nr(pid));
-				*ppClient = pClient->next;
-				while (pClient->msg_count) {
-					pMsg = remove_msg(pInfo, pClient);
-					if (pMsg) {
-						kfree(pMsg);
-						TRACE_M("enable_signals - msg "
-							"kfree %p", pMsg);
-					}
-				}
-				put_pid(pClient->pid);
-				kfree(pClient);
-				TRACE_M("enable_signals - kfree %p", pClient);
-				return 0;
-			}
-		}
-		return -EINVAL;
-	} else {
-		pClient = findClient(pInfo, pid);
-		if (pClient) {
-			/* update signal options */
-			pClient->sig_flags = arg;
-		} else {
-			/* add client to client list */
-			pClient = kmalloc(sizeof(struct r3964_client_info),
-					GFP_KERNEL);
-			TRACE_M("enable_signals - kmalloc %p", pClient);
-			if (pClient == NULL)
-				return -ENOMEM;
-
-			TRACE_PS("add client %d to client list", pid_nr(pid));
-			spin_lock_init(&pClient->lock);
-			pClient->sig_flags = arg;
-			pClient->pid = get_pid(pid);
-			pClient->next = pInfo->firstClient;
-			pClient->first_msg = NULL;
-			pClient->last_msg = NULL;
-			pClient->next_block_to_read = NULL;
-			pClient->msg_count = 0;
-			pInfo->firstClient = pClient;
-		}
-	}
-
-	return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-			 unsigned char __user * buf)
-{
-	struct r3964_client_info *pClient;
-	struct r3964_block_header *block;
-
-	if (!buf) {
-		return -EINVAL;
-	}
-
-	pClient = findClient(pInfo, pid);
-	if (pClient == NULL) {
-		return -EINVAL;
-	}
-
-	block = pClient->next_block_to_read;
-	if (!block) {
-		return 0;
-	} else {
-		if (copy_to_user(buf, block->data, block->length))
-			return -EFAULT;
-
-		remove_client_block(pInfo, pClient);
-		return block->length;
-	}
-
-	return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-		int error_code, struct r3964_block_header *pBlock)
-{
-	struct r3964_message *pMsg;
-	unsigned long flags;
-
-	if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
-		pMsg = kmalloc(sizeof(struct r3964_message),
-				error_code ? GFP_ATOMIC : GFP_KERNEL);
-		TRACE_M("add_msg - kmalloc %p", pMsg);
-		if (pMsg == NULL) {
-			return;
-		}
-
-		spin_lock_irqsave(&pClient->lock, flags);
-
-		pMsg->msg_id = msg_id;
-		pMsg->arg = arg;
-		pMsg->error_code = error_code;
-		pMsg->block = pBlock;
-		pMsg->next = NULL;
-
-		if (pClient->last_msg == NULL) {
-			pClient->first_msg = pClient->last_msg = pMsg;
-		} else {
-			pClient->last_msg->next = pMsg;
-			pClient->last_msg = pMsg;
-		}
-
-		pClient->msg_count++;
-
-		if (pBlock != NULL) {
-			pBlock->locks++;
-		}
-		spin_unlock_irqrestore(&pClient->lock, flags);
-	} else {
-		if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
-		    && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
-			pClient->last_msg->arg++;
-			TRACE_PE("add_msg - inc prev OVERFLOW-msg");
-		} else {
-			msg_id = R3964_MSG_ACK;
-			arg = 0;
-			error_code = R3964_OVERFLOW;
-			pBlock = NULL;
-			TRACE_PE("add_msg - queue OVERFLOW-msg");
-			goto queue_the_message;
-		}
-	}
-	/* Send SIGIO signal to client process: */
-	if (pClient->sig_flags & R3964_USE_SIGIO) {
-		kill_pid(pClient->pid, SIGIO, 1);
-	}
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-					struct r3964_client_info *pClient)
-{
-	struct r3964_message *pMsg = NULL;
-	unsigned long flags;
-
-	if (pClient->first_msg) {
-		spin_lock_irqsave(&pClient->lock, flags);
-
-		pMsg = pClient->first_msg;
-		pClient->first_msg = pMsg->next;
-		if (pClient->first_msg == NULL) {
-			pClient->last_msg = NULL;
-		}
-
-		pClient->msg_count--;
-		if (pMsg->block) {
-			remove_client_block(pInfo, pClient);
-			pClient->next_block_to_read = pMsg->block;
-		}
-		spin_unlock_irqrestore(&pClient->lock, flags);
-	}
-	return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
-				struct r3964_client_info *pClient)
-{
-	struct r3964_block_header *block;
-
-	TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
-	block = pClient->next_block_to_read;
-	if (block) {
-		block->locks--;
-		if (block->locks == 0) {
-			remove_from_rx_queue(pInfo, block);
-		}
-	}
-	pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
-	struct r3964_info *pInfo;
-
-	TRACE_L("open");
-	TRACE_L("tty=%p, PID=%d, disc_data=%p",
-		tty, current->pid, tty->disc_data);
-
-	pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
-	TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
-	if (!pInfo) {
-		printk(KERN_ERR "r3964: failed to alloc info structure\n");
-		return -ENOMEM;
-	}
-
-	pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
-	TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
-	if (!pInfo->rx_buf) {
-		printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
-		kfree(pInfo);
-		TRACE_M("r3964_open - info kfree %p", pInfo);
-		return -ENOMEM;
-	}
-
-	pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
-	TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
-	if (!pInfo->tx_buf) {
-		printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
-		kfree(pInfo->rx_buf);
-		TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
-		kfree(pInfo);
-		TRACE_M("r3964_open - info kfree %p", pInfo);
-		return -ENOMEM;
-	}
-
-	spin_lock_init(&pInfo->lock);
-	pInfo->tty = tty;
-	init_waitqueue_head(&pInfo->read_wait);
-	pInfo->priority = R3964_MASTER;
-	pInfo->rx_first = pInfo->rx_last = NULL;
-	pInfo->tx_first = pInfo->tx_last = NULL;
-	pInfo->rx_position = 0;
-	pInfo->tx_position = 0;
-	pInfo->last_rx = 0;
-	pInfo->blocks_in_rx_queue = 0;
-	pInfo->firstClient = NULL;
-	pInfo->state = R3964_IDLE;
-	pInfo->flags = R3964_DEBUG;
-	pInfo->nRetry = 0;
-
-	tty->disc_data = pInfo;
-	tty->receive_room = 65536;
-
-	setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
-
-	return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	struct r3964_client_info *pClient, *pNext;
-	struct r3964_message *pMsg;
-	struct r3964_block_header *pHeader, *pNextHeader;
-	unsigned long flags;
-
-	TRACE_L("close");
-
-	/*
-	 * Make sure that our task queue isn't activated.  If it
-	 * is, take it out of the linked list.
-	 */
-	del_timer_sync(&pInfo->tmr);
-
-	/* Remove client-structs and message queues: */
-	pClient = pInfo->firstClient;
-	while (pClient) {
-		pNext = pClient->next;
-		while (pClient->msg_count) {
-			pMsg = remove_msg(pInfo, pClient);
-			if (pMsg) {
-				kfree(pMsg);
-				TRACE_M("r3964_close - msg kfree %p", pMsg);
-			}
-		}
-		put_pid(pClient->pid);
-		kfree(pClient);
-		TRACE_M("r3964_close - client kfree %p", pClient);
-		pClient = pNext;
-	}
-	/* Remove jobs from tx_queue: */
-	spin_lock_irqsave(&pInfo->lock, flags);
-	pHeader = pInfo->tx_first;
-	pInfo->tx_first = pInfo->tx_last = NULL;
-	spin_unlock_irqrestore(&pInfo->lock, flags);
-
-	while (pHeader) {
-		pNextHeader = pHeader->next;
-		kfree(pHeader);
-		pHeader = pNextHeader;
-	}
-
-	/* Free buffers: */
-	wake_up_interruptible(&pInfo->read_wait);
-	kfree(pInfo->rx_buf);
-	TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
-	kfree(pInfo->tx_buf);
-	TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
-	kfree(pInfo);
-	TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-			  unsigned char __user * buf, size_t nr)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	struct r3964_client_info *pClient;
-	struct r3964_message *pMsg;
-	struct r3964_client_message theMsg;
-	int ret;
-
-	TRACE_L("read()");
-
-	tty_lock();
-
-	pClient = findClient(pInfo, task_pid(current));
-	if (pClient) {
-		pMsg = remove_msg(pInfo, pClient);
-		if (pMsg == NULL) {
-			/* no messages available. */
-			if (file->f_flags & O_NONBLOCK) {
-				ret = -EAGAIN;
-				goto unlock;
-			}
-			/* block until there is a message: */
-			wait_event_interruptible_tty(pInfo->read_wait,
-					(pMsg = remove_msg(pInfo, pClient)));
-		}
-
-		/* If we still haven't got a message, we must have been signalled */
-
-		if (!pMsg) {
-			ret = -EINTR;
-			goto unlock;
-		}
-
-		/* deliver msg to client process: */
-		theMsg.msg_id = pMsg->msg_id;
-		theMsg.arg = pMsg->arg;
-		theMsg.error_code = pMsg->error_code;
-		ret = sizeof(struct r3964_client_message);
-
-		kfree(pMsg);
-		TRACE_M("r3964_read - msg kfree %p", pMsg);
-
-		if (copy_to_user(buf, &theMsg, ret)) {
-			ret = -EFAULT;
-			goto unlock;
-		}
-
-		TRACE_PS("read - return %d", ret);
-		goto unlock;
-	}
-	ret = -EPERM;
-unlock:
-	tty_unlock();
-	return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-			   const unsigned char *data, size_t count)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	struct r3964_block_header *pHeader;
-	struct r3964_client_info *pClient;
-	unsigned char *new_data;
-
-	TRACE_L("write request, %d characters", count);
-/* 
- * Verify the pointers 
- */
-
-	if (!pInfo)
-		return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
-	if (count > R3964_MTU) {
-		if (pInfo->flags & R3964_DEBUG) {
-			TRACE_L(KERN_WARNING "r3964_write: truncating user "
-				"packet from %u to mtu %d", count, R3964_MTU);
-		}
-		count = R3964_MTU;
-	}
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
-	new_data = kmalloc(count + sizeof(struct r3964_block_header),
-			GFP_KERNEL);
-	TRACE_M("r3964_write - kmalloc %p", new_data);
-	if (new_data == NULL) {
-		if (pInfo->flags & R3964_DEBUG) {
-			printk(KERN_ERR "r3964_write: no memory\n");
-		}
-		return -ENOSPC;
-	}
-
-	pHeader = (struct r3964_block_header *)new_data;
-	pHeader->data = new_data + sizeof(struct r3964_block_header);
-	pHeader->length = count;
-	pHeader->locks = 0;
-	pHeader->owner = NULL;
-
-	tty_lock();
-
-	pClient = findClient(pInfo, task_pid(current));
-	if (pClient) {
-		pHeader->owner = pClient;
-	}
-
-	memcpy(pHeader->data, data, count);	/* We already verified this */
-
-	if (pInfo->flags & R3964_DEBUG) {
-		dump_block(pHeader->data, count);
-	}
-
-/*
- * Add buffer to transmit-queue:
- */
-	add_tx_queue(pInfo, pHeader);
-	trigger_transmit(pInfo);
-
-	tty_unlock();
-
-	return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-		unsigned int cmd, unsigned long arg)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	if (pInfo == NULL)
-		return -EINVAL;
-	switch (cmd) {
-	case R3964_ENABLE_SIGNALS:
-		return enable_signals(pInfo, task_pid(current), arg);
-	case R3964_SETPRIORITY:
-		if (arg < R3964_MASTER || arg > R3964_SLAVE)
-			return -EINVAL;
-		pInfo->priority = arg & 0xff;
-		return 0;
-	case R3964_USE_BCC:
-		if (arg)
-			pInfo->flags |= R3964_BCC;
-		else
-			pInfo->flags &= ~R3964_BCC;
-		return 0;
-	case R3964_READ_TELEGRAM:
-		return read_telegram(pInfo, task_pid(current),
-				(unsigned char __user *)arg);
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-	TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-			struct poll_table_struct *wait)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	struct r3964_client_info *pClient;
-	struct r3964_message *pMsg = NULL;
-	unsigned long flags;
-	int result = POLLOUT;
-
-	TRACE_L("POLL");
-
-	pClient = findClient(pInfo, task_pid(current));
-	if (pClient) {
-		poll_wait(file, &pInfo->read_wait, wait);
-		spin_lock_irqsave(&pInfo->lock, flags);
-		pMsg = pClient->first_msg;
-		spin_unlock_irqrestore(&pInfo->lock, flags);
-		if (pMsg)
-			result |= POLLIN | POLLRDNORM;
-	} else {
-		result = -EINVAL;
-	}
-	return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			char *fp, int count)
-{
-	struct r3964_info *pInfo = tty->disc_data;
-	const unsigned char *p;
-	char *f, flags = 0;
-	int i;
-
-	for (i = count, p = cp, f = fp; i; i--, p++) {
-		if (f)
-			flags = *f++;
-		if (flags == TTY_NORMAL) {
-			receive_char(pInfo, *p);
-		} else {
-			receive_error(pInfo, flags);
-		}
-
-	}
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
diff -druN linux-libre-2.6.36-gnu/drivers/char/n_tty.c linux-libre-2.6.37-gnu/drivers/char/n_tty.c
--- linux-libre-2.6.36-gnu/drivers/char/n_tty.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/n_tty.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,2121 +0,0 @@
-/*
- * n_tty.c --- implements the N_TTY line discipline.
- *
- * This code used to be in tty_io.c, but things are getting hairy
- * enough that it made sense to split things off.  (The N_TTY
- * processing has changed so much that it's hardly recognizable,
- * anyway...)
- *
- * Note that the open routine for N_TTY is guaranteed never to return
- * an error.  This is because Linux will fall back to setting a line
- * to N_TTY if it can not switch to any other line discipline.
- *
- * Written by Theodore Ts'o, Copyright 1994.
- *
- * This file also contains code originally written by Linus Torvalds,
- * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
- *
- * This file may be redistributed under the terms of the GNU General Public
- * License.
- *
- * Reduced memory usage for older ARM systems  - Russell King.
- *
- * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
- *		the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
- *		who actually finally proved there really was a race.
- *
- * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
- *		waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *		Also fixed a bug in BLOCKING mode where n_tty_write returns
- *		EAGAIN
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#include <asm/system.h>
-
-/* number of characters left in xmit buffer before select has we have room */
-#define WAKEUP_CHARS 256
-
-/*
- * This defines the low- and high-watermarks for throttling and
- * unthrottling the TTY driver.  These watermarks are used for
- * controlling the space in the read buffer.
- */
-#define TTY_THRESHOLD_THROTTLE		128 /* now based on remaining room */
-#define TTY_THRESHOLD_UNTHROTTLE 	128
-
-/*
- * Special byte codes used in the echo buffer to represent operations
- * or special handling of characters.  Bytes in the echo buffer that
- * are not part of such special blocks are treated as normal character
- * codes.
- */
-#define ECHO_OP_START 0xff
-#define ECHO_OP_MOVE_BACK_COL 0x80
-#define ECHO_OP_SET_CANON_COL 0x81
-#define ECHO_OP_ERASE_TAB 0x82
-
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
-			       unsigned char __user *ptr)
-{
-	tty_audit_add_data(tty, &x, 1);
-	return put_user(x, ptr);
-}
-
-/**
- *	n_tty_set__room	-	receive space
- *	@tty: terminal
- *
- *	Called by the driver to find out how much data it is
- *	permitted to feed to the line discipline without any being lost
- *	and thus to manage flow control. Not serialized. Answers for the
- *	"instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
-	/* tty->read_cnt is not read locked ? */
-	int	left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-	/*
-	 * If we are doing input canonicalization, and there are no
-	 * pending newlines, let characters through without limit, so
-	 * that erase characters will be handled.  Other excess
-	 * characters will be beeped.
-	 */
-	if (left <= 0)
-		left = tty->icanon && !tty->canon_data;
-	tty->receive_room = left;
-}
-
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
-{
-	if (tty->read_cnt < N_TTY_BUF_SIZE) {
-		tty->read_buf[tty->read_head] = c;
-		tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
-		tty->read_cnt++;
-	}
-}
-
-/**
- *	put_tty_queue		-	add character to tty
- *	@c: character
- *	@tty: tty device
- *
- *	Add a character to the tty read_buf queue. This is done under the
- *	read_lock to serialize character addition and also to protect us
- *	against parallel reads or flushes
- */
-
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
-{
-	unsigned long flags;
-	/*
-	 *	The problem of stomping on the buffers ends here.
-	 *	Why didn't anyone see this one coming? --AJK
-	*/
-	spin_lock_irqsave(&tty->read_lock, flags);
-	put_tty_queue_nolock(c, tty);
-	spin_unlock_irqrestore(&tty->read_lock, flags);
-}
-
-/**
- *	check_unthrottle	-	allow new receive data
- *	@tty; tty device
- *
- *	Check whether to call the driver unthrottle functions
- *
- *	Can sleep, may be called under the atomic_read_lock mutex but
- *	this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
-	if (tty->count)
-		tty_unthrottle(tty);
-}
-
-/**
- *	reset_buffer_flags	-	reset buffer state
- *	@tty: terminal to reset
- *
- *	Reset the read buffer counters, clear the flags,
- *	and make sure the driver is unthrottled. Called
- *	from n_tty_open() and n_tty_flush_buffer().
- *
- *	Locking: tty_read_lock for read fields.
- */
-
-static void reset_buffer_flags(struct tty_struct *tty)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->read_lock, flags);
-	tty->read_head = tty->read_tail = tty->read_cnt = 0;
-	spin_unlock_irqrestore(&tty->read_lock, flags);
-
-	mutex_lock(&tty->echo_lock);
-	tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
-	mutex_unlock(&tty->echo_lock);
-
-	tty->canon_head = tty->canon_data = tty->erasing = 0;
-	memset(&tty->read_flags, 0, sizeof tty->read_flags);
-	n_tty_set_room(tty);
-	check_unthrottle(tty);
-}
-
-/**
- *	n_tty_flush_buffer	-	clean input queue
- *	@tty:	terminal device
- *
- *	Flush the input buffer. Called when the line discipline is
- *	being closed, when the tty layer wants the buffer flushed (eg
- *	at hangup) or when the N_TTY line discipline internally has to
- *	clean the pending queue (for example some signals).
- *
- *	Locking: ctrl_lock, read_lock.
- */
-
-static void n_tty_flush_buffer(struct tty_struct *tty)
-{
-	unsigned long flags;
-	/* clear everything and unthrottle the driver */
-	reset_buffer_flags(tty);
-
-	if (!tty->link)
-		return;
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	if (tty->link->packet) {
-		tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-		wake_up_interruptible(&tty->link->read_wait);
-	}
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-}
-
-/**
- *	n_tty_chars_in_buffer	-	report available bytes
- *	@tty: tty device
- *
- *	Report the number of characters buffered to be delivered to user
- *	at this instant in time.
- *
- *	Locking: read_lock
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
-	unsigned long flags;
-	ssize_t n = 0;
-
-	spin_lock_irqsave(&tty->read_lock, flags);
-	if (!tty->icanon) {
-		n = tty->read_cnt;
-	} else if (tty->canon_data) {
-		n = (tty->canon_head > tty->read_tail) ?
-			tty->canon_head - tty->read_tail :
-			tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
-	}
-	spin_unlock_irqrestore(&tty->read_lock, flags);
-	return n;
-}
-
-/**
- *	is_utf8_continuation	-	utf8 multibyte check
- *	@c: byte to check
- *
- *	Returns true if the utf8 character 'c' is a multibyte continuation
- *	character. We use this to correctly compute the on screen size
- *	of the character when printing
- */
-
-static inline int is_utf8_continuation(unsigned char c)
-{
-	return (c & 0xc0) == 0x80;
-}
-
-/**
- *	is_continuation		-	multibyte check
- *	@c: byte to check
- *
- *	Returns true if the utf8 character 'c' is a multibyte continuation
- *	character and the terminal is in unicode mode.
- */
-
-static inline int is_continuation(unsigned char c, struct tty_struct *tty)
-{
-	return I_IUTF8(tty) && is_utf8_continuation(c);
-}
-
-/**
- *	do_output_char			-	output one character
- *	@c: character (or partial unicode symbol)
- *	@tty: terminal device
- *	@space: space available in tty driver write buffer
- *
- *	This is a helper function that handles one output character
- *	(including special characters like TAB, CR, LF, etc.),
- *	doing OPOST processing and putting the results in the
- *	tty driver's write buffer.
- *
- *	Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
- *	and NLDLY.  They simply aren't relevant in the world today.
- *	If you ever need them, add them here.
- *
- *	Returns the number of bytes of buffer space used or -1 if
- *	no space left.
- *
- *	Locking: should be called under the output_lock to protect
- *		 the column state and space left in the buffer
- */
-
-static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
-{
-	int	spaces;
-
-	if (!space)
-		return -1;
-
-	switch (c) {
-	case '\n':
-		if (O_ONLRET(tty))
-			tty->column = 0;
-		if (O_ONLCR(tty)) {
-			if (space < 2)
-				return -1;
-			tty->canon_column = tty->column = 0;
-			tty->ops->write(tty, "\r\n", 2);
-			return 2;
-		}
-		tty->canon_column = tty->column;
-		break;
-	case '\r':
-		if (O_ONOCR(tty) && tty->column == 0)
-			return 0;
-		if (O_OCRNL(tty)) {
-			c = '\n';
-			if (O_ONLRET(tty))
-				tty->canon_column = tty->column = 0;
-			break;
-		}
-		tty->canon_column = tty->column = 0;
-		break;
-	case '\t':
-		spaces = 8 - (tty->column & 7);
-		if (O_TABDLY(tty) == XTABS) {
-			if (space < spaces)
-				return -1;
-			tty->column += spaces;
-			tty->ops->write(tty, "        ", spaces);
-			return spaces;
-		}
-		tty->column += spaces;
-		break;
-	case '\b':
-		if (tty->column > 0)
-			tty->column--;
-		break;
-	default:
-		if (!iscntrl(c)) {
-			if (O_OLCUC(tty))
-				c = toupper(c);
-			if (!is_continuation(c, tty))
-				tty->column++;
-		}
-		break;
-	}
-
-	tty_put_char(tty, c);
-	return 1;
-}
-
-/**
- *	process_output			-	output post processor
- *	@c: character (or partial unicode symbol)
- *	@tty: terminal device
- *
- *	Output one character with OPOST processing.
- *	Returns -1 when the output device is full and the character
- *	must be retried.
- *
- *	Locking: output_lock to protect column state and space left
- *		 (also, this is called from n_tty_write under the
- *		  tty layer write lock)
- */
-
-static int process_output(unsigned char c, struct tty_struct *tty)
-{
-	int	space, retval;
-
-	mutex_lock(&tty->output_lock);
-
-	space = tty_write_room(tty);
-	retval = do_output_char(c, tty, space);
-
-	mutex_unlock(&tty->output_lock);
-	if (retval < 0)
-		return -1;
-	else
-		return 0;
-}
-
-/**
- *	process_output_block		-	block post processor
- *	@tty: terminal device
- *	@buf: character buffer
- *	@nr: number of bytes to output
- *
- *	Output a block of characters with OPOST processing.
- *	Returns the number of characters output.
- *
- *	This path is used to speed up block console writes, among other
- *	things when processing blocks of output data. It handles only
- *	the simple cases normally found and helps to generate blocks of
- *	symbols for the console driver and thus improve performance.
- *
- *	Locking: output_lock to protect column state and space left
- *		 (also, this is called from n_tty_write under the
- *		  tty layer write lock)
- */
-
-static ssize_t process_output_block(struct tty_struct *tty,
-				    const unsigned char *buf, unsigned int nr)
-{
-	int	space;
-	int 	i;
-	const unsigned char *cp;
-
-	mutex_lock(&tty->output_lock);
-
-	space = tty_write_room(tty);
-	if (!space) {
-		mutex_unlock(&tty->output_lock);
-		return 0;
-	}
-	if (nr > space)
-		nr = space;
-
-	for (i = 0, cp = buf; i < nr; i++, cp++) {
-		unsigned char c = *cp;
-
-		switch (c) {
-		case '\n':
-			if (O_ONLRET(tty))
-				tty->column = 0;
-			if (O_ONLCR(tty))
-				goto break_out;
-			tty->canon_column = tty->column;
-			break;
-		case '\r':
-			if (O_ONOCR(tty) && tty->column == 0)
-				goto break_out;
-			if (O_OCRNL(tty))
-				goto break_out;
-			tty->canon_column = tty->column = 0;
-			break;
-		case '\t':
-			goto break_out;
-		case '\b':
-			if (tty->column > 0)
-				tty->column--;
-			break;
-		default:
-			if (!iscntrl(c)) {
-				if (O_OLCUC(tty))
-					goto break_out;
-				if (!is_continuation(c, tty))
-					tty->column++;
-			}
-			break;
-		}
-	}
-break_out:
-	i = tty->ops->write(tty, buf, i);
-
-	mutex_unlock(&tty->output_lock);
-	return i;
-}
-
-/**
- *	process_echoes	-	write pending echo characters
- *	@tty: terminal device
- *
- *	Write previously buffered echo (and other ldisc-generated)
- *	characters to the tty.
- *
- *	Characters generated by the ldisc (including echoes) need to
- *	be buffered because the driver's write buffer can fill during
- *	heavy program output.  Echoing straight to the driver will
- *	often fail under these conditions, causing lost characters and
- *	resulting mismatches of ldisc state information.
- *
- *	Since the ldisc state must represent the characters actually sent
- *	to the driver at the time of the write, operations like certain
- *	changes in column state are also saved in the buffer and executed
- *	here.
- *
- *	A circular fifo buffer is used so that the most recent characters
- *	are prioritized.  Also, when control characters are echoed with a
- *	prefixed "^", the pair is treated atomically and thus not separated.
- *
- *	Locking: output_lock to protect column state and space left,
- *		 echo_lock to protect the echo buffer
- */
-
-static void process_echoes(struct tty_struct *tty)
-{
-	int	space, nr;
-	unsigned char c;
-	unsigned char *cp, *buf_end;
-
-	if (!tty->echo_cnt)
-		return;
-
-	mutex_lock(&tty->output_lock);
-	mutex_lock(&tty->echo_lock);
-
-	space = tty_write_room(tty);
-
-	buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
-	cp = tty->echo_buf + tty->echo_pos;
-	nr = tty->echo_cnt;
-	while (nr > 0) {
-		c = *cp;
-		if (c == ECHO_OP_START) {
-			unsigned char op;
-			unsigned char *opp;
-			int no_space_left = 0;
-
-			/*
-			 * If the buffer byte is the start of a multi-byte
-			 * operation, get the next byte, which is either the
-			 * op code or a control character value.
-			 */
-			opp = cp + 1;
-			if (opp == buf_end)
-				opp -= N_TTY_BUF_SIZE;
-			op = *opp;
-
-			switch (op) {
-				unsigned int num_chars, num_bs;
-
-			case ECHO_OP_ERASE_TAB:
-				if (++opp == buf_end)
-					opp -= N_TTY_BUF_SIZE;
-				num_chars = *opp;
-
-				/*
-				 * Determine how many columns to go back
-				 * in order to erase the tab.
-				 * This depends on the number of columns
-				 * used by other characters within the tab
-				 * area.  If this (modulo 8) count is from
-				 * the start of input rather than from a
-				 * previous tab, we offset by canon column.
-				 * Otherwise, tab spacing is normal.
-				 */
-				if (!(num_chars & 0x80))
-					num_chars += tty->canon_column;
-				num_bs = 8 - (num_chars & 7);
-
-				if (num_bs > space) {
-					no_space_left = 1;
-					break;
-				}
-				space -= num_bs;
-				while (num_bs--) {
-					tty_put_char(tty, '\b');
-					if (tty->column > 0)
-						tty->column--;
-				}
-				cp += 3;
-				nr -= 3;
-				break;
-
-			case ECHO_OP_SET_CANON_COL:
-				tty->canon_column = tty->column;
-				cp += 2;
-				nr -= 2;
-				break;
-
-			case ECHO_OP_MOVE_BACK_COL:
-				if (tty->column > 0)
-					tty->column--;
-				cp += 2;
-				nr -= 2;
-				break;
-
-			case ECHO_OP_START:
-				/* This is an escaped echo op start code */
-				if (!space) {
-					no_space_left = 1;
-					break;
-				}
-				tty_put_char(tty, ECHO_OP_START);
-				tty->column++;
-				space--;
-				cp += 2;
-				nr -= 2;
-				break;
-
-			default:
-				/*
-				 * If the op is not a special byte code,
-				 * it is a ctrl char tagged to be echoed
-				 * as "^X" (where X is the letter
-				 * representing the control char).
-				 * Note that we must ensure there is
-				 * enough space for the whole ctrl pair.
-				 *
-				 */
-				if (space < 2) {
-					no_space_left = 1;
-					break;
-				}
-				tty_put_char(tty, '^');
-				tty_put_char(tty, op ^ 0100);
-				tty->column += 2;
-				space -= 2;
-				cp += 2;
-				nr -= 2;
-			}
-
-			if (no_space_left)
-				break;
-		} else {
-			if (O_OPOST(tty) &&
-			    !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-				int retval = do_output_char(c, tty, space);
-				if (retval < 0)
-					break;
-				space -= retval;
-			} else {
-				if (!space)
-					break;
-				tty_put_char(tty, c);
-				space -= 1;
-			}
-			cp += 1;
-			nr -= 1;
-		}
-
-		/* When end of circular buffer reached, wrap around */
-		if (cp >= buf_end)
-			cp -= N_TTY_BUF_SIZE;
-	}
-
-	if (nr == 0) {
-		tty->echo_pos = 0;
-		tty->echo_cnt = 0;
-		tty->echo_overrun = 0;
-	} else {
-		int num_processed = tty->echo_cnt - nr;
-		tty->echo_pos += num_processed;
-		tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-		tty->echo_cnt = nr;
-		if (num_processed > 0)
-			tty->echo_overrun = 0;
-	}
-
-	mutex_unlock(&tty->echo_lock);
-	mutex_unlock(&tty->output_lock);
-
-	if (tty->ops->flush_chars)
-		tty->ops->flush_chars(tty);
-}
-
-/**
- *	add_echo_byte	-	add a byte to the echo buffer
- *	@c: unicode byte to echo
- *	@tty: terminal device
- *
- *	Add a character or operation byte to the echo buffer.
- *
- *	Should be called under the echo lock to protect the echo buffer.
- */
-
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
-{
-	int	new_byte_pos;
-
-	if (tty->echo_cnt == N_TTY_BUF_SIZE) {
-		/* Circular buffer is already at capacity */
-		new_byte_pos = tty->echo_pos;
-
-		/*
-		 * Since the buffer start position needs to be advanced,
-		 * be sure to step by a whole operation byte group.
-		 */
-		if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
-			if (tty->echo_buf[(tty->echo_pos + 1) &
-					  (N_TTY_BUF_SIZE - 1)] ==
-						ECHO_OP_ERASE_TAB) {
-				tty->echo_pos += 3;
-				tty->echo_cnt -= 2;
-			} else {
-				tty->echo_pos += 2;
-				tty->echo_cnt -= 1;
-			}
-		} else {
-			tty->echo_pos++;
-		}
-		tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-
-		tty->echo_overrun = 1;
-	} else {
-		new_byte_pos = tty->echo_pos + tty->echo_cnt;
-		new_byte_pos &= N_TTY_BUF_SIZE - 1;
-		tty->echo_cnt++;
-	}
-
-	tty->echo_buf[new_byte_pos] = c;
-}
-
-/**
- *	echo_move_back_col	-	add operation to move back a column
- *	@tty: terminal device
- *
- *	Add an operation to the echo buffer to move back one column.
- *
- *	Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_move_back_col(struct tty_struct *tty)
-{
-	mutex_lock(&tty->echo_lock);
-
-	add_echo_byte(ECHO_OP_START, tty);
-	add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
-	mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *	echo_set_canon_col	-	add operation to set the canon column
- *	@tty: terminal device
- *
- *	Add an operation to the echo buffer to set the canon column
- *	to the current column.
- *
- *	Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_set_canon_col(struct tty_struct *tty)
-{
-	mutex_lock(&tty->echo_lock);
-
-	add_echo_byte(ECHO_OP_START, tty);
-	add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
-	mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *	echo_erase_tab	-	add operation to erase a tab
- *	@num_chars: number of character columns already used
- *	@after_tab: true if num_chars starts after a previous tab
- *	@tty: terminal device
- *
- *	Add an operation to the echo buffer to erase a tab.
- *
- *	Called by the eraser function, which knows how many character
- *	columns have been used since either a previous tab or the start
- *	of input.  This information will be used later, along with
- *	canon column (if applicable), to go back the correct number
- *	of columns.
- *
- *	Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_erase_tab(unsigned int num_chars, int after_tab,
-			   struct tty_struct *tty)
-{
-	mutex_lock(&tty->echo_lock);
-
-	add_echo_byte(ECHO_OP_START, tty);
-	add_echo_byte(ECHO_OP_ERASE_TAB, tty);
-
-	/* We only need to know this modulo 8 (tab spacing) */
-	num_chars &= 7;
-
-	/* Set the high bit as a flag if num_chars is after a previous tab */
-	if (after_tab)
-		num_chars |= 0x80;
-
-	add_echo_byte(num_chars, tty);
-
-	mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *	echo_char_raw	-	echo a character raw
- *	@c: unicode byte to echo
- *	@tty: terminal device
- *
- *	Echo user input back onto the screen. This must be called only when
- *	L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *	This variant does not treat control characters specially.
- *
- *	Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
-{
-	mutex_lock(&tty->echo_lock);
-
-	if (c == ECHO_OP_START) {
-		add_echo_byte(ECHO_OP_START, tty);
-		add_echo_byte(ECHO_OP_START, tty);
-	} else {
-		add_echo_byte(c, tty);
-	}
-
-	mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *	echo_char	-	echo a character
- *	@c: unicode byte to echo
- *	@tty: terminal device
- *
- *	Echo user input back onto the screen. This must be called only when
- *	L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *	This variant tags control characters to be echoed as "^X"
- *	(where X is the letter representing the control char).
- *
- *	Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char(unsigned char c, struct tty_struct *tty)
-{
-	mutex_lock(&tty->echo_lock);
-
-	if (c == ECHO_OP_START) {
-		add_echo_byte(ECHO_OP_START, tty);
-		add_echo_byte(ECHO_OP_START, tty);
-	} else {
-		if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
-			add_echo_byte(ECHO_OP_START, tty);
-		add_echo_byte(c, tty);
-	}
-
-	mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *	finish_erasing		-	complete erase
- *	@tty: tty doing the erase
- */
-
-static inline void finish_erasing(struct tty_struct *tty)
-{
-	if (tty->erasing) {
-		echo_char_raw('/', tty);
-		tty->erasing = 0;
-	}
-}
-
-/**
- *	eraser		-	handle erase function
- *	@c: character input
- *	@tty: terminal device
- *
- *	Perform erase and necessary output when an erase character is
- *	present in the stream from the driver layer. Handles the complexities
- *	of UTF-8 multibyte symbols.
- *
- *	Locking: read_lock for tty buffers
- */
-
-static void eraser(unsigned char c, struct tty_struct *tty)
-{
-	enum { ERASE, WERASE, KILL } kill_type;
-	int head, seen_alnums, cnt;
-	unsigned long flags;
-
-	/* FIXME: locking needed ? */
-	if (tty->read_head == tty->canon_head) {
-		/* process_output('\a', tty); */ /* what do you think? */
-		return;
-	}
-	if (c == ERASE_CHAR(tty))
-		kill_type = ERASE;
-	else if (c == WERASE_CHAR(tty))
-		kill_type = WERASE;
-	else {
-		if (!L_ECHO(tty)) {
-			spin_lock_irqsave(&tty->read_lock, flags);
-			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-					  (N_TTY_BUF_SIZE - 1));
-			tty->read_head = tty->canon_head;
-			spin_unlock_irqrestore(&tty->read_lock, flags);
-			return;
-		}
-		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
-			spin_lock_irqsave(&tty->read_lock, flags);
-			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-					  (N_TTY_BUF_SIZE - 1));
-			tty->read_head = tty->canon_head;
-			spin_unlock_irqrestore(&tty->read_lock, flags);
-			finish_erasing(tty);
-			echo_char(KILL_CHAR(tty), tty);
-			/* Add a newline if ECHOK is on and ECHOKE is off. */
-			if (L_ECHOK(tty))
-				echo_char_raw('\n', tty);
-			return;
-		}
-		kill_type = KILL;
-	}
-
-	seen_alnums = 0;
-	/* FIXME: Locking ?? */
-	while (tty->read_head != tty->canon_head) {
-		head = tty->read_head;
-
-		/* erase a single possibly multibyte character */
-		do {
-			head = (head - 1) & (N_TTY_BUF_SIZE-1);
-			c = tty->read_buf[head];
-		} while (is_continuation(c, tty) && head != tty->canon_head);
-
-		/* do not partially erase */
-		if (is_continuation(c, tty))
-			break;
-
-		if (kill_type == WERASE) {
-			/* Equivalent to BSD's ALTWERASE. */
-			if (isalnum(c) || c == '_')
-				seen_alnums++;
-			else if (seen_alnums)
-				break;
-		}
-		cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
-		spin_lock_irqsave(&tty->read_lock, flags);
-		tty->read_head = head;
-		tty->read_cnt -= cnt;
-		spin_unlock_irqrestore(&tty->read_lock, flags);
-		if (L_ECHO(tty)) {
-			if (L_ECHOPRT(tty)) {
-				if (!tty->erasing) {
-					echo_char_raw('\\', tty);
-					tty->erasing = 1;
-				}
-				/* if cnt > 1, output a multi-byte character */
-				echo_char(c, tty);
-				while (--cnt > 0) {
-					head = (head+1) & (N_TTY_BUF_SIZE-1);
-					echo_char_raw(tty->read_buf[head], tty);
-					echo_move_back_col(tty);
-				}
-			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
-				echo_char(ERASE_CHAR(tty), tty);
-			} else if (c == '\t') {
-				unsigned int num_chars = 0;
-				int after_tab = 0;
-				unsigned long tail = tty->read_head;
-
-				/*
-				 * Count the columns used for characters
-				 * since the start of input or after a
-				 * previous tab.
-				 * This info is used to go back the correct
-				 * number of columns.
-				 */
-				while (tail != tty->canon_head) {
-					tail = (tail-1) & (N_TTY_BUF_SIZE-1);
-					c = tty->read_buf[tail];
-					if (c == '\t') {
-						after_tab = 1;
-						break;
-					} else if (iscntrl(c)) {
-						if (L_ECHOCTL(tty))
-							num_chars += 2;
-					} else if (!is_continuation(c, tty)) {
-						num_chars++;
-					}
-				}
-				echo_erase_tab(num_chars, after_tab, tty);
-			} else {
-				if (iscntrl(c) && L_ECHOCTL(tty)) {
-					echo_char_raw('\b', tty);
-					echo_char_raw(' ', tty);
-					echo_char_raw('\b', tty);
-				}
-				if (!iscntrl(c) || L_ECHOCTL(tty)) {
-					echo_char_raw('\b', tty);
-					echo_char_raw(' ', tty);
-					echo_char_raw('\b', tty);
-				}
-			}
-		}
-		if (kill_type == ERASE)
-			break;
-	}
-	if (tty->read_head == tty->canon_head && L_ECHO(tty))
-		finish_erasing(tty);
-}
-
-/**
- *	isig		-	handle the ISIG optio
- *	@sig: signal
- *	@tty: terminal
- *	@flush: force flush
- *
- *	Called when a signal is being sent due to terminal input. This
- *	may caus terminal flushing to take place according to the termios
- *	settings and character used. Called from the driver receive_buf
- *	path so serialized.
- *
- *	Locking: ctrl_lock, read_lock (both via flush buffer)
- */
-
-static inline void isig(int sig, struct tty_struct *tty, int flush)
-{
-	if (tty->pgrp)
-		kill_pgrp(tty->pgrp, sig, 1);
-	if (flush || !L_NOFLSH(tty)) {
-		n_tty_flush_buffer(tty);
-		tty_driver_flush_buffer(tty);
-	}
-}
-
-/**
- *	n_tty_receive_break	-	handle break
- *	@tty: terminal
- *
- *	An RS232 break event has been hit in the incoming bitstream. This
- *	can cause a variety of events depending upon the termios settings.
- *
- *	Called from the receive_buf path so single threaded.
- */
-
-static inline void n_tty_receive_break(struct tty_struct *tty)
-{
-	if (I_IGNBRK(tty))
-		return;
-	if (I_BRKINT(tty)) {
-		isig(SIGINT, tty, 1);
-		return;
-	}
-	if (I_PARMRK(tty)) {
-		put_tty_queue('\377', tty);
-		put_tty_queue('\0', tty);
-	}
-	put_tty_queue('\0', tty);
-	wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *	n_tty_receive_overrun	-	handle overrun reporting
- *	@tty: terminal
- *
- *	Data arrived faster than we could process it. While the tty
- *	driver has flagged this the bits that were missed are gone
- *	forever.
- *
- *	Called from the receive_buf path so single threaded. Does not
- *	need locking as num_overrun and overrun_time are function
- *	private.
- */
-
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
-{
-	char buf[64];
-
-	tty->num_overrun++;
-	if (time_before(tty->overrun_time, jiffies - HZ) ||
-			time_after(tty->overrun_time, jiffies)) {
-		printk(KERN_WARNING "%s: %d input overrun(s)\n",
-			tty_name(tty, buf),
-			tty->num_overrun);
-		tty->overrun_time = jiffies;
-		tty->num_overrun = 0;
-	}
-}
-
-/**
- *	n_tty_receive_parity_error	-	error notifier
- *	@tty: terminal device
- *	@c: character
- *
- *	Process a parity error and queue the right data to indicate
- *	the error case if necessary. Locking as per n_tty_receive_buf.
- */
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
-					      unsigned char c)
-{
-	if (I_IGNPAR(tty))
-		return;
-	if (I_PARMRK(tty)) {
-		put_tty_queue('\377', tty);
-		put_tty_queue('\0', tty);
-		put_tty_queue(c, tty);
-	} else	if (I_INPCK(tty))
-		put_tty_queue('\0', tty);
-	else
-		put_tty_queue(c, tty);
-	wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *	n_tty_receive_char	-	perform processing
- *	@tty: terminal device
- *	@c: character
- *
- *	Process an individual character of input received from the driver.
- *	This is serialized with respect to itself by the rules for the
- *	driver above.
- */
-
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
-	unsigned long flags;
-	int parmrk;
-
-	if (tty->raw) {
-		put_tty_queue(c, tty);
-		return;
-	}
-
-	if (I_ISTRIP(tty))
-		c &= 0x7f;
-	if (I_IUCLC(tty) && L_IEXTEN(tty))
-		c = tolower(c);
-
-	if (L_EXTPROC(tty)) {
-		put_tty_queue(c, tty);
-		return;
-	}
-
-	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-	    I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
-	    c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
-		start_tty(tty);
-		process_echoes(tty);
-	}
-
-	if (tty->closing) {
-		if (I_IXON(tty)) {
-			if (c == START_CHAR(tty)) {
-				start_tty(tty);
-				process_echoes(tty);
-			} else if (c == STOP_CHAR(tty))
-				stop_tty(tty);
-		}
-		return;
-	}
-
-	/*
-	 * If the previous character was LNEXT, or we know that this
-	 * character is not one of the characters that we'll have to
-	 * handle specially, do shortcut processing to speed things
-	 * up.
-	 */
-	if (!test_bit(c, tty->process_char_map) || tty->lnext) {
-		tty->lnext = 0;
-		parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-		if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-			/* beep if no space */
-			if (L_ECHO(tty))
-				process_output('\a', tty);
-			return;
-		}
-		if (L_ECHO(tty)) {
-			finish_erasing(tty);
-			/* Record the column of first canon char. */
-			if (tty->canon_head == tty->read_head)
-				echo_set_canon_col(tty);
-			echo_char(c, tty);
-			process_echoes(tty);
-		}
-		if (parmrk)
-			put_tty_queue(c, tty);
-		put_tty_queue(c, tty);
-		return;
-	}
-
-	if (I_IXON(tty)) {
-		if (c == START_CHAR(tty)) {
-			start_tty(tty);
-			process_echoes(tty);
-			return;
-		}
-		if (c == STOP_CHAR(tty)) {
-			stop_tty(tty);
-			return;
-		}
-	}
-
-	if (L_ISIG(tty)) {
-		int signal;
-		signal = SIGINT;
-		if (c == INTR_CHAR(tty))
-			goto send_signal;
-		signal = SIGQUIT;
-		if (c == QUIT_CHAR(tty))
-			goto send_signal;
-		signal = SIGTSTP;
-		if (c == SUSP_CHAR(tty)) {
-send_signal:
-			/*
-			 * Note that we do not use isig() here because we want
-			 * the order to be:
-			 * 1) flush, 2) echo, 3) signal
-			 */
-			if (!L_NOFLSH(tty)) {
-				n_tty_flush_buffer(tty);
-				tty_driver_flush_buffer(tty);
-			}
-			if (I_IXON(tty))
-				start_tty(tty);
-			if (L_ECHO(tty)) {
-				echo_char(c, tty);
-				process_echoes(tty);
-			}
-			if (tty->pgrp)
-				kill_pgrp(tty->pgrp, signal, 1);
-			return;
-		}
-	}
-
-	if (c == '\r') {
-		if (I_IGNCR(tty))
-			return;
-		if (I_ICRNL(tty))
-			c = '\n';
-	} else if (c == '\n' && I_INLCR(tty))
-		c = '\r';
-
-	if (tty->icanon) {
-		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
-		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
-			eraser(c, tty);
-			process_echoes(tty);
-			return;
-		}
-		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
-			tty->lnext = 1;
-			if (L_ECHO(tty)) {
-				finish_erasing(tty);
-				if (L_ECHOCTL(tty)) {
-					echo_char_raw('^', tty);
-					echo_char_raw('\b', tty);
-					process_echoes(tty);
-				}
-			}
-			return;
-		}
-		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
-		    L_IEXTEN(tty)) {
-			unsigned long tail = tty->canon_head;
-
-			finish_erasing(tty);
-			echo_char(c, tty);
-			echo_char_raw('\n', tty);
-			while (tail != tty->read_head) {
-				echo_char(tty->read_buf[tail], tty);
-				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-			}
-			process_echoes(tty);
-			return;
-		}
-		if (c == '\n') {
-			if (tty->read_cnt >= N_TTY_BUF_SIZE) {
-				if (L_ECHO(tty))
-					process_output('\a', tty);
-				return;
-			}
-			if (L_ECHO(tty) || L_ECHONL(tty)) {
-				echo_char_raw('\n', tty);
-				process_echoes(tty);
-			}
-			goto handle_newline;
-		}
-		if (c == EOF_CHAR(tty)) {
-			if (tty->read_cnt >= N_TTY_BUF_SIZE)
-				return;
-			if (tty->canon_head != tty->read_head)
-				set_bit(TTY_PUSH, &tty->flags);
-			c = __DISABLED_CHAR;
-			goto handle_newline;
-		}
-		if ((c == EOL_CHAR(tty)) ||
-		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
-			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
-				 ? 1 : 0;
-			if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-				if (L_ECHO(tty))
-					process_output('\a', tty);
-				return;
-			}
-			/*
-			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
-			 */
-			if (L_ECHO(tty)) {
-				/* Record the column of first canon char. */
-				if (tty->canon_head == tty->read_head)
-					echo_set_canon_col(tty);
-				echo_char(c, tty);
-				process_echoes(tty);
-			}
-			/*
-			 * XXX does PARMRK doubling happen for
-			 * EOL_CHAR and EOL2_CHAR?
-			 */
-			if (parmrk)
-				put_tty_queue(c, tty);
-
-handle_newline:
-			spin_lock_irqsave(&tty->read_lock, flags);
-			set_bit(tty->read_head, tty->read_flags);
-			put_tty_queue_nolock(c, tty);
-			tty->canon_head = tty->read_head;
-			tty->canon_data++;
-			spin_unlock_irqrestore(&tty->read_lock, flags);
-			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-			if (waitqueue_active(&tty->read_wait))
-				wake_up_interruptible(&tty->read_wait);
-			return;
-		}
-	}
-
-	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-	if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-		/* beep if no space */
-		if (L_ECHO(tty))
-			process_output('\a', tty);
-		return;
-	}
-	if (L_ECHO(tty)) {
-		finish_erasing(tty);
-		if (c == '\n')
-			echo_char_raw('\n', tty);
-		else {
-			/* Record the column of first canon char. */
-			if (tty->canon_head == tty->read_head)
-				echo_set_canon_col(tty);
-			echo_char(c, tty);
-		}
-		process_echoes(tty);
-	}
-
-	if (parmrk)
-		put_tty_queue(c, tty);
-
-	put_tty_queue(c, tty);
-}
-
-
-/**
- *	n_tty_write_wakeup	-	asynchronous I/O notifier
- *	@tty: tty device
- *
- *	Required for the ptys, serial driver etc. since processes
- *	that attach themselves to the master and rely on ASYNC
- *	IO must be woken up
- */
-
-static void n_tty_write_wakeup(struct tty_struct *tty)
-{
-	if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
-		kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-}
-
-/**
- *	n_tty_receive_buf	-	data receive
- *	@tty: terminal device
- *	@cp: buffer
- *	@fp: flag buffer
- *	@count: characters
- *
- *	Called by the terminal driver when a block of characters has
- *	been received. This function must be called from soft contexts
- *	not from interrupt context. The driver is responsible for making
- *	calls one at a time and in order (or using flush_to_ldisc)
- */
-
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-			      char *fp, int count)
-{
-	const unsigned char *p;
-	char *f, flags = TTY_NORMAL;
-	int	i;
-	char	buf[64];
-	unsigned long cpuflags;
-
-	if (!tty->read_buf)
-		return;
-
-	if (tty->real_raw) {
-		spin_lock_irqsave(&tty->read_lock, cpuflags);
-		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-			N_TTY_BUF_SIZE - tty->read_head);
-		i = min(count, i);
-		memcpy(tty->read_buf + tty->read_head, cp, i);
-		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-		tty->read_cnt += i;
-		cp += i;
-		count -= i;
-
-		i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-			N_TTY_BUF_SIZE - tty->read_head);
-		i = min(count, i);
-		memcpy(tty->read_buf + tty->read_head, cp, i);
-		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-		tty->read_cnt += i;
-		spin_unlock_irqrestore(&tty->read_lock, cpuflags);
-	} else {
-		for (i = count, p = cp, f = fp; i; i--, p++) {
-			if (f)
-				flags = *f++;
-			switch (flags) {
-			case TTY_NORMAL:
-				n_tty_receive_char(tty, *p);
-				break;
-			case TTY_BREAK:
-				n_tty_receive_break(tty);
-				break;
-			case TTY_PARITY:
-			case TTY_FRAME:
-				n_tty_receive_parity_error(tty, *p);
-				break;
-			case TTY_OVERRUN:
-				n_tty_receive_overrun(tty);
-				break;
-			default:
-				printk(KERN_ERR "%s: unknown flag %d\n",
-				       tty_name(tty, buf), flags);
-				break;
-			}
-		}
-		if (tty->ops->flush_chars)
-			tty->ops->flush_chars(tty);
-	}
-
-	n_tty_set_room(tty);
-
-	if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
-		L_EXTPROC(tty)) {
-		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-		if (waitqueue_active(&tty->read_wait))
-			wake_up_interruptible(&tty->read_wait);
-	}
-
-	/*
-	 * Check the remaining room for the input canonicalization
-	 * mode.  We don't want to throttle the driver if we're in
-	 * canonical mode and don't have a newline yet!
-	 */
-	if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
-		tty_throttle(tty);
-}
-
-int is_ignored(int sig)
-{
-	return (sigismember(&current->blocked, sig) ||
-		current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
-/**
- *	n_tty_set_termios	-	termios data changed
- *	@tty: terminal
- *	@old: previous data
- *
- *	Called by the tty layer when the user changes termios flags so
- *	that the line discipline can plan ahead. This function cannot sleep
- *	and is protected from re-entry by the tty layer. The user is
- *	guaranteed that this function will not be re-entered or in progress
- *	when the ldisc is closed.
- *
- *	Locking: Caller holds tty->termios_mutex
- */
-
-static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-	int canon_change = 1;
-	BUG_ON(!tty);
-
-	if (old)
-		canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
-	if (canon_change) {
-		memset(&tty->read_flags, 0, sizeof tty->read_flags);
-		tty->canon_head = tty->read_tail;
-		tty->canon_data = 0;
-		tty->erasing = 0;
-	}
-
-	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-		wake_up_interruptible(&tty->read_wait);
-
-	tty->icanon = (L_ICANON(tty) != 0);
-	if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
-		tty->raw = 1;
-		tty->real_raw = 1;
-		n_tty_set_room(tty);
-		return;
-	}
-	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
-	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
-	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
-	    I_PARMRK(tty)) {
-		memset(tty->process_char_map, 0, 256/8);
-
-		if (I_IGNCR(tty) || I_ICRNL(tty))
-			set_bit('\r', tty->process_char_map);
-		if (I_INLCR(tty))
-			set_bit('\n', tty->process_char_map);
-
-		if (L_ICANON(tty)) {
-			set_bit(ERASE_CHAR(tty), tty->process_char_map);
-			set_bit(KILL_CHAR(tty), tty->process_char_map);
-			set_bit(EOF_CHAR(tty), tty->process_char_map);
-			set_bit('\n', tty->process_char_map);
-			set_bit(EOL_CHAR(tty), tty->process_char_map);
-			if (L_IEXTEN(tty)) {
-				set_bit(WERASE_CHAR(tty),
-					tty->process_char_map);
-				set_bit(LNEXT_CHAR(tty),
-					tty->process_char_map);
-				set_bit(EOL2_CHAR(tty),
-					tty->process_char_map);
-				if (L_ECHO(tty))
-					set_bit(REPRINT_CHAR(tty),
-						tty->process_char_map);
-			}
-		}
-		if (I_IXON(tty)) {
-			set_bit(START_CHAR(tty), tty->process_char_map);
-			set_bit(STOP_CHAR(tty), tty->process_char_map);
-		}
-		if (L_ISIG(tty)) {
-			set_bit(INTR_CHAR(tty), tty->process_char_map);
-			set_bit(QUIT_CHAR(tty), tty->process_char_map);
-			set_bit(SUSP_CHAR(tty), tty->process_char_map);
-		}
-		clear_bit(__DISABLED_CHAR, tty->process_char_map);
-		tty->raw = 0;
-		tty->real_raw = 0;
-	} else {
-		tty->raw = 1;
-		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
-		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&
-		    (tty->driver->flags & TTY_DRIVER_REAL_RAW))
-			tty->real_raw = 1;
-		else
-			tty->real_raw = 0;
-	}
-	n_tty_set_room(tty);
-	/* The termios change make the tty ready for I/O */
-	wake_up_interruptible(&tty->write_wait);
-	wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *	n_tty_close		-	close the ldisc for this tty
- *	@tty: device
- *
- *	Called from the terminal layer when this line discipline is
- *	being shut down, either because of a close or becsuse of a
- *	discipline change. The function will not be called while other
- *	ldisc methods are in progress.
- */
-
-static void n_tty_close(struct tty_struct *tty)
-{
-	n_tty_flush_buffer(tty);
-	if (tty->read_buf) {
-		kfree(tty->read_buf);
-		tty->read_buf = NULL;
-	}
-	if (tty->echo_buf) {
-		kfree(tty->echo_buf);
-		tty->echo_buf = NULL;
-	}
-}
-
-/**
- *	n_tty_open		-	open an ldisc
- *	@tty: terminal to open
- *
- *	Called when this line discipline is being attached to the
- *	terminal device. Can sleep. Called serialized so that no
- *	other events will occur in parallel. No further open will occur
- *	until a close.
- */
-
-static int n_tty_open(struct tty_struct *tty)
-{
-	if (!tty)
-		return -EINVAL;
-
-	/* These are ugly. Currently a malloc failure here can panic */
-	if (!tty->read_buf) {
-		tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-		if (!tty->read_buf)
-			return -ENOMEM;
-	}
-	if (!tty->echo_buf) {
-		tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-
-		if (!tty->echo_buf)
-			return -ENOMEM;
-	}
-	reset_buffer_flags(tty);
-	tty->column = 0;
-	n_tty_set_termios(tty, NULL);
-	tty->minimum_to_wake = 1;
-	tty->closing = 0;
-	return 0;
-}
-
-static inline int input_available_p(struct tty_struct *tty, int amt)
-{
-	tty_flush_to_ldisc(tty);
-	if (tty->icanon && !L_EXTPROC(tty)) {
-		if (tty->canon_data)
-			return 1;
-	} else if (tty->read_cnt >= (amt ? amt : 1))
-		return 1;
-
-	return 0;
-}
-
-/**
- * 	copy_from_read_buf	-	copy read data directly
- *	@tty: terminal device
- *	@b: user data
- *	@nr: size of data
- *
- *	Helper function to speed up n_tty_read.  It is only called when
- *	ICANON is off; it copies characters straight from the tty queue to
- *	user space directly.  It can be profitably called twice; once to
- *	drain the space from the tail pointer to the (physical) end of the
- *	buffer, and once to drain the space from the (physical) beginning of
- *	the buffer to head pointer.
- *
- *	Called under the tty->atomic_read_lock sem
- *
- */
-
-static int copy_from_read_buf(struct tty_struct *tty,
-				      unsigned char __user **b,
-				      size_t *nr)
-
-{
-	int retval;
-	size_t n;
-	unsigned long flags;
-
-	retval = 0;
-	spin_lock_irqsave(&tty->read_lock, flags);
-	n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
-	n = min(*nr, n);
-	spin_unlock_irqrestore(&tty->read_lock, flags);
-	if (n) {
-		retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
-		n -= retval;
-		tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
-		spin_lock_irqsave(&tty->read_lock, flags);
-		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
-		tty->read_cnt -= n;
-		/* Turn single EOF into zero-length read */
-		if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-			if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-				n--;
-		}
-		spin_unlock_irqrestore(&tty->read_lock, flags);
-		*b += n;
-		*nr -= n;
-	}
-	return retval;
-}
-
-extern ssize_t redirected_tty_write(struct file *, const char __user *,
-							size_t, loff_t *);
-
-/**
- *	job_control		-	check job control
- *	@tty: tty
- *	@file: file handle
- *
- *	Perform job control management checks on this file/tty descriptor
- *	and if appropriate send any needed signals and return a negative
- *	error code if action should be taken.
- *
- *	FIXME:
- *	Locking: None - redirected write test is safe, testing
- *	current->signal should possibly lock current->sighand
- *	pgrp locking ?
- */
-
-static int job_control(struct tty_struct *tty, struct file *file)
-{
-	/* Job control check -- must be done at start and after
-	   every sleep (POSIX.1 7.1.1.4). */
-	/* NOTE: not yet done after every sleep pending a thorough
-	   check of the logic of this change. -- jlc */
-	/* don't stop on /dev/console */
-	if (file->f_op->write != redirected_tty_write &&
-	    current->signal->tty == tty) {
-		if (!tty->pgrp)
-			printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-		else if (task_pgrp(current) != tty->pgrp) {
-			if (is_ignored(SIGTTIN) ||
-			    is_current_pgrp_orphaned())
-				return -EIO;
-			kill_pgrp(task_pgrp(current), SIGTTIN, 1);
-			set_thread_flag(TIF_SIGPENDING);
-			return -ERESTARTSYS;
-		}
-	}
-	return 0;
-}
-
-
-/**
- *	n_tty_read		-	read function for tty
- *	@tty: tty device
- *	@file: file object
- *	@buf: userspace buffer pointer
- *	@nr: size of I/O
- *
- *	Perform reads for the line discipline. We are guaranteed that the
- *	line discipline will not be closed under us but we may get multiple
- *	parallel readers and must handle this ourselves. We may also get
- *	a hangup. Always called in user context, may sleep.
- *
- *	This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
-			 unsigned char __user *buf, size_t nr)
-{
-	unsigned char __user *b = buf;
-	DECLARE_WAITQUEUE(wait, current);
-	int c;
-	int minimum, time;
-	ssize_t retval = 0;
-	ssize_t size;
-	long timeout;
-	unsigned long flags;
-	int packet;
-
-do_it_again:
-
-	BUG_ON(!tty->read_buf);
-
-	c = job_control(tty, file);
-	if (c < 0)
-		return c;
-
-	minimum = time = 0;
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (!tty->icanon) {
-		time = (HZ / 10) * TIME_CHAR(tty);
-		minimum = MIN_CHAR(tty);
-		if (minimum) {
-			if (time)
-				tty->minimum_to_wake = 1;
-			else if (!waitqueue_active(&tty->read_wait) ||
-				 (tty->minimum_to_wake > minimum))
-				tty->minimum_to_wake = minimum;
-		} else {
-			timeout = 0;
-			if (time) {
-				timeout = time;
-				time = 0;
-			}
-			tty->minimum_to_wake = minimum = 1;
-		}
-	}
-
-	/*
-	 *	Internal serialization of reads.
-	 */
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&tty->atomic_read_lock))
-			return -EAGAIN;
-	} else {
-		if (mutex_lock_interruptible(&tty->atomic_read_lock))
-			return -ERESTARTSYS;
-	}
-	packet = tty->packet;
-
-	add_wait_queue(&tty->read_wait, &wait);
-	while (nr) {
-		/* First test for status change. */
-		if (packet && tty->link->ctrl_status) {
-			unsigned char cs;
-			if (b != buf)
-				break;
-			spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-			cs = tty->link->ctrl_status;
-			tty->link->ctrl_status = 0;
-			spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-			if (tty_put_user(tty, cs, b++)) {
-				retval = -EFAULT;
-				b--;
-				break;
-			}
-			nr--;
-			break;
-		}
-		/* This statement must be first before checking for input
-		   so that any interrupt will set the state back to
-		   TASK_RUNNING. */
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
-		    ((minimum - (b - buf)) >= 1))
-			tty->minimum_to_wake = (minimum - (b - buf));
-
-		if (!input_available_p(tty, 0)) {
-			if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-				retval = -EIO;
-				break;
-			}
-			if (tty_hung_up_p(file))
-				break;
-			if (!timeout)
-				break;
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				retval = -ERESTARTSYS;
-				break;
-			}
-			/* FIXME: does n_tty_set_room need locking ? */
-			n_tty_set_room(tty);
-			timeout = schedule_timeout(timeout);
-			continue;
-		}
-		__set_current_state(TASK_RUNNING);
-
-		/* Deal with packet mode. */
-		if (packet && b == buf) {
-			if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
-				retval = -EFAULT;
-				b--;
-				break;
-			}
-			nr--;
-		}
-
-		if (tty->icanon && !L_EXTPROC(tty)) {
-			/* N.B. avoid overrun if nr == 0 */
-			while (nr && tty->read_cnt) {
-				int eol;
-
-				eol = test_and_clear_bit(tty->read_tail,
-						tty->read_flags);
-				c = tty->read_buf[tty->read_tail];
-				spin_lock_irqsave(&tty->read_lock, flags);
-				tty->read_tail = ((tty->read_tail+1) &
-						  (N_TTY_BUF_SIZE-1));
-				tty->read_cnt--;
-				if (eol) {
-					/* this test should be redundant:
-					 * we shouldn't be reading data if
-					 * canon_data is 0
-					 */
-					if (--tty->canon_data < 0)
-						tty->canon_data = 0;
-				}
-				spin_unlock_irqrestore(&tty->read_lock, flags);
-
-				if (!eol || (c != __DISABLED_CHAR)) {
-					if (tty_put_user(tty, c, b++)) {
-						retval = -EFAULT;
-						b--;
-						break;
-					}
-					nr--;
-				}
-				if (eol) {
-					tty_audit_push(tty);
-					break;
-				}
-			}
-			if (retval)
-				break;
-		} else {
-			int uncopied;
-			/* The copy function takes the read lock and handles
-			   locking internally for this case */
-			uncopied = copy_from_read_buf(tty, &b, &nr);
-			uncopied += copy_from_read_buf(tty, &b, &nr);
-			if (uncopied) {
-				retval = -EFAULT;
-				break;
-			}
-		}
-
-		/* If there is enough space in the read buffer now, let the
-		 * low-level driver know. We use n_tty_chars_in_buffer() to
-		 * check the buffer, as it now knows about canonical mode.
-		 * Otherwise, if the driver is throttled and the line is
-		 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-		 * we won't get any more characters.
-		 */
-		if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-			n_tty_set_room(tty);
-			check_unthrottle(tty);
-		}
-
-		if (b - buf >= minimum)
-			break;
-		if (time)
-			timeout = time;
-	}
-	mutex_unlock(&tty->atomic_read_lock);
-	remove_wait_queue(&tty->read_wait, &wait);
-
-	if (!waitqueue_active(&tty->read_wait))
-		tty->minimum_to_wake = minimum;
-
-	__set_current_state(TASK_RUNNING);
-	size = b - buf;
-	if (size) {
-		retval = size;
-		if (nr)
-			clear_bit(TTY_PUSH, &tty->flags);
-	} else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-		 goto do_it_again;
-
-	n_tty_set_room(tty);
-	return retval;
-}
-
-/**
- *	n_tty_write		-	write function for tty
- *	@tty: tty device
- *	@file: file object
- *	@buf: userspace buffer pointer
- *	@nr: size of I/O
- *
- *	Write function of the terminal device.  This is serialized with
- *	respect to other write callers but not to termios changes, reads
- *	and other such events.  Since the receive code will echo characters,
- *	thus calling driver write methods, the output_lock is used in
- *	the output processing functions called here as well as in the
- *	echo processing function to protect the column state and space
- *	left in the buffer.
- *
- *	This code must be sure never to sleep through a hangup.
- *
- *	Locking: output_lock to protect column state and space left
- *		 (note that the process_output*() functions take this
- *		  lock themselves)
- */
-
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
-			   const unsigned char *buf, size_t nr)
-{
-	const unsigned char *b = buf;
-	DECLARE_WAITQUEUE(wait, current);
-	int c;
-	ssize_t retval = 0;
-
-	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-	if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-	}
-
-	/* Write out any echoed characters that are still pending */
-	process_echoes(tty);
-
-	add_wait_queue(&tty->write_wait, &wait);
-	while (1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
-			retval = -EIO;
-			break;
-		}
-		if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-			while (nr > 0) {
-				ssize_t num = process_output_block(tty, b, nr);
-				if (num < 0) {
-					if (num == -EAGAIN)
-						break;
-					retval = num;
-					goto break_out;
-				}
-				b += num;
-				nr -= num;
-				if (nr == 0)
-					break;
-				c = *b;
-				if (process_output(c, tty) < 0)
-					break;
-				b++; nr--;
-			}
-			if (tty->ops->flush_chars)
-				tty->ops->flush_chars(tty);
-		} else {
-			while (nr > 0) {
-				c = tty->ops->write(tty, b, nr);
-				if (c < 0) {
-					retval = c;
-					goto break_out;
-				}
-				if (!c)
-					break;
-				b += c;
-				nr -= c;
-			}
-		}
-		if (!nr)
-			break;
-		if (file->f_flags & O_NONBLOCK) {
-			retval = -EAGAIN;
-			break;
-		}
-		schedule();
-	}
-break_out:
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&tty->write_wait, &wait);
-	if (b - buf != nr && tty->fasync)
-		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-	return (b - buf) ? b - buf : retval;
-}
-
-/**
- *	n_tty_poll		-	poll method for N_TTY
- *	@tty: terminal device
- *	@file: file accessing it
- *	@wait: poll table
- *
- *	Called when the line discipline is asked to poll() for data or
- *	for special events. This code is not serialized with respect to
- *	other events save open/close.
- *
- *	This code must be sure never to sleep through a hangup.
- *	Called without the kernel lock held - fine
- */
-
-static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
-							poll_table *wait)
-{
-	unsigned int mask = 0;
-
-	poll_wait(file, &tty->read_wait, wait);
-	poll_wait(file, &tty->write_wait, wait);
-	if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
-		mask |= POLLIN | POLLRDNORM;
-	if (tty->packet && tty->link->ctrl_status)
-		mask |= POLLPRI | POLLIN | POLLRDNORM;
-	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-		mask |= POLLHUP;
-	if (tty_hung_up_p(file))
-		mask |= POLLHUP;
-	if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
-		if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-			tty->minimum_to_wake = MIN_CHAR(tty);
-		else
-			tty->minimum_to_wake = 1;
-	}
-	if (tty->ops->write && !tty_is_writelocked(tty) &&
-			tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
-			tty_write_room(tty) > 0)
-		mask |= POLLOUT | POLLWRNORM;
-	return mask;
-}
-
-static unsigned long inq_canon(struct tty_struct *tty)
-{
-	int nr, head, tail;
-
-	if (!tty->canon_data)
-		return 0;
-	head = tty->canon_head;
-	tail = tty->read_tail;
-	nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-	/* Skip EOF-chars.. */
-	while (head != tail) {
-		if (test_bit(tail, tty->read_flags) &&
-		    tty->read_buf[tail] == __DISABLED_CHAR)
-			nr--;
-		tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-	}
-	return nr;
-}
-
-static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	int retval;
-
-	switch (cmd) {
-	case TIOCOUTQ:
-		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-	case TIOCINQ:
-		/* FIXME: Locking */
-		retval = tty->read_cnt;
-		if (L_ICANON(tty))
-			retval = inq_canon(tty);
-		return put_user(retval, (unsigned int __user *) arg);
-	default:
-		return n_tty_ioctl_helper(tty, file, cmd, arg);
-	}
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
-	.magic           = TTY_LDISC_MAGIC,
-	.name            = "n_tty",
-	.open            = n_tty_open,
-	.close           = n_tty_close,
-	.flush_buffer    = n_tty_flush_buffer,
-	.chars_in_buffer = n_tty_chars_in_buffer,
-	.read            = n_tty_read,
-	.write           = n_tty_write,
-	.ioctl           = n_tty_ioctl,
-	.set_termios     = n_tty_set_termios,
-	.poll            = n_tty_poll,
-	.receive_buf     = n_tty_receive_buf,
-	.write_wakeup    = n_tty_write_wakeup
-};
-
-/**
- *	n_tty_inherit_ops	-	inherit N_TTY methods
- *	@ops: struct tty_ldisc_ops where to save N_TTY methods
- *
- *	Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
- *	methods.
- */
-
-void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
-{
-	*ops = tty_ldisc_N_TTY;
-	ops->owner = NULL;
-	ops->refcount = ops->flags = 0;
-}
-EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff -druN linux-libre-2.6.36-gnu/drivers/char/nvram.c linux-libre-2.6.37-gnu/drivers/char/nvram.c
--- linux-libre-2.6.36-gnu/drivers/char/nvram.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/nvram.c	2011-01-04 19:50:19.000000000 -0500
@@ -109,10 +109,11 @@
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/system.h>
 
+static DEFINE_MUTEX(nvram_mutex);
 static DEFINE_SPINLOCK(nvram_state_lock);
 static int nvram_open_cnt;	/* #times opened */
 static int nvram_open_mode;	/* special open modes */
@@ -308,7 +309,7 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 
-		lock_kernel();
+		mutex_lock(&nvram_mutex);
 		spin_lock_irq(&rtc_lock);
 
 		for (i = 0; i < NVRAM_BYTES; ++i)
@@ -316,7 +317,7 @@
 		__nvram_set_checksum();
 
 		spin_unlock_irq(&rtc_lock);
-		unlock_kernel();
+		mutex_unlock(&nvram_mutex);
 		return 0;
 
 	case NVRAM_SETCKS:
@@ -325,11 +326,11 @@
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 
-		lock_kernel();
+		mutex_lock(&nvram_mutex);
 		spin_lock_irq(&rtc_lock);
 		__nvram_set_checksum();
 		spin_unlock_irq(&rtc_lock);
-		unlock_kernel();
+		mutex_unlock(&nvram_mutex);
 		return 0;
 
 	default:
diff -druN linux-libre-2.6.36-gnu/drivers/char/nwbutton.c linux-libre-2.6.37-gnu/drivers/char/nwbutton.c
--- linux-libre-2.6.36-gnu/drivers/char/nwbutton.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/nwbutton.c	2011-01-04 19:50:19.000000000 -0500
@@ -182,6 +182,7 @@
 static const struct file_operations button_fops = {
 	.owner		= THIS_MODULE,
 	.read		= button_read,
+	.llseek		= noop_llseek,
 };
 
 /* 
diff -druN linux-libre-2.6.36-gnu/drivers/char/nwflash.c linux-libre-2.6.37-gnu/drivers/char/nwflash.c
--- linux-libre-2.6.36-gnu/drivers/char/nwflash.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/nwflash.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,7 +25,6 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/jiffies.h>
 
@@ -41,6 +40,7 @@
 
 #define	NWFLASH_VERSION "6.4"
 
+static DEFINE_MUTEX(flash_mutex);
 static void kick_open(void);
 static int get_flash_id(void);
 static int erase_block(int nBlock);
@@ -96,7 +96,7 @@
 
 static long flash_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
-	lock_kernel();
+	mutex_lock(&flash_mutex);
 	switch (cmd) {
 	case CMD_WRITE_DISABLE:
 		gbWriteBase64Enable = 0;
@@ -114,10 +114,10 @@
 	default:
 		gbWriteBase64Enable = 0;
 		gbWriteEnable = 0;
-		unlock_kernel();
+		mutex_unlock(&flash_mutex);
 		return -EINVAL;
 	}
-	unlock_kernel();
+	mutex_unlock(&flash_mutex);
 	return 0;
 }
 
@@ -282,7 +282,7 @@
 {
 	loff_t ret;
 
-	lock_kernel();
+	mutex_lock(&flash_mutex);
 	if (flashdebug)
 		printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
 		       (unsigned int) offset, orig);
@@ -317,7 +317,7 @@
 	default:
 		ret = -EINVAL;
 	}
-	unlock_kernel();
+	mutex_unlock(&flash_mutex);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/pc8736x_gpio.c linux-libre-2.6.37-gnu/drivers/char/pc8736x_gpio.c
--- linux-libre-2.6.36-gnu/drivers/char/pc8736x_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pc8736x_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -234,6 +234,7 @@
 	.open	= pc8736x_gpio_open,
 	.write	= nsc_gpio_write,
 	.read	= nsc_gpio_read,
+	.llseek = no_llseek,
 };
 
 static void __init pc8736x_init_shadow(void)
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/cm4000_cs.c linux-libre-2.6.37-gnu/drivers/char/pcmcia/cm4000_cs.c
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/cm4000_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/cm4000_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,11 +30,10 @@
 #include <linux/fs.h>
 #include <linux/delay.h>
 #include <linux/bitrev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -55,7 +54,7 @@
 			   __func__ , ## args);		\
 	} while (0)
 
-static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte";
+static DEFINE_MUTEX(cmm_mutex);
 
 #define	T_1SEC		(HZ)
 #define	T_10MSEC	msecs_to_jiffies(10)
@@ -980,8 +979,9 @@
 		if (dev->flags0 & 1) {
 			set_bit(IS_CMM_ABSENT, &dev->flags);
 			rc = -ENODEV;
+		} else {
+			rc = -EIO;
 		}
-		rc = -EIO;
 		goto release_io;
 	}
 
@@ -1418,7 +1418,7 @@
 	       iminor(inode), ioctl_names[_IOC_NR(cmd)]);
 #endif
 
-	lock_kernel();
+	mutex_lock(&cmm_mutex);
 	rc = -ENODEV;
 	link = dev_table[iminor(inode)];
 	if (!pcmcia_dev_present(link)) {
@@ -1626,7 +1626,7 @@
 		rc = -ENOTTY;
 	}
 out:
-	unlock_kernel();
+	mutex_unlock(&cmm_mutex);
 	return rc;
 }
 
@@ -1640,7 +1640,7 @@
 	if (minor >= CM4000_MAX_DEV)
 		return -ENODEV;
 
-	lock_kernel();
+	mutex_lock(&cmm_mutex);
 	link = dev_table[minor];
 	if (link == NULL || !pcmcia_dev_present(link)) {
 		ret = -ENODEV;
@@ -1667,7 +1667,7 @@
 	/* opening will always block since the
 	 * monitor will be started by open, which
 	 * means we have to wait for ATR becoming
-	 * vaild = block until valid (or card
+	 * valid = block until valid (or card
 	 * inserted)
 	 */
 	if (filp->f_flags & O_NONBLOCK) {
@@ -1685,7 +1685,7 @@
 	DEBUGP(2, dev, "<- cmm_open\n");
 	ret = nonseekable_open(inode, filp);
 out:
-	unlock_kernel();
+	mutex_unlock(&cmm_mutex);
 	return ret;
 }
 
@@ -1742,20 +1742,8 @@
 
 /*==== Interface to PCMCIA Layer =======================================*/
 
-static int cm4000_config_check(struct pcmcia_device *p_dev,
-			       cistpl_cftable_entry_t *cfg,
-			       cistpl_cftable_entry_t *dflt,
-			       unsigned int vcc,
-			       void *priv_data)
+static int cm4000_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-	if (!cfg->io.nwin)
-		return -ENODEV;
-
-	p_dev->resource[0]->start = cfg->io.win[0].base;
-	p_dev->resource[0]->end = cfg->io.win[0].len;
-	p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-	p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
 	return pcmcia_request_io(p_dev);
 }
 
@@ -1763,13 +1751,13 @@
 {
 	struct cm4000_dev *dev;
 
+	link->config_flags |= CONF_AUTO_SET_IO;
+
 	/* read the config-tuples */
 	if (pcmcia_loop_config(link, cm4000_config_check, NULL))
 		goto cs_release;
 
-	link->conf.IntType = 00000002;
-
-	if (pcmcia_request_configuration(link, &link->conf))
+	if (pcmcia_enable_device(link))
 		goto cs_release;
 
 	dev = link->priv;
@@ -1829,7 +1817,6 @@
 
 	dev->p_dev = link;
 	link->priv = dev;
-	link->conf.IntType = INT_MEMORY_AND_IO;
 	dev_table[i] = link;
 
 	init_waitqueue_head(&dev->devq);
@@ -1880,6 +1867,7 @@
 	.unlocked_ioctl	= cmm_ioctl,
 	.open	= cmm_open,
 	.release= cmm_close,
+	.llseek = no_llseek,
 };
 
 static struct pcmcia_device_id cm4000_ids[] = {
@@ -1891,9 +1879,7 @@
 
 static struct pcmcia_driver cm4000_driver = {
 	.owner	  = THIS_MODULE,
-	.drv	  = {
-		.name = "cm4000_cs",
-		},
+	.name	  = "cm4000_cs",
 	.probe    = cm4000_probe,
 	.remove   = cm4000_detach,
 	.suspend  = cm4000_suspend,
@@ -1905,8 +1891,6 @@
 {
 	int rc;
 
-	printk(KERN_INFO "%s\n", version);
-
 	cmm_class = class_create(THIS_MODULE, "cardman_4000");
 	if (IS_ERR(cmm_class))
 		return PTR_ERR(cmm_class);
@@ -1931,7 +1915,6 @@
 
 static void __exit cmm_exit(void)
 {
-	printk(KERN_INFO MODULE_NAME ": unloading\n");
 	pcmcia_unregister_driver(&cm4000_driver);
 	unregister_chrdev(major, DEVICE_NAME);
 	class_destroy(cmm_class);
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/cm4040_cs.c linux-libre-2.6.37-gnu/drivers/char/pcmcia/cm4040_cs.c
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/cm4040_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/cm4040_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,12 +24,11 @@
 #include <linux/fs.h>
 #include <linux/delay.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/wait.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -49,8 +48,7 @@
 			   __func__ , ## args);		\
 	} while (0)
 
-static char *version =
-"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte";
+static DEFINE_MUTEX(cm4040_mutex);
 
 #define	CCID_DRIVER_BULK_DEFAULT_TIMEOUT  	(150*HZ)
 #define	CCID_DRIVER_ASYNC_POWERUP_TIMEOUT 	(35*HZ)
@@ -444,7 +442,7 @@
 	if (minor >= CM_MAX_DEV)
 		return -ENODEV;
 
-	lock_kernel();
+	mutex_lock(&cm4040_mutex);
 	link = dev_table[minor];
 	if (link == NULL || !pcmcia_dev_present(link)) {
 		ret = -ENODEV;
@@ -473,7 +471,7 @@
 	DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
 	ret = nonseekable_open(inode, filp);
 out:
-	unlock_kernel();
+	mutex_unlock(&cm4040_mutex);
 	return ret;
 }
 
@@ -516,26 +514,9 @@
 	return;
 }
 
-static int cm4040_config_check(struct pcmcia_device *p_dev,
-			       cistpl_cftable_entry_t *cfg,
-			       cistpl_cftable_entry_t *dflt,
-			       unsigned int vcc,
-			       void *priv_data)
+static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-	int rc;
-	if (!cfg->io.nwin)
-		return -ENODEV;
-
-	/* Get the IOaddr */
-	p_dev->resource[0]->start = cfg->io.win[0].base;
-	p_dev->resource[0]->end = cfg->io.win[0].len;
-	p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-	p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-	rc = pcmcia_request_io(p_dev);
-
-	dev_printk(KERN_INFO, &p_dev->dev,
-		   "pcmcia_request_io returned 0x%x\n", rc);
-	return rc;
+	return pcmcia_request_io(p_dev);
 }
 
 
@@ -544,15 +525,15 @@
 	struct reader_dev *dev;
 	int fail_rc;
 
+	link->config_flags |= CONF_AUTO_SET_IO;
+
 	if (pcmcia_loop_config(link, cm4040_config_check, NULL))
 		goto cs_release;
 
-	link->conf.IntType = 00000002;
-
-	fail_rc = pcmcia_request_configuration(link, &link->conf);
+	fail_rc = pcmcia_enable_device(link);
 	if (fail_rc != 0) {
 		dev_printk(KERN_INFO, &link->dev,
-			   "pcmcia_request_configuration failed 0x%x\n",
+			   "pcmcia_enable_device failed 0x%x\n",
 			   fail_rc);
 		goto cs_release;
 	}
@@ -599,7 +580,6 @@
 	link->priv = dev;
 	dev->p_dev = link;
 
-	link->conf.IntType = INT_MEMORY_AND_IO;
 	dev_table[i] = link;
 
 	init_waitqueue_head(&dev->devq);
@@ -650,6 +630,7 @@
 	.open		= cm4040_open,
 	.release	= cm4040_close,
 	.poll		= cm4040_poll,
+	.llseek		= no_llseek,
 };
 
 static struct pcmcia_device_id cm4040_ids[] = {
@@ -662,9 +643,7 @@
 
 static struct pcmcia_driver reader_driver = {
   	.owner		= THIS_MODULE,
-  	.drv		= {
-		.name	= "cm4040_cs",
-	},
+	.name		= "cm4040_cs",
 	.probe		= reader_probe,
 	.remove		= reader_detach,
 	.id_table	= cm4040_ids,
@@ -674,7 +653,6 @@
 {
 	int rc;
 
-	printk(KERN_INFO "%s\n", version);
 	cmx_class = class_create(THIS_MODULE, "cardman_4040");
 	if (IS_ERR(cmx_class))
 		return PTR_ERR(cmx_class);
@@ -699,7 +677,6 @@
 
 static void __exit cm4040_exit(void)
 {
-	printk(KERN_INFO MODULE_NAME ": unloading\n");
 	pcmcia_unregister_driver(&reader_driver);
 	unregister_chrdev(major, DEVICE_NAME);
 	class_destroy(cmx_class);
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/main.c linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/main.c
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/main.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/main.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,6 @@
 #include <pcmcia/device_id.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/cs.h>
 
 static struct pcmcia_device_id ipw_ids[] = {
 	PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
@@ -76,23 +75,18 @@
 	schedule_work(&ipw->work_reboot);
 }
 
-static int ipwireless_probe(struct pcmcia_device *p_dev,
-			    cistpl_cftable_entry_t *cfg,
-			    cistpl_cftable_entry_t *dflt,
-			    unsigned int vcc,
-			    void *priv_data)
+static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 {
 	struct ipw_dev *ipw = priv_data;
 	struct resource *io_resource;
 	int ret;
 
+	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
 	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	p_dev->resource[0]->start = cfg->io.win[0].base;
-	p_dev->resource[0]->end = cfg->io.win[0].len;
 
 	/* 0x40 causes it to generate level mode interrupts. */
 	/* 0x04 enables IREQ pin. */
-	p_dev->conf.ConfigIndex = cfg->index | 0x44;
+	p_dev->config_index |= 0x44;
 	p_dev->io_lines = 16;
 	ret = pcmcia_request_io(p_dev);
 	if (ret)
@@ -102,65 +96,49 @@
 				resource_size(p_dev->resource[0]),
 				IPWIRELESS_PCCARD_NAME);
 
-	if (cfg->mem.nwin == 0)
-		return 0;
-
-	ipw->request_common_memory.Attributes =
+	p_dev->resource[2]->flags |=
 		WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-	ipw->request_common_memory.Base = cfg->mem.win[0].host_addr;
-	ipw->request_common_memory.Size = cfg->mem.win[0].len;
-	if (ipw->request_common_memory.Size < 0x1000)
-		ipw->request_common_memory.Size = 0x1000;
-	ipw->request_common_memory.AccessSpeed = 0;
-
-	ret = pcmcia_request_window(p_dev, &ipw->request_common_memory,
-				&ipw->handle_common_memory);
 
+	ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);
 	if (ret != 0)
 		goto exit1;
 
-	ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory,
-				cfg->mem.win[0].card_addr);
-
+	ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
 	if (ret != 0)
 		goto exit2;
 
-	ipw->is_v2_card = cfg->mem.win[0].len == 0x100;
+	ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
 
-	ipw->common_memory = ioremap(ipw->request_common_memory.Base,
-				ipw->request_common_memory.Size);
-	request_mem_region(ipw->request_common_memory.Base,
-			ipw->request_common_memory.Size,
+	ipw->attr_memory = ioremap(p_dev->resource[2]->start,
+				resource_size(p_dev->resource[2]));
+	request_mem_region(p_dev->resource[2]->start,
+			resource_size(p_dev->resource[2]),
 			IPWIRELESS_PCCARD_NAME);
 
-	ipw->request_attr_memory.Attributes =
-		WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
-	ipw->request_attr_memory.Base = 0;
-	ipw->request_attr_memory.Size = 0;	/* this used to be 0x1000 */
-	ipw->request_attr_memory.AccessSpeed = 0;
-
-	ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory,
-				&ipw->handle_attr_memory);
-
+	p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
+					WIN_ENABLE;
+	p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
+	ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
 	if (ret != 0)
 		goto exit2;
 
-	ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0);
+	ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
 	if (ret != 0)
 		goto exit3;
 
-	ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
-				ipw->request_attr_memory.Size);
-	request_mem_region(ipw->request_attr_memory.Base,
-			ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME);
+	ipw->attr_memory = ioremap(p_dev->resource[3]->start,
+				resource_size(p_dev->resource[3]));
+	request_mem_region(p_dev->resource[3]->start,
+			resource_size(p_dev->resource[3]),
+			IPWIRELESS_PCCARD_NAME);
 
 	return 0;
 
 exit3:
 exit2:
 	if (ipw->common_memory) {
-		release_mem_region(ipw->request_common_memory.Base,
-				ipw->request_common_memory.Size);
+		release_mem_region(p_dev->resource[2]->start,
+				resource_size(p_dev->resource[2]));
 		iounmap(ipw->common_memory);
 	}
 exit1:
@@ -175,14 +153,13 @@
 	int ret = 0;
 
 	ipw->is_v2_card = 0;
+	link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |
+		CONF_ENABLE_IRQ;
 
 	ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
 	if (ret != 0)
 		return ret;
 
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-
 	INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
 
 	ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
@@ -201,13 +178,9 @@
 			(unsigned int) link->irq);
 	if (ipw->attr_memory && ipw->common_memory)
 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-			": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n",
-			ipw->request_attr_memory.Base,
-			ipw->request_attr_memory.Base
-			+ ipw->request_attr_memory.Size - 1,
-			ipw->request_common_memory.Base,
-			ipw->request_common_memory.Base
-			+ ipw->request_common_memory.Size - 1);
+			": attr memory %pR, common memory %pR\n",
+			link->resource[3],
+			link->resource[2]);
 
 	ipw->network = ipwireless_network_create(ipw->hardware);
 	if (!ipw->network)
@@ -223,25 +196,23 @@
 	 * Do the RequestConfiguration last, because it enables interrupts.
 	 * Then we don't get any interrupts before we're ready for them.
 	 */
-	ret = pcmcia_request_configuration(link, &link->conf);
-
+	ret = pcmcia_enable_device(link);
 	if (ret != 0)
 		goto exit;
 
 	return 0;
 
 exit:
-	if (ipw->attr_memory) {
-		release_mem_region(ipw->request_attr_memory.Base,
-				ipw->request_attr_memory.Size);
-		iounmap(ipw->attr_memory);
-
-	}
 	if (ipw->common_memory) {
-		release_mem_region(ipw->request_common_memory.Base,
-				ipw->request_common_memory.Size);
+		release_mem_region(link->resource[2]->start,
+				resource_size(link->resource[2]));
 		iounmap(ipw->common_memory);
 	}
+	if (ipw->attr_memory) {
+		release_mem_region(link->resource[3]->start,
+				resource_size(link->resource[3]));
+		iounmap(ipw->attr_memory);
+	}
 	pcmcia_disable_device(link);
 	return -1;
 }
@@ -249,13 +220,13 @@
 static void release_ipwireless(struct ipw_dev *ipw)
 {
 	if (ipw->common_memory) {
-		release_mem_region(ipw->request_common_memory.Base,
-				ipw->request_common_memory.Size);
+		release_mem_region(ipw->link->resource[2]->start,
+				resource_size(ipw->link->resource[2]));
 		iounmap(ipw->common_memory);
 	}
 	if (ipw->attr_memory) {
-		release_mem_region(ipw->request_attr_memory.Base,
-				ipw->request_attr_memory.Size);
+		release_mem_region(ipw->link->resource[3]->start,
+				resource_size(ipw->link->resource[3]));
 		iounmap(ipw->attr_memory);
 	}
 	pcmcia_disable_device(ipw->link);
@@ -324,7 +295,7 @@
 	.owner		= THIS_MODULE,
 	.probe          = ipwireless_attach,
 	.remove         = ipwireless_detach,
-	.drv = { .name  = IPWIRELESS_PCCARD_NAME },
+	.name		= IPWIRELESS_PCCARD_NAME,
 	.id_table       = ipw_ids
 };
 
@@ -336,9 +307,6 @@
 {
 	int ret;
 
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
-	       IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n");
-
 	ret = ipwireless_tty_init();
 	if (ret != 0)
 		return ret;
@@ -355,9 +323,6 @@
  */
 static void __exit exit_ipwireless(void)
 {
-	printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
-			IPWIRELESS_PCMCIA_VERSION " removed\n");
-
 	pcmcia_unregister_driver(&me);
 	ipwireless_tty_release();
 }
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/main.h linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/main.h
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/main.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/main.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -45,13 +44,9 @@
 	struct pcmcia_device *link;
 	int is_v2_card;
 
-	window_handle_t handle_attr_memory;
 	void __iomem *attr_memory;
-	win_req_t request_attr_memory;
 
-	window_handle_t handle_common_memory;
 	void __iomem *common_memory;
-	win_req_t request_common_memory;
 
 	/* Reference to attribute memory, containing CIS data */
 	void *attribute_memory;
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/Makefile linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,5 +6,5 @@
 
 obj-$(CONFIG_IPWIRELESS) += ipwireless.o
 
-ipwireless-objs := hardware.o main.o network.o tty.o
+ipwireless-y := hardware.o main.o network.o tty.o
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/tty.h linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/tty.h
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/ipwireless/tty.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/ipwireless/tty.h	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/Kconfig linux-libre-2.6.37-gnu/drivers/char/pcmcia/Kconfig
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
 
 	  This kernel driver requires additional userspace support, either
 	  by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
-	  or via the cm4000 backend of OpenCT (http://www.opensc.com/).
+	  or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc).
 
 config CARDMAN_4040
 	tristate "Omnikey CardMan 4040 support"
@@ -41,7 +41,7 @@
 	  in I/O space.  To use the kernel driver, you will need either the
 	  PC/SC ifdhandler provided from the Omnikey homepage
 	  (http://www.omnikey.com/), or a current development version of OpenCT
-	  (http://www.opensc.org/).
+	  (http://www.opensc-project.org/opensc).
 
 config IPWIRELESS
 	tristate "IPWireless 3G UMTS PCMCIA card support"
diff -druN linux-libre-2.6.36-gnu/drivers/char/pcmcia/synclink_cs.c linux-libre-2.6.37-gnu/drivers/char/pcmcia/synclink_cs.c
--- linux-libre-2.6.36-gnu/drivers/char/pcmcia/synclink_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pcmcia/synclink_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -70,7 +70,6 @@
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -550,9 +549,6 @@
 
     /* Initialize the struct pcmcia_device structure */
 
-    link->conf.Attributes = 0;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-
     ret = mgslpc_config(link);
     if (ret)
 	    return ret;
@@ -565,20 +561,8 @@
 /* Card has been inserted.
  */
 
-static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
-			  cistpl_cftable_entry_t *cfg,
-			  cistpl_cftable_entry_t *dflt,
-			  unsigned int vcc,
-			  void *priv_data)
+static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
 {
-	if (!cfg->io.nwin)
-		return -ENODEV;
-
-	p_dev->resource[0]->start = cfg->io.win[0].base;
-	p_dev->resource[0]->end = cfg->io.win[0].len;
-	p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-	p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
 	return pcmcia_request_io(p_dev);
 }
 
@@ -590,32 +574,24 @@
     if (debug_level >= DEBUG_LEVEL_INFO)
 	    printk("mgslpc_config(0x%p)\n", link);
 
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
     ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
     if (ret != 0)
 	    goto failed;
 
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 8;
-    link->conf.Present = PRESENT_OPTION;
+    link->config_index = 8;
+    link->config_regs = PRESENT_OPTION;
 
     ret = pcmcia_request_irq(link, mgslpc_isr);
     if (ret)
 	    goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
 	    goto failed;
 
     info->io_base = link->resource[0]->start;
     info->irq_level = link->irq;
-
-    dev_info(&link->dev, "index 0x%02x:",
-	    link->conf.ConfigIndex);
-    if (link->conf.Attributes & CONF_ENABLE_IRQ)
-	    printk(", irq %d", link->irq);
-    if (link->resource[0])
-	    printk(", io %pR", link->resource[0]);
-    printk("\n");
     return 0;
 
 failed:
@@ -2215,6 +2191,32 @@
 	return 0;
 }
 
+static int mgslpc_get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
+{
+	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+
+	return 0;
+}
+
 /* Service an IOCTL request
  *
  * Arguments:
@@ -2230,11 +2232,7 @@
 			unsigned int cmd, unsigned long arg)
 {
 	MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
-	int error;
-	struct mgsl_icount cnow;	/* kernel counter temps */
-	struct serial_icounter_struct __user *p_cuser;	/* user space */
 	void __user *argp = (void __user *)arg;
-	unsigned long flags;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
@@ -2244,7 +2242,7 @@
 		return -ENODEV;
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+	    (cmd != TIOCMIWAIT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
@@ -2274,34 +2272,6 @@
 		return wait_events(info, argp);
 	case TIOCMIWAIT:
 		return modem_input_wait(info,(int)arg);
-	case TIOCGICOUNT:
-		spin_lock_irqsave(&info->lock,flags);
-		cnow = info->icount;
-		spin_unlock_irqrestore(&info->lock,flags);
-		p_cuser = argp;
-		PUT_USER(error,cnow.cts, &p_cuser->cts);
-		if (error) return error;
-		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
-		if (error) return error;
-		PUT_USER(error,cnow.rng, &p_cuser->rng);
-		if (error) return error;
-		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
-		if (error) return error;
-		PUT_USER(error,cnow.rx, &p_cuser->rx);
-		if (error) return error;
-		PUT_USER(error,cnow.tx, &p_cuser->tx);
-		if (error) return error;
-		PUT_USER(error,cnow.frame, &p_cuser->frame);
-		if (error) return error;
-		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
-		if (error) return error;
-		PUT_USER(error,cnow.parity, &p_cuser->parity);
-		if (error) return error;
-		PUT_USER(error,cnow.brk, &p_cuser->brk);
-		if (error) return error;
-		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
-		if (error) return error;
-		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
@@ -2797,9 +2767,7 @@
 
 static struct pcmcia_driver mgslpc_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "synclink_cs",
-	},
+	.name		= "synclink_cs",
 	.probe		= mgslpc_probe,
 	.remove		= mgslpc_detach,
 	.id_table	= mgslpc_ids,
@@ -2828,6 +2796,7 @@
 	.hangup = mgslpc_hangup,
 	.tiocmget = tiocmget,
 	.tiocmset = tiocmset,
+	.get_icount = mgslpc_get_icount,
 	.proc_fops = &mgslpc_proc_fops,
 };
 
@@ -2835,8 +2804,6 @@
 {
 	int rc;
 
-	printk("Unloading %s: version %s\n", driver_name, driver_version);
-
 	while(mgslpc_device_list)
 		mgslpc_remove_device(mgslpc_device_list);
 
@@ -2859,8 +2826,6 @@
 	    BREAKPOINT();
     }
 
-    printk("%s %s\n", driver_name, driver_version);
-
     if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
 	    return rc;
 
@@ -4127,6 +4092,8 @@
 	if (cmd != SIOCWANDEV)
 		return hdlc_ioctl(dev, ifr, cmd);
 
+	memset(&new_line, 0, size);
+
 	switch(ifr->ifr_settings.type) {
 	case IF_GET_IFACE: /* return current sync_serial_settings */
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/ppdev.c linux-libre-2.6.37-gnu/drivers/char/ppdev.c
--- linux-libre-2.6.36-gnu/drivers/char/ppdev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ppdev.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,7 +67,7 @@
 #include <linux/slab.h>
 #include <linux/major.h>
 #include <linux/ppdev.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/uaccess.h>
 
 #define PP_VERSION "ppdev: user-space parallel port driver"
@@ -97,6 +97,7 @@
 /* ROUND_UP macro from fs/select.c */
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 
+static DEFINE_MUTEX(pp_do_mutex);
 static inline void pp_enable_irq (struct pp_struct *pp)
 {
 	struct parport *port = pp->pdev->port;
@@ -612,6 +613,7 @@
 
 	case PPGETTIME:
 		to_jiffies = pp->pdev->timeout;
+		memset(&par_timeout, 0, sizeof(par_timeout));
 		par_timeout.tv_sec = to_jiffies / HZ;
 		par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
 		if (copy_to_user (argp, &par_timeout, sizeof(struct timeval)))
@@ -630,9 +632,9 @@
 static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	long ret;
-	lock_kernel();
+	mutex_lock(&pp_do_mutex);
 	ret = pp_do_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&pp_do_mutex);
 	return ret;
 }
 
@@ -641,7 +643,6 @@
 	unsigned int minor = iminor(inode);
 	struct pp_struct *pp;
 
-	cycle_kernel_lock();
 	if (minor >= PARPORT_MAX)
 		return -ENXIO;
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/pty.c linux-libre-2.6.37-gnu/drivers/char/pty.c
--- linux-libre-2.6.36-gnu/drivers/char/pty.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/pty.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,775 +0,0 @@
-/*
- *  linux/drivers/char/pty.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  Added support for a Unix98-style ptmx device.
- *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- *  When reading this code see also fs/devpts. In particular note that the
- *  driver_data field is used by the devpts side as a binding to the devpts
- *  inode.
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/devpts_fs.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-
-#ifdef CONFIG_UNIX98_PTYS
-static struct tty_driver *ptm_driver;
-static struct tty_driver *pts_driver;
-#endif
-
-static void pty_close(struct tty_struct *tty, struct file *filp)
-{
-	BUG_ON(!tty);
-	if (tty->driver->subtype == PTY_TYPE_MASTER)
-		WARN_ON(tty->count > 1);
-	else {
-		if (tty->count > 2)
-			return;
-	}
-	wake_up_interruptible(&tty->read_wait);
-	wake_up_interruptible(&tty->write_wait);
-	tty->packet = 0;
-	if (!tty->link)
-		return;
-	tty->link->packet = 0;
-	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-	wake_up_interruptible(&tty->link->read_wait);
-	wake_up_interruptible(&tty->link->write_wait);
-	if (tty->driver->subtype == PTY_TYPE_MASTER) {
-		set_bit(TTY_OTHER_CLOSED, &tty->flags);
-#ifdef CONFIG_UNIX98_PTYS
-		if (tty->driver == ptm_driver)
-			devpts_pty_kill(tty->link);
-#endif
-		tty_unlock();
-		tty_vhangup(tty->link);
-		tty_lock();
-	}
-}
-
-/*
- * The unthrottle routine is called by the line discipline to signal
- * that it can receive more characters.  For PTY's, the TTY_THROTTLED
- * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
- * characters in the queue.  This is necessary since each time this
- * happens, we need to wake up any sleeping processes that could be
- * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
- * for the pty buffer to be drained.
- */
-static void pty_unthrottle(struct tty_struct *tty)
-{
-	tty_wakeup(tty->link);
-	set_bit(TTY_THROTTLED, &tty->flags);
-}
-
-/**
- *	pty_space	-	report space left for writing
- *	@to: tty we are writing into
- *
- *	The tty buffers allow 64K but we sneak a peak and clip at 8K this
- *	allows a lot of overspill room for echo and other fun messes to
- *	be handled properly
- */
-
-static int pty_space(struct tty_struct *to)
-{
-	int n = 8192 - to->buf.memory_used;
-	if (n < 0)
-		return 0;
-	return n;
-}
-
-/**
- *	pty_write		-	write to a pty
- *	@tty: the tty we write from
- *	@buf: kernel buffer of data
- *	@count: bytes to write
- *
- *	Our "hardware" write method. Data is coming from the ldisc which
- *	may be in a non sleeping state. We simply throw this at the other
- *	end of the link as if we were an IRQ handler receiving stuff for
- *	the other side of the pty/tty pair.
- */
-
-static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
-{
-	struct tty_struct *to = tty->link;
-
-	if (tty->stopped)
-		return 0;
-
-	if (c > 0) {
-		/* Stuff the data into the input queue of the other end */
-		c = tty_insert_flip_string(to, buf, c);
-		/* And shovel */
-		if (c) {
-			tty_flip_buffer_push(to);
-			tty_wakeup(tty);
-		}
-	}
-	return c;
-}
-
-/**
- *	pty_write_room	-	write space
- *	@tty: tty we are writing from
- *
- *	Report how many bytes the ldisc can send into the queue for
- *	the other device.
- */
-
-static int pty_write_room(struct tty_struct *tty)
-{
-	if (tty->stopped)
-		return 0;
-	return pty_space(tty->link);
-}
-
-/**
- *	pty_chars_in_buffer	-	characters currently in our tx queue
- *	@tty: our tty
- *
- *	Report how much we have in the transmit queue. As everything is
- *	instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
-	return 0;
-}
-
-/* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user *arg)
-{
-	int val;
-	if (get_user(val, arg))
-		return -EFAULT;
-	if (val)
-		set_bit(TTY_PTY_LOCK, &tty->flags);
-	else
-		clear_bit(TTY_PTY_LOCK, &tty->flags);
-	return 0;
-}
-
-/* Send a signal to the slave */
-static int pty_signal(struct tty_struct *tty, int sig)
-{
-	unsigned long flags;
-	struct pid *pgrp;
-
-	if (tty->link) {
-		spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-		pgrp = get_pid(tty->link->pgrp);
-		spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-
-		kill_pgrp(pgrp, sig, 1);
-		put_pid(pgrp);
-	}
-	return 0;
-}
-
-static void pty_flush_buffer(struct tty_struct *tty)
-{
-	struct tty_struct *to = tty->link;
-	unsigned long flags;
-
-	if (!to)
-		return;
-	/* tty_buffer_flush(to); FIXME */
-	if (to->packet) {
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
-		wake_up_interruptible(&to->read_wait);
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	}
-}
-
-static int pty_open(struct tty_struct *tty, struct file *filp)
-{
-	int	retval = -ENODEV;
-
-	if (!tty || !tty->link)
-		goto out;
-
-	retval = -EIO;
-	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-		goto out;
-	if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
-		goto out;
-	if (tty->link->count != 1)
-		goto out;
-
-	clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-	set_bit(TTY_THROTTLED, &tty->flags);
-	retval = 0;
-out:
-	return retval;
-}
-
-static void pty_set_termios(struct tty_struct *tty,
-					struct ktermios *old_termios)
-{
-	tty->termios->c_cflag &= ~(CSIZE | PARENB);
-	tty->termios->c_cflag |= (CS8 | CREAD);
-}
-
-/**
- *	pty_do_resize		-	resize event
- *	@tty: tty being resized
- *	@ws: window size being set.
- *
- *	Update the termios variables and send the necessary signals to
- *	peform a terminal resize correctly
- */
-
-int pty_resize(struct tty_struct *tty,  struct winsize *ws)
-{
-	struct pid *pgrp, *rpgrp;
-	unsigned long flags;
-	struct tty_struct *pty = tty->link;
-
-	/* For a PTY we need to lock the tty side */
-	mutex_lock(&tty->termios_mutex);
-	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-		goto done;
-
-	/* Get the PID values and reference them so we can
-	   avoid holding the tty ctrl lock while sending signals.
-	   We need to lock these individually however. */
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	pgrp = get_pid(tty->pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	spin_lock_irqsave(&pty->ctrl_lock, flags);
-	rpgrp = get_pid(pty->pgrp);
-	spin_unlock_irqrestore(&pty->ctrl_lock, flags);
-
-	if (pgrp)
-		kill_pgrp(pgrp, SIGWINCH, 1);
-	if (rpgrp != pgrp && rpgrp)
-		kill_pgrp(rpgrp, SIGWINCH, 1);
-
-	put_pid(pgrp);
-	put_pid(rpgrp);
-
-	tty->winsize = *ws;
-	pty->winsize = *ws;	/* Never used so will go away soon */
-done:
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-	struct tty_struct *o_tty;
-	int idx = tty->index;
-	int retval;
-
-	o_tty = alloc_tty_struct();
-	if (!o_tty)
-		return -ENOMEM;
-	if (!try_module_get(driver->other->owner)) {
-		/* This cannot in fact currently happen */
-		free_tty_struct(o_tty);
-		return -ENOMEM;
-	}
-	initialize_tty_struct(o_tty, driver->other, idx);
-
-	/* We always use new tty termios data so we can do this
-	   the easy way .. */
-	retval = tty_init_termios(tty);
-	if (retval)
-		goto free_mem_out;
-
-	retval = tty_init_termios(o_tty);
-	if (retval) {
-		tty_free_termios(tty);
-		goto free_mem_out;
-	}
-
-	/*
-	 * Everything allocated ... set up the o_tty structure.
-	 */
-	driver->other->ttys[idx] = o_tty;
-	tty_driver_kref_get(driver->other);
-	if (driver->subtype == PTY_TYPE_MASTER)
-		o_tty->count++;
-	/* Establish the links in both directions */
-	tty->link   = o_tty;
-	o_tty->link = tty;
-
-	tty_driver_kref_get(driver);
-	tty->count++;
-	driver->ttys[idx] = tty;
-	return 0;
-free_mem_out:
-	module_put(o_tty->driver->owner);
-	free_tty_struct(o_tty);
-	return -ENOMEM;
-}
-
-static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-		return pty_set_lock(tty, (int __user *) arg);
-	case TIOCSIG:    /* Send signal to other side of pty */
-		return pty_signal(tty, (int) arg);
-	}
-	return -ENOIOCTLCMD;
-}
-
-static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
-module_param(legacy_count, int, 0);
-
-/*
- * The master side of a pty can do TIOCSPTLCK and thus
- * has pty_bsd_ioctl.
- */
-static const struct tty_operations master_pty_ops_bsd = {
-	.install = pty_install,
-	.open = pty_open,
-	.close = pty_close,
-	.write = pty_write,
-	.write_room = pty_write_room,
-	.flush_buffer = pty_flush_buffer,
-	.chars_in_buffer = pty_chars_in_buffer,
-	.unthrottle = pty_unthrottle,
-	.set_termios = pty_set_termios,
-	.ioctl = pty_bsd_ioctl,
-	.resize = pty_resize
-};
-
-static const struct tty_operations slave_pty_ops_bsd = {
-	.install = pty_install,
-	.open = pty_open,
-	.close = pty_close,
-	.write = pty_write,
-	.write_room = pty_write_room,
-	.flush_buffer = pty_flush_buffer,
-	.chars_in_buffer = pty_chars_in_buffer,
-	.unthrottle = pty_unthrottle,
-	.set_termios = pty_set_termios,
-	.resize = pty_resize
-};
-
-static void __init legacy_pty_init(void)
-{
-	struct tty_driver *pty_driver, *pty_slave_driver;
-
-	if (legacy_count <= 0)
-		return;
-
-	pty_driver = alloc_tty_driver(legacy_count);
-	if (!pty_driver)
-		panic("Couldn't allocate pty driver");
-
-	pty_slave_driver = alloc_tty_driver(legacy_count);
-	if (!pty_slave_driver)
-		panic("Couldn't allocate pty slave driver");
-
-	pty_driver->owner = THIS_MODULE;
-	pty_driver->driver_name = "pty_master";
-	pty_driver->name = "pty";
-	pty_driver->major = PTY_MASTER_MAJOR;
-	pty_driver->minor_start = 0;
-	pty_driver->type = TTY_DRIVER_TYPE_PTY;
-	pty_driver->subtype = PTY_TYPE_MASTER;
-	pty_driver->init_termios = tty_std_termios;
-	pty_driver->init_termios.c_iflag = 0;
-	pty_driver->init_termios.c_oflag = 0;
-	pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-	pty_driver->init_termios.c_lflag = 0;
-	pty_driver->init_termios.c_ispeed = 38400;
-	pty_driver->init_termios.c_ospeed = 38400;
-	pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
-	pty_driver->other = pty_slave_driver;
-	tty_set_operations(pty_driver, &master_pty_ops_bsd);
-
-	pty_slave_driver->owner = THIS_MODULE;
-	pty_slave_driver->driver_name = "pty_slave";
-	pty_slave_driver->name = "ttyp";
-	pty_slave_driver->major = PTY_SLAVE_MAJOR;
-	pty_slave_driver->minor_start = 0;
-	pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
-	pty_slave_driver->subtype = PTY_TYPE_SLAVE;
-	pty_slave_driver->init_termios = tty_std_termios;
-	pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-	pty_slave_driver->init_termios.c_ispeed = 38400;
-	pty_slave_driver->init_termios.c_ospeed = 38400;
-	pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-					TTY_DRIVER_REAL_RAW;
-	pty_slave_driver->other = pty_driver;
-	tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
-
-	if (tty_register_driver(pty_driver))
-		panic("Couldn't register pty driver");
-	if (tty_register_driver(pty_slave_driver))
-		panic("Couldn't register pty slave driver");
-}
-#else
-static inline void legacy_pty_init(void) { }
-#endif
-
-/* Unix98 devices */
-#ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
-
-static struct cdev ptmx_cdev;
-
-static struct ctl_table pty_table[] = {
-	{
-		.procname	= "max",
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.data		= &pty_limit,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &pty_limit_min,
-		.extra2		= &pty_limit_max,
-	}, {
-		.procname	= "nr",
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.data		= &pty_count,
-		.proc_handler	= proc_dointvec,
-	}, 
-	{}
-};
-
-static struct ctl_table pty_kern_table[] = {
-	{
-		.procname	= "pty",
-		.mode		= 0555,
-		.child		= pty_table,
-	},
-	{}
-};
-
-static struct ctl_table pty_root_table[] = {
-	{
-		.procname	= "kernel",
-		.mode		= 0555,
-		.child		= pty_kern_table,
-	},
-	{}
-};
-
-
-static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
-			    unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-		return pty_set_lock(tty, (int __user *)arg);
-	case TIOCGPTN: /* Get PT Number */
-		return put_user(tty->index, (unsigned int __user *)arg);
-	case TIOCSIG:    /* Send signal to other side of pty */
-		return pty_signal(tty, (int) arg);
-	}
-
-	return -ENOIOCTLCMD;
-}
-
-/**
- *	ptm_unix98_lookup	-	find a pty master
- *	@driver: ptm driver
- *	@idx: tty index
- *
- *	Look up a pty master device. Called under the tty_mutex for now.
- *	This provides our locking.
- */
-
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
-		struct inode *ptm_inode, int idx)
-{
-	struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-	if (tty)
-		tty = tty->link;
-	return tty;
-}
-
-/**
- *	pts_unix98_lookup	-	find a pty slave
- *	@driver: pts driver
- *	@idx: tty index
- *
- *	Look up a pty master device. Called under the tty_mutex for now.
- *	This provides our locking.
- */
-
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
-		struct inode *pts_inode, int idx)
-{
-	struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
-	/* Master must be open before slave */
-	if (!tty)
-		return ERR_PTR(-EIO);
-	return tty;
-}
-
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
-	/* We have our own method as we don't use the tty index */
-	kfree(tty->termios);
-}
-
-/* We have no need to install and remove our tty objects as devpts does all
-   the work for us */
-
-static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-	struct tty_struct *o_tty;
-	int idx = tty->index;
-
-	o_tty = alloc_tty_struct();
-	if (!o_tty)
-		return -ENOMEM;
-	if (!try_module_get(driver->other->owner)) {
-		/* This cannot in fact currently happen */
-		free_tty_struct(o_tty);
-		return -ENOMEM;
-	}
-	initialize_tty_struct(o_tty, driver->other, idx);
-
-	tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-	if (tty->termios == NULL)
-		goto free_mem_out;
-	*tty->termios = driver->init_termios;
-	tty->termios_locked = tty->termios + 1;
-
-	o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-	if (o_tty->termios == NULL)
-		goto free_mem_out;
-	*o_tty->termios = driver->other->init_termios;
-	o_tty->termios_locked = o_tty->termios + 1;
-
-	tty_driver_kref_get(driver->other);
-	if (driver->subtype == PTY_TYPE_MASTER)
-		o_tty->count++;
-	/* Establish the links in both directions */
-	tty->link   = o_tty;
-	o_tty->link = tty;
-	/*
-	 * All structures have been allocated, so now we install them.
-	 * Failures after this point use release_tty to clean up, so
-	 * there's no need to null out the local pointers.
-	 */
-	tty_driver_kref_get(driver);
-	tty->count++;
-	pty_count++;
-	return 0;
-free_mem_out:
-	kfree(o_tty->termios);
-	module_put(o_tty->driver->owner);
-	free_tty_struct(o_tty);
-	kfree(tty->termios);
-	return -ENOMEM;
-}
-
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
-	pty_count--;
-}
-
-static const struct tty_operations ptm_unix98_ops = {
-	.lookup = ptm_unix98_lookup,
-	.install = pty_unix98_install,
-	.remove = pty_unix98_remove,
-	.open = pty_open,
-	.close = pty_close,
-	.write = pty_write,
-	.write_room = pty_write_room,
-	.flush_buffer = pty_flush_buffer,
-	.chars_in_buffer = pty_chars_in_buffer,
-	.unthrottle = pty_unthrottle,
-	.set_termios = pty_set_termios,
-	.ioctl = pty_unix98_ioctl,
-	.shutdown = pty_unix98_shutdown,
-	.resize = pty_resize
-};
-
-static const struct tty_operations pty_unix98_ops = {
-	.lookup = pts_unix98_lookup,
-	.install = pty_unix98_install,
-	.remove = pty_unix98_remove,
-	.open = pty_open,
-	.close = pty_close,
-	.write = pty_write,
-	.write_room = pty_write_room,
-	.flush_buffer = pty_flush_buffer,
-	.chars_in_buffer = pty_chars_in_buffer,
-	.unthrottle = pty_unthrottle,
-	.set_termios = pty_set_termios,
-	.shutdown = pty_unix98_shutdown
-};
-
-/**
- *	ptmx_open		-	open a unix 98 pty master
- *	@inode: inode of device file
- *	@filp: file pointer to tty
- *
- *	Allocate a unix98 pty master device from the ptmx driver.
- *
- *	Locking: tty_mutex protects the init_dev work. tty->count should
- * 		protect the rest.
- *		allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty;
-	int retval;
-	int index;
-
-	nonseekable_open(inode, filp);
-
-	/* find a device that is not in use. */
-	tty_lock();
-	index = devpts_new_index(inode);
-	tty_unlock();
-	if (index < 0)
-		return index;
-
-	mutex_lock(&tty_mutex);
-	tty_lock();
-	tty = tty_init_dev(ptm_driver, index, 1);
-	mutex_unlock(&tty_mutex);
-
-	if (IS_ERR(tty)) {
-		retval = PTR_ERR(tty);
-		goto out;
-	}
-
-	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-
-	tty_add_file(tty, filp);
-
-	retval = devpts_pty_new(inode, tty->link);
-	if (retval)
-		goto out1;
-
-	retval = ptm_driver->ops->open(tty, filp);
-	if (retval)
-		goto out2;
-out1:
-	tty_unlock();
-	return retval;
-out2:
-	tty_unlock();
-	tty_release(inode, filp);
-	return retval;
-out:
-	devpts_kill_index(inode, index);
-	tty_unlock();
-	return retval;
-}
-
-static struct file_operations ptmx_fops;
-
-static void __init unix98_pty_init(void)
-{
-	ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-	if (!ptm_driver)
-		panic("Couldn't allocate Unix98 ptm driver");
-	pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-	if (!pts_driver)
-		panic("Couldn't allocate Unix98 pts driver");
-
-	ptm_driver->owner = THIS_MODULE;
-	ptm_driver->driver_name = "pty_master";
-	ptm_driver->name = "ptm";
-	ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
-	ptm_driver->minor_start = 0;
-	ptm_driver->type = TTY_DRIVER_TYPE_PTY;
-	ptm_driver->subtype = PTY_TYPE_MASTER;
-	ptm_driver->init_termios = tty_std_termios;
-	ptm_driver->init_termios.c_iflag = 0;
-	ptm_driver->init_termios.c_oflag = 0;
-	ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-	ptm_driver->init_termios.c_lflag = 0;
-	ptm_driver->init_termios.c_ispeed = 38400;
-	ptm_driver->init_termios.c_ospeed = 38400;
-	ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-	ptm_driver->other = pts_driver;
-	tty_set_operations(ptm_driver, &ptm_unix98_ops);
-
-	pts_driver->owner = THIS_MODULE;
-	pts_driver->driver_name = "pty_slave";
-	pts_driver->name = "pts";
-	pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
-	pts_driver->minor_start = 0;
-	pts_driver->type = TTY_DRIVER_TYPE_PTY;
-	pts_driver->subtype = PTY_TYPE_SLAVE;
-	pts_driver->init_termios = tty_std_termios;
-	pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-	pts_driver->init_termios.c_ispeed = 38400;
-	pts_driver->init_termios.c_ospeed = 38400;
-	pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-		TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-	pts_driver->other = ptm_driver;
-	tty_set_operations(pts_driver, &pty_unix98_ops);
-
-	if (tty_register_driver(ptm_driver))
-		panic("Couldn't register Unix98 ptm driver");
-	if (tty_register_driver(pts_driver))
-		panic("Couldn't register Unix98 pts driver");
-
-	register_sysctl_table(pty_root_table);
-
-	/* Now create the /dev/ptmx special device */
-	tty_default_fops(&ptmx_fops);
-	ptmx_fops.open = ptmx_open;
-
-	cdev_init(&ptmx_cdev, &ptmx_fops);
-	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-		panic("Couldn't register /dev/ptmx driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-}
-
-#else
-static inline void unix98_pty_init(void) { }
-#endif
-
-static int __init pty_init(void)
-{
-	legacy_pty_init();
-	unix98_pty_init();
-	return 0;
-}
-module_init(pty_init);
diff -druN linux-libre-2.6.36-gnu/drivers/char/ramoops.c linux-libre-2.6.37-gnu/drivers/char/ramoops.c
--- linux-libre-2.6.36-gnu/drivers/char/ramoops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/ramoops.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,9 +25,10 @@
 #include <linux/time.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/ramoops.h>
 
 #define RAMOOPS_KERNMSG_HDR "===="
-#define RAMOOPS_HEADER_SIZE   (5 + sizeof(struct timeval))
 
 #define RECORD_SIZE 4096
 
@@ -63,8 +64,8 @@
 			struct ramoops_context, dump);
 	unsigned long s1_start, s2_start;
 	unsigned long l1_cpy, l2_cpy;
-	int res;
-	char *buf;
+	int res, hdr_size;
+	char *buf, *buf_orig;
 	struct timeval timestamp;
 
 	/* Only dump oopses if dump_oops is set */
@@ -72,6 +73,8 @@
 		return;
 
 	buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+	buf_orig = buf;
+
 	memset(buf, '\0', RECORD_SIZE);
 	res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
 	buf += res;
@@ -79,8 +82,9 @@
 	res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
 	buf += res;
 
-	l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
-	l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+	hdr_size = buf - buf_orig;
+	l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size));
+	l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy);
 
 	s2_start = l2 - l2_cpy;
 	s1_start = l1 - l1_cpy;
@@ -91,11 +95,17 @@
 	cxt->count = (cxt->count + 1) % cxt->max_count;
 }
 
-static int __init ramoops_init(void)
+static int __init ramoops_probe(struct platform_device *pdev)
 {
+	struct ramoops_platform_data *pdata = pdev->dev.platform_data;
 	struct ramoops_context *cxt = &oops_cxt;
 	int err = -EINVAL;
 
+	if (pdata) {
+		mem_size = pdata->mem_size;
+		mem_address = pdata->mem_address;
+	}
+
 	if (!mem_size) {
 		printk(KERN_ERR "ramoops: invalid size specification");
 		goto fail3;
@@ -142,7 +152,7 @@
 	return err;
 }
 
-static void __exit ramoops_exit(void)
+static int __exit ramoops_remove(struct platform_device *pdev)
 {
 	struct ramoops_context *cxt = &oops_cxt;
 
@@ -151,8 +161,26 @@
 
 	iounmap(cxt->virt_addr);
 	release_mem_region(cxt->phys_addr, cxt->size);
+	return 0;
 }
 
+static struct platform_driver ramoops_driver = {
+	.remove		= __exit_p(ramoops_remove),
+	.driver		= {
+		.name	= "ramoops",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ramoops_init(void)
+{
+	return platform_driver_probe(&ramoops_driver, ramoops_probe);
+}
+
+static void __exit ramoops_exit(void)
+{
+	platform_driver_unregister(&ramoops_driver);
+}
 
 module_init(ramoops_init);
 module_exit(ramoops_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/char/random.c linux-libre-2.6.37-gnu/drivers/char/random.c
--- linux-libre-2.6.36-gnu/drivers/char/random.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/random.c	2011-01-04 19:50:19.000000000 -0500
@@ -1165,6 +1165,7 @@
 	.poll  = random_poll,
 	.unlocked_ioctl = random_ioctl,
 	.fasync = random_fasync,
+	.llseek = noop_llseek,
 };
 
 const struct file_operations urandom_fops = {
@@ -1172,6 +1173,7 @@
 	.write = random_write,
 	.unlocked_ioctl = random_ioctl,
 	.fasync = random_fasync,
+	.llseek = noop_llseek,
 };
 
 /***************************************************************
diff -druN linux-libre-2.6.36-gnu/drivers/char/raw.c linux-libre-2.6.37-gnu/drivers/char/raw.c
--- linux-libre-2.6.36-gnu/drivers/char/raw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/raw.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,8 +19,8 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/gfp.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 
@@ -55,7 +55,6 @@
 		return 0;
 	}
 
-	lock_kernel();
 	mutex_lock(&raw_mutex);
 
 	/*
@@ -82,7 +81,6 @@
 			bdev->bd_inode->i_mapping;
 	filp->private_data = bdev;
 	mutex_unlock(&raw_mutex);
-	unlock_kernel();
 	return 0;
 
 out2:
@@ -91,7 +89,6 @@
 	blkdev_put(bdev, filp->f_mode);
 out:
 	mutex_unlock(&raw_mutex);
-	unlock_kernel();
 	return err;
 }
 
@@ -125,20 +122,84 @@
 raw_ioctl(struct file *filp, unsigned int command, unsigned long arg)
 {
 	struct block_device *bdev = filp->private_data;
-	int ret;
+	return blkdev_ioctl(bdev, 0, command, arg);
+}
 
-	lock_kernel();
-	ret = blkdev_ioctl(bdev, 0, command, arg);
-	unlock_kernel();
+static int bind_set(int number, u64 major, u64 minor)
+{
+	dev_t dev = MKDEV(major, minor);
+	struct raw_device_data *rawdev;
+	int err = 0;
 
-	return ret;
+	if (number <= 0 || number >= MAX_RAW_MINORS)
+		return -EINVAL;
+
+	if (MAJOR(dev) != major || MINOR(dev) != minor)
+		return -EINVAL;
+
+	rawdev = &raw_devices[number];
+
+	/*
+	 * This is like making block devices, so demand the
+	 * same capability
+	 */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	/*
+	 * For now, we don't need to check that the underlying
+	 * block device is present or not: we can do that when
+	 * the raw device is opened.  Just check that the
+	 * major/minor numbers make sense.
+	 */
+
+	if (MAJOR(dev) == 0 && dev != 0)
+		return -EINVAL;
+
+	mutex_lock(&raw_mutex);
+	if (rawdev->inuse) {
+		mutex_unlock(&raw_mutex);
+		return -EBUSY;
+	}
+	if (rawdev->binding) {
+		bdput(rawdev->binding);
+		module_put(THIS_MODULE);
+	}
+	if (!dev) {
+		/* unbind */
+		rawdev->binding = NULL;
+		device_destroy(raw_class, MKDEV(RAW_MAJOR, number));
+	} else {
+		rawdev->binding = bdget(dev);
+		if (rawdev->binding == NULL) {
+			err = -ENOMEM;
+		} else {
+			dev_t raw = MKDEV(RAW_MAJOR, number);
+			__module_get(THIS_MODULE);
+			device_destroy(raw_class, raw);
+			device_create(raw_class, NULL, raw, NULL,
+				      "raw%d", number);
+		}
+	}
+	mutex_unlock(&raw_mutex);
+	return err;
 }
 
-static void bind_device(struct raw_config_request *rq)
+static int bind_get(int number, dev_t *dev)
 {
-	device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor));
-	device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL,
-		      "raw%d", rq->raw_minor);
+	struct raw_device_data *rawdev;
+	struct block_device *bdev;
+
+	if (number <= 0 || number >= MAX_RAW_MINORS)
+		return -EINVAL;
+
+	rawdev = &raw_devices[number];
+
+	mutex_lock(&raw_mutex);
+	bdev = rawdev->binding;
+	*dev = bdev ? bdev->bd_dev : 0;
+	mutex_unlock(&raw_mutex);
+	return 0;
 }
 
 /*
@@ -149,105 +210,78 @@
 			  unsigned long arg)
 {
 	struct raw_config_request rq;
-	struct raw_device_data *rawdev;
-	int err = 0;
+	dev_t dev;
+	int err;
 
-	lock_kernel();
 	switch (command) {
 	case RAW_SETBIND:
+		if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
+			return -EFAULT;
+
+		return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
+
 	case RAW_GETBIND:
+		if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
+			return -EFAULT;
 
-		/* First, find out which raw minor we want */
+		err = bind_get(rq.raw_minor, &dev);
+		if (err)
+			return err;
 
-		if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) {
-			err = -EFAULT;
-			goto out;
-		}
+		rq.block_major = MAJOR(dev);
+		rq.block_minor = MINOR(dev);
 
-		if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) {
-			err = -EINVAL;
-			goto out;
-		}
-		rawdev = &raw_devices[rq.raw_minor];
+		if (copy_to_user((void __user *)arg, &rq, sizeof(rq)))
+			return -EFAULT;
 
-		if (command == RAW_SETBIND) {
-			dev_t dev;
+		return 0;
+	}
 
-			/*
-			 * This is like making block devices, so demand the
-			 * same capability
-			 */
-			if (!capable(CAP_SYS_ADMIN)) {
-				err = -EPERM;
-				goto out;
-			}
+	return -EINVAL;
+}
 
-			/*
-			 * For now, we don't need to check that the underlying
-			 * block device is present or not: we can do that when
-			 * the raw device is opened.  Just check that the
-			 * major/minor numbers make sense.
-			 */
+#ifdef CONFIG_COMPAT
+struct raw32_config_request {
+	compat_int_t	raw_minor;
+	compat_u64	block_major;
+	compat_u64	block_minor;
+};
 
-			dev = MKDEV(rq.block_major, rq.block_minor);
-			if ((rq.block_major == 0 && rq.block_minor != 0) ||
-					MAJOR(dev) != rq.block_major ||
-					MINOR(dev) != rq.block_minor) {
-				err = -EINVAL;
-				goto out;
-			}
+static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct raw32_config_request __user *user_req = compat_ptr(arg);
+	struct raw32_config_request rq;
+	dev_t dev;
+	int err = 0;
 
-			mutex_lock(&raw_mutex);
-			if (rawdev->inuse) {
-				mutex_unlock(&raw_mutex);
-				err = -EBUSY;
-				goto out;
-			}
-			if (rawdev->binding) {
-				bdput(rawdev->binding);
-				module_put(THIS_MODULE);
-			}
-			if (rq.block_major == 0 && rq.block_minor == 0) {
-				/* unbind */
-				rawdev->binding = NULL;
-				device_destroy(raw_class,
-						MKDEV(RAW_MAJOR, rq.raw_minor));
-			} else {
-				rawdev->binding = bdget(dev);
-				if (rawdev->binding == NULL)
-					err = -ENOMEM;
-				else {
-					__module_get(THIS_MODULE);
-					bind_device(&rq);
-				}
-			}
-			mutex_unlock(&raw_mutex);
-		} else {
-			struct block_device *bdev;
+	switch (cmd) {
+	case RAW_SETBIND:
+		if (copy_from_user(&rq, user_req, sizeof(rq)))
+			return -EFAULT;
 
-			mutex_lock(&raw_mutex);
-			bdev = rawdev->binding;
-			if (bdev) {
-				rq.block_major = MAJOR(bdev->bd_dev);
-				rq.block_minor = MINOR(bdev->bd_dev);
-			} else {
-				rq.block_major = rq.block_minor = 0;
-			}
-			mutex_unlock(&raw_mutex);
-			if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) {
-				err = -EFAULT;
-				goto out;
-			}
-		}
-		break;
-	default:
-		err = -EINVAL;
-		break;
+		return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
+
+	case RAW_GETBIND:
+		if (copy_from_user(&rq, user_req, sizeof(rq)))
+			return -EFAULT;
+
+		err = bind_get(rq.raw_minor, &dev);
+		if (err)
+			return err;
+
+		rq.block_major = MAJOR(dev);
+		rq.block_minor = MINOR(dev);
+
+		if (copy_to_user(user_req, &rq, sizeof(rq)))
+			return -EFAULT;
+
+		return 0;
 	}
-out:
-	unlock_kernel();
-	return err;
+
+	return -EINVAL;
 }
+#endif
 
 static const struct file_operations raw_fops = {
 	.read		= do_sync_read,
@@ -258,13 +292,18 @@
 	.open		= raw_open,
 	.release	= raw_release,
 	.unlocked_ioctl = raw_ioctl,
+	.llseek		= default_llseek,
 	.owner		= THIS_MODULE,
 };
 
 static const struct file_operations raw_ctl_fops = {
 	.unlocked_ioctl = raw_ctl_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= raw_ctl_compat_ioctl,
+#endif
 	.open		= raw_open,
 	.owner		= THIS_MODULE,
+	.llseek		= noop_llseek,
 };
 
 static struct cdev raw_cdev;
diff -druN linux-libre-2.6.36-gnu/drivers/char/rio/Makefile linux-libre-2.6.37-gnu/drivers/char/rio/Makefile
--- linux-libre-2.6.36-gnu/drivers/char/rio/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/rio/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -8,5 +8,5 @@
 
 obj-$(CONFIG_RIO) += rio.o
 
-rio-objs := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+rio-y := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
             rioparam.o rioroute.o riotable.o riotty.o
diff -druN linux-libre-2.6.36-gnu/drivers/char/rio/rio_linux.c linux-libre-2.6.37-gnu/drivers/char/rio/rio_linux.c
--- linux-libre-2.6.36-gnu/drivers/char/rio/rio_linux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/rio/rio_linux.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,7 +44,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 
@@ -122,6 +122,7 @@
 
 
 /* These constants are derived from SCO Source */
+static DEFINE_MUTEX(rio_fw_mutex);
 static struct Conf
  RIOConf = {
 	/* locator */ "RIO Config here",
@@ -241,6 +242,7 @@
 static const struct file_operations rio_fw_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = rio_fw_ioctl,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice rio_fw_device = {
@@ -566,9 +568,9 @@
 	func_enter();
 
 	/* The "dev" argument isn't used. */
-	lock_kernel();
+	mutex_lock(&rio_fw_mutex);
 	rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN));
-	unlock_kernel();
+	mutex_unlock(&rio_fw_mutex);
 
 	func_exit();
 	return rc;
diff -druN linux-libre-2.6.36-gnu/drivers/char/rocket.c linux-libre-2.6.37-gnu/drivers/char/rocket.c
--- linux-libre-2.6.36-gnu/drivers/char/rocket.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/rocket.c	2011-01-04 19:50:19.000000000 -0500
@@ -2345,7 +2345,7 @@
 	ret = tty_register_driver(rocket_driver);
 	if (ret < 0) {
 		printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
-		goto err_tty;
+		goto err_controller;
 	}
 
 #ifdef ROCKET_DEBUG_OPEN
@@ -2380,6 +2380,9 @@
 	return 0;
 err_ttyu:
 	tty_unregister_driver(rocket_driver);
+err_controller:
+	if (controller)
+		release_region(controller, 4);
 err_tty:
 	put_tty_driver(rocket_driver);
 err:
diff -druN linux-libre-2.6.36-gnu/drivers/char/scx200_gpio.c linux-libre-2.6.37-gnu/drivers/char/scx200_gpio.c
--- linux-libre-2.6.36-gnu/drivers/char/scx200_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/scx200_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,6 +67,7 @@
 	.read    = nsc_gpio_read,
 	.open    = scx200_gpio_open,
 	.release = scx200_gpio_release,
+	.llseek  = no_llseek,
 };
 
 static struct cdev scx200_gpio_cdev;  /* use 1 cdev for all pins */
diff -druN linux-libre-2.6.36-gnu/drivers/char/selection.c linux-libre-2.6.37-gnu/drivers/char/selection.c
--- linux-libre-2.6.36-gnu/drivers/char/selection.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/selection.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,348 +0,0 @@
-/*
- * linux/drivers/char/selection.c
- *
- * This module exports the functions:
- *
- *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
- *     'void clear_selection(void)'
- *     'int paste_selection(struct tty_struct *)'
- *     'int sel_loadlut(char __user *)'
- *
- * Now that /dev/vcs exists, most of this can disappear again.
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/tiocl.h>
-#include <linux/console.h>
-#include <linux/smp_lock.h>
-
-/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c)	((c) == ' ')
-
-extern void poke_blanked_console(void);
-
-/* Variables for selection control. */
-/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons;		/* must not be deallocated */
-static int use_unicode;
-static volatile int sel_start = -1; 	/* cleared by clear_selection */
-static int sel_end;
-static int sel_buffer_lth;
-static char *sel_buffer;
-
-/* clear_selection, highlight and highlight_pointer can be called
-   from interrupt (via scrollback/front) */
-
-/* set reverse video on characters s-e of console with selection. */
-static inline void highlight(const int s, const int e)
-{
-	invert_screen(sel_cons, s, e-s+2, 1);
-}
-
-/* use complementary color to show the pointer */
-static inline void highlight_pointer(const int where)
-{
-	complement_pos(sel_cons, where);
-}
-
-static u16
-sel_pos(int n)
-{
-	return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
-				use_unicode);
-}
-
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
-	highlight_pointer(-1); /* hide the pointer */
-	if (sel_start != -1) {
-		highlight(sel_start, sel_end);
-		sel_start = -1;
-	}
-}
-
-/*
- * User settable table: what characters are to be considered alphabetic?
- * 256 bits
- */
-static u32 inwordLut[8]={
-  0x00000000, /* control chars     */
-  0x03FF0000, /* digits            */
-  0x87FFFFFE, /* uppercase and '_' */
-  0x07FFFFFE, /* lowercase         */
-  0x00000000,
-  0x00000000,
-  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
-  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
-};
-
-static inline int inword(const u16 c) {
-	return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
-}
-
-/* set inwordLut contents. Invoked by ioctl(). */
-int sel_loadlut(char __user *p)
-{
-	return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
-}
-
-/* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p, int size_row)
-{
-	return (!(p % size_row)	|| !((p + 2) % size_row));
-}
-
-/* constrain v such that v <= u */
-static inline unsigned short limit(const unsigned short v, const unsigned short u)
-{
-	return (v > u) ? u : v;
-}
-
-/* stores the char in UTF8 and returns the number of bytes used (1-3) */
-static int store_utf8(u16 c, char *p)
-{
-	if (c < 0x80) {
-		/*  0******* */
-		p[0] = c;
-		return 1;
-	} else if (c < 0x800) {
-		/* 110***** 10****** */
-		p[0] = 0xc0 | (c >> 6);
-		p[1] = 0x80 | (c & 0x3f);
-		return 2;
-    	} else {
-		/* 1110**** 10****** 10****** */
-		p[0] = 0xe0 | (c >> 12);
-		p[1] = 0x80 | ((c >> 6) & 0x3f);
-		p[2] = 0x80 | (c & 0x3f);
-		return 3;
-    	}
-}
-
-/* set the current selection. Invoked by ioctl() or by kernel code. */
-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-	int sel_mode, new_sel_start, new_sel_end, spc;
-	char *bp, *obp;
-	int i, ps, pe, multiplier;
-	u16 c;
-	struct kbd_struct *kbd = kbd_table + fg_console;
-
-	poke_blanked_console();
-
-	{ unsigned short xs, ys, xe, ye;
-
-	  if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
-		return -EFAULT;
-	  __get_user(xs, &sel->xs);
-	  __get_user(ys, &sel->ys);
-	  __get_user(xe, &sel->xe);
-	  __get_user(ye, &sel->ye);
-	  __get_user(sel_mode, &sel->sel_mode);
-	  xs--; ys--; xe--; ye--;
-	  xs = limit(xs, vc->vc_cols - 1);
-	  ys = limit(ys, vc->vc_rows - 1);
-	  xe = limit(xe, vc->vc_cols - 1);
-	  ye = limit(ye, vc->vc_rows - 1);
-	  ps = ys * vc->vc_size_row + (xs << 1);
-	  pe = ye * vc->vc_size_row + (xe << 1);
-
-	  if (sel_mode == TIOCL_SELCLEAR) {
-	      /* useful for screendump without selection highlights */
-	      clear_selection();
-	      return 0;
-	  }
-
-	  if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
-	      mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
-	      return 0;
-	  }
-        }
-
-	if (ps > pe)	/* make sel_start <= sel_end */
-	{
-		int tmp = ps;
-		ps = pe;
-		pe = tmp;
-	}
-
-	if (sel_cons != vc_cons[fg_console].d) {
-		clear_selection();
-		sel_cons = vc_cons[fg_console].d;
-	}
-	use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
-
-	switch (sel_mode)
-	{
-		case TIOCL_SELCHAR:	/* character-by-character selection */
-			new_sel_start = ps;
-			new_sel_end = pe;
-			break;
-		case TIOCL_SELWORD:	/* word-by-word selection */
-			spc = isspace(sel_pos(ps));
-			for (new_sel_start = ps; ; ps -= 2)
-			{
-				if ((spc && !isspace(sel_pos(ps))) ||
-				    (!spc && !inword(sel_pos(ps))))
-					break;
-				new_sel_start = ps;
-				if (!(ps % vc->vc_size_row))
-					break;
-			}
-			spc = isspace(sel_pos(pe));
-			for (new_sel_end = pe; ; pe += 2)
-			{
-				if ((spc && !isspace(sel_pos(pe))) ||
-				    (!spc && !inword(sel_pos(pe))))
-					break;
-				new_sel_end = pe;
-				if (!((pe + 2) % vc->vc_size_row))
-					break;
-			}
-			break;
-		case TIOCL_SELLINE:	/* line-by-line selection */
-			new_sel_start = ps - ps % vc->vc_size_row;
-			new_sel_end = pe + vc->vc_size_row
-				    - pe % vc->vc_size_row - 2;
-			break;
-		case TIOCL_SELPOINTER:
-			highlight_pointer(pe);
-			return 0;
-		default:
-			return -EINVAL;
-	}
-
-	/* remove the pointer */
-	highlight_pointer(-1);
-
-	/* select to end of line if on trailing space */
-	if (new_sel_end > new_sel_start &&
-		!atedge(new_sel_end, vc->vc_size_row) &&
-		isspace(sel_pos(new_sel_end))) {
-		for (pe = new_sel_end + 2; ; pe += 2)
-			if (!isspace(sel_pos(pe)) ||
-			    atedge(pe, vc->vc_size_row))
-				break;
-		if (isspace(sel_pos(pe)))
-			new_sel_end = pe;
-	}
-	if (sel_start == -1)	/* no current selection */
-		highlight(new_sel_start, new_sel_end);
-	else if (new_sel_start == sel_start)
-	{
-		if (new_sel_end == sel_end)	/* no action required */
-			return 0;
-		else if (new_sel_end > sel_end)	/* extend to right */
-			highlight(sel_end + 2, new_sel_end);
-		else				/* contract from right */
-			highlight(new_sel_end + 2, sel_end);
-	}
-	else if (new_sel_end == sel_end)
-	{
-		if (new_sel_start < sel_start)	/* extend to left */
-			highlight(new_sel_start, sel_start - 2);
-		else				/* contract from left */
-			highlight(sel_start, new_sel_start - 2);
-	}
-	else	/* some other case; start selection from scratch */
-	{
-		clear_selection();
-		highlight(new_sel_start, new_sel_end);
-	}
-	sel_start = new_sel_start;
-	sel_end = new_sel_end;
-
-	/* Allocate a new buffer before freeing the old one ... */
-	multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
-	bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
-	if (!bp) {
-		printk(KERN_WARNING "selection: kmalloc() failed\n");
-		clear_selection();
-		return -ENOMEM;
-	}
-	kfree(sel_buffer);
-	sel_buffer = bp;
-
-	obp = bp;
-	for (i = sel_start; i <= sel_end; i += 2) {
-		c = sel_pos(i);
-		if (use_unicode)
-			bp += store_utf8(c, bp);
-		else
-			*bp++ = c;
-		if (!isspace(c))
-			obp = bp;
-		if (! ((i + 2) % vc->vc_size_row)) {
-			/* strip trailing blanks from line and add newline,
-			   unless non-space at end of line. */
-			if (obp != bp) {
-				bp = obp;
-				*bp++ = '\r';
-			}
-			obp = bp;
-		}
-	}
-	sel_buffer_lth = bp - sel_buffer;
-	return 0;
-}
-
-/* Insert the contents of the selection buffer into the
- * queue of the tty associated with the current console.
- * Invoked by ioctl().
- */
-int paste_selection(struct tty_struct *tty)
-{
-	struct vc_data *vc = tty->driver_data;
-	int	pasted = 0;
-	unsigned int count;
-	struct  tty_ldisc *ld;
-	DECLARE_WAITQUEUE(wait, current);
-
-	/* always called with BTM from vt_ioctl */
-	WARN_ON(!tty_locked());
-
-	acquire_console_sem();
-	poke_blanked_console();
-	release_console_sem();
-
-	ld = tty_ldisc_ref(tty);
-	if (!ld) {
-		tty_unlock();
-		ld = tty_ldisc_ref_wait(tty);
-		tty_lock();
-	}
-
-	add_wait_queue(&vc->paste_wait, &wait);
-	while (sel_buffer && sel_buffer_lth > pasted) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (test_bit(TTY_THROTTLED, &tty->flags)) {
-			schedule();
-			continue;
-		}
-		count = sel_buffer_lth - pasted;
-		count = min(count, tty->receive_room);
-		tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
-								NULL, count);
-		pasted += count;
-	}
-	remove_wait_queue(&vc->paste_wait, &wait);
-	__set_current_state(TASK_RUNNING);
-
-	tty_ldisc_deref(ld);
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/char/serial167.c linux-libre-2.6.37-gnu/drivers/char/serial167.c
--- linux-libre-2.6.36-gnu/drivers/char/serial167.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/serial167.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,6 @@
 #include <linux/interrupt.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
-#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
diff -druN linux-libre-2.6.36-gnu/drivers/char/snsc.c linux-libre-2.6.37-gnu/drivers/char/snsc.c
--- linux-libre-2.6.36-gnu/drivers/char/snsc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/snsc.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,7 @@
 #include <linux/poll.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <asm/sn/io.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/module.h>
@@ -34,6 +34,7 @@
 #define SCDRV_BUFSZ	2048
 #define SCDRV_TIMEOUT	1000
 
+static DEFINE_MUTEX(scdrv_mutex);
 static irqreturn_t
 scdrv_interrupt(int irq, void *subch_data)
 {
@@ -105,7 +106,7 @@
 	file->private_data = sd;
 
 	/* hook this subchannel up to the system controller interrupt */
-	lock_kernel();
+	mutex_lock(&scdrv_mutex);
 	rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
 			 IRQF_SHARED | IRQF_DISABLED,
 			 SYSCTL_BASENAME, sd);
@@ -113,10 +114,10 @@
 		ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
 		kfree(sd);
 		printk("%s: irq request failed (%d)\n", __func__, rv);
-		unlock_kernel();
+		mutex_unlock(&scdrv_mutex);
 		return -EBUSY;
 	}
-	unlock_kernel();
+	mutex_unlock(&scdrv_mutex);
 	return 0;
 }
 
@@ -357,6 +358,7 @@
 	.poll =		scdrv_poll,
 	.open =		scdrv_open,
 	.release =	scdrv_release,
+	.llseek =	noop_llseek,
 };
 
 static struct class *snsc_class;
diff -druN linux-libre-2.6.36-gnu/drivers/char/specialix.c linux-libre-2.6.37-gnu/drivers/char/specialix.c
--- linux-libre-2.6.36-gnu/drivers/char/specialix.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/specialix.c	2011-01-04 19:50:19.000000000 -0500
@@ -87,7 +87,6 @@
 #include <linux/tty_flip.h>
 #include <linux/mm.h>
 #include <linux/serial.h>
-#include <linux/smp_lock.h>
 #include <linux/fcntl.h>
 #include <linux/major.h>
 #include <linux/delay.h>
diff -druN linux-libre-2.6.36-gnu/drivers/char/stallion.c linux-libre-2.6.37-gnu/drivers/char/stallion.c
--- linux-libre-2.6.36-gnu/drivers/char/stallion.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/stallion.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,6 @@
 #include <linux/stallion.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/ctype.h>
@@ -608,6 +607,7 @@
 static const struct file_operations	stl_fsiomem = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= stl_memioctl,
+	.llseek		= noop_llseek,
 };
 
 static struct class *stallion_class;
@@ -3180,7 +3180,7 @@
 
 /*
  *	Return the current state of data flow on this port. This is only
- *	really interresting when determining if data has fully completed
+ *	really interesting when determining if data has fully completed
  *	transmission or not... This is easy for the cd1400, it accurately
  *	maintains the busy port flag.
  */
@@ -4130,7 +4130,7 @@
 
 /*
  *	Return the current state of data flow on this port. This is only
- *	really interresting when determining if data has fully completed
+ *	really interesting when determining if data has fully completed
  *	transmission or not... The sc26198 interrupt scheme cannot
  *	determine when all data has actually drained, so we need to
  *	check the port statusy register to be sure.
diff -druN linux-libre-2.6.36-gnu/drivers/char/sx.c linux-libre-2.6.37-gnu/drivers/char/sx.c
--- linux-libre-2.6.36-gnu/drivers/char/sx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/sx.c	2011-01-04 19:50:19.000000000 -0500
@@ -216,7 +216,6 @@
 #include <linux/eisa.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/bitops.h>
@@ -397,6 +396,7 @@
 static const struct file_operations sx_fw_fops = {
 	.owner = THIS_MODULE,
 	.unlocked_ioctl = sx_fw_ioctl,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice sx_fw_device = {
diff -druN linux-libre-2.6.36-gnu/drivers/char/synclink.c linux-libre-2.6.37-gnu/drivers/char/synclink.c
--- linux-libre-2.6.36-gnu/drivers/char/synclink.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/synclink.c	2011-01-04 19:50:19.000000000 -0500
@@ -2925,6 +2925,38 @@
 	
 }	/* end of mgsl_break() */
 
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ *     RI where only 0->1 is counted.
+ */
+static int msgl_get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
+
+{
+	struct mgsl_struct * info = tty->driver_data;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->irq_spinlock,flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+	return 0;
+}
+
 /* mgsl_ioctl()	Service an IOCTL request
  * 	
  * Arguments:
@@ -2949,7 +2981,7 @@
 		return -ENODEV;
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+	    (cmd != TIOCMIWAIT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
@@ -2959,11 +2991,7 @@
 
 static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
 {
-	int error;
-	struct mgsl_icount cnow;	/* kernel counter temps */
 	void __user *argp = (void __user *)arg;
-	struct serial_icounter_struct __user *p_cuser;	/* user space */
-	unsigned long flags;
 	
 	switch (cmd) {
 		case MGSL_IOCGPARAMS:
@@ -2992,40 +3020,6 @@
 		case TIOCMIWAIT:
 			return modem_input_wait(info,(int)arg);
 
-		/* 
-		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
-		 * Return: write counters to the user passed counter struct
-		 * NB: both 1->0 and 0->1 transitions are counted except for
-		 *     RI where only 0->1 is counted.
-		 */
-		case TIOCGICOUNT:
-			spin_lock_irqsave(&info->irq_spinlock,flags);
-			cnow = info->icount;
-			spin_unlock_irqrestore(&info->irq_spinlock,flags);
-			p_cuser = argp;
-			PUT_USER(error,cnow.cts, &p_cuser->cts);
-			if (error) return error;
-			PUT_USER(error,cnow.dsr, &p_cuser->dsr);
-			if (error) return error;
-			PUT_USER(error,cnow.rng, &p_cuser->rng);
-			if (error) return error;
-			PUT_USER(error,cnow.dcd, &p_cuser->dcd);
-			if (error) return error;
-			PUT_USER(error,cnow.rx, &p_cuser->rx);
-			if (error) return error;
-			PUT_USER(error,cnow.tx, &p_cuser->tx);
-			if (error) return error;
-			PUT_USER(error,cnow.frame, &p_cuser->frame);
-			if (error) return error;
-			PUT_USER(error,cnow.overrun, &p_cuser->overrun);
-			if (error) return error;
-			PUT_USER(error,cnow.parity, &p_cuser->parity);
-			if (error) return error;
-			PUT_USER(error,cnow.brk, &p_cuser->brk);
-			if (error) return error;
-			PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
-			if (error) return error;
-			return 0;
 		default:
 			return -ENOIOCTLCMD;
 	}
@@ -4328,6 +4322,7 @@
 	.hangup = mgsl_hangup,
 	.tiocmget = tiocmget,
 	.tiocmset = tiocmset,
+	.get_icount = msgl_get_icount,
 	.proc_fops = &mgsl_proc_fops,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/synclink_gt.c linux-libre-2.6.37-gnu/drivers/char/synclink_gt.c
--- linux-libre-2.6.36-gnu/drivers/char/synclink_gt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/synclink_gt.c	2011-01-04 19:50:19.000000000 -0500
@@ -301,6 +301,8 @@
 	unsigned int rx_pio;
 	unsigned int if_mode;
 	unsigned int base_clock;
+	unsigned int xsync;
+	unsigned int xctrl;
 
 	/* device status */
 
@@ -405,6 +407,8 @@
 #define TDCSR 0x94 /* tx DMA control/status */
 #define RDDAR 0x98 /* rx DMA descriptor address */
 #define TDDAR 0x9c /* tx DMA descriptor address */
+#define XSR   0x40 /* extended sync pattern */
+#define XCR   0x44 /* extended control */
 
 #define RXIDLE      BIT14
 #define RXBREAK     BIT14
@@ -517,6 +521,10 @@
 static int  set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
 static int  get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
 static int  wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int  get_xsync(struct slgt_info *info, int __user *if_mode);
+static int  set_xsync(struct slgt_info *info, int if_mode);
+static int  get_xctrl(struct slgt_info *info, int __user *if_mode);
+static int  set_xctrl(struct slgt_info *info, int if_mode);
 
 /*
  * driver functions
@@ -1032,9 +1040,6 @@
 		 unsigned int cmd, unsigned long arg)
 {
 	struct slgt_info *info = tty->driver_data;
-	struct mgsl_icount cnow;	/* kernel counter temps */
-	struct serial_icounter_struct __user *p_cuser;	/* user space */
-	unsigned long flags;
 	void __user *argp = (void __user *)arg;
 	int ret;
 
@@ -1043,7 +1048,7 @@
 	DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd));
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+	    (cmd != TIOCMIWAIT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
@@ -1053,30 +1058,20 @@
 		return wait_mgsl_event(info, argp);
 	case TIOCMIWAIT:
 		return modem_input_wait(info,(int)arg);
-	case TIOCGICOUNT:
-		spin_lock_irqsave(&info->lock,flags);
-		cnow = info->icount;
-		spin_unlock_irqrestore(&info->lock,flags);
-		p_cuser = argp;
-		if (put_user(cnow.cts, &p_cuser->cts) ||
-		    put_user(cnow.dsr, &p_cuser->dsr) ||
-		    put_user(cnow.rng, &p_cuser->rng) ||
-		    put_user(cnow.dcd, &p_cuser->dcd) ||
-		    put_user(cnow.rx, &p_cuser->rx) ||
-		    put_user(cnow.tx, &p_cuser->tx) ||
-		    put_user(cnow.frame, &p_cuser->frame) ||
-		    put_user(cnow.overrun, &p_cuser->overrun) ||
-		    put_user(cnow.parity, &p_cuser->parity) ||
-		    put_user(cnow.brk, &p_cuser->brk) ||
-		    put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
-			return -EFAULT;
-		return 0;
 	case MGSL_IOCSGPIO:
 		return set_gpio(info, argp);
 	case MGSL_IOCGGPIO:
 		return get_gpio(info, argp);
 	case MGSL_IOCWAITGPIO:
 		return wait_gpio(info, argp);
+	case MGSL_IOCGXSYNC:
+		return get_xsync(info, argp);
+	case MGSL_IOCSXSYNC:
+		return set_xsync(info, (int)arg);
+	case MGSL_IOCGXCTRL:
+		return get_xctrl(info, argp);
+	case MGSL_IOCSXCTRL:
+		return set_xctrl(info, (int)arg);
 	}
 	mutex_lock(&info->port.mutex);
 	switch (cmd) {
@@ -1117,6 +1112,33 @@
 	return ret;
 }
 
+static int get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
+
+{
+	struct slgt_info *info = tty->driver_data;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+
+	return 0;
+}
+
 /*
  * support for 32 bit ioctl calls on 64 bit systems
  */
@@ -1126,6 +1148,7 @@
 	struct MGSL_PARAMS32 tmp_params;
 
 	DBGINFO(("%s get_params32\n", info->device_name));
+	memset(&tmp_params, 0, sizeof(tmp_params));
 	tmp_params.mode            = (compat_ulong_t)info->params.mode;
 	tmp_params.loopback        = info->params.loopback;
 	tmp_params.flags           = info->params.flags;
@@ -1206,16 +1229,16 @@
 	case MGSL_IOCSGPIO:
 	case MGSL_IOCGGPIO:
 	case MGSL_IOCWAITGPIO:
-	case TIOCGICOUNT:
-		rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
-		break;
-
+	case MGSL_IOCGXSYNC:
+	case MGSL_IOCGXCTRL:
 	case MGSL_IOCSTXIDLE:
 	case MGSL_IOCTXENABLE:
 	case MGSL_IOCRXENABLE:
 	case MGSL_IOCTXABORT:
 	case TIOCMIWAIT:
 	case MGSL_IOCSIF:
+	case MGSL_IOCSXSYNC:
+	case MGSL_IOCSXCTRL:
 		rc = ioctl(tty, file, cmd, arg);
 		break;
 	}
@@ -1615,6 +1638,8 @@
 	if (cmd != SIOCWANDEV)
 		return hdlc_ioctl(dev, ifr, cmd);
 
+	memset(&new_line, 0, sizeof(new_line));
+
 	switch(ifr->ifr_settings.type) {
 	case IF_GET_IFACE: /* return current sync_serial_settings */
 
@@ -1956,6 +1981,7 @@
 			case MGSL_MODE_RAW:
 			case MGSL_MODE_MONOSYNC:
 			case MGSL_MODE_BISYNC:
+			case MGSL_MODE_XSYNC:
 				while(rx_get_buf(info));
 				break;
 			}
@@ -2355,26 +2381,27 @@
 
 	DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level));
 
-	spin_lock(&info->lock);
-
 	while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
 		DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
 		info->irq_occurred = true;
 		for(i=0; i < info->port_count ; i++) {
 			if (info->port_array[i] == NULL)
 				continue;
+			spin_lock(&info->port_array[i]->lock);
 			if (gsr & (BIT8 << i))
 				isr_serial(info->port_array[i]);
 			if (gsr & (BIT16 << (i*2)))
 				isr_rdma(info->port_array[i]);
 			if (gsr & (BIT17 << (i*2)))
 				isr_tdma(info->port_array[i]);
+			spin_unlock(&info->port_array[i]->lock);
 		}
 	}
 
 	if (info->gpio_present) {
 		unsigned int state;
 		unsigned int changed;
+		spin_lock(&info->lock);
 		while ((changed = rd_reg32(info, IOSR)) != 0) {
 			DBGISR(("%s iosr=%08x\n", info->device_name, changed));
 			/* read latched state of GPIO signals */
@@ -2386,22 +2413,24 @@
 					isr_gpio(info->port_array[i], changed, state);
 			}
 		}
+		spin_unlock(&info->lock);
 	}
 
 	for(i=0; i < info->port_count ; i++) {
 		struct slgt_info *port = info->port_array[i];
-
-		if (port && (port->port.count || port->netcount) &&
+		if (port == NULL)
+			continue;
+		spin_lock(&port->lock);
+		if ((port->port.count || port->netcount) &&
 		    port->pending_bh && !port->bh_running &&
 		    !port->bh_requested) {
 			DBGISR(("%s bh queued\n", port->device_name));
 			schedule_work(&port->task);
 			port->bh_requested = true;
 		}
+		spin_unlock(&port->lock);
 	}
 
-	spin_unlock(&info->lock);
-
 	DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level));
 	return IRQ_HANDLED;
 }
@@ -2881,6 +2910,69 @@
 	return 0;
 }
 
+static int get_xsync(struct slgt_info *info, int __user *xsync)
+{
+	DBGINFO(("%s get_xsync=%x\n", info->device_name, info->xsync));
+	if (put_user(info->xsync, xsync))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * set extended sync pattern (1 to 4 bytes) for extended sync mode
+ *
+ * sync pattern is contained in least significant bytes of value
+ * most significant byte of sync pattern is oldest (1st sent/detected)
+ */
+static int set_xsync(struct slgt_info *info, int xsync)
+{
+	unsigned long flags;
+
+	DBGINFO(("%s set_xsync=%x)\n", info->device_name, xsync));
+	spin_lock_irqsave(&info->lock, flags);
+	info->xsync = xsync;
+	wr_reg32(info, XSR, xsync);
+	spin_unlock_irqrestore(&info->lock, flags);
+	return 0;
+}
+
+static int get_xctrl(struct slgt_info *info, int __user *xctrl)
+{
+	DBGINFO(("%s get_xctrl=%x\n", info->device_name, info->xctrl));
+	if (put_user(info->xctrl, xctrl))
+		return -EFAULT;
+	return 0;
+}
+
+/*
+ * set extended control options
+ *
+ * xctrl[31:19] reserved, must be zero
+ * xctrl[18:17] extended sync pattern length in bytes
+ *              00 = 1 byte  in xsr[7:0]
+ *              01 = 2 bytes in xsr[15:0]
+ *              10 = 3 bytes in xsr[23:0]
+ *              11 = 4 bytes in xsr[31:0]
+ * xctrl[16]    1 = enable terminal count, 0=disabled
+ * xctrl[15:0]  receive terminal count for fixed length packets
+ *              value is count minus one (0 = 1 byte packet)
+ *              when terminal count is reached, receiver
+ *              automatically returns to hunt mode and receive
+ *              FIFO contents are flushed to DMA buffers with
+ *              end of frame (EOF) status
+ */
+static int set_xctrl(struct slgt_info *info, int xctrl)
+{
+	unsigned long flags;
+
+	DBGINFO(("%s set_xctrl=%x)\n", info->device_name, xctrl));
+	spin_lock_irqsave(&info->lock, flags);
+	info->xctrl = xctrl;
+	wr_reg32(info, XCR, xctrl);
+	spin_unlock_irqrestore(&info->lock, flags);
+	return 0;
+}
+
 /*
  * set general purpose IO pin state and direction
  *
@@ -2904,7 +2996,7 @@
 		 info->device_name, gpio.state, gpio.smask,
 		 gpio.dir, gpio.dmask));
 
-	spin_lock_irqsave(&info->lock,flags);
+	spin_lock_irqsave(&info->port_array[0]->lock, flags);
 	if (gpio.dmask) {
 		data = rd_reg32(info, IODR);
 		data |= gpio.dmask & gpio.dir;
@@ -2917,7 +3009,7 @@
 		data &= ~(gpio.smask & ~gpio.state);
 		wr_reg32(info, IOVR, data);
 	}
-	spin_unlock_irqrestore(&info->lock,flags);
+	spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
 
 	return 0;
 }
@@ -3018,7 +3110,7 @@
 		return -EINVAL;
 	init_cond_wait(&wait, gpio.smask);
 
-	spin_lock_irqsave(&info->lock, flags);
+	spin_lock_irqsave(&info->port_array[0]->lock, flags);
 	/* enable interrupts for watched pins */
 	wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
 	/* get current pin states */
@@ -3030,20 +3122,20 @@
 	} else {
 		/* wait for target state */
 		add_cond_wait(&info->gpio_wait_q, &wait);
-		spin_unlock_irqrestore(&info->lock, flags);
+		spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
 		schedule();
 		if (signal_pending(current))
 			rc = -ERESTARTSYS;
 		else
 			gpio.state = wait.data;
-		spin_lock_irqsave(&info->lock, flags);
+		spin_lock_irqsave(&info->port_array[0]->lock, flags);
 		remove_cond_wait(&info->gpio_wait_q, &wait);
 	}
 
 	/* disable all GPIO interrupts if no waiting processes */
 	if (info->gpio_wait_q == NULL)
 		wr_reg32(info, IOER, 0);
-	spin_unlock_irqrestore(&info->lock,flags);
+	spin_unlock_irqrestore(&info->port_array[0]->lock, flags);
 
 	if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
 		rc = -EFAULT;
@@ -3576,7 +3668,6 @@
 
 		/* copy resource information from first port to others */
 		for (i = 1; i < port_count; ++i) {
-			port_array[i]->lock      = port_array[0]->lock;
 			port_array[i]->irq_level = port_array[0]->irq_level;
 			port_array[i]->reg_addr  = port_array[0]->reg_addr;
 			alloc_dma_bufs(port_array[i]);
@@ -3642,6 +3733,7 @@
 	.hangup = hangup,
 	.tiocmget = tiocmget,
 	.tiocmset = tiocmset,
+	.get_icount = get_icount,
 	.proc_fops = &synclink_gt_proc_fops,
 };
 
@@ -3760,7 +3852,9 @@
 #define CALC_REGADDR() \
 	unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \
 	if (addr >= 0x80) \
-		reg_addr += (info->port_num) * 32;
+		reg_addr += (info->port_num) * 32; \
+	else if (addr >= 0x40)	\
+		reg_addr += (info->port_num) * 16;
 
 static __u8 rd_reg8(struct slgt_info *info, unsigned int addr)
 {
@@ -4179,7 +4273,13 @@
 
 	/* TCR (tx control)
 	 *
-	 * 15..13  mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+	 * 15..13  mode
+	 *         000=HDLC/SDLC
+	 *         001=raw bit synchronous
+	 *         010=asynchronous/isochronous
+	 *         011=monosync byte synchronous
+	 *         100=bisync byte synchronous
+	 *         101=xsync byte synchronous
 	 * 12..10  encoding
 	 * 09      CRC enable
 	 * 08      CRC32
@@ -4194,6 +4294,9 @@
 	val = BIT2;
 
 	switch(info->params.mode) {
+	case MGSL_MODE_XSYNC:
+		val |= BIT15 + BIT13;
+		break;
 	case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
 	case MGSL_MODE_BISYNC:   val |= BIT15; break;
 	case MGSL_MODE_RAW:      val |= BIT13; break;
@@ -4248,7 +4351,13 @@
 
 	/* RCR (rx control)
 	 *
-	 * 15..13  mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
+	 * 15..13  mode
+	 *         000=HDLC/SDLC
+	 *         001=raw bit synchronous
+	 *         010=asynchronous/isochronous
+	 *         011=monosync byte synchronous
+	 *         100=bisync byte synchronous
+	 *         101=xsync byte synchronous
 	 * 12..10  encoding
 	 * 09      CRC enable
 	 * 08      CRC32
@@ -4260,6 +4369,9 @@
 	val = 0;
 
 	switch(info->params.mode) {
+	case MGSL_MODE_XSYNC:
+		val |= BIT15 + BIT13;
+		break;
 	case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
 	case MGSL_MODE_BISYNC:   val |= BIT15; break;
 	case MGSL_MODE_RAW:      val |= BIT13; break;
@@ -4676,6 +4788,7 @@
 	switch(info->params.mode) {
 	case MGSL_MODE_MONOSYNC:
 	case MGSL_MODE_BISYNC:
+	case MGSL_MODE_XSYNC:
 		/* ignore residue in byte synchronous modes */
 		if (desc_residue(info->rbufs[i]))
 			count--;
diff -druN linux-libre-2.6.36-gnu/drivers/char/synclinkmp.c linux-libre-2.6.37-gnu/drivers/char/synclinkmp.c
--- linux-libre-2.6.36-gnu/drivers/char/synclinkmp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/synclinkmp.c	2011-01-04 19:50:19.000000000 -0500
@@ -1258,10 +1258,6 @@
 		 unsigned int cmd, unsigned long arg)
 {
 	SLMP_INFO *info = tty->driver_data;
-	int error;
-	struct mgsl_icount cnow;	/* kernel counter temps */
-	struct serial_icounter_struct __user *p_cuser;	/* user space */
-	unsigned long flags;
 	void __user *argp = (void __user *)arg;
 
 	if (debug_level >= DEBUG_LEVEL_INFO)
@@ -1272,7 +1268,7 @@
 		return -ENODEV;
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+	    (cmd != TIOCMIWAIT)) {
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
@@ -1310,40 +1306,38 @@
 		 * NB: both 1->0 and 0->1 transitions are counted except for
 		 *     RI where only 0->1 is counted.
 		 */
-	case TIOCGICOUNT:
-		spin_lock_irqsave(&info->lock,flags);
-		cnow = info->icount;
-		spin_unlock_irqrestore(&info->lock,flags);
-		p_cuser = argp;
-		PUT_USER(error,cnow.cts, &p_cuser->cts);
-		if (error) return error;
-		PUT_USER(error,cnow.dsr, &p_cuser->dsr);
-		if (error) return error;
-		PUT_USER(error,cnow.rng, &p_cuser->rng);
-		if (error) return error;
-		PUT_USER(error,cnow.dcd, &p_cuser->dcd);
-		if (error) return error;
-		PUT_USER(error,cnow.rx, &p_cuser->rx);
-		if (error) return error;
-		PUT_USER(error,cnow.tx, &p_cuser->tx);
-		if (error) return error;
-		PUT_USER(error,cnow.frame, &p_cuser->frame);
-		if (error) return error;
-		PUT_USER(error,cnow.overrun, &p_cuser->overrun);
-		if (error) return error;
-		PUT_USER(error,cnow.parity, &p_cuser->parity);
-		if (error) return error;
-		PUT_USER(error,cnow.brk, &p_cuser->brk);
-		if (error) return error;
-		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
-		if (error) return error;
-		return 0;
 	default:
 		return -ENOIOCTLCMD;
 	}
 	return 0;
 }
 
+static int get_icount(struct tty_struct *tty,
+				struct serial_icounter_struct *icount)
+{
+	SLMP_INFO *info = tty->driver_data;
+	struct mgsl_icount cnow;	/* kernel counter temps */
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->lock,flags);
+	cnow = info->icount;
+	spin_unlock_irqrestore(&info->lock,flags);
+
+	icount->cts = cnow.cts;
+	icount->dsr = cnow.dsr;
+	icount->rng = cnow.rng;
+	icount->dcd = cnow.dcd;
+	icount->rx = cnow.rx;
+	icount->tx = cnow.tx;
+	icount->frame = cnow.frame;
+	icount->overrun = cnow.overrun;
+	icount->parity = cnow.parity;
+	icount->brk = cnow.brk;
+	icount->buf_overrun = cnow.buf_overrun;
+
+	return 0;
+}
+
 /*
  * /proc fs routines....
  */
@@ -3909,6 +3903,7 @@
 	.hangup = hangup,
 	.tiocmget = tiocmget,
 	.tiocmset = tiocmset,
+	.get_icount = get_icount,
 	.proc_fops = &synclinkmp_proc_fops,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/sysrq.c linux-libre-2.6.37-gnu/drivers/char/sysrq.c
--- linux-libre-2.6.36-gnu/drivers/char/sysrq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/sysrq.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,801 +0,0 @@
-/*
- *	Linux Magic System Request Key Hacks
- *
- *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *	based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
- *
- *	(c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
- *	overhauled to use key registration
- *	based upon discusions in irc://irc.openprojects.net/#kernelnewbies
- *
- *	Copyright (c) 2010 Dmitry Torokhov
- *	Input handler conversion
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/reboot.h>
-#include <linux/sysrq.h>
-#include <linux/kbd_kern.h>
-#include <linux/proc_fs.h>
-#include <linux/nmi.h>
-#include <linux/quotaops.h>
-#include <linux/perf_event.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <linux/writeback.h>
-#include <linux/buffer_head.h>		/* for fsync_bdev() */
-#include <linux/swap.h>
-#include <linux/spinlock.h>
-#include <linux/vt_kern.h>
-#include <linux/workqueue.h>
-#include <linux/hrtimer.h>
-#include <linux/oom.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-
-#include <asm/ptrace.h>
-#include <asm/irq_regs.h>
-
-/* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
-static bool __read_mostly sysrq_always_enabled;
-
-static bool sysrq_on(void)
-{
-	return sysrq_enabled || sysrq_always_enabled;
-}
-
-/*
- * A value of 1 means 'all', other nonzero values are an op mask:
- */
-static bool sysrq_on_mask(int mask)
-{
-	return sysrq_always_enabled ||
-	       sysrq_enabled == 1 ||
-	       (sysrq_enabled & mask);
-}
-
-static int __init sysrq_always_enabled_setup(char *str)
-{
-	sysrq_always_enabled = true;
-	pr_info("sysrq always enabled.\n");
-
-	return 1;
-}
-
-__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
-
-
-static void sysrq_handle_loglevel(int key)
-{
-	int i;
-
-	i = key - '0';
-	console_loglevel = 7;
-	printk("Loglevel set to %d\n", i);
-	console_loglevel = i;
-}
-static struct sysrq_key_op sysrq_loglevel_op = {
-	.handler	= sysrq_handle_loglevel,
-	.help_msg	= "loglevel(0-9)",
-	.action_msg	= "Changing Loglevel",
-	.enable_mask	= SYSRQ_ENABLE_LOG,
-};
-
-#ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key)
-{
-	struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-	schedule_work(SAK_work);
-}
-static struct sysrq_key_op sysrq_SAK_op = {
-	.handler	= sysrq_handle_SAK,
-	.help_msg	= "saK",
-	.action_msg	= "SAK",
-	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_VT
-static void sysrq_handle_unraw(int key)
-{
-	struct kbd_struct *kbd = &kbd_table[fg_console];
-
-	if (kbd)
-		kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-}
-static struct sysrq_key_op sysrq_unraw_op = {
-	.handler	= sysrq_handle_unraw,
-	.help_msg	= "unRaw",
-	.action_msg	= "Keyboard mode set to system default",
-	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
-#endif /* CONFIG_VT */
-
-static void sysrq_handle_crash(int key)
-{
-	char *killer = NULL;
-
-	panic_on_oops = 1;	/* force panic */
-	wmb();
-	*killer = 1;
-}
-static struct sysrq_key_op sysrq_crash_op = {
-	.handler	= sysrq_handle_crash,
-	.help_msg	= "Crash",
-	.action_msg	= "Trigger a crash",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_reboot(int key)
-{
-	lockdep_off();
-	local_irq_enable();
-	emergency_restart();
-}
-static struct sysrq_key_op sysrq_reboot_op = {
-	.handler	= sysrq_handle_reboot,
-	.help_msg	= "reBoot",
-	.action_msg	= "Resetting",
-	.enable_mask	= SYSRQ_ENABLE_BOOT,
-};
-
-static void sysrq_handle_sync(int key)
-{
-	emergency_sync();
-}
-static struct sysrq_key_op sysrq_sync_op = {
-	.handler	= sysrq_handle_sync,
-	.help_msg	= "Sync",
-	.action_msg	= "Emergency Sync",
-	.enable_mask	= SYSRQ_ENABLE_SYNC,
-};
-
-static void sysrq_handle_show_timers(int key)
-{
-	sysrq_timer_list_show();
-}
-
-static struct sysrq_key_op sysrq_show_timers_op = {
-	.handler	= sysrq_handle_show_timers,
-	.help_msg	= "show-all-timers(Q)",
-	.action_msg	= "Show clockevent devices & pending hrtimers (no others)",
-};
-
-static void sysrq_handle_mountro(int key)
-{
-	emergency_remount();
-}
-static struct sysrq_key_op sysrq_mountro_op = {
-	.handler	= sysrq_handle_mountro,
-	.help_msg	= "Unmount",
-	.action_msg	= "Emergency Remount R/O",
-	.enable_mask	= SYSRQ_ENABLE_REMOUNT,
-};
-
-#ifdef CONFIG_LOCKDEP
-static void sysrq_handle_showlocks(int key)
-{
-	debug_show_all_locks();
-}
-
-static struct sysrq_key_op sysrq_showlocks_op = {
-	.handler	= sysrq_handle_showlocks,
-	.help_msg	= "show-all-locks(D)",
-	.action_msg	= "Show Locks Held",
-};
-#else
-#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(show_lock);
-
-static void showacpu(void *dummy)
-{
-	unsigned long flags;
-
-	/* Idle CPUs have no interesting backtrace. */
-	if (idle_cpu(smp_processor_id()))
-		return;
-
-	spin_lock_irqsave(&show_lock, flags);
-	printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-	show_stack(NULL, NULL);
-	spin_unlock_irqrestore(&show_lock, flags);
-}
-
-static void sysrq_showregs_othercpus(struct work_struct *dummy)
-{
-	smp_call_function(showacpu, NULL, 0);
-}
-
-static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
-
-static void sysrq_handle_showallcpus(int key)
-{
-	/*
-	 * Fall back to the workqueue based printing if the
-	 * backtrace printing did not succeed or the
-	 * architecture has no support for it:
-	 */
-	if (!trigger_all_cpu_backtrace()) {
-		struct pt_regs *regs = get_irq_regs();
-
-		if (regs) {
-			printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-			show_regs(regs);
-		}
-		schedule_work(&sysrq_showallcpus);
-	}
-}
-
-static struct sysrq_key_op sysrq_showallcpus_op = {
-	.handler	= sysrq_handle_showallcpus,
-	.help_msg	= "show-backtrace-all-active-cpus(L)",
-	.action_msg	= "Show backtrace of all active CPUs",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-#endif
-
-static void sysrq_handle_showregs(int key)
-{
-	struct pt_regs *regs = get_irq_regs();
-	if (regs)
-		show_regs(regs);
-	perf_event_print_debug();
-}
-static struct sysrq_key_op sysrq_showregs_op = {
-	.handler	= sysrq_handle_showregs,
-	.help_msg	= "show-registers(P)",
-	.action_msg	= "Show Regs",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate(int key)
-{
-	show_state();
-}
-static struct sysrq_key_op sysrq_showstate_op = {
-	.handler	= sysrq_handle_showstate,
-	.help_msg	= "show-task-states(T)",
-	.action_msg	= "Show State",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate_blocked(int key)
-{
-	show_state_filter(TASK_UNINTERRUPTIBLE);
-}
-static struct sysrq_key_op sysrq_showstate_blocked_op = {
-	.handler	= sysrq_handle_showstate_blocked,
-	.help_msg	= "show-blocked-tasks(W)",
-	.action_msg	= "Show Blocked State",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-
-#ifdef CONFIG_TRACING
-#include <linux/ftrace.h>
-
-static void sysrq_ftrace_dump(int key)
-{
-	ftrace_dump(DUMP_ALL);
-}
-static struct sysrq_key_op sysrq_ftrace_dump_op = {
-	.handler	= sysrq_ftrace_dump,
-	.help_msg	= "dump-ftrace-buffer(Z)",
-	.action_msg	= "Dump ftrace buffer",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-#else
-#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-static void sysrq_handle_showmem(int key)
-{
-	show_mem();
-}
-static struct sysrq_key_op sysrq_showmem_op = {
-	.handler	= sysrq_handle_showmem,
-	.help_msg	= "show-memory-usage(M)",
-	.action_msg	= "Show Memory",
-	.enable_mask	= SYSRQ_ENABLE_DUMP,
-};
-
-/*
- * Signal sysrq helper function.  Sends a signal to all user processes.
- */
-static void send_sig_all(int sig)
-{
-	struct task_struct *p;
-
-	for_each_process(p) {
-		if (p->mm && !is_global_init(p))
-			/* Not swapper, init nor kernel thread */
-			force_sig(sig, p);
-	}
-}
-
-static void sysrq_handle_term(int key)
-{
-	send_sig_all(SIGTERM);
-	console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_term_op = {
-	.handler	= sysrq_handle_term,
-	.help_msg	= "terminate-all-tasks(E)",
-	.action_msg	= "Terminate All Tasks",
-	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
-};
-
-static void moom_callback(struct work_struct *ignored)
-{
-	out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
-}
-
-static DECLARE_WORK(moom_work, moom_callback);
-
-static void sysrq_handle_moom(int key)
-{
-	schedule_work(&moom_work);
-}
-static struct sysrq_key_op sysrq_moom_op = {
-	.handler	= sysrq_handle_moom,
-	.help_msg	= "memory-full-oom-kill(F)",
-	.action_msg	= "Manual OOM execution",
-	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
-};
-
-#ifdef CONFIG_BLOCK
-static void sysrq_handle_thaw(int key)
-{
-	emergency_thaw_all();
-}
-static struct sysrq_key_op sysrq_thaw_op = {
-	.handler	= sysrq_handle_thaw,
-	.help_msg	= "thaw-filesystems(J)",
-	.action_msg	= "Emergency Thaw of all frozen filesystems",
-	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
-};
-#endif
-
-static void sysrq_handle_kill(int key)
-{
-	send_sig_all(SIGKILL);
-	console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_kill_op = {
-	.handler	= sysrq_handle_kill,
-	.help_msg	= "kill-all-tasks(I)",
-	.action_msg	= "Kill All Tasks",
-	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
-};
-
-static void sysrq_handle_unrt(int key)
-{
-	normalize_rt_tasks();
-}
-static struct sysrq_key_op sysrq_unrt_op = {
-	.handler	= sysrq_handle_unrt,
-	.help_msg	= "nice-all-RT-tasks(N)",
-	.action_msg	= "Nice All RT Tasks",
-	.enable_mask	= SYSRQ_ENABLE_RTNICE,
-};
-
-/* Key Operations table and lock */
-static DEFINE_SPINLOCK(sysrq_key_table_lock);
-
-static struct sysrq_key_op *sysrq_key_table[36] = {
-	&sysrq_loglevel_op,		/* 0 */
-	&sysrq_loglevel_op,		/* 1 */
-	&sysrq_loglevel_op,		/* 2 */
-	&sysrq_loglevel_op,		/* 3 */
-	&sysrq_loglevel_op,		/* 4 */
-	&sysrq_loglevel_op,		/* 5 */
-	&sysrq_loglevel_op,		/* 6 */
-	&sysrq_loglevel_op,		/* 7 */
-	&sysrq_loglevel_op,		/* 8 */
-	&sysrq_loglevel_op,		/* 9 */
-
-	/*
-	 * a: Don't use for system provided sysrqs, it is handled specially on
-	 * sparc and will never arrive.
-	 */
-	NULL,				/* a */
-	&sysrq_reboot_op,		/* b */
-	&sysrq_crash_op,		/* c & ibm_emac driver debug */
-	&sysrq_showlocks_op,		/* d */
-	&sysrq_term_op,			/* e */
-	&sysrq_moom_op,			/* f */
-	/* g: May be registered for the kernel debugger */
-	NULL,				/* g */
-	NULL,				/* h - reserved for help */
-	&sysrq_kill_op,			/* i */
-#ifdef CONFIG_BLOCK
-	&sysrq_thaw_op,			/* j */
-#else
-	NULL,				/* j */
-#endif
-	&sysrq_SAK_op,			/* k */
-#ifdef CONFIG_SMP
-	&sysrq_showallcpus_op,		/* l */
-#else
-	NULL,				/* l */
-#endif
-	&sysrq_showmem_op,		/* m */
-	&sysrq_unrt_op,			/* n */
-	/* o: This will often be registered as 'Off' at init time */
-	NULL,				/* o */
-	&sysrq_showregs_op,		/* p */
-	&sysrq_show_timers_op,		/* q */
-	&sysrq_unraw_op,		/* r */
-	&sysrq_sync_op,			/* s */
-	&sysrq_showstate_op,		/* t */
-	&sysrq_mountro_op,		/* u */
-	/* v: May be registered for frame buffer console restore */
-	NULL,				/* v */
-	&sysrq_showstate_blocked_op,	/* w */
-	/* x: May be registered on ppc/powerpc for xmon */
-	NULL,				/* x */
-	/* y: May be registered on sparc64 for global register dump */
-	NULL,				/* y */
-	&sysrq_ftrace_dump_op,		/* z */
-};
-
-/* key2index calculation, -1 on invalid index */
-static int sysrq_key_table_key2index(int key)
-{
-	int retval;
-
-	if ((key >= '0') && (key <= '9'))
-		retval = key - '0';
-	else if ((key >= 'a') && (key <= 'z'))
-		retval = key + 10 - 'a';
-	else
-		retval = -1;
-	return retval;
-}
-
-/*
- * get and put functions for the table, exposed to modules.
- */
-struct sysrq_key_op *__sysrq_get_key_op(int key)
-{
-        struct sysrq_key_op *op_p = NULL;
-        int i;
-
-	i = sysrq_key_table_key2index(key);
-	if (i != -1)
-	        op_p = sysrq_key_table[i];
-
-        return op_p;
-}
-
-static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
-{
-        int i = sysrq_key_table_key2index(key);
-
-        if (i != -1)
-                sysrq_key_table[i] = op_p;
-}
-
-void __handle_sysrq(int key, bool check_mask)
-{
-	struct sysrq_key_op *op_p;
-	int orig_log_level;
-	int i;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sysrq_key_table_lock, flags);
-	/*
-	 * Raise the apparent loglevel to maximum so that the sysrq header
-	 * is shown to provide the user with positive feedback.  We do not
-	 * simply emit this at KERN_EMERG as that would change message
-	 * routing in the consumers of /proc/kmsg.
-	 */
-	orig_log_level = console_loglevel;
-	console_loglevel = 7;
-	printk(KERN_INFO "SysRq : ");
-
-        op_p = __sysrq_get_key_op(key);
-        if (op_p) {
-		/*
-		 * Should we check for enabled operations (/proc/sysrq-trigger
-		 * should not) and is the invoked operation enabled?
-		 */
-		if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-			printk("%s\n", op_p->action_msg);
-			console_loglevel = orig_log_level;
-			op_p->handler(key);
-		} else {
-			printk("This sysrq operation is disabled.\n");
-		}
-	} else {
-		printk("HELP : ");
-		/* Only print the help msg once per handler */
-		for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
-			if (sysrq_key_table[i]) {
-				int j;
-
-				for (j = 0; sysrq_key_table[i] !=
-						sysrq_key_table[j]; j++)
-					;
-				if (j != i)
-					continue;
-				printk("%s ", sysrq_key_table[i]->help_msg);
-			}
-		}
-		printk("\n");
-		console_loglevel = orig_log_level;
-	}
-	spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-}
-
-void handle_sysrq(int key)
-{
-	if (sysrq_on())
-		__handle_sysrq(key, true);
-}
-EXPORT_SYMBOL(handle_sysrq);
-
-#ifdef CONFIG_INPUT
-
-/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
-        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
-        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
-        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
-        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
-        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
-        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-        "\r\000/";                                      /* 0x60 - 0x6f */
-
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
-		         unsigned int code, int value)
-{
-	if (type != EV_KEY)
-		goto out;
-
-	switch (code) {
-
-	case KEY_LEFTALT:
-	case KEY_RIGHTALT:
-		if (value)
-			sysrq_alt = code;
-		else {
-			if (sysrq_down && code == sysrq_alt_use)
-				sysrq_down = false;
-
-			sysrq_alt = 0;
-		}
-		break;
-
-	case KEY_SYSRQ:
-		if (value == 1 && sysrq_alt) {
-			sysrq_down = true;
-			sysrq_alt_use = sysrq_alt;
-		}
-		break;
-
-	default:
-		if (sysrq_down && value && value != 2)
-			__handle_sysrq(sysrq_xlate[code], true);
-		break;
-	}
-
-out:
-	return sysrq_down;
-}
-
-static int sysrq_connect(struct input_handler *handler,
-			 struct input_dev *dev,
-			 const struct input_device_id *id)
-{
-	struct input_handle *handle;
-	int error;
-
-	sysrq_down = false;
-	sysrq_alt = 0;
-
-	handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-	if (!handle)
-		return -ENOMEM;
-
-	handle->dev = dev;
-	handle->handler = handler;
-	handle->name = "sysrq";
-
-	error = input_register_handle(handle);
-	if (error) {
-		pr_err("Failed to register input sysrq handler, error %d\n",
-			error);
-		goto err_free;
-	}
-
-	error = input_open_device(handle);
-	if (error) {
-		pr_err("Failed to open input device, error %d\n", error);
-		goto err_unregister;
-	}
-
-	return 0;
-
- err_unregister:
-	input_unregister_handle(handle);
- err_free:
-	kfree(handle);
-	return error;
-}
-
-static void sysrq_disconnect(struct input_handle *handle)
-{
-	input_close_device(handle);
-	input_unregister_handle(handle);
-	kfree(handle);
-}
-
-/*
- * We are matching on KEY_LEFTALT insteard of KEY_SYSRQ because not all
- * keyboards have SysRq ikey predefined and so user may add it to keymap
- * later, but we expect all such keyboards to have left alt.
- */
-static const struct input_device_id sysrq_ids[] = {
-	{
-		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-				INPUT_DEVICE_ID_MATCH_KEYBIT,
-		.evbit = { BIT_MASK(EV_KEY) },
-		.keybit = { BIT_MASK(KEY_LEFTALT) },
-	},
-	{ },
-};
-
-static struct input_handler sysrq_handler = {
-	.filter		= sysrq_filter,
-	.connect	= sysrq_connect,
-	.disconnect	= sysrq_disconnect,
-	.name		= "sysrq",
-	.id_table	= sysrq_ids,
-};
-
-static bool sysrq_handler_registered;
-
-static inline void sysrq_register_handler(void)
-{
-	int error;
-
-	error = input_register_handler(&sysrq_handler);
-	if (error)
-		pr_err("Failed to register input handler, error %d", error);
-	else
-		sysrq_handler_registered = true;
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-	if (sysrq_handler_registered) {
-		input_unregister_handler(&sysrq_handler);
-		sysrq_handler_registered = false;
-	}
-}
-
-#else
-
-static inline void sysrq_register_handler(void)
-{
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-}
-
-#endif /* CONFIG_INPUT */
-
-int sysrq_toggle_support(int enable_mask)
-{
-	bool was_enabled = sysrq_on();
-
-	sysrq_enabled = enable_mask;
-
-	if (was_enabled != sysrq_on()) {
-		if (sysrq_on())
-			sysrq_register_handler();
-		else
-			sysrq_unregister_handler();
-	}
-
-	return 0;
-}
-
-static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
-                                struct sysrq_key_op *remove_op_p)
-{
-	int retval;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sysrq_key_table_lock, flags);
-	if (__sysrq_get_key_op(key) == remove_op_p) {
-		__sysrq_put_key_op(key, insert_op_p);
-		retval = 0;
-	} else {
-		retval = -1;
-	}
-	spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-	return retval;
-}
-
-int register_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-	return __sysrq_swap_key_ops(key, op_p, NULL);
-}
-EXPORT_SYMBOL(register_sysrq_key);
-
-int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-	return __sysrq_swap_key_ops(key, NULL, op_p);
-}
-EXPORT_SYMBOL(unregister_sysrq_key);
-
-#ifdef CONFIG_PROC_FS
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
-				   size_t count, loff_t *ppos)
-{
-	if (count) {
-		char c;
-
-		if (get_user(c, buf))
-			return -EFAULT;
-		__handle_sysrq(c, false);
-	}
-
-	return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
-	.write		= write_sysrq_trigger,
-};
-
-static void sysrq_init_procfs(void)
-{
-	if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
-			 &proc_sysrq_trigger_operations))
-		pr_err("Failed to register proc interface\n");
-}
-
-#else
-
-static inline void sysrq_init_procfs(void)
-{
-}
-
-#endif /* CONFIG_PROC_FS */
-
-static int __init sysrq_init(void)
-{
-	sysrq_init_procfs();
-
-	if (sysrq_on())
-		sysrq_register_handler();
-
-	return 0;
-}
-module_init(sysrq_init);
diff -druN linux-libre-2.6.36-gnu/drivers/char/tb0219.c linux-libre-2.6.37-gnu/drivers/char/tb0219.c
--- linux-libre-2.6.36-gnu/drivers/char/tb0219.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tb0219.c	2011-01-04 19:50:19.000000000 -0500
@@ -261,6 +261,7 @@
 	.write		= tanbac_tb0219_write,
 	.open		= tanbac_tb0219_open,
 	.release	= tanbac_tb0219_release,
+	.llseek		= no_llseek,
 };
 
 static void tb0219_restart(char *command)
diff -druN linux-libre-2.6.36-gnu/drivers/char/tlclk.c linux-libre-2.6.37-gnu/drivers/char/tlclk.c
--- linux-libre-2.6.36-gnu/drivers/char/tlclk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tlclk.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/timer.h>
 #include <linux/sysfs.h>
 #include <linux/device.h>
@@ -206,7 +206,7 @@
 {
 	int result;
 
-	lock_kernel();
+	mutex_lock(&tlclk_mutex);
 	if (test_and_set_bit(0, &useflags)) {
 		result = -EBUSY;
 		/* this legacy device is always one per system and it doesn't
@@ -229,7 +229,7 @@
 		inb(TLCLK_REG6);	/* Clear interrupt events */
 
 out:
-	unlock_kernel();
+	mutex_unlock(&tlclk_mutex);
 	return result;
 }
 
@@ -267,6 +267,7 @@
 	.read = tlclk_read,
 	.open = tlclk_open,
 	.release = tlclk_release,
+	.llseek = noop_llseek,
 
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/toshiba.c linux-libre-2.6.37-gnu/drivers/char/toshiba.c
--- linux-libre-2.6.36-gnu/drivers/char/toshiba.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/toshiba.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,7 +68,7 @@
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/toshiba.h>
 
 #define TOSH_MINOR_DEV 181
@@ -78,6 +78,7 @@
 MODULE_DESCRIPTION("Toshiba laptop SMM driver");
 MODULE_SUPPORTED_DEVICE("toshiba");
 
+static DEFINE_MUTEX(tosh_mutex);
 static int tosh_fn;
 module_param_named(fn, tosh_fn, int, 0);
 MODULE_PARM_DESC(fn, "User specified Fn key detection port");
@@ -95,6 +96,7 @@
 static const struct file_operations tosh_fops = {
 	.owner		= THIS_MODULE,
 	.unlocked_ioctl	= tosh_ioctl,
+	.llseek		= noop_llseek,
 };
 
 static struct miscdevice tosh_device = {
@@ -274,16 +276,16 @@
 				return -EINVAL;
 
 			/* do we need to emulate the fan ? */
-			lock_kernel();
+			mutex_lock(&tosh_mutex);
 			if (tosh_fan==1) {
 				if (((ax==0xf300) || (ax==0xf400)) && (bx==0x0004)) {
 					err = tosh_emulate_fan(&regs);
-					unlock_kernel();
+					mutex_unlock(&tosh_mutex);
 					break;
 				}
 			}
 			err = tosh_smm(&regs);
-			unlock_kernel();
+			mutex_unlock(&tosh_mutex);
 			break;
 		default:
 			return -EINVAL;
diff -druN linux-libre-2.6.36-gnu/drivers/char/tpm/Kconfig linux-libre-2.6.37-gnu/drivers/char/tpm/Kconfig
--- linux-libre-2.6.36-gnu/drivers/char/tpm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tpm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -58,6 +58,6 @@
 	  To compile this driver as a module, choose M here; the module
 	  will be called tpm_infineon.
 	  Further information on this driver and the supported hardware
-	  can be found at http://www.prosec.rub.de/tpm
+	  can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
 
 endif # TCG_TPM
diff -druN linux-libre-2.6.36-gnu/drivers/char/tpm/tpm.c linux-libre-2.6.37-gnu/drivers/char/tpm/tpm.c
--- linux-libre-2.6.36-gnu/drivers/char/tpm/tpm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tpm/tpm.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,16 @@
 #define TPM_MAX_PROTECTED_ORDINAL 12
 #define TPM_PROTECTED_ORDINAL_MASK 0xFF
 
+/*
+ * Bug workaround - some TPM's don't flush the most
+ * recently changed pcr on suspend, so force the flush
+ * with an extend to the selected _unused_ non-volatile pcr.
+ */
+static int tpm_suspend_pcr;
+module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
+MODULE_PARM_DESC(suspend_pcr,
+		 "PCR to use for dummy writes to faciltate flush on suspend.");
+
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
@@ -1077,18 +1087,6 @@
 	.ordinal = TPM_ORD_SAVESTATE
 };
 
-/* Bug workaround - some TPM's don't flush the most
- * recently changed pcr on suspend, so force the flush
- * with an extend to the selected _unused_ non-volatile pcr.
- */
-static int tpm_suspend_pcr;
-static int __init tpm_suspend_setup(char *str)
-{
-	get_option(&str, &tpm_suspend_pcr);
-	return 1;
-}
-__setup("tpm_suspend_pcr=", tpm_suspend_setup);
-
 /*
  * We are about to suspend. Save the TPM state
  * so that it can be restored.
diff -druN linux-libre-2.6.36-gnu/drivers/char/tpm/tpm_infineon.c linux-libre-2.6.37-gnu/drivers/char/tpm/tpm_infineon.c
--- linux-libre-2.6.36-gnu/drivers/char/tpm/tpm_infineon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tpm/tpm_infineon.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
  * Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com>
  * Sirrix AG - security technologies, http://www.sirrix.com and
  * Applied Data Security Group, Ruhr-University Bochum, Germany
- * Project-Homepage: http://www.prosec.rub.de/tpm
+ * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
diff -druN linux-libre-2.6.36-gnu/drivers/char/tpm/tpm_tis.c linux-libre-2.6.37-gnu/drivers/char/tpm/tpm_tis.c
--- linux-libre-2.6.36-gnu/drivers/char/tpm/tpm_tis.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tpm/tpm_tis.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
+#include <linux/acpi.h>
 #include "tpm.h"
 
 #define TPM_HEADER_SIZE 10
@@ -78,6 +79,26 @@
 static LIST_HEAD(tis_chips);
 static DEFINE_SPINLOCK(tis_lock);
 
+#ifdef CONFIG_ACPI
+static int is_itpm(struct pnp_dev *dev)
+{
+	struct acpi_device *acpi = pnp_acpi_device(dev);
+	struct acpi_hardware_id *id;
+
+	list_for_each_entry(id, &acpi->pnp.ids, list) {
+		if (!strcmp("INTC0102", id->id))
+			return 1;
+	}
+
+	return 0;
+}
+#else
+static int is_itpm(struct pnp_dev *dev)
+{
+	return 0;
+}
+#endif
+
 static int check_locality(struct tpm_chip *chip, int l)
 {
 	if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
@@ -472,6 +493,9 @@
 		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
 		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
+	if (is_itpm(to_pnp_dev(dev)))
+		itpm = 1;
+
 	if (itpm)
 		dev_info(dev, "Intel iTPM workaround enabled\n");
 
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_audit.c linux-libre-2.6.37-gnu/drivers/char/tty_audit.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_audit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_audit.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,340 +0,0 @@
-/*
- * Creating audit events from TTY input.
- *
- * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
- * material is made available to anyone wishing to use, modify, copy, or
- * redistribute it subject to the terms and conditions of the GNU General
- * Public License v.2.
- *
- * Authors: Miloslav Trmac <mitr@redhat.com>
- */
-
-#include <linux/audit.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-
-struct tty_audit_buf {
-	atomic_t count;
-	struct mutex mutex;	/* Protects all data below */
-	int major, minor;	/* The TTY which the data is from */
-	unsigned icanon:1;
-	size_t valid;
-	unsigned char *data;	/* Allocated size N_TTY_BUF_SIZE */
-};
-
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
-						 int icanon)
-{
-	struct tty_audit_buf *buf;
-
-	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-	if (!buf)
-		goto err;
-	buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-	if (!buf->data)
-		goto err_buf;
-	atomic_set(&buf->count, 1);
-	mutex_init(&buf->mutex);
-	buf->major = major;
-	buf->minor = minor;
-	buf->icanon = icanon;
-	buf->valid = 0;
-	return buf;
-
-err_buf:
-	kfree(buf);
-err:
-	return NULL;
-}
-
-static void tty_audit_buf_free(struct tty_audit_buf *buf)
-{
-	WARN_ON(buf->valid != 0);
-	kfree(buf->data);
-	kfree(buf);
-}
-
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
-	if (atomic_dec_and_test(&buf->count))
-		tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, struct task_struct *tsk,
-			  uid_t loginuid, unsigned sessionid, int major,
-			  int minor, unsigned char *data, size_t size)
-{
-	struct audit_buffer *ab;
-
-	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
-	if (ab) {
-		char name[sizeof(tsk->comm)];
-		uid_t uid = task_uid(tsk);
-
-		audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
-				 "major=%d minor=%d comm=", description,
-				 tsk->pid, uid, loginuid, sessionid,
-				 major, minor);
-		get_task_comm(name, tsk);
-		audit_log_untrustedstring(ab, name);
-		audit_log_format(ab, " data=");
-		audit_log_n_hex(ab, data, size);
-		audit_log_end(ab);
-	}
-}
-
-/**
- *	tty_audit_buf_push	-	Push buffered data out
- *
- *	Generate an audit message from the contents of @buf, which is owned by
- *	@tsk with @loginuid.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
-			       unsigned int sessionid,
-			       struct tty_audit_buf *buf)
-{
-	if (buf->valid == 0)
-		return;
-	if (audit_enabled == 0)
-		return;
-	tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
-		      buf->data, buf->valid);
-	buf->valid = 0;
-}
-
-/**
- *	tty_audit_buf_push_current	-	Push buffered data out
- *
- *	Generate an audit message from the contents of @buf, which is owned by
- *	the current task.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
-{
-	uid_t auid = audit_get_loginuid(current);
-	unsigned int sessionid = audit_get_sessionid(current);
-	tty_audit_buf_push(current, auid, sessionid, buf);
-}
-
-/**
- *	tty_audit_exit	-	Handle a task exit
- *
- *	Make sure all buffered data is written out and deallocate the buffer.
- *	Only needs to be called if current->signal->tty_audit_buf != %NULL.
- */
-void tty_audit_exit(void)
-{
-	struct tty_audit_buf *buf;
-
-	spin_lock_irq(&current->sighand->siglock);
-	buf = current->signal->tty_audit_buf;
-	current->signal->tty_audit_buf = NULL;
-	spin_unlock_irq(&current->sighand->siglock);
-	if (!buf)
-		return;
-
-	mutex_lock(&buf->mutex);
-	tty_audit_buf_push_current(buf);
-	mutex_unlock(&buf->mutex);
-
-	tty_audit_buf_put(buf);
-}
-
-/**
- *	tty_audit_fork	-	Copy TTY audit state for a new task
- *
- *	Set up TTY audit state in @sig from current.  @sig needs no locking.
- */
-void tty_audit_fork(struct signal_struct *sig)
-{
-	spin_lock_irq(&current->sighand->siglock);
-	sig->audit_tty = current->signal->audit_tty;
-	spin_unlock_irq(&current->sighand->siglock);
-}
-
-/**
- *	tty_audit_tiocsti	-	Log TIOCSTI
- */
-void tty_audit_tiocsti(struct tty_struct *tty, char ch)
-{
-	struct tty_audit_buf *buf;
-	int major, minor, should_audit;
-
-	spin_lock_irq(&current->sighand->siglock);
-	should_audit = current->signal->audit_tty;
-	buf = current->signal->tty_audit_buf;
-	if (buf)
-		atomic_inc(&buf->count);
-	spin_unlock_irq(&current->sighand->siglock);
-
-	major = tty->driver->major;
-	minor = tty->driver->minor_start + tty->index;
-	if (buf) {
-		mutex_lock(&buf->mutex);
-		if (buf->major == major && buf->minor == minor)
-			tty_audit_buf_push_current(buf);
-		mutex_unlock(&buf->mutex);
-		tty_audit_buf_put(buf);
-	}
-
-	if (should_audit && audit_enabled) {
-		uid_t auid;
-		unsigned int sessionid;
-
-		auid = audit_get_loginuid(current);
-		sessionid = audit_get_sessionid(current);
-		tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
-			      minor, &ch, 1);
-	}
-}
-
-/**
- *	tty_audit_push_task	-	Flush task's pending audit data
- */
-void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
-{
-	struct tty_audit_buf *buf;
-
-	spin_lock_irq(&tsk->sighand->siglock);
-	buf = tsk->signal->tty_audit_buf;
-	if (buf)
-		atomic_inc(&buf->count);
-	spin_unlock_irq(&tsk->sighand->siglock);
-	if (!buf)
-		return;
-
-	mutex_lock(&buf->mutex);
-	tty_audit_buf_push(tsk, loginuid, sessionid, buf);
-	mutex_unlock(&buf->mutex);
-
-	tty_audit_buf_put(buf);
-}
-
-/**
- *	tty_audit_buf_get	-	Get an audit buffer.
- *
- *	Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
- *	if TTY auditing is disabled or out of memory.  Otherwise, return a new
- *	reference to the buffer.
- */
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
-{
-	struct tty_audit_buf *buf, *buf2;
-
-	buf = NULL;
-	buf2 = NULL;
-	spin_lock_irq(&current->sighand->siglock);
-	if (likely(!current->signal->audit_tty))
-		goto out;
-	buf = current->signal->tty_audit_buf;
-	if (buf) {
-		atomic_inc(&buf->count);
-		goto out;
-	}
-	spin_unlock_irq(&current->sighand->siglock);
-
-	buf2 = tty_audit_buf_alloc(tty->driver->major,
-				   tty->driver->minor_start + tty->index,
-				   tty->icanon);
-	if (buf2 == NULL) {
-		audit_log_lost("out of memory in TTY auditing");
-		return NULL;
-	}
-
-	spin_lock_irq(&current->sighand->siglock);
-	if (!current->signal->audit_tty)
-		goto out;
-	buf = current->signal->tty_audit_buf;
-	if (!buf) {
-		current->signal->tty_audit_buf = buf2;
-		buf = buf2;
-		buf2 = NULL;
-	}
-	atomic_inc(&buf->count);
-	/* Fall through */
- out:
-	spin_unlock_irq(&current->sighand->siglock);
-	if (buf2)
-		tty_audit_buf_free(buf2);
-	return buf;
-}
-
-/**
- *	tty_audit_add_data	-	Add data for TTY auditing.
- *
- *	Audit @data of @size from @tty, if necessary.
- */
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
-			size_t size)
-{
-	struct tty_audit_buf *buf;
-	int major, minor;
-
-	if (unlikely(size == 0))
-		return;
-
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY
-	    && tty->driver->subtype == PTY_TYPE_MASTER)
-		return;
-
-	buf = tty_audit_buf_get(tty);
-	if (!buf)
-		return;
-
-	mutex_lock(&buf->mutex);
-	major = tty->driver->major;
-	minor = tty->driver->minor_start + tty->index;
-	if (buf->major != major || buf->minor != minor
-	    || buf->icanon != tty->icanon) {
-		tty_audit_buf_push_current(buf);
-		buf->major = major;
-		buf->minor = minor;
-		buf->icanon = tty->icanon;
-	}
-	do {
-		size_t run;
-
-		run = N_TTY_BUF_SIZE - buf->valid;
-		if (run > size)
-			run = size;
-		memcpy(buf->data + buf->valid, data, run);
-		buf->valid += run;
-		data += run;
-		size -= run;
-		if (buf->valid == N_TTY_BUF_SIZE)
-			tty_audit_buf_push_current(buf);
-	} while (size != 0);
-	mutex_unlock(&buf->mutex);
-	tty_audit_buf_put(buf);
-}
-
-/**
- *	tty_audit_push	-	Push buffered data out
- *
- *	Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
-	struct tty_audit_buf *buf;
-
-	spin_lock_irq(&current->sighand->siglock);
-	if (likely(!current->signal->audit_tty)) {
-		spin_unlock_irq(&current->sighand->siglock);
-		return;
-	}
-	buf = current->signal->tty_audit_buf;
-	if (buf)
-		atomic_inc(&buf->count);
-	spin_unlock_irq(&current->sighand->siglock);
-
-	if (buf) {
-		int major, minor;
-
-		major = tty->driver->major;
-		minor = tty->driver->minor_start + tty->index;
-		mutex_lock(&buf->mutex);
-		if (buf->major == major && buf->minor == minor)
-			tty_audit_buf_push_current(buf);
-		mutex_unlock(&buf->mutex);
-		tty_audit_buf_put(buf);
-	}
-}
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_buffer.c linux-libre-2.6.37-gnu/drivers/char/tty_buffer.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_buffer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_buffer.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,524 +0,0 @@
-/*
- * Tty buffer allocation management
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-/**
- *	tty_buffer_free_all		-	free buffers used by a tty
- *	@tty: tty to free from
- *
- *	Remove all the buffers pending on a tty whether queued with data
- *	or in the free ring. Must be called when the tty is no longer in use
- *
- *	Locking: none
- */
-
-void tty_buffer_free_all(struct tty_struct *tty)
-{
-	struct tty_buffer *thead;
-	while ((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		kfree(thead);
-	}
-	while ((thead = tty->buf.free) != NULL) {
-		tty->buf.free = thead->next;
-		kfree(thead);
-	}
-	tty->buf.tail = NULL;
-	tty->buf.memory_used = 0;
-}
-
-/**
- *	tty_buffer_alloc	-	allocate a tty buffer
- *	@tty: tty device
- *	@size: desired size (characters)
- *
- *	Allocate a new tty buffer to hold the desired number of characters.
- *	Return NULL if out of memory or the allocation would exceed the
- *	per device queue
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer *p;
-
-	if (tty->buf.memory_used + size > 65536)
-		return NULL;
-	p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-	if (p == NULL)
-		return NULL;
-	p->used = 0;
-	p->size = size;
-	p->next = NULL;
-	p->commit = 0;
-	p->read = 0;
-	p->char_buf_ptr = (char *)(p->data);
-	p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-	tty->buf.memory_used += size;
-	return p;
-}
-
-/**
- *	tty_buffer_free		-	free a tty buffer
- *	@tty: tty owning the buffer
- *	@b: the buffer to free
- *
- *	Free a tty buffer, or add it to the free list according to our
- *	internal strategy
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-	/* Dumb strategy for now - should keep some stats */
-	tty->buf.memory_used -= b->size;
-	WARN_ON(tty->buf.memory_used < 0);
-
-	if (b->size >= 512)
-		kfree(b);
-	else {
-		b->next = tty->buf.free;
-		tty->buf.free = b;
-	}
-}
-
-/**
- *	__tty_buffer_flush		-	flush full tty buffers
- *	@tty: tty to flush
- *
- *	flush all the buffers containing receive data. Caller must
- *	hold the buffer lock and must have ensured no parallel flush to
- *	ldisc is running.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-	struct tty_buffer *thead;
-
-	while ((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		tty_buffer_free(tty, thead);
-	}
-	tty->buf.tail = NULL;
-}
-
-/**
- *	tty_buffer_flush		-	flush full tty buffers
- *	@tty: tty to flush
- *
- *	flush all the buffers containing receive data. If the buffer is
- *	being processed by flush_to_ldisc then we defer the processing
- *	to that function
- *
- *	Locking: none
- */
-
-void tty_buffer_flush(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
-	/* If the data is being pushed to the tty layer then we can't
-	   process it here. Instead set a flag and the flush_to_ldisc
-	   path will process the flush request before it exits */
-	if (test_bit(TTY_FLUSHING, &tty->flags)) {
-		set_bit(TTY_FLUSHPENDING, &tty->flags);
-		spin_unlock_irqrestore(&tty->buf.lock, flags);
-		wait_event(tty->read_wait,
-				test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-		return;
-	} else
-		__tty_buffer_flush(tty);
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *	tty_buffer_find		-	find a free tty buffer
- *	@tty: tty owning the buffer
- *	@size: characters wanted
- *
- *	Locate an existing suitable tty buffer or if we are lacking one then
- *	allocate a new one. We round our buffers off in 256 character chunks
- *	to get better allocation behaviour.
- *
- *	Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer **tbh = &tty->buf.free;
-	while ((*tbh) != NULL) {
-		struct tty_buffer *t = *tbh;
-		if (t->size >= size) {
-			*tbh = t->next;
-			t->next = NULL;
-			t->used = 0;
-			t->commit = 0;
-			t->read = 0;
-			tty->buf.memory_used += t->size;
-			return t;
-		}
-		tbh = &((*tbh)->next);
-	}
-	/* Round the buffer size out */
-	size = (size + 0xFF) & ~0xFF;
-	return tty_buffer_alloc(tty, size);
-	/* Should possibly check if this fails for the largest buffer we
-	   have queued and recycle that ? */
-}
-
-/**
- *	tty_buffer_request_room		-	grow tty buffer if needed
- *	@tty: tty structure
- *	@size: size desired
- *
- *	Make at least size bytes of linear space available for the tty
- *	buffer. If we fail return the size we managed to find.
- *
- *	Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-	struct tty_buffer *b, *n;
-	int left;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
-	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-	   remove this conditional if its worth it. This would be invisible
-	   to the callers */
-	if ((b = tty->buf.tail) != NULL)
-		left = b->size - b->used;
-	else
-		left = 0;
-
-	if (left < size) {
-		/* This is the slow path - looking for new buffers to use */
-		if ((n = tty_buffer_find(tty, size)) != NULL) {
-			if (b != NULL) {
-				b->next = n;
-				b->commit = b->used;
-			} else
-				tty->buf.head = n;
-			tty->buf.tail = n;
-		} else
-			size = left;
-	}
-
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-	return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *	tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
- *	@tty: tty structure
- *	@chars: characters
- *	@flag: flag value for each character
- *	@size: size
- *
- *	Queue a series of bytes to the tty buffering. All the characters
- *	passed are marked with the supplied flag. Returns the number added.
- *
- *	Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
-		const unsigned char *chars, char flag, size_t size)
-{
-	int copied = 0;
-	do {
-		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
-			break;
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memset(tb->flag_buf_ptr + tb->used, flag, space);
-		tb->used += space;
-		copied += space;
-		chars += space;
-		/* There is a small chance that we need to split the data over
-		   several buffers. If this is the case we must loop */
-	} while (unlikely(size > copied));
-	return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
-
-/**
- *	tty_insert_flip_string_flags	-	Add characters to the tty buffer
- *	@tty: tty structure
- *	@chars: characters
- *	@flags: flag bytes
- *	@size: size
- *
- *	Queue a series of bytes to the tty buffering. For each character
- *	the flags array indicates the status of the character. Returns the
- *	number added.
- *
- *	Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-		const unsigned char *chars, const char *flags, size_t size)
-{
-	int copied = 0;
-	do {
-		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-		int space = tty_buffer_request_room(tty, goal);
-		struct tty_buffer *tb = tty->buf.tail;
-		/* If there is no space then tb may be NULL */
-		if (unlikely(space == 0))
-			break;
-		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-		tb->used += space;
-		copied += space;
-		chars += space;
-		flags += space;
-		/* There is a small chance that we need to split the data over
-		   several buffers. If this is the case we must loop */
-	} while (unlikely(size > copied));
-	return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *	tty_schedule_flip	-	push characters to ldisc
- *	@tty: tty to push from
- *
- *	Takes any pending buffers and transfers their ownership to the
- *	ldisc side of the queue. It then schedules those characters for
- *	processing by the line discipline.
- *
- *	Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-	if (tty->buf.tail != NULL)
-		tty->buf.tail->commit = tty->buf.tail->used;
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-	schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *	tty_prepare_flip_string		-	make room for characters
- *	@tty: tty
- *	@chars: return pointer for character write area
- *	@size: desired size
- *
- *	Prepare a block of space in the buffer for data. Returns the length
- *	available and buffer pointer to the space which is now allocated and
- *	accounted for as ready for normal characters. This is used for drivers
- *	that need their own block copy routines into the buffer. There is no
- *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-								size_t size)
-{
-	int space = tty_buffer_request_room(tty, size);
-	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-		tb->used += space;
-	}
-	return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *	tty_prepare_flip_string_flags	-	make room for characters
- *	@tty: tty
- *	@chars: return pointer for character write area
- *	@flags: return pointer for status flag write area
- *	@size: desired size
- *
- *	Prepare a block of space in the buffer for data. Returns the length
- *	available and buffer pointer to the space which is now allocated and
- *	accounted for as ready for characters. This is used for drivers
- *	that need their own block copy routines into the buffer. There is no
- *	guarantee the buffer is a DMA target!
- *
- *	Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-			unsigned char **chars, char **flags, size_t size)
-{
-	int space = tty_buffer_request_room(tty, size);
-	if (likely(space)) {
-		struct tty_buffer *tb = tty->buf.tail;
-		*chars = tb->char_buf_ptr + tb->used;
-		*flags = tb->flag_buf_ptr + tb->used;
-		tb->used += space;
-	}
-	return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
-/**
- *	flush_to_ldisc
- *	@work: tty structure passed from work queue.
- *
- *	This routine is called out of the software interrupt to flush data
- *	from the buffer chain to the line discipline.
- *
- *	Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *	while invoking the line discipline receive_buf method. The
- *	receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, buf.work.work);
-	unsigned long 	flags;
-	struct tty_ldisc *disc;
-
-	disc = tty_ldisc_ref(tty);
-	if (disc == NULL)	/*  !TTY_LDISC */
-		return;
-
-	spin_lock_irqsave(&tty->buf.lock, flags);
-
-	if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-		struct tty_buffer *head;
-		while ((head = tty->buf.head) != NULL) {
-			int count;
-			char *char_buf;
-			unsigned char *flag_buf;
-
-			count = head->commit - head->read;
-			if (!count) {
-				if (head->next == NULL)
-					break;
-				tty->buf.head = head->next;
-				tty_buffer_free(tty, head);
-				continue;
-			}
-			/* Ldisc or user is trying to flush the buffers
-			   we are feeding to the ldisc, stop feeding the
-			   line discipline as we want to empty the queue */
-			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-				break;
-			if (!tty->receive_room) {
-				schedule_delayed_work(&tty->buf.work, 1);
-				break;
-			}
-			if (count > tty->receive_room)
-				count = tty->receive_room;
-			char_buf = head->char_buf_ptr + head->read;
-			flag_buf = head->flag_buf_ptr + head->read;
-			head->read += count;
-			spin_unlock_irqrestore(&tty->buf.lock, flags);
-			disc->ops->receive_buf(tty, char_buf,
-							flag_buf, count);
-			spin_lock_irqsave(&tty->buf.lock, flags);
-		}
-		clear_bit(TTY_FLUSHING, &tty->flags);
-	}
-
-	/* We may have a deferred request to flush the input buffer,
-	   if so pull the chain under the lock and empty the queue */
-	if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-		__tty_buffer_flush(tty);
-		clear_bit(TTY_FLUSHPENDING, &tty->flags);
-		wake_up(&tty->read_wait);
-	}
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-	tty_ldisc_deref(disc);
-}
-
-/**
- *	tty_flush_to_ldisc
- *	@tty: tty to push
- *
- *	Push the terminal flip buffers to the line discipline.
- *
- *	Must not be called from IRQ context.
- */
-void tty_flush_to_ldisc(struct tty_struct *tty)
-{
-	flush_delayed_work(&tty->buf.work);
-}
-
-/**
- *	tty_flip_buffer_push	-	terminal
- *	@tty: tty to push
- *
- *	Queue a push of the terminal flip buffers to the line discipline. This
- *	function must not be called from IRQ context if tty->low_latency is set.
- *
- *	In the event of the queue being busy for flipping the work will be
- *	held off and retried later.
- *
- *	Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->buf.lock, flags);
-	if (tty->buf.tail != NULL)
-		tty->buf.tail->commit = tty->buf.tail->used;
-	spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-	if (tty->low_latency)
-		flush_to_ldisc(&tty->buf.work.work);
-	else
-		schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-/**
- *	tty_buffer_init		-	prepare a tty buffer structure
- *	@tty: tty to initialise
- *
- *	Set up the initial state of the buffer management for a tty device.
- *	Must be called before the other tty buffer functions are used.
- *
- *	Locking: none
- */
-
-void tty_buffer_init(struct tty_struct *tty)
-{
-	spin_lock_init(&tty->buf.lock);
-	tty->buf.head = NULL;
-	tty->buf.tail = NULL;
-	tty->buf.free = NULL;
-	tty->buf.memory_used = 0;
-	INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-}
-
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_io.c linux-libre-2.6.37-gnu/drivers/char/tty_io.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_io.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,3198 +0,0 @@
-/*
- *  linux/drivers/char/tty_io.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time.  Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c).  This
- * makes for cleaner and more compact code.  -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling.  No delays, but all
- * other bits should be there.
- *	-- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- *	-- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- *	-- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- *      -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- *	-- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- *	-- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- *      -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context.  Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- *			 -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = {	/* for the benefit of tty drivers  */
-	.c_iflag = ICRNL | IXON,
-	.c_oflag = OPOST | ONLCR,
-	.c_cflag = B38400 | CS8 | CREAD | HUPCL,
-	.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
-		   ECHOCTL | ECHOKE | IEXTEN,
-	.c_cc = INIT_C_CC,
-	.c_ispeed = 38400,
-	.c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
-   could do with some rationalisation such as pulling the tty proc function
-   into this file */
-
-LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
-   vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-							size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-				unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int __tty_fasync(int fd, struct file *filp, int on);
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- *	alloc_tty_struct	-	allocate a tty object
- *
- *	Return a new empty tty structure. The data fields have not
- *	been initialized in any way but has been zeroed
- *
- *	Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
-	return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- *	free_tty_struct		-	free a disused tty
- *	@tty: tty struct to free
- *
- *	Free the write buffers, tty queue and tty memory itself.
- *
- *	Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
-	kfree(tty->write_buf);
-	tty_buffer_free_all(tty);
-	kfree(tty);
-}
-
-static inline struct tty_struct *file_tty(struct file *file)
-{
-	return ((struct tty_file_private *)file->private_data)->tty;
-}
-
-/* Associate a new file with the tty structure */
-void tty_add_file(struct tty_struct *tty, struct file *file)
-{
-	struct tty_file_private *priv;
-
-	/* XXX: must implement proper error handling in callers */
-	priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL);
-
-	priv->tty = tty;
-	priv->file = file;
-	file->private_data = priv;
-
-	spin_lock(&tty_files_lock);
-	list_add(&priv->list, &tty->tty_files);
-	spin_unlock(&tty_files_lock);
-}
-
-/* Delete file from its tty */
-void tty_del_file(struct file *file)
-{
-	struct tty_file_private *priv = file->private_data;
-
-	spin_lock(&tty_files_lock);
-	list_del(&priv->list);
-	spin_unlock(&tty_files_lock);
-	file->private_data = NULL;
-	kfree(priv);
-}
-
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- *	tty_name	-	return tty naming
- *	@tty: tty structure
- *	@buf: buffer for output
- *
- *	Convert a tty structure into a name. The name reflects the kernel
- *	naming policy and if udev is in use may not reflect user space
- *
- *	Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
-	if (!tty) /* Hmm.  NULL pointer.  That's fun. */
-		strcpy(buf, "NULL tty");
-	else
-		strcpy(buf, tty->name);
-	return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
-			      const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
-	if (!tty) {
-		printk(KERN_WARNING
-			"null TTY for (%d:%d) in %s\n",
-			imajor(inode), iminor(inode), routine);
-		return 1;
-	}
-	if (tty->magic != TTY_MAGIC) {
-		printk(KERN_WARNING
-			"bad magic number for tty struct (%d:%d) in %s\n",
-			imajor(inode), iminor(inode), routine);
-		return 1;
-	}
-#endif
-	return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
-	struct list_head *p;
-	int count = 0;
-
-	spin_lock(&tty_files_lock);
-	list_for_each(p, &tty->tty_files) {
-		count++;
-	}
-	spin_unlock(&tty_files_lock);
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_SLAVE &&
-	    tty->link && tty->link->count)
-		count++;
-	if (tty->count != count) {
-		printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
-				    "!= #fd's(%d) in %s\n",
-		       tty->name, tty->count, count, routine);
-		return count;
-	}
-#endif
-	return 0;
-}
-
-/**
- *	get_tty_driver		-	find device of a tty
- *	@dev_t: device identifier
- *	@index: returns the index of the tty
- *
- *	This routine returns a tty driver structure, given a device number
- *	and also passes back the index number.
- *
- *	Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
-	struct tty_driver *p;
-
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		dev_t base = MKDEV(p->major, p->minor_start);
-		if (device < base || device >= base + p->num)
-			continue;
-		*index = device - base;
-		return tty_driver_kref_get(p);
-	}
-	return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- *	tty_find_polling_driver	-	find device of a polled tty
- *	@name: name string to match
- *	@line: pointer to resulting tty line nr
- *
- *	This routine returns a tty driver structure, given a name
- *	and the condition that the tty driver is capable of polled
- *	operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
-	struct tty_driver *p, *res = NULL;
-	int tty_line = 0;
-	int len;
-	char *str, *stp;
-
-	for (str = name; *str; str++)
-		if ((*str >= '0' && *str <= '9') || *str == ',')
-			break;
-	if (!*str)
-		return NULL;
-
-	len = str - name;
-	tty_line = simple_strtoul(str, &str, 10);
-
-	mutex_lock(&tty_mutex);
-	/* Search through the tty devices to look for a match */
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (strncmp(name, p->name, len) != 0)
-			continue;
-		stp = str;
-		if (*stp == ',')
-			stp++;
-		if (*stp == '\0')
-			stp = NULL;
-
-		if (tty_line >= 0 && tty_line < p->num && p->ops &&
-		    p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
-			res = tty_driver_kref_get(p);
-			*line = tty_line;
-			break;
-		}
-	}
-	mutex_unlock(&tty_mutex);
-
-	return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- *	tty_check_change	-	check for POSIX terminal changes
- *	@tty: tty to check
- *
- *	If we try to write to, or set the state of, a terminal and we're
- *	not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *	ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *	Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	if (current->signal->tty != tty)
-		return 0;
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-	if (!tty->pgrp) {
-		printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-		goto out_unlock;
-	}
-	if (task_pgrp(current) == tty->pgrp)
-		goto out_unlock;
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (is_ignored(SIGTTOU))
-		goto out;
-	if (is_current_pgrp_orphaned()) {
-		ret = -EIO;
-		goto out;
-	}
-	kill_pgrp(task_pgrp(current), SIGTTOU, 1);
-	set_thread_flag(TIF_SIGPENDING);
-	ret = -ERESTARTSYS;
-out:
-	return ret;
-out_unlock:
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
-				size_t count, loff_t *ppos)
-{
-	return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-				 size_t count, loff_t *ppos)
-{
-	return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
-	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
-		unsigned long arg)
-{
-	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
-				     unsigned int cmd, unsigned long arg)
-{
-	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
-	.llseek		= no_llseek,
-	.read		= tty_read,
-	.write		= tty_write,
-	.poll		= tty_poll,
-	.unlocked_ioctl	= tty_ioctl,
-	.compat_ioctl	= tty_compat_ioctl,
-	.open		= tty_open,
-	.release	= tty_release,
-	.fasync		= tty_fasync,
-};
-
-static const struct file_operations console_fops = {
-	.llseek		= no_llseek,
-	.read		= tty_read,
-	.write		= redirected_tty_write,
-	.poll		= tty_poll,
-	.unlocked_ioctl	= tty_ioctl,
-	.compat_ioctl	= tty_compat_ioctl,
-	.open		= tty_open,
-	.release	= tty_release,
-	.fasync		= tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
-	.llseek		= no_llseek,
-	.read		= hung_up_tty_read,
-	.write		= hung_up_tty_write,
-	.poll		= hung_up_tty_poll,
-	.unlocked_ioctl	= hung_up_tty_ioctl,
-	.compat_ioctl	= hung_up_tty_compat_ioctl,
-	.release	= tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- *	tty_wakeup	-	request more data
- *	@tty: terminal
- *
- *	Internal and external helper for wakeups of tty. This function
- *	informs the line discipline if present that the driver is ready
- *	to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld;
-
-	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
-		ld = tty_ldisc_ref(tty);
-		if (ld) {
-			if (ld->ops->write_wakeup)
-				ld->ops->write_wakeup(tty);
-			tty_ldisc_deref(ld);
-		}
-	}
-	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- *	__tty_hangup		-	actual handler for hangup events
- *	@work: tty device
- *
- *	This can be called by the "eventd" kernel thread.  That is process
- *	synchronous but doesn't hold any locks, so we need to make sure we
- *	have the appropriate locks for what we're doing.
- *
- *	The hangup event clears any pending redirections onto the hung up
- *	device. It ensures future writes will error and it does the needed
- *	line discipline hangup and signal delivery. The tty object itself
- *	remains intact.
- *
- *	Locking:
- *		BTM
- *		  redirect lock for undoing redirection
- *		  file list lock for manipulating list of ttys
- *		  tty_ldisc_lock from called functions
- *		  termios_mutex resetting termios data
- *		  tasklist_lock to walk task list for hangup event
- *		    ->siglock to protect ->signal/->sighand
- */
-void __tty_hangup(struct tty_struct *tty)
-{
-	struct file *cons_filp = NULL;
-	struct file *filp, *f = NULL;
-	struct task_struct *p;
-	struct tty_file_private *priv;
-	int    closecount = 0, n;
-	unsigned long flags;
-	int refs = 0;
-
-	if (!tty)
-		return;
-
-
-	spin_lock(&redirect_lock);
-	if (redirect && file_tty(redirect) == tty) {
-		f = redirect;
-		redirect = NULL;
-	}
-	spin_unlock(&redirect_lock);
-
-	tty_lock();
-
-	/* inuse_filps is protected by the single tty lock,
-	   this really needs to change if we want to flush the
-	   workqueue with the lock held */
-	check_tty_count(tty, "tty_hangup");
-
-	spin_lock(&tty_files_lock);
-	/* This breaks for file handles being sent over AF_UNIX sockets ? */
-	list_for_each_entry(priv, &tty->tty_files, list) {
-		filp = priv->file;
-		if (filp->f_op->write == redirected_tty_write)
-			cons_filp = filp;
-		if (filp->f_op->write != tty_write)
-			continue;
-		closecount++;
-		__tty_fasync(-1, filp, 0);	/* can't block */
-		filp->f_op = &hung_up_tty_fops;
-	}
-	spin_unlock(&tty_files_lock);
-
-	tty_ldisc_hangup(tty);
-
-	read_lock(&tasklist_lock);
-	if (tty->session) {
-		do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-			spin_lock_irq(&p->sighand->siglock);
-			if (p->signal->tty == tty) {
-				p->signal->tty = NULL;
-				/* We defer the dereferences outside fo
-				   the tasklist lock */
-				refs++;
-			}
-			if (!p->signal->leader) {
-				spin_unlock_irq(&p->sighand->siglock);
-				continue;
-			}
-			__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-			__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-			put_pid(p->signal->tty_old_pgrp);  /* A noop */
-			spin_lock_irqsave(&tty->ctrl_lock, flags);
-			if (tty->pgrp)
-				p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-			spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-			spin_unlock_irq(&p->sighand->siglock);
-		} while_each_pid_task(tty->session, PIDTYPE_SID, p);
-	}
-	read_unlock(&tasklist_lock);
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	clear_bit(TTY_THROTTLED, &tty->flags);
-	clear_bit(TTY_PUSH, &tty->flags);
-	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-	put_pid(tty->session);
-	put_pid(tty->pgrp);
-	tty->session = NULL;
-	tty->pgrp = NULL;
-	tty->ctrl_status = 0;
-	set_bit(TTY_HUPPED, &tty->flags);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	/* Account for the p->signal references we killed */
-	while (refs--)
-		tty_kref_put(tty);
-
-	/*
-	 * If one of the devices matches a console pointer, we
-	 * cannot just call hangup() because that will cause
-	 * tty->count and state->count to go out of sync.
-	 * So we just call close() the right number of times.
-	 */
-	if (cons_filp) {
-		if (tty->ops->close)
-			for (n = 0; n < closecount; n++)
-				tty->ops->close(tty, cons_filp);
-	} else if (tty->ops->hangup)
-		(tty->ops->hangup)(tty);
-	/*
-	 * We don't want to have driver/ldisc interactions beyond
-	 * the ones we did here. The driver layer expects no
-	 * calls after ->hangup() from the ldisc side. However we
-	 * can't yet guarantee all that.
-	 */
-	set_bit(TTY_HUPPED, &tty->flags);
-	tty_ldisc_enable(tty);
-
-	tty_unlock();
-
-	if (f)
-		fput(f);
-}
-
-static void do_tty_hangup(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, hangup_work);
-
-	__tty_hangup(tty);
-}
-
-/**
- *	tty_hangup		-	trigger a hangup event
- *	@tty: tty to hangup
- *
- *	A carrier loss (virtual or otherwise) has occurred on this like
- *	schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-	char	buf[64];
-	printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
-	schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- *	tty_vhangup		-	process vhangup
- *	@tty: tty to hangup
- *
- *	The user has asked via system call for the terminal to be hung up.
- *	We do this synchronously so that when the syscall returns the process
- *	is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-	char	buf[64];
-
-	printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
-	__tty_hangup(tty);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-
-/**
- *	tty_vhangup_self	-	process vhangup for own ctty
- *
- *	Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
-	struct tty_struct *tty;
-
-	tty = get_current_tty();
-	if (tty) {
-		tty_vhangup(tty);
-		tty_kref_put(tty);
-	}
-}
-
-/**
- *	tty_hung_up_p		-	was tty hung up
- *	@filp: file pointer of tty
- *
- *	Return true if the tty has been subject to a vhangup or a carrier
- *	loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
-	return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
-	struct task_struct *p;
-	do_each_pid_task(session, PIDTYPE_SID, p) {
-		proc_clear_tty(p);
-	} while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- *	disassociate_ctty	-	disconnect controlling tty
- *	@on_exit: true if exiting so need to "hang up" the session
- *
- *	This function is typically called only by the session leader, when
- *	it wants to disassociate itself from its controlling tty.
- *
- *	It performs the following functions:
- * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
- * 	(2)  Clears the tty from being controlling the session
- * 	(3)  Clears the controlling tty for all processes in the
- * 		session group.
- *
- *	The argument on_exit is set to 1 if called when a process is
- *	exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *	Locking:
- *		BTM is taken for hysterical raisins, and held when
- *		  called from no_tty().
- *		  tty_mutex is taken to protect tty
- *		  ->siglock is taken to protect ->signal/->sighand
- *		  tasklist_lock is taken to walk process list for sessions
- *		    ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
-	struct tty_struct *tty;
-	struct pid *tty_pgrp = NULL;
-
-	if (!current->signal->leader)
-		return;
-
-	tty = get_current_tty();
-	if (tty) {
-		tty_pgrp = get_pid(tty->pgrp);
-		if (on_exit) {
-			if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
-				tty_vhangup(tty);
-		}
-		tty_kref_put(tty);
-	} else if (on_exit) {
-		struct pid *old_pgrp;
-		spin_lock_irq(&current->sighand->siglock);
-		old_pgrp = current->signal->tty_old_pgrp;
-		current->signal->tty_old_pgrp = NULL;
-		spin_unlock_irq(&current->sighand->siglock);
-		if (old_pgrp) {
-			kill_pgrp(old_pgrp, SIGHUP, on_exit);
-			kill_pgrp(old_pgrp, SIGCONT, on_exit);
-			put_pid(old_pgrp);
-		}
-		return;
-	}
-	if (tty_pgrp) {
-		kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-		if (!on_exit)
-			kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-		put_pid(tty_pgrp);
-	}
-
-	spin_lock_irq(&current->sighand->siglock);
-	put_pid(current->signal->tty_old_pgrp);
-	current->signal->tty_old_pgrp = NULL;
-	spin_unlock_irq(&current->sighand->siglock);
-
-	tty = get_current_tty();
-	if (tty) {
-		unsigned long flags;
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		put_pid(tty->session);
-		put_pid(tty->pgrp);
-		tty->session = NULL;
-		tty->pgrp = NULL;
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		tty_kref_put(tty);
-	} else {
-#ifdef TTY_DEBUG_HANGUP
-		printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-		       " = NULL", tty);
-#endif
-	}
-
-	/* Now clear signal->tty under the lock */
-	read_lock(&tasklist_lock);
-	session_clear_tty(task_session(current));
-	read_unlock(&tasklist_lock);
-}
-
-/**
- *
- *	no_tty	- Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
-	struct task_struct *tsk = current;
-	tty_lock();
-	disassociate_ctty(0);
-	tty_unlock();
-	proc_clear_tty(tsk);
-}
-
-
-/**
- *	stop_tty	-	propagate flow control
- *	@tty: tty to stop
- *
- *	Perform flow control to the driver. For PTY/TTY pairs we
- *	must also propagate the TIOCKPKT status. May be called
- *	on an already stopped device and will not re-call the driver
- *	method.
- *
- *	This functionality is used by both the line disciplines for
- *	halting incoming flow and by the driver. It may therefore be
- *	called from any context, may be under the tty atomic_write_lock
- *	but not always.
- *
- *	Locking:
- *		Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	if (tty->stopped) {
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		return;
-	}
-	tty->stopped = 1;
-	if (tty->link && tty->link->packet) {
-		tty->ctrl_status &= ~TIOCPKT_START;
-		tty->ctrl_status |= TIOCPKT_STOP;
-		wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-	}
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (tty->ops->stop)
-		(tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- *	start_tty	-	propagate flow control
- *	@tty: tty to start
- *
- *	Start a tty that has been stopped if at all possible. Perform
- *	any necessary wakeups and propagate the TIOCPKT status. If this
- *	is the tty was previous stopped and is being started then the
- *	driver start method is invoked and the line discipline woken.
- *
- *	Locking:
- *		ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	if (!tty->stopped || tty->flow_stopped) {
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		return;
-	}
-	tty->stopped = 0;
-	if (tty->link && tty->link->packet) {
-		tty->ctrl_status &= ~TIOCPKT_STOP;
-		tty->ctrl_status |= TIOCPKT_START;
-		wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-	}
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-	if (tty->ops->start)
-		(tty->ops->start)(tty);
-	/* If we have a running line discipline it may need kicking */
-	tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- *	tty_read	-	read method for tty device files
- *	@file: pointer to tty file
- *	@buf: user buffer
- *	@count: size of user buffer
- *	@ppos: unused
- *
- *	Perform the read system call function on this terminal device. Checks
- *	for hung up devices before calling the line discipline method.
- *
- *	Locking:
- *		Locks the line discipline internally while needed. Multiple
- *	read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-			loff_t *ppos)
-{
-	int i;
-	struct inode *inode = file->f_path.dentry->d_inode;
-	struct tty_struct *tty = file_tty(file);
-	struct tty_ldisc *ld;
-
-	if (tty_paranoia_check(tty, inode, "tty_read"))
-		return -EIO;
-	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-		return -EIO;
-
-	/* We want to wait for the line discipline to sort out in this
-	   situation */
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->read)
-		i = (ld->ops->read)(tty, file, buf, count);
-	else
-		i = -EIO;
-	tty_ldisc_deref(ld);
-	if (i > 0)
-		inode->i_atime = current_fs_time(inode->i_sb);
-	return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
-	mutex_unlock(&tty->atomic_write_lock);
-	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
-	if (!mutex_trylock(&tty->atomic_write_lock)) {
-		if (ndelay)
-			return -EAGAIN;
-		if (mutex_lock_interruptible(&tty->atomic_write_lock))
-			return -ERESTARTSYS;
-	}
-	return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
-	ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
-	struct tty_struct *tty,
-	struct file *file,
-	const char __user *buf,
-	size_t count)
-{
-	ssize_t ret, written = 0;
-	unsigned int chunk;
-
-	ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * We chunk up writes into a temporary buffer. This
-	 * simplifies low-level drivers immensely, since they
-	 * don't have locking issues and user mode accesses.
-	 *
-	 * But if TTY_NO_WRITE_SPLIT is set, we should use a
-	 * big chunk-size..
-	 *
-	 * The default chunk-size is 2kB, because the NTTY
-	 * layer has problems with bigger chunks. It will
-	 * claim to be able to handle more characters than
-	 * it actually does.
-	 *
-	 * FIXME: This can probably go away now except that 64K chunks
-	 * are too likely to fail unless switched to vmalloc...
-	 */
-	chunk = 2048;
-	if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
-		chunk = 65536;
-	if (count < chunk)
-		chunk = count;
-
-	/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
-	if (tty->write_cnt < chunk) {
-		unsigned char *buf_chunk;
-
-		if (chunk < 1024)
-			chunk = 1024;
-
-		buf_chunk = kmalloc(chunk, GFP_KERNEL);
-		if (!buf_chunk) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		kfree(tty->write_buf);
-		tty->write_cnt = chunk;
-		tty->write_buf = buf_chunk;
-	}
-
-	/* Do the write .. */
-	for (;;) {
-		size_t size = count;
-		if (size > chunk)
-			size = chunk;
-		ret = -EFAULT;
-		if (copy_from_user(tty->write_buf, buf, size))
-			break;
-		ret = write(tty, file, tty->write_buf, size);
-		if (ret <= 0)
-			break;
-		written += ret;
-		buf += ret;
-		count -= ret;
-		if (!count)
-			break;
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		cond_resched();
-	}
-	if (written) {
-		struct inode *inode = file->f_path.dentry->d_inode;
-		inode->i_mtime = current_fs_time(inode->i_sb);
-		ret = written;
-	}
-out:
-	tty_write_unlock(tty);
-	return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BTM and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-	if (tty) {
-		mutex_lock(&tty->atomic_write_lock);
-		tty_lock();
-		if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-			tty_unlock();
-			tty->ops->write(tty, msg, strlen(msg));
-		} else
-			tty_unlock();
-		tty_write_unlock(tty);
-	}
-	return;
-}
-
-
-/**
- *	tty_write		-	write method for tty device file
- *	@file: tty file pointer
- *	@buf: user data to write
- *	@count: bytes to write
- *	@ppos: unused
- *
- *	Write data to a tty device via the line discipline.
- *
- *	Locking:
- *		Locks the line discipline as required
- *		Writes to the tty driver are serialized by the atomic_write_lock
- *	and are then processed in chunks to the device. The line discipline
- *	write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
-						size_t count, loff_t *ppos)
-{
-	struct inode *inode = file->f_path.dentry->d_inode;
-	struct tty_struct *tty = file_tty(file);
- 	struct tty_ldisc *ld;
-	ssize_t ret;
-
-	if (tty_paranoia_check(tty, inode, "tty_write"))
-		return -EIO;
-	if (!tty || !tty->ops->write ||
-		(test_bit(TTY_IO_ERROR, &tty->flags)))
-			return -EIO;
-	/* Short term debug to catch buggy drivers */
-	if (tty->ops->write_room == NULL)
-		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
-			tty->driver->name);
-	ld = tty_ldisc_ref_wait(tty);
-	if (!ld->ops->write)
-		ret = -EIO;
-	else
-		ret = do_tty_write(ld->ops->write, tty, file, buf, count);
-	tty_ldisc_deref(ld);
-	return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-						size_t count, loff_t *ppos)
-{
-	struct file *p = NULL;
-
-	spin_lock(&redirect_lock);
-	if (redirect) {
-		get_file(redirect);
-		p = redirect;
-	}
-	spin_unlock(&redirect_lock);
-
-	if (p) {
-		ssize_t res;
-		res = vfs_write(p, buf, count, &p->f_pos);
-		fput(p);
-		return res;
-	}
-	return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- *	pty_line_name	-	generate name for a pty
- *	@driver: the tty driver in use
- *	@index: the minor number
- *	@p: output buffer of at least 6 bytes
- *
- *	Generate a name from a driver reference and write it to the output
- *	buffer.
- *
- *	Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
-	int i = index + driver->name_base;
-	/* ->name is initialized to "ttyp", but "tty" is expected */
-	sprintf(p, "%s%c%x",
-		driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
-		ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- *	tty_line_name	-	generate name for a tty
- *	@driver: the tty driver in use
- *	@index: the minor number
- *	@p: output buffer of at least 7 bytes
- *
- *	Generate a name from a driver reference and write it to the output
- *	buffer.
- *
- *	Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
-	sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- *	tty_driver_lookup_tty() - find an existing tty, if any
- *	@driver: the driver for the tty
- *	@idx:	 the minor number
- *
- *	Return the tty, if found or ERR_PTR() otherwise.
- *
- *	Locking: tty_mutex must be held. If tty is found, the mutex must
- *	be held until the 'fast-open' is also done. Will change once we
- *	have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
-		struct inode *inode, int idx)
-{
-	struct tty_struct *tty;
-
-	if (driver->ops->lookup)
-		return driver->ops->lookup(driver, inode, idx);
-
-	tty = driver->ttys[idx];
-	return tty;
-}
-
-/**
- *	tty_init_termios	-  helper for termios setup
- *	@tty: the tty to set up
- *
- *	Initialise the termios structures for this tty. Thus runs under
- *	the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
-	struct ktermios *tp;
-	int idx = tty->index;
-
-	tp = tty->driver->termios[idx];
-	if (tp == NULL) {
-		tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-		if (tp == NULL)
-			return -ENOMEM;
-		memcpy(tp, &tty->driver->init_termios,
-						sizeof(struct ktermios));
-		tty->driver->termios[idx] = tp;
-	}
-	tty->termios = tp;
-	tty->termios_locked = tp + 1;
-
-	/* Compatibility until drivers always set this */
-	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-	tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- *	tty_driver_install_tty() - install a tty entry in the driver
- *	@driver: the driver for the tty
- *	@tty: the tty
- *
- *	Install a tty object into the driver tables. The tty->index field
- *	will be set by the time this is called. This method is responsible
- *	for ensuring any need additional structures are allocated and
- *	configured.
- *
- *	Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
-						struct tty_struct *tty)
-{
-	int idx = tty->index;
-	int ret;
-
-	if (driver->ops->install) {
-		ret = driver->ops->install(driver, tty);
-		return ret;
-	}
-
-	if (tty_init_termios(tty) == 0) {
-		tty_driver_kref_get(driver);
-		tty->count++;
-		driver->ttys[idx] = tty;
-		return 0;
-	}
-	return -ENOMEM;
-}
-
-/**
- *	tty_driver_remove_tty() - remove a tty from the driver tables
- *	@driver: the driver for the tty
- *	@idx:	 the minor number
- *
- *	Remvoe a tty object from the driver tables. The tty->index field
- *	will be set by the time this is called.
- *
- *	Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
-						struct tty_struct *tty)
-{
-	if (driver->ops->remove)
-		driver->ops->remove(driver, tty);
-	else
-		driver->ttys[tty->index] = NULL;
-}
-
-/*
- * 	tty_reopen()	- fast re-open of an open tty
- * 	@tty	- the tty to open
- *
- *	Return 0 on success, -errno on error.
- *
- *	Locking: tty_mutex must be held from the time the tty was found
- *		 till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
-	struct tty_driver *driver = tty->driver;
-
-	if (test_bit(TTY_CLOSING, &tty->flags))
-		return -EIO;
-
-	if (driver->type == TTY_DRIVER_TYPE_PTY &&
-	    driver->subtype == PTY_TYPE_MASTER) {
-		/*
-		 * special case for PTY masters: only one open permitted,
-		 * and the slave side open count is incremented as well.
-		 */
-		if (tty->count)
-			return -EIO;
-
-		tty->link->count++;
-	}
-	tty->count++;
-	tty->driver = driver; /* N.B. why do this every time?? */
-
-	mutex_lock(&tty->ldisc_mutex);
-	WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-	mutex_unlock(&tty->ldisc_mutex);
-
-	return 0;
-}
-
-/**
- *	tty_init_dev		-	initialise a tty device
- *	@driver: tty driver we are opening a device on
- *	@idx: device index
- *	@ret_tty: returned tty structure
- *	@first_ok: ok to open a new device (used by ptmx)
- *
- *	Prepare a tty device. This may not be a "new" clean device but
- *	could also be an active device. The pty drivers require special
- *	handling because of this.
- *
- *	Locking:
- *		The function is called under the tty_mutex, which
- *	protects us from the tty struct or driver itself going away.
- *
- *	On exit the tty device has the line discipline attached and
- *	a reference count of 1. If a pair was created for pty/tty use
- *	and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-								int first_ok)
-{
-	struct tty_struct *tty;
-	int retval;
-
-	/* Check if pty master is being opened multiple times */
-	if (driver->subtype == PTY_TYPE_MASTER &&
-		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-		return ERR_PTR(-EIO);
-	}
-
-	/*
-	 * First time open is complex, especially for PTY devices.
-	 * This code guarantees that either everything succeeds and the
-	 * TTY is ready for operation, or else the table slots are vacated
-	 * and the allocated memory released.  (Except that the termios
-	 * and locked termios may be retained.)
-	 */
-
-	if (!try_module_get(driver->owner))
-		return ERR_PTR(-ENODEV);
-
-	tty = alloc_tty_struct();
-	if (!tty)
-		goto fail_no_mem;
-	initialize_tty_struct(tty, driver, idx);
-
-	retval = tty_driver_install_tty(driver, tty);
-	if (retval < 0) {
-		free_tty_struct(tty);
-		module_put(driver->owner);
-		return ERR_PTR(retval);
-	}
-
-	/*
-	 * Structures all installed ... call the ldisc open routines.
-	 * If we fail here just call release_tty to clean up.  No need
-	 * to decrement the use counts, as release_tty doesn't care.
-	 */
-	retval = tty_ldisc_setup(tty, tty->link);
-	if (retval)
-		goto release_mem_out;
-	return tty;
-
-fail_no_mem:
-	module_put(driver->owner);
-	return ERR_PTR(-ENOMEM);
-
-	/* call the tty release_tty routine to clean out this slot */
-release_mem_out:
-	if (printk_ratelimit())
-		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
-				 "clearing slot %d\n", idx);
-	release_tty(tty, idx);
-	return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
-	struct ktermios *tp;
-	int idx = tty->index;
-	/* Kill this flag and push into drivers for locking etc */
-	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-		/* FIXME: Locking on ->termios array */
-		tp = tty->termios;
-		tty->driver->termios[idx] = NULL;
-		kfree(tp);
-	}
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
-	tty_driver_remove_tty(tty->driver, tty);
-	tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- *	release_one_tty		-	release tty structure memory
- *	@kref: kref of tty we are obliterating
- *
- *	Releases memory associated with a tty structure, and clears out the
- *	driver table slots. This function is called when a device is no longer
- *	in use. It also gets called when setup of a device fails.
- *
- *	Locking:
- *		tty_mutex - sometimes only
- *		takes the file list lock internally when working on the list
- *	of ttys that the driver keeps.
- *
- *	This method gets called from a work queue so that the driver private
- *	cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, hangup_work);
-	struct tty_driver *driver = tty->driver;
-
-	if (tty->ops->cleanup)
-		tty->ops->cleanup(tty);
-
-	tty->magic = 0;
-	tty_driver_kref_put(driver);
-	module_put(driver->owner);
-
-	spin_lock(&tty_files_lock);
-	list_del_init(&tty->tty_files);
-	spin_unlock(&tty_files_lock);
-
-	put_pid(tty->pgrp);
-	put_pid(tty->session);
-	free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
-	struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
-	if (tty->ops->shutdown)
-		tty->ops->shutdown(tty);
-	else
-		tty_shutdown(tty);
-
-	/* The hangup queue is now free so we can reuse it rather than
-	   waste a chunk of memory for each port */
-	INIT_WORK(&tty->hangup_work, release_one_tty);
-	schedule_work(&tty->hangup_work);
-}
-
-/**
- *	tty_kref_put		-	release a tty kref
- *	@tty: tty device
- *
- *	Release a reference to a tty device and if need be let the kref
- *	layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
-	if (tty)
-		kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- *	release_tty		-	release tty structure memory
- *
- *	Release both @tty and a possible linked partner (think pty pair),
- *	and decrement the refcount of the backing module.
- *
- *	Locking:
- *		tty_mutex - sometimes only
- *		takes the file list lock internally when working on the list
- *	of ttys that the driver keeps.
- *		FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
-	/* This should always be true but check for the moment */
-	WARN_ON(tty->index != idx);
-
-	if (tty->link)
-		tty_kref_put(tty->link);
-	tty_kref_put(tty);
-}
-
-/**
- *	tty_release		-	vfs callback for close
- *	@inode: inode of tty
- *	@filp: file pointer for handle to tty
- *
- *	Called the last time each file handle is closed that references
- *	this tty. There may however be several such references.
- *
- *	Locking:
- *		Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty = file_tty(filp);
-	struct tty_struct *o_tty;
-	int	pty_master, tty_closing, o_tty_closing, do_sleep;
-	int	devpts;
-	int	idx;
-	char	buf[64];
-
-	if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-		return 0;
-
-	tty_lock();
-	check_tty_count(tty, "tty_release_dev");
-
-	__tty_fasync(-1, filp, 0);
-
-	idx = tty->index;
-	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-		      tty->driver->subtype == PTY_TYPE_MASTER);
-	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
-	o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
-	if (idx < 0 || idx >= tty->driver->num) {
-		printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-				  "free (%s)\n", tty->name);
-		tty_unlock();
-		return 0;
-	}
-	if (!devpts) {
-		if (tty != tty->driver->ttys[idx]) {
-			tty_unlock();
-			printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-			       "for (%s)\n", idx, tty->name);
-			return 0;
-		}
-		if (tty->termios != tty->driver->termios[idx]) {
-			tty_unlock();
-			printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-			       "for (%s)\n",
-			       idx, tty->name);
-			return 0;
-		}
-	}
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-	       tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
-	if (tty->driver->other &&
-	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-		if (o_tty != tty->driver->other->ttys[idx]) {
-			tty_unlock();
-			printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-					  "not o_tty for (%s)\n",
-			       idx, tty->name);
-			return 0 ;
-		}
-		if (o_tty->termios != tty->driver->other->termios[idx]) {
-			tty_unlock();
-			printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-					  "not o_termios for (%s)\n",
-			       idx, tty->name);
-			return 0;
-		}
-		if (o_tty->link != tty) {
-			tty_unlock();
-			printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-			return 0;
-		}
-	}
-#endif
-	if (tty->ops->close)
-		tty->ops->close(tty, filp);
-
-	tty_unlock();
-	/*
-	 * Sanity check: if tty->count is going to zero, there shouldn't be
-	 * any waiters on tty->read_wait or tty->write_wait.  We test the
-	 * wait queues and kick everyone out _before_ actually starting to
-	 * close.  This ensures that we won't block while releasing the tty
-	 * structure.
-	 *
-	 * The test for the o_tty closing is necessary, since the master and
-	 * slave sides may close in any order.  If the slave side closes out
-	 * first, its count will be one, since the master side holds an open.
-	 * Thus this test wouldn't be triggered at the time the slave closes,
-	 * so we do it now.
-	 *
-	 * Note that it's possible for the tty to be opened again while we're
-	 * flushing out waiters.  By recalculating the closing flags before
-	 * each iteration we avoid any problems.
-	 */
-	while (1) {
-		/* Guard against races with tty->count changes elsewhere and
-		   opens on /dev/tty */
-
-		mutex_lock(&tty_mutex);
-		tty_lock();
-		tty_closing = tty->count <= 1;
-		o_tty_closing = o_tty &&
-			(o_tty->count <= (pty_master ? 1 : 0));
-		do_sleep = 0;
-
-		if (tty_closing) {
-			if (waitqueue_active(&tty->read_wait)) {
-				wake_up_poll(&tty->read_wait, POLLIN);
-				do_sleep++;
-			}
-			if (waitqueue_active(&tty->write_wait)) {
-				wake_up_poll(&tty->write_wait, POLLOUT);
-				do_sleep++;
-			}
-		}
-		if (o_tty_closing) {
-			if (waitqueue_active(&o_tty->read_wait)) {
-				wake_up_poll(&o_tty->read_wait, POLLIN);
-				do_sleep++;
-			}
-			if (waitqueue_active(&o_tty->write_wait)) {
-				wake_up_poll(&o_tty->write_wait, POLLOUT);
-				do_sleep++;
-			}
-		}
-		if (!do_sleep)
-			break;
-
-		printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-				    "active!\n", tty_name(tty, buf));
-		tty_unlock();
-		mutex_unlock(&tty_mutex);
-		schedule();
-	}
-
-	/*
-	 * The closing flags are now consistent with the open counts on
-	 * both sides, and we've completed the last operation that could
-	 * block, so it's safe to proceed with closing.
-	 */
-	if (pty_master) {
-		if (--o_tty->count < 0) {
-			printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-					    "(%d) for %s\n",
-			       o_tty->count, tty_name(o_tty, buf));
-			o_tty->count = 0;
-		}
-	}
-	if (--tty->count < 0) {
-		printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-		       tty->count, tty_name(tty, buf));
-		tty->count = 0;
-	}
-
-	/*
-	 * We've decremented tty->count, so we need to remove this file
-	 * descriptor off the tty->tty_files list; this serves two
-	 * purposes:
-	 *  - check_tty_count sees the correct number of file descriptors
-	 *    associated with this tty.
-	 *  - do_tty_hangup no longer sees this file descriptor as
-	 *    something that needs to be handled for hangups.
-	 */
-	tty_del_file(filp);
-
-	/*
-	 * Perform some housekeeping before deciding whether to return.
-	 *
-	 * Set the TTY_CLOSING flag if this was the last open.  In the
-	 * case of a pty we may have to wait around for the other side
-	 * to close, and TTY_CLOSING makes sure we can't be reopened.
-	 */
-	if (tty_closing)
-		set_bit(TTY_CLOSING, &tty->flags);
-	if (o_tty_closing)
-		set_bit(TTY_CLOSING, &o_tty->flags);
-
-	/*
-	 * If _either_ side is closing, make sure there aren't any
-	 * processes that still think tty or o_tty is their controlling
-	 * tty.
-	 */
-	if (tty_closing || o_tty_closing) {
-		read_lock(&tasklist_lock);
-		session_clear_tty(tty->session);
-		if (o_tty)
-			session_clear_tty(o_tty->session);
-		read_unlock(&tasklist_lock);
-	}
-
-	mutex_unlock(&tty_mutex);
-
-	/* check whether both sides are closing ... */
-	if (!tty_closing || (o_tty && !o_tty_closing)) {
-		tty_unlock();
-		return 0;
-	}
-
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "freeing tty structure...");
-#endif
-	/*
-	 * Ask the line discipline code to release its structures
-	 */
-	tty_ldisc_release(tty, o_tty);
-	/*
-	 * The release_tty function takes care of the details of clearing
-	 * the slots and preserving the termios structure.
-	 */
-	release_tty(tty, idx);
-
-	/* Make this pty number available for reallocation */
-	if (devpts)
-		devpts_kill_index(inode, idx);
-	tty_unlock();
-	return 0;
-}
-
-/**
- *	tty_open		-	open a tty device
- *	@inode: inode of device file
- *	@filp: file pointer to tty
- *
- *	tty_open and tty_release keep up the tty count that contains the
- *	number of opens done on a tty. We cannot use the inode-count, as
- *	different inodes might point to the same tty.
- *
- *	Open-counting is needed for pty masters, as well as for keeping
- *	track of serial lines: DTR is dropped when the last close happens.
- *	(This is not done solely through tty->count, now.  - Ted 1/27/92)
- *
- *	The termios state of a pty is reset on first open so that
- *	settings don't persist across reuse.
- *
- *	Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- *		 tty->count should protect the rest.
- *		 ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
-	struct tty_struct *tty = NULL;
-	int noctty, retval;
-	struct tty_driver *driver;
-	int index;
-	dev_t device = inode->i_rdev;
-	unsigned saved_flags = filp->f_flags;
-
-	nonseekable_open(inode, filp);
-
-retry_open:
-	noctty = filp->f_flags & O_NOCTTY;
-	index  = -1;
-	retval = 0;
-
-	mutex_lock(&tty_mutex);
-	tty_lock();
-
-	if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-		tty = get_current_tty();
-		if (!tty) {
-			tty_unlock();
-			mutex_unlock(&tty_mutex);
-			return -ENXIO;
-		}
-		driver = tty_driver_kref_get(tty->driver);
-		index = tty->index;
-		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-		/* noctty = 1; */
-		/* FIXME: Should we take a driver reference ? */
-		tty_kref_put(tty);
-		goto got_driver;
-	}
-#ifdef CONFIG_VT
-	if (device == MKDEV(TTY_MAJOR, 0)) {
-		extern struct tty_driver *console_driver;
-		driver = tty_driver_kref_get(console_driver);
-		index = fg_console;
-		noctty = 1;
-		goto got_driver;
-	}
-#endif
-	if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-		struct tty_driver *console_driver = console_device(&index);
-		if (console_driver) {
-			driver = tty_driver_kref_get(console_driver);
-			if (driver) {
-				/* Don't let /dev/console block */
-				filp->f_flags |= O_NONBLOCK;
-				noctty = 1;
-				goto got_driver;
-			}
-		}
-		tty_unlock();
-		mutex_unlock(&tty_mutex);
-		return -ENODEV;
-	}
-
-	driver = get_tty_driver(device, &index);
-	if (!driver) {
-		tty_unlock();
-		mutex_unlock(&tty_mutex);
-		return -ENODEV;
-	}
-got_driver:
-	if (!tty) {
-		/* check whether we're reopening an existing tty */
-		tty = tty_driver_lookup_tty(driver, inode, index);
-
-		if (IS_ERR(tty)) {
-			tty_unlock();
-			mutex_unlock(&tty_mutex);
-			return PTR_ERR(tty);
-		}
-	}
-
-	if (tty) {
-		retval = tty_reopen(tty);
-		if (retval)
-			tty = ERR_PTR(retval);
-	} else
-		tty = tty_init_dev(driver, index, 0);
-
-	mutex_unlock(&tty_mutex);
-	tty_driver_kref_put(driver);
-	if (IS_ERR(tty)) {
-		tty_unlock();
-		return PTR_ERR(tty);
-	}
-
-	tty_add_file(tty, filp);
-
-	check_tty_count(tty, "tty_open");
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
-	if (!retval) {
-		if (tty->ops->open)
-			retval = tty->ops->open(tty, filp);
-		else
-			retval = -ENODEV;
-	}
-	filp->f_flags = saved_flags;
-
-	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-						!capable(CAP_SYS_ADMIN))
-		retval = -EBUSY;
-
-	if (retval) {
-#ifdef TTY_DEBUG_HANGUP
-		printk(KERN_DEBUG "error %d in opening %s...", retval,
-		       tty->name);
-#endif
-		tty_unlock(); /* need to call tty_release without BTM */
-		tty_release(inode, filp);
-		if (retval != -ERESTARTSYS)
-			return retval;
-
-		if (signal_pending(current))
-			return retval;
-
-		schedule();
-		/*
-		 * Need to reset f_op in case a hangup happened.
-		 */
-		tty_lock();
-		if (filp->f_op == &hung_up_tty_fops)
-			filp->f_op = &tty_fops;
-		tty_unlock();
-		goto retry_open;
-	}
-	tty_unlock();
-
-
-	mutex_lock(&tty_mutex);
-	tty_lock();
-	spin_lock_irq(&current->sighand->siglock);
-	if (!noctty &&
-	    current->signal->leader &&
-	    !current->signal->tty &&
-	    tty->session == NULL)
-		__proc_set_tty(current, tty);
-	spin_unlock_irq(&current->sighand->siglock);
-	tty_unlock();
-	mutex_unlock(&tty_mutex);
-	return 0;
-}
-
-
-
-/**
- *	tty_poll	-	check tty status
- *	@filp: file being polled
- *	@wait: poll wait structures to update
- *
- *	Call the line discipline polling method to obtain the poll
- *	status of the device.
- *
- *	Locking: locks called line discipline but ldisc poll method
- *	may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
-	struct tty_struct *tty = file_tty(filp);
-	struct tty_ldisc *ld;
-	int ret = 0;
-
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
-		return 0;
-
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->poll)
-		ret = (ld->ops->poll)(tty, filp, wait);
-	tty_ldisc_deref(ld);
-	return ret;
-}
-
-static int __tty_fasync(int fd, struct file *filp, int on)
-{
-	struct tty_struct *tty = file_tty(filp);
-	unsigned long flags;
-	int retval = 0;
-
-	if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
-		goto out;
-
-	retval = fasync_helper(fd, filp, on, &tty->fasync);
-	if (retval <= 0)
-		goto out;
-
-	if (on) {
-		enum pid_type type;
-		struct pid *pid;
-		if (!waitqueue_active(&tty->read_wait))
-			tty->minimum_to_wake = 1;
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		if (tty->pgrp) {
-			pid = tty->pgrp;
-			type = PIDTYPE_PGID;
-		} else {
-			pid = task_pid(current);
-			type = PIDTYPE_PID;
-		}
-		get_pid(pid);
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		retval = __f_setown(filp, pid, type, 0);
-		put_pid(pid);
-		if (retval)
-			goto out;
-	} else {
-		if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-			tty->minimum_to_wake = N_TTY_BUF_SIZE;
-	}
-	retval = 0;
-out:
-	return retval;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
-	int retval;
-	tty_lock();
-	retval = __tty_fasync(fd, filp, on);
-	tty_unlock();
-	return retval;
-}
-
-/**
- *	tiocsti			-	fake input character
- *	@tty: tty to fake input into
- *	@p: pointer to character
- *
- *	Fake input to a tty device. Does the necessary locking and
- *	input management.
- *
- *	FIXME: does not honour flow control ??
- *
- *	Locking:
- *		Called functions take tty_ldisc_lock
- *		current->signal->tty check is safe without locks
- *
- *	FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
-	char ch, mbz = 0;
-	struct tty_ldisc *ld;
-
-	if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (get_user(ch, p))
-		return -EFAULT;
-	tty_audit_tiocsti(tty, ch);
-	ld = tty_ldisc_ref_wait(tty);
-	ld->ops->receive_buf(tty, &ch, &mbz, 1);
-	tty_ldisc_deref(ld);
-	return 0;
-}
-
-/**
- *	tiocgwinsz		-	implement window query ioctl
- *	@tty; tty
- *	@arg: user buffer for result
- *
- *	Copies the kernel idea of the window size into the user buffer.
- *
- *	Locking: tty->termios_mutex is taken to ensure the winsize data
- *		is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-	int err;
-
-	mutex_lock(&tty->termios_mutex);
-	err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-	mutex_unlock(&tty->termios_mutex);
-
-	return err ? -EFAULT: 0;
-}
-
-/**
- *	tty_do_resize		-	resize event
- *	@tty: tty being resized
- *	@rows: rows (character)
- *	@cols: cols (character)
- *
- *	Update the termios variables and send the necessary signals to
- *	peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
-	struct pid *pgrp;
-	unsigned long flags;
-
-	/* Lock the tty */
-	mutex_lock(&tty->termios_mutex);
-	if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-		goto done;
-	/* Get the PID values and reference them so we can
-	   avoid holding the tty ctrl lock while sending signals */
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	pgrp = get_pid(tty->pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	if (pgrp)
-		kill_pgrp(pgrp, SIGWINCH, 1);
-	put_pid(pgrp);
-
-	tty->winsize = *ws;
-done:
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-
-/**
- *	tiocswinsz		-	implement window size set ioctl
- *	@tty; tty side of tty
- *	@arg: user buffer for result
- *
- *	Copies the user idea of the window size to the kernel. Traditionally
- *	this is just advisory information but for the Linux console it
- *	actually has driver level meaning and triggers a VC resize.
- *
- *	Locking:
- *		Driver dependant. The default do_resize method takes the
- *	tty termios mutex and ctrl_lock. The console takes its own lock
- *	then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-	struct winsize tmp_ws;
-	if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-		return -EFAULT;
-
-	if (tty->ops->resize)
-		return tty->ops->resize(tty, &tmp_ws);
-	else
-		return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- *	tioccons	-	allow admin to move logical console
- *	@file: the file to become console
- *
- *	Allow the adminstrator to move the redirected console device
- *
- *	Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (file->f_op->write == redirected_tty_write) {
-		struct file *f;
-		spin_lock(&redirect_lock);
-		f = redirect;
-		redirect = NULL;
-		spin_unlock(&redirect_lock);
-		if (f)
-			fput(f);
-		return 0;
-	}
-	spin_lock(&redirect_lock);
-	if (redirect) {
-		spin_unlock(&redirect_lock);
-		return -EBUSY;
-	}
-	get_file(file);
-	redirect = file;
-	spin_unlock(&redirect_lock);
-	return 0;
-}
-
-/**
- *	fionbio		-	non blocking ioctl
- *	@file: file to set blocking value
- *	@p: user parameter
- *
- *	Historical tty interfaces had a blocking control ioctl before
- *	the generic functionality existed. This piece of history is preserved
- *	in the expected tty API of posix OS's.
- *
- *	Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
-	int nonblock;
-
-	if (get_user(nonblock, p))
-		return -EFAULT;
-
-	spin_lock(&file->f_lock);
-	if (nonblock)
-		file->f_flags |= O_NONBLOCK;
-	else
-		file->f_flags &= ~O_NONBLOCK;
-	spin_unlock(&file->f_lock);
-	return 0;
-}
-
-/**
- *	tiocsctty	-	set controlling tty
- *	@tty: tty structure
- *	@arg: user argument
- *
- *	This ioctl is used to manage job control. It permits a session
- *	leader to set this tty as the controlling tty for the session.
- *
- *	Locking:
- *		Takes tty_mutex() to protect tty instance
- *		Takes tasklist_lock internally to walk sessions
- *		Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
-	int ret = 0;
-	if (current->signal->leader && (task_session(current) == tty->session))
-		return ret;
-
-	mutex_lock(&tty_mutex);
-	/*
-	 * The process must be a session leader and
-	 * not have a controlling tty already.
-	 */
-	if (!current->signal->leader || current->signal->tty) {
-		ret = -EPERM;
-		goto unlock;
-	}
-
-	if (tty->session) {
-		/*
-		 * This tty is already the controlling
-		 * tty for another session group!
-		 */
-		if (arg == 1 && capable(CAP_SYS_ADMIN)) {
-			/*
-			 * Steal it away
-			 */
-			read_lock(&tasklist_lock);
-			session_clear_tty(tty->session);
-			read_unlock(&tasklist_lock);
-		} else {
-			ret = -EPERM;
-			goto unlock;
-		}
-	}
-	proc_set_tty(current, tty);
-unlock:
-	mutex_unlock(&tty_mutex);
-	return ret;
-}
-
-/**
- *	tty_get_pgrp	-	return a ref counted pgrp pid
- *	@tty: tty to read
- *
- *	Returns a refcounted instance of the pid struct for the process
- *	group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
-	unsigned long flags;
-	struct pid *pgrp;
-
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	pgrp = get_pid(tty->pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-	return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- *	tiocgpgrp		-	get process group
- *	@tty: tty passed by user
- *	@real_tty: tty side of the tty pased by the user if a pty else the tty
- *	@p: returned pid
- *
- *	Obtain the process group of the tty. If there is no process group
- *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	struct pid *pid;
-	int ret;
-	/*
-	 * (tty == real_tty) is a cheap way of
-	 * testing if the tty is NOT a master pty.
-	 */
-	if (tty == real_tty && current->signal->tty != real_tty)
-		return -ENOTTY;
-	pid = tty_get_pgrp(real_tty);
-	ret =  put_user(pid_vnr(pid), p);
-	put_pid(pid);
-	return ret;
-}
-
-/**
- *	tiocspgrp		-	attempt to set process group
- *	@tty: tty passed by user
- *	@real_tty: tty side device matching tty passed by user
- *	@p: pid pointer
- *
- *	Set the process group of the tty to the session passed. Only
- *	permitted where the tty session is our session.
- *
- *	Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	struct pid *pgrp;
-	pid_t pgrp_nr;
-	int retval = tty_check_change(real_tty);
-	unsigned long flags;
-
-	if (retval == -EIO)
-		return -ENOTTY;
-	if (retval)
-		return retval;
-	if (!current->signal->tty ||
-	    (current->signal->tty != real_tty) ||
-	    (real_tty->session != task_session(current)))
-		return -ENOTTY;
-	if (get_user(pgrp_nr, p))
-		return -EFAULT;
-	if (pgrp_nr < 0)
-		return -EINVAL;
-	rcu_read_lock();
-	pgrp = find_vpid(pgrp_nr);
-	retval = -ESRCH;
-	if (!pgrp)
-		goto out_unlock;
-	retval = -EPERM;
-	if (session_of_pgrp(pgrp) != task_session(current))
-		goto out_unlock;
-	retval = 0;
-	spin_lock_irqsave(&tty->ctrl_lock, flags);
-	put_pid(real_tty->pgrp);
-	real_tty->pgrp = get_pid(pgrp);
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
-	rcu_read_unlock();
-	return retval;
-}
-
-/**
- *	tiocgsid		-	get session id
- *	@tty: tty passed by user
- *	@real_tty: tty side of the tty pased by the user if a pty else the tty
- *	@p: pointer to returned session id
- *
- *	Obtain the session id of the tty. If there is no session
- *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-	/*
-	 * (tty == real_tty) is a cheap way of
-	 * testing if the tty is NOT a master pty.
-	*/
-	if (tty == real_tty && current->signal->tty != real_tty)
-		return -ENOTTY;
-	if (!real_tty->session)
-		return -ENOTTY;
-	return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- *	tiocsetd	-	set line discipline
- *	@tty: tty device
- *	@p: pointer to user data
- *
- *	Set the line discipline according to user request.
- *
- *	Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
-	int ldisc;
-	int ret;
-
-	if (get_user(ldisc, p))
-		return -EFAULT;
-
-	ret = tty_set_ldisc(tty, ldisc);
-
-	return ret;
-}
-
-/**
- *	send_break	-	performed time break
- *	@tty: device to break on
- *	@duration: timeout in mS
- *
- *	Perform a timed break on hardware that lacks its own driver level
- *	timed break functionality.
- *
- *	Locking:
- *		atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
-	int retval;
-
-	if (tty->ops->break_ctl == NULL)
-		return 0;
-
-	if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
-		retval = tty->ops->break_ctl(tty, duration);
-	else {
-		/* Do the work ourselves */
-		if (tty_write_lock(tty, 0) < 0)
-			return -EINTR;
-		retval = tty->ops->break_ctl(tty, -1);
-		if (retval)
-			goto out;
-		if (!signal_pending(current))
-			msleep_interruptible(duration);
-		retval = tty->ops->break_ctl(tty, 0);
-out:
-		tty_write_unlock(tty);
-		if (signal_pending(current))
-			retval = -EINTR;
-	}
-	return retval;
-}
-
-/**
- *	tty_tiocmget		-	get modem status
- *	@tty: tty device
- *	@file: user file pointer
- *	@p: pointer to result
- *
- *	Obtain the modem status bits from the tty driver if the feature
- *	is supported. Return -EINVAL if it is not available.
- *
- *	Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
-	int retval = -EINVAL;
-
-	if (tty->ops->tiocmget) {
-		retval = tty->ops->tiocmget(tty, file);
-
-		if (retval >= 0)
-			retval = put_user(retval, p);
-	}
-	return retval;
-}
-
-/**
- *	tty_tiocmset		-	set modem status
- *	@tty: tty device
- *	@file: user file pointer
- *	@cmd: command - clear bits, set bits or set all
- *	@p: pointer to desired bits
- *
- *	Set the modem status bits from the tty driver if the feature
- *	is supported. Return -EINVAL if it is not available.
- *
- *	Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
-	     unsigned __user *p)
-{
-	int retval;
-	unsigned int set, clear, val;
-
-	if (tty->ops->tiocmset == NULL)
-		return -EINVAL;
-
-	retval = get_user(val, p);
-	if (retval)
-		return retval;
-	set = clear = 0;
-	switch (cmd) {
-	case TIOCMBIS:
-		set = val;
-		break;
-	case TIOCMBIC:
-		clear = val;
-		break;
-	case TIOCMSET:
-		set = val;
-		clear = ~val;
-		break;
-	}
-	set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-	clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-	return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		tty = tty->link;
-	return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-	    return tty;
-	return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct tty_struct *tty = file_tty(file);
-	struct tty_struct *real_tty;
-	void __user *p = (void __user *)arg;
-	int retval;
-	struct tty_ldisc *ld;
-	struct inode *inode = file->f_dentry->d_inode;
-
-	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-		return -EINVAL;
-
-	real_tty = tty_pair_get_tty(tty);
-
-	/*
-	 * Factor out some common prep work
-	 */
-	switch (cmd) {
-	case TIOCSETD:
-	case TIOCSBRK:
-	case TIOCCBRK:
-	case TCSBRK:
-	case TCSBRKP:
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-		if (cmd != TIOCCBRK) {
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-		}
-		break;
-	}
-
-	/*
-	 *	Now do the stuff.
-	 */
-	switch (cmd) {
-	case TIOCSTI:
-		return tiocsti(tty, p);
-	case TIOCGWINSZ:
-		return tiocgwinsz(real_tty, p);
-	case TIOCSWINSZ:
-		return tiocswinsz(real_tty, p);
-	case TIOCCONS:
-		return real_tty != tty ? -EINVAL : tioccons(file);
-	case FIONBIO:
-		return fionbio(file, p);
-	case TIOCEXCL:
-		set_bit(TTY_EXCLUSIVE, &tty->flags);
-		return 0;
-	case TIOCNXCL:
-		clear_bit(TTY_EXCLUSIVE, &tty->flags);
-		return 0;
-	case TIOCNOTTY:
-		if (current->signal->tty != tty)
-			return -ENOTTY;
-		no_tty();
-		return 0;
-	case TIOCSCTTY:
-		return tiocsctty(tty, arg);
-	case TIOCGPGRP:
-		return tiocgpgrp(tty, real_tty, p);
-	case TIOCSPGRP:
-		return tiocspgrp(tty, real_tty, p);
-	case TIOCGSID:
-		return tiocgsid(tty, real_tty, p);
-	case TIOCGETD:
-		return put_user(tty->ldisc->ops->num, (int __user *)p);
-	case TIOCSETD:
-		return tiocsetd(tty, p);
-	/*
-	 * Break handling
-	 */
-	case TIOCSBRK:	/* Turn break on, unconditionally */
-		if (tty->ops->break_ctl)
-			return tty->ops->break_ctl(tty, -1);
-		return 0;
-	case TIOCCBRK:	/* Turn break off, unconditionally */
-		if (tty->ops->break_ctl)
-			return tty->ops->break_ctl(tty, 0);
-		return 0;
-	case TCSBRK:   /* SVID version: non-zero arg --> no break */
-		/* non-zero arg means wait for all output data
-		 * to be sent (performed above) but don't send break.
-		 * This is used by the tcdrain() termios function.
-		 */
-		if (!arg)
-			return send_break(tty, 250);
-		return 0;
-	case TCSBRKP:	/* support for POSIX tcsendbreak() */
-		return send_break(tty, arg ? arg*100 : 250);
-
-	case TIOCMGET:
-		return tty_tiocmget(tty, file, p);
-	case TIOCMSET:
-	case TIOCMBIC:
-	case TIOCMBIS:
-		return tty_tiocmset(tty, file, cmd, p);
-	case TCFLSH:
-		switch (arg) {
-		case TCIFLUSH:
-		case TCIOFLUSH:
-		/* flush tty buffer and allow ldisc to process ioctl */
-			tty_buffer_flush(tty);
-			break;
-		}
-		break;
-	}
-	if (tty->ops->ioctl) {
-		retval = (tty->ops->ioctl)(tty, file, cmd, arg);
-		if (retval != -ENOIOCTLCMD)
-			return retval;
-	}
-	ld = tty_ldisc_ref_wait(tty);
-	retval = -EINVAL;
-	if (ld->ops->ioctl) {
-		retval = ld->ops->ioctl(tty, file, cmd, arg);
-		if (retval == -ENOIOCTLCMD)
-			retval = -EINVAL;
-	}
-	tty_ldisc_deref(ld);
-	return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-				unsigned long arg)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct tty_struct *tty = file_tty(file);
-	struct tty_ldisc *ld;
-	int retval = -ENOIOCTLCMD;
-
-	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-		return -EINVAL;
-
-	if (tty->ops->compat_ioctl) {
-		retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
-		if (retval != -ENOIOCTLCMD)
-			return retval;
-	}
-
-	ld = tty_ldisc_ref_wait(tty);
-	if (ld->ops->compat_ioctl)
-		retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
-	tty_ldisc_deref(ld);
-
-	return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" ---  the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key".  Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal.  But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context.  This can
- * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
-	tty_hangup(tty);
-#else
-	struct task_struct *g, *p;
-	struct pid *session;
-	int		i;
-	struct file	*filp;
-	struct fdtable *fdt;
-
-	if (!tty)
-		return;
-	session = tty->session;
-
-	tty_ldisc_flush(tty);
-
-	tty_driver_flush_buffer(tty);
-
-	read_lock(&tasklist_lock);
-	/* Kill the entire session */
-	do_each_pid_task(session, PIDTYPE_SID, p) {
-		printk(KERN_NOTICE "SAK: killed process %d"
-			" (%s): task_session(p)==tty->session\n",
-			task_pid_nr(p), p->comm);
-		send_sig(SIGKILL, p, 1);
-	} while_each_pid_task(session, PIDTYPE_SID, p);
-	/* Now kill any processes that happen to have the
-	 * tty open.
-	 */
-	do_each_thread(g, p) {
-		if (p->signal->tty == tty) {
-			printk(KERN_NOTICE "SAK: killed process %d"
-			    " (%s): task_session(p)==tty->session\n",
-			    task_pid_nr(p), p->comm);
-			send_sig(SIGKILL, p, 1);
-			continue;
-		}
-		task_lock(p);
-		if (p->files) {
-			/*
-			 * We don't take a ref to the file, so we must
-			 * hold ->file_lock instead.
-			 */
-			spin_lock(&p->files->file_lock);
-			fdt = files_fdtable(p->files);
-			for (i = 0; i < fdt->max_fds; i++) {
-				filp = fcheck_files(p->files, i);
-				if (!filp)
-					continue;
-				if (filp->f_op->read == tty_read &&
-				    file_tty(filp) == tty) {
-					printk(KERN_NOTICE "SAK: killed process %d"
-					    " (%s): fd#%d opened to the tty\n",
-					    task_pid_nr(p), p->comm, i);
-					force_sig(SIGKILL, p);
-					break;
-				}
-			}
-			spin_unlock(&p->files->file_lock);
-		}
-		task_unlock(p);
-	} while_each_thread(g, p);
-	read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
-	struct tty_struct *tty =
-		container_of(work, struct tty_struct, SAK_work);
-	__do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
-	if (!tty)
-		return;
-	schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-/**
- *	initialize_tty_struct
- *	@tty: tty to initialize
- *
- *	This subroutine initializes a tty structure that has been newly
- *	allocated.
- *
- *	Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
-		struct tty_driver *driver, int idx)
-{
-	memset(tty, 0, sizeof(struct tty_struct));
-	kref_init(&tty->kref);
-	tty->magic = TTY_MAGIC;
-	tty_ldisc_init(tty);
-	tty->session = NULL;
-	tty->pgrp = NULL;
-	tty->overrun_time = jiffies;
-	tty->buf.head = tty->buf.tail = NULL;
-	tty_buffer_init(tty);
-	mutex_init(&tty->termios_mutex);
-	mutex_init(&tty->ldisc_mutex);
-	init_waitqueue_head(&tty->write_wait);
-	init_waitqueue_head(&tty->read_wait);
-	INIT_WORK(&tty->hangup_work, do_tty_hangup);
-	mutex_init(&tty->atomic_read_lock);
-	mutex_init(&tty->atomic_write_lock);
-	mutex_init(&tty->output_lock);
-	mutex_init(&tty->echo_lock);
-	spin_lock_init(&tty->read_lock);
-	spin_lock_init(&tty->ctrl_lock);
-	INIT_LIST_HEAD(&tty->tty_files);
-	INIT_WORK(&tty->SAK_work, do_SAK_work);
-
-	tty->driver = driver;
-	tty->ops = driver->ops;
-	tty->index = idx;
-	tty_line_name(driver, idx, tty->name);
-}
-
-/**
- *	tty_put_char	-	write one character to a tty
- *	@tty: tty
- *	@ch: character
- *
- *	Write one byte to the tty using the provided put_char method
- *	if present. Returns the number of characters successfully output.
- *
- *	Note: the specific put_char operation in the driver layer may go
- *	away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	if (tty->ops->put_char)
-		return tty->ops->put_char(tty, ch);
-	return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- *	tty_register_device - register a tty device
- *	@driver: the tty driver that describes the tty device
- *	@index: the index in the tty driver for this tty device
- *	@device: a struct device that is associated with this tty device.
- *		This field is optional, if there is no known struct device
- *		for this tty device it can be set to NULL safely.
- *
- *	Returns a pointer to the struct device for this tty device
- *	(or ERR_PTR(-EFOO) on error).
- *
- *	This call is required to be made to register an individual tty device
- *	if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *	that bit is not set, this function should not be called by a tty
- *	driver.
- *
- *	Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
-				   struct device *device)
-{
-	char name[64];
-	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
-	if (index >= driver->num) {
-		printk(KERN_ERR "Attempt to register invalid tty line number "
-		       " (%d).\n", index);
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (driver->type == TTY_DRIVER_TYPE_PTY)
-		pty_line_name(driver, index, name);
-	else
-		tty_line_name(driver, index, name);
-
-	return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- * 	tty_unregister_device - unregister a tty device
- * 	@driver: the tty driver that describes the tty device
- * 	@index: the index in the tty driver for this tty device
- *
- * 	If a tty device is registered with a call to tty_register_device() then
- *	this function must be called when the tty device is gone.
- *
- *	Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
-	device_destroy(tty_class,
-		MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
-	struct tty_driver *driver;
-
-	driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-	if (driver) {
-		kref_init(&driver->kref);
-		driver->magic = TTY_DRIVER_MAGIC;
-		driver->num = lines;
-		/* later we'll move allocation of tables here */
-	}
-	return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
-	struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
-	int i;
-	struct ktermios *tp;
-	void *p;
-
-	if (driver->flags & TTY_DRIVER_INSTALLED) {
-		/*
-		 * Free the termios and termios_locked structures because
-		 * we don't want to get memory leaks when modular tty
-		 * drivers are removed from the kernel.
-		 */
-		for (i = 0; i < driver->num; i++) {
-			tp = driver->termios[i];
-			if (tp) {
-				driver->termios[i] = NULL;
-				kfree(tp);
-			}
-			if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-				tty_unregister_device(driver, i);
-		}
-		p = driver->ttys;
-		proc_tty_unregister_driver(driver);
-		driver->ttys = NULL;
-		driver->termios = NULL;
-		kfree(p);
-		cdev_del(&driver->cdev);
-	}
-	kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
-	kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
-			const struct tty_operations *op)
-{
-	driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
-	tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
-	int error;
-	int i;
-	dev_t dev;
-	void **p = NULL;
-
-	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-		p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-		if (!p)
-			return -ENOMEM;
-	}
-
-	if (!driver->major) {
-		error = alloc_chrdev_region(&dev, driver->minor_start,
-						driver->num, driver->name);
-		if (!error) {
-			driver->major = MAJOR(dev);
-			driver->minor_start = MINOR(dev);
-		}
-	} else {
-		dev = MKDEV(driver->major, driver->minor_start);
-		error = register_chrdev_region(dev, driver->num, driver->name);
-	}
-	if (error < 0) {
-		kfree(p);
-		return error;
-	}
-
-	if (p) {
-		driver->ttys = (struct tty_struct **)p;
-		driver->termios = (struct ktermios **)(p + driver->num);
-	} else {
-		driver->ttys = NULL;
-		driver->termios = NULL;
-	}
-
-	cdev_init(&driver->cdev, &tty_fops);
-	driver->cdev.owner = driver->owner;
-	error = cdev_add(&driver->cdev, dev, driver->num);
-	if (error) {
-		unregister_chrdev_region(dev, driver->num);
-		driver->ttys = NULL;
-		driver->termios = NULL;
-		kfree(p);
-		return error;
-	}
-
-	mutex_lock(&tty_mutex);
-	list_add(&driver->tty_drivers, &tty_drivers);
-	mutex_unlock(&tty_mutex);
-
-	if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-		for (i = 0; i < driver->num; i++)
-		    tty_register_device(driver, i, NULL);
-	}
-	proc_tty_register_driver(driver);
-	driver->flags |= TTY_DRIVER_INSTALLED;
-	return 0;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
-	/* FIXME */
-	if (driver->refcount)
-		return -EBUSY;
-#endif
-	unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
-				driver->num);
-	mutex_lock(&tty_mutex);
-	list_del(&driver->tty_drivers);
-	mutex_unlock(&tty_mutex);
-	return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
-	return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
-	unsigned long flags;
-	struct tty_struct *tty;
-	spin_lock_irqsave(&p->sighand->siglock, flags);
-	tty = p->signal->tty;
-	p->signal->tty = NULL;
-	spin_unlock_irqrestore(&p->sighand->siglock, flags);
-	tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-	if (tty) {
-		unsigned long flags;
-		/* We should not have a session or pgrp to put here but.... */
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		put_pid(tty->session);
-		put_pid(tty->pgrp);
-		tty->pgrp = get_pid(task_pgrp(tsk));
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		tty->session = get_pid(task_session(tsk));
-		if (tsk->signal->tty) {
-			printk(KERN_DEBUG "tty not NULL!!\n");
-			tty_kref_put(tsk->signal->tty);
-		}
-	}
-	put_pid(tsk->signal->tty_old_pgrp);
-	tsk->signal->tty = tty_kref_get(tty);
-	tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-	spin_lock_irq(&tsk->sighand->siglock);
-	__proc_set_tty(tsk, tty);
-	spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
-	struct tty_struct *tty;
-	unsigned long flags;
-
-	spin_lock_irqsave(&current->sighand->siglock, flags);
-	tty = tty_kref_get(current->signal->tty);
-	spin_unlock_irqrestore(&current->sighand->siglock, flags);
-	return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
-	*fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-	initcall_t *call;
-
-	/* Setup the default TTY line discipline. */
-	tty_ldisc_begin();
-
-	/*
-	 * set up the console device so that later boot sequences can
-	 * inform about problems etc..
-	 */
-	call = __con_initcall_start;
-	while (call < __con_initcall_end) {
-		(*call)();
-		call++;
-	}
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
-	if (!mode)
-		return NULL;
-	if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
-	    dev->devt == MKDEV(TTYAUX_MAJOR, 2))
-		*mode = 0666;
-	return NULL;
-}
-
-static int __init tty_class_init(void)
-{
-	tty_class = class_create(THIS_MODULE, "tty");
-	if (IS_ERR(tty_class))
-		return PTR_ERR(tty_class);
-	tty_class->devnode = tty_devnode;
-	return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
-	cdev_init(&tty_cdev, &tty_fops);
-	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
-		panic("Couldn't register /dev/tty driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-			      "tty");
-
-	cdev_init(&console_cdev, &console_fops);
-	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
-	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
-		panic("Couldn't register /dev/console driver\n");
-	device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
-			      "console");
-
-#ifdef CONFIG_VT
-	vty_init(&console_fops);
-#endif
-	return 0;
-}
-
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_ioctl.c linux-libre-2.6.37-gnu/drivers/char/tty_ioctl.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_ioctl.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1179 +0,0 @@
-/*
- *  linux/drivers/char/tty_ioctl.c
- *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- */
-
-#include <linux/types.h>
-#include <linux/termios.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/tty.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#undef TTY_DEBUG_WAIT_UNTIL_SENT
-
-#undef	DEBUG
-
-/*
- * Internal flag options for termios setting behavior
- */
-#define TERMIOS_FLUSH	1
-#define TERMIOS_WAIT	2
-#define TERMIOS_TERMIO	4
-#define TERMIOS_OLD	8
-
-
-/**
- *	tty_chars_in_buffer	-	characters pending
- *	@tty: terminal
- *
- *	Return the number of bytes of data in the device private
- *	output queue. If no private method is supplied there is assumed
- *	to be no queue on the device.
- */
-
-int tty_chars_in_buffer(struct tty_struct *tty)
-{
-	if (tty->ops->chars_in_buffer)
-		return tty->ops->chars_in_buffer(tty);
-	else
-		return 0;
-}
-EXPORT_SYMBOL(tty_chars_in_buffer);
-
-/**
- *	tty_write_room		-	write queue space
- *	@tty: terminal
- *
- *	Return the number of bytes that can be queued to this device
- *	at the present time. The result should be treated as a guarantee
- *	and the driver cannot offer a value it later shrinks by more than
- *	the number of bytes written. If no method is provided 2K is always
- *	returned and data may be lost as there will be no flow control.
- */
- 
-int tty_write_room(struct tty_struct *tty)
-{
-	if (tty->ops->write_room)
-		return tty->ops->write_room(tty);
-	return 2048;
-}
-EXPORT_SYMBOL(tty_write_room);
-
-/**
- *	tty_driver_flush_buffer	-	discard internal buffer
- *	@tty: terminal
- *
- *	Discard the internal output buffer for this device. If no method
- *	is provided then either the buffer cannot be hardware flushed or
- *	there is no buffer driver side.
- */
-void tty_driver_flush_buffer(struct tty_struct *tty)
-{
-	if (tty->ops->flush_buffer)
-		tty->ops->flush_buffer(tty);
-}
-EXPORT_SYMBOL(tty_driver_flush_buffer);
-
-/**
- *	tty_throttle		-	flow control
- *	@tty: terminal
- *
- *	Indicate that a tty should stop transmitting data down the stack.
- *	Takes the termios mutex to protect against parallel throttle/unthrottle
- *	and also to ensure the driver can consistently reference its own
- *	termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
-	mutex_lock(&tty->termios_mutex);
-	/* check TTY_THROTTLED first so it indicates our state */
-	if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
-	    tty->ops->throttle)
-		tty->ops->throttle(tty);
-	mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_throttle);
-
-/**
- *	tty_unthrottle		-	flow control
- *	@tty: terminal
- *
- *	Indicate that a tty may continue transmitting data down the stack.
- *	Takes the termios mutex to protect against parallel throttle/unthrottle
- *	and also to ensure the driver can consistently reference its own
- *	termios data at this point when implementing software flow control.
- *
- *	Drivers should however remember that the stack can issue a throttle,
- *	then change flow control method, then unthrottle.
- */
-
-void tty_unthrottle(struct tty_struct *tty)
-{
-	mutex_lock(&tty->termios_mutex);
-	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
-	    tty->ops->unthrottle)
-		tty->ops->unthrottle(tty);
-	mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_unthrottle);
-
-/**
- *	tty_wait_until_sent	-	wait for I/O to finish
- *	@tty: tty we are waiting for
- *	@timeout: how long we will wait
- *
- *	Wait for characters pending in a tty driver to hit the wire, or
- *	for a timeout to occur (eg due to flow control)
- *
- *	Locking: none
- */
-
-void tty_wait_until_sent(struct tty_struct *tty, long timeout)
-{
-#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
-	char buf[64];
-
-	printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
-#endif
-	if (!timeout)
-		timeout = MAX_SCHEDULE_TIMEOUT;
-	if (wait_event_interruptible_timeout(tty->write_wait,
-			!tty_chars_in_buffer(tty), timeout) >= 0) {
-		if (tty->ops->wait_until_sent)
-			tty->ops->wait_until_sent(tty, timeout);
-	}
-}
-EXPORT_SYMBOL(tty_wait_until_sent);
-
-
-/*
- *		Termios Helper Methods
- */
-
-static void unset_locked_termios(struct ktermios *termios,
-				 struct ktermios *old,
-				 struct ktermios *locked)
-{
-	int	i;
-
-#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
-
-	if (!locked) {
-		printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
-		return;
-	}
-
-	NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
-	NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
-	NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
-	NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
-	termios->c_line = locked->c_line ? old->c_line : termios->c_line;
-	for (i = 0; i < NCCS; i++)
-		termios->c_cc[i] = locked->c_cc[i] ?
-			old->c_cc[i] : termios->c_cc[i];
-	/* FIXME: What should we do for i/ospeed */
-}
-
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static const speed_t baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
-	76800, 153600, 307200, 614400, 921600
-#else
-	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
-	2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-#ifndef __sparc__
-static const tcflag_t baud_bits[] = {
-	B0, B50, B75, B110, B134, B150, B200, B300, B600,
-	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-	B57600, B115200, B230400, B460800, B500000, B576000,
-	B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
-	B3000000, B3500000, B4000000
-};
-#else
-static const tcflag_t baud_bits[] = {
-	B0, B50, B75, B110, B134, B150, B200, B300, B600,
-	B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-	B57600, B115200, B230400, B460800, B76800, B153600,
-	B307200, B614400, B921600
-};
-#endif
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- *	tty_termios_baud_rate
- *	@termios: termios structure
- *
- *	Convert termios baud rate data into a speed. This should be called
- *	with the termios lock held if this termios is a terminal termios
- *	structure. May change the termios data. Device drivers can call this
- *	function but should use ->c_[io]speed directly as they are updated.
- *
- *	Locking: none
- */
-
-speed_t tty_termios_baud_rate(struct ktermios *termios)
-{
-	unsigned int cbaud;
-
-	cbaud = termios->c_cflag & CBAUD;
-
-#ifdef BOTHER
-	/* Magic token for arbitary speed via c_ispeed/c_ospeed */
-	if (cbaud == BOTHER)
-		return termios->c_ospeed;
-#endif
-	if (cbaud & CBAUDEX) {
-		cbaud &= ~CBAUDEX;
-
-		if (cbaud < 1 || cbaud + 15 > n_baud_table)
-			termios->c_cflag &= ~CBAUDEX;
-		else
-			cbaud += 15;
-	}
-	return baud_table[cbaud];
-}
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- *	tty_termios_input_baud_rate
- *	@termios: termios structure
- *
- *	Convert termios baud rate data into a speed. This should be called
- *	with the termios lock held if this termios is a terminal termios
- *	structure. May change the termios data. Device drivers can call this
- *	function but should use ->c_[io]speed directly as they are updated.
- *
- *	Locking: none
- */
-
-speed_t tty_termios_input_baud_rate(struct ktermios *termios)
-{
-#ifdef IBSHIFT
-	unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
-
-	if (cbaud == B0)
-		return tty_termios_baud_rate(termios);
-
-	/* Magic token for arbitary speed via c_ispeed*/
-	if (cbaud == BOTHER)
-		return termios->c_ispeed;
-
-	if (cbaud & CBAUDEX) {
-		cbaud &= ~CBAUDEX;
-
-		if (cbaud < 1 || cbaud + 15 > n_baud_table)
-			termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
-		else
-			cbaud += 15;
-	}
-	return baud_table[cbaud];
-#else
-	return tty_termios_baud_rate(termios);
-#endif
-}
-EXPORT_SYMBOL(tty_termios_input_baud_rate);
-
-/**
- *	tty_termios_encode_baud_rate
- *	@termios: ktermios structure holding user requested state
- *	@ispeed: input speed
- *	@ospeed: output speed
- *
- *	Encode the speeds set into the passed termios structure. This is
- *	used as a library helper for drivers os that they can report back
- *	the actual speed selected when it differs from the speed requested
- *
- *	For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
- *	we need to carefully set the bits when the user does not get the
- *	desired speed. We allow small margins and preserve as much of possible
- *	of the input intent to keep compatibility.
- *
- *	Locking: Caller should hold termios lock. This is already held
- *	when calling this function from the driver termios handler.
- *
- *	The ifdefs deal with platforms whose owners have yet to update them
- *	and will all go away once this is done.
- */
-
-void tty_termios_encode_baud_rate(struct ktermios *termios,
-				  speed_t ibaud, speed_t obaud)
-{
-	int i = 0;
-	int ifound = -1, ofound = -1;
-	int iclose = ibaud/50, oclose = obaud/50;
-	int ibinput = 0;
-
-	if (obaud == 0)			/* CD dropped 		  */
-		ibaud = 0;		/* Clear ibaud to be sure */
-
-	termios->c_ispeed = ibaud;
-	termios->c_ospeed = obaud;
-
-#ifdef BOTHER
-	/* If the user asked for a precise weird speed give a precise weird
-	   answer. If they asked for a Bfoo speed they many have problems
-	   digesting non-exact replies so fuzz a bit */
-
-	if ((termios->c_cflag & CBAUD) == BOTHER)
-		oclose = 0;
-	if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
-		iclose = 0;
-	if ((termios->c_cflag >> IBSHIFT) & CBAUD)
-		ibinput = 1;	/* An input speed was specified */
-#endif
-	termios->c_cflag &= ~CBAUD;
-
-	/*
-	 *	Our goal is to find a close match to the standard baud rate
-	 *	returned. Walk the baud rate table and if we get a very close
-	 *	match then report back the speed as a POSIX Bxxxx value by
-	 *	preference
-	 */
-
-	do {
-		if (obaud - oclose <= baud_table[i] &&
-		    obaud + oclose >= baud_table[i]) {
-			termios->c_cflag |= baud_bits[i];
-			ofound = i;
-		}
-		if (ibaud - iclose <= baud_table[i] &&
-		    ibaud + iclose >= baud_table[i]) {
-			/* For the case input == output don't set IBAUD bits
-			   if the user didn't do so */
-			if (ofound == i && !ibinput)
-				ifound  = i;
-#ifdef IBSHIFT
-			else {
-				ifound = i;
-				termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-			}
-#endif
-		}
-	} while (++i < n_baud_table);
-
-	/*
-	 *	If we found no match then use BOTHER if provided or warn
-	 *	the user their platform maintainer needs to wake up if not.
-	 */
-#ifdef BOTHER
-	if (ofound == -1)
-		termios->c_cflag |= BOTHER;
-	/* Set exact input bits only if the input and output differ or the
-	   user already did */
-	if (ifound == -1 && (ibaud != obaud || ibinput))
-		termios->c_cflag |= (BOTHER << IBSHIFT);
-#else
-	if (ifound == -1 || ofound == -1) {
-		printk_once(KERN_WARNING "tty: Unable to return correct "
-			  "speed data as your architecture needs updating.\n");
-	}
-#endif
-}
-EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-
-/**
- *	tty_encode_baud_rate		-	set baud rate of the tty
- *	@ibaud: input baud rate
- *	@obad: output baud rate
- *
- *	Update the current termios data for the tty with the new speed
- *	settings. The caller must hold the termios_mutex for the tty in
- *	question.
- */
-
-void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
-{
-	tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
-}
-EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
-
-/**
- *	tty_get_baud_rate	-	get tty bit rates
- *	@tty: tty to query
- *
- *	Returns the baud rate as an integer for this terminal. The
- *	termios lock must be held by the caller and the terminal bit
- *	flags may be updated.
- *
- *	Locking: none
- */
-
-speed_t tty_get_baud_rate(struct tty_struct *tty)
-{
-	speed_t baud = tty_termios_baud_rate(tty->termios);
-
-	if (baud == 38400 && tty->alt_speed) {
-		if (!tty->warned) {
-			printk(KERN_WARNING "Use of setserial/setrocket to "
-					    "set SPD_* flags is deprecated\n");
-			tty->warned = 1;
-		}
-		baud = tty->alt_speed;
-	}
-
-	return baud;
-}
-EXPORT_SYMBOL(tty_get_baud_rate);
-
-/**
- *	tty_termios_copy_hw	-	copy hardware settings
- *	@new: New termios
- *	@old: Old termios
- *
- *	Propogate the hardware specific terminal setting bits from
- *	the old termios structure to the new one. This is used in cases
- *	where the hardware does not support reconfiguration or as a helper
- *	in some cases where only minimal reconfiguration is supported
- */
-
-void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
-{
-	/* The bits a dumb device handles in software. Smart devices need
-	   to always provide a set_termios method */
-	new->c_cflag &= HUPCL | CREAD | CLOCAL;
-	new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
-	new->c_ispeed = old->c_ispeed;
-	new->c_ospeed = old->c_ospeed;
-}
-EXPORT_SYMBOL(tty_termios_copy_hw);
-
-/**
- *	tty_termios_hw_change	-	check for setting change
- *	@a: termios
- *	@b: termios to compare
- *
- *	Check if any of the bits that affect a dumb device have changed
- *	between the two termios structures, or a speed change is needed.
- */
-
-int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
-{
-	if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
-		return 1;
-	if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
-		return 1;
-	return 0;
-}
-EXPORT_SYMBOL(tty_termios_hw_change);
-
-/**
- *	change_termios		-	update termios values
- *	@tty: tty to update
- *	@new_termios: desired new value
- *
- *	Perform updates to the termios values set on this terminal. There
- *	is a bit of layering violation here with n_tty in terms of the
- *	internal knowledge of this function.
- *
- *	Locking: termios_mutex
- */
-
-static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
-{
-	struct ktermios old_termios;
-	struct tty_ldisc *ld;
-	unsigned long flags;
-
-	/*
-	 *	Perform the actual termios internal changes under lock.
-	 */
-
-
-	/* FIXME: we need to decide on some locking/ordering semantics
-	   for the set_termios notification eventually */
-	mutex_lock(&tty->termios_mutex);
-	old_termios = *tty->termios;
-	*tty->termios = *new_termios;
-	unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-
-	/* See if packet mode change of state. */
-	if (tty->link && tty->link->packet) {
-		int extproc = (old_termios.c_lflag & EXTPROC) |
-				(tty->termios->c_lflag & EXTPROC);
-		int old_flow = ((old_termios.c_iflag & IXON) &&
-				(old_termios.c_cc[VSTOP] == '\023') &&
-				(old_termios.c_cc[VSTART] == '\021'));
-		int new_flow = (I_IXON(tty) &&
-				STOP_CHAR(tty) == '\023' &&
-				START_CHAR(tty) == '\021');
-		if ((old_flow != new_flow) || extproc) {
-			spin_lock_irqsave(&tty->ctrl_lock, flags);
-			if (old_flow != new_flow) {
-				tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
-				if (new_flow)
-					tty->ctrl_status |= TIOCPKT_DOSTOP;
-				else
-					tty->ctrl_status |= TIOCPKT_NOSTOP;
-			}
-			if (extproc)
-				tty->ctrl_status |= TIOCPKT_IOCTL;
-			spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-			wake_up_interruptible(&tty->link->read_wait);
-		}
-	}
-
-	if (tty->ops->set_termios)
-		(*tty->ops->set_termios)(tty, &old_termios);
-	else
-		tty_termios_copy_hw(tty->termios, &old_termios);
-
-	ld = tty_ldisc_ref(tty);
-	if (ld != NULL) {
-		if (ld->ops->set_termios)
-			(ld->ops->set_termios)(tty, &old_termios);
-		tty_ldisc_deref(ld);
-	}
-	mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *	set_termios		-	set termios values for a tty
- *	@tty: terminal device
- *	@arg: user data
- *	@opt: option information
- *
- *	Helper function to prepare termios data and run necessary other
- *	functions before using change_termios to do the actual changes.
- *
- *	Locking:
- *		Called functions take ldisc and termios_mutex locks
- */
-
-static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
-{
-	struct ktermios tmp_termios;
-	struct tty_ldisc *ld;
-	int retval = tty_check_change(tty);
-
-	if (retval)
-		return retval;
-
-	mutex_lock(&tty->termios_mutex);
-	memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
-	mutex_unlock(&tty->termios_mutex);
-
-	if (opt & TERMIOS_TERMIO) {
-		if (user_termio_to_kernel_termios(&tmp_termios,
-						(struct termio __user *)arg))
-			return -EFAULT;
-#ifdef TCGETS2
-	} else if (opt & TERMIOS_OLD) {
-		if (user_termios_to_kernel_termios_1(&tmp_termios,
-						(struct termios __user *)arg))
-			return -EFAULT;
-	} else {
-		if (user_termios_to_kernel_termios(&tmp_termios,
-						(struct termios2 __user *)arg))
-			return -EFAULT;
-	}
-#else
-	} else if (user_termios_to_kernel_termios(&tmp_termios,
-					(struct termios __user *)arg))
-		return -EFAULT;
-#endif
-
-	/* If old style Bfoo values are used then load c_ispeed/c_ospeed
-	 * with the real speed so its unconditionally usable */
-	tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
-	tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
-
-	ld = tty_ldisc_ref(tty);
-
-	if (ld != NULL) {
-		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		tty_ldisc_deref(ld);
-	}
-
-	if (opt & TERMIOS_WAIT) {
-		tty_wait_until_sent(tty, 0);
-		if (signal_pending(current))
-			return -EINTR;
-	}
-
-	change_termios(tty, &tmp_termios);
-
-	/* FIXME: Arguably if tmp_termios == tty->termios AND the
-	   actual requested termios was not tmp_termios then we may
-	   want to return an error as no user requested change has
-	   succeeded */
-	return 0;
-}
-
-static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
-{
-	mutex_lock(&tty->termios_mutex);
-	memcpy(kterm, tty->termios, sizeof(struct ktermios));
-	mutex_unlock(&tty->termios_mutex);
-}
-
-static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
-{
-	mutex_lock(&tty->termios_mutex);
-	memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
-	mutex_unlock(&tty->termios_mutex);
-}
-
-static int get_termio(struct tty_struct *tty, struct termio __user *termio)
-{
-	struct ktermios kterm;
-	copy_termios(tty, &kterm);
-	if (kernel_termios_to_user_termio(termio, &kterm))
-		return -EFAULT;
-	return 0;
-}
-
-
-#ifdef TCGETX
-
-/**
- *	set_termiox	-	set termiox fields if possible
- *	@tty: terminal
- *	@arg: termiox structure from user
- *	@opt: option flags for ioctl type
- *
- *	Implement the device calling points for the SYS5 termiox ioctl
- *	interface in Linux
- */
-
-static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
-{
-	struct termiox tnew;
-	struct tty_ldisc *ld;
-
-	if (tty->termiox == NULL)
-		return -EINVAL;
-	if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
-		return -EFAULT;
-
-	ld = tty_ldisc_ref(tty);
-	if (ld != NULL) {
-		if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		tty_ldisc_deref(ld);
-	}
-	if (opt & TERMIOS_WAIT) {
-		tty_wait_until_sent(tty, 0);
-		if (signal_pending(current))
-			return -EINTR;
-	}
-
-	mutex_lock(&tty->termios_mutex);
-	if (tty->ops->set_termiox)
-		tty->ops->set_termiox(tty, &tnew);
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-
-#endif
-
-
-#ifdef TIOCGETP
-/*
- * These are deprecated, but there is limited support..
- *
- * The "sg_flags" translation is a joke..
- */
-static int get_sgflags(struct tty_struct *tty)
-{
-	int flags = 0;
-
-	if (!(tty->termios->c_lflag & ICANON)) {
-		if (tty->termios->c_lflag & ISIG)
-			flags |= 0x02;		/* cbreak */
-		else
-			flags |= 0x20;		/* raw */
-	}
-	if (tty->termios->c_lflag & ECHO)
-		flags |= 0x08;			/* echo */
-	if (tty->termios->c_oflag & OPOST)
-		if (tty->termios->c_oflag & ONLCR)
-			flags |= 0x10;		/* crmod */
-	return flags;
-}
-
-static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-	struct sgttyb tmp;
-
-	mutex_lock(&tty->termios_mutex);
-	tmp.sg_ispeed = tty->termios->c_ispeed;
-	tmp.sg_ospeed = tty->termios->c_ospeed;
-	tmp.sg_erase = tty->termios->c_cc[VERASE];
-	tmp.sg_kill = tty->termios->c_cc[VKILL];
-	tmp.sg_flags = get_sgflags(tty);
-	mutex_unlock(&tty->termios_mutex);
-
-	return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static void set_sgflags(struct ktermios *termios, int flags)
-{
-	termios->c_iflag = ICRNL | IXON;
-	termios->c_oflag = 0;
-	termios->c_lflag = ISIG | ICANON;
-	if (flags & 0x02) {	/* cbreak */
-		termios->c_iflag = 0;
-		termios->c_lflag &= ~ICANON;
-	}
-	if (flags & 0x08) {		/* echo */
-		termios->c_lflag |= ECHO | ECHOE | ECHOK |
-				    ECHOCTL | ECHOKE | IEXTEN;
-	}
-	if (flags & 0x10) {		/* crmod */
-		termios->c_oflag |= OPOST | ONLCR;
-	}
-	if (flags & 0x20) {	/* raw */
-		termios->c_iflag = 0;
-		termios->c_lflag &= ~(ISIG | ICANON);
-	}
-	if (!(termios->c_lflag & ICANON)) {
-		termios->c_cc[VMIN] = 1;
-		termios->c_cc[VTIME] = 0;
-	}
-}
-
-/**
- *	set_sgttyb		-	set legacy terminal values
- *	@tty: tty structure
- *	@sgttyb: pointer to old style terminal structure
- *
- *	Updates a terminal from the legacy BSD style terminal information
- *	structure.
- *
- *	Locking: termios_mutex
- */
-
-static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-	int retval;
-	struct sgttyb tmp;
-	struct ktermios termios;
-
-	retval = tty_check_change(tty);
-	if (retval)
-		return retval;
-
-	if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
-		return -EFAULT;
-
-	mutex_lock(&tty->termios_mutex);
-	termios = *tty->termios;
-	termios.c_cc[VERASE] = tmp.sg_erase;
-	termios.c_cc[VKILL] = tmp.sg_kill;
-	set_sgflags(&termios, tmp.sg_flags);
-	/* Try and encode into Bfoo format */
-#ifdef BOTHER
-	tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
-						termios.c_ospeed);
-#endif
-	mutex_unlock(&tty->termios_mutex);
-	change_termios(tty, &termios);
-	return 0;
-}
-#endif
-
-#ifdef TIOCGETC
-static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-	struct tchars tmp;
-
-	mutex_lock(&tty->termios_mutex);
-	tmp.t_intrc = tty->termios->c_cc[VINTR];
-	tmp.t_quitc = tty->termios->c_cc[VQUIT];
-	tmp.t_startc = tty->termios->c_cc[VSTART];
-	tmp.t_stopc = tty->termios->c_cc[VSTOP];
-	tmp.t_eofc = tty->termios->c_cc[VEOF];
-	tmp.t_brkc = tty->termios->c_cc[VEOL2];	/* what is brkc anyway? */
-	mutex_unlock(&tty->termios_mutex);
-	return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-	struct tchars tmp;
-
-	if (copy_from_user(&tmp, tchars, sizeof(tmp)))
-		return -EFAULT;
-	mutex_lock(&tty->termios_mutex);
-	tty->termios->c_cc[VINTR] = tmp.t_intrc;
-	tty->termios->c_cc[VQUIT] = tmp.t_quitc;
-	tty->termios->c_cc[VSTART] = tmp.t_startc;
-	tty->termios->c_cc[VSTOP] = tmp.t_stopc;
-	tty->termios->c_cc[VEOF] = tmp.t_eofc;
-	tty->termios->c_cc[VEOL2] = tmp.t_brkc;	/* what is brkc anyway? */
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-#endif
-
-#ifdef TIOCGLTC
-static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-	struct ltchars tmp;
-
-	mutex_lock(&tty->termios_mutex);
-	tmp.t_suspc = tty->termios->c_cc[VSUSP];
-	/* what is dsuspc anyway? */
-	tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
-	tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
-	/* what is flushc anyway? */
-	tmp.t_flushc = tty->termios->c_cc[VEOL2];
-	tmp.t_werasc = tty->termios->c_cc[VWERASE];
-	tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
-	mutex_unlock(&tty->termios_mutex);
-	return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-	struct ltchars tmp;
-
-	if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
-		return -EFAULT;
-
-	mutex_lock(&tty->termios_mutex);
-	tty->termios->c_cc[VSUSP] = tmp.t_suspc;
-	/* what is dsuspc anyway? */
-	tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
-	tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
-	/* what is flushc anyway? */
-	tty->termios->c_cc[VEOL2] = tmp.t_flushc;
-	tty->termios->c_cc[VWERASE] = tmp.t_werasc;
-	tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
-	mutex_unlock(&tty->termios_mutex);
-	return 0;
-}
-#endif
-
-/**
- *	send_prio_char		-	send priority character
- *
- *	Send a high priority character to the tty even if stopped
- *
- *	Locking: none for xchar method, write ordering for write method.
- */
-
-static int send_prio_char(struct tty_struct *tty, char ch)
-{
-	int	was_stopped = tty->stopped;
-
-	if (tty->ops->send_xchar) {
-		tty->ops->send_xchar(tty, ch);
-		return 0;
-	}
-
-	if (tty_write_lock(tty, 0) < 0)
-		return -ERESTARTSYS;
-
-	if (was_stopped)
-		start_tty(tty);
-	tty->ops->write(tty, &ch, 1);
-	if (was_stopped)
-		stop_tty(tty);
-	tty_write_unlock(tty);
-	return 0;
-}
-
-/**
- *	tty_change_softcar	-	carrier change ioctl helper
- *	@tty: tty to update
- *	@arg: enable/disable CLOCAL
- *
- *	Perform a change to the CLOCAL state and call into the driver
- *	layer to make it visible. All done with the termios mutex
- */
-
-static int tty_change_softcar(struct tty_struct *tty, int arg)
-{
-	int ret = 0;
-	int bit = arg ? CLOCAL : 0;
-	struct ktermios old;
-
-	mutex_lock(&tty->termios_mutex);
-	old = *tty->termios;
-	tty->termios->c_cflag &= ~CLOCAL;
-	tty->termios->c_cflag |= bit;
-	if (tty->ops->set_termios)
-		tty->ops->set_termios(tty, &old);
-	if ((tty->termios->c_cflag & CLOCAL) != bit)
-		ret = -EINVAL;
-	mutex_unlock(&tty->termios_mutex);
-	return ret;
-}
-
-/**
- *	tty_mode_ioctl		-	mode related ioctls
- *	@tty: tty for the ioctl
- *	@file: file pointer for the tty
- *	@cmd: command
- *	@arg: ioctl argument
- *
- *	Perform non line discipline specific mode control ioctls. This
- *	is designed to be called by line disciplines to ensure they provide
- *	consistent mode setting.
- */
-
-int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	struct tty_struct *real_tty;
-	void __user *p = (void __user *)arg;
-	int ret = 0;
-	struct ktermios kterm;
-
-	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-	    tty->driver->subtype == PTY_TYPE_MASTER)
-		real_tty = tty->link;
-	else
-		real_tty = tty;
-
-	switch (cmd) {
-#ifdef TIOCGETP
-	case TIOCGETP:
-		return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
-	case TIOCSETP:
-	case TIOCSETN:
-		return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
-#endif
-#ifdef TIOCGETC
-	case TIOCGETC:
-		return get_tchars(real_tty, p);
-	case TIOCSETC:
-		return set_tchars(real_tty, p);
-#endif
-#ifdef TIOCGLTC
-	case TIOCGLTC:
-		return get_ltchars(real_tty, p);
-	case TIOCSLTC:
-		return set_ltchars(real_tty, p);
-#endif
-	case TCSETSF:
-		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
-	case TCSETSW:
-		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
-	case TCSETS:
-		return set_termios(real_tty, p, TERMIOS_OLD);
-#ifndef TCGETS2
-	case TCGETS:
-		copy_termios(real_tty, &kterm);
-		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-			ret = -EFAULT;
-		return ret;
-#else
-	case TCGETS:
-		copy_termios(real_tty, &kterm);
-		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-			ret = -EFAULT;
-		return ret;
-	case TCGETS2:
-		copy_termios(real_tty, &kterm);
-		if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
-			ret = -EFAULT;
-		return ret;
-	case TCSETSF2:
-		return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
-	case TCSETSW2:
-		return set_termios(real_tty, p, TERMIOS_WAIT);
-	case TCSETS2:
-		return set_termios(real_tty, p, 0);
-#endif
-	case TCGETA:
-		return get_termio(real_tty, p);
-	case TCSETAF:
-		return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
-	case TCSETAW:
-		return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
-	case TCSETA:
-		return set_termios(real_tty, p, TERMIOS_TERMIO);
-#ifndef TCGETS2
-	case TIOCGLCKTRMIOS:
-		copy_termios_locked(real_tty, &kterm);
-		if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-			ret = -EFAULT;
-		return ret;
-	case TIOCSLCKTRMIOS:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		copy_termios_locked(real_tty, &kterm);
-		if (user_termios_to_kernel_termios(&kterm,
-					       (struct termios __user *) arg))
-			return -EFAULT;
-		mutex_lock(&real_tty->termios_mutex);
-		memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-		mutex_unlock(&real_tty->termios_mutex);
-		return 0;
-#else
-	case TIOCGLCKTRMIOS:
-		copy_termios_locked(real_tty, &kterm);
-		if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-			ret = -EFAULT;
-		return ret;
-	case TIOCSLCKTRMIOS:
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		copy_termios_locked(real_tty, &kterm);
-		if (user_termios_to_kernel_termios_1(&kterm,
-					       (struct termios __user *) arg))
-			return -EFAULT;
-		mutex_lock(&real_tty->termios_mutex);
-		memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-		mutex_unlock(&real_tty->termios_mutex);
-		return ret;
-#endif
-#ifdef TCGETX
-	case TCGETX: {
-		struct termiox ktermx;
-		if (real_tty->termiox == NULL)
-			return -EINVAL;
-		mutex_lock(&real_tty->termios_mutex);
-		memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
-		mutex_unlock(&real_tty->termios_mutex);
-		if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
-			ret = -EFAULT;
-		return ret;
-	}
-	case TCSETX:
-		return set_termiox(real_tty, p, 0);
-	case TCSETXW:
-		return set_termiox(real_tty, p, TERMIOS_WAIT);
-	case TCSETXF:
-		return set_termiox(real_tty, p, TERMIOS_FLUSH);
-#endif		
-	case TIOCGSOFTCAR:
-		copy_termios(real_tty, &kterm);
-		ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
-						(int __user *)arg);
-		return ret;
-	case TIOCSSOFTCAR:
-		if (get_user(arg, (unsigned int __user *) arg))
-			return -EFAULT;
-		return tty_change_softcar(real_tty, arg);
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-EXPORT_SYMBOL_GPL(tty_mode_ioctl);
-
-int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
-{
-	struct tty_ldisc *ld;
-	int retval = tty_check_change(tty);
-	if (retval)
-		return retval;
-
-	ld = tty_ldisc_ref_wait(tty);
-	switch (arg) {
-	case TCIFLUSH:
-		if (ld && ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		break;
-	case TCIOFLUSH:
-		if (ld && ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		/* fall through */
-	case TCOFLUSH:
-		tty_driver_flush_buffer(tty);
-		break;
-	default:
-		tty_ldisc_deref(ld);
-		return -EINVAL;
-	}
-	tty_ldisc_deref(ld);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(tty_perform_flush);
-
-int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	int retval;
-
-	switch (cmd) {
-	case TCXONC:
-		retval = tty_check_change(tty);
-		if (retval)
-			return retval;
-		switch (arg) {
-		case TCOOFF:
-			if (!tty->flow_stopped) {
-				tty->flow_stopped = 1;
-				stop_tty(tty);
-			}
-			break;
-		case TCOON:
-			if (tty->flow_stopped) {
-				tty->flow_stopped = 0;
-				start_tty(tty);
-			}
-			break;
-		case TCIOFF:
-			if (STOP_CHAR(tty) != __DISABLED_CHAR)
-				return send_prio_char(tty, STOP_CHAR(tty));
-			break;
-		case TCION:
-			if (START_CHAR(tty) != __DISABLED_CHAR)
-				return send_prio_char(tty, START_CHAR(tty));
-			break;
-		default:
-			return -EINVAL;
-		}
-		return 0;
-	case TCFLSH:
-		return tty_perform_flush(tty, arg);
-	case TIOCPKT:
-	{
-		int pktmode;
-
-		if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
-		    tty->driver->subtype != PTY_TYPE_MASTER)
-			return -ENOTTY;
-		if (get_user(pktmode, (int __user *) arg))
-			return -EFAULT;
-		spin_lock_irqsave(&tty->ctrl_lock, flags);
-		if (pktmode) {
-			if (!tty->packet) {
-				tty->packet = 1;
-				tty->link->ctrl_status = 0;
-			}
-		} else
-			tty->packet = 0;
-		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-		return 0;
-	}
-	default:
-		/* Try the mode commands */
-		return tty_mode_ioctl(tty, file, cmd, arg);
-	}
-}
-EXPORT_SYMBOL(n_tty_ioctl_helper);
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_ldisc.c linux-libre-2.6.37-gnu/drivers/char/tty_ldisc.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_ldisc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_ldisc.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,915 +0,0 @@
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/smp_lock.h>	/* For the moment */
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-/*
- *	This guards the refcounted line discipline lists. The lock
- *	must be taken with irqs off because there are hangup path
- *	callers who will do ldisc lookups and cannot sleep.
- */
-
-static DEFINE_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-/* Line disc dispatch table */
-static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-
-static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
-{
-	if (ld)
-		atomic_inc(&ld->users);
-	return ld;
-}
-
-static void put_ldisc(struct tty_ldisc *ld)
-{
-	unsigned long flags;
-
-	if (WARN_ON_ONCE(!ld))
-		return;
-
-	/*
-	 * If this is the last user, free the ldisc, and
-	 * release the ldisc ops.
-	 *
-	 * We really want an "atomic_dec_and_lock_irqsave()",
-	 * but we don't have it, so this does it by hand.
-	 */
-	local_irq_save(flags);
-	if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
-		struct tty_ldisc_ops *ldo = ld->ops;
-
-		ldo->refcount--;
-		module_put(ldo->owner);
-		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-		kfree(ld);
-		return;
-	}
-	local_irq_restore(flags);
-}
-
-/**
- *	tty_register_ldisc	-	install a line discipline
- *	@disc: ldisc number
- *	@new_ldisc: pointer to the ldisc object
- *
- *	Installs a new line discipline into the kernel. The discipline
- *	is set up as unreferenced and then made available to the kernel
- *	from this point onwards.
- *
- *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	if (disc < N_TTY || disc >= NR_LDISCS)
-		return -EINVAL;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	tty_ldiscs[disc] = new_ldisc;
-	new_ldisc->num = disc;
-	new_ldisc->refcount = 0;
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/**
- *	tty_unregister_ldisc	-	unload a line discipline
- *	@disc: ldisc number
- *	@new_ldisc: pointer to the ldisc object
- *
- *	Remove a line discipline from the kernel providing it is not
- *	currently in use.
- *
- *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_unregister_ldisc(int disc)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	if (disc < N_TTY || disc >= NR_LDISCS)
-		return -EINVAL;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	if (tty_ldiscs[disc]->refcount)
-		ret = -EBUSY;
-	else
-		tty_ldiscs[disc] = NULL;
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-	return ret;
-}
-EXPORT_SYMBOL(tty_unregister_ldisc);
-
-static struct tty_ldisc_ops *get_ldops(int disc)
-{
-	unsigned long flags;
-	struct tty_ldisc_ops *ldops, *ret;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	ret = ERR_PTR(-EINVAL);
-	ldops = tty_ldiscs[disc];
-	if (ldops) {
-		ret = ERR_PTR(-EAGAIN);
-		if (try_module_get(ldops->owner)) {
-			ldops->refcount++;
-			ret = ldops;
-		}
-	}
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-	return ret;
-}
-
-static void put_ldops(struct tty_ldisc_ops *ldops)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	ldops->refcount--;
-	module_put(ldops->owner);
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-/**
- *	tty_ldisc_get		-	take a reference to an ldisc
- *	@disc: ldisc number
- *
- *	Takes a reference to a line discipline. Deals with refcounts and
- *	module locking counts. Returns NULL if the discipline is not available.
- *	Returns a pointer to the discipline and bumps the ref count if it is
- *	available
- *
- *	Locking:
- *		takes tty_ldisc_lock to guard against ldisc races
- */
-
-static struct tty_ldisc *tty_ldisc_get(int disc)
-{
-	struct tty_ldisc *ld;
-	struct tty_ldisc_ops *ldops;
-
-	if (disc < N_TTY || disc >= NR_LDISCS)
-		return ERR_PTR(-EINVAL);
-
-	/*
-	 * Get the ldisc ops - we may need to request them to be loaded
-	 * dynamically and try again.
-	 */
-	ldops = get_ldops(disc);
-	if (IS_ERR(ldops)) {
-		request_module("tty-ldisc-%d", disc);
-		ldops = get_ldops(disc);
-		if (IS_ERR(ldops))
-			return ERR_CAST(ldops);
-	}
-
-	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-	if (ld == NULL) {
-		put_ldops(ldops);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	ld->ops = ldops;
-	atomic_set(&ld->users, 1);
-	return ld;
-}
-
-static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-	return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	(*pos)++;
-	return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-	int i = *(loff_t *)v;
-	struct tty_ldisc_ops *ldops;
-
-	ldops = get_ldops(i);
-	if (IS_ERR(ldops))
-		return 0;
-	seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
-	put_ldops(ldops);
-	return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-	.start	= tty_ldiscs_seq_start,
-	.next	= tty_ldiscs_seq_next,
-	.stop	= tty_ldiscs_seq_stop,
-	.show	= tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-	return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-const struct file_operations tty_ldiscs_proc_fops = {
-	.owner		= THIS_MODULE,
-	.open		= proc_tty_ldiscs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= seq_release,
-};
-
-/**
- *	tty_ldisc_assign	-	set ldisc on a tty
- *	@tty: tty to assign
- *	@ld: line discipline
- *
- *	Install an instance of a line discipline into a tty structure. The
- *	ldisc must have a reference count above zero to ensure it remains.
- *	The tty instance refcount starts at zero.
- *
- *	Locking:
- *		Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-	tty->ldisc = ld;
-}
-
-/**
- *	tty_ldisc_try		-	internal helper
- *	@tty: the tty
- *
- *	Make a single attempt to grab and bump the refcount on
- *	the tty ldisc. Return 0 on failure or 1 on success. This is
- *	used to implement both the waiting and non waiting versions
- *	of tty_ldisc_ref
- *
- *	Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
-	unsigned long flags;
-	struct tty_ldisc *ld;
-
-	spin_lock_irqsave(&tty_ldisc_lock, flags);
-	ld = NULL;
-	if (test_bit(TTY_LDISC, &tty->flags))
-		ld = get_ldisc(tty->ldisc);
-	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-	return ld;
-}
-
-/**
- *	tty_ldisc_ref_wait	-	wait for the tty ldisc
- *	@tty: tty device
- *
- *	Dereference the line discipline for the terminal and take a
- *	reference to it. If the line discipline is in flux then
- *	wait patiently until it changes.
- *
- *	Note: Must not be called from an IRQ/timer context. The caller
- *	must also be careful not to hold other locks that will deadlock
- *	against a discipline change, such as an existing ldisc reference
- *	(which we check for)
- *
- *	Locking: call functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld;
-
-	/* wait_event is a macro */
-	wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
-	return ld;
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
-
-/**
- *	tty_ldisc_ref		-	get the tty ldisc
- *	@tty: tty device
- *
- *	Dereference the line discipline for the terminal and take a
- *	reference to it. If the line discipline is in flux then
- *	return NULL. Can be called from IRQ and timer functions.
- *
- *	Locking: called functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
-{
-	return tty_ldisc_try(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref);
-
-/**
- *	tty_ldisc_deref		-	free a tty ldisc reference
- *	@ld: reference to free up
- *
- *	Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
- *	be called in IRQ context.
- *
- *	Locking: takes tty_ldisc_lock
- */
-
-void tty_ldisc_deref(struct tty_ldisc *ld)
-{
-	put_ldisc(ld);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
-{
-	put_ldisc(ld);
-}
-
-/**
- *	tty_ldisc_enable	-	allow ldisc use
- *	@tty: terminal to activate ldisc on
- *
- *	Set the TTY_LDISC flag when the line discipline can be called
- *	again. Do necessary wakeups for existing sleepers. Clear the LDISC
- *	changing flag to indicate any ldisc change is now over.
- *
- *	Note: nobody should set the TTY_LDISC bit except via this function.
- *	Clearing directly is allowed.
- */
-
-void tty_ldisc_enable(struct tty_struct *tty)
-{
-	set_bit(TTY_LDISC, &tty->flags);
-	clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-	wake_up(&tty_ldisc_wait);
-}
-
-/**
- *	tty_ldisc_flush	-	flush line discipline queue
- *	@tty: tty
- *
- *	Flush the line discipline queue (if any) for this tty. If there
- *	is no line discipline active this is a no-op.
- */
-
-void tty_ldisc_flush(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld = tty_ldisc_ref(tty);
-	if (ld) {
-		if (ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		tty_ldisc_deref(ld);
-	}
-	tty_buffer_flush(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-
-/**
- *	tty_set_termios_ldisc		-	set ldisc field
- *	@tty: tty structure
- *	@num: line discipline number
- *
- *	This is probably overkill for real world processors but
- *	they are not on hot paths so a little discipline won't do
- *	any harm.
- *
- *	Locking: takes termios_mutex
- */
-
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
-{
-	mutex_lock(&tty->termios_mutex);
-	tty->termios->c_line = num;
-	mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *	tty_ldisc_open		-	open a line discipline
- *	@tty: tty we are opening the ldisc on
- *	@ld: discipline to open
- *
- *	A helper opening method. Also a convenient debugging and check
- *	point.
- *
- *	Locking: always called with BTM already held.
- */
-
-static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-	WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
-	if (ld->ops->open) {
-		int ret;
-                /* BTM here locks versus a hangup event */
-		WARN_ON(!tty_locked());
-		ret = ld->ops->open(tty);
-		return ret;
-	}
-	return 0;
-}
-
-/**
- *	tty_ldisc_close		-	close a line discipline
- *	@tty: tty we are opening the ldisc on
- *	@ld: discipline to close
- *
- *	A helper close method. Also a convenient debugging and check
- *	point.
- */
-
-static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-	WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
-	clear_bit(TTY_LDISC_OPEN, &tty->flags);
-	if (ld->ops->close)
-		ld->ops->close(tty);
-}
-
-/**
- *	tty_ldisc_restore	-	helper for tty ldisc change
- *	@tty: tty to recover
- *	@old: previous ldisc
- *
- *	Restore the previous line discipline or N_TTY when a line discipline
- *	change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
-	char buf[64];
-	struct tty_ldisc *new_ldisc;
-	int r;
-
-	/* There is an outstanding reference here so this is safe */
-	old = tty_ldisc_get(old->ops->num);
-	WARN_ON(IS_ERR(old));
-	tty_ldisc_assign(tty, old);
-	tty_set_termios_ldisc(tty, old->ops->num);
-	if (tty_ldisc_open(tty, old) < 0) {
-		tty_ldisc_put(old);
-		/* This driver is always present */
-		new_ldisc = tty_ldisc_get(N_TTY);
-		if (IS_ERR(new_ldisc))
-			panic("n_tty: get");
-		tty_ldisc_assign(tty, new_ldisc);
-		tty_set_termios_ldisc(tty, N_TTY);
-		r = tty_ldisc_open(tty, new_ldisc);
-		if (r < 0)
-			panic("Couldn't open N_TTY ldisc for "
-			      "%s --- error %d.",
-			      tty_name(tty, buf), r);
-	}
-}
-
-/**
- *	tty_ldisc_halt		-	shut down the line discipline
- *	@tty: tty device
- *
- *	Shut down the line discipline and work queue for this tty device.
- *	The TTY_LDISC flag being cleared ensures no further references can
- *	be obtained while the delayed work queue halt ensures that no more
- *	data is fed to the ldisc.
- *
- *	You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- *	in order to make sure any currently executing ldisc work is also
- *	flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty)
-{
-	clear_bit(TTY_LDISC, &tty->flags);
-	return cancel_delayed_work_sync(&tty->buf.work);
-}
-
-/**
- *	tty_set_ldisc		-	set line discipline
- *	@tty: the terminal to set
- *	@ldisc: the line discipline
- *
- *	Set the discipline of a tty line. Must be called from a process
- *	context. The ldisc change logic has to protect itself against any
- *	overlapping ldisc change (including on the other end of pty pairs),
- *	the close of one side of a tty/pty pair, and eventually hangup.
- *
- *	Locking: takes tty_ldisc_lock, termios_mutex
- */
-
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
-	int retval;
-	struct tty_ldisc *o_ldisc, *new_ldisc;
-	int work, o_work = 0;
-	struct tty_struct *o_tty;
-
-	new_ldisc = tty_ldisc_get(ldisc);
-	if (IS_ERR(new_ldisc))
-		return PTR_ERR(new_ldisc);
-
-	tty_lock();
-	/*
-	 *	We need to look at the tty locking here for pty/tty pairs
-	 *	when both sides try to change in parallel.
-	 */
-
-	o_tty = tty->link;	/* o_tty is the pty side or NULL */
-
-
-	/*
-	 *	Check the no-op case
-	 */
-
-	if (tty->ldisc->ops->num == ldisc) {
-		tty_unlock();
-		tty_ldisc_put(new_ldisc);
-		return 0;
-	}
-
-	tty_unlock();
-	/*
-	 *	Problem: What do we do if this blocks ?
-	 *	We could deadlock here
-	 */
-
-	tty_wait_until_sent(tty, 0);
-
-	tty_lock();
-	mutex_lock(&tty->ldisc_mutex);
-
-	/*
-	 *	We could be midstream of another ldisc change which has
-	 *	dropped the lock during processing. If so we need to wait.
-	 */
-
-	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-		mutex_unlock(&tty->ldisc_mutex);
-		tty_unlock();
-		wait_event(tty_ldisc_wait,
-			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-		tty_lock();
-		mutex_lock(&tty->ldisc_mutex);
-	}
-
-	set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
-	/*
-	 *	No more input please, we are switching. The new ldisc
-	 *	will update this value in the ldisc open function
-	 */
-
-	tty->receive_room = 0;
-
-	o_ldisc = tty->ldisc;
-
-	tty_unlock();
-	/*
-	 *	Make sure we don't change while someone holds a
-	 *	reference to the line discipline. The TTY_LDISC bit
-	 *	prevents anyone taking a reference once it is clear.
-	 *	We need the lock to avoid racing reference takers.
-	 *
-	 *	We must clear the TTY_LDISC bit here to avoid a livelock
-	 *	with a userspace app continually trying to use the tty in
-	 *	parallel to the change and re-referencing the tty.
-	 */
-
-	work = tty_ldisc_halt(tty);
-	if (o_tty)
-		o_work = tty_ldisc_halt(o_tty);
-
-	/*
-	 * Wait for ->hangup_work and ->buf.work handlers to terminate.
-	 * We must drop the mutex here in case a hangup is also in process.
-	 */
-
-	mutex_unlock(&tty->ldisc_mutex);
-
-	flush_scheduled_work();
-
-	tty_lock();
-	mutex_lock(&tty->ldisc_mutex);
-	if (test_bit(TTY_HUPPED, &tty->flags)) {
-		/* We were raced by the hangup method. It will have stomped
-		   the ldisc data and closed the ldisc down */
-		clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-		mutex_unlock(&tty->ldisc_mutex);
-		tty_ldisc_put(new_ldisc);
-		tty_unlock();
-		return -EIO;
-	}
-
-	/* Shutdown the current discipline. */
-	tty_ldisc_close(tty, o_ldisc);
-
-	/* Now set up the new line discipline. */
-	tty_ldisc_assign(tty, new_ldisc);
-	tty_set_termios_ldisc(tty, ldisc);
-
-	retval = tty_ldisc_open(tty, new_ldisc);
-	if (retval < 0) {
-		/* Back to the old one or N_TTY if we can't */
-		tty_ldisc_put(new_ldisc);
-		tty_ldisc_restore(tty, o_ldisc);
-	}
-
-	/* At this point we hold a reference to the new ldisc and a
-	   a reference to the old ldisc. If we ended up flipping back
-	   to the existing ldisc we have two references to it */
-
-	if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
-		tty->ops->set_ldisc(tty);
-
-	tty_ldisc_put(o_ldisc);
-
-	/*
-	 *	Allow ldisc referencing to occur again
-	 */
-
-	tty_ldisc_enable(tty);
-	if (o_tty)
-		tty_ldisc_enable(o_tty);
-
-	/* Restart the work queue in case no characters kick it off. Safe if
-	   already running */
-	if (work)
-		schedule_delayed_work(&tty->buf.work, 1);
-	if (o_work)
-		schedule_delayed_work(&o_tty->buf.work, 1);
-	mutex_unlock(&tty->ldisc_mutex);
-	tty_unlock();
-	return retval;
-}
-
-/**
- *	tty_reset_termios	-	reset terminal state
- *	@tty: tty to reset
- *
- *	Restore a terminal to the driver default state.
- */
-
-static void tty_reset_termios(struct tty_struct *tty)
-{
-	mutex_lock(&tty->termios_mutex);
-	*tty->termios = tty->driver->init_termios;
-	tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-	tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-	mutex_unlock(&tty->termios_mutex);
-}
-
-
-/**
- *	tty_ldisc_reinit	-	reinitialise the tty ldisc
- *	@tty: tty to reinit
- *	@ldisc: line discipline to reinitialize
- *
- *	Switch the tty to a line discipline and leave the ldisc
- *	state closed
- */
-
-static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
-{
-	struct tty_ldisc *ld;
-
-	tty_ldisc_close(tty, tty->ldisc);
-	tty_ldisc_put(tty->ldisc);
-	tty->ldisc = NULL;
-	/*
-	 *	Switch the line discipline back
-	 */
-	ld = tty_ldisc_get(ldisc);
-	BUG_ON(IS_ERR(ld));
-	tty_ldisc_assign(tty, ld);
-	tty_set_termios_ldisc(tty, ldisc);
-}
-
-/**
- *	tty_ldisc_hangup		-	hangup ldisc reset
- *	@tty: tty being hung up
- *
- *	Some tty devices reset their termios when they receive a hangup
- *	event. In that situation we must also switch back to N_TTY properly
- *	before we reset the termios data.
- *
- *	Locking: We can take the ldisc mutex as the rest of the code is
- *	careful to allow for this.
- *
- *	In the pty pair case this occurs in the close() path of the
- *	tty itself so we must be careful about locking rules.
- */
-
-void tty_ldisc_hangup(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld;
-	int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
-	int err = 0;
-
-	/*
-	 * FIXME! What are the locking issues here? This may me overdoing
-	 * things... This question is especially important now that we've
-	 * removed the irqlock.
-	 */
-	ld = tty_ldisc_ref(tty);
-	if (ld != NULL) {
-		/* We may have no line discipline at this point */
-		if (ld->ops->flush_buffer)
-			ld->ops->flush_buffer(tty);
-		tty_driver_flush_buffer(tty);
-		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-		    ld->ops->write_wakeup)
-			ld->ops->write_wakeup(tty);
-		if (ld->ops->hangup)
-			ld->ops->hangup(tty);
-		tty_ldisc_deref(ld);
-	}
-	/*
-	 * FIXME: Once we trust the LDISC code better we can wait here for
-	 * ldisc completion and fix the driver call race
-	 */
-	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-	wake_up_interruptible_poll(&tty->read_wait, POLLIN);
-	/*
-	 * Shutdown the current line discipline, and reset it to
-	 * N_TTY if need be.
-	 *
-	 * Avoid racing set_ldisc or tty_ldisc_release
-	 */
-	mutex_lock(&tty->ldisc_mutex);
-
-	/*
-	 * this is like tty_ldisc_halt, but we need to give up
-	 * the BTM before calling cancel_delayed_work_sync,
-	 * which may need to wait for another function taking the BTM
-	 */
-	clear_bit(TTY_LDISC, &tty->flags);
-	tty_unlock();
-	cancel_delayed_work_sync(&tty->buf.work);
-	mutex_unlock(&tty->ldisc_mutex);
-
-	tty_lock();
-	mutex_lock(&tty->ldisc_mutex);
-
-	/* At this point we have a closed ldisc and we want to
-	   reopen it. We could defer this to the next open but
-	   it means auditing a lot of other paths so this is
-	   a FIXME */
-	if (tty->ldisc) {	/* Not yet closed */
-		if (reset == 0) {
-			tty_ldisc_reinit(tty, tty->termios->c_line);
-			err = tty_ldisc_open(tty, tty->ldisc);
-		}
-		/* If the re-open fails or we reset then go to N_TTY. The
-		   N_TTY open cannot fail */
-		if (reset || err) {
-			tty_ldisc_reinit(tty, N_TTY);
-			WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-		}
-		tty_ldisc_enable(tty);
-	}
-	mutex_unlock(&tty->ldisc_mutex);
-	if (reset)
-		tty_reset_termios(tty);
-}
-
-/**
- *	tty_ldisc_setup			-	open line discipline
- *	@tty: tty being shut down
- *	@o_tty: pair tty for pty/tty pairs
- *
- *	Called during the initial open of a tty/pty pair in order to set up the
- *	line disciplines and bind them to the tty. This has no locking issues
- *	as the device isn't yet active.
- */
-
-int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-	struct tty_ldisc *ld = tty->ldisc;
-	int retval;
-
-	retval = tty_ldisc_open(tty, ld);
-	if (retval)
-		return retval;
-
-	if (o_tty) {
-		retval = tty_ldisc_open(o_tty, o_tty->ldisc);
-		if (retval) {
-			tty_ldisc_close(tty, ld);
-			return retval;
-		}
-		tty_ldisc_enable(o_tty);
-	}
-	tty_ldisc_enable(tty);
-	return 0;
-}
-/**
- *	tty_ldisc_release		-	release line discipline
- *	@tty: tty being shut down
- *	@o_tty: pair tty for pty/tty pairs
- *
- *	Called during the final close of a tty/pty pair in order to shut down
- *	the line discpline layer. On exit the ldisc assigned is N_TTY and the
- *	ldisc has not been opened.
- */
-
-void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-	/*
-	 * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
-	 * kill any delayed work. As this is the final close it does not
-	 * race with the set_ldisc code path.
-	 */
-
-	tty_unlock();
-	tty_ldisc_halt(tty);
-	flush_scheduled_work();
-	tty_lock();
-
-	mutex_lock(&tty->ldisc_mutex);
-	/*
-	 * Now kill off the ldisc
-	 */
-	tty_ldisc_close(tty, tty->ldisc);
-	tty_ldisc_put(tty->ldisc);
-	/* Force an oops if we mess this up */
-	tty->ldisc = NULL;
-
-	/* Ensure the next open requests the N_TTY ldisc */
-	tty_set_termios_ldisc(tty, N_TTY);
-	mutex_unlock(&tty->ldisc_mutex);
-
-	/* This will need doing differently if we need to lock */
-	if (o_tty)
-		tty_ldisc_release(o_tty, NULL);
-
-	/* And the memory resources remaining (buffers, termios) will be
-	   disposed of when the kref hits zero */
-}
-
-/**
- *	tty_ldisc_init		-	ldisc setup for new tty
- *	@tty: tty being allocated
- *
- *	Set up the line discipline objects for a newly allocated tty. Note that
- *	the tty structure is not completely set up when this call is made.
- */
-
-void tty_ldisc_init(struct tty_struct *tty)
-{
-	struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
-	if (IS_ERR(ld))
-		panic("n_tty: init_tty");
-	tty_ldisc_assign(tty, ld);
-}
-
-void tty_ldisc_begin(void)
-{
-	/* Setup the default TTY line discipline. */
-	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_mutex.c linux-libre-2.6.37-gnu/drivers/char/tty_mutex.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_mutex.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_mutex.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,47 +0,0 @@
-/*
- * drivers/char/tty_lock.c
- */
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/semaphore.h>
-#include <linux/sched.h>
-
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
-struct task_struct *__big_tty_mutex_owner;
-EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
-
-/*
- * Getting the big tty mutex.
- */
-void __lockfunc tty_lock(void)
-{
-	struct task_struct *task = current;
-
-	WARN_ON(__big_tty_mutex_owner == task);
-
-	mutex_lock(&big_tty_mutex);
-	__big_tty_mutex_owner = task;
-}
-EXPORT_SYMBOL(tty_lock);
-
-void __lockfunc tty_unlock(void)
-{
-	struct task_struct *task = current;
-
-	WARN_ON(__big_tty_mutex_owner != task);
-	__big_tty_mutex_owner = NULL;
-
-	mutex_unlock(&big_tty_mutex);
-}
-EXPORT_SYMBOL(tty_unlock);
diff -druN linux-libre-2.6.36-gnu/drivers/char/tty_port.c linux-libre-2.6.37-gnu/drivers/char/tty_port.c
--- linux-libre-2.6.36-gnu/drivers/char/tty_port.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/tty_port.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,446 +0,0 @@
-/*
- * Tty port functions
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-void tty_port_init(struct tty_port *port)
-{
-	memset(port, 0, sizeof(*port));
-	init_waitqueue_head(&port->open_wait);
-	init_waitqueue_head(&port->close_wait);
-	init_waitqueue_head(&port->delta_msr_wait);
-	mutex_init(&port->mutex);
-	mutex_init(&port->buf_mutex);
-	spin_lock_init(&port->lock);
-	port->close_delay = (50 * HZ) / 100;
-	port->closing_wait = (3000 * HZ) / 100;
-	kref_init(&port->kref);
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-	/* We may sleep in get_zeroed_page() */
-	mutex_lock(&port->buf_mutex);
-	if (port->xmit_buf == NULL)
-		port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-	mutex_unlock(&port->buf_mutex);
-	if (port->xmit_buf == NULL)
-		return -ENOMEM;
-	return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-	mutex_lock(&port->buf_mutex);
-	if (port->xmit_buf != NULL) {
-		free_page((unsigned long)port->xmit_buf);
-		port->xmit_buf = NULL;
-	}
-	mutex_unlock(&port->buf_mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-static void tty_port_destructor(struct kref *kref)
-{
-	struct tty_port *port = container_of(kref, struct tty_port, kref);
-	if (port->xmit_buf)
-		free_page((unsigned long)port->xmit_buf);
-	if (port->ops->destruct)
-		port->ops->destruct(port);
-	else
-		kfree(port);
-}
-
-void tty_port_put(struct tty_port *port)
-{
-	if (port)
-		kref_put(&port->kref, tty_port_destructor);
-}
-EXPORT_SYMBOL(tty_port_put);
-
-/**
- *	tty_port_tty_get	-	get a tty reference
- *	@port: tty port
- *
- *	Return a refcount protected tty instance or NULL if the port is not
- *	associated with a tty (eg due to close or hangup)
- */
-
-struct tty_struct *tty_port_tty_get(struct tty_port *port)
-{
-	unsigned long flags;
-	struct tty_struct *tty;
-
-	spin_lock_irqsave(&port->lock, flags);
-	tty = tty_kref_get(port->tty);
-	spin_unlock_irqrestore(&port->lock, flags);
-	return tty;
-}
-EXPORT_SYMBOL(tty_port_tty_get);
-
-/**
- *	tty_port_tty_set	-	set the tty of a port
- *	@port: tty port
- *	@tty: the tty
- *
- *	Associate the port and tty pair. Manages any internal refcounts.
- *	Pass NULL to deassociate a port
- */
-
-void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&port->lock, flags);
-	if (port->tty)
-		tty_kref_put(port->tty);
-	port->tty = tty_kref_get(tty);
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_tty_set);
-
-static void tty_port_shutdown(struct tty_port *port)
-{
-	mutex_lock(&port->mutex);
-	if (port->ops->shutdown && !port->console &&
-		test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
-			port->ops->shutdown(port);
-	mutex_unlock(&port->mutex);
-}
-
-/**
- *	tty_port_hangup		-	hangup helper
- *	@port: tty port
- *
- *	Perform port level tty hangup flag and count changes. Drop the tty
- *	reference.
- */
-
-void tty_port_hangup(struct tty_port *port)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&port->lock, flags);
-	port->count = 0;
-	port->flags &= ~ASYNC_NORMAL_ACTIVE;
-	if (port->tty) {
-		set_bit(TTY_IO_ERROR, &port->tty->flags);
-		tty_kref_put(port->tty);
-	}
-	port->tty = NULL;
-	spin_unlock_irqrestore(&port->lock, flags);
-	wake_up_interruptible(&port->open_wait);
-	wake_up_interruptible(&port->delta_msr_wait);
-	tty_port_shutdown(port);
-}
-EXPORT_SYMBOL(tty_port_hangup);
-
-/**
- *	tty_port_carrier_raised	-	carrier raised check
- *	@port: tty port
- *
- *	Wrapper for the carrier detect logic. For the moment this is used
- *	to hide some internal details. This will eventually become entirely
- *	internal to the tty port.
- */
-
-int tty_port_carrier_raised(struct tty_port *port)
-{
-	if (port->ops->carrier_raised == NULL)
-		return 1;
-	return port->ops->carrier_raised(port);
-}
-EXPORT_SYMBOL(tty_port_carrier_raised);
-
-/**
- *	tty_port_raise_dtr_rts	-	Raise DTR/RTS
- *	@port: tty port
- *
- *	Wrapper for the DTR/RTS raise logic. For the moment this is used
- *	to hide some internal details. This will eventually become entirely
- *	internal to the tty port.
- */
-
-void tty_port_raise_dtr_rts(struct tty_port *port)
-{
-	if (port->ops->dtr_rts)
-		port->ops->dtr_rts(port, 1);
-}
-EXPORT_SYMBOL(tty_port_raise_dtr_rts);
-
-/**
- *	tty_port_lower_dtr_rts	-	Lower DTR/RTS
- *	@port: tty port
- *
- *	Wrapper for the DTR/RTS raise logic. For the moment this is used
- *	to hide some internal details. This will eventually become entirely
- *	internal to the tty port.
- */
-
-void tty_port_lower_dtr_rts(struct tty_port *port)
-{
-	if (port->ops->dtr_rts)
-		port->ops->dtr_rts(port, 0);
-}
-EXPORT_SYMBOL(tty_port_lower_dtr_rts);
-
-/**
- *	tty_port_block_til_ready	-	Waiting logic for tty open
- *	@port: the tty port being opened
- *	@tty: the tty device being bound
- *	@filp: the file pointer of the opener
- *
- *	Implement the core POSIX/SuS tty behaviour when opening a tty device.
- *	Handles:
- *		- hangup (both before and during)
- *		- non blocking open
- *		- rts/dtr/dcd
- *		- signals
- *		- port flags and counts
- *
- *	The passed tty_port must implement the carrier_raised method if it can
- *	do carrier detect and the dtr_rts method if it supports software
- *	management of these lines. Note that the dtr/rts raise is done each
- *	iteration as a hangup may have previously dropped them while we wait.
- */
-
-int tty_port_block_til_ready(struct tty_port *port,
-				struct tty_struct *tty, struct file *filp)
-{
-	int do_clocal = 0, retval;
-	unsigned long flags;
-	DEFINE_WAIT(wait);
-	int cd;
-
-	/* block if port is in the process of being closed */
-	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-		wait_event_interruptible_tty(port->close_wait,
-				!(port->flags & ASYNC_CLOSING));
-		if (port->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-	}
-
-	/* if non-blocking mode is set we can pass directly to open unless
-	   the port has just hung up or is in another error state */
-	if (tty->flags & (1 << TTY_IO_ERROR)) {
-		port->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-	if (filp->f_flags & O_NONBLOCK) {
-		/* Indicate we are open */
-		if (tty->termios->c_cflag & CBAUD)
-			tty_port_raise_dtr_rts(port);
-		port->flags |= ASYNC_NORMAL_ACTIVE;
-		return 0;
-	}
-
-	if (C_CLOCAL(tty))
-		do_clocal = 1;
-
-	/* Block waiting until we can proceed. We may need to wait for the
-	   carrier, but we must also wait for any close that is in progress
-	   before the next open may complete */
-
-	retval = 0;
-
-	/* The port lock protects the port counts */
-	spin_lock_irqsave(&port->lock, flags);
-	if (!tty_hung_up_p(filp))
-		port->count--;
-	port->blocked_open++;
-	spin_unlock_irqrestore(&port->lock, flags);
-
-	while (1) {
-		/* Indicate we are open */
-		if (tty->termios->c_cflag & CBAUD)
-			tty_port_raise_dtr_rts(port);
-
-		prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-		/* Check for a hangup or uninitialised port.
-							Return accordingly */
-		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-			if (port->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-			break;
-		}
-		/* Probe the carrier. For devices with no carrier detect this
-		   will always return true */
-		cd = tty_port_carrier_raised(port);
-		if (!(port->flags & ASYNC_CLOSING) &&
-				(do_clocal || cd))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-		tty_unlock();
-		schedule();
-		tty_lock();
-	}
-	finish_wait(&port->open_wait, &wait);
-
-	/* Update counts. A parallel hangup will have set count to zero and
-	   we must not mess that up further */
-	spin_lock_irqsave(&port->lock, flags);
-	if (!tty_hung_up_p(filp))
-		port->count++;
-	port->blocked_open--;
-	if (retval == 0)
-		port->flags |= ASYNC_NORMAL_ACTIVE;
-	spin_unlock_irqrestore(&port->lock, flags);
-	return retval;
-}
-EXPORT_SYMBOL(tty_port_block_til_ready);
-
-int tty_port_close_start(struct tty_port *port,
-				struct tty_struct *tty, struct file *filp)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&port->lock, flags);
-	if (tty_hung_up_p(filp)) {
-		spin_unlock_irqrestore(&port->lock, flags);
-		return 0;
-	}
-
-	if (tty->count == 1 && port->count != 1) {
-		printk(KERN_WARNING
-		    "tty_port_close_start: tty->count = 1 port count = %d.\n",
-								port->count);
-		port->count = 1;
-	}
-	if (--port->count < 0) {
-		printk(KERN_WARNING "tty_port_close_start: count = %d\n",
-								port->count);
-		port->count = 0;
-	}
-
-	if (port->count) {
-		spin_unlock_irqrestore(&port->lock, flags);
-		if (port->ops->drop)
-			port->ops->drop(port);
-		return 0;
-	}
-	set_bit(ASYNCB_CLOSING, &port->flags);
-	tty->closing = 1;
-	spin_unlock_irqrestore(&port->lock, flags);
-	/* Don't block on a stalled port, just pull the chain */
-	if (tty->flow_stopped)
-		tty_driver_flush_buffer(tty);
-	if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
-			port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, port->closing_wait);
-	if (port->drain_delay) {
-		unsigned int bps = tty_get_baud_rate(tty);
-		long timeout;
-
-		if (bps > 1200)
-			timeout = max_t(long,
-				(HZ * 10 * port->drain_delay) / bps, HZ / 10);
-		else
-			timeout = 2 * HZ;
-		schedule_timeout_interruptible(timeout);
-	}
-	/* Flush the ldisc buffering */
-	tty_ldisc_flush(tty);
-
-	/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
-	   hang up the line */
-	if (tty->termios->c_cflag & HUPCL)
-		tty_port_lower_dtr_rts(port);
-
-	/* Don't call port->drop for the last reference. Callers will want
-	   to drop the last active reference in ->shutdown() or the tty
-	   shutdown path */
-	return 1;
-}
-EXPORT_SYMBOL(tty_port_close_start);
-
-void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&port->lock, flags);
-	tty->closing = 0;
-
-	if (port->blocked_open) {
-		spin_unlock_irqrestore(&port->lock, flags);
-		if (port->close_delay) {
-			msleep_interruptible(
-				jiffies_to_msecs(port->close_delay));
-		}
-		spin_lock_irqsave(&port->lock, flags);
-		wake_up_interruptible(&port->open_wait);
-	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-	wake_up_interruptible(&port->close_wait);
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_close_end);
-
-void tty_port_close(struct tty_port *port, struct tty_struct *tty,
-							struct file *filp)
-{
-	if (tty_port_close_start(port, tty, filp) == 0)
-		return;
-	tty_port_shutdown(port);
-	set_bit(TTY_IO_ERROR, &tty->flags);
-	tty_port_close_end(port, tty);
-	tty_port_tty_set(port, NULL);
-}
-EXPORT_SYMBOL(tty_port_close);
-
-int tty_port_open(struct tty_port *port, struct tty_struct *tty,
-							struct file *filp)
-{
-	spin_lock_irq(&port->lock);
-	if (!tty_hung_up_p(filp))
-		++port->count;
-	spin_unlock_irq(&port->lock);
-	tty_port_tty_set(port, tty);
-
-	/*
-	 * Do the device-specific open only if the hardware isn't
-	 * already initialized. Serialize open and shutdown using the
-	 * port mutex.
-	 */
-
-	mutex_lock(&port->mutex);
-
-	if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
-		clear_bit(TTY_IO_ERROR, &tty->flags);
-		if (port->ops->activate) {
-			int retval = port->ops->activate(port, tty);
-			if (retval) {
-				mutex_unlock(&port->mutex);
-				return retval;
-			}
-		}
-		set_bit(ASYNCB_INITIALIZED, &port->flags);
-	}
-	mutex_unlock(&port->mutex);
-	return tty_port_block_til_ready(port, tty, filp);
-}
-
-EXPORT_SYMBOL(tty_port_open);
diff -druN linux-libre-2.6.36-gnu/drivers/char/ttyprintk.c linux-libre-2.6.37-gnu/drivers/char/ttyprintk.c
--- linux-libre-2.6.36-gnu/drivers/char/ttyprintk.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/char/ttyprintk.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,225 @@
+/*
+ *  linux/drivers/char/ttyprintk.c
+ *
+ *  Copyright (C) 2010  Samo Pogacnik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the smems of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+/*
+ * This pseudo device allows user to make printk messages. It is possible
+ * to store "console" messages inline with kernel messages for better analyses
+ * of the boot process, for example.
+ */
+
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+struct ttyprintk_port {
+	struct tty_port port;
+	struct mutex port_write_mutex;
+};
+
+static struct ttyprintk_port tpk_port;
+
+/*
+ * Our simple preformatting supports transparent output of (time-stamped)
+ * printk messages (also suitable for logging service):
+ * - any cr is replaced by nl
+ * - adds a ttyprintk source tag in front of each line
+ * - too long message is fragmeted, with '\'nl between fragments
+ * - TPK_STR_SIZE isn't really the write_room limiting factor, bcause
+ *   it is emptied on the fly during preformatting.
+ */
+#define TPK_STR_SIZE 508 /* should be bigger then max expected line length */
+#define TPK_MAX_ROOM 4096 /* we could assume 4K for instance */
+static const char *tpk_tag = "[U] "; /* U for User */
+static int tpk_curr;
+
+static int tpk_printk(const unsigned char *buf, int count)
+{
+	static char tmp[TPK_STR_SIZE + 4];
+	int i = tpk_curr;
+
+	if (buf == NULL) {
+		/* flush tmp[] */
+		if (tpk_curr > 0) {
+			/* non nl or cr terminated message - add nl */
+			tmp[tpk_curr + 0] = '\n';
+			tmp[tpk_curr + 1] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+		return i;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp[tpk_curr] = buf[i];
+		if (tpk_curr < TPK_STR_SIZE) {
+			switch (buf[i]) {
+			case '\r':
+				/* replace cr with nl */
+				tmp[tpk_curr + 0] = '\n';
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				if (buf[i + 1] == '\n')
+					i++;
+				break;
+			case '\n':
+				tmp[tpk_curr + 1] = '\0';
+				printk(KERN_INFO "%s%s", tpk_tag, tmp);
+				tpk_curr = 0;
+				break;
+			default:
+				tpk_curr++;
+			}
+		} else {
+			/* end of tmp buffer reached: cut the message in two */
+			tmp[tpk_curr + 1] = '\\';
+			tmp[tpk_curr + 2] = '\n';
+			tmp[tpk_curr + 3] = '\0';
+			printk(KERN_INFO "%s%s", tpk_tag, tmp);
+			tpk_curr = 0;
+		}
+	}
+
+	return count;
+}
+
+/*
+ * TTY operations open function.
+ */
+static int tpk_open(struct tty_struct *tty, struct file *filp)
+{
+	tty->driver_data = &tpk_port;
+
+	return tty_port_open(&tpk_port.port, tty, filp);
+}
+
+/*
+ * TTY operations close function.
+ */
+static void tpk_close(struct tty_struct *tty, struct file *filp)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	mutex_lock(&tpkp->port_write_mutex);
+	/* flush tpk_printk buffer */
+	tpk_printk(NULL, 0);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	tty_port_close(&tpkp->port, tty, filp);
+}
+
+/*
+ * TTY operations write function.
+ */
+static int tpk_write(struct tty_struct *tty,
+		const unsigned char *buf, int count)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+	int ret;
+
+
+	/* exclusive use of tpk_printk within this tty */
+	mutex_lock(&tpkp->port_write_mutex);
+	ret = tpk_printk(buf, count);
+	mutex_unlock(&tpkp->port_write_mutex);
+
+	return ret;
+}
+
+/*
+ * TTY operations write_room function.
+ */
+static int tpk_write_room(struct tty_struct *tty)
+{
+	return TPK_MAX_ROOM;
+}
+
+/*
+ * TTY operations ioctl function.
+ */
+static int tpk_ioctl(struct tty_struct *tty, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct ttyprintk_port *tpkp = tty->driver_data;
+
+	if (!tpkp)
+		return -EINVAL;
+
+	switch (cmd) {
+	/* Stop TIOCCONS */
+	case TIOCCONS:
+		return -EOPNOTSUPP;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct tty_operations ttyprintk_ops = {
+	.open = tpk_open,
+	.close = tpk_close,
+	.write = tpk_write,
+	.write_room = tpk_write_room,
+	.ioctl = tpk_ioctl,
+};
+
+struct tty_port_operations null_ops = { };
+
+static struct tty_driver *ttyprintk_driver;
+
+static int __init ttyprintk_init(void)
+{
+	int ret = -ENOMEM;
+	void *rp;
+
+	ttyprintk_driver = alloc_tty_driver(1);
+	if (!ttyprintk_driver)
+		return ret;
+
+	ttyprintk_driver->owner = THIS_MODULE;
+	ttyprintk_driver->driver_name = "ttyprintk";
+	ttyprintk_driver->name = "ttyprintk";
+	ttyprintk_driver->major = TTYAUX_MAJOR;
+	ttyprintk_driver->minor_start = 3;
+	ttyprintk_driver->num = 1;
+	ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+	ttyprintk_driver->init_termios = tty_std_termios;
+	ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
+	ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+		TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+
+	ret = tty_register_driver(ttyprintk_driver);
+	if (ret < 0) {
+		printk(KERN_ERR "Couldn't register ttyprintk driver\n");
+		goto error;
+	}
+
+	/* create our unnumbered device */
+	rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
+				ttyprintk_driver->name);
+	if (IS_ERR(rp)) {
+		printk(KERN_ERR "Couldn't create ttyprintk device\n");
+		ret = PTR_ERR(rp);
+		goto error;
+	}
+
+	tty_port_init(&tpk_port.port);
+	tpk_port.port.ops = &null_ops;
+	mutex_init(&tpk_port.port_write_mutex);
+
+	return 0;
+
+error:
+	put_tty_driver(ttyprintk_driver);
+	ttyprintk_driver = NULL;
+	return ret;
+}
+module_init(ttyprintk_init);
diff -druN linux-libre-2.6.36-gnu/drivers/char/uv_mmtimer.c linux-libre-2.6.37-gnu/drivers/char/uv_mmtimer.c
--- linux-libre-2.6.36-gnu/drivers/char/uv_mmtimer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/uv_mmtimer.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,7 +23,6 @@
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/math64.h>
-#include <linux/smp_lock.h>
 
 #include <asm/genapic.h>
 #include <asm/uv/uv_hub.h>
@@ -52,6 +51,7 @@
 	.owner = THIS_MODULE,
 	.mmap =	uv_mmtimer_mmap,
 	.unlocked_ioctl = uv_mmtimer_ioctl,
+	.llseek = noop_llseek,
 };
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/char/vc_screen.c linux-libre-2.6.37-gnu/drivers/char/vc_screen.c
--- linux-libre-2.6.36-gnu/drivers/char/vc_screen.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/vc_screen.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,509 +0,0 @@
-/*
- * linux/drivers/char/vc_screen.c
- *
- * Provide access to virtual console memory.
- * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
- * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
- *            [minor: N]
- *
- * /dev/vcsaN: idem, but including attributes, and prefixed with
- *	the 4 bytes lines,columns,x,y (as screendump used to give).
- *	Attribute/character pair is in native endianity.
- *            [minor: N+128]
- *
- * This replaces screendump and part of selection, so that the system
- * administrator can control access using file system permissions.
- *
- * aeb@cwi.nl - efter Friedas begravelse - 950211
- *
- * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
- *	 - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
- *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
- */
-
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/kbd_kern.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#undef attr
-#undef org
-#undef addr
-#define HEADER_SIZE	4
-
-static int
-vcs_size(struct inode *inode)
-{
-	int size;
-	int minor = iminor(inode);
-	int currcons = minor & 127;
-	struct vc_data *vc;
-
-	if (currcons == 0)
-		currcons = fg_console;
-	else
-		currcons--;
-	if (!vc_cons_allocated(currcons))
-		return -ENXIO;
-	vc = vc_cons[currcons].d;
-
-	size = vc->vc_rows * vc->vc_cols;
-
-	if (minor & 128)
-		size = 2*size + HEADER_SIZE;
-	return size;
-}
-
-static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
-{
-	int size;
-
-	mutex_lock(&con_buf_mtx);
-	size = vcs_size(file->f_path.dentry->d_inode);
-	switch (orig) {
-		default:
-			mutex_unlock(&con_buf_mtx);
-			return -EINVAL;
-		case 2:
-			offset += size;
-			break;
-		case 1:
-			offset += file->f_pos;
-		case 0:
-			break;
-	}
-	if (offset < 0 || offset > size) {
-		mutex_unlock(&con_buf_mtx);
-		return -EINVAL;
-	}
-	file->f_pos = offset;
-	mutex_unlock(&con_buf_mtx);
-	return file->f_pos;
-}
-
-
-static ssize_t
-vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-	struct inode *inode = file->f_path.dentry->d_inode;
-	unsigned int currcons = iminor(inode);
-	struct vc_data *vc;
-	long pos;
-	long viewed, attr, read;
-	int col, maxcol;
-	unsigned short *org = NULL;
-	ssize_t ret;
-
-	mutex_lock(&con_buf_mtx);
-
-	pos = *ppos;
-
-	/* Select the proper current console and verify
-	 * sanity of the situation under the console lock.
-	 */
-	acquire_console_sem();
-
-	attr = (currcons & 128);
-	currcons = (currcons & 127);
-	if (currcons == 0) {
-		currcons = fg_console;
-		viewed = 1;
-	} else {
-		currcons--;
-		viewed = 0;
-	}
-	ret = -ENXIO;
-	if (!vc_cons_allocated(currcons))
-		goto unlock_out;
-	vc = vc_cons[currcons].d;
-
-	ret = -EINVAL;
-	if (pos < 0)
-		goto unlock_out;
-	read = 0;
-	ret = 0;
-	while (count) {
-		char *con_buf0, *con_buf_start;
-		long this_round, size;
-		ssize_t orig_count;
-		long p = pos;
-
-		/* Check whether we are above size each round,
-		 * as copy_to_user at the end of this loop
-		 * could sleep.
-		 */
-		size = vcs_size(inode);
-		if (pos >= size)
-			break;
-		if (count > size - pos)
-			count = size - pos;
-
-		this_round = count;
-		if (this_round > CON_BUF_SIZE)
-			this_round = CON_BUF_SIZE;
-
-		/* Perform the whole read into the local con_buf.
-		 * Then we can drop the console spinlock and safely
-		 * attempt to move it to userspace.
-		 */
-
-		con_buf_start = con_buf0 = con_buf;
-		orig_count = this_round;
-		maxcol = vc->vc_cols;
-		if (!attr) {
-			org = screen_pos(vc, p, viewed);
-			col = p % maxcol;
-			p += maxcol - col;
-			while (this_round-- > 0) {
-				*con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
-				if (++col == maxcol) {
-					org = screen_pos(vc, p, viewed);
-					col = 0;
-					p += maxcol;
-				}
-			}
-		} else {
-			if (p < HEADER_SIZE) {
-				size_t tmp_count;
-
-				con_buf0[0] = (char)vc->vc_rows;
-				con_buf0[1] = (char)vc->vc_cols;
-				getconsxy(vc, con_buf0 + 2);
-
-				con_buf_start += p;
-				this_round += p;
-				if (this_round > CON_BUF_SIZE) {
-					this_round = CON_BUF_SIZE;
-					orig_count = this_round - p;
-				}
-
-				tmp_count = HEADER_SIZE;
-				if (tmp_count > this_round)
-					tmp_count = this_round;
-
-				/* Advance state pointers and move on. */
-				this_round -= tmp_count;
-				p = HEADER_SIZE;
-				con_buf0 = con_buf + HEADER_SIZE;
-				/* If this_round >= 0, then p is even... */
-			} else if (p & 1) {
-				/* Skip first byte for output if start address is odd
-				 * Update region sizes up/down depending on free
-				 * space in buffer.
-				 */
-				con_buf_start++;
-				if (this_round < CON_BUF_SIZE)
-					this_round++;
-				else
-					orig_count--;
-			}
-			if (this_round > 0) {
-				unsigned short *tmp_buf = (unsigned short *)con_buf0;
-
-				p -= HEADER_SIZE;
-				p /= 2;
-				col = p % maxcol;
-
-				org = screen_pos(vc, p, viewed);
-				p += maxcol - col;
-
-				/* Buffer has even length, so we can always copy
-				 * character + attribute. We do not copy last byte
-				 * to userspace if this_round is odd.
-				 */
-				this_round = (this_round + 1) >> 1;
-
-				while (this_round) {
-					*tmp_buf++ = vcs_scr_readw(vc, org++);
-					this_round --;
-					if (++col == maxcol) {
-						org = screen_pos(vc, p, viewed);
-						col = 0;
-						p += maxcol;
-					}
-				}
-			}
-		}
-
-		/* Finally, release the console semaphore while we push
-		 * all the data to userspace from our temporary buffer.
-		 *
-		 * AKPM: Even though it's a semaphore, we should drop it because
-		 * the pagefault handling code may want to call printk().
-		 */
-
-		release_console_sem();
-		ret = copy_to_user(buf, con_buf_start, orig_count);
-		acquire_console_sem();
-
-		if (ret) {
-			read += (orig_count - ret);
-			ret = -EFAULT;
-			break;
-		}
-		buf += orig_count;
-		pos += orig_count;
-		read += orig_count;
-		count -= orig_count;
-	}
-	*ppos += read;
-	if (read)
-		ret = read;
-unlock_out:
-	release_console_sem();
-	mutex_unlock(&con_buf_mtx);
-	return ret;
-}
-
-static ssize_t
-vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-	struct inode *inode = file->f_path.dentry->d_inode;
-	unsigned int currcons = iminor(inode);
-	struct vc_data *vc;
-	long pos;
-	long viewed, attr, size, written;
-	char *con_buf0;
-	int col, maxcol;
-	u16 *org0 = NULL, *org = NULL;
-	size_t ret;
-
-	mutex_lock(&con_buf_mtx);
-
-	pos = *ppos;
-
-	/* Select the proper current console and verify
-	 * sanity of the situation under the console lock.
-	 */
-	acquire_console_sem();
-
-	attr = (currcons & 128);
-	currcons = (currcons & 127);
-
-	if (currcons == 0) {
-		currcons = fg_console;
-		viewed = 1;
-	} else {
-		currcons--;
-		viewed = 0;
-	}
-	ret = -ENXIO;
-	if (!vc_cons_allocated(currcons))
-		goto unlock_out;
-	vc = vc_cons[currcons].d;
-
-	size = vcs_size(inode);
-	ret = -EINVAL;
-	if (pos < 0 || pos > size)
-		goto unlock_out;
-	if (count > size - pos)
-		count = size - pos;
-	written = 0;
-	while (count) {
-		long this_round = count;
-		size_t orig_count;
-		long p;
-
-		if (this_round > CON_BUF_SIZE)
-			this_round = CON_BUF_SIZE;
-
-		/* Temporarily drop the console lock so that we can read
-		 * in the write data from userspace safely.
-		 */
-		release_console_sem();
-		ret = copy_from_user(con_buf, buf, this_round);
-		acquire_console_sem();
-
-		if (ret) {
-			this_round -= ret;
-			if (!this_round) {
-				/* Abort loop if no data were copied. Otherwise
-				 * fail with -EFAULT.
-				 */
-				if (written)
-					break;
-				ret = -EFAULT;
-				goto unlock_out;
-			}
-		}
-
-		/* The vcs_size might have changed while we slept to grab
-		 * the user buffer, so recheck.
-		 * Return data written up to now on failure.
-		 */
-		size = vcs_size(inode);
-		if (pos >= size)
-			break;
-		if (this_round > size - pos)
-			this_round = size - pos;
-
-		/* OK, now actually push the write to the console
-		 * under the lock using the local kernel buffer.
-		 */
-
-		con_buf0 = con_buf;
-		orig_count = this_round;
-		maxcol = vc->vc_cols;
-		p = pos;
-		if (!attr) {
-			org0 = org = screen_pos(vc, p, viewed);
-			col = p % maxcol;
-			p += maxcol - col;
-
-			while (this_round > 0) {
-				unsigned char c = *con_buf0++;
-
-				this_round--;
-				vcs_scr_writew(vc,
-					       (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-				org++;
-				if (++col == maxcol) {
-					org = screen_pos(vc, p, viewed);
-					col = 0;
-					p += maxcol;
-				}
-			}
-		} else {
-			if (p < HEADER_SIZE) {
-				char header[HEADER_SIZE];
-
-				getconsxy(vc, header + 2);
-				while (p < HEADER_SIZE && this_round > 0) {
-					this_round--;
-					header[p++] = *con_buf0++;
-				}
-				if (!viewed)
-					putconsxy(vc, header + 2);
-			}
-			p -= HEADER_SIZE;
-			col = (p/2) % maxcol;
-			if (this_round > 0) {
-				org0 = org = screen_pos(vc, p/2, viewed);
-				if ((p & 1) && this_round > 0) {
-					char c;
-
-					this_round--;
-					c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-					vcs_scr_writew(vc, c |
-					     (vcs_scr_readw(vc, org) & 0xff00), org);
-#else
-					vcs_scr_writew(vc, (c << 8) |
-					     (vcs_scr_readw(vc, org) & 0xff), org);
-#endif
-					org++;
-					p++;
-					if (++col == maxcol) {
-						org = screen_pos(vc, p/2, viewed);
-						col = 0;
-					}
-				}
-				p /= 2;
-				p += maxcol - col;
-			}
-			while (this_round > 1) {
-				unsigned short w;
-
-				w = get_unaligned(((unsigned short *)con_buf0));
-				vcs_scr_writew(vc, w, org++);
-				con_buf0 += 2;
-				this_round -= 2;
-				if (++col == maxcol) {
-					org = screen_pos(vc, p, viewed);
-					col = 0;
-					p += maxcol;
-				}
-			}
-			if (this_round > 0) {
-				unsigned char c;
-
-				c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-				vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
-#else
-				vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-#endif
-			}
-		}
-		count -= orig_count;
-		written += orig_count;
-		buf += orig_count;
-		pos += orig_count;
-		if (org0)
-			update_region(vc, (unsigned long)(org0), org - org0);
-	}
-	*ppos += written;
-	ret = written;
-
-unlock_out:
-	release_console_sem();
-
-	mutex_unlock(&con_buf_mtx);
-
-	return ret;
-}
-
-static int
-vcs_open(struct inode *inode, struct file *filp)
-{
-	unsigned int currcons = iminor(inode) & 127;
-	int ret = 0;
-	
-	tty_lock();
-	if(currcons && !vc_cons_allocated(currcons-1))
-		ret = -ENXIO;
-	tty_unlock();
-	return ret;
-}
-
-static const struct file_operations vcs_fops = {
-	.llseek		= vcs_lseek,
-	.read		= vcs_read,
-	.write		= vcs_write,
-	.open		= vcs_open,
-};
-
-static struct class *vc_class;
-
-void vcs_make_sysfs(int index)
-{
-	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
-		      "vcs%u", index + 1);
-	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
-		      "vcsa%u", index + 1);
-}
-
-void vcs_remove_sysfs(int index)
-{
-	device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
-	device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
-}
-
-int __init vcs_init(void)
-{
-	unsigned int i;
-
-	if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
-		panic("unable to get major %d for vcs device", VCS_MAJOR);
-	vc_class = class_create(THIS_MODULE, "vc");
-
-	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
-	device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
-	for (i = 0; i < MIN_NR_CONSOLES; i++)
-		vcs_make_sysfs(i);
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/char/viotape.c linux-libre-2.6.37-gnu/drivers/char/viotape.c
--- linux-libre-2.6.36-gnu/drivers/char/viotape.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/viotape.c	2011-01-04 19:50:19.000000000 -0500
@@ -46,7 +46,7 @@
 #include <linux/completion.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
@@ -64,6 +64,7 @@
 #define VIOTAPE_KERN_WARN	KERN_WARNING "viotape: "
 #define VIOTAPE_KERN_INFO	KERN_INFO "viotape: "
 
+static DEFINE_MUTEX(proc_viotape_mutex);
 static int viotape_numdev;
 
 /*
@@ -684,9 +685,9 @@
 {
 	long rc;
 
-	lock_kernel();
+	mutex_lock(&proc_viotape_mutex);
 	rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&proc_viotape_mutex);
 	return rc;
 }
 
@@ -700,7 +701,7 @@
 	if (op == NULL)
 		return -ENOMEM;
 
-	lock_kernel();
+	mutex_lock(&proc_viotape_mutex);
 	get_dev_info(file->f_path.dentry->d_inode, &devi);
 
 	/* Note: We currently only support one mode! */
@@ -731,7 +732,7 @@
 
 free_op:
 	free_op_struct(op);
-	unlock_kernel();
+	mutex_unlock(&proc_viotape_mutex);
 	return ret;
 }
 
@@ -804,6 +805,7 @@
 	.unlocked_ioctl =	viotap_unlocked_ioctl,
 	.open =			viotap_open,
 	.release =		viotap_release,
+	.llseek = 		noop_llseek,
 };
 
 /* Handle interrupt events for tape */
diff -druN linux-libre-2.6.36-gnu/drivers/char/virtio_console.c linux-libre-2.6.37-gnu/drivers/char/virtio_console.c
--- linux-libre-2.6.36-gnu/drivers/char/virtio_console.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/virtio_console.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,6 +48,9 @@
 	/* Used for exporting per-port information to debugfs */
 	struct dentry *debugfs_dir;
 
+	/* List of all the devices we're handling */
+	struct list_head portdevs;
+
 	/* Number of devices this driver is handling */
 	unsigned int index;
 
@@ -108,6 +111,9 @@
  * ports for that device (vdev->priv).
  */
 struct ports_device {
+	/* Next portdev in the list, head is in the pdrvdata struct */
+	struct list_head list;
+
 	/*
 	 * Workqueue handlers where we process deferred work after
 	 * notification
@@ -178,15 +184,21 @@
 	struct console cons;
 
 	/* Each port associates with a separate char device */
-	struct cdev cdev;
+	struct cdev *cdev;
 	struct device *dev;
 
+	/* Reference-counting to handle port hot-unplugs and file operations */
+	struct kref kref;
+
 	/* A waitqueue for poll() or blocking read operations */
 	wait_queue_head_t waitqueue;
 
 	/* The 'name' of the port that we expose via sysfs properties */
 	char *name;
 
+	/* We can notify apps of host connect / disconnect events via SIGIO */
+	struct fasync_struct *async_queue;
+
 	/* The 'id' to identify the port with the Host */
 	u32 id;
 
@@ -221,6 +233,41 @@
 	return port;
 }
 
+static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
+						 dev_t dev)
+{
+	struct port *port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&portdev->ports_lock, flags);
+	list_for_each_entry(port, &portdev->ports, list)
+		if (port->cdev->dev == dev)
+			goto out;
+	port = NULL;
+out:
+	spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+	return port;
+}
+
+static struct port *find_port_by_devt(dev_t dev)
+{
+	struct ports_device *portdev;
+	struct port *port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdrvdata_lock, flags);
+	list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
+		port = find_port_by_devt_in_portdev(portdev, dev);
+		if (port)
+			goto out;
+	}
+	port = NULL;
+out:
+	spin_unlock_irqrestore(&pdrvdata_lock, flags);
+	return port;
+}
+
 static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
 {
 	struct port *port;
@@ -410,7 +457,10 @@
 static ssize_t send_control_msg(struct port *port, unsigned int event,
 				unsigned int value)
 {
-	return __send_control_msg(port->portdev, port->id, event, value);
+	/* Did the port get unplugged before userspace closed it? */
+	if (port->portdev)
+		return __send_control_msg(port->portdev, port->id, event, value);
+	return 0;
 }
 
 /* Callers must take the port->outvq_lock */
@@ -525,6 +575,10 @@
 /* The condition that must be true for polling to end */
 static bool will_read_block(struct port *port)
 {
+	if (!port->guest_connected) {
+		/* Port got hot-unplugged. Let's exit. */
+		return false;
+	}
 	return !port_has_data(port) && port->host_connected;
 }
 
@@ -575,6 +629,9 @@
 		if (ret < 0)
 			return ret;
 	}
+	/* Port got hot-unplugged. */
+	if (!port->guest_connected)
+		return -ENODEV;
 	/*
 	 * We could've received a disconnection message while we were
 	 * waiting for more data.
@@ -616,6 +673,9 @@
 		if (ret < 0)
 			return ret;
 	}
+	/* Port got hot-unplugged. */
+	if (!port->guest_connected)
+		return -ENODEV;
 
 	count = min((size_t)(32 * 1024), count);
 
@@ -656,6 +716,10 @@
 	port = filp->private_data;
 	poll_wait(filp, &port->waitqueue, wait);
 
+	if (!port->guest_connected) {
+		/* Port got unplugged */
+		return POLLHUP;
+	}
 	ret = 0;
 	if (!will_read_block(port))
 		ret |= POLLIN | POLLRDNORM;
@@ -667,6 +731,8 @@
 	return ret;
 }
 
+static void remove_port(struct kref *kref);
+
 static int port_fops_release(struct inode *inode, struct file *filp)
 {
 	struct port *port;
@@ -687,6 +753,16 @@
 	reclaim_consumed_buffers(port);
 	spin_unlock_irq(&port->outvq_lock);
 
+	/*
+	 * Locks aren't necessary here as a port can't be opened after
+	 * unplug, and if a port isn't unplugged, a kref would already
+	 * exist for the port.  Plus, taking ports_lock here would
+	 * create a dependency on other locks taken by functions
+	 * inside remove_port if we're the last holder of the port,
+	 * creating many problems.
+	 */
+	kref_put(&port->kref, remove_port);
+
 	return 0;
 }
 
@@ -694,22 +770,31 @@
 {
 	struct cdev *cdev = inode->i_cdev;
 	struct port *port;
+	int ret;
 
-	port = container_of(cdev, struct port, cdev);
+	port = find_port_by_devt(cdev->dev);
 	filp->private_data = port;
 
+	/* Prevent against a port getting hot-unplugged at the same time */
+	spin_lock_irq(&port->portdev->ports_lock);
+	kref_get(&port->kref);
+	spin_unlock_irq(&port->portdev->ports_lock);
+
 	/*
 	 * Don't allow opening of console port devices -- that's done
 	 * via /dev/hvc
 	 */
-	if (is_console_port(port))
-		return -ENXIO;
+	if (is_console_port(port)) {
+		ret = -ENXIO;
+		goto out;
+	}
 
 	/* Allow only one process to open a particular port at a time */
 	spin_lock_irq(&port->inbuf_lock);
 	if (port->guest_connected) {
 		spin_unlock_irq(&port->inbuf_lock);
-		return -EMFILE;
+		ret = -EMFILE;
+		goto out;
 	}
 
 	port->guest_connected = true;
@@ -724,10 +809,23 @@
 	reclaim_consumed_buffers(port);
 	spin_unlock_irq(&port->outvq_lock);
 
+	nonseekable_open(inode, filp);
+
 	/* Notify host of port being opened */
 	send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
 	return 0;
+out:
+	kref_put(&port->kref, remove_port);
+	return ret;
+}
+
+static int port_fops_fasync(int fd, struct file *filp, int mode)
+{
+	struct port *port;
+
+	port = filp->private_data;
+	return fasync_helper(fd, filp, mode, &port->async_queue);
 }
 
 /*
@@ -743,6 +841,8 @@
 	.write = port_fops_write,
 	.poll  = port_fops_poll,
 	.release = port_fops_release,
+	.fasync = port_fops_fasync,
+	.llseek = no_llseek,
 };
 
 /*
@@ -1001,6 +1101,12 @@
 	return nr_added_bufs;
 }
 
+static void send_sigio_to_port(struct port *port)
+{
+	if (port->async_queue && port->guest_connected)
+		kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
+}
+
 static int add_port(struct ports_device *portdev, u32 id)
 {
 	char debugfs_name[16];
@@ -1015,6 +1121,7 @@
 		err = -ENOMEM;
 		goto fail;
 	}
+	kref_init(&port->kref);
 
 	port->portdev = portdev;
 	port->id = id;
@@ -1022,6 +1129,7 @@
 	port->name = NULL;
 	port->inbuf = NULL;
 	port->cons.hvc = NULL;
+	port->async_queue = NULL;
 
 	port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
 
@@ -1032,14 +1140,20 @@
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
 
-	cdev_init(&port->cdev, &port_fops);
+	port->cdev = cdev_alloc();
+	if (!port->cdev) {
+		dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
+		err = -ENOMEM;
+		goto free_port;
+	}
+	port->cdev->ops = &port_fops;
 
 	devt = MKDEV(portdev->chr_major, id);
-	err = cdev_add(&port->cdev, devt, 1);
+	err = cdev_add(port->cdev, devt, 1);
 	if (err < 0) {
 		dev_err(&port->portdev->vdev->dev,
 			"Error %d adding cdev for port %u\n", err, id);
-		goto free_port;
+		goto free_cdev;
 	}
 	port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
 				  devt, port, "vport%up%u",
@@ -1104,7 +1218,7 @@
 free_device:
 	device_destroy(pdrvdata.class, port->dev->devt);
 free_cdev:
-	cdev_del(&port->cdev);
+	cdev_del(port->cdev);
 free_port:
 	kfree(port);
 fail:
@@ -1113,21 +1227,45 @@
 	return err;
 }
 
-/* Remove all port-specific data. */
-static int remove_port(struct port *port)
+/* No users remain, remove all port-specific data. */
+static void remove_port(struct kref *kref)
+{
+	struct port *port;
+
+	port = container_of(kref, struct port, kref);
+
+	sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+	device_destroy(pdrvdata.class, port->dev->devt);
+	cdev_del(port->cdev);
+
+	kfree(port->name);
+
+	debugfs_remove(port->debugfs_file);
+
+	kfree(port);
+}
+
+/*
+ * Port got unplugged.  Remove port from portdev's list and drop the
+ * kref reference.  If no userspace has this port opened, it will
+ * result in immediate removal the port.
+ */
+static void unplug_port(struct port *port)
 {
 	struct port_buffer *buf;
 
+	spin_lock_irq(&port->portdev->ports_lock);
+	list_del(&port->list);
+	spin_unlock_irq(&port->portdev->ports_lock);
+
 	if (port->guest_connected) {
 		port->guest_connected = false;
 		port->host_connected = false;
 		wake_up_interruptible(&port->waitqueue);
-		send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-	}
 
-	spin_lock_irq(&port->portdev->ports_lock);
-	list_del(&port->list);
-	spin_unlock_irq(&port->portdev->ports_lock);
+		/* Let the app know the port is going down. */
+		send_sigio_to_port(port);
+	}
 
 	if (is_console_port(port)) {
 		spin_lock_irq(&pdrvdata_lock);
@@ -1146,9 +1284,6 @@
 		hvc_remove(port->cons.hvc);
 #endif
 	}
-	sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-	device_destroy(pdrvdata.class, port->dev->devt);
-	cdev_del(&port->cdev);
 
 	/* Remove unused data this port might have received. */
 	discard_port_data(port);
@@ -1159,12 +1294,19 @@
 	while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
 		free_buf(buf);
 
-	kfree(port->name);
-
-	debugfs_remove(port->debugfs_file);
+	/*
+	 * We should just assume the device itself has gone off --
+	 * else a close on an open port later will try to send out a
+	 * control message.
+	 */
+	port->portdev = NULL;
 
-	kfree(port);
-	return 0;
+	/*
+	 * Locks around here are not necessary - a port can't be
+	 * opened after we removed the port struct from ports_list
+	 * above.
+	 */
+	kref_put(&port->kref, remove_port);
 }
 
 /* Any private messages that the Host and Guest want to share */
@@ -1203,7 +1345,7 @@
 		add_port(portdev, cpkt->id);
 		break;
 	case VIRTIO_CONSOLE_PORT_REMOVE:
-		remove_port(port);
+		unplug_port(port);
 		break;
 	case VIRTIO_CONSOLE_CONSOLE_PORT:
 		if (!cpkt->value)
@@ -1245,6 +1387,12 @@
 		spin_lock_irq(&port->outvq_lock);
 		reclaim_consumed_buffers(port);
 		spin_unlock_irq(&port->outvq_lock);
+
+		/*
+		 * If the guest is connected, it'll be interested in
+		 * knowing the host connection state changed.
+		 */
+		send_sigio_to_port(port);
 		break;
 	case VIRTIO_CONSOLE_PORT_NAME:
 		/*
@@ -1341,6 +1489,9 @@
 
 	wake_up_interruptible(&port->waitqueue);
 
+	/* Send a SIGIO indicating new data in case the process asked for it */
+	send_sigio_to_port(port);
+
 	if (is_console_port(port) && hvc_poll(port->cons.hvc))
 		hvc_kick();
 }
@@ -1396,31 +1547,16 @@
 	nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
 
 	vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
-	if (!vqs) {
-		err = -ENOMEM;
-		goto fail;
-	}
 	io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
-	if (!io_callbacks) {
-		err = -ENOMEM;
-		goto free_vqs;
-	}
 	io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
-	if (!io_names) {
-		err = -ENOMEM;
-		goto free_callbacks;
-	}
 	portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
 				  GFP_KERNEL);
-	if (!portdev->in_vqs) {
-		err = -ENOMEM;
-		goto free_names;
-	}
 	portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
 				   GFP_KERNEL);
-	if (!portdev->out_vqs) {
+	if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
+			!portdev->out_vqs) {
 		err = -ENOMEM;
-		goto free_invqs;
+		goto free;
 	}
 
 	/*
@@ -1454,7 +1590,7 @@
 					      io_callbacks,
 					      (const char **)io_names);
 	if (err)
-		goto free_outvqs;
+		goto free;
 
 	j = 0;
 	portdev->in_vqs[0] = vqs[0];
@@ -1470,23 +1606,19 @@
 			portdev->out_vqs[i] = vqs[j + 1];
 		}
 	}
-	kfree(io_callbacks);
 	kfree(io_names);
+	kfree(io_callbacks);
 	kfree(vqs);
 
 	return 0;
 
-free_names:
-	kfree(io_names);
-free_callbacks:
-	kfree(io_callbacks);
-free_outvqs:
+free:
 	kfree(portdev->out_vqs);
-free_invqs:
 	kfree(portdev->in_vqs);
-free_vqs:
+	kfree(io_names);
+	kfree(io_callbacks);
 	kfree(vqs);
-fail:
+
 	return err;
 }
 
@@ -1577,6 +1709,10 @@
 		add_port(portdev, 0);
 	}
 
+	spin_lock_irq(&pdrvdata_lock);
+	list_add_tail(&portdev->list, &pdrvdata.portdevs);
+	spin_unlock_irq(&pdrvdata_lock);
+
 	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
 			   VIRTIO_CONSOLE_DEVICE_READY, 1);
 	return 0;
@@ -1600,23 +1736,41 @@
 {
 	struct ports_device *portdev;
 	struct port *port, *port2;
-	struct port_buffer *buf;
-	unsigned int len;
 
 	portdev = vdev->priv;
 
+	spin_lock_irq(&pdrvdata_lock);
+	list_del(&portdev->list);
+	spin_unlock_irq(&pdrvdata_lock);
+
+	/* Disable interrupts for vqs */
+	vdev->config->reset(vdev);
+	/* Finish up work that's lined up */
 	cancel_work_sync(&portdev->control_work);
 
 	list_for_each_entry_safe(port, port2, &portdev->ports, list)
-		remove_port(port);
+		unplug_port(port);
 
 	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 
-	while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-		free_buf(buf);
+	/*
+	 * When yanking out a device, we immediately lose the
+	 * (device-side) queues.  So there's no point in keeping the
+	 * guest side around till we drop our final reference.  This
+	 * also means that any ports which are in an open state will
+	 * have to just stop using the port, as the vqs are going
+	 * away.
+	 */
+	if (use_multiport(portdev)) {
+		struct port_buffer *buf;
+		unsigned int len;
 
-	while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-		free_buf(buf);
+		while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+			free_buf(buf);
+
+		while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+			free_buf(buf);
+	}
 
 	vdev->config->del_vqs(vdev);
 	kfree(portdev->in_vqs);
@@ -1663,6 +1817,7 @@
 			   PTR_ERR(pdrvdata.debugfs_dir));
 	}
 	INIT_LIST_HEAD(&pdrvdata.consoles);
+	INIT_LIST_HEAD(&pdrvdata.portdevs);
 
 	return register_virtio_driver(&virtio_console);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/char/vt.c linux-libre-2.6.37-gnu/drivers/char/vt.c
--- linux-libre-2.6.36-gnu/drivers/char/vt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/vt.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,4204 +0,0 @@
-/*
- *  linux/drivers/char/vt.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * Hopefully this will be a rather complete VT102 implementation.
- *
- * Beeping thanks to John T Kohl.
- *
- * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
- *   Chars, and VT100 enhancements by Peter MacDonald.
- *
- * Copy and paste function by Andrew Haylett,
- *   some enhancements by Alessandro Rubini.
- *
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- *
- * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
- * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
- *
- * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
- * Resizing of consoles, aeb, 940926
- *
- * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
- * <poe@daimi.aau.dk>
- *
- * User-defined bell sound, new setterm control sequences and printk
- * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
- *
- * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
- *
- * Merge with the abstract console driver by Geert Uytterhoeven
- * <geert@linux-m68k.org>, Jan 1997.
- *
- *   Original m68k console driver modifications by
- *
- *     - Arno Griffioen <arno@usn.nl>
- *     - David Carter <carter@cs.bris.ac.uk>
- * 
- *   The abstract console driver provides a generic interface for a text
- *   console. It supports VGA text mode, frame buffer based graphical consoles
- *   and special graphics processors that are only accessible through some
- *   registers (e.g. a TMS340x0 GSP).
- *
- *   The interface to the hardware is specified using a special structure
- *   (struct consw) which contains function pointers to console operations
- *   (see <linux/console.h> for more information).
- *
- * Support for changeable cursor shape
- * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
- *
- * Ported to i386 and con_scrolldelta fixed
- * by Emmanuel Marty <core@ggi-project.org>, April 1998
- *
- * Resurrected character buffers in videoram plus lots of other trickery
- * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
- *
- * Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe.  17Jun00, Andrew Morton
- *
- * Removed console_lock, enabled interrupts across all console operations
- * 13 March 2001, Andrew Morton
- *
- * Fixed UTF-8 mode so alternate charset modes always work according
- * to control sequences interpreted in do_con_trol function
- * preserving backward VT100 semigraphics compatibility,
- * malformed UTF sequences represented as sequences of replacement glyphs,
- * original codes or '?' as a last resort if replacement glyph is undefined
- * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/smp_lock.h>
-#include <linux/tiocl.h>
-#include <linux/kbd_kern.h>
-#include <linux/consolemap.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/pm.h>
-#include <linux/font.h>
-#include <linux/bitops.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <linux/kdb.h>
-#include <linux/ctype.h>
-
-#define MAX_NR_CON_DRIVER 16
-
-#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT   2
-#define CON_DRIVER_FLAG_ATTR   4
-
-struct con_driver {
-	const struct consw *con;
-	const char *desc;
-	struct device *dev;
-	int node;
-	int first;
-	int last;
-	int flag;
-};
-
-static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
-const struct consw *conswitchp;
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501	/* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH	750
-#define DEFAULT_BELL_DURATION	(HZ/8)
-
-struct vc vc_cons [MAX_NR_CONSOLES];
-
-#ifndef VT_SINGLE_DRIVER
-static const struct consw *con_driver_map[MAX_NR_CONSOLES];
-#endif
-
-static int con_open(struct tty_struct *, struct file *);
-static void vc_init(struct vc_data *vc, unsigned int rows,
-		    unsigned int cols, int do_clear);
-static void gotoxy(struct vc_data *vc, int new_x, int new_y);
-static void save_cur(struct vc_data *vc);
-static void reset_terminal(struct vc_data *vc, int do_clear);
-static void con_flush_chars(struct tty_struct *tty);
-static int set_vesa_blanking(char __user *p);
-static void set_cursor(struct vc_data *vc);
-static void hide_cursor(struct vc_data *vc);
-static void console_callback(struct work_struct *ignored);
-static void blank_screen_t(unsigned long dummy);
-static void set_palette(struct vc_data *vc);
-
-static int printable;		/* Is console ready for printing? */
-int default_utf8 = true;
-module_param(default_utf8, int, S_IRUGO | S_IWUSR);
-int global_cursor_default = -1;
-module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
-
-static int cur_default = CUR_DEFAULT;
-module_param(cur_default, int, S_IRUGO | S_IWUSR);
-
-/*
- * ignore_poke: don't unblank the screen when things are typed.  This is
- * mainly for the privacy of braille terminal users.
- */
-static int ignore_poke;
-
-int do_poke_blanked_console;
-int console_blanked;
-
-static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int vesa_off_interval;
-static int blankinterval = 10*60;
-core_param(consoleblank, blankinterval, int, 0444);
-
-static DECLARE_WORK(console_work, console_callback);
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * saved_* variants are for save/restore around kernel debugger enter/leave
- */
-int fg_console;
-int last_console;
-int want_console = -1;
-static int saved_fg_console;
-static int saved_last_console;
-static int saved_want_console;
-static int saved_vc_mode;
-static int saved_console_blanked;
-
-/*
- * For each existing display, we have a pointer to console currently visible
- * on that display, allowing consoles other than fg_console to be refreshed
- * appropriately. Unless the low-level driver supplies its own display_fg
- * variable, we use this one for the "master display".
- */
-static struct vc_data *master_display_fg;
-
-/*
- * Unfortunately, we need to delay tty echo when we're currently writing to the
- * console since the code is (and always was) not re-entrant, so we schedule
- * all flip requests to process context with schedule-task() and run it from
- * console_callback().
- */
-
-/*
- * For the same reason, we defer scrollback to the console callback.
- */
-static int scrollback_delta;
-
-/*
- * Hook so that the power management routines can (un)blank
- * the console on our behalf.
- */
-int (*console_blank_hook)(int);
-
-static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
-static int blank_state;
-static int blank_timer_expired;
-enum {
-	blank_off = 0,
-	blank_normal_wait,
-	blank_vesa_wait,
-};
-
-/*
- * Notifier list for console events.
- */
-static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
-
-int register_vt_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_register(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_vt_notifier);
-
-int unregister_vt_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_vt_notifier);
-
-static void notify_write(struct vc_data *vc, unsigned int unicode)
-{
-	struct vt_notifier_param param = { .vc = vc, unicode = unicode };
-	atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
-}
-
-static void notify_update(struct vc_data *vc)
-{
-	struct vt_notifier_param param = { .vc = vc };
-	atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
-}
-/*
- *	Low-Level Functions
- */
-
-#define IS_FG(vc)	((vc)->vc_num == fg_console)
-
-#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE(vc)	0
-#else
-#define DO_UPDATE(vc)	(CON_IS_VISIBLE(vc) && !console_blanked)
-#endif
-
-static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
-{
-	unsigned short *p;
-	
-	if (!viewed)
-		p = (unsigned short *)(vc->vc_origin + offset);
-	else if (!vc->vc_sw->con_screen_pos)
-		p = (unsigned short *)(vc->vc_visible_origin + offset);
-	else
-		p = vc->vc_sw->con_screen_pos(vc, offset);
-	return p;
-}
-
-/* Called  from the keyboard irq path.. */
-static inline void scrolldelta(int lines)
-{
-	/* FIXME */
-	/* scrolldelta needs some kind of consistency lock, but the BKL was
-	   and still is not protecting versus the scheduled back end */
-	scrollback_delta += lines;
-	schedule_console_callback();
-}
-
-void schedule_console_callback(void)
-{
-	schedule_work(&console_work);
-}
-
-static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-	unsigned short *d, *s;
-
-	if (t+nr >= b)
-		nr = b - t - 1;
-	if (b > vc->vc_rows || t >= b || nr < 1)
-		return;
-	if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
-		return;
-	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
-	scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-	scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
-		    vc->vc_size_row * nr);
-}
-
-static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-	unsigned short *s;
-	unsigned int step;
-
-	if (t+nr >= b)
-		nr = b - t - 1;
-	if (b > vc->vc_rows || t >= b || nr < 1)
-		return;
-	if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
-		return;
-	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-	step = vc->vc_cols * nr;
-	scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-	scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
-}
-
-static void do_update_region(struct vc_data *vc, unsigned long start, int count)
-{
-#ifndef VT_BUF_VRAM_ONLY
-	unsigned int xx, yy, offset;
-	u16 *p;
-
-	p = (u16 *) start;
-	if (!vc->vc_sw->con_getxy) {
-		offset = (start - vc->vc_origin) / 2;
-		xx = offset % vc->vc_cols;
-		yy = offset / vc->vc_cols;
-	} else {
-		int nxx, nyy;
-		start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-		xx = nxx; yy = nyy;
-	}
-	for(;;) {
-		u16 attrib = scr_readw(p) & 0xff00;
-		int startx = xx;
-		u16 *q = p;
-		while (xx < vc->vc_cols && count) {
-			if (attrib != (scr_readw(p) & 0xff00)) {
-				if (p > q)
-					vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-				startx = xx;
-				q = p;
-				attrib = scr_readw(p) & 0xff00;
-			}
-			p++;
-			xx++;
-			count--;
-		}
-		if (p > q)
-			vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-		if (!count)
-			break;
-		xx = 0;
-		yy++;
-		if (vc->vc_sw->con_getxy) {
-			p = (u16 *)start;
-			start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-		}
-	}
-#endif
-}
-
-void update_region(struct vc_data *vc, unsigned long start, int count)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (DO_UPDATE(vc)) {
-		hide_cursor(vc);
-		do_update_region(vc, start, count);
-		set_cursor(vc);
-	}
-}
-
-/* Structure of attributes is hardware-dependent */
-
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
-    u8 _underline, u8 _reverse, u8 _italic)
-{
-	if (vc->vc_sw->con_build_attr)
-		return vc->vc_sw->con_build_attr(vc, _color, _intensity,
-		       _blink, _underline, _reverse, _italic);
-
-#ifndef VT_BUF_VRAM_ONLY
-/*
- * ++roman: I completely changed the attribute format for monochrome
- * mode (!can_do_color). The formerly used MDA (monochrome display
- * adapter) format didn't allow the combination of certain effects.
- * Now the attribute is just a bit vector:
- *  Bit 0..1: intensity (0..2)
- *  Bit 2   : underline
- *  Bit 3   : reverse
- *  Bit 7   : blink
- */
-	{
-	u8 a = _color;
-	if (!vc->vc_can_do_color)
-		return _intensity |
-		       (_italic ? 2 : 0) |
-		       (_underline ? 4 : 0) |
-		       (_reverse ? 8 : 0) |
-		       (_blink ? 0x80 : 0);
-	if (_italic)
-		a = (a & 0xF0) | vc->vc_itcolor;
-	else if (_underline)
-		a = (a & 0xf0) | vc->vc_ulcolor;
-	else if (_intensity == 0)
-		a = (a & 0xf0) | vc->vc_ulcolor;
-	if (_reverse)
-		a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
-	if (_blink)
-		a ^= 0x80;
-	if (_intensity == 2)
-		a ^= 0x08;
-	if (vc->vc_hi_font_mask == 0x100)
-		a <<= 1;
-	return a;
-	}
-#else
-	return 0;
-#endif
-}
-
-static void update_attr(struct vc_data *vc)
-{
-	vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
-	              vc->vc_blink, vc->vc_underline,
-	              vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
-	vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
-{
-	unsigned short *p;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	count /= 2;
-	p = screenpos(vc, offset, viewed);
-	if (vc->vc_sw->con_invert_region)
-		vc->vc_sw->con_invert_region(vc, p, count);
-#ifndef VT_BUF_VRAM_ONLY
-	else {
-		u16 *q = p;
-		int cnt = count;
-		u16 a;
-
-		if (!vc->vc_can_do_color) {
-			while (cnt--) {
-			    a = scr_readw(q);
-			    a ^= 0x0800;
-			    scr_writew(a, q);
-			    q++;
-			}
-		} else if (vc->vc_hi_font_mask == 0x100) {
-			while (cnt--) {
-				a = scr_readw(q);
-				a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-				scr_writew(a, q);
-				q++;
-			}
-		} else {
-			while (cnt--) {
-				a = scr_readw(q);
-				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-				scr_writew(a, q);
-				q++;
-			}
-		}
-	}
-#endif
-	if (DO_UPDATE(vc))
-		do_update_region(vc, (unsigned long) p, count);
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(struct vc_data *vc, int offset)
-{
-	static int old_offset = -1;
-	static unsigned short old;
-	static unsigned short oldx, oldy;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	if (old_offset != -1 && old_offset >= 0 &&
-	    old_offset < vc->vc_screenbuf_size) {
-		scr_writew(old, screenpos(vc, old_offset, 1));
-		if (DO_UPDATE(vc))
-			vc->vc_sw->con_putc(vc, old, oldy, oldx);
-	}
-
-	old_offset = offset;
-
-	if (offset != -1 && offset >= 0 &&
-	    offset < vc->vc_screenbuf_size) {
-		unsigned short new;
-		unsigned short *p;
-		p = screenpos(vc, offset, 1);
-		old = scr_readw(p);
-		new = old ^ vc->vc_complement_mask;
-		scr_writew(new, p);
-		if (DO_UPDATE(vc)) {
-			oldx = (offset >> 1) % vc->vc_cols;
-			oldy = (offset >> 1) / vc->vc_cols;
-			vc->vc_sw->con_putc(vc, new, oldy, oldx);
-		}
-	}
-
-}
-
-static void insert_char(struct vc_data *vc, unsigned int nr)
-{
-	unsigned short *p, *q = (unsigned short *)vc->vc_pos;
-
-	p = q + vc->vc_cols - nr - vc->vc_x;
-	while (--p >= q)
-		scr_writew(scr_readw(p), p + nr);
-	scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
-	vc->vc_need_wrap = 0;
-	if (DO_UPDATE(vc)) {
-		unsigned short oldattr = vc->vc_attr;
-		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
-				     vc->vc_cols - vc->vc_x - nr);
-		vc->vc_attr = vc->vc_video_erase_char >> 8;
-		while (nr--)
-			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
-		vc->vc_attr = oldattr;
-	}
-}
-
-static void delete_char(struct vc_data *vc, unsigned int nr)
-{
-	unsigned int i = vc->vc_x;
-	unsigned short *p = (unsigned short *)vc->vc_pos;
-
-	while (++i <= vc->vc_cols - nr) {
-		scr_writew(scr_readw(p+nr), p);
-		p++;
-	}
-	scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
-	vc->vc_need_wrap = 0;
-	if (DO_UPDATE(vc)) {
-		unsigned short oldattr = vc->vc_attr;
-		vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
-				     vc->vc_cols - vc->vc_x - nr);
-		vc->vc_attr = vc->vc_video_erase_char >> 8;
-		while (nr--)
-			vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
-				     vc->vc_cols - 1 - nr);
-		vc->vc_attr = oldattr;
-	}
-}
-
-static int softcursor_original;
-
-static void add_softcursor(struct vc_data *vc)
-{
-	int i = scr_readw((u16 *) vc->vc_pos);
-	u32 type = vc->vc_cursor_type;
-
-	if (! (type & 0x10)) return;
-	if (softcursor_original != -1) return;
-	softcursor_original = i;
-	i |= ((type >> 8) & 0xff00 );
-	i ^= ((type) & 0xff00 );
-	if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
-	if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
-	scr_writew(i, (u16 *) vc->vc_pos);
-	if (DO_UPDATE(vc))
-		vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
-}
-
-static void hide_softcursor(struct vc_data *vc)
-{
-	if (softcursor_original != -1) {
-		scr_writew(softcursor_original, (u16 *)vc->vc_pos);
-		if (DO_UPDATE(vc))
-			vc->vc_sw->con_putc(vc, softcursor_original,
-					vc->vc_y, vc->vc_x);
-		softcursor_original = -1;
-	}
-}
-
-static void hide_cursor(struct vc_data *vc)
-{
-	if (vc == sel_cons)
-		clear_selection();
-	vc->vc_sw->con_cursor(vc, CM_ERASE);
-	hide_softcursor(vc);
-}
-
-static void set_cursor(struct vc_data *vc)
-{
-	if (!IS_FG(vc) || console_blanked ||
-	    vc->vc_mode == KD_GRAPHICS)
-		return;
-	if (vc->vc_deccm) {
-		if (vc == sel_cons)
-			clear_selection();
-		add_softcursor(vc);
-		if ((vc->vc_cursor_type & 0x0f) != 1)
-			vc->vc_sw->con_cursor(vc, CM_DRAW);
-	} else
-		hide_cursor(vc);
-}
-
-static void set_origin(struct vc_data *vc)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (!CON_IS_VISIBLE(vc) ||
-	    !vc->vc_sw->con_set_origin ||
-	    !vc->vc_sw->con_set_origin(vc))
-		vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-	vc->vc_visible_origin = vc->vc_origin;
-	vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
-	vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
-}
-
-static inline void save_screen(struct vc_data *vc)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (vc->vc_sw->con_save_screen)
-		vc->vc_sw->con_save_screen(vc);
-}
-
-/*
- *	Redrawing of screen
- */
-
-static void clear_buffer_attributes(struct vc_data *vc)
-{
-	unsigned short *p = (unsigned short *)vc->vc_origin;
-	int count = vc->vc_screenbuf_size / 2;
-	int mask = vc->vc_hi_font_mask | 0xff;
-
-	for (; count > 0; count--, p++) {
-		scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
-	}
-}
-
-void redraw_screen(struct vc_data *vc, int is_switch)
-{
-	int redraw = 0;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	if (!vc) {
-		/* strange ... */
-		/* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
-		return;
-	}
-
-	if (is_switch) {
-		struct vc_data *old_vc = vc_cons[fg_console].d;
-		if (old_vc == vc)
-			return;
-		if (!CON_IS_VISIBLE(vc))
-			redraw = 1;
-		*vc->vc_display_fg = vc;
-		fg_console = vc->vc_num;
-		hide_cursor(old_vc);
-		if (!CON_IS_VISIBLE(old_vc)) {
-			save_screen(old_vc);
-			set_origin(old_vc);
-		}
-	} else {
-		hide_cursor(vc);
-		redraw = 1;
-	}
-
-	if (redraw) {
-		int update;
-		int old_was_color = vc->vc_can_do_color;
-
-		set_origin(vc);
-		update = vc->vc_sw->con_switch(vc);
-		set_palette(vc);
-		/*
-		 * If console changed from mono<->color, the best we can do
-		 * is to clear the buffer attributes. As it currently stands,
-		 * rebuilding new attributes from the old buffer is not doable
-		 * without overly complex code.
-		 */
-		if (old_was_color != vc->vc_can_do_color) {
-			update_attr(vc);
-			clear_buffer_attributes(vc);
-		}
-
-		/* Forcibly update if we're panicing */
-		if ((update && vc->vc_mode != KD_GRAPHICS) ||
-		    vt_force_oops_output(vc))
-			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-	}
-	set_cursor(vc);
-	if (is_switch) {
-		set_leds();
-		compute_shiftstate();
-		notify_update(vc);
-	}
-}
-
-/*
- *	Allocation, freeing and resizing of VTs.
- */
-
-int vc_cons_allocated(unsigned int i)
-{
-	return (i < MAX_NR_CONSOLES && vc_cons[i].d);
-}
-
-static void visual_init(struct vc_data *vc, int num, int init)
-{
-	/* ++Geert: vc->vc_sw->con_init determines console size */
-	if (vc->vc_sw)
-		module_put(vc->vc_sw->owner);
-	vc->vc_sw = conswitchp;
-#ifndef VT_SINGLE_DRIVER
-	if (con_driver_map[num])
-		vc->vc_sw = con_driver_map[num];
-#endif
-	__module_get(vc->vc_sw->owner);
-	vc->vc_num = num;
-	vc->vc_display_fg = &master_display_fg;
-	vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
-	vc->vc_uni_pagedir = 0;
-	vc->vc_hi_font_mask = 0;
-	vc->vc_complement_mask = 0;
-	vc->vc_can_do_color = 0;
-	vc->vc_panic_force_write = false;
-	vc->vc_sw->con_init(vc, init);
-	if (!vc->vc_complement_mask)
-		vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
-	vc->vc_s_complement_mask = vc->vc_complement_mask;
-	vc->vc_size_row = vc->vc_cols << 1;
-	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-}
-
-int vc_allocate(unsigned int currcons)	/* return 0 on success */
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (currcons >= MAX_NR_CONSOLES)
-		return -ENXIO;
-	if (!vc_cons[currcons].d) {
-	    struct vc_data *vc;
-	    struct vt_notifier_param param;
-
-	    /* prevent users from taking too much memory */
-	    if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
-	      return -EPERM;
-
-	    /* due to the granularity of kmalloc, we waste some memory here */
-	    /* the alloc is done in two steps, to optimize the common situation
-	       of a 25x80 console (structsize=216, screenbuf_size=4000) */
-	    /* although the numbers above are not valid since long ago, the
-	       point is still up-to-date and the comment still has its value
-	       even if only as a historical artifact.  --mj, July 1998 */
-	    param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
-	    if (!vc)
-		return -ENOMEM;
-	    vc_cons[currcons].d = vc;
-	    tty_port_init(&vc->port);
-	    INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-	    visual_init(vc, currcons, 1);
-	    if (!*vc->vc_uni_pagedir_loc)
-		con_set_default_unimap(vc);
-	    vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
-	    if (!vc->vc_screenbuf) {
-		kfree(vc);
-		vc_cons[currcons].d = NULL;
-		return -ENOMEM;
-	    }
-
-	    /* If no drivers have overridden us and the user didn't pass a
-	       boot option, default to displaying the cursor */
-	    if (global_cursor_default == -1)
-		    global_cursor_default = 1;
-
-	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-	    vcs_make_sysfs(currcons);
-	    atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
-	}
-	return 0;
-}
-
-static inline int resize_screen(struct vc_data *vc, int width, int height,
-				int user)
-{
-	/* Resizes the resolution of the display adapater */
-	int err = 0;
-
-	if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
-		err = vc->vc_sw->con_resize(vc, width, height, user);
-
-	return err;
-}
-
-/*
- * Change # of rows and columns (0 means unchanged/the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-#define VC_RESIZE_MAXCOL (32767)
-#define VC_RESIZE_MAXROW (32767)
-
-/**
- *	vc_do_resize	-	resizing method for the tty
- *	@tty: tty being resized
- *	@real_tty: real tty (different to tty if a pty/tty pair)
- *	@vc: virtual console private data
- *	@cols: columns
- *	@lines: lines
- *
- *	Resize a virtual console, clipping according to the actual constraints.
- *	If the caller passes a tty structure then update the termios winsize
- *	information and perform any necessary signal handling.
- *
- *	Caller must hold the console semaphore. Takes the termios mutex and
- *	ctrl_lock of the tty IFF a tty is passed.
- */
-
-static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-				unsigned int cols, unsigned int lines)
-{
-	unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
-	unsigned long end;
-	unsigned int old_cols, old_rows, old_row_size, old_screen_size;
-	unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-	unsigned int user;
-	unsigned short *newscreen;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	if (!vc)
-		return -ENXIO;
-
-	user = vc->vc_resize_user;
-	vc->vc_resize_user = 0;
-
-	if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
-		return -EINVAL;
-
-	new_cols = (cols ? cols : vc->vc_cols);
-	new_rows = (lines ? lines : vc->vc_rows);
-	new_row_size = new_cols << 1;
-	new_screen_size = new_row_size * new_rows;
-
-	if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
-		return 0;
-
-	newscreen = kmalloc(new_screen_size, GFP_USER);
-	if (!newscreen)
-		return -ENOMEM;
-
-	old_rows = vc->vc_rows;
-	old_cols = vc->vc_cols;
-	old_row_size = vc->vc_size_row;
-	old_screen_size = vc->vc_screenbuf_size;
-
-	err = resize_screen(vc, new_cols, new_rows, user);
-	if (err) {
-		kfree(newscreen);
-		return err;
-	}
-
-	vc->vc_rows = new_rows;
-	vc->vc_cols = new_cols;
-	vc->vc_size_row = new_row_size;
-	vc->vc_screenbuf_size = new_screen_size;
-
-	rlth = min(old_row_size, new_row_size);
-	rrem = new_row_size - rlth;
-	old_origin = vc->vc_origin;
-	new_origin = (long) newscreen;
-	new_scr_end = new_origin + new_screen_size;
-
-	if (vc->vc_y > new_rows) {
-		if (old_rows - vc->vc_y < new_rows) {
-			/*
-			 * Cursor near the bottom, copy contents from the
-			 * bottom of buffer
-			 */
-			old_origin += (old_rows - new_rows) * old_row_size;
-		} else {
-			/*
-			 * Cursor is in no man's land, copy 1/2 screenful
-			 * from the top and bottom of cursor position
-			 */
-			old_origin += (vc->vc_y - new_rows/2) * old_row_size;
-		}
-	}
-
-	end = old_origin + old_row_size * min(old_rows, new_rows);
-
-	update_attr(vc);
-
-	while (old_origin < end) {
-		scr_memcpyw((unsigned short *) new_origin,
-			    (unsigned short *) old_origin, rlth);
-		if (rrem)
-			scr_memsetw((void *)(new_origin + rlth),
-				    vc->vc_video_erase_char, rrem);
-		old_origin += old_row_size;
-		new_origin += new_row_size;
-	}
-	if (new_scr_end > new_origin)
-		scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
-			    new_scr_end - new_origin);
-	kfree(vc->vc_screenbuf);
-	vc->vc_screenbuf = newscreen;
-	vc->vc_screenbuf_size = new_screen_size;
-	set_origin(vc);
-
-	/* do part of a reset_terminal() */
-	vc->vc_top = 0;
-	vc->vc_bottom = vc->vc_rows;
-	gotoxy(vc, vc->vc_x, vc->vc_y);
-	save_cur(vc);
-
-	if (tty) {
-		/* Rewrite the requested winsize data with the actual
-		   resulting sizes */
-		struct winsize ws;
-		memset(&ws, 0, sizeof(ws));
-		ws.ws_row = vc->vc_rows;
-		ws.ws_col = vc->vc_cols;
-		ws.ws_ypixel = vc->vc_scan_lines;
-		tty_do_resize(tty, &ws);
-	}
-
-	if (CON_IS_VISIBLE(vc))
-		update_screen(vc);
-	vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
-	return err;
-}
-
-/**
- *	vc_resize		-	resize a VT
- *	@vc: virtual console
- *	@cols: columns
- *	@rows: rows
- *
- *	Resize a virtual console as seen from the console end of things. We
- *	use the common vc_do_resize methods to update the structures. The
- *	caller must hold the console sem to protect console internals and
- *	vc->port.tty
- */
-
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
-{
-	return vc_do_resize(vc->port.tty, vc, cols, rows);
-}
-
-/**
- *	vt_resize		-	resize a VT
- *	@tty: tty to resize
- *	@ws: winsize attributes
- *
- *	Resize a virtual terminal. This is called by the tty layer as we
- *	register our own handler for resizing. The mutual helper does all
- *	the actual work.
- *
- *	Takes the console sem and the called methods then take the tty
- *	termios_mutex and the tty ctrl_lock in that order.
- */
-static int vt_resize(struct tty_struct *tty, struct winsize *ws)
-{
-	struct vc_data *vc = tty->driver_data;
-	int ret;
-
-	acquire_console_sem();
-	ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-	release_console_sem();
-	return ret;
-}
-
-void vc_deallocate(unsigned int currcons)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (vc_cons_allocated(currcons)) {
-		struct vc_data *vc = vc_cons[currcons].d;
-		struct vt_notifier_param param = { .vc = vc };
-
-		atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
-		vcs_remove_sysfs(currcons);
-		vc->vc_sw->con_deinit(vc);
-		put_pid(vc->vt_pid);
-		module_put(vc->vc_sw->owner);
-		kfree(vc->vc_screenbuf);
-		if (currcons >= MIN_NR_CONSOLES)
-			kfree(vc);
-		vc_cons[currcons].d = NULL;
-	}
-}
-
-/*
- *	VT102 emulator
- */
-
-#define set_kbd(vc, x)	set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x)	clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)	vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-
-#define decarm		VC_REPEAT
-#define decckm		VC_CKMODE
-#define kbdapplic	VC_APPLIC
-#define lnm		VC_CRLF
-
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
-				       8,12,10,14, 9,13,11,15 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
-
-/*
- * gotoxy() must verify all boundaries, because the arguments
- * might also be negative. If the given position is out of
- * bounds, the cursor is placed at the nearest margin.
- */
-static void gotoxy(struct vc_data *vc, int new_x, int new_y)
-{
-	int min_y, max_y;
-
-	if (new_x < 0)
-		vc->vc_x = 0;
-	else {
-		if (new_x >= vc->vc_cols)
-			vc->vc_x = vc->vc_cols - 1;
-		else
-			vc->vc_x = new_x;
-	}
-
- 	if (vc->vc_decom) {
-		min_y = vc->vc_top;
-		max_y = vc->vc_bottom;
-	} else {
-		min_y = 0;
-		max_y = vc->vc_rows;
-	}
-	if (new_y < min_y)
-		vc->vc_y = min_y;
-	else if (new_y >= max_y)
-		vc->vc_y = max_y - 1;
-	else
-		vc->vc_y = new_y;
-	vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
-	vc->vc_need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(struct vc_data *vc, int new_x, int new_y)
-{
-	gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
-}
-
-void scrollback(struct vc_data *vc, int lines)
-{
-	if (!lines)
-		lines = vc->vc_rows / 2;
-	scrolldelta(-lines);
-}
-
-void scrollfront(struct vc_data *vc, int lines)
-{
-	if (!lines)
-		lines = vc->vc_rows / 2;
-	scrolldelta(lines);
-}
-
-static void lf(struct vc_data *vc)
-{
-    	/* don't scroll if above bottom of scrolling region, or
-	 * if below scrolling region
-	 */
-    	if (vc->vc_y + 1 == vc->vc_bottom)
-		scrup(vc, vc->vc_top, vc->vc_bottom, 1);
-	else if (vc->vc_y < vc->vc_rows - 1) {
-	    	vc->vc_y++;
-		vc->vc_pos += vc->vc_size_row;
-	}
-	vc->vc_need_wrap = 0;
-	notify_write(vc, '\n');
-}
-
-static void ri(struct vc_data *vc)
-{
-    	/* don't scroll if below top of scrolling region, or
-	 * if above scrolling region
-	 */
-	if (vc->vc_y == vc->vc_top)
-		scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
-	else if (vc->vc_y > 0) {
-		vc->vc_y--;
-		vc->vc_pos -= vc->vc_size_row;
-	}
-	vc->vc_need_wrap = 0;
-}
-
-static inline void cr(struct vc_data *vc)
-{
-	vc->vc_pos -= vc->vc_x << 1;
-	vc->vc_need_wrap = vc->vc_x = 0;
-	notify_write(vc, '\r');
-}
-
-static inline void bs(struct vc_data *vc)
-{
-	if (vc->vc_x) {
-		vc->vc_pos -= 2;
-		vc->vc_x--;
-		vc->vc_need_wrap = 0;
-		notify_write(vc, '\b');
-	}
-}
-
-static inline void del(struct vc_data *vc)
-{
-	/* ignored */
-}
-
-static void csi_J(struct vc_data *vc, int vpar)
-{
-	unsigned int count;
-	unsigned short * start;
-
-	switch (vpar) {
-		case 0:	/* erase from cursor to end of display */
-			count = (vc->vc_scr_end - vc->vc_pos) >> 1;
-			start = (unsigned short *)vc->vc_pos;
-			if (DO_UPDATE(vc)) {
-				/* do in two stages */
-				vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-					      vc->vc_cols - vc->vc_x);
-				vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
-					      vc->vc_rows - vc->vc_y - 1,
-					      vc->vc_cols);
-			}
-			break;
-		case 1:	/* erase from start to cursor */
-			count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
-			start = (unsigned short *)vc->vc_origin;
-			if (DO_UPDATE(vc)) {
-				/* do in two stages */
-				vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
-					      vc->vc_cols);
-				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-					      vc->vc_x + 1);
-			}
-			break;
-		case 2: /* erase whole display */
-			count = vc->vc_cols * vc->vc_rows;
-			start = (unsigned short *)vc->vc_origin;
-			if (DO_UPDATE(vc))
-				vc->vc_sw->con_clear(vc, 0, 0,
-					      vc->vc_rows,
-					      vc->vc_cols);
-			break;
-		default:
-			return;
-	}
-	scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-	vc->vc_need_wrap = 0;
-}
-
-static void csi_K(struct vc_data *vc, int vpar)
-{
-	unsigned int count;
-	unsigned short * start;
-
-	switch (vpar) {
-		case 0:	/* erase from cursor to end of line */
-			count = vc->vc_cols - vc->vc_x;
-			start = (unsigned short *)vc->vc_pos;
-			if (DO_UPDATE(vc))
-				vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-						     vc->vc_cols - vc->vc_x);
-			break;
-		case 1:	/* erase from start of line to cursor */
-			start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-			count = vc->vc_x + 1;
-			if (DO_UPDATE(vc))
-				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-						     vc->vc_x + 1);
-			break;
-		case 2: /* erase whole line */
-			start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-			count = vc->vc_cols;
-			if (DO_UPDATE(vc))
-				vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-					      vc->vc_cols);
-			break;
-		default:
-			return;
-	}
-	scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-	vc->vc_need_wrap = 0;
-}
-
-static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
-{					  /* not vt100? */
-	int count;
-
-	if (!vpar)
-		vpar++;
-	count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
-
-	scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
-	if (DO_UPDATE(vc))
-		vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
-	vc->vc_need_wrap = 0;
-}
-
-static void default_attr(struct vc_data *vc)
-{
-	vc->vc_intensity = 1;
-	vc->vc_italic = 0;
-	vc->vc_underline = 0;
-	vc->vc_reverse = 0;
-	vc->vc_blink = 0;
-	vc->vc_color = vc->vc_def_color;
-}
-
-/* console_sem is held */
-static void csi_m(struct vc_data *vc)
-{
-	int i;
-
-	for (i = 0; i <= vc->vc_npar; i++)
-		switch (vc->vc_par[i]) {
-			case 0:	/* all attributes off */
-				default_attr(vc);
-				break;
-			case 1:
-				vc->vc_intensity = 2;
-				break;
-			case 2:
-				vc->vc_intensity = 0;
-				break;
-			case 3:
-				vc->vc_italic = 1;
-				break;
-			case 4:
-				vc->vc_underline = 1;
-				break;
-			case 5:
-				vc->vc_blink = 1;
-				break;
-			case 7:
-				vc->vc_reverse = 1;
-				break;
-			case 10: /* ANSI X3.64-1979 (SCO-ish?)
-				  * Select primary font, don't display
-				  * control chars if defined, don't set
-				  * bit 8 on output.
-				  */
-				vc->vc_translate = set_translate(vc->vc_charset == 0
-						? vc->vc_G0_charset
-						: vc->vc_G1_charset, vc);
-				vc->vc_disp_ctrl = 0;
-				vc->vc_toggle_meta = 0;
-				break;
-			case 11: /* ANSI X3.64-1979 (SCO-ish?)
-				  * Select first alternate font, lets
-				  * chars < 32 be displayed as ROM chars.
-				  */
-				vc->vc_translate = set_translate(IBMPC_MAP, vc);
-				vc->vc_disp_ctrl = 1;
-				vc->vc_toggle_meta = 0;
-				break;
-			case 12: /* ANSI X3.64-1979 (SCO-ish?)
-				  * Select second alternate font, toggle
-				  * high bit before displaying as ROM char.
-				  */
-				vc->vc_translate = set_translate(IBMPC_MAP, vc);
-				vc->vc_disp_ctrl = 1;
-				vc->vc_toggle_meta = 1;
-				break;
-			case 21:
-			case 22:
-				vc->vc_intensity = 1;
-				break;
-			case 23:
-				vc->vc_italic = 0;
-				break;
-			case 24:
-				vc->vc_underline = 0;
-				break;
-			case 25:
-				vc->vc_blink = 0;
-				break;
-			case 27:
-				vc->vc_reverse = 0;
-				break;
-			case 38: /* ANSI X3.64-1979 (SCO-ish?)
-				  * Enables underscore, white foreground
-				  * with white underscore (Linux - use
-				  * default foreground).
-				  */
-				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-				vc->vc_underline = 1;
-				break;
-			case 39: /* ANSI X3.64-1979 (SCO-ish?)
-				  * Disable underline option.
-				  * Reset colour to default? It did this
-				  * before...
-				  */
-				vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-				vc->vc_underline = 0;
-				break;
-			case 49:
-				vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
-				break;
-			default:
-				if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-					vc->vc_color = color_table[vc->vc_par[i] - 30]
-						| (vc->vc_color & 0xf0);
-				else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
-					vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
-						| (vc->vc_color & 0x0f);
-				break;
-		}
-	update_attr(vc);
-}
-
-static void respond_string(const char *p, struct tty_struct *tty)
-{
-	while (*p) {
-		tty_insert_flip_char(tty, *p, 0);
-		p++;
-	}
-	con_schedule_flip(tty);
-}
-
-static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
-{
-	char buf[40];
-
-	sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
-	respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct *tty)
-{
-	respond_string("\033[0n", tty);	/* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
-	respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
-{
-	char buf[8];
-
-	sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
-		(char)('!' + mry));
-	respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
-	return vc_cons[fg_console].d->vc_report_mouse;
-}
-
-/* console_sem is held */
-static void set_mode(struct vc_data *vc, int on_off)
-{
-	int i;
-
-	for (i = 0; i <= vc->vc_npar; i++)
-		if (vc->vc_ques) {
-			switch(vc->vc_par[i]) {	/* DEC private modes set/reset */
-			case 1:			/* Cursor keys send ^[Ox/^[[x */
-				if (on_off)
-					set_kbd(vc, decckm);
-				else
-					clr_kbd(vc, decckm);
-				break;
-			case 3:	/* 80/132 mode switch unimplemented */
-				vc->vc_deccolm = on_off;
-#if 0
-				vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-				/* this alone does not suffice; some user mode
-				   utility has to change the hardware regs */
-#endif
-				break;
-			case 5:			/* Inverted screen on/off */
-				if (vc->vc_decscnm != on_off) {
-					vc->vc_decscnm = on_off;
-					invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
-					update_attr(vc);
-				}
-				break;
-			case 6:			/* Origin relative/absolute */
-				vc->vc_decom = on_off;
-				gotoxay(vc, 0, 0);
-				break;
-			case 7:			/* Autowrap on/off */
-				vc->vc_decawm = on_off;
-				break;
-			case 8:			/* Autorepeat on/off */
-				if (on_off)
-					set_kbd(vc, decarm);
-				else
-					clr_kbd(vc, decarm);
-				break;
-			case 9:
-				vc->vc_report_mouse = on_off ? 1 : 0;
-				break;
-			case 25:		/* Cursor on/off */
-				vc->vc_deccm = on_off;
-				break;
-			case 1000:
-				vc->vc_report_mouse = on_off ? 2 : 0;
-				break;
-			}
-		} else {
-			switch(vc->vc_par[i]) {	/* ANSI modes set/reset */
-			case 3:			/* Monitor (display ctrls) */
-				vc->vc_disp_ctrl = on_off;
-				break;
-			case 4:			/* Insert Mode on/off */
-				vc->vc_decim = on_off;
-				break;
-			case 20:		/* Lf, Enter == CrLf/Lf */
-				if (on_off)
-					set_kbd(vc, lnm);
-				else
-					clr_kbd(vc, lnm);
-				break;
-			}
-		}
-}
-
-/* console_sem is held */
-static void setterm_command(struct vc_data *vc)
-{
-	switch(vc->vc_par[0]) {
-		case 1:	/* set color for underline mode */
-			if (vc->vc_can_do_color &&
-					vc->vc_par[1] < 16) {
-				vc->vc_ulcolor = color_table[vc->vc_par[1]];
-				if (vc->vc_underline)
-					update_attr(vc);
-			}
-			break;
-		case 2:	/* set color for half intensity mode */
-			if (vc->vc_can_do_color &&
-					vc->vc_par[1] < 16) {
-				vc->vc_halfcolor = color_table[vc->vc_par[1]];
-				if (vc->vc_intensity == 0)
-					update_attr(vc);
-			}
-			break;
-		case 8:	/* store colors as defaults */
-			vc->vc_def_color = vc->vc_attr;
-			if (vc->vc_hi_font_mask == 0x100)
-				vc->vc_def_color >>= 1;
-			default_attr(vc);
-			update_attr(vc);
-			break;
-		case 9:	/* set blanking interval */
-			blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
-			poke_blanked_console();
-			break;
-		case 10: /* set bell frequency in Hz */
-			if (vc->vc_npar >= 1)
-				vc->vc_bell_pitch = vc->vc_par[1];
-			else
-				vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-			break;
-		case 11: /* set bell duration in msec */
-			if (vc->vc_npar >= 1)
-				vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
-					vc->vc_par[1] * HZ / 1000 : 0;
-			else
-				vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-			break;
-		case 12: /* bring specified console to the front */
-			if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
-				set_console(vc->vc_par[1] - 1);
-			break;
-		case 13: /* unblank the screen */
-			poke_blanked_console();
-			break;
-		case 14: /* set vesa powerdown interval */
-			vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
-			break;
-		case 15: /* activate the previous console */
-			set_console(last_console);
-			break;
-	}
-}
-
-/* console_sem is held */
-static void csi_at(struct vc_data *vc, unsigned int nr)
-{
-	if (nr > vc->vc_cols - vc->vc_x)
-		nr = vc->vc_cols - vc->vc_x;
-	else if (!nr)
-		nr = 1;
-	insert_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_L(struct vc_data *vc, unsigned int nr)
-{
-	if (nr > vc->vc_rows - vc->vc_y)
-		nr = vc->vc_rows - vc->vc_y;
-	else if (!nr)
-		nr = 1;
-	scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
-	vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held */
-static void csi_P(struct vc_data *vc, unsigned int nr)
-{
-	if (nr > vc->vc_cols - vc->vc_x)
-		nr = vc->vc_cols - vc->vc_x;
-	else if (!nr)
-		nr = 1;
-	delete_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_M(struct vc_data *vc, unsigned int nr)
-{
-	if (nr > vc->vc_rows - vc->vc_y)
-		nr = vc->vc_rows - vc->vc_y;
-	else if (!nr)
-		nr=1;
-	scrup(vc, vc->vc_y, vc->vc_bottom, nr);
-	vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(struct vc_data *vc)
-{
-	vc->vc_saved_x		= vc->vc_x;
-	vc->vc_saved_y		= vc->vc_y;
-	vc->vc_s_intensity	= vc->vc_intensity;
-	vc->vc_s_italic         = vc->vc_italic;
-	vc->vc_s_underline	= vc->vc_underline;
-	vc->vc_s_blink		= vc->vc_blink;
-	vc->vc_s_reverse	= vc->vc_reverse;
-	vc->vc_s_charset	= vc->vc_charset;
-	vc->vc_s_color		= vc->vc_color;
-	vc->vc_saved_G0		= vc->vc_G0_charset;
-	vc->vc_saved_G1		= vc->vc_G1_charset;
-}
-
-/* console_sem is held */
-static void restore_cur(struct vc_data *vc)
-{
-	gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
-	vc->vc_intensity	= vc->vc_s_intensity;
-	vc->vc_italic		= vc->vc_s_italic;
-	vc->vc_underline	= vc->vc_s_underline;
-	vc->vc_blink		= vc->vc_s_blink;
-	vc->vc_reverse		= vc->vc_s_reverse;
-	vc->vc_charset		= vc->vc_s_charset;
-	vc->vc_color		= vc->vc_s_color;
-	vc->vc_G0_charset	= vc->vc_saved_G0;
-	vc->vc_G1_charset	= vc->vc_saved_G1;
-	vc->vc_translate	= set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
-	update_attr(vc);
-	vc->vc_need_wrap = 0;
-}
-
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
-	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
-	ESpalette };
-
-/* console_sem is held (except via vc_init()) */
-static void reset_terminal(struct vc_data *vc, int do_clear)
-{
-	vc->vc_top		= 0;
-	vc->vc_bottom		= vc->vc_rows;
-	vc->vc_state		= ESnormal;
-	vc->vc_ques		= 0;
-	vc->vc_translate	= set_translate(LAT1_MAP, vc);
-	vc->vc_G0_charset	= LAT1_MAP;
-	vc->vc_G1_charset	= GRAF_MAP;
-	vc->vc_charset		= 0;
-	vc->vc_need_wrap	= 0;
-	vc->vc_report_mouse	= 0;
-	vc->vc_utf              = default_utf8;
-	vc->vc_utf_count	= 0;
-
-	vc->vc_disp_ctrl	= 0;
-	vc->vc_toggle_meta	= 0;
-
-	vc->vc_decscnm		= 0;
-	vc->vc_decom		= 0;
-	vc->vc_decawm		= 1;
-	vc->vc_deccm		= global_cursor_default;
-	vc->vc_decim		= 0;
-
-	set_kbd(vc, decarm);
-	clr_kbd(vc, decckm);
-	clr_kbd(vc, kbdapplic);
-	clr_kbd(vc, lnm);
-	kbd_table[vc->vc_num].lockstate = 0;
-	kbd_table[vc->vc_num].slockstate = 0;
-	kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-	kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-	/* do not do set_leds here because this causes an endless tasklet loop
-	   when the keyboard hasn't been initialized yet */
-
-	vc->vc_cursor_type = cur_default;
-	vc->vc_complement_mask = vc->vc_s_complement_mask;
-
-	default_attr(vc);
-	update_attr(vc);
-
-	vc->vc_tab_stop[0]	= 0x01010100;
-	vc->vc_tab_stop[1]	=
-	vc->vc_tab_stop[2]	=
-	vc->vc_tab_stop[3]	=
-	vc->vc_tab_stop[4]	=
-	vc->vc_tab_stop[5]	=
-	vc->vc_tab_stop[6]	=
-	vc->vc_tab_stop[7]	= 0x01010101;
-
-	vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-	vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-
-	gotoxy(vc, 0, 0);
-	save_cur(vc);
-	if (do_clear)
-	    csi_J(vc, 2);
-}
-
-/* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
-{
-	/*
-	 *  Control characters can be used in the _middle_
-	 *  of an escape sequence.
-	 */
-	switch (c) {
-	case 0:
-		return;
-	case 7:
-		if (vc->vc_bell_duration)
-			kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-		return;
-	case 8:
-		bs(vc);
-		return;
-	case 9:
-		vc->vc_pos -= (vc->vc_x << 1);
-		while (vc->vc_x < vc->vc_cols - 1) {
-			vc->vc_x++;
-			if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
-				break;
-		}
-		vc->vc_pos += (vc->vc_x << 1);
-		notify_write(vc, '\t');
-		return;
-	case 10: case 11: case 12:
-		lf(vc);
-		if (!is_kbd(vc, lnm))
-			return;
-	case 13:
-		cr(vc);
-		return;
-	case 14:
-		vc->vc_charset = 1;
-		vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-		vc->vc_disp_ctrl = 1;
-		return;
-	case 15:
-		vc->vc_charset = 0;
-		vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-		vc->vc_disp_ctrl = 0;
-		return;
-	case 24: case 26:
-		vc->vc_state = ESnormal;
-		return;
-	case 27:
-		vc->vc_state = ESesc;
-		return;
-	case 127:
-		del(vc);
-		return;
-	case 128+27:
-		vc->vc_state = ESsquare;
-		return;
-	}
-	switch(vc->vc_state) {
-	case ESesc:
-		vc->vc_state = ESnormal;
-		switch (c) {
-		case '[':
-			vc->vc_state = ESsquare;
-			return;
-		case ']':
-			vc->vc_state = ESnonstd;
-			return;
-		case '%':
-			vc->vc_state = ESpercent;
-			return;
-		case 'E':
-			cr(vc);
-			lf(vc);
-			return;
-		case 'M':
-			ri(vc);
-			return;
-		case 'D':
-			lf(vc);
-			return;
-		case 'H':
-			vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
-			return;
-		case 'Z':
-			respond_ID(tty);
-			return;
-		case '7':
-			save_cur(vc);
-			return;
-		case '8':
-			restore_cur(vc);
-			return;
-		case '(':
-			vc->vc_state = ESsetG0;
-			return;
-		case ')':
-			vc->vc_state = ESsetG1;
-			return;
-		case '#':
-			vc->vc_state = EShash;
-			return;
-		case 'c':
-			reset_terminal(vc, 1);
-			return;
-		case '>':  /* Numeric keypad */
-			clr_kbd(vc, kbdapplic);
-			return;
-		case '=':  /* Appl. keypad */
-			set_kbd(vc, kbdapplic);
-			return;
-		}
-		return;
-	case ESnonstd:
-		if (c=='P') {   /* palette escape sequence */
-			for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-				vc->vc_par[vc->vc_npar] = 0;
-			vc->vc_npar = 0;
-			vc->vc_state = ESpalette;
-			return;
-		} else if (c=='R') {   /* reset palette */
-			reset_palette(vc);
-			vc->vc_state = ESnormal;
-		} else
-			vc->vc_state = ESnormal;
-		return;
-	case ESpalette:
-		if (isxdigit(c)) {
-			vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
-			if (vc->vc_npar == 7) {
-				int i = vc->vc_par[0] * 3, j = 1;
-				vc->vc_palette[i] = 16 * vc->vc_par[j++];
-				vc->vc_palette[i++] += vc->vc_par[j++];
-				vc->vc_palette[i] = 16 * vc->vc_par[j++];
-				vc->vc_palette[i++] += vc->vc_par[j++];
-				vc->vc_palette[i] = 16 * vc->vc_par[j++];
-				vc->vc_palette[i] += vc->vc_par[j];
-				set_palette(vc);
-				vc->vc_state = ESnormal;
-			}
-		} else
-			vc->vc_state = ESnormal;
-		return;
-	case ESsquare:
-		for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-			vc->vc_par[vc->vc_npar] = 0;
-		vc->vc_npar = 0;
-		vc->vc_state = ESgetpars;
-		if (c == '[') { /* Function key */
-			vc->vc_state=ESfunckey;
-			return;
-		}
-		vc->vc_ques = (c == '?');
-		if (vc->vc_ques)
-			return;
-	case ESgetpars:
-		if (c == ';' && vc->vc_npar < NPAR - 1) {
-			vc->vc_npar++;
-			return;
-		} else if (c>='0' && c<='9') {
-			vc->vc_par[vc->vc_npar] *= 10;
-			vc->vc_par[vc->vc_npar] += c - '0';
-			return;
-		} else
-			vc->vc_state = ESgotpars;
-	case ESgotpars:
-		vc->vc_state = ESnormal;
-		switch(c) {
-		case 'h':
-			set_mode(vc, 1);
-			return;
-		case 'l':
-			set_mode(vc, 0);
-			return;
-		case 'c':
-			if (vc->vc_ques) {
-				if (vc->vc_par[0])
-					vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
-				else
-					vc->vc_cursor_type = cur_default;
-				return;
-			}
-			break;
-		case 'm':
-			if (vc->vc_ques) {
-				clear_selection();
-				if (vc->vc_par[0])
-					vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-				else
-					vc->vc_complement_mask = vc->vc_s_complement_mask;
-				return;
-			}
-			break;
-		case 'n':
-			if (!vc->vc_ques) {
-				if (vc->vc_par[0] == 5)
-					status_report(tty);
-				else if (vc->vc_par[0] == 6)
-					cursor_report(vc, tty);
-			}
-			return;
-		}
-		if (vc->vc_ques) {
-			vc->vc_ques = 0;
-			return;
-		}
-		switch(c) {
-		case 'G': case '`':
-			if (vc->vc_par[0])
-				vc->vc_par[0]--;
-			gotoxy(vc, vc->vc_par[0], vc->vc_y);
-			return;
-		case 'A':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
-			return;
-		case 'B': case 'e':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
-			return;
-		case 'C': case 'a':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
-			return;
-		case 'D':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
-			return;
-		case 'E':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
-			return;
-		case 'F':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
-			return;
-		case 'd':
-			if (vc->vc_par[0])
-				vc->vc_par[0]--;
-			gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
-			return;
-		case 'H': case 'f':
-			if (vc->vc_par[0])
-				vc->vc_par[0]--;
-			if (vc->vc_par[1])
-				vc->vc_par[1]--;
-			gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-			return;
-		case 'J':
-			csi_J(vc, vc->vc_par[0]);
-			return;
-		case 'K':
-			csi_K(vc, vc->vc_par[0]);
-			return;
-		case 'L':
-			csi_L(vc, vc->vc_par[0]);
-			return;
-		case 'M':
-			csi_M(vc, vc->vc_par[0]);
-			return;
-		case 'P':
-			csi_P(vc, vc->vc_par[0]);
-			return;
-		case 'c':
-			if (!vc->vc_par[0])
-				respond_ID(tty);
-			return;
-		case 'g':
-			if (!vc->vc_par[0])
-				vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
-			else if (vc->vc_par[0] == 3) {
-				vc->vc_tab_stop[0] =
-					vc->vc_tab_stop[1] =
-					vc->vc_tab_stop[2] =
-					vc->vc_tab_stop[3] =
-					vc->vc_tab_stop[4] =
-					vc->vc_tab_stop[5] =
-					vc->vc_tab_stop[6] =
-					vc->vc_tab_stop[7] = 0;
-			}
-			return;
-		case 'm':
-			csi_m(vc);
-			return;
-		case 'q': /* DECLL - but only 3 leds */
-			/* map 0,1,2,3 to 0,1,2,4 */
-			if (vc->vc_par[0] < 4)
-				setledstate(kbd_table + vc->vc_num,
-					    (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-			return;
-		case 'r':
-			if (!vc->vc_par[0])
-				vc->vc_par[0]++;
-			if (!vc->vc_par[1])
-				vc->vc_par[1] = vc->vc_rows;
-			/* Minimum allowed region is 2 lines */
-			if (vc->vc_par[0] < vc->vc_par[1] &&
-			    vc->vc_par[1] <= vc->vc_rows) {
-				vc->vc_top = vc->vc_par[0] - 1;
-				vc->vc_bottom = vc->vc_par[1];
-				gotoxay(vc, 0, 0);
-			}
-			return;
-		case 's':
-			save_cur(vc);
-			return;
-		case 'u':
-			restore_cur(vc);
-			return;
-		case 'X':
-			csi_X(vc, vc->vc_par[0]);
-			return;
-		case '@':
-			csi_at(vc, vc->vc_par[0]);
-			return;
-		case ']': /* setterm functions */
-			setterm_command(vc);
-			return;
-		}
-		return;
-	case ESpercent:
-		vc->vc_state = ESnormal;
-		switch (c) {
-		case '@':  /* defined in ISO 2022 */
-			vc->vc_utf = 0;
-			return;
-		case 'G':  /* prelim official escape code */
-		case '8':  /* retained for compatibility */
-			vc->vc_utf = 1;
-			return;
-		}
-		return;
-	case ESfunckey:
-		vc->vc_state = ESnormal;
-		return;
-	case EShash:
-		vc->vc_state = ESnormal;
-		if (c == '8') {
-			/* DEC screen alignment test. kludge :-) */
-			vc->vc_video_erase_char =
-				(vc->vc_video_erase_char & 0xff00) | 'E';
-			csi_J(vc, 2);
-			vc->vc_video_erase_char =
-				(vc->vc_video_erase_char & 0xff00) | ' ';
-			do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-		}
-		return;
-	case ESsetG0:
-		if (c == '0')
-			vc->vc_G0_charset = GRAF_MAP;
-		else if (c == 'B')
-			vc->vc_G0_charset = LAT1_MAP;
-		else if (c == 'U')
-			vc->vc_G0_charset = IBMPC_MAP;
-		else if (c == 'K')
-			vc->vc_G0_charset = USER_MAP;
-		if (vc->vc_charset == 0)
-			vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-		vc->vc_state = ESnormal;
-		return;
-	case ESsetG1:
-		if (c == '0')
-			vc->vc_G1_charset = GRAF_MAP;
-		else if (c == 'B')
-			vc->vc_G1_charset = LAT1_MAP;
-		else if (c == 'U')
-			vc->vc_G1_charset = IBMPC_MAP;
-		else if (c == 'K')
-			vc->vc_G1_charset = USER_MAP;
-		if (vc->vc_charset == 1)
-			vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-		vc->vc_state = ESnormal;
-		return;
-	default:
-		vc->vc_state = ESnormal;
-	}
-}
-
-/* This is a temporary buffer used to prepare a tty console write
- * so that we can easily avoid touching user space while holding the
- * console spinlock.  It is allocated in con_init and is shared by
- * this code and the vc_screen read/write tty calls.
- *
- * We have to allocate this statically in the kernel data section
- * since console_init (and thus con_init) are called before any
- * kernel memory allocation is available.
- */
-char con_buf[CON_BUF_SIZE];
-DEFINE_MUTEX(con_buf_mtx);
-
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
-	uint32_t first;
-	uint32_t last;
-};
-
-static int bisearch(uint32_t ucs, const struct interval *table, int max)
-{
-	int min = 0;
-	int mid;
-
-	if (ucs < table[0].first || ucs > table[max].last)
-		return 0;
-	while (max >= min) {
-		mid = (min + max) / 2;
-		if (ucs > table[mid].last)
-			min = mid + 1;
-		else if (ucs < table[mid].first)
-			max = mid - 1;
-		else
-			return 1;
-	}
-	return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
-	static const struct interval double_width[] = {
-		{ 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
-		{ 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
-		{ 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
-		{ 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
-	};
-	return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
-}
-
-/* acquires console_sem */
-static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-#ifdef VT_BUF_VRAM_ONLY
-#define FLUSH do { } while(0);
-#else
-#define FLUSH if (draw_x >= 0) { \
-	vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
-	draw_x = -1; \
-	}
-#endif
-
-	int c, tc, ok, n = 0, draw_x = -1;
-	unsigned int currcons;
-	unsigned long draw_from = 0, draw_to = 0;
-	struct vc_data *vc;
-	unsigned char vc_attr;
-	struct vt_notifier_param param;
-	uint8_t rescan;
-	uint8_t inverse;
-	uint8_t width;
-	u16 himask, charmask;
-
-	if (in_interrupt())
-		return count;
-
-	might_sleep();
-
-	acquire_console_sem();
-	vc = tty->driver_data;
-	if (vc == NULL) {
-		printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-		release_console_sem();
-		return 0;
-	}
-
-	currcons = vc->vc_num;
-	if (!vc_cons_allocated(currcons)) {
-	    /* could this happen? */
-		printk_once("con_write: tty %d not allocated\n", currcons+1);
-	    release_console_sem();
-	    return 0;
-	}
-
-	himask = vc->vc_hi_font_mask;
-	charmask = himask ? 0x1ff : 0xff;
-
-	/* undraw cursor first */
-	if (IS_FG(vc))
-		hide_cursor(vc);
-
-	param.vc = vc;
-
-	while (!tty->stopped && count) {
-		int orig = *buf;
-		c = orig;
-		buf++;
-		n++;
-		count--;
-		rescan = 0;
-		inverse = 0;
-		width = 1;
-
-		/* Do no translation at all in control states */
-		if (vc->vc_state != ESnormal) {
-			tc = c;
-		} else if (vc->vc_utf && !vc->vc_disp_ctrl) {
-		    /* Combine UTF-8 into Unicode in vc_utf_char.
-		     * vc_utf_count is the number of continuation bytes still
-		     * expected to arrive.
-		     * vc_npar is the number of continuation bytes arrived so
-		     * far
-		     */
-rescan_last_byte:
-		    if ((c & 0xc0) == 0x80) {
-			/* Continuation byte received */
-			static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
-			if (vc->vc_utf_count) {
-			    vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
-			    vc->vc_npar++;
-			    if (--vc->vc_utf_count) {
-				/* Still need some bytes */
-				continue;
-			    }
-			    /* Got a whole character */
-			    c = vc->vc_utf_char;
-			    /* Reject overlong sequences */
-			    if (c <= utf8_length_changes[vc->vc_npar - 1] ||
-					c > utf8_length_changes[vc->vc_npar])
-				c = 0xfffd;
-			} else {
-			    /* Unexpected continuation byte */
-			    vc->vc_utf_count = 0;
-			    c = 0xfffd;
-			}
-		    } else {
-			/* Single ASCII byte or first byte of a sequence received */
-			if (vc->vc_utf_count) {
-			    /* Continuation byte expected */
-			    rescan = 1;
-			    vc->vc_utf_count = 0;
-			    c = 0xfffd;
-			} else if (c > 0x7f) {
-			    /* First byte of a multibyte sequence received */
-			    vc->vc_npar = 0;
-			    if ((c & 0xe0) == 0xc0) {
-				vc->vc_utf_count = 1;
-				vc->vc_utf_char = (c & 0x1f);
-			    } else if ((c & 0xf0) == 0xe0) {
-				vc->vc_utf_count = 2;
-				vc->vc_utf_char = (c & 0x0f);
-			    } else if ((c & 0xf8) == 0xf0) {
-				vc->vc_utf_count = 3;
-				vc->vc_utf_char = (c & 0x07);
-			    } else if ((c & 0xfc) == 0xf8) {
-				vc->vc_utf_count = 4;
-				vc->vc_utf_char = (c & 0x03);
-			    } else if ((c & 0xfe) == 0xfc) {
-				vc->vc_utf_count = 5;
-				vc->vc_utf_char = (c & 0x01);
-			    } else {
-				/* 254 and 255 are invalid */
-				c = 0xfffd;
-			    }
-			    if (vc->vc_utf_count) {
-				/* Still need some bytes */
-				continue;
-			    }
-			}
-			/* Nothing to do if an ASCII byte was received */
-		    }
-		    /* End of UTF-8 decoding. */
-		    /* c is the received character, or U+FFFD for invalid sequences. */
-		    /* Replace invalid Unicode code points with U+FFFD too */
-		    if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
-			c = 0xfffd;
-		    tc = c;
-		} else {	/* no utf or alternate charset mode */
-		    tc = vc_translate(vc, c);
-		}
-
-		param.c = tc;
-		if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
-					&param) == NOTIFY_STOP)
-			continue;
-
-                /* If the original code was a control character we
-                 * only allow a glyph to be displayed if the code is
-                 * not normally used (such as for cursor movement) or
-                 * if the disp_ctrl mode has been explicitly enabled.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
-			    !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
-				  vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
-			&& (c != 127 || vc->vc_disp_ctrl)
-			&& (c != 128+27);
-
-		if (vc->vc_state == ESnormal && ok) {
-			if (vc->vc_utf && !vc->vc_disp_ctrl) {
-				if (is_double_width(c))
-					width = 2;
-			}
-			/* Now try to find out how to display it */
-			tc = conv_uni_to_pc(vc, tc);
-			if (tc & ~charmask) {
-				if (tc == -1 || tc == -2) {
-				    continue; /* nothing to display */
-				}
-				/* Glyph not found */
-				if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
-				    /* In legacy mode use the glyph we get by a 1:1 mapping.
-				       This would make absolutely no sense with Unicode in mind,
-				       but do this for ASCII characters since a font may lack
-				       Unicode mapping info and we don't want to end up with
-				       having question marks only. */
-				    tc = c;
-				} else {
-				    /* Display U+FFFD. If it's not found, display an inverse question mark. */
-				    tc = conv_uni_to_pc(vc, 0xfffd);
-				    if (tc < 0) {
-					inverse = 1;
-					tc = conv_uni_to_pc(vc, '?');
-					if (tc < 0) tc = '?';
-				    }
-				}
-			}
-
-			if (!inverse) {
-				vc_attr = vc->vc_attr;
-			} else {
-				/* invert vc_attr */
-				if (!vc->vc_can_do_color) {
-					vc_attr = (vc->vc_attr) ^ 0x08;
-				} else if (vc->vc_hi_font_mask == 0x100) {
-					vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
-				} else {
-					vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
-				}
-				FLUSH
-			}
-
-			while (1) {
-				if (vc->vc_need_wrap || vc->vc_decim)
-					FLUSH
-				if (vc->vc_need_wrap) {
-					cr(vc);
-					lf(vc);
-				}
-				if (vc->vc_decim)
-					insert_char(vc, 1);
-				scr_writew(himask ?
-					     ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-					     (vc_attr << 8) + tc,
-					   (u16 *) vc->vc_pos);
-				if (DO_UPDATE(vc) && draw_x < 0) {
-					draw_x = vc->vc_x;
-					draw_from = vc->vc_pos;
-				}
-				if (vc->vc_x == vc->vc_cols - 1) {
-					vc->vc_need_wrap = vc->vc_decawm;
-					draw_to = vc->vc_pos + 2;
-				} else {
-					vc->vc_x++;
-					draw_to = (vc->vc_pos += 2);
-				}
-
-				if (!--width) break;
-
-				tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
-				if (tc < 0) tc = ' ';
-			}
-			notify_write(vc, c);
-
-			if (inverse) {
-				FLUSH
-			}
-
-			if (rescan) {
-				rescan = 0;
-				inverse = 0;
-				width = 1;
-				c = orig;
-				goto rescan_last_byte;
-			}
-			continue;
-		}
-		FLUSH
-		do_con_trol(tty, vc, orig);
-	}
-	FLUSH
-	console_conditional_schedule();
-	release_console_sem();
-	notify_update(vc);
-	return n;
-#undef FLUSH
-}
-
-/*
- * This is the console switching callback.
- *
- * Doing console switching in a process context allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt).  Synchronization
- * with other console code and prevention of re-entrancy is
- * ensured with console_sem.
- */
-static void console_callback(struct work_struct *ignored)
-{
-	acquire_console_sem();
-
-	if (want_console >= 0) {
-		if (want_console != fg_console &&
-		    vc_cons_allocated(want_console)) {
-			hide_cursor(vc_cons[fg_console].d);
-			change_console(vc_cons[want_console].d);
-			/* we only changed when the console had already
-			   been allocated - a new console is not created
-			   in an interrupt routine */
-		}
-		want_console = -1;
-	}
-	if (do_poke_blanked_console) { /* do not unblank for a LED change */
-		do_poke_blanked_console = 0;
-		poke_blanked_console();
-	}
-	if (scrollback_delta) {
-		struct vc_data *vc = vc_cons[fg_console].d;
-		clear_selection();
-		if (vc->vc_mode == KD_TEXT)
-			vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
-		scrollback_delta = 0;
-	}
-	if (blank_timer_expired) {
-		do_blank_screen(0);
-		blank_timer_expired = 0;
-	}
-	notify_update(vc_cons[fg_console].d);
-
-	release_console_sem();
-}
-
-int set_console(int nr)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-
-	if (!vc_cons_allocated(nr) || vt_dont_switch ||
-		(vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
-
-		/*
-		 * Console switch will fail in console_callback() or
-		 * change_console() so there is no point scheduling
-		 * the callback
-		 *
-		 * Existing set_console() users don't check the return
-		 * value so this shouldn't break anything
-		 */
-		return -EINVAL;
-	}
-
-	want_console = nr;
-	schedule_console_callback();
-
-	return 0;
-}
-
-struct tty_driver *console_driver;
-
-#ifdef CONFIG_VT_CONSOLE
-
-/**
- * vt_kmsg_redirect() - Sets/gets the kernel message console
- * @new:	The new virtual terminal number or -1 if the console should stay
- * 		unchanged
- *
- * By default, the kernel messages are always printed on the current virtual
- * console. However, the user may modify that default with the
- * TIOCL_SETKMSGREDIRECT ioctl call.
- *
- * This function sets the kernel message console to be @new. It returns the old
- * virtual console number. The virtual terminal number 0 (both as parameter and
- * return value) means no redirection (i.e. always printed on the currently
- * active console).
- *
- * The parameter -1 means that only the current console is returned, but the
- * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
- * case to make the code more understandable.
- *
- * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
- * the parameter and always returns 0.
- */
-int vt_kmsg_redirect(int new)
-{
-	static int kmsg_con;
-
-	if (new != -1)
-		return xchg(&kmsg_con, new);
-	else
-		return kmsg_con;
-}
-
-/*
- *	Console on virtual terminal
- *
- * The console must be locked when we get here.
- */
-
-static void vt_console_print(struct console *co, const char *b, unsigned count)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-	unsigned char c;
-	static DEFINE_SPINLOCK(printing_lock);
-	const ushort *start;
-	ushort cnt = 0;
-	ushort myx;
-	int kmsg_console;
-
-	/* console busy or not yet initialized */
-	if (!printable)
-		return;
-	if (!spin_trylock(&printing_lock))
-		return;
-
-	kmsg_console = vt_get_kmsg_redirect();
-	if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
-		vc = vc_cons[kmsg_console - 1].d;
-
-	/* read `x' only after setting currcons properly (otherwise
-	   the `x' macro will read the x of the foreground console). */
-	myx = vc->vc_x;
-
-	if (!vc_cons_allocated(fg_console)) {
-		/* impossible */
-		/* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
-		goto quit;
-	}
-
-	if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-		goto quit;
-
-	/* undraw cursor first */
-	if (IS_FG(vc))
-		hide_cursor(vc);
-
-	start = (ushort *)vc->vc_pos;
-
-	/* Contrived structure to try to emulate original need_wrap behaviour
-	 * Problems caused when we have need_wrap set on '\n' character */
-	while (count--) {
-		c = *b++;
-		if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
-			if (cnt > 0) {
-				if (CON_IS_VISIBLE(vc))
-					vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-				vc->vc_x += cnt;
-				if (vc->vc_need_wrap)
-					vc->vc_x--;
-				cnt = 0;
-			}
-			if (c == 8) {		/* backspace */
-				bs(vc);
-				start = (ushort *)vc->vc_pos;
-				myx = vc->vc_x;
-				continue;
-			}
-			if (c != 13)
-				lf(vc);
-			cr(vc);
-			start = (ushort *)vc->vc_pos;
-			myx = vc->vc_x;
-			if (c == 10 || c == 13)
-				continue;
-		}
-		scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
-		notify_write(vc, c);
-		cnt++;
-		if (myx == vc->vc_cols - 1) {
-			vc->vc_need_wrap = 1;
-			continue;
-		}
-		vc->vc_pos += 2;
-		myx++;
-	}
-	if (cnt > 0) {
-		if (CON_IS_VISIBLE(vc))
-			vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-		vc->vc_x += cnt;
-		if (vc->vc_x == vc->vc_cols) {
-			vc->vc_x--;
-			vc->vc_need_wrap = 1;
-		}
-	}
-	set_cursor(vc);
-	notify_update(vc);
-
-quit:
-	spin_unlock(&printing_lock);
-}
-
-static struct tty_driver *vt_console_device(struct console *c, int *index)
-{
-	*index = c->index ? c->index-1 : fg_console;
-	return console_driver;
-}
-
-static struct console vt_console_driver = {
-	.name		= "tty",
-	.write		= vt_console_print,
-	.device		= vt_console_device,
-	.unblank	= unblank_screen,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-#endif
-
-/*
- *	Handling of Linux-specific VC ioctls
- */
-
-/*
- * Generally a bit racy with respect to console_sem().
- *
- * There are some functions which don't need it.
- *
- * There are some functions which can sleep for arbitrary periods
- * (paste_selection) but we don't need the lock there anyway.
- *
- * set_selection has locking, and definitely needs it
- */
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
-	char type, data;
-	char __user *p = (char __user *)arg;
-	int lines;
-	int ret;
-
-	if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (get_user(type, p))
-		return -EFAULT;
-	ret = 0;
-
-	switch (type)
-	{
-		case TIOCL_SETSEL:
-			acquire_console_sem();
-			ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-			release_console_sem();
-			break;
-		case TIOCL_PASTESEL:
-			ret = paste_selection(tty);
-			break;
-		case TIOCL_UNBLANKSCREEN:
-			acquire_console_sem();
-			unblank_screen();
-			release_console_sem();
-			break;
-		case TIOCL_SELLOADLUT:
-			ret = sel_loadlut(p);
-			break;
-		case TIOCL_GETSHIFTSTATE:
-
-	/*
-	 * Make it possible to react to Shift+Mousebutton.
-	 * Note that 'shift_state' is an undocumented
-	 * kernel-internal variable; programs not closely
-	 * related to the kernel should not use this.
-	 */
-	 		data = shift_state;
-			ret = __put_user(data, p);
-			break;
-		case TIOCL_GETMOUSEREPORTING:
-			data = mouse_reporting();
-			ret = __put_user(data, p);
-			break;
-		case TIOCL_SETVESABLANK:
-			ret = set_vesa_blanking(p);
-			break;
-		case TIOCL_GETKMSGREDIRECT:
-			data = vt_get_kmsg_redirect();
-			ret = __put_user(data, p);
-			break;
-		case TIOCL_SETKMSGREDIRECT:
-			if (!capable(CAP_SYS_ADMIN)) {
-				ret = -EPERM;
-			} else {
-				if (get_user(data, p+1))
-					ret = -EFAULT;
-				else
-					vt_kmsg_redirect(data);
-			}
-			break;
-		case TIOCL_GETFGCONSOLE:
-			ret = fg_console;
-			break;
-		case TIOCL_SCROLLCONSOLE:
-			if (get_user(lines, (s32 __user *)(p+4))) {
-				ret = -EFAULT;
-			} else {
-				scrollfront(vc_cons[fg_console].d, lines);
-				ret = 0;
-			}
-			break;
-		case TIOCL_BLANKSCREEN:	/* until explicitly unblanked, not only poked */
-			acquire_console_sem();
-			ignore_poke = 1;
-			do_blank_screen(0);
-			release_console_sem();
-			break;
-		case TIOCL_BLANKEDSCREEN:
-			ret = console_blanked;
-			break;
-		default:
-			ret = -EINVAL;
-			break;
-	}
-	return ret;
-}
-
-/*
- * /dev/ttyN handling
- */
-
-static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-	int	retval;
-
-	retval = do_con_write(tty, buf, count);
-	con_flush_chars(tty);
-
-	return retval;
-}
-
-static int con_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	if (in_interrupt())
-		return 0;	/* n_r3964 calls put_char() from interrupt context */
-	return do_con_write(tty, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
-	if (tty->stopped)
-		return 0;
-	return 32768;		/* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
-	return 0;		/* we're not buffering */
-}
-
-/*
- * con_throttle and con_unthrottle are only used for
- * paste_selection(), which has to stuff in a large number of
- * characters...
- */
-static void con_throttle(struct tty_struct *tty)
-{
-}
-
-static void con_unthrottle(struct tty_struct *tty)
-{
-	struct vc_data *vc = tty->driver_data;
-
-	wake_up_interruptible(&vc->paste_wait);
-}
-
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
-{
-	int console_num;
-	if (!tty)
-		return;
-	console_num = tty->index;
-	if (!vc_cons_allocated(console_num))
-		return;
-	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
-	int console_num;
-	if (!tty)
-		return;
-	console_num = tty->index;
-	if (!vc_cons_allocated(console_num))
-		return;
-	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-	set_leds();
-}
-
-static void con_flush_chars(struct tty_struct *tty)
-{
-	struct vc_data *vc;
-
-	if (in_interrupt())	/* from flush_to_ldisc */
-		return;
-
-	/* if we race with con_close(), vt may be null */
-	acquire_console_sem();
-	vc = tty->driver_data;
-	if (vc)
-		set_cursor(vc);
-	release_console_sem();
-}
-
-/*
- * Allocate the console screen memory.
- */
-static int con_open(struct tty_struct *tty, struct file *filp)
-{
-	unsigned int currcons = tty->index;
-	int ret = 0;
-
-	acquire_console_sem();
-	if (tty->driver_data == NULL) {
-		ret = vc_allocate(currcons);
-		if (ret == 0) {
-			struct vc_data *vc = vc_cons[currcons].d;
-
-			/* Still being freed */
-			if (vc->port.tty) {
-				release_console_sem();
-				return -ERESTARTSYS;
-			}
-			tty->driver_data = vc;
-			vc->port.tty = tty;
-
-			if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-				tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-				tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-			}
-			if (vc->vc_utf)
-				tty->termios->c_iflag |= IUTF8;
-			else
-				tty->termios->c_iflag &= ~IUTF8;
-			release_console_sem();
-			return ret;
-		}
-	}
-	release_console_sem();
-	return ret;
-}
-
-static void con_close(struct tty_struct *tty, struct file *filp)
-{
-	/* Nothing to do - we defer to shutdown */
-}
-
-static void con_shutdown(struct tty_struct *tty)
-{
-	struct vc_data *vc = tty->driver_data;
-	BUG_ON(vc == NULL);
-	acquire_console_sem();
-	vc->port.tty = NULL;
-	release_console_sem();
-	tty_shutdown(tty);
-}
-
-static int default_italic_color    = 2; // green (ASCII)
-static int default_underline_color = 3; // cyan (ASCII)
-module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
-module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
-
-static void vc_init(struct vc_data *vc, unsigned int rows,
-		    unsigned int cols, int do_clear)
-{
-	int j, k ;
-
-	vc->vc_cols = cols;
-	vc->vc_rows = rows;
-	vc->vc_size_row = cols << 1;
-	vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-
-	set_origin(vc);
-	vc->vc_pos = vc->vc_origin;
-	reset_vc(vc);
-	for (j=k=0; j<16; j++) {
-		vc->vc_palette[k++] = default_red[j] ;
-		vc->vc_palette[k++] = default_grn[j] ;
-		vc->vc_palette[k++] = default_blu[j] ;
-	}
-	vc->vc_def_color       = 0x07;   /* white */
-	vc->vc_ulcolor         = default_underline_color;
-	vc->vc_itcolor         = default_italic_color;
-	vc->vc_halfcolor       = 0x08;   /* grey */
-	init_waitqueue_head(&vc->paste_wait);
-	reset_terminal(vc, do_clear);
-}
-
-/*
- * This routine initializes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequence.
- */
-
-static int __init con_init(void)
-{
-	const char *display_desc = NULL;
-	struct vc_data *vc;
-	unsigned int currcons = 0, i;
-
-	acquire_console_sem();
-
-	if (conswitchp)
-		display_desc = conswitchp->con_startup();
-	if (!display_desc) {
-		fg_console = 0;
-		release_console_sem();
-		return 0;
-	}
-
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		struct con_driver *con_driver = &registered_con_driver[i];
-
-		if (con_driver->con == NULL) {
-			con_driver->con = conswitchp;
-			con_driver->desc = display_desc;
-			con_driver->flag = CON_DRIVER_FLAG_INIT;
-			con_driver->first = 0;
-			con_driver->last = MAX_NR_CONSOLES - 1;
-			break;
-		}
-	}
-
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-		con_driver_map[i] = conswitchp;
-
-	if (blankinterval) {
-		blank_state = blank_normal_wait;
-		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-	}
-
-	for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
-		vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
-		INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-		tty_port_init(&vc->port);
-		visual_init(vc, currcons, 1);
-		vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-		vc_init(vc, vc->vc_rows, vc->vc_cols,
-			currcons || !vc->vc_sw->con_save_screen);
-	}
-	currcons = fg_console = 0;
-	master_display_fg = vc = vc_cons[currcons].d;
-	set_origin(vc);
-	save_screen(vc);
-	gotoxy(vc, vc->vc_x, vc->vc_y);
-	csi_J(vc, 0);
-	update_screen(vc);
-	printk("Console: %s %s %dx%d",
-		vc->vc_can_do_color ? "colour" : "mono",
-		display_desc, vc->vc_cols, vc->vc_rows);
-	printable = 1;
-	printk("\n");
-
-	release_console_sem();
-
-#ifdef CONFIG_VT_CONSOLE
-	register_console(&vt_console_driver);
-#endif
-	return 0;
-}
-console_initcall(con_init);
-
-static const struct tty_operations con_ops = {
-	.open = con_open,
-	.close = con_close,
-	.write = con_write,
-	.write_room = con_write_room,
-	.put_char = con_put_char,
-	.flush_chars = con_flush_chars,
-	.chars_in_buffer = con_chars_in_buffer,
-	.ioctl = vt_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = vt_compat_ioctl,
-#endif
-	.stop = con_stop,
-	.start = con_start,
-	.throttle = con_throttle,
-	.unthrottle = con_unthrottle,
-	.resize = vt_resize,
-	.shutdown = con_shutdown
-};
-
-static struct cdev vc0_cdev;
-
-int __init vty_init(const struct file_operations *console_fops)
-{
-	cdev_init(&vc0_cdev, console_fops);
-	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-		panic("Couldn't register /dev/tty0 driver\n");
-	device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-	vcs_init();
-
-	console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
-	if (!console_driver)
-		panic("Couldn't allocate console driver\n");
-	console_driver->owner = THIS_MODULE;
-	console_driver->name = "tty";
-	console_driver->name_base = 1;
-	console_driver->major = TTY_MAJOR;
-	console_driver->minor_start = 1;
-	console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
-	console_driver->init_termios = tty_std_termios;
-	if (default_utf8)
-		console_driver->init_termios.c_iflag |= IUTF8;
-	console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	tty_set_operations(console_driver, &con_ops);
-	if (tty_register_driver(console_driver))
-		panic("Couldn't register console driver\n");
-	kbd_init();
-	console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-	mda_console_init();
-#endif
-	return 0;
-}
-
-#ifndef VT_SINGLE_DRIVER
-
-static struct class *vtconsole_class;
-
-static int bind_con_driver(const struct consw *csw, int first, int last,
-			   int deflt)
-{
-	struct module *owner = csw->owner;
-	const char *desc = NULL;
-	struct con_driver *con_driver;
-	int i, j = -1, k = -1, retval = -ENODEV;
-
-	if (!try_module_get(owner))
-		return -ENODEV;
-
-	acquire_console_sem();
-
-	/* check if driver is registered */
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		con_driver = &registered_con_driver[i];
-
-		if (con_driver->con == csw) {
-			desc = con_driver->desc;
-			retval = 0;
-			break;
-		}
-	}
-
-	if (retval)
-		goto err;
-
-	if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
-		csw->con_startup();
-		con_driver->flag |= CON_DRIVER_FLAG_INIT;
-	}
-
-	if (deflt) {
-		if (conswitchp)
-			module_put(conswitchp->owner);
-
-		__module_get(owner);
-		conswitchp = csw;
-	}
-
-	first = max(first, con_driver->first);
-	last = min(last, con_driver->last);
-
-	for (i = first; i <= last; i++) {
-		int old_was_color;
-		struct vc_data *vc = vc_cons[i].d;
-
-		if (con_driver_map[i])
-			module_put(con_driver_map[i]->owner);
-		__module_get(owner);
-		con_driver_map[i] = csw;
-
-		if (!vc || !vc->vc_sw)
-			continue;
-
-		j = i;
-
-		if (CON_IS_VISIBLE(vc)) {
-			k = i;
-			save_screen(vc);
-		}
-
-		old_was_color = vc->vc_can_do_color;
-		vc->vc_sw->con_deinit(vc);
-		vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-		visual_init(vc, i, 0);
-		set_origin(vc);
-		update_attr(vc);
-
-		/* If the console changed between mono <-> color, then
-		 * the attributes in the screenbuf will be wrong.  The
-		 * following resets all attributes to something sane.
-		 */
-		if (old_was_color != vc->vc_can_do_color)
-			clear_buffer_attributes(vc);
-	}
-
-	printk("Console: switching ");
-	if (!deflt)
-		printk("consoles %d-%d ", first+1, last+1);
-	if (j >= 0) {
-		struct vc_data *vc = vc_cons[j].d;
-
-		printk("to %s %s %dx%d\n",
-		       vc->vc_can_do_color ? "colour" : "mono",
-		       desc, vc->vc_cols, vc->vc_rows);
-
-		if (k >= 0) {
-			vc = vc_cons[k].d;
-			update_screen(vc);
-		}
-	} else
-		printk("to %s\n", desc);
-
-	retval = 0;
-err:
-	release_console_sem();
-	module_put(owner);
-	return retval;
-};
-
-#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
-	int i, retval = 0;
-
-	for (i = first; i <= last; i++) {
-		struct vc_data *vc = vc_cons[i].d;
-
-		if (vc && vc->vc_mode == KD_GRAPHICS) {
-			retval = 1;
-			break;
-		}
-	}
-
-	return retval;
-}
-
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
-{
-	struct module *owner = csw->owner;
-	const struct consw *defcsw = NULL;
-	struct con_driver *con_driver = NULL, *con_back = NULL;
-	int i, retval = -ENODEV;
-
-	if (!try_module_get(owner))
-		return -ENODEV;
-
-	acquire_console_sem();
-
-	/* check if driver is registered and if it is unbindable */
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		con_driver = &registered_con_driver[i];
-
-		if (con_driver->con == csw &&
-		    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-			retval = 0;
-			break;
-		}
-	}
-
-	if (retval) {
-		release_console_sem();
-		goto err;
-	}
-
-	retval = -ENODEV;
-
-	/* check if backup driver exists */
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		con_back = &registered_con_driver[i];
-
-		if (con_back->con &&
-		    !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
-			defcsw = con_back->con;
-			retval = 0;
-			break;
-		}
-	}
-
-	if (retval) {
-		release_console_sem();
-		goto err;
-	}
-
-	if (!con_is_bound(csw)) {
-		release_console_sem();
-		goto err;
-	}
-
-	first = max(first, con_driver->first);
-	last = min(last, con_driver->last);
-
-	for (i = first; i <= last; i++) {
-		if (con_driver_map[i] == csw) {
-			module_put(csw->owner);
-			con_driver_map[i] = NULL;
-		}
-	}
-
-	if (!con_is_bound(defcsw)) {
-		const struct consw *defconsw = conswitchp;
-
-		defcsw->con_startup();
-		con_back->flag |= CON_DRIVER_FLAG_INIT;
-		/*
-		 * vgacon may change the default driver to point
-		 * to dummycon, we restore it here...
-		 */
-		conswitchp = defconsw;
-	}
-
-	if (!con_is_bound(csw))
-		con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
-
-	release_console_sem();
-	/* ignore return value, binding should not fail */
-	bind_con_driver(defcsw, first, last, deflt);
-err:
-	module_put(owner);
-	return retval;
-
-}
-EXPORT_SYMBOL(unbind_con_driver);
-
-static int vt_bind(struct con_driver *con)
-{
-	const struct consw *defcsw = NULL, *csw = NULL;
-	int i, more = 1, first = -1, last = -1, deflt = 0;
-
- 	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-	    con_is_graphics(con->con, con->first, con->last))
-		goto err;
-
-	csw = con->con;
-
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		struct con_driver *con = &registered_con_driver[i];
-
-		if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
-			defcsw = con->con;
-			break;
-		}
-	}
-
-	if (!defcsw)
-		goto err;
-
-	while (more) {
-		more = 0;
-
-		for (i = con->first; i <= con->last; i++) {
-			if (con_driver_map[i] == defcsw) {
-				if (first == -1)
-					first = i;
-				last = i;
-				more = 1;
-			} else if (first != -1)
-				break;
-		}
-
-		if (first == 0 && last == MAX_NR_CONSOLES -1)
-			deflt = 1;
-
-		if (first != -1)
-			bind_con_driver(csw, first, last, deflt);
-
-		first = -1;
-		last = -1;
-		deflt = 0;
-	}
-
-err:
-	return 0;
-}
-
-static int vt_unbind(struct con_driver *con)
-{
-	const struct consw *csw = NULL;
-	int i, more = 1, first = -1, last = -1, deflt = 0;
-
- 	if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-	    con_is_graphics(con->con, con->first, con->last))
-		goto err;
-
-	csw = con->con;
-
-	while (more) {
-		more = 0;
-
-		for (i = con->first; i <= con->last; i++) {
-			if (con_driver_map[i] == csw) {
-				if (first == -1)
-					first = i;
-				last = i;
-				more = 1;
-			} else if (first != -1)
-				break;
-		}
-
-		if (first == 0 && last == MAX_NR_CONSOLES -1)
-			deflt = 1;
-
-		if (first != -1)
-			unbind_con_driver(csw, first, last, deflt);
-
-		first = -1;
-		last = -1;
-		deflt = 0;
-	}
-
-err:
-	return 0;
-}
-#else
-static inline int vt_bind(struct con_driver *con)
-{
-	return 0;
-}
-static inline int vt_unbind(struct con_driver *con)
-{
-	return 0;
-}
-#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
-
-static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
-			  const char *buf, size_t count)
-{
-	struct con_driver *con = dev_get_drvdata(dev);
-	int bind = simple_strtoul(buf, NULL, 0);
-
-	if (bind)
-		vt_bind(con);
-	else
-		vt_unbind(con);
-
-	return count;
-}
-
-static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
-			 char *buf)
-{
-	struct con_driver *con = dev_get_drvdata(dev);
-	int bind = con_is_bound(con->con);
-
-	return snprintf(buf, PAGE_SIZE, "%i\n", bind);
-}
-
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-			 char *buf)
-{
-	struct con_driver *con = dev_get_drvdata(dev);
-
-	return snprintf(buf, PAGE_SIZE, "%s %s\n",
-			(con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
-			 con->desc);
-
-}
-
-static struct device_attribute device_attrs[] = {
-	__ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
-	__ATTR(name, S_IRUGO, show_name, NULL),
-};
-
-static int vtconsole_init_device(struct con_driver *con)
-{
-	int i;
-	int error = 0;
-
-	con->flag |= CON_DRIVER_FLAG_ATTR;
-	dev_set_drvdata(con->dev, con);
-	for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-		error = device_create_file(con->dev, &device_attrs[i]);
-		if (error)
-			break;
-	}
-
-	if (error) {
-		while (--i >= 0)
-			device_remove_file(con->dev, &device_attrs[i]);
-		con->flag &= ~CON_DRIVER_FLAG_ATTR;
-	}
-
-	return error;
-}
-
-static void vtconsole_deinit_device(struct con_driver *con)
-{
-	int i;
-
-	if (con->flag & CON_DRIVER_FLAG_ATTR) {
-		for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-			device_remove_file(con->dev, &device_attrs[i]);
-		con->flag &= ~CON_DRIVER_FLAG_ATTR;
-	}
-}
-
-/**
- * con_is_bound - checks if driver is bound to the console
- * @csw: console driver
- *
- * RETURNS: zero if unbound, nonzero if bound
- *
- * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
- */
-int con_is_bound(const struct consw *csw)
-{
-	int i, bound = 0;
-
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		if (con_driver_map[i] == csw) {
-			bound = 1;
-			break;
-		}
-	}
-
-	return bound;
-}
-EXPORT_SYMBOL(con_is_bound);
-
-/**
- * con_debug_enter - prepare the console for the kernel debugger
- * @sw: console driver
- *
- * Called when the console is taken over by the kernel debugger, this
- * function needs to save the current console state, then put the console
- * into a state suitable for the kernel debugger.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to prepare
- * the console for the debugger.
- */
-int con_debug_enter(struct vc_data *vc)
-{
-	int ret = 0;
-
-	saved_fg_console = fg_console;
-	saved_last_console = last_console;
-	saved_want_console = want_console;
-	saved_vc_mode = vc->vc_mode;
-	saved_console_blanked = console_blanked;
-	vc->vc_mode = KD_TEXT;
-	console_blanked = 0;
-	if (vc->vc_sw->con_debug_enter)
-		ret = vc->vc_sw->con_debug_enter(vc);
-#ifdef CONFIG_KGDB_KDB
-	/* Set the initial LINES variable if it is not already set */
-	if (vc->vc_rows < 999) {
-		int linecount;
-		char lns[4];
-		const char *setargs[3] = {
-			"set",
-			"LINES",
-			lns,
-		};
-		if (kdbgetintenv(setargs[0], &linecount)) {
-			snprintf(lns, 4, "%i", vc->vc_rows);
-			kdb_set(2, setargs);
-		}
-	}
-#endif /* CONFIG_KGDB_KDB */
-	return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_enter);
-
-/**
- * con_debug_leave - restore console state
- * @sw: console driver
- *
- * Restore the console state to what it was before the kernel debugger
- * was invoked.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to restore
- * the console.
- */
-int con_debug_leave(void)
-{
-	struct vc_data *vc;
-	int ret = 0;
-
-	fg_console = saved_fg_console;
-	last_console = saved_last_console;
-	want_console = saved_want_console;
-	console_blanked = saved_console_blanked;
-	vc_cons[fg_console].d->vc_mode = saved_vc_mode;
-
-	vc = vc_cons[fg_console].d;
-	if (vc->vc_sw->con_debug_leave)
-		ret = vc->vc_sw->con_debug_leave(vc);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_leave);
-
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
-	struct module *owner = csw->owner;
-	struct con_driver *con_driver;
-	const char *desc;
-	int i, retval = 0;
-
-	if (!try_module_get(owner))
-		return -ENODEV;
-
-	acquire_console_sem();
-
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		con_driver = &registered_con_driver[i];
-
-		/* already registered */
-		if (con_driver->con == csw)
-			retval = -EINVAL;
-	}
-
-	if (retval)
-		goto err;
-
-	desc = csw->con_startup();
-
-	if (!desc)
-		goto err;
-
-	retval = -EINVAL;
-
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		con_driver = &registered_con_driver[i];
-
-		if (con_driver->con == NULL) {
-			con_driver->con = csw;
-			con_driver->desc = desc;
-			con_driver->node = i;
-			con_driver->flag = CON_DRIVER_FLAG_MODULE |
-			                   CON_DRIVER_FLAG_INIT;
-			con_driver->first = first;
-			con_driver->last = last;
-			retval = 0;
-			break;
-		}
-	}
-
-	if (retval)
-		goto err;
-
-	con_driver->dev = device_create(vtconsole_class, NULL,
-						MKDEV(0, con_driver->node),
-						NULL, "vtcon%i",
-						con_driver->node);
-
-	if (IS_ERR(con_driver->dev)) {
-		printk(KERN_WARNING "Unable to create device for %s; "
-		       "errno = %ld\n", con_driver->desc,
-		       PTR_ERR(con_driver->dev));
-		con_driver->dev = NULL;
-	} else {
-		vtconsole_init_device(con_driver);
-	}
-
-err:
-	release_console_sem();
-	module_put(owner);
-	return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
-
-/**
- * unregister_con_driver - unregister console driver from console layer
- * @csw: console driver
- *
- * DESCRIPTION: All drivers that registers to the console layer must
- * call this function upon exit, or if the console driver is in a state
- * where it won't be able to handle console services, such as the
- * framebuffer console without loaded framebuffer drivers.
- *
- * The driver must unbind first prior to unregistration.
- */
-int unregister_con_driver(const struct consw *csw)
-{
-	int i, retval = -ENODEV;
-
-	acquire_console_sem();
-
-	/* cannot unregister a bound driver */
-	if (con_is_bound(csw))
-		goto err;
-
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		struct con_driver *con_driver = &registered_con_driver[i];
-
-		if (con_driver->con == csw &&
-		    con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-			vtconsole_deinit_device(con_driver);
-			device_destroy(vtconsole_class,
-				       MKDEV(0, con_driver->node));
-			con_driver->con = NULL;
-			con_driver->desc = NULL;
-			con_driver->dev = NULL;
-			con_driver->node = 0;
-			con_driver->flag = 0;
-			con_driver->first = 0;
-			con_driver->last = 0;
-			retval = 0;
-			break;
-		}
-	}
-err:
-	release_console_sem();
-	return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
-/*
- *	If we support more console drivers, this function is used
- *	when a driver wants to take over some existing consoles
- *	and become default driver for newly opened ones.
- *
- *      take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
-	int err;
-
-	err = register_con_driver(csw, first, last);
-
-	if (!err)
-		bind_con_driver(csw, first, last, deflt);
-
-	return err;
-}
-
-/*
- * give_up_console is a wrapper to unregister_con_driver. It will only
- * work if driver is fully unbound.
- */
-void give_up_console(const struct consw *csw)
-{
-	unregister_con_driver(csw);
-}
-
-static int __init vtconsole_class_init(void)
-{
-	int i;
-
-	vtconsole_class = class_create(THIS_MODULE, "vtconsole");
-	if (IS_ERR(vtconsole_class)) {
-		printk(KERN_WARNING "Unable to create vt console class; "
-		       "errno = %ld\n", PTR_ERR(vtconsole_class));
-		vtconsole_class = NULL;
-	}
-
-	/* Add system drivers to sysfs */
-	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-		struct con_driver *con = &registered_con_driver[i];
-
-		if (con->con && !con->dev) {
-			con->dev = device_create(vtconsole_class, NULL,
-							 MKDEV(0, con->node),
-							 NULL, "vtcon%i",
-							 con->node);
-
-			if (IS_ERR(con->dev)) {
-				printk(KERN_WARNING "Unable to create "
-				       "device for %s; errno = %ld\n",
-				       con->desc, PTR_ERR(con->dev));
-				con->dev = NULL;
-			} else {
-				vtconsole_init_device(con);
-			}
-		}
-	}
-
-	return 0;
-}
-postcore_initcall(vtconsole_class_init);
-
-#endif
-
-/*
- *	Screen blanking
- */
-
-static int set_vesa_blanking(char __user *p)
-{
-	unsigned int mode;
-
-	if (get_user(mode, p + 1))
-		return -EFAULT;
-
-	vesa_blank_mode = (mode < 4) ? mode : 0;
-	return 0;
-}
-
-void do_blank_screen(int entering_gfx)
-{
-	struct vc_data *vc = vc_cons[fg_console].d;
-	int i;
-
-	WARN_CONSOLE_UNLOCKED();
-
-	if (console_blanked) {
-		if (blank_state == blank_vesa_wait) {
-			blank_state = blank_off;
-			vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
-		}
-		return;
-	}
-
-	/* entering graphics mode? */
-	if (entering_gfx) {
-		hide_cursor(vc);
-		save_screen(vc);
-		vc->vc_sw->con_blank(vc, -1, 1);
-		console_blanked = fg_console + 1;
-		blank_state = blank_off;
-		set_origin(vc);
-		return;
-	}
-
-	if (blank_state != blank_normal_wait)
-		return;
-	blank_state = blank_off;
-
-	/* don't blank graphics */
-	if (vc->vc_mode != KD_TEXT) {
-		console_blanked = fg_console + 1;
-		return;
-	}
-
-	hide_cursor(vc);
-	del_timer_sync(&console_timer);
-	blank_timer_expired = 0;
-
-	save_screen(vc);
-	/* In case we need to reset origin, blanking hook returns 1 */
-	i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
-	console_blanked = fg_console + 1;
-	if (i)
-		set_origin(vc);
-
-	if (console_blank_hook && console_blank_hook(1))
-		return;
-
-	if (vesa_off_interval && vesa_blank_mode) {
-		blank_state = blank_vesa_wait;
-		mod_timer(&console_timer, jiffies + vesa_off_interval);
-	}
-	vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_blank_screen);
-
-/*
- * Called by timer as well as from vt_console_driver
- */
-void do_unblank_screen(int leaving_gfx)
-{
-	struct vc_data *vc;
-
-	/* This should now always be called from a "sane" (read: can schedule)
-	 * context for the sake of the low level drivers, except in the special
-	 * case of oops_in_progress
-	 */
-	if (!oops_in_progress)
-		might_sleep();
-
-	WARN_CONSOLE_UNLOCKED();
-
-	ignore_poke = 0;
-	if (!console_blanked)
-		return;
-	if (!vc_cons_allocated(fg_console)) {
-		/* impossible */
-		printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
-		return;
-	}
-	vc = vc_cons[fg_console].d;
-	/* Try to unblank in oops case too */
-	if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-		return; /* but leave console_blanked != 0 */
-
-	if (blankinterval) {
-		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-		blank_state = blank_normal_wait;
-	}
-
-	console_blanked = 0;
-	if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
-		/* Low-level driver cannot restore -> do it ourselves */
-		update_screen(vc);
-	if (console_blank_hook)
-		console_blank_hook(0);
-	set_palette(vc);
-	set_cursor(vc);
-	vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_unblank_screen);
-
-/*
- * This is called by the outside world to cause a forced unblank, mostly for
- * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
- * call it with 1 as an argument and so force a mode restore... that may kill
- * X or at least garbage the screen but would also make the Oops visible...
- */
-void unblank_screen(void)
-{
-	do_unblank_screen(0);
-}
-
-/*
- * We defer the timer blanking to work queue so it can take the console mutex
- * (console operations can still happen at irq time, but only from printk which
- * has the console mutex. Not perfect yet, but better than no locking
- */
-static void blank_screen_t(unsigned long dummy)
-{
-	if (unlikely(!keventd_up())) {
-		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-		return;
-	}
-	blank_timer_expired = 1;
-	schedule_work(&console_work);
-}
-
-void poke_blanked_console(void)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	/* Add this so we quickly catch whoever might call us in a non
-	 * safe context. Nowadays, unblank_screen() isn't to be called in
-	 * atomic contexts and is allowed to schedule (with the special case
-	 * of oops_in_progress, but that isn't of any concern for this
-	 * function. --BenH.
-	 */
-	might_sleep();
-
-	/* This isn't perfectly race free, but a race here would be mostly harmless,
-	 * at worse, we'll do a spurrious blank and it's unlikely
-	 */
-	del_timer(&console_timer);
-	blank_timer_expired = 0;
-
-	if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
-		return;
-	if (console_blanked)
-		unblank_screen();
-	else if (blankinterval) {
-		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-		blank_state = blank_normal_wait;
-	}
-}
-
-/*
- *	Palettes
- */
-
-static void set_palette(struct vc_data *vc)
-{
-	WARN_CONSOLE_UNLOCKED();
-
-	if (vc->vc_mode != KD_GRAPHICS)
-		vc->vc_sw->con_set_palette(vc, color_table);
-}
-
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-	if (set) {
-	    get_user(default_red[i], arg++);
-	    get_user(default_grn[i], arg++);
-	    get_user(default_blu[i], arg++);
-	} else {
-	    put_user(default_red[i], arg++);
-	    put_user(default_grn[i], arg++);
-	    put_user(default_blu[i], arg++);
-	}
-    if (set) {
-	for (i = 0; i < MAX_NR_CONSOLES; i++)
-	    if (vc_cons_allocated(i)) {
-		for (j = k = 0; j < 16; j++) {
-		    vc_cons[i].d->vc_palette[k++] = default_red[j];
-		    vc_cons[i].d->vc_palette[k++] = default_grn[j];
-		    vc_cons[i].d->vc_palette[k++] = default_blu[j];
-		}
-		set_palette(vc_cons[i].d);
-	    }
-    }
-    return 0;
-}
-
-/*
- * Load palette into the DAC registers. arg points to a colour
- * map, 3 bytes per colour, 16 colours, range from 0 to 255.
- */
-
-int con_set_cmap(unsigned char __user *arg)
-{
-	int rc;
-
-	acquire_console_sem();
-	rc = set_get_cmap (arg,1);
-	release_console_sem();
-
-	return rc;
-}
-
-int con_get_cmap(unsigned char __user *arg)
-{
-	int rc;
-
-	acquire_console_sem();
-	rc = set_get_cmap (arg,0);
-	release_console_sem();
-
-	return rc;
-}
-
-void reset_palette(struct vc_data *vc)
-{
-	int j, k;
-	for (j=k=0; j<16; j++) {
-		vc->vc_palette[k++] = default_red[j];
-		vc->vc_palette[k++] = default_grn[j];
-		vc->vc_palette[k++] = default_blu[j];
-	}
-	set_palette(vc);
-}
-
-/*
- *  Font switching
- *
- *  Currently we only support fonts up to 32 pixels wide, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
- *  depending on width) reserved for each character which is kinda wasty, but 
- *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
- *  is upto the actual low-level console-driver convert data into its favorite
- *  format (maybe we should add a `fontoffset' field to the `display'
- *  structure so we won't have to convert the fontdata all the time.
- *  /Jes
- */
-
-#define max_font_size 65536
-
-static int con_font_get(struct vc_data *vc, struct console_font_op *op)
-{
-	struct console_font font;
-	int rc = -EINVAL;
-	int c;
-
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-
-	if (op->data) {
-		font.data = kmalloc(max_font_size, GFP_KERNEL);
-		if (!font.data)
-			return -ENOMEM;
-	} else
-		font.data = NULL;
-
-	acquire_console_sem();
-	if (vc->vc_sw->con_font_get)
-		rc = vc->vc_sw->con_font_get(vc, &font);
-	else
-		rc = -ENOSYS;
-	release_console_sem();
-
-	if (rc)
-		goto out;
-
-	c = (font.width+7)/8 * 32 * font.charcount;
-
-	if (op->data && font.charcount > op->charcount)
-		rc = -ENOSPC;
-	if (!(op->flags & KD_FONT_FLAG_OLD)) {
-		if (font.width > op->width || font.height > op->height) 
-			rc = -ENOSPC;
-	} else {
-		if (font.width != 8)
-			rc = -EIO;
-		else if ((op->height && font.height > op->height) ||
-			 font.height > 32)
-			rc = -ENOSPC;
-	}
-	if (rc)
-		goto out;
-
-	op->height = font.height;
-	op->width = font.width;
-	op->charcount = font.charcount;
-
-	if (op->data && copy_to_user(op->data, font.data, c))
-		rc = -EFAULT;
-
-out:
-	kfree(font.data);
-	return rc;
-}
-
-static int con_font_set(struct vc_data *vc, struct console_font_op *op)
-{
-	struct console_font font;
-	int rc = -EINVAL;
-	int size;
-
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-	if (!op->data)
-		return -EINVAL;
-	if (op->charcount > 512)
-		return -EINVAL;
-	if (!op->height) {		/* Need to guess font height [compat] */
-		int h, i;
-		u8 __user *charmap = op->data;
-		u8 tmp;
-		
-		/* If from KDFONTOP ioctl, don't allow things which can be done in userland,
-		   so that we can get rid of this soon */
-		if (!(op->flags & KD_FONT_FLAG_OLD))
-			return -EINVAL;
-		for (h = 32; h > 0; h--)
-			for (i = 0; i < op->charcount; i++) {
-				if (get_user(tmp, &charmap[32*i+h-1]))
-					return -EFAULT;
-				if (tmp)
-					goto nonzero;
-			}
-		return -EINVAL;
-	nonzero:
-		op->height = h;
-	}
-	if (op->width <= 0 || op->width > 32 || op->height > 32)
-		return -EINVAL;
-	size = (op->width+7)/8 * 32 * op->charcount;
-	if (size > max_font_size)
-		return -ENOSPC;
-	font.charcount = op->charcount;
-	font.height = op->height;
-	font.width = op->width;
-	font.data = memdup_user(op->data, size);
-	if (IS_ERR(font.data))
-		return PTR_ERR(font.data);
-	acquire_console_sem();
-	if (vc->vc_sw->con_font_set)
-		rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
-	else
-		rc = -ENOSYS;
-	release_console_sem();
-	kfree(font.data);
-	return rc;
-}
-
-static int con_font_default(struct vc_data *vc, struct console_font_op *op)
-{
-	struct console_font font = {.width = op->width, .height = op->height};
-	char name[MAX_FONT_NAME];
-	char *s = name;
-	int rc;
-
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-
-	if (!op->data)
-		s = NULL;
-	else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
-		return -EFAULT;
-	else
-		name[MAX_FONT_NAME - 1] = 0;
-
-	acquire_console_sem();
-	if (vc->vc_sw->con_font_default)
-		rc = vc->vc_sw->con_font_default(vc, &font, s);
-	else
-		rc = -ENOSYS;
-	release_console_sem();
-	if (!rc) {
-		op->width = font.width;
-		op->height = font.height;
-	}
-	return rc;
-}
-
-static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
-{
-	int con = op->height;
-	int rc;
-
-	if (vc->vc_mode != KD_TEXT)
-		return -EINVAL;
-
-	acquire_console_sem();
-	if (!vc->vc_sw->con_font_copy)
-		rc = -ENOSYS;
-	else if (con < 0 || !vc_cons_allocated(con))
-		rc = -ENOTTY;
-	else if (con == vc->vc_num)	/* nothing to do */
-		rc = 0;
-	else
-		rc = vc->vc_sw->con_font_copy(vc, con);
-	release_console_sem();
-	return rc;
-}
-
-int con_font_op(struct vc_data *vc, struct console_font_op *op)
-{
-	switch (op->op) {
-	case KD_FONT_OP_SET:
-		return con_font_set(vc, op);
-	case KD_FONT_OP_GET:
-		return con_font_get(vc, op);
-	case KD_FONT_OP_SET_DEFAULT:
-		return con_font_default(vc, op);
-	case KD_FONT_OP_COPY:
-		return con_font_copy(vc, op);
-	}
-	return -ENOSYS;
-}
-
-/*
- *	Interface exported to selection and vcs.
- */
-
-/* used by selection */
-u16 screen_glyph(struct vc_data *vc, int offset)
-{
-	u16 w = scr_readw(screenpos(vc, offset, 1));
-	u16 c = w & 0xff;
-
-	if (w & vc->vc_hi_font_mask)
-		c |= 0x100;
-	return c;
-}
-EXPORT_SYMBOL_GPL(screen_glyph);
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
-{
-	return screenpos(vc, 2 * w_offset, viewed);
-}
-
-void getconsxy(struct vc_data *vc, unsigned char *p)
-{
-	p[0] = vc->vc_x;
-	p[1] = vc->vc_y;
-}
-
-void putconsxy(struct vc_data *vc, unsigned char *p)
-{
-	hide_cursor(vc);
-	gotoxy(vc, p[0], p[1]);
-	set_cursor(vc);
-}
-
-u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
-{
-	if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
-		return softcursor_original;
-	return scr_readw(org);
-}
-
-void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
-{
-	scr_writew(val, org);
-	if ((unsigned long)org == vc->vc_pos) {
-		softcursor_original = -1;
-		add_softcursor(vc);
-	}
-}
-
-/*
- *	Visible symbols for modules
- */
-
-EXPORT_SYMBOL(color_table);
-EXPORT_SYMBOL(default_red);
-EXPORT_SYMBOL(default_grn);
-EXPORT_SYMBOL(default_blu);
-EXPORT_SYMBOL(update_region);
-EXPORT_SYMBOL(redraw_screen);
-EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(fg_console);
-EXPORT_SYMBOL(console_blank_hook);
-EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vc_cons);
-EXPORT_SYMBOL(global_cursor_default);
-#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
-EXPORT_SYMBOL(give_up_console);
-#endif
diff -druN linux-libre-2.6.36-gnu/drivers/char/vt_ioctl.c linux-libre-2.6.37-gnu/drivers/char/vt_ioctl.c
--- linux-libre-2.6.36-gnu/drivers/char/vt_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/vt_ioctl.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1787 +0,0 @@
-/*
- *  linux/drivers/char/vt_ioctl.c
- *
- *  Copyright (C) 1992 obz under the linux copyright
- *
- *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
- *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
- *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
- *  Some code moved for less code duplication - Andi Kleen - Mar 1997
- *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/console.h>
-#include <linux/consolemap.h>
-#include <linux/signal.h>
-#include <linux/smp_lock.h>
-#include <linux/timex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/selection.h>
-
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
-
-#define VT_IS_IN_USE(i)	(console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i)	(VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
-
-/*
- * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
- * experimentation and study of X386 SYSV handling.
- *
- * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
- * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
- * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
- * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
- * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
- * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
- * to the current console is done by the main ioctl code.
- */
-
-#ifdef CONFIG_X86
-#include <linux/syscalls.h>
-#endif
-
-static void complete_change_console(struct vc_data *vc);
-
-/*
- *	User space VT_EVENT handlers
- */
-
-struct vt_event_wait {
-	struct list_head list;
-	struct vt_event event;
-	int done;
-};
-
-static LIST_HEAD(vt_events);
-static DEFINE_SPINLOCK(vt_event_lock);
-static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
-
-/**
- *	vt_event_post
- *	@event: the event that occurred
- *	@old: old console
- *	@new: new console
- *
- *	Post an VT event to interested VT handlers
- */
-
-void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
-{
-	struct list_head *pos, *head;
-	unsigned long flags;
-	int wake = 0;
-
-	spin_lock_irqsave(&vt_event_lock, flags);
-	head = &vt_events;
-
-	list_for_each(pos, head) {
-		struct vt_event_wait *ve = list_entry(pos,
-						struct vt_event_wait, list);
-		if (!(ve->event.event & event))
-			continue;
-		ve->event.event = event;
-		/* kernel view is consoles 0..n-1, user space view is
-		   console 1..n with 0 meaning current, so we must bias */
-		ve->event.oldev = old + 1;
-		ve->event.newev = new + 1;
-		wake = 1;
-		ve->done = 1;
-	}
-	spin_unlock_irqrestore(&vt_event_lock, flags);
-	if (wake)
-		wake_up_interruptible(&vt_event_waitqueue);
-}
-
-/**
- *	vt_event_wait		-	wait for an event
- *	@vw: our event
- *
- *	Waits for an event to occur which completes our vt_event_wait
- *	structure. On return the structure has wv->done set to 1 for success
- *	or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
-{
-	unsigned long flags;
-	/* Prepare the event */
-	INIT_LIST_HEAD(&vw->list);
-	vw->done = 0;
-	/* Queue our event */
-	spin_lock_irqsave(&vt_event_lock, flags);
-	list_add(&vw->list, &vt_events);
-	spin_unlock_irqrestore(&vt_event_lock, flags);
-	/* Wait for it to pass */
-	wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
-	/* Dequeue it */
-	spin_lock_irqsave(&vt_event_lock, flags);
-	list_del(&vw->list);
-	spin_unlock_irqrestore(&vt_event_lock, flags);
-}
-
-/**
- *	vt_event_wait_ioctl	-	event ioctl handler
- *	@arg: argument to ioctl
- *
- *	Implement the VT_WAITEVENT ioctl using the VT event interface
- */
-
-static int vt_event_wait_ioctl(struct vt_event __user *event)
-{
-	struct vt_event_wait vw;
-
-	if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
-		return -EFAULT;
-	/* Highest supported event for now */
-	if (vw.event.event & ~VT_MAX_EVENT)
-		return -EINVAL;
-
-	vt_event_wait(&vw);
-	/* If it occurred report it */
-	if (vw.done) {
-		if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
-			return -EFAULT;
-		return 0;
-	}
-	return -EINTR;
-}
-
-/**
- *	vt_waitactive	-	active console wait
- *	@event: event code
- *	@n: new console
- *
- *	Helper for event waits. Used to implement the legacy
- *	event waiting ioctls in terms of events
- */
-
-int vt_waitactive(int n)
-{
-	struct vt_event_wait vw;
-	do {
-		if (n == fg_console + 1)
-			break;
-		vw.event.event = VT_EVENT_SWITCH;
-		vt_event_wait(&vw);
-		if (vw.done == 0)
-			return -EINTR;
-	} while (vw.event.newev != n);
-	return 0;
-}
-
-/*
- * these are the valid i/o ports we're allowed to change. they map all the
- * video ports
- */
-#define GPFIRST 0x3b4
-#define GPLAST 0x3df
-#define GPNUM (GPLAST - GPFIRST + 1)
-
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-	struct kbentry tmp;
-	ushort *key_map, val, ov;
-
-	if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-		return -EFAULT;
-
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	switch (cmd) {
-	case KDGKBENT:
-		key_map = key_maps[s];
-		if (key_map) {
-		    val = U(key_map[i]);
-		    if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-			val = K_HOLE;
-		} else
-		    val = (i ? K_HOLE : K_NOSUCHMAP);
-		return put_user(val, &user_kbe->kb_value);
-	case KDSKBENT:
-		if (!perm)
-			return -EPERM;
-		if (!i && v == K_NOSUCHMAP) {
-			/* deallocate map */
-			key_map = key_maps[s];
-			if (s && key_map) {
-			    key_maps[s] = NULL;
-			    if (key_map[0] == U(K_ALLOCATED)) {
-					kfree(key_map);
-					keymap_count--;
-			    }
-			}
-			break;
-		}
-
-		if (KTYP(v) < NR_TYPES) {
-		    if (KVAL(v) > max_vals[KTYP(v)])
-				return -EINVAL;
-		} else
-		    if (kbd->kbdmode != VC_UNICODE)
-				return -EINVAL;
-
-		/* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-		/* assignment to entry 0 only tests validity of args */
-		if (!i)
-			break;
-#endif
-
-		if (!(key_map = key_maps[s])) {
-			int j;
-
-			if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-			    !capable(CAP_SYS_RESOURCE))
-				return -EPERM;
-
-			key_map = kmalloc(sizeof(plain_map),
-						     GFP_KERNEL);
-			if (!key_map)
-				return -ENOMEM;
-			key_maps[s] = key_map;
-			key_map[0] = U(K_ALLOCATED);
-			for (j = 1; j < NR_KEYS; j++)
-				key_map[j] = U(K_HOLE);
-			keymap_count++;
-		}
-		ov = U(key_map[i]);
-		if (v == ov)
-			break;	/* nothing to do */
-		/*
-		 * Attention Key.
-		 */
-		if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		key_map[i] = U(v);
-		if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-			compute_shiftstate();
-		break;
-	}
-	return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-	struct kbkeycode tmp;
-	int kc = 0;
-
-	if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-		return -EFAULT;
-	switch (cmd) {
-	case KDGETKEYCODE:
-		kc = getkeycode(tmp.scancode);
-		if (kc >= 0)
-			kc = put_user(kc, &user_kbkc->keycode);
-		break;
-	case KDSETKEYCODE:
-		if (!perm)
-			return -EPERM;
-		kc = setkeycode(tmp.scancode, tmp.keycode);
-		break;
-	}
-	return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-	struct kbsentry *kbs;
-	char *p;
-	u_char *q;
-	u_char __user *up;
-	int sz;
-	int delta;
-	char *first_free, *fj, *fnw;
-	int i, j, k;
-	int ret;
-
-	if (!capable(CAP_SYS_TTY_CONFIG))
-		perm = 0;
-
-	kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-	if (!kbs) {
-		ret = -ENOMEM;
-		goto reterr;
-	}
-
-	/* we mostly copy too much here (512bytes), but who cares ;) */
-	if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-		ret = -EFAULT;
-		goto reterr;
-	}
-	kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-	i = kbs->kb_func;
-
-	switch (cmd) {
-	case KDGKBSENT:
-		sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-						  a struct member */
-		up = user_kdgkb->kb_string;
-		p = func_table[i];
-		if(p)
-			for ( ; *p && sz; p++, sz--)
-				if (put_user(*p, up++)) {
-					ret = -EFAULT;
-					goto reterr;
-				}
-		if (put_user('\0', up)) {
-			ret = -EFAULT;
-			goto reterr;
-		}
-		kfree(kbs);
-		return ((p && *p) ? -EOVERFLOW : 0);
-	case KDSKBSENT:
-		if (!perm) {
-			ret = -EPERM;
-			goto reterr;
-		}
-
-		q = func_table[i];
-		first_free = funcbufptr + (funcbufsize - funcbufleft);
-		for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-			;
-		if (j < MAX_NR_FUNC)
-			fj = func_table[j];
-		else
-			fj = first_free;
-
-		delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-		if (delta <= funcbufleft) { 	/* it fits in current buf */
-		    if (j < MAX_NR_FUNC) {
-			memmove(fj + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			    if (func_table[k])
-				func_table[k] += delta;
-		    }
-		    if (!q)
-		      func_table[i] = fj;
-		    funcbufleft -= delta;
-		} else {			/* allocate a larger buffer */
-		    sz = 256;
-		    while (sz < funcbufsize - funcbufleft + delta)
-		      sz <<= 1;
-		    fnw = kmalloc(sz, GFP_KERNEL);
-		    if(!fnw) {
-		      ret = -ENOMEM;
-		      goto reterr;
-		    }
-
-		    if (!q)
-		      func_table[i] = fj;
-		    if (fj > funcbufptr)
-			memmove(fnw, funcbufptr, fj - funcbufptr);
-		    for (k = 0; k < j; k++)
-		      if (func_table[k])
-			func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-		    if (first_free > fj) {
-			memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-			for (k = j; k < MAX_NR_FUNC; k++)
-			  if (func_table[k])
-			    func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-		    }
-		    if (funcbufptr != func_buf)
-		      kfree(funcbufptr);
-		    funcbufptr = fnw;
-		    funcbufleft = funcbufleft - delta + sz - funcbufsize;
-		    funcbufsize = sz;
-		}
-		strcpy(func_table[i], kbs->kb_string);
-		break;
-	}
-	ret = 0;
-reterr:
-	kfree(kbs);
-	return ret;
-}
-
-static inline int 
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
-	struct consolefontdesc cfdarg;
-	int i;
-
-	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
-		return -EFAULT;
- 	
-	switch (cmd) {
-	case PIO_FONTX:
-		if (!perm)
-			return -EPERM;
-		op->op = KD_FONT_OP_SET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = cfdarg.chardata;
-		return con_font_op(vc_cons[fg_console].d, op);
-	case GIO_FONTX: {
-		op->op = KD_FONT_OP_GET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = cfdarg.chardata;
-		i = con_font_op(vc_cons[fg_console].d, op);
-		if (i)
-			return i;
-		cfdarg.charheight = op->height;
-		cfdarg.charcount = op->charcount;
-		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
-			return -EFAULT;
-		return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static inline int 
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
-{
-	struct unimapdesc tmp;
-
-	if (copy_from_user(&tmp, user_ud, sizeof tmp))
-		return -EFAULT;
-	if (tmp.entries)
-		if (!access_ok(VERIFY_WRITE, tmp.entries,
-				tmp.entry_ct*sizeof(struct unipair)))
-			return -EFAULT;
-	switch (cmd) {
-	case PIO_UNIMAP:
-		if (!perm)
-			return -EPERM;
-		return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
-	case GIO_UNIMAP:
-		if (!perm && fg_console != vc->vc_num)
-			return -EPERM;
-		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
-	}
-	return 0;
-}
-
-
-
-/*
- * We handle the console-specific ioctl's here.  We allow the
- * capability to modify any console, not just the fg_console. 
- */
-int vt_ioctl(struct tty_struct *tty, struct file * file,
-	     unsigned int cmd, unsigned long arg)
-{
-	struct vc_data *vc = tty->driver_data;
-	struct console_font_op op;	/* used in multiple places here */
-	struct kbd_struct * kbd;
-	unsigned int console;
-	unsigned char ucval;
-	void __user *up = (void __user *)arg;
-	int i, perm;
-	int ret = 0;
-
-	console = vc->vc_num;
-
-	tty_lock();
-
-	if (!vc_cons_allocated(console)) { 	/* impossible? */
-		ret = -ENOIOCTLCMD;
-		goto out;
-	}
-
-
-	/*
-	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-	 */
-	perm = 0;
-	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-		perm = 1;
- 
-	kbd = kbd_table + console;
-	switch (cmd) {
-	case TIOCLINUX:
-		ret = tioclinux(tty, arg);
-		break;
-	case KIOCSOUND:
-		if (!perm)
-			goto eperm;
-		/*
-		 * The use of PIT_TICK_RATE is historic, it used to be
-		 * the platform-dependent CLOCK_TICK_RATE between 2.6.12
-		 * and 2.6.36, which was a minor but unfortunate ABI
-		 * change.
-		 */
-		if (arg)
-			arg = PIT_TICK_RATE / arg;
-		kd_mksound(arg, 0);
-		break;
-
-	case KDMKTONE:
-		if (!perm)
-			goto eperm;
-	{
-		unsigned int ticks, count;
-		
-		/*
-		 * Generate the tone for the appropriate number of ticks.
-		 * If the time is zero, turn off sound ourselves.
-		 */
-		ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
-		count = ticks ? (arg & 0xffff) : 0;
-		if (count)
-			count = PIT_TICK_RATE / count;
-		kd_mksound(count, ticks);
-		break;
-	}
-
-	case KDGKBTYPE:
-		/*
-		 * this is naive.
-		 */
-		ucval = KB_101;
-		goto setchar;
-
-		/*
-		 * These cannot be implemented on any machine that implements
-		 * ioperm() in user level (such as Alpha PCs) or not at all.
-		 *
-		 * XXX: you should never use these, just call ioperm directly..
-		 */
-#ifdef CONFIG_X86
-	case KDADDIO:
-	case KDDELIO:
-		/*
-		 * KDADDIO and KDDELIO may be able to add ports beyond what
-		 * we reject here, but to be safe...
-		 */
-		if (arg < GPFIRST || arg > GPLAST) {
-			ret = -EINVAL;
-			break;
-		}
-		ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
-		break;
-
-	case KDENABIO:
-	case KDDISABIO:
-		ret = sys_ioperm(GPFIRST, GPNUM,
-				  (cmd == KDENABIO)) ? -ENXIO : 0;
-		break;
-#endif
-
-	/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
-		
-	case KDKBDREP:
-	{
-		struct kbd_repeat kbrep;
-		
-		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
-
-		if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
-			ret =  -EFAULT;
-			break;
-		}
-		ret = kbd_rate(&kbrep);
-		if (ret)
-			break;
-		if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
-			ret = -EFAULT;
-		break;
-	}
-
-	case KDSETMODE:
-		/*
-		 * currently, setting the mode from KD_TEXT to KD_GRAPHICS
-		 * doesn't do a whole lot. i'm not sure if it should do any
-		 * restoration of modes or what...
-		 *
-		 * XXX It should at least call into the driver, fbdev's definitely
-		 * need to restore their engine state. --BenH
-		 */
-		if (!perm)
-			goto eperm;
-		switch (arg) {
-		case KD_GRAPHICS:
-			break;
-		case KD_TEXT0:
-		case KD_TEXT1:
-			arg = KD_TEXT;
-		case KD_TEXT:
-			break;
-		default:
-			ret = -EINVAL;
-			goto out;
-		}
-		if (vc->vc_mode == (unsigned char) arg)
-			break;
-		vc->vc_mode = (unsigned char) arg;
-		if (console != fg_console)
-			break;
-		/*
-		 * explicitly blank/unblank the screen if switching modes
-		 */
-		acquire_console_sem();
-		if (arg == KD_TEXT)
-			do_unblank_screen(1);
-		else
-			do_blank_screen(1);
-		release_console_sem();
-		break;
-
-	case KDGETMODE:
-		ucval = vc->vc_mode;
-		goto setint;
-
-	case KDMAPDISP:
-	case KDUNMAPDISP:
-		/*
-		 * these work like a combination of mmap and KDENABIO.
-		 * this could be easily finished.
-		 */
-		ret = -EINVAL;
-		break;
-
-	case KDSKBMODE:
-		if (!perm)
-			goto eperm;
-		switch(arg) {
-		  case K_RAW:
-			kbd->kbdmode = VC_RAW;
-			break;
-		  case K_MEDIUMRAW:
-			kbd->kbdmode = VC_MEDIUMRAW;
-			break;
-		  case K_XLATE:
-			kbd->kbdmode = VC_XLATE;
-			compute_shiftstate();
-			break;
-		  case K_UNICODE:
-			kbd->kbdmode = VC_UNICODE;
-			compute_shiftstate();
-			break;
-		  default:
-			ret = -EINVAL;
-			goto out;
-		}
-		tty_ldisc_flush(tty);
-		break;
-
-	case KDGKBMODE:
-		ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
-				 (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
-				 (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
-				 K_XLATE);
-		goto setint;
-
-	/* this could be folded into KDSKBMODE, but for compatibility
-	   reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
-	case KDSKBMETA:
-		switch(arg) {
-		  case K_METABIT:
-			clr_vc_kbd_mode(kbd, VC_META);
-			break;
-		  case K_ESCPREFIX:
-			set_vc_kbd_mode(kbd, VC_META);
-			break;
-		  default:
-			ret = -EINVAL;
-		}
-		break;
-
-	case KDGKBMETA:
-		ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
-	setint:
-		ret = put_user(ucval, (int __user *)arg);
-		break;
-
-	case KDGETKEYCODE:
-	case KDSETKEYCODE:
-		if(!capable(CAP_SYS_TTY_CONFIG))
-			perm = 0;
-		ret = do_kbkeycode_ioctl(cmd, up, perm);
-		break;
-
-	case KDGKBENT:
-	case KDSKBENT:
-		ret = do_kdsk_ioctl(cmd, up, perm, kbd);
-		break;
-
-	case KDGKBSENT:
-	case KDSKBSENT:
-		ret = do_kdgkb_ioctl(cmd, up, perm);
-		break;
-
-	case KDGKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		int i;
-
-		if (put_user(accent_table_size, &a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		for (i = 0; i < accent_table_size; i++) {
-			diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-			diacr.base = conv_uni_to_8bit(accent_table[i].base);
-			diacr.result = conv_uni_to_8bit(accent_table[i].result);
-			if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-		}
-		break;
-	}
-	case KDGKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-
-		if (put_user(accent_table_size, &a->kb_cnt))
-			ret = -EFAULT;
-		else if (copy_to_user(a->kbdiacruc, accent_table,
-				accent_table_size*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
-		break;
-	}
-
-	case KDSKBDIACR:
-	{
-		struct kbdiacrs __user *a = up;
-		struct kbdiacr diacr;
-		unsigned int ct;
-		int i;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		for (i = 0; i < ct; i++) {
-			if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-				ret = -EFAULT;
-				break;
-			}
-			accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-			accent_table[i].base = conv_8bit_to_uni(diacr.base);
-			accent_table[i].result = conv_8bit_to_uni(diacr.result);
-		}
-		break;
-	}
-
-	case KDSKBDIACRUC:
-	{
-		struct kbdiacrsuc __user *a = up;
-		unsigned int ct;
-
-		if (!perm)
-			goto eperm;
-		if (get_user(ct,&a->kb_cnt)) {
-			ret = -EFAULT;
-			break;
-		}
-		if (ct >= MAX_DIACR) {
-			ret = -EINVAL;
-			break;
-		}
-		accent_table_size = ct;
-		if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-			ret = -EFAULT;
-		break;
-	}
-
-	/* the ioctls below read/set the flags usually shown in the leds */
-	/* don't use them - they will go away without warning */
-	case KDGKBLED:
-		ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-		goto setchar;
-
-	case KDSKBLED:
-		if (!perm)
-			goto eperm;
-		if (arg & ~0x77) {
-			ret = -EINVAL;
-			break;
-		}
-		kbd->ledflagstate = (arg & 7);
-		kbd->default_ledflagstate = ((arg >> 4) & 7);
-		set_leds();
-		break;
-
-	/* the ioctls below only set the lights, not the functions */
-	/* for those, see KDGKBLED and KDSKBLED above */
-	case KDGETLED:
-		ucval = getledstate();
-	setchar:
-		ret = put_user(ucval, (char __user *)arg);
-		break;
-
-	case KDSETLED:
-		if (!perm)
-			goto eperm;
-		setledstate(kbd, arg);
-		break;
-
-	/*
-	 * A process can indicate its willingness to accept signals
-	 * generated by pressing an appropriate key combination.
-	 * Thus, one can have a daemon that e.g. spawns a new console
-	 * upon a keypress and then changes to it.
-	 * See also the kbrequest field of inittab(5).
-	 */
-	case KDSIGACCEPT:
-	{
-		if (!perm || !capable(CAP_KILL))
-			goto eperm;
-		if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
-			ret = -EINVAL;
-		else {
-			spin_lock_irq(&vt_spawn_con.lock);
-			put_pid(vt_spawn_con.pid);
-			vt_spawn_con.pid = get_pid(task_pid(current));
-			vt_spawn_con.sig = arg;
-			spin_unlock_irq(&vt_spawn_con.lock);
-		}
-		break;
-	}
-
-	case VT_SETMODE:
-	{
-		struct vt_mode tmp;
-
-		if (!perm)
-			goto eperm;
-		if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
-			ret = -EFAULT;
-			goto out;
-		}
-		if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
-			ret = -EINVAL;
-			goto out;
-		}
-		acquire_console_sem();
-		vc->vt_mode = tmp;
-		/* the frsig is ignored, so we set it to 0 */
-		vc->vt_mode.frsig = 0;
-		put_pid(vc->vt_pid);
-		vc->vt_pid = get_pid(task_pid(current));
-		/* no switch is required -- saw@shade.msu.ru */
-		vc->vt_newvt = -1;
-		release_console_sem();
-		break;
-	}
-
-	case VT_GETMODE:
-	{
-		struct vt_mode tmp;
-		int rc;
-
-		acquire_console_sem();
-		memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-		release_console_sem();
-
-		rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
-		if (rc)
-			ret = -EFAULT;
-		break;
-	}
-
-	/*
-	 * Returns global vt state. Note that VT 0 is always open, since
-	 * it's an alias for the current VT, and people can't use it here.
-	 * We cannot return state for more than 16 VTs, since v_state is short.
-	 */
-	case VT_GETSTATE:
-	{
-		struct vt_stat __user *vtstat = up;
-		unsigned short state, mask;
-
-		if (put_user(fg_console + 1, &vtstat->v_active))
-			ret = -EFAULT;
-		else {
-			state = 1;	/* /dev/tty0 is always open */
-			for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
-							++i, mask <<= 1)
-				if (VT_IS_IN_USE(i))
-					state |= mask;
-			ret = put_user(state, &vtstat->v_state);
-		}
-		break;
-	}
-
-	/*
-	 * Returns the first available (non-opened) console.
-	 */
-	case VT_OPENQRY:
-		for (i = 0; i < MAX_NR_CONSOLES; ++i)
-			if (! VT_IS_IN_USE(i))
-				break;
-		ucval = i < MAX_NR_CONSOLES ? (i+1) : -1;
-		goto setint;		 
-
-	/*
-	 * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
-	 * with num >= 1 (switches to vt 0, our console, are not allowed, just
-	 * to preserve sanity).
-	 */
-	case VT_ACTIVATE:
-		if (!perm)
-			goto eperm;
-		if (arg == 0 || arg > MAX_NR_CONSOLES)
-			ret =  -ENXIO;
-		else {
-			arg--;
-			acquire_console_sem();
-			ret = vc_allocate(arg);
-			release_console_sem();
-			if (ret)
-				break;
-			set_console(arg);
-		}
-		break;
-
-	case VT_SETACTIVATE:
-	{
-		struct vt_setactivate vsa;
-
-		if (!perm)
-			goto eperm;
-
-		if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
-					sizeof(struct vt_setactivate))) {
-			ret = -EFAULT;
-			goto out;
-		}
-		if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
-			ret = -ENXIO;
-		else {
-			vsa.console--;
-			acquire_console_sem();
-			ret = vc_allocate(vsa.console);
-			if (ret == 0) {
-				struct vc_data *nvc;
-				/* This is safe providing we don't drop the
-				   console sem between vc_allocate and
-				   finishing referencing nvc */
-				nvc = vc_cons[vsa.console].d;
-				nvc->vt_mode = vsa.mode;
-				nvc->vt_mode.frsig = 0;
-				put_pid(nvc->vt_pid);
-				nvc->vt_pid = get_pid(task_pid(current));
-			}
-			release_console_sem();
-			if (ret)
-				break;
-			/* Commence switch and lock */
-			set_console(arg);
-		}
-	}
-
-	/*
-	 * wait until the specified VT has been activated
-	 */
-	case VT_WAITACTIVE:
-		if (!perm)
-			goto eperm;
-		if (arg == 0 || arg > MAX_NR_CONSOLES)
-			ret = -ENXIO;
-		else
-			ret = vt_waitactive(arg);
-		break;
-
-	/*
-	 * If a vt is under process control, the kernel will not switch to it
-	 * immediately, but postpone the operation until the process calls this
-	 * ioctl, allowing the switch to complete.
-	 *
-	 * According to the X sources this is the behavior:
-	 *	0:	pending switch-from not OK
-	 *	1:	pending switch-from OK
-	 *	2:	completed switch-to OK
-	 */
-	case VT_RELDISP:
-		if (!perm)
-			goto eperm;
-
-		if (vc->vt_mode.mode != VT_PROCESS) {
-			ret = -EINVAL;
-			break;
-		}
-		/*
-		 * Switching-from response
-		 */
-		acquire_console_sem();
-		if (vc->vt_newvt >= 0) {
-			if (arg == 0)
-				/*
-				 * Switch disallowed, so forget we were trying
-				 * to do it.
-				 */
-				vc->vt_newvt = -1;
-
-			else {
-				/*
-				 * The current vt has been released, so
-				 * complete the switch.
-				 */
-				int newvt;
-				newvt = vc->vt_newvt;
-				vc->vt_newvt = -1;
-				ret = vc_allocate(newvt);
-				if (ret) {
-					release_console_sem();
-					break;
-				}
-				/*
-				 * When we actually do the console switch,
-				 * make sure we are atomic with respect to
-				 * other console switches..
-				 */
-				complete_change_console(vc_cons[newvt].d);
-			}
-		} else {
-			/*
-			 * Switched-to response
-			 */
-			/*
-			 * If it's just an ACK, ignore it
-			 */
-			if (arg != VT_ACKACQ)
-				ret = -EINVAL;
-		}
-		release_console_sem();
-		break;
-
-	 /*
-	  * Disallocate memory associated to VT (but leave VT1)
-	  */
-	 case VT_DISALLOCATE:
-		if (arg > MAX_NR_CONSOLES) {
-			ret = -ENXIO;
-			break;
-		}
-		if (arg == 0) {
-		    /* deallocate all unused consoles, but leave 0 */
-			acquire_console_sem();
-			for (i=1; i<MAX_NR_CONSOLES; i++)
-				if (! VT_BUSY(i))
-					vc_deallocate(i);
-			release_console_sem();
-		} else {
-			/* deallocate a single console, if possible */
-			arg--;
-			if (VT_BUSY(arg))
-				ret = -EBUSY;
-			else if (arg) {			      /* leave 0 */
-				acquire_console_sem();
-				vc_deallocate(arg);
-				release_console_sem();
-			}
-		}
-		break;
-
-	case VT_RESIZE:
-	{
-		struct vt_sizes __user *vtsizes = up;
-		struct vc_data *vc;
-
-		ushort ll,cc;
-		if (!perm)
-			goto eperm;
-		if (get_user(ll, &vtsizes->v_rows) ||
-		    get_user(cc, &vtsizes->v_cols))
-			ret = -EFAULT;
-		else {
-			acquire_console_sem();
-			for (i = 0; i < MAX_NR_CONSOLES; i++) {
-				vc = vc_cons[i].d;
-
-				if (vc) {
-					vc->vc_resize_user = 1;
-					vc_resize(vc_cons[i].d, cc, ll);
-				}
-			}
-			release_console_sem();
-		}
-		break;
-	}
-
-	case VT_RESIZEX:
-	{
-		struct vt_consize __user *vtconsize = up;
-		ushort ll,cc,vlin,clin,vcol,ccol;
-		if (!perm)
-			goto eperm;
-		if (!access_ok(VERIFY_READ, vtconsize,
-				sizeof(struct vt_consize))) {
-			ret = -EFAULT;
-			break;
-		}
-		/* FIXME: Should check the copies properly */
-		__get_user(ll, &vtconsize->v_rows);
-		__get_user(cc, &vtconsize->v_cols);
-		__get_user(vlin, &vtconsize->v_vlin);
-		__get_user(clin, &vtconsize->v_clin);
-		__get_user(vcol, &vtconsize->v_vcol);
-		__get_user(ccol, &vtconsize->v_ccol);
-		vlin = vlin ? vlin : vc->vc_scan_lines;
-		if (clin) {
-			if (ll) {
-				if (ll != vlin/clin) {
-					/* Parameters don't add up */
-					ret = -EINVAL;
-					break;
-				}
-			} else 
-				ll = vlin/clin;
-		}
-		if (vcol && ccol) {
-			if (cc) {
-				if (cc != vcol/ccol) {
-					ret = -EINVAL;
-					break;
-				}
-			} else
-				cc = vcol/ccol;
-		}
-
-		if (clin > 32) {
-			ret =  -EINVAL;
-			break;
-		}
-		    
-		for (i = 0; i < MAX_NR_CONSOLES; i++) {
-			if (!vc_cons[i].d)
-				continue;
-			acquire_console_sem();
-			if (vlin)
-				vc_cons[i].d->vc_scan_lines = vlin;
-			if (clin)
-				vc_cons[i].d->vc_font.height = clin;
-			vc_cons[i].d->vc_resize_user = 1;
-			vc_resize(vc_cons[i].d, cc, ll);
-			release_console_sem();
-		}
-		break;
-	}
-
-	case PIO_FONT: {
-		if (!perm)
-			goto eperm;
-		op.op = KD_FONT_OP_SET;
-		op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC;	/* Compatibility */
-		op.width = 8;
-		op.height = 0;
-		op.charcount = 256;
-		op.data = up;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		break;
-	}
-
-	case GIO_FONT: {
-		op.op = KD_FONT_OP_GET;
-		op.flags = KD_FONT_FLAG_OLD;
-		op.width = 8;
-		op.height = 32;
-		op.charcount = 256;
-		op.data = up;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		break;
-	}
-
-	case PIO_CMAP:
-                if (!perm)
-			ret = -EPERM;
-		else
-	                ret = con_set_cmap(up);
-		break;
-
-	case GIO_CMAP:
-                ret = con_get_cmap(up);
-		break;
-
-	case PIO_FONTX:
-	case GIO_FONTX:
-		ret = do_fontx_ioctl(cmd, up, perm, &op);
-		break;
-
-	case PIO_FONTRESET:
-	{
-		if (!perm)
-			goto eperm;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
-		/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
-		   font is not saved. */
-		ret = -ENOSYS;
-		break;
-#else
-		{
-		op.op = KD_FONT_OP_SET_DEFAULT;
-		op.data = NULL;
-		ret = con_font_op(vc_cons[fg_console].d, &op);
-		if (ret)
-			break;
-		con_set_default_unimap(vc_cons[fg_console].d);
-		break;
-		}
-#endif
-	}
-
-	case KDFONTOP: {
-		if (copy_from_user(&op, up, sizeof(op))) {
-			ret = -EFAULT;
-			break;
-		}
-		if (!perm && op.op != KD_FONT_OP_GET)
-			goto eperm;
-		ret = con_font_op(vc, &op);
-		if (ret)
-			break;
-		if (copy_to_user(up, &op, sizeof(op)))
-			ret = -EFAULT;
-		break;
-	}
-
-	case PIO_SCRNMAP:
-		if (!perm)
-			ret = -EPERM;
-		else
-			ret = con_set_trans_old(up);
-		break;
-
-	case GIO_SCRNMAP:
-		ret = con_get_trans_old(up);
-		break;
-
-	case PIO_UNISCRNMAP:
-		if (!perm)
-			ret = -EPERM;
-		else
-			ret = con_set_trans_new(up);
-		break;
-
-	case GIO_UNISCRNMAP:
-		ret = con_get_trans_new(up);
-		break;
-
-	case PIO_UNIMAPCLR:
-	      { struct unimapinit ui;
-		if (!perm)
-			goto eperm;
-		ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-		if (ret)
-			ret = -EFAULT;
-		else
-			con_clear_unimap(vc, &ui);
-		break;
-	      }
-
-	case PIO_UNIMAP:
-	case GIO_UNIMAP:
-		ret = do_unimap_ioctl(cmd, up, perm, vc);
-		break;
-
-	case VT_LOCKSWITCH:
-		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
-		vt_dont_switch = 1;
-		break;
-	case VT_UNLOCKSWITCH:
-		if (!capable(CAP_SYS_TTY_CONFIG))
-			goto eperm;
-		vt_dont_switch = 0;
-		break;
-	case VT_GETHIFONTMASK:
-		ret = put_user(vc->vc_hi_font_mask,
-					(unsigned short __user *)arg);
-		break;
-	case VT_WAITEVENT:
-		ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
-		break;
-	default:
-		ret = -ENOIOCTLCMD;
-	}
-out:
-	tty_unlock();
-	return ret;
-eperm:
-	ret = -EPERM;
-	goto out;
-}
-
-void reset_vc(struct vc_data *vc)
-{
-	vc->vc_mode = KD_TEXT;
-	kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-	vc->vt_mode.mode = VT_AUTO;
-	vc->vt_mode.waitv = 0;
-	vc->vt_mode.relsig = 0;
-	vc->vt_mode.acqsig = 0;
-	vc->vt_mode.frsig = 0;
-	put_pid(vc->vt_pid);
-	vc->vt_pid = NULL;
-	vc->vt_newvt = -1;
-	if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
-		reset_palette(vc);
-}
-
-void vc_SAK(struct work_struct *work)
-{
-	struct vc *vc_con =
-		container_of(work, struct vc, SAK_work);
-	struct vc_data *vc;
-	struct tty_struct *tty;
-
-	acquire_console_sem();
-	vc = vc_con->d;
-	if (vc) {
-		tty = vc->port.tty;
-		/*
-		 * SAK should also work in all raw modes and reset
-		 * them properly.
-		 */
-		if (tty)
-			__do_SAK(tty);
-		reset_vc(vc);
-	}
-	release_console_sem();
-}
-
-#ifdef CONFIG_COMPAT
-
-struct compat_consolefontdesc {
-	unsigned short charcount;       /* characters in font (256 or 512) */
-	unsigned short charheight;      /* scan lines per character (1-32) */
-	compat_caddr_t chardata;	/* font data in expanded form */
-};
-
-static inline int
-compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
-			 int perm, struct console_font_op *op)
-{
-	struct compat_consolefontdesc cfdarg;
-	int i;
-
-	if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
-		return -EFAULT;
-
-	switch (cmd) {
-	case PIO_FONTX:
-		if (!perm)
-			return -EPERM;
-		op->op = KD_FONT_OP_SET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = compat_ptr(cfdarg.chardata);
-		return con_font_op(vc_cons[fg_console].d, op);
-	case GIO_FONTX:
-		op->op = KD_FONT_OP_GET;
-		op->flags = KD_FONT_FLAG_OLD;
-		op->width = 8;
-		op->height = cfdarg.charheight;
-		op->charcount = cfdarg.charcount;
-		op->data = compat_ptr(cfdarg.chardata);
-		i = con_font_op(vc_cons[fg_console].d, op);
-		if (i)
-			return i;
-		cfdarg.charheight = op->height;
-		cfdarg.charcount = op->charcount;
-		if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
-			return -EFAULT;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-struct compat_console_font_op {
-	compat_uint_t op;        /* operation code KD_FONT_OP_* */
-	compat_uint_t flags;     /* KD_FONT_FLAG_* */
-	compat_uint_t width, height;     /* font size */
-	compat_uint_t charcount;
-	compat_caddr_t data;    /* font data with height fixed to 32 */
-};
-
-static inline int
-compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
-			 int perm, struct console_font_op *op, struct vc_data *vc)
-{
-	int i;
-
-	if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
-		return -EFAULT;
-	if (!perm && op->op != KD_FONT_OP_GET)
-		return -EPERM;
-	op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
-	op->flags |= KD_FONT_FLAG_OLD;
-	i = con_font_op(vc, op);
-	if (i)
-		return i;
-	((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
-	if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
-		return -EFAULT;
-	return 0;
-}
-
-struct compat_unimapdesc {
-	unsigned short entry_ct;
-	compat_caddr_t entries;
-};
-
-static inline int
-compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
-			 int perm, struct vc_data *vc)
-{
-	struct compat_unimapdesc tmp;
-	struct unipair __user *tmp_entries;
-
-	if (copy_from_user(&tmp, user_ud, sizeof tmp))
-		return -EFAULT;
-	tmp_entries = compat_ptr(tmp.entries);
-	if (tmp_entries)
-		if (!access_ok(VERIFY_WRITE, tmp_entries,
-				tmp.entry_ct*sizeof(struct unipair)))
-			return -EFAULT;
-	switch (cmd) {
-	case PIO_UNIMAP:
-		if (!perm)
-			return -EPERM;
-		return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
-	case GIO_UNIMAP:
-		if (!perm && fg_console != vc->vc_num)
-			return -EPERM;
-		return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
-	}
-	return 0;
-}
-
-long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
-	     unsigned int cmd, unsigned long arg)
-{
-	struct vc_data *vc = tty->driver_data;
-	struct console_font_op op;	/* used in multiple places here */
-	struct kbd_struct *kbd;
-	unsigned int console;
-	void __user *up = (void __user *)arg;
-	int perm;
-	int ret = 0;
-
-	console = vc->vc_num;
-
-	tty_lock();
-
-	if (!vc_cons_allocated(console)) { 	/* impossible? */
-		ret = -ENOIOCTLCMD;
-		goto out;
-	}
-
-	/*
-	 * To have permissions to do most of the vt ioctls, we either have
-	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-	 */
-	perm = 0;
-	if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-		perm = 1;
-
-	kbd = kbd_table + console;
-	switch (cmd) {
-	/*
-	 * these need special handlers for incompatible data structures
-	 */
-	case PIO_FONTX:
-	case GIO_FONTX:
-		ret = compat_fontx_ioctl(cmd, up, perm, &op);
-		break;
-
-	case KDFONTOP:
-		ret = compat_kdfontop_ioctl(up, perm, &op, vc);
-		break;
-
-	case PIO_UNIMAP:
-	case GIO_UNIMAP:
-		ret = compat_unimap_ioctl(cmd, up, perm, vc);
-		break;
-
-	/*
-	 * all these treat 'arg' as an integer
-	 */
-	case KIOCSOUND:
-	case KDMKTONE:
-#ifdef CONFIG_X86
-	case KDADDIO:
-	case KDDELIO:
-#endif
-	case KDSETMODE:
-	case KDMAPDISP:
-	case KDUNMAPDISP:
-	case KDSKBMODE:
-	case KDSKBMETA:
-	case KDSKBLED:
-	case KDSETLED:
-	case KDSIGACCEPT:
-	case VT_ACTIVATE:
-	case VT_WAITACTIVE:
-	case VT_RELDISP:
-	case VT_DISALLOCATE:
-	case VT_RESIZE:
-	case VT_RESIZEX:
-		goto fallback;
-
-	/*
-	 * the rest has a compatible data structure behind arg,
-	 * but we have to convert it to a proper 64 bit pointer.
-	 */
-	default:
-		arg = (unsigned long)compat_ptr(arg);
-		goto fallback;
-	}
-out:
-	tty_unlock();
-	return ret;
-
-fallback:
-	tty_unlock();
-	return vt_ioctl(tty, file, cmd, arg);
-}
-
-
-#endif /* CONFIG_COMPAT */
-
-
-/*
- * Performs the back end of a vt switch. Called under the console
- * semaphore.
- */
-static void complete_change_console(struct vc_data *vc)
-{
-	unsigned char old_vc_mode;
-	int old = fg_console;
-
-	last_console = fg_console;
-
-	/*
-	 * If we're switching, we could be going from KD_GRAPHICS to
-	 * KD_TEXT mode or vice versa, which means we need to blank or
-	 * unblank the screen later.
-	 */
-	old_vc_mode = vc_cons[fg_console].d->vc_mode;
-	switch_screen(vc);
-
-	/*
-	 * This can't appear below a successful kill_pid().  If it did,
-	 * then the *blank_screen operation could occur while X, having
-	 * received acqsig, is waking up on another processor.  This
-	 * condition can lead to overlapping accesses to the VGA range
-	 * and the framebuffer (causing system lockups).
-	 *
-	 * To account for this we duplicate this code below only if the
-	 * controlling process is gone and we've called reset_vc.
-	 */
-	if (old_vc_mode != vc->vc_mode) {
-		if (vc->vc_mode == KD_TEXT)
-			do_unblank_screen(1);
-		else
-			do_blank_screen(1);
-	}
-
-	/*
-	 * If this new console is under process control, send it a signal
-	 * telling it that it has acquired. Also check if it has died and
-	 * clean up (similar to logic employed in change_console())
-	 */
-	if (vc->vt_mode.mode == VT_PROCESS) {
-		/*
-		 * Send the signal as privileged - kill_pid() will
-		 * tell us if the process has gone or something else
-		 * is awry
-		 */
-		if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
-		/*
-		 * The controlling process has died, so we revert back to
-		 * normal operation. In this case, we'll also change back
-		 * to KD_TEXT mode. I'm not sure if this is strictly correct
-		 * but it saves the agony when the X server dies and the screen
-		 * remains blanked due to KD_GRAPHICS! It would be nice to do
-		 * this outside of VT_PROCESS but there is no single process
-		 * to account for and tracking tty count may be undesirable.
-		 */
-			reset_vc(vc);
-
-			if (old_vc_mode != vc->vc_mode) {
-				if (vc->vc_mode == KD_TEXT)
-					do_unblank_screen(1);
-				else
-					do_blank_screen(1);
-			}
-		}
-	}
-
-	/*
-	 * Wake anyone waiting for their VT to activate
-	 */
-	vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
-	return;
-}
-
-/*
- * Performs the front-end of a vt switch
- */
-void change_console(struct vc_data *new_vc)
-{
-	struct vc_data *vc;
-
-	if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
-		return;
-
-	/*
-	 * If this vt is in process mode, then we need to handshake with
-	 * that process before switching. Essentially, we store where that
-	 * vt wants to switch to and wait for it to tell us when it's done
-	 * (via VT_RELDISP ioctl).
-	 *
-	 * We also check to see if the controlling process still exists.
-	 * If it doesn't, we reset this vt to auto mode and continue.
-	 * This is a cheap way to track process control. The worst thing
-	 * that can happen is: we send a signal to a process, it dies, and
-	 * the switch gets "lost" waiting for a response; hopefully, the
-	 * user will try again, we'll detect the process is gone (unless
-	 * the user waits just the right amount of time :-) and revert the
-	 * vt to auto control.
-	 */
-	vc = vc_cons[fg_console].d;
-	if (vc->vt_mode.mode == VT_PROCESS) {
-		/*
-		 * Send the signal as privileged - kill_pid() will
-		 * tell us if the process has gone or something else
-		 * is awry.
-		 *
-		 * We need to set vt_newvt *before* sending the signal or we
-		 * have a race.
-		 */
-		vc->vt_newvt = new_vc->vc_num;
-		if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
-			/*
-			 * It worked. Mark the vt to switch to and
-			 * return. The process needs to send us a
-			 * VT_RELDISP ioctl to complete the switch.
-			 */
-			return;
-		}
-
-		/*
-		 * The controlling process has died, so we revert back to
-		 * normal operation. In this case, we'll also change back
-		 * to KD_TEXT mode. I'm not sure if this is strictly correct
-		 * but it saves the agony when the X server dies and the screen
-		 * remains blanked due to KD_GRAPHICS! It would be nice to do
-		 * this outside of VT_PROCESS but there is no single process
-		 * to account for and tracking tty count may be undesirable.
-		 */
-		reset_vc(vc);
-
-		/*
-		 * Fall through to normal (VT_AUTO) handling of the switch...
-		 */
-	}
-
-	/*
-	 * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
-	 */
-	if (vc->vc_mode == KD_GRAPHICS)
-		return;
-
-	complete_change_console(new_vc);
-}
-
-/* Perform a kernel triggered VT switch for suspend/resume */
-
-static int disable_vt_switch;
-
-int vt_move_to_console(unsigned int vt, int alloc)
-{
-	int prev;
-
-	acquire_console_sem();
-	/* Graphics mode - up to X */
-	if (disable_vt_switch) {
-		release_console_sem();
-		return 0;
-	}
-	prev = fg_console;
-
-	if (alloc && vc_allocate(vt)) {
-		/* we can't have a free VC for now. Too bad,
-		 * we don't want to mess the screen for now. */
-		release_console_sem();
-		return -ENOSPC;
-	}
-
-	if (set_console(vt)) {
-		/*
-		 * We're unable to switch to the SUSPEND_CONSOLE.
-		 * Let the calling function know so it can decide
-		 * what to do.
-		 */
-		release_console_sem();
-		return -EIO;
-	}
-	release_console_sem();
-	tty_lock();
-	if (vt_waitactive(vt + 1)) {
-		pr_debug("Suspend: Can't switch VCs.");
-		tty_unlock();
-		return -EINTR;
-	}
-	tty_unlock();
-	return prev;
-}
-
-/*
- * Normally during a suspend, we allocate a new console and switch to it.
- * When we resume, we switch back to the original console.  This switch
- * can be slow, so on systems where the framebuffer can handle restoration
- * of video registers anyways, there's little point in doing the console
- * switch.  This function allows you to disable it by passing it '0'.
- */
-void pm_set_vt_switch(int do_switch)
-{
-	acquire_console_sem();
-	disable_vt_switch = !do_switch;
-	release_console_sem();
-}
-EXPORT_SYMBOL(pm_set_vt_switch);
diff -druN linux-libre-2.6.36-gnu/drivers/char/xilinx_hwicap/xilinx_hwicap.c linux-libre-2.6.37-gnu/drivers/char/xilinx_hwicap/xilinx_hwicap.c
--- linux-libre-2.6.36-gnu/drivers/char/xilinx_hwicap/xilinx_hwicap.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/char/xilinx_hwicap/xilinx_hwicap.c	2011-01-04 19:50:19.000000000 -0500
@@ -81,7 +81,6 @@
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
 #include <linux/mutex.h>
-#include <linux/smp_lock.h>
 #include <linux/sysctl.h>
 #include <linux/fs.h>
 #include <linux/cdev.h>
@@ -112,6 +111,7 @@
 #define HWICAP_DEVICES 1
 
 /* An array, which is set to true when the device is registered. */
+static DEFINE_MUTEX(hwicap_mutex);
 static bool probed_devices[HWICAP_DEVICES];
 static struct mutex icap_sem;
 
@@ -502,7 +502,7 @@
 	struct hwicap_drvdata *drvdata;
 	int status;
 
-	lock_kernel();
+	mutex_lock(&hwicap_mutex);
 	drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
 
 	status = mutex_lock_interruptible(&drvdata->sem);
@@ -528,7 +528,7 @@
  error:
 	mutex_unlock(&drvdata->sem);
  out:
-	unlock_kernel();
+	mutex_unlock(&hwicap_mutex);
 	return status;
 }
 
@@ -567,6 +567,7 @@
 	.read = hwicap_read,
 	.open = hwicap_open,
 	.release = hwicap_release,
+	.llseek = noop_llseek,
 };
 
 static int __devinit hwicap_setup(struct device *dev, int id,
diff -druN linux-libre-2.6.36-gnu/drivers/clocksource/sh_cmt.c linux-libre-2.6.37-gnu/drivers/clocksource/sh_cmt.c
--- linux-libre-2.6.36-gnu/drivers/clocksource/sh_cmt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/clocksource/sh_cmt.c	2011-01-04 19:50:19.000000000 -0500
@@ -283,16 +283,21 @@
 	} while (delay);
 }
 
-static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
 {
-	unsigned long flags;
-
 	if (delta > p->max_match_value)
 		dev_warn(&p->pdev->dev, "delta out of range\n");
 
-	spin_lock_irqsave(&p->lock, flags);
 	p->next_match_value = delta;
 	sh_cmt_clock_event_program_verify(p, 0);
+}
+
+static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	__sh_cmt_set_next(p, delta);
 	spin_unlock_irqrestore(&p->lock, flags);
 }
 
@@ -308,7 +313,7 @@
 	 * isr before we end up here.
 	 */
 	if (p->flags & FLAG_CLOCKSOURCE)
-		p->total_cycles += p->match_value;
+		p->total_cycles += p->match_value + 1;
 
 	if (!(p->flags & FLAG_REPROGRAM))
 		p->next_match_value = p->max_match_value;
@@ -359,7 +364,7 @@
 
 	/* setup timeout if no clockevent */
 	if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT)))
-		sh_cmt_set_next(p, p->max_match_value);
+		__sh_cmt_set_next(p, p->max_match_value);
  out:
 	spin_unlock_irqrestore(&p->lock, flags);
 
@@ -381,7 +386,7 @@
 
 	/* adjust the timeout to maximum if only clocksource left */
 	if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE))
-		sh_cmt_set_next(p, p->max_match_value);
+		__sh_cmt_set_next(p, p->max_match_value);
 
 	spin_unlock_irqrestore(&p->lock, flags);
 }
@@ -403,7 +408,7 @@
 	raw = sh_cmt_get_counter(p, &has_wrapped);
 
 	if (unlikely(has_wrapped))
-		raw += p->match_value;
+		raw += p->match_value + 1;
 	spin_unlock_irqrestore(&p->lock, flags);
 
 	return value + raw;
@@ -445,7 +450,7 @@
 
 	/* clk_get_rate() needs an enabled clock */
 	clk_enable(p->clk);
-	p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+	p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
 	clk_disable(p->clk);
 
 	/* TODO: calculate good shift from rate and counter bit width */
@@ -478,7 +483,7 @@
 	ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
 
 	if (periodic)
-		sh_cmt_set_next(p, (p->rate + HZ/2) / HZ);
+		sh_cmt_set_next(p, ((p->rate + HZ/2) / HZ) - 1);
 	else
 		sh_cmt_set_next(p, p->max_match_value);
 }
@@ -523,9 +528,9 @@
 
 	BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
 	if (likely(p->flags & FLAG_IRQCONTEXT))
-		p->next_match_value = delta;
+		p->next_match_value = delta - 1;
 	else
-		sh_cmt_set_next(p, delta);
+		sh_cmt_set_next(p, delta - 1);
 
 	return 0;
 }
@@ -616,13 +621,9 @@
 	/* get hold of clock */
 	p->clk = clk_get(&p->pdev->dev, "cmt_fck");
 	if (IS_ERR(p->clk)) {
-		dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-		p->clk = clk_get(&p->pdev->dev, cfg->clk);
-		if (IS_ERR(p->clk)) {
-			dev_err(&p->pdev->dev, "cannot get clock\n");
-			ret = PTR_ERR(p->clk);
-			goto err1;
-		}
+		dev_err(&p->pdev->dev, "cannot get clock\n");
+		ret = PTR_ERR(p->clk);
+		goto err1;
 	}
 
 	if (resource_size(res) == 6) {
diff -druN linux-libre-2.6.36-gnu/drivers/clocksource/sh_mtu2.c linux-libre-2.6.37-gnu/drivers/clocksource/sh_mtu2.c
--- linux-libre-2.6.36-gnu/drivers/clocksource/sh_mtu2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/clocksource/sh_mtu2.c	2011-01-04 19:50:19.000000000 -0500
@@ -287,13 +287,9 @@
 	/* get hold of clock */
 	p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
 	if (IS_ERR(p->clk)) {
-		dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-		p->clk = clk_get(&p->pdev->dev, cfg->clk);
-		if (IS_ERR(p->clk)) {
-			dev_err(&p->pdev->dev, "cannot get clock\n");
-			ret = PTR_ERR(p->clk);
-			goto err1;
-		}
+		dev_err(&p->pdev->dev, "cannot get clock\n");
+		ret = PTR_ERR(p->clk);
+		goto err1;
 	}
 
 	return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
diff -druN linux-libre-2.6.36-gnu/drivers/clocksource/sh_tmu.c linux-libre-2.6.37-gnu/drivers/clocksource/sh_tmu.c
--- linux-libre-2.6.36-gnu/drivers/clocksource/sh_tmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/clocksource/sh_tmu.c	2011-01-04 19:50:19.000000000 -0500
@@ -393,13 +393,9 @@
 	/* get hold of clock */
 	p->clk = clk_get(&p->pdev->dev, "tmu_fck");
 	if (IS_ERR(p->clk)) {
-		dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-		p->clk = clk_get(&p->pdev->dev, cfg->clk);
-		if (IS_ERR(p->clk)) {
-			dev_err(&p->pdev->dev, "cannot get clock\n");
-			ret = PTR_ERR(p->clk);
-			goto err1;
-		}
+		dev_err(&p->pdev->dev, "cannot get clock\n");
+		ret = PTR_ERR(p->clk);
+		goto err1;
 	}
 
 	return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
diff -druN linux-libre-2.6.36-gnu/drivers/connector/cn_queue.c linux-libre-2.6.37-gnu/drivers/connector/cn_queue.c
--- linux-libre-2.6.36-gnu/drivers/connector/cn_queue.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/connector/cn_queue.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,48 +31,6 @@
 #include <linux/connector.h>
 #include <linux/delay.h>
 
-
-/*
- * This job is sent to the kevent workqueue.
- * While no event is once sent to any callback, the connector workqueue
- * is not created to avoid a useless waiting kernel task.
- * Once the first event is received, we create this dedicated workqueue which
- * is necessary because the flow of data can be high and we don't want
- * to encumber keventd with that.
- */
-static void cn_queue_create(struct work_struct *work)
-{
-	struct cn_queue_dev *dev;
-
-	dev = container_of(work, struct cn_queue_dev, wq_creation);
-
-	dev->cn_queue = create_singlethread_workqueue(dev->name);
-	/* If we fail, we will use keventd for all following connector jobs */
-	WARN_ON(!dev->cn_queue);
-}
-
-/*
- * Queue a data sent to a callback.
- * If the connector workqueue is already created, we queue the job on it.
- * Otherwise, we queue the job to kevent and queue the connector workqueue
- * creation too.
- */
-int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work)
-{
-	struct cn_queue_dev *pdev = cbq->pdev;
-
-	if (likely(pdev->cn_queue))
-		return queue_work(pdev->cn_queue, work);
-
-	/* Don't create the connector workqueue twice */
-	if (atomic_inc_return(&pdev->wq_requested) == 1)
-		schedule_work(&pdev->wq_creation);
-	else
-		atomic_dec(&pdev->wq_requested);
-
-	return schedule_work(work);
-}
-
 void cn_queue_wrapper(struct work_struct *work)
 {
 	struct cn_callback_entry *cbq =
@@ -111,11 +69,7 @@
 
 static void cn_queue_free_callback(struct cn_callback_entry *cbq)
 {
-	/* The first jobs have been sent to kevent, flush them too */
-	flush_scheduled_work();
-	if (cbq->pdev->cn_queue)
-		flush_workqueue(cbq->pdev->cn_queue);
-
+	flush_workqueue(cbq->pdev->cn_queue);
 	kfree(cbq);
 }
 
@@ -193,11 +147,14 @@
 	atomic_set(&dev->refcnt, 0);
 	INIT_LIST_HEAD(&dev->queue_list);
 	spin_lock_init(&dev->queue_lock);
-	init_waitqueue_head(&dev->wq_created);
 
 	dev->nls = nls;
 
-	INIT_WORK(&dev->wq_creation, cn_queue_create);
+	dev->cn_queue = alloc_ordered_workqueue(dev->name, 0);
+	if (!dev->cn_queue) {
+		kfree(dev);
+		return NULL;
+	}
 
 	return dev;
 }
@@ -205,25 +162,9 @@
 void cn_queue_free_dev(struct cn_queue_dev *dev)
 {
 	struct cn_callback_entry *cbq, *n;
-	long timeout;
-	DEFINE_WAIT(wait);
 
-	/* Flush the first pending jobs queued on kevent */
-	flush_scheduled_work();
-
-	/* If the connector workqueue creation is still pending, wait for it */
-	prepare_to_wait(&dev->wq_created, &wait, TASK_UNINTERRUPTIBLE);
-	if (atomic_read(&dev->wq_requested) && !dev->cn_queue) {
-		timeout = schedule_timeout(HZ * 2);
-		if (!timeout && !dev->cn_queue)
-			WARN_ON(1);
-	}
-	finish_wait(&dev->wq_created, &wait);
-
-	if (dev->cn_queue) {
-		flush_workqueue(dev->cn_queue);
-		destroy_workqueue(dev->cn_queue);
-	}
+	flush_workqueue(dev->cn_queue);
+	destroy_workqueue(dev->cn_queue);
 
 	spin_lock_bh(&dev->queue_lock);
 	list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)
diff -druN linux-libre-2.6.36-gnu/drivers/connector/connector.c linux-libre-2.6.37-gnu/drivers/connector/connector.c
--- linux-libre-2.6.36-gnu/drivers/connector/connector.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/connector/connector.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,6 +36,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR);
 
 static struct cn_dev cdev;
 
@@ -133,7 +134,8 @@
 					__cbq->data.skb == NULL)) {
 				__cbq->data.skb = skb;
 
-				if (queue_cn_work(__cbq, &__cbq->work))
+				if (queue_work(dev->cbdev->cn_queue,
+					       &__cbq->work))
 					err = 0;
 				else
 					err = -EINVAL;
@@ -148,13 +150,11 @@
 					d->callback = __cbq->data.callback;
 					d->free = __new_cbq;
 
-					__new_cbq->pdev = __cbq->pdev;
-
 					INIT_WORK(&__new_cbq->work,
 							&cn_queue_wrapper);
 
-					if (queue_cn_work(__new_cbq,
-						    &__new_cbq->work))
+					if (queue_work(dev->cbdev->cn_queue,
+						       &__new_cbq->work))
 						err = 0;
 					else {
 						kfree(__new_cbq);
diff -druN linux-libre-2.6.36-gnu/drivers/cpufreq/cpufreq.c linux-libre-2.6.37-gnu/drivers/cpufreq/cpufreq.c
--- linux-libre-2.6.36-gnu/drivers/cpufreq/cpufreq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/cpufreq/cpufreq.c	2011-01-04 19:50:19.000000000 -0500
@@ -918,8 +918,8 @@
 
 	spin_lock_irqsave(&cpufreq_driver_lock, flags);
 	for_each_cpu(j, policy->cpus) {
-	if (!cpu_online(j))
-		continue;
+		if (!cpu_online(j))
+			continue;
 		per_cpu(cpufreq_cpu_data, j) = policy;
 		per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/cpufreq/cpufreq_ondemand.c linux-libre-2.6.37-gnu/drivers/cpufreq/cpufreq_ondemand.c
--- linux-libre-2.6.36-gnu/drivers/cpufreq/cpufreq_ondemand.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/cpufreq/cpufreq_ondemand.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,8 @@
 
 #define DEF_FREQUENCY_DOWN_DIFFERENTIAL		(10)
 #define DEF_FREQUENCY_UP_THRESHOLD		(80)
+#define DEF_SAMPLING_DOWN_FACTOR		(1)
+#define MAX_SAMPLING_DOWN_FACTOR		(100000)
 #define MICRO_FREQUENCY_DOWN_DIFFERENTIAL	(3)
 #define MICRO_FREQUENCY_UP_THRESHOLD		(95)
 #define MICRO_FREQUENCY_MIN_SAMPLE_RATE		(10000)
@@ -82,6 +84,7 @@
 	unsigned int freq_lo;
 	unsigned int freq_lo_jiffies;
 	unsigned int freq_hi_jiffies;
+	unsigned int rate_mult;
 	int cpu;
 	unsigned int sample_type:1;
 	/*
@@ -108,10 +111,12 @@
 	unsigned int up_threshold;
 	unsigned int down_differential;
 	unsigned int ignore_nice;
+	unsigned int sampling_down_factor;
 	unsigned int powersave_bias;
 	unsigned int io_is_busy;
 } dbs_tuners_ins = {
 	.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+	.sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
 	.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
 	.ignore_nice = 0,
 	.powersave_bias = 0,
@@ -259,6 +264,7 @@
 show_one(sampling_rate, sampling_rate);
 show_one(io_is_busy, io_is_busy);
 show_one(up_threshold, up_threshold);
+show_one(sampling_down_factor, sampling_down_factor);
 show_one(ignore_nice_load, ignore_nice);
 show_one(powersave_bias, powersave_bias);
 
@@ -340,6 +346,29 @@
 	return count;
 }
 
+static ssize_t store_sampling_down_factor(struct kobject *a,
+			struct attribute *b, const char *buf, size_t count)
+{
+	unsigned int input, j;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+
+	if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
+		return -EINVAL;
+	mutex_lock(&dbs_mutex);
+	dbs_tuners_ins.sampling_down_factor = input;
+
+	/* Reset down sampling multiplier in case it was active */
+	for_each_online_cpu(j) {
+		struct cpu_dbs_info_s *dbs_info;
+		dbs_info = &per_cpu(od_cpu_dbs_info, j);
+		dbs_info->rate_mult = 1;
+	}
+	mutex_unlock(&dbs_mutex);
+
+	return count;
+}
+
 static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
 				      const char *buf, size_t count)
 {
@@ -401,6 +430,7 @@
 define_one_global_rw(sampling_rate);
 define_one_global_rw(io_is_busy);
 define_one_global_rw(up_threshold);
+define_one_global_rw(sampling_down_factor);
 define_one_global_rw(ignore_nice_load);
 define_one_global_rw(powersave_bias);
 
@@ -409,6 +439,7 @@
 	&sampling_rate_min.attr,
 	&sampling_rate.attr,
 	&up_threshold.attr,
+	&sampling_down_factor.attr,
 	&ignore_nice_load.attr,
 	&powersave_bias.attr,
 	&io_is_busy.attr,
@@ -562,6 +593,10 @@
 
 	/* Check for frequency increase */
 	if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
+		/* If switching to max speed, apply sampling_down_factor */
+		if (policy->cur < policy->max)
+			this_dbs_info->rate_mult =
+				dbs_tuners_ins.sampling_down_factor;
 		dbs_freq_increase(policy, policy->max);
 		return;
 	}
@@ -584,6 +619,9 @@
 				(dbs_tuners_ins.up_threshold -
 				 dbs_tuners_ins.down_differential);
 
+		/* No longer fully busy, reset rate_mult */
+		this_dbs_info->rate_mult = 1;
+
 		if (freq_next < policy->min)
 			freq_next = policy->min;
 
@@ -607,7 +645,8 @@
 	int sample_type = dbs_info->sample_type;
 
 	/* We want all CPUs to do sampling nearly on same jiffy */
-	int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+	int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
+		* dbs_info->rate_mult);
 
 	if (num_online_cpus() > 1)
 		delay -= jiffies % delay;
@@ -711,6 +750,7 @@
 			}
 		}
 		this_dbs_info->cpu = cpu;
+		this_dbs_info->rate_mult = 1;
 		ondemand_powersave_bias_init_cpu(cpu);
 		/*
 		 * Start the timerschedule work, when this governor
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/amcc/Makefile linux-libre-2.6.37-gnu/drivers/crypto/amcc/Makefile
--- linux-libre-2.6.36-gnu/drivers/crypto/amcc/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/amcc/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,2 +1,2 @@
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += crypto4xx.o
-crypto4xx-objs :=  crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
+crypto4xx-y :=  crypto4xx_core.o crypto4xx_alg.o crypto4xx_sa.o
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/hifn_795x.c linux-libre-2.6.37-gnu/drivers/crypto/hifn_795x.c
--- linux-libre-2.6.36-gnu/drivers/crypto/hifn_795x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/hifn_795x.c	2011-01-04 19:50:19.000000000 -0500
@@ -1467,7 +1467,7 @@
 		return -EINVAL;
 
 	while (size) {
-		copy = min(drest, min(size, dst->length));
+		copy = min3(drest, size, dst->length);
 
 		size -= copy;
 		drest -= copy;
@@ -1729,7 +1729,7 @@
 		return -EINVAL;
 
 	while (size) {
-		copy = min(srest, min(dst->length, size));
+		copy = min3(srest, dst->length, size);
 
 		daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
 		memcpy(daddr + dst->offset + offset, saddr, copy);
@@ -2700,8 +2700,7 @@
 	dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		cancel_delayed_work(&dev->work);
-		flush_scheduled_work();
+		cancel_delayed_work_sync(&dev->work);
 
 		hifn_unregister_rng(dev);
 		hifn_unregister_alg(dev);
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/Kconfig linux-libre-2.6.37-gnu/drivers/crypto/Kconfig
--- linux-libre-2.6.36-gnu/drivers/crypto/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -172,6 +172,7 @@
 
 config CRYPTO_DEV_NIAGARA2
        tristate "Niagara2 Stream Processing Unit driver"
+       select CRYPTO_DES
        select CRYPTO_ALGAPI
        depends on SPARC64
        help
@@ -243,4 +244,12 @@
 	  OMAP processors have SHA1/MD5 hw accelerator. Select this if you
 	  want to use the OMAP module for SHA1/MD5 algorithms.
 
+config CRYPTO_DEV_OMAP_AES
+	tristate "Support for OMAP AES hw engine"
+	depends on ARCH_OMAP2 || ARCH_OMAP3
+	select CRYPTO_AES
+	help
+	  OMAP processors have AES module accelerator. Select this if you
+	  want to use the OMAP module for AES algorithms.
+
 endif # CRYPTO_HW
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/Makefile linux-libre-2.6.37-gnu/drivers/crypto/Makefile
--- linux-libre-2.6.36-gnu/drivers/crypto/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -2,11 +2,12 @@
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
-n2_crypto-objs := n2_core.o n2_asm.o
+n2_crypto-y := n2_core.o n2_asm.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
 obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
 obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
 obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
 
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/n2_core.c linux-libre-2.6.37-gnu/drivers/crypto/n2_core.c
--- linux-libre-2.6.36-gnu/drivers/crypto/n2_core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/n2_core.c	2011-01-04 19:50:19.000000000 -0500
@@ -1832,7 +1832,7 @@
 		return -ENODEV;
 
 	ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
-	if (!intr)
+	if (!ino)
 		return -ENODEV;
 
 	if (intr_len != ino_len)
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/omap-aes.c linux-libre-2.6.37-gnu/drivers/crypto/omap-aes.c
--- linux-libre-2.6.36-gnu/drivers/crypto/omap-aes.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/crypto/omap-aes.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,948 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for OMAP AES HW acceleration.
+ *
+ * Copyright (c) 2010 Nokia Corporation
+ * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+
+#include <plat/cpu.h>
+#include <plat/dma.h>
+
+/* OMAP TRM gives bitfields as start:end, where start is the higher bit
+   number. For example 7:0 */
+#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))
+#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
+
+#define AES_REG_KEY(x)			(0x1C - ((x ^ 0x01) * 0x04))
+#define AES_REG_IV(x)			(0x20 + ((x) * 0x04))
+
+#define AES_REG_CTRL			0x30
+#define AES_REG_CTRL_CTR_WIDTH		(1 << 7)
+#define AES_REG_CTRL_CTR		(1 << 6)
+#define AES_REG_CTRL_CBC		(1 << 5)
+#define AES_REG_CTRL_KEY_SIZE		(3 << 3)
+#define AES_REG_CTRL_DIRECTION		(1 << 2)
+#define AES_REG_CTRL_INPUT_READY	(1 << 1)
+#define AES_REG_CTRL_OUTPUT_READY	(1 << 0)
+
+#define AES_REG_DATA			0x34
+#define AES_REG_DATA_N(x)		(0x34 + ((x) * 0x04))
+
+#define AES_REG_REV			0x44
+#define AES_REG_REV_MAJOR		0xF0
+#define AES_REG_REV_MINOR		0x0F
+
+#define AES_REG_MASK			0x48
+#define AES_REG_MASK_SIDLE		(1 << 6)
+#define AES_REG_MASK_START		(1 << 5)
+#define AES_REG_MASK_DMA_OUT_EN		(1 << 3)
+#define AES_REG_MASK_DMA_IN_EN		(1 << 2)
+#define AES_REG_MASK_SOFTRESET		(1 << 1)
+#define AES_REG_AUTOIDLE		(1 << 0)
+
+#define AES_REG_SYSSTATUS		0x4C
+#define AES_REG_SYSSTATUS_RESETDONE	(1 << 0)
+
+#define DEFAULT_TIMEOUT		(5*HZ)
+
+#define FLAGS_MODE_MASK		0x000f
+#define FLAGS_ENCRYPT		BIT(0)
+#define FLAGS_CBC		BIT(1)
+#define FLAGS_GIV		BIT(2)
+
+#define FLAGS_NEW_KEY		BIT(4)
+#define FLAGS_NEW_IV		BIT(5)
+#define FLAGS_INIT		BIT(6)
+#define FLAGS_FAST		BIT(7)
+#define FLAGS_BUSY		8
+
+struct omap_aes_ctx {
+	struct omap_aes_dev *dd;
+
+	int		keylen;
+	u32		key[AES_KEYSIZE_256 / sizeof(u32)];
+	unsigned long	flags;
+};
+
+struct omap_aes_reqctx {
+	unsigned long mode;
+};
+
+#define OMAP_AES_QUEUE_LENGTH	1
+#define OMAP_AES_CACHE_SIZE	0
+
+struct omap_aes_dev {
+	struct list_head	list;
+	unsigned long		phys_base;
+	void __iomem 		*io_base;
+	struct clk		*iclk;
+	struct omap_aes_ctx	*ctx;
+	struct device		*dev;
+	unsigned long		flags;
+
+	u32			*iv;
+	u32			ctrl;
+
+	spinlock_t			lock;
+	struct crypto_queue		queue;
+
+	struct tasklet_struct		task;
+
+	struct ablkcipher_request	*req;
+	size_t				total;
+	struct scatterlist		*in_sg;
+	size_t				in_offset;
+	struct scatterlist		*out_sg;
+	size_t				out_offset;
+
+	size_t			buflen;
+	void			*buf_in;
+	size_t			dma_size;
+	int			dma_in;
+	int			dma_lch_in;
+	dma_addr_t		dma_addr_in;
+	void			*buf_out;
+	int			dma_out;
+	int			dma_lch_out;
+	dma_addr_t		dma_addr_out;
+};
+
+/* keep registered devices data here */
+static LIST_HEAD(dev_list);
+static DEFINE_SPINLOCK(list_lock);
+
+static inline u32 omap_aes_read(struct omap_aes_dev *dd, u32 offset)
+{
+	return __raw_readl(dd->io_base + offset);
+}
+
+static inline void omap_aes_write(struct omap_aes_dev *dd, u32 offset,
+				  u32 value)
+{
+	__raw_writel(value, dd->io_base + offset);
+}
+
+static inline void omap_aes_write_mask(struct omap_aes_dev *dd, u32 offset,
+					u32 value, u32 mask)
+{
+	u32 val;
+
+	val = omap_aes_read(dd, offset);
+	val &= ~mask;
+	val |= value;
+	omap_aes_write(dd, offset, val);
+}
+
+static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
+					u32 *value, int count)
+{
+	for (; count--; value++, offset += 4)
+		omap_aes_write(dd, offset, *value);
+}
+
+static int omap_aes_wait(struct omap_aes_dev *dd, u32 offset, u32 bit)
+{
+	unsigned long timeout = jiffies + DEFAULT_TIMEOUT;
+
+	while (!(omap_aes_read(dd, offset) & bit)) {
+		if (time_is_before_jiffies(timeout)) {
+			dev_err(dd->dev, "omap-aes timeout\n");
+			return -ETIMEDOUT;
+		}
+	}
+	return 0;
+}
+
+static int omap_aes_hw_init(struct omap_aes_dev *dd)
+{
+	int err = 0;
+
+	clk_enable(dd->iclk);
+	if (!(dd->flags & FLAGS_INIT)) {
+		/* is it necessary to reset before every operation? */
+		omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_SOFTRESET,
+					AES_REG_MASK_SOFTRESET);
+		/*
+		 * prevent OCP bus error (SRESP) in case an access to the module
+		 * is performed while the module is coming out of soft reset
+		 */
+		__asm__ __volatile__("nop");
+		__asm__ __volatile__("nop");
+
+		err = omap_aes_wait(dd, AES_REG_SYSSTATUS,
+				AES_REG_SYSSTATUS_RESETDONE);
+		if (!err)
+			dd->flags |= FLAGS_INIT;
+	}
+
+	return err;
+}
+
+static void omap_aes_hw_cleanup(struct omap_aes_dev *dd)
+{
+	clk_disable(dd->iclk);
+}
+
+static void omap_aes_write_ctrl(struct omap_aes_dev *dd)
+{
+	unsigned int key32;
+	int i;
+	u32 val, mask;
+
+	val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3);
+	if (dd->flags & FLAGS_CBC)
+		val |= AES_REG_CTRL_CBC;
+	if (dd->flags & FLAGS_ENCRYPT)
+		val |= AES_REG_CTRL_DIRECTION;
+
+	if (dd->ctrl == val && !(dd->flags & FLAGS_NEW_IV) &&
+		   !(dd->ctx->flags & FLAGS_NEW_KEY))
+		goto out;
+
+	/* only need to write control registers for new settings */
+
+	dd->ctrl = val;
+
+	val = 0;
+	if (dd->dma_lch_out >= 0)
+		val |= AES_REG_MASK_DMA_OUT_EN;
+	if (dd->dma_lch_in >= 0)
+		val |= AES_REG_MASK_DMA_IN_EN;
+
+	mask = AES_REG_MASK_DMA_IN_EN | AES_REG_MASK_DMA_OUT_EN;
+
+	omap_aes_write_mask(dd, AES_REG_MASK, val, mask);
+
+	pr_debug("Set key\n");
+	key32 = dd->ctx->keylen / sizeof(u32);
+	/* set a key */
+	for (i = 0; i < key32; i++) {
+		omap_aes_write(dd, AES_REG_KEY(i),
+			__le32_to_cpu(dd->ctx->key[i]));
+	}
+	dd->ctx->flags &= ~FLAGS_NEW_KEY;
+
+	if (dd->flags & FLAGS_NEW_IV) {
+		pr_debug("Set IV\n");
+		omap_aes_write_n(dd, AES_REG_IV(0), dd->iv, 4);
+		dd->flags &= ~FLAGS_NEW_IV;
+	}
+
+	mask = AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION |
+			AES_REG_CTRL_KEY_SIZE;
+
+	omap_aes_write_mask(dd, AES_REG_CTRL, dd->ctrl, mask);
+
+out:
+	/* start DMA or disable idle mode */
+	omap_aes_write_mask(dd, AES_REG_MASK, AES_REG_MASK_START,
+			    AES_REG_MASK_START);
+}
+
+static struct omap_aes_dev *omap_aes_find_dev(struct omap_aes_ctx *ctx)
+{
+	struct omap_aes_dev *dd = NULL, *tmp;
+
+	spin_lock_bh(&list_lock);
+	if (!ctx->dd) {
+		list_for_each_entry(tmp, &dev_list, list) {
+			/* FIXME: take fist available aes core */
+			dd = tmp;
+			break;
+		}
+		ctx->dd = dd;
+	} else {
+		/* already found before */
+		dd = ctx->dd;
+	}
+	spin_unlock_bh(&list_lock);
+
+	return dd;
+}
+
+static void omap_aes_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct omap_aes_dev *dd = data;
+
+	if (lch == dd->dma_lch_out)
+		tasklet_schedule(&dd->task);
+}
+
+static int omap_aes_dma_init(struct omap_aes_dev *dd)
+{
+	int err = -ENOMEM;
+
+	dd->dma_lch_out = -1;
+	dd->dma_lch_in = -1;
+
+	dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
+	dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, OMAP_AES_CACHE_SIZE);
+	dd->buflen = PAGE_SIZE << OMAP_AES_CACHE_SIZE;
+	dd->buflen &= ~(AES_BLOCK_SIZE - 1);
+
+	if (!dd->buf_in || !dd->buf_out) {
+		dev_err(dd->dev, "unable to alloc pages.\n");
+		goto err_alloc;
+	}
+
+	/* MAP here */
+	dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen,
+					 DMA_TO_DEVICE);
+	if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
+		dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+		err = -EINVAL;
+		goto err_map_in;
+	}
+
+	dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen,
+					  DMA_FROM_DEVICE);
+	if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
+		dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
+		err = -EINVAL;
+		goto err_map_out;
+	}
+
+	err = omap_request_dma(dd->dma_in, "omap-aes-rx",
+			       omap_aes_dma_callback, dd, &dd->dma_lch_in);
+	if (err) {
+		dev_err(dd->dev, "Unable to request DMA channel\n");
+		goto err_dma_in;
+	}
+	err = omap_request_dma(dd->dma_out, "omap-aes-tx",
+			       omap_aes_dma_callback, dd, &dd->dma_lch_out);
+	if (err) {
+		dev_err(dd->dev, "Unable to request DMA channel\n");
+		goto err_dma_out;
+	}
+
+	omap_set_dma_dest_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_CONSTANT,
+				 dd->phys_base + AES_REG_DATA, 0, 4);
+
+	omap_set_dma_dest_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+	omap_set_dma_src_burst_mode(dd->dma_lch_in, OMAP_DMA_DATA_BURST_4);
+
+	omap_set_dma_src_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_CONSTANT,
+				dd->phys_base + AES_REG_DATA, 0, 4);
+
+	omap_set_dma_src_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+	omap_set_dma_dest_burst_mode(dd->dma_lch_out, OMAP_DMA_DATA_BURST_4);
+
+	return 0;
+
+err_dma_out:
+	omap_free_dma(dd->dma_lch_in);
+err_dma_in:
+	dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+			 DMA_FROM_DEVICE);
+err_map_out:
+	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+err_map_in:
+	free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
+	free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
+err_alloc:
+	if (err)
+		pr_err("error: %d\n", err);
+	return err;
+}
+
+static void omap_aes_dma_cleanup(struct omap_aes_dev *dd)
+{
+	omap_free_dma(dd->dma_lch_out);
+	omap_free_dma(dd->dma_lch_in);
+	dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+			 DMA_FROM_DEVICE);
+	dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, DMA_TO_DEVICE);
+	free_pages((unsigned long)dd->buf_out, OMAP_AES_CACHE_SIZE);
+	free_pages((unsigned long)dd->buf_in, OMAP_AES_CACHE_SIZE);
+}
+
+static void sg_copy_buf(void *buf, struct scatterlist *sg,
+			      unsigned int start, unsigned int nbytes, int out)
+{
+	struct scatter_walk walk;
+
+	if (!nbytes)
+		return;
+
+	scatterwalk_start(&walk, sg);
+	scatterwalk_advance(&walk, start);
+	scatterwalk_copychunks(buf, &walk, nbytes, out);
+	scatterwalk_done(&walk, out, 0);
+}
+
+static int sg_copy(struct scatterlist **sg, size_t *offset, void *buf,
+		   size_t buflen, size_t total, int out)
+{
+	unsigned int count, off = 0;
+
+	while (buflen && total) {
+		count = min((*sg)->length - *offset, total);
+		count = min(count, buflen);
+
+		if (!count)
+			return off;
+
+		sg_copy_buf(buf + off, *sg, *offset, count, out);
+
+		off += count;
+		buflen -= count;
+		*offset += count;
+		total -= count;
+
+		if (*offset == (*sg)->length) {
+			*sg = sg_next(*sg);
+			if (*sg)
+				*offset = 0;
+			else
+				total = 0;
+		}
+	}
+
+	return off;
+}
+
+static int omap_aes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+			       dma_addr_t dma_addr_out, int length)
+{
+	struct omap_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct omap_aes_dev *dd = ctx->dd;
+	int len32;
+
+	pr_debug("len: %d\n", length);
+
+	dd->dma_size = length;
+
+	if (!(dd->flags & FLAGS_FAST))
+		dma_sync_single_for_device(dd->dev, dma_addr_in, length,
+					   DMA_TO_DEVICE);
+
+	len32 = DIV_ROUND_UP(length, sizeof(u32));
+
+	/* IN */
+	omap_set_dma_transfer_params(dd->dma_lch_in, OMAP_DMA_DATA_TYPE_S32,
+				     len32, 1, OMAP_DMA_SYNC_PACKET, dd->dma_in,
+					OMAP_DMA_DST_SYNC);
+
+	omap_set_dma_src_params(dd->dma_lch_in, 0, OMAP_DMA_AMODE_POST_INC,
+				dma_addr_in, 0, 0);
+
+	/* OUT */
+	omap_set_dma_transfer_params(dd->dma_lch_out, OMAP_DMA_DATA_TYPE_S32,
+				     len32, 1, OMAP_DMA_SYNC_PACKET,
+					dd->dma_out, OMAP_DMA_SRC_SYNC);
+
+	omap_set_dma_dest_params(dd->dma_lch_out, 0, OMAP_DMA_AMODE_POST_INC,
+				 dma_addr_out, 0, 0);
+
+	omap_start_dma(dd->dma_lch_in);
+	omap_start_dma(dd->dma_lch_out);
+
+	omap_aes_write_ctrl(dd);
+
+	return 0;
+}
+
+static int omap_aes_crypt_dma_start(struct omap_aes_dev *dd)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+					crypto_ablkcipher_reqtfm(dd->req));
+	int err, fast = 0, in, out;
+	size_t count;
+	dma_addr_t addr_in, addr_out;
+
+	pr_debug("total: %d\n", dd->total);
+
+	if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
+		/* check for alignment */
+		in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
+		out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
+
+		fast = in && out;
+	}
+
+	if (fast)  {
+		count = min(dd->total, sg_dma_len(dd->in_sg));
+		count = min(count, sg_dma_len(dd->out_sg));
+
+		if (count != dd->total)
+			return -EINVAL;
+
+		pr_debug("fast\n");
+
+		err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+		if (!err) {
+			dev_err(dd->dev, "dma_map_sg() error\n");
+			return -EINVAL;
+		}
+
+		err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+		if (!err) {
+			dev_err(dd->dev, "dma_map_sg() error\n");
+			dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+			return -EINVAL;
+		}
+
+		addr_in = sg_dma_address(dd->in_sg);
+		addr_out = sg_dma_address(dd->out_sg);
+
+		dd->flags |= FLAGS_FAST;
+
+	} else {
+		/* use cache buffers */
+		count = sg_copy(&dd->in_sg, &dd->in_offset, dd->buf_in,
+				 dd->buflen, dd->total, 0);
+
+		addr_in = dd->dma_addr_in;
+		addr_out = dd->dma_addr_out;
+
+		dd->flags &= ~FLAGS_FAST;
+
+	}
+
+	dd->total -= count;
+
+	err = omap_aes_hw_init(dd);
+
+	err = omap_aes_crypt_dma(tfm, addr_in, addr_out, count);
+
+	return err;
+}
+
+static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
+{
+	struct omap_aes_ctx *ctx;
+
+	pr_debug("err: %d\n", err);
+
+	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(dd->req));
+
+	if (!dd->total)
+		dd->req->base.complete(&dd->req->base, err);
+}
+
+static int omap_aes_crypt_dma_stop(struct omap_aes_dev *dd)
+{
+	int err = 0;
+	size_t count;
+
+	pr_debug("total: %d\n", dd->total);
+
+	omap_aes_write_mask(dd, AES_REG_MASK, 0, AES_REG_MASK_START);
+
+	omap_aes_hw_cleanup(dd);
+
+	omap_stop_dma(dd->dma_lch_in);
+	omap_stop_dma(dd->dma_lch_out);
+
+	if (dd->flags & FLAGS_FAST) {
+		dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
+		dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+	} else {
+		dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
+					   dd->dma_size, DMA_FROM_DEVICE);
+
+		/* copy data */
+		count = sg_copy(&dd->out_sg, &dd->out_offset, dd->buf_out,
+				 dd->buflen, dd->dma_size, 1);
+		if (count != dd->dma_size) {
+			err = -EINVAL;
+			pr_err("not all data converted: %u\n", count);
+		}
+	}
+
+	if (err || !dd->total)
+		omap_aes_finish_req(dd, err);
+
+	return err;
+}
+
+static int omap_aes_handle_req(struct omap_aes_dev *dd)
+{
+	struct crypto_async_request *async_req, *backlog;
+	struct omap_aes_ctx *ctx;
+	struct omap_aes_reqctx *rctx;
+	struct ablkcipher_request *req;
+	unsigned long flags;
+
+	if (dd->total)
+		goto start;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	backlog = crypto_get_backlog(&dd->queue);
+	async_req = crypto_dequeue_request(&dd->queue);
+	if (!async_req)
+		clear_bit(FLAGS_BUSY, &dd->flags);
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	if (!async_req)
+		return 0;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	req = ablkcipher_request_cast(async_req);
+
+	pr_debug("get new req\n");
+
+	/* assign new request to device */
+	dd->req = req;
+	dd->total = req->nbytes;
+	dd->in_offset = 0;
+	dd->in_sg = req->src;
+	dd->out_offset = 0;
+	dd->out_sg = req->dst;
+
+	rctx = ablkcipher_request_ctx(req);
+	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	rctx->mode &= FLAGS_MODE_MASK;
+	dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+	dd->iv = req->info;
+	if ((dd->flags & FLAGS_CBC) && dd->iv)
+		dd->flags |= FLAGS_NEW_IV;
+	else
+		dd->flags &= ~FLAGS_NEW_IV;
+
+	ctx->dd = dd;
+	if (dd->ctx != ctx) {
+		/* assign new context to device */
+		dd->ctx = ctx;
+		ctx->flags |= FLAGS_NEW_KEY;
+	}
+
+	if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE))
+		pr_err("request size is not exact amount of AES blocks\n");
+
+start:
+	return omap_aes_crypt_dma_start(dd);
+}
+
+static void omap_aes_task(unsigned long data)
+{
+	struct omap_aes_dev *dd = (struct omap_aes_dev *)data;
+	int err;
+
+	pr_debug("enter\n");
+
+	err = omap_aes_crypt_dma_stop(dd);
+
+	err = omap_aes_handle_req(dd);
+
+	pr_debug("exit\n");
+}
+
+static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+	struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(
+			crypto_ablkcipher_reqtfm(req));
+	struct omap_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct omap_aes_dev *dd;
+	unsigned long flags;
+	int err;
+
+	pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
+		  !!(mode & FLAGS_ENCRYPT),
+		  !!(mode & FLAGS_CBC));
+
+	dd = omap_aes_find_dev(ctx);
+	if (!dd)
+		return -ENODEV;
+
+	rctx->mode = mode;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	err = ablkcipher_enqueue_request(&dd->queue, req);
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	if (!test_and_set_bit(FLAGS_BUSY, &dd->flags))
+		omap_aes_handle_req(dd);
+
+	pr_debug("exit\n");
+
+	return err;
+}
+
+/* ********************** ALG API ************************************ */
+
+static int omap_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+			   unsigned int keylen)
+{
+	struct omap_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
+		   keylen != AES_KEYSIZE_256)
+		return -EINVAL;
+
+	pr_debug("enter, keylen: %d\n", keylen);
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+	ctx->flags |= FLAGS_NEW_KEY;
+
+	return 0;
+}
+
+static int omap_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+	return omap_aes_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int omap_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+	return omap_aes_crypt(req, 0);
+}
+
+static int omap_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+	return omap_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int omap_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+	return omap_aes_crypt(req, FLAGS_CBC);
+}
+
+static int omap_aes_cra_init(struct crypto_tfm *tfm)
+{
+	pr_debug("enter\n");
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
+
+	return 0;
+}
+
+static void omap_aes_cra_exit(struct crypto_tfm *tfm)
+{
+	pr_debug("enter\n");
+}
+
+/* ********************** ALGS ************************************ */
+
+static struct crypto_alg algs[] = {
+{
+	.cra_name		= "ecb(aes)",
+	.cra_driver_name	= "ecb-aes-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_aes_ctx),
+	.cra_alignmask	 	= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_aes_cra_init,
+	.cra_exit		= omap_aes_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.setkey		= omap_aes_setkey,
+		.encrypt	= omap_aes_ecb_encrypt,
+		.decrypt	= omap_aes_ecb_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(aes)",
+	.cra_driver_name	= "cbc-aes-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= AES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_aes_ctx),
+	.cra_alignmask	 	= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_aes_cra_init,
+	.cra_exit		= omap_aes_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= AES_MIN_KEY_SIZE,
+		.max_keysize	= AES_MAX_KEY_SIZE,
+		.ivsize		= AES_BLOCK_SIZE,
+		.setkey		= omap_aes_setkey,
+		.encrypt	= omap_aes_cbc_encrypt,
+		.decrypt	= omap_aes_cbc_decrypt,
+	}
+}
+};
+
+static int omap_aes_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct omap_aes_dev *dd;
+	struct resource *res;
+	int err = -ENOMEM, i, j;
+	u32 reg;
+
+	dd = kzalloc(sizeof(struct omap_aes_dev), GFP_KERNEL);
+	if (dd == NULL) {
+		dev_err(dev, "unable to alloc data struct.\n");
+		goto err_data;
+	}
+	dd->dev = dev;
+	platform_set_drvdata(pdev, dd);
+
+	spin_lock_init(&dd->lock);
+	crypto_init_queue(&dd->queue, OMAP_AES_QUEUE_LENGTH);
+
+	/* Get the base address */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "invalid resource type\n");
+		err = -ENODEV;
+		goto err_res;
+	}
+	dd->phys_base = res->start;
+
+	/* Get the DMA */
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res)
+		dev_info(dev, "no DMA info\n");
+	else
+		dd->dma_out = res->start;
+
+	/* Get the DMA */
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res)
+		dev_info(dev, "no DMA info\n");
+	else
+		dd->dma_in = res->start;
+
+	/* Initializing the clock */
+	dd->iclk = clk_get(dev, "ick");
+	if (!dd->iclk) {
+		dev_err(dev, "clock intialization failed.\n");
+		err = -ENODEV;
+		goto err_res;
+	}
+
+	dd->io_base = ioremap(dd->phys_base, SZ_4K);
+	if (!dd->io_base) {
+		dev_err(dev, "can't ioremap\n");
+		err = -ENOMEM;
+		goto err_io;
+	}
+
+	clk_enable(dd->iclk);
+	reg = omap_aes_read(dd, AES_REG_REV);
+	dev_info(dev, "OMAP AES hw accel rev: %u.%u\n",
+		 (reg & AES_REG_REV_MAJOR) >> 4, reg & AES_REG_REV_MINOR);
+	clk_disable(dd->iclk);
+
+	tasklet_init(&dd->task, omap_aes_task, (unsigned long)dd);
+
+	err = omap_aes_dma_init(dd);
+	if (err)
+		goto err_dma;
+
+	INIT_LIST_HEAD(&dd->list);
+	spin_lock(&list_lock);
+	list_add_tail(&dd->list, &dev_list);
+	spin_unlock(&list_lock);
+
+	for (i = 0; i < ARRAY_SIZE(algs); i++) {
+		pr_debug("i: %d\n", i);
+		INIT_LIST_HEAD(&algs[i].cra_list);
+		err = crypto_register_alg(&algs[i]);
+		if (err)
+			goto err_algs;
+	}
+
+	pr_info("probe() done\n");
+
+	return 0;
+err_algs:
+	for (j = 0; j < i; j++)
+		crypto_unregister_alg(&algs[j]);
+	omap_aes_dma_cleanup(dd);
+err_dma:
+	tasklet_kill(&dd->task);
+	iounmap(dd->io_base);
+err_io:
+	clk_put(dd->iclk);
+err_res:
+	kfree(dd);
+	dd = NULL;
+err_data:
+	dev_err(dev, "initialization failed.\n");
+	return err;
+}
+
+static int omap_aes_remove(struct platform_device *pdev)
+{
+	struct omap_aes_dev *dd = platform_get_drvdata(pdev);
+	int i;
+
+	if (!dd)
+		return -ENODEV;
+
+	spin_lock(&list_lock);
+	list_del(&dd->list);
+	spin_unlock(&list_lock);
+
+	for (i = 0; i < ARRAY_SIZE(algs); i++)
+		crypto_unregister_alg(&algs[i]);
+
+	tasklet_kill(&dd->task);
+	omap_aes_dma_cleanup(dd);
+	iounmap(dd->io_base);
+	clk_put(dd->iclk);
+	kfree(dd);
+	dd = NULL;
+
+	return 0;
+}
+
+static struct platform_driver omap_aes_driver = {
+	.probe	= omap_aes_probe,
+	.remove	= omap_aes_remove,
+	.driver	= {
+		.name	= "omap-aes",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init omap_aes_mod_init(void)
+{
+	pr_info("loading %s driver\n", "omap-aes");
+
+	if (!cpu_class_is_omap2() || omap_type() != OMAP2_DEVICE_TYPE_SEC) {
+		pr_err("Unsupported cpu\n");
+		return -ENODEV;
+	}
+
+	return  platform_driver_register(&omap_aes_driver);
+}
+
+static void __exit omap_aes_mod_exit(void)
+{
+	platform_driver_unregister(&omap_aes_driver);
+}
+
+module_init(omap_aes_mod_init);
+module_exit(omap_aes_mod_exit);
+
+MODULE_DESCRIPTION("OMAP AES hw acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Dmitry Kasatkin");
+
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/omap-sham.c linux-libre-2.6.37-gnu/drivers/crypto/omap-sham.c
--- linux-libre-2.6.36-gnu/drivers/crypto/omap-sham.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/omap-sham.c	2011-01-04 19:50:19.000000000 -0500
@@ -311,7 +311,8 @@
 	len32 = DIV_ROUND_UP(length, sizeof(u32));
 
 	omap_set_dma_transfer_params(dd->dma_lch, OMAP_DMA_DATA_TYPE_S32, len32,
-			1, OMAP_DMA_SYNC_PACKET, dd->dma, OMAP_DMA_DST_SYNC);
+			1, OMAP_DMA_SYNC_PACKET, dd->dma,
+				OMAP_DMA_DST_SYNC_PREFETCH);
 
 	omap_set_dma_src_params(dd->dma_lch, 0, OMAP_DMA_AMODE_POST_INC,
 				dma_addr, 0, 0);
@@ -1072,6 +1073,9 @@
 	omap_set_dma_dest_burst_mode(dd->dma_lch,
 			OMAP_DMA_DATA_BURST_16);
 
+	omap_set_dma_src_burst_mode(dd->dma_lch,
+			OMAP_DMA_DATA_BURST_4);
+
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/padlock-aes.c linux-libre-2.6.37-gnu/drivers/crypto/padlock-aes.c
--- linux-libre-2.6.36-gnu/drivers/crypto/padlock-aes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/padlock-aes.c	2011-01-04 19:50:19.000000000 -0500
@@ -286,7 +286,7 @@
 	if (initial)
 		asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
 			      : "+S" (input), "+D" (output), "+a" (iv)
-			      : "d" (control_word), "b" (key), "c" (count));
+			      : "d" (control_word), "b" (key), "c" (initial));
 
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"	/* rep xcryptcbc */
 		      : "+S" (input), "+D" (output), "+a" (iv)
diff -druN linux-libre-2.6.36-gnu/drivers/crypto/talitos.c linux-libre-2.6.37-gnu/drivers/crypto/talitos.c
--- linux-libre-2.6.36-gnu/drivers/crypto/talitos.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/crypto/talitos.c	2011-01-04 19:50:19.000000000 -0500
@@ -161,7 +161,7 @@
 static void to_talitos_ptr(struct talitos_ptr *talitos_ptr, dma_addr_t dma_addr)
 {
 	talitos_ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
-	talitos_ptr->eptr = cpu_to_be32(upper_32_bits(dma_addr));
+	talitos_ptr->eptr = upper_32_bits(dma_addr);
 }
 
 /*
@@ -332,10 +332,9 @@
 
 	/* GO! */
 	wmb();
-	out_be32(priv->reg + TALITOS_FF(ch),
-		 cpu_to_be32(upper_32_bits(request->dma_desc)));
+	out_be32(priv->reg + TALITOS_FF(ch), upper_32_bits(request->dma_desc));
 	out_be32(priv->reg + TALITOS_FF_LO(ch),
-		 cpu_to_be32(lower_32_bits(request->dma_desc)));
+		 lower_32_bits(request->dma_desc));
 
 	spin_unlock_irqrestore(&priv->chan[ch].head_lock, flags);
 
@@ -1751,14 +1750,14 @@
 	ahash_init(areq);
 	req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
 
-	req_ctx->hw_context[0] = cpu_to_be32(SHA224_H0);
-	req_ctx->hw_context[1] = cpu_to_be32(SHA224_H1);
-	req_ctx->hw_context[2] = cpu_to_be32(SHA224_H2);
-	req_ctx->hw_context[3] = cpu_to_be32(SHA224_H3);
-	req_ctx->hw_context[4] = cpu_to_be32(SHA224_H4);
-	req_ctx->hw_context[5] = cpu_to_be32(SHA224_H5);
-	req_ctx->hw_context[6] = cpu_to_be32(SHA224_H6);
-	req_ctx->hw_context[7] = cpu_to_be32(SHA224_H7);
+	req_ctx->hw_context[0] = SHA224_H0;
+	req_ctx->hw_context[1] = SHA224_H1;
+	req_ctx->hw_context[2] = SHA224_H2;
+	req_ctx->hw_context[3] = SHA224_H3;
+	req_ctx->hw_context[4] = SHA224_H4;
+	req_ctx->hw_context[5] = SHA224_H5;
+	req_ctx->hw_context[6] = SHA224_H6;
+	req_ctx->hw_context[7] = SHA224_H7;
 
 	/* init 64-bit count */
 	req_ctx->hw_context[8] = 0;
@@ -2333,8 +2332,7 @@
 		talitos_unregister_rng(dev);
 
 	for (i = 0; i < priv->num_channels; i++)
-		if (priv->chan[i].fifo)
-			kfree(priv->chan[i].fifo);
+		kfree(priv->chan[i].fifo);
 
 	kfree(priv->chan);
 
@@ -2389,6 +2387,9 @@
 					DESC_HDR_MODE0_MDEU_SHA256;
 		}
 		break;
+	default:
+		dev_err(dev, "unknown algorithm type %d\n", t_alg->algt.type);
+		return ERR_PTR(-EINVAL);
 	}
 
 	alg->cra_module = THIS_MODULE;
diff -druN linux-libre-2.6.36-gnu/drivers/dma/amba-pl08x.c linux-libre-2.6.37-gnu/drivers/dma/amba-pl08x.c
--- linux-libre-2.6.36-gnu/drivers/dma/amba-pl08x.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/dma/amba-pl08x.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2167 @@
+/*
+ * Copyright (c) 2006 ARM Ltd.
+ * Copyright (c) 2010 ST-Ericsson SA
+ *
+ * Author: Peter Pearse <peter.pearse@arm.com>
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is iin this distribution in the
+ * file called COPYING.
+ *
+ * Documentation: ARM DDI 0196G == PL080
+ * Documentation: ARM DDI 0218E	== PL081
+ *
+ * PL080 & PL081 both have 16 sets of DMA signals that can be routed to
+ * any channel.
+ *
+ * The PL080 has 8 channels available for simultaneous use, and the PL081
+ * has only two channels. So on these DMA controllers the number of channels
+ * and the number of incoming DMA signals are two totally different things.
+ * It is usually not possible to theoretically handle all physical signals,
+ * so a multiplexing scheme with possible denial of use is necessary.
+ *
+ * The PL080 has a dual bus master, PL081 has a single master.
+ *
+ * Memory to peripheral transfer may be visualized as
+ *	Get data from memory to DMAC
+ *	Until no data left
+ *		On burst request from peripheral
+ *			Destination burst from DMAC to peripheral
+ *			Clear burst request
+ *	Raise terminal count interrupt
+ *
+ * For peripherals with a FIFO:
+ * Source      burst size == half the depth of the peripheral FIFO
+ * Destination burst size == the depth of the peripheral FIFO
+ *
+ * (Bursts are irrelevant for mem to mem transfers - there are no burst
+ * signals, the DMA controller will simply facilitate its AHB master.)
+ *
+ * ASSUMES default (little) endianness for DMA transfers
+ *
+ * Only DMAC flow control is implemented
+ *
+ * Global TODO:
+ * - Break out common code from arch/arm/mach-s3c64xx and share
+ */
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/amba/bus.h>
+#include <linux/dmaengine.h>
+#include <linux/amba/pl08x.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/hardware/pl080.h>
+#include <asm/dma.h>
+#include <asm/mach/dma.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+
+#define DRIVER_NAME	"pl08xdmac"
+
+/**
+ * struct vendor_data - vendor-specific config parameters
+ * for PL08x derivates
+ * @name: the name of this specific variant
+ * @channels: the number of channels available in this variant
+ * @dualmaster: whether this version supports dual AHB masters
+ * or not.
+ */
+struct vendor_data {
+	char *name;
+	u8 channels;
+	bool dualmaster;
+};
+
+/*
+ * PL08X private data structures
+ * An LLI struct - see pl08x TRM
+ * Note that next uses bit[0] as a bus bit,
+ * start & end do not - their bus bit info
+ * is in cctl
+ */
+struct lli {
+	dma_addr_t src;
+	dma_addr_t dst;
+	dma_addr_t next;
+	u32 cctl;
+};
+
+/**
+ * struct pl08x_driver_data - the local state holder for the PL08x
+ * @slave: slave engine for this instance
+ * @memcpy: memcpy engine for this instance
+ * @base: virtual memory base (remapped) for the PL08x
+ * @adev: the corresponding AMBA (PrimeCell) bus entry
+ * @vd: vendor data for this PL08x variant
+ * @pd: platform data passed in from the platform/machine
+ * @phy_chans: array of data for the physical channels
+ * @pool: a pool for the LLI descriptors
+ * @pool_ctr: counter of LLIs in the pool
+ * @lock: a spinlock for this struct
+ */
+struct pl08x_driver_data {
+	struct dma_device slave;
+	struct dma_device memcpy;
+	void __iomem *base;
+	struct amba_device *adev;
+	struct vendor_data *vd;
+	struct pl08x_platform_data *pd;
+	struct pl08x_phy_chan *phy_chans;
+	struct dma_pool *pool;
+	int pool_ctr;
+	spinlock_t lock;
+};
+
+/*
+ * PL08X specific defines
+ */
+
+/*
+ * Memory boundaries: the manual for PL08x says that the controller
+ * cannot read past a 1KiB boundary, so these defines are used to
+ * create transfer LLIs that do not cross such boundaries.
+ */
+#define PL08X_BOUNDARY_SHIFT		(10)	/* 1KB 0x400 */
+#define PL08X_BOUNDARY_SIZE		(1 << PL08X_BOUNDARY_SHIFT)
+
+/* Minimum period between work queue runs */
+#define PL08X_WQ_PERIODMIN	20
+
+/* Size (bytes) of each LLI buffer allocated for one transfer */
+# define PL08X_LLI_TSFR_SIZE	0x2000
+
+/* Maximimum times we call dma_pool_alloc on this pool without freeing */
+#define PL08X_MAX_ALLOCS	0x40
+#define MAX_NUM_TSFR_LLIS	(PL08X_LLI_TSFR_SIZE/sizeof(struct lli))
+#define PL08X_ALIGN		8
+
+static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct pl08x_dma_chan, chan);
+}
+
+/*
+ * Physical channel handling
+ */
+
+/* Whether a certain channel is busy or not */
+static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
+{
+	unsigned int val;
+
+	val = readl(ch->base + PL080_CH_CONFIG);
+	return val & PL080_CONFIG_ACTIVE;
+}
+
+/*
+ * Set the initial DMA register values i.e. those for the first LLI
+ * The next lli pointer and the configuration interrupt bit have
+ * been set when the LLIs were constructed
+ */
+static void pl08x_set_cregs(struct pl08x_driver_data *pl08x,
+			    struct pl08x_phy_chan *ch)
+{
+	/* Wait for channel inactive */
+	while (pl08x_phy_channel_busy(ch))
+		;
+
+	dev_vdbg(&pl08x->adev->dev,
+		"WRITE channel %d: csrc=%08x, cdst=%08x, "
+		 "cctl=%08x, clli=%08x, ccfg=%08x\n",
+		ch->id,
+		ch->csrc,
+		ch->cdst,
+		ch->cctl,
+		ch->clli,
+		ch->ccfg);
+
+	writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR);
+	writel(ch->cdst, ch->base + PL080_CH_DST_ADDR);
+	writel(ch->clli, ch->base + PL080_CH_LLI);
+	writel(ch->cctl, ch->base + PL080_CH_CONTROL);
+	writel(ch->ccfg, ch->base + PL080_CH_CONFIG);
+}
+
+static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_channel_data *cd = plchan->cd;
+	struct pl08x_phy_chan *phychan = plchan->phychan;
+	struct pl08x_txd *txd = plchan->at;
+
+	/* Copy the basic control register calculated at transfer config */
+	phychan->csrc = txd->csrc;
+	phychan->cdst = txd->cdst;
+	phychan->clli = txd->clli;
+	phychan->cctl = txd->cctl;
+
+	/* Assign the signal to the proper control registers */
+	phychan->ccfg = cd->ccfg;
+	phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK;
+	phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK;
+	/* If it wasn't set from AMBA, ignore it */
+	if (txd->direction == DMA_TO_DEVICE)
+		/* Select signal as destination */
+		phychan->ccfg |=
+			(phychan->signal << PL080_CONFIG_DST_SEL_SHIFT);
+	else if (txd->direction == DMA_FROM_DEVICE)
+		/* Select signal as source */
+		phychan->ccfg |=
+			(phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT);
+	/* Always enable error interrupts */
+	phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK;
+	/* Always enable terminal interrupts */
+	phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK;
+}
+
+/*
+ * Enable the DMA channel
+ * Assumes all other configuration bits have been set
+ * as desired before this code is called
+ */
+static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x,
+				  struct pl08x_phy_chan *ch)
+{
+	u32 val;
+
+	/*
+	 * Do not access config register until channel shows as disabled
+	 */
+	while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id))
+		;
+
+	/*
+	 * Do not access config register until channel shows as inactive
+	 */
+	val = readl(ch->base + PL080_CH_CONFIG);
+	while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
+		val = readl(ch->base + PL080_CH_CONFIG);
+
+	writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG);
+}
+
+/*
+ * Overall DMAC remains enabled always.
+ *
+ * Disabling individual channels could lose data.
+ *
+ * Disable the peripheral DMA after disabling the DMAC
+ * in order to allow the DMAC FIFO to drain, and
+ * hence allow the channel to show inactive
+ *
+ */
+static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
+{
+	u32 val;
+
+	/* Set the HALT bit and wait for the FIFO to drain */
+	val = readl(ch->base + PL080_CH_CONFIG);
+	val |= PL080_CONFIG_HALT;
+	writel(val, ch->base + PL080_CH_CONFIG);
+
+	/* Wait for channel inactive */
+	while (pl08x_phy_channel_busy(ch))
+		;
+}
+
+static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
+{
+	u32 val;
+
+	/* Clear the HALT bit */
+	val = readl(ch->base + PL080_CH_CONFIG);
+	val &= ~PL080_CONFIG_HALT;
+	writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+
+/* Stops the channel */
+static void pl08x_stop_phy_chan(struct pl08x_phy_chan *ch)
+{
+	u32 val;
+
+	pl08x_pause_phy_chan(ch);
+
+	/* Disable channel */
+	val = readl(ch->base + PL080_CH_CONFIG);
+	val &= ~PL080_CONFIG_ENABLE;
+	val &= ~PL080_CONFIG_ERR_IRQ_MASK;
+	val &= ~PL080_CONFIG_TC_IRQ_MASK;
+	writel(val, ch->base + PL080_CH_CONFIG);
+}
+
+static inline u32 get_bytes_in_cctl(u32 cctl)
+{
+	/* The source width defines the number of bytes */
+	u32 bytes = cctl & PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+	switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
+	case PL080_WIDTH_8BIT:
+		break;
+	case PL080_WIDTH_16BIT:
+		bytes *= 2;
+		break;
+	case PL080_WIDTH_32BIT:
+		bytes *= 4;
+		break;
+	}
+	return bytes;
+}
+
+/* The channel should be paused when calling this */
+static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_phy_chan *ch;
+	struct pl08x_txd *txdi = NULL;
+	struct pl08x_txd *txd;
+	unsigned long flags;
+	u32 bytes = 0;
+
+	spin_lock_irqsave(&plchan->lock, flags);
+
+	ch = plchan->phychan;
+	txd = plchan->at;
+
+	/*
+	 * Next follow the LLIs to get the number of pending bytes in the
+	 * currently active transaction.
+	 */
+	if (ch && txd) {
+		struct lli *llis_va = txd->llis_va;
+		struct lli *llis_bus = (struct lli *) txd->llis_bus;
+		u32 clli = readl(ch->base + PL080_CH_LLI);
+
+		/* First get the bytes in the current active LLI */
+		bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
+
+		if (clli) {
+			int i = 0;
+
+			/* Forward to the LLI pointed to by clli */
+			while ((clli != (u32) &(llis_bus[i])) &&
+			       (i < MAX_NUM_TSFR_LLIS))
+				i++;
+
+			while (clli) {
+				bytes += get_bytes_in_cctl(llis_va[i].cctl);
+				/*
+				 * A clli of 0x00000000 will terminate the
+				 * LLI list
+				 */
+				clli = llis_va[i].next;
+				i++;
+			}
+		}
+	}
+
+	/* Sum up all queued transactions */
+	if (!list_empty(&plchan->desc_list)) {
+		list_for_each_entry(txdi, &plchan->desc_list, node) {
+			bytes += txdi->len;
+		}
+
+	}
+
+	spin_unlock_irqrestore(&plchan->lock, flags);
+
+	return bytes;
+}
+
+/*
+ * Allocate a physical channel for a virtual channel
+ */
+static struct pl08x_phy_chan *
+pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
+		      struct pl08x_dma_chan *virt_chan)
+{
+	struct pl08x_phy_chan *ch = NULL;
+	unsigned long flags;
+	int i;
+
+	/*
+	 * Try to locate a physical channel to be used for
+	 * this transfer. If all are taken return NULL and
+	 * the requester will have to cope by using some fallback
+	 * PIO mode or retrying later.
+	 */
+	for (i = 0; i < pl08x->vd->channels; i++) {
+		ch = &pl08x->phy_chans[i];
+
+		spin_lock_irqsave(&ch->lock, flags);
+
+		if (!ch->serving) {
+			ch->serving = virt_chan;
+			ch->signal = -1;
+			spin_unlock_irqrestore(&ch->lock, flags);
+			break;
+		}
+
+		spin_unlock_irqrestore(&ch->lock, flags);
+	}
+
+	if (i == pl08x->vd->channels) {
+		/* No physical channel available, cope with it */
+		return NULL;
+	}
+
+	return ch;
+}
+
+static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
+					 struct pl08x_phy_chan *ch)
+{
+	unsigned long flags;
+
+	/* Stop the channel and clear its interrupts */
+	pl08x_stop_phy_chan(ch);
+	writel((1 << ch->id), pl08x->base + PL080_ERR_CLEAR);
+	writel((1 << ch->id), pl08x->base + PL080_TC_CLEAR);
+
+	/* Mark it as free */
+	spin_lock_irqsave(&ch->lock, flags);
+	ch->serving = NULL;
+	spin_unlock_irqrestore(&ch->lock, flags);
+}
+
+/*
+ * LLI handling
+ */
+
+static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded)
+{
+	switch (coded) {
+	case PL080_WIDTH_8BIT:
+		return 1;
+	case PL080_WIDTH_16BIT:
+		return 2;
+	case PL080_WIDTH_32BIT:
+		return 4;
+	default:
+		break;
+	}
+	BUG();
+	return 0;
+}
+
+static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
+				  u32 tsize)
+{
+	u32 retbits = cctl;
+
+	/* Remove all src, dst and transfersize bits */
+	retbits &= ~PL080_CONTROL_DWIDTH_MASK;
+	retbits &= ~PL080_CONTROL_SWIDTH_MASK;
+	retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK;
+
+	/* Then set the bits according to the parameters */
+	switch (srcwidth) {
+	case 1:
+		retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT;
+		break;
+	case 2:
+		retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT;
+		break;
+	case 4:
+		retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	switch (dstwidth) {
+	case 1:
+		retbits |= PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT;
+		break;
+	case 2:
+		retbits |= PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT;
+		break;
+	case 4:
+		retbits |= PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	retbits |= tsize << PL080_CONTROL_TRANSFER_SIZE_SHIFT;
+	return retbits;
+}
+
+/*
+ * Autoselect a master bus to use for the transfer
+ * this prefers the destination bus if both available
+ * if fixed address on one bus the other will be chosen
+ */
+void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus,
+	struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus,
+	struct pl08x_bus_data **sbus, u32 cctl)
+{
+	if (!(cctl & PL080_CONTROL_DST_INCR)) {
+		*mbus = src_bus;
+		*sbus = dst_bus;
+	} else if (!(cctl & PL080_CONTROL_SRC_INCR)) {
+		*mbus = dst_bus;
+		*sbus = src_bus;
+	} else {
+		if (dst_bus->buswidth == 4) {
+			*mbus = dst_bus;
+			*sbus = src_bus;
+		} else if (src_bus->buswidth == 4) {
+			*mbus = src_bus;
+			*sbus = dst_bus;
+		} else if (dst_bus->buswidth == 2) {
+			*mbus = dst_bus;
+			*sbus = src_bus;
+		} else if (src_bus->buswidth == 2) {
+			*mbus = src_bus;
+			*sbus = dst_bus;
+		} else {
+			/* src_bus->buswidth == 1 */
+			*mbus = dst_bus;
+			*sbus = src_bus;
+		}
+	}
+}
+
+/*
+ * Fills in one LLI for a certain transfer descriptor
+ * and advance the counter
+ */
+int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
+			    struct pl08x_txd *txd, int num_llis, int len,
+			    u32 cctl, u32 *remainder)
+{
+	struct lli *llis_va = txd->llis_va;
+	struct lli *llis_bus = (struct lli *) txd->llis_bus;
+
+	BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
+
+	llis_va[num_llis].cctl		= cctl;
+	llis_va[num_llis].src		= txd->srcbus.addr;
+	llis_va[num_llis].dst		= txd->dstbus.addr;
+
+	/*
+	 * On versions with dual masters, you can optionally AND on
+	 * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read
+	 * in new LLIs with that controller, but we always try to
+	 * choose AHB1 to point into memory. The idea is to have AHB2
+	 * fixed on the peripheral and AHB1 messing around in the
+	 * memory. So we don't manipulate this bit currently.
+	 */
+
+	llis_va[num_llis].next =
+		(dma_addr_t)((u32) &(llis_bus[num_llis + 1]));
+
+	if (cctl & PL080_CONTROL_SRC_INCR)
+		txd->srcbus.addr += len;
+	if (cctl & PL080_CONTROL_DST_INCR)
+		txd->dstbus.addr += len;
+
+	*remainder -= len;
+
+	return num_llis + 1;
+}
+
+/*
+ * Return number of bytes to fill to boundary, or len
+ */
+static inline u32 pl08x_pre_boundary(u32 addr, u32 len)
+{
+	u32 boundary;
+
+	boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1)
+		<< PL08X_BOUNDARY_SHIFT;
+
+	if (boundary < addr + len)
+		return boundary - addr;
+	else
+		return len;
+}
+
+/*
+ * This fills in the table of LLIs for the transfer descriptor
+ * Note that we assume we never have to change the burst sizes
+ * Return 0 for error
+ */
+static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
+			      struct pl08x_txd *txd)
+{
+	struct pl08x_channel_data *cd = txd->cd;
+	struct pl08x_bus_data *mbus, *sbus;
+	u32 remainder;
+	int num_llis = 0;
+	u32 cctl;
+	int max_bytes_per_lli;
+	int total_bytes = 0;
+	struct lli *llis_va;
+	struct lli *llis_bus;
+
+	if (!txd) {
+		dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__);
+		return 0;
+	}
+
+	txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT,
+				      &txd->llis_bus);
+	if (!txd->llis_va) {
+		dev_err(&pl08x->adev->dev, "%s no memory for llis\n", __func__);
+		return 0;
+	}
+
+	pl08x->pool_ctr++;
+
+	/*
+	 * Initialize bus values for this transfer
+	 * from the passed optimal values
+	 */
+	if (!cd) {
+		dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__);
+		return 0;
+	}
+
+	/* Get the default CCTL from the platform data */
+	cctl = cd->cctl;
+
+	/*
+	 * On the PL080 we have two bus masters and we
+	 * should select one for source and one for
+	 * destination. We try to use AHB2 for the
+	 * bus which does not increment (typically the
+	 * peripheral) else we just choose something.
+	 */
+	cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
+	if (pl08x->vd->dualmaster) {
+		if (cctl & PL080_CONTROL_SRC_INCR)
+			/* Source increments, use AHB2 for destination */
+			cctl |= PL080_CONTROL_DST_AHB2;
+		else if (cctl & PL080_CONTROL_DST_INCR)
+			/* Destination increments, use AHB2 for source */
+			cctl |= PL080_CONTROL_SRC_AHB2;
+		else
+			/* Just pick something, source AHB1 dest AHB2 */
+			cctl |= PL080_CONTROL_DST_AHB2;
+	}
+
+	/* Find maximum width of the source bus */
+	txd->srcbus.maxwidth =
+		pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >>
+				       PL080_CONTROL_SWIDTH_SHIFT);
+
+	/* Find maximum width of the destination bus */
+	txd->dstbus.maxwidth =
+		pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >>
+				       PL080_CONTROL_DWIDTH_SHIFT);
+
+	/* Set up the bus widths to the maximum */
+	txd->srcbus.buswidth = txd->srcbus.maxwidth;
+	txd->dstbus.buswidth = txd->dstbus.maxwidth;
+	dev_vdbg(&pl08x->adev->dev,
+		 "%s source bus is %d bytes wide, dest bus is %d bytes wide\n",
+		 __func__, txd->srcbus.buswidth, txd->dstbus.buswidth);
+
+
+	/*
+	 * Bytes transferred == tsize * MIN(buswidths), not max(buswidths)
+	 */
+	max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) *
+		PL080_CONTROL_TRANSFER_SIZE_MASK;
+	dev_vdbg(&pl08x->adev->dev,
+		 "%s max bytes per lli = %d\n",
+		 __func__, max_bytes_per_lli);
+
+	/* We need to count this down to zero */
+	remainder = txd->len;
+	dev_vdbg(&pl08x->adev->dev,
+		 "%s remainder = %d\n",
+		 __func__, remainder);
+
+	/*
+	 * Choose bus to align to
+	 * - prefers destination bus if both available
+	 * - if fixed address on one bus chooses other
+	 * - modifies cctl to choose an apropriate master
+	 */
+	pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus,
+				&mbus, &sbus, cctl);
+
+
+	/*
+	 * The lowest bit of the LLI register
+	 * is also used to indicate which master to
+	 * use for reading the LLIs.
+	 */
+
+	if (txd->len < mbus->buswidth) {
+		/*
+		 * Less than a bus width available
+		 * - send as single bytes
+		 */
+		while (remainder) {
+			dev_vdbg(&pl08x->adev->dev,
+				 "%s single byte LLIs for a transfer of "
+				 "less than a bus width (remain %08x)\n",
+				 __func__, remainder);
+			cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+			num_llis =
+				pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1,
+					cctl, &remainder);
+			total_bytes++;
+		}
+	} else {
+		/*
+		 *  Make one byte LLIs until master bus is aligned
+		 *  - slave will then be aligned also
+		 */
+		while ((mbus->addr) % (mbus->buswidth)) {
+			dev_vdbg(&pl08x->adev->dev,
+				"%s adjustment lli for less than bus width "
+				 "(remain %08x)\n",
+				 __func__, remainder);
+			cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+			num_llis = pl08x_fill_lli_for_desc
+				(pl08x, txd, num_llis, 1, cctl, &remainder);
+			total_bytes++;
+		}
+
+		/*
+		 *  Master now aligned
+		 * - if slave is not then we must set its width down
+		 */
+		if (sbus->addr % sbus->buswidth) {
+			dev_dbg(&pl08x->adev->dev,
+				"%s set down bus width to one byte\n",
+				 __func__);
+
+			sbus->buswidth = 1;
+		}
+
+		/*
+		 * Make largest possible LLIs until less than one bus
+		 * width left
+		 */
+		while (remainder > (mbus->buswidth - 1)) {
+			int lli_len, target_len;
+			int tsize;
+			int odd_bytes;
+
+			/*
+			 * If enough left try to send max possible,
+			 * otherwise try to send the remainder
+			 */
+			target_len = remainder;
+			if (remainder > max_bytes_per_lli)
+				target_len = max_bytes_per_lli;
+
+			/*
+			 * Set bus lengths for incrementing busses
+			 * to number of bytes which fill to next memory
+			 * boundary
+			 */
+			if (cctl & PL080_CONTROL_SRC_INCR)
+				txd->srcbus.fill_bytes =
+					pl08x_pre_boundary(
+						txd->srcbus.addr,
+						remainder);
+			else
+				txd->srcbus.fill_bytes =
+					max_bytes_per_lli;
+
+			if (cctl & PL080_CONTROL_DST_INCR)
+				txd->dstbus.fill_bytes =
+					pl08x_pre_boundary(
+						txd->dstbus.addr,
+						remainder);
+			else
+				txd->dstbus.fill_bytes =
+						max_bytes_per_lli;
+
+			/*
+			 *  Find the nearest
+			 */
+			lli_len	= min(txd->srcbus.fill_bytes,
+				txd->dstbus.fill_bytes);
+
+			BUG_ON(lli_len > remainder);
+
+			if (lli_len <= 0) {
+				dev_err(&pl08x->adev->dev,
+					"%s lli_len is %d, <= 0\n",
+						__func__, lli_len);
+				return 0;
+			}
+
+			if (lli_len == target_len) {
+				/*
+				 * Can send what we wanted
+				 */
+				/*
+				 *  Maintain alignment
+				 */
+				lli_len	= (lli_len/mbus->buswidth) *
+							mbus->buswidth;
+				odd_bytes = 0;
+			} else {
+				/*
+				 * So now we know how many bytes to transfer
+				 * to get to the nearest boundary
+				 * The next lli will past the boundary
+				 * - however we may be working to a boundary
+				 *   on the slave bus
+				 *   We need to ensure the master stays aligned
+				 */
+				odd_bytes = lli_len % mbus->buswidth;
+				/*
+				 * - and that we are working in multiples
+				 *   of the bus widths
+				 */
+				lli_len -= odd_bytes;
+
+			}
+
+			if (lli_len) {
+				/*
+				 * Check against minimum bus alignment:
+				 * Calculate actual transfer size in relation
+				 * to bus width an get a maximum remainder of
+				 * the smallest bus width - 1
+				 */
+				/* FIXME: use round_down()? */
+				tsize = lli_len / min(mbus->buswidth,
+						      sbus->buswidth);
+				lli_len	= tsize * min(mbus->buswidth,
+						      sbus->buswidth);
+
+				if (target_len != lli_len) {
+					dev_vdbg(&pl08x->adev->dev,
+					"%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n",
+					__func__, target_len, lli_len, txd->len);
+				}
+
+				cctl = pl08x_cctl_bits(cctl,
+						       txd->srcbus.buswidth,
+						       txd->dstbus.buswidth,
+						       tsize);
+
+				dev_vdbg(&pl08x->adev->dev,
+					"%s fill lli with single lli chunk of size %08x (remainder %08x)\n",
+					__func__, lli_len, remainder);
+				num_llis = pl08x_fill_lli_for_desc(pl08x, txd,
+						num_llis, lli_len, cctl,
+						&remainder);
+				total_bytes += lli_len;
+			}
+
+
+			if (odd_bytes) {
+				/*
+				 * Creep past the boundary,
+				 * maintaining master alignment
+				 */
+				int j;
+				for (j = 0; (j < mbus->buswidth)
+						&& (remainder); j++) {
+					cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+					dev_vdbg(&pl08x->adev->dev,
+						"%s align with boundardy, single byte (remain %08x)\n",
+						__func__, remainder);
+					num_llis =
+						pl08x_fill_lli_for_desc(pl08x,
+							txd, num_llis, 1,
+							cctl, &remainder);
+					total_bytes++;
+				}
+			}
+		}
+
+		/*
+		 * Send any odd bytes
+		 */
+		if (remainder < 0) {
+			dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n",
+					__func__, remainder);
+			return 0;
+		}
+
+		while (remainder) {
+			cctl = pl08x_cctl_bits(cctl, 1, 1, 1);
+			dev_vdbg(&pl08x->adev->dev,
+				"%s align with boundardy, single odd byte (remain %d)\n",
+				__func__, remainder);
+			num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis,
+					1, cctl, &remainder);
+			total_bytes++;
+		}
+	}
+	if (total_bytes != txd->len) {
+		dev_err(&pl08x->adev->dev,
+			"%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n",
+			__func__, total_bytes, txd->len);
+		return 0;
+	}
+
+	if (num_llis >= MAX_NUM_TSFR_LLIS) {
+		dev_err(&pl08x->adev->dev,
+			"%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
+			__func__, (u32) MAX_NUM_TSFR_LLIS);
+		return 0;
+	}
+	/*
+	 * Decide whether this is a loop or a terminated transfer
+	 */
+	llis_va = txd->llis_va;
+	llis_bus = (struct lli *) txd->llis_bus;
+
+	if (cd->circular_buffer) {
+		/*
+		 * Loop the circular buffer so that the next element
+		 * points back to the beginning of the LLI.
+		 */
+		llis_va[num_llis - 1].next =
+			(dma_addr_t)((unsigned int)&(llis_bus[0]));
+	} else {
+		/*
+		 * On non-circular buffers, the final LLI terminates
+		 * the LLI.
+		 */
+		llis_va[num_llis - 1].next = 0;
+		/*
+		 * The final LLI element shall also fire an interrupt
+		 */
+		llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+	}
+
+	/* Now store the channel register values */
+	txd->csrc = llis_va[0].src;
+	txd->cdst = llis_va[0].dst;
+	if (num_llis > 1)
+		txd->clli = llis_va[0].next;
+	else
+		txd->clli = 0;
+
+	txd->cctl = llis_va[0].cctl;
+	/* ccfg will be set at physical channel allocation time */
+
+#ifdef VERBOSE_DEBUG
+	{
+		int i;
+
+		for (i = 0; i < num_llis; i++) {
+			dev_vdbg(&pl08x->adev->dev,
+				 "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n",
+				 i,
+				 &llis_va[i],
+				 llis_va[i].src,
+				 llis_va[i].dst,
+				 llis_va[i].cctl,
+				 llis_va[i].next
+				);
+		}
+	}
+#endif
+
+	return num_llis;
+}
+
+/* You should call this with the struct pl08x lock held */
+static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
+			   struct pl08x_txd *txd)
+{
+	if (!txd)
+		dev_err(&pl08x->adev->dev,
+			"%s no descriptor to free\n",
+			__func__);
+
+	/* Free the LLI */
+	dma_pool_free(pl08x->pool, txd->llis_va,
+		      txd->llis_bus);
+
+	pl08x->pool_ctr--;
+
+	kfree(txd);
+}
+
+static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
+				struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_txd *txdi = NULL;
+	struct pl08x_txd *next;
+
+	if (!list_empty(&plchan->desc_list)) {
+		list_for_each_entry_safe(txdi,
+					 next, &plchan->desc_list, node) {
+			list_del(&txdi->node);
+			pl08x_free_txd(pl08x, txdi);
+		}
+
+	}
+}
+
+/*
+ * The DMA ENGINE API
+ */
+static int pl08x_alloc_chan_resources(struct dma_chan *chan)
+{
+	return 0;
+}
+
+static void pl08x_free_chan_resources(struct dma_chan *chan)
+{
+}
+
+/*
+ * This should be called with the channel plchan->lock held
+ */
+static int prep_phy_channel(struct pl08x_dma_chan *plchan,
+			    struct pl08x_txd *txd)
+{
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_phy_chan *ch;
+	int ret;
+
+	/* Check if we already have a channel */
+	if (plchan->phychan)
+		return 0;
+
+	ch = pl08x_get_phy_channel(pl08x, plchan);
+	if (!ch) {
+		/* No physical channel available, cope with it */
+		dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
+		return -EBUSY;
+	}
+
+	/*
+	 * OK we have a physical channel: for memcpy() this is all we
+	 * need, but for slaves the physical signals may be muxed!
+	 * Can the platform allow us to use this channel?
+	 */
+	if (plchan->slave &&
+	    ch->signal < 0 &&
+	    pl08x->pd->get_signal) {
+		ret = pl08x->pd->get_signal(plchan);
+		if (ret < 0) {
+			dev_dbg(&pl08x->adev->dev,
+				"unable to use physical channel %d for transfer on %s due to platform restrictions\n",
+				ch->id, plchan->name);
+			/* Release physical channel & return */
+			pl08x_put_phy_channel(pl08x, ch);
+			return -EBUSY;
+		}
+		ch->signal = ret;
+	}
+
+	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
+		 ch->id,
+		 ch->signal,
+		 plchan->name);
+
+	plchan->phychan = ch;
+
+	return 0;
+}
+
+static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
+
+	atomic_inc(&plchan->last_issued);
+	tx->cookie = atomic_read(&plchan->last_issued);
+	/* This unlock follows the lock in the prep() function */
+	spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+
+	return tx->cookie;
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
+		struct dma_chan *chan, unsigned long flags)
+{
+	struct dma_async_tx_descriptor *retval = NULL;
+
+	return retval;
+}
+
+/*
+ * Code accessing dma_async_is_complete() in a tight loop
+ * may give problems - could schedule where indicated.
+ * If slaves are relying on interrupts to signal completion this
+ * function must not be called with interrupts disabled
+ */
+static enum dma_status
+pl08x_dma_tx_status(struct dma_chan *chan,
+		    dma_cookie_t cookie,
+		    struct dma_tx_state *txstate)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	dma_cookie_t last_used;
+	dma_cookie_t last_complete;
+	enum dma_status ret;
+	u32 bytesleft = 0;
+
+	last_used = atomic_read(&plchan->last_issued);
+	last_complete = plchan->lc;
+
+	ret = dma_async_is_complete(cookie, last_complete, last_used);
+	if (ret == DMA_SUCCESS) {
+		dma_set_tx_state(txstate, last_complete, last_used, 0);
+		return ret;
+	}
+
+	/*
+	 * schedule(); could be inserted here
+	 */
+
+	/*
+	 * This cookie not complete yet
+	 */
+	last_used = atomic_read(&plchan->last_issued);
+	last_complete = plchan->lc;
+
+	/* Get number of bytes left in the active transactions and queue */
+	bytesleft = pl08x_getbytes_chan(plchan);
+
+	dma_set_tx_state(txstate, last_complete, last_used,
+			 bytesleft);
+
+	if (plchan->state == PL08X_CHAN_PAUSED)
+		return DMA_PAUSED;
+
+	/* Whether waiting or running, we're in progress */
+	return DMA_IN_PROGRESS;
+}
+
+/* PrimeCell DMA extension */
+struct burst_table {
+	int burstwords;
+	u32 reg;
+};
+
+static const struct burst_table burst_sizes[] = {
+	{
+		.burstwords = 256,
+		.reg = (PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 128,
+		.reg = (PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 64,
+		.reg = (PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 32,
+		.reg = (PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 16,
+		.reg = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 8,
+		.reg = (PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 4,
+		.reg = (PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+	{
+		.burstwords = 1,
+		.reg = (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT),
+	},
+};
+
+static void dma_set_runtime_config(struct dma_chan *chan,
+			       struct dma_slave_config *config)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_channel_data *cd = plchan->cd;
+	enum dma_slave_buswidth addr_width;
+	u32 maxburst;
+	u32 cctl = 0;
+	/* Mask out all except src and dst channel */
+	u32 ccfg = cd->ccfg & 0x000003DEU;
+	int i = 0;
+
+	/* Transfer direction */
+	plchan->runtime_direction = config->direction;
+	if (config->direction == DMA_TO_DEVICE) {
+		plchan->runtime_addr = config->dst_addr;
+		cctl |= PL080_CONTROL_SRC_INCR;
+		ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+		addr_width = config->dst_addr_width;
+		maxburst = config->dst_maxburst;
+	} else if (config->direction == DMA_FROM_DEVICE) {
+		plchan->runtime_addr = config->src_addr;
+		cctl |= PL080_CONTROL_DST_INCR;
+		ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
+		addr_width = config->src_addr_width;
+		maxburst = config->src_maxburst;
+	} else {
+		dev_err(&pl08x->adev->dev,
+			"bad runtime_config: alien transfer direction\n");
+		return;
+	}
+
+	switch (addr_width) {
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		cctl |= (PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+			(PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT);
+		break;
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		cctl |= (PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+			(PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT);
+		break;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		cctl |= (PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT) |
+			(PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT);
+		break;
+	default:
+		dev_err(&pl08x->adev->dev,
+			"bad runtime_config: alien address width\n");
+		return;
+	}
+
+	/*
+	 * Now decide on a maxburst:
+	 * If this channel will only request single transfers, set
+	 * this down to ONE element.
+	 */
+	if (plchan->cd->single) {
+		cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) |
+			(PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT);
+	} else {
+		while (i < ARRAY_SIZE(burst_sizes)) {
+			if (burst_sizes[i].burstwords <= maxburst)
+				break;
+			i++;
+		}
+		cctl |= burst_sizes[i].reg;
+	}
+
+	/* Access the cell in privileged mode, non-bufferable, non-cacheable */
+	cctl &= ~PL080_CONTROL_PROT_MASK;
+	cctl |= PL080_CONTROL_PROT_SYS;
+
+	/* Modify the default channel data to fit PrimeCell request */
+	cd->cctl = cctl;
+	cd->ccfg = ccfg;
+
+	dev_dbg(&pl08x->adev->dev,
+		"configured channel %s (%s) for %s, data width %d, "
+		"maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n",
+		dma_chan_name(chan), plchan->name,
+		(config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
+		addr_width,
+		maxburst,
+		cctl, ccfg);
+}
+
+/*
+ * Slave transactions callback to the slave device to allow
+ * synchronization of slave DMA signals with the DMAC enable
+ */
+static void pl08x_issue_pending(struct dma_chan *chan)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	unsigned long flags;
+
+	spin_lock_irqsave(&plchan->lock, flags);
+	/* Something is already active */
+	if (plchan->at) {
+			spin_unlock_irqrestore(&plchan->lock, flags);
+			return;
+	}
+
+	/* Didn't get a physical channel so waiting for it ... */
+	if (plchan->state == PL08X_CHAN_WAITING)
+		return;
+
+	/* Take the first element in the queue and execute it */
+	if (!list_empty(&plchan->desc_list)) {
+		struct pl08x_txd *next;
+
+		next = list_first_entry(&plchan->desc_list,
+					struct pl08x_txd,
+					node);
+		list_del(&next->node);
+		plchan->at = next;
+		plchan->state = PL08X_CHAN_RUNNING;
+
+		/* Configure the physical channel for the active txd */
+		pl08x_config_phychan_for_txd(plchan);
+		pl08x_set_cregs(pl08x, plchan->phychan);
+		pl08x_enable_phy_chan(pl08x, plchan->phychan);
+	}
+
+	spin_unlock_irqrestore(&plchan->lock, flags);
+}
+
+static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
+					struct pl08x_txd *txd)
+{
+	int num_llis;
+	struct pl08x_driver_data *pl08x = plchan->host;
+	int ret;
+
+	num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
+
+	if (!num_llis)
+		return -EINVAL;
+
+	spin_lock_irqsave(&plchan->lock, plchan->lockflags);
+
+	/*
+	 * If this device is not using a circular buffer then
+	 * queue this new descriptor for transfer.
+	 * The descriptor for a circular buffer continues
+	 * to be used until the channel is freed.
+	 */
+	if (txd->cd->circular_buffer)
+		dev_err(&pl08x->adev->dev,
+			"%s attempting to queue a circular buffer\n",
+			__func__);
+	else
+		list_add_tail(&txd->node,
+			      &plchan->desc_list);
+
+	/*
+	 * See if we already have a physical channel allocated,
+	 * else this is the time to try to get one.
+	 */
+	ret = prep_phy_channel(plchan, txd);
+	if (ret) {
+		/*
+		 * No physical channel available, we will
+		 * stack up the memcpy channels until there is a channel
+		 * available to handle it whereas slave transfers may
+		 * have been denied due to platform channel muxing restrictions
+		 * and since there is no guarantee that this will ever be
+		 * resolved, and since the signal must be aquired AFTER
+		 * aquiring the physical channel, we will let them be NACK:ed
+		 * with -EBUSY here. The drivers can alway retry the prep()
+		 * call if they are eager on doing this using DMA.
+		 */
+		if (plchan->slave) {
+			pl08x_free_txd_list(pl08x, plchan);
+			spin_unlock_irqrestore(&plchan->lock, plchan->lockflags);
+			return -EBUSY;
+		}
+		/* Do this memcpy whenever there is a channel ready */
+		plchan->state = PL08X_CHAN_WAITING;
+		plchan->waiting = txd;
+	} else
+		/*
+		 * Else we're all set, paused and ready to roll,
+		 * status will switch to PL08X_CHAN_RUNNING when
+		 * we call issue_pending(). If there is something
+		 * running on the channel already we don't change
+		 * its state.
+		 */
+		if (plchan->state == PL08X_CHAN_IDLE)
+			plchan->state = PL08X_CHAN_PAUSED;
+
+	/*
+	 * Notice that we leave plchan->lock locked on purpose:
+	 * it will be unlocked in the subsequent tx_submit()
+	 * call. This is a consequence of the current API.
+	 */
+
+	return 0;
+}
+
+/*
+ * Initialize a descriptor to be used by memcpy submit
+ */
+static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
+		struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
+		size_t len, unsigned long flags)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_txd *txd;
+	int ret;
+
+	txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+	if (!txd) {
+		dev_err(&pl08x->adev->dev,
+			"%s no memory for descriptor\n", __func__);
+		return NULL;
+	}
+
+	dma_async_tx_descriptor_init(&txd->tx, chan);
+	txd->direction = DMA_NONE;
+	txd->srcbus.addr = src;
+	txd->dstbus.addr = dest;
+
+	/* Set platform data for m2m */
+	txd->cd = &pl08x->pd->memcpy_channel;
+	/* Both to be incremented or the code will break */
+	txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR;
+	txd->tx.tx_submit = pl08x_tx_submit;
+	txd->tx.callback = NULL;
+	txd->tx.callback_param = NULL;
+	txd->len = len;
+
+	INIT_LIST_HEAD(&txd->node);
+	ret = pl08x_prep_channel_resources(plchan, txd);
+	if (ret)
+		return NULL;
+	/*
+	 * NB: the channel lock is held at this point so tx_submit()
+	 * must be called in direct succession.
+	 */
+
+	return &txd->tx;
+}
+
+struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_data_direction direction,
+		unsigned long flags)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_txd *txd;
+	int ret;
+
+	/*
+	 * Current implementation ASSUMES only one sg
+	 */
+	if (sg_len != 1) {
+		dev_err(&pl08x->adev->dev, "%s prepared too long sglist\n",
+			__func__);
+		BUG();
+	}
+
+	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+		__func__, sgl->length, plchan->name);
+
+	txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT);
+	if (!txd) {
+		dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
+		return NULL;
+	}
+
+	dma_async_tx_descriptor_init(&txd->tx, chan);
+
+	if (direction != plchan->runtime_direction)
+		dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
+			"the direction configured for the PrimeCell\n",
+			__func__);
+
+	/*
+	 * Set up addresses, the PrimeCell configured address
+	 * will take precedence since this may configure the
+	 * channel target address dynamically at runtime.
+	 */
+	txd->direction = direction;
+	if (direction == DMA_TO_DEVICE) {
+		txd->srcbus.addr = sgl->dma_address;
+		if (plchan->runtime_addr)
+			txd->dstbus.addr = plchan->runtime_addr;
+		else
+			txd->dstbus.addr = plchan->cd->addr;
+	} else if (direction == DMA_FROM_DEVICE) {
+		if (plchan->runtime_addr)
+			txd->srcbus.addr = plchan->runtime_addr;
+		else
+			txd->srcbus.addr = plchan->cd->addr;
+		txd->dstbus.addr = sgl->dma_address;
+	} else {
+		dev_err(&pl08x->adev->dev,
+			"%s direction unsupported\n", __func__);
+		return NULL;
+	}
+	txd->cd = plchan->cd;
+	txd->tx.tx_submit = pl08x_tx_submit;
+	txd->tx.callback = NULL;
+	txd->tx.callback_param = NULL;
+	txd->len = sgl->length;
+	INIT_LIST_HEAD(&txd->node);
+
+	ret = pl08x_prep_channel_resources(plchan, txd);
+	if (ret)
+		return NULL;
+	/*
+	 * NB: the channel lock is held at this point so tx_submit()
+	 * must be called in direct succession.
+	 */
+
+	return &txd->tx;
+}
+
+static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+			 unsigned long arg)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	unsigned long flags;
+	int ret = 0;
+
+	/* Controls applicable to inactive channels */
+	if (cmd == DMA_SLAVE_CONFIG) {
+		dma_set_runtime_config(chan,
+				       (struct dma_slave_config *)
+				       arg);
+		return 0;
+	}
+
+	/*
+	 * Anything succeeds on channels with no physical allocation and
+	 * no queued transfers.
+	 */
+	spin_lock_irqsave(&plchan->lock, flags);
+	if (!plchan->phychan && !plchan->at) {
+		spin_unlock_irqrestore(&plchan->lock, flags);
+		return 0;
+	}
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		plchan->state = PL08X_CHAN_IDLE;
+
+		if (plchan->phychan) {
+			pl08x_stop_phy_chan(plchan->phychan);
+
+			/*
+			 * Mark physical channel as free and free any slave
+			 * signal
+			 */
+			if ((plchan->phychan->signal >= 0) &&
+			    pl08x->pd->put_signal) {
+				pl08x->pd->put_signal(plchan);
+				plchan->phychan->signal = -1;
+			}
+			pl08x_put_phy_channel(pl08x, plchan->phychan);
+			plchan->phychan = NULL;
+		}
+		/* Stop any pending tasklet */
+		tasklet_disable(&plchan->tasklet);
+		/* Dequeue jobs and free LLIs */
+		if (plchan->at) {
+			pl08x_free_txd(pl08x, plchan->at);
+			plchan->at = NULL;
+		}
+		/* Dequeue jobs not yet fired as well */
+		pl08x_free_txd_list(pl08x, plchan);
+		break;
+	case DMA_PAUSE:
+		pl08x_pause_phy_chan(plchan->phychan);
+		plchan->state = PL08X_CHAN_PAUSED;
+		break;
+	case DMA_RESUME:
+		pl08x_resume_phy_chan(plchan->phychan);
+		plchan->state = PL08X_CHAN_RUNNING;
+		break;
+	default:
+		/* Unknown command */
+		ret = -ENXIO;
+		break;
+	}
+
+	spin_unlock_irqrestore(&plchan->lock, flags);
+
+	return ret;
+}
+
+bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
+{
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	char *name = chan_id;
+
+	/* Check that the channel is not taken! */
+	if (!strcmp(plchan->name, name))
+		return true;
+
+	return false;
+}
+
+/*
+ * Just check that the device is there and active
+ * TODO: turn this bit on/off depending on the number of
+ * physical channels actually used, if it is zero... well
+ * shut it off. That will save some power. Cut the clock
+ * at the same time.
+ */
+static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
+{
+	u32 val;
+
+	val = readl(pl08x->base + PL080_CONFIG);
+	val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE);
+	/* We implictly clear bit 1 and that means little-endian mode */
+	val |= PL080_CONFIG_ENABLE;
+	writel(val, pl08x->base + PL080_CONFIG);
+}
+
+static void pl08x_tasklet(unsigned long data)
+{
+	struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
+	struct pl08x_phy_chan *phychan = plchan->phychan;
+	struct pl08x_driver_data *pl08x = plchan->host;
+
+	if (!plchan)
+		BUG();
+
+	spin_lock(&plchan->lock);
+
+	if (plchan->at) {
+		dma_async_tx_callback callback =
+			plchan->at->tx.callback;
+		void *callback_param =
+			plchan->at->tx.callback_param;
+
+		/*
+		 * Update last completed
+		 */
+		plchan->lc =
+			(plchan->at->tx.cookie);
+
+		/*
+		 * Callback to signal completion
+		 */
+		if (callback)
+			callback(callback_param);
+
+		/*
+		 * Device callbacks should NOT clear
+		 * the current transaction on the channel
+		 * Linus: sometimes they should?
+		 */
+		if (!plchan->at)
+			BUG();
+
+		/*
+		 * Free the descriptor if it's not for a device
+		 * using a circular buffer
+		 */
+		if (!plchan->at->cd->circular_buffer) {
+			pl08x_free_txd(pl08x, plchan->at);
+			plchan->at = NULL;
+		}
+		/*
+		 * else descriptor for circular
+		 * buffers only freed when
+		 * client has disabled dma
+		 */
+	}
+	/*
+	 * If a new descriptor is queued, set it up
+	 * plchan->at is NULL here
+	 */
+	if (!list_empty(&plchan->desc_list)) {
+		struct pl08x_txd *next;
+
+		next = list_first_entry(&plchan->desc_list,
+					struct pl08x_txd,
+					node);
+		list_del(&next->node);
+		plchan->at = next;
+		/* Configure the physical channel for the next txd */
+		pl08x_config_phychan_for_txd(plchan);
+		pl08x_set_cregs(pl08x, plchan->phychan);
+		pl08x_enable_phy_chan(pl08x, plchan->phychan);
+	} else {
+		struct pl08x_dma_chan *waiting = NULL;
+
+		/*
+		 * No more jobs, so free up the physical channel
+		 * Free any allocated signal on slave transfers too
+		 */
+		if ((phychan->signal >= 0) && pl08x->pd->put_signal) {
+			pl08x->pd->put_signal(plchan);
+			phychan->signal = -1;
+		}
+		pl08x_put_phy_channel(pl08x, phychan);
+		plchan->phychan = NULL;
+		plchan->state = PL08X_CHAN_IDLE;
+
+		/*
+		 * And NOW before anyone else can grab that free:d
+		 * up physical channel, see if there is some memcpy
+		 * pending that seriously needs to start because of
+		 * being stacked up while we were choking the
+		 * physical channels with data.
+		 */
+		list_for_each_entry(waiting, &pl08x->memcpy.channels,
+				    chan.device_node) {
+		  if (waiting->state == PL08X_CHAN_WAITING &&
+			    waiting->waiting != NULL) {
+				int ret;
+
+				/* This should REALLY not fail now */
+				ret = prep_phy_channel(waiting,
+						       waiting->waiting);
+				BUG_ON(ret);
+				waiting->state = PL08X_CHAN_RUNNING;
+				waiting->waiting = NULL;
+				pl08x_issue_pending(&waiting->chan);
+				break;
+			}
+		}
+	}
+
+	spin_unlock(&plchan->lock);
+}
+
+static irqreturn_t pl08x_irq(int irq, void *dev)
+{
+	struct pl08x_driver_data *pl08x = dev;
+	u32 mask = 0;
+	u32 val;
+	int i;
+
+	val = readl(pl08x->base + PL080_ERR_STATUS);
+	if (val) {
+		/*
+		 * An error interrupt (on one or more channels)
+		 */
+		dev_err(&pl08x->adev->dev,
+			"%s error interrupt, register value 0x%08x\n",
+				__func__, val);
+		/*
+		 * Simply clear ALL PL08X error interrupts,
+		 * regardless of channel and cause
+		 * FIXME: should be 0x00000003 on PL081 really.
+		 */
+		writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+	}
+	val = readl(pl08x->base + PL080_INT_STATUS);
+	for (i = 0; i < pl08x->vd->channels; i++) {
+		if ((1 << i) & val) {
+			/* Locate physical channel */
+			struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
+			struct pl08x_dma_chan *plchan = phychan->serving;
+
+			/* Schedule tasklet on this channel */
+			tasklet_schedule(&plchan->tasklet);
+
+			mask |= (1 << i);
+		}
+	}
+	/*
+	 * Clear only the terminal interrupts on channels we processed
+	 */
+	writel(mask, pl08x->base + PL080_TC_CLEAR);
+
+	return mask ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*
+ * Initialise the DMAC memcpy/slave channels.
+ * Make a local wrapper to hold required data
+ */
+static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
+					   struct dma_device *dmadev,
+					   unsigned int channels,
+					   bool slave)
+{
+	struct pl08x_dma_chan *chan;
+	int i;
+
+	INIT_LIST_HEAD(&dmadev->channels);
+	/*
+	 * Register as many many memcpy as we have physical channels,
+	 * we won't always be able to use all but the code will have
+	 * to cope with that situation.
+	 */
+	for (i = 0; i < channels; i++) {
+		chan = kzalloc(sizeof(struct pl08x_dma_chan), GFP_KERNEL);
+		if (!chan) {
+			dev_err(&pl08x->adev->dev,
+				"%s no memory for channel\n", __func__);
+			return -ENOMEM;
+		}
+
+		chan->host = pl08x;
+		chan->state = PL08X_CHAN_IDLE;
+
+		if (slave) {
+			chan->slave = true;
+			chan->name = pl08x->pd->slave_channels[i].bus_id;
+			chan->cd = &pl08x->pd->slave_channels[i];
+		} else {
+			chan->cd = &pl08x->pd->memcpy_channel;
+			chan->name = kasprintf(GFP_KERNEL, "memcpy%d", i);
+			if (!chan->name) {
+				kfree(chan);
+				return -ENOMEM;
+			}
+		}
+		dev_info(&pl08x->adev->dev,
+			 "initialize virtual channel \"%s\"\n",
+			 chan->name);
+
+		chan->chan.device = dmadev;
+		atomic_set(&chan->last_issued, 0);
+		chan->lc = atomic_read(&chan->last_issued);
+
+		spin_lock_init(&chan->lock);
+		INIT_LIST_HEAD(&chan->desc_list);
+		tasklet_init(&chan->tasklet, pl08x_tasklet,
+			     (unsigned long) chan);
+
+		list_add_tail(&chan->chan.device_node, &dmadev->channels);
+	}
+	dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
+		 i, slave ? "slave" : "memcpy");
+	return i;
+}
+
+static void pl08x_free_virtual_channels(struct dma_device *dmadev)
+{
+	struct pl08x_dma_chan *chan = NULL;
+	struct pl08x_dma_chan *next;
+
+	list_for_each_entry_safe(chan,
+				 next, &dmadev->channels, chan.device_node) {
+		list_del(&chan->chan.device_node);
+		kfree(chan);
+	}
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const char *pl08x_state_str(enum pl08x_dma_chan_state state)
+{
+	switch (state) {
+	case PL08X_CHAN_IDLE:
+		return "idle";
+	case PL08X_CHAN_RUNNING:
+		return "running";
+	case PL08X_CHAN_PAUSED:
+		return "paused";
+	case PL08X_CHAN_WAITING:
+		return "waiting";
+	default:
+		break;
+	}
+	return "UNKNOWN STATE";
+}
+
+static int pl08x_debugfs_show(struct seq_file *s, void *data)
+{
+	struct pl08x_driver_data *pl08x = s->private;
+	struct pl08x_dma_chan *chan;
+	struct pl08x_phy_chan *ch;
+	unsigned long flags;
+	int i;
+
+	seq_printf(s, "PL08x physical channels:\n");
+	seq_printf(s, "CHANNEL:\tUSER:\n");
+	seq_printf(s, "--------\t-----\n");
+	for (i = 0; i < pl08x->vd->channels; i++) {
+		struct pl08x_dma_chan *virt_chan;
+
+		ch = &pl08x->phy_chans[i];
+
+		spin_lock_irqsave(&ch->lock, flags);
+		virt_chan = ch->serving;
+
+		seq_printf(s, "%d\t\t%s\n",
+			   ch->id, virt_chan ? virt_chan->name : "(none)");
+
+		spin_unlock_irqrestore(&ch->lock, flags);
+	}
+
+	seq_printf(s, "\nPL08x virtual memcpy channels:\n");
+	seq_printf(s, "CHANNEL:\tSTATE:\n");
+	seq_printf(s, "--------\t------\n");
+	list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
+		seq_printf(s, "%s\t\t\%s\n", chan->name,
+			   pl08x_state_str(chan->state));
+	}
+
+	seq_printf(s, "\nPL08x virtual slave channels:\n");
+	seq_printf(s, "CHANNEL:\tSTATE:\n");
+	seq_printf(s, "--------\t------\n");
+	list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
+		seq_printf(s, "%s\t\t\%s\n", chan->name,
+			   pl08x_state_str(chan->state));
+	}
+
+	return 0;
+}
+
+static int pl08x_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, pl08x_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations pl08x_debugfs_operations = {
+	.open		= pl08x_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+	/* Expose a simple debugfs interface to view all clocks */
+	(void) debugfs_create_file(dev_name(&pl08x->adev->dev), S_IFREG | S_IRUGO,
+				   NULL, pl08x,
+				   &pl08x_debugfs_operations);
+}
+
+#else
+static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x)
+{
+}
+#endif
+
+static int pl08x_probe(struct amba_device *adev, struct amba_id *id)
+{
+	struct pl08x_driver_data *pl08x;
+	struct vendor_data *vd = id->data;
+	int ret = 0;
+	int i;
+
+	ret = amba_request_regions(adev, NULL);
+	if (ret)
+		return ret;
+
+	/* Create the driver state holder */
+	pl08x = kzalloc(sizeof(struct pl08x_driver_data), GFP_KERNEL);
+	if (!pl08x) {
+		ret = -ENOMEM;
+		goto out_no_pl08x;
+	}
+
+	/* Initialize memcpy engine */
+	dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask);
+	pl08x->memcpy.dev = &adev->dev;
+	pl08x->memcpy.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+	pl08x->memcpy.device_free_chan_resources = pl08x_free_chan_resources;
+	pl08x->memcpy.device_prep_dma_memcpy = pl08x_prep_dma_memcpy;
+	pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+	pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
+	pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
+	pl08x->memcpy.device_control = pl08x_control;
+
+	/* Initialize slave engine */
+	dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+	pl08x->slave.dev = &adev->dev;
+	pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
+	pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
+	pl08x->slave.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
+	pl08x->slave.device_tx_status = pl08x_dma_tx_status;
+	pl08x->slave.device_issue_pending = pl08x_issue_pending;
+	pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+	pl08x->slave.device_control = pl08x_control;
+
+	/* Get the platform data */
+	pl08x->pd = dev_get_platdata(&adev->dev);
+	if (!pl08x->pd) {
+		dev_err(&adev->dev, "no platform data supplied\n");
+		goto out_no_platdata;
+	}
+
+	/* Assign useful pointers to the driver state */
+	pl08x->adev = adev;
+	pl08x->vd = vd;
+
+	/* A DMA memory pool for LLIs, align on 1-byte boundary */
+	pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
+			PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
+	if (!pl08x->pool) {
+		ret = -ENOMEM;
+		goto out_no_lli_pool;
+	}
+
+	spin_lock_init(&pl08x->lock);
+
+	pl08x->base = ioremap(adev->res.start, resource_size(&adev->res));
+	if (!pl08x->base) {
+		ret = -ENOMEM;
+		goto out_no_ioremap;
+	}
+
+	/* Turn on the PL08x */
+	pl08x_ensure_on(pl08x);
+
+	/*
+	 * Attach the interrupt handler
+	 */
+	writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR);
+	writel(0x000000FF, pl08x->base + PL080_TC_CLEAR);
+
+	ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED,
+			  vd->name, pl08x);
+	if (ret) {
+		dev_err(&adev->dev, "%s failed to request interrupt %d\n",
+			__func__, adev->irq[0]);
+		goto out_no_irq;
+	}
+
+	/* Initialize physical channels */
+	pl08x->phy_chans = kmalloc((vd->channels * sizeof(struct pl08x_phy_chan)),
+			GFP_KERNEL);
+	if (!pl08x->phy_chans) {
+		dev_err(&adev->dev, "%s failed to allocate "
+			"physical channel holders\n",
+			__func__);
+		goto out_no_phychans;
+	}
+
+	for (i = 0; i < vd->channels; i++) {
+		struct pl08x_phy_chan *ch = &pl08x->phy_chans[i];
+
+		ch->id = i;
+		ch->base = pl08x->base + PL080_Cx_BASE(i);
+		spin_lock_init(&ch->lock);
+		ch->serving = NULL;
+		ch->signal = -1;
+		dev_info(&adev->dev,
+			 "physical channel %d is %s\n", i,
+			 pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE");
+	}
+
+	/* Register as many memcpy channels as there are physical channels */
+	ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->memcpy,
+					      pl08x->vd->channels, false);
+	if (ret <= 0) {
+		dev_warn(&pl08x->adev->dev,
+			 "%s failed to enumerate memcpy channels - %d\n",
+			 __func__, ret);
+		goto out_no_memcpy;
+	}
+	pl08x->memcpy.chancnt = ret;
+
+	/* Register slave channels */
+	ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave,
+					      pl08x->pd->num_slave_channels,
+					      true);
+	if (ret <= 0) {
+		dev_warn(&pl08x->adev->dev,
+			"%s failed to enumerate slave channels - %d\n",
+				__func__, ret);
+		goto out_no_slave;
+	}
+	pl08x->slave.chancnt = ret;
+
+	ret = dma_async_device_register(&pl08x->memcpy);
+	if (ret) {
+		dev_warn(&pl08x->adev->dev,
+			"%s failed to register memcpy as an async device - %d\n",
+			__func__, ret);
+		goto out_no_memcpy_reg;
+	}
+
+	ret = dma_async_device_register(&pl08x->slave);
+	if (ret) {
+		dev_warn(&pl08x->adev->dev,
+			"%s failed to register slave as an async device - %d\n",
+			__func__, ret);
+		goto out_no_slave_reg;
+	}
+
+	amba_set_drvdata(adev, pl08x);
+	init_pl08x_debugfs(pl08x);
+	dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n",
+		vd->name, adev->res.start);
+	return 0;
+
+out_no_slave_reg:
+	dma_async_device_unregister(&pl08x->memcpy);
+out_no_memcpy_reg:
+	pl08x_free_virtual_channels(&pl08x->slave);
+out_no_slave:
+	pl08x_free_virtual_channels(&pl08x->memcpy);
+out_no_memcpy:
+	kfree(pl08x->phy_chans);
+out_no_phychans:
+	free_irq(adev->irq[0], pl08x);
+out_no_irq:
+	iounmap(pl08x->base);
+out_no_ioremap:
+	dma_pool_destroy(pl08x->pool);
+out_no_lli_pool:
+out_no_platdata:
+	kfree(pl08x);
+out_no_pl08x:
+	amba_release_regions(adev);
+	return ret;
+}
+
+/* PL080 has 8 channels and the PL080 have just 2 */
+static struct vendor_data vendor_pl080 = {
+	.name = "PL080",
+	.channels = 8,
+	.dualmaster = true,
+};
+
+static struct vendor_data vendor_pl081 = {
+	.name = "PL081",
+	.channels = 2,
+	.dualmaster = false,
+};
+
+static struct amba_id pl08x_ids[] = {
+	/* PL080 */
+	{
+		.id	= 0x00041080,
+		.mask	= 0x000fffff,
+		.data	= &vendor_pl080,
+	},
+	/* PL081 */
+	{
+		.id	= 0x00041081,
+		.mask	= 0x000fffff,
+		.data	= &vendor_pl081,
+	},
+	/* Nomadik 8815 PL080 variant */
+	{
+		.id	= 0x00280880,
+		.mask	= 0x00ffffff,
+		.data	= &vendor_pl080,
+	},
+	{ 0, 0 },
+};
+
+static struct amba_driver pl08x_amba_driver = {
+	.drv.name	= DRIVER_NAME,
+	.id_table	= pl08x_ids,
+	.probe		= pl08x_probe,
+};
+
+static int __init pl08x_init(void)
+{
+	int retval;
+	retval = amba_driver_register(&pl08x_amba_driver);
+	if (retval)
+		printk(KERN_WARNING DRIVER_NAME
+		       "failed to register as an amba device (%d)\n",
+		       retval);
+	return retval;
+}
+subsys_initcall(pl08x_init);
diff -druN linux-libre-2.6.36-gnu/drivers/dma/at_hdmac.c linux-libre-2.6.37-gnu/drivers/dma/at_hdmac.c
--- linux-libre-2.6.36-gnu/drivers/dma/at_hdmac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/at_hdmac.c	2011-01-04 19:50:19.000000000 -0500
@@ -722,7 +722,7 @@
 			desc->lli.daddr = mem;
 			desc->lli.ctrla = ctrla
 					| ATC_DST_WIDTH(mem_width)
-					| len >> mem_width;
+					| len >> reg_width;
 			desc->lli.ctrlb = ctrlb;
 
 			if (!first) {
diff -druN linux-libre-2.6.36-gnu/drivers/dma/coh901318.c linux-libre-2.6.37-gnu/drivers/dma/coh901318.c
--- linux-libre-2.6.36-gnu/drivers/dma/coh901318.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/coh901318.c	2011-01-04 19:50:19.000000000 -0500
@@ -157,6 +157,7 @@
 	.owner		= THIS_MODULE,
 	.open		= coh901318_debugfs_open,
 	.read		= coh901318_debugfs_read,
+	.llseek		= default_llseek,
 };
 
 
@@ -1609,7 +1610,7 @@
 {
 	return platform_driver_probe(&coh901318_driver, coh901318_probe);
 }
-subsys_initcall(coh901318_init);
+arch_initcall(coh901318_init);
 
 void __exit coh901318_exit(void)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/dma/dmaengine.c linux-libre-2.6.37-gnu/drivers/dma/dmaengine.c
--- linux-libre-2.6.36-gnu/drivers/dma/dmaengine.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/dmaengine.c	2011-01-04 19:50:19.000000000 -0500
@@ -690,8 +690,12 @@
 		!device->device_prep_dma_memset);
 	BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
 		!device->device_prep_dma_interrupt);
+	BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
+		!device->device_prep_dma_sg);
 	BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
 		!device->device_prep_slave_sg);
+	BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
+		!device->device_prep_dma_cyclic);
 	BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
 		!device->device_control);
 
@@ -702,7 +706,7 @@
 	BUG_ON(!device->dev);
 
 	/* note: this only matters in the
-	 * CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH=y case
+	 * CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case
 	 */
 	if (device_has_all_tx_types(device))
 		dma_cap_set(DMA_ASYNC_TX, device->cap_mask);
@@ -976,7 +980,7 @@
 	struct dma_chan *chan)
 {
 	tx->chan = chan;
-	#ifndef CONFIG_ASYNC_TX_DISABLE_CHANNEL_SWITCH
+	#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	spin_lock_init(&tx->lock);
 	#endif
 }
diff -druN linux-libre-2.6.36-gnu/drivers/dma/fsldma.c linux-libre-2.6.37-gnu/drivers/dma/fsldma.c
--- linux-libre-2.6.36-gnu/drivers/dma/fsldma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/fsldma.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,9 +35,10 @@
 #include <linux/dmapool.h>
 #include <linux/of_platform.h>
 
-#include <asm/fsldma.h>
 #include "fsldma.h"
 
+static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+
 static void dma_init(struct fsldma_chan *chan)
 {
 	/* Reset the channel */
@@ -49,9 +50,11 @@
 		 * EIE - Error interrupt enable
 		 * EOSIE - End of segments interrupt enable (basic mode)
 		 * EOLNIE - End of links interrupt enable
+		 * BWC - Bandwidth sharing among channels
 		 */
-		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EIE
-				| FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
+		DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC
+				| FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE
+				| FSL_DMA_MR_EOSIE, 32);
 		break;
 	case FSL_DMA_IP_83XX:
 		/* Set the channel to below modes:
@@ -499,7 +502,7 @@
 
 	new = fsl_dma_alloc_descriptor(chan);
 	if (!new) {
-		dev_err(chan->dev, "No free memory for link descriptor\n");
+		dev_err(chan->dev, msg_ld_oom);
 		return NULL;
 	}
 
@@ -536,8 +539,7 @@
 		/* Allocate the link descriptor from DMA pool */
 		new = fsl_dma_alloc_descriptor(chan);
 		if (!new) {
-			dev_err(chan->dev,
-					"No free memory for link descriptor\n");
+			dev_err(chan->dev, msg_ld_oom);
 			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
@@ -583,223 +585,205 @@
 	return NULL;
 }
 
-/**
- * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
- * @chan: DMA channel
- * @sgl: scatterlist to transfer to/from
- * @sg_len: number of entries in @scatterlist
- * @direction: DMA direction
- * @flags: DMAEngine flags
- *
- * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
- * DMA_SLAVE API, this gets the device-specific information from the
- * chan->private variable.
- */
-static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
-	struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
-	enum dma_data_direction direction, unsigned long flags)
+static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
+	struct scatterlist *dst_sg, unsigned int dst_nents,
+	struct scatterlist *src_sg, unsigned int src_nents,
+	unsigned long flags)
 {
-	struct fsldma_chan *chan;
 	struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
-	struct fsl_dma_slave *slave;
-	size_t copy;
-
-	int i;
-	struct scatterlist *sg;
-	size_t sg_used;
-	size_t hw_used;
-	struct fsl_dma_hw_addr *hw;
-	dma_addr_t dma_dst, dma_src;
-
-	if (!dchan)
-		return NULL;
+	struct fsldma_chan *chan = to_fsl_chan(dchan);
+	size_t dst_avail, src_avail;
+	dma_addr_t dst, src;
+	size_t len;
 
-	if (!dchan->private)
+	/* basic sanity checks */
+	if (dst_nents == 0 || src_nents == 0)
 		return NULL;
 
-	chan = to_fsl_chan(dchan);
-	slave = dchan->private;
-
-	if (list_empty(&slave->addresses))
+	if (dst_sg == NULL || src_sg == NULL)
 		return NULL;
 
-	hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
-	hw_used = 0;
-
 	/*
-	 * Build the hardware transaction to copy from the scatterlist to
-	 * the hardware, or from the hardware to the scatterlist
-	 *
-	 * If you are copying from the hardware to the scatterlist and it
-	 * takes two hardware entries to fill an entire page, then both
-	 * hardware entries will be coalesced into the same page
-	 *
-	 * If you are copying from the scatterlist to the hardware and a
-	 * single page can fill two hardware entries, then the data will
-	 * be read out of the page into the first hardware entry, and so on
+	 * TODO: should we check that both scatterlists have the same
+	 * TODO: number of bytes in total? Is that really an error?
 	 */
-	for_each_sg(sgl, sg, sg_len, i) {
-		sg_used = 0;
 
-		/* Loop until the entire scatterlist entry is used */
-		while (sg_used < sg_dma_len(sg)) {
+	/* get prepared for the loop */
+	dst_avail = sg_dma_len(dst_sg);
+	src_avail = sg_dma_len(src_sg);
 
-			/*
-			 * If we've used up the current hardware address/length
-			 * pair, we need to load a new one
-			 *
-			 * This is done in a while loop so that descriptors with
-			 * length == 0 will be skipped
-			 */
-			while (hw_used >= hw->length) {
+	/* run until we are out of scatterlist entries */
+	while (true) {
 
-				/*
-				 * If the current hardware entry is the last
-				 * entry in the list, we're finished
-				 */
-				if (list_is_last(&hw->entry, &slave->addresses))
-					goto finished;
+		/* create the largest transaction possible */
+		len = min_t(size_t, src_avail, dst_avail);
+		len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
+		if (len == 0)
+			goto fetch;
 
-				/* Get the next hardware address/length pair */
-				hw = list_entry(hw->entry.next,
-						struct fsl_dma_hw_addr, entry);
-				hw_used = 0;
-			}
+		dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
+		src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;
 
-			/* Allocate the link descriptor from DMA pool */
-			new = fsl_dma_alloc_descriptor(chan);
-			if (!new) {
-				dev_err(chan->dev, "No free memory for "
-						       "link descriptor\n");
-				goto fail;
-			}
+		/* allocate and populate the descriptor */
+		new = fsl_dma_alloc_descriptor(chan);
+		if (!new) {
+			dev_err(chan->dev, msg_ld_oom);
+			goto fail;
+		}
 #ifdef FSL_DMA_LD_DEBUG
-			dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+		dev_dbg(chan->dev, "new link desc alloc %p\n", new);
 #endif
 
-			/*
-			 * Calculate the maximum number of bytes to transfer,
-			 * making sure it is less than the DMA controller limit
-			 */
-			copy = min_t(size_t, sg_dma_len(sg) - sg_used,
-					     hw->length - hw_used);
-			copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
-
-			/*
-			 * DMA_FROM_DEVICE
-			 * from the hardware to the scatterlist
-			 *
-			 * DMA_TO_DEVICE
-			 * from the scatterlist to the hardware
-			 */
-			if (direction == DMA_FROM_DEVICE) {
-				dma_src = hw->address + hw_used;
-				dma_dst = sg_dma_address(sg) + sg_used;
-			} else {
-				dma_src = sg_dma_address(sg) + sg_used;
-				dma_dst = hw->address + hw_used;
-			}
+		set_desc_cnt(chan, &new->hw, len);
+		set_desc_src(chan, &new->hw, src);
+		set_desc_dst(chan, &new->hw, dst);
 
-			/* Fill in the descriptor */
-			set_desc_cnt(chan, &new->hw, copy);
-			set_desc_src(chan, &new->hw, dma_src);
-			set_desc_dst(chan, &new->hw, dma_dst);
+		if (!first)
+			first = new;
+		else
+			set_desc_next(chan, &prev->hw, new->async_tx.phys);
 
-			/*
-			 * If this is not the first descriptor, chain the
-			 * current descriptor after the previous descriptor
-			 */
-			if (!first) {
-				first = new;
-			} else {
-				set_desc_next(chan, &prev->hw,
-					      new->async_tx.phys);
-			}
+		new->async_tx.cookie = 0;
+		async_tx_ack(&new->async_tx);
+		prev = new;
 
-			new->async_tx.cookie = 0;
-			async_tx_ack(&new->async_tx);
+		/* Insert the link descriptor to the LD ring */
+		list_add_tail(&new->node, &first->tx_list);
 
-			prev = new;
-			sg_used += copy;
-			hw_used += copy;
+		/* update metadata */
+		dst_avail -= len;
+		src_avail -= len;
 
-			/* Insert the link descriptor into the LD ring */
-			list_add_tail(&new->node, &first->tx_list);
-		}
-	}
+fetch:
+		/* fetch the next dst scatterlist entry */
+		if (dst_avail == 0) {
 
-finished:
+			/* no more entries: we're done */
+			if (dst_nents == 0)
+				break;
 
-	/* All of the hardware address/length pairs had length == 0 */
-	if (!first || !new)
-		return NULL;
+			/* fetch the next entry: if there are no more: done */
+			dst_sg = sg_next(dst_sg);
+			if (dst_sg == NULL)
+				break;
 
-	new->async_tx.flags = flags;
-	new->async_tx.cookie = -EBUSY;
+			dst_nents--;
+			dst_avail = sg_dma_len(dst_sg);
+		}
 
-	/* Set End-of-link to the last link descriptor of new list */
-	set_ld_eol(chan, new);
+		/* fetch the next src scatterlist entry */
+		if (src_avail == 0) {
 
-	/* Enable extra controller features */
-	if (chan->set_src_loop_size)
-		chan->set_src_loop_size(chan, slave->src_loop_size);
+			/* no more entries: we're done */
+			if (src_nents == 0)
+				break;
 
-	if (chan->set_dst_loop_size)
-		chan->set_dst_loop_size(chan, slave->dst_loop_size);
+			/* fetch the next entry: if there are no more: done */
+			src_sg = sg_next(src_sg);
+			if (src_sg == NULL)
+				break;
 
-	if (chan->toggle_ext_start)
-		chan->toggle_ext_start(chan, slave->external_start);
+			src_nents--;
+			src_avail = sg_dma_len(src_sg);
+		}
+	}
 
-	if (chan->toggle_ext_pause)
-		chan->toggle_ext_pause(chan, slave->external_pause);
+	new->async_tx.flags = flags; /* client is in control of this ack */
+	new->async_tx.cookie = -EBUSY;
 
-	if (chan->set_request_count)
-		chan->set_request_count(chan, slave->request_count);
+	/* Set End-of-link to the last link descriptor of new list */
+	set_ld_eol(chan, new);
 
 	return &first->async_tx;
 
 fail:
-	/* If first was not set, then we failed to allocate the very first
-	 * descriptor, and we're done */
 	if (!first)
 		return NULL;
 
+	fsldma_free_desc_list_reverse(chan, &first->tx_list);
+	return NULL;
+}
+
+/**
+ * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
+ * @chan: DMA channel
+ * @sgl: scatterlist to transfer to/from
+ * @sg_len: number of entries in @scatterlist
+ * @direction: DMA direction
+ * @flags: DMAEngine flags
+ *
+ * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
+ * DMA_SLAVE API, this gets the device-specific information from the
+ * chan->private variable.
+ */
+static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
+	struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
+	enum dma_data_direction direction, unsigned long flags)
+{
 	/*
-	 * First is set, so all of the descriptors we allocated have been added
-	 * to first->tx_list, INCLUDING "first" itself. Therefore we
-	 * must traverse the list backwards freeing each descriptor in turn
+	 * This operation is not supported on the Freescale DMA controller
 	 *
-	 * We're re-using variables for the loop, oh well
+	 * However, we need to provide the function pointer to allow the
+	 * device_control() method to work.
 	 */
-	fsldma_free_desc_list_reverse(chan, &first->tx_list);
 	return NULL;
 }
 
 static int fsl_dma_device_control(struct dma_chan *dchan,
 				  enum dma_ctrl_cmd cmd, unsigned long arg)
 {
+	struct dma_slave_config *config;
 	struct fsldma_chan *chan;
 	unsigned long flags;
-
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
+	int size;
 
 	if (!dchan)
 		return -EINVAL;
 
 	chan = to_fsl_chan(dchan);
 
-	/* Halt the DMA engine */
-	dma_halt(chan);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		/* Halt the DMA engine */
+		dma_halt(chan);
 
-	spin_lock_irqsave(&chan->desc_lock, flags);
+		spin_lock_irqsave(&chan->desc_lock, flags);
 
-	/* Remove and free all of the descriptors in the LD queue */
-	fsldma_free_desc_list(chan, &chan->ld_pending);
-	fsldma_free_desc_list(chan, &chan->ld_running);
+		/* Remove and free all of the descriptors in the LD queue */
+		fsldma_free_desc_list(chan, &chan->ld_pending);
+		fsldma_free_desc_list(chan, &chan->ld_running);
 
-	spin_unlock_irqrestore(&chan->desc_lock, flags);
+		spin_unlock_irqrestore(&chan->desc_lock, flags);
+		return 0;
+
+	case DMA_SLAVE_CONFIG:
+		config = (struct dma_slave_config *)arg;
+
+		/* make sure the channel supports setting burst size */
+		if (!chan->set_request_count)
+			return -ENXIO;
+
+		/* we set the controller burst size depending on direction */
+		if (config->direction == DMA_TO_DEVICE)
+			size = config->dst_addr_width * config->dst_maxburst;
+		else
+			size = config->src_addr_width * config->src_maxburst;
+
+		chan->set_request_count(chan, size);
+		return 0;
+
+	case FSLDMA_EXTERNAL_START:
+
+		/* make sure the channel supports external start */
+		if (!chan->toggle_ext_start)
+			return -ENXIO;
+
+		chan->toggle_ext_start(chan, arg);
+		return 0;
+
+	default:
+		return -ENXIO;
+	}
 
 	return 0;
 }
@@ -1327,11 +1311,13 @@
 
 	dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
 	dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
+	dma_cap_set(DMA_SG, fdev->common.cap_mask);
 	dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
 	fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
 	fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
 	fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
 	fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
+	fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
 	fdev->common.device_tx_status = fsl_tx_status;
 	fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
 	fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
diff -druN linux-libre-2.6.36-gnu/drivers/dma/fsldma.h linux-libre-2.6.37-gnu/drivers/dma/fsldma.h
--- linux-libre-2.6.36-gnu/drivers/dma/fsldma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/fsldma.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Author:
  *   Zhang Wei <wei.zhang@freescale.com>, Jul 2007
@@ -36,6 +36,13 @@
 #define FSL_DMA_MR_DAHE		0x00002000
 #define FSL_DMA_MR_SAHE		0x00001000
 
+/*
+ * Bandwidth/pause control determines how many bytes a given
+ * channel is allowed to transfer before the DMA engine pauses
+ * the current channel and switches to the next channel
+ */
+#define FSL_DMA_MR_BWC         0x08000000
+
 /* Special MR definition for MPC8349 */
 #define FSL_DMA_MR_EOTIE	0x00000080
 #define FSL_DMA_MR_PRC_RM	0x00000800
diff -druN linux-libre-2.6.36-gnu/drivers/dma/imx-dma.c linux-libre-2.6.37-gnu/drivers/dma/imx-dma.c
--- linux-libre-2.6.36-gnu/drivers/dma/imx-dma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/dma/imx-dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,424 @@
+/*
+ * drivers/dma/imx-dma.c
+ *
+ * This file contains a driver for the Freescale i.MX DMA engine
+ * found on i.MX1/21/27
+ *
+ * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+
+#include <asm/irq.h>
+#include <mach/dma-v1.h>
+#include <mach/hardware.h>
+
+struct imxdma_channel {
+	struct imxdma_engine		*imxdma;
+	unsigned int			channel;
+	unsigned int			imxdma_channel;
+
+	enum dma_slave_buswidth		word_size;
+	dma_addr_t			per_address;
+	u32				watermark_level;
+	struct dma_chan			chan;
+	spinlock_t			lock;
+	struct dma_async_tx_descriptor	desc;
+	dma_cookie_t			last_completed;
+	enum dma_status			status;
+	int				dma_request;
+	struct scatterlist		*sg_list;
+};
+
+#define MAX_DMA_CHANNELS 8
+
+struct imxdma_engine {
+	struct device			*dev;
+	struct dma_device		dma_device;
+	struct imxdma_channel		channel[MAX_DMA_CHANNELS];
+};
+
+static struct imxdma_channel *to_imxdma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct imxdma_channel, chan);
+}
+
+static void imxdma_handle(struct imxdma_channel *imxdmac)
+{
+	if (imxdmac->desc.callback)
+		imxdmac->desc.callback(imxdmac->desc.callback_param);
+	imxdmac->last_completed = imxdmac->desc.cookie;
+}
+
+static void imxdma_irq_handler(int channel, void *data)
+{
+	struct imxdma_channel *imxdmac = data;
+
+	imxdmac->status = DMA_SUCCESS;
+	imxdma_handle(imxdmac);
+}
+
+static void imxdma_err_handler(int channel, void *data, int error)
+{
+	struct imxdma_channel *imxdmac = data;
+
+	imxdmac->status = DMA_ERROR;
+	imxdma_handle(imxdmac);
+}
+
+static void imxdma_progression(int channel, void *data,
+		struct scatterlist *sg)
+{
+	struct imxdma_channel *imxdmac = data;
+
+	imxdmac->status = DMA_SUCCESS;
+	imxdma_handle(imxdmac);
+}
+
+static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct dma_slave_config *dmaengine_cfg = (void *)arg;
+	int ret;
+	unsigned int mode = 0;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		imxdmac->status = DMA_ERROR;
+		imx_dma_disable(imxdmac->imxdma_channel);
+		return 0;
+	case DMA_SLAVE_CONFIG:
+		if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+			imxdmac->per_address = dmaengine_cfg->src_addr;
+			imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
+			imxdmac->word_size = dmaengine_cfg->src_addr_width;
+		} else {
+			imxdmac->per_address = dmaengine_cfg->dst_addr;
+			imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
+			imxdmac->word_size = dmaengine_cfg->dst_addr_width;
+		}
+
+		switch (imxdmac->word_size) {
+		case DMA_SLAVE_BUSWIDTH_1_BYTE:
+			mode = IMX_DMA_MEMSIZE_8;
+			break;
+		case DMA_SLAVE_BUSWIDTH_2_BYTES:
+			mode = IMX_DMA_MEMSIZE_16;
+			break;
+		default:
+		case DMA_SLAVE_BUSWIDTH_4_BYTES:
+			mode = IMX_DMA_MEMSIZE_32;
+			break;
+		}
+		ret = imx_dma_config_channel(imxdmac->imxdma_channel,
+				mode | IMX_DMA_TYPE_FIFO,
+				IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+				imxdmac->dma_request, 1);
+
+		if (ret)
+			return ret;
+
+		imx_dma_config_burstlen(imxdmac->imxdma_channel, imxdmac->watermark_level);
+
+		return 0;
+	default:
+		return -ENOSYS;
+	}
+
+	return -EINVAL;
+}
+
+static enum dma_status imxdma_tx_status(struct dma_chan *chan,
+					    dma_cookie_t cookie,
+					    struct dma_tx_state *txstate)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	dma_cookie_t last_used;
+	enum dma_status ret;
+
+	last_used = chan->cookie;
+
+	ret = dma_async_is_complete(cookie, imxdmac->last_completed, last_used);
+	dma_set_tx_state(txstate, imxdmac->last_completed, last_used, 0);
+
+	return ret;
+}
+
+static dma_cookie_t imxdma_assign_cookie(struct imxdma_channel *imxdma)
+{
+	dma_cookie_t cookie = imxdma->chan.cookie;
+
+	if (++cookie < 0)
+		cookie = 1;
+
+	imxdma->chan.cookie = cookie;
+	imxdma->desc.cookie = cookie;
+
+	return cookie;
+}
+
+static dma_cookie_t imxdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(tx->chan);
+	dma_cookie_t cookie;
+
+	spin_lock_irq(&imxdmac->lock);
+
+	cookie = imxdma_assign_cookie(imxdmac);
+
+	imx_dma_enable(imxdmac->imxdma_channel);
+
+	spin_unlock_irq(&imxdmac->lock);
+
+	return cookie;
+}
+
+static int imxdma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imx_dma_data *data = chan->private;
+
+	imxdmac->dma_request = data->dma_request;
+
+	dma_async_tx_descriptor_init(&imxdmac->desc, chan);
+	imxdmac->desc.tx_submit = imxdma_tx_submit;
+	/* txd.flags will be overwritten in prep funcs */
+	imxdmac->desc.flags = DMA_CTRL_ACK;
+
+	imxdmac->status = DMA_SUCCESS;
+
+	return 0;
+}
+
+static void imxdma_free_chan_resources(struct dma_chan *chan)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+
+	imx_dma_disable(imxdmac->imxdma_channel);
+
+	if (imxdmac->sg_list) {
+		kfree(imxdmac->sg_list);
+		imxdmac->sg_list = NULL;
+	}
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_data_direction direction,
+		unsigned long flags)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct scatterlist *sg;
+	int i, ret, dma_length = 0;
+	unsigned int dmamode;
+
+	if (imxdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+
+	imxdmac->status = DMA_IN_PROGRESS;
+
+	for_each_sg(sgl, sg, sg_len, i) {
+		dma_length += sg->length;
+	}
+
+	if (direction == DMA_FROM_DEVICE)
+		dmamode = DMA_MODE_READ;
+	else
+		dmamode = DMA_MODE_WRITE;
+
+	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, sgl, sg_len,
+		 dma_length, imxdmac->per_address, dmamode);
+	if (ret)
+		return NULL;
+
+	return &imxdmac->desc;
+}
+
+static struct dma_async_tx_descriptor *imxdma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+	struct imxdma_engine *imxdma = imxdmac->imxdma;
+	int i, ret;
+	unsigned int periods = buf_len / period_len;
+	unsigned int dmamode;
+
+	dev_dbg(imxdma->dev, "%s channel: %d buf_len=%d period_len=%d\n",
+			__func__, imxdmac->channel, buf_len, period_len);
+
+	if (imxdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+	imxdmac->status = DMA_IN_PROGRESS;
+
+	ret = imx_dma_setup_progression_handler(imxdmac->imxdma_channel,
+			imxdma_progression);
+	if (ret) {
+		dev_err(imxdma->dev, "Failed to setup the DMA handler\n");
+		return NULL;
+	}
+
+	if (imxdmac->sg_list)
+		kfree(imxdmac->sg_list);
+
+	imxdmac->sg_list = kcalloc(periods + 1,
+			sizeof(struct scatterlist), GFP_KERNEL);
+	if (!imxdmac->sg_list)
+		return NULL;
+
+	sg_init_table(imxdmac->sg_list, periods);
+
+	for (i = 0; i < periods; i++) {
+		imxdmac->sg_list[i].page_link = 0;
+		imxdmac->sg_list[i].offset = 0;
+		imxdmac->sg_list[i].dma_address = dma_addr;
+		imxdmac->sg_list[i].length = period_len;
+		dma_addr += period_len;
+	}
+
+	/* close the loop */
+	imxdmac->sg_list[periods].offset = 0;
+	imxdmac->sg_list[periods].length = 0;
+	imxdmac->sg_list[periods].page_link =
+		((unsigned long)imxdmac->sg_list | 0x01) & ~0x02;
+
+	if (direction == DMA_FROM_DEVICE)
+		dmamode = DMA_MODE_READ;
+	else
+		dmamode = DMA_MODE_WRITE;
+
+	ret = imx_dma_setup_sg(imxdmac->imxdma_channel, imxdmac->sg_list, periods,
+		 IMX_DMA_LENGTH_LOOP, imxdmac->per_address, dmamode);
+	if (ret)
+		return NULL;
+
+	return &imxdmac->desc;
+}
+
+static void imxdma_issue_pending(struct dma_chan *chan)
+{
+	/*
+	 * Nothing to do. We only have a single descriptor
+	 */
+}
+
+static int __init imxdma_probe(struct platform_device *pdev)
+{
+	struct imxdma_engine *imxdma;
+	int ret, i;
+
+	imxdma = kzalloc(sizeof(*imxdma), GFP_KERNEL);
+	if (!imxdma)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&imxdma->dma_device.channels);
+
+	/* Initialize channel parameters */
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+		imxdmac->imxdma_channel = imx_dma_request_by_prio("dmaengine",
+				DMA_PRIO_MEDIUM);
+		if ((int)imxdmac->channel < 0) {
+			ret = -ENODEV;
+			goto err_init;
+		}
+
+		imx_dma_setup_handlers(imxdmac->imxdma_channel,
+		       imxdma_irq_handler, imxdma_err_handler, imxdmac);
+
+		imxdmac->imxdma = imxdma;
+		spin_lock_init(&imxdmac->lock);
+
+		dma_cap_set(DMA_SLAVE, imxdma->dma_device.cap_mask);
+		dma_cap_set(DMA_CYCLIC, imxdma->dma_device.cap_mask);
+
+		imxdmac->chan.device = &imxdma->dma_device;
+		imxdmac->chan.chan_id = i;
+		imxdmac->channel = i;
+
+		/* Add the channel to the DMAC list */
+		list_add_tail(&imxdmac->chan.device_node, &imxdma->dma_device.channels);
+	}
+
+	imxdma->dev = &pdev->dev;
+	imxdma->dma_device.dev = &pdev->dev;
+
+	imxdma->dma_device.device_alloc_chan_resources = imxdma_alloc_chan_resources;
+	imxdma->dma_device.device_free_chan_resources = imxdma_free_chan_resources;
+	imxdma->dma_device.device_tx_status = imxdma_tx_status;
+	imxdma->dma_device.device_prep_slave_sg = imxdma_prep_slave_sg;
+	imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
+	imxdma->dma_device.device_control = imxdma_control;
+	imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
+
+	platform_set_drvdata(pdev, imxdma);
+
+	ret = dma_async_device_register(&imxdma->dma_device);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register\n");
+		goto err_init;
+	}
+
+	return 0;
+
+err_init:
+	while (--i >= 0) {
+		struct imxdma_channel *imxdmac = &imxdma->channel[i];
+		imx_dma_free(imxdmac->imxdma_channel);
+	}
+
+	kfree(imxdma);
+	return ret;
+}
+
+static int __exit imxdma_remove(struct platform_device *pdev)
+{
+	struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
+	int i;
+
+        dma_async_device_unregister(&imxdma->dma_device);
+
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+		 imx_dma_free(imxdmac->imxdma_channel);
+	}
+
+        kfree(imxdma);
+
+        return 0;
+}
+
+static struct platform_driver imxdma_driver = {
+	.driver		= {
+		.name	= "imx-dma",
+	},
+	.remove		= __exit_p(imxdma_remove),
+};
+
+static int __init imxdma_module_init(void)
+{
+	return platform_driver_probe(&imxdma_driver, imxdma_probe);
+}
+subsys_initcall(imxdma_module_init);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX dma driver");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/dma/imx-sdma.c linux-libre-2.6.37-gnu/drivers/dma/imx-sdma.c
--- linux-libre-2.6.36-gnu/drivers/dma/imx-sdma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/dma/imx-sdma.c	2012-03-23 23:31:22.000000000 -0400
@@ -0,0 +1,1392 @@
+/*
+ * drivers/dma/imx-sdma.c
+ *
+ * This file contains a driver for the Freescale Smart DMA engine
+ *
+ * Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * Based on code from Freescale:
+ *
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+
+#include <asm/irq.h>
+#include <mach/sdma.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+
+/* SDMA registers */
+#define SDMA_H_C0PTR		0x000
+#define SDMA_H_INTR		0x004
+#define SDMA_H_STATSTOP		0x008
+#define SDMA_H_START		0x00c
+#define SDMA_H_EVTOVR		0x010
+#define SDMA_H_DSPOVR		0x014
+#define SDMA_H_HOSTOVR		0x018
+#define SDMA_H_EVTPEND		0x01c
+#define SDMA_H_DSPENBL		0x020
+#define SDMA_H_RESET		0x024
+#define SDMA_H_EVTERR		0x028
+#define SDMA_H_INTRMSK		0x02c
+#define SDMA_H_PSW		0x030
+#define SDMA_H_EVTERRDBG	0x034
+#define SDMA_H_CONFIG		0x038
+#define SDMA_ONCE_ENB		0x040
+#define SDMA_ONCE_DATA		0x044
+#define SDMA_ONCE_INSTR		0x048
+#define SDMA_ONCE_STAT		0x04c
+#define SDMA_ONCE_CMD		0x050
+#define SDMA_EVT_MIRROR		0x054
+#define SDMA_ILLINSTADDR	0x058
+#define SDMA_CHN0ADDR		0x05c
+#define SDMA_ONCE_RTB		0x060
+#define SDMA_XTRIG_CONF1	0x070
+#define SDMA_XTRIG_CONF2	0x074
+#define SDMA_CHNENBL0_V2	0x200
+#define SDMA_CHNENBL0_V1	0x080
+#define SDMA_CHNPRI_0		0x100
+
+/*
+ * Buffer descriptor status values.
+ */
+#define BD_DONE  0x01
+#define BD_WRAP  0x02
+#define BD_CONT  0x04
+#define BD_INTR  0x08
+#define BD_RROR  0x10
+#define BD_LAST  0x20
+#define BD_EXTD  0x80
+
+/*
+ * Data Node descriptor status values.
+ */
+#define DND_END_OF_FRAME  0x80
+#define DND_END_OF_XFER   0x40
+#define DND_DONE          0x20
+#define DND_UNUSED        0x01
+
+/*
+ * IPCV2 descriptor status values.
+ */
+#define BD_IPCV2_END_OF_FRAME  0x40
+
+#define IPCV2_MAX_NODES        50
+/*
+ * Error bit set in the CCB status field by the SDMA,
+ * in setbd routine, in case of a transfer error
+ */
+#define DATA_ERROR  0x10000000
+
+/*
+ * Buffer descriptor commands.
+ */
+#define C0_ADDR             0x01
+#define C0_LOAD             0x02
+#define C0_DUMP             0x03
+#define C0_SETCTX           0x07
+#define C0_GETCTX           0x03
+#define C0_SETDM            0x01
+#define C0_SETPM            0x04
+#define C0_GETDM            0x02
+#define C0_GETPM            0x08
+/*
+ * Change endianness indicator in the BD command field
+ */
+#define CHANGE_ENDIANNESS   0x80
+
+/*
+ * Mode/Count of data node descriptors - IPCv2
+ */
+struct sdma_mode_count {
+	u32 count   : 16; /* size of the buffer pointed by this BD */
+	u32 status  :  8; /* E,R,I,C,W,D status bits stored here */
+	u32 command :  8; /* command mostlky used for channel 0 */
+};
+
+/*
+ * Buffer descriptor
+ */
+struct sdma_buffer_descriptor {
+	struct sdma_mode_count  mode;
+	u32 buffer_addr;	/* address of the buffer described */
+	u32 ext_buffer_addr;	/* extended buffer address */
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_channel_control - Channel control Block
+ *
+ * @current_bd_ptr	current buffer descriptor processed
+ * @base_bd_ptr		first element of buffer descriptor array
+ * @unused		padding. The SDMA engine expects an array of 128 byte
+ *			control blocks
+ */
+struct sdma_channel_control {
+	u32 current_bd_ptr;
+	u32 base_bd_ptr;
+	u32 unused[2];
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_state_registers - SDMA context for a channel
+ *
+ * @pc:		program counter
+ * @t:		test bit: status of arithmetic & test instruction
+ * @rpc:	return program counter
+ * @sf:		source fault while loading data
+ * @spc:	loop start program counter
+ * @df:		destination fault while storing data
+ * @epc:	loop end program counter
+ * @lm:		loop mode
+ */
+struct sdma_state_registers {
+	u32 pc     :14;
+	u32 unused1: 1;
+	u32 t      : 1;
+	u32 rpc    :14;
+	u32 unused0: 1;
+	u32 sf     : 1;
+	u32 spc    :14;
+	u32 unused2: 1;
+	u32 df     : 1;
+	u32 epc    :14;
+	u32 lm     : 2;
+} __attribute__ ((packed));
+
+/**
+ * struct sdma_context_data - sdma context specific to a channel
+ *
+ * @channel_state:	channel state bits
+ * @gReg:		general registers
+ * @mda:		burst dma destination address register
+ * @msa:		burst dma source address register
+ * @ms:			burst dma status register
+ * @md:			burst dma data register
+ * @pda:		peripheral dma destination address register
+ * @psa:		peripheral dma source address register
+ * @ps:			peripheral dma status register
+ * @pd:			peripheral dma data register
+ * @ca:			CRC polynomial register
+ * @cs:			CRC accumulator register
+ * @dda:		dedicated core destination address register
+ * @dsa:		dedicated core source address register
+ * @ds:			dedicated core status register
+ * @dd:			dedicated core data register
+ */
+struct sdma_context_data {
+	struct sdma_state_registers  channel_state;
+	u32  gReg[8];
+	u32  mda;
+	u32  msa;
+	u32  ms;
+	u32  md;
+	u32  pda;
+	u32  psa;
+	u32  ps;
+	u32  pd;
+	u32  ca;
+	u32  cs;
+	u32  dda;
+	u32  dsa;
+	u32  ds;
+	u32  dd;
+	u32  scratch0;
+	u32  scratch1;
+	u32  scratch2;
+	u32  scratch3;
+	u32  scratch4;
+	u32  scratch5;
+	u32  scratch6;
+	u32  scratch7;
+} __attribute__ ((packed));
+
+#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
+
+struct sdma_engine;
+
+/**
+ * struct sdma_channel - housekeeping for a SDMA channel
+ *
+ * @sdma		pointer to the SDMA engine for this channel
+ * @channel		the channel number, matches dmaengine chan_id
+ * @direction		transfer type. Needed for setting SDMA script
+ * @peripheral_type	Peripheral type. Needed for setting SDMA script
+ * @event_id0		aka dma request line
+ * @event_id1		for channels that use 2 events
+ * @word_size		peripheral access size
+ * @buf_tail		ID of the buffer that was processed
+ * @done		channel completion
+ * @num_bd		max NUM_BD. number of descriptors currently handling
+ */
+struct sdma_channel {
+	struct sdma_engine		*sdma;
+	unsigned int			channel;
+	enum dma_data_direction		direction;
+	enum sdma_peripheral_type	peripheral_type;
+	unsigned int			event_id0;
+	unsigned int			event_id1;
+	enum dma_slave_buswidth		word_size;
+	unsigned int			buf_tail;
+	struct completion		done;
+	unsigned int			num_bd;
+	struct sdma_buffer_descriptor	*bd;
+	dma_addr_t			bd_phys;
+	unsigned int			pc_from_device, pc_to_device;
+	unsigned long			flags;
+	dma_addr_t			per_address;
+	u32				event_mask0, event_mask1;
+	u32				watermark_level;
+	u32				shp_addr, per_addr;
+	struct dma_chan			chan;
+	spinlock_t			lock;
+	struct dma_async_tx_descriptor	desc;
+	dma_cookie_t			last_completed;
+	enum dma_status			status;
+};
+
+#define IMX_DMA_SG_LOOP		(1 << 0)
+
+#define MAX_DMA_CHANNELS 32
+#define MXC_SDMA_DEFAULT_PRIORITY 1
+#define MXC_SDMA_MIN_PRIORITY 1
+#define MXC_SDMA_MAX_PRIORITY 7
+
+/**
+ * struct sdma_script_start_addrs - SDMA script start pointers
+ *
+ * start addresses of the different functions in the physical
+ * address space of the SDMA engine.
+ */
+struct sdma_script_start_addrs {
+	u32 ap_2_ap_addr;
+	u32 ap_2_bp_addr;
+	u32 ap_2_ap_fixed_addr;
+	u32 bp_2_ap_addr;
+	u32 loopback_on_dsp_side_addr;
+	u32 mcu_interrupt_only_addr;
+	u32 firi_2_per_addr;
+	u32 firi_2_mcu_addr;
+	u32 per_2_firi_addr;
+	u32 mcu_2_firi_addr;
+	u32 uart_2_per_addr;
+	u32 uart_2_mcu_addr;
+	u32 per_2_app_addr;
+	u32 mcu_2_app_addr;
+	u32 per_2_per_addr;
+	u32 uartsh_2_per_addr;
+	u32 uartsh_2_mcu_addr;
+	u32 per_2_shp_addr;
+	u32 mcu_2_shp_addr;
+	u32 ata_2_mcu_addr;
+	u32 mcu_2_ata_addr;
+	u32 app_2_per_addr;
+	u32 app_2_mcu_addr;
+	u32 shp_2_per_addr;
+	u32 shp_2_mcu_addr;
+	u32 mshc_2_mcu_addr;
+	u32 mcu_2_mshc_addr;
+	u32 spdif_2_mcu_addr;
+	u32 mcu_2_spdif_addr;
+	u32 asrc_2_mcu_addr;
+	u32 ext_mem_2_ipu_addr;
+	u32 descrambler_addr;
+	u32 dptc_dvfs_addr;
+	u32 utra_addr;
+	u32 ram_code_start_addr;
+};
+
+#define SDMA_FIRMWARE_MAGIC 0x414d4453
+
+/**
+ * struct sdma_firmware_header - Layout of the firmware image
+ *
+ * @magic		"SDMA"
+ * @version_major	increased whenever layout of struct sdma_script_start_addrs
+ *			changes.
+ * @version_minor	firmware minor version (for binary compatible changes)
+ * @script_addrs_start	offset of struct sdma_script_start_addrs in this image
+ * @num_script_addrs	Number of script addresses in this image
+ * @ram_code_start	offset of SDMA ram image in this firmware image
+ * @ram_code_size	size of SDMA ram image
+ * @script_addrs	Stores the start address of the SDMA scripts
+ *			(in SDMA memory space)
+ */
+struct sdma_firmware_header {
+	u32	magic;
+	u32	version_major;
+	u32	version_minor;
+	u32	script_addrs_start;
+	u32	num_script_addrs;
+	u32	ram_code_start;
+	u32	ram_code_size;
+};
+
+struct sdma_engine {
+	struct device			*dev;
+	struct sdma_channel		channel[MAX_DMA_CHANNELS];
+	struct sdma_channel_control	*channel_control;
+	void __iomem			*regs;
+	unsigned int			version;
+	unsigned int			num_events;
+	struct sdma_context_data	*context;
+	dma_addr_t			context_phys;
+	struct dma_device		dma_device;
+	struct clk			*clk;
+	struct sdma_script_start_addrs	*script_addrs;
+};
+
+#define SDMA_H_CONFIG_DSPDMA	(1 << 12) /* indicates if the DSPDMA is used */
+#define SDMA_H_CONFIG_RTD_PINS	(1 << 11) /* indicates if Real-Time Debug pins are enabled */
+#define SDMA_H_CONFIG_ACR	(1 << 4)  /* indicates if AHB freq /core freq = 2 or 1 */
+#define SDMA_H_CONFIG_CSM	(3)       /* indicates which context switch mode is selected*/
+
+static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
+{
+	u32 chnenbl0 = (sdma->version == 2 ? SDMA_CHNENBL0_V2 : SDMA_CHNENBL0_V1);
+
+	return chnenbl0 + event * 4;
+}
+
+static int sdma_config_ownership(struct sdma_channel *sdmac,
+		bool event_override, bool mcu_override, bool dsp_override)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	u32 evt, mcu, dsp;
+
+	if (event_override && mcu_override && dsp_override)
+		return -EINVAL;
+
+	evt = __raw_readl(sdma->regs + SDMA_H_EVTOVR);
+	mcu = __raw_readl(sdma->regs + SDMA_H_HOSTOVR);
+	dsp = __raw_readl(sdma->regs + SDMA_H_DSPOVR);
+
+	if (dsp_override)
+		dsp &= ~(1 << channel);
+	else
+		dsp |= (1 << channel);
+
+	if (event_override)
+		evt &= ~(1 << channel);
+	else
+		evt |= (1 << channel);
+
+	if (mcu_override)
+		mcu &= ~(1 << channel);
+	else
+		mcu |= (1 << channel);
+
+	__raw_writel(evt, sdma->regs + SDMA_H_EVTOVR);
+	__raw_writel(mcu, sdma->regs + SDMA_H_HOSTOVR);
+	__raw_writel(dsp, sdma->regs + SDMA_H_DSPOVR);
+
+	return 0;
+}
+
+/*
+ * sdma_run_channel - run a channel and wait till it's done
+ */
+static int sdma_run_channel(struct sdma_channel *sdmac)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	int ret;
+
+	init_completion(&sdmac->done);
+
+	__raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+
+	ret = wait_for_completion_timeout(&sdmac->done, HZ);
+
+	return ret ? 0 : -ETIMEDOUT;
+}
+
+static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
+		u32 address)
+{
+	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+	void *buf_virt;
+	dma_addr_t buf_phys;
+	int ret;
+
+	buf_virt = dma_alloc_coherent(NULL,
+			size,
+			&buf_phys, GFP_KERNEL);
+	if (!buf_virt)
+		return -ENOMEM;
+
+	bd0->mode.command = C0_SETPM;
+	bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+	bd0->mode.count = size / 2;
+	bd0->buffer_addr = buf_phys;
+	bd0->ext_buffer_addr = address;
+
+	memcpy(buf_virt, buf, size);
+
+	ret = sdma_run_channel(&sdma->channel[0]);
+
+	dma_free_coherent(NULL, size, buf_virt, buf_phys);
+
+	return ret;
+}
+
+static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	u32 val;
+	u32 chnenbl = chnenbl_ofs(sdma, event);
+
+	val = __raw_readl(sdma->regs + chnenbl);
+	val |= (1 << channel);
+	__raw_writel(val, sdma->regs + chnenbl);
+}
+
+static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	u32 chnenbl = chnenbl_ofs(sdma, event);
+	u32 val;
+
+	val = __raw_readl(sdma->regs + chnenbl);
+	val &= ~(1 << channel);
+	__raw_writel(val, sdma->regs + chnenbl);
+}
+
+static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
+{
+	struct sdma_buffer_descriptor *bd;
+
+	/*
+	 * loop mode. Iterate over descriptors, re-setup them and
+	 * call callback function.
+	 */
+	while (1) {
+		bd = &sdmac->bd[sdmac->buf_tail];
+
+		if (bd->mode.status & BD_DONE)
+			break;
+
+		if (bd->mode.status & BD_RROR)
+			sdmac->status = DMA_ERROR;
+		else
+			sdmac->status = DMA_SUCCESS;
+
+		bd->mode.status |= BD_DONE;
+		sdmac->buf_tail++;
+		sdmac->buf_tail %= sdmac->num_bd;
+
+		if (sdmac->desc.callback)
+			sdmac->desc.callback(sdmac->desc.callback_param);
+	}
+}
+
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
+{
+	struct sdma_buffer_descriptor *bd;
+	int i, error = 0;
+
+	/*
+	 * non loop mode. Iterate over all descriptors, collect
+	 * errors and call callback function
+	 */
+	for (i = 0; i < sdmac->num_bd; i++) {
+		bd = &sdmac->bd[i];
+
+		 if (bd->mode.status & (BD_DONE | BD_RROR))
+			error = -EIO;
+	}
+
+	if (error)
+		sdmac->status = DMA_ERROR;
+	else
+		sdmac->status = DMA_SUCCESS;
+
+	if (sdmac->desc.callback)
+		sdmac->desc.callback(sdmac->desc.callback_param);
+	sdmac->last_completed = sdmac->desc.cookie;
+}
+
+static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
+{
+	complete(&sdmac->done);
+
+	/* not interested in channel 0 interrupts */
+	if (sdmac->channel == 0)
+		return;
+
+	if (sdmac->flags & IMX_DMA_SG_LOOP)
+		sdma_handle_channel_loop(sdmac);
+	else
+		mxc_sdma_handle_channel_normal(sdmac);
+}
+
+static irqreturn_t sdma_int_handler(int irq, void *dev_id)
+{
+	struct sdma_engine *sdma = dev_id;
+	u32 stat;
+
+	stat = __raw_readl(sdma->regs + SDMA_H_INTR);
+	__raw_writel(stat, sdma->regs + SDMA_H_INTR);
+
+	while (stat) {
+		int channel = fls(stat) - 1;
+		struct sdma_channel *sdmac = &sdma->channel[channel];
+
+		mxc_sdma_handle_channel(sdmac);
+
+		stat &= ~(1 << channel);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * sets the pc of SDMA script according to the peripheral type
+ */
+static void sdma_get_pc(struct sdma_channel *sdmac,
+		enum sdma_peripheral_type peripheral_type)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int per_2_emi = 0, emi_2_per = 0;
+	/*
+	 * These are needed once we start to support transfers between
+	 * two peripherals or memory-to-memory transfers
+	 */
+	int per_2_per = 0, emi_2_emi = 0;
+
+	sdmac->pc_from_device = 0;
+	sdmac->pc_to_device = 0;
+
+	switch (peripheral_type) {
+	case IMX_DMATYPE_MEMORY:
+		emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
+		break;
+	case IMX_DMATYPE_DSP:
+		emi_2_per = sdma->script_addrs->bp_2_ap_addr;
+		per_2_emi = sdma->script_addrs->ap_2_bp_addr;
+		break;
+	case IMX_DMATYPE_FIRI:
+		per_2_emi = sdma->script_addrs->firi_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_firi_addr;
+		break;
+	case IMX_DMATYPE_UART:
+		per_2_emi = sdma->script_addrs->uart_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_app_addr;
+		break;
+	case IMX_DMATYPE_UART_SP:
+		per_2_emi = sdma->script_addrs->uartsh_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
+		break;
+	case IMX_DMATYPE_ATA:
+		per_2_emi = sdma->script_addrs->ata_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
+		break;
+	case IMX_DMATYPE_CSPI:
+	case IMX_DMATYPE_EXT:
+	case IMX_DMATYPE_SSI:
+		per_2_emi = sdma->script_addrs->app_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_app_addr;
+		break;
+	case IMX_DMATYPE_SSI_SP:
+	case IMX_DMATYPE_MMC:
+	case IMX_DMATYPE_SDHC:
+	case IMX_DMATYPE_CSPI_SP:
+	case IMX_DMATYPE_ESAI:
+	case IMX_DMATYPE_MSHC_SP:
+		per_2_emi = sdma->script_addrs->shp_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_shp_addr;
+		break;
+	case IMX_DMATYPE_ASRC:
+		per_2_emi = sdma->script_addrs->asrc_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->asrc_2_mcu_addr;
+		per_2_per = sdma->script_addrs->per_2_per_addr;
+		break;
+	case IMX_DMATYPE_MSHC:
+		per_2_emi = sdma->script_addrs->mshc_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_mshc_addr;
+		break;
+	case IMX_DMATYPE_CCM:
+		per_2_emi = sdma->script_addrs->dptc_dvfs_addr;
+		break;
+	case IMX_DMATYPE_SPDIF:
+		per_2_emi = sdma->script_addrs->spdif_2_mcu_addr;
+		emi_2_per = sdma->script_addrs->mcu_2_spdif_addr;
+		break;
+	case IMX_DMATYPE_IPU_MEMORY:
+		emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
+		break;
+	default:
+		break;
+	}
+
+	sdmac->pc_from_device = per_2_emi;
+	sdmac->pc_to_device = emi_2_per;
+}
+
+static int sdma_load_context(struct sdma_channel *sdmac)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	int load_address;
+	struct sdma_context_data *context = sdma->context;
+	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+	int ret;
+
+	if (sdmac->direction == DMA_FROM_DEVICE) {
+		load_address = sdmac->pc_from_device;
+	} else {
+		load_address = sdmac->pc_to_device;
+	}
+
+	if (load_address < 0)
+		return load_address;
+
+	dev_dbg(sdma->dev, "load_address = %d\n", load_address);
+	dev_dbg(sdma->dev, "wml = 0x%08x\n", sdmac->watermark_level);
+	dev_dbg(sdma->dev, "shp_addr = 0x%08x\n", sdmac->shp_addr);
+	dev_dbg(sdma->dev, "per_addr = 0x%08x\n", sdmac->per_addr);
+	dev_dbg(sdma->dev, "event_mask0 = 0x%08x\n", sdmac->event_mask0);
+	dev_dbg(sdma->dev, "event_mask1 = 0x%08x\n", sdmac->event_mask1);
+
+	memset(context, 0, sizeof(*context));
+	context->channel_state.pc = load_address;
+
+	/* Send by context the event mask,base address for peripheral
+	 * and watermark level
+	 */
+	context->gReg[0] = sdmac->event_mask1;
+	context->gReg[1] = sdmac->event_mask0;
+	context->gReg[2] = sdmac->per_addr;
+	context->gReg[6] = sdmac->shp_addr;
+	context->gReg[7] = sdmac->watermark_level;
+
+	bd0->mode.command = C0_SETDM;
+	bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+	bd0->mode.count = sizeof(*context) / 4;
+	bd0->buffer_addr = sdma->context_phys;
+	bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
+
+	ret = sdma_run_channel(&sdma->channel[0]);
+
+	return ret;
+}
+
+static void sdma_disable_channel(struct sdma_channel *sdmac)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+
+	__raw_writel(1 << channel, sdma->regs + SDMA_H_STATSTOP);
+	sdmac->status = DMA_ERROR;
+}
+
+static int sdma_config_channel(struct sdma_channel *sdmac)
+{
+	int ret;
+
+	sdma_disable_channel(sdmac);
+
+	sdmac->event_mask0 = 0;
+	sdmac->event_mask1 = 0;
+	sdmac->shp_addr = 0;
+	sdmac->per_addr = 0;
+
+	if (sdmac->event_id0) {
+		if (sdmac->event_id0 > 32)
+			return -EINVAL;
+		sdma_event_enable(sdmac, sdmac->event_id0);
+	}
+
+	switch (sdmac->peripheral_type) {
+	case IMX_DMATYPE_DSP:
+		sdma_config_ownership(sdmac, false, true, true);
+		break;
+	case IMX_DMATYPE_MEMORY:
+		sdma_config_ownership(sdmac, false, true, false);
+		break;
+	default:
+		sdma_config_ownership(sdmac, true, true, false);
+		break;
+	}
+
+	sdma_get_pc(sdmac, sdmac->peripheral_type);
+
+	if ((sdmac->peripheral_type != IMX_DMATYPE_MEMORY) &&
+			(sdmac->peripheral_type != IMX_DMATYPE_DSP)) {
+		/* Handle multiple event channels differently */
+		if (sdmac->event_id1) {
+			sdmac->event_mask1 = 1 << (sdmac->event_id1 % 32);
+			if (sdmac->event_id1 > 31)
+				sdmac->watermark_level |= 1 << 31;
+			sdmac->event_mask0 = 1 << (sdmac->event_id0 % 32);
+			if (sdmac->event_id0 > 31)
+				sdmac->watermark_level |= 1 << 30;
+		} else {
+			sdmac->event_mask0 = 1 << sdmac->event_id0;
+			sdmac->event_mask1 = 1 << (sdmac->event_id0 - 32);
+		}
+		/* Watermark Level */
+		sdmac->watermark_level |= sdmac->watermark_level;
+		/* Address */
+		sdmac->shp_addr = sdmac->per_address;
+	} else {
+		sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
+	}
+
+	ret = sdma_load_context(sdmac);
+
+	return ret;
+}
+
+static int sdma_set_channel_priority(struct sdma_channel *sdmac,
+		unsigned int priority)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+
+	if (priority < MXC_SDMA_MIN_PRIORITY
+	    || priority > MXC_SDMA_MAX_PRIORITY) {
+		return -EINVAL;
+	}
+
+	__raw_writel(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
+
+	return 0;
+}
+
+static int sdma_request_channel(struct sdma_channel *sdmac)
+{
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+	int ret = -EBUSY;
+
+	sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL);
+	if (!sdmac->bd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(sdmac->bd, 0, PAGE_SIZE);
+
+	sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
+	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+	clk_enable(sdma->clk);
+
+	sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
+
+	init_completion(&sdmac->done);
+
+	sdmac->buf_tail = 0;
+
+	return 0;
+out:
+
+	return ret;
+}
+
+static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
+{
+	__raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+}
+
+static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdma)
+{
+	dma_cookie_t cookie = sdma->chan.cookie;
+
+	if (++cookie < 0)
+		cookie = 1;
+
+	sdma->chan.cookie = cookie;
+	sdma->desc.cookie = cookie;
+
+	return cookie;
+}
+
+static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct sdma_channel, chan);
+}
+
+static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+	dma_cookie_t cookie;
+
+	spin_lock_irq(&sdmac->lock);
+
+	cookie = sdma_assign_cookie(sdmac);
+
+	sdma_enable_channel(sdma, tx->chan->chan_id);
+
+	spin_unlock_irq(&sdmac->lock);
+
+	return cookie;
+}
+
+static int sdma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct imx_dma_data *data = chan->private;
+	int prio, ret;
+
+	/* No need to execute this for internal channel 0 */
+	if (chan->chan_id == 0)
+		return 0;
+
+	if (!data)
+		return -EINVAL;
+
+	switch (data->priority) {
+	case DMA_PRIO_HIGH:
+		prio = 3;
+		break;
+	case DMA_PRIO_MEDIUM:
+		prio = 2;
+		break;
+	case DMA_PRIO_LOW:
+	default:
+		prio = 1;
+		break;
+	}
+
+	sdmac->peripheral_type = data->peripheral_type;
+	sdmac->event_id0 = data->dma_request;
+	ret = sdma_set_channel_priority(sdmac, prio);
+	if (ret)
+		return ret;
+
+	ret = sdma_request_channel(sdmac);
+	if (ret)
+		return ret;
+
+	dma_async_tx_descriptor_init(&sdmac->desc, chan);
+	sdmac->desc.tx_submit = sdma_tx_submit;
+	/* txd.flags will be overwritten in prep funcs */
+	sdmac->desc.flags = DMA_CTRL_ACK;
+
+	return 0;
+}
+
+static void sdma_free_chan_resources(struct dma_chan *chan)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+
+	sdma_disable_channel(sdmac);
+
+	if (sdmac->event_id0)
+		sdma_event_disable(sdmac, sdmac->event_id0);
+	if (sdmac->event_id1)
+		sdma_event_disable(sdmac, sdmac->event_id1);
+
+	sdmac->event_id0 = 0;
+	sdmac->event_id1 = 0;
+
+	sdma_set_channel_priority(sdmac, 0);
+
+	dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
+
+	clk_disable(sdma->clk);
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_data_direction direction,
+		unsigned long flags)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+	int ret, i, count;
+	int channel = chan->chan_id;
+	struct scatterlist *sg;
+
+	if (sdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+	sdmac->status = DMA_IN_PROGRESS;
+
+	sdmac->flags = 0;
+
+	dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
+			sg_len, channel);
+
+	sdmac->direction = direction;
+	ret = sdma_load_context(sdmac);
+	if (ret)
+		goto err_out;
+
+	if (sg_len > NUM_BD) {
+		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
+				channel, sg_len, NUM_BD);
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	for_each_sg(sgl, sg, sg_len, i) {
+		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+		int param;
+
+		bd->buffer_addr = sg->dma_address;
+
+		count = sg->length;
+
+		if (count > 0xffff) {
+			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
+					channel, count, 0xffff);
+			ret = -EINVAL;
+			goto err_out;
+		}
+
+		bd->mode.count = count;
+
+		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
+			ret =  -EINVAL;
+			goto err_out;
+		}
+		if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+			bd->mode.command = 0;
+		else
+			bd->mode.command = sdmac->word_size;
+
+		param = BD_DONE | BD_EXTD | BD_CONT;
+
+		if (sdmac->flags & IMX_DMA_SG_LOOP) {
+			param |= BD_INTR;
+			if (i + 1 == sg_len)
+				param |= BD_WRAP;
+		}
+
+		if (i + 1 == sg_len)
+			param |= BD_INTR;
+
+		dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
+				i, count, sg->dma_address,
+				param & BD_WRAP ? "wrap" : "",
+				param & BD_INTR ? " intr" : "");
+
+		bd->mode.status = param;
+	}
+
+	sdmac->num_bd = sg_len;
+	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+	return &sdmac->desc;
+err_out:
+	return NULL;
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_engine *sdma = sdmac->sdma;
+	int num_periods = buf_len / period_len;
+	int channel = chan->chan_id;
+	int ret, i = 0, buf = 0;
+
+	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
+
+	if (sdmac->status == DMA_IN_PROGRESS)
+		return NULL;
+
+	sdmac->status = DMA_IN_PROGRESS;
+
+	sdmac->flags |= IMX_DMA_SG_LOOP;
+	sdmac->direction = direction;
+	ret = sdma_load_context(sdmac);
+	if (ret)
+		goto err_out;
+
+	if (num_periods > NUM_BD) {
+		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
+				channel, num_periods, NUM_BD);
+		goto err_out;
+	}
+
+	if (period_len > 0xffff) {
+		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n",
+				channel, period_len, 0xffff);
+		goto err_out;
+	}
+
+	while (buf < buf_len) {
+		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+		int param;
+
+		bd->buffer_addr = dma_addr;
+
+		bd->mode.count = period_len;
+
+		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
+			goto err_out;
+		if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
+			bd->mode.command = 0;
+		else
+			bd->mode.command = sdmac->word_size;
+
+		param = BD_DONE | BD_EXTD | BD_CONT | BD_INTR;
+		if (i + 1 == num_periods)
+			param |= BD_WRAP;
+
+		dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%08x %s%s\n",
+				i, period_len, dma_addr,
+				param & BD_WRAP ? "wrap" : "",
+				param & BD_INTR ? " intr" : "");
+
+		bd->mode.status = param;
+
+		dma_addr += period_len;
+		buf += period_len;
+
+		i++;
+	}
+
+	sdmac->num_bd = num_periods;
+	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+
+	return &sdmac->desc;
+err_out:
+	sdmac->status = DMA_ERROR;
+	return NULL;
+}
+
+static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct dma_slave_config *dmaengine_cfg = (void *)arg;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		sdma_disable_channel(sdmac);
+		return 0;
+	case DMA_SLAVE_CONFIG:
+		if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+			sdmac->per_address = dmaengine_cfg->src_addr;
+			sdmac->watermark_level = dmaengine_cfg->src_maxburst;
+			sdmac->word_size = dmaengine_cfg->src_addr_width;
+		} else {
+			sdmac->per_address = dmaengine_cfg->dst_addr;
+			sdmac->watermark_level = dmaengine_cfg->dst_maxburst;
+			sdmac->word_size = dmaengine_cfg->dst_addr_width;
+		}
+		return sdma_config_channel(sdmac);
+	default:
+		return -ENOSYS;
+	}
+
+	return -EINVAL;
+}
+
+static enum dma_status sdma_tx_status(struct dma_chan *chan,
+					    dma_cookie_t cookie,
+					    struct dma_tx_state *txstate)
+{
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	dma_cookie_t last_used;
+	enum dma_status ret;
+
+	last_used = chan->cookie;
+
+	ret = dma_async_is_complete(cookie, sdmac->last_completed, last_used);
+	dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
+
+	return ret;
+}
+
+static void sdma_issue_pending(struct dma_chan *chan)
+{
+	/*
+	 * Nothing to do. We only have a single descriptor
+	 */
+}
+
+static int __init sdma_init(struct sdma_engine *sdma,
+		void *ram_code, int ram_code_size)
+{
+	int i, ret;
+	dma_addr_t ccb_phys;
+
+	switch (sdma->version) {
+	case 1:
+		sdma->num_events = 32;
+		break;
+	case 2:
+		sdma->num_events = 48;
+		break;
+	default:
+		dev_err(sdma->dev, "Unknown version %d. aborting\n", sdma->version);
+		return -ENODEV;
+	}
+
+	clk_enable(sdma->clk);
+
+	/* Be sure SDMA has not started yet */
+	__raw_writel(0, sdma->regs + SDMA_H_C0PTR);
+
+	sdma->channel_control = dma_alloc_coherent(NULL,
+			MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
+			sizeof(struct sdma_context_data),
+			&ccb_phys, GFP_KERNEL);
+
+	if (!sdma->channel_control) {
+		ret = -ENOMEM;
+		goto err_dma_alloc;
+	}
+
+	sdma->context = (void *)sdma->channel_control +
+		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
+	sdma->context_phys = ccb_phys +
+		MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control);
+
+	/* Zero-out the CCB structures array just allocated */
+	memset(sdma->channel_control, 0,
+			MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control));
+
+	/* disable all channels */
+	for (i = 0; i < sdma->num_events; i++)
+		__raw_writel(0, sdma->regs + chnenbl_ofs(sdma, i));
+
+	/* All channels have priority 0 */
+	for (i = 0; i < MAX_DMA_CHANNELS; i++)
+		__raw_writel(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+
+	ret = sdma_request_channel(&sdma->channel[0]);
+	if (ret)
+		goto err_dma_alloc;
+
+	sdma_config_ownership(&sdma->channel[0], false, true, false);
+
+	/* Set Command Channel (Channel Zero) */
+	__raw_writel(0x4050, sdma->regs + SDMA_CHN0ADDR);
+
+	/* Set bits of CONFIG register but with static context switching */
+	/* FIXME: Check whether to set ACR bit depending on clock ratios */
+	__raw_writel(0, sdma->regs + SDMA_H_CONFIG);
+
+	__raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
+
+	/* download the RAM image for SDMA */
+	sdma_load_script(sdma, ram_code,
+			ram_code_size,
+			sdma->script_addrs->ram_code_start_addr);
+
+	/* Set bits of CONFIG register with given context switching mode */
+	__raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+
+	/* Initializes channel's priorities */
+	sdma_set_channel_priority(&sdma->channel[0], 7);
+
+	clk_disable(sdma->clk);
+
+	return 0;
+
+err_dma_alloc:
+	clk_disable(sdma->clk);
+	dev_err(sdma->dev, "initialisation failed with %d\n", ret);
+	return ret;
+}
+
+static int __init sdma_probe(struct platform_device *pdev)
+{
+	int ret;
+	const struct firmware *fw;
+	const struct sdma_firmware_header *header;
+	const struct sdma_script_start_addrs *addr;
+	int irq;
+	unsigned short *ram_code;
+	struct resource *iores;
+	struct sdma_platform_data *pdata = pdev->dev.platform_data;
+	char *fwname;
+	int i;
+	dma_cap_mask_t mask;
+	struct sdma_engine *sdma;
+
+	sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
+	if (!sdma)
+		return -ENOMEM;
+
+	sdma->dev = &pdev->dev;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	if (!iores || irq < 0 || !pdata) {
+		ret = -EINVAL;
+		goto err_irq;
+	}
+
+	if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) {
+		ret = -EBUSY;
+		goto err_request_region;
+	}
+
+	sdma->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(sdma->clk)) {
+		ret = PTR_ERR(sdma->clk);
+		goto err_clk;
+	}
+
+	sdma->regs = ioremap(iores->start, resource_size(iores));
+	if (!sdma->regs) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma);
+	if (ret)
+		goto err_request_irq;
+
+	fwname = kasprintf(GFP_KERNEL, "/*(DEBLOBBED)*/",
+			pdata->cpu_name, pdata->to_version);
+	if (!fwname) {
+		ret = -ENOMEM;
+		goto err_cputype;
+	}
+
+	ret = reject_firmware(&fw, fwname, &pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request firmware \"%s\" failed with %d\n",
+				fwname, ret);
+		kfree(fwname);
+		goto err_cputype;
+	}
+	kfree(fwname);
+
+	if (fw->size < sizeof(*header))
+		goto err_firmware;
+
+	header = (struct sdma_firmware_header *)fw->data;
+
+	if (header->magic != SDMA_FIRMWARE_MAGIC)
+		goto err_firmware;
+	if (header->ram_code_start + header->ram_code_size > fw->size)
+		goto err_firmware;
+
+	addr = (void *)header + header->script_addrs_start;
+	ram_code = (void *)header + header->ram_code_start;
+	sdma->script_addrs = kmalloc(sizeof(*addr), GFP_KERNEL);
+	if (!sdma->script_addrs)
+		goto err_firmware;
+	memcpy(sdma->script_addrs, addr, sizeof(*addr));
+
+	sdma->version = pdata->sdma_version;
+
+	INIT_LIST_HEAD(&sdma->dma_device.channels);
+	/* Initialize channel parameters */
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		struct sdma_channel *sdmac = &sdma->channel[i];
+
+		sdmac->sdma = sdma;
+		spin_lock_init(&sdmac->lock);
+
+		dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
+		dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+
+		sdmac->chan.device = &sdma->dma_device;
+		sdmac->chan.chan_id = i;
+		sdmac->channel = i;
+
+		/* Add the channel to the DMAC list */
+		list_add_tail(&sdmac->chan.device_node, &sdma->dma_device.channels);
+	}
+
+	ret = sdma_init(sdma, ram_code, header->ram_code_size);
+	if (ret)
+		goto err_init;
+
+	sdma->dma_device.dev = &pdev->dev;
+
+	sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
+	sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources;
+	sdma->dma_device.device_tx_status = sdma_tx_status;
+	sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
+	sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
+	sdma->dma_device.device_control = sdma_control;
+	sdma->dma_device.device_issue_pending = sdma_issue_pending;
+
+	ret = dma_async_device_register(&sdma->dma_device);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to register\n");
+		goto err_init;
+	}
+
+	dev_info(&pdev->dev, "initialized (firmware %d.%d)\n",
+			header->version_major,
+			header->version_minor);
+
+	/* request channel 0. This is an internal control channel
+	 * to the SDMA engine and not available to clients.
+	 */
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_request_channel(mask, NULL, NULL);
+
+	release_firmware(fw);
+
+	return 0;
+
+err_init:
+	kfree(sdma->script_addrs);
+err_firmware:
+	release_firmware(fw);
+err_cputype:
+	free_irq(irq, sdma);
+err_request_irq:
+	iounmap(sdma->regs);
+err_ioremap:
+	clk_put(sdma->clk);
+err_clk:
+	release_mem_region(iores->start, resource_size(iores));
+err_request_region:
+err_irq:
+	kfree(sdma);
+	return 0;
+}
+
+static int __exit sdma_remove(struct platform_device *pdev)
+{
+	return -EBUSY;
+}
+
+static struct platform_driver sdma_driver = {
+	.driver		= {
+		.name	= "imx-sdma",
+	},
+	.remove		= __exit_p(sdma_remove),
+};
+
+static int __init sdma_module_init(void)
+{
+	return platform_driver_probe(&sdma_driver, sdma_probe);
+}
+module_init(sdma_module_init);
+
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX SDMA driver");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/dma/intel_mid_dma.c linux-libre-2.6.37-gnu/drivers/dma/intel_mid_dma.c
--- linux-libre-2.6.36-gnu/drivers/dma/intel_mid_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/intel_mid_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
  */
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
 #include <linux/intel_mid_dma.h>
 
 #define MAX_CHAN	4 /*max ch across controllers*/
@@ -91,13 +92,13 @@
 	int byte_width = 0, block_ts = 0;
 
 	switch (tx_width) {
-	case LNW_DMA_WIDTH_8BIT:
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
 		byte_width = 1;
 		break;
-	case LNW_DMA_WIDTH_16BIT:
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
 		byte_width = 2;
 		break;
-	case LNW_DMA_WIDTH_32BIT:
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
 	default:
 		byte_width = 4;
 		break;
@@ -247,16 +248,17 @@
 	struct middma_device *mid = to_middma_device(midc->chan.device);
 
 	/*  channel is idle */
-	if (midc->in_use && test_ch_en(midc->dma_base, midc->ch_id)) {
+	if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
 		/*error*/
 		pr_err("ERR_MDMA: channel is busy in start\n");
 		/* The tasklet will hopefully advance the queue... */
 		return;
 	}
-
+	midc->busy = true;
 	/*write registers and en*/
 	iowrite32(first->sar, midc->ch_regs + SAR);
 	iowrite32(first->dar, midc->ch_regs + DAR);
+	iowrite32(first->lli_phys, midc->ch_regs + LLP);
 	iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
 	iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
 	iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
@@ -264,9 +266,9 @@
 	pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
 		(int)first->sar, (int)first->dar, first->cfg_hi,
 		first->cfg_lo, first->ctl_hi, first->ctl_lo);
+	first->status = DMA_IN_PROGRESS;
 
 	iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
-	first->status = DMA_IN_PROGRESS;
 }
 
 /**
@@ -283,20 +285,36 @@
 {
 	struct dma_async_tx_descriptor	*txd = &desc->txd;
 	dma_async_tx_callback callback_txd = NULL;
+	struct intel_mid_dma_lli	*llitem;
 	void *param_txd = NULL;
 
 	midc->completed = txd->cookie;
 	callback_txd = txd->callback;
 	param_txd = txd->callback_param;
 
-	list_move(&desc->desc_node, &midc->free_list);
-
+	if (desc->lli != NULL) {
+		/*clear the DONE bit of completed LLI in memory*/
+		llitem = desc->lli + desc->current_lli;
+		llitem->ctl_hi &= CLEAR_DONE;
+		if (desc->current_lli < desc->lli_length-1)
+			(desc->current_lli)++;
+		else
+			desc->current_lli = 0;
+	}
 	spin_unlock_bh(&midc->lock);
 	if (callback_txd) {
 		pr_debug("MDMA: TXD callback set ... calling\n");
 		callback_txd(param_txd);
-		spin_lock_bh(&midc->lock);
-		return;
+	}
+	if (midc->raw_tfr) {
+		desc->status = DMA_SUCCESS;
+		if (desc->lli != NULL) {
+			pci_pool_free(desc->lli_pool, desc->lli,
+						desc->lli_phys);
+			pci_pool_destroy(desc->lli_pool);
+		}
+		list_move(&desc->desc_node, &midc->free_list);
+		midc->busy = false;
 	}
 	spin_lock_bh(&midc->lock);
 
@@ -317,14 +335,89 @@
 
 	/*tx is complete*/
 	list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-		if (desc->status == DMA_IN_PROGRESS)  {
-			desc->status = DMA_SUCCESS;
+		if (desc->status == DMA_IN_PROGRESS)
 			midc_descriptor_complete(midc, desc);
-		}
 	}
 	return;
-}
+	}
+/**
+ * midc_lli_fill_sg -		Helper function to convert
+ *				SG list to Linked List Items.
+ *@midc: Channel
+ *@desc: DMA descriptor
+ *@sglist: Pointer to SG list
+ *@sglen: SG list length
+ *@flags: DMA transaction flags
+ *
+ * Walk through the SG list and convert the SG list into Linked
+ * List Items (LLI).
+ */
+static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+				struct intel_mid_dma_desc *desc,
+				struct scatterlist *sglist,
+				unsigned int sglen,
+				unsigned int flags)
+{
+	struct intel_mid_dma_slave *mids;
+	struct scatterlist  *sg;
+	dma_addr_t lli_next, sg_phy_addr;
+	struct intel_mid_dma_lli *lli_bloc_desc;
+	union intel_mid_dma_ctl_lo ctl_lo;
+	union intel_mid_dma_ctl_hi ctl_hi;
+	int i;
+
+	pr_debug("MDMA: Entered midc_lli_fill_sg\n");
+	mids = midc->mid_slave;
+
+	lli_bloc_desc = desc->lli;
+	lli_next = desc->lli_phys;
+
+	ctl_lo.ctl_lo = desc->ctl_lo;
+	ctl_hi.ctl_hi = desc->ctl_hi;
+	for_each_sg(sglist, sg, sglen, i) {
+		/*Populate CTL_LOW and LLI values*/
+		if (i != sglen - 1) {
+			lli_next = lli_next +
+				sizeof(struct intel_mid_dma_lli);
+		} else {
+		/*Check for circular list, otherwise terminate LLI to ZERO*/
+			if (flags & DMA_PREP_CIRCULAR_LIST) {
+				pr_debug("MDMA: LLI is configured in circular mode\n");
+				lli_next = desc->lli_phys;
+			} else {
+				lli_next = 0;
+				ctl_lo.ctlx.llp_dst_en = 0;
+				ctl_lo.ctlx.llp_src_en = 0;
+			}
+		}
+		/*Populate CTL_HI values*/
+		ctl_hi.ctlx.block_ts = get_block_ts(sg->length,
+							desc->width,
+							midc->dma->block_size);
+		/*Populate SAR and DAR values*/
+		sg_phy_addr = sg_phys(sg);
+		if (desc->dirn ==  DMA_TO_DEVICE) {
+			lli_bloc_desc->sar  = sg_phy_addr;
+			lli_bloc_desc->dar  = mids->dma_slave.dst_addr;
+		} else if (desc->dirn ==  DMA_FROM_DEVICE) {
+			lli_bloc_desc->sar  = mids->dma_slave.src_addr;
+			lli_bloc_desc->dar  = sg_phy_addr;
+		}
+		/*Copy values into block descriptor in system memroy*/
+		lli_bloc_desc->llp = lli_next;
+		lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
+		lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
 
+		lli_bloc_desc++;
+	}
+	/*Copy very first LLI values to descriptor*/
+	desc->ctl_lo = desc->lli->ctl_lo;
+	desc->ctl_hi = desc->lli->ctl_hi;
+	desc->sar = desc->lli->sar;
+	desc->dar = desc->lli->dar;
+
+	return 0;
+}
 /*****************************************************************************
 DMA engine callback Functions*/
 /**
@@ -349,12 +442,12 @@
 	desc->txd.cookie = cookie;
 
 
-	if (list_empty(&midc->active_list)) {
-		midc_dostart(midc, desc);
+	if (list_empty(&midc->active_list))
 		list_add_tail(&desc->desc_node, &midc->active_list);
-	} else {
+	else
 		list_add_tail(&desc->desc_node, &midc->queue);
-	}
+
+	midc_dostart(midc, desc);
 	spin_unlock_bh(&midc->lock);
 
 	return cookie;
@@ -414,6 +507,23 @@
 	return ret;
 }
 
+static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
+{
+	struct intel_mid_dma_chan	*midc = to_intel_mid_dma_chan(chan);
+	struct dma_slave_config  *slave = (struct dma_slave_config *)arg;
+	struct intel_mid_dma_slave *mid_slave;
+
+	BUG_ON(!midc);
+	BUG_ON(!slave);
+	pr_debug("MDMA: slave control called\n");
+
+	mid_slave = to_intel_mid_dma_slave(slave);
+
+	BUG_ON(!mid_slave);
+
+	midc->mid_slave = mid_slave;
+	return 0;
+}
 /**
  * intel_mid_dma_device_control -	DMA device control
  * @chan: chan for DMA control
@@ -428,49 +538,41 @@
 	struct intel_mid_dma_chan	*midc = to_intel_mid_dma_chan(chan);
 	struct middma_device	*mid = to_middma_device(chan->device);
 	struct intel_mid_dma_desc	*desc, *_desc;
-	LIST_HEAD(list);
+	union intel_mid_dma_cfg_lo cfg_lo;
+
+	if (cmd == DMA_SLAVE_CONFIG)
+		return dma_slave_control(chan, arg);
 
 	if (cmd != DMA_TERMINATE_ALL)
 		return -ENXIO;
 
 	spin_lock_bh(&midc->lock);
-	if (midc->in_use == false) {
+	if (midc->busy == false) {
 		spin_unlock_bh(&midc->lock);
 		return 0;
 	}
-	list_splice_init(&midc->free_list, &list);
-	midc->descs_allocated = 0;
-	midc->slave = NULL;
-
+	/*Suspend and disable the channel*/
+	cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
+	cfg_lo.cfgx.ch_susp = 1;
+	iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
+	iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+	midc->busy = false;
 	/* Disable interrupts */
 	disable_dma_interrupt(midc);
+	midc->descs_allocated = 0;
 
 	spin_unlock_bh(&midc->lock);
-	list_for_each_entry_safe(desc, _desc, &list, desc_node) {
-		pr_debug("MDMA: freeing descriptor %p\n", desc);
-		pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
+	list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+		if (desc->lli != NULL) {
+			pci_pool_free(desc->lli_pool, desc->lli,
+						desc->lli_phys);
+			pci_pool_destroy(desc->lli_pool);
+		}
+		list_move(&desc->desc_node, &midc->free_list);
 	}
 	return 0;
 }
 
-/**
- * intel_mid_dma_prep_slave_sg -	Prep slave sg txn
- * @chan: chan for DMA transfer
- * @sgl: scatter gather list
- * @sg_len: length of sg txn
- * @direction: DMA transfer dirtn
- * @flags: DMA flags
- *
- * Do DMA sg txn: NOT supported now
- */
-static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
-			struct dma_chan *chan, struct scatterlist *sgl,
-			unsigned int sg_len, enum dma_data_direction direction,
-			unsigned long flags)
-{
-	/*not supported now*/
-	return NULL;
-}
 
 /**
  * intel_mid_dma_prep_memcpy -	Prep memcpy txn
@@ -495,23 +597,24 @@
 	union intel_mid_dma_ctl_hi ctl_hi;
 	union intel_mid_dma_cfg_lo cfg_lo;
 	union intel_mid_dma_cfg_hi cfg_hi;
-	enum intel_mid_dma_width width = 0;
+	enum dma_slave_buswidth width;
 
 	pr_debug("MDMA: Prep for memcpy\n");
-	WARN_ON(!chan);
+	BUG_ON(!chan);
 	if (!len)
 		return NULL;
 
-	mids = chan->private;
-	WARN_ON(!mids);
-
 	midc = to_intel_mid_dma_chan(chan);
-	WARN_ON(!midc);
+	BUG_ON(!midc);
+
+	mids = midc->mid_slave;
+	BUG_ON(!mids);
 
 	pr_debug("MDMA:called for DMA %x CH %d Length %zu\n",
 				midc->dma->pci_id, midc->ch_id, len);
 	pr_debug("MDMA:Cfg passed Mode %x, Dirn %x, HS %x, Width %x\n",
-		mids->cfg_mode, mids->dirn, mids->hs_mode, mids->src_width);
+			mids->cfg_mode, mids->dma_slave.direction,
+			mids->hs_mode, mids->dma_slave.src_addr_width);
 
 	/*calculate CFG_LO*/
 	if (mids->hs_mode == LNW_DMA_SW_HS) {
@@ -530,13 +633,13 @@
 		if (midc->dma->pimr_mask) {
 			cfg_hi.cfgx.protctl = 0x0; /*default value*/
 			cfg_hi.cfgx.fifo_mode = 1;
-			if (mids->dirn == DMA_TO_DEVICE) {
+			if (mids->dma_slave.direction == DMA_TO_DEVICE) {
 				cfg_hi.cfgx.src_per = 0;
 				if (mids->device_instance == 0)
 					cfg_hi.cfgx.dst_per = 3;
 				if (mids->device_instance == 1)
 					cfg_hi.cfgx.dst_per = 1;
-			} else if (mids->dirn == DMA_FROM_DEVICE) {
+			} else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
 				if (mids->device_instance == 0)
 					cfg_hi.cfgx.src_per = 2;
 				if (mids->device_instance == 1)
@@ -552,7 +655,8 @@
 
 	/*calculate CTL_HI*/
 	ctl_hi.ctlx.reser = 0;
-	width = mids->src_width;
+	ctl_hi.ctlx.done  = 0;
+	width = mids->dma_slave.src_addr_width;
 
 	ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
 	pr_debug("MDMA:calc len %d for block size %d\n",
@@ -560,21 +664,21 @@
 	/*calculate CTL_LO*/
 	ctl_lo.ctl_lo = 0;
 	ctl_lo.ctlx.int_en = 1;
-	ctl_lo.ctlx.dst_tr_width = mids->dst_width;
-	ctl_lo.ctlx.src_tr_width = mids->src_width;
-	ctl_lo.ctlx.dst_msize = mids->src_msize;
-	ctl_lo.ctlx.src_msize = mids->dst_msize;
+	ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width;
+	ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width;
+	ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst;
+	ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst;
 
 	if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
 		ctl_lo.ctlx.tt_fc = 0;
 		ctl_lo.ctlx.sinc = 0;
 		ctl_lo.ctlx.dinc = 0;
 	} else {
-		if (mids->dirn == DMA_TO_DEVICE) {
+		if (mids->dma_slave.direction == DMA_TO_DEVICE) {
 			ctl_lo.ctlx.sinc = 0;
 			ctl_lo.ctlx.dinc = 2;
 			ctl_lo.ctlx.tt_fc = 1;
-		} else if (mids->dirn == DMA_FROM_DEVICE) {
+		} else if (mids->dma_slave.direction == DMA_FROM_DEVICE) {
 			ctl_lo.ctlx.sinc = 2;
 			ctl_lo.ctlx.dinc = 0;
 			ctl_lo.ctlx.tt_fc = 2;
@@ -597,7 +701,10 @@
 	desc->ctl_lo = ctl_lo.ctl_lo;
 	desc->ctl_hi = ctl_hi.ctl_hi;
 	desc->width = width;
-	desc->dirn = mids->dirn;
+	desc->dirn = mids->dma_slave.direction;
+	desc->lli_phys = 0;
+	desc->lli = NULL;
+	desc->lli_pool = NULL;
 	return &desc->txd;
 
 err_desc_get:
@@ -605,6 +712,85 @@
 	midc_desc_put(midc, desc);
 	return NULL;
 }
+/**
+ * intel_mid_dma_prep_slave_sg -	Prep slave sg txn
+ * @chan: chan for DMA transfer
+ * @sgl: scatter gather list
+ * @sg_len: length of sg txn
+ * @direction: DMA transfer dirtn
+ * @flags: DMA flags
+ *
+ * Prepares LLI based periphral transfer
+ */
+static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
+			struct dma_chan *chan, struct scatterlist *sgl,
+			unsigned int sg_len, enum dma_data_direction direction,
+			unsigned long flags)
+{
+	struct intel_mid_dma_chan *midc = NULL;
+	struct intel_mid_dma_slave *mids = NULL;
+	struct intel_mid_dma_desc *desc = NULL;
+	struct dma_async_tx_descriptor *txd = NULL;
+	union intel_mid_dma_ctl_lo ctl_lo;
+
+	pr_debug("MDMA: Prep for slave SG\n");
+
+	if (!sg_len) {
+		pr_err("MDMA: Invalid SG length\n");
+		return NULL;
+	}
+	midc = to_intel_mid_dma_chan(chan);
+	BUG_ON(!midc);
+
+	mids = midc->mid_slave;
+	BUG_ON(!mids);
+
+	if (!midc->dma->pimr_mask) {
+		pr_debug("MDMA: SG list is not supported by this controller\n");
+		return  NULL;
+	}
+
+	pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n",
+			sg_len, direction, flags);
+
+	txd = intel_mid_dma_prep_memcpy(chan, 0, 0, sgl->length, flags);
+	if (NULL == txd) {
+		pr_err("MDMA: Prep memcpy failed\n");
+		return NULL;
+	}
+	desc = to_intel_mid_dma_desc(txd);
+	desc->dirn = direction;
+	ctl_lo.ctl_lo = desc->ctl_lo;
+	ctl_lo.ctlx.llp_dst_en = 1;
+	ctl_lo.ctlx.llp_src_en = 1;
+	desc->ctl_lo = ctl_lo.ctl_lo;
+	desc->lli_length = sg_len;
+	desc->current_lli = 0;
+	/* DMA coherent memory pool for LLI descriptors*/
+	desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
+				midc->dma->pdev,
+				(sizeof(struct intel_mid_dma_lli)*sg_len),
+				32, 0);
+	if (NULL == desc->lli_pool) {
+		pr_err("MID_DMA:LLI pool create failed\n");
+		return NULL;
+	}
+
+	desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
+	if (!desc->lli) {
+		pr_err("MID_DMA: LLI alloc failed\n");
+		pci_pool_destroy(desc->lli_pool);
+		return NULL;
+	}
+
+	midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
+	if (flags & DMA_PREP_INTERRUPT) {
+		iowrite32(UNMASK_INTR_REG(midc->ch_id),
+				midc->dma_base + MASK_BLOCK);
+		pr_debug("MDMA:Enabled Block interrupt\n");
+	}
+	return &desc->txd;
+}
 
 /**
  * intel_mid_dma_free_chan_resources -	Frees dma resources
@@ -618,11 +804,11 @@
 	struct middma_device	*mid = to_middma_device(chan->device);
 	struct intel_mid_dma_desc	*desc, *_desc;
 
-	if (true == midc->in_use) {
+	if (true == midc->busy) {
 		/*trying to free ch in use!!!!!*/
 		pr_err("ERR_MDMA: trying to free ch in use\n");
 	}
-
+	pm_runtime_put(&mid->pdev->dev);
 	spin_lock_bh(&midc->lock);
 	midc->descs_allocated = 0;
 	list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
@@ -639,6 +825,7 @@
 	}
 	spin_unlock_bh(&midc->lock);
 	midc->in_use = false;
+	midc->busy = false;
 	/* Disable CH interrupts */
 	iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
 	iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
@@ -659,11 +846,20 @@
 	dma_addr_t		phys;
 	int	i = 0;
 
+	pm_runtime_get_sync(&mid->pdev->dev);
+
+	if (mid->state == SUSPENDED) {
+		if (dma_resume(mid->pdev)) {
+			pr_err("ERR_MDMA: resume failed");
+			return -EFAULT;
+		}
+	}
 
 	/* ASSERT:  channel is idle */
 	if (test_ch_en(mid->dma_base, midc->ch_id)) {
 		/*ch is not idle*/
 		pr_err("ERR_MDMA: ch not idle\n");
+		pm_runtime_put(&mid->pdev->dev);
 		return -EIO;
 	}
 	midc->completed = chan->cookie = 1;
@@ -674,6 +870,7 @@
 		desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
 		if (!desc) {
 			pr_err("ERR_MDMA: desc failed\n");
+			pm_runtime_put(&mid->pdev->dev);
 			return -ENOMEM;
 			/*check*/
 		}
@@ -686,7 +883,8 @@
 		list_add_tail(&desc->desc_node, &midc->free_list);
 	}
 	spin_unlock_bh(&midc->lock);
-	midc->in_use = false;
+	midc->in_use = true;
+	midc->busy = false;
 	pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
 	return i;
 }
@@ -715,7 +913,7 @@
 {
 	struct middma_device *mid = NULL;
 	struct intel_mid_dma_chan *midc = NULL;
-	u32 status;
+	u32 status, raw_tfr, raw_block;
 	int i;
 
 	mid = (struct middma_device *)data;
@@ -724,8 +922,9 @@
 		return;
 	}
 	pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
-	status = ioread32(mid->dma_base + RAW_TFR);
-	pr_debug("MDMA:RAW_TFR %x\n", status);
+	raw_tfr = ioread32(mid->dma_base + RAW_TFR);
+	raw_block = ioread32(mid->dma_base + RAW_BLOCK);
+	status = raw_tfr | raw_block;
 	status &= mid->intr_mask;
 	while (status) {
 		/*txn interrupt*/
@@ -741,15 +940,23 @@
 		}
 		pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
 				status, midc->ch_id, i);
+		midc->raw_tfr = raw_tfr;
+		midc->raw_block = raw_block;
+		spin_lock_bh(&midc->lock);
 		/*clearing this interrupts first*/
 		iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
-		iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_BLOCK);
-
-		spin_lock_bh(&midc->lock);
+		if (raw_block) {
+			iowrite32((1 << midc->ch_id),
+				mid->dma_base + CLEAR_BLOCK);
+		}
 		midc_scan_descriptors(mid, midc);
 		pr_debug("MDMA:Scan of desc... complete, unmasking\n");
 		iowrite32(UNMASK_INTR_REG(midc->ch_id),
 				mid->dma_base + MASK_TFR);
+		if (raw_block) {
+			iowrite32(UNMASK_INTR_REG(midc->ch_id),
+				mid->dma_base + MASK_BLOCK);
+		}
 		spin_unlock_bh(&midc->lock);
 	}
 
@@ -804,9 +1011,14 @@
 static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
 {
 	struct middma_device *mid = data;
-	u32 status;
+	u32 tfr_status, err_status;
 	int call_tasklet = 0;
 
+	tfr_status = ioread32(mid->dma_base + RAW_TFR);
+	err_status = ioread32(mid->dma_base + RAW_ERR);
+	if (!tfr_status && !err_status)
+		return IRQ_NONE;
+
 	/*DMA Interrupt*/
 	pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
 	if (!mid) {
@@ -814,19 +1026,18 @@
 		return -EINVAL;
 	}
 
-	status = ioread32(mid->dma_base + RAW_TFR);
-	pr_debug("MDMA: Status %x, Mask %x\n", status, mid->intr_mask);
-	status &= mid->intr_mask;
-	if (status) {
+	pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
+	tfr_status &= mid->intr_mask;
+	if (tfr_status) {
 		/*need to disable intr*/
-		iowrite32((status << 8), mid->dma_base + MASK_TFR);
-		pr_debug("MDMA: Calling tasklet %x\n", status);
+		iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
+		iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
+		pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
 		call_tasklet = 1;
 	}
-	status = ioread32(mid->dma_base + RAW_ERR);
-	status &= mid->intr_mask;
-	if (status) {
-		iowrite32(MASK_INTR_REG(status), mid->dma_base + MASK_ERR);
+	err_status &= mid->intr_mask;
+	if (err_status) {
+		iowrite32(MASK_INTR_REG(err_status), mid->dma_base + MASK_ERR);
 		call_tasklet = 1;
 	}
 	if (call_tasklet)
@@ -856,7 +1067,6 @@
 {
 	struct middma_device *dma = pci_get_drvdata(pdev);
 	int err, i;
-	unsigned int irq_level;
 
 	/* DMA coherent memory pool for DMA descriptor allocations */
 	dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
@@ -865,7 +1075,6 @@
 	if (NULL == dma->dma_pool) {
 		pr_err("ERR_MDMA:pci_pool_create failed\n");
 		err = -ENOMEM;
-		kfree(dma);
 		goto err_dma_pool;
 	}
 
@@ -884,6 +1093,7 @@
 	pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
 	/*init CH structures*/
 	dma->intr_mask = 0;
+	dma->state = RUNNING;
 	for (i = 0; i < dma->max_chan; i++) {
 		struct intel_mid_dma_chan *midch = &dma->ch[i];
 
@@ -943,7 +1153,6 @@
 
 	/*register irq */
 	if (dma->pimr_mask) {
-		irq_level = IRQF_SHARED;
 		pr_debug("MDMA:Requesting irq shared for DMAC1\n");
 		err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
 			IRQF_SHARED, "INTEL_MID_DMAC1", dma);
@@ -951,10 +1160,9 @@
 			goto err_irq;
 	} else {
 		dma->intr_mask = 0x03;
-		irq_level = 0;
 		pr_debug("MDMA:Requesting irq for DMAC2\n");
 		err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
-			0, "INTEL_MID_DMAC2", dma);
+			IRQF_SHARED, "INTEL_MID_DMAC2", dma);
 		if (0 != err)
 			goto err_irq;
 	}
@@ -977,7 +1185,6 @@
 	free_irq(pdev->irq, dma);
 err_irq:
 	pci_pool_destroy(dma->dma_pool);
-	kfree(dma);
 err_dma_pool:
 	pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
 	return err;
@@ -1070,6 +1277,9 @@
 	if (err)
 		goto err_dma;
 
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_allow(&pdev->dev);
 	return 0;
 
 err_dma:
@@ -1104,6 +1314,85 @@
 	pci_disable_device(pdev);
 }
 
+/* Power Management */
+/*
+* dma_suspend - PCI suspend function
+*
+* @pci: PCI device structure
+* @state: PM message
+*
+* This function is called by OS when a power event occurs
+*/
+int dma_suspend(struct pci_dev *pci, pm_message_t state)
+{
+	int i;
+	struct middma_device *device = pci_get_drvdata(pci);
+	pr_debug("MDMA: dma_suspend called\n");
+
+	for (i = 0; i < device->max_chan; i++) {
+		if (device->ch[i].in_use)
+			return -EAGAIN;
+	}
+	device->state = SUSPENDED;
+	pci_set_drvdata(pci, device);
+	pci_save_state(pci);
+	pci_disable_device(pci);
+	pci_set_power_state(pci, PCI_D3hot);
+	return 0;
+}
+
+/**
+* dma_resume - PCI resume function
+*
+* @pci:	PCI device structure
+*
+* This function is called by OS when a power event occurs
+*/
+int dma_resume(struct pci_dev *pci)
+{
+	int ret;
+	struct middma_device *device = pci_get_drvdata(pci);
+
+	pr_debug("MDMA: dma_resume called\n");
+	pci_set_power_state(pci, PCI_D0);
+	pci_restore_state(pci);
+	ret = pci_enable_device(pci);
+	if (ret) {
+		pr_err("MDMA: device cant be enabled for %x\n", pci->device);
+		return ret;
+	}
+	device->state = RUNNING;
+	iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+	pci_set_drvdata(pci, device);
+	return 0;
+}
+
+static int dma_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	return dma_suspend(pci_dev, PMSG_SUSPEND);
+}
+
+static int dma_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pci_dev = to_pci_dev(dev);
+	return dma_resume(pci_dev);
+}
+
+static int dma_runtime_idle(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct middma_device *device = pci_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < device->max_chan; i++) {
+		if (device->ch[i].in_use)
+			return -EAGAIN;
+	}
+
+	return pm_schedule_suspend(dev, 0);
+}
+
 /******************************************************************************
 * PCI stuff
 */
@@ -1116,24 +1405,37 @@
 };
 MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
 
-static struct pci_driver intel_mid_dma_pci = {
+static const struct dev_pm_ops intel_mid_dma_pm = {
+	.runtime_suspend = dma_runtime_suspend,
+	.runtime_resume = dma_runtime_resume,
+	.runtime_idle = dma_runtime_idle,
+};
+
+static struct pci_driver intel_mid_dma_pci_driver = {
 	.name		=	"Intel MID DMA",
 	.id_table	=	intel_mid_dma_ids,
 	.probe		=	intel_mid_dma_probe,
 	.remove		=	__devexit_p(intel_mid_dma_remove),
+#ifdef CONFIG_PM
+	.suspend = dma_suspend,
+	.resume = dma_resume,
+	.driver = {
+		.pm = &intel_mid_dma_pm,
+	},
+#endif
 };
 
 static int __init intel_mid_dma_init(void)
 {
 	pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
 			INTEL_MID_DMA_DRIVER_VERSION);
-	return pci_register_driver(&intel_mid_dma_pci);
+	return pci_register_driver(&intel_mid_dma_pci_driver);
 }
 fs_initcall(intel_mid_dma_init);
 
 static void __exit intel_mid_dma_exit(void)
 {
-	pci_unregister_driver(&intel_mid_dma_pci);
+	pci_unregister_driver(&intel_mid_dma_pci_driver);
 }
 module_exit(intel_mid_dma_exit);
 
diff -druN linux-libre-2.6.36-gnu/drivers/dma/intel_mid_dma_regs.h linux-libre-2.6.37-gnu/drivers/dma/intel_mid_dma_regs.h
--- linux-libre-2.6.36-gnu/drivers/dma/intel_mid_dma_regs.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/intel_mid_dma_regs.h	2011-01-04 19:50:19.000000000 -0500
@@ -29,11 +29,12 @@
 #include <linux/dmapool.h>
 #include <linux/pci_ids.h>
 
-#define INTEL_MID_DMA_DRIVER_VERSION "1.0.5"
+#define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
 
 #define	REG_BIT0		0x00000001
 #define	REG_BIT8		0x00000100
-
+#define INT_MASK_WE		0x8
+#define CLEAR_DONE		0xFFFFEFFF
 #define UNMASK_INTR_REG(chan_num) \
 	((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
 #define MASK_INTR_REG(chan_num) (REG_BIT8 << chan_num)
@@ -41,6 +42,9 @@
 #define ENABLE_CHANNEL(chan_num) \
 	((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
 
+#define DISABLE_CHANNEL(chan_num) \
+	(REG_BIT8 << chan_num)
+
 #define DESCS_PER_CHANNEL	16
 /*DMA Registers*/
 /*registers associated with channel programming*/
@@ -50,6 +54,7 @@
 /*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/
 #define SAR			0x00 /* Source Address Register*/
 #define DAR			0x08 /* Destination Address Register*/
+#define LLP			0x10 /* Linked List Pointer Register*/
 #define CTL_LOW			0x18 /* Control Register*/
 #define CTL_HIGH		0x1C /* Control Register*/
 #define CFG_LOW			0x40 /* Configuration Register Low*/
@@ -112,8 +117,8 @@
 union intel_mid_dma_ctl_hi {
 	struct {
 		u32	block_ts:12;	/*block transfer size*/
-					/*configured by DMAC*/
-		u32	reser:20;
+		u32	done:1;		/*Done - updated by DMAC*/
+		u32	reser:19;	/*configured by DMAC*/
 	} ctlx;
 	u32	ctl_hi;
 
@@ -152,6 +157,7 @@
 	u32	cfg_hi;
 };
 
+
 /**
  * struct intel_mid_dma_chan - internal mid representation of a DMA channel
  * @chan: dma_chan strcture represetation for mid chan
@@ -166,7 +172,10 @@
  * @slave: dma slave struture
  * @descs_allocated: total number of decsiptors allocated
  * @dma: dma device struture pointer
+ * @busy: bool representing if ch is busy (active txn) or not
  * @in_use: bool representing if ch is in use or not
+ * @raw_tfr: raw trf interrupt recieved
+ * @raw_block: raw block interrupt recieved
  */
 struct intel_mid_dma_chan {
 	struct dma_chan		chan;
@@ -178,10 +187,13 @@
 	struct list_head	active_list;
 	struct list_head	queue;
 	struct list_head	free_list;
-	struct intel_mid_dma_slave	*slave;
 	unsigned int		descs_allocated;
 	struct middma_device	*dma;
+	bool			busy;
 	bool			in_use;
+	u32			raw_tfr;
+	u32			raw_block;
+	struct intel_mid_dma_slave *mid_slave;
 };
 
 static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
@@ -190,6 +202,10 @@
 	return container_of(chan, struct intel_mid_dma_chan, chan);
 }
 
+enum intel_mid_dma_state {
+	RUNNING = 0,
+	SUSPENDED,
+};
 /**
  * struct middma_device - internal representation of a DMA device
  * @pdev: PCI device
@@ -205,6 +221,7 @@
  * @max_chan: max number of chs supported (from drv_data)
  * @block_size: Block size of DMA transfer supported (from drv_data)
  * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
+ * @state: dma PM device state
  */
 struct middma_device {
 	struct pci_dev		*pdev;
@@ -220,6 +237,7 @@
 	int			max_chan;
 	int			block_size;
 	unsigned int		pimr_mask;
+	enum intel_mid_dma_state state;
 };
 
 static inline struct middma_device *to_middma_device(struct dma_device *common)
@@ -238,14 +256,27 @@
 	u32				cfg_lo;
 	u32				ctl_lo;
 	u32				ctl_hi;
+	struct pci_pool			*lli_pool;
+	struct intel_mid_dma_lli	*lli;
+	dma_addr_t			lli_phys;
+	unsigned int			lli_length;
+	unsigned int			current_lli;
 	dma_addr_t			next;
 	enum dma_data_direction		dirn;
 	enum dma_status			status;
-	enum intel_mid_dma_width	width; /*width of DMA txn*/
+	enum dma_slave_buswidth		width; /*width of DMA txn*/
 	enum intel_mid_dma_mode		cfg_mode; /*mode configuration*/
 
 };
 
+struct intel_mid_dma_lli {
+	dma_addr_t			sar;
+	dma_addr_t			dar;
+	dma_addr_t			llp;
+	u32				ctl_lo;
+	u32				ctl_hi;
+} __attribute__ ((packed));
+
 static inline int test_ch_en(void __iomem *dma, u32 ch_no)
 {
 	u32 en_reg = ioread32(dma + DMA_CHAN_EN);
@@ -257,4 +288,14 @@
 {
 	return container_of(txd, struct intel_mid_dma_desc, txd);
 }
+
+static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
+		(struct dma_slave_config *slave)
+{
+	return container_of(slave, struct intel_mid_dma_slave, dma_slave);
+}
+
+
+int dma_resume(struct pci_dev *pci);
+
 #endif /*__INTEL_MID_DMAC_REGS_H__*/
diff -druN linux-libre-2.6.36-gnu/drivers/dma/ioat/Makefile linux-libre-2.6.37-gnu/drivers/dma/ioat/Makefile
--- linux-libre-2.6.36-gnu/drivers/dma/ioat/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/ioat/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,2 +1,2 @@
 obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
-ioatdma-objs := pci.o dma.o dma_v2.o dma_v3.o dca.o
+ioatdma-y := pci.o dma.o dma_v2.o dma_v3.o dca.o
diff -druN linux-libre-2.6.36-gnu/drivers/dma/Kconfig linux-libre-2.6.37-gnu/drivers/dma/Kconfig
--- linux-libre-2.6.36-gnu/drivers/dma/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -46,15 +46,22 @@
 
 	  If unsure, say N.
 
-config ASYNC_TX_DISABLE_CHANNEL_SWITCH
+config ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	bool
 
+config AMBA_PL08X
+	bool "ARM PrimeCell PL080 or PL081 support"
+	depends on ARM_AMBA && EXPERIMENTAL
+	select DMA_ENGINE
+	help
+	  Platform has a PL08x DMAC device
+	  which can provide DMA engine support
+
 config INTEL_IOATDMA
 	tristate "Intel I/OAT DMA support"
 	depends on PCI && X86
 	select DMA_ENGINE
 	select DCA
-	select ASYNC_TX_DISABLE_CHANNEL_SWITCH
 	select ASYNC_TX_DISABLE_PQ_VAL_DMA
 	select ASYNC_TX_DISABLE_XOR_VAL_DMA
 	help
@@ -69,6 +76,7 @@
 	tristate "Intel IOP ADMA support"
 	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
 	select DMA_ENGINE
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	help
 	  Enable support for the Intel(R) IOP Series RAID engines.
 
@@ -93,6 +101,7 @@
 	tristate "Freescale Elo and Elo Plus DMA support"
 	depends on FSL_SOC
 	select DMA_ENGINE
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	---help---
 	  Enable support for the Freescale Elo and Elo Plus DMA controllers.
 	  The Elo is the DMA controller on some 82xx and 83xx parts, and the
@@ -109,6 +118,7 @@
 	bool "Marvell XOR engine support"
 	depends on PLAT_ORION
 	select DMA_ENGINE
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	---help---
 	  Enable support for the Marvell XOR engine.
 
@@ -166,6 +176,7 @@
 	depends on 440SPe || 440SP
 	select DMA_ENGINE
 	select ARCH_HAS_ASYNC_TX_FIND_CHANNEL
+	select ASYNC_TX_ENABLE_CHANNEL_SWITCH
 	help
 	  Enable support for the AMCC PPC440SPe RAID engines.
 
@@ -189,11 +200,27 @@
 	  platform_data for a dma-pl330 device.
 
 config PCH_DMA
-	tristate "Topcliff PCH DMA support"
+	tristate "Topcliff (Intel EG20T) PCH DMA support"
 	depends on PCI && X86
 	select DMA_ENGINE
 	help
-	  Enable support for the Topcliff PCH DMA engine.
+	  Enable support for the Topcliff (Intel EG20T) PCH DMA engine.
+
+config IMX_SDMA
+	tristate "i.MX SDMA support"
+	depends on ARCH_MX25 || ARCH_MX3 || ARCH_MX5
+	select DMA_ENGINE
+	help
+	  Support the i.MX SDMA engine. This engine is integrated into
+	  Freescale i.MX25/31/35/51 chips.
+
+config IMX_DMA
+	tristate "i.MX DMA support"
+	depends on ARCH_MX1 || ARCH_MX21 || MACH_MX27
+	select DMA_ENGINE
+	help
+	  Support the i.MX DMA engine. This engine is integrated into
+	  Freescale i.MX1/21/27 chips.
 
 config DMA_ENGINE
 	bool
diff -druN linux-libre-2.6.36-gnu/drivers/dma/Makefile linux-libre-2.6.37-gnu/drivers/dma/Makefile
--- linux-libre-2.6.36-gnu/drivers/dma/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 ifeq ($(CONFIG_DMADEVICES_DEBUG),y)
-	EXTRA_CFLAGS	+= -DDEBUG
+	ccflags-y	+= -DDEBUG
 endif
 ifeq ($(CONFIG_DMADEVICES_VDEBUG),y)
-	EXTRA_CFLAGS	+= -DVERBOSE_DEBUG
+	ccflags-y	+= -DVERBOSE_DEBUG
 endif
 
 obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
@@ -21,7 +21,10 @@
 obj-$(CONFIG_SH_DMAE) += shdma.o
 obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
 obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
+obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
+obj-$(CONFIG_IMX_DMA) += imx-dma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
 obj-$(CONFIG_PCH_DMA) += pch_dma.o
+obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
diff -druN linux-libre-2.6.36-gnu/drivers/dma/mv_xor.c linux-libre-2.6.37-gnu/drivers/dma/mv_xor.c
--- linux-libre-2.6.36-gnu/drivers/dma/mv_xor.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/mv_xor.c	2011-01-04 19:50:19.000000000 -0500
@@ -449,7 +449,7 @@
 static void mv_xor_tasklet(unsigned long data)
 {
 	struct mv_xor_chan *chan = (struct mv_xor_chan *) data;
-	__mv_xor_slot_cleanup(chan);
+	mv_xor_slot_cleanup(chan);
 }
 
 static struct mv_xor_desc_slot *
diff -druN linux-libre-2.6.36-gnu/drivers/dma/pch_dma.c linux-libre-2.6.37-gnu/drivers/dma/pch_dma.c
--- linux-libre-2.6.36-gnu/drivers/dma/pch_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/pch_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -259,11 +259,6 @@
 		return;
 	}
 
-	channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
-	channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
-	channel_writel(pd_chan, SIZE, desc->regs.size);
-	channel_writel(pd_chan, NEXT, desc->regs.next);
-
 	dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> dev_addr: %x\n",
 		pd_chan->chan.chan_id, desc->regs.dev_addr);
 	dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> mem_addr: %x\n",
@@ -273,10 +268,16 @@
 	dev_dbg(chan2dev(&pd_chan->chan), "chan %d -> next: %x\n",
 		pd_chan->chan.chan_id, desc->regs.next);
 
-	if (list_empty(&desc->tx_list))
+	if (list_empty(&desc->tx_list)) {
+		channel_writel(pd_chan, DEV_ADDR, desc->regs.dev_addr);
+		channel_writel(pd_chan, MEM_ADDR, desc->regs.mem_addr);
+		channel_writel(pd_chan, SIZE, desc->regs.size);
+		channel_writel(pd_chan, NEXT, desc->regs.next);
 		pdc_set_mode(&pd_chan->chan, DMA_CTL0_ONESHOT);
-	else
+	} else {
+		channel_writel(pd_chan, NEXT, desc->txd.phys);
 		pdc_set_mode(&pd_chan->chan, DMA_CTL0_SG);
+	}
 
 	val = dma_readl(pd, CTL2);
 	val |= 1 << (DMA_CTL2_START_SHIFT_BITS + pd_chan->chan.chan_id);
@@ -926,6 +927,7 @@
 static const struct pci_device_id pch_dma_id_table[] = {
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 },
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 },
+	{ 0, },
 };
 
 static struct pci_driver pch_dma_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/dma/ppc4xx/adma.c linux-libre-2.6.37-gnu/drivers/dma/ppc4xx/adma.c
--- linux-libre-2.6.36-gnu/drivers/dma/ppc4xx/adma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/ppc4xx/adma.c	2011-01-04 19:50:19.000000000 -0500
@@ -4449,9 +4449,8 @@
 
 	if (!request_mem_region(res.start, resource_size(&res),
 				dev_driver_string(&ofdev->dev))) {
-		dev_err(&ofdev->dev, "failed to request memory region "
-			"(0x%016llx-0x%016llx)\n",
-			(u64)res.start, (u64)res.end);
+		dev_err(&ofdev->dev, "failed to request memory region %pR\n",
+			&res);
 		initcode = PPC_ADMA_INIT_MEMREG;
 		ret = -EBUSY;
 		goto out;
diff -druN linux-libre-2.6.36-gnu/drivers/dma/shdma.c linux-libre-2.6.37-gnu/drivers/dma/shdma.c
--- linux-libre-2.6.36-gnu/drivers/dma/shdma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/shdma.c	2011-01-04 19:50:19.000000000 -0500
@@ -1213,3 +1213,4 @@
 MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>");
 MODULE_DESCRIPTION("Renesas SH DMA Engine driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sh-dma-engine");
diff -druN linux-libre-2.6.36-gnu/drivers/dma/ste_dma40.c linux-libre-2.6.37-gnu/drivers/dma/ste_dma40.c
--- linux-libre-2.6.36-gnu/drivers/dma/ste_dma40.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/ste_dma40.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,11 +1,8 @@
 /*
- * driver/dma/ste_dma40.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
  */
 
 #include <linux/kernel.h>
@@ -14,6 +11,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/err.h>
 
 #include <plat/ste_dma40.h>
 
@@ -32,6 +30,11 @@
 
 /* Hardware requirement on LCLA alignment */
 #define LCLA_ALIGNMENT 0x40000
+
+/* Max number of links per event group */
+#define D40_LCLA_LINK_PER_EVENT_GRP 128
+#define D40_LCLA_END D40_LCLA_LINK_PER_EVENT_GRP
+
 /* Attempts before giving up to trying to get pages that are aligned */
 #define MAX_LCLA_ALLOC_ATTEMPTS 256
 
@@ -41,7 +44,7 @@
 #define D40_ALLOC_LOG_FREE	0
 
 /* Hardware designer of the block */
-#define D40_PERIPHID2_DESIGNER 0x8
+#define D40_HW_DESIGNER 0x8
 
 /**
  * enum 40_command - The different commands and/or statuses.
@@ -84,18 +87,17 @@
  * @lli_log: Same as above but for logical channels.
  * @lli_pool: The pool with two entries pre-allocated.
  * @lli_len: Number of llis of current descriptor.
- * @lli_count: Number of transfered llis.
- * @lli_tx_len: Max number of LLIs per transfer, there can be
- * many transfer for one descriptor.
+ * @lli_current: Number of transfered llis.
+ * @lcla_alloc: Number of LCLA entries allocated.
  * @txd: DMA engine struct. Used for among other things for communication
  * during a transfer.
  * @node: List entry.
- * @dir: The transfer direction of this job.
  * @is_in_client_list: true if the client owns this descriptor.
+ * @is_hw_linked: true if this job will automatically be continued for
+ * the previous one.
  *
  * This descriptor is used for both logical and physical transfers.
  */
-
 struct d40_desc {
 	/* LLI physical */
 	struct d40_phy_lli_bidir	 lli_phy;
@@ -104,14 +106,14 @@
 
 	struct d40_lli_pool		 lli_pool;
 	int				 lli_len;
-	int				 lli_count;
-	u32				 lli_tx_len;
+	int				 lli_current;
+	int				 lcla_alloc;
 
 	struct dma_async_tx_descriptor	 txd;
 	struct list_head		 node;
 
-	enum dma_data_direction		 dir;
 	bool				 is_in_client_list;
+	bool				 is_hw_linked;
 };
 
 /**
@@ -123,17 +125,14 @@
  * @pages: The number of pages needed for all physical channels.
  * Only used later for clean-up on error
  * @lock: Lock to protect the content in this struct.
- * @alloc_map: Bitmap mapping between physical channel and LCLA entries.
- * @num_blocks: The number of entries of alloc_map. Equals to the
- * number of physical channels.
+ * @alloc_map: big map over which LCLA entry is own by which job.
  */
 struct d40_lcla_pool {
 	void		*base;
 	void		*base_unaligned;
 	int		 pages;
 	spinlock_t	 lock;
-	u32		*alloc_map;
-	int		 num_blocks;
+	struct d40_desc	**alloc_map;
 };
 
 /**
@@ -146,9 +145,7 @@
  * this physical channel. Can also be free or physically allocated.
  * @allocated_dst: Same as for src but is dst.
  * allocated_dst and allocated_src uses the D40_ALLOC* defines as well as
- * event line number. Both allocated_src and allocated_dst can not be
- * allocated to a physical channel, since the interrupt handler has then
- * no way of figure out which one the interrupt belongs to.
+ * event line number.
  */
 struct d40_phy_res {
 	spinlock_t lock;
@@ -178,6 +175,7 @@
  * @active: Active descriptor.
  * @queue: Queued jobs.
  * @dma_cfg: The client configuration of this dma channel.
+ * @configured: whether the dma_cfg configuration is valid
  * @base: Pointer to the device instance struct.
  * @src_def_cfg: Default cfg register setting for src.
  * @dst_def_cfg: Default cfg register setting for dst.
@@ -201,12 +199,12 @@
 	struct list_head		 active;
 	struct list_head		 queue;
 	struct stedma40_chan_cfg	 dma_cfg;
+	bool				 configured;
 	struct d40_base			*base;
 	/* Default register configurations */
 	u32				 src_def_cfg;
 	u32				 dst_def_cfg;
 	struct d40_def_lcsp		 log_def;
-	struct d40_lcla_elem		 lcla;
 	struct d40_log_lli_full		*lcpa;
 	/* Runtime reconfiguration */
 	dma_addr_t			runtime_addr;
@@ -234,7 +232,6 @@
  * @dma_both: dma_device channels that can do both memcpy and slave transfers.
  * @dma_slave: dma_device channels that can do only do slave transfers.
  * @dma_memcpy: dma_device channels that can do only do memcpy transfers.
- * @phy_chans: Room for all possible physical channels in system.
  * @log_chans: Room for all possible logical channels in system.
  * @lookup_log_chans: Used to map interrupt number to logical channel. Points
  * to log_chans entries.
@@ -340,9 +337,6 @@
 					      align);
 		d40d->lli_phy.dst = PTR_ALIGN(d40d->lli_phy.src + lli_len,
 					      align);
-
-		d40d->lli_phy.src_addr = virt_to_phys(d40d->lli_phy.src);
-		d40d->lli_phy.dst_addr = virt_to_phys(d40d->lli_phy.dst);
 	}
 
 	return 0;
@@ -357,22 +351,67 @@
 	d40d->lli_log.dst = NULL;
 	d40d->lli_phy.src = NULL;
 	d40d->lli_phy.dst = NULL;
-	d40d->lli_phy.src_addr = 0;
-	d40d->lli_phy.dst_addr = 0;
 }
 
-static dma_cookie_t d40_assign_cookie(struct d40_chan *d40c,
-				      struct d40_desc *desc)
+static int d40_lcla_alloc_one(struct d40_chan *d40c,
+			      struct d40_desc *d40d)
 {
-	dma_cookie_t cookie = d40c->chan.cookie;
+	unsigned long flags;
+	int i;
+	int ret = -EINVAL;
+	int p;
 
-	if (++cookie < 0)
-		cookie = 1;
+	spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
 
-	d40c->chan.cookie = cookie;
-	desc->txd.cookie = cookie;
+	p = d40c->phy_chan->num * D40_LCLA_LINK_PER_EVENT_GRP;
+
+	/*
+	 * Allocate both src and dst at the same time, therefore the half
+	 * start on 1 since 0 can't be used since zero is used as end marker.
+	 */
+	for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+		if (!d40c->base->lcla_pool.alloc_map[p + i]) {
+			d40c->base->lcla_pool.alloc_map[p + i] = d40d;
+			d40d->lcla_alloc++;
+			ret = i;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+	return ret;
+}
+
+static int d40_lcla_free_all(struct d40_chan *d40c,
+			     struct d40_desc *d40d)
+{
+	unsigned long flags;
+	int i;
+	int ret = -EINVAL;
+
+	if (d40c->log_num == D40_PHY_CHAN)
+		return 0;
+
+	spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
+
+	for (i = 1 ; i < D40_LCLA_LINK_PER_EVENT_GRP / 2; i++) {
+		if (d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num *
+						    D40_LCLA_LINK_PER_EVENT_GRP + i] == d40d) {
+			d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num *
+							D40_LCLA_LINK_PER_EVENT_GRP + i] = NULL;
+			d40d->lcla_alloc--;
+			if (d40d->lcla_alloc == 0) {
+				ret = 0;
+				break;
+			}
+		}
+	}
+
+	spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
+
+	return ret;
 
-	return cookie;
 }
 
 static void d40_desc_remove(struct d40_desc *d40d)
@@ -382,28 +421,35 @@
 
 static struct d40_desc *d40_desc_get(struct d40_chan *d40c)
 {
-	struct d40_desc *d;
-	struct d40_desc *_d;
+	struct d40_desc *desc = NULL;
 
 	if (!list_empty(&d40c->client)) {
+		struct d40_desc *d;
+		struct d40_desc *_d;
+
 		list_for_each_entry_safe(d, _d, &d40c->client, node)
 			if (async_tx_test_ack(&d->txd)) {
 				d40_pool_lli_free(d);
 				d40_desc_remove(d);
+				desc = d;
+				memset(desc, 0, sizeof(*desc));
 				break;
 			}
-	} else {
-		d = kmem_cache_alloc(d40c->base->desc_slab, GFP_NOWAIT);
-		if (d != NULL) {
-			memset(d, 0, sizeof(struct d40_desc));
-			INIT_LIST_HEAD(&d->node);
-		}
 	}
-	return d;
+
+	if (!desc)
+		desc = kmem_cache_zalloc(d40c->base->desc_slab, GFP_NOWAIT);
+
+	if (desc)
+		INIT_LIST_HEAD(&desc->node);
+
+	return desc;
 }
 
 static void d40_desc_free(struct d40_chan *d40c, struct d40_desc *d40d)
 {
+
+	d40_lcla_free_all(d40c, d40d);
 	kmem_cache_free(d40c->base->desc_slab, d40d);
 }
 
@@ -412,6 +458,59 @@
 	list_add_tail(&desc->node, &d40c->active);
 }
 
+static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+	int curr_lcla = -EINVAL, next_lcla;
+
+	if (d40c->log_num == D40_PHY_CHAN) {
+		d40_phy_lli_write(d40c->base->virtbase,
+				  d40c->phy_chan->num,
+				  d40d->lli_phy.dst,
+				  d40d->lli_phy.src);
+		d40d->lli_current = d40d->lli_len;
+	} else {
+
+		if ((d40d->lli_len - d40d->lli_current) > 1)
+			curr_lcla = d40_lcla_alloc_one(d40c, d40d);
+
+		d40_log_lli_lcpa_write(d40c->lcpa,
+				       &d40d->lli_log.dst[d40d->lli_current],
+				       &d40d->lli_log.src[d40d->lli_current],
+				       curr_lcla);
+
+		d40d->lli_current++;
+		for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) {
+			struct d40_log_lli *lcla;
+
+			if (d40d->lli_current + 1 < d40d->lli_len)
+				next_lcla = d40_lcla_alloc_one(d40c, d40d);
+			else
+				next_lcla = -EINVAL;
+
+			lcla = d40c->base->lcla_pool.base +
+				d40c->phy_chan->num * 1024 +
+				8 * curr_lcla * 2;
+
+			d40_log_lli_lcla_write(lcla,
+					       &d40d->lli_log.dst[d40d->lli_current],
+					       &d40d->lli_log.src[d40d->lli_current],
+					       next_lcla);
+
+			(void) dma_map_single(d40c->base->dev, lcla,
+					      2 * sizeof(struct d40_log_lli),
+					      DMA_TO_DEVICE);
+
+			curr_lcla = next_lcla;
+
+			if (curr_lcla == -EINVAL) {
+				d40d->lli_current++;
+				break;
+			}
+
+		}
+	}
+}
+
 static struct d40_desc *d40_first_active_get(struct d40_chan *d40c)
 {
 	struct d40_desc *d;
@@ -443,68 +542,26 @@
 	return d;
 }
 
-/* Support functions for logical channels */
-
-static int d40_lcla_id_get(struct d40_chan *d40c)
+static struct d40_desc *d40_last_queued(struct d40_chan *d40c)
 {
-	int src_id = 0;
-	int dst_id = 0;
-	struct d40_log_lli *lcla_lidx_base =
-		d40c->base->lcla_pool.base + d40c->phy_chan->num * 1024;
-	int i;
-	int lli_per_log = d40c->base->plat_data->llis_per_log;
-	unsigned long flags;
-
-	if (d40c->lcla.src_id >= 0 && d40c->lcla.dst_id >= 0)
-		return 0;
-
-	if (d40c->base->lcla_pool.num_blocks > 32)
-		return -EINVAL;
-
-	spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
-
-	for (i = 0; i < d40c->base->lcla_pool.num_blocks; i++) {
-		if (!(d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &
-		      (0x1 << i))) {
-			d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] |=
-				(0x1 << i);
-			break;
-		}
-	}
-	src_id = i;
-	if (src_id >= d40c->base->lcla_pool.num_blocks)
-		goto err;
+	struct d40_desc *d;
 
-	for (; i < d40c->base->lcla_pool.num_blocks; i++) {
-		if (!(d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &
-		      (0x1 << i))) {
-			d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] |=
-				(0x1 << i);
+	if (list_empty(&d40c->queue))
+		return NULL;
+	list_for_each_entry(d, &d40c->queue, node)
+		if (list_is_last(&d->node, &d40c->queue))
 			break;
-		}
-	}
-
-	dst_id = i;
-	if (dst_id == src_id)
-		goto err;
-
-	d40c->lcla.src_id = src_id;
-	d40c->lcla.dst_id = dst_id;
-	d40c->lcla.dst = lcla_lidx_base + dst_id * lli_per_log + 1;
-	d40c->lcla.src = lcla_lidx_base + src_id * lli_per_log + 1;
-
-	spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
-	return 0;
-err:
-	spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
-	return -EINVAL;
+	return d;
 }
 
+/* Support functions for logical channels */
+
 
 static int d40_channel_execute_command(struct d40_chan *d40c,
 				       enum d40_command command)
 {
-	int status, i;
+	u32 status;
+	int i;
 	void __iomem *active_reg;
 	int ret = 0;
 	unsigned long flags;
@@ -567,35 +624,19 @@
 static void d40_term_all(struct d40_chan *d40c)
 {
 	struct d40_desc *d40d;
-	unsigned long flags;
 
 	/* Release active descriptors */
 	while ((d40d = d40_first_active_get(d40c))) {
 		d40_desc_remove(d40d);
-
-		/* Return desc to free-list */
 		d40_desc_free(d40c, d40d);
 	}
 
 	/* Release queued descriptors waiting for transfer */
 	while ((d40d = d40_first_queued(d40c))) {
 		d40_desc_remove(d40d);
-
-		/* Return desc to free-list */
 		d40_desc_free(d40c, d40d);
 	}
 
-	spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags);
-
-	d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &=
-		(~(0x1 << d40c->lcla.dst_id));
-	d40c->base->lcla_pool.alloc_map[d40c->phy_chan->num] &=
-		(~(0x1 << d40c->lcla.src_id));
-
-	d40c->lcla.src_id = -1;
-	d40c->lcla.dst_id = -1;
-
-	spin_unlock_irqrestore(&d40c->base->lcla_pool.lock, flags);
 
 	d40c->pending_tx = 0;
 	d40c->busy = false;
@@ -640,45 +681,47 @@
 
 static u32 d40_chan_has_events(struct d40_chan *d40c)
 {
-	u32 val = 0;
+	u32 val;
 
-	/* If SSLNK or SDLNK is zero all events are disabled */
-	if ((d40c->dma_cfg.dir ==  STEDMA40_PERIPH_TO_MEM) ||
-	    (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH))
-		val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-			    d40c->phy_chan->num * D40_DREG_PCDELTA +
-			    D40_CHAN_REG_SSLNK);
+	val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+		    d40c->phy_chan->num * D40_DREG_PCDELTA +
+		    D40_CHAN_REG_SSLNK);
 
-	if (d40c->dma_cfg.dir !=  STEDMA40_PERIPH_TO_MEM)
-		val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-			    d40c->phy_chan->num * D40_DREG_PCDELTA +
-			    D40_CHAN_REG_SDLNK);
+	val |= readl(d40c->base->virtbase + D40_DREG_PCBASE +
+		     d40c->phy_chan->num * D40_DREG_PCDELTA +
+		     D40_CHAN_REG_SDLNK);
 	return val;
 }
 
-static void d40_config_enable_lidx(struct d40_chan *d40c)
+static u32 d40_get_prmo(struct d40_chan *d40c)
 {
-	/* Set LIDX for lcla */
-	writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
-	       D40_SREG_ELEM_LOG_LIDX_MASK,
-	       d40c->base->virtbase + D40_DREG_PCBASE +
-	       d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
+	static const unsigned int phy_map[] = {
+		[STEDMA40_PCHAN_BASIC_MODE]
+			= D40_DREG_PRMO_PCHAN_BASIC,
+		[STEDMA40_PCHAN_MODULO_MODE]
+			= D40_DREG_PRMO_PCHAN_MODULO,
+		[STEDMA40_PCHAN_DOUBLE_DST_MODE]
+			= D40_DREG_PRMO_PCHAN_DOUBLE_DST,
+	};
+	static const unsigned int log_map[] = {
+		[STEDMA40_LCHAN_SRC_PHY_DST_LOG]
+			= D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG,
+		[STEDMA40_LCHAN_SRC_LOG_DST_PHY]
+			= D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY,
+		[STEDMA40_LCHAN_SRC_LOG_DST_LOG]
+			= D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG,
+	};
 
-	writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
-	       D40_SREG_ELEM_LOG_LIDX_MASK,
-	       d40c->base->virtbase + D40_DREG_PCBASE +
-	       d40c->phy_chan->num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
+	if (d40c->log_num == D40_PHY_CHAN)
+		return phy_map[d40c->dma_cfg.mode_opt];
+	else
+		return log_map[d40c->dma_cfg.mode_opt];
 }
 
-static int d40_config_write(struct d40_chan *d40c)
+static void d40_config_write(struct d40_chan *d40c)
 {
 	u32 addr_base;
 	u32 var;
-	int res;
-
-	res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
-	if (res)
-		return res;
 
 	/* Odd addresses are even addresses + 4 */
 	addr_base = (d40c->phy_chan->num % 2) * 4;
@@ -688,8 +731,7 @@
 	writel(var, d40c->base->virtbase + D40_DREG_PRMSE + addr_base);
 
 	/* Setup operational mode option register */
-	var = ((d40c->dma_cfg.channel_type >> STEDMA40_INFO_CH_MODE_OPT_POS) &
-	       0x3) << D40_CHAN_POS(d40c->phy_chan->num);
+	var = d40_get_prmo(d40c) << D40_CHAN_POS(d40c->phy_chan->num);
 
 	writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base);
 
@@ -704,41 +746,181 @@
 		       d40c->phy_chan->num * D40_DREG_PCDELTA +
 		       D40_CHAN_REG_SDCFG);
 
-		d40_config_enable_lidx(d40c);
+		/* Set LIDX for lcla */
+		writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+		       D40_SREG_ELEM_LOG_LIDX_MASK,
+		       d40c->base->virtbase + D40_DREG_PCBASE +
+		       d40c->phy_chan->num * D40_DREG_PCDELTA +
+		       D40_CHAN_REG_SDELT);
+
+		writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) &
+		       D40_SREG_ELEM_LOG_LIDX_MASK,
+		       d40c->base->virtbase + D40_DREG_PCBASE +
+		       d40c->phy_chan->num * D40_DREG_PCDELTA +
+		       D40_CHAN_REG_SSELT);
+
 	}
+}
+
+static u32 d40_residue(struct d40_chan *d40c)
+{
+	u32 num_elt;
+
+	if (d40c->log_num != D40_PHY_CHAN)
+		num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
+			>> D40_MEM_LCSP2_ECNT_POS;
+	else
+		num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
+				 d40c->phy_chan->num * D40_DREG_PCDELTA +
+				 D40_CHAN_REG_SDELT) &
+			   D40_SREG_ELEM_PHY_ECNT_MASK) >>
+			D40_SREG_ELEM_PHY_ECNT_POS;
+	return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
+}
+
+static bool d40_tx_is_linked(struct d40_chan *d40c)
+{
+	bool is_link;
+
+	if (d40c->log_num != D40_PHY_CHAN)
+		is_link = readl(&d40c->lcpa->lcsp3) &  D40_MEM_LCSP3_DLOS_MASK;
+	else
+		is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+				d40c->phy_chan->num * D40_DREG_PCDELTA +
+				D40_CHAN_REG_SDLNK) &
+			D40_SREG_LNK_PHYS_LNK_MASK;
+	return is_link;
+}
+
+static int d40_pause(struct dma_chan *chan)
+{
+	struct d40_chan *d40c =
+		container_of(chan, struct d40_chan, chan);
+	int res = 0;
+	unsigned long flags;
+
+	if (!d40c->busy)
+		return 0;
+
+	spin_lock_irqsave(&d40c->lock, flags);
+
+	res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
+	if (res == 0) {
+		if (d40c->log_num != D40_PHY_CHAN) {
+			d40_config_set_event(d40c, false);
+			/* Resume the other logical channels if any */
+			if (d40_chan_has_events(d40c))
+				res = d40_channel_execute_command(d40c,
+								  D40_DMA_RUN);
+		}
+	}
+
+	spin_unlock_irqrestore(&d40c->lock, flags);
 	return res;
 }
 
-static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d)
+static int d40_resume(struct dma_chan *chan)
 {
-	if (d40d->lli_phy.dst && d40d->lli_phy.src) {
-		d40_phy_lli_write(d40c->base->virtbase,
-				  d40c->phy_chan->num,
-				  d40d->lli_phy.dst,
-				  d40d->lli_phy.src);
-	} else if (d40d->lli_log.dst && d40d->lli_log.src) {
-		struct d40_log_lli *src = d40d->lli_log.src;
-		struct d40_log_lli *dst = d40d->lli_log.dst;
-		int s;
+	struct d40_chan *d40c =
+		container_of(chan, struct d40_chan, chan);
+	int res = 0;
+	unsigned long flags;
 
-		src += d40d->lli_count;
-		dst += d40d->lli_count;
-		s = d40_log_lli_write(d40c->lcpa,
-				      d40c->lcla.src, d40c->lcla.dst,
-				      dst, src,
-				      d40c->base->plat_data->llis_per_log);
+	if (!d40c->busy)
+		return 0;
 
-		/* If s equals to zero, the job is not linked */
-		if (s > 0) {
-			(void) dma_map_single(d40c->base->dev, d40c->lcla.src,
-					      s * sizeof(struct d40_log_lli),
-					      DMA_TO_DEVICE);
-			(void) dma_map_single(d40c->base->dev, d40c->lcla.dst,
-					      s * sizeof(struct d40_log_lli),
-					      DMA_TO_DEVICE);
+	spin_lock_irqsave(&d40c->lock, flags);
+
+	if (d40c->base->rev == 0)
+		if (d40c->log_num != D40_PHY_CHAN) {
+			res = d40_channel_execute_command(d40c,
+							  D40_DMA_SUSPEND_REQ);
+			goto no_suspend;
 		}
+
+	/* If bytes left to transfer or linked tx resume job */
+	if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
+
+		if (d40c->log_num != D40_PHY_CHAN)
+			d40_config_set_event(d40c, true);
+
+		res = d40_channel_execute_command(d40c, D40_DMA_RUN);
+	}
+
+no_suspend:
+	spin_unlock_irqrestore(&d40c->lock, flags);
+	return res;
+}
+
+static void d40_tx_submit_log(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+	/* TODO: Write */
+}
+
+static void d40_tx_submit_phy(struct d40_chan *d40c, struct d40_desc *d40d)
+{
+	struct d40_desc *d40d_prev = NULL;
+	int i;
+	u32 val;
+
+	if (!list_empty(&d40c->queue))
+		d40d_prev = d40_last_queued(d40c);
+	else if (!list_empty(&d40c->active))
+		d40d_prev = d40_first_active_get(d40c);
+
+	if (!d40d_prev)
+		return;
+
+	/* Here we try to join this job with previous jobs */
+	val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+		    d40c->phy_chan->num * D40_DREG_PCDELTA +
+		    D40_CHAN_REG_SSLNK);
+
+	/* Figure out which link we're currently transmitting */
+	for (i = 0; i < d40d_prev->lli_len; i++)
+		if (val == d40d_prev->lli_phy.src[i].reg_lnk)
+			break;
+
+	val = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+		    d40c->phy_chan->num * D40_DREG_PCDELTA +
+		    D40_CHAN_REG_SSELT) >> D40_SREG_ELEM_LOG_ECNT_POS;
+
+	if (i == (d40d_prev->lli_len - 1) && val > 0) {
+		/* Change the current one */
+		writel(virt_to_phys(d40d->lli_phy.src),
+		       d40c->base->virtbase + D40_DREG_PCBASE +
+		       d40c->phy_chan->num * D40_DREG_PCDELTA +
+		       D40_CHAN_REG_SSLNK);
+		writel(virt_to_phys(d40d->lli_phy.dst),
+		       d40c->base->virtbase + D40_DREG_PCBASE +
+		       d40c->phy_chan->num * D40_DREG_PCDELTA +
+		       D40_CHAN_REG_SDLNK);
+
+		d40d->is_hw_linked = true;
+
+	} else if (i < d40d_prev->lli_len) {
+		(void) dma_unmap_single(d40c->base->dev,
+					virt_to_phys(d40d_prev->lli_phy.src),
+					d40d_prev->lli_pool.size,
+					DMA_TO_DEVICE);
+
+		/* Keep the settings */
+		val = d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk &
+			~D40_SREG_LNK_PHYS_LNK_MASK;
+		d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk =
+			val | virt_to_phys(d40d->lli_phy.src);
+
+		val = d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk &
+			~D40_SREG_LNK_PHYS_LNK_MASK;
+		d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk =
+			val | virt_to_phys(d40d->lli_phy.dst);
+
+		(void) dma_map_single(d40c->base->dev,
+				      d40d_prev->lli_phy.src,
+				      d40d_prev->lli_pool.size,
+				      DMA_TO_DEVICE);
+		d40d->is_hw_linked = true;
 	}
-	d40d->lli_count += d40d->lli_tx_len;
 }
 
 static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -749,14 +931,28 @@
 	struct d40_desc *d40d = container_of(tx, struct d40_desc, txd);
 	unsigned long flags;
 
+	(void) d40_pause(&d40c->chan);
+
 	spin_lock_irqsave(&d40c->lock, flags);
 
-	tx->cookie = d40_assign_cookie(d40c, d40d);
+	d40c->chan.cookie++;
+
+	if (d40c->chan.cookie < 0)
+		d40c->chan.cookie = 1;
+
+	d40d->txd.cookie = d40c->chan.cookie;
+
+	if (d40c->log_num == D40_PHY_CHAN)
+		d40_tx_submit_phy(d40c, d40d);
+	else
+		d40_tx_submit_log(d40c, d40d);
 
 	d40_desc_queue(d40c, d40d);
 
 	spin_unlock_irqrestore(&d40c->lock, flags);
 
+	(void) d40_resume(&d40c->chan);
+
 	return tx->cookie;
 }
 
@@ -796,14 +992,21 @@
 		/* Add to active queue */
 		d40_desc_submit(d40c, d40d);
 
-		/* Initiate DMA job */
-		d40_desc_load(d40c, d40d);
+		/*
+		 * If this job is already linked in hw,
+		 * do not submit it.
+		 */
 
-		/* Start dma job */
-		err = d40_start(d40c);
+		if (!d40d->is_hw_linked) {
+			/* Initiate DMA job */
+			d40_desc_load(d40c, d40d);
 
-		if (err)
-			return NULL;
+			/* Start dma job */
+			err = d40_start(d40c);
+
+			if (err)
+				return NULL;
+		}
 	}
 
 	return d40d;
@@ -814,17 +1017,15 @@
 {
 	struct d40_desc *d40d;
 
-	if (!d40c->phy_chan)
-		return;
-
 	/* Get first active entry from list */
 	d40d = d40_first_active_get(d40c);
 
 	if (d40d == NULL)
 		return;
 
-	if (d40d->lli_count < d40d->lli_len) {
+	d40_lcla_free_all(d40c, d40d);
 
+	if (d40d->lli_current < d40d->lli_len) {
 		d40_desc_load(d40c, d40d);
 		/* Start dma job */
 		(void) d40_start(d40c);
@@ -842,7 +1043,7 @@
 static void dma_tasklet(unsigned long data)
 {
 	struct d40_chan *d40c = (struct d40_chan *) data;
-	struct d40_desc *d40d_fin;
+	struct d40_desc *d40d;
 	unsigned long flags;
 	dma_async_tx_callback callback;
 	void *callback_param;
@@ -850,12 +1051,12 @@
 	spin_lock_irqsave(&d40c->lock, flags);
 
 	/* Get first active entry from list */
-	d40d_fin = d40_first_active_get(d40c);
+	d40d = d40_first_active_get(d40c);
 
-	if (d40d_fin == NULL)
+	if (d40d == NULL)
 		goto err;
 
-	d40c->completed = d40d_fin->txd.cookie;
+	d40c->completed = d40d->txd.cookie;
 
 	/*
 	 * If terminating a channel pending_tx is set to zero.
@@ -867,19 +1068,19 @@
 	}
 
 	/* Callback to client */
-	callback = d40d_fin->txd.callback;
-	callback_param = d40d_fin->txd.callback_param;
+	callback = d40d->txd.callback;
+	callback_param = d40d->txd.callback_param;
 
-	if (async_tx_test_ack(&d40d_fin->txd)) {
-		d40_pool_lli_free(d40d_fin);
-		d40_desc_remove(d40d_fin);
-		/* Return desc to free-list */
-		d40_desc_free(d40c, d40d_fin);
+	if (async_tx_test_ack(&d40d->txd)) {
+		d40_pool_lli_free(d40d);
+		d40_desc_remove(d40d);
+		d40_desc_free(d40c, d40d);
 	} else {
-		if (!d40d_fin->is_in_client_list) {
-			d40_desc_remove(d40d_fin);
-			list_add_tail(&d40d_fin->node, &d40c->client);
-			d40d_fin->is_in_client_list = true;
+		if (!d40d->is_in_client_list) {
+			d40_desc_remove(d40d);
+			d40_lcla_free_all(d40c, d40d);
+			list_add_tail(&d40d->node, &d40c->client);
+			d40d->is_in_client_list = true;
 		}
 	}
 
@@ -890,7 +1091,7 @@
 
 	spin_unlock_irqrestore(&d40c->lock, flags);
 
-	if (callback)
+	if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
 		callback(callback_param);
 
 	return;
@@ -919,7 +1120,6 @@
 
 	int i;
 	u32 regs[ARRAY_SIZE(il)];
-	u32 tmp;
 	u32 idx;
 	u32 row;
 	long chan = -1;
@@ -946,9 +1146,7 @@
 		idx = chan & (BITS_PER_LONG - 1);
 
 		/* ACK interrupt */
-		tmp = readl(base->virtbase + il[row].clr);
-		tmp |= 1 << idx;
-		writel(tmp, base->virtbase + il[row].clr);
+		writel(1 << idx, base->virtbase + il[row].clr);
 
 		if (il[row].offset == D40_PHY_CHAN)
 			d40c = base->lookup_phy_chans[idx];
@@ -971,24 +1169,47 @@
 	return IRQ_HANDLED;
 }
 
-
 static int d40_validate_conf(struct d40_chan *d40c,
 			     struct stedma40_chan_cfg *conf)
 {
 	int res = 0;
 	u32 dst_event_group = D40_TYPE_TO_GROUP(conf->dst_dev_type);
 	u32 src_event_group = D40_TYPE_TO_GROUP(conf->src_dev_type);
-	bool is_log = (conf->channel_type & STEDMA40_CHANNEL_IN_OPER_MODE)
-		== STEDMA40_CHANNEL_IN_LOG_MODE;
+	bool is_log = conf->mode == STEDMA40_MODE_LOGICAL;
 
-	if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH &&
+	if (!conf->dir) {
+		dev_err(&d40c->chan.dev->device, "[%s] Invalid direction.\n",
+			__func__);
+		res = -EINVAL;
+	}
+
+	if (conf->dst_dev_type != STEDMA40_DEV_DST_MEMORY &&
+	    d40c->base->plat_data->dev_tx[conf->dst_dev_type] == 0 &&
+	    d40c->runtime_addr == 0) {
+
+		dev_err(&d40c->chan.dev->device,
+			"[%s] Invalid TX channel address (%d)\n",
+			__func__, conf->dst_dev_type);
+		res = -EINVAL;
+	}
+
+	if (conf->src_dev_type != STEDMA40_DEV_SRC_MEMORY &&
+	    d40c->base->plat_data->dev_rx[conf->src_dev_type] == 0 &&
+	    d40c->runtime_addr == 0) {
+		dev_err(&d40c->chan.dev->device,
+			"[%s] Invalid RX channel address (%d)\n",
+			__func__, conf->src_dev_type);
+		res = -EINVAL;
+	}
+
+	if (conf->dir == STEDMA40_MEM_TO_PERIPH &&
 	    dst_event_group == STEDMA40_DEV_DST_MEMORY) {
 		dev_err(&d40c->chan.dev->device, "[%s] Invalid dst\n",
 			__func__);
 		res = -EINVAL;
 	}
 
-	if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM &&
+	if (conf->dir == STEDMA40_PERIPH_TO_MEM &&
 	    src_event_group == STEDMA40_DEV_SRC_MEMORY) {
 		dev_err(&d40c->chan.dev->device, "[%s] Invalid src\n",
 			__func__);
@@ -1082,7 +1303,6 @@
 
 	spin_lock_irqsave(&phy->lock, flags);
 	if (!log_event_line) {
-		/* Physical interrupts are masked per physical full channel */
 		phy->allocated_dst = D40_ALLOC_FREE;
 		phy->allocated_src = D40_ALLOC_FREE;
 		is_free = true;
@@ -1119,10 +1339,7 @@
 	int j;
 	int log_num;
 	bool is_src;
-	bool is_log = (d40c->dma_cfg.channel_type &
-		       STEDMA40_CHANNEL_IN_OPER_MODE)
-		== STEDMA40_CHANNEL_IN_LOG_MODE;
-
+	bool is_log = d40c->dma_cfg.mode == STEDMA40_MODE_LOGICAL;
 
 	phys = d40c->base->phy_res;
 
@@ -1251,7 +1468,6 @@
 		list_for_each_entry_safe(d, _d, &d40c->client, node) {
 			d40_pool_lli_free(d);
 			d40_desc_remove(d);
-			/* Return desc to free-list */
 			d40_desc_free(d40c, d);
 		}
 
@@ -1324,37 +1540,12 @@
 		return res;
 	}
 	d40c->phy_chan = NULL;
-	/* Invalidate channel type */
-	d40c->dma_cfg.channel_type = 0;
+	d40c->configured = false;
 	d40c->base->lookup_phy_chans[phy->num] = NULL;
 
 	return 0;
 }
 
-static int d40_pause(struct dma_chan *chan)
-{
-	struct d40_chan *d40c =
-		container_of(chan, struct d40_chan, chan);
-	int res;
-	unsigned long flags;
-
-	spin_lock_irqsave(&d40c->lock, flags);
-
-	res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ);
-	if (res == 0) {
-		if (d40c->log_num != D40_PHY_CHAN) {
-			d40_config_set_event(d40c, false);
-			/* Resume the other logical channels if any */
-			if (d40_chan_has_events(d40c))
-				res = d40_channel_execute_command(d40c,
-								  D40_DMA_RUN);
-		}
-	}
-
-	spin_unlock_irqrestore(&d40c->lock, flags);
-	return res;
-}
-
 static bool d40_is_paused(struct d40_chan *d40c)
 {
 	bool is_paused = false;
@@ -1381,16 +1572,22 @@
 	}
 
 	if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH ||
-	    d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM)
+	    d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) {
 		event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type);
-	else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM)
+		status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+			       d40c->phy_chan->num * D40_DREG_PCDELTA +
+			       D40_CHAN_REG_SDLNK);
+	} else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) {
 		event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type);
-	else {
+		status = readl(d40c->base->virtbase + D40_DREG_PCBASE +
+			       d40c->phy_chan->num * D40_DREG_PCDELTA +
+			       D40_CHAN_REG_SSLNK);
+	} else {
 		dev_err(&d40c->chan.dev->device,
 			"[%s] Unknown direction\n", __func__);
 		goto _exit;
 	}
-	status = d40_chan_has_events(d40c);
+
 	status = (status & D40_EVENTLINE_MASK(event)) >>
 		D40_EVENTLINE_POS(event);
 
@@ -1403,64 +1600,6 @@
 }
 
 
-static bool d40_tx_is_linked(struct d40_chan *d40c)
-{
-	bool is_link;
-
-	if (d40c->log_num != D40_PHY_CHAN)
-		is_link = readl(&d40c->lcpa->lcsp3) &  D40_MEM_LCSP3_DLOS_MASK;
-	else
-		is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE +
-				d40c->phy_chan->num * D40_DREG_PCDELTA +
-				D40_CHAN_REG_SDLNK) &
-			D40_SREG_LNK_PHYS_LNK_MASK;
-	return is_link;
-}
-
-static u32 d40_residue(struct d40_chan *d40c)
-{
-	u32 num_elt;
-
-	if (d40c->log_num != D40_PHY_CHAN)
-		num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK)
-			>> D40_MEM_LCSP2_ECNT_POS;
-	else
-		num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE +
-				 d40c->phy_chan->num * D40_DREG_PCDELTA +
-				 D40_CHAN_REG_SDELT) &
-			   D40_SREG_ELEM_PHY_ECNT_MASK) >>
-			D40_SREG_ELEM_PHY_ECNT_POS;
-	return num_elt * (1 << d40c->dma_cfg.dst_info.data_width);
-}
-
-static int d40_resume(struct dma_chan *chan)
-{
-	struct d40_chan *d40c =
-		container_of(chan, struct d40_chan, chan);
-	int res = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&d40c->lock, flags);
-
-	if (d40c->base->rev == 0)
-		if (d40c->log_num != D40_PHY_CHAN) {
-			res = d40_channel_execute_command(d40c,
-							  D40_DMA_SUSPEND_REQ);
-			goto no_suspend;
-		}
-
-	/* If bytes left to transfer or linked tx resume job */
-	if (d40_residue(d40c) || d40_tx_is_linked(d40c)) {
-		if (d40c->log_num != D40_PHY_CHAN)
-			d40_config_set_event(d40c, true);
-		res = d40_channel_execute_command(d40c, D40_DMA_RUN);
-	}
-
-no_suspend:
-	spin_unlock_irqrestore(&d40c->lock, flags);
-	return res;
-}
-
 static u32 stedma40_residue(struct dma_chan *chan)
 {
 	struct d40_chan *d40c =
@@ -1475,51 +1614,6 @@
 	return bytes_left;
 }
 
-/* Public DMA functions in addition to the DMA engine framework */
-
-int stedma40_set_psize(struct dma_chan *chan,
-		       int src_psize,
-		       int dst_psize)
-{
-	struct d40_chan *d40c =
-		container_of(chan, struct d40_chan, chan);
-	unsigned long flags;
-
-	spin_lock_irqsave(&d40c->lock, flags);
-
-	if (d40c->log_num != D40_PHY_CHAN) {
-		d40c->log_def.lcsp1 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
-		d40c->log_def.lcsp3 &= ~D40_MEM_LCSP1_SCFG_PSIZE_MASK;
-		d40c->log_def.lcsp1 |= src_psize <<
-			D40_MEM_LCSP1_SCFG_PSIZE_POS;
-		d40c->log_def.lcsp3 |= dst_psize <<
-			D40_MEM_LCSP1_SCFG_PSIZE_POS;
-		goto out;
-	}
-
-	if (src_psize == STEDMA40_PSIZE_PHY_1)
-		d40c->src_def_cfg &= ~(1 << D40_SREG_CFG_PHY_PEN_POS);
-	else {
-		d40c->src_def_cfg |= 1 << D40_SREG_CFG_PHY_PEN_POS;
-		d40c->src_def_cfg &= ~(STEDMA40_PSIZE_PHY_16 <<
-				       D40_SREG_CFG_PSIZE_POS);
-		d40c->src_def_cfg |= src_psize << D40_SREG_CFG_PSIZE_POS;
-	}
-
-	if (dst_psize == STEDMA40_PSIZE_PHY_1)
-		d40c->dst_def_cfg &= ~(1 << D40_SREG_CFG_PHY_PEN_POS);
-	else {
-		d40c->dst_def_cfg |= 1 << D40_SREG_CFG_PHY_PEN_POS;
-		d40c->dst_def_cfg &= ~(STEDMA40_PSIZE_PHY_16 <<
-				       D40_SREG_CFG_PSIZE_POS);
-		d40c->dst_def_cfg |= dst_psize << D40_SREG_CFG_PSIZE_POS;
-	}
-out:
-	spin_unlock_irqrestore(&d40c->lock, flags);
-	return 0;
-}
-EXPORT_SYMBOL(stedma40_set_psize);
-
 struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan,
 						   struct scatterlist *sgl_dst,
 						   struct scatterlist *sgl_src,
@@ -1545,21 +1639,10 @@
 		goto err;
 
 	d40d->lli_len = sgl_len;
-	d40d->lli_tx_len = d40d->lli_len;
+	d40d->lli_current = 0;
 	d40d->txd.flags = dma_flags;
 
 	if (d40c->log_num != D40_PHY_CHAN) {
-		if (d40d->lli_len > d40c->base->plat_data->llis_per_log)
-			d40d->lli_tx_len = d40c->base->plat_data->llis_per_log;
-
-		if (sgl_len > 1)
-			/*
-			 * Check if there is space available in lcla. If not,
-			 * split list into 1-length and run only in lcpa
-			 * space.
-			 */
-			if (d40_lcla_id_get(d40c) != 0)
-				d40d->lli_tx_len = 1;
 
 		if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) {
 			dev_err(&d40c->chan.dev->device,
@@ -1567,27 +1650,17 @@
 			goto err;
 		}
 
-		(void) d40_log_sg_to_lli(d40c->lcla.src_id,
-					 sgl_src,
+		(void) d40_log_sg_to_lli(sgl_src,
 					 sgl_len,
 					 d40d->lli_log.src,
 					 d40c->log_def.lcsp1,
-					 d40c->dma_cfg.src_info.data_width,
-					 dma_flags & DMA_PREP_INTERRUPT,
-					 d40d->lli_tx_len,
-					 d40c->base->plat_data->llis_per_log);
+					 d40c->dma_cfg.src_info.data_width);
 
-		(void) d40_log_sg_to_lli(d40c->lcla.dst_id,
-					 sgl_dst,
+		(void) d40_log_sg_to_lli(sgl_dst,
 					 sgl_len,
 					 d40d->lli_log.dst,
 					 d40c->log_def.lcsp3,
-					 d40c->dma_cfg.dst_info.data_width,
-					 dma_flags & DMA_PREP_INTERRUPT,
-					 d40d->lli_tx_len,
-					 d40c->base->plat_data->llis_per_log);
-
-
+					 d40c->dma_cfg.dst_info.data_width);
 	} else {
 		if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) {
 			dev_err(&d40c->chan.dev->device,
@@ -1599,11 +1672,10 @@
 					sgl_len,
 					0,
 					d40d->lli_phy.src,
-					d40d->lli_phy.src_addr,
+					virt_to_phys(d40d->lli_phy.src),
 					d40c->src_def_cfg,
 					d40c->dma_cfg.src_info.data_width,
-					d40c->dma_cfg.src_info.psize,
-					true);
+					d40c->dma_cfg.src_info.psize);
 
 		if (res < 0)
 			goto err;
@@ -1612,11 +1684,10 @@
 					sgl_len,
 					0,
 					d40d->lli_phy.dst,
-					d40d->lli_phy.dst_addr,
+					virt_to_phys(d40d->lli_phy.dst),
 					d40c->dst_def_cfg,
 					d40c->dma_cfg.dst_info.data_width,
-					d40c->dma_cfg.dst_info.psize,
-					true);
+					d40c->dma_cfg.dst_info.psize);
 
 		if (res < 0)
 			goto err;
@@ -1633,6 +1704,8 @@
 
 	return &d40d->txd;
 err:
+	if (d40d)
+		d40_desc_free(d40c, d40d);
 	spin_unlock_irqrestore(&d40c->lock, flags);
 	return NULL;
 }
@@ -1652,6 +1725,9 @@
 	} else
 		err = d40_config_memcpy(d40c);
 
+	if (!err)
+		d40c->configured = true;
+
 	return err == 0;
 }
 EXPORT_SYMBOL(stedma40_filter);
@@ -1668,11 +1744,8 @@
 
 	d40c->completed = chan->cookie = 1;
 
-	/*
-	 * If no dma configuration is set (channel_type == 0)
-	 * use default configuration (memcpy)
-	 */
-	if (d40c->dma_cfg.channel_type == 0) {
+	/* If no dma configuration is set use default configuration (memcpy) */
+	if (!d40c->configured) {
 		err = d40_config_memcpy(d40c);
 		if (err) {
 			dev_err(&d40c->chan.dev->device,
@@ -1712,14 +1785,8 @@
 	 * resource is free. In case of multiple logical channels
 	 * on the same physical resource, only the first write is necessary.
 	 */
-	if (is_free_phy) {
-		err = d40_config_write(d40c);
-		if (err) {
-			dev_err(&d40c->chan.dev->device,
-				"[%s] Failed to configure channel\n",
-				__func__);
-		}
-	}
+	if (is_free_phy)
+		d40_config_write(d40c);
 fail:
 	spin_unlock_irqrestore(&d40c->lock, flags);
 	return err;
@@ -1790,23 +1857,21 @@
 			goto err;
 		}
 		d40d->lli_len = 1;
-		d40d->lli_tx_len = 1;
+		d40d->lli_current = 0;
 
 		d40_log_fill_lli(d40d->lli_log.src,
 				 src,
 				 size,
-				 0,
 				 d40c->log_def.lcsp1,
 				 d40c->dma_cfg.src_info.data_width,
-				 false, true);
+				 true);
 
 		d40_log_fill_lli(d40d->lli_log.dst,
 				 dst,
 				 size,
-				 0,
 				 d40c->log_def.lcsp3,
 				 d40c->dma_cfg.dst_info.data_width,
-				 true, true);
+				 true);
 
 	} else {
 
@@ -1851,12 +1916,25 @@
 err_fill_lli:
 	dev_err(&d40c->chan.dev->device,
 		"[%s] Failed filling in PHY LLI\n", __func__);
-	d40_pool_lli_free(d40d);
 err:
+	if (d40d)
+		d40_desc_free(d40c, d40d);
 	spin_unlock_irqrestore(&d40c->lock, flags);
 	return NULL;
 }
 
+static struct dma_async_tx_descriptor *
+d40_prep_sg(struct dma_chan *chan,
+	    struct scatterlist *dst_sg, unsigned int dst_nents,
+	    struct scatterlist *src_sg, unsigned int src_nents,
+	    unsigned long dma_flags)
+{
+	if (dst_nents != src_nents)
+		return NULL;
+
+	return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags);
+}
+
 static int d40_prep_slave_sg_log(struct d40_desc *d40d,
 				 struct d40_chan *d40c,
 				 struct scatterlist *sgl,
@@ -1874,19 +1952,7 @@
 	}
 
 	d40d->lli_len = sg_len;
-	if (d40d->lli_len <= d40c->base->plat_data->llis_per_log)
-		d40d->lli_tx_len = d40d->lli_len;
-	else
-		d40d->lli_tx_len = d40c->base->plat_data->llis_per_log;
-
-	if (sg_len > 1)
-		/*
-		 * Check if there is space available in lcla.
-		 * If not, split list into 1-length and run only
-		 * in lcpa space.
-		 */
-		if (d40_lcla_id_get(d40c) != 0)
-			d40d->lli_tx_len = 1;
+	d40d->lli_current = 0;
 
 	if (direction == DMA_FROM_DEVICE)
 		if (d40c->runtime_addr)
@@ -1902,16 +1968,13 @@
 	else
 		return -EINVAL;
 
-	total_size = d40_log_sg_to_dev(&d40c->lcla,
-				       sgl, sg_len,
+	total_size = d40_log_sg_to_dev(sgl, sg_len,
 				       &d40d->lli_log,
 				       &d40c->log_def,
 				       d40c->dma_cfg.src_info.data_width,
 				       d40c->dma_cfg.dst_info.data_width,
 				       direction,
-				       dma_flags & DMA_PREP_INTERRUPT,
-				       dev_addr, d40d->lli_tx_len,
-				       d40c->base->plat_data->llis_per_log);
+				       dev_addr);
 
 	if (total_size < 0)
 		return -EINVAL;
@@ -1937,7 +2000,7 @@
 	}
 
 	d40d->lli_len = sgl_len;
-	d40d->lli_tx_len = sgl_len;
+	d40d->lli_current = 0;
 
 	if (direction == DMA_FROM_DEVICE) {
 		dst_dev_addr = 0;
@@ -1958,11 +2021,10 @@
 				sgl_len,
 				src_dev_addr,
 				d40d->lli_phy.src,
-				d40d->lli_phy.src_addr,
+				virt_to_phys(d40d->lli_phy.src),
 				d40c->src_def_cfg,
 				d40c->dma_cfg.src_info.data_width,
-				d40c->dma_cfg.src_info.psize,
-				true);
+				d40c->dma_cfg.src_info.psize);
 	if (res < 0)
 		return res;
 
@@ -1970,11 +2032,10 @@
 				sgl_len,
 				dst_dev_addr,
 				d40d->lli_phy.dst,
-				d40d->lli_phy.dst_addr,
+				virt_to_phys(d40d->lli_phy.dst),
 				d40c->dst_def_cfg,
 				d40c->dma_cfg.dst_info.data_width,
-				d40c->dma_cfg.dst_info.psize,
-				 true);
+				d40c->dma_cfg.dst_info.psize);
 	if (res < 0)
 		return res;
 
@@ -2001,17 +2062,11 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	if (d40c->dma_cfg.pre_transfer)
-		d40c->dma_cfg.pre_transfer(chan,
-					   d40c->dma_cfg.pre_transfer_data,
-					   sg_dma_len(sgl));
-
 	spin_lock_irqsave(&d40c->lock, flags);
 	d40d = d40_desc_get(d40c);
-	spin_unlock_irqrestore(&d40c->lock, flags);
 
 	if (d40d == NULL)
-		return NULL;
+		goto err;
 
 	if (d40c->log_num != D40_PHY_CHAN)
 		err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len,
@@ -2024,7 +2079,7 @@
 			"[%s] Failed to prepare %s slave sg job: %d\n",
 			__func__,
 			d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err);
-		return NULL;
+		goto err;
 	}
 
 	d40d->txd.flags = dma_flags;
@@ -2033,7 +2088,14 @@
 
 	d40d->txd.tx_submit = d40_tx_submit;
 
+	spin_unlock_irqrestore(&d40c->lock, flags);
 	return &d40d->txd;
+
+err:
+	if (d40d)
+		d40_desc_free(d40c, d40d);
+	spin_unlock_irqrestore(&d40c->lock, flags);
+	return NULL;
 }
 
 static enum dma_status d40_tx_status(struct dma_chan *chan,
@@ -2166,25 +2228,43 @@
 		return;
 	}
 
-	if (config_maxburst >= 16)
-		psize = STEDMA40_PSIZE_LOG_16;
-	else if (config_maxburst >= 8)
-		psize = STEDMA40_PSIZE_LOG_8;
-	else if (config_maxburst >= 4)
-		psize = STEDMA40_PSIZE_LOG_4;
-	else
-		psize = STEDMA40_PSIZE_LOG_1;
+	if (d40c->log_num != D40_PHY_CHAN) {
+		if (config_maxburst >= 16)
+			psize = STEDMA40_PSIZE_LOG_16;
+		else if (config_maxburst >= 8)
+			psize = STEDMA40_PSIZE_LOG_8;
+		else if (config_maxburst >= 4)
+			psize = STEDMA40_PSIZE_LOG_4;
+		else
+			psize = STEDMA40_PSIZE_LOG_1;
+	} else {
+		if (config_maxburst >= 16)
+			psize = STEDMA40_PSIZE_PHY_16;
+		else if (config_maxburst >= 8)
+			psize = STEDMA40_PSIZE_PHY_8;
+		else if (config_maxburst >= 4)
+			psize = STEDMA40_PSIZE_PHY_4;
+		else
+			psize = STEDMA40_PSIZE_PHY_1;
+	}
 
 	/* Set up all the endpoint configs */
 	cfg->src_info.data_width = addr_width;
 	cfg->src_info.psize = psize;
-	cfg->src_info.endianess = STEDMA40_LITTLE_ENDIAN;
+	cfg->src_info.big_endian = false;
 	cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
 	cfg->dst_info.data_width = addr_width;
 	cfg->dst_info.psize = psize;
-	cfg->dst_info.endianess = STEDMA40_LITTLE_ENDIAN;
+	cfg->dst_info.big_endian = false;
 	cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
 
+	/* Fill in register values */
+	if (d40c->log_num != D40_PHY_CHAN)
+		d40_log_cfg(cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3);
+	else
+		d40_phy_cfg(cfg, &d40c->src_def_cfg,
+			    &d40c->dst_def_cfg, false);
+
 	/* These settings will take precedence later */
 	d40c->runtime_addr = config_addr;
 	d40c->runtime_direction = config->direction;
@@ -2247,10 +2327,6 @@
 		d40c->base = base;
 		d40c->chan.device = dma;
 
-		/* Invalidate lcla element */
-		d40c->lcla.src_id = -1;
-		d40c->lcla.dst_id = -1;
-
 		spin_lock_init(&d40c->lock);
 
 		d40c->log_num = D40_PHY_CHAN;
@@ -2281,6 +2357,7 @@
 	base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources;
 	base->dma_slave.device_free_chan_resources = d40_free_chan_resources;
 	base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
+	base->dma_slave.device_prep_dma_sg = d40_prep_sg;
 	base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
 	base->dma_slave.device_tx_status = d40_tx_status;
 	base->dma_slave.device_issue_pending = d40_issue_pending;
@@ -2301,10 +2378,12 @@
 
 	dma_cap_zero(base->dma_memcpy.cap_mask);
 	dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask);
+	dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
 
 	base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources;
 	base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources;
 	base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
+	base->dma_slave.device_prep_dma_sg = d40_prep_sg;
 	base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
 	base->dma_memcpy.device_tx_status = d40_tx_status;
 	base->dma_memcpy.device_issue_pending = d40_issue_pending;
@@ -2331,10 +2410,12 @@
 	dma_cap_zero(base->dma_both.cap_mask);
 	dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask);
 	dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask);
+	dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
 
 	base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources;
 	base->dma_both.device_free_chan_resources = d40_free_chan_resources;
 	base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
+	base->dma_slave.device_prep_dma_sg = d40_prep_sg;
 	base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
 	base->dma_both.device_tx_status = d40_tx_status;
 	base->dma_both.device_issue_pending = d40_issue_pending;
@@ -2387,9 +2468,11 @@
 
 	/* Mark disabled channels as occupied */
 	for (i = 0; base->plat_data->disabled_channels[i] != -1; i++) {
-			base->phy_res[i].allocated_src = D40_ALLOC_PHY;
-			base->phy_res[i].allocated_dst = D40_ALLOC_PHY;
-			num_phy_chans_avail--;
+		int chan = base->plat_data->disabled_channels[i];
+
+		base->phy_res[chan].allocated_src = D40_ALLOC_PHY;
+		base->phy_res[chan].allocated_dst = D40_ALLOC_PHY;
+		num_phy_chans_avail--;
 	}
 
 	dev_info(base->dev, "%d of %d physical DMA channels available\n",
@@ -2441,6 +2524,7 @@
 	int num_phy_chans;
 	int i;
 	u32 val;
+	u32 rev;
 
 	clk = clk_get(&pdev->dev, NULL);
 
@@ -2479,21 +2563,26 @@
 		}
 	}
 
-	/* Get silicon revision */
+	/* Get silicon revision and designer */
 	val = readl(virtbase + D40_DREG_PERIPHID2);
 
-	if ((val & 0xf) != D40_PERIPHID2_DESIGNER) {
+	if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) !=
+	    D40_HW_DESIGNER) {
 		dev_err(&pdev->dev,
 			"[%s] Unknown designer! Got %x wanted %x\n",
-			__func__, val & 0xf, D40_PERIPHID2_DESIGNER);
+			__func__, val & D40_DREG_PERIPHID2_DESIGNER_MASK,
+			D40_HW_DESIGNER);
 		goto failure;
 	}
 
+	rev = (val & D40_DREG_PERIPHID2_REV_MASK) >>
+		D40_DREG_PERIPHID2_REV_POS;
+
 	/* The number of physical channels on this HW */
 	num_phy_chans = 4 * (readl(virtbase + D40_DREG_ICFG) & 0x7) + 4;
 
 	dev_info(&pdev->dev, "hardware revision: %d @ 0x%x\n",
-		 (val >> 4) & 0xf, res->start);
+		 rev, res->start);
 
 	plat_data = pdev->dev.platform_data;
 
@@ -2515,7 +2604,7 @@
 		goto failure;
 	}
 
-	base->rev = (val >> 4) & 0xf;
+	base->rev = rev;
 	base->clk = clk;
 	base->num_phy_chans = num_phy_chans;
 	base->num_log_chans = num_log_chans;
@@ -2549,7 +2638,10 @@
 		if (!base->lookup_log_chans)
 			goto failure;
 	}
-	base->lcla_pool.alloc_map = kzalloc(num_phy_chans * sizeof(u32),
+
+	base->lcla_pool.alloc_map = kzalloc(num_phy_chans *
+					    sizeof(struct d40_desc *) *
+					    D40_LCLA_LINK_PER_EVENT_GRP,
 					    GFP_KERNEL);
 	if (!base->lcla_pool.alloc_map)
 		goto failure;
@@ -2563,7 +2655,7 @@
 	return base;
 
 failure:
-	if (clk) {
+	if (!IS_ERR(clk)) {
 		clk_disable(clk);
 		clk_put(clk);
 	}
@@ -2700,8 +2792,10 @@
 	if (i < MAX_LCLA_ALLOC_ATTEMPTS) {
 		base->lcla_pool.base = (void *)page_list[i];
 	} else {
-		/* After many attempts, no succees with finding the correct
-		 * alignment try with allocating a big buffer */
+		/*
+		 * After many attempts and no succees with finding the correct
+		 * alignment, try with allocating a big buffer.
+		 */
 		dev_warn(base->dev,
 			 "[%s] Failed to get %d pages @ 18 bit align.\n",
 			 __func__, base->lcla_pool.pages);
@@ -2794,8 +2888,6 @@
 
 	spin_lock_init(&base->lcla_pool.lock);
 
-	base->lcla_pool.num_blocks = base->num_phy_chans;
-
 	base->irq = platform_get_irq(pdev, 0);
 
 	ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
@@ -2823,8 +2915,9 @@
 		if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
 			free_pages((unsigned long)base->lcla_pool.base,
 				   base->lcla_pool.pages);
-		if (base->lcla_pool.base_unaligned)
-			kfree(base->lcla_pool.base_unaligned);
+
+		kfree(base->lcla_pool.base_unaligned);
+
 		if (base->phy_lcpa)
 			release_mem_region(base->phy_lcpa,
 					   base->lcpa_size);
diff -druN linux-libre-2.6.36-gnu/drivers/dma/ste_dma40_ll.c linux-libre-2.6.37-gnu/drivers/dma/ste_dma40_ll.c
--- linux-libre-2.6.36-gnu/drivers/dma/ste_dma40_ll.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/ste_dma40_ll.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,8 @@
 /*
- * driver/dma/ste_dma40_ll.c
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
  */
 
 #include <linux/kernel.h>
@@ -39,16 +37,13 @@
 	    cfg->dir ==  STEDMA40_PERIPH_TO_PERIPH)
 		l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS;
 
-	l3 |= 1 << D40_MEM_LCSP3_DCFG_TIM_POS;
 	l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS;
 	l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS;
 	l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS;
-	l3 |= 1 << D40_MEM_LCSP3_DTCP_POS;
 
 	l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS;
 	l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
 	l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS;
-	l1 |= 1 << D40_MEM_LCSP1_STCP_POS;
 
 	*lcsp1 = l1;
 	*lcsp3 = l3;
@@ -113,13 +108,15 @@
 		src |= 1 << D40_SREG_CFG_LOG_GIM_POS;
 	}
 
-	if (cfg->channel_type & STEDMA40_HIGH_PRIORITY_CHANNEL) {
+	if (cfg->high_priority) {
 		src |= 1 << D40_SREG_CFG_PRI_POS;
 		dst |= 1 << D40_SREG_CFG_PRI_POS;
 	}
 
-	src |= cfg->src_info.endianess << D40_SREG_CFG_LBE_POS;
-	dst |= cfg->dst_info.endianess << D40_SREG_CFG_LBE_POS;
+	if (cfg->src_info.big_endian)
+		src |= 1 << D40_SREG_CFG_LBE_POS;
+	if (cfg->dst_info.big_endian)
+		dst |= 1 << D40_SREG_CFG_LBE_POS;
 
 	*src_cfg = src;
 	*dst_cfg = dst;
@@ -197,8 +194,7 @@
 		      dma_addr_t lli_phys,
 		      u32 reg_cfg,
 		      u32 data_width,
-		      int psize,
-		      bool term_int)
+		      int psize)
 {
 	int total_size = 0;
 	int i;
@@ -238,7 +234,7 @@
 	}
 
 	return total_size;
- err:
+err:
 	return err;
 }
 
@@ -271,11 +267,59 @@
 
 /* DMA logical lli operations */
 
+static void d40_log_lli_link(struct d40_log_lli *lli_dst,
+			     struct d40_log_lli *lli_src,
+			     int next)
+{
+	u32 slos = 0;
+	u32 dlos = 0;
+
+	if (next != -EINVAL) {
+		slos = next * 2;
+		dlos = next * 2 + 1;
+	} else {
+		lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
+		lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
+	}
+
+	lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+		(slos << D40_MEM_LCSP1_SLOS_POS);
+
+	lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) |
+		(dlos << D40_MEM_LCSP1_SLOS_POS);
+}
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+			   struct d40_log_lli *lli_dst,
+			   struct d40_log_lli *lli_src,
+			   int next)
+{
+	d40_log_lli_link(lli_dst, lli_src, next);
+
+	writel(lli_src->lcsp02, &lcpa[0].lcsp0);
+	writel(lli_src->lcsp13, &lcpa[0].lcsp1);
+	writel(lli_dst->lcsp02, &lcpa[0].lcsp2);
+	writel(lli_dst->lcsp13, &lcpa[0].lcsp3);
+}
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+			   struct d40_log_lli *lli_dst,
+			   struct d40_log_lli *lli_src,
+			   int next)
+{
+	d40_log_lli_link(lli_dst, lli_src, next);
+
+	writel(lli_src->lcsp02, &lcla[0].lcsp02);
+	writel(lli_src->lcsp13, &lcla[0].lcsp13);
+	writel(lli_dst->lcsp02, &lcla[1].lcsp02);
+	writel(lli_dst->lcsp13, &lcla[1].lcsp13);
+}
+
 void d40_log_fill_lli(struct d40_log_lli *lli,
 		      dma_addr_t data, u32 data_size,
-		      u32 lli_next_off, u32 reg_cfg,
+		      u32 reg_cfg,
 		      u32 data_width,
-		      bool term_int, bool addr_inc)
+		      bool addr_inc)
 {
 	lli->lcsp13 = reg_cfg;
 
@@ -290,165 +334,69 @@
 	if (addr_inc)
 		lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK;
 
-	lli->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
-	/* If this scatter list entry is the last one, no next link */
-	lli->lcsp13 |= (lli_next_off << D40_MEM_LCSP1_SLOS_POS) &
-		D40_MEM_LCSP1_SLOS_MASK;
-
-	if (term_int)
-		lli->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
-	else
-		lli->lcsp13 &= ~D40_MEM_LCSP1_SCFG_TIM_MASK;
 }
 
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
-		      struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
 		      int sg_len,
 		      struct d40_log_lli_bidir *lli,
 		      struct d40_def_lcsp *lcsp,
 		      u32 src_data_width,
 		      u32 dst_data_width,
 		      enum dma_data_direction direction,
-		      bool term_int, dma_addr_t dev_addr, int max_len,
-		      int llis_per_log)
+		      dma_addr_t dev_addr)
 {
 	int total_size = 0;
 	struct scatterlist *current_sg = sg;
 	int i;
-	u32 next_lli_off_dst = 0;
-	u32 next_lli_off_src = 0;
 
 	for_each_sg(sg, current_sg, sg_len, i) {
 		total_size += sg_dma_len(current_sg);
 
-		/*
-		 * If this scatter list entry is the last one or
-		 * max length, terminate link.
-		 */
-		if (sg_len - 1 == i || ((i+1) % max_len == 0)) {
-			next_lli_off_src = 0;
-			next_lli_off_dst = 0;
-		} else {
-			if (next_lli_off_dst == 0 &&
-			    next_lli_off_src == 0) {
-				/* The first lli will be at next_lli_off */
-				next_lli_off_dst = (lcla->dst_id *
-						    llis_per_log + 1);
-				next_lli_off_src = (lcla->src_id *
-						    llis_per_log + 1);
-			} else {
-				next_lli_off_dst++;
-				next_lli_off_src++;
-			}
-		}
-
 		if (direction == DMA_TO_DEVICE) {
 			d40_log_fill_lli(&lli->src[i],
 					 sg_phys(current_sg),
 					 sg_dma_len(current_sg),
-					 next_lli_off_src,
 					 lcsp->lcsp1, src_data_width,
-					 false,
 					 true);
 			d40_log_fill_lli(&lli->dst[i],
 					 dev_addr,
 					 sg_dma_len(current_sg),
-					 next_lli_off_dst,
 					 lcsp->lcsp3, dst_data_width,
-					 /* No next == terminal interrupt */
-					 term_int && !next_lli_off_dst,
 					 false);
 		} else {
 			d40_log_fill_lli(&lli->dst[i],
 					 sg_phys(current_sg),
 					 sg_dma_len(current_sg),
-					 next_lli_off_dst,
 					 lcsp->lcsp3, dst_data_width,
-					 /* No next == terminal interrupt */
-					 term_int && !next_lli_off_dst,
 					 true);
 			d40_log_fill_lli(&lli->src[i],
 					 dev_addr,
 					 sg_dma_len(current_sg),
-					 next_lli_off_src,
 					 lcsp->lcsp1, src_data_width,
-					 false,
 					 false);
 		}
 	}
 	return total_size;
 }
 
-int d40_log_sg_to_lli(int lcla_id,
-		      struct scatterlist *sg,
+int d40_log_sg_to_lli(struct scatterlist *sg,
 		      int sg_len,
 		      struct d40_log_lli *lli_sg,
 		      u32 lcsp13, /* src or dst*/
-		      u32 data_width,
-		      bool term_int, int max_len, int llis_per_log)
+		      u32 data_width)
 {
 	int total_size = 0;
 	struct scatterlist *current_sg = sg;
 	int i;
-	u32 next_lli_off = 0;
 
 	for_each_sg(sg, current_sg, sg_len, i) {
 		total_size += sg_dma_len(current_sg);
 
-		/*
-		 * If this scatter list entry is the last one or
-		 * max length, terminate link.
-		 */
-		if (sg_len - 1 == i || ((i+1) % max_len == 0))
-			next_lli_off = 0;
-		else {
-			if (next_lli_off == 0)
-				/* The first lli will be at next_lli_off */
-				next_lli_off = lcla_id * llis_per_log + 1;
-			else
-				next_lli_off++;
-		}
-
 		d40_log_fill_lli(&lli_sg[i],
 				 sg_phys(current_sg),
 				 sg_dma_len(current_sg),
-				 next_lli_off,
 				 lcsp13, data_width,
-				 term_int && !next_lli_off,
 				 true);
 	}
 	return total_size;
 }
-
-int d40_log_lli_write(struct d40_log_lli_full *lcpa,
-		       struct d40_log_lli *lcla_src,
-		       struct d40_log_lli *lcla_dst,
-		       struct d40_log_lli *lli_dst,
-		       struct d40_log_lli *lli_src,
-		       int llis_per_log)
-{
-	u32 slos;
-	u32 dlos;
-	int i;
-
-	writel(lli_src->lcsp02, &lcpa->lcsp0);
-	writel(lli_src->lcsp13, &lcpa->lcsp1);
-	writel(lli_dst->lcsp02, &lcpa->lcsp2);
-	writel(lli_dst->lcsp13, &lcpa->lcsp3);
-
-	slos = lli_src->lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
-	dlos = lli_dst->lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
-
-	for (i = 0; (i < llis_per_log) && slos && dlos; i++) {
-		writel(lli_src[i + 1].lcsp02, &lcla_src[i].lcsp02);
-		writel(lli_src[i + 1].lcsp13, &lcla_src[i].lcsp13);
-		writel(lli_dst[i + 1].lcsp02, &lcla_dst[i].lcsp02);
-		writel(lli_dst[i + 1].lcsp13, &lcla_dst[i].lcsp13);
-
-		slos = lli_src[i + 1].lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
-		dlos = lli_dst[i + 1].lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
-	}
-
-	return i;
-
-}
diff -druN linux-libre-2.6.36-gnu/drivers/dma/ste_dma40_ll.h linux-libre-2.6.37-gnu/drivers/dma/ste_dma40_ll.h
--- linux-libre-2.6.36-gnu/drivers/dma/ste_dma40_ll.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/ste_dma40_ll.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,8 @@
 /*
- * driver/dma/ste_dma40_ll.h
- *
- * Copyright (C) ST-Ericsson 2007-2010
+ * Copyright (C) ST-Ericsson SA 2007-2010
+ * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson SA
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson SA
  * License terms: GNU General Public License (GPL) version 2
- * Author: Per Friden <per.friden@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
  */
 #ifndef STE_DMA40_LL_H
 #define STE_DMA40_LL_H
@@ -132,6 +130,13 @@
 #define D40_DREG_PRMSO		0x014
 #define D40_DREG_PRMOE		0x018
 #define D40_DREG_PRMOO		0x01C
+#define D40_DREG_PRMO_PCHAN_BASIC		0x1
+#define D40_DREG_PRMO_PCHAN_MODULO		0x2
+#define D40_DREG_PRMO_PCHAN_DOUBLE_DST		0x3
+#define D40_DREG_PRMO_LCHAN_SRC_PHY_DST_LOG	0x1
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_PHY	0x2
+#define D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG	0x3
+
 #define D40_DREG_LCPA		0x020
 #define D40_DREG_LCLA		0x024
 #define D40_DREG_ACTIVE		0x050
@@ -163,6 +168,9 @@
 #define D40_DREG_PERIPHID0	0xFE0
 #define D40_DREG_PERIPHID1	0xFE4
 #define D40_DREG_PERIPHID2	0xFE8
+#define D40_DREG_PERIPHID2_REV_POS 4
+#define D40_DREG_PERIPHID2_REV_MASK (0xf << D40_DREG_PERIPHID2_REV_POS)
+#define D40_DREG_PERIPHID2_DESIGNER_MASK 0xf
 #define D40_DREG_PERIPHID3	0xFEC
 #define D40_DREG_CELLID0	0xFF0
 #define D40_DREG_CELLID1	0xFF4
@@ -199,8 +207,6 @@
  *
  * @src: Register settings for src channel.
  * @dst: Register settings for dst channel.
- * @dst_addr: Physical destination address.
- * @src_addr: Physical source address.
  *
  * All DMA transfers have a source and a destination.
  */
@@ -208,8 +214,6 @@
 struct d40_phy_lli_bidir {
 	struct d40_phy_lli	*src;
 	struct d40_phy_lli	*dst;
-	dma_addr_t		 dst_addr;
-	dma_addr_t		 src_addr;
 };
 
 
@@ -271,29 +275,16 @@
 	u32 lcsp1;
 };
 
-/**
- * struct d40_lcla_elem - Info for one LCA element.
- *
- * @src_id: logical channel src id
- * @dst_id: logical channel dst id
- * @src: LCPA formated src parameters
- * @dst: LCPA formated dst parameters
- *
- */
-struct d40_lcla_elem {
-	int			src_id;
-	int			dst_id;
-	struct d40_log_lli     *src;
-	struct d40_log_lli     *dst;
-};
-
 /* Physical channels */
 
 void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
-		 u32 *src_cfg, u32 *dst_cfg, bool is_log);
+		 u32 *src_cfg,
+		 u32 *dst_cfg,
+		 bool is_log);
 
 void d40_log_cfg(struct stedma40_chan_cfg *cfg,
-		 u32 *lcsp1, u32 *lcsp2);
+		 u32 *lcsp1,
+		 u32 *lcsp2);
 
 int d40_phy_sg_to_lli(struct scatterlist *sg,
 		      int sg_len,
@@ -302,8 +293,7 @@
 		      dma_addr_t lli_phys,
 		      u32 reg_cfg,
 		      u32 data_width,
-		      int psize,
-		      bool term_int);
+		      int psize);
 
 int d40_phy_fill_lli(struct d40_phy_lli *lli,
 		     dma_addr_t data,
@@ -323,35 +313,35 @@
 /* Logical channels */
 
 void d40_log_fill_lli(struct d40_log_lli *lli,
-		      dma_addr_t data, u32 data_size,
-		      u32 lli_next_off, u32 reg_cfg,
+		      dma_addr_t data,
+		      u32 data_size,
+		      u32 reg_cfg,
 		      u32 data_width,
-		      bool term_int, bool addr_inc);
+		      bool addr_inc);
 
-int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
-		      struct scatterlist *sg,
+int d40_log_sg_to_dev(struct scatterlist *sg,
 		      int sg_len,
 		      struct d40_log_lli_bidir *lli,
 		      struct d40_def_lcsp *lcsp,
 		      u32 src_data_width,
 		      u32 dst_data_width,
 		      enum dma_data_direction direction,
-		      bool term_int, dma_addr_t dev_addr, int max_len,
-		      int llis_per_log);
-
-int d40_log_lli_write(struct d40_log_lli_full *lcpa,
-		      struct d40_log_lli *lcla_src,
-		      struct d40_log_lli *lcla_dst,
-		      struct d40_log_lli *lli_dst,
-		      struct d40_log_lli *lli_src,
-		      int llis_per_log);
+		      dma_addr_t dev_addr);
 
-int d40_log_sg_to_lli(int lcla_id,
-		      struct scatterlist *sg,
+int d40_log_sg_to_lli(struct scatterlist *sg,
 		      int sg_len,
 		      struct d40_log_lli *lli_sg,
 		      u32 lcsp13, /* src or dst*/
-		      u32 data_width,
-		      bool term_int, int max_len, int llis_per_log);
+		      u32 data_width);
+
+void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa,
+			    struct d40_log_lli *lli_dst,
+			    struct d40_log_lli *lli_src,
+			    int next);
+
+void d40_log_lli_lcla_write(struct d40_log_lli *lcla,
+			    struct d40_log_lli *lli_dst,
+			    struct d40_log_lli *lli_src,
+			    int next);
 
 #endif /* STE_DMA40_LLI_H */
diff -druN linux-libre-2.6.36-gnu/drivers/dma/timb_dma.c linux-libre-2.6.37-gnu/drivers/dma/timb_dma.c
--- linux-libre-2.6.36-gnu/drivers/dma/timb_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/dma/timb_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -759,7 +759,7 @@
 			pdata->channels + i;
 
 		/* even channels are RX, odd are TX */
-		if (((i % 2) && pchan->rx) || (!(i % 2) && !pchan->rx)) {
+		if ((i % 2) == pchan->rx) {
 			dev_err(&pdev->dev, "Wrong channel configuration\n");
 			err = -EINVAL;
 			goto err_tasklet_kill;
diff -druN linux-libre-2.6.36-gnu/drivers/edac/amd64_edac.c linux-libre-2.6.37-gnu/drivers/edac/amd64_edac.c
--- linux-libre-2.6.36-gnu/drivers/edac/amd64_edac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/amd64_edac.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 #include "amd64_edac.h"
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 static struct edac_pci_ctl_info *amd64_ctl_pci;
 
@@ -1572,7 +1572,7 @@
 	debugf1("   HoleOffset=0x%x  HoleValid=0x%x IntlvSel=0x%x\n",
 			hole_off, hole_valid, intlv_sel);
 
-	if (intlv_en ||
+	if (intlv_en &&
 	    (intlv_sel != ((sys_addr >> 12) & intlv_en)))
 		return -EINVAL;
 
@@ -2073,11 +2073,18 @@
 		amd64_handle_ue(mci, info);
 }
 
-void amd64_decode_bus_error(int node_id, struct err_regs *regs)
+void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
 {
 	struct mem_ctl_info *mci = mci_lookup[node_id];
+	struct err_regs regs;
 
-	__amd64_decode_bus_error(mci, regs);
+	regs.nbsl  = (u32) m->status;
+	regs.nbsh  = (u32)(m->status >> 32);
+	regs.nbeal = (u32) m->addr;
+	regs.nbeah = (u32)(m->addr >> 32);
+	regs.nbcfg = nbcfg;
+
+	__amd64_decode_bus_error(mci, &regs);
 
 	/*
 	 * Check the UE bit of the NB status high register, if set generate some
@@ -2086,7 +2093,7 @@
 	 *
 	 * FIXME: this should go somewhere else, if at all.
 	 */
-	if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
+	if (regs.nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
 		edac_mc_handle_ue_no_info(mci, "UE bit is set");
 
 }
@@ -2927,7 +2934,7 @@
 	 * to finish initialization of the MC instances.
 	 */
 	err = -ENODEV;
-	for (nb = 0; nb < num_k8_northbridges; nb++) {
+	for (nb = 0; nb < k8_northbridges.num; nb++) {
 		if (!pvt_lookup[nb])
 			continue;
 
diff -druN linux-libre-2.6.36-gnu/drivers/edac/amd64_edac_dbg.c linux-libre-2.6.37-gnu/drivers/edac/amd64_edac_dbg.c
--- linux-libre-2.6.36-gnu/drivers/edac/amd64_edac_dbg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/amd64_edac_dbg.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,167 +1,16 @@
 #include "amd64_edac.h"
 
-/*
- * accept a hex value and store it into the virtual error register file, field:
- * nbeal and nbeah. Assume virtual error values have already been set for: NBSL,
- * NBSH and NBCFG. Then proceed to map the error values to a MC, CSROW and
- * CHANNEL
- */
-static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data,
-				size_t count)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	unsigned long long value;
-	int ret = 0;
-
-	ret = strict_strtoull(data, 16, &value);
-	if (ret != -EINVAL) {
-		debugf0("received NBEA= 0x%llx\n", value);
-
-		/* place the value into the virtual error packet */
-		pvt->ctl_error_info.nbeal = (u32) value;
-		value >>= 32;
-		pvt->ctl_error_info.nbeah = (u32) value;
-
-		/* Process the Mapping request */
-		/* TODO: Add race prevention */
-		amd_decode_nb_mce(pvt->mc_node_id, &pvt->ctl_error_info, 1);
-
-		return count;
-	}
-	return ret;
-}
-
-/* display back what the last NBEA (MCA NB Address (MC4_ADDR)) was written */
-static ssize_t amd64_nbea_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	u64 value;
-
-	value = pvt->ctl_error_info.nbeah;
-	value <<= 32;
-	value |= pvt->ctl_error_info.nbeal;
-
-	return sprintf(data, "%llx\n", value);
-}
-
-/* store the NBSL (MCA NB Status Low (MC4_STATUS)) value user desires */
-static ssize_t amd64_nbsl_store(struct mem_ctl_info *mci, const char *data,
-				size_t count)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	unsigned long value;
-	int ret = 0;
-
-	ret = strict_strtoul(data, 16, &value);
-	if (ret != -EINVAL) {
-		debugf0("received NBSL= 0x%lx\n", value);
-
-		pvt->ctl_error_info.nbsl = (u32) value;
-
-		return count;
-	}
-	return ret;
-}
-
-/* display back what the last NBSL value written */
-static ssize_t amd64_nbsl_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	u32 value;
-
-	value = pvt->ctl_error_info.nbsl;
-
-	return sprintf(data, "%x\n", value);
-}
-
-/* store the NBSH (MCA NB Status High) value user desires */
-static ssize_t amd64_nbsh_store(struct mem_ctl_info *mci, const char *data,
-				size_t count)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	unsigned long value;
-	int ret = 0;
-
-	ret = strict_strtoul(data, 16, &value);
-	if (ret != -EINVAL) {
-		debugf0("received NBSH= 0x%lx\n", value);
-
-		pvt->ctl_error_info.nbsh = (u32) value;
-
-		return count;
-	}
-	return ret;
-}
-
-/* display back what the last NBSH value written */
-static ssize_t amd64_nbsh_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	u32 value;
-
-	value = pvt->ctl_error_info.nbsh;
-
-	return sprintf(data, "%x\n", value);
-}
-
-/* accept and store the NBCFG (MCA NB Configuration) value user desires */
-static ssize_t amd64_nbcfg_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-	unsigned long value;
-	int ret = 0;
-
-	ret = strict_strtoul(data, 16, &value);
-	if (ret != -EINVAL) {
-		debugf0("received NBCFG= 0x%lx\n", value);
-
-		pvt->ctl_error_info.nbcfg = (u32) value;
-
-		return count;
-	}
-	return ret;
-}
-
-/* various show routines for the controls of a MCI */
-static ssize_t amd64_nbcfg_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-
-	return sprintf(data, "%x\n", pvt->ctl_error_info.nbcfg);
-}
-
-
-static ssize_t amd64_dhar_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-
-	return sprintf(data, "%x\n", pvt->dhar);
-}
-
-
-static ssize_t amd64_dbam_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-
-	return sprintf(data, "%x\n", pvt->dbam0);
-}
-
-
-static ssize_t amd64_topmem_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-
-	return sprintf(data, "%llx\n", pvt->top_mem);
+#define EDAC_DCT_ATTR_SHOW(reg)						\
+static ssize_t amd64_##reg##_show(struct mem_ctl_info *mci, char *data)	\
+{									\
+	struct amd64_pvt *pvt = mci->pvt_info;				\
+		return sprintf(data, "0x%016llx\n", (u64)pvt->reg);	\
 }
 
-
-static ssize_t amd64_topmem2_show(struct mem_ctl_info *mci, char *data)
-{
-	struct amd64_pvt *pvt = mci->pvt_info;
-
-	return sprintf(data, "%llx\n", pvt->top_mem2);
-}
+EDAC_DCT_ATTR_SHOW(dhar);
+EDAC_DCT_ATTR_SHOW(dbam0);
+EDAC_DCT_ATTR_SHOW(top_mem);
+EDAC_DCT_ATTR_SHOW(top_mem2);
 
 static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
 {
@@ -182,38 +31,6 @@
 
 	{
 		.attr = {
-			.name = "nbea_ctl",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_nbea_show,
-		.store = amd64_nbea_store,
-	},
-	{
-		.attr = {
-			.name = "nbsl_ctl",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_nbsl_show,
-		.store = amd64_nbsl_store,
-	},
-	{
-		.attr = {
-			.name = "nbsh_ctl",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_nbsh_show,
-		.store = amd64_nbsh_store,
-	},
-	{
-		.attr = {
-			.name = "nbcfg_ctl",
-			.mode = (S_IRUGO | S_IWUSR)
-		},
-		.show = amd64_nbcfg_show,
-		.store = amd64_nbcfg_store,
-	},
-	{
-		.attr = {
 			.name = "dhar",
 			.mode = (S_IRUGO)
 		},
@@ -225,7 +42,7 @@
 			.name = "dbam",
 			.mode = (S_IRUGO)
 		},
-		.show = amd64_dbam_show,
+		.show = amd64_dbam0_show,
 		.store = NULL,
 	},
 	{
@@ -233,7 +50,7 @@
 			.name = "topmem",
 			.mode = (S_IRUGO)
 		},
-		.show = amd64_topmem_show,
+		.show = amd64_top_mem_show,
 		.store = NULL,
 	},
 	{
@@ -241,7 +58,7 @@
 			.name = "topmem2",
 			.mode = (S_IRUGO)
 		},
-		.show = amd64_topmem2_show,
+		.show = amd64_top_mem2_show,
 		.store = NULL,
 	},
 	{
diff -druN linux-libre-2.6.36-gnu/drivers/edac/amd64_edac.h linux-libre-2.6.37-gnu/drivers/edac/amd64_edac.h
--- linux-libre-2.6.36-gnu/drivers/edac/amd64_edac.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/amd64_edac.h	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 #include <linux/edac.h>
 #include <asm/msr.h>
 #include "edac_core.h"
-#include "edac_mce_amd.h"
+#include "mce_amd.h"
 
 #define amd64_printk(level, fmt, arg...) \
 	edac_printk(level, "amd64", fmt, ##arg)
@@ -482,11 +482,10 @@
 extern const char *to_msgs[2];
 extern const char *pp_msgs[4];
 extern const char *ii_msgs[4];
-extern const char *ext_msgs[32];
 extern const char *htlink_msgs[8];
 
 #ifdef CONFIG_EDAC_DEBUG
-#define NUM_DBG_ATTRS 9
+#define NUM_DBG_ATTRS 5
 #else
 #define NUM_DBG_ATTRS 0
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_core.h linux-libre-2.6.37-gnu/drivers/edac/edac_core.h
--- linux-libre-2.6.36-gnu/drivers/edac/edac_core.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_core.h	2011-01-04 19:50:19.000000000 -0500
@@ -41,9 +41,11 @@
 #define MC_PROC_NAME_MAX_LEN	7
 
 #if PAGE_SHIFT < 20
-#define PAGES_TO_MiB( pages )	( ( pages ) >> ( 20 - PAGE_SHIFT ) )
+#define PAGES_TO_MiB(pages)	((pages) >> (20 - PAGE_SHIFT))
+#define MiB_TO_PAGES(mb)	((mb) << (20 - PAGE_SHIFT))
 #else				/* PAGE_SHIFT > 20 */
-#define PAGES_TO_MiB( pages )	( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#define PAGES_TO_MiB(pages)	((pages) << (PAGE_SHIFT - 20))
+#define MiB_TO_PAGES(mb)	((mb) >> (PAGE_SHIFT - 20))
 #endif
 
 #define edac_printk(level, prefix, fmt, arg...) \
@@ -328,7 +330,7 @@
 
 struct mcidev_sysfs_group {
 	const char *name;				/* group name */
-	struct mcidev_sysfs_attribute *mcidev_attr;	/* group attributes */
+	const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
 };
 
 struct mcidev_sysfs_group_kobj {
@@ -336,7 +338,7 @@
 
 	struct kobject kobj;		/* kobj for the group */
 
-	struct mcidev_sysfs_group *grp;	/* group description table */
+	const struct mcidev_sysfs_group *grp;	/* group description table */
 	struct mem_ctl_info *mci;	/* the parent */
 };
 
@@ -347,7 +349,7 @@
 struct mcidev_sysfs_attribute {
 	/* It should use either attr or grp */
 	struct attribute attr;
-	struct mcidev_sysfs_group *grp;	/* Points to a group of attributes */
+	const struct mcidev_sysfs_group *grp;	/* Points to a group of attributes */
 
 	/* Ops for show/store values at the attribute - not used on group */
         ssize_t (*show)(struct mem_ctl_info *,char *);
@@ -440,7 +442,7 @@
 	 * If attributes are desired, then set to array of attributes
 	 * If no attributes are desired, leave NULL
 	 */
-	struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+	const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
 
 	/* work struct for this MC */
 	struct delayed_work work;
@@ -810,6 +812,7 @@
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
 extern void edac_mc_free(struct mem_ctl_info *mci);
 extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *find_mci_by_dev(struct device *dev);
 extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
 extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
 				      unsigned long page);
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_device_sysfs.c linux-libre-2.6.37-gnu/drivers/edac/edac_device_sysfs.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_device_sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_device_sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,7 +1,7 @@
 /*
  * file for managing the edac_device class of devices for EDAC
  *
- * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ * (C) 2007 SoftwareBitMaker 
  *
  * This file may be distributed under the terms of the
  * GNU General Public License.
@@ -13,6 +13,7 @@
 #include <linux/ctype.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/edac.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
@@ -235,7 +236,7 @@
 	debugf1("%s()\n", __func__);
 
 	/* get the /sys/devices/system/edac reference */
-	edac_class = edac_get_edac_class();
+	edac_class = edac_get_sysfs_class();
 	if (edac_class == NULL) {
 		debugf1("%s() no edac_class error\n", __func__);
 		err = -ENODEV;
@@ -255,7 +256,7 @@
 
 	if (!try_module_get(edac_dev->owner)) {
 		err = -ENODEV;
-		goto err_out;
+		goto err_mod_get;
 	}
 
 	/* register */
@@ -282,6 +283,9 @@
 err_kobj_reg:
 	module_put(edac_dev->owner);
 
+err_mod_get:
+	edac_put_sysfs_class();
+
 err_out:
 	return err;
 }
@@ -290,12 +294,11 @@
  * edac_device_unregister_sysfs_main_kobj:
  *	the '..../edac/<name>' kobject
  */
-void edac_device_unregister_sysfs_main_kobj(
-					struct edac_device_ctl_info *edac_dev)
+void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
 {
 	debugf0("%s()\n", __func__);
 	debugf4("%s() name of kobject is: %s\n",
-		__func__, kobject_name(&edac_dev->kobj));
+		__func__, kobject_name(&dev->kobj));
 
 	/*
 	 * Unregister the edac device's kobject and
@@ -304,7 +307,8 @@
 	 *   a) module_put() this module
 	 *   b) 'kfree' the memory
 	 */
-	kobject_put(&edac_dev->kobj);
+	kobject_put(&dev->kobj);
+	edac_put_sysfs_class();
 }
 
 /* edac_dev -> instance information */
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_mc.c linux-libre-2.6.37-gnu/drivers/edac/edac_mc.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_mc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_mc.c	2011-01-04 19:50:19.000000000 -0500
@@ -207,6 +207,7 @@
 	}
 
 	mci->op_state = OP_ALLOC;
+	INIT_LIST_HEAD(&mci->grp_kobj_list);
 
 	/*
 	 * Initialize the 'root' kobj for the edac_mc controller
@@ -234,18 +235,24 @@
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
+	debugf1("%s()\n", __func__);
+
 	edac_mc_unregister_sysfs_main_kobj(mci);
+
+	/* free the mci instance memory here */
+	kfree(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
 
-/*
+/**
  * find_mci_by_dev
  *
  *	scan list of controllers looking for the one that manages
  *	the 'dev' device
+ * @dev: pointer to a struct device related with the MCI
  */
-static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
+struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 {
 	struct mem_ctl_info *mci;
 	struct list_head *item;
@@ -261,6 +268,7 @@
 
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(find_mci_by_dev);
 
 /*
  * handler for EDAC to check if NMI type handler has asserted interrupt
@@ -578,14 +586,16 @@
 		return NULL;
 	}
 
-	/* marking MCI offline */
-	mci->op_state = OP_OFFLINE;
-
 	del_mc_from_global_list(mci);
 	mutex_unlock(&mem_ctls_mutex);
 
-	/* flush workq processes and remove sysfs */
+	/* flush workq processes */
 	edac_mc_workq_teardown(mci);
+
+	/* marking MCI offline */
+	mci->op_state = OP_OFFLINE;
+
+	/* remove from sysfs */
 	edac_remove_sysfs_mci_device(mci);
 
 	edac_printk(KERN_INFO, EDAC_MC,
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_mce_amd.c linux-libre-2.6.37-gnu/drivers/edac/edac_mce_amd.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_mce_amd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_mce_amd.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,452 +0,0 @@
-#include <linux/module.h>
-#include "edac_mce_amd.h"
-
-static bool report_gart_errors;
-static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
-
-void amd_report_gart_errors(bool v)
-{
-	report_gart_errors = v;
-}
-EXPORT_SYMBOL_GPL(amd_report_gart_errors);
-
-void amd_register_ecc_decoder(void (*f)(int, struct err_regs *))
-{
-	nb_bus_decoder = f;
-}
-EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
-
-void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *))
-{
-	if (nb_bus_decoder) {
-		WARN_ON(nb_bus_decoder != f);
-
-		nb_bus_decoder = NULL;
-	}
-}
-EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
-
-/*
- * string representation for the different MCA reported error types, see F3x48
- * or MSR0000_0411.
- */
-const char *tt_msgs[] = {        /* transaction type */
-	"instruction",
-	"data",
-	"generic",
-	"reserved"
-};
-EXPORT_SYMBOL_GPL(tt_msgs);
-
-const char *ll_msgs[] = {	/* cache level */
-	"L0",
-	"L1",
-	"L2",
-	"L3/generic"
-};
-EXPORT_SYMBOL_GPL(ll_msgs);
-
-const char *rrrr_msgs[] = {
-	"generic",
-	"generic read",
-	"generic write",
-	"data read",
-	"data write",
-	"inst fetch",
-	"prefetch",
-	"evict",
-	"snoop",
-	"reserved RRRR= 9",
-	"reserved RRRR= 10",
-	"reserved RRRR= 11",
-	"reserved RRRR= 12",
-	"reserved RRRR= 13",
-	"reserved RRRR= 14",
-	"reserved RRRR= 15"
-};
-EXPORT_SYMBOL_GPL(rrrr_msgs);
-
-const char *pp_msgs[] = {	/* participating processor */
-	"local node originated (SRC)",
-	"local node responded to request (RES)",
-	"local node observed as 3rd party (OBS)",
-	"generic"
-};
-EXPORT_SYMBOL_GPL(pp_msgs);
-
-const char *to_msgs[] = {
-	"no timeout",
-	"timed out"
-};
-EXPORT_SYMBOL_GPL(to_msgs);
-
-const char *ii_msgs[] = {	/* memory or i/o */
-	"mem access",
-	"reserved",
-	"i/o access",
-	"generic"
-};
-EXPORT_SYMBOL_GPL(ii_msgs);
-
-/*
- * Map the 4 or 5 (family-specific) bits of Extended Error code to the
- * string table.
- */
-const char *ext_msgs[] = {
-	"K8 ECC error",					/* 0_0000b */
-	"CRC error on link",				/* 0_0001b */
-	"Sync error packets on link",			/* 0_0010b */
-	"Master Abort during link operation",		/* 0_0011b */
-	"Target Abort during link operation",		/* 0_0100b */
-	"Invalid GART PTE entry during table walk",	/* 0_0101b */
-	"Unsupported atomic RMW command received",	/* 0_0110b */
-	"WDT error: NB transaction timeout",		/* 0_0111b */
-	"ECC/ChipKill ECC error",			/* 0_1000b */
-	"SVM DEV Error",				/* 0_1001b */
-	"Link Data error",				/* 0_1010b */
-	"Link/L3/Probe Filter Protocol error",		/* 0_1011b */
-	"NB Internal Arrays Parity error",		/* 0_1100b */
-	"DRAM Address/Control Parity error",		/* 0_1101b */
-	"Link Transmission error",			/* 0_1110b */
-	"GART/DEV Table Walk Data error"		/* 0_1111b */
-	"Res 0x100 error",				/* 1_0000b */
-	"Res 0x101 error",				/* 1_0001b */
-	"Res 0x102 error",				/* 1_0010b */
-	"Res 0x103 error",				/* 1_0011b */
-	"Res 0x104 error",				/* 1_0100b */
-	"Res 0x105 error",				/* 1_0101b */
-	"Res 0x106 error",				/* 1_0110b */
-	"Res 0x107 error",				/* 1_0111b */
-	"Res 0x108 error",				/* 1_1000b */
-	"Res 0x109 error",				/* 1_1001b */
-	"Res 0x10A error",				/* 1_1010b */
-	"Res 0x10B error",				/* 1_1011b */
-	"ECC error in L3 Cache Data",			/* 1_1100b */
-	"L3 Cache Tag error",				/* 1_1101b */
-	"L3 Cache LRU Parity error",			/* 1_1110b */
-	"Probe Filter error"				/* 1_1111b */
-};
-EXPORT_SYMBOL_GPL(ext_msgs);
-
-static void amd_decode_dc_mce(u64 mc0_status)
-{
-	u32 ec  = mc0_status & 0xffff;
-	u32 xec = (mc0_status >> 16) & 0xf;
-
-	pr_emerg("Data Cache Error");
-
-	if (xec == 1 && TLB_ERROR(ec))
-		pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
-	else if (xec == 0) {
-		if (mc0_status & (1ULL << 40))
-			pr_cont(" during Data Scrub.\n");
-		else if (TLB_ERROR(ec))
-			pr_cont(": %s TLB parity error.\n", LL_MSG(ec));
-		else if (MEM_ERROR(ec)) {
-			u8 ll   = ec & 0x3;
-			u8 tt   = (ec >> 2) & 0x3;
-			u8 rrrr = (ec >> 4) & 0xf;
-
-			/* see F10h BKDG (31116), Table 92. */
-			if (ll == 0x1) {
-				if (tt != 0x1)
-					goto wrong_dc_mce;
-
-				pr_cont(": Data/Tag %s error.\n", RRRR_MSG(ec));
-
-			} else if (ll == 0x2 && rrrr == 0x3)
-				pr_cont(" during L1 linefill from L2.\n");
-			else
-				goto wrong_dc_mce;
-		} else if (BUS_ERROR(ec) && boot_cpu_data.x86 == 0xf)
-			pr_cont(" during system linefill.\n");
-		else
-			goto wrong_dc_mce;
-	} else
-		goto wrong_dc_mce;
-
-	return;
-
-wrong_dc_mce:
-	pr_warning("Corrupted DC MCE info?\n");
-}
-
-static void amd_decode_ic_mce(u64 mc1_status)
-{
-	u32 ec  = mc1_status & 0xffff;
-	u32 xec = (mc1_status >> 16) & 0xf;
-
-	pr_emerg("Instruction Cache Error");
-
-	if (xec == 1 && TLB_ERROR(ec))
-		pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
-	else if (xec == 0) {
-		if (TLB_ERROR(ec))
-			pr_cont(": %s TLB Parity error.\n", LL_MSG(ec));
-		else if (BUS_ERROR(ec)) {
-			if (boot_cpu_data.x86 == 0xf &&
-			    (mc1_status & (1ULL << 58)))
-				pr_cont(" during system linefill.\n");
-			else
-				pr_cont(" during attempted NB data read.\n");
-		} else if (MEM_ERROR(ec)) {
-			u8 ll   = ec & 0x3;
-			u8 rrrr = (ec >> 4) & 0xf;
-
-			if (ll == 0x2)
-				pr_cont(" during a linefill from L2.\n");
-			else if (ll == 0x1) {
-
-				switch (rrrr) {
-				case 0x5:
-					pr_cont(": Parity error during "
-					       "data load.\n");
-					break;
-
-				case 0x7:
-					pr_cont(": Copyback Parity/Victim"
-						" error.\n");
-					break;
-
-				case 0x8:
-					pr_cont(": Tag Snoop error.\n");
-					break;
-
-				default:
-					goto wrong_ic_mce;
-					break;
-				}
-			}
-		} else
-			goto wrong_ic_mce;
-	} else
-		goto wrong_ic_mce;
-
-	return;
-
-wrong_ic_mce:
-	pr_warning("Corrupted IC MCE info?\n");
-}
-
-static void amd_decode_bu_mce(u64 mc2_status)
-{
-	u32 ec = mc2_status & 0xffff;
-	u32 xec = (mc2_status >> 16) & 0xf;
-
-	pr_emerg("Bus Unit Error");
-
-	if (xec == 0x1)
-		pr_cont(" in the write data buffers.\n");
-	else if (xec == 0x3)
-		pr_cont(" in the victim data buffers.\n");
-	else if (xec == 0x2 && MEM_ERROR(ec))
-		pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
-	else if (xec == 0x0) {
-		if (TLB_ERROR(ec))
-			pr_cont(": %s error in a Page Descriptor Cache or "
-				"Guest TLB.\n", TT_MSG(ec));
-		else if (BUS_ERROR(ec))
-			pr_cont(": %s/ECC error in data read from NB: %s.\n",
-				RRRR_MSG(ec), PP_MSG(ec));
-		else if (MEM_ERROR(ec)) {
-			u8 rrrr = (ec >> 4) & 0xf;
-
-			if (rrrr >= 0x7)
-				pr_cont(": %s error during data copyback.\n",
-					RRRR_MSG(ec));
-			else if (rrrr <= 0x1)
-				pr_cont(": %s parity/ECC error during data "
-					"access from L2.\n", RRRR_MSG(ec));
-			else
-				goto wrong_bu_mce;
-		} else
-			goto wrong_bu_mce;
-	} else
-		goto wrong_bu_mce;
-
-	return;
-
-wrong_bu_mce:
-	pr_warning("Corrupted BU MCE info?\n");
-}
-
-static void amd_decode_ls_mce(u64 mc3_status)
-{
-	u32 ec  = mc3_status & 0xffff;
-	u32 xec = (mc3_status >> 16) & 0xf;
-
-	pr_emerg("Load Store Error");
-
-	if (xec == 0x0) {
-		u8 rrrr = (ec >> 4) & 0xf;
-
-		if (!BUS_ERROR(ec) || (rrrr != 0x3 && rrrr != 0x4))
-			goto wrong_ls_mce;
-
-		pr_cont(" during %s.\n", RRRR_MSG(ec));
-	}
-	return;
-
-wrong_ls_mce:
-	pr_warning("Corrupted LS MCE info?\n");
-}
-
-void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors)
-{
-	u32 ec  = ERROR_CODE(regs->nbsl);
-
-	if (!handle_errors)
-		return;
-
-	/*
-	 * GART TLB error reporting is disabled by default. Bail out early.
-	 */
-	if (TLB_ERROR(ec) && !report_gart_errors)
-		return;
-
-	pr_emerg("Northbridge Error, node %d", node_id);
-
-	/*
-	 * F10h, revD can disable ErrCpu[3:0] so check that first and also the
-	 * value encoding has changed so interpret those differently
-	 */
-	if ((boot_cpu_data.x86 == 0x10) &&
-	    (boot_cpu_data.x86_model > 7)) {
-		if (regs->nbsh & K8_NBSH_ERR_CPU_VAL)
-			pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf));
-	} else {
-		u8 assoc_cpus = regs->nbsh & 0xf;
-
-		if (assoc_cpus > 0)
-			pr_cont(", core: %d", fls(assoc_cpus) - 1);
-
-		pr_cont("\n");
-	}
-
-	pr_emerg("%s.\n", EXT_ERR_MSG(regs->nbsl));
-
-	if (BUS_ERROR(ec) && nb_bus_decoder)
-		nb_bus_decoder(node_id, regs);
-}
-EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
-
-static void amd_decode_fr_mce(u64 mc5_status)
-{
-	/* we have only one error signature so match all fields at once. */
-	if ((mc5_status & 0xffff) == 0x0f0f)
-		pr_emerg(" FR Error: CPU Watchdog timer expire.\n");
-	else
-		pr_warning("Corrupted FR MCE info?\n");
-}
-
-static inline void amd_decode_err_code(unsigned int ec)
-{
-	if (TLB_ERROR(ec)) {
-		pr_emerg("Transaction: %s, Cache Level %s\n",
-			 TT_MSG(ec), LL_MSG(ec));
-	} else if (MEM_ERROR(ec)) {
-		pr_emerg("Transaction: %s, Type: %s, Cache Level: %s",
-			 RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
-	} else if (BUS_ERROR(ec)) {
-		pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, "
-			 "Participating Processor: %s\n",
-			  RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
-			  PP_MSG(ec));
-	} else
-		pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
-}
-
-static int amd_decode_mce(struct notifier_block *nb, unsigned long val,
-			   void *data)
-{
-	struct mce *m = (struct mce *)data;
-	struct err_regs regs;
-	int node, ecc;
-
-	pr_emerg("MC%d_STATUS: ", m->bank);
-
-	pr_cont("%sorrected error, other errors lost: %s, "
-		 "CPU context corrupt: %s",
-		 ((m->status & MCI_STATUS_UC) ? "Unc"  : "C"),
-		 ((m->status & MCI_STATUS_OVER) ? "yes"  : "no"),
-		 ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
-
-	/* do the two bits[14:13] together */
-	ecc = (m->status >> 45) & 0x3;
-	if (ecc)
-		pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
-
-	pr_cont("\n");
-
-	switch (m->bank) {
-	case 0:
-		amd_decode_dc_mce(m->status);
-		break;
-
-	case 1:
-		amd_decode_ic_mce(m->status);
-		break;
-
-	case 2:
-		amd_decode_bu_mce(m->status);
-		break;
-
-	case 3:
-		amd_decode_ls_mce(m->status);
-		break;
-
-	case 4:
-		regs.nbsl  = (u32) m->status;
-		regs.nbsh  = (u32)(m->status >> 32);
-		regs.nbeal = (u32) m->addr;
-		regs.nbeah = (u32)(m->addr >> 32);
-		node       = amd_get_nb_id(m->extcpu);
-
-		amd_decode_nb_mce(node, &regs, 1);
-		break;
-
-	case 5:
-		amd_decode_fr_mce(m->status);
-		break;
-
-	default:
-		break;
-	}
-
-	amd_decode_err_code(m->status & 0xffff);
-
-	return NOTIFY_STOP;
-}
-
-static struct notifier_block amd_mce_dec_nb = {
-	.notifier_call	= amd_decode_mce,
-};
-
-static int __init mce_amd_init(void)
-{
-	/*
-	 * We can decode MCEs for K8, F10h and F11h CPUs:
-	 */
-	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
-		return 0;
-
-	if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
-		return 0;
-
-	atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
-
-	return 0;
-}
-early_initcall(mce_amd_init);
-
-#ifdef MODULE
-static void __exit mce_amd_exit(void)
-{
-	atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
-}
-
-MODULE_DESCRIPTION("AMD MCE decoder");
-MODULE_ALIAS("edac-mce-amd");
-MODULE_LICENSE("GPL");
-module_exit(mce_amd_exit);
-#endif
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_mce_amd.h linux-libre-2.6.37-gnu/drivers/edac/edac_mce_amd.h
--- linux-libre-2.6.36-gnu/drivers/edac/edac_mce_amd.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_mce_amd.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,69 +0,0 @@
-#ifndef _EDAC_MCE_AMD_H
-#define _EDAC_MCE_AMD_H
-
-#include <asm/mce.h>
-
-#define ERROR_CODE(x)			((x) & 0xffff)
-#define EXT_ERROR_CODE(x)		(((x) >> 16) & 0x1f)
-#define EXT_ERR_MSG(x)			ext_msgs[EXT_ERROR_CODE(x)]
-
-#define LOW_SYNDROME(x)			(((x) >> 15) & 0xff)
-#define HIGH_SYNDROME(x)		(((x) >> 24) & 0xff)
-
-#define TLB_ERROR(x)			(((x) & 0xFFF0) == 0x0010)
-#define MEM_ERROR(x)			(((x) & 0xFF00) == 0x0100)
-#define BUS_ERROR(x)			(((x) & 0xF800) == 0x0800)
-
-#define TT(x)				(((x) >> 2) & 0x3)
-#define TT_MSG(x)			tt_msgs[TT(x)]
-#define II(x)				(((x) >> 2) & 0x3)
-#define II_MSG(x)			ii_msgs[II(x)]
-#define LL(x)				(((x) >> 0) & 0x3)
-#define LL_MSG(x)			ll_msgs[LL(x)]
-#define RRRR(x)				(((x) >> 4) & 0xf)
-#define RRRR_MSG(x)			rrrr_msgs[RRRR(x)]
-#define TO(x)				(((x) >> 8) & 0x1)
-#define TO_MSG(x)			to_msgs[TO(x)]
-#define PP(x)				(((x) >> 9) & 0x3)
-#define PP_MSG(x)			pp_msgs[PP(x)]
-
-#define K8_NBSH				0x4C
-
-#define K8_NBSH_VALID_BIT		BIT(31)
-#define K8_NBSH_OVERFLOW		BIT(30)
-#define K8_NBSH_UC_ERR			BIT(29)
-#define K8_NBSH_ERR_EN			BIT(28)
-#define K8_NBSH_MISCV			BIT(27)
-#define K8_NBSH_VALID_ERROR_ADDR	BIT(26)
-#define K8_NBSH_PCC			BIT(25)
-#define K8_NBSH_ERR_CPU_VAL		BIT(24)
-#define K8_NBSH_CECC			BIT(14)
-#define K8_NBSH_UECC			BIT(13)
-#define K8_NBSH_ERR_SCRUBER		BIT(8)
-
-extern const char *tt_msgs[];
-extern const char *ll_msgs[];
-extern const char *rrrr_msgs[];
-extern const char *pp_msgs[];
-extern const char *to_msgs[];
-extern const char *ii_msgs[];
-extern const char *ext_msgs[];
-
-/*
- * relevant NB regs
- */
-struct err_regs {
-	u32 nbcfg;
-	u32 nbsh;
-	u32 nbsl;
-	u32 nbeah;
-	u32 nbeal;
-};
-
-
-void amd_report_gart_errors(bool);
-void amd_register_ecc_decoder(void (*f)(int, struct err_regs *));
-void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *));
-void amd_decode_nb_mce(int, struct err_regs *, int);
-
-#endif /* _EDAC_MCE_AMD_H */
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_mc_sysfs.c linux-libre-2.6.37-gnu/drivers/edac/edac_mc_sysfs.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_mc_sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_mc_sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -11,6 +11,7 @@
 
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/edac.h>
 #include <linux/bug.h>
 
 #include "edac_core.h"
@@ -630,9 +631,6 @@
 
 	/* decrement the module ref count */
 	module_put(mci->owner);
-
-	/* free the mci instance memory here */
-	kfree(mci);
 }
 
 static struct kobj_type ktype_mci = {
@@ -712,6 +710,8 @@
  */
 void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 {
+	debugf1("%s()\n", __func__);
+
 	/* delete the kobj from the mc_kset */
 	kobject_put(&mci->edac_mci_kobj);
 }
@@ -759,8 +759,6 @@
 
 	grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
 	mci = grp->mci;
-
-	kobject_put(&mci->edac_mci_kobj);
 }
 
 /* Intermediate show/store table */
@@ -783,7 +781,7 @@
  * object tree.
  */
 static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
-				struct mcidev_sysfs_attribute *sysfs_attrib,
+				const struct mcidev_sysfs_attribute *sysfs_attrib,
 				struct kobject *kobj)
 {
 	int err;
@@ -791,6 +789,7 @@
 	debugf1("%s()\n", __func__);
 
 	while (sysfs_attrib) {
+		debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
 		if (sysfs_attrib->grp) {
 			struct mcidev_sysfs_group_kobj *grp_kobj;
 
@@ -798,10 +797,9 @@
 			if (!grp_kobj)
 				return -ENOMEM;
 
-			list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
-
 			grp_kobj->grp = sysfs_attrib->grp;
 			grp_kobj->mci = mci;
+			list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
 
 			debugf0("%s() grp %s, mci %p\n", __func__,
 				sysfs_attrib->grp->name, mci);
@@ -810,26 +808,28 @@
 						&ktype_inst_grp,
 						&mci->edac_mci_kobj,
 						sysfs_attrib->grp->name);
-			if (err)
+			if (err < 0) {
+				printk(KERN_ERR "kobject_init_and_add failed: %d\n", err);
 				return err;
-
+			}
 			err = edac_create_mci_instance_attributes(mci,
 					grp_kobj->grp->mcidev_attr,
 					&grp_kobj->kobj);
 
-			if (err)
+			if (err < 0)
 				return err;
 		} else if (sysfs_attrib->attr.name) {
 			debugf0("%s() file %s\n", __func__,
 				sysfs_attrib->attr.name);
 
 			err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+			if (err < 0) {
+				printk(KERN_ERR "sysfs_create_file failed: %d\n", err);
+				return err;
+			}
 		} else
 			break;
 
-		if (err) {
-			return err;
-		}
 		sysfs_attrib++;
 	}
 
@@ -842,7 +842,7 @@
  *	directory of this mci instance.
  */
 static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
-				struct mcidev_sysfs_attribute *sysfs_attrib,
+				const struct mcidev_sysfs_attribute *sysfs_attrib,
 				struct kobject *kobj, int count)
 {
 	struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
@@ -854,13 +854,24 @@
 	 * Remove first all the atributes
 	 */
 	while (sysfs_attrib) {
+		debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib);
 		if (sysfs_attrib->grp) {
-			list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
-					    list)
-				if (grp_kobj->grp == sysfs_attrib->grp)
+			debugf1("%s() seeking for group %s\n",
+				__func__, sysfs_attrib->grp->name);
+			list_for_each_entry(grp_kobj,
+					    &mci->grp_kobj_list, list) {
+				debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp);
+				if (grp_kobj->grp == sysfs_attrib->grp) {
 					edac_remove_mci_instance_attributes(mci,
 						    grp_kobj->grp->mcidev_attr,
 						    &grp_kobj->kobj, count + 1);
+					debugf0("%s() group %s\n", __func__,
+						sysfs_attrib->grp->name);
+					kobject_put(&grp_kobj->kobj);
+				}
+			}
+			debugf1("%s() end of seeking for group %s\n",
+				__func__, sysfs_attrib->grp->name);
 		} else if (sysfs_attrib->attr.name) {
 			debugf0("%s() file %s\n", __func__,
 				sysfs_attrib->attr.name);
@@ -870,15 +881,14 @@
 		sysfs_attrib++;
 	}
 
-	/*
-	 * Now that all attributes got removed, it is save to remove all groups
-	 */
-	if (!count)
-		list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
-					 list) {
-			debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
-			kobject_put(&grp_kobj->kobj);
-		}
+	/* Remove the group objects */
+	if (count)
+		return;
+	list_for_each_entry_safe(grp_kobj, tmp,
+				 &mci->grp_kobj_list, list) {
+		list_del(&grp_kobj->list);
+		kfree(grp_kobj);
+	}
 }
 
 
@@ -970,6 +980,7 @@
 	debugf0("%s()\n", __func__);
 
 	/* remove all csrow kobjects */
+	debugf0("%s()  unregister this mci kobj\n", __func__);
 	for (i = 0; i < mci->nr_csrows; i++) {
 		if (mci->csrows[i].nr_pages > 0) {
 			debugf0("%s()  unreg csrow-%d\n", __func__, i);
@@ -977,20 +988,20 @@
 		}
 	}
 
-	debugf0("%s()  remove_link\n", __func__);
+	/* remove this mci instance's attribtes */
+	if (mci->mc_driver_sysfs_attributes) {
+		debugf0("%s()  unregister mci private attributes\n", __func__);
+		edac_remove_mci_instance_attributes(mci,
+						mci->mc_driver_sysfs_attributes,
+						&mci->edac_mci_kobj, 0);
+	}
 
 	/* remove the symlink */
+	debugf0("%s()  remove_link\n", __func__);
 	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
 
-	debugf0("%s()  remove_mci_instance\n", __func__);
-
-	/* remove this mci instance's attribtes */
-	edac_remove_mci_instance_attributes(mci,
-					    mci->mc_driver_sysfs_attributes,
-					    &mci->edac_mci_kobj, 0);
-	debugf0("%s()  unregister this mci kobj\n", __func__);
-
 	/* unregister this instance's kobject */
+	debugf0("%s()  remove_mci_instance\n", __func__);
 	kobject_put(&mci->edac_mci_kobj);
 }
 
@@ -1011,13 +1022,13 @@
  */
 int edac_sysfs_setup_mc_kset(void)
 {
-	int err = 0;
+	int err = -EINVAL;
 	struct sysdev_class *edac_class;
 
 	debugf1("%s()\n", __func__);
 
 	/* get the /sys/devices/system/edac class reference */
-	edac_class = edac_get_edac_class();
+	edac_class = edac_get_sysfs_class();
 	if (edac_class == NULL) {
 		debugf1("%s() no edac_class error=%d\n", __func__, err);
 		goto fail_out;
@@ -1028,15 +1039,16 @@
 	if (!mc_kset) {
 		err = -ENOMEM;
 		debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
-		goto fail_out;
+		goto fail_kset;
 	}
 
 	debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
 
 	return 0;
 
+fail_kset:
+	edac_put_sysfs_class();
 
-	/* error unwind stack */
 fail_out:
 	return err;
 }
@@ -1049,5 +1061,6 @@
 void edac_sysfs_teardown_mc_kset(void)
 {
 	kset_unregister(mc_kset);
+	edac_put_sysfs_class();
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_module.c linux-libre-2.6.37-gnu/drivers/edac/edac_module.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_module.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_module.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,15 +27,6 @@
 struct workqueue_struct *edac_workqueue;
 
 /*
- * sysfs object: /sys/devices/system/edac
- *	need to export to other files in this modules
- */
-static struct sysdev_class edac_class = {
-	.name = "edac",
-};
-static int edac_class_valid;
-
-/*
  * edac_op_state_to_string()
  */
 char *edac_op_state_to_string(int opstate)
@@ -55,60 +46,6 @@
 }
 
 /*
- * edac_get_edac_class()
- *
- *	return pointer to the edac class of 'edac'
- */
-struct sysdev_class *edac_get_edac_class(void)
-{
-	struct sysdev_class *classptr = NULL;
-
-	if (edac_class_valid)
-		classptr = &edac_class;
-
-	return classptr;
-}
-
-/*
- * edac_register_sysfs_edac_name()
- *
- *	register the 'edac' into /sys/devices/system
- *
- * return:
- *	0  success
- *	!0 error
- */
-static int edac_register_sysfs_edac_name(void)
-{
-	int err;
-
-	/* create the /sys/devices/system/edac directory */
-	err = sysdev_class_register(&edac_class);
-
-	if (err) {
-		debugf1("%s() error=%d\n", __func__, err);
-		return err;
-	}
-
-	edac_class_valid = 1;
-	return 0;
-}
-
-/*
- * sysdev_class_unregister()
- *
- *	unregister the 'edac' from /sys/devices/system
- */
-static void edac_unregister_sysfs_edac_name(void)
-{
-	/* only if currently registered, then unregister it */
-	if (edac_class_valid)
-		sysdev_class_unregister(&edac_class);
-
-	edac_class_valid = 0;
-}
-
-/*
  * edac_workqueue_setup
  *	initialize the edac work queue for polling operations
  */
@@ -154,21 +91,11 @@
 	edac_pci_clear_parity_errors();
 
 	/*
-	 * perform the registration of the /sys/devices/system/edac class object
-	 */
-	if (edac_register_sysfs_edac_name()) {
-		edac_printk(KERN_ERR, EDAC_MC,
-			"Error initializing 'edac' kobject\n");
-		err = -ENODEV;
-		goto error;
-	}
-
-	/*
 	 * now set up the mc_kset under the edac class object
 	 */
 	err = edac_sysfs_setup_mc_kset();
 	if (err)
-		goto sysfs_setup_fail;
+		goto error;
 
 	/* Setup/Initialize the workq for this core */
 	err = edac_workqueue_setup();
@@ -183,9 +110,6 @@
 workq_fail:
 	edac_sysfs_teardown_mc_kset();
 
-sysfs_setup_fail:
-	edac_unregister_sysfs_edac_name();
-
 error:
 	return err;
 }
@@ -201,7 +125,6 @@
 	/* tear down the various subsystems */
 	edac_workqueue_teardown();
 	edac_sysfs_teardown_mc_kset();
-	edac_unregister_sysfs_edac_name();
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_module.h linux-libre-2.6.37-gnu/drivers/edac/edac_module.h
--- linux-libre-2.6.36-gnu/drivers/edac/edac_module.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_module.h	2011-01-04 19:50:19.000000000 -0500
@@ -42,7 +42,6 @@
 				struct edac_device_ctl_info *edac_dev);
 extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
-extern struct sysdev_class *edac_get_edac_class(void);
 
 /* edac core workqueue: single CPU mode */
 extern struct workqueue_struct *edac_workqueue;
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_pci_sysfs.c linux-libre-2.6.37-gnu/drivers/edac/edac_pci_sysfs.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_pci_sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_pci_sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,7 +7,7 @@
  *
  */
 #include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/edac.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
 
@@ -354,7 +354,7 @@
 	/* First time, so create the main kobject and its
 	 * controls and atributes
 	 */
-	edac_class = edac_get_edac_class();
+	edac_class = edac_get_sysfs_class();
 	if (edac_class == NULL) {
 		debugf1("%s() no edac_class\n", __func__);
 		err = -ENODEV;
@@ -368,7 +368,7 @@
 	if (!try_module_get(THIS_MODULE)) {
 		debugf1("%s() try_module_get() failed\n", __func__);
 		err = -ENODEV;
-		goto decrement_count_fail;
+		goto mod_get_fail;
 	}
 
 	edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
@@ -403,6 +403,9 @@
 kzalloc_fail:
 	module_put(THIS_MODULE);
 
+mod_get_fail:
+	edac_put_sysfs_class();
+
 decrement_count_fail:
 	/* if are on this error exit, nothing to tear down */
 	atomic_dec(&edac_pci_sysfs_refcount);
@@ -429,6 +432,7 @@
 			__func__);
 		kobject_put(edac_pci_top_main_kobj);
 	}
+	edac_put_sysfs_class();
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/drivers/edac/edac_stub.c linux-libre-2.6.37-gnu/drivers/edac/edac_stub.c
--- linux-libre-2.6.36-gnu/drivers/edac/edac_stub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/edac_stub.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,10 +3,13 @@
  *
  * Author: Dave Jiang <djiang@mvista.com>
  *
- * 2007 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2007 (c) MontaVista Software, Inc.
+ * 2010 (c) Advanced Micro Devices Inc.
+ *	    Borislav Petkov <borislav.petkov@amd.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
  *
  */
 #include <linux/module.h>
@@ -23,6 +26,8 @@
 int edac_err_assert = 0;
 EXPORT_SYMBOL_GPL(edac_err_assert);
 
+static atomic_t edac_class_valid = ATOMIC_INIT(0);
+
 /*
  * called to determine if there is an EDAC driver interested in
  * knowing an event (such as NMI) occurred
@@ -44,3 +49,41 @@
 	edac_err_assert++;
 }
 EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ *	need to export to other files
+ */
+struct sysdev_class edac_class = {
+	.name = "edac",
+};
+EXPORT_SYMBOL_GPL(edac_class);
+
+/* return pointer to the 'edac' node in sysfs */
+struct sysdev_class *edac_get_sysfs_class(void)
+{
+	int err = 0;
+
+	if (atomic_read(&edac_class_valid))
+		goto out;
+
+	/* create the /sys/devices/system/edac directory */
+	err = sysdev_class_register(&edac_class);
+	if (err) {
+		printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
+		return NULL;
+	}
+
+out:
+	atomic_inc(&edac_class_valid);
+	return &edac_class;
+}
+EXPORT_SYMBOL_GPL(edac_get_sysfs_class);
+
+void edac_put_sysfs_class(void)
+{
+	/* last user unregisters it */
+	if (atomic_dec_and_test(&edac_class_valid))
+		sysdev_class_unregister(&edac_class);
+}
+EXPORT_SYMBOL_GPL(edac_put_sysfs_class);
diff -druN linux-libre-2.6.36-gnu/drivers/edac/i7300_edac.c linux-libre-2.6.37-gnu/drivers/edac/i7300_edac.c
--- linux-libre-2.6.36-gnu/drivers/edac/i7300_edac.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/edac/i7300_edac.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1247 @@
+/*
+ * Intel 7300 class Memory Controllers kernel module (Clarksboro)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2 only.
+ *
+ * Copyright (c) 2010 by:
+ *	 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ *
+ * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet
+ *	http://www.intel.com/Assets/PDF/datasheet/318082.pdf
+ *
+ * TODO: The chipset allow checking for PCI Express errors also. Currently,
+ *	 the driver covers only memory error errors
+ *
+ * This driver uses "csrows" EDAC attribute to represent DIMM slot#
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <linux/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I7300 module when modifications are made
+ */
+#define I7300_REVISION    " Ver: 1.0.0 " __DATE__
+
+#define EDAC_MOD_STR      "i7300_edac"
+
+#define i7300_printk(level, fmt, arg...) \
+	edac_printk(level, "i7300", fmt, ##arg)
+
+#define i7300_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg)
+
+/***********************************************
+ * i7300 Limit constants Structs and static vars
+ ***********************************************/
+
+/*
+ * Memory topology is organized as:
+ *	Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0)
+ *	Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0)
+ * Each channel can have to 8 DIMM sets (called as SLOTS)
+ * Slots should generally be filled in pairs
+ *	Except on Single Channel mode of operation
+ *		just slot 0/channel0 filled on this mode
+ *	On normal operation mode, the two channels on a branch should be
+ *		filled together for the same SLOT#
+ * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four
+ *		channels on both branches should be filled
+ */
+
+/* Limits for i7300 */
+#define MAX_SLOTS		8
+#define MAX_BRANCHES		2
+#define MAX_CH_PER_BRANCH	2
+#define MAX_CHANNELS		(MAX_CH_PER_BRANCH * MAX_BRANCHES)
+#define MAX_MIR			3
+
+#define to_channel(ch, branch)	((((branch)) << 1) | (ch))
+
+#define to_csrow(slot, ch, branch)					\
+		(to_channel(ch, branch) | ((slot) << 2))
+
+/* Device name and register DID (Device ID) */
+struct i7300_dev_info {
+	const char *ctl_name;	/* name for this device */
+	u16 fsb_mapping_errors;	/* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i7300_dev_info i7300_devs[] = {
+	{
+		.ctl_name = "I7300",
+		.fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+	},
+};
+
+struct i7300_dimm_info {
+	int megabytes;		/* size, 0 means not present  */
+};
+
+/* driver private data structure */
+struct i7300_pvt {
+	struct pci_dev *pci_dev_16_0_fsb_ctlr;		/* 16.0 */
+	struct pci_dev *pci_dev_16_1_fsb_addr_map;	/* 16.1 */
+	struct pci_dev *pci_dev_16_2_fsb_err_regs;	/* 16.2 */
+	struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES];	/* 21.0  and 22.0 */
+
+	u16 tolm;				/* top of low memory */
+	u64 ambase;				/* AMB BAR */
+
+	u32 mc_settings;			/* Report several settings */
+	u32 mc_settings_a;
+
+	u16 mir[MAX_MIR];			/* Memory Interleave Reg*/
+
+	u16 mtr[MAX_SLOTS][MAX_BRANCHES];	/* Memory Technlogy Reg */
+	u16 ambpresent[MAX_CHANNELS];		/* AMB present regs */
+
+	/* DIMM information matrix, allocating architecture maximums */
+	struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS];
+
+	/* Temporary buffer for use when preparing error messages */
+	char *tmp_prt_buffer;
+};
+
+/* FIXME: Why do we need to have this static? */
+static struct edac_pci_ctl_info *i7300_pci;
+
+/***************************************************
+ * i7300 Register definitions for memory enumeration
+ ***************************************************/
+
+/*
+ * Device 16,
+ * Function 0: System Address (not documented)
+ * Function 1: Memory Branch Map, Control, Errors Register
+ */
+
+	/* OFFSETS for Function 0 */
+#define AMBASE			0x48 /* AMB Mem Mapped Reg Region Base */
+#define MAXCH			0x56 /* Max Channel Number */
+#define MAXDIMMPERCH		0x57 /* Max DIMM PER Channel Number */
+
+	/* OFFSETS for Function 1 */
+#define MC_SETTINGS		0x40
+  #define IS_MIRRORED(mc)		((mc) & (1 << 16))
+  #define IS_ECC_ENABLED(mc)		((mc) & (1 << 5))
+  #define IS_RETRY_ENABLED(mc)		((mc) & (1 << 31))
+  #define IS_SCRBALGO_ENHANCED(mc)	((mc) & (1 << 8))
+
+#define MC_SETTINGS_A		0x58
+  #define IS_SINGLE_MODE(mca)		((mca) & (1 << 14))
+
+#define TOLM			0x6C
+
+#define MIR0			0x80
+#define MIR1			0x84
+#define MIR2			0x88
+
+/*
+ * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available
+ * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it
+ * seems that we cannot use this information directly for the same usage.
+ * Each memory slot may have up to 2 AMB interfaces, one for income and another
+ * for outcome interface to the next slot.
+ * For now, the driver just stores the AMB present registers, but rely only at
+ * the MTR info to detect memory.
+ * Datasheet is also not clear about how to map each AMBPRESENT registers to
+ * one of the 4 available channels.
+ */
+#define AMBPRESENT_0	0x64
+#define AMBPRESENT_1	0x66
+
+const static u16 mtr_regs[MAX_SLOTS] = {
+	0x80, 0x84, 0x88, 0x8c,
+	0x82, 0x86, 0x8a, 0x8e
+};
+
+/*
+ * Defines to extract the vaious fields from the
+ *	MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr)		((mtr) & (1 << 8))
+#define MTR_DIMMS_ETHROTTLE(mtr)	((mtr) & (1 << 7))
+#define MTR_DRAM_WIDTH(mtr)		(((mtr) & (1 << 6)) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr)		(((mtr) & (1 << 5)) ? 8 : 4)
+#define MTR_DIMM_RANKS(mtr)		(((mtr) & (1 << 4)) ? 1 : 0)
+#define MTR_DIMM_ROWS(mtr)		(((mtr) >> 2) & 0x3)
+#define MTR_DRAM_BANKS_ADDR_BITS	2
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr)	(MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+/* MTR NUMROW */
+static const char *numrow_toString[] = {
+	"8,192 - 13 rows",
+	"16,384 - 14 rows",
+	"32,768 - 15 rows",
+	"65,536 - 16 rows"
+};
+
+/* MTR NUMCOL */
+static const char *numcol_toString[] = {
+	"1,024 - 10 columns",
+	"2,048 - 11 columns",
+	"4,096 - 12 columns",
+	"reserved"
+};
+#endif
+
+/************************************************
+ * i7300 Register definitions for error detection
+ ************************************************/
+
+/*
+ * Device 16.1: FBD Error Registers
+ */
+#define FERR_FAT_FBD	0x98
+static const char *ferr_fat_fbd_name[] = {
+	[22] = "Non-Redundant Fast Reset Timeout",
+	[2]  = ">Tmid Thermal event with intelligent throttling disabled",
+	[1]  = "Memory or FBD configuration CRC read error",
+	[0]  = "Memory Write error on non-redundant retry or "
+	       "FBD configuration Write error on retry",
+};
+#define GET_FBD_FAT_IDX(fbderr)	(fbderr & (3 << 28))
+#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+
+#define FERR_NF_FBD	0xa0
+static const char *ferr_nf_fbd_name[] = {
+	[24] = "DIMM-Spare Copy Completed",
+	[23] = "DIMM-Spare Copy Initiated",
+	[22] = "Redundant Fast Reset Timeout",
+	[21] = "Memory Write error on redundant retry",
+	[18] = "SPD protocol Error",
+	[17] = "FBD Northbound parity error on FBD Sync Status",
+	[16] = "Correctable Patrol Data ECC",
+	[15] = "Correctable Resilver- or Spare-Copy Data ECC",
+	[14] = "Correctable Mirrored Demand Data ECC",
+	[13] = "Correctable Non-Mirrored Demand Data ECC",
+	[11] = "Memory or FBD configuration CRC read error",
+	[10] = "FBD Configuration Write error on first attempt",
+	[9]  = "Memory Write error on first attempt",
+	[8]  = "Non-Aliased Uncorrectable Patrol Data ECC",
+	[7]  = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
+	[6]  = "Non-Aliased Uncorrectable Mirrored Demand Data ECC",
+	[5]  = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC",
+	[4]  = "Aliased Uncorrectable Patrol Data ECC",
+	[3]  = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC",
+	[2]  = "Aliased Uncorrectable Mirrored Demand Data ECC",
+	[1]  = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
+	[0]  = "Uncorrectable Data ECC on Replay",
+};
+#define GET_FBD_NF_IDX(fbderr)	(fbderr & (3 << 28))
+#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
+			      (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
+			      (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
+			      (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
+			      (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
+			      (1 << 1)  | (1 << 0))
+
+#define EMASK_FBD	0xa8
+#define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\
+			    (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\
+			    (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\
+			    (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\
+			    (1 << 9)  | (1 << 8)  | (1 << 7)  | (1 << 6)  |\
+			    (1 << 5)  | (1 << 4)  | (1 << 3)  | (1 << 2)  |\
+			    (1 << 1)  | (1 << 0))
+
+/*
+ * Device 16.2: Global Error Registers
+ */
+
+#define FERR_GLOBAL_HI	0x48
+static const char *ferr_global_hi_name[] = {
+	[3] = "FSB 3 Fatal Error",
+	[2] = "FSB 2 Fatal Error",
+	[1] = "FSB 1 Fatal Error",
+	[0] = "FSB 0 Fatal Error",
+};
+#define ferr_global_hi_is_fatal(errno)	1
+
+#define FERR_GLOBAL_LO	0x40
+static const char *ferr_global_lo_name[] = {
+	[31] = "Internal MCH Fatal Error",
+	[30] = "Intel QuickData Technology Device Fatal Error",
+	[29] = "FSB1 Fatal Error",
+	[28] = "FSB0 Fatal Error",
+	[27] = "FBD Channel 3 Fatal Error",
+	[26] = "FBD Channel 2 Fatal Error",
+	[25] = "FBD Channel 1 Fatal Error",
+	[24] = "FBD Channel 0 Fatal Error",
+	[23] = "PCI Express Device 7Fatal Error",
+	[22] = "PCI Express Device 6 Fatal Error",
+	[21] = "PCI Express Device 5 Fatal Error",
+	[20] = "PCI Express Device 4 Fatal Error",
+	[19] = "PCI Express Device 3 Fatal Error",
+	[18] = "PCI Express Device 2 Fatal Error",
+	[17] = "PCI Express Device 1 Fatal Error",
+	[16] = "ESI Fatal Error",
+	[15] = "Internal MCH Non-Fatal Error",
+	[14] = "Intel QuickData Technology Device Non Fatal Error",
+	[13] = "FSB1 Non-Fatal Error",
+	[12] = "FSB 0 Non-Fatal Error",
+	[11] = "FBD Channel 3 Non-Fatal Error",
+	[10] = "FBD Channel 2 Non-Fatal Error",
+	[9]  = "FBD Channel 1 Non-Fatal Error",
+	[8]  = "FBD Channel 0 Non-Fatal Error",
+	[7]  = "PCI Express Device 7 Non-Fatal Error",
+	[6]  = "PCI Express Device 6 Non-Fatal Error",
+	[5]  = "PCI Express Device 5 Non-Fatal Error",
+	[4]  = "PCI Express Device 4 Non-Fatal Error",
+	[3]  = "PCI Express Device 3 Non-Fatal Error",
+	[2]  = "PCI Express Device 2 Non-Fatal Error",
+	[1]  = "PCI Express Device 1 Non-Fatal Error",
+	[0]  = "ESI Non-Fatal Error",
+};
+#define ferr_global_lo_is_fatal(errno)	((errno < 16) ? 0 : 1)
+
+#define NRECMEMA	0xbe
+  #define NRECMEMA_BANK(v)	(((v) >> 12) & 7)
+  #define NRECMEMA_RANK(v)	(((v) >> 8) & 15)
+
+#define NRECMEMB	0xc0
+  #define NRECMEMB_IS_WR(v)	((v) & (1 << 31))
+  #define NRECMEMB_CAS(v)	(((v) >> 16) & 0x1fff)
+  #define NRECMEMB_RAS(v)	((v) & 0xffff)
+
+#define REDMEMA		0xdc
+
+#define REDMEMB		0x7c
+  #define IS_SECOND_CH(v)	((v) * (1 << 17))
+
+#define RECMEMA		0xe0
+  #define RECMEMA_BANK(v)	(((v) >> 12) & 7)
+  #define RECMEMA_RANK(v)	(((v) >> 8) & 15)
+
+#define RECMEMB		0xe4
+  #define RECMEMB_IS_WR(v)	((v) & (1 << 31))
+  #define RECMEMB_CAS(v)	(((v) >> 16) & 0x1fff)
+  #define RECMEMB_RAS(v)	((v) & 0xffff)
+
+/********************************************
+ * i7300 Functions related to error detection
+ ********************************************/
+
+/**
+ * get_err_from_table() - Gets the error message from a table
+ * @table:	table name (array of char *)
+ * @size:	number of elements at the table
+ * @pos:	position of the element to be returned
+ *
+ * This is a small routine that gets the pos-th element of a table. If the
+ * element doesn't exist (or it is empty), it returns "reserved".
+ * Instead of calling it directly, the better is to call via the macro
+ * GET_ERR_FROM_TABLE(), that automatically checks the table size via
+ * ARRAY_SIZE() macro
+ */
+static const char *get_err_from_table(const char *table[], int size, int pos)
+{
+	if (unlikely(pos >= size))
+		return "Reserved";
+
+	if (unlikely(!table[pos]))
+		return "Reserved";
+
+	return table[pos];
+}
+
+#define GET_ERR_FROM_TABLE(table, pos)				\
+	get_err_from_table(table, ARRAY_SIZE(table), pos)
+
+/**
+ * i7300_process_error_global() - Retrieve the hardware error information from
+ *				  the hardware global error registers and
+ *				  sends it to dmesg
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_process_error_global(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	u32 errnum, value;
+	unsigned long errors;
+	const char *specific;
+	bool is_fatal;
+
+	pvt = mci->pvt_info;
+
+	/* read in the 1st FATAL error register */
+	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_HI, &value);
+	if (unlikely(value)) {
+		errors = value;
+		errnum = find_first_bit(&errors,
+					ARRAY_SIZE(ferr_global_hi_name));
+		specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum);
+		is_fatal = ferr_global_hi_is_fatal(errnum);
+
+		/* Clear the error bit */
+		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+				       FERR_GLOBAL_HI, value);
+
+		goto error_global;
+	}
+
+	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_LO, &value);
+	if (unlikely(value)) {
+		errors = value;
+		errnum = find_first_bit(&errors,
+					ARRAY_SIZE(ferr_global_lo_name));
+		specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum);
+		is_fatal = ferr_global_lo_is_fatal(errnum);
+
+		/* Clear the error bit */
+		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+				       FERR_GLOBAL_LO, value);
+
+		goto error_global;
+	}
+	return;
+
+error_global:
+	i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n",
+			is_fatal ? "Fatal" : "NOT fatal", specific);
+}
+
+/**
+ * i7300_process_fbd_error() - Retrieve the hardware error information from
+ *			       the FBD error registers and sends it via
+ *			       EDAC error API calls
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_process_fbd_error(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	u32 errnum, value;
+	u16 val16;
+	unsigned branch, channel, bank, rank, cas, ras;
+	u32 syndrome;
+
+	unsigned long errors;
+	const char *specific;
+	bool is_wr;
+
+	pvt = mci->pvt_info;
+
+	/* read in the 1st FATAL error register */
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_FAT_FBD, &value);
+	if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) {
+		errors = value & FERR_FAT_FBD_ERR_MASK ;
+		errnum = find_first_bit(&errors,
+					ARRAY_SIZE(ferr_fat_fbd_name));
+		specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum);
+
+		branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
+		pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
+				     NRECMEMA, &val16);
+		bank = NRECMEMA_BANK(val16);
+		rank = NRECMEMA_RANK(val16);
+
+		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+				NRECMEMB, &value);
+
+		is_wr = NRECMEMB_IS_WR(value);
+		cas = NRECMEMB_CAS(value);
+		ras = NRECMEMB_RAS(value);
+
+		snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
+			"FATAL (Branch=%d DRAM-Bank=%d %s "
+			"RAS=%d CAS=%d Err=0x%lx (%s))",
+			branch, bank,
+			is_wr ? "RDWR" : "RD",
+			ras, cas,
+			errors, specific);
+
+		/* Call the helper to output message */
+		edac_mc_handle_fbd_ue(mci, rank, branch << 1,
+				      (branch << 1) + 1,
+				      pvt->tmp_prt_buffer);
+	}
+
+	/* read in the 1st NON-FATAL error register */
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_NF_FBD, &value);
+	if (unlikely(value & FERR_NF_FBD_ERR_MASK)) {
+		errors = value & FERR_NF_FBD_ERR_MASK;
+		errnum = find_first_bit(&errors,
+					ARRAY_SIZE(ferr_nf_fbd_name));
+		specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
+
+		/* Clear the error bit */
+		pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+				       FERR_GLOBAL_LO, value);
+
+		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			REDMEMA, &syndrome);
+
+		branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0;
+		pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map,
+				     RECMEMA, &val16);
+		bank = RECMEMA_BANK(val16);
+		rank = RECMEMA_RANK(val16);
+
+		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+				RECMEMB, &value);
+
+		is_wr = RECMEMB_IS_WR(value);
+		cas = RECMEMB_CAS(value);
+		ras = RECMEMB_RAS(value);
+
+		pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+				     REDMEMB, &value);
+
+		channel = (branch << 1);
+		if (IS_SECOND_CH(value))
+			channel++;
+
+		/* Form out message */
+		snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
+			"Corrected error (Branch=%d, Channel %d), "
+			" DRAM-Bank=%d %s "
+			"RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))",
+			branch, channel,
+			bank,
+			is_wr ? "RDWR" : "RD",
+			ras, cas,
+			errors, syndrome, specific);
+
+		/*
+		 * Call the helper to output message
+		 * NOTE: Errors are reported per-branch, and not per-channel
+		 *	 Currently, we don't know how to identify the right
+		 *	 channel.
+		 */
+		edac_mc_handle_fbd_ce(mci, rank, channel,
+				      pvt->tmp_prt_buffer);
+	}
+	return;
+}
+
+/**
+ * i7300_check_error() - Calls the error checking subroutines
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_check_error(struct mem_ctl_info *mci)
+{
+	i7300_process_error_global(mci);
+	i7300_process_fbd_error(mci);
+};
+
+/**
+ * i7300_clear_error() - Clears the error registers
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_clear_error(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt = mci->pvt_info;
+	u32 value;
+	/*
+	 * All error values are RWC - we need to read and write 1 to the
+	 * bit that we want to cleanup
+	 */
+
+	/* Clear global error registers */
+	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_HI, &value);
+	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_HI, value);
+
+	pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_LO, &value);
+	pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs,
+			      FERR_GLOBAL_LO, value);
+
+	/* Clear FBD error registers */
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_FAT_FBD, &value);
+	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_FAT_FBD, value);
+
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_NF_FBD, &value);
+	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      FERR_NF_FBD, value);
+}
+
+/**
+ * i7300_enable_error_reporting() - Enable the memory reporting logic at the
+ *				    hardware
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt = mci->pvt_info;
+	u32 fbd_error_mask;
+
+	/* Read the FBD Error Mask Register */
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			      EMASK_FBD, &fbd_error_mask);
+
+	/* Enable with a '0' */
+	fbd_error_mask &= ~(EMASK_FBD_ERR_MASK);
+
+	pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
+			       EMASK_FBD, fbd_error_mask);
+}
+
+/************************************************
+ * i7300 Functions related to memory enumberation
+ ************************************************/
+
+/**
+ * decode_mtr() - Decodes the MTR descriptor, filling the edac structs
+ * @pvt: pointer to the private data struct used by i7300 driver
+ * @slot: DIMM slot (0 to 7)
+ * @ch: Channel number within the branch (0 or 1)
+ * @branch: Branch number (0 or 1)
+ * @dinfo: Pointer to DIMM info where dimm size is stored
+ * @p_csrow: Pointer to the struct csrow_info that corresponds to that element
+ */
+static int decode_mtr(struct i7300_pvt *pvt,
+		      int slot, int ch, int branch,
+		      struct i7300_dimm_info *dinfo,
+		      struct csrow_info *p_csrow,
+		      u32 *nr_pages)
+{
+	int mtr, ans, addrBits, channel;
+
+	channel = to_channel(ch, branch);
+
+	mtr = pvt->mtr[slot][branch];
+	ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0;
+
+	debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n",
+		slot, channel,
+		ans ? "Present" : "NOT Present");
+
+	/* Determine if there is a DIMM present in this DIMM slot */
+	if (!ans)
+		return 0;
+
+	/* Start with the number of bits for a Bank
+	* on the DRAM */
+	addrBits = MTR_DRAM_BANKS_ADDR_BITS;
+	/* Add thenumber of ROW bits */
+	addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+	/* add the number of COLUMN bits */
+	addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+	/* add the number of RANK bits */
+	addrBits += MTR_DIMM_RANKS(mtr);
+
+	addrBits += 6;	/* add 64 bits per DIMM */
+	addrBits -= 20;	/* divide by 2^^20 */
+	addrBits -= 3;	/* 8 bits per bytes */
+
+	dinfo->megabytes = 1 << addrBits;
+	*nr_pages = dinfo->megabytes << 8;
+
+	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+
+	debugf2("\t\tELECTRICAL THROTTLING is %s\n",
+		MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled");
+
+	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single");
+	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+	debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
+
+	p_csrow->grain = 8;
+	p_csrow->mtype = MEM_FB_DDR2;
+	p_csrow->csrow_idx = slot;
+	p_csrow->page_mask = 0;
+
+	/*
+	 * The type of error detection actually depends of the
+	 * mode of operation. When it is just one single memory chip, at
+	 * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code.
+	 * In normal or mirrored mode, it uses Lockstep mode,
+	 * with the possibility of using an extended algorithm for x8 memories
+	 * See datasheet Sections 7.3.6 to 7.3.8
+	 */
+
+	if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
+		p_csrow->edac_mode = EDAC_SECDED;
+		debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
+	} else {
+		debugf2("\t\tECC code is on Lockstep mode\n");
+		if (MTR_DRAM_WIDTH(mtr) == 8)
+			p_csrow->edac_mode = EDAC_S8ECD8ED;
+		else
+			p_csrow->edac_mode = EDAC_S4ECD4ED;
+	}
+
+	/* ask what device type on this row */
+	if (MTR_DRAM_WIDTH(mtr) == 8) {
+		debugf2("\t\tScrub algorithm for x8 is on %s mode\n",
+			IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
+					    "enhanced" : "normal");
+
+		p_csrow->dtype = DEV_X8;
+	} else
+		p_csrow->dtype = DEV_X4;
+
+	return mtr;
+}
+
+/**
+ * print_dimm_size() - Prints dump of the memory organization
+ * @pvt: pointer to the private data struct used by i7300 driver
+ *
+ * Useful for debug. If debug is disabled, this routine do nothing
+ */
+static void print_dimm_size(struct i7300_pvt *pvt)
+{
+#ifdef CONFIG_EDAC_DEBUG
+	struct i7300_dimm_info *dinfo;
+	char *p;
+	int space, n;
+	int channel, slot;
+
+	space = PAGE_SIZE;
+	p = pvt->tmp_prt_buffer;
+
+	n = snprintf(p, space, "              ");
+	p += n;
+	space -= n;
+	for (channel = 0; channel < MAX_CHANNELS; channel++) {
+		n = snprintf(p, space, "channel %d | ", channel);
+		p += n;
+		space -= n;
+	}
+	debugf2("%s\n", pvt->tmp_prt_buffer);
+	p = pvt->tmp_prt_buffer;
+	space = PAGE_SIZE;
+	n = snprintf(p, space, "-------------------------------"
+			       "------------------------------");
+	p += n;
+	space -= n;
+	debugf2("%s\n", pvt->tmp_prt_buffer);
+	p = pvt->tmp_prt_buffer;
+	space = PAGE_SIZE;
+
+	for (slot = 0; slot < MAX_SLOTS; slot++) {
+		n = snprintf(p, space, "csrow/SLOT %d  ", slot);
+		p += n;
+		space -= n;
+
+		for (channel = 0; channel < MAX_CHANNELS; channel++) {
+			dinfo = &pvt->dimm_info[slot][channel];
+			n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
+			p += n;
+			space -= n;
+		}
+
+		debugf2("%s\n", pvt->tmp_prt_buffer);
+		p = pvt->tmp_prt_buffer;
+		space = PAGE_SIZE;
+	}
+
+	n = snprintf(p, space, "-------------------------------"
+			       "------------------------------");
+	p += n;
+	space -= n;
+	debugf2("%s\n", pvt->tmp_prt_buffer);
+	p = pvt->tmp_prt_buffer;
+	space = PAGE_SIZE;
+#endif
+}
+
+/**
+ * i7300_init_csrows() - Initialize the 'csrows' table within
+ *			 the mci control structure with the
+ *			 addressing of memory.
+ * @mci: struct mem_ctl_info pointer
+ */
+static int i7300_init_csrows(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	struct i7300_dimm_info *dinfo;
+	struct csrow_info *p_csrow;
+	int rc = -ENODEV;
+	int mtr;
+	int ch, branch, slot, channel;
+	u32 last_page = 0, nr_pages;
+
+	pvt = mci->pvt_info;
+
+	debugf2("Memory Technology Registers:\n");
+
+	/* Get the AMB present registers for the four channels */
+	for (branch = 0; branch < MAX_BRANCHES; branch++) {
+		/* Read and dump branch 0's MTRs */
+		channel = to_channel(0, branch);
+		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+				     AMBPRESENT_0,
+				&pvt->ambpresent[channel]);
+		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
+			channel, pvt->ambpresent[channel]);
+
+		channel = to_channel(1, branch);
+		pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+				     AMBPRESENT_1,
+				&pvt->ambpresent[channel]);
+		debugf2("\t\tAMB-present CH%d = 0x%x:\n",
+			channel, pvt->ambpresent[channel]);
+	}
+
+	/* Get the set of MTR[0-7] regs by each branch */
+	for (slot = 0; slot < MAX_SLOTS; slot++) {
+		int where = mtr_regs[slot];
+		for (branch = 0; branch < MAX_BRANCHES; branch++) {
+			pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
+					where,
+					&pvt->mtr[slot][branch]);
+			for (ch = 0; ch < MAX_BRANCHES; ch++) {
+				int channel = to_channel(ch, branch);
+
+				dinfo = &pvt->dimm_info[slot][channel];
+				p_csrow = &mci->csrows[slot];
+
+				mtr = decode_mtr(pvt, slot, ch, branch,
+						 dinfo, p_csrow, &nr_pages);
+				/* if no DIMMS on this row, continue */
+				if (!MTR_DIMMS_PRESENT(mtr))
+					continue;
+
+				/* Update per_csrow memory count */
+				p_csrow->nr_pages += nr_pages;
+				p_csrow->first_page = last_page;
+				last_page += nr_pages;
+				p_csrow->last_page = last_page;
+
+				rc = 0;
+			}
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * decode_mir() - Decodes Memory Interleave Register (MIR) info
+ * @int mir_no: number of the MIR register to decode
+ * @mir: array with the MIR data cached on the driver
+ */
+static void decode_mir(int mir_no, u16 mir[MAX_MIR])
+{
+	if (mir[mir_no] & 3)
+		debugf2("MIR%d: limit= 0x%x Branch(es) that participate:"
+			" %s %s\n",
+			mir_no,
+			(mir[mir_no] >> 4) & 0xfff,
+			(mir[mir_no] & 1) ? "B0" : "",
+			(mir[mir_no] & 2) ? "B1" : "");
+}
+
+/**
+ * i7300_get_mc_regs() - Get the contents of the MC enumeration registers
+ * @mci: struct mem_ctl_info pointer
+ *
+ * Data read is cached internally for its usage when needed
+ */
+static int i7300_get_mc_regs(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	u32 actual_tolm;
+	int i, rc;
+
+	pvt = mci->pvt_info;
+
+	pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE,
+			(u32 *) &pvt->ambase);
+
+	debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase);
+
+	/* Get the Branch Map regs */
+	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm);
+	pvt->tolm >>= 12;
+	debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+		pvt->tolm);
+
+	actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28));
+	debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n",
+		actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28);
+
+	/* Get memory controller settings */
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS,
+			     &pvt->mc_settings);
+	pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A,
+			     &pvt->mc_settings_a);
+
+	if (IS_SINGLE_MODE(pvt->mc_settings_a))
+		debugf0("Memory controller operating on single mode\n");
+	else
+		debugf0("Memory controller operating on %s mode\n",
+		IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored");
+
+	debugf0("Error detection is %s\n",
+		IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+	debugf0("Retry is %s\n",
+		IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled");
+
+	/* Get Memory Interleave Range registers */
+	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0,
+			     &pvt->mir[0]);
+	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1,
+			     &pvt->mir[1]);
+	pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2,
+			     &pvt->mir[2]);
+
+	/* Decode the MIR regs */
+	for (i = 0; i < MAX_MIR; i++)
+		decode_mir(i, pvt->mir);
+
+	rc = i7300_init_csrows(mci);
+	if (rc < 0)
+		return rc;
+
+	/* Go and determine the size of each DIMM and place in an
+	 * orderly matrix */
+	print_dimm_size(pvt);
+
+	return 0;
+}
+
+/*************************************************
+ * i7300 Functions related to device probe/release
+ *************************************************/
+
+/**
+ * i7300_put_devices() - Release the PCI devices
+ * @mci: struct mem_ctl_info pointer
+ */
+static void i7300_put_devices(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	int branch;
+
+	pvt = mci->pvt_info;
+
+	/* Decrement usage count for devices */
+	for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++)
+		pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]);
+	pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs);
+	pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map);
+}
+
+/**
+ * i7300_get_devices() - Find and perform 'get' operation on the MCH's
+ *			 device/functions we want to reference for this driver
+ * @mci: struct mem_ctl_info pointer
+ *
+ * Access and prepare the several devices for usage:
+ * I7300 devices used by this driver:
+ *    Device 16, functions 0,1 and 2:	PCI_DEVICE_ID_INTEL_I7300_MCH_ERR
+ *    Device 21 function 0:		PCI_DEVICE_ID_INTEL_I7300_MCH_FB0
+ *    Device 22 function 0:		PCI_DEVICE_ID_INTEL_I7300_MCH_FB1
+ */
+static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
+{
+	struct i7300_pvt *pvt;
+	struct pci_dev *pdev;
+
+	pvt = mci->pvt_info;
+
+	/* Attempt to 'get' the MCH register we want */
+	pdev = NULL;
+	while (!pvt->pci_dev_16_1_fsb_addr_map ||
+	       !pvt->pci_dev_16_2_fsb_err_regs) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				      PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
+		if (!pdev) {
+			/* End of list, leave */
+			i7300_printk(KERN_ERR,
+				"'system address,Process Bus' "
+				"device not found:"
+				"vendor 0x%x device 0x%x ERR funcs "
+				"(broken BIOS?)\n",
+				PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+			goto error;
+		}
+
+		/* Store device 16 funcs 1 and 2 */
+		switch (PCI_FUNC(pdev->devfn)) {
+		case 1:
+			pvt->pci_dev_16_1_fsb_addr_map = pdev;
+			break;
+		case 2:
+			pvt->pci_dev_16_2_fsb_err_regs = pdev;
+			break;
+		}
+	}
+
+	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->pci_dev_16_0_fsb_ctlr),
+		pvt->pci_dev_16_0_fsb_ctlr->vendor,
+		pvt->pci_dev_16_0_fsb_ctlr->device);
+	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->pci_dev_16_1_fsb_addr_map),
+		pvt->pci_dev_16_1_fsb_addr_map->vendor,
+		pvt->pci_dev_16_1_fsb_addr_map->device);
+	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->pci_dev_16_2_fsb_err_regs),
+		pvt->pci_dev_16_2_fsb_err_regs->vendor,
+		pvt->pci_dev_16_2_fsb_err_regs->device);
+
+	pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL,
+					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB0,
+					    NULL);
+	if (!pvt->pci_dev_2x_0_fbd_branch[0]) {
+		i7300_printk(KERN_ERR,
+			"MC: 'BRANCH 0' device not found:"
+			"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0);
+		goto error;
+	}
+
+	pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL,
+					    PCI_DEVICE_ID_INTEL_I7300_MCH_FB1,
+					    NULL);
+	if (!pvt->pci_dev_2x_0_fbd_branch[1]) {
+		i7300_printk(KERN_ERR,
+			"MC: 'BRANCH 1' device not found:"
+			"vendor 0x%x device 0x%x Func 0 "
+			"(broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL,
+			PCI_DEVICE_ID_INTEL_I7300_MCH_FB1);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	i7300_put_devices(mci);
+	return -ENODEV;
+}
+
+/**
+ * i7300_init_one() - Probe for one instance of the device
+ * @pdev: struct pci_dev pointer
+ * @id: struct pci_device_id pointer - currently unused
+ */
+static int __devinit i7300_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *id)
+{
+	struct mem_ctl_info *mci;
+	struct i7300_pvt *pvt;
+	int num_channels;
+	int num_dimms_per_channel;
+	int num_csrows;
+	int rc;
+
+	/* wake up device */
+	rc = pci_enable_device(pdev);
+	if (rc == -EIO)
+		return rc;
+
+	debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+		__func__,
+		pdev->bus->number,
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+	/* We only are looking for func 0 of the set */
+	if (PCI_FUNC(pdev->devfn) != 0)
+		return -ENODEV;
+
+	/* As we don't have a motherboard identification routine to determine
+	 * actual number of slots/dimms per channel, we thus utilize the
+	 * resource as specified by the chipset. Thus, we might have
+	 * have more DIMMs per channel than actually on the mobo, but this
+	 * allows the driver to support upto the chipset max, without
+	 * some fancy mobo determination.
+	 */
+	num_dimms_per_channel = MAX_SLOTS;
+	num_channels = MAX_CHANNELS;
+	num_csrows = MAX_SLOTS * MAX_CHANNELS;
+
+	debugf0("MC: %s(): Number of - Channels= %d  DIMMS= %d  CSROWS= %d\n",
+		__func__, num_channels, num_dimms_per_channel, num_csrows);
+
+	/* allocate a new MC control structure */
+	mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+	if (mci == NULL)
+		return -ENOMEM;
+
+	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+
+	pvt = mci->pvt_info;
+	pvt->pci_dev_16_0_fsb_ctlr = pdev;	/* Record this device in our private */
+
+	pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!pvt->tmp_prt_buffer) {
+		edac_mc_free(mci);
+		return -ENOMEM;
+	}
+
+	/* 'get' the pci devices we want to reserve for our use */
+	if (i7300_get_devices(mci))
+		goto fail0;
+
+	mci->mc_idx = 0;
+	mci->mtype_cap = MEM_FLAG_FB_DDR2;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE;
+	mci->edac_cap = EDAC_FLAG_NONE;
+	mci->mod_name = "i7300_edac.c";
+	mci->mod_ver = I7300_REVISION;
+	mci->ctl_name = i7300_devs[0].ctl_name;
+	mci->dev_name = pci_name(pdev);
+	mci->ctl_page_to_phys = NULL;
+
+	/* Set the function pointer to an actual operation function */
+	mci->edac_check = i7300_check_error;
+
+	/* initialize the MC control structure 'csrows' table
+	 * with the mapping and control information */
+	if (i7300_get_mc_regs(mci)) {
+		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+			"    because i7300_init_csrows() returned nonzero "
+			"value\n");
+		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
+	} else {
+		debugf1("MC: Enable error reporting now\n");
+		i7300_enable_error_reporting(mci);
+	}
+
+	/* add this new MC control structure to EDAC's list of MCs */
+	if (edac_mc_add_mc(mci)) {
+		debugf0("MC: " __FILE__
+			": %s(): failed edac_mc_add_mc()\n", __func__);
+		/* FIXME: perhaps some code should go here that disables error
+		 * reporting if we just enabled it
+		 */
+		goto fail1;
+	}
+
+	i7300_clear_error(mci);
+
+	/* allocating generic PCI control info */
+	i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i7300_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
+	return 0;
+
+	/* Error exit unwinding stack */
+fail1:
+
+	i7300_put_devices(mci);
+
+fail0:
+	kfree(pvt->tmp_prt_buffer);
+	edac_mc_free(mci);
+	return -ENODEV;
+}
+
+/**
+ * i7300_remove_one() - Remove the driver
+ * @pdev: struct pci_dev pointer
+ */
+static void __devexit i7300_remove_one(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+	char *tmp;
+
+	debugf0(__FILE__ ": %s()\n", __func__);
+
+	if (i7300_pci)
+		edac_pci_release_generic_ctl(i7300_pci);
+
+	mci = edac_mc_del_mc(&pdev->dev);
+	if (!mci)
+		return;
+
+	tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer;
+
+	/* retrieve references to resources, and free those resources */
+	i7300_put_devices(mci);
+
+	kfree(tmp);
+	edac_mc_free(mci);
+}
+
+/*
+ * pci_device_id: table for which devices we are looking for
+ *
+ * Has only 8086:360c PCI ID
+ */
+static const struct pci_device_id i7300_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)},
+	{0,}			/* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i7300_pci_tbl);
+
+/*
+ * i7300_driver: pci_driver structure for this module
+ */
+static struct pci_driver i7300_driver = {
+	.name = "i7300_edac",
+	.probe = i7300_init_one,
+	.remove = __devexit_p(i7300_remove_one),
+	.id_table = i7300_pci_tbl,
+};
+
+/**
+ * i7300_init() - Registers the driver
+ */
+static int __init i7300_init(void)
+{
+	int pci_rc;
+
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
+	opstate_init();
+
+	pci_rc = pci_register_driver(&i7300_driver);
+
+	return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/**
+ * i7300_init() - Unregisters the driver
+ */
+static void __exit i7300_exit(void)
+{
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	pci_unregister_driver(&i7300_driver);
+}
+
+module_init(i7300_init);
+module_exit(i7300_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - "
+		   I7300_REVISION);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff -druN linux-libre-2.6.36-gnu/drivers/edac/i7core_edac.c linux-libre-2.6.37-gnu/drivers/edac/i7core_edac.c
--- linux-libre-2.6.36-gnu/drivers/edac/i7core_edac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/i7core_edac.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,6 +39,14 @@
 
 #include "edac_core.h"
 
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+static int probed;
+
+static int use_pci_fixup;
+module_param(use_pci_fixup, int, 0444);
+MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
 /*
  * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
  * registers start at bus 255, and are not reported by BIOS.
@@ -212,8 +220,8 @@
 };
 
 struct pci_id_table {
-	struct pci_id_descr	*descr;
-	int			n_devs;
+	const struct pci_id_descr	*descr;
+	int				n_devs;
 };
 
 struct i7core_dev {
@@ -235,8 +243,6 @@
 	struct i7core_inject	inject;
 	struct i7core_channel	channel[NUM_CHANS];
 
-	int		channels; /* Number of active channels */
-
 	int		ce_count_available;
 	int 		csrow_map[NUM_CHANS][MAX_DIMMS];
 
@@ -261,22 +267,22 @@
 
 	/* Count indicator to show errors not got */
 	unsigned		mce_overrun;
-};
 
-/* Static vars */
-static LIST_HEAD(i7core_edac_list);
-static DEFINE_MUTEX(i7core_edac_lock);
+	/* Struct to control EDAC polling */
+	struct edac_pci_ctl_info *i7core_pci;
+};
 
 #define PCI_DESCR(device, function, device_id)	\
 	.dev = (device),			\
 	.func = (function),			\
 	.dev_id = (device_id)
 
-struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
 		/* Memory controller */
 	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR)     },
 	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD)  },
-			/* Exists only for RDIMM */
+
+		/* Exists only for RDIMM */
 	{ PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1  },
 	{ PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
 
@@ -297,19 +303,9 @@
 	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
 	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
 	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC)   },
-
-		/* Generic Non-core registers */
-	/*
-	 * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
-	 * On Xeon 55xx, however, it has a different id (8086:2c40). So,
-	 * the probing code needs to test for the other address in case of
-	 * failure of this one
-	 */
-	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE)  },
-
 };
 
-struct pci_id_descr pci_dev_descr_lynnfield[] = {
+static const struct pci_id_descr pci_dev_descr_lynnfield[] = {
 	{ PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR)         },
 	{ PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD)      },
 	{ PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST)     },
@@ -323,15 +319,9 @@
 	{ PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
 	{ PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
 	{ PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC)   },
-
-	/*
-	 * This is the PCI device has an alternate address on some
-	 * processors like Core i7 860
-	 */
-	{ PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE)     },
 };
 
-struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
+static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
 		/* Memory controller */
 	{ PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2)     },
 	{ PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2)  },
@@ -356,17 +346,14 @@
 	{ PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
 	{ PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
 	{ PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2)   },
-
-		/* Generic Non-core registers */
-	{ PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2)  },
-
 };
 
-#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) }
-struct pci_id_table pci_dev_table[] = {
+#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
+static const struct pci_id_table pci_dev_table[] = {
 	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
 	PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
 	PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
+	{0,}			/* 0 terminated list. */
 };
 
 /*
@@ -378,8 +365,6 @@
 	{0,}			/* 0 terminated list. */
 };
 
-static struct edac_pci_ctl_info *i7core_pci;
-
 /****************************************************************************
 			Anciliary status routines
  ****************************************************************************/
@@ -442,6 +427,36 @@
 	return NULL;
 }
 
+static struct i7core_dev *alloc_i7core_dev(u8 socket,
+					   const struct pci_id_table *table)
+{
+	struct i7core_dev *i7core_dev;
+
+	i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+	if (!i7core_dev)
+		return NULL;
+
+	i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs,
+				   GFP_KERNEL);
+	if (!i7core_dev->pdev) {
+		kfree(i7core_dev);
+		return NULL;
+	}
+
+	i7core_dev->socket = socket;
+	i7core_dev->n_devs = table->n_devs;
+	list_add_tail(&i7core_dev->list, &i7core_edac_list);
+
+	return i7core_dev;
+}
+
+static void free_i7core_dev(struct i7core_dev *i7core_dev)
+{
+	list_del(&i7core_dev->list);
+	kfree(i7core_dev->pdev);
+	kfree(i7core_dev);
+}
+
 /****************************************************************************
 			Memory check routines
  ****************************************************************************/
@@ -484,7 +499,7 @@
  * to add a fake description for csrows.
  * So, this driver is attributing one DIMM memory for one csrow.
  */
-static int i7core_get_active_channels(u8 socket, unsigned *channels,
+static int i7core_get_active_channels(const u8 socket, unsigned *channels,
 				      unsigned *csrows)
 {
 	struct pci_dev *pdev = NULL;
@@ -545,12 +560,13 @@
 	return 0;
 }
 
-static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+static int get_dimm_config(const struct mem_ctl_info *mci)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
 	struct csrow_info *csr;
 	struct pci_dev *pdev;
 	int i, j;
+	int csrow = 0;
 	unsigned long last_page = 0;
 	enum edac_type mode;
 	enum mem_type mtype;
@@ -664,13 +680,9 @@
 				RANKOFFSET(dimm_dod[j]),
 				banks, ranks, rows, cols);
 
-#if PAGE_SHIFT > 20
-			npages = size >> (PAGE_SHIFT - 20);
-#else
-			npages = size << (20 - PAGE_SHIFT);
-#endif
+			npages = MiB_TO_PAGES(size);
 
-			csr = &mci->csrows[*csrow];
+			csr = &mci->csrows[csrow];
 			csr->first_page = last_page + 1;
 			last_page += npages;
 			csr->last_page = last_page;
@@ -678,13 +690,13 @@
 
 			csr->page_mask = 0;
 			csr->grain = 8;
-			csr->csrow_idx = *csrow;
+			csr->csrow_idx = csrow;
 			csr->nr_channels = 1;
 
 			csr->channels[0].chan_idx = i;
 			csr->channels[0].ce_count = 0;
 
-			pvt->csrow_map[i][j] = *csrow;
+			pvt->csrow_map[i][j] = csrow;
 
 			switch (banks) {
 			case 4:
@@ -703,7 +715,7 @@
 			csr->edac_mode = mode;
 			csr->mtype = mtype;
 
-			(*csrow)++;
+			csrow++;
 		}
 
 		pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
@@ -736,7 +748,7 @@
    we're disabling error injection on all write calls to the sysfs nodes that
    controls the error code injection.
  */
-static int disable_inject(struct mem_ctl_info *mci)
+static int disable_inject(const struct mem_ctl_info *mci)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
 
@@ -921,7 +933,7 @@
 DECLARE_ADDR_MATCH(page, 0x10000);
 DECLARE_ADDR_MATCH(col, 0x4000);
 
-static int write_and_test(struct pci_dev *dev, int where, u32 val)
+static int write_and_test(struct pci_dev *dev, const int where, const u32 val)
 {
 	u32 read;
 	int count;
@@ -1120,35 +1132,34 @@
  * Sysfs struct
  */
 
-
-static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
 	ATTR_ADDR_MATCH(channel),
 	ATTR_ADDR_MATCH(dimm),
 	ATTR_ADDR_MATCH(rank),
 	ATTR_ADDR_MATCH(bank),
 	ATTR_ADDR_MATCH(page),
 	ATTR_ADDR_MATCH(col),
-	{ .attr = { .name = NULL } }
+	{ } /* End of list */
 };
 
-static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+static const struct mcidev_sysfs_group i7core_inject_addrmatch = {
 	.name  = "inject_addrmatch",
 	.mcidev_attr = i7core_addrmatch_attrs,
 };
 
-static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
 	ATTR_COUNTER(0),
 	ATTR_COUNTER(1),
 	ATTR_COUNTER(2),
 	{ .attr = { .name = NULL } }
 };
 
-static struct mcidev_sysfs_group i7core_udimm_counters = {
+static const struct mcidev_sysfs_group i7core_udimm_counters = {
 	.name  = "all_channel_counts",
 	.mcidev_attr = i7core_udimm_counters_attrs,
 };
 
-static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
+static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = {
 	{
 		.attr = {
 			.name = "inject_section",
@@ -1180,8 +1191,44 @@
 		.show  = i7core_inject_enable_show,
 		.store = i7core_inject_enable_store,
 	},
-	{ .attr = { .name = NULL } },	/* Reserved for udimm counters */
-	{ .attr = { .name = NULL } }
+	{ }	/* End of list */
+};
+
+static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = {
+	{
+		.attr = {
+			.name = "inject_section",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_section_show,
+		.store = i7core_inject_section_store,
+	}, {
+		.attr = {
+			.name = "inject_type",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_type_show,
+		.store = i7core_inject_type_store,
+	}, {
+		.attr = {
+			.name = "inject_eccmask",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_eccmask_show,
+		.store = i7core_inject_eccmask_store,
+	}, {
+		.grp = &i7core_inject_addrmatch,
+	}, {
+		.attr = {
+			.name = "inject_enable",
+			.mode = (S_IRUGO | S_IWUSR)
+		},
+		.show  = i7core_inject_enable_show,
+		.store = i7core_inject_enable_store,
+	}, {
+		.grp = &i7core_udimm_counters,
+	},
+	{ }	/* End of list */
 };
 
 /****************************************************************************
@@ -1189,7 +1236,7 @@
  ****************************************************************************/
 
 /*
- *	i7core_put_devices	'put' all the devices that we have
+ *	i7core_put_all_devices	'put' all the devices that we have
  *				reserved via 'get'
  */
 static void i7core_put_devices(struct i7core_dev *i7core_dev)
@@ -1206,23 +1253,23 @@
 			PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 		pci_dev_put(pdev);
 	}
-	kfree(i7core_dev->pdev);
-	list_del(&i7core_dev->list);
-	kfree(i7core_dev);
 }
 
 static void i7core_put_all_devices(void)
 {
 	struct i7core_dev *i7core_dev, *tmp;
 
-	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list)
+	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
 		i7core_put_devices(i7core_dev);
+		free_i7core_dev(i7core_dev);
+	}
 }
 
-static void __init i7core_xeon_pci_fixup(struct pci_id_table *table)
+static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table)
 {
 	struct pci_dev *pdev = NULL;
 	int i;
+
 	/*
 	 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
 	 * aren't announced by acpi. So, we need to use a legacy scan probing
@@ -1257,16 +1304,18 @@
 }
 
 /*
- *	i7core_get_devices	Find and perform 'get' operation on the MCH's
+ *	i7core_get_all_devices	Find and perform 'get' operation on the MCH's
  *			device/functions we want to reference for this driver
  *
  *			Need to 'get' device 16 func 1 and func 2
  */
-int i7core_get_onedevice(struct pci_dev **prev, int devno,
-			 struct pci_id_descr *dev_descr, unsigned n_devs,
-			 unsigned last_bus)
+static int i7core_get_onedevice(struct pci_dev **prev,
+				const struct pci_id_table *table,
+				const unsigned devno,
+				const unsigned last_bus)
 {
 	struct i7core_dev *i7core_dev;
+	const struct pci_id_descr *dev_descr = &table->descr[devno];
 
 	struct pci_dev *pdev = NULL;
 	u8 bus = 0;
@@ -1275,20 +1324,6 @@
 	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
 			      dev_descr->dev_id, *prev);
 
-	/*
-	 * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
-	 * is at addr 8086:2c40, instead of 8086:2c41. So, we need
-	 * to probe for the alternate address in case of failure
-	 */
-	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
-		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
-
-	if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
-		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
-				      *prev);
-
 	if (!pdev) {
 		if (*prev) {
 			*prev = pdev;
@@ -1315,18 +1350,11 @@
 
 	i7core_dev = get_i7core_dev(socket);
 	if (!i7core_dev) {
-		i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
-		if (!i7core_dev)
-			return -ENOMEM;
-		i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs,
-					   GFP_KERNEL);
-		if (!i7core_dev->pdev) {
-			kfree(i7core_dev);
+		i7core_dev = alloc_i7core_dev(socket, table);
+		if (!i7core_dev) {
+			pci_dev_put(pdev);
 			return -ENOMEM;
 		}
-		i7core_dev->socket = socket;
-		i7core_dev->n_devs = n_devs;
-		list_add_tail(&i7core_dev->list, &i7core_edac_list);
 	}
 
 	if (i7core_dev->pdev[devno]) {
@@ -1368,27 +1396,31 @@
 		dev_descr->func,
 		PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
+	/*
+	 * As stated on drivers/pci/search.c, the reference count for
+	 * @from is always decremented if it is not %NULL. So, as we need
+	 * to get all devices up to null, we need to do a get for the device
+	 */
+	pci_dev_get(pdev);
+
 	*prev = pdev;
 
 	return 0;
 }
 
-static int i7core_get_devices(struct pci_id_table *table)
+static int i7core_get_all_devices(void)
 {
 	int i, rc, last_bus;
 	struct pci_dev *pdev = NULL;
-	struct pci_id_descr *dev_descr;
+	const struct pci_id_table *table = pci_dev_table;
 
 	last_bus = i7core_pci_lastbus();
 
 	while (table && table->descr) {
-		dev_descr = table->descr;
 		for (i = 0; i < table->n_devs; i++) {
 			pdev = NULL;
 			do {
-				rc = i7core_get_onedevice(&pdev, i,
-							  &dev_descr[i],
-							  table->n_devs,
+				rc = i7core_get_onedevice(&pdev, table, i,
 							  last_bus);
 				if (rc < 0) {
 					if (i == 0) {
@@ -1404,7 +1436,6 @@
 	}
 
 	return 0;
-	return 0;
 }
 
 static int mci_bind_devs(struct mem_ctl_info *mci,
@@ -1414,10 +1445,6 @@
 	struct pci_dev *pdev;
 	int i, func, slot;
 
-	/* Associates i7core_dev and mci for future usage */
-	pvt->i7core_dev = i7core_dev;
-	i7core_dev->mci = mci;
-
 	pvt->is_registered = 0;
 	for (i = 0; i < i7core_dev->n_devs; i++) {
 		pdev = i7core_dev->pdev[i];
@@ -1448,15 +1475,6 @@
 			pvt->is_registered = 1;
 	}
 
-	/*
-	 * Add extra nodes to count errors on udimm
-	 * For registered memory, this is not needed, since the counters
-	 * are already displayed at the standard locations
-	 */
-	if (!pvt->is_registered)
-		i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp =
-			&i7core_udimm_counters;
-
 	return 0;
 
 error:
@@ -1470,7 +1488,9 @@
 			Error check routines
  ****************************************************************************/
 static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
-					 int chan, int dimm, int add)
+				      const int chan,
+				      const int dimm,
+				      const int add)
 {
 	char *msg;
 	struct i7core_pvt *pvt = mci->pvt_info;
@@ -1487,7 +1507,10 @@
 }
 
 static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
-			int chan, int new0, int new1, int new2)
+					 const int chan,
+					 const int new0,
+					 const int new1,
+					 const int new2)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
 	int add0 = 0, add1 = 0, add2 = 0;
@@ -1641,7 +1664,7 @@
  * fields
  */
 static void i7core_mce_output_error(struct mem_ctl_info *mci,
-				    struct mce *m)
+				    const struct mce *m)
 {
 	struct i7core_pvt *pvt = mci->pvt_info;
 	char *type, *optype, *err, *msg;
@@ -1845,28 +1868,85 @@
 	return 1;
 }
 
-static int i7core_register_mci(struct i7core_dev *i7core_dev,
-			       int num_channels, int num_csrows)
+static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
+{
+	pvt->i7core_pci = edac_pci_create_generic_ctl(
+						&pvt->i7core_dev->pdev[0]->dev,
+						EDAC_MOD_STR);
+	if (unlikely(!pvt->i7core_pci))
+		pr_warn("Unable to setup PCI error report via EDAC\n");
+}
+
+static void i7core_pci_ctl_release(struct i7core_pvt *pvt)
+{
+	if (likely(pvt->i7core_pci))
+		edac_pci_release_generic_ctl(pvt->i7core_pci);
+	else
+		i7core_printk(KERN_ERR,
+				"Couldn't find mem_ctl_info for socket %d\n",
+				pvt->i7core_dev->socket);
+	pvt->i7core_pci = NULL;
+}
+
+static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
+{
+	struct mem_ctl_info *mci = i7core_dev->mci;
+	struct i7core_pvt *pvt;
+
+	if (unlikely(!mci || !mci->pvt_info)) {
+		debugf0("MC: " __FILE__ ": %s(): dev = %p\n",
+			__func__, &i7core_dev->pdev[0]->dev);
+
+		i7core_printk(KERN_ERR, "Couldn't find mci handler\n");
+		return;
+	}
+
+	pvt = mci->pvt_info;
+
+	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+		__func__, mci, &i7core_dev->pdev[0]->dev);
+
+	/* Disable MCE NMI handler */
+	edac_mce_unregister(&pvt->edac_mce);
+
+	/* Disable EDAC polling */
+	i7core_pci_ctl_release(pvt);
+
+	/* Remove MC sysfs nodes */
+	edac_mc_del_mc(mci->dev);
+
+	debugf1("%s: free mci struct\n", mci->ctl_name);
+	kfree(mci->ctl_name);
+	edac_mc_free(mci);
+	i7core_dev->mci = NULL;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev)
 {
 	struct mem_ctl_info *mci;
 	struct i7core_pvt *pvt;
-	int csrow = 0;
-	int rc;
+	int rc, channels, csrows;
+
+	/* Check the number of active and not disabled channels */
+	rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows);
+	if (unlikely(rc < 0))
+		return rc;
 
 	/* allocate a new MC control structure */
-	mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels,
-			    i7core_dev->socket);
+	mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket);
 	if (unlikely(!mci))
 		return -ENOMEM;
 
-	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
-
-	/* record ptr to the generic device */
-	mci->dev = &i7core_dev->pdev[0]->dev;
+	debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
+		__func__, mci, &i7core_dev->pdev[0]->dev);
 
 	pvt = mci->pvt_info;
 	memset(pvt, 0, sizeof(*pvt));
 
+	/* Associates i7core_dev and mci for future usage */
+	pvt->i7core_dev = i7core_dev;
+	i7core_dev->mci = mci;
+
 	/*
 	 * FIXME: how to handle RDDR3 at MCI level? It is possible to have
 	 * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
@@ -1881,17 +1961,23 @@
 				  i7core_dev->socket);
 	mci->dev_name = pci_name(i7core_dev->pdev[0]);
 	mci->ctl_page_to_phys = NULL;
-	mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs;
-	/* Set the function pointer to an actual operation function */
-	mci->edac_check = i7core_check_error;
 
 	/* Store pci devices at mci for faster access */
 	rc = mci_bind_devs(mci, i7core_dev);
 	if (unlikely(rc < 0))
-		goto fail;
+		goto fail0;
+
+	if (pvt->is_registered)
+		mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs;
+	else
+		mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs;
 
 	/* Get dimm basic config */
-	get_dimm_config(mci, &csrow);
+	get_dimm_config(mci);
+	/* record ptr to the generic device */
+	mci->dev = &i7core_dev->pdev[0]->dev;
+	/* Set the function pointer to an actual operation function */
+	mci->edac_check = i7core_check_error;
 
 	/* add this new MC control structure to EDAC's list of MCs */
 	if (unlikely(edac_mc_add_mc(mci))) {
@@ -1902,19 +1988,7 @@
 		 */
 
 		rc = -EINVAL;
-		goto fail;
-	}
-
-	/* allocating generic PCI control info */
-	i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev,
-						 EDAC_MOD_STR);
-	if (unlikely(!i7core_pci)) {
-		printk(KERN_WARNING
-			"%s(): Unable to create PCI control\n",
-			__func__);
-		printk(KERN_WARNING
-			"%s(): PCI error report via EDAC not setup\n",
-			__func__);
+		goto fail0;
 	}
 
 	/* Default error mask is any memory */
@@ -1925,19 +1999,28 @@
 	pvt->inject.page = -1;
 	pvt->inject.col = -1;
 
+	/* allocating generic PCI control info */
+	i7core_pci_ctl_create(pvt);
+
 	/* Registers on edac_mce in order to receive memory errors */
 	pvt->edac_mce.priv = mci;
 	pvt->edac_mce.check_error = i7core_mce_check_error;
-
 	rc = edac_mce_register(&pvt->edac_mce);
 	if (unlikely(rc < 0)) {
 		debugf0("MC: " __FILE__
 			": %s(): failed edac_mce_register()\n", __func__);
+		goto fail1;
 	}
 
-fail:
-	if (rc < 0)
-		edac_mc_free(mci);
+	return 0;
+
+fail1:
+	i7core_pci_ctl_release(pvt);
+	edac_mc_del_mc(mci->dev);
+fail0:
+	kfree(mci->ctl_name);
+	edac_mc_free(mci);
+	i7core_dev->mci = NULL;
 	return rc;
 }
 
@@ -1949,8 +2032,6 @@
  *		< 0 for error code
  */
 
-static int probed = 0;
-
 static int __devinit i7core_probe(struct pci_dev *pdev,
 				  const struct pci_device_id *id)
 {
@@ -1965,25 +2046,16 @@
 	 */
 	if (unlikely(probed >= 1)) {
 		mutex_unlock(&i7core_edac_lock);
-		return -EINVAL;
+		return -ENODEV;
 	}
 	probed++;
 
-	rc = i7core_get_devices(pci_dev_table);
+	rc = i7core_get_all_devices();
 	if (unlikely(rc < 0))
 		goto fail0;
 
 	list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
-		int channels;
-		int csrows;
-
-		/* Check the number of active and not disabled channels */
-		rc = i7core_get_active_channels(i7core_dev->socket,
-						&channels, &csrows);
-		if (unlikely(rc < 0))
-			goto fail1;
-
-		rc = i7core_register_mci(i7core_dev, channels, csrows);
+		rc = i7core_register_mci(i7core_dev);
 		if (unlikely(rc < 0))
 			goto fail1;
 	}
@@ -1994,6 +2066,9 @@
 	return 0;
 
 fail1:
+	list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+		i7core_unregister_mci(i7core_dev);
+
 	i7core_put_all_devices();
 fail0:
 	mutex_unlock(&i7core_edac_lock);
@@ -2006,14 +2081,10 @@
  */
 static void __devexit i7core_remove(struct pci_dev *pdev)
 {
-	struct mem_ctl_info *mci;
-	struct i7core_dev *i7core_dev, *tmp;
+	struct i7core_dev *i7core_dev;
 
 	debugf0(__FILE__ ": %s()\n", __func__);
 
-	if (i7core_pci)
-		edac_pci_release_generic_ctl(i7core_pci);
-
 	/*
 	 * we have a trouble here: pdev value for removal will be wrong, since
 	 * it will point to the X58 register used to detect that the machine
@@ -2023,22 +2094,18 @@
 	 */
 
 	mutex_lock(&i7core_edac_lock);
-	list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
-		mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
-		if (mci) {
-			struct i7core_pvt *pvt = mci->pvt_info;
 
-			i7core_dev = pvt->i7core_dev;
-			edac_mce_unregister(&pvt->edac_mce);
-			kfree(mci->ctl_name);
-			edac_mc_free(mci);
-			i7core_put_devices(i7core_dev);
-		} else {
-			i7core_printk(KERN_ERR,
-				      "Couldn't find mci for socket %d\n",
-				      i7core_dev->socket);
-		}
+	if (unlikely(!probed)) {
+		mutex_unlock(&i7core_edac_lock);
+		return;
 	}
+
+	list_for_each_entry(i7core_dev, &i7core_edac_list, list)
+		i7core_unregister_mci(i7core_dev);
+
+	/* Release PCI resources */
+	i7core_put_all_devices();
+
 	probed--;
 
 	mutex_unlock(&i7core_edac_lock);
@@ -2070,7 +2137,8 @@
 	/* Ensure that the OPSTATE is set correctly for POLL or NMI */
 	opstate_init();
 
-	i7core_xeon_pci_fixup(pci_dev_table);
+	if (use_pci_fixup)
+		i7core_xeon_pci_fixup(pci_dev_table);
 
 	pci_rc = pci_register_driver(&i7core_driver);
 
diff -druN linux-libre-2.6.36-gnu/drivers/edac/i82443bxgx_edac.c linux-libre-2.6.37-gnu/drivers/edac/i82443bxgx_edac.c
--- linux-libre-2.6.36-gnu/drivers/edac/i82443bxgx_edac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/i82443bxgx_edac.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
  * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
  *
  * Written with reference to 82443BX Host Bridge Datasheet:
- * http://www.intel.com/design/chipsets/440/documentation.htm
+ * http://download.intel.com/design/chipsets/datashts/29063301.pdf 
  * references to this document given in [].
  *
  * This module doesn't support the 440LX, but it may be possible to
diff -druN linux-libre-2.6.36-gnu/drivers/edac/Kconfig linux-libre-2.6.37-gnu/drivers/edac/Kconfig
--- linux-libre-2.6.36-gnu/drivers/edac/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 	  there're four debug levels (x=0,1,2,3 from low to high).
 	  Usually you should select 'N'.
 
- config EDAC_DECODE_MCE
+config EDAC_DECODE_MCE
 	tristate "Decode MCEs in human-readable form (only on AMD for now)"
 	depends on CPU_SUP_AMD && X86_MCE
 	default y
@@ -51,6 +51,16 @@
 	  which occur really early upon boot, before the module infrastructure
 	  has been initialized.
 
+config EDAC_MCE_INJ
+	tristate "Simple MCE injection interface over /sysfs"
+	depends on EDAC_DECODE_MCE
+	default n
+	help
+	  This is a simple interface to inject MCEs over /sysfs and test
+	  the MCE decoding code in EDAC.
+
+	  This is currently AMD-only.
+
 config EDAC_MM_EDAC
 	tristate "Main Memory EDAC (Error Detection And Correction) reporting"
 	help
@@ -66,13 +76,13 @@
 
 config EDAC_AMD64
 	tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
-	depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
+	depends on EDAC_MM_EDAC && AMD_NB && X86_64 && PCI && EDAC_DECODE_MCE
 	help
 	  Support for error detection and correction on the AMD 64
 	  Families of Memory Controllers (K8, F10h and F11h)
 
 config EDAC_AMD64_ERROR_INJECTION
-	bool "Sysfs Error Injection facilities"
+	bool "Sysfs HW Error injection facilities"
 	depends on EDAC_AMD64
 	help
 	  Recent Opterons (Family 10h and later) provide for Memory Error
@@ -199,6 +209,13 @@
 	  Support for error detection and correction the Intel
 	  San Clemente MCH.
 
+config EDAC_I7300
+	tristate "Intel Clarksboro MCH"
+	depends on EDAC_MM_EDAC && X86 && PCI
+	help
+	  Support for error detection and correction the Intel
+	  Clarksboro MCH (Intel 7300 chipset).
+
 config EDAC_MPC85XX
 	tristate "Freescale MPC83xx / MPC85xx"
 	depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
diff -druN linux-libre-2.6.36-gnu/drivers/edac/Makefile linux-libre-2.6.37-gnu/drivers/edac/Makefile
--- linux-libre-2.6.36-gnu/drivers/edac/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/edac/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -10,13 +10,16 @@
 obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.o
 obj-$(CONFIG_EDAC_MCE)			+= edac_mce.o
 
-edac_core-objs	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
-edac_core-objs	+= edac_module.o edac_device_sysfs.o
+edac_core-y	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-y	+= edac_module.o edac_device_sysfs.o
 
 ifdef CONFIG_PCI
-edac_core-objs	+= edac_pci.o edac_pci_sysfs.o
+edac_core-y	+= edac_pci.o edac_pci_sysfs.o
 endif
 
+obj-$(CONFIG_EDAC_MCE_INJ)		+= mce_amd_inj.o
+
+edac_mce_amd-y				:= mce_amd.o
 obj-$(CONFIG_EDAC_DECODE_MCE)		+= edac_mce_amd.o
 
 obj-$(CONFIG_EDAC_AMD76X)		+= amd76x_edac.o
@@ -24,6 +27,7 @@
 obj-$(CONFIG_EDAC_I5000)		+= i5000_edac.o
 obj-$(CONFIG_EDAC_I5100)		+= i5100_edac.o
 obj-$(CONFIG_EDAC_I5400)		+= i5400_edac.o
+obj-$(CONFIG_EDAC_I7300)		+= i7300_edac.o
 obj-$(CONFIG_EDAC_I7CORE)		+= i7core_edac.o
 obj-$(CONFIG_EDAC_E7XXX)		+= e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
diff -druN linux-libre-2.6.36-gnu/drivers/edac/mce_amd.c linux-libre-2.6.37-gnu/drivers/edac/mce_amd.c
--- linux-libre-2.6.36-gnu/drivers/edac/mce_amd.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/edac/mce_amd.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,680 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "mce_amd.h"
+
+static struct amd_decoder_ops *fam_ops;
+
+static u8 nb_err_cpumask = 0xf;
+
+static bool report_gart_errors;
+static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg);
+
+void amd_report_gart_errors(bool v)
+{
+	report_gart_errors = v;
+}
+EXPORT_SYMBOL_GPL(amd_report_gart_errors);
+
+void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32))
+{
+	nb_bus_decoder = f;
+}
+EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
+
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32))
+{
+	if (nb_bus_decoder) {
+		WARN_ON(nb_bus_decoder != f);
+
+		nb_bus_decoder = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
+
+/*
+ * string representation for the different MCA reported error types, see F3x48
+ * or MSR0000_0411.
+ */
+
+/* transaction type */
+const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
+EXPORT_SYMBOL_GPL(tt_msgs);
+
+/* cache level */
+const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
+EXPORT_SYMBOL_GPL(ll_msgs);
+
+/* memory transaction type */
+const char *rrrr_msgs[] = {
+       "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
+};
+EXPORT_SYMBOL_GPL(rrrr_msgs);
+
+/* participating processor */
+const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
+EXPORT_SYMBOL_GPL(pp_msgs);
+
+/* request timeout */
+const char *to_msgs[] = { "no timeout",	"timed out" };
+EXPORT_SYMBOL_GPL(to_msgs);
+
+/* memory or i/o */
+const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+EXPORT_SYMBOL_GPL(ii_msgs);
+
+static const char *f10h_nb_mce_desc[] = {
+	"HT link data error",
+	"Protocol error (link, L3, probe filter, etc.)",
+	"Parity error in NB-internal arrays",
+	"Link Retry due to IO link transmission error",
+	"L3 ECC data cache error",
+	"ECC error in L3 cache tag",
+	"L3 LRU parity bits error",
+	"ECC Error in the Probe Filter directory"
+};
+
+static bool f12h_dc_mce(u16 ec)
+{
+	bool ret = false;
+
+	if (MEM_ERROR(ec)) {
+		u8 ll = ec & 0x3;
+		ret = true;
+
+		if (ll == LL_L2)
+			pr_cont("during L1 linefill from L2.\n");
+		else if (ll == LL_L1)
+			pr_cont("Data/Tag %s error.\n", RRRR_MSG(ec));
+		else
+			ret = false;
+	}
+	return ret;
+}
+
+static bool f10h_dc_mce(u16 ec)
+{
+	u8 r4  = (ec >> 4) & 0xf;
+	u8 ll  = ec & 0x3;
+
+	if (r4 == R4_GEN && ll == LL_L1) {
+		pr_cont("during data scrub.\n");
+		return true;
+	}
+	return f12h_dc_mce(ec);
+}
+
+static bool k8_dc_mce(u16 ec)
+{
+	if (BUS_ERROR(ec)) {
+		pr_cont("during system linefill.\n");
+		return true;
+	}
+
+	return f10h_dc_mce(ec);
+}
+
+static bool f14h_dc_mce(u16 ec)
+{
+	u8 r4	 = (ec >> 4) & 0xf;
+	u8 ll	 = ec & 0x3;
+	u8 tt	 = (ec >> 2) & 0x3;
+	u8 ii	 = tt;
+	bool ret = true;
+
+	if (MEM_ERROR(ec)) {
+
+		if (tt != TT_DATA || ll != LL_L1)
+			return false;
+
+		switch (r4) {
+		case R4_DRD:
+		case R4_DWR:
+			pr_cont("Data/Tag parity error due to %s.\n",
+				(r4 == R4_DRD ? "load/hw prf" : "store"));
+			break;
+		case R4_EVICT:
+			pr_cont("Copyback parity error on a tag miss.\n");
+			break;
+		case R4_SNOOP:
+			pr_cont("Tag parity error during snoop.\n");
+			break;
+		default:
+			ret = false;
+		}
+	} else if (BUS_ERROR(ec)) {
+
+		if ((ii != II_MEM && ii != II_IO) || ll != LL_LG)
+			return false;
+
+		pr_cont("System read data error on a ");
+
+		switch (r4) {
+		case R4_RD:
+			pr_cont("TLB reload.\n");
+			break;
+		case R4_DWR:
+			pr_cont("store.\n");
+			break;
+		case R4_DRD:
+			pr_cont("load.\n");
+			break;
+		default:
+			ret = false;
+		}
+	} else {
+		ret = false;
+	}
+
+	return ret;
+}
+
+static void amd_decode_dc_mce(struct mce *m)
+{
+	u16 ec = m->status & 0xffff;
+	u8 xec = (m->status >> 16) & 0xf;
+
+	pr_emerg(HW_ERR "Data Cache Error: ");
+
+	/* TLB error signatures are the same across families */
+	if (TLB_ERROR(ec)) {
+		u8 tt = (ec >> 2) & 0x3;
+
+		if (tt == TT_DATA) {
+			pr_cont("%s TLB %s.\n", LL_MSG(ec),
+				(xec ? "multimatch" : "parity error"));
+			return;
+		}
+		else
+			goto wrong_dc_mce;
+	}
+
+	if (!fam_ops->dc_mce(ec))
+		goto wrong_dc_mce;
+
+	return;
+
+wrong_dc_mce:
+	pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
+}
+
+static bool k8_ic_mce(u16 ec)
+{
+	u8 ll	 = ec & 0x3;
+	u8 r4	 = (ec >> 4) & 0xf;
+	bool ret = true;
+
+	if (!MEM_ERROR(ec))
+		return false;
+
+	if (ll == 0x2)
+		pr_cont("during a linefill from L2.\n");
+	else if (ll == 0x1) {
+		switch (r4) {
+		case R4_IRD:
+			pr_cont("Parity error during data load.\n");
+			break;
+
+		case R4_EVICT:
+			pr_cont("Copyback Parity/Victim error.\n");
+			break;
+
+		case R4_SNOOP:
+			pr_cont("Tag Snoop error.\n");
+			break;
+
+		default:
+			ret = false;
+			break;
+		}
+	} else
+		ret = false;
+
+	return ret;
+}
+
+static bool f14h_ic_mce(u16 ec)
+{
+	u8 ll    = ec & 0x3;
+	u8 tt    = (ec >> 2) & 0x3;
+	u8 r4  = (ec >> 4) & 0xf;
+	bool ret = true;
+
+	if (MEM_ERROR(ec)) {
+		if (tt != 0 || ll != 1)
+			ret = false;
+
+		if (r4 == R4_IRD)
+			pr_cont("Data/tag array parity error for a tag hit.\n");
+		else if (r4 == R4_SNOOP)
+			pr_cont("Tag error during snoop/victimization.\n");
+		else
+			ret = false;
+	}
+	return ret;
+}
+
+static void amd_decode_ic_mce(struct mce *m)
+{
+	u16 ec = m->status & 0xffff;
+	u8 xec = (m->status >> 16) & 0xf;
+
+	pr_emerg(HW_ERR "Instruction Cache Error: ");
+
+	if (TLB_ERROR(ec))
+		pr_cont("%s TLB %s.\n", LL_MSG(ec),
+			(xec ? "multimatch" : "parity error"));
+	else if (BUS_ERROR(ec)) {
+		bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
+
+		pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
+	} else if (fam_ops->ic_mce(ec))
+		;
+	else
+		pr_emerg(HW_ERR "Corrupted IC MCE info?\n");
+}
+
+static void amd_decode_bu_mce(struct mce *m)
+{
+	u32 ec = m->status & 0xffff;
+	u32 xec = (m->status >> 16) & 0xf;
+
+	pr_emerg(HW_ERR "Bus Unit Error");
+
+	if (xec == 0x1)
+		pr_cont(" in the write data buffers.\n");
+	else if (xec == 0x3)
+		pr_cont(" in the victim data buffers.\n");
+	else if (xec == 0x2 && MEM_ERROR(ec))
+		pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
+	else if (xec == 0x0) {
+		if (TLB_ERROR(ec))
+			pr_cont(": %s error in a Page Descriptor Cache or "
+				"Guest TLB.\n", TT_MSG(ec));
+		else if (BUS_ERROR(ec))
+			pr_cont(": %s/ECC error in data read from NB: %s.\n",
+				RRRR_MSG(ec), PP_MSG(ec));
+		else if (MEM_ERROR(ec)) {
+			u8 rrrr = (ec >> 4) & 0xf;
+
+			if (rrrr >= 0x7)
+				pr_cont(": %s error during data copyback.\n",
+					RRRR_MSG(ec));
+			else if (rrrr <= 0x1)
+				pr_cont(": %s parity/ECC error during data "
+					"access from L2.\n", RRRR_MSG(ec));
+			else
+				goto wrong_bu_mce;
+		} else
+			goto wrong_bu_mce;
+	} else
+		goto wrong_bu_mce;
+
+	return;
+
+wrong_bu_mce:
+	pr_emerg(HW_ERR "Corrupted BU MCE info?\n");
+}
+
+static void amd_decode_ls_mce(struct mce *m)
+{
+	u16 ec = m->status & 0xffff;
+	u8 xec = (m->status >> 16) & 0xf;
+
+	if (boot_cpu_data.x86 == 0x14) {
+		pr_emerg("You shouldn't be seeing an LS MCE on this cpu family,"
+			 " please report on LKML.\n");
+		return;
+	}
+
+	pr_emerg(HW_ERR "Load Store Error");
+
+	if (xec == 0x0) {
+		u8 r4 = (ec >> 4) & 0xf;
+
+		if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
+			goto wrong_ls_mce;
+
+		pr_cont(" during %s.\n", RRRR_MSG(ec));
+	} else
+		goto wrong_ls_mce;
+
+	return;
+
+wrong_ls_mce:
+	pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
+}
+
+static bool k8_nb_mce(u16 ec, u8 xec)
+{
+	bool ret = true;
+
+	switch (xec) {
+	case 0x1:
+		pr_cont("CRC error detected on HT link.\n");
+		break;
+
+	case 0x5:
+		pr_cont("Invalid GART PTE entry during GART table walk.\n");
+		break;
+
+	case 0x6:
+		pr_cont("Unsupported atomic RMW received from an IO link.\n");
+		break;
+
+	case 0x0:
+	case 0x8:
+		if (boot_cpu_data.x86 == 0x11)
+			return false;
+
+		pr_cont("DRAM ECC error detected on the NB.\n");
+		break;
+
+	case 0xd:
+		pr_cont("Parity error on the DRAM addr/ctl signals.\n");
+		break;
+
+	default:
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+static bool f10h_nb_mce(u16 ec, u8 xec)
+{
+	bool ret = true;
+	u8 offset = 0;
+
+	if (k8_nb_mce(ec, xec))
+		return true;
+
+	switch(xec) {
+	case 0xa ... 0xc:
+		offset = 10;
+		break;
+
+	case 0xe:
+		offset = 11;
+		break;
+
+	case 0xf:
+		if (TLB_ERROR(ec))
+			pr_cont("GART Table Walk data error.\n");
+		else if (BUS_ERROR(ec))
+			pr_cont("DMA Exclusion Vector Table Walk error.\n");
+		else
+			ret = false;
+
+		goto out;
+		break;
+
+	case 0x1c ... 0x1f:
+		offset = 24;
+		break;
+
+	default:
+		ret = false;
+
+		goto out;
+		break;
+	}
+
+	pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]);
+
+out:
+	return ret;
+}
+
+static bool nb_noop_mce(u16 ec, u8 xec)
+{
+	return false;
+}
+
+void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
+{
+	u8 xec   = (m->status >> 16) & 0x1f;
+	u16 ec   = m->status & 0xffff;
+	u32 nbsh = (u32)(m->status >> 32);
+
+	pr_emerg(HW_ERR "Northbridge Error, node %d: ", node_id);
+
+	/*
+	 * F10h, revD can disable ErrCpu[3:0] so check that first and also the
+	 * value encoding has changed so interpret those differently
+	 */
+	if ((boot_cpu_data.x86 == 0x10) &&
+	    (boot_cpu_data.x86_model > 7)) {
+		if (nbsh & K8_NBSH_ERR_CPU_VAL)
+			pr_cont(", core: %u", (u8)(nbsh & nb_err_cpumask));
+	} else {
+		u8 assoc_cpus = nbsh & nb_err_cpumask;
+
+		if (assoc_cpus > 0)
+			pr_cont(", core: %d", fls(assoc_cpus) - 1);
+	}
+
+	switch (xec) {
+	case 0x2:
+		pr_cont("Sync error (sync packets on HT link detected).\n");
+		return;
+
+	case 0x3:
+		pr_cont("HT Master abort.\n");
+		return;
+
+	case 0x4:
+		pr_cont("HT Target abort.\n");
+		return;
+
+	case 0x7:
+		pr_cont("NB Watchdog timeout.\n");
+		return;
+
+	case 0x9:
+		pr_cont("SVM DMA Exclusion Vector error.\n");
+		return;
+
+	default:
+		break;
+	}
+
+	if (!fam_ops->nb_mce(ec, xec))
+		goto wrong_nb_mce;
+
+	if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10)
+		if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
+			nb_bus_decoder(node_id, m, nbcfg);
+
+	return;
+
+wrong_nb_mce:
+	pr_emerg(HW_ERR "Corrupted NB MCE info?\n");
+}
+EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
+
+static void amd_decode_fr_mce(struct mce *m)
+{
+	if (boot_cpu_data.x86 == 0xf ||
+	    boot_cpu_data.x86 == 0x11)
+		goto wrong_fr_mce;
+
+	/* we have only one error signature so match all fields at once. */
+	if ((m->status & 0xffff) == 0x0f0f) {
+		pr_emerg(HW_ERR "FR Error: CPU Watchdog timer expire.\n");
+		return;
+	}
+
+wrong_fr_mce:
+	pr_emerg(HW_ERR "Corrupted FR MCE info?\n");
+}
+
+static inline void amd_decode_err_code(u16 ec)
+{
+	if (TLB_ERROR(ec)) {
+		pr_emerg(HW_ERR "Transaction: %s, Cache Level: %s\n",
+			 TT_MSG(ec), LL_MSG(ec));
+	} else if (MEM_ERROR(ec)) {
+		pr_emerg(HW_ERR "Transaction: %s, Type: %s, Cache Level: %s\n",
+			 RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
+	} else if (BUS_ERROR(ec)) {
+		pr_emerg(HW_ERR "Transaction: %s (%s), %s, Cache Level: %s, "
+			 "Participating Processor: %s\n",
+			  RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
+			  PP_MSG(ec));
+	} else
+		pr_emerg(HW_ERR "Huh? Unknown MCE error 0x%x\n", ec);
+}
+
+/*
+ * Filter out unwanted MCE signatures here.
+ */
+static bool amd_filter_mce(struct mce *m)
+{
+	u8 xec = (m->status >> 16) & 0x1f;
+
+	/*
+	 * NB GART TLB error reporting is disabled by default.
+	 */
+	if (m->bank == 4 && xec == 0x5 && !report_gart_errors)
+		return true;
+
+	return false;
+}
+
+int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
+{
+	struct mce *m = (struct mce *)data;
+	int node, ecc;
+
+	if (amd_filter_mce(m))
+		return NOTIFY_STOP;
+
+	pr_emerg(HW_ERR "MC%d_STATUS: ", m->bank);
+
+	pr_cont("%sorrected error, other errors lost: %s, "
+		 "CPU context corrupt: %s",
+		 ((m->status & MCI_STATUS_UC) ? "Unc"  : "C"),
+		 ((m->status & MCI_STATUS_OVER) ? "yes"  : "no"),
+		 ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
+
+	/* do the two bits[14:13] together */
+	ecc = (m->status >> 45) & 0x3;
+	if (ecc)
+		pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
+
+	pr_cont("\n");
+
+	switch (m->bank) {
+	case 0:
+		amd_decode_dc_mce(m);
+		break;
+
+	case 1:
+		amd_decode_ic_mce(m);
+		break;
+
+	case 2:
+		amd_decode_bu_mce(m);
+		break;
+
+	case 3:
+		amd_decode_ls_mce(m);
+		break;
+
+	case 4:
+		node = amd_get_nb_id(m->extcpu);
+		amd_decode_nb_mce(node, m, 0);
+		break;
+
+	case 5:
+		amd_decode_fr_mce(m);
+		break;
+
+	default:
+		break;
+	}
+
+	amd_decode_err_code(m->status & 0xffff);
+
+	return NOTIFY_STOP;
+}
+EXPORT_SYMBOL_GPL(amd_decode_mce);
+
+static struct notifier_block amd_mce_dec_nb = {
+	.notifier_call	= amd_decode_mce,
+};
+
+static int __init mce_amd_init(void)
+{
+	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+		return 0;
+
+	if ((boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x12) &&
+	    (boot_cpu_data.x86 != 0x14 || boot_cpu_data.x86_model > 0xf))
+		return 0;
+
+	fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
+	if (!fam_ops)
+		return -ENOMEM;
+
+	switch (boot_cpu_data.x86) {
+	case 0xf:
+		fam_ops->dc_mce = k8_dc_mce;
+		fam_ops->ic_mce = k8_ic_mce;
+		fam_ops->nb_mce = k8_nb_mce;
+		break;
+
+	case 0x10:
+		fam_ops->dc_mce = f10h_dc_mce;
+		fam_ops->ic_mce = k8_ic_mce;
+		fam_ops->nb_mce = f10h_nb_mce;
+		break;
+
+	case 0x11:
+		fam_ops->dc_mce = k8_dc_mce;
+		fam_ops->ic_mce = k8_ic_mce;
+		fam_ops->nb_mce = f10h_nb_mce;
+		break;
+
+	case 0x12:
+		fam_ops->dc_mce = f12h_dc_mce;
+		fam_ops->ic_mce = k8_ic_mce;
+		fam_ops->nb_mce = nb_noop_mce;
+		break;
+
+	case 0x14:
+		nb_err_cpumask  = 0x3;
+		fam_ops->dc_mce = f14h_dc_mce;
+		fam_ops->ic_mce = f14h_ic_mce;
+		fam_ops->nb_mce = nb_noop_mce;
+		break;
+
+	default:
+		printk(KERN_WARNING "Huh? What family is that: %d?!\n",
+				    boot_cpu_data.x86);
+		kfree(fam_ops);
+		return -EINVAL;
+	}
+
+	pr_info("MCE: In-kernel MCE decoding enabled.\n");
+
+	atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
+
+	return 0;
+}
+early_initcall(mce_amd_init);
+
+#ifdef MODULE
+static void __exit mce_amd_exit(void)
+{
+	atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
+	kfree(fam_ops);
+}
+
+MODULE_DESCRIPTION("AMD MCE decoder");
+MODULE_ALIAS("edac-mce-amd");
+MODULE_LICENSE("GPL");
+module_exit(mce_amd_exit);
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/edac/mce_amd.h linux-libre-2.6.37-gnu/drivers/edac/mce_amd.h
--- linux-libre-2.6.36-gnu/drivers/edac/mce_amd.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/edac/mce_amd.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,114 @@
+#ifndef _EDAC_MCE_AMD_H
+#define _EDAC_MCE_AMD_H
+
+#include <linux/notifier.h>
+
+#include <asm/mce.h>
+
+#define BIT_64(n)			(U64_C(1) << (n))
+
+#define ERROR_CODE(x)			((x) & 0xffff)
+#define EXT_ERROR_CODE(x)		(((x) >> 16) & 0x1f)
+
+#define LOW_SYNDROME(x)			(((x) >> 15) & 0xff)
+#define HIGH_SYNDROME(x)		(((x) >> 24) & 0xff)
+
+#define TLB_ERROR(x)			(((x) & 0xFFF0) == 0x0010)
+#define MEM_ERROR(x)			(((x) & 0xFF00) == 0x0100)
+#define BUS_ERROR(x)			(((x) & 0xF800) == 0x0800)
+
+#define TT(x)				(((x) >> 2) & 0x3)
+#define TT_MSG(x)			tt_msgs[TT(x)]
+#define II(x)				(((x) >> 2) & 0x3)
+#define II_MSG(x)			ii_msgs[II(x)]
+#define LL(x)				(((x) >> 0) & 0x3)
+#define LL_MSG(x)			ll_msgs[LL(x)]
+#define TO(x)				(((x) >> 8) & 0x1)
+#define TO_MSG(x)			to_msgs[TO(x)]
+#define PP(x)				(((x) >> 9) & 0x3)
+#define PP_MSG(x)			pp_msgs[PP(x)]
+
+#define RRRR(x)				(((x) >> 4) & 0xf)
+#define RRRR_MSG(x)			((RRRR(x) < 9) ?  rrrr_msgs[RRRR(x)] : "Wrong R4!")
+
+#define K8_NBSH				0x4C
+
+#define K8_NBSH_VALID_BIT		BIT(31)
+#define K8_NBSH_OVERFLOW		BIT(30)
+#define K8_NBSH_UC_ERR			BIT(29)
+#define K8_NBSH_ERR_EN			BIT(28)
+#define K8_NBSH_MISCV			BIT(27)
+#define K8_NBSH_VALID_ERROR_ADDR	BIT(26)
+#define K8_NBSH_PCC			BIT(25)
+#define K8_NBSH_ERR_CPU_VAL		BIT(24)
+#define K8_NBSH_CECC			BIT(14)
+#define K8_NBSH_UECC			BIT(13)
+#define K8_NBSH_ERR_SCRUBER		BIT(8)
+
+enum tt_ids {
+	TT_INSTR = 0,
+	TT_DATA,
+	TT_GEN,
+	TT_RESV,
+};
+
+enum ll_ids {
+	LL_RESV = 0,
+	LL_L1,
+	LL_L2,
+	LL_LG,
+};
+
+enum ii_ids {
+	II_MEM = 0,
+	II_RESV,
+	II_IO,
+	II_GEN,
+};
+
+enum rrrr_ids {
+	R4_GEN	= 0,
+	R4_RD,
+	R4_WR,
+	R4_DRD,
+	R4_DWR,
+	R4_IRD,
+	R4_PREF,
+	R4_EVICT,
+	R4_SNOOP,
+};
+
+extern const char *tt_msgs[];
+extern const char *ll_msgs[];
+extern const char *rrrr_msgs[];
+extern const char *pp_msgs[];
+extern const char *to_msgs[];
+extern const char *ii_msgs[];
+
+/*
+ * relevant NB regs
+ */
+struct err_regs {
+	u32 nbcfg;
+	u32 nbsh;
+	u32 nbsl;
+	u32 nbeah;
+	u32 nbeal;
+};
+
+/*
+ * per-family decoder ops
+ */
+struct amd_decoder_ops {
+	bool (*dc_mce)(u16);
+	bool (*ic_mce)(u16);
+	bool (*nb_mce)(u16, u8);
+};
+
+void amd_report_gart_errors(bool);
+void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32));
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32));
+void amd_decode_nb_mce(int, struct mce *, u32);
+int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data);
+
+#endif /* _EDAC_MCE_AMD_H */
diff -druN linux-libre-2.6.36-gnu/drivers/edac/mce_amd_inj.c linux-libre-2.6.37-gnu/drivers/edac/mce_amd_inj.c
--- linux-libre-2.6.36-gnu/drivers/edac/mce_amd_inj.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/edac/mce_amd_inj.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,171 @@
+/*
+ * A simple MCE injection facility for testing the MCE decoding code. This
+ * driver should be built as module so that it can be loaded on production
+ * kernels for testing purposes.
+ *
+ * This file may be distributed under the terms of the GNU General Public
+ * License version 2.
+ *
+ * Copyright (c) 2010:  Borislav Petkov <borislav.petkov@amd.com>
+ *			Advanced Micro Devices Inc.
+ */
+
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/edac.h>
+#include <asm/mce.h>
+
+#include "mce_amd.h"
+
+struct edac_mce_attr {
+	struct attribute attr;
+	ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf);
+	ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr,
+			 const char *buf, size_t count);
+};
+
+#define EDAC_MCE_ATTR(_name, _mode, _show, _store)			\
+static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store)
+
+static struct kobject *mce_kobj;
+
+/*
+ * Collect all the MCi_XXX settings
+ */
+static struct mce i_mce;
+
+#define MCE_INJECT_STORE(reg)						\
+static ssize_t edac_inject_##reg##_store(struct kobject *kobj,		\
+					 struct edac_mce_attr *attr,	\
+					 const char *data, size_t count)\
+{									\
+	int ret = 0;							\
+	unsigned long value;						\
+									\
+	ret = strict_strtoul(data, 16, &value);				\
+	if (ret < 0)							\
+		printk(KERN_ERR "Error writing MCE " #reg " field.\n");	\
+									\
+	i_mce.reg = value;						\
+									\
+	return count;							\
+}
+
+MCE_INJECT_STORE(status);
+MCE_INJECT_STORE(misc);
+MCE_INJECT_STORE(addr);
+
+#define MCE_INJECT_SHOW(reg)						\
+static ssize_t edac_inject_##reg##_show(struct kobject *kobj,		\
+					struct edac_mce_attr *attr,	\
+					char *buf)			\
+{									\
+	return sprintf(buf, "0x%016llx\n", i_mce.reg);			\
+}
+
+MCE_INJECT_SHOW(status);
+MCE_INJECT_SHOW(misc);
+MCE_INJECT_SHOW(addr);
+
+EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store);
+EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store);
+EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store);
+
+/*
+ * This denotes into which bank we're injecting and triggers
+ * the injection, at the same time.
+ */
+static ssize_t edac_inject_bank_store(struct kobject *kobj,
+				      struct edac_mce_attr *attr,
+				      const char *data, size_t count)
+{
+	int ret = 0;
+	unsigned long value;
+
+	ret = strict_strtoul(data, 10, &value);
+	if (ret < 0) {
+		printk(KERN_ERR "Invalid bank value!\n");
+		return -EINVAL;
+	}
+
+	if (value > 5) {
+		printk(KERN_ERR "Non-existant MCE bank: %lu\n", value);
+		return -EINVAL;
+	}
+
+	i_mce.bank = value;
+
+	amd_decode_mce(NULL, 0, &i_mce);
+
+	return count;
+}
+
+static ssize_t edac_inject_bank_show(struct kobject *kobj,
+				     struct edac_mce_attr *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", i_mce.bank);
+}
+
+EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store);
+
+static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc,
+					       &mce_attr_addr, &mce_attr_bank
+};
+
+static int __init edac_init_mce_inject(void)
+{
+	struct sysdev_class *edac_class = NULL;
+	int i, err = 0;
+
+	edac_class = edac_get_sysfs_class();
+	if (!edac_class)
+		return -EINVAL;
+
+	mce_kobj = kobject_create_and_add("mce", &edac_class->kset.kobj);
+	if (!mce_kobj) {
+		printk(KERN_ERR "Error creating a mce kset.\n");
+		err = -ENOMEM;
+		goto err_mce_kobj;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) {
+		err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr);
+		if (err) {
+			printk(KERN_ERR "Error creating %s in sysfs.\n",
+					sysfs_attrs[i]->attr.name);
+			goto err_sysfs_create;
+		}
+	}
+	return 0;
+
+err_sysfs_create:
+	while (--i >= 0)
+		sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+
+	kobject_del(mce_kobj);
+
+err_mce_kobj:
+	edac_put_sysfs_class();
+
+	return err;
+}
+
+static void __exit edac_exit_mce_inject(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++)
+		sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+
+	kobject_del(mce_kobj);
+
+	edac_put_sysfs_class();
+}
+
+module_init(edac_init_mce_inject);
+module_exit(edac_exit_mce_inject);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>");
+MODULE_AUTHOR("AMD Inc.");
+MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding");
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/init_ohci1394_dma.c linux-libre-2.6.37-gnu/drivers/firewire/init_ohci1394_dma.c
--- linux-libre-2.6.36-gnu/drivers/firewire/init_ohci1394_dma.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/firewire/init_ohci1394_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,309 @@
+/*
+ * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers
+ *
+ * Copyright (C) 2006-2007      Bernhard Kaindl <bk@suse.de>
+ *
+ * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c
+ * this file has functions to:
+ * - scan the PCI very early on boot for all OHCI 1394-compliant controllers
+ * - reset and initialize them and make them join the IEEE1394 bus and
+ * - enable physical DMA on them to allow remote debugging
+ *
+ * All code and data is marked as __init and __initdata, respective as
+ * during boot, all OHCI1394 controllers may be claimed by the firewire
+ * stack and at this point, this code should not touch them anymore.
+ *
+ * To use physical DMA after the initialization of the firewire stack,
+ * be sure that the stack enables it and (re-)attach after the bus reset
+ * which may be caused by the firewire stack initialization.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>		/* for PCI defines */
+#include <linux/string.h>
+
+#include <asm/pci-direct.h>	/* for direct PCI config space access */
+#include <asm/fixmap.h>
+
+#include <linux/init_ohci1394_dma.h>
+#include "ohci.h"
+
+int __initdata init_ohci1394_dma_early;
+
+struct ohci {
+	void __iomem *registers;
+};
+
+static inline void reg_write(const struct ohci *ohci, int offset, u32 data)
+{
+	writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct ohci *ohci, int offset)
+{
+	return readl(ohci->registers + offset);
+}
+
+#define OHCI_LOOP_COUNT		100	/* Number of loops for reg read waits */
+
+/* Reads a PHY register of an OHCI-1394 controller */
+static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr)
+{
+	int i;
+	u32 r;
+
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
+			break;
+		mdelay(1);
+	}
+	r = reg_read(ohci, OHCI1394_PhyControl);
+
+	return (r & 0x00ff0000) >> 16;
+}
+
+/* Writes to a PHY register of an OHCI-1394 controller */
+static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data)
+{
+	int i;
+
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000))
+			break;
+		mdelay(1);
+	}
+}
+
+/* Resets an OHCI-1394 controller (for sane state before initialization) */
+static inline void __init init_ohci1394_soft_reset(struct ohci *ohci)
+{
+	int i;
+
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (!(reg_read(ohci, OHCI1394_HCControlSet)
+				   & OHCI1394_HCControl_softReset))
+			break;
+		mdelay(1);
+	}
+}
+
+#define OHCI1394_MAX_AT_REQ_RETRIES	0xf
+#define OHCI1394_MAX_AT_RESP_RETRIES	0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES	0x8
+
+/* Basic OHCI-1394 register and port inititalization */
+static inline void __init init_ohci1394_initialize(struct ohci *ohci)
+{
+	u32 bus_options;
+	int num_ports, i;
+
+	/* Put some defaults to these undefined bus options */
+	bus_options = reg_read(ohci, OHCI1394_BusOptions);
+	bus_options |=  0x60000000; /* Enable CMC and ISC */
+	bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
+	bus_options &= ~0x18000000; /* Disable PMC and BMC */
+	reg_write(ohci, OHCI1394_BusOptions, bus_options);
+
+	/* Set the bus number */
+	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
+
+	/* Enable posted writes */
+	reg_write(ohci, OHCI1394_HCControlSet,
+			OHCI1394_HCControl_postedWriteEnable);
+
+	/* Clear link control register */
+	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
+
+	/* enable phys */
+	reg_write(ohci, OHCI1394_LinkControlSet,
+			OHCI1394_LinkControl_rcvPhyPkt);
+
+	/* Don't accept phy packets into AR request context */
+	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
+
+	/* Clear the Isochonouys interrupt masks */
+	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
+
+	/* Accept asyncronous transfer requests from all nodes for now */
+	reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+	/* Specify asyncronous transfer retries */
+	reg_write(ohci, OHCI1394_ATRetries,
+		  OHCI1394_MAX_AT_REQ_RETRIES |
+		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
+
+	/* We don't want hardware swapping */
+	reg_write(ohci, OHCI1394_HCControlClear,
+		  OHCI1394_HCControl_noByteSwapData);
+
+	/* Enable link */
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
+
+	/* If anything is connected to a port, make sure it is enabled */
+	num_ports = get_phy_reg(ohci, 2) & 0xf;
+	for (i = 0; i < num_ports; i++) {
+		unsigned int status;
+
+		set_phy_reg(ohci, 7, i);
+		status = get_phy_reg(ohci, 8);
+
+		if (status & 0x20)
+			set_phy_reg(ohci, 8, status & ~1);
+	}
+}
+
+/**
+ * init_ohci1394_wait_for_busresets - wait until bus resets are completed
+ *
+ * OHCI1394 initialization itself and any device going on- or offline
+ * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec
+ * specifies that physical DMA is disabled on each bus reset and it
+ * has to be enabled after each bus reset when needed. We resort
+ * to polling here because on early boot, we have no interrupts.
+ */
+static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci)
+{
+	int i, events;
+
+	for (i = 0; i < 9; i++) {
+		mdelay(200);
+		events = reg_read(ohci, OHCI1394_IntEventSet);
+		if (events & OHCI1394_busReset)
+			reg_write(ohci, OHCI1394_IntEventClear,
+					OHCI1394_busReset);
+	}
+}
+
+/**
+ * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging
+ * This enables remote DMA access over IEEE1394 from every host for the low
+ * 4GB of address space. DMA accesses above 4GB are not available currently.
+ */
+static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci)
+{
+	reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+	reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+	reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
+}
+
+/**
+ * init_ohci1394_reset_and_init_dma - init controller and enable DMA
+ * This initializes the given controller and enables physical DMA engine in it.
+ */
+static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci)
+{
+	/* Start off with a soft reset, clears everything to a sane state. */
+	init_ohci1394_soft_reset(ohci);
+
+	/* Accessing some registers without LPS enabled may cause lock up */
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
+
+	/* Disable and clear interrupts */
+	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+
+	mdelay(50); /* Wait 50msec to make sure we have full link enabled */
+
+	init_ohci1394_initialize(ohci);
+	/*
+	 * The initialization causes at least one IEEE1394 bus reset. Enabling
+	 * physical DMA only works *after* *all* bus resets have calmed down:
+	 */
+	init_ohci1394_wait_for_busresets(ohci);
+
+	/* We had to wait and do this now if we want to debug early problems */
+	init_ohci1394_enable_physical_dma(ohci);
+}
+
+/**
+ * init_ohci1394_controller - Map the registers of the controller and init DMA
+ * This maps the registers of the specified controller and initializes it
+ */
+static inline void __init init_ohci1394_controller(int num, int slot, int func)
+{
+	unsigned long ohci_base;
+	struct ohci ohci;
+
+	printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
+			 " at %02x:%02x.%x\n", num, slot, func);
+
+	ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2))
+						   & PCI_BASE_ADDRESS_MEM_MASK;
+
+	set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
+
+	ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE);
+
+	init_ohci1394_reset_and_init_dma(&ohci);
+}
+
+/**
+ * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them
+ * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them
+ */
+void __init init_ohci1394_dma_on_all_controllers(void)
+{
+	int num, slot, func;
+	u32 class;
+
+	if (!early_pci_allowed())
+		return;
+
+	/* Poor man's PCI discovery, the only thing we can do at early boot */
+	for (num = 0; num < 32; num++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < 8; func++) {
+				class = read_pci_config(num, slot, func,
+							PCI_CLASS_REVISION);
+				if (class == 0xffffffff)
+					continue; /* No device at this func */
+
+				if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
+					continue; /* Not an OHCI-1394 device */
+
+				init_ohci1394_controller(num, slot, func);
+				break; /* Assume one controller per device */
+			}
+		}
+	}
+	printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n");
+}
+
+/**
+ * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization
+ */
+static int __init setup_ohci1394_dma(char *opt)
+{
+	if (!strcmp(opt, "early"))
+		init_ohci1394_dma_early = 1;
+	return 0;
+}
+
+/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */
+early_param("ohci1394_dma", setup_ohci1394_dma);
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/Kconfig linux-libre-2.6.37-gnu/drivers/firewire/Kconfig
--- linux-libre-2.6.36-gnu/drivers/firewire/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,9 +3,6 @@
 	# firewire-core does not depend on PCI but is
 	# not useful without PCI controller driver
 
-comment "You can enable one or both FireWire driver stacks."
-comment "The newer stack is recommended."
-
 config FIREWIRE
 	tristate "FireWire driver stack"
 	select CRC_ITU_T
@@ -64,8 +61,6 @@
 	  To compile this driver as a module, say M here:  The module will be
 	  called firewire-net.
 
-source "drivers/ieee1394/Kconfig"
-
 config FIREWIRE_NOSY
 	tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
 	depends on PCI
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/Makefile linux-libre-2.6.37-gnu/drivers/firewire/Makefile
--- linux-libre-2.6.36-gnu/drivers/firewire/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -13,3 +13,4 @@
 obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
 obj-$(CONFIG_FIREWIRE_NET)  += firewire-net.o
 obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
+obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/net.c linux-libre-2.6.37-gnu/drivers/firewire/net.c
--- linux-libre-2.6.36-gnu/drivers/firewire/net.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/net.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,8 +7,8 @@
  */
 
 #include <linux/bug.h>
+#include <linux/delay.h>
 #include <linux/device.h>
-#include <linux/ethtool.h>
 #include <linux/firewire.h>
 #include <linux/firewire-constants.h>
 #include <linux/highmem.h>
@@ -27,8 +27,14 @@
 #include <asm/unaligned.h>
 #include <net/arp.h>
 
-#define FWNET_MAX_FRAGMENTS	25	/* arbitrary limit */
-#define FWNET_ISO_PAGE_COUNT	(PAGE_SIZE < 16 * 1024 ? 4 : 2)
+/* rx limits */
+#define FWNET_MAX_FRAGMENTS		30 /* arbitrary, > TX queue depth */
+#define FWNET_ISO_PAGE_COUNT		(PAGE_SIZE < 16*1024 ? 4 : 2)
+
+/* tx limits */
+#define FWNET_MAX_QUEUED_DATAGRAMS	20 /* < 64 = number of tlabels */
+#define FWNET_MIN_QUEUED_DATAGRAMS	10 /* should keep AT DMA busy enough */
+#define FWNET_TX_QUEUE_LEN		FWNET_MAX_QUEUED_DATAGRAMS /* ? */
 
 #define IEEE1394_BROADCAST_CHANNEL	31
 #define IEEE1394_ALL_NODES		(0xffc0 | 0x003f)
@@ -170,15 +176,8 @@
 	struct fw_address_handler handler;
 	u64 local_fifo;
 
-	/* List of packets to be sent */
-	struct list_head packet_list;
-	/*
-	 * List of packets that were broadcasted.  When we get an ISO interrupt
-	 * one of them has been sent
-	 */
-	struct list_head broadcasted_list;
-	/* List of packets that have been sent but not yet acked */
-	struct list_head sent_list;
+	/* Number of tx datagrams that have been queued but not yet acked */
+	int queued_datagrams;
 
 	struct list_head peer_list;
 	struct fw_card *card;
@@ -196,7 +195,7 @@
 	unsigned pdg_size;        /* pd_list size */
 
 	u16 datagram_label;       /* outgoing datagram label */
-	unsigned max_payload;     /* includes RFC2374_FRAG_HDR_SIZE overhead */
+	u16 max_payload;          /* includes RFC2374_FRAG_HDR_SIZE overhead */
 	int node_id;
 	int generation;
 	unsigned speed;
@@ -204,22 +203,18 @@
 
 /* This is our task struct. It's used for the packet complete callback.  */
 struct fwnet_packet_task {
-	/*
-	 * ptask can actually be on dev->packet_list, dev->broadcasted_list,
-	 * or dev->sent_list depending on its current state.
-	 */
-	struct list_head pt_link;
 	struct fw_transaction transaction;
 	struct rfc2734_header hdr;
 	struct sk_buff *skb;
 	struct fwnet_device *dev;
 
 	int outstanding_pkts;
-	unsigned max_payload;
 	u64 fifo_addr;
 	u16 dest_node;
+	u16 max_payload;
 	u8 generation;
 	u8 speed;
+	u8 enqueued;
 };
 
 /*
@@ -651,8 +646,6 @@
 		net->stats.rx_packets++;
 		net->stats.rx_bytes += skb->len;
 	}
-	if (netif_queue_stopped(net))
-		netif_wake_queue(net);
 
 	return 0;
 
@@ -661,8 +654,6 @@
 	net->stats.rx_dropped++;
 
 	dev_kfree_skb_any(skb);
-	if (netif_queue_stopped(net))
-		netif_wake_queue(net);
 
 	return -ENOENT;
 }
@@ -794,15 +785,10 @@
 	 * Datagram is not complete, we're done for the
 	 * moment.
 	 */
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	return 0;
+	retval = 0;
  fail:
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	if (netif_queue_stopped(net))
-		netif_wake_queue(net);
-
 	return retval;
 }
 
@@ -902,11 +888,19 @@
 	kmem_cache_free(fwnet_packet_task_cache, ptask);
 }
 
+/* Caller must hold dev->lock. */
+static void dec_queued_datagrams(struct fwnet_device *dev)
+{
+	if (--dev->queued_datagrams == FWNET_MIN_QUEUED_DATAGRAMS)
+		netif_wake_queue(dev->netdev);
+}
+
 static int fwnet_send_packet(struct fwnet_packet_task *ptask);
 
 static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
 {
 	struct fwnet_device *dev = ptask->dev;
+	struct sk_buff *skb = ptask->skb;
 	unsigned long flags;
 	bool free;
 
@@ -915,10 +909,14 @@
 	ptask->outstanding_pkts--;
 
 	/* Check whether we or the networking TX soft-IRQ is last user. */
-	free = (ptask->outstanding_pkts == 0 && !list_empty(&ptask->pt_link));
+	free = (ptask->outstanding_pkts == 0 && ptask->enqueued);
+	if (free)
+		dec_queued_datagrams(dev);
 
-	if (ptask->outstanding_pkts == 0)
-		list_del(&ptask->pt_link);
+	if (ptask->outstanding_pkts == 0) {
+		dev->netdev->stats.tx_packets++;
+		dev->netdev->stats.tx_bytes += skb->len;
+	}
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -927,7 +925,6 @@
 		u16 fg_off;
 		u16 datagram_label;
 		u16 lf;
-		struct sk_buff *skb;
 
 		/* Update the ptask to point to the next fragment and send it */
 		lf = fwnet_get_hdr_lf(&ptask->hdr);
@@ -954,7 +951,7 @@
 			datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
 			break;
 		}
-		skb = ptask->skb;
+
 		skb_pull(skb, ptask->max_payload);
 		if (ptask->outstanding_pkts > 1) {
 			fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
@@ -971,6 +968,31 @@
 		fwnet_free_ptask(ptask);
 }
 
+static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
+{
+	struct fwnet_device *dev = ptask->dev;
+	unsigned long flags;
+	bool free;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	/* One fragment failed; don't try to send remaining fragments. */
+	ptask->outstanding_pkts = 0;
+
+	/* Check whether we or the networking TX soft-IRQ is last user. */
+	free = ptask->enqueued;
+	if (free)
+		dec_queued_datagrams(dev);
+
+	dev->netdev->stats.tx_dropped++;
+	dev->netdev->stats.tx_errors++;
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (free)
+		fwnet_free_ptask(ptask);
+}
+
 static void fwnet_write_complete(struct fw_card *card, int rcode,
 				 void *payload, size_t length, void *data)
 {
@@ -978,11 +1000,12 @@
 
 	ptask = data;
 
-	if (rcode == RCODE_COMPLETE)
+	if (rcode == RCODE_COMPLETE) {
 		fwnet_transmit_packet_done(ptask);
-	else
+	} else {
 		fw_error("fwnet_write_complete: failed: %x\n", rcode);
-		/* ??? error recovery */
+		fwnet_transmit_packet_failed(ptask);
+	}
 }
 
 static int fwnet_send_packet(struct fwnet_packet_task *ptask)
@@ -1040,9 +1063,11 @@
 		spin_lock_irqsave(&dev->lock, flags);
 
 		/* If the AT tasklet already ran, we may be last user. */
-		free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+		free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
 		if (!free)
-			list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
+			ptask->enqueued = true;
+		else
+			dec_queued_datagrams(dev);
 
 		spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -1057,9 +1082,11 @@
 	spin_lock_irqsave(&dev->lock, flags);
 
 	/* If the AT tasklet already ran, we may be last user. */
-	free = (ptask->outstanding_pkts == 0 && list_empty(&ptask->pt_link));
+	free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
 	if (!free)
-		list_add_tail(&ptask->pt_link, &dev->sent_list);
+		ptask->enqueued = true;
+	else
+		dec_queued_datagrams(dev);
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
@@ -1225,6 +1252,15 @@
 	struct fwnet_peer *peer;
 	unsigned long flags;
 
+	spin_lock_irqsave(&dev->lock, flags);
+
+	/* Can this happen? */
+	if (netif_queue_stopped(dev->netdev)) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		return NETDEV_TX_BUSY;
+	}
+
 	ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
 	if (ptask == NULL)
 		goto fail;
@@ -1243,9 +1279,6 @@
 	proto = hdr_buf.h_proto;
 	dg_size = skb->len;
 
-	/* serialize access to peer, including peer->datagram_label */
-	spin_lock_irqsave(&dev->lock, flags);
-
 	/*
 	 * Set the transmission type for the packet.  ARP packets and IP
 	 * broadcast packets are sent via GASP.
@@ -1267,7 +1300,7 @@
 
 		peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
 		if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
-			goto fail_unlock;
+			goto fail;
 
 		generation         = peer->generation;
 		dest_node          = peer->node_id;
@@ -1321,18 +1354,21 @@
 		max_payload += RFC2374_FRAG_HDR_SIZE;
 	}
 
+	if (++dev->queued_datagrams == FWNET_MAX_QUEUED_DATAGRAMS)
+		netif_stop_queue(dev->netdev);
+
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ptask->max_payload = max_payload;
-	INIT_LIST_HEAD(&ptask->pt_link);
+	ptask->enqueued    = 0;
 
 	fwnet_send_packet(ptask);
 
 	return NETDEV_TX_OK;
 
- fail_unlock:
-	spin_unlock_irqrestore(&dev->lock, flags);
  fail:
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	if (ptask)
 		kmem_cache_free(fwnet_packet_task_cache, ptask);
 
@@ -1361,17 +1397,6 @@
 	return 0;
 }
 
-static void fwnet_get_drvinfo(struct net_device *net,
-			      struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, KBUILD_MODNAME);
-	strcpy(info->bus_info, "ieee1394");
-}
-
-static const struct ethtool_ops fwnet_ethtool_ops = {
-	.get_drvinfo = fwnet_get_drvinfo,
-};
-
 static const struct net_device_ops fwnet_netdev_ops = {
 	.ndo_open       = fwnet_open,
 	.ndo_stop	= fwnet_stop,
@@ -1389,8 +1414,7 @@
 	net->addr_len		= FWNET_ALEN;
 	net->hard_header_len	= FWNET_HLEN;
 	net->type		= ARPHRD_IEEE1394;
-	net->tx_queue_len	= 10;
-	SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
+	net->tx_queue_len	= FWNET_TX_QUEUE_LEN;
 }
 
 /* caller must hold fwnet_device_mutex */
@@ -1470,14 +1494,9 @@
 	dev->broadcast_rcv_context = NULL;
 	dev->broadcast_xmt_max_payload = 0;
 	dev->broadcast_xmt_datagramlabel = 0;
-
 	dev->local_fifo = FWNET_NO_FIFO_ADDR;
-
-	INIT_LIST_HEAD(&dev->packet_list);
-	INIT_LIST_HEAD(&dev->broadcasted_list);
-	INIT_LIST_HEAD(&dev->sent_list);
+	dev->queued_datagrams = 0;
 	INIT_LIST_HEAD(&dev->peer_list);
-
 	dev->card = card;
 	dev->netdev = net;
 
@@ -1535,7 +1554,7 @@
 	struct fwnet_peer *peer = dev_get_drvdata(_dev);
 	struct fwnet_device *dev = peer->dev;
 	struct net_device *net;
-	struct fwnet_packet_task *ptask, *pt_next;
+	int i;
 
 	mutex_lock(&fwnet_device_mutex);
 
@@ -1553,21 +1572,9 @@
 					      dev->card);
 			fw_iso_context_destroy(dev->broadcast_rcv_context);
 		}
-		list_for_each_entry_safe(ptask, pt_next,
-					 &dev->packet_list, pt_link) {
-			dev_kfree_skb_any(ptask->skb);
-			kmem_cache_free(fwnet_packet_task_cache, ptask);
-		}
-		list_for_each_entry_safe(ptask, pt_next,
-					 &dev->broadcasted_list, pt_link) {
-			dev_kfree_skb_any(ptask->skb);
-			kmem_cache_free(fwnet_packet_task_cache, ptask);
-		}
-		list_for_each_entry_safe(ptask, pt_next,
-					 &dev->sent_list, pt_link) {
-			dev_kfree_skb_any(ptask->skb);
-			kmem_cache_free(fwnet_packet_task_cache, ptask);
-		}
+		for (i = 0; dev->queued_datagrams && i < 5; i++)
+			ssleep(1);
+		WARN_ON(dev->queued_datagrams);
 		list_del(&dev->dev_link);
 
 		free_netdev(net);
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/nosy.c linux-libre-2.6.37-gnu/drivers/firewire/nosy.c
--- linux-libre-2.6.36-gnu/drivers/firewire/nosy.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/nosy.c	2011-01-04 19:50:19.000000000 -0500
@@ -405,6 +405,7 @@
 	.poll =			nosy_poll,
 	.open =			nosy_open,
 	.release =		nosy_release,
+	.llseek =		noop_llseek,
 };
 
 #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/ohci.c linux-libre-2.6.37-gnu/drivers/firewire/ohci.c
--- linux-libre-2.6.36-gnu/drivers/firewire/ohci.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/ohci.c	2011-01-04 19:50:19.000000000 -0500
@@ -242,6 +242,7 @@
 
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
+#define PCI_DEVICE_ID_AGERE_FW643	0x5901
 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW	0x2380
 #define PCI_DEVICE_ID_TI_TSB12LV22	0x8009
 
@@ -253,18 +254,34 @@
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
-	unsigned short vendor, device, flags;
+	unsigned short vendor, device, revision, flags;
 } ohci_quirks[] = {
-	{PCI_VENDOR_ID_TI,	PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
-							    QUIRK_RESET_PACKET |
-							    QUIRK_NO_1394A},
-	{PCI_VENDOR_ID_TI,	PCI_ANY_ID,	QUIRK_RESET_PACKET},
-	{PCI_VENDOR_ID_AL,	PCI_ANY_ID,	QUIRK_CYCLE_TIMER},
-	{PCI_VENDOR_ID_JMICRON,	PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
-	{PCI_VENDOR_ID_NEC,	PCI_ANY_ID,	QUIRK_CYCLE_TIMER},
-	{PCI_VENDOR_ID_VIA,	PCI_ANY_ID,	QUIRK_CYCLE_TIMER},
-	{PCI_VENDOR_ID_RICOH,	PCI_ANY_ID,	QUIRK_CYCLE_TIMER},
-	{PCI_VENDOR_ID_APPLE,	PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
+	{PCI_VENDOR_ID_AL, PCI_ANY_ID, PCI_ANY_ID,
+		QUIRK_CYCLE_TIMER},
+
+	{PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_FW, PCI_ANY_ID,
+		QUIRK_BE_HEADERS},
+
+	{PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
+		QUIRK_NO_MSI},
+
+	{PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID,
+		QUIRK_NO_MSI},
+
+	{PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID,
+		QUIRK_CYCLE_TIMER},
+
+	{PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID,
+		QUIRK_CYCLE_TIMER},
+
+	{PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID,
+		QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A},
+
+	{PCI_VENDOR_ID_TI, PCI_ANY_ID, PCI_ANY_ID,
+		QUIRK_RESET_PACKET},
+
+	{PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID,
+		QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
 };
 
 /* This overrides anything that was found in ohci_quirks[]. */
@@ -577,17 +594,11 @@
 	return ret;
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_link_page(struct ar_context *ctx,
+				 struct ar_buffer *ab, dma_addr_t ab_bus)
 {
-	struct device *dev = ctx->ohci->card.device;
-	struct ar_buffer *ab;
-	dma_addr_t uninitialized_var(ab_bus);
 	size_t offset;
 
-	ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-	if (ab == NULL)
-		return -ENOMEM;
-
 	ab->next = NULL;
 	memset(&ab->descriptor, 0, sizeof(ab->descriptor));
 	ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
@@ -606,6 +617,19 @@
 
 	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
 	flush_writes(ctx->ohci);
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+	struct device *dev = ctx->ohci->card.device;
+	struct ar_buffer *ab;
+	dma_addr_t uninitialized_var(ab_bus);
+
+	ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
+	if (ab == NULL)
+		return -ENOMEM;
+
+	ar_context_link_page(ctx, ab, ab_bus);
 
 	return 0;
 }
@@ -730,16 +754,17 @@
 static void ar_context_tasklet(unsigned long data)
 {
 	struct ar_context *ctx = (struct ar_context *)data;
-	struct fw_ohci *ohci = ctx->ohci;
 	struct ar_buffer *ab;
 	struct descriptor *d;
 	void *buffer, *end;
+	__le16 res_count;
 
 	ab = ctx->current_buffer;
 	d = &ab->descriptor;
 
-	if (d->res_count == 0) {
-		size_t size, rest, offset;
+	res_count = ACCESS_ONCE(d->res_count);
+	if (res_count == 0) {
+		size_t size, size2, rest, pktsize, size3, offset;
 		dma_addr_t start_bus;
 		void *start;
 
@@ -750,29 +775,63 @@
 		 */
 
 		offset = offsetof(struct ar_buffer, data);
-		start = buffer = ab;
+		start = ab;
 		start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+		buffer = ab->data;
 
 		ab = ab->next;
 		d = &ab->descriptor;
-		size = buffer + PAGE_SIZE - ctx->pointer;
+		size = start + PAGE_SIZE - ctx->pointer;
+		/* valid buffer data in the next page */
 		rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+		/* what actually fits in this page */
+		size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
 		memmove(buffer, ctx->pointer, size);
-		memcpy(buffer + size, ab->data, rest);
-		ctx->current_buffer = ab;
-		ctx->pointer = (void *) ab->data + rest;
-		end = buffer + size + rest;
+		memcpy(buffer + size, ab->data, size2);
 
-		while (buffer < end)
-			buffer = handle_ar_packet(ctx, buffer);
+		while (size > 0) {
+			void *next = handle_ar_packet(ctx, buffer);
+			pktsize = next - buffer;
+			if (pktsize >= size) {
+				/*
+				 * We have handled all the data that was
+				 * originally in this page, so we can now
+				 * continue in the next page.
+				 */
+				buffer = next;
+				break;
+			}
+			/* move the next packet to the start of the buffer */
+			memmove(buffer, next, size + size2 - pktsize);
+			size -= pktsize;
+			/* fill up this page again */
+			size3 = min(rest - size2,
+				    (size_t)PAGE_SIZE - offset - size - size2);
+			memcpy(buffer + size + size2,
+			       (void *) ab->data + size2, size3);
+			size2 += size3;
+		}
 
-		dma_free_coherent(ohci->card.device, PAGE_SIZE,
-				  start, start_bus);
-		ar_context_add_page(ctx);
+		if (rest > 0) {
+			/* handle the packets that are fully in the next page */
+			buffer = (void *) ab->data +
+					(buffer - (start + offset + size));
+			end = (void *) ab->data + rest;
+
+			while (buffer < end)
+				buffer = handle_ar_packet(ctx, buffer);
+
+			ctx->current_buffer = ab;
+			ctx->pointer = end;
+
+			ar_context_link_page(ctx, start, start_bus);
+		} else {
+			ctx->pointer = start + PAGE_SIZE;
+		}
 	} else {
 		buffer = ctx->pointer;
 		ctx->pointer = end =
-			(void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+			(void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
 
 		while (buffer < end)
 			buffer = handle_ar_packet(ctx, buffer);
@@ -2885,9 +2944,11 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(ohci_quirks); i++)
-		if (ohci_quirks[i].vendor == dev->vendor &&
-		    (ohci_quirks[i].device == dev->device ||
-		     ohci_quirks[i].device == (unsigned short)PCI_ANY_ID)) {
+		if ((ohci_quirks[i].vendor == dev->vendor) &&
+		    (ohci_quirks[i].device == (unsigned short)PCI_ANY_ID ||
+		     ohci_quirks[i].device == dev->device) &&
+		    (ohci_quirks[i].revision == (unsigned short)PCI_ANY_ID ||
+		     ohci_quirks[i].revision >= dev->revision)) {
 			ohci->quirks = ohci_quirks[i].flags;
 			break;
 		}
diff -druN linux-libre-2.6.36-gnu/drivers/firewire/sbp2.c linux-libre-2.6.37-gnu/drivers/firewire/sbp2.c
--- linux-libre-2.6.36-gnu/drivers/firewire/sbp2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firewire/sbp2.c	2011-01-04 19:50:19.000000000 -0500
@@ -1468,7 +1468,7 @@
 
 /* SCSI stack integration */
 
-static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done)
 {
 	struct sbp2_logical_unit *lu = cmd->device->hostdata;
 	struct fw_device *device = target_device(lu->tgt);
@@ -1534,6 +1534,8 @@
 	return retval;
 }
 
+static DEF_SCSI_QCMD(sbp2_scsi_queuecommand)
+
 static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 {
 	struct sbp2_logical_unit *lu = sdev->hostdata;
diff -druN linux-libre-2.6.36-gnu/drivers/firmware/dmi_scan.c linux-libre-2.6.37-gnu/drivers/firmware/dmi_scan.c
--- linux-libre-2.6.36-gnu/drivers/firmware/dmi_scan.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firmware/dmi_scan.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/ctype.h>
 #include <linux/dmi.h>
 #include <linux/efi.h>
 #include <linux/bootmem.h>
@@ -361,6 +362,33 @@
 	}
 }
 
+static void __init print_filtered(const char *info)
+{
+	const char *p;
+
+	if (!info)
+		return;
+
+	for (p = info; *p; p++)
+		if (isprint(*p))
+			printk(KERN_CONT "%c", *p);
+		else
+			printk(KERN_CONT "\\x%02x", *p & 0xff);
+}
+
+static void __init dmi_dump_ids(void)
+{
+	printk(KERN_DEBUG "DMI: ");
+	print_filtered(dmi_get_system_info(DMI_BOARD_NAME));
+	printk(KERN_CONT "/");
+	print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
+	printk(KERN_CONT ", BIOS ");
+	print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
+	printk(KERN_CONT " ");
+	print_filtered(dmi_get_system_info(DMI_BIOS_DATE));
+	printk(KERN_CONT "\n");
+}
+
 static int __init dmi_present(const char __iomem *p)
 {
 	u8 buf[15];
@@ -381,8 +409,10 @@
 			       buf[14] >> 4, buf[14] & 0xF);
 		else
 			printk(KERN_INFO "DMI present.\n");
-		if (dmi_walk_early(dmi_decode) == 0)
+		if (dmi_walk_early(dmi_decode) == 0) {
+			dmi_dump_ids();
 			return 0;
+		}
 	}
 	return 1;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/firmware/edd.c linux-libre-2.6.37-gnu/drivers/firmware/edd.c
--- linux-libre-2.6.36-gnu/drivers/firmware/edd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firmware/edd.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,7 @@
  * made in setup.S, copied to safe structures in setup.c,
  * and presents it in sysfs.
  *
- * Please see http://linux.dell.com/edd30/results.html for
+ * Please see http://linux.dell.com/edd/results.html for
  * the list of BIOSs which have been reported to implement EDD.
  *
  * This program is free software; you can redistribute it and/or modify
diff -druN linux-libre-2.6.36-gnu/drivers/firmware/Kconfig linux-libre-2.6.37-gnu/drivers/firmware/Kconfig
--- linux-libre-2.6.36-gnu/drivers/firmware/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firmware/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -74,7 +74,8 @@
 
 	  You must also enable the appropriate drivers (serial, VGA, etc.)
 
-	  See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
+	  See DIG64_HCDPv20_042804.pdf available from
+	  <http://www.dig64.org/specifications/> 
 
 config DELL_RBU
 	tristate "BIOS update support for DELL systems via sysfs"
@@ -125,7 +126,7 @@
 config ISCSI_IBFT
 	tristate "iSCSI Boot Firmware Table Attributes module"
 	select ISCSI_BOOT_SYSFS
-	depends on ISCSI_IBFT_FIND && SCSI
+	depends on ISCSI_IBFT_FIND && SCSI && SCSI_LOWLEVEL
 	default	n
 	help
 	  This option enables support for detection and exposing of iSCSI
diff -druN linux-libre-2.6.36-gnu/drivers/firmware/pcdp.h linux-libre-2.6.37-gnu/drivers/firmware/pcdp.h
--- linux-libre-2.6.36-gnu/drivers/firmware/pcdp.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/firmware/pcdp.h	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 /*
  * Definitions for PCDP-defined console devices
  *
- * v1.0a: http://www.dig64.org/specifications/DIG64_HCDPv10a_01.pdf
- * v2.0:  http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
+ * For DIG64_HCDPv10a_01.pdf and DIG64_PCDPv20.pdf (v1.0a and v2.0 resp.),
+ * please see <http://www.dig64.org/specifications/>
  *
  * (c) Copyright 2002, 2004 Hewlett-Packard Development Company, L.P.
  *	Khalid Aziz <khalid.aziz@hp.com>
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/74x164.c linux-libre-2.6.37-gnu/drivers/gpio/74x164.c
--- linux-libre-2.6.36-gnu/drivers/gpio/74x164.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpio/74x164.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,182 @@
+/*
+ *  74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
+ *
+ *  Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2010 Miguel Gaio <miguel.gaio@efixo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/74x164.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#define GEN_74X164_GPIO_COUNT	8
+
+
+struct gen_74x164_chip {
+	struct spi_device	*spi;
+	struct gpio_chip	gpio_chip;
+	struct mutex		lock;
+	u8			port_config;
+};
+
+static void gen_74x164_set_value(struct gpio_chip *, unsigned, int);
+
+static struct gen_74x164_chip *gpio_to_chip(struct gpio_chip *gc)
+{
+	return container_of(gc, struct gen_74x164_chip, gpio_chip);
+}
+
+static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
+{
+	return spi_write(chip->spi,
+			 &chip->port_config, sizeof(chip->port_config));
+}
+
+static int gen_74x164_direction_output(struct gpio_chip *gc,
+		unsigned offset, int val)
+{
+	gen_74x164_set_value(gc, offset, val);
+	return 0;
+}
+
+static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
+{
+	struct gen_74x164_chip *chip = gpio_to_chip(gc);
+	int ret;
+
+	mutex_lock(&chip->lock);
+	ret = (chip->port_config >> offset) & 0x1;
+	mutex_unlock(&chip->lock);
+
+	return ret;
+}
+
+static void gen_74x164_set_value(struct gpio_chip *gc,
+		unsigned offset, int val)
+{
+	struct gen_74x164_chip *chip = gpio_to_chip(gc);
+
+	mutex_lock(&chip->lock);
+	if (val)
+		chip->port_config |= (1 << offset);
+	else
+		chip->port_config &= ~(1 << offset);
+
+	__gen_74x164_write_config(chip);
+	mutex_unlock(&chip->lock);
+}
+
+static int __devinit gen_74x164_probe(struct spi_device *spi)
+{
+	struct gen_74x164_chip *chip;
+	struct gen_74x164_chip_platform_data *pdata;
+	int ret;
+
+	pdata = spi->dev.platform_data;
+	if (!pdata || !pdata->base) {
+		dev_dbg(&spi->dev, "incorrect or missing platform data\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * bits_per_word cannot be configured in platform data
+	 */
+	spi->bits_per_word = 8;
+
+	ret = spi_setup(spi);
+	if (ret < 0)
+		return ret;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	mutex_init(&chip->lock);
+
+	dev_set_drvdata(&spi->dev, chip);
+
+	chip->spi = spi;
+
+	chip->gpio_chip.label = GEN_74X164_DRIVER_NAME,
+		chip->gpio_chip.direction_output = gen_74x164_direction_output;
+	chip->gpio_chip.get = gen_74x164_get_value;
+	chip->gpio_chip.set = gen_74x164_set_value;
+	chip->gpio_chip.base = pdata->base;
+	chip->gpio_chip.ngpio = GEN_74X164_GPIO_COUNT;
+	chip->gpio_chip.can_sleep = 1;
+	chip->gpio_chip.dev = &spi->dev;
+	chip->gpio_chip.owner = THIS_MODULE;
+
+	ret = __gen_74x164_write_config(chip);
+	if (ret) {
+		dev_err(&spi->dev, "Failed writing: %d\n", ret);
+		goto exit_destroy;
+	}
+
+	ret = gpiochip_add(&chip->gpio_chip);
+	if (ret)
+		goto exit_destroy;
+
+	return ret;
+
+exit_destroy:
+	dev_set_drvdata(&spi->dev, NULL);
+	mutex_destroy(&chip->lock);
+	kfree(chip);
+	return ret;
+}
+
+static int gen_74x164_remove(struct spi_device *spi)
+{
+	struct gen_74x164_chip *chip;
+	int ret;
+
+	chip = dev_get_drvdata(&spi->dev);
+	if (chip == NULL)
+		return -ENODEV;
+
+	dev_set_drvdata(&spi->dev, NULL);
+
+	ret = gpiochip_remove(&chip->gpio_chip);
+	if (!ret) {
+		mutex_destroy(&chip->lock);
+		kfree(chip);
+	} else
+		dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
+				ret);
+
+	return ret;
+}
+
+static struct spi_driver gen_74x164_driver = {
+	.driver = {
+		.name		= GEN_74X164_DRIVER_NAME,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= gen_74x164_probe,
+	.remove		= __devexit_p(gen_74x164_remove),
+};
+
+static int __init gen_74x164_init(void)
+{
+	return spi_register_driver(&gen_74x164_driver);
+}
+subsys_initcall(gen_74x164_init);
+
+static void __exit gen_74x164_exit(void)
+{
+	spi_unregister_driver(&gen_74x164_driver);
+}
+module_exit(gen_74x164_exit);
+
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
+MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>");
+MODULE_DESCRIPTION("GPIO expander driver for 74X164 8-bits shift register");
+MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/adp5588-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/adp5588-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/adp5588-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/adp5588-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,8 @@
 /*
  * GPIO Chip driver for Analog Devices
- * ADP5588 I/O Expander and QWERTY Keypad Controller
+ * ADP5588/ADP5587 I/O Expander and QWERTY Keypad Controller
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2010 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -13,21 +13,34 @@
 #include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <linux/i2c/adp5588.h>
 
-#define DRV_NAME		"adp5588-gpio"
-#define MAXGPIO			18
-#define ADP_BANK(offs)		((offs) >> 3)
-#define ADP_BIT(offs)		(1u << ((offs) & 0x7))
+#define DRV_NAME	"adp5588-gpio"
+
+/*
+ * Early pre 4.0 Silicon required to delay readout by at least 25ms,
+ * since the Event Counter Register updated 25ms after the interrupt
+ * asserted.
+ */
+#define WA_DELAYED_READOUT_REVID(rev)	((rev) < 4)
 
 struct adp5588_gpio {
 	struct i2c_client *client;
 	struct gpio_chip gpio_chip;
 	struct mutex lock;	/* protect cached dir, dat_out */
+	/* protect serialized access to the interrupt controller bus */
+	struct mutex irq_lock;
 	unsigned gpio_start;
+	unsigned irq_base;
 	uint8_t dat_out[3];
 	uint8_t dir[3];
+	uint8_t int_lvl[3];
+	uint8_t int_en[3];
+	uint8_t irq_mask[3];
+	uint8_t irq_stat[3];
 };
 
 static int adp5588_gpio_read(struct i2c_client *client, u8 reg)
@@ -55,8 +68,8 @@
 	struct adp5588_gpio *dev =
 	    container_of(chip, struct adp5588_gpio, gpio_chip);
 
-	return !!(adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + ADP_BANK(off))
-		  & ADP_BIT(off));
+	return !!(adp5588_gpio_read(dev->client,
+		  GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
 }
 
 static void adp5588_gpio_set_value(struct gpio_chip *chip,
@@ -66,8 +79,8 @@
 	struct adp5588_gpio *dev =
 	    container_of(chip, struct adp5588_gpio, gpio_chip);
 
-	bank = ADP_BANK(off);
-	bit = ADP_BIT(off);
+	bank = ADP5588_BANK(off);
+	bit = ADP5588_BIT(off);
 
 	mutex_lock(&dev->lock);
 	if (val)
@@ -87,10 +100,10 @@
 	struct adp5588_gpio *dev =
 	    container_of(chip, struct adp5588_gpio, gpio_chip);
 
-	bank = ADP_BANK(off);
+	bank = ADP5588_BANK(off);
 
 	mutex_lock(&dev->lock);
-	dev->dir[bank] &= ~ADP_BIT(off);
+	dev->dir[bank] &= ~ADP5588_BIT(off);
 	ret = adp5588_gpio_write(dev->client, GPIO_DIR1 + bank, dev->dir[bank]);
 	mutex_unlock(&dev->lock);
 
@@ -105,8 +118,8 @@
 	struct adp5588_gpio *dev =
 	    container_of(chip, struct adp5588_gpio, gpio_chip);
 
-	bank = ADP_BANK(off);
-	bit = ADP_BIT(off);
+	bank = ADP5588_BANK(off);
+	bit = ADP5588_BIT(off);
 
 	mutex_lock(&dev->lock);
 	dev->dir[bank] |= bit;
@@ -125,6 +138,213 @@
 	return ret;
 }
 
+#ifdef CONFIG_GPIO_ADP5588_IRQ
+static int adp5588_gpio_to_irq(struct gpio_chip *chip, unsigned off)
+{
+	struct adp5588_gpio *dev =
+		container_of(chip, struct adp5588_gpio, gpio_chip);
+	return dev->irq_base + off;
+}
+
+static void adp5588_irq_bus_lock(unsigned int irq)
+{
+	struct adp5588_gpio *dev = get_irq_chip_data(irq);
+	mutex_lock(&dev->irq_lock);
+}
+
+ /*
+  * genirq core code can issue chip->mask/unmask from atomic context.
+  * This doesn't work for slow busses where an access needs to sleep.
+  * bus_sync_unlock() is therefore called outside the atomic context,
+  * syncs the current irq mask state with the slow external controller
+  * and unlocks the bus.
+  */
+
+static void adp5588_irq_bus_sync_unlock(unsigned int irq)
+{
+	struct adp5588_gpio *dev = get_irq_chip_data(irq);
+	int i;
+
+	for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++)
+		if (dev->int_en[i] ^ dev->irq_mask[i]) {
+			dev->int_en[i] = dev->irq_mask[i];
+			adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i,
+					   dev->int_en[i]);
+		}
+
+	mutex_unlock(&dev->irq_lock);
+}
+
+static void adp5588_irq_mask(unsigned int irq)
+{
+	struct adp5588_gpio *dev = get_irq_chip_data(irq);
+	unsigned gpio = irq - dev->irq_base;
+
+	dev->irq_mask[ADP5588_BANK(gpio)] &= ~ADP5588_BIT(gpio);
+}
+
+static void adp5588_irq_unmask(unsigned int irq)
+{
+	struct adp5588_gpio *dev = get_irq_chip_data(irq);
+	unsigned gpio = irq - dev->irq_base;
+
+	dev->irq_mask[ADP5588_BANK(gpio)] |= ADP5588_BIT(gpio);
+}
+
+static int adp5588_irq_set_type(unsigned int irq, unsigned int type)
+{
+	struct adp5588_gpio *dev = get_irq_chip_data(irq);
+	uint16_t gpio = irq - dev->irq_base;
+	unsigned bank, bit;
+
+	if ((type & IRQ_TYPE_EDGE_BOTH)) {
+		dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
+			irq, type);
+		return -EINVAL;
+	}
+
+	bank = ADP5588_BANK(gpio);
+	bit = ADP5588_BIT(gpio);
+
+	if (type & IRQ_TYPE_LEVEL_HIGH)
+		dev->int_lvl[bank] |= bit;
+	else if (type & IRQ_TYPE_LEVEL_LOW)
+		dev->int_lvl[bank] &= ~bit;
+	else
+		return -EINVAL;
+
+	adp5588_gpio_direction_input(&dev->gpio_chip, gpio);
+	adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank,
+			   dev->int_lvl[bank]);
+
+	return 0;
+}
+
+static struct irq_chip adp5588_irq_chip = {
+	.name			= "adp5588",
+	.mask			= adp5588_irq_mask,
+	.unmask			= adp5588_irq_unmask,
+	.bus_lock		= adp5588_irq_bus_lock,
+	.bus_sync_unlock	= adp5588_irq_bus_sync_unlock,
+	.set_type		= adp5588_irq_set_type,
+};
+
+static int adp5588_gpio_read_intstat(struct i2c_client *client, u8 *buf)
+{
+	int ret = i2c_smbus_read_i2c_block_data(client, GPIO_INT_STAT1, 3, buf);
+
+	if (ret < 0)
+		dev_err(&client->dev, "Read INT_STAT Error\n");
+
+	return ret;
+}
+
+static irqreturn_t adp5588_irq_handler(int irq, void *devid)
+{
+	struct adp5588_gpio *dev = devid;
+	unsigned status, bank, bit, pending;
+	int ret;
+	status = adp5588_gpio_read(dev->client, INT_STAT);
+
+	if (status & ADP5588_GPI_INT) {
+		ret = adp5588_gpio_read_intstat(dev->client, dev->irq_stat);
+		if (ret < 0)
+			memset(dev->irq_stat, 0, ARRAY_SIZE(dev->irq_stat));
+
+		for (bank = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO);
+			bank++, bit = 0) {
+			pending = dev->irq_stat[bank] & dev->irq_mask[bank];
+
+			while (pending) {
+				if (pending & (1 << bit)) {
+					handle_nested_irq(dev->irq_base +
+							  (bank << 3) + bit);
+					pending &= ~(1 << bit);
+
+				}
+				bit++;
+			}
+		}
+	}
+
+	adp5588_gpio_write(dev->client, INT_STAT, status); /* Status is W1C */
+
+	return IRQ_HANDLED;
+}
+
+static int adp5588_irq_setup(struct adp5588_gpio *dev)
+{
+	struct i2c_client *client = dev->client;
+	struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+	unsigned gpio;
+	int ret;
+
+	adp5588_gpio_write(client, CFG, ADP5588_AUTO_INC);
+	adp5588_gpio_write(client, INT_STAT, -1); /* status is W1C */
+	adp5588_gpio_read_intstat(client, dev->irq_stat); /* read to clear */
+
+	dev->irq_base = pdata->irq_base;
+	mutex_init(&dev->irq_lock);
+
+	for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) {
+		int irq = gpio + dev->irq_base;
+		set_irq_chip_data(irq, dev);
+		set_irq_chip_and_handler(irq, &adp5588_irq_chip,
+					 handle_level_irq);
+		set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+		/*
+		 * ARM needs us to explicitly flag the IRQ as VALID,
+		 * once we do so, it will also set the noprobe.
+		 */
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		set_irq_noprobe(irq);
+#endif
+	}
+
+	ret = request_threaded_irq(client->irq,
+				   NULL,
+				   adp5588_irq_handler,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   dev_name(&client->dev), dev);
+	if (ret) {
+		dev_err(&client->dev, "failed to request irq %d\n",
+			client->irq);
+		goto out;
+	}
+
+	dev->gpio_chip.to_irq = adp5588_gpio_to_irq;
+	adp5588_gpio_write(client, CFG,
+		ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_GPI_INT);
+
+	return 0;
+
+out:
+	dev->irq_base = 0;
+	return ret;
+}
+
+static void adp5588_irq_teardown(struct adp5588_gpio *dev)
+{
+	if (dev->irq_base)
+		free_irq(dev->client->irq, dev);
+}
+
+#else
+static int adp5588_irq_setup(struct adp5588_gpio *dev)
+{
+	struct i2c_client *client = dev->client;
+	dev_warn(&client->dev, "interrupt support not compiled in\n");
+
+	return 0;
+}
+
+static void adp5588_irq_teardown(struct adp5588_gpio *dev)
+{
+}
+#endif /* CONFIG_GPIO_ADP5588_IRQ */
+
 static int __devinit adp5588_gpio_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
@@ -160,37 +380,46 @@
 	gc->can_sleep = 1;
 
 	gc->base = pdata->gpio_start;
-	gc->ngpio = MAXGPIO;
+	gc->ngpio = ADP5588_MAXGPIO;
 	gc->label = client->name;
 	gc->owner = THIS_MODULE;
 
 	mutex_init(&dev->lock);
 
-
 	ret = adp5588_gpio_read(dev->client, DEV_ID);
 	if (ret < 0)
 		goto err;
 
 	revid = ret & ADP5588_DEVICE_ID_MASK;
 
-	for (i = 0, ret = 0; i <= ADP_BANK(MAXGPIO); i++) {
+	for (i = 0, ret = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) {
 		dev->dat_out[i] = adp5588_gpio_read(client, GPIO_DAT_OUT1 + i);
 		dev->dir[i] = adp5588_gpio_read(client, GPIO_DIR1 + i);
 		ret |= adp5588_gpio_write(client, KP_GPIO1 + i, 0);
 		ret |= adp5588_gpio_write(client, GPIO_PULL1 + i,
 				(pdata->pullup_dis_mask >> (8 * i)) & 0xFF);
-
+		ret |= adp5588_gpio_write(client, GPIO_INT_EN1 + i, 0);
 		if (ret)
 			goto err;
 	}
 
+	if (pdata->irq_base) {
+		if (WA_DELAYED_READOUT_REVID(revid)) {
+			dev_warn(&client->dev, "GPIO int not supported\n");
+		} else {
+			ret = adp5588_irq_setup(dev);
+			if (ret)
+				goto err;
+		}
+	}
+
 	ret = gpiochip_add(&dev->gpio_chip);
 	if (ret)
-		goto err;
+		goto err_irq;
 
-	dev_info(&client->dev, "gpios %d..%d on a %s Rev. %d\n",
+	dev_info(&client->dev, "gpios %d..%d (IRQ Base %d) on a %s Rev. %d\n",
 			gc->base, gc->base + gc->ngpio - 1,
-			client->name, revid);
+			pdata->irq_base, client->name, revid);
 
 	if (pdata->setup) {
 		ret = pdata->setup(client, gc->base, gc->ngpio, pdata->context);
@@ -199,8 +428,11 @@
 	}
 
 	i2c_set_clientdata(client, dev);
+
 	return 0;
 
+err_irq:
+	adp5588_irq_teardown(dev);
 err:
 	kfree(dev);
 	return ret;
@@ -222,6 +454,9 @@
 		}
 	}
 
+	if (dev->irq_base)
+		free_irq(dev->client->irq, dev);
+
 	ret = gpiochip_remove(&dev->gpio_chip);
 	if (ret) {
 		dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/basic_mmio_gpio.c linux-libre-2.6.37-gnu/drivers/gpio/basic_mmio_gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/basic_mmio_gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpio/basic_mmio_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,297 @@
+/*
+ * Driver for basic memory-mapped GPIO controllers.
+ *
+ * Copyright 2008 MontaVista Software, Inc.
+ * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
+ * ...``                                                         ```````..
+ * ..The simplest form of a GPIO controller that the driver supports is``
+ *  `.just a single "data" register, where GPIO state can be read and/or `
+ *    `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.```````
+ *        `````````
+                                    ___
+_/~~|___/~|   . ```~~~~~~       ___/___\___     ,~.`.`.`.`````.~~...,,,,...
+__________|~$@~~~        %~    /o*o*o*o*o*o\   .. Implementing such a GPIO .
+o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
+                                                 `....trivial..'~`.```.```
+ *                                                    ```````
+ *  .```````~~~~`..`.``.``.
+ * .  The driver supports  `...       ,..```.`~~~```````````````....````.``,,
+ * .   big-endian notation, just`.  .. A bit more sophisticated controllers ,
+ *  . register the device with -be`. .with a pair of set/clear-bit registers ,
+ *   `.. suffix.  ```~~`````....`.`   . affecting the data register and the .`
+ *     ``.`.``...```                  ```.. output pins are also supported.`
+ *                        ^^             `````.`````````.,``~``~``~~``````
+ *                                                   .                  ^^
+ *   ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`..
+ * .. The expectation is that in at least some cases .    ,-~~~-,
+ *  .this will be used with roll-your-own ASIC/FPGA .`     \   /
+ *  .logic in Verilog or VHDL. ~~~`````````..`````~~`       \ /
+ *  ..````````......```````````                             \o_
+ *                                                           |
+ *                              ^^                          / \
+ *
+ *           ...`````~~`.....``.`..........``````.`.``.```........``.
+ *            `  8, 16, 32 and 64 bits registers are supported, and``.
+ *            . the number of GPIOs is determined by the width of   ~
+ *             .. the registers. ,............```.`.`..`.`.~~~.`.`.`~
+ *               `.......````.```
+ */
+
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/log2.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/basic_mmio_gpio.h>
+
+struct bgpio_chip {
+	struct gpio_chip gc;
+	void __iomem *reg_dat;
+	void __iomem *reg_set;
+	void __iomem *reg_clr;
+
+	/* Number of bits (GPIOs): <register width> * 8. */
+	int bits;
+
+	/*
+	 * Some GPIO controllers work with the big-endian bits notation,
+	 * e.g. in a 8-bits register, GPIO7 is the least significant bit.
+	 */
+	int big_endian_bits;
+
+	/*
+	 * Used to lock bgpio_chip->data. Also, this is needed to keep
+	 * shadowed and real data registers writes together.
+	 */
+	spinlock_t lock;
+
+	/* Shadowed data register to clear/set bits safely. */
+	unsigned long data;
+};
+
+static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
+{
+	return container_of(gc, struct bgpio_chip, gc);
+}
+
+static unsigned long bgpio_in(struct bgpio_chip *bgc)
+{
+	switch (bgc->bits) {
+	case 8:
+		return __raw_readb(bgc->reg_dat);
+	case 16:
+		return __raw_readw(bgc->reg_dat);
+	case 32:
+		return __raw_readl(bgc->reg_dat);
+#if BITS_PER_LONG >= 64
+	case 64:
+		return __raw_readq(bgc->reg_dat);
+#endif
+	}
+	return -EINVAL;
+}
+
+static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
+		      unsigned long data)
+{
+	switch (bgc->bits) {
+	case 8:
+		__raw_writeb(data, reg);
+		return;
+	case 16:
+		__raw_writew(data, reg);
+		return;
+	case 32:
+		__raw_writel(data, reg);
+		return;
+#if BITS_PER_LONG >= 64
+	case 64:
+		__raw_writeq(data, reg);
+		return;
+#endif
+	}
+}
+
+static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
+{
+	if (bgc->big_endian_bits)
+		return 1 << (bgc->bits - 1 - pin);
+	else
+		return 1 << pin;
+}
+
+static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+	return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
+}
+
+static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct bgpio_chip *bgc = to_bgpio_chip(gc);
+	unsigned long mask = bgpio_pin2mask(bgc, gpio);
+	unsigned long flags;
+
+	if (bgc->reg_set) {
+		if (val)
+			bgpio_out(bgc, bgc->reg_set, mask);
+		else
+			bgpio_out(bgc, bgc->reg_clr, mask);
+		return;
+	}
+
+	spin_lock_irqsave(&bgc->lock, flags);
+
+	if (val)
+		bgc->data |= mask;
+	else
+		bgc->data &= ~mask;
+
+	bgpio_out(bgc, bgc->reg_dat, bgc->data);
+
+	spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	return 0;
+}
+
+static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	bgpio_set(gc, gpio, val);
+	return 0;
+}
+
+static int __devinit bgpio_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	struct device *dev = &pdev->dev;
+	struct bgpio_pdata *pdata = dev_get_platdata(dev);
+	struct bgpio_chip *bgc;
+	struct resource *res_dat;
+	struct resource *res_set;
+	struct resource *res_clr;
+	resource_size_t dat_sz;
+	int bits;
+	int ret;
+
+	res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+	if (!res_dat)
+		return -EINVAL;
+
+	dat_sz = resource_size(res_dat);
+	if (!is_power_of_2(dat_sz))
+		return -EINVAL;
+
+	bits = dat_sz * 8;
+	if (bits > BITS_PER_LONG)
+		return -EINVAL;
+
+	bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
+	if (!bgc)
+		return -ENOMEM;
+
+	bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
+	if (!bgc->reg_dat)
+		return -ENOMEM;
+
+	res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
+	res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
+	if (res_set && res_clr) {
+		if (resource_size(res_set) != resource_size(res_clr) ||
+				resource_size(res_set) != dat_sz)
+			return -EINVAL;
+
+		bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
+		bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
+		if (!bgc->reg_set || !bgc->reg_clr)
+			return -ENOMEM;
+	} else if (res_set || res_clr) {
+		return -EINVAL;
+	}
+
+	spin_lock_init(&bgc->lock);
+
+	bgc->bits = bits;
+	bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
+	bgc->data = bgpio_in(bgc);
+
+	bgc->gc.ngpio = bits;
+	bgc->gc.direction_input = bgpio_dir_in;
+	bgc->gc.direction_output = bgpio_dir_out;
+	bgc->gc.get = bgpio_get;
+	bgc->gc.set = bgpio_set;
+	bgc->gc.dev = dev;
+	bgc->gc.label = dev_name(dev);
+
+	if (pdata)
+		bgc->gc.base = pdata->base;
+	else
+		bgc->gc.base = -1;
+
+	dev_set_drvdata(dev, bgc);
+
+	ret = gpiochip_add(&bgc->gc);
+	if (ret)
+		dev_err(dev, "gpiochip_add() failed: %d\n", ret);
+
+	return ret;
+}
+
+static int __devexit bgpio_remove(struct platform_device *pdev)
+{
+	struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
+
+	return gpiochip_remove(&bgc->gc);
+}
+
+static const struct platform_device_id bgpio_id_table[] = {
+	{ "basic-mmio-gpio", },
+	{ "basic-mmio-gpio-be", },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, bgpio_id_table);
+
+static struct platform_driver bgpio_driver = {
+	.driver = {
+		.name = "basic-mmio-gpio",
+	},
+	.id_table = bgpio_id_table,
+	.probe = bgpio_probe,
+	.remove = __devexit_p(bgpio_remove),
+};
+
+static int __init bgpio_init(void)
+{
+	return platform_driver_register(&bgpio_driver);
+}
+module_init(bgpio_init);
+
+static void __exit bgpio_exit(void)
+{
+	platform_driver_unregister(&bgpio_driver);
+}
+module_exit(bgpio_exit);
+
+MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
+MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/cs5535-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/cs5535-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/cs5535-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/cs5535-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,6 +56,29 @@
  * registers, see include/linux/cs5535.h.
  */
 
+static void errata_outl(struct cs5535_gpio_chip *chip, u32 val,
+		unsigned int reg)
+{
+	unsigned long addr = chip->base + 0x80 + reg;
+
+	/*
+	 * According to the CS5536 errata (#36), after suspend
+	 * a write to the high bank GPIO register will clear all
+	 * non-selected bits; the recommended workaround is a
+	 * read-modify-write operation.
+	 *
+	 * Don't apply this errata to the edge status GPIOs, as writing
+	 * to their lower bits will clear them.
+	 */
+	if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) {
+		if (val & 0xffff)
+			val |= (inl(addr) & 0xffff); /* ignore the high bits */
+		else
+			val |= (inl(addr) ^ (val >> 16));
+	}
+	outl(val, addr);
+}
+
 static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
 		unsigned int reg)
 {
@@ -64,7 +87,7 @@
 		outl(1 << offset, chip->base + reg);
 	else
 		/* high bank register */
-		outl(1 << (offset - 16), chip->base + 0x80 + reg);
+		errata_outl(chip, 1 << (offset - 16), reg);
 }
 
 void cs5535_gpio_set(unsigned offset, unsigned int reg)
@@ -86,7 +109,7 @@
 		outl(1 << (offset + 16), chip->base + reg);
 	else
 		/* high bank register */
-		outl(1 << offset, chip->base + 0x80 + reg);
+		errata_outl(chip, 1 << offset, reg);
 }
 
 void cs5535_gpio_clear(unsigned offset, unsigned int reg)
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/gpiolib.c linux-libre-2.6.37-gnu/drivers/gpio/gpiolib.c
--- linux-libre-2.6.36-gnu/drivers/gpio/gpiolib.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/gpiolib.c	2011-01-04 19:50:19.000000000 -0500
@@ -1281,6 +1281,9 @@
 		err = gpio_direction_output(gpio,
 				(flags & GPIOF_INIT_HIGH) ? 1 : 0);
 
+	if (err)
+		gpio_free(gpio);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(gpio_request_one);
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/Kconfig linux-libre-2.6.37-gnu/drivers/gpio/Kconfig
--- linux-libre-2.6.36-gnu/drivers/gpio/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -70,6 +70,11 @@
 
 comment "Memory mapped GPIO expanders:"
 
+config GPIO_BASIC_MMIO
+	tristate "Basic memory-mapped GPIO controllers support"
+	help
+	  Say yes here to support basic memory-mapped GPIO controllers.
+
 config GPIO_IT8761E
 	tristate "IT8761E GPIO support"
 	depends on GPIOLIB
@@ -111,6 +116,18 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called sch-gpio.
 
+config GPIO_VX855
+	tristate "VIA VX855/VX875 GPIO"
+	depends on GPIOLIB
+	select MFD_CORE
+	select MFD_VX855
+	help
+	  Support access to the VX855/VX875 GPIO lines through the gpio library.
+
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the
+	  functionality of the device.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_MAX7300
@@ -267,6 +284,13 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called adp5588-gpio.
 
+config GPIO_ADP5588_IRQ
+	bool "Interrupt controller support for ADP5588"
+	depends on GPIO_ADP5588=y
+	help
+	  Say yes here to enable the adp5588 to be used as an interrupt
+	  controller. It requires the driver to be built in the kernel.
+
 comment "PCI GPIO expanders:"
 
 config GPIO_CS5535
@@ -301,6 +325,14 @@
 	help
 	  Say Y here to support Intel Langwell/Penwell GPIO.
 
+config GPIO_PCH
+	tristate "PCH GPIO of Intel Topcliff"
+	depends on PCI
+	help
+	  This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
+	  which is an IOH(Input/Output Hub) for x86 embedded processor.
+	  This driver can access PCH GPIO device.
+
 config GPIO_TIMBERDALE
 	bool "Support for timberdale GPIO IP"
 	depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
@@ -339,6 +371,14 @@
 	  SPI driver for Freescale MC33880 high-side/low-side switch.
 	  This provides GPIO interface supporting inputs and outputs.
 
+config GPIO_74X164
+	tristate "74x164 serial-in/parallel-out 8-bits shift register"
+	depends on SPI_MASTER
+	help
+	  Platform driver for 74x164 compatible serial-in/parallel-out
+	  8-outputs shift registers. This driver can be used to provide access
+	  to more gpio outputs.
+
 comment "AC97 GPIO expanders:"
 
 config GPIO_UCB1400
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/langwell_gpio.c linux-libre-2.6.37-gnu/drivers/gpio/langwell_gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/langwell_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/langwell_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -18,10 +18,12 @@
 /* Supports:
  * Moorestown platform Langwell chip.
  * Medfield platform Penwell chip.
+ * Whitney point.
  */
 
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/stddef.h>
@@ -158,15 +160,15 @@
 	spin_unlock_irqrestore(&lnw->lock, flags);
 
 	return 0;
-};
+}
 
 static void lnw_irq_unmask(unsigned irq)
 {
-};
+}
 
 static void lnw_irq_mask(unsigned irq)
 {
-};
+}
 
 static struct irq_chip lnw_irqchip = {
 	.name		= "LNW-GPIO",
@@ -300,9 +302,88 @@
 	.probe		= lnw_gpio_probe,
 };
 
+
+static int __devinit wp_gpio_probe(struct platform_device *pdev)
+{
+	struct lnw_gpio *lnw;
+	struct gpio_chip *gc;
+	struct resource *rc;
+	int retval = 0;
+
+	rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!rc)
+		return -EINVAL;
+
+	lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
+	if (!lnw) {
+		dev_err(&pdev->dev,
+			"can't allocate whitneypoint_gpio chip data\n");
+		return -ENOMEM;
+	}
+	lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
+	if (lnw->reg_base == NULL) {
+		retval = -EINVAL;
+		goto err_kmalloc;
+	}
+	spin_lock_init(&lnw->lock);
+	gc = &lnw->chip;
+	gc->label = dev_name(&pdev->dev);
+	gc->owner = THIS_MODULE;
+	gc->direction_input = lnw_gpio_direction_input;
+	gc->direction_output = lnw_gpio_direction_output;
+	gc->get = lnw_gpio_get;
+	gc->set = lnw_gpio_set;
+	gc->to_irq = NULL;
+	gc->base = 0;
+	gc->ngpio = 64;
+	gc->can_sleep = 0;
+	retval = gpiochip_add(gc);
+	if (retval) {
+		dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
+								retval);
+		goto err_ioremap;
+	}
+	platform_set_drvdata(pdev, lnw);
+	return 0;
+err_ioremap:
+	iounmap(lnw->reg_base);
+err_kmalloc:
+	kfree(lnw);
+	return retval;
+}
+
+static int __devexit wp_gpio_remove(struct platform_device *pdev)
+{
+	struct lnw_gpio *lnw = platform_get_drvdata(pdev);
+	int err;
+	err = gpiochip_remove(&lnw->chip);
+	if (err)
+		dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
+	iounmap(lnw->reg_base);
+	kfree(lnw);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver wp_gpio_driver = {
+	.probe		= wp_gpio_probe,
+	.remove		= __devexit_p(wp_gpio_remove),
+	.driver		= {
+		.name	= "wp_gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
 static int __init lnw_gpio_init(void)
 {
-	return pci_register_driver(&lnw_gpio_driver);
+	int ret;
+	ret =  pci_register_driver(&lnw_gpio_driver);
+	if (ret < 0)
+		return ret;
+	ret = platform_driver_register(&wp_gpio_driver);
+	if (ret < 0)
+		pci_unregister_driver(&lnw_gpio_driver);
+	return ret;
 }
 
 device_initcall(lnw_gpio_init);
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/Makefile linux-libre-2.6.37-gnu/drivers/gpio/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpio/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 
 obj-$(CONFIG_GPIO_ADP5520)	+= adp5520-gpio.o
 obj-$(CONFIG_GPIO_ADP5588)	+= adp5588-gpio.o
+obj-$(CONFIG_GPIO_BASIC_MMIO)	+= basic_mmio_gpio.o
 obj-$(CONFIG_GPIO_LANGWELL)	+= langwell_gpio.o
 obj-$(CONFIG_GPIO_MAX730X)	+= max730x.o
 obj-$(CONFIG_GPIO_MAX7300)	+= max7300.o
@@ -17,8 +18,10 @@
 obj-$(CONFIG_GPIO_MAX732X)	+= max732x.o
 obj-$(CONFIG_GPIO_MC33880)	+= mc33880.o
 obj-$(CONFIG_GPIO_MCP23S08)	+= mcp23s08.o
+obj-$(CONFIG_GPIO_74X164)	+= 74x164.o
 obj-$(CONFIG_GPIO_PCA953X)	+= pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)	+= pcf857x.o
+obj-$(CONFIG_GPIO_PCH)		+= pch_gpio.o
 obj-$(CONFIG_GPIO_PL061)	+= pl061.o
 obj-$(CONFIG_GPIO_STMPE)	+= stmpe-gpio.o
 obj-$(CONFIG_GPIO_TC35892)	+= tc35892-gpio.o
@@ -37,3 +40,4 @@
 obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
 obj-$(CONFIG_GPIO_SX150X)	+= sx150x.o
+obj-$(CONFIG_GPIO_VX855)	+= vx855_gpio.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/pca953x.c linux-libre-2.6.37-gnu/drivers/gpio/pca953x.c
--- linux-libre-2.6.36-gnu/drivers/gpio/pca953x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/pca953x.c	2011-01-04 19:50:19.000000000 -0500
@@ -345,7 +345,7 @@
 
 	do {
 		level = __ffs(pending);
-		handle_nested_irq(level + chip->irq_base);
+		generic_handle_irq(level + chip->irq_base);
 
 		pending &= ~(1 << level);
 	} while (pending);
@@ -360,7 +360,8 @@
 	struct pca953x_platform_data *pdata = client->dev.platform_data;
 	int ret;
 
-	if (pdata->irq_base && (id->driver_data & PCA953X_INT)) {
+	if (pdata->irq_base != -1
+			&& (id->driver_data & PCA953X_INT)) {
 		int lvl;
 
 		ret = pca953x_read_reg(chip, PCA953X_INPUT,
@@ -383,7 +384,6 @@
 			set_irq_chip_data(irq, chip);
 			set_irq_chip_and_handler(irq, &pca953x_irq_chip,
 						 handle_edge_irq);
-			set_irq_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
 			set_irq_flags(irq, IRQF_VALID);
 #else
@@ -394,6 +394,7 @@
 		ret = request_threaded_irq(client->irq,
 					   NULL,
 					   pca953x_irq_handler,
+					   IRQF_TRIGGER_RISING |
 					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 					   dev_name(&client->dev), chip);
 		if (ret) {
@@ -408,13 +409,13 @@
 	return 0;
 
 out_failed:
-	chip->irq_base = 0;
+	chip->irq_base = -1;
 	return ret;
 }
 
 static void pca953x_irq_teardown(struct pca953x_chip *chip)
 {
-	if (chip->irq_base)
+	if (chip->irq_base != -1)
 		free_irq(chip->client->irq, chip);
 }
 #else /* CONFIG_GPIO_PCA953X_IRQ */
@@ -424,7 +425,7 @@
 	struct i2c_client *client = chip->client;
 	struct pca953x_platform_data *pdata = client->dev.platform_data;
 
-	if (pdata->irq_base && (id->driver_data & PCA953X_INT))
+	if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
 		dev_warn(&client->dev, "interrupt support not compiled in\n");
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/pch_gpio.c linux-libre-2.6.37-gnu/drivers/gpio/pch_gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/pch_gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpio/pch_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+
+#define PCH_GPIO_ALL_PINS	0xfff /* Mask for GPIO pins 0 to 11 */
+#define GPIO_NUM_PINS	12	/* Specifies number of GPIO PINS GPIO0-GPIO11 */
+
+struct pch_regs {
+	u32	ien;
+	u32	istatus;
+	u32	idisp;
+	u32	iclr;
+	u32	imask;
+	u32	imaskclr;
+	u32	po;
+	u32	pi;
+	u32	pm;
+	u32	im0;
+	u32	im1;
+	u32	reserved[4];
+	u32	reset;
+};
+
+/**
+ * struct pch_gpio_reg_data - The register store data.
+ * @po_reg:	To store contents of PO register.
+ * @pm_reg:	To store contents of PM register.
+ */
+struct pch_gpio_reg_data {
+	u32 po_reg;
+	u32 pm_reg;
+};
+
+/**
+ * struct pch_gpio - GPIO private data structure.
+ * @base:			PCI base address of Memory mapped I/O register.
+ * @reg:			Memory mapped PCH GPIO register list.
+ * @dev:			Pointer to device structure.
+ * @gpio:			Data for GPIO infrastructure.
+ * @pch_gpio_reg:		Memory mapped Register data is saved here
+ *				when suspend.
+ */
+struct pch_gpio {
+	void __iomem *base;
+	struct pch_regs __iomem *reg;
+	struct device *dev;
+	struct gpio_chip gpio;
+	struct pch_gpio_reg_data pch_gpio_reg;
+	struct mutex lock;
+};
+
+static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
+{
+	u32 reg_val;
+	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+
+	mutex_lock(&chip->lock);
+	reg_val = ioread32(&chip->reg->po);
+	if (val)
+		reg_val |= (1 << nr);
+	else
+		reg_val &= ~(1 << nr);
+
+	iowrite32(reg_val, &chip->reg->po);
+	mutex_unlock(&chip->lock);
+}
+
+static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
+{
+	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+
+	return ioread32(&chip->reg->pi) & (1 << nr);
+}
+
+static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
+				     int val)
+{
+	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	u32 pm;
+	u32 reg_val;
+
+	mutex_lock(&chip->lock);
+	pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS;
+	pm |= (1 << nr);
+	iowrite32(pm, &chip->reg->pm);
+
+	reg_val = ioread32(&chip->reg->po);
+	if (val)
+		reg_val |= (1 << nr);
+	else
+		reg_val &= ~(1 << nr);
+
+	mutex_unlock(&chip->lock);
+
+	return 0;
+}
+
+static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
+{
+	struct pch_gpio *chip =	container_of(gpio, struct pch_gpio, gpio);
+	u32 pm;
+
+	mutex_lock(&chip->lock);
+	pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/
+	pm &= ~(1 << nr);
+	iowrite32(pm, &chip->reg->pm);
+	mutex_unlock(&chip->lock);
+
+	return 0;
+}
+
+/*
+ * Save register configuration and disable interrupts.
+ */
+static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
+{
+	chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po);
+	chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm);
+}
+
+/*
+ * This function restores the register configuration of the GPIO device.
+ */
+static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
+{
+	/* to store contents of PO register */
+	iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po);
+	/* to store contents of PM register */
+	iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm);
+}
+
+static void pch_gpio_setup(struct pch_gpio *chip)
+{
+	struct gpio_chip *gpio = &chip->gpio;
+
+	gpio->label = dev_name(chip->dev);
+	gpio->owner = THIS_MODULE;
+	gpio->direction_input = pch_gpio_direction_input;
+	gpio->get = pch_gpio_get;
+	gpio->direction_output = pch_gpio_direction_output;
+	gpio->set = pch_gpio_set;
+	gpio->dbg_show = NULL;
+	gpio->base = -1;
+	gpio->ngpio = GPIO_NUM_PINS;
+	gpio->can_sleep = 0;
+}
+
+static int __devinit pch_gpio_probe(struct pci_dev *pdev,
+				    const struct pci_device_id *id)
+{
+	s32 ret;
+	struct pch_gpio *chip;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	chip->dev = &pdev->dev;
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "%s : pci_enable_device FAILED", __func__);
+		goto err_pci_enable;
+	}
+
+	ret = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (ret) {
+		dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret);
+		goto err_request_regions;
+	}
+
+	chip->base = pci_iomap(pdev, 1, 0);
+	if (chip->base == 0) {
+		dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
+		ret = -ENOMEM;
+		goto err_iomap;
+	}
+
+	chip->reg = chip->base;
+	pci_set_drvdata(pdev, chip);
+	mutex_init(&chip->lock);
+	pch_gpio_setup(chip);
+	ret = gpiochip_add(&chip->gpio);
+	if (ret) {
+		dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n");
+		goto err_gpiochip_add;
+	}
+
+	return 0;
+
+err_gpiochip_add:
+	pci_iounmap(pdev, chip->base);
+
+err_iomap:
+	pci_release_regions(pdev);
+
+err_request_regions:
+	pci_disable_device(pdev);
+
+err_pci_enable:
+	kfree(chip);
+	dev_err(&pdev->dev, "%s Failed returns %d\n", __func__, ret);
+	return ret;
+}
+
+static void __devexit pch_gpio_remove(struct pci_dev *pdev)
+{
+	int err;
+	struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+	err = gpiochip_remove(&chip->gpio);
+	if (err)
+		dev_err(&pdev->dev, "Failed gpiochip_remove\n");
+
+	pci_iounmap(pdev, chip->base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	kfree(chip);
+}
+
+#ifdef CONFIG_PM
+static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	s32 ret;
+	struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+	pch_gpio_save_reg_conf(chip);
+	pch_gpio_restore_reg_conf(chip);
+
+	ret = pci_save_state(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "pci_save_state Failed-%d\n", ret);
+		return ret;
+	}
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D0);
+	ret = pci_enable_wake(pdev, PCI_D0, 1);
+	if (ret)
+		dev_err(&pdev->dev, "pci_enable_wake Failed -%d\n", ret);
+
+	return 0;
+}
+
+static int pch_gpio_resume(struct pci_dev *pdev)
+{
+	s32 ret;
+	struct pch_gpio *chip = pci_get_drvdata(pdev);
+
+	ret = pci_enable_wake(pdev, PCI_D0, 0);
+
+	pci_set_power_state(pdev, PCI_D0);
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "pci_enable_device Failed-%d ", ret);
+		return ret;
+	}
+	pci_restore_state(pdev);
+
+	iowrite32(0x01, &chip->reg->reset);
+	iowrite32(0x00, &chip->reg->reset);
+	pch_gpio_restore_reg_conf(chip);
+
+	return 0;
+}
+#else
+#define pch_gpio_suspend NULL
+#define pch_gpio_resume NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
+	{ 0, }
+};
+
+static struct pci_driver pch_gpio_driver = {
+	.name = "pch_gpio",
+	.id_table = pch_gpio_pcidev_id,
+	.probe = pch_gpio_probe,
+	.remove = __devexit_p(pch_gpio_remove),
+	.suspend = pch_gpio_suspend,
+	.resume = pch_gpio_resume
+};
+
+static int __init pch_gpio_pci_init(void)
+{
+	return pci_register_driver(&pch_gpio_driver);
+}
+module_init(pch_gpio_pci_init);
+
+static void __exit pch_gpio_pci_exit(void)
+{
+	pci_unregister_driver(&pch_gpio_driver);
+}
+module_exit(pch_gpio_pci_exit);
+
+MODULE_DESCRIPTION("PCH GPIO PCI Driver");
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/rdc321x-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/rdc321x-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/rdc321x-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/rdc321x-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -135,7 +135,7 @@
 	struct rdc321x_gpio *rdc321x_gpio_dev;
 	struct rdc321x_gpio_pdata *pdata;
 
-	pdata = pdev->dev.platform_data;
+	pdata = platform_get_drvdata(pdev);
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform data supplied\n");
 		return -ENODEV;
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/stmpe-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/stmpe-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/stmpe-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/stmpe-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,7 @@
 	struct mutex irq_lock;
 
 	int irq_base;
+	unsigned norequest_mask;
 
 	/* Caches of interrupt control registers for bus_lock */
 	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -103,6 +104,9 @@
 	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
 	struct stmpe *stmpe = stmpe_gpio->stmpe;
 
+	if (stmpe_gpio->norequest_mask & (1 << offset))
+		return -EINVAL;
+
 	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
 }
 
@@ -287,8 +291,6 @@
 	int irq;
 
 	pdata = stmpe->pdata->gpio;
-	if (!pdata)
-		return -ENODEV;
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0)
@@ -302,6 +304,7 @@
 
 	stmpe_gpio->dev = &pdev->dev;
 	stmpe_gpio->stmpe = stmpe;
+	stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
 
 	stmpe_gpio->chip = template_chip;
 	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
@@ -312,11 +315,11 @@
 
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
 	if (ret)
-		return ret;
+		goto out_free;
 
 	ret = stmpe_gpio_irq_init(stmpe_gpio);
 	if (ret)
-		goto out_free;
+		goto out_disable;
 
 	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
 				   "stmpe-gpio", stmpe_gpio);
@@ -342,6 +345,8 @@
 	free_irq(irq, stmpe_gpio);
 out_removeirq:
 	stmpe_gpio_irq_remove(stmpe_gpio);
+out_disable:
+	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
 out_free:
 	kfree(stmpe_gpio);
 	return ret;
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/tc35892-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/tc35892-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/tc35892-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/tc35892-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -322,6 +322,9 @@
 		goto out_freeirq;
 	}
 
+	if (pdata->setup)
+		pdata->setup(tc35892, tc35892_gpio->chip.base);
+
 	platform_set_drvdata(pdev, tc35892_gpio);
 
 	return 0;
@@ -338,9 +341,14 @@
 static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
 {
 	struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
+	struct tc35892 *tc35892 = tc35892_gpio->tc35892;
+	struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
 	int irq = platform_get_irq(pdev, 0);
 	int ret;
 
+	if (pdata->remove)
+		pdata->remove(tc35892, tc35892_gpio->chip.base);
+
 	ret = gpiochip_remove(&tc35892_gpio->chip);
 	if (ret < 0) {
 		dev_err(tc35892_gpio->dev,
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/timbgpio.c linux-libre-2.6.37-gnu/drivers/gpio/timbgpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/timbgpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/timbgpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,6 +47,7 @@
 	spinlock_t		lock; /* mutual exclusion */
 	struct gpio_chip	gpio;
 	int			irq_base;
+	unsigned long		last_ier;
 };
 
 static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
@@ -112,16 +113,24 @@
 {
 	struct timbgpio *tgpio = get_irq_chip_data(irq);
 	int offset = irq - tgpio->irq_base;
+	unsigned long flags;
 
-	timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0);
+	spin_lock_irqsave(&tgpio->lock, flags);
+	tgpio->last_ier &= ~(1 << offset);
+	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
+	spin_unlock_irqrestore(&tgpio->lock, flags);
 }
 
 static void timbgpio_irq_enable(unsigned irq)
 {
 	struct timbgpio *tgpio = get_irq_chip_data(irq);
 	int offset = irq - tgpio->irq_base;
+	unsigned long flags;
 
-	timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1);
+	spin_lock_irqsave(&tgpio->lock, flags);
+	tgpio->last_ier |= 1 << offset;
+	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
+	spin_unlock_irqrestore(&tgpio->lock, flags);
 }
 
 static int timbgpio_irq_type(unsigned irq, unsigned trigger)
@@ -194,8 +203,16 @@
 	ipr = ioread32(tgpio->membase + TGPIO_IPR);
 	iowrite32(ipr, tgpio->membase + TGPIO_ICR);
 
+	/*
+	 * Some versions of the hardware trash the IER register if more than
+	 * one interrupt is received simultaneously.
+	 */
+	iowrite32(0, tgpio->membase + TGPIO_IER);
+
 	for_each_set_bit(offset, &ipr, tgpio->gpio.ngpio)
 		generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
+
+	iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
 }
 
 static struct irq_chip timbgpio_irqchip = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/vx855_gpio.c linux-libre-2.6.37-gnu/drivers/gpio/vx855_gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/vx855_gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpio/vx855_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,332 @@
+/*
+ * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
+ *
+ * Copyright (C) 2009 VIA Technologies, Inc.
+ * Copyright (C) 2010 One Laptop per Child
+ * Author: Harald Welte <HaraldWelte@viatech.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#define MODULE_NAME "vx855_gpio"
+
+/* The VX855 south bridge has the following GPIO pins:
+ *	GPI 0...13	General Purpose Input
+ *	GPO 0...12	General Purpose Output
+ *	GPIO 0...14	General Purpose I/O (Open-Drain)
+ */
+
+#define NR_VX855_GPI	14
+#define NR_VX855_GPO	13
+#define NR_VX855_GPIO	15
+
+#define NR_VX855_GPInO	(NR_VX855_GPI + NR_VX855_GPO)
+#define NR_VX855_GP	(NR_VX855_GPI + NR_VX855_GPO + NR_VX855_GPIO)
+
+struct vx855_gpio {
+	struct gpio_chip gpio;
+	spinlock_t lock;
+	u32 io_gpi;
+	u32 io_gpo;
+	bool gpi_reserved;
+	bool gpo_reserved;
+};
+
+/* resolve a GPIx into the corresponding bit position */
+static inline u_int32_t gpi_i_bit(int i)
+{
+	if (i < 10)
+		return 1 << i;
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpo_o_bit(int i)
+{
+	if (i < 11)
+		return 1 << i;
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_i_bit(int i)
+{
+	if (i < 14)
+		return 1 << (i + 10);
+	else
+		return 1 << (i + 14);
+}
+
+static inline u_int32_t gpio_o_bit(int i)
+{
+	if (i < 14)
+		return 1 << (i + 11);
+	else
+		return 1 << (i + 13);
+}
+
+/* Mapping betwee numeric GPIO ID and the actual GPIO hardware numbering:
+ * 0..13	GPI 0..13
+ * 14..26	GPO 0..12
+ * 27..41	GPIO 0..14
+ */
+
+static int vx855gpio_direction_input(struct gpio_chip *gpio,
+				     unsigned int nr)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	unsigned long flags;
+	u_int32_t reg_out;
+
+	/* Real GPI bits are always in input direction */
+	if (nr < NR_VX855_GPI)
+		return 0;
+
+	/* Real GPO bits cannot be put in output direction */
+	if (nr < NR_VX855_GPInO)
+		return -EINVAL;
+
+	/* Open Drain GPIO have to be set to one */
+	spin_lock_irqsave(&vg->lock, flags);
+	reg_out = inl(vg->io_gpo);
+	reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+	outl(reg_out, vg->io_gpo);
+	spin_unlock_irqrestore(&vg->lock, flags);
+
+	return 0;
+}
+
+static int vx855gpio_get(struct gpio_chip *gpio, unsigned int nr)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	u_int32_t reg_in;
+	int ret = 0;
+
+	if (nr < NR_VX855_GPI) {
+		reg_in = inl(vg->io_gpi);
+		if (reg_in & gpi_i_bit(nr))
+			ret = 1;
+	} else if (nr < NR_VX855_GPInO) {
+		/* GPO don't have an input bit, we need to read it
+		 * back from the output register */
+		reg_in = inl(vg->io_gpo);
+		if (reg_in & gpo_o_bit(nr - NR_VX855_GPI))
+			ret = 1;
+	} else {
+		reg_in = inl(vg->io_gpi);
+		if (reg_in & gpio_i_bit(nr - NR_VX855_GPInO))
+			ret = 1;
+	}
+
+	return ret;
+}
+
+static void vx855gpio_set(struct gpio_chip *gpio, unsigned int nr,
+			  int val)
+{
+	struct vx855_gpio *vg = container_of(gpio, struct vx855_gpio, gpio);
+	unsigned long flags;
+	u_int32_t reg_out;
+
+	/* True GPI cannot be switched to output mode */
+	if (nr < NR_VX855_GPI)
+		return;
+
+	spin_lock_irqsave(&vg->lock, flags);
+	reg_out = inl(vg->io_gpo);
+	if (nr < NR_VX855_GPInO) {
+		if (val)
+			reg_out |= gpo_o_bit(nr - NR_VX855_GPI);
+		else
+			reg_out &= ~gpo_o_bit(nr - NR_VX855_GPI);
+	} else {
+		if (val)
+			reg_out |= gpio_o_bit(nr - NR_VX855_GPInO);
+		else
+			reg_out &= ~gpio_o_bit(nr - NR_VX855_GPInO);
+	}
+	outl(reg_out, vg->io_gpo);
+	spin_unlock_irqrestore(&vg->lock, flags);
+}
+
+static int vx855gpio_direction_output(struct gpio_chip *gpio,
+				      unsigned int nr, int val)
+{
+	/* True GPI cannot be switched to output mode */
+	if (nr < NR_VX855_GPI)
+		return -EINVAL;
+
+	/* True GPO don't need to be switched to output mode,
+	 * and GPIO are open-drain, i.e. also need no switching,
+	 * so all we do is set the level */
+	vx855gpio_set(gpio, nr, val);
+
+	return 0;
+}
+
+static const char *vx855gpio_names[NR_VX855_GP] = {
+	"VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4",
+	"VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9",
+	"VX855_GPI10", "VX855_GPI11", "VX855_GPI12", "VX855_GPI13",
+	"VX855_GPO0", "VX855_GPO1", "VX855_GPO2", "VX855_GPO3", "VX855_GPO4",
+	"VX855_GPO5", "VX855_GPO6", "VX855_GPO7", "VX855_GPO8", "VX855_GPO9",
+	"VX855_GPO10", "VX855_GPO11", "VX855_GPO12",
+	"VX855_GPIO0", "VX855_GPIO1", "VX855_GPIO2", "VX855_GPIO3",
+	"VX855_GPIO4", "VX855_GPIO5", "VX855_GPIO6", "VX855_GPIO7",
+	"VX855_GPIO8", "VX855_GPIO9", "VX855_GPIO10", "VX855_GPIO11",
+	"VX855_GPIO12", "VX855_GPIO13", "VX855_GPIO14"
+};
+
+static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
+{
+	struct gpio_chip *c = &vg->gpio;
+
+	c->label = "VX855 South Bridge";
+	c->owner = THIS_MODULE;
+	c->direction_input = vx855gpio_direction_input;
+	c->direction_output = vx855gpio_direction_output;
+	c->get = vx855gpio_get;
+	c->set = vx855gpio_set;
+	c->dbg_show = NULL;
+	c->base = 0;
+	c->ngpio = NR_VX855_GP;
+	c->can_sleep = 0;
+	c->names = vx855gpio_names;
+}
+
+/* This platform device is ordinarily registered by the vx855 mfd driver */
+static __devinit int vx855gpio_probe(struct platform_device *pdev)
+{
+	struct resource *res_gpi;
+	struct resource *res_gpo;
+	struct vx855_gpio *vg;
+	int ret;
+
+	res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1);
+	if (!res_gpi || !res_gpo)
+		return -EBUSY;
+
+	vg = kzalloc(sizeof(*vg), GFP_KERNEL);
+	if (!vg)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, vg);
+
+	dev_info(&pdev->dev, "found VX855 GPIO controller\n");
+	vg->io_gpi = res_gpi->start;
+	vg->io_gpo = res_gpo->start;
+	spin_lock_init(&vg->lock);
+
+	/*
+	 * A single byte is used to control various GPIO ports on the VX855,
+	 * and in the case of the OLPC XO-1.5, some of those ports are used
+	 * for switches that are interpreted and exposed through ACPI. ACPI
+	 * will have reserved the region, so our own reservation will not
+	 * succeed. Ignore and continue.
+	 */
+
+	if (!request_region(res_gpi->start, resource_size(res_gpi),
+			MODULE_NAME "_gpi"))
+		dev_warn(&pdev->dev,
+			"GPI I/O resource busy, probably claimed by ACPI\n");
+	else
+		vg->gpi_reserved = true;
+
+	if (!request_region(res_gpo->start, resource_size(res_gpo),
+			MODULE_NAME "_gpo"))
+		dev_warn(&pdev->dev,
+			"GPO I/O resource busy, probably claimed by ACPI\n");
+	else
+		vg->gpo_reserved = true;
+
+	vx855gpio_gpio_setup(vg);
+
+	ret = gpiochip_add(&vg->gpio);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register GPIOs\n");
+		goto out_release;
+	}
+
+	return 0;
+
+out_release:
+	if (vg->gpi_reserved)
+		release_region(res_gpi->start, resource_size(res_gpi));
+	if (vg->gpo_reserved)
+		release_region(res_gpi->start, resource_size(res_gpo));
+	platform_set_drvdata(pdev, NULL);
+	kfree(vg);
+	return ret;
+}
+
+static int __devexit vx855gpio_remove(struct platform_device *pdev)
+{
+	struct vx855_gpio *vg = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	if (gpiochip_remove(&vg->gpio))
+		dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
+
+	if (vg->gpi_reserved) {
+		res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+		release_region(res->start, resource_size(res));
+	}
+	if (vg->gpo_reserved) {
+		res = platform_get_resource(pdev, IORESOURCE_IO, 1);
+		release_region(res->start, resource_size(res));
+	}
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(vg);
+	return 0;
+}
+
+static struct platform_driver vx855gpio_driver = {
+	.driver = {
+		.name	= MODULE_NAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= vx855gpio_probe,
+	.remove		= __devexit_p(vx855gpio_remove),
+};
+
+static int vx855gpio_init(void)
+{
+	return platform_driver_register(&vx855gpio_driver);
+}
+module_init(vx855gpio_init);
+
+static void vx855gpio_exit(void)
+{
+	platform_driver_unregister(&vx855gpio_driver);
+}
+module_exit(vx855gpio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <HaraldWelte@viatech.com>");
+MODULE_DESCRIPTION("GPIO driver for the VIA VX855 chipset");
+MODULE_ALIAS("platform:vx855_gpio");
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/wm8994-gpio.c linux-libre-2.6.37-gnu/drivers/gpio/wm8994-gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/wm8994-gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/wm8994-gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -140,6 +140,7 @@
 	.get			= wm8994_gpio_get,
 	.direction_output	= wm8994_gpio_direction_out,
 	.set			= wm8994_gpio_set,
+	.to_irq			= wm8994_gpio_to_irq,
 	.dbg_show		= wm8994_gpio_dbg_show,
 	.can_sleep		= 1,
 };
diff -druN linux-libre-2.6.36-gnu/drivers/gpio/xilinx_gpio.c linux-libre-2.6.37-gnu/drivers/gpio/xilinx_gpio.c
--- linux-libre-2.6.36-gnu/drivers/gpio/xilinx_gpio.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpio/xilinx_gpio.c	2011-01-04 19:50:19.000000000 -0500
@@ -171,13 +171,13 @@
 	/* Update GPIO state shadow register with default value */
 	tree_info = of_get_property(np, "xlnx,dout-default", NULL);
 	if (tree_info)
-		chip->gpio_state = *tree_info;
+		chip->gpio_state = be32_to_cpup(tree_info);
 
 	/* Update GPIO direction shadow register with default value */
 	chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
 	tree_info = of_get_property(np, "xlnx,tri-default", NULL);
 	if (tree_info)
-		chip->gpio_dir = *tree_info;
+		chip->gpio_dir = be32_to_cpup(tree_info);
 
 	/* Check device node and parent device node for device width */
 	chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
@@ -186,7 +186,7 @@
 		tree_info = of_get_property(np->parent,
 					    "xlnx,gpio-width", NULL);
 	if (tree_info)
-		chip->mmchip.gc.ngpio = *tree_info;
+		chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
 
 	spin_lock_init(&chip->gpio_lock);
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_agpsupport.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_agpsupport.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_agpsupport.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_agpsupport.c	2011-01-04 19:50:19.000000000 -0500
@@ -193,7 +193,7 @@
  * \return zero on success or a negative number on failure.
  *
  * Verifies the AGP device is present and has been acquired, allocates the
- * memory via alloc_agp() and creates a drm_agp_mem entry for it.
+ * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it.
  */
 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
 {
@@ -211,7 +211,7 @@
 
 	pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
 	type = (u32) request->type;
-	if (!(memory = drm_alloc_agp(dev, pages, type))) {
+	if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) {
 		kfree(entry);
 		return -ENOMEM;
 	}
@@ -423,38 +423,6 @@
 	return head;
 }
 
-/** Calls agp_allocate_memory() */
-DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data * bridge,
-				     size_t pages, u32 type)
-{
-	return agp_allocate_memory(bridge, pages, type);
-}
-
-/** Calls agp_free_memory() */
-int drm_agp_free_memory(DRM_AGP_MEM * handle)
-{
-	if (!handle)
-		return 0;
-	agp_free_memory(handle);
-	return 1;
-}
-
-/** Calls agp_bind_memory() */
-int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
-{
-	if (!handle)
-		return -EINVAL;
-	return agp_bind_memory(handle, start);
-}
-
-/** Calls agp_unbind_memory() */
-int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
-{
-	if (!handle)
-		return -EINVAL;
-	return agp_unbind_memory(handle);
-}
-
 /**
  * Binds a collection of pages into AGP memory at the given offset, returning
  * the AGP memory structure containing them.
@@ -474,7 +442,7 @@
 
 	DRM_DEBUG("\n");
 
-	mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
+	mem = agp_allocate_memory(dev->agp->bridge, num_pages,
 				      type);
 	if (mem == NULL) {
 		DRM_ERROR("Failed to allocate memory for %ld pages\n",
@@ -487,7 +455,7 @@
 	mem->page_count = num_pages;
 
 	mem->is_flushed = true;
-	ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
+	ret = agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
 	if (ret != 0) {
 		DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
 		agp_free_memory(mem);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_context.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_context.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_context.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_context.c	2011-01-04 19:50:19.000000000 -0500
@@ -333,14 +333,6 @@
 		return -ENOMEM;
 	}
 
-	if (ctx->handle != DRM_KERNEL_CONTEXT) {
-		if (dev->driver->context_ctor)
-			if (!dev->driver->context_ctor(dev, ctx->handle)) {
-				DRM_DEBUG("Running out of ctxs or memory.\n");
-				return -ENOMEM;
-			}
-	}
-
 	ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
 	if (!ctx_entry) {
 		DRM_DEBUG("out of memory\n");
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_crtc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_crtc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_crtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_crtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -156,12 +156,12 @@
 	{ DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO", 0 },
 	{ DRM_MODE_CONNECTOR_LVDS, "LVDS", 0 },
 	{ DRM_MODE_CONNECTOR_Component, "Component", 0 },
-	{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN", 0 },
-	{ DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort", 0 },
-	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A", 0 },
-	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B", 0 },
+	{ DRM_MODE_CONNECTOR_9PinDIN, "DIN", 0 },
+	{ DRM_MODE_CONNECTOR_DisplayPort, "DP", 0 },
+	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A", 0 },
+	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 },
 	{ DRM_MODE_CONNECTOR_TV, "TV", 0 },
-	{ DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort", 0 },
+	{ DRM_MODE_CONNECTOR_eDP, "eDP", 0 },
 };
 
 static struct drm_prop_enum_list drm_encoder_enum_list[] =
@@ -1854,7 +1854,8 @@
 	}
 
 	if (fb->funcs->dirty) {
-		ret = fb->funcs->dirty(fb, flags, r->color, clips, num_clips);
+		ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
+				       clips, num_clips);
 	} else {
 		ret = -ENOSYS;
 		goto out_err2;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_crtc_helper.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_crtc_helper.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_crtc_helper.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_crtc_helper.c	2011-01-04 19:50:19.000000000 -0500
@@ -276,7 +276,7 @@
 	struct drm_crtc *tmp;
 	int crtc_mask = 1;
 
-	WARN(!crtc, "checking null crtc?");
+	WARN(!crtc, "checking null crtc?\n");
 
 	dev = crtc->dev;
 
@@ -471,6 +471,7 @@
 	int count = 0, ro, fail = 0;
 	struct drm_crtc_helper_funcs *crtc_funcs;
 	int ret = 0;
+	int i;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -666,6 +667,12 @@
 		if (ret != 0)
 			goto fail;
 	}
+	DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+	for (i = 0; i < set->num_connectors; i++) {
+		DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+			      drm_get_connector_name(set->connectors[i]));
+		set->connectors[i]->dpms = DRM_MODE_DPMS_ON;
+	}
 
 	kfree(save_connectors);
 	kfree(save_encoders);
@@ -841,7 +848,7 @@
 	struct delayed_work *delayed_work = to_delayed_work(work);
 	struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
 	struct drm_connector *connector;
-	enum drm_connector_status old_status, status;
+	enum drm_connector_status old_status;
 	bool repoll = false, changed = false;
 
 	if (!drm_kms_helper_poll)
@@ -866,8 +873,12 @@
 		    !(connector->polled & DRM_CONNECTOR_POLL_HPD))
 			continue;
 
-		status = connector->funcs->detect(connector, false);
-		if (old_status != status)
+		connector->status = connector->funcs->detect(connector, false);
+		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+			      connector->base.id,
+			      drm_get_connector_name(connector),
+			      old_status, connector->status);
+		if (old_status != connector->status)
 			changed = true;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_debugfs.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_debugfs.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,7 +48,6 @@
 	{"queues", drm_queues_info, 0},
 	{"bufs", drm_bufs_info, 0},
 	{"gem_names", drm_gem_name_info, DRIVER_GEM},
-	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
 	{"vma", drm_vma_info, 0},
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_drawable.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_drawable.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_drawable.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_drawable.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,198 +0,0 @@
-/**
- * \file drm_drawable.c
- * IOCTLs for drawables
- *
- * \author Rickard E. (Rik) Faith <faith@valinux.com>
- * \author Gareth Hughes <gareth@valinux.com>
- * \author Michel DÃ¤nzer <michel@tungstengraphics.com>
- */
-
-/*
- * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
- *
- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
- * All Rights Reserved.
- *
- * 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 (including the next
- * paragraph) 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
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS 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.
- */
-
-#include "drmP.h"
-
-/**
- * Allocate drawable ID and memory to store information about it.
- */
-int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-	unsigned long irqflags;
-	struct drm_draw *draw = data;
-	int new_id = 0;
-	int ret;
-
-again:
-	if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
-		DRM_ERROR("Out of memory expanding drawable idr\n");
-		return -ENOMEM;
-	}
-
-	spin_lock_irqsave(&dev->drw_lock, irqflags);
-	ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
-	if (ret == -EAGAIN) {
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-		goto again;
-	}
-
-	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
-	draw->handle = new_id;
-
-	DRM_DEBUG("%d\n", draw->handle);
-
-	return 0;
-}
-
-/**
- * Free drawable ID and memory to store information about it.
- */
-int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-	struct drm_draw *draw = data;
-	unsigned long irqflags;
-	struct drm_drawable_info *info;
-
-	spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-	info = drm_get_drawable_info(dev, draw->handle);
-	if (info == NULL) {
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-		return -EINVAL;
-	}
-	kfree(info->rects);
-	kfree(info);
-
-	idr_remove(&dev->drw_idr, draw->handle);
-
-	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-	DRM_DEBUG("%d\n", draw->handle);
-	return 0;
-}
-
-int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
-{
-	struct drm_update_draw *update = data;
-	unsigned long irqflags;
-	struct drm_clip_rect *rects;
-	struct drm_drawable_info *info;
-	int err;
-
-	info = idr_find(&dev->drw_idr, update->handle);
-	if (!info) {
-		info = kzalloc(sizeof(*info), GFP_KERNEL);
-		if (!info)
-			return -ENOMEM;
-		if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
-			DRM_ERROR("No such drawable %d\n", update->handle);
-			kfree(info);
-			return -EINVAL;
-		}
-	}
-
-	switch (update->type) {
-	case DRM_DRAWABLE_CLIPRECTS:
-		if (update->num == 0)
-			rects = NULL;
-		else if (update->num != info->num_rects) {
-			rects = kmalloc(update->num *
-					sizeof(struct drm_clip_rect),
-					GFP_KERNEL);
-		} else
-			rects = info->rects;
-
-		if (update->num && !rects) {
-			DRM_ERROR("Failed to allocate cliprect memory\n");
-			err = -ENOMEM;
-			goto error;
-		}
-
-		if (update->num && DRM_COPY_FROM_USER(rects,
-						     (struct drm_clip_rect __user *)
-						     (unsigned long)update->data,
-						     update->num *
-						     sizeof(*rects))) {
-			DRM_ERROR("Failed to copy cliprects from userspace\n");
-			err = -EFAULT;
-			goto error;
-		}
-
-		spin_lock_irqsave(&dev->drw_lock, irqflags);
-
-		if (rects != info->rects) {
-			kfree(info->rects);
-		}
-
-		info->rects = rects;
-		info->num_rects = update->num;
-
-		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
-		DRM_DEBUG("Updated %d cliprects for drawable %d\n",
-			  info->num_rects, update->handle);
-		break;
-	default:
-		DRM_ERROR("Invalid update type %d\n", update->type);
-		return -EINVAL;
-	}
-
-	return 0;
-
-error:
-	if (rects != info->rects)
-		kfree(rects);
-
-	return err;
-}
-
-/**
- * Caller must hold the drawable spinlock!
- */
-struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
-{
-	return idr_find(&dev->drw_idr, id);
-}
-EXPORT_SYMBOL(drm_get_drawable_info);
-
-static int drm_drawable_free(int idr, void *p, void *data)
-{
-	struct drm_drawable_info *info = p;
-
-	if (info) {
-		kfree(info->rects);
-		kfree(info);
-	}
-
-	return 0;
-}
-
-void drm_drawable_free_all(struct drm_device *dev)
-{
-	idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
-	idr_remove_all(&dev->drw_idr);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,8 +91,8 @@
 	DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
 
-	DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-	DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
 	DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
 	DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
@@ -127,7 +127,7 @@
 
 	DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
 
-	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
 	DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED),
@@ -180,10 +180,6 @@
 
 	mutex_lock(&dev->struct_mutex);
 
-	/* Free drawable information memory */
-	drm_drawable_free_all(dev);
-	del_timer(&dev->timer);
-
 	/* Clear AGP information */
 	if (drm_core_has_AGP(dev) && dev->agp &&
 			!drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -284,7 +280,8 @@
 /** File operations structure */
 static const struct file_operations drm_stub_fops = {
 	.owner = THIS_MODULE,
-	.open = drm_stub_open
+	.open = drm_stub_open,
+	.llseek = noop_llseek,
 };
 
 static int __init drm_core_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_edid.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_edid.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_edid.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_edid.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
@@ -241,7 +240,7 @@
 			.addr	= DDC_ADDR,
 			.flags	= I2C_M_RD,
 			.len	= len,
-			.buf	= buf + start,
+			.buf	= buf,
 		}
 	};
 
@@ -254,7 +253,7 @@
 static u8 *
 drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
 {
-	int i, j = 0;
+	int i, j = 0, valid_extensions = 0;
 	u8 *block, *new;
 
 	if ((block = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
@@ -281,14 +280,28 @@
 
 	for (j = 1; j <= block[0x7e]; j++) {
 		for (i = 0; i < 4; i++) {
-			if (drm_do_probe_ddc_edid(adapter, block, j,
-						  EDID_LENGTH))
+			if (drm_do_probe_ddc_edid(adapter,
+				  block + (valid_extensions + 1) * EDID_LENGTH,
+				  j, EDID_LENGTH))
 				goto out;
-			if (drm_edid_block_valid(block + j * EDID_LENGTH))
+			if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
+				valid_extensions++;
 				break;
+			}
 		}
 		if (i == 4)
-			goto carp;
+			dev_warn(connector->dev->dev,
+			 "%s: Ignoring invalid EDID block %d.\n",
+			 drm_get_connector_name(connector), j);
+	}
+
+	if (valid_extensions != block[0x7e]) {
+		block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
+		block[0x7e] = valid_extensions;
+		new = krealloc(block, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+		if (!new)
+			goto out;
+		block = new;
 	}
 
 	return block;
@@ -1268,34 +1281,51 @@
 }
 
 #define HDMI_IDENTIFIER 0x000C03
+#define AUDIO_BLOCK	0x01
 #define VENDOR_BLOCK    0x03
+#define EDID_BASIC_AUDIO	(1 << 6)
+
 /**
- * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
- * @edid: monitor EDID information
- *
- * Parse the CEA extension according to CEA-861-B.
- * Return true if HDMI, false if not or unknown.
+ * Search EDID for CEA extension block.
  */
-bool drm_detect_hdmi_monitor(struct edid *edid)
+static u8 *drm_find_cea_extension(struct edid *edid)
 {
-	char *edid_ext = NULL;
-	int i, hdmi_id;
-	int start_offset, end_offset;
-	bool is_hdmi = false;
+	u8 *edid_ext = NULL;
+	int i;
 
 	/* No EDID or EDID extensions */
 	if (edid == NULL || edid->extensions == 0)
-		goto end;
+		return NULL;
 
 	/* Find CEA extension */
 	for (i = 0; i < edid->extensions; i++) {
-		edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
-		/* This block is CEA extension */
-		if (edid_ext[0] == 0x02)
+		edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+		if (edid_ext[0] == CEA_EXT)
 			break;
 	}
 
 	if (i == edid->extensions)
+		return NULL;
+
+	return edid_ext;
+}
+
+/**
+ * drm_detect_hdmi_monitor - detect whether monitor is hdmi.
+ * @edid: monitor EDID information
+ *
+ * Parse the CEA extension according to CEA-861-B.
+ * Return true if HDMI, false if not or unknown.
+ */
+bool drm_detect_hdmi_monitor(struct edid *edid)
+{
+	u8 *edid_ext;
+	int i, hdmi_id;
+	int start_offset, end_offset;
+	bool is_hdmi = false;
+
+	edid_ext = drm_find_cea_extension(edid);
+	if (!edid_ext)
 		goto end;
 
 	/* Data block offset in CEA extension block */
@@ -1326,6 +1356,53 @@
 EXPORT_SYMBOL(drm_detect_hdmi_monitor);
 
 /**
+ * drm_detect_monitor_audio - check monitor audio capability
+ *
+ * Monitor should have CEA extension block.
+ * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
+ * audio' only. If there is any audio extension block and supported
+ * audio format, assume at least 'basic audio' support, even if 'basic
+ * audio' is not defined in EDID.
+ *
+ */
+bool drm_detect_monitor_audio(struct edid *edid)
+{
+	u8 *edid_ext;
+	int i, j;
+	bool has_audio = false;
+	int start_offset, end_offset;
+
+	edid_ext = drm_find_cea_extension(edid);
+	if (!edid_ext)
+		goto end;
+
+	has_audio = ((edid_ext[3] & EDID_BASIC_AUDIO) != 0);
+
+	if (has_audio) {
+		DRM_DEBUG_KMS("Monitor has basic audio support\n");
+		goto end;
+	}
+
+	/* Data block offset in CEA extension block */
+	start_offset = 4;
+	end_offset = edid_ext[2];
+
+	for (i = start_offset; i < end_offset;
+			i += ((edid_ext[i] & 0x1f) + 1)) {
+		if ((edid_ext[i] >> 5) == AUDIO_BLOCK) {
+			has_audio = true;
+			for (j = 1; j < (edid_ext[i] & 0x1f); j += 3)
+				DRM_DEBUG_KMS("CEA audio format %d\n",
+					      (edid_ext[i + j] >> 3) & 0xf);
+			goto end;
+		}
+	}
+end:
+	return has_audio;
+}
+EXPORT_SYMBOL(drm_detect_monitor_audio);
+
+/**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
  * @edid: edid data
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_fb_helper.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_fb_helper.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_fb_helper.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_fb_helper.c	2011-01-04 19:50:19.000000000 -0500
@@ -242,6 +242,30 @@
 	return 0;
 }
 
+static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
+{
+	uint16_t *r_base, *g_base, *b_base;
+	int i;
+
+	r_base = crtc->gamma_store;
+	g_base = r_base + crtc->gamma_size;
+	b_base = g_base + crtc->gamma_size;
+
+	for (i = 0; i < crtc->gamma_size; i++)
+		helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
+}
+
+static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
+{
+	uint16_t *r_base, *g_base, *b_base;
+
+	r_base = crtc->gamma_store;
+	g_base = r_base + crtc->gamma_size;
+	b_base = g_base + crtc->gamma_size;
+
+	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
+}
+
 int drm_fb_helper_debug_enter(struct fb_info *info)
 {
 	struct drm_fb_helper *helper = info->par;
@@ -260,11 +284,12 @@
 				continue;
 
 			funcs =	mode_set->crtc->helper_private;
+			drm_fb_helper_save_lut_atomic(mode_set->crtc, helper);
 			funcs->mode_set_base_atomic(mode_set->crtc,
 						    mode_set->fb,
 						    mode_set->x,
-						    mode_set->y);
-
+						    mode_set->y,
+						    ENTER_ATOMIC_MODE_SET);
 		}
 	}
 
@@ -308,8 +333,9 @@
 			continue;
 		}
 
+		drm_fb_helper_restore_lut_atomic(mode_set->crtc);
 		funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x,
-					    crtc->y);
+					    crtc->y, LEAVE_ATOMIC_MODE_SET);
 	}
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_fops.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_fops.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_fops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_fops.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,7 +37,6 @@
 #include "drmP.h"
 #include <linux/poll.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 
 /* from BKL pushdown: note that nothing else serializes idr_find() */
 DEFINE_MUTEX(drm_global_mutex);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_gem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_gem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_gem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_gem.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,12 +92,6 @@
 
 	spin_lock_init(&dev->object_name_lock);
 	idr_init(&dev->object_name_idr);
-	atomic_set(&dev->object_count, 0);
-	atomic_set(&dev->object_memory, 0);
-	atomic_set(&dev->pin_count, 0);
-	atomic_set(&dev->pin_memory, 0);
-	atomic_set(&dev->gtt_count, 0);
-	atomic_set(&dev->gtt_memory, 0);
 
 	mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
 	if (!mm) {
@@ -151,9 +145,6 @@
 	atomic_set(&obj->handle_count, 0);
 	obj->size = size;
 
-	atomic_inc(&dev->object_count);
-	atomic_add(obj->size, &dev->object_memory);
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_gem_object_init);
@@ -180,8 +171,6 @@
 	return obj;
 fput:
 	/* Object_init mangles the global counters - readjust them. */
-	atomic_dec(&dev->object_count);
-	atomic_sub(obj->size, &dev->object_memory);
 	fput(obj->filp);
 free:
 	kfree(obj);
@@ -436,10 +425,7 @@
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
-	struct drm_device *dev = obj->dev;
 	fput(obj->filp);
-	atomic_dec(&dev->object_count);
-	atomic_sub(obj->size, &dev->object_memory);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_info.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_info.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_info.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_info.c	2011-01-04 19:50:19.000000000 -0500
@@ -270,20 +270,6 @@
 	return 0;
 }
 
-int drm_gem_object_info(struct seq_file *m, void* data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-
-	seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
-	seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
-	seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
-	seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
-	seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
-	seq_printf(m, "%d gtt total\n", dev->gtt_total);
-	return 0;
-}
-
 #if DRM_DEBUG_CODE
 
 int drm_vma_info(struct seq_file *m, void *data)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_irq.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_irq.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -585,10 +585,13 @@
 	struct timeval now;
 	unsigned long flags;
 	unsigned int seq;
+	int ret;
 
 	e = kzalloc(sizeof *e, GFP_KERNEL);
-	if (e == NULL)
-		return -ENOMEM;
+	if (e == NULL) {
+		ret = -ENOMEM;
+		goto err_put;
+	}
 
 	e->pipe = pipe;
 	e->base.pid = current->pid;
@@ -603,9 +606,8 @@
 	spin_lock_irqsave(&dev->event_lock, flags);
 
 	if (file_priv->event_space < sizeof e->event) {
-		spin_unlock_irqrestore(&dev->event_lock, flags);
-		kfree(e);
-		return -ENOMEM;
+		ret = -EBUSY;
+		goto err_unlock;
 	}
 
 	file_priv->event_space -= sizeof e->event;
@@ -626,7 +628,7 @@
 	if ((seq - vblwait->request.sequence) <= (1 << 23)) {
 		e->event.tv_sec = now.tv_sec;
 		e->event.tv_usec = now.tv_usec;
-		drm_vblank_put(dev, e->pipe);
+		drm_vblank_put(dev, pipe);
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 		trace_drm_vblank_event_delivered(current->pid, pipe,
@@ -638,6 +640,13 @@
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
 	return 0;
+
+err_unlock:
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+	kfree(e);
+err_put:
+	drm_vblank_put(dev, pipe);
+	return ret;
 }
 
 /**
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_lock.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_lock.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_lock.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_lock.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,6 +37,8 @@
 
 static int drm_notifier(void *priv);
 
+static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
+
 /**
  * Lock ioctl.
  *
@@ -124,9 +126,6 @@
 		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
 	}
 
-	if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
-		dev->driver->dma_ready(dev);
-
 	if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
 	{
 		if (dev->driver->dma_quiescent(dev)) {
@@ -136,12 +135,6 @@
 		}
 	}
 
-	if (dev->driver->kernel_context_switch &&
-	    dev->last_context != lock->context) {
-		dev->driver->kernel_context_switch(dev, dev->last_context,
-						   lock->context);
-	}
-
 	return 0;
 }
 
@@ -169,15 +162,8 @@
 
 	atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
-	/* kernel_context_switch isn't used by any of the x86 drm
-	 * modules but is required by the Sparc driver.
-	 */
-	if (dev->driver->kernel_context_switch_unlock)
-		dev->driver->kernel_context_switch_unlock(dev);
-	else {
-		if (drm_lock_free(&master->lock, lock->context)) {
-			/* FIXME: Should really bail out here. */
-		}
+	if (drm_lock_free(&master->lock, lock->context)) {
+		/* FIXME: Should really bail out here. */
 	}
 
 	unblock_all_signals();
@@ -193,6 +179,7 @@
  *
  * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
  */
+static
 int drm_lock_take(struct drm_lock_data *lock_data,
 		  unsigned int context)
 {
@@ -229,7 +216,6 @@
 	}
 	return 0;
 }
-EXPORT_SYMBOL(drm_lock_take);
 
 /**
  * This takes a lock forcibly and hands it to context.	Should ONLY be used
@@ -297,7 +283,6 @@
 	wake_up_interruptible(&lock_data->lock_queue);
 	return 0;
 }
-EXPORT_SYMBOL(drm_lock_free);
 
 /**
  * If we get here, it means that the process has called DRM_IOCTL_LOCK
@@ -360,7 +345,6 @@
 	}
 	spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_take);
 
 void drm_idlelock_release(struct drm_lock_data *lock_data)
 {
@@ -380,8 +364,6 @@
 	}
 	spin_unlock_bh(&lock_data->spinlock);
 }
-EXPORT_SYMBOL(drm_idlelock_release);
-
 
 int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
 {
@@ -390,5 +372,3 @@
 		_DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
 		master->lock.file_priv == file_priv);
 }
-
-EXPORT_SYMBOL(drm_i_have_hw_lock);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_memory.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_memory.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_memory.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_memory.c	2011-01-04 19:50:19.000000000 -0500
@@ -99,29 +99,23 @@
 	return addr;
 }
 
-/** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(struct drm_device * dev, int pages, u32 type)
-{
-	return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
-}
-
 /** Wrapper around agp_free_memory() */
-int drm_free_agp(DRM_AGP_MEM * handle, int pages)
+void drm_free_agp(DRM_AGP_MEM * handle, int pages)
 {
-	return drm_agp_free_memory(handle) ? 0 : -EINVAL;
+	agp_free_memory(handle);
 }
 EXPORT_SYMBOL(drm_free_agp);
 
 /** Wrapper around agp_bind_memory() */
 int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
 {
-	return drm_agp_bind_memory(handle, start);
+	return agp_bind_memory(handle, start);
 }
 
 /** Wrapper around agp_unbind_memory() */
 int drm_unbind_agp(DRM_AGP_MEM * handle)
 {
-	return drm_agp_unbind_memory(handle);
+	return agp_unbind_memory(handle);
 }
 EXPORT_SYMBOL(drm_unbind_agp);
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_modes.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_modes.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_modes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_modes.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,7 +76,7 @@
  * according to the hdisplay, vdisplay, vrefresh.
  * It is based from the VESA(TM) Coordinated Video Timing Generator by
  * Graham Loveridge April 9, 2003 available at
- * http://www.vesa.org/public/CVT/CVTd6r1.xls
+ * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls 
  *
  * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
  * What I have done is to translate it by using integer calculation.
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_proc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_proc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_proc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_proc.c	2011-01-04 19:50:19.000000000 -0500
@@ -55,7 +55,6 @@
 	{"queues", drm_queues_info, 0},
 	{"bufs", drm_bufs_info, 0},
 	{"gem_names", drm_gem_name_info, DRIVER_GEM},
-	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
 	{"vma", drm_vma_info, 0},
 #endif
@@ -151,7 +150,6 @@
 int drm_proc_init(struct drm_minor *minor, int minor_id,
 		  struct proc_dir_entry *root)
 {
-	struct drm_device *dev = minor->dev;
 	char name[64];
 	int ret;
 
@@ -172,14 +170,6 @@
 		return ret;
 	}
 
-	if (dev->driver->proc_init) {
-		ret = dev->driver->proc_init(minor);
-		if (ret) {
-			DRM_ERROR("DRM: Driver failed to initialize "
-				  "/proc/dri.\n");
-			return ret;
-		}
-	}
 	return 0;
 }
 
@@ -216,15 +206,11 @@
  */
 int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
 {
-	struct drm_device *dev = minor->dev;
 	char name[64];
 
 	if (!root || !minor->proc_root)
 		return 0;
 
-	if (dev->driver->proc_cleanup)
-		dev->driver->proc_cleanup(minor);
-
 	drm_proc_remove_files(drm_proc_list, DRM_PROC_ENTRIES, minor);
 
 	sprintf(name, "%d", minor->index);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_scatter.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_scatter.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_scatter.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_scatter.c	2011-01-04 19:50:19.000000000 -0500
@@ -184,8 +184,6 @@
 	drm_sg_cleanup(entry);
 	return -ENOMEM;
 }
-EXPORT_SYMBOL(drm_sg_alloc);
-
 
 int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_stub.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_stub.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_stub.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_stub.c	2011-01-04 19:50:19.000000000 -0500
@@ -240,14 +240,10 @@
 	INIT_LIST_HEAD(&dev->vblank_event_list);
 
 	spin_lock_init(&dev->count_lock);
-	spin_lock_init(&dev->drw_lock);
 	spin_lock_init(&dev->event_lock);
-	init_timer(&dev->timer);
 	mutex_init(&dev->struct_mutex);
 	mutex_init(&dev->ctxlist_mutex);
 
-	idr_init(&dev->drw_idr);
-
 	if (drm_ht_create(&dev->map_hash, 12)) {
 		return -ENOMEM;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_vm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_vm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/drm_vm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/drm_vm.c	2011-01-04 19:50:19.000000000 -0500
@@ -523,14 +523,7 @@
 	return 0;
 }
 
-resource_size_t drm_core_get_map_ofs(struct drm_local_map * map)
-{
-	return map->offset;
-}
-
-EXPORT_SYMBOL(drm_core_get_map_ofs);
-
-resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
+static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev)
 {
 #ifdef __alpha__
 	return dev->hose->dense_mem_base - dev->hose->mem_space->start;
@@ -539,8 +532,6 @@
 #endif
 }
 
-EXPORT_SYMBOL(drm_core_get_reg_ofs);
-
 /**
  * mmap DMA memory.
  *
@@ -627,7 +618,7 @@
 #endif
 	case _DRM_FRAME_BUFFER:
 	case _DRM_REGISTERS:
-		offset = dev->driver->get_reg_ofs(dev);
+		offset = drm_core_get_reg_ofs(dev);
 		vma->vm_flags |= VM_IO;	/* not in core dump */
 		vma->vm_page_prot = drm_io_prot(map->type, vma);
 #if !defined(__arm__)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i810/i810_dma.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i810/i810_dma.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i810/i810_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i810/i810_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -119,6 +119,7 @@
 	.unlocked_ioctl = i810_ioctl,
 	.mmap = i810_mmap_buffers,
 	.fasync = drm_fasync,
+	.llseek = noop_llseek,
 };
 
 static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i810/i810_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i810/i810_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i810/i810_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i810/i810_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,8 +52,6 @@
 	.device_is_agp = i810_driver_device_is_agp,
 	.reclaim_buffers_locked = i810_driver_reclaim_buffers_locked,
 	.dma_quiescent = i810_driver_dma_quiescent,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = i810_ioctls,
 	.fops = {
 		 .owner = THIS_MODULE,
@@ -63,6 +61,7 @@
 		 .mmap = drm_mmap,
 		 .poll = drm_poll,
 		 .fasync = drm_fasync,
+		 .llseek = noop_llseek,
 	},
 
 	.pci_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i830/i830_dma.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i830/i830_dma.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i830/i830_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i830/i830_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -121,6 +121,7 @@
 	.unlocked_ioctl = i830_ioctl,
 	.mmap = i830_mmap_buffers,
 	.fasync = drm_fasync,
+	.llseek = noop_llseek,
 };
 
 static int i830_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i830/i830_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i830/i830_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i830/i830_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i830/i830_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,8 +57,6 @@
 	.device_is_agp = i830_driver_device_is_agp,
 	.reclaim_buffers_locked = i830_driver_reclaim_buffers_locked,
 	.dma_quiescent = i830_driver_dma_quiescent,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 #if USE_IRQS
 	.irq_preinstall = i830_driver_irq_preinstall,
 	.irq_postinstall = i830_driver_irq_postinstall,
@@ -74,6 +72,7 @@
 		 .mmap = drm_mmap,
 		 .poll = drm_poll,
 		 .fasync = drm_fasync,
+		 .llseek = noop_llseek,
 	},
 
 	.pci_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ch7017.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ch7017.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ch7017.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ch7017.c	2011-01-04 19:50:19.000000000 -0500
@@ -165,67 +165,44 @@
 static void ch7017_dump_regs(struct intel_dvo_device *dvo);
 static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
 
-static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
 {
-	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-	u8 out_buf[2];
-	u8 in_buf[2];
-
 	struct i2c_msg msgs[] = {
 		{
 			.addr = dvo->slave_addr,
 			.flags = 0,
 			.len = 1,
-			.buf = out_buf,
+			.buf = &addr,
 		},
 		{
 			.addr = dvo->slave_addr,
 			.flags = I2C_M_RD,
 			.len = 1,
-			.buf = in_buf,
+			.buf = val,
 		}
 	};
-
-	out_buf[0] = addr;
-	out_buf[1] = 0;
-
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
-		*val= in_buf[0];
-		return true;
-	};
-
-	return false;
+	return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
 }
 
-static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
 {
-	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-	uint8_t out_buf[2];
+	uint8_t buf[2] = { addr, val };
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
 		.flags = 0,
 		.len = 2,
-		.buf = out_buf,
+		.buf = buf,
 	};
-
-	out_buf[0] = addr;
-	out_buf[1] = val;
-
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
-		return true;
-
-	return false;
+	return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
 }
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
 			struct i2c_adapter *adapter)
 {
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	struct ch7017_priv *priv;
-	uint8_t val;
+	const char *str;
+	u8 val;
 
 	priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
 	if (priv == NULL)
@@ -237,16 +214,27 @@
 	if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
 		goto fail;
 
-	if (val != CH7017_DEVICE_ID_VALUE &&
-	    val != CH7018_DEVICE_ID_VALUE &&
-	    val != CH7019_DEVICE_ID_VALUE) {
+	switch (val) {
+	case CH7017_DEVICE_ID_VALUE:
+		str = "ch7017";
+		break;
+	case CH7018_DEVICE_ID_VALUE:
+		str = "ch7018";
+		break;
+	case CH7019_DEVICE_ID_VALUE:
+		str = "ch7019";
+		break;
+	default:
 		DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
-				"Slave %d.\n",
-			  val, i2cbus->adapter.name,dvo->slave_addr);
+			      "slave %d.\n",
+			      val, adapter->name,dvo->slave_addr);
 		goto fail;
 	}
 
+	DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+		      str, adapter->name, dvo->slave_addr);
 	return true;
+
 fail:
 	kfree(priv);
 	return false;
@@ -254,7 +242,7 @@
 
 static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
 {
-	return connector_status_unknown;
+	return connector_status_connected;
 }
 
 static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
@@ -368,7 +356,7 @@
 	}
 
 	/* XXX: Should actually wait for update power status somehow */
-	udelay(20000);
+	msleep(20);
 }
 
 static void ch7017_dump_regs(struct intel_dvo_device *dvo)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ch7xxx.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ch7xxx.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ch7xxx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ch7xxx.c	2011-01-04 19:50:19.000000000 -0500
@@ -113,7 +113,6 @@
 {
 	struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -135,14 +134,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!ch7xxx->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -152,7 +151,6 @@
 {
 	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -164,12 +162,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!ch7xxx->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ivch.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ivch.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_ivch.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_ivch.c	2011-01-04 19:50:19.000000000 -0500
@@ -167,7 +167,6 @@
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[1];
 	u8 in_buf[2];
 
@@ -193,7 +192,7 @@
 
 	out_buf[0] = addr;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+	if (i2c_transfer(adapter, msgs, 3) == 3) {
 		*data = (in_buf[1] << 8) | in_buf[0];
 		return true;
 	};
@@ -201,7 +200,7 @@
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
 				"%s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -211,7 +210,6 @@
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[3];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -224,12 +222,12 @@
 	out_buf[1] = data & 0xff;
 	out_buf[2] = data >> 8;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_sil164.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_sil164.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_sil164.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_sil164.c	2011-01-04 19:50:19.000000000 -0500
@@ -69,7 +69,6 @@
 {
 	struct sil164_priv *sil = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -91,14 +90,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!sil->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -107,7 +106,6 @@
 {
 	struct sil164_priv *sil= dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -119,12 +117,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!sil->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_tfp410.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_tfp410.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/dvo_tfp410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/dvo_tfp410.c	2011-01-04 19:50:19.000000000 -0500
@@ -94,7 +94,6 @@
 {
 	struct tfp410_priv *tfp = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -116,14 +115,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!tfp->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -132,7 +131,6 @@
 {
 	struct tfp410_priv *tfp = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -144,12 +142,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!tfp->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_debugfs.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_debugfs.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,9 +40,51 @@
 
 #if defined(CONFIG_DEBUG_FS)
 
-#define ACTIVE_LIST	1
-#define FLUSHING_LIST	2
-#define INACTIVE_LIST	3
+enum {
+	ACTIVE_LIST,
+	FLUSHING_LIST,
+	INACTIVE_LIST,
+	PINNED_LIST,
+	DEFERRED_FREE_LIST,
+};
+
+static const char *yesno(int v)
+{
+	return v ? "yes" : "no";
+}
+
+static int i915_capabilities(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	const struct intel_device_info *info = INTEL_INFO(dev);
+
+	seq_printf(m, "gen: %d\n", info->gen);
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+	B(is_mobile);
+	B(is_i85x);
+	B(is_i915g);
+	B(is_i945gm);
+	B(is_g33);
+	B(need_gfx_hws);
+	B(is_g4x);
+	B(is_pineview);
+	B(is_broadwater);
+	B(is_crestline);
+	B(has_fbc);
+	B(has_rc6);
+	B(has_pipe_cxsr);
+	B(has_hotplug);
+	B(cursor_needs_physical);
+	B(has_overlay);
+	B(overlay_needs_physical);
+	B(supports_tv);
+	B(has_bsd_ring);
+	B(has_blt_ring);
+#undef B
+
+	return 0;
+}
 
 static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
 {
@@ -64,6 +106,29 @@
     }
 }
 
+static void
+describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
+{
+	seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+		   &obj->base,
+		   get_pin_flag(obj),
+		   get_tiling_flag(obj),
+		   obj->base.size,
+		   obj->base.read_domains,
+		   obj->base.write_domain,
+		   obj->last_rendering_seqno,
+		   obj->dirty ? " dirty" : "",
+		   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
+	if (obj->base.name)
+		seq_printf(m, " (name: %d)", obj->base.name);
+	if (obj->fence_reg != I915_FENCE_REG_NONE)
+		seq_printf(m, " (fence: %d)", obj->fence_reg);
+	if (obj->gtt_space != NULL)
+		seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+	if (obj->ring != NULL)
+		seq_printf(m, " (%s)", obj->ring->name);
+}
+
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -72,56 +137,80 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv;
-	spinlock_t *lock = NULL;
+	size_t total_obj_size, total_gtt_size;
+	int count, ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	switch (list) {
 	case ACTIVE_LIST:
 		seq_printf(m, "Active:\n");
-		lock = &dev_priv->mm.active_list_lock;
-		head = &dev_priv->render_ring.active_list;
+		head = &dev_priv->mm.active_list;
 		break;
 	case INACTIVE_LIST:
 		seq_printf(m, "Inactive:\n");
 		head = &dev_priv->mm.inactive_list;
 		break;
+	case PINNED_LIST:
+		seq_printf(m, "Pinned:\n");
+		head = &dev_priv->mm.pinned_list;
+		break;
 	case FLUSHING_LIST:
 		seq_printf(m, "Flushing:\n");
 		head = &dev_priv->mm.flushing_list;
 		break;
+	case DEFERRED_FREE_LIST:
+		seq_printf(m, "Deferred free:\n");
+		head = &dev_priv->mm.deferred_free_list;
+		break;
 	default:
-		DRM_INFO("Ooops, unexpected list\n");
-		return 0;
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
 	}
 
-	if (lock)
-		spin_lock(lock);
-	list_for_each_entry(obj_priv, head, list)
-	{
-		seq_printf(m, "    %p: %s %8zd %08x %08x %d%s%s",
-			   &obj_priv->base,
-			   get_pin_flag(obj_priv),
-			   obj_priv->base.size,
-			   obj_priv->base.read_domains,
-			   obj_priv->base.write_domain,
-			   obj_priv->last_rendering_seqno,
-			   obj_priv->dirty ? " dirty" : "",
-			   obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : "");
-
-		if (obj_priv->base.name)
-			seq_printf(m, " (name: %d)", obj_priv->base.name);
-		if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-			seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
-		if (obj_priv->gtt_space != NULL)
-			seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
-
+	total_obj_size = total_gtt_size = count = 0;
+	list_for_each_entry(obj_priv, head, mm_list) {
+		seq_printf(m, "   ");
+		describe_obj(m, obj_priv);
 		seq_printf(m, "\n");
+		total_obj_size += obj_priv->base.size;
+		total_gtt_size += obj_priv->gtt_space->size;
+		count++;
 	}
+	mutex_unlock(&dev->struct_mutex);
+
+	seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+		   count, total_obj_size, total_gtt_size);
+	return 0;
+}
+
+static int i915_gem_object_info(struct seq_file *m, void* data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
+	seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
+	seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
+	seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+	seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
+	seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
+	seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+
+	mutex_unlock(&dev->struct_mutex);
 
-	if (lock)
-	    spin_unlock(lock);
 	return 0;
 }
 
+
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -176,6 +265,11 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_request *gem_request;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	seq_printf(m, "Request:\n");
 	list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
@@ -184,6 +278,8 @@
 			   gem_request->seqno,
 			   (int) (jiffies - gem_request->emitted_jiffies));
 	}
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -192,16 +288,24 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (dev_priv->render_ring.status_page.page_addr != NULL) {
 		seq_printf(m, "Current sequence: %d\n",
-			   i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+			   dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
 	} else {
 		seq_printf(m, "Current sequence: hws uninitialized\n");
 	}
 	seq_printf(m, "Waiter sequence:  %d\n",
 			dev_priv->mm.waiting_gem_seqno);
 	seq_printf(m, "IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -211,6 +315,11 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (!HAS_PCH_SPLIT(dev)) {
 		seq_printf(m, "Interrupt enable:    %08x\n",
@@ -247,7 +356,7 @@
 		   atomic_read(&dev_priv->irq_received));
 	if (dev_priv->render_ring.status_page.page_addr != NULL) {
 		seq_printf(m, "Current sequence:    %d\n",
-			   i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+			   dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
 	} else {
 		seq_printf(m, "Current sequence:    hws uninitialized\n");
 	}
@@ -255,6 +364,8 @@
 		   dev_priv->mm.waiting_gem_seqno);
 	seq_printf(m, "IRQ sequence:        %d\n",
 		   dev_priv->mm.irq_gem_seqno);
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -263,7 +374,11 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int i;
+	int i, ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
 	seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
@@ -289,6 +404,7 @@
 			seq_printf(m, "\n");
 		}
 	}
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -313,16 +429,19 @@
 	return 0;
 }
 
-static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
+static void i915_dump_object(struct seq_file *m,
+			     struct io_mapping *mapping,
+			     struct drm_i915_gem_object *obj_priv)
 {
-	int page, i;
-	uint32_t *mem;
+	int page, page_count, i;
 
+	page_count = obj_priv->base.size / PAGE_SIZE;
 	for (page = 0; page < page_count; page++) {
-		mem = kmap_atomic(pages[page], KM_USER0);
+		u32 *mem = io_mapping_map_wc(mapping,
+					     obj_priv->gtt_offset + page * PAGE_SIZE);
 		for (i = 0; i < PAGE_SIZE; i += 4)
 			seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-		kunmap_atomic(mem, KM_USER0);
+		io_mapping_unmap(mem);
 	}
 }
 
@@ -335,27 +454,20 @@
 	struct drm_i915_gem_object *obj_priv;
 	int ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
-	list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
-			list) {
+	list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
 		obj = &obj_priv->base;
 		if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
-		    ret = i915_gem_object_get_pages(obj, 0);
-		    if (ret) {
-			    DRM_ERROR("Failed to get pages: %d\n", ret);
-			    spin_unlock(&dev_priv->mm.active_list_lock);
-			    return ret;
-		    }
-
-		    seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
-		    i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
-
-		    i915_gem_object_put_pages(obj);
+		    seq_printf(m, "--- gtt_offset = 0x%08x\n",
+			       obj_priv->gtt_offset);
+		    i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
 		}
 	}
 
-	spin_unlock(&dev_priv->mm.active_list_lock);
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -365,20 +477,24 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u8 *virt;
-	uint32_t *ptr, off;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (!dev_priv->render_ring.gem_object) {
 		seq_printf(m, "No ringbuffer setup\n");
-		return 0;
-	}
-
-	virt = dev_priv->render_ring.virtual_start;
+	} else {
+		u8 *virt = dev_priv->render_ring.virtual_start;
+		uint32_t off;
 
-	for (off = 0; off < dev_priv->render_ring.size; off += 4) {
-		ptr = (uint32_t *)(virt + off);
-		seq_printf(m, "%08x :  %08x\n", off, *ptr);
+		for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+			uint32_t *ptr = (uint32_t *)(virt + off);
+			seq_printf(m, "%08x :  %08x\n", off, *ptr);
+		}
 	}
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -396,7 +512,7 @@
 	seq_printf(m, "RingHead :  %08x\n", head);
 	seq_printf(m, "RingTail :  %08x\n", tail);
 	seq_printf(m, "RingSize :  %08lx\n", dev_priv->render_ring.size);
-	seq_printf(m, "Acthd :     %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
+	seq_printf(m, "Acthd :     %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
 
 	return 0;
 }
@@ -458,7 +574,7 @@
 	seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
 	seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
 	seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
 		seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
 	}
@@ -642,6 +758,9 @@
 	} else {
 		seq_printf(m, "FBC disabled: ");
 		switch (dev_priv->no_fbc_reason) {
+		case FBC_NO_OUTPUT:
+			seq_printf(m, "no outputs");
+			break;
 		case FBC_STOLEN_TOO_SMALL:
 			seq_printf(m, "not enough stolen memory");
 			break;
@@ -675,15 +794,17 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	bool sr_enabled = false;
 
-	if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev))
+	if (IS_GEN5(dev))
+		sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
+	else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
 		sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
 	else if (IS_I915GM(dev))
 		sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
 	else if (IS_PINEVIEW(dev))
 		sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
 
-	seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
-		   "disabled");
+	seq_printf(m, "self-refresh: %s\n",
+		   sr_enabled ? "enabled" : "disabled");
 
 	return 0;
 }
@@ -694,10 +815,16 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long temp, chipset, gfx;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	temp = i915_mch_val(dev_priv);
 	chipset = i915_chipset_val(dev_priv);
 	gfx = i915_gfx_val(dev_priv);
+	mutex_unlock(&dev->struct_mutex);
 
 	seq_printf(m, "GMCH temp: %ld\n", temp);
 	seq_printf(m, "Chipset power: %ld\n", chipset);
@@ -718,6 +845,68 @@
 	return 0;
 }
 
+static int i915_opregion(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	if (opregion->header)
+		seq_write(m, opregion->header, OPREGION_SIZE);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev;
+	struct intel_framebuffer *fb;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	if (ret)
+		return ret;
+
+	ifbdev = dev_priv->fbdev;
+	fb = to_intel_framebuffer(ifbdev->helper.fb);
+
+	seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+		   fb->base.width,
+		   fb->base.height,
+		   fb->base.depth,
+		   fb->base.bits_per_pixel);
+	describe_obj(m, to_intel_bo(fb->obj));
+	seq_printf(m, "\n");
+
+	list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
+		if (&fb->base == ifbdev->helper.fb)
+			continue;
+
+		seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+			   fb->base.width,
+			   fb->base.height,
+			   fb->base.depth,
+			   fb->base.bits_per_pixel);
+		describe_obj(m, to_intel_bo(fb->obj));
+		seq_printf(m, "\n");
+	}
+
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
 		 struct file *filp)
@@ -741,6 +930,9 @@
 		       "wedged :  %d\n",
 		       atomic_read(&dev_priv->mm.wedged));
 
+	if (len > sizeof (buf))
+		len = sizeof (buf);
+
 	return simple_read_from_buffer(ubuf, max, ppos, buf, len);
 }
 
@@ -770,7 +962,7 @@
 
 	atomic_set(&dev_priv->mm.wedged, val);
 	if (val) {
-		DRM_WAKEUP(&dev_priv->irq_queue);
+		wake_up_all(&dev_priv->irq_queue);
 		queue_work(dev_priv->wq, &dev_priv->error_work);
 	}
 
@@ -782,6 +974,7 @@
 	.open = i915_wedged_open,
 	.read = i915_wedged_read,
 	.write = i915_wedged_write,
+	.llseek = default_llseek,
 };
 
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
@@ -823,9 +1016,13 @@
 }
 
 static struct drm_info_list i915_debugfs_list[] = {
+	{"i915_capabilities", i915_capabilities, 0, 0},
+	{"i915_gem_objects", i915_gem_object_info, 0},
 	{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
 	{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
 	{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+	{"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
+	{"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
 	{"i915_gem_pageflip", i915_gem_pageflip_info, 0},
 	{"i915_gem_request", i915_gem_request_info, 0},
 	{"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -845,6 +1042,8 @@
 	{"i915_gfxec", i915_gfxec, 0},
 	{"i915_fbc_status", i915_fbc_status, 0},
 	{"i915_sr_status", i915_sr_status, 0},
+	{"i915_opregion", i915_opregion, 0},
+	{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_dma.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_dma.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,14 +34,14 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 #include "i915_trace.h"
+#include "../../../platform/x86/intel_ips.h"
 #include <linux/pci.h>
 #include <linux/vgaarb.h>
 #include <linux/acpi.h>
 #include <linux/pnp.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
-
-extern int intel_max_stolen; /* from AGP driver */
+#include <acpi/video.h>
 
 /**
  * Sets up the hardware status page for devices that need a physical address
@@ -64,7 +64,7 @@
 
 	memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
 					     0xf0;
 
@@ -133,8 +133,8 @@
 
 	mutex_lock(&dev->struct_mutex);
 	intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-	if (HAS_BSD(dev))
-		intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+	intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+	intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
 	mutex_unlock(&dev->struct_mutex);
 
 	/* Clear the HWS virtual address at teardown */
@@ -222,7 +222,7 @@
 	DRM_DEBUG_DRIVER("hw status page @ %p\n",
 				ring->status_page.page_addr);
 	if (ring->status_page.gfx_addr != 0)
-		ring->setup_status_page(dev, ring);
+		intel_ring_setup_status_page(dev, ring);
 	else
 		I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 
@@ -377,7 +377,7 @@
 		return -EINVAL;
 	}
 
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		BEGIN_LP_RING(4);
 		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
 		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
@@ -481,7 +481,7 @@
 
 		if (!IS_I830(dev) && !IS_845G(dev)) {
 			BEGIN_LP_RING(2);
-			if (IS_I965G(dev)) {
+			if (INTEL_INFO(dev)->gen >= 4) {
 				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
 				OUT_RING(batch->start);
 			} else {
@@ -500,7 +500,7 @@
 	}
 
 
-	if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+	if (IS_G4X(dev) || IS_GEN5(dev)) {
 		BEGIN_LP_RING(2);
 		OUT_RING(MI_FLUSH | MI_NO_WRITE_FLUSH | MI_INVALIDATE_ISP);
 		OUT_RING(MI_NOOP);
@@ -765,6 +765,12 @@
 	case I915_PARAM_HAS_BSD:
 		value = HAS_BSD(dev);
 		break;
+	case I915_PARAM_HAS_BLT:
+		value = HAS_BLT(dev);
+		break;
+	case I915_PARAM_HAS_COHERENT_RINGS:
+		value = 1;
+		break;
 	default:
 		DRM_DEBUG_DRIVER("Unknown parameter %d\n",
 				 param->param);
@@ -888,12 +894,12 @@
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp_lo, temp_hi = 0;
 	u64 mchbar_addr;
 	int ret;
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
 	pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
 	mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
@@ -920,7 +926,7 @@
 		return ret;
 	}
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
 				       upper_32_bits(dev_priv->mch_res.start));
 
@@ -934,7 +940,7 @@
 intel_setup_mchbar(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp;
 	bool enabled;
 
@@ -971,7 +977,7 @@
 intel_teardown_mchbar(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp;
 
 	if (dev_priv->mchbar_need_disable) {
@@ -990,174 +996,6 @@
 		release_resource(&dev_priv->mch_res);
 }
 
-/**
- * i915_probe_agp - get AGP bootup configuration
- * @pdev: PCI device
- * @aperture_size: returns AGP aperture configured size
- * @preallocated_size: returns size of BIOS preallocated AGP space
- *
- * Since Intel integrated graphics are UMA, the BIOS has to set aside
- * some RAM for the framebuffer at early boot.  This code figures out
- * how much was set aside so we can use it for our own purposes.
- */
-static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
-			  uint32_t *preallocated_size,
-			  uint32_t *start)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u16 tmp = 0;
-	unsigned long overhead;
-	unsigned long stolen;
-
-	/* Get the fb aperture size and "stolen" memory amount. */
-	pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
-
-	*aperture_size = 1024 * 1024;
-	*preallocated_size = 1024 * 1024;
-
-	switch (dev->pdev->device) {
-	case PCI_DEVICE_ID_INTEL_82830_CGC:
-	case PCI_DEVICE_ID_INTEL_82845G_IG:
-	case PCI_DEVICE_ID_INTEL_82855GM_IG:
-	case PCI_DEVICE_ID_INTEL_82865_IG:
-		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
-			*aperture_size *= 64;
-		else
-			*aperture_size *= 128;
-		break;
-	default:
-		/* 9xx supports large sizes, just look at the length */
-		*aperture_size = pci_resource_len(dev->pdev, 2);
-		break;
-	}
-
-	/*
-	 * Some of the preallocated space is taken by the GTT
-	 * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
-	 */
-	if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
-		overhead = 4096;
-	else
-		overhead = (*aperture_size / 1024) + 4096;
-
-	if (IS_GEN6(dev)) {
-		/* SNB has memory control reg at 0x50.w */
-		pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
-
-		switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
-		case INTEL_855_GMCH_GMS_DISABLED:
-			DRM_ERROR("video memory is disabled\n");
-			return -1;
-		case SNB_GMCH_GMS_STOLEN_32M:
-			stolen = 32 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_64M:
-			stolen = 64 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_96M:
-			stolen = 96 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_128M:
-			stolen = 128 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_160M:
-			stolen = 160 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_192M:
-			stolen = 192 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_224M:
-			stolen = 224 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_256M:
-			stolen = 256 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_288M:
-			stolen = 288 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_320M:
-			stolen = 320 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_352M:
-			stolen = 352 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_384M:
-			stolen = 384 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_416M:
-			stolen = 416 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_448M:
-			stolen = 448 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_480M:
-			stolen = 480 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_512M:
-			stolen = 512 * 1024 * 1024;
-			break;
-		default:
-			DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-				  tmp & SNB_GMCH_GMS_STOLEN_MASK);
-			return -1;
-		}
-	} else {
-		switch (tmp & INTEL_GMCH_GMS_MASK) {
-		case INTEL_855_GMCH_GMS_DISABLED:
-			DRM_ERROR("video memory is disabled\n");
-			return -1;
-		case INTEL_855_GMCH_GMS_STOLEN_1M:
-			stolen = 1 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_4M:
-			stolen = 4 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_8M:
-			stolen = 8 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_16M:
-			stolen = 16 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_32M:
-			stolen = 32 * 1024 * 1024;
-			break;
-		case INTEL_915G_GMCH_GMS_STOLEN_48M:
-			stolen = 48 * 1024 * 1024;
-			break;
-		case INTEL_915G_GMCH_GMS_STOLEN_64M:
-			stolen = 64 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_128M:
-			stolen = 128 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_256M:
-			stolen = 256 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_96M:
-			stolen = 96 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_160M:
-			stolen = 160 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_224M:
-			stolen = 224 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_352M:
-			stolen = 352 * 1024 * 1024;
-			break;
-		default:
-			DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-				  tmp & INTEL_GMCH_GMS_MASK);
-			return -1;
-		}
-	}
-
-	*preallocated_size = stolen - overhead;
-	*start = overhead;
-
-	return 0;
-}
-
 #define PTE_ADDRESS_MASK		0xfffff000
 #define PTE_ADDRESS_MASK_HIGH		0x000000f0 /* i915+ */
 #define PTE_MAPPING_TYPE_UNCACHED	(0 << 1)
@@ -1181,11 +1019,11 @@
 {
 	unsigned long *gtt;
 	unsigned long entry, phys;
-	int gtt_bar = IS_I9XX(dev) ? 0 : 1;
+	int gtt_bar = IS_GEN2(dev) ? 1 : 0;
 	int gtt_offset, gtt_size;
 
-	if (IS_I965G(dev)) {
-		if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
+		if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
 			gtt_offset = 2*1024*1024;
 			gtt_size = 2*1024*1024;
 		} else {
@@ -1210,10 +1048,8 @@
 	DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
 
 	/* Mask out these reserved bits on this hardware. */
-	if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
-	    IS_I945G(dev) || IS_I945GM(dev)) {
+	if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
 		entry &= ~PTE_ADDRESS_MASK_HIGH;
-	}
 
 	/* If it's not a mapping type we know, then bail. */
 	if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
@@ -1252,7 +1088,7 @@
 	unsigned long ll_base = 0;
 
 	/* Leave 1M for line length buffer & misc. */
-	compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
+	compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
 	if (!compressed_fb) {
 		dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
 		i915_warn_stolen(dev);
@@ -1273,7 +1109,7 @@
 	}
 
 	if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
-		compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
+		compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
 						    4096, 0);
 		if (!compressed_llb) {
 			i915_warn_stolen(dev);
@@ -1343,10 +1179,8 @@
 		/* i915 resume handler doesn't set to D0 */
 		pci_set_power_state(dev->pdev, PCI_D0);
 		i915_resume(dev);
-		drm_kms_helper_poll_enable(dev);
 	} else {
 		printk(KERN_ERR "i915: switched off\n");
-		drm_kms_helper_poll_disable(dev);
 		i915_suspend(dev, pmm);
 	}
 }
@@ -1363,23 +1197,14 @@
 }
 
 static int i915_load_modeset_init(struct drm_device *dev,
-				  unsigned long prealloc_start,
 				  unsigned long prealloc_size,
 				  unsigned long agp_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int fb_bar = IS_I9XX(dev) ? 2 : 0;
 	int ret = 0;
 
-	dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
-		0xff000000;
-
-	/* Basic memrange allocator for stolen space (aka vram) */
-	drm_mm_init(&dev_priv->vram, 0, prealloc_size);
-	DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
-
-	/* We're off and running w/KMS */
-	dev_priv->mm.suspended = 0;
+	/* Basic memrange allocator for stolen space (aka mm.vram) */
+	drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
 
 	/* Let GEM Manage from end of prealloc space to end of aperture.
 	 *
@@ -1414,7 +1239,7 @@
 	 */
 	dev_priv->allow_batchbuffer = 1;
 
-	ret = intel_init_bios(dev);
+	ret = intel_parse_bios(dev);
 	if (ret)
 		DRM_INFO("failed to find VBIOS tables\n");
 
@@ -1423,6 +1248,8 @@
 	if (ret)
 		goto cleanup_ringbuffer;
 
+	intel_register_dsm_handler();
+
 	ret = vga_switcheroo_register_client(dev->pdev,
 					     i915_switcheroo_set_state,
 					     i915_switcheroo_can_switch);
@@ -1443,17 +1270,15 @@
 	/* FIXME: do pre/post-mode set stuff in core KMS code */
 	dev->vblank_disable_allowed = 1;
 
-	/*
-	 * Initialize the hardware status page IRQ location.
-	 */
-
-	I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
-
 	ret = intel_fbdev_init(dev);
 	if (ret)
 		goto cleanup_irq;
 
 	drm_kms_helper_poll_init(dev);
+
+	/* We're off and running w/KMS */
+	dev_priv->mm.suspended = 0;
+
 	return 0;
 
 cleanup_irq:
@@ -1907,7 +1732,7 @@
  *   - dev_priv->fmax
  *   - dev_priv->gpu_busy
  */
-DEFINE_SPINLOCK(mchdev_lock);
+static DEFINE_SPINLOCK(mchdev_lock);
 
 /**
  * i915_read_mch_val - return value for IPS use
@@ -2047,6 +1872,26 @@
 EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
 
 /**
+ * Tells the intel_ips driver that the i915 driver is now loaded, if
+ * IPS got loaded first.
+ *
+ * This awkward dance is so that neither module has to depend on the
+ * other in order for IPS to do the appropriate communication of
+ * GPU turbo limits to i915.
+ */
+static void
+ips_ping_for_i915_load(void)
+{
+	void (*link)(void);
+
+	link = symbol_get(ips_link_to_i915_driver);
+	if (link) {
+		link();
+		symbol_put(ips_link_to_i915_driver);
+	}
+}
+
+/**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
  * @flags: startup flags
@@ -2062,7 +1907,7 @@
 	struct drm_i915_private *dev_priv;
 	resource_size_t base, size;
 	int ret = 0, mmio_bar;
-	uint32_t agp_size, prealloc_size, prealloc_start;
+	uint32_t agp_size, prealloc_size;
 	/* i915 has 4 more counters */
 	dev->counters += 4;
 	dev->types[6] = _DRM_STAT_IRQ;
@@ -2079,7 +1924,7 @@
 	dev_priv->info = (struct intel_device_info *) flags;
 
 	/* Add register map (needed for suspend/resume) */
-	mmio_bar = IS_I9XX(dev) ? 0 : 1;
+	mmio_bar = IS_GEN2(dev) ? 1 : 0;
 	base = pci_resource_start(dev->pdev, mmio_bar);
 	size = pci_resource_len(dev->pdev, mmio_bar);
 
@@ -2121,17 +1966,32 @@
 			 "performance may suffer.\n");
 	}
 
-	ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
-	if (ret)
+	dev_priv->mm.gtt = intel_gtt_get();
+	if (!dev_priv->mm.gtt) {
+		DRM_ERROR("Failed to initialize GTT\n");
+		ret = -ENODEV;
 		goto out_iomapfree;
-
-	if (prealloc_size > intel_max_stolen) {
-		DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
-			 prealloc_size >> 20, intel_max_stolen >> 20);
-		prealloc_size = intel_max_stolen;
 	}
 
-	dev_priv->wq = create_singlethread_workqueue("i915");
+	prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+	agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+	/* The i915 workqueue is primarily used for batched retirement of
+	 * requests (and thus managing bo) once the task has been completed
+	 * by the GPU. i915_gem_retire_requests() is called directly when we
+	 * need high-priority retirement, such as waiting for an explicit
+	 * bo.
+	 *
+	 * It is also used for periodic low-priority events, such as
+	 * idle-timers and hangcheck.
+	 *
+	 * All tasks on the workqueue are expected to acquire the dev mutex
+	 * so there is no point in running more than one instance of the
+	 * workqueue at any time: max_active = 1 and NON_REENTRANT.
+	 */
+	dev_priv->wq = alloc_workqueue("i915",
+				       WQ_UNBOUND | WQ_NON_REENTRANT,
+				       1);
 	if (dev_priv->wq == NULL) {
 		DRM_ERROR("Failed to create our workqueue.\n");
 		ret = -ENOMEM;
@@ -2159,13 +2019,18 @@
 
 	dev->driver->get_vblank_counter = i915_get_vblank_counter;
 	dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-	if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+	if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
 		dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
 		dev->driver->get_vblank_counter = gm45_get_vblank_counter;
 	}
 
 	/* Try to make sure MCHBAR is enabled before poking at it */
 	intel_setup_mchbar(dev);
+	intel_setup_gmbus(dev);
+	intel_opregion_setup(dev);
+
+	/* Make sure the bios did its job and set up vital registers */
+	intel_setup_bios(dev);
 
 	i915_gem_load(dev);
 
@@ -2178,7 +2043,7 @@
 
 	if (IS_PINEVIEW(dev))
 		i915_pineview_get_mem_freq(dev);
-	else if (IS_IRONLAKE(dev))
+	else if (IS_GEN5(dev))
 		i915_ironlake_get_mem_freq(dev);
 
 	/* On the 945G/GM, the chipset reports the MSI capability on the
@@ -2212,8 +2077,7 @@
 	intel_detect_pch(dev);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-		ret = i915_load_modeset_init(dev, prealloc_start,
-					     prealloc_size, agp_size);
+		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
 		if (ret < 0) {
 			DRM_ERROR("failed to init modeset\n");
 			goto out_workqueue_free;
@@ -2221,7 +2085,8 @@
 	}
 
 	/* Must be done after probing outputs */
-	intel_opregion_init(dev, 0);
+	intel_opregion_init(dev);
+	acpi_video_register();
 
 	setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
 		    (unsigned long) dev);
@@ -2231,8 +2096,7 @@
 	dev_priv->mchdev_lock = &mchdev_lock;
 	spin_unlock(&mchdev_lock);
 
-	/* XXX Prevent module unload due to memory corruption bugs. */
-	__module_get(THIS_MODULE);
+	ips_ping_for_i915_load();
 
 	return 0;
 
@@ -2252,15 +2116,20 @@
 int i915_driver_unload(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	i915_destroy_error_state(dev);
+	int ret;
 
 	spin_lock(&mchdev_lock);
 	i915_mch_dev = NULL;
 	spin_unlock(&mchdev_lock);
 
-	destroy_workqueue(dev_priv->wq);
-	del_timer_sync(&dev_priv->hangcheck_timer);
+	mutex_lock(&dev->struct_mutex);
+	ret = i915_gpu_idle(dev);
+	if (ret)
+		DRM_ERROR("failed to idle hardware: %d\n", ret);
+	mutex_unlock(&dev->struct_mutex);
+
+	/* Cancel the retire work handler, which should be idle now. */
+	cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
 	io_mapping_free(dev_priv->mm.gtt_mapping);
 	if (dev_priv->mm.gtt_mtrr >= 0) {
@@ -2269,7 +2138,10 @@
 		dev_priv->mm.gtt_mtrr = -1;
 	}
 
+	acpi_video_unregister();
+
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		intel_fbdev_fini(dev);
 		intel_modeset_cleanup(dev);
 
 		/*
@@ -2281,20 +2153,25 @@
 			dev_priv->child_dev = NULL;
 			dev_priv->child_dev_num = 0;
 		}
-		drm_irq_uninstall(dev);
+
 		vga_switcheroo_unregister_client(dev->pdev);
 		vga_client_register(dev->pdev, NULL, NULL, NULL);
 	}
 
+	/* Free error state after interrupts are fully disabled. */
+	del_timer_sync(&dev_priv->hangcheck_timer);
+	cancel_work_sync(&dev_priv->error_work);
+	i915_destroy_error_state(dev);
+
 	if (dev->pdev->msi_enabled)
 		pci_disable_msi(dev->pdev);
 
-	if (dev_priv->regs != NULL)
-		iounmap(dev_priv->regs);
-
-	intel_opregion_free(dev, 0);
+	intel_opregion_fini(dev);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		/* Flush any outstanding unpin_work. */
+		flush_workqueue(dev_priv->wq);
+
 		i915_gem_free_all_phys_object(dev);
 
 		mutex_lock(&dev->struct_mutex);
@@ -2302,34 +2179,41 @@
 		mutex_unlock(&dev->struct_mutex);
 		if (I915_HAS_FBC(dev) && i915_powersave)
 			i915_cleanup_compression(dev);
-		drm_mm_takedown(&dev_priv->vram);
-		i915_gem_lastclose(dev);
+		drm_mm_takedown(&dev_priv->mm.vram);
 
 		intel_cleanup_overlay(dev);
+
+		if (!I915_NEED_GFX_HWS(dev))
+			i915_free_hws(dev);
 	}
 
+	if (dev_priv->regs != NULL)
+		iounmap(dev_priv->regs);
+
+	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 
+	destroy_workqueue(dev_priv->wq);
+
 	pci_dev_put(dev_priv->bridge_dev);
 	kfree(dev->dev_private);
 
 	return 0;
 }
 
-int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+int i915_driver_open(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv;
+	struct drm_i915_file_private *file_priv;
 
 	DRM_DEBUG_DRIVER("\n");
-	i915_file_priv = (struct drm_i915_file_private *)
-	    kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
-
-	if (!i915_file_priv)
+	file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+	if (!file_priv)
 		return -ENOMEM;
 
-	file_priv->driver_priv = i915_file_priv;
+	file->driver_priv = file_priv;
 
-	INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
+	spin_lock_init(&file_priv->mm.lock);
+	INIT_LIST_HEAD(&file_priv->mm.request_list);
 
 	return 0;
 }
@@ -2372,11 +2256,11 @@
 		i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
-void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
 
-	kfree(i915_file_priv);
+	kfree(file_priv);
 }
 
 struct drm_ioctl_desc i915_ioctls[] = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #include <linux/console.h>
 #include "drm_crtc_helper.h"
@@ -43,7 +44,7 @@
 module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
 unsigned int i915_powersave = 1;
-module_param_named(powersave, i915_powersave, int, 0400);
+module_param_named(powersave, i915_powersave, int, 0600);
 
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
@@ -61,86 +62,111 @@
 	.driver_data = (unsigned long) info }
 
 static const struct intel_device_info intel_i830_info = {
-	.gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_845g_info = {
-	.gen = 2, .is_i8xx = 1,
+	.gen = 2,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-	.gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+	.gen = 2, .is_i85x = 1, .is_mobile = 1,
 	.cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-	.gen = 2, .is_i8xx = 1,
+	.gen = 2,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i915g_info = {
-	.gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
+	.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-	.gen = 3, .is_i9xx = 1,  .is_mobile = 1,
+	.gen = 3, .is_mobile = 1,
 	.cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
+	.supports_tv = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-	.gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
+	.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-	.gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
+	.gen = 3, .is_i945gm = 1, .is_mobile = 1,
 	.has_hotplug = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
+	.supports_tv = 1,
 };
 
 static const struct intel_device_info intel_i965g_info = {
-	.gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 4, .is_broadwater = 1,
 	.has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-	.gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
+	.gen = 4, .is_crestline = 1,
 	.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+	.has_overlay = 1,
+	.supports_tv = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-	.gen = 3, .is_g33 = 1, .is_i9xx = 1,
+	.gen = 3, .is_g33 = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_g45_info = {
-	.gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+	.gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
 	.has_pipe_cxsr = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-	.gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
+	.gen = 4, .is_g4x = 1,
 	.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
 	.has_pipe_cxsr = 1, .has_hotplug = 1,
+	.supports_tv = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
-	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
+	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
-	.gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 5,
 	.need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-	.gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
-	.need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+	.gen = 5, .is_mobile = 1,
+	.need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1,
+	.has_fbc = 0, /* disabled due to buggy hardware */
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
-	.gen = 6, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 6,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
+	.has_blt_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-	.gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1,
+	.gen = 6, .is_mobile = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
+	.has_blt_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {		/* aka */
@@ -237,7 +263,7 @@
 
 	i915_save_state(dev);
 
-	intel_opregion_free(dev, 1);
+	intel_opregion_fini(dev);
 
 	/* Modeset on resume, not lid events */
 	dev_priv->modeset_on_lid = 0;
@@ -258,6 +284,8 @@
 	if (state.event == PM_EVENT_PRETHAW)
 		return 0;
 
+	drm_kms_helper_poll_disable(dev);
+
 	error = i915_drm_freeze(dev);
 	if (error)
 		return error;
@@ -277,8 +305,7 @@
 	int error = 0;
 
 	i915_restore_state(dev);
-
-	intel_opregion_init(dev, 1);
+	intel_opregion_setup(dev);
 
 	/* KMS EnterVT equivalent */
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -294,6 +321,8 @@
 		drm_helper_resume_force_mode(dev);
 	}
 
+	intel_opregion_init(dev);
+
 	dev_priv->modeset_on_lid = 0;
 
 	return error;
@@ -301,12 +330,79 @@
 
 int i915_resume(struct drm_device *dev)
 {
+	int ret;
+
 	if (pci_enable_device(dev->pdev))
 		return -EIO;
 
 	pci_set_master(dev->pdev);
 
-	return i915_drm_thaw(dev);
+	ret = i915_drm_thaw(dev);
+	if (ret)
+		return ret;
+
+	drm_kms_helper_poll_enable(dev);
+	return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (IS_I85X(dev))
+		return -ENODEV;
+
+	I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+	POSTING_READ(D_STATE);
+
+	if (IS_I830(dev) || IS_845G(dev)) {
+		I915_WRITE(DEBUG_RESET_I830,
+			   DEBUG_RESET_DISPLAY |
+			   DEBUG_RESET_RENDER |
+			   DEBUG_RESET_FULL);
+		POSTING_READ(DEBUG_RESET_I830);
+		msleep(1);
+
+		I915_WRITE(DEBUG_RESET_I830, 0);
+		POSTING_READ(DEBUG_RESET_I830);
+	}
+
+	msleep(1);
+
+	I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+	POSTING_READ(D_STATE);
+
+	return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+	u8 gdrst;
+	pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+	return gdrst & 0x1;
+}
+
+static int i965_do_reset(struct drm_device *dev, u8 flags)
+{
+	u8 gdrst;
+
+	/*
+	 * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+	 * well as the reset bit (GR/bit 0).  Setting the GR bit
+	 * triggers the reset; when done, the hardware will clear it.
+	 */
+	pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+	pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+
+	return wait_for(i965_reset_complete(dev), 500);
+}
+
+static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+	return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
 }
 
 /**
@@ -325,54 +421,39 @@
  *   - re-init interrupt state
  *   - re-init display
  */
-int i965_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev, u8 flags)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	unsigned long timeout;
-	u8 gdrst;
 	/*
 	 * We really should only reset the display subsystem if we actually
 	 * need to
 	 */
 	bool need_display = true;
+	int ret;
 
 	mutex_lock(&dev->struct_mutex);
 
-	/*
-	 * Clear request list
-	 */
-	i915_gem_retire_requests(dev);
-
-	if (need_display)
-		i915_save_display(dev);
-
-	if (IS_I965G(dev) || IS_G4X(dev)) {
-		/*
-		 * Set the domains we want to reset, then the reset bit (bit 0).
-		 * Clear the reset bit after a while and wait for hardware status
-		 * bit (bit 1) to be set
-		 */
-		pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-		pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
-		udelay(50);
-		pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe);
-
-		/* ...we don't want to loop forever though, 500ms should be plenty */
-	       timeout = jiffies + msecs_to_jiffies(500);
-		do {
-			udelay(100);
-			pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-		} while ((gdrst & 0x1) && time_after(timeout, jiffies));
+	i915_gem_reset(dev);
 
-		if (gdrst & 0x1) {
-			WARN(true, "i915: Failed to reset chip\n");
-			mutex_unlock(&dev->struct_mutex);
-			return -EIO;
-		}
-	} else {
-		DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+	ret = -ENODEV;
+	if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+		DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
+	} else switch (INTEL_INFO(dev)->gen) {
+	case 5:
+		ret = ironlake_do_reset(dev, flags);
+		break;
+	case 4:
+		ret = i965_do_reset(dev, flags);
+		break;
+	case 2:
+		ret = i8xx_do_reset(dev, flags);
+		break;
+	}
+	dev_priv->last_gpu_reset = get_seconds();
+	if (ret) {
+		DRM_ERROR("Failed to reset chip.\n");
 		mutex_unlock(&dev->struct_mutex);
-		return -ENODEV;
+		return ret;
 	}
 
 	/* Ok, now get things going again... */
@@ -400,13 +481,19 @@
 		mutex_lock(&dev->struct_mutex);
 	}
 
+	mutex_unlock(&dev->struct_mutex);
+
 	/*
-	 * Display needs restore too...
+	 * Perform a full modeset as on later generations, e.g. Ironlake, we may
+	 * need to retrain the display link and cannot just restore the register
+	 * values.
 	 */
-	if (need_display)
-		i915_restore_display(dev);
+	if (need_display) {
+		mutex_lock(&dev->mode_config.mutex);
+		drm_helper_resume_force_mode(dev);
+		mutex_unlock(&dev->mode_config.mutex);
+	}
 
-	mutex_unlock(&dev->struct_mutex);
 	return 0;
 }
 
@@ -524,8 +611,6 @@
 	.irq_uninstall = i915_driver_irq_uninstall,
 	.irq_handler = i915_driver_irq_handler,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.master_create = i915_master_create,
 	.master_destroy = i915_master_destroy,
 #if defined(CONFIG_DEBUG_FS)
@@ -548,6 +633,7 @@
 #ifdef CONFIG_COMPAT
 		 .compat_ioctl = i915_compat_ioctl,
 #endif
+		 .llseek = noop_llseek,
 	},
 
 	.pci_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_drv.h linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_drv.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_drv.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_drv.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,8 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/i2c.h>
+#include <drm/intel-gtt.h>
 
 /* General customization:
  */
@@ -73,11 +75,9 @@
 #define DRIVER_PATCHLEVEL	0
 
 #define WATCH_COHERENCY	0
-#define WATCH_BUF	0
 #define WATCH_EXEC	0
-#define WATCH_LRU	0
 #define WATCH_RELOC	0
-#define WATCH_INACTIVE	0
+#define WATCH_LISTS	0
 #define WATCH_PWRITE	0
 
 #define I915_GEM_PHYS_CURSOR_0 1
@@ -110,8 +110,9 @@
 	struct opregion_acpi *acpi;
 	struct opregion_swsci *swsci;
 	struct opregion_asle *asle;
-	int enabled;
+	void *vbt;
 };
+#define OPREGION_SIZE            (8*1024)
 
 struct intel_overlay;
 struct intel_overlay_error_state;
@@ -125,13 +126,16 @@
 struct drm_i915_fence_reg {
 	struct drm_gem_object *obj;
 	struct list_head lru_list;
+	bool gpu;
 };
 
 struct sdvo_device_mapping {
+	u8 initialized;
 	u8 dvo_port;
 	u8 slave_addr;
 	u8 dvo_wiring;
-	u8 initialized;
+	u8 i2c_pin;
+	u8 i2c_speed;
 	u8 ddc_pin;
 };
 
@@ -193,28 +197,29 @@
 struct intel_device_info {
 	u8 gen;
 	u8 is_mobile : 1;
-	u8 is_i8xx : 1;
 	u8 is_i85x : 1;
 	u8 is_i915g : 1;
-	u8 is_i9xx : 1;
 	u8 is_i945gm : 1;
-	u8 is_i965g : 1;
-	u8 is_i965gm : 1;
 	u8 is_g33 : 1;
 	u8 need_gfx_hws : 1;
 	u8 is_g4x : 1;
 	u8 is_pineview : 1;
 	u8 is_broadwater : 1;
 	u8 is_crestline : 1;
-	u8 is_ironlake : 1;
 	u8 has_fbc : 1;
 	u8 has_rc6 : 1;
 	u8 has_pipe_cxsr : 1;
 	u8 has_hotplug : 1;
 	u8 cursor_needs_physical : 1;
+	u8 has_overlay : 1;
+	u8 overlay_needs_physical : 1;
+	u8 supports_tv : 1;
+	u8 has_bsd_ring : 1;
+	u8 has_blt_ring : 1;
 };
 
 enum no_fbc_reason {
+	FBC_NO_OUTPUT, /* no outputs enabled to compress */
 	FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
 	FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
 	FBC_MODE_TOO_LARGE, /* mode too large for compression */
@@ -241,9 +246,16 @@
 
 	void __iomem *regs;
 
+	struct intel_gmbus {
+		struct i2c_adapter adapter;
+		struct i2c_adapter *force_bit;
+		u32 reg0;
+	} *gmbus;
+
 	struct pci_dev *bridge_dev;
 	struct intel_ring_buffer render_ring;
 	struct intel_ring_buffer bsd_ring;
+	struct intel_ring_buffer blt_ring;
 	uint32_t next_seqno;
 
 	drm_dma_handle_t *status_page_dmah;
@@ -263,6 +275,9 @@
 	int front_offset;
 	int current_page;
 	int page_flipping;
+#define I915_DEBUG_READ (1<<0)
+#define I915_DEBUG_WRITE (1<<1)
+	unsigned long debug_flags;
 
 	wait_queue_head_t irq_queue;
 	atomic_t irq_received;
@@ -289,24 +304,21 @@
 	unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
 	int vblank_pipe;
 	int num_pipe;
-	u32 flush_rings;
-#define FLUSH_RENDER_RING	0x1
-#define FLUSH_BSD_RING		0x2
 
 	/* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
+#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
 	struct timer_list hangcheck_timer;
 	int hangcheck_count;
 	uint32_t last_acthd;
 	uint32_t last_instdone;
 	uint32_t last_instdone1;
 
-	struct drm_mm vram;
-
 	unsigned long cfb_size;
 	unsigned long cfb_pitch;
+	unsigned long cfb_offset;
 	int cfb_fence;
 	int cfb_plane;
+	int cfb_y;
 
 	int irq_enabled;
 
@@ -316,8 +328,7 @@
 	struct intel_overlay *overlay;
 
 	/* LVDS info */
-	int backlight_duty_cycle;  /* restore backlight to this value */
-	bool panel_wants_dither;
+	int backlight_level;  /* restore backlight to this value */
 	struct drm_display_mode *panel_fixed_mode;
 	struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
 	struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -328,13 +339,23 @@
 	unsigned int lvds_vbt:1;
 	unsigned int int_crt_support:1;
 	unsigned int lvds_use_ssc:1;
-	unsigned int edp_support:1;
 	int lvds_ssc_freq;
-	int edp_bpp;
+	struct {
+		int rate;
+		int lanes;
+		int preemphasis;
+		int vswing;
+
+		bool initialized;
+		bool support;
+		int bpp;
+		struct edp_power_seq pps;
+	} edp;
+	bool no_aux_handshake;
 
 	struct notifier_block lid_notifier;
 
-	int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
+	int crt_ddc_pin;
 	struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
 	int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
 	int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -344,6 +365,7 @@
 	spinlock_t error_lock;
 	struct drm_i915_error_state *first_error;
 	struct work_struct error_work;
+	struct completion error_completion;
 	struct workqueue_struct *wq;
 
 	/* Display functions */
@@ -507,6 +529,11 @@
 	u32 saveMCHBAR_RENDER_STANDBY;
 
 	struct {
+		/** Bridge to intel-gtt-ko */
+		struct intel_gtt *gtt;
+		/** Memory allocator for GTT stolen memory */
+		struct drm_mm vram;
+		/** Memory allocator for GTT */
 		struct drm_mm gtt_space;
 
 		struct io_mapping *gtt_mapping;
@@ -521,7 +548,16 @@
 		 */
 		struct list_head shrink_list;
 
-		spinlock_t active_list_lock;
+		/**
+		 * List of objects currently involved in rendering.
+		 *
+		 * Includes buffers having the contents of their GPU caches
+		 * flushed, not necessarily primitives.  last_rendering_seqno
+		 * represents when the rendering involved will be completed.
+		 *
+		 * A reference is held on the buffer while on this list.
+		 */
+		struct list_head active_list;
 
 		/**
 		 * List of objects which are not in the ringbuffer but which
@@ -535,15 +571,6 @@
 		struct list_head flushing_list;
 
 		/**
-		 * List of objects currently pending a GPU write flush.
-		 *
-		 * All elements on this list will belong to either the
-		 * active_list or flushing_list, last_rendering_seqno can
-		 * be used to differentiate between the two elements.
-		 */
-		struct list_head gpu_write_list;
-
-		/**
 		 * LRU list of objects which are not in the ringbuffer and
 		 * are ready to unbind, but are still in the GTT.
 		 *
@@ -555,6 +582,12 @@
 		 */
 		struct list_head inactive_list;
 
+		/**
+		 * LRU list of objects which are not in the ringbuffer but
+		 * are still pinned in the GTT.
+		 */
+		struct list_head pinned_list;
+
 		/** LRU list of objects with fence regs on them. */
 		struct list_head fence_list;
 
@@ -611,6 +644,17 @@
 
 		/* storage for physical objects */
 		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+		uint32_t flush_rings;
+
+		/* accounting, useful for userland debugging */
+		size_t object_memory;
+		size_t pin_memory;
+		size_t gtt_memory;
+		size_t gtt_total;
+		u32 object_count;
+		u32 pin_count;
+		u32 gtt_count;
 	} mm;
 	struct sdvo_device_mapping sdvo_mappings[2];
 	/* indicate whether the LVDS_BORDER should be enabled or not */
@@ -626,8 +670,6 @@
 	/* Reclocking support */
 	bool render_reclock_avail;
 	bool lvds_downclock_avail;
-	/* indicate whether the LVDS EDID is OK */
-	bool lvds_edid_good;
 	/* indicates the reduced downclock for LVDS*/
 	int lvds_downclock;
 	struct work_struct idle_work;
@@ -661,6 +703,8 @@
 	struct drm_mm_node *compressed_fb;
 	struct drm_mm_node *compressed_llb;
 
+	unsigned long last_gpu_reset;
+
 	/* list of fbdev register on this device */
 	struct intel_fbdev *fbdev;
 } drm_i915_private_t;
@@ -673,7 +717,8 @@
 	struct drm_mm_node *gtt_space;
 
 	/** This object's place on the active/flushing/inactive lists */
-	struct list_head list;
+	struct list_head ring_list;
+	struct list_head mm_list;
 	/** This object's place on GPU write list */
 	struct list_head gpu_write_list;
 	/** This object's place on eviction list */
@@ -816,12 +861,14 @@
 	/** global list entry for this request */
 	struct list_head list;
 
+	struct drm_i915_file_private *file_priv;
 	/** file_priv list entry for this request */
 	struct list_head client_list;
 };
 
 struct drm_i915_file_private {
 	struct {
+		struct spinlock lock;
 		struct list_head request_list;
 	} mm;
 };
@@ -862,7 +909,7 @@
 extern int i915_emit_box(struct drm_device *dev,
 			 struct drm_clip_rect *boxes,
 			 int i, int DR1, int DR4);
-extern int i965_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev, u8 flags);
 extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -871,7 +918,6 @@
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
-void i915_destroy_error_state(struct drm_device *dev);
 extern int i915_irq_emit(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -908,6 +954,12 @@
 
 void intel_enable_asle (struct drm_device *dev);
 
+#ifdef CONFIG_DEBUG_FS
+extern void i915_destroy_error_state(struct drm_device *dev);
+#else
+#define i915_destroy_error_state(x)
+#endif
+
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -922,6 +974,7 @@
 extern void i915_mem_release(struct drm_device * dev,
 			     struct drm_file *file_priv, struct mem_block *heap);
 /* i915_gem.c */
+int i915_gem_check_is_wedged(struct drm_device *dev);
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -972,17 +1025,28 @@
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
-bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+	return (int32_t)(seq1 - seq2) >= 0;
+}
+
+int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+				  bool interruptible);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+				  bool interruptible);
 void i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_reset(struct drm_device *dev);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
 int i915_gem_object_set_domain(struct drm_gem_object *obj,
 			       uint32_t read_domains,
 			       uint32_t write_domain);
+int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+			      bool interruptible);
 int i915_gem_init_ringbuffer(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int i915_gem_do_init(struct drm_device *dev, unsigned long start,
@@ -990,16 +1054,18 @@
 int i915_gpu_idle(struct drm_device *dev);
 int i915_gem_idle(struct drm_device *dev);
 uint32_t i915_add_request(struct drm_device *dev,
-		struct drm_file *file_priv,
-		uint32_t flush_domains,
-		struct intel_ring_buffer *ring);
+			  struct drm_file *file_priv,
+			  struct drm_i915_gem_request *request,
+			  struct intel_ring_buffer *ring);
 int i915_do_wait_request(struct drm_device *dev,
-		uint32_t seqno, int interruptible,
-		struct intel_ring_buffer *ring);
+			 uint32_t seqno,
+			 bool interruptible,
+			 struct intel_ring_buffer *ring);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
 				      int write);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+					 bool pipelined);
 int i915_gem_attach_phys_object(struct drm_device *dev,
 				struct drm_gem_object *obj,
 				int id,
@@ -1007,10 +1073,7 @@
 void i915_gem_detach_phys_object(struct drm_device *dev,
 				 struct drm_gem_object *obj);
 void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void i915_gem_object_put_pages(struct drm_gem_object *obj);
 void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
 
 void i915_gem_shrinker_init(void);
 void i915_gem_shrinker_exit(void);
@@ -1032,15 +1095,14 @@
 /* i915_gem_debug.c */
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 			  const char *where, uint32_t mark);
-#if WATCH_INACTIVE
-void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#if WATCH_LISTS
+int i915_verify_lists(struct drm_device *dev);
 #else
-#define i915_verify_inactive(dev, file, line)
+#define i915_verify_lists(dev) 0
 #endif
 void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 			  const char *where, uint32_t mark);
-void i915_dump_lru(struct drm_device *dev, const char *where);
 
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
@@ -1054,21 +1116,42 @@
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
+/* intel_i2c.c */
+extern int intel_setup_gmbus(struct drm_device *dev);
+extern void intel_teardown_gmbus(struct drm_device *dev);
+extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+	return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
+}
+extern void intel_i2c_reset(struct drm_device *dev);
+
+/* intel_opregion.c */
+extern int intel_opregion_setup(struct drm_device *dev);
 #ifdef CONFIG_ACPI
-/* i915_opregion.c */
-extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev, int suspend);
-extern void opregion_asle_intr(struct drm_device *dev);
-extern void ironlake_opregion_gse_intr(struct drm_device *dev);
-extern void opregion_enable_asle(struct drm_device *dev);
+extern void intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_fini(struct drm_device *dev);
+extern void intel_opregion_asle_intr(struct drm_device *dev);
+extern void intel_opregion_gse_intr(struct drm_device *dev);
+extern void intel_opregion_enable_asle(struct drm_device *dev);
 #else
-static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
-static inline void opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void opregion_enable_asle(struct drm_device *dev) { return; }
+static inline void intel_opregion_init(struct drm_device *dev) { return; }
+static inline void intel_opregion_fini(struct drm_device *dev) { return; }
+static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
+/* intel_acpi.c */
+#ifdef CONFIG_ACPI
+extern void intel_register_dsm_handler(void);
+extern void intel_unregister_dsm_handler(void);
+#else
+static inline void intel_register_dsm_handler(void) { return; }
+static inline void intel_unregister_dsm_handler(void) { return; }
+#endif /* CONFIG_ACPI */
+
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1084,8 +1167,10 @@
 extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
 
 /* overlay */
+#ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+#endif
 
 /**
  * Lock test for when it's just for synchronization of ring access.
@@ -1099,8 +1184,26 @@
 		LOCK_TEST_WITH_RETURN(dev, file_priv);			\
 } while (0)
 
-#define I915_READ(reg)          readl(dev_priv->regs + (reg))
-#define I915_WRITE(reg, val)     writel(val, dev_priv->regs + (reg))
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+	u32 val;
+
+	val = readl(dev_priv->regs + reg);
+	if (dev_priv->debug_flags & I915_DEBUG_READ)
+		printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+	return val;
+}
+
+static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
+			      u32 val)
+{
+	writel(val, dev_priv->regs + reg);
+	if (dev_priv->debug_flags & I915_DEBUG_WRITE)
+		printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+}
+
+#define I915_READ(reg)          i915_read(dev_priv, (reg))
+#define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
 #define I915_READ16(reg)	readw(dev_priv->regs + (reg))
 #define I915_WRITE16(reg, val)	writel(val, dev_priv->regs + (reg))
 #define I915_READ8(reg)		readb(dev_priv->regs + (reg))
@@ -1110,6 +1213,11 @@
 #define POSTING_READ(reg)	(void)I915_READ(reg)
 #define POSTING_READ16(reg)	(void)I915_READ16(reg)
 
+#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
+				I915_DEBUG_WRITE)
+#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
+							    I915_DEBUG_WRITE))
+
 #define I915_VERBOSE 0
 
 #define BEGIN_LP_RING(n)  do { \
@@ -1166,8 +1274,6 @@
 #define IS_I915GM(dev)		((dev)->pci_device == 0x2592)
 #define IS_I945G(dev)		((dev)->pci_device == 0x2772)
 #define IS_I945GM(dev)		(INTEL_INFO(dev)->is_i945gm)
-#define IS_I965G(dev)		(INTEL_INFO(dev)->is_i965g)
-#define IS_I965GM(dev)		(INTEL_INFO(dev)->is_i965gm)
 #define IS_BROADWATER(dev)	(INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)	(INTEL_INFO(dev)->is_crestline)
 #define IS_GM45(dev)		((dev)->pci_device == 0x2A42)
@@ -1178,8 +1284,6 @@
 #define IS_G33(dev)		(INTEL_INFO(dev)->is_g33)
 #define IS_IRONLAKE_D(dev)	((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)	((dev)->pci_device == 0x0046)
-#define IS_IRONLAKE(dev)	(INTEL_INFO(dev)->is_ironlake)
-#define IS_I9XX(dev)		(INTEL_INFO(dev)->is_i9xx)
 #define IS_MOBILE(dev)		(INTEL_INFO(dev)->is_mobile)
 
 #define IS_GEN2(dev)	(INTEL_INFO(dev)->gen == 2)
@@ -1188,36 +1292,38 @@
 #define IS_GEN5(dev)	(INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)	(INTEL_INFO(dev)->gen == 6)
 
-#define HAS_BSD(dev)            (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
+#define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
 #define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 
+#define HAS_OVERLAY(dev) 		(INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev)	(INTEL_INFO(dev)->overlay_needs_physical)
+
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
-#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
 						      IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev)	(IS_I9XX(dev) && !IS_PINEVIEW(dev))
-#define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_IRONLAKE(dev))
-#define SUPPORTS_INTEGRATED_DP(dev)	(IS_G4X(dev) || IS_IRONLAKE(dev))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev)	(!IS_GEN2(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_GEN5(dev))
+#define SUPPORTS_INTEGRATED_DP(dev)	(IS_G4X(dev) || IS_GEN5(dev))
 #define SUPPORTS_EDP(dev)		(IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev)		(IS_I9XX(dev) && IS_MOBILE(dev) && \
-					!IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
-					!IS_GEN6(dev))
+#define SUPPORTS_TV(dev)		(INTEL_INFO(dev)->supports_tv)
 #define I915_HAS_HOTPLUG(dev)		 (INTEL_INFO(dev)->has_hotplug)
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
 
-#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev))
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
 
-#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) ||	\
-			    IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
 
 #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
+#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
 
 #define PRIMARY_RINGBUFFER_SIZE         (128*1024)
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,6 +37,7 @@
 #include <linux/intel-gtt.h>
 
 static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
+
 static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
@@ -46,7 +47,8 @@
 						     uint64_t offset,
 						     uint64_t size);
 static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+					  bool interruptible);
 static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
 					   unsigned alignment);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
@@ -55,9 +57,111 @@
 				struct drm_file *file_priv);
 static void i915_gem_free_object_tail(struct drm_gem_object *obj);
 
+static int
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+			  gfp_t gfpmask);
+
+static void
+i915_gem_object_put_pages(struct drm_gem_object *obj);
+
 static LIST_HEAD(shrink_list);
 static DEFINE_SPINLOCK(shrink_list_lock);
 
+/* some bookkeeping */
+static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.object_count++;
+	dev_priv->mm.object_memory += size;
+}
+
+static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.object_count--;
+	dev_priv->mm.object_memory -= size;
+}
+
+static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.gtt_count++;
+	dev_priv->mm.gtt_memory += size;
+}
+
+static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.gtt_count--;
+	dev_priv->mm.gtt_memory -= size;
+}
+
+static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.pin_count++;
+	dev_priv->mm.pin_memory += size;
+}
+
+static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.pin_count--;
+	dev_priv->mm.pin_memory -= size;
+}
+
+int
+i915_gem_check_is_wedged(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct completion *x = &dev_priv->error_completion;
+	unsigned long flags;
+	int ret;
+
+	if (!atomic_read(&dev_priv->mm.wedged))
+		return 0;
+
+	ret = wait_for_completion_interruptible(x);
+	if (ret)
+		return ret;
+
+	/* Success, we reset the GPU! */
+	if (!atomic_read(&dev_priv->mm.wedged))
+		return 0;
+
+	/* GPU is hung, bump the completion count to account for
+	 * the token we just consumed so that we never hit zero and
+	 * end up waiting upon a subsequent completion event that
+	 * will never happen.
+	 */
+	spin_lock_irqsave(&x->wait.lock, flags);
+	x->done++;
+	spin_unlock_irqrestore(&x->wait.lock, flags);
+	return -EIO;
+}
+
+static int i915_mutex_lock_interruptible(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	if (atomic_read(&dev_priv->mm.wedged)) {
+		mutex_unlock(&dev->struct_mutex);
+		return -EAGAIN;
+	}
+
+	WARN_ON(i915_verify_lists(dev));
+	return 0;
+}
+
 static inline bool
 i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
 {
@@ -66,7 +170,8 @@
 		obj_priv->pin_count == 0;
 }
 
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+int i915_gem_do_init(struct drm_device *dev,
+		     unsigned long start,
 		     unsigned long end)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -80,7 +185,7 @@
 	drm_mm_init(&dev_priv->mm.gtt_space, start,
 		    end - start);
 
-	dev->gtt_total = (uint32_t) (end - start);
+	dev_priv->mm.gtt_total = end - start;
 
 	return 0;
 }
@@ -103,14 +208,16 @@
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file_priv)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_get_aperture *args = data;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM))
 		return -ENODEV;
 
-	args->aper_size = dev->gtt_total;
-	args->aper_available_size = (args->aper_size -
-				     atomic_read(&dev->pin_memory));
+	mutex_lock(&dev->struct_mutex);
+	args->aper_size = dev_priv->mm.gtt_total;
+	args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -136,12 +243,17 @@
 		return -ENOMEM;
 
 	ret = drm_gem_handle_create(file_priv, obj, &handle);
-	/* drop reference from allocate - handle holds it now */
-	drm_gem_object_unreference_unlocked(obj);
 	if (ret) {
+		drm_gem_object_release(obj);
+		i915_gem_info_remove_obj(dev->dev_private, obj->size);
+		kfree(obj);
 		return ret;
 	}
 
+	/* drop reference from allocate - handle holds it now */
+	drm_gem_object_unreference(obj);
+	trace_i915_gem_object_create(obj);
+
 	args->handle = handle;
 	return 0;
 }
@@ -152,19 +264,14 @@
 		char __user *data,
 		int length)
 {
-	char __iomem *vaddr;
-	int unwritten;
-
-	vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
-	if (vaddr == NULL)
-		return -ENOMEM;
-	unwritten = __copy_to_user_inatomic(data, vaddr + page_offset, length);
-	kunmap_atomic(vaddr, KM_USER0);
+	char *vaddr;
+	int ret;
 
-	if (unwritten)
-		return -EFAULT;
+	vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+	ret = __copy_to_user_inatomic(data, vaddr + page_offset, length);
+	kunmap_atomic(vaddr);
 
-	return 0;
+	return ret;
 }
 
 static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
@@ -258,22 +365,10 @@
 	loff_t offset, page_base;
 	char __user *user_data;
 	int page_offset, page_length;
-	int ret;
 
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	mutex_lock(&dev->struct_mutex);
-
-	ret = i915_gem_object_get_pages(obj, 0);
-	if (ret != 0)
-		goto fail_unlock;
-
-	ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
-							args->size);
-	if (ret != 0)
-		goto fail_put_pages;
-
 	obj_priv = to_intel_bo(obj);
 	offset = args->offset;
 
@@ -290,23 +385,17 @@
 		if ((page_offset + remain) > PAGE_SIZE)
 			page_length = PAGE_SIZE - page_offset;
 
-		ret = fast_shmem_read(obj_priv->pages,
-				      page_base, page_offset,
-				      user_data, page_length);
-		if (ret)
-			goto fail_put_pages;
+		if (fast_shmem_read(obj_priv->pages,
+				    page_base, page_offset,
+				    user_data, page_length))
+			return -EFAULT;
 
 		remain -= page_length;
 		user_data += page_length;
 		offset += page_length;
 	}
 
-fail_put_pages:
-	i915_gem_object_put_pages(obj);
-fail_unlock:
-	mutex_unlock(&dev->struct_mutex);
-
-	return ret;
+	return 0;
 }
 
 static int
@@ -367,31 +456,28 @@
 	last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
 	num_pages = last_data_page - first_data_page + 1;
 
-	user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+	user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
 	if (user_pages == NULL)
 		return -ENOMEM;
 
+	mutex_unlock(&dev->struct_mutex);
 	down_read(&mm->mmap_sem);
 	pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
 				      num_pages, 1, 0, user_pages, NULL);
 	up_read(&mm->mmap_sem);
+	mutex_lock(&dev->struct_mutex);
 	if (pinned_pages < num_pages) {
 		ret = -EFAULT;
-		goto fail_put_user_pages;
+		goto out;
 	}
 
-	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
-	mutex_lock(&dev->struct_mutex);
-
-	ret = i915_gem_object_get_pages_or_evict(obj);
+	ret = i915_gem_object_set_cpu_read_domain_range(obj,
+							args->offset,
+							args->size);
 	if (ret)
-		goto fail_unlock;
+		goto out;
 
-	ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset,
-							args->size);
-	if (ret != 0)
-		goto fail_put_pages;
+	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
 	obj_priv = to_intel_bo(obj);
 	offset = args->offset;
@@ -436,11 +522,7 @@
 		offset += page_length;
 	}
 
-fail_put_pages:
-	i915_gem_object_put_pages(obj);
-fail_unlock:
-	mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
 	for (i = 0; i < pinned_pages; i++) {
 		SetPageDirty(user_pages[i]);
 		page_cache_release(user_pages[i]);
@@ -462,37 +544,60 @@
 	struct drm_i915_gem_pread *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-	int ret;
+	int ret = 0;
+
+	if (args->size == 0)
+		return 0;
+
+	if (!access_ok(VERIFY_WRITE,
+		       (char __user *)(uintptr_t)args->data_ptr,
+		       args->size))
+		return -EFAULT;
+
+	ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
+				       args->size);
+	if (ret)
+		return -EFAULT;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-	if (obj == NULL)
-		return -ENOENT;
+	if (obj == NULL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
 	obj_priv = to_intel_bo(obj);
 
 	/* Bounds check source.  */
 	if (args->offset > obj->size || args->size > obj->size - args->offset) {
 		ret = -EINVAL;
-		goto err;
+		goto out;
 	}
 
-	if (!access_ok(VERIFY_WRITE,
-		       (char __user *)(uintptr_t)args->data_ptr,
-		       args->size)) {
-		ret = -EFAULT;
-		goto err;
-	}
+	ret = i915_gem_object_get_pages_or_evict(obj);
+	if (ret)
+		goto out;
 
-	if (i915_gem_object_needs_bit17_swizzle(obj)) {
-		ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
-	} else {
+	ret = i915_gem_object_set_cpu_read_domain_range(obj,
+							args->offset,
+							args->size);
+	if (ret)
+		goto out_put;
+
+	ret = -EFAULT;
+	if (!i915_gem_object_needs_bit17_swizzle(obj))
 		ret = i915_gem_shmem_pread_fast(dev, obj, args, file_priv);
-		if (ret != 0)
-			ret = i915_gem_shmem_pread_slow(dev, obj, args,
-							file_priv);
-	}
+	if (ret == -EFAULT)
+		ret = i915_gem_shmem_pread_slow(dev, obj, args, file_priv);
 
-err:
-	drm_gem_object_unreference_unlocked(obj);
+out_put:
+	i915_gem_object_put_pages(obj);
+out:
+	drm_gem_object_unreference(obj);
+unlock:
+	mutex_unlock(&dev->struct_mutex);
 	return ret;
 }
 
@@ -509,13 +614,11 @@
 	char *vaddr_atomic;
 	unsigned long unwritten;
 
-	vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0);
+	vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
 	unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
 						      user_data, length);
-	io_mapping_unmap_atomic(vaddr_atomic, KM_USER0);
-	if (unwritten)
-		return -EFAULT;
-	return 0;
+	io_mapping_unmap_atomic(vaddr_atomic);
+	return unwritten;
 }
 
 /* Here's the write path which can sleep for
@@ -548,18 +651,14 @@
 		 char __user *data,
 		 int length)
 {
-	char __iomem *vaddr;
-	unsigned long unwritten;
+	char *vaddr;
+	int ret;
 
-	vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT], KM_USER0);
-	if (vaddr == NULL)
-		return -ENOMEM;
-	unwritten = __copy_from_user_inatomic(vaddr + page_offset, data, length);
-	kunmap_atomic(vaddr, KM_USER0);
+	vaddr = kmap_atomic(pages[page_base >> PAGE_SHIFT]);
+	ret = __copy_from_user_inatomic(vaddr + page_offset, data, length);
+	kunmap_atomic(vaddr);
 
-	if (unwritten)
-		return -EFAULT;
-	return 0;
+	return ret;
 }
 
 /**
@@ -577,22 +676,10 @@
 	loff_t offset, page_base;
 	char __user *user_data;
 	int page_offset, page_length;
-	int ret;
 
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-
-	mutex_lock(&dev->struct_mutex);
-	ret = i915_gem_object_pin(obj, 0);
-	if (ret) {
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
-	}
-	ret = i915_gem_object_set_to_gtt_domain(obj, 1);
-	if (ret)
-		goto fail;
-
 	obj_priv = to_intel_bo(obj);
 	offset = obj_priv->gtt_offset + args->offset;
 
@@ -609,26 +696,21 @@
 		if ((page_offset + remain) > PAGE_SIZE)
 			page_length = PAGE_SIZE - page_offset;
 
-		ret = fast_user_write (dev_priv->mm.gtt_mapping, page_base,
-				       page_offset, user_data, page_length);
-
 		/* If we get a fault while copying data, then (presumably) our
 		 * source page isn't available.  Return the error and we'll
 		 * retry in the slow path.
 		 */
-		if (ret)
-			goto fail;
+		if (fast_user_write(dev_priv->mm.gtt_mapping, page_base,
+				    page_offset, user_data, page_length))
+
+			return -EFAULT;
 
 		remain -= page_length;
 		user_data += page_length;
 		offset += page_length;
 	}
 
-fail:
-	i915_gem_object_unpin(obj);
-	mutex_unlock(&dev->struct_mutex);
-
-	return ret;
+	return 0;
 }
 
 /**
@@ -665,27 +747,24 @@
 	last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
 	num_pages = last_data_page - first_data_page + 1;
 
-	user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+	user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
 	if (user_pages == NULL)
 		return -ENOMEM;
 
+	mutex_unlock(&dev->struct_mutex);
 	down_read(&mm->mmap_sem);
 	pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
 				      num_pages, 0, 0, user_pages, NULL);
 	up_read(&mm->mmap_sem);
+	mutex_lock(&dev->struct_mutex);
 	if (pinned_pages < num_pages) {
 		ret = -EFAULT;
 		goto out_unpin_pages;
 	}
 
-	mutex_lock(&dev->struct_mutex);
-	ret = i915_gem_object_pin(obj, 0);
-	if (ret)
-		goto out_unlock;
-
 	ret = i915_gem_object_set_to_gtt_domain(obj, 1);
 	if (ret)
-		goto out_unpin_object;
+		goto out_unpin_pages;
 
 	obj_priv = to_intel_bo(obj);
 	offset = obj_priv->gtt_offset + args->offset;
@@ -721,10 +800,6 @@
 		data_ptr += page_length;
 	}
 
-out_unpin_object:
-	i915_gem_object_unpin(obj);
-out_unlock:
-	mutex_unlock(&dev->struct_mutex);
 out_unpin_pages:
 	for (i = 0; i < pinned_pages; i++)
 		page_cache_release(user_pages[i]);
@@ -747,21 +822,10 @@
 	loff_t offset, page_base;
 	char __user *user_data;
 	int page_offset, page_length;
-	int ret;
 
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	mutex_lock(&dev->struct_mutex);
-
-	ret = i915_gem_object_get_pages(obj, 0);
-	if (ret != 0)
-		goto fail_unlock;
-
-	ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-	if (ret != 0)
-		goto fail_put_pages;
-
 	obj_priv = to_intel_bo(obj);
 	offset = args->offset;
 	obj_priv->dirty = 1;
@@ -779,23 +843,17 @@
 		if ((page_offset + remain) > PAGE_SIZE)
 			page_length = PAGE_SIZE - page_offset;
 
-		ret = fast_shmem_write(obj_priv->pages,
+		if (fast_shmem_write(obj_priv->pages,
 				       page_base, page_offset,
-				       user_data, page_length);
-		if (ret)
-			goto fail_put_pages;
+				       user_data, page_length))
+			return -EFAULT;
 
 		remain -= page_length;
 		user_data += page_length;
 		offset += page_length;
 	}
 
-fail_put_pages:
-	i915_gem_object_put_pages(obj);
-fail_unlock:
-	mutex_unlock(&dev->struct_mutex);
-
-	return ret;
+	return 0;
 }
 
 /**
@@ -833,30 +891,26 @@
 	last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
 	num_pages = last_data_page - first_data_page + 1;
 
-	user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
+	user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
 	if (user_pages == NULL)
 		return -ENOMEM;
 
+	mutex_unlock(&dev->struct_mutex);
 	down_read(&mm->mmap_sem);
 	pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
 				      num_pages, 0, 0, user_pages, NULL);
 	up_read(&mm->mmap_sem);
+	mutex_lock(&dev->struct_mutex);
 	if (pinned_pages < num_pages) {
 		ret = -EFAULT;
-		goto fail_put_user_pages;
+		goto out;
 	}
 
-	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
-
-	mutex_lock(&dev->struct_mutex);
-
-	ret = i915_gem_object_get_pages_or_evict(obj);
+	ret = i915_gem_object_set_to_cpu_domain(obj, 1);
 	if (ret)
-		goto fail_unlock;
+		goto out;
 
-	ret = i915_gem_object_set_to_cpu_domain(obj, 1);
-	if (ret != 0)
-		goto fail_put_pages;
+	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
 	obj_priv = to_intel_bo(obj);
 	offset = args->offset;
@@ -902,11 +956,7 @@
 		offset += page_length;
 	}
 
-fail_put_pages:
-	i915_gem_object_put_pages(obj);
-fail_unlock:
-	mutex_unlock(&dev->struct_mutex);
-fail_put_user_pages:
+out:
 	for (i = 0; i < pinned_pages; i++)
 		page_cache_release(user_pages[i]);
 	drm_free_large(user_pages);
@@ -921,29 +971,41 @@
  */
 int
 i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
-		      struct drm_file *file_priv)
+		      struct drm_file *file)
 {
 	struct drm_i915_gem_pwrite *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-	int ret = 0;
+	int ret;
 
-	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-	if (obj == NULL)
-		return -ENOENT;
+	if (args->size == 0)
+		return 0;
+
+	if (!access_ok(VERIFY_READ,
+		       (char __user *)(uintptr_t)args->data_ptr,
+		       args->size))
+		return -EFAULT;
+
+	ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
+				      args->size);
+	if (ret)
+		return -EFAULT;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
+	obj = drm_gem_object_lookup(dev, file, args->handle);
+	if (obj == NULL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
 	obj_priv = to_intel_bo(obj);
 
 	/* Bounds check destination. */
 	if (args->offset > obj->size || args->size > obj->size - args->offset) {
 		ret = -EINVAL;
-		goto err;
-	}
-
-	if (!access_ok(VERIFY_READ,
-		       (char __user *)(uintptr_t)args->data_ptr,
-		       args->size)) {
-		ret = -EFAULT;
-		goto err;
+		goto out;
 	}
 
 	/* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -953,32 +1015,47 @@
 	 * perspective, requiring manual detiling by the client.
 	 */
 	if (obj_priv->phys_obj)
-		ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
+		ret = i915_gem_phys_pwrite(dev, obj, args, file);
 	else if (obj_priv->tiling_mode == I915_TILING_NONE &&
-		 dev->gtt_total != 0 &&
+		 obj_priv->gtt_space &&
 		 obj->write_domain != I915_GEM_DOMAIN_CPU) {
-		ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
-		if (ret == -EFAULT) {
-			ret = i915_gem_gtt_pwrite_slow(dev, obj, args,
-						       file_priv);
-		}
-	} else if (i915_gem_object_needs_bit17_swizzle(obj)) {
-		ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file_priv);
+		ret = i915_gem_object_pin(obj, 0);
+		if (ret)
+			goto out;
+
+		ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+		if (ret)
+			goto out_unpin;
+
+		ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
+		if (ret == -EFAULT)
+			ret = i915_gem_gtt_pwrite_slow(dev, obj, args, file);
+
+out_unpin:
+		i915_gem_object_unpin(obj);
 	} else {
-		ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file_priv);
-		if (ret == -EFAULT) {
-			ret = i915_gem_shmem_pwrite_slow(dev, obj, args,
-							 file_priv);
-		}
-	}
+		ret = i915_gem_object_get_pages_or_evict(obj);
+		if (ret)
+			goto out;
 
-#if WATCH_PWRITE
-	if (ret)
-		DRM_INFO("pwrite failed %d\n", ret);
-#endif
+		ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+		if (ret)
+			goto out_put;
 
-err:
-	drm_gem_object_unreference_unlocked(obj);
+		ret = -EFAULT;
+		if (!i915_gem_object_needs_bit17_swizzle(obj))
+			ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
+		if (ret == -EFAULT)
+			ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+
+out_put:
+		i915_gem_object_put_pages(obj);
+	}
+
+out:
+	drm_gem_object_unreference(obj);
+unlock:
+	mutex_unlock(&dev->struct_mutex);
 	return ret;
 }
 
@@ -1014,19 +1091,19 @@
 	if (write_domain != 0 && read_domains != write_domain)
 		return -EINVAL;
 
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-	if (obj == NULL)
-		return -ENOENT;
+	if (obj == NULL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
 	obj_priv = to_intel_bo(obj);
 
-	mutex_lock(&dev->struct_mutex);
-
 	intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-	DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
-		 obj, obj->size, read_domains, write_domain);
-#endif
 	if (read_domains & I915_GEM_DOMAIN_GTT) {
 		ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
 
@@ -1050,12 +1127,12 @@
 		ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
 	}
 
-	
 	/* Maintain LRU order of "inactive" objects */
 	if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
-		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+		list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
 
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
 	return ret;
 }
@@ -1069,30 +1146,27 @@
 {
 	struct drm_i915_gem_sw_finish *args = data;
 	struct drm_gem_object *obj;
-	struct drm_i915_gem_object *obj_priv;
 	int ret = 0;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM))
 		return -ENODEV;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
-		mutex_unlock(&dev->struct_mutex);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto unlock;
 	}
 
-#if WATCH_BUF
-	DRM_INFO("%s: sw_finish %d (%p %zd)\n",
-		 __func__, args->handle, obj, obj->size);
-#endif
-	obj_priv = to_intel_bo(obj);
-
 	/* Pinned buffers may be scanout, so flush the cache */
-	if (obj_priv->pin_count)
+	if (to_intel_bo(obj)->pin_count)
 		i915_gem_object_flush_cpu_write_domain(obj);
 
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
 	return ret;
 }
@@ -1181,13 +1255,13 @@
 
 	/* Need a new fence register? */
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
-		ret = i915_gem_object_get_fence_reg(obj);
+		ret = i915_gem_object_get_fence_reg(obj, true);
 		if (ret)
 			goto unlock;
 	}
 
 	if (i915_gem_object_is_inactive(obj_priv))
-		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+		list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
 
 	pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
 		page_offset;
@@ -1246,7 +1320,7 @@
 						    obj->size / PAGE_SIZE, 0, 0);
 	if (!list->file_offset_node) {
 		DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
-		ret = -ENOMEM;
+		ret = -ENOSPC;
 		goto out_free_list;
 	}
 
@@ -1258,9 +1332,9 @@
 	}
 
 	list->hash.key = list->file_offset_node->start;
-	if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+	ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+	if (ret) {
 		DRM_ERROR("failed to add to map hash\n");
-		ret = -ENOMEM;
 		goto out_free_mm;
 	}
 
@@ -1345,14 +1419,14 @@
 	 * Minimum alignment is 4k (GTT page size), but might be greater
 	 * if a fence register is needed for the object.
 	 */
-	if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE)
+	if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
 		return 4096;
 
 	/*
 	 * Previous chips need to be aligned to the size of the smallest
 	 * fence register that can contain the object.
 	 */
-	if (IS_I9XX(dev))
+	if (INTEL_INFO(dev)->gen == 3)
 		start = 1024*1024;
 	else
 		start = 512*1024;
@@ -1390,29 +1464,27 @@
 	if (!(dev->driver->driver_features & DRIVER_GEM))
 		return -ENODEV;
 
-	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-	if (obj == NULL)
-		return -ENOENT;
-
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL) {
+		ret = -ENOENT;
+		goto unlock;
+	}
 	obj_priv = to_intel_bo(obj);
 
 	if (obj_priv->madv != I915_MADV_WILLNEED) {
 		DRM_ERROR("Attempting to mmap a purgeable buffer\n");
-		drm_gem_object_unreference(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
-
 	if (!obj_priv->mmap_offset) {
 		ret = i915_gem_create_mmap_offset(obj);
-		if (ret) {
-			drm_gem_object_unreference(obj);
-			mutex_unlock(&dev->struct_mutex);
-			return ret;
-		}
+		if (ret)
+			goto out;
 	}
 
 	args->offset = obj_priv->mmap_offset;
@@ -1423,20 +1495,18 @@
 	 */
 	if (!obj_priv->agp_mem) {
 		ret = i915_gem_object_bind_to_gtt(obj, 0);
-		if (ret) {
-			drm_gem_object_unreference(obj);
-			mutex_unlock(&dev->struct_mutex);
-			return ret;
-		}
+		if (ret)
+			goto out;
 	}
 
+out:
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
-
-	return 0;
+	return ret;
 }
 
-void
+static void
 i915_gem_object_put_pages(struct drm_gem_object *obj)
 {
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1470,13 +1540,25 @@
 	obj_priv->pages = NULL;
 }
 
+static uint32_t
+i915_gem_next_request_seqno(struct drm_device *dev,
+			    struct intel_ring_buffer *ring)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	ring->outstanding_lazy_request = true;
+	return dev_priv->next_seqno;
+}
+
 static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+i915_gem_object_move_to_active(struct drm_gem_object *obj,
 			       struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+	uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
+
 	BUG_ON(ring == NULL);
 	obj_priv->ring = ring;
 
@@ -1485,10 +1567,10 @@
 		drm_gem_object_reference(obj);
 		obj_priv->active = 1;
 	}
+
 	/* Move from whatever list we were on to the tail of execution. */
-	spin_lock(&dev_priv->mm.active_list_lock);
-	list_move_tail(&obj_priv->list, &ring->active_list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
+	list_move_tail(&obj_priv->mm_list, &dev_priv->mm.active_list);
+	list_move_tail(&obj_priv->ring_list, &ring->active_list);
 	obj_priv->last_rendering_seqno = seqno;
 }
 
@@ -1500,7 +1582,8 @@
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
 	BUG_ON(!obj_priv->active);
-	list_move_tail(&obj_priv->list, &dev_priv->mm.flushing_list);
+	list_move_tail(&obj_priv->mm_list, &dev_priv->mm.flushing_list);
+	list_del_init(&obj_priv->ring_list);
 	obj_priv->last_rendering_seqno = 0;
 }
 
@@ -1538,11 +1621,11 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
 	if (obj_priv->pin_count != 0)
-		list_del_init(&obj_priv->list);
+		list_move_tail(&obj_priv->mm_list, &dev_priv->mm.pinned_list);
 	else
-		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+		list_move_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+	list_del_init(&obj_priv->ring_list);
 
 	BUG_ON(!list_empty(&obj_priv->gpu_write_list));
 
@@ -1552,30 +1635,28 @@
 		obj_priv->active = 0;
 		drm_gem_object_unreference(obj);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 }
 
 static void
 i915_gem_process_flushing_list(struct drm_device *dev,
-			       uint32_t flush_domains, uint32_t seqno,
+			       uint32_t flush_domains,
 			       struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv, *next;
 
 	list_for_each_entry_safe(obj_priv, next,
-				 &dev_priv->mm.gpu_write_list,
+				 &ring->gpu_write_list,
 				 gpu_write_list) {
 		struct drm_gem_object *obj = &obj_priv->base;
 
-		if ((obj->write_domain & flush_domains) ==
-		    obj->write_domain &&
-		    obj_priv->ring->ring_flag == ring->ring_flag) {
+		if (obj->write_domain & flush_domains) {
 			uint32_t old_write_domain = obj->write_domain;
 
 			obj->write_domain = 0;
 			list_del_init(&obj_priv->gpu_write_list);
-			i915_gem_object_move_to_active(obj, seqno, ring);
+			i915_gem_object_move_to_active(obj, ring);
 
 			/* update the fence lru list */
 			if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1593,23 +1674,27 @@
 }
 
 uint32_t
-i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
-		 uint32_t flush_domains, struct intel_ring_buffer *ring)
+i915_add_request(struct drm_device *dev,
+		 struct drm_file *file,
+		 struct drm_i915_gem_request *request,
+		 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_file_private *i915_file_priv = NULL;
-	struct drm_i915_gem_request *request;
+	struct drm_i915_file_private *file_priv = NULL;
 	uint32_t seqno;
 	int was_empty;
 
-	if (file_priv != NULL)
-		i915_file_priv = file_priv->driver_priv;
+	if (file != NULL)
+		file_priv = file->driver_priv;
 
-	request = kzalloc(sizeof(*request), GFP_KERNEL);
-	if (request == NULL)
-		return 0;
+	if (request == NULL) {
+		request = kzalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return 0;
+	}
 
-	seqno = ring->add_request(dev, ring, file_priv, flush_domains);
+	seqno = ring->add_request(dev, ring, 0);
+	ring->outstanding_lazy_request = false;
 
 	request->seqno = seqno;
 	request->ring = ring;
@@ -1617,23 +1702,20 @@
 	was_empty = list_empty(&ring->request_list);
 	list_add_tail(&request->list, &ring->request_list);
 
-	if (i915_file_priv) {
+	if (file_priv) {
+		spin_lock(&file_priv->mm.lock);
+		request->file_priv = file_priv;
 		list_add_tail(&request->client_list,
-			      &i915_file_priv->mm.request_list);
-	} else {
-		INIT_LIST_HEAD(&request->client_list);
+			      &file_priv->mm.request_list);
+		spin_unlock(&file_priv->mm.lock);
 	}
 
-	/* Associate any objects on the flushing list matching the write
-	 * domain we're flushing with our flush.
-	 */
-	if (flush_domains != 0) 
-		i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
-
 	if (!dev_priv->mm.suspended) {
-		mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+		mod_timer(&dev_priv->hangcheck_timer,
+			  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 		if (was_empty)
-			queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+			queue_delayed_work(dev_priv->wq,
+					   &dev_priv->mm.retire_work, HZ);
 	}
 	return seqno;
 }
@@ -1644,91 +1726,105 @@
  * Ensures that all commands in the ring are finished
  * before signalling the CPU
  */
-static uint32_t
+static void
 i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
 {
 	uint32_t flush_domains = 0;
 
 	/* The sampler always gets flushed on i965 (sigh) */
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		flush_domains |= I915_GEM_DOMAIN_SAMPLER;
 
 	ring->flush(dev, ring,
 			I915_GEM_DOMAIN_COMMAND, flush_domains);
-	return flush_domains;
 }
 
-/**
- * Moves buffers associated only with the given active seqno from the active
- * to inactive list, potentially freeing them.
- */
-static void
-i915_gem_retire_request(struct drm_device *dev,
-			struct drm_i915_gem_request *request)
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = request->file_priv;
 
-	trace_i915_gem_request_retire(dev, request->seqno);
+	if (!file_priv)
+		return;
 
-	/* Move any buffers on the active list that are no longer referenced
-	 * by the ringbuffer to the flushing/inactive lists as appropriate.
-	 */
-	spin_lock(&dev_priv->mm.active_list_lock);
-	while (!list_empty(&request->ring->active_list)) {
-		struct drm_gem_object *obj;
-		struct drm_i915_gem_object *obj_priv;
+	spin_lock(&file_priv->mm.lock);
+	list_del(&request->client_list);
+	request->file_priv = NULL;
+	spin_unlock(&file_priv->mm.lock);
+}
 
-		obj_priv = list_first_entry(&request->ring->active_list,
-					    struct drm_i915_gem_object,
-					    list);
-		obj = &obj_priv->base;
+static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
+				      struct intel_ring_buffer *ring)
+{
+	while (!list_empty(&ring->request_list)) {
+		struct drm_i915_gem_request *request;
 
-		/* If the seqno being retired doesn't match the oldest in the
-		 * list, then the oldest in the list must still be newer than
-		 * this seqno.
-		 */
-		if (obj_priv->last_rendering_seqno != request->seqno)
-			goto out;
+		request = list_first_entry(&ring->request_list,
+					   struct drm_i915_gem_request,
+					   list);
 
-#if WATCH_LRU
-		DRM_INFO("%s: retire %d moves to inactive list %p\n",
-			 __func__, request->seqno, obj);
-#endif
+		list_del(&request->list);
+		i915_gem_request_remove_from_client(request);
+		kfree(request);
+	}
 
-		if (obj->write_domain != 0)
-			i915_gem_object_move_to_flushing(obj);
-		else {
-			/* Take a reference on the object so it won't be
-			 * freed while the spinlock is held.  The list
-			 * protection for this spinlock is safe when breaking
-			 * the lock like this since the next thing we do
-			 * is just get the head of the list again.
-			 */
-			drm_gem_object_reference(obj);
-			i915_gem_object_move_to_inactive(obj);
-			spin_unlock(&dev_priv->mm.active_list_lock);
-			drm_gem_object_unreference(obj);
-			spin_lock(&dev_priv->mm.active_list_lock);
-		}
+	while (!list_empty(&ring->active_list)) {
+		struct drm_i915_gem_object *obj_priv;
+
+		obj_priv = list_first_entry(&ring->active_list,
+					    struct drm_i915_gem_object,
+					    ring_list);
+
+		obj_priv->base.write_domain = 0;
+		list_del_init(&obj_priv->gpu_write_list);
+		i915_gem_object_move_to_inactive(&obj_priv->base);
 	}
-out:
-	spin_unlock(&dev_priv->mm.active_list_lock);
 }
 
-/**
- * Returns true if seq1 is later than seq2.
- */
-bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+void i915_gem_reset(struct drm_device *dev)
 {
-	return (int32_t)(seq1 - seq2) >= 0;
-}
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj_priv;
+	int i;
 
-uint32_t
-i915_get_gem_seqno(struct drm_device *dev,
-		   struct intel_ring_buffer *ring)
-{
-	return ring->get_gem_seqno(dev, ring);
+	i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
+	i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
+	i915_gem_reset_ring_lists(dev_priv, &dev_priv->blt_ring);
+
+	/* Remove anything from the flushing lists. The GPU cache is likely
+	 * to be lost on reset along with the data, so simply move the
+	 * lost bo to the inactive list.
+	 */
+	while (!list_empty(&dev_priv->mm.flushing_list)) {
+		obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+					    struct drm_i915_gem_object,
+					    mm_list);
+
+		obj_priv->base.write_domain = 0;
+		list_del_init(&obj_priv->gpu_write_list);
+		i915_gem_object_move_to_inactive(&obj_priv->base);
+	}
+
+	/* Move everything out of the GPU domains to ensure we do any
+	 * necessary invalidation upon reuse.
+	 */
+	list_for_each_entry(obj_priv,
+			    &dev_priv->mm.inactive_list,
+			    mm_list)
+	{
+		obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+	}
+
+	/* The fence registers are invalidated so clear them out */
+	for (i = 0; i < 16; i++) {
+		struct drm_i915_fence_reg *reg;
+
+		reg = &dev_priv->fence_regs[i];
+		if (!reg->obj)
+			continue;
+
+		i915_gem_clear_fence_reg(reg->obj);
+	}
 }
 
 /**
@@ -1741,38 +1837,58 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	uint32_t seqno;
 
-	if (!ring->status_page.page_addr
-			|| list_empty(&ring->request_list))
+	if (!ring->status_page.page_addr ||
+	    list_empty(&ring->request_list))
 		return;
 
-	seqno = i915_get_gem_seqno(dev, ring);
+	WARN_ON(i915_verify_lists(dev));
 
+	seqno = ring->get_seqno(dev, ring);
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
-		uint32_t retiring_seqno;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
 					   list);
-		retiring_seqno = request->seqno;
 
-		if (i915_seqno_passed(seqno, retiring_seqno) ||
-		    atomic_read(&dev_priv->mm.wedged)) {
-			i915_gem_retire_request(dev, request);
+		if (!i915_seqno_passed(seqno, request->seqno))
+			break;
 
-			list_del(&request->list);
-			list_del(&request->client_list);
-			kfree(request);
-		} else
+		trace_i915_gem_request_retire(dev, request->seqno);
+
+		list_del(&request->list);
+		i915_gem_request_remove_from_client(request);
+		kfree(request);
+	}
+
+	/* Move any buffers on the active list that are no longer referenced
+	 * by the ringbuffer to the flushing/inactive lists as appropriate.
+	 */
+	while (!list_empty(&ring->active_list)) {
+		struct drm_gem_object *obj;
+		struct drm_i915_gem_object *obj_priv;
+
+		obj_priv = list_first_entry(&ring->active_list,
+					    struct drm_i915_gem_object,
+					    ring_list);
+
+		if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
 			break;
+
+		obj = &obj_priv->base;
+		if (obj->write_domain != 0)
+			i915_gem_object_move_to_flushing(obj);
+		else
+			i915_gem_object_move_to_inactive(obj);
 	}
 
 	if (unlikely (dev_priv->trace_irq_seqno &&
 		      i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-
 		ring->user_irq_put(dev, ring);
 		dev_priv->trace_irq_seqno = 0;
 	}
+
+	WARN_ON(i915_verify_lists(dev));
 }
 
 void
@@ -1790,16 +1906,16 @@
 	     */
 	    list_for_each_entry_safe(obj_priv, tmp,
 				     &dev_priv->mm.deferred_free_list,
-				     list)
+				     mm_list)
 		    i915_gem_free_object_tail(&obj_priv->base);
 	}
 
 	i915_gem_retire_requests_ring(dev, &dev_priv->render_ring);
-	if (HAS_BSD(dev))
-		i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+	i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
+	i915_gem_retire_requests_ring(dev, &dev_priv->blt_ring);
 }
 
-void
+static void
 i915_gem_retire_work_handler(struct work_struct *work)
 {
 	drm_i915_private_t *dev_priv;
@@ -1809,20 +1925,25 @@
 				mm.retire_work.work);
 	dev = dev_priv->dev;
 
-	mutex_lock(&dev->struct_mutex);
+	/* Come back later if the device is busy... */
+	if (!mutex_trylock(&dev->struct_mutex)) {
+		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+		return;
+	}
+
 	i915_gem_retire_requests(dev);
 
 	if (!dev_priv->mm.suspended &&
 		(!list_empty(&dev_priv->render_ring.request_list) ||
-			(HAS_BSD(dev) &&
-			 !list_empty(&dev_priv->bsd_ring.request_list))))
+		 !list_empty(&dev_priv->bsd_ring.request_list) ||
+		 !list_empty(&dev_priv->blt_ring.request_list)))
 		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
 	mutex_unlock(&dev->struct_mutex);
 }
 
 int
 i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
-		int interruptible, struct intel_ring_buffer *ring)
+		     bool interruptible, struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 ier;
@@ -1831,9 +1952,16 @@
 	BUG_ON(seqno == 0);
 
 	if (atomic_read(&dev_priv->mm.wedged))
-		return -EIO;
+		return -EAGAIN;
 
-	if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
+	if (ring->outstanding_lazy_request) {
+		seqno = i915_add_request(dev, NULL, NULL, ring);
+		if (seqno == 0)
+			return -ENOMEM;
+	}
+	BUG_ON(seqno == dev_priv->next_seqno);
+
+	if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
 		if (HAS_PCH_SPLIT(dev))
 			ier = I915_READ(DEIER) | I915_READ(GTIER);
 		else
@@ -1852,12 +1980,12 @@
 		if (interruptible)
 			ret = wait_event_interruptible(ring->irq_queue,
 				i915_seqno_passed(
-					ring->get_gem_seqno(dev, ring), seqno)
+					ring->get_seqno(dev, ring), seqno)
 				|| atomic_read(&dev_priv->mm.wedged));
 		else
 			wait_event(ring->irq_queue,
 				i915_seqno_passed(
-					ring->get_gem_seqno(dev, ring), seqno)
+					ring->get_seqno(dev, ring), seqno)
 				|| atomic_read(&dev_priv->mm.wedged));
 
 		ring->user_irq_put(dev, ring);
@@ -1866,11 +1994,12 @@
 		trace_i915_gem_request_wait_end(dev, seqno);
 	}
 	if (atomic_read(&dev_priv->mm.wedged))
-		ret = -EIO;
+		ret = -EAGAIN;
 
 	if (ret && ret != -ERESTARTSYS)
-		DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
-			  __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
+		DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
+			  __func__, ret, seqno, ring->get_seqno(dev, ring),
+			  dev_priv->next_seqno);
 
 	/* Directly dispatch request retiring.  While we have the work queue
 	 * to handle this, the waiter on a request often wants an associated
@@ -1889,27 +2018,48 @@
  */
 static int
 i915_wait_request(struct drm_device *dev, uint32_t seqno,
-		struct intel_ring_buffer *ring)
+		  struct intel_ring_buffer *ring)
 {
 	return i915_do_wait_request(dev, seqno, 1, ring);
 }
 
 static void
+i915_gem_flush_ring(struct drm_device *dev,
+		    struct drm_file *file_priv,
+		    struct intel_ring_buffer *ring,
+		    uint32_t invalidate_domains,
+		    uint32_t flush_domains)
+{
+	ring->flush(dev, ring, invalidate_domains, flush_domains);
+	i915_gem_process_flushing_list(dev, flush_domains, ring);
+}
+
+static void
 i915_gem_flush(struct drm_device *dev,
+	       struct drm_file *file_priv,
 	       uint32_t invalidate_domains,
-	       uint32_t flush_domains)
+	       uint32_t flush_domains,
+	       uint32_t flush_rings)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
+
 	if (flush_domains & I915_GEM_DOMAIN_CPU)
 		drm_agp_chipset_flush(dev);
-	dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
-			invalidate_domains,
-			flush_domains);
 
-	if (HAS_BSD(dev))
-		dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
-				invalidate_domains,
-				flush_domains);
+	if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+		if (flush_rings & RING_RENDER)
+			i915_gem_flush_ring(dev, file_priv,
+					    &dev_priv->render_ring,
+					    invalidate_domains, flush_domains);
+		if (flush_rings & RING_BSD)
+			i915_gem_flush_ring(dev, file_priv,
+					    &dev_priv->bsd_ring,
+					    invalidate_domains, flush_domains);
+		if (flush_rings & RING_BLT)
+			i915_gem_flush_ring(dev, file_priv,
+					    &dev_priv->blt_ring,
+					    invalidate_domains, flush_domains);
+	}
 }
 
 /**
@@ -1917,7 +2067,8 @@
  * safe to unbind from the GTT or access from the CPU.
  */
 static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+			       bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1932,13 +2083,11 @@
 	 * it.
 	 */
 	if (obj_priv->active) {
-#if WATCH_BUF
-		DRM_INFO("%s: object %p wait for seqno %08x\n",
-			  __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-		ret = i915_wait_request(dev,
-				obj_priv->last_rendering_seqno, obj_priv->ring);
-		if (ret != 0)
+		ret = i915_do_wait_request(dev,
+					   obj_priv->last_rendering_seqno,
+					   interruptible,
+					   obj_priv->ring);
+		if (ret)
 			return ret;
 	}
 
@@ -1952,14 +2101,10 @@
 i915_gem_object_unbind(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret = 0;
 
-#if WATCH_BUF
-	DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
-	DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
-#endif
 	if (obj_priv->gtt_space == NULL)
 		return 0;
 
@@ -1984,33 +2129,27 @@
 	 * should be safe and we need to cleanup or else we might
 	 * cause memory corruption through use-after-free.
 	 */
+	if (ret) {
+		i915_gem_clflush_object(obj);
+		obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+	}
 
 	/* release the fence reg _after_ flushing */
 	if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
 		i915_gem_clear_fence_reg(obj);
 
-	if (obj_priv->agp_mem != NULL) {
-		drm_unbind_agp(obj_priv->agp_mem);
-		drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
-		obj_priv->agp_mem = NULL;
-	}
+	drm_unbind_agp(obj_priv->agp_mem);
+	drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
 
 	i915_gem_object_put_pages(obj);
 	BUG_ON(obj_priv->pages_refcount);
 
-	if (obj_priv->gtt_space) {
-		atomic_dec(&dev->gtt_count);
-		atomic_sub(obj->size, &dev->gtt_memory);
-
-		drm_mm_put_block(obj_priv->gtt_space);
-		obj_priv->gtt_space = NULL;
-	}
+	i915_gem_info_remove_gtt(dev_priv, obj->size);
+	list_del_init(&obj_priv->mm_list);
 
-	/* Remove ourselves from the LRU list if present. */
-	spin_lock(&dev_priv->mm.active_list_lock);
-	if (!list_empty(&obj_priv->list))
-		list_del_init(&obj_priv->list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
+	drm_mm_put_block(obj_priv->gtt_space);
+	obj_priv->gtt_space = NULL;
+	obj_priv->gtt_offset = 0;
 
 	if (i915_gem_object_is_purgeable(obj_priv))
 		i915_gem_object_truncate(obj);
@@ -2020,48 +2159,48 @@
 	return ret;
 }
 
+static int i915_ring_idle(struct drm_device *dev,
+			  struct intel_ring_buffer *ring)
+{
+	if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
+		return 0;
+
+	i915_gem_flush_ring(dev, NULL, ring,
+			    I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+	return i915_wait_request(dev,
+				 i915_gem_next_request_seqno(dev, ring),
+				 ring);
+}
+
 int
 i915_gpu_idle(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	bool lists_empty;
-	uint32_t seqno1, seqno2;
 	int ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
-		       list_empty(&dev_priv->render_ring.active_list) &&
-		       (!HAS_BSD(dev) ||
-			list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
+		       list_empty(&dev_priv->mm.active_list));
 	if (lists_empty)
 		return 0;
 
 	/* Flush everything onto the inactive list. */
-	i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
-	seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-			&dev_priv->render_ring);
-	if (seqno1 == 0)
-		return -ENOMEM;
-	ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
-
-	if (HAS_BSD(dev)) {
-		seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-				&dev_priv->bsd_ring);
-		if (seqno2 == 0)
-			return -ENOMEM;
+	ret = i915_ring_idle(dev, &dev_priv->render_ring);
+	if (ret)
+		return ret;
 
-		ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
-		if (ret)
-			return ret;
-	}
+	ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
+	if (ret)
+		return ret;
 
+	ret = i915_ring_idle(dev, &dev_priv->blt_ring);
+	if (ret)
+		return ret;
 
-	return ret;
+	return 0;
 }
 
-int
+static int
 i915_gem_object_get_pages(struct drm_gem_object *obj,
 			  gfp_t gfpmask)
 {
@@ -2241,7 +2380,8 @@
 	I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
 }
 
-static int i915_find_fence_reg(struct drm_device *dev)
+static int i915_find_fence_reg(struct drm_device *dev,
+			       bool interruptible)
 {
 	struct drm_i915_fence_reg *reg = NULL;
 	struct drm_i915_gem_object *obj_priv = NULL;
@@ -2286,7 +2426,7 @@
 	 * private reference to obj like the other callers of put_fence_reg
 	 * (set_tiling ioctl) do. */
 	drm_gem_object_reference(obj);
-	ret = i915_gem_object_put_fence_reg(obj);
+	ret = i915_gem_object_put_fence_reg(obj, interruptible);
 	drm_gem_object_unreference(obj);
 	if (ret != 0)
 		return ret;
@@ -2308,7 +2448,8 @@
  * and tiling format.
  */
 int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+			      bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2343,7 +2484,7 @@
 		break;
 	}
 
-	ret = i915_find_fence_reg(dev);
+	ret = i915_find_fence_reg(dev, interruptible);
 	if (ret < 0)
 		return ret;
 
@@ -2421,15 +2562,19 @@
  * i915_gem_object_put_fence_reg - waits on outstanding fenced access
  * to the buffer to finish, and then resets the fence register.
  * @obj: tiled object holding a fence register.
+ * @bool: whether the wait upon the fence is interruptible
  *
  * Zeroes out the fence register itself and clears out the associated
  * data structures in dev_priv and obj_priv.
  */
 int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+			      bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+	struct drm_i915_fence_reg *reg;
 
 	if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
 		return 0;
@@ -2444,20 +2589,23 @@
 	 * therefore we must wait for any outstanding access to complete
 	 * before clearing the fence.
 	 */
-	if (!IS_I965G(dev)) {
+	reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+	if (reg->gpu) {
 		int ret;
 
 		ret = i915_gem_object_flush_gpu_write_domain(obj);
-		if (ret != 0)
+		if (ret)
 			return ret;
 
-		ret = i915_gem_object_wait_rendering(obj);
-		if (ret != 0)
+		ret = i915_gem_object_wait_rendering(obj, interruptible);
+		if (ret)
 			return ret;
+
+		reg->gpu = false;
 	}
 
 	i915_gem_object_flush_gtt_write_domain(obj);
-	i915_gem_clear_fence_reg (obj);
+	i915_gem_clear_fence_reg(obj);
 
 	return 0;
 }
@@ -2490,7 +2638,7 @@
 	/* If the object is bigger than the entire aperture, reject it early
 	 * before evicting everything in a vain attempt to find space.
 	 */
-	if (obj->size > dev->gtt_total) {
+	if (obj->size > dev_priv->mm.gtt_total) {
 		DRM_ERROR("Attempting to bind an object larger than the aperture\n");
 		return -E2BIG;
 	}
@@ -2498,19 +2646,13 @@
  search_free:
 	free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
 					obj->size, alignment, 0);
-	if (free_space != NULL) {
+	if (free_space != NULL)
 		obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size,
 						       alignment);
-		if (obj_priv->gtt_space != NULL)
-			obj_priv->gtt_offset = obj_priv->gtt_space->start;
-	}
 	if (obj_priv->gtt_space == NULL) {
 		/* If the gtt is empty and we're still having trouble
 		 * fitting our object in, we're out of memory.
 		 */
-#if WATCH_LRU
-		DRM_INFO("%s: GTT full, evicting something\n", __func__);
-#endif
 		ret = i915_gem_evict_something(dev, obj->size, alignment);
 		if (ret)
 			return ret;
@@ -2518,10 +2660,6 @@
 		goto search_free;
 	}
 
-#if WATCH_BUF
-	DRM_INFO("Binding object of size %zd at 0x%08x\n",
-		 obj->size, obj_priv->gtt_offset);
-#endif
 	ret = i915_gem_object_get_pages(obj, gfpmask);
 	if (ret) {
 		drm_mm_put_block(obj_priv->gtt_space);
@@ -2553,7 +2691,7 @@
 	obj_priv->agp_mem = drm_agp_bind_pages(dev,
 					       obj_priv->pages,
 					       obj->size >> PAGE_SHIFT,
-					       obj_priv->gtt_offset,
+					       obj_priv->gtt_space->start,
 					       obj_priv->agp_type);
 	if (obj_priv->agp_mem == NULL) {
 		i915_gem_object_put_pages(obj);
@@ -2566,11 +2704,10 @@
 
 		goto search_free;
 	}
-	atomic_inc(&dev->gtt_count);
-	atomic_add(obj->size, &dev->gtt_memory);
 
 	/* keep track of bounds object by adding it to the inactive list */
-	list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+	list_add_tail(&obj_priv->mm_list, &dev_priv->mm.inactive_list);
+	i915_gem_info_add_gtt(dev_priv, obj->size);
 
 	/* Assert that the object is not currently in any GPU domain. As it
 	 * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2579,6 +2716,7 @@
 	BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
 	BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
 
+	obj_priv->gtt_offset = obj_priv->gtt_space->start;
 	trace_i915_gem_object_bind(obj, obj_priv->gtt_offset);
 
 	return 0;
@@ -2607,20 +2745,21 @@
 {
 	struct drm_device *dev = obj->dev;
 	uint32_t old_write_domain;
-	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
 	if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
 		return 0;
 
 	/* Queue the GPU write cache flushing we need. */
 	old_write_domain = obj->write_domain;
-	i915_gem_flush(dev, 0, obj->write_domain);
-	if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
-		return -ENOMEM;
+	i915_gem_flush_ring(dev, NULL,
+			    to_intel_bo(obj)->ring,
+			    0, obj->write_domain);
+	BUG_ON(obj->write_domain);
 
 	trace_i915_gem_object_change_domain(obj,
 					    obj->read_domains,
 					    old_write_domain);
+
 	return 0;
 }
 
@@ -2665,26 +2804,6 @@
 					    old_write_domain);
 }
 
-int
-i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
-{
-	int ret = 0;
-
-	switch (obj->write_domain) {
-	case I915_GEM_DOMAIN_GTT:
-		i915_gem_object_flush_gtt_write_domain(obj);
-		break;
-	case I915_GEM_DOMAIN_CPU:
-		i915_gem_object_flush_cpu_write_domain(obj);
-		break;
-	default:
-		ret = i915_gem_object_flush_gpu_write_domain(obj);
-		break;
-	}
-
-	return ret;
-}
-
 /**
  * Moves a single object to the GTT read, and possibly write domain.
  *
@@ -2705,29 +2824,22 @@
 	ret = i915_gem_object_flush_gpu_write_domain(obj);
 	if (ret != 0)
 		return ret;
-
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
-	if (ret != 0)
+	ret = i915_gem_object_wait_rendering(obj, true);
+	if (ret)
 		return ret;
 
+	i915_gem_object_flush_cpu_write_domain(obj);
+
 	old_write_domain = obj->write_domain;
 	old_read_domains = obj->read_domains;
 
-	/* If we're writing through the GTT domain, then CPU and GPU caches
-	 * will need to be invalidated at next use.
-	 */
-	if (write)
-		obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
-	i915_gem_object_flush_cpu_write_domain(obj);
-
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
 	BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
 	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 	if (write) {
+		obj->read_domains = I915_GEM_DOMAIN_GTT;
 		obj->write_domain = I915_GEM_DOMAIN_GTT;
 		obj_priv->dirty = 1;
 	}
@@ -2744,11 +2856,11 @@
  * wait, as in modesetting process we're not supposed to be interrupted.
  */
 int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+				     bool pipelined)
 {
-	struct drm_device *dev = obj->dev;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-	uint32_t old_write_domain, old_read_domains;
+	uint32_t old_read_domains;
 	int ret;
 
 	/* Not valid to be called on unbound objects. */
@@ -2759,40 +2871,39 @@
 	if (ret)
 		return ret;
 
-	/* Wait on any GPU rendering and flushing to occur. */
-	if (obj_priv->active) {
-#if WATCH_BUF
-		DRM_INFO("%s: object %p wait for seqno %08x\n",
-			  __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-		ret = i915_do_wait_request(dev,
-				obj_priv->last_rendering_seqno,
-				0,
-				obj_priv->ring);
-		if (ret != 0)
+	/* Currently, we are always called from an non-interruptible context. */
+	if (!pipelined) {
+		ret = i915_gem_object_wait_rendering(obj, false);
+		if (ret)
 			return ret;
 	}
 
 	i915_gem_object_flush_cpu_write_domain(obj);
 
-	old_write_domain = obj->write_domain;
 	old_read_domains = obj->read_domains;
-
-	/* It should now be out of any other write domains, and we can update
-	 * the domain values for our changes.
-	 */
-	BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-	obj->read_domains = I915_GEM_DOMAIN_GTT;
-	obj->write_domain = I915_GEM_DOMAIN_GTT;
-	obj_priv->dirty = 1;
+	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 
 	trace_i915_gem_object_change_domain(obj,
 					    old_read_domains,
-					    old_write_domain);
+					    obj->write_domain);
 
 	return 0;
 }
 
+int
+i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+			  bool interruptible)
+{
+	if (!obj->active)
+		return 0;
+
+	if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
+		i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
+				    0, obj->base.write_domain);
+
+	return i915_gem_object_wait_rendering(&obj->base, interruptible);
+}
+
 /**
  * Moves a single object to the CPU read, and possibly write domain.
  *
@@ -2806,13 +2917,11 @@
 	int ret;
 
 	ret = i915_gem_object_flush_gpu_write_domain(obj);
-	if (ret)
-		return ret;
-
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
 	if (ret != 0)
 		return ret;
+	ret = i915_gem_object_wait_rendering(obj, true);
+	if (ret)
+		return ret;
 
 	i915_gem_object_flush_gtt_write_domain(obj);
 
@@ -2840,7 +2949,7 @@
 	 * need to be invalidated at next use.
 	 */
 	if (write) {
-		obj->read_domains &= I915_GEM_DOMAIN_CPU;
+		obj->read_domains = I915_GEM_DOMAIN_CPU;
 		obj->write_domain = I915_GEM_DOMAIN_CPU;
 	}
 
@@ -2963,26 +3072,18 @@
  *		drm_agp_chipset_flush
  */
 static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
+i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
+				  struct intel_ring_buffer *ring)
 {
 	struct drm_device		*dev = obj->dev;
-	drm_i915_private_t		*dev_priv = dev->dev_private;
+	struct drm_i915_private		*dev_priv = dev->dev_private;
 	struct drm_i915_gem_object	*obj_priv = to_intel_bo(obj);
 	uint32_t			invalidate_domains = 0;
 	uint32_t			flush_domains = 0;
 	uint32_t			old_read_domains;
 
-	BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
-	BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
-
 	intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-	DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
-		 __func__, obj,
-		 obj->read_domains, obj->pending_read_domains,
-		 obj->write_domain, obj->pending_write_domain);
-#endif
 	/*
 	 * If the object isn't moving to a new write domain,
 	 * let the object stay in multiple read domains
@@ -2999,7 +3100,8 @@
 	 * write domain
 	 */
 	if (obj->write_domain &&
-	    obj->write_domain != obj->pending_read_domains) {
+	    (obj->write_domain != obj->pending_read_domains ||
+	     obj_priv->ring != ring)) {
 		flush_domains |= obj->write_domain;
 		invalidate_domains |=
 			obj->pending_read_domains & ~obj->write_domain;
@@ -3009,13 +3111,8 @@
 	 * stale data. That is, any new read domains.
 	 */
 	invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
-	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
-#if WATCH_BUF
-		DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
-			 __func__, flush_domains, invalidate_domains);
-#endif
+	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
 		i915_gem_clflush_object(obj);
-	}
 
 	old_read_domains = obj->read_domains;
 
@@ -3029,21 +3126,12 @@
 		obj->pending_write_domain = obj->write_domain;
 	obj->read_domains = obj->pending_read_domains;
 
-	if (flush_domains & I915_GEM_GPU_DOMAINS) {
-		if (obj_priv->ring == &dev_priv->render_ring)
-			dev_priv->flush_rings |= FLUSH_RENDER_RING;
-		else if (obj_priv->ring == &dev_priv->bsd_ring)
-			dev_priv->flush_rings |= FLUSH_BSD_RING;
-	}
-
 	dev->invalidate_domains |= invalidate_domains;
 	dev->flush_domains |= flush_domains;
-#if WATCH_BUF
-	DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
-		 __func__,
-		 obj->read_domains, obj->write_domain,
-		 dev->invalidate_domains, dev->flush_domains);
-#endif
+	if (flush_domains & I915_GEM_GPU_DOMAINS)
+		dev_priv->mm.flush_rings |= obj_priv->ring->id;
+	if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+		dev_priv->mm.flush_rings |= ring->id;
 
 	trace_i915_gem_object_change_domain(obj,
 					    old_read_domains,
@@ -3107,13 +3195,12 @@
 		return i915_gem_object_set_to_cpu_domain(obj, 0);
 
 	ret = i915_gem_object_flush_gpu_write_domain(obj);
+	if (ret != 0)
+		return ret;
+	ret = i915_gem_object_wait_rendering(obj, true);
 	if (ret)
 		return ret;
 
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
-	if (ret != 0)
-		return ret;
 	i915_gem_object_flush_gtt_write_domain(obj);
 
 	/* If we're already fully in the CPU read domain, we're done. */
@@ -3160,339 +3247,478 @@
 	return 0;
 }
 
-/**
- * Pin an object to the GTT and evaluate the relocations landing in it.
- */
 static int
-i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
-				 struct drm_file *file_priv,
-				 struct drm_i915_gem_exec_object2 *entry,
-				 struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
+				   struct drm_file *file_priv,
+				   struct drm_i915_gem_exec_object2 *entry,
+				   struct drm_i915_gem_relocation_entry *reloc)
 {
-	struct drm_device *dev = obj->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-	int i, ret;
-	void __iomem *reloc_page;
-	bool need_fence;
+	struct drm_device *dev = obj->base.dev;
+	struct drm_gem_object *target_obj;
+	uint32_t target_offset;
+	int ret = -EINVAL;
 
-	need_fence = entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-	             obj_priv->tiling_mode != I915_TILING_NONE;
+	target_obj = drm_gem_object_lookup(dev, file_priv,
+					   reloc->target_handle);
+	if (target_obj == NULL)
+		return -ENOENT;
 
-	/* Check fence reg constraints and rebind if necessary */
-	if (need_fence &&
-	    !i915_gem_object_fence_offset_ok(obj,
-					     obj_priv->tiling_mode)) {
-		ret = i915_gem_object_unbind(obj);
-		if (ret)
-			return ret;
-	}
+	target_offset = to_intel_bo(target_obj)->gtt_offset;
 
-	/* Choose the GTT offset for our buffer and put it there. */
-	ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
-	if (ret)
-		return ret;
+#if WATCH_RELOC
+	DRM_INFO("%s: obj %p offset %08x target %d "
+		 "read %08x write %08x gtt %08x "
+		 "presumed %08x delta %08x\n",
+		 __func__,
+		 obj,
+		 (int) reloc->offset,
+		 (int) reloc->target_handle,
+		 (int) reloc->read_domains,
+		 (int) reloc->write_domain,
+		 (int) target_offset,
+		 (int) reloc->presumed_offset,
+		 reloc->delta);
+#endif
 
-	/*
-	 * Pre-965 chips need a fence register set up in order to
-	 * properly handle blits to/from tiled surfaces.
+	/* The target buffer should have appeared before us in the
+	 * exec_object list, so it should have a GTT space bound by now.
 	 */
-	if (need_fence) {
-		ret = i915_gem_object_get_fence_reg(obj);
-		if (ret != 0) {
-			i915_gem_object_unpin(obj);
-			return ret;
-		}
+	if (target_offset == 0) {
+		DRM_ERROR("No GTT space found for object %d\n",
+			  reloc->target_handle);
+		goto err;
 	}
 
-	entry->offset = obj_priv->gtt_offset;
+	/* Validate that the target is in a valid r/w GPU domain */
+	if (reloc->write_domain & (reloc->write_domain - 1)) {
+		DRM_ERROR("reloc with multiple write domains: "
+			  "obj %p target %d offset %d "
+			  "read %08x write %08x",
+			  obj, reloc->target_handle,
+			  (int) reloc->offset,
+			  reloc->read_domains,
+			  reloc->write_domain);
+		goto err;
+	}
+	if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
+	    reloc->read_domains & I915_GEM_DOMAIN_CPU) {
+		DRM_ERROR("reloc with read/write CPU domains: "
+			  "obj %p target %d offset %d "
+			  "read %08x write %08x",
+			  obj, reloc->target_handle,
+			  (int) reloc->offset,
+			  reloc->read_domains,
+			  reloc->write_domain);
+		goto err;
+	}
+	if (reloc->write_domain && target_obj->pending_write_domain &&
+	    reloc->write_domain != target_obj->pending_write_domain) {
+		DRM_ERROR("Write domain conflict: "
+			  "obj %p target %d offset %d "
+			  "new %08x old %08x\n",
+			  obj, reloc->target_handle,
+			  (int) reloc->offset,
+			  reloc->write_domain,
+			  target_obj->pending_write_domain);
+		goto err;
+	}
 
-	/* Apply the relocations, using the GTT aperture to avoid cache
-	 * flushing requirements.
+	target_obj->pending_read_domains |= reloc->read_domains;
+	target_obj->pending_write_domain |= reloc->write_domain;
+
+	/* If the relocation already has the right value in it, no
+	 * more work needs to be done.
 	 */
-	for (i = 0; i < entry->relocation_count; i++) {
-		struct drm_i915_gem_relocation_entry *reloc= &relocs[i];
-		struct drm_gem_object *target_obj;
-		struct drm_i915_gem_object *target_obj_priv;
-		uint32_t reloc_val, reloc_offset;
+	if (target_offset == reloc->presumed_offset)
+		goto out;
+
+	/* Check that the relocation address is valid... */
+	if (reloc->offset > obj->base.size - 4) {
+		DRM_ERROR("Relocation beyond object bounds: "
+			  "obj %p target %d offset %d size %d.\n",
+			  obj, reloc->target_handle,
+			  (int) reloc->offset,
+			  (int) obj->base.size);
+		goto err;
+	}
+	if (reloc->offset & 3) {
+		DRM_ERROR("Relocation not 4-byte aligned: "
+			  "obj %p target %d offset %d.\n",
+			  obj, reloc->target_handle,
+			  (int) reloc->offset);
+		goto err;
+	}
+
+	/* and points to somewhere within the target object. */
+	if (reloc->delta >= target_obj->size) {
+		DRM_ERROR("Relocation beyond target object bounds: "
+			  "obj %p target %d delta %d size %d.\n",
+			  obj, reloc->target_handle,
+			  (int) reloc->delta,
+			  (int) target_obj->size);
+		goto err;
+	}
+
+	reloc->delta += target_offset;
+	if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+		uint32_t page_offset = reloc->offset & ~PAGE_MASK;
+		char *vaddr;
+
+		vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
+		*(uint32_t *)(vaddr + page_offset) = reloc->delta;
+		kunmap_atomic(vaddr);
+	} else {
+		struct drm_i915_private *dev_priv = dev->dev_private;
 		uint32_t __iomem *reloc_entry;
+		void __iomem *reloc_page;
 
-		target_obj = drm_gem_object_lookup(obj->dev, file_priv,
-						   reloc->target_handle);
-		if (target_obj == NULL) {
-			i915_gem_object_unpin(obj);
-			return -ENOENT;
-		}
-		target_obj_priv = to_intel_bo(target_obj);
+		ret = i915_gem_object_set_to_gtt_domain(&obj->base, 1);
+		if (ret)
+			goto err;
 
-#if WATCH_RELOC
-		DRM_INFO("%s: obj %p offset %08x target %d "
-			 "read %08x write %08x gtt %08x "
-			 "presumed %08x delta %08x\n",
-			 __func__,
-			 obj,
-			 (int) reloc->offset,
-			 (int) reloc->target_handle,
-			 (int) reloc->read_domains,
-			 (int) reloc->write_domain,
-			 (int) target_obj_priv->gtt_offset,
-			 (int) reloc->presumed_offset,
-			 reloc->delta);
-#endif
+		/* Map the page containing the relocation we're going to perform.  */
+		reloc->offset += obj->gtt_offset;
+		reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+						      reloc->offset & PAGE_MASK);
+		reloc_entry = (uint32_t __iomem *)
+			(reloc_page + (reloc->offset & ~PAGE_MASK));
+		iowrite32(reloc->delta, reloc_entry);
+		io_mapping_unmap_atomic(reloc_page);
+	}
 
-		/* The target buffer should have appeared before us in the
-		 * exec_object list, so it should have a GTT space bound by now.
-		 */
-		if (target_obj_priv->gtt_space == NULL) {
-			DRM_ERROR("No GTT space found for object %d\n",
-				  reloc->target_handle);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
+	/* and update the user's relocation entry */
+	reloc->presumed_offset = target_offset;
 
-		/* Validate that the target is in a valid r/w GPU domain */
-		if (reloc->write_domain & (reloc->write_domain - 1)) {
-			DRM_ERROR("reloc with multiple write domains: "
-				  "obj %p target %d offset %d "
-				  "read %08x write %08x",
-				  obj, reloc->target_handle,
-				  (int) reloc->offset,
-				  reloc->read_domains,
-				  reloc->write_domain);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
-		if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
-		    reloc->read_domains & I915_GEM_DOMAIN_CPU) {
-			DRM_ERROR("reloc with read/write CPU domains: "
-				  "obj %p target %d offset %d "
-				  "read %08x write %08x",
-				  obj, reloc->target_handle,
-				  (int) reloc->offset,
-				  reloc->read_domains,
-				  reloc->write_domain);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
-		if (reloc->write_domain && target_obj->pending_write_domain &&
-		    reloc->write_domain != target_obj->pending_write_domain) {
-			DRM_ERROR("Write domain conflict: "
-				  "obj %p target %d offset %d "
-				  "new %08x old %08x\n",
-				  obj, reloc->target_handle,
-				  (int) reloc->offset,
-				  reloc->write_domain,
-				  target_obj->pending_write_domain);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
+out:
+	ret = 0;
+err:
+	drm_gem_object_unreference(target_obj);
+	return ret;
+}
 
-		target_obj->pending_read_domains |= reloc->read_domains;
-		target_obj->pending_write_domain |= reloc->write_domain;
+static int
+i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
+				    struct drm_file *file_priv,
+				    struct drm_i915_gem_exec_object2 *entry)
+{
+	struct drm_i915_gem_relocation_entry __user *user_relocs;
+	int i, ret;
 
-		/* If the relocation already has the right value in it, no
-		 * more work needs to be done.
-		 */
-		if (target_obj_priv->gtt_offset == reloc->presumed_offset) {
-			drm_gem_object_unreference(target_obj);
-			continue;
-		}
+	user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
+	for (i = 0; i < entry->relocation_count; i++) {
+		struct drm_i915_gem_relocation_entry reloc;
 
-		/* Check that the relocation address is valid... */
-		if (reloc->offset > obj->size - 4) {
-			DRM_ERROR("Relocation beyond object bounds: "
-				  "obj %p target %d offset %d size %d.\n",
-				  obj, reloc->target_handle,
-				  (int) reloc->offset, (int) obj->size);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
-		if (reloc->offset & 3) {
-			DRM_ERROR("Relocation not 4-byte aligned: "
-				  "obj %p target %d offset %d.\n",
-				  obj, reloc->target_handle,
-				  (int) reloc->offset);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
+		if (__copy_from_user_inatomic(&reloc,
+					      user_relocs+i,
+					      sizeof(reloc)))
+			return -EFAULT;
 
-		/* and points to somewhere within the target object. */
-		if (reloc->delta >= target_obj->size) {
-			DRM_ERROR("Relocation beyond target object bounds: "
-				  "obj %p target %d delta %d size %d.\n",
-				  obj, reloc->target_handle,
-				  (int) reloc->delta, (int) target_obj->size);
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
+		ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &reloc);
+		if (ret)
+			return ret;
 
-		ret = i915_gem_object_set_to_gtt_domain(obj, 1);
-		if (ret != 0) {
-			drm_gem_object_unreference(target_obj);
-			i915_gem_object_unpin(obj);
-			return -EINVAL;
-		}
+		if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
+					    &reloc.presumed_offset,
+					    sizeof(reloc.presumed_offset)))
+			return -EFAULT;
+	}
 
-		/* Map the page containing the relocation we're going to
-		 * perform.
-		 */
-		reloc_offset = obj_priv->gtt_offset + reloc->offset;
-		reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-						      (reloc_offset &
-						       ~(PAGE_SIZE - 1)),
-						      KM_USER0);
-		reloc_entry = (uint32_t __iomem *)(reloc_page +
-						   (reloc_offset & (PAGE_SIZE - 1)));
-		reloc_val = target_obj_priv->gtt_offset + reloc->delta;
+	return 0;
+}
 
-#if WATCH_BUF
-		DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
-			  obj, (unsigned int) reloc->offset,
-			  readl(reloc_entry), reloc_val);
-#endif
-		writel(reloc_val, reloc_entry);
-		io_mapping_unmap_atomic(reloc_page, KM_USER0);
+static int
+i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj,
+					 struct drm_file *file_priv,
+					 struct drm_i915_gem_exec_object2 *entry,
+					 struct drm_i915_gem_relocation_entry *relocs)
+{
+	int i, ret;
 
-		/* The updated presumed offset for this entry will be
-		 * copied back out to the user.
-		 */
-		reloc->presumed_offset = target_obj_priv->gtt_offset;
+	for (i = 0; i < entry->relocation_count; i++) {
+		ret = i915_gem_execbuffer_relocate_entry(obj, file_priv, entry, &relocs[i]);
+		if (ret)
+			return ret;
+	}
 
-		drm_gem_object_unreference(target_obj);
+	return 0;
+}
+
+static int
+i915_gem_execbuffer_relocate(struct drm_device *dev,
+			     struct drm_file *file,
+			     struct drm_gem_object **object_list,
+			     struct drm_i915_gem_exec_object2 *exec_list,
+			     int count)
+{
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+		obj->base.pending_read_domains = 0;
+		obj->base.pending_write_domain = 0;
+		ret = i915_gem_execbuffer_relocate_object(obj, file,
+							  &exec_list[i]);
+		if (ret)
+			return ret;
 	}
 
-#if WATCH_BUF
-	if (0)
-		i915_gem_dump_object(obj, 128, __func__, ~0);
-#endif
 	return 0;
 }
 
-/* Throttle our rendering by waiting until the ring has completed our requests
- * emitted over 20 msec ago.
- *
- * Note that if we were to use the current jiffies each time around the loop,
- * we wouldn't escape the function with any frames outstanding if the time to
- * render a frame was over 20ms.
- *
- * This should get us reasonable parallelism between CPU and GPU but also
- * relatively low latency when blocking on a particular request to finish.
- */
 static int
-i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+i915_gem_execbuffer_reserve(struct drm_device *dev,
+			    struct drm_file *file,
+			    struct drm_gem_object **object_list,
+			    struct drm_i915_gem_exec_object2 *exec_list,
+			    int count)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
-	int ret = 0;
-	unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret, i, retry;
 
-	mutex_lock(&dev->struct_mutex);
-	while (!list_empty(&i915_file_priv->mm.request_list)) {
-		struct drm_i915_gem_request *request;
+	/* attempt to pin all of the buffers into the GTT */
+	for (retry = 0; retry < 2; retry++) {
+		ret = 0;
+		for (i = 0; i < count; i++) {
+			struct drm_i915_gem_exec_object2 *entry = &exec_list[i];
+			struct drm_i915_gem_object *obj= to_intel_bo(object_list[i]);
+			bool need_fence =
+				entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
+				obj->tiling_mode != I915_TILING_NONE;
 
-		request = list_first_entry(&i915_file_priv->mm.request_list,
-					   struct drm_i915_gem_request,
-					   client_list);
+			/* Check fence reg constraints and rebind if necessary */
+			if (need_fence &&
+			    !i915_gem_object_fence_offset_ok(&obj->base,
+							     obj->tiling_mode)) {
+				ret = i915_gem_object_unbind(&obj->base);
+				if (ret)
+					break;
+			}
 
-		if (time_after_eq(request->emitted_jiffies, recent_enough))
-			break;
+			ret = i915_gem_object_pin(&obj->base, entry->alignment);
+			if (ret)
+				break;
 
-		ret = i915_wait_request(dev, request->seqno, request->ring);
-		if (ret != 0)
+			/*
+			 * Pre-965 chips need a fence register set up in order
+			 * to properly handle blits to/from tiled surfaces.
+			 */
+			if (need_fence) {
+				ret = i915_gem_object_get_fence_reg(&obj->base, true);
+				if (ret) {
+					i915_gem_object_unpin(&obj->base);
+					break;
+				}
+
+				dev_priv->fence_regs[obj->fence_reg].gpu = true;
+			}
+
+			entry->offset = obj->gtt_offset;
+		}
+
+		while (i--)
+			i915_gem_object_unpin(object_list[i]);
+
+		if (ret == 0)
 			break;
+
+		if (ret != -ENOSPC || retry)
+			return ret;
+
+		ret = i915_gem_evict_everything(dev);
+		if (ret)
+			return ret;
 	}
-	mutex_unlock(&dev->struct_mutex);
 
-	return ret;
+	return 0;
 }
 
 static int
-i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object2 *exec_list,
-			      uint32_t buffer_count,
-			      struct drm_i915_gem_relocation_entry **relocs)
+i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
+				  struct drm_file *file,
+				  struct drm_gem_object **object_list,
+				  struct drm_i915_gem_exec_object2 *exec_list,
+				  int count)
 {
-	uint32_t reloc_count = 0, reloc_index = 0, i;
-	int ret;
+	struct drm_i915_gem_relocation_entry *reloc;
+	int i, total, ret;
 
-	*relocs = NULL;
-	for (i = 0; i < buffer_count; i++) {
-		if (reloc_count + exec_list[i].relocation_count < reloc_count)
-			return -EINVAL;
-		reloc_count += exec_list[i].relocation_count;
+	for (i = 0; i < count; i++) {
+		struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+		obj->in_execbuffer = false;
 	}
 
-	*relocs = drm_calloc_large(reloc_count, sizeof(**relocs));
-	if (*relocs == NULL) {
-		DRM_ERROR("failed to alloc relocs, count %d\n", reloc_count);
+	mutex_unlock(&dev->struct_mutex);
+
+	total = 0;
+	for (i = 0; i < count; i++)
+		total += exec_list[i].relocation_count;
+
+	reloc = drm_malloc_ab(total, sizeof(*reloc));
+	if (reloc == NULL) {
+		mutex_lock(&dev->struct_mutex);
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < buffer_count; i++) {
+	total = 0;
+	for (i = 0; i < count; i++) {
 		struct drm_i915_gem_relocation_entry __user *user_relocs;
 
 		user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
 
-		ret = copy_from_user(&(*relocs)[reloc_index],
-				     user_relocs,
-				     exec_list[i].relocation_count *
-				     sizeof(**relocs));
-		if (ret != 0) {
-			drm_free_large(*relocs);
-			*relocs = NULL;
-			return -EFAULT;
+		if (copy_from_user(reloc+total, user_relocs,
+				   exec_list[i].relocation_count *
+				   sizeof(*reloc))) {
+			ret = -EFAULT;
+			mutex_lock(&dev->struct_mutex);
+			goto err;
 		}
 
-		reloc_index += exec_list[i].relocation_count;
+		total += exec_list[i].relocation_count;
 	}
 
-	return 0;
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		mutex_lock(&dev->struct_mutex);
+		goto err;
+	}
+
+	ret = i915_gem_execbuffer_reserve(dev, file,
+					  object_list, exec_list,
+					  count);
+	if (ret)
+		goto err;
+
+	total = 0;
+	for (i = 0; i < count; i++) {
+		struct drm_i915_gem_object *obj = to_intel_bo(object_list[i]);
+		obj->base.pending_read_domains = 0;
+		obj->base.pending_write_domain = 0;
+		ret = i915_gem_execbuffer_relocate_object_slow(obj, file,
+							       &exec_list[i],
+							       reloc + total);
+		if (ret)
+			goto err;
+
+		total += exec_list[i].relocation_count;
+	}
+
+	/* Leave the user relocations as are, this is the painfully slow path,
+	 * and we want to avoid the complication of dropping the lock whilst
+	 * having buffers reserved in the aperture and so causing spurious
+	 * ENOSPC for random operations.
+	 */
+
+err:
+	drm_free_large(reloc);
+	return ret;
 }
 
 static int
-i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object2 *exec_list,
-			    uint32_t buffer_count,
-			    struct drm_i915_gem_relocation_entry *relocs)
+i915_gem_execbuffer_move_to_gpu(struct drm_device *dev,
+				struct drm_file *file,
+				struct intel_ring_buffer *ring,
+				struct drm_gem_object **objects,
+				int count)
 {
-	uint32_t reloc_count = 0, i;
-	int ret = 0;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret, i;
 
-	if (relocs == NULL)
-	    return 0;
+	/* Zero the global flush/invalidate flags. These
+	 * will be modified as new domains are computed
+	 * for each object
+	 */
+	dev->invalidate_domains = 0;
+	dev->flush_domains = 0;
+	dev_priv->mm.flush_rings = 0;
+	for (i = 0; i < count; i++)
+		i915_gem_object_set_to_gpu_domain(objects[i], ring);
 
-	for (i = 0; i < buffer_count; i++) {
-		struct drm_i915_gem_relocation_entry __user *user_relocs;
-		int unwritten;
+	if (dev->invalidate_domains | dev->flush_domains) {
+#if WATCH_EXEC
+		DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
+			  __func__,
+			 dev->invalidate_domains,
+			 dev->flush_domains);
+#endif
+		i915_gem_flush(dev, file,
+			       dev->invalidate_domains,
+			       dev->flush_domains,
+			       dev_priv->mm.flush_rings);
+	}
 
-		user_relocs = (void __user *)(uintptr_t)exec_list[i].relocs_ptr;
+	for (i = 0; i < count; i++) {
+		struct drm_i915_gem_object *obj = to_intel_bo(objects[i]);
+		/* XXX replace with semaphores */
+		if (obj->ring && ring != obj->ring) {
+			ret = i915_gem_object_wait_rendering(&obj->base, true);
+			if (ret)
+				return ret;
+		}
+	}
 
-		unwritten = copy_to_user(user_relocs,
-					 &relocs[reloc_count],
-					 exec_list[i].relocation_count *
-					 sizeof(*relocs));
+	return 0;
+}
 
-		if (unwritten) {
-			ret = -EFAULT;
-			goto err;
-		}
+/* Throttle our rendering by waiting until the ring has completed our requests
+ * emitted over 20 msec ago.
+ *
+ * Note that if we were to use the current jiffies each time around the loop,
+ * we wouldn't escape the function with any frames outstanding if the time to
+ * render a frame was over 20ms.
+ *
+ * This should get us reasonable parallelism between CPU and GPU but also
+ * relatively low latency when blocking on a particular request to finish.
+ */
+static int
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+	unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+	struct drm_i915_gem_request *request;
+	struct intel_ring_buffer *ring = NULL;
+	u32 seqno = 0;
+	int ret;
 
-		reloc_count += exec_list[i].relocation_count;
+	spin_lock(&file_priv->mm.lock);
+	list_for_each_entry(request, &file_priv->mm.request_list, client_list) {
+		if (time_after_eq(request->emitted_jiffies, recent_enough))
+			break;
+
+		ring = request->ring;
+		seqno = request->seqno;
 	}
+	spin_unlock(&file_priv->mm.lock);
 
-err:
-	drm_free_large(relocs);
+	if (seqno == 0)
+		return 0;
+
+	ret = 0;
+	if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+		/* And wait for the seqno passing without holding any locks and
+		 * causing extra latency for others. This is safe as the irq
+		 * generation is designed to be run atomically and so is
+		 * lockless.
+		 */
+		ring->user_irq_get(dev, ring);
+		ret = wait_event_interruptible(ring->irq_queue,
+					       i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+					       || atomic_read(&dev_priv->mm.wedged));
+		ring->user_irq_put(dev, ring);
+
+		if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+			ret = -EIO;
+	}
+
+	if (ret == 0)
+		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
 	return ret;
 }
 
 static int
-i915_gem_check_execbuffer (struct drm_i915_gem_execbuffer2 *exec,
-			   uint64_t exec_offset)
+i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec,
+			  uint64_t exec_offset)
 {
 	uint32_t exec_start, exec_len;
 
@@ -3509,44 +3735,39 @@
 }
 
 static int
-i915_gem_wait_for_pending_flip(struct drm_device *dev,
-			       struct drm_gem_object **object_list,
-			       int count)
+validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+		   int count)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *obj_priv;
-	DEFINE_WAIT(wait);
-	int i, ret = 0;
+	int i;
 
-	for (;;) {
-		prepare_to_wait(&dev_priv->pending_flip_queue,
-				&wait, TASK_INTERRUPTIBLE);
-		for (i = 0; i < count; i++) {
-			obj_priv = to_intel_bo(object_list[i]);
-			if (atomic_read(&obj_priv->pending_flip) > 0)
-				break;
-		}
-		if (i == count)
-			break;
+	for (i = 0; i < count; i++) {
+		char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
+		int length; /* limited by fault_in_pages_readable() */
 
-		if (!signal_pending(current)) {
-			mutex_unlock(&dev->struct_mutex);
-			schedule();
-			mutex_lock(&dev->struct_mutex);
-			continue;
-		}
-		ret = -ERESTARTSYS;
-		break;
+		/* First check for malicious input causing overflow */
+		if (exec[i].relocation_count >
+		    INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
+			return -EINVAL;
+
+		length = exec[i].relocation_count *
+			sizeof(struct drm_i915_gem_relocation_entry);
+		if (!access_ok(VERIFY_READ, ptr, length))
+			return -EFAULT;
+
+		/* we may also need to update the presumed offsets */
+		if (!access_ok(VERIFY_WRITE, ptr, length))
+			return -EFAULT;
+
+		if (fault_in_pages_readable(ptr, length))
+			return -EFAULT;
 	}
-	finish_wait(&dev_priv->pending_flip_queue, &wait);
 
-	return ret;
+	return 0;
 }
 
-
-int
+static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
-		       struct drm_file *file_priv,
+		       struct drm_file *file,
 		       struct drm_i915_gem_execbuffer2 *args,
 		       struct drm_i915_gem_exec_object2 *exec_list)
 {
@@ -3555,26 +3776,47 @@
 	struct drm_gem_object *batch_obj;
 	struct drm_i915_gem_object *obj_priv;
 	struct drm_clip_rect *cliprects = NULL;
-	struct drm_i915_gem_relocation_entry *relocs = NULL;
-	int ret = 0, ret2, i, pinned = 0;
+	struct drm_i915_gem_request *request = NULL;
+	int ret, i, flips;
 	uint64_t exec_offset;
-	uint32_t seqno, flush_domains, reloc_index;
-	int pin_tries, flips;
 
 	struct intel_ring_buffer *ring = NULL;
 
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
+
+	ret = validate_exec_list(exec_list, args->buffer_count);
+	if (ret)
+		return ret;
+
 #if WATCH_EXEC
 	DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
 		  (int) args->buffers_ptr, args->buffer_count, args->batch_len);
 #endif
-	if (args->flags & I915_EXEC_BSD) {
+	switch (args->flags & I915_EXEC_RING_MASK) {
+	case I915_EXEC_DEFAULT:
+	case I915_EXEC_RENDER:
+		ring = &dev_priv->render_ring;
+		break;
+	case I915_EXEC_BSD:
 		if (!HAS_BSD(dev)) {
-			DRM_ERROR("execbuf with wrong flag\n");
+			DRM_ERROR("execbuf with invalid ring (BSD)\n");
 			return -EINVAL;
 		}
 		ring = &dev_priv->bsd_ring;
-	} else {
-		ring = &dev_priv->render_ring;
+		break;
+	case I915_EXEC_BLT:
+		if (!HAS_BLT(dev)) {
+			DRM_ERROR("execbuf with invalid ring (BLT)\n");
+			return -EINVAL;
+		}
+		ring = &dev_priv->blt_ring;
+		break;
+	default:
+		DRM_ERROR("execbuf with unknown ring: %d\n",
+			  (int)(args->flags & I915_EXEC_RING_MASK));
+		return -EINVAL;
 	}
 
 	if (args->buffer_count < 1) {
@@ -3609,20 +3851,15 @@
 		}
 	}
 
-	ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
-					    &relocs);
-	if (ret != 0)
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL) {
+		ret = -ENOMEM;
 		goto pre_mutex_err;
+	}
 
-	mutex_lock(&dev->struct_mutex);
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
-	if (atomic_read(&dev_priv->mm.wedged)) {
-		mutex_unlock(&dev->struct_mutex);
-		ret = -EIO;
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
 		goto pre_mutex_err;
-	}
 
 	if (dev_priv->mm.suspended) {
 		mutex_unlock(&dev->struct_mutex);
@@ -3631,9 +3868,8 @@
 	}
 
 	/* Look up object handles */
-	flips = 0;
 	for (i = 0; i < args->buffer_count; i++) {
-		object_list[i] = drm_gem_object_lookup(dev, file_priv,
+		object_list[i] = drm_gem_object_lookup(dev, file,
 						       exec_list[i].handle);
 		if (object_list[i] == NULL) {
 			DRM_ERROR("Invalid object handle %d at index %d\n",
@@ -3654,75 +3890,28 @@
 			goto err;
 		}
 		obj_priv->in_execbuffer = true;
-		flips += atomic_read(&obj_priv->pending_flip);
 	}
 
-	if (flips > 0) {
-		ret = i915_gem_wait_for_pending_flip(dev, object_list,
-						     args->buffer_count);
-		if (ret)
-			goto err;
-	}
-
-	/* Pin and relocate */
-	for (pin_tries = 0; ; pin_tries++) {
-		ret = 0;
-		reloc_index = 0;
-
-		for (i = 0; i < args->buffer_count; i++) {
-			object_list[i]->pending_read_domains = 0;
-			object_list[i]->pending_write_domain = 0;
-			ret = i915_gem_object_pin_and_relocate(object_list[i],
-							       file_priv,
-							       &exec_list[i],
-							       &relocs[reloc_index]);
-			if (ret)
-				break;
-			pinned = i + 1;
-			reloc_index += exec_list[i].relocation_count;
-		}
-		/* success */
-		if (ret == 0)
-			break;
-
-		/* error other than GTT full, or we've already tried again */
-		if (ret != -ENOSPC || pin_tries >= 1) {
-			if (ret != -ERESTARTSYS) {
-				unsigned long long total_size = 0;
-				int num_fences = 0;
-				for (i = 0; i < args->buffer_count; i++) {
-					obj_priv = to_intel_bo(object_list[i]);
+	/* Move the objects en-masse into the GTT, evicting if necessary. */
+	ret = i915_gem_execbuffer_reserve(dev, file,
+					  object_list, exec_list,
+					  args->buffer_count);
+	if (ret)
+		goto err;
 
-					total_size += object_list[i]->size;
-					num_fences +=
-						exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE &&
-						obj_priv->tiling_mode != I915_TILING_NONE;
-				}
-				DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n",
-					  pinned+1, args->buffer_count,
-					  total_size, num_fences,
-					  ret);
-				DRM_ERROR("%d objects [%d pinned], "
-					  "%d object bytes [%d pinned], "
-					  "%d/%d gtt bytes\n",
-					  atomic_read(&dev->object_count),
-					  atomic_read(&dev->pin_count),
-					  atomic_read(&dev->object_memory),
-					  atomic_read(&dev->pin_memory),
-					  atomic_read(&dev->gtt_memory),
-					  dev->gtt_total);
-			}
-			goto err;
+	/* The objects are in their final locations, apply the relocations. */
+	ret = i915_gem_execbuffer_relocate(dev, file,
+					   object_list, exec_list,
+					   args->buffer_count);
+	if (ret) {
+		if (ret == -EFAULT) {
+			ret = i915_gem_execbuffer_relocate_slow(dev, file,
+								object_list,
+								exec_list,
+								args->buffer_count);
+			BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 		}
-
-		/* unpin all of our buffers */
-		for (i = 0; i < pinned; i++)
-			i915_gem_object_unpin(object_list[i]);
-		pinned = 0;
-
-		/* evict everyone we can from the aperture */
-		ret = i915_gem_evict_everything(dev);
-		if (ret && ret != -ENOSPC)
+		if (ret)
 			goto err;
 	}
 
@@ -3735,72 +3924,28 @@
 	}
 	batch_obj->pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
 
-	/* Sanity check the batch buffer, prior to moving objects */
-	exec_offset = exec_list[args->buffer_count - 1].offset;
-	ret = i915_gem_check_execbuffer (args, exec_offset);
+	/* Sanity check the batch buffer */
+	exec_offset = to_intel_bo(batch_obj)->gtt_offset;
+	ret = i915_gem_check_execbuffer(args, exec_offset);
 	if (ret != 0) {
 		DRM_ERROR("execbuf with invalid offset/length\n");
 		goto err;
 	}
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
-	/* Zero the global flush/invalidate flags. These
-	 * will be modified as new domains are computed
-	 * for each object
-	 */
-	dev->invalidate_domains = 0;
-	dev->flush_domains = 0;
-	dev_priv->flush_rings = 0;
-
-	for (i = 0; i < args->buffer_count; i++) {
-		struct drm_gem_object *obj = object_list[i];
-
-		/* Compute new gpu domains and update invalidate/flush */
-		i915_gem_object_set_to_gpu_domain(obj);
-	}
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
-	if (dev->invalidate_domains | dev->flush_domains) {
-#if WATCH_EXEC
-		DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
-			  __func__,
-			 dev->invalidate_domains,
-			 dev->flush_domains);
-#endif
-		i915_gem_flush(dev,
-			       dev->invalidate_domains,
-			       dev->flush_domains);
-		if (dev_priv->flush_rings & FLUSH_RENDER_RING)
-			(void)i915_add_request(dev, file_priv,
-					       dev->flush_domains,
-					       &dev_priv->render_ring);
-		if (dev_priv->flush_rings & FLUSH_BSD_RING)
-			(void)i915_add_request(dev, file_priv,
-					       dev->flush_domains,
-					       &dev_priv->bsd_ring);
-	}
+	ret = i915_gem_execbuffer_move_to_gpu(dev, file, ring,
+					      object_list, args->buffer_count);
+	if (ret)
+		goto err;
 
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
-		struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 		uint32_t old_write_domain = obj->write_domain;
-
 		obj->write_domain = obj->pending_write_domain;
-		if (obj->write_domain)
-			list_move_tail(&obj_priv->gpu_write_list,
-				       &dev_priv->mm.gpu_write_list);
-		else
-			list_del_init(&obj_priv->gpu_write_list);
-
 		trace_i915_gem_object_change_domain(obj,
 						    obj->read_domains,
 						    old_write_domain);
 	}
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
 #if WATCH_COHERENCY
 	for (i = 0; i < args->buffer_count; i++) {
 		i915_gem_object_check_coherency(object_list[i],
@@ -3815,9 +3960,38 @@
 			      ~0);
 #endif
 
+	/* Check for any pending flips. As we only maintain a flip queue depth
+	 * of 1, we can simply insert a WAIT for the next display flip prior
+	 * to executing the batch and avoid stalling the CPU.
+	 */
+	flips = 0;
+	for (i = 0; i < args->buffer_count; i++) {
+		if (object_list[i]->write_domain)
+			flips |= atomic_read(&to_intel_bo(object_list[i])->pending_flip);
+	}
+	if (flips) {
+		int plane, flip_mask;
+
+		for (plane = 0; flips >> plane; plane++) {
+			if (((flips >> plane) & 1) == 0)
+				continue;
+
+			if (plane)
+				flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
+			else
+				flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
+
+			intel_ring_begin(dev, ring, 2);
+			intel_ring_emit(dev, ring,
+					MI_WAIT_FOR_EVENT | flip_mask);
+			intel_ring_emit(dev, ring, MI_NOOP);
+			intel_ring_advance(dev, ring);
+		}
+	}
+
 	/* Exec the batchbuffer */
 	ret = ring->dispatch_gem_execbuffer(dev, ring, args,
-			cliprects, exec_offset);
+					    cliprects, exec_offset);
 	if (ret) {
 		DRM_ERROR("dispatch failed %d\n", ret);
 		goto err;
@@ -3827,38 +4001,21 @@
 	 * Ensure that the commands in the batch buffer are
 	 * finished before the interrupt fires
 	 */
-	flush_domains = i915_retire_commands(dev, ring);
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	i915_retire_commands(dev, ring);
 
-	/*
-	 * Get a seqno representing the execution of the current buffer,
-	 * which we can wait on.  We would like to mitigate these interrupts,
-	 * likely by only creating seqnos occasionally (so that we have
-	 * *some* interrupts representing completion of buffers that we can
-	 * wait on when trying to clear up gtt space).
-	 */
-	seqno = i915_add_request(dev, file_priv, flush_domains, ring);
-	BUG_ON(seqno == 0);
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
-		obj_priv = to_intel_bo(obj);
 
-		i915_gem_object_move_to_active(obj, seqno, ring);
-#if WATCH_LRU
-		DRM_INFO("%s: move to exec list %p\n", __func__, obj);
-#endif
+		i915_gem_object_move_to_active(obj, ring);
+		if (obj->write_domain)
+			list_move_tail(&to_intel_bo(obj)->gpu_write_list,
+				       &ring->gpu_write_list);
 	}
-#if WATCH_LRU
-	i915_dump_lru(dev, __func__);
-#endif
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	i915_add_request(dev, file, request, ring);
+	request = NULL;
 
 err:
-	for (i = 0; i < pinned; i++)
-		i915_gem_object_unpin(object_list[i]);
-
 	for (i = 0; i < args->buffer_count; i++) {
 		if (object_list[i]) {
 			obj_priv = to_intel_bo(object_list[i]);
@@ -3870,22 +4027,9 @@
 	mutex_unlock(&dev->struct_mutex);
 
 pre_mutex_err:
-	/* Copy the updated relocations out regardless of current error
-	 * state.  Failure to update the relocs would mean that the next
-	 * time userland calls execbuf, it would do so with presumed offset
-	 * state that didn't match the actual object state.
-	 */
-	ret2 = i915_gem_put_relocs_to_user(exec_list, args->buffer_count,
-					   relocs);
-	if (ret2 != 0) {
-		DRM_ERROR("Failed to copy relocations back out: %d\n", ret2);
-
-		if (ret == 0)
-			ret = ret2;
-	}
-
 	drm_free_large(object_list);
 	kfree(cliprects);
+	kfree(request);
 
 	return ret;
 }
@@ -3942,7 +4086,7 @@
 		exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
 		exec2_list[i].alignment = exec_list[i].alignment;
 		exec2_list[i].offset = exec_list[i].offset;
-		if (!IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen < 4)
 			exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
 		else
 			exec2_list[i].flags = 0;
@@ -4039,20 +4183,19 @@
 i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
 {
 	struct drm_device *dev = obj->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret;
 
 	BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 
 	if (obj_priv->gtt_space != NULL) {
 		if (alignment == 0)
 			alignment = i915_gem_get_gtt_alignment(obj);
 		if (obj_priv->gtt_offset & (alignment - 1)) {
 			WARN(obj_priv->pin_count,
-			     "bo is already pinned with incorrect alignment:"
-			     " offset=%x, req.alignment=%x\n",
+			     "bo is already pinned with incorrect alignment: offset=%x, req.alignment=%x\n",
 			     obj_priv->gtt_offset, alignment);
 			ret = i915_gem_object_unbind(obj);
 			if (ret)
@@ -4072,14 +4215,13 @@
 	 * remove it from the inactive list
 	 */
 	if (obj_priv->pin_count == 1) {
-		atomic_inc(&dev->pin_count);
-		atomic_add(obj->size, &dev->pin_memory);
-		if (!obj_priv->active &&
-		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-			list_del_init(&obj_priv->list);
+		i915_gem_info_add_pin(dev_priv, obj->size);
+		if (!obj_priv->active)
+			list_move_tail(&obj_priv->mm_list,
+				       &dev_priv->mm.pinned_list);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
 
+	WARN_ON(i915_verify_lists(dev));
 	return 0;
 }
 
@@ -4090,7 +4232,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 	obj_priv->pin_count--;
 	BUG_ON(obj_priv->pin_count < 0);
 	BUG_ON(obj_priv->gtt_space == NULL);
@@ -4100,14 +4242,12 @@
 	 * the inactive list
 	 */
 	if (obj_priv->pin_count == 0) {
-		if (!obj_priv->active &&
-		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-			list_move_tail(&obj_priv->list,
+		if (!obj_priv->active)
+			list_move_tail(&obj_priv->mm_list,
 				       &dev_priv->mm.inactive_list);
-		atomic_dec(&dev->pin_count);
-		atomic_sub(obj->size, &dev->pin_memory);
+		i915_gem_info_remove_pin(dev_priv, obj->size);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 }
 
 int
@@ -4119,41 +4259,36 @@
 	struct drm_i915_gem_object *obj_priv;
 	int ret;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
-		DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
-			  args->handle);
-		mutex_unlock(&dev->struct_mutex);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto unlock;
 	}
 	obj_priv = to_intel_bo(obj);
 
 	if (obj_priv->madv != I915_MADV_WILLNEED) {
 		DRM_ERROR("Attempting to pin a purgeable buffer\n");
-		drm_gem_object_unreference(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
 		DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
 			  args->handle);
-		drm_gem_object_unreference(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	obj_priv->user_pin_count++;
 	obj_priv->pin_filp = file_priv;
 	if (obj_priv->user_pin_count == 1) {
 		ret = i915_gem_object_pin(obj, args->alignment);
-		if (ret != 0) {
-			drm_gem_object_unreference(obj);
-			mutex_unlock(&dev->struct_mutex);
-			return ret;
-		}
+		if (ret)
+			goto out;
 	}
 
 	/* XXX - flush the CPU caches for pinned objects
@@ -4161,10 +4296,11 @@
 	 */
 	i915_gem_object_flush_cpu_write_domain(obj);
 	args->offset = obj_priv->gtt_offset;
+out:
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
-
-	return 0;
+	return ret;
 }
 
 int
@@ -4174,24 +4310,24 @@
 	struct drm_i915_gem_pin *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
-		DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
-			  args->handle);
-		mutex_unlock(&dev->struct_mutex);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto unlock;
 	}
-
 	obj_priv = to_intel_bo(obj);
+
 	if (obj_priv->pin_filp != file_priv) {
 		DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
 			  args->handle);
-		drm_gem_object_unreference(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 	obj_priv->user_pin_count--;
 	if (obj_priv->user_pin_count == 0) {
@@ -4199,9 +4335,11 @@
 		i915_gem_object_unpin(obj);
 	}
 
+out:
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
-	return 0;
+	return ret;
 }
 
 int
@@ -4211,22 +4349,24 @@
 	struct drm_i915_gem_busy *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
-		DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
-			  args->handle);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto unlock;
 	}
-
-	mutex_lock(&dev->struct_mutex);
+	obj_priv = to_intel_bo(obj);
 
 	/* Count all active objects as busy, even if they are currently not used
 	 * by the gpu. Users of this interface expect objects to eventually
 	 * become non-busy without any further actions, therefore emit any
 	 * necessary flushes here.
 	 */
-	obj_priv = to_intel_bo(obj);
 	args->busy = obj_priv->active;
 	if (args->busy) {
 		/* Unconditionally flush objects, even when the gpu still uses this
@@ -4234,9 +4374,19 @@
 		 * use this buffer rather sooner than later, so issuing the required
 		 * flush earlier is beneficial.
 		 */
-		if (obj->write_domain) {
-			i915_gem_flush(dev, 0, obj->write_domain);
-			(void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
+		if (obj->write_domain & I915_GEM_GPU_DOMAINS) {
+			i915_gem_flush_ring(dev, file_priv,
+					    obj_priv->ring,
+					    0, obj->write_domain);
+		} else if (obj_priv->ring->outstanding_lazy_request) {
+			/* This ring is not being cleared by active usage,
+			 * so emit a request to do so.
+			 */
+			u32 seqno = i915_add_request(dev,
+						     NULL, NULL,
+						     obj_priv->ring);
+			if (seqno == 0)
+				ret = -ENOMEM;
 		}
 
 		/* Update the active list for the hardware's current position.
@@ -4250,8 +4400,9 @@
 	}
 
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
-	return 0;
+	return ret;
 }
 
 int
@@ -4268,6 +4419,7 @@
 	struct drm_i915_gem_madvise *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret;
 
 	switch (args->madv) {
 	case I915_MADV_DONTNEED:
@@ -4277,22 +4429,20 @@
 	    return -EINVAL;
 	}
 
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
+
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
-		DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
-			  args->handle);
-		return -ENOENT;
+		ret = -ENOENT;
+		goto unlock;
 	}
-
-	mutex_lock(&dev->struct_mutex);
 	obj_priv = to_intel_bo(obj);
 
 	if (obj_priv->pin_count) {
-		drm_gem_object_unreference(obj);
-		mutex_unlock(&dev->struct_mutex);
-
-		DRM_ERROR("Attempted i915_gem_madvise_ioctl() on a pinned object\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	if (obj_priv->madv != __I915_MADV_PURGED)
@@ -4305,15 +4455,17 @@
 
 	args->retained = obj_priv->madv != __I915_MADV_PURGED;
 
+out:
 	drm_gem_object_unreference(obj);
+unlock:
 	mutex_unlock(&dev->struct_mutex);
-
-	return 0;
+	return ret;
 }
 
 struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
 					      size_t size)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj;
 
 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -4325,18 +4477,19 @@
 		return NULL;
 	}
 
+	i915_gem_info_add_obj(dev_priv, size);
+
 	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
 	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
 	obj->agp_type = AGP_USER_MEMORY;
 	obj->base.driver_private = NULL;
 	obj->fence_reg = I915_FENCE_REG_NONE;
-	INIT_LIST_HEAD(&obj->list);
+	INIT_LIST_HEAD(&obj->mm_list);
+	INIT_LIST_HEAD(&obj->ring_list);
 	INIT_LIST_HEAD(&obj->gpu_write_list);
 	obj->madv = I915_MADV_WILLNEED;
 
-	trace_i915_gem_object_create(&obj->base);
-
 	return &obj->base;
 }
 
@@ -4356,7 +4509,7 @@
 
 	ret = i915_gem_object_unbind(obj);
 	if (ret == -ERESTARTSYS) {
-		list_move(&obj_priv->list,
+		list_move(&obj_priv->mm_list,
 			  &dev_priv->mm.deferred_free_list);
 		return;
 	}
@@ -4365,6 +4518,7 @@
 		i915_gem_free_mmap_offset(obj);
 
 	drm_gem_object_release(obj);
+	i915_gem_info_remove_obj(dev_priv, obj->size);
 
 	kfree(obj_priv->page_cpu_valid);
 	kfree(obj_priv->bit_17);
@@ -4395,10 +4549,7 @@
 
 	mutex_lock(&dev->struct_mutex);
 
-	if (dev_priv->mm.suspended ||
-			(dev_priv->render_ring.gem_object == NULL) ||
-			(HAS_BSD(dev) &&
-			 dev_priv->bsd_ring.gem_object == NULL)) {
+	if (dev_priv->mm.suspended) {
 		mutex_unlock(&dev->struct_mutex);
 		return 0;
 	}
@@ -4423,7 +4574,7 @@
 	 * And not confound mm.suspended!
 	 */
 	dev_priv->mm.suspended = 1;
-	del_timer(&dev_priv->hangcheck_timer);
+	del_timer_sync(&dev_priv->hangcheck_timer);
 
 	i915_kernel_lost_context(dev);
 	i915_gem_cleanup_ringbuffer(dev);
@@ -4503,36 +4654,34 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
-	dev_priv->render_ring = render_ring;
-
-	if (!I915_NEED_GFX_HWS(dev)) {
-		dev_priv->render_ring.status_page.page_addr
-			= dev_priv->status_page_dmah->vaddr;
-		memset(dev_priv->render_ring.status_page.page_addr,
-				0, PAGE_SIZE);
-	}
-
 	if (HAS_PIPE_CONTROL(dev)) {
 		ret = i915_gem_init_pipe_control(dev);
 		if (ret)
 			return ret;
 	}
 
-	ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+	ret = intel_init_render_ring_buffer(dev);
 	if (ret)
 		goto cleanup_pipe_control;
 
 	if (HAS_BSD(dev)) {
-		dev_priv->bsd_ring = bsd_ring;
-		ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+		ret = intel_init_bsd_ring_buffer(dev);
 		if (ret)
 			goto cleanup_render_ring;
 	}
 
+	if (HAS_BLT(dev)) {
+		ret = intel_init_blt_ring_buffer(dev);
+		if (ret)
+			goto cleanup_bsd_ring;
+	}
+
 	dev_priv->next_seqno = 1;
 
 	return 0;
 
+cleanup_bsd_ring:
+	intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
 cleanup_render_ring:
 	intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
 cleanup_pipe_control:
@@ -4547,8 +4696,8 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
 	intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
-	if (HAS_BSD(dev))
-		intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+	intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+	intel_cleanup_ring_buffer(dev, &dev_priv->blt_ring);
 	if (HAS_PIPE_CONTROL(dev))
 		i915_gem_cleanup_pipe_control(dev);
 }
@@ -4577,15 +4726,15 @@
 		return ret;
 	}
 
-	spin_lock(&dev_priv->mm.active_list_lock);
+	BUG_ON(!list_empty(&dev_priv->mm.active_list));
 	BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
-	BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
+	BUG_ON(!list_empty(&dev_priv->bsd_ring.active_list));
+	BUG_ON(!list_empty(&dev_priv->blt_ring.active_list));
 	BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 	BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
 	BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
-	BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
+	BUG_ON(!list_empty(&dev_priv->bsd_ring.request_list));
+	BUG_ON(!list_empty(&dev_priv->blt_ring.request_list));
 	mutex_unlock(&dev->struct_mutex);
 
 	ret = drm_irq_install(dev);
@@ -4627,28 +4776,34 @@
 		DRM_ERROR("failed to idle hardware: %d\n", ret);
 }
 
+static void
+init_ring_lists(struct intel_ring_buffer *ring)
+{
+	INIT_LIST_HEAD(&ring->active_list);
+	INIT_LIST_HEAD(&ring->request_list);
+	INIT_LIST_HEAD(&ring->gpu_write_list);
+}
+
 void
 i915_gem_load(struct drm_device *dev)
 {
 	int i;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	spin_lock_init(&dev_priv->mm.active_list_lock);
+	INIT_LIST_HEAD(&dev_priv->mm.active_list);
 	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
-	INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
 	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+	INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
 	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 	INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
-	INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
-	INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
-	if (HAS_BSD(dev)) {
-		INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list);
-		INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list);
-	}
+	init_ring_lists(&dev_priv->render_ring);
+	init_ring_lists(&dev_priv->bsd_ring);
+	init_ring_lists(&dev_priv->blt_ring);
 	for (i = 0; i < 16; i++)
 		INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
 	INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
 			  i915_gem_retire_work_handler);
+	init_completion(&dev_priv->error_completion);
 	spin_lock(&shrink_list_lock);
 	list_add(&dev_priv->mm.shrink_list, &shrink_list);
 	spin_unlock(&shrink_list_lock);
@@ -4667,21 +4822,30 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		dev_priv->fence_reg_start = 3;
 
-	if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+	if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
 		dev_priv->num_fence_regs = 16;
 	else
 		dev_priv->num_fence_regs = 8;
 
 	/* Initialize fence registers to zero */
-	if (IS_I965G(dev)) {
+	switch (INTEL_INFO(dev)->gen) {
+	case 6:
+		for (i = 0; i < 16; i++)
+			I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
+		break;
+	case 5:
+	case 4:
 		for (i = 0; i < 16; i++)
 			I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-	} else {
-		for (i = 0; i < 8; i++)
-			I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+		break;
+	case 3:
 		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
 			for (i = 0; i < 8; i++)
 				I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+	case 2:
+		for (i = 0; i < 8; i++)
+			I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+		break;
 	}
 	i915_gem_detect_bit_6_swizzle(dev);
 	init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4691,8 +4855,8 @@
  * Create a physically contiguous memory object for this object
  * e.g. for cursor + overlay regs
  */
-int i915_gem_init_phys_object(struct drm_device *dev,
-			      int id, int size, int align)
+static int i915_gem_init_phys_object(struct drm_device *dev,
+				     int id, int size, int align)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_phys_object *phys_obj;
@@ -4724,7 +4888,7 @@
 	return ret;
 }
 
-void i915_gem_free_phys_object(struct drm_device *dev, int id)
+static void i915_gem_free_phys_object(struct drm_device *dev, int id)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_phys_object *phys_obj;
@@ -4772,11 +4936,11 @@
 	page_count = obj->size / PAGE_SIZE;
 
 	for (i = 0; i < page_count; i++) {
-		char *dst = kmap_atomic(obj_priv->pages[i], KM_USER0);
+		char *dst = kmap_atomic(obj_priv->pages[i]);
 		char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
 
 		memcpy(dst, src, PAGE_SIZE);
-		kunmap_atomic(dst, KM_USER0);
+		kunmap_atomic(dst);
 	}
 	drm_clflush_pages(obj_priv->pages, page_count);
 	drm_agp_chipset_flush(dev);
@@ -4833,11 +4997,11 @@
 	page_count = obj->size / PAGE_SIZE;
 
 	for (i = 0; i < page_count; i++) {
-		char *src = kmap_atomic(obj_priv->pages[i], KM_USER0);
+		char *src = kmap_atomic(obj_priv->pages[i]);
 		char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
 
 		memcpy(dst, src, PAGE_SIZE);
-		kunmap_atomic(src, KM_USER0);
+		kunmap_atomic(src);
 	}
 
 	i915_gem_object_put_pages(obj);
@@ -4853,34 +5017,48 @@
 		     struct drm_file *file_priv)
 {
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-	void *obj_addr;
-	int ret;
-	char __user *user_data;
+	void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset;
+	char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
 
-	user_data = (char __user *) (uintptr_t) args->data_ptr;
-	obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+	DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size);
 
-	DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size);
-	ret = copy_from_user(obj_addr, user_data, args->size);
-	if (ret)
-		return -EFAULT;
+	if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
+		unsigned long unwritten;
+
+		/* The physical object once assigned is fixed for the lifetime
+		 * of the obj, so we can safely drop the lock and continue
+		 * to access vaddr.
+		 */
+		mutex_unlock(&dev->struct_mutex);
+		unwritten = copy_from_user(vaddr, user_data, args->size);
+		mutex_lock(&dev->struct_mutex);
+		if (unwritten)
+			return -EFAULT;
+	}
 
 	drm_agp_chipset_flush(dev);
 	return 0;
 }
 
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
 
 	/* Clean up our request list when the client is going away, so that
 	 * later retire_requests won't dereference our soon-to-be-gone
 	 * file_priv.
 	 */
-	mutex_lock(&dev->struct_mutex);
-	while (!list_empty(&i915_file_priv->mm.request_list))
-		list_del_init(i915_file_priv->mm.request_list.next);
-	mutex_unlock(&dev->struct_mutex);
+	spin_lock(&file_priv->mm.lock);
+	while (!list_empty(&file_priv->mm.request_list)) {
+		struct drm_i915_gem_request *request;
+
+		request = list_first_entry(&file_priv->mm.request_list,
+					   struct drm_i915_gem_request,
+					   client_list);
+		list_del(&request->client_list);
+		request->file_priv = NULL;
+	}
+	spin_unlock(&file_priv->mm.lock);
 }
 
 static int
@@ -4889,12 +5067,8 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int lists_empty;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
-		      list_empty(&dev_priv->render_ring.active_list);
-	if (HAS_BSD(dev))
-		lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
+		      list_empty(&dev_priv->mm.active_list);
 
 	return !lists_empty;
 }
@@ -4916,7 +5090,7 @@
 			if (mutex_trylock(&dev->struct_mutex)) {
 				list_for_each_entry(obj_priv,
 						    &dev_priv->mm.inactive_list,
-						    list)
+						    mm_list)
 					cnt++;
 				mutex_unlock(&dev->struct_mutex);
 			}
@@ -4942,7 +5116,7 @@
 
 		list_for_each_entry_safe(obj_priv, next_obj,
 					 &dev_priv->mm.inactive_list,
-					 list) {
+					 mm_list) {
 			if (i915_gem_object_is_purgeable(obj_priv)) {
 				i915_gem_object_unbind(&obj_priv->base);
 				if (--nr_to_scan <= 0)
@@ -4971,7 +5145,7 @@
 
 		list_for_each_entry_safe(obj_priv, next_obj,
 					 &dev_priv->mm.inactive_list,
-					 list) {
+					 mm_list) {
 			if (nr_to_scan > 0) {
 				i915_gem_object_unbind(&obj_priv->base);
 				nr_to_scan--;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_debug.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_debug.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,29 +30,112 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#if WATCH_INACTIVE
-void
-i915_verify_inactive(struct drm_device *dev, char *file, int line)
+#if WATCH_LISTS
+int
+i915_verify_lists(struct drm_device *dev)
 {
+	static int warned;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_gem_object *obj;
-	struct drm_i915_gem_object *obj_priv;
+	struct drm_i915_gem_object *obj;
+	int err = 0;
 
-	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-		obj = &obj_priv->base;
-		if (obj_priv->pin_count || obj_priv->active ||
-		    (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-					   I915_GEM_DOMAIN_GTT)))
-			DRM_ERROR("inactive %p (p %d a %d w %x)  %s:%d\n",
+	if (warned)
+		return 0;
+
+	list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed render active %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) {
+			DRM_ERROR("invalid render active %p (a %d r %x)\n",
 				  obj,
-				  obj_priv->pin_count, obj_priv->active,
-				  obj->write_domain, file, line);
+				  obj->active,
+				  obj->base.read_domains);
+			err++;
+		} else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) {
+			DRM_ERROR("invalid render active %p (w %x, gwl %d)\n",
+				  obj,
+				  obj->base.write_domain,
+				  !list_empty(&obj->gpu_write_list));
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed flushing %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 ||
+			   list_empty(&obj->gpu_write_list)){
+			DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n",
+				  obj,
+				  obj->active,
+				  obj->base.write_domain,
+				  !list_empty(&obj->gpu_write_list));
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed gpu write %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) {
+			DRM_ERROR("invalid gpu write %p (a %d w %x)\n",
+				  obj,
+				  obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
 	}
+
+	list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed inactive %p\n", obj);
+			err++;
+			break;
+		} else if (obj->pin_count || obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+			DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n",
+				  obj,
+				  obj->pin_count, obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed pinned %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->pin_count || obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+			DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
+				  obj,
+				  obj->pin_count, obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
+	}
+
+	return warned = err;
 }
 #endif /* WATCH_INACTIVE */
 
 
-#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+#if WATCH_EXEC | WATCH_PWRITE
 static void
 i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
 		   uint32_t bias, uint32_t mark)
@@ -97,41 +180,6 @@
 }
 #endif
 
-#if WATCH_LRU
-void
-i915_dump_lru(struct drm_device *dev, const char *where)
-{
-	drm_i915_private_t		*dev_priv = dev->dev_private;
-	struct drm_i915_gem_object	*obj_priv;
-
-	DRM_INFO("active list %s {\n", where);
-	spin_lock(&dev_priv->mm.active_list_lock);
-	list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
-			    list)
-	{
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	spin_unlock(&dev_priv->mm.active_list_lock);
-	DRM_INFO("}\n");
-	DRM_INFO("flushing list %s {\n", where);
-	list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
-			    list)
-	{
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	DRM_INFO("}\n");
-	DRM_INFO("inactive %s {\n", where);
-	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	DRM_INFO("}\n");
-}
-#endif
-
-
 #if WATCH_COHERENCY
 void
 i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_evict.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_evict.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_evict.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_evict.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,49 +31,6 @@
 #include "i915_drv.h"
 #include "i915_drm.h"
 
-static struct drm_i915_gem_object *
-i915_gem_next_active_object(struct drm_device *dev,
-			    struct list_head **render_iter,
-			    struct list_head **bsd_iter)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *render_obj = NULL, *bsd_obj = NULL;
-
-	if (*render_iter != &dev_priv->render_ring.active_list)
-		render_obj = list_entry(*render_iter,
-					struct drm_i915_gem_object,
-					list);
-
-	if (HAS_BSD(dev)) {
-		if (*bsd_iter != &dev_priv->bsd_ring.active_list)
-			bsd_obj = list_entry(*bsd_iter,
-					     struct drm_i915_gem_object,
-					     list);
-
-		if (render_obj == NULL) {
-			*bsd_iter = (*bsd_iter)->next;
-			return bsd_obj;
-		}
-
-		if (bsd_obj == NULL) {
-			*render_iter = (*render_iter)->next;
-			return render_obj;
-		}
-
-		/* XXX can we handle seqno wrapping? */
-		if (render_obj->last_rendering_seqno < bsd_obj->last_rendering_seqno) {
-			*render_iter = (*render_iter)->next;
-			return render_obj;
-		} else {
-			*bsd_iter = (*bsd_iter)->next;
-			return bsd_obj;
-		}
-	} else {
-		*render_iter = (*render_iter)->next;
-		return render_obj;
-	}
-}
-
 static bool
 mark_free(struct drm_i915_gem_object *obj_priv,
 	   struct list_head *unwind)
@@ -83,18 +40,12 @@
 	return drm_mm_scan_add_block(obj_priv->gtt_space);
 }
 
-#define i915_for_each_active_object(OBJ, R, B) \
-	*(R) = dev_priv->render_ring.active_list.next; \
-	*(B) = dev_priv->bsd_ring.active_list.next; \
-	while (((OBJ) = i915_gem_next_active_object(dev, (R), (B))) != NULL)
-
 int
 i915_gem_evict_something(struct drm_device *dev, int min_size, unsigned alignment)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct list_head eviction_list, unwind_list;
 	struct drm_i915_gem_object *obj_priv;
-	struct list_head *render_iter, *bsd_iter;
 	int ret = 0;
 
 	i915_gem_retire_requests(dev);
@@ -131,13 +82,13 @@
 	drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);
 
 	/* First see if there is a large enough contiguous idle region... */
-	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
 		if (mark_free(obj_priv, &unwind_list))
 			goto found;
 	}
 
 	/* Now merge in the soon-to-be-expired objects... */
-	i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+	list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
 		/* Does the object require an outstanding flush? */
 		if (obj_priv->base.write_domain || obj_priv->pin_count)
 			continue;
@@ -147,14 +98,14 @@
 	}
 
 	/* Finally add anything with a pending flush (in order of retirement) */
-	list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+	list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
 		if (obj_priv->pin_count)
 			continue;
 
 		if (mark_free(obj_priv, &unwind_list))
 			goto found;
 	}
-	i915_for_each_active_object(obj_priv, &render_iter, &bsd_iter) {
+	list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
 		if (! obj_priv->base.write_domain || obj_priv->pin_count)
 			continue;
 
@@ -212,14 +163,9 @@
 	int ret;
 	bool lists_empty;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
-		       list_empty(&dev_priv->render_ring.active_list) &&
-		       (!HAS_BSD(dev)
-			|| list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
+		       list_empty(&dev_priv->mm.active_list));
 	if (lists_empty)
 		return -ENOSPC;
 
@@ -234,13 +180,9 @@
 	if (ret)
 		return ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
-		       list_empty(&dev_priv->render_ring.active_list) &&
-		       (!HAS_BSD(dev)
-			|| list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
+		       list_empty(&dev_priv->mm.active_list));
 	BUG_ON(!lists_empty);
 
 	return 0;
@@ -258,7 +200,7 @@
 
 		obj = &list_first_entry(&dev_priv->mm.inactive_list,
 					struct drm_i915_gem_object,
-					list)->base;
+					mm_list)->base;
 
 		ret = i915_gem_object_unbind(obj);
 		if (ret != 0) {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_tiling.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_tiling.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_gem_tiling.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_gem_tiling.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,13 +92,13 @@
 	uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 	uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
-	if (IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+	if (IS_GEN5(dev) || IS_GEN6(dev)) {
 		/* On Ironlake whatever DRAM config, GPU always do
 		 * same swizzling setup.
 		 */
 		swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 		swizzle_y = I915_BIT_6_SWIZZLE_9;
-	} else if (!IS_I9XX(dev)) {
+	} else if (IS_GEN2(dev)) {
 		/* As far as we know, the 865 doesn't have these bit 6
 		 * swizzling issues.
 		 */
@@ -190,19 +190,19 @@
 	if (tiling_mode == I915_TILING_NONE)
 		return true;
 
-	if (!IS_I9XX(dev) ||
+	if (IS_GEN2(dev) ||
 	    (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
 		tile_width = 128;
 	else
 		tile_width = 512;
 
 	/* check maximum stride & object size */
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		/* i965 stores the end address of the gtt mapping in the fence
 		 * reg, so dont bother to check the size */
 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
 			return false;
-	} else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+	} else {
 		if (stride > 8192)
 			return false;
 
@@ -216,7 +216,7 @@
 	}
 
 	/* 965+ just needs multiples of tile width */
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		if (stride & (tile_width - 1))
 			return false;
 		return true;
@@ -244,16 +244,18 @@
 	if (tiling_mode == I915_TILING_NONE)
 		return true;
 
-	if (!IS_I965G(dev)) {
-		if (obj_priv->gtt_offset & (obj->size - 1))
+	if (INTEL_INFO(dev)->gen >= 4)
+		return true;
+
+	if (obj_priv->gtt_offset & (obj->size - 1))
+		return false;
+
+	if (IS_GEN3(dev)) {
+		if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
+			return false;
+	} else {
+		if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
 			return false;
-		if (IS_I9XX(dev)) {
-			if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
-				return false;
-		} else {
-			if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
-				return false;
-		}
 	}
 
 	return true;
@@ -271,7 +273,11 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-	int ret = 0;
+	int ret;
+
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
@@ -328,7 +334,7 @@
 		if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
 			ret = i915_gem_object_unbind(obj);
 		else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-			ret = i915_gem_object_put_fence_reg(obj);
+			ret = i915_gem_object_put_fence_reg(obj, true);
 		else
 			i915_gem_release_mmap(obj);
 
@@ -399,16 +405,14 @@
  * bit 17 of its physical address and therefore being interpreted differently
  * by the GPU.
  */
-static int
+static void
 i915_gem_swizzle_page(struct page *page)
 {
+	char temp[64];
 	char *vaddr;
 	int i;
-	char temp[64];
 
 	vaddr = kmap(page);
-	if (vaddr == NULL)
-		return -ENOMEM;
 
 	for (i = 0; i < PAGE_SIZE; i += 128) {
 		memcpy(temp, &vaddr[i], 64);
@@ -417,8 +421,6 @@
 	}
 
 	kunmap(page);
-
-	return 0;
 }
 
 void
@@ -440,11 +442,7 @@
 		char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
 		if ((new_bit_17 & 0x1) !=
 		    (test_bit(i, obj_priv->bit_17) != 0)) {
-			int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
-			if (ret != 0) {
-				DRM_ERROR("Failed to swizzle page\n");
-				return;
-			}
+			i915_gem_swizzle_page(obj_priv->pages[i]);
 			set_page_dirty(obj_priv->pages[i]);
 		}
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_irq.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_irq.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -85,7 +85,7 @@
 }
 
 /* For display hotplug interrupt */
-void
+static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
 	if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -172,7 +172,7 @@
 	else {
 		i915_enable_pipestat(dev_priv, 1,
 				     PIPE_LEGACY_BLC_EVENT_ENABLE);
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			i915_enable_pipestat(dev_priv, 0,
 					     PIPE_LEGACY_BLC_EVENT_ENABLE);
 	}
@@ -191,12 +191,7 @@
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
-	if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
-		return 1;
-
-	return 0;
+	return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -207,10 +202,7 @@
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long high_frame;
 	unsigned long low_frame;
-	u32 high1, high2, low, count;
-
-	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	u32 high1, high2, low;
 
 	if (!i915_pipe_enabled(dev, pipe)) {
 		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -218,23 +210,23 @@
 		return 0;
 	}
 
+	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
 	/*
 	 * High & low register fields aren't synchronized, so make sure
 	 * we get a low value that's stable across two reads of the high
 	 * register.
 	 */
 	do {
-		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
-		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
-			PIPE_FRAME_LOW_SHIFT);
-		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
+		high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
+		low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
+		high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
 	} while (high1 != high2);
 
-	count = (high1 << 8) | low;
-
-	return count;
+	high1 >>= PIPE_FRAME_HIGH_SHIFT;
+	low >>= PIPE_FRAME_LOW_SHIFT;
+	return (high1 << 8) | low;
 }
 
 u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -260,16 +252,12 @@
 						    hotplug_work);
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
+
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+		if (encoder->hot_plug)
+			encoder->hot_plug(encoder);
 
-	if (mode_config->num_encoder) {
-		list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-			struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	
-			if (intel_encoder->hot_plug)
-				(*intel_encoder->hot_plug) (intel_encoder);
-		}
-	}
 	/* Just fire off a uevent and let userspace tell us what to do */
 	drm_helper_hpd_irq_event(dev);
 }
@@ -305,13 +293,30 @@
 	return;
 }
 
-irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+static void notify_ring(struct drm_device *dev,
+			struct intel_ring_buffer *ring)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 seqno = ring->get_seqno(dev, ring);
+	ring->irq_gem_seqno = seqno;
+	trace_i915_gem_request_complete(dev, seqno);
+	wake_up_all(&ring->irq_queue);
+	dev_priv->hangcheck_count = 0;
+	mod_timer(&dev_priv->hangcheck_timer,
+		  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+}
+
+static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	int ret = IRQ_NONE;
 	u32 de_iir, gt_iir, de_ier, pch_iir;
+	u32 hotplug_mask;
 	struct drm_i915_master_private *master_priv;
-	struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+	u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+	if (IS_GEN6(dev))
+		bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
 	/* disable master interrupt before clearing iir  */
 	de_ier = I915_READ(DEIER);
@@ -325,6 +330,11 @@
 	if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
 		goto done;
 
+	if (HAS_PCH_CPT(dev))
+		hotplug_mask = SDE_HOTPLUG_MASK_CPT;
+	else
+		hotplug_mask = SDE_HOTPLUG_MASK;
+
 	ret = IRQ_HANDLED;
 
 	if (dev->primary->master) {
@@ -334,29 +344,24 @@
 				READ_BREADCRUMB(dev_priv);
 	}
 
-	if (gt_iir & GT_PIPE_NOTIFY) {
-		u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
-		render_ring->irq_gem_seqno = seqno;
-		trace_i915_gem_request_complete(dev, seqno);
-		DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
-		dev_priv->hangcheck_count = 0;
-		mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
-	}
-	if (gt_iir & GT_BSD_USER_INTERRUPT)
-		DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
+	if (gt_iir & GT_PIPE_NOTIFY)
+		notify_ring(dev, &dev_priv->render_ring);
+	if (gt_iir & bsd_usr_interrupt)
+		notify_ring(dev, &dev_priv->bsd_ring);
+	if (HAS_BLT(dev) && gt_iir & GT_BLT_USER_INTERRUPT)
+		notify_ring(dev, &dev_priv->blt_ring);
 
 	if (de_iir & DE_GSE)
-		ironlake_opregion_gse_intr(dev);
+		intel_opregion_gse_intr(dev);
 
 	if (de_iir & DE_PLANEA_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 0);
-		intel_finish_page_flip(dev, 0);
+		intel_finish_page_flip_plane(dev, 0);
 	}
 
 	if (de_iir & DE_PLANEB_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 1);
-		intel_finish_page_flip(dev, 1);
+		intel_finish_page_flip_plane(dev, 1);
 	}
 
 	if (de_iir & DE_PIPEA_VBLANK)
@@ -366,10 +371,8 @@
 		drm_handle_vblank(dev, 1);
 
 	/* check event from PCH */
-	if ((de_iir & DE_PCH_EVENT) &&
-	    (pch_iir & SDE_HOTPLUG_MASK)) {
+	if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask))
 		queue_work(dev_priv->wq, &dev_priv->hotplug_work);
-	}
 
 	if (de_iir & DE_PCU_EVENT) {
 		I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
@@ -404,23 +407,20 @@
 	char *reset_event[] = { "RESET=1", NULL };
 	char *reset_done_event[] = { "ERROR=0", NULL };
 
-	DRM_DEBUG_DRIVER("generating error event\n");
 	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
 	if (atomic_read(&dev_priv->mm.wedged)) {
-		if (IS_I965G(dev)) {
-			DRM_DEBUG_DRIVER("resetting chip\n");
-			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
-			if (!i965_reset(dev, GDRST_RENDER)) {
-				atomic_set(&dev_priv->mm.wedged, 0);
-				kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
-			}
-		} else {
-			DRM_DEBUG_DRIVER("reboot required\n");
+		DRM_DEBUG_DRIVER("resetting chip\n");
+		kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+		if (!i915_reset(dev, GRDOM_RENDER)) {
+			atomic_set(&dev_priv->mm.wedged, 0);
+			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
 		}
+		complete_all(&dev_priv->error_completion);
 	}
 }
 
+#ifdef CONFIG_DEBUG_FS
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_device *dev,
 			 struct drm_gem_object *src)
@@ -456,10 +456,9 @@
 
 		local_irq_save(flags);
 		s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-					     reloc_offset,
-					     KM_IRQ0);
+					     reloc_offset);
 		memcpy_fromio(d, s, PAGE_SIZE);
-		io_mapping_unmap_atomic(s, KM_IRQ0);
+		io_mapping_unmap_atomic(s);
 		local_irq_restore(flags);
 
 		dst->pages[page] = d;
@@ -511,7 +510,7 @@
 
 	if (IS_I830(dev) || IS_845G(dev))
 		cmd = MI_BATCH_BUFFER;
-	else if (IS_I965G(dev))
+	else if (INTEL_INFO(dev)->gen >= 4)
 		cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
 		       MI_BATCH_NON_SECURE_I965);
 	else
@@ -584,13 +583,16 @@
 		return;
 	}
 
-	error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
+	DRM_DEBUG_DRIVER("generating error event\n");
+
+	error->seqno =
+		dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
 	error->eir = I915_READ(EIR);
 	error->pgtbl_er = I915_READ(PGTBL_ER);
 	error->pipeastat = I915_READ(PIPEASTAT);
 	error->pipebstat = I915_READ(PIPEBSTAT);
 	error->instpm = I915_READ(INSTPM);
-	if (!IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen < 4) {
 		error->ipeir = I915_READ(IPEIR);
 		error->ipehr = I915_READ(IPEHR);
 		error->instdone = I915_READ(INSTDONE);
@@ -612,9 +614,7 @@
 	batchbuffer[0] = NULL;
 	batchbuffer[1] = NULL;
 	count = 0;
-	list_for_each_entry(obj_priv,
-			&dev_priv->render_ring.active_list, list) {
-
+	list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
 		struct drm_gem_object *obj = &obj_priv->base;
 
 		if (batchbuffer[0] == NULL &&
@@ -631,7 +631,7 @@
 	}
 	/* Scan the other lists for completeness for those bizarre errors. */
 	if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-		list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+		list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, mm_list) {
 			struct drm_gem_object *obj = &obj_priv->base;
 
 			if (batchbuffer[0] == NULL &&
@@ -649,7 +649,7 @@
 		}
 	}
 	if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
-		list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
+		list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, mm_list) {
 			struct drm_gem_object *obj = &obj_priv->base;
 
 			if (batchbuffer[0] == NULL &&
@@ -668,7 +668,7 @@
 	}
 
 	/* We need to copy these to an anonymous buffer as the simplest
-	 * method to avoid being overwritten by userpace.
+	 * method to avoid being overwritten by userspace.
 	 */
 	error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
 	if (batchbuffer[1] != batchbuffer[0])
@@ -690,8 +690,7 @@
 
 	if (error->active_bo) {
 		int i = 0;
-		list_for_each_entry(obj_priv,
-				&dev_priv->render_ring.active_list, list) {
+		list_for_each_entry(obj_priv, &dev_priv->mm.active_list, mm_list) {
 			struct drm_gem_object *obj = &obj_priv->base;
 
 			error->active_bo[i].size = obj->size;
@@ -744,6 +743,9 @@
 	if (error)
 		i915_error_state_free(dev, error);
 }
+#else
+#define i915_capture_error_state(x)
+#endif
 
 static void i915_report_and_clear_eir(struct drm_device *dev)
 {
@@ -785,7 +787,7 @@
 		}
 	}
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (eir & I915_ERROR_PAGE_TABLE) {
 			u32 pgtbl_err = I915_READ(PGTBL_ER);
 			printk(KERN_ERR "page table error\n");
@@ -811,7 +813,7 @@
 		printk(KERN_ERR "instruction error\n");
 		printk(KERN_ERR "  INSTPM: 0x%08x\n",
 		       I915_READ(INSTPM));
-		if (!IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen < 4) {
 			u32 ipeir = I915_READ(IPEIR);
 
 			printk(KERN_ERR "  IPEIR: 0x%08x\n",
@@ -876,12 +878,17 @@
 	i915_report_and_clear_eir(dev);
 
 	if (wedged) {
+		INIT_COMPLETION(dev_priv->error_completion);
 		atomic_set(&dev_priv->mm.wedged, 1);
 
 		/*
 		 * Wakeup waiting processes so they don't hang
 		 */
-		DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+		wake_up_all(&dev_priv->render_ring.irq_queue);
+		if (HAS_BSD(dev))
+			wake_up_all(&dev_priv->bsd_ring.irq_queue);
+		if (HAS_BLT(dev))
+			wake_up_all(&dev_priv->blt_ring.irq_queue);
 	}
 
 	queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -912,7 +919,7 @@
 
 	/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
 	obj_priv = to_intel_bo(work->pending_flip_obj);
-	if(IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
 		stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
 	} else {
@@ -942,7 +949,6 @@
 	unsigned long irqflags;
 	int irq_received;
 	int ret = IRQ_NONE;
-	struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
 
 	atomic_inc(&dev_priv->irq_received);
 
@@ -951,7 +957,7 @@
 
 	iir = I915_READ(IIR);
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
 	else
 		vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
@@ -1019,18 +1025,10 @@
 					READ_BREADCRUMB(dev_priv);
 		}
 
-		if (iir & I915_USER_INTERRUPT) {
-			u32 seqno =
-				render_ring->get_gem_seqno(dev, render_ring);
-			render_ring->irq_gem_seqno = seqno;
-			trace_i915_gem_request_complete(dev, seqno);
-			DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
-			dev_priv->hangcheck_count = 0;
-			mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
-		}
-
+		if (iir & I915_USER_INTERRUPT)
+			notify_ring(dev, &dev_priv->render_ring);
 		if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
-			DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+			notify_ring(dev, &dev_priv->bsd_ring);
 
 		if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
 			intel_prepare_page_flip(dev, 0);
@@ -1065,7 +1063,7 @@
 		if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 		    (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 		    (iir & I915_ASLE_INTERRUPT))
-			opregion_asle_intr(dev);
+			intel_opregion_asle_intr(dev);
 
 		/* With MSI, interrupts are only generated when iir
 		 * transitions from zero to nonzero.  If another bit got
@@ -1207,18 +1205,15 @@
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	u32 pipeconf;
 
-	pipeconf = I915_READ(pipeconf_reg);
-	if (!(pipeconf & PIPEACONF_ENABLE))
+	if (!i915_pipe_enabled(dev, pipe))
 		return -EINVAL;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	if (HAS_PCH_SPLIT(dev))
 		ironlake_enable_display_irq(dev_priv, (pipe == 0) ? 
 					    DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-	else if (IS_I965G(dev))
+	else if (INTEL_INFO(dev)->gen >= 4)
 		i915_enable_pipestat(dev_priv, pipe,
 				     PIPE_START_VBLANK_INTERRUPT_ENABLE);
 	else
@@ -1252,7 +1247,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (!HAS_PCH_SPLIT(dev))
-		opregion_enable_asle(dev);
+		intel_opregion_enable_asle(dev);
 	dev_priv->irq_enabled = 1;
 }
 
@@ -1311,7 +1306,7 @@
 	return -EINVAL;
 }
 
-struct drm_i915_gem_request *
+static struct drm_i915_gem_request *
 i915_get_tail_request(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1331,11 +1326,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	uint32_t acthd, instdone, instdone1;
 
-	/* No reset support on this chip yet. */
-	if (IS_GEN6(dev))
-		return;
-
-	if (!IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen < 4) {
 		acthd = I915_READ(ACTHD);
 		instdone = I915_READ(INSTDONE);
 		instdone1 = 0;
@@ -1347,9 +1338,8 @@
 
 	/* If all work is done then ACTHD clearly hasn't advanced. */
 	if (list_empty(&dev_priv->render_ring.request_list) ||
-		i915_seqno_passed(i915_get_gem_seqno(dev,
-				&dev_priv->render_ring),
-			i915_get_tail_request(dev)->seqno)) {
+		i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
+				  i915_get_tail_request(dev)->seqno)) {
 		bool missed_wakeup = false;
 
 		dev_priv->hangcheck_count = 0;
@@ -1357,13 +1347,19 @@
 		/* Issue a wake-up to catch stuck h/w. */
 		if (dev_priv->render_ring.waiting_gem_seqno &&
 		    waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-			DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+			wake_up_all(&dev_priv->render_ring.irq_queue);
 			missed_wakeup = true;
 		}
 
 		if (dev_priv->bsd_ring.waiting_gem_seqno &&
 		    waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-			DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+			wake_up_all(&dev_priv->bsd_ring.irq_queue);
+			missed_wakeup = true;
+		}
+
+		if (dev_priv->blt_ring.waiting_gem_seqno &&
+		    waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
+			wake_up_all(&dev_priv->blt_ring.irq_queue);
 			missed_wakeup = true;
 		}
 
@@ -1377,6 +1373,21 @@
 	    dev_priv->last_instdone1 == instdone1) {
 		if (dev_priv->hangcheck_count++ > 1) {
 			DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+
+			if (!IS_GEN2(dev)) {
+				/* Is the chip hanging on a WAIT_FOR_EVENT?
+				 * If so we can simply poke the RB_WAIT bit
+				 * and break the hang. This should work on
+				 * all but the second generation chipsets.
+				 */
+				u32 tmp = I915_READ(PRB0_CTL);
+				if (tmp & RING_WAIT) {
+					I915_WRITE(PRB0_CTL, tmp);
+					POSTING_READ(PRB0_CTL);
+					goto out;
+				}
+			}
+
 			i915_handle_error(dev, true);
 			return;
 		}
@@ -1388,8 +1399,10 @@
 		dev_priv->last_instdone1 = instdone1;
 	}
 
+out:
 	/* Reset timer case chip hangs without another request being added */
-	mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+	mod_timer(&dev_priv->hangcheck_timer,
+		  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
 /* drm_dma.h hooks
@@ -1424,8 +1437,7 @@
 	u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
 			   DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
 	u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
-	u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
-			   SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+	u32 hotplug_mask;
 
 	dev_priv->irq_mask_reg = ~display_mask;
 	dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK;
@@ -1436,20 +1448,35 @@
 	I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
 	(void) I915_READ(DEIER);
 
-	/* Gen6 only needs render pipe_control now */
-	if (IS_GEN6(dev))
-		render_mask = GT_PIPE_NOTIFY;
+	if (IS_GEN6(dev)) {
+		render_mask =
+			GT_PIPE_NOTIFY |
+			GT_GEN6_BSD_USER_INTERRUPT |
+			GT_BLT_USER_INTERRUPT;
+	}
 
 	dev_priv->gt_irq_mask_reg = ~render_mask;
 	dev_priv->gt_irq_enable_reg = render_mask;
 
 	I915_WRITE(GTIIR, I915_READ(GTIIR));
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev)) {
 		I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+		I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+		I915_WRITE(GEN6_BLITTER_IMR, ~GEN6_BLITTER_USER_INTERRUPT);
+	}
+
 	I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
 	(void) I915_READ(GTIER);
 
+	if (HAS_PCH_CPT(dev)) {
+		hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT  |
+			       SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ;
+	} else {
+		hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
+			       SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
+	}
+
 	dev_priv->pch_irq_mask_reg = ~hotplug_mask;
 	dev_priv->pch_irq_enable_reg = hotplug_mask;
 
@@ -1506,9 +1533,10 @@
 	u32 error_mask;
 
 	DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
-
 	if (HAS_BSD(dev))
 		DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
+	if (HAS_BLT(dev))
+		DRM_INIT_WAITQUEUE(&dev_priv->blt_ring.irq_queue);
 
 	dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
@@ -1578,7 +1606,7 @@
 		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 	}
 
-	opregion_enable_asle(dev);
+	intel_opregion_enable_asle(dev);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_opregion.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_opregion.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_opregion.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_opregion.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,562 +0,0 @@
-/*
- * Copyright 2008 Intel Corporation <hong.liu@intel.com>
- * Copyright 2008 Red Hat <mjg@redhat.com>
- *
- * 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, sub license, 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 (including the
- * next paragraph) 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
- * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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.
- *
- */
-
-#include <linux/acpi.h>
-#include <acpi/video.h>
-
-#include "drmP.h"
-#include "i915_drm.h"
-#include "i915_drv.h"
-
-#define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
-#define PCI_ASLS 0xfc
-
-#define OPREGION_SZ            (8*1024)
-#define OPREGION_HEADER_OFFSET 0
-#define OPREGION_ACPI_OFFSET   0x100
-#define OPREGION_SWSCI_OFFSET  0x200
-#define OPREGION_ASLE_OFFSET   0x300
-#define OPREGION_VBT_OFFSET    0x1000
-
-#define OPREGION_SIGNATURE "IntelGraphicsMem"
-#define MBOX_ACPI      (1<<0)
-#define MBOX_SWSCI     (1<<1)
-#define MBOX_ASLE      (1<<2)
-
-struct opregion_header {
-       u8 signature[16];
-       u32 size;
-       u32 opregion_ver;
-       u8 bios_ver[32];
-       u8 vbios_ver[16];
-       u8 driver_ver[16];
-       u32 mboxes;
-       u8 reserved[164];
-} __attribute__((packed));
-
-/* OpRegion mailbox #1: public ACPI methods */
-struct opregion_acpi {
-       u32 drdy;       /* driver readiness */
-       u32 csts;       /* notification status */
-       u32 cevt;       /* current event */
-       u8 rsvd1[20];
-       u32 didl[8];    /* supported display devices ID list */
-       u32 cpdl[8];    /* currently presented display list */
-       u32 cadl[8];    /* currently active display list */
-       u32 nadl[8];    /* next active devices list */
-       u32 aslp;       /* ASL sleep time-out */
-       u32 tidx;       /* toggle table index */
-       u32 chpd;       /* current hotplug enable indicator */
-       u32 clid;       /* current lid state*/
-       u32 cdck;       /* current docking state */
-       u32 sxsw;       /* Sx state resume */
-       u32 evts;       /* ASL supported events */
-       u32 cnot;       /* current OS notification */
-       u32 nrdy;       /* driver status */
-       u8 rsvd2[60];
-} __attribute__((packed));
-
-/* OpRegion mailbox #2: SWSCI */
-struct opregion_swsci {
-       u32 scic;       /* SWSCI command|status|data */
-       u32 parm;       /* command parameters */
-       u32 dslp;       /* driver sleep time-out */
-       u8 rsvd[244];
-} __attribute__((packed));
-
-/* OpRegion mailbox #3: ASLE */
-struct opregion_asle {
-       u32 ardy;       /* driver readiness */
-       u32 aslc;       /* ASLE interrupt command */
-       u32 tche;       /* technology enabled indicator */
-       u32 alsi;       /* current ALS illuminance reading */
-       u32 bclp;       /* backlight brightness to set */
-       u32 pfit;       /* panel fitting state */
-       u32 cblv;       /* current brightness level */
-       u16 bclm[20];   /* backlight level duty cycle mapping table */
-       u32 cpfm;       /* current panel fitting mode */
-       u32 epfm;       /* enabled panel fitting modes */
-       u8 plut[74];    /* panel LUT and identifier */
-       u32 pfmb;       /* PWM freq and min brightness */
-       u8 rsvd[102];
-} __attribute__((packed));
-
-/* ASLE irq request bits */
-#define ASLE_SET_ALS_ILLUM     (1 << 0)
-#define ASLE_SET_BACKLIGHT     (1 << 1)
-#define ASLE_SET_PFIT          (1 << 2)
-#define ASLE_SET_PWM_FREQ      (1 << 3)
-#define ASLE_REQ_MSK           0xf
-
-/* response bits of ASLE irq request */
-#define ASLE_ALS_ILLUM_FAILED	(1<<10)
-#define ASLE_BACKLIGHT_FAILED	(1<<12)
-#define ASLE_PFIT_FAILED	(1<<14)
-#define ASLE_PWM_FREQ_FAILED	(1<<16)
-
-/* ASLE backlight brightness to set */
-#define ASLE_BCLP_VALID                (1<<31)
-#define ASLE_BCLP_MSK          (~(1<<31))
-
-/* ASLE panel fitting request */
-#define ASLE_PFIT_VALID         (1<<31)
-#define ASLE_PFIT_CENTER (1<<0)
-#define ASLE_PFIT_STRETCH_TEXT (1<<1)
-#define ASLE_PFIT_STRETCH_GFX (1<<2)
-
-/* PWM frequency and minimum brightness */
-#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
-#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
-#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
-#define ASLE_PFMB_PWM_VALID (1<<31)
-
-#define ASLE_CBLV_VALID         (1<<31)
-
-#define ACPI_OTHER_OUTPUT (0<<8)
-#define ACPI_VGA_OUTPUT (1<<8)
-#define ACPI_TV_OUTPUT (2<<8)
-#define ACPI_DIGITAL_OUTPUT (3<<8)
-#define ACPI_LVDS_OUTPUT (4<<8)
-
-static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 blc_pwm_ctl, blc_pwm_ctl2;
-	u32 max_backlight, level, shift;
-
-	if (!(bclp & ASLE_BCLP_VALID))
-		return ASLE_BACKLIGHT_FAILED;
-
-	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
-		return ASLE_BACKLIGHT_FAILED;
-
-	blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-	blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-	if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-		pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-	else {
-		if (IS_PINEVIEW(dev)) {
-			blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-			max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-		} else {
-			blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-			max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-		}
-		level = (bclp * max_backlight) / 255;
-		I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-	}
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-	return 0;
-}
-
-static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
-{
-	/* alsi is the current ALS reading in lux. 0 indicates below sensor
-	   range, 0xffff indicates above sensor range. 1-0xfffe are valid */
-	return 0;
-}
-
-static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	if (pfmb & ASLE_PFMB_PWM_VALID) {
-		u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-		u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
-		blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
-		pwm = pwm >> 9;
-		/* FIXME - what do we do with the PWM? */
-	}
-	return 0;
-}
-
-static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
-{
-	/* Panel fitting is currently controlled by the X code, so this is a
-	   noop until modesetting support works fully */
-	if (!(pfit & ASLE_PFIT_VALID))
-		return ASLE_PFIT_FAILED;
-	return 0;
-}
-
-void opregion_asle_intr(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 asle_stat = 0;
-	u32 asle_req;
-
-	if (!asle)
-		return;
-
-	asle_req = asle->aslc & ASLE_REQ_MSK;
-
-	if (!asle_req) {
-		DRM_DEBUG_DRIVER("non asle set request??\n");
-		return;
-	}
-
-	if (asle_req & ASLE_SET_ALS_ILLUM)
-		asle_stat |= asle_set_als_illum(dev, asle->alsi);
-
-	if (asle_req & ASLE_SET_BACKLIGHT)
-		asle_stat |= asle_set_backlight(dev, asle->bclp);
-
-	if (asle_req & ASLE_SET_PFIT)
-		asle_stat |= asle_set_pfit(dev, asle->pfit);
-
-	if (asle_req & ASLE_SET_PWM_FREQ)
-		asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
-
-	asle->aslc = asle_stat;
-}
-
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 cpu_pwm_ctl, pch_pwm_ctl2;
-	u32 max_backlight, level;
-
-	if (!(bclp & ASLE_BCLP_VALID))
-		return ASLE_BACKLIGHT_FAILED;
-
-	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
-		return ASLE_BACKLIGHT_FAILED;
-
-	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-	/* get the max PWM frequency */
-	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-	/* calculate the expected PMW frequency */
-	level = (bclp * max_backlight) / 255;
-	/* reserve the high 16 bits */
-	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-	/* write the updated PWM frequency */
-	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-	return 0;
-}
-
-void ironlake_opregion_gse_intr(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 asle_stat = 0;
-	u32 asle_req;
-
-	if (!asle)
-		return;
-
-	asle_req = asle->aslc & ASLE_REQ_MSK;
-
-	if (!asle_req) {
-		DRM_DEBUG_DRIVER("non asle set request??\n");
-		return;
-	}
-
-	if (asle_req & ASLE_SET_ALS_ILLUM) {
-		DRM_DEBUG_DRIVER("Illum is not supported\n");
-		asle_stat |= ASLE_ALS_ILLUM_FAILED;
-	}
-
-	if (asle_req & ASLE_SET_BACKLIGHT)
-		asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
-
-	if (asle_req & ASLE_SET_PFIT) {
-		DRM_DEBUG_DRIVER("Pfit is not supported\n");
-		asle_stat |= ASLE_PFIT_FAILED;
-	}
-
-	if (asle_req & ASLE_SET_PWM_FREQ) {
-		DRM_DEBUG_DRIVER("PWM freq is not supported\n");
-		asle_stat |= ASLE_PWM_FREQ_FAILED;
-	}
-
-	asle->aslc = asle_stat;
-}
-#define ASLE_ALS_EN    (1<<0)
-#define ASLE_BLC_EN    (1<<1)
-#define ASLE_PFIT_EN   (1<<2)
-#define ASLE_PFMB_EN   (1<<3)
-
-void opregion_enable_asle(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-
-	if (asle) {
-		if (IS_MOBILE(dev)) {
-			unsigned long irqflags;
-
-			spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
-			intel_enable_asle(dev);
-			spin_unlock_irqrestore(&dev_priv->user_irq_lock,
-					       irqflags);
-		}
-
-		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
-			ASLE_PFMB_EN;
-		asle->ardy = 1;
-	}
-}
-
-#define ACPI_EV_DISPLAY_SWITCH (1<<0)
-#define ACPI_EV_LID            (1<<1)
-#define ACPI_EV_DOCK           (1<<2)
-
-static struct intel_opregion *system_opregion;
-
-static int intel_opregion_video_event(struct notifier_block *nb,
-				      unsigned long val, void *data)
-{
-	/* The only video events relevant to opregion are 0x80. These indicate
-	   either a docking event, lid switch or display switch request. In
-	   Linux, these are handled by the dock, button and video drivers.
-	   We might want to fix the video driver to be opregion-aware in
-	   future, but right now we just indicate to the firmware that the
-	   request has been handled */
-
-	struct opregion_acpi *acpi;
-
-	if (!system_opregion)
-		return NOTIFY_DONE;
-
-	acpi = system_opregion->acpi;
-	acpi->csts = 0;
-
-	return NOTIFY_OK;
-}
-
-static struct notifier_block intel_opregion_notifier = {
-	.notifier_call = intel_opregion_video_event,
-};
-
-/*
- * Initialise the DIDL field in opregion. This passes a list of devices to
- * the firmware. Values are defined by section B.4.2 of the ACPI specification
- * (version 3)
- */
-
-static void intel_didl_outputs(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_opregion *opregion = &dev_priv->opregion;
-	struct drm_connector *connector;
-	acpi_handle handle;
-	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
-	unsigned long long device_id;
-	acpi_status status;
-	int i = 0;
-
-	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
-	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
-		return;
-
-	if (acpi_is_video_device(acpi_dev))
-		acpi_video_bus = acpi_dev;
-	else {
-		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
-			if (acpi_is_video_device(acpi_cdev)) {
-				acpi_video_bus = acpi_cdev;
-				break;
-			}
-		}
-	}
-
-	if (!acpi_video_bus) {
-		printk(KERN_WARNING "No ACPI video bus found\n");
-		return;
-	}
-
-	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
-		if (i >= 8) {
-			dev_printk (KERN_ERR, &dev->pdev->dev,
-				    "More than 8 outputs detected\n");
-			return;
-		}
-		status =
-			acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
-						NULL, &device_id);
-		if (ACPI_SUCCESS(status)) {
-			if (!device_id)
-				goto blind_set;
-			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
-			i++;
-		}
-	}
-
-end:
-	/* If fewer than 8 outputs, the list must be null terminated */
-	if (i < 8)
-		opregion->acpi->didl[i] = 0;
-	return;
-
-blind_set:
-	i = 0;
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		int output_type = ACPI_OTHER_OUTPUT;
-		if (i >= 8) {
-			dev_printk (KERN_ERR, &dev->pdev->dev,
-				    "More than 8 outputs detected\n");
-			return;
-		}
-		switch (connector->connector_type) {
-		case DRM_MODE_CONNECTOR_VGA:
-		case DRM_MODE_CONNECTOR_DVIA:
-			output_type = ACPI_VGA_OUTPUT;
-			break;
-		case DRM_MODE_CONNECTOR_Composite:
-		case DRM_MODE_CONNECTOR_SVIDEO:
-		case DRM_MODE_CONNECTOR_Component:
-		case DRM_MODE_CONNECTOR_9PinDIN:
-			output_type = ACPI_TV_OUTPUT;
-			break;
-		case DRM_MODE_CONNECTOR_DVII:
-		case DRM_MODE_CONNECTOR_DVID:
-		case DRM_MODE_CONNECTOR_DisplayPort:
-		case DRM_MODE_CONNECTOR_HDMIA:
-		case DRM_MODE_CONNECTOR_HDMIB:
-			output_type = ACPI_DIGITAL_OUTPUT;
-			break;
-		case DRM_MODE_CONNECTOR_LVDS:
-			output_type = ACPI_LVDS_OUTPUT;
-			break;
-		}
-		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
-		i++;
-	}
-	goto end;
-}
-
-int intel_opregion_init(struct drm_device *dev, int resume)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_opregion *opregion = &dev_priv->opregion;
-	void *base;
-	u32 asls, mboxes;
-	int err = 0;
-
-	pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
-	DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
-	if (asls == 0) {
-		DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
-		return -ENOTSUPP;
-	}
-
-	base = ioremap(asls, OPREGION_SZ);
-	if (!base)
-		return -ENOMEM;
-
-	opregion->header = base;
-	if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
-		DRM_DEBUG_DRIVER("opregion signature mismatch\n");
-		err = -EINVAL;
-		goto err_out;
-	}
-
-	mboxes = opregion->header->mboxes;
-	if (mboxes & MBOX_ACPI) {
-		DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
-		opregion->acpi = base + OPREGION_ACPI_OFFSET;
-		if (drm_core_check_feature(dev, DRIVER_MODESET))
-			intel_didl_outputs(dev);
-	} else {
-		DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
-		err = -ENOTSUPP;
-		goto err_out;
-	}
-	opregion->enabled = 1;
-
-	if (mboxes & MBOX_SWSCI) {
-		DRM_DEBUG_DRIVER("SWSCI supported\n");
-		opregion->swsci = base + OPREGION_SWSCI_OFFSET;
-	}
-	if (mboxes & MBOX_ASLE) {
-		DRM_DEBUG_DRIVER("ASLE supported\n");
-		opregion->asle = base + OPREGION_ASLE_OFFSET;
-		opregion_enable_asle(dev);
-	}
-
-	if (!resume)
-		acpi_video_register();
-
-
-	/* Notify BIOS we are ready to handle ACPI video ext notifs.
-	 * Right now, all the events are handled by the ACPI video module.
-	 * We don't actually need to do anything with them. */
-	opregion->acpi->csts = 0;
-	opregion->acpi->drdy = 1;
-
-	system_opregion = opregion;
-	register_acpi_notifier(&intel_opregion_notifier);
-
-	return 0;
-
-err_out:
-	iounmap(opregion->header);
-	opregion->header = NULL;
-	acpi_video_register();
-	return err;
-}
-
-void intel_opregion_free(struct drm_device *dev, int suspend)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_opregion *opregion = &dev_priv->opregion;
-
-	if (!opregion->enabled)
-		return;
-
-	if (!suspend)
-		acpi_video_unregister();
-
-	opregion->acpi->drdy = 0;
-
-	system_opregion = NULL;
-	unregister_acpi_notifier(&intel_opregion_notifier);
-
-	/* just clear all opregion memory pointers now */
-	iounmap(opregion->header);
-	opregion->header = NULL;
-	opregion->acpi = NULL;
-	opregion->swsci = NULL;
-	opregion->asle = NULL;
-
-	opregion->enabled = 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_reg.h linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_reg.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_reg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_reg.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,52 +25,16 @@
 #ifndef _I915_REG_H_
 #define _I915_REG_H_
 
+#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+
 /*
  * The Bridge device's PCI config space has information about the
  * fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
  */
 #define INTEL_GMCH_CTRL		0x52
 #define INTEL_GMCH_VGA_DISABLE  (1 << 1)
-#define INTEL_GMCH_ENABLED	0x4
-#define INTEL_GMCH_MEM_MASK	0x1
-#define INTEL_GMCH_MEM_64M	0x1
-#define INTEL_GMCH_MEM_128M	0
-
-#define INTEL_GMCH_GMS_MASK		(0xf << 4)
-#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4)
-#define INTEL_GMCH_GMS_STOLEN_128M	(0x8 << 4)
-#define INTEL_GMCH_GMS_STOLEN_256M	(0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M	(0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M	(0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M	(0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M	(0xd << 4)
-
-#define SNB_GMCH_CTRL	0x50
-#define SNB_GMCH_GMS_STOLEN_MASK	0xF8
-#define SNB_GMCH_GMS_STOLEN_32M		(1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M		(2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M		(3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M	(4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M	(5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M	(6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M	(7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M	(8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M	(9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M	(0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M	(0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M	(0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M	(0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M	(0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M	(0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M	(0x10 << 3)
 
 /* PCI config space */
 
@@ -106,10 +70,13 @@
 #define   I915_GC_RENDER_CLOCK_200_MHZ	(1 << 0)
 #define   I915_GC_RENDER_CLOCK_333_MHZ	(4 << 0)
 #define LBB	0xf4
-#define GDRST 0xc0
-#define  GDRST_FULL	(0<<2)
-#define  GDRST_RENDER	(1<<2)
-#define  GDRST_MEDIA	(3<<2)
+
+/* Graphics reset regs */
+#define I965_GDRST 0xc0 /* PCI config register */
+#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define  GRDOM_FULL	(0<<2)
+#define  GRDOM_RENDER	(1<<2)
+#define  GRDOM_MEDIA	(3<<2)
 
 /* VGA stuff */
 
@@ -192,11 +159,11 @@
 #define MI_STORE_DWORD_INDEX	MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
 #define MI_LOAD_REGISTER_IMM	MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW		MI_INSTR(0x26, 2) /* for GEN6 */
 #define MI_BATCH_BUFFER		MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE	(1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define MI_BATCH_BUFFER_START	MI_INSTR(0x31, 0)
-
 /*
  * 3D instructions used by the kernel
  */
@@ -249,6 +216,16 @@
 #define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
 #define   PIPE_CONTROL_STALL_EN	(1<<1) /* in addr word, Ironlake+ only */
 
+
+/*
+ * Reset registers
+ */
+#define DEBUG_RESET_I830		0x6070
+#define  DEBUG_RESET_FULL		(1<<7)
+#define  DEBUG_RESET_RENDER		(1<<8)
+#define  DEBUG_RESET_DISPLAY		(1<<9)
+
+
 /*
  * Fence registers
  */
@@ -283,6 +260,17 @@
 #define PRB0_HEAD	0x02034
 #define PRB0_START	0x02038
 #define PRB0_CTL	0x0203c
+#define RENDER_RING_BASE	0x02000
+#define BSD_RING_BASE		0x04000
+#define GEN6_BSD_RING_BASE	0x12000
+#define BLT_RING_BASE		0x22000
+#define RING_TAIL(base)		((base)+0x30)
+#define RING_HEAD(base)		((base)+0x34)
+#define RING_START(base)	((base)+0x38)
+#define RING_CTL(base)		((base)+0x3c)
+#define RING_HWS_PGA(base)	((base)+0x80)
+#define RING_HWS_PGA_GEN6(base)	((base)+0x2080)
+#define RING_ACTHD(base)	((base)+0x74)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000
 #define   HEAD_WRAP_ONE		0x00200000
@@ -295,6 +283,8 @@
 #define   RING_VALID_MASK	0x00000001
 #define   RING_VALID		0x00000001
 #define   RING_INVALID		0x00000000
+#define   RING_WAIT_I8XX	(1<<0) /* gen2, PRBx_HEAD */
+#define   RING_WAIT		(1<<11) /* gen3+, PRBx_CTL */
 #define PRB1_TAIL	0x02040 /* 915+ only */
 #define PRB1_HEAD	0x02044 /* 915+ only */
 #define PRB1_START	0x02048 /* 915+ only */
@@ -306,7 +296,6 @@
 #define INSTDONE1	0x0207c /* 965+ only */
 #define ACTHD_I965	0x02074
 #define HWS_PGA		0x02080
-#define HWS_PGA_GEN6	0x04080
 #define HWS_ADDRESS_MASK	0xfffff000
 #define HWS_START_ADDRESS_SHIFT	4
 #define PWRCTXA		0x2088 /* 965GM+ only */
@@ -464,17 +453,17 @@
 #define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR	(1 << 25)
 #define   GEN6_BLITTER_SYNC_STATUS			(1 << 24)
 #define   GEN6_BLITTER_USER_INTERRUPT			(1 << 22)
-/*
- * BSD (bit stream decoder instruction and interrupt control register defines
- * (G4X and Ironlake only)
- */
 
-#define BSD_RING_TAIL          0x04030
-#define BSD_RING_HEAD          0x04034
-#define BSD_RING_START         0x04038
-#define BSD_RING_CTL           0x0403c
-#define BSD_RING_ACTHD         0x04074
-#define BSD_HWS_PGA            0x04080
+#define GEN6_BSD_SLEEP_PSMI_CONTROL	0x12050
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK	(1 << 16)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE		(1 << 0)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE		0
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR			(1 << 3)
+
+#define GEN6_BSD_IMR			0x120a8
+#define   GEN6_BSD_IMR_USER_INTERRUPT	(1 << 12)
+
+#define GEN6_BSD_RNCID			0x12198
 
 /*
  * Framebuffer compression (915+ only)
@@ -579,12 +568,51 @@
 # define GPIO_DATA_VAL_IN		(1 << 12)
 # define GPIO_DATA_PULLUP_DISABLE	(1 << 13)
 
-#define GMBUS0			0x5100
-#define GMBUS1			0x5104
-#define GMBUS2			0x5108
-#define GMBUS3			0x510c
-#define GMBUS4			0x5110
-#define GMBUS5			0x5120
+#define GMBUS0			0x5100 /* clock/port select */
+#define   GMBUS_RATE_100KHZ	(0<<8)
+#define   GMBUS_RATE_50KHZ	(1<<8)
+#define   GMBUS_RATE_400KHZ	(2<<8) /* reserved on Pineview */
+#define   GMBUS_RATE_1MHZ	(3<<8) /* reserved on Pineview */
+#define   GMBUS_HOLD_EXT	(1<<7) /* 300ns hold time, rsvd on Pineview */
+#define   GMBUS_PORT_DISABLED	0
+#define   GMBUS_PORT_SSC	1
+#define   GMBUS_PORT_VGADDC	2
+#define   GMBUS_PORT_PANEL	3
+#define   GMBUS_PORT_DPC	4 /* HDMIC */
+#define   GMBUS_PORT_DPB	5 /* SDVO, HDMIB */
+				  /* 6 reserved */
+#define   GMBUS_PORT_DPD	7 /* HDMID */
+#define   GMBUS_NUM_PORTS       8
+#define GMBUS1			0x5104 /* command/status */
+#define   GMBUS_SW_CLR_INT	(1<<31)
+#define   GMBUS_SW_RDY		(1<<30)
+#define   GMBUS_ENT		(1<<29) /* enable timeout */
+#define   GMBUS_CYCLE_NONE	(0<<25)
+#define   GMBUS_CYCLE_WAIT	(1<<25)
+#define   GMBUS_CYCLE_INDEX	(2<<25)
+#define   GMBUS_CYCLE_STOP	(4<<25)
+#define   GMBUS_BYTE_COUNT_SHIFT 16
+#define   GMBUS_SLAVE_INDEX_SHIFT 8
+#define   GMBUS_SLAVE_ADDR_SHIFT 1
+#define   GMBUS_SLAVE_READ	(1<<0)
+#define   GMBUS_SLAVE_WRITE	(0<<0)
+#define GMBUS2			0x5108 /* status */
+#define   GMBUS_INUSE		(1<<15)
+#define   GMBUS_HW_WAIT_PHASE	(1<<14)
+#define   GMBUS_STALL_TIMEOUT	(1<<13)
+#define   GMBUS_INT		(1<<12)
+#define   GMBUS_HW_RDY		(1<<11)
+#define   GMBUS_SATOER		(1<<10)
+#define   GMBUS_ACTIVE		(1<<9)
+#define GMBUS3			0x510c /* data buffer bytes 3-0 */
+#define GMBUS4			0x5110 /* interrupt mask (Pineview+) */
+#define   GMBUS_SLAVE_TIMEOUT_EN (1<<4)
+#define   GMBUS_NAK_EN		(1<<3)
+#define   GMBUS_IDLE_EN		(1<<2)
+#define   GMBUS_HW_WAIT_EN	(1<<1)
+#define   GMBUS_HW_RDY_EN	(1<<0)
+#define GMBUS5			0x5120 /* byte index */
+#define   GMBUS_2BYTE_INDEX_EN	(1<<31)
 
 /*
  * Clock control & power management
@@ -603,6 +631,7 @@
 #define   VGA1_PD_P1_MASK	(0x1f << 8)
 #define DPLL_A	0x06014
 #define DPLL_B	0x06018
+#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
 #define   DPLL_VCO_ENABLE		(1 << 31)
 #define   DPLL_DVO_HIGH_SPEED		(1 << 30)
 #define   DPLL_SYNCLOCK_ENABLE		(1 << 29)
@@ -633,31 +662,6 @@
 #define LVDS			0x61180
 #define LVDS_ON			(1<<31)
 
-#define ADPA			0x61100
-#define ADPA_DPMS_MASK		(~(3<<10))
-#define ADPA_DPMS_ON		(0<<10)
-#define ADPA_DPMS_SUSPEND	(1<<10)
-#define ADPA_DPMS_STANDBY	(2<<10)
-#define ADPA_DPMS_OFF		(3<<10)
-
-#define RING_TAIL		0x00
-#define TAIL_ADDR		0x001FFFF8
-#define RING_HEAD		0x04
-#define HEAD_WRAP_COUNT		0xFFE00000
-#define HEAD_WRAP_ONE		0x00200000
-#define HEAD_ADDR		0x001FFFFC
-#define RING_START		0x08
-#define START_ADDR		0xFFFFF000
-#define RING_LEN		0x0C
-#define RING_NR_PAGES		0x001FF000
-#define RING_REPORT_MASK	0x00000006
-#define RING_REPORT_64K		0x00000002
-#define RING_REPORT_128K	0x00000004
-#define RING_NO_REPORT		0x00000000
-#define RING_VALID_MASK		0x00000001
-#define RING_VALID		0x00000001
-#define RING_INVALID		0x00000000
-
 /* Scratch pad debug 0 reg:
  */
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830	0x001f0000
@@ -736,10 +740,13 @@
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK	0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT	0
 #define DPLL_B_MD 0x06020 /* 965+ only */
+#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
 #define FPA0	0x06040
 #define FPA1	0x06044
 #define FPB0	0x06048
 #define FPB1	0x0604c
+#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
+#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
 #define   FP_N_DIV_MASK		0x003f0000
 #define   FP_N_PINEVIEW_DIV_MASK	0x00ff0000
 #define   FP_N_DIV_SHIFT		16
@@ -760,6 +767,7 @@
 #define   DPLLA_TEST_M_BYPASS		(1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE	(1 << 0)
 #define D_STATE		0x6104
+#define  DSTATE_GFX_RESET_I830			(1<<6)
 #define  DSTATE_PLL_D3_OFF			(1<<3)
 #define  DSTATE_GFX_CLOCK_GATING		(1<<1)
 #define  DSTATE_DOT_CLOCK_GATING		(1<<0)
@@ -926,6 +934,8 @@
 #define CLKCFG_MEM_800					(3 << 4)
 #define CLKCFG_MEM_MASK					(7 << 4)
 
+#define TSC1			0x11001
+#define   TSE			(1<<0)
 #define TR1			0x11006
 #define TSFS			0x11020
 #define   TSFS_SLOPE_MASK	0x0000ff00
@@ -1070,6 +1080,8 @@
 #define   MEMSTAT_SRC_CTL_STDBY 3
 #define RCPREVBSYTUPAVG		0x113b8
 #define RCPREVBSYTDNAVG		0x113bc
+#define PMMISC			0x11214
+#define   MCPPCE_EN		(1<<0) /* enable PM_MSG from PCH->MPC */
 #define SDEW			0x1124c
 #define CSIEW0			0x11250
 #define CSIEW1			0x11254
@@ -1150,6 +1162,15 @@
 #define PIPEBSRC	0x6101c
 #define BCLRPAT_B	0x61020
 
+#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
+#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
+#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
+#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
+#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
+#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
+#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
+
 /* VGA port control */
 #define ADPA			0x61100
 #define   ADPA_DAC_ENABLE	(1<<31)
@@ -1173,6 +1194,7 @@
 #define   ADPA_DPMS_STANDBY	(2<<10)
 #define   ADPA_DPMS_OFF		(3<<10)
 
+
 /* Hotplug control (945+ only) */
 #define PORT_HOTPLUG_EN		0x61110
 #define   HDMIB_HOTPLUG_INT_EN			(1 << 29)
@@ -1331,6 +1353,22 @@
 #define   LVDS_B0B3_POWER_DOWN		(0 << 2)
 #define   LVDS_B0B3_POWER_UP		(3 << 2)
 
+/* Video Data Island Packet control */
+#define VIDEO_DIP_DATA		0x61178
+#define VIDEO_DIP_CTL		0x61170
+#define   VIDEO_DIP_ENABLE		(1 << 31)
+#define   VIDEO_DIP_PORT_B		(1 << 29)
+#define   VIDEO_DIP_PORT_C		(2 << 29)
+#define   VIDEO_DIP_ENABLE_AVI		(1 << 21)
+#define   VIDEO_DIP_ENABLE_VENDOR	(2 << 21)
+#define   VIDEO_DIP_ENABLE_SPD		(8 << 21)
+#define   VIDEO_DIP_SELECT_AVI		(0 << 19)
+#define   VIDEO_DIP_SELECT_VENDOR	(1 << 19)
+#define   VIDEO_DIP_SELECT_SPD		(3 << 19)
+#define   VIDEO_DIP_FREQ_ONCE		(0 << 16)
+#define   VIDEO_DIP_FREQ_VSYNC		(1 << 16)
+#define   VIDEO_DIP_FREQ_2VSYNC		(2 << 16)
+
 /* Panel power sequencing */
 #define PP_STATUS	0x61200
 #define   PP_ON		(1 << 31)
@@ -1346,6 +1384,9 @@
 #define   PP_SEQUENCE_ON	(1 << 28)
 #define   PP_SEQUENCE_OFF	(2 << 28)
 #define   PP_SEQUENCE_MASK	0x30000000
+#define   PP_CYCLE_DELAY_ACTIVE	(1 << 27)
+#define   PP_SEQUENCE_STATE_ON_IDLE (1 << 3)
+#define   PP_SEQUENCE_STATE_MASK 0x0000000f
 #define PP_CONTROL	0x61204
 #define   POWER_TARGET_ON	(1 << 0)
 #define PP_ON_DELAYS	0x61208
@@ -1481,6 +1522,7 @@
 # define TV_TEST_MODE_MASK		(7 << 0)
 
 #define TV_DAC			0x68004
+# define TV_DAC_SAVE		0x00ffff00
 /**
  * Reports that DAC state change logic has reported change (RO).
  *
@@ -2075,29 +2117,35 @@
 
 /* Display & cursor control */
 
-/* dithering flag on Ironlake */
-#define PIPE_ENABLE_DITHER		(1 << 4)
-#define PIPE_DITHER_TYPE_MASK		(3 << 2)
-#define PIPE_DITHER_TYPE_SPATIAL	(0 << 2)
-#define PIPE_DITHER_TYPE_ST01		(1 << 2)
 /* Pipe A */
 #define PIPEADSL		0x70000
-#define   DSL_LINEMASK	       	0x00000fff
+#define   DSL_LINEMASK		0x00000fff
 #define PIPEACONF		0x70008
-#define   PIPEACONF_ENABLE	(1<<31)
-#define   PIPEACONF_DISABLE	0
-#define   PIPEACONF_DOUBLE_WIDE	(1<<30)
+#define   PIPECONF_ENABLE	(1<<31)
+#define   PIPECONF_DISABLE	0
+#define   PIPECONF_DOUBLE_WIDE	(1<<30)
 #define   I965_PIPECONF_ACTIVE	(1<<30)
-#define   PIPEACONF_SINGLE_WIDE	0
-#define   PIPEACONF_PIPE_UNLOCKED 0
-#define   PIPEACONF_PIPE_LOCKED	(1<<25)
-#define   PIPEACONF_PALETTE	0
-#define   PIPEACONF_GAMMA		(1<<24)
+#define   PIPECONF_SINGLE_WIDE	0
+#define   PIPECONF_PIPE_UNLOCKED 0
+#define   PIPECONF_PIPE_LOCKED	(1<<25)
+#define   PIPECONF_PALETTE	0
+#define   PIPECONF_GAMMA		(1<<24)
 #define   PIPECONF_FORCE_BORDER	(1<<25)
 #define   PIPECONF_PROGRESSIVE	(0 << 21)
 #define   PIPECONF_INTERLACE_W_FIELD_INDICATION	(6 << 21)
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY		(7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK	(1<<16)
+#define   PIPECONF_BPP_MASK	(0x000000e0)
+#define   PIPECONF_BPP_8	(0<<5)
+#define   PIPECONF_BPP_10	(1<<5)
+#define   PIPECONF_BPP_6	(2<<5)
+#define   PIPECONF_BPP_12	(3<<5)
+#define   PIPECONF_DITHER_EN	(1<<4)
+#define   PIPECONF_DITHER_TYPE_MASK (0x0000000c)
+#define   PIPECONF_DITHER_TYPE_SP (0<<2)
+#define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
+#define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
+#define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 #define PIPEASTAT		0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS		(1UL<<31)
 #define   PIPE_CRC_ERROR_ENABLE			(1UL<<29)
@@ -2128,12 +2176,15 @@
 #define   PIPE_START_VBLANK_INTERRUPT_STATUS	(1UL<<2) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_STATUS		(1UL<<1)
 #define   PIPE_OVERLAY_UPDATED_STATUS		(1UL<<0)
-#define   PIPE_BPC_MASK 			(7 << 5) /* Ironlake */
+#define   PIPE_BPC_MASK				(7 << 5) /* Ironlake */
 #define   PIPE_8BPC				(0 << 5)
 #define   PIPE_10BPC				(1 << 5)
 #define   PIPE_6BPC				(2 << 5)
 #define   PIPE_12BPC				(3 << 5)
 
+#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
+#define PIPEDSL(pipe)  _PIPE(pipe, PIPEADSL, PIPEBDSL)
+
 #define DSPARB			0x70030
 #define   DSPARB_CSTART_MASK	(0x7f << 7)
 #define   DSPARB_CSTART_SHIFT	7
@@ -2206,8 +2257,8 @@
 #define  WM1_LP_SR_EN		(1<<31)
 #define  WM1_LP_LATENCY_SHIFT	24
 #define  WM1_LP_LATENCY_MASK	(0x7f<<24)
-#define  WM1_LP_FBC_LP1_MASK	(0xf<<20)
-#define  WM1_LP_FBC_LP1_SHIFT	20
+#define  WM1_LP_FBC_MASK	(0xf<<20)
+#define  WM1_LP_FBC_SHIFT	20
 #define  WM1_LP_SR_MASK		(0x1ff<<8)
 #define  WM1_LP_SR_SHIFT	8
 #define  WM1_LP_CURSOR_MASK	(0x3f)
@@ -2333,6 +2384,14 @@
 #define DSPASURF		0x7019C /* 965+ only */
 #define DSPATILEOFF		0x701A4 /* 965+ only */
 
+#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
+#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
+#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
+#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
+#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
+#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
+#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
+
 /* VBIOS flags */
 #define SWF00			0x71410
 #define SWF01			0x71414
@@ -2397,6 +2456,7 @@
 #define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
 
 #define FDI_PLL_BIOS_0  0x46000
+#define  FDI_PLL_FB_CLOCK_MASK  0xff
 #define FDI_PLL_BIOS_1  0x46004
 #define FDI_PLL_BIOS_2  0x46008
 #define DISPLAY_PORT_PLL_BIOS_0         0x4600c
@@ -2411,6 +2471,9 @@
 # define MARIUNIT_CLOCK_GATE_DISABLE		(1 << 18)
 # define SVSMUNIT_CLOCK_GATE_DISABLE		(1 << 1)
 
+#define PCH_3DCGDIS1		0x46024
+# define VFMUNIT_CLOCK_GATE_DISABLE		(1 << 11)
+
 #define FDI_PLL_FREQ_CTL        0x46030
 #define  FDI_PLL_FREQ_CHANGE_REQUEST    (1<<24)
 #define  FDI_PLL_FREQ_LOCK_LIMIT_MASK   0xfff00
@@ -2420,46 +2483,47 @@
 #define PIPEA_DATA_M1           0x60030
 #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
 #define  TU_SIZE_MASK           0x7e000000
-#define  PIPEA_DATA_M1_OFFSET   0
+#define  PIPE_DATA_M1_OFFSET    0
 #define PIPEA_DATA_N1           0x60034
-#define  PIPEA_DATA_N1_OFFSET   0
+#define  PIPE_DATA_N1_OFFSET    0
 
 #define PIPEA_DATA_M2           0x60038
-#define  PIPEA_DATA_M2_OFFSET   0
+#define  PIPE_DATA_M2_OFFSET    0
 #define PIPEA_DATA_N2           0x6003c
-#define  PIPEA_DATA_N2_OFFSET   0
+#define  PIPE_DATA_N2_OFFSET    0
 
 #define PIPEA_LINK_M1           0x60040
-#define  PIPEA_LINK_M1_OFFSET   0
+#define  PIPE_LINK_M1_OFFSET    0
 #define PIPEA_LINK_N1           0x60044
-#define  PIPEA_LINK_N1_OFFSET   0
+#define  PIPE_LINK_N1_OFFSET    0
 
 #define PIPEA_LINK_M2           0x60048
-#define  PIPEA_LINK_M2_OFFSET   0
+#define  PIPE_LINK_M2_OFFSET    0
 #define PIPEA_LINK_N2           0x6004c
-#define  PIPEA_LINK_N2_OFFSET   0
+#define  PIPE_LINK_N2_OFFSET    0
 
 /* PIPEB timing regs are same start from 0x61000 */
 
 #define PIPEB_DATA_M1           0x61030
-#define  PIPEB_DATA_M1_OFFSET   0
 #define PIPEB_DATA_N1           0x61034
-#define  PIPEB_DATA_N1_OFFSET   0
 
 #define PIPEB_DATA_M2           0x61038
-#define  PIPEB_DATA_M2_OFFSET   0
 #define PIPEB_DATA_N2           0x6103c
-#define  PIPEB_DATA_N2_OFFSET   0
 
 #define PIPEB_LINK_M1           0x61040
-#define  PIPEB_LINK_M1_OFFSET   0
 #define PIPEB_LINK_N1           0x61044
-#define  PIPEB_LINK_N1_OFFSET   0
 
 #define PIPEB_LINK_M2           0x61048
-#define  PIPEB_LINK_M2_OFFSET   0
 #define PIPEB_LINK_N2           0x6104c
-#define  PIPEB_LINK_N2_OFFSET   0
+
+#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
+#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
+#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
+#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
+#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
+#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
+#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
+#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
 
 /* CPU panel fitter */
 #define PFA_CTL_1               0x68080
@@ -2516,7 +2580,8 @@
 #define GT_SYNC_STATUS          (1 << 2)
 #define GT_USER_INTERRUPT       (1 << 0)
 #define GT_BSD_USER_INTERRUPT   (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT	(1 << 12)
+#define GT_BLT_USER_INTERRUPT	(1 << 22)
 
 #define GTISR   0x44010
 #define GTIMR   0x44014
@@ -2526,6 +2591,13 @@
 #define ILK_DISPLAY_CHICKEN2	0x42004
 #define  ILK_DPARB_GATE	(1<<22)
 #define  ILK_VSDPFD_FULL	(1<<21)
+#define ILK_DISPLAY_CHICKEN_FUSES	0x42014
+#define  ILK_INTERNAL_GRAPHICS_DISABLE	(1<<31)
+#define  ILK_INTERNAL_DISPLAY_DISABLE	(1<<30)
+#define  ILK_DISPLAY_DEBUG_DISABLE	(1<<29)
+#define  ILK_HDCP_DISABLE		(1<<25)
+#define  ILK_eDP_A_DISABLE		(1<<24)
+#define  ILK_DESKTOP			(1<<23)
 #define ILK_DSPCLK_GATE		0x42020
 #define  ILK_DPARB_CLK_GATE	(1<<5)
 /* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */
@@ -2551,6 +2623,10 @@
 #define SDE_PORTD_HOTPLUG_CPT	(1 << 23)
 #define SDE_PORTC_HOTPLUG_CPT	(1 << 22)
 #define SDE_PORTB_HOTPLUG_CPT	(1 << 21)
+#define SDE_HOTPLUG_MASK_CPT	(SDE_CRT_HOTPLUG_CPT |		\
+				 SDE_PORTD_HOTPLUG_CPT |	\
+				 SDE_PORTC_HOTPLUG_CPT |	\
+				 SDE_PORTB_HOTPLUG_CPT)
 
 #define SDEISR  0xc4000
 #define SDEIMR  0xc4004
@@ -2600,11 +2676,14 @@
 
 #define PCH_DPLL_A              0xc6014
 #define PCH_DPLL_B              0xc6018
+#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
 
 #define PCH_FPA0                0xc6040
 #define PCH_FPA1                0xc6044
 #define PCH_FPB0                0xc6048
 #define PCH_FPB1                0xc604c
+#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
+#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
 
 #define PCH_DPLL_TEST           0xc606c
 
@@ -2690,6 +2769,13 @@
 #define TRANS_VBLANK_B          0xe1010
 #define TRANS_VSYNC_B           0xe1014
 
+#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
+#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
+#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
+#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
+#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
+#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
+
 #define TRANSB_DATA_M1          0xe1030
 #define TRANSB_DATA_N1          0xe1034
 #define TRANSB_DATA_M2          0xe1038
@@ -2701,6 +2787,7 @@
 
 #define TRANSACONF              0xf0008
 #define TRANSBCONF              0xf1008
+#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
@@ -2721,10 +2808,15 @@
 #define FDI_RXA_CHICKEN         0xc200c
 #define FDI_RXB_CHICKEN         0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_ENABLE       (1)
+#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, FDI_RXA_CHICKEN, FDI_RXB_CHICKEN)
+
+#define SOUTH_DSPCLK_GATE_D	0xc2020
+#define  PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29)
 
 /* CPU: FDI_TX */
 #define FDI_TXA_CTL             0x60100
 #define FDI_TXB_CTL             0x61100
+#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
 #define  FDI_TX_DISABLE         (0<<31)
 #define  FDI_TX_ENABLE          (1<<31)
 #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
@@ -2766,8 +2858,8 @@
 /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 #define FDI_RXA_CTL             0xf000c
 #define FDI_RXB_CTL             0xf100c
+#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
-#define  FDI_RX_DISABLE         (0<<31)
 /* train, dp width same as FDI_TX */
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
@@ -2782,8 +2874,7 @@
 #define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
 #define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
-#define  FDI_SEL_RAWCLK                 (0<<4)
-#define  FDI_SEL_PCDCLK                 (1<<4)
+#define  FDI_PCDCLK	                (1<<4)
 /* CPT */
 #define  FDI_AUTO_TRAINING			(1<<10)
 #define  FDI_LINK_TRAIN_PATTERN_1_CPT		(0<<8)
@@ -2798,6 +2889,9 @@
 #define FDI_RXA_TUSIZE2         0xf0038
 #define FDI_RXB_TUSIZE1         0xf1030
 #define FDI_RXB_TUSIZE2         0xf1038
+#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
+#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
 
 /* FDI_RX interrupt register format */
 #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
@@ -2816,6 +2910,8 @@
 #define FDI_RXA_IMR             0xf0018
 #define FDI_RXB_IIR             0xf1014
 #define FDI_RXB_IMR             0xf1018
+#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
 
 #define FDI_PLL_CTL_1           0xfe000
 #define FDI_PLL_CTL_2           0xfe004
@@ -2935,6 +3031,7 @@
 #define TRANS_DP_CTL_A		0xe0300
 #define TRANS_DP_CTL_B		0xe1300
 #define TRANS_DP_CTL_C		0xe2300
+#define TRANS_DP_CTL(pipe)	(TRANS_DP_CTL_A + (pipe) * 0x01000)
 #define  TRANS_DP_OUTPUT_ENABLE	(1<<31)
 #define  TRANS_DP_PORT_SEL_B	(0<<29)
 #define  TRANS_DP_PORT_SEL_C	(1<<29)
@@ -2946,6 +3043,7 @@
 #define  TRANS_DP_10BPC		(1<<9)
 #define  TRANS_DP_6BPC		(2<<9)
 #define  TRANS_DP_12BPC		(3<<9)
+#define  TRANS_DP_BPC_MASK	(3<<9)
 #define  TRANS_DP_VSYNC_ACTIVE_HIGH	(1<<4)
 #define  TRANS_DP_VSYNC_ACTIVE_LOW	0
 #define  TRANS_DP_HSYNC_ACTIVE_HIGH	(1<<3)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_suspend.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_suspend.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/i915_suspend.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/i915_suspend.c	2011-01-04 19:50:19.000000000 -0500
@@ -239,6 +239,16 @@
 	if (drm_core_check_feature(dev, DRIVER_MODESET))
 		return;
 
+	/* Cursor state */
+	dev_priv->saveCURACNTR = I915_READ(CURACNTR);
+	dev_priv->saveCURAPOS = I915_READ(CURAPOS);
+	dev_priv->saveCURABASE = I915_READ(CURABASE);
+	dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
+	dev_priv->saveCURBPOS = I915_READ(CURBPOS);
+	dev_priv->saveCURBBASE = I915_READ(CURBBASE);
+	if (IS_GEN2(dev))
+		dev_priv->saveCURSIZE = I915_READ(CURSIZE);
+
 	if (HAS_PCH_SPLIT(dev)) {
 		dev_priv->savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL);
 		dev_priv->saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL);
@@ -256,7 +266,7 @@
 		dev_priv->saveFPA1 = I915_READ(FPA1);
 		dev_priv->saveDPLL_A = I915_READ(DPLL_A);
 	}
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
 	dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
 	dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
@@ -294,7 +304,7 @@
 	dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
 	dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
 	dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		dev_priv->saveDSPASURF = I915_READ(DSPASURF);
 		dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
 	}
@@ -313,7 +323,7 @@
 		dev_priv->saveFPB1 = I915_READ(FPB1);
 		dev_priv->saveDPLL_B = I915_READ(DPLL_B);
 	}
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
 	dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
 	dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
@@ -351,7 +361,7 @@
 	dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
 	dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
 	dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
-	if (IS_I965GM(dev) || IS_GM45(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
 		dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
 	}
@@ -404,7 +414,7 @@
 	I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
 	POSTING_READ(dpll_a_reg);
 	udelay(150);
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
 		POSTING_READ(DPLL_A_MD);
 	}
@@ -448,7 +458,7 @@
 	I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
 	I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
 	I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
 		I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
 	}
@@ -473,7 +483,7 @@
 	I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
 	POSTING_READ(dpll_b_reg);
 	udelay(150);
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
 		POSTING_READ(DPLL_B_MD);
 	}
@@ -517,7 +527,7 @@
 	I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
 	I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
 	I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
 		I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
 	}
@@ -529,6 +539,16 @@
 	I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
 	I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
 
+	/* Cursor state */
+	I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
+	I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
+	I915_WRITE(CURABASE, dev_priv->saveCURABASE);
+	I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
+	I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
+	I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
+	if (IS_GEN2(dev))
+		I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
+
 	return;
 }
 
@@ -543,16 +563,6 @@
 	/* Don't save them in KMS mode */
 	i915_save_modeset_reg(dev);
 
-	/* Cursor state */
-	dev_priv->saveCURACNTR = I915_READ(CURACNTR);
-	dev_priv->saveCURAPOS = I915_READ(CURAPOS);
-	dev_priv->saveCURABASE = I915_READ(CURABASE);
-	dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
-	dev_priv->saveCURBPOS = I915_READ(CURBPOS);
-	dev_priv->saveCURBBASE = I915_READ(CURBBASE);
-	if (!IS_I9XX(dev))
-		dev_priv->saveCURSIZE = I915_READ(CURSIZE);
-
 	/* CRT state */
 	if (HAS_PCH_SPLIT(dev)) {
 		dev_priv->saveADPA = I915_READ(PCH_ADPA);
@@ -573,7 +583,7 @@
 		dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
 		dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
 		dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
 		if (IS_MOBILE(dev) && !IS_I830(dev))
 			dev_priv->saveLVDS = I915_READ(LVDS);
@@ -657,16 +667,6 @@
 	/* Don't restore them in KMS mode */
 	i915_restore_modeset_reg(dev);
 
-	/* Cursor state */
-	I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
-	I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
-	I915_WRITE(CURABASE, dev_priv->saveCURABASE);
-	I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
-	I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
-	I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
-	if (!IS_I9XX(dev))
-		I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
-
 	/* CRT state */
 	if (HAS_PCH_SPLIT(dev))
 		I915_WRITE(PCH_ADPA, dev_priv->saveADPA);
@@ -674,7 +674,7 @@
 		I915_WRITE(ADPA, dev_priv->saveADPA);
 
 	/* LVDS state */
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
 
 	if (HAS_PCH_SPLIT(dev)) {
@@ -862,8 +862,10 @@
 	/* Clock gating state */
 	intel_init_clock_gating(dev);
 
-	if (HAS_PCH_SPLIT(dev))
+	if (HAS_PCH_SPLIT(dev)) {
 		ironlake_enable_drps(dev);
+		intel_init_emon(dev);
+	}
 
 	/* Cache mode state */
 	I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
@@ -878,9 +880,7 @@
 	for (i = 0; i < 3; i++)
 		I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
 
-	/* I2C state */
-	intel_i2c_reset_gmbus(dev);
+	intel_i2c_reset(dev);
 
 	return 0;
 }
-
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_acpi.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_acpi.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_acpi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_acpi.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,252 @@
+/*
+ * Intel ACPI functions
+ *
+ * _DSM related code stolen from nouveau_acpi.c.
+ */
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <linux/vga_switcheroo.h>
+#include <acpi/acpi_drivers.h>
+
+#include "drmP.h"
+
+#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
+
+#define INTEL_DSM_FN_SUPPORTED_FUNCTIONS 0 /* No args */
+#define INTEL_DSM_FN_PLATFORM_MUX_INFO 1 /* No args */
+
+static struct intel_dsm_priv {
+	acpi_handle dhandle;
+} intel_dsm_priv;
+
+static const u8 intel_dsm_guid[] = {
+	0xd3, 0x73, 0xd8, 0x7e,
+	0xd0, 0xc2,
+	0x4f, 0x4e,
+	0xa8, 0x54,
+	0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
+};
+
+static int intel_dsm(acpi_handle handle, int func, int arg)
+{
+	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_object_list input;
+	union acpi_object params[4];
+	union acpi_object *obj;
+	u32 result;
+	int ret = 0;
+
+	input.count = 4;
+	input.pointer = params;
+	params[0].type = ACPI_TYPE_BUFFER;
+	params[0].buffer.length = sizeof(intel_dsm_guid);
+	params[0].buffer.pointer = (char *)intel_dsm_guid;
+	params[1].type = ACPI_TYPE_INTEGER;
+	params[1].integer.value = INTEL_DSM_REVISION_ID;
+	params[2].type = ACPI_TYPE_INTEGER;
+	params[2].integer.value = func;
+	params[3].type = ACPI_TYPE_INTEGER;
+	params[3].integer.value = arg;
+
+	ret = acpi_evaluate_object(handle, "_DSM", &input, &output);
+	if (ret) {
+		DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+		return ret;
+	}
+
+	obj = (union acpi_object *)output.pointer;
+
+	result = 0;
+	switch (obj->type) {
+	case ACPI_TYPE_INTEGER:
+		result = obj->integer.value;
+		break;
+
+	case ACPI_TYPE_BUFFER:
+		if (obj->buffer.length == 4) {
+			result =(obj->buffer.pointer[0] |
+				(obj->buffer.pointer[1] <<  8) |
+				(obj->buffer.pointer[2] << 16) |
+				(obj->buffer.pointer[3] << 24));
+			break;
+		}
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (result == 0x80000002)
+		ret = -ENODEV;
+
+	kfree(output.pointer);
+	return ret;
+}
+
+static char *intel_dsm_port_name(u8 id)
+{
+	switch (id) {
+	case 0:
+		return "Reserved";
+	case 1:
+		return "Analog VGA";
+	case 2:
+		return "LVDS";
+	case 3:
+		return "Reserved";
+	case 4:
+		return "HDMI/DVI_B";
+	case 5:
+		return "HDMI/DVI_C";
+	case 6:
+		return "HDMI/DVI_D";
+	case 7:
+		return "DisplayPort_A";
+	case 8:
+		return "DisplayPort_B";
+	case 9:
+		return "DisplayPort_C";
+	case 0xa:
+		return "DisplayPort_D";
+	case 0xb:
+	case 0xc:
+	case 0xd:
+		return "Reserved";
+	case 0xe:
+		return "WiDi";
+	default:
+		return "bad type";
+	}
+}
+
+static char *intel_dsm_mux_type(u8 type)
+{
+	switch (type) {
+	case 0:
+		return "unknown";
+	case 1:
+		return "No MUX, iGPU only";
+	case 2:
+		return "No MUX, dGPU only";
+	case 3:
+		return "MUXed between iGPU and dGPU";
+	default:
+		return "bad type";
+	}
+}
+
+static void intel_dsm_platform_mux_info(void)
+{
+	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_object_list input;
+	union acpi_object params[4];
+	union acpi_object *pkg;
+	int i, ret;
+
+	input.count = 4;
+	input.pointer = params;
+	params[0].type = ACPI_TYPE_BUFFER;
+	params[0].buffer.length = sizeof(intel_dsm_guid);
+	params[0].buffer.pointer = (char *)intel_dsm_guid;
+	params[1].type = ACPI_TYPE_INTEGER;
+	params[1].integer.value = INTEL_DSM_REVISION_ID;
+	params[2].type = ACPI_TYPE_INTEGER;
+	params[2].integer.value = INTEL_DSM_FN_PLATFORM_MUX_INFO;
+	params[3].type = ACPI_TYPE_INTEGER;
+	params[3].integer.value = 0;
+
+	ret = acpi_evaluate_object(intel_dsm_priv.dhandle, "_DSM", &input,
+				   &output);
+	if (ret) {
+		DRM_DEBUG_DRIVER("failed to evaluate _DSM: %d\n", ret);
+		goto out;
+	}
+
+	pkg = (union acpi_object *)output.pointer;
+
+	if (pkg->type == ACPI_TYPE_PACKAGE) {
+		union acpi_object *connector_count = &pkg->package.elements[0];
+		DRM_DEBUG_DRIVER("MUX info connectors: %lld\n",
+			  (unsigned long long)connector_count->integer.value);
+		for (i = 1; i < pkg->package.count; i++) {
+			union acpi_object *obj = &pkg->package.elements[i];
+			union acpi_object *connector_id =
+				&obj->package.elements[0];
+			union acpi_object *info = &obj->package.elements[1];
+			DRM_DEBUG_DRIVER("Connector id: 0x%016llx\n",
+				  (unsigned long long)connector_id->integer.value);
+			DRM_DEBUG_DRIVER("  port id: %s\n",
+			       intel_dsm_port_name(info->buffer.pointer[0]));
+			DRM_DEBUG_DRIVER("  display mux info: %s\n",
+			       intel_dsm_mux_type(info->buffer.pointer[1]));
+			DRM_DEBUG_DRIVER("  aux/dc mux info: %s\n",
+			       intel_dsm_mux_type(info->buffer.pointer[2]));
+			DRM_DEBUG_DRIVER("  hpd mux info: %s\n",
+			       intel_dsm_mux_type(info->buffer.pointer[3]));
+		}
+	} else {
+		DRM_ERROR("MUX INFO call failed\n");
+	}
+
+out:
+	kfree(output.pointer);
+}
+
+static bool intel_dsm_pci_probe(struct pci_dev *pdev)
+{
+	acpi_handle dhandle, intel_handle;
+	acpi_status status;
+	int ret;
+
+	dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+	if (!dhandle)
+		return false;
+
+	status = acpi_get_handle(dhandle, "_DSM", &intel_handle);
+	if (ACPI_FAILURE(status)) {
+		DRM_DEBUG_KMS("no _DSM method for intel device\n");
+		return false;
+	}
+
+	ret = intel_dsm(dhandle, INTEL_DSM_FN_SUPPORTED_FUNCTIONS, 0);
+	if (ret < 0) {
+		DRM_ERROR("failed to get supported _DSM functions\n");
+		return false;
+	}
+
+	intel_dsm_priv.dhandle = dhandle;
+
+	intel_dsm_platform_mux_info();
+	return true;
+}
+
+static bool intel_dsm_detect(void)
+{
+	char acpi_method_name[255] = { 0 };
+	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
+	struct pci_dev *pdev = NULL;
+	bool has_dsm = false;
+	int vga_count = 0;
+
+	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
+		vga_count++;
+		has_dsm |= intel_dsm_pci_probe(pdev);
+	}
+
+	if (vga_count == 2 && has_dsm) {
+		acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+		DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+				 acpi_method_name);
+		return true;
+	}
+
+	return false;
+}
+
+void intel_register_dsm_handler(void)
+{
+	if (!intel_dsm_detect())
+		return;
+}
+
+void intel_unregister_dsm_handler(void)
+{
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_bios.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_bios.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_bios.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_bios.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,6 +24,7 @@
  *    Eric Anholt <eric@anholt.net>
  *
  */
+#include <drm/drm_dp_helper.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
@@ -129,10 +130,6 @@
 	int i, temp_downclock;
 	struct drm_display_mode *temp_mode;
 
-	/* Defaults if we can't find VBT info */
-	dev_priv->lvds_dither = 0;
-	dev_priv->lvds_vbt = 0;
-
 	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
 	if (!lvds_options)
 		return;
@@ -140,6 +137,7 @@
 	dev_priv->lvds_dither = lvds_options->pixel_dither;
 	if (lvds_options->panel_type == 0xff)
 		return;
+
 	panel_type = lvds_options->panel_type;
 
 	lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
@@ -169,6 +167,8 @@
 			((unsigned char *)entry + dvo_timing_offset);
 
 	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+	if (!panel_fixed_mode)
+		return;
 
 	fill_detail_timing_data(panel_fixed_mode, dvo_timing);
 
@@ -230,8 +230,6 @@
 	struct lvds_dvo_timing *dvo_timing;
 	struct drm_display_mode *panel_fixed_mode;
 
-	dev_priv->sdvo_lvds_vbt_mode = NULL;
-
 	sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
 	if (!sdvo_lvds_options)
 		return;
@@ -260,10 +258,6 @@
 	struct drm_device *dev = dev_priv->dev;
 	struct bdb_general_features *general;
 
-	/* Set sensible defaults in case we can't find the general block */
-	dev_priv->int_tv_support = 1;
-	dev_priv->int_crt_support = 1;
-
 	general = find_section(bdb, BDB_GENERAL_FEATURES);
 	if (general) {
 		dev_priv->int_tv_support = general->int_tv_support;
@@ -271,10 +265,10 @@
 		dev_priv->lvds_use_ssc = general->enable_ssc;
 
 		if (dev_priv->lvds_use_ssc) {
-			if (IS_I85X(dev_priv->dev))
+			if (IS_I85X(dev))
 				dev_priv->lvds_ssc_freq =
 					general->ssc_freq ? 66 : 48;
-			else if (IS_IRONLAKE(dev_priv->dev) || IS_GEN6(dev))
+			else if (IS_GEN5(dev) || IS_GEN6(dev))
 				dev_priv->lvds_ssc_freq =
 					general->ssc_freq ? 100 : 120;
 			else
@@ -289,14 +283,6 @@
 			  struct bdb_header *bdb)
 {
 	struct bdb_general_definitions *general;
-	const int crt_bus_map_table[] = {
-		GPIOB,
-		GPIOA,
-		GPIOC,
-		GPIOD,
-		GPIOE,
-		GPIOF,
-	};
 
 	general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (general) {
@@ -304,10 +290,8 @@
 		if (block_size >= sizeof(*general)) {
 			int bus_pin = general->crt_ddc_gmbus_pin;
 			DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
-			if ((bus_pin >= 1) && (bus_pin <= 6)) {
-				dev_priv->crt_ddc_bus =
-					crt_bus_map_table[bus_pin-1];
-			}
+			if (bus_pin >= 1 && bus_pin <= 6)
+				dev_priv->crt_ddc_pin = bus_pin;
 		} else {
 			DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
 				  block_size);
@@ -317,7 +301,7 @@
 
 static void
 parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
-		       struct bdb_header *bdb)
+			  struct bdb_header *bdb)
 {
 	struct sdvo_device_mapping *p_mapping;
 	struct bdb_general_definitions *p_defs;
@@ -327,7 +311,7 @@
 
 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (!p_defs) {
-		DRM_DEBUG_KMS("No general definition block is found\n");
+		DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
 		return;
 	}
 	/* judge whether the size of child device meets the requirements.
@@ -377,7 +361,16 @@
 			p_mapping->slave_addr = p_child->slave_addr;
 			p_mapping->dvo_wiring = p_child->dvo_wiring;
 			p_mapping->ddc_pin = p_child->ddc_pin;
+			p_mapping->i2c_pin = p_child->i2c_pin;
+			p_mapping->i2c_speed = p_child->i2c_speed;
 			p_mapping->initialized = 1;
+			DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
+				      p_mapping->dvo_port,
+				      p_mapping->slave_addr,
+				      p_mapping->dvo_wiring,
+				      p_mapping->ddc_pin,
+				      p_mapping->i2c_pin,
+				      p_mapping->i2c_speed);
 		} else {
 			DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
 					 "two SDVO device.\n");
@@ -409,14 +402,11 @@
 	if (!driver)
 		return;
 
-	if (driver && SUPPORTS_EDP(dev) &&
-	    driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
-		dev_priv->edp_support = 1;
-	} else {
-		dev_priv->edp_support = 0;
-	}
+	if (SUPPORTS_EDP(dev) &&
+	    driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+		dev_priv->edp.support = 1;
 
-	if (driver && driver->dual_frequency)
+	if (driver->dual_frequency)
 		dev_priv->render_reclock_avail = true;
 }
 
@@ -424,27 +414,78 @@
 parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
 	struct bdb_edp *edp;
+	struct edp_power_seq *edp_pps;
+	struct edp_link_params *edp_link_params;
 
 	edp = find_section(bdb, BDB_EDP);
 	if (!edp) {
-		if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+		if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
 			DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
-				      "supported, assume 18bpp panel color "
-				      "depth.\n");
-			dev_priv->edp_bpp = 18;
+				      "supported, assume %dbpp panel color "
+				      "depth.\n",
+				      dev_priv->edp.bpp);
 		}
 		return;
 	}
 
 	switch ((edp->color_depth >> (panel_type * 2)) & 3) {
 	case EDP_18BPP:
-		dev_priv->edp_bpp = 18;
+		dev_priv->edp.bpp = 18;
 		break;
 	case EDP_24BPP:
-		dev_priv->edp_bpp = 24;
+		dev_priv->edp.bpp = 24;
 		break;
 	case EDP_30BPP:
-		dev_priv->edp_bpp = 30;
+		dev_priv->edp.bpp = 30;
+		break;
+	}
+
+	/* Get the eDP sequencing and link info */
+	edp_pps = &edp->power_seqs[panel_type];
+	edp_link_params = &edp->link_params[panel_type];
+
+	dev_priv->edp.pps = *edp_pps;
+
+	dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+		DP_LINK_BW_1_62;
+	switch (edp_link_params->lanes) {
+	case 0:
+		dev_priv->edp.lanes = 1;
+		break;
+	case 1:
+		dev_priv->edp.lanes = 2;
+		break;
+	case 3:
+	default:
+		dev_priv->edp.lanes = 4;
+		break;
+	}
+	switch (edp_link_params->preemphasis) {
+	case 0:
+		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+		break;
+	case 1:
+		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+		break;
+	case 2:
+		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+		break;
+	case 3:
+		dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+		break;
+	}
+	switch (edp_link_params->vswing) {
+	case 0:
+		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+		break;
+	case 1:
+		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+		break;
+	case 2:
+		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+		break;
+	case 3:
+		dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
 		break;
 	}
 }
@@ -460,7 +501,7 @@
 
 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (!p_defs) {
-		DRM_DEBUG_KMS("No general definition block is found\n");
+		DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
 		return;
 	}
 	/* judge whether the size of child device meets the requirements.
@@ -513,50 +554,83 @@
 	}
 	return;
 }
+
+static void
+init_vbt_defaults(struct drm_i915_private *dev_priv)
+{
+	dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+
+	/* LFP panel data */
+	dev_priv->lvds_dither = 1;
+	dev_priv->lvds_vbt = 0;
+
+	/* SDVO panel data */
+	dev_priv->sdvo_lvds_vbt_mode = NULL;
+
+	/* general features */
+	dev_priv->int_tv_support = 1;
+	dev_priv->int_crt_support = 1;
+	dev_priv->lvds_use_ssc = 0;
+
+	/* eDP data */
+	dev_priv->edp.bpp = 18;
+}
+
 /**
- * intel_init_bios - initialize VBIOS settings & find VBT
+ * intel_parse_bios - find VBT and initialize settings from the BIOS
  * @dev: DRM device
  *
  * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
  * to appropriate values.
  *
- * VBT existence is a sanity check that is relied on by other i830_bios.c code.
- * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
- * feed an updated VBT back through that, compared to what we'll fetch using
- * this method of groping around in the BIOS data.
- *
  * Returns 0 on success, nonzero on failure.
  */
 bool
-intel_init_bios(struct drm_device *dev)
+intel_parse_bios(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct pci_dev *pdev = dev->pdev;
-	struct vbt_header *vbt = NULL;
-	struct bdb_header *bdb;
-	u8 __iomem *bios;
-	size_t size;
-	int i;
+	struct bdb_header *bdb = NULL;
+	u8 __iomem *bios = NULL;
 
-	bios = pci_map_rom(pdev, &size);
-	if (!bios)
-		return -1;
+	init_vbt_defaults(dev_priv);
 
-	/* Scour memory looking for the VBT signature */
-	for (i = 0; i + 4 < size; i++) {
-		if (!memcmp(bios + i, "$VBT", 4)) {
-			vbt = (struct vbt_header *)(bios + i);
-			break;
-		}
+	/* XXX Should this validation be moved to intel_opregion.c? */
+	if (dev_priv->opregion.vbt) {
+		struct vbt_header *vbt = dev_priv->opregion.vbt;
+		if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+			DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
+					 vbt->signature);
+			bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+		} else
+			dev_priv->opregion.vbt = NULL;
 	}
 
-	if (!vbt) {
-		DRM_ERROR("VBT signature missing\n");
-		pci_unmap_rom(pdev, bios);
-		return -1;
-	}
+	if (bdb == NULL) {
+		struct vbt_header *vbt = NULL;
+		size_t size;
+		int i;
 
-	bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+		bios = pci_map_rom(pdev, &size);
+		if (!bios)
+			return -1;
+
+		/* Scour memory looking for the VBT signature */
+		for (i = 0; i + 4 < size; i++) {
+			if (!memcmp(bios + i, "$VBT", 4)) {
+				vbt = (struct vbt_header *)(bios + i);
+				break;
+			}
+		}
+
+		if (!vbt) {
+			DRM_ERROR("VBT signature missing\n");
+			pci_unmap_rom(pdev, bios);
+			return -1;
+		}
+
+		bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+	}
 
 	/* Grab useful general definitions */
 	parse_general_features(dev_priv, bdb);
@@ -568,7 +642,25 @@
 	parse_driver_features(dev_priv, bdb);
 	parse_edp(dev_priv, bdb);
 
-	pci_unmap_rom(pdev, bios);
+	if (bios)
+		pci_unmap_rom(pdev, bios);
 
 	return 0;
 }
+
+/* Ensure that vital registers have been initialised, even if the BIOS
+ * is absent or just failing to do its job.
+ */
+void intel_setup_bios(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	 /* Set the Panel Power On/Off timings if uninitialized. */
+	if ((I915_READ(PP_ON_DELAYS) == 0) && (I915_READ(PP_OFF_DELAYS) == 0)) {
+		/* Set T2 to 40ms and T5 to 200ms */
+		I915_WRITE(PP_ON_DELAYS, 0x019007d0);
+
+		/* Set T3 to 35ms and Tx to 200ms */
+		I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_bios.h linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_bios.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_bios.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_bios.h	2011-01-04 19:50:19.000000000 -0500
@@ -197,7 +197,8 @@
 struct child_device_config {
 	u16 handle;
 	u16 device_type;
-	u8  device_id[10]; /* See DEVICE_TYPE_* above */
+	u8  i2c_speed;
+	u8  rsvd[9];
 	u16 addin_offset;
 	u8  dvo_port; /* See Device_PORT_* above */
 	u8  i2c_pin;
@@ -466,7 +467,8 @@
 	struct edp_link_params link_params[16];
 } __attribute__ ((packed));
 
-bool intel_init_bios(struct drm_device *dev);
+void intel_setup_bios(struct drm_device *dev);
+bool intel_parse_bios(struct drm_device *dev);
 
 /*
  * Driver<->VBIOS interaction occurs through scratch bits in
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_crt.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_crt.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_crt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_crt.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,25 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+/* Here's the desired hotplug mode */
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |		\
+			   ADPA_CRT_HOTPLUG_WARMUP_10MS |		\
+			   ADPA_CRT_HOTPLUG_SAMPLE_4S |			\
+			   ADPA_CRT_HOTPLUG_VOLTAGE_50 |		\
+			   ADPA_CRT_HOTPLUG_VOLREF_325MV |		\
+			   ADPA_CRT_HOTPLUG_ENABLE)
+
+struct intel_crt {
+	struct intel_encoder base;
+	bool force_hotplug_required;
+};
+
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_crt, base);
+}
+
 static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
@@ -79,7 +98,7 @@
 	if (mode->clock < 25000)
 		return MODE_CLOCK_LOW;
 
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		max_clock = 350000;
 	else
 		max_clock = 400000;
@@ -123,13 +142,13 @@
 	 * Disable separate mode multiplier used when cloning SDVO to CRT
 	 * XXX this needs to be adjusted when we really are cloning
 	 */
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		dpll_md = I915_READ(dpll_md_reg);
 		I915_WRITE(dpll_md_reg,
 			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
 	}
 
-	adpa = 0;
+	adpa = ADPA_HOTPLUG_BITS;
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -157,52 +176,44 @@
 static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
+	struct intel_crt *crt = intel_attached_crt(connector);
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 adpa, temp;
+	u32 adpa;
 	bool ret;
-	bool turn_off_dac = false;
-
-	temp = adpa = I915_READ(PCH_ADPA);
 
-	if (HAS_PCH_SPLIT(dev))
-		turn_off_dac = true;
+	/* The first time through, trigger an explicit detection cycle */
+	if (crt->force_hotplug_required) {
+		bool turn_off_dac = HAS_PCH_SPLIT(dev);
+		u32 save_adpa;
 
-	adpa &= ~ADPA_CRT_HOTPLUG_MASK;
-	if (turn_off_dac)
-		adpa &= ~ADPA_DAC_ENABLE;
+		crt->force_hotplug_required = 0;
 
-	/* disable HPD first */
-	I915_WRITE(PCH_ADPA, adpa);
-	(void)I915_READ(PCH_ADPA);
+		save_adpa = adpa = I915_READ(PCH_ADPA);
+		DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
 
-	adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
-			ADPA_CRT_HOTPLUG_WARMUP_10MS |
-			ADPA_CRT_HOTPLUG_SAMPLE_4S |
-			ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
-			ADPA_CRT_HOTPLUG_VOLREF_325MV |
-			ADPA_CRT_HOTPLUG_ENABLE |
-			ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
+		adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
+		if (turn_off_dac)
+			adpa &= ~ADPA_DAC_ENABLE;
 
-	DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
-	I915_WRITE(PCH_ADPA, adpa);
+		I915_WRITE(PCH_ADPA, adpa);
 
-	if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
-		     1000, 1))
-		DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
+		if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
+			     1000))
+			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
 
-	if (turn_off_dac) {
-		I915_WRITE(PCH_ADPA, temp);
-		(void)I915_READ(PCH_ADPA);
+		if (turn_off_dac) {
+			I915_WRITE(PCH_ADPA, save_adpa);
+			POSTING_READ(PCH_ADPA);
+		}
 	}
 
 	/* Check the status to see if both blue and green are on now */
 	adpa = I915_READ(PCH_ADPA);
-	adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
-	if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
-		(adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
+	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
 		ret = true;
 	else
 		ret = false;
+	DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
 
 	return ret;
 }
@@ -244,7 +255,7 @@
 		/* wait for FORCE_DETECT to go off */
 		if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
 			      CRT_HOTPLUG_FORCE_DETECT) == 0,
-			     1000, 1))
+			     1000))
 			DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
 	}
 
@@ -261,21 +272,46 @@
 	return ret;
 }
 
-static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
+static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
 {
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+	u8 buf;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = 0xA0,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+	};
+	/* DDC monitor detect: Does it ACK a write to 0xA0? */
+	return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
+}
+
+static bool intel_crt_detect_ddc(struct intel_crt *crt)
+{
+	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
 
 	/* CRT should always be at 0, but check anyway */
-	if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
+	if (crt->base.type != INTEL_OUTPUT_ANALOG)
 		return false;
 
-	return intel_ddc_probe(intel_encoder);
+	if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
+		DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n");
+		return true;
+	}
+
+	if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
+		DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+		return true;
+	}
+
+	return false;
 }
 
 static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
 {
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &crt->base.base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -295,6 +331,8 @@
 	uint8_t	st00;
 	enum drm_connector_status status;
 
+	DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
 	if (pipe == 0) {
 		bclrpat_reg = BCLRPAT_A;
 		vtotal_reg = VTOTAL_A;
@@ -324,9 +362,10 @@
 	/* Set the border color to purple. */
 	I915_WRITE(bclrpat_reg, 0x500050);
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		uint32_t pipeconf = I915_READ(pipeconf_reg);
 		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+		POSTING_READ(pipeconf_reg);
 		/* Wait for next Vblank to substitue
 		 * border color for Color info */
 		intel_wait_for_vblank(dev, pipe);
@@ -404,34 +443,40 @@
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+	struct intel_crt *crt = intel_attached_crt(connector);
 	struct drm_crtc *crtc;
 	int dpms_mode;
 	enum drm_connector_status status;
 
-	if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
-		if (intel_crt_detect_hotplug(connector))
+	if (I915_HAS_HOTPLUG(dev)) {
+		if (intel_crt_detect_hotplug(connector)) {
+			DRM_DEBUG_KMS("CRT detected via hotplug\n");
 			return connector_status_connected;
-		else
+		} else {
+			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
 			return connector_status_disconnected;
+		}
 	}
 
-	if (intel_crt_detect_ddc(encoder))
+	if (intel_crt_detect_ddc(crt))
 		return connector_status_connected;
 
 	if (!force)
 		return connector->status;
 
 	/* for pre-945g platforms use load detect */
-	if (encoder->crtc && encoder->crtc->enabled) {
-		status = intel_crt_load_detect(encoder->crtc, intel_encoder);
+	crtc = crt->base.base.crtc;
+	if (crtc && crtc->enabled) {
+		status = intel_crt_load_detect(crtc, crt);
 	} else {
-		crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+		crtc = intel_get_load_detect_pipe(&crt->base, connector,
 						  NULL, &dpms_mode);
 		if (crtc) {
-			status = intel_crt_load_detect(crtc, intel_encoder);
-			intel_release_load_detect_pipe(intel_encoder,
+			if (intel_crt_detect_ddc(crt))
+				status = connector_status_connected;
+			else
+				status = intel_crt_load_detect(crtc, crt);
+			intel_release_load_detect_pipe(&crt->base,
 						       connector, dpms_mode);
 		} else
 			status = connector_status_unknown;
@@ -449,32 +494,18 @@
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
-	int ret;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	struct i2c_adapter *ddc_bus;
 	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
 
-
-	ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+	ret = intel_ddc_get_modes(connector,
+				 &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
 	if (ret || !IS_G4X(dev))
-		goto end;
+		return ret;
 
 	/* Try to probe digital port for output in DVI-I -> VGA mode. */
-	ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
-
-	if (!ddc_bus) {
-		dev_printk(KERN_ERR, &connector->dev->pdev->dev,
-			   "DDC bus registration failed for CRTDDC_D.\n");
-		goto end;
-	}
-	/* Try to get modes by GPIOD port */
-	ret = intel_ddc_get_modes(connector, ddc_bus);
-	intel_i2c_destroy(ddc_bus);
-
-end:
-	return ret;
-
+	return intel_ddc_get_modes(connector,
+				   &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,7 +538,7 @@
 static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
 	.mode_valid = intel_crt_mode_valid,
 	.get_modes = intel_crt_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -517,18 +548,17 @@
 void intel_crt_init(struct drm_device *dev)
 {
 	struct drm_connector *connector;
-	struct intel_encoder *intel_encoder;
+	struct intel_crt *crt;
 	struct intel_connector *intel_connector;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 i2c_reg;
 
-	intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
-	if (!intel_encoder)
+	crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
+	if (!crt)
 		return;
 
 	intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
 	if (!intel_connector) {
-		kfree(intel_encoder);
+		kfree(crt);
 		return;
 	}
 
@@ -536,37 +566,20 @@
 	drm_connector_init(dev, &intel_connector->base,
 			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
+	drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
 			 DRM_MODE_ENCODER_DAC);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
-
-	/* Set up the DDC bus. */
-	if (HAS_PCH_SPLIT(dev))
-		i2c_reg = PCH_GPIOA;
-	else {
-		i2c_reg = GPIOA;
-		/* Use VBT information for CRT DDC if available */
-		if (dev_priv->crt_ddc_bus != 0)
-			i2c_reg = dev_priv->crt_ddc_bus;
-	}
-	intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
-	if (!intel_encoder->ddc_bus) {
-		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-			   "failed.\n");
-		return;
-	}
+	intel_connector_attach_encoder(intel_connector, &crt->base);
 
-	intel_encoder->type = INTEL_OUTPUT_ANALOG;
-	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-				   (1 << INTEL_ANALOG_CLONE_BIT) |
-				   (1 << INTEL_SDVO_LVDS_CLONE_BIT);
-	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+	crt->base.type = INTEL_OUTPUT_ANALOG;
+	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
+				1 << INTEL_ANALOG_CLONE_BIT |
+				1 << INTEL_SDVO_LVDS_CLONE_BIT);
+	crt->base.crtc_mask = (1 << 0) | (1 << 1);
 	connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
 
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
+	drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
 	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
 	drm_sysfs_connector_add(connector);
@@ -576,5 +589,22 @@
 	else
 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
 
+	/*
+	 * Configure the automatic hotplug detection stuff
+	 */
+	crt->force_hotplug_required = 0;
+	if (HAS_PCH_SPLIT(dev)) {
+		u32 adpa;
+
+		adpa = I915_READ(PCH_ADPA);
+		adpa &= ~ADPA_CRT_HOTPLUG_MASK;
+		adpa |= ADPA_HOTPLUG_BITS;
+		I915_WRITE(PCH_ADPA, adpa);
+		POSTING_READ(PCH_ADPA);
+
+		DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
+		crt->force_hotplug_required = 1;
+	}
+
 	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_display.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_display.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_display.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_display.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,8 +43,8 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
     /* given values */
@@ -342,6 +342,16 @@
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
 			   int target, int refclk, intel_clock_t *best_clock);
 
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+	if (IS_GEN5(dev)) {
+		struct drm_i915_private *dev_priv = dev->dev_private;
+		return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+	} else
+		return 27;
+}
+
 static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,		.max = I8XX_VCO_MAX },
@@ -701,16 +711,16 @@
 		limit = intel_ironlake_limit(crtc);
 	else if (IS_G4X(dev)) {
 		limit = intel_g4x_limit(crtc);
-	} else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) {
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-			limit = &intel_limits_i9xx_lvds;
-		else
-			limit = &intel_limits_i9xx_sdvo;
 	} else if (IS_PINEVIEW(dev)) {
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
 			limit = &intel_limits_pineview_lvds;
 		else
 			limit = &intel_limits_pineview_sdvo;
+	} else if (!IS_GEN2(dev)) {
+		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+			limit = &intel_limits_i9xx_lvds;
+		else
+			limit = &intel_limits_i9xx_sdvo;
 	} else {
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
 			limit = &intel_limits_i8xx_lvds;
@@ -744,20 +754,17 @@
 /**
  * Returns whether any output on the specified pipe is of the specified type
  */
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
 {
-    struct drm_device *dev = crtc->dev;
-    struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_encoder *l_entry;
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *mode_config = &dev->mode_config;
+	struct intel_encoder *encoder;
 
-    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
-	    if (l_entry && l_entry->crtc == crtc) {
-		    struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
-		    if (intel_encoder->type == type)
-			    return true;
-	    }
-    }
-    return false;
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+		if (encoder->base.crtc == crtc && encoder->type == type)
+			return true;
+
+	return false;
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -928,10 +935,6 @@
 	struct drm_device *dev = crtc->dev;
 	intel_clock_t clock;
 
-	/* return directly when it is eDP */
-	if (HAS_eDP)
-		return true;
-
 	if (target < 200000) {
 		clock.n = 1;
 		clock.p1 = 2;
@@ -955,26 +958,26 @@
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
 		      int target, int refclk, intel_clock_t *best_clock)
 {
-    intel_clock_t clock;
-    if (target < 200000) {
-	clock.p1 = 2;
-	clock.p2 = 10;
-	clock.n = 2;
-	clock.m1 = 23;
-	clock.m2 = 8;
-    } else {
-	clock.p1 = 1;
-	clock.p2 = 10;
-	clock.n = 1;
-	clock.m1 = 14;
-	clock.m2 = 2;
-    }
-    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
-    clock.p = (clock.p1 * clock.p2);
-    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
-    clock.vco = 0;
-    memcpy(best_clock, &clock, sizeof(intel_clock_t));
-    return true;
+	intel_clock_t clock;
+	if (target < 200000) {
+		clock.p1 = 2;
+		clock.p2 = 10;
+		clock.n = 2;
+		clock.m1 = 23;
+		clock.m2 = 8;
+	} else {
+		clock.p1 = 1;
+		clock.p2 = 10;
+		clock.n = 1;
+		clock.m1 = 14;
+		clock.m2 = 2;
+	}
+	clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+	clock.p = (clock.p1 * clock.p2);
+	clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+	clock.vco = 0;
+	memcpy(best_clock, &clock, sizeof(intel_clock_t));
+	return true;
 }
 
 /**
@@ -1007,9 +1010,9 @@
 		   I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
 
 	/* Wait for vblank interrupt bit to set */
-	if (wait_for((I915_READ(pipestat_reg) &
-		      PIPE_VBLANK_INTERRUPT_STATUS),
-		     50, 0))
+	if (wait_for(I915_READ(pipestat_reg) &
+		     PIPE_VBLANK_INTERRUPT_STATUS,
+		     50))
 		DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
@@ -1028,36 +1031,35 @@
  * Otherwise:
  *   wait for the display line value to settle (it usually
  *   ends up stopping at the start of the next frame).
- *  
+ *
  */
-static void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
+void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (INTEL_INFO(dev)->gen >= 4) {
-		int pipeconf_reg = (pipe == 0 ? PIPEACONF : PIPEBCONF);
+		int reg = PIPECONF(pipe);
 
 		/* Wait for the Pipe State to go off */
-		if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0,
-			     100, 0))
+		if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
+			     100))
 			DRM_DEBUG_KMS("pipe_off wait timed out\n");
 	} else {
 		u32 last_line;
-		int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
+		int reg = PIPEDSL(pipe);
 		unsigned long timeout = jiffies + msecs_to_jiffies(100);
 
 		/* Wait for the display line to settle */
 		do {
-			last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
+			last_line = I915_READ(reg) & DSL_LINEMASK;
 			mdelay(5);
-		} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
+		} while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
 			 time_after(timeout, jiffies));
 		if (time_after(jiffies, timeout))
 			DRM_DEBUG_KMS("pipe_off wait timed out\n");
 	}
 }
 
-/* Parameters have changed, update FBC info */
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1069,6 +1071,14 @@
 	int plane, i;
 	u32 fbc_ctl, fbc_ctl2;
 
+	if (fb->pitch == dev_priv->cfb_pitch &&
+	    obj_priv->fence_reg == dev_priv->cfb_fence &&
+	    intel_crtc->plane == dev_priv->cfb_plane &&
+	    I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+		return;
+
+	i8xx_disable_fbc(dev);
+
 	dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
 
 	if (fb->pitch < dev_priv->cfb_pitch)
@@ -1102,7 +1112,7 @@
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
 	DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-		  dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+		      dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
 void i8xx_disable_fbc(struct drm_device *dev)
@@ -1110,19 +1120,16 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 fbc_ctl;
 
-	if (!I915_HAS_FBC(dev))
-		return;
-
-	if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
-		return;	/* Already off, just return */
-
 	/* Disable compression */
 	fbc_ctl = I915_READ(FBC_CONTROL);
+	if ((fbc_ctl & FBC_CTL_EN) == 0)
+		return;
+
 	fbc_ctl &= ~FBC_CTL_EN;
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
 	/* Wait for compressing bit to clear */
-	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
 		DRM_DEBUG_KMS("FBC idle timed out\n");
 		return;
 	}
@@ -1145,14 +1152,27 @@
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
-		     DPFC_CTL_PLANEB);
+	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 	unsigned long stall_watermark = 200;
 	u32 dpfc_ctl;
 
+	dpfc_ctl = I915_READ(DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+		    dev_priv->cfb_fence == obj_priv->fence_reg &&
+		    dev_priv->cfb_plane == intel_crtc->plane &&
+		    dev_priv->cfb_y == crtc->y)
+			return;
+
+		I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+		POSTING_READ(DPFC_CONTROL);
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+	}
+
 	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj_priv->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
+	dev_priv->cfb_y = crtc->y;
 
 	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1162,7 +1182,6 @@
 		I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
 	}
 
-	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 	I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
 		   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1181,10 +1200,12 @@
 
 	/* Disable compression */
 	dpfc_ctl = I915_READ(DPFC_CONTROL);
-	dpfc_ctl &= ~DPFC_CTL_EN;
-	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 
-	DRM_DEBUG_KMS("disabled FBC\n");
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
 }
 
 static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1202,16 +1223,30 @@
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
-					       DPFC_CTL_PLANEB;
+	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 	unsigned long stall_watermark = 200;
 	u32 dpfc_ctl;
 
+	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+		    dev_priv->cfb_fence == obj_priv->fence_reg &&
+		    dev_priv->cfb_plane == intel_crtc->plane &&
+		    dev_priv->cfb_offset == obj_priv->gtt_offset &&
+		    dev_priv->cfb_y == crtc->y)
+			return;
+
+		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+		POSTING_READ(ILK_DPFC_CONTROL);
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+	}
+
 	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj_priv->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
+	dev_priv->cfb_offset = obj_priv->gtt_offset;
+	dev_priv->cfb_y = crtc->y;
 
-	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
 	dpfc_ctl &= DPFC_RESERVED;
 	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1221,15 +1256,13 @@
 		I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
 	}
 
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 	I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
 		   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
 	I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
 	I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
 	/* enable it... */
-	I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
-		   DPFC_CTL_EN);
+	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
 	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
@@ -1241,10 +1274,12 @@
 
 	/* Disable compression */
 	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-	dpfc_ctl &= ~DPFC_CTL_EN;
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-	DRM_DEBUG_KMS("disabled FBC\n");
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
 }
 
 static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1286,8 +1321,7 @@
 
 /**
  * intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
  *
  * Set up the framebuffer compression hardware at mode set time.  We
  * enable it if possible:
@@ -1304,18 +1338,14 @@
  *
  * We need to enable/disable FBC on a global basis.
  */
-static void intel_update_fbc(struct drm_crtc *crtc,
-			     struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
 {
-	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_crtc *crtc = NULL, *tmp_crtc;
+	struct intel_crtc *intel_crtc;
+	struct drm_framebuffer *fb;
 	struct intel_framebuffer *intel_fb;
 	struct drm_i915_gem_object *obj_priv;
-	struct drm_crtc *tmp_crtc;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = intel_crtc->plane;
-	int crtcs_enabled = 0;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -1325,12 +1355,6 @@
 	if (!I915_HAS_FBC(dev))
 		return;
 
-	if (!crtc->fb)
-		return;
-
-	intel_fb = to_intel_framebuffer(fb);
-	obj_priv = to_intel_bo(intel_fb->obj);
-
 	/*
 	 * If FBC is already on, we just have to verify that we can
 	 * keep it that way...
@@ -1341,35 +1365,47 @@
 	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
 	 */
 	list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-		if (tmp_crtc->enabled)
-			crtcs_enabled++;
+		if (tmp_crtc->enabled) {
+			if (crtc) {
+				DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+				dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+				goto out_disable;
+			}
+			crtc = tmp_crtc;
+		}
 	}
-	DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
-	if (crtcs_enabled > 1) {
-		DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-		dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+	if (!crtc || crtc->fb == NULL) {
+		DRM_DEBUG_KMS("no output, disabling\n");
+		dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
 		goto out_disable;
 	}
+
+	intel_crtc = to_intel_crtc(crtc);
+	fb = crtc->fb;
+	intel_fb = to_intel_framebuffer(fb);
+	obj_priv = to_intel_bo(intel_fb->obj);
+
 	if (intel_fb->obj->size > dev_priv->cfb_size) {
 		DRM_DEBUG_KMS("framebuffer too large, disabling "
-				"compression\n");
+			      "compression\n");
 		dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
 		goto out_disable;
 	}
-	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
-	    (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+	if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+	    (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
 		DRM_DEBUG_KMS("mode incompatible with compression, "
-				"disabling\n");
+			      "disabling\n");
 		dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
 		goto out_disable;
 	}
-	if ((mode->hdisplay > 2048) ||
-	    (mode->vdisplay > 1536)) {
+	if ((crtc->mode.hdisplay > 2048) ||
+	    (crtc->mode.vdisplay > 1536)) {
 		DRM_DEBUG_KMS("mode too large for compression, disabling\n");
 		dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
 		goto out_disable;
 	}
-	if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
+	if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
 		DRM_DEBUG_KMS("plane not 0, disabling compression\n");
 		dev_priv->no_fbc_reason = FBC_BAD_PLANE;
 		goto out_disable;
@@ -1384,18 +1420,7 @@
 	if (in_dbg_master())
 		goto out_disable;
 
-	if (intel_fbc_enabled(dev)) {
-		/* We can re-enable it in this case, but need to update pitch */
-		if ((fb->pitch > dev_priv->cfb_pitch) ||
-		    (obj_priv->fence_reg != dev_priv->cfb_fence) ||
-		    (plane != dev_priv->cfb_plane))
-			intel_disable_fbc(dev);
-	}
-
-	/* Now try to turn it back on if possible */
-	if (!intel_fbc_enabled(dev))
-		intel_enable_fbc(crtc, 500);
-
+	intel_enable_fbc(crtc, 500);
 	return;
 
 out_disable:
@@ -1407,7 +1432,9 @@
 }
 
 int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+			   struct drm_gem_object *obj,
+			   bool pipelined)
 {
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	u32 alignment;
@@ -1417,7 +1444,7 @@
 	case I915_TILING_NONE:
 		if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
 			alignment = 128 * 1024;
-		else if (IS_I965G(dev))
+		else if (INTEL_INFO(dev)->gen >= 4)
 			alignment = 4 * 1024;
 		else
 			alignment = 64 * 1024;
@@ -1435,9 +1462,13 @@
 	}
 
 	ret = i915_gem_object_pin(obj, alignment);
-	if (ret != 0)
+	if (ret)
 		return ret;
 
+	ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+	if (ret)
+		goto err_unpin;
+
 	/* Install a fence for tiled scan-out. Pre-i965 always needs a
 	 * fence, whereas 965+ only requires a fence if using
 	 * framebuffer compression.  For simplicity, we always install
@@ -1445,20 +1476,22 @@
 	 */
 	if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
 	    obj_priv->tiling_mode != I915_TILING_NONE) {
-		ret = i915_gem_object_get_fence_reg(obj);
-		if (ret != 0) {
-			i915_gem_object_unpin(obj);
-			return ret;
-		}
+		ret = i915_gem_object_get_fence_reg(obj, false);
+		if (ret)
+			goto err_unpin;
 	}
 
 	return 0;
+
+err_unpin:
+	i915_gem_object_unpin(obj);
+	return ret;
 }
 
 /* Assume fb object is pinned & idle & fenced and just update base pointers */
 static int
 intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-			   int x, int y)
+			   int x, int y, enum mode_set_atomic state)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1468,12 +1501,8 @@
 	struct drm_gem_object *obj;
 	int plane = intel_crtc->plane;
 	unsigned long Start, Offset;
-	int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
-	int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
-	int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
-	int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
 	u32 dspcntr;
+	u32 reg;
 
 	switch (plane) {
 	case 0:
@@ -1488,7 +1517,8 @@
 	obj = intel_fb->obj;
 	obj_priv = to_intel_bo(obj);
 
-	dspcntr = I915_READ(dspcntr_reg);
+	reg = DSPCNTR(plane);
+	dspcntr = I915_READ(reg);
 	/* Mask out pixel format bits in case we change it */
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 	switch (fb->bits_per_pixel) {
@@ -1509,7 +1539,7 @@
 		DRM_ERROR("Unknown color depth\n");
 		return -EINVAL;
 	}
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		if (obj_priv->tiling_mode != I915_TILING_NONE)
 			dspcntr |= DISPPLANE_TILED;
 		else
@@ -1520,28 +1550,24 @@
 		/* must disable */
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-	I915_WRITE(dspcntr_reg, dspcntr);
+	I915_WRITE(reg, dspcntr);
 
 	Start = obj_priv->gtt_offset;
 	Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 
 	DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
 		      Start, Offset, x, y, fb->pitch);
-	I915_WRITE(dspstride, fb->pitch);
-	if (IS_I965G(dev)) {
-		I915_WRITE(dspsurf, Start);
-		I915_WRITE(dsptileoff, (y << 16) | x);
-		I915_WRITE(dspbase, Offset);
-	} else {
-		I915_WRITE(dspbase, Start + Offset);
-	}
-	POSTING_READ(dspbase);
-
-	if (IS_I965G(dev) || plane == 0)
-		intel_update_fbc(crtc, &crtc->mode);
+	I915_WRITE(DSPSTRIDE(plane), fb->pitch);
+	if (INTEL_INFO(dev)->gen >= 4) {
+		I915_WRITE(DSPSURF(plane), Start);
+		I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+		I915_WRITE(DSPADDR(plane), Offset);
+	} else
+		I915_WRITE(DSPADDR(plane), Start + Offset);
+	POSTING_READ(reg);
 
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
-	intel_increase_pllclock(crtc, true);
+	intel_update_fbc(dev);
+	intel_increase_pllclock(crtc);
 
 	return 0;
 }
@@ -1553,11 +1579,6 @@
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_master_private *master_priv;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_framebuffer *intel_fb;
-	struct drm_i915_gem_object *obj_priv;
-	struct drm_gem_object *obj;
-	int pipe = intel_crtc->pipe;
-	int plane = intel_crtc->plane;
 	int ret;
 
 	/* no fb bound */
@@ -1566,45 +1587,54 @@
 		return 0;
 	}
 
-	switch (plane) {
+	switch (intel_crtc->plane) {
 	case 0:
 	case 1:
 		break;
 	default:
-		DRM_ERROR("Can't update plane %d in SAREA\n", plane);
 		return -EINVAL;
 	}
 
-	intel_fb = to_intel_framebuffer(crtc->fb);
-	obj = intel_fb->obj;
-	obj_priv = to_intel_bo(obj);
-
 	mutex_lock(&dev->struct_mutex);
-	ret = intel_pin_and_fence_fb_obj(dev, obj);
+	ret = intel_pin_and_fence_fb_obj(dev,
+					 to_intel_framebuffer(crtc->fb)->obj,
+					 false);
 	if (ret != 0) {
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
 	}
 
-	ret = i915_gem_object_set_to_display_plane(obj);
-	if (ret != 0) {
-		i915_gem_object_unpin(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
+	if (old_fb) {
+		struct drm_i915_private *dev_priv = dev->dev_private;
+		struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
+		struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+		wait_event(dev_priv->pending_flip_queue,
+			   atomic_read(&obj_priv->pending_flip) == 0);
+
+		/* Big Hammer, we also need to ensure that any pending
+		 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
+		 * current scanout is retired before unpinning the old
+		 * framebuffer.
+		 */
+		ret = i915_gem_object_flush_gpu(obj_priv, false);
+		if (ret) {
+			i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+			mutex_unlock(&dev->struct_mutex);
+			return ret;
+		}
 	}
 
-	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
+	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
+					 LEAVE_ATOMIC_MODE_SET);
 	if (ret) {
-		i915_gem_object_unpin(obj);
+		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
 	}
 
-	if (old_fb) {
-		intel_fb = to_intel_framebuffer(old_fb);
-		obj_priv = to_intel_bo(intel_fb->obj);
-		i915_gem_object_unpin(intel_fb->obj);
-	}
+	if (old_fb)
+		i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
 
 	mutex_unlock(&dev->struct_mutex);
 
@@ -1615,7 +1645,7 @@
 	if (!master_priv->sarea_priv)
 		return 0;
 
-	if (pipe) {
+	if (intel_crtc->pipe) {
 		master_priv->sarea_priv->pipeB_x = x;
 		master_priv->sarea_priv->pipeB_y = y;
 	} else {
@@ -1626,7 +1656,7 @@
 	return 0;
 }
 
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1659,9 +1689,41 @@
 	}
 	I915_WRITE(DP_A, dpa_ctl);
 
+	POSTING_READ(DP_A);
 	udelay(500);
 }
 
+static void intel_fdi_normal_train(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	u32 reg, temp;
+
+	/* enable normal train */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+	I915_WRITE(reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_NONE;
+	}
+	I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+	/* wait one idle pattern time */
+	POSTING_READ(reg);
+	udelay(1000);
+}
+
 /* The FDI link training functions for ILK/Ibexpeak. */
 static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -1669,84 +1731,88 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-	u32 temp, tries = 0;
+	u32 reg, temp, tries;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
-	temp = I915_READ(fdi_rx_imr_reg);
+	reg = FDI_RX_IMR(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_RX_SYMBOL_LOCK;
 	temp &= ~FDI_RX_BIT_LOCK;
-	I915_WRITE(fdi_rx_imr_reg, temp);
-	I915_READ(fdi_rx_imr_reg);
+	I915_WRITE(reg, temp);
+	I915_READ(reg);
 	udelay(150);
 
 	/* enable CPU FDI TX and PCH FDI RX */
-	temp = I915_READ(fdi_tx_reg);
-	temp |= FDI_TX_ENABLE;
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~(7 << 19);
 	temp |= (intel_crtc->fdi_lanes - 1) << 19;
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	I915_WRITE(fdi_tx_reg, temp);
-	I915_READ(fdi_tx_reg);
+	I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-	I915_READ(fdi_rx_reg);
+	I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
 	udelay(150);
 
+	/* Ironlake workaround, enable clock pointer after FDI enable*/
+	I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_ENABLE);
+
+	reg = FDI_RX_IIR(pipe);
 	for (tries = 0; tries < 5; tries++) {
-		temp = I915_READ(fdi_rx_iir_reg);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if ((temp & FDI_RX_BIT_LOCK)) {
 			DRM_DEBUG_KMS("FDI train 1 done.\n");
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_BIT_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
 			break;
 		}
 	}
 	if (tries == 5)
-		DRM_DEBUG_KMS("FDI train 1 fail!\n");
+		DRM_ERROR("FDI train 1 fail!\n");
 
 	/* Train 2 */
-	temp = I915_READ(fdi_tx_reg);
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	I915_WRITE(fdi_tx_reg, temp);
+	I915_WRITE(reg, temp);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	I915_WRITE(fdi_rx_reg, temp);
-	udelay(150);
+	I915_WRITE(reg, temp);
 
-	tries = 0;
+	POSTING_READ(reg);
+	udelay(150);
 
+	reg = FDI_RX_IIR(pipe);
 	for (tries = 0; tries < 5; tries++) {
-		temp = I915_READ(fdi_rx_iir_reg);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_SYMBOL_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_SYMBOL_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
 			DRM_DEBUG_KMS("FDI train 2 done.\n");
 			break;
 		}
 	}
 	if (tries == 5)
-		DRM_DEBUG_KMS("FDI train 2 fail!\n");
+		DRM_ERROR("FDI train 2 fail!\n");
 
 	DRM_DEBUG_KMS("FDI train done\n");
+
 }
 
-static int snb_b_fdi_train_param [] = {
+static const int const snb_b_fdi_train_param [] = {
 	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
 	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
 	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -1760,24 +1826,22 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-	u32 temp, i;
+	u32 reg, temp, i;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
-	temp = I915_READ(fdi_rx_imr_reg);
+	reg = FDI_RX_IMR(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_RX_SYMBOL_LOCK;
 	temp &= ~FDI_RX_BIT_LOCK;
-	I915_WRITE(fdi_rx_imr_reg, temp);
-	I915_READ(fdi_rx_imr_reg);
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	/* enable CPU FDI TX and PCH FDI RX */
-	temp = I915_READ(fdi_tx_reg);
-	temp |= FDI_TX_ENABLE;
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~(7 << 19);
 	temp |= (intel_crtc->fdi_lanes - 1) << 19;
 	temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1785,10 +1849,10 @@
 	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 	/* SNB-B */
 	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-	I915_WRITE(fdi_tx_reg, temp);
-	I915_READ(fdi_tx_reg);
+	I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	if (HAS_PCH_CPT(dev)) {
 		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
 		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1796,32 +1860,37 @@
 		temp &= ~FDI_LINK_TRAIN_NONE;
 		temp |= FDI_LINK_TRAIN_PATTERN_1;
 	}
-	I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-	I915_READ(fdi_rx_reg);
+	I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	for (i = 0; i < 4; i++ ) {
-		temp = I915_READ(fdi_tx_reg);
+		reg = FDI_TX_CTL(pipe);
+		temp = I915_READ(reg);
 		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 		temp |= snb_b_fdi_train_param[i];
-		I915_WRITE(fdi_tx_reg, temp);
+		I915_WRITE(reg, temp);
+
+		POSTING_READ(reg);
 		udelay(500);
 
-		temp = I915_READ(fdi_rx_iir_reg);
+		reg = FDI_RX_IIR(pipe);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_BIT_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_BIT_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
 			DRM_DEBUG_KMS("FDI train 1 done.\n");
 			break;
 		}
 	}
 	if (i == 4)
-		DRM_DEBUG_KMS("FDI train 1 fail!\n");
+		DRM_ERROR("FDI train 1 fail!\n");
 
 	/* Train 2 */
-	temp = I915_READ(fdi_tx_reg);
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
 	if (IS_GEN6(dev)) {
@@ -1829,9 +1898,10 @@
 		/* SNB-B */
 		temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
 	}
-	I915_WRITE(fdi_tx_reg, temp);
+	I915_WRITE(reg, temp);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	if (HAS_PCH_CPT(dev)) {
 		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
 		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1839,535 +1909,598 @@
 		temp &= ~FDI_LINK_TRAIN_NONE;
 		temp |= FDI_LINK_TRAIN_PATTERN_2;
 	}
-	I915_WRITE(fdi_rx_reg, temp);
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	for (i = 0; i < 4; i++ ) {
-		temp = I915_READ(fdi_tx_reg);
+		reg = FDI_TX_CTL(pipe);
+		temp = I915_READ(reg);
 		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 		temp |= snb_b_fdi_train_param[i];
-		I915_WRITE(fdi_tx_reg, temp);
+		I915_WRITE(reg, temp);
+
+		POSTING_READ(reg);
 		udelay(500);
 
-		temp = I915_READ(fdi_rx_iir_reg);
+		reg = FDI_RX_IIR(pipe);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_SYMBOL_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_SYMBOL_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
 			DRM_DEBUG_KMS("FDI train 2 done.\n");
 			break;
 		}
 	}
 	if (i == 4)
-		DRM_DEBUG_KMS("FDI train 2 fail!\n");
+		DRM_ERROR("FDI train 2 fail!\n");
 
 	DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	int plane = intel_crtc->plane;
-	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
-	int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-	int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-	int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-	int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-	int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-	int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-	int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
-	int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
-	int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
-	int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
-	int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
-	int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
-	int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-	u32 temp;
-	u32 pipe_bpc;
+	u32 reg, temp;
 
-	temp = I915_READ(pipeconf_reg);
-	pipe_bpc = temp & PIPE_BPC_MASK;
+	/* Write the TU size bits so error detection works */
+	I915_WRITE(FDI_RX_TUSIZE1(pipe),
+		   I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
 
-	/* XXX: When our outputs are all unaware of DPMS modes other than off
-	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
-	 */
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-		DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+	/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~((0x7 << 19) | (0x7 << 16));
+	temp |= (intel_crtc->fdi_lanes - 1) << 19;
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
 
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-			temp = I915_READ(PCH_LVDS);
-			if ((temp & LVDS_PORT_EN) == 0) {
-				I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-				POSTING_READ(PCH_LVDS);
-			}
-		}
+	POSTING_READ(reg);
+	udelay(200);
 
-		if (!HAS_eDP) {
+	/* Switch from Rawclk to PCDclk */
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp | FDI_PCDCLK);
 
-			/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-			temp = I915_READ(fdi_rx_reg);
-			/*
-			 * make the BPC in FDI Rx be consistent with that in
-			 * pipeconf reg.
-			 */
-			temp &= ~(0x7 << 16);
-			temp |= (pipe_bpc << 11);
-			temp &= ~(7 << 19);
-			temp |= (intel_crtc->fdi_lanes - 1) << 19;
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
+	POSTING_READ(reg);
+	udelay(200);
 
-			/* Switch from Rawclk to PCDclk */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
+	/* Enable CPU FDI TX PLL, always on for Ironlake */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+		I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
-			/* Enable CPU FDI TX PLL, always on for Ironlake */
-			temp = I915_READ(fdi_tx_reg);
-			if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-				I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-				I915_READ(fdi_tx_reg);
-				udelay(100);
-			}
-		}
+		POSTING_READ(reg);
+		udelay(100);
+	}
+}
 
-		/* Enable panel fitting for LVDS */
-		if (dev_priv->pch_pf_size &&
-		    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-		    || HAS_eDP || intel_pch_has_edp(crtc))) {
-			/* Force use of hard-coded filter coefficients
-			 * as some pre-programmed values are broken,
-			 * e.g. x201.
-			 */
-			I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
-				   PF_ENABLE | PF_FILTER_MED_3x3);
-			I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-				   dev_priv->pch_pf_pos);
-			I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-				   dev_priv->pch_pf_size);
-		}
+static void intel_flush_display_plane(struct drm_device *dev,
+				      int plane)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 reg = DSPADDR(plane);
+	I915_WRITE(reg, I915_READ(reg));
+}
 
-		/* Enable CPU pipe */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) == 0) {
-			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-			I915_READ(pipeconf_reg);
-			udelay(100);
-		}
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 tmp;
 
-		/* configure and enable CPU plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-		}
+	if (IS_GEN2(dev))
+		/* Can't break the hang on i8xx */
+		return;
 
-		if (!HAS_eDP) {
-			/* For PCH output, training FDI link */
-			if (IS_GEN6(dev))
-				gen6_fdi_link_train(crtc);
-			else
-				ironlake_fdi_link_train(crtc);
+	tmp = I915_READ(PRB0_CTL);
+	if (tmp & RING_WAIT) {
+		I915_WRITE(PRB0_CTL, tmp);
+		POSTING_READ(PRB0_CTL);
+	}
+}
 
-			/* enable PCH DPLL */
-			temp = I915_READ(pch_dpll_reg);
-			if ((temp & DPLL_VCO_ENABLE) == 0) {
-				I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-				I915_READ(pch_dpll_reg);
-			}
-			udelay(200);
+static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+{
+	struct drm_i915_gem_object *obj_priv;
+	struct drm_i915_private *dev_priv;
 
-			if (HAS_PCH_CPT(dev)) {
-				/* Be sure PCH DPLL SEL is set */
-				temp = I915_READ(PCH_DPLL_SEL);
-				if (trans_dpll_sel == 0 &&
-						(temp & TRANSA_DPLL_ENABLE) == 0)
-					temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-				else if (trans_dpll_sel == 1 &&
-						(temp & TRANSB_DPLL_ENABLE) == 0)
-					temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-				I915_WRITE(PCH_DPLL_SEL, temp);
-				I915_READ(PCH_DPLL_SEL);
-			}
+	if (crtc->fb == NULL)
+		return;
 
-			/* set transcoder timing */
-			I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-			I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-			I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
+	obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+	dev_priv = crtc->dev->dev_private;
+	wait_event(dev_priv->pending_flip_queue,
+		   atomic_read(&obj_priv->pending_flip) == 0);
+}
 
-			I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-			I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-			I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
+static void ironlake_crtc_enable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
+	u32 reg, temp;
 
-			/* enable normal train */
-			temp = I915_READ(fdi_tx_reg);
-			temp &= ~FDI_LINK_TRAIN_NONE;
-			I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-					FDI_TX_ENHANCE_FRAME_ENABLE);
-			I915_READ(fdi_tx_reg);
+	if (intel_crtc->active)
+		return;
 
-			temp = I915_READ(fdi_rx_reg);
-			if (HAS_PCH_CPT(dev)) {
-				temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-				temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-			} else {
-				temp &= ~FDI_LINK_TRAIN_NONE;
-				temp |= FDI_LINK_TRAIN_NONE;
-			}
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-			I915_READ(fdi_rx_reg);
+	intel_crtc->active = true;
+	intel_update_watermarks(dev);
 
-			/* wait one idle pattern time */
-			udelay(100);
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+		temp = I915_READ(PCH_LVDS);
+		if ((temp & LVDS_PORT_EN) == 0)
+			I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+	}
 
-			/* For PCH DP, enable TRANS_DP_CTL */
-			if (HAS_PCH_CPT(dev) &&
-			    intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
-				int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-				int reg;
+	ironlake_fdi_enable(crtc);
 
-				reg = I915_READ(trans_dp_ctl);
-				reg &= ~(TRANS_DP_PORT_SEL_MASK |
-					 TRANS_DP_SYNC_MASK);
-				reg |= (TRANS_DP_OUTPUT_ENABLE |
-					TRANS_DP_ENH_FRAMING);
+	/* Enable panel fitting for LVDS */
+	if (dev_priv->pch_pf_size &&
+	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+		/* Force use of hard-coded filter coefficients
+		 * as some pre-programmed values are broken,
+		 * e.g. x201.
+		 */
+		I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+			   PF_ENABLE | PF_FILTER_MED_3x3);
+		I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+			   dev_priv->pch_pf_pos);
+		I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+			   dev_priv->pch_pf_size);
+	}
 
-				if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
-				      reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-				if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
-				      reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+	/* Enable CPU pipe */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if ((temp & PIPECONF_ENABLE) == 0) {
+		I915_WRITE(reg, temp | PIPECONF_ENABLE);
+		POSTING_READ(reg);
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+	}
 
-				switch (intel_trans_dp_port_sel(crtc)) {
-				case PCH_DP_B:
-					reg |= TRANS_DP_PORT_SEL_B;
-					break;
-				case PCH_DP_C:
-					reg |= TRANS_DP_PORT_SEL_C;
-					break;
-				case PCH_DP_D:
-					reg |= TRANS_DP_PORT_SEL_D;
-					break;
-				default:
-					DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
-					reg |= TRANS_DP_PORT_SEL_B;
-					break;
-				}
+	/* configure and enable CPU plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
 
-				I915_WRITE(trans_dp_ctl, reg);
-				POSTING_READ(trans_dp_ctl);
-			}
+	/* For PCH output, training FDI link */
+	if (IS_GEN6(dev))
+		gen6_fdi_link_train(crtc);
+	else
+		ironlake_fdi_link_train(crtc);
 
-			/* enable PCH transcoder */
-			temp = I915_READ(transconf_reg);
-			/*
-			 * make the BPC in transcoder be consistent with
-			 * that in pipeconf reg.
-			 */
-			temp &= ~PIPE_BPC_MASK;
-			temp |= pipe_bpc;
-			I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-			I915_READ(transconf_reg);
+	/* enable PCH DPLL */
+	reg = PCH_DPLL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & DPLL_VCO_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+		POSTING_READ(reg);
+		udelay(200);
+	}
 
-			if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
-				DRM_ERROR("failed to enable transcoder\n");
-		}
+	if (HAS_PCH_CPT(dev)) {
+		/* Be sure PCH DPLL SEL is set */
+		temp = I915_READ(PCH_DPLL_SEL);
+		if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+			temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+		else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+			temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+		I915_WRITE(PCH_DPLL_SEL, temp);
+	}
 
-		intel_crtc_load_lut(crtc);
+	/* set transcoder timing */
+	I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+	I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+	I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
 
-		intel_update_fbc(crtc, &crtc->mode);
-		break;
+	I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+	I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+	I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
 
-	case DRM_MODE_DPMS_OFF:
-		DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+	intel_fdi_normal_train(crtc);
 
-		drm_vblank_off(dev, pipe);
-		/* Disable display plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-			I915_READ(dspbase_reg);
+	/* For PCH DP, enable TRANS_DP_CTL */
+	if (HAS_PCH_CPT(dev) &&
+	    intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+		reg = TRANS_DP_CTL(pipe);
+		temp = I915_READ(reg);
+		temp &= ~(TRANS_DP_PORT_SEL_MASK |
+			  TRANS_DP_SYNC_MASK |
+			  TRANS_DP_BPC_MASK);
+		temp |= (TRANS_DP_OUTPUT_ENABLE |
+			 TRANS_DP_ENH_FRAMING);
+		temp |= TRANS_DP_8BPC;
+
+		if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+			temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+		if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+			temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+		switch (intel_trans_dp_port_sel(crtc)) {
+		case PCH_DP_B:
+			temp |= TRANS_DP_PORT_SEL_B;
+			break;
+		case PCH_DP_C:
+			temp |= TRANS_DP_PORT_SEL_C;
+			break;
+		case PCH_DP_D:
+			temp |= TRANS_DP_PORT_SEL_D;
+			break;
+		default:
+			DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+			temp |= TRANS_DP_PORT_SEL_B;
+			break;
 		}
 
-		if (dev_priv->cfb_plane == plane &&
-		    dev_priv->display.disable_fbc)
-			dev_priv->display.disable_fbc(dev);
+		I915_WRITE(reg, temp);
+	}
 
-		/* disable cpu pipe, disable after all planes disabled */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+	/* enable PCH transcoder */
+	reg = TRANSCONF(pipe);
+	temp = I915_READ(reg);
+	/*
+	 * make the BPC in transcoder be consistent with
+	 * that in pipeconf reg.
+	 */
+	temp &= ~PIPE_BPC_MASK;
+	temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+	I915_WRITE(reg, temp | TRANS_ENABLE);
+	if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+		DRM_ERROR("failed to enable transcoder %d\n", pipe);
 
-			/* wait for cpu pipe off, pipe state */
-			if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
-				DRM_ERROR("failed to turn off cpu pipe\n");
-		} else
-			DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+	intel_crtc_load_lut(crtc);
+	intel_update_fbc(dev);
+	intel_crtc_update_cursor(crtc, true);
+}
 
-		udelay(100);
+static void ironlake_crtc_disable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
+	u32 reg, temp;
 
-		/* Disable PF */
-		I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
-		I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+	if (!intel_crtc->active)
+		return;
 
-		/* disable CPU FDI tx and PCH FDI rx */
-		temp = I915_READ(fdi_tx_reg);
-		I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
-		I915_READ(fdi_tx_reg);
+	intel_crtc_wait_for_pending_flips(crtc);
+	drm_vblank_off(dev, pipe);
+	intel_crtc_update_cursor(crtc, false);
 
-		temp = I915_READ(fdi_rx_reg);
-		/* BPC in FDI rx is consistent with that in pipeconf */
-		temp &= ~(0x07 << 16);
-		temp |= (pipe_bpc << 11);
-		I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
-		I915_READ(fdi_rx_reg);
+	/* Disable display plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if (temp & DISPLAY_PLANE_ENABLE) {
+		I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
 
-		udelay(100);
+	if (dev_priv->cfb_plane == plane &&
+	    dev_priv->display.disable_fbc)
+		dev_priv->display.disable_fbc(dev);
 
-		/* still set train pattern 1 */
-		temp = I915_READ(fdi_tx_reg);
+	/* disable cpu pipe, disable after all planes disabled */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if (temp & PIPECONF_ENABLE) {
+		I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+		POSTING_READ(reg);
+		/* wait for cpu pipe off, pipe state */
+		intel_wait_for_pipe_off(dev, intel_crtc->pipe);
+	}
+
+	/* Disable PF */
+	I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+	I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+	/* disable CPU FDI tx and PCH FDI rx */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+	POSTING_READ(reg);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~(0x7 << 16);
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
+	udelay(100);
+
+	/* Ironlake workaround, disable clock pointer after downing FDI */
+	if (HAS_PCH_IBX(dev))
+		I915_WRITE(FDI_RX_CHICKEN(pipe),
+			   I915_READ(FDI_RX_CHICKEN(pipe) &
+				     ~FDI_RX_PHASE_SYNC_POINTER_ENABLE));
+
+	/* still set train pattern 1 */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	I915_WRITE(reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	} else {
 		temp &= ~FDI_LINK_TRAIN_NONE;
 		temp |= FDI_LINK_TRAIN_PATTERN_1;
-		I915_WRITE(fdi_tx_reg, temp);
-		POSTING_READ(fdi_tx_reg);
-
-		temp = I915_READ(fdi_rx_reg);
-		if (HAS_PCH_CPT(dev)) {
-			temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-			temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-		} else {
-			temp &= ~FDI_LINK_TRAIN_NONE;
-			temp |= FDI_LINK_TRAIN_PATTERN_1;
-		}
-		I915_WRITE(fdi_rx_reg, temp);
-		POSTING_READ(fdi_rx_reg);
+	}
+	/* BPC in FDI rx is consistent with that in PIPECONF */
+	temp &= ~(0x07 << 16);
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp);
 
-		udelay(100);
+	POSTING_READ(reg);
+	udelay(100);
 
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-			temp = I915_READ(PCH_LVDS);
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+		temp = I915_READ(PCH_LVDS);
+		if (temp & LVDS_PORT_EN) {
 			I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-			I915_READ(PCH_LVDS);
+			POSTING_READ(PCH_LVDS);
 			udelay(100);
 		}
+	}
 
-		/* disable PCH transcoder */
-		temp = I915_READ(transconf_reg);
-		if ((temp & TRANS_ENABLE) != 0) {
-			I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
+	/* disable PCH transcoder */
+	reg = TRANSCONF(plane);
+	temp = I915_READ(reg);
+	if (temp & TRANS_ENABLE) {
+		I915_WRITE(reg, temp & ~TRANS_ENABLE);
+		/* wait for PCH transcoder off, transcoder state */
+		if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+			DRM_ERROR("failed to disable transcoder\n");
+	}
 
-			/* wait for PCH transcoder off, transcoder state */
-			if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
-				DRM_ERROR("failed to disable transcoder\n");
-		}
+	if (HAS_PCH_CPT(dev)) {
+		/* disable TRANS_DP_CTL */
+		reg = TRANS_DP_CTL(pipe);
+		temp = I915_READ(reg);
+		temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+		I915_WRITE(reg, temp);
 
-		temp = I915_READ(transconf_reg);
-		/* BPC in transcoder is consistent with that in pipeconf */
-		temp &= ~PIPE_BPC_MASK;
-		temp |= pipe_bpc;
-		I915_WRITE(transconf_reg, temp);
-		I915_READ(transconf_reg);
-		udelay(100);
+		/* disable DPLL_SEL */
+		temp = I915_READ(PCH_DPLL_SEL);
+		if (pipe == 0)
+			temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+		else
+			temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+		I915_WRITE(PCH_DPLL_SEL, temp);
+	}
 
-		if (HAS_PCH_CPT(dev)) {
-			/* disable TRANS_DP_CTL */
-			int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-			int reg;
+	/* disable PCH DPLL */
+	reg = PCH_DPLL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-			reg = I915_READ(trans_dp_ctl);
-			reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
-			I915_WRITE(trans_dp_ctl, reg);
-			POSTING_READ(trans_dp_ctl);
+	/* Switch from PCDclk to Rawclk */
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_PCDCLK);
 
-			/* disable DPLL_SEL */
-			temp = I915_READ(PCH_DPLL_SEL);
-			if (trans_dpll_sel == 0)
-				temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
-			else
-				temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-			I915_WRITE(PCH_DPLL_SEL, temp);
-			I915_READ(PCH_DPLL_SEL);
+	/* Disable CPU FDI TX PLL */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
 
-		}
+	POSTING_READ(reg);
+	udelay(100);
 
-		/* disable PCH DPLL */
-		temp = I915_READ(pch_dpll_reg);
-		I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-		I915_READ(pch_dpll_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
 
-		/* Switch from PCDclk to Rawclk */
-		temp = I915_READ(fdi_rx_reg);
-		temp &= ~FDI_SEL_PCDCLK;
-		I915_WRITE(fdi_rx_reg, temp);
-		I915_READ(fdi_rx_reg);
+	/* Wait for the clocks to turn off. */
+	POSTING_READ(reg);
+	udelay(100);
 
-		/* Disable CPU FDI TX PLL */
-		temp = I915_READ(fdi_tx_reg);
-		I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-		I915_READ(fdi_tx_reg);
-		udelay(100);
+	intel_crtc->active = false;
+	intel_update_watermarks(dev);
+	intel_update_fbc(dev);
+	intel_clear_scanline_wait(dev);
+}
 
-		temp = I915_READ(fdi_rx_reg);
-		temp &= ~FDI_RX_PLL_ENABLE;
-		I915_WRITE(fdi_rx_reg, temp);
-		I915_READ(fdi_rx_reg);
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
 
-		/* Wait for the clocks to turn off. */
-		udelay(100);
+	/* XXX: When our outputs are all unaware of DPMS modes other than off
+	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+	 */
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+		DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
+		ironlake_crtc_enable(crtc);
+		break;
+
+	case DRM_MODE_DPMS_OFF:
+		DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
+		ironlake_crtc_disable(crtc);
 		break;
 	}
 }
 
 static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 {
-	struct intel_overlay *overlay;
-	int ret;
-
 	if (!enable && intel_crtc->overlay) {
-		overlay = intel_crtc->overlay;
-		mutex_lock(&overlay->dev->struct_mutex);
-		for (;;) {
-			ret = intel_overlay_switch_off(overlay);
-			if (ret == 0)
-				break;
+		struct drm_device *dev = intel_crtc->base.dev;
 
-			ret = intel_overlay_recover_from_interrupt(overlay, 0);
-			if (ret != 0) {
-				/* overlay doesn't react anymore. Usually
-				 * results in a black screen and an unkillable
-				 * X server. */
-				BUG();
-				overlay->hw_wedged = HW_WEDGED;
-				break;
-			}
-		}
-		mutex_unlock(&overlay->dev->struct_mutex);
+		mutex_lock(&dev->struct_mutex);
+		(void) intel_overlay_switch_off(intel_crtc->overlay, false);
+		mutex_unlock(&dev->struct_mutex);
 	}
-	/* Let userspace switch the overlay on again. In most cases userspace
-	 * has to recompute where to put it anyway. */
 
-	return;
+	/* Let userspace switch the overlay on again. In most cases userspace
+	 * has to recompute where to put it anyway.
+	 */
 }
 
-static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void i9xx_crtc_enable(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
-	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	u32 temp;
+	u32 reg, temp;
 
-	/* XXX: When our outputs are all unaware of DPMS modes other than off
-	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
-	 */
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-		/* Enable the DPLL */
-		temp = I915_READ(dpll_reg);
-		if ((temp & DPLL_VCO_ENABLE) == 0) {
-			I915_WRITE(dpll_reg, temp);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-		}
+	if (intel_crtc->active)
+		return;
 
-		/* Enable the pipe */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) == 0)
-			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+	intel_crtc->active = true;
+	intel_update_watermarks(dev);
 
-		/* Enable the plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-		}
+	/* Enable the DPLL */
+	reg = DPLL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & DPLL_VCO_ENABLE) == 0) {
+		I915_WRITE(reg, temp);
 
-		intel_crtc_load_lut(crtc);
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
 
-		if ((IS_I965G(dev) || plane == 0))
-			intel_update_fbc(crtc, &crtc->mode);
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 
-		/* Give the overlay scaler a chance to enable if it's on this pipe */
-		intel_crtc_dpms_overlay(intel_crtc, true);
-	break;
-	case DRM_MODE_DPMS_OFF:
-		/* Give the overlay scaler a chance to disable if it's on this pipe */
-		intel_crtc_dpms_overlay(intel_crtc, false);
-		drm_vblank_off(dev, pipe);
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
 
-		if (dev_priv->cfb_plane == plane &&
-		    dev_priv->display.disable_fbc)
-			dev_priv->display.disable_fbc(dev);
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
 
-		/* Disable display plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-			I915_READ(dspbase_reg);
-		}
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
+	}
 
-		/* Don't disable pipe A or pipe A PLLs if needed */
-		if (pipeconf_reg == PIPEACONF &&
-		    (dev_priv->quirks & QUIRK_PIPEA_FORCE)) {
-			/* Wait for vblank for the disable to take effect */
+	/* Enable the pipe */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if ((temp & PIPECONF_ENABLE) == 0)
+		I915_WRITE(reg, temp | PIPECONF_ENABLE);
+
+	/* Enable the plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
+
+	intel_crtc_load_lut(crtc);
+	intel_update_fbc(dev);
+
+	/* Give the overlay scaler a chance to enable if it's on this pipe */
+	intel_crtc_dpms_overlay(intel_crtc, true);
+	intel_crtc_update_cursor(crtc, true);
+}
+
+static void i9xx_crtc_disable(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
+	u32 reg, temp;
+
+	if (!intel_crtc->active)
+		return;
+
+	/* Give the overlay scaler a chance to disable if it's on this pipe */
+	intel_crtc_wait_for_pending_flips(crtc);
+	drm_vblank_off(dev, pipe);
+	intel_crtc_dpms_overlay(intel_crtc, false);
+	intel_crtc_update_cursor(crtc, false);
+
+	if (dev_priv->cfb_plane == plane &&
+	    dev_priv->display.disable_fbc)
+		dev_priv->display.disable_fbc(dev);
+
+	/* Disable display plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if (temp & DISPLAY_PLANE_ENABLE) {
+		I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+		/* Flush the plane changes */
+		intel_flush_display_plane(dev, plane);
+
+		/* Wait for vblank for the disable to take effect */
+		if (IS_GEN2(dev))
 			intel_wait_for_vblank(dev, pipe);
-			goto skip_pipe_off;
-		}
+	}
 
-		/* Next, disable display pipes */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-			I915_READ(pipeconf_reg);
-		}
+	/* Don't disable pipe A or pipe A PLLs if needed */
+	if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+		goto done;
+
+	/* Next, disable display pipes */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if (temp & PIPECONF_ENABLE) {
+		I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
 
 		/* Wait for the pipe to turn off */
+		POSTING_READ(reg);
 		intel_wait_for_pipe_off(dev, pipe);
+	}
+
+	reg = DPLL(pipe);
+	temp = I915_READ(reg);
+	if (temp & DPLL_VCO_ENABLE) {
+		I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
 
-		temp = I915_READ(dpll_reg);
-		if ((temp & DPLL_VCO_ENABLE) != 0) {
-			I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-		}
-	skip_pipe_off:
 		/* Wait for the clocks to turn off. */
+		POSTING_READ(reg);
 		udelay(150);
+	}
+
+done:
+	intel_crtc->active = false;
+	intel_update_fbc(dev);
+	intel_update_watermarks(dev);
+	intel_clear_scanline_wait(dev);
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	/* XXX: When our outputs are all unaware of DPMS modes other than off
+	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
+	 */
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+		i9xx_crtc_enable(crtc);
+		break;
+	case DRM_MODE_DPMS_OFF:
+		i9xx_crtc_disable(crtc);
 		break;
 	}
 }
@@ -2388,26 +2521,9 @@
 		return;
 
 	intel_crtc->dpms_mode = mode;
-	intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
-	/* When switching on the display, ensure that SR is disabled
-	 * with multiple pipes prior to enabling to new pipe.
-	 *
-	 * When switching off the display, make sure the cursor is
-	 * properly hidden prior to disabling the pipe.
-	 */
-	if (mode == DRM_MODE_DPMS_ON)
-		intel_update_watermarks(dev);
-	else
-		intel_crtc_update_cursor(crtc);
 
 	dev_priv->display.dpms(crtc, mode);
 
-	if (mode == DRM_MODE_DPMS_ON)
-		intel_crtc_update_cursor(crtc);
-	else
-		intel_update_watermarks(dev);
-
 	if (!dev->primary->master)
 		return;
 
@@ -2432,16 +2548,46 @@
 	}
 }
 
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+static void intel_crtc_disable(struct drm_crtc *crtc)
 {
 	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	struct drm_device *dev = crtc->dev;
+
 	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	if (crtc->fb) {
+		mutex_lock(&dev->struct_mutex);
+		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+		mutex_unlock(&dev->struct_mutex);
+	}
 }
 
-static void intel_crtc_commit (struct drm_crtc *crtc)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here.  We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
 {
-	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+	i9xx_crtc_disable(crtc);
+}
+
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
+{
+	i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+	ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+	ironlake_crtc_enable(crtc);
 }
 
 void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2460,13 +2606,7 @@
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-	if (intel_encoder->ddc_bus)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
-
-	if (intel_encoder->i2c_bus)
-		intel_i2c_destroy(intel_encoder->i2c_bus);
+	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
 	drm_encoder_cleanup(encoder);
 	kfree(intel_encoder);
@@ -2557,33 +2697,6 @@
 	return 133000;
 }
 
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-int intel_panel_fitter_pipe (struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32  pfit_control;
-
-	/* i830 doesn't have a panel fitter */
-	if (IS_I830(dev))
-		return -1;
-
-	pfit_control = I915_READ(PFIT_CONTROL);
-
-	/* See if the panel fitter is in use */
-	if ((pfit_control & PFIT_ENABLE) == 0)
-		return -1;
-
-	/* 965 can place panel fitter on either pipe */
-	if (IS_I965G(dev))
-		return (pfit_control >> 29) & 0x3;
-
-	/* older chips can only use pipe 1 */
-	return 1;
-}
-
 struct fdi_m_n {
 	u32        tu;
 	u32        gmch_m;
@@ -2601,27 +2714,19 @@
 	}
 }
 
-#define DATA_N 0x800000
-#define LINK_N 0x80000
-
 static void
 ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
 		     int link_clock, struct fdi_m_n *m_n)
 {
-	u64 temp;
-
 	m_n->tu = 64; /* default size */
 
-	temp = (u64) DATA_N * pixel_clock;
-	temp = div_u64(temp, link_clock);
-	m_n->gmch_m = div_u64(temp * bits_per_pixel, nlanes);
-	m_n->gmch_m >>= 3; /* convert to bytes_per_pixel */
-	m_n->gmch_n = DATA_N;
+	/* BUG_ON(pixel_clock > INT_MAX / 36); */
+	m_n->gmch_m = bits_per_pixel * pixel_clock;
+	m_n->gmch_n = link_clock * nlanes * 8;
 	fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
 
-	temp = (u64) LINK_N * pixel_clock;
-	m_n->link_m = div_u64(temp, link_clock);
-	m_n->link_n = LINK_N;
+	m_n->link_m = pixel_clock;
+	m_n->link_n = link_clock;
 	fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
@@ -2902,7 +3007,7 @@
 		size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
@@ -2919,7 +3024,7 @@
 	size >>= 1; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
@@ -2934,8 +3039,8 @@
 	size >>= 2; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A",
-		  size);
+		      plane ? "B" : "A",
+		      size);
 
 	return size;
 }
@@ -2950,14 +3055,14 @@
 	size >>= 1; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
 
 static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
-			  int planeb_clock, int sr_hdisplay, int unused,
-			  int pixel_size)
+			       int planeb_clock, int sr_hdisplay, int unused,
+			       int pixel_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	const struct cxsr_latency *latency;
@@ -3069,13 +3174,13 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 
 		entries_required = (((sr_latency_ns / line_time_us) +
 				     1000) / 1000) * pixel_size * 64;
 		entries_required = DIV_ROUND_UP(entries_required,
-					   g4x_cursor_wm_info.cacheline_size);
+						g4x_cursor_wm_info.cacheline_size);
 		cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 
 		if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3087,7 +3192,7 @@
 	} else {
 		/* Turn off self refresh if both pipes are enabled */
 		I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-					& ~FW_BLC_SELF_EN);
+			   & ~FW_BLC_SELF_EN);
 	}
 
 	DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3125,7 +3230,7 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
 		DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
 		srwm = I965_FIFO_SIZE - sr_entries;
@@ -3134,11 +3239,11 @@
 		srwm &= 0x1ff;
 
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			     pixel_size * 64;
+			pixel_size * 64;
 		sr_entries = DIV_ROUND_UP(sr_entries,
 					  i965_cursor_wm_info.cacheline_size);
 		cursor_sr = i965_cursor_wm_info.fifo_size -
-			    (sr_entries + i965_cursor_wm_info.guard_size);
+			(sr_entries + i965_cursor_wm_info.guard_size);
 
 		if (cursor_sr > i965_cursor_wm_info.max_wm)
 			cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3146,11 +3251,11 @@
 		DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
 			      "cursor %d\n", srwm, cursor_sr);
 
-		if (IS_I965GM(dev))
+		if (IS_CRESTLINE(dev))
 			I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 	} else {
 		/* Turn off self refresh if both pipes are enabled */
-		if (IS_I965GM(dev))
+		if (IS_CRESTLINE(dev))
 			I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
 				   & ~FW_BLC_SELF_EN);
 	}
@@ -3180,9 +3285,9 @@
 	int sr_clock, sr_entries = 0;
 
 	/* Create copies of the base settings for each pipe */
-	if (IS_I965GM(dev) || IS_I945GM(dev))
+	if (IS_CRESTLINE(dev) || IS_I945GM(dev))
 		planea_params = planeb_params = i945_wm_info;
-	else if (IS_I9XX(dev))
+	else if (!IS_GEN2(dev))
 		planea_params = planeb_params = i915_wm_info;
 	else
 		planea_params = planeb_params = i855_wm_info;
@@ -3217,7 +3322,7 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 		DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
 		srwm = total_size - sr_entries;
@@ -3242,7 +3347,7 @@
 	}
 
 	DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-		  planea_wm, planeb_wm, cwm, srwm);
+		      planea_wm, planeb_wm, cwm, srwm);
 
 	fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
 	fwater_hi = (cwm & 0x1f);
@@ -3276,146 +3381,130 @@
 #define ILK_LP0_PLANE_LATENCY		700
 #define ILK_LP0_CURSOR_LATENCY		1300
 
-static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
-		       int planeb_clock, int sr_hdisplay, int sr_htotal,
-		       int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+				 int pipe,
+				 int *plane_wm,
+				 int *cursor_wm)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-	int sr_wm, cursor_wm;
-	unsigned long line_time_us;
-	int sr_clock, entries_required;
-	u32 reg_value;
-	int line_count;
-	int planea_htotal = 0, planeb_htotal = 0;
 	struct drm_crtc *crtc;
+	int htotal, hdisplay, clock, pixel_size = 0;
+	int line_time_us, line_count, entries;
 
-	/* Need htotal for all active display plane */
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
-			if (intel_crtc->plane == 0)
-				planea_htotal = crtc->mode.htotal;
-			else
-				planeb_htotal = crtc->mode.htotal;
-		}
-	}
+	crtc = intel_get_crtc_for_pipe(dev, pipe);
+	if (crtc->fb == NULL || !crtc->enabled)
+		return false;
 
-	/* Calculate and update the watermark for plane A */
-	if (planea_clock) {
-		entries_required = ((planea_clock / 1000) * pixel_size *
-				     ILK_LP0_PLANE_LATENCY) / 1000;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_wm_info.cacheline_size);
-		planea_wm = entries_required +
-			    ironlake_display_wm_info.guard_size;
+	htotal = crtc->mode.htotal;
+	hdisplay = crtc->mode.hdisplay;
+	clock = crtc->mode.clock;
+	pixel_size = crtc->fb->bits_per_pixel / 8;
 
-		if (planea_wm > (int)ironlake_display_wm_info.max_wm)
-			planea_wm = ironlake_display_wm_info.max_wm;
+	/* Use the small buffer method to calculate plane watermark */
+	entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+	entries = DIV_ROUND_UP(entries,
+			       ironlake_display_wm_info.cacheline_size);
+	*plane_wm = entries + ironlake_display_wm_info.guard_size;
+	if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+		*plane_wm = ironlake_display_wm_info.max_wm;
 
-		/* Use the large buffer method to calculate cursor watermark */
-		line_time_us = (planea_htotal * 1000) / planea_clock;
+	/* Use the large buffer method to calculate cursor watermark */
+	line_time_us = ((htotal * 1000) / clock);
+	line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+	entries = line_count * 64 * pixel_size;
+	entries = DIV_ROUND_UP(entries,
+			       ironlake_cursor_wm_info.cacheline_size);
+	*cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+	if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+		*cursor_wm = ironlake_cursor_wm_info.max_wm;
 
-		/* Use ns/us then divide to preserve precision */
-		line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+	return true;
+}
 
-		/* calculate the cursor watermark for cursor A */
-		entries_required = line_count * 64 * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_wm_info.cacheline_size);
-		cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-		if (cursora_wm > ironlake_cursor_wm_info.max_wm)
-			cursora_wm = ironlake_cursor_wm_info.max_wm;
+static void ironlake_update_wm(struct drm_device *dev,
+			       int planea_clock, int planeb_clock,
+			       int sr_hdisplay, int sr_htotal,
+			       int pixel_size)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int plane_wm, cursor_wm, enabled;
+	int tmp;
 
-		reg_value = I915_READ(WM0_PIPEA_ILK);
-		reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-		reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
-			     (cursora_wm & WM0_PIPE_CURSOR_MASK);
-		I915_WRITE(WM0_PIPEA_ILK, reg_value);
-		DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
-				"cursor: %d\n", planea_wm, cursora_wm);
+	enabled = 0;
+	if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+		I915_WRITE(WM0_PIPEA_ILK,
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+			      " plane %d, " "cursor: %d\n",
+			      plane_wm, cursor_wm);
+		enabled++;
 	}
-	/* Calculate and update the watermark for plane B */
-	if (planeb_clock) {
-		entries_required = ((planeb_clock / 1000) * pixel_size *
-				     ILK_LP0_PLANE_LATENCY) / 1000;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_wm_info.cacheline_size);
-		planeb_wm = entries_required +
-			    ironlake_display_wm_info.guard_size;
-
-		if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
-			planeb_wm = ironlake_display_wm_info.max_wm;
 
-		/* Use the large buffer method to calculate cursor watermark */
-		line_time_us = (planeb_htotal * 1000) / planeb_clock;
-
-		/* Use ns/us then divide to preserve precision */
-		line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-		/* calculate the cursor watermark for cursor B */
-		entries_required = line_count * 64 * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_wm_info.cacheline_size);
-		cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-		if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
-			cursorb_wm = ironlake_cursor_wm_info.max_wm;
-
-		reg_value = I915_READ(WM0_PIPEB_ILK);
-		reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-		reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
-			     (cursorb_wm & WM0_PIPE_CURSOR_MASK);
-		I915_WRITE(WM0_PIPEB_ILK, reg_value);
-		DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
-				"cursor: %d\n", planeb_wm, cursorb_wm);
+	if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+		I915_WRITE(WM0_PIPEB_ILK,
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+			      " plane %d, cursor: %d\n",
+			      plane_wm, cursor_wm);
+		enabled++;
 	}
 
 	/*
 	 * Calculate and update the self-refresh watermark only when one
 	 * display plane is used.
 	 */
-	if (!planea_clock || !planeb_clock) {
-
+	tmp = 0;
+	if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+		unsigned long line_time_us;
+		int small, large, plane_fbc;
+		int sr_clock, entries;
+		int line_count, line_size;
 		/* Read the self-refresh latency. The unit is 0.5us */
 		int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
 
 		sr_clock = planea_clock ? planea_clock : planeb_clock;
-		line_time_us = ((sr_htotal * 1000) / sr_clock);
+		line_time_us = (sr_htotal * 1000) / sr_clock;
 
 		/* Use ns/us then divide to preserve precision */
 		line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
-			       / 1000;
+			/ 1000;
+		line_size = sr_hdisplay * pixel_size;
 
-		/* calculate the self-refresh watermark for display plane */
-		entries_required = line_count * sr_hdisplay * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_srwm_info.cacheline_size);
-		sr_wm = entries_required +
-			ironlake_display_srwm_info.guard_size;
+		/* Use the minimum of the small and large buffer method for primary */
+		small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+		large = line_count * line_size;
 
-		/* calculate the self-refresh watermark for display cursor */
-		entries_required = line_count * pixel_size * 64;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_srwm_info.cacheline_size);
-		cursor_wm = entries_required +
-			    ironlake_cursor_srwm_info.guard_size;
+		entries = DIV_ROUND_UP(min(small, large),
+				       ironlake_display_srwm_info.cacheline_size);
 
-		/* configure watermark and enable self-refresh */
-		reg_value = I915_READ(WM1_LP_ILK);
-		reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
-			       WM1_LP_CURSOR_MASK);
-		reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
-			     (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
+		plane_fbc = entries * 64;
+		plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
 
-		I915_WRITE(WM1_LP_ILK, reg_value);
-		DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
-				"cursor %d\n", sr_wm, cursor_wm);
+		plane_wm = entries + ironlake_display_srwm_info.guard_size;
+		if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+			plane_wm = ironlake_display_srwm_info.max_wm;
 
-	} else {
-		/* Turn off self refresh if both pipes are enabled */
-		I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
+		/* calculate the self-refresh watermark for display cursor */
+		entries = line_count * pixel_size * 64;
+		entries = DIV_ROUND_UP(entries,
+				       ironlake_cursor_srwm_info.cacheline_size);
+
+		cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+		if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+			cursor_wm = ironlake_cursor_srwm_info.max_wm;
+
+		/* configure watermark and enable self-refresh */
+		tmp = (WM1_LP_SR_EN |
+		       (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+		       (plane_fbc << WM1_LP_FBC_SHIFT) |
+		       (plane_wm << WM1_LP_SR_SHIFT) |
+		       cursor_wm);
+		DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+			      " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
 	}
+	I915_WRITE(WM1_LP_ILK, tmp);
+	/* XXX setup WM2 and WM3 */
 }
+
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -3447,7 +3536,7 @@
  *
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
-  */
+ */
 static void intel_update_watermarks(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3463,15 +3552,15 @@
 	/* Get the clock config from both planes */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+		if (intel_crtc->active) {
 			enabled++;
 			if (intel_crtc->plane == 0) {
 				DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
-					  intel_crtc->pipe, crtc->mode.clock);
+					      intel_crtc->pipe, crtc->mode.clock);
 				planea_clock = crtc->mode.clock;
 			} else {
 				DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
-					  intel_crtc->pipe, crtc->mode.clock);
+					      intel_crtc->pipe, crtc->mode.clock);
 				planeb_clock = crtc->mode.clock;
 			}
 			sr_hdisplay = crtc->mode.hdisplay;
@@ -3502,62 +3591,35 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
-	int fp_reg = (pipe == 0) ? FPA0 : FPB0;
-	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-	int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-	int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-	int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
-	int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
-	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+	u32 fp_reg, dpll_reg;
 	int refclk, num_connectors = 0;
 	intel_clock_t clock, reduced_clock;
-	u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+	u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
 	bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
 	bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
 	struct intel_encoder *has_edp_encoder = NULL;
 	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
 	const intel_limit_t *limit;
 	int ret;
 	struct fdi_m_n m_n = {0};
-	int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
-	int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
-	int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
-	int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
-	int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
-	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-	int lvds_reg = LVDS;
-	u32 temp;
-	int sdvo_pixel_multiply;
+	u32 reg, temp;
 	int target_clock;
 
 	drm_vblank_pre_modeset(dev, pipe);
 
-	list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-		struct intel_encoder *intel_encoder;
-
-		if (encoder->crtc != crtc)
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+		if (encoder->base.crtc != crtc)
 			continue;
 
-		intel_encoder = enc_to_intel_encoder(encoder);
-		switch (intel_encoder->type) {
+		switch (encoder->type) {
 		case INTEL_OUTPUT_LVDS:
 			is_lvds = true;
 			break;
 		case INTEL_OUTPUT_SDVO:
 		case INTEL_OUTPUT_HDMI:
 			is_sdvo = true;
-			if (intel_encoder->needs_tv_clock)
+			if (encoder->needs_tv_clock)
 				is_tv = true;
 			break;
 		case INTEL_OUTPUT_DVO:
@@ -3573,7 +3635,7 @@
 			is_dp = true;
 			break;
 		case INTEL_OUTPUT_EDP:
-			has_edp_encoder = intel_encoder;
+			has_edp_encoder = encoder;
 			break;
 		}
 
@@ -3583,15 +3645,15 @@
 	if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
 		refclk = dev_priv->lvds_ssc_freq * 1000;
 		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-					refclk / 1000);
-	} else if (IS_I9XX(dev)) {
+			      refclk / 1000);
+	} else if (!IS_GEN2(dev)) {
 		refclk = 96000;
-		if (HAS_PCH_SPLIT(dev))
+		if (HAS_PCH_SPLIT(dev) &&
+		    (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
 			refclk = 120000; /* 120Mhz refclk */
 	} else {
 		refclk = 48000;
 	}
-	
 
 	/*
 	 * Returns a set of divisors for the desired target clock with the given
@@ -3607,13 +3669,13 @@
 	}
 
 	/* Ensure that the cursor is valid for the new mode before changing... */
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	if (is_lvds && dev_priv->lvds_downclock_avail) {
 		has_reduced_clock = limit->find_pll(limit, crtc,
-							    dev_priv->lvds_downclock,
-							    refclk,
-							    &reduced_clock);
+						    dev_priv->lvds_downclock,
+						    refclk,
+						    &reduced_clock);
 		if (has_reduced_clock && (clock.p != reduced_clock.p)) {
 			/*
 			 * If the different P is found, it means that we can't
@@ -3622,7 +3684,7 @@
 			 * feature.
 			 */
 			DRM_DEBUG_KMS("Different P is found for "
-						"LVDS clock/downclock\n");
+				      "LVDS clock/downclock\n");
 			has_reduced_clock = 0;
 		}
 	}
@@ -3630,14 +3692,14 @@
 	   this mirrors vbios setting. */
 	if (is_sdvo && is_tv) {
 		if (adjusted_mode->clock >= 100000
-				&& adjusted_mode->clock < 140500) {
+		    && adjusted_mode->clock < 140500) {
 			clock.p1 = 2;
 			clock.p2 = 10;
 			clock.n = 3;
 			clock.m1 = 16;
 			clock.m2 = 8;
 		} else if (adjusted_mode->clock >= 140500
-				&& adjusted_mode->clock <= 200000) {
+			   && adjusted_mode->clock <= 200000) {
 			clock.p1 = 1;
 			clock.p2 = 10;
 			clock.n = 6;
@@ -3648,35 +3710,43 @@
 
 	/* FDI link */
 	if (HAS_PCH_SPLIT(dev)) {
+		int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
 		int lane = 0, link_bw, bpp;
-		/* eDP doesn't require FDI link, so just set DP M/N
+		/* CPU eDP doesn't require FDI link, so just set DP M/N
 		   according to current link config */
-		if (has_edp_encoder) {
+		if (has_edp_encoder && !intel_encoder_is_pch_edp(&encoder->base)) {
 			target_clock = mode->clock;
 			intel_edp_link_config(has_edp_encoder,
 					      &lane, &link_bw);
 		} else {
-			/* DP over FDI requires target mode clock
+			/* [e]DP over FDI requires target mode clock
 			   instead of link clock */
-			if (is_dp)
+			if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
 				target_clock = mode->clock;
 			else
 				target_clock = adjusted_mode->clock;
-			link_bw = 270000;
+
+			/* FDI is a binary signal running at ~2.7GHz, encoding
+			 * each output octet as 10 bits. The actual frequency
+			 * is stored as a divider into a 100MHz clock, and the
+			 * mode pixel clock is stored in units of 1KHz.
+			 * Hence the bw of each lane in terms of the mode signal
+			 * is:
+			 */
+			link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
 		}
 
 		/* determine panel color depth */
-		temp = I915_READ(pipeconf_reg);
+		temp = I915_READ(PIPECONF(pipe));
 		temp &= ~PIPE_BPC_MASK;
 		if (is_lvds) {
-			int lvds_reg = I915_READ(PCH_LVDS);
 			/* the BPC will be 6 if it is 18-bit LVDS panel */
-			if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+			if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
 				temp |= PIPE_8BPC;
 			else
 				temp |= PIPE_6BPC;
-		} else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
-			switch (dev_priv->edp_bpp/3) {
+		} else if (has_edp_encoder) {
+			switch (dev_priv->edp.bpp/3) {
 			case 8:
 				temp |= PIPE_8BPC;
 				break;
@@ -3692,8 +3762,7 @@
 			}
 		} else
 			temp |= PIPE_8BPC;
-		I915_WRITE(pipeconf_reg, temp);
-		I915_READ(pipeconf_reg);
+		I915_WRITE(PIPECONF(pipe), temp);
 
 		switch (temp & PIPE_BPC_MASK) {
 		case PIPE_8BPC:
@@ -3725,6 +3794,8 @@
 
 		intel_crtc->fdi_lanes = lane;
 
+		if (pixel_multiplier > 1)
+			link_bw *= pixel_multiplier;
 		ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
 	}
 
@@ -3738,33 +3809,39 @@
 		/* Always enable nonspread source */
 		temp &= ~DREF_NONSPREAD_SOURCE_MASK;
 		temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-		I915_WRITE(PCH_DREF_CONTROL, temp);
-		POSTING_READ(PCH_DREF_CONTROL);
-
 		temp &= ~DREF_SSC_SOURCE_MASK;
 		temp |= DREF_SSC_SOURCE_ENABLE;
 		I915_WRITE(PCH_DREF_CONTROL, temp);
-		POSTING_READ(PCH_DREF_CONTROL);
 
+		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 
 		if (has_edp_encoder) {
 			if (dev_priv->lvds_use_ssc) {
 				temp |= DREF_SSC1_ENABLE;
 				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
 
+				POSTING_READ(PCH_DREF_CONTROL);
 				udelay(200);
+			}
+			temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
-				temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
+			/* Enable CPU source on CPU attached eDP */
+			if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+				if (dev_priv->lvds_use_ssc)
+					temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+				else
+					temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
 			} else {
-				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
+				/* Enable SSC on PCH eDP if needed */
+				if (dev_priv->lvds_use_ssc) {
+					DRM_ERROR("enabling SSC on PCH\n");
+					temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+				}
 			}
+			I915_WRITE(PCH_DREF_CONTROL, temp);
+			POSTING_READ(PCH_DREF_CONTROL);
+			udelay(200);
 		}
 	}
 
@@ -3780,23 +3857,26 @@
 				reduced_clock.m2;
 	}
 
+	dpll = 0;
 	if (!HAS_PCH_SPLIT(dev))
 		dpll = DPLL_VGA_MODE_DIS;
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (is_lvds)
 			dpll |= DPLLB_MODE_LVDS;
 		else
 			dpll |= DPLLB_MODE_DAC_SERIAL;
 		if (is_sdvo) {
+			int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+			if (pixel_multiplier > 1) {
+				if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+					dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+				else if (HAS_PCH_SPLIT(dev))
+					dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+			}
 			dpll |= DPLL_DVO_HIGH_SPEED;
-			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-			if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-			else if (HAS_PCH_SPLIT(dev))
-				dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 		}
-		if (is_dp)
+		if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
 			dpll |= DPLL_DVO_HIGH_SPEED;
 
 		/* compute bitmask from p1 value */
@@ -3824,7 +3904,7 @@
 			dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
 			break;
 		}
-		if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 			dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 	} else {
 		if (is_lvds) {
@@ -3851,7 +3931,7 @@
 		dpll |= PLL_REF_INPUT_DREFCLK;
 
 	/* setup pipeconf */
-	pipeconf = I915_READ(pipeconf_reg);
+	pipeconf = I915_READ(PIPECONF(pipe));
 
 	/* Set up the display plane register */
 	dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3865,7 +3945,7 @@
 			dspcntr |= DISPPLANE_SEL_PIPE_B;
 	}
 
-	if (pipe == 0 && !IS_I965G(dev)) {
+	if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
 		/* Enable pixel doubling when the dot clock is > 90% of the (display)
 		 * core speed.
 		 *
@@ -3874,51 +3954,47 @@
 		 */
 		if (mode->clock >
 		    dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-			pipeconf |= PIPEACONF_DOUBLE_WIDE;
+			pipeconf |= PIPECONF_DOUBLE_WIDE;
 		else
-			pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+			pipeconf &= ~PIPECONF_DOUBLE_WIDE;
 	}
 
 	dspcntr |= DISPLAY_PLANE_ENABLE;
-	pipeconf |= PIPEACONF_ENABLE;
+	pipeconf |= PIPECONF_ENABLE;
 	dpll |= DPLL_VCO_ENABLE;
 
-
-	/* Disable the panel fitter if it was on our pipe */
-	if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
-		I915_WRITE(PFIT_CONTROL, 0);
-
 	DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
 	drm_mode_debug_printmodeline(mode);
 
 	/* assign to Ironlake registers */
 	if (HAS_PCH_SPLIT(dev)) {
-		fp_reg = pch_fp_reg;
-		dpll_reg = pch_dpll_reg;
+		fp_reg = PCH_FP0(pipe);
+		dpll_reg = PCH_DPLL(pipe);
+	} else {
+		fp_reg = FP0(pipe);
+		dpll_reg = DPLL(pipe);
 	}
 
-	if (!has_edp_encoder) {
+	/* PCH eDP needs FDI, but CPU eDP does not */
+	if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 		I915_WRITE(fp_reg, fp);
 		I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-		I915_READ(dpll_reg);
+
+		POSTING_READ(dpll_reg);
 		udelay(150);
 	}
 
 	/* enable transcoder DPLL */
 	if (HAS_PCH_CPT(dev)) {
 		temp = I915_READ(PCH_DPLL_SEL);
-		if (trans_dpll_sel == 0)
-			temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+		if (pipe == 0)
+			temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
 		else
-			temp |=	(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+			temp |=	TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
 		I915_WRITE(PCH_DPLL_SEL, temp);
-		I915_READ(PCH_DPLL_SEL);
-		udelay(150);
-	}
 
-	if (HAS_PCH_SPLIT(dev)) {
-		pipeconf &= ~PIPE_ENABLE_DITHER;
-		pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+		POSTING_READ(PCH_DPLL_SEL);
+		udelay(150);
 	}
 
 	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3926,58 +4002,60 @@
 	 * things on.
 	 */
 	if (is_lvds) {
-		u32 lvds;
-
+		reg = LVDS;
 		if (HAS_PCH_SPLIT(dev))
-			lvds_reg = PCH_LVDS;
+			reg = PCH_LVDS;
 
-		lvds = I915_READ(lvds_reg);
-		lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+		temp = I915_READ(reg);
+		temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
 		if (pipe == 1) {
 			if (HAS_PCH_CPT(dev))
-				lvds |= PORT_TRANS_B_SEL_CPT;
+				temp |= PORT_TRANS_B_SEL_CPT;
 			else
-				lvds |= LVDS_PIPEB_SELECT;
+				temp |= LVDS_PIPEB_SELECT;
 		} else {
 			if (HAS_PCH_CPT(dev))
-				lvds &= ~PORT_TRANS_SEL_MASK;
+				temp &= ~PORT_TRANS_SEL_MASK;
 			else
-				lvds &= ~LVDS_PIPEB_SELECT;
+				temp &= ~LVDS_PIPEB_SELECT;
 		}
 		/* set the corresponsding LVDS_BORDER bit */
-		lvds |= dev_priv->lvds_border_bits;
+		temp |= dev_priv->lvds_border_bits;
 		/* Set the B0-B3 data pairs corresponding to whether we're going to
 		 * set the DPLLs for dual-channel mode or not.
 		 */
 		if (clock.p2 == 7)
-			lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+			temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
 		else
-			lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+			temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
 		/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
 		 * appropriately here, but we need to look more thoroughly into how
 		 * panels behave in the two modes.
 		 */
-		/* set the dithering flag */
-		if (IS_I965G(dev)) {
-			if (dev_priv->lvds_dither) {
-				if (HAS_PCH_SPLIT(dev)) {
-					pipeconf |= PIPE_ENABLE_DITHER;
-					pipeconf |= PIPE_DITHER_TYPE_ST01;
-				} else
-					lvds |= LVDS_ENABLE_DITHER;
-			} else {
-				if (!HAS_PCH_SPLIT(dev)) {
-					lvds &= ~LVDS_ENABLE_DITHER;
-				}
-			}
+		/* set the dithering flag on non-PCH LVDS as needed */
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+			if (dev_priv->lvds_dither)
+				temp |= LVDS_ENABLE_DITHER;
+			else
+				temp &= ~LVDS_ENABLE_DITHER;
 		}
-		I915_WRITE(lvds_reg, lvds);
-		I915_READ(lvds_reg);
+		I915_WRITE(reg, temp);
 	}
-	if (is_dp)
+
+	/* set the dithering flag and clear for anything other than a panel. */
+	if (HAS_PCH_SPLIT(dev)) {
+		pipeconf &= ~PIPECONF_DITHER_EN;
+		pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+		if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+			pipeconf |= PIPECONF_DITHER_EN;
+			pipeconf |= PIPECONF_DITHER_TYPE_ST1;
+		}
+	}
+
+	if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 		intel_dp_set_m_n(crtc, mode, adjusted_mode);
-	else if (HAS_PCH_SPLIT(dev)) {
+	} else if (HAS_PCH_SPLIT(dev)) {
 		/* For non-DP output, clear any trans DP clock recovery setting.*/
 		if (pipe == 0) {
 			I915_WRITE(TRANSA_DATA_M1, 0);
@@ -3992,29 +4070,35 @@
 		}
 	}
 
-	if (!has_edp_encoder) {
+	if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 		I915_WRITE(fp_reg, fp);
 		I915_WRITE(dpll_reg, dpll);
-		I915_READ(dpll_reg);
+
 		/* Wait for the clocks to stabilize. */
+		POSTING_READ(dpll_reg);
 		udelay(150);
 
-		if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+			temp = 0;
 			if (is_sdvo) {
-				sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-				I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
-					((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
-			} else
-				I915_WRITE(dpll_md_reg, 0);
+				temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+				if (temp > 1)
+					temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+				else
+					temp = 0;
+			}
+			I915_WRITE(DPLL_MD(pipe), temp);
 		} else {
 			/* write it again -- the BIOS does, after all */
 			I915_WRITE(dpll_reg, dpll);
 		}
-		I915_READ(dpll_reg);
+
 		/* Wait for the clocks to stabilize. */
+		POSTING_READ(dpll_reg);
 		udelay(150);
 	}
 
+	intel_crtc->lowfreq_avail = false;
 	if (is_lvds && has_reduced_clock && i915_powersave) {
 		I915_WRITE(fp_reg + 4, fp2);
 		intel_crtc->lowfreq_avail = true;
@@ -4024,7 +4108,6 @@
 		}
 	} else {
 		I915_WRITE(fp_reg + 4, fp);
-		intel_crtc->lowfreq_avail = false;
 		if (HAS_PIPE_CXSR(dev)) {
 			DRM_DEBUG_KMS("disabling CxSR downclocking\n");
 			pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4043,70 +4126,62 @@
 	} else
 		pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
 
-	I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+	I915_WRITE(HTOTAL(pipe),
+		   (adjusted_mode->crtc_hdisplay - 1) |
 		   ((adjusted_mode->crtc_htotal - 1) << 16));
-	I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+	I915_WRITE(HBLANK(pipe),
+		   (adjusted_mode->crtc_hblank_start - 1) |
 		   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-	I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+	I915_WRITE(HSYNC(pipe),
+		   (adjusted_mode->crtc_hsync_start - 1) |
 		   ((adjusted_mode->crtc_hsync_end - 1) << 16));
-	I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+	I915_WRITE(VTOTAL(pipe),
+		   (adjusted_mode->crtc_vdisplay - 1) |
 		   ((adjusted_mode->crtc_vtotal - 1) << 16));
-	I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+	I915_WRITE(VBLANK(pipe),
+		   (adjusted_mode->crtc_vblank_start - 1) |
 		   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-	I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+	I915_WRITE(VSYNC(pipe),
+		   (adjusted_mode->crtc_vsync_start - 1) |
 		   ((adjusted_mode->crtc_vsync_end - 1) << 16));
-	/* pipesrc and dspsize control the size that is scaled from, which should
-	 * always be the user's requested size.
+
+	/* pipesrc and dspsize control the size that is scaled from,
+	 * which should always be the user's requested size.
 	 */
 	if (!HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
-				(mode->hdisplay - 1));
-		I915_WRITE(dsppos_reg, 0);
+		I915_WRITE(DSPSIZE(plane),
+			   ((mode->vdisplay - 1) << 16) |
+			   (mode->hdisplay - 1));
+		I915_WRITE(DSPPOS(plane), 0);
 	}
-	I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+	I915_WRITE(PIPESRC(pipe),
+		   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
 	if (HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
-		I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
-		I915_WRITE(link_m1_reg, m_n.link_m);
-		I915_WRITE(link_n1_reg, m_n.link_n);
+		I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+		I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+		I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+		I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
-		if (has_edp_encoder) {
+		if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
 			ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-		} else {
-			/* enable FDI RX PLL too */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
-
-			/* enable FDI TX PLL too */
-			temp = I915_READ(fdi_tx_reg);
-			I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-			I915_READ(fdi_tx_reg);
-
-			/* enable FDI RX PCDCLK */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
 		}
 	}
 
-	I915_WRITE(pipeconf_reg, pipeconf);
-	I915_READ(pipeconf_reg);
+	I915_WRITE(PIPECONF(pipe), pipeconf);
+	POSTING_READ(PIPECONF(pipe));
 
 	intel_wait_for_vblank(dev, pipe);
 
-	if (IS_IRONLAKE(dev)) {
+	if (IS_GEN5(dev)) {
 		/* enable address swizzle for tiling buffer */
 		temp = I915_READ(DISP_ARB_CTL);
 		I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
 	}
 
-	I915_WRITE(dspcntr_reg, dspcntr);
+	I915_WRITE(DSPCNTR(plane), dspcntr);
 
-	/* Flush the plane changes */
 	ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
 	intel_update_watermarks(dev);
@@ -4199,7 +4274,8 @@
 }
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+				     bool on)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4212,7 +4288,7 @@
 
 	pos = 0;
 
-	if (intel_crtc->cursor_on && crtc->fb) {
+	if (on && crtc->enabled && crtc->fb) {
 		base = intel_crtc->cursor_addr;
 		if (x > (int) crtc->fb->width)
 			base = 0;
@@ -4324,7 +4400,7 @@
 		addr = obj_priv->phys_obj->handle->busaddr;
 	}
 
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		I915_WRITE(CURSIZE, (height << 12) | width);
 
  finish:
@@ -4344,7 +4420,7 @@
 	intel_crtc->cursor_width = width;
 	intel_crtc->cursor_height = height;
 
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	return 0;
 fail_unpin:
@@ -4363,7 +4439,7 @@
 	intel_crtc->cursor_x = x;
 	intel_crtc->cursor_y = y;
 
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	return 0;
 }
@@ -4432,7 +4508,7 @@
 	struct intel_crtc *intel_crtc;
 	struct drm_crtc *possible_crtc;
 	struct drm_crtc *supported_crtc =NULL;
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_crtc *crtc = NULL;
 	struct drm_device *dev = encoder->dev;
 	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4513,7 +4589,7 @@
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
 				    struct drm_connector *connector, int dpms_mode)
 {
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4559,7 +4635,7 @@
 		clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
 	}
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (IS_PINEVIEW(dev))
 			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
 				DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
@@ -4663,8 +4739,6 @@
 	struct drm_device *dev = (struct drm_device *)arg;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
 	dev_priv->busy = false;
 
 	queue_work(dev_priv->wq, &dev_priv->idle_work);
@@ -4678,14 +4752,12 @@
 	struct drm_crtc *crtc = &intel_crtc->base;
 	drm_i915_private_t *dev_priv = crtc->dev->dev_private;
 
-	DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
 	intel_crtc->busy = false;
 
 	queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4720,9 +4792,8 @@
 	}
 
 	/* Schedule downclock */
-	if (schedule)
-		mod_timer(&intel_crtc->idle_timer, jiffies +
-			  msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+	mod_timer(&intel_crtc->idle_timer, jiffies +
+		  msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4858,7 +4929,7 @@
 					I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
 				}
 				/* Non-busy -> busy, upclock */
-				intel_increase_pllclock(crtc, true);
+				intel_increase_pllclock(crtc);
 				intel_crtc->busy = true;
 			} else {
 				/* Busy -> busy, put off timer */
@@ -4872,8 +4943,22 @@
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct intel_unpin_work *work;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	work = intel_crtc->unpin_work;
+	intel_crtc->unpin_work = NULL;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (work) {
+		cancel_work_sync(&work->work);
+		kfree(work);
+	}
 
 	drm_crtc_cleanup(crtc);
+
 	kfree(intel_crtc);
 }
 
@@ -4928,12 +5013,11 @@
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
-	obj_priv = to_intel_bo(work->pending_flip_obj);
-
-	/* Initial scanout buffer will have a 0 pending flip count */
-	if ((atomic_read(&obj_priv->pending_flip) == 0) ||
-	    atomic_dec_and_test(&obj_priv->pending_flip))
-		DRM_WAKEUP(&dev_priv->pending_flip_queue);
+	obj_priv = to_intel_bo(work->old_fb_obj);
+	atomic_clear_mask(1 << intel_crtc->plane,
+			  &obj_priv->pending_flip.counter);
+	if (atomic_read(&obj_priv->pending_flip) == 0)
+		wake_up(&dev_priv->pending_flip_queue);
 	schedule_work(&work->work);
 
 	trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5014,7 +5098,7 @@
 	obj = intel_fb->obj;
 
 	mutex_lock(&dev->struct_mutex);
-	ret = intel_pin_and_fence_fb_obj(dev, obj);
+	ret = intel_pin_and_fence_fb_obj(dev, obj, true);
 	if (ret)
 		goto cleanup_work;
 
@@ -5023,29 +5107,33 @@
 	drm_gem_object_reference(obj);
 
 	crtc->fb = fb;
-	ret = i915_gem_object_flush_write_domain(obj);
-	if (ret)
-		goto cleanup_objs;
 
 	ret = drm_vblank_get(dev, intel_crtc->pipe);
 	if (ret)
 		goto cleanup_objs;
 
-	obj_priv = to_intel_bo(obj);
-	atomic_inc(&obj_priv->pending_flip);
+	/* Block clients from rendering to the new back buffer until
+	 * the flip occurs and the object is no longer visible.
+	 */
+	atomic_add(1 << intel_crtc->plane,
+		   &to_intel_bo(work->old_fb_obj)->pending_flip);
+
 	work->pending_flip_obj = obj;
+	obj_priv = to_intel_bo(obj);
 
 	if (IS_GEN3(dev) || IS_GEN2(dev)) {
 		u32 flip_mask;
 
+		/* Can't queue multiple flips, so wait for the previous
+		 * one to finish before executing the next.
+		 */
+		BEGIN_LP_RING(2);
 		if (intel_crtc->plane)
 			flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
 		else
 			flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
-		BEGIN_LP_RING(2);
 		OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
-		OUT_RING(0);
+		OUT_RING(MI_NOOP);
 		ADVANCE_LP_RING();
 	}
 
@@ -5126,15 +5214,14 @@
 	return ret;
 }
 
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.dpms = intel_crtc_dpms,
 	.mode_fixup = intel_crtc_mode_fixup,
 	.mode_set = intel_crtc_mode_set,
 	.mode_set_base = intel_pipe_set_base,
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
-	.prepare = intel_crtc_prepare,
-	.commit = intel_crtc_commit,
 	.load_lut = intel_crtc_load_lut,
+	.disable = intel_crtc_disable,
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -5146,6 +5233,55 @@
 	.page_flip = intel_crtc_page_flip,
 };
 
+static void intel_sanitize_modesetting(struct drm_device *dev,
+				       int pipe, int plane)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 reg, val;
+
+	if (HAS_PCH_SPLIT(dev))
+		return;
+
+	/* Who knows what state these registers were left in by the BIOS or
+	 * grub?
+	 *
+	 * If we leave the registers in a conflicting state (e.g. with the
+	 * display plane reading from the other pipe than the one we intend
+	 * to use) then when we attempt to teardown the active mode, we will
+	 * not disable the pipes and planes in the correct order -- leaving
+	 * a plane reading from a disabled pipe and possibly leading to
+	 * undefined behaviour.
+	 */
+
+	reg = DSPCNTR(plane);
+	val = I915_READ(reg);
+
+	if ((val & DISPLAY_PLANE_ENABLE) == 0)
+		return;
+	if (!!(val & DISPPLANE_SEL_PIPE_MASK) == pipe)
+		return;
+
+	/* This display plane is active and attached to the other CPU pipe. */
+	pipe = !pipe;
+
+	/* Disable the plane and wait for it to stop reading from the pipe. */
+	I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
+	intel_flush_display_plane(dev, plane);
+
+	if (IS_GEN2(dev))
+		intel_wait_for_vblank(dev, pipe);
+
+	if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+		return;
+
+	/* Switch off the pipe. */
+	reg = PIPECONF(pipe);
+	val = I915_READ(reg);
+	if (val & PIPECONF_ENABLE) {
+		I915_WRITE(reg, val & ~PIPECONF_ENABLE);
+		intel_wait_for_pipe_off(dev, pipe);
+	}
+}
 
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
@@ -5160,8 +5296,6 @@
 	drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-	intel_crtc->pipe = pipe;
-	intel_crtc->plane = pipe;
 	for (i = 0; i < 256; i++) {
 		intel_crtc->lut_r[i] = i;
 		intel_crtc->lut_g[i] = i;
@@ -5171,9 +5305,9 @@
 	/* Swap pipes & planes for FBC on pre-965 */
 	intel_crtc->pipe = pipe;
 	intel_crtc->plane = pipe;
-	if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+	if (IS_MOBILE(dev) && IS_GEN3(dev)) {
 		DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-		intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+		intel_crtc->plane = !pipe;
 	}
 
 	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5183,12 +5317,24 @@
 
 	intel_crtc->cursor_addr = 0;
 	intel_crtc->dpms_mode = -1;
+	intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+	if (HAS_PCH_SPLIT(dev)) {
+		intel_helper_funcs.prepare = ironlake_crtc_prepare;
+		intel_helper_funcs.commit = ironlake_crtc_commit;
+	} else {
+		intel_helper_funcs.prepare = i9xx_crtc_prepare;
+		intel_helper_funcs.commit = i9xx_crtc_commit;
+	}
+
 	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
 	intel_crtc->busy = false;
 
 	setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
 		    (unsigned long)intel_crtc);
+
+	intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane);
 }
 
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
@@ -5218,47 +5364,56 @@
 	return 0;
 }
 
-struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
-{
-	struct drm_crtc *crtc = NULL;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->pipe == pipe)
-			break;
-	}
-	return crtc;
-}
-
 static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
+	struct intel_encoder *encoder;
 	int index_mask = 0;
-	struct drm_encoder *encoder;
 	int entry = 0;
 
-        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-		if (type_mask & intel_encoder->clone_mask)
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+		if (type_mask & encoder->clone_mask)
 			index_mask |= (1 << entry);
 		entry++;
 	}
+
 	return index_mask;
 }
 
+static bool has_edp_a(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!IS_MOBILE(dev))
+		return false;
+
+	if ((I915_READ(DP_A) & DP_DETECTED) == 0)
+		return false;
+
+	if (IS_GEN5(dev) &&
+	    (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
+		return false;
+
+	return true;
+}
 
 static void intel_setup_outputs(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
 	bool dpd_is_edp = false;
+	bool has_lvds = false;
 
 	if (IS_MOBILE(dev) && !IS_I830(dev))
-		intel_lvds_init(dev);
+		has_lvds = intel_lvds_init(dev);
+	if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
+		/* disable the panel fitter on everything but LVDS */
+		I915_WRITE(PFIT_CONTROL, 0);
+	}
 
 	if (HAS_PCH_SPLIT(dev)) {
 		dpd_is_edp = intel_dpd_is_edp(dev);
 
-		if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
+		if (has_edp_a(dev))
 			intel_dp_init(dev, DP_A);
 
 		if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
@@ -5338,12 +5493,10 @@
 	if (SUPPORTS_TV(dev))
 		intel_tv_init(dev);
 
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-		encoder->possible_crtcs = intel_encoder->crtc_mask;
-		encoder->possible_clones = intel_encoder_clones(dev,
-						intel_encoder->clone_mask);
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+		encoder->base.possible_crtcs = encoder->crtc_mask;
+		encoder->base.possible_clones =
+			intel_encoder_clones(dev, encoder->clone_mask);
 	}
 }
 
@@ -5377,8 +5530,25 @@
 			   struct drm_mode_fb_cmd *mode_cmd,
 			   struct drm_gem_object *obj)
 {
+	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret;
 
+	if (obj_priv->tiling_mode == I915_TILING_Y)
+		return -EINVAL;
+
+	if (mode_cmd->pitch & 63)
+		return -EINVAL;
+
+	switch (mode_cmd->bpp) {
+	case 8:
+	case 16:
+	case 24:
+	case 32:
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
 	if (ret) {
 		DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5487,6 +5657,10 @@
 	u32 rgvmodectl = I915_READ(MEMMODECTL);
 	u8 fmax, fmin, fstart, vstart;
 
+	/* Enable temp reporting */
+	I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+	I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
 	/* 100ms RC evaluation intervals */
 	I915_WRITE(RCUPEI, 100000);
 	I915_WRITE(RCDNEI, 100000);
@@ -5502,20 +5676,19 @@
 	fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
 	fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
 		MEMMODE_FSTART_SHIFT;
-	fstart = fmax;
 
 	vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
 		PXVFREQ_PX_SHIFT;
 
-	dev_priv->fmax = fstart; /* IPS callback will increase this */
+	dev_priv->fmax = fmax; /* IPS callback will increase this */
 	dev_priv->fstart = fstart;
 
-	dev_priv->max_delay = fmax;
+	dev_priv->max_delay = fstart;
 	dev_priv->min_delay = fmin;
 	dev_priv->cur_delay = fstart;
 
-	DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
-			 fstart);
+	DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
+			 fmax, fmin, fstart);
 
 	I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
 
@@ -5529,7 +5702,7 @@
 	rgvmodectl |= MEMMODE_SWMODE_EN;
 	I915_WRITE(MEMMODECTL, rgvmodectl);
 
-	if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
+	if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
 		DRM_ERROR("stuck trying to change perf mode\n");
 	msleep(1);
 
@@ -5660,7 +5833,7 @@
 	if (HAS_PCH_SPLIT(dev)) {
 		uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
 
-		if (IS_IRONLAKE(dev)) {
+		if (IS_GEN5(dev)) {
 			/* Required for FBC */
 			dspclk_gate |= DPFDUNIT_CLOCK_GATE_DISABLE;
 			/* Required for CxSR */
@@ -5669,18 +5842,27 @@
 			I915_WRITE(PCH_3DCGDIS0,
 				   MARIUNIT_CLOCK_GATE_DISABLE |
 				   SVSMUNIT_CLOCK_GATE_DISABLE);
+			I915_WRITE(PCH_3DCGDIS1,
+				   VFMUNIT_CLOCK_GATE_DISABLE);
 		}
 
 		I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
 		/*
+		 * On Ibex Peak and Cougar Point, we need to disable clock
+		 * gating for the panel power sequencer or it will fail to
+		 * start up when no ports are active.
+		 */
+		I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+
+		/*
 		 * According to the spec the following bits should be set in
 		 * order to enable memory self-refresh
 		 * The bit 22/21 of 0x42004
 		 * The bit 5 of 0x42020
 		 * The bit 15 of 0x45000
 		 */
-		if (IS_IRONLAKE(dev)) {
+		if (IS_GEN5(dev)) {
 			I915_WRITE(ILK_DISPLAY_CHICKEN2,
 					(I915_READ(ILK_DISPLAY_CHICKEN2) |
 					ILK_DPARB_GATE | ILK_VSDPFD_FULL));
@@ -5728,20 +5910,20 @@
 		if (IS_GM45(dev))
 			dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
 		I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-	} else if (IS_I965GM(dev)) {
+	} else if (IS_CRESTLINE(dev)) {
 		I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
 		I915_WRITE(RENCLK_GATE_D2, 0);
 		I915_WRITE(DSPCLK_GATE_D, 0);
 		I915_WRITE(RAMCLK_GATE_D, 0);
 		I915_WRITE16(DEUC, 0);
-	} else if (IS_I965G(dev)) {
+	} else if (IS_BROADWATER(dev)) {
 		I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
 		       I965_RCC_CLOCK_GATE_DISABLE |
 		       I965_RCPB_CLOCK_GATE_DISABLE |
 		       I965_ISC_CLOCK_GATE_DISABLE |
 		       I965_FBC_CLOCK_GATE_DISABLE);
 		I915_WRITE(RENCLK_GATE_D2, 0);
-	} else if (IS_I9XX(dev)) {
+	} else if (IS_GEN3(dev)) {
 		u32 dstate = I915_READ(D_STATE);
 
 		dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
@@ -5823,7 +6005,7 @@
 			dev_priv->display.fbc_enabled = g4x_fbc_enabled;
 			dev_priv->display.enable_fbc = g4x_enable_fbc;
 			dev_priv->display.disable_fbc = g4x_disable_fbc;
-		} else if (IS_I965GM(dev)) {
+		} else if (IS_CRESTLINE(dev)) {
 			dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
 			dev_priv->display.enable_fbc = i8xx_enable_fbc;
 			dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -5856,7 +6038,7 @@
 
 	/* For FIFO watermark updates */
 	if (HAS_PCH_SPLIT(dev)) {
-		if (IS_IRONLAKE(dev)) {
+		if (IS_GEN5(dev)) {
 			if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
 				dev_priv->display.update_wm = ironlake_update_wm;
 			else {
@@ -5883,9 +6065,9 @@
 			dev_priv->display.update_wm = pineview_update_wm;
 	} else if (IS_G4X(dev))
 		dev_priv->display.update_wm = g4x_update_wm;
-	else if (IS_I965G(dev))
+	else if (IS_GEN4(dev))
 		dev_priv->display.update_wm = i965_update_wm;
-	else if (IS_I9XX(dev)) {
+	else if (IS_GEN3(dev)) {
 		dev_priv->display.update_wm = i9xx_update_wm;
 		dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
 	} else if (IS_I85X(dev)) {
@@ -5999,24 +6181,24 @@
 
 	intel_init_display(dev);
 
-	if (IS_I965G(dev)) {
-		dev->mode_config.max_width = 8192;
-		dev->mode_config.max_height = 8192;
-	} else if (IS_I9XX(dev)) {
+	if (IS_GEN2(dev)) {
+		dev->mode_config.max_width = 2048;
+		dev->mode_config.max_height = 2048;
+	} else if (IS_GEN3(dev)) {
 		dev->mode_config.max_width = 4096;
 		dev->mode_config.max_height = 4096;
 	} else {
-		dev->mode_config.max_width = 2048;
-		dev->mode_config.max_height = 2048;
+		dev->mode_config.max_width = 8192;
+		dev->mode_config.max_height = 8192;
 	}
 
 	/* set memory base */
-	if (IS_I9XX(dev))
-		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
-	else
+	if (IS_GEN2(dev))
 		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+	else
+		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
 
-	if (IS_MOBILE(dev) || IS_I9XX(dev))
+	if (IS_MOBILE(dev) || !IS_GEN2(dev))
 		dev_priv->num_pipe = 2;
 	else
 		dev_priv->num_pipe = 1;
@@ -6052,10 +6234,11 @@
 	struct drm_crtc *crtc;
 	struct intel_crtc *intel_crtc;
 
+	drm_kms_helper_poll_fini(dev);
 	mutex_lock(&dev->struct_mutex);
 
-	drm_kms_helper_poll_fini(dev);
-	intel_fbdev_fini(dev);
+	intel_unregister_dsm_handler();
+
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		/* Skip inactive CRTCs */
@@ -6063,12 +6246,9 @@
 			continue;
 
 		intel_crtc = to_intel_crtc(crtc);
-		intel_increase_pllclock(crtc, false);
-		del_timer_sync(&intel_crtc->idle_timer);
+		intel_increase_pllclock(crtc);
 	}
 
-	del_timer_sync(&dev_priv->idle_timer);
-
 	if (dev_priv->display.disable_fbc)
 		dev_priv->display.disable_fbc(dev);
 
@@ -6097,33 +6277,36 @@
 
 	mutex_unlock(&dev->struct_mutex);
 
+	/* Disable the irq before mode object teardown, for the irq might
+	 * enqueue unpin/hotplug work. */
+	drm_irq_uninstall(dev);
+	cancel_work_sync(&dev_priv->hotplug_work);
+
+	/* Shut off idle work before the crtcs get freed. */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		intel_crtc = to_intel_crtc(crtc);
+		del_timer_sync(&intel_crtc->idle_timer);
+	}
+	del_timer_sync(&dev_priv->idle_timer);
+	cancel_work_sync(&dev_priv->idle_work);
+
 	drm_mode_config_cleanup(dev);
 }
 
-
 /*
  * Return which encoder is currently attached for connector.
  */
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 {
-	struct drm_mode_object *obj;
-	struct drm_encoder *encoder;
-	int i;
-
-	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-		if (connector->encoder_ids[i] == 0)
-			break;
-
-		obj = drm_mode_object_find(connector->dev,
-                                           connector->encoder_ids[i],
-                                           DRM_MODE_OBJECT_ENCODER);
-		if (!obj)
-			continue;
+	return &intel_attached_encoder(connector)->base;
+}
 
-		encoder = obj_to_encoder(obj);
-		return encoder;
-	}
-	return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+				    struct intel_encoder *encoder)
+{
+	connector->encoder = encoder;
+	drm_mode_connector_attach_encoder(&connector->base,
+					  &encoder->base);
 }
 
 /*
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_dp.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_dp.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_dp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_dp.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,15 +42,13 @@
 
 #define DP_LINK_CONFIGURATION_SIZE	9
 
-#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP)
-#define IS_PCH_eDP(i) ((i)->is_pch_edp)
-
 struct intel_dp {
 	struct intel_encoder base;
 	uint32_t output_reg;
 	uint32_t DP;
 	uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
 	bool has_audio;
+	int force_audio;
 	int dpms_mode;
 	uint8_t link_bw;
 	uint8_t lane_count;
@@ -58,14 +56,69 @@
 	struct i2c_adapter adapter;
 	struct i2c_algo_dp_aux_data algo;
 	bool is_pch_edp;
+	uint8_t	train_set[4];
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+	struct drm_property *force_audio_property;
 };
 
+/**
+ * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
+ * @intel_dp: DP struct
+ *
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
+ * will return true, and false otherwise.
+ */
+static bool is_edp(struct intel_dp *intel_dp)
+{
+	return intel_dp->base.type == INTEL_OUTPUT_EDP;
+}
+
+/**
+ * is_pch_edp - is the port on the PCH and attached to an eDP panel?
+ * @intel_dp: DP struct
+ *
+ * Returns true if the given DP struct corresponds to a PCH DP port attached
+ * to an eDP panel, false otherwise.  Helpful for determining whether we
+ * may need FDI resources for a given DP output or not.
+ */
+static bool is_pch_edp(struct intel_dp *intel_dp)
+{
+	return intel_dp->is_pch_edp;
+}
+
 static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base);
+	return container_of(encoder, struct intel_dp, base.base);
 }
 
-static void intel_dp_link_train(struct intel_dp *intel_dp);
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_dp, base);
+}
+
+/**
+ * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
+ * @encoder: DRM encoder
+ *
+ * Return true if @encoder corresponds to a PCH attached eDP panel.  Needed
+ * by intel_display.c.
+ */
+bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
+{
+	struct intel_dp *intel_dp;
+
+	if (!encoder)
+		return false;
+
+	intel_dp = enc_to_intel_dp(encoder);
+
+	return is_pch_edp(intel_dp);
+}
+
+static void intel_dp_start_link_train(struct intel_dp *intel_dp);
+static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
 
 void
@@ -129,8 +182,8 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-		return (pixel_clock * dev_priv->edp_bpp) / 8;
+	if (is_edp(intel_dp))
+		return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
 	else
 		return pixel_clock * 3;
 }
@@ -145,15 +198,13 @@
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
 	int max_lanes = intel_dp_max_lane_count(intel_dp);
 
-	if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-	    dev_priv->panel_fixed_mode) {
+	if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
 		if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
 			return MODE_PANEL;
 
@@ -163,7 +214,7 @@
 
 	/* only refuse the mode on non eDP since we have seen some wierd eDP panels
 	   which are outside spec tolerances but somehow work by magic */
-	if (!IS_eDP(intel_dp) &&
+	if (!is_edp(intel_dp) &&
 	    (intel_dp_link_required(connector->dev, intel_dp, mode->clock)
 	     > intel_dp_max_data_rate(max_link_clock, max_lanes)))
 		return MODE_CLOCK_HIGH;
@@ -233,7 +284,7 @@
 		uint8_t *recv, int recv_size)
 {
 	uint32_t output_reg = intel_dp->output_reg;
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t ch_ctl = output_reg + 0x10;
 	uint32_t ch_data = ch_ctl + 4;
@@ -246,8 +297,11 @@
 	/* The clock divider is based off the hrawclk,
 	 * and would like to run at 2MHz. So, take the
 	 * hrawclk value and divide by 2 and use that
+	 *
+	 * Note that PCH attached eDP panels should use a 125MHz input
+	 * clock divider.
 	 */
-	if (IS_eDP(intel_dp)) {
+	if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
 		if (IS_GEN6(dev))
 			aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
 		else
@@ -425,6 +479,7 @@
 	uint16_t address = algo_data->address;
 	uint8_t msg[5];
 	uint8_t reply[2];
+	unsigned retry;
 	int msg_bytes;
 	int reply_bytes;
 	int ret;
@@ -459,14 +514,33 @@
 		break;
 	}
 
-	for (;;) {
-	  ret = intel_dp_aux_ch(intel_dp,
-				msg, msg_bytes,
-				reply, reply_bytes);
+	for (retry = 0; retry < 5; retry++) {
+		ret = intel_dp_aux_ch(intel_dp,
+				      msg, msg_bytes,
+				      reply, reply_bytes);
 		if (ret < 0) {
 			DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
 			return ret;
 		}
+
+		switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
+		case AUX_NATIVE_REPLY_ACK:
+			/* I2C-over-AUX Reply field is only valid
+			 * when paired with AUX ACK.
+			 */
+			break;
+		case AUX_NATIVE_REPLY_NACK:
+			DRM_DEBUG_KMS("aux_ch native nack\n");
+			return -EREMOTEIO;
+		case AUX_NATIVE_REPLY_DEFER:
+			udelay(100);
+			continue;
+		default:
+			DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
+				  reply[0]);
+			return -EREMOTEIO;
+		}
+
 		switch (reply[0] & AUX_I2C_REPLY_MASK) {
 		case AUX_I2C_REPLY_ACK:
 			if (mode == MODE_I2C_READ) {
@@ -474,17 +548,20 @@
 			}
 			return reply_bytes - 1;
 		case AUX_I2C_REPLY_NACK:
-			DRM_DEBUG_KMS("aux_ch nack\n");
+			DRM_DEBUG_KMS("aux_i2c nack\n");
 			return -EREMOTEIO;
 		case AUX_I2C_REPLY_DEFER:
-			DRM_DEBUG_KMS("aux_ch defer\n");
+			DRM_DEBUG_KMS("aux_i2c defer\n");
 			udelay(100);
 			break;
 		default:
-			DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
+			DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
 			return -EREMOTEIO;
 		}
 	}
+
+	DRM_ERROR("too many retries, giving up\n");
+	return -EREMOTEIO;
 }
 
 static int
@@ -519,8 +596,7 @@
 	int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
 	static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
 
-	if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-	    dev_priv->panel_fixed_mode) {
+	if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
 		intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
 		intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
 					mode, adjusted_mode);
@@ -549,7 +625,7 @@
 		}
 	}
 
-	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+	if (is_edp(intel_dp)) {
 		/* okay we failed just pick the highest */
 		intel_dp->lane_count = max_lane_count;
 		intel_dp->link_bw = bws[max_clock];
@@ -598,25 +674,6 @@
 	intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
 }
 
-bool intel_pch_has_edp(struct drm_crtc *crtc)
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_encoder *encoder;
-
-	list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-		struct intel_dp *intel_dp;
-
-		if (encoder->crtc != crtc)
-			continue;
-
-		intel_dp = enc_to_intel_dp(encoder);
-		if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
-			return intel_dp->is_pch_edp;
-	}
-	return false;
-}
-
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		 struct drm_display_mode *adjusted_mode)
@@ -641,8 +698,10 @@
 		intel_dp = enc_to_intel_dp(encoder);
 		if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
 			lane_count = intel_dp->lane_count;
-			if (IS_PCH_eDP(intel_dp))
-				bpp = dev_priv->edp_bpp;
+			break;
+		} else if (is_edp(intel_dp)) {
+			lane_count = dev_priv->edp.lanes;
+			bpp = dev_priv->edp.bpp;
 			break;
 		}
 	}
@@ -698,7 +757,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_crtc *crtc = intel_dp->base.enc.crtc;
+	struct drm_crtc *crtc = intel_dp->base.base.crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
 	intel_dp->DP = (DP_VOLTAGE_0_4 |
@@ -709,7 +768,7 @@
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
 		intel_dp->DP |= DP_SYNC_VS_HIGH;
 
-	if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+	if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
 		intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
 	else
 		intel_dp->DP |= DP_LINK_TRAIN_OFF;
@@ -744,7 +803,7 @@
 	if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
 		intel_dp->DP |= DP_PIPEB_SELECT;
 
-	if (IS_eDP(intel_dp)) {
+	if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
 		/* don't miss out required setting for eDP */
 		intel_dp->DP |= DP_PLL_ENABLE;
 		if (adjusted_mode->clock < 200000)
@@ -754,13 +813,15 @@
 	}
 }
 
-static void ironlake_edp_panel_on (struct drm_device *dev)
+/* Returns true if the panel was already on when called */
+static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
 {
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 pp;
+	u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
 
 	if (I915_READ(PCH_PP_STATUS) & PP_ON)
-		return;
+		return true;
 
 	pp = I915_READ(PCH_PP_CONTROL);
 
@@ -771,21 +832,30 @@
 
 	pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
 	I915_WRITE(PCH_PP_CONTROL, pp);
+	POSTING_READ(PCH_PP_CONTROL);
 
-	if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+	/* Ouch. We need to wait here for some panels, like Dell e6510
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+	 */
+	msleep(300);
+
+	if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask,
+		     5000))
 		DRM_ERROR("panel on wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
-	pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
 	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
+
+	return false;
 }
 
 static void ironlake_edp_panel_off (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 pp;
+	u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
+		PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
 
 	pp = I915_READ(PCH_PP_CONTROL);
 
@@ -796,15 +866,20 @@
 
 	pp &= ~POWER_TARGET_ON;
 	I915_WRITE(PCH_PP_CONTROL, pp);
+	POSTING_READ(PCH_PP_CONTROL);
 
-	if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+	if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
 		DRM_ERROR("panel off wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
-	/* Make sure VDD is enabled so DP AUX will work */
-	pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */
+	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
+
+	/* Ouch. We need to wait here for some panels, like Dell e6510
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+	 */
+	msleep(300);
 }
 
 static void ironlake_edp_backlight_on (struct drm_device *dev)
@@ -813,6 +888,13 @@
 	u32 pp;
 
 	DRM_DEBUG_KMS("\n");
+	/*
+	 * If we enable the backlight right away following a panel power
+	 * on, we may see slight flicker as the panel syncs with the eDP
+	 * link.  So delay a bit to make sure the image is solid before
+	 * allowing it to appear.
+	 */
+	msleep(300);
 	pp = I915_READ(PCH_PP_CONTROL);
 	pp |= EDP_BLC_ENABLE;
 	I915_WRITE(PCH_PP_CONTROL, pp);
@@ -837,8 +919,10 @@
 
 	DRM_DEBUG_KMS("\n");
 	dpa_ctl = I915_READ(DP_A);
-	dpa_ctl &= ~DP_PLL_ENABLE;
+	dpa_ctl |= DP_PLL_ENABLE;
 	I915_WRITE(DP_A, dpa_ctl);
+	POSTING_READ(DP_A);
+	udelay(200);
 }
 
 static void ironlake_edp_pll_off(struct drm_encoder *encoder)
@@ -848,8 +932,9 @@
 	u32 dpa_ctl;
 
 	dpa_ctl = I915_READ(DP_A);
-	dpa_ctl |= DP_PLL_ENABLE;
+	dpa_ctl &= ~DP_PLL_ENABLE;
 	I915_WRITE(DP_A, dpa_ctl);
+	POSTING_READ(DP_A);
 	udelay(200);
 }
 
@@ -857,29 +942,31 @@
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-	if (IS_eDP(intel_dp)) {
+	if (is_edp(intel_dp)) {
 		ironlake_edp_backlight_off(dev);
-		ironlake_edp_panel_on(dev);
-		ironlake_edp_pll_on(encoder);
+		ironlake_edp_panel_on(intel_dp);
+		if (!is_pch_edp(intel_dp))
+			ironlake_edp_pll_on(encoder);
+		else
+			ironlake_edp_pll_off(encoder);
 	}
-	if (dp_reg & DP_PORT_EN)
-		intel_dp_link_down(intel_dp);
+	intel_dp_link_down(intel_dp);
 }
 
 static void intel_dp_commit(struct drm_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-	if (!(dp_reg & DP_PORT_EN)) {
-		intel_dp_link_train(intel_dp);
-	}
-	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+	intel_dp_start_link_train(intel_dp);
+
+	if (is_edp(intel_dp))
+		ironlake_edp_panel_on(intel_dp);
+
+	intel_dp_complete_link_train(intel_dp);
+
+	if (is_edp(intel_dp))
 		ironlake_edp_backlight_on(dev);
 }
 
@@ -892,22 +979,22 @@
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
 	if (mode != DRM_MODE_DPMS_ON) {
-		if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+		if (is_edp(intel_dp))
 			ironlake_edp_backlight_off(dev);
+		intel_dp_link_down(intel_dp);
+		if (is_edp(intel_dp))
 			ironlake_edp_panel_off(dev);
-		}
-		if (dp_reg & DP_PORT_EN)
-			intel_dp_link_down(intel_dp);
-		if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+		if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
 			ironlake_edp_pll_off(encoder);
 	} else {
+		if (is_edp(intel_dp))
+			ironlake_edp_panel_on(intel_dp);
 		if (!(dp_reg & DP_PORT_EN)) {
-			if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-				ironlake_edp_panel_on(dev);
-			intel_dp_link_train(intel_dp);
-			if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-				ironlake_edp_backlight_on(dev);
+			intel_dp_start_link_train(intel_dp);
+			intel_dp_complete_link_train(intel_dp);
 		}
+		if (is_edp(intel_dp))
+			ironlake_edp_backlight_on(dev);
 	}
 	intel_dp->dpms_mode = mode;
 }
@@ -917,14 +1004,13 @@
  * link status information
  */
 static bool
-intel_dp_get_link_status(struct intel_dp *intel_dp,
-			 uint8_t link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp)
 {
 	int ret;
 
 	ret = intel_dp_aux_native_read(intel_dp,
 				       DP_LANE0_1_STATUS,
-				       link_status, DP_LINK_STATUS_SIZE);
+				       intel_dp->link_status, DP_LINK_STATUS_SIZE);
 	if (ret != DP_LINK_STATUS_SIZE)
 		return false;
 	return true;
@@ -999,18 +1085,15 @@
 }
 
 static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-		       uint8_t link_status[DP_LINK_STATUS_SIZE],
-		       int lane_count,
-		       uint8_t train_set[4])
+intel_get_adjust_train(struct intel_dp *intel_dp)
 {
 	uint8_t v = 0;
 	uint8_t p = 0;
 	int lane;
 
-	for (lane = 0; lane < lane_count; lane++) {
-		uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
-		uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+	for (lane = 0; lane < intel_dp->lane_count; lane++) {
+		uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+		uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
 
 		if (this_v > v)
 			v = this_v;
@@ -1025,7 +1108,7 @@
 		p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
 	for (lane = 0; lane < 4; lane++)
-		train_set[lane] = v | p;
+		intel_dp->train_set[lane] = v | p;
 }
 
 static uint32_t
@@ -1116,18 +1199,18 @@
 			 DP_LANE_CHANNEL_EQ_DONE|\
 			 DP_LANE_SYMBOL_LOCKED)
 static bool
-intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+intel_channel_eq_ok(struct intel_dp *intel_dp)
 {
 	uint8_t lane_align;
 	uint8_t lane_status;
 	int lane;
 
-	lane_align = intel_dp_link_status(link_status,
+	lane_align = intel_dp_link_status(intel_dp->link_status,
 					  DP_LANE_ALIGN_STATUS_UPDATED);
 	if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
 		return false;
-	for (lane = 0; lane < lane_count; lane++) {
-		lane_status = intel_get_lane_status(link_status, lane);
+	for (lane = 0; lane < intel_dp->lane_count; lane++) {
+		lane_status = intel_get_lane_status(intel_dp->link_status, lane);
 		if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
 			return false;
 	}
@@ -1137,10 +1220,9 @@
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
 			uint32_t dp_reg_value,
-			uint8_t dp_train_pat,
-			uint8_t train_set[4])
+			uint8_t dp_train_pat)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
@@ -1152,28 +1234,27 @@
 				    dp_train_pat);
 
 	ret = intel_dp_aux_native_write(intel_dp,
-					DP_TRAINING_LANE0_SET, train_set, 4);
+					DP_TRAINING_LANE0_SET,
+					intel_dp->train_set, 4);
 	if (ret != 4)
 		return false;
 
 	return true;
 }
 
+/* Enable corresponding port and start training pattern 1 */
 static void
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint8_t	train_set[4];
-	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
 	int i;
 	uint8_t voltage;
 	bool clock_recovery = false;
-	bool channel_eq = false;
 	int tries;
 	u32 reg;
 	uint32_t DP = intel_dp->DP;
-	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
 
 	/* Enable output, wait for it to become active */
 	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
@@ -1186,94 +1267,107 @@
 				  DP_LINK_CONFIGURATION_SIZE);
 
 	DP |= DP_PORT_EN;
-	if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+	if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
 		DP &= ~DP_LINK_TRAIN_MASK_CPT;
 	else
 		DP &= ~DP_LINK_TRAIN_MASK;
-	memset(train_set, 0, 4);
+	memset(intel_dp->train_set, 0, 4);
 	voltage = 0xff;
 	tries = 0;
 	clock_recovery = false;
 	for (;;) {
-		/* Use train_set[0] to set the voltage and pre emphasis values */
+		/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
 		uint32_t    signal_levels;
-		if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-			signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+		if (IS_GEN6(dev) && is_edp(intel_dp)) {
+			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
 			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
 		} else {
-			signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+			signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
 			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
 		}
 
-		if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+		if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
 			reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
 		else
 			reg = DP | DP_LINK_TRAIN_PAT_1;
 
 		if (!intel_dp_set_link_train(intel_dp, reg,
-					     DP_TRAINING_PATTERN_1, train_set))
+					     DP_TRAINING_PATTERN_1))
 			break;
 		/* Set training pattern 1 */
 
 		udelay(100);
-		if (!intel_dp_get_link_status(intel_dp, link_status))
+		if (!intel_dp_get_link_status(intel_dp))
 			break;
 
-		if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+		if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
 			clock_recovery = true;
 			break;
 		}
 
 		/* Check to see if we've tried the max voltage */
 		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
 				break;
 		if (i == intel_dp->lane_count)
 			break;
 
 		/* Check to see if we've tried the same voltage 5 times */
-		if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
 			++tries;
 			if (tries == 5)
 				break;
 		} else
 			tries = 0;
-		voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
-		/* Compute new train_set as requested by target */
-		intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+		/* Compute new intel_dp->train_set as requested by target */
+		intel_get_adjust_train(intel_dp);
 	}
 
+	intel_dp->DP = DP;
+}
+
+static void
+intel_dp_complete_link_train(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool channel_eq = false;
+	int tries;
+	u32 reg;
+	uint32_t DP = intel_dp->DP;
+
 	/* channel equalization */
 	tries = 0;
 	channel_eq = false;
 	for (;;) {
-		/* Use train_set[0] to set the voltage and pre emphasis values */
+		/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
 		uint32_t    signal_levels;
 
-		if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-			signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+		if (IS_GEN6(dev) && is_edp(intel_dp)) {
+			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
 			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
 		} else {
-			signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+			signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
 			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
 		}
 
-		if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+		if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
 			reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
 		else
 			reg = DP | DP_LINK_TRAIN_PAT_2;
 
 		/* channel eq pattern */
 		if (!intel_dp_set_link_train(intel_dp, reg,
-					     DP_TRAINING_PATTERN_2, train_set))
+					     DP_TRAINING_PATTERN_2))
 			break;
 
 		udelay(400);
-		if (!intel_dp_get_link_status(intel_dp, link_status))
+		if (!intel_dp_get_link_status(intel_dp))
 			break;
 
-		if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) {
+		if (intel_channel_eq_ok(intel_dp)) {
 			channel_eq = true;
 			break;
 		}
@@ -1282,12 +1376,12 @@
 		if (tries > 5)
 			break;
 
-		/* Compute new train_set as requested by target */
-		intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+		/* Compute new intel_dp->train_set as requested by target */
+		intel_get_adjust_train(intel_dp);
 		++tries;
 	}
 
-	if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
+	if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
 		reg = DP | DP_LINK_TRAIN_OFF_CPT;
 	else
 		reg = DP | DP_LINK_TRAIN_OFF;
@@ -1301,33 +1395,57 @@
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t DP = intel_dp->DP;
 
+	if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+		return;
+
 	DRM_DEBUG_KMS("\n");
 
-	if (IS_eDP(intel_dp)) {
+	if (is_edp(intel_dp)) {
 		DP &= ~DP_PLL_ENABLE;
 		I915_WRITE(intel_dp->output_reg, DP);
 		POSTING_READ(intel_dp->output_reg);
 		udelay(100);
 	}
 
-	if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
+	if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
 		DP &= ~DP_LINK_TRAIN_MASK_CPT;
 		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
-		POSTING_READ(intel_dp->output_reg);
 	} else {
 		DP &= ~DP_LINK_TRAIN_MASK;
 		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
-		POSTING_READ(intel_dp->output_reg);
 	}
+	POSTING_READ(intel_dp->output_reg);
 
-	udelay(17000);
+	msleep(17);
 
-	if (IS_eDP(intel_dp))
+	if (is_edp(intel_dp))
 		DP |= DP_LINK_TRAIN_OFF;
+
+	if (!HAS_PCH_CPT(dev) &&
+	    I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+		/* Hardware workaround: leaving our transcoder select
+		 * set to transcoder B while it's off will prevent the
+		 * corresponding HDMI output on transcoder A.
+		 *
+		 * Combine this with another hardware workaround:
+		 * transcoder select bit can only be cleared while the
+		 * port is enabled.
+		 */
+		DP &= ~DP_PIPEB_SELECT;
+		I915_WRITE(intel_dp->output_reg, DP);
+
+		/* Changes to enable or select take place the vblank
+		 * after being written.
+		 */
+		intel_wait_for_vblank(intel_dp->base.base.dev,
+				      intel_crtc->pipe);
+	}
+
 	I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
 	POSTING_READ(intel_dp->output_reg);
 }
@@ -1344,32 +1462,34 @@
 static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
-	uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-	if (!intel_dp->base.enc.crtc)
+	if (!intel_dp->base.base.crtc)
 		return;
 
-	if (!intel_dp_get_link_status(intel_dp, link_status)) {
+	if (!intel_dp_get_link_status(intel_dp)) {
 		intel_dp_link_down(intel_dp);
 		return;
 	}
 
-	if (!intel_channel_eq_ok(link_status, intel_dp->lane_count))
-		intel_dp_link_train(intel_dp);
+	if (!intel_channel_eq_ok(intel_dp)) {
+		intel_dp_start_link_train(intel_dp);
+		intel_dp_complete_link_train(intel_dp);
+	}
 }
 
 static enum drm_connector_status
-ironlake_dp_detect(struct drm_connector *connector)
+ironlake_dp_detect(struct intel_dp *intel_dp)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	enum drm_connector_status status;
 
+	/* Can't disconnect eDP */
+	if (is_edp(intel_dp))
+		return connector_status_connected;
+
 	status = connector_status_disconnected;
 	if (intel_dp_aux_native_read(intel_dp,
 				     0x000, intel_dp->dpcd,
-				     sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
-	{
+				     sizeof (intel_dp->dpcd))
+	    == sizeof(intel_dp->dpcd)) {
 		if (intel_dp->dpcd[0] != 0)
 			status = connector_status_connected;
 	}
@@ -1378,26 +1498,13 @@
 	return status;
 }
 
-/**
- * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
- *
- * \return true if DP port is connected.
- * \return false if DP port is disconnected.
- */
 static enum drm_connector_status
-intel_dp_detect(struct drm_connector *connector, bool force)
+g4x_dp_detect(struct intel_dp *intel_dp)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t temp, bit;
 	enum drm_connector_status status;
-
-	intel_dp->has_audio = false;
-
-	if (HAS_PCH_SPLIT(dev))
-		return ironlake_dp_detect(connector);
+	uint32_t temp, bit;
 
 	switch (intel_dp->output_reg) {
 	case DP_B:
@@ -1419,31 +1526,66 @@
 		return connector_status_disconnected;
 
 	status = connector_status_disconnected;
-	if (intel_dp_aux_native_read(intel_dp,
-				     0x000, intel_dp->dpcd,
+	if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
 				     sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
 	{
 		if (intel_dp->dpcd[0] != 0)
 			status = connector_status_connected;
 	}
+
 	return status;
 }
 
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector, bool force)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct drm_device *dev = intel_dp->base.base.dev;
+	enum drm_connector_status status;
+	struct edid *edid = NULL;
+
+	intel_dp->has_audio = false;
+
+	if (HAS_PCH_SPLIT(dev))
+		status = ironlake_dp_detect(intel_dp);
+	else
+		status = g4x_dp_detect(intel_dp);
+	if (status != connector_status_connected)
+		return status;
+
+	if (intel_dp->force_audio) {
+		intel_dp->has_audio = intel_dp->force_audio > 0;
+	} else {
+		edid = drm_get_edid(connector, &intel_dp->adapter);
+		if (edid) {
+			intel_dp->has_audio = drm_detect_monitor_audio(edid);
+			connector->display_info.raw_edid = NULL;
+			kfree(edid);
+		}
+	}
+
+	return connector_status_connected;
+}
+
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
 	/* We should parse the EDID data and find out if it has an audio sink
 	 */
 
-	ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
+	ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
 	if (ret) {
-		if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
-		    !dev_priv->panel_fixed_mode) {
+		if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
 			struct drm_display_mode *newmode;
 			list_for_each_entry(newmode, &connector->probed_modes,
 					    head) {
@@ -1459,7 +1601,7 @@
 	}
 
 	/* if eDP has no EDID, try to use fixed panel mode from VBT */
-	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+	if (is_edp(intel_dp)) {
 		if (dev_priv->panel_fixed_mode != NULL) {
 			struct drm_display_mode *mode;
 			mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
@@ -1470,6 +1612,46 @@
 	return 0;
 }
 
+static int
+intel_dp_set_property(struct drm_connector *connector,
+		      struct drm_property *property,
+		      uint64_t val)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int ret;
+
+	ret = drm_connector_property_set_value(connector, property, val);
+	if (ret)
+		return ret;
+
+	if (property == intel_dp->force_audio_property) {
+		if (val == intel_dp->force_audio)
+			return 0;
+
+		intel_dp->force_audio = val;
+
+		if (val > 0 && intel_dp->has_audio)
+			return 0;
+		if (val < 0 && !intel_dp->has_audio)
+			return 0;
+
+		intel_dp->has_audio = val > 0;
+		goto done;
+	}
+
+	return -EINVAL;
+
+done:
+	if (intel_dp->base.base.crtc) {
+		struct drm_crtc *crtc = intel_dp->base.base.crtc;
+		drm_crtc_helper_set_mode(crtc, &crtc->mode,
+					 crtc->x, crtc->y,
+					 crtc->fb);
+	}
+
+	return 0;
+}
+
 static void
 intel_dp_destroy (struct drm_connector *connector)
 {
@@ -1478,6 +1660,15 @@
 	kfree(connector);
 }
 
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+	i2c_del_adapter(&intel_dp->adapter);
+	drm_encoder_cleanup(encoder);
+	kfree(intel_dp);
+}
+
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
 	.dpms = intel_dp_dpms,
 	.mode_fixup = intel_dp_mode_fixup,
@@ -1490,20 +1681,21 @@
 	.dpms = drm_helper_connector_dpms,
 	.detect = intel_dp_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = intel_dp_set_property,
 	.destroy = intel_dp_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
 	.get_modes = intel_dp_get_modes,
 	.mode_valid = intel_dp_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
-	.destroy = intel_encoder_destroy,
+	.destroy = intel_dp_encoder_destroy,
 };
 
-void
+static void
 intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 {
 	struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -1554,6 +1746,20 @@
 	return false;
 }
 
+static void
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+
+	intel_dp->force_audio_property =
+		drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+	if (intel_dp->force_audio_property) {
+		intel_dp->force_audio_property->values[0] = -1;
+		intel_dp->force_audio_property->values[1] = 1;
+		drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
+	}
+}
+
 void
 intel_dp_init(struct drm_device *dev, int output_reg)
 {
@@ -1580,7 +1786,7 @@
 		if (intel_dpd_is_edp(dev))
 			intel_dp->is_pch_edp = true;
 
-	if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+	if (output_reg == DP_A || is_pch_edp(intel_dp)) {
 		type = DRM_MODE_CONNECTOR_eDP;
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 	} else {
@@ -1601,7 +1807,7 @@
 	else if (output_reg == DP_D || output_reg == PCH_DP_D)
 		intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
 
-	if (IS_eDP(intel_dp))
+	if (is_edp(intel_dp))
 		intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
 
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
@@ -1612,12 +1818,11 @@
 	intel_dp->has_audio = false;
 	intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
 			 DRM_MODE_ENCODER_TMDS);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	drm_sysfs_connector_add(connector);
 
 	/* Set up the DDC bus. */
@@ -1647,10 +1852,29 @@
 
 	intel_dp_i2c_init(intel_dp, intel_connector, name);
 
-	intel_encoder->ddc_bus = &intel_dp->adapter;
+	/* Cache some DPCD data in the eDP case */
+	if (is_edp(intel_dp)) {
+		int ret;
+		bool was_on;
+
+		was_on = ironlake_edp_panel_on(intel_dp);
+		ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
+					       intel_dp->dpcd,
+					       sizeof(intel_dp->dpcd));
+		if (ret == sizeof(intel_dp->dpcd)) {
+			if (intel_dp->dpcd[0] >= 0x11)
+				dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
+					DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+		} else {
+			DRM_ERROR("failed to retrieve link info\n");
+		}
+		if (!was_on)
+			ironlake_edp_panel_off(dev);
+	}
+
 	intel_encoder->hot_plug = intel_dp_hot_plug;
 
-	if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
+	if (is_edp(intel_dp)) {
 		/* initialize panel mode from VBT if available for eDP */
 		if (dev_priv->lfp_lvds_vbt_mode) {
 			dev_priv->panel_fixed_mode =
@@ -1662,6 +1886,8 @@
 		}
 	}
 
+	intel_dp_add_properties(intel_dp, connector);
+
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
 	 * 0xd.  Failure to do so will result in spurious interrupts being
 	 * generated on the port when a cable is not attached.
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_drv.h linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_drv.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_drv.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_drv.h	2011-01-04 19:50:19.000000000 -0500
@@ -26,14 +26,12 @@
 #define __INTEL_DRV_H__
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/i2c-algo-bit.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
-
 #include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
 
-#define wait_for(COND, MS, W) ({ \
+#define _wait_for(COND, MS, W) ({ \
 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
 	int ret__ = 0;							\
 	while (! (COND)) {						\
@@ -41,11 +39,24 @@
 			ret__ = -ETIMEDOUT;				\
 			break;						\
 		}							\
-		if (W) msleep(W);					\
+		if (W && !in_dbg_master()) msleep(W);			\
 	}								\
 	ret__;								\
 })
 
+#define wait_for(COND, MS) _wait_for(COND, MS, 1)
+#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+
+#define MSLEEP(x) do { \
+	if (in_dbg_master()) \
+	       	mdelay(x); \
+	else \
+		msleep(x); \
+} while(0)
+
+#define KHz(x) (1000*x)
+#define MHz(x) KHz(1000*x)
+
 /*
  * Display related stuff
  */
@@ -96,24 +107,39 @@
 #define INTEL_DVO_CHIP_TMDS 2
 #define INTEL_DVO_CHIP_TVOUT 4
 
-struct intel_i2c_chan {
-	struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
-	u32 reg; /* GPIO reg */
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo;
-};
+/* drm_display_mode->private_flags */
+#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
+#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+
+static inline void
+intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
+				int multiplier)
+{
+	mode->clock *= multiplier;
+	mode->private_flags |= multiplier;
+}
+
+static inline int
+intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
+{
+	return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
+}
 
 struct intel_framebuffer {
 	struct drm_framebuffer base;
 	struct drm_gem_object *obj;
 };
 
+struct intel_fbdev {
+	struct drm_fb_helper helper;
+	struct intel_framebuffer ifb;
+	struct list_head fbdev_list;
+	struct drm_display_mode *our_mode;
+};
 
 struct intel_encoder {
-	struct drm_encoder enc;
+	struct drm_encoder base;
 	int type;
-	struct i2c_adapter *i2c_bus;
-	struct i2c_adapter *ddc_bus;
 	bool load_detect_temp;
 	bool needs_tv_clock;
 	void (*hot_plug)(struct intel_encoder *);
@@ -123,32 +149,7 @@
 
 struct intel_connector {
 	struct drm_connector base;
-};
-
-struct intel_crtc;
-struct intel_overlay {
-	struct drm_device *dev;
-	struct intel_crtc *crtc;
-	struct drm_i915_gem_object *vid_bo;
-	struct drm_i915_gem_object *old_vid_bo;
-	int active;
-	int pfit_active;
-	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
-	u32 color_key;
-	u32 brightness, contrast, saturation;
-	u32 old_xscale, old_yscale;
-	/* register access */
-	u32 flip_addr;
-	struct drm_i915_gem_object *reg_bo;
-	void *virt_addr;
-	/* flip handling */
-	uint32_t last_flip_req;
-	int hw_wedged;
-#define HW_WEDGED		1
-#define NEEDS_WAIT_FOR_FLIP	2
-#define RELEASE_OLD_VID		3
-#define SWITCH_OFF_STAGE_1	4
-#define SWITCH_OFF_STAGE_2	5
+	struct intel_encoder *encoder;
 };
 
 struct intel_crtc {
@@ -157,6 +158,7 @@
 	enum plane plane;
 	u8 lut_r[256], lut_g[256], lut_b[256];
 	int dpms_mode;
+	bool active; /* is the crtc on? independent of the dpms mode */
 	bool busy; /* is scanout buffer being updated frequently? */
 	struct timer_list idle_timer;
 	bool lowfreq_avail;
@@ -168,14 +170,53 @@
 	uint32_t cursor_addr;
 	int16_t cursor_x, cursor_y;
 	int16_t cursor_width, cursor_height;
-	bool cursor_visible, cursor_on;
+	bool cursor_visible;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
-#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+#define DIP_TYPE_AVI    0x82
+#define DIP_VERSION_AVI 0x2
+#define DIP_LEN_AVI     13
+
+struct dip_infoframe {
+	uint8_t type;		/* HB0 */
+	uint8_t ver;		/* HB1 */
+	uint8_t len;		/* HB2 - body len, not including checksum */
+	uint8_t ecc;		/* Header ECC */
+	uint8_t checksum;	/* PB0 */
+	union {
+		struct {
+			/* PB1 - Y 6:5, A 4:4, B 3:2, S 1:0 */
+			uint8_t Y_A_B_S;
+			/* PB2 - C 7:6, M 5:4, R 3:0 */
+			uint8_t C_M_R;
+			/* PB3 - ITC 7:7, EC 6:4, Q 3:2, SC 1:0 */
+			uint8_t ITC_EC_Q_SC;
+			/* PB4 - VIC 6:0 */
+			uint8_t VIC;
+			/* PB5 - PR 3:0 */
+			uint8_t PR;
+			/* PB6 to PB13 */
+			uint16_t top_bar_end;
+			uint16_t bottom_bar_start;
+			uint16_t left_bar_end;
+			uint16_t right_bar_start;
+		} avi;
+		uint8_t payload[27];
+	} __attribute__ ((packed)) body;
+} __attribute__((packed));
+
+static inline struct drm_crtc *
+intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	return dev_priv->pipe_to_crtc_mapping[pipe];
+}
+
 struct intel_unpin_work {
 	struct work_struct work;
 	struct drm_device *dev;
@@ -186,51 +227,56 @@
 	bool enable_stall_check;
 };
 
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-				     const char *name);
-void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
-void intel_i2c_reset_gmbus(struct drm_device *dev);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
 extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
 extern void intel_dvo_init(struct drm_device *dev);
 extern void intel_tv_init(struct drm_device *dev);
 extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
-extern void intel_lvds_init(struct drm_device *dev);
+extern bool intel_lvds_init(struct drm_device *dev);
 extern void intel_dp_init(struct drm_device *dev, int dp_reg);
 void
 intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		 struct drm_display_mode *adjusted_mode);
-extern bool intel_pch_has_edp(struct drm_crtc *crtc);
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
+extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
 
-
+/* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 				   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct drm_device *dev,
 				    int fitting_mode,
 				    struct drm_display_mode *mode,
 				    struct drm_display_mode *adjusted_mode);
+extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
+extern u32 intel_panel_get_backlight(struct drm_device *dev);
+extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
-extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
 extern void intel_encoder_commit (struct drm_encoder *encoder);
 extern void intel_encoder_destroy(struct drm_encoder *encoder);
 
-extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
+static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
+{
+	return to_intel_connector(connector)->encoder;
+}
+
+extern void intel_connector_attach_encoder(struct intel_connector *connector,
+					   struct intel_encoder *encoder);
+extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
 
 extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 						    struct drm_crtc *crtc);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
 						   struct drm_connector *connector,
 						   struct drm_display_mode *mode,
@@ -250,9 +296,11 @@
 extern void intel_init_clock_gating(struct drm_device *dev);
 extern void ironlake_enable_drps(struct drm_device *dev);
 extern void ironlake_disable_drps(struct drm_device *dev);
+extern void intel_init_emon(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
-				      struct drm_gem_object *obj);
+				      struct drm_gem_object *obj,
+				      bool pipelined);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
@@ -267,9 +315,8 @@
 
 extern void intel_setup_overlay(struct drm_device *dev);
 extern void intel_cleanup_overlay(struct drm_device *dev);
-extern int intel_overlay_switch_off(struct intel_overlay *overlay);
-extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-						int interruptible);
+extern int intel_overlay_switch_off(struct intel_overlay *overlay,
+				    bool interruptible);
 extern int intel_overlay_put_image(struct drm_device *dev, void *data,
 				   struct drm_file *file_priv);
 extern int intel_overlay_attrs(struct drm_device *dev, void *data,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_dvo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_dvo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_dvo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_dvo.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,7 @@
 		.name = "ch7017",
 		.dvo_reg = DVOC,
 		.slave_addr = 0x75,
-		.gpio = GPIOE,
+		.gpio = GMBUS_PORT_DPB,
 		.dev_ops = &ch7017_ops,
 	}
 };
@@ -88,7 +88,13 @@
 
 static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
+	return container_of(encoder, struct intel_dvo, base.base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_dvo, base);
 }
 
 static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
@@ -112,8 +118,7 @@
 static int intel_dvo_mode_valid(struct drm_connector *connector,
 				struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 
 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		return MODE_NO_DBLESCAN;
@@ -224,23 +229,22 @@
 static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 	return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
 }
 
 static int intel_dvo_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
 	/* We should probably have an i2c driver get_modes function for those
 	 * devices which will have a fixed set of modes determined by the chip
 	 * (TV-out, for example), but for now with just TMDS and LVDS,
 	 * that's not the case.
 	 */
-	intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
+	intel_ddc_get_modes(connector,
+			    &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
 	if (!list_empty(&connector->probed_modes))
 		return 1;
 
@@ -281,7 +285,7 @@
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
 	.mode_valid = intel_dvo_mode_valid,
 	.get_modes = intel_dvo_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
@@ -311,8 +315,7 @@
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 	uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
 	struct drm_display_mode *mode = NULL;
 
@@ -323,7 +326,7 @@
 		struct drm_crtc *crtc;
 		int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
-		crtc = intel_get_crtc_from_pipe(dev, pipe);
+		crtc = intel_get_crtc_for_pipe(dev, pipe);
 		if (crtc) {
 			mode = intel_crtc_mode_get(dev, crtc);
 			if (mode) {
@@ -341,11 +344,10 @@
 
 void intel_dvo_init(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_dvo *intel_dvo;
 	struct intel_connector *intel_connector;
-	struct i2c_adapter *i2cbus = NULL;
-	int ret = 0;
 	int i;
 	int encoder_type = DRM_MODE_ENCODER_NONE;
 
@@ -360,16 +362,14 @@
 	}
 
 	intel_encoder = &intel_dvo->base;
-
-	/* Set up the DDC bus */
-	intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
-	if (!intel_encoder->ddc_bus)
-		goto free_intel;
+	drm_encoder_init(dev, &intel_encoder->base,
+			 &intel_dvo_enc_funcs, encoder_type);
 
 	/* Now, try to find a controller */
 	for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
 		struct drm_connector *connector = &intel_connector->base;
 		const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+		struct i2c_adapter *i2c;
 		int gpio;
 
 		/* Allow the I2C driver info to specify the GPIO to be used in
@@ -379,24 +379,18 @@
 		if (dvo->gpio != 0)
 			gpio = dvo->gpio;
 		else if (dvo->type == INTEL_DVO_CHIP_LVDS)
-			gpio = GPIOB;
+			gpio = GMBUS_PORT_SSC;
 		else
-			gpio = GPIOE;
+			gpio = GMBUS_PORT_DPB;
 
 		/* Set up the I2C bus necessary for the chip we're probing.
 		 * It appears that everything is on GPIOE except for panels
 		 * on i830 laptops, which are on GPIOB (DVOA).
 		 */
-		if (i2cbus != NULL)
-			intel_i2c_destroy(i2cbus);
-		if (!(i2cbus = intel_i2c_create(dev, gpio,
-			gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-			continue;
-		}
+		i2c = &dev_priv->gmbus[gpio].adapter;
 
 		intel_dvo->dev = *dvo;
-		ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
-		if (!ret)
+		if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
 			continue;
 
 		intel_encoder->type = INTEL_OUTPUT_DVO;
@@ -427,13 +421,10 @@
 		connector->interlace_allowed = false;
 		connector->doublescan_allowed = false;
 
-		drm_encoder_init(dev, &intel_encoder->enc,
-				 &intel_dvo_enc_funcs, encoder_type);
-		drm_encoder_helper_add(&intel_encoder->enc,
+		drm_encoder_helper_add(&intel_encoder->base,
 				       &intel_dvo_helper_funcs);
 
-		drm_mode_connector_attach_encoder(&intel_connector->base,
-						  &intel_encoder->enc);
+		intel_connector_attach_encoder(intel_connector, intel_encoder);
 		if (dvo->type == INTEL_DVO_CHIP_LVDS) {
 			/* For our LVDS chipsets, we should hopefully be able
 			 * to dig the fixed panel mode out of the BIOS data.
@@ -451,11 +442,7 @@
 		return;
 	}
 
-	intel_i2c_destroy(intel_encoder->ddc_bus);
-	/* Didn't find a chip, so tear down. */
-	if (i2cbus != NULL)
-		intel_i2c_destroy(i2cbus);
-free_intel:
+	drm_encoder_cleanup(&intel_encoder->base);
 	kfree(intel_dvo);
 	kfree(intel_connector);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_fb.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_fb.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_fb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_fb.c	2011-01-04 19:50:19.000000000 -0500
@@ -44,13 +44,6 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-struct intel_fbdev {
-	struct drm_fb_helper helper;
-	struct intel_framebuffer ifb;
-	struct list_head fbdev_list;
-	struct drm_display_mode *our_mode;
-};
-
 static struct fb_ops intelfb_ops = {
 	.owner = THIS_MODULE,
 	.fb_check_var = drm_fb_helper_check_var,
@@ -75,7 +68,7 @@
 	struct drm_gem_object *fbo = NULL;
 	struct drm_i915_gem_object *obj_priv;
 	struct device *device = &dev->pdev->dev;
-	int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+	int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
 
 	/* we don't do packed 24bpp */
 	if (sizes->surface_bpp == 24)
@@ -100,19 +93,13 @@
 
 	mutex_lock(&dev->struct_mutex);
 
-	ret = intel_pin_and_fence_fb_obj(dev, fbo);
+	/* Flush everything out, we'll be doing GTT only from now on */
+	ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
 	if (ret) {
 		DRM_ERROR("failed to pin fb: %d\n", ret);
 		goto out_unref;
 	}
 
-	/* Flush everything out, we'll be doing GTT only from now on */
-	ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
-	if (ret) {
-		DRM_ERROR("failed to bind fb: %d.\n", ret);
-		goto out_unpin;
-	}
-
 	info = framebuffer_alloc(0, device);
 	if (!info) {
 		ret = -ENOMEM;
@@ -142,7 +129,7 @@
 		goto out_unpin;
 	}
 	info->apertures->ranges[0].base = dev->mode_config.fb_base;
-	if (IS_I9XX(dev))
+	if (!IS_GEN2(dev))
 		info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
 	else
 		info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
@@ -219,8 +206,8 @@
 	.fb_probe = intel_fb_find_or_create_single,
 };
 
-int intel_fbdev_destroy(struct drm_device *dev,
-			struct intel_fbdev *ifbdev)
+static void intel_fbdev_destroy(struct drm_device *dev,
+				struct intel_fbdev *ifbdev)
 {
 	struct fb_info *info;
 	struct intel_framebuffer *ifb = &ifbdev->ifb;
@@ -238,11 +225,9 @@
 
 	drm_framebuffer_cleanup(&ifb->base);
 	if (ifb->obj) {
-		drm_gem_object_unreference(ifb->obj);
+		drm_gem_object_unreference_unlocked(ifb->obj);
 		ifb->obj = NULL;
 	}
-
-	return 0;
 }
 
 int intel_fbdev_init(struct drm_device *dev)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_hdmi.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_hdmi.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_hdmi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_hdmi.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,12 +40,76 @@
 struct intel_hdmi {
 	struct intel_encoder base;
 	u32 sdvox_reg;
+	int ddc_bus;
 	bool has_hdmi_sink;
+	bool has_audio;
+	int force_audio;
+	struct drm_property *force_audio_property;
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
+	return container_of(encoder, struct intel_hdmi, base.base);
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_hdmi, base);
+}
+
+void intel_dip_infoframe_csum(struct dip_infoframe *avi_if)
+{
+	uint8_t *data = (uint8_t *)avi_if;
+	uint8_t sum = 0;
+	unsigned i;
+
+	avi_if->checksum = 0;
+	avi_if->ecc = 0;
+
+	for (i = 0; i < sizeof(*avi_if); i++)
+		sum += data[i];
+
+	avi_if->checksum = 0x100 - sum;
+}
+
+static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+{
+	struct dip_infoframe avi_if = {
+		.type = DIP_TYPE_AVI,
+		.ver = DIP_VERSION_AVI,
+		.len = DIP_LEN_AVI,
+	};
+	uint32_t *data = (uint32_t *)&avi_if;
+	struct drm_device *dev = encoder->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	u32 port;
+	unsigned i;
+
+	if (!intel_hdmi->has_hdmi_sink)
+		return;
+
+	/* XXX first guess at handling video port, is this corrent? */
+	if (intel_hdmi->sdvox_reg == SDVOB)
+		port = VIDEO_DIP_PORT_B;
+	else if (intel_hdmi->sdvox_reg == SDVOC)
+		port = VIDEO_DIP_PORT_C;
+	else
+		return;
+
+	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC);
+
+	intel_dip_infoframe_csum(&avi_if);
+	for (i = 0; i < sizeof(avi_if); i += 4) {
+		I915_WRITE(VIDEO_DIP_DATA, *data);
+		data++;
+	}
+
+	I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port |
+		   VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC |
+		   VIDEO_DIP_ENABLE_AVI);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -65,10 +129,13 @@
 	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 		sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
 
-	if (intel_hdmi->has_hdmi_sink) {
+	/* Required on CPT */
+	if (intel_hdmi->has_hdmi_sink && HAS_PCH_CPT(dev))
+		sdvox |= HDMI_MODE_SELECT;
+
+	if (intel_hdmi->has_audio) {
 		sdvox |= SDVO_AUDIO_ENABLE;
-		if (HAS_PCH_CPT(dev))
-			sdvox |= HDMI_MODE_SELECT;
+		sdvox |= SDVO_NULL_PACKETS_DURING_VSYNC;
 	}
 
 	if (intel_crtc->pipe == 1) {
@@ -80,6 +147,8 @@
 
 	I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
 	POSTING_READ(intel_hdmi->sdvox_reg);
+
+	intel_hdmi_set_avi_infoframe(encoder);
 }
 
 static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode)
@@ -141,36 +210,85 @@
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	struct edid *edid = NULL;
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
+	struct edid *edid;
 	enum drm_connector_status status = connector_status_disconnected;
 
 	intel_hdmi->has_hdmi_sink = false;
-	edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
+	intel_hdmi->has_audio = false;
+	edid = drm_get_edid(connector,
+			    &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 
 	if (edid) {
 		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
 			status = connector_status_connected;
 			intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+			intel_hdmi->has_audio = drm_detect_monitor_audio(edid);
 		}
 		connector->display_info.raw_edid = NULL;
 		kfree(edid);
 	}
 
+	if (status == connector_status_connected) {
+		if (intel_hdmi->force_audio)
+			intel_hdmi->has_audio = intel_hdmi->force_audio > 0;
+	}
+
 	return status;
 }
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
 	/* We should parse the EDID data and find out if it's an HDMI sink so
 	 * we can send audio to it.
 	 */
 
-	return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
+	return intel_ddc_get_modes(connector,
+				   &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+}
+
+static int
+intel_hdmi_set_property(struct drm_connector *connector,
+		      struct drm_property *property,
+		      uint64_t val)
+{
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	int ret;
+
+	ret = drm_connector_property_set_value(connector, property, val);
+	if (ret)
+		return ret;
+
+	if (property == intel_hdmi->force_audio_property) {
+		if (val == intel_hdmi->force_audio)
+			return 0;
+
+		intel_hdmi->force_audio = val;
+
+		if (val > 0 && intel_hdmi->has_audio)
+			return 0;
+		if (val < 0 && !intel_hdmi->has_audio)
+			return 0;
+
+		intel_hdmi->has_audio = val > 0;
+		goto done;
+	}
+
+	return -EINVAL;
+
+done:
+	if (intel_hdmi->base.base.crtc) {
+		struct drm_crtc *crtc = intel_hdmi->base.base.crtc;
+		drm_crtc_helper_set_mode(crtc, &crtc->mode,
+					 crtc->x, crtc->y,
+					 crtc->fb);
+	}
+
+	return 0;
 }
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -192,19 +310,34 @@
 	.dpms = drm_helper_connector_dpms,
 	.detect = intel_hdmi_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = intel_hdmi_set_property,
 	.destroy = intel_hdmi_destroy,
 };
 
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
 	.get_modes = intel_hdmi_get_modes,
 	.mode_valid = intel_hdmi_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
 	.destroy = intel_encoder_destroy,
 };
 
+static void
+intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+
+	intel_hdmi->force_audio_property =
+		drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+	if (intel_hdmi->force_audio_property) {
+		intel_hdmi->force_audio_property->values[0] = -1;
+		intel_hdmi->force_audio_property->values[1] = 1;
+		drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
+	}
+}
+
 void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -224,6 +357,9 @@
 	}
 
 	intel_encoder = &intel_hdmi->base;
+	drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+
 	connector = &intel_connector->base;
 	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
 			   DRM_MODE_CONNECTOR_HDMIA);
@@ -239,39 +375,33 @@
 	/* Set up the DDC bus. */
 	if (sdvox_reg == SDVOB) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
 		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == SDVOC) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
 		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMIB) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
-								"HDMIB");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
 		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMIC) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
-								"HDMIC");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
 		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMID) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
-								"HDMID");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
 		dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
 	}
-	if (!intel_encoder->ddc_bus)
-		goto err_connector;
 
 	intel_hdmi->sdvox_reg = sdvox_reg;
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
-			 DRM_MODE_ENCODER_TMDS);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
+	intel_hdmi_add_properties(intel_hdmi, connector);
+
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	drm_sysfs_connector_add(connector);
 
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -282,13 +412,4 @@
 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
-
-	return;
-
-err_connector:
-	drm_connector_cleanup(connector);
-	kfree(intel_hdmi);
-	kfree(intel_connector);
-
-	return;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_i2c.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_i2c.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright Â© 2006-2008 Intel Corporation
+ * Copyright Â© 2006-2008,2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,10 +24,9 @@
  *
  * Authors:
  *	Eric Anholt <eric@anholt.net>
+ *	Chris Wilson <chris@chris-wilson.co.uk>
  */
 #include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm.h"
@@ -35,79 +34,106 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
+/* Intel GPIO access functions */
+
+#define I2C_RISEFALL_TIME 20
+
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
+{
+	return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+struct intel_gpio {
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+	struct drm_i915_private *dev_priv;
+	u32 reg;
+};
+
+void
+intel_i2c_reset(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (HAS_PCH_SPLIT(dev))
+		I915_WRITE(PCH_GMBUS0, 0);
+	else
+		I915_WRITE(GMBUS0, 0);
+}
+
+static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
+{
+	u32 val;
 
 	/* When using bit bashing for I2C, this bit needs to be set to 1 */
-	if (!IS_PINEVIEW(dev))
+	if (!IS_PINEVIEW(dev_priv->dev))
 		return;
+
+	val = I915_READ(DSPCLK_GATE_D);
 	if (enable)
-		I915_WRITE(DSPCLK_GATE_D,
-			I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
+		val |= DPCUNIT_CLOCK_GATE_DISABLE;
 	else
-		I915_WRITE(DSPCLK_GATE_D,
-			I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
+		val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
+	I915_WRITE(DSPCLK_GATE_D, val);
 }
 
-/*
- * Intel GPIO access functions
- */
+static u32 get_reserved(struct intel_gpio *gpio)
+{
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	struct drm_device *dev = dev_priv->dev;
+	u32 reserved = 0;
 
-#define I2C_RISEFALL_TIME 20
+	/* On most chips, these bits must be preserved in software. */
+	if (!IS_I830(dev) && !IS_845G(dev))
+		reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
+						   GPIO_CLOCK_PULLUP_DISABLE);
+
+	return reserved;
+}
 
 static int get_clock(void *data)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 val;
-
-	val = I915_READ(chan->reg);
-	return ((val & GPIO_CLOCK_VAL_IN) != 0);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+	I915_WRITE(gpio->reg, reserved);
+	return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 val;
-
-	val = I915_READ(chan->reg);
-	return ((val & GPIO_DATA_VAL_IN) != 0);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+	I915_WRITE(gpio->reg, reserved);
+	return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 reserved = 0, clock_bits;
-
-	/* On most chips, these bits must be preserved in software. */
-	if (!IS_I830(dev) && !IS_845G(dev))
-		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-						   GPIO_CLOCK_PULLUP_DISABLE);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	u32 clock_bits;
 
 	if (state_high)
 		clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
 	else
 		clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
 			GPIO_CLOCK_VAL_MASK;
-	I915_WRITE(chan->reg, reserved | clock_bits);
-	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+
+	I915_WRITE(gpio->reg, reserved | clock_bits);
+	POSTING_READ(gpio->reg);
 }
 
 static void set_data(void *data, int state_high)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 reserved = 0, data_bits;
-
-	/* On most chips, these bits must be preserved in software. */
-	if (!IS_I830(dev) && !IS_845G(dev))
-		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-						   GPIO_CLOCK_PULLUP_DISABLE);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	u32 data_bits;
 
 	if (state_high)
 		data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
@@ -115,109 +141,314 @@
 		data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
 			GPIO_DATA_VAL_MASK;
 
-	I915_WRITE(chan->reg, reserved | data_bits);
-	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+	I915_WRITE(gpio->reg, reserved | data_bits);
+	POSTING_READ(gpio->reg);
 }
 
-/* Clears the GMBUS setup.  Our driver doesn't make use of the GMBUS I2C
- * engine, but if the BIOS leaves it enabled, then that can break our use
- * of the bit-banging I2C interfaces.  This is notably the case with the
- * Mac Mini in EFI mode.
- */
-void
-intel_i2c_reset_gmbus(struct drm_device *dev)
+static struct i2c_adapter *
+intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	static const int map_pin_to_reg[] = {
+		0,
+		GPIOB,
+		GPIOA,
+		GPIOC,
+		GPIOD,
+		GPIOE,
+		0,
+		GPIOF,
+	};
+	struct intel_gpio *gpio;
 
-	if (HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(PCH_GMBUS0, 0);
-	} else {
-		I915_WRITE(GMBUS0, 0);
+	if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
+		return NULL;
+
+	gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
+	if (gpio == NULL)
+		return NULL;
+
+	gpio->reg = map_pin_to_reg[pin];
+	if (HAS_PCH_SPLIT(dev_priv->dev))
+		gpio->reg += PCH_GPIOA - GPIOA;
+	gpio->dev_priv = dev_priv;
+
+	snprintf(gpio->adapter.name, sizeof(gpio->adapter.name),
+		 "i915 GPIO%c", "?BACDE?F"[pin]);
+	gpio->adapter.owner = THIS_MODULE;
+	gpio->adapter.algo_data	= &gpio->algo;
+	gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
+	gpio->algo.setsda = set_data;
+	gpio->algo.setscl = set_clock;
+	gpio->algo.getsda = get_data;
+	gpio->algo.getscl = get_clock;
+	gpio->algo.udelay = I2C_RISEFALL_TIME;
+	gpio->algo.timeout = usecs_to_jiffies(2200);
+	gpio->algo.data = gpio;
+
+	if (i2c_bit_add_bus(&gpio->adapter))
+		goto out_free;
+
+	return &gpio->adapter;
+
+out_free:
+	kfree(gpio);
+	return NULL;
+}
+
+static int
+intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
+		     struct i2c_adapter *adapter,
+		     struct i2c_msg *msgs,
+		     int num)
+{
+	struct intel_gpio *gpio = container_of(adapter,
+					       struct intel_gpio,
+					       adapter);
+	int ret;
+
+	intel_i2c_reset(dev_priv->dev);
+
+	intel_i2c_quirk_set(dev_priv, true);
+	set_data(gpio, 1);
+	set_clock(gpio, 1);
+	udelay(I2C_RISEFALL_TIME);
+
+	ret = adapter->algo->master_xfer(adapter, msgs, num);
+
+	set_data(gpio, 1);
+	set_clock(gpio, 1);
+	intel_i2c_quirk_set(dev_priv, false);
+
+	return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter,
+	   struct i2c_msg *msgs,
+	   int num)
+{
+	struct intel_gmbus *bus = container_of(adapter,
+					       struct intel_gmbus,
+					       adapter);
+	struct drm_i915_private *dev_priv = adapter->algo_data;
+	int i, reg_offset;
+
+	if (bus->force_bit)
+		return intel_i2c_quirk_xfer(dev_priv,
+					    bus->force_bit, msgs, num);
+
+	reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+
+	I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+
+	for (i = 0; i < num; i++) {
+		u16 len = msgs[i].len;
+		u8 *buf = msgs[i].buf;
+
+		if (msgs[i].flags & I2C_M_RD) {
+			I915_WRITE(GMBUS1 + reg_offset,
+				   GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+				   (len << GMBUS_BYTE_COUNT_SHIFT) |
+				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+				   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+			POSTING_READ(GMBUS2+reg_offset);
+			do {
+				u32 val, loop = 0;
+
+				if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+					goto timeout;
+				if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+					return 0;
+
+				val = I915_READ(GMBUS3 + reg_offset);
+				do {
+					*buf++ = val & 0xff;
+					val >>= 8;
+				} while (--len && ++loop < 4);
+			} while (len);
+		} else {
+			u32 val, loop;
+
+			val = loop = 0;
+			do {
+				val |= *buf++ << (8 * loop);
+			} while (--len && ++loop < 4);
+
+			I915_WRITE(GMBUS3 + reg_offset, val);
+			I915_WRITE(GMBUS1 + reg_offset,
+				   (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+				   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
+				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+				   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+			POSTING_READ(GMBUS2+reg_offset);
+
+			while (len) {
+				if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+					goto timeout;
+				if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+					return 0;
+
+				val = loop = 0;
+				do {
+					val |= *buf++ << (8 * loop);
+				} while (--len && ++loop < 4);
+
+				I915_WRITE(GMBUS3 + reg_offset, val);
+				POSTING_READ(GMBUS2+reg_offset);
+			}
+		}
+
+		if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+			goto timeout;
+		if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+			return 0;
 	}
+
+	return num;
+
+timeout:
+	DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
+		 bus->reg0 & 0xff, bus->adapter.name);
+	/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+	bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
+	if (!bus->force_bit)
+		return -ENOMEM;
+
+	return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
+}
+
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+	struct intel_gmbus *bus = container_of(adapter,
+					       struct intel_gmbus,
+					       adapter);
+
+	if (bus->force_bit)
+		bus->force_bit->algo->functionality(bus->force_bit);
+
+	return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+		/* I2C_FUNC_10BIT_ADDR | */
+		I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+		I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
 }
 
+static const struct i2c_algorithm gmbus_algorithm = {
+	.master_xfer	= gmbus_xfer,
+	.functionality	= gmbus_func
+};
+
 /**
- * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
  * @dev: DRM device
- * @output: driver specific output device
- * @reg: GPIO reg to use
- * @name: name for this bus
- * @slave_addr: slave address (if fixed)
- *
- * Creates and registers a new i2c bus with the Linux i2c layer, for use
- * in output probing and control (e.g. DDC or SDVO control functions).
- *
- * Possible values for @reg include:
- *   %GPIOA
- *   %GPIOB
- *   %GPIOC
- *   %GPIOD
- *   %GPIOE
- *   %GPIOF
- *   %GPIOG
- *   %GPIOH
- * see PRM for details on how these different busses are used.
  */
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-				     const char *name)
+int intel_setup_gmbus(struct drm_device *dev)
 {
-	struct intel_i2c_chan *chan;
+	static const char *names[GMBUS_NUM_PORTS] = {
+		"disabled",
+		"ssc",
+		"vga",
+		"panel",
+		"dpc",
+		"dpb",
+		"reserved",
+		"dpd",
+	};
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret, i;
 
-	chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
-	if (!chan)
-		goto out_free;
+	dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+				  GFP_KERNEL);
+	if (dev_priv->gmbus == NULL)
+		return -ENOMEM;
 
-	chan->drm_dev = dev;
-	chan->reg = reg;
-	snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
-	chan->adapter.owner = THIS_MODULE;
-	chan->adapter.algo_data	= &chan->algo;
-	chan->adapter.dev.parent = &dev->pdev->dev;
-	chan->algo.setsda = set_data;
-	chan->algo.setscl = set_clock;
-	chan->algo.getsda = get_data;
-	chan->algo.getscl = get_clock;
-	chan->algo.udelay = 20;
-	chan->algo.timeout = usecs_to_jiffies(2200);
-	chan->algo.data = chan;
+	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
 
-	i2c_set_adapdata(&chan->adapter, chan);
+		bus->adapter.owner = THIS_MODULE;
+		bus->adapter.class = I2C_CLASS_DDC;
+		snprintf(bus->adapter.name,
+			 sizeof(bus->adapter.name),
+			 "i915 gmbus %s",
+			 names[i]);
 
-	if(i2c_bit_add_bus(&chan->adapter))
-		goto out_free;
+		bus->adapter.dev.parent = &dev->pdev->dev;
+		bus->adapter.algo_data	= dev_priv;
 
-	intel_i2c_reset_gmbus(dev);
+		bus->adapter.algo = &gmbus_algorithm;
+		ret = i2c_add_adapter(&bus->adapter);
+		if (ret)
+			goto err;
 
-	/* JJJ:  raise SCL and SDA? */
-	intel_i2c_quirk_set(dev, true);
-	set_data(chan, 1);
-	set_clock(chan, 1);
-	intel_i2c_quirk_set(dev, false);
-	udelay(20);
+		/* By default use a conservative clock rate */
+		bus->reg0 = i | GMBUS_RATE_100KHZ;
 
-	return &chan->adapter;
+		/* XXX force bit banging until GMBUS is fully debugged */
+		bus->force_bit = intel_gpio_create(dev_priv, i);
+	}
 
-out_free:
-	kfree(chan);
-	return NULL;
+	intel_i2c_reset(dev_priv->dev);
+
+	return 0;
+
+err:
+	while (--i) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
+		i2c_del_adapter(&bus->adapter);
+	}
+	kfree(dev_priv->gmbus);
+	dev_priv->gmbus = NULL;
+	return ret;
 }
 
-/**
- * intel_i2c_destroy - unregister and free i2c bus resources
- * @output: channel to free
- *
- * Unregister the adapter from the i2c layer, then free the structure.
- */
-void intel_i2c_destroy(struct i2c_adapter *adapter)
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
 {
-	struct intel_i2c_chan *chan;
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
 
-	if (!adapter)
+	/* speed:
+	 * 0x0 = 100 KHz
+	 * 0x1 = 50 KHz
+	 * 0x2 = 400 KHz
+	 * 0x3 = 1000 Khz
+	 */
+	bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8);
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+	if (force_bit) {
+		if (bus->force_bit == NULL) {
+			struct drm_i915_private *dev_priv = adapter->algo_data;
+			bus->force_bit = intel_gpio_create(dev_priv,
+							   bus->reg0 & 0xff);
+		}
+	} else {
+		if (bus->force_bit) {
+			i2c_del_adapter(bus->force_bit);
+			kfree(bus->force_bit);
+			bus->force_bit = NULL;
+		}
+	}
+}
+
+void intel_teardown_gmbus(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
+
+	if (dev_priv->gmbus == NULL)
 		return;
 
-	chan = container_of(adapter,
-			    struct intel_i2c_chan,
-			    adapter);
-	i2c_del_adapter(&chan->adapter);
-	kfree(chan);
+	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
+		if (bus->force_bit) {
+			i2c_del_adapter(bus->force_bit);
+			kfree(bus->force_bit);
+		}
+		i2c_del_adapter(&bus->adapter);
+	}
+
+	kfree(dev_priv->gmbus);
+	dev_priv->gmbus = NULL;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_lvds.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_lvds.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_lvds.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_lvds.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,102 +43,111 @@
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
 	struct intel_encoder base;
+
+	struct edid *edid;
+
 	int fitting_mode;
 	u32 pfit_control;
 	u32 pfit_pgm_ratios;
+	bool pfit_dirty;
+
+	struct drm_display_mode *fixed_mode;
 };
 
-static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
+	return container_of(encoder, struct intel_lvds, base.base);
 }
 
-/**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
- */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blc_pwm_ctl, reg;
-
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
-	else
-		reg = BLC_PWM_CTL;
-
-	blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-	I915_WRITE(reg, (blc_pwm_ctl |
-				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_lvds, base);
 }
 
 /**
- * Returns the maximum level of the backlight duty cycle field.
+ * Sets the power state for the panel.
  */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+static void intel_lvds_enable(struct intel_lvds *intel_lvds)
 {
+	struct drm_device *dev = intel_lvds->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg;
+	u32 ctl_reg, lvds_reg;
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_PCH_CTL2;
-	else
-		reg = BLC_PWM_CTL;
+	if (HAS_PCH_SPLIT(dev)) {
+		ctl_reg = PCH_PP_CONTROL;
+		lvds_reg = PCH_LVDS;
+	} else {
+		ctl_reg = PP_CONTROL;
+		lvds_reg = LVDS;
+	}
 
-	return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+	I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
+
+	if (intel_lvds->pfit_dirty) {
+		/*
+		 * Enable automatic panel scaling so that non-native modes
+		 * fill the screen.  The panel fitter should only be
+		 * adjusted whilst the pipe is disabled, according to
+		 * register description and PRM.
+		 */
+		DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+			      intel_lvds->pfit_control,
+			      intel_lvds->pfit_pgm_ratios);
+		if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) {
+			DRM_ERROR("timed out waiting for panel to power off\n");
+		} else {
+			I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
+			I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+			intel_lvds->pfit_dirty = false;
+		}
+	}
+
+	I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+	POSTING_READ(lvds_reg);
+
+	intel_panel_set_backlight(dev, dev_priv->backlight_level);
 }
 
-/**
- * Sets the power state for the panel.
- */
-static void intel_lvds_set_power(struct drm_device *dev, bool on)
+static void intel_lvds_disable(struct intel_lvds *intel_lvds)
 {
+	struct drm_device *dev = intel_lvds->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 ctl_reg, status_reg, lvds_reg;
+	u32 ctl_reg, lvds_reg;
 
 	if (HAS_PCH_SPLIT(dev)) {
 		ctl_reg = PCH_PP_CONTROL;
-		status_reg = PCH_PP_STATUS;
 		lvds_reg = PCH_LVDS;
 	} else {
 		ctl_reg = PP_CONTROL;
-		status_reg = PP_STATUS;
 		lvds_reg = LVDS;
 	}
 
-	if (on) {
-		I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
-		POSTING_READ(lvds_reg);
-
-		I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
-			   POWER_TARGET_ON);
-		if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
-			DRM_ERROR("timed out waiting to enable LVDS pipe");
+	dev_priv->backlight_level = intel_panel_get_backlight(dev);
+	intel_panel_set_backlight(dev, 0);
 
-		intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
-	} else {
-		intel_lvds_set_backlight(dev, 0);
+	I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
 
-		I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
-			   ~POWER_TARGET_ON);
-		if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
-			DRM_ERROR("timed out waiting for LVDS pipe to turn off");
+	if (intel_lvds->pfit_control) {
+		if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+			DRM_ERROR("timed out waiting for panel to power off\n");
 
-		I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
-		POSTING_READ(lvds_reg);
+		I915_WRITE(PFIT_CONTROL, 0);
+		intel_lvds->pfit_dirty = true;
 	}
+
+	I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
+	POSTING_READ(lvds_reg);
 }
 
 static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 {
-	struct drm_device *dev = encoder->dev;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
 	if (mode == DRM_MODE_DPMS_ON)
-		intel_lvds_set_power(dev, true);
+		intel_lvds_enable(intel_lvds);
 	else
-		intel_lvds_set_power(dev, false);
+		intel_lvds_disable(intel_lvds);
 
 	/* XXX: We never power down the LVDS pairs. */
 }
@@ -146,16 +155,13 @@
 static int intel_lvds_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
-	struct drm_device *dev = connector->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+	struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
 
-	if (fixed_mode)	{
-		if (mode->hdisplay > fixed_mode->hdisplay)
-			return MODE_PANEL;
-		if (mode->vdisplay > fixed_mode->vdisplay)
-			return MODE_PANEL;
-	}
+	if (mode->hdisplay > fixed_mode->hdisplay)
+		return MODE_PANEL;
+	if (mode->vdisplay > fixed_mode->vdisplay)
+		return MODE_PANEL;
 
 	return MODE_OK;
 }
@@ -223,12 +229,12 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 	struct drm_encoder *tmp_encoder;
 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 
 	/* Should never happen!! */
-	if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+	if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
 		DRM_ERROR("Can't support LVDS on pipe A\n");
 		return false;
 	}
@@ -241,9 +247,6 @@
 			return false;
 		}
 	}
-	/* If we don't have a panel mode, there is nothing we can do */
-	if (dev_priv->panel_fixed_mode == NULL)
-		return true;
 
 	/*
 	 * We have timings from the BIOS for the panel, put them in
@@ -251,7 +254,7 @@
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+	intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
 
 	if (HAS_PCH_SPLIT(dev)) {
 		intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -260,8 +263,8 @@
 	}
 
 	/* Make sure pre-965s set dither correctly */
-	if (!IS_I965G(dev)) {
-		if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+	if (INTEL_INFO(dev)->gen < 4) {
+		if (dev_priv->lvds_dither)
 			pfit_control |= PANEL_8TO6_DITHER_ENABLE;
 	}
 
@@ -271,7 +274,7 @@
 		goto out;
 
 	/* 965+ wants fuzzy fitting */
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
 				 PFIT_FILTER_FUZZY);
 
@@ -297,7 +300,7 @@
 
 	case DRM_MODE_SCALE_ASPECT:
 		/* Scale but preserve the aspect ratio */
-		if (IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen >= 4) {
 			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
 			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 
@@ -356,7 +359,7 @@
 		 * Fortunately this is all done for us in hw.
 		 */
 		pfit_control |= PFIT_ENABLE;
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			pfit_control |= PFIT_SCALING_AUTO;
 		else
 			pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -369,8 +372,12 @@
 	}
 
 out:
-	intel_lvds->pfit_control = pfit_control;
-	intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+	if (pfit_control != intel_lvds->pfit_control ||
+	    pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
+		intel_lvds->pfit_control = pfit_control;
+		intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+		intel_lvds->pfit_dirty = true;
+	}
 	dev_priv->lvds_border_bits = border;
 
 	/*
@@ -386,56 +393,71 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
-	else
-		reg = BLC_PWM_CTL;
+	dev_priv->backlight_level = intel_panel_get_backlight(dev);
 
-	dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-				       BACKLIGHT_DUTY_CYCLE_MASK);
+	/* We try to do the minimum that is necessary in order to unlock
+	 * the registers for mode setting.
+	 *
+	 * On Ironlake, this is quite simple as we just set the unlock key
+	 * and ignore all subtleties. (This may cause some issues...)
+	 *
+	 * Prior to Ironlake, we must disable the pipe if we want to adjust
+	 * the panel fitter. However at all other times we can just reset
+	 * the registers regardless.
+	 */
 
-	intel_lvds_set_power(dev, false);
+	if (HAS_PCH_SPLIT(dev)) {
+		I915_WRITE(PCH_PP_CONTROL,
+			   I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+	} else if (intel_lvds->pfit_dirty) {
+		I915_WRITE(PP_CONTROL,
+			   (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
+			   & ~POWER_TARGET_ON);
+	} else {
+		I915_WRITE(PP_CONTROL,
+			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+	}
 }
 
-static void intel_lvds_commit( struct drm_encoder *encoder)
+static void intel_lvds_commit(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-	if (dev_priv->backlight_duty_cycle == 0)
-		dev_priv->backlight_duty_cycle =
-			intel_lvds_get_max_backlight(dev);
+	if (dev_priv->backlight_level == 0)
+		dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-	intel_lvds_set_power(dev, true);
+	/* Undo any unlocking done in prepare to prevent accidental
+	 * adjustment of the registers.
+	 */
+	if (HAS_PCH_SPLIT(dev)) {
+		u32 val = I915_READ(PCH_PP_CONTROL);
+		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+			I915_WRITE(PCH_PP_CONTROL, val & 0x3);
+	} else {
+		u32 val = I915_READ(PP_CONTROL);
+		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+			I915_WRITE(PP_CONTROL, val & 0x3);
+	}
+
+	/* Always do a full power on as we do not know what state
+	 * we were left in.
+	 */
+	intel_lvds_enable(intel_lvds);
 }
 
 static void intel_lvds_mode_set(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode)
 {
-	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
-
 	/*
 	 * The LVDS pin pair will already have been turned on in the
 	 * intel_crtc_mode_set since it has a large impact on the DPLL
 	 * settings.
 	 */
-
-	if (HAS_PCH_SPLIT(dev))
-		return;
-
-	/*
-	 * Enable automatic panel scaling so that non-native modes fill the
-	 * screen.  Should be enabled before the pipe is enabled, according to
-	 * register description and PRM.
-	 */
-	I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
-	I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
 }
 
 /**
@@ -465,38 +487,19 @@
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	int ret = 0;
-
-	if (dev_priv->lvds_edid_good) {
-		ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
-
-		if (ret)
-			return ret;
-	}
-
-	/* Didn't get an EDID, so
-	 * Set wide sync ranges so we get all modes
-	 * handed to valid_mode for checking
-	 */
-	connector->display_info.min_vfreq = 0;
-	connector->display_info.max_vfreq = 200;
-	connector->display_info.min_hfreq = 0;
-	connector->display_info.max_hfreq = 200;
-
-	if (dev_priv->panel_fixed_mode != NULL) {
-		struct drm_display_mode *mode;
+	struct drm_display_mode *mode;
 
-		mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
-		drm_mode_probed_add(connector, mode);
+	if (intel_lvds->edid)
+		return drm_add_edid_modes(connector, intel_lvds->edid);
 
-		return 1;
-	}
+	mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+	if (mode == 0)
+		return 0;
 
-	return 0;
+	drm_mode_probed_add(connector, mode);
+	return 1;
 }
 
 static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
@@ -587,18 +590,17 @@
 				   struct drm_property *property,
 				   uint64_t value)
 {
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
 	struct drm_device *dev = connector->dev;
 
-	if (property == dev->mode_config.scaling_mode_property &&
-				connector->encoder) {
-		struct drm_crtc *crtc = connector->encoder->crtc;
-		struct drm_encoder *encoder = connector->encoder;
-		struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+	if (property == dev->mode_config.scaling_mode_property) {
+		struct drm_crtc *crtc = intel_lvds->base.base.crtc;
 
 		if (value == DRM_MODE_SCALE_NONE) {
 			DRM_DEBUG_KMS("no scaling not supported\n");
-			return 0;
+			return -EINVAL;
 		}
+
 		if (intel_lvds->fitting_mode == value) {
 			/* the LVDS scaling property is not changed */
 			return 0;
@@ -628,7 +630,7 @@
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
 	.get_modes = intel_lvds_get_modes,
 	.mode_valid = intel_lvds_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
@@ -726,16 +728,14 @@
  * Find the reduced downclock for LVDS in EDID.
  */
 static void intel_find_lvds_downclock(struct drm_device *dev,
-				struct drm_connector *connector)
+				      struct drm_display_mode *fixed_mode,
+				      struct drm_connector *connector)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *scan, *panel_fixed_mode;
+	struct drm_display_mode *scan;
 	int temp_downclock;
 
-	panel_fixed_mode = dev_priv->panel_fixed_mode;
-	temp_downclock = panel_fixed_mode->clock;
-
-	mutex_lock(&dev->mode_config.mutex);
+	temp_downclock = fixed_mode->clock;
 	list_for_each_entry(scan, &connector->probed_modes, head) {
 		/*
 		 * If one mode has the same resolution with the fixed_panel
@@ -744,14 +744,14 @@
 		 * case we can set the different FPx0/1 to dynamically select
 		 * between low and high frequency.
 		 */
-		if (scan->hdisplay == panel_fixed_mode->hdisplay &&
-			scan->hsync_start == panel_fixed_mode->hsync_start &&
-			scan->hsync_end == panel_fixed_mode->hsync_end &&
-			scan->htotal == panel_fixed_mode->htotal &&
-			scan->vdisplay == panel_fixed_mode->vdisplay &&
-			scan->vsync_start == panel_fixed_mode->vsync_start &&
-			scan->vsync_end == panel_fixed_mode->vsync_end &&
-			scan->vtotal == panel_fixed_mode->vtotal) {
+		if (scan->hdisplay == fixed_mode->hdisplay &&
+		    scan->hsync_start == fixed_mode->hsync_start &&
+		    scan->hsync_end == fixed_mode->hsync_end &&
+		    scan->htotal == fixed_mode->htotal &&
+		    scan->vdisplay == fixed_mode->vdisplay &&
+		    scan->vsync_start == fixed_mode->vsync_start &&
+		    scan->vsync_end == fixed_mode->vsync_end &&
+		    scan->vtotal == fixed_mode->vtotal) {
 			if (scan->clock < temp_downclock) {
 				/*
 				 * The downclock is already found. But we
@@ -761,17 +761,14 @@
 			}
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
-	if (temp_downclock < panel_fixed_mode->clock &&
-	    i915_lvds_downclock) {
+	if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
 		/* We found the downclock for LVDS. */
 		dev_priv->lvds_downclock_avail = 1;
 		dev_priv->lvds_downclock = temp_downclock;
 		DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
-				"Normal clock %dKhz, downclock %dKhz\n",
-				panel_fixed_mode->clock, temp_downclock);
+			      "Normal clock %dKhz, downclock %dKhz\n",
+			      fixed_mode->clock, temp_downclock);
 	}
-	return;
 }
 
 /*
@@ -780,38 +777,67 @@
  * If it is present, return 1.
  * If it is not present, return false.
  * If no child dev is parsed from VBT, it assumes that the LVDS is present.
- * Note: The addin_offset should also be checked for LVDS panel.
- * Only when it is non-zero, it is assumed that it is present.
  */
-static int lvds_is_present_in_vbt(struct drm_device *dev)
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+				   u8 *i2c_pin)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct child_device_config *p_child;
-	int i, ret;
+	int i;
 
 	if (!dev_priv->child_dev_num)
-		return 1;
+		return true;
 
-	ret = 0;
 	for (i = 0; i < dev_priv->child_dev_num; i++) {
-		p_child = dev_priv->child_dev + i;
-		/*
-		 * If the device type is not LFP, continue.
-		 * If the device type is 0x22, it is also regarded as LFP.
+		struct child_device_config *child = dev_priv->child_dev + i;
+
+		/* If the device type is not LFP, continue.
+		 * We have to check both the new identifiers as well as the
+		 * old for compatibility with some BIOSes.
 		 */
-		if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
-			p_child->device_type != DEVICE_TYPE_LFP)
+		if (child->device_type != DEVICE_TYPE_INT_LFP &&
+		    child->device_type != DEVICE_TYPE_LFP)
 			continue;
 
-		/* The addin_offset should be checked. Only when it is
-		 * non-zero, it is regarded as present.
+		if (child->i2c_pin)
+		    *i2c_pin = child->i2c_pin;
+
+		/* However, we cannot trust the BIOS writers to populate
+		 * the VBT correctly.  Since LVDS requires additional
+		 * information from AIM blocks, a non-zero addin offset is
+		 * a good indicator that the LVDS is actually present.
 		 */
-		if (p_child->addin_offset) {
-			ret = 1;
-			break;
-		}
+		if (child->addin_offset)
+			return true;
+
+		/* But even then some BIOS writers perform some black magic
+		 * and instantiate the device without reference to any
+		 * additional data.  Trust that if the VBT was written into
+		 * the OpRegion then they have validated the LVDS's existence.
+		 */
+		if (dev_priv->opregion.vbt)
+			return true;
 	}
-	return ret;
+
+	return false;
+}
+
+static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u8 buf = 0;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = 0xA0,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+	};
+	struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter;
+	/* XXX this only appears to work when using GMBUS */
+	if (intel_gmbus_is_forced_bit(i2c))
+		return true;
+	return i2c_transfer(i2c, msgs, 1) == 1;
 }
 
 /**
@@ -821,7 +847,7 @@
  * Create the connector, register the LVDS DDC bus, and try to figure out what
  * modes we can display on the LVDS panel (if present).
  */
-void intel_lvds_init(struct drm_device *dev)
+bool intel_lvds_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_lvds *intel_lvds;
@@ -832,48 +858,58 @@
 	struct drm_display_mode *scan; /* *modes, *bios_mode; */
 	struct drm_crtc *crtc;
 	u32 lvds;
-	int pipe, gpio = GPIOC;
+	int pipe;
+	u8 pin;
 
 	/* Skip init on machines we know falsely report LVDS */
 	if (dmi_check_system(intel_no_lvds))
-		return;
+		return false;
 
-	if (!lvds_is_present_in_vbt(dev)) {
+	pin = GMBUS_PORT_PANEL;
+	if (!lvds_is_present_in_vbt(dev, &pin)) {
 		DRM_DEBUG_KMS("LVDS is not present in VBT\n");
-		return;
+		return false;
 	}
 
 	if (HAS_PCH_SPLIT(dev)) {
 		if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
-			return;
-		if (dev_priv->edp_support) {
+			return false;
+		if (dev_priv->edp.support) {
 			DRM_DEBUG_KMS("disable LVDS for eDP support\n");
-			return;
+			return false;
 		}
-		gpio = PCH_GPIOC;
+	}
+
+	if (!intel_lvds_ddc_probe(dev, pin)) {
+		DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
+		return false;
 	}
 
 	intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
 	if (!intel_lvds) {
-		return;
+		return false;
 	}
 
 	intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
 	if (!intel_connector) {
 		kfree(intel_lvds);
-		return;
+		return false;
+	}
+
+	if (!HAS_PCH_SPLIT(dev)) {
+		intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
 	}
 
 	intel_encoder = &intel_lvds->base;
-	encoder = &intel_encoder->enc;
+	encoder = &intel_encoder->base;
 	connector = &intel_connector->base;
 	drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
 			   DRM_MODE_CONNECTOR_LVDS);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
 			 DRM_MODE_ENCODER_LVDS);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_encoder->type = INTEL_OUTPUT_LVDS;
 
 	intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
@@ -904,43 +940,50 @@
 	 *    if closed, act like it's not there for now
 	 */
 
-	/* Set up the DDC bus. */
-	intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
-	if (!intel_encoder->ddc_bus) {
-		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-			   "failed.\n");
-		goto failed;
-	}
-
 	/*
 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
 	 * preferred mode is the right one.
 	 */
-	dev_priv->lvds_edid_good = true;
-
-	if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
-		dev_priv->lvds_edid_good = false;
+	intel_lvds->edid = drm_get_edid(connector,
+					&dev_priv->gmbus[pin].adapter);
+	if (intel_lvds->edid) {
+		if (drm_add_edid_modes(connector,
+				       intel_lvds->edid)) {
+			drm_mode_connector_update_edid_property(connector,
+								intel_lvds->edid);
+		} else {
+			kfree(intel_lvds->edid);
+			intel_lvds->edid = NULL;
+		}
+	}
+	if (!intel_lvds->edid) {
+		/* Didn't get an EDID, so
+		 * Set wide sync ranges so we get all modes
+		 * handed to valid_mode for checking
+		 */
+		connector->display_info.min_vfreq = 0;
+		connector->display_info.max_vfreq = 200;
+		connector->display_info.min_hfreq = 0;
+		connector->display_info.max_hfreq = 200;
+	}
 
 	list_for_each_entry(scan, &connector->probed_modes, head) {
-		mutex_lock(&dev->mode_config.mutex);
 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
-			dev_priv->panel_fixed_mode =
+			intel_lvds->fixed_mode =
 				drm_mode_duplicate(dev, scan);
-			mutex_unlock(&dev->mode_config.mutex);
-			intel_find_lvds_downclock(dev, connector);
+			intel_find_lvds_downclock(dev,
+						  intel_lvds->fixed_mode,
+						  connector);
 			goto out;
 		}
-		mutex_unlock(&dev->mode_config.mutex);
 	}
 
 	/* Failed to get EDID, what about VBT? */
 	if (dev_priv->lfp_lvds_vbt_mode) {
-		mutex_lock(&dev->mode_config.mutex);
-		dev_priv->panel_fixed_mode =
+		intel_lvds->fixed_mode =
 			drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
-		mutex_unlock(&dev->mode_config.mutex);
-		if (dev_priv->panel_fixed_mode) {
-			dev_priv->panel_fixed_mode->type |=
+		if (intel_lvds->fixed_mode) {
+			intel_lvds->fixed_mode->type |=
 				DRM_MODE_TYPE_PREFERRED;
 			goto out;
 		}
@@ -958,19 +1001,19 @@
 
 	lvds = I915_READ(LVDS);
 	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-	crtc = intel_get_crtc_from_pipe(dev, pipe);
+	crtc = intel_get_crtc_for_pipe(dev, pipe);
 
 	if (crtc && (lvds & LVDS_PORT_EN)) {
-		dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
-		if (dev_priv->panel_fixed_mode) {
-			dev_priv->panel_fixed_mode->type |=
+		intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+		if (intel_lvds->fixed_mode) {
+			intel_lvds->fixed_mode->type |=
 				DRM_MODE_TYPE_PREFERRED;
 			goto out;
 		}
 	}
 
 	/* If we still don't have a mode after all that, give up. */
-	if (!dev_priv->panel_fixed_mode)
+	if (!intel_lvds->fixed_mode)
 		goto failed;
 
 out:
@@ -993,14 +1036,13 @@
 	/* keep the LVDS connector */
 	dev_priv->int_lvds_connector = connector;
 	drm_sysfs_connector_add(connector);
-	return;
+	return true;
 
 failed:
 	DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-	if (intel_encoder->ddc_bus)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
 	drm_connector_cleanup(connector);
 	drm_encoder_cleanup(encoder);
 	kfree(intel_lvds);
 	kfree(intel_connector);
+	return false;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_modes.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_modes.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_modes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_modes.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2007, 2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,11 +34,11 @@
  * intel_ddc_probe
  *
  */
-bool intel_ddc_probe(struct intel_encoder *intel_encoder)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 {
+	struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
 	u8 out_buf[] = { 0x0, 0x0};
 	u8 buf[2];
-	int ret;
 	struct i2c_msg msgs[] = {
 		{
 			.addr = 0x50,
@@ -54,13 +54,7 @@
 		}
 	};
 
-	intel_i2c_quirk_set(intel_encoder->enc.dev, true);
-	ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
-	intel_i2c_quirk_set(intel_encoder->enc.dev, false);
-	if (ret == 2)
-		return true;
-
-	return false;
+	return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
 }
 
 /**
@@ -76,9 +70,7 @@
 	struct edid *edid;
 	int ret = 0;
 
-	intel_i2c_quirk_set(connector->dev, true);
 	edid = drm_get_edid(connector, adapter);
-	intel_i2c_quirk_set(connector->dev, false);
 	if (edid) {
 		drm_mode_connector_update_edid_property(connector, edid);
 		ret = drm_add_edid_modes(connector, edid);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_opregion.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_opregion.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_opregion.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_opregion.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2008 Intel Corporation <hong.liu@intel.com>
+ * Copyright 2008 Red Hat <mjg@redhat.com>
+ *
+ * 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, sub license, 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 (including the
+ * next paragraph) 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
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <acpi/video.h>
+
+#include "drmP.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+#define PCI_ASLE 0xe4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET   0x100
+#define OPREGION_SWSCI_OFFSET  0x200
+#define OPREGION_ASLE_OFFSET   0x300
+#define OPREGION_VBT_OFFSET    0x400
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI      (1<<0)
+#define MBOX_SWSCI     (1<<1)
+#define MBOX_ASLE      (1<<2)
+
+struct opregion_header {
+       u8 signature[16];
+       u32 size;
+       u32 opregion_ver;
+       u8 bios_ver[32];
+       u8 vbios_ver[16];
+       u8 driver_ver[16];
+       u32 mboxes;
+       u8 reserved[164];
+} __attribute__((packed));
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+       u32 drdy;       /* driver readiness */
+       u32 csts;       /* notification status */
+       u32 cevt;       /* current event */
+       u8 rsvd1[20];
+       u32 didl[8];    /* supported display devices ID list */
+       u32 cpdl[8];    /* currently presented display list */
+       u32 cadl[8];    /* currently active display list */
+       u32 nadl[8];    /* next active devices list */
+       u32 aslp;       /* ASL sleep time-out */
+       u32 tidx;       /* toggle table index */
+       u32 chpd;       /* current hotplug enable indicator */
+       u32 clid;       /* current lid state*/
+       u32 cdck;       /* current docking state */
+       u32 sxsw;       /* Sx state resume */
+       u32 evts;       /* ASL supported events */
+       u32 cnot;       /* current OS notification */
+       u32 nrdy;       /* driver status */
+       u8 rsvd2[60];
+} __attribute__((packed));
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+       u32 scic;       /* SWSCI command|status|data */
+       u32 parm;       /* command parameters */
+       u32 dslp;       /* driver sleep time-out */
+       u8 rsvd[244];
+} __attribute__((packed));
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+       u32 ardy;       /* driver readiness */
+       u32 aslc;       /* ASLE interrupt command */
+       u32 tche;       /* technology enabled indicator */
+       u32 alsi;       /* current ALS illuminance reading */
+       u32 bclp;       /* backlight brightness to set */
+       u32 pfit;       /* panel fitting state */
+       u32 cblv;       /* current brightness level */
+       u16 bclm[20];   /* backlight level duty cycle mapping table */
+       u32 cpfm;       /* current panel fitting mode */
+       u32 epfm;       /* enabled panel fitting modes */
+       u8 plut[74];    /* panel LUT and identifier */
+       u32 pfmb;       /* PWM freq and min brightness */
+       u8 rsvd[102];
+} __attribute__((packed));
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM     (1 << 0)
+#define ASLE_SET_BACKLIGHT     (1 << 1)
+#define ASLE_SET_PFIT          (1 << 2)
+#define ASLE_SET_PWM_FREQ      (1 << 3)
+#define ASLE_REQ_MSK           0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED	(1<<10)
+#define ASLE_BACKLIGHT_FAILED	(1<<12)
+#define ASLE_PFIT_FAILED	(1<<14)
+#define ASLE_PWM_FREQ_FAILED	(1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID                (1<<31)
+#define ASLE_BCLP_MSK          (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID         (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID         (1<<31)
+
+#define ACPI_OTHER_OUTPUT (0<<8)
+#define ACPI_VGA_OUTPUT (1<<8)
+#define ACPI_TV_OUTPUT (2<<8)
+#define ACPI_DIGITAL_OUTPUT (3<<8)
+#define ACPI_LVDS_OUTPUT (4<<8)
+
+#ifdef CONFIG_ACPI
+static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct opregion_asle *asle = dev_priv->opregion.asle;
+	u32 max;
+
+	if (!(bclp & ASLE_BCLP_VALID))
+		return ASLE_BACKLIGHT_FAILED;
+
+	bclp &= ASLE_BCLP_MSK;
+	if (bclp > 255)
+		return ASLE_BACKLIGHT_FAILED;
+
+	max = intel_panel_get_max_backlight(dev);
+	intel_panel_set_backlight(dev, bclp * max / 255);
+	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+
+	return 0;
+}
+
+static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
+{
+	/* alsi is the current ALS reading in lux. 0 indicates below sensor
+	   range, 0xffff indicates above sensor range. 1-0xfffe are valid */
+	return 0;
+}
+
+static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (pfmb & ASLE_PFMB_PWM_VALID) {
+		u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
+		u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
+		blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
+		pwm = pwm >> 9;
+		/* FIXME - what do we do with the PWM? */
+	}
+	return 0;
+}
+
+static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
+{
+	/* Panel fitting is currently controlled by the X code, so this is a
+	   noop until modesetting support works fully */
+	if (!(pfit & ASLE_PFIT_VALID))
+		return ASLE_PFIT_FAILED;
+	return 0;
+}
+
+void intel_opregion_asle_intr(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct opregion_asle *asle = dev_priv->opregion.asle;
+	u32 asle_stat = 0;
+	u32 asle_req;
+
+	if (!asle)
+		return;
+
+	asle_req = asle->aslc & ASLE_REQ_MSK;
+
+	if (!asle_req) {
+		DRM_DEBUG_DRIVER("non asle set request??\n");
+		return;
+	}
+
+	if (asle_req & ASLE_SET_ALS_ILLUM)
+		asle_stat |= asle_set_als_illum(dev, asle->alsi);
+
+	if (asle_req & ASLE_SET_BACKLIGHT)
+		asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+	if (asle_req & ASLE_SET_PFIT)
+		asle_stat |= asle_set_pfit(dev, asle->pfit);
+
+	if (asle_req & ASLE_SET_PWM_FREQ)
+		asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+
+	asle->aslc = asle_stat;
+}
+
+/* Only present on Ironlake+ */
+void intel_opregion_gse_intr(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct opregion_asle *asle = dev_priv->opregion.asle;
+	u32 asle_stat = 0;
+	u32 asle_req;
+
+	if (!asle)
+		return;
+
+	asle_req = asle->aslc & ASLE_REQ_MSK;
+
+	if (!asle_req) {
+		DRM_DEBUG_DRIVER("non asle set request??\n");
+		return;
+	}
+
+	if (asle_req & ASLE_SET_ALS_ILLUM) {
+		DRM_DEBUG_DRIVER("Illum is not supported\n");
+		asle_stat |= ASLE_ALS_ILLUM_FAILED;
+	}
+
+	if (asle_req & ASLE_SET_BACKLIGHT)
+		asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+	if (asle_req & ASLE_SET_PFIT) {
+		DRM_DEBUG_DRIVER("Pfit is not supported\n");
+		asle_stat |= ASLE_PFIT_FAILED;
+	}
+
+	if (asle_req & ASLE_SET_PWM_FREQ) {
+		DRM_DEBUG_DRIVER("PWM freq is not supported\n");
+		asle_stat |= ASLE_PWM_FREQ_FAILED;
+	}
+
+	asle->aslc = asle_stat;
+}
+#define ASLE_ALS_EN    (1<<0)
+#define ASLE_BLC_EN    (1<<1)
+#define ASLE_PFIT_EN   (1<<2)
+#define ASLE_PFMB_EN   (1<<3)
+
+void intel_opregion_enable_asle(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct opregion_asle *asle = dev_priv->opregion.asle;
+
+	if (asle) {
+		if (IS_MOBILE(dev)) {
+			unsigned long irqflags;
+
+			spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+			intel_enable_asle(dev);
+			spin_unlock_irqrestore(&dev_priv->user_irq_lock,
+					       irqflags);
+		}
+
+		asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+			ASLE_PFMB_EN;
+		asle->ardy = 1;
+	}
+}
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID            (1<<1)
+#define ACPI_EV_DOCK           (1<<2)
+
+static struct intel_opregion *system_opregion;
+
+static int intel_opregion_video_event(struct notifier_block *nb,
+				      unsigned long val, void *data)
+{
+	/* The only video events relevant to opregion are 0x80. These indicate
+	   either a docking event, lid switch or display switch request. In
+	   Linux, these are handled by the dock, button and video drivers.
+	   We might want to fix the video driver to be opregion-aware in
+	   future, but right now we just indicate to the firmware that the
+	   request has been handled */
+
+	struct opregion_acpi *acpi;
+
+	if (!system_opregion)
+		return NOTIFY_DONE;
+
+	acpi = system_opregion->acpi;
+	acpi->csts = 0;
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block intel_opregion_notifier = {
+	.notifier_call = intel_opregion_video_event,
+};
+
+/*
+ * Initialise the DIDL field in opregion. This passes a list of devices to
+ * the firmware. Values are defined by section B.4.2 of the ACPI specification
+ * (version 3)
+ */
+
+static void intel_didl_outputs(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+	struct drm_connector *connector;
+	acpi_handle handle;
+	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
+	unsigned long long device_id;
+	acpi_status status;
+	int i = 0;
+
+	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
+	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
+		return;
+
+	if (acpi_is_video_device(acpi_dev))
+		acpi_video_bus = acpi_dev;
+	else {
+		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
+			if (acpi_is_video_device(acpi_cdev)) {
+				acpi_video_bus = acpi_cdev;
+				break;
+			}
+		}
+	}
+
+	if (!acpi_video_bus) {
+		printk(KERN_WARNING "No ACPI video bus found\n");
+		return;
+	}
+
+	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
+		if (i >= 8) {
+			dev_printk (KERN_ERR, &dev->pdev->dev,
+				    "More than 8 outputs detected\n");
+			return;
+		}
+		status =
+			acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
+						NULL, &device_id);
+		if (ACPI_SUCCESS(status)) {
+			if (!device_id)
+				goto blind_set;
+			opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+			i++;
+		}
+	}
+
+end:
+	/* If fewer than 8 outputs, the list must be null terminated */
+	if (i < 8)
+		opregion->acpi->didl[i] = 0;
+	return;
+
+blind_set:
+	i = 0;
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		int output_type = ACPI_OTHER_OUTPUT;
+		if (i >= 8) {
+			dev_printk (KERN_ERR, &dev->pdev->dev,
+				    "More than 8 outputs detected\n");
+			return;
+		}
+		switch (connector->connector_type) {
+		case DRM_MODE_CONNECTOR_VGA:
+		case DRM_MODE_CONNECTOR_DVIA:
+			output_type = ACPI_VGA_OUTPUT;
+			break;
+		case DRM_MODE_CONNECTOR_Composite:
+		case DRM_MODE_CONNECTOR_SVIDEO:
+		case DRM_MODE_CONNECTOR_Component:
+		case DRM_MODE_CONNECTOR_9PinDIN:
+			output_type = ACPI_TV_OUTPUT;
+			break;
+		case DRM_MODE_CONNECTOR_DVII:
+		case DRM_MODE_CONNECTOR_DVID:
+		case DRM_MODE_CONNECTOR_DisplayPort:
+		case DRM_MODE_CONNECTOR_HDMIA:
+		case DRM_MODE_CONNECTOR_HDMIB:
+			output_type = ACPI_DIGITAL_OUTPUT;
+			break;
+		case DRM_MODE_CONNECTOR_LVDS:
+			output_type = ACPI_LVDS_OUTPUT;
+			break;
+		}
+		opregion->acpi->didl[i] |= (1<<31) | output_type | i;
+		i++;
+	}
+	goto end;
+}
+
+void intel_opregion_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+
+	if (!opregion->header)
+		return;
+
+	if (opregion->acpi) {
+		if (drm_core_check_feature(dev, DRIVER_MODESET))
+			intel_didl_outputs(dev);
+
+		/* Notify BIOS we are ready to handle ACPI video ext notifs.
+		 * Right now, all the events are handled by the ACPI video module.
+		 * We don't actually need to do anything with them. */
+		opregion->acpi->csts = 0;
+		opregion->acpi->drdy = 1;
+
+		system_opregion = opregion;
+		register_acpi_notifier(&intel_opregion_notifier);
+	}
+
+	if (opregion->asle)
+		intel_opregion_enable_asle(dev);
+}
+
+void intel_opregion_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+
+	if (!opregion->header)
+		return;
+
+	if (opregion->acpi) {
+		opregion->acpi->drdy = 0;
+
+		system_opregion = NULL;
+		unregister_acpi_notifier(&intel_opregion_notifier);
+	}
+
+	/* just clear all opregion memory pointers now */
+	iounmap(opregion->header);
+	opregion->header = NULL;
+	opregion->acpi = NULL;
+	opregion->swsci = NULL;
+	opregion->asle = NULL;
+	opregion->vbt = NULL;
+}
+#endif
+
+int intel_opregion_setup(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+	void *base;
+	u32 asls, mboxes;
+	int err = 0;
+
+	pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
+	DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
+	if (asls == 0) {
+		DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
+		return -ENOTSUPP;
+	}
+
+	base = ioremap(asls, OPREGION_SIZE);
+	if (!base)
+		return -ENOMEM;
+
+	if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+		DRM_DEBUG_DRIVER("opregion signature mismatch\n");
+		err = -EINVAL;
+		goto err_out;
+	}
+	opregion->header = base;
+	opregion->vbt = base + OPREGION_VBT_OFFSET;
+
+	mboxes = opregion->header->mboxes;
+	if (mboxes & MBOX_ACPI) {
+		DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
+		opregion->acpi = base + OPREGION_ACPI_OFFSET;
+	}
+
+	if (mboxes & MBOX_SWSCI) {
+		DRM_DEBUG_DRIVER("SWSCI supported\n");
+		opregion->swsci = base + OPREGION_SWSCI_OFFSET;
+	}
+	if (mboxes & MBOX_ASLE) {
+		DRM_DEBUG_DRIVER("ASLE supported\n");
+		opregion->asle = base + OPREGION_ASLE_OFFSET;
+	}
+
+	return 0;
+
+err_out:
+	iounmap(base);
+	return err;
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_overlay.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_overlay.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_overlay.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_overlay.c	2011-01-04 19:50:19.000000000 -0500
@@ -170,57 +170,143 @@
     u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
 };
 
-/* overlay flip addr flag */
-#define OFC_UPDATE		0x1
-
-#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
-
+struct intel_overlay {
+	struct drm_device *dev;
+	struct intel_crtc *crtc;
+	struct drm_i915_gem_object *vid_bo;
+	struct drm_i915_gem_object *old_vid_bo;
+	int active;
+	int pfit_active;
+	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
+	u32 color_key;
+	u32 brightness, contrast, saturation;
+	u32 old_xscale, old_yscale;
+	/* register access */
+	u32 flip_addr;
+	struct drm_i915_gem_object *reg_bo;
+	/* flip handling */
+	uint32_t last_flip_req;
+	void (*flip_tail)(struct intel_overlay *);
+};
 
-static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+static struct overlay_registers *
+intel_overlay_map_regs(struct intel_overlay *overlay)
 {
         drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 	struct overlay_registers *regs;
 
-	/* no recursive mappings */
-	BUG_ON(overlay->virt_addr);
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		regs = overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
+					 overlay->reg_bo->gtt_offset);
 
-	if (OVERLAY_NONPHYSICAL(overlay->dev)) {
-		regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-						overlay->reg_bo->gtt_offset,
-						KM_USER0);
+	return regs;
+}
 
-		if (!regs) {
-			DRM_ERROR("failed to map overlay regs in GTT\n");
-			return NULL;
-		}
-	} else
-		regs = overlay->reg_bo->phys_obj->handle->vaddr;
+static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
+				     struct overlay_registers *regs)
+{
+	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		io_mapping_unmap(regs);
+}
 
-	return overlay->virt_addr = regs;
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+					 struct drm_i915_gem_request *request,
+					 bool interruptible,
+					 void (*tail)(struct intel_overlay *))
+{
+	struct drm_device *dev = overlay->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	BUG_ON(overlay->last_flip_req);
+	overlay->last_flip_req =
+		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+	if (overlay->last_flip_req == 0)
+		return -ENOMEM;
+
+	overlay->flip_tail = tail;
+	ret = i915_do_wait_request(dev,
+				   overlay->last_flip_req, true,
+				   &dev_priv->render_ring);
+	if (ret)
+		return ret;
+
+	overlay->last_flip_req = 0;
+	return 0;
 }
 
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
 {
-	if (OVERLAY_NONPHYSICAL(overlay->dev))
-		io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc;
+	struct drm_crtc_helper_funcs *crtc_funcs;
+	struct drm_display_mode vesa_640x480 = {
+		DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+			 752, 800, 0, 480, 489, 492, 525, 0,
+			 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+	}, *mode;
 
-	overlay->virt_addr = NULL;
+	crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+	if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+		return 0;
 
-	return;
+	/* most i8xx have pipe a forced on, so don't trust dpms mode */
+	if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
+		return 0;
+
+	crtc_funcs = crtc->base.helper_private;
+	if (crtc_funcs->dpms == NULL)
+		return 0;
+
+	DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+	mode = drm_mode_duplicate(dev, &vesa_640x480);
+	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+	if(!drm_crtc_helper_set_mode(&crtc->base, mode,
+				       crtc->base.x, crtc->base.y,
+				       crtc->base.fb))
+		return 0;
+
+	crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+	return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
 	struct drm_device *dev = overlay->dev;
+	struct drm_i915_gem_request *request;
+	int pipe_a_quirk = 0;
 	int ret;
-	drm_i915_private_t *dev_priv = dev->dev_private;
 
 	BUG_ON(overlay->active);
-
 	overlay->active = 1;
-	overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
+
+	if (IS_I830(dev)) {
+		pipe_a_quirk = i830_activate_pipe_a(dev);
+		if (pipe_a_quirk < 0)
+			return pipe_a_quirk;
+	}
+
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	BEGIN_LP_RING(4);
 	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
@@ -229,32 +315,30 @@
 	OUT_RING(MI_NOOP);
 	ADVANCE_LP_RING();
 
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev,
-			overlay->last_flip_req, 1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
+	ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
+out:
+	if (pipe_a_quirk)
+		i830_deactivate_pipe_a(dev);
 
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
-	return 0;
+	return ret;
 }
 
 /* overlay needs to be enabled in OCMD reg */
-static void intel_overlay_continue(struct intel_overlay *overlay,
-			    bool load_polyphase_filter)
+static int intel_overlay_continue(struct intel_overlay *overlay,
+				  bool load_polyphase_filter)
 {
 	struct drm_device *dev = overlay->dev;
         drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_request *request;
 	u32 flip_addr = overlay->flip_addr;
 	u32 tmp;
 
 	BUG_ON(!overlay->active);
 
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
+
 	if (load_polyphase_filter)
 		flip_addr |= OFC_UPDATE;
 
@@ -269,220 +353,132 @@
         ADVANCE_LP_RING();
 
 	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
+		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+	return 0;
 }
 
-static int intel_overlay_wait_flip(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 {
-	struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
-	u32 tmp;
-
-	if (overlay->last_flip_req != 0) {
-		ret = i915_do_wait_request(dev, overlay->last_flip_req,
-				1, &dev_priv->render_ring);
-		if (ret == 0) {
-			overlay->last_flip_req = 0;
-
-			tmp = I915_READ(ISR);
+	struct drm_gem_object *obj = &overlay->old_vid_bo->base;
 
-			if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
-				return 0;
-		}
-	}
+	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(obj);
 
-	/* synchronous slowpath */
-	overlay->hw_wedged = RELEASE_OLD_VID;
+	overlay->old_vid_bo = NULL;
+}
 
-	BEGIN_LP_RING(2);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
+static void intel_overlay_off_tail(struct intel_overlay *overlay)
+{
+	struct drm_gem_object *obj;
 
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
+	/* never have the overlay hw on without showing a frame */
+	BUG_ON(!overlay->vid_bo);
+	obj = &overlay->vid_bo->base;
 
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
+	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(obj);
+	overlay->vid_bo = NULL;
 
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
-	return 0;
+	overlay->crtc->overlay = NULL;
+	overlay->crtc = NULL;
+	overlay->active = 0;
 }
 
 /* overlay needs to be disabled in OCMD reg */
-static int intel_overlay_off(struct intel_overlay *overlay)
+static int intel_overlay_off(struct intel_overlay *overlay,
+			     bool interruptible)
 {
-	u32 flip_addr = overlay->flip_addr;
 	struct drm_device *dev = overlay->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
+	u32 flip_addr = overlay->flip_addr;
+	struct drm_i915_gem_request *request;
 
 	BUG_ON(!overlay->active);
 
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
+
 	/* According to intel docs the overlay hw may hang (when switching
 	 * off) without loading the filter coeffs. It is however unclear whether
 	 * this applies to the disabling of the overlay or to the switching off
 	 * of the hw. Do it in both cases */
 	flip_addr |= OFC_UPDATE;
 
+	BEGIN_LP_RING(6);
 	/* wait for overlay to go idle */
-	overlay->hw_wedged = SWITCH_OFF_STAGE_1;
-
-	BEGIN_LP_RING(4);
 	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
 	OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
-
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
+	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
 	/* turn overlay off */
-	overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-	BEGIN_LP_RING(4);
-        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
 	OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
+	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
 	ADVANCE_LP_RING();
 
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
-	return ret;
-}
-
-static void intel_overlay_off_tail(struct intel_overlay *overlay)
-{
-	struct drm_gem_object *obj;
-
-	/* never have the overlay hw on without showing a frame */
-	BUG_ON(!overlay->vid_bo);
-	obj = &overlay->vid_bo->base;
-
-	i915_gem_object_unpin(obj);
-	drm_gem_object_unreference(obj);
-	overlay->vid_bo = NULL;
-
-	overlay->crtc->overlay = NULL;
-	overlay->crtc = NULL;
-	overlay->active = 0;
+	return intel_overlay_do_wait_request(overlay, request, interruptible,
+					     intel_overlay_off_tail);
 }
 
 /* recover from an interruption due to a signal
  * We have to be careful not to repeat work forever an make forward progess. */
-int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-					 int interruptible)
+static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
+						bool interruptible)
 {
 	struct drm_device *dev = overlay->dev;
-	struct drm_gem_object *obj;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 flip_addr;
 	int ret;
 
-	if (overlay->hw_wedged == HW_WEDGED)
-		return -EIO;
-
-	if (overlay->last_flip_req == 0) {
-		overlay->last_flip_req =
-			i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-		if (overlay->last_flip_req == 0)
-			return -ENOMEM;
-	}
+	if (overlay->last_flip_req == 0)
+		return 0;
 
 	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			interruptible, &dev_priv->render_ring);
-	if (ret != 0)
+				   interruptible, &dev_priv->render_ring);
+	if (ret)
 		return ret;
 
-	switch (overlay->hw_wedged) {
-		case RELEASE_OLD_VID:
-			obj = &overlay->old_vid_bo->base;
-			i915_gem_object_unpin(obj);
-			drm_gem_object_unreference(obj);
-			overlay->old_vid_bo = NULL;
-			break;
-		case SWITCH_OFF_STAGE_1:
-			flip_addr = overlay->flip_addr;
-			flip_addr |= OFC_UPDATE;
-
-			overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-			BEGIN_LP_RING(4);
-			OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-			OUT_RING(flip_addr);
-			OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-			OUT_RING(MI_NOOP);
-			ADVANCE_LP_RING();
-
-			overlay->last_flip_req = i915_add_request(dev, NULL,
-					0, &dev_priv->render_ring);
-			if (overlay->last_flip_req == 0)
-				return -ENOMEM;
-
-			ret = i915_do_wait_request(dev, overlay->last_flip_req,
-					interruptible, &dev_priv->render_ring);
-			if (ret != 0)
-				return ret;
-
-		case SWITCH_OFF_STAGE_2:
-			intel_overlay_off_tail(overlay);
-			break;
-		default:
-			BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
-	}
+	if (overlay->flip_tail)
+		overlay->flip_tail(overlay);
 
-	overlay->hw_wedged = 0;
 	overlay->last_flip_req = 0;
 	return 0;
 }
 
 /* Wait for pending overlay flip and release old frame.
  * Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs_atomic */
+ * via intel_overlay_(un)map_regs
+ */
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
+	struct drm_device *dev = overlay->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
-	struct drm_gem_object *obj;
 
-	/* only wait if there is actually an old frame to release to
-	 * guarantee forward progress */
+	/* Only wait if there is actually an old frame to release to
+	 * guarantee forward progress.
+	 */
 	if (!overlay->old_vid_bo)
 		return 0;
 
-	ret = intel_overlay_wait_flip(overlay);
-	if (ret != 0)
-		return ret;
+	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
+		struct drm_i915_gem_request *request;
 
-	obj = &overlay->old_vid_bo->base;
-	i915_gem_object_unpin(obj);
-	drm_gem_object_unreference(obj);
-	overlay->old_vid_bo = NULL;
+		/* synchronous slowpath */
+		request = kzalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return -ENOMEM;
+
+		BEGIN_LP_RING(2);
+		OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+		OUT_RING(MI_NOOP);
+		ADVANCE_LP_RING();
 
+		ret = intel_overlay_do_wait_request(overlay, request, true,
+						    intel_overlay_release_old_vid_tail);
+		if (ret)
+			return ret;
+	}
+
+	intel_overlay_release_old_vid_tail(overlay);
 	return 0;
 }
 
@@ -506,65 +502,65 @@
 static int packed_depth_bytes(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-			return 4;
-		case I915_OVERLAY_YUV411:
-			/* return 6; not implemented */
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+		return 4;
+	case I915_OVERLAY_YUV411:
+		/* return 6; not implemented */
+	default:
+		return -EINVAL;
 	}
 }
 
 static int packed_width_bytes(u32 format, short width)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-			return width << 1;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+		return width << 1;
+	default:
+		return -EINVAL;
 	}
 }
 
 static int uv_hsubsampling(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-		case I915_OVERLAY_YUV420:
-			return 2;
-		case I915_OVERLAY_YUV411:
-		case I915_OVERLAY_YUV410:
-			return 4;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+	case I915_OVERLAY_YUV420:
+		return 2;
+	case I915_OVERLAY_YUV411:
+	case I915_OVERLAY_YUV410:
+		return 4;
+	default:
+		return -EINVAL;
 	}
 }
 
 static int uv_vsubsampling(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV420:
-		case I915_OVERLAY_YUV410:
-			return 2;
-		case I915_OVERLAY_YUV422:
-		case I915_OVERLAY_YUV411:
-			return 1;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV420:
+	case I915_OVERLAY_YUV410:
+		return 2;
+	case I915_OVERLAY_YUV422:
+	case I915_OVERLAY_YUV411:
+		return 1;
+	default:
+		return -EINVAL;
 	}
 }
 
 static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
 {
 	u32 mask, shift, ret;
-	if (IS_I9XX(dev)) {
-		mask = 0x3f;
-		shift = 6;
-	} else {
+	if (IS_GEN2(dev)) {
 		mask = 0x1f;
 		shift = 5;
+	} else {
+		mask = 0x3f;
+		shift = 6;
 	}
 	ret = ((offset + width + mask) >> shift) - (offset >> shift);
-	if (IS_I9XX(dev))
+	if (!IS_GEN2(dev))
 		ret <<= 1;
 	ret -=1;
 	return ret << 2;
@@ -587,7 +583,9 @@
 	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
 	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
 	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
-	0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
+	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
+};
+
 static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
 	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
 	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
@@ -597,7 +595,8 @@
 	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
 	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
 	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
-	0x3000, 0x0800, 0x3000};
+	0x3000, 0x0800, 0x3000
+};
 
 static void update_polyphase_filter(struct overlay_registers *regs)
 {
@@ -630,29 +629,31 @@
 		yscale = 1 << FP_SHIFT;
 
 	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
-		xscale_UV = xscale/uv_hscale;
-		yscale_UV = yscale/uv_vscale;
-		/* make the Y scale to UV scale ratio an exact multiply */
-		xscale = xscale_UV * uv_hscale;
-		yscale = yscale_UV * uv_vscale;
+	xscale_UV = xscale/uv_hscale;
+	yscale_UV = yscale/uv_vscale;
+	/* make the Y scale to UV scale ratio an exact multiply */
+	xscale = xscale_UV * uv_hscale;
+	yscale = yscale_UV * uv_vscale;
 	/*} else {
-		xscale_UV = 0;
-		yscale_UV = 0;
-	}*/
+	  xscale_UV = 0;
+	  yscale_UV = 0;
+	  }*/
 
 	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
 		scale_changed = true;
 	overlay->old_xscale = xscale;
 	overlay->old_yscale = yscale;
 
-	regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
-		| ((xscale >> FP_SHIFT) << 16)
-		| ((xscale & FRACT_MASK) << 3);
-	regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
-		| ((xscale_UV >> FP_SHIFT) << 16)
-		| ((xscale_UV & FRACT_MASK) << 3);
-	regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
-		| ((yscale_UV >> FP_SHIFT) << 0);
+	regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
+			   ((xscale >> FP_SHIFT)  << 16) |
+			   ((xscale & FRACT_MASK) << 3));
+
+	regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
+			 ((xscale_UV >> FP_SHIFT)  << 16) |
+			 ((xscale_UV & FRACT_MASK) << 3));
+
+	regs->UVSCALEV = ((((yscale    >> FP_SHIFT) << 16) |
+			   ((yscale_UV >> FP_SHIFT) << 0)));
 
 	if (scale_changed)
 		update_polyphase_filter(regs);
@@ -664,22 +665,28 @@
 			    struct overlay_registers *regs)
 {
 	u32 key = overlay->color_key;
+
 	switch (overlay->crtc->base.fb->bits_per_pixel) {
-		case 8:
-			regs->DCLRKV = 0;
-			regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
-		case 16:
-			if (overlay->crtc->base.fb->depth == 15) {
-				regs->DCLRKV = RGB15_TO_COLORKEY(key);
-				regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
-			} else {
-				regs->DCLRKV = RGB16_TO_COLORKEY(key);
-				regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
-			}
-		case 24:
-		case 32:
-			regs->DCLRKV = key;
-			regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+	case 8:
+		regs->DCLRKV = 0;
+		regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+		break;
+
+	case 16:
+		if (overlay->crtc->base.fb->depth == 15) {
+			regs->DCLRKV = RGB15_TO_COLORKEY(key);
+			regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+		} else {
+			regs->DCLRKV = RGB16_TO_COLORKEY(key);
+			regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+		}
+		break;
+
+	case 24:
+	case 32:
+		regs->DCLRKV = key;
+		regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+		break;
 	}
 }
 
@@ -689,48 +696,48 @@
 
 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-			case I915_OVERLAY_YUV422:
-				cmd |= OCMD_YUV_422_PLANAR;
-				break;
-			case I915_OVERLAY_YUV420:
-				cmd |= OCMD_YUV_420_PLANAR;
-				break;
-			case I915_OVERLAY_YUV411:
-			case I915_OVERLAY_YUV410:
-				cmd |= OCMD_YUV_410_PLANAR;
-				break;
+		case I915_OVERLAY_YUV422:
+			cmd |= OCMD_YUV_422_PLANAR;
+			break;
+		case I915_OVERLAY_YUV420:
+			cmd |= OCMD_YUV_420_PLANAR;
+			break;
+		case I915_OVERLAY_YUV411:
+		case I915_OVERLAY_YUV410:
+			cmd |= OCMD_YUV_410_PLANAR;
+			break;
 		}
 	} else { /* YUV packed */
 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-			case I915_OVERLAY_YUV422:
-				cmd |= OCMD_YUV_422_PACKED;
-				break;
-			case I915_OVERLAY_YUV411:
-				cmd |= OCMD_YUV_411_PACKED;
-				break;
+		case I915_OVERLAY_YUV422:
+			cmd |= OCMD_YUV_422_PACKED;
+			break;
+		case I915_OVERLAY_YUV411:
+			cmd |= OCMD_YUV_411_PACKED;
+			break;
 		}
 
 		switch (params->format & I915_OVERLAY_SWAP_MASK) {
-			case I915_OVERLAY_NO_SWAP:
-				break;
-			case I915_OVERLAY_UV_SWAP:
-				cmd |= OCMD_UV_SWAP;
-				break;
-			case I915_OVERLAY_Y_SWAP:
-				cmd |= OCMD_Y_SWAP;
-				break;
-			case I915_OVERLAY_Y_AND_UV_SWAP:
-				cmd |= OCMD_Y_AND_UV_SWAP;
-				break;
+		case I915_OVERLAY_NO_SWAP:
+			break;
+		case I915_OVERLAY_UV_SWAP:
+			cmd |= OCMD_UV_SWAP;
+			break;
+		case I915_OVERLAY_Y_SWAP:
+			cmd |= OCMD_Y_SWAP;
+			break;
+		case I915_OVERLAY_Y_AND_UV_SWAP:
+			cmd |= OCMD_Y_AND_UV_SWAP;
+			break;
 		}
 	}
 
 	return cmd;
 }
 
-int intel_overlay_do_put_image(struct intel_overlay *overlay,
-			       struct drm_gem_object *new_bo,
-			       struct put_image_params *params)
+static int intel_overlay_do_put_image(struct intel_overlay *overlay,
+				      struct drm_gem_object *new_bo,
+				      struct put_image_params *params)
 {
 	int ret, tmp_width;
 	struct overlay_registers *regs;
@@ -755,24 +762,24 @@
 		goto out_unpin;
 
 	if (!overlay->active) {
-		regs = intel_overlay_map_regs_atomic(overlay);
+		regs = intel_overlay_map_regs(overlay);
 		if (!regs) {
 			ret = -ENOMEM;
 			goto out_unpin;
 		}
 		regs->OCONFIG = OCONF_CC_OUT_8BIT;
-		if (IS_I965GM(overlay->dev))
+		if (IS_GEN4(overlay->dev))
 			regs->OCONFIG |= OCONF_CSC_MODE_BT709;
 		regs->OCONFIG |= overlay->crtc->pipe == 0 ?
 			OCONF_PIPE_A : OCONF_PIPE_B;
-		intel_overlay_unmap_regs_atomic(overlay);
+		intel_overlay_unmap_regs(overlay, regs);
 
 		ret = intel_overlay_on(overlay);
 		if (ret != 0)
 			goto out_unpin;
 	}
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	if (!regs) {
 		ret = -ENOMEM;
 		goto out_unpin;
@@ -788,7 +795,7 @@
 
 	regs->SWIDTH = params->src_w;
 	regs->SWIDTHSW = calc_swidthsw(overlay->dev,
-			params->offset_Y, tmp_width);
+				       params->offset_Y, tmp_width);
 	regs->SHEIGHT = params->src_h;
 	regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
 	regs->OSTRIDE = params->stride_Y;
@@ -799,9 +806,9 @@
 		u32 tmp_U, tmp_V;
 		regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
 		tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
-				params->src_w/uv_hscale);
+				      params->src_w/uv_hscale);
 		tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
-				params->src_w/uv_hscale);
+				      params->src_w/uv_hscale);
 		regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
 		regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
 		regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
@@ -815,9 +822,11 @@
 
 	regs->OCMD = overlay_cmd_reg(params);
 
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
-	intel_overlay_continue(overlay, scale_changed);
+	ret = intel_overlay_continue(overlay, scale_changed);
+	if (ret)
+		goto out_unpin;
 
 	overlay->old_vid_bo = overlay->vid_bo;
 	overlay->vid_bo = to_intel_bo(new_bo);
@@ -829,20 +838,19 @@
 	return ret;
 }
 
-int intel_overlay_switch_off(struct intel_overlay *overlay)
+int intel_overlay_switch_off(struct intel_overlay *overlay,
+			     bool interruptible)
 {
-	int ret;
 	struct overlay_registers *regs;
 	struct drm_device *dev = overlay->dev;
+	int ret;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
-	if (overlay->hw_wedged) {
-		ret = intel_overlay_recover_from_interrupt(overlay, 1);
-		if (ret != 0)
-			return ret;
-	}
+	ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
+	if (ret != 0)
+		return ret;
 
 	if (!overlay->active)
 		return 0;
@@ -851,33 +859,29 @@
 	if (ret != 0)
 		return ret;
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	regs->OCMD = 0;
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
-	ret = intel_overlay_off(overlay);
+	ret = intel_overlay_off(overlay, interruptible);
 	if (ret != 0)
 		return ret;
 
 	intel_overlay_off_tail(overlay);
-
 	return 0;
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
 					  struct intel_crtc *crtc)
 {
-        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
-	u32 pipeconf;
-	int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
+	drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 
-	if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
+	if (!crtc->active)
 		return -EINVAL;
 
-	pipeconf = I915_READ(pipeconf_reg);
-
 	/* can't use the overlay with double wide pipe */
-	if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
+	if (INTEL_INFO(overlay->dev)->gen < 4 &&
+	    (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
 		return -EINVAL;
 
 	return 0;
@@ -886,20 +890,22 @@
 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
 {
 	struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 ratio;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 pfit_control = I915_READ(PFIT_CONTROL);
+	u32 ratio;
 
 	/* XXX: This is not the same logic as in the xorg driver, but more in
-	 * line with the intel documentation for the i965 */
-	if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
-		ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
-	} else { /* on i965 use the PGM reg to read out the autoscaler values */
-		ratio = I915_READ(PFIT_PGM_RATIOS);
-		if (IS_I965G(dev))
-			ratio >>= PFIT_VERT_SCALE_SHIFT_965;
+	 * line with the intel documentation for the i965
+	 */
+	if (INTEL_INFO(dev)->gen >= 4) {
+	       	/* on i965 use the PGM reg to read out the autoscaler values */
+		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
+	} else {
+		if (pfit_control & VERT_AUTO_SCALE)
+			ratio = I915_READ(PFIT_AUTO_RATIOS);
 		else
-			ratio >>= PFIT_VERT_SCALE_SHIFT;
+			ratio = I915_READ(PFIT_PGM_RATIOS);
+		ratio >>= PFIT_VERT_SCALE_SHIFT;
 	}
 
 	overlay->pfit_vscale_ratio = ratio;
@@ -910,12 +916,10 @@
 {
 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
 
-	if ((rec->dst_x < mode->crtc_hdisplay)
-	    && (rec->dst_x + rec->dst_width
-		    <= mode->crtc_hdisplay)
-	    && (rec->dst_y < mode->crtc_vdisplay)
-	    && (rec->dst_y + rec->dst_height
-		    <= mode->crtc_vdisplay))
+	if (rec->dst_x < mode->crtc_hdisplay &&
+	    rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
+	    rec->dst_y < mode->crtc_vdisplay &&
+	    rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
 		return 0;
 	else
 		return -EINVAL;
@@ -940,53 +944,59 @@
 			     struct drm_intel_overlay_put_image *rec,
 			     struct drm_gem_object *new_bo)
 {
-	u32 stride_mask;
-	int depth;
 	int uv_hscale = uv_hsubsampling(rec->flags);
 	int uv_vscale = uv_vsubsampling(rec->flags);
-	size_t tmp;
+	u32 stride_mask;
+	int depth;
+	u32 tmp;
 
 	/* check src dimensions */
 	if (IS_845G(dev) || IS_I830(dev)) {
-		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
-		    || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
+		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
+		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
 			return -EINVAL;
 	} else {
-		if (rec->src_height > IMAGE_MAX_HEIGHT
-		    || rec->src_width > IMAGE_MAX_WIDTH)
+		if (rec->src_height > IMAGE_MAX_HEIGHT ||
+		    rec->src_width  > IMAGE_MAX_WIDTH)
 			return -EINVAL;
 	}
+
 	/* better safe than sorry, use 4 as the maximal subsampling ratio */
-	if (rec->src_height < N_VERT_Y_TAPS*4
-	    || rec->src_width < N_HORIZ_Y_TAPS*4)
+	if (rec->src_height < N_VERT_Y_TAPS*4 ||
+	    rec->src_width  < N_HORIZ_Y_TAPS*4)
 		return -EINVAL;
 
 	/* check alignment constraints */
 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-		case I915_OVERLAY_RGB:
-			/* not implemented */
+	case I915_OVERLAY_RGB:
+		/* not implemented */
+		return -EINVAL;
+
+	case I915_OVERLAY_YUV_PACKED:
+		if (uv_vscale != 1)
 			return -EINVAL;
-		case I915_OVERLAY_YUV_PACKED:
-			depth = packed_depth_bytes(rec->flags);
-			if (uv_vscale != 1)
-				return -EINVAL;
-			if (depth < 0)
-				return depth;
-			/* ignore UV planes */
-			rec->stride_UV = 0;
-			rec->offset_U = 0;
-			rec->offset_V = 0;
-			/* check pixel alignment */
-			if (rec->offset_Y % depth)
-				return -EINVAL;
-			break;
-		case I915_OVERLAY_YUV_PLANAR:
-			if (uv_vscale < 0 || uv_hscale < 0)
-				return -EINVAL;
-			/* no offset restrictions for planar formats */
-			break;
-		default:
+
+		depth = packed_depth_bytes(rec->flags);
+		if (depth < 0)
+			return depth;
+
+		/* ignore UV planes */
+		rec->stride_UV = 0;
+		rec->offset_U = 0;
+		rec->offset_V = 0;
+		/* check pixel alignment */
+		if (rec->offset_Y % depth)
+			return -EINVAL;
+		break;
+
+	case I915_OVERLAY_YUV_PLANAR:
+		if (uv_vscale < 0 || uv_hscale < 0)
 			return -EINVAL;
+		/* no offset restrictions for planar formats */
+		break;
+
+	default:
+		return -EINVAL;
 	}
 
 	if (rec->src_width % uv_hscale)
@@ -1000,47 +1010,74 @@
 
 	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
 		return -EINVAL;
-	if (IS_I965G(dev) && rec->stride_Y < 512)
+	if (IS_GEN4(dev) && rec->stride_Y < 512)
 		return -EINVAL;
 
 	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
-		4 : 8;
-	if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
+		4096 : 8192;
+	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
 		return -EINVAL;
 
 	/* check buffer dimensions */
 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-		case I915_OVERLAY_RGB:
-		case I915_OVERLAY_YUV_PACKED:
-			/* always 4 Y values per depth pixels */
-			if (packed_width_bytes(rec->flags, rec->src_width)
-					> rec->stride_Y)
-				return -EINVAL;
+	case I915_OVERLAY_RGB:
+	case I915_OVERLAY_YUV_PACKED:
+		/* always 4 Y values per depth pixels */
+		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
+			return -EINVAL;
 
-			tmp = rec->stride_Y*rec->src_height;
-			if (rec->offset_Y + tmp > new_bo->size)
-				return -EINVAL;
-			break;
-		case I915_OVERLAY_YUV_PLANAR:
-			if (rec->src_width > rec->stride_Y)
-				return -EINVAL;
-			if (rec->src_width/uv_hscale > rec->stride_UV)
-				return -EINVAL;
+		tmp = rec->stride_Y*rec->src_height;
+		if (rec->offset_Y + tmp > new_bo->size)
+			return -EINVAL;
+		break;
 
-			tmp = rec->stride_Y*rec->src_height;
-			if (rec->offset_Y + tmp > new_bo->size)
-				return -EINVAL;
-			tmp = rec->stride_UV*rec->src_height;
-			tmp /= uv_vscale;
-			if (rec->offset_U + tmp > new_bo->size
-			    || rec->offset_V + tmp > new_bo->size)
-				return -EINVAL;
-			break;
+	case I915_OVERLAY_YUV_PLANAR:
+		if (rec->src_width > rec->stride_Y)
+			return -EINVAL;
+		if (rec->src_width/uv_hscale > rec->stride_UV)
+			return -EINVAL;
+
+		tmp = rec->stride_Y * rec->src_height;
+		if (rec->offset_Y + tmp > new_bo->size)
+			return -EINVAL;
+
+		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
+		if (rec->offset_U + tmp > new_bo->size ||
+		    rec->offset_V + tmp > new_bo->size)
+			return -EINVAL;
+		break;
 	}
 
 	return 0;
 }
 
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32  pfit_control;
+
+	/* i830 doesn't have a panel fitter */
+	if (IS_I830(dev))
+		return -1;
+
+	pfit_control = I915_READ(PFIT_CONTROL);
+
+	/* See if the panel fitter is in use */
+	if ((pfit_control & PFIT_ENABLE) == 0)
+		return -1;
+
+	/* 965 can place panel fitter on either pipe */
+	if (IS_GEN4(dev))
+		return (pfit_control >> 29) & 0x3;
+
+	/* older chips can only use pipe 1 */
+	return 1;
+}
+
 int intel_overlay_put_image(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
@@ -1068,7 +1105,7 @@
 		mutex_lock(&dev->mode_config.mutex);
 		mutex_lock(&dev->struct_mutex);
 
-		ret = intel_overlay_switch_off(overlay);
+		ret = intel_overlay_switch_off(overlay, true);
 
 		mutex_unlock(&dev->struct_mutex);
 		mutex_unlock(&dev->mode_config.mutex);
@@ -1081,7 +1118,7 @@
 		return -ENOMEM;
 
 	drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
-                        DRM_MODE_OBJECT_CRTC);
+					   DRM_MODE_OBJECT_CRTC);
 	if (!drmmode_obj) {
 		ret = -ENOENT;
 		goto out_free;
@@ -1089,7 +1126,7 @@
 	crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
 
 	new_bo = drm_gem_object_lookup(dev, file_priv,
-			put_image_rec->bo_handle);
+				       put_image_rec->bo_handle);
 	if (!new_bo) {
 		ret = -ENOENT;
 		goto out_free;
@@ -1098,15 +1135,13 @@
 	mutex_lock(&dev->mode_config.mutex);
 	mutex_lock(&dev->struct_mutex);
 
-	if (overlay->hw_wedged) {
-		ret = intel_overlay_recover_from_interrupt(overlay, 1);
-		if (ret != 0)
-			goto out_unlock;
-	}
+	ret = intel_overlay_recover_from_interrupt(overlay, true);
+	if (ret != 0)
+		goto out_unlock;
 
 	if (overlay->crtc != crtc) {
 		struct drm_display_mode *mode = &crtc->base.mode;
-		ret = intel_overlay_switch_off(overlay);
+		ret = intel_overlay_switch_off(overlay, true);
 		if (ret != 0)
 			goto out_unlock;
 
@@ -1117,9 +1152,9 @@
 		overlay->crtc = crtc;
 		crtc->overlay = overlay;
 
-		if (intel_panel_fitter_pipe(dev) == crtc->pipe
-		    /* and line to wide, i.e. one-line-mode */
-		    && mode->hdisplay > 1024) {
+		/* line too wide, i.e. one-line-mode */
+		if (mode->hdisplay > 1024 &&
+		    intel_panel_fitter_pipe(dev) == crtc->pipe) {
 			overlay->pfit_active = 1;
 			update_pfit_vscale_ratio(overlay);
 		} else
@@ -1132,10 +1167,10 @@
 
 	if (overlay->pfit_active) {
 		params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
-			overlay->pfit_vscale_ratio);
+				 overlay->pfit_vscale_ratio);
 		/* shifting right rounds downwards, so add 1 */
 		params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
-			overlay->pfit_vscale_ratio) + 1;
+				 overlay->pfit_vscale_ratio) + 1;
 	} else {
 		params->dst_y = put_image_rec->dst_y;
 		params->dst_h = put_image_rec->dst_height;
@@ -1147,8 +1182,8 @@
 	params->src_h = put_image_rec->src_height;
 	params->src_scan_w = put_image_rec->src_scan_width;
 	params->src_scan_h = put_image_rec->src_scan_height;
-	if (params->src_scan_h > params->src_h
-	    || params->src_scan_w > params->src_w) {
+	if (params->src_scan_h > params->src_h ||
+	    params->src_scan_w > params->src_w) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
@@ -1204,7 +1239,7 @@
 		return false;
 
 	for (i = 0; i < 3; i++) {
-		if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
+		if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
 			return false;
 	}
 
@@ -1225,16 +1260,18 @@
 
 static int check_gamma(struct drm_intel_overlay_attrs *attrs)
 {
-	if (!check_gamma_bounds(0, attrs->gamma0)
-	    || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
-	    || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
-	    || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
-	    || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
-	    || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
-	    || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
+	if (!check_gamma_bounds(0, attrs->gamma0) ||
+	    !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
+	    !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
+	    !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
+	    !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
+	    !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
+	    !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
 		return -EINVAL;
+
 	if (!check_gamma5_errata(attrs->gamma5))
 		return -EINVAL;
+
 	return 0;
 }
 
@@ -1261,13 +1298,14 @@
 	mutex_lock(&dev->mode_config.mutex);
 	mutex_lock(&dev->struct_mutex);
 
+	ret = -EINVAL;
 	if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
-		attrs->color_key = overlay->color_key;
+		attrs->color_key  = overlay->color_key;
 		attrs->brightness = overlay->brightness;
-		attrs->contrast = overlay->contrast;
+		attrs->contrast   = overlay->contrast;
 		attrs->saturation = overlay->saturation;
 
-		if (IS_I9XX(dev)) {
+		if (!IS_GEN2(dev)) {
 			attrs->gamma0 = I915_READ(OGAMC0);
 			attrs->gamma1 = I915_READ(OGAMC1);
 			attrs->gamma2 = I915_READ(OGAMC2);
@@ -1275,29 +1313,20 @@
 			attrs->gamma4 = I915_READ(OGAMC4);
 			attrs->gamma5 = I915_READ(OGAMC5);
 		}
-		ret = 0;
 	} else {
-		overlay->color_key = attrs->color_key;
-		if (attrs->brightness >= -128 && attrs->brightness <= 127) {
-			overlay->brightness = attrs->brightness;
-		} else {
-			ret = -EINVAL;
+		if (attrs->brightness < -128 || attrs->brightness > 127)
 			goto out_unlock;
-		}
-		if (attrs->contrast <= 255) {
-			overlay->contrast = attrs->contrast;
-		} else {
-			ret = -EINVAL;
+		if (attrs->contrast > 255)
 			goto out_unlock;
-		}
-		if (attrs->saturation <= 1023) {
-			overlay->saturation = attrs->saturation;
-		} else {
-			ret = -EINVAL;
+		if (attrs->saturation > 1023)
 			goto out_unlock;
-		}
 
-		regs = intel_overlay_map_regs_atomic(overlay);
+		overlay->color_key  = attrs->color_key;
+		overlay->brightness = attrs->brightness;
+		overlay->contrast   = attrs->contrast;
+		overlay->saturation = attrs->saturation;
+
+		regs = intel_overlay_map_regs(overlay);
 		if (!regs) {
 			ret = -ENOMEM;
 			goto out_unlock;
@@ -1305,13 +1334,11 @@
 
 		update_reg_attrs(overlay, regs);
 
-		intel_overlay_unmap_regs_atomic(overlay);
+		intel_overlay_unmap_regs(overlay, regs);
 
 		if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
-			if (!IS_I9XX(dev)) {
-				ret = -EINVAL;
+			if (IS_GEN2(dev))
 				goto out_unlock;
-			}
 
 			if (overlay->active) {
 				ret = -EBUSY;
@@ -1319,7 +1346,7 @@
 			}
 
 			ret = check_gamma(attrs);
-			if (ret != 0)
+			if (ret)
 				goto out_unlock;
 
 			I915_WRITE(OGAMC0, attrs->gamma0);
@@ -1329,9 +1356,9 @@
 			I915_WRITE(OGAMC4, attrs->gamma4);
 			I915_WRITE(OGAMC5, attrs->gamma5);
 		}
-		ret = 0;
 	}
 
+	ret = 0;
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
 	mutex_unlock(&dev->mode_config.mutex);
@@ -1347,7 +1374,7 @@
 	struct overlay_registers *regs;
 	int ret;
 
-	if (!OVERLAY_EXISTS(dev))
+	if (!HAS_OVERLAY(dev))
 		return;
 
 	overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
@@ -1360,22 +1387,28 @@
 		goto out_free;
 	overlay->reg_bo = to_intel_bo(reg_bo);
 
-	if (OVERLAY_NONPHYSICAL(dev)) {
-		ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
-		if (ret) {
-                        DRM_ERROR("failed to pin overlay register bo\n");
-                        goto out_free_bo;
-                }
-		overlay->flip_addr = overlay->reg_bo->gtt_offset;
-	} else {
+	if (OVERLAY_NEEDS_PHYSICAL(dev)) {
 		ret = i915_gem_attach_phys_object(dev, reg_bo,
 						  I915_GEM_PHYS_OVERLAY_REGS,
-						  0);
+						  PAGE_SIZE);
                 if (ret) {
                         DRM_ERROR("failed to attach phys overlay regs\n");
                         goto out_free_bo;
                 }
 		overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+	} else {
+		ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
+		if (ret) {
+                        DRM_ERROR("failed to pin overlay register bo\n");
+                        goto out_free_bo;
+                }
+		overlay->flip_addr = overlay->reg_bo->gtt_offset;
+
+		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
+		if (ret) {
+                        DRM_ERROR("failed to move overlay register bo into the GTT\n");
+                        goto out_unpin_bo;
+                }
 	}
 
 	/* init all values */
@@ -1384,21 +1417,22 @@
 	overlay->contrast = 75;
 	overlay->saturation = 146;
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	if (!regs)
 		goto out_free_bo;
 
 	memset(regs, 0, sizeof(struct overlay_registers));
 	update_polyphase_filter(regs);
-
 	update_reg_attrs(overlay, regs);
 
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
 	dev_priv->overlay = overlay;
 	DRM_INFO("initialized overlay support\n");
 	return;
 
+out_unpin_bo:
+	i915_gem_object_unpin(reg_bo);
 out_free_bo:
 	drm_gem_object_unreference(reg_bo);
 out_free:
@@ -1408,18 +1442,23 @@
 
 void intel_cleanup_overlay(struct drm_device *dev)
 {
-        drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	if (dev_priv->overlay) {
-		/* The bo's should be free'd by the generic code already.
-		 * Furthermore modesetting teardown happens beforehand so the
-		 * hardware should be off already */
-		BUG_ON(dev_priv->overlay->active);
+	if (!dev_priv->overlay)
+		return;
 
-		kfree(dev_priv->overlay);
-	}
+	/* The bo's should be free'd by the generic code already.
+	 * Furthermore modesetting teardown happens beforehand so the
+	 * hardware should be off already */
+	BUG_ON(dev_priv->overlay->active);
+
+	drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+	kfree(dev_priv->overlay);
 }
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
 struct intel_overlay_error_state {
 	struct overlay_registers regs;
 	unsigned long base;
@@ -1427,6 +1466,29 @@
 	u32 isr;
 };
 
+static struct overlay_registers *
+intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+{
+	drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+	struct overlay_registers *regs;
+
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		regs = overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+						overlay->reg_bo->gtt_offset);
+
+	return regs;
+}
+
+static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
+					    struct overlay_registers *regs)
+{
+	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		io_mapping_unmap_atomic(regs);
+}
+
+
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_device *dev)
 {
@@ -1444,17 +1506,17 @@
 
 	error->dovsta = I915_READ(DOVSTA);
 	error->isr = I915_READ(ISR);
-	if (OVERLAY_NONPHYSICAL(overlay->dev))
-		error->base = (long) overlay->reg_bo->gtt_offset;
-	else
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
 		error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		error->base = (long) overlay->reg_bo->gtt_offset;
 
 	regs = intel_overlay_map_regs_atomic(overlay);
 	if (!regs)
 		goto err;
 
 	memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs_atomic(overlay, regs);
 
 	return error;
 
@@ -1515,3 +1577,4 @@
 	P(UVSCALEV);
 #undef P
 }
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_panel.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_panel.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_panel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_panel.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,6 +30,8 @@
 
 #include "intel_drv.h"
 
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 		       struct drm_display_mode *adjusted_mode)
@@ -109,3 +111,110 @@
 	dev_priv->pch_pf_pos = (x << 16) | y;
 	dev_priv->pch_pf_size = (width << 16) | height;
 }
+
+static int is_backlight_combination_mode(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (INTEL_INFO(dev)->gen >= 4)
+		return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+
+	if (IS_GEN2(dev))
+		return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	return 0;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 max;
+
+	if (HAS_PCH_SPLIT(dev)) {
+		max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+	} else {
+		max = I915_READ(BLC_PWM_CTL);
+		if (IS_PINEVIEW(dev)) {
+			max >>= 17;
+		} else {
+			max >>= 16;
+			if (INTEL_INFO(dev)->gen < 4)
+				max &= ~1;
+		}
+
+		if (is_backlight_combination_mode(dev))
+			max *= 0xff;
+	}
+
+	if (max == 0) {
+		/* XXX add code here to query mode clock or hardware clock
+		 * and program max PWM appropriately.
+		 */
+		DRM_ERROR("fixme: max PWM is zero.\n");
+		max = 1;
+	}
+
+	DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+	return max;
+}
+
+u32 intel_panel_get_backlight(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val;
+
+	if (HAS_PCH_SPLIT(dev)) {
+		val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+	} else {
+		val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+		if (IS_PINEVIEW(dev))
+			val >>= 1;
+
+		if (is_backlight_combination_mode(dev)){
+			u8 lbpc;
+
+			val &= ~1;
+			pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+			val *= lbpc;
+			val >>= 1;
+		}
+	}
+
+	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+	return val;
+}
+
+static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+}
+
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 tmp;
+
+	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+	if (HAS_PCH_SPLIT(dev))
+		return intel_pch_panel_set_backlight(dev, level);
+
+	if (is_backlight_combination_mode(dev)){
+		u32 max = intel_panel_get_max_backlight(dev);
+		u8 lpbc;
+
+		lpbc = level * 0xfe / max + 1;
+		level /= lpbc;
+		pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+	}
+
+	tmp = I915_READ(BLC_PWM_CTL);
+	if (IS_PINEVIEW(dev)) {
+		tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+		level <<= 1;
+	} else
+		tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+	I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_ringbuffer.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_ringbuffer.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_ringbuffer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_ringbuffer.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include "i915_drv.h"
 #include "i915_drm.h"
 #include "i915_trace.h"
+#include "intel_drv.h"
 
 static u32 i915_gem_get_seqno(struct drm_device *dev)
 {
@@ -49,9 +50,9 @@
 
 static void
 render_ring_flush(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		u32	invalidate_domains,
-		u32	flush_domains)
+		  struct intel_ring_buffer *ring,
+		  u32	invalidate_domains,
+		  u32	flush_domains)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 cmd;
@@ -97,7 +98,7 @@
 		if ((invalidate_domains|flush_domains) &
 		    I915_GEM_DOMAIN_RENDER)
 			cmd &= ~MI_NO_WRITE_FLUSH;
-		if (!IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen < 4) {
 			/*
 			 * On the 965, the sampler cache always gets flushed
 			 * and this bit is reserved.
@@ -118,38 +119,26 @@
 	}
 }
 
-static unsigned int render_ring_get_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(PRB0_HEAD) & HEAD_ADDR;
-}
-
-static unsigned int render_ring_get_tail(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+static void ring_write_tail(struct drm_device *dev,
+			    struct intel_ring_buffer *ring,
+			    u32 value)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(PRB0_TAIL) & TAIL_ADDR;
+	I915_WRITE_TAIL(ring, value);
 }
 
-static unsigned int render_ring_get_active_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct drm_device *dev,
+			       struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+	u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+			RING_ACTHD(ring->mmio_base) : ACTHD;
 
 	return I915_READ(acthd_reg);
 }
 
-static void render_ring_advance_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(PRB0_TAIL, ring->tail);
-}
-
 static int init_ring_common(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	u32 head;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -157,57 +146,59 @@
 	obj_priv = to_intel_bo(ring->gem_object);
 
 	/* Stop the ring if it's running. */
-	I915_WRITE(ring->regs.ctl, 0);
-	I915_WRITE(ring->regs.head, 0);
-	I915_WRITE(ring->regs.tail, 0);
+	I915_WRITE_CTL(ring, 0);
+	I915_WRITE_HEAD(ring, 0);
+	ring->write_tail(dev, ring, 0);
 
 	/* Initialize the ring. */
-	I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
-	head = ring->get_head(dev, ring);
+	I915_WRITE_START(ring, obj_priv->gtt_offset);
+	head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
 	/* G45 ring initialization fails to reset head to zero */
 	if (head != 0) {
-		DRM_ERROR("%s head not reset to zero "
-				"ctl %08x head %08x tail %08x start %08x\n",
-				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+		DRM_DEBUG_KMS("%s head not reset to zero "
+			      "ctl %08x head %08x tail %08x start %08x\n",
+			      ring->name,
+			      I915_READ_CTL(ring),
+			      I915_READ_HEAD(ring),
+			      I915_READ_TAIL(ring),
+			      I915_READ_START(ring));
 
-		I915_WRITE(ring->regs.head, 0);
+		I915_WRITE_HEAD(ring, 0);
 
-		DRM_ERROR("%s head forced to zero "
-				"ctl %08x head %08x tail %08x start %08x\n",
-				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+		if (I915_READ_HEAD(ring) & HEAD_ADDR) {
+			DRM_ERROR("failed to set %s head to zero "
+				  "ctl %08x head %08x tail %08x start %08x\n",
+				  ring->name,
+				  I915_READ_CTL(ring),
+				  I915_READ_HEAD(ring),
+				  I915_READ_TAIL(ring),
+				  I915_READ_START(ring));
+		}
 	}
 
-	I915_WRITE(ring->regs.ctl,
+	I915_WRITE_CTL(ring,
 			((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
-			| RING_NO_REPORT | RING_VALID);
+			| RING_REPORT_64K | RING_VALID);
 
-	head = I915_READ(ring->regs.head) & HEAD_ADDR;
+	head = I915_READ_HEAD(ring) & HEAD_ADDR;
 	/* If the head is still not zero, the ring is dead */
 	if (head != 0) {
 		DRM_ERROR("%s initialization failed "
 				"ctl %08x head %08x tail %08x start %08x\n",
 				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+				I915_READ_CTL(ring),
+				I915_READ_HEAD(ring),
+				I915_READ_TAIL(ring),
+				I915_READ_START(ring));
 		return -EIO;
 	}
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		i915_kernel_lost_context(dev);
 	else {
-		ring->head = ring->get_head(dev, ring);
-		ring->tail = ring->get_tail(dev, ring);
+		ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+		ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
@@ -216,13 +207,13 @@
 }
 
 static int init_render_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret = init_ring_common(dev, ring);
 	int mode;
 
-	if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+	if (INTEL_INFO(dev)->gen > 3) {
 		mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
 		if (IS_GEN6(dev))
 			mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
@@ -250,9 +241,8 @@
  */
 static u32
 render_ring_add_request(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_file *file_priv,
-		u32 flush_domains)
+			struct intel_ring_buffer *ring,
+			u32 flush_domains)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 seqno;
@@ -315,8 +305,8 @@
 }
 
 static u32
-render_ring_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct drm_device *dev,
+		      struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	if (HAS_PIPE_CONTROL(dev))
@@ -327,7 +317,7 @@
 
 static void
 render_ring_get_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
@@ -344,7 +334,7 @@
 
 static void
 render_ring_put_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
@@ -360,21 +350,23 @@
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
-static void render_setup_status_page(struct drm_device *dev,
-	struct	intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct drm_device *dev,
+				  struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	if (IS_GEN6(dev)) {
-		I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
-		I915_READ(HWS_PGA_GEN6); /* posting read */
+		I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
+			   ring->status_page.gfx_addr);
+		I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
 	} else {
-		I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
-		I915_READ(HWS_PGA); /* posting read */
+		I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+			   ring->status_page.gfx_addr);
+		I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
 	}
 
 }
 
-void
+static void
 bsd_ring_flush(struct drm_device *dev,
 		struct intel_ring_buffer *ring,
 		u32     invalidate_domains,
@@ -386,45 +378,16 @@
 	intel_ring_advance(dev, ring);
 }
 
-static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_ACTHD);
-}
-
-static inline void bsd_ring_advance_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(BSD_RING_TAIL, ring->tail);
-}
-
 static int init_bsd_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	return init_ring_common(dev, ring);
 }
 
 static u32
-bsd_ring_add_request(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_file *file_priv,
-		u32 flush_domains)
+ring_add_request(struct drm_device *dev,
+		 struct intel_ring_buffer *ring,
+		 u32 flush_domains)
 {
 	u32 seqno;
 
@@ -443,40 +406,32 @@
 	return seqno;
 }
 
-static void bsd_setup_status_page(struct drm_device *dev,
-		struct  intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
-	I915_READ(BSD_HWS_PGA);
-}
-
 static void
 bsd_ring_get_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+		      struct intel_ring_buffer *ring)
 {
 	/* do nothing */
 }
 static void
 bsd_ring_put_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+		      struct intel_ring_buffer *ring)
 {
 	/* do nothing */
 }
 
 static u32
-bsd_ring_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+ring_status_page_get_seqno(struct drm_device *dev,
+			   struct intel_ring_buffer *ring)
 {
 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
 static int
-bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_i915_gem_execbuffer2 *exec,
-		struct drm_clip_rect *cliprects,
-		uint64_t exec_offset)
+ring_dispatch_gem_execbuffer(struct drm_device *dev,
+			     struct intel_ring_buffer *ring,
+			     struct drm_i915_gem_execbuffer2 *exec,
+			     struct drm_clip_rect *cliprects,
+			     uint64_t exec_offset)
 {
 	uint32_t exec_start;
 	exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
@@ -488,13 +443,12 @@
 	return 0;
 }
 
-
 static int
 render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_i915_gem_execbuffer2 *exec,
-		struct drm_clip_rect *cliprects,
-		uint64_t exec_offset)
+				    struct intel_ring_buffer *ring,
+				    struct drm_i915_gem_execbuffer2 *exec,
+				    struct drm_clip_rect *cliprects,
+				    uint64_t exec_offset)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int nbox = exec->num_cliprects;
@@ -523,8 +477,8 @@
 			intel_ring_emit(dev, ring, exec_start + exec_len - 4);
 			intel_ring_emit(dev, ring, 0);
 		} else {
-			intel_ring_begin(dev, ring, 4);
-			if (IS_I965G(dev)) {
+			intel_ring_begin(dev, ring, 2);
+			if (INTEL_INFO(dev)->gen >= 4) {
 				intel_ring_emit(dev, ring,
 						MI_BATCH_BUFFER_START | (2 << 6)
 						| MI_BATCH_NON_SECURE_I965);
@@ -539,7 +493,7 @@
 		intel_ring_advance(dev, ring);
 	}
 
-	if (IS_G4X(dev) || IS_IRONLAKE(dev)) {
+	if (IS_G4X(dev) || IS_GEN5(dev)) {
 		intel_ring_begin(dev, ring, 2);
 		intel_ring_emit(dev, ring, MI_FLUSH |
 				MI_NO_WRITE_FLUSH |
@@ -553,7 +507,7 @@
 }
 
 static void cleanup_status_page(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+				struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
@@ -573,7 +527,7 @@
 }
 
 static int init_status_page(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
@@ -603,7 +557,7 @@
 	ring->status_page.obj = obj;
 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-	ring->setup_status_page(dev, ring);
+	intel_ring_setup_status_page(dev, ring);
 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
 			ring->name, ring->status_page.gfx_addr);
 
@@ -617,15 +571,18 @@
 	return ret;
 }
 
-
 int intel_init_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			   struct intel_ring_buffer *ring)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv;
 	struct drm_gem_object *obj;
 	int ret;
 
 	ring->dev = dev;
+	INIT_LIST_HEAD(&ring->active_list);
+	INIT_LIST_HEAD(&ring->request_list);
+	INIT_LIST_HEAD(&ring->gpu_write_list);
 
 	if (I915_NEED_GFX_HWS(dev)) {
 		ret = init_status_page(dev, ring);
@@ -642,7 +599,7 @@
 
 	ring->gem_object = obj;
 
-	ret = i915_gem_object_pin(obj, ring->alignment);
+	ret = i915_gem_object_pin(obj, PAGE_SIZE);
 	if (ret)
 		goto err_unref;
 
@@ -668,14 +625,12 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		i915_kernel_lost_context(dev);
 	else {
-		ring->head = ring->get_head(dev, ring);
-		ring->tail = ring->get_tail(dev, ring);
+		ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+		ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
 	}
-	INIT_LIST_HEAD(&ring->active_list);
-	INIT_LIST_HEAD(&ring->request_list);
 	return ret;
 
 err_unmap:
@@ -691,7 +646,7 @@
 }
 
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			       struct intel_ring_buffer *ring)
 {
 	if (ring->gem_object == NULL)
 		return;
@@ -701,11 +656,15 @@
 	i915_gem_object_unpin(ring->gem_object);
 	drm_gem_object_unreference(ring->gem_object);
 	ring->gem_object = NULL;
+
+	if (ring->cleanup)
+		ring->cleanup(ring);
+
 	cleanup_status_page(dev, ring);
 }
 
-int intel_wrap_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct drm_device *dev,
+				  struct intel_ring_buffer *ring)
 {
 	unsigned int *virt;
 	int rem;
@@ -731,14 +690,23 @@
 }
 
 int intel_wait_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n)
+			   struct intel_ring_buffer *ring, int n)
 {
 	unsigned long end;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	u32 head;
 
 	trace_i915_ring_wait_begin (dev);
 	end = jiffies + 3 * HZ;
 	do {
-		ring->head = ring->get_head(dev, ring);
+		/* If the reported head position has wrapped or hasn't advanced,
+		 * fallback to the slow and accurate path.
+		 */
+		head = intel_read_status_page(ring, 4);
+		if (head < ring->actual_head)
+			head = I915_READ_HEAD(ring);
+		ring->actual_head = head;
+		ring->head = head & HEAD_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
@@ -753,14 +721,15 @@
 				master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 		}
 
-		yield();
+		msleep(1);
 	} while (!time_after(jiffies, end));
 	trace_i915_ring_wait_end (dev);
 	return -EBUSY;
 }
 
 void intel_ring_begin(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int num_dwords)
+		      struct intel_ring_buffer *ring,
+		      int num_dwords)
 {
 	int n = 4*num_dwords;
 	if (unlikely(ring->tail + n > ring->size))
@@ -772,97 +741,287 @@
 }
 
 void intel_ring_advance(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	ring->tail &= ring->size - 1;
-	ring->advance_ring(dev, ring);
-}
-
-void intel_fill_struct(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		void *data,
-		unsigned int len)
+			struct intel_ring_buffer *ring)
 {
-	unsigned int *virt = ring->virtual_start + ring->tail;
-	BUG_ON((len&~(4-1)) != 0);
-	intel_ring_begin(dev, ring, len/4);
-	memcpy(virt, data, len);
-	ring->tail += len;
 	ring->tail &= ring->size - 1;
-	ring->space -= len;
-	intel_ring_advance(dev, ring);
+	ring->write_tail(dev, ring, ring->tail);
 }
 
-struct intel_ring_buffer render_ring = {
+static const struct intel_ring_buffer render_ring = {
 	.name			= "render ring",
-	.regs                   = {
-		.ctl = PRB0_CTL,
-		.head = PRB0_HEAD,
-		.tail = PRB0_TAIL,
-		.start = PRB0_START
-	},
-	.ring_flag		= I915_EXEC_RENDER,
+	.id			= RING_RENDER,
+	.mmio_base		= RENDER_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
-	.alignment		= PAGE_SIZE,
-	.virtual_start		= NULL,
-	.dev			= NULL,
-	.gem_object		= NULL,
-	.head			= 0,
-	.tail			= 0,
-	.space			= 0,
-	.user_irq_refcount	= 0,
-	.irq_gem_seqno		= 0,
-	.waiting_gem_seqno	= 0,
-	.setup_status_page	= render_setup_status_page,
 	.init			= init_render_ring,
-	.get_head		= render_ring_get_head,
-	.get_tail		= render_ring_get_tail,
-	.get_active_head	= render_ring_get_active_head,
-	.advance_ring		= render_ring_advance_ring,
+	.write_tail		= ring_write_tail,
 	.flush			= render_ring_flush,
 	.add_request		= render_ring_add_request,
-	.get_gem_seqno		= render_ring_get_gem_seqno,
+	.get_seqno		= render_ring_get_seqno,
 	.user_irq_get		= render_ring_get_user_irq,
 	.user_irq_put		= render_ring_put_user_irq,
 	.dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
-	.status_page		= {NULL, 0, NULL},
-	.map			= {0,}
 };
 
 /* ring buffer for bit-stream decoder */
 
-struct intel_ring_buffer bsd_ring = {
+static const struct intel_ring_buffer bsd_ring = {
 	.name                   = "bsd ring",
-	.regs			= {
-		.ctl = BSD_RING_CTL,
-		.head = BSD_RING_HEAD,
-		.tail = BSD_RING_TAIL,
-		.start = BSD_RING_START
-	},
-	.ring_flag		= I915_EXEC_BSD,
+	.id			= RING_BSD,
+	.mmio_base		= BSD_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
-	.alignment		= PAGE_SIZE,
-	.virtual_start		= NULL,
-	.dev			= NULL,
-	.gem_object		= NULL,
-	.head			= 0,
-	.tail			= 0,
-	.space			= 0,
-	.user_irq_refcount	= 0,
-	.irq_gem_seqno		= 0,
-	.waiting_gem_seqno	= 0,
-	.setup_status_page	= bsd_setup_status_page,
 	.init			= init_bsd_ring,
-	.get_head		= bsd_ring_get_head,
-	.get_tail		= bsd_ring_get_tail,
-	.get_active_head	= bsd_ring_get_active_head,
-	.advance_ring		= bsd_ring_advance_ring,
+	.write_tail		= ring_write_tail,
 	.flush			= bsd_ring_flush,
-	.add_request		= bsd_ring_add_request,
-	.get_gem_seqno		= bsd_ring_get_gem_seqno,
+	.add_request		= ring_add_request,
+	.get_seqno		= ring_status_page_get_seqno,
 	.user_irq_get		= bsd_ring_get_user_irq,
 	.user_irq_put		= bsd_ring_put_user_irq,
-	.dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
-	.status_page		= {NULL, 0, NULL},
-	.map			= {0,}
+	.dispatch_gem_execbuffer = ring_dispatch_gem_execbuffer,
+};
+
+
+static void gen6_bsd_ring_write_tail(struct drm_device *dev,
+				     struct intel_ring_buffer *ring,
+				     u32 value)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Every tail move must follow the sequence below */
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
+       I915_WRITE(GEN6_BSD_RNCID, 0x0);
+
+       if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+                               GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+                       50))
+               DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+       I915_WRITE_TAIL(ring, value);
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+}
+
+static void gen6_ring_flush(struct drm_device *dev,
+			    struct intel_ring_buffer *ring,
+			    u32 invalidate_domains,
+			    u32 flush_domains)
+{
+       intel_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_FLUSH_DW);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+				  struct intel_ring_buffer *ring,
+				  struct drm_i915_gem_execbuffer2 *exec,
+				  struct drm_clip_rect *cliprects,
+				  uint64_t exec_offset)
+{
+       uint32_t exec_start;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+
+       intel_ring_begin(dev, ring, 2);
+       intel_ring_emit(dev, ring,
+		       MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+       /* bit0-7 is the length on GEN6+ */
+       intel_ring_emit(dev, ring, exec_start);
+       intel_ring_advance(dev, ring);
+
+       return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+static const struct intel_ring_buffer gen6_bsd_ring = {
+       .name			= "gen6 bsd ring",
+       .id			= RING_BSD,
+       .mmio_base		= GEN6_BSD_RING_BASE,
+       .size			= 32 * PAGE_SIZE,
+       .init			= init_bsd_ring,
+       .write_tail		= gen6_bsd_ring_write_tail,
+       .flush			= gen6_ring_flush,
+       .add_request		= ring_add_request,
+       .get_seqno		= ring_status_page_get_seqno,
+       .user_irq_get		= bsd_ring_get_user_irq,
+       .user_irq_put		= bsd_ring_put_user_irq,
+       .dispatch_gem_execbuffer	= gen6_ring_dispatch_gem_execbuffer,
 };
+
+/* Blitter support (SandyBridge+) */
+
+static void
+blt_ring_get_user_irq(struct drm_device *dev,
+		      struct intel_ring_buffer *ring)
+{
+	/* do nothing */
+}
+static void
+blt_ring_put_user_irq(struct drm_device *dev,
+		      struct intel_ring_buffer *ring)
+{
+	/* do nothing */
+}
+
+
+/* Workaround for some stepping of SNB,
+ * each time when BLT engine ring tail moved,
+ * the first command in the ring to be parsed
+ * should be MI_BATCH_BUFFER_START
+ */
+#define NEED_BLT_WORKAROUND(dev) \
+	(IS_GEN6(dev) && (dev->pdev->revision < 8))
+
+static inline struct drm_i915_gem_object *
+to_blt_workaround(struct intel_ring_buffer *ring)
+{
+	return ring->private;
+}
+
+static int blt_ring_init(struct drm_device *dev,
+			 struct intel_ring_buffer *ring)
+{
+	if (NEED_BLT_WORKAROUND(dev)) {
+		struct drm_i915_gem_object *obj;
+		u32 __iomem *ptr;
+		int ret;
+
+		obj = to_intel_bo(i915_gem_alloc_object(dev, 4096));
+		if (obj == NULL)
+			return -ENOMEM;
+
+		ret = i915_gem_object_pin(&obj->base, 4096);
+		if (ret) {
+			drm_gem_object_unreference(&obj->base);
+			return ret;
+		}
+
+		ptr = kmap(obj->pages[0]);
+		iowrite32(MI_BATCH_BUFFER_END, ptr);
+		iowrite32(MI_NOOP, ptr+1);
+		kunmap(obj->pages[0]);
+
+		ret = i915_gem_object_set_to_gtt_domain(&obj->base, false);
+		if (ret) {
+			i915_gem_object_unpin(&obj->base);
+			drm_gem_object_unreference(&obj->base);
+			return ret;
+		}
+
+		ring->private = obj;
+	}
+
+	return init_ring_common(dev, ring);
+}
+
+static void blt_ring_begin(struct drm_device *dev,
+			   struct intel_ring_buffer *ring,
+			  int num_dwords)
+{
+	if (ring->private) {
+		intel_ring_begin(dev, ring, num_dwords+2);
+		intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START);
+		intel_ring_emit(dev, ring, to_blt_workaround(ring)->gtt_offset);
+	} else
+		intel_ring_begin(dev, ring, 4);
+}
+
+static void blt_ring_flush(struct drm_device *dev,
+			   struct intel_ring_buffer *ring,
+			   u32 invalidate_domains,
+			   u32 flush_domains)
+{
+	blt_ring_begin(dev, ring, 4);
+	intel_ring_emit(dev, ring, MI_FLUSH_DW);
+	intel_ring_emit(dev, ring, 0);
+	intel_ring_emit(dev, ring, 0);
+	intel_ring_emit(dev, ring, 0);
+	intel_ring_advance(dev, ring);
+}
+
+static u32
+blt_ring_add_request(struct drm_device *dev,
+		     struct intel_ring_buffer *ring,
+		     u32 flush_domains)
+{
+	u32 seqno = i915_gem_get_seqno(dev);
+
+	blt_ring_begin(dev, ring, 4);
+	intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
+	intel_ring_emit(dev, ring,
+			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+	intel_ring_emit(dev, ring, seqno);
+	intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
+	intel_ring_advance(dev, ring);
+
+	DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+	return seqno;
+}
+
+static void blt_ring_cleanup(struct intel_ring_buffer *ring)
+{
+	if (!ring->private)
+		return;
+
+	i915_gem_object_unpin(ring->private);
+	drm_gem_object_unreference(ring->private);
+	ring->private = NULL;
+}
+
+static const struct intel_ring_buffer gen6_blt_ring = {
+       .name			= "blt ring",
+       .id			= RING_BLT,
+       .mmio_base		= BLT_RING_BASE,
+       .size			= 32 * PAGE_SIZE,
+       .init			= blt_ring_init,
+       .write_tail		= ring_write_tail,
+       .flush			= blt_ring_flush,
+       .add_request		= blt_ring_add_request,
+       .get_seqno		= ring_status_page_get_seqno,
+       .user_irq_get		= blt_ring_get_user_irq,
+       .user_irq_put		= blt_ring_put_user_irq,
+       .dispatch_gem_execbuffer	= gen6_ring_dispatch_gem_execbuffer,
+       .cleanup			= blt_ring_cleanup,
+};
+
+int intel_init_render_ring_buffer(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	dev_priv->render_ring = render_ring;
+
+	if (!I915_NEED_GFX_HWS(dev)) {
+		dev_priv->render_ring.status_page.page_addr
+			= dev_priv->status_page_dmah->vaddr;
+		memset(dev_priv->render_ring.status_page.page_addr,
+				0, PAGE_SIZE);
+	}
+
+	return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+}
+
+int intel_init_bsd_ring_buffer(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	if (IS_GEN6(dev))
+		dev_priv->bsd_ring = gen6_bsd_ring;
+	else
+		dev_priv->bsd_ring = bsd_ring;
+
+	return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+}
+
+int intel_init_blt_ring_buffer(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	dev_priv->blt_ring = gen6_blt_ring;
+
+	return intel_init_ring_buffer(dev, &dev_priv->blt_ring);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_ringbuffer.h linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_ringbuffer.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_ringbuffer.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_ringbuffer.h	2011-01-04 19:50:19.000000000 -0500
@@ -7,25 +7,33 @@
 	struct		drm_gem_object *obj;
 };
 
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+
 struct drm_i915_gem_execbuffer2;
 struct  intel_ring_buffer {
 	const char	*name;
-	struct		ring_regs {
-			u32 ctl;
-			u32 head;
-			u32 tail;
-			u32 start;
-	} regs;
-	unsigned int	ring_flag;
+	enum intel_ring_id {
+		RING_RENDER = 0x1,
+		RING_BSD = 0x2,
+		RING_BLT = 0x4,
+	} id;
+	u32		mmio_base;
 	unsigned long	size;
-	unsigned int	alignment;
 	void		*virtual_start;
 	struct		drm_device *dev;
 	struct		drm_gem_object *gem_object;
 
-	unsigned int	head;
-	unsigned int	tail;
-	unsigned int	space;
+	u32		actual_head;
+	u32		head;
+	u32		tail;
+	int		space;
 	struct intel_hw_status_page status_page;
 
 	u32		irq_gem_seqno;		/* last seq seem at irq time */
@@ -35,35 +43,28 @@
 			struct intel_ring_buffer *ring);
 	void		(*user_irq_put)(struct drm_device *dev,
 			struct intel_ring_buffer *ring);
-	void		(*setup_status_page)(struct drm_device *dev,
-			struct	intel_ring_buffer *ring);
 
 	int		(*init)(struct drm_device *dev,
 			struct intel_ring_buffer *ring);
 
-	unsigned int	(*get_head)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	unsigned int	(*get_tail)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	unsigned int	(*get_active_head)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	void		(*advance_ring)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
+	void		(*write_tail)(struct drm_device *dev,
+				      struct intel_ring_buffer *ring,
+				      u32 value);
 	void		(*flush)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
 			u32	invalidate_domains,
 			u32	flush_domains);
 	u32		(*add_request)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
-			struct drm_file *file_priv,
 			u32 flush_domains);
-	u32		(*get_gem_seqno)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
+	u32		(*get_seqno)(struct drm_device *dev,
+				     struct intel_ring_buffer *ring);
 	int		(*dispatch_gem_execbuffer)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
 			struct drm_i915_gem_execbuffer2 *exec,
 			struct drm_clip_rect *cliprects,
 			uint64_t exec_offset);
+	void		(*cleanup)(struct intel_ring_buffer *ring);
 
 	/**
 	 * List of objects currently involved in rendering from the
@@ -83,8 +84,24 @@
 	 */
 	struct list_head request_list;
 
+	/**
+	 * List of objects currently pending a GPU write flush.
+	 *
+	 * All elements on this list will belong to either the
+	 * active_list or flushing_list, last_rendering_seqno can
+	 * be used to differentiate between the two elements.
+	 */
+	struct list_head gpu_write_list;
+
+	/**
+	 * Do we have some not yet emitted requests outstanding?
+	 */
+	bool outstanding_lazy_request;
+
 	wait_queue_head_t irq_queue;
 	drm_local_map_t map;
+
+	void *private;
 };
 
 static inline u32
@@ -96,15 +113,13 @@
 }
 
 int intel_init_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			   struct intel_ring_buffer *ring);
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			       struct intel_ring_buffer *ring);
 int intel_wait_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n);
-int intel_wrap_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			   struct intel_ring_buffer *ring, int n);
 void intel_ring_begin(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n);
+		      struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct drm_device *dev,
 				   struct intel_ring_buffer *ring,
@@ -115,17 +130,19 @@
 	ring->tail += 4;
 }
 
-void intel_fill_struct(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		void *data,
-		unsigned int len);
 void intel_ring_advance(struct drm_device *dev,
 		struct intel_ring_buffer *ring);
 
 u32 intel_ring_get_seqno(struct drm_device *dev,
 		struct intel_ring_buffer *ring);
 
-extern struct intel_ring_buffer render_ring;
-extern struct intel_ring_buffer bsd_ring;
+int intel_init_render_ring_buffer(struct drm_device *dev);
+int intel_init_bsd_ring_buffer(struct drm_device *dev);
+int intel_init_blt_ring_buffer(struct drm_device *dev);
+
+u32 intel_ring_get_active_head(struct drm_device *dev,
+			       struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct drm_device *dev,
+				  struct intel_ring_buffer *ring);
 
 #endif /* _INTEL_RINGBUFFER_H_ */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_sdvo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_sdvo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_sdvo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_sdvo.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,8 +65,11 @@
 struct intel_sdvo {
 	struct intel_encoder base;
 
+	struct i2c_adapter *i2c;
 	u8 slave_addr;
 
+	struct i2c_adapter ddc;
+
 	/* Register for the SDVO device: SDVOB or SDVOC */
 	int sdvo_reg;
 
@@ -104,34 +107,25 @@
 	 * This is set if we treat the device as HDMI, instead of DVI.
 	 */
 	bool is_hdmi;
+	bool has_hdmi_monitor;
+	bool has_hdmi_audio;
 
 	/**
-	 * This is set if we detect output of sdvo device as LVDS.
+	 * This is set if we detect output of sdvo device as LVDS and
+	 * have a valid fixed mode to use with the panel.
 	 */
 	bool is_lvds;
 
 	/**
-	 * This is sdvo flags for input timing.
-	 */
-	uint8_t sdvo_flags;
-
-	/**
 	 * This is sdvo fixed pannel mode pointer
 	 */
 	struct drm_display_mode *sdvo_lvds_fixed_mode;
 
-	/*
-	 * supported encoding mode, used to determine whether HDMI is
-	 * supported
-	 */
-	struct intel_sdvo_encode encode;
-
 	/* DDC bus used by this SDVO encoder */
 	uint8_t ddc_bus;
 
-	/* Mac mini hack -- use the same DDC as the analog connector */
-	struct i2c_adapter *analog_ddc_bus;
-
+	/* Input timings for adjusted_mode */
+	struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -140,11 +134,15 @@
 	/* Mark the type of connector */
 	uint16_t output_flag;
 
+	int force_audio;
+
 	/* This contains all current supported TV format */
 	u8 tv_format_supported[TV_FORMAT_NUM];
 	int   format_supported_num;
 	struct drm_property *tv_format;
 
+	struct drm_property *force_audio_property;
+
 	/* add the property for the SDVO-TV */
 	struct drm_property *left;
 	struct drm_property *right;
@@ -186,9 +184,15 @@
 	u32	cur_dot_crawl,	max_dot_crawl;
 };
 
-static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base);
+	return container_of(encoder, struct intel_sdvo, base.base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_sdvo, base);
 }
 
 static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -213,7 +217,7 @@
  */
 static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 bval = val, cval = val;
 	int i;
@@ -245,49 +249,29 @@
 
 static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
 {
-	u8 out_buf[2] = { addr, 0 };
-	u8 buf[2];
 	struct i2c_msg msgs[] = {
 		{
-			.addr = intel_sdvo->slave_addr >> 1,
+			.addr = intel_sdvo->slave_addr,
 			.flags = 0,
 			.len = 1,
-			.buf = out_buf,
+			.buf = &addr,
 		},
 		{
-			.addr = intel_sdvo->slave_addr >> 1,
+			.addr = intel_sdvo->slave_addr,
 			.flags = I2C_M_RD,
 			.len = 1,
-			.buf = buf,
+			.buf = ch,
 		}
 	};
 	int ret;
 
-	if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
-	{
-		*ch = buf[0];
+	if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
 		return true;
-	}
 
 	DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
 	return false;
 }
 
-static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch)
-{
-	u8 out_buf[2] = { addr, ch };
-	struct i2c_msg msgs[] = {
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 2,
-			.buf = out_buf,
-		}
-	};
-
-	return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
-}
-
 #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
 /** Mapping of command numbers to names, for debug output */
 static const struct _sdvo_cmd_name {
@@ -432,22 +416,6 @@
 	DRM_LOG_KMS("\n");
 }
 
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-				 const void *args, int args_len)
-{
-	int i;
-
-	intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
-	for (i = 0; i < args_len; i++) {
-		if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i,
-					   ((u8*)args)[i]))
-			return false;
-	}
-
-	return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd);
-}
-
 static const char *cmd_status_names[] = {
 	"Power on",
 	"Success",
@@ -458,54 +426,115 @@
 	"Scaling not supported"
 };
 
-static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo,
-				      void *response, int response_len,
-				      u8 status)
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+				 const void *args, int args_len)
 {
-	int i;
+	u8 buf[args_len*2 + 2], status;
+	struct i2c_msg msgs[args_len + 3];
+	int i, ret;
 
-	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
-	for (i = 0; i < response_len; i++)
-		DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
-	for (; i < 8; i++)
-		DRM_LOG_KMS("   ");
-	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
-	else
-		DRM_LOG_KMS("(??? %d)", status);
-	DRM_LOG_KMS("\n");
+	intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+	for (i = 0; i < args_len; i++) {
+		msgs[i].addr = intel_sdvo->slave_addr;
+		msgs[i].flags = 0;
+		msgs[i].len = 2;
+		msgs[i].buf = buf + 2 *i;
+		buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+		buf[2*i + 1] = ((u8*)args)[i];
+	}
+	msgs[i].addr = intel_sdvo->slave_addr;
+	msgs[i].flags = 0;
+	msgs[i].len = 2;
+	msgs[i].buf = buf + 2*i;
+	buf[2*i + 0] = SDVO_I2C_OPCODE;
+	buf[2*i + 1] = cmd;
+
+	/* the following two are to read the response */
+	status = SDVO_I2C_CMD_STATUS;
+	msgs[i+1].addr = intel_sdvo->slave_addr;
+	msgs[i+1].flags = 0;
+	msgs[i+1].len = 1;
+	msgs[i+1].buf = &status;
+
+	msgs[i+2].addr = intel_sdvo->slave_addr;
+	msgs[i+2].flags = I2C_M_RD;
+	msgs[i+2].len = 1;
+	msgs[i+2].buf = &status;
+
+	ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+		return false;
+	}
+	if (ret != i+3) {
+		/* failure in I2C transfer */
+		DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+		return false;
+	}
+
+	i = 3;
+	while (status == SDVO_CMD_STATUS_PENDING && i--) {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_CMD_STATUS,
+					  &status))
+			return false;
+	}
+	if (status != SDVO_CMD_STATUS_SUCCESS) {
+		DRM_DEBUG_KMS("command returns response %s [%d]\n",
+			      status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
+			      status);
+		return false;
+	}
+
+	return true;
 }
 
 static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
 				     void *response, int response_len)
 {
-	int i;
+	u8 retry = 5;
 	u8 status;
-	u8 retry = 50;
-
-	while (retry--) {
-		/* Read the command response */
-		for (i = 0; i < response_len; i++) {
-			if (!intel_sdvo_read_byte(intel_sdvo,
-						  SDVO_I2C_RETURN_0 + i,
-						  &((u8 *)response)[i]))
-				return false;
-		}
+	int i;
 
-		/* read the return status */
-		if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS,
+	/*
+	 * The documentation states that all commands will be
+	 * processed within 15Âµs, and that we need only poll
+	 * the status byte a maximum of 3 times in order for the
+	 * command to be complete.
+	 *
+	 * Check 5 times in case the hardware failed to read the docs.
+	 */
+	do {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_CMD_STATUS,
 					  &status))
 			return false;
+	} while (status == SDVO_CMD_STATUS_PENDING && --retry);
 
-		intel_sdvo_debug_response(intel_sdvo, response, response_len,
-					  status);
-		if (status != SDVO_CMD_STATUS_PENDING)
-			break;
+	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+	else
+		DRM_LOG_KMS("(??? %d)", status);
 
-		mdelay(50);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		goto log_fail;
+
+	/* Read the command response */
+	for (i = 0; i < response_len; i++) {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_RETURN_0 + i,
+					  &((u8 *)response)[i]))
+			goto log_fail;
+		DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
 	}
+	DRM_LOG_KMS("\n");
+	return true;
 
-	return status == SDVO_CMD_STATUS_SUCCESS;
+log_fail:
+	DRM_LOG_KMS("\n");
+	return false;
 }
 
 static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
@@ -518,71 +547,17 @@
 		return 4;
 }
 
-/**
- * Try to read the response after issuie the DDC switch command. But it
- * is noted that we must do the action of reading response and issuing DDC
- * switch command in one I2C transaction. Otherwise when we try to start
- * another I2C transaction after issuing the DDC bus switch, it will be
- * switched to the internal SDVO register.
- */
-static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
-					      u8 target)
+static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+					      u8 ddc_bus)
 {
-	u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
-	struct i2c_msg msgs[] = {
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 2,
-			.buf = out_buf,
-		},
-		/* the following two are to read the response */
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 1,
-			.buf = cmd_buf,
-		},
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = I2C_M_RD,
-			.len = 1,
-			.buf = ret_value,
-		},
-	};
-
-	intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
-					&target, 1);
-	/* write the DDC switch command argument */
-	intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target);
-
-	out_buf[0] = SDVO_I2C_OPCODE;
-	out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
-	cmd_buf[0] = SDVO_I2C_CMD_STATUS;
-	cmd_buf[1] = 0;
-	ret_value[0] = 0;
-	ret_value[1] = 0;
-
-	ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
-	if (ret != 3) {
-		/* failure in I2C transfer */
-		DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
-		return;
-	}
-	if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
-		DRM_DEBUG_KMS("DDC switch command returns response %d\n",
-					ret_value[0]);
-		return;
-	}
-	return;
+	return intel_sdvo_write_cmd(intel_sdvo,
+				    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+				    &ddc_bus, 1);
 }
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-	if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
-		return false;
-
-	return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+	return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
 }
 
 static bool
@@ -819,17 +794,13 @@
 		mode->flags |= DRM_MODE_FLAG_PVSYNC;
 }
 
-static bool intel_sdvo_get_supp_encode(struct intel_sdvo *intel_sdvo,
-				       struct intel_sdvo_encode *encode)
+static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
 {
-	if (intel_sdvo_get_value(intel_sdvo,
-				  SDVO_CMD_GET_SUPP_ENCODE,
-				  encode, sizeof(*encode)))
-		return true;
+	struct intel_sdvo_encode encode;
 
-	/* non-support means DVI */
-	memset(encode, 0, sizeof(*encode));
-	return false;
+	return intel_sdvo_get_value(intel_sdvo,
+				  SDVO_CMD_GET_SUPP_ENCODE,
+				  &encode, sizeof(encode));
 }
 
 static bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
@@ -874,115 +845,33 @@
 }
 #endif
 
-static bool intel_sdvo_set_hdmi_buf(struct intel_sdvo *intel_sdvo,
-				    int index,
-				    uint8_t *data, int8_t size, uint8_t tx_rate)
-{
-    uint8_t set_buf_index[2];
-
-    set_buf_index[0] = index;
-    set_buf_index[1] = 0;
-
-    if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
-			      set_buf_index, 2))
-	    return false;
-
-    for (; size > 0; size -= 8) {
-	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA, data, 8))
-		return false;
-
-	data += 8;
-    }
-
-    return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
-}
-
-static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
-{
-	uint8_t csum = 0;
-	int i;
-
-	for (i = 0; i < size; i++)
-		csum += data[i];
-
-	return 0x100 - csum;
-}
-
-#define DIP_TYPE_AVI	0x82
-#define DIP_VERSION_AVI	0x2
-#define DIP_LEN_AVI	13
-
-struct dip_infoframe {
-	uint8_t type;
-	uint8_t version;
-	uint8_t len;
-	uint8_t checksum;
-	union {
-		struct {
-			/* Packet Byte #1 */
-			uint8_t S:2;
-			uint8_t B:2;
-			uint8_t A:1;
-			uint8_t Y:2;
-			uint8_t rsvd1:1;
-			/* Packet Byte #2 */
-			uint8_t R:4;
-			uint8_t M:2;
-			uint8_t C:2;
-			/* Packet Byte #3 */
-			uint8_t SC:2;
-			uint8_t Q:2;
-			uint8_t EC:3;
-			uint8_t ITC:1;
-			/* Packet Byte #4 */
-			uint8_t VIC:7;
-			uint8_t rsvd2:1;
-			/* Packet Byte #5 */
-			uint8_t PR:4;
-			uint8_t rsvd3:4;
-			/* Packet Byte #6~13 */
-			uint16_t top_bar_end;
-			uint16_t bottom_bar_start;
-			uint16_t left_bar_end;
-			uint16_t right_bar_start;
-		} avi;
-		struct {
-			/* Packet Byte #1 */
-			uint8_t channel_count:3;
-			uint8_t rsvd1:1;
-			uint8_t coding_type:4;
-			/* Packet Byte #2 */
-			uint8_t sample_size:2; /* SS0, SS1 */
-			uint8_t sample_frequency:3;
-			uint8_t rsvd2:3;
-			/* Packet Byte #3 */
-			uint8_t coding_type_private:5;
-			uint8_t rsvd3:3;
-			/* Packet Byte #4 */
-			uint8_t channel_allocation;
-			/* Packet Byte #5 */
-			uint8_t rsvd4:3;
-			uint8_t level_shift:4;
-			uint8_t downmix_inhibit:1;
-		} audio;
-		uint8_t payload[28];
-	} __attribute__ ((packed)) u;
-} __attribute__((packed));
-
-static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
-					 struct drm_display_mode * mode)
+static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
 {
 	struct dip_infoframe avi_if = {
 		.type = DIP_TYPE_AVI,
-		.version = DIP_VERSION_AVI,
+		.ver = DIP_VERSION_AVI,
 		.len = DIP_LEN_AVI,
 	};
+	uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
+	uint8_t set_buf_index[2] = { 1, 0 };
+	uint64_t *data = (uint64_t *)&avi_if;
+	unsigned i;
 
-	avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
-						    4 + avi_if.len);
-	return intel_sdvo_set_hdmi_buf(intel_sdvo, 1, (uint8_t *)&avi_if,
-				       4 + avi_if.len,
-				       SDVO_HBUF_TX_VSYNC);
+	intel_dip_infoframe_csum(&avi_if);
+
+	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_INDEX,
+				  set_buf_index, 2))
+		return false;
+
+	for (i = 0; i < sizeof(avi_if); i += 8) {
+		if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_DATA,
+					  data, 8))
+			return false;
+		data++;
+	}
+
+	return intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_HBUF_TXRATE,
+				    &tx_rate, 1);
 }
 
 static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
@@ -1022,8 +911,6 @@
 					struct drm_display_mode *mode,
 					struct drm_display_mode *adjusted_mode)
 {
-	struct intel_sdvo_dtd input_dtd;
-
 	/* Reset the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return false;
@@ -1035,14 +922,12 @@
 		return false;
 
 	if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-						   &input_dtd))
+						   &intel_sdvo->input_dtd))
 		return false;
 
-	intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-	intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
+	intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
 
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
-	mode->clock = adjusted_mode->clock;
 	return true;
 }
 
@@ -1050,7 +935,8 @@
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+	int multiplier;
 
 	/* We need to construct preferred input timings based on our
 	 * output timings.  To do that, we have to set the output
@@ -1065,10 +951,8 @@
 							     mode,
 							     adjusted_mode);
 	} else if (intel_sdvo->is_lvds) {
-		drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
-
 		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-							    intel_sdvo->sdvo_lvds_fixed_mode))
+							     intel_sdvo->sdvo_lvds_fixed_mode))
 			return false;
 
 		(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +961,10 @@
 	}
 
 	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
-	 * SDVO device will be told of the multiplier during mode_set.
+	 * SDVO device will factor out the multiplier during mode_set.
 	 */
-	adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+	multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
+	intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
 
 	return true;
 }
@@ -1092,11 +977,12 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	u32 sdvox = 0;
-	int sdvo_pixel_multiply, rate;
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+	u32 sdvox;
 	struct intel_sdvo_in_out_map in_out;
 	struct intel_sdvo_dtd input_dtd;
+	int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+	int rate;
 
 	if (!mode)
 		return;
@@ -1114,28 +1000,23 @@
 			     SDVO_CMD_SET_IN_OUT_MAP,
 			     &in_out, sizeof(in_out));
 
-	if (intel_sdvo->is_hdmi) {
-		if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
-			return;
-
-		sdvox |= SDVO_AUDIO_ENABLE;
-	}
+	/* Set the output timings to the screen */
+	if (!intel_sdvo_set_target_output(intel_sdvo,
+					  intel_sdvo->attached_output))
+		return;
 
 	/* We have tried to get input timing in mode_fixup, and filled into
-	   adjusted_mode */
-	intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-	if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
-		input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
-
-	/* If it's a TV, we already set the output timing in mode_fixup.
-	 * Otherwise, the output timing is equal to the input timing.
+	 * adjusted_mode.
 	 */
-	if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
+	if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
+		input_dtd = intel_sdvo->input_dtd;
+	} else {
 		/* Set the output timing to the screen */
 		if (!intel_sdvo_set_target_output(intel_sdvo,
 						  intel_sdvo->attached_output))
 			return;
 
+		intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
 		(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
 	}
 
@@ -1143,31 +1024,18 @@
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return;
 
-	if (intel_sdvo->is_tv) {
-		if (!intel_sdvo_set_tv_format(intel_sdvo))
-			return;
-	}
+	if (intel_sdvo->has_hdmi_monitor &&
+	    !intel_sdvo_set_avi_infoframe(intel_sdvo))
+		return;
 
-	/* We would like to use intel_sdvo_create_preferred_input_timing() to
-	 * provide the device with a timing it can support, if it supports that
-	 * feature.  However, presumably we would need to adjust the CRTC to
-	 * output the preferred timing, and we don't support that currently.
-	 */
-#if 0
-	success = intel_sdvo_create_preferred_input_timing(encoder, clock,
-							   width, height);
-	if (success) {
-		struct intel_sdvo_dtd *input_dtd;
+	if (intel_sdvo->is_tv &&
+	    !intel_sdvo_set_tv_format(intel_sdvo))
+		return;
 
-		intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
-		intel_sdvo_set_input_timing(encoder, &input_dtd);
-	}
-#else
 	(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
-#endif
 
-	sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
-	switch (sdvo_pixel_multiply) {
+	switch (pixel_multiplier) {
+	default:
 	case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
 	case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
 	case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1176,14 +1044,14 @@
 		return;
 
 	/* Set the SDVO control regs. */
-	if (IS_I965G(dev)) {
-		sdvox |= SDVO_BORDER_ENABLE;
+	if (INTEL_INFO(dev)->gen >= 4) {
+		sdvox = SDVO_BORDER_ENABLE;
 		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
 			sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 			sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
 	} else {
-		sdvox |= I915_READ(intel_sdvo->sdvo_reg);
+		sdvox = I915_READ(intel_sdvo->sdvo_reg);
 		switch (intel_sdvo->sdvo_reg) {
 		case SDVOB:
 			sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1064,18 @@
 	}
 	if (intel_crtc->pipe == 1)
 		sdvox |= SDVO_PIPE_B_SELECT;
+	if (intel_sdvo->has_hdmi_audio)
+		sdvox |= SDVO_AUDIO_ENABLE;
 
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		/* done in crtc_mode_set as the dpll_md reg must be written early */
 	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
 		/* done in crtc_mode_set as it lives inside the dpll register */
 	} else {
-		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+		sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
 	}
 
-	if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
+	if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
 		sdvox |= SDVO_STALL_SELECT;
 	intel_sdvo_write_sdvox(intel_sdvo, sdvox);
 }
@@ -1214,7 +1084,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	u32 temp;
 
@@ -1260,8 +1130,7 @@
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 
 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		return MODE_NO_DBLESCAN;
@@ -1285,7 +1154,38 @@
 
 static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
 {
-	return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps));
+	if (!intel_sdvo_get_value(intel_sdvo,
+				  SDVO_CMD_GET_DEVICE_CAPS,
+				  caps, sizeof(*caps)))
+		return false;
+
+	DRM_DEBUG_KMS("SDVO capabilities:\n"
+		      "  vendor_id: %d\n"
+		      "  device_id: %d\n"
+		      "  device_rev_id: %d\n"
+		      "  sdvo_version_major: %d\n"
+		      "  sdvo_version_minor: %d\n"
+		      "  sdvo_inputs_mask: %d\n"
+		      "  smooth_scaling: %d\n"
+		      "  sharp_scaling: %d\n"
+		      "  up_scaling: %d\n"
+		      "  down_scaling: %d\n"
+		      "  stall_support: %d\n"
+		      "  output_flags: %d\n",
+		      caps->vendor_id,
+		      caps->device_id,
+		      caps->device_rev_id,
+		      caps->sdvo_version_major,
+		      caps->sdvo_version_minor,
+		      caps->sdvo_inputs_mask,
+		      caps->smooth_scaling,
+		      caps->sharp_scaling,
+		      caps->up_scaling,
+		      caps->down_scaling,
+		      caps->stall_support,
+		      caps->output_flags);
+
+	return true;
 }
 
 /* No use! */
@@ -1389,99 +1289,79 @@
 	return (caps > 1);
 }
 
-static struct drm_connector *
-intel_find_analog_connector(struct drm_device *dev)
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
 {
-	struct drm_connector *connector;
-	struct drm_encoder *encoder;
-	struct intel_sdvo *intel_sdvo;
-
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		intel_sdvo = enc_to_intel_sdvo(encoder);
-		if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) {
-			list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-				if (encoder == intel_attached_encoder(connector))
-					return connector;
-			}
-		}
-	}
-	return NULL;
+	struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+	return drm_get_edid(connector, &sdvo->ddc);
 }
 
-static int
-intel_analog_is_connected(struct drm_device *dev)
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
 {
-	struct drm_connector *analog_connector;
-
-	analog_connector = intel_find_analog_connector(dev);
-	if (!analog_connector)
-		return false;
-
-	if (analog_connector->funcs->detect(analog_connector, false) ==
-			connector_status_disconnected)
-		return false;
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
-	return true;
+	return drm_get_edid(connector,
+			    &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
 }
 
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-	enum drm_connector_status status = connector_status_connected;
-	struct edid *edid = NULL;
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+	enum drm_connector_status status;
+	struct edid *edid;
 
-	edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
+	edid = intel_sdvo_get_edid(connector);
 
-	/* This is only applied to SDVO cards with multiple outputs */
 	if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
-		uint8_t saved_ddc, temp_ddc;
-		saved_ddc = intel_sdvo->ddc_bus;
-		temp_ddc = intel_sdvo->ddc_bus >> 1;
+		u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
 		/*
 		 * Don't use the 1 as the argument of DDC bus switch to get
 		 * the EDID. It is used for SDVO SPD ROM.
 		 */
-		while(temp_ddc > 1) {
-			intel_sdvo->ddc_bus = temp_ddc;
-			edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
-			if (edid) {
-				/*
-				 * When we can get the EDID, maybe it is the
-				 * correct DDC bus. Update it.
-				 */
-				intel_sdvo->ddc_bus = temp_ddc;
+		for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+			intel_sdvo->ddc_bus = ddc;
+			edid = intel_sdvo_get_edid(connector);
+			if (edid)
 				break;
-			}
-			temp_ddc >>= 1;
 		}
+		/*
+		 * If we found the EDID on the other bus,
+		 * assume that is the correct DDC bus.
+		 */
 		if (edid == NULL)
 			intel_sdvo->ddc_bus = saved_ddc;
 	}
-	/* when there is no edid and no monitor is connected with VGA
-	 * port, try to use the CRT ddc to read the EDID for DVI-connector
+
+	/*
+	 * When there is no edid and no monitor is connected with VGA
+	 * port, try to use the CRT ddc to read the EDID for DVI-connector.
 	 */
-	if (edid == NULL && intel_sdvo->analog_ddc_bus &&
-	    !intel_analog_is_connected(connector->dev))
-		edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
+	if (edid == NULL)
+		edid = intel_sdvo_get_analog_edid(connector);
 
+	status = connector_status_unknown;
 	if (edid != NULL) {
-		bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
-		bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK);
-
 		/* DDC bus is shared, match EDID to connector type */
-		if (is_digital && need_digital)
-			intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
-		else if (is_digital != need_digital)
-			status = connector_status_disconnected;
-
+		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+			status = connector_status_connected;
+			if (intel_sdvo->is_hdmi) {
+				intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
+				intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
+			}
+		}
 		connector->display_info.raw_edid = NULL;
-	} else
-		status = connector_status_disconnected;
-	
-	kfree(edid);
+		kfree(edid);
+	}
+
+	if (status == connector_status_connected) {
+		struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
+		if (intel_sdvo_connector->force_audio)
+			intel_sdvo->has_hdmi_audio = intel_sdvo_connector->force_audio > 0;
+	}
 
 	return status;
 }
@@ -1490,22 +1370,25 @@
 intel_sdvo_detect(struct drm_connector *connector, bool force)
 {
 	uint16_t response;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
 	enum drm_connector_status ret;
 
 	if (!intel_sdvo_write_cmd(intel_sdvo,
-			     SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
+				  SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
 		return connector_status_unknown;
-	if (intel_sdvo->is_tv) {
-		/* add 30ms delay when the output type is SDVO-TV */
+
+	/* add 30ms delay when the output type might be TV */
+	if (intel_sdvo->caps.output_flags &
+	    (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0))
 		mdelay(30);
-	}
+
 	if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
 		return connector_status_unknown;
 
-	DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
+	DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+		      response & 0xff, response >> 8,
+		      intel_sdvo_connector->output_flag);
 
 	if (response == 0)
 		return connector_status_disconnected;
@@ -1538,12 +1421,10 @@
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	int num_modes;
+	struct edid *edid;
 
 	/* set the bus switch and get the modes */
-	num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+	edid = intel_sdvo_get_edid(connector);
 
 	/*
 	 * Mac mini hack.  On this device, the DVI-I connector shares one DDC
@@ -1551,12 +1432,16 @@
 	 * DDC fails, check to see if the analog output is disconnected, in
 	 * which case we'll look there for the digital DDC data.
 	 */
-	if (num_modes == 0 &&
-	    intel_sdvo->analog_ddc_bus &&
-	    !intel_analog_is_connected(connector->dev)) {
-		/* Switch to the analog ddc bus and try that
-		 */
-		(void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
+	if (edid == NULL)
+		edid = intel_sdvo_get_analog_edid(connector);
+
+	if (edid != NULL) {
+		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+			drm_mode_connector_update_edid_property(connector, edid);
+			drm_add_edid_modes(connector, edid);
+		}
+		connector->display_info.raw_edid = NULL;
+		kfree(edid);
 	}
 }
 
@@ -1627,8 +1512,7 @@
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_sdtv_resolution_request tv_res;
 	uint32_t reply = 0, format_map = 0;
 	int i;
@@ -1644,7 +1528,8 @@
 		return;
 
 	BUILD_BUG_ON(sizeof(tv_res) != 3);
-	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+	if (!intel_sdvo_write_cmd(intel_sdvo,
+				  SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
 				  &tv_res, sizeof(tv_res)))
 		return;
 	if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
@@ -1662,8 +1547,7 @@
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	struct drm_display_mode *newmode;
 
@@ -1672,7 +1556,7 @@
 	 * Assume that the preferred modes are
 	 * arranged in priority order.
 	 */
-	intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+	intel_ddc_get_modes(connector, intel_sdvo->i2c);
 	if (list_empty(&connector->probed_modes) == false)
 		goto end;
 
@@ -1693,6 +1577,10 @@
 		if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
 			intel_sdvo->sdvo_lvds_fixed_mode =
 				drm_mode_duplicate(connector->dev, newmode);
+
+			drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
+					      0);
+
 			intel_sdvo->is_lvds = true;
 			break;
 		}
@@ -1775,8 +1663,7 @@
 			struct drm_property *property,
 			uint64_t val)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
 	uint16_t temp_value;
 	uint8_t cmd;
@@ -1786,6 +1673,21 @@
 	if (ret)
 		return ret;
 
+	if (property == intel_sdvo_connector->force_audio_property) {
+		if (val == intel_sdvo_connector->force_audio)
+			return 0;
+
+		intel_sdvo_connector->force_audio = val;
+
+		if (val > 0 && intel_sdvo->has_hdmi_audio)
+			return 0;
+		if (val < 0 && !intel_sdvo->has_hdmi_audio)
+			return 0;
+
+		intel_sdvo->has_hdmi_audio = val > 0;
+		goto done;
+	}
+
 #define CHECK_PROPERTY(name, NAME) \
 	if (intel_sdvo_connector->name == property) { \
 		if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
@@ -1879,9 +1781,8 @@
 
 
 done:
-	if (encoder->crtc) {
-		struct drm_crtc *crtc = encoder->crtc;
-
+	if (intel_sdvo->base.base.crtc) {
+		struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
 		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
 					 crtc->y, crtc->fb);
 	}
@@ -1909,20 +1810,18 @@
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
 	.get_modes = intel_sdvo_get_modes,
 	.mode_valid = intel_sdvo_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-
-	if (intel_sdvo->analog_ddc_bus)
-		intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 
 	if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
 		drm_mode_destroy(encoder->dev,
 				 intel_sdvo->sdvo_lvds_fixed_mode);
 
+	i2c_del_adapter(&intel_sdvo->ddc);
 	intel_encoder_destroy(encoder);
 }
 
@@ -1990,53 +1889,51 @@
 		intel_sdvo_guess_ddc_bus(sdvo);
 }
 
-static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+			  struct intel_sdvo *sdvo, u32 reg)
 {
-	return intel_sdvo_set_target_output(intel_sdvo,
-					    device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1) &&
-		intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
-				     &intel_sdvo->is_hdmi, 1);
-}
+	struct sdvo_device_mapping *mapping;
+	u8 pin, speed;
 
-static struct intel_sdvo *
-intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan)
-{
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_encoder *encoder;
+	if (IS_SDVOB(reg))
+		mapping = &dev_priv->sdvo_mappings[0];
+	else
+		mapping = &dev_priv->sdvo_mappings[1];
 
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-		if (intel_sdvo->base.ddc_bus == &chan->adapter)
-			return intel_sdvo;
+	pin = GMBUS_PORT_DPB;
+	speed = GMBUS_RATE_1MHZ >> 8;
+	if (mapping->initialized) {
+		pin = mapping->i2c_pin;
+		speed = mapping->i2c_speed;
 	}
 
-	return NULL;
+	if (pin < GMBUS_NUM_PORTS) {
+		sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+		intel_gmbus_set_speed(sdvo->i2c, speed);
+		intel_gmbus_force_bit(sdvo->i2c, true);
+	} else
+		sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;
 }
 
-static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
-				  struct i2c_msg msgs[], int num)
+static bool
+intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
 {
-	struct intel_sdvo *intel_sdvo;
-	struct i2c_algo_bit_data *algo_data;
-	const struct i2c_algorithm *algo;
+	int is_hdmi;
 
-	algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
-	intel_sdvo =
-		intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *)
-					      (algo_data->data));
-	if (intel_sdvo == NULL)
-		return -EINVAL;
+	if (!intel_sdvo_check_supp_encode(intel_sdvo))
+		return false;
 
-	algo = intel_sdvo->base.i2c_bus->algo;
+	if (!intel_sdvo_set_target_output(intel_sdvo,
+					  device == 0 ? SDVO_OUTPUT_TMDS0 : SDVO_OUTPUT_TMDS1))
+		return false;
 
-	intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus);
-	return algo->master_xfer(i2c_adap, msgs, num);
-}
+	is_hdmi = 0;
+	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, &is_hdmi, 1))
+		return false;
 
-static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
-	.master_xfer	= intel_sdvo_master_xfer,
-};
+	return !!is_hdmi;
+}
 
 static u8
 intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
@@ -2076,26 +1973,44 @@
 }
 
 static void
-intel_sdvo_connector_init(struct drm_encoder *encoder,
-			  struct drm_connector *connector)
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+			  struct intel_sdvo *encoder)
 {
-	drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
-			   connector->connector_type);
+	drm_connector_init(encoder->base.base.dev,
+			   &connector->base.base,
+			   &intel_sdvo_connector_funcs,
+			   connector->base.base.connector_type);
 
-	drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+	drm_connector_helper_add(&connector->base.base,
+				 &intel_sdvo_connector_helper_funcs);
 
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+	connector->base.base.interlace_allowed = 0;
+	connector->base.base.doublescan_allowed = 0;
+	connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
-	drm_mode_connector_attach_encoder(connector, encoder);
-	drm_sysfs_connector_add(connector);
+	intel_connector_attach_encoder(&connector->base, &encoder->base);
+	drm_sysfs_connector_add(&connector->base.base);
+}
+
+static void
+intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
+{
+	struct drm_device *dev = connector->base.base.dev;
+
+	connector->force_audio_property =
+		drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
+	if (connector->force_audio_property) {
+		connector->force_audio_property->values[0] = -1;
+		connector->force_audio_property->values[1] = 1;
+		drm_connector_attach_property(&connector->base.base,
+					      connector->force_audio_property, 0);
+	}
 }
 
 static bool
 intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 {
-	struct drm_encoder *encoder = &intel_sdvo->base.enc;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
 	struct drm_connector *connector;
 	struct intel_connector *intel_connector;
 	struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2118,19 +2033,21 @@
 	encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
 	connector->connector_type = DRM_MODE_CONNECTOR_DVID;
 
-	if (intel_sdvo_get_supp_encode(intel_sdvo, &intel_sdvo->encode)
-		&& intel_sdvo_get_digital_encoding_mode(intel_sdvo, device)
-		&& intel_sdvo->is_hdmi) {
+	if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
 		/* enable hdmi encoding mode if supported */
 		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
 		intel_sdvo_set_colorimetry(intel_sdvo,
 					   SDVO_COLORIMETRY_RGB256);
 		connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
+
+		intel_sdvo->is_hdmi = true;
 	}
 	intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
 				       (1 << INTEL_ANALOG_CLONE_BIT));
 
-	intel_sdvo_connector_init(encoder, connector);
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+	if (intel_sdvo->is_hdmi)
+		intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
 
 	return true;
 }
@@ -2138,36 +2055,36 @@
 static bool
 intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
 
 	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
 	if (!intel_sdvo_connector)
 		return false;
 
 	intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 
-        intel_sdvo->controlled_output |= type;
-        intel_sdvo_connector->output_flag = type;
+	intel_sdvo->controlled_output |= type;
+	intel_sdvo_connector->output_flag = type;
 
-        intel_sdvo->is_tv = true;
-        intel_sdvo->base.needs_tv_clock = true;
-        intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+	intel_sdvo->is_tv = true;
+	intel_sdvo->base.needs_tv_clock = true;
+	intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
 
-        intel_sdvo_connector_init(encoder, connector);
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
 
-        if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+	if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
 		goto err;
 
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
 		goto err;
 
-        return true;
+	return true;
 
 err:
 	intel_sdvo_destroy(connector);
@@ -2177,43 +2094,44 @@
 static bool
 intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
 
 	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
 	if (!intel_sdvo_connector)
 		return false;
 
 	intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
+	connector = &intel_connector->base;
 	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-        encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+	encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_VGA;
 
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-        }
+	if (device == 0) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+	} else if (device == 1) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+	}
 
-        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+	intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
 				       (1 << INTEL_ANALOG_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        return true;
+	intel_sdvo_connector_init(intel_sdvo_connector,
+				  intel_sdvo);
+	return true;
 }
 
 static bool
 intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
 
 	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
 	if (!intel_sdvo_connector)
@@ -2221,22 +2139,22 @@
 
 	intel_connector = &intel_sdvo_connector->base;
 	connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-        connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+	encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+	connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
 
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-        }
+	if (device == 0) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+	} else if (device == 1) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+	}
 
-        intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+	intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
 				       (1 << INTEL_SDVO_LVDS_CLONE_BIT));
 
-        intel_sdvo_connector_init(encoder, connector);
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
 		goto err;
 
 	return true;
@@ -2307,7 +2225,7 @@
 					  struct intel_sdvo_connector *intel_sdvo_connector,
 					  int type)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct intel_sdvo_tv_format format;
 	uint32_t format_map, i;
 
@@ -2373,7 +2291,7 @@
 				      struct intel_sdvo_connector *intel_sdvo_connector,
 				      struct intel_sdvo_enhancements_reply enhancements)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_connector *connector = &intel_sdvo_connector->base.base;
 	uint16_t response, data_value[2];
 
@@ -2502,7 +2420,7 @@
 					struct intel_sdvo_connector *intel_sdvo_connector,
 					struct intel_sdvo_enhancements_reply enhancements)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_connector *connector = &intel_sdvo_connector->base.base;
 	uint16_t response, data_value[2];
 
@@ -2535,7 +2453,43 @@
 		return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
 	else
 		return true;
+}
+
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+				     struct i2c_msg *msgs,
+				     int num)
+{
+	struct intel_sdvo *sdvo = adapter->algo_data;
+
+	if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+		return -EIO;
+
+	return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
+
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+	struct intel_sdvo *sdvo = adapter->algo_data;
+	return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+	.master_xfer	= intel_sdvo_ddc_proxy_xfer,
+	.functionality	= intel_sdvo_ddc_proxy_func
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+			  struct drm_device *dev)
+{
+	sdvo->ddc.owner = THIS_MODULE;
+	sdvo->ddc.class = I2C_CLASS_DDC;
+	snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+	sdvo->ddc.dev.parent = &dev->pdev->dev;
+	sdvo->ddc.algo_data = sdvo;
+	sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
 
+	return i2c_add_adapter(&sdvo->ddc) == 0;
 }
 
 bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
@@ -2543,95 +2497,66 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_sdvo *intel_sdvo;
-	u8 ch[0x40];
 	int i;
-	u32 i2c_reg, ddc_reg, analog_ddc_reg;
 
 	intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
 	if (!intel_sdvo)
 		return false;
 
+	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
+		kfree(intel_sdvo);
+		return false;
+	}
+
 	intel_sdvo->sdvo_reg = sdvo_reg;
 
 	intel_encoder = &intel_sdvo->base;
 	intel_encoder->type = INTEL_OUTPUT_SDVO;
+	/* encoder type will be decided later */
+	drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-	if (HAS_PCH_SPLIT(dev)) {
-		i2c_reg = PCH_GPIOE;
-		ddc_reg = PCH_GPIOE;
-		analog_ddc_reg = PCH_GPIOA;
-	} else {
-		i2c_reg = GPIOE;
-		ddc_reg = GPIOE;
-		analog_ddc_reg = GPIOA;
-	}
-
-	/* setup the DDC bus. */
-	if (IS_SDVOB(sdvo_reg))
-		intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
-	else
-		intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
-
-	if (!intel_encoder->i2c_bus)
-		goto err_inteloutput;
-
-	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
-
-	/* Save the bit-banging i2c functionality for use by the DDC wrapper */
-	intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
+	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+	intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
 
 	/* Read the regs to test if we can talk to the device */
 	for (i = 0; i < 0x40; i++) {
-		if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
+		u8 byte;
+
+		if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
 			DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
 				      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-			goto err_i2c;
+			goto err;
 		}
 	}
 
-	/* setup the DDC bus. */
-	if (IS_SDVOB(sdvo_reg)) {
-		intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
-		intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-						"SDVOB/VGA DDC BUS");
+	if (IS_SDVOB(sdvo_reg))
 		dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-	} else {
-		intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
-		intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-						"SDVOC/VGA DDC BUS");
+	else
 		dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
-	}
-	if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
-		goto err_i2c;
 
-	/* Wrap with our custom algo which switches to DDC mode */
-	intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
-
-	/* encoder type will be decided later */
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
 	/* In default case sdvo lvds is false */
 	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-		goto err_enc;
+		goto err;
 
 	if (intel_sdvo_output_setup(intel_sdvo,
 				    intel_sdvo->caps.output_flags) != true) {
 		DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
 			      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-		goto err_enc;
+		goto err;
 	}
 
 	intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
-		goto err_enc;
+		goto err;
 
 	if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
 						    &intel_sdvo->pixel_clock_min,
 						    &intel_sdvo->pixel_clock_max))
-		goto err_enc;
+		goto err;
 
 	DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
 			"clock range %dMHz - %dMHz, "
@@ -2651,16 +2576,9 @@
 			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 	return true;
 
-err_enc:
-	drm_encoder_cleanup(&intel_encoder->enc);
-err_i2c:
-	if (intel_sdvo->analog_ddc_bus != NULL)
-		intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
-	if (intel_encoder->ddc_bus != NULL)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
-	if (intel_encoder->i2c_bus != NULL)
-		intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
+	drm_encoder_cleanup(&intel_encoder->base);
+	i2c_del_adapter(&intel_sdvo->ddc);
 	kfree(intel_sdvo);
 
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_tv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_tv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/intel_tv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/intel_tv.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,7 +48,7 @@
 	struct intel_encoder base;
 
 	int type;
-	char *tv_format;
+	const char *tv_format;
 	int margin[4];
 	u32 save_TV_H_CTL_1;
 	u32 save_TV_H_CTL_2;
@@ -350,7 +350,7 @@
 
 
 struct tv_mode {
-	char *name;
+	const char *name;
 	int clock;
 	int refresh; /* in millihertz (for precision) */
 	u32 oversample;
@@ -900,7 +900,14 @@
 
 static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base);
+	return container_of(encoder, struct intel_tv, base.base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_tv,
+			    base);
 }
 
 static void
@@ -922,7 +929,7 @@
 }
 
 static const struct tv_mode *
-intel_tv_mode_lookup (char *tv_format)
+intel_tv_mode_lookup(const char *tv_format)
 {
 	int i;
 
@@ -936,22 +943,23 @@
 }
 
 static const struct tv_mode *
-intel_tv_mode_find (struct intel_tv *intel_tv)
+intel_tv_mode_find(struct intel_tv *intel_tv)
 {
 	return intel_tv_mode_lookup(intel_tv->tv_format);
 }
 
 static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+intel_tv_mode_valid(struct drm_connector *connector,
+		    struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
 	/* Ensure TV refresh is close to desired refresh */
 	if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
 				< 1000)
 		return MODE_OK;
+
 	return MODE_CLOCK_RANGE;
 }
 
@@ -1131,7 +1139,7 @@
 			   color_conversion->av);
 	}
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		I915_WRITE(TV_CLR_KNOBS, 0x00404000);
 	else
 		I915_WRITE(TV_CLR_KNOBS, 0x00606000);
@@ -1157,12 +1165,12 @@
 		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
 
 		/* Wait for vblank for the disable to take effect */
-		if (!IS_I9XX(dev))
+		if (IS_GEN2(dev))
 			intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-		I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+		I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
 		/* Wait for vblank for the disable to take effect. */
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
+		intel_wait_for_pipe_off(dev, intel_crtc->pipe);
 
 		/* Filter ctl must be set before TV_WIN_SIZE */
 		I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
@@ -1196,7 +1204,7 @@
 		I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
 	for (i = 0; i < 43; i++)
 		I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
-	I915_WRITE(TV_DAC, 0);
+	I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
 	I915_WRITE(TV_CTL, tv_ctl);
 }
 
@@ -1228,15 +1236,13 @@
 static int
 intel_tv_detect_type (struct intel_tv *intel_tv)
 {
-	struct drm_encoder *encoder = &intel_tv->base.enc;
+	struct drm_encoder *encoder = &intel_tv->base.base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 	u32 tv_ctl, save_tv_ctl;
 	u32 tv_dac, save_tv_dac;
-	int type = DRM_MODE_CONNECTOR_Unknown;
-
-	tv_dac = I915_READ(TV_DAC);
+	int type;
 
 	/* Disable TV interrupts around load detect or we'll recurse */
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
@@ -1244,19 +1250,14 @@
 			      PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 
-	/*
-	 * Detect TV by polling)
-	 */
-	save_tv_dac = tv_dac;
-	tv_ctl = I915_READ(TV_CTL);
-	save_tv_ctl = tv_ctl;
-	tv_ctl &= ~TV_ENC_ENABLE;
-	tv_ctl &= ~TV_TEST_MODE_MASK;
+	save_tv_dac = tv_dac = I915_READ(TV_DAC);
+	save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+	/* Poll for TV detection */
+	tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
 	tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-	tv_dac &= ~TVDAC_SENSE_MASK;
-	tv_dac &= ~DAC_A_MASK;
-	tv_dac &= ~DAC_B_MASK;
-	tv_dac &= ~DAC_C_MASK;
+
+	tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
 	tv_dac |= (TVDAC_STATE_CHG_EN |
 		   TVDAC_A_SENSE_CTL |
 		   TVDAC_B_SENSE_CTL |
@@ -1265,37 +1266,40 @@
 		   DAC_A_0_7_V |
 		   DAC_B_0_7_V |
 		   DAC_C_0_7_V);
+
 	I915_WRITE(TV_CTL, tv_ctl);
 	I915_WRITE(TV_DAC, tv_dac);
 	POSTING_READ(TV_DAC);
-	msleep(20);
 
-	tv_dac = I915_READ(TV_DAC);
-	I915_WRITE(TV_DAC, save_tv_dac);
-	I915_WRITE(TV_CTL, save_tv_ctl);
-	POSTING_READ(TV_CTL);
-	msleep(20);
+	intel_wait_for_vblank(intel_tv->base.base.dev,
+			      to_intel_crtc(intel_tv->base.base.crtc)->pipe);
 
-	/*
-	 *  A B C
-	 *  0 1 1 Composite
-	 *  1 0 X svideo
-	 *  0 0 0 Component
-	 */
-	if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
-		DRM_DEBUG_KMS("Detected Composite TV connection\n");
-		type = DRM_MODE_CONNECTOR_Composite;
-	} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
-		DRM_DEBUG_KMS("Detected S-Video TV connection\n");
-		type = DRM_MODE_CONNECTOR_SVIDEO;
-	} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
-		DRM_DEBUG_KMS("Detected Component TV connection\n");
-		type = DRM_MODE_CONNECTOR_Component;
-	} else {
-		DRM_DEBUG_KMS("No TV connection detected\n");
-		type = -1;
+	type = -1;
+	if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
+		DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+		/*
+		 *  A B C
+		 *  0 1 1 Composite
+		 *  1 0 X svideo
+		 *  0 0 0 Component
+		 */
+		if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+			DRM_DEBUG_KMS("Detected Composite TV connection\n");
+			type = DRM_MODE_CONNECTOR_Composite;
+		} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+			DRM_DEBUG_KMS("Detected S-Video TV connection\n");
+			type = DRM_MODE_CONNECTOR_SVIDEO;
+		} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+			DRM_DEBUG_KMS("Detected Component TV connection\n");
+			type = DRM_MODE_CONNECTOR_Component;
+		} else {
+			DRM_DEBUG_KMS("Unrecognised TV connection\n");
+		}
 	}
 
+	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+	I915_WRITE(TV_CTL, save_tv_ctl);
+
 	/* Restore interrupt config */
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
@@ -1311,8 +1315,7 @@
  */
 static void intel_tv_find_better_format(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 	int i;
 
@@ -1344,14 +1347,13 @@
 intel_tv_detect(struct drm_connector *connector, bool force)
 {
 	struct drm_display_mode mode;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	int type;
 
 	mode = reported_modes[0];
 	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-	if (encoder->crtc && encoder->crtc->enabled) {
+	if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
 		type = intel_tv_detect_type(intel_tv);
 	} else if (force) {
 		struct drm_crtc *crtc;
@@ -1375,11 +1377,10 @@
 	return connector_status_connected;
 }
 
-static struct input_res {
-	char *name;
+static const struct input_res {
+	const char *name;
 	int w, h;
-} input_res_table[] =
-{
+} input_res_table[] = {
 	{"640x480", 640, 480},
 	{"800x600", 800, 600},
 	{"1024x768", 1024, 768},
@@ -1396,8 +1397,7 @@
 intel_tv_chose_preferred_modes(struct drm_connector *connector,
 			       struct drm_display_mode *mode_ptr)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
 	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1422,15 +1422,14 @@
 intel_tv_get_modes(struct drm_connector *connector)
 {
 	struct drm_display_mode *mode_ptr;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 	int j, count = 0;
 	u64 tmp;
 
 	for (j = 0; j < ARRAY_SIZE(input_res_table);
 	     j++) {
-		struct input_res *input = &input_res_table[j];
+		const struct input_res *input = &input_res_table[j];
 		unsigned int hactive_s = input->w;
 		unsigned int vactive_s = input->h;
 
@@ -1488,9 +1487,8 @@
 		      uint64_t val)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
-	struct drm_crtc *crtc = encoder->crtc;
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
+	struct drm_crtc *crtc = intel_tv->base.base.crtc;
 	int ret = 0;
 	bool changed = false;
 
@@ -1555,7 +1553,7 @@
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
 	.mode_valid = intel_tv_mode_valid,
 	.get_modes = intel_tv_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1607,7 +1605,7 @@
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
 	u32 tv_dac_on, tv_dac_off, save_tv_dac;
-	char **tv_format_names;
+	char *tv_format_names[ARRAY_SIZE(tv_modes)];
 	int i, initial_mode = 0;
 
 	if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1661,15 +1659,15 @@
 	drm_connector_init(dev, connector, &intel_tv_connector_funcs,
 			   DRM_MODE_CONNECTOR_SVIDEO);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
 			 DRM_MODE_ENCODER_TVDAC);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_encoder->type = INTEL_OUTPUT_TVOUT;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
 	intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
-	intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
-	intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+	intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+	intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
 	intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
 	/* BIOS margin values */
@@ -1678,21 +1676,19 @@
 	intel_tv->margin[TV_MARGIN_RIGHT] = 46;
 	intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
 
-	intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+	intel_tv->tv_format = tv_modes[initial_mode].name;
 
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
 	drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
 	connector->interlace_allowed = false;
 	connector->doublescan_allowed = false;
 
 	/* Create TV properties then attach current values */
-	tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
-				  GFP_KERNEL);
-	if (!tv_format_names)
-		goto out;
 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
-		tv_format_names[i] = tv_modes[i].name;
-	drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
+		tv_format_names[i] = (char *)tv_modes[i].name;
+	drm_mode_create_tv_properties(dev,
+				      ARRAY_SIZE(tv_modes),
+				      tv_format_names);
 
 	drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
 				   initial_mode);
@@ -1708,6 +1704,5 @@
 	drm_connector_attach_property(connector,
 				   dev->mode_config.tv_bottom_margin_property,
 				   intel_tv->margin[TV_MARGIN_BOTTOM]);
-out:
 	drm_sysfs_connector_add(connector);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/i915/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/i915/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -26,15 +26,17 @@
 	  intel_dvo.o \
 	  intel_ringbuffer.o \
 	  intel_overlay.o \
+	  intel_opregion.o \
 	  dvo_ch7xxx.o \
 	  dvo_ch7017.o \
 	  dvo_ivch.o \
 	  dvo_tfp410.o \
 	  dvo_sil164.o
 
-i915-$(CONFIG_ACPI)	+= i915_opregion.o
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 
+i915-$(CONFIG_ACPI)	+= intel_acpi.o
+
 obj-$(CONFIG_DRM_I915)  += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/Kconfig linux-libre-2.6.37-gnu/drivers/gpu/drm/Kconfig
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -73,7 +73,8 @@
 
 config DRM_I810
 	tristate "Intel I810"
-	depends on DRM && AGP && AGP_INTEL
+	# BKL usage in order to avoid AB-BA deadlocks, may become BROKEN_ON_SMP
+	depends on DRM && AGP && AGP_INTEL && BKL
 	help
 	  Choose this option if you have an Intel I810 graphics card.  If M is
 	  selected, the module will be called i810.  AGP support is required
@@ -86,6 +87,8 @@
 
 config DRM_I830
 	tristate "i830 driver"
+	# BKL usage in order to avoid AB-BA deadlocks, i830 may get removed
+	depends on BKL
 	help
 	  Choose this option if you have a system that has Intel 830M, 845G,
 	  852GM, 855GM or 865G integrated graphics.  If M is selected, the
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
 ccflags-y := -Iinclude/drm
 
 drm-y       :=	drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
-		drm_context.o drm_dma.o drm_drawable.o \
+		drm_context.o drm_dma.o \
 		drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
 		drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
 		drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/mga/mga_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/mga/mga_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/mga/mga_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/mga/mga_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,8 +60,6 @@
 	.irq_uninstall = mga_driver_irq_uninstall,
 	.irq_handler = mga_driver_irq_handler,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = mga_ioctls,
 	.dma_ioctl = mga_dma_buffers,
 	.fops = {
@@ -75,6 +73,7 @@
 #ifdef CONFIG_COMPAT
 		.compat_ioctl = mga_compat_ioctl,
 #endif
+		.llseek = noop_llseek,
 	},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/Kconfig linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/Kconfig
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -10,6 +10,7 @@
 	select FB
 	select FRAMEBUFFER_CONSOLE if !EMBEDDED
 	select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
+	select ACPI_VIDEO if ACPI
 	help
 	  Choose this option for open-source nVidia support.
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -9,7 +9,8 @@
              nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
              nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
              nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
-             nouveau_dp.o \
+             nouveau_dp.o nouveau_ramht.o \
+	     nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
              nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
@@ -23,7 +24,8 @@
              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 nv04_fbcon.o \
              nv10_gpio.o nv50_gpio.o \
-	     nv50_calc.o
+	     nv50_calc.o \
+	     nv04_pm.o nv50_pm.o nva3_pm.o
 
 nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_acpi.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_acpi.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_acpi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_acpi.c	2011-01-04 19:50:19.000000000 -0500
@@ -292,6 +292,6 @@
 	if (ret < 0)
 		return ret;
 
-	nv_connector->edid = edid;
+	nv_connector->edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_backlight.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_backlight.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_backlight.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_backlight.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,7 @@
  */
 
 #include <linux/backlight.h>
+#include <linux/acpi.h>
 
 #include "drmP.h"
 #include "nouveau_drv.h"
@@ -136,6 +137,14 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
+#ifdef CONFIG_ACPI
+	if (acpi_video_backlight_support()) {
+		NV_INFO(dev, "ACPI backlight interface available, "
+			     "not registering our own\n");
+		return 0;
+	}
+#endif
+
 	switch (dev_priv->card_type) {
 	case NV_40:
 		return nouveau_nv40_backlight_init(dev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bios.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bios.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bios.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bios.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,9 +43,6 @@
 #define BIOSLOG(sip, fmt, arg...) NV_DEBUG(sip->dev, fmt, ##arg)
 #define LOG_OLD_VALUE(x)
 
-#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
-#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
-
 struct init_exec {
 	bool execute;
 	bool repeat;
@@ -272,12 +269,6 @@
 	int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
 };
 
-struct bit_entry {
-	uint8_t id[2];
-	uint16_t length;
-	uint16_t offset;
-};
-
 static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *);
 
 #define MACRO_INDEX_SIZE	2
@@ -1231,7 +1222,7 @@
 			return 3;
 		}
 
-		if (cond & 1)
+		if (!(cond & 1))
 			iexec->execute = false;
 	}
 		break;
@@ -2167,11 +2158,11 @@
 
 	if (off < pci_resource_len(dev->pdev, 1)) {
 		uint8_t __iomem *p =
-			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+			io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
 
 		val = ioread32(p + (off & ~PAGE_MASK));
 
-		io_mapping_unmap_atomic(p, KM_USER0);
+		io_mapping_unmap_atomic(p);
 	}
 
 	return val;
@@ -2183,12 +2174,12 @@
 {
 	if (off < pci_resource_len(dev->pdev, 1)) {
 		uint8_t __iomem *p =
-			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
+			io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
 
 		iowrite32(val, p + (off & ~PAGE_MASK));
 		wmb();
 
-		io_mapping_unmap_atomic(p, KM_USER0);
+		io_mapping_unmap_atomic(p);
 	}
 }
 
@@ -4675,6 +4666,92 @@
 	return 0;
 }
 
+struct pll_mapping {
+	u8  type;
+	u32 reg;
+};
+
+static struct pll_mapping nv04_pll_mapping[] = {
+	{ PLL_CORE  , NV_PRAMDAC_NVPLL_COEFF },
+	{ PLL_MEMORY, NV_PRAMDAC_MPLL_COEFF },
+	{ PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+	{ PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+	{}
+};
+
+static struct pll_mapping nv40_pll_mapping[] = {
+	{ PLL_CORE  , 0x004000 },
+	{ PLL_MEMORY, 0x004020 },
+	{ PLL_VPLL0 , NV_PRAMDAC_VPLL_COEFF },
+	{ PLL_VPLL1 , NV_RAMDAC_VPLL2 },
+	{}
+};
+
+static struct pll_mapping nv50_pll_mapping[] = {
+	{ PLL_CORE  , 0x004028 },
+	{ PLL_SHADER, 0x004020 },
+	{ PLL_UNK03 , 0x004000 },
+	{ PLL_MEMORY, 0x004008 },
+	{ PLL_UNK40 , 0x00e810 },
+	{ PLL_UNK41 , 0x00e818 },
+	{ PLL_UNK42 , 0x00e824 },
+	{ PLL_VPLL0 , 0x614100 },
+	{ PLL_VPLL1 , 0x614900 },
+	{}
+};
+
+static struct pll_mapping nv84_pll_mapping[] = {
+	{ PLL_CORE  , 0x004028 },
+	{ PLL_SHADER, 0x004020 },
+	{ PLL_MEMORY, 0x004008 },
+	{ PLL_UNK05 , 0x004030 },
+	{ PLL_UNK41 , 0x00e818 },
+	{ PLL_VPLL0 , 0x614100 },
+	{ PLL_VPLL1 , 0x614900 },
+	{}
+};
+
+u32
+get_pll_register(struct drm_device *dev, enum pll_types type)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct pll_mapping *map;
+	int i;
+
+	if (dev_priv->card_type < NV_40)
+		map = nv04_pll_mapping;
+	else
+	if (dev_priv->card_type < NV_50)
+		map = nv40_pll_mapping;
+	else {
+		u8 *plim = &bios->data[bios->pll_limit_tbl_ptr];
+
+		if (plim[0] >= 0x30) {
+			u8 *entry = plim + plim[1];
+			for (i = 0; i < plim[3]; i++, entry += plim[2]) {
+				if (entry[0] == type)
+					return ROM32(entry[3]);
+			}
+
+			return 0;
+		}
+
+		if (dev_priv->chipset == 0x50)
+			map = nv50_pll_mapping;
+		else
+			map = nv84_pll_mapping;
+	}
+
+	while (map->reg) {
+		if (map->type == type)
+			return map->reg;
+		map++;
+	}
+
+	return 0;
+}
+
 int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim)
 {
 	/*
@@ -4750,6 +4827,17 @@
 	/* initialize all members to zero */
 	memset(pll_lim, 0, sizeof(struct pll_lims));
 
+	/* if we were passed a type rather than a register, figure
+	 * out the register and store it
+	 */
+	if (limit_match > PLL_MAX)
+		pll_lim->reg = limit_match;
+	else {
+		pll_lim->reg = get_pll_register(dev, limit_match);
+		if (!pll_lim->reg)
+			return -ENOENT;
+	}
+
 	if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
 		uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];
 
@@ -4785,7 +4873,6 @@
 		pll_lim->max_usable_log2p = 0x6;
 	} else if (pll_lim_ver == 0x20 || pll_lim_ver == 0x21) {
 		uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen;
-		uint32_t reg = 0; /* default match */
 		uint8_t *pll_rec;
 		int i;
 
@@ -4797,37 +4884,22 @@
 			NV_WARN(dev, "Default PLL limit entry has non-zero "
 				       "register field\n");
 
-		if (limit_match > MAX_PLL_TYPES)
-			/* we've been passed a reg as the match */
-			reg = limit_match;
-		else /* limit match is a pll type */
-			for (i = 1; i < entries && !reg; i++) {
-				uint32_t cmpreg = ROM32(bios->data[plloffs + recordlen * i]);
-
-				if (limit_match == NVPLL &&
-				    (cmpreg == NV_PRAMDAC_NVPLL_COEFF || cmpreg == 0x4000))
-					reg = cmpreg;
-				if (limit_match == MPLL &&
-				    (cmpreg == NV_PRAMDAC_MPLL_COEFF || cmpreg == 0x4020))
-					reg = cmpreg;
-				if (limit_match == VPLL1 &&
-				    (cmpreg == NV_PRAMDAC_VPLL_COEFF || cmpreg == 0x4010))
-					reg = cmpreg;
-				if (limit_match == VPLL2 &&
-				    (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018))
-					reg = cmpreg;
-			}
-
 		for (i = 1; i < entries; i++)
-			if (ROM32(bios->data[plloffs + recordlen * i]) == reg) {
+			if (ROM32(bios->data[plloffs + recordlen * i]) == pll_lim->reg) {
 				pllindex = i;
 				break;
 			}
 
+		if ((dev_priv->card_type >= NV_50) && (pllindex == 0)) {
+			NV_ERROR(dev, "Register 0x%08x not found in PLL "
+				 "limits table", pll_lim->reg);
+			return -ENOENT;
+		}
+
 		pll_rec = &bios->data[plloffs + recordlen * pllindex];
 
 		BIOSLOG(bios, "Loading PLL limits for reg 0x%08x\n",
-			pllindex ? reg : 0);
+			pllindex ? pll_lim->reg : 0);
 
 		/*
 		 * Frequencies are stored in tables in MHz, kHz are more
@@ -4877,8 +4949,8 @@
 		if (cv == 0x51 && !pll_lim->refclk) {
 			uint32_t sel_clk = bios_rd32(bios, NV_PRAMDAC_SEL_CLK);
 
-			if (((limit_match == NV_PRAMDAC_VPLL_COEFF || limit_match == VPLL1) && sel_clk & 0x20) ||
-			    ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) {
+			if ((pll_lim->reg == NV_PRAMDAC_VPLL_COEFF && sel_clk & 0x20) ||
+			    (pll_lim->reg == NV_RAMDAC_VPLL2 && sel_clk & 0x80)) {
 				if (bios_idxprt_rd(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_CHIP_ID_INDEX) < 0xa3)
 					pll_lim->refclk = 200000;
 				else
@@ -4891,10 +4963,10 @@
 		int i;
 
 		BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-			limit_match);
+			pll_lim->reg);
 
 		for (i = 0; i < entries; i++, entry += recordlen) {
-			if (ROM32(entry[3]) == limit_match) {
+			if (ROM32(entry[3]) == pll_lim->reg) {
 				record = &bios->data[ROM16(entry[1])];
 				break;
 			}
@@ -4902,7 +4974,7 @@
 
 		if (!record) {
 			NV_ERROR(dev, "Register 0x%08x not found in PLL "
-				 "limits table", limit_match);
+				 "limits table", pll_lim->reg);
 			return -ENOENT;
 		}
 
@@ -4931,10 +5003,10 @@
 		int i;
 
 		BIOSLOG(bios, "Loading PLL limits for register 0x%08x\n",
-			limit_match);
+			pll_lim->reg);
 
 		for (i = 0; i < entries; i++, entry += recordlen) {
-			if (ROM32(entry[3]) == limit_match) {
+			if (ROM32(entry[3]) == pll_lim->reg) {
 				record = &bios->data[ROM16(entry[1])];
 				break;
 			}
@@ -4942,7 +5014,7 @@
 
 		if (!record) {
 			NV_ERROR(dev, "Register 0x%08x not found in PLL "
-				 "limits table", limit_match);
+				 "limits table", pll_lim->reg);
 			return -ENOENT;
 		}
 
@@ -5293,7 +5365,7 @@
 	if (bitentry->length < 0x5)
 		return 0;
 
-	if (bitentry->id[1] < 2) {
+	if (bitentry->version < 2) {
 		bios->ram_restrict_group_count = bios->data[bitentry->offset + 2];
 		bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
 	} else {
@@ -5403,27 +5475,40 @@
 
 #define BIT_TABLE(id, funcid) ((struct bit_table){ id, parse_bit_##funcid##_tbl_entry })
 
+int
+bit_table(struct drm_device *dev, u8 id, struct bit_entry *bit)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	u8 entries, *entry;
+
+	entries = bios->data[bios->offset + 10];
+	entry   = &bios->data[bios->offset + 12];
+	while (entries--) {
+		if (entry[0] == id) {
+			bit->id = entry[0];
+			bit->version = entry[1];
+			bit->length = ROM16(entry[2]);
+			bit->offset = ROM16(entry[4]);
+			bit->data = ROMPTR(bios, entry[4]);
+			return 0;
+		}
+
+		entry += bios->data[bios->offset + 9];
+	}
+
+	return -ENOENT;
+}
+
 static int
 parse_bit_table(struct nvbios *bios, const uint16_t bitoffset,
 		struct bit_table *table)
 {
 	struct drm_device *dev = bios->dev;
-	uint8_t maxentries = bios->data[bitoffset + 4];
-	int i, offset;
 	struct bit_entry bitentry;
 
-	for (i = 0, offset = bitoffset + 6; i < maxentries; i++, offset += 6) {
-		bitentry.id[0] = bios->data[offset];
-
-		if (bitentry.id[0] != table->id)
-			continue;
-
-		bitentry.id[1] = bios->data[offset + 1];
-		bitentry.length = ROM16(bios->data[offset + 2]);
-		bitentry.offset = ROM16(bios->data[offset + 4]);
-
+	if (bit_table(dev, table->id, &bitentry) == 0)
 		return table->parse_fn(dev, bios, &bitentry);
-	}
 
 	NV_INFO(dev, "BIT table '%c' not found\n", table->id);
 	return -ENOSYS;
@@ -5683,8 +5768,14 @@
 static struct dcb_gpio_entry *
 new_gpio_entry(struct nvbios *bios)
 {
+	struct drm_device *dev = bios->dev;
 	struct dcb_gpio_table *gpio = &bios->dcb.gpio;
 
+	if (gpio->entries >= DCB_MAX_NUM_GPIO_ENTRIES) {
+		NV_ERROR(dev, "exceeded maximum number of gpio entries!!\n");
+		return NULL;
+	}
+
 	return &gpio->entry[gpio->entries++];
 }
 
@@ -5706,113 +5797,90 @@
 }
 
 static void
-parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
-	struct dcb_gpio_entry *gpio;
-	uint16_t ent = ROM16(bios->data[offset]);
-	uint8_t line = ent & 0x1f,
-		tag = ent >> 5 & 0x3f,
-		flags = ent >> 11 & 0x1f;
-
-	if (tag == 0x3f)
-		return;
-
-	gpio = new_gpio_entry(bios);
-
-	gpio->tag = tag;
-	gpio->line = line;
-	gpio->invert = flags != 4;
-	gpio->entry = ent;
-}
-
-static void
-parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset)
-{
-	uint32_t entry = ROM32(bios->data[offset]);
-	struct dcb_gpio_entry *gpio;
-
-	if ((entry & 0x0000ff00) == 0x0000ff00)
-		return;
-
-	gpio = new_gpio_entry(bios);
-	gpio->tag = (entry & 0x0000ff00) >> 8;
-	gpio->line = (entry & 0x0000001f) >> 0;
-	gpio->state_default = (entry & 0x01000000) >> 24;
-	gpio->state[0] = (entry & 0x18000000) >> 27;
-	gpio->state[1] = (entry & 0x60000000) >> 29;
-	gpio->entry = entry;
-}
-
-static void
 parse_dcb_gpio_table(struct nvbios *bios)
 {
 	struct drm_device *dev = bios->dev;
-	uint16_t gpio_table_ptr = bios->dcb.gpio_table_ptr;
-	uint8_t *gpio_table = &bios->data[gpio_table_ptr];
-	int header_len = gpio_table[1],
-	    entries = gpio_table[2],
-	    entry_len = gpio_table[3];
-	void (*parse_entry)(struct nvbios *, uint16_t) = NULL;
+	struct dcb_gpio_entry *e;
+	u8 headerlen, entries, recordlen;
+	u8 *dcb, *gpio = NULL, *entry;
 	int i;
 
-	if (bios->dcb.version >= 0x40) {
-		if (gpio_table_ptr && entry_len != 4) {
-			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
-			return;
-		}
-
-		parse_entry = parse_dcb40_gpio_entry;
-
-	} else if (bios->dcb.version >= 0x30) {
-		if (gpio_table_ptr && entry_len != 2) {
-			NV_WARN(dev, "Invalid DCB GPIO table entry length.\n");
-			return;
-		}
+	dcb = ROMPTR(bios, bios->data[0x36]);
+	if (dcb[0] >= 0x30) {
+		gpio = ROMPTR(bios, dcb[10]);
+		if (!gpio)
+			goto no_table;
 
-		parse_entry = parse_dcb30_gpio_entry;
+		headerlen = gpio[1];
+		entries   = gpio[2];
+		recordlen = gpio[3];
+	} else
+	if (dcb[0] >= 0x22 && dcb[-1] >= 0x13) {
+		gpio = ROMPTR(bios, dcb[-15]);
+		if (!gpio)
+			goto no_table;
 
-	} else if (bios->dcb.version >= 0x22) {
-		/*
-		 * DCBs older than v3.0 don't really have a GPIO
-		 * table, instead they keep some GPIO info at fixed
-		 * locations.
-		 */
-		uint16_t dcbptr = ROM16(bios->data[0x36]);
-		uint8_t *tvdac_gpio = &bios->data[dcbptr - 5];
+		headerlen = 3;
+		entries   = gpio[2];
+		recordlen = gpio[1];
+	} else
+	if (dcb[0] >= 0x22) {
+		/* No GPIO table present, parse the TVDAC GPIO data. */
+		uint8_t *tvdac_gpio = &dcb[-5];
 
 		if (tvdac_gpio[0] & 1) {
-			struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
-
-			gpio->tag = DCB_GPIO_TVDAC0;
-			gpio->line = tvdac_gpio[1] >> 4;
-			gpio->invert = tvdac_gpio[0] & 2;
+			e = new_gpio_entry(bios);
+			e->tag = DCB_GPIO_TVDAC0;
+			e->line = tvdac_gpio[1] >> 4;
+			e->invert = tvdac_gpio[0] & 2;
 		}
-	} else {
-		/*
-		 * No systematic way to store GPIO info on pre-v2.2
-		 * DCBs, try to match the PCI device IDs.
-		 */
 
-		/* Apple iMac G4 NV18 */
-		if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
-			struct dcb_gpio_entry *gpio = new_gpio_entry(bios);
+		goto no_table;
+	} else {
+		NV_DEBUG(dev, "no/unknown gpio table on DCB 0x%02x\n", dcb[0]);
+		goto no_table;
+	}
 
-			gpio->tag = DCB_GPIO_TVDAC0;
-			gpio->line = 4;
-		}
+	entry = gpio + headerlen;
+	for (i = 0; i < entries; i++, entry += recordlen) {
+		e = new_gpio_entry(bios);
+		if (!e)
+			break;
 
-	}
+		if (gpio[0] < 0x40) {
+			e->entry = ROM16(entry[0]);
+			e->tag = (e->entry & 0x07e0) >> 5;
+			if (e->tag == 0x3f) {
+				bios->dcb.gpio.entries--;
+				continue;
+			}
 
-	if (!gpio_table_ptr)
-		return;
+			e->line = (e->entry & 0x001f);
+			e->invert = ((e->entry & 0xf800) >> 11) != 4;
+		} else {
+			e->entry = ROM32(entry[0]);
+			e->tag = (e->entry & 0x0000ff00) >> 8;
+			if (e->tag == 0xff) {
+				bios->dcb.gpio.entries--;
+				continue;
+			}
 
-	if (entries > DCB_MAX_NUM_GPIO_ENTRIES) {
-		NV_WARN(dev, "Too many entries in the DCB GPIO table.\n");
-		entries = DCB_MAX_NUM_GPIO_ENTRIES;
+			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;
+		}
 	}
 
-	for (i = 0; i < entries; i++)
-		parse_entry(bios, gpio_table_ptr + header_len + entry_len * i);
+no_table:
+	/* Apple iMac G4 NV18 */
+	if (nv_match_device(dev, 0x0189, 0x10de, 0x0010)) {
+		e = new_gpio_entry(bios);
+		if (e) {
+			e->tag = DCB_GPIO_TVDAC0;
+			e->line = 4;
+		}
+	}
 }
 
 struct dcb_connector_table_entry *
@@ -6680,6 +6748,8 @@
 					bit_signature, sizeof(bit_signature));
 	if (offset) {
 		NV_TRACE(dev, "BIT BIOS found\n");
+		bios->type = NVBIOS_BIT;
+		bios->offset = offset;
 		return parse_bit_structure(bios, offset + 6);
 	}
 
@@ -6687,6 +6757,8 @@
 					bmp_signature, sizeof(bmp_signature));
 	if (offset) {
 		NV_TRACE(dev, "BMP BIOS found\n");
+		bios->type = NVBIOS_BMP;
+		bios->offset = offset;
 		return parse_bmp_structure(dev, bios, offset);
 	}
 
@@ -6757,7 +6829,7 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	unsigned htotal;
 
-	if (dev_priv->chipset >= NV_50) {
+	if (dev_priv->card_type >= NV_50) {
 		if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
 		    NVReadVgaCrtc(dev, 0, 0x1a) == 0)
 			return false;
@@ -6806,6 +6878,8 @@
 			"running VBIOS init tables.\n");
 		bios->execute = true;
 	}
+	if (nouveau_force_post)
+		bios->execute = true;
 
 	ret = nouveau_run_vbios_init(dev);
 	if (ret)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bios.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bios.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bios.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bios.h	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,20 @@
 
 #define DCB_LOC_ON_CHIP 0
 
+#define ROM16(x) le16_to_cpu(*(uint16_t *)&(x))
+#define ROM32(x) le32_to_cpu(*(uint32_t *)&(x))
+#define ROMPTR(bios, x) (ROM16(x) ? &(bios)->data[ROM16(x)] : NULL)
+
+struct bit_entry {
+	uint8_t  id;
+	uint8_t  version;
+	uint16_t length;
+	uint16_t offset;
+	uint8_t *data;
+};
+
+int bit_table(struct drm_device *, u8 id, struct bit_entry *);
+
 struct dcb_i2c_entry {
 	uint32_t entry;
 	uint8_t port_type;
@@ -170,16 +184,28 @@
 	LVDS_PANEL_OFF
 };
 
-/* changing these requires matching changes to reg tables in nv_get_clock */
-#define MAX_PLL_TYPES	4
+/* these match types in pll limits table version 0x40,
+ * nouveau uses them on all chipsets internally where a
+ * specific pll needs to be referenced, but the exact
+ * register isn't known.
+ */
 enum pll_types {
-	NVPLL,
-	MPLL,
-	VPLL1,
-	VPLL2
+	PLL_CORE   = 0x01,
+	PLL_SHADER = 0x02,
+	PLL_UNK03  = 0x03,
+	PLL_MEMORY = 0x04,
+	PLL_UNK05  = 0x05,
+	PLL_UNK40  = 0x40,
+	PLL_UNK41  = 0x41,
+	PLL_UNK42  = 0x42,
+	PLL_VPLL0  = 0x80,
+	PLL_VPLL1  = 0x81,
+	PLL_MAX    = 0xff
 };
 
 struct pll_lims {
+	u32 reg;
+
 	struct {
 		int minfreq;
 		int maxfreq;
@@ -212,6 +238,11 @@
 
 struct nvbios {
 	struct drm_device *dev;
+	enum {
+		NVBIOS_BMP,
+		NVBIOS_BIT
+	} type;
+	uint16_t offset;
 
 	uint8_t chip_version;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_bo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_bo.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,21 +36,6 @@
 #include <linux/log2.h>
 #include <linux/slab.h>
 
-int
-nouveau_bo_sync_gpu(struct nouveau_bo *nvbo, struct nouveau_channel *chan)
-{
-	struct nouveau_fence *prev_fence = nvbo->bo.sync_obj;
-	int ret;
-
-	if (!prev_fence || nouveau_fence_channel(prev_fence) == chan)
-		return 0;
-
-	spin_lock(&nvbo->bo.lock);
-	ret = ttm_bo_wait(&nvbo->bo, false, false, false);
-	spin_unlock(&nvbo->bo.lock);
-	return ret;
-}
-
 static void
 nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
 {
@@ -58,8 +43,6 @@
 	struct drm_device *dev = dev_priv->dev;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 
-	ttm_bo_kunmap(&nvbo->kmap);
-
 	if (unlikely(nvbo->gem))
 		DRM_ERROR("bo %p still attached to GEM object\n", bo);
 
@@ -160,12 +143,12 @@
 	nvbo->no_vm = no_vm;
 	nvbo->tile_mode = tile_mode;
 	nvbo->tile_flags = tile_flags;
+	nvbo->bo.bdev = &dev_priv->ttm.bdev;
 
-	nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
+	nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo),
+			       &align, &size);
 	align >>= PAGE_SHIFT;
 
-	nvbo->placement.fpfn = 0;
-	nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0;
 	nouveau_bo_placement_set(nvbo, flags, 0);
 
 	nvbo->channel = chan;
@@ -195,6 +178,31 @@
 		pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
 }
 
+static void
+set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
+{
+	struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
+
+	if (dev_priv->card_type == NV_10 &&
+	    nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
+		/*
+		 * Make sure that the color and depth buffers are handled
+		 * by independent memory controller units. Up to a 9x
+		 * speed up when alpha-blending and depth-test are enabled
+		 * at the same time.
+		 */
+		int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
+
+		if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
+			nvbo->placement.fpfn = vram_pages / 2;
+			nvbo->placement.lpfn = ~0;
+		} else {
+			nvbo->placement.fpfn = 0;
+			nvbo->placement.lpfn = vram_pages / 2;
+		}
+	}
+}
+
 void
 nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 {
@@ -209,6 +217,8 @@
 	pl->busy_placement = nvbo->busy_placements;
 	set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
 			   type | busy, flags);
+
+	set_placement_range(nvbo, type);
 }
 
 int
@@ -305,7 +315,8 @@
 void
 nouveau_bo_unmap(struct nouveau_bo *nvbo)
 {
-	ttm_bo_kunmap(&nvbo->kmap);
+	if (nvbo)
+		ttm_bo_kunmap(&nvbo->kmap);
 }
 
 u16
@@ -399,14 +410,19 @@
 		man->default_caching = TTM_PL_FLAG_CACHED;
 		break;
 	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
 		man->flags = TTM_MEMTYPE_FLAG_FIXED |
 			     TTM_MEMTYPE_FLAG_MAPPABLE;
 		man->available_caching = TTM_PL_FLAG_UNCACHED |
 					 TTM_PL_FLAG_WC;
 		man->default_caching = TTM_PL_FLAG_WC;
-		man->gpu_offset = dev_priv->vm_vram_base;
+		if (dev_priv->card_type == NV_50)
+			man->gpu_offset = 0x40000000;
+		else
+			man->gpu_offset = 0;
 		break;
 	case TTM_PL_TT:
+		man->func = &ttm_bo_manager_func;
 		switch (dev_priv->gart_info.type) {
 		case NOUVEAU_GART_AGP:
 			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -469,19 +485,26 @@
 	if (ret)
 		return ret;
 
-	ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
-					evict || (nvbo->channel &&
-						  nvbo->channel != chan),
+	if (nvbo->channel) {
+		ret = nouveau_fence_sync(fence, nvbo->channel);
+		if (ret)
+			goto out;
+	}
+
+	ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict,
 					no_wait_reserve, no_wait_gpu, new_mem);
+out:
 	nouveau_fence_unref((void *)&fence);
 	return ret;
 }
 
 static inline uint32_t
-nouveau_bo_mem_ctxdma(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
-		      struct ttm_mem_reg *mem)
+nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
+		      struct nouveau_channel *chan, struct ttm_mem_reg *mem)
 {
-	if (chan == nouveau_bdev(nvbo->bo.bdev)->channel) {
+	struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+	if (nvbo->no_vm) {
 		if (mem->mem_type == TTM_PL_TT)
 			return NvDmaGART;
 		return NvDmaVRAM;
@@ -493,86 +516,183 @@
 }
 
 static int
-nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
-		     bool no_wait_reserve, bool no_wait_gpu,
-		     struct ttm_mem_reg *new_mem)
+nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
-	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
-	struct ttm_mem_reg *old_mem = &bo->mem;
-	struct nouveau_channel *chan;
-	uint64_t src_offset, dst_offset;
-	uint32_t page_count;
+	struct nouveau_bo *nvbo = nouveau_bo(bo);
+	u64 length = (new_mem->num_pages << PAGE_SHIFT);
+	u64 src_offset, dst_offset;
 	int ret;
 
-	chan = nvbo->channel;
-	if (!chan || nvbo->tile_flags || nvbo->no_vm)
-		chan = dev_priv->channel;
-
-	src_offset = old_mem->mm_node->start << PAGE_SHIFT;
-	dst_offset = new_mem->mm_node->start << PAGE_SHIFT;
-	if (chan != dev_priv->channel) {
-		if (old_mem->mem_type == TTM_PL_TT)
-			src_offset += dev_priv->vm_gart_base;
-		else
+	src_offset = old_mem->start << PAGE_SHIFT;
+	dst_offset = new_mem->start << PAGE_SHIFT;
+	if (!nvbo->no_vm) {
+		if (old_mem->mem_type == TTM_PL_VRAM)
 			src_offset += dev_priv->vm_vram_base;
-
-		if (new_mem->mem_type == TTM_PL_TT)
-			dst_offset += dev_priv->vm_gart_base;
 		else
+			src_offset += dev_priv->vm_gart_base;
+
+		if (new_mem->mem_type == TTM_PL_VRAM)
 			dst_offset += dev_priv->vm_vram_base;
+		else
+			dst_offset += dev_priv->vm_gart_base;
 	}
 
 	ret = RING_SPACE(chan, 3);
 	if (ret)
 		return ret;
-	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
-	OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, old_mem));
-	OUT_RING(chan, nouveau_bo_mem_ctxdma(nvbo, chan, new_mem));
 
-	if (dev_priv->card_type >= NV_50) {
-		ret = RING_SPACE(chan, 4);
+	BEGIN_RING(chan, NvSubM2MF, 0x0184, 2);
+	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
+	while (length) {
+		u32 amount, stride, height;
+
+		amount  = min(length, (u64)(4 * 1024 * 1024));
+		stride  = 16 * 4;
+		height  = amount / stride;
+
+		if (new_mem->mem_type == TTM_PL_VRAM &&
+		    nouveau_bo_tile_layout(nvbo)) {
+			ret = RING_SPACE(chan, 8);
+			if (ret)
+				return ret;
+
+			BEGIN_RING(chan, NvSubM2MF, 0x0200, 7);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, stride);
+			OUT_RING  (chan, height);
+			OUT_RING  (chan, 1);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, 0);
+		} else {
+			ret = RING_SPACE(chan, 2);
+			if (ret)
+				return ret;
+
+			BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
+			OUT_RING  (chan, 1);
+		}
+		if (old_mem->mem_type == TTM_PL_VRAM &&
+		    nouveau_bo_tile_layout(nvbo)) {
+			ret = RING_SPACE(chan, 8);
+			if (ret)
+				return ret;
+
+			BEGIN_RING(chan, NvSubM2MF, 0x021c, 7);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, stride);
+			OUT_RING  (chan, height);
+			OUT_RING  (chan, 1);
+			OUT_RING  (chan, 0);
+			OUT_RING  (chan, 0);
+		} else {
+			ret = RING_SPACE(chan, 2);
+			if (ret)
+				return ret;
+
+			BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
+			OUT_RING  (chan, 1);
+		}
+
+		ret = RING_SPACE(chan, 14);
 		if (ret)
 			return ret;
-		BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
-		OUT_RING(chan, 1);
-		BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
-		OUT_RING(chan, 1);
+
+		BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
+		OUT_RING  (chan, upper_32_bits(src_offset));
+		OUT_RING  (chan, upper_32_bits(dst_offset));
+		BEGIN_RING(chan, NvSubM2MF, 0x030c, 8);
+		OUT_RING  (chan, lower_32_bits(src_offset));
+		OUT_RING  (chan, lower_32_bits(dst_offset));
+		OUT_RING  (chan, stride);
+		OUT_RING  (chan, stride);
+		OUT_RING  (chan, stride);
+		OUT_RING  (chan, height);
+		OUT_RING  (chan, 0x00000101);
+		OUT_RING  (chan, 0x00000000);
+		BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
+		OUT_RING  (chan, 0);
+
+		length -= amount;
+		src_offset += amount;
+		dst_offset += amount;
 	}
 
+	return 0;
+}
+
+static int
+nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+		  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+	u32 src_offset = old_mem->start << PAGE_SHIFT;
+	u32 dst_offset = new_mem->start << PAGE_SHIFT;
+	u32 page_count = new_mem->num_pages;
+	int ret;
+
+	ret = RING_SPACE(chan, 3);
+	if (ret)
+		return ret;
+
+	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
+	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
+	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
+
 	page_count = new_mem->num_pages;
 	while (page_count) {
 		int line_count = (page_count > 2047) ? 2047 : page_count;
 
-		if (dev_priv->card_type >= NV_50) {
-			ret = RING_SPACE(chan, 3);
-			if (ret)
-				return ret;
-			BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
-			OUT_RING(chan, upper_32_bits(src_offset));
-			OUT_RING(chan, upper_32_bits(dst_offset));
-		}
 		ret = RING_SPACE(chan, 11);
 		if (ret)
 			return ret;
+
 		BEGIN_RING(chan, NvSubM2MF,
 				 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
-		OUT_RING(chan, lower_32_bits(src_offset));
-		OUT_RING(chan, lower_32_bits(dst_offset));
-		OUT_RING(chan, PAGE_SIZE); /* src_pitch */
-		OUT_RING(chan, PAGE_SIZE); /* dst_pitch */
-		OUT_RING(chan, PAGE_SIZE); /* line_length */
-		OUT_RING(chan, line_count);
-		OUT_RING(chan, (1<<8)|(1<<0));
-		OUT_RING(chan, 0);
+		OUT_RING  (chan, src_offset);
+		OUT_RING  (chan, dst_offset);
+		OUT_RING  (chan, PAGE_SIZE); /* src_pitch */
+		OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */
+		OUT_RING  (chan, PAGE_SIZE); /* line_length */
+		OUT_RING  (chan, line_count);
+		OUT_RING  (chan, 0x00000101);
+		OUT_RING  (chan, 0x00000000);
 		BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
-		OUT_RING(chan, 0);
+		OUT_RING  (chan, 0);
 
 		page_count -= line_count;
 		src_offset += (PAGE_SIZE * line_count);
 		dst_offset += (PAGE_SIZE * line_count);
 	}
 
+	return 0;
+}
+
+static int
+nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
+		     bool no_wait_reserve, bool no_wait_gpu,
+		     struct ttm_mem_reg *new_mem)
+{
+	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+	struct nouveau_bo *nvbo = nouveau_bo(bo);
+	struct nouveau_channel *chan;
+	int ret;
+
+	chan = nvbo->channel;
+	if (!chan || nvbo->no_vm)
+		chan = dev_priv->channel;
+
+	if (dev_priv->card_type < NV_50)
+		ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+	else
+		ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+	if (ret)
+		return ret;
+
 	return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 }
 
@@ -606,12 +726,7 @@
 
 	ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
 out:
-	if (tmp_mem.mm_node) {
-		spin_lock(&bo->bdev->glob->lru_lock);
-		drm_mm_put_block(tmp_mem.mm_node);
-		spin_unlock(&bo->bdev->glob->lru_lock);
-	}
-
+	ttm_bo_mem_put(bo, &tmp_mem);
 	return ret;
 }
 
@@ -644,12 +759,7 @@
 		goto out;
 
 out:
-	if (tmp_mem.mm_node) {
-		spin_lock(&bo->bdev->glob->lru_lock);
-		drm_mm_put_block(tmp_mem.mm_node);
-		spin_unlock(&bo->bdev->glob->lru_lock);
-	}
-
+	ttm_bo_mem_put(bo, &tmp_mem);
 	return ret;
 }
 
@@ -669,12 +779,13 @@
 		return 0;
 	}
 
-	offset = new_mem->mm_node->start << PAGE_SHIFT;
+	offset = new_mem->start << PAGE_SHIFT;
 
 	if (dev_priv->card_type == NV_50) {
 		ret = nv50_mem_vm_bind_linear(dev,
 					      offset + dev_priv->vm_vram_base,
-					      new_mem->size, nvbo->tile_flags,
+					      new_mem->size,
+					      nouveau_bo_tile_layout(nvbo),
 					      offset);
 		if (ret)
 			return ret;
@@ -719,12 +830,6 @@
 	if (ret)
 		return ret;
 
-	/* Software copy if the card isn't up and running yet. */
-	if (!dev_priv->channel) {
-		ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
-		goto out;
-	}
-
 	/* Fake bo copy. */
 	if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
 		BUG_ON(bo->mem.mm_node != NULL);
@@ -733,6 +838,12 @@
 		goto out;
 	}
 
+	/* Software copy if the card isn't up and running yet. */
+	if (!dev_priv->channel) {
+		ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+		goto out;
+	}
+
 	/* Hardware assisted copy. */
 	if (new_mem->mem_type == TTM_PL_SYSTEM)
 		ret = nouveau_bo_move_flipd(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem);
@@ -783,14 +894,14 @@
 	case TTM_PL_TT:
 #if __OS_HAS_AGP
 		if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
-			mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+			mem->bus.offset = mem->start << PAGE_SHIFT;
 			mem->bus.base = dev_priv->gart_info.aper_base;
 			mem->bus.is_iomem = true;
 		}
 #endif
 		break;
 	case TTM_PL_VRAM:
-		mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+		mem->bus.offset = mem->start << PAGE_SHIFT;
 		mem->bus.base = pci_resource_start(dev->pdev, 1);
 		mem->bus.is_iomem = true;
 		break;
@@ -808,7 +919,27 @@
 static int
 nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
 {
-	return 0;
+	struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev);
+	struct nouveau_bo *nvbo = nouveau_bo(bo);
+
+	/* as long as the bo isn't in vram, and isn't tiled, we've got
+	 * nothing to do here.
+	 */
+	if (bo->mem.mem_type != TTM_PL_VRAM) {
+		if (dev_priv->card_type < NV_50 ||
+		    !nouveau_bo_tile_layout(nvbo))
+			return 0;
+	}
+
+	/* make sure bo is in mappable vram */
+	if (bo->mem.start + bo->mem.num_pages < dev_priv->fb_mappable_pages)
+		return 0;
+
+
+	nvbo->placement.fpfn = 0;
+	nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
+	nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0);
+	return ttm_bo_validate(bo, &nvbo->placement, false, true, false);
 }
 
 struct ttm_bo_driver nouveau_bo_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_calc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_calc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_calc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_calc.c	2011-01-04 19:50:19.000000000 -0500
@@ -198,8 +198,8 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv_fifo_info fifo_data;
 	struct nv_sim_state sim_data;
-	int MClk = nouveau_hw_get_clock(dev, MPLL);
-	int NVClk = nouveau_hw_get_clock(dev, NVPLL);
+	int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY);
+	int NVClk = nouveau_hw_get_clock(dev, PLL_CORE);
 	uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
 
 	sim_data.pclk_khz = VClk;
@@ -234,7 +234,7 @@
 }
 
 static void
-nv30_update_arb(int *burst, int *lwm)
+nv20_update_arb(int *burst, int *lwm)
 {
 	unsigned int fifo_size, burst_size, graphics_lwm;
 
@@ -251,14 +251,14 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->card_type < NV_30)
+	if (dev_priv->card_type < NV_20)
 		nv04_update_arb(dev, vclk, bpp, burst, lwm);
 	else if ((dev->pci_device & 0xfff0) == 0x0240 /*CHIPSET_C51*/ ||
 		 (dev->pci_device & 0xfff0) == 0x03d0 /*CHIPSET_C512*/) {
 		*burst = 128;
 		*lwm = 0x0480;
 	} else
-		nv30_update_arb(burst, lwm);
+		nv20_update_arb(burst, lwm);
 }
 
 static int
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_channel.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_channel.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_channel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_channel.c	2011-01-04 19:50:19.000000000 -0500
@@ -48,14 +48,14 @@
 						  dev_priv->gart_info.aper_size,
 						  NV_DMA_ACCESS_RO, &pushbuf,
 						  NULL);
-		chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
 	} else
 	if (dev_priv->card_type != NV_04) {
 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0,
 					     dev_priv->fb_available_size,
 					     NV_DMA_ACCESS_RO,
 					     NV_DMA_TARGET_VIDMEM, &pushbuf);
-		chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
+		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
 	} else {
 		/* NV04 cmdbuf hack, from original ddx.. not sure of it's
 		 * exact reason for existing :)  PCI access to cmdbuf in
@@ -67,17 +67,11 @@
 					     dev_priv->fb_available_size,
 					     NV_DMA_ACCESS_RO,
 					     NV_DMA_TARGET_PCI, &pushbuf);
-		chan->pushbuf_base = pb->bo.mem.mm_node->start << PAGE_SHIFT;
-	}
-
-	ret = nouveau_gpuobj_ref_add(dev, chan, 0, pushbuf, &chan->pushbuf);
-	if (ret) {
-		NV_ERROR(dev, "Error referencing pushbuf ctxdma: %d\n", ret);
-		if (pushbuf != dev_priv->gart_info.sg_ctxdma)
-			nouveau_gpuobj_del(dev, &pushbuf);
-		return ret;
+		chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT;
 	}
 
+	nouveau_gpuobj_ref(pushbuf, &chan->pushbuf);
+	nouveau_gpuobj_ref(NULL, &pushbuf);
 	return 0;
 }
 
@@ -229,7 +223,7 @@
 
 	ret = nouveau_dma_init(chan);
 	if (!ret)
-		ret = nouveau_fence_init(chan);
+		ret = nouveau_fence_channel_init(chan);
 	if (ret) {
 		nouveau_channel_free(chan);
 		return ret;
@@ -276,7 +270,7 @@
 	 * above attempts at idling were OK, but if we failed this'll tell TTM
 	 * we're done with the buffers.
 	 */
-	nouveau_fence_fini(chan);
+	nouveau_fence_channel_fini(chan);
 
 	/* This will prevent pfifo from switching channels. */
 	pfifo->reassign(dev, false);
@@ -308,8 +302,9 @@
 	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
 	/* Release the channel's resources */
-	nouveau_gpuobj_ref_del(dev, &chan->pushbuf);
+	nouveau_gpuobj_ref(NULL, &chan->pushbuf);
 	if (chan->pushbuf_bo) {
+		nouveau_bo_unmap(chan->pushbuf_bo);
 		nouveau_bo_unpin(chan->pushbuf_bo);
 		nouveau_bo_ref(NULL, &chan->pushbuf_bo);
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_connector.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_connector.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_connector.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_connector.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,6 +76,22 @@
 	return NULL;
 }
 
+/*TODO: This could use improvement, and learn to handle the fixed
+ *      BIOS tables etc.  It's fine currently, for its only user.
+ */
+int
+nouveau_connector_bpp(struct drm_connector *connector)
+{
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+
+	if (nv_connector->edid && nv_connector->edid->revision >= 4) {
+		u8 bpc = ((nv_connector->edid->input & 0x70) >> 3) + 4;
+		if (bpc > 4)
+			return bpc;
+	}
+
+	return 18;
+}
 
 static void
 nouveau_connector_destroy(struct drm_connector *drm_connector)
@@ -130,6 +146,36 @@
 	return NULL;
 }
 
+static struct nouveau_encoder *
+nouveau_connector_of_detect(struct drm_connector *connector)
+{
+#ifdef __powerpc__
+	struct drm_device *dev = connector->dev;
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct nouveau_encoder *nv_encoder;
+	struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);
+
+	if (!dn ||
+	    !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) ||
+	      (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG))))
+		return NULL;
+
+	for_each_child_of_node(dn, cn) {
+		const char *name = of_get_property(cn, "name", NULL);
+		const void *edid = of_get_property(cn, "EDID", NULL);
+		int idx = name ? name[strlen(name) - 1] - 'A' : 0;
+
+		if (nv_encoder->dcb->i2c_index == idx && edid) {
+			nv_connector->edid =
+				kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
+			of_node_put(cn);
+			return nv_encoder;
+		}
+	}
+#endif
+	return NULL;
+}
+
 static void
 nouveau_connector_set_encoder(struct drm_connector *connector,
 			      struct nouveau_encoder *nv_encoder)
@@ -225,11 +271,17 @@
 		return connector_status_connected;
 	}
 
+	nv_encoder = nouveau_connector_of_detect(connector);
+	if (nv_encoder) {
+		nouveau_connector_set_encoder(connector, nv_encoder);
+		return connector_status_connected;
+	}
+
 detect_analog:
 	nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
 	if (!nv_encoder && !nouveau_tv_disable)
 		nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
-	if (nv_encoder) {
+	if (nv_encoder && force) {
 		struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 		struct drm_encoder_helper_funcs *helper =
 						encoder->helper_private;
@@ -589,11 +641,28 @@
 	return ret;
 }
 
+static unsigned
+get_tmds_link_bandwidth(struct drm_connector *connector)
+{
+	struct nouveau_connector *nv_connector = nouveau_connector(connector);
+	struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
+	struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
+
+	if (dcb->location != DCB_LOC_ON_CHIP ||
+	    dev_priv->chipset >= 0x46)
+		return 165000;
+	else if (dev_priv->chipset >= 0x40)
+		return 155000;
+	else if (dev_priv->chipset >= 0x18)
+		return 135000;
+	else
+		return 112000;
+}
+
 static int
 nouveau_connector_mode_valid(struct drm_connector *connector,
 			     struct drm_display_mode *mode)
 {
-	struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
 	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
@@ -611,11 +680,9 @@
 		max_clock = 400000;
 		break;
 	case OUTPUT_TMDS:
-		if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
-		    !nv_encoder->dcb->duallink_possible)
-			max_clock = 165000;
-		else
-			max_clock = 330000;
+		max_clock = get_tmds_link_bandwidth(connector);
+		if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
+			max_clock *= 2;
 		break;
 	case OUTPUT_ANALOG:
 		max_clock = nv_encoder->dcb->crtconf.maxfreq;
@@ -630,7 +697,7 @@
 		else
 			max_clock = nv_encoder->dp.link_nr * 162000;
 
-		clock *= 3;
+		clock = clock * nouveau_connector_bpp(connector) / 8;
 		break;
 	default:
 		BUG_ON(1);
@@ -657,44 +724,6 @@
 	return NULL;
 }
 
-void
-nouveau_connector_set_polling(struct drm_connector *connector)
-{
-	struct drm_device *dev = connector->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct drm_crtc *crtc;
-	bool spare_crtc = false;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-		spare_crtc |= !crtc->enabled;
-
-	connector->polled = 0;
-
-	switch (connector->connector_type) {
-	case DRM_MODE_CONNECTOR_VGA:
-	case DRM_MODE_CONNECTOR_TV:
-		if (dev_priv->card_type >= NV_50 ||
-		    (nv_gf4_disp_arch(dev) && spare_crtc))
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-		break;
-
-	case DRM_MODE_CONNECTOR_DVII:
-	case DRM_MODE_CONNECTOR_DVID:
-	case DRM_MODE_CONNECTOR_HDMIA:
-	case DRM_MODE_CONNECTOR_DisplayPort:
-	case DRM_MODE_CONNECTOR_eDP:
-		if (dev_priv->card_type >= NV_50)
-			connector->polled = DRM_CONNECTOR_POLL_HPD;
-		else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
-			 spare_crtc)
-			connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-		break;
-
-	default:
-		break;
-	}
-}
-
 static const struct drm_connector_helper_funcs
 nouveau_connector_helper_funcs = {
 	.get_modes = nouveau_connector_get_modes,
@@ -820,6 +849,7 @@
 					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:
@@ -836,11 +866,16 @@
 				dev->mode_config.dithering_mode_property,
 				nv_connector->use_dithering ?
 				DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
+
+		if (dcb->type != DCB_CONNECTOR_LVDS) {
+			if (dev_priv->card_type >= NV_50)
+				connector->polled = DRM_CONNECTOR_POLL_HPD;
+			else
+				connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		}
 		break;
 	}
 
-	nouveau_connector_set_polling(connector);
-
 	drm_sysfs_connector_add(connector);
 	dcb->drm = connector;
 	return dcb->drm;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_connector.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_connector.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_connector.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_connector.h	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
 struct drm_connector *
 nouveau_connector_create(struct drm_device *, int index);
 
-void
-nouveau_connector_set_polling(struct drm_connector *);
+int
+nouveau_connector_bpp(struct drm_connector *);
 
 #endif /* __NOUVEAU_CONNECTOR_H__ */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_debugfs.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_debugfs.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_debugfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_debugfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -157,7 +157,23 @@
 	return 0;
 }
 
+static int
+nouveau_debugfs_evict_vram(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_nouveau_private *dev_priv = node->minor->dev->dev_private;
+	int ret;
+
+	ret = ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
+	if (ret)
+		seq_printf(m, "failed: %d", ret);
+	else
+		seq_printf(m, "succeeded\n");
+	return 0;
+}
+
 static struct drm_info_list nouveau_debugfs_list[] = {
+	{ "evict_vram", nouveau_debugfs_evict_vram, 0, NULL },
 	{ "chipset", nouveau_debugfs_chipset_info, 0, NULL },
 	{ "memory", nouveau_debugfs_memory_info, 0, NULL },
 	{ "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dma.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dma.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 
 void
 nouveau_dma_pre_init(struct nouveau_channel *chan)
@@ -58,26 +59,17 @@
 {
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *m2mf = NULL;
-	struct nouveau_gpuobj *nvsw = NULL;
+	struct nouveau_gpuobj *obj = NULL;
 	int ret, i;
 
 	/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
 	ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
-				    0x0039 : 0x5039, &m2mf);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
-	if (ret)
-		return ret;
-
-	/* Create an NV_SW object for various sync purposes */
-	ret = nouveau_gpuobj_sw_new(chan, NV_SW, &nvsw);
+				    0x0039 : 0x5039, &obj);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_ref_add(dev, chan, NvSw, nvsw, NULL);
+	ret = nouveau_ramht_insert(chan, NvM2MF, obj);
+	nouveau_gpuobj_ref(NULL, &obj);
 	if (ret)
 		return ret;
 
@@ -91,11 +83,6 @@
 	if (ret)
 		return ret;
 
-	/* Map M2MF notifier object - fbcon. */
-	ret = nouveau_bo_map(chan->notifier_bo);
-	if (ret)
-		return ret;
-
 	/* Insert NOPS for NOUVEAU_DMA_SKIPS */
 	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
 	if (ret)
@@ -113,13 +100,6 @@
 	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
 	OUT_RING(chan, NvNotify0);
 
-	/* Initialise NV_SW */
-	ret = RING_SPACE(chan, 2);
-	if (ret)
-		return ret;
-	BEGIN_RING(chan, NvSubSw, 0, 1);
-	OUT_RING(chan, NvSw);
-
 	/* Sit back and pray the channel works.. */
 	FIRE_RING(chan);
 
@@ -217,7 +197,7 @@
 
 		chan->dma.ib_free = get - chan->dma.ib_put;
 		if (chan->dma.ib_free <= 0)
-			chan->dma.ib_free += chan->dma.ib_max + 1;
+			chan->dma.ib_free += chan->dma.ib_max;
 	}
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dma.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dma.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dma.h	2011-01-04 19:50:19.000000000 -0500
@@ -72,6 +72,7 @@
 	NvGdiRect	= 0x8000000c,
 	NvImageBlit	= 0x8000000d,
 	NvSw		= 0x8000000e,
+	NvSema		= 0x8000000f,
 
 	/* G80+ display objects */
 	NvEvoVRAM	= 0x01000000,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dp.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dp.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_dp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_dp.c	2011-01-04 19:50:19.000000000 -0500
@@ -317,7 +317,8 @@
 		return false;
 
 	config[0] = nv_encoder->dp.link_nr;
-	if (nv_encoder->dp.dpcd_version >= 0x11)
+	if (nv_encoder->dp.dpcd_version >= 0x11 &&
+	    nv_encoder->dp.enhanced_frame)
 		config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 
 	ret = nouveau_dp_lane_count_set(encoder, config[0]);
@@ -468,10 +469,12 @@
 	    !nv_encoder->dcb->dpconf.link_bw)
 		nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
 
-	nv_encoder->dp.link_nr = dpcd[2] & 0xf;
+	nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
 	if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr)
 		nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
 
+	nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP);
+
 	return true;
 }
 
@@ -524,7 +527,8 @@
 		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(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
+		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;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,13 +31,14 @@
 #include "nouveau_hw.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_pm.h"
 #include "nv50_display.h"
 
 #include "drm_pciids.h"
 
-MODULE_PARM_DESC(noagp, "Disable AGP");
-int nouveau_noagp;
-module_param_named(noagp, nouveau_noagp, int, 0400);
+MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)");
+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 */
@@ -79,6 +80,10 @@
 int nouveau_nofbaccel = 0;
 module_param_named(nofbaccel, nouveau_nofbaccel, int, 0400);
 
+MODULE_PARM_DESC(force_post, "Force POST");
+int nouveau_force_post = 0;
+module_param_named(force_post, nouveau_force_post, int, 0400);
+
 MODULE_PARM_DESC(override_conntype, "Ignore DCB connector type");
 int nouveau_override_conntype = 0;
 module_param_named(override_conntype, nouveau_override_conntype, int, 0400);
@@ -102,6 +107,14 @@
 int nouveau_reg_debug;
 module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
 
+MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
+char *nouveau_perflvl;
+module_param_named(perflvl, nouveau_perflvl, charp, 0400);
+
+MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
+int nouveau_perflvl_wr;
+module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
+
 int nouveau_fbpercrtc;
 #if 0
 module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
@@ -271,6 +284,8 @@
 	if (ret)
 		return ret;
 
+	nouveau_pm_resume(dev);
+
 	if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) {
 		ret = nouveau_mem_init_agp(dev);
 		if (ret) {
@@ -379,8 +394,6 @@
 	.irq_uninstall = nouveau_irq_uninstall,
 	.irq_handler = nouveau_irq_handler,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = nouveau_ioctls,
 	.fops = {
 		.owner = THIS_MODULE,
@@ -393,6 +406,7 @@
 #if defined(CONFIG_COMPAT)
 		.compat_ioctl = nouveau_compat_ioctl,
 #endif
+		.llseek = noop_llseek,
 	},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_drv.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_drv.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_drv.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_drv.h	2011-01-04 19:50:19.000000000 -0500
@@ -100,6 +100,9 @@
 	int pin_refcnt;
 };
 
+#define nouveau_bo_tile_layout(nvbo)				\
+	((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
+
 static inline struct nouveau_bo *
 nouveau_bo(struct ttm_buffer_object *bo)
 {
@@ -133,22 +136,24 @@
 #define NVOBJ_ENGINE_DISPLAY	2
 #define NVOBJ_ENGINE_INT	0xdeadbeef
 
-#define NVOBJ_FLAG_ALLOW_NO_REFS	(1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC		(1 << 1)
 #define NVOBJ_FLAG_ZERO_FREE		(1 << 2)
-#define NVOBJ_FLAG_FAKE			(1 << 3)
 struct nouveau_gpuobj {
+	struct drm_device *dev;
+	struct kref refcount;
 	struct list_head list;
 
-	struct nouveau_channel *im_channel;
 	struct drm_mm_node *im_pramin;
 	struct nouveau_bo *im_backing;
-	uint32_t im_backing_start;
 	uint32_t *im_backing_suspend;
 	int im_bound;
 
 	uint32_t flags;
-	int refcount;
+
+	u32 size;
+	u32 pinst;
+	u32 cinst;
+	u64 vinst;
 
 	uint32_t engine;
 	uint32_t class;
@@ -157,16 +162,6 @@
 	void *priv;
 };
 
-struct nouveau_gpuobj_ref {
-	struct list_head list;
-
-	struct nouveau_gpuobj *gpuobj;
-	uint32_t instance;
-
-	struct nouveau_channel *channel;
-	int handle;
-};
-
 struct nouveau_channel {
 	struct drm_device *dev;
 	int id;
@@ -192,33 +187,32 @@
 	} fence;
 
 	/* DMA push buffer */
-	struct nouveau_gpuobj_ref *pushbuf;
-	struct nouveau_bo         *pushbuf_bo;
-	uint32_t                   pushbuf_base;
+	struct nouveau_gpuobj *pushbuf;
+	struct nouveau_bo     *pushbuf_bo;
+	uint32_t               pushbuf_base;
 
 	/* Notifier memory */
 	struct nouveau_bo *notifier_bo;
 	struct drm_mm notifier_heap;
 
 	/* PFIFO context */
-	struct nouveau_gpuobj_ref *ramfc;
-	struct nouveau_gpuobj_ref *cache;
+	struct nouveau_gpuobj *ramfc;
+	struct nouveau_gpuobj *cache;
 
 	/* PGRAPH context */
 	/* XXX may be merge 2 pointers as private data ??? */
-	struct nouveau_gpuobj_ref *ramin_grctx;
+	struct nouveau_gpuobj *ramin_grctx;
 	void *pgraph_ctx;
 
 	/* NV50 VM */
-	struct nouveau_gpuobj     *vm_pd;
-	struct nouveau_gpuobj_ref *vm_gart_pt;
-	struct nouveau_gpuobj_ref *vm_vram_pt[NV50_VM_VRAM_NR];
+	struct nouveau_gpuobj *vm_pd;
+	struct nouveau_gpuobj *vm_gart_pt;
+	struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
 
 	/* Objects */
-	struct nouveau_gpuobj_ref *ramin; /* Private instmem */
-	struct drm_mm              ramin_heap; /* Private PRAMIN heap */
-	struct nouveau_gpuobj_ref *ramht; /* Hash table */
-	struct list_head           ramht_refs; /* Objects referenced by RAMHT */
+	struct nouveau_gpuobj *ramin; /* Private instmem */
+	struct drm_mm          ramin_heap; /* Private PRAMIN heap */
+	struct nouveau_ramht  *ramht; /* Hash table */
 
 	/* GPU object info for stuff used in-kernel (mm_enabled) */
 	uint32_t m2mf_ntfy;
@@ -296,7 +290,7 @@
 struct nouveau_fifo_engine {
 	int  channels;
 
-	struct nouveau_gpuobj_ref *playlist[2];
+	struct nouveau_gpuobj *playlist[2];
 	int cur_playlist;
 
 	int  (*init)(struct drm_device *);
@@ -305,7 +299,6 @@
 	void (*disable)(struct drm_device *);
 	void (*enable)(struct drm_device *);
 	bool (*reassign)(struct drm_device *, bool enable);
-	bool (*cache_flush)(struct drm_device *dev);
 	bool (*cache_pull)(struct drm_device *dev, bool enable);
 
 	int  (*channel_id)(struct drm_device *);
@@ -314,6 +307,7 @@
 	void (*destroy_context)(struct nouveau_channel *);
 	int  (*load_context)(struct nouveau_channel *);
 	int  (*unload_context)(struct drm_device *);
+	void (*tlb_flush)(struct drm_device *dev);
 };
 
 struct nouveau_pgraph_object_method {
@@ -334,7 +328,7 @@
 	int grctx_size;
 
 	/* NV2x/NV3x context table (0x400780) */
-	struct nouveau_gpuobj_ref *ctx_table;
+	struct nouveau_gpuobj *ctx_table;
 
 	int  (*init)(struct drm_device *);
 	void (*takedown)(struct drm_device *);
@@ -346,6 +340,7 @@
 	void (*destroy_context)(struct nouveau_channel *);
 	int  (*load_context)(struct nouveau_channel *);
 	int  (*unload_context)(struct drm_device *);
+	void (*tlb_flush)(struct drm_device *dev);
 
 	void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
 				  uint32_t size, uint32_t pitch);
@@ -369,6 +364,91 @@
 	void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
 };
 
+struct nouveau_pm_voltage_level {
+	u8 voltage;
+	u8 vid;
+};
+
+struct nouveau_pm_voltage {
+	bool supported;
+	u8 vid_mask;
+
+	struct nouveau_pm_voltage_level *level;
+	int nr_level;
+};
+
+#define NOUVEAU_PM_MAX_LEVEL 8
+struct nouveau_pm_level {
+	struct device_attribute dev_attr;
+	char name[32];
+	int id;
+
+	u32 core;
+	u32 memory;
+	u32 shader;
+	u32 unk05;
+
+	u8 voltage;
+	u8 fanspeed;
+
+	u16 memscript;
+};
+
+struct nouveau_pm_temp_sensor_constants {
+	u16 offset_constant;
+	s16 offset_mult;
+	u16 offset_div;
+	u16 slope_mult;
+	u16 slope_div;
+};
+
+struct nouveau_pm_threshold_temp {
+	s16 critical;
+	s16 down_clock;
+	s16 fan_boost;
+};
+
+struct nouveau_pm_memtiming {
+	u32 reg_100220;
+	u32 reg_100224;
+	u32 reg_100228;
+	u32 reg_10022c;
+	u32 reg_100230;
+	u32 reg_100234;
+	u32 reg_100238;
+	u32 reg_10023c;
+};
+
+struct nouveau_pm_memtimings {
+	bool supported;
+	struct nouveau_pm_memtiming *timing;
+	int nr_timing;
+};
+
+struct nouveau_pm_engine {
+	struct nouveau_pm_voltage voltage;
+	struct nouveau_pm_level perflvl[NOUVEAU_PM_MAX_LEVEL];
+	int nr_perflvl;
+	struct nouveau_pm_memtimings memtimings;
+	struct nouveau_pm_temp_sensor_constants sensor_constants;
+	struct nouveau_pm_threshold_temp threshold_temp;
+
+	struct nouveau_pm_level boot;
+	struct nouveau_pm_level *cur;
+
+	struct device *hwmon;
+
+	int (*clock_get)(struct drm_device *, u32 id);
+	void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *,
+			   u32 id, int khz);
+	void (*clock_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 *);
+	int (*fanspeed_set)(struct drm_device *, int fanspeed);
+	int (*temp_get)(struct drm_device *);
+};
+
 struct nouveau_engine {
 	struct nouveau_instmem_engine instmem;
 	struct nouveau_mc_engine      mc;
@@ -378,6 +458,7 @@
 	struct nouveau_fifo_engine    fifo;
 	struct nouveau_display_engine display;
 	struct nouveau_gpio_engine    gpio;
+	struct nouveau_pm_engine      pm;
 };
 
 struct nouveau_pll_vals {
@@ -409,13 +490,13 @@
 };
 
 struct nv04_crtc_reg {
-	unsigned char MiscOutReg;     /* */
+	unsigned char MiscOutReg;
 	uint8_t CRTC[0xa0];
 	uint8_t CR58[0x10];
 	uint8_t Sequencer[5];
 	uint8_t Graphics[9];
 	uint8_t Attribute[21];
-	unsigned char DAC[768];       /* Internal Colorlookuptable */
+	unsigned char DAC[768];
 
 	/* PCRTC regs */
 	uint32_t fb_start;
@@ -463,43 +544,9 @@
 };
 
 struct nv04_mode_state {
-	uint32_t bpp;
-	uint32_t width;
-	uint32_t height;
-	uint32_t interlace;
-	uint32_t repaint0;
-	uint32_t repaint1;
-	uint32_t screen;
-	uint32_t scale;
-	uint32_t dither;
-	uint32_t extra;
-	uint32_t fifo;
-	uint32_t pixel;
-	uint32_t horiz;
-	int arbitration0;
-	int arbitration1;
-	uint32_t pll;
-	uint32_t pllB;
-	uint32_t vpll;
-	uint32_t vpll2;
-	uint32_t vpllB;
-	uint32_t vpll2B;
+	struct nv04_crtc_reg crtc_reg[2];
 	uint32_t pllsel;
 	uint32_t sel_clk;
-	uint32_t general;
-	uint32_t crtcOwner;
-	uint32_t head;
-	uint32_t head2;
-	uint32_t cursorConfig;
-	uint32_t cursor0;
-	uint32_t cursor1;
-	uint32_t cursor2;
-	uint32_t timingH;
-	uint32_t timingV;
-	uint32_t displayV;
-	uint32_t crtcSync;
-
-	struct nv04_crtc_reg crtc_reg[2];
 };
 
 enum nouveau_card_type {
@@ -522,8 +569,14 @@
 	int flags;
 
 	void __iomem *mmio;
+
+	spinlock_t ramin_lock;
 	void __iomem *ramin;
-	uint32_t ramin_size;
+	u32 ramin_size;
+	u32 ramin_base;
+	bool ramin_available;
+	struct drm_mm ramin_heap;
+	struct list_head gpuobj_list;
 
 	struct nouveau_bo *vga_ram;
 
@@ -531,6 +584,12 @@
 	struct work_struct irq_work;
 	struct work_struct hpd_work;
 
+	struct {
+		spinlock_t lock;
+		uint32_t hpd0_bits;
+		uint32_t hpd1_bits;
+	} hpd_state;
+
 	struct list_head vbl_waiting;
 
 	struct {
@@ -540,6 +599,12 @@
 		atomic_t validate_sequence;
 	} ttm;
 
+	struct {
+		spinlock_t lock;
+		struct drm_mm heap;
+		struct nouveau_bo *bo;
+	} fence;
+
 	int fifo_alloc_count;
 	struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
 
@@ -550,15 +615,11 @@
 	spinlock_t context_switch_lock;
 
 	/* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */
-	struct nouveau_gpuobj *ramht;
+	struct nouveau_ramht  *ramht;
+	struct nouveau_gpuobj *ramfc;
+	struct nouveau_gpuobj *ramro;
+
 	uint32_t ramin_rsvd_vram;
-	uint32_t ramht_offset;
-	uint32_t ramht_size;
-	uint32_t ramht_bits;
-	uint32_t ramfc_offset;
-	uint32_t ramfc_size;
-	uint32_t ramro_offset;
-	uint32_t ramro_size;
 
 	struct {
 		enum {
@@ -576,14 +637,12 @@
 	} gart_info;
 
 	/* nv10-nv40 tiling regions */
-	struct {
-		struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR];
-		spinlock_t lock;
-	} tile;
+	struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR];
 
 	/* VRAM/fb configuration */
 	uint64_t vram_size;
 	uint64_t vram_sys_base;
+	u32 vram_rblock_size;
 
 	uint64_t fb_phys;
 	uint64_t fb_available_size;
@@ -600,10 +659,6 @@
 	struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
 	int vm_vram_pt_nr;
 
-	struct drm_mm ramin_heap;
-
-	struct list_head gpuobj_list;
-
 	struct nvbios vbios;
 
 	struct nv04_mode_state mode_reg;
@@ -634,6 +689,12 @@
 };
 
 static inline struct drm_nouveau_private *
+nouveau_private(struct drm_device *dev)
+{
+	return dev->dev_private;
+}
+
+static inline struct drm_nouveau_private *
 nouveau_bdev(struct ttm_bo_device *bd)
 {
 	return container_of(bd, struct drm_nouveau_private, ttm.bdev);
@@ -669,7 +730,7 @@
 } while (0)
 
 /* nouveau_drv.c */
-extern int nouveau_noagp;
+extern int nouveau_agpmode;
 extern int nouveau_duallink;
 extern int nouveau_uscript_lvds;
 extern int nouveau_uscript_tmds;
@@ -683,7 +744,10 @@
 extern int nouveau_ignorelid;
 extern int nouveau_nofbaccel;
 extern int nouveau_noaccel;
+extern int nouveau_force_post;
 extern int nouveau_override_conntype;
+extern char *nouveau_perflvl;
+extern int nouveau_perflvl_wr;
 
 extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
 extern int nouveau_pci_resume(struct pci_dev *pdev);
@@ -704,8 +768,10 @@
 extern int  nouveau_card_init(struct drm_device *);
 
 /* nouveau_mem.c */
-extern int  nouveau_mem_detect(struct drm_device *dev);
-extern int  nouveau_mem_init(struct drm_device *);
+extern int  nouveau_mem_vram_init(struct drm_device *);
+extern void nouveau_mem_vram_fini(struct drm_device *);
+extern int  nouveau_mem_gart_init(struct drm_device *);
+extern void nouveau_mem_gart_fini(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
 extern int  nouveau_mem_reset_agp(struct drm_device *);
 extern void nouveau_mem_close(struct drm_device *);
@@ -749,7 +815,6 @@
 extern int  nouveau_gpuobj_early_init(struct drm_device *);
 extern int  nouveau_gpuobj_init(struct drm_device *);
 extern void nouveau_gpuobj_takedown(struct drm_device *);
-extern void nouveau_gpuobj_late_takedown(struct drm_device *);
 extern int  nouveau_gpuobj_suspend(struct drm_device *dev);
 extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev);
 extern void nouveau_gpuobj_resume(struct drm_device *dev);
@@ -759,24 +824,11 @@
 extern int nouveau_gpuobj_new(struct drm_device *, struct nouveau_channel *,
 			      uint32_t size, int align, uint32_t flags,
 			      struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_del(struct drm_device *, struct nouveau_gpuobj **);
-extern int nouveau_gpuobj_ref_add(struct drm_device *, struct nouveau_channel *,
-				  uint32_t handle, struct nouveau_gpuobj *,
-				  struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_del(struct drm_device *,
-				  struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_ref_find(struct nouveau_channel *, uint32_t handle,
-				   struct nouveau_gpuobj_ref **ref_ret);
-extern int nouveau_gpuobj_new_ref(struct drm_device *,
-				  struct nouveau_channel *alloc_chan,
-				  struct nouveau_channel *ref_chan,
-				  uint32_t handle, uint32_t size, int align,
-				  uint32_t flags, struct nouveau_gpuobj_ref **);
-extern int nouveau_gpuobj_new_fake(struct drm_device *,
-				   uint32_t p_offset, uint32_t b_offset,
-				   uint32_t size, uint32_t flags,
-				   struct nouveau_gpuobj **,
-				   struct nouveau_gpuobj_ref**);
+extern void nouveau_gpuobj_ref(struct nouveau_gpuobj *,
+			       struct nouveau_gpuobj **);
+extern int nouveau_gpuobj_new_fake(struct drm_device *, u32 pinst, u64 vinst,
+				   u32 size, u32 flags,
+				   struct nouveau_gpuobj **);
 extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class,
 				  uint64_t offset, uint64_t size, int access,
 				  int target, struct nouveau_gpuobj **);
@@ -879,6 +931,7 @@
 						      enum dcb_gpio_tag);
 extern struct dcb_connector_table_entry *
 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 *,
@@ -925,10 +978,10 @@
 extern void nv40_fb_takedown(struct drm_device *);
 extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
 				      uint32_t, uint32_t);
-
 /* nv50_fb.c */
 extern int  nv50_fb_init(struct drm_device *);
 extern void nv50_fb_takedown(struct drm_device *);
+extern void nv50_fb_vm_trap(struct drm_device *, int display, const char *);
 
 /* nvc0_fb.c */
 extern int  nvc0_fb_init(struct drm_device *);
@@ -939,7 +992,6 @@
 extern void nv04_fifo_disable(struct drm_device *);
 extern void nv04_fifo_enable(struct drm_device *);
 extern bool nv04_fifo_reassign(struct drm_device *, bool);
-extern bool nv04_fifo_cache_flush(struct drm_device *);
 extern bool nv04_fifo_cache_pull(struct drm_device *, bool);
 extern int  nv04_fifo_channel_id(struct drm_device *);
 extern int  nv04_fifo_create_context(struct nouveau_channel *);
@@ -970,6 +1022,7 @@
 extern void nv50_fifo_destroy_context(struct nouveau_channel *);
 extern int  nv50_fifo_load_context(struct nouveau_channel *);
 extern int  nv50_fifo_unload_context(struct drm_device *);
+extern void nv50_fifo_tlb_flush(struct drm_device *dev);
 
 /* nvc0_fifo.c */
 extern int  nvc0_fifo_init(struct drm_device *);
@@ -977,7 +1030,6 @@
 extern void nvc0_fifo_disable(struct drm_device *);
 extern void nvc0_fifo_enable(struct drm_device *);
 extern bool nvc0_fifo_reassign(struct drm_device *, bool);
-extern bool nvc0_fifo_cache_flush(struct drm_device *);
 extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
 extern int  nvc0_fifo_channel_id(struct drm_device *);
 extern int  nvc0_fifo_create_context(struct nouveau_channel *);
@@ -1048,6 +1100,8 @@
 extern int  nv50_graph_unload_context(struct drm_device *);
 extern void nv50_graph_context_switch(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
+extern void nv50_graph_tlb_flush(struct drm_device *dev);
+extern void nv86_graph_tlb_flush(struct drm_device *dev);
 
 /* nvc0_graph.c */
 extern int  nvc0_graph_init(struct drm_device *);
@@ -1165,19 +1219,24 @@
 extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
 extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
 extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
-extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
 
 /* nouveau_fence.c */
 struct nouveau_fence;
-extern int nouveau_fence_init(struct nouveau_channel *);
-extern void nouveau_fence_fini(struct nouveau_channel *);
+extern int nouveau_fence_init(struct drm_device *);
+extern void nouveau_fence_fini(struct drm_device *);
+extern int nouveau_fence_channel_init(struct nouveau_channel *);
+extern void nouveau_fence_channel_fini(struct nouveau_channel *);
 extern void nouveau_fence_update(struct nouveau_channel *);
 extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **,
 			     bool emit);
 extern int nouveau_fence_emit(struct nouveau_fence *);
+extern void nouveau_fence_work(struct nouveau_fence *fence,
+			       void (*work)(void *priv, bool signalled),
+			       void *priv);
 struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
 extern bool nouveau_fence_signalled(void *obj, void *arg);
 extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
+extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
 extern int nouveau_fence_flush(void *obj, void *arg);
 extern void nouveau_fence_unref(void **obj);
 extern void *nouveau_fence_ref(void *obj);
@@ -1255,12 +1314,11 @@
 	iowrite32_native(val, dev_priv->mmio + reg);
 }
 
-static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
+static inline u32 nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
 {
 	u32 tmp = nv_rd32(dev, reg);
-	tmp &= ~mask;
-	tmp |= val;
-	nv_wr32(dev, reg, tmp);
+	nv_wr32(dev, reg, (tmp & ~mask) | val);
+	return tmp;
 }
 
 static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
@@ -1275,7 +1333,7 @@
 	iowrite8(val, dev_priv->mmio + reg);
 }
 
-#define nv_wait(reg, mask, val) \
+#define nv_wait(dev, reg, mask, val) \
 	nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val))
 
 /* PRAMIN access */
@@ -1292,17 +1350,8 @@
 }
 
 /* object access */
-static inline u32 nv_ro32(struct drm_device *dev, struct nouveau_gpuobj *obj,
-				unsigned index)
-{
-	return nv_ri32(dev, obj->im_pramin->start + index * 4);
-}
-
-static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj,
-				unsigned index, u32 val)
-{
-	nv_wi32(dev, obj->im_pramin->start + index * 4, val);
-}
+extern u32 nv_ro32(struct nouveau_gpuobj *, u32 offset);
+extern void nv_wo32(struct nouveau_gpuobj *, u32 offset, u32 val);
 
 /*
  * Logging
@@ -1403,6 +1452,7 @@
 #define NV_SW_SEMAPHORE_OFFSET                                       0x00000064
 #define NV_SW_SEMAPHORE_ACQUIRE                                      0x00000068
 #define NV_SW_SEMAPHORE_RELEASE                                      0x0000006c
+#define NV_SW_YIELD                                                  0x00000080
 #define NV_SW_DMA_VBLSEM                                             0x0000018c
 #define NV_SW_VBLSEM_OFFSET                                          0x00000400
 #define NV_SW_VBLSEM_RELEASE_VALUE                                   0x00000404
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_encoder.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_encoder.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_encoder.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_encoder.h	2011-01-04 19:50:19.000000000 -0500
@@ -55,6 +55,7 @@
 			int dpcd_version;
 			int link_nr;
 			int link_bw;
+			bool enhanced_frame;
 		} dp;
 	};
 };
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_fbcon.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_fbcon.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_fbcon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_fbcon.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,6 +104,8 @@
 	.fb_pan_display = drm_fb_helper_pan_display,
 	.fb_blank = drm_fb_helper_blank,
 	.fb_setcmap = drm_fb_helper_setcmap,
+	.fb_debug_enter = drm_fb_helper_debug_enter,
+	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static struct fb_ops nv04_fbcon_ops = {
@@ -117,6 +119,8 @@
 	.fb_pan_display = drm_fb_helper_pan_display,
 	.fb_blank = drm_fb_helper_blank,
 	.fb_setcmap = drm_fb_helper_setcmap,
+	.fb_debug_enter = drm_fb_helper_debug_enter,
+	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static struct fb_ops nv50_fbcon_ops = {
@@ -130,6 +134,8 @@
 	.fb_pan_display = drm_fb_helper_pan_display,
 	.fb_blank = drm_fb_helper_blank,
 	.fb_setcmap = drm_fb_helper_setcmap,
+	.fb_debug_enter = drm_fb_helper_debug_enter,
+	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_fence.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_fence.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_fence.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_fence.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,9 +28,11 @@
 #include "drm.h"
 
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 #include "nouveau_dma.h"
 
-#define USE_REFCNT (dev_priv->card_type >= NV_10)
+#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
 
 struct nouveau_fence {
 	struct nouveau_channel *channel;
@@ -39,6 +41,15 @@
 
 	uint32_t sequence;
 	bool signalled;
+
+	void (*work)(void *priv, bool signalled);
+	void *priv;
+};
+
+struct nouveau_semaphore {
+	struct kref ref;
+	struct drm_device *dev;
+	struct drm_mm_node *mem;
 };
 
 static inline struct nouveau_fence *
@@ -59,14 +70,13 @@
 void
 nouveau_fence_update(struct nouveau_channel *chan)
 {
-	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-	struct list_head *entry, *tmp;
-	struct nouveau_fence *fence;
+	struct drm_device *dev = chan->dev;
+	struct nouveau_fence *tmp, *fence;
 	uint32_t sequence;
 
 	spin_lock(&chan->fence.lock);
 
-	if (USE_REFCNT)
+	if (USE_REFCNT(dev))
 		sequence = nvchan_rd32(chan, 0x48);
 	else
 		sequence = atomic_read(&chan->fence.last_sequence_irq);
@@ -75,12 +85,14 @@
 		goto out;
 	chan->fence.sequence_ack = sequence;
 
-	list_for_each_safe(entry, tmp, &chan->fence.pending) {
-		fence = list_entry(entry, struct nouveau_fence, entry);
-
+	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
 		sequence = fence->sequence;
 		fence->signalled = true;
 		list_del(&fence->entry);
+
+		if (unlikely(fence->work))
+			fence->work(fence->priv, true);
+
 		kref_put(&fence->refcount, nouveau_fence_del);
 
 		if (sequence == chan->fence.sequence_ack)
@@ -121,8 +133,8 @@
 int
 nouveau_fence_emit(struct nouveau_fence *fence)
 {
-	struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
 	struct nouveau_channel *chan = fence->channel;
+	struct drm_device *dev = chan->dev;
 	int ret;
 
 	ret = RING_SPACE(chan, 2);
@@ -143,7 +155,7 @@
 	list_add_tail(&fence->entry, &chan->fence.pending);
 	spin_unlock(&chan->fence.lock);
 
-	BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
+	BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1);
 	OUT_RING(chan, fence->sequence);
 	FIRE_RING(chan);
 
@@ -151,6 +163,25 @@
 }
 
 void
+nouveau_fence_work(struct nouveau_fence *fence,
+		   void (*work)(void *priv, bool signalled),
+		   void *priv)
+{
+	BUG_ON(fence->work);
+
+	spin_lock(&fence->channel->fence.lock);
+
+	if (fence->signalled) {
+		work(priv, true);
+	} else {
+		fence->work = work;
+		fence->priv = priv;
+	}
+
+	spin_unlock(&fence->channel->fence.lock);
+}
+
+void
 nouveau_fence_unref(void **sync_obj)
 {
 	struct nouveau_fence *fence = nouveau_fence(*sync_obj);
@@ -213,6 +244,167 @@
 	return ret;
 }
 
+static struct nouveau_semaphore *
+alloc_semaphore(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_semaphore *sema;
+	int ret;
+
+	if (!USE_SEMA(dev))
+		return NULL;
+
+	sema = kmalloc(sizeof(*sema), GFP_KERNEL);
+	if (!sema)
+		goto fail;
+
+	ret = drm_mm_pre_get(&dev_priv->fence.heap);
+	if (ret)
+		goto fail;
+
+	spin_lock(&dev_priv->fence.lock);
+	sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
+	if (sema->mem)
+		sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0);
+	spin_unlock(&dev_priv->fence.lock);
+
+	if (!sema->mem)
+		goto fail;
+
+	kref_init(&sema->ref);
+	sema->dev = dev;
+	nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0);
+
+	return sema;
+fail:
+	kfree(sema);
+	return NULL;
+}
+
+static void
+free_semaphore(struct kref *ref)
+{
+	struct nouveau_semaphore *sema =
+		container_of(ref, struct nouveau_semaphore, ref);
+	struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+	spin_lock(&dev_priv->fence.lock);
+	drm_mm_put_block(sema->mem);
+	spin_unlock(&dev_priv->fence.lock);
+
+	kfree(sema);
+}
+
+static void
+semaphore_work(void *priv, bool signalled)
+{
+	struct nouveau_semaphore *sema = priv;
+	struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+
+	if (unlikely(!signalled))
+		nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);
+
+	kref_put(&sema->ref, free_semaphore);
+}
+
+static int
+emit_semaphore(struct nouveau_channel *chan, int method,
+	       struct nouveau_semaphore *sema)
+{
+	struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
+	struct nouveau_fence *fence;
+	bool smart = (dev_priv->card_type >= NV_50);
+	int ret;
+
+	ret = RING_SPACE(chan, smart ? 8 : 4);
+	if (ret)
+		return ret;
+
+	if (smart) {
+		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+		OUT_RING(chan, NvSema);
+	}
+	BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1);
+	OUT_RING(chan, sema->mem->start);
+
+	if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) {
+		/*
+		 * NV50 tries to be too smart and context-switch
+		 * between semaphores instead of doing a "first come,
+		 * first served" strategy like previous cards
+		 * do.
+		 *
+		 * That's bad because the ACQUIRE latency can get as
+		 * large as the PFIFO context time slice in the
+		 * typical DRI2 case where you have several
+		 * outstanding semaphores at the same moment.
+		 *
+		 * If we're going to ACQUIRE, force the card to
+		 * context switch before, just in case the matching
+		 * RELEASE is already scheduled to be executed in
+		 * another channel.
+		 */
+		BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+		OUT_RING(chan, 0);
+	}
+
+	BEGIN_RING(chan, NvSubSw, method, 1);
+	OUT_RING(chan, 1);
+
+	if (smart && method == NV_SW_SEMAPHORE_RELEASE) {
+		/*
+		 * Force the card to context switch, there may be
+		 * another channel waiting for the semaphore we just
+		 * released.
+		 */
+		BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1);
+		OUT_RING(chan, 0);
+	}
+
+	/* Delay semaphore destruction until its work is done */
+	ret = nouveau_fence_new(chan, &fence, true);
+	if (ret)
+		return ret;
+
+	kref_get(&sema->ref);
+	nouveau_fence_work(fence, semaphore_work, sema);
+	nouveau_fence_unref((void *)&fence);
+
+	return 0;
+}
+
+int
+nouveau_fence_sync(struct nouveau_fence *fence,
+		   struct nouveau_channel *wchan)
+{
+	struct nouveau_channel *chan = nouveau_fence_channel(fence);
+	struct drm_device *dev = wchan->dev;
+	struct nouveau_semaphore *sema;
+	int ret;
+
+	if (likely(!fence || chan == wchan ||
+		   nouveau_fence_signalled(fence, NULL)))
+		return 0;
+
+	sema = alloc_semaphore(dev);
+	if (!sema) {
+		/* Early card or broken userspace, fall back to
+		 * software sync. */
+		return nouveau_fence_wait(fence, NULL, false, false);
+	}
+
+	/* Make wchan wait until it gets signalled */
+	ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema);
+	if (ret)
+		goto out;
+
+	/* Signal the semaphore from chan */
+	ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema);
+out:
+	kref_put(&sema->ref, free_semaphore);
+	return ret;
+}
+
 int
 nouveau_fence_flush(void *sync_obj, void *sync_arg)
 {
@@ -220,26 +412,123 @@
 }
 
 int
-nouveau_fence_init(struct nouveau_channel *chan)
+nouveau_fence_channel_init(struct nouveau_channel *chan)
 {
+	struct drm_device *dev = chan->dev;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_gpuobj *obj = NULL;
+	int ret;
+
+	/* Create an NV_SW object for various sync purposes */
+	ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj);
+	if (ret)
+		return ret;
+
+	ret = nouveau_ramht_insert(chan, NvSw, obj);
+	nouveau_gpuobj_ref(NULL, &obj);
+	if (ret)
+		return ret;
+
+	ret = RING_SPACE(chan, 2);
+	if (ret)
+		return ret;
+	BEGIN_RING(chan, NvSubSw, 0, 1);
+	OUT_RING(chan, NvSw);
+
+	/* Create a DMA object for the shared cross-channel sync area. */
+	if (USE_SEMA(dev)) {
+		struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node;
+
+		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+					     mem->start << PAGE_SHIFT,
+					     mem->size << PAGE_SHIFT,
+					     NV_DMA_ACCESS_RW,
+					     NV_DMA_TARGET_VIDMEM, &obj);
+		if (ret)
+			return ret;
+
+		ret = nouveau_ramht_insert(chan, NvSema, obj);
+		nouveau_gpuobj_ref(NULL, &obj);
+		if (ret)
+			return ret;
+
+		ret = RING_SPACE(chan, 2);
+		if (ret)
+			return ret;
+		BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1);
+		OUT_RING(chan, NvSema);
+	}
+
+	FIRE_RING(chan);
+
 	INIT_LIST_HEAD(&chan->fence.pending);
 	spin_lock_init(&chan->fence.lock);
 	atomic_set(&chan->fence.last_sequence_irq, 0);
+
 	return 0;
 }
 
 void
-nouveau_fence_fini(struct nouveau_channel *chan)
+nouveau_fence_channel_fini(struct nouveau_channel *chan)
 {
-	struct list_head *entry, *tmp;
-	struct nouveau_fence *fence;
-
-	list_for_each_safe(entry, tmp, &chan->fence.pending) {
-		fence = list_entry(entry, struct nouveau_fence, entry);
+	struct nouveau_fence *tmp, *fence;
 
+	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
 		fence->signalled = true;
 		list_del(&fence->entry);
+
+		if (unlikely(fence->work))
+			fence->work(fence->priv, false);
+
 		kref_put(&fence->refcount, nouveau_fence_del);
 	}
 }
 
+int
+nouveau_fence_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int ret;
+
+	/* Create a shared VRAM heap for cross-channel sync. */
+	if (USE_SEMA(dev)) {
+		ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM,
+				     0, 0, false, true, &dev_priv->fence.bo);
+		if (ret)
+			return ret;
+
+		ret = nouveau_bo_pin(dev_priv->fence.bo, TTM_PL_FLAG_VRAM);
+		if (ret)
+			goto fail;
+
+		ret = nouveau_bo_map(dev_priv->fence.bo);
+		if (ret)
+			goto fail;
+
+		ret = drm_mm_init(&dev_priv->fence.heap, 0,
+				  dev_priv->fence.bo->bo.mem.size);
+		if (ret)
+			goto fail;
+
+		spin_lock_init(&dev_priv->fence.lock);
+	}
+
+	return 0;
+fail:
+	nouveau_bo_unmap(dev_priv->fence.bo);
+	nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+	return ret;
+}
+
+void
+nouveau_fence_fini(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	if (USE_SEMA(dev)) {
+		drm_mm_takedown(&dev_priv->fence.heap);
+		nouveau_bo_unmap(dev_priv->fence.bo);
+		nouveau_bo_unpin(dev_priv->fence.bo);
+		nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+	}
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_gem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_gem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_gem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_gem.c	2011-01-04 19:50:19.000000000 -0500
@@ -107,23 +107,29 @@
 }
 
 static bool
-nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
-	switch (tile_flags) {
-	case 0x0000:
-	case 0x1800:
-	case 0x2800:
-	case 0x4800:
-	case 0x7000:
-	case 0x7400:
-	case 0x7a00:
-	case 0xe000:
-		break;
-	default:
-		NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
-		return false;
+nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->card_type >= NV_50) {
+		switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) {
+		case 0x0000:
+		case 0x1800:
+		case 0x2800:
+		case 0x4800:
+		case 0x7000:
+		case 0x7400:
+		case 0x7a00:
+		case 0xe000:
+			return true;
+		}
+	} else {
+		if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))
+			return true;
 	}
 
-	return true;
+	NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
+	return false;
 }
 
 int
@@ -362,7 +368,7 @@
 	list_for_each_entry(nvbo, list, entry) {
 		struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
-		ret = nouveau_bo_sync_gpu(nvbo, chan);
+		ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
 		if (unlikely(ret)) {
 			NV_ERROR(dev, "fail pre-validate sync\n");
 			return ret;
@@ -385,7 +391,7 @@
 			return ret;
 		}
 
-		ret = nouveau_bo_sync_gpu(nvbo, chan);
+		ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan);
 		if (unlikely(ret)) {
 			NV_ERROR(dev, "fail post-validate sync\n");
 			return ret;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_grctx.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_grctx.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_grctx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_grctx.h	2011-01-04 19:50:19.000000000 -0500
@@ -126,7 +126,7 @@
 	reg = (reg - 0x00400000) / 4;
 	reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
 
-	nv_wo32(ctx->dev, ctx->data, reg, val);
+	nv_wo32(ctx->data, reg * 4, val);
 }
 #endif
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_hw.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_hw.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_hw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_hw.c	2011-01-04 19:50:19.000000000 -0500
@@ -305,7 +305,7 @@
 	bool mpll = Preg == 0x4020;
 	uint32_t oldPval = nvReadMC(dev, Preg);
 	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
-	uint32_t Pval = (oldPval & (mpll ? ~(0x11 << 16) : ~(1 << 16))) |
+	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
 			0xc << 28 | pv->log2P << 16;
 	uint32_t saved4600 = 0;
 	/* some cards have different maskc040s */
@@ -427,22 +427,12 @@
 		       struct nouveau_pll_vals *pllvals)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	const uint32_t nv04_regs[MAX_PLL_TYPES] = { NV_PRAMDAC_NVPLL_COEFF,
-						    NV_PRAMDAC_MPLL_COEFF,
-						    NV_PRAMDAC_VPLL_COEFF,
-						    NV_RAMDAC_VPLL2 };
-	const uint32_t nv40_regs[MAX_PLL_TYPES] = { 0x4000,
-						    0x4020,
-						    NV_PRAMDAC_VPLL_COEFF,
-						    NV_RAMDAC_VPLL2 };
-	uint32_t reg1, pll1, pll2 = 0;
+	uint32_t reg1 = get_pll_register(dev, plltype), pll1, pll2 = 0;
 	struct pll_lims pll_lim;
 	int ret;
 
-	if (dev_priv->card_type < NV_40)
-		reg1 = nv04_regs[plltype];
-	else
-		reg1 = nv40_regs[plltype];
+	if (reg1 == 0)
+		return -ENOENT;
 
 	pll1 = nvReadMC(dev, reg1);
 
@@ -491,8 +481,10 @@
 nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
 {
 	struct nouveau_pll_vals pllvals;
+	int ret;
 
-	if (plltype == MPLL && (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
+	if (plltype == PLL_MEMORY &&
+	    (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
 		uint32_t mpllP;
 
 		pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
@@ -501,14 +493,17 @@
 
 		return 400000 / mpllP;
 	} else
-	if (plltype == MPLL && (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
+	if (plltype == PLL_MEMORY &&
+	    (dev->pci_device & 0xff0) == CHIPSET_NFORCE2) {
 		uint32_t clock;
 
 		pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
 		return clock;
 	}
 
-	nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+	ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
+	if (ret)
+		return ret;
 
 	return nouveau_hw_pllvals_to_clk(&pllvals);
 }
@@ -524,11 +519,11 @@
 
 	struct pll_lims pll_lim;
 	struct nouveau_pll_vals pv;
-	uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
+	enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
 
-	if (get_pll_limits(dev, head ? VPLL2 : VPLL1, &pll_lim))
+	if (get_pll_limits(dev, pll, &pll_lim))
 		return;
-	nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &pv);
+	nouveau_hw_get_pllvals(dev, pll, &pv);
 
 	if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
 	    pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
@@ -541,7 +536,7 @@
 	pv.M1 = pll_lim.vco1.max_m;
 	pv.N1 = pll_lim.vco1.min_n;
 	pv.log2P = pll_lim.max_usable_log2p;
-	nouveau_hw_setpll(dev, pllreg, &pv);
+	nouveau_hw_setpll(dev, pll_lim.reg, &pv);
 }
 
 /*
@@ -661,7 +656,7 @@
 	if (dev_priv->card_type >= NV_10)
 		regp->nv10_cursync = NVReadRAMDAC(dev, head, NV_RAMDAC_NV10_CURSYNC);
 
-	nouveau_hw_get_pllvals(dev, head ? VPLL2 : VPLL1, &regp->pllvals);
+	nouveau_hw_get_pllvals(dev, head ? PLL_VPLL1 : PLL_VPLL0, &regp->pllvals);
 	state->pllsel = NVReadRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT);
 	if (nv_two_heads(dev))
 		state->sel_clk = NVReadRAMDAC(dev, 0, NV_PRAMDAC_SEL_CLK);
@@ -866,10 +861,11 @@
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
 
-	if (dev_priv->card_type >= NV_30) {
+	if (dev_priv->card_type >= NV_20)
 		rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+	if (dev_priv->card_type >= NV_30)
 		rd_cio_state(dev, head, regp, 0x9f);
-	}
 
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
@@ -976,10 +972,11 @@
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
 
-	if (dev_priv->card_type >= NV_30) {
+	if (dev_priv->card_type >= NV_20)
 		wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+
+	if (dev_priv->card_type >= NV_30)
 		wr_cio_state(dev, head, regp, 0x9f);
-	}
 
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_hw.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_hw.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_hw.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_hw.h	2011-01-04 19:50:19.000000000 -0500
@@ -416,6 +416,25 @@
 }
 
 static inline void
+nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
+
+	if (dev_priv->card_type == NV_04) {
+		/*
+		 * Hilarious, the 24th bit doesn't want to stick to
+		 * PCRTC_START...
+		 */
+		int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
+
+		NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
+			       (cre_heb & ~0x40) | ((offset >> 18) & 0x40));
+	}
+}
+
+static inline void
 nv_show_cursor(struct drm_device *dev, int head, bool show)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -256,7 +256,7 @@
 	if (index >= DCB_MAX_NUM_I2C_ENTRIES)
 		return NULL;
 
-	if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
+	if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
 		uint32_t reg = 0xe500, val;
 
 		if (i2c->port_type == 6) {
@@ -299,7 +299,10 @@
 
 int
 nouveau_i2c_identify(struct drm_device *dev, const char *what,
-		     struct i2c_board_info *info, int index)
+		     struct i2c_board_info *info,
+		     bool (*match)(struct nouveau_i2c_chan *,
+				   struct i2c_board_info *),
+		     int index)
 {
 	struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
 	int i;
@@ -307,7 +310,8 @@
 	NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
 
 	for (i = 0; info[i].addr; i++) {
-		if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
+		if (nouveau_probe_i2c_addr(i2c, info[i].addr) &&
+		    (!match || match(i2c, &info[i]))) {
 			NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
 			return i;
 		}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_i2c.h	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,6 @@
 #define __NOUVEAU_I2C_H__
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 #include "drm_dp_helper.h"
 
@@ -44,7 +43,10 @@
 struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
 bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
 int nouveau_i2c_identify(struct drm_device *dev, const char *what,
-			 struct i2c_board_info *info, int index);
+			 struct i2c_board_info *info,
+			 bool (*match)(struct nouveau_i2c_chan *,
+				       struct i2c_board_info *),
+			 int index);
 
 extern const struct i2c_algorithm nouveau_dp_i2c_algo;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_irq.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_irq.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,12 +35,20 @@
 #include "nouveau_drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_reg.h"
+#include "nouveau_ramht.h"
 #include <linux/ratelimit.h>
 
 /* needed for hotplug irq */
 #include "nouveau_connector.h"
 #include "nv50_display.h"
 
+static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
+
+static int nouveau_ratelimit(void)
+{
+	return __ratelimit(&nouveau_ratelimit_state);
+}
+
 void
 nouveau_irq_preinstall(struct drm_device *dev)
 {
@@ -52,6 +60,7 @@
 	if (dev_priv->card_type >= NV_50) {
 		INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
 		INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
+		spin_lock_init(&dev_priv->hpd_state.lock);
 		INIT_LIST_HEAD(&dev_priv->vbl_waiting);
 	}
 }
@@ -106,15 +115,16 @@
 	const int mthd = addr & 0x1ffc;
 
 	if (mthd == 0x0000) {
-		struct nouveau_gpuobj_ref *ref = NULL;
+		struct nouveau_gpuobj *gpuobj;
 
-		if (nouveau_gpuobj_ref_find(chan, data, &ref))
+		gpuobj = nouveau_ramht_find(chan, data);
+		if (!gpuobj)
 			return false;
 
-		if (ref->gpuobj->engine != NVOBJ_ENGINE_SW)
+		if (gpuobj->engine != NVOBJ_ENGINE_SW)
 			return false;
 
-		chan->sw_subchannel[subc] = ref->gpuobj->class;
+		chan->sw_subchannel[subc] = gpuobj->class;
 		nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev,
 			NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4));
 		return true;
@@ -200,16 +210,47 @@
 		}
 
 		if (status & NV_PFIFO_INTR_DMA_PUSHER) {
-			NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d\n", chid);
+			u32 dma_get = nv_rd32(dev, 0x003244);
+			u32 dma_put = nv_rd32(dev, 0x003240);
+			u32 push = nv_rd32(dev, 0x003220);
+			u32 state = nv_rd32(dev, 0x003228);
 
-			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
-			nv_wr32(dev, NV03_PFIFO_INTR_0,
-						NV_PFIFO_INTR_DMA_PUSHER);
+			if (dev_priv->card_type == NV_50) {
+				u32 ho_get = nv_rd32(dev, 0x003328);
+				u32 ho_put = nv_rd32(dev, 0x003320);
+				u32 ib_get = nv_rd32(dev, 0x003334);
+				u32 ib_put = nv_rd32(dev, 0x003330);
 
-			nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, 0x00000000);
-			if (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT) != get)
-				nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET,
-								get + 4);
+				if (nouveau_ratelimit())
+					NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
+					     "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
+					     "State 0x%08x Push 0x%08x\n",
+						chid, ho_get, dma_get, ho_put,
+						dma_put, ib_get, ib_put, state,
+						push);
+
+				/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+				nv_wr32(dev, 0x003364, 0x00000000);
+				if (dma_get != dma_put || ho_get != ho_put) {
+					nv_wr32(dev, 0x003244, dma_put);
+					nv_wr32(dev, 0x003328, ho_put);
+				} else
+				if (ib_get != ib_put) {
+					nv_wr32(dev, 0x003334, ib_put);
+				}
+			} else {
+				NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
+					     "Put 0x%08x State 0x%08x Push 0x%08x\n",
+					chid, dma_get, dma_put, state, push);
+
+				if (dma_get != dma_put)
+					nv_wr32(dev, 0x003244, dma_put);
+			}
+
+			nv_wr32(dev, 0x003228, 0x00000000);
+			nv_wr32(dev, 0x003220, 0x00000001);
+			nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+			status &= ~NV_PFIFO_INTR_DMA_PUSHER;
 		}
 
 		if (status & NV_PFIFO_INTR_SEMAPHORE) {
@@ -226,9 +267,18 @@
 			nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
 		}
 
+		if (dev_priv->card_type == NV_50) {
+			if (status & 0x00000010) {
+				nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT");
+				status &= ~0x00000010;
+				nv_wr32(dev, 0x002100, 0x00000010);
+			}
+		}
+
 		if (status) {
-			NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
-				status, chid);
+			if (nouveau_ratelimit())
+				NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
+					status, chid);
 			nv_wr32(dev, NV03_PFIFO_INTR_0, status);
 			status = 0;
 		}
@@ -357,7 +407,7 @@
 			if (!chan || !chan->ramin_grctx)
 				continue;
 
-			if (inst == chan->ramin_grctx->instance)
+			if (inst == chan->ramin_grctx->pinst)
 				break;
 		}
 	} else {
@@ -369,7 +419,7 @@
 			if (!chan || !chan->ramin)
 				continue;
 
-			if (inst == chan->ramin->instance)
+			if (inst == chan->ramin->vinst)
 				break;
 		}
 	}
@@ -505,13 +555,6 @@
 		nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
 }
 
-static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
-
-static int nouveau_ratelimit(void)
-{
-	return __ratelimit(&nouveau_ratelimit_state);
-}
-
 
 static inline void
 nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
@@ -605,40 +648,6 @@
 	nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING);
 }
 
-static void
-nv50_pfb_vm_trap(struct drm_device *dev, int display, const char *name)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t trap[6];
-	int i, ch;
-	uint32_t idx = nv_rd32(dev, 0x100c90);
-	if (idx & 0x80000000) {
-		idx &= 0xffffff;
-		if (display) {
-			for (i = 0; i < 6; i++) {
-				nv_wr32(dev, 0x100c90, idx | i << 24);
-				trap[i] = nv_rd32(dev, 0x100c94);
-			}
-			for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
-				struct nouveau_channel *chan = dev_priv->fifos[ch];
-
-				if (!chan || !chan->ramin)
-					continue;
-
-				if (trap[1] == chan->ramin->instance >> 12)
-					break;
-			}
-			NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x %08x channel %d\n",
-					name, (trap[5]&0x100?"read":"write"),
-					trap[5]&0xff, trap[4]&0xffff,
-					trap[3]&0xffff, trap[0], trap[2], ch);
-		}
-		nv_wr32(dev, 0x100c90, idx | 0x80000000);
-	} else if (display) {
-		NV_INFO(dev, "%s - no VM fault?\n", name);
-	}
-}
-
 static struct nouveau_enum_names nv50_mp_exec_error_names[] =
 {
 	{ 3, "STACK_UNDERFLOW" },
@@ -711,7 +720,7 @@
 		tps++;
 		switch (type) {
 		case 6: /* texture error... unknown for now */
-			nv50_pfb_vm_trap(dev, display, name);
+			nv50_fb_vm_trap(dev, display, name);
 			if (display) {
 				NV_ERROR(dev, "magic set %d:\n", i);
 				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
@@ -734,7 +743,7 @@
 			uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
 			uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
 			uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
-			nv50_pfb_vm_trap(dev, display, name);
+			nv50_fb_vm_trap(dev, display, name);
 			/* 2d engine destination */
 			if (ustatus & 0x00000010) {
 				if (display) {
@@ -817,7 +826,7 @@
 
 		/* Known to be triggered by screwed up NOTIFY and COND... */
 		if (ustatus & 0x00000001) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT");
 			nv_wr32(dev, 0x400500, 0);
 			if (nv_rd32(dev, 0x400808) & 0x80000000) {
 				if (display) {
@@ -842,7 +851,7 @@
 			ustatus &= ~0x00000001;
 		}
 		if (ustatus & 0x00000002) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY");
 			nv_wr32(dev, 0x400500, 0);
 			if (nv_rd32(dev, 0x40084c) & 0x80000000) {
 				if (display) {
@@ -884,15 +893,15 @@
 			NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n");
 		}
 		if (ustatus & 0x00000001) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY");
 			ustatus &= ~0x00000001;
 		}
 		if (ustatus & 0x00000002) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN");
 			ustatus &= ~0x00000002;
 		}
 		if (ustatus & 0x00000004) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT");
 			ustatus &= ~0x00000004;
 		}
 		NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n",
@@ -917,7 +926,7 @@
 			NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n");
 		}
 		if (ustatus & 0x00000001) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT");
 			NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n",
 					nv_rd32(dev, 0x400c00),
 					nv_rd32(dev, 0x400c08),
@@ -939,7 +948,7 @@
 			NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n");
 		}
 		if (ustatus & 0x00000001) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT");
 			NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n",
 					nv_rd32(dev, 0x401804),
 					nv_rd32(dev, 0x401808),
@@ -964,7 +973,7 @@
 			NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n");
 		}
 		if (ustatus & 0x00000001) {
-			nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
+			nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT");
 			NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n",
 					nv_rd32(dev, 0x405800),
 					nv_rd32(dev, 0x405804),
@@ -986,7 +995,7 @@
 	 * remaining, so try to handle it anyway. Perhaps related to that
 	 * unknown DMA slot on tesla? */
 	if (status & 0x20) {
-		nv50_pfb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
+		nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04");
 		ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
 		if (display)
 			NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_mem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_mem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_mem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_mem.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,7 +33,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "drm_sarea.h"
+
 #include "nouveau_drv.h"
+#include "nouveau_pm.h"
 
 /*
  * NV10-NV40 tiling helpers
@@ -47,18 +49,14 @@
 	struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-	struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+	struct nouveau_tile_reg *tile = &dev_priv->tile[i];
 
 	tile->addr = addr;
 	tile->size = size;
 	tile->used = !!pitch;
 	nouveau_fence_unref((void **)&tile->fence);
 
-	if (!pfifo->cache_flush(dev))
-		return;
-
 	pfifo->reassign(dev, false);
-	pfifo->cache_flush(dev);
 	pfifo->cache_pull(dev, false);
 
 	nouveau_wait_for_idle(dev);
@@ -76,34 +74,36 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-	struct nouveau_tile_reg *tile = dev_priv->tile.reg, *found = NULL;
-	int i;
+	struct nouveau_tile_reg *found = NULL;
+	unsigned long i, flags;
 
-	spin_lock(&dev_priv->tile.lock);
+	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
 
 	for (i = 0; i < pfb->num_tiles; i++) {
-		if (tile[i].used)
+		struct nouveau_tile_reg *tile = &dev_priv->tile[i];
+
+		if (tile->used)
 			/* Tile region in use. */
 			continue;
 
-		if (tile[i].fence &&
-		    !nouveau_fence_signalled(tile[i].fence, NULL))
+		if (tile->fence &&
+		    !nouveau_fence_signalled(tile->fence, NULL))
 			/* Pending tile region. */
 			continue;
 
-		if (max(tile[i].addr, addr) <
-		    min(tile[i].addr + tile[i].size, addr + size))
+		if (max(tile->addr, addr) <
+		    min(tile->addr + tile->size, addr + size))
 			/* Kill an intersecting tile region. */
 			nv10_mem_set_region_tiling(dev, i, 0, 0, 0);
 
 		if (pitch && !found) {
 			/* Free tile region. */
 			nv10_mem_set_region_tiling(dev, i, addr, size, pitch);
-			found = &tile[i];
+			found = tile;
 		}
 	}
 
-	spin_unlock(&dev_priv->tile.lock);
+	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
 	return found;
 }
@@ -169,16 +169,16 @@
 			virt  += (end - pte);
 
 			while (pte < end) {
-				nv_wo32(dev, pgt, pte++, offset_l);
-				nv_wo32(dev, pgt, pte++, offset_h);
+				nv_wo32(pgt, (pte * 4) + 0, offset_l);
+				nv_wo32(pgt, (pte * 4) + 4, offset_h);
+				pte += 2;
 			}
 		}
 	}
-	dev_priv->engine.instmem.flush(dev);
 
-	nv50_vm_flush(dev, 5);
-	nv50_vm_flush(dev, 0);
-	nv50_vm_flush(dev, 4);
+	dev_priv->engine.instmem.flush(dev);
+	dev_priv->engine.fifo.tlb_flush(dev);
+	dev_priv->engine.graph.tlb_flush(dev);
 	nv50_vm_flush(dev, 6);
 	return 0;
 }
@@ -203,14 +203,15 @@
 		pages -= (end - pte);
 		virt  += (end - pte) << 15;
 
-		while (pte < end)
-			nv_wo32(dev, pgt, pte++, 0);
+		while (pte < end) {
+			nv_wo32(pgt, (pte * 4), 0);
+			pte++;
+		}
 	}
-	dev_priv->engine.instmem.flush(dev);
 
-	nv50_vm_flush(dev, 5);
-	nv50_vm_flush(dev, 0);
-	nv50_vm_flush(dev, 4);
+	dev_priv->engine.instmem.flush(dev);
+	dev_priv->engine.fifo.tlb_flush(dev);
+	dev_priv->engine.graph.tlb_flush(dev);
 	nv50_vm_flush(dev, 6);
 }
 
@@ -218,7 +219,7 @@
  * Cleanup everything
  */
 void
-nouveau_mem_close(struct drm_device *dev)
+nouveau_mem_vram_fini(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
@@ -229,6 +230,19 @@
 
 	nouveau_ttm_global_release(dev_priv);
 
+	if (dev_priv->fb_mtrr >= 0) {
+		drm_mtrr_del(dev_priv->fb_mtrr,
+			     pci_resource_start(dev->pdev, 1),
+			     pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
+		dev_priv->fb_mtrr = -1;
+	}
+}
+
+void
+nouveau_mem_gart_fini(struct drm_device *dev)
+{
+	nouveau_sgdma_takedown(dev);
+
 	if (drm_core_has_AGP(dev) && dev->agp) {
 		struct drm_agp_mem *entry, *tempe;
 
@@ -248,13 +262,6 @@
 		dev->agp->acquired = 0;
 		dev->agp->enabled = 0;
 	}
-
-	if (dev_priv->fb_mtrr) {
-		drm_mtrr_del(dev_priv->fb_mtrr,
-			     pci_resource_start(dev->pdev, 1),
-			     pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
-		dev_priv->fb_mtrr = -1;
-	}
 }
 
 static uint32_t
@@ -305,8 +312,62 @@
 	return 0;
 }
 
-/* returns the amount of FB ram in bytes */
-int
+static void
+nv50_vram_preinit(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int i, parts, colbits, rowbitsa, rowbitsb, banks;
+	u64 rowsize, predicted;
+	u32 r0, r4, rt, ru;
+
+	r0 = nv_rd32(dev, 0x100200);
+	r4 = nv_rd32(dev, 0x100204);
+	rt = nv_rd32(dev, 0x100250);
+	ru = nv_rd32(dev, 0x001540);
+	NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+	for (i = 0, parts = 0; i < 8; i++) {
+		if (ru & (0x00010000 << i))
+			parts++;
+	}
+
+	colbits  =  (r4 & 0x0000f000) >> 12;
+	rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+	rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+	banks    = ((r4 & 0x01000000) ? 8 : 4);
+
+	rowsize = parts * banks * (1 << colbits) * 8;
+	predicted = rowsize << rowbitsa;
+	if (r0 & 0x00000004)
+		predicted += rowsize << rowbitsb;
+
+	if (predicted != dev_priv->vram_size) {
+		NV_WARN(dev, "memory controller reports %dMiB VRAM\n",
+			(u32)(dev_priv->vram_size >> 20));
+		NV_WARN(dev, "we calculated %dMiB VRAM\n",
+			(u32)(predicted >> 20));
+	}
+
+	dev_priv->vram_rblock_size = rowsize >> 12;
+	if (rt & 1)
+		dev_priv->vram_rblock_size *= 3;
+
+	NV_DEBUG(dev, "rblock %lld bytes\n",
+		 (u64)dev_priv->vram_rblock_size << 12);
+}
+
+static void
+nvaa_vram_preinit(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	/* To our knowledge, there's no large scale reordering of pages
+	 * that occurs on IGP chipsets.
+	 */
+	dev_priv->vram_rblock_size = 1;
+}
+
+static int
 nouveau_mem_detect(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -325,9 +386,18 @@
 		dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
 		dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
 		dev_priv->vram_size &= 0xffffffff00ll;
-		if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
+
+		switch (dev_priv->chipset) {
+		case 0xaa:
+		case 0xac:
+		case 0xaf:
 			dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
 			dev_priv->vram_sys_base <<= 12;
+			nvaa_vram_preinit(dev);
+			break;
+		default:
+			nv50_vram_preinit(dev);
+			break;
 		}
 	} else {
 		dev_priv->vram_size  = nv_rd32(dev, 0x10f20c) << 20;
@@ -345,6 +415,33 @@
 	return -ENOMEM;
 }
 
+#if __OS_HAS_AGP
+static unsigned long
+get_agp_mode(struct drm_device *dev, unsigned long mode)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	/*
+	 * FW seems to be broken on nv18, it makes the card lock up
+	 * randomly.
+	 */
+	if (dev_priv->chipset == 0x18)
+		mode &= ~PCI_AGP_COMMAND_FW;
+
+	/*
+	 * AGP mode set in the command line.
+	 */
+	if (nouveau_agpmode > 0) {
+		bool agpv3 = mode & 0x8;
+		int rate = agpv3 ? nouveau_agpmode / 4 : nouveau_agpmode;
+
+		mode = (mode & ~0x7) | (rate & 0x7);
+	}
+
+	return mode;
+}
+#endif
+
 int
 nouveau_mem_reset_agp(struct drm_device *dev)
 {
@@ -355,7 +452,8 @@
 	/* First of all, disable fast writes, otherwise if it's
 	 * already enabled in the AGP bridge and we disable the card's
 	 * AGP controller we might be locking ourselves out of it. */
-	if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
+	if ((nv_rd32(dev, NV04_PBUS_PCI_NV_19) |
+	     dev->agp->mode) & PCI_AGP_COMMAND_FW) {
 		struct drm_agp_info info;
 		struct drm_agp_mode mode;
 
@@ -363,7 +461,7 @@
 		if (ret)
 			return ret;
 
-		mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
+		mode.mode = get_agp_mode(dev, info.mode) & ~PCI_AGP_COMMAND_FW;
 		ret = drm_agp_enable(dev, mode);
 		if (ret)
 			return ret;
@@ -418,7 +516,7 @@
 	}
 
 	/* see agp.h for the AGPSTAT_* modes available */
-	mode.mode = info.mode;
+	mode.mode = get_agp_mode(dev, info.mode);
 	ret = drm_agp_enable(dev, mode);
 	if (ret) {
 		NV_ERROR(dev, "Unable to enable AGP: %d\n", ret);
@@ -433,24 +531,27 @@
 }
 
 int
-nouveau_mem_init(struct drm_device *dev)
+nouveau_mem_vram_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
-	int ret, dma_bits = 32;
-
-	dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
-	dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+	int ret, dma_bits;
 
 	if (dev_priv->card_type >= NV_50 &&
 	    pci_dma_supported(dev->pdev, DMA_BIT_MASK(40)))
 		dma_bits = 40;
+	else
+		dma_bits = 32;
 
 	ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits));
-	if (ret) {
-		NV_ERROR(dev, "Error setting DMA mask: %d\n", ret);
+	if (ret)
 		return ret;
-	}
+
+	ret = nouveau_mem_detect(dev);
+	if (ret)
+		return ret;
+
+	dev_priv->fb_phys = pci_resource_start(dev->pdev, 1);
 
 	ret = nouveau_ttm_global_init(dev_priv);
 	if (ret)
@@ -465,8 +566,6 @@
 		return ret;
 	}
 
-	spin_lock_init(&dev_priv->tile.lock);
-
 	dev_priv->fb_available_size = dev_priv->vram_size;
 	dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
 	if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1))
@@ -474,7 +573,16 @@
 			pci_resource_len(dev->pdev, 1);
 	dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
 
-	/* remove reserved space at end of vram from available amount */
+	/* reserve space at end of VRAM for PRAMIN */
+	if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 ||
+	    dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b)
+		dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
+	else
+	if (dev_priv->card_type >= NV_40)
+		dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
+	else
+		dev_priv->ramin_rsvd_vram = (512 * 1024);
+
 	dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
 	dev_priv->fb_aper_free = dev_priv->fb_available_size;
 
@@ -495,9 +603,23 @@
 		nouveau_bo_ref(NULL, &dev_priv->vga_ram);
 	}
 
-	/* GART */
+	dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
+					 pci_resource_len(dev->pdev, 1),
+					 DRM_MTRR_WC);
+	return 0;
+}
+
+int
+nouveau_mem_gart_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct ttm_bo_device *bdev = &dev_priv->ttm.bdev;
+	int ret;
+
+	dev_priv->gart_info.type = NOUVEAU_GART_NONE;
+
 #if !defined(__powerpc__) && !defined(__ia64__)
-	if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
+	if (drm_device_is_agp(dev) && dev->agp && nouveau_agpmode) {
 		ret = nouveau_mem_init_agp(dev);
 		if (ret)
 			NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
@@ -523,11 +645,157 @@
 		return ret;
 	}
 
-	dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
-					 pci_resource_len(dev->pdev, 1),
-					 DRM_MTRR_WC);
-
 	return 0;
 }
 
+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 *mem = NULL, *entry;
+	int i, recordlen, entries;
+
+	if (bios->type == NVBIOS_BIT) {
+		if (bit_table(dev, 'P', &P))
+			return;
+
+		if (P.version == 1)
+			mem = ROMPTR(bios, P.data[4]);
+		else
+		if (P.version == 2)
+			mem = ROMPTR(bios, P.data[8]);
+		else {
+			NV_WARN(dev, "unknown mem for BIT P %d\n", P.version);
+		}
+	} else {
+		NV_DEBUG(dev, "BMP version too old for memory\n");
+		return;
+	}
+
+	if (!mem) {
+		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]);
+		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]);
+		return;
+	}
+
+	/* parse vbios entries into common format */
+	memtimings->timing =
+		kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL);
+	if (!memtimings->timing)
+		return;
+
+	entry = mem + mem[1];
+	for (i = 0; i < entries; i++, entry += recordlen) {
+		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) << 24 |
+				      tUNK_18 << 16 |
+				      (tUNK_1 + tUNK_19 + 1) << 8 |
+				      (tUNK_2 - 1));
+
+		timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
+		if(recordlen > 19) {
+			timing->reg_100228 += (tUNK_19 - 1) << 24;
+		}/* I cannot back-up this else-statement right now
+			 else {
+			timing->reg_100228 += tUNK_12 << 24;
+		}*/
+
+		/* XXX: reg_10022c */
+		timing->reg_10022c = tUNK_2 - 1;
+
+		timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
+				      tUNK_13 << 8  | tUNK_13);
+
+		/* XXX: +6? */
+		timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
+		timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+
+		/* XXX; reg_100238, reg_10023c
+		 * reg: 0x00??????
+		 * reg_10023c:
+		 *      0 for pre-NV50 cards
+		 *      0x????0202 for NV50+ cards (empirical evidence) */
+		if(dev_priv->card_type >= NV_50) {
+			timing->reg_10023c = 0x202;
+		}
+
+		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);
+	}
+
+	memtimings->nr_timing  = entries;
+	memtimings->supported = true;
+}
+
+void
+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);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_notifier.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_notifier.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_notifier.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_notifier.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,6 +28,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 int
 nouveau_notifier_init_channel(struct nouveau_channel *chan)
@@ -112,7 +113,7 @@
 		return -ENOMEM;
 	}
 
-	offset = chan->notifier_bo->bo.mem.mm_node->start << PAGE_SHIFT;
+	offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT;
 	if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) {
 		target = NV_DMA_TARGET_VIDMEM;
 	} else
@@ -146,11 +147,11 @@
 	nobj->dtor = nouveau_notifier_gpuobj_dtor;
 	nobj->priv = mem;
 
-	ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
+	ret = nouveau_ramht_insert(chan, handle, nobj);
+	nouveau_gpuobj_ref(NULL, &nobj);
 	if (ret) {
-		nouveau_gpuobj_del(dev, &nobj);
 		drm_mm_put_block(mem);
-		NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
+		NV_ERROR(dev, "Error adding notifier to ramht: %d\n", ret);
 		return ret;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_object.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_object.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_object.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_object.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,6 +34,7 @@
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
+#include "nouveau_ramht.h"
 
 /* NVidia uses context objects to drive drawing operations.
 
@@ -65,137 +66,6 @@
    The key into the hash table depends on the object handle and channel id and
    is given as:
 */
-static uint32_t
-nouveau_ramht_hash_handle(struct drm_device *dev, int channel, uint32_t handle)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t hash = 0;
-	int i;
-
-	NV_DEBUG(dev, "ch%d handle=0x%08x\n", channel, handle);
-
-	for (i = 32; i > 0; i -= dev_priv->ramht_bits) {
-		hash ^= (handle & ((1 << dev_priv->ramht_bits) - 1));
-		handle >>= dev_priv->ramht_bits;
-	}
-
-	if (dev_priv->card_type < NV_50)
-		hash ^= channel << (dev_priv->ramht_bits - 4);
-	hash <<= 3;
-
-	NV_DEBUG(dev, "hash=0x%08x\n", hash);
-	return hash;
-}
-
-static int
-nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
-			  uint32_t offset)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t ctx = nv_ro32(dev, ramht, (offset + 4)/4);
-
-	if (dev_priv->card_type < NV_40)
-		return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
-	return (ctx != 0);
-}
-
-static int
-nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-	struct nouveau_channel *chan = ref->channel;
-	struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-	uint32_t ctx, co, ho;
-
-	if (!ramht) {
-		NV_ERROR(dev, "No hash table!\n");
-		return -EINVAL;
-	}
-
-	if (dev_priv->card_type < NV_40) {
-		ctx = NV_RAMHT_CONTEXT_VALID | (ref->instance >> 4) |
-		      (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-		      (ref->gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
-	} else
-	if (dev_priv->card_type < NV_50) {
-		ctx = (ref->instance >> 4) |
-		      (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
-		      (ref->gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
-	} else {
-		if (ref->gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
-			ctx = (ref->instance << 10) | 2;
-		} else {
-			ctx = (ref->instance >> 4) |
-			      ((ref->gpuobj->engine <<
-				NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
-		}
-	}
-
-	co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
-	do {
-		if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
-			NV_DEBUG(dev,
-				 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-				 chan->id, co, ref->handle, ctx);
-			nv_wo32(dev, ramht, (co + 0)/4, ref->handle);
-			nv_wo32(dev, ramht, (co + 4)/4, ctx);
-
-			list_add_tail(&ref->list, &chan->ramht_refs);
-			instmem->flush(dev);
-			return 0;
-		}
-		NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
-			 chan->id, co, nv_ro32(dev, ramht, co/4));
-
-		co += 8;
-		if (co >= dev_priv->ramht_size)
-			co = 0;
-	} while (co != ho);
-
-	NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
-	return -ENOMEM;
-}
-
-static void
-nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
-	struct nouveau_channel *chan = ref->channel;
-	struct nouveau_gpuobj *ramht = chan->ramht ? chan->ramht->gpuobj : NULL;
-	uint32_t co, ho;
-
-	if (!ramht) {
-		NV_ERROR(dev, "No hash table!\n");
-		return;
-	}
-
-	co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
-	do {
-		if (nouveau_ramht_entry_valid(dev, ramht, co) &&
-		    (ref->handle == nv_ro32(dev, ramht, (co/4)))) {
-			NV_DEBUG(dev,
-				 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
-				 chan->id, co, ref->handle,
-				 nv_ro32(dev, ramht, (co + 4)));
-			nv_wo32(dev, ramht, (co + 0)/4, 0x00000000);
-			nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
-
-			list_del(&ref->list);
-			instmem->flush(dev);
-			return;
-		}
-
-		co += 8;
-		if (co >= dev_priv->ramht_size)
-			co = 0;
-	} while (co != ho);
-	list_del(&ref->list);
-
-	NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
-		 chan->id, ref->handle);
-}
 
 int
 nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
@@ -205,7 +75,7 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_engine *engine = &dev_priv->engine;
 	struct nouveau_gpuobj *gpuobj;
-	struct drm_mm *pramin = NULL;
+	struct drm_mm_node *ramin = NULL;
 	int ret;
 
 	NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@@ -218,69 +88,102 @@
 	if (!gpuobj)
 		return -ENOMEM;
 	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
+	gpuobj->dev = dev;
 	gpuobj->flags = flags;
-	gpuobj->im_channel = chan;
+	kref_init(&gpuobj->refcount);
+	gpuobj->size = size;
 
+	spin_lock(&dev_priv->ramin_lock);
 	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+	spin_unlock(&dev_priv->ramin_lock);
 
-	/* Choose between global instmem heap, and per-channel private
-	 * instmem heap.  On <NV50 allow requests for private instmem
-	 * to be satisfied from global heap if no per-channel area
-	 * available.
-	 */
 	if (chan) {
 		NV_DEBUG(dev, "channel heap\n");
-		pramin = &chan->ramin_heap;
+
+		ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0);
+		if (ramin)
+			ramin = drm_mm_get_block(ramin, size, align);
+
+		if (!ramin) {
+			nouveau_gpuobj_ref(NULL, &gpuobj);
+			return -ENOMEM;
+		}
 	} else {
 		NV_DEBUG(dev, "global heap\n");
-		pramin = &dev_priv->ramin_heap;
 
+		/* allocate backing pages, sets vinst */
 		ret = engine->instmem.populate(dev, gpuobj, &size);
 		if (ret) {
-			nouveau_gpuobj_del(dev, &gpuobj);
+			nouveau_gpuobj_ref(NULL, &gpuobj);
 			return ret;
 		}
-	}
 
-	/* Allocate a chunk of the PRAMIN aperture */
-	gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
-	if (gpuobj->im_pramin)
-		gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
+		/* try and get aperture space */
+		do {
+			if (drm_mm_pre_get(&dev_priv->ramin_heap))
+				return -ENOMEM;
 
-	if (!gpuobj->im_pramin) {
-		nouveau_gpuobj_del(dev, &gpuobj);
-		return -ENOMEM;
+			spin_lock(&dev_priv->ramin_lock);
+			ramin = drm_mm_search_free(&dev_priv->ramin_heap, size,
+						   align, 0);
+			if (ramin == NULL) {
+				spin_unlock(&dev_priv->ramin_lock);
+				nouveau_gpuobj_ref(NULL, &gpuobj);
+				return -ENOMEM;
+			}
+
+			ramin = drm_mm_get_block_atomic(ramin, size, align);
+			spin_unlock(&dev_priv->ramin_lock);
+		} while (ramin == NULL);
+
+		/* on nv50 it's ok to fail, we have a fallback path */
+		if (!ramin && dev_priv->card_type < NV_50) {
+			nouveau_gpuobj_ref(NULL, &gpuobj);
+			return -ENOMEM;
+		}
 	}
 
-	if (!chan) {
+	/* if we got a chunk of the aperture, map pages into it */
+	gpuobj->im_pramin = ramin;
+	if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) {
 		ret = engine->instmem.bind(dev, gpuobj);
 		if (ret) {
-			nouveau_gpuobj_del(dev, &gpuobj);
+			nouveau_gpuobj_ref(NULL, &gpuobj);
 			return ret;
 		}
 	}
 
+	/* calculate the various different addresses for the object */
+	if (chan) {
+		gpuobj->pinst = chan->ramin->pinst;
+		if (gpuobj->pinst != ~0)
+			gpuobj->pinst += gpuobj->im_pramin->start;
+
+		if (dev_priv->card_type < NV_50) {
+			gpuobj->cinst = gpuobj->pinst;
+		} else {
+			gpuobj->cinst = gpuobj->im_pramin->start;
+			gpuobj->vinst = gpuobj->im_pramin->start +
+					chan->ramin->vinst;
+		}
+	} else {
+		if (gpuobj->im_pramin)
+			gpuobj->pinst = gpuobj->im_pramin->start;
+		else
+			gpuobj->pinst = ~0;
+		gpuobj->cinst = 0xdeadbeef;
+	}
+
 	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
 		int i;
 
-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-			nv_wo32(dev, gpuobj, i/4, 0);
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, 0);
 		engine->instmem.flush(dev);
 	}
 
-	*gpuobj_ret = gpuobj;
-	return 0;
-}
-
-int
-nouveau_gpuobj_early_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	NV_DEBUG(dev, "\n");
-
-	INIT_LIST_HEAD(&dev_priv->gpuobj_list);
 
+	*gpuobj_ret = gpuobj;
 	return 0;
 }
 
@@ -288,18 +191,12 @@
 nouveau_gpuobj_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int ret;
 
 	NV_DEBUG(dev, "\n");
 
-	if (dev_priv->card_type < NV_50) {
-		ret = nouveau_gpuobj_new_fake(dev,
-			dev_priv->ramht_offset, ~0, dev_priv->ramht_size,
-			NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ALLOW_NO_REFS,
-						&dev_priv->ramht, NULL);
-		if (ret)
-			return ret;
-	}
+	INIT_LIST_HEAD(&dev_priv->gpuobj_list);
+	spin_lock_init(&dev_priv->ramin_lock);
+	dev_priv->ramin_base = ~0;
 
 	return 0;
 }
@@ -311,297 +208,89 @@
 
 	NV_DEBUG(dev, "\n");
 
-	nouveau_gpuobj_del(dev, &dev_priv->ramht);
+	BUG_ON(!list_empty(&dev_priv->gpuobj_list));
 }
 
-void
-nouveau_gpuobj_late_takedown(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *gpuobj = NULL;
-	struct list_head *entry, *tmp;
-
-	NV_DEBUG(dev, "\n");
-
-	list_for_each_safe(entry, tmp, &dev_priv->gpuobj_list) {
-		gpuobj = list_entry(entry, struct nouveau_gpuobj, list);
-
-		NV_ERROR(dev, "gpuobj %p still exists at takedown, refs=%d\n",
-			 gpuobj, gpuobj->refcount);
-		gpuobj->refcount = 0;
-		nouveau_gpuobj_del(dev, &gpuobj);
-	}
-}
 
-int
-nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
+static void
+nouveau_gpuobj_del(struct kref *ref)
 {
+	struct nouveau_gpuobj *gpuobj =
+		container_of(ref, struct nouveau_gpuobj, refcount);
+	struct drm_device *dev = gpuobj->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_engine *engine = &dev_priv->engine;
-	struct nouveau_gpuobj *gpuobj;
 	int i;
 
-	NV_DEBUG(dev, "gpuobj %p\n", pgpuobj ? *pgpuobj : NULL);
-
-	if (!dev_priv || !pgpuobj || !(*pgpuobj))
-		return -EINVAL;
-	gpuobj = *pgpuobj;
-
-	if (gpuobj->refcount != 0) {
-		NV_ERROR(dev, "gpuobj refcount is %d\n", gpuobj->refcount);
-		return -EINVAL;
-	}
+	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
 
 	if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-			nv_wo32(dev, gpuobj, i/4, 0);
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, 0);
 		engine->instmem.flush(dev);
 	}
 
 	if (gpuobj->dtor)
 		gpuobj->dtor(dev, gpuobj);
 
-	if (gpuobj->im_backing && !(gpuobj->flags & NVOBJ_FLAG_FAKE))
+	if (gpuobj->im_backing)
 		engine->instmem.clear(dev, gpuobj);
 
-	if (gpuobj->im_pramin) {
-		if (gpuobj->flags & NVOBJ_FLAG_FAKE)
-			kfree(gpuobj->im_pramin);
-		else
-			drm_mm_put_block(gpuobj->im_pramin);
-	}
-
+	spin_lock(&dev_priv->ramin_lock);
+	if (gpuobj->im_pramin)
+		drm_mm_put_block(gpuobj->im_pramin);
 	list_del(&gpuobj->list);
+	spin_unlock(&dev_priv->ramin_lock);
 
-	*pgpuobj = NULL;
 	kfree(gpuobj);
-	return 0;
-}
-
-static int
-nouveau_gpuobj_instance_get(struct drm_device *dev,
-			    struct nouveau_channel *chan,
-			    struct nouveau_gpuobj *gpuobj, uint32_t *inst)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *cpramin;
-
-	/* <NV50 use PRAMIN address everywhere */
-	if (dev_priv->card_type < NV_50) {
-		*inst = gpuobj->im_pramin->start;
-		return 0;
-	}
-
-	if (chan && gpuobj->im_channel != chan) {
-		NV_ERROR(dev, "Channel mismatch: obj %d, ref %d\n",
-			 gpuobj->im_channel->id, chan->id);
-		return -EINVAL;
-	}
-
-	/* NV50 channel-local instance */
-	if (chan) {
-		cpramin = chan->ramin->gpuobj;
-		*inst = gpuobj->im_pramin->start - cpramin->im_pramin->start;
-		return 0;
-	}
-
-	/* NV50 global (VRAM) instance */
-	if (!gpuobj->im_channel) {
-		/* ...from global heap */
-		if (!gpuobj->im_backing) {
-			NV_ERROR(dev, "AII, no VRAM backing gpuobj\n");
-			return -EINVAL;
-		}
-		*inst = gpuobj->im_backing_start;
-		return 0;
-	} else {
-		/* ...from local heap */
-		cpramin = gpuobj->im_channel->ramin->gpuobj;
-		*inst = cpramin->im_backing_start +
-			(gpuobj->im_pramin->start - cpramin->im_pramin->start);
-		return 0;
-	}
-
-	return -EINVAL;
-}
-
-int
-nouveau_gpuobj_ref_add(struct drm_device *dev, struct nouveau_channel *chan,
-		       uint32_t handle, struct nouveau_gpuobj *gpuobj,
-		       struct nouveau_gpuobj_ref **ref_ret)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj_ref *ref;
-	uint32_t instance;
-	int ret;
-
-	NV_DEBUG(dev, "ch%d h=0x%08x gpuobj=%p\n",
-		 chan ? chan->id : -1, handle, gpuobj);
-
-	if (!dev_priv || !gpuobj || (ref_ret && *ref_ret != NULL))
-		return -EINVAL;
-
-	if (!chan && !ref_ret)
-		return -EINVAL;
-
-	if (gpuobj->engine == NVOBJ_ENGINE_SW && !gpuobj->im_pramin) {
-		/* sw object */
-		instance = 0x40;
-	} else {
-		ret = nouveau_gpuobj_instance_get(dev, chan, gpuobj, &instance);
-		if (ret)
-			return ret;
-	}
-
-	ref = kzalloc(sizeof(*ref), GFP_KERNEL);
-	if (!ref)
-		return -ENOMEM;
-	INIT_LIST_HEAD(&ref->list);
-	ref->gpuobj   = gpuobj;
-	ref->channel  = chan;
-	ref->instance = instance;
-
-	if (!ref_ret) {
-		ref->handle = handle;
-
-		ret = nouveau_ramht_insert(dev, ref);
-		if (ret) {
-			kfree(ref);
-			return ret;
-		}
-	} else {
-		ref->handle = ~0;
-		*ref_ret = ref;
-	}
-
-	ref->gpuobj->refcount++;
-	return 0;
 }
 
-int nouveau_gpuobj_ref_del(struct drm_device *dev, struct nouveau_gpuobj_ref **pref)
-{
-	struct nouveau_gpuobj_ref *ref;
-
-	NV_DEBUG(dev, "ref %p\n", pref ? *pref : NULL);
-
-	if (!dev || !pref || *pref == NULL)
-		return -EINVAL;
-	ref = *pref;
-
-	if (ref->handle != ~0)
-		nouveau_ramht_remove(dev, ref);
-
-	if (ref->gpuobj) {
-		ref->gpuobj->refcount--;
-
-		if (ref->gpuobj->refcount == 0) {
-			if (!(ref->gpuobj->flags & NVOBJ_FLAG_ALLOW_NO_REFS))
-				nouveau_gpuobj_del(dev, &ref->gpuobj);
-		}
-	}
-
-	*pref = NULL;
-	kfree(ref);
-	return 0;
-}
-
-int
-nouveau_gpuobj_new_ref(struct drm_device *dev,
-		       struct nouveau_channel *oc, struct nouveau_channel *rc,
-		       uint32_t handle, uint32_t size, int align,
-		       uint32_t flags, struct nouveau_gpuobj_ref **ref)
-{
-	struct nouveau_gpuobj *gpuobj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, oc, size, align, flags, &gpuobj);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_ref_add(dev, rc, handle, gpuobj, ref);
-	if (ret) {
-		nouveau_gpuobj_del(dev, &gpuobj);
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-nouveau_gpuobj_ref_find(struct nouveau_channel *chan, uint32_t handle,
-			struct nouveau_gpuobj_ref **ref_ret)
+void
+nouveau_gpuobj_ref(struct nouveau_gpuobj *ref, struct nouveau_gpuobj **ptr)
 {
-	struct nouveau_gpuobj_ref *ref;
-	struct list_head *entry, *tmp;
-
-	list_for_each_safe(entry, tmp, &chan->ramht_refs) {
-		ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
+	if (ref)
+		kref_get(&ref->refcount);
 
-		if (ref->handle == handle) {
-			if (ref_ret)
-				*ref_ret = ref;
-			return 0;
-		}
-	}
+	if (*ptr)
+		kref_put(&(*ptr)->refcount, nouveau_gpuobj_del);
 
-	return -EINVAL;
+	*ptr = ref;
 }
 
 int
-nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
-			uint32_t b_offset, uint32_t size,
-			uint32_t flags, struct nouveau_gpuobj **pgpuobj,
-			struct nouveau_gpuobj_ref **pref)
+nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
+			u32 size, u32 flags, struct nouveau_gpuobj **pgpuobj)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_gpuobj *gpuobj = NULL;
 	int i;
 
 	NV_DEBUG(dev,
-		 "p_offset=0x%08x b_offset=0x%08x size=0x%08x flags=0x%08x\n",
-		 p_offset, b_offset, size, flags);
+		 "pinst=0x%08x vinst=0x%010llx size=0x%08x flags=0x%08x\n",
+		 pinst, vinst, size, flags);
 
 	gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
 	if (!gpuobj)
 		return -ENOMEM;
 	NV_DEBUG(dev, "gpuobj %p\n", gpuobj);
-	gpuobj->im_channel = NULL;
-	gpuobj->flags      = flags | NVOBJ_FLAG_FAKE;
-
-	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
-
-	if (p_offset != ~0) {
-		gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
-					    GFP_KERNEL);
-		if (!gpuobj->im_pramin) {
-			nouveau_gpuobj_del(dev, &gpuobj);
-			return -ENOMEM;
-		}
-		gpuobj->im_pramin->start = p_offset;
-		gpuobj->im_pramin->size  = size;
-	}
-
-	if (b_offset != ~0) {
-		gpuobj->im_backing = (struct nouveau_bo *)-1;
-		gpuobj->im_backing_start = b_offset;
-	}
+	gpuobj->dev = dev;
+	gpuobj->flags = flags;
+	kref_init(&gpuobj->refcount);
+	gpuobj->size  = size;
+	gpuobj->pinst = pinst;
+	gpuobj->cinst = 0xdeadbeef;
+	gpuobj->vinst = vinst;
 
 	if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
-		for (i = 0; i < gpuobj->im_pramin->size; i += 4)
-			nv_wo32(dev, gpuobj, i/4, 0);
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, 0);
 		dev_priv->engine.instmem.flush(dev);
 	}
 
-	if (pref) {
-		i = nouveau_gpuobj_ref_add(dev, NULL, 0, gpuobj, pref);
-		if (i) {
-			nouveau_gpuobj_del(dev, &gpuobj);
-			return i;
-		}
-	}
-
-	if (pgpuobj)
-		*pgpuobj = gpuobj;
+	spin_lock(&dev_priv->ramin_lock);
+	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+	spin_unlock(&dev_priv->ramin_lock);
+	*pgpuobj = gpuobj;
 	return 0;
 }
 
@@ -685,14 +374,12 @@
 		adjust = offset &  0x00000fff;
 		frame  = offset & ~0x00000fff;
 
-		nv_wo32(dev, *gpuobj, 0, ((1<<12) | (1<<13) |
-				(adjust << 20) |
-				 (access << 14) |
-				 (target << 16) |
-				  class));
-		nv_wo32(dev, *gpuobj, 1, size - 1);
-		nv_wo32(dev, *gpuobj, 2, frame | pte_flags);
-		nv_wo32(dev, *gpuobj, 3, frame | pte_flags);
+		nv_wo32(*gpuobj,  0, ((1<<12) | (1<<13) | (adjust << 20) |
+				      (access << 14) | (target << 16) |
+				      class));
+		nv_wo32(*gpuobj,  4, size - 1);
+		nv_wo32(*gpuobj,  8, frame | pte_flags);
+		nv_wo32(*gpuobj, 12, frame | pte_flags);
 	} else {
 		uint64_t limit = offset + size - 1;
 		uint32_t flags0, flags5;
@@ -705,12 +392,12 @@
 			flags5 = 0x00080000;
 		}
 
-		nv_wo32(dev, *gpuobj, 0, flags0 | class);
-		nv_wo32(dev, *gpuobj, 1, lower_32_bits(limit));
-		nv_wo32(dev, *gpuobj, 2, lower_32_bits(offset));
-		nv_wo32(dev, *gpuobj, 3, ((upper_32_bits(limit) & 0xff) << 24) |
-					(upper_32_bits(offset) & 0xff));
-		nv_wo32(dev, *gpuobj, 5, flags5);
+		nv_wo32(*gpuobj,  0, flags0 | class);
+		nv_wo32(*gpuobj,  4, lower_32_bits(limit));
+		nv_wo32(*gpuobj,  8, lower_32_bits(offset));
+		nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) |
+				      (upper_32_bits(offset) & 0xff));
+		nv_wo32(*gpuobj, 20, flags5);
 	}
 
 	instmem->flush(dev);
@@ -741,7 +428,7 @@
 			*o_ret = 0;
 	} else
 	if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) {
-		*gpuobj = dev_priv->gart_info.sg_ctxdma;
+		nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj);
 		if (offset & ~0xffffffffULL) {
 			NV_ERROR(dev, "obj offset exceeds 32-bits\n");
 			return -EINVAL;
@@ -829,25 +516,25 @@
 	}
 
 	if (dev_priv->card_type >= NV_50) {
-		nv_wo32(dev, *gpuobj, 0, class);
-		nv_wo32(dev, *gpuobj, 5, 0x00010000);
+		nv_wo32(*gpuobj,  0, class);
+		nv_wo32(*gpuobj, 20, 0x00010000);
 	} else {
 		switch (class) {
 		case NV_CLASS_NULL:
-			nv_wo32(dev, *gpuobj, 0, 0x00001030);
-			nv_wo32(dev, *gpuobj, 1, 0xFFFFFFFF);
+			nv_wo32(*gpuobj, 0, 0x00001030);
+			nv_wo32(*gpuobj, 4, 0xFFFFFFFF);
 			break;
 		default:
 			if (dev_priv->card_type >= NV_40) {
-				nv_wo32(dev, *gpuobj, 0, class);
+				nv_wo32(*gpuobj, 0, class);
 #ifdef __BIG_ENDIAN
-				nv_wo32(dev, *gpuobj, 2, 0x01000000);
+				nv_wo32(*gpuobj, 8, 0x01000000);
 #endif
 			} else {
 #ifdef __BIG_ENDIAN
-				nv_wo32(dev, *gpuobj, 0, class | 0x00080000);
+				nv_wo32(*gpuobj, 0, class | 0x00080000);
 #else
-				nv_wo32(dev, *gpuobj, 0, class);
+				nv_wo32(*gpuobj, 0, class);
 #endif
 			}
 		}
@@ -873,10 +560,15 @@
 	gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
 	if (!gpuobj)
 		return -ENOMEM;
+	gpuobj->dev = chan->dev;
 	gpuobj->engine = NVOBJ_ENGINE_SW;
 	gpuobj->class = class;
+	kref_init(&gpuobj->refcount);
+	gpuobj->cinst = 0x40;
 
+	spin_lock(&dev_priv->ramin_lock);
 	list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
+	spin_unlock(&dev_priv->ramin_lock);
 	*gpuobj_ret = gpuobj;
 	return 0;
 }
@@ -886,7 +578,6 @@
 {
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *pramin = NULL;
 	uint32_t size;
 	uint32_t base;
 	int ret;
@@ -911,18 +602,16 @@
 		size += 0x1000;
 	}
 
-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
-				     &chan->ramin);
+	ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
 	if (ret) {
 		NV_ERROR(dev, "Error allocating channel PRAMIN: %d\n", ret);
 		return ret;
 	}
-	pramin = chan->ramin->gpuobj;
 
-	ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
+	ret = drm_mm_init(&chan->ramin_heap, base, size);
 	if (ret) {
 		NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
+		nouveau_gpuobj_ref(NULL, &chan->ramin);
 		return ret;
 	}
 
@@ -939,8 +628,6 @@
 	struct nouveau_gpuobj *vram = NULL, *tt = NULL;
 	int ret, i;
 
-	INIT_LIST_HEAD(&chan->ramht_refs);
-
 	NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
 
 	/* Allocate a chunk of memory for per-channel object storage */
@@ -956,41 +643,38 @@
 	 *    locations determined during init.
 	 */
 	if (dev_priv->card_type >= NV_50) {
-		uint32_t vm_offset, pde;
+		u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+		u64 vm_vinst = chan->ramin->vinst + pgd_offs;
+		u32 vm_pinst = chan->ramin->pinst;
+		u32 pde;
 
-		vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
-		vm_offset += chan->ramin->gpuobj->im_pramin->start;
+		if (vm_pinst != ~0)
+			vm_pinst += pgd_offs;
 
-		ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
-							0, &chan->vm_pd, NULL);
+		ret = nouveau_gpuobj_new_fake(dev, vm_pinst, vm_vinst, 0x4000,
+					      0, &chan->vm_pd);
 		if (ret)
 			return ret;
 		for (i = 0; i < 0x4000; i += 8) {
-			nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
-			nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
+			nv_wo32(chan->vm_pd, i + 0, 0x00000000);
+			nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe);
 		}
 
-		pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 2;
-		ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
-					     dev_priv->gart_info.sg_ctxdma,
-					     &chan->vm_gart_pt);
-		if (ret)
-			return ret;
-		nv_wo32(dev, chan->vm_pd, pde++,
-			    chan->vm_gart_pt->instance | 0x03);
-		nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+		nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma,
+				   &chan->vm_gart_pt);
+		pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8;
+		nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3);
+		nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
 
-		pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 2;
+		pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8;
 		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-			ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
-						     dev_priv->vm_vram_pt[i],
-						     &chan->vm_vram_pt[i]);
-			if (ret)
-				return ret;
+			nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i],
+					   &chan->vm_vram_pt[i]);
 
-			nv_wo32(dev, chan->vm_pd, pde++,
-				    chan->vm_vram_pt[i]->instance | 0x61);
-			nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
+			nv_wo32(chan->vm_pd, pde + 0,
+				chan->vm_vram_pt[i]->vinst | 0x61);
+			nv_wo32(chan->vm_pd, pde + 4, 0x00000000);
+			pde += 8;
 		}
 
 		instmem->flush(dev);
@@ -998,15 +682,17 @@
 
 	/* RAMHT */
 	if (dev_priv->card_type < NV_50) {
-		ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->ramht,
-					     &chan->ramht);
+		nouveau_ramht_ref(dev_priv->ramht, &chan->ramht, NULL);
+	} else {
+		struct nouveau_gpuobj *ramht = NULL;
+
+		ret = nouveau_gpuobj_new(dev, chan, 0x8000, 16,
+					 NVOBJ_FLAG_ZERO_ALLOC, &ramht);
 		if (ret)
 			return ret;
-	} else {
-		ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0,
-					     0x8000, 16,
-					     NVOBJ_FLAG_ZERO_ALLOC,
-					     &chan->ramht);
+
+		ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+		nouveau_gpuobj_ref(NULL, &ramht);
 		if (ret)
 			return ret;
 	}
@@ -1023,24 +709,32 @@
 		}
 	} else {
 		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
-						0, dev_priv->fb_available_size,
-						NV_DMA_ACCESS_RW,
-						NV_DMA_TARGET_VIDMEM, &vram);
+					     0, dev_priv->fb_available_size,
+					     NV_DMA_ACCESS_RW,
+					     NV_DMA_TARGET_VIDMEM, &vram);
 		if (ret) {
 			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
 			return ret;
 		}
 	}
 
-	ret = nouveau_gpuobj_ref_add(dev, chan, vram_h, vram, NULL);
+	ret = nouveau_ramht_insert(chan, vram_h, vram);
+	nouveau_gpuobj_ref(NULL, &vram);
 	if (ret) {
-		NV_ERROR(dev, "Error referencing VRAM ctxdma: %d\n", ret);
+		NV_ERROR(dev, "Error adding VRAM ctxdma to RAMHT: %d\n", ret);
 		return ret;
 	}
 
 	/* TT memory ctxdma */
 	if (dev_priv->card_type >= NV_50) {
-		tt = vram;
+		ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+					     0, dev_priv->vm_end,
+					     NV_DMA_ACCESS_RW,
+					     NV_DMA_TARGET_AGP, &tt);
+		if (ret) {
+			NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret);
+			return ret;
+		}
 	} else
 	if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) {
 		ret = nouveau_gpuobj_gart_dma_new(chan, 0,
@@ -1056,9 +750,10 @@
 		return ret;
 	}
 
-	ret = nouveau_gpuobj_ref_add(dev, chan, tt_h, tt, NULL);
+	ret = nouveau_ramht_insert(chan, tt_h, tt);
+	nouveau_gpuobj_ref(NULL, &tt);
 	if (ret) {
-		NV_ERROR(dev, "Error referencing TT ctxdma: %d\n", ret);
+		NV_ERROR(dev, "Error adding TT ctxdma to RAMHT: %d\n", ret);
 		return ret;
 	}
 
@@ -1070,33 +765,23 @@
 {
 	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
 	struct drm_device *dev = chan->dev;
-	struct list_head *entry, *tmp;
-	struct nouveau_gpuobj_ref *ref;
 	int i;
 
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
-	if (!chan->ramht_refs.next)
+	if (!chan->ramht)
 		return;
 
-	list_for_each_safe(entry, tmp, &chan->ramht_refs) {
-		ref = list_entry(entry, struct nouveau_gpuobj_ref, list);
-
-		nouveau_gpuobj_ref_del(dev, &ref);
-	}
-
-	nouveau_gpuobj_ref_del(dev, &chan->ramht);
+	nouveau_ramht_ref(NULL, &chan->ramht, chan);
 
-	nouveau_gpuobj_del(dev, &chan->vm_pd);
-	nouveau_gpuobj_ref_del(dev, &chan->vm_gart_pt);
+	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+	nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt);
 	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
-		nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
+		nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
 
 	if (chan->ramin_heap.free_stack.next)
 		drm_mm_takedown(&chan->ramin_heap);
-	if (chan->ramin)
-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
-
+	nouveau_gpuobj_ref(NULL, &chan->ramin);
 }
 
 int
@@ -1117,17 +802,17 @@
 	}
 
 	list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) {
-		if (!gpuobj->im_backing || (gpuobj->flags & NVOBJ_FLAG_FAKE))
+		if (!gpuobj->im_backing)
 			continue;
 
-		gpuobj->im_backing_suspend = vmalloc(gpuobj->im_pramin->size);
+		gpuobj->im_backing_suspend = vmalloc(gpuobj->size);
 		if (!gpuobj->im_backing_suspend) {
 			nouveau_gpuobj_resume(dev);
 			return -ENOMEM;
 		}
 
-		for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
-			gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
+		for (i = 0; i < gpuobj->size; i += 4)
+			gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i);
 	}
 
 	return 0;
@@ -1172,8 +857,8 @@
 		if (!gpuobj->im_backing_suspend)
 			continue;
 
-		for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
-			nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
+		for (i = 0; i < gpuobj->size; i += 4)
+			nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]);
 		dev_priv->engine.instmem.flush(dev);
 	}
 
@@ -1208,25 +893,24 @@
 		return -EPERM;
 	}
 
-	if (nouveau_gpuobj_ref_find(chan, init->handle, NULL) == 0)
+	if (nouveau_ramht_find(chan, init->handle))
 		return -EEXIST;
 
 	if (!grc->software)
 		ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr);
 	else
 		ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr);
-
 	if (ret) {
 		NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n",
 			 ret, init->channel, init->handle);
 		return ret;
 	}
 
-	ret = nouveau_gpuobj_ref_add(dev, chan, init->handle, gr, NULL);
+	ret = nouveau_ramht_insert(chan, init->handle, gr);
+	nouveau_gpuobj_ref(NULL, &gr);
 	if (ret) {
 		NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n",
 			 ret, init->channel, init->handle);
-		nouveau_gpuobj_del(dev, &gr);
 		return ret;
 	}
 
@@ -1237,16 +921,62 @@
 			      struct drm_file *file_priv)
 {
 	struct drm_nouveau_gpuobj_free *objfree = data;
-	struct nouveau_gpuobj_ref *ref;
+	struct nouveau_gpuobj *gpuobj;
 	struct nouveau_channel *chan;
-	int ret;
 
 	NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
 
-	ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);
-	if (ret)
-		return ret;
-	nouveau_gpuobj_ref_del(dev, &ref);
+	gpuobj = nouveau_ramht_find(chan, objfree->handle);
+	if (!gpuobj)
+		return -ENOENT;
 
+	nouveau_ramht_remove(chan, objfree->handle);
 	return 0;
 }
+
+u32
+nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset)
+{
+	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+	struct drm_device *dev = gpuobj->dev;
+
+	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+		u64  ptr = gpuobj->vinst + offset;
+		u32 base = ptr >> 16;
+		u32  val;
+
+		spin_lock(&dev_priv->ramin_lock);
+		if (dev_priv->ramin_base != base) {
+			dev_priv->ramin_base = base;
+			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+		}
+		val = nv_rd32(dev, 0x700000 + (ptr & 0xffff));
+		spin_unlock(&dev_priv->ramin_lock);
+		return val;
+	}
+
+	return nv_ri32(dev, gpuobj->pinst + offset);
+}
+
+void
+nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val)
+{
+	struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private;
+	struct drm_device *dev = gpuobj->dev;
+
+	if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) {
+		u64  ptr = gpuobj->vinst + offset;
+		u32 base = ptr >> 16;
+
+		spin_lock(&dev_priv->ramin_lock);
+		if (dev_priv->ramin_base != base) {
+			dev_priv->ramin_base = base;
+			nv_wr32(dev, 0x001700, dev_priv->ramin_base);
+		}
+		nv_wr32(dev, 0x700000 + (ptr & 0xffff), val);
+		spin_unlock(&dev_priv->ramin_lock);
+		return;
+	}
+
+	nv_wi32(dev, gpuobj->pinst + offset, val);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_perf.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_perf.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_perf.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_perf.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010 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_pm.h"
+
+static void
+legacy_perf_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	char *perf, *entry, *bmp = &bios->data[bios->offset];
+	int headerlen, use_straps;
+
+	if (bmp[5] < 0x5 || bmp[6] < 0x14) {
+		NV_DEBUG(dev, "BMP version too old for perf\n");
+		return;
+	}
+
+	perf = ROMPTR(bios, bmp[0x73]);
+	if (!perf) {
+		NV_DEBUG(dev, "No memclock table pointer found.\n");
+		return;
+	}
+
+	switch (perf[0]) {
+	case 0x12:
+	case 0x14:
+	case 0x18:
+		use_straps = 0;
+		headerlen = 1;
+		break;
+	case 0x01:
+		use_straps = perf[1] & 1;
+		headerlen = (use_straps ? 8 : 2);
+		break;
+	default:
+		NV_WARN(dev, "Unknown memclock table version %x.\n", perf[0]);
+		return;
+	}
+
+	entry = perf + headerlen;
+	if (use_straps)
+		entry += (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x3c) >> 1;
+
+	sprintf(pm->perflvl[0].name, "performance_level_0");
+	pm->perflvl[0].memory = ROM16(entry[0]) * 20;
+	pm->nr_perflvl = 1;
+}
+
+void
+nouveau_perf_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct bit_entry P;
+	u8 version, headerlen, recordlen, entries;
+	u8 *perf, *entry;
+	int vid, i;
+
+	if (bios->type == NVBIOS_BIT) {
+		if (bit_table(dev, 'P', &P))
+			return;
+
+		if (P.version != 1 && P.version != 2) {
+			NV_WARN(dev, "unknown perf for BIT P %d\n", P.version);
+			return;
+		}
+
+		perf = ROMPTR(bios, P.data[0]);
+		version   = perf[0];
+		headerlen = perf[1];
+		if (version < 0x40) {
+			recordlen = perf[3] + (perf[4] * perf[5]);
+			entries   = perf[2];
+		} else {
+			recordlen = perf[2] + (perf[3] * perf[4]);
+			entries   = perf[5];
+		}
+	} else {
+		if (bios->data[bios->offset + 6] < 0x25) {
+			legacy_perf_init(dev);
+			return;
+		}
+
+		perf = ROMPTR(bios, bios->data[bios->offset + 0x94]);
+		if (!perf) {
+			NV_DEBUG(dev, "perf table pointer invalid\n");
+			return;
+		}
+
+		version   = perf[1];
+		headerlen = perf[0];
+		recordlen = perf[3];
+		entries   = perf[2];
+	}
+
+	entry = perf + headerlen;
+	for (i = 0; i < entries; i++) {
+		struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+
+		if (entry[0] == 0xff) {
+			entry += recordlen;
+			continue;
+		}
+
+		switch (version) {
+		case 0x12:
+		case 0x13:
+		case 0x15:
+			perflvl->fanspeed = entry[55];
+			perflvl->voltage = entry[56];
+			perflvl->core = ROM32(entry[1]) * 10;
+			perflvl->memory = ROM32(entry[5]) * 20;
+			break;
+		case 0x21:
+		case 0x23:
+		case 0x24:
+			perflvl->fanspeed = entry[4];
+			perflvl->voltage = entry[5];
+			perflvl->core = ROM16(entry[6]) * 1000;
+
+			if (dev_priv->chipset == 0x49 ||
+			    dev_priv->chipset == 0x4b)
+				perflvl->memory = ROM16(entry[11]) * 1000;
+			else
+				perflvl->memory = ROM16(entry[11]) * 2000;
+
+			break;
+		case 0x25:
+			perflvl->fanspeed = entry[4];
+			perflvl->voltage = entry[5];
+			perflvl->core = ROM16(entry[6]) * 1000;
+			perflvl->shader = ROM16(entry[10]) * 1000;
+			perflvl->memory = ROM16(entry[12]) * 1000;
+			break;
+		case 0x30:
+			perflvl->memscript = ROM16(entry[2]);
+		case 0x35:
+			perflvl->fanspeed = entry[6];
+			perflvl->voltage = entry[7];
+			perflvl->core = ROM16(entry[8]) * 1000;
+			perflvl->shader = ROM16(entry[10]) * 1000;
+			perflvl->memory = ROM16(entry[12]) * 1000;
+			/*XXX: confirm on 0x35 */
+			perflvl->unk05 = ROM16(entry[16]) * 1000;
+			break;
+		case 0x40:
+#define subent(n) entry[perf[2] + ((n) * perf[3])]
+			perflvl->fanspeed = 0; /*XXX*/
+			perflvl->voltage = entry[2];
+			perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
+			perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
+			perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+			break;
+		}
+
+		/* make sure vid is valid */
+		if (pm->voltage.supported && perflvl->voltage) {
+			vid = nouveau_volt_vid_lookup(dev, perflvl->voltage);
+			if (vid < 0) {
+				NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i);
+				entry += recordlen;
+				continue;
+			}
+		}
+
+		snprintf(perflvl->name, sizeof(perflvl->name),
+			 "performance_level_%d", i);
+		perflvl->id = i;
+		pm->nr_perflvl++;
+
+		entry += recordlen;
+	}
+}
+
+void
+nouveau_perf_fini(struct drm_device *dev)
+{
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_pm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_pm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2010 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_pm.h"
+
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+static int
+nouveau_pm_clock_set(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+		     u8 id, u32 khz)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	void *pre_state;
+
+	if (khz == 0)
+		return 0;
+
+	pre_state = pm->clock_pre(dev, perflvl, id, khz);
+	if (IS_ERR(pre_state))
+		return PTR_ERR(pre_state);
+
+	if (pre_state)
+		pm->clock_set(dev, pre_state);
+	return 0;
+}
+
+static int
+nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	int ret;
+
+	if (perflvl == pm->cur)
+		return 0;
+
+	if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
+		ret = pm->voltage_set(dev, perflvl->voltage);
+		if (ret) {
+			NV_ERROR(dev, "voltage_set %d failed: %d\n",
+				 perflvl->voltage, 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);
+
+	pm->cur = perflvl;
+	return 0;
+}
+
+static int
+nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_level *perflvl = NULL;
+
+	/* safety precaution, for now */
+	if (nouveau_perflvl_wr != 7777)
+		return -EPERM;
+
+	if (!pm->clock_set)
+		return -EINVAL;
+
+	if (!strncmp(profile, "boot", 4))
+		perflvl = &pm->boot;
+	else {
+		int pl = simple_strtol(profile, NULL, 10);
+		int i;
+
+		for (i = 0; i < pm->nr_perflvl; i++) {
+			if (pm->perflvl[i].id == pl) {
+				perflvl = &pm->perflvl[i];
+				break;
+			}
+		}
+
+		if (!perflvl)
+			return -EINVAL;
+	}
+
+	NV_INFO(dev, "setting performance level: %s\n", profile);
+	return nouveau_pm_perflvl_set(dev, perflvl);
+}
+
+static int
+nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	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;
+
+	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_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;
+	}
+
+	return 0;
+}
+
+static void
+nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
+{
+	char c[16], s[16], v[16], f[16];
+
+	c[0] = '\0';
+	if (perflvl->core)
+		snprintf(c, sizeof(c), " core %dMHz", perflvl->core / 1000);
+
+	s[0] = '\0';
+	if (perflvl->shader)
+		snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000);
+
+	v[0] = '\0';
+	if (perflvl->voltage)
+		snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10);
+
+	f[0] = '\0';
+	if (perflvl->fanspeed)
+		snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
+
+	snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
+		 c, s, v, f);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl_info(struct device *d,
+			    struct device_attribute *a, char *buf)
+{
+	struct nouveau_pm_level *perflvl = (struct nouveau_pm_level *)a;
+	char *ptr = buf;
+	int len = PAGE_SIZE;
+
+	snprintf(ptr, len, "%d: ", perflvl->id);
+	ptr += strlen(buf);
+	len -= strlen(buf);
+
+	nouveau_pm_perflvl_info(perflvl, ptr, len);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_level cur;
+	int len = PAGE_SIZE, ret;
+	char *ptr = buf;
+
+	if (!pm->cur)
+		snprintf(ptr, len, "setting: boot\n");
+	else if (pm->cur == &pm->boot)
+		snprintf(ptr, len, "setting: boot\nc: ");
+	else
+		snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id);
+	ptr += strlen(buf);
+	len -= strlen(buf);
+
+	ret = nouveau_pm_perflvl_get(dev, &cur);
+	if (ret == 0)
+		nouveau_pm_perflvl_info(&cur, ptr, len);
+	return strlen(buf);
+}
+
+static ssize_t
+nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
+		       const char *buf, size_t count)
+{
+	struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
+	int ret;
+
+	ret = nouveau_pm_profile_set(dev, buf);
+	if (ret)
+		return ret;
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
+		   nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
+
+static int
+nouveau_sysfs_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct device *d = &dev->pdev->dev;
+	int ret, i;
+
+	ret = device_create_file(d, &dev_attr_performance_level);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < pm->nr_perflvl; i++) {
+		struct nouveau_pm_level *perflvl = &pm->perflvl[i];
+
+		perflvl->dev_attr.attr.name = perflvl->name;
+		perflvl->dev_attr.attr.mode = S_IRUGO;
+		perflvl->dev_attr.show = nouveau_pm_get_perflvl_info;
+		perflvl->dev_attr.store = NULL;
+		sysfs_attr_init(&perflvl->dev_attr.attr);
+
+		ret = device_create_file(d, &perflvl->dev_attr);
+		if (ret) {
+			NV_ERROR(dev, "failed pervlvl %d sysfs: %d\n",
+				 perflvl->id, i);
+			perflvl->dev_attr.attr.name = NULL;
+			nouveau_pm_fini(dev);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void
+nouveau_sysfs_fini(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct device *d = &dev->pdev->dev;
+	int i;
+
+	device_remove_file(d, &dev_attr_performance_level);
+	for (i = 0; i < pm->nr_perflvl; i++) {
+		struct nouveau_pm_level *pl = &pm->perflvl[i];
+
+		if (!pl->dev_attr.attr.name)
+			break;
+
+		device_remove_file(d, &pl->dev_attr);
+	}
+}
+
+#ifdef CONFIG_HWMON
+static ssize_t
+nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = dev_get_drvdata(d);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
+						  NULL, 0);
+
+static ssize_t
+nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
+{
+	struct drm_device *dev = dev_get_drvdata(d);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
+}
+static ssize_t
+nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
+						const char *buf, size_t count)
+{
+	struct drm_device *dev = dev_get_drvdata(d);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+	long value;
+
+	if (strict_strtol(buf, 10, &value) == -EINVAL)
+		return count;
+
+	temp->down_clock = value/1000;
+
+	nouveau_temp_safety_checks(dev);
+
+	return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
+						  nouveau_hwmon_set_max_temp,
+						  0);
+
+static ssize_t
+nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
+							char *buf)
+{
+	struct drm_device *dev = dev_get_drvdata(d);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
+}
+static ssize_t
+nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
+							    const char *buf,
+								size_t count)
+{
+	struct drm_device *dev = dev_get_drvdata(d);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
+	long value;
+
+	if (strict_strtol(buf, 10, &value) == -EINVAL)
+		return count;
+
+	temp->critical = value/1000;
+
+	nouveau_temp_safety_checks(dev);
+
+	return count;
+}
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
+						nouveau_hwmon_critical_temp,
+						nouveau_hwmon_set_critical_temp,
+						0);
+
+static ssize_t nouveau_hwmon_show_name(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return sprintf(buf, "nouveau\n");
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
+
+static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return sprintf(buf, "1000\n");
+}
+static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
+						nouveau_hwmon_show_update_rate,
+						NULL, 0);
+
+static struct attribute *hwmon_attributes[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_name.dev_attr.attr,
+	&sensor_dev_attr_update_rate.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group hwmon_attrgroup = {
+	.attrs = hwmon_attributes,
+};
+#endif
+
+static int
+nouveau_hwmon_init(struct drm_device *dev)
+{
+#ifdef CONFIG_HWMON
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct device *hwmon_dev;
+	int ret;
+
+	if (!pm->temp_get)
+		return -ENODEV;
+
+	hwmon_dev = hwmon_device_register(&dev->pdev->dev);
+	if (IS_ERR(hwmon_dev)) {
+		ret = PTR_ERR(hwmon_dev);
+		NV_ERROR(dev,
+			"Unable to register hwmon device: %d\n", ret);
+		return ret;
+	}
+	dev_set_drvdata(hwmon_dev, dev);
+	ret = sysfs_create_group(&hwmon_dev->kobj,
+					&hwmon_attrgroup);
+	if (ret) {
+		NV_ERROR(dev,
+			"Unable to create hwmon sysfs file: %d\n", ret);
+		hwmon_device_unregister(hwmon_dev);
+		return ret;
+	}
+
+	pm->hwmon = hwmon_dev;
+#endif
+	return 0;
+}
+
+static void
+nouveau_hwmon_fini(struct drm_device *dev)
+{
+#ifdef CONFIG_HWMON
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+	if (pm->hwmon) {
+		sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
+		hwmon_device_unregister(pm->hwmon);
+	}
+#endif
+}
+
+int
+nouveau_pm_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	char info[256];
+	int ret, i;
+
+	nouveau_volt_init(dev);
+	nouveau_perf_init(dev);
+	nouveau_temp_init(dev);
+	nouveau_mem_timing_init(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);
+	}
+
+	/* determine current ("boot") performance level */
+	ret = nouveau_pm_perflvl_get(dev, &pm->boot);
+	if (ret == 0) {
+		pm->cur = &pm->boot;
+
+		nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
+		NV_INFO(dev, "c: %s", info);
+	}
+
+	/* switch performance levels now if requested */
+	if (nouveau_perflvl != NULL) {
+		ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
+		if (ret) {
+			NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
+				 nouveau_perflvl, ret);
+		}
+	}
+
+	nouveau_sysfs_init(dev);
+	nouveau_hwmon_init(dev);
+
+	return 0;
+}
+
+void
+nouveau_pm_fini(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+
+	if (pm->cur != &pm->boot)
+		nouveau_pm_perflvl_set(dev, &pm->boot);
+
+	nouveau_mem_timing_fini(dev);
+	nouveau_temp_fini(dev);
+	nouveau_perf_fini(dev);
+	nouveau_volt_fini(dev);
+
+	nouveau_hwmon_fini(dev);
+	nouveau_sysfs_fini(dev);
+}
+
+void
+nouveau_pm_resume(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_level *perflvl;
+
+	if (pm->cur == &pm->boot)
+		return;
+
+	perflvl = pm->cur;
+	pm->cur = &pm->boot;
+	nouveau_pm_perflvl_set(dev, perflvl);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_pm.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_pm.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_pm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_pm.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 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
+ */
+
+#ifndef __NOUVEAU_PM_H__
+#define __NOUVEAU_PM_H__
+
+/* nouveau_pm.c */
+int  nouveau_pm_init(struct drm_device *dev);
+void nouveau_pm_fini(struct drm_device *dev);
+void nouveau_pm_resume(struct drm_device *dev);
+
+/* nouveau_volt.c */
+void nouveau_volt_init(struct drm_device *);
+void nouveau_volt_fini(struct drm_device *);
+int  nouveau_volt_vid_lookup(struct drm_device *, int voltage);
+int  nouveau_volt_lvl_lookup(struct drm_device *, int vid);
+int  nouveau_voltage_gpio_get(struct drm_device *);
+int  nouveau_voltage_gpio_set(struct drm_device *, int voltage);
+
+/* nouveau_perf.c */
+void nouveau_perf_init(struct drm_device *);
+void nouveau_perf_fini(struct drm_device *);
+
+/* nouveau_mem.c */
+void nouveau_mem_timing_init(struct drm_device *);
+void nouveau_mem_timing_fini(struct drm_device *);
+
+/* nv04_pm.c */
+int nv04_pm_clock_get(struct drm_device *, u32 id);
+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 *);
+
+/* 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 *,
+			u32 id, int khz);
+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 *);
+
+/* nouveau_temp.c */
+void nouveau_temp_init(struct drm_device *dev);
+void nouveau_temp_fini(struct drm_device *dev);
+void nouveau_temp_safety_checks(struct drm_device *dev);
+int nv40_temp_get(struct drm_device *dev);
+int nv84_temp_get(struct drm_device *dev);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2010 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"
+
+static u32
+nouveau_ramht_hash_handle(struct nouveau_channel *chan, u32 handle)
+{
+	struct drm_device *dev = chan->dev;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_ramht *ramht = chan->ramht;
+	u32 hash = 0;
+	int i;
+
+	NV_DEBUG(dev, "ch%d handle=0x%08x\n", chan->id, handle);
+
+	for (i = 32; i > 0; i -= ramht->bits) {
+		hash ^= (handle & ((1 << ramht->bits) - 1));
+		handle >>= ramht->bits;
+	}
+
+	if (dev_priv->card_type < NV_50)
+		hash ^= chan->id << (ramht->bits - 4);
+	hash <<= 3;
+
+	NV_DEBUG(dev, "hash=0x%08x\n", hash);
+	return hash;
+}
+
+static int
+nouveau_ramht_entry_valid(struct drm_device *dev, struct nouveau_gpuobj *ramht,
+			  u32 offset)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 ctx = nv_ro32(ramht, offset + 4);
+
+	if (dev_priv->card_type < NV_40)
+		return ((ctx & NV_RAMHT_CONTEXT_VALID) != 0);
+	return (ctx != 0);
+}
+
+static int
+nouveau_ramht_entry_same_channel(struct nouveau_channel *chan,
+				 struct nouveau_gpuobj *ramht, u32 offset)
+{
+	struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+	u32 ctx = nv_ro32(ramht, offset + 4);
+
+	if (dev_priv->card_type >= NV_50)
+		return true;
+	else if (dev_priv->card_type >= NV_40)
+		return chan->id ==
+			((ctx >> NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+	else
+		return chan->id ==
+			((ctx >> NV_RAMHT_CONTEXT_CHANNEL_SHIFT) & 0x1f);
+}
+
+int
+nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
+		     struct nouveau_gpuobj *gpuobj)
+{
+	struct drm_device *dev = chan->dev;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+	struct nouveau_ramht_entry *entry;
+	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+	unsigned long flags;
+	u32 ctx, co, ho;
+
+	if (nouveau_ramht_find(chan, handle))
+		return -EEXIST;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+	entry->channel = chan;
+	entry->gpuobj = NULL;
+	entry->handle = handle;
+	nouveau_gpuobj_ref(gpuobj, &entry->gpuobj);
+
+	if (dev_priv->card_type < NV_40) {
+		ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) |
+		      (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+		      (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT);
+	} else
+	if (dev_priv->card_type < NV_50) {
+		ctx = (gpuobj->cinst >> 4) |
+		      (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) |
+		      (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT);
+	} else {
+		if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) {
+			ctx = (gpuobj->cinst << 10) | 2;
+		} else {
+			ctx = (gpuobj->cinst >> 4) |
+			      ((gpuobj->engine <<
+				NV40_RAMHT_CONTEXT_ENGINE_SHIFT));
+		}
+	}
+
+	spin_lock_irqsave(&chan->ramht->lock, flags);
+	list_add(&entry->head, &chan->ramht->entries);
+
+	co = ho = nouveau_ramht_hash_handle(chan, handle);
+	do {
+		if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
+			NV_DEBUG(dev,
+				 "insert ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+				 chan->id, co, handle, ctx);
+			nv_wo32(ramht, co + 0, handle);
+			nv_wo32(ramht, co + 4, ctx);
+
+			spin_unlock_irqrestore(&chan->ramht->lock, flags);
+			instmem->flush(dev);
+			return 0;
+		}
+		NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
+			 chan->id, co, nv_ro32(ramht, co));
+
+		co += 8;
+		if (co >= ramht->size)
+			co = 0;
+	} while (co != ho);
+
+	NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
+	list_del(&entry->head);
+	spin_unlock_irqrestore(&chan->ramht->lock, flags);
+	kfree(entry);
+	return -ENOMEM;
+}
+
+static struct nouveau_ramht_entry *
+nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
+{
+	struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
+	struct nouveau_ramht_entry *entry;
+	unsigned long flags;
+
+	if (!ramht)
+		return NULL;
+
+	spin_lock_irqsave(&ramht->lock, flags);
+	list_for_each_entry(entry, &ramht->entries, head) {
+		if (entry->channel == chan &&
+		    (!handle || entry->handle == handle)) {
+			list_del(&entry->head);
+			spin_unlock_irqrestore(&ramht->lock, flags);
+
+			return entry;
+		}
+	}
+	spin_unlock_irqrestore(&ramht->lock, flags);
+
+	return NULL;
+}
+
+static void
+nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
+{
+	struct drm_device *dev = chan->dev;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
+	struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
+	unsigned long flags;
+	u32 co, ho;
+
+	spin_lock_irqsave(&chan->ramht->lock, flags);
+	co = ho = nouveau_ramht_hash_handle(chan, handle);
+	do {
+		if (nouveau_ramht_entry_valid(dev, ramht, co) &&
+		    nouveau_ramht_entry_same_channel(chan, ramht, co) &&
+		    (handle == nv_ro32(ramht, co))) {
+			NV_DEBUG(dev,
+				 "remove ch%d 0x%08x: h=0x%08x, c=0x%08x\n",
+				 chan->id, co, handle, nv_ro32(ramht, co + 4));
+			nv_wo32(ramht, co + 0, 0x00000000);
+			nv_wo32(ramht, co + 4, 0x00000000);
+			instmem->flush(dev);
+			goto out;
+		}
+
+		co += 8;
+		if (co >= ramht->size)
+			co = 0;
+	} while (co != ho);
+
+	NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
+		 chan->id, handle);
+out:
+	spin_unlock_irqrestore(&chan->ramht->lock, flags);
+}
+
+void
+nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
+{
+	struct nouveau_ramht_entry *entry;
+
+	entry = nouveau_ramht_remove_entry(chan, handle);
+	if (!entry)
+		return;
+
+	nouveau_ramht_remove_hash(chan, entry->handle);
+	nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+	kfree(entry);
+}
+
+struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle)
+{
+	struct nouveau_ramht *ramht = chan->ramht;
+	struct nouveau_ramht_entry *entry;
+	struct nouveau_gpuobj *gpuobj = NULL;
+	unsigned long flags;
+
+	if (unlikely(!chan->ramht))
+		return NULL;
+
+	spin_lock_irqsave(&ramht->lock, flags);
+	list_for_each_entry(entry, &chan->ramht->entries, head) {
+		if (entry->channel == chan && entry->handle == handle) {
+			gpuobj = entry->gpuobj;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&ramht->lock, flags);
+
+	return gpuobj;
+}
+
+int
+nouveau_ramht_new(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+		  struct nouveau_ramht **pramht)
+{
+	struct nouveau_ramht *ramht;
+
+	ramht = kzalloc(sizeof(*ramht), GFP_KERNEL);
+	if (!ramht)
+		return -ENOMEM;
+
+	ramht->dev = dev;
+	kref_init(&ramht->refcount);
+	ramht->bits = drm_order(gpuobj->size / 8);
+	INIT_LIST_HEAD(&ramht->entries);
+	spin_lock_init(&ramht->lock);
+	nouveau_gpuobj_ref(gpuobj, &ramht->gpuobj);
+
+	*pramht = ramht;
+	return 0;
+}
+
+static void
+nouveau_ramht_del(struct kref *ref)
+{
+	struct nouveau_ramht *ramht =
+		container_of(ref, struct nouveau_ramht, refcount);
+
+	nouveau_gpuobj_ref(NULL, &ramht->gpuobj);
+	kfree(ramht);
+}
+
+void
+nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
+		  struct nouveau_channel *chan)
+{
+	struct nouveau_ramht_entry *entry;
+	struct nouveau_ramht *ramht;
+
+	if (ref)
+		kref_get(&ref->refcount);
+
+	ramht = *ptr;
+	if (ramht) {
+		while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
+			nouveau_ramht_remove_hash(chan, entry->handle);
+			nouveau_gpuobj_ref(NULL, &entry->gpuobj);
+			kfree(entry);
+		}
+
+		kref_put(&ramht->refcount, nouveau_ramht_del);
+	}
+	*ptr = ref;
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_ramht.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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
+ */
+
+#ifndef __NOUVEAU_RAMHT_H__
+#define __NOUVEAU_RAMHT_H__
+
+struct nouveau_ramht_entry {
+	struct list_head head;
+	struct nouveau_channel *channel;
+	struct nouveau_gpuobj *gpuobj;
+	u32 handle;
+};
+
+struct nouveau_ramht {
+	struct drm_device *dev;
+	struct kref refcount;
+	spinlock_t lock;
+	struct nouveau_gpuobj *gpuobj;
+	struct list_head entries;
+	int bits;
+};
+
+extern int  nouveau_ramht_new(struct drm_device *, struct nouveau_gpuobj *,
+			      struct nouveau_ramht **);
+extern void nouveau_ramht_ref(struct nouveau_ramht *, struct nouveau_ramht **,
+			      struct nouveau_channel *unref_channel);
+
+extern int  nouveau_ramht_insert(struct nouveau_channel *, u32 handle,
+				 struct nouveau_gpuobj *);
+extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle);
+extern struct nouveau_gpuobj *
+nouveau_ramht_find(struct nouveau_channel *chan, u32 handle);
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_reg.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_reg.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_reg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_reg.h	2011-01-04 19:50:19.000000000 -0500
@@ -551,6 +551,8 @@
 #define NV10_PFIFO_CACHE1_DMA_SUBROUTINE                   0x0000324C
 #define NV03_PFIFO_CACHE1_PULL0                            0x00003240
 #define NV04_PFIFO_CACHE1_PULL0                            0x00003250
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED            0x00000010
+#    define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY              0x00001000
 #define NV03_PFIFO_CACHE1_PULL1                            0x00003250
 #define NV04_PFIFO_CACHE1_PULL1                            0x00003254
 #define NV04_PFIFO_CACHE1_HASH                             0x00003258
@@ -785,15 +787,12 @@
 #define NV50_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
 #define NV50_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610b70 + (i) * 0x8)
 #define NV50_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610b74 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_P(i)                (0x00610b80 + (i) * 0x8)
+#define NV50_PDISPLAY_EXT_MODE_CTRL_C(i)                (0x00610b84 + (i) * 0x8)
 #define NV50_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610bdc + (i) * 0x8)
 #define NV50_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610be0 + (i) * 0x8)
-
 #define NV90_PDISPLAY_SOR_MODE_CTRL_P(i)                (0x00610794 + (i) * 0x8)
 #define NV90_PDISPLAY_SOR_MODE_CTRL_C(i)                (0x00610798 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_P(i)                (0x00610b58 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL_C(i)                (0x00610b5c + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_P(i)               (0x00610b80 + (i) * 0x8)
-#define NV90_PDISPLAY_DAC_MODE_CTRL2_C(i)               (0x00610b84 + (i) * 0x8)
 
 #define NV50_PDISPLAY_CRTC_CLK                                       0x00614000
 #define NV50_PDISPLAY_CRTC_CLK_CTRL1(i)                 ((i) * 0x800 + 0x614100)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_sgdma.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_sgdma.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_sgdma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_sgdma.c	2011-01-04 19:50:19.000000000 -0500
@@ -95,9 +95,9 @@
 	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
 	unsigned i, j, pte;
 
-	NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
+	NV_DEBUG(dev, "pg=0x%lx\n", mem->start);
 
-	pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
+	pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT);
 	nvbe->pte_start = pte;
 	for (i = 0; i < nvbe->nr_pages; i++) {
 		dma_addr_t dma_offset = nvbe->pages[i];
@@ -105,11 +105,13 @@
 		uint32_t offset_h = upper_32_bits(dma_offset);
 
 		for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
-			if (dev_priv->card_type < NV_50)
-				nv_wo32(dev, gpuobj, pte++, offset_l | 3);
-			else {
-				nv_wo32(dev, gpuobj, pte++, offset_l | 0x21);
-				nv_wo32(dev, gpuobj, pte++, offset_h & 0xff);
+			if (dev_priv->card_type < NV_50) {
+				nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
+				pte += 1;
+			} else {
+				nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21);
+				nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff);
+				pte += 2;
 			}
 
 			dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -118,8 +120,8 @@
 	dev_priv->engine.instmem.flush(nvbe->dev);
 
 	if (dev_priv->card_type == NV_50) {
-		nv50_vm_flush(dev, 5); /* PGRAPH */
-		nv50_vm_flush(dev, 0); /* PFIFO */
+		dev_priv->engine.fifo.tlb_flush(dev);
+		dev_priv->engine.graph.tlb_flush(dev);
 	}
 
 	nvbe->bound = true;
@@ -145,11 +147,13 @@
 		dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
 
 		for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) {
-			if (dev_priv->card_type < NV_50)
-				nv_wo32(dev, gpuobj, pte++, dma_offset | 3);
-			else {
-				nv_wo32(dev, gpuobj, pte++, dma_offset | 0x21);
-				nv_wo32(dev, gpuobj, pte++, 0x00000000);
+			if (dev_priv->card_type < NV_50) {
+				nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3);
+				pte += 1;
+			} else {
+				nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000);
+				nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000);
+				pte += 2;
 			}
 
 			dma_offset += NV_CTXDMA_PAGE_SIZE;
@@ -158,8 +162,8 @@
 	dev_priv->engine.instmem.flush(nvbe->dev);
 
 	if (dev_priv->card_type == NV_50) {
-		nv50_vm_flush(dev, 5);
-		nv50_vm_flush(dev, 0);
+		dev_priv->engine.fifo.tlb_flush(dev);
+		dev_priv->engine.graph.tlb_flush(dev);
 	}
 
 	nvbe->bound = false;
@@ -220,7 +224,11 @@
 	int i, ret;
 
 	if (dev_priv->card_type < NV_50) {
-		aper_size = (64 * 1024 * 1024);
+		if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
+			aper_size = 64 * 1024 * 1024;
+		else
+			aper_size = 512 * 1024 * 1024;
+
 		obj_size  = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
 		obj_size += 8; /* ctxdma header */
 	} else {
@@ -230,7 +238,6 @@
 	}
 
 	ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16,
-				      NVOBJ_FLAG_ALLOW_NO_REFS |
 				      NVOBJ_FLAG_ZERO_ALLOC |
 				      NVOBJ_FLAG_ZERO_FREE, &gpuobj);
 	if (ret) {
@@ -239,9 +246,9 @@
 	}
 
 	dev_priv->gart_info.sg_dummy_page =
-		alloc_page(GFP_KERNEL|__GFP_DMA32);
+		alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO);
 	if (!dev_priv->gart_info.sg_dummy_page) {
-		nouveau_gpuobj_del(dev, &gpuobj);
+		nouveau_gpuobj_ref(NULL, &gpuobj);
 		return -ENOMEM;
 	}
 
@@ -250,29 +257,34 @@
 		pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0,
 			     PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 	if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) {
-		nouveau_gpuobj_del(dev, &gpuobj);
+		nouveau_gpuobj_ref(NULL, &gpuobj);
 		return -EFAULT;
 	}
 
 	if (dev_priv->card_type < NV_50) {
+		/* special case, allocated from global instmem heap so
+		 * cinst is invalid, we use it on all channels though so
+		 * cinst needs to be valid, set it the same as pinst
+		 */
+		gpuobj->cinst = gpuobj->pinst;
+
 		/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
 		 * confirmed to work on c51.  Perhaps means NV_DMA_TARGET_PCIE
 		 * on those cards? */
-		nv_wo32(dev, gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
-				       (1 << 12) /* PT present */ |
-				       (0 << 13) /* PT *not* linear */ |
-				       (NV_DMA_ACCESS_RW  << 14) |
-				       (NV_DMA_TARGET_PCI << 16));
-		nv_wo32(dev, gpuobj, 1, aper_size - 1);
+		nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY |
+				   (1 << 12) /* PT present */ |
+				   (0 << 13) /* PT *not* linear */ |
+				   (NV_DMA_ACCESS_RW  << 14) |
+				   (NV_DMA_TARGET_PCI << 16));
+		nv_wo32(gpuobj, 4, aper_size - 1);
 		for (i = 2; i < 2 + (aper_size >> 12); i++) {
-			nv_wo32(dev, gpuobj, i,
-				    dev_priv->gart_info.sg_dummy_bus | 3);
+			nv_wo32(gpuobj, i * 4,
+				dev_priv->gart_info.sg_dummy_bus | 3);
 		}
 	} else {
 		for (i = 0; i < obj_size; i += 8) {
-			nv_wo32(dev, gpuobj, (i+0)/4,
-				    dev_priv->gart_info.sg_dummy_bus | 0x21);
-			nv_wo32(dev, gpuobj, (i+4)/4, 0);
+			nv_wo32(gpuobj, i + 0, 0x00000000);
+			nv_wo32(gpuobj, i + 4, 0x00000000);
 		}
 	}
 	dev_priv->engine.instmem.flush(dev);
@@ -298,7 +310,7 @@
 		dev_priv->gart_info.sg_dummy_bus = 0;
 	}
 
-	nouveau_gpuobj_del(dev, &dev_priv->gart_info.sg_ctxdma);
+	nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma);
 }
 
 int
@@ -308,9 +320,9 @@
 	struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
 	int pte;
 
-	pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
+	pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2;
 	if (dev_priv->card_type < NV_50) {
-		*page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
+		*page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK;
 		return 0;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_state.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_state.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_state.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_state.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,6 +35,8 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
+#include "nouveau_pm.h"
 #include "nv50_display.h"
 
 static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -78,7 +80,6 @@
 		engine->fifo.disable		= nv04_fifo_disable;
 		engine->fifo.enable		= nv04_fifo_enable;
 		engine->fifo.reassign		= nv04_fifo_reassign;
-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
 		engine->fifo.channel_id		= nv04_fifo_channel_id;
 		engine->fifo.create_context	= nv04_fifo_create_context;
@@ -95,6 +96,9 @@
 		engine->gpio.get		= NULL;
 		engine->gpio.set		= NULL;
 		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;
 		break;
 	case 0x10:
 		engine->instmem.init		= nv04_instmem_init;
@@ -130,7 +134,6 @@
 		engine->fifo.disable		= nv04_fifo_disable;
 		engine->fifo.enable		= nv04_fifo_enable;
 		engine->fifo.reassign		= nv04_fifo_reassign;
-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
 		engine->fifo.channel_id		= nv10_fifo_channel_id;
 		engine->fifo.create_context	= nv10_fifo_create_context;
@@ -147,6 +150,9 @@
 		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;
 		break;
 	case 0x20:
 		engine->instmem.init		= nv04_instmem_init;
@@ -182,7 +188,6 @@
 		engine->fifo.disable		= nv04_fifo_disable;
 		engine->fifo.enable		= nv04_fifo_enable;
 		engine->fifo.reassign		= nv04_fifo_reassign;
-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
 		engine->fifo.channel_id		= nv10_fifo_channel_id;
 		engine->fifo.create_context	= nv10_fifo_create_context;
@@ -199,6 +204,9 @@
 		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;
 		break;
 	case 0x30:
 		engine->instmem.init		= nv04_instmem_init;
@@ -234,7 +242,6 @@
 		engine->fifo.disable		= nv04_fifo_disable;
 		engine->fifo.enable		= nv04_fifo_enable;
 		engine->fifo.reassign		= nv04_fifo_reassign;
-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
 		engine->fifo.channel_id		= nv10_fifo_channel_id;
 		engine->fifo.create_context	= nv10_fifo_create_context;
@@ -251,6 +258,11 @@
 		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.voltage_get		= nouveau_voltage_gpio_get;
+		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
 		break;
 	case 0x40:
 	case 0x60:
@@ -287,7 +299,6 @@
 		engine->fifo.disable		= nv04_fifo_disable;
 		engine->fifo.enable		= nv04_fifo_enable;
 		engine->fifo.reassign		= nv04_fifo_reassign;
-		engine->fifo.cache_flush	= nv04_fifo_cache_flush;
 		engine->fifo.cache_pull		= nv04_fifo_cache_pull;
 		engine->fifo.channel_id		= nv10_fifo_channel_id;
 		engine->fifo.create_context	= nv40_fifo_create_context;
@@ -304,6 +315,12 @@
 		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.voltage_get		= nouveau_voltage_gpio_get;
+		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
+		engine->pm.temp_get		= nv40_temp_get;
 		break;
 	case 0x50:
 	case 0x80: /* gotta love NVIDIA's consistency.. */
@@ -337,6 +354,15 @@
 		engine->graph.destroy_context	= nv50_graph_destroy_context;
 		engine->graph.load_context	= nv50_graph_load_context;
 		engine->graph.unload_context	= nv50_graph_unload_context;
+		if (dev_priv->chipset != 0x86)
+			engine->graph.tlb_flush	= nv50_graph_tlb_flush;
+		else {
+			/* from what i can see nvidia do this on every
+			 * pre-NVA3 board except NVAC, but, we've only
+			 * ever seen problems on NV86
+			 */
+			engine->graph.tlb_flush	= nv86_graph_tlb_flush;
+		}
 		engine->fifo.channels		= 128;
 		engine->fifo.init		= nv50_fifo_init;
 		engine->fifo.takedown		= nv50_fifo_takedown;
@@ -348,6 +374,7 @@
 		engine->fifo.destroy_context	= nv50_fifo_destroy_context;
 		engine->fifo.load_context	= nv50_fifo_load_context;
 		engine->fifo.unload_context	= nv50_fifo_unload_context;
+		engine->fifo.tlb_flush		= nv50_fifo_tlb_flush;
 		engine->display.early_init	= nv50_display_early_init;
 		engine->display.late_takedown	= nv50_display_late_takedown;
 		engine->display.create		= nv50_display_create;
@@ -358,6 +385,27 @@
 		engine->gpio.get		= nv50_gpio_get;
 		engine->gpio.set		= nv50_gpio_set;
 		engine->gpio.irq_enable		= nv50_gpio_irq_enable;
+		switch (dev_priv->chipset) {
+		case 0xa3:
+		case 0xa5:
+		case 0xa8:
+		case 0xaf:
+			engine->pm.clock_get	= nva3_pm_clock_get;
+			engine->pm.clock_pre	= nva3_pm_clock_pre;
+			engine->pm.clock_set	= nva3_pm_clock_set;
+			break;
+		default:
+			engine->pm.clock_get	= nv50_pm_clock_get;
+			engine->pm.clock_pre	= nv50_pm_clock_pre;
+			engine->pm.clock_set	= nv50_pm_clock_set;
+			break;
+		}
+		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
+		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
+		if (dev_priv->chipset >= 0x84)
+			engine->pm.temp_get	= nv84_temp_get;
+		else
+			engine->pm.temp_get	= nv40_temp_get;
 		break;
 	case 0xC0:
 		engine->instmem.init		= nvc0_instmem_init;
@@ -437,16 +485,14 @@
 nouveau_card_init_channel(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *gpuobj;
+	struct nouveau_gpuobj *gpuobj = NULL;
 	int ret;
 
 	ret = nouveau_channel_alloc(dev, &dev_priv->channel,
-				    (struct drm_file *)-2,
-				    NvDmaFB, NvDmaTT);
+				    (struct drm_file *)-2, NvDmaFB, NvDmaTT);
 	if (ret)
 		return ret;
 
-	gpuobj = NULL;
 	ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
 				     0, dev_priv->vram_size,
 				     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
@@ -454,26 +500,25 @@
 	if (ret)
 		goto out_err;
 
-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
-				     gpuobj, NULL);
+	ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj);
+	nouveau_gpuobj_ref(NULL, &gpuobj);
 	if (ret)
 		goto out_err;
 
-	gpuobj = NULL;
 	ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
 					  dev_priv->gart_info.aper_size,
 					  NV_DMA_ACCESS_RW, &gpuobj, NULL);
 	if (ret)
 		goto out_err;
 
-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
-				     gpuobj, NULL);
+	ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj);
+	nouveau_gpuobj_ref(NULL, &gpuobj);
 	if (ret)
 		goto out_err;
 
 	return 0;
+
 out_err:
-	nouveau_gpuobj_del(dev, &gpuobj);
 	nouveau_channel_free(dev_priv->channel);
 	dev_priv->channel = NULL;
 	return ret;
@@ -534,35 +579,28 @@
 	if (ret)
 		goto out_display_early;
 
-	ret = nouveau_mem_detect(dev);
+	nouveau_pm_init(dev);
+
+	ret = nouveau_mem_vram_init(dev);
 	if (ret)
 		goto out_bios;
 
-	ret = nouveau_gpuobj_early_init(dev);
+	ret = nouveau_gpuobj_init(dev);
 	if (ret)
-		goto out_bios;
+		goto out_vram;
 
-	/* Initialise instance memory, must happen before mem_init so we
-	 * know exactly how much VRAM we're able to use for "normal"
-	 * purposes.
-	 */
 	ret = engine->instmem.init(dev);
 	if (ret)
-		goto out_gpuobj_early;
+		goto out_gpuobj;
 
-	/* Setup the memory manager */
-	ret = nouveau_mem_init(dev);
+	ret = nouveau_mem_gart_init(dev);
 	if (ret)
 		goto out_instmem;
 
-	ret = nouveau_gpuobj_init(dev);
-	if (ret)
-		goto out_mem;
-
 	/* PMC */
 	ret = engine->mc.init(dev);
 	if (ret)
-		goto out_gpuobj;
+		goto out_gart;
 
 	/* PGPIO */
 	ret = engine->gpio.init(dev);
@@ -611,9 +649,13 @@
 	/* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
 	if (!engine->graph.accel_blocked) {
-		ret = nouveau_card_init_channel(dev);
+		ret = nouveau_fence_init(dev);
 		if (ret)
 			goto out_irq;
+
+		ret = nouveau_card_init_channel(dev);
+		if (ret)
+			goto out_fence;
 	}
 
 	ret = nouveau_backlight_init(dev);
@@ -624,6 +666,8 @@
 	drm_kms_helper_poll_init(dev);
 	return 0;
 
+out_fence:
+	nouveau_fence_fini(dev);
 out_irq:
 	drm_irq_uninstall(dev);
 out_display:
@@ -642,16 +686,16 @@
 	engine->gpio.takedown(dev);
 out_mc:
 	engine->mc.takedown(dev);
-out_gpuobj:
-	nouveau_gpuobj_takedown(dev);
-out_mem:
-	nouveau_sgdma_takedown(dev);
-	nouveau_mem_close(dev);
+out_gart:
+	nouveau_mem_gart_fini(dev);
 out_instmem:
 	engine->instmem.takedown(dev);
-out_gpuobj_early:
-	nouveau_gpuobj_late_takedown(dev);
+out_gpuobj:
+	nouveau_gpuobj_takedown(dev);
+out_vram:
+	nouveau_mem_vram_fini(dev);
 out_bios:
+	nouveau_pm_fini(dev);
 	nouveau_bios_takedown(dev);
 out_display_early:
 	engine->display.late_takedown(dev);
@@ -667,7 +711,8 @@
 
 	nouveau_backlight_exit(dev);
 
-	if (dev_priv->channel) {
+	if (!engine->graph.accel_blocked) {
+		nouveau_fence_fini(dev);
 		nouveau_channel_free(dev_priv->channel);
 		dev_priv->channel = NULL;
 	}
@@ -686,15 +731,15 @@
 	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
 	ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
 	mutex_unlock(&dev->struct_mutex);
-	nouveau_sgdma_takedown(dev);
+	nouveau_mem_gart_fini(dev);
 
-	nouveau_gpuobj_takedown(dev);
-	nouveau_mem_close(dev);
 	engine->instmem.takedown(dev);
+	nouveau_gpuobj_takedown(dev);
+	nouveau_mem_vram_fini(dev);
 
 	drm_irq_uninstall(dev);
 
-	nouveau_gpuobj_late_takedown(dev);
+	nouveau_pm_fini(dev);
 	nouveau_bios_takedown(dev);
 
 	vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -1006,6 +1051,9 @@
 	case NOUVEAU_GETPARAM_PTIMER_TIME:
 		getparam->value = dev_priv->engine.timer.read(dev);
 		break;
+	case NOUVEAU_GETPARAM_HAS_BO_USAGE:
+		getparam->value = 1;
+		break;
 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
 		/* NV40 and NV50 versions are quite different, but register
 		 * address is the same. User is supposed to know the card
@@ -1016,7 +1064,7 @@
 		}
 		/* FALLTHRU */
 	default:
-		NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
+		NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
 		return -EINVAL;
 	}
 
@@ -1031,7 +1079,7 @@
 
 	switch (setparam->param) {
 	default:
-		NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
+		NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);
 		return -EINVAL;
 	}
 
@@ -1057,7 +1105,7 @@
 /* Waits for PGRAPH to go completely idle */
 bool nouveau_wait_for_idle(struct drm_device *dev)
 {
-	if (!nv_wait(NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
+	if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) {
 		NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n",
 			 nv_rd32(dev, NV04_PGRAPH_STATUS));
 		return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_temp.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_temp.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_temp.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_temp.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2010 PathScale 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: Martin Peres
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_pm.h"
+
+static void
+nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+	struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+	int i, headerlen, recordlen, entries;
+
+	if (!temp) {
+		NV_DEBUG(dev, "temperature table pointer invalid\n");
+		return;
+	}
+
+	/* Set the default sensor's contants */
+	sensor->offset_constant = 0;
+	sensor->offset_mult = 1;
+	sensor->offset_div = 1;
+	sensor->slope_mult = 1;
+	sensor->slope_div = 1;
+
+	/* Set the default temperature thresholds */
+	temps->critical = 110;
+	temps->down_clock = 100;
+	temps->fan_boost = 90;
+
+	/* Set the known default values to setup the temperature sensor */
+	if (dev_priv->card_type >= NV_40) {
+		switch (dev_priv->chipset) {
+		case 0x43:
+			sensor->offset_mult = 32060;
+			sensor->offset_div = 1000;
+			sensor->slope_mult = 792;
+			sensor->slope_div = 1000;
+			break;
+
+		case 0x44:
+		case 0x47:
+		case 0x4a:
+			sensor->offset_mult = 27839;
+			sensor->offset_div = 1000;
+			sensor->slope_mult = 780;
+			sensor->slope_div = 1000;
+			break;
+
+		case 0x46:
+			sensor->offset_mult = -24775;
+			sensor->offset_div = 100;
+			sensor->slope_mult = 467;
+			sensor->slope_div = 10000;
+			break;
+
+		case 0x49:
+			sensor->offset_mult = -25051;
+			sensor->offset_div = 100;
+			sensor->slope_mult = 458;
+			sensor->slope_div = 10000;
+			break;
+
+		case 0x4b:
+			sensor->offset_mult = -24088;
+			sensor->offset_div = 100;
+			sensor->slope_mult = 442;
+			sensor->slope_div = 10000;
+			break;
+
+		case 0x50:
+			sensor->offset_mult = -22749;
+			sensor->offset_div = 100;
+			sensor->slope_mult = 431;
+			sensor->slope_div = 10000;
+			break;
+		}
+	}
+
+	headerlen = temp[1];
+	recordlen = temp[2];
+	entries = temp[3];
+	temp = temp + headerlen;
+
+	/* Read the entries from the table */
+	for (i = 0; i < entries; i++) {
+		u16 value = ROM16(temp[1]);
+
+		switch (temp[0]) {
+		case 0x01:
+			if ((value & 0x8f) == 0)
+				sensor->offset_constant = (value >> 9) & 0x7f;
+			break;
+
+		case 0x04:
+			if ((value & 0xf00f) == 0xa000) /* core */
+				temps->critical = (value&0x0ff0) >> 4;
+			break;
+
+		case 0x07:
+			if ((value & 0xf00f) == 0xa000) /* core */
+				temps->down_clock = (value&0x0ff0) >> 4;
+			break;
+
+		case 0x08:
+			if ((value & 0xf00f) == 0xa000) /* core */
+				temps->fan_boost = (value&0x0ff0) >> 4;
+			break;
+
+		case 0x10:
+			sensor->offset_mult = value;
+			break;
+
+		case 0x11:
+			sensor->offset_div = value;
+			break;
+
+		case 0x12:
+			sensor->slope_mult = value;
+			break;
+
+		case 0x13:
+			sensor->slope_div = value;
+			break;
+		}
+		temp += recordlen;
+	}
+
+	nouveau_temp_safety_checks(dev);
+}
+
+static int
+nv40_sensor_setup(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+	u32 offset = sensor->offset_mult / sensor->offset_div;
+	u32 sensor_calibration;
+
+	/* set up the sensors */
+	sensor_calibration = 120 - offset - sensor->offset_constant;
+	sensor_calibration = sensor_calibration * sensor->slope_div /
+				sensor->slope_mult;
+
+	if (dev_priv->chipset >= 0x46)
+		sensor_calibration |= 0x80000000;
+	else
+		sensor_calibration |= 0x10000000;
+
+	nv_wr32(dev, 0x0015b0, sensor_calibration);
+
+	/* Wait for the sensor to update */
+	msleep(5);
+
+	/* read */
+	return nv_rd32(dev, 0x0015b4) & 0x1fff;
+}
+
+int
+nv40_temp_get(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
+	int offset = sensor->offset_mult / sensor->offset_div;
+	int core_temp;
+
+	if (dev_priv->card_type >= NV_50) {
+		core_temp = nv_rd32(dev, 0x20008);
+	} else {
+		core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
+		/* Setup the sensor if the temperature is 0 */
+		if (core_temp == 0)
+			core_temp = nv40_sensor_setup(dev);
+	}
+
+	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+	core_temp = core_temp + offset + sensor->offset_constant;
+
+	return core_temp;
+}
+
+int
+nv84_temp_get(struct drm_device *dev)
+{
+	return nv_rd32(dev, 0x20400);
+}
+
+void
+nouveau_temp_safety_checks(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
+
+	if (temps->critical > 120)
+		temps->critical = 120;
+	else if (temps->critical < 80)
+		temps->critical = 80;
+
+	if (temps->down_clock > 110)
+		temps->down_clock = 110;
+	else if (temps->down_clock < 60)
+		temps->down_clock = 60;
+
+	if (temps->fan_boost > 100)
+		temps->fan_boost = 100;
+	else if (temps->fan_boost < 40)
+		temps->fan_boost = 40;
+}
+
+static bool
+probe_monitoring_device(struct nouveau_i2c_chan *i2c,
+			struct i2c_board_info *info)
+{
+	char modalias[16] = "i2c:";
+	struct i2c_client *client;
+
+	strlcat(modalias, info->type, sizeof(modalias));
+	request_module(modalias);
+
+	client = i2c_new_device(&i2c->adapter, info);
+	if (!client)
+		return false;
+
+	if (!client->driver || client->driver->detect(client, info)) {
+		i2c_unregister_device(client);
+		return false;
+	}
+
+	return true;
+}
+
+static void
+nouveau_temp_probe_i2c(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct dcb_table *dcb = &dev_priv->vbios.dcb;
+	struct i2c_board_info info[] = {
+		{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
+		{ I2C_BOARD_INFO("w83781d", 0x2d) },
+		{ I2C_BOARD_INFO("f75375", 0x2e) },
+		{ I2C_BOARD_INFO("adt7473", 0x2e) },
+		{ I2C_BOARD_INFO("lm99", 0x4c) },
+		{ }
+	};
+	int idx = (dcb->version >= 0x40 ?
+		   dcb->i2c_default_indices & 0xf : 2);
+
+	nouveau_i2c_identify(dev, "monitoring device", info,
+			     probe_monitoring_device, idx);
+}
+
+void
+nouveau_temp_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct bit_entry P;
+	u8 *temp = NULL;
+
+	if (bios->type == NVBIOS_BIT) {
+		if (bit_table(dev, 'P', &P))
+			return;
+
+		if (P.version == 1)
+			temp = ROMPTR(bios, P.data[12]);
+		else if (P.version == 2)
+			temp = ROMPTR(bios, P.data[16]);
+		else
+			NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
+
+		nouveau_temp_vbios_parse(dev, temp);
+	}
+
+	nouveau_temp_probe_i2c(dev);
+}
+
+void
+nouveau_temp_fini(struct drm_device *dev)
+{
+
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_volt.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_volt.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nouveau_volt.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nouveau_volt.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2010 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_pm.h"
+
+static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a };
+static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]);
+
+int
+nouveau_voltage_gpio_get(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+	u8 vid = 0;
+	int i;
+
+	for (i = 0; i < nr_vidtag; i++) {
+		if (!(volt->vid_mask & (1 << i)))
+			continue;
+
+		vid |= gpio->get(dev, vidtag[i]) << i;
+	}
+
+	return nouveau_volt_lvl_lookup(dev, vid);
+}
+
+int
+nouveau_voltage_gpio_set(struct drm_device *dev, int voltage)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
+	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+	int vid, i;
+
+	vid = nouveau_volt_vid_lookup(dev, voltage);
+	if (vid < 0)
+		return vid;
+
+	for (i = 0; i < nr_vidtag; i++) {
+		if (!(volt->vid_mask & (1 << i)))
+			continue;
+
+		gpio->set(dev, vidtag[i], !!(vid & (1 << i)));
+	}
+
+	return 0;
+}
+
+int
+nouveau_volt_vid_lookup(struct drm_device *dev, int voltage)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+	int i;
+
+	for (i = 0; i < volt->nr_level; i++) {
+		if (volt->level[i].voltage == voltage)
+			return volt->level[i].vid;
+	}
+
+	return -ENOENT;
+}
+
+int
+nouveau_volt_lvl_lookup(struct drm_device *dev, int vid)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+	int i;
+
+	for (i = 0; i < volt->nr_level; i++) {
+		if (volt->level[i].vid == vid)
+			return volt->level[i].voltage;
+	}
+
+	return -ENOENT;
+}
+
+void
+nouveau_volt_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+	struct nouveau_pm_voltage *voltage = &pm->voltage;
+	struct nvbios *bios = &dev_priv->vbios;
+	struct bit_entry P;
+	u8 *volt = NULL, *entry;
+	int i, headerlen, recordlen, entries, vidmask, vidshift;
+
+	if (bios->type == NVBIOS_BIT) {
+		if (bit_table(dev, 'P', &P))
+			return;
+
+		if (P.version == 1)
+			volt = ROMPTR(bios, P.data[16]);
+		else
+		if (P.version == 2)
+			volt = ROMPTR(bios, P.data[12]);
+		else {
+			NV_WARN(dev, "unknown volt for BIT P %d\n", P.version);
+		}
+	} else {
+		if (bios->data[bios->offset + 6] < 0x27) {
+			NV_DEBUG(dev, "BMP version too old for voltage\n");
+			return;
+		}
+
+		volt = ROMPTR(bios, bios->data[bios->offset + 0x98]);
+	}
+
+	if (!volt) {
+		NV_DEBUG(dev, "voltage table pointer invalid\n");
+		return;
+	}
+
+	switch (volt[0]) {
+	case 0x10:
+	case 0x11:
+	case 0x12:
+		headerlen = 5;
+		recordlen = volt[1];
+		entries   = volt[2];
+		vidshift  = 0;
+		vidmask   = volt[4];
+		break;
+	case 0x20:
+		headerlen = volt[1];
+		recordlen = volt[3];
+		entries   = volt[2];
+		vidshift  = 0; /* could be vidshift like 0x30? */
+		vidmask   = volt[5];
+		break;
+	case 0x30:
+		headerlen = volt[1];
+		recordlen = volt[2];
+		entries   = volt[3];
+		vidshift  = hweight8(volt[5]);
+		vidmask   = volt[4];
+		break;
+	default:
+		NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
+		return;
+	}
+
+	/* validate vid mask */
+	voltage->vid_mask = vidmask;
+	if (!voltage->vid_mask)
+		return;
+
+	i = 0;
+	while (vidmask) {
+		if (i > nr_vidtag) {
+			NV_DEBUG(dev, "vid bit %d unknown\n", i);
+			return;
+		}
+
+		if (!nouveau_bios_gpio_entry(dev, vidtag[i])) {
+			NV_DEBUG(dev, "vid bit %d has no gpio tag\n", i);
+			return;
+		}
+
+		vidmask >>= 1;
+		i++;
+	}
+
+	/* parse vbios entries into common format */
+	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;
+	}
+	voltage->nr_level  = entries;
+	voltage->supported = true;
+}
+
+void
+nouveau_volt_fini(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pm_voltage *volt = &dev_priv->engine.pm.voltage;
+
+	kfree(volt->level);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_crtc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_crtc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_crtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_crtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 #include "nouveau_fb.h"
 #include "nouveau_hw.h"
 #include "nvreg.h"
+#include "nouveau_fbcon.h"
 
 static int
 nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@ -109,7 +110,7 @@
 	struct nouveau_pll_vals *pv = &regp->pllvals;
 	struct pll_lims pll_lim;
 
-	if (get_pll_limits(dev, nv_crtc->index ? VPLL2 : VPLL1, &pll_lim))
+	if (get_pll_limits(dev, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, &pll_lim))
 		return;
 
 	/* NM2 == 0 is used to determine single stage mode on two stage plls */
@@ -157,7 +158,6 @@
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
-	struct drm_connector *connector;
 	unsigned char seq1 = 0, crtc17 = 0;
 	unsigned char crtc1A;
 
@@ -212,10 +212,6 @@
 	NVVgaSeqReset(dev, nv_crtc->index, false);
 
 	NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
-
-	/* Update connector polling modes */
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-		nouveau_connector_set_polling(connector);
 }
 
 static bool
@@ -718,6 +714,7 @@
 
 	drm_crtc_cleanup(crtc);
 
+	nouveau_bo_unmap(nv_crtc->cursor.nvbo);
 	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
 	kfree(nv_crtc);
 }
@@ -768,8 +765,9 @@
 }
 
 static int
-nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
-			struct drm_framebuffer *old_fb)
+nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
+			   struct drm_framebuffer *passed_fb,
+			   int x, int y, bool atomic)
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
@@ -780,13 +778,26 @@
 	int arb_burst, arb_lwm;
 	int ret;
 
-	ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
-	if (ret)
-		return ret;
+	/* If atomic, we want to switch to the fb we were passed, so
+	 * now we update pointers to do that.  (We don't pin; just
+	 * assume we're already pinned and update the base address.)
+	 */
+	if (atomic) {
+		drm_fb = passed_fb;
+		fb = nouveau_framebuffer(passed_fb);
+	}
+	else {
+		/* If not atomic, we can go ahead and pin, and unpin the
+		 * old fb we were passed.
+		 */
+		ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+		if (ret)
+			return ret;
 
-	if (old_fb) {
-		struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
-		nouveau_bo_unpin(ofb->nvbo);
+		if (passed_fb) {
+			struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+			nouveau_bo_unpin(ofb->nvbo);
+		}
 	}
 
 	nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -815,7 +826,7 @@
 	/* Update the framebuffer location. */
 	regp->fb_start = nv_crtc->fb.offset & ~3;
 	regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
-	NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
+	nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
 
 	/* Update the arbitration parameters. */
 	nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
@@ -826,7 +837,7 @@
 	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FF_INDEX);
 	crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_FFLWM__INDEX);
 
-	if (dev_priv->card_type >= NV_30) {
+	if (dev_priv->card_type >= NV_20) {
 		regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8;
 		crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_47);
 	}
@@ -834,6 +845,29 @@
 	return 0;
 }
 
+static int
+nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+			struct drm_framebuffer *old_fb)
+{
+	return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false);
+}
+
+static int
+nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+			       struct drm_framebuffer *fb,
+			       int x, int y, enum mode_set_atomic state)
+{
+	struct drm_nouveau_private *dev_priv = crtc->dev->dev_private;
+	struct drm_device *dev = dev_priv->dev;
+
+	if (state == ENTER_ATOMIC_MODE_SET)
+		nouveau_fbcon_save_disable_accel(dev);
+	else
+		nouveau_fbcon_restore_accel(dev);
+
+	return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true);
+}
+
 static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src,
 			       struct nouveau_bo *dst)
 {
@@ -962,6 +996,7 @@
 	.mode_fixup = nv_crtc_mode_fixup,
 	.mode_set = nv_crtc_mode_set,
 	.mode_set_base = nv04_crtc_mode_set_base,
+	.mode_set_base_atomic = nv04_crtc_mode_set_base_atomic,
 	.load_lut = nv_crtc_gamma_load,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_dac.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_dac.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_dac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_dac.c	2011-01-04 19:50:19.000000000 -0500
@@ -291,6 +291,8 @@
 	msleep(5);
 
 	sample = NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
+	/* do it again just in case it's a residual current */
+	sample &= NVReadRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + regoffset);
 
 	temp = NVReadRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL);
 	NVWriteRAMDAC(dev, head, NV_PRAMDAC_TEST_CONTROL,
@@ -343,22 +345,13 @@
 {
 	struct drm_encoder_helper_funcs *helper = encoder->helper_private;
 	struct drm_device *dev = encoder->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	int head = nouveau_crtc(encoder->crtc)->index;
-	struct nv04_crtc_reg *crtcstate = dev_priv->mode_reg.crtc_reg;
 
 	helper->dpms(encoder, DRM_MODE_DPMS_OFF);
 
 	nv04_dfp_disable(dev, head);
-
-	/* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-	 * at LCD__INDEX which we don't alter
-	 */
-	if (!(crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] & 0x44))
-		crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
 }
 
-
 static void nv04_dac_mode_set(struct drm_encoder *encoder,
 			      struct drm_display_mode *mode,
 			      struct drm_display_mode *adjusted_mode)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_dfp.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_dfp.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_dfp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_dfp.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,6 +104,8 @@
 	}
 	/* don't inadvertently turn it on when state written later */
 	crtcstate[head].fp_control = FP_TG_CONTROL_OFF;
+	crtcstate[head].CRTC[NV_CIO_CRE_LCD__INDEX] &=
+		~NV_CIO_CRE_LCD_ROUTE_MASK;
 }
 
 void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
@@ -183,14 +185,15 @@
 	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 	struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
 
-	/* For internal panels and gpu scaling on DVI we need the native mode */
-	if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
-		if (!nv_connector->native_mode)
-			return false;
+	if (!nv_connector->native_mode ||
+	    nv_connector->scaling_mode == DRM_MODE_SCALE_NONE ||
+	    mode->hdisplay > nv_connector->native_mode->hdisplay ||
+	    mode->vdisplay > nv_connector->native_mode->vdisplay) {
+		nv_encoder->mode = *adjusted_mode;
+
+	} else {
 		nv_encoder->mode = *nv_connector->native_mode;
 		adjusted_mode->clock = nv_connector->native_mode->clock;
-	} else {
-		nv_encoder->mode = *adjusted_mode;
 	}
 
 	return true;
@@ -253,26 +256,21 @@
 
 	nv04_dfp_prepare_sel_clk(dev, nv_encoder, head);
 
-	/* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-	 * at LCD__INDEX which we don't alter
-	 */
-	if (!(*cr_lcd & 0x44)) {
-		*cr_lcd = 0x3;
+	*cr_lcd = (*cr_lcd & ~NV_CIO_CRE_LCD_ROUTE_MASK) | 0x3;
 
-		if (nv_two_heads(dev)) {
-			if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
-				*cr_lcd |= head ? 0x0 : 0x8;
-			else {
-				*cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
-				if (nv_encoder->dcb->type == OUTPUT_LVDS)
-					*cr_lcd |= 0x30;
-				if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
-					/* avoid being connected to both crtcs */
-					*cr_lcd_oth &= ~0x30;
-					NVWriteVgaCrtc(dev, head ^ 1,
-						       NV_CIO_CRE_LCD__INDEX,
-						       *cr_lcd_oth);
-				}
+	if (nv_two_heads(dev)) {
+		if (nv_encoder->dcb->location == DCB_LOC_ON_CHIP)
+			*cr_lcd |= head ? 0x0 : 0x8;
+		else {
+			*cr_lcd |= (nv_encoder->dcb->or << 4) & 0x30;
+			if (nv_encoder->dcb->type == OUTPUT_LVDS)
+				*cr_lcd |= 0x30;
+			if ((*cr_lcd & 0x30) == (*cr_lcd_oth & 0x30)) {
+				/* avoid being connected to both crtcs */
+				*cr_lcd_oth &= ~0x30;
+				NVWriteVgaCrtc(dev, head ^ 1,
+					       NV_CIO_CRE_LCD__INDEX,
+					       *cr_lcd_oth);
 			}
 		}
 	}
@@ -640,7 +638,7 @@
 	    get_tmds_slave(encoder))
 		return;
 
-	type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+	type = nouveau_i2c_identify(dev, "TMDS transmitter", info, NULL, 2);
 	if (type < 0)
 		return;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_fbcon.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_fbcon.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_fbcon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_fbcon.c	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 #include "nouveau_fbcon.h"
 
 void
@@ -169,11 +170,9 @@
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, handle, obj, NULL);
-	if (ret)
-		return ret;
-
-	return 0;
+	ret = nouveau_ramht_insert(dev_priv->channel, handle, obj);
+	nouveau_gpuobj_ref(NULL, &obj);
+	return ret;
 }
 
 int
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
-#define NV04_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV04_RAMFC__SIZE))
+#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
 #define NV04_RAMFC__SIZE 32
 #define NV04_RAMFC_DMA_PUT                                       0x00
 #define NV04_RAMFC_DMA_GET                                       0x04
@@ -38,10 +39,8 @@
 #define NV04_RAMFC_ENGINE                                        0x14
 #define NV04_RAMFC_PULL1_ENGINE                                  0x18
 
-#define RAMFC_WR(offset, val) nv_wo32(dev, chan->ramfc->gpuobj, \
-					 NV04_RAMFC_##offset/4, (val))
-#define RAMFC_RD(offset)      nv_ro32(dev, chan->ramfc->gpuobj, \
-					 NV04_RAMFC_##offset/4)
+#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val))
+#define RAMFC_RD(offset)      nv_ro32(chan->ramfc, NV04_RAMFC_##offset)
 
 void
 nv04_fifo_disable(struct drm_device *dev)
@@ -72,37 +71,32 @@
 }
 
 bool
-nv04_fifo_cache_flush(struct drm_device *dev)
+nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
-	uint64_t start = ptimer->read(dev);
-
-	do {
-		if (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) ==
-		    nv_rd32(dev, NV03_PFIFO_CACHE1_PUT))
-			return true;
-
-	} while (ptimer->read(dev) - start < 100000000);
-
-	NV_ERROR(dev, "Timeout flushing the PFIFO cache.\n");
+	int pull = nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 1, enable);
 
-	return false;
-}
+	if (!enable) {
+		/* In some cases the PFIFO puller may be left in an
+		 * inconsistent state if you try to stop it when it's
+		 * busy translating handles. Sometimes you get a
+		 * PFIFO_CACHE_ERROR, sometimes it just fails silently
+		 * sending incorrect instance offsets to PGRAPH after
+		 * it's started up again. To avoid the latter we
+		 * invalidate the most recently calculated instance.
+		 */
+		if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
+			     NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
+			NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
 
-bool
-nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
-{
-	uint32_t pull = nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0);
+		if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
+		    NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+			nv_wr32(dev, NV03_PFIFO_INTR_0,
+				NV_PFIFO_INTR_CACHE_ERROR);
 
-	if (enable) {
-		nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull | 1);
-	} else {
-		nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, pull & ~1);
 		nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
 	}
 
-	return !!(pull & 1);
+	return pull & 1;
 }
 
 int
@@ -130,7 +124,7 @@
 						NV04_RAMFC__SIZE,
 						NVOBJ_FLAG_ZERO_ALLOC |
 						NVOBJ_FLAG_ZERO_FREE,
-						NULL, &chan->ramfc);
+						&chan->ramfc);
 	if (ret)
 		return ret;
 
@@ -139,7 +133,7 @@
 	/* Setup initial state */
 	RAMFC_WR(DMA_PUT, chan->pushbuf_base);
 	RAMFC_WR(DMA_GET, chan->pushbuf_base);
-	RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
+	RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4);
 	RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 			     NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -161,7 +155,7 @@
 	nv_wr32(dev, NV04_PFIFO_MODE,
 		nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-	nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -264,10 +258,10 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht_bits - 9) << 16) |
-				       (dev_priv->ramht_offset >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
-	nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+				       ((dev_priv->ramht->bits - 9) << 16) |
+				       (dev_priv->ramht->gpuobj->pinst >> 8));
+	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+	nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
 }
 
 static void
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_instmem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_instmem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_instmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_instmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 /* returns the size of fifo context */
 static int
@@ -17,102 +18,51 @@
 	return 32;
 }
 
-static void
-nv04_instmem_determine_amount(struct drm_device *dev)
+int nv04_instmem_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i;
-
-	/* Figure out how much instance memory we need */
-	if (dev_priv->card_type >= NV_40) {
-		/* We'll want more instance memory than this on some NV4x cards.
-		 * There's a 16MB aperture to play with that maps onto the end
-		 * of vram.  For now, only reserve a small piece until we know
-		 * more about what each chipset requires.
-		 */
-		switch (dev_priv->chipset) {
-		case 0x40:
-		case 0x47:
-		case 0x49:
-		case 0x4b:
-			dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024);
-			break;
-		default:
-			dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024);
-			break;
-		}
-	} else {
-		/*XXX: what *are* the limits on <NV40 cards?
-		 */
-		dev_priv->ramin_rsvd_vram = (512 * 1024);
-	}
-	NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
+	struct nouveau_gpuobj *ramht = NULL;
+	u32 offset, length;
+	int ret;
 
-	/* Clear all of it, except the BIOS image that's in the first 64KiB */
-	for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
-		nv_wi32(dev, i, 0x00000000);
-}
+	/* RAMIN always available */
+	dev_priv->ramin_available = true;
 
-static void
-nv04_instmem_configure_fixed_tables(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_engine *engine = &dev_priv->engine;
+	/* Setup shared RAMHT */
+	ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096,
+				      NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+	if (ret)
+		return ret;
 
-	/* FIFO hash table (RAMHT)
-	 *   use 4k hash table at RAMIN+0x10000
-	 *   TODO: extend the hash table
-	 */
-	dev_priv->ramht_offset = 0x10000;
-	dev_priv->ramht_bits   = 9;
-	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits); /* nr entries */
-	dev_priv->ramht_size  *= 8; /* 2 32-bit values per entry in RAMHT */
-	NV_DEBUG(dev, "RAMHT offset=0x%x, size=%d\n", dev_priv->ramht_offset,
-						      dev_priv->ramht_size);
+	ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht);
+	nouveau_gpuobj_ref(NULL, &ramht);
+	if (ret)
+		return ret;
 
-	/* FIFO runout table (RAMRO) - 512k at 0x11200 */
-	dev_priv->ramro_offset = 0x11200;
-	dev_priv->ramro_size   = 512;
-	NV_DEBUG(dev, "RAMRO offset=0x%x, size=%d\n", dev_priv->ramro_offset,
-						      dev_priv->ramro_size);
+	/* And RAMRO */
+	ret = nouveau_gpuobj_new_fake(dev, 0x11200, ~0, 512,
+				      NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramro);
+	if (ret)
+		return ret;
 
-	/* FIFO context table (RAMFC)
-	 *   NV40  : Not sure exactly how to position RAMFC on some cards,
-	 *           0x30002 seems to position it at RAMIN+0x20000 on these
-	 *           cards.  RAMFC is 4kb (32 fifos, 128byte entries).
-	 *   Others: Position RAMFC at RAMIN+0x11400
-	 */
-	dev_priv->ramfc_size = engine->fifo.channels *
-						nouveau_fifo_ctx_size(dev);
+	/* And RAMFC */
+	length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev);
 	switch (dev_priv->card_type) {
 	case NV_40:
-		dev_priv->ramfc_offset = 0x20000;
+		offset = 0x20000;
 		break;
-	case NV_30:
-	case NV_20:
-	case NV_10:
-	case NV_04:
 	default:
-		dev_priv->ramfc_offset = 0x11400;
+		offset = 0x11400;
 		break;
 	}
-	NV_DEBUG(dev, "RAMFC offset=0x%x, size=%d\n", dev_priv->ramfc_offset,
-						      dev_priv->ramfc_size);
-}
 
-int nv04_instmem_init(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t offset;
-	int ret;
-
-	nv04_instmem_determine_amount(dev);
-	nv04_instmem_configure_fixed_tables(dev);
+	ret = nouveau_gpuobj_new_fake(dev, offset, ~0, length,
+				      NVOBJ_FLAG_ZERO_ALLOC, &dev_priv->ramfc);
+	if (ret)
+		return ret;
 
-	/* Create a heap to manage RAMIN allocations, we don't allocate
-	 * the space that was reserved for RAMHT/FC/RO.
-	 */
-	offset = dev_priv->ramfc_offset + dev_priv->ramfc_size;
+	/* Only allow space after RAMFC to be used for object allocation */
+	offset += length;
 
 	/* It appears RAMRO (or something?) is controlled by 0x2220/0x2230
 	 * on certain NV4x chipsets as well as RAMFC.  When 0x2230 == 0
@@ -140,46 +90,34 @@
 void
 nv04_instmem_takedown(struct drm_device *dev)
 {
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
+	nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
+	nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
 }
 
 int
-nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, uint32_t *sz)
+nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+		      uint32_t *sz)
 {
-	if (gpuobj->im_backing)
-		return -EINVAL;
-
 	return 0;
 }
 
 void
 nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-	if (gpuobj && gpuobj->im_backing) {
-		if (gpuobj->im_bound)
-			dev_priv->engine.instmem.unbind(dev, gpuobj);
-		gpuobj->im_backing = NULL;
-	}
 }
 
 int
 nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-	if (!gpuobj->im_pramin || gpuobj->im_bound)
-		return -EINVAL;
-
-	gpuobj->im_bound = 1;
 	return 0;
 }
 
 int
 nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
-	if (gpuobj->im_bound == 0)
-		return -EINVAL;
-
-	gpuobj->im_bound = 0;
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_pm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_pm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2010 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_hw.h"
+#include "nouveau_pm.h"
+
+struct nv04_pm_state {
+	struct pll_lims pll;
+	struct nouveau_pll_vals calc;
+};
+
+int
+nv04_pm_clock_get(struct drm_device *dev, u32 id)
+{
+	return nouveau_hw_get_clock(dev, id);
+}
+
+void *
+nv04_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+		  u32 id, int khz)
+{
+	struct nv04_pm_state *state;
+	int ret;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+
+	ret = get_pll_limits(dev, id, &state->pll);
+	if (ret) {
+		kfree(state);
+		return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+	}
+
+	ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
+	if (!ret) {
+		kfree(state);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return state;
+}
+
+void
+nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nv04_pm_state *state = pre_state;
+	u32 reg = state->pll.reg;
+
+	/* thank the insane nouveau_hw_setpll() interface for this */
+	if (dev_priv->card_type >= NV_40)
+		reg += 4;
+
+	nouveau_hw_setpll(dev, reg, &state->calc);
+
+	if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
+		if (dev_priv->card_type == NV_20)
+			nv_mask(dev, 0x1002c4, 0, 1 << 20);
+
+		/* Reset the DLLs */
+		nv_mask(dev, 0x1002c0, 0, 1 << 8);
+	}
+
+	kfree(state);
+}
+
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_tv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_tv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv04_tv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv04_tv.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,8 +49,8 @@
 
 int nv04_tv_identify(struct drm_device *dev, int i2c_index)
 {
-	return nouveau_i2c_identify(dev, "TV encoder",
-				    nv04_tv_encoder_info, i2c_index);
+	return nouveau_i2c_identify(dev, "TV encoder", nv04_tv_encoder_info,
+				    NULL, i2c_index);
 }
 
 
@@ -99,12 +99,10 @@
 
 	state->tv_setup = 0;
 
-	if (bind) {
-		state->CRTC[NV_CIO_CRE_LCD__INDEX] = 0;
+	if (bind)
 		state->CRTC[NV_CIO_CRE_49] |= 0x10;
-	} else {
+	else
 		state->CRTC[NV_CIO_CRE_49] &= ~0x10;
-	}
 
 	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_LCD__INDEX,
 		       state->CRTC[NV_CIO_CRE_LCD__INDEX]);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv10_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv10_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv10_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv10_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
-#define NV10_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV10_RAMFC__SIZE))
+#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE))
 #define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
 
 int
@@ -48,7 +49,7 @@
 
 	ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0,
 				      NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
-				      NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+				      NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
 	if (ret)
 		return ret;
 
@@ -57,7 +58,7 @@
 	 */
 	nv_wi32(dev, fc +  0, chan->pushbuf_base);
 	nv_wi32(dev, fc +  4, chan->pushbuf_base);
-	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+	nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
 	nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			      NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 			      NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -80,7 +81,7 @@
 	nv_wr32(dev, NV04_PFIFO_MODE,
 			nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-	nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -202,14 +203,14 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht_bits - 9) << 16) |
-				       (dev_priv->ramht_offset >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+				       ((dev_priv->ramht->bits - 9) << 16) |
+				       (dev_priv->ramht->gpuobj->pinst >> 8));
+	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
 
 	if (dev_priv->chipset < 0x17) {
-		nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc_offset >> 8);
+		nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
 	} else {
-		nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc_offset >> 8) |
+		nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) |
 					       (1 << 16) /* 64 Bytes entry*/);
 		/* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv10_graph.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv10_graph.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv10_graph.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv10_graph.c	2011-01-04 19:50:19.000000000 -0500
@@ -803,7 +803,7 @@
 	/* Load context for next channel */
 	chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
 	chan = dev_priv->fifos[chid];
-	if (chan)
+	if (chan && chan->pgraph_ctx)
 		nv10_graph_load_context(chan);
 
 	pgraph->fifo_access(dev, true);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv.c	2011-01-04 19:50:19.000000000 -0500
@@ -193,55 +193,56 @@
 	}
 }
 
-static const struct {
-	int hdisplay;
-	int vdisplay;
-} modes[] = {
-	{ 640, 400 },
-	{ 640, 480 },
-	{ 720, 480 },
-	{ 720, 576 },
-	{ 800, 600 },
-	{ 1024, 768 },
-	{ 1280, 720 },
-	{ 1280, 1024 },
-	{ 1920, 1080 }
-};
-
-static int nv17_tv_get_modes(struct drm_encoder *encoder,
-			     struct drm_connector *connector)
+static int nv17_tv_get_ld_modes(struct drm_encoder *encoder,
+				struct drm_connector *connector)
 {
 	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
-	struct drm_display_mode *mode;
-	struct drm_display_mode *output_mode;
+	struct drm_display_mode *mode, *tv_mode;
 	int n = 0;
-	int i;
 
-	if (tv_norm->kind != CTV_ENC_MODE) {
-		struct drm_display_mode *tv_mode;
-
-		for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
-			mode = drm_mode_duplicate(encoder->dev, tv_mode);
+	for (tv_mode = nv17_tv_modes; tv_mode->hdisplay; tv_mode++) {
+		mode = drm_mode_duplicate(encoder->dev, tv_mode);
 
-			mode->clock = tv_norm->tv_enc_mode.vrefresh *
-						mode->htotal / 1000 *
-						mode->vtotal / 1000;
+		mode->clock = tv_norm->tv_enc_mode.vrefresh *
+			mode->htotal / 1000 *
+			mode->vtotal / 1000;
 
-			if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-				mode->clock *= 2;
+		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+			mode->clock *= 2;
 
-			if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
-			    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
-				mode->type |= DRM_MODE_TYPE_PREFERRED;
+		if (mode->hdisplay == tv_norm->tv_enc_mode.hdisplay &&
+		    mode->vdisplay == tv_norm->tv_enc_mode.vdisplay)
+			mode->type |= DRM_MODE_TYPE_PREFERRED;
 
-			drm_mode_probed_add(connector, mode);
-			n++;
-		}
-		return n;
+		drm_mode_probed_add(connector, mode);
+		n++;
 	}
 
-	/* tv_norm->kind == CTV_ENC_MODE */
-	output_mode = &tv_norm->ctv_enc_mode.mode;
+	return n;
+}
+
+static int nv17_tv_get_hd_modes(struct drm_encoder *encoder,
+				struct drm_connector *connector)
+{
+	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+	struct drm_display_mode *output_mode = &tv_norm->ctv_enc_mode.mode;
+	struct drm_display_mode *mode;
+	const struct {
+		int hdisplay;
+		int vdisplay;
+	} modes[] = {
+		{ 640, 400 },
+		{ 640, 480 },
+		{ 720, 480 },
+		{ 720, 576 },
+		{ 800, 600 },
+		{ 1024, 768 },
+		{ 1280, 720 },
+		{ 1280, 1024 },
+		{ 1920, 1080 }
+	};
+	int i, n = 0;
+
 	for (i = 0; i < ARRAY_SIZE(modes); i++) {
 		if (modes[i].hdisplay > output_mode->hdisplay ||
 		    modes[i].vdisplay > output_mode->vdisplay)
@@ -251,11 +252,12 @@
 		    modes[i].vdisplay == output_mode->vdisplay) {
 			mode = drm_mode_duplicate(encoder->dev, output_mode);
 			mode->type |= DRM_MODE_TYPE_PREFERRED;
+
 		} else {
 			mode = drm_cvt_mode(encoder->dev, modes[i].hdisplay,
-				modes[i].vdisplay, 60, false,
-				output_mode->flags & DRM_MODE_FLAG_INTERLACE,
-				false);
+					    modes[i].vdisplay, 60, false,
+					    (output_mode->flags &
+					     DRM_MODE_FLAG_INTERLACE), false);
 		}
 
 		/* CVT modes are sometimes unsuitable... */
@@ -266,6 +268,7 @@
 					     - mode->hdisplay) * 9 / 10) & ~7;
 			mode->hsync_end = mode->hsync_start + 8;
 		}
+
 		if (output_mode->vdisplay >= 1024) {
 			mode->vtotal = output_mode->vtotal;
 			mode->vsync_start = output_mode->vsync_start;
@@ -276,9 +279,21 @@
 		drm_mode_probed_add(connector, mode);
 		n++;
 	}
+
 	return n;
 }
 
+static int nv17_tv_get_modes(struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
+
+	if (tv_norm->kind == CTV_ENC_MODE)
+		return nv17_tv_get_hd_modes(encoder, connector);
+	else
+		return nv17_tv_get_ld_modes(encoder, connector);
+}
+
 static int nv17_tv_mode_valid(struct drm_encoder *encoder,
 			      struct drm_display_mode *mode)
 {
@@ -408,15 +423,8 @@
 
 	}
 
-	/* Some NV4x have unknown values (0x3f, 0x50, 0x54, 0x6b, 0x79, 0x7f)
-	 * at LCD__INDEX which we don't alter
-	 */
-	if (!(*cr_lcd & 0x44)) {
-		if (tv_norm->kind == CTV_ENC_MODE)
-			*cr_lcd = 0x1 | (head ? 0x0 : 0x8);
-		else
-			*cr_lcd = 0;
-	}
+	if (tv_norm->kind == CTV_ENC_MODE)
+		*cr_lcd |= 0x1 | (head ? 0x0 : 0x8);
 
 	/* Set the DACCLK register */
 	dacclk = (NVReadRAMDAC(dev, 0, dacclk_off) & ~0x30) | 0x1;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv.h	2011-01-04 19:50:19.000000000 -0500
@@ -127,7 +127,8 @@
 
 /* TV hardware access functions */
 
-static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val)
+static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg,
+				uint32_t val)
 {
 	nv_wr32(dev, reg, val);
 }
@@ -137,7 +138,8 @@
 	return nv_rd32(dev, reg);
 }
 
-static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, uint8_t val)
+static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg,
+				   uint8_t val)
 {
 	nv_write_ptv(dev, NV_PTV_TV_INDEX, reg);
 	nv_write_ptv(dev, NV_PTV_TV_DATA, val);
@@ -149,8 +151,11 @@
 	return nv_read_ptv(dev, NV_PTV_TV_DATA);
 }
 
-#define nv_load_ptv(dev, state, reg) nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
-#define nv_save_ptv(dev, state, reg) state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
-#define nv_load_tv_enc(dev, state, reg) nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
+#define nv_load_ptv(dev, state, reg) \
+	nv_write_ptv(dev, NV_PTV_OFFSET + 0x##reg, state->ptv_##reg)
+#define nv_save_ptv(dev, state, reg) \
+	state->ptv_##reg = nv_read_ptv(dev, NV_PTV_OFFSET + 0x##reg)
+#define nv_load_tv_enc(dev, state, reg) \
+	nv_write_tv_enc(dev, 0x##reg, state->tv_enc[0x##reg])
 
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv_modes.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv_modes.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv17_tv_modes.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv17_tv_modes.c	2011-01-04 19:50:19.000000000 -0500
@@ -336,12 +336,17 @@
 			struct filter_params *p = &fparams[k][j];
 
 			for (i = 0; i < 7; i++) {
-				int64_t c = (p->k1 + p->ki*i + p->ki2*i*i + p->ki3*i*i*i)
-					+ (p->kr + p->kir*i + p->ki2r*i*i + p->ki3r*i*i*i)*rs[k]
-					+ (p->kf + p->kif*i + p->ki2f*i*i + p->ki3f*i*i*i)*flicker
-					+ (p->krf + p->kirf*i + p->ki2rf*i*i + p->ki3rf*i*i*i)*flicker*rs[k];
+				int64_t c = (p->k1 + p->ki*i + p->ki2*i*i +
+					     p->ki3*i*i*i)
+					+ (p->kr + p->kir*i + p->ki2r*i*i +
+					   p->ki3r*i*i*i) * rs[k]
+					+ (p->kf + p->kif*i + p->ki2f*i*i +
+					   p->ki3f*i*i*i) * flicker
+					+ (p->krf + p->kirf*i + p->ki2rf*i*i +
+					   p->ki3rf*i*i*i) * flicker * rs[k];
 
-				(*filters[k])[j][i] = (c + id5/2) >> 39 & (0x1 << 31 | 0x7f << 9);
+				(*filters[k])[j][i] = (c + id5/2) >> 39
+					& (0x1 << 31 | 0x7f << 9);
 			}
 		}
 	}
@@ -349,7 +354,8 @@
 
 /* Hardware state saving/restoring */
 
-static void tv_save_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_save_filter(struct drm_device *dev, uint32_t base,
+			   uint32_t regs[4][7])
 {
 	int i, j;
 	uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -360,7 +366,8 @@
 	}
 }
 
-static void tv_load_filter(struct drm_device *dev, uint32_t base, uint32_t regs[4][7])
+static void tv_load_filter(struct drm_device *dev, uint32_t base,
+			   uint32_t regs[4][7])
 {
 	int i, j;
 	uint32_t offsets[] = { base, base + 0x1c, base + 0x40, base + 0x5c };
@@ -504,10 +511,10 @@
 		break;
 	}
 
-	regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20], 255,
-					 tv_enc->saturation);
-	regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22], 255,
-					 tv_enc->saturation);
+	regs->tv_enc[0x20] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x20],
+					 255, tv_enc->saturation);
+	regs->tv_enc[0x22] = interpolate(0, tv_norm->tv_enc_mode.tv_enc[0x22],
+					 255, tv_enc->saturation);
 	regs->tv_enc[0x25] = tv_enc->hue * 255 / 100;
 
 	nv_load_ptv(dev, regs, 204);
@@ -541,7 +548,8 @@
 	int head = nouveau_crtc(encoder->crtc)->index;
 	struct nv04_crtc_reg *regs = &dev_priv->mode_reg.crtc_reg[head];
 	struct drm_display_mode *crtc_mode = &encoder->crtc->mode;
-	struct drm_display_mode *output_mode = &get_tv_norm(encoder)->ctv_enc_mode.mode;
+	struct drm_display_mode *output_mode =
+		&get_tv_norm(encoder)->ctv_enc_mode.mode;
 	int overscan, hmargin, vmargin, hratio, vratio;
 
 	/* The rescaler doesn't do the right thing for interlaced modes. */
@@ -553,13 +561,15 @@
 	hmargin = (output_mode->hdisplay - crtc_mode->hdisplay) / 2;
 	vmargin = (output_mode->vdisplay - crtc_mode->vdisplay) / 2;
 
-	hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20), hmargin,
-			      overscan);
-	vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20), vmargin,
-			      overscan);
+	hmargin = interpolate(0, min(hmargin, output_mode->hdisplay/20),
+			      hmargin, overscan);
+	vmargin = interpolate(0, min(vmargin, output_mode->vdisplay/20),
+			      vmargin, overscan);
 
-	hratio = crtc_mode->hdisplay * 0x800 / (output_mode->hdisplay - 2*hmargin);
-	vratio = crtc_mode->vdisplay * 0x800 / (output_mode->vdisplay - 2*vmargin) & ~3;
+	hratio = crtc_mode->hdisplay * 0x800 /
+		(output_mode->hdisplay - 2*hmargin);
+	vratio = crtc_mode->vdisplay * 0x800 /
+		(output_mode->vdisplay - 2*vmargin) & ~3;
 
 	regs->fp_horiz_regs[FP_VALID_START] = hmargin;
 	regs->fp_horiz_regs[FP_VALID_END] = output_mode->hdisplay - hmargin - 1;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv20_graph.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv20_graph.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv20_graph.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv20_graph.c	2011-01-04 19:50:19.000000000 -0500
@@ -37,49 +37,49 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
-	nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+	nv_wo32(ctx, 0x033c, 0xffff0000);
+	nv_wo32(ctx, 0x03a0, 0x0fff0000);
+	nv_wo32(ctx, 0x03a4, 0x0fff0000);
+	nv_wo32(ctx, 0x047c, 0x00000101);
+	nv_wo32(ctx, 0x0490, 0x00000111);
+	nv_wo32(ctx, 0x04a8, 0x44400000);
 	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080000);
+		nv_wo32(ctx, i, 0x00080000);
 	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x000105b8);
+		nv_wo32(ctx, i, 0x000105b8);
 	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
+		nv_wo32(ctx, i, 0x00080008);
 	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
-	nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+	nv_wo32(ctx, 0x05fc, 0x00000001);
+	nv_wo32(ctx, 0x0604, 0x00004000);
+	nv_wo32(ctx, 0x0610, 0x00000001);
+	nv_wo32(ctx, 0x0618, 0x00040000);
+	nv_wo32(ctx, 0x061c, 0x00010000);
 	for (i = 0x1c1c; i <= 0x248c; i += 16) {
-		nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-		nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-		nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+		nv_wo32(ctx, (i + 0), 0x10700ff9);
+		nv_wo32(ctx, (i + 4), 0x0436086c);
+		nv_wo32(ctx, (i + 8), 0x000c001b);
 	}
-	nv_wo32(dev, ctx, 0x281c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2830/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x285c/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2860/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2864/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x286c/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2870/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2878/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x2880/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x34a4/4, 0x000fe000);
-	nv_wo32(dev, ctx, 0x3530/4, 0x000003f8);
-	nv_wo32(dev, ctx, 0x3540/4, 0x002fe000);
+	nv_wo32(ctx, 0x281c, 0x3f800000);
+	nv_wo32(ctx, 0x2830, 0x3f800000);
+	nv_wo32(ctx, 0x285c, 0x40000000);
+	nv_wo32(ctx, 0x2860, 0x3f800000);
+	nv_wo32(ctx, 0x2864, 0x3f000000);
+	nv_wo32(ctx, 0x286c, 0x40000000);
+	nv_wo32(ctx, 0x2870, 0x3f800000);
+	nv_wo32(ctx, 0x2878, 0xbf800000);
+	nv_wo32(ctx, 0x2880, 0xbf800000);
+	nv_wo32(ctx, 0x34a4, 0x000fe000);
+	nv_wo32(ctx, 0x3530, 0x000003f8);
+	nv_wo32(ctx, 0x3540, 0x002fe000);
 	for (i = 0x355c; i <= 0x3578; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x001c527c);
+		nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -87,58 +87,58 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x035c/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x03c0/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x03c4/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x049c/4, 0x00000101);
-	nv_wo32(dev, ctx, 0x04b0/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x04c8/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x04cc/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x04d0/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x04e4/4, 0x44400000);
-	nv_wo32(dev, ctx, 0x04fc/4, 0x4b800000);
+	nv_wo32(ctx, 0x035c, 0xffff0000);
+	nv_wo32(ctx, 0x03c0, 0x0fff0000);
+	nv_wo32(ctx, 0x03c4, 0x0fff0000);
+	nv_wo32(ctx, 0x049c, 0x00000101);
+	nv_wo32(ctx, 0x04b0, 0x00000111);
+	nv_wo32(ctx, 0x04c8, 0x00000080);
+	nv_wo32(ctx, 0x04cc, 0xffff0000);
+	nv_wo32(ctx, 0x04d0, 0x00000001);
+	nv_wo32(ctx, 0x04e4, 0x44400000);
+	nv_wo32(ctx, 0x04fc, 0x4b800000);
 	for (i = 0x0510; i <= 0x051c; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x0530; i <= 0x053c; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080000);
+		nv_wo32(ctx, i, 0x00080000);
 	for (i = 0x0548; i <= 0x0554; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x0558; i <= 0x0564; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x000105b8);
+		nv_wo32(ctx, i, 0x000105b8);
 	for (i = 0x0568; i <= 0x0574; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
+		nv_wo32(ctx, i, 0x00080008);
 	for (i = 0x0598; i <= 0x05d4; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x05e0/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x0620/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0624/4, 0x30201000);
-	nv_wo32(dev, ctx, 0x0628/4, 0x70605040);
-	nv_wo32(dev, ctx, 0x062c/4, 0xb0a09080);
-	nv_wo32(dev, ctx, 0x0630/4, 0xf0e0d0c0);
-	nv_wo32(dev, ctx, 0x0664/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x066c/4, 0x00004000);
-	nv_wo32(dev, ctx, 0x0678/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0680/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x0684/4, 0x00010000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x05e0, 0x4b7fffff);
+	nv_wo32(ctx, 0x0620, 0x00000080);
+	nv_wo32(ctx, 0x0624, 0x30201000);
+	nv_wo32(ctx, 0x0628, 0x70605040);
+	nv_wo32(ctx, 0x062c, 0xb0a09080);
+	nv_wo32(ctx, 0x0630, 0xf0e0d0c0);
+	nv_wo32(ctx, 0x0664, 0x00000001);
+	nv_wo32(ctx, 0x066c, 0x00004000);
+	nv_wo32(ctx, 0x0678, 0x00000001);
+	nv_wo32(ctx, 0x0680, 0x00040000);
+	nv_wo32(ctx, 0x0684, 0x00010000);
 	for (i = 0x1b04; i <= 0x2374; i += 16) {
-		nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-		nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-		nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+		nv_wo32(ctx, (i + 0), 0x10700ff9);
+		nv_wo32(ctx, (i + 4), 0x0436086c);
+		nv_wo32(ctx, (i + 8), 0x000c001b);
 	}
-	nv_wo32(dev, ctx, 0x2704/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2718/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2744/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2748/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x274c/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x2754/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2758/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2760/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x2768/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x308c/4, 0x000fe000);
-	nv_wo32(dev, ctx, 0x3108/4, 0x000003f8);
-	nv_wo32(dev, ctx, 0x3468/4, 0x002fe000);
+	nv_wo32(ctx, 0x2704, 0x3f800000);
+	nv_wo32(ctx, 0x2718, 0x3f800000);
+	nv_wo32(ctx, 0x2744, 0x40000000);
+	nv_wo32(ctx, 0x2748, 0x3f800000);
+	nv_wo32(ctx, 0x274c, 0x3f000000);
+	nv_wo32(ctx, 0x2754, 0x40000000);
+	nv_wo32(ctx, 0x2758, 0x3f800000);
+	nv_wo32(ctx, 0x2760, 0xbf800000);
+	nv_wo32(ctx, 0x2768, 0xbf800000);
+	nv_wo32(ctx, 0x308c, 0x000fe000);
+	nv_wo32(ctx, 0x3108, 0x000003f8);
+	nv_wo32(ctx, 0x3468, 0x002fe000);
 	for (i = 0x3484; i <= 0x34a0; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x001c527c);
+		nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -146,49 +146,49 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x033c/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x03a0/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x03a4/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x047c/4, 0x00000101);
-	nv_wo32(dev, ctx, 0x0490/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x04a8/4, 0x44400000);
+	nv_wo32(ctx, 0x033c, 0xffff0000);
+	nv_wo32(ctx, 0x03a0, 0x0fff0000);
+	nv_wo32(ctx, 0x03a4, 0x0fff0000);
+	nv_wo32(ctx, 0x047c, 0x00000101);
+	nv_wo32(ctx, 0x0490, 0x00000111);
+	nv_wo32(ctx, 0x04a8, 0x44400000);
 	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080000);
+		nv_wo32(ctx, i, 0x00080000);
 	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x000105b8);
+		nv_wo32(ctx, i, 0x000105b8);
 	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
+		nv_wo32(ctx, i, 0x00080008);
 	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x05a4/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x05fc/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0604/4, 0x00004000);
-	nv_wo32(dev, ctx, 0x0610/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0618/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x061c/4, 0x00010000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
+	nv_wo32(ctx, 0x05fc, 0x00000001);
+	nv_wo32(ctx, 0x0604, 0x00004000);
+	nv_wo32(ctx, 0x0610, 0x00000001);
+	nv_wo32(ctx, 0x0618, 0x00040000);
+	nv_wo32(ctx, 0x061c, 0x00010000);
 	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
-		nv_wo32(dev, ctx, (i + 0)/4, 0x10700ff9);
-		nv_wo32(dev, ctx, (i + 4)/4, 0x0436086c);
-		nv_wo32(dev, ctx, (i + 8)/4, 0x000c001b);
+		nv_wo32(ctx, (i + 0), 0x10700ff9);
+		nv_wo32(ctx, (i + 4), 0x0436086c);
+		nv_wo32(ctx, (i + 8), 0x000c001b);
 	}
-	nv_wo32(dev, ctx, 0x269c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x26b0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x26dc/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x26e0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x26e4/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x26ec/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x26f0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x26f8/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x2700/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x3024/4, 0x000fe000);
-	nv_wo32(dev, ctx, 0x30a0/4, 0x000003f8);
-	nv_wo32(dev, ctx, 0x33fc/4, 0x002fe000);
+	nv_wo32(ctx, 0x269c, 0x3f800000);
+	nv_wo32(ctx, 0x26b0, 0x3f800000);
+	nv_wo32(ctx, 0x26dc, 0x40000000);
+	nv_wo32(ctx, 0x26e0, 0x3f800000);
+	nv_wo32(ctx, 0x26e4, 0x3f000000);
+	nv_wo32(ctx, 0x26ec, 0x40000000);
+	nv_wo32(ctx, 0x26f0, 0x3f800000);
+	nv_wo32(ctx, 0x26f8, 0xbf800000);
+	nv_wo32(ctx, 0x2700, 0xbf800000);
+	nv_wo32(ctx, 0x3024, 0x000fe000);
+	nv_wo32(ctx, 0x30a0, 0x000003f8);
+	nv_wo32(ctx, 0x33fc, 0x002fe000);
 	for (i = 0x341c; i <= 0x3438; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x001c527c);
+		nv_wo32(ctx, i, 0x001c527c);
 }
 
 static void
@@ -196,57 +196,57 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x0410/4, 0x00000101);
-	nv_wo32(dev, ctx, 0x0424/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x0428/4, 0x00000060);
-	nv_wo32(dev, ctx, 0x0444/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0448/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x044c/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x0460/4, 0x44400000);
-	nv_wo32(dev, ctx, 0x048c/4, 0xffff0000);
+	nv_wo32(ctx, 0x0410, 0x00000101);
+	nv_wo32(ctx, 0x0424, 0x00000111);
+	nv_wo32(ctx, 0x0428, 0x00000060);
+	nv_wo32(ctx, 0x0444, 0x00000080);
+	nv_wo32(ctx, 0x0448, 0xffff0000);
+	nv_wo32(ctx, 0x044c, 0x00000001);
+	nv_wo32(ctx, 0x0460, 0x44400000);
+	nv_wo32(ctx, 0x048c, 0xffff0000);
 	for (i = 0x04e0; i < 0x04e8; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x04ec/4, 0x00011100);
+		nv_wo32(ctx, i, 0x0fff0000);
+	nv_wo32(ctx, 0x04ec, 0x00011100);
 	for (i = 0x0508; i < 0x0548; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x0550/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x058c/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0590/4, 0x30201000);
-	nv_wo32(dev, ctx, 0x0594/4, 0x70605040);
-	nv_wo32(dev, ctx, 0x0598/4, 0xb8a89888);
-	nv_wo32(dev, ctx, 0x059c/4, 0xf8e8d8c8);
-	nv_wo32(dev, ctx, 0x05b0/4, 0xb0000000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x0550, 0x4b7fffff);
+	nv_wo32(ctx, 0x058c, 0x00000080);
+	nv_wo32(ctx, 0x0590, 0x30201000);
+	nv_wo32(ctx, 0x0594, 0x70605040);
+	nv_wo32(ctx, 0x0598, 0xb8a89888);
+	nv_wo32(ctx, 0x059c, 0xf8e8d8c8);
+	nv_wo32(ctx, 0x05b0, 0xb0000000);
 	for (i = 0x0600; i < 0x0640; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00010588);
+		nv_wo32(ctx, i, 0x00010588);
 	for (i = 0x0640; i < 0x0680; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x06c0; i < 0x0700; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0008aae4);
+		nv_wo32(ctx, i, 0x0008aae4);
 	for (i = 0x0700; i < 0x0740; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x0740; i < 0x0780; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
-	nv_wo32(dev, ctx, 0x085c/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x0860/4, 0x00010000);
+		nv_wo32(ctx, i, 0x00080008);
+	nv_wo32(ctx, 0x085c, 0x00040000);
+	nv_wo32(ctx, 0x0860, 0x00010000);
 	for (i = 0x0864; i < 0x0874; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00040004);
+		nv_wo32(ctx, i, 0x00040004);
 	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
-		nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-		nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-		nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+		nv_wo32(ctx, i + 0, 0x10700ff9);
+		nv_wo32(ctx, i + 1, 0x0436086c);
+		nv_wo32(ctx, i + 2, 0x000c001b);
 	}
 	for (i = 0x30b8; i < 0x30c8; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0000ffff);
-	nv_wo32(dev, ctx, 0x344c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3808/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x381c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3848/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x384c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3850/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x3858/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x385c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3864/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x386c/4, 0xbf800000);
+		nv_wo32(ctx, i, 0x0000ffff);
+	nv_wo32(ctx, 0x344c, 0x3f800000);
+	nv_wo32(ctx, 0x3808, 0x3f800000);
+	nv_wo32(ctx, 0x381c, 0x3f800000);
+	nv_wo32(ctx, 0x3848, 0x40000000);
+	nv_wo32(ctx, 0x384c, 0x3f800000);
+	nv_wo32(ctx, 0x3850, 0x3f000000);
+	nv_wo32(ctx, 0x3858, 0x40000000);
+	nv_wo32(ctx, 0x385c, 0x3f800000);
+	nv_wo32(ctx, 0x3864, 0xbf800000);
+	nv_wo32(ctx, 0x386c, 0xbf800000);
 }
 
 static void
@@ -254,57 +254,57 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x040c/4, 0x01000101);
-	nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
-	nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
-	nv_wo32(dev, ctx, 0x0480/4, 0xffff0000);
+	nv_wo32(ctx, 0x040c, 0x01000101);
+	nv_wo32(ctx, 0x0420, 0x00000111);
+	nv_wo32(ctx, 0x0424, 0x00000060);
+	nv_wo32(ctx, 0x0440, 0x00000080);
+	nv_wo32(ctx, 0x0444, 0xffff0000);
+	nv_wo32(ctx, 0x0448, 0x00000001);
+	nv_wo32(ctx, 0x045c, 0x44400000);
+	nv_wo32(ctx, 0x0480, 0xffff0000);
 	for (i = 0x04d4; i < 0x04dc; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x04e0/4, 0x00011100);
+		nv_wo32(ctx, i, 0x0fff0000);
+	nv_wo32(ctx, 0x04e0, 0x00011100);
 	for (i = 0x04fc; i < 0x053c; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x0544/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x057c/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0580/4, 0x30201000);
-	nv_wo32(dev, ctx, 0x0584/4, 0x70605040);
-	nv_wo32(dev, ctx, 0x0588/4, 0xb8a89888);
-	nv_wo32(dev, ctx, 0x058c/4, 0xf8e8d8c8);
-	nv_wo32(dev, ctx, 0x05a0/4, 0xb0000000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x0544, 0x4b7fffff);
+	nv_wo32(ctx, 0x057c, 0x00000080);
+	nv_wo32(ctx, 0x0580, 0x30201000);
+	nv_wo32(ctx, 0x0584, 0x70605040);
+	nv_wo32(ctx, 0x0588, 0xb8a89888);
+	nv_wo32(ctx, 0x058c, 0xf8e8d8c8);
+	nv_wo32(ctx, 0x05a0, 0xb0000000);
 	for (i = 0x05f0; i < 0x0630; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00010588);
+		nv_wo32(ctx, i, 0x00010588);
 	for (i = 0x0630; i < 0x0670; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x06b0; i < 0x06f0; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0008aae4);
+		nv_wo32(ctx, i, 0x0008aae4);
 	for (i = 0x06f0; i < 0x0730; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x0730; i < 0x0770; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
-	nv_wo32(dev, ctx, 0x0850/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x0854/4, 0x00010000);
+		nv_wo32(ctx, i, 0x00080008);
+	nv_wo32(ctx, 0x0850, 0x00040000);
+	nv_wo32(ctx, 0x0854, 0x00010000);
 	for (i = 0x0858; i < 0x0868; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00040004);
+		nv_wo32(ctx, i, 0x00040004);
 	for (i = 0x15ac; i <= 0x271c ; i += 16) {
-		nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-		nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-		nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+		nv_wo32(ctx, i + 0, 0x10700ff9);
+		nv_wo32(ctx, i + 1, 0x0436086c);
+		nv_wo32(ctx, i + 2, 0x000c001b);
 	}
 	for (i = 0x274c; i < 0x275c; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0000ffff);
-	nv_wo32(dev, ctx, 0x2ae0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2e9c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2eb0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2edc/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2ee0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2ee4/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x2eec/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x2ef0/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x2ef8/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x2f00/4, 0xbf800000);
+		nv_wo32(ctx, i, 0x0000ffff);
+	nv_wo32(ctx, 0x2ae0, 0x3f800000);
+	nv_wo32(ctx, 0x2e9c, 0x3f800000);
+	nv_wo32(ctx, 0x2eb0, 0x3f800000);
+	nv_wo32(ctx, 0x2edc, 0x40000000);
+	nv_wo32(ctx, 0x2ee0, 0x3f800000);
+	nv_wo32(ctx, 0x2ee4, 0x3f000000);
+	nv_wo32(ctx, 0x2eec, 0x40000000);
+	nv_wo32(ctx, 0x2ef0, 0x3f800000);
+	nv_wo32(ctx, 0x2ef8, 0xbf800000);
+	nv_wo32(ctx, 0x2f00, 0xbf800000);
 }
 
 static void
@@ -312,57 +312,57 @@
 {
 	int i;
 
-	nv_wo32(dev, ctx, 0x040c/4, 0x00000101);
-	nv_wo32(dev, ctx, 0x0420/4, 0x00000111);
-	nv_wo32(dev, ctx, 0x0424/4, 0x00000060);
-	nv_wo32(dev, ctx, 0x0440/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x0444/4, 0xffff0000);
-	nv_wo32(dev, ctx, 0x0448/4, 0x00000001);
-	nv_wo32(dev, ctx, 0x045c/4, 0x44400000);
-	nv_wo32(dev, ctx, 0x0488/4, 0xffff0000);
+	nv_wo32(ctx, 0x040c, 0x00000101);
+	nv_wo32(ctx, 0x0420, 0x00000111);
+	nv_wo32(ctx, 0x0424, 0x00000060);
+	nv_wo32(ctx, 0x0440, 0x00000080);
+	nv_wo32(ctx, 0x0444, 0xffff0000);
+	nv_wo32(ctx, 0x0448, 0x00000001);
+	nv_wo32(ctx, 0x045c, 0x44400000);
+	nv_wo32(ctx, 0x0488, 0xffff0000);
 	for (i = 0x04dc; i < 0x04e4; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0fff0000);
-	nv_wo32(dev, ctx, 0x04e8/4, 0x00011100);
+		nv_wo32(ctx, i, 0x0fff0000);
+	nv_wo32(ctx, 0x04e8, 0x00011100);
 	for (i = 0x0504; i < 0x0544; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x07ff0000);
-	nv_wo32(dev, ctx, 0x054c/4, 0x4b7fffff);
-	nv_wo32(dev, ctx, 0x0588/4, 0x00000080);
-	nv_wo32(dev, ctx, 0x058c/4, 0x30201000);
-	nv_wo32(dev, ctx, 0x0590/4, 0x70605040);
-	nv_wo32(dev, ctx, 0x0594/4, 0xb8a89888);
-	nv_wo32(dev, ctx, 0x0598/4, 0xf8e8d8c8);
-	nv_wo32(dev, ctx, 0x05ac/4, 0xb0000000);
+		nv_wo32(ctx, i, 0x07ff0000);
+	nv_wo32(ctx, 0x054c, 0x4b7fffff);
+	nv_wo32(ctx, 0x0588, 0x00000080);
+	nv_wo32(ctx, 0x058c, 0x30201000);
+	nv_wo32(ctx, 0x0590, 0x70605040);
+	nv_wo32(ctx, 0x0594, 0xb8a89888);
+	nv_wo32(ctx, 0x0598, 0xf8e8d8c8);
+	nv_wo32(ctx, 0x05ac, 0xb0000000);
 	for (i = 0x0604; i < 0x0644; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00010588);
+		nv_wo32(ctx, i, 0x00010588);
 	for (i = 0x0644; i < 0x0684; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00030303);
+		nv_wo32(ctx, i, 0x00030303);
 	for (i = 0x06c4; i < 0x0704; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0008aae4);
+		nv_wo32(ctx, i, 0x0008aae4);
 	for (i = 0x0704; i < 0x0744; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x01012000);
+		nv_wo32(ctx, i, 0x01012000);
 	for (i = 0x0744; i < 0x0784; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00080008);
-	nv_wo32(dev, ctx, 0x0860/4, 0x00040000);
-	nv_wo32(dev, ctx, 0x0864/4, 0x00010000);
+		nv_wo32(ctx, i, 0x00080008);
+	nv_wo32(ctx, 0x0860, 0x00040000);
+	nv_wo32(ctx, 0x0864, 0x00010000);
 	for (i = 0x0868; i < 0x0878; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x00040004);
+		nv_wo32(ctx, i, 0x00040004);
 	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
-		nv_wo32(dev, ctx, i/4 + 0, 0x10700ff9);
-		nv_wo32(dev, ctx, i/4 + 1, 0x0436086c);
-		nv_wo32(dev, ctx, i/4 + 2, 0x000c001b);
+		nv_wo32(ctx, i + 0, 0x10700ff9);
+		nv_wo32(ctx, i + 4, 0x0436086c);
+		nv_wo32(ctx, i + 8, 0x000c001b);
 	}
 	for (i = 0x30bc; i < 0x30cc; i += 4)
-		nv_wo32(dev, ctx, i/4, 0x0000ffff);
-	nv_wo32(dev, ctx, 0x3450/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x380c/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3820/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x384c/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x3850/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3854/4, 0x3f000000);
-	nv_wo32(dev, ctx, 0x385c/4, 0x40000000);
-	nv_wo32(dev, ctx, 0x3860/4, 0x3f800000);
-	nv_wo32(dev, ctx, 0x3868/4, 0xbf800000);
-	nv_wo32(dev, ctx, 0x3870/4, 0xbf800000);
+		nv_wo32(ctx, i, 0x0000ffff);
+	nv_wo32(ctx, 0x3450, 0x3f800000);
+	nv_wo32(ctx, 0x380c, 0x3f800000);
+	nv_wo32(ctx, 0x3820, 0x3f800000);
+	nv_wo32(ctx, 0x384c, 0x40000000);
+	nv_wo32(ctx, 0x3850, 0x3f800000);
+	nv_wo32(ctx, 0x3854, 0x3f000000);
+	nv_wo32(ctx, 0x385c, 0x40000000);
+	nv_wo32(ctx, 0x3860, 0x3f800000);
+	nv_wo32(ctx, 0x3868, 0xbf800000);
+	nv_wo32(ctx, 0x3870, 0xbf800000);
 }
 
 int
@@ -372,7 +372,7 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 	void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
-	unsigned int idoffs = 0x28/4;
+	unsigned int idoffs = 0x28;
 	int ret;
 
 	switch (dev_priv->chipset) {
@@ -403,21 +403,19 @@
 		BUG_ON(1);
 	}
 
-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-				     16, NVOBJ_FLAG_ZERO_ALLOC,
-				     &chan->ramin_grctx);
+	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
 	if (ret)
 		return ret;
 
 	/* Initialise default context values */
-	ctx_init(dev, chan->ramin_grctx->gpuobj);
+	ctx_init(dev, chan->ramin_grctx);
 
 	/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-	nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
-					(chan->id << 24) | 0x1); /* CTX_USER */
+	nv_wo32(chan->ramin_grctx, idoffs,
+		(chan->id << 24) | 0x1); /* CTX_USER */
 
-	nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
-		     chan->ramin_grctx->instance >> 4);
+	nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
 	return 0;
 }
 
@@ -428,10 +426,8 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 
-	if (chan->ramin_grctx)
-		nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
-
-	nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
+	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+	nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
 }
 
 int
@@ -442,7 +438,7 @@
 
 	if (!chan->ramin_grctx)
 		return -EINVAL;
-	inst = chan->ramin_grctx->instance >> 4;
+	inst = chan->ramin_grctx->pinst >> 4;
 
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -465,7 +461,7 @@
 	chan = pgraph->channel(dev);
 	if (!chan)
 		return 0;
-	inst = chan->ramin_grctx->instance >> 4;
+	inst = chan->ramin_grctx->pinst >> 4;
 
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
@@ -552,15 +548,15 @@
 
 	if (!pgraph->ctx_table) {
 		/* Create Context Pointer Table */
-		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
-						  NVOBJ_FLAG_ZERO_ALLOC,
-						  &pgraph->ctx_table);
+		ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+					 NVOBJ_FLAG_ZERO_ALLOC,
+					 &pgraph->ctx_table);
 		if (ret)
 			return ret;
 	}
 
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-		     pgraph->ctx_table->instance >> 4);
+		     pgraph->ctx_table->pinst >> 4);
 
 	nv20_graph_rdi(dev);
 
@@ -646,7 +642,7 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 
-	nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
+	nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
 }
 
 int
@@ -681,15 +677,15 @@
 
 	if (!pgraph->ctx_table) {
 		/* Create Context Pointer Table */
-		ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
-						  NVOBJ_FLAG_ZERO_ALLOC,
-						  &pgraph->ctx_table);
+		ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
+					 NVOBJ_FLAG_ZERO_ALLOC,
+					 &pgraph->ctx_table);
 		if (ret)
 			return ret;
 	}
 
 	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-		     pgraph->ctx_table->instance >> 4);
+		     pgraph->ctx_table->pinst >> 4);
 
 	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
 	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,8 +27,9 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
+#include "nouveau_ramht.h"
 
-#define NV40_RAMFC(c) (dev_priv->ramfc_offset + ((c) * NV40_RAMFC__SIZE))
+#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE))
 #define NV40_RAMFC__SIZE 128
 
 int
@@ -42,7 +43,7 @@
 
 	ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
 				      NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
-				      NVOBJ_FLAG_ZERO_FREE, NULL, &chan->ramfc);
+				      NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
 	if (ret)
 		return ret;
 
@@ -50,7 +51,7 @@
 
 	nv_wi32(dev, fc +  0, chan->pushbuf_base);
 	nv_wi32(dev, fc +  4, chan->pushbuf_base);
-	nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
+	nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
 	nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
 			      NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
 			      NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
@@ -58,7 +59,7 @@
 			      NV_PFIFO_CACHE1_BIG_ENDIAN |
 #endif
 			      0x30000000 /* no idea.. */);
-	nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
+	nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4);
 	nv_wi32(dev, fc + 60, 0x0001FFFF);
 
 	/* enable the fifo dma operation */
@@ -77,8 +78,7 @@
 	nv_wr32(dev, NV04_PFIFO_MODE,
 		nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id));
 
-	if (chan->ramfc)
-		nouveau_gpuobj_ref_del(dev, &chan->ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->ramfc);
 }
 
 static void
@@ -241,9 +241,9 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
 	nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
-				       ((dev_priv->ramht_bits - 9) << 16) |
-				       (dev_priv->ramht_offset >> 8));
-	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro_offset>>8);
+				       ((dev_priv->ramht->bits - 9) << 16) |
+				       (dev_priv->ramht->gpuobj->pinst >> 8));
+	nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
 
 	switch (dev_priv->chipset) {
 	case 0x47:
@@ -271,7 +271,7 @@
 		nv_wr32(dev, 0x2230, 0);
 		nv_wr32(dev, NV40_PFIFO_RAMFC,
 			((dev_priv->vram_size - 512 * 1024 +
-			  dev_priv->ramfc_offset) >> 16) | (3 << 16));
+			  dev_priv->ramfc->pinst) >> 16) | (3 << 16));
 		break;
 	}
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_graph.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_graph.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_graph.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_graph.c	2011-01-04 19:50:19.000000000 -0500
@@ -45,7 +45,7 @@
 		struct nouveau_channel *chan = dev_priv->fifos[i];
 
 		if (chan && chan->ramin_grctx &&
-		    chan->ramin_grctx->instance == inst)
+		    chan->ramin_grctx->pinst == inst)
 			return chan;
 	}
 
@@ -61,27 +61,25 @@
 	struct nouveau_grctx ctx = {};
 	int ret;
 
-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-				     16, NVOBJ_FLAG_ZERO_ALLOC,
-				     &chan->ramin_grctx);
+	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
 	if (ret)
 		return ret;
 
 	/* Initialise default context values */
 	ctx.dev = chan->dev;
 	ctx.mode = NOUVEAU_GRCTX_VALS;
-	ctx.data = chan->ramin_grctx->gpuobj;
+	ctx.data = chan->ramin_grctx;
 	nv40_grctx_init(&ctx);
 
-	nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
-		     chan->ramin_grctx->gpuobj->im_pramin->start);
+	nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
 	return 0;
 }
 
 void
 nv40_graph_destroy_context(struct nouveau_channel *chan)
 {
-	nouveau_gpuobj_ref_del(chan->dev, &chan->ramin_grctx);
+	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
 }
 
 static int
@@ -135,7 +133,7 @@
 
 	if (!chan->ramin_grctx)
 		return -EINVAL;
-	inst = chan->ramin_grctx->instance >> 4;
+	inst = chan->ramin_grctx->pinst >> 4;
 
 	ret = nv40_graph_transfer_context(dev, inst, 0);
 	if (ret)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_grctx.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_grctx.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv40_grctx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv40_grctx.c	2011-01-04 19:50:19.000000000 -0500
@@ -596,13 +596,13 @@
 
 	offset += 0x0280/4;
 	for (i = 0; i < 16; i++, offset += 2)
-		nv_wo32(dev, obj, offset, 0x3f800000);
+		nv_wo32(obj, offset * 4, 0x3f800000);
 
 	for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
 		for (i = 0; i < vs_nr_b0 * 6; i += 6)
-			nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001);
+			nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
 		for (i = 0; i < vs_nr_b1 * 4; i += 4)
-			nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000);
+			nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
 	}
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_calc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_calc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_calc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_calc.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,24 +51,28 @@
 	       int *N, int *fN, int *M, int *P)
 {
 	fixed20_12 fb_div, a, b;
+	u32 refclk = pll->refclk / 10;
+	u32 max_vco_freq = pll->vco1.maxfreq / 10;
+	u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
+	clk /= 10;
 
-	*P = pll->vco1.maxfreq / clk;
+	*P = max_vco_freq / clk;
 	if (*P > pll->max_p)
 		*P = pll->max_p;
 	if (*P < pll->min_p)
 		*P = pll->min_p;
 
-	/* *M = ceil(refclk / pll->vco.max_inputfreq); */
-	a.full = dfixed_const(pll->refclk);
-	b.full = dfixed_const(pll->vco1.max_inputfreq);
+	/* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
+	a.full = dfixed_const(refclk + max_vco_inputfreq);
+	b.full = dfixed_const(max_vco_inputfreq);
 	a.full = dfixed_div(a, b);
-	a.full = dfixed_ceil(a);
+	a.full = dfixed_floor(a);
 	*M = dfixed_trunc(a);
 
 	/* fb_div = (vco * *M) / refclk; */
 	fb_div.full = dfixed_const(clk * *P);
 	fb_div.full = dfixed_mul(fb_div, a);
-	a.full = dfixed_const(pll->refclk);
+	a.full = dfixed_const(refclk);
 	fb_div.full = dfixed_div(fb_div, a);
 
 	/* *N = floor(fb_div); */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_crtc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_crtc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_crtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_crtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -104,8 +104,7 @@
 		OUT_RING(evo, nv_crtc->lut.depth == 8 ?
 				NV50_EVO_CRTC_CLUT_MODE_OFF :
 				NV50_EVO_CRTC_CLUT_MODE_ON);
-		OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.mm_node->start <<
-				 PAGE_SHIFT) >> 8);
+		OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.start << PAGE_SHIFT) >> 8);
 		if (dev_priv->chipset != 0x50) {
 			BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
 			OUT_RING(evo, NvEvoVRAM);
@@ -266,15 +265,10 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct pll_lims pll;
-	uint32_t reg, reg1, reg2;
+	uint32_t reg1, reg2;
 	int ret, N1, M1, N2, M2, P;
 
-	if (dev_priv->chipset < NV_C0)
-		reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
-	else
-		reg = 0x614140 + (head * 0x800);
-
-	ret = get_pll_limits(dev, reg, &pll);
+	ret = get_pll_limits(dev, PLL_VPLL0 + head, &pll);
 	if (ret)
 		return ret;
 
@@ -286,11 +280,11 @@
 		NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
 			 pclk, ret, N1, M1, N2, M2, P);
 
-		reg1 = nv_rd32(dev, reg + 4) & 0xff00ff00;
-		reg2 = nv_rd32(dev, reg + 8) & 0x8000ff00;
-		nv_wr32(dev, reg, 0x10000611);
-		nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
-		nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
+		reg1 = nv_rd32(dev, pll.reg + 4) & 0xff00ff00;
+		reg2 = nv_rd32(dev, pll.reg + 8) & 0x8000ff00;
+		nv_wr32(dev, pll.reg + 0, 0x10000611);
+		nv_wr32(dev, pll.reg + 4, reg1 | (M1 << 16) | N1);
+		nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
 	} else
 	if (dev_priv->chipset < NV_C0) {
 		ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
@@ -300,10 +294,10 @@
 		NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
 			 pclk, ret, N1, N2, M1, P);
 
-		reg1 = nv_rd32(dev, reg + 4) & 0xffc00000;
-		nv_wr32(dev, reg, 0x50000610);
-		nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
-		nv_wr32(dev, reg + 8, N2);
+		reg1 = nv_rd32(dev, pll.reg + 4) & 0xffc00000;
+		nv_wr32(dev, pll.reg + 0, 0x50000610);
+		nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
+		nv_wr32(dev, pll.reg + 8, N2);
 	} else {
 		ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
 		if (ret <= 0)
@@ -312,9 +306,9 @@
 		NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
 			 pclk, ret, N1, N2, M1, P);
 
-		nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
-		nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
-		nv_wr32(dev, reg + 0x10, N2 << 16);
+		nv_mask(dev, pll.reg + 0x0c, 0x00000000, 0x00000100);
+		nv_wr32(dev, pll.reg + 0x04, (P << 16) | (N1 << 8) | M1);
+		nv_wr32(dev, pll.reg + 0x10, N2 << 16);
 	}
 
 	return 0;
@@ -338,7 +332,9 @@
 
 	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);
 	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
 	kfree(nv_crtc->mode);
 	kfree(nv_crtc);
@@ -491,8 +487,9 @@
 }
 
 static int
-nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
-			   struct drm_framebuffer *old_fb, bool update)
+nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
+			   struct drm_framebuffer *passed_fb,
+			   int x, int y, bool update, bool atomic)
 {
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct drm_device *dev = nv_crtc->base.dev;
@@ -504,6 +501,28 @@
 
 	NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
+	/* If atomic, we want to switch to the fb we were passed, so
+	 * now we update pointers to do that.  (We don't pin; just
+	 * assume we're already pinned and update the base address.)
+	 */
+	if (atomic) {
+		drm_fb = passed_fb;
+		fb = nouveau_framebuffer(passed_fb);
+	}
+	else {
+		/* If not atomic, we can go ahead and pin, and unpin the
+		 * old fb we were passed.
+		 */
+		ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
+		if (ret)
+			return ret;
+
+		if (passed_fb) {
+			struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb);
+			nouveau_bo_unpin(ofb->nvbo);
+		}
+	}
+
 	switch (drm_fb->depth) {
 	case  8:
 		format = NV50_EVO_CRTC_FB_DEPTH_8;
@@ -526,17 +545,8 @@
 		 return -EINVAL;
 	}
 
-	ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM);
-	if (ret)
-		return ret;
-
-	if (old_fb) {
-		struct nouveau_framebuffer *ofb = nouveau_framebuffer(old_fb);
-		nouveau_bo_unpin(ofb->nvbo);
-	}
-
 	nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
-	nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
+	nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
 	nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
 	if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
 		ret = RING_SPACE(evo, 2);
@@ -568,7 +578,7 @@
 				  fb->nvbo->tile_mode);
 	}
 	if (dev_priv->chipset == 0x50)
-		OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
+		OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
 	else
 		OUT_RING(evo, format);
 
@@ -685,14 +695,22 @@
 	nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false);
 	nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false);
 
-	return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, false);
+	return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false);
 }
 
 static int
 nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 			struct drm_framebuffer *old_fb)
 {
-	return nv50_crtc_do_mode_set_base(crtc, x, y, old_fb, true);
+	return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false);
+}
+
+static int
+nv50_crtc_mode_set_base_atomic(struct drm_crtc *crtc,
+			       struct drm_framebuffer *fb,
+			       int x, int y, enum mode_set_atomic state)
+{
+	return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true);
 }
 
 static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = {
@@ -702,6 +720,7 @@
 	.mode_fixup = nv50_crtc_mode_fixup,
 	.mode_set = nv50_crtc_mode_set,
 	.mode_set_base = nv50_crtc_mode_set_base,
+	.mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
 	.load_lut = nv50_crtc_lut_load,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_cursor.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_cursor.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_cursor.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_cursor.c	2011-01-04 19:50:19.000000000 -0500
@@ -147,7 +147,7 @@
 	NV_DEBUG_KMS(dev, "\n");
 
 	nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
-	if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
+	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",
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_dac.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_dac.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_dac.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_dac.c	2011-01-04 19:50:19.000000000 -0500
@@ -79,7 +79,7 @@
 
 	nv_wr32(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
 		0x00150000 | NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING);
-	if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+	if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
 		     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
 		NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
 		NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -130,7 +130,7 @@
 	NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
 
 	/* wait for it to be done */
-	if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
+	if (!nv_wait(dev, NV50_PDISPLAY_DAC_DPMS_CTRL(or),
 		     NV50_PDISPLAY_DAC_DPMS_CTRL_PENDING, 0)) {
 		NV_ERROR(dev, "timeout: DAC_DPMS_CTRL_PENDING(%d) == 0\n", or);
 		NV_ERROR(dev, "DAC_DPMS_CTRL(%d) = 0x%08x\n", or,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_display.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_display.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_display.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_display.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,8 +30,22 @@
 #include "nouveau_connector.h"
 #include "nouveau_fb.h"
 #include "nouveau_fbcon.h"
+#include "nouveau_ramht.h"
 #include "drm_crtc_helper.h"
 
+static inline int
+nv50_sor_nr(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	if (dev_priv->chipset  < 0x90 ||
+	    dev_priv->chipset == 0x92 ||
+	    dev_priv->chipset == 0xa0)
+		return 2;
+
+	return 4;
+}
+
 static void
 nv50_evo_channel_del(struct nouveau_channel **pchan)
 {
@@ -42,6 +56,7 @@
 	*pchan = NULL;
 
 	nouveau_gpuobj_channel_takedown(chan);
+	nouveau_bo_unmap(chan->pushbuf_bo);
 	nouveau_bo_ref(NULL, &chan->pushbuf_bo);
 
 	if (chan->user)
@@ -65,23 +80,23 @@
 		return ret;
 	obj->engine = NVOBJ_ENGINE_DISPLAY;
 
-	ret = nouveau_gpuobj_ref_add(dev, evo, name, obj, NULL);
-	if (ret) {
-		nouveau_gpuobj_del(dev, &obj);
-		return ret;
-	}
-
-	nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
-	nv_wo32(dev, obj, 1, limit);
-	nv_wo32(dev, obj, 2, offset);
-	nv_wo32(dev, obj, 3, 0x00000000);
-	nv_wo32(dev, obj, 4, 0x00000000);
+	nv_wo32(obj,  0, (tile_flags << 22) | (magic_flags << 16) | class);
+	nv_wo32(obj,  4, limit);
+	nv_wo32(obj,  8, offset);
+	nv_wo32(obj, 12, 0x00000000);
+	nv_wo32(obj, 16, 0x00000000);
 	if (dev_priv->card_type < NV_C0)
-		nv_wo32(dev, obj, 5, 0x00010000);
+		nv_wo32(obj, 20, 0x00010000);
 	else
-		nv_wo32(dev, obj, 5, 0x00020000);
+		nv_wo32(obj, 20, 0x00020000);
 	dev_priv->engine.instmem.flush(dev);
 
+	ret = nouveau_ramht_insert(evo, name, obj);
+	nouveau_gpuobj_ref(NULL, &obj);
+	if (ret) {
+		return ret;
+	}
+
 	return 0;
 }
 
@@ -89,6 +104,7 @@
 nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_gpuobj *ramht = NULL;
 	struct nouveau_channel *chan;
 	int ret;
 
@@ -102,32 +118,35 @@
 	chan->user_get = 4;
 	chan->user_put = 0;
 
-	INIT_LIST_HEAD(&chan->ramht_refs);
-
-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32768, 0x1000,
-				     NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
+	ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin);
 	if (ret) {
 		NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret);
 		nv50_evo_channel_del(pchan);
 		return ret;
 	}
 
-	ret = drm_mm_init(&chan->ramin_heap,
-			  chan->ramin->gpuobj->im_pramin->start, 32768);
+	ret = drm_mm_init(&chan->ramin_heap, 0, 32768);
 	if (ret) {
 		NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
 		nv50_evo_channel_del(pchan);
 		return ret;
 	}
 
-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 4096, 16,
-				     0, &chan->ramht);
+	ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht);
 	if (ret) {
 		NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret);
 		nv50_evo_channel_del(pchan);
 		return ret;
 	}
 
+	ret = nouveau_ramht_new(dev, ramht, &chan->ramht);
+	nouveau_gpuobj_ref(NULL, &ramht);
+	if (ret) {
+		nv50_evo_channel_del(pchan);
+		return ret;
+	}
+
 	if (dev_priv->chipset != 0x50) {
 		ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19,
 					  0, 0xffffffff);
@@ -227,11 +246,11 @@
 		nv_wr32(dev, 0x006101d0 + (i * 0x04), val);
 	}
 	/* SOR */
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < nv50_sor_nr(dev); i++) {
 		val = nv_rd32(dev, 0x0061c000 + (i * 0x800));
 		nv_wr32(dev, 0x006101e0 + (i * 0x04), val);
 	}
-	/* Something not yet in use, tv-out maybe. */
+	/* EXT */
 	for (i = 0; i < 3; i++) {
 		val = nv_rd32(dev, 0x0061e000 + (i * 0x800));
 		nv_wr32(dev, 0x006101f0 + (i * 0x04), val);
@@ -260,7 +279,7 @@
 	if (nv_rd32(dev, NV50_PDISPLAY_INTR_1) & 0x100) {
 		nv_wr32(dev, NV50_PDISPLAY_INTR_1, 0x100);
 		nv_wr32(dev, 0x006194e8, nv_rd32(dev, 0x006194e8) & ~1);
-		if (!nv_wait(0x006194e8, 2, 0)) {
+		if (!nv_wait(dev, 0x006194e8, 2, 0)) {
 			NV_ERROR(dev, "timeout: (0x6194e8 & 2) != 0\n");
 			NV_ERROR(dev, "0x6194e8 = 0x%08x\n",
 						nv_rd32(dev, 0x6194e8));
@@ -291,7 +310,8 @@
 
 	nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE);
 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03);
-	if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x40000000, 0x40000000)) {
+	if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0),
+		     0x40000000, 0x40000000)) {
 		NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n");
 		NV_ERROR(dev, "0x610200 = 0x%08x\n",
 			  nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
@@ -300,7 +320,7 @@
 
 	for (i = 0; i < 2; i++) {
 		nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000);
-		if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+		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",
@@ -310,7 +330,7 @@
 
 		nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
 			NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON);
-		if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
+		if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i),
 			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS,
 			     NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE)) {
 			NV_ERROR(dev, "timeout: "
@@ -321,16 +341,16 @@
 		}
 	}
 
-	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->instance >> 8) | 9);
+	nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9);
 
 	/* initialise fifo */
 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0),
-		((evo->pushbuf_bo->bo.mem.mm_node->start << PAGE_SHIFT) >> 8) |
+		((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) |
 		NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM |
 		NV50_PDISPLAY_CHANNEL_DMA_CB_VALID);
 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000);
 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002);
-	if (!nv_wait(0x610200, 0x80000000, 0x00000000)) {
+	if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) {
 		NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n");
 		NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200));
 		return -EBUSY;
@@ -370,7 +390,7 @@
 	BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1);
 	OUT_RING(evo, 0);
 	FIRE_RING(evo);
-	if (!nv_wait(0x640004, 0xffffffff, evo->dma.put << 2))
+	if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2))
 		NV_ERROR(dev, "evo pushbuf stalled\n");
 
 	/* enable clock change interrupts. */
@@ -424,7 +444,7 @@
 			continue;
 
 		nv_wr32(dev, NV50_PDISPLAY_INTR_1, mask);
-		if (!nv_wait(NV50_PDISPLAY_INTR_1, mask, mask)) {
+		if (!nv_wait(dev, NV50_PDISPLAY_INTR_1, mask, mask)) {
 			NV_ERROR(dev, "timeout: (0x610024 & 0x%08x) == "
 				      "0x%08x\n", mask, mask);
 			NV_ERROR(dev, "0x610024 = 0x%08x\n",
@@ -434,14 +454,14 @@
 
 	nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0);
 	nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0);
-	if (!nv_wait(NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
+	if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) {
 		NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n");
 		NV_ERROR(dev, "0x610200 = 0x%08x\n",
 			  nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)));
 	}
 
 	for (i = 0; i < 3; i++) {
-		if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(i),
+		if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i),
 			     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
 			NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", i);
 			NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", i,
@@ -710,7 +730,7 @@
 		or = i;
 	}
 
-	for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+	for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
 		if (dev_priv->chipset  < 0x90 ||
 		    dev_priv->chipset == 0x92 ||
 		    dev_priv->chipset == 0xa0)
@@ -841,7 +861,7 @@
 		or = i;
 	}
 
-	for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
+	for (i = 0; type == OUTPUT_ANY && i < nv50_sor_nr(dev); i++) {
 		if (dev_priv->chipset  < 0x90 ||
 		    dev_priv->chipset == 0x92 ||
 		    dev_priv->chipset == 0xa0)
@@ -1012,11 +1032,18 @@
 	struct drm_connector *connector;
 	const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
 	uint32_t unplug_mask, plug_mask, change_mask;
-	uint32_t hpd0, hpd1 = 0;
+	uint32_t hpd0, hpd1;
 
-	hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
+	spin_lock_irq(&dev_priv->hpd_state.lock);
+	hpd0 = dev_priv->hpd_state.hpd0_bits;
+	dev_priv->hpd_state.hpd0_bits = 0;
+	hpd1 = dev_priv->hpd_state.hpd1_bits;
+	dev_priv->hpd_state.hpd1_bits = 0;
+	spin_unlock_irq(&dev_priv->hpd_state.lock);
+
+	hpd0 &= nv_rd32(dev, 0xe050);
 	if (dev_priv->chipset >= 0x90)
-		hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
+		hpd1 &= nv_rd32(dev, 0xe070);
 
 	plug_mask   = (hpd0 & 0x0000ffff) | (hpd1 << 16);
 	unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
@@ -1058,10 +1085,6 @@
 			helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
 	}
 
-	nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
-	if (dev_priv->chipset >= 0x90)
-		nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
-
 	drm_helper_hpd_irq_event(dev);
 }
 
@@ -1072,8 +1095,22 @@
 	uint32_t delayed = 0;
 
 	if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
-		if (!work_pending(&dev_priv->hpd_work))
-			queue_work(dev_priv->wq, &dev_priv->hpd_work);
+		uint32_t hpd0_bits, hpd1_bits = 0;
+
+		hpd0_bits = nv_rd32(dev, 0xe054);
+		nv_wr32(dev, 0xe054, hpd0_bits);
+
+		if (dev_priv->chipset >= 0x90) {
+			hpd1_bits = nv_rd32(dev, 0xe074);
+			nv_wr32(dev, 0xe074, hpd1_bits);
+		}
+
+		spin_lock(&dev_priv->hpd_state.lock);
+		dev_priv->hpd_state.hpd0_bits |= hpd0_bits;
+		dev_priv->hpd_state.hpd1_bits |= hpd1_bits;
+		spin_unlock(&dev_priv->hpd_state.lock);
+
+		queue_work(dev_priv->wq, &dev_priv->hpd_work);
 	}
 
 	while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fb.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fb.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fb.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
 	case 0x50:
 		nv_wr32(dev, 0x100c90, 0x0707ff);
 		break;
+	case 0xa3:
 	case 0xa5:
 	case 0xa8:
 		nv_wr32(dev, 0x100c90, 0x0d0fff);
@@ -36,3 +37,42 @@
 nv50_fb_takedown(struct drm_device *dev)
 {
 }
+
+void
+nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 trap[6], idx, chinst;
+	int i, ch;
+
+	idx = nv_rd32(dev, 0x100c90);
+	if (!(idx & 0x80000000))
+		return;
+	idx &= 0x00ffffff;
+
+	for (i = 0; i < 6; i++) {
+		nv_wr32(dev, 0x100c90, idx | i << 24);
+		trap[i] = nv_rd32(dev, 0x100c94);
+	}
+	nv_wr32(dev, 0x100c90, idx | 0x80000000);
+
+	if (!display)
+		return;
+
+	chinst = (trap[2] << 16) | trap[1];
+	for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
+		struct nouveau_channel *chan = dev_priv->fifos[ch];
+
+		if (!chan || !chan->ramin)
+			continue;
+
+		if (chinst == chan->ramin->vinst >> 12)
+			break;
+	}
+
+	NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x "
+		     "channel %d (0x%08x)\n",
+		name, (trap[5] & 0x100 ? "read" : "write"),
+		trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
+		trap[0], ch, chinst);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fbcon.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fbcon.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fbcon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fbcon.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,7 @@
 #include "drmP.h"
 #include "nouveau_drv.h"
 #include "nouveau_dma.h"
+#include "nouveau_ramht.h"
 #include "nouveau_fbcon.h"
 
 void
@@ -193,7 +194,8 @@
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
+	ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
+	nouveau_gpuobj_ref(NULL, &eng2d);
 	if (ret)
 		return ret;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,13 +27,14 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_ramht.h"
 
 static void
 nv50_fifo_playlist_update(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-	struct nouveau_gpuobj_ref *cur;
+	struct nouveau_gpuobj *cur;
 	int i, nr;
 
 	NV_DEBUG(dev, "\n");
@@ -43,12 +44,14 @@
 
 	/* We never schedule channel 0 or 127 */
 	for (i = 1, nr = 0; i < 127; i++) {
-		if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
-			nv_wo32(dev, cur->gpuobj, nr++, i);
+		if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) {
+			nv_wo32(cur, (nr * 4), i);
+			nr++;
+		}
 	}
 	dev_priv->engine.instmem.flush(dev);
 
-	nv_wr32(dev, 0x32f4, cur->instance >> 12);
+	nv_wr32(dev, 0x32f4, cur->vinst >> 12);
 	nv_wr32(dev, 0x32ec, nr);
 	nv_wr32(dev, 0x2500, 0x101);
 }
@@ -63,9 +66,9 @@
 	NV_DEBUG(dev, "ch%d\n", channel);
 
 	if (dev_priv->chipset == 0x50)
-		inst = chan->ramfc->instance >> 12;
+		inst = chan->ramfc->vinst >> 12;
 	else
-		inst = chan->ramfc->instance >> 8;
+		inst = chan->ramfc->vinst >> 8;
 
 	nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
 		     NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
@@ -163,19 +166,19 @@
 		goto just_reset;
 	}
 
-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
-				     NVOBJ_FLAG_ZERO_ALLOC,
-				     &pfifo->playlist[0]);
+	ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC,
+				 &pfifo->playlist[0]);
 	if (ret) {
 		NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
 		return ret;
 	}
 
-	ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
-				     NVOBJ_FLAG_ZERO_ALLOC,
-				     &pfifo->playlist[1]);
+	ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC,
+				 &pfifo->playlist[1]);
 	if (ret) {
-		nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
+		nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
 		NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
 		return ret;
 	}
@@ -203,8 +206,8 @@
 	if (!pfifo->playlist[0])
 		return;
 
-	nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
-	nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
+	nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
+	nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
 }
 
 int
@@ -226,59 +229,54 @@
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
 	if (dev_priv->chipset == 0x50) {
-		uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
-		uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
-
-		ret = nouveau_gpuobj_new_fake(dev, ramin_poffset, ramin_voffset,
-					      0x100, NVOBJ_FLAG_ZERO_ALLOC |
-					      NVOBJ_FLAG_ZERO_FREE, &ramfc,
+		ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
+					      chan->ramin->vinst, 0x100,
+					      NVOBJ_FLAG_ZERO_ALLOC |
+					      NVOBJ_FLAG_ZERO_FREE,
 					      &chan->ramfc);
 		if (ret)
 			return ret;
 
-		ret = nouveau_gpuobj_new_fake(dev, ramin_poffset + 0x0400,
-					      ramin_voffset + 0x0400, 4096,
-					      0, NULL, &chan->cache);
+		ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400,
+					      chan->ramin->vinst + 0x0400,
+					      4096, 0, &chan->cache);
 		if (ret)
 			return ret;
 	} else {
-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 0x100, 256,
-					     NVOBJ_FLAG_ZERO_ALLOC |
-					     NVOBJ_FLAG_ZERO_FREE,
-					     &chan->ramfc);
+		ret = nouveau_gpuobj_new(dev, chan, 0x100, 256,
+					 NVOBJ_FLAG_ZERO_ALLOC |
+					 NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
 		if (ret)
 			return ret;
-		ramfc = chan->ramfc->gpuobj;
 
-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
-					     0, &chan->cache);
+		ret = nouveau_gpuobj_new(dev, chan, 4096, 1024,
+					 0, &chan->cache);
 		if (ret)
 			return ret;
 	}
+	ramfc = chan->ramfc;
 
 	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
 
-	nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
-	nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
-				    (4 << 24) /* SEARCH_FULL */ |
-				    (chan->ramht->instance >> 4));
-	nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
-	nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
-	nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
-	nv_wo32(dev, ramfc, 0x7c/4, 0x30000001);
-	nv_wo32(dev, ramfc, 0x78/4, 0x00000000);
-	nv_wo32(dev, ramfc, 0x3c/4, 0x403f6078);
-	nv_wo32(dev, ramfc, 0x50/4, chan->pushbuf_base +
-				    chan->dma.ib_base * 4);
-	nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
+	nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
+	nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+			     (4 << 24) /* SEARCH_FULL */ |
+			     (chan->ramht->gpuobj->cinst >> 4));
+	nv_wo32(ramfc, 0x44, 0x2101ffff);
+	nv_wo32(ramfc, 0x60, 0x7fffffff);
+	nv_wo32(ramfc, 0x40, 0x00000000);
+	nv_wo32(ramfc, 0x7c, 0x30000001);
+	nv_wo32(ramfc, 0x78, 0x00000000);
+	nv_wo32(ramfc, 0x3c, 0x403f6078);
+	nv_wo32(ramfc, 0x50, chan->pushbuf_base + chan->dma.ib_base * 4);
+	nv_wo32(ramfc, 0x54, drm_order(chan->dma.ib_max + 1) << 16);
 
 	if (dev_priv->chipset != 0x50) {
-		nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
-		nv_wo32(dev, chan->ramin->gpuobj, 1,
-						chan->ramfc->instance >> 8);
+		nv_wo32(chan->ramin, 0, chan->id);
+		nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8);
 
-		nv_wo32(dev, ramfc, 0x88/4, chan->cache->instance >> 10);
-		nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
+		nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10);
+		nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12);
 	}
 
 	dev_priv->engine.instmem.flush(dev);
@@ -293,12 +291,13 @@
 nv50_fifo_destroy_context(struct nouveau_channel *chan)
 {
 	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj_ref *ramfc = chan->ramfc;
+	struct nouveau_gpuobj *ramfc = NULL;
 
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
 	/* This will ensure the channel is seen as disabled. */
-	chan->ramfc = NULL;
+	nouveau_gpuobj_ref(chan->ramfc, &ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->ramfc);
 	nv50_fifo_channel_disable(dev, chan->id);
 
 	/* Dummy channel, also used on ch 127 */
@@ -306,8 +305,8 @@
 		nv50_fifo_channel_disable(dev, 127);
 	nv50_fifo_playlist_update(dev);
 
-	nouveau_gpuobj_ref_del(dev, &ramfc);
-	nouveau_gpuobj_ref_del(dev, &chan->cache);
+	nouveau_gpuobj_ref(NULL, &ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->cache);
 }
 
 int
@@ -315,63 +314,63 @@
 {
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *ramfc = chan->ramfc->gpuobj;
-	struct nouveau_gpuobj *cache = chan->cache->gpuobj;
+	struct nouveau_gpuobj *ramfc = chan->ramfc;
+	struct nouveau_gpuobj *cache = chan->cache;
 	int ptr, cnt;
 
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
-	nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
-	nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
-	nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
-	nv_wr32(dev, 0x3320, nv_ro32(dev, ramfc, 0x0c/4));
-	nv_wr32(dev, 0x3244, nv_ro32(dev, ramfc, 0x10/4));
-	nv_wr32(dev, 0x3328, nv_ro32(dev, ramfc, 0x14/4));
-	nv_wr32(dev, 0x3368, nv_ro32(dev, ramfc, 0x18/4));
-	nv_wr32(dev, 0x336c, nv_ro32(dev, ramfc, 0x1c/4));
-	nv_wr32(dev, 0x3370, nv_ro32(dev, ramfc, 0x20/4));
-	nv_wr32(dev, 0x3374, nv_ro32(dev, ramfc, 0x24/4));
-	nv_wr32(dev, 0x3378, nv_ro32(dev, ramfc, 0x28/4));
-	nv_wr32(dev, 0x337c, nv_ro32(dev, ramfc, 0x2c/4));
-	nv_wr32(dev, 0x3228, nv_ro32(dev, ramfc, 0x30/4));
-	nv_wr32(dev, 0x3364, nv_ro32(dev, ramfc, 0x34/4));
-	nv_wr32(dev, 0x32a0, nv_ro32(dev, ramfc, 0x38/4));
-	nv_wr32(dev, 0x3224, nv_ro32(dev, ramfc, 0x3c/4));
-	nv_wr32(dev, 0x324c, nv_ro32(dev, ramfc, 0x40/4));
-	nv_wr32(dev, 0x2044, nv_ro32(dev, ramfc, 0x44/4));
-	nv_wr32(dev, 0x322c, nv_ro32(dev, ramfc, 0x48/4));
-	nv_wr32(dev, 0x3234, nv_ro32(dev, ramfc, 0x4c/4));
-	nv_wr32(dev, 0x3340, nv_ro32(dev, ramfc, 0x50/4));
-	nv_wr32(dev, 0x3344, nv_ro32(dev, ramfc, 0x54/4));
-	nv_wr32(dev, 0x3280, nv_ro32(dev, ramfc, 0x58/4));
-	nv_wr32(dev, 0x3254, nv_ro32(dev, ramfc, 0x5c/4));
-	nv_wr32(dev, 0x3260, nv_ro32(dev, ramfc, 0x60/4));
-	nv_wr32(dev, 0x3264, nv_ro32(dev, ramfc, 0x64/4));
-	nv_wr32(dev, 0x3268, nv_ro32(dev, ramfc, 0x68/4));
-	nv_wr32(dev, 0x326c, nv_ro32(dev, ramfc, 0x6c/4));
-	nv_wr32(dev, 0x32e4, nv_ro32(dev, ramfc, 0x70/4));
-	nv_wr32(dev, 0x3248, nv_ro32(dev, ramfc, 0x74/4));
-	nv_wr32(dev, 0x2088, nv_ro32(dev, ramfc, 0x78/4));
-	nv_wr32(dev, 0x2058, nv_ro32(dev, ramfc, 0x7c/4));
-	nv_wr32(dev, 0x2210, nv_ro32(dev, ramfc, 0x80/4));
+	nv_wr32(dev, 0x3330, nv_ro32(ramfc, 0x00));
+	nv_wr32(dev, 0x3334, nv_ro32(ramfc, 0x04));
+	nv_wr32(dev, 0x3240, nv_ro32(ramfc, 0x08));
+	nv_wr32(dev, 0x3320, nv_ro32(ramfc, 0x0c));
+	nv_wr32(dev, 0x3244, nv_ro32(ramfc, 0x10));
+	nv_wr32(dev, 0x3328, nv_ro32(ramfc, 0x14));
+	nv_wr32(dev, 0x3368, nv_ro32(ramfc, 0x18));
+	nv_wr32(dev, 0x336c, nv_ro32(ramfc, 0x1c));
+	nv_wr32(dev, 0x3370, nv_ro32(ramfc, 0x20));
+	nv_wr32(dev, 0x3374, nv_ro32(ramfc, 0x24));
+	nv_wr32(dev, 0x3378, nv_ro32(ramfc, 0x28));
+	nv_wr32(dev, 0x337c, nv_ro32(ramfc, 0x2c));
+	nv_wr32(dev, 0x3228, nv_ro32(ramfc, 0x30));
+	nv_wr32(dev, 0x3364, nv_ro32(ramfc, 0x34));
+	nv_wr32(dev, 0x32a0, nv_ro32(ramfc, 0x38));
+	nv_wr32(dev, 0x3224, nv_ro32(ramfc, 0x3c));
+	nv_wr32(dev, 0x324c, nv_ro32(ramfc, 0x40));
+	nv_wr32(dev, 0x2044, nv_ro32(ramfc, 0x44));
+	nv_wr32(dev, 0x322c, nv_ro32(ramfc, 0x48));
+	nv_wr32(dev, 0x3234, nv_ro32(ramfc, 0x4c));
+	nv_wr32(dev, 0x3340, nv_ro32(ramfc, 0x50));
+	nv_wr32(dev, 0x3344, nv_ro32(ramfc, 0x54));
+	nv_wr32(dev, 0x3280, nv_ro32(ramfc, 0x58));
+	nv_wr32(dev, 0x3254, nv_ro32(ramfc, 0x5c));
+	nv_wr32(dev, 0x3260, nv_ro32(ramfc, 0x60));
+	nv_wr32(dev, 0x3264, nv_ro32(ramfc, 0x64));
+	nv_wr32(dev, 0x3268, nv_ro32(ramfc, 0x68));
+	nv_wr32(dev, 0x326c, nv_ro32(ramfc, 0x6c));
+	nv_wr32(dev, 0x32e4, nv_ro32(ramfc, 0x70));
+	nv_wr32(dev, 0x3248, nv_ro32(ramfc, 0x74));
+	nv_wr32(dev, 0x2088, nv_ro32(ramfc, 0x78));
+	nv_wr32(dev, 0x2058, nv_ro32(ramfc, 0x7c));
+	nv_wr32(dev, 0x2210, nv_ro32(ramfc, 0x80));
 
-	cnt = nv_ro32(dev, ramfc, 0x84/4);
+	cnt = nv_ro32(ramfc, 0x84);
 	for (ptr = 0; ptr < cnt; ptr++) {
 		nv_wr32(dev, NV40_PFIFO_CACHE1_METHOD(ptr),
-			nv_ro32(dev, cache, (ptr * 2) + 0));
+			nv_ro32(cache, (ptr * 8) + 0));
 		nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr),
-			nv_ro32(dev, cache, (ptr * 2) + 1));
+			nv_ro32(cache, (ptr * 8) + 4));
 	}
 	nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2);
 	nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
 
 	/* guessing that all the 0x34xx regs aren't on NV50 */
 	if (dev_priv->chipset != 0x50) {
-		nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
-		nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
-		nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
-		nv_wr32(dev, 0x3408, nv_ro32(dev, ramfc, 0x94/4));
-		nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
+		nv_wr32(dev, 0x340c, nv_ro32(ramfc, 0x88));
+		nv_wr32(dev, 0x3400, nv_ro32(ramfc, 0x8c));
+		nv_wr32(dev, 0x3404, nv_ro32(ramfc, 0x90));
+		nv_wr32(dev, 0x3408, nv_ro32(ramfc, 0x94));
+		nv_wr32(dev, 0x3410, nv_ro32(ramfc, 0x98));
 	}
 
 	nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
@@ -399,62 +398,63 @@
 		return -EINVAL;
 	}
 	NV_DEBUG(dev, "ch%d\n", chan->id);
-	ramfc = chan->ramfc->gpuobj;
-	cache = chan->cache->gpuobj;
+	ramfc = chan->ramfc;
+	cache = chan->cache;
 
-	nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
-	nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
-	nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
-	nv_wo32(dev, ramfc, 0x0c/4, nv_rd32(dev, 0x3320));
-	nv_wo32(dev, ramfc, 0x10/4, nv_rd32(dev, 0x3244));
-	nv_wo32(dev, ramfc, 0x14/4, nv_rd32(dev, 0x3328));
-	nv_wo32(dev, ramfc, 0x18/4, nv_rd32(dev, 0x3368));
-	nv_wo32(dev, ramfc, 0x1c/4, nv_rd32(dev, 0x336c));
-	nv_wo32(dev, ramfc, 0x20/4, nv_rd32(dev, 0x3370));
-	nv_wo32(dev, ramfc, 0x24/4, nv_rd32(dev, 0x3374));
-	nv_wo32(dev, ramfc, 0x28/4, nv_rd32(dev, 0x3378));
-	nv_wo32(dev, ramfc, 0x2c/4, nv_rd32(dev, 0x337c));
-	nv_wo32(dev, ramfc, 0x30/4, nv_rd32(dev, 0x3228));
-	nv_wo32(dev, ramfc, 0x34/4, nv_rd32(dev, 0x3364));
-	nv_wo32(dev, ramfc, 0x38/4, nv_rd32(dev, 0x32a0));
-	nv_wo32(dev, ramfc, 0x3c/4, nv_rd32(dev, 0x3224));
-	nv_wo32(dev, ramfc, 0x40/4, nv_rd32(dev, 0x324c));
-	nv_wo32(dev, ramfc, 0x44/4, nv_rd32(dev, 0x2044));
-	nv_wo32(dev, ramfc, 0x48/4, nv_rd32(dev, 0x322c));
-	nv_wo32(dev, ramfc, 0x4c/4, nv_rd32(dev, 0x3234));
-	nv_wo32(dev, ramfc, 0x50/4, nv_rd32(dev, 0x3340));
-	nv_wo32(dev, ramfc, 0x54/4, nv_rd32(dev, 0x3344));
-	nv_wo32(dev, ramfc, 0x58/4, nv_rd32(dev, 0x3280));
-	nv_wo32(dev, ramfc, 0x5c/4, nv_rd32(dev, 0x3254));
-	nv_wo32(dev, ramfc, 0x60/4, nv_rd32(dev, 0x3260));
-	nv_wo32(dev, ramfc, 0x64/4, nv_rd32(dev, 0x3264));
-	nv_wo32(dev, ramfc, 0x68/4, nv_rd32(dev, 0x3268));
-	nv_wo32(dev, ramfc, 0x6c/4, nv_rd32(dev, 0x326c));
-	nv_wo32(dev, ramfc, 0x70/4, nv_rd32(dev, 0x32e4));
-	nv_wo32(dev, ramfc, 0x74/4, nv_rd32(dev, 0x3248));
-	nv_wo32(dev, ramfc, 0x78/4, nv_rd32(dev, 0x2088));
-	nv_wo32(dev, ramfc, 0x7c/4, nv_rd32(dev, 0x2058));
-	nv_wo32(dev, ramfc, 0x80/4, nv_rd32(dev, 0x2210));
+	nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330));
+	nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334));
+	nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240));
+	nv_wo32(ramfc, 0x0c, nv_rd32(dev, 0x3320));
+	nv_wo32(ramfc, 0x10, nv_rd32(dev, 0x3244));
+	nv_wo32(ramfc, 0x14, nv_rd32(dev, 0x3328));
+	nv_wo32(ramfc, 0x18, nv_rd32(dev, 0x3368));
+	nv_wo32(ramfc, 0x1c, nv_rd32(dev, 0x336c));
+	nv_wo32(ramfc, 0x20, nv_rd32(dev, 0x3370));
+	nv_wo32(ramfc, 0x24, nv_rd32(dev, 0x3374));
+	nv_wo32(ramfc, 0x28, nv_rd32(dev, 0x3378));
+	nv_wo32(ramfc, 0x2c, nv_rd32(dev, 0x337c));
+	nv_wo32(ramfc, 0x30, nv_rd32(dev, 0x3228));
+	nv_wo32(ramfc, 0x34, nv_rd32(dev, 0x3364));
+	nv_wo32(ramfc, 0x38, nv_rd32(dev, 0x32a0));
+	nv_wo32(ramfc, 0x3c, nv_rd32(dev, 0x3224));
+	nv_wo32(ramfc, 0x40, nv_rd32(dev, 0x324c));
+	nv_wo32(ramfc, 0x44, nv_rd32(dev, 0x2044));
+	nv_wo32(ramfc, 0x48, nv_rd32(dev, 0x322c));
+	nv_wo32(ramfc, 0x4c, nv_rd32(dev, 0x3234));
+	nv_wo32(ramfc, 0x50, nv_rd32(dev, 0x3340));
+	nv_wo32(ramfc, 0x54, nv_rd32(dev, 0x3344));
+	nv_wo32(ramfc, 0x58, nv_rd32(dev, 0x3280));
+	nv_wo32(ramfc, 0x5c, nv_rd32(dev, 0x3254));
+	nv_wo32(ramfc, 0x60, nv_rd32(dev, 0x3260));
+	nv_wo32(ramfc, 0x64, nv_rd32(dev, 0x3264));
+	nv_wo32(ramfc, 0x68, nv_rd32(dev, 0x3268));
+	nv_wo32(ramfc, 0x6c, nv_rd32(dev, 0x326c));
+	nv_wo32(ramfc, 0x70, nv_rd32(dev, 0x32e4));
+	nv_wo32(ramfc, 0x74, nv_rd32(dev, 0x3248));
+	nv_wo32(ramfc, 0x78, nv_rd32(dev, 0x2088));
+	nv_wo32(ramfc, 0x7c, nv_rd32(dev, 0x2058));
+	nv_wo32(ramfc, 0x80, nv_rd32(dev, 0x2210));
 
 	put = (nv_rd32(dev, NV03_PFIFO_CACHE1_PUT) & 0x7ff) >> 2;
 	get = (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) & 0x7ff) >> 2;
 	ptr = 0;
 	while (put != get) {
-		nv_wo32(dev, cache, ptr++,
-			    nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
-		nv_wo32(dev, cache, ptr++,
-			    nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
+		nv_wo32(cache, ptr + 0,
+			nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
+		nv_wo32(cache, ptr + 4,
+			nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
 		get = (get + 1) & 0x1ff;
+		ptr += 8;
 	}
 
 	/* guessing that all the 0x34xx regs aren't on NV50 */
 	if (dev_priv->chipset != 0x50) {
-		nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
-		nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
-		nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
-		nv_wo32(dev, ramfc, 0x90/4, nv_rd32(dev, 0x3404));
-		nv_wo32(dev, ramfc, 0x94/4, nv_rd32(dev, 0x3408));
-		nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
+		nv_wo32(ramfc, 0x84, ptr >> 3);
+		nv_wo32(ramfc, 0x88, nv_rd32(dev, 0x340c));
+		nv_wo32(ramfc, 0x8c, nv_rd32(dev, 0x3400));
+		nv_wo32(ramfc, 0x90, nv_rd32(dev, 0x3404));
+		nv_wo32(ramfc, 0x94, nv_rd32(dev, 0x3408));
+		nv_wo32(ramfc, 0x98, nv_rd32(dev, 0x3410));
 	}
 
 	dev_priv->engine.instmem.flush(dev);
@@ -464,3 +464,8 @@
 	return 0;
 }
 
+void
+nv50_fifo_tlb_flush(struct drm_device *dev)
+{
+	nv50_vm_flush(dev, 5);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_graph.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_graph.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_graph.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_graph.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,7 +27,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
-
+#include "nouveau_ramht.h"
 #include "nouveau_grctx.h"
 
 static void
@@ -181,7 +181,7 @@
 	/* Be sure we're not in the middle of a context switch or bad things
 	 * will happen, such as unloading the wrong pgraph context.
 	 */
-	if (!nv_wait(0x400300, 0x00000001, 0x00000000))
+	if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
 		NV_ERROR(dev, "Ctxprog is still running\n");
 
 	inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
@@ -192,7 +192,7 @@
 	for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
 		struct nouveau_channel *chan = dev_priv->fifos[i];
 
-		if (chan && chan->ramin && chan->ramin->instance == inst)
+		if (chan && chan->ramin && chan->ramin->vinst == inst)
 			return chan;
 	}
 
@@ -204,36 +204,34 @@
 {
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
-	struct nouveau_gpuobj *obj;
+	struct nouveau_gpuobj *ramin = chan->ramin;
 	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 	struct nouveau_grctx ctx = {};
 	int hdr, ret;
 
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
-				     0x1000, NVOBJ_FLAG_ZERO_ALLOC |
-				     NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+	ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000,
+				 NVOBJ_FLAG_ZERO_ALLOC |
+				 NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
 	if (ret)
 		return ret;
-	obj = chan->ramin_grctx->gpuobj;
 
 	hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-	nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
-	nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
-					   pgraph->grctx_size - 1);
-	nv_wo32(dev, ramin, (hdr + 0x08)/4, chan->ramin_grctx->instance);
-	nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
-	nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
-	nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
+	nv_wo32(ramin, hdr + 0x00, 0x00190002);
+	nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
+				   pgraph->grctx_size - 1);
+	nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+	nv_wo32(ramin, hdr + 0x0c, 0);
+	nv_wo32(ramin, hdr + 0x10, 0);
+	nv_wo32(ramin, hdr + 0x14, 0x00010000);
 
 	ctx.dev = chan->dev;
 	ctx.mode = NOUVEAU_GRCTX_VALS;
-	ctx.data = obj;
+	ctx.data = chan->ramin_grctx;
 	nv50_grctx_init(&ctx);
 
-	nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
+	nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
 
 	dev_priv->engine.instmem.flush(dev);
 	return 0;
@@ -248,14 +246,14 @@
 
 	NV_DEBUG(dev, "ch%d\n", chan->id);
 
-	if (!chan->ramin || !chan->ramin->gpuobj)
+	if (!chan->ramin)
 		return;
 
 	for (i = hdr; i < hdr + 24; i += 4)
-		nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
+		nv_wo32(chan->ramin, i, 0);
 	dev_priv->engine.instmem.flush(dev);
 
-	nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
+	nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
 }
 
 static int
@@ -282,7 +280,7 @@
 int
 nv50_graph_load_context(struct nouveau_channel *chan)
 {
-	uint32_t inst = chan->ramin->instance >> 12;
+	uint32_t inst = chan->ramin->vinst >> 12;
 
 	NV_DEBUG(chan->dev, "ch%d\n", chan->id);
 	return nv50_graph_do_load_context(chan->dev, inst);
@@ -327,15 +325,16 @@
 nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass,
 			   int mthd, uint32_t data)
 {
-	struct nouveau_gpuobj_ref *ref = NULL;
+	struct nouveau_gpuobj *gpuobj;
 
-	if (nouveau_gpuobj_ref_find(chan, data, &ref))
+	gpuobj = nouveau_ramht_find(chan, data);
+	if (!gpuobj)
 		return -ENOENT;
 
-	if (nouveau_notifier_offset(ref->gpuobj, NULL))
+	if (nouveau_notifier_offset(gpuobj, NULL))
 		return -EINVAL;
 
-	chan->nvsw.vblsem = ref->gpuobj;
+	chan->nvsw.vblsem = gpuobj;
 	chan->nvsw.vblsem_offset = ~0;
 	return 0;
 }
@@ -403,3 +402,55 @@
 	{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
 	{}
 };
+
+void
+nv50_graph_tlb_flush(struct drm_device *dev)
+{
+	nv50_vm_flush(dev, 0);
+}
+
+void
+nv86_graph_tlb_flush(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
+	bool idle, timeout = false;
+	unsigned long flags;
+	u64 start;
+	u32 tmp;
+
+	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+	nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+
+	start = ptimer->read(dev);
+	do {
+		idle = true;
+
+		for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+	} while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
+
+	if (timeout) {
+		NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+			      "0x%08x 0x%08x 0x%08x 0x%08x\n",
+			 nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
+			 nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+	}
+
+	nv50_vm_flush(dev, 0);
+
+	nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_grctx.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_grctx.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_grctx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_grctx.c	2011-01-04 19:50:19.000000000 -0500
@@ -103,6 +103,9 @@
 #include "nouveau_drv.h"
 #include "nouveau_grctx.h"
 
+#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
+#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
+
 /*
  * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
  * the GPU itself that does context-switching, but it needs a special
@@ -182,6 +185,7 @@
 	case 0xa8:
 	case 0xaa:
 	case 0xac:
+	case 0xaf:
 		break;
 	default:
 		NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
@@ -268,6 +272,9 @@
  */
 
 static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx);
+
+static void
 nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
@@ -286,7 +293,7 @@
 		gr_def(ctx, 0x400840, 0xffe806a8);
 	}
 	gr_def(ctx, 0x400844, 0x00000002);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+	if (IS_NVA3F(dev_priv->chipset))
 		gr_def(ctx, 0x400894, 0x00001000);
 	gr_def(ctx, 0x4008e8, 0x00000003);
 	gr_def(ctx, 0x4008ec, 0x00001000);
@@ -299,13 +306,15 @@
 
 	if (dev_priv->chipset >= 0xa0)
 		cp_ctx(ctx, 0x400b00, 0x1);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
+	if (IS_NVA3F(dev_priv->chipset)) {
 		cp_ctx(ctx, 0x400b10, 0x1);
 		gr_def(ctx, 0x400b10, 0x0001629d);
 		cp_ctx(ctx, 0x400b20, 0x1);
 		gr_def(ctx, 0x400b20, 0x0001629d);
 	}
 
+	nv50_graph_construct_mmio_ddata(ctx);
+
 	/* 0C00: VFETCH */
 	cp_ctx(ctx, 0x400c08, 0x2);
 	gr_def(ctx, 0x400c08, 0x0000fe0c);
@@ -314,7 +323,7 @@
 	if (dev_priv->chipset < 0xa0) {
 		cp_ctx(ctx, 0x401008, 0x4);
 		gr_def(ctx, 0x401014, 0x00001000);
-	} else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa) {
+	} else if (!IS_NVA3F(dev_priv->chipset)) {
 		cp_ctx(ctx, 0x401008, 0x5);
 		gr_def(ctx, 0x401018, 0x00001000);
 	} else {
@@ -368,10 +377,13 @@
 	case 0xa3:
 	case 0xa5:
 	case 0xa8:
+	case 0xaf:
 		gr_def(ctx, 0x401c00, 0x142500df);
 		break;
 	}
 
+	/* 2000 */
+
 	/* 2400 */
 	cp_ctx(ctx, 0x402400, 0x1);
 	if (dev_priv->chipset == 0x50)
@@ -380,12 +392,12 @@
 		cp_ctx(ctx, 0x402408, 0x2);
 	gr_def(ctx, 0x402408, 0x00000600);
 
-	/* 2800 */
+	/* 2800: CSCHED */
 	cp_ctx(ctx, 0x402800, 0x1);
 	if (dev_priv->chipset == 0x50)
 		gr_def(ctx, 0x402800, 0x00000006);
 
-	/* 2C00 */
+	/* 2C00: ZCULL */
 	cp_ctx(ctx, 0x402c08, 0x6);
 	if (dev_priv->chipset != 0x50)
 		gr_def(ctx, 0x402c14, 0x01000000);
@@ -396,23 +408,23 @@
 		cp_ctx(ctx, 0x402ca0, 0x2);
 	if (dev_priv->chipset < 0xa0)
 		gr_def(ctx, 0x402ca0, 0x00000400);
-	else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
+	else if (!IS_NVA3F(dev_priv->chipset))
 		gr_def(ctx, 0x402ca0, 0x00000800);
 	else
 		gr_def(ctx, 0x402ca0, 0x00000400);
 	cp_ctx(ctx, 0x402cac, 0x4);
 
-	/* 3000 */
+	/* 3000: ENG2D */
 	cp_ctx(ctx, 0x403004, 0x1);
 	gr_def(ctx, 0x403004, 0x00000001);
 
-	/* 3404 */
+	/* 3400 */
 	if (dev_priv->chipset >= 0xa0) {
 		cp_ctx(ctx, 0x403404, 0x1);
 		gr_def(ctx, 0x403404, 0x00000001);
 	}
 
-	/* 5000 */
+	/* 5000: CCACHE */
 	cp_ctx(ctx, 0x405000, 0x1);
 	switch (dev_priv->chipset) {
 	case 0x50:
@@ -425,6 +437,7 @@
 	case 0xa8:
 	case 0xaa:
 	case 0xac:
+	case 0xaf:
 		gr_def(ctx, 0x405000, 0x000e0080);
 		break;
 	case 0x86:
@@ -441,210 +454,6 @@
 	cp_ctx(ctx, 0x405024, 0x1);
 	cp_ctx(ctx, 0x40502c, 0x1);
 
-	/* 5400 or maybe 4800 */
-	if (dev_priv->chipset == 0x50) {
-		offset = 0x405400;
-		cp_ctx(ctx, 0x405400, 0xea);
-	} else if (dev_priv->chipset < 0x94) {
-		offset = 0x405400;
-		cp_ctx(ctx, 0x405400, 0xcb);
-	} else if (dev_priv->chipset < 0xa0) {
-		offset = 0x405400;
-		cp_ctx(ctx, 0x405400, 0xcc);
-	} else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		offset = 0x404800;
-		cp_ctx(ctx, 0x404800, 0xda);
-	} else {
-		offset = 0x405400;
-		cp_ctx(ctx, 0x405400, 0xd4);
-	}
-	gr_def(ctx, offset + 0x0c, 0x00000002);
-	gr_def(ctx, offset + 0x10, 0x00000001);
-	if (dev_priv->chipset >= 0x94)
-		offset += 4;
-	gr_def(ctx, offset + 0x1c, 0x00000001);
-	gr_def(ctx, offset + 0x20, 0x00000100);
-	gr_def(ctx, offset + 0x38, 0x00000002);
-	gr_def(ctx, offset + 0x3c, 0x00000001);
-	gr_def(ctx, offset + 0x40, 0x00000001);
-	gr_def(ctx, offset + 0x50, 0x00000001);
-	gr_def(ctx, offset + 0x54, 0x003fffff);
-	gr_def(ctx, offset + 0x58, 0x00001fff);
-	gr_def(ctx, offset + 0x60, 0x00000001);
-	gr_def(ctx, offset + 0x64, 0x00000001);
-	gr_def(ctx, offset + 0x6c, 0x00000001);
-	gr_def(ctx, offset + 0x70, 0x00000001);
-	gr_def(ctx, offset + 0x74, 0x00000001);
-	gr_def(ctx, offset + 0x78, 0x00000004);
-	gr_def(ctx, offset + 0x7c, 0x00000001);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		offset += 4;
-	gr_def(ctx, offset + 0x80, 0x00000001);
-	gr_def(ctx, offset + 0x84, 0x00000001);
-	gr_def(ctx, offset + 0x88, 0x00000007);
-	gr_def(ctx, offset + 0x8c, 0x00000001);
-	gr_def(ctx, offset + 0x90, 0x00000007);
-	gr_def(ctx, offset + 0x94, 0x00000001);
-	gr_def(ctx, offset + 0x98, 0x00000001);
-	gr_def(ctx, offset + 0x9c, 0x00000001);
-	if (dev_priv->chipset == 0x50) {
-		 gr_def(ctx, offset + 0xb0, 0x00000001);
-		 gr_def(ctx, offset + 0xb4, 0x00000001);
-		 gr_def(ctx, offset + 0xbc, 0x00000001);
-		 gr_def(ctx, offset + 0xc0, 0x0000000a);
-		 gr_def(ctx, offset + 0xd0, 0x00000040);
-		 gr_def(ctx, offset + 0xd8, 0x00000002);
-		 gr_def(ctx, offset + 0xdc, 0x00000100);
-		 gr_def(ctx, offset + 0xe0, 0x00000001);
-		 gr_def(ctx, offset + 0xe4, 0x00000100);
-		 gr_def(ctx, offset + 0x100, 0x00000001);
-		 gr_def(ctx, offset + 0x124, 0x00000004);
-		 gr_def(ctx, offset + 0x13c, 0x00000001);
-		 gr_def(ctx, offset + 0x140, 0x00000100);
-		 gr_def(ctx, offset + 0x148, 0x00000001);
-		 gr_def(ctx, offset + 0x154, 0x00000100);
-		 gr_def(ctx, offset + 0x158, 0x00000001);
-		 gr_def(ctx, offset + 0x15c, 0x00000100);
-		 gr_def(ctx, offset + 0x164, 0x00000001);
-		 gr_def(ctx, offset + 0x170, 0x00000100);
-		 gr_def(ctx, offset + 0x174, 0x00000001);
-		 gr_def(ctx, offset + 0x17c, 0x00000001);
-		 gr_def(ctx, offset + 0x188, 0x00000002);
-		 gr_def(ctx, offset + 0x190, 0x00000001);
-		 gr_def(ctx, offset + 0x198, 0x00000001);
-		 gr_def(ctx, offset + 0x1ac, 0x00000003);
-		 offset += 0xd0;
-	} else {
-		gr_def(ctx, offset + 0xb0, 0x00000001);
-		gr_def(ctx, offset + 0xb4, 0x00000100);
-		gr_def(ctx, offset + 0xbc, 0x00000001);
-		gr_def(ctx, offset + 0xc8, 0x00000100);
-		gr_def(ctx, offset + 0xcc, 0x00000001);
-		gr_def(ctx, offset + 0xd0, 0x00000100);
-		gr_def(ctx, offset + 0xd8, 0x00000001);
-		gr_def(ctx, offset + 0xe4, 0x00000100);
-	}
-	gr_def(ctx, offset + 0xf8, 0x00000004);
-	gr_def(ctx, offset + 0xfc, 0x00000070);
-	gr_def(ctx, offset + 0x100, 0x00000080);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		offset += 4;
-	gr_def(ctx, offset + 0x114, 0x0000000c);
-	if (dev_priv->chipset == 0x50)
-		offset -= 4;
-	gr_def(ctx, offset + 0x11c, 0x00000008);
-	gr_def(ctx, offset + 0x120, 0x00000014);
-	if (dev_priv->chipset == 0x50) {
-		gr_def(ctx, offset + 0x124, 0x00000026);
-		offset -= 0x18;
-	} else {
-		gr_def(ctx, offset + 0x128, 0x00000029);
-		gr_def(ctx, offset + 0x12c, 0x00000027);
-		gr_def(ctx, offset + 0x130, 0x00000026);
-		gr_def(ctx, offset + 0x134, 0x00000008);
-		gr_def(ctx, offset + 0x138, 0x00000004);
-		gr_def(ctx, offset + 0x13c, 0x00000027);
-	}
-	gr_def(ctx, offset + 0x148, 0x00000001);
-	gr_def(ctx, offset + 0x14c, 0x00000002);
-	gr_def(ctx, offset + 0x150, 0x00000003);
-	gr_def(ctx, offset + 0x154, 0x00000004);
-	gr_def(ctx, offset + 0x158, 0x00000005);
-	gr_def(ctx, offset + 0x15c, 0x00000006);
-	gr_def(ctx, offset + 0x160, 0x00000007);
-	gr_def(ctx, offset + 0x164, 0x00000001);
-	gr_def(ctx, offset + 0x1a8, 0x000000cf);
-	if (dev_priv->chipset == 0x50)
-		offset -= 4;
-	gr_def(ctx, offset + 0x1d8, 0x00000080);
-	gr_def(ctx, offset + 0x1dc, 0x00000004);
-	gr_def(ctx, offset + 0x1e0, 0x00000004);
-	if (dev_priv->chipset == 0x50)
-		offset -= 4;
-	else
-		gr_def(ctx, offset + 0x1e4, 0x00000003);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		gr_def(ctx, offset + 0x1ec, 0x00000003);
-		offset += 8;
-	}
-	gr_def(ctx, offset + 0x1e8, 0x00000001);
-	if (dev_priv->chipset == 0x50)
-		offset -= 4;
-	gr_def(ctx, offset + 0x1f4, 0x00000012);
-	gr_def(ctx, offset + 0x1f8, 0x00000010);
-	gr_def(ctx, offset + 0x1fc, 0x0000000c);
-	gr_def(ctx, offset + 0x200, 0x00000001);
-	gr_def(ctx, offset + 0x210, 0x00000004);
-	gr_def(ctx, offset + 0x214, 0x00000002);
-	gr_def(ctx, offset + 0x218, 0x00000004);
-	if (dev_priv->chipset >= 0xa0)
-		offset += 4;
-	gr_def(ctx, offset + 0x224, 0x003fffff);
-	gr_def(ctx, offset + 0x228, 0x00001fff);
-	if (dev_priv->chipset == 0x50)
-		offset -= 0x20;
-	else if (dev_priv->chipset >= 0xa0) {
-		gr_def(ctx, offset + 0x250, 0x00000001);
-		gr_def(ctx, offset + 0x254, 0x00000001);
-		gr_def(ctx, offset + 0x258, 0x00000002);
-		offset += 0x10;
-	}
-	gr_def(ctx, offset + 0x250, 0x00000004);
-	gr_def(ctx, offset + 0x254, 0x00000014);
-	gr_def(ctx, offset + 0x258, 0x00000001);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		offset += 4;
-	gr_def(ctx, offset + 0x264, 0x00000002);
-	if (dev_priv->chipset >= 0xa0)
-		offset += 8;
-	gr_def(ctx, offset + 0x270, 0x00000001);
-	gr_def(ctx, offset + 0x278, 0x00000002);
-	gr_def(ctx, offset + 0x27c, 0x00001000);
-	if (dev_priv->chipset == 0x50)
-		offset -= 0xc;
-	else {
-		gr_def(ctx, offset + 0x280, 0x00000e00);
-		gr_def(ctx, offset + 0x284, 0x00001000);
-		gr_def(ctx, offset + 0x288, 0x00001e00);
-	}
-	gr_def(ctx, offset + 0x290, 0x00000001);
-	gr_def(ctx, offset + 0x294, 0x00000001);
-	gr_def(ctx, offset + 0x298, 0x00000001);
-	gr_def(ctx, offset + 0x29c, 0x00000001);
-	gr_def(ctx, offset + 0x2a0, 0x00000001);
-	gr_def(ctx, offset + 0x2b0, 0x00000200);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		gr_def(ctx, offset + 0x2b4, 0x00000200);
-		offset += 4;
-	}
-	if (dev_priv->chipset < 0xa0) {
-		gr_def(ctx, offset + 0x2b8, 0x00000001);
-		gr_def(ctx, offset + 0x2bc, 0x00000070);
-		gr_def(ctx, offset + 0x2c0, 0x00000080);
-		gr_def(ctx, offset + 0x2cc, 0x00000001);
-		gr_def(ctx, offset + 0x2d0, 0x00000070);
-		gr_def(ctx, offset + 0x2d4, 0x00000080);
-	} else {
-		gr_def(ctx, offset + 0x2b8, 0x00000001);
-		gr_def(ctx, offset + 0x2bc, 0x000000f0);
-		gr_def(ctx, offset + 0x2c0, 0x000000ff);
-		gr_def(ctx, offset + 0x2cc, 0x00000001);
-		gr_def(ctx, offset + 0x2d0, 0x000000f0);
-		gr_def(ctx, offset + 0x2d4, 0x000000ff);
-		gr_def(ctx, offset + 0x2dc, 0x00000009);
-		offset += 4;
-	}
-	gr_def(ctx, offset + 0x2e4, 0x00000001);
-	gr_def(ctx, offset + 0x2e8, 0x000000cf);
-	gr_def(ctx, offset + 0x2f0, 0x00000001);
-	gr_def(ctx, offset + 0x300, 0x000000cf);
-	gr_def(ctx, offset + 0x308, 0x00000002);
-	gr_def(ctx, offset + 0x310, 0x00000001);
-	gr_def(ctx, offset + 0x318, 0x00000001);
-	gr_def(ctx, offset + 0x320, 0x000000cf);
-	gr_def(ctx, offset + 0x324, 0x000000cf);
-	gr_def(ctx, offset + 0x328, 0x00000001);
-
 	/* 6000? */
 	if (dev_priv->chipset == 0x50)
 		cp_ctx(ctx, 0x4063e0, 0x1);
@@ -661,7 +470,7 @@
 			gr_def(ctx, 0x406818, 0x00000f80);
 		else
 			gr_def(ctx, 0x406818, 0x00001f80);
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
+		if (IS_NVA3F(dev_priv->chipset))
 			gr_def(ctx, 0x40681c, 0x00000030);
 		cp_ctx(ctx, 0x406830, 0x3);
 	}
@@ -706,7 +515,7 @@
 
 			if (dev_priv->chipset < 0xa0)
 				cp_ctx(ctx, 0x407094 + (i<<8), 1);
-			else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+			else if (!IS_NVA3F(dev_priv->chipset))
 				cp_ctx(ctx, 0x407094 + (i<<8), 3);
 			else {
 				cp_ctx(ctx, 0x407094 + (i<<8), 4);
@@ -799,6 +608,7 @@
 				case 0xa8:
 				case 0xaa:
 				case 0xac:
+				case 0xaf:
 					gr_def(ctx, offset + 0x1c, 0x300c0000);
 					break;
 				}
@@ -825,7 +635,7 @@
 				gr_def(ctx, base + 0x304, 0x00007070);
 			else if (dev_priv->chipset < 0xa0)
 				gr_def(ctx, base + 0x304, 0x00027070);
-			else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+			else if (!IS_NVA3F(dev_priv->chipset))
 				gr_def(ctx, base + 0x304, 0x01127070);
 			else
 				gr_def(ctx, base + 0x304, 0x05127070);
@@ -849,7 +659,7 @@
 			if (dev_priv->chipset < 0xa0) {
 				cp_ctx(ctx, base + 0x340, 9);
 				offset = base + 0x340;
-			} else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+			} else if (!IS_NVA3F(dev_priv->chipset)) {
 				cp_ctx(ctx, base + 0x33c, 0xb);
 				offset = base + 0x344;
 			} else {
@@ -880,7 +690,7 @@
 			gr_def(ctx, offset + 0x0, 0x000001f0);
 			gr_def(ctx, offset + 0x4, 0x00000001);
 			gr_def(ctx, offset + 0x8, 0x00000003);
-			if (dev_priv->chipset == 0x50 || dev_priv->chipset >= 0xaa)
+			if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset))
 				gr_def(ctx, offset + 0xc, 0x00008000);
 			gr_def(ctx, offset + 0x14, 0x00039e00);
 			cp_ctx(ctx, offset + 0x1c, 2);
@@ -892,7 +702,7 @@
 
 			if (dev_priv->chipset >= 0xa0) {
 				cp_ctx(ctx, base + 0x54c, 2);
-				if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa)
+				if (!IS_NVA3F(dev_priv->chipset))
 					gr_def(ctx, base + 0x54c, 0x003fe006);
 				else
 					gr_def(ctx, base + 0x54c, 0x003fe007);
@@ -948,6 +758,336 @@
 	}
 }
 
+static void
+dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+	int i;
+	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
+		for (i = 0; i < num; i++)
+			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
+	ctx->ctxvals_pos += num;
+}
+
+static void
+nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
+{
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	int base, num;
+	base = ctx->ctxvals_pos;
+
+	/* tesla state */
+	dd_emit(ctx, 1, 0);	/* 00000001 UNK0F90 */
+	dd_emit(ctx, 1, 0);	/* 00000001 UNK135C */
+
+	/* SRC_TIC state */
+	dd_emit(ctx, 1, 0);	/* 00000007 SRC_TILE_MODE_Z */
+	dd_emit(ctx, 1, 2);	/* 00000007 SRC_TILE_MODE_Y */
+	dd_emit(ctx, 1, 1);	/* 00000001 SRC_LINEAR #1 */
+	dd_emit(ctx, 1, 0);	/* 000000ff SRC_ADDRESS_HIGH */
+	dd_emit(ctx, 1, 0);	/* 00000001 SRC_SRGB */
+	if (dev_priv->chipset >= 0x94)
+		dd_emit(ctx, 1, 0);	/* 00000003 eng2d UNK0258 */
+	dd_emit(ctx, 1, 1);	/* 00000fff SRC_DEPTH */
+	dd_emit(ctx, 1, 0x100);	/* 0000ffff SRC_HEIGHT */
+
+	/* turing state */
+	dd_emit(ctx, 1, 0);		/* 0000000f TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f SAMPLERS_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
+	dd_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
+	dd_emit(ctx, 1, 0);		/* ffffffff SHARED_SIZE */
+	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
+	dd_emit(ctx, 1, 1);		/* 0000ffff BLOCK_ALLOC_THREADS */
+	dd_emit(ctx, 1, 1);		/* 00000001 LANES32 */
+	dd_emit(ctx, 1, 0);		/* 000000ff UNK370 */
+	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_UNK */
+	dd_emit(ctx, 1, 0);		/* 000000ff USER_PARAM_COUNT */
+	dd_emit(ctx, 1, 1);		/* 000000ff UNK384 bits 8-15 */
+	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_X */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_XMY */
+	dd_emit(ctx, 1, 0);		/* 00000001 BLOCKDIM_XMY_OVERFLOW */
+	dd_emit(ctx, 1, 1);		/* 0003ffff BLOCKDIM_XMYMZ */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCKDIM_Y */
+	dd_emit(ctx, 1, 1);		/* 0000007f BLOCKDIM_Z */
+	dd_emit(ctx, 1, 4);		/* 000000ff CP_REG_ALLOC_TEMP */
+	dd_emit(ctx, 1, 1);		/* 00000001 BLOCKDIM_DIRTY */
+	if (IS_NVA3F(dev_priv->chipset))
+		dd_emit(ctx, 1, 0);	/* 00000003 UNK03E8 */
+	dd_emit(ctx, 1, 1);		/* 0000007f BLOCK_ALLOC_HALFWARPS */
+	dd_emit(ctx, 1, 1);		/* 00000007 LOCAL_WARPS_NO_CLAMP */
+	dd_emit(ctx, 1, 7);		/* 00000007 LOCAL_WARPS_LOG_ALLOC */
+	dd_emit(ctx, 1, 1);		/* 00000007 STACK_WARPS_NO_CLAMP */
+	dd_emit(ctx, 1, 7);		/* 00000007 STACK_WARPS_LOG_ALLOC */
+	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
+	dd_emit(ctx, 1, 1);		/* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
+	dd_emit(ctx, 1, 1);		/* 000007ff BLOCK_ALLOC_THREADS */
+
+	/* compat 2d state */
+	if (dev_priv->chipset == 0x50) {
+		dd_emit(ctx, 4, 0);		/* 0000ffff clip X, Y, W, H */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff chroma COLOR_FORMAT */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff pattern COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff pattern SHAPE */
+		dd_emit(ctx, 1, 1);		/* ffffffff pattern PATTERN_SELECT */
+
+		dd_emit(ctx, 1, 0xa);		/* ffffffff surf2d SRC_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff surf2d DMA_SRC */
+		dd_emit(ctx, 1, 0);		/* 000000ff surf2d SRC_ADDRESS_HIGH */
+		dd_emit(ctx, 1, 0);		/* ffffffff surf2d SRC_ADDRESS_LOW */
+		dd_emit(ctx, 1, 0x40);		/* 0000ffff surf2d SRC_PITCH */
+		dd_emit(ctx, 1, 0);		/* 0000000f surf2d SRC_TILE_MODE_Z */
+		dd_emit(ctx, 1, 2);		/* 0000000f surf2d SRC_TILE_MODE_Y */
+		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_HEIGHT */
+		dd_emit(ctx, 1, 1);		/* 00000001 surf2d SRC_LINEAR */
+		dd_emit(ctx, 1, 0x100);		/* ffffffff surf2d SRC_WIDTH */
+
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_B_Y */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_C_Y */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect CLIP_D_Y */
+		dd_emit(ctx, 1, 1);		/* ffffffff gdirect COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff gdirect OPERATION */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_X */
+		dd_emit(ctx, 1, 0);		/* 0000ffff gdirect POINT_Y */
+
+		dd_emit(ctx, 1, 0);		/* 0000ffff blit SRC_Y */
+		dd_emit(ctx, 1, 0);		/* ffffffff blit OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff ifc OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc INDEX_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc LUT_OFFSET */
+		dd_emit(ctx, 1, 4);		/* ffffffff iifc COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff iifc OPERATION */
+	}
+
+	/* m2mf state */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_COUNT */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf LINE_LENGTH_IN */
+	dd_emit(ctx, 2, 0);		/* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
+	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_OUT */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_OUT */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_OUT_Z */
+	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_OUT */
+	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_OUT */
+	dd_emit(ctx, 1, 1);		/* ffffffff m2mf TILING_DEPTH_IN */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_HEIGHT_IN */
+	dd_emit(ctx, 1, 0);		/* ffffffff m2mf TILING_POSITION_IN_Z */
+	dd_emit(ctx, 1, 1);		/* 00000001 m2mf LINEAR_IN */
+	dd_emit(ctx, 2, 0);		/* 0000ffff m2mf TILING_POSITION_IN_X, Y */
+	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_IN */
+
+	/* more compat 2d state */
+	if (dev_priv->chipset == 0x50) {
+		dd_emit(ctx, 1, 1);		/* ffffffff line COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff line OPERATION */
+
+		dd_emit(ctx, 1, 1);		/* ffffffff triangle COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff triangle OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* 0000000f sifm TILE_MODE_Z */
+		dd_emit(ctx, 1, 2);		/* 0000000f sifm TILE_MODE_Y */
+		dd_emit(ctx, 1, 0);		/* 000000ff sifm FORMAT_FILTER */
+		dd_emit(ctx, 1, 1);		/* 000000ff sifm FORMAT_ORIGIN */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_PITCH */
+		dd_emit(ctx, 1, 1);		/* 00000001 sifm SRC_LINEAR */
+		dd_emit(ctx, 1, 0);		/* 000000ff sifm SRC_OFFSET_HIGH */
+		dd_emit(ctx, 1, 0);		/* ffffffff sifm SRC_OFFSET */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_HEIGHT */
+		dd_emit(ctx, 1, 0);		/* 0000ffff sifm SRC_WIDTH */
+		dd_emit(ctx, 1, 3);		/* ffffffff sifm COLOR_FORMAT */
+		dd_emit(ctx, 1, 0);		/* ffffffff sifm OPERATION */
+
+		dd_emit(ctx, 1, 0);		/* ffffffff sifc OPERATION */
+	}
+
+	/* tesla state */
+	dd_emit(ctx, 1, 0);		/* 0000000f GP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f GP_SAMPLERS_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 000000ff */
+	dd_emit(ctx, 1, 0);		/* ffffffff */
+	dd_emit(ctx, 1, 4);		/* 000000ff UNK12B0_0 */
+	dd_emit(ctx, 1, 0x70);		/* 000000ff UNK12B0_1 */
+	dd_emit(ctx, 1, 0x80);		/* 000000ff UNK12B0_3 */
+	dd_emit(ctx, 1, 0);		/* 000000ff UNK12B0_2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f FP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f FP_SAMPLERS_LOG2 */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		dd_emit(ctx, 1, 0);	/* ffffffff */
+		dd_emit(ctx, 1, 0);	/* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
+	} else {
+		dd_emit(ctx, 1, 0);	/* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
+	} 
+	dd_emit(ctx, 1, 0xc);		/* 000000ff SEMANTIC_COLOR.BFC0_ID */
+	if (dev_priv->chipset != 0x50)
+		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_COLOR.CLMP_EN */
+	dd_emit(ctx, 1, 8);		/* 000000ff SEMANTIC_COLOR.COLR_NR */
+	dd_emit(ctx, 1, 0x14);		/* 000000ff SEMANTIC_COLOR.FFC0_ID */
+	if (dev_priv->chipset == 0x50) {
+		dd_emit(ctx, 1, 0);	/* 000000ff SEMANTIC_LAYER */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+	} else {
+		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_PTSZ.ENABLE */
+		dd_emit(ctx, 1, 0x29);	/* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
+		dd_emit(ctx, 1, 0x27);	/* 000000ff SEMANTIC_PRIM */
+		dd_emit(ctx, 1, 0x26);	/* 000000ff SEMANTIC_LAYER */
+		dd_emit(ctx, 1, 8);	/* 0000000f SMENATIC_CLIP.CLIP_HIGH */
+		dd_emit(ctx, 1, 4);	/* 000000ff SEMANTIC_CLIP.CLIP_LO */
+		dd_emit(ctx, 1, 0x27);	/* 000000ff UNK0FD4 */
+		dd_emit(ctx, 1, 0);	/* 00000001 UNK1900 */
+	}
+	dd_emit(ctx, 1, 0);		/* 00000007 RT_CONTROL_MAP0 */
+	dd_emit(ctx, 1, 1);		/* 00000007 RT_CONTROL_MAP1 */
+	dd_emit(ctx, 1, 2);		/* 00000007 RT_CONTROL_MAP2 */
+	dd_emit(ctx, 1, 3);		/* 00000007 RT_CONTROL_MAP3 */
+	dd_emit(ctx, 1, 4);		/* 00000007 RT_CONTROL_MAP4 */
+	dd_emit(ctx, 1, 5);		/* 00000007 RT_CONTROL_MAP5 */
+	dd_emit(ctx, 1, 6);		/* 00000007 RT_CONTROL_MAP6 */
+	dd_emit(ctx, 1, 7);		/* 00000007 RT_CONTROL_MAP7 */
+	dd_emit(ctx, 1, 1);		/* 0000000f RT_CONTROL_COUNT */
+	dd_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_UNK */
+	dd_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff RT_FORMAT */
+	dd_emit(ctx, 7, 0);		/* 000000ff RT_FORMAT */
+	if (dev_priv->chipset != 0x50)
+		dd_emit(ctx, 3, 0);	/* 1, 1, 1 */
+	else
+		dd_emit(ctx, 2, 0);	/* 1, 1 */
+	dd_emit(ctx, 1, 0);		/* ffffffff GP_ENABLE */
+	dd_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
+	dd_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	dd_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		dd_emit(ctx, 1, 3);	/* 00000003 */
+		dd_emit(ctx, 1, 0);	/* 00000001 UNK1418. Alone. */
+	}
+	if (dev_priv->chipset != 0x50)
+		dd_emit(ctx, 1, 3);	/* 00000003 UNK15AC */
+	dd_emit(ctx, 1, 1);		/* ffffffff RASTERIZE_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_CONTROL.EXPORTS_Z */
+	if (dev_priv->chipset != 0x50)
+		dd_emit(ctx, 1, 0);	/* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
+	dd_emit(ctx, 1, 0x12);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT */
+	dd_emit(ctx, 1, 0x10);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
+	dd_emit(ctx, 1, 0xc);		/* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
+	dd_emit(ctx, 1, 1);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
+	dd_emit(ctx, 1, 0);		/* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
+	dd_emit(ctx, 1, 4);		/* 000000ff FP_RESULT_COUNT */
+	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
+	dd_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+	if (dev_priv->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* ffffffff */
+	dd_emit(ctx, 1, 0);		/* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
+	dd_emit(ctx, 1, 0);		/* ffffffff STRMOUT_ENABLE */
+	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	dd_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE*/
+	if (dev_priv->chipset != 0x50)
+		dd_emit(ctx, 8, 0);	/* 00000001 */
+	if (dev_priv->chipset >= 0xa0) {
+		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.COMP */
+		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.SIZE */
+		dd_emit(ctx, 1, 2);	/* 00000007 VTX_ATTR_DEFINE.TYPE */
+		dd_emit(ctx, 1, 0);	/* 000000ff VTX_ATTR_DEFINE.ATTR */
+	}
+	dd_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	dd_emit(ctx, 1, 0x14);		/* 0000001f ZETA_FORMAT */
+	dd_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 0000000f VP_TEXTURES_LOG2 */
+	dd_emit(ctx, 1, 0);		/* 0000000f VP_SAMPLERS_LOG2 */
+	if (IS_NVA3F(dev_priv->chipset))
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_BACK */
+	if (dev_priv->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
+	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
+	if (dev_priv->chipset >= 0xa0)
+		dd_emit(ctx, 1, 0);	/* 00000003 */
+	dd_emit(ctx, 1, 0);		/* 00000001 CULL_FACE_ENABLE */
+	dd_emit(ctx, 1, 1);		/* 00000003 CULL_FACE */
+	dd_emit(ctx, 1, 0);		/* 00000001 FRONT_FACE */
+	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_FRONT */
+	dd_emit(ctx, 1, 0x1000);	/* 00007fff UNK141C */
+	if (dev_priv->chipset != 0x50) {
+		dd_emit(ctx, 1, 0xe00);		/* 7fff */
+		dd_emit(ctx, 1, 0x1000);	/* 7fff */
+		dd_emit(ctx, 1, 0x1e00);	/* 7fff */
+	}
+	dd_emit(ctx, 1, 0);		/* 00000001 BEGIN_END_ACTIVE */
+	dd_emit(ctx, 1, 1);		/* 00000001 POLYGON_MODE_??? */
+	dd_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
+	dd_emit(ctx, 1, 1);		/* 000000ff FP_REG_ALLOC_TEMP... without /4? */
+	dd_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
+	dd_emit(ctx, 1, 1);		/* 00000001 */
+	dd_emit(ctx, 1, 0);		/* 00000001 */
+	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
+	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
+	dd_emit(ctx, 1, 0x200);		/* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
+	if (IS_NVA3F(dev_priv->chipset))
+		dd_emit(ctx, 1, 0x200);
+	dd_emit(ctx, 1, 0);		/* 00000001 */
+	if (dev_priv->chipset < 0xa0) {
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0x70);	/* 000000ff */
+		dd_emit(ctx, 1, 0x80);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0x70);	/* 000000ff */
+		dd_emit(ctx, 1, 0x80);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+	} else {
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
+		dd_emit(ctx, 1, 0xff);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 00000001 */
+		dd_emit(ctx, 1, 1);	/* 00000001 */
+		dd_emit(ctx, 1, 0xf0);	/* 000000ff */
+		dd_emit(ctx, 1, 0xff);	/* 000000ff */
+		dd_emit(ctx, 1, 0);	/* 000000ff */
+		dd_emit(ctx, 1, 9);	/* 0000003f UNK114C.COMP,SIZE */
+	}
+
+	/* eng2d state */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d COLOR_KEY_ENABLE */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d COLOR_KEY_FORMAT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d DST_DEPTH */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DST_FORMAT */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d DST_LAYER */
+	dd_emit(ctx, 1, 1);		/* 00000001 eng2d DST_LINEAR */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d PATTERN_COLOR_FORMAT */
+	dd_emit(ctx, 1, 0);		/* 00000007 eng2d OPERATION */
+	dd_emit(ctx, 1, 0);		/* 00000003 eng2d PATTERN_SELECT */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SIFC_FORMAT */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d SIFC_BITMAP_ENABLE */
+	dd_emit(ctx, 1, 2);		/* 00000003 eng2d SIFC_BITMAP_UNK808 */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DU_DX_FRACT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DU_DX_INT */
+	dd_emit(ctx, 1, 0);		/* ffffffff eng2d BLIT_DV_DY_FRACT */
+	dd_emit(ctx, 1, 1);		/* ffffffff eng2d BLIT_DV_DY_INT */
+	dd_emit(ctx, 1, 0);		/* 00000001 eng2d BLIT_CONTROL_FILTER */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d DRAW_COLOR_FORMAT */
+	dd_emit(ctx, 1, 0xcf);		/* 000000ff eng2d SRC_FORMAT */
+	dd_emit(ctx, 1, 1);		/* 00000001 eng2d SRC_LINEAR #2 */
+
+	num = ctx->ctxvals_pos - base;
+	ctx->ctxvals_pos = base;
+	if (IS_NVA3F(dev_priv->chipset))
+		cp_ctx(ctx, 0x404800, num);
+	else
+		cp_ctx(ctx, 0x405400, num);
+}
+
 /*
  * xfer areas. These are a pain.
  *
@@ -990,28 +1130,33 @@
  * without the help of ctxprog.
  */
 
-static inline void
+static void
 xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
 	int i;
 	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
 		for (i = 0; i < num; i++)
-			nv_wo32(ctx->dev, ctx->data, ctx->ctxvals_pos + (i << 3), val);
+			nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
 	ctx->ctxvals_pos += num << 3;
 }
 
 /* Gene declarations... */
 
+static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx);
+static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
 static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
 
@@ -1030,102 +1175,32 @@
 	if (dev_priv->chipset < 0xa0) {
 		/* Strand 0 */
 		ctx->ctxvals_pos = offset;
-		switch (dev_priv->chipset) {
-		case 0x50:
-			xf_emit(ctx, 0x99, 0);
-			break;
-		case 0x84:
-		case 0x86:
-			xf_emit(ctx, 0x384, 0);
-			break;
-		case 0x92:
-		case 0x94:
-		case 0x96:
-		case 0x98:
-			xf_emit(ctx, 0x380, 0);
-			break;
-		}
-		nv50_graph_construct_gene_m2mf (ctx);
-		switch (dev_priv->chipset) {
-		case 0x50:
-		case 0x84:
-		case 0x86:
-		case 0x98:
-			xf_emit(ctx, 0x4c4, 0);
-			break;
-		case 0x92:
-		case 0x94:
-		case 0x96:
-			xf_emit(ctx, 0x984, 0);
-			break;
-		}
-		nv50_graph_construct_gene_unk5(ctx);
-		if (dev_priv->chipset == 0x50)
-			xf_emit(ctx, 0xa, 0);
-		else
-			xf_emit(ctx, 0xb, 0);
-		nv50_graph_construct_gene_unk4(ctx);
-		nv50_graph_construct_gene_unk3(ctx);
+		nv50_graph_construct_gene_dispatch(ctx);
+		nv50_graph_construct_gene_m2mf(ctx);
+		nv50_graph_construct_gene_unk24xx(ctx);
+		nv50_graph_construct_gene_clipid(ctx);
+		nv50_graph_construct_gene_zcull(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 1 */
 		ctx->ctxvals_pos = offset + 0x1;
-		nv50_graph_construct_gene_unk6(ctx);
-		nv50_graph_construct_gene_unk7(ctx);
-		nv50_graph_construct_gene_unk8(ctx);
-		switch (dev_priv->chipset) {
-		case 0x50:
-		case 0x92:
-			xf_emit(ctx, 0xfb, 0);
-			break;
-		case 0x84:
-			xf_emit(ctx, 0xd3, 0);
-			break;
-		case 0x94:
-		case 0x96:
-			xf_emit(ctx, 0xab, 0);
-			break;
-		case 0x86:
-		case 0x98:
-			xf_emit(ctx, 0x6b, 0);
-			break;
-		}
-		xf_emit(ctx, 2, 0x4e3bfdf);
-		xf_emit(ctx, 4, 0);
-		xf_emit(ctx, 1, 0x0fac6881);
-		xf_emit(ctx, 0xb, 0);
-		xf_emit(ctx, 2, 0x4e3bfdf);
+		nv50_graph_construct_gene_vfetch(ctx);
+		nv50_graph_construct_gene_eng2d(ctx);
+		nv50_graph_construct_gene_csched(ctx);
+		nv50_graph_construct_gene_ropm1(ctx);
+		nv50_graph_construct_gene_ropm2(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 2 */
 		ctx->ctxvals_pos = offset + 0x2;
-		switch (dev_priv->chipset) {
-		case 0x50:
-		case 0x92:
-			xf_emit(ctx, 0xa80, 0);
-			break;
-		case 0x84:
-			xf_emit(ctx, 0xa7e, 0);
-			break;
-		case 0x94:
-		case 0x96:
-			xf_emit(ctx, 0xa7c, 0);
-			break;
-		case 0x86:
-		case 0x98:
-			xf_emit(ctx, 0xa7a, 0);
-			break;
-		}
-		xf_emit(ctx, 1, 0x3fffff);
-		xf_emit(ctx, 2, 0);
-		xf_emit(ctx, 1, 0x1fff);
-		xf_emit(ctx, 0xe, 0);
-		nv50_graph_construct_gene_unk9(ctx);
-		nv50_graph_construct_gene_unk2(ctx);
-		nv50_graph_construct_gene_unk1(ctx);
-		nv50_graph_construct_gene_unk10(ctx);
+		nv50_graph_construct_gene_ccache(ctx);
+		nv50_graph_construct_gene_unk1cxx(ctx);
+		nv50_graph_construct_gene_strmout(ctx);
+		nv50_graph_construct_gene_unk14xx(ctx);
+		nv50_graph_construct_gene_unk10xx(ctx);
+		nv50_graph_construct_gene_unk34xx(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
@@ -1150,86 +1225,46 @@
 	} else {
 		/* Strand 0 */
 		ctx->ctxvals_pos = offset;
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-			xf_emit(ctx, 0x385, 0);
-		else
-			xf_emit(ctx, 0x384, 0);
+		nv50_graph_construct_gene_dispatch(ctx);
 		nv50_graph_construct_gene_m2mf(ctx);
-		xf_emit(ctx, 0x950, 0);
-		nv50_graph_construct_gene_unk10(ctx);
-		xf_emit(ctx, 1, 0x0fac6881);
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-			xf_emit(ctx, 1, 1);
-			xf_emit(ctx, 3, 0);
-		}
-		nv50_graph_construct_gene_unk8(ctx);
-		if (dev_priv->chipset == 0xa0)
-			xf_emit(ctx, 0x189, 0);
-		else if (dev_priv->chipset == 0xa3)
-			xf_emit(ctx, 0xd5, 0);
-		else if (dev_priv->chipset == 0xa5)
-			xf_emit(ctx, 0x99, 0);
-		else if (dev_priv->chipset == 0xaa)
-			xf_emit(ctx, 0x65, 0);
-		else
-			xf_emit(ctx, 0x6d, 0);
-		nv50_graph_construct_gene_unk9(ctx);
+		nv50_graph_construct_gene_unk34xx(ctx);
+		nv50_graph_construct_gene_csched(ctx);
+		nv50_graph_construct_gene_unk1cxx(ctx);
+		nv50_graph_construct_gene_strmout(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 1 */
 		ctx->ctxvals_pos = offset + 1;
-		nv50_graph_construct_gene_unk1(ctx);
+		nv50_graph_construct_gene_unk10xx(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 2 */
 		ctx->ctxvals_pos = offset + 2;
-		if (dev_priv->chipset == 0xa0) {
-			nv50_graph_construct_gene_unk2(ctx);
-		}
-		xf_emit(ctx, 0x36, 0);
-		nv50_graph_construct_gene_unk5(ctx);
+		if (dev_priv->chipset == 0xa0)
+			nv50_graph_construct_gene_unk14xx(ctx);
+		nv50_graph_construct_gene_unk24xx(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 3 */
 		ctx->ctxvals_pos = offset + 3;
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 1, 1);
-		nv50_graph_construct_gene_unk6(ctx);
+		nv50_graph_construct_gene_vfetch(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 4 */
 		ctx->ctxvals_pos = offset + 4;
-		if (dev_priv->chipset == 0xa0)
-			xf_emit(ctx, 0xa80, 0);
-		else if (dev_priv->chipset == 0xa3)
-			xf_emit(ctx, 0xa7c, 0);
-		else
-			xf_emit(ctx, 0xa7a, 0);
-		xf_emit(ctx, 1, 0x3fffff);
-		xf_emit(ctx, 2, 0);
-		xf_emit(ctx, 1, 0x1fff);
+		nv50_graph_construct_gene_ccache(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
 		/* Strand 5 */
 		ctx->ctxvals_pos = offset + 5;
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 1, 0x0fac6881);
-		xf_emit(ctx, 0xb, 0);
-		xf_emit(ctx, 2, 0x4e3bfdf);
-		xf_emit(ctx, 3, 0);
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-			xf_emit(ctx, 1, 0x11);
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 2, 0x4e3bfdf);
-		xf_emit(ctx, 2, 0);
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-			xf_emit(ctx, 1, 0x11);
-		xf_emit(ctx, 1, 0);
+		nv50_graph_construct_gene_ropm2(ctx);
+		nv50_graph_construct_gene_ropm1(ctx);
+		/* per-ROP context */
 		for (i = 0; i < 8; i++)
 			if (units & (1<<(i+16)))
 				nv50_graph_construct_gene_ropc(ctx);
@@ -1238,10 +1273,9 @@
 
 		/* Strand 6 */
 		ctx->ctxvals_pos = offset + 6;
-		nv50_graph_construct_gene_unk3(ctx);
-		xf_emit(ctx, 0xb, 0);
-		nv50_graph_construct_gene_unk4(ctx);
-		nv50_graph_construct_gene_unk7(ctx);
+		nv50_graph_construct_gene_zcull(ctx);
+		nv50_graph_construct_gene_clipid(ctx);
+		nv50_graph_construct_gene_eng2d(ctx);
 		if (units & (1 << 0))
 			nv50_graph_construct_xfer_tp(ctx);
 		if (units & (1 << 1))
@@ -1269,7 +1303,7 @@
 			if (units & (1 << 9))
 				nv50_graph_construct_xfer_tp(ctx);
 		} else {
-			nv50_graph_construct_gene_unk2(ctx);
+			nv50_graph_construct_gene_unk14xx(ctx);
 		}
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
@@ -1290,9 +1324,70 @@
  */
 
 static void
+nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
+{
+	/* start of strand 0 */
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	/* SEEK */
+	if (dev_priv->chipset == 0x50)
+		xf_emit(ctx, 5, 0);
+	else if (!IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 6, 0);
+	else
+		xf_emit(ctx, 4, 0);
+	/* SEEK */
+	/* the PGRAPH's internal FIFO */
+	if (dev_priv->chipset == 0x50)
+		xf_emit(ctx, 8*3, 0);
+	else
+		xf_emit(ctx, 0x100*3, 0);
+	/* and another bonus slot?!? */
+	xf_emit(ctx, 3, 0);
+	/* and YET ANOTHER bonus slot? */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 3, 0);
+	/* SEEK */
+	/* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	xf_emit(ctx, 9, 0);
+	/* SEEK */
+	if (dev_priv->chipset < 0x90)
+		xf_emit(ctx, 4, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 6*2, 0);
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 6*2, 0);
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	if (dev_priv->chipset == 0x50)
+		xf_emit(ctx, 0x1c, 0);
+	else if (dev_priv->chipset < 0xa0)
+		xf_emit(ctx, 0x1e, 0);
+	else
+		xf_emit(ctx, 0x22, 0);
+	/* SEEK */
+	xf_emit(ctx, 0x15, 0);
+}
+
+static void
 nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
 {
-	/* m2mf state */
+	/* Strand 0, right after dispatch */
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	int smallm2mf = 0;
+	if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98)
+		smallm2mf = 1;
+	/* SEEK */
 	xf_emit (ctx, 1, 0);		/* DMA_NOTIFY instance >> 4 */
 	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_IN instance >> 4 */
 	xf_emit (ctx, 1, 0);		/* DMA_BUFFER_OUT instance >> 4 */
@@ -1319,427 +1414,975 @@
 	xf_emit (ctx, 1, 0);		/* TILING_POSITION_OUT */
 	xf_emit (ctx, 1, 0);		/* OFFSET_IN_HIGH */
 	xf_emit (ctx, 1, 0);		/* OFFSET_OUT_HIGH */
+	/* SEEK */
+	if (smallm2mf)
+		xf_emit(ctx, 0x40, 0);	/* 20 * ffffffff, 3ffff */
+	else
+		xf_emit(ctx, 0x100, 0);	/* 80 * ffffffff, 3ffff */
+	xf_emit(ctx, 4, 0);		/* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
+	/* SEEK */
+	if (smallm2mf)
+		xf_emit(ctx, 0x400, 0);	/* ffffffff */
+	else
+		xf_emit(ctx, 0x800, 0);	/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
+	/* SEEK */
+	xf_emit(ctx, 0x40, 0);		/* 20 * bits ffffffff, 3ffff */
+	xf_emit(ctx, 0x6, 0);		/* 1f, 0, 1f, 0, 1f, 0 */
 }
 
 static void
-nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* end of area 2 on pre-NVA0, area 1 on NVAx */
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x80);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0x80c14);
-	xf_emit(ctx, 1, 0);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);
-	else
-		xf_emit(ctx, 1, 0x7ff);
+	xf_emit(ctx, 2, 0);		/* RO */
+	xf_emit(ctx, 0x800, 0);		/* ffffffff */
 	switch (dev_priv->chipset) {
 	case 0x50:
-	case 0x86:
-	case 0x98:
-	case 0xaa:
-	case 0xac:
-		xf_emit(ctx, 0x542, 0);
+	case 0x92:
+	case 0xa0:
+		xf_emit(ctx, 0x2b, 0);
 		break;
 	case 0x84:
-	case 0x92:
+		xf_emit(ctx, 0x29, 0);
+		break;
 	case 0x94:
 	case 0x96:
-		xf_emit(ctx, 0x942, 0);
-		break;
-	case 0xa0:
 	case 0xa3:
-		xf_emit(ctx, 0x2042, 0);
+		xf_emit(ctx, 0x27, 0);
 		break;
+	case 0x86:
+	case 0x98:
 	case 0xa5:
 	case 0xa8:
-		xf_emit(ctx, 0x842, 0);
+	case 0xaa:
+	case 0xac:
+	case 0xaf:
+		xf_emit(ctx, 0x25, 0);
 		break;
 	}
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x80);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x27);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x26);
-	xf_emit(ctx, 3, 0);
+	/* CB bindings, 0x80 of them. first word is address >> 8, second is
+	 * size >> 4 | valid << 24 */
+	xf_emit(ctx, 0x100, 0);		/* ffffffff CB_DEF */
+	xf_emit(ctx, 1, 0);		/* 0000007f CB_ADDR_BUFFER */
+	xf_emit(ctx, 1, 0);		/* 0 */
+	xf_emit(ctx, 0x30, 0);		/* ff SET_PROGRAM_CB */
+	xf_emit(ctx, 1, 0);		/* 3f last SET_PROGRAM_CB */
+	xf_emit(ctx, 4, 0);		/* RO */
+	xf_emit(ctx, 0x100, 0);		/* ffffffff */
+	xf_emit(ctx, 8, 0);		/* 1f, 0, 0, ... */
+	xf_emit(ctx, 8, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 3 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CODE_CB */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TIC */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TSC */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
+	xf_emit(ctx, 1, 0);		/* 000000ff TIC_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff TIC_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
+	xf_emit(ctx, 1, 0);		/* 000000ff TSC_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff TSC_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
+	xf_emit(ctx, 1, 0);		/* 000000ff VP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff VP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff VP_START_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff CB_DEF_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff CB_DEF_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff GP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff GP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff GP_START_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff FP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff FP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 00ffffff FP_START_ID */
 }
 
 static void
-nv50_graph_construct_gene_unk10(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
 {
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	int i;
 	/* end of area 2 on pre-NVA0, area 1 on NVAx */
-	xf_emit(ctx, 0x10, 0x04000000);
-	xf_emit(ctx, 0x24, 0);
-	xf_emit(ctx, 2, 0x04e3bfdf);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x1fe21);
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	if (dev_priv->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);
+	else
+		xf_emit(ctx, 1, 0x7ff);	/* 000007ff */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	for (i = 0; i < 8; i++) {
+		switch (dev_priv->chipset) {
+		case 0x50:
+		case 0x86:
+		case 0x98:
+		case 0xaa:
+		case 0xac:
+			xf_emit(ctx, 0xa0, 0);	/* ffffffff */
+			break;
+		case 0x84:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+			xf_emit(ctx, 0x120, 0);
+			break;
+		case 0xa5:
+		case 0xa8:
+			xf_emit(ctx, 0x100, 0);	/* ffffffff */
+			break;
+		case 0xa0:
+		case 0xa3:
+		case 0xaf:
+			xf_emit(ctx, 0x400, 0);	/* ffffffff */
+			break;
+		}
+		xf_emit(ctx, 4, 0);	/* 3f, 0, 0, 0 */
+		xf_emit(ctx, 4, 0);	/* ffffffff */
+	}
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_TEMP */
+	xf_emit(ctx, 1, 1);		/* 00000001 RASTERIZE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0x27);		/* 000000ff UNK0FD4 */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);		/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 }
 
 static void
-nv50_graph_construct_gene_unk2(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
+{
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	/* end of area 2 on pre-NVA0, area 1 on NVAx */
+	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000003 VIEWPORT_CLIP_MODE */
+	xf_emit(ctx, 0x10, 0x04000000);	/* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
+	xf_emit(ctx, 0x20, 0);		/* ffffffff POLYGON_STIPPLE */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0x1fe21);	/* 0001ffff tesla UNK0FAC */
+	if (dev_priv->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0x0fac6881);
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 1);
+		xf_emit(ctx, 3, 0);
+	}
+}
+
+static void
+nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
 	/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
 	if (dev_priv->chipset != 0x50) {
-		xf_emit(ctx, 5, 0);
-		xf_emit(ctx, 1, 0x80c14);
-		xf_emit(ctx, 2, 0);
-		xf_emit(ctx, 1, 0x804);
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 2, 4);
-		xf_emit(ctx, 1, 0x8100c12);
+		xf_emit(ctx, 5, 0);		/* ffffffff */
+		xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 1, 0);		/* 000003ff */
+		xf_emit(ctx, 1, 0x804);		/* 00000fff SEMANTIC_CLIP */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 2, 4);		/* 7f, ff */
+		xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
 	}
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x10);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 3, 0);
-	else
-		xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x804);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x1a);
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 000000ff VP_CLIP_DISTANCE_ENABLE */
 	if (dev_priv->chipset != 0x50)
-		xf_emit(ctx, 1, 0x7f);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x80c14);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 6, 0);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);
-	else
-		xf_emit(ctx, 1, 0x7ff);
-	xf_emit(ctx, 1, 0x80c14);
-	xf_emit(ctx, 0x38, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 0x38, 0);
-	xf_emit(ctx, 2, 0x88);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 0x16, 0);
-	xf_emit(ctx, 1, 0x26);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x3f800000);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 4, 0);
-	else
-		xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x1a);
-	xf_emit(ctx, 1, 0x10);
+		xf_emit(ctx, 1, 0);		/* 3ff */
+	xf_emit(ctx, 1, 0);			/* 000000ff tesla UNK1940 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
+	xf_emit(ctx, 1, 0x804);			/* 00000fff SEMANTIC_CLIP */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
 	if (dev_priv->chipset != 0x50)
-		xf_emit(ctx, 0x28, 0);
+		xf_emit(ctx, 1, 0x7f);		/* 000000ff tesla UNK0FFC */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 SHADE_MODEL */
+	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0F8C */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0x8100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 4, 0);			/* ffffffff NOPERSPECTIVE_BITMAP */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
+	if (dev_priv->chipset == 0x50)
+		xf_emit(ctx, 1, 0x3ff);		/* 000003ff tesla UNK0D68 */
 	else
-		xf_emit(ctx, 0x25, 0);
-	xf_emit(ctx, 1, 0x52);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x26);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x1a);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x00ffff00);
-	xf_emit(ctx, 1, 0);
+		xf_emit(ctx, 1, 0x7ff);		/* 000007ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0x80c14);		/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);			/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
+	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
+	xf_emit(ctx, 3, 0);			/* ffffffff last VIEWPORT_SCALE? */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);			/* 00000001 */
+	xf_emit(ctx, 0x30, 0);			/* ffffffff VIEWPORT_TRANSLATE */
+	xf_emit(ctx, 3, 0);			/* f, 0, 0 */
+	xf_emit(ctx, 3, 0);			/* ffffffff */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 2, 0x88);			/* 000001ff tesla UNK19D8 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 4);			/* 0000000f CULL_MODE */
+	xf_emit(ctx, 2, 0);			/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 2, 0);			/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0);			/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 0x10, 0);			/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
+	xf_emit(ctx, 1, 0x3f800000);		/* ffffffff LINE_WIDTH */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	if (dev_priv->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);		/* ffffffff */
+		xf_emit(ctx, 1, 0);		/* 00000001 */
+		xf_emit(ctx, 1, 0);		/* 000003ff */
+	}
+	xf_emit(ctx, 0x20, 0);			/* 10xbits ffffffff, 3fffff. SCISSOR_* */
+	xf_emit(ctx, 1, 0);			/* f */
+	xf_emit(ctx, 1, 0);			/* 0? */
+	xf_emit(ctx, 1, 0);			/* ffffffff */
+	xf_emit(ctx, 1, 0);			/* 003fffff */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0x52);			/* 000001ff SEMANTIC_PTSZ */
+	xf_emit(ctx, 1, 0);			/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0x26);			/* 000000ff SEMANTIC_LAYER */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 4);			/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);			/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);		/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);			/* 0000000f */
 }
 
 static void
-nv50_graph_construct_gene_unk3(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* end of area 0 on pre-NVA0, beginning of area 6 on NVAx */
-	xf_emit(ctx, 1, 0x3f);
-	xf_emit(ctx, 0xa, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 0x04000000);
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 4);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 0x10, 0);
-	else
-		xf_emit(ctx, 0x11, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x1001);
-	xf_emit(ctx, 4, 0xffff);
-	xf_emit(ctx, 0x20, 0);
-	xf_emit(ctx, 0x10, 0x3f800000);
-	xf_emit(ctx, 1, 0x10);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0);
-	else
-		xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 2, 0);
+	/* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (dev_priv->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1108 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
+	/* SEEK */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
+	xf_emit(ctx, 1, 3);		/* 00000003 FP_CTRL_UNK196C */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1968 */
+	if (dev_priv->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 0fffffff tesla UNK1104 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK151C */
 }
 
 static void
-nv50_graph_construct_gene_unk4(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx)
 {
-	/* middle of area 0 on pre-NVA0, middle of area 6 on NVAx */
-	xf_emit(ctx, 2, 0x04000000);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x80);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x80);
-	xf_emit(ctx, 1, 0);
+	/* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000007 UNK0FB4 */
+	/* SEEK */
+	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_HORIZ */
+	xf_emit(ctx, 4, 0);		/* 07ffffff CLIPID_REGION_VERT */
+	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff UNK1508 */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIPID_ENABLE */
+	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ID */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLIPID_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLIPID_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x80);		/* 00003fff CLIPID_HEIGHT */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_CLIPID */
 }
 
 static void
-nv50_graph_construct_gene_unk5(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* middle of area 0 on pre-NVA0 [after m2mf], end of area 2 on NVAx */
-	xf_emit(ctx, 2, 4);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0x1c4d, 0);
+	int i;
+	/* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 0x33, 0);
+	/* SEEK */
+	xf_emit(ctx, 2, 0);
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 4, 0);	/* RO */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
+
+		xf_emit(ctx, 4, 0);	/* RO */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 9, 0);	/* ffffffff, 7ff */
+	}
 	else
-		xf_emit(ctx, 0x1c4b, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0x8100c12);
+	{
+		xf_emit(ctx, 0xc, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+
+		/* SEEK */
+		xf_emit(ctx, 0xc, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+		xf_emit(ctx, 1, 0);	/* 1ff */
+		xf_emit(ctx, 8, 0);	/* 0? */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
 	if (dev_priv->chipset != 0x50)
-		xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x80c14);
-	xf_emit(ctx, 1, 1);
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	/* SEEK */
 	if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0x80c14);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 1, 0x27);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x3c1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x16, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 1, 0);
+		xf_emit(ctx, 2, 4);	/* 000000ff */
+	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0x27);		/* 000000ff SEMANTIC_PRIM_ID */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	for (i = 0; i < 10; i++) {
+		/* SEEK */
+		xf_emit(ctx, 0x40, 0);		/* ffffffff */
+		xf_emit(ctx, 0x10, 0);		/* 3, 0, 0.... */
+		xf_emit(ctx, 0x10, 0);		/* ffffffff */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_CTRL */
+	xf_emit(ctx, 1, 1);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff NOPERSPECTIVE_BITMAP */
+	xf_emit(ctx, 0x10, 0);		/* 00ffffff POINT_COORD_REPLACE_MAP */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	if (dev_priv->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 000003ff */
 }
 
 static void
-nv50_graph_construct_gene_unk6(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* beginning of area 1 on pre-NVA0 [after m2mf], area 3 on NVAx */
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0xf);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 8, 0);
-	else
-		xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x20);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0x11, 0);
+	int acnt = 0x10, rep, i;
+	/* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
+	if (IS_NVA3F(dev_priv->chipset))
+		acnt = 0x20;
+	/* SEEK */
+	if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK13A4 */
+		xf_emit(ctx, 1, 1);	/* 00000fff tesla UNK1318 */
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff VERTEX_BUFFER_FIRST */
+	xf_emit(ctx, 1, 0);		/* 00000001 PRIMITIVE_RESTART_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0DE8 */
+	xf_emit(ctx, 1, 0);		/* ffffffff PRIMITIVE_RESTART_INDEX */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATR_MASK_UNK0DD0 */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0x20);		/* 0000ffff tesla UNK129C */
+	xf_emit(ctx, 1, 0);		/* 000000ff turing UNK370??? */
+	xf_emit(ctx, 1, 0);		/* 0000ffff turing USER_PARAM_COUNT */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0xb, 0);	/* RO */
 	else if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 0xf, 0);
+		xf_emit(ctx, 0x9, 0);	/* RO */
 	else
-		xf_emit(ctx, 0xe, 0);
-	xf_emit(ctx, 1, 0x1a);
-	xf_emit(ctx, 0xd, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 8);
-	xf_emit(ctx, 1, 0);
+		xf_emit(ctx, 0x8, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 00000001 EDGE_FLAG */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	/* SEEK */
+	xf_emit(ctx, 0xc, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 7f/ff */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 4);		/* 000001ff UNK1A28 */
+	xf_emit(ctx, 1, 8);		/* 000001ff UNK0DF0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);
+		xf_emit(ctx, 1, 0x3ff);	/* 3ff tesla UNK0D68 */
 	else
-		xf_emit(ctx, 1, 0x7ff);
+		xf_emit(ctx, 1, 0x7ff);	/* 7ff tesla UNK0D68 */
 	if (dev_priv->chipset == 0xa8)
-		xf_emit(ctx, 1, 0x1e00);
-	xf_emit(ctx, 0xc, 0);
-	xf_emit(ctx, 1, 0xf);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 0x125, 0);
-	else if (dev_priv->chipset < 0xa0)
-		xf_emit(ctx, 0x126, 0);
-	else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
-		xf_emit(ctx, 0x124, 0);
+		xf_emit(ctx, 1, 0x1e00);	/* 7fff */
+	/* SEEK */
+	xf_emit(ctx, 0xc, 0);		/* RO or close */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0)
+		xf_emit(ctx, 2, 0);	/* ffffffff */
 	else
-		xf_emit(ctx, 0x1f7, 0);
-	xf_emit(ctx, 1, 0xf);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 3, 0);
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0FD8 */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 0x10, 0);	/* 0? */
+		xf_emit(ctx, 2, 0);	/* weird... */
+		xf_emit(ctx, 2, 0);	/* RO */
+	} else {
+		xf_emit(ctx, 8, 0);	/* 0? */
+		xf_emit(ctx, 1, 0);	/* weird... */
+		xf_emit(ctx, 2, 0);	/* RO */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff VB_ELEMENT_BASE */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK1438 */
+	xf_emit(ctx, acnt, 0);		/* 1 tesla UNK1000 */
+	if (dev_priv->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1118? */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
+	xf_emit(ctx, 1, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
+	xf_emit(ctx, 1, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* RO */
+	xf_emit(ctx, 2, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK111C? */
+	xf_emit(ctx, 1, 0);		/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 000000ff UNK15F4_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK15F4_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 000000ff UNK0F84_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff UNK0F84_ADDRESS_LOW */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 00000fff VERTEX_ARRAY_STRIDE */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_LOW */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_ARRAY_HIGH */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_LIMIT_LOW */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_LIMIT_HIGH */
+	xf_emit(ctx, 3, 0);		/* f/1f */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, acnt, 0);		/* f */
+		xf_emit(ctx, 3, 0);		/* f/1f */
+	}
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 2, 0);	/* RO */
 	else
-		xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0xa1, 0);
+		xf_emit(ctx, 5, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffff DMA_VTXBUF */
+	/* SEEK */
+	if (dev_priv->chipset < 0xa0) {
+		xf_emit(ctx, 0x41, 0);	/* RO */
+		/* SEEK */
+		xf_emit(ctx, 0x11, 0);	/* RO */
+	} else if (!IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0x50, 0);	/* RO */
 	else
-		xf_emit(ctx, 0x5a, 0);
-	xf_emit(ctx, 1, 0xf);
+		xf_emit(ctx, 0x58, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, 1, 1);		/* 1 UNK0DEC */
+	/* SEEK */
+	xf_emit(ctx, acnt*4, 0);	/* ffffffff VTX_ATTR */
+	xf_emit(ctx, 4, 0);		/* f/1f, 0, 0, 0 */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0x1d, 0);	/* RO */
+	else
+		xf_emit(ctx, 0x16, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	/* SEEK */
 	if (dev_priv->chipset < 0xa0)
-		xf_emit(ctx, 0x834, 0);
-	else if (dev_priv->chipset == 0xa0)
-		xf_emit(ctx, 0x1873, 0);
-	else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0x8ba, 0);
+		xf_emit(ctx, 8, 0);	/* RO */
+	else if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0xc, 0);	/* RO */
 	else
-		xf_emit(ctx, 0x833, 0);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 0xf, 0);
+		xf_emit(ctx, 7, 0);	/* RO */
+	/* SEEK */
+	xf_emit(ctx, 0xa, 0);		/* RO */
+	if (dev_priv->chipset == 0xa0)
+		rep = 0xc;
+	else
+		rep = 4;
+	for (i = 0; i < rep; i++) {
+		/* SEEK */
+		if (IS_NVA3F(dev_priv->chipset))
+			xf_emit(ctx, 0x20, 0);	/* ffffffff */
+		xf_emit(ctx, 0x200, 0);	/* ffffffff */
+		xf_emit(ctx, 4, 0);	/* 7f/ff, 0, 0, 0 */
+		xf_emit(ctx, 4, 0);	/* ffffffff */
+	}
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 113/111 */
+	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
+	xf_emit(ctx, acnt/8, 0);	/* ffffffff VTX_ATTR_MASK_UNK0DD0 */
+	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 7, 0);	/* weird... */
+	else
+		xf_emit(ctx, 5, 0);	/* weird... */
 }
 
 static void
-nv50_graph_construct_gene_unk7(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* middle of area 1 on pre-NVA0 [after m2mf], middle of area 6 on NVAx */
-	xf_emit(ctx, 2, 0);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 2, 1);
-	else
-		xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0x100);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 8);
-	xf_emit(ctx, 5, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 3, 1);
-	xf_emit(ctx, 1, 0xcf);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 6, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 3, 1);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x15);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x4444480);
-	xf_emit(ctx, 0x37, 0);
+	/* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 2, 0);		/* 0001ffff CLIP_X, CLIP_Y */
+	xf_emit(ctx, 2, 0);		/* 0000ffff CLIP_W, CLIP_H */
+	xf_emit(ctx, 1, 0);		/* 00000001 CLIP_ENABLE */
+	if (dev_priv->chipset < 0xa0) {
+		/* this is useless on everything but the original NV50,
+		 * guess they forgot to nuke it. Or just didn't bother. */
+		xf_emit(ctx, 2, 0);	/* 0000ffff IFC_CLIP_X, Y */
+		xf_emit(ctx, 2, 1);	/* 0000ffff IFC_CLIP_W, H */
+		xf_emit(ctx, 1, 0);	/* 00000001 IFC_CLIP_ENABLE */
+	}
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
+	xf_emit(ctx, 1, 0x11);		/* 3f[NV50]/7f[NV84+] DST_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff DRAW_POINT_X */
+	xf_emit(ctx, 1, 8);		/* 0000000f DRAW_UNK58C */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_X_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_X_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DST_Y_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff SIFC_DST_Y_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DX_DU_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DX_DU_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff SIFC_DY_DV_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff SIFC_DY_DV_INT */
+	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_WIDTH */
+	xf_emit(ctx, 1, 1);		/* 0000ffff SIFC_HEIGHT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
+	xf_emit(ctx, 1, 2);		/* 00000003 SIFC_BITMAP_UNK808 */
+	xf_emit(ctx, 1, 0);		/* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
+	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_LSB_FIRST */
+	xf_emit(ctx, 1, 0);		/* 00000001 SIFC_BITMAP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_X */
+	xf_emit(ctx, 1, 0);		/* 0000ffff BLIT_DST_Y */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_W */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLIT_DST_H */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_X_FRACT */
+	xf_emit(ctx, 1, 0);		/* 0001ffff BLIT_SRC_X_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_SRC_Y_FRACT */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK888 */
+	xf_emit(ctx, 1, 4);		/* 0000003f UNK884 */
+	xf_emit(ctx, 1, 0);		/* 00000007 UNK880 */
+	xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK0FB8 */
+	xf_emit(ctx, 1, 0x15);		/* 000000ff tesla UNK128C */
+	xf_emit(ctx, 2, 0);		/* 00000007, ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK260 */
+	xf_emit(ctx, 1, 0x4444480);	/* 1fffffff UNK870 */
+	/* SEEK */
+	xf_emit(ctx, 0x10, 0);
+	/* SEEK */
+	xf_emit(ctx, 0x27, 0);
 }
 
 static void
-nv50_graph_construct_gene_unk8(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
 {
-	/* middle of area 1 on pre-NVA0 [after m2mf], middle of area 0 on NVAx */
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x100);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x10001);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x10001);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x10001);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 2);
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	/* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
+	/* SEEK */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1924 */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* ffffffff turing UNK364 */
+	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK36C */
+	xf_emit(ctx, 1, 0);		/* 0000ffff USER_PARAM_COUNT */
+	xf_emit(ctx, 1, 0x100);		/* 00ffffff turing UNK384 */
+	xf_emit(ctx, 1, 0);		/* 0000000f turing UNK2A0 */
+	xf_emit(ctx, 1, 0);		/* 0000ffff GRIDID */
+	xf_emit(ctx, 1, 0x10001);	/* ffffffff GRIDDIM_XY */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0x10001);	/* ffffffff BLOCKDIM_XY */
+	xf_emit(ctx, 1, 1);		/* 0000ffff BLOCKDIM_Z */
+	xf_emit(ctx, 1, 0x10001);	/* 00ffffff BLOCK_ALLOC */
+	xf_emit(ctx, 1, 1);		/* 00000001 LANES32 */
+	xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+	xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
+	/* SEEK */
+	xf_emit(ctx, 0x40, 0);		/* ffffffff USER_PARAM */
+	switch (dev_priv->chipset) {
+	case 0x50:
+	case 0x92:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x80, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0x10*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x84:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x60, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x94:
+	case 0x96:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x40, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 8*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0x86:
+	case 0x98:
+		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
+		xf_emit(ctx, 0x10, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa0:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0xf0, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0x1e*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa3:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x60, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 0xc*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xa5:
+	case 0xaf:
+		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
+		xf_emit(ctx, 0x30, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 6*2, 0);	/* ffffffff, 1f */
+		break;
+	case 0xaa:
+		xf_emit(ctx, 0x12, 0);
+		break;
+	case 0xa8:
+	case 0xac:
+		xf_emit(ctx, 4, 0);	/* f, 0, 0, 0 */
+		xf_emit(ctx, 0x10, 0);	/* fff */
+		xf_emit(ctx, 2, 0);	/* ff, fff */
+		xf_emit(ctx, 2*2, 0);	/* ffffffff, 1f */
+		break;
+	}
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000000 */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 0000001f */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 4, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000003 turing UNK35C */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 000000ff */
 }
 
 static void
-nv50_graph_construct_gene_unk9(struct nouveau_grctx *ctx)
+nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	/* middle of area 2 on pre-NVA0 [after m2mf], end of area 0 on NVAx */
-	xf_emit(ctx, 1, 0x3f800000);
-	xf_emit(ctx, 6, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0x1a);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x12, 0);
-	xf_emit(ctx, 1, 0x00ffff00);
-	xf_emit(ctx, 6, 0);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 0xf, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 2, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 3);
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 0x3f800000);	/* ffffffff LINE_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
+	xf_emit(ctx, 3, 0);		/* 00000001 POLYGON_OFFSET_*_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 0000000f CULL_MODE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
+	xf_emit(ctx, 0x10, 0);		/* 00000001 SCISSOR_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_UNITS */
+	xf_emit(ctx, 1, 0);		/* ffffffff POLYGON_OFFSET_FACTOR */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
+	xf_emit(ctx, 2, 0);		/* 07ffffff SCREEN_SCISSOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0x11);		/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 8, 0);		/* 00000001 RT_HORIZ_LINEAR */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 3);	/* 00000003 UNK16B4 */
 	else if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 0x04000000);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 5);
-	xf_emit(ctx, 1, 0x52);
-	if (dev_priv->chipset == 0x50) {
-		xf_emit(ctx, 0x13, 0);
-	} else {
-		xf_emit(ctx, 4, 0);
-		xf_emit(ctx, 1, 1);
-		if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-			xf_emit(ctx, 0x11, 0);
-		else
-			xf_emit(ctx, 0x10, 0);
+		xf_emit(ctx, 1, 1);	/* 00000001 UNK16B4 */
+	xf_emit(ctx, 1, 0);		/* 00000003 MULTISAMPLE_CTRL */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0F90 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 2, 0x04000000);	/* 07ffffff tesla UNK0D6C */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 5);		/* 0000000f UNK1408 */
+	xf_emit(ctx, 1, 0x52);		/* 000001ff SEMANTIC_PTSZ */
+	xf_emit(ctx, 1, 0);		/* ffffffff POINT_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 00000007 tesla UNK0FB4 */
+	if (dev_priv->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);	/* 3ff */
+		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK1110 */
 	}
-	xf_emit(ctx, 0x10, 0x3f800000);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 0x26, 0);
-	xf_emit(ctx, 1, 0x8100c12);
-	xf_emit(ctx, 1, 5);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 4, 0xffff);
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1928 */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0x10);		/* 000000ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 0x20, 0);		/* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK187C */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 5);		/* 0000000f tesla UNK1220 */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 000000ff tesla UNK1A20 */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
 	if (dev_priv->chipset != 0x50)
-		xf_emit(ctx, 1, 3);
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
 	if (dev_priv->chipset < 0xa0)
-		xf_emit(ctx, 0x1f, 0);
-	else if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0xc, 0);
-	else
-		xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x00ffff00);
-	xf_emit(ctx, 1, 0x1a);
+		xf_emit(ctx, 0x1c, 0);	/* RO */
+	else if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0x9, 0);
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
+	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
 	if (dev_priv->chipset != 0x50) {
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 1, 3);
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
+		xf_emit(ctx, 1, 0);	/* 3ff */
 	}
+	/* XXX: the following block could belong either to unk1cxx, or
+	 * to STRMOUT. Rather hard to tell. */
 	if (dev_priv->chipset < 0xa0)
-		xf_emit(ctx, 0x26, 0);
+		xf_emit(ctx, 0x25, 0);
 	else
-		xf_emit(ctx, 0x3c, 0);
-	xf_emit(ctx, 1, 0x102);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 4, 4);
-	if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0);
+		xf_emit(ctx, 0x3b, 0);
+}
+
+static void
+nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
+{
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
+	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
+	if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
+	}
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0x3ff);
+		xf_emit(ctx, 1, 0x3ff);	/* 000003ff tesla UNK0D68 */
 	else
-		xf_emit(ctx, 1, 0x7ff);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x102);
-	xf_emit(ctx, 9, 0);
-	xf_emit(ctx, 4, 4);
-	xf_emit(ctx, 0x2c, 0);
+		xf_emit(ctx, 1, 0x7ff);	/* 000007ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
+	xf_emit(ctx, 4, 0);		/* 000000ff STRMOUT_ADDRESS_HIGH */
+	xf_emit(ctx, 4, 0);		/* ffffffff STRMOUT_ADDRESS_LOW */
+	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
+	if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
+		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
+	}
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STRMOUT */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	/* SEEK */
+	xf_emit(ctx, 0x20, 0);		/* ffffffff STRMOUT_MAP */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000000? */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+}
+
+static void
+nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
+{
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
+{
+	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 2, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	/* SEEK */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
+	xf_emit(ctx, 1, 0);		/* 000000ff QUERY_ADDRESS_HIGH */
+	xf_emit(ctx, 2, 0);		/* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 eng2d UNK260 */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 }
 
 static void
@@ -1749,443 +2392,709 @@
 	int magic2;
 	if (dev_priv->chipset == 0x50) {
 		magic2 = 0x00003e60;
-	} else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+	} else if (!IS_NVA3F(dev_priv->chipset)) {
 		magic2 = 0x001ffe67;
 	} else {
 		magic2 = 0x00087e67;
 	}
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, magic2);
-	xf_emit(ctx, 4, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 7, 0);
-	if (dev_priv->chipset >= 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 0x15);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 4, 0);
+	xf_emit(ctx, 1, 0);		/* f/7 MUTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset))
+		xf_emit(ctx, 1, 0x15);	/* 000000ff */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0x10);		/* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
-		xf_emit(ctx, 1, 4);
-		xf_emit(ctx, 1, 0x400);
-		xf_emit(ctx, 1, 0x300);
-		xf_emit(ctx, 1, 0x1001);
+		xf_emit(ctx, 3, 0);	/* ff, ffffffff, ffffffff */
+		xf_emit(ctx, 1, 4);	/* 7 */
+		xf_emit(ctx, 1, 0x400);	/* fffffff */
+		xf_emit(ctx, 1, 0x300);	/* ffff */
+		xf_emit(ctx, 1, 0x1001);	/* 1fff */
 		if (dev_priv->chipset != 0xa0) {
-			if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-				xf_emit(ctx, 1, 0);
+			if (IS_NVA3F(dev_priv->chipset))
+				xf_emit(ctx, 1, 0);	/* 0000000f UNK15C8 */
 			else
-				xf_emit(ctx, 1, 0x15);
+				xf_emit(ctx, 1, 0x15);	/* ff */
 		}
-		xf_emit(ctx, 3, 0);
 	}
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x13, 0);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 0x10, 0);
-	xf_emit(ctx, 0x10, 0x3f800000);
-	xf_emit(ctx, 0x19, 0);
-	xf_emit(ctx, 1, 0x10);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x3f);
-	xf_emit(ctx, 6, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1900 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
+	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_BACK_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 2, 0);		/* ffffffff DEPTH_BOUNDS */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff CLEAR_STENCIL */
+	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_REF */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 1, 0x10);		/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
+	xf_emit(ctx, 1, 0);		/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 2, 0);		/* ffff0ff3, ffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
 	if (dev_priv->chipset >= 0xa0) {
 		xf_emit(ctx, 2, 0);
 		xf_emit(ctx, 1, 0x1001);
 		xf_emit(ctx, 0xb, 0);
 	} else {
-		xf_emit(ctx, 0xc, 0);
+		xf_emit(ctx, 1, 0);	/* 00000007 */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1534 */
+		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+		xf_emit(ctx, 8, 0);	/* 00000001 BLEND_ENABLE */
+		xf_emit(ctx, 1, 0);	/* ffff0ff3 */
 	}
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x11);
-	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 4, 0);
-	else
-		xf_emit(ctx, 6, 0);
-	xf_emit(ctx, 3, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, magic2);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 0x18, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 8, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 8, 1);
-		xf_emit(ctx, 3, 0);
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 5, 0);
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 0x16, 0);
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	if (dev_priv->chipset != 0x50) {
+		xf_emit(ctx, 1, 0);	/* 0000000f LOGIC_OP */
+		xf_emit(ctx, 1, 0);	/* 000000ff */
+	}
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 2, 1);		/* 00000007 BLEND_EQUATION_RGB, ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 0);		/* 00000001 */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK12E4 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 0000000f */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+	} else if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 00000007 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* ffffffff */
+		xf_emit(ctx, 2, 0);	/* 00000001 */
 	} else {
-		if (dev_priv->chipset >= 0xa0)
-			xf_emit(ctx, 0x1b, 0);
-		else
-			xf_emit(ctx, 0x15, 0);
+		xf_emit(ctx, 1, 0);	/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1430 */
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A3C */
 	}
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 1);
+	xf_emit(ctx, 4, 0);		/* ffffffff CLEAR_COLOR */
+	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR A R G B */
+	xf_emit(ctx, 1, 0);		/* 00000fff eng2d UNK2B0 */
 	if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 4, 0);
-	else
-		xf_emit(ctx, 3, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 0x10, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 0x10, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 8, 1);
-		xf_emit(ctx, 3, 0);
+		xf_emit(ctx, 2, 0);	/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* 000003ff */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f LOGIC_OP */
+	if (dev_priv->chipset >= 0xa0)
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4? NVA3+ only? */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK15C4 */
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK1140 */
 	}
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x5b, 0);
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 00000007 PATTERN_COLOR_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 PATTERN_MONO_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff PATTERN_MONO_BITMAP */
+	xf_emit(ctx, 1, 0);		/* 00000003 PATTERN_SELECT */
+	xf_emit(ctx, 1, 0);		/* 000000ff ROP */
+	xf_emit(ctx, 1, 0);		/* ffffffff BETA1 */
+	xf_emit(ctx, 1, 0);		/* ffffffff BETA4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 0x50, 0);		/* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x1(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
 	int magic3;
-	if (dev_priv->chipset == 0x50)
+	switch (dev_priv->chipset) {
+	case 0x50:
 		magic3 = 0x1000;
-	else if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8)
+		break;
+	case 0x86:
+	case 0x98:
+	case 0xa8:
+	case 0xaa:
+	case 0xac:
+	case 0xaf:
 		magic3 = 0x1e00;
-	else
+		break;
+	default:
 		magic3 = 0;
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 4);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0x24, 0);
+	}
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113[NVA0+] */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0x1f, 0);	/* ffffffff */
 	else if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 0x14, 0);
+		xf_emit(ctx, 0x0f, 0);	/* ffffffff */
 	else
-		xf_emit(ctx, 0x15, 0);
-	xf_emit(ctx, 2, 4);
+		xf_emit(ctx, 0x10, 0);	/* fffffff VP_RESULT_MAP_1 up */
+	xf_emit(ctx, 2, 0);		/* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
 	if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0x03020100);
+		xf_emit(ctx, 1, 0x03020100);	/* ffffffff */
 	else
-		xf_emit(ctx, 1, 0x00608080);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 2, 4);
-	xf_emit(ctx, 1, 0x80);
+		xf_emit(ctx, 1, 0x00608080);	/* fffffff VP_RESULT_MAP_0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 2, 0);		/* 111/113, 7f/ff */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
 	if (magic3)
-		xf_emit(ctx, 1, magic3);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 0x24, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0x80);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0x03020100);
-	xf_emit(ctx, 1, 3);
+		xf_emit(ctx, 1, magic3);	/* 00007fff tesla UNK141C */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 0x1f, 0);		/* ffffffff GP_RESULT_MAP_1 up */
+	xf_emit(ctx, 1, 0);		/* 0000001f */
+	xf_emit(ctx, 1, 0);		/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0x03020100);	/* ffffffff GP_RESULT_MAP_0 */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
 	if (magic3)
-		xf_emit(ctx, 1, magic3);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 4);
+		xf_emit(ctx, 1, magic3);	/* 7fff tesla UNK141C */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK13A0 */
+	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+	xf_emit(ctx, 1, 0);		/* 111/113 */
 	if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
-		xf_emit(ctx, 0x1024, 0);
+		xf_emit(ctx, 0x1020, 0);	/* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
 	else if (dev_priv->chipset < 0xa0)
-		xf_emit(ctx, 0xa24, 0);
-	else if (dev_priv->chipset == 0xa0 || dev_priv->chipset >= 0xaa)
-		xf_emit(ctx, 0x214, 0);
+		xf_emit(ctx, 0xa20, 0);	/* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+	else if (!IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 0x210, 0);	/* ffffffff */
 	else
-		xf_emit(ctx, 0x414, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 2, 0);
+		xf_emit(ctx, 0x410, 0);	/* ffffffff */
+	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
+	xf_emit(ctx, 1, 3);		/* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+	xf_emit(ctx, 1, 0);		/* 00000001 PROVOKING_VERTEX_LAST */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
 	int magic1, magic2;
 	if (dev_priv->chipset == 0x50) {
 		magic1 = 0x3ff;
 		magic2 = 0x00003e60;
-	} else if (dev_priv->chipset <= 0xa0 || dev_priv->chipset >= 0xaa) {
+	} else if (!IS_NVA3F(dev_priv->chipset)) {
 		magic1 = 0x7ff;
 		magic2 = 0x001ffe67;
 	} else {
 		magic1 = 0x7ff;
 		magic2 = 0x00087e67;
 	}
-	xf_emit(ctx, 3, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0xc, 0);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 0xb, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 4, 0xffff);
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 5, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 1, 3);
-		xf_emit(ctx, 1, 0);
-	} else if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0xa, 0);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 0x18, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 8, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 8, 1);
-		xf_emit(ctx, 1, 0);
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* ffffffff ALPHA_TEST_REF */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000000f UNK16A0 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_BACK_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK0FDC */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ff[NV50]/3ff[NV84+] */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
+	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff COLOR_KEY */
+	xf_emit(ctx, 1, 0);		/* 00000001 COLOR_KEY_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 COLOR_KEY_FORMAT */
+	xf_emit(ctx, 2, 0);		/* ffffffff SIFC_BITMAP_COLOR */
+	xf_emit(ctx, 1, 1);		/* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK16B4 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1298 */
+	} else if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK16B4 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+	} else {
+		xf_emit(ctx, 1, 0);	/* 00000003 MULTISAMPLE_CTRL */
 	}
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 3, 0xcf);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0xa, 0);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 8, 1);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, magic2);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x11);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 2, 1);
-	else
-		xf_emit(ctx, 1, 1);
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4 */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_RGB */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_RGB */
+		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);	/* 0000001f IBLEND_DST_ALPHA */
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+	}
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 00000007 OPERATION */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff DRAW_COLOR_FORMAT */
+	xf_emit(ctx, 1, 0xcf);		/* 000000ff SRC_FORMAT */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK133C */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 8, 1);		/* 00000001 UNK19E0 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	if(dev_priv->chipset == 0x50)
-		xf_emit(ctx, 1, 0);
-	else
-		xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 5, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, magic1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 0x28, 0);
-	xf_emit(ctx, 8, 8);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 8, 0x400);
-	xf_emit(ctx, 8, 0x300);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x20);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 0x100);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x40);
-	xf_emit(ctx, 1, 0x100);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 4, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, magic2);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 9, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x400);
-	xf_emit(ctx, 1, 0x300);
-	xf_emit(ctx, 1, 0x1001);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 4, 0);
+		xf_emit(ctx, 1, 0);	/* ff */
 	else
-		xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 1, 0xf);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 0x15, 0);
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 3, 0);
-	} else
-		xf_emit(ctx, 0x17, 0);
+		xf_emit(ctx, 3, 0);	/* 1, 7, 3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* 000fffff BLIT_DV_DY_FRACT */
+	xf_emit(ctx, 1, 1);		/* 0001ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, magic1);	/* 3ff/7ff tesla UNK0D68 */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 8, 0);		/* 0000ffff DMA_COLOR */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_GLOBAL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_LOCAL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_STACK */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_DST */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 8, 0);		/* 000000ff RT_ADDRESS_HIGH */
+	xf_emit(ctx, 8, 0);		/* ffffffff RT_LAYER_STRIDE */
+	xf_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
+	xf_emit(ctx, 8, 8);		/* 0000007f RT_TILE_MODE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 8, 0x400);		/* 0fffffff RT_HORIZ */
+	xf_emit(ctx, 8, 0x300);		/* 0000ffff RT_VERT */
+	xf_emit(ctx, 1, 1);		/* 00001fff RT_ARRAY_MODE */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0x20);		/* 00000fff DST_TILE_MODE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_HEIGHT */
+	xf_emit(ctx, 1, 0);		/* 000007ff DST_LAYER */
+	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
+	xf_emit(ctx, 1, 0);		/* ffffffff DST_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0);		/* 000000ff DST_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0x40);		/* 0007ffff DST_PITCH */
+	xf_emit(ctx, 1, 0x100);		/* 0001ffff DST_WIDTH */
+	xf_emit(ctx, 1, 0);		/* 0000ffff */
+	xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK15AC */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 2);		/* 00000003 tesla UNK143C */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_ZETA */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 2, 0);		/* ffff, ff/3ff */
+	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_LAYER_STRIDE */
+	xf_emit(ctx, 1, 0);		/* 000000ff ZETA_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);		/* ffffffff ZETA_ADDRESS_LOW */
+	xf_emit(ctx, 1, 4);		/* 00000007 ZETA_TILE_MODE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	xf_emit(ctx, 1, 0x400);		/* 0fffffff ZETA_HORIZ */
+	xf_emit(ctx, 1, 0x300);		/* 0000ffff ZETA_VERT */
+	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 0);	/* 00000001 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 7, 0);		/* 3f/7f RT_FORMAT */
+	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0xf);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
+	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 0);		/* 7 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	}
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
 	if (dev_priv->chipset >= 0xa0)
-		xf_emit(ctx, 1, 0x0fac6881);
-	xf_emit(ctx, 1, magic2);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 3, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 2, 1);
-	else
-		xf_emit(ctx, 1, 1);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 2, 0);
-	else if (dev_priv->chipset != 0x50)
-		xf_emit(ctx, 1, 0);
+		xf_emit(ctx, 1, 0x0fac6881);	/* fffffff */
+	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
+	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK0FB0 */
+	xf_emit(ctx, 1, 0);		/* ff/3ff */
+	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
+	xf_emit(ctx, 1, 0);		/* 00000007 */
+	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
+	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		xf_emit(ctx, 1, 0);	/* 0000000f tesla UNK15C8 */
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
+	if (dev_priv->chipset >= 0xa0) {
+		xf_emit(ctx, 3, 0);		/* 7/f, 1, ffff0ff3 */
+		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
+		xf_emit(ctx, 4, 0);		/* 1, 1, 1, 3ff */
+		xf_emit(ctx, 1, 4);		/* 7 */
+		xf_emit(ctx, 1, 0);		/* 1 */
+		xf_emit(ctx, 2, 1);		/* 1 */
+		xf_emit(ctx, 2, 0);		/* 7, f */
+		xf_emit(ctx, 1, 1);		/* 1 */
+		xf_emit(ctx, 1, 0);		/* 7/f */
+		if (IS_NVA3F(dev_priv->chipset))
+			xf_emit(ctx, 0x9, 0);	/* 1 */
+		else
+			xf_emit(ctx, 0x8, 0);	/* 1 */
+		xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+		xf_emit(ctx, 8, 1);		/* 1 */
+		xf_emit(ctx, 1, 0x11);		/* 7f */
+		xf_emit(ctx, 7, 0);		/* 7f */
+		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
+		xf_emit(ctx, 1, 0xf);		/* f */
+		xf_emit(ctx, 7, 0);		/* f */
+		xf_emit(ctx, 1, 0x11);		/* 7f */
+		xf_emit(ctx, 1, 1);		/* 1 */
+		xf_emit(ctx, 5, 0);		/* 1, 7, 3ff, 3, 7 */
+		if (IS_NVA3F(dev_priv->chipset)) {
+			xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
+			xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+		}
+	}
 }
 
 static void
-nv50_graph_construct_xfer_tp_x3(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
+	xf_emit(ctx, 2, 0);		/* 1 LINKED_TSC. yes, 2. */
+	if (dev_priv->chipset != 0x50)
+		xf_emit(ctx, 1, 0);	/* 3 */
+	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DU_DX_INT */
+	xf_emit(ctx, 1, 0);		/* fffff BLIT_DU_DX_FRACT */
+	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DV_DY_INT */
+	xf_emit(ctx, 1, 0);		/* fffff BLIT_DV_DY_FRACT */
 	if (dev_priv->chipset == 0x50)
-		xf_emit(ctx, 2, 0);
-	else
-		xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0x2a712488);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x4085c000);
-	xf_emit(ctx, 1, 0x40);
-	xf_emit(ctx, 1, 0x100);
-	xf_emit(ctx, 1, 0x10100);
-	xf_emit(ctx, 1, 0x02800000);
-}
-
-static void
-nv50_graph_construct_xfer_tp_x4(struct nouveau_grctx *ctx)
-{
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	xf_emit(ctx, 2, 0x04e3bfdf);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x00ffff00);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 2, 1);
+		xf_emit(ctx, 1, 0);	/* 3 BLIT_CONTROL */
 	else
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 0x00ffff00);
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0x30201000);
-	xf_emit(ctx, 1, 0x70605040);
-	xf_emit(ctx, 1, 0xb8a89888);
-	xf_emit(ctx, 1, 0xf8e8d8c8);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x1a);
+		xf_emit(ctx, 2, 0);	/* 3ff, 1 */
+	xf_emit(ctx, 1, 0x2a712488);	/* ffffffff SRC_TIC_0 */
+	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_1 */
+	xf_emit(ctx, 1, 0x4085c000);	/* ffffffff SRC_TIC_2 */
+	xf_emit(ctx, 1, 0x40);		/* ffffffff SRC_TIC_3 */
+	xf_emit(ctx, 1, 0x100);		/* ffffffff SRC_TIC_4 */
+	xf_emit(ctx, 1, 0x10100);	/* ffffffff SRC_TIC_5 */
+	xf_emit(ctx, 1, 0x02800000);	/* ffffffff SRC_TIC_6 */
+	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_7 */
+	if (dev_priv->chipset == 0x50) {
+		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK358 */
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
+		xf_emit(ctx, 1, 0);	/* 00000003 turing UNK37C tesla UNK1690 */
+		xf_emit(ctx, 1, 0);	/* 00000003 BLIT_CONTROL */
+		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK32C tesla UNK0F94 */
+	} else if (!IS_NVAAF(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1664 / turing UNK03E8 */
+		xf_emit(ctx, 1, 0);	/* 00000003 */
+		xf_emit(ctx, 1, 0);	/* 000003ff */
+	} else {
+		xf_emit(ctx, 0x6, 0);
+	}
+	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A34 */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_TEXTURE */
+	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_SRC */
 }
 
 static void
-nv50_graph_construct_xfer_tp_x5(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 0xfac6881);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 2, 0);
-	xf_emit(ctx, 1, 1);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 0xb, 0);
-	else
-		xf_emit(ctx, 0xa, 0);
-	xf_emit(ctx, 8, 1);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0xfac6881);
-	xf_emit(ctx, 1, 0xf);
-	xf_emit(ctx, 7, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 1);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 6, 0);
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 6, 0);
-	} else {
-		xf_emit(ctx, 0xb, 0);
-	}
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 2, 0);		/* 7, ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0D64 */
+	xf_emit(ctx, 1, 0x04e3bfdf);	/* ffffffff UNK0DF4 */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK0F98 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
+	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
+	xf_emit(ctx, 1, 0);		/* 00000001 POLYGON_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
+	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1658 */
+	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
+	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE */
+	xf_emit(ctx, 1, 1);		/* 00000001 UNK15B4 */
+	xf_emit(ctx, 1, 0);		/* 00000001 POINT_SPRITE_ENABLE */
+	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK165C */
+	xf_emit(ctx, 1, 0x30201000);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0x70605040);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0xb8a89888);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0xf8e8d8c8);	/* ffffffff tesla UNK1670 */
+	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
+	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
 }
 
 static void
@@ -2193,108 +3102,136 @@
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
 	if (dev_priv->chipset < 0xa0) {
-		nv50_graph_construct_xfer_tp_x1(ctx);
-		nv50_graph_construct_xfer_tp_x2(ctx);
-		nv50_graph_construct_xfer_tp_x3(ctx);
-		if (dev_priv->chipset == 0x50)
-			xf_emit(ctx, 0xf, 0);
-		else
-			xf_emit(ctx, 0x12, 0);
-		nv50_graph_construct_xfer_tp_x4(ctx);
+		nv50_graph_construct_xfer_unk84xx(ctx);
+		nv50_graph_construct_xfer_tprop(ctx);
+		nv50_graph_construct_xfer_tex(ctx);
+		nv50_graph_construct_xfer_unk8cxx(ctx);
 	} else {
-		nv50_graph_construct_xfer_tp_x3(ctx);
-		if (dev_priv->chipset < 0xaa)
-			xf_emit(ctx, 0xc, 0);
-		else
-			xf_emit(ctx, 0xa, 0);
-		nv50_graph_construct_xfer_tp_x2(ctx);
-		nv50_graph_construct_xfer_tp_x5(ctx);
-		nv50_graph_construct_xfer_tp_x4(ctx);
-		nv50_graph_construct_xfer_tp_x1(ctx);
+		nv50_graph_construct_xfer_tex(ctx);
+		nv50_graph_construct_xfer_tprop(ctx);
+		nv50_graph_construct_xfer_unk8cxx(ctx);
+		nv50_graph_construct_xfer_unk84xx(ctx);
 	}
 }
 
 static void
-nv50_graph_construct_xfer_tp2(struct nouveau_grctx *ctx)
+nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
 {
 	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	int i, mpcnt;
-	if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
-		mpcnt = 1;
-	else if (dev_priv->chipset < 0xa0 || dev_priv->chipset >= 0xa8)
-		mpcnt = 2;
-	else
-		mpcnt = 3;
+	int i, mpcnt = 2;
+	switch (dev_priv->chipset) {
+		case 0x98:
+		case 0xaa:
+			mpcnt = 1;
+			break;
+		case 0x50:
+		case 0x84:
+		case 0x86:
+		case 0x92:
+		case 0x94:
+		case 0x96:
+		case 0xa8:
+		case 0xac:
+			mpcnt = 2;
+			break;
+		case 0xa0:
+		case 0xa3:
+		case 0xa5:
+		case 0xaf:
+			mpcnt = 3;
+			break;
+	}
 	for (i = 0; i < mpcnt; i++) {
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 1, 0x80);
-		xf_emit(ctx, 1, 0x80007004);
-		xf_emit(ctx, 1, 0x04000400);
+		xf_emit(ctx, 1, 0);		/* ff */
+		xf_emit(ctx, 1, 0x80);		/* ffffffff tesla UNK1404 */
+		xf_emit(ctx, 1, 0x80007004);	/* ffffffff tesla UNK12B0 */
+		xf_emit(ctx, 1, 0x04000400);	/* ffffffff */
 		if (dev_priv->chipset >= 0xa0)
-			xf_emit(ctx, 1, 0xc0);
-		xf_emit(ctx, 1, 0x1000);
-		xf_emit(ctx, 2, 0);
-		if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa8) {
-			xf_emit(ctx, 1, 0xe00);
-			xf_emit(ctx, 1, 0x1e00);
+			xf_emit(ctx, 1, 0xc0);	/* 00007fff tesla UNK152C */
+		xf_emit(ctx, 1, 0x1000);	/* 0000ffff tesla UNK0D60 */
+		xf_emit(ctx, 1, 0);		/* ff/3ff */
+		xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
+		if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) {
+			xf_emit(ctx, 1, 0xe00);		/* 7fff */
+			xf_emit(ctx, 1, 0x1e00);	/* 7fff */
 		}
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 2, 0);
+		xf_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
+		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 		if (dev_priv->chipset == 0x50)
-			xf_emit(ctx, 2, 0x1000);
-		xf_emit(ctx, 1, 1);
-		xf_emit(ctx, 1, 0);
-		xf_emit(ctx, 1, 4);
-		xf_emit(ctx, 1, 2);
-		if (dev_priv->chipset >= 0xaa)
-			xf_emit(ctx, 0xb, 0);
+			xf_emit(ctx, 2, 0x1000);	/* 7fff tesla UNK141C */
+		xf_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
+		xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
+		xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
+		if (IS_NVAAF(dev_priv->chipset))
+			xf_emit(ctx, 0xb, 0);	/* RO */
 		else if (dev_priv->chipset >= 0xa0)
-			xf_emit(ctx, 0xc, 0);
+			xf_emit(ctx, 0xc, 0);	/* RO */
 		else
-			xf_emit(ctx, 0xa, 0);
+			xf_emit(ctx, 0xa, 0);	/* RO */
 	}
-	xf_emit(ctx, 1, 0x08100c12);
-	xf_emit(ctx, 1, 0);
+	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 0);			/* ff/3ff */
 	if (dev_priv->chipset >= 0xa0) {
-		xf_emit(ctx, 1, 0x1fe21);
+		xf_emit(ctx, 1, 0x1fe21);	/* 0003ffff tesla UNK0FAC */
 	}
-	xf_emit(ctx, 5, 0);
-	xf_emit(ctx, 4, 0xffff);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 2, 0x10001);
-	xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 0x1fe21);
-	xf_emit(ctx, 1, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 1);
-	xf_emit(ctx, 4, 0);
-	xf_emit(ctx, 1, 0x08100c12);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 8, 0);
-	xf_emit(ctx, 1, 0xfac6881);
-	xf_emit(ctx, 1, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa)
-		xf_emit(ctx, 1, 3);
-	xf_emit(ctx, 3, 0);
-	xf_emit(ctx, 1, 4);
-	xf_emit(ctx, 9, 0);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 2, 1);
-	xf_emit(ctx, 1, 2);
-	xf_emit(ctx, 3, 1);
-	xf_emit(ctx, 1, 0);
-	if (dev_priv->chipset > 0xa0 && dev_priv->chipset < 0xaa) {
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 0x10, 1);
-		xf_emit(ctx, 8, 2);
-		xf_emit(ctx, 0x18, 1);
-		xf_emit(ctx, 3, 0);
+	xf_emit(ctx, 3, 0);			/* 7fff, 0, 0 */
+	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1534 */
+	xf_emit(ctx, 1, 0);			/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+	xf_emit(ctx, 4, 0xffff);		/* 0000ffff MSAA_MASK */
+	xf_emit(ctx, 1, 1);			/* 00000001 LANES32 */
+	xf_emit(ctx, 1, 0x10001);		/* 00ffffff BLOCK_ALLOC */
+	xf_emit(ctx, 1, 0x10001);		/* ffffffff BLOCKDIM_XY */
+	xf_emit(ctx, 1, 1);			/* 0000ffff BLOCKDIM_Z */
+	xf_emit(ctx, 1, 0);			/* ffffffff SHARED_SIZE */
+	xf_emit(ctx, 1, 0x1fe21);		/* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
+	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A34 */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK169C */
+	xf_emit(ctx, 1, 0);			/* ff/3ff */
+	xf_emit(ctx, 1, 0);			/* 1 LINKED_TSC */
+	xf_emit(ctx, 1, 0);			/* ff FP_ADDRESS_HIGH */
+	xf_emit(ctx, 1, 0);			/* ffffffff FP_ADDRESS_LOW */
+	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
+	xf_emit(ctx, 1, 4);			/* 00000007 FP_CONTROL */
+	xf_emit(ctx, 1, 0);			/* 000000ff FRAG_COLOR_CLAMP_EN */
+	xf_emit(ctx, 1, 2);			/* 00000003 REG_MODE */
+	xf_emit(ctx, 1, 0x11);			/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 7, 0);			/* 0000007f RT_FORMAT */
+	xf_emit(ctx, 1, 0);			/* 00000007 */
+	xf_emit(ctx, 1, 0xfac6881);		/* 0fffffff RT_CONTROL */
+	xf_emit(ctx, 1, 0);			/* 00000003 MULTISAMPLE_CTRL */
+	if (IS_NVA3F(dev_priv->chipset))
+		xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK16B4 */
+	xf_emit(ctx, 1, 0);			/* 00000001 ALPHA_TEST_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000007 ALPHA_TEST_FUNC */
+	xf_emit(ctx, 1, 0);			/* 00000001 FRAMEBUFFER_SRGB */
+	xf_emit(ctx, 1, 4);			/* ffffffff tesla UNK1400 */
+	xf_emit(ctx, 8, 0);			/* 00000001 BLEND_ENABLE */
+	xf_emit(ctx, 1, 0);			/* 00000001 LOGIC_OP_ENABLE */
+	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_RGB */
+	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_RGB */
+	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_RGB */
+	xf_emit(ctx, 1, 2);			/* 0000001f BLEND_FUNC_SRC_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_ALPHA */
+	xf_emit(ctx, 1, 1);			/* 00000001 UNK133C */
+	if (IS_NVA3F(dev_priv->chipset)) {
+		xf_emit(ctx, 1, 0);		/* 00000001 UNK12E4 */
+		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_RGB */
+		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_RGB */
+		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_RGB */
+		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 00000007 IBLEND_EQUATION_ALPHA */
+		xf_emit(ctx, 8, 1);		/* 00000001 IBLEND_UNK00 */
+		xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1928 */
+		xf_emit(ctx, 1, 0);		/* 00000001 UNK1140 */
 	}
-	xf_emit(ctx, 1, 4);
+	xf_emit(ctx, 1, 0);			/* 00000003 tesla UNK0F90 */
+	xf_emit(ctx, 1, 4);			/* 000000ff FP_RESULT_COUNT */
+	/* XXX: demagic this part some day */
 	if (dev_priv->chipset == 0x50)
 		xf_emit(ctx, 0x3a0, 0);
 	else if (dev_priv->chipset < 0x94)
@@ -2303,9 +3240,9 @@
 		xf_emit(ctx, 0x39f, 0);
 	else
 		xf_emit(ctx, 0x3a3, 0);
-	xf_emit(ctx, 1, 0x11);
-	xf_emit(ctx, 1, 0);
-	xf_emit(ctx, 1, 1);
+	xf_emit(ctx, 1, 0x11);			/* 3f/7f DST_FORMAT */
+	xf_emit(ctx, 1, 0);			/* 7 OPERATION */
+	xf_emit(ctx, 1, 1);			/* 1 DST_LINEAR */
 	xf_emit(ctx, 0x2d, 0);
 }
 
@@ -2323,52 +3260,56 @@
 	if (dev_priv->chipset < 0xa0) {
 		for (i = 0; i < 8; i++) {
 			ctx->ctxvals_pos = offset + i;
+			/* that little bugger belongs to csched. No idea
+			 * what it's doing here. */
 			if (i == 0)
-				xf_emit(ctx, 1, 0x08100c12);
+				xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
 			if (units & (1 << i))
-				nv50_graph_construct_xfer_tp2(ctx);
+				nv50_graph_construct_xfer_mpc(ctx);
 			if ((ctx->ctxvals_pos-offset)/8 > size)
 				size = (ctx->ctxvals_pos-offset)/8;
 		}
 	} else {
 		/* Strand 0: TPs 0, 1 */
 		ctx->ctxvals_pos = offset;
-		xf_emit(ctx, 1, 0x08100c12);
+		/* that little bugger belongs to csched. No idea
+		 * what it's doing here. */
+		xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
 		if (units & (1 << 0))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 1))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
-		/* Strand 0: TPs 2, 3 */
+		/* Strand 1: TPs 2, 3 */
 		ctx->ctxvals_pos = offset + 1;
 		if (units & (1 << 2))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 3))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
-		/* Strand 0: TPs 4, 5, 6 */
+		/* Strand 2: TPs 4, 5, 6 */
 		ctx->ctxvals_pos = offset + 2;
 		if (units & (1 << 4))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 5))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 6))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 
-		/* Strand 0: TPs 7, 8, 9 */
+		/* Strand 3: TPs 7, 8, 9 */
 		ctx->ctxvals_pos = offset + 3;
 		if (units & (1 << 7))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 8))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if (units & (1 << 9))
-			nv50_graph_construct_xfer_tp2(ctx);
+			nv50_graph_construct_xfer_mpc(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
 			size = (ctx->ctxvals_pos-offset)/8;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_instmem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_instmem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_instmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_instmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,39 +32,87 @@
 struct nv50_instmem_priv {
 	uint32_t save1700[5]; /* 0x1700->0x1710 */
 
-	struct nouveau_gpuobj_ref *pramin_pt;
-	struct nouveau_gpuobj_ref *pramin_bar;
-	struct nouveau_gpuobj_ref *fb_bar;
+	struct nouveau_gpuobj *pramin_pt;
+	struct nouveau_gpuobj *pramin_bar;
+	struct nouveau_gpuobj *fb_bar;
 };
 
-#define NV50_INSTMEM_PAGE_SHIFT 12
-#define NV50_INSTMEM_PAGE_SIZE  (1 << NV50_INSTMEM_PAGE_SHIFT)
-#define NV50_INSTMEM_PT_SIZE(a)	(((a) >> 12) << 3)
+static void
+nv50_channel_del(struct nouveau_channel **pchan)
+{
+	struct nouveau_channel *chan;
 
-/*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN
- */
-#define BAR0_WI32(g, o, v) do {                                   \
-	uint32_t offset;                                          \
-	if ((g)->im_backing) {                                    \
-		offset = (g)->im_backing_start;                   \
-	} else {                                                  \
-		offset  = chan->ramin->gpuobj->im_backing_start;  \
-		offset += (g)->im_pramin->start;                  \
-	}                                                         \
-	offset += (o);                                            \
-	nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v));              \
-} while (0)
+	chan = *pchan;
+	*pchan = NULL;
+	if (!chan)
+		return;
+
+	nouveau_gpuobj_ref(NULL, &chan->ramfc);
+	nouveau_gpuobj_ref(NULL, &chan->vm_pd);
+	if (chan->ramin_heap.free_stack.next)
+		drm_mm_takedown(&chan->ramin_heap);
+	nouveau_gpuobj_ref(NULL, &chan->ramin);
+	kfree(chan);
+}
+
+static int
+nv50_channel_new(struct drm_device *dev, u32 size,
+		 struct nouveau_channel **pchan)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200;
+	u32  fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200;
+	struct nouveau_channel *chan;
+	int ret;
+
+	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+	if (!chan)
+		return -ENOMEM;
+	chan->dev = dev;
+
+	ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin);
+	if (ret) {
+		nv50_channel_del(&chan);
+		return ret;
+	}
+
+	ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size);
+	if (ret) {
+		nv50_channel_del(&chan);
+		return ret;
+	}
+
+	ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+				      chan->ramin->pinst + pgd,
+				      chan->ramin->vinst + pgd,
+				      0x4000, NVOBJ_FLAG_ZERO_ALLOC,
+				      &chan->vm_pd);
+	if (ret) {
+		nv50_channel_del(&chan);
+		return ret;
+	}
+
+	ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 :
+				      chan->ramin->pinst + fc,
+				      chan->ramin->vinst + fc, 0x100,
+				      NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc);
+	if (ret) {
+		nv50_channel_del(&chan);
+		return ret;
+	}
+
+	*pchan = chan;
+	return 0;
+}
 
 int
 nv50_instmem_init(struct drm_device *dev)
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size;
-	uint32_t save_nv001700;
-	uint64_t v;
 	struct nv50_instmem_priv *priv;
+	struct nouveau_channel *chan;
 	int ret, i;
+	u32 tmp;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -75,27 +123,61 @@
 	for (i = 0x1700; i <= 0x1710; i += 4)
 		priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
 
-	/* Reserve the last MiB of VRAM, we should probably try to avoid
-	 * setting up the below tables over the top of the VBIOS image at
-	 * some point.
-	 */
-	dev_priv->ramin_rsvd_vram = 1 << 20;
-	c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
-	c_size   = 128 << 10;
-	c_vmpd   = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
-	c_ramfc  = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
-	c_base   = c_vmpd + 0x4000;
-	pt_size  = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size);
+	/* Global PRAMIN heap */
+	ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size);
+	if (ret) {
+		NV_ERROR(dev, "Failed to init RAMIN heap\n");
+		return -ENOMEM;
+	}
 
-	NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset);
-	NV_DEBUG(dev, "    VBIOS image: 0x%08x\n",
-				(nv_rd32(dev, 0x619f04) & ~0xff) << 8);
-	NV_DEBUG(dev, "  Aperture size: %d MiB\n", dev_priv->ramin_size >> 20);
-	NV_DEBUG(dev, "        PT size: %d KiB\n", pt_size >> 10);
+	/* we need a channel to plug into the hw to control the BARs */
+	ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]);
+	if (ret)
+		return ret;
+	chan = dev_priv->fifos[127] = dev_priv->fifos[0];
 
-	/* Determine VM layout, we need to do this first to make sure
-	 * we allocate enough memory for all the page tables.
-	 */
+	/* allocate page table for PRAMIN BAR */
+	ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8,
+				 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
+				 &priv->pramin_pt);
+	if (ret)
+		return ret;
+
+	nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63);
+	nv_wo32(chan->vm_pd, 0x0004, 0);
+
+	/* DMA object for PRAMIN BAR */
+	ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar);
+	if (ret)
+		return ret;
+	nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000);
+	nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1);
+	nv_wo32(priv->pramin_bar, 0x08, 0x00000000);
+	nv_wo32(priv->pramin_bar, 0x0c, 0x00000000);
+	nv_wo32(priv->pramin_bar, 0x10, 0x00000000);
+	nv_wo32(priv->pramin_bar, 0x14, 0x00000000);
+
+	/* map channel into PRAMIN, gpuobj didn't do it for us */
+	ret = nv50_instmem_bind(dev, chan->ramin);
+	if (ret)
+		return ret;
+
+	/* poke regs... */
+	nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12));
+	nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12));
+	nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4));
+
+	tmp = nv_ri32(dev, 0);
+	nv_wi32(dev, 0, ~tmp);
+	if (nv_ri32(dev, 0) != ~tmp) {
+		NV_ERROR(dev, "PRAMIN readback failed\n");
+		return -EIO;
+	}
+	nv_wi32(dev, 0, tmp);
+
+	dev_priv->ramin_available = true;
+
+	/* Determine VM layout */
 	dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK);
 	dev_priv->vm_gart_size = NV50_VM_BLOCK;
 
@@ -115,172 +197,41 @@
 		 dev_priv->vm_vram_base,
 		 dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1);
 
-	c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8);
-
-	/* Map BAR0 PRAMIN aperture over the memory we want to use */
-	save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN);
-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16));
-
-	/* Create a fake channel, and use it as our "dummy" channels 0/127.
-	 * The main reason for creating a channel is so we can use the gpuobj
-	 * code.  However, it's probably worth noting that NVIDIA also setup
-	 * their channels 0/127 with the same values they configure here.
-	 * So, there may be some other reason for doing this.
-	 *
-	 * Have to create the entire channel manually, as the real channel
-	 * creation code assumes we have PRAMIN access, and we don't until
-	 * we're done here.
-	 */
-	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
-	if (!chan)
-		return -ENOMEM;
-	chan->id = 0;
-	chan->dev = dev;
-	chan->file_priv = (struct drm_file *)-2;
-	dev_priv->fifos[0] = dev_priv->fifos[127] = chan;
-
-	INIT_LIST_HEAD(&chan->ramht_refs);
-
-	/* Channel's PRAMIN object + heap */
-	ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0,
-							NULL, &chan->ramin);
-	if (ret)
-		return ret;
-
-	if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
-		return -ENOMEM;
-
-	/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
-	ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc,
-						0x4000, 0, NULL, &chan->ramfc);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < c_vmpd; i += 4)
-		BAR0_WI32(chan->ramin->gpuobj, i, 0);
-
-	/* VM page directory */
-	ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd,
-					   0x4000, 0, &chan->vm_pd, NULL);
-	if (ret)
-		return ret;
-	for (i = 0; i < 0x4000; i += 8) {
-		BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000);
-		BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000);
-	}
-
-	/* PRAMIN page table, cheat and map into VM at 0x0000000000.
-	 * We map the entire fake channel into the start of the PRAMIN BAR
-	 */
-	ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
-				     0, &priv->pramin_pt);
-	if (ret)
-		return ret;
-
-	v = c_offset | 1;
-	if (dev_priv->vram_sys_base) {
-		v += dev_priv->vram_sys_base;
-		v |= 0x30;
-	}
-
-	i = 0;
-	while (v < dev_priv->vram_sys_base + c_offset + c_size) {
-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v));
-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v));
-		v += 0x1000;
-		i += 8;
-	}
-
-	while (i < pt_size) {
-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
-		BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
-		i += 8;
-	}
-
-	BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
-	BAR0_WI32(chan->vm_pd, 0x04, 0x00000000);
-
 	/* VRAM page table(s), mapped into VM at +1GiB  */
 	for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-		ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0,
-					     NV50_VM_BLOCK/65536*8, 0, 0,
-					     &chan->vm_vram_pt[i]);
+		ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8,
+					 0, NVOBJ_FLAG_ZERO_ALLOC,
+					 &chan->vm_vram_pt[i]);
 		if (ret) {
-			NV_ERROR(dev, "Error creating VRAM page tables: %d\n",
-									ret);
+			NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret);
 			dev_priv->vm_vram_pt_nr = i;
 			return ret;
 		}
-		dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj;
-
-		for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size;
-								v += 4)
-			BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0);
+		dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i];
 
-		BAR0_WI32(chan->vm_pd, 0x10 + (i*8),
-			  chan->vm_vram_pt[i]->instance | 0x61);
-		BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0);
+		nv_wo32(chan->vm_pd, 0x10 + (i*8),
+			chan->vm_vram_pt[i]->vinst | 0x61);
+		nv_wo32(chan->vm_pd, 0x14 + (i*8), 0);
 	}
 
-	/* DMA object for PRAMIN BAR */
-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
-							&priv->pramin_bar);
-	if (ret)
-		return ret;
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000);
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1);
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000);
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000);
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000);
-	BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000);
-
 	/* DMA object for FB BAR */
-	ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0,
-							&priv->fb_bar);
+	ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar);
 	if (ret)
 		return ret;
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000);
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 +
-					      pci_resource_len(dev->pdev, 1) - 1);
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000);
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000);
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000);
-	BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000);
+	nv_wo32(priv->fb_bar, 0x00, 0x7fc00000);
+	nv_wo32(priv->fb_bar, 0x04, 0x40000000 +
+				    pci_resource_len(dev->pdev, 1) - 1);
+	nv_wo32(priv->fb_bar, 0x08, 0x40000000);
+	nv_wo32(priv->fb_bar, 0x0c, 0x00000000);
+	nv_wo32(priv->fb_bar, 0x10, 0x00000000);
+	nv_wo32(priv->fb_bar, 0x14, 0x00000000);
 
-	/* Poke the relevant regs, and pray it works :) */
-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
-	nv_wr32(dev, NV50_PUNK_UNK1710, 0);
-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
-					 NV50_PUNK_BAR_CFG_BASE_VALID);
-	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
-					NV50_PUNK_BAR1_CTXDMA_VALID);
-	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
-					NV50_PUNK_BAR3_CTXDMA_VALID);
+	dev_priv->engine.instmem.flush(dev);
 
+	nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4));
 	for (i = 0; i < 8; i++)
 		nv_wr32(dev, 0x1900 + (i*4), 0);
 
-	/* Assume that praying isn't enough, check that we can re-read the
-	 * entire fake channel back from the PRAMIN BAR */
-	for (i = 0; i < c_size; i += 4) {
-		if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
-			NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
-									i);
-			return -EINVAL;
-		}
-	}
-
-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
-
-	/* Global PRAMIN heap */
-	if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
-		NV_ERROR(dev, "Failed to init RAMIN heap\n");
-	}
-
-	/*XXX: incorrect, but needed to make hash func "work" */
-	dev_priv->ramht_offset = 0x10000;
-	dev_priv->ramht_bits   = 9;
-	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
 	return 0;
 }
 
@@ -297,29 +248,24 @@
 	if (!priv)
 		return;
 
+	dev_priv->ramin_available = false;
+
 	/* Restore state from before init */
 	for (i = 0x1700; i <= 0x1710; i += 4)
 		nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]);
 
-	nouveau_gpuobj_ref_del(dev, &priv->fb_bar);
-	nouveau_gpuobj_ref_del(dev, &priv->pramin_bar);
-	nouveau_gpuobj_ref_del(dev, &priv->pramin_pt);
+	nouveau_gpuobj_ref(NULL, &priv->fb_bar);
+	nouveau_gpuobj_ref(NULL, &priv->pramin_bar);
+	nouveau_gpuobj_ref(NULL, &priv->pramin_pt);
 
 	/* Destroy dummy channel */
 	if (chan) {
-		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) {
-			nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
-			dev_priv->vm_vram_pt[i] = NULL;
-		}
+		for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
+			nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]);
 		dev_priv->vm_vram_pt_nr = 0;
 
-		nouveau_gpuobj_del(dev, &chan->vm_pd);
-		nouveau_gpuobj_ref_del(dev, &chan->ramfc);
-		nouveau_gpuobj_ref_del(dev, &chan->ramin);
-		drm_mm_takedown(&chan->ramin_heap);
-
-		dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
-		kfree(chan);
+		nv50_channel_del(&dev_priv->fifos[0]);
+		dev_priv->fifos[127] = NULL;
 	}
 
 	dev_priv->engine.instmem.priv = NULL;
@@ -331,14 +277,14 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_channel *chan = dev_priv->fifos[0];
-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+	struct nouveau_gpuobj *ramin = chan->ramin;
 	int i;
 
-	ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size);
+	ramin->im_backing_suspend = vmalloc(ramin->size);
 	if (!ramin->im_backing_suspend)
 		return -ENOMEM;
 
-	for (i = 0; i < ramin->im_pramin->size; i += 4)
+	for (i = 0; i < ramin->size; i += 4)
 		ramin->im_backing_suspend[i/4] = nv_ri32(dev, i);
 	return 0;
 }
@@ -349,23 +295,25 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
 	struct nouveau_channel *chan = dev_priv->fifos[0];
-	struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
+	struct nouveau_gpuobj *ramin = chan->ramin;
 	int i;
 
-	nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16));
-	for (i = 0; i < ramin->im_pramin->size; i += 4)
-		BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]);
+	dev_priv->ramin_available = false;
+	dev_priv->ramin_base = ~0;
+	for (i = 0; i < ramin->size; i += 4)
+		nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]);
+	dev_priv->ramin_available = true;
 	vfree(ramin->im_backing_suspend);
 	ramin->im_backing_suspend = NULL;
 
 	/* Poke the relevant regs, and pray it works :) */
-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12));
+	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12));
 	nv_wr32(dev, NV50_PUNK_UNK1710, 0);
-	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) |
+	nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) |
 					 NV50_PUNK_BAR_CFG_BASE_VALID);
-	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) |
+	nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) |
 					NV50_PUNK_BAR1_CTXDMA_VALID);
-	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) |
+	nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) |
 					NV50_PUNK_BAR3_CTXDMA_VALID);
 
 	for (i = 0; i < 8; i++)
@@ -381,7 +329,7 @@
 	if (gpuobj->im_backing)
 		return -EINVAL;
 
-	*sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE);
+	*sz = ALIGN(*sz, 4096);
 	if (*sz == 0)
 		return -EINVAL;
 
@@ -399,9 +347,7 @@
 		return ret;
 	}
 
-	gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
-	gpuobj->im_backing_start <<= PAGE_SHIFT;
-
+	gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
 	return 0;
 }
 
@@ -424,7 +370,7 @@
 {
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
-	struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
+	struct nouveau_gpuobj *pramin_pt = priv->pramin_pt;
 	uint32_t pte, pte_end;
 	uint64_t vram;
 
@@ -436,11 +382,11 @@
 
 	pte     = (gpuobj->im_pramin->start >> 12) << 1;
 	pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
-	vram    = gpuobj->im_backing_start;
+	vram    = gpuobj->vinst;
 
 	NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
 		 gpuobj->im_pramin->start, pte, pte_end);
-	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+	NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
 
 	vram |= 1;
 	if (dev_priv->vram_sys_base) {
@@ -449,13 +395,13 @@
 	}
 
 	while (pte < pte_end) {
-		nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
-		nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
-		vram += NV50_INSTMEM_PAGE_SIZE;
+		nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram));
+		nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram));
+		vram += 0x1000;
+		pte += 2;
 	}
 	dev_priv->engine.instmem.flush(dev);
 
-	nv50_vm_flush(dev, 4);
 	nv50_vm_flush(dev, 6);
 
 	gpuobj->im_bound = 1;
@@ -472,12 +418,17 @@
 	if (gpuobj->im_bound == 0)
 		return -EINVAL;
 
+	/* can happen during late takedown */
+	if (unlikely(!dev_priv->ramin_available))
+		return 0;
+
 	pte     = (gpuobj->im_pramin->start >> 12) << 1;
 	pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
 
 	while (pte < pte_end) {
-		nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
-		nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
+		nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000);
+		nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000);
+		pte += 2;
 	}
 	dev_priv->engine.instmem.flush(dev);
 
@@ -489,7 +440,7 @@
 nv50_instmem_flush(struct drm_device *dev)
 {
 	nv_wr32(dev, 0x00330c, 0x00000001);
-	if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
+	if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000))
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -497,7 +448,7 @@
 nv84_instmem_flush(struct drm_device *dev)
 {
 	nv_wr32(dev, 0x070000, 0x00000001);
-	if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -505,7 +456,7 @@
 nv50_vm_flush(struct drm_device *dev, int engine)
 {
 	nv_wr32(dev, 0x100c80, (engine << 16) | 1);
-	if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
+	if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000))
 		NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_pm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_pm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 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"
+
+struct nv50_pm_state {
+	struct nouveau_pm_level *perflvl;
+	struct pll_lims pll;
+	enum pll_types type;
+	int N, M, P;
+};
+
+int
+nv50_pm_clock_get(struct drm_device *dev, u32 id)
+{
+	struct pll_lims pll;
+	int P, N, M, ret;
+	u32 reg0, reg1;
+
+	ret = get_pll_limits(dev, id, &pll);
+	if (ret)
+		return ret;
+
+	reg0 = nv_rd32(dev, pll.reg + 0);
+	reg1 = nv_rd32(dev, pll.reg + 4);
+	P = (reg0 & 0x00070000) >> 16;
+	N = (reg1 & 0x0000ff00) >> 8;
+	M = (reg1 & 0x000000ff);
+
+	return ((pll.refclk * N / M) >> P);
+}
+
+void *
+nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+		  u32 id, int khz)
+{
+	struct nv50_pm_state *state;
+	int dummy, ret;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+	state->type = id;
+	state->perflvl = perflvl;
+
+	ret = get_pll_limits(dev, id, &state->pll);
+	if (ret < 0) {
+		kfree(state);
+		return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+	}
+
+	ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M,
+			    &dummy, &dummy, &state->P);
+	if (ret < 0) {
+		kfree(state);
+		return ERR_PTR(ret);
+	}
+
+	return state;
+}
+
+void
+nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+	struct nv50_pm_state *state = pre_state;
+	struct nouveau_pm_level *perflvl = state->perflvl;
+	u32 reg = state->pll.reg, tmp;
+	struct bit_entry BIT_M;
+	u16 script;
+	int N = state->N;
+	int M = state->M;
+	int P = state->P;
+
+	if (state->type == PLL_MEMORY && perflvl->memscript &&
+	    bit_table(dev, 'M', &BIT_M) == 0 &&
+	    BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+		script = ROM16(BIT_M.data[0x05]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+		script = ROM16(BIT_M.data[0x07]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+		script = ROM16(BIT_M.data[0x09]);
+		if (script)
+			nouveau_bios_run_init_table(dev, script, NULL);
+
+		nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
+	}
+
+	if (state->type == PLL_MEMORY) {
+		nv_wr32(dev, 0x100210, 0);
+		nv_wr32(dev, 0x1002dc, 1);
+	}
+
+	tmp  = nv_rd32(dev, reg + 0) & 0xfff8ffff;
+	tmp |= 0x80000000 | (P << 16);
+	nv_wr32(dev, reg + 0, tmp);
+	nv_wr32(dev, reg + 4, (N << 8) | M);
+
+	if (state->type == PLL_MEMORY) {
+		nv_wr32(dev, 0x1002dc, 0);
+		nv_wr32(dev, 0x100210, 0x80000000);
+	}
+
+	kfree(state);
+}
+
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_sor.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_sor.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nv50_sor.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nv50_sor.c	2011-01-04 19:50:19.000000000 -0500
@@ -92,7 +92,7 @@
 	}
 
 	/* wait for it to be done */
-	if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
+	if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or),
 		     NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
 		NV_ERROR(dev, "timeout: SOR_DPMS_CTRL_PENDING(%d) == 0\n", or);
 		NV_ERROR(dev, "SOR_DPMS_CTRL(%d) = 0x%08x\n", or,
@@ -108,7 +108,7 @@
 
 	nv_wr32(dev, NV50_PDISPLAY_SOR_DPMS_CTRL(or), val |
 		NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING);
-	if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_STATE(or),
+	if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or),
 		     NV50_PDISPLAY_SOR_DPMS_STATE_WAIT, 0)) {
 		NV_ERROR(dev, "timeout: SOR_DPMS_STATE_WAIT(%d) == 0\n", or);
 		NV_ERROR(dev, "SOR_DPMS_STATE(%d) = 0x%08x\n", or,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nva3_pm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nva3_pm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nva3_pm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nva3_pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2010 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"
+
+/*XXX: boards using limits 0x40 need fixing, the register layout
+ *     is correct here, but, there's some other funny magic
+ *     that modifies things, so it's not likely we'll set/read
+ *     the correct timings yet..  working on it...
+ */
+
+struct nva3_pm_state {
+	struct pll_lims pll;
+	int N, M, P;
+};
+
+int
+nva3_pm_clock_get(struct drm_device *dev, u32 id)
+{
+	struct pll_lims pll;
+	int P, N, M, ret;
+	u32 reg;
+
+	ret = get_pll_limits(dev, id, &pll);
+	if (ret)
+		return ret;
+
+	reg = nv_rd32(dev, pll.reg + 4);
+	P = (reg & 0x003f0000) >> 16;
+	N = (reg & 0x0000ff00) >> 8;
+	M = (reg & 0x000000ff);
+	return pll.refclk * N / M / P;
+}
+
+void *
+nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
+		  u32 id, int khz)
+{
+	struct nva3_pm_state *state;
+	int dummy, ret;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return ERR_PTR(-ENOMEM);
+
+	ret = get_pll_limits(dev, id, &state->pll);
+	if (ret < 0) {
+		kfree(state);
+		return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+	}
+
+	ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
+			     &state->M, &state->P);
+	if (ret < 0) {
+		kfree(state);
+		return ERR_PTR(ret);
+	}
+
+	return state;
+}
+
+void
+nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
+{
+	struct nva3_pm_state *state = pre_state;
+	u32 reg = state->pll.reg;
+
+	nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
+	kfree(state);
+}
+
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvc0_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvc0_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvc0_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvc0_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,12 +43,6 @@
 }
 
 bool
-nvc0_fifo_cache_flush(struct drm_device *dev)
-{
-	return true;
-}
-
-bool
 nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
 {
 	return false;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvc0_instmem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvc0_instmem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvc0_instmem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvc0_instmem.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,8 +50,7 @@
 		return ret;
 	}
 
-	gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
-	gpuobj->im_backing_start <<= PAGE_SHIFT;
+	gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT;
 	return 0;
 }
 
@@ -84,11 +83,11 @@
 
 	pte     = gpuobj->im_pramin->start >> 12;
 	pte_end = (gpuobj->im_pramin->size >> 12) + pte;
-	vram    = gpuobj->im_backing_start;
+	vram    = gpuobj->vinst;
 
 	NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
 		 gpuobj->im_pramin->start, pte, pte_end);
-	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+	NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst);
 
 	while (pte < pte_end) {
 		nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
@@ -134,7 +133,7 @@
 nvc0_instmem_flush(struct drm_device *dev)
 {
 	nv_wr32(dev, 0x070000, 1);
-	if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+	if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000))
 		NV_ERROR(dev, "PRAMIN flush timeout\n");
 }
 
@@ -221,10 +220,6 @@
 		return -ENOMEM;
 	}
 
-	/*XXX: incorrect, but needed to make hash func "work" */
-	dev_priv->ramht_offset = 0x10000;
-	dev_priv->ramht_bits   = 9;
-	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits) * 8;
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvreg.h linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvreg.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/nouveau/nvreg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/nouveau/nvreg.h	2011-01-04 19:50:19.000000000 -0500
@@ -263,6 +263,7 @@
 #		define NV_CIO_CRE_HCUR_ADDR1_ADR	7:2
 #	define NV_CIO_CRE_LCD__INDEX		0x33
 #		define NV_CIO_CRE_LCD_LCD_SELECT	0:0
+#		define NV_CIO_CRE_LCD_ROUTE_MASK	0x3b
 #	define NV_CIO_CRE_DDC0_STATUS__INDEX	0x36
 #	define NV_CIO_CRE_DDC0_WR__INDEX	0x37
 #	define NV_CIO_CRE_ILACE__INDEX		0x39	/* interlace */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/r128/r128_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/r128/r128_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/r128/r128_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/r128/r128_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -56,8 +56,6 @@
 	.irq_uninstall = r128_driver_irq_uninstall,
 	.irq_handler = r128_driver_irq_handler,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = r128_ioctls,
 	.dma_ioctl = r128_cce_buffers,
 	.fops = {
@@ -71,6 +69,7 @@
 #ifdef CONFIG_COMPAT
 		.compat_ioctl = r128_compat_ioctl,
 #endif
+		.llseek = noop_llseek,
 	},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/atombios_crtc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/atombios_crtc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/atombios_crtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/atombios_crtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -253,7 +253,8 @@
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
 		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
-		atombios_blank_crtc(crtc, ATOM_ENABLE);
+		if (radeon_crtc->enabled)
+			atombios_blank_crtc(crtc, ATOM_ENABLE);
 		if (ASIC_IS_DCE3(rdev))
 			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
 		atombios_enable_crtc(crtc, ATOM_DISABLE);
@@ -398,65 +399,76 @@
 
 
 union atom_enable_ss {
-	ENABLE_LVDS_SS_PARAMETERS legacy;
+	ENABLE_LVDS_SS_PARAMETERS lvds_ss;
+	ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2;
 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
+	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
 };
 
-static void atombios_enable_ss(struct drm_crtc *crtc)
+static void atombios_crtc_program_ss(struct drm_crtc *crtc,
+				     int enable,
+				     int pll_id,
+				     struct radeon_atom_ss *ss)
 {
-	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct radeon_device *rdev = dev->dev_private;
-	struct drm_encoder *encoder = NULL;
-	struct radeon_encoder *radeon_encoder = NULL;
-	struct radeon_encoder_atom_dig *dig = NULL;
 	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
 	union atom_enable_ss args;
-	uint16_t percentage = 0;
-	uint8_t type = 0, step = 0, delay = 0, range = 0;
 
-	/* XXX add ss support for DCE4 */
-	if (ASIC_IS_DCE4(rdev))
-		return;
+	memset(&args, 0, sizeof(args));
 
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		if (encoder->crtc == crtc) {
-			radeon_encoder = to_radeon_encoder(encoder);
-			/* only enable spread spectrum on LVDS */
-			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-				dig = radeon_encoder->enc_priv;
-				if (dig && dig->ss) {
-					percentage = dig->ss->percentage;
-					type = dig->ss->type;
-					step = dig->ss->step;
-					delay = dig->ss->delay;
-					range = dig->ss->range;
-				} else
-					return;
-			} else
-				return;
+	if (ASIC_IS_DCE4(rdev)) {
+		args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+		args.v2.ucSpreadSpectrumType = ss->type;
+		switch (pll_id) {
+		case ATOM_PPLL1:
+			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
+			args.v2.usSpreadSpectrumAmount = ss->amount;
+			args.v2.usSpreadSpectrumStep = ss->step;
 			break;
+		case ATOM_PPLL2:
+			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P2PLL;
+			args.v2.usSpreadSpectrumAmount = ss->amount;
+			args.v2.usSpreadSpectrumStep = ss->step;
+			break;
+		case ATOM_DCPLL:
+			args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_DCPLL;
+			args.v2.usSpreadSpectrumAmount = 0;
+			args.v2.usSpreadSpectrumStep = 0;
+			break;
+		case ATOM_PPLL_INVALID:
+			return;
 		}
-	}
-
-	if (!radeon_encoder)
-		return;
-
-	memset(&args, 0, sizeof(args));
-	if (ASIC_IS_AVIVO(rdev)) {
-		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
-		args.v1.ucSpreadSpectrumType = type;
-		args.v1.ucSpreadSpectrumStep = step;
-		args.v1.ucSpreadSpectrumDelay = delay;
-		args.v1.ucSpreadSpectrumRange = range;
-		args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
-		args.v1.ucEnable = ATOM_ENABLE;
+		args.v2.ucEnable = enable;
+	} else if (ASIC_IS_DCE3(rdev)) {
+		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+		args.v1.ucSpreadSpectrumType = ss->type;
+		args.v1.ucSpreadSpectrumStep = ss->step;
+		args.v1.ucSpreadSpectrumDelay = ss->delay;
+		args.v1.ucSpreadSpectrumRange = ss->range;
+		args.v1.ucPpll = pll_id;
+		args.v1.ucEnable = enable;
+	} else if (ASIC_IS_AVIVO(rdev)) {
+		if (enable == ATOM_DISABLE) {
+			atombios_disable_ss(crtc);
+			return;
+		}
+		args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+		args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+		args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
+		args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
+		args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
+		args.lvds_ss_2.ucEnable = enable;
 	} else {
-		args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
-		args.legacy.ucSpreadSpectrumType = type;
-		args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
-		args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
-		args.legacy.ucEnable = ATOM_ENABLE;
+		if (enable == ATOM_DISABLE) {
+			atombios_disable_ss(crtc);
+			return;
+		}
+		args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
+		args.lvds_ss.ucSpreadSpectrumType = ss->type;
+		args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
+		args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
+		args.lvds_ss.ucEnable = enable;
 	}
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
@@ -468,7 +480,9 @@
 
 static u32 atombios_adjust_pll(struct drm_crtc *crtc,
 			       struct drm_display_mode *mode,
-			       struct radeon_pll *pll)
+			       struct radeon_pll *pll,
+			       bool ss_enabled,
+			       struct radeon_atom_ss *ss)
 {
 	struct drm_device *dev = crtc->dev;
 	struct radeon_device *rdev = dev->dev_private;
@@ -482,19 +496,6 @@
 	/* reset the pll flags */
 	pll->flags = 0;
 
-	/* select the PLL algo */
-	if (ASIC_IS_AVIVO(rdev)) {
-		if (radeon_new_pll == 0)
-			pll->algo = PLL_ALGO_LEGACY;
-		else
-			pll->algo = PLL_ALGO_NEW;
-	} else {
-		if (radeon_new_pll == 1)
-			pll->algo = PLL_ALGO_NEW;
-		else
-			pll->algo = PLL_ALGO_LEGACY;
-	}
-
 	if (ASIC_IS_AVIVO(rdev)) {
 		if ((rdev->family == CHIP_RS600) ||
 		    (rdev->family == CHIP_RS690) ||
@@ -530,30 +531,23 @@
 					dp_clock = dig_connector->dp_clock;
 				}
 			}
-
+#if 0 /* doesn't work properly on some laptops */
+			/* use recommended ref_div for ss */
+			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+				if (ss_enabled) {
+					if (ss->refdiv) {
+						pll->flags |= RADEON_PLL_USE_REF_DIV;
+						pll->reference_div = ss->refdiv;
+					}
+				}
+			}
+#endif
 			if (ASIC_IS_AVIVO(rdev)) {
 				/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
 				if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
 					adjusted_clock = mode->clock * 2;
-				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
-					pll->algo = PLL_ALGO_LEGACY;
+				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
 					pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
-				}
-				/* There is some evidence (often anecdotal) that RV515/RV620 LVDS
-				 * (on some boards at least) prefers the legacy algo.  I'm not
-				 * sure whether this should handled generically or on a
-				 * case-by-case quirk basis.  Both algos should work fine in the
-				 * majority of cases.
-				 */
-				if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
-				    ((rdev->family == CHIP_RV515) ||
-				     (rdev->family == CHIP_RV620))) {
-					/* allow the user to overrride just in case */
-					if (radeon_new_pll == 1)
-						pll->algo = PLL_ALGO_NEW;
-					else
-						pll->algo = PLL_ALGO_LEGACY;
-				}
 			} else {
 				if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
 					pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
@@ -589,9 +583,9 @@
 				args.v1.ucTransmitterID = radeon_encoder->encoder_id;
 				args.v1.ucEncodeMode = encoder_mode;
 				if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-					/* may want to enable SS on DP eventually */
-					/* args.v1.ucConfig |=
-					   ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/
+					if (ss_enabled)
+						args.v1.ucConfig |=
+							ADJUST_DISPLAY_CONFIG_SS_ENABLE;
 				} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
 					args.v1.ucConfig |=
 						ADJUST_DISPLAY_CONFIG_SS_ENABLE;
@@ -608,11 +602,10 @@
 				args.v3.sInput.ucDispPllConfig = 0;
 				if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
 					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-
 					if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-						/* may want to enable SS on DP/eDP eventually */
-						/*args.v3.sInput.ucDispPllConfig |=
-						  DISPPLL_CONFIG_SS_ENABLE;*/
+						if (ss_enabled)
+							args.v3.sInput.ucDispPllConfig |=
+								DISPPLL_CONFIG_SS_ENABLE;
 						args.v3.sInput.ucDispPllConfig |=
 							DISPPLL_CONFIG_COHERENT_MODE;
 						/* 16200 or 27000 */
@@ -632,17 +625,17 @@
 					}
 				} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
 					if (encoder_mode == ATOM_ENCODER_MODE_DP) {
-						/* may want to enable SS on DP/eDP eventually */
-						/*args.v3.sInput.ucDispPllConfig |=
-						  DISPPLL_CONFIG_SS_ENABLE;*/
+						if (ss_enabled)
+							args.v3.sInput.ucDispPllConfig |=
+								DISPPLL_CONFIG_SS_ENABLE;
 						args.v3.sInput.ucDispPllConfig |=
 							DISPPLL_CONFIG_COHERENT_MODE;
 						/* 16200 or 27000 */
 						args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
 					} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
-						/* want to enable SS on LVDS eventually */
-						/*args.v3.sInput.ucDispPllConfig |=
-						  DISPPLL_CONFIG_SS_ENABLE;*/
+						if (ss_enabled)
+							args.v3.sInput.ucDispPllConfig |=
+								DISPPLL_CONFIG_SS_ENABLE;
 					} else {
 						if (mode->clock > 165000)
 							args.v3.sInput.ucDispPllConfig |=
@@ -816,6 +809,8 @@
 	struct radeon_pll *pll;
 	u32 adjusted_clock;
 	int encoder_mode = 0;
+	struct radeon_atom_ss ss;
+	bool ss_enabled = false;
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 		if (encoder->crtc == crtc) {
@@ -842,25 +837,123 @@
 		break;
 	}
 
+	if (radeon_encoder->active_device &
+	    (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
+		struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+		struct drm_connector *connector =
+			radeon_get_connector_for_encoder(encoder);
+		struct radeon_connector *radeon_connector =
+			to_radeon_connector(connector);
+		struct radeon_connector_atom_dig *dig_connector =
+			radeon_connector->con_priv;
+		int dp_clock;
+
+		switch (encoder_mode) {
+		case ATOM_ENCODER_MODE_DP:
+			/* DP/eDP */
+			dp_clock = dig_connector->dp_clock / 10;
+			if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
+				if (ASIC_IS_DCE4(rdev))
+					ss_enabled =
+						radeon_atombios_get_asic_ss_info(rdev, &ss,
+										 dig->lcd_ss_id,
+										 dp_clock);
+				else
+					ss_enabled =
+						radeon_atombios_get_ppll_ss_info(rdev, &ss,
+										 dig->lcd_ss_id);
+			} else {
+				if (ASIC_IS_DCE4(rdev))
+					ss_enabled =
+						radeon_atombios_get_asic_ss_info(rdev, &ss,
+										 ASIC_INTERNAL_SS_ON_DP,
+										 dp_clock);
+				else {
+					if (dp_clock == 16200) {
+						ss_enabled =
+							radeon_atombios_get_ppll_ss_info(rdev, &ss,
+											 ATOM_DP_SS_ID2);
+						if (!ss_enabled)
+							ss_enabled =
+								radeon_atombios_get_ppll_ss_info(rdev, &ss,
+												 ATOM_DP_SS_ID1);
+					} else
+						ss_enabled =
+							radeon_atombios_get_ppll_ss_info(rdev, &ss,
+											 ATOM_DP_SS_ID1);
+				}
+			}
+			break;
+		case ATOM_ENCODER_MODE_LVDS:
+			if (ASIC_IS_DCE4(rdev))
+				ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+									      dig->lcd_ss_id,
+									      mode->clock / 10);
+			else
+				ss_enabled = radeon_atombios_get_ppll_ss_info(rdev, &ss,
+									      dig->lcd_ss_id);
+			break;
+		case ATOM_ENCODER_MODE_DVI:
+			if (ASIC_IS_DCE4(rdev))
+				ss_enabled =
+					radeon_atombios_get_asic_ss_info(rdev, &ss,
+									 ASIC_INTERNAL_SS_ON_TMDS,
+									 mode->clock / 10);
+			break;
+		case ATOM_ENCODER_MODE_HDMI:
+			if (ASIC_IS_DCE4(rdev))
+				ss_enabled =
+					radeon_atombios_get_asic_ss_info(rdev, &ss,
+									 ASIC_INTERNAL_SS_ON_HDMI,
+									 mode->clock / 10);
+			break;
+		default:
+			break;
+		}
+	}
+
 	/* adjust pixel clock as needed */
-	adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
+	adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss);
 
 	radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
 			   &ref_div, &post_div);
 
+	atombios_crtc_program_ss(crtc, ATOM_DISABLE, radeon_crtc->pll_id, &ss);
+
 	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
 				  encoder_mode, radeon_encoder->encoder_id, mode->clock,
 				  ref_div, fb_div, frac_fb_div, post_div);
 
+	if (ss_enabled) {
+		/* calculate ss amount and step size */
+		if (ASIC_IS_DCE4(rdev)) {
+			u32 step_size;
+			u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
+			ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
+			ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+				ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
+			if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
+				step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
+					(125 * 25 * pll->reference_freq / 100);
+			else
+				step_size = (2 * amount * ref_div * (ss.rate * 2048)) /
+					(125 * 25 * pll->reference_freq / 100);
+			ss.step = step_size;
+		}
+
+		atombios_crtc_program_ss(crtc, ATOM_ENABLE, radeon_crtc->pll_id, &ss);
+	}
 }
 
-static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
-				   struct drm_framebuffer *old_fb)
+static int evergreen_crtc_do_set_base(struct drm_crtc *crtc,
+				      struct drm_framebuffer *fb,
+				      int x, int y, int atomic)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_framebuffer *radeon_fb;
+	struct drm_framebuffer *target_fb;
 	struct drm_gem_object *obj;
 	struct radeon_bo *rbo;
 	uint64_t fb_location;
@@ -868,28 +961,43 @@
 	int r;
 
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!atomic && !crtc->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
 
-	radeon_fb = to_radeon_framebuffer(crtc->fb);
+	if (atomic) {
+		radeon_fb = to_radeon_framebuffer(fb);
+		target_fb = fb;
+	}
+	else {
+		radeon_fb = to_radeon_framebuffer(crtc->fb);
+		target_fb = crtc->fb;
+	}
 
-	/* Pin framebuffer & get tilling informations */
+	/* If atomic, assume fb object is pinned & idle & fenced and
+	 * just update base pointers
+	 */
 	obj = radeon_fb->obj;
 	rbo = obj->driver_private;
 	r = radeon_bo_reserve(rbo, false);
 	if (unlikely(r != 0))
 		return r;
-	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
-	if (unlikely(r != 0)) {
-		radeon_bo_unreserve(rbo);
-		return -EINVAL;
+
+	if (atomic)
+		fb_location = radeon_bo_gpu_offset(rbo);
+	else {
+		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+		if (unlikely(r != 0)) {
+			radeon_bo_unreserve(rbo);
+			return -EINVAL;
+		}
 	}
+
 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
 	radeon_bo_unreserve(rbo);
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (target_fb->bits_per_pixel) {
 	case 8:
 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
@@ -909,7 +1017,7 @@
 		break;
 	default:
 		DRM_ERROR("Unsupported screen depth %d\n",
-			  crtc->fb->bits_per_pixel);
+			  target_fb->bits_per_pixel);
 		return -EINVAL;
 	}
 
@@ -955,10 +1063,10 @@
 	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
 	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
 	WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
-	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
-	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
 
-	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+	fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
 	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
@@ -977,8 +1085,8 @@
 	else
 		WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
 
-	if (old_fb && old_fb != crtc->fb) {
-		radeon_fb = to_radeon_framebuffer(old_fb);
+	if (!atomic && fb && fb != crtc->fb) {
+		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = radeon_fb->obj->driver_private;
 		r = radeon_bo_reserve(rbo, false);
 		if (unlikely(r != 0))
@@ -993,8 +1101,9 @@
 	return 0;
 }
 
-static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
-			       struct drm_framebuffer *old_fb)
+static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
+				  struct drm_framebuffer *fb,
+				  int x, int y, int atomic)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
@@ -1002,33 +1111,48 @@
 	struct radeon_framebuffer *radeon_fb;
 	struct drm_gem_object *obj;
 	struct radeon_bo *rbo;
+	struct drm_framebuffer *target_fb;
 	uint64_t fb_location;
 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
 	int r;
 
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!atomic && !crtc->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
 
-	radeon_fb = to_radeon_framebuffer(crtc->fb);
+	if (atomic) {
+		radeon_fb = to_radeon_framebuffer(fb);
+		target_fb = fb;
+	}
+	else {
+		radeon_fb = to_radeon_framebuffer(crtc->fb);
+		target_fb = crtc->fb;
+	}
 
-	/* Pin framebuffer & get tilling informations */
 	obj = radeon_fb->obj;
 	rbo = obj->driver_private;
 	r = radeon_bo_reserve(rbo, false);
 	if (unlikely(r != 0))
 		return r;
-	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
-	if (unlikely(r != 0)) {
-		radeon_bo_unreserve(rbo);
-		return -EINVAL;
+
+	/* If atomic, assume fb object is pinned & idle & fenced and
+	 * just update base pointers
+	 */
+	if (atomic)
+		fb_location = radeon_bo_gpu_offset(rbo);
+	else {
+		r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
+		if (unlikely(r != 0)) {
+			radeon_bo_unreserve(rbo);
+			return -EINVAL;
+		}
 	}
 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
 	radeon_bo_unreserve(rbo);
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (target_fb->bits_per_pixel) {
 	case 8:
 		fb_format =
 		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
@@ -1052,7 +1176,7 @@
 		break;
 	default:
 		DRM_ERROR("Unsupported screen depth %d\n",
-			  crtc->fb->bits_per_pixel);
+			  target_fb->bits_per_pixel);
 		return -EINVAL;
 	}
 
@@ -1093,10 +1217,10 @@
 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
 	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
 	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
-	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
-	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, target_fb->width);
+	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, target_fb->height);
 
-	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+	fb_pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
 	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
 
@@ -1115,8 +1239,8 @@
 	else
 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
 
-	if (old_fb && old_fb != crtc->fb) {
-		radeon_fb = to_radeon_framebuffer(old_fb);
+	if (!atomic && fb && fb != crtc->fb) {
+		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = radeon_fb->obj->driver_private;
 		r = radeon_bo_reserve(rbo, false);
 		if (unlikely(r != 0))
@@ -1138,11 +1262,26 @@
 	struct radeon_device *rdev = dev->dev_private;
 
 	if (ASIC_IS_DCE4(rdev))
-		return evergreen_crtc_set_base(crtc, x, y, old_fb);
+		return evergreen_crtc_do_set_base(crtc, old_fb, x, y, 0);
 	else if (ASIC_IS_AVIVO(rdev))
-		return avivo_crtc_set_base(crtc, x, y, old_fb);
+		return avivo_crtc_do_set_base(crtc, old_fb, x, y, 0);
 	else
-		return radeon_crtc_set_base(crtc, x, y, old_fb);
+		return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+                                  struct drm_framebuffer *fb,
+				  int x, int y, enum mode_set_atomic state)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+	if (ASIC_IS_DCE4(rdev))
+		return evergreen_crtc_do_set_base(crtc, fb, x, y, 1);
+	else if (ASIC_IS_AVIVO(rdev))
+		return avivo_crtc_do_set_base(crtc, fb, x, y, 1);
+	else
+		return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
 }
 
 /* properly set additional regs when using atombios */
@@ -1230,12 +1369,19 @@
 		}
 	}
 
-	atombios_disable_ss(crtc);
 	/* always set DCPLL */
-	if (ASIC_IS_DCE4(rdev))
+	if (ASIC_IS_DCE4(rdev)) {
+		struct radeon_atom_ss ss;
+		bool ss_enabled = radeon_atombios_get_asic_ss_info(rdev, &ss,
+								   ASIC_INTERNAL_SS_ON_DCPLL,
+								   rdev->clock.default_dispclk);
+		if (ss_enabled)
+			atombios_crtc_program_ss(crtc, ATOM_DISABLE, ATOM_DCPLL, &ss);
 		atombios_crtc_set_dcpll(crtc);
+		if (ss_enabled)
+			atombios_crtc_program_ss(crtc, ATOM_ENABLE, ATOM_DCPLL, &ss);
+	}
 	atombios_crtc_set_pll(crtc, adjusted_mode);
-	atombios_enable_ss(crtc);
 
 	if (ASIC_IS_DCE4(rdev))
 		atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
@@ -1311,6 +1457,7 @@
 	.mode_fixup = atombios_crtc_mode_fixup,
 	.mode_set = atombios_crtc_mode_set,
 	.mode_set_base = atombios_crtc_set_base,
+	.mode_set_base_atomic = atombios_crtc_set_base_atomic,
 	.prepare = atombios_crtc_prepare,
 	.commit = atombios_crtc_commit,
 	.load_lut = radeon_crtc_load_lut,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/atom.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/atom.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/atom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/atom.c	2011-01-04 19:50:19.000000000 -0500
@@ -112,6 +112,7 @@
 			base += 3;
 			break;
 		case ATOM_IIO_WRITE:
+			(void)ctx->card->ioreg_read(ctx->card, CU16(base + 1));
 			ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp);
 			base += 3;
 			break;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_kms.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_kms.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_kms.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_kms.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,774 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, 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 (including the next
+ * paragraph) 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) AND/OR ITS SUPPLIERS 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:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#include "evergreend.h"
+#include "evergreen_blit_shaders.h"
+
+#define DI_PT_RECTLIST        0x11
+#define DI_INDEX_SIZE_16_BIT  0x0
+#define DI_SRC_SEL_AUTO_INDEX 0x2
+
+#define FMT_8                 0x1
+#define FMT_5_6_5             0x8
+#define FMT_8_8_8_8           0x1a
+#define COLOR_8               0x1
+#define COLOR_5_6_5           0x8
+#define COLOR_8_8_8_8         0x1a
+
+/* emits 17 */
+static void
+set_render_target(struct radeon_device *rdev, int format,
+		  int w, int h, u64 gpu_addr)
+{
+	u32 cb_color_info;
+	int pitch, slice;
+
+	h = ALIGN(h, 8);
+	if (h < 8)
+		h = 8;
+
+	cb_color_info = ((format << 2) | (1 << 24));
+	pitch = (w / 8) - 1;
+	slice = ((w * h) / 64) - 1;
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 15));
+	radeon_ring_write(rdev, (CB_COLOR0_BASE - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, gpu_addr >> 8);
+	radeon_ring_write(rdev, pitch);
+	radeon_ring_write(rdev, slice);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, cb_color_info);
+	radeon_ring_write(rdev, (1 << 4));
+	radeon_ring_write(rdev, (w - 1) | ((h - 1) << 16));
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+}
+
+/* emits 5dw */
+static void
+cp_set_surface_sync(struct radeon_device *rdev,
+		    u32 sync_type, u32 size,
+		    u64 mc_addr)
+{
+	u32 cp_coher_size;
+
+	if (size == 0xffffffff)
+		cp_coher_size = 0xffffffff;
+	else
+		cp_coher_size = ((size + 255) >> 8);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3));
+	radeon_ring_write(rdev, sync_type);
+	radeon_ring_write(rdev, cp_coher_size);
+	radeon_ring_write(rdev, mc_addr >> 8);
+	radeon_ring_write(rdev, 10); /* poll interval */
+}
+
+/* emits 11dw + 1 surface sync = 16dw */
+static void
+set_shaders(struct radeon_device *rdev)
+{
+	u64 gpu_addr;
+
+	/* VS */
+	gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 3));
+	radeon_ring_write(rdev, (SQ_PGM_START_VS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, gpu_addr >> 8);
+	radeon_ring_write(rdev, 2);
+	radeon_ring_write(rdev, 0);
+
+	/* PS */
+	gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.ps_offset;
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 4));
+	radeon_ring_write(rdev, (SQ_PGM_START_PS - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, gpu_addr >> 8);
+	radeon_ring_write(rdev, 1);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 2);
+
+	gpu_addr = rdev->r600_blit.shader_gpu_addr + rdev->r600_blit.vs_offset;
+	cp_set_surface_sync(rdev, PACKET3_SH_ACTION_ENA, 512, gpu_addr);
+}
+
+/* emits 10 + 1 sync (5) = 15 */
+static void
+set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr)
+{
+	u32 sq_vtx_constant_word2, sq_vtx_constant_word3;
+
+	/* high addr, stride */
+	sq_vtx_constant_word2 = ((upper_32_bits(gpu_addr) & 0xff) | (16 << 8));
+	/* xyzw swizzles */
+	sq_vtx_constant_word3 = (0 << 3) | (1 << 6) | (2 << 9) | (3 << 12);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+	radeon_ring_write(rdev, 0x580);
+	radeon_ring_write(rdev, gpu_addr & 0xffffffff);
+	radeon_ring_write(rdev, 48 - 1); /* size */
+	radeon_ring_write(rdev, sq_vtx_constant_word2);
+	radeon_ring_write(rdev, sq_vtx_constant_word3);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30);
+
+	if (rdev->family == CHIP_CEDAR)
+		cp_set_surface_sync(rdev,
+				    PACKET3_TC_ACTION_ENA, 48, gpu_addr);
+	else
+		cp_set_surface_sync(rdev,
+				    PACKET3_VC_ACTION_ENA, 48, gpu_addr);
+
+}
+
+/* emits 10 */
+static void
+set_tex_resource(struct radeon_device *rdev,
+		 int format, int w, int h, int pitch,
+		 u64 gpu_addr)
+{
+	u32 sq_tex_resource_word0, sq_tex_resource_word1;
+	u32 sq_tex_resource_word4, sq_tex_resource_word7;
+
+	if (h < 1)
+		h = 1;
+
+	sq_tex_resource_word0 = (1 << 0); /* 2D */
+	sq_tex_resource_word0 |= ((((pitch >> 3) - 1) << 6) |
+				  ((w - 1) << 18));
+	sq_tex_resource_word1 = ((h - 1) << 0);
+	/* xyzw swizzles */
+	sq_tex_resource_word4 = (0 << 16) | (1 << 19) | (2 << 22) | (3 << 25);
+
+	sq_tex_resource_word7 = format | (SQ_TEX_VTX_VALID_TEXTURE << 30);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8));
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, sq_tex_resource_word0);
+	radeon_ring_write(rdev, sq_tex_resource_word1);
+	radeon_ring_write(rdev, gpu_addr >> 8);
+	radeon_ring_write(rdev, gpu_addr >> 8);
+	radeon_ring_write(rdev, sq_tex_resource_word4);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, sq_tex_resource_word7);
+}
+
+/* emits 12 */
+static void
+set_scissors(struct radeon_device *rdev, int x1, int y1,
+	     int x2, int y2)
+{
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+	radeon_ring_write(rdev, (PA_SC_SCREEN_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, (x1 << 0) | (y1 << 16));
+	radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+	radeon_ring_write(rdev, (PA_SC_GENERIC_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+	radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+	radeon_ring_write(rdev, (PA_SC_WINDOW_SCISSOR_TL - PACKET3_SET_CONTEXT_REG_START) >> 2);
+	radeon_ring_write(rdev, (x1 << 0) | (y1 << 16) | (1 << 31));
+	radeon_ring_write(rdev, (x2 << 0) | (y2 << 16));
+}
+
+/* emits 10 */
+static void
+draw_auto(struct radeon_device *rdev)
+{
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+	radeon_ring_write(rdev, (VGT_PRIMITIVE_TYPE - PACKET3_SET_CONFIG_REG_START) >> 2);
+	radeon_ring_write(rdev, DI_PT_RECTLIST);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_INDEX_TYPE, 0));
+	radeon_ring_write(rdev, DI_INDEX_SIZE_16_BIT);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_NUM_INSTANCES, 0));
+	radeon_ring_write(rdev, 1);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_DRAW_INDEX_AUTO, 1));
+	radeon_ring_write(rdev, 3);
+	radeon_ring_write(rdev, DI_SRC_SEL_AUTO_INDEX);
+
+}
+
+/* emits 30 */
+static void
+set_default_state(struct radeon_device *rdev)
+{
+	u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2, sq_gpr_resource_mgmt_3;
+	u32 sq_thread_resource_mgmt, sq_thread_resource_mgmt_2;
+	u32 sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2, sq_stack_resource_mgmt_3;
+	int num_ps_gprs, num_vs_gprs, num_temp_gprs;
+	int num_gs_gprs, num_es_gprs, num_hs_gprs, num_ls_gprs;
+	int num_ps_threads, num_vs_threads, num_gs_threads, num_es_threads;
+	int num_hs_threads, num_ls_threads;
+	int num_ps_stack_entries, num_vs_stack_entries, num_gs_stack_entries, num_es_stack_entries;
+	int num_hs_stack_entries, num_ls_stack_entries;
+
+	switch (rdev->family) {
+	case CHIP_CEDAR:
+	default:
+		num_ps_gprs = 93;
+		num_vs_gprs = 46;
+		num_temp_gprs = 4;
+		num_gs_gprs = 31;
+		num_es_gprs = 31;
+		num_hs_gprs = 23;
+		num_ls_gprs = 23;
+		num_ps_threads = 96;
+		num_vs_threads = 16;
+		num_gs_threads = 16;
+		num_es_threads = 16;
+		num_hs_threads = 16;
+		num_ls_threads = 16;
+		num_ps_stack_entries = 42;
+		num_vs_stack_entries = 42;
+		num_gs_stack_entries = 42;
+		num_es_stack_entries = 42;
+		num_hs_stack_entries = 42;
+		num_ls_stack_entries = 42;
+		break;
+	case CHIP_REDWOOD:
+		num_ps_gprs = 93;
+		num_vs_gprs = 46;
+		num_temp_gprs = 4;
+		num_gs_gprs = 31;
+		num_es_gprs = 31;
+		num_hs_gprs = 23;
+		num_ls_gprs = 23;
+		num_ps_threads = 128;
+		num_vs_threads = 20;
+		num_gs_threads = 20;
+		num_es_threads = 20;
+		num_hs_threads = 20;
+		num_ls_threads = 20;
+		num_ps_stack_entries = 42;
+		num_vs_stack_entries = 42;
+		num_gs_stack_entries = 42;
+		num_es_stack_entries = 42;
+		num_hs_stack_entries = 42;
+		num_ls_stack_entries = 42;
+		break;
+	case CHIP_JUNIPER:
+		num_ps_gprs = 93;
+		num_vs_gprs = 46;
+		num_temp_gprs = 4;
+		num_gs_gprs = 31;
+		num_es_gprs = 31;
+		num_hs_gprs = 23;
+		num_ls_gprs = 23;
+		num_ps_threads = 128;
+		num_vs_threads = 20;
+		num_gs_threads = 20;
+		num_es_threads = 20;
+		num_hs_threads = 20;
+		num_ls_threads = 20;
+		num_ps_stack_entries = 85;
+		num_vs_stack_entries = 85;
+		num_gs_stack_entries = 85;
+		num_es_stack_entries = 85;
+		num_hs_stack_entries = 85;
+		num_ls_stack_entries = 85;
+		break;
+	case CHIP_CYPRESS:
+	case CHIP_HEMLOCK:
+		num_ps_gprs = 93;
+		num_vs_gprs = 46;
+		num_temp_gprs = 4;
+		num_gs_gprs = 31;
+		num_es_gprs = 31;
+		num_hs_gprs = 23;
+		num_ls_gprs = 23;
+		num_ps_threads = 128;
+		num_vs_threads = 20;
+		num_gs_threads = 20;
+		num_es_threads = 20;
+		num_hs_threads = 20;
+		num_ls_threads = 20;
+		num_ps_stack_entries = 85;
+		num_vs_stack_entries = 85;
+		num_gs_stack_entries = 85;
+		num_es_stack_entries = 85;
+		num_hs_stack_entries = 85;
+		num_ls_stack_entries = 85;
+		break;
+	}
+
+	if (rdev->family == CHIP_CEDAR)
+		sq_config = 0;
+	else
+		sq_config = VC_ENABLE;
+
+	sq_config |= (EXPORT_SRC_C |
+		      CS_PRIO(0) |
+		      LS_PRIO(0) |
+		      HS_PRIO(0) |
+		      PS_PRIO(0) |
+		      VS_PRIO(1) |
+		      GS_PRIO(2) |
+		      ES_PRIO(3));
+
+	sq_gpr_resource_mgmt_1 = (NUM_PS_GPRS(num_ps_gprs) |
+				  NUM_VS_GPRS(num_vs_gprs) |
+				  NUM_CLAUSE_TEMP_GPRS(num_temp_gprs));
+	sq_gpr_resource_mgmt_2 = (NUM_GS_GPRS(num_gs_gprs) |
+				  NUM_ES_GPRS(num_es_gprs));
+	sq_gpr_resource_mgmt_3 = (NUM_HS_GPRS(num_hs_gprs) |
+				  NUM_LS_GPRS(num_ls_gprs));
+	sq_thread_resource_mgmt = (NUM_PS_THREADS(num_ps_threads) |
+				   NUM_VS_THREADS(num_vs_threads) |
+				   NUM_GS_THREADS(num_gs_threads) |
+				   NUM_ES_THREADS(num_es_threads));
+	sq_thread_resource_mgmt_2 = (NUM_HS_THREADS(num_hs_threads) |
+				     NUM_LS_THREADS(num_ls_threads));
+	sq_stack_resource_mgmt_1 = (NUM_PS_STACK_ENTRIES(num_ps_stack_entries) |
+				    NUM_VS_STACK_ENTRIES(num_vs_stack_entries));
+	sq_stack_resource_mgmt_2 = (NUM_GS_STACK_ENTRIES(num_gs_stack_entries) |
+				    NUM_ES_STACK_ENTRIES(num_es_stack_entries));
+	sq_stack_resource_mgmt_3 = (NUM_HS_STACK_ENTRIES(num_hs_stack_entries) |
+				    NUM_LS_STACK_ENTRIES(num_ls_stack_entries));
+
+	/* set clear context state */
+	radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+	radeon_ring_write(rdev, 0);
+
+	/* disable dyn gprs */
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+	radeon_ring_write(rdev, (SQ_DYN_GPR_CNTL_PS_FLUSH_REQ - PACKET3_SET_CONFIG_REG_START) >> 2);
+	radeon_ring_write(rdev, 0);
+
+	/* SQ config */
+	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 11));
+	radeon_ring_write(rdev, (SQ_CONFIG - PACKET3_SET_CONFIG_REG_START) >> 2);
+	radeon_ring_write(rdev, sq_config);
+	radeon_ring_write(rdev, sq_gpr_resource_mgmt_1);
+	radeon_ring_write(rdev, sq_gpr_resource_mgmt_2);
+	radeon_ring_write(rdev, sq_gpr_resource_mgmt_3);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, 0);
+	radeon_ring_write(rdev, sq_thread_resource_mgmt);
+	radeon_ring_write(rdev, sq_thread_resource_mgmt_2);
+	radeon_ring_write(rdev, sq_stack_resource_mgmt_1);
+	radeon_ring_write(rdev, sq_stack_resource_mgmt_2);
+	radeon_ring_write(rdev, sq_stack_resource_mgmt_3);
+
+	/* CONTEXT_CONTROL */
+	radeon_ring_write(rdev, 0xc0012800);
+	radeon_ring_write(rdev, 0x80000000);
+	radeon_ring_write(rdev, 0x80000000);
+
+	/* SQ_VTX_BASE_VTX_LOC */
+	radeon_ring_write(rdev, 0xc0026f00);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000000);
+
+	/* SET_SAMPLER */
+	radeon_ring_write(rdev, 0xc0036e00);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000012);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000000);
+
+}
+
+static inline uint32_t i2f(uint32_t input)
+{
+	u32 result, i, exponent, fraction;
+
+	if ((input & 0x3fff) == 0)
+		result = 0; /* 0 is a special case */
+	else {
+		exponent = 140; /* exponent biased by 127; */
+		fraction = (input & 0x3fff) << 10; /* cheat and only
+						      handle numbers below 2^^15 */
+		for (i = 0; i < 14; i++) {
+			if (fraction & 0x800000)
+				break;
+			else {
+				fraction = fraction << 1; /* keep
+							     shifting left until top bit = 1 */
+				exponent = exponent - 1;
+			}
+		}
+		result = exponent << 23 | (fraction & 0x7fffff); /* mask
+								    off top bit; assumed 1 */
+	}
+	return result;
+}
+
+int evergreen_blit_init(struct radeon_device *rdev)
+{
+	u32 obj_size;
+	int r;
+	void *ptr;
+
+	/* pin copy shader into vram if already initialized */
+	if (rdev->r600_blit.shader_obj)
+		goto done;
+
+	mutex_init(&rdev->r600_blit.mutex);
+	rdev->r600_blit.state_offset = 0;
+	rdev->r600_blit.state_len = 0;
+	obj_size = 0;
+
+	rdev->r600_blit.vs_offset = obj_size;
+	obj_size += evergreen_vs_size * 4;
+	obj_size = ALIGN(obj_size, 256);
+
+	rdev->r600_blit.ps_offset = obj_size;
+	obj_size += evergreen_ps_size * 4;
+	obj_size = ALIGN(obj_size, 256);
+
+	r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+				&rdev->r600_blit.shader_obj);
+	if (r) {
+		DRM_ERROR("evergreen failed to allocate shader\n");
+		return r;
+	}
+
+	DRM_DEBUG("evergreen blit allocated bo %08x vs %08x ps %08x\n",
+		  obj_size,
+		  rdev->r600_blit.vs_offset, rdev->r600_blit.ps_offset);
+
+	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+	if (unlikely(r != 0))
+		return r;
+	r = radeon_bo_kmap(rdev->r600_blit.shader_obj, &ptr);
+	if (r) {
+		DRM_ERROR("failed to map blit object %d\n", r);
+		return r;
+	}
+
+	memcpy(ptr + rdev->r600_blit.vs_offset, evergreen_vs, evergreen_vs_size * 4);
+	memcpy(ptr + rdev->r600_blit.ps_offset, evergreen_ps, evergreen_ps_size * 4);
+	radeon_bo_kunmap(rdev->r600_blit.shader_obj);
+	radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+	if (unlikely(r != 0))
+		return r;
+	r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->r600_blit.shader_gpu_addr);
+	radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+	if (r) {
+		dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+		return r;
+	}
+	rdev->mc.active_vram_size = rdev->mc.real_vram_size;
+	return 0;
+}
+
+void evergreen_blit_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
+	if (rdev->r600_blit.shader_obj == NULL)
+		return;
+	/* If we can't reserve the bo, unref should be enough to destroy
+	 * it when it becomes idle.
+	 */
+	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+	if (!r) {
+		radeon_bo_unpin(rdev->r600_blit.shader_obj);
+		radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+	}
+	radeon_bo_unref(&rdev->r600_blit.shader_obj);
+}
+
+static int evergreen_vb_ib_get(struct radeon_device *rdev)
+{
+	int r;
+	r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
+	if (r) {
+		DRM_ERROR("failed to get IB for vertex buffer\n");
+		return r;
+	}
+
+	rdev->r600_blit.vb_total = 64*1024;
+	rdev->r600_blit.vb_used = 0;
+	return 0;
+}
+
+static void evergreen_vb_ib_put(struct radeon_device *rdev)
+{
+	radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
+	radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+}
+
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes)
+{
+	int r;
+	int ring_size, line_size;
+	int max_size;
+	/* loops of emits + fence emit possible */
+	int dwords_per_loop = 74, num_loops;
+
+	r = evergreen_vb_ib_get(rdev);
+	if (r)
+		return r;
+
+	/* 8 bpp vs 32 bpp for xfer unit */
+	if (size_bytes & 3)
+		line_size = 8192;
+	else
+		line_size = 8192 * 4;
+
+	max_size = 8192 * line_size;
+
+	/* major loops cover the max size transfer */
+	num_loops = ((size_bytes + max_size) / max_size);
+	/* minor loops cover the extra non aligned bits */
+	num_loops += ((size_bytes % line_size) ? 1 : 0);
+	/* calculate number of loops correctly */
+	ring_size = num_loops * dwords_per_loop;
+	/* set default  + shaders */
+	ring_size += 46; /* shaders + def state */
+	ring_size += 10; /* fence emit for VB IB */
+	ring_size += 5; /* done copy */
+	ring_size += 10; /* fence emit for done copy */
+	r = radeon_ring_lock(rdev, ring_size);
+	if (r)
+		return r;
+
+	set_default_state(rdev); /* 30 */
+	set_shaders(rdev); /* 16 */
+	return 0;
+}
+
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
+{
+	int r;
+
+	if (rdev->r600_blit.vb_ib)
+		evergreen_vb_ib_put(rdev);
+
+	if (fence)
+		r = radeon_fence_emit(rdev, fence);
+
+	radeon_ring_unlock_commit(rdev);
+}
+
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+			     u64 src_gpu_addr, u64 dst_gpu_addr,
+			     int size_bytes)
+{
+	int max_bytes;
+	u64 vb_gpu_addr;
+	u32 *vb;
+
+	DRM_DEBUG("emitting copy %16llx %16llx %d %d\n", src_gpu_addr, dst_gpu_addr,
+		  size_bytes, rdev->r600_blit.vb_used);
+	vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
+	if ((size_bytes & 3) || (src_gpu_addr & 3) || (dst_gpu_addr & 3)) {
+		max_bytes = 8192;
+
+		while (size_bytes) {
+			int cur_size = size_bytes;
+			int src_x = src_gpu_addr & 255;
+			int dst_x = dst_gpu_addr & 255;
+			int h = 1;
+			src_gpu_addr = src_gpu_addr & ~255ULL;
+			dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+			if (!src_x && !dst_x) {
+				h = (cur_size / max_bytes);
+				if (h > 8192)
+					h = 8192;
+				if (h == 0)
+					h = 1;
+				else
+					cur_size = max_bytes;
+			} else {
+				if (cur_size > max_bytes)
+					cur_size = max_bytes;
+				if (cur_size > (max_bytes - dst_x))
+					cur_size = (max_bytes - dst_x);
+				if (cur_size > (max_bytes - src_x))
+					cur_size = (max_bytes - src_x);
+			}
+
+			if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+				WARN_ON(1);
+			}
+
+			vb[0] = i2f(dst_x);
+			vb[1] = 0;
+			vb[2] = i2f(src_x);
+			vb[3] = 0;
+
+			vb[4] = i2f(dst_x);
+			vb[5] = i2f(h);
+			vb[6] = i2f(src_x);
+			vb[7] = i2f(h);
+
+			vb[8] = i2f(dst_x + cur_size);
+			vb[9] = i2f(h);
+			vb[10] = i2f(src_x + cur_size);
+			vb[11] = i2f(h);
+
+			/* src 10 */
+			set_tex_resource(rdev, FMT_8,
+					 src_x + cur_size, h, src_x + cur_size,
+					 src_gpu_addr);
+
+			/* 5 */
+			cp_set_surface_sync(rdev,
+					    PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+
+			/* dst 17 */
+			set_render_target(rdev, COLOR_8,
+					  dst_x + cur_size, h,
+					  dst_gpu_addr);
+
+			/* scissors 12 */
+			set_scissors(rdev, dst_x, 0, dst_x + cur_size, h);
+
+			/* 15 */
+			vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+			set_vtx_resource(rdev, vb_gpu_addr);
+
+			/* draw 10 */
+			draw_auto(rdev);
+
+			/* 5 */
+			cp_set_surface_sync(rdev,
+					    PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+					    cur_size * h, dst_gpu_addr);
+
+			vb += 12;
+			rdev->r600_blit.vb_used += 12 * 4;
+
+			src_gpu_addr += cur_size * h;
+			dst_gpu_addr += cur_size * h;
+			size_bytes -= cur_size * h;
+		}
+	} else {
+		max_bytes = 8192 * 4;
+
+		while (size_bytes) {
+			int cur_size = size_bytes;
+			int src_x = (src_gpu_addr & 255);
+			int dst_x = (dst_gpu_addr & 255);
+			int h = 1;
+			src_gpu_addr = src_gpu_addr & ~255ULL;
+			dst_gpu_addr = dst_gpu_addr & ~255ULL;
+
+			if (!src_x && !dst_x) {
+				h = (cur_size / max_bytes);
+				if (h > 8192)
+					h = 8192;
+				if (h == 0)
+					h = 1;
+				else
+					cur_size = max_bytes;
+			} else {
+				if (cur_size > max_bytes)
+					cur_size = max_bytes;
+				if (cur_size > (max_bytes - dst_x))
+					cur_size = (max_bytes - dst_x);
+				if (cur_size > (max_bytes - src_x))
+					cur_size = (max_bytes - src_x);
+			}
+
+			if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
+				WARN_ON(1);
+			}
+
+			vb[0] = i2f(dst_x / 4);
+			vb[1] = 0;
+			vb[2] = i2f(src_x / 4);
+			vb[3] = 0;
+
+			vb[4] = i2f(dst_x / 4);
+			vb[5] = i2f(h);
+			vb[6] = i2f(src_x / 4);
+			vb[7] = i2f(h);
+
+			vb[8] = i2f((dst_x + cur_size) / 4);
+			vb[9] = i2f(h);
+			vb[10] = i2f((src_x + cur_size) / 4);
+			vb[11] = i2f(h);
+
+			/* src 10 */
+			set_tex_resource(rdev, FMT_8_8_8_8,
+					 (src_x + cur_size) / 4,
+					 h, (src_x + cur_size) / 4,
+					 src_gpu_addr);
+			/* 5 */
+			cp_set_surface_sync(rdev,
+					    PACKET3_TC_ACTION_ENA, (src_x + cur_size * h), src_gpu_addr);
+
+			/* dst 17 */
+			set_render_target(rdev, COLOR_8_8_8_8,
+					  (dst_x + cur_size) / 4, h,
+					  dst_gpu_addr);
+
+			/* scissors 12  */
+			set_scissors(rdev, (dst_x / 4), 0, (dst_x + cur_size / 4), h);
+
+			/* Vertex buffer setup 15 */
+			vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
+			set_vtx_resource(rdev, vb_gpu_addr);
+
+			/* draw 10 */
+			draw_auto(rdev);
+
+			/* 5 */
+			cp_set_surface_sync(rdev,
+					    PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
+					    cur_size * h, dst_gpu_addr);
+
+			/* 74 ring dwords per loop */
+			vb += 12;
+			rdev->r600_blit.vb_used += 12 * 4;
+
+			src_gpu_addr += cur_size * h;
+			dst_gpu_addr += cur_size * h;
+			size_bytes -= cur_size * h;
+		}
+	}
+}
+
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, 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 (including the next
+ * paragraph) 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) AND/OR ITS SUPPLIERS 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:
+ *     Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+/*
+ * evergreen cards need to use the 3D engine to blit data which requires
+ * quite a bit of hw state setup.  Rather than pull the whole 3D driver
+ * (which normally generates the 3D state) into the DRM, we opt to use
+ * statically generated state tables.  The regsiter state and shaders
+ * were hand generated to support blitting functionality.  See the 3D
+ * driver or documentation for descriptions of the registers and
+ * shader instructions.
+ */
+
+const u32 evergreen_default_state[] =
+{
+	0xc0016900,
+	0x0000023b,
+	0x00000000, /* SQ_LDS_ALLOC_PS */
+
+	0xc0066900,
+	0x00000240,
+	0x00000000, /* SQ_ESGS_RING_ITEMSIZE */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+
+	0xc0046900,
+	0x00000247,
+	0x00000000, /* SQ_GS_VERT_ITEMSIZE */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+
+	0xc0026900,
+	0x00000010,
+	0x00000000, /* DB_Z_INFO */
+	0x00000000, /* DB_STENCIL_INFO */
+
+	0xc0016900,
+	0x00000200,
+	0x00000000, /* DB_DEPTH_CONTROL */
+
+	0xc0066900,
+	0x00000000,
+	0x00000060, /* DB_RENDER_CONTROL */
+	0x00000000, /* DB_COUNT_CONTROL */
+	0x00000000, /* DB_DEPTH_VIEW */
+	0x0000002a, /* DB_RENDER_OVERRIDE */
+	0x00000000, /* DB_RENDER_OVERRIDE2 */
+	0x00000000, /* DB_HTILE_DATA_BASE */
+
+	0xc0026900,
+	0x0000000a,
+	0x00000000, /* DB_STENCIL_CLEAR */
+	0x00000000, /* DB_DEPTH_CLEAR */
+
+	0xc0016900,
+	0x000002dc,
+	0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+	0xc0016900,
+	0x00000080,
+	0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+	0xc00d6900,
+	0x00000083,
+	0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+	0x00000000, /* PA_SC_CLIPRECT_0_TL */
+	0x20002000, /* PA_SC_CLIPRECT_0_BR */
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0x00000000,
+	0x20002000,
+	0xaaaaaaaa, /* PA_SC_EDGERULE */
+	0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+	0x0000000f, /* CB_TARGET_MASK */
+	0x0000000f, /* CB_SHADER_MASK */
+
+	0xc0226900,
+	0x00000094,
+	0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+	0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x80000000,
+	0x20002000,
+	0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+	0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+	0xc0016900,
+	0x000000d4,
+	0x00000000, /* SX_MISC */
+
+	0xc0026900,
+	0x00000292,
+	0x00000000, /* PA_SC_MODE_CNTL_0 */
+	0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+	0xc0106900,
+	0x00000300,
+	0x00000000, /* PA_SC_LINE_CNTL */
+	0x00000000, /* PA_SC_AA_CONFIG */
+	0x00000005, /* PA_SU_VTX_CNTL */
+	0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_VERT_DISC_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_CLIP_ADJ */
+	0x3f800000, /* PA_CL_GB_HORZ_DISC_ADJ */
+	0x00000000, /* PA_SC_AA_SAMPLE_LOCS_0 */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /* PA_SC_AA_SAMPLE_LOCS_7 */
+	0xffffffff, /* PA_SC_AA_MASK */
+
+	0xc00d6900,
+	0x00000202,
+	0x00cc0010, /* CB_COLOR_CONTROL */
+	0x00000210, /* DB_SHADER_CONTROL */
+	0x00010000, /* PA_CL_CLIP_CNTL */
+	0x00000004, /* PA_SU_SC_MODE_CNTL */
+	0x00000100, /* PA_CL_VTE_CNTL */
+	0x00000000, /* PA_CL_VS_OUT_CNTL */
+	0x00000000, /* PA_CL_NANINF_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_CNTL */
+	0x00000000, /* PA_SU_LINE_STIPPLE_SCALE */
+	0x00000000, /* PA_SU_PRIM_FILTER_CNTL */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /* SQ_DYN_GPR_RESOURCE_LIMIT_1 */
+
+	0xc0066900,
+	0x000002de,
+	0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+
+	0xc0016900,
+	0x00000229,
+	0x00000000, /* SQ_PGM_START_FS */
+
+	0xc0016900,
+	0x0000022a,
+	0x00000000, /* SQ_PGM_RESOURCES_FS */
+
+	0xc0096900,
+	0x00000100,
+	0x00ffffff, /* VGT_MAX_VTX_INDX */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /* SX_ALPHA_TEST_CONTROL */
+	0x00000000, /* CB_BLEND_RED */
+	0x00000000, /* CB_BLEND_GREEN */
+	0x00000000, /* CB_BLEND_BLUE */
+	0x00000000, /* CB_BLEND_ALPHA */
+
+	0xc0026900,
+	0x000002a8,
+	0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+	0x00000000, /*  */
+
+	0xc0026900,
+	0x000002ad,
+	0x00000000, /* VGT_REUSE_OFF */
+	0x00000000, /*  */
+
+	0xc0116900,
+	0x00000280,
+	0x00000000, /* PA_SU_POINT_SIZE */
+	0x00000000, /* PA_SU_POINT_MINMAX */
+	0x00000008, /* PA_SU_LINE_CNTL */
+	0x00000000, /* PA_SC_LINE_STIPPLE */
+	0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+	0x00000000, /* VGT_HOS_CNTL */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /* VGT_GS_MODE */
+
+	0xc0016900,
+	0x000002a1,
+	0x00000000, /* VGT_PRIMITIVEID_EN */
+
+	0xc0016900,
+	0x000002a5,
+	0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+	0xc0016900,
+	0x000002d5,
+	0x00000000, /* VGT_SHADER_STAGES_EN */
+
+	0xc0026900,
+	0x000002e5,
+	0x00000000, /* VGT_STRMOUT_CONFIG */
+	0x00000000, /*  */
+
+	0xc0016900,
+	0x000001e0,
+	0x00000000, /* CB_BLEND0_CONTROL */
+
+	0xc0016900,
+	0x000001b1,
+	0x00000000, /* SPI_VS_OUT_CONFIG */
+
+	0xc0016900,
+	0x00000187,
+	0x00000000, /* SPI_VS_OUT_ID_0 */
+
+	0xc0016900,
+	0x00000191,
+	0x00000100, /* SPI_PS_INPUT_CNTL_0 */
+
+	0xc00b6900,
+	0x000001b3,
+	0x20000001, /* SPI_PS_IN_CONTROL_0 */
+	0x00000000, /* SPI_PS_IN_CONTROL_1 */
+	0x00000000, /* SPI_INTERP_CONTROL_0 */
+	0x00000000, /* SPI_INPUT_Z */
+	0x00000000, /* SPI_FOG_CNTL */
+	0x00100000, /* SPI_BARYC_CNTL */
+	0x00000000, /* SPI_PS_IN_CONTROL_2 */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+	0x00000000, /*  */
+
+	0xc0026900,
+	0x00000316,
+	0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+	0x00000010, /*  */
+};
+
+const u32 evergreen_vs[] =
+{
+	0x00000004,
+	0x80800400,
+	0x0000a03c,
+	0x95000688,
+	0x00004000,
+	0x15200688,
+	0x00000000,
+	0x00000000,
+	0x3c000000,
+	0x67961001,
+	0x00080000,
+	0x00000000,
+	0x1c000000,
+	0x67961000,
+	0x00000008,
+	0x00000000,
+};
+
+const u32 evergreen_ps[] =
+{
+	0x00000003,
+	0xa00c0000,
+	0x00000008,
+	0x80400000,
+	0x00000000,
+	0x95200688,
+	0x00380400,
+	0x00146b10,
+	0x00380000,
+	0x20146b10,
+	0x00380400,
+	0x40146b00,
+	0x80380000,
+	0x60146b00,
+	0x00000000,
+	0x00000000,
+	0x00000010,
+	0x000d1000,
+	0xb0800000,
+	0x00000000,
+};
+
+const u32 evergreen_ps_size = ARRAY_SIZE(evergreen_ps);
+const u32 evergreen_vs_size = ARRAY_SIZE(evergreen_vs);
+const u32 evergreen_default_size = ARRAY_SIZE(evergreen_default_state);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen_blit_shaders.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 Advanced Micro Devices, 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 (including the next
+ * paragraph) 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) AND/OR ITS SUPPLIERS 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.
+ *
+ */
+
+#ifndef EVERGREEN_BLIT_SHADERS_H
+#define EVERGREEN_BLIT_SHADERS_H
+
+extern const u32 evergreen_ps[];
+extern const u32 evergreen_vs[];
+extern const u32 evergreen_default_state[];
+
+extern const u32 evergreen_ps_size, evergreen_vs_size;
+extern const u32 evergreen_default_size;
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreen.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreen.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,6 +32,7 @@
 #include "atom.h"
 #include "avivod.h"
 #include "evergreen_reg.h"
+#include "evergreen_blit_shaders.h"
 
 #define EVERGREEN_PFP_UCODE_SIZE 1120
 #define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -284,9 +285,444 @@
 	}
 }
 
+/* watermark setup */
+
+static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev,
+					struct radeon_crtc *radeon_crtc,
+					struct drm_display_mode *mode,
+					struct drm_display_mode *other_mode)
+{
+	u32 tmp = 0;
+	/*
+	 * Line Buffer Setup
+	 * There are 3 line buffers, each one shared by 2 display controllers.
+	 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+	 * the display controllers.  The paritioning is done via one of four
+	 * preset allocations specified in bits 2:0:
+	 * first display controller
+	 *  0 - first half of lb (3840 * 2)
+	 *  1 - first 3/4 of lb (5760 * 2)
+	 *  2 - whole lb (7680 * 2)
+	 *  3 - first 1/4 of lb (1920 * 2)
+	 * second display controller
+	 *  4 - second half of lb (3840 * 2)
+	 *  5 - second 3/4 of lb (5760 * 2)
+	 *  6 - whole lb (7680 * 2)
+	 *  7 - last 1/4 of lb (1920 * 2)
+	 */
+	if (mode && other_mode) {
+		if (mode->hdisplay > other_mode->hdisplay) {
+			if (mode->hdisplay > 2560)
+				tmp = 1; /* 3/4 */
+			else
+				tmp = 0; /* 1/2 */
+		} else if (other_mode->hdisplay > mode->hdisplay) {
+			if (other_mode->hdisplay > 2560)
+				tmp = 3; /* 1/4 */
+			else
+				tmp = 0; /* 1/2 */
+		} else
+			tmp = 0; /* 1/2 */
+	} else if (mode)
+		tmp = 2; /* whole */
+	else if (other_mode)
+		tmp = 3; /* 1/4 */
+
+	/* second controller of the pair uses second half of the lb */
+	if (radeon_crtc->crtc_id % 2)
+		tmp += 4;
+	WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp);
+
+	switch (tmp) {
+	case 0:
+	case 4:
+	default:
+		return 3840 * 2;
+	case 1:
+	case 5:
+		return 5760 * 2;
+	case 2:
+	case 6:
+		return 7680 * 2;
+	case 3:
+	case 7:
+		return 1920 * 2;
+	}
+}
+
+static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev)
+{
+	u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+	switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+	case 0:
+	default:
+		return 1;
+	case 1:
+		return 2;
+	case 2:
+		return 4;
+	case 3:
+		return 8;
+	}
+}
+
+struct evergreen_wm_params {
+	u32 dram_channels; /* number of dram channels */
+	u32 yclk;          /* bandwidth per dram data pin in kHz */
+	u32 sclk;          /* engine clock in kHz */
+	u32 disp_clk;      /* display clock in kHz */
+	u32 src_width;     /* viewport width */
+	u32 active_time;   /* active display time in ns */
+	u32 blank_time;    /* blank time in ns */
+	bool interlaced;    /* mode is interlaced */
+	fixed20_12 vsc;    /* vertical scale ratio */
+	u32 num_heads;     /* number of active crtcs */
+	u32 bytes_per_pixel; /* bytes per pixel display + overlay */
+	u32 lb_size;       /* line buffer allocated to pipe */
+	u32 vtaps;         /* vertical scaler taps */
+};
+
+static u32 evergreen_dram_bandwidth(struct evergreen_wm_params *wm)
+{
+	/* Calculate DRAM Bandwidth and the part allocated to display. */
+	fixed20_12 dram_efficiency; /* 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	dram_efficiency.full = dfixed_const(7);
+	dram_efficiency.full = dfixed_div(dram_efficiency, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, dram_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+	/* Calculate DRAM Bandwidth and the part allocated to display. */
+	fixed20_12 disp_dram_allocation; /* 0.3 to 0.7 */
+	fixed20_12 yclk, dram_channels, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	yclk.full = dfixed_const(wm->yclk);
+	yclk.full = dfixed_div(yclk, a);
+	dram_channels.full = dfixed_const(wm->dram_channels * 4);
+	a.full = dfixed_const(10);
+	disp_dram_allocation.full = dfixed_const(3); /* XXX worse case value 0.3 */
+	disp_dram_allocation.full = dfixed_div(disp_dram_allocation, a);
+	bandwidth.full = dfixed_mul(dram_channels, yclk);
+	bandwidth.full = dfixed_mul(bandwidth, disp_dram_allocation);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_data_return_bandwidth(struct evergreen_wm_params *wm)
+{
+	/* Calculate the display Data return Bandwidth */
+	fixed20_12 return_efficiency; /* 0.8 */
+	fixed20_12 sclk, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	sclk.full = dfixed_const(wm->sclk);
+	sclk.full = dfixed_div(sclk, a);
+	a.full = dfixed_const(10);
+	return_efficiency.full = dfixed_const(8);
+	return_efficiency.full = dfixed_div(return_efficiency, a);
+	a.full = dfixed_const(32);
+	bandwidth.full = dfixed_mul(a, sclk);
+	bandwidth.full = dfixed_mul(bandwidth, return_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_dmif_request_bandwidth(struct evergreen_wm_params *wm)
+{
+	/* Calculate the DMIF Request Bandwidth */
+	fixed20_12 disp_clk_request_efficiency; /* 0.8 */
+	fixed20_12 disp_clk, bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	disp_clk.full = dfixed_const(wm->disp_clk);
+	disp_clk.full = dfixed_div(disp_clk, a);
+	a.full = dfixed_const(10);
+	disp_clk_request_efficiency.full = dfixed_const(8);
+	disp_clk_request_efficiency.full = dfixed_div(disp_clk_request_efficiency, a);
+	a.full = dfixed_const(32);
+	bandwidth.full = dfixed_mul(a, disp_clk);
+	bandwidth.full = dfixed_mul(bandwidth, disp_clk_request_efficiency);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_available_bandwidth(struct evergreen_wm_params *wm)
+{
+	/* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+	u32 dram_bandwidth = evergreen_dram_bandwidth(wm);
+	u32 data_return_bandwidth = evergreen_data_return_bandwidth(wm);
+	u32 dmif_req_bandwidth = evergreen_dmif_request_bandwidth(wm);
+
+	return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+static u32 evergreen_average_bandwidth(struct evergreen_wm_params *wm)
+{
+	/* Calculate the display mode Average Bandwidth
+	 * DisplayMode should contain the source and destination dimensions,
+	 * timing, etc.
+	 */
+	fixed20_12 bpp;
+	fixed20_12 line_time;
+	fixed20_12 src_width;
+	fixed20_12 bandwidth;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1000);
+	line_time.full = dfixed_const(wm->active_time + wm->blank_time);
+	line_time.full = dfixed_div(line_time, a);
+	bpp.full = dfixed_const(wm->bytes_per_pixel);
+	src_width.full = dfixed_const(wm->src_width);
+	bandwidth.full = dfixed_mul(src_width, bpp);
+	bandwidth.full = dfixed_mul(bandwidth, wm->vsc);
+	bandwidth.full = dfixed_div(bandwidth, line_time);
+
+	return dfixed_trunc(bandwidth);
+}
+
+static u32 evergreen_latency_watermark(struct evergreen_wm_params *wm)
+{
+	/* First calcualte the latency in ns */
+	u32 mc_latency = 2000; /* 2000 ns. */
+	u32 available_bandwidth = evergreen_available_bandwidth(wm);
+	u32 worst_chunk_return_time = (512 * 8 * 1000) / available_bandwidth;
+	u32 cursor_line_pair_return_time = (128 * 4 * 1000) / available_bandwidth;
+	u32 dc_latency = 40000000 / wm->disp_clk; /* dc pipe latency */
+	u32 other_heads_data_return_time = ((wm->num_heads + 1) * worst_chunk_return_time) +
+		(wm->num_heads * cursor_line_pair_return_time);
+	u32 latency = mc_latency + other_heads_data_return_time + dc_latency;
+	u32 max_src_lines_per_dst_line, lb_fill_bw, line_fill_time;
+	fixed20_12 a, b, c;
+
+	if (wm->num_heads == 0)
+		return 0;
+
+	a.full = dfixed_const(2);
+	b.full = dfixed_const(1);
+	if ((wm->vsc.full > a.full) ||
+	    ((wm->vsc.full > b.full) && (wm->vtaps >= 3)) ||
+	    (wm->vtaps >= 5) ||
+	    ((wm->vsc.full >= a.full) && wm->interlaced))
+		max_src_lines_per_dst_line = 4;
+	else
+		max_src_lines_per_dst_line = 2;
+
+	a.full = dfixed_const(available_bandwidth);
+	b.full = dfixed_const(wm->num_heads);
+	a.full = dfixed_div(a, b);
+
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(wm->disp_clk);
+	b.full = dfixed_div(c, b);
+	c.full = dfixed_const(wm->bytes_per_pixel);
+	b.full = dfixed_mul(b, c);
+
+	lb_fill_bw = min(dfixed_trunc(a), dfixed_trunc(b));
+
+	a.full = dfixed_const(max_src_lines_per_dst_line * wm->src_width * wm->bytes_per_pixel);
+	b.full = dfixed_const(1000);
+	c.full = dfixed_const(lb_fill_bw);
+	b.full = dfixed_div(c, b);
+	a.full = dfixed_div(a, b);
+	line_fill_time = dfixed_trunc(a);
+
+	if (line_fill_time < wm->active_time)
+		return latency;
+	else
+		return latency + (line_fill_time - wm->active_time);
+
+}
+
+static bool evergreen_average_bandwidth_vs_dram_bandwidth_for_display(struct evergreen_wm_params *wm)
+{
+	if (evergreen_average_bandwidth(wm) <=
+	    (evergreen_dram_bandwidth_for_display(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+};
+
+static bool evergreen_average_bandwidth_vs_available_bandwidth(struct evergreen_wm_params *wm)
+{
+	if (evergreen_average_bandwidth(wm) <=
+	    (evergreen_available_bandwidth(wm) / wm->num_heads))
+		return true;
+	else
+		return false;
+};
+
+static bool evergreen_check_latency_hiding(struct evergreen_wm_params *wm)
+{
+	u32 lb_partitions = wm->lb_size / wm->src_width;
+	u32 line_time = wm->active_time + wm->blank_time;
+	u32 latency_tolerant_lines;
+	u32 latency_hiding;
+	fixed20_12 a;
+
+	a.full = dfixed_const(1);
+	if (wm->vsc.full > a.full)
+		latency_tolerant_lines = 1;
+	else {
+		if (lb_partitions <= (wm->vtaps + 1))
+			latency_tolerant_lines = 1;
+		else
+			latency_tolerant_lines = 2;
+	}
+
+	latency_hiding = (latency_tolerant_lines * line_time + wm->blank_time);
+
+	if (evergreen_latency_watermark(wm) <= latency_hiding)
+		return true;
+	else
+		return false;
+}
+
+static void evergreen_program_watermarks(struct radeon_device *rdev,
+					 struct radeon_crtc *radeon_crtc,
+					 u32 lb_size, u32 num_heads)
+{
+	struct drm_display_mode *mode = &radeon_crtc->base.mode;
+	struct evergreen_wm_params wm;
+	u32 pixel_period;
+	u32 line_time = 0;
+	u32 latency_watermark_a = 0, latency_watermark_b = 0;
+	u32 priority_a_mark = 0, priority_b_mark = 0;
+	u32 priority_a_cnt = PRIORITY_OFF;
+	u32 priority_b_cnt = PRIORITY_OFF;
+	u32 pipe_offset = radeon_crtc->crtc_id * 16;
+	u32 tmp, arb_control3;
+	fixed20_12 a, b, c;
+
+	if (radeon_crtc->base.enabled && num_heads && mode) {
+		pixel_period = 1000000 / (u32)mode->clock;
+		line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+		priority_a_cnt = 0;
+		priority_b_cnt = 0;
+
+		wm.yclk = rdev->pm.current_mclk * 10;
+		wm.sclk = rdev->pm.current_sclk * 10;
+		wm.disp_clk = mode->clock;
+		wm.src_width = mode->crtc_hdisplay;
+		wm.active_time = mode->crtc_hdisplay * pixel_period;
+		wm.blank_time = line_time - wm.active_time;
+		wm.interlaced = false;
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			wm.interlaced = true;
+		wm.vsc = radeon_crtc->vsc;
+		wm.vtaps = 1;
+		if (radeon_crtc->rmx_type != RMX_OFF)
+			wm.vtaps = 2;
+		wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+		wm.lb_size = lb_size;
+		wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+		wm.num_heads = num_heads;
+
+		/* set for high clocks */
+		latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535);
+		/* set for low clocks */
+		/* wm.yclk = low clk; wm.sclk = low clk */
+		latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535);
+
+		/* possibly force display priority to high */
+		/* should really do this at mode validation time... */
+		if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+		    !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
+		    !evergreen_check_latency_hiding(&wm) ||
+		    (rdev->disp_priority == 2)) {
+			DRM_INFO("force priority to high\n");
+			priority_a_cnt |= PRIORITY_ALWAYS_ON;
+			priority_b_cnt |= PRIORITY_ALWAYS_ON;
+		}
+
+		a.full = dfixed_const(1000);
+		b.full = dfixed_const(mode->clock);
+		b.full = dfixed_div(b, a);
+		c.full = dfixed_const(latency_watermark_a);
+		c.full = dfixed_mul(c, b);
+		c.full = dfixed_mul(c, radeon_crtc->hsc);
+		c.full = dfixed_div(c, a);
+		a.full = dfixed_const(16);
+		c.full = dfixed_div(c, a);
+		priority_a_mark = dfixed_trunc(c);
+		priority_a_cnt |= priority_a_mark & PRIORITY_MARK_MASK;
+
+		a.full = dfixed_const(1000);
+		b.full = dfixed_const(mode->clock);
+		b.full = dfixed_div(b, a);
+		c.full = dfixed_const(latency_watermark_b);
+		c.full = dfixed_mul(c, b);
+		c.full = dfixed_mul(c, radeon_crtc->hsc);
+		c.full = dfixed_div(c, a);
+		a.full = dfixed_const(16);
+		c.full = dfixed_div(c, a);
+		priority_b_mark = dfixed_trunc(c);
+		priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+	}
+
+	/* select wm A */
+	arb_control3 = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+	tmp = arb_control3;
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(1);
+	WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+	WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* select wm B */
+	tmp = RREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset);
+	tmp &= ~LATENCY_WATERMARK_MASK(3);
+	tmp |= LATENCY_WATERMARK_MASK(2);
+	WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, tmp);
+	WREG32(PIPE0_LATENCY_CONTROL + pipe_offset,
+	       (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+		LATENCY_HIGH_WATERMARK(line_time)));
+	/* restore original selection */
+	WREG32(PIPE0_ARBITRATION_CONTROL3 + pipe_offset, arb_control3);
+
+	/* write the priority marks */
+	WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
+	WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+
+}
+
 void evergreen_bandwidth_update(struct radeon_device *rdev)
 {
-	/* XXX */
+	struct drm_display_mode *mode0 = NULL;
+	struct drm_display_mode *mode1 = NULL;
+	u32 num_heads = 0, lb_size;
+	int i;
+
+	radeon_update_display_priority(rdev);
+
+	for (i = 0; i < rdev->num_crtc; i++) {
+		if (rdev->mode_info.crtcs[i]->base.enabled)
+			num_heads++;
+	}
+	for (i = 0; i < rdev->num_crtc; i += 2) {
+		mode0 = &rdev->mode_info.crtcs[i]->base.mode;
+		mode1 = &rdev->mode_info.crtcs[i+1]->base.mode;
+		lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode0, mode1);
+		evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+		lb_size = evergreen_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i+1], mode1, mode0);
+		evergreen_program_watermarks(rdev, rdev->mode_info.crtcs[i+1], lb_size, num_heads);
+	}
 }
 
 static int evergreen_mc_wait_for_idle(struct radeon_device *rdev)
@@ -312,6 +748,8 @@
 	unsigned i;
 	u32 tmp;
 
+	WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1);
+
 	WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1));
 	for (i = 0; i < rdev->usec_timeout; i++) {
 		/* read MC_STATUS */
@@ -677,7 +1115,7 @@
 
 static int evergreen_cp_start(struct radeon_device *rdev)
 {
-	int r;
+	int r, i;
 	uint32_t cp_me;
 
 	r = radeon_ring_lock(rdev, 7);
@@ -697,16 +1135,39 @@
 	cp_me = 0xff;
 	WREG32(CP_ME_CNTL, cp_me);
 
-	r = radeon_ring_lock(rdev, 4);
+	r = radeon_ring_lock(rdev, evergreen_default_size + 15);
 	if (r) {
 		DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
 		return r;
 	}
-	/* init some VGT regs */
-	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
-	radeon_ring_write(rdev, (VGT_VERTEX_REUSE_BLOCK_CNTL - PACKET3_SET_CONTEXT_REG_START) >> 2);
-	radeon_ring_write(rdev, 0xe);
-	radeon_ring_write(rdev, 0x10);
+
+	/* setup clear context state */
+	radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(rdev, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+	for (i = 0; i < evergreen_default_size; i++)
+		radeon_ring_write(rdev, evergreen_default_state[i]);
+
+	radeon_ring_write(rdev, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+	radeon_ring_write(rdev, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+	/* set clear context state */
+	radeon_ring_write(rdev, PACKET3(PACKET3_CLEAR_STATE, 0));
+	radeon_ring_write(rdev, 0);
+
+	/* SQ_VTX_BASE_VTX_LOC */
+	radeon_ring_write(rdev, 0xc0026f00);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000000);
+	radeon_ring_write(rdev, 0x00000000);
+
+	/* Clear consts */
+	radeon_ring_write(rdev, 0xc0036f00);
+	radeon_ring_write(rdev, 0x00000bc4);
+	radeon_ring_write(rdev, 0xffffffff);
+	radeon_ring_write(rdev, 0xffffffff);
+	radeon_ring_write(rdev, 0xffffffff);
+
 	radeon_ring_unlock_commit(rdev);
 
 	return 0;
@@ -731,7 +1192,7 @@
 
 	/* Set ring buffer size */
 	rb_bufsz = drm_order(rdev->cp.ring_size / 8);
-	tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
 	tmp |= BUF_SWAP_32BIT;
 #endif
@@ -745,8 +1206,19 @@
 	WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
 	WREG32(CP_RB_RPTR_WR, 0);
 	WREG32(CP_RB_WPTR, 0);
-	WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
-	WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+	/* set the wb address wether it's enabled or not */
+	WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+	WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+	if (rdev->wb.enabled)
+		WREG32(SCRATCH_UMSK, 0xff);
+	else {
+		tmp |= RB_NO_UPDATE;
+		WREG32(SCRATCH_UMSK, 0);
+	}
+
 	mdelay(1);
 	WREG32(CP_RB_CNTL, tmp);
 
@@ -1180,7 +1652,36 @@
 		}
 	}
 
-	rdev->config.evergreen.tile_config = gb_addr_config;
+	/* setup tiling info dword.  gb_addr_config is not adequate since it does
+	 * not have bank info, so create a custom tiling dword.
+	 * bits 3:0   num_pipes
+	 * bits 7:4   num_banks
+	 * bits 11:8  group_size
+	 * bits 15:12 row_size
+	 */
+	rdev->config.evergreen.tile_config = 0;
+	switch (rdev->config.evergreen.max_tile_pipes) {
+	case 1:
+	default:
+		rdev->config.evergreen.tile_config |= (0 << 0);
+		break;
+	case 2:
+		rdev->config.evergreen.tile_config |= (1 << 0);
+		break;
+	case 4:
+		rdev->config.evergreen.tile_config |= (2 << 0);
+		break;
+	case 8:
+		rdev->config.evergreen.tile_config |= (3 << 0);
+		break;
+	}
+	rdev->config.evergreen.tile_config |=
+		((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+	rdev->config.evergreen.tile_config |=
+		((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
+	rdev->config.evergreen.tile_config |=
+		((gb_addr_config & 0x30000000) >> 28) << 12;
+
 	WREG32(GB_BACKEND_MAP, gb_backend_map);
 	WREG32(GB_ADDR_CONFIG, gb_addr_config);
 	WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
@@ -1423,7 +1924,6 @@
 static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
 {
 	struct evergreen_mc_save save;
-	u32 srbm_reset = 0;
 	u32 grbm_reset = 0;
 
 	dev_info(rdev->dev, "GPU softreset \n");
@@ -1462,16 +1962,6 @@
 	udelay(50);
 	WREG32(GRBM_SOFT_RESET, 0);
 	(void)RREG32(GRBM_SOFT_RESET);
-
-	/* reset all the system blocks */
-	srbm_reset = SRBM_SOFT_RESET_ALL_MASK;
-
-	dev_info(rdev->dev, "  SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
-	WREG32(SRBM_SOFT_RESET, srbm_reset);
-	(void)RREG32(SRBM_SOFT_RESET);
-	udelay(50);
-	WREG32(SRBM_SOFT_RESET, 0);
-	(void)RREG32(SRBM_SOFT_RESET);
 	/* Wait a little for things to settle down */
 	udelay(50);
 	dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
@@ -1482,10 +1972,6 @@
 		RREG32(GRBM_STATUS_SE1));
 	dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
 		RREG32(SRBM_STATUS));
-	/* After reset we need to reinit the asic as GPU often endup in an
-	 * incoherent state.
-	 */
-	atom_asic_init(rdev->mode_info.atom_context);
 	evergreen_mc_resume(rdev, &save);
 	return 0;
 }
@@ -1563,7 +2049,7 @@
 	u32 grbm_int_cntl = 0;
 
 	if (!rdev->irq.installed) {
-		WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
 		return -EINVAL;
 	}
 	/* don't enable anything if the ih is disabled */
@@ -1584,6 +2070,7 @@
 	if (rdev->irq.sw_int) {
 		DRM_DEBUG("evergreen_irq_set: sw int\n");
 		cp_int_cntl |= RB_INT_ENABLE;
+		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
 	}
 	if (rdev->irq.crtc_vblank_int[0]) {
 		DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@@ -1760,8 +2247,10 @@
 {
 	u32 wptr, tmp;
 
-	/* XXX use writeback */
-	wptr = RREG32(IH_RB_WPTR);
+	if (rdev->wb.enabled)
+		wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+	else
+		wptr = RREG32(IH_RB_WPTR);
 
 	if (wptr & RB_OVERFLOW) {
 		/* When a ring buffer overflow happen start parsing interrupt
@@ -1822,6 +2311,7 @@
 			case 0: /* D1 vblank */
 				if (disp_int & LB_D1_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 0);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int &= ~LB_D1_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D1 vblank\n");
@@ -1843,6 +2333,7 @@
 			case 0: /* D2 vblank */
 				if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 1);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D2 vblank\n");
@@ -1864,6 +2355,7 @@
 			case 0: /* D3 vblank */
 				if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 2);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D3 vblank\n");
@@ -1885,6 +2377,7 @@
 			case 0: /* D4 vblank */
 				if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 3);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D4 vblank\n");
@@ -1906,6 +2399,7 @@
 			case 0: /* D5 vblank */
 				if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 4);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D5 vblank\n");
@@ -1927,6 +2421,7 @@
 			case 0: /* D6 vblank */
 				if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
 					drm_handle_vblank(rdev->ddev, 5);
+					rdev->pm.vblank_sync = true;
 					wake_up(&rdev->irq.vblank_queue);
 					disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
 					DRM_DEBUG("IH: D6 vblank\n");
@@ -2000,6 +2495,7 @@
 			break;
 		case 181: /* CP EOP event */
 			DRM_DEBUG("IH: CP EOP\n");
+			radeon_fence_process(rdev);
 			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: CP EOP\n");
@@ -2048,26 +2544,18 @@
 			return r;
 	}
 	evergreen_gpu_init(rdev);
-#if 0
-	if (!rdev->r600_blit.shader_obj) {
-		r = r600_blit_init(rdev);
-		if (r) {
-			DRM_ERROR("radeon: failed blitter (%d).\n", r);
-			return r;
-		}
-	}
 
-	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-	if (unlikely(r != 0))
-		return r;
-	r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-			&rdev->r600_blit.shader_gpu_addr);
-	radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+	r = evergreen_blit_init(rdev);
 	if (r) {
-		DRM_ERROR("failed to pin blit object %d\n", r);
-		return r;
+		evergreen_blit_fini(rdev);
+		rdev->asic->copy = NULL;
+		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
-#endif
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
 
 	/* Enable IRQ */
 	r = r600_irq_init(rdev);
@@ -2087,8 +2575,6 @@
 	r = evergreen_cp_resume(rdev);
 	if (r)
 		return r;
-	/* write back buffer are not vital so don't worry about failure */
-	r600_wb_enable(rdev);
 
 	return 0;
 }
@@ -2097,6 +2583,11 @@
 {
 	int r;
 
+	/* reset the asic, the gfx blocks are often in a bad state
+	 * after the driver is unloaded or after a resume
+	 */
+	if (radeon_asic_reset(rdev))
+		dev_warn(rdev->dev, "GPU reset failed !\n");
 	/* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
 	 * posting will perform necessary task to bring back GPU into good
 	 * shape.
@@ -2122,23 +2613,43 @@
 
 int evergreen_suspend(struct radeon_device *rdev)
 {
-#if 0
 	int r;
-#endif
+
 	/* FIXME: we should wait for ring to be empty */
 	r700_cp_stop(rdev);
 	rdev->cp.ready = false;
 	evergreen_irq_suspend(rdev);
-	r600_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	evergreen_pcie_gart_disable(rdev);
-#if 0
+
 	/* unpin shaders bo */
 	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
 	if (likely(r == 0)) {
 		radeon_bo_unpin(rdev->r600_blit.shader_obj);
 		radeon_bo_unreserve(rdev->r600_blit.shader_obj);
 	}
-#endif
+
+	return 0;
+}
+
+int evergreen_copy_blit(struct radeon_device *rdev,
+			uint64_t src_offset, uint64_t dst_offset,
+			unsigned num_pages, struct radeon_fence *fence)
+{
+	int r;
+
+	mutex_lock(&rdev->r600_blit.mutex);
+	rdev->r600_blit.vb_ib = NULL;
+	r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE);
+	if (r) {
+		if (rdev->r600_blit.vb_ib)
+			radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
+		mutex_unlock(&rdev->r600_blit.mutex);
+		return r;
+	}
+	evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE);
+	evergreen_blit_done_copy(rdev, fence);
+	mutex_unlock(&rdev->r600_blit.mutex);
 	return 0;
 }
 
@@ -2193,6 +2704,11 @@
 	r = radeon_atombios_init(rdev);
 	if (r)
 		return r;
+	/* reset the asic, the gfx blocks are often in a bad state
+	 * after the driver is unloaded or after a resume
+	 */
+	if (radeon_asic_reset(rdev))
+		dev_warn(rdev->dev, "GPU reset failed !\n");
 	/* Post card if necessary */
 	if (!evergreen_card_posted(rdev)) {
 		if (!rdev->bios) {
@@ -2246,8 +2762,8 @@
 	if (r) {
 		dev_err(rdev->dev, "disabling GPU acceleration\n");
 		r700_cp_fini(rdev);
-		r600_wb_fini(rdev);
 		r600_irq_fini(rdev);
+		radeon_wb_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		evergreen_pcie_gart_fini(rdev);
 		rdev->accel_working = false;
@@ -2269,10 +2785,10 @@
 
 void evergreen_fini(struct radeon_device *rdev)
 {
-	/*r600_blit_fini(rdev);*/
+	evergreen_blit_fini(rdev);
 	r700_cp_fini(rdev);
-	r600_wb_fini(rdev);
 	r600_irq_fini(rdev);
+	radeon_wb_fini(rdev);
 	radeon_irq_kms_fini(rdev);
 	evergreen_pcie_gart_fini(rdev);
 	radeon_gem_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreend.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreend.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/evergreend.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/evergreend.h	2011-01-04 19:50:19.000000000 -0500
@@ -174,6 +174,7 @@
 #define	HDP_NONSURFACE_BASE				0x2C04
 #define	HDP_NONSURFACE_INFO				0x2C08
 #define	HDP_NONSURFACE_SIZE				0x2C0C
+#define HDP_MEM_COHERENCY_FLUSH_CNTL			0x5480
 #define HDP_REG_COHERENCY_FLUSH_CNTL			0x54A0
 #define	HDP_TILING_CONFIG				0x2F3C
 
@@ -412,6 +413,19 @@
 #define		SOFT_RESET_REGBB		       	(1 << 22)
 #define		SOFT_RESET_ORB				(1 << 23)
 
+/* display watermarks */
+#define	DC_LB_MEMORY_SPLIT				  0x6b0c
+#define	PRIORITY_A_CNT			                  0x6b18
+#define		PRIORITY_MARK_MASK			  0x7fff
+#define		PRIORITY_OFF				  (1 << 16)
+#define		PRIORITY_ALWAYS_ON			  (1 << 20)
+#define	PRIORITY_B_CNT			                  0x6b1c
+#define	PIPE0_ARBITRATION_CONTROL3			  0x0bf0
+#       define LATENCY_WATERMARK_MASK(x)                  ((x) << 16)
+#define	PIPE0_LATENCY_CONTROL			          0x0bf4
+#       define LATENCY_LOW_WATERMARK(x)                   ((x) << 0)
+#       define LATENCY_HIGH_WATERMARK(x)                  ((x) << 16)
+
 #define IH_RB_CNTL                                        0x3e00
 #       define IH_RB_ENABLE                               (1 << 0)
 #       define IH_IB_SIZE(x)                              ((x) << 1) /* log2 */
@@ -645,6 +659,8 @@
 #define	PACKET3_EVENT_WRITE_EOP				0x47
 #define	PACKET3_EVENT_WRITE_EOS				0x48
 #define	PACKET3_PREAMBLE_CNTL				0x4A
+#              define PACKET3_PREAMBLE_BEGIN_CLEAR_STATE     (2 << 28)
+#              define PACKET3_PREAMBLE_END_CLEAR_STATE       (3 << 28)
 #define	PACKET3_RB_OFFSET				0x4B
 #define	PACKET3_ALU_PS_CONST_BUFFER_COPY		0x4C
 #define	PACKET3_ALU_VS_CONST_BUFFER_COPY		0x4D
@@ -802,6 +818,11 @@
 #define SQ_ALU_CONST_CACHE_LS_14			0x28f78
 #define SQ_ALU_CONST_CACHE_LS_15			0x28f7c
 
+#define PA_SC_SCREEN_SCISSOR_TL                         0x28030
+#define PA_SC_GENERIC_SCISSOR_TL                        0x28240
+#define PA_SC_WINDOW_SCISSOR_TL                         0x28204
+#define VGT_PRIMITIVE_TYPE                              0x8958
+
 #define DB_DEPTH_CONTROL				0x28800
 #define DB_DEPTH_VIEW					0x28008
 #define DB_HTILE_DATA_BASE				0x28014
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,7 @@
 	rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
 	r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
 	r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
-	evergreen.o evergreen_cs.o
+	evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r100.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r100.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r100.c	2012-03-23 21:39:49.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r100.c	2012-03-23 23:31:04.000000000 -0400
@@ -436,7 +436,7 @@
 	int r;
 
 	if (rdev->gart.table.ram.ptr) {
-		WARN(1, "R100 PCI GART already initialized.\n");
+		WARN(1, "R100 PCI GART already initialized\n");
 		return 0;
 	}
 	/* Initialize common gart structure */
@@ -510,7 +510,7 @@
 	uint32_t tmp = 0;
 
 	if (!rdev->irq.installed) {
-		WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
 		WREG32(R_000040_GEN_INT_CNTL, 0);
 		return -EINVAL;
 	}
@@ -669,67 +669,6 @@
 	radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
 }
 
-int r100_wb_init(struct radeon_device *rdev)
-{
-	int r;
-
-	if (rdev->wb.wb_obj == NULL) {
-		r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
-					RADEON_GEM_DOMAIN_GTT,
-					&rdev->wb.wb_obj);
-		if (r) {
-			dev_err(rdev->dev, "(%d) create WB buffer failed\n", r);
-			return r;
-		}
-		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-		if (unlikely(r != 0))
-			return r;
-		r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
-					&rdev->wb.gpu_addr);
-		if (r) {
-			dev_err(rdev->dev, "(%d) pin WB buffer failed\n", r);
-			radeon_bo_unreserve(rdev->wb.wb_obj);
-			return r;
-		}
-		r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
-		radeon_bo_unreserve(rdev->wb.wb_obj);
-		if (r) {
-			dev_err(rdev->dev, "(%d) map WB buffer failed\n", r);
-			return r;
-		}
-	}
-	WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr);
-	WREG32(R_00070C_CP_RB_RPTR_ADDR,
-		S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + 1024) >> 2));
-	WREG32(R_000770_SCRATCH_UMSK, 0xff);
-	return 0;
-}
-
-void r100_wb_disable(struct radeon_device *rdev)
-{
-	WREG32(R_000770_SCRATCH_UMSK, 0);
-}
-
-void r100_wb_fini(struct radeon_device *rdev)
-{
-	int r;
-
-	r100_wb_disable(rdev);
-	if (rdev->wb.wb_obj) {
-		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-		if (unlikely(r != 0)) {
-			dev_err(rdev->dev, "(%d) can't finish WB\n", r);
-			return;
-		}
-		radeon_bo_kunmap(rdev->wb.wb_obj);
-		radeon_bo_unpin(rdev->wb.wb_obj);
-		radeon_bo_unreserve(rdev->wb.wb_obj);
-		radeon_bo_unref(&rdev->wb.wb_obj);
-		rdev->wb.wb = NULL;
-		rdev->wb.wb_obj = NULL;
-	}
-}
-
 int r100_copy_blit(struct radeon_device *rdev,
 		   uint64_t src_offset,
 		   uint64_t dst_offset,
@@ -990,20 +929,32 @@
 	WREG32(0x718, pre_write_timer | (pre_write_limit << 28));
 	tmp = (REG_SET(RADEON_RB_BUFSZ, rb_bufsz) |
 	       REG_SET(RADEON_RB_BLKSZ, rb_blksz) |
-	       REG_SET(RADEON_MAX_FETCH, max_fetch) |
-	       RADEON_RB_NO_UPDATE);
+	       REG_SET(RADEON_MAX_FETCH, max_fetch));
 #ifdef __BIG_ENDIAN
 	tmp |= RADEON_BUF_SWAP_32BIT;
 #endif
-	WREG32(RADEON_CP_RB_CNTL, tmp);
+	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_NO_UPDATE);
 
 	/* Set ring address */
 	DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr);
 	WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr);
 	/* Force read & write ptr to 0 */
-	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+	WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE);
 	WREG32(RADEON_CP_RB_RPTR_WR, 0);
 	WREG32(RADEON_CP_RB_WPTR, 0);
+
+	/* set the wb address whether it's enabled or not */
+	WREG32(R_00070C_CP_RB_RPTR_ADDR,
+		S_00070C_RB_RPTR_ADDR((rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) >> 2));
+	WREG32(R_000774_SCRATCH_ADDR, rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET);
+
+	if (rdev->wb.enabled)
+		WREG32(R_000770_SCRATCH_UMSK, 0xff);
+	else {
+		tmp |= RADEON_RB_NO_UPDATE;
+		WREG32(R_000770_SCRATCH_UMSK, 0);
+	}
+
 	WREG32(RADEON_CP_RB_CNTL, tmp);
 	udelay(10);
 	rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
@@ -1046,6 +997,7 @@
 	rdev->cp.ready = false;
 	WREG32(RADEON_CP_CSQ_MODE, 0);
 	WREG32(RADEON_CP_CSQ_CNTL, 0);
+	WREG32(R_000770_SCRATCH_UMSK, 0);
 	if (r100_gui_wait_for_idle(rdev)) {
 		printk(KERN_WARNING "Failed to wait GUI idle while "
 		       "programming pipes. Bad things might happen.\n");
@@ -2312,6 +2264,9 @@
 		/* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - 
 		 * Novell bug 204882 + along with lots of ubuntu ones
 		 */
+		if (rdev->mc.aper_size > config_aper_size)
+			config_aper_size = rdev->mc.aper_size;
+
 		if (config_aper_size > rdev->mc.real_vram_size)
 			rdev->mc.mc_vram_size = config_aper_size;
 		else
@@ -3219,6 +3174,8 @@
 	for (u = 0; u < track->num_texture; u++) {
 		if (!track->textures[u].enabled)
 			continue;
+		if (track->textures[u].lookup_disable)
+			continue;
 		robj = track->textures[u].robj;
 		if (robj == NULL) {
 			DRM_ERROR("No texture bound to unit %u\n", u);
@@ -3453,6 +3410,7 @@
 		track->textures[i].robj = NULL;
 		/* CS IB emission code makes sure texture unit are disabled */
 		track->textures[i].enabled = false;
+		track->textures[i].lookup_disable = false;
 		track->textures[i].roundup_w = true;
 		track->textures[i].roundup_h = true;
 		if (track->separate_cube)
@@ -3731,6 +3689,12 @@
 		if (r)
 			return r;
 	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r100_irq_set(rdev);
 	rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -3740,9 +3704,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -3776,7 +3737,7 @@
 int r100_suspend(struct radeon_device *rdev)
 {
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	r100_irq_disable(rdev);
 	if (rdev->flags & RADEON_IS_PCI)
 		r100_pci_gart_disable(rdev);
@@ -3786,7 +3747,7 @@
 void r100_fini(struct radeon_device *rdev)
 {
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	if (rdev->flags & RADEON_IS_PCI)
@@ -3899,7 +3860,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		if (rdev->flags & RADEON_IS_PCI)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r100_track.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r100_track.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r100_track.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r100_track.h	2011-01-04 19:50:19.000000000 -0500
@@ -46,6 +46,7 @@
 	unsigned		height_11;
 	bool			use_pitch;
 	bool			enabled;
+	bool                    lookup_disable;
 	bool			roundup_w;
 	bool			roundup_h;
 	unsigned                compress_format;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r200.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r200.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r200.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r200.c	2011-01-04 19:50:19.000000000 -0500
@@ -447,6 +447,8 @@
 			track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK);
 			track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK);
 		}
+		if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE)
+			track->textures[i].lookup_disable = true;
 		switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) {
 		case R200_TXFORMAT_I8:
 		case R200_TXFORMAT_RGB332:
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r300.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r300.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r300.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r300.c	2011-01-04 19:50:19.000000000 -0500
@@ -91,7 +91,7 @@
 	int r;
 
 	if (rdev->gart.table.vram.robj) {
-		WARN(1, "RV370 PCIE GART already initialized.\n");
+		WARN(1, "RV370 PCIE GART already initialized\n");
 		return 0;
 	}
 	/* Initialize common gart structure */
@@ -1332,6 +1332,12 @@
 		if (r)
 			return r;
 	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r100_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -1341,9 +1347,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -1379,7 +1382,7 @@
 int r300_suspend(struct radeon_device *rdev)
 {
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	r100_irq_disable(rdev);
 	if (rdev->flags & RADEON_IS_PCIE)
 		rv370_pcie_gart_disable(rdev);
@@ -1391,7 +1394,7 @@
 void r300_fini(struct radeon_device *rdev)
 {
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	if (rdev->flags & RADEON_IS_PCIE)
@@ -1484,7 +1487,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		if (rdev->flags & RADEON_IS_PCIE)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r420.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r420.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r420.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r420.c	2011-01-04 19:50:19.000000000 -0500
@@ -248,6 +248,12 @@
 			return r;
 	}
 	r420_pipes_init(rdev);
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r100_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -258,10 +264,6 @@
 		return r;
 	}
 	r420_cp_errata_init(rdev);
-	r = r100_wb_init(rdev);
-	if (r) {
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
-	}
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -302,7 +304,7 @@
 {
 	r420_cp_errata_fini(rdev);
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	r100_irq_disable(rdev);
 	if (rdev->flags & RADEON_IS_PCIE)
 		rv370_pcie_gart_disable(rdev);
@@ -314,7 +316,7 @@
 void r420_fini(struct radeon_device *rdev)
 {
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	if (rdev->flags & RADEON_IS_PCIE)
@@ -418,7 +420,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		if (rdev->flags & RADEON_IS_PCIE)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r520.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r520.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r520.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r520.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,6 +181,12 @@
 		if (r)
 			return r;
 	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	rs600_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -190,9 +196,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -295,7 +298,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		rv370_pcie_gart_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_blit_kms.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_blit_kms.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_blit_kms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_blit_kms.c	2011-01-04 19:50:19.000000000 -0500
@@ -472,9 +472,10 @@
 	u32 packet2s[16];
 	int num_packet2s = 0;
 
-	/* don't reinitialize blit */
+	/* pin copy shader into vram if already initialized */
 	if (rdev->r600_blit.shader_obj)
-		return 0;
+		goto done;
+
 	mutex_init(&rdev->r600_blit.mutex);
 	rdev->r600_blit.state_offset = 0;
 
@@ -500,7 +501,7 @@
 	obj_size += r6xx_ps_size * 4;
 	obj_size = ALIGN(obj_size, 256);
 
-	r = radeon_bo_create(rdev, NULL, obj_size, true, RADEON_GEM_DOMAIN_VRAM,
+	r = radeon_bo_create(rdev, NULL, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
 				&rdev->r600_blit.shader_obj);
 	if (r) {
 		DRM_ERROR("r600 failed to allocate shader\n");
@@ -532,6 +533,18 @@
 	memcpy(ptr + rdev->r600_blit.ps_offset, r6xx_ps, r6xx_ps_size * 4);
 	radeon_bo_kunmap(rdev->r600_blit.shader_obj);
 	radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+
+done:
+	r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
+	if (unlikely(r != 0))
+		return r;
+	r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
+			  &rdev->r600_blit.shader_gpu_addr);
+	radeon_bo_unreserve(rdev->r600_blit.shader_obj);
+	if (r) {
+		dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
+		return r;
+	}
 	rdev->mc.active_vram_size = rdev->mc.real_vram_size;
 	return 0;
 }
@@ -554,7 +567,7 @@
 	radeon_bo_unref(&rdev->r600_blit.shader_obj);
 }
 
-int r600_vb_ib_get(struct radeon_device *rdev)
+static int r600_vb_ib_get(struct radeon_device *rdev)
 {
 	int r;
 	r = radeon_ib_get(rdev, &rdev->r600_blit.vb_ib);
@@ -568,7 +581,7 @@
 	return 0;
 }
 
-void r600_vb_ib_put(struct radeon_device *rdev)
+static void r600_vb_ib_put(struct radeon_device *rdev)
 {
 	radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
 	radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
@@ -650,8 +663,8 @@
 			int src_x = src_gpu_addr & 255;
 			int dst_x = dst_gpu_addr & 255;
 			int h = 1;
-			src_gpu_addr = src_gpu_addr & ~255;
-			dst_gpu_addr = dst_gpu_addr & ~255;
+			src_gpu_addr = src_gpu_addr & ~255ULL;
+			dst_gpu_addr = dst_gpu_addr & ~255ULL;
 
 			if (!src_x && !dst_x) {
 				h = (cur_size / max_bytes);
@@ -672,17 +685,6 @@
 
 			if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
 				WARN_ON(1);
-
-#if 0
-				r600_vb_ib_put(rdev);
-
-				r600_nomm_put_vb(dev);
-				r600_nomm_get_vb(dev);
-				if (!dev_priv->blit_vb)
-					return;
-				set_shaders(dev);
-				vb = r600_nomm_get_vb_ptr(dev);
-#endif
 			}
 
 			vb[0] = i2f(dst_x);
@@ -744,8 +746,8 @@
 			int src_x = (src_gpu_addr & 255);
 			int dst_x = (dst_gpu_addr & 255);
 			int h = 1;
-			src_gpu_addr = src_gpu_addr & ~255;
-			dst_gpu_addr = dst_gpu_addr & ~255;
+			src_gpu_addr = src_gpu_addr & ~255ULL;
+			dst_gpu_addr = dst_gpu_addr & ~255ULL;
 
 			if (!src_x && !dst_x) {
 				h = (cur_size / max_bytes);
@@ -767,17 +769,6 @@
 			if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
 				WARN_ON(1);
 			}
-#if 0
-			if ((rdev->blit_vb->used + 48) > rdev->blit_vb->total) {
-				r600_nomm_put_vb(dev);
-				r600_nomm_get_vb(dev);
-				if (!rdev->blit_vb)
-					return;
-
-				set_shaders(dev);
-				vb = r600_nomm_get_vb_ptr(dev);
-			}
-#endif
 
 			vb[0] = i2f(dst_x / 4);
 			vb[1] = 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600.c	2012-03-23 21:39:56.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600.c	2012-03-23 23:31:11.000000000 -0400
@@ -64,14 +64,8 @@
 {
 	u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >>
 		ASIC_T_SHIFT;
-	u32 actual_temp = 0;
 
-	if ((temp >> 7) & 1)
-		actual_temp = 0;
-	else
-		actual_temp = (temp >> 1) & 0xff;
-
-	return actual_temp * 1000;
+	return temp * 1000;
 }
 
 void r600_pm_get_dynpm_state(struct radeon_device *rdev)
@@ -851,12 +845,15 @@
 	u32 tmp;
 
 	/* flush hdp cache so updates hit vram */
-	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) {
+	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
+	    !(rdev->flags & RADEON_IS_AGP)) {
 		void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
 		u32 tmp;
 
 		/* r7xx hw bug.  write to HDP_DEBUG1 followed by fb read
 		 * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+		 * This seems to cause problems on some AGP cards. Just use the old
+		 * method for them.
 		 */
 		WREG32(HDP_DEBUG1, 0);
 		tmp = readl((void __iomem *)ptr);
@@ -886,7 +883,7 @@
 	int r;
 
 	if (rdev->gart.table.vram.robj) {
-		WARN(1, "R600 PCIE GART already initialized.\n");
+		WARN(1, "R600 PCIE GART already initialized\n");
 		return 0;
 	}
 	/* Initialize common gart structure */
@@ -1168,8 +1165,10 @@
 				mc->vram_end, mc->real_vram_size >> 20);
 	} else {
 		u64 base = 0;
-		if (rdev->flags & RADEON_IS_IGP)
-			base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
+		if (rdev->flags & RADEON_IS_IGP) {
+			base = RREG32(MC_VM_FB_LOCATION) & 0xFFFF;
+			base <<= 24;
+		}
 		radeon_vram_location(rdev, &rdev->mc, base);
 		rdev->mc.gtt_base_align = 0;
 		radeon_gtt_location(rdev, mc);
@@ -1310,13 +1309,19 @@
 	u32 srbm_status;
 	u32 grbm_status;
 	u32 grbm_status2;
+	struct r100_gpu_lockup *lockup;
 	int r;
 
+	if (rdev->family >= CHIP_RV770)
+		lockup = &rdev->config.rv770.lockup;
+	else
+		lockup = &rdev->config.r600.lockup;
+
 	srbm_status = RREG32(R_000E50_SRBM_STATUS);
 	grbm_status = RREG32(R_008010_GRBM_STATUS);
 	grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
 	if (!G_008010_GUI_ACTIVE(grbm_status)) {
-		r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp);
+		r100_gpu_lockup_update(lockup, &rdev->cp);
 		return false;
 	}
 	/* force CP activities */
@@ -1328,7 +1333,7 @@
 		radeon_ring_unlock_commit(rdev);
 	}
 	rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
-	return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp);
+	return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp);
 }
 
 int r600_asic_reset(struct radeon_device *rdev)
@@ -1575,8 +1580,11 @@
 	rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes;
 	rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
 	tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
-	tiling_config |= GROUP_SIZE(0);
-	rdev->config.r600.tiling_group_size = 256;
+	tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+	if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+		rdev->config.r600.tiling_group_size = 512;
+	else
+		rdev->config.r600.tiling_group_size = 256;
 	tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
 	if (tmp > 3) {
 		tiling_config |= ROW_TILING(3);
@@ -1887,6 +1895,7 @@
 {
 	rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
 	WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
+	WREG32(SCRATCH_UMSK, 0);
 }
 
 int r600_init_microcode(struct radeon_device *rdev)
@@ -2119,7 +2128,7 @@
 
 	/* Set ring buffer size */
 	rb_bufsz = drm_order(rdev->cp.ring_size / 8);
-	tmp = RB_NO_UPDATE | (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+	tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
 #ifdef __BIG_ENDIAN
 	tmp |= BUF_SWAP_32BIT;
 #endif
@@ -2133,8 +2142,19 @@
 	WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA);
 	WREG32(CP_RB_RPTR_WR, 0);
 	WREG32(CP_RB_WPTR, 0);
-	WREG32(CP_RB_RPTR_ADDR, rdev->cp.gpu_addr & 0xFFFFFFFF);
-	WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->cp.gpu_addr));
+
+	/* set the wb address whether it's enabled or not */
+	WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+	WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+	if (rdev->wb.enabled)
+		WREG32(SCRATCH_UMSK, 0xff);
+	else {
+		tmp |= RB_NO_UPDATE;
+		WREG32(SCRATCH_UMSK, 0);
+	}
+
 	mdelay(1);
 	WREG32(CP_RB_CNTL, tmp);
 
@@ -2186,9 +2206,10 @@
 	int i;
 
 	rdev->scratch.num_reg = 7;
+	rdev->scratch.reg_base = SCRATCH_REG0;
 	for (i = 0; i < rdev->scratch.num_reg; i++) {
 		rdev->scratch.free[i] = true;
-		rdev->scratch.reg[i] = SCRATCH_REG0 + (i * 4);
+		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
 	}
 }
 
@@ -2232,88 +2253,34 @@
 	return r;
 }
 
-void r600_wb_disable(struct radeon_device *rdev)
-{
-	int r;
-
-	WREG32(SCRATCH_UMSK, 0);
-	if (rdev->wb.wb_obj) {
-		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-		if (unlikely(r != 0))
-			return;
-		radeon_bo_kunmap(rdev->wb.wb_obj);
-		radeon_bo_unpin(rdev->wb.wb_obj);
-		radeon_bo_unreserve(rdev->wb.wb_obj);
-	}
-}
-
-void r600_wb_fini(struct radeon_device *rdev)
-{
-	r600_wb_disable(rdev);
-	if (rdev->wb.wb_obj) {
-		radeon_bo_unref(&rdev->wb.wb_obj);
-		rdev->wb.wb = NULL;
-		rdev->wb.wb_obj = NULL;
-	}
-}
-
-int r600_wb_enable(struct radeon_device *rdev)
-{
-	int r;
-
-	if (rdev->wb.wb_obj == NULL) {
-		r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, true,
-				RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
-		if (r) {
-			dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
-			return r;
-		}
-		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
-		if (unlikely(r != 0)) {
-			r600_wb_fini(rdev);
-			return r;
-		}
-		r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
-				&rdev->wb.gpu_addr);
-		if (r) {
-			radeon_bo_unreserve(rdev->wb.wb_obj);
-			dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
-			r600_wb_fini(rdev);
-			return r;
-		}
-		r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
-		radeon_bo_unreserve(rdev->wb.wb_obj);
-		if (r) {
-			dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
-			r600_wb_fini(rdev);
-			return r;
-		}
-	}
-	WREG32(SCRATCH_ADDR, (rdev->wb.gpu_addr >> 8) & 0xFFFFFFFF);
-	WREG32(CP_RB_RPTR_ADDR, (rdev->wb.gpu_addr + 1024) & 0xFFFFFFFC);
-	WREG32(CP_RB_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + 1024) & 0xFF);
-	WREG32(SCRATCH_UMSK, 0xff);
-	return 0;
-}
-
 void r600_fence_ring_emit(struct radeon_device *rdev,
 			  struct radeon_fence *fence)
 {
-	/* Also consider EVENT_WRITE_EOP.  it handles the interrupts + timestamps + events */
-
-	radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
-	radeon_ring_write(rdev, CACHE_FLUSH_AND_INV_EVENT);
-	/* wait for 3D idle clean */
-	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-	radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
-	radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
-	/* Emit fence sequence & fire IRQ */
-	radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-	radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
-	radeon_ring_write(rdev, fence->seq);
-	/* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
-	radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
-	radeon_ring_write(rdev, RB_INT_STAT);
+	if (rdev->wb.use_event) {
+		u64 addr = rdev->wb.gpu_addr + R600_WB_EVENT_OFFSET +
+			(u64)(rdev->fence_drv.scratch_reg - rdev->scratch.reg_base);
+		/* EVENT_WRITE_EOP - flush caches, send int */
+		radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+		radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5));
+		radeon_ring_write(rdev, addr & 0xffffffff);
+		radeon_ring_write(rdev, (upper_32_bits(addr) & 0xff) | DATA_SEL(1) | INT_SEL(2));
+		radeon_ring_write(rdev, fence->seq);
+		radeon_ring_write(rdev, 0);
+	} else {
+		radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0));
+		radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT) | EVENT_INDEX(0));
+		/* wait for 3D idle clean */
+		radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+		radeon_ring_write(rdev, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+		radeon_ring_write(rdev, WAIT_3D_IDLE_bit | WAIT_3D_IDLECLEAN_bit);
+		/* Emit fence sequence & fire IRQ */
+		radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+		radeon_ring_write(rdev, ((rdev->fence_drv.scratch_reg - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
+		radeon_ring_write(rdev, fence->seq);
+		/* CP_INTERRUPT packet 3 no longer exists, use packet 0 */
+		radeon_ring_write(rdev, PACKET0(CP_INT_STATUS, 0));
+		radeon_ring_write(rdev, RB_INT_STAT);
+	}
 }
 
 int r600_copy_blit(struct radeon_device *rdev,
@@ -2395,19 +2362,12 @@
 		rdev->asic->copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
-	/* pin copy shader into vram */
-	if (rdev->r600_blit.shader_obj) {
-		r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-		if (unlikely(r != 0))
-			return r;
-		r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-				&rdev->r600_blit.shader_gpu_addr);
-		radeon_bo_unreserve(rdev->r600_blit.shader_obj);
-		if (r) {
-			dev_err(rdev->dev, "(%d) pin blit object failed\n", r);
-			return r;
-		}
-	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r = r600_irq_init(rdev);
 	if (r) {
@@ -2426,8 +2386,7 @@
 	r = r600_cp_resume(rdev);
 	if (r)
 		return r;
-	/* write back buffer are not vital so don't worry about failure */
-	r600_wb_enable(rdev);
+
 	return 0;
 }
 
@@ -2486,7 +2445,7 @@
 	r600_cp_stop(rdev);
 	rdev->cp.ready = false;
 	r600_irq_suspend(rdev);
-	r600_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	r600_pcie_gart_disable(rdev);
 	/* unpin shaders bo */
 	if (rdev->r600_blit.shader_obj) {
@@ -2583,8 +2542,8 @@
 	if (r) {
 		dev_err(rdev->dev, "disabling GPU acceleration\n");
 		r600_cp_fini(rdev);
-		r600_wb_fini(rdev);
 		r600_irq_fini(rdev);
+		radeon_wb_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		r600_pcie_gart_fini(rdev);
 		rdev->accel_working = false;
@@ -2614,8 +2573,8 @@
 	r600_audio_fini(rdev);
 	r600_blit_fini(rdev);
 	r600_cp_fini(rdev);
-	r600_wb_fini(rdev);
 	r600_irq_fini(rdev);
+	radeon_wb_fini(rdev);
 	radeon_irq_kms_fini(rdev);
 	r600_pcie_gart_fini(rdev);
 	radeon_agp_fini(rdev);
@@ -2737,7 +2696,7 @@
 	/* Allocate ring buffer */
 	if (rdev->ih.ring_obj == NULL) {
 		r = radeon_bo_create(rdev, NULL, rdev->ih.ring_size,
-				     true,
+				     PAGE_SIZE, true,
 				     RADEON_GEM_DOMAIN_GTT,
 				     &rdev->ih.ring_obj);
 		if (r) {
@@ -2950,10 +2909,13 @@
 	ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
 		      IH_WPTR_OVERFLOW_CLEAR |
 		      (rb_bufsz << 1));
-	/* WPTR writeback, not yet */
-	/*ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;*/
-	WREG32(IH_RB_WPTR_ADDR_LO, 0);
-	WREG32(IH_RB_WPTR_ADDR_HI, 0);
+
+	if (rdev->wb.enabled)
+		ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+	/* set the writeback address whether it's enabled or not */
+	WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+	WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
 
 	WREG32(IH_RB_CNTL, ih_rb_cntl);
 
@@ -3005,7 +2967,7 @@
 	u32 hdmi1, hdmi2;
 
 	if (!rdev->irq.installed) {
-		WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
 		return -EINVAL;
 	}
 	/* don't enable anything if the ih is disabled */
@@ -3037,6 +2999,7 @@
 	if (rdev->irq.sw_int) {
 		DRM_DEBUG("r600_irq_set: sw int\n");
 		cp_int_cntl |= RB_INT_ENABLE;
+		cp_int_cntl |= TIME_STAMP_INT_ENABLE;
 	}
 	if (rdev->irq.crtc_vblank_int[0]) {
 		DRM_DEBUG("r600_irq_set: vblank 0\n");
@@ -3211,8 +3174,10 @@
 {
 	u32 wptr, tmp;
 
-	/* XXX use writeback */
-	wptr = RREG32(IH_RB_WPTR);
+	if (rdev->wb.enabled)
+		wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4];
+	else
+		wptr = RREG32(IH_RB_WPTR);
 
 	if (wptr & RB_OVERFLOW) {
 		/* When a ring buffer overflow happen start parsing interrupt
@@ -3400,6 +3365,7 @@
 			break;
 		case 181: /* CP EOP event */
 			DRM_DEBUG("IH: CP EOP\n");
+			radeon_fence_process(rdev);
 			break;
 		case 233: /* GUI IDLE */
 			DRM_DEBUG("IH: CP EOP\n");
@@ -3495,10 +3461,12 @@
 void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo)
 {
 	/* r7xx hw bug.  write to HDP_DEBUG1 followed by fb read
-	 * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL
+	 * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL.
+	 * This seems to cause problems on some AGP cards. Just use the old
+	 * method for them.
 	 */
 	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) &&
-	    rdev->vram_scratch.ptr) {
+	    rdev->vram_scratch.ptr && !(rdev->flags & RADEON_IS_AGP)) {
 		void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
 		u32 tmp;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_cs.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_cs.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,6 +50,7 @@
 	u32			nsamples;
 	u32			cb_color_base_last[8];
 	struct radeon_bo	*cb_color_bo[8];
+	u64			cb_color_bo_mc[8];
 	u32			cb_color_bo_offset[8];
 	struct radeon_bo	*cb_color_frag_bo[8];
 	struct radeon_bo	*cb_color_tile_bo[8];
@@ -67,6 +68,7 @@
 	u32			db_depth_size;
 	u32			db_offset;
 	struct radeon_bo	*db_bo;
+	u64			db_bo_mc;
 };
 
 static inline int r600_bpe_from_format(u32 *bpe, u32 format)
@@ -140,6 +142,68 @@
 	return 0;
 }
 
+struct array_mode_checker {
+	int array_mode;
+	u32 group_size;
+	u32 nbanks;
+	u32 npipes;
+	u32 nsamples;
+	u32 bpe;
+};
+
+/* returns alignment in pixels for pitch/height/depth and bytes for base */
+static inline int r600_get_array_mode_alignment(struct array_mode_checker *values,
+						u32 *pitch_align,
+						u32 *height_align,
+						u32 *depth_align,
+						u64 *base_align)
+{
+	u32 tile_width = 8;
+	u32 tile_height = 8;
+	u32 macro_tile_width = values->nbanks;
+	u32 macro_tile_height = values->npipes;
+	u32 tile_bytes = tile_width * tile_height * values->bpe * values->nsamples;
+	u32 macro_tile_bytes = macro_tile_width * macro_tile_height * tile_bytes;
+
+	switch (values->array_mode) {
+	case ARRAY_LINEAR_GENERAL:
+		/* technically tile_width/_height for pitch/height */
+		*pitch_align = 1; /* tile_width */
+		*height_align = 1; /* tile_height */
+		*depth_align = 1;
+		*base_align = 1;
+		break;
+	case ARRAY_LINEAR_ALIGNED:
+		*pitch_align = max((u32)64, (u32)(values->group_size / values->bpe));
+		*height_align = tile_height;
+		*depth_align = 1;
+		*base_align = values->group_size;
+		break;
+	case ARRAY_1D_TILED_THIN1:
+		*pitch_align = max((u32)tile_width,
+				   (u32)(values->group_size /
+					 (tile_height * values->bpe * values->nsamples)));
+		*height_align = tile_height;
+		*depth_align = 1;
+		*base_align = values->group_size;
+		break;
+	case ARRAY_2D_TILED_THIN1:
+		*pitch_align = max((u32)macro_tile_width,
+				  (u32)(((values->group_size / tile_height) /
+					 (values->bpe * values->nsamples)) *
+					values->nbanks)) * tile_width;
+		*height_align = macro_tile_height * tile_height;
+		*depth_align = 1;
+		*base_align = max(macro_tile_bytes,
+				  (*pitch_align) * values->bpe * (*height_align) * values->nsamples);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void r600_cs_track_init(struct r600_cs_track *track)
 {
 	int i;
@@ -153,10 +217,12 @@
 		track->cb_color_info[i] = 0;
 		track->cb_color_bo[i] = NULL;
 		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+		track->cb_color_bo_mc[i] = 0xFFFFFFFF;
 	}
 	track->cb_target_mask = 0xFFFFFFFF;
 	track->cb_shader_mask = 0xFFFFFFFF;
 	track->db_bo = NULL;
+	track->db_bo_mc = 0xFFFFFFFF;
 	/* assume the biggest format and that htile is enabled */
 	track->db_depth_info = 7 | (1 << 25);
 	track->db_depth_view = 0xFFFFC000;
@@ -168,8 +234,12 @@
 static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
 {
 	struct r600_cs_track *track = p->track;
-	u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
+	u32 bpe = 0, slice_tile_max, size, tmp;
+	u32 height, height_align, pitch, pitch_align, depth_align;
+	u64 base_offset, base_align;
+	struct array_mode_checker array_check;
 	volatile u32 *ib = p->ib->ptr;
+	unsigned array_mode;
 
 	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
 		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
@@ -182,57 +252,40 @@
 			i, track->cb_color_info[i]);
 		return -EINVAL;
 	}
-	/* pitch is the number of 8x8 tiles per row */
-	pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
+	/* pitch in pixels */
+	pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) * 8;
 	slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
-	height = size / (pitch * 8 * bpe);
+	slice_tile_max *= 64;
+	height = slice_tile_max / pitch;
 	if (height > 8192)
 		height = 8192;
-	if (height > 7)
-		height &= ~0x7;
-	switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
+	array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
+
+	base_offset = track->cb_color_bo_mc[i] + track->cb_color_bo_offset[i];
+	array_check.array_mode = array_mode;
+	array_check.group_size = track->group_size;
+	array_check.nbanks = track->nbanks;
+	array_check.npipes = track->npipes;
+	array_check.nsamples = track->nsamples;
+	array_check.bpe = bpe;
+	if (r600_get_array_mode_alignment(&array_check,
+					  &pitch_align, &height_align, &depth_align, &base_align)) {
+		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
+			 G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
+			 track->cb_color_info[i]);
+		return -EINVAL;
+	}
+	switch (array_mode) {
 	case V_0280A0_ARRAY_LINEAR_GENERAL:
-		/* technically height & 0x7 */
 		break;
 	case V_0280A0_ARRAY_LINEAR_ALIGNED:
-		pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				 __func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		if (!IS_ALIGNED(height, 8)) {
-			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-				 __func__, __LINE__, height);
-			return -EINVAL;
-		}
 		break;
 	case V_0280A0_ARRAY_1D_TILED_THIN1:
-		pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8;
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				 __func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		if (!IS_ALIGNED(height, 8)) {
-			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-				 __func__, __LINE__, height);
-			return -EINVAL;
-		}
+		/* avoid breaking userspace */
+		if (height > 7)
+			height &= ~0x7;
 		break;
 	case V_0280A0_ARRAY_2D_TILED_THIN1:
-		pitch_align = max((u32)track->nbanks,
-				  (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks));
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				__func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		if (!IS_ALIGNED((height / 8), track->nbanks)) {
-			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
-				 __func__, __LINE__, height);
-			return -EINVAL;
-		}
 		break;
 	default:
 		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -240,21 +293,42 @@
 			track->cb_color_info[i]);
 		return -EINVAL;
 	}
-	/* check offset */
-	tmp = height * pitch * 8 * bpe;
-	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
-		dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]);
+
+	if (!IS_ALIGNED(pitch, pitch_align)) {
+		dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
+			 __func__, __LINE__, pitch);
 		return -EINVAL;
 	}
-	if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
-		dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
+	if (!IS_ALIGNED(height, height_align)) {
+		dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+			 __func__, __LINE__, height);
+		return -EINVAL;
+	}
+	if (!IS_ALIGNED(base_offset, base_align)) {
+		dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
 		return -EINVAL;
 	}
+
+	/* check offset */
+	tmp = height * pitch * bpe;
+	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
+		if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
+			/* the initial DDX does bad things with the CB size occasionally */
+			/* it rounds up height too far for slice tile max but the BO is smaller */
+			/* r600c,g also seem to flush at bad times in some apps resulting in
+			 * bogus values here. So for linear just allow anything to avoid breaking
+			 * broken userspace.
+			 */
+		} else {
+			dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
+			return -EINVAL;
+		}
+	}
 	/* limit max tile */
-	tmp = (height * pitch * 8) >> 6;
+	tmp = (height * pitch) >> 6;
 	if (tmp < slice_tile_max)
 		slice_tile_max = tmp;
-	tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
+	tmp = S_028060_PITCH_TILE_MAX((pitch / 8) - 1) |
 		S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
 	ib[track->cb_color_size_idx[i]] = tmp;
 	return 0;
@@ -296,7 +370,12 @@
 	/* Check depth buffer */
 	if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
 		G_028800_Z_ENABLE(track->db_depth_control)) {
-		u32 nviews, bpe, ntiles, pitch, pitch_align, height, size;
+		u32 nviews, bpe, ntiles, size, slice_tile_max;
+		u32 height, height_align, pitch, pitch_align, depth_align;
+		u64 base_offset, base_align;
+		struct array_mode_checker array_check;
+		int array_mode;
+
 		if (track->db_bo == NULL) {
 			dev_warn(p->dev, "z/stencil with no depth buffer\n");
 			return -EINVAL;
@@ -339,39 +418,34 @@
 			ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
 		} else {
 			size = radeon_bo_size(track->db_bo);
-			pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
-			height = size / (pitch * 8 * bpe);
-			height &= ~0x7;
-			if (!height)
-				height = 8;
-
-			switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+			/* pitch in pixels */
+			pitch = (G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1) * 8;
+			slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
+			slice_tile_max *= 64;
+			height = slice_tile_max / pitch;
+			if (height > 8192)
+				height = 8192;
+			base_offset = track->db_bo_mc + track->db_offset;
+			array_mode = G_028010_ARRAY_MODE(track->db_depth_info);
+			array_check.array_mode = array_mode;
+			array_check.group_size = track->group_size;
+			array_check.nbanks = track->nbanks;
+			array_check.npipes = track->npipes;
+			array_check.nsamples = track->nsamples;
+			array_check.bpe = bpe;
+			if (r600_get_array_mode_alignment(&array_check,
+							  &pitch_align, &height_align, &depth_align, &base_align)) {
+				dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+					 G_028010_ARRAY_MODE(track->db_depth_info),
+					 track->db_depth_info);
+				return -EINVAL;
+			}
+			switch (array_mode) {
 			case V_028010_ARRAY_1D_TILED_THIN1:
-				pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8);
-				if (!IS_ALIGNED(pitch, pitch_align)) {
-					dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-						 __func__, __LINE__, pitch);
-					return -EINVAL;
-				}
-				if (!IS_ALIGNED(height, 8)) {
-					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-						 __func__, __LINE__, height);
-					return -EINVAL;
-				}
+				/* don't break userspace */
+				height &= ~0x7;
 				break;
 			case V_028010_ARRAY_2D_TILED_THIN1:
-				pitch_align = max((u32)track->nbanks,
-						  (u32)(((track->group_size / 8) / bpe) * track->nbanks));
-				if (!IS_ALIGNED(pitch, pitch_align)) {
-					dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
-						 __func__, __LINE__, pitch);
-					return -EINVAL;
-				}
-				if ((height / 8) & (track->nbanks - 1)) {
-					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
-						 __func__, __LINE__, height);
-					return -EINVAL;
-				}
 				break;
 			default:
 				dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
@@ -379,15 +453,27 @@
 					 track->db_depth_info);
 				return -EINVAL;
 			}
-			if (!IS_ALIGNED(track->db_offset, track->group_size)) {
-				dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+
+			if (!IS_ALIGNED(pitch, pitch_align)) {
+				dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+					 __func__, __LINE__, pitch);
 				return -EINVAL;
 			}
+			if (!IS_ALIGNED(height, height_align)) {
+				dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+					 __func__, __LINE__, height);
+				return -EINVAL;
+			}
+			if (!IS_ALIGNED(base_offset, base_align)) {
+				dev_warn(p->dev, "%s offset[%d] 0x%llx not aligned\n", __func__, i, base_offset);
+				return -EINVAL;
+			}
+
 			ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
 			nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
 			tmp = ntiles * bpe * 64 * nviews;
 			if ((tmp + track->db_offset) > radeon_bo_size(track->db_bo)) {
-				dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %d have %ld)\n",
+				dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %d -> %u have %lu)\n",
 						track->db_depth_size, ntiles, nviews, bpe, tmp + track->db_offset,
 						radeon_bo_size(track->db_bo));
 				return -EINVAL;
@@ -938,6 +1024,7 @@
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
+		track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
 		break;
 	case DB_DEPTH_BASE:
 		r = r600_cs_packet_next_reloc(p, &reloc);
@@ -949,6 +1036,7 @@
 		track->db_offset = radeon_get_ib_value(p, idx) << 8;
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_bo = reloc->robj;
+		track->db_bo_mc = reloc->lobj.gpu_offset;
 		break;
 	case DB_HTILE_DATA_BASE:
 	case SQ_PGM_START_FS:
@@ -1070,16 +1158,25 @@
 static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
 					      struct radeon_bo *texture,
 					      struct radeon_bo *mipmap,
+					      u64 base_offset,
+					      u64 mip_offset,
 					      u32 tiling_flags)
 {
 	struct r600_cs_track *track = p->track;
 	u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
-	u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
+	u32 word0, word1, l0_size, mipmap_size;
+	u32 height_align, pitch, pitch_align, depth_align;
+	u64 base_align;
+	struct array_mode_checker array_check;
 
 	/* on legacy kernel we don't perform advanced check */
 	if (p->rdev == NULL)
 		return 0;
 
+	/* convert to bytes */
+	base_offset <<= 8;
+	mip_offset <<= 8;
+
 	word0 = radeon_get_ib_value(p, idx + 0);
 	if (tiling_flags & RADEON_TILING_MACRO)
 		word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
@@ -1112,46 +1209,38 @@
 		return -EINVAL;
 	}
 
-	pitch = G_038000_PITCH(word0) + 1;
-	switch (G_038000_TILE_MODE(word0)) {
-	case V_038000_ARRAY_LINEAR_GENERAL:
-		pitch_align = 1;
-		/* XXX check height align */
-		break;
-	case V_038000_ARRAY_LINEAR_ALIGNED:
-		pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-				 __func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		/* XXX check height align */
-		break;
-	case V_038000_ARRAY_1D_TILED_THIN1:
-		pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8;
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-				 __func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		/* XXX check height align */
-		break;
-	case V_038000_ARRAY_2D_TILED_THIN1:
-		pitch_align = max((u32)track->nbanks,
-				  (u32)(((track->group_size / 8) / bpe) * track->nbanks));
-		if (!IS_ALIGNED(pitch, pitch_align)) {
-			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
-				__func__, __LINE__, pitch);
-			return -EINVAL;
-		}
-		/* XXX check height align */
-		break;
-	default:
-		dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
-			 G_038000_TILE_MODE(word0), word0);
+	/* pitch in texels */
+	pitch = (G_038000_PITCH(word0) + 1) * 8;
+	array_check.array_mode = G_038000_TILE_MODE(word0);
+	array_check.group_size = track->group_size;
+	array_check.nbanks = track->nbanks;
+	array_check.npipes = track->npipes;
+	array_check.nsamples = 1;
+	array_check.bpe = bpe;
+	if (r600_get_array_mode_alignment(&array_check,
+					  &pitch_align, &height_align, &depth_align, &base_align)) {
+		dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
+			 __func__, __LINE__, G_038000_TILE_MODE(word0));
+		return -EINVAL;
+	}
+
+	/* XXX check height as well... */
+
+	if (!IS_ALIGNED(pitch, pitch_align)) {
+		dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+			 __func__, __LINE__, pitch);
+		return -EINVAL;
+	}
+	if (!IS_ALIGNED(base_offset, base_align)) {
+		dev_warn(p->dev, "%s:%d tex base offset (0x%llx) invalid\n",
+			 __func__, __LINE__, base_offset);
+		return -EINVAL;
+	}
+	if (!IS_ALIGNED(mip_offset, base_align)) {
+		dev_warn(p->dev, "%s:%d tex mip offset (0x%llx) invalid\n",
+			 __func__, __LINE__, mip_offset);
 		return -EINVAL;
 	}
-	/* XXX check offset align */
 
 	word0 = radeon_get_ib_value(p, idx + 4);
 	word1 = radeon_get_ib_value(p, idx + 5);
@@ -1386,7 +1475,10 @@
 				mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				mipmap = reloc->robj;
 				r = r600_check_texture_resource(p,  idx+(i*7)+1,
-								texture, mipmap, reloc->lobj.tiling_flags);
+								texture, mipmap,
+								base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
+								mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
+								reloc->lobj.tiling_flags);
 				if (r)
 					return r;
 				ib[idx+1+(i*7)+2] += base_offset;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600d.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600d.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600d.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600d.h	2011-01-04 19:50:19.000000000 -0500
@@ -51,6 +51,12 @@
 #define PTE_READABLE				(1 << 5)
 #define PTE_WRITEABLE				(1 << 6)
 
+/* tiling bits */
+#define     ARRAY_LINEAR_GENERAL              0x00000000
+#define     ARRAY_LINEAR_ALIGNED              0x00000001
+#define     ARRAY_1D_TILED_THIN1              0x00000002
+#define     ARRAY_2D_TILED_THIN1              0x00000004
+
 /* Registers */
 #define	ARB_POP						0x2418
 #define 	ENABLE_TC128					(1 << 30)
@@ -474,6 +480,7 @@
 #define	VGT_VERTEX_REUSE_BLOCK_CNTL			0x28C58
 #define		VTX_REUSE_DEPTH_MASK				0x000000FF
 #define VGT_EVENT_INITIATOR                             0x28a90
+#       define CACHE_FLUSH_AND_INV_EVENT_TS                     (0x14 << 0)
 #       define CACHE_FLUSH_AND_INV_EVENT                        (0x16 << 0)
 
 #define VM_CONTEXT0_CNTL				0x1410
@@ -775,7 +782,27 @@
 #define		PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
 #define	PACKET3_COND_WRITE				0x45
 #define	PACKET3_EVENT_WRITE				0x46
+#define		EVENT_TYPE(x)                           ((x) << 0)
+#define		EVENT_INDEX(x)                          ((x) << 8)
+                /* 0 - any non-TS event
+		 * 1 - ZPASS_DONE
+		 * 2 - SAMPLE_PIPELINESTAT
+		 * 3 - SAMPLE_STREAMOUTSTAT*
+		 * 4 - *S_PARTIAL_FLUSH
+		 * 5 - TS events
+		 */
 #define	PACKET3_EVENT_WRITE_EOP				0x47
+#define		DATA_SEL(x)                             ((x) << 29)
+                /* 0 - discard
+		 * 1 - send low 32bit data
+		 * 2 - send 64bit data
+		 * 3 - send 64bit counter value
+		 */
+#define		INT_SEL(x)                              ((x) << 24)
+                /* 0 - none
+		 * 1 - interrupt only (DATA_SEL = 0)
+		 * 2 - interrupt when data write is confirmed
+		 */
 #define	PACKET3_ONE_REG_WRITE				0x57
 #define	PACKET3_SET_CONFIG_REG				0x68
 #define		PACKET3_SET_CONFIG_REG_OFFSET			0x00008000
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_reg.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_reg.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/r600_reg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/r600_reg.h	2011-01-04 19:50:19.000000000 -0500
@@ -86,6 +86,7 @@
 #define R600_HDP_NONSURFACE_BASE                                0x2c04
 
 #define R600_BUS_CNTL                                           0x5420
+#       define R600_BIOS_ROM_DIS                                (1 << 1)
 #define R600_CONFIG_CNTL                                        0x5424
 #define R600_CONFIG_MEMSIZE                                     0x5428
 #define R600_CONFIG_F0_BASE                                     0x542C
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_asic.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_asic.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_asic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_asic.c	2011-01-04 19:50:19.000000000 -0500
@@ -726,9 +726,9 @@
 	.get_vblank_counter = &evergreen_get_vblank_counter,
 	.fence_ring_emit = &r600_fence_ring_emit,
 	.cs_parse = &evergreen_cs_parse,
-	.copy_blit = NULL,
-	.copy_dma = NULL,
-	.copy = NULL,
+	.copy_blit = &evergreen_copy_blit,
+	.copy_dma = &evergreen_copy_blit,
+	.copy = &evergreen_copy_blit,
 	.get_engine_clock = &radeon_atom_get_engine_clock,
 	.set_engine_clock = &radeon_atom_set_engine_clock,
 	.get_memory_clock = &radeon_atom_get_memory_clock,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_asic.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_asic.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_asic.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_asic.h	2011-01-04 19:50:19.000000000 -0500
@@ -108,9 +108,6 @@
 void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save);
 void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save);
 void r100_vram_init_sizes(struct radeon_device *rdev);
-void r100_wb_disable(struct radeon_device *rdev);
-void r100_wb_fini(struct radeon_device *rdev);
-int r100_wb_init(struct radeon_device *rdev);
 int r100_cp_reset(struct radeon_device *rdev);
 void r100_vga_render_disable(struct radeon_device *rdev);
 void r100_restore_sanity(struct radeon_device *rdev);
@@ -257,11 +254,6 @@
 int r600_cs_parse(struct radeon_cs_parser *p);
 void r600_fence_ring_emit(struct radeon_device *rdev,
 			  struct radeon_fence *fence);
-int r600_copy_dma(struct radeon_device *rdev,
-		  uint64_t src_offset,
-		  uint64_t dst_offset,
-		  unsigned num_pages,
-		  struct radeon_fence *fence);
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_set(struct radeon_device *rdev);
 bool r600_gpu_is_lockup(struct radeon_device *rdev);
@@ -307,6 +299,9 @@
 bool evergreen_gpu_is_lockup(struct radeon_device *rdev);
 int evergreen_asic_reset(struct radeon_device *rdev);
 void evergreen_bandwidth_update(struct radeon_device *rdev);
+int evergreen_copy_blit(struct radeon_device *rdev,
+			uint64_t src_offset, uint64_t dst_offset,
+			unsigned num_pages, struct radeon_fence *fence);
 void evergreen_hpd_init(struct radeon_device *rdev);
 void evergreen_hpd_fini(struct radeon_device *rdev);
 bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_atombios.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_atombios.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_atombios.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_atombios.c	2011-01-04 19:50:19.000000000 -0500
@@ -98,6 +98,14 @@
 				}
 			}
 
+			/* some DCE3 boards have bad data for this entry */
+			if (ASIC_IS_DCE3(rdev)) {
+				if ((i == 4) &&
+				    (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+				    (gpio->sucI2cId.ucAccess == 0x94))
+					gpio->sucI2cId.ucAccess = 0x14;
+			}
+
 			if (gpio->sucI2cId.ucAccess == id) {
 				i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
 				i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
@@ -174,6 +182,14 @@
 				}
 			}
 
+			/* some DCE3 boards have bad data for this entry */
+			if (ASIC_IS_DCE3(rdev)) {
+				if ((i == 4) &&
+				    (gpio->usClkMaskRegisterIndex == 0x1fda) &&
+				    (gpio->sucI2cId.ucAccess == 0x94))
+					gpio->sucI2cId.ucAccess = 0x14;
+			}
+
 			i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
 			i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
 			i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
@@ -526,8 +542,6 @@
 	if (crev < 2)
 		return false;
 
-	router.valid = false;
-
 	obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
 	path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
 	    (ctx->bios + data_offset +
@@ -624,6 +638,8 @@
 			if (connector_type == DRM_MODE_CONNECTOR_Unknown)
 				continue;
 
+			router.ddc_valid = false;
+			router.cd_valid = false;
 			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
 				uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
 
@@ -647,9 +663,8 @@
 								 usDeviceTag));
 
 				} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
-					router.valid = false;
 					for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
-						u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
+						u16 router_obj_id = le16_to_cpu(router_obj->asObjects[k].usObjectID);
 						if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
 							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
 								(ctx->bios + data_offset +
@@ -657,6 +672,7 @@
 							ATOM_I2C_RECORD *i2c_record;
 							ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
 							ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+							ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *cd_path;
 							ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
 								(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
 								(ctx->bios + data_offset +
@@ -690,10 +706,18 @@
 								case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
 									ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
 										record;
-									router.valid = true;
-									router.mux_type = ddc_path->ucMuxType;
-									router.mux_control_pin = ddc_path->ucMuxControlPin;
-									router.mux_state = ddc_path->ucMuxState[enum_id];
+									router.ddc_valid = true;
+									router.ddc_mux_type = ddc_path->ucMuxType;
+									router.ddc_mux_control_pin = ddc_path->ucMuxControlPin;
+									router.ddc_mux_state = ddc_path->ucMuxState[enum_id];
+									break;
+								case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
+									cd_path = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)
+										record;
+									router.cd_valid = true;
+									router.cd_mux_type = cd_path->ucMuxType;
+									router.cd_mux_control_pin = cd_path->ucMuxControlPin;
+									router.cd_mux_state = cd_path->ucMuxState[enum_id];
 									break;
 								}
 								record = (ATOM_COMMON_RECORD_HEADER *)
@@ -860,7 +884,8 @@
 	size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
 	struct radeon_router router;
 
-	router.valid = false;
+	router.ddc_valid = false;
+	router.cd_valid = false;
 
 	bios_connectors = kzalloc(bc_size, GFP_KERNEL);
 	if (!bios_connectors)
@@ -1112,8 +1137,7 @@
 			 * pre-DCE 3.0 r6xx hardware.  This might need to be adjusted per
 			 * family.
 			 */
-			if (!radeon_new_pll)
-				p1pll->pll_out_min = 64800;
+			p1pll->pll_out_min = 64800;
 		}
 
 		p1pll->pll_in_min =
@@ -1277,36 +1301,27 @@
 	return false;
 }
 
-static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct
-							  radeon_encoder
-							  *encoder,
-							  int id)
+bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+				      struct radeon_atom_ss *ss,
+				      int id)
 {
-	struct drm_device *dev = encoder->base.dev;
-	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_mode_info *mode_info = &rdev->mode_info;
 	int index = GetIndexIntoMasterTable(DATA, PPLL_SS_Info);
-	uint16_t data_offset;
+	uint16_t data_offset, size;
 	struct _ATOM_SPREAD_SPECTRUM_INFO *ss_info;
 	uint8_t frev, crev;
-	struct radeon_atom_ss *ss = NULL;
-	int i;
-
-	if (id > ATOM_MAX_SS_ENTRY)
-		return NULL;
+	int i, num_indices;
 
-	if (atom_parse_data_header(mode_info->atom_context, index, NULL,
+	memset(ss, 0, sizeof(struct radeon_atom_ss));
+	if (atom_parse_data_header(mode_info->atom_context, index, &size,
 				   &frev, &crev, &data_offset)) {
 		ss_info =
 			(struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset);
 
-		ss =
-		    kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL);
-
-		if (!ss)
-			return NULL;
+		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+			sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
 
-		for (i = 0; i < ATOM_MAX_SS_ENTRY; i++) {
+		for (i = 0; i < num_indices; i++) {
 			if (ss_info->asSS_Info[i].ucSS_Id == id) {
 				ss->percentage =
 					le16_to_cpu(ss_info->asSS_Info[i].usSpreadSpectrumPercentage);
@@ -1315,11 +1330,88 @@
 				ss->delay = ss_info->asSS_Info[i].ucSS_Delay;
 				ss->range = ss_info->asSS_Info[i].ucSS_Range;
 				ss->refdiv = ss_info->asSS_Info[i].ucRecommendedRef_Div;
-				break;
+				return true;
 			}
 		}
 	}
-	return ss;
+	return false;
+}
+
+union asic_ss_info {
+	struct _ATOM_ASIC_INTERNAL_SS_INFO info;
+	struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2;
+	struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3;
+};
+
+bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+				      struct radeon_atom_ss *ss,
+				      int id, u32 clock)
+{
+	struct radeon_mode_info *mode_info = &rdev->mode_info;
+	int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+	uint16_t data_offset, size;
+	union asic_ss_info *ss_info;
+	uint8_t frev, crev;
+	int i, num_indices;
+
+	memset(ss, 0, sizeof(struct radeon_atom_ss));
+	if (atom_parse_data_header(mode_info->atom_context, index, &size,
+				   &frev, &crev, &data_offset)) {
+
+		ss_info =
+			(union asic_ss_info *)(mode_info->atom_context->bios + data_offset);
+
+		switch (frev) {
+		case 1:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_ASIC_SS_ASSIGNMENT);
+
+			for (i = 0; i < num_indices; i++) {
+				if ((ss_info->info.asSpreadSpectrum[i].ucClockIndication == id) &&
+				    (clock <= ss_info->info.asSpreadSpectrum[i].ulTargetClockRange)) {
+					ss->percentage =
+						le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+					ss->type = ss_info->info.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+					ss->rate = le16_to_cpu(ss_info->info.asSpreadSpectrum[i].usSpreadRateInKhz);
+					return true;
+				}
+			}
+			break;
+		case 2:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
+			for (i = 0; i < num_indices; i++) {
+				if ((ss_info->info_2.asSpreadSpectrum[i].ucClockIndication == id) &&
+				    (clock <= ss_info->info_2.asSpreadSpectrum[i].ulTargetClockRange)) {
+					ss->percentage =
+						le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+					ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+					ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+					return true;
+				}
+			}
+			break;
+		case 3:
+			num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+				sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
+			for (i = 0; i < num_indices; i++) {
+				if ((ss_info->info_3.asSpreadSpectrum[i].ucClockIndication == id) &&
+				    (clock <= ss_info->info_3.asSpreadSpectrum[i].ulTargetClockRange)) {
+					ss->percentage =
+						le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
+					ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
+					ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+					return true;
+				}
+			}
+			break;
+		default:
+			DRM_ERROR("Unsupported ASIC_InternalSS_Info table: %d %d\n", frev, crev);
+			break;
+		}
+
+	}
+	return false;
 }
 
 union lvds_info {
@@ -1371,7 +1463,7 @@
 			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
 		lvds->panel_pwr_delay =
 		    le16_to_cpu(lvds_info->info.usOffDelayInMs);
-		lvds->lvds_misc = lvds_info->info.ucLVDS_Misc;
+		lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
 
 		misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
 		if (misc & ATOM_VSYNC_POLARITY)
@@ -1388,19 +1480,7 @@
 		/* set crtc values */
 		drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
 
-		lvds->ss = radeon_atombios_get_ss_info(encoder, lvds_info->info.ucSS_Id);
-
-		if (ASIC_IS_AVIVO(rdev)) {
-			if (radeon_new_pll == 0)
-				lvds->pll_algo = PLL_ALGO_LEGACY;
-			else
-				lvds->pll_algo = PLL_ALGO_NEW;
-		} else {
-			if (radeon_new_pll == 1)
-				lvds->pll_algo = PLL_ALGO_NEW;
-			else
-				lvds->pll_algo = PLL_ALGO_LEGACY;
-		}
+		lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
 
 		encoder->native_mode = lvds->native_mode;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_benchmark.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_benchmark.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_benchmark.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_benchmark.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,7 @@
 
 	size = bsize;
 	n = 1024;
-	r = radeon_bo_create(rdev, NULL, size, true, sdomain, &sobj);
+	r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, sdomain, &sobj);
 	if (r) {
 		goto out_cleanup;
 	}
@@ -53,7 +53,7 @@
 	if (r) {
 		goto out_cleanup;
 	}
-	r = radeon_bo_create(rdev, NULL, size, true, ddomain, &dobj);
+	r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, ddomain, &dobj);
 	if (r) {
 		goto out_cleanup;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_bios.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_bios.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_bios.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_bios.c	2011-01-04 19:50:19.000000000 -0500
@@ -130,6 +130,7 @@
 	}
 	return true;
 }
+
 static bool r700_read_disabled_bios(struct radeon_device *rdev)
 {
 	uint32_t viph_control;
@@ -143,7 +144,7 @@
 	bool r;
 
 	viph_control = RREG32(RADEON_VIPH_CONTROL);
-	bus_cntl = RREG32(RADEON_BUS_CNTL);
+	bus_cntl = RREG32(R600_BUS_CNTL);
 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -152,7 +153,7 @@
 	/* disable VIP */
 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
 	/* enable the rom */
-	WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
 	/* Disable VGA mode */
 	WREG32(AVIVO_D1VGA_CONTROL,
 	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
@@ -191,7 +192,7 @@
 			cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
 	}
 	WREG32(RADEON_VIPH_CONTROL, viph_control);
-	WREG32(RADEON_BUS_CNTL, bus_cntl);
+	WREG32(R600_BUS_CNTL, bus_cntl);
 	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
 	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
 	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
@@ -216,7 +217,7 @@
 	bool r;
 
 	viph_control = RREG32(RADEON_VIPH_CONTROL);
-	bus_cntl = RREG32(RADEON_BUS_CNTL);
+	bus_cntl = RREG32(R600_BUS_CNTL);
 	d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
 	d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
 	vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
@@ -231,7 +232,7 @@
 	/* disable VIP */
 	WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
 	/* enable the rom */
-	WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+	WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
 	/* Disable VGA mode */
 	WREG32(AVIVO_D1VGA_CONTROL,
 	       (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
@@ -262,7 +263,7 @@
 
 	/* restore regs */
 	WREG32(RADEON_VIPH_CONTROL, viph_control);
-	WREG32(RADEON_BUS_CNTL, bus_cntl);
+	WREG32(R600_BUS_CNTL, bus_cntl);
 	WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
 	WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
 	WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_combios.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_combios.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_combios.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_combios.c	2011-01-04 19:50:19.000000000 -0500
@@ -571,6 +571,7 @@
 	}
 
 	if (clk_mask && data_mask) {
+		/* system specific masks */
 		i2c.mask_clk_mask = clk_mask;
 		i2c.mask_data_mask = data_mask;
 		i2c.a_clk_mask = clk_mask;
@@ -579,7 +580,19 @@
 		i2c.en_data_mask = data_mask;
 		i2c.y_clk_mask = clk_mask;
 		i2c.y_data_mask = data_mask;
+	} else if ((ddc_line == RADEON_GPIOPAD_MASK) ||
+		   (ddc_line == RADEON_MDGPIO_MASK)) {
+		/* default gpiopad masks */
+		i2c.mask_clk_mask = (0x20 << 8);
+		i2c.mask_data_mask = 0x80;
+		i2c.a_clk_mask = (0x20 << 8);
+		i2c.a_data_mask = 0x80;
+		i2c.en_clk_mask = (0x20 << 8);
+		i2c.en_data_mask = 0x80;
+		i2c.y_clk_mask = (0x20 << 8);
+		i2c.y_data_mask = 0x80;
 	} else {
+		/* default masks for ddc pads */
 		i2c.mask_clk_mask = RADEON_GPIO_EN_1;
 		i2c.mask_data_mask = RADEON_GPIO_EN_0;
 		i2c.a_clk_mask = RADEON_GPIO_A_1;
@@ -716,7 +729,7 @@
 					clk = RBIOS8(offset + 3 + (i * 5) + 3);
 					data = RBIOS8(offset + 3 + (i * 5) + 4);
 					i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
-								    clk, data);
+								    (1 << clk), (1 << data));
 					rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
 					break;
 				}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_connectors.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_connectors.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_connectors.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_connectors.c	2011-01-04 19:50:19.000000000 -0500
@@ -183,13 +183,13 @@
 					continue;
 
 				if (priority == true) {
-					DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
-					DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
+					DRM_DEBUG_KMS("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
+					DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(connector));
 					conflict->status = connector_status_disconnected;
 					radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
 				} else {
-					DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
-					DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
+					DRM_DEBUG_KMS("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
+					DRM_DEBUG_KMS("in favor of %s\n", drm_get_connector_name(conflict));
 					current_status = connector_status_disconnected;
 				}
 				break;
@@ -326,6 +326,34 @@
 		}
 	}
 
+	if (property == rdev->mode_info.underscan_hborder_property) {
+		/* need to find digital encoder on connector */
+		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+		if (!encoder)
+			return 0;
+
+		radeon_encoder = to_radeon_encoder(encoder);
+
+		if (radeon_encoder->underscan_hborder != val) {
+			radeon_encoder->underscan_hborder = val;
+			radeon_property_change_mode(&radeon_encoder->base);
+		}
+	}
+
+	if (property == rdev->mode_info.underscan_vborder_property) {
+		/* need to find digital encoder on connector */
+		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+		if (!encoder)
+			return 0;
+
+		radeon_encoder = to_radeon_encoder(encoder);
+
+		if (radeon_encoder->underscan_vborder != val) {
+			radeon_encoder->underscan_vborder = val;
+			radeon_property_change_mode(&radeon_encoder->base);
+		}
+	}
+
 	if (property == rdev->mode_info.tv_std_property) {
 		encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC);
 		if (!encoder) {
@@ -404,13 +432,13 @@
 			    mode->vdisplay == native_mode->vdisplay) {
 				*native_mode = *mode;
 				drm_mode_set_crtcinfo(native_mode, CRTC_INTERLACE_HALVE_V);
-				DRM_INFO("Determined LVDS native mode details from EDID\n");
+				DRM_DEBUG_KMS("Determined LVDS native mode details from EDID\n");
 				break;
 			}
 		}
 	}
 	if (!native_mode->clock) {
-		DRM_INFO("No LVDS native mode details, disabling RMX\n");
+		DRM_DEBUG_KMS("No LVDS native mode details, disabling RMX\n");
 		radeon_encoder->rmx_type = RMX_OFF;
 	}
 }
@@ -635,6 +663,11 @@
 				ret = connector_status_connected;
 		}
 	} else {
+
+		/* if we aren't forcing don't do destructive polling */
+		if (!force)
+			return connector->status;
+
 		if (radeon_connector->dac_load_detect && encoder) {
 			encoder_funcs = encoder->helper_private;
 			ret = encoder_funcs->detect(encoder, connector);
@@ -822,6 +855,11 @@
 	if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
 		goto out;
 
+	if (!force) {
+		ret = connector->status;
+		goto out;
+	}
+
 	/* find analog encoder */
 	if (radeon_connector->dac_load_detect) {
 		for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
@@ -970,9 +1008,21 @@
 static int radeon_dp_get_modes(struct drm_connector *connector)
 {
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
 	int ret;
 
+	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		if (!radeon_dig_connector->edp_on)
+			atombios_set_edp_panel_power(connector,
+						     ATOM_TRANSMITTER_ACTION_POWER_ON);
+	}
 	ret = radeon_ddc_get_modes(radeon_connector);
+	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		if (!radeon_dig_connector->edp_on)
+			atombios_set_edp_panel_power(connector,
+						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
+	}
+
 	return ret;
 }
 
@@ -991,8 +1041,14 @@
 	if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
 		/* eDP is always DP */
 		radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+		if (!radeon_dig_connector->edp_on)
+			atombios_set_edp_panel_power(connector,
+						     ATOM_TRANSMITTER_ACTION_POWER_ON);
 		if (radeon_dp_getdpcd(radeon_connector))
 			ret = connector_status_connected;
+		if (!radeon_dig_connector->edp_on)
+			atombios_set_edp_panel_power(connector,
+						     ATOM_TRANSMITTER_ACTION_POWER_OFF);
 	} else {
 		radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
 		if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
@@ -1078,7 +1134,7 @@
 				radeon_connector->shared_ddc = true;
 				shared_ddc = true;
 			}
-			if (radeon_connector->router_bus && router->valid &&
+			if (radeon_connector->router_bus && router->ddc_valid &&
 			    (radeon_connector->router.router_id == router->router_id)) {
 				radeon_connector->shared_ddc = false;
 				shared_ddc = false;
@@ -1098,7 +1154,7 @@
 	radeon_connector->connector_object_id = connector_object_id;
 	radeon_connector->hpd = *hpd;
 	radeon_connector->router = *router;
-	if (router->valid) {
+	if (router->ddc_valid || router->cd_valid) {
 		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
 		if (!radeon_connector->router_bus)
 			goto failed;
@@ -1119,6 +1175,8 @@
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		connector->interlace_allowed = true;
+		connector->doublescan_allowed = true;
 		break;
 	case DRM_MODE_CONNECTOR_DVIA:
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1134,6 +1192,8 @@
 					      1);
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+		connector->interlace_allowed = true;
+		connector->doublescan_allowed = true;
 		break;
 	case DRM_MODE_CONNECTOR_DVII:
 	case DRM_MODE_CONNECTOR_DVID:
@@ -1153,16 +1213,28 @@
 		drm_connector_attach_property(&radeon_connector->base,
 					      rdev->mode_info.coherent_mode_property,
 					      1);
-		if (ASIC_IS_AVIVO(rdev))
+		if (ASIC_IS_AVIVO(rdev)) {
 			drm_connector_attach_property(&radeon_connector->base,
 						      rdev->mode_info.underscan_property,
 						      UNDERSCAN_AUTO);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_hborder_property,
+						      0);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_vborder_property,
+						      0);
+		}
 		if (connector_type == DRM_MODE_CONNECTOR_DVII) {
 			radeon_connector->dac_load_detect = true;
 			drm_connector_attach_property(&radeon_connector->base,
 						      rdev->mode_info.load_detect_property,
 						      1);
 		}
+		connector->interlace_allowed = true;
+		if (connector_type == DRM_MODE_CONNECTOR_DVII)
+			connector->doublescan_allowed = true;
+		else
+			connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_HDMIA:
 	case DRM_MODE_CONNECTOR_HDMIB:
@@ -1181,11 +1253,23 @@
 		drm_connector_attach_property(&radeon_connector->base,
 					      rdev->mode_info.coherent_mode_property,
 					      1);
-		if (ASIC_IS_AVIVO(rdev))
+		if (ASIC_IS_AVIVO(rdev)) {
 			drm_connector_attach_property(&radeon_connector->base,
 						      rdev->mode_info.underscan_property,
 						      UNDERSCAN_AUTO);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_hborder_property,
+						      0);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_vborder_property,
+						      0);
+		}
 		subpixel_order = SubPixelHorizontalRGB;
+		connector->interlace_allowed = true;
+		if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+			connector->doublescan_allowed = true;
+		else
+			connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_DisplayPort:
 	case DRM_MODE_CONNECTOR_eDP:
@@ -1212,10 +1296,20 @@
 		drm_connector_attach_property(&radeon_connector->base,
 					      rdev->mode_info.coherent_mode_property,
 					      1);
-		if (ASIC_IS_AVIVO(rdev))
+		if (ASIC_IS_AVIVO(rdev)) {
 			drm_connector_attach_property(&radeon_connector->base,
 						      rdev->mode_info.underscan_property,
 						      UNDERSCAN_AUTO);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_hborder_property,
+						      0);
+			drm_connector_attach_property(&radeon_connector->base,
+						      rdev->mode_info.underscan_vborder_property,
+						      0);
+		}
+		connector->interlace_allowed = true;
+		/* in theory with a DP to VGA converter... */
+		connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_SVIDEO:
 	case DRM_MODE_CONNECTOR_Composite:
@@ -1231,6 +1325,8 @@
 					      radeon_atombios_get_tv_info(rdev));
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+		connector->interlace_allowed = false;
+		connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_LVDS:
 		radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
@@ -1249,6 +1345,8 @@
 					      dev->mode_config.scaling_mode_property,
 					      DRM_MODE_SCALE_FULLSCREEN);
 		subpixel_order = SubPixelHorizontalRGB;
+		connector->interlace_allowed = false;
+		connector->doublescan_allowed = false;
 		break;
 	}
 
@@ -1326,6 +1424,8 @@
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
 		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+		connector->interlace_allowed = true;
+		connector->doublescan_allowed = true;
 		break;
 	case DRM_MODE_CONNECTOR_DVIA:
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1341,6 +1441,8 @@
 					      1);
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+		connector->interlace_allowed = true;
+		connector->doublescan_allowed = true;
 		break;
 	case DRM_MODE_CONNECTOR_DVII:
 	case DRM_MODE_CONNECTOR_DVID:
@@ -1358,6 +1460,11 @@
 						      1);
 		}
 		subpixel_order = SubPixelHorizontalRGB;
+		connector->interlace_allowed = true;
+		if (connector_type == DRM_MODE_CONNECTOR_DVII)
+			connector->doublescan_allowed = true;
+		else
+			connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_SVIDEO:
 	case DRM_MODE_CONNECTOR_Composite:
@@ -1380,6 +1487,8 @@
 					      radeon_combios_get_tv_info(rdev));
 		/* no HPD on analog connectors */
 		radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+		connector->interlace_allowed = false;
+		connector->doublescan_allowed = false;
 		break;
 	case DRM_MODE_CONNECTOR_LVDS:
 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
@@ -1393,6 +1502,8 @@
 					      dev->mode_config.scaling_mode_property,
 					      DRM_MODE_SCALE_FULLSCREEN);
 		subpixel_order = SubPixelHorizontalRGB;
+		connector->interlace_allowed = false;
+		connector->doublescan_allowed = false;
 		break;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_cs.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_cs.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -268,7 +268,7 @@
 	}
 	r = radeon_ib_schedule(rdev, parser.ib);
 	if (r) {
-		DRM_ERROR("Faild to schedule IB !\n");
+		DRM_ERROR("Failed to schedule IB !\n");
 	}
 	radeon_cs_parser_fini(&parser, r);
 	mutex_unlock(&rdev->cs_mutex);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_cursor.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_cursor.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_cursor.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_cursor.c	2011-01-04 19:50:19.000000000 -0500
@@ -118,22 +118,25 @@
 }
 
 static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
-			      uint32_t gpu_addr)
+			      uint64_t gpu_addr)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct radeon_device *rdev = crtc->dev->dev_private;
 
 	if (ASIC_IS_DCE4(rdev)) {
-		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, 0);
-		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
+		       upper_32_bits(gpu_addr));
+		WREG32(EVERGREEN_CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+		       gpu_addr & 0xffffffff);
 	} else if (ASIC_IS_AVIVO(rdev)) {
 		if (rdev->family >= CHIP_RV770) {
 			if (radeon_crtc->crtc_id)
-				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, 0);
+				WREG32(R700_D2CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
 			else
-				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, 0);
+				WREG32(R700_D1CUR_SURFACE_ADDRESS_HIGH, upper_32_bits(gpu_addr));
 		}
-		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+		WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+		       gpu_addr & 0xffffffff);
 	} else {
 		radeon_crtc->legacy_cursor_offset = gpu_addr - radeon_crtc->legacy_display_base_addr;
 		/* offset is from DISP(2)_BASE_ADDRESS */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_device.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_device.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_device.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_device.c	2011-01-04 19:50:19.000000000 -0500
@@ -117,9 +117,10 @@
 	} else {
 		rdev->scratch.num_reg = 7;
 	}
+	rdev->scratch.reg_base = RADEON_SCRATCH_REG0;
 	for (i = 0; i < rdev->scratch.num_reg; i++) {
 		rdev->scratch.free[i] = true;
-		rdev->scratch.reg[i] = RADEON_SCRATCH_REG0 + (i * 4);
+		rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
 	}
 }
 
@@ -149,6 +150,86 @@
 	}
 }
 
+void radeon_wb_disable(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->wb.wb_obj) {
+		r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+		if (unlikely(r != 0))
+			return;
+		radeon_bo_kunmap(rdev->wb.wb_obj);
+		radeon_bo_unpin(rdev->wb.wb_obj);
+		radeon_bo_unreserve(rdev->wb.wb_obj);
+	}
+	rdev->wb.enabled = false;
+}
+
+void radeon_wb_fini(struct radeon_device *rdev)
+{
+	radeon_wb_disable(rdev);
+	if (rdev->wb.wb_obj) {
+		radeon_bo_unref(&rdev->wb.wb_obj);
+		rdev->wb.wb = NULL;
+		rdev->wb.wb_obj = NULL;
+	}
+}
+
+int radeon_wb_init(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->wb.wb_obj == NULL) {
+		r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
+				RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
+		if (r) {
+			dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
+			return r;
+		}
+	}
+	r = radeon_bo_reserve(rdev->wb.wb_obj, false);
+	if (unlikely(r != 0)) {
+		radeon_wb_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
+			  &rdev->wb.gpu_addr);
+	if (r) {
+		radeon_bo_unreserve(rdev->wb.wb_obj);
+		dev_warn(rdev->dev, "(%d) pin WB bo failed\n", r);
+		radeon_wb_fini(rdev);
+		return r;
+	}
+	r = radeon_bo_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
+	radeon_bo_unreserve(rdev->wb.wb_obj);
+	if (r) {
+		dev_warn(rdev->dev, "(%d) map WB bo failed\n", r);
+		radeon_wb_fini(rdev);
+		return r;
+	}
+
+	/* disable event_write fences */
+	rdev->wb.use_event = false;
+	/* disabled via module param */
+	if (radeon_no_wb == 1)
+		rdev->wb.enabled = false;
+	else {
+		/* often unreliable on AGP */
+		if (rdev->flags & RADEON_IS_AGP) {
+			rdev->wb.enabled = false;
+		} else {
+			rdev->wb.enabled = true;
+			/* event_write fences are only available on r600+ */
+			if (rdev->family >= CHIP_R600)
+				rdev->wb.use_event = true;
+		}
+	}
+
+	dev_info(rdev->dev, "WB %sabled\n", rdev->wb.enabled ? "en" : "dis");
+
+	return 0;
+}
+
 /**
  * radeon_vram_location - try to find VRAM location
  * @rdev: radeon device structure holding all necessary informations
@@ -205,7 +286,7 @@
 		mc->mc_vram_size = mc->aper_size;
 	}
 	mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
-	dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n",
+	dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
 			mc->mc_vram_size >> 20, mc->vram_start,
 			mc->vram_end, mc->real_vram_size >> 20);
 }
@@ -242,7 +323,7 @@
 		mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
 	}
 	mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
-	dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
+	dev_info(rdev->dev, "GTT: %lluM 0x%016llX - 0x%016llX\n",
 			mc->gtt_size >> 20, mc->gtt_start, mc->gtt_end);
 }
 
@@ -829,11 +910,6 @@
 	radeon_pm_resume(rdev);
 	radeon_restore_bios_scratch_regs(rdev);
 
-	/* turn on display hw */
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-	}
-
 	radeon_fbdev_set_suspend(rdev, 0);
 	release_console_sem();
 
@@ -841,6 +917,10 @@
 	radeon_hpd_init(rdev);
 	/* blat the mode back in */
 	drm_helper_resume_force_mode(dev);
+	/* turn on display hw */
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+	}
 	return 0;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_display.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_display.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_display.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_display.c	2011-01-04 19:50:19.000000000 -0500
@@ -315,10 +315,14 @@
 				 radeon_connector->ddc_bus->rec.en_data_reg,
 				 radeon_connector->ddc_bus->rec.y_clk_reg,
 				 radeon_connector->ddc_bus->rec.y_data_reg);
-			if (radeon_connector->router_bus)
+			if (radeon_connector->router.ddc_valid)
 				DRM_INFO("  DDC Router 0x%x/0x%x\n",
-					 radeon_connector->router.mux_control_pin,
-					 radeon_connector->router.mux_state);
+					 radeon_connector->router.ddc_mux_control_pin,
+					 radeon_connector->router.ddc_mux_state);
+			if (radeon_connector->router.cd_valid)
+				DRM_INFO("  Clock/Data Router 0x%x/0x%x\n",
+					 radeon_connector->router.cd_mux_control_pin,
+					 radeon_connector->router.cd_mux_state);
 		} else {
 			if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
 			    connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
@@ -398,8 +402,8 @@
 	int ret = 0;
 
 	/* on hw with routers, select right port */
-	if (radeon_connector->router.valid)
-		radeon_router_select_port(radeon_connector);
+	if (radeon_connector->router.ddc_valid)
+		radeon_router_select_ddc_port(radeon_connector);
 
 	if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
 	    (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
@@ -432,8 +436,8 @@
 	int ret = 0;
 
 	/* on hw with routers, select right port */
-	if (radeon_connector->router.valid)
-		radeon_router_select_port(radeon_connector);
+	if (radeon_connector->router.ddc_valid)
+		radeon_router_select_ddc_port(radeon_connector);
 
 	if (!radeon_connector->ddc_bus)
 		return -1;
@@ -454,13 +458,13 @@
 	return n;
 }
 
-static void radeon_compute_pll_legacy(struct radeon_pll *pll,
-				      uint64_t freq,
-				      uint32_t *dot_clock_p,
-				      uint32_t *fb_div_p,
-				      uint32_t *frac_fb_div_p,
-				      uint32_t *ref_div_p,
-				      uint32_t *post_div_p)
+void radeon_compute_pll(struct radeon_pll *pll,
+			uint64_t freq,
+			uint32_t *dot_clock_p,
+			uint32_t *fb_div_p,
+			uint32_t *frac_fb_div_p,
+			uint32_t *ref_div_p,
+			uint32_t *post_div_p)
 {
 	uint32_t min_ref_div = pll->min_ref_div;
 	uint32_t max_ref_div = pll->max_ref_div;
@@ -513,7 +517,7 @@
 		max_fractional_feed_div = pll->max_frac_feedback_div;
 	}
 
-	for (post_div = min_post_div; post_div <= max_post_div; ++post_div) {
+	for (post_div = max_post_div; post_div >= min_post_div; --post_div) {
 		uint32_t ref_div;
 
 		if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
@@ -631,214 +635,6 @@
 	*post_div_p = best_post_div;
 }
 
-static bool
-calc_fb_div(struct radeon_pll *pll,
-	    uint32_t freq,
-            uint32_t post_div,
-            uint32_t ref_div,
-            uint32_t *fb_div,
-            uint32_t *fb_div_frac)
-{
-	fixed20_12 feedback_divider, a, b;
-	u32 vco_freq;
-
-	vco_freq = freq * post_div;
-	/* feedback_divider = vco_freq * ref_div / pll->reference_freq; */
-	a.full = dfixed_const(pll->reference_freq);
-	feedback_divider.full = dfixed_const(vco_freq);
-	feedback_divider.full = dfixed_div(feedback_divider, a);
-	a.full = dfixed_const(ref_div);
-	feedback_divider.full = dfixed_mul(feedback_divider, a);
-
-	if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
-		/* feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; */
-		a.full = dfixed_const(10);
-		feedback_divider.full = dfixed_mul(feedback_divider, a);
-		feedback_divider.full += dfixed_const_half(0);
-		feedback_divider.full = dfixed_floor(feedback_divider);
-		feedback_divider.full = dfixed_div(feedback_divider, a);
-
-		/* *fb_div = floor(feedback_divider); */
-		a.full = dfixed_floor(feedback_divider);
-		*fb_div = dfixed_trunc(a);
-		/* *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; */
-		a.full = dfixed_const(10);
-		b.full = dfixed_mul(feedback_divider, a);
-
-		feedback_divider.full = dfixed_floor(feedback_divider);
-		feedback_divider.full = dfixed_mul(feedback_divider, a);
-		feedback_divider.full = b.full - feedback_divider.full;
-		*fb_div_frac = dfixed_trunc(feedback_divider);
-	} else {
-		/* *fb_div = floor(feedback_divider + 0.5); */
-		feedback_divider.full += dfixed_const_half(0);
-		feedback_divider.full = dfixed_floor(feedback_divider);
-
-		*fb_div = dfixed_trunc(feedback_divider);
-		*fb_div_frac = 0;
-	}
-
-	if (((*fb_div) < pll->min_feedback_div) || ((*fb_div) > pll->max_feedback_div))
-		return false;
-	else
-		return true;
-}
-
-static bool
-calc_fb_ref_div(struct radeon_pll *pll,
-		uint32_t freq,
-		uint32_t post_div,
-		uint32_t *fb_div,
-                uint32_t *fb_div_frac,
-                uint32_t *ref_div)
-{
-	fixed20_12 ffreq, max_error, error, pll_out, a;
-	u32 vco;
-	u32 pll_out_min, pll_out_max;
-
-	if (pll->flags & RADEON_PLL_IS_LCD) {
-		pll_out_min = pll->lcd_pll_out_min;
-		pll_out_max = pll->lcd_pll_out_max;
-	} else {
-		pll_out_min = pll->pll_out_min;
-		pll_out_max = pll->pll_out_max;
-	}
-
-	ffreq.full = dfixed_const(freq);
-	/* max_error = ffreq * 0.0025; */
-	a.full = dfixed_const(400);
-	max_error.full = dfixed_div(ffreq, a);
-
-	for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) {
-		if (calc_fb_div(pll, freq, post_div, (*ref_div), fb_div, fb_div_frac)) {
-			vco = pll->reference_freq * (((*fb_div) * 10) + (*fb_div_frac));
-			vco = vco / ((*ref_div) * 10);
-
-			if ((vco < pll_out_min) || (vco > pll_out_max))
-				continue;
-
-			/* pll_out = vco / post_div; */
-			a.full = dfixed_const(post_div);
-			pll_out.full = dfixed_const(vco);
-			pll_out.full = dfixed_div(pll_out, a);
-
-			if (pll_out.full >= ffreq.full) {
-				error.full = pll_out.full - ffreq.full;
-				if (error.full <= max_error.full)
-					return true;
-			}
-		}
-	}
-	return false;
-}
-
-static void radeon_compute_pll_new(struct radeon_pll *pll,
-				   uint64_t freq,
-				   uint32_t *dot_clock_p,
-				   uint32_t *fb_div_p,
-				   uint32_t *frac_fb_div_p,
-				   uint32_t *ref_div_p,
-				   uint32_t *post_div_p)
-{
-	u32 fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0;
-	u32 best_freq = 0, vco_frequency;
-	u32 pll_out_min, pll_out_max;
-
-	if (pll->flags & RADEON_PLL_IS_LCD) {
-		pll_out_min = pll->lcd_pll_out_min;
-		pll_out_max = pll->lcd_pll_out_max;
-	} else {
-		pll_out_min = pll->pll_out_min;
-		pll_out_max = pll->pll_out_max;
-	}
-
-	/* freq = freq / 10; */
-	do_div(freq, 10);
-
-	if (pll->flags & RADEON_PLL_USE_POST_DIV) {
-		post_div = pll->post_div;
-		if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div))
-			goto done;
-
-		vco_frequency = freq * post_div;
-		if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
-			goto done;
-
-		if (pll->flags & RADEON_PLL_USE_REF_DIV) {
-			ref_div = pll->reference_div;
-			if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
-				goto done;
-			if (!calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
-				goto done;
-		}
-	} else {
-		for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) {
-			if (pll->flags & RADEON_PLL_LEGACY) {
-				if ((post_div == 5) ||
-				    (post_div == 7) ||
-				    (post_div == 9) ||
-				    (post_div == 10) ||
-				    (post_div == 11))
-					continue;
-			}
-
-			if ((pll->flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
-				continue;
-
-			vco_frequency = freq * post_div;
-			if ((vco_frequency < pll_out_min) || (vco_frequency > pll_out_max))
-				continue;
-			if (pll->flags & RADEON_PLL_USE_REF_DIV) {
-				ref_div = pll->reference_div;
-				if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div))
-					goto done;
-				if (calc_fb_div(pll, freq, post_div, ref_div, &fb_div, &fb_div_frac))
-					break;
-			} else {
-				if (calc_fb_ref_div(pll, freq, post_div, &fb_div, &fb_div_frac, &ref_div))
-					break;
-			}
-		}
-	}
-
-	best_freq = pll->reference_freq * 10 * fb_div;
-	best_freq += pll->reference_freq * fb_div_frac;
-	best_freq = best_freq / (ref_div * post_div);
-
-done:
-	if (best_freq == 0)
-		DRM_ERROR("Couldn't find valid PLL dividers\n");
-
-	*dot_clock_p = best_freq / 10;
-	*fb_div_p = fb_div;
-	*frac_fb_div_p = fb_div_frac;
-	*ref_div_p = ref_div;
-	*post_div_p = post_div;
-
-	DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p);
-}
-
-void radeon_compute_pll(struct radeon_pll *pll,
-			uint64_t freq,
-			uint32_t *dot_clock_p,
-			uint32_t *fb_div_p,
-			uint32_t *frac_fb_div_p,
-			uint32_t *ref_div_p,
-			uint32_t *post_div_p)
-{
-	switch (pll->algo) {
-	case PLL_ALGO_NEW:
-		radeon_compute_pll_new(pll, freq, dot_clock_p, fb_div_p,
-				       frac_fb_div_p, ref_div_p, post_div_p);
-		break;
-	case PLL_ALGO_LEGACY:
-	default:
-		radeon_compute_pll_legacy(pll, freq, dot_clock_p, fb_div_p,
-					  frac_fb_div_p, ref_div_p, post_div_p);
-		break;
-	}
-}
-
 static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
@@ -1002,6 +798,24 @@
 				      radeon_underscan_enum_list[i].name);
 	}
 
+	rdev->mode_info.underscan_hborder_property =
+		drm_property_create(rdev->ddev,
+					DRM_MODE_PROP_RANGE,
+					"underscan hborder", 2);
+	if (!rdev->mode_info.underscan_hborder_property)
+		return -ENOMEM;
+	rdev->mode_info.underscan_hborder_property->values[0] = 0;
+	rdev->mode_info.underscan_hborder_property->values[1] = 128;
+
+	rdev->mode_info.underscan_vborder_property =
+		drm_property_create(rdev->ddev,
+					DRM_MODE_PROP_RANGE,
+					"underscan vborder", 2);
+	if (!rdev->mode_info.underscan_vborder_property)
+		return -ENOMEM;
+	rdev->mode_info.underscan_vborder_property->values[0] = 0;
+	rdev->mode_info.underscan_vborder_property->values[1] = 128;
+
 	return 0;
 }
 
@@ -1159,8 +973,14 @@
 			     ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) &&
 			      drm_detect_hdmi_monitor(radeon_connector->edid) &&
 			      is_hdtv_mode(mode)))) {
-				radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
-				radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
+				if (radeon_encoder->underscan_hborder != 0)
+					radeon_crtc->h_border = radeon_encoder->underscan_hborder;
+				else
+					radeon_crtc->h_border = (mode->hdisplay >> 5) + 16;
+				if (radeon_encoder->underscan_vborder != 0)
+					radeon_crtc->v_border = radeon_encoder->underscan_vborder;
+				else
+					radeon_crtc->v_border = (mode->vdisplay >> 5) + 16;
 				radeon_crtc->rmx_type = RMX_FULL;
 				src_v = crtc->mode.vdisplay;
 				dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2);
@@ -1195,3 +1015,156 @@
 	}
 	return true;
 }
+
+/*
+ * Retrieve current video scanout position of crtc on a given gpu.
+ *
+ * \param rdev Device to query.
+ * \param crtc Crtc to query.
+ * \param *vpos Location where vertical scanout position should be stored.
+ * \param *hpos Location where horizontal scanout position should go.
+ *
+ * Returns vpos as a positive number while in active scanout area.
+ * Returns vpos as a negative number inside vblank, counting the number
+ * of scanlines to go until end of vblank, e.g., -1 means "one scanline
+ * until start of active scanout / end of vblank."
+ *
+ * \return Flags, or'ed together as follows:
+ *
+ * RADEON_SCANOUTPOS_VALID = Query successfull.
+ * RADEON_SCANOUTPOS_INVBL = Inside vblank.
+ * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
+ * this flag means that returned position may be offset by a constant but
+ * unknown small number of scanlines wrt. real scanout position.
+ *
+ */
+int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos)
+{
+	u32 stat_crtc = 0, vbl = 0, position = 0;
+	int vbl_start, vbl_end, vtotal, ret = 0;
+	bool in_vbl = true;
+
+	if (ASIC_IS_DCE4(rdev)) {
+		if (crtc == 0) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC0_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC0_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 1) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC1_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC1_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 2) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC2_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC2_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 3) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC3_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC3_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 4) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC4_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC4_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 5) {
+			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
+				     EVERGREEN_CRTC5_REGISTER_OFFSET);
+			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
+					  EVERGREEN_CRTC5_REGISTER_OFFSET);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+	} else if (ASIC_IS_AVIVO(rdev)) {
+		if (crtc == 0) {
+			vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END);
+			position = RREG32(AVIVO_D1CRTC_STATUS_POSITION);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 1) {
+			vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END);
+			position = RREG32(AVIVO_D2CRTC_STATUS_POSITION);
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+	} else {
+		/* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */
+		if (crtc == 0) {
+			/* Assume vbl_end == 0, get vbl_start from
+			 * upper 16 bits.
+			 */
+			vbl = (RREG32(RADEON_CRTC_V_TOTAL_DISP) &
+				RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+			/* Only retrieve vpos from upper 16 bits, set hpos == 0. */
+			position = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+			stat_crtc = RREG32(RADEON_CRTC_STATUS);
+			if (!(stat_crtc & 1))
+				in_vbl = false;
+
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+		if (crtc == 1) {
+			vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) &
+				RADEON_CRTC_V_DISP) >> RADEON_CRTC_V_DISP_SHIFT;
+			position = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL;
+			stat_crtc = RREG32(RADEON_CRTC2_STATUS);
+			if (!(stat_crtc & 1))
+				in_vbl = false;
+
+			ret |= RADEON_SCANOUTPOS_VALID;
+		}
+	}
+
+	/* Decode into vertical and horizontal scanout position. */
+	*vpos = position & 0x1fff;
+	*hpos = (position >> 16) & 0x1fff;
+
+	/* Valid vblank area boundaries from gpu retrieved? */
+	if (vbl > 0) {
+		/* Yes: Decode. */
+		ret |= RADEON_SCANOUTPOS_ACCURATE;
+		vbl_start = vbl & 0x1fff;
+		vbl_end = (vbl >> 16) & 0x1fff;
+	}
+	else {
+		/* No: Fake something reasonable which gives at least ok results. */
+		vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay;
+		vbl_end = 0;
+	}
+
+	/* Test scanout position against vblank region. */
+	if ((*vpos < vbl_start) && (*vpos >= vbl_end))
+		in_vbl = false;
+
+	/* Check if inside vblank area and apply corrective offsets:
+	 * vpos will then be >=0 in video scanout area, but negative
+	 * within vblank area, counting down the number of lines until
+	 * start of scanout.
+	 */
+
+	/* Inside "upper part" of vblank area? Apply corrective offset if so: */
+	if (in_vbl && (*vpos >= vbl_start)) {
+		vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal;
+		*vpos = *vpos - vtotal;
+	}
+
+	/* Correct for shifted end of vbl at vbl_end. */
+	*vpos = *vpos - vbl_end;
+
+	/* In vblank? */
+	if (in_vbl)
+		ret |= RADEON_SCANOUTPOS_INVBL;
+
+	return ret;
+}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -47,9 +47,10 @@
  * - 2.4.0 - add crtc id query
  * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen
  * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500)
+ *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
  */
 #define KMS_DRIVER_MAJOR	2
-#define KMS_DRIVER_MINOR	6
+#define KMS_DRIVER_MINOR	7
 #define KMS_DRIVER_PATCHLEVEL	0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -93,7 +94,6 @@
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
-int radeon_new_pll = -1;
 int radeon_audio = 1;
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
@@ -131,9 +131,6 @@
 MODULE_PARM_DESC(tv, "TV enable (0 = disable)");
 module_param_named(tv, radeon_tv, int, 0444);
 
-MODULE_PARM_DESC(new_pll, "Select new PLL code");
-module_param_named(new_pll, radeon_new_pll, int, 0444);
-
 MODULE_PARM_DESC(audio, "Audio enable (0 = disable)");
 module_param_named(audio, radeon_audio, int, 0444);
 
@@ -203,8 +200,6 @@
 	.irq_uninstall = radeon_driver_irq_uninstall,
 	.irq_handler = radeon_driver_irq_handler,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = radeon_ioctls,
 	.dma_ioctl = radeon_cp_buffers,
 	.fops = {
@@ -219,6 +214,7 @@
 #ifdef CONFIG_COMPAT
 		 .compat_ioctl = radeon_compat_ioctl,
 #endif
+		 .llseek = noop_llseek,
 	},
 
 	.pci_driver = {
@@ -236,9 +232,28 @@
 
 static struct drm_driver kms_driver;
 
+static void radeon_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+	struct apertures_struct *ap;
+	bool primary = false;
+
+	ap = alloc_apertures(1);
+	ap->ranges[0].base = pci_resource_start(pdev, 0);
+	ap->ranges[0].size = pci_resource_len(pdev, 0);
+
+#ifdef CONFIG_X86
+	primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
+#endif
+	remove_conflicting_framebuffers(ap, "radeondrmfb", primary);
+	kfree(ap);
+}
+
 static int __devinit
 radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
+	/* Get rid of things like offb */
+	radeon_kick_out_firmware_fb(pdev);
+
 	return drm_get_pci_dev(pdev, ent, &kms_driver);
 }
 
@@ -290,8 +305,6 @@
 	.irq_uninstall = radeon_driver_irq_uninstall_kms,
 	.irq_handler = radeon_driver_irq_handler_kms,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = radeon_ioctls_kms,
 	.gem_init_object = radeon_gem_object_init,
 	.gem_free_object = radeon_gem_object_free,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_encoders.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_encoders.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_encoders.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_encoders.c	2011-01-04 19:50:19.000000000 -0500
@@ -176,6 +176,7 @@
 		return false;
 	}
 }
+
 void
 radeon_link_encoder_connector(struct drm_device *dev)
 {
@@ -228,6 +229,27 @@
 	return NULL;
 }
 
+struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_encoder *other_encoder;
+	struct radeon_encoder *other_radeon_encoder;
+
+	if (radeon_encoder->is_ext_encoder)
+		return NULL;
+
+	list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+		if (other_encoder == encoder)
+			continue;
+		other_radeon_encoder = to_radeon_encoder(other_encoder);
+		if (other_radeon_encoder->is_ext_encoder &&
+		    (radeon_encoder->devices & other_radeon_encoder->devices))
+			return other_encoder;
+	}
+	return NULL;
+}
+
 void radeon_panel_mode_fixup(struct drm_encoder *encoder,
 			     struct drm_display_mode *adjusted_mode)
 {
@@ -426,52 +448,49 @@
 
 }
 
+union dvo_encoder_control {
+	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
+	DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
+	DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
+};
+
 void
-atombios_external_tmds_setup(struct drm_encoder *encoder, int action)
+atombios_dvo_setup(struct drm_encoder *encoder, int action)
 {
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args;
-	int index = 0;
+	union dvo_encoder_control args;
+	int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
 
 	memset(&args, 0, sizeof(args));
 
-	index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
-
-	args.sXTmdsEncoder.ucEnable = action;
-
-	if (radeon_encoder->pixel_clock > 165000)
-		args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
-
-	/*if (pScrn->rgbBits == 8)*/
-	args.sXTmdsEncoder.ucMisc |= (1 << 1);
-
-	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-}
-
-static void
-atombios_ddia_setup(struct drm_encoder *encoder, int action)
-{
-	struct drm_device *dev = encoder->dev;
-	struct radeon_device *rdev = dev->dev_private;
-	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-	DVO_ENCODER_CONTROL_PS_ALLOCATION args;
-	int index = 0;
-
-	memset(&args, 0, sizeof(args));
+	if (ASIC_IS_DCE3(rdev)) {
+		/* DCE3+ */
+		args.dvo_v3.ucAction = action;
+		args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+		args.dvo_v3.ucDVOConfig = 0; /* XXX */
+	} else if (ASIC_IS_DCE2(rdev)) {
+		/* DCE2 (pre-DCE3 R6xx, RS600/690/740 */
+		args.dvo.sDVOEncoder.ucAction = action;
+		args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+		/* DFP1, CRT1, TV1 depending on the type of port */
+		args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
 
-	index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+		if (radeon_encoder->pixel_clock > 165000)
+			args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
+	} else {
+		/* R4xx, R5xx */
+		args.ext_tmds.sXTmdsEncoder.ucEnable = action;
 
-	args.sDVOEncoder.ucAction = action;
-	args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+		if (radeon_encoder->pixel_clock > 165000)
+			args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
 
-	if (radeon_encoder->pixel_clock > 165000)
-		args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
+		/*if (pScrn->rgbBits == 8)*/
+		args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
+	}
 
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
 }
 
 union lvds_encoder_control {
@@ -529,17 +548,17 @@
 				args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
 			args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-				if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+				if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
 					args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-				if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
-					args.v1.ucMisc |= (1 << 1);
+				if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
+					args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
 			} else {
 				if (dig->linkb)
 					args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
 				if (radeon_encoder->pixel_clock > 165000)
 					args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
 				/*if (pScrn->rgbBits == 8) */
-				args.v1.ucMisc |= (1 << 1);
+				args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
 			}
 			break;
 		case 2:
@@ -558,18 +577,18 @@
 			args.v2.ucTemporal = 0;
 			args.v2.ucFRC = 0;
 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-				if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
+				if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
 					args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-				if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) {
+				if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) {
 					args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
-					if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+					if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
 						args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
 				}
-				if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) {
+				if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) {
 					args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
-					if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
+					if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
 						args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
-					if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
+					if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
 						args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
 				}
 			} else {
@@ -595,6 +614,7 @@
 int
 atombios_get_encoder_mode(struct drm_encoder *encoder)
 {
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_connector *connector;
@@ -602,9 +622,20 @@
 	struct radeon_connector_atom_dig *dig_connector;
 
 	connector = radeon_get_connector_for_encoder(encoder);
-	if (!connector)
-		return 0;
-
+	if (!connector) {
+		switch (radeon_encoder->encoder_id) {
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+			return ATOM_ENCODER_MODE_DVI;
+		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+		default:
+			return ATOM_ENCODER_MODE_CRT;
+		}
+	}
 	radeon_connector = to_radeon_connector(connector);
 
 	switch (connector->connector_type) {
@@ -834,6 +865,9 @@
 	memset(&args, 0, sizeof(args));
 
 	switch (radeon_encoder->encoder_id) {
+	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+		index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+		break;
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
@@ -978,6 +1012,105 @@
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+void
+atombios_set_edp_panel_power(struct drm_connector *connector, int action)
+{
+	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+	struct drm_device *dev = radeon_connector->base.dev;
+	struct radeon_device *rdev = dev->dev_private;
+	union dig_transmitter_control args;
+	int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+	uint8_t frev, crev;
+
+	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+		return;
+
+	if (!ASIC_IS_DCE4(rdev))
+		return;
+
+	if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+	    (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
+		return;
+
+	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+		return;
+
+	memset(&args, 0, sizeof(args));
+
+	args.v1.ucAction = action;
+
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+union external_encoder_control {
+	EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+};
+
+static void
+atombios_external_encoder_setup(struct drm_encoder *encoder,
+				struct drm_encoder *ext_encoder,
+				int action)
+{
+	struct drm_device *dev = encoder->dev;
+	struct radeon_device *rdev = dev->dev_private;
+	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	union external_encoder_control args;
+	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+	int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
+	u8 frev, crev;
+	int dp_clock = 0;
+	int dp_lane_count = 0;
+	int connector_object_id = 0;
+
+	if (connector) {
+		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		struct radeon_connector_atom_dig *dig_connector =
+			radeon_connector->con_priv;
+
+		dp_clock = dig_connector->dp_clock;
+		dp_lane_count = dig_connector->dp_lane_count;
+		connector_object_id =
+			(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+	}
+
+	memset(&args, 0, sizeof(args));
+
+	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+		return;
+
+	switch (frev) {
+	case 1:
+		/* no params on frev 1 */
+		break;
+	case 2:
+		switch (crev) {
+		case 1:
+		case 2:
+			args.v1.sDigEncoder.ucAction = action;
+			args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+			args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+			if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+				if (dp_clock == 270000)
+					args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+				args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
+			} else if (radeon_encoder->pixel_clock > 165000)
+				args.v1.sDigEncoder.ucLaneNum = 8;
+			else
+				args.v1.sDigEncoder.ucLaneNum = 4;
+			break;
+		default:
+			DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+			return;
+		}
+		break;
+	default:
+		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+		return;
+	}
+	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
 static void
 atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
 {
@@ -1021,6 +1154,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
 	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
 	int index = 0;
 	bool is_dig = false;
@@ -1043,9 +1177,14 @@
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
-	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
 		index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
 		break;
+	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+		if (ASIC_IS_DCE3(rdev))
+			is_dig = true;
+		else
+			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+		break;
 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
 		index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
 		break;
@@ -1082,34 +1221,85 @@
 			if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
 				struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
+				if (connector &&
+				    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+					struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+					struct radeon_connector_atom_dig *radeon_dig_connector =
+						radeon_connector->con_priv;
+					atombios_set_edp_panel_power(connector,
+								     ATOM_TRANSMITTER_ACTION_POWER_ON);
+					radeon_dig_connector->edp_on = true;
+				}
 				dp_link_train(encoder, connector);
 				if (ASIC_IS_DCE4(rdev))
 					atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
 			}
+			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
 			break;
 		case DRM_MODE_DPMS_STANDBY:
 		case DRM_MODE_DPMS_SUSPEND:
 		case DRM_MODE_DPMS_OFF:
 			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0);
 			if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) {
+				struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+
 				if (ASIC_IS_DCE4(rdev))
 					atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+				if (connector &&
+				    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
+					struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+					struct radeon_connector_atom_dig *radeon_dig_connector =
+						radeon_connector->con_priv;
+					atombios_set_edp_panel_power(connector,
+								     ATOM_TRANSMITTER_ACTION_POWER_OFF);
+					radeon_dig_connector->edp_on = false;
+				}
 			}
+			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
 			break;
 		}
 	} else {
 		switch (mode) {
 		case DRM_MODE_DPMS_ON:
 			args.ucAction = ATOM_ENABLE;
+			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+				args.ucAction = ATOM_LCD_BLON;
+				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+			}
 			break;
 		case DRM_MODE_DPMS_STANDBY:
 		case DRM_MODE_DPMS_SUSPEND:
 		case DRM_MODE_DPMS_OFF:
 			args.ucAction = ATOM_DISABLE;
+			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+				args.ucAction = ATOM_LCD_BLOFF;
+				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+			}
 			break;
 		}
-		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 	}
+
+	if (ext_encoder) {
+		int action;
+
+		switch (mode) {
+		case DRM_MODE_DPMS_ON:
+		default:
+			action = ATOM_ENABLE;
+			break;
+		case DRM_MODE_DPMS_STANDBY:
+		case DRM_MODE_DPMS_SUSPEND:
+		case DRM_MODE_DPMS_OFF:
+			action = ATOM_DISABLE;
+			break;
+		}
+		atombios_external_encoder_setup(encoder, ext_encoder, action);
+	}
+
 	radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
 
 }
@@ -1242,7 +1432,7 @@
 		break;
 	default:
 		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
-		break;
+		return;
 	}
 
 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
@@ -1357,6 +1547,7 @@
 	struct drm_device *dev = encoder->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
 
 	radeon_encoder->pixel_clock = adjusted_mode->clock;
 
@@ -1400,11 +1591,9 @@
 		}
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
-		atombios_ddia_setup(encoder, ATOM_ENABLE);
-		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-		atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+		atombios_dvo_setup(encoder, ATOM_ENABLE);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1419,6 +1608,11 @@
 		}
 		break;
 	}
+
+	if (ext_encoder) {
+		atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
+	}
+
 	atombios_apply_encoder_quirks(encoder, adjusted_mode);
 
 	if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
@@ -1520,6 +1714,7 @@
 static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
 {
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
 	if (radeon_encoder->active_device &
 	    (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
@@ -1531,6 +1726,13 @@
 	radeon_atom_output_lock(encoder, true);
 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
+	/* select the clock/data port if it uses a router */
+	if (connector) {
+		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+		if (radeon_connector->router.cd_valid)
+			radeon_router_select_cd_port(radeon_connector);
+	}
+
 	/* this is needed for the pll/ss setup to work correctly in some cases */
 	atombios_set_encoder_crtc_source(encoder);
 }
@@ -1547,6 +1749,23 @@
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig;
+
+	/* check for pre-DCE3 cards with shared encoders;
+	 * can't really use the links individually, so don't disable
+	 * the encoder if it's in use by another connector
+	 */
+	if (!ASIC_IS_DCE3(rdev)) {
+		struct drm_encoder *other_encoder;
+		struct radeon_encoder *other_radeon_encoder;
+
+		list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
+			other_radeon_encoder = to_radeon_encoder(other_encoder);
+			if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) &&
+			    drm_helper_encoder_in_use(other_encoder))
+				goto disable_done;
+		}
+	}
+
 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
 	switch (radeon_encoder->encoder_id) {
@@ -1570,11 +1789,9 @@
 		}
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
-		atombios_ddia_setup(encoder, ATOM_DISABLE);
-		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-		atombios_external_tmds_setup(encoder, ATOM_DISABLE);
+		atombios_dvo_setup(encoder, ATOM_DISABLE);
 		break;
 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1586,6 +1803,7 @@
 		break;
 	}
 
+disable_done:
 	if (radeon_encoder_is_digital(encoder)) {
 		if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
 			r600_hdmi_disable(encoder);
@@ -1595,6 +1813,53 @@
 	radeon_encoder->active_device = 0;
 }
 
+/* these are handled by the primary encoders */
+static void radeon_atom_ext_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void radeon_atom_ext_commit(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_mode_set(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void radeon_atom_ext_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static void
+radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
+	.dpms = radeon_atom_ext_dpms,
+	.mode_fixup = radeon_atom_ext_mode_fixup,
+	.prepare = radeon_atom_ext_prepare,
+	.mode_set = radeon_atom_ext_mode_set,
+	.commit = radeon_atom_ext_commit,
+	.disable = radeon_atom_ext_disable,
+	/* no detect for TMDS/LVDS yet */
+};
+
 static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
 	.dpms = radeon_atom_encoder_dpms,
 	.mode_fixup = radeon_atom_mode_fixup,
@@ -1704,6 +1969,7 @@
 	radeon_encoder->devices = supported_device;
 	radeon_encoder->rmx_type = RMX_OFF;
 	radeon_encoder->underscan_type = UNDERSCAN_OFF;
+	radeon_encoder->is_ext_encoder = false;
 
 	switch (radeon_encoder->encoder_id) {
 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
@@ -1745,6 +2011,9 @@
 			radeon_encoder->rmx_type = RMX_FULL;
 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
 			radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+		} else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+			radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
 		} else {
 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
 			radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
@@ -1753,5 +2022,22 @@
 		}
 		drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
 		break;
+	case ENCODER_OBJECT_ID_SI170B:
+	case ENCODER_OBJECT_ID_CH7303:
+	case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
+	case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
+	case ENCODER_OBJECT_ID_TITFP513:
+	case ENCODER_OBJECT_ID_VT1623:
+	case ENCODER_OBJECT_ID_HDMI_SI1930:
+		/* these are handled by the primary encoders */
+		radeon_encoder->is_ext_encoder = true;
+		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+		else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+		else
+			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+		drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
+		break;
 	}
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_fb.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_fb.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_fb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_fb.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,6 +59,8 @@
 	.fb_pan_display = drm_fb_helper_pan_display,
 	.fb_blank = drm_fb_helper_blank,
 	.fb_setcmap = drm_fb_helper_setcmap,
+	.fb_debug_enter = drm_fb_helper_debug_enter,
+	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
 
@@ -243,7 +245,7 @@
 		goto out_unref;
 	}
 	info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
-	info->apertures->ranges[0].size = rdev->mc.real_vram_size;
+	info->apertures->ranges[0].size = rdev->mc.aper_size;
 
 	info->fix.mmio_start = 0;
 	info->fix.mmio_len = 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_fence.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_fence.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_fence.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_fence.c	2011-01-04 19:50:19.000000000 -0500
@@ -72,7 +72,15 @@
 	bool wake = false;
 	unsigned long cjiffies;
 
-	seq = RREG32(rdev->fence_drv.scratch_reg);
+	if (rdev->wb.enabled) {
+		u32 scratch_index;
+		if (rdev->wb.use_event)
+			scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+		else
+			scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base;
+		seq = rdev->wb.wb[scratch_index/4];
+	} else
+		seq = RREG32(rdev->fence_drv.scratch_reg);
 	if (seq != rdev->fence_drv.last_seq) {
 		rdev->fence_drv.last_seq = seq;
 		rdev->fence_drv.last_jiffies = jiffies;
@@ -232,7 +240,8 @@
 		 */
 		if (seq == rdev->fence_drv.last_seq && radeon_gpu_is_lockup(rdev)) {
 			/* good news we believe it's a lockup */
-			WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n", fence->seq, seq);
+			WARN(1, "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n",
+			     fence->seq, seq);
 			/* FIXME: what should we do ? marking everyone
 			 * as signaled for now
 			 */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_gart.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_gart.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_gart.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_gart.c	2011-01-04 19:50:19.000000000 -0500
@@ -79,8 +79,8 @@
 
 	if (rdev->gart.table.vram.robj == NULL) {
 		r = radeon_bo_create(rdev, NULL, rdev->gart.table_size,
-					true, RADEON_GEM_DOMAIN_VRAM,
-					&rdev->gart.table.vram.robj);
+				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+				     &rdev->gart.table.vram.robj);
 		if (r) {
 			return r;
 		}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_gem.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_gem.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_gem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_gem.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,7 +67,7 @@
 	if (alignment < PAGE_SIZE) {
 		alignment = PAGE_SIZE;
 	}
-	r = radeon_bo_create(rdev, gobj, size, kernel, initial_domain, &robj);
+	r = radeon_bo_create(rdev, gobj, size, alignment, kernel, initial_domain, &robj);
 	if (r) {
 		if (r != -ERESTARTSYS)
 			DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon.h	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,6 @@
 extern int radeon_testing;
 extern int radeon_connector_table;
 extern int radeon_tv;
-extern int radeon_new_pll;
 extern int radeon_audio;
 extern int radeon_disp_priority;
 extern int radeon_hw_i2c;
@@ -366,6 +365,7 @@
  */
 struct radeon_scratch {
 	unsigned		num_reg;
+	uint32_t                reg_base;
 	bool			free[32];
 	uint32_t		reg[32];
 };
@@ -594,8 +594,15 @@
 	struct radeon_bo	*wb_obj;
 	volatile uint32_t	*wb;
 	uint64_t		gpu_addr;
+	bool                    enabled;
+	bool                    use_event;
 };
 
+#define RADEON_WB_SCRATCH_OFFSET 0
+#define RADEON_WB_CP_RPTR_OFFSET 1024
+#define R600_WB_IH_WPTR_OFFSET   2048
+#define R600_WB_EVENT_OFFSET     3072
+
 /**
  * struct radeon_pm - power management datas
  * @max_bandwidth:      maximum bandwidth the gpu has (MByte/s)
@@ -1124,6 +1131,12 @@
 void r600_kms_blit_copy(struct radeon_device *rdev,
 			u64 src_gpu_addr, u64 dst_gpu_addr,
 			int size_bytes);
+/* evergreen blit */
+int evergreen_blit_prepare_copy(struct radeon_device *rdev, int size_bytes);
+void evergreen_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence);
+void evergreen_kms_blit_copy(struct radeon_device *rdev,
+			     u64 src_gpu_addr, u64 dst_gpu_addr,
+			     int size_bytes);
 
 static inline uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
 {
@@ -1249,6 +1262,10 @@
 		(rdev->family == CHIP_RS400) ||			\
 		(rdev->family == CHIP_RS480))
 #define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
+#define ASIC_IS_DCE2(rdev) ((rdev->family == CHIP_RS600)  ||	\
+			    (rdev->family == CHIP_RS690)  ||	\
+			    (rdev->family == CHIP_RS740)  ||	\
+			    (rdev->family >= CHIP_R600))
 #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
 #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
 #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR))
@@ -1341,6 +1358,9 @@
 extern void radeon_update_display_priority(struct radeon_device *rdev);
 extern bool radeon_boot_test_post_card(struct radeon_device *rdev);
 extern void radeon_scratch_init(struct radeon_device *rdev);
+extern void radeon_wb_fini(struct radeon_device *rdev);
+extern int radeon_wb_init(struct radeon_device *rdev);
+extern void radeon_wb_disable(struct radeon_device *rdev);
 extern void radeon_surface_init(struct radeon_device *rdev);
 extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
 extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
@@ -1425,9 +1445,6 @@
 extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
 extern int r600_ib_test(struct radeon_device *rdev);
 extern int r600_ring_test(struct radeon_device *rdev);
-extern void r600_wb_fini(struct radeon_device *rdev);
-extern int r600_wb_enable(struct radeon_device *rdev);
-extern void r600_wb_disable(struct radeon_device *rdev);
 extern void r600_scratch_init(struct radeon_device *rdev);
 extern int r600_blit_init(struct radeon_device *rdev);
 extern void r600_blit_fini(struct radeon_device *rdev);
@@ -1465,6 +1482,8 @@
 extern void r700_cp_fini(struct radeon_device *rdev);
 extern void evergreen_disable_interrupt_state(struct radeon_device *rdev);
 extern int evergreen_irq_set(struct radeon_device *rdev);
+extern int evergreen_blit_init(struct radeon_device *rdev);
+extern void evergreen_blit_fini(struct radeon_device *rdev);
 
 /* radeon_acpi.c */ 
 #if defined(CONFIG_ACPI) 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_i2c.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_i2c.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -53,8 +53,8 @@
 	};
 
 	/* on hw with routers, select right port */
-	if (radeon_connector->router.valid)
-		radeon_router_select_port(radeon_connector);
+	if (radeon_connector->router.ddc_valid)
+		radeon_router_select_ddc_port(radeon_connector);
 
 	ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
 	if (ret == 2)
@@ -896,7 +896,8 @@
 	     ((rdev->family <= CHIP_RS480) ||
 	      ((rdev->family >= CHIP_RV515) && (rdev->family <= CHIP_R580))))) {
 		/* set the radeon hw i2c adapter */
-		sprintf(i2c->adapter.name, "Radeon i2c hw bus %s", name);
+		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+			 "Radeon i2c hw bus %s", name);
 		i2c->adapter.algo = &radeon_i2c_algo;
 		ret = i2c_add_adapter(&i2c->adapter);
 		if (ret) {
@@ -905,7 +906,8 @@
 		}
 	} else {
 		/* set the radeon bit adapter */
-		sprintf(i2c->adapter.name, "Radeon i2c bit bus %s", name);
+		snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+			 "Radeon i2c bit bus %s", name);
 		i2c->adapter.algo_data = &i2c->algo.bit;
 		i2c->algo.bit.pre_xfer = pre_xfer;
 		i2c->algo.bit.post_xfer = post_xfer;
@@ -946,6 +948,8 @@
 	i2c->rec = *rec;
 	i2c->adapter.owner = THIS_MODULE;
 	i2c->dev = dev;
+	snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+		 "Radeon aux bus %s", name);
 	i2c_set_adapdata(&i2c->adapter, i2c);
 	i2c->adapter.algo_data = &i2c->algo.dp;
 	i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch;
@@ -1084,26 +1088,51 @@
 			  addr, val);
 }
 
-/* router switching */
-void radeon_router_select_port(struct radeon_connector *radeon_connector)
+/* ddc router switching */
+void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector)
 {
 	u8 val;
 
-	if (!radeon_connector->router.valid)
+	if (!radeon_connector->router.ddc_valid)
 		return;
 
 	radeon_i2c_get_byte(radeon_connector->router_bus,
 			    radeon_connector->router.i2c_addr,
 			    0x3, &val);
-	val &= radeon_connector->router.mux_control_pin;
+	val &= ~radeon_connector->router.ddc_mux_control_pin;
 	radeon_i2c_put_byte(radeon_connector->router_bus,
 			    radeon_connector->router.i2c_addr,
 			    0x3, val);
 	radeon_i2c_get_byte(radeon_connector->router_bus,
 			    radeon_connector->router.i2c_addr,
 			    0x1, &val);
-	val &= radeon_connector->router.mux_control_pin;
-	val |= radeon_connector->router.mux_state;
+	val &= ~radeon_connector->router.ddc_mux_control_pin;
+	val |= radeon_connector->router.ddc_mux_state;
+	radeon_i2c_put_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x1, val);
+}
+
+/* clock/data router switching */
+void radeon_router_select_cd_port(struct radeon_connector *radeon_connector)
+{
+	u8 val;
+
+	if (!radeon_connector->router.cd_valid)
+		return;
+
+	radeon_i2c_get_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x3, &val);
+	val &= ~radeon_connector->router.cd_mux_control_pin;
+	radeon_i2c_put_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x3, val);
+	radeon_i2c_get_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x1, &val);
+	val &= ~radeon_connector->router.cd_mux_control_pin;
+	val |= radeon_connector->router.cd_mux_state;
 	radeon_i2c_put_byte(radeon_connector->router_bus,
 			    radeon_connector->router.i2c_addr,
 			    0x1, val);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_irq.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_irq.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_irq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_irq.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,7 +76,7 @@
 		default:
 			DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 				  crtc);
-			return EINVAL;
+			return -EINVAL;
 		}
 	} else {
 		switch (crtc) {
@@ -89,7 +89,7 @@
 		default:
 			DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
 				  crtc);
-			return EINVAL;
+			return -EINVAL;
 		}
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_legacy_crtc.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_legacy_crtc.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_legacy_crtc.c	2011-01-04 19:50:19.000000000 -0500
@@ -348,10 +348,25 @@
 int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 			 struct drm_framebuffer *old_fb)
 {
+	return radeon_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+				struct drm_framebuffer *fb,
+				int x, int y, enum mode_set_atomic state)
+{
+	return radeon_crtc_do_set_base(crtc, fb, x, y, 1);
+}
+
+int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+			 struct drm_framebuffer *fb,
+			 int x, int y, int atomic)
+{
 	struct drm_device *dev = crtc->dev;
 	struct radeon_device *rdev = dev->dev_private;
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
 	struct radeon_framebuffer *radeon_fb;
+	struct drm_framebuffer *target_fb;
 	struct drm_gem_object *obj;
 	struct radeon_bo *rbo;
 	uint64_t base;
@@ -364,14 +379,21 @@
 
 	DRM_DEBUG_KMS("\n");
 	/* no fb bound */
-	if (!crtc->fb) {
+	if (!atomic && !crtc->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
 	}
 
-	radeon_fb = to_radeon_framebuffer(crtc->fb);
+	if (atomic) {
+		radeon_fb = to_radeon_framebuffer(fb);
+		target_fb = fb;
+	}
+	else {
+		radeon_fb = to_radeon_framebuffer(crtc->fb);
+		target_fb = crtc->fb;
+	}
 
-	switch (crtc->fb->bits_per_pixel) {
+	switch (target_fb->bits_per_pixel) {
 	case 8:
 		format = 2;
 		break;
@@ -415,10 +437,10 @@
 
 	crtc_offset_cntl = 0;
 
-	pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
-	crtc_pitch  = (((pitch_pixels * crtc->fb->bits_per_pixel) +
-			((crtc->fb->bits_per_pixel * 8) - 1)) /
-		       (crtc->fb->bits_per_pixel * 8));
+	pitch_pixels = target_fb->pitch / (target_fb->bits_per_pixel / 8);
+	crtc_pitch  = (((pitch_pixels * target_fb->bits_per_pixel) +
+			((target_fb->bits_per_pixel * 8) - 1)) /
+		       (target_fb->bits_per_pixel * 8));
 	crtc_pitch |= crtc_pitch << 16;
 
 
@@ -443,14 +465,14 @@
 			crtc_tile_x0_y0 = x | (y << 16);
 			base &= ~0x7ff;
 		} else {
-			int byteshift = crtc->fb->bits_per_pixel >> 4;
+			int byteshift = target_fb->bits_per_pixel >> 4;
 			int tile_addr = (((y >> 3) * pitch_pixels +  x) >> (8 - byteshift)) << 11;
 			base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
 			crtc_offset_cntl |= (y % 16);
 		}
 	} else {
 		int offset = y * pitch_pixels + x;
-		switch (crtc->fb->bits_per_pixel) {
+		switch (target_fb->bits_per_pixel) {
 		case 8:
 			offset *= 1;
 			break;
@@ -496,8 +518,8 @@
 	WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
 	WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
 
-	if (old_fb && old_fb != crtc->fb) {
-		radeon_fb = to_radeon_framebuffer(old_fb);
+	if (!atomic && fb && fb != crtc->fb) {
+		radeon_fb = to_radeon_framebuffer(fb);
 		rbo = radeon_fb->obj->driver_private;
 		r = radeon_bo_reserve(rbo, false);
 		if (unlikely(r != 0))
@@ -717,10 +739,6 @@
 		pll = &rdev->clock.p1pll;
 
 	pll->flags = RADEON_PLL_LEGACY;
-	if (radeon_new_pll == 1)
-		pll->algo = PLL_ALGO_NEW;
-	else
-		pll->algo = PLL_ALGO_LEGACY;
 
 	if (mode->clock > 200000) /* range limits??? */
 		pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
@@ -1040,6 +1058,7 @@
 	.mode_fixup = radeon_crtc_mode_fixup,
 	.mode_set = radeon_crtc_mode_set,
 	.mode_set_base = radeon_crtc_set_base,
+	.mode_set_base_atomic = radeon_crtc_set_base_atomic,
 	.prepare = radeon_crtc_prepare,
 	.commit = radeon_crtc_commit,
 	.load_lut = radeon_crtc_load_lut,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_legacy_encoders.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_legacy_encoders.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_legacy_encoders.c	2011-01-04 19:50:19.000000000 -0500
@@ -670,7 +670,7 @@
 
 	if (rdev->is_atom_bios) {
 		radeon_encoder->pixel_clock = adjusted_mode->clock;
-		atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+		atombios_dvo_setup(encoder, ATOM_ENABLE);
 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
 	} else {
 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_mode.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_mode.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_mode.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_mode.h	2011-01-04 19:50:19.000000000 -0500
@@ -35,8 +35,8 @@
 #include <drm_edid.h>
 #include <drm_dp_helper.h>
 #include <drm_fixed.h>
+#include <drm_crtc_helper.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 
 struct radeon_bo;
@@ -150,12 +150,6 @@
 #define RADEON_PLL_USE_POST_DIV         (1 << 12)
 #define RADEON_PLL_IS_LCD               (1 << 13)
 
-/* pll algo */
-enum radeon_pll_algo {
-	PLL_ALGO_LEGACY,
-	PLL_ALGO_NEW
-};
-
 struct radeon_pll {
 	/* reference frequency */
 	uint32_t reference_freq;
@@ -188,8 +182,6 @@
 
 	/* pll id */
 	uint32_t id;
-	/* pll algo */
-	enum radeon_pll_algo algo;
 };
 
 struct radeon_i2c_chan {
@@ -241,6 +233,8 @@
 	struct drm_property *tmds_pll_property;
 	/* underscan */
 	struct drm_property *underscan_property;
+	struct drm_property *underscan_hborder_property;
+	struct drm_property *underscan_vborder_property;
 	/* hardcoded DFP edid from BIOS */
 	struct edid *bios_hardcoded_edid;
 
@@ -336,22 +330,24 @@
 struct radeon_atom_ss {
 	uint16_t percentage;
 	uint8_t type;
-	uint8_t step;
+	uint16_t step;
 	uint8_t delay;
 	uint8_t range;
 	uint8_t refdiv;
+	/* asic_ss */
+	uint16_t rate;
+	uint16_t amount;
 };
 
 struct radeon_encoder_atom_dig {
 	bool linkb;
 	/* atom dig */
 	bool coherent_mode;
-	int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB */
-	/* atom lvds */
-	uint32_t lvds_misc;
+	int dig_encoder; /* -1 disabled, 0 DIGA, 1 DIGB, etc. */
+	/* atom lvds/edp */
+	uint32_t lcd_misc;
 	uint16_t panel_pwr_delay;
-	enum radeon_pll_algo pll_algo;
-	struct radeon_atom_ss *ss;
+	uint32_t lcd_ss_id;
 	/* panel mode */
 	struct drm_display_mode native_mode;
 };
@@ -370,6 +366,8 @@
 	uint32_t pixel_clock;
 	enum radeon_rmx_type rmx_type;
 	enum radeon_underscan_type underscan_type;
+	uint32_t underscan_hborder;
+	uint32_t underscan_vborder;
 	struct drm_display_mode native_mode;
 	void *enc_priv;
 	int audio_polling_active;
@@ -377,6 +375,7 @@
 	int hdmi_config_offset;
 	int hdmi_audio_workaround;
 	int hdmi_buffer_status;
+	bool is_ext_encoder;
 };
 
 struct radeon_connector_atom_dig {
@@ -387,6 +386,7 @@
 	u8 dp_sink_type;
 	int dp_clock;
 	int dp_lane_count;
+	bool edp_on;
 };
 
 struct radeon_gpio_rec {
@@ -403,13 +403,19 @@
 };
 
 struct radeon_router {
-	bool valid;
 	u32 router_id;
 	struct radeon_i2c_bus_rec i2c_info;
 	u8 i2c_addr;
-	u8 mux_type;
-	u8 mux_control_pin;
-	u8 mux_state;
+	/* i2c mux */
+	bool ddc_valid;
+	u8 ddc_mux_type;
+	u8 ddc_mux_control_pin;
+	u8 ddc_mux_state;
+	/* clock/data mux */
+	bool cd_valid;
+	u8 cd_mux_type;
+	u8 cd_mux_control_pin;
+	u8 cd_mux_state;
 };
 
 struct radeon_connector {
@@ -436,6 +442,11 @@
 	struct drm_gem_object *obj;
 };
 
+/* radeon_get_crtc_scanoutpos() return flags */
+#define RADEON_SCANOUTPOS_VALID        (1 << 0)
+#define RADEON_SCANOUTPOS_INVBL        (1 << 1)
+#define RADEON_SCANOUTPOS_ACCURATE     (1 << 2)
+
 extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std
@@ -485,12 +496,20 @@
 				u8 slave_addr,
 				u8 addr,
 				u8 val);
-extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
+extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
 extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
 extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
 
+extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
+					     struct radeon_atom_ss *ss,
+					     int id);
+extern bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
+					     struct radeon_atom_ss *ss,
+					     int id, u32 clock);
+
 extern void radeon_compute_pll(struct radeon_pll *pll,
 			       uint64_t freq,
 			       uint32_t *dot_clock_p,
@@ -506,14 +525,19 @@
 struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
 struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
 struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
-extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
 extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
 extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
+extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
 extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
 
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
 extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 				   struct drm_framebuffer *old_fb);
+extern int atombios_crtc_set_base_atomic(struct drm_crtc *crtc,
+					 struct drm_framebuffer *fb,
+					 int x, int y,
+					 enum mode_set_atomic state);
 extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
 				   struct drm_display_mode *mode,
 				   struct drm_display_mode *adjusted_mode,
@@ -523,7 +547,13 @@
 
 extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
 				 struct drm_framebuffer *old_fb);
-
+extern int radeon_crtc_set_base_atomic(struct drm_crtc *crtc,
+				       struct drm_framebuffer *fb,
+				       int x, int y,
+				       enum mode_set_atomic state);
+extern int radeon_crtc_do_set_base(struct drm_crtc *crtc,
+				   struct drm_framebuffer *fb,
+				   int x, int y, int atomic);
 extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
 				  struct drm_file *file_priv,
 				  uint32_t handle,
@@ -532,6 +562,8 @@
 extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 				   int x, int y);
 
+extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos);
+
 extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev);
 extern struct edid *
 radeon_combios_get_hardcoded_edid(struct radeon_device *rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_object.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_object.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_object.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_object.c	2011-01-04 19:50:19.000000000 -0500
@@ -69,7 +69,7 @@
 	u32 c = 0;
 
 	rbo->placement.fpfn = 0;
-	rbo->placement.lpfn = rbo->rdev->mc.active_vram_size >> PAGE_SHIFT;
+	rbo->placement.lpfn = 0;
 	rbo->placement.placement = rbo->placements;
 	rbo->placement.busy_placement = rbo->placements;
 	if (domain & RADEON_GEM_DOMAIN_VRAM)
@@ -86,11 +86,13 @@
 }
 
 int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj,
-			unsigned long size, bool kernel, u32 domain,
-			struct radeon_bo **bo_ptr)
+		     unsigned long size, int byte_align, bool kernel, u32 domain,
+		     struct radeon_bo **bo_ptr)
 {
 	struct radeon_bo *bo;
 	enum ttm_bo_type type;
+	unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
+	unsigned long max_size = 0;
 	int r;
 
 	if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
@@ -102,6 +104,16 @@
 		type = ttm_bo_type_device;
 	}
 	*bo_ptr = NULL;
+
+	/* maximun bo size is the minimun btw visible vram and gtt size */
+	max_size = min(rdev->mc.visible_vram_size, rdev->mc.gtt_size);
+	if ((page_align << PAGE_SHIFT) >= max_size) {
+		printk(KERN_WARNING "%s:%d alloc size %ldM bigger than %ldMb limit\n",
+			__func__, __LINE__, page_align  >> (20 - PAGE_SHIFT), max_size >> 20);
+		return -ENOMEM;
+	}
+
+retry:
 	bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
 	if (bo == NULL)
 		return -ENOMEM;
@@ -109,13 +121,11 @@
 	bo->gobj = gobj;
 	bo->surface_reg = -1;
 	INIT_LIST_HEAD(&bo->list);
-
-retry:
 	radeon_ttm_placement_from_domain(bo, domain);
 	/* Kernel allocation are uninterruptible */
 	mutex_lock(&rdev->vram_mutex);
 	r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
-			&bo->placement, 0, 0, !kernel, NULL, size,
+			&bo->placement, page_align, 0, !kernel, NULL, size,
 			&radeon_ttm_bo_destroy);
 	mutex_unlock(&rdev->vram_mutex);
 	if (unlikely(r != 0)) {
@@ -435,7 +445,7 @@
 
 out:
 	radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
-			       bo->tbo.mem.mm_node->start << PAGE_SHIFT,
+			       bo->tbo.mem.start << PAGE_SHIFT,
 			       bo->tbo.num_pages << PAGE_SHIFT);
 	return 0;
 }
@@ -532,7 +542,7 @@
 	rdev = rbo->rdev;
 	if (bo->mem.mem_type == TTM_PL_VRAM) {
 		size = bo->mem.num_pages << PAGE_SHIFT;
-		offset = bo->mem.mm_node->start << PAGE_SHIFT;
+		offset = bo->mem.start << PAGE_SHIFT;
 		if ((offset + size) > rdev->mc.visible_vram_size) {
 			/* hurrah the memory is not visible ! */
 			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
@@ -540,7 +550,7 @@
 			r = ttm_bo_validate(bo, &rbo->placement, false, true, false);
 			if (unlikely(r != 0))
 				return r;
-			offset = bo->mem.mm_node->start << PAGE_SHIFT;
+			offset = bo->mem.start << PAGE_SHIFT;
 			/* this should not happen */
 			if ((offset + size) > rdev->mc.visible_vram_size)
 				return -EINVAL;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_object.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_object.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_object.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_object.h	2011-01-04 19:50:19.000000000 -0500
@@ -137,9 +137,10 @@
 }
 
 extern int radeon_bo_create(struct radeon_device *rdev,
-				struct drm_gem_object *gobj, unsigned long size,
-				bool kernel, u32 domain,
-				struct radeon_bo **bo_ptr);
+			    struct drm_gem_object *gobj, unsigned long size,
+			    int byte_align,
+			    bool kernel, u32 domain,
+			    struct radeon_bo **bo_ptr);
 extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
 extern void radeon_bo_kunmap(struct radeon_bo *bo);
 extern void radeon_bo_unref(struct radeon_bo **bo);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_pm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_pm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_pm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_pm.c	2011-01-04 19:50:19.000000000 -0500
@@ -712,73 +712,21 @@
 
 static bool radeon_pm_in_vbl(struct radeon_device *rdev)
 {
-	u32 stat_crtc = 0, vbl = 0, position = 0;
+	int  crtc, vpos, hpos, vbl_status;
 	bool in_vbl = true;
 
-	if (ASIC_IS_DCE4(rdev)) {
-		if (rdev->pm.active_crtcs & (1 << 0)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC0_REGISTER_OFFSET) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 1)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC1_REGISTER_OFFSET) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 2)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC2_REGISTER_OFFSET) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 3)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC3_REGISTER_OFFSET) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 4)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC4_REGISTER_OFFSET) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 5)) {
-			vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END +
-				     EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
-			position = RREG32(EVERGREEN_CRTC_STATUS_POSITION +
-					  EVERGREEN_CRTC5_REGISTER_OFFSET) & 0xfff;
-		}
-	} else if (ASIC_IS_AVIVO(rdev)) {
-		if (rdev->pm.active_crtcs & (1 << 0)) {
-			vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END) & 0xfff;
-			position = RREG32(AVIVO_D1CRTC_STATUS_POSITION) & 0xfff;
-		}
-		if (rdev->pm.active_crtcs & (1 << 1)) {
-			vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END) & 0xfff;
-			position = RREG32(AVIVO_D2CRTC_STATUS_POSITION) & 0xfff;
-		}
-		if (position < vbl && position > 1)
-			in_vbl = false;
-	} else {
-		if (rdev->pm.active_crtcs & (1 << 0)) {
-			stat_crtc = RREG32(RADEON_CRTC_STATUS);
-			if (!(stat_crtc & 1))
-				in_vbl = false;
-		}
-		if (rdev->pm.active_crtcs & (1 << 1)) {
-			stat_crtc = RREG32(RADEON_CRTC2_STATUS);
-			if (!(stat_crtc & 1))
+	/* Iterate over all active crtc's. All crtc's must be in vblank,
+	 * otherwise return in_vbl == false.
+	 */
+	for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
+		if (rdev->pm.active_crtcs & (1 << crtc)) {
+			vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos);
+			if ((vbl_status & RADEON_SCANOUTPOS_VALID) &&
+			    !(vbl_status & RADEON_SCANOUTPOS_INVBL))
 				in_vbl = false;
 		}
 	}
 
-	if (position < vbl && position > 1)
-		in_vbl = false;
-
 	return in_vbl;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_reg.h linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_reg.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_reg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_reg.h	2011-01-04 19:50:19.000000000 -0500
@@ -2836,6 +2836,7 @@
 #       define R200_TXFORMAT_ST_ROUTE_STQ5	(5 << 24)
 #       define R200_TXFORMAT_ST_ROUTE_MASK	(7 << 24)
 #       define R200_TXFORMAT_ST_ROUTE_SHIFT	24
+#       define R200_TXFORMAT_LOOKUP_DISABLE	(1 << 27)
 #       define R200_TXFORMAT_ALPHA_MASK_ENABLE	(1 << 28)
 #       define R200_TXFORMAT_CHROMA_KEY_ENABLE	(1 << 29)
 #       define R200_TXFORMAT_CUBIC_MAP_ENABLE		(1 << 30)
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_ring.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_ring.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_ring.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_ring.c	2011-01-04 19:50:19.000000000 -0500
@@ -176,8 +176,8 @@
 	INIT_LIST_HEAD(&rdev->ib_pool.bogus_ib);
 	/* Allocate 1M object buffer */
 	r = radeon_bo_create(rdev, NULL,  RADEON_IB_POOL_SIZE*64*1024,
-				true, RADEON_GEM_DOMAIN_GTT,
-				&rdev->ib_pool.robj);
+			     PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+			     &rdev->ib_pool.robj);
 	if (r) {
 		DRM_ERROR("radeon: failed to ib pool (%d).\n", r);
 		return r;
@@ -247,10 +247,14 @@
  */
 void radeon_ring_free_size(struct radeon_device *rdev)
 {
-	if (rdev->family >= CHIP_R600)
-		rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
-	else
-		rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+	if (rdev->wb.enabled)
+		rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4];
+	else {
+		if (rdev->family >= CHIP_R600)
+			rdev->cp.rptr = RREG32(R600_CP_RB_RPTR);
+		else
+			rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+	}
 	/* This works because ring_size is a power of 2 */
 	rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4));
 	rdev->cp.ring_free_dw -= rdev->cp.wptr;
@@ -328,7 +332,7 @@
 	rdev->cp.ring_size = ring_size;
 	/* Allocate ring buffer */
 	if (rdev->cp.ring_obj == NULL) {
-		r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, true,
+		r = radeon_bo_create(rdev, NULL, rdev->cp.ring_size, PAGE_SIZE, true,
 					RADEON_GEM_DOMAIN_GTT,
 					&rdev->cp.ring_obj);
 		if (r) {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_test.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_test.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_test.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_test.c	2011-01-04 19:50:19.000000000 -0500
@@ -52,7 +52,7 @@
 		goto out_cleanup;
 	}
 
-	r = radeon_bo_create(rdev, NULL, size, true, RADEON_GEM_DOMAIN_VRAM,
+	r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
 				&vram_obj);
 	if (r) {
 		DRM_ERROR("Failed to create VRAM object\n");
@@ -71,7 +71,7 @@
 		void **gtt_start, **gtt_end;
 		void **vram_start, **vram_end;
 
-		r = radeon_bo_create(rdev, NULL, size, true,
+		r = radeon_bo_create(rdev, NULL, size, PAGE_SIZE, true,
 					 RADEON_GEM_DOMAIN_GTT, gtt_obj + i);
 		if (r) {
 			DRM_ERROR("Failed to create GTT object %d\n", i);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_ttm.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_ttm.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/radeon_ttm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/radeon_ttm.c	2011-01-04 19:50:19.000000000 -0500
@@ -152,6 +152,7 @@
 		man->default_caching = TTM_PL_FLAG_CACHED;
 		break;
 	case TTM_PL_TT:
+		man->func = &ttm_bo_manager_func;
 		man->gpu_offset = rdev->mc.gtt_start;
 		man->available_caching = TTM_PL_MASK_CACHING;
 		man->default_caching = TTM_PL_FLAG_CACHED;
@@ -173,6 +174,7 @@
 		break;
 	case TTM_PL_VRAM:
 		/* "On-card" video ram */
+		man->func = &ttm_bo_manager_func;
 		man->gpu_offset = rdev->mc.vram_start;
 		man->flags = TTM_MEMTYPE_FLAG_FIXED |
 			     TTM_MEMTYPE_FLAG_MAPPABLE;
@@ -246,8 +248,8 @@
 	if (unlikely(r)) {
 		return r;
 	}
-	old_start = old_mem->mm_node->start << PAGE_SHIFT;
-	new_start = new_mem->mm_node->start << PAGE_SHIFT;
+	old_start = old_mem->start << PAGE_SHIFT;
+	new_start = new_mem->start << PAGE_SHIFT;
 
 	switch (old_mem->mem_type) {
 	case TTM_PL_VRAM:
@@ -326,14 +328,7 @@
 	}
 	r = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem);
 out_cleanup:
-	if (tmp_mem.mm_node) {
-		struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
-		spin_lock(&glob->lru_lock);
-		drm_mm_put_block(tmp_mem.mm_node);
-		spin_unlock(&glob->lru_lock);
-		return r;
-	}
+	ttm_bo_mem_put(bo, &tmp_mem);
 	return r;
 }
 
@@ -372,14 +367,7 @@
 		goto out_cleanup;
 	}
 out_cleanup:
-	if (tmp_mem.mm_node) {
-		struct ttm_bo_global *glob = rdev->mman.bdev.glob;
-
-		spin_lock(&glob->lru_lock);
-		drm_mm_put_block(tmp_mem.mm_node);
-		spin_unlock(&glob->lru_lock);
-		return r;
-	}
+	ttm_bo_mem_put(bo, &tmp_mem);
 	return r;
 }
 
@@ -449,14 +437,14 @@
 #if __OS_HAS_AGP
 		if (rdev->flags & RADEON_IS_AGP) {
 			/* RADEON_IS_AGP is set only if AGP is active */
-			mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+			mem->bus.offset = mem->start << PAGE_SHIFT;
 			mem->bus.base = rdev->mc.agp_base;
 			mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
 		}
 #endif
 		break;
 	case TTM_PL_VRAM:
-		mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+		mem->bus.offset = mem->start << PAGE_SHIFT;
 		/* check if it's visible */
 		if ((mem->bus.offset + mem->bus.size) > rdev->mc.visible_vram_size)
 			return -EINVAL;
@@ -541,7 +529,7 @@
 		DRM_ERROR("Failed initializing VRAM heap.\n");
 		return r;
 	}
-	r = radeon_bo_create(rdev, NULL, 256 * 1024, true,
+	r = radeon_bo_create(rdev, NULL, 256 * 1024, PAGE_SIZE, true,
 				RADEON_GEM_DOMAIN_VRAM,
 				&rdev->stollen_vga_memory);
 	if (r) {
@@ -631,7 +619,7 @@
 		return drm_mmap(filp, vma);
 	}
 
-	file_priv = (struct drm_file *)filp->private_data;
+	file_priv = filp->private_data;
 	rdev = file_priv->minor->dev->dev_private;
 	if (rdev == NULL) {
 		return -EINVAL;
@@ -699,9 +687,10 @@
 	int r;
 
 	gtt = container_of(backend, struct radeon_ttm_backend, backend);
-	gtt->offset = bo_mem->mm_node->start << PAGE_SHIFT;
+	gtt->offset = bo_mem->start << PAGE_SHIFT;
 	if (!gtt->num_pages) {
-		WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
+		WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
+		     gtt->num_pages, bo_mem, backend);
 	}
 	r = radeon_gart_bind(gtt->rdev, gtt->offset,
 			     gtt->num_pages, gtt->pages);
@@ -798,9 +787,9 @@
 		radeon_mem_types_list[i].show = &radeon_mm_dump_table;
 		radeon_mem_types_list[i].driver_features = 0;
 		if (i == 0)
-			radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].manager;
+			radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_VRAM].priv;
 		else
-			radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].manager;
+			radeon_mem_types_list[i].data = &rdev->mman.bdev.man[TTM_PL_TT].priv;
 
 	}
 	/* Add ttm page pool to debugfs */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/reg_srcs/evergreen linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/reg_srcs/evergreen
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/reg_srcs/evergreen	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/reg_srcs/evergreen	2011-01-04 19:50:19.000000000 -0500
@@ -22,6 +22,10 @@
 0x00008B10 PA_SC_LINE_STIPPLE_STATE
 0x00008BF0 PA_SC_ENHANCE
 0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008D90 SQ_DYN_GPR_OPTIMIZATION
+0x00008D94 SQ_DYN_GPR_SIMD_LOCK_EN
+0x00008D98 SQ_DYN_GPR_THREAD_LIMIT
+0x00008D9C SQ_DYN_GPR_LDS_LIMIT
 0x00008C00 SQ_CONFIG
 0x00008C04 SQ_GPR_RESOURCE_MGMT_1
 0x00008C08 SQ_GPR_RESOURCE_MGMT_2
@@ -34,6 +38,10 @@
 0x00008C24 SQ_STACK_RESOURCE_MGMT_2
 0x00008C28 SQ_STACK_RESOURCE_MGMT_3
 0x00008DF8 SQ_CONST_MEM_BASE
+0x00008E20 SQ_STATIC_THREAD_MGMT_1
+0x00008E24 SQ_STATIC_THREAD_MGMT_2
+0x00008E28 SQ_STATIC_THREAD_MGMT_3
+0x00008E2C SQ_LDS_RESOURCE_MGMT
 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
 0x00009100 SPI_CONFIG_CNTL
 0x0000913C SPI_CONFIG_CNTL_1
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs400.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs400.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs400.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs400.c	2011-01-04 19:50:19.000000000 -0500
@@ -78,7 +78,7 @@
 	int r;
 
 	if (rdev->gart.table.ram.ptr) {
-		WARN(1, "RS400 GART already initialized.\n");
+		WARN(1, "RS400 GART already initialized\n");
 		return 0;
 	}
 	/* Check gart size */
@@ -397,6 +397,12 @@
 	r = rs400_gart_enable(rdev);
 	if (r)
 		return r;
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r100_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -406,9 +412,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -443,7 +446,7 @@
 int rs400_suspend(struct radeon_device *rdev)
 {
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	r100_irq_disable(rdev);
 	rs400_gart_disable(rdev);
 	return 0;
@@ -452,7 +455,7 @@
 void rs400_fini(struct radeon_device *rdev)
 {
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	rs400_gart_fini(rdev);
@@ -526,7 +529,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		rs400_gart_fini(rdev);
 		radeon_irq_kms_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs600.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs600.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs600.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs600.c	2011-01-04 19:50:19.000000000 -0500
@@ -375,7 +375,7 @@
 	int r;
 
 	if (rdev->gart.table.vram.robj) {
-		WARN(1, "RS600 GART already initialized.\n");
+		WARN(1, "RS600 GART already initialized\n");
 		return 0;
 	}
 	/* Initialize common gart structure */
@@ -505,7 +505,7 @@
 		~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
 
 	if (!rdev->irq.installed) {
-		WARN(1, "Can't enable IRQ/MSI because no handler is installed.\n");
+		WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
 		WREG32(R_000040_GEN_INT_CNTL, 0);
 		return -EINVAL;
 	}
@@ -796,6 +796,12 @@
 	r = rs600_gart_enable(rdev);
 	if (r)
 		return r;
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	rs600_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -805,9 +811,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -848,7 +851,7 @@
 {
 	r600_audio_fini(rdev);
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	rs600_irq_disable(rdev);
 	rs600_gart_disable(rdev);
 	return 0;
@@ -858,7 +861,7 @@
 {
 	r600_audio_fini(rdev);
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	rs600_gart_fini(rdev);
@@ -932,7 +935,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		rs600_gart_fini(rdev);
 		radeon_irq_kms_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs690.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs690.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rs690.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rs690.c	2011-01-04 19:50:19.000000000 -0500
@@ -616,6 +616,12 @@
 	r = rs400_gart_enable(rdev);
 	if (r)
 		return r;
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	rs600_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -625,9 +631,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -668,7 +671,7 @@
 {
 	r600_audio_fini(rdev);
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	rs600_irq_disable(rdev);
 	rs400_gart_disable(rdev);
 	return 0;
@@ -678,7 +681,7 @@
 {
 	r600_audio_fini(rdev);
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	rs400_gart_fini(rdev);
@@ -753,7 +756,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		rs400_gart_fini(rdev);
 		radeon_irq_kms_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rv515.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rv515.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rv515.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rv515.c	2011-01-04 19:50:19.000000000 -0500
@@ -386,6 +386,12 @@
 		if (r)
 			return r;
 	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	rs600_irq_set(rdev);
 	rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
@@ -395,9 +401,6 @@
 		dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
 		return r;
 	}
-	r = r100_wb_init(rdev);
-	if (r)
-		dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
 	r = r100_ib_init(rdev);
 	if (r) {
 		dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
@@ -431,7 +434,7 @@
 int rv515_suspend(struct radeon_device *rdev)
 {
 	r100_cp_disable(rdev);
-	r100_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	rs600_irq_disable(rdev);
 	if (rdev->flags & RADEON_IS_PCIE)
 		rv370_pcie_gart_disable(rdev);
@@ -447,7 +450,7 @@
 void rv515_fini(struct radeon_device *rdev)
 {
 	r100_cp_fini(rdev);
-	r100_wb_fini(rdev);
+	radeon_wb_fini(rdev);
 	r100_ib_fini(rdev);
 	radeon_gem_fini(rdev);
 	rv370_pcie_gart_fini(rdev);
@@ -527,7 +530,7 @@
 		/* Somethings want wront with the accel init stop accel */
 		dev_err(rdev->dev, "Disabling GPU acceleration\n");
 		r100_cp_fini(rdev);
-		r100_wb_fini(rdev);
+		radeon_wb_fini(rdev);
 		r100_ib_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		rv370_pcie_gart_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rv770.c linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rv770.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/radeon/rv770.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/radeon/rv770.c	2011-01-04 19:50:19.000000000 -0500
@@ -269,6 +269,7 @@
 {
 	rdev->mc.active_vram_size = rdev->mc.visible_vram_size;
 	WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
+	WREG32(SCRATCH_UMSK, 0);
 }
 
 static int rv770_cp_load_microcode(struct radeon_device *rdev)
@@ -643,10 +644,11 @@
 	else
 		gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT);
 	rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3);
-
-	gb_tiling_config |= GROUP_SIZE(0);
-	rdev->config.rv770.tiling_group_size = 256;
-
+	gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT);
+	if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT)
+		rdev->config.rv770.tiling_group_size = 512;
+	else
+		rdev->config.rv770.tiling_group_size = 256;
 	if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) {
 		gb_tiling_config |= ROW_TILING(3);
 		gb_tiling_config |= SAMPLE_SPLIT(3);
@@ -913,8 +915,8 @@
 
 	if (rdev->vram_scratch.robj == NULL) {
 		r = radeon_bo_create(rdev, NULL, RADEON_GPU_PAGE_SIZE,
-					true, RADEON_GEM_DOMAIN_VRAM,
-					&rdev->vram_scratch.robj);
+				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
+				     &rdev->vram_scratch.robj);
 		if (r) {
 			return r;
 		}
@@ -1030,19 +1032,12 @@
 		rdev->asic->copy = NULL;
 		dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
 	}
-	/* pin copy shader into vram */
-	if (rdev->r600_blit.shader_obj) {
-		r = radeon_bo_reserve(rdev->r600_blit.shader_obj, false);
-		if (unlikely(r != 0))
-			return r;
-		r = radeon_bo_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
-				&rdev->r600_blit.shader_gpu_addr);
-		radeon_bo_unreserve(rdev->r600_blit.shader_obj);
-		if (r) {
-			DRM_ERROR("failed to pin blit object %d\n", r);
-			return r;
-		}
-	}
+
+	/* allocate wb buffer */
+	r = radeon_wb_init(rdev);
+	if (r)
+		return r;
+
 	/* Enable IRQ */
 	r = r600_irq_init(rdev);
 	if (r) {
@@ -1061,8 +1056,7 @@
 	r = r600_cp_resume(rdev);
 	if (r)
 		return r;
-	/* write back buffer are not vital so don't worry about failure */
-	r600_wb_enable(rdev);
+
 	return 0;
 }
 
@@ -1108,7 +1102,7 @@
 	r700_cp_stop(rdev);
 	rdev->cp.ready = false;
 	r600_irq_suspend(rdev);
-	r600_wb_disable(rdev);
+	radeon_wb_disable(rdev);
 	rv770_pcie_gart_disable(rdev);
 	/* unpin shaders bo */
 	if (rdev->r600_blit.shader_obj) {
@@ -1203,8 +1197,8 @@
 	if (r) {
 		dev_err(rdev->dev, "disabling GPU acceleration\n");
 		r700_cp_fini(rdev);
-		r600_wb_fini(rdev);
 		r600_irq_fini(rdev);
+		radeon_wb_fini(rdev);
 		radeon_irq_kms_fini(rdev);
 		rv770_pcie_gart_fini(rdev);
 		rdev->accel_working = false;
@@ -1236,8 +1230,8 @@
 {
 	r600_blit_fini(rdev);
 	r700_cp_fini(rdev);
-	r600_wb_fini(rdev);
 	r600_irq_fini(rdev);
+	radeon_wb_fini(rdev);
 	radeon_irq_kms_fini(rdev);
 	rv770_pcie_gart_fini(rdev);
 	rv770_vram_scratch_fini(rdev);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/savage/savage_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/savage/savage_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/savage/savage_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/savage/savage_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,8 +42,6 @@
 	.lastclose = savage_driver_lastclose,
 	.unload = savage_driver_unload,
 	.reclaim_buffers = savage_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = savage_ioctls,
 	.dma_ioctl = savage_bci_buffers,
 	.fops = {
@@ -54,6 +52,7 @@
 		 .mmap = drm_mmap,
 		 .poll = drm_poll,
 		 .fasync = drm_fasync,
+		 .llseek = noop_llseek,
 	},
 
 	.pci_driver = {
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/sis/sis_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/sis/sis_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/sis/sis_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/sis/sis_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -67,13 +67,10 @@
 	.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
 	.load = sis_driver_load,
 	.unload = sis_driver_unload,
-	.context_dtor = NULL,
 	.dma_quiescent = sis_idle,
 	.reclaim_buffers = NULL,
 	.reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
 	.lastclose = sis_lastclose,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = sis_ioctls,
 	.fops = {
 		 .owner = THIS_MODULE,
@@ -83,6 +80,7 @@
 		 .mmap = drm_mmap,
 		 .poll = drm_poll,
 		 .fasync = drm_fasync,
+		 .llseek = noop_llseek,
 	},
 	.pci_driver = {
 		 .name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/tdfx/tdfx_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/tdfx/tdfx_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/tdfx/tdfx_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/tdfx/tdfx_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -42,8 +42,6 @@
 static struct drm_driver driver = {
 	.driver_features = DRIVER_USE_MTRR,
 	.reclaim_buffers = drm_core_reclaim_buffers,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.fops = {
 		 .owner = THIS_MODULE,
 		 .open = drm_open,
@@ -52,6 +50,7 @@
 		 .mmap = drm_mmap,
 		 .poll = drm_poll,
 		 .fasync = drm_fasync,
+		 .llseek = noop_llseek,
 	},
 	.pci_driver = {
 		 .name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,7 @@
 ccflags-y := -Iinclude/drm
 ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
 	ttm_bo_util.o ttm_bo_vm.o ttm_module.o \
-	ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o
+	ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o \
+	ttm_bo_manager.o
 
 obj-$(CONFIG_DRM_TTM) += ttm.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_agp_backend.c linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_agp_backend.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_agp_backend.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_agp_backend.c	2011-01-04 19:50:19.000000000 -0500
@@ -74,6 +74,7 @@
 {
 	struct ttm_agp_backend *agp_be =
 	    container_of(backend, struct ttm_agp_backend, backend);
+	struct drm_mm_node *node = bo_mem->mm_node;
 	struct agp_memory *mem = agp_be->mem;
 	int cached = (bo_mem->placement & TTM_PL_FLAG_CACHED);
 	int ret;
@@ -81,7 +82,7 @@
 	mem->is_flushed = 1;
 	mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY;
 
-	ret = agp_bind_memory(mem, bo_mem->mm_node->start);
+	ret = agp_bind_memory(mem, node->start);
 	if (ret)
 		printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n");
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,14 +27,6 @@
 /*
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
-/* Notes:
- *
- * We store bo pointer in drm_mm_node struct so we know which bo own a
- * specific node. There is no protection on the pointer, thus to make
- * sure things don't go berserk you have to access this pointer while
- * holding the global lru lock and make sure anytime you free a node you
- * reset the pointer to NULL.
- */
 
 #include "ttm/ttm_module.h"
 #include "ttm/ttm_bo_driver.h"
@@ -45,6 +37,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/module.h>
+#include <asm/atomic.h>
 
 #define TTM_ASSERT_LOCKED(param)
 #define TTM_DEBUG(fmt, arg...)
@@ -84,11 +77,8 @@
 		man->available_caching);
 	printk(KERN_ERR TTM_PFX "    default_caching: 0x%08X\n",
 		man->default_caching);
-	if (mem_type != TTM_PL_SYSTEM) {
-		spin_lock(&bdev->glob->lru_lock);
-		drm_mm_debug_table(&man->manager, TTM_PFX);
-		spin_unlock(&bdev->glob->lru_lock);
-	}
+	if (mem_type != TTM_PL_SYSTEM)
+		(*man->func->debug)(man, TTM_PFX);
 }
 
 static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
@@ -169,18 +159,13 @@
 
 int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
 {
-
 	if (interruptible) {
-		int ret = 0;
-
-		ret = wait_event_interruptible(bo->event_queue,
+		return wait_event_interruptible(bo->event_queue,
 					       atomic_read(&bo->reserved) == 0);
-		if (unlikely(ret != 0))
-			return ret;
 	} else {
 		wait_event(bo->event_queue, atomic_read(&bo->reserved) == 0);
+		return 0;
 	}
-	return 0;
 }
 EXPORT_SYMBOL(ttm_bo_wait_unreserved);
 
@@ -239,6 +224,9 @@
 	int ret;
 
 	while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
+		/**
+		 * Deadlock avoidance for multi-bo reserving.
+		 */
 		if (use_sequence && bo->seq_valid &&
 			(sequence - bo->val_seq < (1 << 31))) {
 			return -EAGAIN;
@@ -256,6 +244,14 @@
 	}
 
 	if (use_sequence) {
+		/**
+		 * Wake up waiters that may need to recheck for deadlock,
+		 * if we decreased the sequence number.
+		 */
+		if (unlikely((bo->val_seq - sequence < (1 << 31))
+			     || !bo->seq_valid))
+			wake_up_all(&bo->event_queue);
+
 		bo->val_seq = sequence;
 		bo->seq_valid = true;
 	} else {
@@ -421,7 +417,7 @@
 
 	if (bo->mem.mm_node) {
 		spin_lock(&bo->lock);
-		bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) +
+		bo->offset = (bo->mem.start << PAGE_SHIFT) +
 		    bdev->man[bo->mem.mem_type].gpu_offset;
 		bo->cur_placement = bo->mem.placement;
 		spin_unlock(&bo->lock);
@@ -442,135 +438,152 @@
 }
 
 /**
- * Call bo::reserved and with the lru lock held.
+ * Call bo::reserved.
  * Will release GPU memory type usage on destruction.
- * This is the place to put in driver specific hooks.
- * Will release the bo::reserved lock and the
- * lru lock on exit.
+ * This is the place to put in driver specific hooks to release
+ * driver private resources.
+ * Will release the bo::reserved lock.
  */
 
 static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
 {
-	struct ttm_bo_global *glob = bo->glob;
-
 	if (bo->ttm) {
-
-		/**
-		 * Release the lru_lock, since we don't want to have
-		 * an atomic requirement on ttm_tt[unbind|destroy].
-		 */
-
-		spin_unlock(&glob->lru_lock);
 		ttm_tt_unbind(bo->ttm);
 		ttm_tt_destroy(bo->ttm);
 		bo->ttm = NULL;
-		spin_lock(&glob->lru_lock);
 	}
 
-	if (bo->mem.mm_node) {
-		drm_mm_put_block(bo->mem.mm_node);
-		bo->mem.mm_node = NULL;
-	}
+	ttm_bo_mem_put(bo, &bo->mem);
 
 	atomic_set(&bo->reserved, 0);
+
+	/*
+	 * Make processes trying to reserve really pick it up.
+	 */
+	smp_mb__after_atomic_dec();
 	wake_up_all(&bo->event_queue);
-	spin_unlock(&glob->lru_lock);
 }
 
-
-/**
- * If bo idle, remove from delayed- and lru lists, and unref.
- * If not idle, and already on delayed list, do nothing.
- * If not idle, and not on delayed list, put on delayed list,
- *   up the list_kref and schedule a delayed list check.
- */
-
-static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
+static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
 {
 	struct ttm_bo_device *bdev = bo->bdev;
 	struct ttm_bo_global *glob = bo->glob;
-	struct ttm_bo_driver *driver = bdev->driver;
+	struct ttm_bo_driver *driver;
+	void *sync_obj = NULL;
+	void *sync_obj_arg;
+	int put_count;
 	int ret;
 
 	spin_lock(&bo->lock);
-retry:
-	(void) ttm_bo_wait(bo, false, false, !remove_all);
-
+	(void) ttm_bo_wait(bo, false, false, true);
 	if (!bo->sync_obj) {
-		int put_count;
-
-		spin_unlock(&bo->lock);
 
 		spin_lock(&glob->lru_lock);
-		ret = ttm_bo_reserve_locked(bo, false, !remove_all, false, 0);
 
 		/**
-		 * Someone else has the object reserved. Bail and retry.
+		 * Lock inversion between bo::reserve and bo::lock here,
+		 * but that's OK, since we're only trylocking.
 		 */
 
-		if (unlikely(ret == -EBUSY)) {
-			spin_unlock(&glob->lru_lock);
-			spin_lock(&bo->lock);
-			goto requeue;
-		}
-
-		/**
-		 * We can re-check for sync object without taking
-		 * the bo::lock since setting the sync object requires
-		 * also bo::reserved. A busy object at this point may
-		 * be caused by another thread starting an accelerated
-		 * eviction.
-		 */
+		ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
 
-		if (unlikely(bo->sync_obj)) {
-			atomic_set(&bo->reserved, 0);
-			wake_up_all(&bo->event_queue);
-			spin_unlock(&glob->lru_lock);
-			spin_lock(&bo->lock);
-			if (remove_all)
-				goto retry;
-			else
-				goto requeue;
-		}
+		if (unlikely(ret == -EBUSY))
+			goto queue;
 
+		spin_unlock(&bo->lock);
 		put_count = ttm_bo_del_from_lru(bo);
 
-		if (!list_empty(&bo->ddestroy)) {
-			list_del_init(&bo->ddestroy);
-			++put_count;
-		}
-
+		spin_unlock(&glob->lru_lock);
 		ttm_bo_cleanup_memtype_use(bo);
 
 		while (put_count--)
 			kref_put(&bo->list_kref, ttm_bo_ref_bug);
 
-		return 0;
+		return;
+	} else {
+		spin_lock(&glob->lru_lock);
 	}
-requeue:
+queue:
+	driver = bdev->driver;
+	if (bo->sync_obj)
+		sync_obj = driver->sync_obj_ref(bo->sync_obj);
+	sync_obj_arg = bo->sync_obj_arg;
+
+	kref_get(&bo->list_kref);
+	list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+	spin_unlock(&glob->lru_lock);
+	spin_unlock(&bo->lock);
+
+	if (sync_obj) {
+		driver->sync_obj_flush(sync_obj, sync_obj_arg);
+		driver->sync_obj_unref(&sync_obj);
+	}
+	schedule_delayed_work(&bdev->wq,
+			      ((HZ / 100) < 1) ? 1 : HZ / 100);
+}
+
+/**
+ * function ttm_bo_cleanup_refs
+ * If bo idle, remove from delayed- and lru lists, and unref.
+ * If not idle, do nothing.
+ *
+ * @interruptible         Any sleeps should occur interruptibly.
+ * @no_wait_reserve       Never wait for reserve. Return -EBUSY instead.
+ * @no_wait_gpu           Never wait for gpu. Return -EBUSY instead.
+ */
+
+static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
+			       bool interruptible,
+			       bool no_wait_reserve,
+			       bool no_wait_gpu)
+{
+	struct ttm_bo_global *glob = bo->glob;
+	int put_count;
+	int ret = 0;
+
+retry:
+	spin_lock(&bo->lock);
+	ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
+	spin_unlock(&bo->lock);
+
+	if (unlikely(ret != 0))
+		return ret;
+
 	spin_lock(&glob->lru_lock);
-	if (list_empty(&bo->ddestroy)) {
-		void *sync_obj = bo->sync_obj;
-		void *sync_obj_arg = bo->sync_obj_arg;
+	ret = ttm_bo_reserve_locked(bo, interruptible,
+				    no_wait_reserve, false, 0);
 
-		kref_get(&bo->list_kref);
-		list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+	if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) {
 		spin_unlock(&glob->lru_lock);
-		spin_unlock(&bo->lock);
+		return ret;
+	}
 
-		if (sync_obj)
-			driver->sync_obj_flush(sync_obj, sync_obj_arg);
-		schedule_delayed_work(&bdev->wq,
-				      ((HZ / 100) < 1) ? 1 : HZ / 100);
-		ret = 0;
+	/**
+	 * We can re-check for sync object without taking
+	 * the bo::lock since setting the sync object requires
+	 * also bo::reserved. A busy object at this point may
+	 * be caused by another thread recently starting an accelerated
+	 * eviction.
+	 */
 
-	} else {
+	if (unlikely(bo->sync_obj)) {
+		atomic_set(&bo->reserved, 0);
+		wake_up_all(&bo->event_queue);
 		spin_unlock(&glob->lru_lock);
-		spin_unlock(&bo->lock);
-		ret = -EBUSY;
+		goto retry;
 	}
 
-	return ret;
+	put_count = ttm_bo_del_from_lru(bo);
+	list_del_init(&bo->ddestroy);
+	++put_count;
+
+	spin_unlock(&glob->lru_lock);
+	ttm_bo_cleanup_memtype_use(bo);
+
+	while (put_count--)
+		kref_put(&bo->list_kref, ttm_bo_ref_bug);
+
+	return 0;
 }
 
 /**
@@ -602,7 +615,8 @@
 		}
 
 		spin_unlock(&glob->lru_lock);
-		ret = ttm_bo_cleanup_refs(entry, remove_all);
+		ret = ttm_bo_cleanup_refs(entry, false, !remove_all,
+					  !remove_all);
 		kref_put(&entry->list_kref, ttm_bo_release_list);
 		entry = nentry;
 
@@ -645,7 +659,7 @@
 		bo->vm_node = NULL;
 	}
 	write_unlock(&bdev->vm_lock);
-	ttm_bo_cleanup_refs(bo, false);
+	ttm_bo_cleanup_refs_or_queue(bo);
 	kref_put(&bo->list_kref, ttm_bo_release_list);
 	write_lock(&bdev->vm_lock);
 }
@@ -680,7 +694,6 @@
 			bool no_wait_reserve, bool no_wait_gpu)
 {
 	struct ttm_bo_device *bdev = bo->bdev;
-	struct ttm_bo_global *glob = bo->glob;
 	struct ttm_mem_reg evict_mem;
 	struct ttm_placement placement;
 	int ret = 0;
@@ -726,12 +739,7 @@
 	if (ret) {
 		if (ret != -ERESTARTSYS)
 			printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
-		spin_lock(&glob->lru_lock);
-		if (evict_mem.mm_node) {
-			drm_mm_put_block(evict_mem.mm_node);
-			evict_mem.mm_node = NULL;
-		}
-		spin_unlock(&glob->lru_lock);
+		ttm_bo_mem_put(bo, &evict_mem);
 		goto out;
 	}
 	bo->evicted = true;
@@ -759,6 +767,18 @@
 	bo = list_first_entry(&man->lru, struct ttm_buffer_object, lru);
 	kref_get(&bo->list_kref);
 
+	if (!list_empty(&bo->ddestroy)) {
+		spin_unlock(&glob->lru_lock);
+		ret = ttm_bo_cleanup_refs(bo, interruptible,
+					  no_wait_reserve, no_wait_gpu);
+		kref_put(&bo->list_kref, ttm_bo_release_list);
+
+		if (likely(ret == 0 || ret == -ERESTARTSYS))
+			return ret;
+
+		goto retry;
+	}
+
 	ret = ttm_bo_reserve_locked(bo, false, no_wait_reserve, false, 0);
 
 	if (unlikely(ret == -EBUSY)) {
@@ -792,41 +812,14 @@
 	return ret;
 }
 
-static int ttm_bo_man_get_node(struct ttm_buffer_object *bo,
-				struct ttm_mem_type_manager *man,
-				struct ttm_placement *placement,
-				struct ttm_mem_reg *mem,
-				struct drm_mm_node **node)
+void ttm_bo_mem_put(struct ttm_buffer_object *bo, struct ttm_mem_reg *mem)
 {
-	struct ttm_bo_global *glob = bo->glob;
-	unsigned long lpfn;
-	int ret;
-
-	lpfn = placement->lpfn;
-	if (!lpfn)
-		lpfn = man->size;
-	*node = NULL;
-	do {
-		ret = drm_mm_pre_get(&man->manager);
-		if (unlikely(ret))
-			return ret;
+	struct ttm_mem_type_manager *man = &bo->bdev->man[mem->mem_type];
 
-		spin_lock(&glob->lru_lock);
-		*node = drm_mm_search_free_in_range(&man->manager,
-					mem->num_pages, mem->page_alignment,
-					placement->fpfn, lpfn, 1);
-		if (unlikely(*node == NULL)) {
-			spin_unlock(&glob->lru_lock);
-			return 0;
-		}
-		*node = drm_mm_get_block_atomic_range(*node, mem->num_pages,
-							mem->page_alignment,
-							placement->fpfn,
-							lpfn);
-		spin_unlock(&glob->lru_lock);
-	} while (*node == NULL);
-	return 0;
+	if (mem->mm_node)
+		(*man->func->put_node)(man, mem);
 }
+EXPORT_SYMBOL(ttm_bo_mem_put);
 
 /**
  * Repeatedly evict memory from the LRU for @mem_type until we create enough
@@ -841,31 +834,22 @@
 					bool no_wait_gpu)
 {
 	struct ttm_bo_device *bdev = bo->bdev;
-	struct ttm_bo_global *glob = bdev->glob;
 	struct ttm_mem_type_manager *man = &bdev->man[mem_type];
-	struct drm_mm_node *node;
 	int ret;
 
 	do {
-		ret = ttm_bo_man_get_node(bo, man, placement, mem, &node);
+		ret = (*man->func->get_node)(man, bo, placement, mem);
 		if (unlikely(ret != 0))
 			return ret;
-		if (node)
-			break;
-		spin_lock(&glob->lru_lock);
-		if (list_empty(&man->lru)) {
-			spin_unlock(&glob->lru_lock);
+		if (mem->mm_node)
 			break;
-		}
-		spin_unlock(&glob->lru_lock);
 		ret = ttm_mem_evict_first(bdev, mem_type, interruptible,
 						no_wait_reserve, no_wait_gpu);
 		if (unlikely(ret != 0))
 			return ret;
 	} while (1);
-	if (node == NULL)
+	if (mem->mm_node == NULL)
 		return -ENOMEM;
-	mem->mm_node = node;
 	mem->mem_type = mem_type;
 	return 0;
 }
@@ -939,7 +923,6 @@
 	bool type_found = false;
 	bool type_ok = false;
 	bool has_erestartsys = false;
-	struct drm_mm_node *node = NULL;
 	int i, ret;
 
 	mem->mm_node = NULL;
@@ -973,17 +956,15 @@
 
 		if (man->has_type && man->use_type) {
 			type_found = true;
-			ret = ttm_bo_man_get_node(bo, man, placement, mem,
-							&node);
+			ret = (*man->func->get_node)(man, bo, placement, mem);
 			if (unlikely(ret))
 				return ret;
 		}
-		if (node)
+		if (mem->mm_node)
 			break;
 	}
 
-	if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || node) {
-		mem->mm_node = node;
+	if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || mem->mm_node) {
 		mem->mem_type = mem_type;
 		mem->placement = cur_flags;
 		return 0;
@@ -1053,7 +1034,6 @@
 			bool interruptible, bool no_wait_reserve,
 			bool no_wait_gpu)
 {
-	struct ttm_bo_global *glob = bo->glob;
 	int ret = 0;
 	struct ttm_mem_reg mem;
 
@@ -1081,11 +1061,8 @@
 		goto out_unlock;
 	ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait_reserve, no_wait_gpu);
 out_unlock:
-	if (ret && mem.mm_node) {
-		spin_lock(&glob->lru_lock);
-		drm_mm_put_block(mem.mm_node);
-		spin_unlock(&glob->lru_lock);
-	}
+	if (ret && mem.mm_node)
+		ttm_bo_mem_put(bo, &mem);
 	return ret;
 }
 
@@ -1093,11 +1070,10 @@
 			     struct ttm_mem_reg *mem)
 {
 	int i;
-	struct drm_mm_node *node = mem->mm_node;
 
-	if (node && placement->lpfn != 0 &&
-	    (node->start < placement->fpfn ||
-	     node->start + node->size > placement->lpfn))
+	if (mem->mm_node && placement->lpfn != 0 &&
+	    (mem->start < placement->fpfn ||
+	     mem->start + mem->num_pages > placement->lpfn))
 		return -1;
 
 	for (i = 0; i < placement->num_placement; i++) {
@@ -1154,35 +1130,9 @@
 int ttm_bo_check_placement(struct ttm_buffer_object *bo,
 				struct ttm_placement *placement)
 {
-	int i;
+	BUG_ON((placement->fpfn || placement->lpfn) &&
+	       (bo->mem.num_pages > (placement->lpfn - placement->fpfn)));
 
-	if (placement->fpfn || placement->lpfn) {
-		if (bo->mem.num_pages > (placement->lpfn - placement->fpfn)) {
-			printk(KERN_ERR TTM_PFX "Page number range to small "
-				"Need %lu pages, range is [%u, %u]\n",
-				bo->mem.num_pages, placement->fpfn,
-				placement->lpfn);
-			return -EINVAL;
-		}
-	}
-	for (i = 0; i < placement->num_placement; i++) {
-		if (!capable(CAP_SYS_ADMIN)) {
-			if (placement->placement[i] & TTM_PL_FLAG_NO_EVICT) {
-				printk(KERN_ERR TTM_PFX "Need to be root to "
-					"modify NO_EVICT status.\n");
-				return -EINVAL;
-			}
-		}
-	}
-	for (i = 0; i < placement->num_busy_placement; i++) {
-		if (!capable(CAP_SYS_ADMIN)) {
-			if (placement->busy_placement[i] & TTM_PL_FLAG_NO_EVICT) {
-				printk(KERN_ERR TTM_PFX "Need to be root to "
-					"modify NO_EVICT status.\n");
-				return -EINVAL;
-			}
-		}
-	}
 	return 0;
 }
 
@@ -1205,6 +1155,10 @@
 	num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	if (num_pages == 0) {
 		printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n");
+		if (destroy)
+			(*destroy)(bo);
+		else
+			kfree(bo);
 		return -EINVAL;
 	}
 	bo->destroy = destroy;
@@ -1341,7 +1295,6 @@
 
 int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
 {
-	struct ttm_bo_global *glob = bdev->glob;
 	struct ttm_mem_type_manager *man;
 	int ret = -EINVAL;
 
@@ -1364,13 +1317,7 @@
 	if (mem_type > 0) {
 		ttm_bo_force_list_clean(bdev, mem_type, false);
 
-		spin_lock(&glob->lru_lock);
-		if (drm_mm_clean(&man->manager))
-			drm_mm_takedown(&man->manager);
-		else
-			ret = -EBUSY;
-
-		spin_unlock(&glob->lru_lock);
+		ret = (*man->func->takedown)(man);
 	}
 
 	return ret;
@@ -1405,32 +1352,18 @@
 	int ret = -EINVAL;
 	struct ttm_mem_type_manager *man;
 
-	if (type >= TTM_NUM_MEM_TYPES) {
-		printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type);
-		return ret;
-	}
-
+	BUG_ON(type >= TTM_NUM_MEM_TYPES);
 	man = &bdev->man[type];
-	if (man->has_type) {
-		printk(KERN_ERR TTM_PFX
-		       "Memory manager already initialized for type %d\n",
-		       type);
-		return ret;
-	}
+	BUG_ON(man->has_type);
 
 	ret = bdev->driver->init_mem_type(bdev, type, man);
 	if (ret)
 		return ret;
+	man->bdev = bdev;
 
 	ret = 0;
 	if (type != TTM_PL_SYSTEM) {
-		if (!p_size) {
-			printk(KERN_ERR TTM_PFX
-			       "Zero size memory manager type %d\n",
-			       type);
-			return ret;
-		}
-		ret = drm_mm_init(&man->manager, 0, p_size);
+		ret = (*man->func->init)(man, p_size);
 		if (ret)
 			return ret;
 	}
@@ -1824,6 +1757,13 @@
 				      struct ttm_buffer_object, swap);
 		kref_get(&bo->list_kref);
 
+		if (!list_empty(&bo->ddestroy)) {
+			spin_unlock(&glob->lru_lock);
+			(void) ttm_bo_cleanup_refs(bo, false, false, false);
+			kref_put(&bo->list_kref, ttm_bo_release_list);
+			continue;
+		}
+
 		/**
 		 * Reserve buffer. Since we unlock while sleeping, we need
 		 * to re-check that nobody removed us from the swap-list while
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo_manager.c linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo_manager.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo_manager.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo_manager.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,157 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "drm_mm.h"
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+/**
+ * Currently we use a spinlock for the lock, but a mutex *may* be
+ * more appropriate to reduce scheduling latency if the range manager
+ * ends up with very fragmented allocation patterns.
+ */
+
+struct ttm_range_manager {
+	struct drm_mm mm;
+	spinlock_t lock;
+};
+
+static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
+			       struct ttm_buffer_object *bo,
+			       struct ttm_placement *placement,
+			       struct ttm_mem_reg *mem)
+{
+	struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+	struct drm_mm *mm = &rman->mm;
+	struct drm_mm_node *node = NULL;
+	unsigned long lpfn;
+	int ret;
+
+	lpfn = placement->lpfn;
+	if (!lpfn)
+		lpfn = man->size;
+	do {
+		ret = drm_mm_pre_get(mm);
+		if (unlikely(ret))
+			return ret;
+
+		spin_lock(&rman->lock);
+		node = drm_mm_search_free_in_range(mm,
+					mem->num_pages, mem->page_alignment,
+					placement->fpfn, lpfn, 1);
+		if (unlikely(node == NULL)) {
+			spin_unlock(&rman->lock);
+			return 0;
+		}
+		node = drm_mm_get_block_atomic_range(node, mem->num_pages,
+						     mem->page_alignment,
+						     placement->fpfn,
+						     lpfn);
+		spin_unlock(&rman->lock);
+	} while (node == NULL);
+
+	mem->mm_node = node;
+	mem->start = node->start;
+	return 0;
+}
+
+static void ttm_bo_man_put_node(struct ttm_mem_type_manager *man,
+				struct ttm_mem_reg *mem)
+{
+	struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+
+	if (mem->mm_node) {
+		spin_lock(&rman->lock);
+		drm_mm_put_block(mem->mm_node);
+		spin_unlock(&rman->lock);
+		mem->mm_node = NULL;
+	}
+}
+
+static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
+			   unsigned long p_size)
+{
+	struct ttm_range_manager *rman;
+	int ret;
+
+	rman = kzalloc(sizeof(*rman), GFP_KERNEL);
+	if (!rman)
+		return -ENOMEM;
+
+	ret = drm_mm_init(&rman->mm, 0, p_size);
+	if (ret) {
+		kfree(rman);
+		return ret;
+	}
+
+	spin_lock_init(&rman->lock);
+	man->priv = rman;
+	return 0;
+}
+
+static int ttm_bo_man_takedown(struct ttm_mem_type_manager *man)
+{
+	struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+	struct drm_mm *mm = &rman->mm;
+
+	spin_lock(&rman->lock);
+	if (drm_mm_clean(mm)) {
+		drm_mm_takedown(mm);
+		spin_unlock(&rman->lock);
+		kfree(rman);
+		man->priv = NULL;
+		return 0;
+	}
+	spin_unlock(&rman->lock);
+	return -EBUSY;
+}
+
+static void ttm_bo_man_debug(struct ttm_mem_type_manager *man,
+			     const char *prefix)
+{
+	struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
+
+	spin_lock(&rman->lock);
+	drm_mm_debug_table(&rman->mm, prefix);
+	spin_unlock(&rman->lock);
+}
+
+const struct ttm_mem_type_manager_func ttm_bo_manager_func = {
+	ttm_bo_man_init,
+	ttm_bo_man_takedown,
+	ttm_bo_man_get_node,
+	ttm_bo_man_put_node,
+	ttm_bo_man_debug
+};
+EXPORT_SYMBOL(ttm_bo_manager_func);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo_util.c linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo_util.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_bo_util.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_bo_util.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,14 +39,7 @@
 
 void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
 {
-	struct ttm_mem_reg *old_mem = &bo->mem;
-
-	if (old_mem->mm_node) {
-		spin_lock(&bo->glob->lru_lock);
-		drm_mm_put_block(old_mem->mm_node);
-		spin_unlock(&bo->glob->lru_lock);
-	}
-	old_mem->mm_node = NULL;
+	ttm_bo_mem_put(bo, &bo->mem);
 }
 
 int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
@@ -170,7 +163,7 @@
 	src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
 
 #ifdef CONFIG_X86
-	dst = kmap_atomic_prot(d, KM_USER0, prot);
+	dst = kmap_atomic_prot(d, prot);
 #else
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
 		dst = vmap(&d, 1, 0, prot);
@@ -183,7 +176,7 @@
 	memcpy_fromio(dst, src, PAGE_SIZE);
 
 #ifdef CONFIG_X86
-	kunmap_atomic(dst, KM_USER0);
+	kunmap_atomic(dst);
 #else
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
 		vunmap(dst);
@@ -206,7 +199,7 @@
 
 	dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
 #ifdef CONFIG_X86
-	src = kmap_atomic_prot(s, KM_USER0, prot);
+	src = kmap_atomic_prot(s, prot);
 #else
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
 		src = vmap(&s, 1, 0, prot);
@@ -219,7 +212,7 @@
 	memcpy_toio(dst, src, PAGE_SIZE);
 
 #ifdef CONFIG_X86
-	kunmap_atomic(src, KM_USER0);
+	kunmap_atomic(src);
 #else
 	if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL))
 		vunmap(src);
@@ -263,8 +256,7 @@
 	dir = 1;
 
 	if ((old_mem->mem_type == new_mem->mem_type) &&
-	    (new_mem->mm_node->start <
-	     old_mem->mm_node->start + old_mem->mm_node->size)) {
+	    (new_mem->start < old_mem->start + old_mem->size)) {
 		dir = -1;
 		add = new_mem->num_pages - 1;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_tt.c linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_tt.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/ttm/ttm_tt.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/ttm/ttm_tt.c	2011-01-04 19:50:19.000000000 -0500
@@ -440,10 +440,8 @@
 		return ret;
 
 	ret = be->func->bind(be, bo_mem);
-	if (ret) {
-		printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n");
+	if (unlikely(ret != 0))
 		return ret;
-	}
 
 	ttm->state = tt_bound;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/via/via_dmablit.c linux-libre-2.6.37-gnu/drivers/gpu/drm/via/via_dmablit.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/via/via_dmablit.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/via/via_dmablit.c	2011-01-04 19:50:19.000000000 -0500
@@ -235,9 +235,9 @@
 	vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) -
 		first_pfn + 1;
 
-	if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
+	vsg->pages = vzalloc(sizeof(struct page *) * vsg->num_pages);
+	if (NULL == vsg->pages)
 		return -ENOMEM;
-	memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
 	down_read(&current->mm->mmap_sem);
 	ret = get_user_pages(current, current->mm,
 			     (unsigned long)xfer->mem_addr,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/via/via_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/via/via_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/via/via_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/via/via_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,8 +51,6 @@
 	.reclaim_buffers_locked = NULL,
 	.reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
 	.lastclose = via_lastclose,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = via_ioctls,
 	.fops = {
 		.owner = THIS_MODULE,
@@ -62,6 +60,7 @@
 		.mmap = drm_mmap,
 		.poll = drm_poll,
 		.fasync = drm_fasync,
+		.llseek = noop_llseek,
 		},
 	.pci_driver = {
 		.name = DRIVER_NAME,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/Makefile linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -4,6 +4,6 @@
 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
 	    vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
 	    vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
-	    vmwgfx_overlay.o vmwgfx_fence.o
+	    vmwgfx_overlay.o vmwgfx_fence.o vmwgfx_gmrid_manager.o
 
 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,6 +39,9 @@
 static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
 	TTM_PL_FLAG_CACHED;
 
+static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
+	TTM_PL_FLAG_CACHED;
+
 struct ttm_placement vmw_vram_placement = {
 	.fpfn = 0,
 	.lpfn = 0,
@@ -48,6 +51,20 @@
 	.busy_placement = &vram_placement_flags
 };
 
+static uint32_t vram_gmr_placement_flags[] = {
+	TTM_PL_FLAG_VRAM | TTM_PL_FLAG_CACHED,
+	VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED
+};
+
+struct ttm_placement vmw_vram_gmr_placement = {
+	.fpfn = 0,
+	.lpfn = 0,
+	.num_placement = 2,
+	.placement = vram_gmr_placement_flags,
+	.num_busy_placement = 1,
+	.busy_placement = &gmr_placement_flags
+};
+
 struct ttm_placement vmw_vram_sys_placement = {
 	.fpfn = 0,
 	.lpfn = 0,
@@ -77,27 +94,52 @@
 
 struct vmw_ttm_backend {
 	struct ttm_backend backend;
+	struct page **pages;
+	unsigned long num_pages;
+	struct vmw_private *dev_priv;
+	int gmr_id;
 };
 
 static int vmw_ttm_populate(struct ttm_backend *backend,
 			    unsigned long num_pages, struct page **pages,
 			    struct page *dummy_read_page)
 {
+	struct vmw_ttm_backend *vmw_be =
+	    container_of(backend, struct vmw_ttm_backend, backend);
+
+	vmw_be->pages = pages;
+	vmw_be->num_pages = num_pages;
+
 	return 0;
 }
 
 static int vmw_ttm_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
 {
-	return 0;
+	struct vmw_ttm_backend *vmw_be =
+	    container_of(backend, struct vmw_ttm_backend, backend);
+
+	vmw_be->gmr_id = bo_mem->start;
+
+	return vmw_gmr_bind(vmw_be->dev_priv, vmw_be->pages,
+			    vmw_be->num_pages, vmw_be->gmr_id);
 }
 
 static int vmw_ttm_unbind(struct ttm_backend *backend)
 {
+	struct vmw_ttm_backend *vmw_be =
+	    container_of(backend, struct vmw_ttm_backend, backend);
+
+	vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
 	return 0;
 }
 
 static void vmw_ttm_clear(struct ttm_backend *backend)
 {
+	struct vmw_ttm_backend *vmw_be =
+		container_of(backend, struct vmw_ttm_backend, backend);
+
+	vmw_be->pages = NULL;
+	vmw_be->num_pages = 0;
 }
 
 static void vmw_ttm_destroy(struct ttm_backend *backend)
@@ -125,6 +167,7 @@
 		return NULL;
 
 	vmw_be->backend.func = &vmw_ttm_func;
+	vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
 
 	return &vmw_be->backend;
 }
@@ -142,15 +185,28 @@
 		/* System memory */
 
 		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
-		man->available_caching = TTM_PL_MASK_CACHING;
+		man->available_caching = TTM_PL_FLAG_CACHED;
 		man->default_caching = TTM_PL_FLAG_CACHED;
 		break;
 	case TTM_PL_VRAM:
 		/* "On-card" video ram */
+		man->func = &ttm_bo_manager_func;
 		man->gpu_offset = 0;
 		man->flags = TTM_MEMTYPE_FLAG_FIXED | TTM_MEMTYPE_FLAG_MAPPABLE;
-		man->available_caching = TTM_PL_MASK_CACHING;
-		man->default_caching = TTM_PL_FLAG_WC;
+		man->available_caching = TTM_PL_FLAG_CACHED;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case VMW_PL_GMR:
+		/*
+		 * "Guest Memory Regions" is an aperture like feature with
+		 *  one slot per bo. There is an upper limit of the number of
+		 *  slots as well as the bo size.
+		 */
+		man->func = &vmw_gmrid_manager_func;
+		man->gpu_offset = 0;
+		man->flags = TTM_MEMTYPE_FLAG_CMA | TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_FLAG_CACHED;
+		man->default_caching = TTM_PL_FLAG_CACHED;
 		break;
 	default:
 		DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
@@ -174,18 +230,6 @@
 	return 0;
 }
 
-static void vmw_move_notify(struct ttm_buffer_object *bo,
-		     struct ttm_mem_reg *new_mem)
-{
-	if (new_mem->mem_type != TTM_PL_SYSTEM)
-		vmw_dmabuf_gmr_unbind(bo);
-}
-
-static void vmw_swap_notify(struct ttm_buffer_object *bo)
-{
-	vmw_dmabuf_gmr_unbind(bo);
-}
-
 static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
 	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
@@ -200,10 +244,10 @@
 		return -EINVAL;
 	switch (mem->mem_type) {
 	case TTM_PL_SYSTEM:
-		/* System memory */
+	case VMW_PL_GMR:
 		return 0;
 	case TTM_PL_VRAM:
-		mem->bus.offset = mem->mm_node->start << PAGE_SHIFT;
+		mem->bus.offset = mem->start << PAGE_SHIFT;
 		mem->bus.base = dev_priv->vram_start;
 		mem->bus.is_iomem = true;
 		break;
@@ -276,8 +320,8 @@
 	.sync_obj_flush = vmw_sync_obj_flush,
 	.sync_obj_unref = vmw_sync_obj_unref,
 	.sync_obj_ref = vmw_sync_obj_ref,
-	.move_notify = vmw_move_notify,
-	.swap_notify = vmw_swap_notify,
+	.move_notify = NULL,
+	.swap_notify = NULL,
 	.fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
 	.io_mem_reserve = &vmw_ttm_io_mem_reserve,
 	.io_mem_free = &vmw_ttm_io_mem_free,
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c	2011-01-04 19:50:19.000000000 -0500
@@ -260,13 +260,11 @@
 	idr_init(&dev_priv->context_idr);
 	idr_init(&dev_priv->surface_idr);
 	idr_init(&dev_priv->stream_idr);
-	ida_init(&dev_priv->gmr_ida);
 	mutex_init(&dev_priv->init_mutex);
 	init_waitqueue_head(&dev_priv->fence_queue);
 	init_waitqueue_head(&dev_priv->fifo_queue);
 	atomic_set(&dev_priv->fence_queue_waiters, 0);
 	atomic_set(&dev_priv->fifo_queue_waiters, 0);
-	INIT_LIST_HEAD(&dev_priv->gmr_lru);
 
 	dev_priv->io_start = pci_resource_start(dev->pdev, 0);
 	dev_priv->vram_start = pci_resource_start(dev->pdev, 1);
@@ -341,6 +339,14 @@
 		goto out_err2;
 	}
 
+	dev_priv->has_gmr = true;
+	if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
+			   dev_priv->max_gmr_ids) != 0) {
+		DRM_INFO("No GMR memory available. "
+			 "Graphics memory resources are very limited.\n");
+		dev_priv->has_gmr = false;
+	}
+
 	dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
 					   dev_priv->mmio_size, DRM_MTRR_WC);
 
@@ -440,13 +446,14 @@
 out_err3:
 	drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
 		     dev_priv->mmio_size, DRM_MTRR_WC);
+	if (dev_priv->has_gmr)
+		(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
 	(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
 out_err2:
 	(void)ttm_bo_device_release(&dev_priv->bdev);
 out_err1:
 	vmw_ttm_global_release(dev_priv);
 out_err0:
-	ida_destroy(&dev_priv->gmr_ida);
 	idr_destroy(&dev_priv->surface_idr);
 	idr_destroy(&dev_priv->context_idr);
 	idr_destroy(&dev_priv->stream_idr);
@@ -478,10 +485,11 @@
 	iounmap(dev_priv->mmio_virt);
 	drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
 		     dev_priv->mmio_size, DRM_MTRR_WC);
+	if (dev_priv->has_gmr)
+		(void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
 	(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
 	(void)ttm_bo_device_release(&dev_priv->bdev);
 	vmw_ttm_global_release(dev_priv);
-	ida_destroy(&dev_priv->gmr_ida);
 	idr_destroy(&dev_priv->surface_idr);
 	idr_destroy(&dev_priv->context_idr);
 	idr_destroy(&dev_priv->stream_idr);
@@ -597,6 +605,8 @@
 static void vmw_master_init(struct vmw_master *vmaster)
 {
 	ttm_lock_init(&vmaster->lock);
+	INIT_LIST_HEAD(&vmaster->fb_surf);
+	mutex_init(&vmaster->fb_surf_mutex);
 }
 
 static int vmw_master_create(struct drm_device *dev,
@@ -608,7 +618,7 @@
 	if (unlikely(vmaster == NULL))
 		return -ENOMEM;
 
-	ttm_lock_init(&vmaster->lock);
+	vmw_master_init(vmaster);
 	ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
 	master->driver_priv = vmaster;
 
@@ -699,6 +709,7 @@
 
 	vmw_fp->locked_master = drm_master_get(file_priv->master);
 	ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+	vmw_kms_idle_workqueues(vmaster);
 
 	if (unlikely((ret != 0))) {
 		DRM_ERROR("Unable to lock TTM at VT switch.\n");
@@ -751,15 +762,16 @@
 		 * Buffer contents is moved to swappable memory.
 		 */
 		ttm_bo_swapout_all(&dev_priv->bdev);
+
 		break;
 	case PM_POST_HIBERNATION:
 	case PM_POST_SUSPEND:
+	case PM_POST_RESTORE:
 		ttm_suspend_unlock(&vmaster->lock);
+
 		break;
 	case PM_RESTORE_PREPARE:
 		break;
-	case PM_POST_RESTORE:
-		break;
 	default:
 		break;
 	}
@@ -770,21 +782,98 @@
  * These might not be needed with the virtual SVGA device.
  */
 
-int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct vmw_private *dev_priv = vmw_priv(dev);
+
+	if (dev_priv->num_3d_resources != 0) {
+		DRM_INFO("Can't suspend or hibernate "
+			 "while 3D resources are active.\n");
+		return -EBUSY;
+	}
+
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, PCI_D3hot);
 	return 0;
 }
 
-int vmw_pci_resume(struct pci_dev *pdev)
+static int vmw_pci_resume(struct pci_dev *pdev)
 {
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 	return pci_enable_device(pdev);
 }
 
+static int vmw_pm_suspend(struct device *kdev)
+{
+	struct pci_dev *pdev = to_pci_dev(kdev);
+	struct pm_message dummy;
+
+	dummy.event = 0;
+
+	return vmw_pci_suspend(pdev, dummy);
+}
+
+static int vmw_pm_resume(struct device *kdev)
+{
+	struct pci_dev *pdev = to_pci_dev(kdev);
+
+	return vmw_pci_resume(pdev);
+}
+
+static int vmw_pm_prepare(struct device *kdev)
+{
+	struct pci_dev *pdev = to_pci_dev(kdev);
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct vmw_private *dev_priv = vmw_priv(dev);
+
+	/**
+	 * Release 3d reference held by fbdev and potentially
+	 * stop fifo.
+	 */
+	dev_priv->suspended = true;
+	if (dev_priv->enable_fb)
+		vmw_3d_resource_dec(dev_priv);
+
+	if (dev_priv->num_3d_resources != 0) {
+
+		DRM_INFO("Can't suspend or hibernate "
+			 "while 3D resources are active.\n");
+
+		if (dev_priv->enable_fb)
+			vmw_3d_resource_inc(dev_priv);
+		dev_priv->suspended = false;
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void vmw_pm_complete(struct device *kdev)
+{
+	struct pci_dev *pdev = to_pci_dev(kdev);
+	struct drm_device *dev = pci_get_drvdata(pdev);
+	struct vmw_private *dev_priv = vmw_priv(dev);
+
+	/**
+	 * Reclaim 3d reference held by fbdev and potentially
+	 * start fifo.
+	 */
+	if (dev_priv->enable_fb)
+		vmw_3d_resource_inc(dev_priv);
+
+	dev_priv->suspended = false;
+}
+
+static const struct dev_pm_ops vmw_pm_ops = {
+	.prepare = vmw_pm_prepare,
+	.complete = vmw_pm_complete,
+	.suspend = vmw_pm_suspend,
+	.resume = vmw_pm_resume,
+};
+
 static struct drm_driver driver = {
 	.driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
 	DRIVER_MODESET,
@@ -798,8 +887,6 @@
 	.irq_handler = vmw_irq_handler,
 	.get_vblank_counter = vmw_get_vblank_counter,
 	.reclaim_buffers_locked = NULL,
-	.get_map_ofs = drm_core_get_map_ofs,
-	.get_reg_ofs = drm_core_get_reg_ofs,
 	.ioctls = vmw_ioctls,
 	.num_ioctls = DRM_ARRAY_SIZE(vmw_ioctls),
 	.dma_quiescent = NULL,	/*vmw_dma_quiescent, */
@@ -820,15 +907,17 @@
 #if defined(CONFIG_COMPAT)
 		 .compat_ioctl = drm_compat_ioctl,
 #endif
-		 },
+		 .llseek = noop_llseek,
+	},
 	.pci_driver = {
-		       .name = VMWGFX_DRIVER_NAME,
-		       .id_table = vmw_pci_id_list,
-		       .probe = vmw_probe,
-		       .remove = vmw_remove,
-		       .suspend = vmw_pci_suspend,
-		       .resume = vmw_pci_resume
-		       },
+		 .name = VMWGFX_DRIVER_NAME,
+		 .id_table = vmw_pci_id_list,
+		 .probe = vmw_probe,
+		 .remove = vmw_remove,
+		 .driver = {
+			 .pm = &vmw_pm_ops
+		 }
+	 },
 	.name = VMWGFX_DRIVER_NAME,
 	.desc = VMWGFX_DRIVER_DESC,
 	.date = VMWGFX_DRIVER_DATE,
@@ -862,3 +951,7 @@
 MODULE_AUTHOR("VMware Inc. and others");
 MODULE_DESCRIPTION("Standalone drm driver for the VMware SVGA device");
 MODULE_LICENSE("GPL and additional rights");
+MODULE_VERSION(__stringify(VMWGFX_DRIVER_MAJOR) "."
+	       __stringify(VMWGFX_DRIVER_MINOR) "."
+	       __stringify(VMWGFX_DRIVER_PATCHLEVEL) "."
+	       "0");
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h	2011-01-04 19:50:19.000000000 -0500
@@ -39,9 +39,9 @@
 #include "ttm/ttm_execbuf_util.h"
 #include "ttm/ttm_module.h"
 
-#define VMWGFX_DRIVER_DATE "20100209"
+#define VMWGFX_DRIVER_DATE "20100927"
 #define VMWGFX_DRIVER_MAJOR 1
-#define VMWGFX_DRIVER_MINOR 2
+#define VMWGFX_DRIVER_MINOR 4
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -49,6 +49,9 @@
 #define VMWGFX_MAX_GMRS 2048
 #define VMWGFX_MAX_DISPLAYS 16
 
+#define VMW_PL_GMR TTM_PL_PRIV0
+#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
+
 struct vmw_fpriv {
 	struct drm_master *locked_master;
 	struct ttm_object_file *tfile;
@@ -57,8 +60,6 @@
 struct vmw_dma_buffer {
 	struct ttm_buffer_object base;
 	struct list_head validate_list;
-	struct list_head gmr_lru;
-	uint32_t gmr_id;
 	bool gmr_bound;
 	uint32_t cur_validate_node;
 	bool on_validate_list;
@@ -151,6 +152,8 @@
 
 struct vmw_master {
 	struct ttm_lock lock;
+	struct mutex fb_surf_mutex;
+	struct list_head fb_surf;
 };
 
 struct vmw_vga_topology_state {
@@ -182,6 +185,7 @@
 	uint32_t capabilities;
 	uint32_t max_gmr_descriptors;
 	uint32_t max_gmr_ids;
+	bool has_gmr;
 	struct mutex hw_mutex;
 
 	/*
@@ -264,14 +268,6 @@
 	struct mutex cmdbuf_mutex;
 
 	/**
-	 * GMR management. Protected by the lru spinlock.
-	 */
-
-	struct ida gmr_ida;
-	struct list_head gmr_lru;
-
-
-	/**
 	 * Operating mode.
 	 */
 
@@ -286,6 +282,7 @@
 	struct vmw_master *active_master;
 	struct vmw_master fbdev_master;
 	struct notifier_block pm_nb;
+	bool suspended;
 
 	struct mutex release_mutex;
 	uint32_t num_3d_resources;
@@ -331,7 +328,9 @@
  */
 
 extern int vmw_gmr_bind(struct vmw_private *dev_priv,
-			struct ttm_buffer_object *bo);
+			struct page *pages[],
+			unsigned long num_pages,
+			int gmr_id);
 extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
 
 /**
@@ -380,14 +379,10 @@
 extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
 extern int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
 				  uint32_t id, struct vmw_dma_buffer **out);
-extern uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo);
-extern void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id);
-extern int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id);
 extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
 				       struct vmw_dma_buffer *bo);
 extern int vmw_dmabuf_from_vram(struct vmw_private *vmw_priv,
 				struct vmw_dma_buffer *bo);
-extern void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo);
 extern int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
 				  struct drm_file *file_priv);
 extern int vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
@@ -439,6 +434,7 @@
 extern struct ttm_placement vmw_vram_placement;
 extern struct ttm_placement vmw_vram_ne_placement;
 extern struct ttm_placement vmw_vram_sys_placement;
+extern struct ttm_placement vmw_vram_gmr_placement;
 extern struct ttm_placement vmw_sys_placement;
 extern struct ttm_bo_driver vmw_bo_driver;
 extern int vmw_dma_quiescent(struct drm_device *dev);
@@ -518,6 +514,10 @@
 			unsigned bbp, unsigned depth);
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster);
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+				uint32_t pitch,
+				uint32_t height);
 u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc);
 
 /**
@@ -537,6 +537,12 @@
 int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
 
 /**
+ * GMR Id manager
+ */
+
+extern const struct ttm_mem_type_manager_func vmw_gmrid_manager_func;
+
+/**
  * Inline helper functions
  */
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c	2011-01-04 19:50:19.000000000 -0500
@@ -538,8 +538,11 @@
 		reloc = &sw_context->relocs[i];
 		validate = &sw_context->val_bufs[reloc->index];
 		bo = validate->bo;
-		reloc->location->offset += bo->offset;
-		reloc->location->gmrId = vmw_dmabuf_gmr(bo);
+		if (bo->mem.mem_type == TTM_PL_VRAM) {
+			reloc->location->offset += bo->offset;
+			reloc->location->gmrId = SVGA_GMR_FRAMEBUFFER;
+		} else
+			reloc->location->gmrId = bo->mem.start;
 	}
 	vmw_free_relocations(sw_context);
 }
@@ -563,25 +566,14 @@
 {
 	int ret;
 
-	if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
-		return 0;
-
-	/**
-	 * Put BO in VRAM, only if there is space.
-	 */
-
-	ret = ttm_bo_validate(bo, &vmw_vram_sys_placement, true, false, false);
-	if (unlikely(ret == -ERESTARTSYS))
-		return ret;
-
 	/**
-	 * Otherwise, set it up as GMR.
+	 * Put BO in VRAM if there is space, otherwise as a GMR.
+	 * If there is no space in VRAM and GMR ids are all used up,
+	 * start evicting GMRs to make room. If the DMA buffer can't be
+	 * used as a GMR, this will return -ENOMEM.
 	 */
 
-	if (vmw_dmabuf_gmr(bo) != SVGA_GMR_NULL)
-		return 0;
-
-	ret = vmw_gmr_bind(dev_priv, bo);
+	ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false, false);
 	if (likely(ret == 0 || ret == -ERESTARTSYS))
 		return ret;
 
@@ -590,6 +582,7 @@
 	 * previous contents.
 	 */
 
+	DRM_INFO("Falling through to VRAM.\n");
 	ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false, false);
 	return ret;
 }
@@ -698,6 +691,7 @@
 
 	fence_rep.error = ret;
 	fence_rep.fence_seq = (uint64_t) sequence;
+	fence_rep.pad64 = 0;
 
 	user_fence_rep = (struct drm_vmw_fence_rep __user *)
 	    (unsigned long)arg->fence_rep;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c	2011-01-04 19:50:19.000000000 -0500
@@ -144,6 +144,13 @@
 		return -EINVAL;
 	}
 
+	if (!vmw_kms_validate_mode_vram(vmw_priv,
+					info->fix.line_length,
+					var->yoffset + var->yres)) {
+		DRM_ERROR("Requested geom can not fit in framebuffer\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -205,6 +212,9 @@
 		SVGAFifoCmdUpdate body;
 	} *cmd;
 
+	if (vmw_priv->suspended)
+		return;
+
 	spin_lock_irqsave(&par->dirty.lock, flags);
 	if (!par->dirty.active) {
 		spin_unlock_irqrestore(&par->dirty.lock, flags);
@@ -616,7 +626,8 @@
 		goto err_unlock;
 
 	if (bo->mem.mem_type == TTM_PL_VRAM &&
-	    bo->mem.mm_node->start < bo->num_pages)
+	    bo->mem.start < bo->num_pages &&
+	    bo->mem.start > 0)
 		(void) ttm_bo_validate(bo, &vmw_sys_placement, false,
 				       false, false);
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c	2011-01-04 19:50:19.000000000 -0500
@@ -545,7 +545,7 @@
 	struct drm_file *file_priv;
 	struct vmw_private *dev_priv;
 
-	file_priv = (struct drm_file *)filp->private_data;
+	file_priv = filp->private_data;
 	dev_priv = vmw_priv(file_priv->minor->dev);
 
 	if (vma->vm_pgoff != (dev_priv->mmio_start >> PAGE_SHIFT) ||
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,7 +146,7 @@
  */
 
 static unsigned long vmw_gmr_count_descriptors(struct page *pages[],
-					       unsigned long num_pages)
+					unsigned long num_pages)
 {
 	unsigned long prev_pfn = ~(0UL);
 	unsigned long pfn;
@@ -163,45 +163,33 @@
 }
 
 int vmw_gmr_bind(struct vmw_private *dev_priv,
-		 struct ttm_buffer_object *bo)
+		 struct page *pages[],
+		 unsigned long num_pages,
+		 int gmr_id)
 {
-	struct ttm_tt *ttm = bo->ttm;
-	unsigned long descriptors;
-	int ret;
-	uint32_t id;
 	struct list_head desc_pages;
+	int ret;
 
-	if (!(dev_priv->capabilities & SVGA_CAP_GMR))
+	if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR)))
 		return -EINVAL;
 
-	ret = ttm_tt_populate(ttm);
-	if (unlikely(ret != 0))
-		return ret;
-
-	descriptors = vmw_gmr_count_descriptors(ttm->pages, ttm->num_pages);
-	if (unlikely(descriptors > dev_priv->max_gmr_descriptors))
+	if (vmw_gmr_count_descriptors(pages, num_pages) >
+	    dev_priv->max_gmr_descriptors)
 		return -EINVAL;
 
 	INIT_LIST_HEAD(&desc_pages);
-	ret = vmw_gmr_build_descriptors(&desc_pages, ttm->pages,
-					ttm->num_pages);
-	if (unlikely(ret != 0))
-		return ret;
 
-	ret = vmw_gmr_id_alloc(dev_priv, &id);
+	ret = vmw_gmr_build_descriptors(&desc_pages, pages, num_pages);
 	if (unlikely(ret != 0))
-		goto out_no_id;
+		return ret;
 
-	vmw_gmr_fire_descriptors(dev_priv, id, &desc_pages);
+	vmw_gmr_fire_descriptors(dev_priv, gmr_id, &desc_pages);
 	vmw_gmr_free_descriptors(&desc_pages);
-	vmw_dmabuf_set_gmr(bo, id);
-	return 0;
 
-out_no_id:
-	vmw_gmr_free_descriptors(&desc_pages);
-	return ret;
+	return 0;
 }
 
+
 void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
 {
 	mutex_lock(&dev_priv->hw_mutex);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,137 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 (including the
+ * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "vmwgfx_drv.h"
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/idr.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+
+struct vmwgfx_gmrid_man {
+	spinlock_t lock;
+	struct ida gmr_ida;
+	uint32_t max_gmr_ids;
+};
+
+static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
+				  struct ttm_buffer_object *bo,
+				  struct ttm_placement *placement,
+				  struct ttm_mem_reg *mem)
+{
+	struct vmwgfx_gmrid_man *gman =
+		(struct vmwgfx_gmrid_man *)man->priv;
+	int ret;
+	int id;
+
+	mem->mm_node = NULL;
+
+	do {
+		if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0))
+			return -ENOMEM;
+
+		spin_lock(&gman->lock);
+		ret = ida_get_new(&gman->gmr_ida, &id);
+
+		if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
+			ida_remove(&gman->gmr_ida, id);
+			spin_unlock(&gman->lock);
+			return 0;
+		}
+
+		spin_unlock(&gman->lock);
+
+	} while (ret == -EAGAIN);
+
+	if (likely(ret == 0)) {
+		mem->mm_node = gman;
+		mem->start = id;
+	}
+
+	return ret;
+}
+
+static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
+				   struct ttm_mem_reg *mem)
+{
+	struct vmwgfx_gmrid_man *gman =
+		(struct vmwgfx_gmrid_man *)man->priv;
+
+	if (mem->mm_node) {
+		spin_lock(&gman->lock);
+		ida_remove(&gman->gmr_ida, mem->start);
+		spin_unlock(&gman->lock);
+		mem->mm_node = NULL;
+	}
+}
+
+static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
+			      unsigned long p_size)
+{
+	struct vmwgfx_gmrid_man *gman =
+		kzalloc(sizeof(*gman), GFP_KERNEL);
+
+	if (unlikely(gman == NULL))
+		return -ENOMEM;
+
+	spin_lock_init(&gman->lock);
+	ida_init(&gman->gmr_ida);
+	gman->max_gmr_ids = p_size;
+	man->priv = (void *) gman;
+	return 0;
+}
+
+static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
+{
+	struct vmwgfx_gmrid_man *gman =
+		(struct vmwgfx_gmrid_man *)man->priv;
+
+	if (gman) {
+		ida_destroy(&gman->gmr_ida);
+		kfree(gman);
+	}
+	return 0;
+}
+
+static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
+				const char *prefix)
+{
+	printk(KERN_INFO "%s: No debug info available for the GMR "
+	       "id manager.\n", prefix);
+}
+
+const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
+	vmw_gmrid_man_init,
+	vmw_gmrid_man_takedown,
+	vmw_gmrid_man_get_node,
+	vmw_gmrid_man_put_node,
+	vmw_gmrid_man_debug
+};
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,6 +54,9 @@
 	case DRM_VMW_PARAM_FIFO_CAPS:
 		param->value = dev_priv->fifo.capabilities;
 		break;
+	case DRM_VMW_PARAM_MAX_FB_SIZE:
+		param->value = dev_priv->vram_size;
+		break;
 	default:
 		DRM_ERROR("Illegal vmwgfx get param request: %d\n",
 			  param->param);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c	2011-01-04 19:50:19.000000000 -0500
@@ -332,18 +332,55 @@
 	struct delayed_work d_work;
 	struct mutex work_lock;
 	bool present_fs;
+	struct list_head head;
+	struct drm_master *master;
 };
 
+/**
+ * vmw_kms_idle_workqueues - Flush workqueues on this master
+ *
+ * @vmaster - Pointer identifying the master, for the surfaces of which
+ * we idle the dirty work queues.
+ *
+ * This function should be called with the ttm lock held in exclusive mode
+ * to idle all dirty work queues before the fifo is taken down.
+ *
+ * The work task may actually requeue itself, but after the flush returns we're
+ * sure that there's nothing to present, since the ttm lock is held in
+ * exclusive mode, so the fifo will never get used.
+ */
+
+void vmw_kms_idle_workqueues(struct vmw_master *vmaster)
+{
+	struct vmw_framebuffer_surface *entry;
+
+	mutex_lock(&vmaster->fb_surf_mutex);
+	list_for_each_entry(entry, &vmaster->fb_surf, head) {
+		if (cancel_delayed_work_sync(&entry->d_work))
+			(void) entry->d_work.work.func(&entry->d_work.work);
+
+		(void) cancel_delayed_work_sync(&entry->d_work);
+	}
+	mutex_unlock(&vmaster->fb_surf_mutex);
+}
+
 void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
 {
-	struct vmw_framebuffer_surface *vfb =
+	struct vmw_framebuffer_surface *vfbs =
 		vmw_framebuffer_to_vfbs(framebuffer);
+	struct vmw_master *vmaster = vmw_master(vfbs->master);
 
-	cancel_delayed_work_sync(&vfb->d_work);
+
+	mutex_lock(&vmaster->fb_surf_mutex);
+	list_del(&vfbs->head);
+	mutex_unlock(&vmaster->fb_surf_mutex);
+
+	cancel_delayed_work_sync(&vfbs->d_work);
+	drm_master_put(&vfbs->master);
 	drm_framebuffer_cleanup(framebuffer);
-	vmw_surface_unreference(&vfb->surface);
+	vmw_surface_unreference(&vfbs->surface);
 
-	kfree(framebuffer);
+	kfree(vfbs);
 }
 
 static void vmw_framebuffer_present_fs_callback(struct work_struct *work)
@@ -362,6 +399,12 @@
 		SVGA3dCopyRect cr;
 	} *cmd;
 
+	/**
+	 * Strictly we should take the ttm_lock in read mode before accessing
+	 * the fifo, to make sure the fifo is present and up. However,
+	 * instead we flush all workqueues under the ttm lock in exclusive mode
+	 * before taking down the fifo.
+	 */
 	mutex_lock(&vfbs->work_lock);
 	if (!vfbs->present_fs)
 		goto out_unlock;
@@ -392,17 +435,20 @@
 
 
 int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+				  struct drm_file *file_priv,
 				  unsigned flags, unsigned color,
 				  struct drm_clip_rect *clips,
 				  unsigned num_clips)
 {
 	struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+	struct vmw_master *vmaster = vmw_master(file_priv->master);
 	struct vmw_framebuffer_surface *vfbs =
 		vmw_framebuffer_to_vfbs(framebuffer);
 	struct vmw_surface *surf = vfbs->surface;
 	struct drm_clip_rect norect;
 	SVGA3dCopyRect *cr;
 	int i, inc = 1;
+	int ret;
 
 	struct {
 		SVGA3dCmdHeader header;
@@ -410,6 +456,13 @@
 		SVGA3dCopyRect cr;
 	} *cmd;
 
+	if (unlikely(vfbs->master != file_priv->master))
+		return -EINVAL;
+
+	ret = ttm_read_lock(&vmaster->lock, true);
+	if (unlikely(ret != 0))
+		return ret;
+
 	if (!num_clips ||
 	    !(dev_priv->fifo.capabilities &
 	      SVGA_FIFO_CAP_SCREEN_OBJECT)) {
@@ -425,6 +478,7 @@
 			 */
 			vmw_framebuffer_present_fs_callback(&vfbs->d_work.work);
 		}
+		ttm_read_unlock(&vmaster->lock);
 		return 0;
 	}
 
@@ -442,6 +496,7 @@
 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
 	if (unlikely(cmd == NULL)) {
 		DRM_ERROR("Fifo reserve failed.\n");
+		ttm_read_unlock(&vmaster->lock);
 		return -ENOMEM;
 	}
 
@@ -461,7 +516,7 @@
 	}
 
 	vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * sizeof(cmd->cr));
-
+	ttm_read_unlock(&vmaster->lock);
 	return 0;
 }
 
@@ -471,16 +526,57 @@
 	.create_handle = vmw_framebuffer_create_handle,
 };
 
-int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
-				    struct vmw_surface *surface,
-				    struct vmw_framebuffer **out,
-				    unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
+					   struct drm_file *file_priv,
+					   struct vmw_surface *surface,
+					   struct vmw_framebuffer **out,
+					   const struct drm_mode_fb_cmd
+					   *mode_cmd)
 
 {
 	struct drm_device *dev = dev_priv->dev;
 	struct vmw_framebuffer_surface *vfbs;
+	enum SVGA3dSurfaceFormat format;
+	struct vmw_master *vmaster = vmw_master(file_priv->master);
 	int ret;
 
+	/*
+	 * Sanity checks.
+	 */
+
+	if (unlikely(surface->mip_levels[0] != 1 ||
+		     surface->num_sizes != 1 ||
+		     surface->sizes[0].width < mode_cmd->width ||
+		     surface->sizes[0].height < mode_cmd->height ||
+		     surface->sizes[0].depth != 1)) {
+		DRM_ERROR("Incompatible surface dimensions "
+			  "for requested mode.\n");
+		return -EINVAL;
+	}
+
+	switch (mode_cmd->depth) {
+	case 32:
+		format = SVGA3D_A8R8G8B8;
+		break;
+	case 24:
+		format = SVGA3D_X8R8G8B8;
+		break;
+	case 16:
+		format = SVGA3D_R5G6B5;
+		break;
+	case 15:
+		format = SVGA3D_A1R5G5B5;
+		break;
+	default:
+		DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth);
+		return -EINVAL;
+	}
+
+	if (unlikely(format != surface->format)) {
+		DRM_ERROR("Invalid surface format for requested mode.\n");
+		return -EINVAL;
+	}
+
 	vfbs = kzalloc(sizeof(*vfbs), GFP_KERNEL);
 	if (!vfbs) {
 		ret = -ENOMEM;
@@ -498,16 +594,22 @@
 	}
 
 	/* XXX get the first 3 from the surface info */
-	vfbs->base.base.bits_per_pixel = 32;
-	vfbs->base.base.pitch = width * 32 / 4;
-	vfbs->base.base.depth = 24;
-	vfbs->base.base.width = width;
-	vfbs->base.base.height = height;
+	vfbs->base.base.bits_per_pixel = mode_cmd->bpp;
+	vfbs->base.base.pitch = mode_cmd->pitch;
+	vfbs->base.base.depth = mode_cmd->depth;
+	vfbs->base.base.width = mode_cmd->width;
+	vfbs->base.base.height = mode_cmd->height;
 	vfbs->base.pin = &vmw_surface_dmabuf_pin;
 	vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
 	vfbs->surface = surface;
+	vfbs->master = drm_master_get(file_priv->master);
 	mutex_init(&vfbs->work_lock);
+
+	mutex_lock(&vmaster->fb_surf_mutex);
 	INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
+	list_add_tail(&vfbs->head, &vmaster->fb_surf);
+	mutex_unlock(&vmaster->fb_surf_mutex);
+
 	*out = &vfbs->base;
 
 	return 0;
@@ -544,18 +646,25 @@
 }
 
 int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+				 struct drm_file *file_priv,
 				 unsigned flags, unsigned color,
 				 struct drm_clip_rect *clips,
 				 unsigned num_clips)
 {
 	struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
+	struct vmw_master *vmaster = vmw_master(file_priv->master);
 	struct drm_clip_rect norect;
+	int ret;
 	struct {
 		uint32_t header;
 		SVGAFifoCmdUpdate body;
 	} *cmd;
 	int i, increment = 1;
 
+	ret = ttm_read_lock(&vmaster->lock, true);
+	if (unlikely(ret != 0))
+		return ret;
+
 	if (!num_clips) {
 		num_clips = 1;
 		clips = &norect;
@@ -570,6 +679,7 @@
 	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips);
 	if (unlikely(cmd == NULL)) {
 		DRM_ERROR("Fifo reserve failed.\n");
+		ttm_read_unlock(&vmaster->lock);
 		return -ENOMEM;
 	}
 
@@ -582,6 +692,7 @@
 	}
 
 	vmw_fifo_commit(dev_priv, sizeof(*cmd) * num_clips);
+	ttm_read_unlock(&vmaster->lock);
 
 	return 0;
 }
@@ -609,6 +720,8 @@
 			       &vmw_vram_ne_placement,
 			       false, &vmw_dmabuf_bo_free);
 	vmw_overlay_resume_all(dev_priv);
+	if (unlikely(ret != 0))
+		vfbs->buffer = NULL;
 
 	return ret;
 }
@@ -619,6 +732,9 @@
 	struct vmw_framebuffer_surface *vfbs =
 		vmw_framebuffer_to_vfbs(&vfb->base);
 
+	if (unlikely(vfbs->buffer == NULL))
+		return 0;
+
 	bo = &vfbs->buffer->base;
 	ttm_bo_unref(&bo);
 	vfbs->buffer = NULL;
@@ -659,16 +775,25 @@
 	return vmw_dmabuf_from_vram(dev_priv, vfbd->buffer);
 }
 
-int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
-				   struct vmw_dma_buffer *dmabuf,
-				   struct vmw_framebuffer **out,
-				   unsigned width, unsigned height)
+static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
+					  struct vmw_dma_buffer *dmabuf,
+					  struct vmw_framebuffer **out,
+					  const struct drm_mode_fb_cmd
+					  *mode_cmd)
 
 {
 	struct drm_device *dev = dev_priv->dev;
 	struct vmw_framebuffer_dmabuf *vfbd;
+	unsigned int requested_size;
 	int ret;
 
+	requested_size = mode_cmd->height * mode_cmd->pitch;
+	if (unlikely(requested_size > dmabuf->base.num_pages * PAGE_SIZE)) {
+		DRM_ERROR("Screen buffer object size is too small "
+			  "for requested mode.\n");
+		return -EINVAL;
+	}
+
 	vfbd = kzalloc(sizeof(*vfbd), GFP_KERNEL);
 	if (!vfbd) {
 		ret = -ENOMEM;
@@ -685,12 +810,11 @@
 		goto out_err3;
 	}
 
-	/* XXX get the first 3 from the surface info */
-	vfbd->base.base.bits_per_pixel = 32;
-	vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
-	vfbd->base.base.depth = 24;
-	vfbd->base.base.width = width;
-	vfbd->base.base.height = height;
+	vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
+	vfbd->base.base.pitch = mode_cmd->pitch;
+	vfbd->base.base.depth = mode_cmd->depth;
+	vfbd->base.base.width = mode_cmd->width;
+	vfbd->base.base.height = mode_cmd->height;
 	vfbd->base.pin = vmw_framebuffer_dmabuf_pin;
 	vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin;
 	vfbd->buffer = dmabuf;
@@ -719,8 +843,25 @@
 	struct vmw_framebuffer *vfb = NULL;
 	struct vmw_surface *surface = NULL;
 	struct vmw_dma_buffer *bo = NULL;
+	u64 required_size;
 	int ret;
 
+	/**
+	 * This code should be conditioned on Screen Objects not being used.
+	 * If screen objects are used, we can allocate a GMR to hold the
+	 * requested framebuffer.
+	 */
+
+	required_size = mode_cmd->pitch * mode_cmd->height;
+	if (unlikely(required_size > (u64) dev_priv->vram_size)) {
+		DRM_ERROR("VRAM size is too small for requested mode.\n");
+		return NULL;
+	}
+
+	/**
+	 * End conditioned code.
+	 */
+
 	ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
 					     mode_cmd->handle, &surface);
 	if (ret)
@@ -729,8 +870,8 @@
 	if (!surface->scanout)
 		goto err_not_scanout;
 
-	ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb,
-					      mode_cmd->width, mode_cmd->height);
+	ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface,
+					      &vfb, mode_cmd);
 
 	/* vmw_user_surface_lookup takes one ref so does new_fb */
 	vmw_surface_unreference(&surface);
@@ -751,7 +892,7 @@
 	}
 
 	ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
-					     mode_cmd->width, mode_cmd->height);
+					     mode_cmd);
 
 	/* vmw_user_dmabuf_lookup takes one ref so does new_fb */
 	vmw_dmabuf_unreference(&bo);
@@ -889,6 +1030,9 @@
 	vmw_priv->num_displays = vmw_read(vmw_priv,
 					  SVGA_REG_NUM_GUEST_DISPLAYS);
 
+	if (vmw_priv->num_displays == 0)
+		vmw_priv->num_displays = 1;
+
 	for (i = 0; i < vmw_priv->num_displays; ++i) {
 		save = &vmw_priv->vga_save[i];
 		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
@@ -997,6 +1141,13 @@
 	return ret;
 }
 
+bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
+				uint32_t pitch,
+				uint32_t height)
+{
+	return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size;
+}
+
 u32 vmw_get_vblank_counter(struct drm_device *dev, int crtc)
 {
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c	2011-01-04 19:50:19.000000000 -0500
@@ -427,7 +427,9 @@
 {
 	struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
 	struct drm_device *dev = connector->dev;
+	struct vmw_private *dev_priv = vmw_priv(dev);
 	struct drm_display_mode *mode = NULL;
+	struct drm_display_mode *bmode;
 	struct drm_display_mode prefmode = { DRM_MODE("preferred",
 		DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -443,22 +445,30 @@
 		mode->hdisplay = ldu->pref_width;
 		mode->vdisplay = ldu->pref_height;
 		mode->vrefresh = drm_mode_vrefresh(mode);
-		drm_mode_probed_add(connector, mode);
+		if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2,
+					       mode->vdisplay)) {
+			drm_mode_probed_add(connector, mode);
 
-		if (ldu->pref_mode) {
-			list_del_init(&ldu->pref_mode->head);
-			drm_mode_destroy(dev, ldu->pref_mode);
-		}
+			if (ldu->pref_mode) {
+				list_del_init(&ldu->pref_mode->head);
+				drm_mode_destroy(dev, ldu->pref_mode);
+			}
 
-		ldu->pref_mode = mode;
+			ldu->pref_mode = mode;
+		}
 	}
 
 	for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
-		if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
-		    vmw_ldu_connector_builtin[i].vdisplay > max_height)
+		bmode = &vmw_ldu_connector_builtin[i];
+		if (bmode->hdisplay > max_width ||
+		    bmode->vdisplay > max_height)
 			continue;
 
-		mode = drm_mode_duplicate(dev, &vmw_ldu_connector_builtin[i]);
+		if (!vmw_kms_validate_mode_vram(dev_priv, bmode->hdisplay * 2,
+						bmode->vdisplay))
+			continue;
+
+		mode = drm_mode_duplicate(dev, bmode);
 		if (!mode)
 			return 0;
 		mode->vrefresh = drm_mode_vrefresh(mode);
@@ -547,7 +557,7 @@
 		return -EINVAL;
 	}
 
-	dev_priv->ldu_priv = kmalloc(GFP_KERNEL, sizeof(*dev_priv->ldu_priv));
+	dev_priv->ldu_priv = kmalloc(sizeof(*dev_priv->ldu_priv), GFP_KERNEL);
 
 	if (!dev_priv->ldu_priv)
 		return -ENOMEM;
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c	2011-01-04 19:50:19.000000000 -0500
@@ -585,7 +585,7 @@
 		return -ENOSYS;
 	}
 
-	overlay = kmalloc(GFP_KERNEL, sizeof(*overlay));
+	overlay = kmalloc(sizeof(*overlay), GFP_KERNEL);
 	if (!overlay)
 		return -ENOMEM;
 
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c	2011-01-04 19:50:19.000000000 -0500
@@ -765,28 +765,11 @@
 	return bo_user_size + page_array_size;
 }
 
-void vmw_dmabuf_gmr_unbind(struct ttm_buffer_object *bo)
-{
-	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
-	struct ttm_bo_global *glob = bo->glob;
-	struct vmw_private *dev_priv =
-		container_of(bo->bdev, struct vmw_private, bdev);
-
-	if (vmw_bo->gmr_bound) {
-		vmw_gmr_unbind(dev_priv, vmw_bo->gmr_id);
-		spin_lock(&glob->lru_lock);
-		ida_remove(&dev_priv->gmr_ida, vmw_bo->gmr_id);
-		spin_unlock(&glob->lru_lock);
-		vmw_bo->gmr_bound = false;
-	}
-}
-
 void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
 {
 	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
 	struct ttm_bo_global *glob = bo->glob;
 
-	vmw_dmabuf_gmr_unbind(bo);
 	ttm_mem_global_free(glob->mem_glob, bo->acc_size);
 	kfree(vmw_bo);
 }
@@ -818,10 +801,7 @@
 
 	memset(vmw_bo, 0, sizeof(*vmw_bo));
 
-	INIT_LIST_HEAD(&vmw_bo->gmr_lru);
 	INIT_LIST_HEAD(&vmw_bo->validate_list);
-	vmw_bo->gmr_id = 0;
-	vmw_bo->gmr_bound = false;
 
 	ret = ttm_bo_init(bdev, &vmw_bo->base, size,
 			  ttm_bo_type_device, placement,
@@ -835,7 +815,6 @@
 	struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
 	struct ttm_bo_global *glob = bo->glob;
 
-	vmw_dmabuf_gmr_unbind(bo);
 	ttm_mem_global_free(glob->mem_glob, bo->acc_size);
 	kfree(vmw_user_bo);
 }
@@ -883,7 +862,7 @@
 			      &vmw_vram_sys_placement, true,
 			      &vmw_user_dmabuf_destroy);
 	if (unlikely(ret != 0))
-		return ret;
+		goto out_no_dmabuf;
 
 	tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
 	ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
@@ -891,19 +870,21 @@
 				   false,
 				   ttm_buffer_type,
 				   &vmw_user_dmabuf_release, NULL);
-	if (unlikely(ret != 0)) {
-		ttm_bo_unref(&tmp);
-	} else {
+	if (unlikely(ret != 0))
+		goto out_no_base_object;
+	else {
 		rep->handle = vmw_user_bo->base.hash.key;
 		rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
 		rep->cur_gmr_id = vmw_user_bo->base.hash.key;
 		rep->cur_gmr_offset = 0;
 	}
-	ttm_bo_unref(&tmp);
 
+out_no_base_object:
+	ttm_bo_unref(&tmp);
+out_no_dmabuf:
 	ttm_read_unlock(&vmaster->lock);
 
-	return 0;
+	return ret;
 }
 
 int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
@@ -938,25 +919,6 @@
 	vmw_bo->on_validate_list = false;
 }
 
-uint32_t vmw_dmabuf_gmr(struct ttm_buffer_object *bo)
-{
-	struct vmw_dma_buffer *vmw_bo;
-
-	if (bo->mem.mem_type == TTM_PL_VRAM)
-		return SVGA_GMR_FRAMEBUFFER;
-
-	vmw_bo = vmw_dma_buffer(bo);
-
-	return (vmw_bo->gmr_bound) ? vmw_bo->gmr_id : SVGA_GMR_NULL;
-}
-
-void vmw_dmabuf_set_gmr(struct ttm_buffer_object *bo, uint32_t id)
-{
-	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
-	vmw_bo->gmr_bound = true;
-	vmw_bo->gmr_id = id;
-}
-
 int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
 			   uint32_t handle, struct vmw_dma_buffer **out)
 {
@@ -985,41 +947,6 @@
 	return 0;
 }
 
-/**
- * TODO: Implement a gmr id eviction mechanism. Currently we just fail
- * when we're out of ids, causing GMR space to be allocated
- * out of VRAM.
- */
-
-int vmw_gmr_id_alloc(struct vmw_private *dev_priv, uint32_t *p_id)
-{
-	struct ttm_bo_global *glob = dev_priv->bdev.glob;
-	int id;
-	int ret;
-
-	do {
-		if (unlikely(ida_pre_get(&dev_priv->gmr_ida, GFP_KERNEL) == 0))
-			return -ENOMEM;
-
-		spin_lock(&glob->lru_lock);
-		ret = ida_get_new(&dev_priv->gmr_ida, &id);
-		spin_unlock(&glob->lru_lock);
-	} while (ret == -EAGAIN);
-
-	if (unlikely(ret != 0))
-		return ret;
-
-	if (unlikely(id >= dev_priv->max_gmr_ids)) {
-		spin_lock(&glob->lru_lock);
-		ida_remove(&dev_priv->gmr_ida, id);
-		spin_unlock(&glob->lru_lock);
-		return -EBUSY;
-	}
-
-	*p_id = (uint32_t) id;
-	return 0;
-}
-
 /*
  * Stream management
  */
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c
--- linux-libre-2.6.36-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c	2011-01-04 19:50:19.000000000 -0500
@@ -39,7 +39,7 @@
 		return drm_mmap(filp, vma);
 	}
 
-	file_priv = (struct drm_file *)filp->private_data;
+	file_priv = filp->private_data;
 	dev_priv = vmw_priv(file_priv->minor->dev);
 	return ttm_bo_mmap(filp, vma, &dev_priv->bdev);
 }
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/Makefile linux-libre-2.6.37-gnu/drivers/gpu/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1 +1 @@
-obj-y			+= drm/ vga/
+obj-y			+= drm/ vga/ stub/
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/stub/Kconfig linux-libre-2.6.37-gnu/drivers/gpu/stub/Kconfig
--- linux-libre-2.6.36-gnu/drivers/gpu/stub/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/stub/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,16 @@
+config STUB_POULSBO
+	tristate "Intel GMA500 Stub Driver"
+	depends on PCI
+	# Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled
+	# but for select to work, need to select ACPI_VIDEO's dependencies, ick
+	select VIDEO_OUTPUT_CONTROL if ACPI
+	select BACKLIGHT_CLASS_DEVICE if ACPI
+	select INPUT if ACPI
+	select ACPI_VIDEO if ACPI
+	help
+	  Choose this option if you have a system that has Intel GMA500
+	  (Poulsbo) integrated graphics. If M is selected, the module will
+	  be called Poulsbo. This driver is a stub driver for Poulsbo that
+	  will call poulsbo.ko to enable the acpi backlight control sysfs
+	  entry file because there have no poulsbo native driver can support
+	  intel opregion.
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/stub/Makefile linux-libre-2.6.37-gnu/drivers/gpu/stub/Makefile
--- linux-libre-2.6.36-gnu/drivers/gpu/stub/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/stub/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1 @@
+obj-$(CONFIG_STUB_POULSBO) += poulsbo.o
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/stub/poulsbo.c linux-libre-2.6.37-gnu/drivers/gpu/stub/poulsbo.c
--- linux-libre-2.6.36-gnu/drivers/gpu/stub/poulsbo.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/gpu/stub/poulsbo.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,64 @@
+/*
+ * Intel Poulsbo Stub driver
+ *
+ * Copyright (C) 2010 Novell <jlee@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/video.h>
+
+#define DRIVER_NAME "poulsbo"
+
+enum {
+	CHIP_PSB_8108 = 0,
+	CHIP_PSB_8109 = 1,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+	{0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8108}, \
+	{0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PSB_8109}, \
+	{0, 0, 0}
+};
+
+static int poulsbo_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return acpi_video_register();
+}
+
+static void poulsbo_remove(struct pci_dev *pdev)
+{
+	acpi_video_unregister();
+}
+
+static struct pci_driver poulsbo_driver = {
+	.name = DRIVER_NAME,
+	.id_table = pciidlist,
+	.probe = poulsbo_probe,
+	.remove = poulsbo_remove,
+};
+
+static int __init poulsbo_init(void)
+{
+	return pci_register_driver(&poulsbo_driver);
+}
+
+static void __exit poulsbo_exit(void)
+{
+	pci_unregister_driver(&poulsbo_driver);
+}
+
+module_init(poulsbo_init);
+module_exit(poulsbo_exit);
+
+MODULE_AUTHOR("Lee, Chun-Yi <jlee@novell.com>");
+MODULE_DESCRIPTION("Poulsbo Stub Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
diff -druN linux-libre-2.6.36-gnu/drivers/gpu/vga/vgaarb.c linux-libre-2.6.37-gnu/drivers/gpu/vga/vgaarb.c
--- linux-libre-2.6.36-gnu/drivers/gpu/vga/vgaarb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/gpu/vga/vgaarb.c	2011-01-04 19:50:19.000000000 -0500
@@ -1211,6 +1211,7 @@
 	.poll = vga_arb_fpoll,
 	.open = vga_arb_open,
 	.release = vga_arb_release,
+	.llseek = noop_llseek,
 };
 
 static struct miscdevice vga_arb_device = {
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-3m-pct.c linux-libre-2.6.37-gnu/drivers/hid/hid-3m-pct.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-3m-pct.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-3m-pct.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,8 @@
  *  HID driver for 3M PCT multitouch panels
  *
  *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se>
+ *  Copyright (c) 2010      Canonical, Ltd.
  *
  */
 
@@ -24,15 +26,26 @@
 
 #include "hid-ids.h"
 
+#define MAX_SLOTS		60
+#define MAX_TRKID		USHRT_MAX
+#define MAX_EVENTS		360
+
+/* estimated signal-to-noise ratios */
+#define SN_MOVE			2048
+#define SN_WIDTH		128
+
 struct mmm_finger {
 	__s32 x, y, w, h;
-	__u8 rank;
+	__u16 id;
+	bool prev_touch;
 	bool touch, valid;
 };
 
 struct mmm_data {
-	struct mmm_finger f[10];
-	__u8 curid, num;
+	struct mmm_finger f[MAX_SLOTS];
+	__u16 id;
+	__u8 curid;
+	__u8 nexp, nreal;
 	bool touch, valid;
 };
 
@@ -40,6 +53,10 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
+	int f1 = field->logical_minimum;
+	int f2 = field->logical_maximum;
+	int df = f2 - f1;
+
 	switch (usage->hid & HID_USAGE_PAGE) {
 
 	case HID_UP_BUTTON:
@@ -50,18 +67,20 @@
 		case HID_GD_X:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_POSITION_X);
+			input_set_abs_params(hi->input, ABS_MT_POSITION_X,
+					     f1, f2, df / SN_MOVE, 0);
 			/* touchscreen emulation */
 			input_set_abs_params(hi->input, ABS_X,
-						field->logical_minimum,
-						field->logical_maximum, 0, 0);
+					     f1, f2, df / SN_MOVE, 0);
 			return 1;
 		case HID_GD_Y:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_POSITION_Y);
+			input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
+					     f1, f2, df / SN_MOVE, 0);
 			/* touchscreen emulation */
 			input_set_abs_params(hi->input, ABS_Y,
-						field->logical_minimum,
-						field->logical_maximum, 0, 0);
+					     f1, f2, df / SN_MOVE, 0);
 			return 1;
 		}
 		return 0;
@@ -81,21 +100,31 @@
 		case HID_DG_TIPSWITCH:
 			/* touchscreen emulation */
 			hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+			input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
 			return 1;
 		case HID_DG_WIDTH:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MAJOR);
+			input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
+					     f1, f2, df / SN_WIDTH, 0);
 			return 1;
 		case HID_DG_HEIGHT:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TOUCH_MINOR);
+			input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
+					     f1, f2, df / SN_WIDTH, 0);
 			input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-					1, 1, 0, 0);
+					0, 1, 0, 0);
 			return 1;
 		case HID_DG_CONTACTID:
-			field->logical_maximum = 59;
+			field->logical_maximum = MAX_TRKID;
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_TRACKING_ID);
+			input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
+					     0, MAX_TRKID, 0, 0);
+			if (!hi->input->mt)
+				input_mt_create_slots(hi->input, MAX_SLOTS);
+			input_set_events_per_packet(hi->input, MAX_EVENTS);
 			return 1;
 		}
 		/* let hid-input decide for the others */
@@ -113,10 +142,10 @@
 		struct hid_field *field, struct hid_usage *usage,
 		unsigned long **bit, int *max)
 {
+	/* tell hid-input to skip setup of these event types */
 	if (usage->type == EV_KEY || usage->type == EV_ABS)
-		clear_bit(usage->code, *bit);
-
-	return 0;
+		set_bit(usage->type, hi->input->evbit);
+	return -1;
 }
 
 /*
@@ -126,70 +155,49 @@
 static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
 {
 	struct mmm_finger *oldest = 0;
-	bool pressed = false, released = false;
 	int i;
-
-	/*
-	 * we need to iterate on all fingers to decide if we have a press
-	 * or a release event in our touchscreen emulation.
-	 */
-	for (i = 0; i < 10; ++i) {
+	for (i = 0; i < MAX_SLOTS; ++i) {
 		struct mmm_finger *f = &md->f[i];
 		if (!f->valid) {
 			/* this finger is just placeholder data, ignore */
-		} else if (f->touch) {
+			continue;
+		}
+		input_mt_slot(input, i);
+		if (f->touch) {
 			/* this finger is on the screen */
 			int wide = (f->w > f->h);
-			input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+			/* divided by two to match visual scale of touch */
+			int major = max(f->w, f->h) >> 1;
+			int minor = min(f->w, f->h) >> 1;
+
+			if (!f->prev_touch)
+				f->id = md->id++;
+			input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
 			input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
 			input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
 			input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
-			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR,
-						wide ? f->w : f->h);
-			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
-						wide ? f->h : f->w);
-			input_mt_sync(input);
-			/*
-			 * touchscreen emulation: maintain the age rank
-			 * of this finger, decide if we have a press
-			 */
-			if (f->rank == 0) {
-				f->rank = ++(md->num);
-				if (f->rank == 1)
-					pressed = true;
-			}
-			if (f->rank == 1)
+			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+			/* touchscreen emulation: pick the oldest contact */
+			if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
 				oldest = f;
 		} else {
 			/* this finger took off the screen */
-			/* touchscreen emulation: maintain age rank of others */
-			int j;
-
-			for (j = 0; j < 10; ++j) {
-				struct mmm_finger *g = &md->f[j];
-				if (g->rank > f->rank) {
-					g->rank--;
-					if (g->rank == 1)
-						oldest = g;
-				}
-			}
-			f->rank = 0;
-			--(md->num);
-			if (md->num == 0)
-				released = true;
+			input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
 		}
+		f->prev_touch = f->touch;
 		f->valid = 0;
 	}
 
 	/* touchscreen emulation */
 	if (oldest) {
-		if (pressed)
-			input_event(input, EV_KEY, BTN_TOUCH, 1);
+		input_event(input, EV_KEY, BTN_TOUCH, 1);
 		input_event(input, EV_ABS, ABS_X, oldest->x);
 		input_event(input, EV_ABS, ABS_Y, oldest->y);
-	} else if (released) {
+	} else {
 		input_event(input, EV_KEY, BTN_TOUCH, 0);
 	}
+	input_sync(input);
 }
 
 /*
@@ -223,10 +231,12 @@
 				md->f[md->curid].h = value;
 			break;
 		case HID_DG_CONTACTID:
+			value = clamp_val(value, 0, MAX_SLOTS - 1);
 			if (md->valid) {
 				md->curid = value;
 				md->f[value].touch = md->touch;
 				md->f[value].valid = 1;
+				md->nreal++;
 			}
 			break;
 		case HID_GD_X:
@@ -238,7 +248,12 @@
 				md->f[md->curid].y = value;
 			break;
 		case HID_DG_CONTACTCOUNT:
-			mmm_filter_event(md, input);
+			if (value)
+				md->nexp = value;
+			if (md->nreal >= md->nexp) {
+				mmm_filter_event(md, input);
+				md->nreal = 0;
+			}
 			break;
 		}
 	}
@@ -255,6 +270,8 @@
 	int ret;
 	struct mmm_data *md;
 
+	hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+
 	md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
 	if (!md) {
 		dev_err(&hdev->dev, "cannot allocate 3M data\n");
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-a4tech.c linux-libre-2.6.37-gnu/drivers/hid/hid-a4tech.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-a4tech.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-a4tech.c	2011-01-04 19:50:19.000000000 -0500
@@ -133,6 +133,8 @@
 		.driver_data = A4_2WHEEL_MOUSE_HACK_7 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
 		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649),
+		.driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, a4_devices);
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-apple.c linux-libre-2.6.37-gnu/drivers/hid/hid-apple.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-apple.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-apple.c	2011-01-04 19:50:19.000000000 -0500
@@ -246,17 +246,18 @@
 /*
  * MacBook JIS keyboard has wrong logical maximum
  */
-static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
 	struct apple_sc *asc = hid_get_drvdata(hdev);
 
-	if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 &&
+	if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
 			rdesc[53] == 0x65 && rdesc[59] == 0x65) {
 		dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
 				"descriptor\n");
 		rdesc[53] = rdesc[59] = 0xe7;
 	}
+	return rdesc;
 }
 
 static void apple_setup_input(struct input_dev *input)
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-cherry.c linux-libre-2.6.37-gnu/drivers/hid/hid-cherry.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-cherry.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-cherry.c	2011-01-04 19:50:19.000000000 -0500
@@ -26,15 +26,16 @@
  * Cherry Cymotion keyboard have an invalid HID report descriptor,
  * that needs fixing before we can parse it.
  */
-static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+	if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
 		dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
 				"descriptor\n");
 		rdesc[11] = rdesc[16] = 0xff;
 		rdesc[12] = rdesc[17] = 0x03;
 	}
+	return rdesc;
 }
 
 #define ch_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-core.c linux-libre-2.6.37-gnu/drivers/hid/hid-core.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-core.c	2011-01-04 19:50:19.000000000 -0500
@@ -388,12 +388,6 @@
 	__u32 data;
 	unsigned n;
 
-	/* Local delimiter could have value 0, which allows size to be 0 */
-	if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) {
-		dbg_hid("item data expected for local item\n");
-		return -1;
-	}
-
 	data = item_udata(item);
 
 	switch (item->tag) {
@@ -651,7 +645,7 @@
 	};
 
 	if (device->driver->report_fixup)
-		device->driver->report_fixup(device, start, size);
+		start = device->driver->report_fixup(device, start, &size);
 
 	device->rdesc = kmemdup(start, size, GFP_KERNEL);
 	if (device->rdesc == NULL)
@@ -1241,6 +1235,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
 #if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
 #endif
@@ -1248,6 +1243,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
@@ -1327,6 +1323,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
@@ -1336,6 +1333,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
@@ -1371,12 +1369,15 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1385,11 +1386,20 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
@@ -1662,6 +1672,7 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_YUREX) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
@@ -1770,6 +1781,11 @@
 		    hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST)
 			return true;
 		break;
+	case USB_VENDOR_ID_HANWANG:
+		if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST &&
+		    hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST)
+			return true;
+		break;
 	}
 
 	if (hdev->type == HID_TYPE_USBMOUSE &&
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-cypress.c linux-libre-2.6.37-gnu/drivers/hid/hid-cypress.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-cypress.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-cypress.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,16 +31,16 @@
  * Some USB barcode readers from cypress have usage min and usage max in
  * the wrong order
  */
-static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 	unsigned int i;
 
 	if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
-		return;
+		return rdesc;
 
-	for (i = 0; i < rsize - 4; i++)
+	for (i = 0; i < *rsize - 4; i++)
 		if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
 			__u8 tmp;
 
@@ -50,6 +50,7 @@
 			rdesc[i + 3] = rdesc[i + 1];
 			rdesc[i + 1] = tmp;
 		}
+	return rdesc;
 }
 
 static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-debug.c linux-libre-2.6.37-gnu/drivers/hid/hid-debug.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-debug.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-debug.c	2011-01-04 19:50:19.000000000 -0500
@@ -570,6 +570,8 @@
 				buf[i];
 		list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
         }
+
+	wake_up_interruptible(&hdev->debug_wait);
 }
 EXPORT_SYMBOL_GPL(hid_debug_event);
 
@@ -1051,6 +1053,7 @@
 	.read           = hid_debug_events_read,
 	.poll		= hid_debug_events_poll,
 	.release        = hid_debug_events_release,
+	.llseek		= noop_llseek,
 };
 
 
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-egalax.c linux-libre-2.6.37-gnu/drivers/hid/hid-egalax.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-egalax.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-egalax.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,7 +31,7 @@
 	bool first;		/* is this the first finger in the frame? */
 	bool valid;		/* valid finger data, or just placeholder? */
 	bool activity;		/* at least one active finger previously? */
-	__u16 lastx, lasty;	/* latest valid (x, y) in the frame */
+	__u16 lastx, lasty, lastz;	/* latest valid (x, y, z) in the frame */
 };
 
 static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -79,6 +79,10 @@
 		case HID_DG_TIPPRESSURE:
 			hid_map_usage(hi, usage, bit, max,
 					EV_ABS, ABS_MT_PRESSURE);
+			/* touchscreen emulation */
+			input_set_abs_params(hi->input, ABS_PRESSURE,
+						field->logical_minimum,
+						field->logical_maximum, 0, 0);
 			return 1;
 		}
 		return 0;
@@ -109,8 +113,8 @@
 	if (td->valid) {
 		/* emit multitouch events */
 		input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
-		input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
-		input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+		input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
+		input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
 		input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
 
 		input_mt_sync(input);
@@ -121,6 +125,7 @@
 		 */
 		td->lastx = td->x;
 		td->lasty = td->y;
+		td->lastz = td->z;
 	}
 
 	/*
@@ -129,8 +134,9 @@
 	 * the oldest on the panel, the one we want for single touch
 	 */
 	if (!td->first && td->activity) {
-		input_event(input, EV_ABS, ABS_X, td->lastx);
-		input_event(input, EV_ABS, ABS_Y, td->lasty);
+		input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
+		input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
+ 		input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
 	}
 
 	if (!td->valid) {
@@ -215,7 +221,7 @@
 	struct egalax_data *td;
 	struct hid_report *report;
 
-	td = kmalloc(sizeof(struct egalax_data), GFP_KERNEL);
+	td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
 	if (!td) {
 		dev_err(&hdev->dev, "cannot allocate eGalax data\n");
 		return -ENOMEM;
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-elecom.c linux-libre-2.6.37-gnu/drivers/hid/hid-elecom.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-elecom.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-elecom.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,14 +20,15 @@
 
 #include "hid-ids.h"
 
-static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
+	if (*rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) {
 		dev_info(&hdev->dev, "Fixing up Elecom BM084 "
 				"report descriptor.\n");
 		rdesc[47] = 0x00;
 	}
+    return rdesc;
 }
 
 static const struct hid_device_id elecom_devices[] = {
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-ids.h linux-libre-2.6.37-gnu/drivers/hid/hid-ids.h
--- linux-libre-2.6.36-gnu/drivers/hid/hid-ids.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-ids.h	2011-01-04 19:50:19.000000000 -0500
@@ -25,6 +25,7 @@
 #define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 #define USB_DEVICE_ID_A4TECH_X5_005D	0x000a
+#define USB_DEVICE_ID_A4TECH_RP_649	0x001a
 
 #define USB_VENDOR_ID_AASHIMA		0x06d6
 #define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
@@ -63,6 +64,7 @@
 #define USB_VENDOR_ID_APPLE		0x05ac
 #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE	0x0304
 #define USB_DEVICE_ID_APPLE_MAGICMOUSE	0x030d
+#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD	0x030e
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI	0x020e
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO	0x020f
 #define USB_DEVICE_ID_APPLE_GEYSER_ANSI	0x0214
@@ -142,6 +144,7 @@
 #define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE       0x0051
 #define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE	0x00ff
 #define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK	0x00d3
+#define USB_DEVICE_ID_CH_AXIS_295	0x001c
 
 #define USB_VENDOR_ID_CHERRY		0x046a
 #define USB_DEVICE_ID_CHERRY_CYMOTION	0x0023
@@ -296,6 +299,10 @@
 #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
 #define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
 
+#define USB_VENDOR_ID_HANWANG		0x0b57
+#define USB_DEVICE_ID_HANWANG_TABLET_FIRST	0x5000
+#define USB_DEVICE_ID_HANWANG_TABLET_LAST	0x8fff
+
 #define USB_VENDOR_ID_HAPP		0x078b
 #define USB_DEVICE_ID_UGCI_DRIVING	0x0010
 #define USB_DEVICE_ID_UGCI_FLYING	0x0020
@@ -304,6 +311,9 @@
 #define USB_VENDOR_ID_IMATION		0x0718
 #define USB_DEVICE_ID_DISC_STAKKA	0xd000
 
+#define USB_VENDOR_ID_JESS		0x0c45
+#define USB_DEVICE_ID_JESS_YUREX	0x1010
+
 #define USB_VENDOR_ID_KBGEAR		0x084e
 #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO	0x1001
 
@@ -340,6 +350,7 @@
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST  0xc110
 #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD	0xc20a
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD	0xc211
 #define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2	0xc218
@@ -351,6 +362,7 @@
 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG	0xc293
 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL	0xc295
 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL	0xc299
+#define USB_DEVICE_ID_LOGITECH_WII_WHEEL	0xc29c
 #define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
 #define USB_DEVICE_ID_S510_RECEIVER	0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
@@ -463,6 +475,8 @@
 
 #define USB_VENDOR_ID_ROCCAT		0x1e7d
 #define USB_DEVICE_ID_ROCCAT_KONE	0x2ced
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED	0x2c24
+#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS	0x2cf6
 
 #define USB_VENDOR_ID_SAITEK		0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
@@ -482,6 +496,12 @@
 #define USB_VENDOR_ID_STANTUM		0x1f87
 #define USB_DEVICE_ID_MTP		0x0002
 
+#define USB_VENDOR_ID_STANTUM_STM		0x0483
+#define USB_DEVICE_ID_MTP_STM		0x3261
+
+#define USB_VENDOR_ID_STANTUM_SITRONIX		0x1403
+#define USB_DEVICE_ID_MTP_SITRONIX		0x5001
+
 #define USB_VENDOR_ID_SUN		0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE	0xcdab
 
@@ -511,8 +531,10 @@
 
 #define USB_VENDOR_ID_UCLOGIC		0x5543
 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209	0x0042
-#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U	0x0003
 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5	0x6001
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U	0x0003
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U	0x0004
+#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U	0x0005
 
 #define USB_VENDOR_ID_VERNIER		0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO	0x0001
@@ -524,6 +546,12 @@
 #define USB_VENDOR_ID_WACOM		0x056a
 #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH	0x81
 
+#define USB_VENDOR_ID_WALTOP				0x172f
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH	0x0032
+#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH	0x0034
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH	0x0501
+#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH	0x0500
+
 #define USB_VENDOR_ID_WISEGROUP		0x0925
 #define USB_DEVICE_ID_SMARTJOY_PLUS	0x0005
 #define USB_DEVICE_ID_1_PHIDGETSERVO_20	0x8101
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-input.c linux-libre-2.6.37-gnu/drivers/hid/hid-input.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-input.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-input.c	2011-01-04 19:50:19.000000000 -0500
@@ -68,39 +68,52 @@
 #define map_key_clear(c)	hid_map_usage_clear(hidinput, usage, &bit, \
 		&max, EV_KEY, (c))
 
-static inline int match_scancode(unsigned int code, unsigned int scancode)
+static bool match_scancode(struct hid_usage *usage,
+			   unsigned int cur_idx, unsigned int scancode)
 {
-	if (scancode == 0)
-		return 1;
-
-	return (code & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
+	return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode;
 }
 
-static inline int match_keycode(unsigned int code, unsigned int keycode)
+static bool match_keycode(struct hid_usage *usage,
+			  unsigned int cur_idx, unsigned int keycode)
 {
-	if (keycode == 0)
-		return 1;
+	/*
+	 * We should exclude unmapped usages when doing lookup by keycode.
+	 */
+	return (usage->type == EV_KEY && usage->code == keycode);
+}
 
-	return code == keycode;
+static bool match_index(struct hid_usage *usage,
+			unsigned int cur_idx, unsigned int idx)
+{
+	return cur_idx == idx;
 }
 
+typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage,
+				unsigned int cur_idx, unsigned int val);
+
 static struct hid_usage *hidinput_find_key(struct hid_device *hid,
-					   unsigned int scancode,
-					   unsigned int keycode)
+					   hid_usage_cmp_t match,
+					   unsigned int value,
+					   unsigned int *usage_idx)
 {
-	int i, j, k;
+	unsigned int i, j, k, cur_idx = 0;
 	struct hid_report *report;
 	struct hid_usage *usage;
 
 	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
 		list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
 			for (i = 0; i < report->maxfield; i++) {
-				for ( j = 0; j < report->field[i]->maxusage; j++) {
+				for (j = 0; j < report->field[i]->maxusage; j++) {
 					usage = report->field[i]->usage + j;
-					if (usage->type == EV_KEY &&
-						match_scancode(usage->hid, scancode) &&
-						match_keycode(usage->code, keycode))
-						return usage;
+					if (usage->type == EV_KEY || usage->type == 0) {
+						if (match(usage, cur_idx, value)) {
+							if (usage_idx)
+								*usage_idx = cur_idx;
+							return usage;
+						}
+						cur_idx++;
+					}
 				}
 			}
 		}
@@ -108,39 +121,68 @@
 	return NULL;
 }
 
+static struct hid_usage *hidinput_locate_usage(struct hid_device *hid,
+					const struct input_keymap_entry *ke,
+					unsigned int *index)
+{
+	struct hid_usage *usage;
+	unsigned int scancode;
+
+	if (ke->flags & INPUT_KEYMAP_BY_INDEX)
+		usage = hidinput_find_key(hid, match_index, ke->index, index);
+	else if (input_scancode_to_scalar(ke, &scancode) == 0)
+		usage = hidinput_find_key(hid, match_scancode, scancode, index);
+	else
+		usage = NULL;
+
+	return usage;
+}
+
 static int hidinput_getkeycode(struct input_dev *dev,
-			       unsigned int scancode, unsigned int *keycode)
+			       struct input_keymap_entry *ke)
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct hid_usage *usage;
+	unsigned int scancode, index;
 
-	usage = hidinput_find_key(hid, scancode, 0);
+	usage = hidinput_locate_usage(hid, ke, &index);
 	if (usage) {
-		*keycode = usage->code;
+		ke->keycode = usage->type == EV_KEY ?
+				usage->code : KEY_RESERVED;
+		ke->index = index;
+		scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE);
+		ke->len = sizeof(scancode);
+		memcpy(ke->scancode, &scancode, sizeof(scancode));
 		return 0;
 	}
+
 	return -EINVAL;
 }
 
 static int hidinput_setkeycode(struct input_dev *dev,
-			       unsigned int scancode, unsigned int keycode)
+			       const struct input_keymap_entry *ke,
+			       unsigned int *old_keycode)
 {
 	struct hid_device *hid = input_get_drvdata(dev);
 	struct hid_usage *usage;
-	int old_keycode;
 
-	usage = hidinput_find_key(hid, scancode, 0);
+	usage = hidinput_locate_usage(hid, ke, NULL);
 	if (usage) {
-		old_keycode = usage->code;
-		usage->code = keycode;
+		*old_keycode = usage->type == EV_KEY ?
+				usage->code : KEY_RESERVED;
+		usage->code = ke->keycode;
 
-		clear_bit(old_keycode, dev->keybit);
+		clear_bit(*old_keycode, dev->keybit);
 		set_bit(usage->code, dev->keybit);
-		dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
-		/* Set the keybit for the old keycode if the old keycode is used
-		 * by another key */
-		if (hidinput_find_key (hid, 0, old_keycode))
-			set_bit(old_keycode, dev->keybit);
+		dbg_hid("Assigned keycode %d to HID usage code %x\n",
+			usage->code, usage->hid);
+
+		/*
+		 * Set the keybit for the old keycode if the old keycode is used
+		 * by another key
+		 */
+		if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL))
+			set_bit(*old_keycode, dev->keybit);
 
 		return 0;
 	}
@@ -149,6 +191,86 @@
 }
 
 
+/**
+ * hidinput_calc_abs_res - calculate an absolute axis resolution
+ * @field: the HID report field to calculate resolution for
+ * @code: axis code
+ *
+ * The formula is:
+ *                         (logical_maximum - logical_minimum)
+ * resolution = ----------------------------------------------------------
+ *              (physical_maximum - physical_minimum) * 10 ^ unit_exponent
+ *
+ * as seen in the HID specification v1.11 6.2.2.7 Global Items.
+ *
+ * Only exponent 1 length units are processed. Centimeters and inches are
+ * converted to millimeters. Degrees are converted to radians.
+ */
+static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
+{
+	__s32 unit_exponent = field->unit_exponent;
+	__s32 logical_extents = field->logical_maximum -
+					field->logical_minimum;
+	__s32 physical_extents = field->physical_maximum -
+					field->physical_minimum;
+	__s32 prev;
+
+	/* Check if the extents are sane */
+	if (logical_extents <= 0 || physical_extents <= 0)
+		return 0;
+
+	/*
+	 * Verify and convert units.
+	 * See HID specification v1.11 6.2.2.7 Global Items for unit decoding
+	 */
+	if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+		if (field->unit == 0x11) {		/* If centimeters */
+			/* Convert to millimeters */
+			unit_exponent += 1;
+		} else if (field->unit == 0x13) {	/* If inches */
+			/* Convert to millimeters */
+			prev = physical_extents;
+			physical_extents *= 254;
+			if (physical_extents < prev)
+				return 0;
+			unit_exponent -= 1;
+		} else {
+			return 0;
+		}
+	} else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+		if (field->unit == 0x14) {		/* If degrees */
+			/* Convert to radians */
+			prev = logical_extents;
+			logical_extents *= 573;
+			if (logical_extents < prev)
+				return 0;
+			unit_exponent += 1;
+		} else if (field->unit != 0x12) {	/* If not radians */
+			return 0;
+		}
+	} else {
+		return 0;
+	}
+
+	/* Apply negative unit exponent */
+	for (; unit_exponent < 0; unit_exponent++) {
+		prev = logical_extents;
+		logical_extents *= 10;
+		if (logical_extents < prev)
+			return 0;
+	}
+	/* Apply positive unit exponent */
+	for (; unit_exponent > 0; unit_exponent--) {
+		prev = physical_extents;
+		physical_extents *= 10;
+		if (physical_extents < prev)
+			return 0;
+	}
+
+	/* Calculate resolution */
+	return logical_extents / physical_extents;
+}
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
 				     struct hid_usage *usage)
 {
@@ -336,6 +458,10 @@
 			map_key_clear(BTN_STYLUS);
 			break;
 
+		case 0x46: /* TabletPick */
+			map_key_clear(BTN_STYLUS2);
+			break;
+
 		default:  goto unknown;
 		}
 		break;
@@ -537,6 +663,9 @@
 			input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
 		else	input_set_abs_params(input, usage->code, a, b, 0, 0);
 
+		input_abs_set_res(input, usage->code,
+				  hidinput_calc_abs_res(field, usage->code));
+
 		/* use a larger default input buffer for MT devices */
 		if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0)
 			input_set_events_per_packet(input, 60);
@@ -659,6 +788,9 @@
 {
 	struct hid_input *hidinput;
 
+	if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC)
+		return;
+
 	list_for_each_entry(hidinput, &hid->inputs, list)
 		input_sync(hidinput->input);
 }
@@ -748,8 +880,8 @@
 					hid->ll_driver->hidinput_input_event;
 				input_dev->open = hidinput_open;
 				input_dev->close = hidinput_close;
-				input_dev->setkeycode = hidinput_setkeycode;
-				input_dev->getkeycode = hidinput_getkeycode;
+				input_dev->setkeycode_new = hidinput_setkeycode;
+				input_dev->getkeycode_new = hidinput_getkeycode;
 
 				input_dev->name = hid->name;
 				input_dev->phys = hid->phys;
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-kye.c linux-libre-2.6.37-gnu/drivers/hid/hid-kye.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-kye.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-kye.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,10 +23,10 @@
  *   - report size 8 count 1 must be size 1 count 8 for button bitfield
  *   - change the button usage range to 4-7 for the extra buttons
  */
-static void kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 74 &&
+	if (*rsize >= 74 &&
 		rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
 		rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
 		rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
@@ -40,6 +40,7 @@
 		rdesc[72] = 0x01;
 		rdesc[74] = 0x08;
 	}
+	return rdesc;
 }
 
 static const struct hid_device_id kye_devices[] = {
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-lg2ff.c linux-libre-2.6.37-gnu/drivers/hid/hid-lg2ff.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-lg2ff.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-lg2ff.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- *  Force feedback support for Logitech Rumblepad 2
+ *  Force feedback support for Logitech RumblePad and Rumblepad 2
  *
  *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.com>
  */
@@ -110,7 +110,7 @@
 
 	usbhid_submit_report(hid, report, USB_DIR_OUT);
 
-	dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
+	dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
 	       "Anssi Hannula <anssi.hannula@gmail.com>\n");
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-lg4ff.c linux-libre-2.6.37-gnu/drivers/hid/hid-lg4ff.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-lg4ff.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-lg4ff.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,136 @@
+/*
+ *  Force feedback support for Logitech Speed Force Wireless
+ *
+ *  http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ *
+ *  Copyright (c) 2010 Simon Wood <simon@mungewell.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+struct lg4ff_device {
+	struct hid_report *report;
+};
+
+static const signed short ff4_wheel_ac[] = {
+	FF_CONSTANT,
+	FF_AUTOCENTER,
+	-1
+};
+
+static int hid_lg4ff_play(struct input_dev *dev, void *data,
+			 struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	int x;
+
+#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+
+	switch (effect->type) {
+	case FF_CONSTANT:
+		x = effect->u.ramp.start_level + 0x80;	/* 0x80 is no force */
+		CLAMP(x);
+		report->field[0]->value[0] = 0x11;	/* Slot 1 */
+		report->field[0]->value[1] = 0x10;
+		report->field[0]->value[2] = x;
+		report->field[0]->value[3] = 0x00;
+		report->field[0]->value[4] = 0x00;
+		report->field[0]->value[5] = 0x08;
+		report->field[0]->value[6] = 0x00;
+		dbg_hid("Autocenter, x=0x%02X\n", x);
+
+		usbhid_submit_report(hid, report, USB_DIR_OUT);
+		break;
+	}
+	return 0;
+}
+
+static void hid_lg4ff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+	__s32 *value = report->field[0]->value;
+
+	*value++ = 0xfe;
+	*value++ = 0x0d;
+	*value++ = 0x07;
+	*value++ = 0x07;
+	*value++ = (magnitude >> 8) & 0xff;
+	*value++ = 0x00;
+	*value = 0x00;
+
+	usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+
+int lg4ff_init(struct hid_device *hid)
+{
+	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev = hidinput->input;
+	struct hid_report *report;
+	struct hid_field *field;
+	const signed short *ff_bits = ff4_wheel_ac;
+	int error;
+	int i;
+
+	/* Find the report to use */
+	if (list_empty(report_list)) {
+		err_hid("No output report found");
+		return -1;
+	}
+
+	/* Check that the report looks ok */
+	report = list_entry(report_list->next, struct hid_report, list);
+	if (!report) {
+		err_hid("NULL output report");
+		return -1;
+	}
+
+	field = report->field[0];
+	if (!field) {
+		err_hid("NULL field");
+		return -1;
+	}
+
+	for (i = 0; ff_bits[i] >= 0; i++)
+		set_bit(ff_bits[i], dev->ffbit);
+
+	error = input_ff_create_memless(dev, NULL, hid_lg4ff_play);
+
+	if (error)
+		return error;
+
+	if (test_bit(FF_AUTOCENTER, dev->ffbit))
+		dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
+
+	dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by "
+			"Simon Wood <simon@mungewell.org>\n");
+	return 0;
+}
+
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-lg.c linux-libre-2.6.37-gnu/drivers/hid/hid-lg.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-lg.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-lg.c	2011-01-04 19:50:19.000000000 -0500
@@ -7,6 +7,7 @@
  *  Copyright (c) 2006-2007 Jiri Kosina
  *  Copyright (c) 2007 Paul Walmsley
  *  Copyright (c) 2008 Jiri Slaby
+ *  Copyright (c) 2010 Hendrik Iben
  */
 
 /*
@@ -19,6 +20,9 @@
 #include <linux/device.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
 
 #include "hid-ids.h"
 #include "hid-lg.h"
@@ -35,31 +39,43 @@
 #define LG_FF2			0x400
 #define LG_RDESC_REL_ABS	0x800
 #define LG_FF3			0x1000
+#define LG_FF4			0x2000
 
 /*
  * Certain Logitech keyboards send in report #3 keys which are far
  * above the logical maximum described in descriptor. This extends
  * the original value of 0x28c of logical maximum to 0x104d
  */
-static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
-	if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
+	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
 		dev_info(&hdev->dev, "fixing up Logitech keyboard report "
 				"descriptor\n");
 		rdesc[84] = rdesc[89] = 0x4d;
 		rdesc[85] = rdesc[90] = 0x10;
 	}
-	if ((quirks & LG_RDESC_REL_ABS) && rsize >= 50 &&
+	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
 			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
 			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
 		dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
 				"report descriptor\n");
 		rdesc[33] = rdesc[50] = 0x02;
 	}
+	if ((quirks & LG_FF4) && *rsize >= 101 &&
+			rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
+			rdesc[47] == 0x05 && rdesc[48] == 0x09) {
+		dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
+			"button descriptor\n");
+		rdesc[41] = 0x05;
+		rdesc[42] = 0x09;
+		rdesc[47] = 0x95;
+		rdesc[48] = 0x0B;
+	}
+	return rdesc;
 }
 
 #define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
@@ -285,12 +301,33 @@
 		goto err_free;
 	}
 
+	if (quirks & LG_FF4) {
+		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+		ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+
+		if (ret >= 0) {
+			/* insert a little delay of 10 jiffies ~ 40ms */
+			wait_queue_head_t wait;
+			init_waitqueue_head (&wait);
+			wait_event_interruptible_timeout(wait, 0, 10);
+
+			/* Select random Address */
+			buf[1] = 0xB2;
+			get_random_bytes(&buf[2], 2);
+
+			ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+		}
+	}
+
 	if (quirks & LG_FF)
 		lgff_init(hdev);
 	if (quirks & LG_FF2)
 		lg2ff_init(hdev);
 	if (quirks & LG_FF3)
 		lg3ff_init(hdev);
+	if (quirks & LG_FF4)
+		lg4ff_init(hdev);
 
 	return 0;
 err_free:
@@ -325,6 +362,8 @@
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
 		.driver_data = LG_NOGET | LG_FF },
 
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
+		.driver_data = LG_FF2 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
 		.driver_data = LG_FF },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
@@ -339,6 +378,8 @@
 		.driver_data = LG_FF },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
 		.driver_data = LG_FF },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
+		.driver_data = LG_FF4 },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
 		.driver_data = LG_FF },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-lg.h linux-libre-2.6.37-gnu/drivers/hid/hid-lg.h
--- linux-libre-2.6.36-gnu/drivers/hid/hid-lg.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-lg.h	2011-01-04 19:50:19.000000000 -0500
@@ -19,4 +19,10 @@
 static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
 #endif
 
+#ifdef CONFIG_LOGIWII_FF
+int lg4ff_init(struct hid_device *hdev);
+#else
+static inline int lg4ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-magicmouse.c linux-libre-2.6.37-gnu/drivers/hid/hid-magicmouse.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-magicmouse.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-magicmouse.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,6 +2,7 @@
  *   Apple "Magic" Wireless Mouse driver
  *
  *   Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
+ *   Copyright (c) 2010 Chase Douglas <chase.douglas@canonical.com>
  */
 
 /*
@@ -53,7 +54,9 @@
 module_param(report_undeciphered, bool, 0644);
 MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
 
-#define TOUCH_REPORT_ID   0x29
+#define TRACKPAD_REPORT_ID 0x28
+#define MOUSE_REPORT_ID    0x29
+#define DOUBLE_REPORT_ID   0xf7
 /* These definitions are not precise, but they're close enough.  (Bits
  * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
  * to be some kind of bit mask -- 0x20 may be a near-field reading,
@@ -67,15 +70,19 @@
 
 #define SCROLL_ACCEL_DEFAULT 7
 
+/* Single touch emulation should only begin when no touches are currently down.
+ * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches
+ * are down and the touch providing for single touch emulation is lifted,
+ * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is
+ * occuring, single_touch_id corresponds with the tracking id of the touch used.
+ */
+#define NO_TOUCHES -1
+#define SINGLE_TOUCH_UP -2
+
 /**
  * struct magicmouse_sc - Tracks Magic Mouse-specific data.
  * @input: Input device through which we report events.
  * @quirks: Currently unused.
- * @last_timestamp: Timestamp from most recent (18-bit) touch report
- *     (units of milliseconds over short windows, but seems to
- *     increase faster when there are no touches).
- * @delta_time: 18-bit difference between the two most recent touch
- *     reports from the mouse.
  * @ntouches: Number of touches in most recent touch report.
  * @scroll_accel: Number of consecutive scroll motions.
  * @scroll_jiffies: Time of last scroll motion.
@@ -86,8 +93,6 @@
 	struct input_dev *input;
 	unsigned long quirks;
 
-	int last_timestamp;
-	int delta_time;
 	int ntouches;
 	int scroll_accel;
 	unsigned long scroll_jiffies;
@@ -98,9 +103,9 @@
 		short scroll_x;
 		short scroll_y;
 		u8 size;
-		u8 down;
 	} touches[16];
 	int tracking_ids[16];
+	int single_touch_id;
 };
 
 static int magicmouse_firm_touch(struct magicmouse_sc *msc)
@@ -166,18 +171,35 @@
 static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
 {
 	struct input_dev *input = msc->input;
-	__s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24;
-	int misc = tdata[5] | tdata[6] << 8;
-	int id = (misc >> 6) & 15;
-	int x = x_y << 12 >> 20;
-	int y = -(x_y >> 20);
-	int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE;
+	int id, x, y, size, orientation, touch_major, touch_minor, state, down;
+
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+		id = (tdata[6] << 2 | tdata[5] >> 6) & 0xf;
+		x = (tdata[1] << 28 | tdata[0] << 20) >> 20;
+		y = -((tdata[2] << 24 | tdata[1] << 16) >> 20);
+		size = tdata[5] & 0x3f;
+		orientation = (tdata[6] >> 2) - 32;
+		touch_major = tdata[3];
+		touch_minor = tdata[4];
+		state = tdata[7] & TOUCH_STATE_MASK;
+		down = state != TOUCH_STATE_NONE;
+	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+		id = (tdata[7] << 2 | tdata[6] >> 6) & 0xf;
+		x = (tdata[1] << 27 | tdata[0] << 19) >> 19;
+		y = -((tdata[3] << 30 | tdata[2] << 22 | tdata[1] << 14) >> 19);
+		size = tdata[6] & 0x3f;
+		orientation = (tdata[7] >> 2) - 32;
+		touch_major = tdata[4];
+		touch_minor = tdata[5];
+		state = tdata[8] & TOUCH_STATE_MASK;
+		down = state != TOUCH_STATE_NONE;
+	}
 
 	/* Store tracking ID and other fields. */
 	msc->tracking_ids[raw_id] = id;
 	msc->touches[id].x = x;
 	msc->touches[id].y = y;
-	msc->touches[id].size = misc & 63;
+	msc->touches[id].size = size;
 
 	/* If requested, emulate a scroll wheel by detecting small
 	 * vertical touch motions.
@@ -188,7 +210,7 @@
 		int step_y = msc->touches[id].scroll_y - y;
 
 		/* Calculate and apply the scroll motion. */
-		switch (tdata[7] & TOUCH_STATE_MASK) {
+		switch (state) {
 		case TOUCH_STATE_START:
 			msc->touches[id].scroll_x = x;
 			msc->touches[id].scroll_y = y;
@@ -222,21 +244,28 @@
 		}
 	}
 
+	if (down) {
+		msc->ntouches++;
+		if (msc->single_touch_id == NO_TOUCHES)
+			msc->single_touch_id = id;
+	} else if (msc->single_touch_id == id)
+		msc->single_touch_id = SINGLE_TOUCH_UP;
+
 	/* Generate the input events for this touch. */
 	if (report_touches && down) {
-		int orientation = (misc >> 10) - 32;
-
-		msc->touches[id].down = 1;
-
 		input_report_abs(input, ABS_MT_TRACKING_ID, id);
-		input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
-		input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
+		input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
 		input_report_abs(input, ABS_MT_ORIENTATION, orientation);
 		input_report_abs(input, ABS_MT_POSITION_X, x);
 		input_report_abs(input, ABS_MT_POSITION_Y, y);
 
-		if (report_undeciphered)
-			input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+		if (report_undeciphered) {
+			if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+				input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+			else /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+				input_event(input, EV_MSC, MSC_RAW, tdata[8]);
+		}
 
 		input_mt_sync(input);
 	}
@@ -247,39 +276,43 @@
 {
 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
 	struct input_dev *input = msc->input;
-	int x, y, ts, ii, clicks, last_up;
+	int x = 0, y = 0, ii, clicks = 0, npoints;
 
 	switch (data[0]) {
-	case 0x10:
-		if (size != 6)
+	case TRACKPAD_REPORT_ID:
+		/* Expect four bytes of prefix, and N*9 bytes of touch data. */
+		if (size < 4 || ((size - 4) % 9) != 0)
 			return 0;
-		x = (__s16)(data[2] | data[3] << 8);
-		y = (__s16)(data[4] | data[5] << 8);
+		npoints = (size - 4) / 9;
+		msc->ntouches = 0;
+		for (ii = 0; ii < npoints; ii++)
+			magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
+
+		/* We don't need an MT sync here because trackpad emits a
+		 * BTN_TOUCH event in a new frame when all touches are released.
+		 */
+		if (msc->ntouches == 0)
+			msc->single_touch_id = NO_TOUCHES;
+
 		clicks = data[1];
+
+		/* The following bits provide a device specific timestamp. They
+		 * are unused here.
+		 *
+		 * ts = data[1] >> 6 | data[2] << 2 | data[3] << 10;
+		 */
 		break;
-	case TOUCH_REPORT_ID:
+	case MOUSE_REPORT_ID:
 		/* Expect six bytes of prefix, and N*8 bytes of touch data. */
 		if (size < 6 || ((size - 6) % 8) != 0)
 			return 0;
-		ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
-		msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff;
-		msc->last_timestamp = ts;
-		msc->ntouches = (size - 6) / 8;
-		for (ii = 0; ii < msc->ntouches; ii++)
+		npoints = (size - 6) / 8;
+		msc->ntouches = 0;
+		for (ii = 0; ii < npoints; ii++)
 			magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
 
-		if (report_touches) {
-			last_up = 1;
-			for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) {
-				if (msc->touches[ii].down) {
-					last_up = 0;
-					msc->touches[ii].down = 0;
-				}
-			}
-			if (last_up) {
-				input_mt_sync(input);
-			}
-		}
+		if (report_touches && msc->ntouches == 0)
+			input_mt_sync(input);
 
 		/* When emulating three-button mode, it is important
 		 * to have the current touch information before
@@ -288,68 +321,72 @@
 		x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22;
 		y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22;
 		clicks = data[3];
+
+		/* The following bits provide a device specific timestamp. They
+		 * are unused here.
+		 *
+		 * ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
+		 */
+		break;
+	case DOUBLE_REPORT_ID:
+		/* Sometimes the trackpad sends two touch reports in one
+		 * packet.
+		 */
+		magicmouse_raw_event(hdev, report, data + 2, data[1]);
+		magicmouse_raw_event(hdev, report, data + 2 + data[1],
+			size - 2 - data[1]);
 		break;
-	case 0x20: /* Theoretically battery status (0-100), but I have
-		    * never seen it -- maybe it is only upon request.
-		    */
-	case 0x60: /* Unknown, maybe laser on/off. */
-	case 0x61: /* Laser reflection status change.
-		    * data[1]: 0 = spotted, 1 = lost
-		    */
 	default:
 		return 0;
 	}
 
-	magicmouse_emit_buttons(msc, clicks & 3);
-	input_report_rel(input, REL_X, x);
-	input_report_rel(input, REL_Y, y);
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+		magicmouse_emit_buttons(msc, clicks & 3);
+		input_report_rel(input, REL_X, x);
+		input_report_rel(input, REL_Y, y);
+	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+		input_report_key(input, BTN_MOUSE, clicks & 1);
+		input_report_key(input, BTN_TOUCH, msc->ntouches > 0);
+		input_report_key(input, BTN_TOOL_FINGER, msc->ntouches == 1);
+		input_report_key(input, BTN_TOOL_DOUBLETAP, msc->ntouches == 2);
+		input_report_key(input, BTN_TOOL_TRIPLETAP, msc->ntouches == 3);
+		input_report_key(input, BTN_TOOL_QUADTAP, msc->ntouches == 4);
+		if (msc->single_touch_id >= 0) {
+			input_report_abs(input, ABS_X,
+				msc->touches[msc->single_touch_id].x);
+			input_report_abs(input, ABS_Y,
+				msc->touches[msc->single_touch_id].y);
+		}
+	}
+
 	input_sync(input);
 	return 1;
 }
 
-static int magicmouse_input_open(struct input_dev *dev)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-
-	return hid->ll_driver->open(hid);
-}
-
-static void magicmouse_input_close(struct input_dev *dev)
-{
-	struct hid_device *hid = input_get_drvdata(dev);
-
-	hid->ll_driver->close(hid);
-}
-
 static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
 {
-	input_set_drvdata(input, hdev);
-	input->event = hdev->ll_driver->hidinput_input_event;
-	input->open = magicmouse_input_open;
-	input->close = magicmouse_input_close;
-
-	input->name = hdev->name;
-	input->phys = hdev->phys;
-	input->uniq = hdev->uniq;
-	input->id.bustype = hdev->bus;
-	input->id.vendor = hdev->vendor;
-	input->id.product = hdev->product;
-	input->id.version = hdev->version;
-	input->dev.parent = hdev->dev.parent;
-
 	__set_bit(EV_KEY, input->evbit);
-	__set_bit(BTN_LEFT, input->keybit);
-	__set_bit(BTN_RIGHT, input->keybit);
-	if (emulate_3button)
-		__set_bit(BTN_MIDDLE, input->keybit);
-	__set_bit(BTN_TOOL_FINGER, input->keybit);
 
-	__set_bit(EV_REL, input->evbit);
-	__set_bit(REL_X, input->relbit);
-	__set_bit(REL_Y, input->relbit);
-	if (emulate_scroll_wheel) {
-		__set_bit(REL_WHEEL, input->relbit);
-		__set_bit(REL_HWHEEL, input->relbit);
+	if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+		__set_bit(BTN_LEFT, input->keybit);
+		__set_bit(BTN_RIGHT, input->keybit);
+		if (emulate_3button)
+			__set_bit(BTN_MIDDLE, input->keybit);
+
+		__set_bit(EV_REL, input->evbit);
+		__set_bit(REL_X, input->relbit);
+		__set_bit(REL_Y, input->relbit);
+		if (emulate_scroll_wheel) {
+			__set_bit(REL_WHEEL, input->relbit);
+			__set_bit(REL_HWHEEL, input->relbit);
+		}
+	} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+		__set_bit(BTN_MOUSE, input->keybit);
+		__set_bit(BTN_TOOL_FINGER, input->keybit);
+		__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+		__set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+		__set_bit(BTN_TOOL_QUADTAP, input->keybit);
+		__set_bit(BTN_TOUCH, input->keybit);
 	}
 
 	if (report_touches) {
@@ -359,16 +396,26 @@
 		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
 		input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
 		input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
-		input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358,
-				4, 0);
+
 		/* Note: Touch Y position from the device is inverted relative
 		 * to how pointer motion is reported (and relative to how USB
 		 * HID recommends the coordinates work).  This driver keeps
 		 * the origin at the same position, and just uses the additive
 		 * inverse of the reported Y.
 		 */
-		input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047,
-				4, 0);
+		if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
+			input_set_abs_params(input, ABS_MT_POSITION_X, -1100,
+				1358, 4, 0);
+			input_set_abs_params(input, ABS_MT_POSITION_Y, -1589,
+				2047, 4, 0);
+		} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+			input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0);
+			input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0);
+			input_set_abs_params(input, ABS_MT_POSITION_X, -2909,
+				3167, 4, 0);
+			input_set_abs_params(input, ABS_MT_POSITION_Y, -2456,
+				2565, 4, 0);
+		}
 	}
 
 	if (report_undeciphered) {
@@ -377,12 +424,22 @@
 	}
 }
 
+static int magicmouse_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+	if (!msc->input)
+		msc->input = hi->input;
+
+	return 0;
+}
+
 static int magicmouse_probe(struct hid_device *hdev,
 	const struct hid_device_id *id)
 {
-	__u8 feature_1[] = { 0xd7, 0x01 };
-	__u8 feature_2[] = { 0xf8, 0x01, 0x32 };
-	struct input_dev *input;
+	__u8 feature[] = { 0xd7, 0x01 };
 	struct magicmouse_sc *msc;
 	struct hid_report *report;
 	int ret;
@@ -398,6 +455,8 @@
 	msc->quirks = id->driver_data;
 	hid_set_drvdata(hdev, msc);
 
+	msc->single_touch_id = NO_TOUCHES;
+
 	ret = hid_parse(hdev);
 	if (ret) {
 		dev_err(&hdev->dev, "magicmouse hid parse failed\n");
@@ -410,10 +469,22 @@
 		goto err_free;
 	}
 
-	/* we are handling the input ourselves */
-	hidinput_disconnect(hdev);
+	/* We do this after hid-input is done parsing reports so that
+	 * hid-input uses the most natural button and axis IDs.
+	 */
+	if (msc->input)
+		magicmouse_setup_input(msc->input, hdev);
+
+	if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
+		report = hid_register_report(hdev, HID_INPUT_REPORT,
+			MOUSE_REPORT_ID);
+	else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
+		report = hid_register_report(hdev, HID_INPUT_REPORT,
+			TRACKPAD_REPORT_ID);
+		report = hid_register_report(hdev, HID_INPUT_REPORT,
+			DOUBLE_REPORT_ID);
+	}
 
-	report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
 	if (!report) {
 		dev_err(&hdev->dev, "unable to register touch report\n");
 		ret = -ENOMEM;
@@ -421,39 +492,15 @@
 	}
 	report->size = 6;
 
-	ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
+	ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
 			HID_FEATURE_REPORT);
-	if (ret != sizeof(feature_1)) {
-		dev_err(&hdev->dev, "unable to request touch data (1:%d)\n",
-				ret);
-		goto err_stop_hw;
-	}
-	ret = hdev->hid_output_raw_report(hdev, feature_2,
-			sizeof(feature_2), HID_FEATURE_REPORT);
-	if (ret != sizeof(feature_2)) {
-		dev_err(&hdev->dev, "unable to request touch data (2:%d)\n",
+	if (ret != sizeof(feature)) {
+		dev_err(&hdev->dev, "unable to request touch data (%d)\n",
 				ret);
 		goto err_stop_hw;
 	}
 
-	input = input_allocate_device();
-	if (!input) {
-		dev_err(&hdev->dev, "can't alloc input device\n");
-		ret = -ENOMEM;
-		goto err_stop_hw;
-	}
-	magicmouse_setup_input(input, hdev);
-
-	ret = input_register_device(input);
-	if (ret) {
-		dev_err(&hdev->dev, "input device registration failed\n");
-		goto err_input;
-	}
-	msc->input = input;
-
 	return 0;
-err_input:
-	input_free_device(input);
 err_stop_hw:
 	hid_hw_stop(hdev);
 err_free:
@@ -466,13 +513,14 @@
 	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
 
 	hid_hw_stop(hdev);
-	input_unregister_device(msc->input);
 	kfree(msc);
 }
 
 static const struct hid_device_id magic_mice[] = {
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
-		.driver_data = 0 },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+		USB_DEVICE_ID_APPLE_MAGICMOUSE), .driver_data = 0 },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+		USB_DEVICE_ID_APPLE_MAGICTRACKPAD), .driver_data = 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, magic_mice);
@@ -483,6 +531,7 @@
 	.probe = magicmouse_probe,
 	.remove = magicmouse_remove,
 	.raw_event = magicmouse_raw_event,
+	.input_mapping = magicmouse_input_mapping,
 };
 
 static int __init magicmouse_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-microsoft.c linux-libre-2.6.37-gnu/drivers/hid/hid-microsoft.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-microsoft.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-microsoft.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,18 +33,19 @@
  * Microsoft Wireless Desktop Receiver (Model 1028) has
  * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
  */
-static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
-	if ((quirks & MS_RDESC) && rsize == 571 && rdesc[557] == 0x19 &&
+	if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
 			rdesc[559] == 0x29) {
 		dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
 				"Model 1028 report descriptor\n");
 		rdesc[557] = 0x35;
 		rdesc[559] = 0x45;
 	}
+	return rdesc;
 }
 
 #define ms_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-monterey.c linux-libre-2.6.37-gnu/drivers/hid/hid-monterey.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-monterey.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-monterey.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,14 +22,15 @@
 
 #include "hid-ids.h"
 
-static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+	if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
 		dev_info(&hdev->dev, "fixing up button/consumer in HID report "
 				"descriptor\n");
 		rdesc[30] = 0x0c;
 	}
+	return rdesc;
 }
 
 #define mr_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-ntrig.c linux-libre-2.6.37-gnu/drivers/hid/hid-ntrig.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-ntrig.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-ntrig.c	2011-01-04 19:50:19.000000000 -0500
@@ -90,6 +90,55 @@
 };
 
 
+/*
+ * This function converts the 4 byte raw firmware code into
+ * a string containing 5 comma separated numbers.
+ */
+static int ntrig_version_string(unsigned char *raw, char *buf)
+{
+	__u8 a =  (raw[1] & 0x0e) >> 1;
+	__u8 b =  (raw[0] & 0x3c) >> 2;
+	__u8 c = ((raw[0] & 0x03) << 3) | ((raw[3] & 0xe0) >> 5);
+	__u8 d = ((raw[3] & 0x07) << 3) | ((raw[2] & 0xe0) >> 5);
+	__u8 e =   raw[2] & 0x07;
+
+	/*
+	 * As yet unmapped bits:
+	 * 0b11000000 0b11110001 0b00011000 0b00011000
+	 */
+
+	return sprintf(buf, "%u.%u.%u.%u.%u", a, b, c, d, e);
+}
+
+static void ntrig_report_version(struct hid_device *hdev)
+{
+	int ret;
+	char buf[20];
+	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
+	unsigned char *data = kmalloc(8, GFP_KERNEL);
+
+	if (!data)
+		goto err_free;
+
+	ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			      USB_REQ_CLEAR_FEATURE,
+			      USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+			      USB_DIR_IN,
+			      0x30c, 1, data, 8,
+			      USB_CTRL_SET_TIMEOUT);
+
+	if (ret == 8) {
+		ret = ntrig_version_string(&data[2], buf);
+
+		dev_info(&hdev->dev,
+			 "Firmware version: %s (%02x%02x %02x%02x)\n",
+			 buf, data[2], data[3], data[4], data[5]);
+	}
+
+err_free:
+	kfree(data);
+}
+
 static ssize_t show_phys_width(struct device *dev,
 			       struct device_attribute *attr,
 			       char *buf)
@@ -377,8 +426,8 @@
  */
 
 static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
-		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+			       struct hid_field *field, struct hid_usage *usage,
+			       unsigned long **bit, int *max)
 {
 	struct ntrig_data *nd = hid_get_drvdata(hdev);
 
@@ -448,13 +497,13 @@
 		/* width/height mapped on TouchMajor/TouchMinor/Orientation */
 		case HID_DG_WIDTH:
 			hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOUCH_MAJOR);
+				      EV_ABS, ABS_MT_TOUCH_MAJOR);
 			return 1;
 		case HID_DG_HEIGHT:
 			hid_map_usage(hi, usage, bit, max,
-					EV_ABS, ABS_MT_TOUCH_MINOR);
+				      EV_ABS, ABS_MT_TOUCH_MINOR);
 			input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-					0, 1, 0, 0);
+					     0, 1, 0, 0);
 			return 1;
 		}
 		return 0;
@@ -468,8 +517,8 @@
 }
 
 static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
-		struct hid_field *field, struct hid_usage *usage,
-		unsigned long **bit, int *max)
+			      struct hid_field *field, struct hid_usage *usage,
+			      unsigned long **bit, int *max)
 {
 	/* No special mappings needed for the pen and single touch */
 	if (field->physical)
@@ -489,7 +538,7 @@
  * and call input_mt_sync after each point if necessary
  */
 static int ntrig_event (struct hid_device *hid, struct hid_field *field,
-		                        struct hid_usage *usage, __s32 value)
+			struct hid_usage *usage, __s32 value)
 {
 	struct input_dev *input = field->hidinput->input;
 	struct ntrig_data *nd = hid_get_drvdata(hid);
@@ -848,6 +897,8 @@
 	if (report)
 		usbhid_submit_report(hdev, report, USB_DIR_OUT);
 
+	ntrig_report_version(hdev);
+
 	ret = sysfs_create_group(&hdev->dev.kobj,
 			&ntrig_attribute_group);
 
@@ -860,7 +911,7 @@
 static void ntrig_remove(struct hid_device *hdev)
 {
 	sysfs_remove_group(&hdev->dev.kobj,
-			&ntrig_attribute_group);
+			   &ntrig_attribute_group);
 	hid_hw_stop(hdev);
 	kfree(hid_get_drvdata(hdev));
 }
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-ortek.c linux-libre-2.6.37-gnu/drivers/hid/hid-ortek.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-ortek.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-ortek.c	2011-01-04 19:50:19.000000000 -0500
@@ -19,14 +19,15 @@
 
 #include "hid-ids.h"
 
-static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
+	if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
 		dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
 				"report descriptor.\n");
 		rdesc[55] = 0x92;
 	}
+	return rdesc;
 }
 
 static const struct hid_device_id ortek_devices[] = {
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-petalynx.c linux-libre-2.6.37-gnu/drivers/hid/hid-petalynx.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-petalynx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-petalynx.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,10 +23,10 @@
 #include "hid-ids.h"
 
 /* Petalynx Maxter Remote has maximum for consumer page set too low */
-static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+	if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
 			rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
 			rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
 		dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
@@ -34,6 +34,7 @@
 		rdesc[60] = 0xfa;
 		rdesc[40] = 0xfa;
 	}
+	return rdesc;
 }
 
 #define pl_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-prodikeys.c linux-libre-2.6.37-gnu/drivers/hid/hid-prodikeys.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-prodikeys.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-prodikeys.c	2011-01-04 19:50:19.000000000 -0500
@@ -740,10 +740,10 @@
 /*
  * PC-MIDI report descriptor for report id is wrong.
  */
-static void pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize == 178 &&
+	if (*rsize == 178 &&
 	      rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
 	      rdesc[113] == 0xff) {
 		dev_info(&hdev->dev, "fixing up pc-midi keyboard report "
@@ -751,6 +751,7 @@
 
 		rdesc[144] = 0x18; /* report 4: was 0x10 report count */
 	}
+	return rdesc;
 }
 
 static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hidraw.c linux-libre-2.6.37-gnu/drivers/hid/hidraw.c
--- linux-libre-2.6.36-gnu/drivers/hid/hidraw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hidraw.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,7 +32,6 @@
 #include <linux/hid.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
-#include <linux/smp_lock.h>
 
 #include <linux/hidraw.h>
 
@@ -218,9 +217,13 @@
 	unsigned int minor = iminor(inode);
 	struct hidraw *dev;
 	struct hidraw_list *list = file->private_data;
+	int ret;
 
-	if (!hidraw_table[minor])
-		return -ENODEV;
+	mutex_lock(&minors_lock);
+	if (!hidraw_table[minor]) {
+		ret = -ENODEV;
+		goto unlock;
+	}
 
 	list_del(&list->node);
 	dev = hidraw_table[minor];
@@ -233,10 +236,12 @@
 			kfree(list->hidraw);
 		}
 	}
-
 	kfree(list);
+	ret = 0;
+unlock:
+	mutex_unlock(&minors_lock);
 
-	return 0;
+	return ret;
 }
 
 static long hidraw_ioctl(struct file *file, unsigned int cmd,
@@ -340,6 +345,7 @@
 	.open =         hidraw_open,
 	.release =      hidraw_release,
 	.unlocked_ioctl = hidraw_ioctl,
+	.llseek =	noop_llseek,
 };
 
 void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-roccat.c linux-libre-2.6.37-gnu/drivers/hid/hid-roccat.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-roccat.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-roccat.c	2011-01-04 19:50:19.000000000 -0500
@@ -384,6 +384,7 @@
 	.poll = roccat_poll,
 	.open = roccat_open,
 	.release = roccat_release,
+	.llseek = noop_llseek,
 };
 
 static int __init roccat_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-roccat-pyra.c linux-libre-2.6.37-gnu/drivers/hid/hid-roccat-pyra.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-roccat-pyra.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-roccat-pyra.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,968 @@
+/*
+ * Roccat Pyra driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+/*
+ * Roccat Pyra is a mobile gamer mouse which comes in wired and wireless
+ * variant. Wireless variant is not tested.
+ * Userland tools can be found at http://sourceforge.net/projects/roccat
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "hid-ids.h"
+#include "hid-roccat.h"
+#include "hid-roccat-pyra.h"
+
+static void profile_activated(struct pyra_device *pyra,
+		unsigned int new_profile)
+{
+	pyra->actual_profile = new_profile;
+	pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi;
+}
+
+static int pyra_send_control(struct usb_device *usb_dev, int value,
+		enum pyra_control_requests request)
+{
+	int len;
+	struct pyra_control control;
+
+	if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
+			request == PYRA_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+			(value < 0 || value > 4))
+		return -EINVAL;
+
+	control.command = PYRA_COMMAND_CONTROL;
+	control.value = value;
+	control.request = request;
+
+	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
+			sizeof(struct pyra_control),
+			USB_CTRL_SET_TIMEOUT);
+
+	if (len != sizeof(struct pyra_control))
+		return len;
+
+	return 0;
+}
+
+static int pyra_receive_control_status(struct usb_device *usb_dev)
+{
+	int len;
+	struct pyra_control control;
+
+	do {
+		msleep(10);
+
+		len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+				USB_REQ_CLEAR_FEATURE,
+				USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+				USB_DIR_IN,
+				PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
+				sizeof(struct pyra_control),
+				USB_CTRL_SET_TIMEOUT);
+
+		/* requested too early, try again */
+	} while (len == -EPROTO);
+
+	if (len == sizeof(struct pyra_control) &&
+			control.command == PYRA_COMMAND_CONTROL &&
+			control.request == PYRA_CONTROL_REQUEST_STATUS &&
+			control.value == 1)
+			return 0;
+	else {
+		dev_err(&usb_dev->dev, "receive control status: "
+				"unknown response 0x%x 0x%x\n",
+				control.request, control.value);
+		return -EINVAL;
+	}
+}
+
+static int pyra_get_profile_settings(struct usb_device *usb_dev,
+		struct pyra_profile_settings *buf, int number)
+{
+	int retval;
+
+	retval = pyra_send_control(usb_dev, number,
+			PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
+
+	if (retval)
+		return retval;
+
+	retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			USB_REQ_CLEAR_FEATURE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+			PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf,
+			sizeof(struct pyra_profile_settings),
+			USB_CTRL_SET_TIMEOUT);
+
+	if (retval != sizeof(struct pyra_profile_settings))
+		return retval;
+
+	return 0;
+}
+
+static int pyra_get_profile_buttons(struct usb_device *usb_dev,
+		struct pyra_profile_buttons *buf, int number)
+{
+	int retval;
+
+	retval = pyra_send_control(usb_dev, number,
+			PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
+
+	if (retval)
+		return retval;
+
+	retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			USB_REQ_CLEAR_FEATURE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+			PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf,
+			sizeof(struct pyra_profile_buttons),
+			USB_CTRL_SET_TIMEOUT);
+
+	if (retval != sizeof(struct pyra_profile_buttons))
+		return retval;
+
+	return 0;
+}
+
+static int pyra_get_settings(struct usb_device *usb_dev,
+		struct pyra_settings *buf)
+{
+	int len;
+	len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			USB_REQ_CLEAR_FEATURE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+			PYRA_USB_COMMAND_SETTINGS, 0, buf,
+			sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(struct pyra_settings))
+		return -EIO;
+	return 0;
+}
+
+static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
+{
+	int len;
+	len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+			USB_REQ_CLEAR_FEATURE,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+			PYRA_USB_COMMAND_INFO, 0, buf,
+			sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(struct pyra_info))
+		return -EIO;
+	return 0;
+}
+
+static int pyra_set_profile_settings(struct usb_device *usb_dev,
+		struct pyra_profile_settings const *settings)
+{
+	int len;
+	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings,
+			sizeof(struct pyra_profile_settings),
+			USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(struct pyra_profile_settings))
+		return -EIO;
+	if (pyra_receive_control_status(usb_dev))
+		return -EIO;
+	return 0;
+}
+
+static int pyra_set_profile_buttons(struct usb_device *usb_dev,
+		struct pyra_profile_buttons const *buttons)
+{
+	int len;
+	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons,
+			sizeof(struct pyra_profile_buttons),
+			USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(struct pyra_profile_buttons))
+		return -EIO;
+	if (pyra_receive_control_status(usb_dev))
+		return -EIO;
+	return 0;
+}
+
+static int pyra_set_settings(struct usb_device *usb_dev,
+		struct pyra_settings const *settings)
+{
+	int len;
+	len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+			USB_REQ_SET_CONFIGURATION,
+			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings,
+			sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
+	if (len != sizeof(struct pyra_settings))
+		return -EIO;
+	if (pyra_receive_control_status(usb_dev))
+		return -EIO;
+	return 0;
+}
+
+static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count, int number)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+	if (off >= sizeof(struct pyra_profile_settings))
+		return 0;
+
+	if (off + count > sizeof(struct pyra_profile_settings))
+		count = sizeof(struct pyra_profile_settings) - off;
+
+	mutex_lock(&pyra->pyra_lock);
+	memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off,
+			count);
+	mutex_unlock(&pyra->pyra_lock);
+
+	return count;
+}
+
+static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_settings(fp, kobj,
+			attr, buf, off, count, 0);
+}
+
+static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_settings(fp, kobj,
+			attr, buf, off, count, 1);
+}
+
+static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_settings(fp, kobj,
+			attr, buf, off, count, 2);
+}
+
+static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_settings(fp, kobj,
+			attr, buf, off, count, 3);
+}
+
+static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_settings(fp, kobj,
+			attr, buf, off, count, 4);
+}
+
+static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count, int number)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+	if (off >= sizeof(struct pyra_profile_buttons))
+		return 0;
+
+	if (off + count > sizeof(struct pyra_profile_buttons))
+		count = sizeof(struct pyra_profile_buttons) - off;
+
+	mutex_lock(&pyra->pyra_lock);
+	memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off,
+			count);
+	mutex_unlock(&pyra->pyra_lock);
+
+	return count;
+}
+
+static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_buttons(fp, kobj,
+			attr, buf, off, count, 0);
+}
+
+static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_buttons(fp, kobj,
+			attr, buf, off, count, 1);
+}
+
+static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_buttons(fp, kobj,
+			attr, buf, off, count, 2);
+}
+
+static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_buttons(fp, kobj,
+			attr, buf, off, count, 3);
+}
+
+static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	return pyra_sysfs_read_profilex_buttons(fp, kobj,
+			attr, buf, off, count, 4);
+}
+
+static ssize_t pyra_sysfs_write_profile_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	int retval = 0;
+	int difference;
+	int profile_number;
+	struct pyra_profile_settings *profile_settings;
+
+	if (off != 0 || count != sizeof(struct pyra_profile_settings))
+		return -EINVAL;
+
+	profile_number = ((struct pyra_profile_settings const *)buf)->number;
+	profile_settings = &pyra->profile_settings[profile_number];
+
+	mutex_lock(&pyra->pyra_lock);
+	difference = memcmp(buf, profile_settings,
+			sizeof(struct pyra_profile_settings));
+	if (difference) {
+		retval = pyra_set_profile_settings(usb_dev,
+				(struct pyra_profile_settings const *)buf);
+		if (!retval)
+			memcpy(profile_settings, buf,
+					sizeof(struct pyra_profile_settings));
+	}
+	mutex_unlock(&pyra->pyra_lock);
+
+	if (retval)
+		return retval;
+
+	return sizeof(struct pyra_profile_settings);
+}
+
+static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	int retval = 0;
+	int difference;
+	int profile_number;
+	struct pyra_profile_buttons *profile_buttons;
+
+	if (off != 0 || count != sizeof(struct pyra_profile_buttons))
+		return -EINVAL;
+
+	profile_number = ((struct pyra_profile_buttons const *)buf)->number;
+	profile_buttons = &pyra->profile_buttons[profile_number];
+
+	mutex_lock(&pyra->pyra_lock);
+	difference = memcmp(buf, profile_buttons,
+			sizeof(struct pyra_profile_buttons));
+	if (difference) {
+		retval = pyra_set_profile_buttons(usb_dev,
+				(struct pyra_profile_buttons const *)buf);
+		if (!retval)
+			memcpy(profile_buttons, buf,
+					sizeof(struct pyra_profile_buttons));
+	}
+	mutex_unlock(&pyra->pyra_lock);
+
+	if (retval)
+		return retval;
+
+	return sizeof(struct pyra_profile_buttons);
+}
+
+static ssize_t pyra_sysfs_read_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+
+	if (off >= sizeof(struct pyra_settings))
+		return 0;
+
+	if (off + count > sizeof(struct pyra_settings))
+		count = sizeof(struct pyra_settings) - off;
+
+	mutex_lock(&pyra->pyra_lock);
+	memcpy(buf, ((char const *)&pyra->settings) + off, count);
+	mutex_unlock(&pyra->pyra_lock);
+
+	return count;
+}
+
+static ssize_t pyra_sysfs_write_settings(struct file *fp,
+		struct kobject *kobj, struct bin_attribute *attr, char *buf,
+		loff_t off, size_t count)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	int retval = 0;
+	int difference;
+
+	if (off != 0 || count != sizeof(struct pyra_settings))
+		return -EINVAL;
+
+	mutex_lock(&pyra->pyra_lock);
+	difference = memcmp(buf, &pyra->settings, sizeof(struct pyra_settings));
+	if (difference) {
+		retval = pyra_set_settings(usb_dev,
+				(struct pyra_settings const *)buf);
+		if (!retval)
+			memcpy(&pyra->settings, buf,
+					sizeof(struct pyra_settings));
+	}
+	mutex_unlock(&pyra->pyra_lock);
+
+	if (retval)
+		return retval;
+
+	profile_activated(pyra, pyra->settings.startup_profile);
+
+	return sizeof(struct pyra_settings);
+}
+
+
+static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
+}
+
+static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
+}
+
+static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
+}
+
+static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+	return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
+}
+
+static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
+
+static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
+
+static DEVICE_ATTR(firmware_version, 0440,
+		pyra_sysfs_show_firmware_version, NULL);
+
+static DEVICE_ATTR(startup_profile, 0440,
+		pyra_sysfs_show_startup_profile, NULL);
+
+static struct attribute *pyra_attributes[] = {
+		&dev_attr_actual_cpi.attr,
+		&dev_attr_actual_profile.attr,
+		&dev_attr_firmware_version.attr,
+		&dev_attr_startup_profile.attr,
+		NULL
+};
+
+static struct attribute_group pyra_attribute_group = {
+		.attrs = pyra_attributes
+};
+
+static struct bin_attribute pyra_profile_settings_attr = {
+		.attr = { .name = "profile_settings", .mode = 0220 },
+		.size = sizeof(struct pyra_profile_settings),
+		.write = pyra_sysfs_write_profile_settings
+};
+
+static struct bin_attribute pyra_profile1_settings_attr = {
+		.attr = { .name = "profile1_settings", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_settings),
+		.read = pyra_sysfs_read_profile1_settings
+};
+
+static struct bin_attribute pyra_profile2_settings_attr = {
+		.attr = { .name = "profile2_settings", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_settings),
+		.read = pyra_sysfs_read_profile2_settings
+};
+
+static struct bin_attribute pyra_profile3_settings_attr = {
+		.attr = { .name = "profile3_settings", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_settings),
+		.read = pyra_sysfs_read_profile3_settings
+};
+
+static struct bin_attribute pyra_profile4_settings_attr = {
+		.attr = { .name = "profile4_settings", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_settings),
+		.read = pyra_sysfs_read_profile4_settings
+};
+
+static struct bin_attribute pyra_profile5_settings_attr = {
+		.attr = { .name = "profile5_settings", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_settings),
+		.read = pyra_sysfs_read_profile5_settings
+};
+
+static struct bin_attribute pyra_profile_buttons_attr = {
+		.attr = { .name = "profile_buttons", .mode = 0220 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.write = pyra_sysfs_write_profile_buttons
+};
+
+static struct bin_attribute pyra_profile1_buttons_attr = {
+		.attr = { .name = "profile1_buttons", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.read = pyra_sysfs_read_profile1_buttons
+};
+
+static struct bin_attribute pyra_profile2_buttons_attr = {
+		.attr = { .name = "profile2_buttons", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.read = pyra_sysfs_read_profile2_buttons
+};
+
+static struct bin_attribute pyra_profile3_buttons_attr = {
+		.attr = { .name = "profile3_buttons", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.read = pyra_sysfs_read_profile3_buttons
+};
+
+static struct bin_attribute pyra_profile4_buttons_attr = {
+		.attr = { .name = "profile4_buttons", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.read = pyra_sysfs_read_profile4_buttons
+};
+
+static struct bin_attribute pyra_profile5_buttons_attr = {
+		.attr = { .name = "profile5_buttons", .mode = 0440 },
+		.size = sizeof(struct pyra_profile_buttons),
+		.read = pyra_sysfs_read_profile5_buttons
+};
+
+static struct bin_attribute pyra_settings_attr = {
+		.attr = { .name = "settings", .mode = 0660 },
+		.size = sizeof(struct pyra_settings),
+		.read = pyra_sysfs_read_settings,
+		.write = pyra_sysfs_write_settings
+};
+
+static int pyra_create_sysfs_attributes(struct usb_interface *intf)
+{
+	int retval;
+
+	retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
+	if (retval)
+		goto exit_1;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile_settings_attr);
+	if (retval)
+		goto exit_2;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile1_settings_attr);
+	if (retval)
+		goto exit_3;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile2_settings_attr);
+	if (retval)
+		goto exit_4;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile3_settings_attr);
+	if (retval)
+		goto exit_5;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile4_settings_attr);
+	if (retval)
+		goto exit_6;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile5_settings_attr);
+	if (retval)
+		goto exit_7;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile_buttons_attr);
+	if (retval)
+		goto exit_8;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile1_buttons_attr);
+	if (retval)
+		goto exit_9;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile2_buttons_attr);
+	if (retval)
+		goto exit_10;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile3_buttons_attr);
+	if (retval)
+		goto exit_11;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile4_buttons_attr);
+	if (retval)
+		goto exit_12;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_profile5_buttons_attr);
+	if (retval)
+		goto exit_13;
+
+	retval = sysfs_create_bin_file(&intf->dev.kobj,
+			&pyra_settings_attr);
+	if (retval)
+		goto exit_14;
+
+	return 0;
+
+exit_14:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
+exit_13:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
+exit_12:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
+exit_11:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
+exit_10:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
+exit_9:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
+exit_8:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
+exit_7:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
+exit_6:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
+exit_5:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
+exit_4:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
+exit_3:
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
+exit_2:
+	sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
+exit_1:
+	return retval;
+}
+
+static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
+{
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
+	sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
+	sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
+}
+
+static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
+		struct pyra_device *pyra)
+{
+	struct pyra_info *info;
+	int retval, i;
+
+	mutex_init(&pyra->pyra_lock);
+
+	info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	retval = pyra_get_info(usb_dev, info);
+	if (retval) {
+		kfree(info);
+		return retval;
+	}
+	pyra->firmware_version = info->firmware_version;
+	kfree(info);
+
+	retval = pyra_get_settings(usb_dev, &pyra->settings);
+	if (retval)
+		return retval;
+
+	for (i = 0; i < 5; ++i) {
+		retval = pyra_get_profile_settings(usb_dev,
+				&pyra->profile_settings[i], i);
+		if (retval)
+			return retval;
+
+		retval = pyra_get_profile_buttons(usb_dev,
+				&pyra->profile_buttons[i], i);
+		if (retval)
+			return retval;
+	}
+
+	profile_activated(pyra, pyra->settings.startup_profile);
+
+	return 0;
+}
+
+static int pyra_init_specials(struct hid_device *hdev)
+{
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
+	struct pyra_device *pyra;
+	int retval;
+
+	if (intf->cur_altsetting->desc.bInterfaceProtocol
+			== USB_INTERFACE_PROTOCOL_MOUSE) {
+
+		pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
+		if (!pyra) {
+			dev_err(&hdev->dev, "can't alloc device descriptor\n");
+			return -ENOMEM;
+		}
+		hid_set_drvdata(hdev, pyra);
+
+		retval = pyra_init_pyra_device_struct(usb_dev, pyra);
+		if (retval) {
+			dev_err(&hdev->dev,
+					"couldn't init struct pyra_device\n");
+			goto exit_free;
+		}
+
+		retval = roccat_connect(hdev);
+		if (retval < 0) {
+			dev_err(&hdev->dev, "couldn't init char dev\n");
+		} else {
+			pyra->chrdev_minor = retval;
+			pyra->roccat_claimed = 1;
+		}
+
+		retval = pyra_create_sysfs_attributes(intf);
+		if (retval) {
+			dev_err(&hdev->dev, "cannot create sysfs files\n");
+			goto exit_free;
+		}
+	} else {
+		hid_set_drvdata(hdev, NULL);
+	}
+
+	return 0;
+exit_free:
+	kfree(pyra);
+	return retval;
+}
+
+static void pyra_remove_specials(struct hid_device *hdev)
+{
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct pyra_device *pyra;
+
+	if (intf->cur_altsetting->desc.bInterfaceProtocol
+			== USB_INTERFACE_PROTOCOL_MOUSE) {
+		pyra_remove_sysfs_attributes(intf);
+		pyra = hid_get_drvdata(hdev);
+		if (pyra->roccat_claimed)
+			roccat_disconnect(pyra->chrdev_minor);
+		kfree(hid_get_drvdata(hdev));
+	}
+}
+
+static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int retval;
+
+	retval = hid_parse(hdev);
+	if (retval) {
+		dev_err(&hdev->dev, "parse failed\n");
+		goto exit;
+	}
+
+	retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (retval) {
+		dev_err(&hdev->dev, "hw start failed\n");
+		goto exit;
+	}
+
+	retval = pyra_init_specials(hdev);
+	if (retval) {
+		dev_err(&hdev->dev, "couldn't install mouse\n");
+		goto exit_stop;
+	}
+	return 0;
+
+exit_stop:
+	hid_hw_stop(hdev);
+exit:
+	return retval;
+}
+
+static void pyra_remove(struct hid_device *hdev)
+{
+	pyra_remove_specials(hdev);
+	hid_hw_stop(hdev);
+}
+
+static void pyra_keep_values_up_to_date(struct pyra_device *pyra,
+		u8 const *data)
+{
+	struct pyra_mouse_event_button const *button_event;
+
+	switch (data[0]) {
+	case PYRA_MOUSE_REPORT_NUMBER_BUTTON:
+		button_event = (struct pyra_mouse_event_button const *)data;
+		switch (button_event->type) {
+		case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
+			profile_activated(pyra, button_event->data1 - 1);
+			break;
+		case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
+			pyra->actual_cpi = button_event->data1;
+			break;
+		}
+		break;
+	}
+}
+
+static void pyra_report_to_chrdev(struct pyra_device const *pyra,
+		u8 const *data)
+{
+	struct pyra_roccat_report roccat_report;
+	struct pyra_mouse_event_button const *button_event;
+
+	if (data[0] != PYRA_MOUSE_REPORT_NUMBER_BUTTON)
+		return;
+
+	button_event = (struct pyra_mouse_event_button const *)data;
+
+	switch (button_event->type) {
+	case PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2:
+	case PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI:
+		roccat_report.type = button_event->type;
+		roccat_report.value = button_event->data1;
+		roccat_report.key = 0;
+		roccat_report_event(pyra->chrdev_minor,
+				(uint8_t const *)&roccat_report,
+				sizeof(struct pyra_roccat_report));
+		break;
+	case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
+	case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
+	case PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH:
+		if (button_event->data2 == PYRA_MOUSE_EVENT_BUTTON_PRESS) {
+			roccat_report.type = button_event->type;
+			roccat_report.key = button_event->data1;
+			/*
+			 * pyra reports profile numbers with range 1-5.
+			 * Keeping this behaviour.
+			 */
+			roccat_report.value = pyra->actual_profile + 1;
+			roccat_report_event(pyra->chrdev_minor,
+					(uint8_t const *)&roccat_report,
+					sizeof(struct pyra_roccat_report));
+		}
+		break;
+	}
+}
+
+static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report,
+		u8 *data, int size)
+{
+	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+	struct pyra_device *pyra = hid_get_drvdata(hdev);
+
+	if (intf->cur_altsetting->desc.bInterfaceProtocol
+			!= USB_INTERFACE_PROTOCOL_MOUSE)
+		return 0;
+
+	pyra_keep_values_up_to_date(pyra, data);
+
+	if (pyra->roccat_claimed)
+		pyra_report_to_chrdev(pyra, data);
+
+	return 0;
+}
+
+static const struct hid_device_id pyra_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT,
+			USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
+	/* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(hid, pyra_devices);
+
+static struct hid_driver pyra_driver = {
+		.name = "pyra",
+		.id_table = pyra_devices,
+		.probe = pyra_probe,
+		.remove = pyra_remove,
+		.raw_event = pyra_raw_event
+};
+
+static int __init pyra_init(void)
+{
+	return hid_register_driver(&pyra_driver);
+}
+
+static void __exit pyra_exit(void)
+{
+	hid_unregister_driver(&pyra_driver);
+}
+
+module_init(pyra_init);
+module_exit(pyra_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Pyra driver");
+MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-roccat-pyra.h linux-libre-2.6.37-gnu/drivers/hid/hid-roccat-pyra.h
--- linux-libre-2.6.36-gnu/drivers/hid/hid-roccat-pyra.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-roccat-pyra.h	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,186 @@
+#ifndef __HID_ROCCAT_PYRA_H
+#define __HID_ROCCAT_PYRA_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/types.h>
+
+#pragma pack(push)
+#pragma pack(1)
+
+struct pyra_b {
+	uint8_t command; /* PYRA_COMMAND_B */
+	uint8_t size; /* always 3 */
+	uint8_t unknown; /* 1 */
+};
+
+struct pyra_control {
+	uint8_t command; /* PYRA_COMMAND_CONTROL */
+	/*
+	 * value is profile number for request_settings and request_buttons
+	 * 1 if status ok for request_status
+	 */
+	uint8_t value; /* Range 0-4 */
+	uint8_t request;
+};
+
+enum pyra_control_requests {
+	PYRA_CONTROL_REQUEST_STATUS = 0x00,
+	PYRA_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
+	PYRA_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20
+};
+
+struct pyra_settings {
+	uint8_t command; /* PYRA_COMMAND_SETTINGS */
+	uint8_t size; /* always 3 */
+	uint8_t startup_profile; /* Range 0-4! */
+};
+
+struct pyra_profile_settings {
+	uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */
+	uint8_t size; /* always 0xd */
+	uint8_t number; /* Range 0-4 */
+	uint8_t xysync;
+	uint8_t x_sensitivity; /* 0x1-0xa */
+	uint8_t y_sensitivity;
+	uint8_t x_cpi; /* unused */
+	uint8_t y_cpi; /* this value is for x and y */
+	uint8_t lightswitch; /* 0 = off, 1 = on */
+	uint8_t light_effect;
+	uint8_t handedness;
+	uint16_t checksum; /* byte sum */
+};
+
+struct pyra_profile_buttons {
+	uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
+	uint8_t size; /* always 0x13 */
+	uint8_t number; /* Range 0-4 */
+	uint8_t buttons[14];
+	uint16_t checksum; /* byte sum */
+};
+
+struct pyra_info {
+	uint8_t command; /* PYRA_COMMAND_INFO */
+	uint8_t size; /* always 6 */
+	uint8_t firmware_version;
+	uint8_t unknown1; /* always 0 */
+	uint8_t unknown2; /* always 1 */
+	uint8_t unknown3; /* always 0 */
+};
+
+enum pyra_commands {
+	PYRA_COMMAND_CONTROL = 0x4,
+	PYRA_COMMAND_SETTINGS = 0x5,
+	PYRA_COMMAND_PROFILE_SETTINGS = 0x6,
+	PYRA_COMMAND_PROFILE_BUTTONS = 0x7,
+	PYRA_COMMAND_INFO = 0x9,
+	PYRA_COMMAND_B = 0xb
+};
+
+enum pyra_usb_commands {
+	PYRA_USB_COMMAND_CONTROL = 0x304,
+	PYRA_USB_COMMAND_SETTINGS = 0x305,
+	PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+	PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+	PYRA_USB_COMMAND_INFO = 0x309,
+	PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */
+};
+
+enum pyra_mouse_report_numbers {
+	PYRA_MOUSE_REPORT_NUMBER_HID = 1,
+	PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2,
+	PYRA_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct pyra_mouse_event_button {
+	uint8_t report_number; /* always 3 */
+	uint8_t unknown; /* always 0 */
+	uint8_t type;
+	uint8_t data1;
+	uint8_t data2;
+};
+
+struct pyra_mouse_event_audio {
+	uint8_t report_number; /* always 2 */
+	uint8_t type;
+	uint8_t unused; /* always 0 */
+};
+
+/* hid audio controls */
+enum pyra_mouse_event_audio_types {
+	PYRA_MOUSE_EVENT_AUDIO_TYPE_MUTE = 0xe2,
+	PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_UP = 0xe9,
+	PYRA_MOUSE_EVENT_AUDIO_TYPE_VOLUME_DOWN = 0xea,
+};
+
+enum pyra_mouse_event_button_types {
+	/*
+	 * Mouse sends tilt events on report_number 1 and 3
+	 * Tilt events are sent repeatedly with 0.94s between first and second
+	 * event and 0.22s on subsequent
+	 */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_TILT = 0x10,
+
+	/*
+	 * These are sent sequentially
+	 * data1 contains new profile number in range 1-5
+	 */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_1 = 0x20,
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_PROFILE_2 = 0x30,
+
+	/*
+	 * data1 = button_number (rmp index)
+	 * data2 = pressed/released
+	 */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO = 0x40,
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT = 0x50,
+
+	/*
+	 * data1 = button_number (rmp index)
+	 */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+
+	/* data1 = new cpi */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_CPI = 0xb0,
+
+	/* data1 and data2 = new sensitivity */
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+
+	PYRA_MOUSE_EVENT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum {
+	PYRA_MOUSE_EVENT_BUTTON_PRESS = 0,
+	PYRA_MOUSE_EVENT_BUTTON_RELEASE = 1,
+};
+
+struct pyra_roccat_report {
+	uint8_t type;
+	uint8_t value;
+	uint8_t key;
+};
+
+#pragma pack(pop)
+
+struct pyra_device {
+	int actual_profile;
+	int actual_cpi;
+	int firmware_version;
+	int roccat_claimed;
+	int chrdev_minor;
+	struct mutex pyra_lock;
+	struct pyra_settings settings;
+	struct pyra_profile_settings profile_settings[5];
+	struct pyra_profile_buttons profile_buttons[5];
+};
+
+#endif
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-samsung.c linux-libre-2.6.37-gnu/drivers/hid/hid-samsung.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-samsung.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-samsung.c	2011-01-04 19:50:19.000000000 -0500
@@ -61,10 +61,10 @@
 			"descriptor\n", rsize);
 }
 
-static void samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+	if (*rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
 			rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
 			rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
 			rdesc[182] == 0x40) {
@@ -74,24 +74,25 @@
 		rdesc[180] = 0x06;
 		rdesc[182] = 0x42;
 	} else
-	if (rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
+	if (*rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
 			rdesc[194] == 0x25 && rdesc[195] == 0x12) {
 		samsung_irda_dev_trace(hdev, 203);
 		rdesc[193] = 0x1;
 		rdesc[195] = 0xf;
 	} else
-	if (rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
+	if (*rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
 			rdesc[126] == 0x25 && rdesc[127] == 0x11) {
 		samsung_irda_dev_trace(hdev, 135);
 		rdesc[125] = 0x1;
 		rdesc[127] = 0xe;
 	} else
-	if (rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
+	if (*rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
 			rdesc[162] == 0x25 && rdesc[163] == 0x01) {
 		samsung_irda_dev_trace(hdev, 171);
 		rdesc[161] = 0x1;
 		rdesc[163] = 0x3;
 	}
+	return rdesc;
 }
 
 #define samsung_kbd_mouse_map_key_clear(c) \
@@ -130,11 +131,12 @@
 	return 1;
 }
 
-static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-	unsigned int rsize)
+static __u8 *samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+	unsigned int *rsize)
 {
 	if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product)
-		samsung_irda_report_fixup(hdev, rdesc, rsize);
+		rdesc = samsung_irda_report_fixup(hdev, rdesc, rsize);
+	return rdesc;
 }
 
 static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-sony.c linux-libre-2.6.37-gnu/drivers/hid/hid-sony.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-sony.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-sony.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,24 +24,46 @@
 
 #include "hid-ids.h"
 
-#define VAIO_RDESC_CONSTANT 0x0001
+#define VAIO_RDESC_CONSTANT     (1 << 0)
+#define SIXAXIS_CONTROLLER_USB  (1 << 1)
+#define SIXAXIS_CONTROLLER_BT   (1 << 2)
 
 struct sony_sc {
 	unsigned long quirks;
 };
 
 /* Sony Vaio VGX has wrongly mouse pointer declared as constant */
-static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
 	struct sony_sc *sc = hid_get_drvdata(hdev);
 
 	if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
-			rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
+			*rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
 		dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
 				"descriptor\n");
 		rdesc[55] = 0x06;
 	}
+	return rdesc;
+}
+
+static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
+		size_t count, unsigned char report_type)
+{
+	struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct usb_host_interface *interface = intf->cur_altsetting;
+	int report_id = buf[0];
+	int ret;
+
+	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		HID_REQ_SET_REPORT,
+		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		((report_type + 1) << 8) | report_id,
+		interface->desc.bInterfaceNumber, buf, count,
+		USB_CTRL_SET_TIMEOUT);
+
+	return ret;
 }
 
 /*
@@ -49,7 +71,7 @@
  * to "operational".  Without this, the ps3 controller will not report any
  * events.
  */
-static int sony_set_operational_usb(struct hid_device *hdev)
+static int sixaxis_set_operational_usb(struct hid_device *hdev)
 {
 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -74,7 +96,7 @@
 	return ret;
 }
 
-static int sony_set_operational_bt(struct hid_device *hdev)
+static int sixaxis_set_operational_bt(struct hid_device *hdev)
 {
 	unsigned char buf[] = { 0xf4,  0x42, 0x03, 0x00, 0x00 };
 	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
@@ -108,16 +130,14 @@
 		goto err_free;
 	}
 
-	switch (hdev->bus) {
-	case BUS_USB:
-		ret = sony_set_operational_usb(hdev);
-		break;
-	case BUS_BLUETOOTH:
-		ret = sony_set_operational_bt(hdev);
-		break;
-	default:
-		ret = 0;
+	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
+		hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
+		ret = sixaxis_set_operational_usb(hdev);
 	}
+	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+		ret = sixaxis_set_operational_bt(hdev);
+	else
+		ret = 0;
 
 	if (ret < 0)
 		goto err_stop;
@@ -137,8 +157,10 @@
 }
 
 static const struct hid_device_id sony_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
-	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
+		.driver_data = SIXAXIS_CONTROLLER_USB },
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
+		.driver_data = SIXAXIS_CONTROLLER_BT },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
 		.driver_data = VAIO_RDESC_CONSTANT },
 	{ }
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-stantum.c linux-libre-2.6.37-gnu/drivers/hid/hid-stantum.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-stantum.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-stantum.c	2011-01-04 19:50:19.000000000 -0500
@@ -249,6 +249,8 @@
 
 static const struct hid_device_id stantum_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, stantum_devices);
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-sunplus.c linux-libre-2.6.37-gnu/drivers/hid/hid-sunplus.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-sunplus.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-sunplus.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,16 +22,17 @@
 
 #include "hid-ids.h"
 
-static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-		unsigned int rsize)
+static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
 {
-	if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+	if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
 			rdesc[106] == 0x03) {
 		dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
 				"report descriptor\n");
 		rdesc[105] = rdesc[110] = 0x03;
 		rdesc[106] = rdesc[111] = 0x21;
 	}
+	return rdesc;
 }
 
 #define sp_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-tmff.c linux-libre-2.6.37-gnu/drivers/hid/hid-tmff.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-tmff.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-tmff.c	2011-01-04 19:50:19.000000000 -0500
@@ -256,6 +256,8 @@
 		.driver_data = (unsigned long)ff_joystick },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654),	/* FGT Force Feedback Wheel */
 		.driver_data = (unsigned long)ff_joystick },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a),	/* F430 Force Feedback Wheel */
+		.driver_data = (unsigned long)ff_joystick },
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, tm_devices);
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-uclogic.c linux-libre-2.6.37-gnu/drivers/hid/hid-uclogic.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-uclogic.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-uclogic.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,623 @@
+/*
+ *  HID driver for UC-Logic devices not fully compliant with HID standard
+ *
+ *  Copyright (c) 2010 Nikolai Kondrashov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * The original descriptors of WPXXXXU tablets have three report IDs, of
+ * which only two are used (8 and 9), and the remaining (7) seems to have
+ * the originally intended pen description which was abandoned for some
+ * reason.  From this unused description it is possible to extract the
+ * actual physical extents and resolution. All the models use the same
+ * descriptor with different extents for the unused report ID.
+ *
+ * Here it is:
+ *
+ *  Usage Page (Digitizer),         ; Digitizer (0Dh)
+ *  Usage (Pen),                    ; Pen (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (7),
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (Tip Switch),         ; Tip switch (42h, momentary control)
+ *      Usage (Barrel Switch),      ; Barrel switch (44h, momentary control)
+ *      Usage (Eraser),             ; Eraser (45h, momentary control)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (3),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage (In Range),           ; In range (32h, momentary control)
+ *      Report Count (1),
+ *      Input (Variable),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Physical Minimum (0),
+ *      Physical Maximum (Xpm),
+ *      Logical Maximum (Xlm),
+ *      Input (Variable),
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Physical Maximum (Ypm),
+ *      Logical Maximum (Ylm),
+ *      Input (Variable),
+ *      Pop,
+ *      Usage Page (Digitizer),     ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),       ; Tip pressure (30h, dynamic value)
+ *      Logical Maximum (1023),
+ *      Input (Variable),
+ *      Report Size (16),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (Mouse),                  ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (8),
+ *    Usage (Pointer),              ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),        ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (03h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Count (3),
+ *      Report Size (1),
+ *      Input (Variable),
+ *      Report Count (5),
+ *      Input (Constant),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Usage (Wheel),              ; Wheel (38h, dynamic value)
+ *      Usage (00h),
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (4),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (Mouse),                  ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (9),
+ *    Usage (Pointer),              ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),        ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (03h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Count (3),
+ *      Report Size (1),
+ *      Input (Variable),
+ *      Report Count (5),
+ *      Input (Constant),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (32767),
+ *      Physical Minimum (0),
+ *      Physical Maximum (32767),
+ *      Report Count (2),
+ *      Report Size (16),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),     ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),       ; Tip pressure (30h, dynamic value)
+ *      Logical Maximum (1023),
+ *      Report Count (1),
+ *      Report Size (16),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection
+ *
+ * Here are the extents values for the WPXXXXU models:
+ *
+ *              Xpm     Xlm     Ypm     Ylm
+ *  WP4030U     4000    8000    3000    6000
+ *  WP5540U     5500    11000   4000    8000
+ *  WP8060U     8000    16000   6000    12000
+ *
+ * This suggests that all of them have 2000 LPI resolution, as advertised.
+ */
+
+/* Size of the original descriptor of WPXXXXU tablets */
+#define WPXXXXU_RDESC_ORIG_SIZE	212
+
+/*
+ * Fixed WP4030U report descriptor.
+ * Although the hardware might actually support it, the mouse description
+ * has been removed, since there seems to be no devices having one and it
+ * wouldn't make much sense because of the working area size.
+ */
+static __u8 wp4030u_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/* Fixed WP5540U report descriptor */
+static __u8 wp5540u_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x08,         /*      Report ID (8),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x05, 0x09,         /*          Usage Page (Button),        */
+	0x19, 0x01,         /*          Usage Minimum (01h),        */
+	0x29, 0x03,         /*          Usage Maximum (03h),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x15, 0x81,         /*          Logical Minimum (-127),     */
+	0x25, 0x7F,         /*          Logical Maximum (127),      */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/* Fixed WP8060U report descriptor */
+static __u8 wp8060u_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x08,         /*      Report ID (8),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x05, 0x09,         /*          Usage Page (Button),        */
+	0x19, 0x01,         /*          Usage Minimum (01h),        */
+	0x29, 0x03,         /*          Usage Maximum (03h),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x15, 0x81,         /*          Logical Minimum (-127),     */
+	0x25, 0x7F,         /*          Logical Maximum (127),      */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/*
+ * Original PF1209 report descriptor.
+ *
+ * The descriptor is similar to WPXXXXU descriptors, with an addition of a
+ * feature report (ID 4) of unknown purpose.
+ *
+ * Although the advertised resolution is 4000 LPI the unused report ID
+ * (taken from WPXXXXU, it seems) states 2000 LPI, but it is probably
+ * incorrect and is a result of blind copying without understanding. Anyway
+ * the real logical extents are always scaled to 0..32767, which IMHO spoils
+ * the precision.
+ *
+ *  Usage Page (Digitizer),         ; Digitizer (0Dh)
+ *  Usage (Pen),                    ; Pen (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (7),
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (Tip Switch),         ; Tip switch (42h, momentary control)
+ *      Usage (Barrel Switch),      ; Barrel switch (44h, momentary control)
+ *      Usage (Eraser),             ; Eraser (45h, momentary control)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (3),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage (In Range),           ; In range (32h, momentary control)
+ *      Report Count (1),
+ *      Input (Variable),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Physical Minimum (0),
+ *      Physical Maximum (12000),
+ *      Logical Maximum (24000),
+ *      Input (Variable),
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Physical Maximum (9000),
+ *      Logical Maximum (18000),
+ *      Input (Variable),
+ *      Pop,
+ *      Usage Page (Digitizer),     ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),       ; Tip pressure (30h, dynamic value)
+ *      Logical Maximum (1023),
+ *      Input (Variable),
+ *      Report Size (16),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (Mouse),                  ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (8),
+ *    Usage (Pointer),              ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),        ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (03h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Count (3),
+ *      Report Size (1),
+ *      Input (Variable),
+ *      Report Count (5),
+ *      Input (Constant),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Usage (Wheel),              ; Wheel (38h, dynamic value)
+ *      Usage (00h),
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (4),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (Mouse),                  ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (9),
+ *    Usage (Pointer),              ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),        ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (03h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Count (3),
+ *      Report Size (1),
+ *      Input (Variable),
+ *      Report Count (5),
+ *      Input (Constant),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (32767),
+ *      Physical Minimum (0),
+ *      Physical Maximum (32767),
+ *      Report Count (2),
+ *      Report Size (16),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),     ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),       ; Tip pressure (30h, dynamic value)
+ *      Logical Maximum (1023),
+ *      Report Count (1),
+ *      Report Size (16),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (00h),
+ *  Collection (Application),
+ *    Report ID (4),
+ *    Logical Minimum (0),
+ *    Logical Maximum (255),
+ *    Usage (00h),
+ *    Report Size (8),
+ *    Report Count (3),
+ *    Feature (Variable),
+ *  End Collection
+ */
+
+/* Size of the original descriptor of PF1209 tablet */
+#define PF1209_RDESC_ORIG_SIZE	234
+
+/*
+ * Fixed PF1209 report descriptor
+ *
+ * The descriptor is fixed similarly to WP5540U and WP8060U, plus the
+ * feature report is removed, because its purpose is unknown and it is of no
+ * use to the generic HID driver anyway for now.
+ */
+static __u8 pf1209_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x09,         /*      Report ID (9),                  */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
+	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x08,         /*      Report ID (8),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x05, 0x09,         /*          Usage Page (Button),        */
+	0x19, 0x01,         /*          Usage Minimum (01h),        */
+	0x29, 0x03,         /*          Usage Maximum (03h),        */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x05,         /*          Report Count (5),           */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x15, 0x81,         /*          Logical Minimum (-127),     */
+	0x25, 0x7F,         /*          Logical Maximum (127),      */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x81, 0x01,         /*          Input (Constant),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+					unsigned int *rsize)
+{
+	switch (hdev->product) {
+	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
+		if (*rsize == PF1209_RDESC_ORIG_SIZE) {
+			rdesc = pf1209_rdesc_fixed;
+			*rsize = sizeof(pf1209_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
+		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+			rdesc = wp4030u_rdesc_fixed;
+			*rsize = sizeof(wp4030u_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
+		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+			rdesc = wp5540u_rdesc_fixed;
+			*rsize = sizeof(wp5540u_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
+		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
+			rdesc = wp8060u_rdesc_fixed;
+			*rsize = sizeof(wp8060u_rdesc_fixed);
+		}
+		break;
+	}
+
+	return rdesc;
+}
+
+static const struct hid_device_id uclogic_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, uclogic_devices);
+
+static struct hid_driver uclogic_driver = {
+	.name = "uclogic",
+	.id_table = uclogic_devices,
+	.report_fixup = uclogic_report_fixup,
+};
+
+static int __init uclogic_init(void)
+{
+	return hid_register_driver(&uclogic_driver);
+}
+
+static void __exit uclogic_exit(void)
+{
+	hid_unregister_driver(&uclogic_driver);
+}
+
+module_init(uclogic_init);
+module_exit(uclogic_exit);
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-waltop.c linux-libre-2.6.37-gnu/drivers/hid/hid-waltop.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-waltop.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-waltop.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1099 @@
+/*
+ *  HID driver for Waltop devices not fully compliant with HID standard
+ *
+ *  Copyright (c) 2010 Nikolai Kondrashov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * There exists an official driver on the manufacturer's website, which
+ * wasn't submitted to the kernel, for some reason. The official driver
+ * doesn't seem to support extra features of some tablets, like wheels.
+ *
+ * It shows that the feature report ID 2 could be used to control any waltop
+ * tablet input mode, switching it between "default", "tablet" and "ink".
+ *
+ * This driver only uses "default" mode for all the supported tablets. This
+ * mode tries to be HID-compatible (not very successfully), but cripples the
+ * resolution of some tablets.
+ *
+ * The "tablet" mode uses some proprietary, yet decipherable protocol, which
+ * represents the correct resolution, but is possibly HID-incompatible (i.e.
+ * indescribable by a report descriptor).
+ *
+ * The purpose of the "ink" mode is unknown.
+ *
+ * The feature reports needed for switching to each mode are these:
+ *
+ * 02 16 00     default
+ * 02 16 01     tablet
+ * 02 16 02     ink
+ */
+
+/*
+ * Original Slim Tablet 5.8 inch report descriptor.
+ *
+ * All the reports except the report with ID 16 (the stylus) are unused,
+ * possibly because the tablet is not configured to, or because they were
+ * just copied from a more capable model. The full purpose of features
+ * described for report ID 2 is unknown.
+ *
+ * The stylus buttons are described as three bit fields, whereas actually
+ * it's an "array", i.e. they're reported as button numbers (1, 2 and 3).
+ * The "eraser" field is not used. There is also a "push" without a "pop" in
+ * the stylus description.
+ *
+ *  Usage Page (Desktop),           ; Generic desktop controls (01h)
+ *  Usage (Mouse),                  ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (1),
+ *    Usage (Pointer),              ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),        ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (05h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Size (3),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Usage (Wheel),              ; Wheel (38h, dynamic value)
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Digitizer),         ; Digitizer (0Dh)
+ *  Usage (Pen),                    ; Pen (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (2),
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *      Usage (Azimuth),            ; Azimuth (3Fh, dynamic value)
+ *      Usage (Altitude),           ; Altitude (40h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (2),
+ *      Feature (Variable),
+ *    End Collection,
+ *    Report ID (5),
+ *    Usage Page (Digitizer),       ; Digitizer (0Dh)
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (10),
+ *    Usage Page (Digitizer),       ; Digitizer (0Dh)
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (16),
+ *    Usage (Stylus),               ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (Tip Switch),         ; Tip switch (42h, momentary control)
+ *      Usage (Barrel Switch),      ; Barrel switch (44h, momentary control)
+ *      Usage (Invert),             ; Invert (3Ch, momentary control)
+ *      Usage (Eraser),             ; Eraser (45h, momentary control)
+ *      Usage (In Range),           ; In range (32h, momentary control)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),       ; Generic desktop controls (01h)
+ *      Usage (X),                  ; X (30h, dynamic value)
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Logical Minimum (0),
+ *      Logical Maximum (10000),
+ *      Physical Minimum (0),
+ *      Physical Maximum (10000),
+ *      Input (Variable),
+ *      Usage (Y),                  ; Y (31h, dynamic value)
+ *      Logical Maximum (6000),
+ *      Physical Maximum (6000),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),     ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),       ; Tip pressure (30h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1023),
+ *      Physical Minimum (0),
+ *      Physical Maximum (1023),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection
+ */
+
+/* Size of the original report descriptor of Slim Tablet 5.8 inch */
+#define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE	222
+
+/*
+ * Fixed Slim Tablet 5.8 inch descriptor.
+ *
+ * All the reports except the stylus report (ID 16) were removed as unused.
+ * The stylus buttons description was fixed.
+ */
+static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x10,         /*      Report ID (16),                 */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x15, 0x01,         /*          Logical Minimum (1),        */
+	0x25, 0x03,         /*          Logical Maximum (3),        */
+	0x75, 0x04,         /*          Report Size (4),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x80,               /*          Input,                      */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
+	0x26, 0x10, 0x27,   /*          Logical Maximum (10000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
+	0x26, 0x70, 0x17,   /*          Logical Maximum (6000),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/*
+ * Original Slim Tablet 12.1 inch report descriptor.
+ *
+ * The descriptor is similar to the Slim Tablet 5.8 inch descriptor with the
+ * addition of a keyboard report, seemingly unused. It may have get here
+ * from a Media Tablet - probably an unimplemented feature.
+ *
+ *  Usage Page (Desktop),             ; Generic desktop controls (01h)
+ *  Usage (Mouse),                    ; Mouse (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (1),
+ *    Usage (Pointer),                ; Pointer (01h, physical collection)
+ *    Collection (Physical),
+ *      Usage Page (Button),          ; Button (09h)
+ *      Usage Minimum (01h),
+ *      Usage Maximum (05h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Size (3),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),         ; Generic desktop controls (01h)
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Usage (Y),                    ; Y (31h, dynamic value)
+ *      Usage (Wheel),                ; Wheel (38h, dynamic value)
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Digitizer),           ; Digitizer (0Dh)
+ *  Usage (Pen),                      ; Pen (02h, application collection)
+ *  Collection (Application),
+ *    Report ID (2),
+ *    Usage (Stylus),                 ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *      Usage (Azimuth),              ; Azimuth (3Fh, dynamic value)
+ *      Usage (Altitude),             ; Altitude (40h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (2),
+ *      Feature (Variable),
+ *    End Collection,
+ *    Report ID (5),
+ *    Usage Page (Digitizer),         ; Digitizer (0Dh)
+ *    Usage (Stylus),                 ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (10),
+ *    Usage Page (Digitizer),         ; Digitizer (0Dh)
+ *    Usage (Stylus),                 ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (16),
+ *    Usage (Stylus),                 ; Stylus (20h, logical collection)
+ *    Collection (Physical),
+ *      Usage (Tip Switch),           ; Tip switch (42h, momentary control)
+ *      Usage (Barrel Switch),        ; Barrel switch (44h, momentary control)
+ *      Usage (Invert),               ; Invert (3Ch, momentary control)
+ *      Usage (Eraser),               ; Eraser (45h, momentary control)
+ *      Usage (In Range),             ; In range (32h, momentary control)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),         ; Generic desktop controls (01h)
+ *      Usage (X),                    ; X (30h, dynamic value)
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Logical Minimum (0),
+ *      Logical Maximum (20000),
+ *      Physical Minimum (0),
+ *      Physical Maximum (20000),
+ *      Input (Variable),
+ *      Usage (Y),                    ; Y (31h, dynamic value)
+ *      Logical Maximum (12500),
+ *      Physical Maximum (12500),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),       ; Digitizer (0Dh)
+ *      Usage (Tip Pressure),         ; Tip pressure (30h, dynamic value)
+ *      Logical Minimum (0),
+ *      Logical Maximum (1023),
+ *      Physical Minimum (0),
+ *      Physical Maximum (1023),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),             ; Generic desktop controls (01h)
+ *  Usage (Keyboard),                 ; Keyboard (06h, application collection)
+ *  Collection (Application),
+ *    Report ID (13),
+ *    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
+ *    Usage Minimum (KB Leftcontrol), ; Keyboard left control
+ *                                    ; (E0h, dynamic value)
+ *    Usage Maximum (KB Right GUI),   ; Keyboard right GUI (E7h, dynamic value)
+ *    Logical Minimum (0),
+ *    Logical Maximum (1),
+ *    Report Size (1),
+ *    Report Count (8),
+ *    Input (Variable),
+ *    Report Size (8),
+ *    Report Count (1),
+ *    Input (Constant),
+ *    Usage Page (Keyboard),          ; Keyboard/keypad (07h)
+ *    Usage Minimum (None),           ; No event (00h, selector)
+ *    Usage Maximum (KB Application), ; Keyboard Application (65h, selector)
+ *    Logical Minimum (0),
+ *    Logical Maximum (101),
+ *    Report Size (8),
+ *    Report Count (5),
+ *    Input,
+ *  End Collection
+ */
+
+/* Size of the original report descriptor of Slim Tablet 12.1 inch */
+#define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE	269
+
+/*
+ * Fixed Slim Tablet 12.1 inch descriptor.
+ *
+ * All the reports except the stylus report (ID 16) were removed as unused.
+ * The stylus buttons description was fixed.
+ */
+static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x10,         /*      Report ID (16),                 */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x15, 0x01,         /*          Logical Minimum (1),        */
+	0x25, 0x03,         /*          Logical Maximum (3),        */
+	0x75, 0x04,         /*          Report Size (4),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x80,               /*          Input,                      */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
+	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
+	0x26, 0xD4, 0x30,   /*          Logical Maximum (12500),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0                /*  End Collection                      */
+};
+
+/*
+ * Original Media Tablet 10.6 inch report descriptor.
+ *
+ * There are at least two versions of this model in the wild. They are
+ * represented by Genius G-Pen M609 (older version) and Genius G-Pen M609X
+ * (newer version).
+ *
+ * Both versions have the usual pen with two barrel buttons and two
+ * identical wheels with center buttons in the top corners of the tablet
+ * base. They also have buttons on the top, between the wheels, for
+ * selecting the wheels' functions and wide/standard mode. In the wide mode
+ * the whole working surface is sensed, in the standard mode a narrower area
+ * is sensed, but the logical report extents remain the same. These modes
+ * correspond roughly to 16:9 and 4:3 aspect ratios respectively.
+ *
+ * The older version has three wheel function buttons ("scroll", "zoom" and
+ * "volume") and two separate buttons for wide and standard mode. The newer
+ * version has four wheel function buttons (plus "brush") and only one
+ * button is used for selecting wide/standard mode. So, the total number of
+ * buttons remains the same, but one of the mode buttons is repurposed as a
+ * wheels' function button in the newer version.
+ *
+ * The wheel functions are:
+ * scroll   - the wheels act as scroll wheels, the center buttons switch
+ *            between vertical and horizontal scrolling;
+ * zoom     - the wheels zoom in/out, the buttons supposedly reset to 100%;
+ * volume   - the wheels control the sound volume, the buttons mute;
+ * brush    - the wheels are supposed to control brush width in a graphics
+ *            editor, the buttons do nothing.
+ *
+ * Below is the newer version's report descriptor. It may very well be that
+ * the older version's descriptor is different and thus it won't be
+ * supported.
+ *
+ * The mouse report (ID 1) only uses the wheel field for reporting the tablet
+ * wheels' scroll mode. The keyboard report (ID 13) is used to report the
+ * wheels' zoom and brush control functions as key presses. The report ID 12
+ * is used to report the wheels' volume control functions. The stylus report
+ * (ID 16) has the same problems as the Slim Tablet 5.8 inch report has.
+ *
+ * The rest of the reports are unused, at least in the default configuration.
+ * The purpose of the features is unknown.
+ *
+ *  Usage Page (Desktop),
+ *  Usage (Mouse),
+ *  Collection (Application),
+ *    Report ID (1),
+ *    Usage (Pointer),
+ *    Collection (Physical),
+ *      Usage Page (Button),
+ *      Usage Minimum (01h),
+ *      Usage Maximum (05h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Size (3),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),
+ *      Usage (X),
+ *      Usage (Y),
+ *      Usage (Wheel),
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Digitizer),
+ *  Usage (Pen),
+ *  Collection (Application),
+ *    Report ID (2),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *      Usage (Azimuth),
+ *      Usage (Altitude),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (2),
+ *      Feature (Variable),
+ *    End Collection,
+ *    Report ID (5),
+ *    Usage Page (Digitizer),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (10),
+ *    Usage Page (Digitizer),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (16),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (Tip Switch),
+ *      Usage (Barrel Switch),
+ *      Usage (Invert),
+ *      Usage (Eraser),
+ *      Usage (In Range),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),
+ *      Usage (X),
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Logical Minimum (0),
+ *      Logical Maximum (18000),
+ *      Physical Minimum (0),
+ *      Physical Maximum (18000),
+ *      Input (Variable),
+ *      Usage (Y),
+ *      Logical Maximum (11000),
+ *      Physical Maximum (11000),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),
+ *      Usage (Tip Pressure),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1023),
+ *      Physical Minimum (0),
+ *      Physical Maximum (1023),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),
+ *  Usage (Keyboard),
+ *  Collection (Application),
+ *    Report ID (13),
+ *    Usage Page (Keyboard),
+ *    Usage Minimum (KB Leftcontrol),
+ *    Usage Maximum (KB Right GUI),
+ *    Logical Minimum (0),
+ *    Logical Maximum (1),
+ *    Report Size (1),
+ *    Report Count (8),
+ *    Input (Variable),
+ *    Report Size (8),
+ *    Report Count (1),
+ *    Input (Constant),
+ *    Usage Page (Keyboard),
+ *    Usage Minimum (None),
+ *    Usage Maximum (KB Application),
+ *    Logical Minimum (0),
+ *    Logical Maximum (101),
+ *    Report Size (8),
+ *    Report Count (5),
+ *    Input,
+ *  End Collection,
+ *  Usage Page (Consumer),
+ *  Usage (Consumer Control),
+ *  Collection (Application),
+ *    Report ID (12),
+ *    Usage (Volume Inc),
+ *    Usage (Volume Dec),
+ *    Usage (Mute),
+ *    Logical Minimum (0),
+ *    Logical Maximum (1),
+ *    Report Size (1),
+ *    Report Count (3),
+ *    Input (Variable, Relative),
+ *    Report Size (5),
+ *    Report Count (1),
+ *    Input (Constant, Variable, Relative),
+ *  End Collection
+ */
+
+/* Size of the original report descriptor of Media Tablet 10.6 inch */
+#define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE	300
+
+/*
+ * Fixed Media Tablet 10.6 inch descriptor.
+ *
+ * The descriptions of reports unused in the default configuration are
+ * removed. The stylus report (ID 16) is fixed similarly to Slim Tablet 5.8
+ * inch.  The unused mouse report (ID 1) fields are replaced with constant
+ * padding.
+ *
+ * The keyboard report (ID 13) is hacked to instead have an "array" field
+ * reporting consumer page controls, and all the unused bits are masked out
+ * with constant padding. The "brush" wheels' function is represented as "Scan
+ * Previous/Next Track" controls due to the lack of brush controls in the
+ * usage tables specification.
+ */
+static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x10,         /*      Report ID (16),                 */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x15, 0x01,         /*          Logical Minimum (1),        */
+	0x25, 0x03,         /*          Logical Maximum (3),        */
+	0x75, 0x04,         /*          Report Size (4),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x80,               /*          Input,                      */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
+	0x26, 0x50, 0x46,   /*          Logical Maximum (18000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
+	0x26, 0xF8, 0x2A,   /*          Logical Maximum (11000),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x01,         /*      Report ID (1),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
+		0x0C, 0x00,
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x0C,         /*  Usage Page (Consumer),              */
+	0x09, 0x01,         /*  Usage (Consumer Control),           */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0D,         /*      Report ID (13),                 */
+	0x95, 0x01,         /*      Report Count (1),               */
+	0x75, 0x10,         /*      Report Size (16),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
+	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
+	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
+	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
+	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
+	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
+	0x15, 0x0C,         /*      Logical Minimum (12),           */
+	0x25, 0x17,         /*      Logical Maximum (23),           */
+	0x75, 0x05,         /*      Report Size (5),                */
+	0x80,               /*      Input,                          */
+	0x75, 0x03,         /*      Report Size (3),                */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0x75, 0x20,         /*      Report Size (32),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0xC0,               /*  End Collection,                     */
+	0x09, 0x01,         /*  Usage (Consumer Control),           */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0C,         /*      Report ID (12),                 */
+	0x75, 0x01,         /*      Report Size (1),                */
+	0x09, 0xE9,         /*      Usage (Volume Inc),             */
+	0x09, 0xEA,         /*      Usage (Volume Dec),             */
+	0x09, 0xE2,         /*      Usage (Mute),                   */
+	0x14,               /*      Logical Minimum (0),            */
+	0x25, 0x01,         /*      Logical Maximum (1),            */
+	0x95, 0x03,         /*      Report Count (3),               */
+	0x81, 0x06,         /*      Input (Variable, Relative),     */
+	0x95, 0x35,         /*      Report Count (53),              */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0xC0                /*  End Collection                      */
+};
+
+/*
+ * Original Media Tablet 14.1 inch report descriptor.
+ *
+ * There are at least two versions of this model in the wild. They are
+ * represented by Genius G-Pen M712 (older version) and Genius G-Pen M712X
+ * (newer version). The hardware difference between these versions is the same
+ * as between older and newer versions of Media Tablet 10.6 inch. The report
+ * descriptors are identical for both versions.
+ *
+ * The function, behavior and report descriptor of this tablet is similar to
+ * that of Media Tablet 10.6 inch. However, there is one more field (with
+ * Consumer AC Pan usage) in the mouse description. Then the tablet X and Y
+ * logical extents both get scaled to 0..16383 range (a hardware limit?),
+ * which kind of defeats the advertised 4000 LPI resolution, considering the
+ * physical extents of 12x7.25 inches. Plus, reports 5, 10 and 255 are used
+ * sometimes (while moving the pen) with unknown purpose. Also, the key codes
+ * generated for zoom in/out are different.
+ *
+ *  Usage Page (Desktop),
+ *  Usage (Mouse),
+ *  Collection (Application),
+ *    Report ID (1),
+ *    Usage (Pointer),
+ *    Collection (Physical),
+ *      Usage Page (Button),
+ *      Usage Minimum (01h),
+ *      Usage Maximum (05h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Size (3),
+ *      Report Count (1),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),
+ *      Usage (X),
+ *      Usage (Y),
+ *      Usage (Wheel),
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (3),
+ *      Input (Variable, Relative),
+ *      Usage Page (Consumer),
+ *      Logical Minimum (-127),
+ *      Logical Maximum (127),
+ *      Report Size (8),
+ *      Report Count (1),
+ *      Usage (AC Pan),
+ *      Input (Variable, Relative),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Digitizer),
+ *  Usage (Pen),
+ *  Collection (Application),
+ *    Report ID (2),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *      Usage (Azimuth),
+ *      Usage (Altitude),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (2),
+ *      Feature (Variable),
+ *    End Collection,
+ *    Report ID (5),
+ *    Usage Page (Digitizer),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (10),
+ *    Usage Page (Digitizer),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (00h),
+ *      Logical Minimum (0),
+ *      Logical Maximum (255),
+ *      Report Size (8),
+ *      Report Count (7),
+ *      Input (Variable),
+ *    End Collection,
+ *    Report ID (16),
+ *    Usage (Stylus),
+ *    Collection (Physical),
+ *      Usage (Tip Switch),
+ *      Usage (Barrel Switch),
+ *      Usage (Invert),
+ *      Usage (Eraser),
+ *      Usage (In Range),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1),
+ *      Report Size (1),
+ *      Report Count (5),
+ *      Input (Variable),
+ *      Report Count (3),
+ *      Input (Constant, Variable),
+ *      Usage Page (Desktop),
+ *      Usage (X),
+ *      Report Size (16),
+ *      Report Count (1),
+ *      Push,
+ *      Unit Exponent (13),
+ *      Unit (Inch^3),
+ *      Logical Minimum (0),
+ *      Logical Maximum (16383),
+ *      Physical Minimum (0),
+ *      Physical Maximum (16383),
+ *      Input (Variable),
+ *      Usage (Y),
+ *      Input (Variable),
+ *      Usage Page (Digitizer),
+ *      Usage (Tip Pressure),
+ *      Logical Minimum (0),
+ *      Logical Maximum (1023),
+ *      Physical Minimum (0),
+ *      Physical Maximum (1023),
+ *      Input (Variable),
+ *    End Collection,
+ *  End Collection,
+ *  Usage Page (Desktop),
+ *  Usage (Keyboard),
+ *  Collection (Application),
+ *    Report ID (13),
+ *    Usage Page (Keyboard),
+ *    Usage Minimum (KB Leftcontrol),
+ *    Usage Maximum (KB Right GUI),
+ *    Logical Minimum (0),
+ *    Logical Maximum (1),
+ *    Report Size (1),
+ *    Report Count (8),
+ *    Input (Variable),
+ *    Report Size (8),
+ *    Report Count (1),
+ *    Input (Constant),
+ *    Usage Page (Keyboard),
+ *    Usage Minimum (None),
+ *    Usage Maximum (KB Application),
+ *    Logical Minimum (0),
+ *    Logical Maximum (101),
+ *    Report Size (8),
+ *    Report Count (5),
+ *    Input,
+ *  End Collection,
+ *  Usage Page (Consumer),
+ *  Usage (Consumer Control),
+ *  Collection (Application),
+ *    Report ID (12),
+ *    Usage (Volume Inc),
+ *    Usage (Volume Dec),
+ *    Usage (Mute),
+ *    Logical Minimum (0),
+ *    Logical Maximum (1),
+ *    Report Size (1),
+ *    Report Count (3),
+ *    Input (Variable, Relative),
+ *    Report Size (5),
+ *    Report Count (1),
+ *    Input (Constant, Variable, Relative),
+ *  End Collection
+ */
+
+/* Size of the original report descriptor of Media Tablet 14.1 inch */
+#define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE	309
+
+/*
+ * Fixed Media Tablet 14.1 inch descriptor.
+ * It is fixed similarly to the Media Tablet 10.6 inch descriptor.
+ */
+static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
+	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
+	0x09, 0x02,         /*  Usage (Pen),                        */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x10,         /*      Report ID (16),                 */
+	0x09, 0x20,         /*      Usage (Stylus),                 */
+	0xA0,               /*      Collection (Physical),          */
+	0x09, 0x42,         /*          Usage (Tip Switch),         */
+	0x09, 0x44,         /*          Usage (Barrel Switch),      */
+	0x09, 0x46,         /*          Usage (Tablet Pick),        */
+	0x15, 0x01,         /*          Logical Minimum (1),        */
+	0x25, 0x03,         /*          Logical Maximum (3),        */
+	0x75, 0x04,         /*          Report Size (4),            */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x80,               /*          Input,                      */
+	0x75, 0x01,         /*          Report Size (1),            */
+	0x09, 0x32,         /*          Usage (In Range),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x75, 0x10,         /*          Report Size (16),           */
+	0x95, 0x01,         /*          Report Count (1),           */
+	0x14,               /*          Logical Minimum (0),        */
+	0xA4,               /*          Push,                       */
+	0x05, 0x01,         /*          Usage Page (Desktop),       */
+	0x65, 0x13,         /*          Unit (Inch),                */
+	0x55, 0xFD,         /*          Unit Exponent (-3),         */
+	0x34,               /*          Physical Minimum (0),       */
+	0x09, 0x30,         /*          Usage (X),                  */
+	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
+	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0x09, 0x31,         /*          Usage (Y),                  */
+	0x46, 0x52, 0x1C,   /*          Physical Maximum (7250),    */
+	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xB4,               /*          Pop,                        */
+	0x09, 0x30,         /*          Usage (Tip Pressure),       */
+	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
+	0x81, 0x02,         /*          Input (Variable),           */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x01,         /*  Usage Page (Desktop),               */
+	0x09, 0x02,         /*  Usage (Mouse),                      */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x01,         /*      Report ID (1),                  */
+	0x09, 0x01,         /*      Usage (Pointer),                */
+	0xA0,               /*      Collection (Physical),          */
+	0x75, 0x08,         /*          Report Size (8),            */
+	0x95, 0x03,         /*          Report Count (3),           */
+	0x81, 0x03,         /*          Input (Constant, Variable), */
+	0x95, 0x02,         /*          Report Count (2),           */
+	0x15, 0xFF,         /*          Logical Minimum (-1),       */
+	0x25, 0x01,         /*          Logical Maximum (1),        */
+	0x09, 0x38,         /*          Usage (Wheel),              */
+	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
+		0x0C, 0x00,
+	0x81, 0x06,         /*          Input (Variable, Relative), */
+	0xC0,               /*      End Collection,                 */
+	0xC0,               /*  End Collection,                     */
+	0x05, 0x0C,         /*  Usage Page (Consumer),              */
+	0x09, 0x01,         /*  Usage (Consumer Control),           */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0D,         /*      Report ID (13),                 */
+	0x95, 0x01,         /*      Report Count (1),               */
+	0x75, 0x10,         /*      Report Size (16),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
+	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
+	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
+	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
+	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x08,               /*      Usage (00h),                    */
+	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
+	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
+	0x15, 0x0C,         /*      Logical Minimum (12),           */
+	0x25, 0x17,         /*      Logical Maximum (23),           */
+	0x75, 0x05,         /*      Report Size (5),                */
+	0x80,               /*      Input,                          */
+	0x75, 0x03,         /*      Report Size (3),                */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0x75, 0x20,         /*      Report Size (32),               */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0xC0,               /*  End Collection,                     */
+	0x09, 0x01,         /*  Usage (Consumer Control),           */
+	0xA1, 0x01,         /*  Collection (Application),           */
+	0x85, 0x0C,         /*      Report ID (12),                 */
+	0x75, 0x01,         /*      Report Size (1),                */
+	0x09, 0xE9,         /*      Usage (Volume Inc),             */
+	0x09, 0xEA,         /*      Usage (Volume Dec),             */
+	0x09, 0xE2,         /*      Usage (Mute),                   */
+	0x14,               /*      Logical Minimum (0),            */
+	0x25, 0x01,         /*      Logical Maximum (1),            */
+	0x95, 0x03,         /*      Report Count (3),               */
+	0x81, 0x06,         /*      Input (Variable, Relative),     */
+	0x75, 0x05,         /*      Report Size (5),                */
+	0x81, 0x03,         /*      Input (Constant, Variable),     */
+	0xC0                /*  End Collection                      */
+};
+
+static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	switch (hdev->product) {
+	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH:
+		if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
+			rdesc = slim_tablet_5_8_inch_rdesc_fixed;
+			*rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH:
+		if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) {
+			rdesc = slim_tablet_12_1_inch_rdesc_fixed;
+			*rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
+		if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
+			rdesc = media_tablet_10_6_inch_rdesc_fixed;
+			*rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
+		}
+		break;
+	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH:
+		if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) {
+			rdesc = media_tablet_14_1_inch_rdesc_fixed;
+			*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
+		}
+		break;
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id waltop_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+				USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+				USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, waltop_devices);
+
+static struct hid_driver waltop_driver = {
+	.name = "waltop",
+	.id_table = waltop_devices,
+	.report_fixup = waltop_report_fixup,
+};
+
+static int __init waltop_init(void)
+{
+	return hid_register_driver(&waltop_driver);
+}
+
+static void __exit waltop_exit(void)
+{
+	hid_unregister_driver(&waltop_driver);
+}
+
+module_init(waltop_init);
+module_exit(waltop_exit);
+MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/hid/hid-zydacron.c linux-libre-2.6.37-gnu/drivers/hid/hid-zydacron.c
--- linux-libre-2.6.36-gnu/drivers/hid/hid-zydacron.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/hid-zydacron.c	2011-01-04 19:50:19.000000000 -0500
@@ -27,10 +27,10 @@
 * Zydacron remote control has an invalid HID report descriptor,
 * that needs fixing before we can parse it.
 */
-static void zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
-	unsigned int rsize)
+static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+	unsigned int *rsize)
 {
-	if (rsize >= 253 &&
+	if (*rsize >= 253 &&
 		rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
 		rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
 		rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
@@ -40,6 +40,7 @@
 			rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
 			rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
 		}
+	return rdesc;
 }
 
 #define zc_map_key_clear(c) \
diff -druN linux-libre-2.6.36-gnu/drivers/hid/Kconfig linux-libre-2.6.37-gnu/drivers/hid/Kconfig
--- linux-libre-2.6.36-gnu/drivers/hid/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -56,20 +56,20 @@
 	depends on HID
 
 config HID_3M_PCT
-	tristate "3M PCT"
+	tristate "3M PCT touchscreen"
 	depends on USB_HID
 	---help---
 	Support for 3M PCT touch screens.
 
 config HID_A4TECH
-	tristate "A4 tech" if EMBEDDED
+	tristate "A4 tech mice" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for A4 tech X5 and WOP-35 / Trust 450L mice.
 
 config HID_ACRUX_FF
-	tristate "ACRUX force feedback support"
+	tristate "ACRUX force feedback"
 	depends on USB_HID
 	select INPUT_FF_MEMLESS
 	---help---
@@ -77,7 +77,7 @@
 	game controllers.
 
 config HID_APPLE
-	tristate "Apple" if EMBEDDED
+	tristate "Apple {i,Power,Mac}Books" if EMBEDDED
 	depends on (USB_HID || BT_HIDP)
 	default !EMBEDDED
 	---help---
@@ -88,7 +88,7 @@
 	MacBooks, MacBook Pros and Apple Aluminum.
 
 config HID_BELKIN
-	tristate "Belkin" if EMBEDDED
+	tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
@@ -101,14 +101,14 @@
 	Support for Cando dual touch panel.
 
 config HID_CHERRY
-	tristate "Cherry" if EMBEDDED
+	tristate "Cherry Cymotion keyboard" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Cherry Cymotion keyboard.
 
 config HID_CHICONY
-	tristate "Chicony" if EMBEDDED
+	tristate "Chicony Tactical pad" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
@@ -130,20 +130,20 @@
 	  and some additional multimedia keys.
 
 config HID_CYPRESS
-	tristate "Cypress" if EMBEDDED
+	tristate "Cypress mouse and barcode readers" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for cypress mouse and barcode readers.
 
 config HID_DRAGONRISE
-	tristate "DragonRise Inc. support"
+	tristate "DragonRise Inc. game controller"
 	depends on USB_HID
 	---help---
 	Say Y here if you have DragonRise Inc.game controllers.
 
 config DRAGONRISE_FF
-	bool "DragonRise Inc. force feedback support"
+	bool "DragonRise Inc. force feedback"
 	depends on HID_DRAGONRISE
 	select INPUT_FF_MEMLESS
 	---help---
@@ -157,46 +157,58 @@
 	Support for the eGalax dual-touch panel.
 
 config HID_ELECOM
-	tristate "ELECOM"
+	tristate "ELECOM BM084 bluetooth mouse"
 	depends on BT_HIDP
 	---help---
 	Support for the ELECOM BM084 (bluetooth mouse).
 
 config HID_EZKEY
-	tristate "Ezkey" if EMBEDDED
+	tristate "Ezkey BTC 8193 keyboard" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Ezkey BTC 8193 keyboard.
 
 config HID_KYE
-	tristate "Kye" if EMBEDDED
+	tristate "Kye/Genius Ergo Mouse" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Kye/Genius Ergo Mouse.
 
+config HID_UCLOGIC
+	tristate "UC-Logic"
+	depends on USB_HID
+	---help---
+	Support for UC-Logic tablets.
+
+config HID_WALTOP
+	tristate "Waltop"
+	depends on USB_HID
+	---help---
+	Support for Waltop tablets.
+
 config HID_GYRATION
-	tristate "Gyration"
+	tristate "Gyration remote control"
 	depends on USB_HID
 	---help---
 	Support for Gyration remote control.
 
 config HID_TWINHAN
-	tristate "Twinhan"
+	tristate "Twinhan IR remote control"
 	depends on USB_HID
 	---help---
 	Support for Twinhan IR remote control.
 
 config HID_KENSINGTON
-	tristate "Kensington" if EMBEDDED
+	tristate "Kensington Slimblade Trackball" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Kensington Slimblade Trackball.
 
 config HID_LOGITECH
-	tristate "Logitech" if EMBEDDED
+	tristate "Logitech devices" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
@@ -220,12 +232,12 @@
 	  force feedback.
 
 config LOGIRUMBLEPAD2_FF
-	bool "Logitech Rumblepad 2 force feedback support"
+	bool "Logitech RumblePad/Rumblepad 2 force feedback support"
 	depends on HID_LOGITECH
 	select INPUT_FF_MEMLESS
 	help
 	  Say Y here if you want to enable force feedback support for Logitech
-	  Rumblepad 2 devices.
+	  RumblePad and Rumblepad 2 devices.
 
 config LOGIG940_FF
 	bool "Logitech Flight System G940 force feedback support"
@@ -235,6 +247,14 @@
 	  Say Y here if you want to enable force feedback support for Logitech
 	  Flight System G940 devices.
 
+config LOGIWII_FF
+	bool "Logitech Speed Force Wireless force feedback support"
+	depends on HID_LOGITECH
+	select INPUT_FF_MEMLESS
+	help
+	  Say Y here if you want to enable force feedback support for Logitech
+	  Speed Force Wireless (Wii) devices.
+
 config HID_MAGICMOUSE
 	tristate "Apple MagicMouse multi-touch support"
 	depends on BT_HIDP
@@ -245,39 +265,39 @@
 	Apple Wireless "Magic" Mouse.
 
 config HID_MICROSOFT
-	tristate "Microsoft" if EMBEDDED
+	tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Microsoft devices that are not fully compliant with HID standard.
 
 config HID_MOSART
-	tristate "MosArt"
+	tristate "MosArt dual-touch panels"
 	depends on USB_HID
 	---help---
 	Support for MosArt dual-touch panels.
 
 config HID_MONTEREY
-	tristate "Monterey" if EMBEDDED
+	tristate "Monterey Genius KB29E keyboard" if EMBEDDED
 	depends on USB_HID
 	default !EMBEDDED
 	---help---
 	Support for Monterey Genius KB29E.
 
 config HID_NTRIG
-	tristate "NTrig"
+	tristate "N-Trig touch screen"
 	depends on USB_HID
 	---help---
 	Support for N-Trig touch screen.
 
 config HID_ORTEK
-	tristate "Ortek"
+	tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad"
 	depends on USB_HID
 	---help---
 	Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
 
 config HID_PANTHERLORD
-	tristate "Pantherlord support"
+	tristate "Pantherlord/GreenAsia game controller"
 	depends on USB_HID
 	---help---
 	  Say Y here if you have a PantherLord/GreenAsia based game controller
@@ -292,7 +312,7 @@
 	  or adapter and want to enable force feedback support for it.
 
 config HID_PETALYNX
-	tristate "Petalynx"
+	tristate "Petalynx Maxter remote control"
 	depends on USB_HID
 	---help---
 	Support for Petalynx Maxter remote control.
@@ -356,7 +376,7 @@
 	  Provide access to PicoLCD's GPO pins via leds class.
 
 config HID_QUANTA
-	tristate "Quanta Optical Touch"
+	tristate "Quanta Optical Touch panels"
 	depends on USB_HID
 	---help---
 	Support for Quanta Optical Touch dual-touch panels.
@@ -376,32 +396,39 @@
 	---help---
 	Support for Roccat Kone mouse.
 
+config HID_ROCCAT_PYRA
+	tristate "Roccat Pyra mouse support"
+	depends on USB_HID
+	select HID_ROCCAT
+	---help---
+	Support for Roccat Pyra mouse.
+
 config HID_SAMSUNG
-	tristate "Samsung"
+	tristate "Samsung InfraRed remote control or keyboards"
 	depends on USB_HID
 	---help---
 	Support for Samsung InfraRed remote control or keyboards.
 
 config HID_SONY
-	tristate "Sony"
+	tristate "Sony PS3 controller"
 	depends on USB_HID
 	---help---
 	Support for Sony PS3 controller.
 
 config HID_STANTUM
-	tristate "Stantum"
+	tristate "Stantum multitouch panel"
 	depends on USB_HID
 	---help---
 	Support for Stantum multitouch panel.
 
 config HID_SUNPLUS
-	tristate "Sunplus"
+	tristate "Sunplus wireless desktop"
 	depends on USB_HID
 	---help---
 	Support for Sunplus wireless desktop.
 
 config HID_GREENASIA
-	tristate "GreenAsia (Product ID 0x12) support"
+	tristate "GreenAsia (Product ID 0x12) game controller support"
 	depends on USB_HID
 	---help---
 	  Say Y here if you have a GreenAsia (Product ID 0x12) based game
diff -druN linux-libre-2.6.36-gnu/drivers/hid/Makefile linux-libre-2.6.37-gnu/drivers/hid/Makefile
--- linux-libre-2.6.36-gnu/drivers/hid/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -21,6 +21,9 @@
 ifdef CONFIG_LOGIG940_FF
 	hid-logitech-objs	+= hid-lg3ff.o
 endif
+ifdef CONFIG_LOGIWII_FF
+	hid-logitech-objs	+= hid-lg4ff.o
+endif
 
 obj-$(CONFIG_HID_3M_PCT)	+= hid-3m-pct.o
 obj-$(CONFIG_HID_A4TECH)	+= hid-a4tech.o
@@ -52,6 +55,7 @@
 obj-$(CONFIG_HID_PICOLCD)	+= hid-picolcd.o
 obj-$(CONFIG_HID_ROCCAT)	+= hid-roccat.o
 obj-$(CONFIG_HID_ROCCAT_KONE)	+= hid-roccat-kone.o
+obj-$(CONFIG_HID_ROCCAT_PYRA)	+= hid-roccat-pyra.o
 obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
@@ -61,9 +65,11 @@
 obj-$(CONFIG_HID_THRUSTMASTER)	+= hid-tmff.o
 obj-$(CONFIG_HID_TOPSEED)	+= hid-topseed.o
 obj-$(CONFIG_HID_TWINHAN)	+= hid-twinhan.o
+obj-$(CONFIG_HID_UCLOGIC)	+= hid-uclogic.o
 obj-$(CONFIG_HID_ZEROPLUS)	+= hid-zpff.o
 obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
+obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff -druN linux-libre-2.6.36-gnu/drivers/hid/usbhid/hid-core.c linux-libre-2.6.37-gnu/drivers/hid/usbhid/hid-core.c
--- linux-libre-2.6.36-gnu/drivers/hid/usbhid/hid-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/usbhid/hid-core.c	2011-01-04 19:50:19.000000000 -0500
@@ -807,9 +807,10 @@
 	struct usb_host_interface *interface = intf->cur_altsetting;
 	int ret;
 
-	if (usbhid->urbout) {
+	if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
 		int actual_length;
 		int skipped_report_id = 0;
+
 		if (buf[0] == 0x0) {
 			/* Don't send the Report ID */
 			buf++;
@@ -1469,9 +1470,6 @@
 	retval = usbhid_quirks_init(quirks_param);
 	if (retval)
 		goto usbhid_quirks_init_fail;
-	retval = hiddev_init();
-	if (retval)
-		goto hiddev_init_fail;
 	retval = usb_register(&hid_driver);
 	if (retval)
 		goto usb_register_fail;
@@ -1479,8 +1477,6 @@
 
 	return 0;
 usb_register_fail:
-	hiddev_exit();
-hiddev_init_fail:
 	usbhid_quirks_exit();
 usbhid_quirks_init_fail:
 	hid_unregister_driver(&hid_usb_driver);
@@ -1493,7 +1489,6 @@
 static void __exit hid_exit(void)
 {
 	usb_deregister(&hid_driver);
-	hiddev_exit();
 	usbhid_quirks_exit();
 	hid_unregister_driver(&hid_usb_driver);
 	destroy_workqueue(resumption_waker);
diff -druN linux-libre-2.6.36-gnu/drivers/hid/usbhid/hiddev.c linux-libre-2.6.37-gnu/drivers/hid/usbhid/hiddev.c
--- linux-libre-2.6.36-gnu/drivers/hid/usbhid/hiddev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/usbhid/hiddev.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/input.h>
 #include <linux/usb.h>
 #include <linux/hid.h>
@@ -67,8 +66,6 @@
 	struct mutex thread_lock;
 };
 
-static struct usb_driver hiddev_driver;
-
 /*
  * Find a report, given the report's type and ID.  The ID can be specified
  * indirectly by REPORT_ID_FIRST (which returns the first report of the given
@@ -847,6 +844,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= hiddev_compat_ioctl,
 #endif
+	.llseek		= noop_llseek,
 };
 
 static char *hiddev_devnode(struct device *dev, mode_t *mode)
@@ -925,41 +923,3 @@
 		kfree(hiddev);
 	}
 }
-
-/* Currently this driver is a USB driver.  It's not a conventional one in
- * the sense that it doesn't probe at the USB level.  Instead it waits to
- * be connected by HID through the hiddev_connect / hiddev_disconnect
- * routines.  The reason to register as a USB device is to gain part of the
- * minor number space from the USB major.
- *
- * In theory, should the HID code be generalized to more than one physical
- * medium (say, IEEE 1384), this driver will probably need to register its
- * own major number, and in doing so, no longer need to register with USB.
- * At that point the probe routine and hiddev_driver struct below will no
- * longer be useful.
- */
-
-
-/* We never attach in this manner, and rely on HID to connect us.  This
- * is why there is no disconnect routine defined in the usb_driver either.
- */
-static int hiddev_usbd_probe(struct usb_interface *intf,
-			     const struct usb_device_id *hiddev_info)
-{
-	return -ENODEV;
-}
-
-static /* const */ struct usb_driver hiddev_driver = {
-	.name =		"hiddev",
-	.probe =	hiddev_usbd_probe,
-};
-
-int __init hiddev_init(void)
-{
-	return usb_register(&hiddev_driver);
-}
-
-void hiddev_exit(void)
-{
-	usb_deregister(&hiddev_driver);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/hid/usbhid/hid-quirks.c linux-libre-2.6.37-gnu/drivers/hid/usbhid/hid-quirks.c
--- linux-libre-2.6.36-gnu/drivers/hid/usbhid/hid-quirks.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hid/usbhid/hid-quirks.c	2011-01-04 19:50:19.000000000 -0500
@@ -34,7 +34,6 @@
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
-	{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -63,6 +62,7 @@
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
@@ -72,6 +72,10 @@
 	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
+	{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ad7414.c linux-libre-2.6.37-gnu/drivers/hwmon/ad7414.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ad7414.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ad7414.c	2011-01-04 19:50:19.000000000 -0500
@@ -178,11 +178,13 @@
 {
 	struct ad7414_data *data;
 	int conf;
-	int err = 0;
+	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-				     I2C_FUNC_SMBUS_READ_WORD_DATA))
+				     I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+		err = -EOPNOTSUPP;
 		goto exit;
+	}
 
 	data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
 	if (!data) {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/adm1025.c linux-libre-2.6.37-gnu/drivers/hwmon/adm1025.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/adm1025.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/adm1025.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
  * resolution of about 0.5% of the nominal value). Temperature values are
  * reported with a 1 deg resolution and a 3 deg accuracy. Complete
  * datasheet can be obtained from Analog's website at:
- *   http://www.analog.com/Analog_Root/productPage/productHome/0,2121,ADM1025,00.html
+ *   http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 
  *
  * This driver also supports the ADM1025A, which differs from the ADM1025
  * only in that it has "open-drain VID inputs while the ADM1025 has
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/adm1026.c linux-libre-2.6.37-gnu/drivers/hwmon/adm1026.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/adm1026.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/adm1026.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,7 +6,7 @@
 
     Chip details at:
 
-    <http://www.analog.com/UploadedFiles/Data_Sheets/779263102ADM1026_a.pdf>
+    <http://www.onsemi.com/PowerSolutions/product.do?id=ADM1026>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -916,27 +916,27 @@
 	int nr = sensor_attr->index;
 	struct i2c_client *client = to_i2c_client(dev);
 	struct adm1026_data *data = i2c_get_clientdata(client);
-	int val, orig_div, new_div, shift;
+	int val, orig_div, new_div;
 
 	val = simple_strtol(buf, NULL, 10);
 	new_div = DIV_TO_REG(val);
-	if (new_div == 0) {
-		return -EINVAL;
-	}
+
 	mutex_lock(&data->update_lock);
 	orig_div = data->fan_div[nr];
 	data->fan_div[nr] = DIV_FROM_REG(new_div);
 
 	if (nr < 4) { /* 0 <= nr < 4 */
-		shift = 2 * nr;
 		adm1026_write_value(client, ADM1026_REG_FAN_DIV_0_3,
-			((DIV_TO_REG(orig_div) & (~(0x03 << shift))) |
-			(new_div << shift)));
+				    (DIV_TO_REG(data->fan_div[0]) << 0) |
+				    (DIV_TO_REG(data->fan_div[1]) << 2) |
+				    (DIV_TO_REG(data->fan_div[2]) << 4) |
+				    (DIV_TO_REG(data->fan_div[3]) << 6));
 	} else { /* 3 < nr < 8 */
-		shift = 2 * (nr - 4);
 		adm1026_write_value(client, ADM1026_REG_FAN_DIV_4_7,
-			((DIV_TO_REG(orig_div) & (~(0x03 << (2 * shift)))) |
-			(new_div << shift)));
+				    (DIV_TO_REG(data->fan_div[4]) << 0) |
+				    (DIV_TO_REG(data->fan_div[5]) << 2) |
+				    (DIV_TO_REG(data->fan_div[6]) << 4) |
+				    (DIV_TO_REG(data->fan_div[7]) << 6));
 	}
 
 	if (data->fan_div[nr] != orig_div) {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/adt7470.c linux-libre-2.6.37-gnu/drivers/hwmon/adt7470.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/adt7470.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/adt7470.c	2011-01-04 19:50:19.000000000 -0500
@@ -1286,8 +1286,10 @@
 	init_completion(&data->auto_update_stop);
 	data->auto_update = kthread_run(adt7470_update_thread, client,
 					dev_name(data->hwmon_dev));
-	if (IS_ERR(data->auto_update))
+	if (IS_ERR(data->auto_update)) {
+		err = PTR_ERR(data->auto_update);
 		goto exit_unregister;
+	}
 
 	return 0;
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/adt7475.c linux-libre-2.6.37-gnu/drivers/hwmon/adt7475.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/adt7475.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/adt7475.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,7 +146,7 @@
 #define TEMP_OFFSET_REG(idx) (REG_TEMP_OFFSET_BASE + (idx))
 #define TEMP_TRANGE_REG(idx) (REG_TEMP_TRANGE_BASE + (idx))
 
-static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
 
 enum chips { adt7473, adt7475, adt7476, adt7490 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/amc6821.c linux-libre-2.6.37-gnu/drivers/hwmon/amc6821.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/amc6821.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/amc6821.c	2011-01-04 19:50:19.000000000 -0500
@@ -4,7 +4,7 @@
 	Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
 
 	Based on max6650.c:
-	Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
+	Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de>
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-core.c linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-core.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-core.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,250 +0,0 @@
-/*
- * Apple Motion Sensor driver
- *
- * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
- * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/of_platform.h>
-#include <asm/pmac_pfunc.h>
-
-#include "ams.h"
-
-/* There is only one motion sensor per machine */
-struct ams ams_info;
-
-static unsigned int verbose;
-module_param(verbose, bool, 0644);
-MODULE_PARM_DESC(verbose, "Show free falls and shocks in kernel output");
-
-/* Call with ams_info.lock held! */
-void ams_sensors(s8 *x, s8 *y, s8 *z)
-{
-	u32 orient = ams_info.vflag? ams_info.orient1 : ams_info.orient2;
-
-	if (orient & 0x80)
-		/* X and Y swapped */
-		ams_info.get_xyz(y, x, z);
-	else
-		ams_info.get_xyz(x, y, z);
-
-	if (orient & 0x04)
-		*z = ~(*z);
-	if (orient & 0x02)
-		*y = ~(*y);
-	if (orient & 0x01)
-		*x = ~(*x);
-}
-
-static ssize_t ams_show_current(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	s8 x, y, z;
-
-	mutex_lock(&ams_info.lock);
-	ams_sensors(&x, &y, &z);
-	mutex_unlock(&ams_info.lock);
-
-	return snprintf(buf, PAGE_SIZE, "%d %d %d\n", x, y, z);
-}
-
-static DEVICE_ATTR(current, S_IRUGO, ams_show_current, NULL);
-
-static void ams_handle_irq(void *data)
-{
-	enum ams_irq irq = *((enum ams_irq *)data);
-
-	spin_lock(&ams_info.irq_lock);
-
-	ams_info.worker_irqs |= irq;
-	schedule_work(&ams_info.worker);
-
-	spin_unlock(&ams_info.irq_lock);
-}
-
-static enum ams_irq ams_freefall_irq_data = AMS_IRQ_FREEFALL;
-static struct pmf_irq_client ams_freefall_client = {
-	.owner = THIS_MODULE,
-	.handler = ams_handle_irq,
-	.data = &ams_freefall_irq_data,
-};
-
-static enum ams_irq ams_shock_irq_data = AMS_IRQ_SHOCK;
-static struct pmf_irq_client ams_shock_client = {
-	.owner = THIS_MODULE,
-	.handler = ams_handle_irq,
-	.data = &ams_shock_irq_data,
-};
-
-/* Once hard disk parking is implemented in the kernel, this function can
- * trigger it.
- */
-static void ams_worker(struct work_struct *work)
-{
-	unsigned long flags;
-	u8 irqs_to_clear;
-
-	mutex_lock(&ams_info.lock);
-
-	spin_lock_irqsave(&ams_info.irq_lock, flags);
-	irqs_to_clear = ams_info.worker_irqs;
-
-	if (ams_info.worker_irqs & AMS_IRQ_FREEFALL) {
-		if (verbose)
-			printk(KERN_INFO "ams: freefall detected!\n");
-
-		ams_info.worker_irqs &= ~AMS_IRQ_FREEFALL;
-	}
-
-	if (ams_info.worker_irqs & AMS_IRQ_SHOCK) {
-		if (verbose)
-			printk(KERN_INFO "ams: shock detected!\n");
-
-		ams_info.worker_irqs &= ~AMS_IRQ_SHOCK;
-	}
-
-	spin_unlock_irqrestore(&ams_info.irq_lock, flags);
-
-	ams_info.clear_irq(irqs_to_clear);
-
-	mutex_unlock(&ams_info.lock);
-}
-
-/* Call with ams_info.lock held! */
-int ams_sensor_attach(void)
-{
-	int result;
-	const u32 *prop;
-
-	/* Get orientation */
-	prop = of_get_property(ams_info.of_node, "orientation", NULL);
-	if (!prop)
-		return -ENODEV;
-	ams_info.orient1 = *prop;
-	ams_info.orient2 = *(prop + 1);
-
-	/* Register freefall interrupt handler */
-	result = pmf_register_irq_client(ams_info.of_node,
-			"accel-int-1",
-			&ams_freefall_client);
-	if (result < 0)
-		return -ENODEV;
-
-	/* Reset saved irqs */
-	ams_info.worker_irqs = 0;
-
-	/* Register shock interrupt handler */
-	result = pmf_register_irq_client(ams_info.of_node,
-			"accel-int-2",
-			&ams_shock_client);
-	if (result < 0)
-		goto release_freefall;
-
-	/* Create device */
-	ams_info.of_dev = of_platform_device_create(ams_info.of_node, "ams", NULL);
-	if (!ams_info.of_dev) {
-		result = -ENODEV;
-		goto release_shock;
-	}
-
-	/* Create attributes */
-	result = device_create_file(&ams_info.of_dev->dev, &dev_attr_current);
-	if (result)
-		goto release_of;
-
-	ams_info.vflag = !!(ams_info.get_vendor() & 0x10);
-
-	/* Init input device */
-	result = ams_input_init();
-	if (result)
-		goto release_device_file;
-
-	return result;
-release_device_file:
-	device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
-release_of:
-	of_device_unregister(ams_info.of_dev);
-release_shock:
-	pmf_unregister_irq_client(&ams_shock_client);
-release_freefall:
-	pmf_unregister_irq_client(&ams_freefall_client);
-	return result;
-}
-
-int __init ams_init(void)
-{
-	struct device_node *np;
-
-	spin_lock_init(&ams_info.irq_lock);
-	mutex_init(&ams_info.lock);
-	INIT_WORK(&ams_info.worker, ams_worker);
-
-#ifdef CONFIG_SENSORS_AMS_I2C
-	np = of_find_node_by_name(NULL, "accelerometer");
-	if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
-		/* Found I2C motion sensor */
-		return ams_i2c_init(np);
-#endif
-
-#ifdef CONFIG_SENSORS_AMS_PMU
-	np = of_find_node_by_name(NULL, "sms");
-	if (np && of_device_is_compatible(np, "sms"))
-		/* Found PMU motion sensor */
-		return ams_pmu_init(np);
-#endif
-	return -ENODEV;
-}
-
-void ams_sensor_detach(void)
-{
-	/* Remove input device */
-	ams_input_exit();
-
-	/* Remove attributes */
-	device_remove_file(&ams_info.of_dev->dev, &dev_attr_current);
-
-	/* Flush interrupt worker
-	 *
-	 * We do this after ams_info.exit(), because an interrupt might
-	 * have arrived before disabling them.
-	 */
-	flush_scheduled_work();
-
-	/* Remove device */
-	of_device_unregister(ams_info.of_dev);
-
-	/* Remove handler */
-	pmf_unregister_irq_client(&ams_shock_client);
-	pmf_unregister_irq_client(&ams_freefall_client);
-}
-
-static void __exit ams_exit(void)
-{
-	/* Shut down implementation */
-	ams_info.exit();
-}
-
-MODULE_AUTHOR("Stelian Pop, Michael Hanselmann");
-MODULE_DESCRIPTION("Apple Motion Sensor driver");
-MODULE_LICENSE("GPL");
-
-module_init(ams_init);
-module_exit(ams_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams.h linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams.h
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,70 +0,0 @@
-#include <linux/i2c.h>
-#include <linux/input-polldev.h>
-#include <linux/kthread.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/of_device.h>
-
-enum ams_irq {
-	AMS_IRQ_FREEFALL = 0x01,
-	AMS_IRQ_SHOCK = 0x02,
-	AMS_IRQ_GLOBAL = 0x04,
-	AMS_IRQ_ALL =
-		AMS_IRQ_FREEFALL |
-		AMS_IRQ_SHOCK |
-		AMS_IRQ_GLOBAL,
-};
-
-struct ams {
-	/* Locks */
-	spinlock_t irq_lock;
-	struct mutex lock;
-
-	/* General properties */
-	struct device_node *of_node;
-	struct platform_device *of_dev;
-	char has_device;
-	char vflag;
-	u32 orient1;
-	u32 orient2;
-
-	/* Interrupt worker */
-	struct work_struct worker;
-	u8 worker_irqs;
-
-	/* Implementation
-	 *
-	 * Only call these functions with the main lock held.
-	 */
-	void (*exit)(void);
-
-	void (*get_xyz)(s8 *x, s8 *y, s8 *z);
-	u8 (*get_vendor)(void);
-
-	void (*clear_irq)(enum ams_irq reg);
-
-#ifdef CONFIG_SENSORS_AMS_I2C
-	/* I2C properties */
-	struct i2c_client *i2c_client;
-#endif
-
-	/* Joystick emulation */
-	struct input_polled_dev *idev;
-	__u16 bustype;
-
-	/* calibrated null values */
-	int xcalib, ycalib, zcalib;
-};
-
-extern struct ams ams_info;
-
-extern void ams_sensors(s8 *x, s8 *y, s8 *z);
-extern int ams_sensor_attach(void);
-extern void ams_sensor_detach(void);
-
-extern int ams_pmu_init(struct device_node *np);
-extern int ams_i2c_init(struct device_node *np);
-
-extern int ams_input_init(void);
-extern void ams_input_exit(void);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-i2c.c linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-i2c.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-i2c.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,277 +0,0 @@
-/*
- * Apple Motion Sensor driver (I2C variant)
- *
- * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
- * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
- *
- * Clean room implementation based on the reverse engineered Mac OS X driver by
- * Johannes Berg <johannes@sipsolutions.net>, documentation available at
- * http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include "ams.h"
-
-/* AMS registers */
-#define AMS_COMMAND	0x00	/* command register */
-#define AMS_STATUS	0x01	/* status register */
-#define AMS_CTRL1	0x02	/* read control 1 (number of values) */
-#define AMS_CTRL2	0x03	/* read control 2 (offset?) */
-#define AMS_CTRL3	0x04	/* read control 3 (size of each value?) */
-#define AMS_DATA1	0x05	/* read data 1 */
-#define AMS_DATA2	0x06	/* read data 2 */
-#define AMS_DATA3	0x07	/* read data 3 */
-#define AMS_DATA4	0x08	/* read data 4 */
-#define AMS_DATAX	0x20	/* data X */
-#define AMS_DATAY	0x21	/* data Y */
-#define AMS_DATAZ	0x22	/* data Z */
-#define AMS_FREEFALL	0x24	/* freefall int control */
-#define AMS_SHOCK	0x25	/* shock int control */
-#define AMS_SENSLOW	0x26	/* sensitivity low limit */
-#define AMS_SENSHIGH	0x27	/* sensitivity high limit */
-#define AMS_CTRLX	0x28	/* control X */
-#define AMS_CTRLY	0x29	/* control Y */
-#define AMS_CTRLZ	0x2A	/* control Z */
-#define AMS_UNKNOWN1	0x2B	/* unknown 1 */
-#define AMS_UNKNOWN2	0x2C	/* unknown 2 */
-#define AMS_UNKNOWN3	0x2D	/* unknown 3 */
-#define AMS_VENDOR	0x2E	/* vendor */
-
-/* AMS commands - use with the AMS_COMMAND register */
-enum ams_i2c_cmd {
-	AMS_CMD_NOOP = 0,
-	AMS_CMD_VERSION,
-	AMS_CMD_READMEM,
-	AMS_CMD_WRITEMEM,
-	AMS_CMD_ERASEMEM,
-	AMS_CMD_READEE,
-	AMS_CMD_WRITEEE,
-	AMS_CMD_RESET,
-	AMS_CMD_START,
-};
-
-static int ams_i2c_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id);
-static int ams_i2c_remove(struct i2c_client *client);
-
-static const struct i2c_device_id ams_id[] = {
-	{ "ams", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, ams_id);
-
-static struct i2c_driver ams_i2c_driver = {
-	.driver = {
-		.name   = "ams",
-		.owner  = THIS_MODULE,
-	},
-	.probe          = ams_i2c_probe,
-	.remove         = ams_i2c_remove,
-	.id_table       = ams_id,
-};
-
-static s32 ams_i2c_read(u8 reg)
-{
-	return i2c_smbus_read_byte_data(ams_info.i2c_client, reg);
-}
-
-static int ams_i2c_write(u8 reg, u8 value)
-{
-	return i2c_smbus_write_byte_data(ams_info.i2c_client, reg, value);
-}
-
-static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
-{
-	s32 result;
-	int count = 3;
-
-	ams_i2c_write(AMS_COMMAND, cmd);
-	msleep(5);
-
-	while (count--) {
-		result = ams_i2c_read(AMS_COMMAND);
-		if (result == 0 || result & 0x80)
-			return 0;
-
-		schedule_timeout_uninterruptible(HZ / 20);
-	}
-
-	return -1;
-}
-
-static void ams_i2c_set_irq(enum ams_irq reg, char enable)
-{
-	if (reg & AMS_IRQ_FREEFALL) {
-		u8 val = ams_i2c_read(AMS_CTRLX);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_i2c_write(AMS_CTRLX, val);
-	}
-
-	if (reg & AMS_IRQ_SHOCK) {
-		u8 val = ams_i2c_read(AMS_CTRLY);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_i2c_write(AMS_CTRLY, val);
-	}
-
-	if (reg & AMS_IRQ_GLOBAL) {
-		u8 val = ams_i2c_read(AMS_CTRLZ);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_i2c_write(AMS_CTRLZ, val);
-	}
-}
-
-static void ams_i2c_clear_irq(enum ams_irq reg)
-{
-	if (reg & AMS_IRQ_FREEFALL)
-		ams_i2c_write(AMS_FREEFALL, 0);
-
-	if (reg & AMS_IRQ_SHOCK)
-		ams_i2c_write(AMS_SHOCK, 0);
-}
-
-static u8 ams_i2c_get_vendor(void)
-{
-	return ams_i2c_read(AMS_VENDOR);
-}
-
-static void ams_i2c_get_xyz(s8 *x, s8 *y, s8 *z)
-{
-	*x = ams_i2c_read(AMS_DATAX);
-	*y = ams_i2c_read(AMS_DATAY);
-	*z = ams_i2c_read(AMS_DATAZ);
-}
-
-static int ams_i2c_probe(struct i2c_client *client,
-			 const struct i2c_device_id *id)
-{
-	int vmaj, vmin;
-	int result;
-
-	/* There can be only one */
-	if (unlikely(ams_info.has_device))
-		return -ENODEV;
-
-	ams_info.i2c_client = client;
-
-	if (ams_i2c_cmd(AMS_CMD_RESET)) {
-		printk(KERN_INFO "ams: Failed to reset the device\n");
-		return -ENODEV;
-	}
-
-	if (ams_i2c_cmd(AMS_CMD_START)) {
-		printk(KERN_INFO "ams: Failed to start the device\n");
-		return -ENODEV;
-	}
-
-	/* get version/vendor information */
-	ams_i2c_write(AMS_CTRL1, 0x02);
-	ams_i2c_write(AMS_CTRL2, 0x85);
-	ams_i2c_write(AMS_CTRL3, 0x01);
-
-	ams_i2c_cmd(AMS_CMD_READMEM);
-
-	vmaj = ams_i2c_read(AMS_DATA1);
-	vmin = ams_i2c_read(AMS_DATA2);
-	if (vmaj != 1 || vmin != 52) {
-		printk(KERN_INFO "ams: Incorrect device version (%d.%d)\n",
-			vmaj, vmin);
-		return -ENODEV;
-	}
-
-	ams_i2c_cmd(AMS_CMD_VERSION);
-
-	vmaj = ams_i2c_read(AMS_DATA1);
-	vmin = ams_i2c_read(AMS_DATA2);
-	if (vmaj != 0 || vmin != 1) {
-		printk(KERN_INFO "ams: Incorrect firmware version (%d.%d)\n",
-			vmaj, vmin);
-		return -ENODEV;
-	}
-
-	/* Disable interrupts */
-	ams_i2c_set_irq(AMS_IRQ_ALL, 0);
-
-	result = ams_sensor_attach();
-	if (result < 0)
-		return result;
-
-	/* Set default values */
-	ams_i2c_write(AMS_SENSLOW, 0x15);
-	ams_i2c_write(AMS_SENSHIGH, 0x60);
-	ams_i2c_write(AMS_CTRLX, 0x08);
-	ams_i2c_write(AMS_CTRLY, 0x0F);
-	ams_i2c_write(AMS_CTRLZ, 0x4F);
-	ams_i2c_write(AMS_UNKNOWN1, 0x14);
-
-	/* Clear interrupts */
-	ams_i2c_clear_irq(AMS_IRQ_ALL);
-
-	ams_info.has_device = 1;
-
-	/* Enable interrupts */
-	ams_i2c_set_irq(AMS_IRQ_ALL, 1);
-
-	printk(KERN_INFO "ams: Found I2C based motion sensor\n");
-
-	return 0;
-}
-
-static int ams_i2c_remove(struct i2c_client *client)
-{
-	if (ams_info.has_device) {
-		ams_sensor_detach();
-
-		/* Disable interrupts */
-		ams_i2c_set_irq(AMS_IRQ_ALL, 0);
-
-		/* Clear interrupts */
-		ams_i2c_clear_irq(AMS_IRQ_ALL);
-
-		printk(KERN_INFO "ams: Unloading\n");
-
-		ams_info.has_device = 0;
-	}
-
-	return 0;
-}
-
-static void ams_i2c_exit(void)
-{
-	i2c_del_driver(&ams_i2c_driver);
-}
-
-int __init ams_i2c_init(struct device_node *np)
-{
-	int result;
-
-	/* Set implementation stuff */
-	ams_info.of_node = np;
-	ams_info.exit = ams_i2c_exit;
-	ams_info.get_vendor = ams_i2c_get_vendor;
-	ams_info.get_xyz = ams_i2c_get_xyz;
-	ams_info.clear_irq = ams_i2c_clear_irq;
-	ams_info.bustype = BUS_I2C;
-
-	result = i2c_add_driver(&ams_i2c_driver);
-
-	return result;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-input.c linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-input.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-input.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-input.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,157 +0,0 @@
-/*
- * Apple Motion Sensor driver (joystick emulation)
- *
- * Copyright (C) 2005 Stelian Pop (stelian@popies.net)
- * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include "ams.h"
-
-static unsigned int joystick;
-module_param(joystick, bool, S_IRUGO);
-MODULE_PARM_DESC(joystick, "Enable the input class device on module load");
-
-static unsigned int invert;
-module_param(invert, bool, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
-
-static DEFINE_MUTEX(ams_input_mutex);
-
-static void ams_idev_poll(struct input_polled_dev *dev)
-{
-	struct input_dev *idev = dev->input;
-	s8 x, y, z;
-
-	mutex_lock(&ams_info.lock);
-
-	ams_sensors(&x, &y, &z);
-
-	x -= ams_info.xcalib;
-	y -= ams_info.ycalib;
-	z -= ams_info.zcalib;
-
-	input_report_abs(idev, ABS_X, invert ? -x : x);
-	input_report_abs(idev, ABS_Y, invert ? -y : y);
-	input_report_abs(idev, ABS_Z, z);
-
-	input_sync(idev);
-
-	mutex_unlock(&ams_info.lock);
-}
-
-/* Call with ams_info.lock held! */
-static int ams_input_enable(void)
-{
-	struct input_dev *input;
-	s8 x, y, z;
-	int error;
-
-	ams_sensors(&x, &y, &z);
-	ams_info.xcalib = x;
-	ams_info.ycalib = y;
-	ams_info.zcalib = z;
-
-	ams_info.idev = input_allocate_polled_device();
-	if (!ams_info.idev)
-		return -ENOMEM;
-
-	ams_info.idev->poll = ams_idev_poll;
-	ams_info.idev->poll_interval = 25;
-
-	input = ams_info.idev->input;
-	input->name = "Apple Motion Sensor";
-	input->id.bustype = ams_info.bustype;
-	input->id.vendor = 0;
-	input->dev.parent = &ams_info.of_dev->dev;
-
-	input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
-	input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
-	input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
-
-	set_bit(EV_ABS, input->evbit);
-	set_bit(EV_KEY, input->evbit);
-	set_bit(BTN_TOUCH, input->keybit);
-
-	error = input_register_polled_device(ams_info.idev);
-	if (error) {
-		input_free_polled_device(ams_info.idev);
-		ams_info.idev = NULL;
-		return error;
-	}
-
-	joystick = 1;
-
-	return 0;
-}
-
-static void ams_input_disable(void)
-{
-	if (ams_info.idev) {
-		input_unregister_polled_device(ams_info.idev);
-		input_free_polled_device(ams_info.idev);
-		ams_info.idev = NULL;
-	}
-
-	joystick = 0;
-}
-
-static ssize_t ams_input_show_joystick(struct device *dev,
-	struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%d\n", joystick);
-}
-
-static ssize_t ams_input_store_joystick(struct device *dev,
-	struct device_attribute *attr, const char *buf, size_t count)
-{
-	unsigned long enable;
-	int error = 0;
-
-	if (strict_strtoul(buf, 0, &enable) || enable > 1)
-		return -EINVAL;
-
-	mutex_lock(&ams_input_mutex);
-
-	if (enable != joystick) {
-		if (enable)
-			error = ams_input_enable();
-		else
-			ams_input_disable();
-	}
-
-	mutex_unlock(&ams_input_mutex);
-
-	return error ? error : count;
-}
-
-static DEVICE_ATTR(joystick, S_IRUGO | S_IWUSR,
-	ams_input_show_joystick, ams_input_store_joystick);
-
-int ams_input_init(void)
-{
-	if (joystick)
-		ams_input_enable();
-
-	return device_create_file(&ams_info.of_dev->dev, &dev_attr_joystick);
-}
-
-void ams_input_exit(void)
-{
-	device_remove_file(&ams_info.of_dev->dev, &dev_attr_joystick);
-
-	mutex_lock(&ams_input_mutex);
-	ams_input_disable();
-	mutex_unlock(&ams_input_mutex);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-pmu.c linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-pmu.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/ams-pmu.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/ams-pmu.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,201 +0,0 @@
-/*
- * Apple Motion Sensor driver (PMU variant)
- *
- * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#include "ams.h"
-
-/* Attitude */
-#define AMS_X			0x00
-#define AMS_Y			0x01
-#define AMS_Z			0x02
-
-/* Not exactly known, maybe chip vendor */
-#define AMS_VENDOR		0x03
-
-/* Freefall registers */
-#define AMS_FF_CLEAR		0x04
-#define AMS_FF_ENABLE		0x05
-#define AMS_FF_LOW_LIMIT	0x06
-#define AMS_FF_DEBOUNCE		0x07
-
-/* Shock registers */
-#define AMS_SHOCK_CLEAR		0x08
-#define AMS_SHOCK_ENABLE	0x09
-#define AMS_SHOCK_HIGH_LIMIT	0x0a
-#define AMS_SHOCK_DEBOUNCE	0x0b
-
-/* Global interrupt and power control register */
-#define AMS_CONTROL		0x0c
-
-static u8 ams_pmu_cmd;
-
-static void ams_pmu_req_complete(struct adb_request *req)
-{
-	complete((struct completion *)req->arg);
-}
-
-/* Only call this function from task context */
-static void ams_pmu_set_register(u8 reg, u8 value)
-{
-	static struct adb_request req;
-	DECLARE_COMPLETION(req_complete);
-
-	req.arg = &req_complete;
-	if (pmu_request(&req, ams_pmu_req_complete, 4, ams_pmu_cmd, 0x00, reg, value))
-		return;
-
-	wait_for_completion(&req_complete);
-}
-
-/* Only call this function from task context */
-static u8 ams_pmu_get_register(u8 reg)
-{
-	static struct adb_request req;
-	DECLARE_COMPLETION(req_complete);
-
-	req.arg = &req_complete;
-	if (pmu_request(&req, ams_pmu_req_complete, 3, ams_pmu_cmd, 0x01, reg))
-		return 0;
-
-	wait_for_completion(&req_complete);
-
-	if (req.reply_len > 0)
-		return req.reply[0];
-	else
-		return 0;
-}
-
-/* Enables or disables the specified interrupts */
-static void ams_pmu_set_irq(enum ams_irq reg, char enable)
-{
-	if (reg & AMS_IRQ_FREEFALL) {
-		u8 val = ams_pmu_get_register(AMS_FF_ENABLE);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_pmu_set_register(AMS_FF_ENABLE, val);
-	}
-
-	if (reg & AMS_IRQ_SHOCK) {
-		u8 val = ams_pmu_get_register(AMS_SHOCK_ENABLE);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_pmu_set_register(AMS_SHOCK_ENABLE, val);
-	}
-
-	if (reg & AMS_IRQ_GLOBAL) {
-		u8 val = ams_pmu_get_register(AMS_CONTROL);
-		if (enable)
-			val |= 0x80;
-		else
-			val &= ~0x80;
-		ams_pmu_set_register(AMS_CONTROL, val);
-	}
-}
-
-static void ams_pmu_clear_irq(enum ams_irq reg)
-{
-	if (reg & AMS_IRQ_FREEFALL)
-		ams_pmu_set_register(AMS_FF_CLEAR, 0x00);
-
-	if (reg & AMS_IRQ_SHOCK)
-		ams_pmu_set_register(AMS_SHOCK_CLEAR, 0x00);
-}
-
-static u8 ams_pmu_get_vendor(void)
-{
-	return ams_pmu_get_register(AMS_VENDOR);
-}
-
-static void ams_pmu_get_xyz(s8 *x, s8 *y, s8 *z)
-{
-	*x = ams_pmu_get_register(AMS_X);
-	*y = ams_pmu_get_register(AMS_Y);
-	*z = ams_pmu_get_register(AMS_Z);
-}
-
-static void ams_pmu_exit(void)
-{
-	ams_sensor_detach();
-
-	/* Disable interrupts */
-	ams_pmu_set_irq(AMS_IRQ_ALL, 0);
-
-	/* Clear interrupts */
-	ams_pmu_clear_irq(AMS_IRQ_ALL);
-
-	ams_info.has_device = 0;
-
-	printk(KERN_INFO "ams: Unloading\n");
-}
-
-int __init ams_pmu_init(struct device_node *np)
-{
-	const u32 *prop;
-	int result;
-
-	/* Set implementation stuff */
-	ams_info.of_node = np;
-	ams_info.exit = ams_pmu_exit;
-	ams_info.get_vendor = ams_pmu_get_vendor;
-	ams_info.get_xyz = ams_pmu_get_xyz;
-	ams_info.clear_irq = ams_pmu_clear_irq;
-	ams_info.bustype = BUS_HOST;
-
-	/* Get PMU command, should be 0x4e, but we can never know */
-	prop = of_get_property(ams_info.of_node, "reg", NULL);
-	if (!prop)
-		return -ENODEV;
-
-	ams_pmu_cmd = ((*prop) >> 8) & 0xff;
-
-	/* Disable interrupts */
-	ams_pmu_set_irq(AMS_IRQ_ALL, 0);
-
-	/* Clear interrupts */
-	ams_pmu_clear_irq(AMS_IRQ_ALL);
-
-	result = ams_sensor_attach();
-	if (result < 0)
-		return result;
-
-	/* Set default values */
-	ams_pmu_set_register(AMS_FF_LOW_LIMIT, 0x15);
-	ams_pmu_set_register(AMS_FF_ENABLE, 0x08);
-	ams_pmu_set_register(AMS_FF_DEBOUNCE, 0x14);
-
-	ams_pmu_set_register(AMS_SHOCK_HIGH_LIMIT, 0x60);
-	ams_pmu_set_register(AMS_SHOCK_ENABLE, 0x0f);
-	ams_pmu_set_register(AMS_SHOCK_DEBOUNCE, 0x14);
-
-	ams_pmu_set_register(AMS_CONTROL, 0x4f);
-
-	/* Clear interrupts */
-	ams_pmu_clear_irq(AMS_IRQ_ALL);
-
-	ams_info.has_device = 1;
-
-	/* Enable interrupts */
-	ams_pmu_set_irq(AMS_IRQ_ALL, 1);
-
-	printk(KERN_INFO "ams: Found PMU based motion sensor\n");
-
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ams/Makefile linux-libre-2.6.37-gnu/drivers/hwmon/ams/Makefile
--- linux-libre-2.6.36-gnu/drivers/hwmon/ams/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ams/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,8 +0,0 @@
-#
-# Makefile for Apple Motion Sensor driver
-#
-
-ams-y					:= ams-core.o ams-input.o
-ams-$(CONFIG_SENSORS_AMS_PMU)		+= ams-pmu.o
-ams-$(CONFIG_SENSORS_AMS_I2C)		+= ams-i2c.o
-obj-$(CONFIG_SENSORS_AMS)		+= ams.o
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/asc7621.c linux-libre-2.6.37-gnu/drivers/hwmon/asc7621.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/asc7621.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/asc7621.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,7 +28,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	0x2c, 0x2d, 0x2e, I2C_CLIENT_END
 };
 
@@ -52,7 +52,7 @@
 	u8 company_id;
 	u8 verstep_reg;
 	u8 verstep_id;
-	unsigned short *addresses;
+	const unsigned short *addresses;
 };
 
 static struct asc7621_chip asc7621_chips[] = {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/asus_atk0110.c linux-libre-2.6.37-gnu/drivers/hwmon/asus_atk0110.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/asus_atk0110.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/asus_atk0110.c	2011-01-04 19:50:19.000000000 -0500
@@ -762,6 +762,7 @@
 	.read		= atk_debugfs_ggrp_read,
 	.open		= atk_debugfs_ggrp_open,
 	.release	= atk_debugfs_ggrp_release,
+	.llseek		= no_llseek,
 };
 
 static void atk_debugfs_init(struct atk_data *data)
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/coretemp.c linux-libre-2.6.37-gnu/drivers/hwmon/coretemp.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/coretemp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/coretemp.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -280,11 +279,9 @@
 	case 0x1a:
 		dev_warn(dev, "TjMax is assumed as 100 C!\n");
 		return 100000;
-		break;
 	case 0x17:
 	case 0x1c:		/* Atom CPUs */
 		return adjust_tjmax(c, id, dev);
-		break;
 	default:
 		dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
 			" using default TjMax of 100C.\n", c->x86_model);
@@ -292,6 +289,15 @@
 	}
 }
 
+static void __devinit get_ucode_rev_on_cpu(void *edx)
+{
+	u32 eax;
+
+	wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+	sync_core();
+	rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
+}
+
 static int __devinit coretemp_probe(struct platform_device *pdev)
 {
 	struct coretemp_data *data;
@@ -327,8 +333,15 @@
 
 	if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
 		/* check for microcode update */
-		rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
-		if (edx < 0x39) {
+		err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
+					       &edx, 1);
+		if (err) {
+			dev_err(&pdev->dev,
+				"Cannot determine microcode revision of "
+				"CPU#%u (%d)!\n", data->id, err);
+			err = -ENODEV;
+			goto exit_free;
+		} else if (edx < 0x39) {
 			err = -ENODEV;
 			dev_err(&pdev->dev,
 				"Errata AE18 not fixed, update BIOS or "
@@ -490,7 +503,7 @@
 	return err;
 }
 
-static void coretemp_device_remove(unsigned int cpu)
+static void __cpuinit coretemp_device_remove(unsigned int cpu)
 {
 	struct pdev_entry *p;
 	unsigned int i;
@@ -569,9 +582,8 @@
 static void __exit coretemp_exit(void)
 {
 	struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
 	unregister_hotcpu_notifier(&coretemp_cpu_notifier);
-#endif
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
 		platform_device_unregister(p->pdev);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/f75375s.c linux-libre-2.6.37-gnu/drivers/hwmon/f75375s.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/f75375s.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/f75375s.c	2011-01-04 19:50:19.000000000 -0500
@@ -6,10 +6,10 @@
  * Datasheets available at:
  *
  * f75375:
- * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
+ * http://www.fintek.com.tw/files/productfiles/F75375_V026P.pdf 
  *
  * f75373:
- * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
+ * http://www.fintek.com.tw/files/productfiles/F75373_V025P.pdf
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/fschmd.c linux-libre-2.6.37-gnu/drivers/hwmon/fschmd.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/fschmd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/fschmd.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,7 +38,6 @@
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
-#include <linux/smp_lock.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
@@ -50,6 +49,7 @@
 #include <linux/kref.h>
 
 /* Addresses to scan */
+static DEFINE_MUTEX(watchdog_mutex);
 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
 
 /* Insmod parameters */
@@ -858,7 +858,7 @@
 	int i, ret = 0;
 	struct fschmd_data *data = filp->private_data;
 
-	lock_kernel();
+	mutex_lock(&watchdog_mutex);
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 		ident.firmware_version = data->revision;
@@ -915,7 +915,7 @@
 	default:
 		ret = -ENOTTY;
 	}
-	unlock_kernel();
+	mutex_unlock(&watchdog_mutex);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/g760a.c linux-libre-2.6.37-gnu/drivers/hwmon/g760a.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/g760a.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/g760a.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
     Copyright (C) 2007  Herbert Valerio Riedel <hvr@gnu.org>
 
     Complete datasheet is available at GMT's website:
-      http://www.gmt.com.tw/datasheet/g760a.pdf
+      http://www.gmt.com.tw/product/datasheet/EDS-760A.pdf 
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/gpio-fan.c linux-libre-2.6.37-gnu/drivers/hwmon/gpio-fan.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/gpio-fan.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hwmon/gpio-fan.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,558 @@
+/*
+ * gpio-fan.c - Hwmon driver for fans connected to GPIO lines.
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/gpio.h>
+#include <linux/gpio-fan.h>
+
+struct gpio_fan_data {
+	struct platform_device	*pdev;
+	struct device		*hwmon_dev;
+	struct mutex		lock; /* lock GPIOs operations. */
+	int			num_ctrl;
+	unsigned		*ctrl;
+	int			num_speed;
+	struct gpio_fan_speed	*speed;
+	int			speed_index;
+#ifdef CONFIG_PM
+	int			resume_speed;
+#endif
+	bool			pwm_enable;
+	struct gpio_fan_alarm	*alarm;
+	struct work_struct	alarm_work;
+};
+
+/*
+ * Alarm GPIO.
+ */
+
+static void fan_alarm_notify(struct work_struct *ws)
+{
+	struct gpio_fan_data *fan_data =
+		container_of(ws, struct gpio_fan_data, alarm_work);
+
+	sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
+	kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
+}
+
+static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
+{
+	struct gpio_fan_data *fan_data = dev_id;
+
+	schedule_work(&fan_data->alarm_work);
+
+	return IRQ_NONE;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	struct gpio_fan_alarm *alarm = fan_data->alarm;
+	int value = gpio_get_value(alarm->gpio);
+
+	if (alarm->active_low)
+		value = !value;
+
+	return sprintf(buf, "%d\n", value);
+}
+
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL);
+
+static int fan_alarm_init(struct gpio_fan_data *fan_data,
+			  struct gpio_fan_alarm *alarm)
+{
+	int err;
+	int alarm_irq;
+	struct platform_device *pdev = fan_data->pdev;
+
+	fan_data->alarm = alarm;
+
+	err = gpio_request(alarm->gpio, "GPIO fan alarm");
+	if (err)
+		return err;
+
+	err = gpio_direction_input(alarm->gpio);
+	if (err)
+		goto err_free_gpio;
+
+	err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
+	if (err)
+		goto err_free_gpio;
+
+	/*
+	 * If the alarm GPIO don't support interrupts, just leave
+	 * without initializing the fail notification support.
+	 */
+	alarm_irq = gpio_to_irq(alarm->gpio);
+	if (alarm_irq < 0)
+		return 0;
+
+	INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
+	set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
+	err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED,
+			  "GPIO fan alarm", fan_data);
+	if (err)
+		goto err_free_sysfs;
+
+	return 0;
+
+err_free_sysfs:
+	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+err_free_gpio:
+	gpio_free(alarm->gpio);
+
+	return err;
+}
+
+static void fan_alarm_free(struct gpio_fan_data *fan_data)
+{
+	struct platform_device *pdev = fan_data->pdev;
+	int alarm_irq = gpio_to_irq(fan_data->alarm->gpio);
+
+	if (alarm_irq >= 0)
+		free_irq(alarm_irq, fan_data);
+	device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
+	gpio_free(fan_data->alarm->gpio);
+}
+
+/*
+ * Control GPIOs.
+ */
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
+{
+	int i;
+
+	for (i = 0; i < fan_data->num_ctrl; i++)
+		gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+}
+
+static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
+{
+	int i;
+	int ctrl_val = 0;
+
+	for (i = 0; i < fan_data->num_ctrl; i++) {
+		int value;
+
+		value = gpio_get_value(fan_data->ctrl[i]);
+		ctrl_val |= (value << i);
+	}
+	return ctrl_val;
+}
+
+/* Must be called with fan_data->lock held, except during initialization. */
+static void set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
+{
+	if (fan_data->speed_index == speed_index)
+		return;
+
+	__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
+	fan_data->speed_index = speed_index;
+}
+
+static int get_fan_speed_index(struct gpio_fan_data *fan_data)
+{
+	int ctrl_val = __get_fan_ctrl(fan_data);
+	int i;
+
+	for (i = 0; i < fan_data->num_speed; i++)
+		if (fan_data->speed[i].ctrl_val == ctrl_val)
+			return i;
+
+	dev_warn(&fan_data->pdev->dev,
+		 "missing speed array entry for GPIO value 0x%x\n", ctrl_val);
+
+	return -EINVAL;
+}
+
+static int rpm_to_speed_index(struct gpio_fan_data *fan_data, int rpm)
+{
+	struct gpio_fan_speed *speed = fan_data->speed;
+	int i;
+
+	for (i = 0; i < fan_data->num_speed; i++)
+		if (speed[i].rpm >= rpm)
+			return i;
+
+	return fan_data->num_speed - 1;
+}
+
+static ssize_t show_pwm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1);
+
+	return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long pwm;
+	int speed_index;
+	int ret = count;
+
+	if (strict_strtoul(buf, 10, &pwm) || pwm > 255)
+		return -EINVAL;
+
+	mutex_lock(&fan_data->lock);
+
+	if (!fan_data->pwm_enable) {
+		ret = -EPERM;
+		goto exit_unlock;
+	}
+
+	speed_index = DIV_ROUND_UP(pwm * (fan_data->num_speed - 1), 255);
+	set_fan_speed(fan_data, speed_index);
+
+exit_unlock:
+	mutex_unlock(&fan_data->lock);
+
+	return ret;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->pwm_enable);
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) || val > 1)
+		return -EINVAL;
+
+	if (fan_data->pwm_enable == val)
+		return count;
+
+	mutex_lock(&fan_data->lock);
+
+	fan_data->pwm_enable = val;
+
+	/* Disable manual control mode: set fan at full speed. */
+	if (val == 0)
+		set_fan_speed(fan_data, fan_data->num_speed - 1);
+
+	mutex_unlock(&fan_data->lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_mode(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0\n");
+}
+
+static ssize_t show_rpm_min(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->speed[0].rpm);
+}
+
+static ssize_t show_rpm_max(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n",
+		       fan_data->speed[fan_data->num_speed - 1].rpm);
+}
+
+static ssize_t show_rpm(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", fan_data->speed[fan_data->speed_index].rpm);
+}
+
+static ssize_t set_rpm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
+	unsigned long rpm;
+	int ret = count;
+
+	if (strict_strtoul(buf, 10, &rpm))
+		return -EINVAL;
+
+	mutex_lock(&fan_data->lock);
+
+	if (!fan_data->pwm_enable) {
+		ret = -EPERM;
+		goto exit_unlock;
+	}
+
+	set_fan_speed(fan_data, rpm_to_speed_index(fan_data, rpm));
+
+exit_unlock:
+	mutex_unlock(&fan_data->lock);
+
+	return ret;
+}
+
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+		   show_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL);
+static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL);
+static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
+static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
+static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
+
+static struct attribute *gpio_fan_ctrl_attributes[] = {
+	&dev_attr_pwm1.attr,
+	&dev_attr_pwm1_enable.attr,
+	&dev_attr_pwm1_mode.attr,
+	&dev_attr_fan1_input.attr,
+	&dev_attr_fan1_target.attr,
+	&dev_attr_fan1_min.attr,
+	&dev_attr_fan1_max.attr,
+	NULL
+};
+
+static const struct attribute_group gpio_fan_ctrl_group = {
+	.attrs = gpio_fan_ctrl_attributes,
+};
+
+static int fan_ctrl_init(struct gpio_fan_data *fan_data,
+			 struct gpio_fan_platform_data *pdata)
+{
+	struct platform_device *pdev = fan_data->pdev;
+	int num_ctrl = pdata->num_ctrl;
+	unsigned *ctrl = pdata->ctrl;
+	int i, err;
+
+	for (i = 0; i < num_ctrl; i++) {
+		err = gpio_request(ctrl[i], "GPIO fan control");
+		if (err)
+			goto err_free_gpio;
+
+		err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
+		if (err) {
+			gpio_free(ctrl[i]);
+			goto err_free_gpio;
+		}
+	}
+
+	fan_data->num_ctrl = num_ctrl;
+	fan_data->ctrl = ctrl;
+	fan_data->num_speed = pdata->num_speed;
+	fan_data->speed = pdata->speed;
+	fan_data->pwm_enable = true; /* Enable manual fan speed control. */
+	fan_data->speed_index = get_fan_speed_index(fan_data);
+	if (fan_data->speed_index < 0) {
+		err = -ENODEV;
+		goto err_free_gpio;
+	}
+
+	err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+	if (err)
+		goto err_free_gpio;
+
+	return 0;
+
+err_free_gpio:
+	for (i = i - 1; i >= 0; i--)
+		gpio_free(ctrl[i]);
+
+	return err;
+}
+
+static void fan_ctrl_free(struct gpio_fan_data *fan_data)
+{
+	struct platform_device *pdev = fan_data->pdev;
+	int i;
+
+	sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
+	for (i = 0; i < fan_data->num_ctrl; i++)
+		gpio_free(fan_data->ctrl[i]);
+}
+
+/*
+ * Platform driver.
+ */
+
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "gpio-fan\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __devinit gpio_fan_probe(struct platform_device *pdev)
+{
+	int err;
+	struct gpio_fan_data *fan_data;
+	struct gpio_fan_platform_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -EINVAL;
+
+	fan_data = kzalloc(sizeof(struct gpio_fan_data), GFP_KERNEL);
+	if (!fan_data)
+		return -ENOMEM;
+
+	fan_data->pdev = pdev;
+	platform_set_drvdata(pdev, fan_data);
+	mutex_init(&fan_data->lock);
+
+	/* Configure alarm GPIO if available. */
+	if (pdata->alarm) {
+		err = fan_alarm_init(fan_data, pdata->alarm);
+		if (err)
+			goto err_free_data;
+	}
+
+	/* Configure control GPIOs if available. */
+	if (pdata->ctrl && pdata->num_ctrl > 0) {
+		if (!pdata->speed || pdata->num_speed <= 1) {
+			err = -EINVAL;
+			goto err_free_alarm;
+		}
+		err = fan_ctrl_init(fan_data, pdata);
+		if (err)
+			goto err_free_alarm;
+	}
+
+	err = device_create_file(&pdev->dev, &dev_attr_name);
+	if (err)
+		goto err_free_ctrl;
+
+	/* Make this driver part of hwmon class. */
+	fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(fan_data->hwmon_dev)) {
+		err = PTR_ERR(fan_data->hwmon_dev);
+		goto err_remove_name;
+	}
+
+	dev_info(&pdev->dev, "GPIO fan initialized\n");
+
+	return 0;
+
+err_remove_name:
+	device_remove_file(&pdev->dev, &dev_attr_name);
+err_free_ctrl:
+	if (fan_data->ctrl)
+		fan_ctrl_free(fan_data);
+err_free_alarm:
+	if (fan_data->alarm)
+		fan_alarm_free(fan_data);
+err_free_data:
+	platform_set_drvdata(pdev, NULL);
+	kfree(fan_data);
+
+	return err;
+}
+
+static int __devexit gpio_fan_remove(struct platform_device *pdev)
+{
+	struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+	hwmon_device_unregister(fan_data->hwmon_dev);
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	if (fan_data->alarm)
+		fan_alarm_free(fan_data);
+	if (fan_data->ctrl)
+		fan_ctrl_free(fan_data);
+	kfree(fan_data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_fan_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+	if (fan_data->ctrl) {
+		fan_data->resume_speed = fan_data->speed_index;
+		set_fan_speed(fan_data, 0);
+	}
+
+	return 0;
+}
+
+static int gpio_fan_resume(struct platform_device *pdev)
+{
+	struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
+
+	if (fan_data->ctrl)
+		set_fan_speed(fan_data, fan_data->resume_speed);
+
+	return 0;
+}
+#else
+#define gpio_fan_suspend NULL
+#define gpio_fan_resume NULL
+#endif
+
+static struct platform_driver gpio_fan_driver = {
+	.probe		= gpio_fan_probe,
+	.remove		= __devexit_p(gpio_fan_remove),
+	.suspend	= gpio_fan_suspend,
+	.resume		= gpio_fan_resume,
+	.driver	= {
+		.name	= "gpio-fan",
+	},
+};
+
+static int __init gpio_fan_init(void)
+{
+	return platform_driver_register(&gpio_fan_driver);
+}
+
+static void __exit gpio_fan_exit(void)
+{
+	platform_driver_unregister(&gpio_fan_driver);
+}
+
+module_init(gpio_fan_init);
+module_exit(gpio_fan_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("GPIO FAN driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-fan");
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/hdaps.c linux-libre-2.6.37-gnu/drivers/hwmon/hdaps.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/hdaps.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/hdaps.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,637 +0,0 @@
-/*
- * drivers/hwmon/hdaps.c - driver for IBM's Hard Drive Active Protection System
- *
- * Copyright (C) 2005 Robert Love <rml@novell.com>
- * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
- *
- * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
- * starting with the R40, T41, and X40.  It provides a basic two-axis
- * accelerometer and other data, such as the device's temperature.
- *
- * This driver is based on the document by Mark A. Smith available at
- * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial
- * and error.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License v2 as published by the
- * Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
- */
-
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/input-polldev.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/io.h>
-
-#define HDAPS_LOW_PORT		0x1600	/* first port used by hdaps */
-#define HDAPS_NR_PORTS		0x30	/* number of ports: 0x1600 - 0x162f */
-
-#define HDAPS_PORT_STATE	0x1611	/* device state */
-#define HDAPS_PORT_YPOS		0x1612	/* y-axis position */
-#define	HDAPS_PORT_XPOS		0x1614	/* x-axis position */
-#define HDAPS_PORT_TEMP1	0x1616	/* device temperature, in Celsius */
-#define HDAPS_PORT_YVAR		0x1617	/* y-axis variance (what is this?) */
-#define HDAPS_PORT_XVAR		0x1619	/* x-axis variance (what is this?) */
-#define HDAPS_PORT_TEMP2	0x161b	/* device temperature (again?) */
-#define HDAPS_PORT_UNKNOWN	0x161c	/* what is this? */
-#define HDAPS_PORT_KMACT	0x161d	/* keyboard or mouse activity */
-
-#define STATE_FRESH		0x50	/* accelerometer data is fresh */
-
-#define KEYBD_MASK		0x20	/* set if keyboard activity */
-#define MOUSE_MASK		0x40	/* set if mouse activity */
-#define KEYBD_ISSET(n)		(!! (n & KEYBD_MASK))	/* keyboard used? */
-#define MOUSE_ISSET(n)		(!! (n & MOUSE_MASK))	/* mouse used? */
-
-#define INIT_TIMEOUT_MSECS	4000	/* wait up to 4s for device init ... */
-#define INIT_WAIT_MSECS		200	/* ... in 200ms increments */
-
-#define HDAPS_POLL_INTERVAL	50	/* poll for input every 1/20s (50 ms)*/
-#define HDAPS_INPUT_FUZZ	4	/* input event threshold */
-#define HDAPS_INPUT_FLAT	4
-
-#define HDAPS_X_AXIS		(1 << 0)
-#define HDAPS_Y_AXIS		(1 << 1)
-#define HDAPS_BOTH_AXES		(HDAPS_X_AXIS | HDAPS_Y_AXIS)
-
-static struct platform_device *pdev;
-static struct input_polled_dev *hdaps_idev;
-static unsigned int hdaps_invert;
-static u8 km_activity;
-static int rest_x;
-static int rest_y;
-
-static DEFINE_MUTEX(hdaps_mtx);
-
-/*
- * __get_latch - Get the value from a given port.  Callers must hold hdaps_mtx.
- */
-static inline u8 __get_latch(u16 port)
-{
-	return inb(port) & 0xff;
-}
-
-/*
- * __check_latch - Check a port latch for a given value.  Returns zero if the
- * port contains the given value.  Callers must hold hdaps_mtx.
- */
-static inline int __check_latch(u16 port, u8 val)
-{
-	if (__get_latch(port) == val)
-		return 0;
-	return -EINVAL;
-}
-
-/*
- * __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained.  Callers must hold hdaps_mtx.
- */
-static int __wait_latch(u16 port, u8 val)
-{
-	unsigned int i;
-
-	for (i = 0; i < 20; i++) {
-		if (!__check_latch(port, val))
-			return 0;
-		udelay(5);
-	}
-
-	return -EIO;
-}
-
-/*
- * __device_refresh - request a refresh from the accelerometer.  Does not wait
- * for refresh to complete.  Callers must hold hdaps_mtx.
- */
-static void __device_refresh(void)
-{
-	udelay(200);
-	if (inb(0x1604) != STATE_FRESH) {
-		outb(0x11, 0x1610);
-		outb(0x01, 0x161f);
-	}
-}
-
-/*
- * __device_refresh_sync - request a synchronous refresh from the
- * accelerometer.  We wait for the refresh to complete.  Returns zero if
- * successful and nonzero on error.  Callers must hold hdaps_mtx.
- */
-static int __device_refresh_sync(void)
-{
-	__device_refresh();
-	return __wait_latch(0x1604, STATE_FRESH);
-}
-
-/*
- * __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh.  Callers must hold hdaps_mtx.
- */
-static inline void __device_complete(void)
-{
-	inb(0x161f);
-	inb(0x1604);
-	__device_refresh();
-}
-
-/*
- * hdaps_readb_one - reads a byte from a single I/O port, placing the value in
- * the given pointer.  Returns zero on success or a negative error on failure.
- * Can sleep.
- */
-static int hdaps_readb_one(unsigned int port, u8 *val)
-{
-	int ret;
-
-	mutex_lock(&hdaps_mtx);
-
-	/* do a sync refresh -- we need to be sure that we read fresh data */
-	ret = __device_refresh_sync();
-	if (ret)
-		goto out;
-
-	*val = inb(port);
-	__device_complete();
-
-out:
-	mutex_unlock(&hdaps_mtx);
-	return ret;
-}
-
-/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */
-static int __hdaps_read_pair(unsigned int port1, unsigned int port2,
-			     int *x, int *y)
-{
-	/* do a sync refresh -- we need to be sure that we read fresh data */
-	if (__device_refresh_sync())
-		return -EIO;
-
-	*y = inw(port2);
-	*x = inw(port1);
-	km_activity = inb(HDAPS_PORT_KMACT);
-	__device_complete();
-
-	/* hdaps_invert is a bitvector to negate the axes */
-	if (hdaps_invert & HDAPS_X_AXIS)
-		*x = -*x;
-	if (hdaps_invert & HDAPS_Y_AXIS)
-		*y = -*y;
-
-	return 0;
-}
-
-/*
- * hdaps_read_pair - reads the values from a pair of ports, placing the values
- * in the given pointers.  Returns zero on success.  Can sleep.
- */
-static int hdaps_read_pair(unsigned int port1, unsigned int port2,
-			   int *val1, int *val2)
-{
-	int ret;
-
-	mutex_lock(&hdaps_mtx);
-	ret = __hdaps_read_pair(port1, port2, val1, val2);
-	mutex_unlock(&hdaps_mtx);
-
-	return ret;
-}
-
-/*
- * hdaps_device_init - initialize the accelerometer.  Returns zero on success
- * and negative error code on failure.  Can sleep.
- */
-static int hdaps_device_init(void)
-{
-	int total, ret = -ENXIO;
-
-	mutex_lock(&hdaps_mtx);
-
-	outb(0x13, 0x1610);
-	outb(0x01, 0x161f);
-	if (__wait_latch(0x161f, 0x00))
-		goto out;
-
-	/*
-	 * Most ThinkPads return 0x01.
-	 *
-	 * Others--namely the R50p, T41p, and T42p--return 0x03.  These laptops
-	 * have "inverted" axises.
-	 *
-	 * The 0x02 value occurs when the chip has been previously initialized.
-	 */
-	if (__check_latch(0x1611, 0x03) &&
-		     __check_latch(0x1611, 0x02) &&
-		     __check_latch(0x1611, 0x01))
-		goto out;
-
-	printk(KERN_DEBUG "hdaps: initial latch check good (0x%02x).\n",
-	       __get_latch(0x1611));
-
-	outb(0x17, 0x1610);
-	outb(0x81, 0x1611);
-	outb(0x01, 0x161f);
-	if (__wait_latch(0x161f, 0x00))
-		goto out;
-	if (__wait_latch(0x1611, 0x00))
-		goto out;
-	if (__wait_latch(0x1612, 0x60))
-		goto out;
-	if (__wait_latch(0x1613, 0x00))
-		goto out;
-	outb(0x14, 0x1610);
-	outb(0x01, 0x1611);
-	outb(0x01, 0x161f);
-	if (__wait_latch(0x161f, 0x00))
-		goto out;
-	outb(0x10, 0x1610);
-	outb(0xc8, 0x1611);
-	outb(0x00, 0x1612);
-	outb(0x02, 0x1613);
-	outb(0x01, 0x161f);
-	if (__wait_latch(0x161f, 0x00))
-		goto out;
-	if (__device_refresh_sync())
-		goto out;
-	if (__wait_latch(0x1611, 0x00))
-		goto out;
-
-	/* we have done our dance, now let's wait for the applause */
-	for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
-		int x, y;
-
-		/* a read of the device helps push it into action */
-		__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
-		if (!__wait_latch(0x1611, 0x02)) {
-			ret = 0;
-			break;
-		}
-
-		msleep(INIT_WAIT_MSECS);
-	}
-
-out:
-	mutex_unlock(&hdaps_mtx);
-	return ret;
-}
-
-
-/* Device model stuff */
-
-static int hdaps_probe(struct platform_device *dev)
-{
-	int ret;
-
-	ret = hdaps_device_init();
-	if (ret)
-		return ret;
-
-	printk(KERN_INFO "hdaps: device successfully initialized.\n");
-	return 0;
-}
-
-static int hdaps_resume(struct platform_device *dev)
-{
-	return hdaps_device_init();
-}
-
-static struct platform_driver hdaps_driver = {
-	.probe = hdaps_probe,
-	.resume = hdaps_resume,
-	.driver	= {
-		.name = "hdaps",
-		.owner = THIS_MODULE,
-	},
-};
-
-/*
- * hdaps_calibrate - Set our "resting" values.  Callers must hold hdaps_mtx.
- */
-static void hdaps_calibrate(void)
-{
-	__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
-}
-
-static void hdaps_mousedev_poll(struct input_polled_dev *dev)
-{
-	struct input_dev *input_dev = dev->input;
-	int x, y;
-
-	mutex_lock(&hdaps_mtx);
-
-	if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
-		goto out;
-
-	input_report_abs(input_dev, ABS_X, x - rest_x);
-	input_report_abs(input_dev, ABS_Y, y - rest_y);
-	input_sync(input_dev);
-
-out:
-	mutex_unlock(&hdaps_mtx);
-}
-
-
-/* Sysfs Files */
-
-static ssize_t hdaps_position_show(struct device *dev,
-				   struct device_attribute *attr, char *buf)
-{
-	int ret, x, y;
-
-	ret = hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y);
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "(%d,%d)\n", x, y);
-}
-
-static ssize_t hdaps_variance_show(struct device *dev,
-				   struct device_attribute *attr, char *buf)
-{
-	int ret, x, y;
-
-	ret = hdaps_read_pair(HDAPS_PORT_XVAR, HDAPS_PORT_YVAR, &x, &y);
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "(%d,%d)\n", x, y);
-}
-
-static ssize_t hdaps_temp1_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	u8 temp;
-	int ret;
-
-	ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
-	if (ret < 0)
-		return ret;
-
-	return sprintf(buf, "%u\n", temp);
-}
-
-static ssize_t hdaps_temp2_show(struct device *dev,
-				struct device_attribute *attr, char *buf)
-{
-	u8 temp;
-	int ret;
-
-	ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
-	if (ret < 0)
-		return ret;
-
-	return sprintf(buf, "%u\n", temp);
-}
-
-static ssize_t hdaps_keyboard_activity_show(struct device *dev,
-					    struct device_attribute *attr,
-					    char *buf)
-{
-	return sprintf(buf, "%u\n", KEYBD_ISSET(km_activity));
-}
-
-static ssize_t hdaps_mouse_activity_show(struct device *dev,
-					 struct device_attribute *attr,
-					 char *buf)
-{
-	return sprintf(buf, "%u\n", MOUSE_ISSET(km_activity));
-}
-
-static ssize_t hdaps_calibrate_show(struct device *dev,
-				    struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "(%d,%d)\n", rest_x, rest_y);
-}
-
-static ssize_t hdaps_calibrate_store(struct device *dev,
-				     struct device_attribute *attr,
-				     const char *buf, size_t count)
-{
-	mutex_lock(&hdaps_mtx);
-	hdaps_calibrate();
-	mutex_unlock(&hdaps_mtx);
-
-	return count;
-}
-
-static ssize_t hdaps_invert_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	return sprintf(buf, "%u\n", hdaps_invert);
-}
-
-static ssize_t hdaps_invert_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf, size_t count)
-{
-	int invert;
-
-	if (sscanf(buf, "%d", &invert) != 1 ||
-	    invert < 0 || invert > HDAPS_BOTH_AXES)
-		return -EINVAL;
-
-	hdaps_invert = invert;
-	hdaps_calibrate();
-
-	return count;
-}
-
-static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL);
-static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL);
-static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL);
-static DEVICE_ATTR(temp2, 0444, hdaps_temp2_show, NULL);
-static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL);
-static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL);
-static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store);
-static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store);
-
-static struct attribute *hdaps_attributes[] = {
-	&dev_attr_position.attr,
-	&dev_attr_variance.attr,
-	&dev_attr_temp1.attr,
-	&dev_attr_temp2.attr,
-	&dev_attr_keyboard_activity.attr,
-	&dev_attr_mouse_activity.attr,
-	&dev_attr_calibrate.attr,
-	&dev_attr_invert.attr,
-	NULL,
-};
-
-static struct attribute_group hdaps_attribute_group = {
-	.attrs = hdaps_attributes,
-};
-
-
-/* Module stuff */
-
-/* hdaps_dmi_match - found a match.  return one, short-circuiting the hunt. */
-static int __init hdaps_dmi_match(const struct dmi_system_id *id)
-{
-	printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
-	return 1;
-}
-
-/* hdaps_dmi_match_invert - found an inverted match. */
-static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
-{
-	hdaps_invert = (unsigned long)id->driver_data;
-	printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n",
-	       hdaps_invert);
-	return hdaps_dmi_match(id);
-}
-
-#define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) {	\
-	.ident = vendor " " model,			\
-	.callback = hdaps_dmi_match_invert,		\
-	.driver_data = (void *)axes,			\
-	.matches = {					\
-		DMI_MATCH(DMI_BOARD_VENDOR, vendor),	\
-		DMI_MATCH(DMI_PRODUCT_VERSION, model)	\
-	}						\
-}
-
-#define HDAPS_DMI_MATCH_NORMAL(vendor, model)		\
-	HDAPS_DMI_MATCH_INVERT(vendor, model, 0)
-
-/* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match
-   "ThinkPad T42p", so the order of the entries matters.
-   If your ThinkPad is not recognized, please update to latest
-   BIOS. This is especially the case for some R52 ThinkPads. */
-static struct dmi_system_id __initdata hdaps_whitelist[] = {
-	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
-	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T400", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
-	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES),
-	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES),
-	{ .ident = NULL }
-};
-
-static int __init hdaps_init(void)
-{
-	struct input_dev *idev;
-	int ret;
-
-	if (!dmi_check_system(hdaps_whitelist)) {
-		printk(KERN_WARNING "hdaps: supported laptop not found!\n");
-		ret = -ENODEV;
-		goto out;
-	}
-
-	if (!request_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS, "hdaps")) {
-		ret = -ENXIO;
-		goto out;
-	}
-
-	ret = platform_driver_register(&hdaps_driver);
-	if (ret)
-		goto out_region;
-
-	pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
-	if (IS_ERR(pdev)) {
-		ret = PTR_ERR(pdev);
-		goto out_driver;
-	}
-
-	ret = sysfs_create_group(&pdev->dev.kobj, &hdaps_attribute_group);
-	if (ret)
-		goto out_device;
-
-	hdaps_idev = input_allocate_polled_device();
-	if (!hdaps_idev) {
-		ret = -ENOMEM;
-		goto out_group;
-	}
-
-	hdaps_idev->poll = hdaps_mousedev_poll;
-	hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
-
-	/* initial calibrate for the input device */
-	hdaps_calibrate();
-
-	/* initialize the input class */
-	idev = hdaps_idev->input;
-	idev->name = "hdaps";
-	idev->phys = "isa1600/input0";
-	idev->id.bustype = BUS_ISA;
-	idev->dev.parent = &pdev->dev;
-	idev->evbit[0] = BIT_MASK(EV_ABS);
-	input_set_abs_params(idev, ABS_X,
-			-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
-	input_set_abs_params(idev, ABS_Y,
-			-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
-
-	ret = input_register_polled_device(hdaps_idev);
-	if (ret)
-		goto out_idev;
-
-	printk(KERN_INFO "hdaps: driver successfully loaded.\n");
-	return 0;
-
-out_idev:
-	input_free_polled_device(hdaps_idev);
-out_group:
-	sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
-out_device:
-	platform_device_unregister(pdev);
-out_driver:
-	platform_driver_unregister(&hdaps_driver);
-out_region:
-	release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
-out:
-	printk(KERN_WARNING "hdaps: driver init failed (ret=%d)!\n", ret);
-	return ret;
-}
-
-static void __exit hdaps_exit(void)
-{
-	input_unregister_polled_device(hdaps_idev);
-	input_free_polled_device(hdaps_idev);
-	sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
-	platform_device_unregister(pdev);
-	platform_driver_unregister(&hdaps_driver);
-	release_region(HDAPS_LOW_PORT, HDAPS_NR_PORTS);
-
-	printk(KERN_INFO "hdaps: driver unloaded.\n");
-}
-
-module_init(hdaps_init);
-module_exit(hdaps_exit);
-
-module_param_named(invert, hdaps_invert, int, 0);
-MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, "
-		 "2 invert y-axis, 3 invert both axes.");
-
-MODULE_AUTHOR("Robert Love");
-MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver");
-MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/hp_accel.c linux-libre-2.6.37-gnu/drivers/hwmon/hp_accel.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/hp_accel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/hp_accel.c	2011-01-04 19:50:19.000000000 -0500
@@ -146,7 +146,7 @@
 
 static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
 {
-	lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
+	lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
 	printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
 
 	return 1;
@@ -154,16 +154,19 @@
 
 /* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
  * If the value is negative, the opposite of the hw value is used. */
-static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
-static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_right = {2, -1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
+#define DEFINE_CONV(name, x, y, z)			      \
+	static union axis_conversion lis3lv02d_axis_##name = \
+		{ .as_array = { x, y, z } }
+DEFINE_CONV(normal, 1, 2, 3);
+DEFINE_CONV(y_inverted, 1, -2, 3);
+DEFINE_CONV(x_inverted, -1, 2, 3);
+DEFINE_CONV(z_inverted, 1, 2, -3);
+DEFINE_CONV(xy_swap, 2, 1, 3);
+DEFINE_CONV(xy_rotated_left, -2, 1, 3);
+DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
+DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
+DEFINE_CONV(xy_rotated_right, 2, -1, 3);
+DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
 
 #define AXIS_DMI_MATCH(_ident, _name, _axis) {		\
 	.ident = _ident,				\
@@ -222,7 +225,7 @@
 	AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
 	AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
 	AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
-	AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd),
+	AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
 	{ NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
@@ -299,7 +302,10 @@
 	lis3lv02d_enum_resources(device);
 
 	/* If possible use a "standard" axes order */
-	if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+	if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
+		printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
+		       lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
+	} else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
 		printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
 				 "using default axes configuration\n");
 		lis3_dev.ac = lis3lv02d_axis_normal;
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/hwmon-vid.c linux-libre-2.6.37-gnu/drivers/hwmon/hwmon-vid.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/hwmon-vid.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/hwmon-vid.c	2011-01-04 19:50:19.000000000 -0500
@@ -38,7 +38,7 @@
  * available at http://developer.intel.com/.
  *
  * AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094,
- * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF
+ * http://support.amd.com/us/Processor_TechDocs/26094.PDF 
  * Table 74. VID Code Voltages
  * This corresponds to an arbitrary VRM code of 24 in the functions below.
  * These CPU models (K8 revision <= E) have 5 VID pins. See also:
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/i5k_amb.c linux-libre-2.6.37-gnu/drivers/hwmon/i5k_amb.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/i5k_amb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/i5k_amb.c	2011-01-04 19:50:19.000000000 -0500
@@ -497,12 +497,14 @@
 	0
 };
 
+#ifdef MODULE
 static struct pci_device_id i5k_amb_ids[] __devinitdata = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+#endif
 
 static int __devinit i5k_amb_probe(struct platform_device *pdev)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/it87.c linux-libre-2.6.37-gnu/drivers/hwmon/it87.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/it87.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/it87.c	2011-01-04 19:50:19.000000000 -0500
@@ -15,7 +15,9 @@
  *            IT8716F  Super I/O chip w/LPC interface
  *            IT8718F  Super I/O chip w/LPC interface
  *            IT8720F  Super I/O chip w/LPC interface
+ *            IT8721F  Super I/O chip w/LPC interface
  *            IT8726F  Super I/O chip w/LPC interface
+ *            IT8758E  Super I/O chip w/LPC interface
  *            Sis950   A clone of the IT8705F
  *
  *  Copyright (C) 2001 Chris Gauthron
@@ -54,7 +56,7 @@
 
 #define DRVNAME "it87"
 
-enum chips { it87, it8712, it8716, it8718, it8720 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -126,6 +128,7 @@
 #define IT8716F_DEVID 0x8716
 #define IT8718F_DEVID 0x8718
 #define IT8720F_DEVID 0x8720
+#define IT8721F_DEVID 0x8721
 #define IT8726F_DEVID 0x8726
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
@@ -184,6 +187,7 @@
 #define IT87_REG_FAN_MAIN_CTRL 0x13
 #define IT87_REG_FAN_CTL       0x14
 #define IT87_REG_PWM(nr)       (0x15 + (nr))
+#define IT87_REG_PWM_DUTY(nr)  (0x63 + (nr) * 8)
 
 #define IT87_REG_VIN(nr)       (0x20 + (nr))
 #define IT87_REG_TEMP(nr)      (0x29 + (nr))
@@ -202,56 +206,6 @@
 #define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
 #define IT87_REG_AUTO_PWM(nr, i)  (0x65 + (nr) * 8 + (i))
 
-#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
-#define IN_FROM_REG(val) ((val) * 16)
-
-static inline u8 FAN_TO_REG(long rpm, int div)
-{
-	if (rpm == 0)
-		return 255;
-	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
-	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
-			     254);
-}
-
-static inline u16 FAN16_TO_REG(long rpm)
-{
-	if (rpm == 0)
-		return 0xffff;
-	return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
-}
-
-#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
-/* The divider is fixed to 2 in 16-bit mode */
-#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))
-
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
-					((val)+500)/1000),-128,127))
-#define TEMP_FROM_REG(val) ((val) * 1000)
-
-#define PWM_TO_REG(val)   ((val) >> 1)
-#define PWM_FROM_REG(val) (((val)&0x7f) << 1)
-
-static int DIV_TO_REG(int val)
-{
-	int answer = 0;
-	while (answer < 7 && (val >>= 1))
-		answer++;
-	return answer;
-}
-#define DIV_FROM_REG(val) (1 << (val))
-
-static const unsigned int pwm_freq[8] = {
-	48000000 / 128,
-	24000000 / 128,
-	12000000 / 128,
-	8000000 / 128,
-	6000000 / 128,
-	3000000 / 128,
-	1500000 / 128,
-	750000 / 128,
-};
-
 
 struct it87_sio_data {
 	enum chips type;
@@ -279,6 +233,7 @@
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
+	u16 in_scaled;		/* Internal voltage sensors are scaled */
 	u8 in[9];		/* Register value */
 	u8 in_max[8];		/* Register value */
 	u8 in_min[8];		/* Register value */
@@ -297,12 +252,16 @@
 	u8 fan_main_ctrl;	/* Register value */
 	u8 fan_ctl;		/* Register value */
 
-	/* The following 3 arrays correspond to the same registers. The
-	 * meaning of bits 6-0 depends on the value of bit 7, and we want
-	 * to preserve settings on mode changes, so we have to track all
-	 * values separately. */
+	/* The following 3 arrays correspond to the same registers up to
+	 * the IT8720F. The meaning of bits 6-0 depends on the value of bit
+	 * 7, and we want to preserve settings on mode changes, so we have
+	 * to track all values separately.
+	 * Starting with the IT8721F, the manual PWM duty cycles are stored
+	 * in separate registers (8-bit values), so the separate tracking
+	 * is no longer needed, but it is still done to keep the driver
+	 * simple. */
 	u8 pwm_ctrl[3];		/* Register value */
-	u8 pwm_duty[3];		/* Manual PWM value set by user (bit 6-0) */
+	u8 pwm_duty[3];		/* Manual PWM value set by user */
 	u8 pwm_temp_map[3];	/* PWM to temp. chan. mapping (bits 1-0) */
 
 	/* Automatic fan speed control registers */
@@ -310,6 +269,96 @@
 	s8 auto_temp[3][5];	/* [nr][0] is point1_temp_hyst */
 };
 
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+{
+	long lsb;
+
+	if (data->type == it8721) {
+		if (data->in_scaled & (1 << nr))
+			lsb = 24;
+		else
+			lsb = 12;
+	} else
+		lsb = 16;
+
+	val = DIV_ROUND_CLOSEST(val, lsb);
+	return SENSORS_LIMIT(val, 0, 255);
+}
+
+static int in_from_reg(const struct it87_data *data, int nr, int val)
+{
+	if (data->type == it8721) {
+		if (data->in_scaled & (1 << nr))
+			return val * 24;
+		else
+			return val * 12;
+	} else
+		return val * 16;
+}
+
+static inline u8 FAN_TO_REG(long rpm, int div)
+{
+	if (rpm == 0)
+		return 255;
+	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
+			     254);
+}
+
+static inline u16 FAN16_TO_REG(long rpm)
+{
+	if (rpm == 0)
+		return 0xffff;
+	return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+}
+
+#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
+				1350000 / ((val) * (div)))
+/* The divider is fixed to 2 in 16-bit mode */
+#define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
+			     1350000 / ((val) * 2))
+
+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \
+					((val) + 500) / 1000), -128, 127))
+#define TEMP_FROM_REG(val) ((val) * 1000)
+
+static u8 pwm_to_reg(const struct it87_data *data, long val)
+{
+	if (data->type == it8721)
+		return val;
+	else
+		return val >> 1;
+}
+
+static int pwm_from_reg(const struct it87_data *data, u8 reg)
+{
+	if (data->type == it8721)
+		return reg;
+	else
+		return (reg & 0x7f) << 1;
+}
+
+
+static int DIV_TO_REG(int val)
+{
+	int answer = 0;
+	while (answer < 7 && (val >>= 1))
+		answer++;
+	return answer;
+}
+#define DIV_FROM_REG(val) (1 << (val))
+
+static const unsigned int pwm_freq[8] = {
+	48000000 / 128,
+	24000000 / 128,
+	12000000 / 128,
+	8000000 / 128,
+	6000000 / 128,
+	3000000 / 128,
+	1500000 / 128,
+	750000 / 128,
+};
+
 static inline int has_16bit_fans(const struct it87_data *data)
 {
 	/* IT8705F Datasheet 0.4.1, 3h == Version G.
@@ -319,7 +368,8 @@
 	    || (data->type == it8712 && data->revision >= 0x08)
 	    || data->type == it8716
 	    || data->type == it8718
-	    || data->type == it8720;
+	    || data->type == it8720
+	    || data->type == it8721;
 }
 
 static inline int has_old_autopwm(const struct it87_data *data)
@@ -357,7 +407,7 @@
 	int nr = sensor_attr->index;
 
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
+	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr]));
 }
 
 static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
@@ -367,7 +417,7 @@
 	int nr = sensor_attr->index;
 
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
+	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr]));
 }
 
 static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
@@ -377,7 +427,7 @@
 	int nr = sensor_attr->index;
 
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
+	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr]));
 }
 
 static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
@@ -393,7 +443,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->in_min[nr] = IN_TO_REG(val);
+	data->in_min[nr] = in_to_reg(data, nr, val);
 	it87_write_value(data, IT87_REG_VIN_MIN(nr),
 			data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
@@ -412,7 +462,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->in_max[nr] = IN_TO_REG(val);
+	data->in_max[nr] = in_to_reg(data, nr, val);
 	it87_write_value(data, IT87_REG_VIN_MAX(nr),
 			data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
@@ -642,7 +692,8 @@
 	int nr = sensor_attr->index;
 
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm_duty[nr]));
+	return sprintf(buf, "%d\n",
+		       pwm_from_reg(data, data->pwm_duty[nr]));
 }
 static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
 		char *buf)
@@ -786,7 +837,9 @@
 				 data->fan_main_ctrl);
 	} else {
 		if (val == 1)				/* Manual mode */
-			data->pwm_ctrl[nr] = data->pwm_duty[nr];
+			data->pwm_ctrl[nr] = data->type == it8721 ?
+					     data->pwm_temp_map[nr] :
+					     data->pwm_duty[nr];
 		else					/* Automatic mode */
 			data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
 		it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
@@ -812,12 +865,25 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->pwm_duty[nr] = PWM_TO_REG(val);
-	/* If we are in manual mode, write the duty cycle immediately;
-	 * otherwise, just store it for later use. */
-	if (!(data->pwm_ctrl[nr] & 0x80)) {
-		data->pwm_ctrl[nr] = data->pwm_duty[nr];
-		it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
+	if (data->type == it8721) {
+		/* If we are in automatic mode, the PWM duty cycle register
+		 * is read-only so we can't write the value */
+		if (data->pwm_ctrl[nr] & 0x80) {
+			mutex_unlock(&data->update_lock);
+			return -EBUSY;
+		}
+		data->pwm_duty[nr] = pwm_to_reg(data, val);
+		it87_write_value(data, IT87_REG_PWM_DUTY(nr),
+				 data->pwm_duty[nr]);
+	} else {
+		data->pwm_duty[nr] = pwm_to_reg(data, val);
+		/* If we are in manual mode, write the duty cycle immediately;
+		 * otherwise, just store it for later use. */
+		if (!(data->pwm_ctrl[nr] & 0x80)) {
+			data->pwm_ctrl[nr] = data->pwm_duty[nr];
+			it87_write_value(data, IT87_REG_PWM(nr),
+					 data->pwm_ctrl[nr]);
+		}
 	}
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -916,7 +982,8 @@
 	int nr = sensor_attr->nr;
 	int point = sensor_attr->index;
 
-	return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point]));
+	return sprintf(buf, "%d\n",
+		       pwm_from_reg(data, data->auto_pwm[nr][point]));
 }
 
 static ssize_t set_auto_pwm(struct device *dev,
@@ -933,7 +1000,7 @@
 		return -EINVAL;
 
 	mutex_lock(&data->update_lock);
-	data->auto_pwm[nr][point] = PWM_TO_REG(val);
+	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
 	it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
 			 data->auto_pwm[nr][point]);
 	mutex_unlock(&data->update_lock);
@@ -1203,9 +1270,16 @@
 		"5VSB",
 		"Vbat",
 	};
+	static const char *labels_it8721[] = {
+		"+3.3V",
+		"3VSB",
+		"Vbat",
+	};
+	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = to_sensor_dev_attr(attr)->index;
 
-	return sprintf(buf, "%s\n", labels[nr]);
+	return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
+							 : labels[nr]);
 }
 static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
 static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
@@ -1490,6 +1564,9 @@
 	case IT8720F_DEVID:
 		sio_data->type = it8720;
 		break;
+	case IT8721F_DEVID:
+		sio_data->type = it8721;
+		break;
 	case 0xffff:	/* No device at all */
 		goto exit;
 	default:
@@ -1530,11 +1607,17 @@
 		int reg;
 
 		superio_select(GPIO);
-		/* We need at least 4 VID pins */
+
 		reg = superio_inb(IT87_SIO_GPIO3_REG);
-		if (reg & 0x0f) {
-			pr_info("it87: VID is disabled (pins used for GPIO)\n");
+		if (sio_data->type == it8721) {
+			/* The IT8721F/IT8758E doesn't have VID pins at all */
 			sio_data->skip_vid = 1;
+		} else {
+			/* We need at least 4 VID pins */
+			if (reg & 0x0f) {
+				pr_info("it87: VID is disabled (pins used for GPIO)\n");
+				sio_data->skip_vid = 1;
+			}
 		}
 
 		/* Check if fan3 is there or not */
@@ -1572,7 +1655,7 @@
 		}
 		if (reg & (1 << 0))
 			sio_data->internal |= (1 << 0);
-		if (reg & (1 << 1))
+		if ((reg & (1 << 1)) || sio_data->type == it8721)
 			sio_data->internal |= (1 << 1);
 
 		sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
@@ -1650,6 +1733,7 @@
 		"it8716",
 		"it8718",
 		"it8720",
+		"it8721",
 	};
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1686,6 +1770,16 @@
 	/* Check PWM configuration */
 	enable_pwm_interface = it87_check_pwm(dev);
 
+	/* Starting with IT8721F, we handle scaling of internal voltages */
+	if (data->type == it8721) {
+		if (sio_data->internal & (1 << 0))
+			data->in_scaled |= (1 << 3);	/* in3 is AVCC */
+		if (sio_data->internal & (1 << 1))
+			data->in_scaled |= (1 << 7);	/* in7 is VSB */
+		if (sio_data->internal & (1 << 2))
+			data->in_scaled |= (1 << 8);	/* in8 is Vbat */
+	}
+
 	/* Initialize the IT87 chip */
 	it87_init_device(pdev);
 
@@ -1884,7 +1978,10 @@
 	 *   channels to use when later setting to automatic mode later.
 	 *   Use a 1:1 mapping by default (we are clueless.)
 	 * In both cases, the value can (and should) be changed by the user
-	 * prior to switching to a different mode. */
+	 * prior to switching to a different mode.
+	 * Note that this is no longer needed for the IT8721F and later, as
+	 * these have separate registers for the temperature mapping and the
+	 * manual duty cycle. */
 	for (i = 0; i < 3; i++) {
 		data->pwm_temp_map[i] = i;
 		data->pwm_duty[i] = 0x7f;	/* Full speed */
@@ -1960,10 +2057,16 @@
 static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
 {
 	data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM(nr));
-	if (data->pwm_ctrl[nr] & 0x80)	/* Automatic mode */
+	if (data->type == it8721) {
 		data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
-	else				/* Manual mode */
-		data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+		data->pwm_duty[nr] = it87_read_value(data,
+						     IT87_REG_PWM_DUTY(nr));
+	} else {
+		if (data->pwm_ctrl[nr] & 0x80)	/* Automatic mode */
+			data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+		else				/* Manual mode */
+			data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
+	}
 
 	if (has_old_autopwm(data)) {
 		int i;
@@ -2051,7 +2154,7 @@
 
 		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
 		/* The 8705 does not have VID capability.
-		   The 8718 and the 8720 don't use IT87_REG_VID for the
+		   The 8718 and later don't use IT87_REG_VID for the
 		   same purpose. */
 		if (data->type == it8712 || data->type == it8716) {
 			data->vid = it87_read_value(data, IT87_REG_VID);
@@ -2151,7 +2254,7 @@
 
 MODULE_AUTHOR("Chris Gauthron, "
 	      "Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
 module_param(fix_pwm_polarity, bool, 0);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/k8temp.c linux-libre-2.6.37-gnu/drivers/hwmon/k8temp.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/k8temp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/k8temp.c	2011-01-04 19:50:19.000000000 -0500
@@ -191,38 +191,31 @@
 	model = boot_cpu_data.x86_model;
 	stepping = boot_cpu_data.x86_mask;
 
-	switch (boot_cpu_data.x86) {
-	case 0xf:
-		/* feature available since SH-C0, exclude older revisions */
-		if (((model == 4) && (stepping == 0)) ||
-		    ((model == 5) && (stepping <= 1))) {
-			err = -ENODEV;
-			goto exit_free;
-		}
-
-		/*
-		 * AMD NPT family 0fh, i.e. RevF and RevG:
-		 * meaning of SEL_CORE bit is inverted
-		 */
-		if (model >= 0x40) {
-			data->swap_core_select = 1;
-			dev_warn(&pdev->dev, "Temperature readouts might be "
-				 "wrong - check erratum #141\n");
-		}
-
-		if (is_rev_g_desktop(model)) {
-			/*
-			 * RevG desktop CPUs (i.e. no socket S1G1 or
-			 * ASB1 parts) need additional offset,
-			 * otherwise reported temperature is below
-			 * ambient temperature
-			 */
-			data->temp_offset = 21000;
-		}
+	/* feature available since SH-C0, exclude older revisions */
+	if (((model == 4) && (stepping == 0)) ||
+	    ((model == 5) && (stepping <= 1))) {
+		err = -ENODEV;
+		goto exit_free;
+	}
 
-		break;
+	/*
+	 * AMD NPT family 0fh, i.e. RevF and RevG:
+	 * meaning of SEL_CORE bit is inverted
+	 */
+	if (model >= 0x40) {
+		data->swap_core_select = 1;
+		dev_warn(&pdev->dev, "Temperature readouts might be wrong - "
+			 "check erratum #141\n");
 	}
 
+	/*
+	 * RevG desktop CPUs (i.e. no socket S1G1 or ASB1 parts) need
+	 * additional offset, otherwise reported temperature is below
+	 * ambient temperature
+	 */
+	if (is_rev_g_desktop(model))
+		data->temp_offset = 21000;
+
 	pci_read_config_byte(pdev, REG_TEMP, &scfg);
 	scfg &= ~(SEL_PLACE | SEL_CORE);		/* Select sensor 0, core0 */
 	pci_write_config_byte(pdev, REG_TEMP, scfg);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/Kconfig linux-libre-2.6.37-gnu/drivers/hwmon/Kconfig
--- linux-libre-2.6.36-gnu/drivers/hwmon/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -129,7 +129,7 @@
 
 config SENSORS_ADM1026
 	tristate "Analog Devices ADM1026 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for Analog Devices ADM1026
@@ -140,7 +140,7 @@
 
 config SENSORS_ADM1029
 	tristate "Analog Devices ADM1029"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Analog Devices ADM1029
 	  sensor chip.
@@ -151,7 +151,7 @@
 
 config SENSORS_ADM1031
 	tristate "Analog Devices ADM1031 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Analog Devices ADM1031
 	  and ADM1030 sensor chips.
@@ -202,7 +202,7 @@
 
 config SENSORS_ADT7475
 	tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the Analog Devices
@@ -249,32 +249,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called k10temp.
 
-config SENSORS_AMS
-	tristate "Apple Motion Sensor driver"
-	depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
-	select INPUT_POLLDEV
-	help
-	  Support for the motion sensor included in PowerBooks. Includes
-	  implementations for PMU and I2C.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called ams.
-
-config SENSORS_AMS_PMU
-	bool "PMU variant"
-	depends on SENSORS_AMS && ADB_PMU
-	default y
-	help
-	  PMU variant of motion sensor, found in late 2005 PowerBooks.
-
-config SENSORS_AMS_I2C
-	bool "I2C variant"
-	depends on SENSORS_AMS && I2C
-	default y
-	help
-	  I2C variant of motion sensor, found in early 2005 PowerBooks and
-	  iBooks.
-
 config SENSORS_ASB100
 	tristate "Asus ASB100 Bach"
 	depends on X86 && I2C && EXPERIMENTAL
@@ -322,7 +296,6 @@
 
 config SENSORS_F71805F
 	tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
-	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for hardware monitoring
 	  features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
@@ -333,7 +306,6 @@
 
 config SENSORS_F71882FG
 	tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000"
-	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get support for hardware monitoring
 	  features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG,
@@ -343,8 +315,8 @@
 	  will be called f71882fg.
 
 config SENSORS_F75375S
-	tristate "Fintek F75375S/SP and F75373";
-	depends on I2C && EXPERIMENTAL
+	tristate "Fintek F75375S/SP and F75373"
+	depends on I2C
 	help
 	  If you say yes here you get support for hardware monitoring
 	  features of the Fintek F75375S/SP and F75373
@@ -399,6 +371,15 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called gl520sm.
 
+config SENSORS_GPIO_FAN
+	tristate "GPIO fan"
+	depends on GENERIC_GPIO
+	help
+	  If you say yes here you get support for fans connected to GPIO lines.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-fan.
+
 config SENSORS_CORETEMP
 	tristate "Intel Core/Core2/Atom temperature sensor"
 	depends on X86 && PCI && EXPERIMENTAL
@@ -447,8 +428,8 @@
 	select HWMON_VID
 	help
 	  If you say yes here you get support for ITE IT8705F, IT8712F,
-	  IT8716F, IT8718F, IT8720F and IT8726F sensor chips, and the
-	  SiS960 clone.
+	  IT8716F, IT8718F, IT8720F, IT8721F, IT8726F and IT8758E sensor
+	  chips, and the SiS960 clone.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
@@ -490,7 +471,7 @@
 
 config SENSORS_LM70
 	tristate "National Semiconductor LM70 / Texas Instruments TMP121"
-	depends on SPI_MASTER && EXPERIMENTAL
+	depends on SPI_MASTER
 	help
 	  If you say yes here you get support for the National Semiconductor
 	  LM70 and Texas Instruments TMP121/TMP123 digital temperature
@@ -558,7 +539,7 @@
 
 config SENSORS_LM80
 	tristate "National Semiconductor LM80"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor
 	  LM80 sensor chips.
@@ -578,11 +559,12 @@
 
 config SENSORS_LM85
 	tristate "National Semiconductor LM85 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for National Semiconductor LM85
-	  sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
+	  sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100,
+	  EMC6D101 and EMC6D102.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm85.
@@ -605,8 +587,8 @@
 	  If you say yes here you get support for National Semiconductor LM90,
 	  LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim
 	  MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
-	  MAX6680, MAX6681 and MAX6692, and Winbond/Nuvoton W83L771AWG/ASG
-	  sensor chips.
+	  MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton
+	  W83L771W/G/AWG/ASG sensor chips.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm90.
@@ -654,6 +636,17 @@
 	  This driver can also be built as a module. If so, the module will
 	  be called ltc4245.
 
+config SENSORS_LTC4261
+	tristate "Linear Technology LTC4261"
+	depends on I2C && EXPERIMENTAL
+	default n
+	help
+	  If you say yes here you get support for Linear Technology LTC4261
+	  Negative Voltage Hot Swap Controller I2C interface.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called ltc4261.
+
 config SENSORS_LM95241
 	tristate "National Semiconductor LM95241 sensor chip"
 	depends on I2C
@@ -706,7 +699,6 @@
 
 config SENSORS_PC87427
 	tristate "National Semiconductor PC87427"
-	depends on EXPERIMENTAL
 	help
 	  If you say yes here you get access to the hardware monitoring
 	  functions of the National Semiconductor PC87427 Super-I/O chip.
@@ -743,14 +735,14 @@
 	  will be called sht15.
 
 config SENSORS_S3C
-	tristate "S3C24XX/S3C64XX Inbuilt ADC"
-	depends on ARCH_S3C2410
+	tristate "Samsung built-in ADC"
+	depends on S3C_ADC
 	help
 	  If you say yes here you get support for the on-board ADCs of
-	  the Samsung S3C24XX or S3C64XX series of SoC
+	  the Samsung S3C24XX, S3C64XX and other series of SoC
 
 	  This driver can also be built as a module. If so, the module
-	  will be called s3c-hwmo.
+	  will be called s3c-hwmon.
 
 config SENSORS_S3C_RAW
 	bool "Include raw channel attributes in sysfs"
@@ -834,7 +826,7 @@
 
 config SENSORS_SMSC47M192
 	tristate "SMSC LPC47M192 and compatibles"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	select HWMON_VID
 	help
 	  If you say yes here you get support for the temperature and
@@ -890,7 +882,7 @@
 
 config SENSORS_THMC50
 	tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for Texas Instruments THMC50
 	  sensor chips and clones: the Analog Devices ADM1022.
@@ -948,7 +940,6 @@
 
 config SENSORS_VT1211
 	tristate "VIA VT1211"
-	depends on EXPERIMENTAL
 	select HWMON_VID
 	help
 	  If you say yes here then you get support for hardware monitoring
@@ -992,7 +983,7 @@
 
 config SENSORS_W83792D
 	tristate "Winbond W83792D"
-	depends on I2C && EXPERIMENTAL
+	depends on I2C
 	help
 	  If you say yes here you get support for the Winbond W83792D chip.
 
@@ -1011,6 +1002,33 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83793.
 
+config SENSORS_W83795
+	tristate "Winbond/Nuvoton W83795G/ADG"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Winbond W83795G and
+	  W83795ADG hardware monitoring chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called w83795.
+
+config SENSORS_W83795_FANCTRL
+	boolean "Include fan control support (DANGEROUS)"
+	depends on SENSORS_W83795 && EXPERIMENTAL
+	default n
+	help
+	  If you say yes here, support for the both manual and automatic
+	  fan control features will be included in the driver.
+
+	  This part of the code wasn't carefully reviewed and tested yet,
+	  so enabling this option is strongly discouraged on production
+	  servers. Only developers and testers should enable it for the
+	  time being.
+
+	  Please also note that this option will create sysfs attribute
+	  files which may change in the future, so you shouldn't rely
+	  on them being stable.
+
 config SENSORS_W83L785TS
 	tristate "Winbond W83L785TS-S"
 	depends on I2C && EXPERIMENTAL
@@ -1088,26 +1106,6 @@
 	  This driver provides support for the Ultra45 workstation environmental
 	  sensors.
 
-config SENSORS_HDAPS
-	tristate "IBM Hard Drive Active Protection System (hdaps)"
-	depends on INPUT && X86
-	select INPUT_POLLDEV
-	default n
-	help
-	  This driver provides support for the IBM Hard Drive Active Protection
-	  System (hdaps), which provides an accelerometer and other misc. data.
-	  ThinkPads starting with the R50, T41, and X40 are supported.  The
-	  accelerometer data is readable via sysfs.
-
-	  This driver also provides an absolute input class device, allowing
-	  the laptop to act as a pinball machine-esque joystick.
-
-	  If your ThinkPad is not recognized by the driver, please update to latest
-	  BIOS. This is especially the case for some R52 ThinkPads.
-
-	  Say Y here if you have an applicable laptop and want to experience
-	  the awesome power of hdaps.
-
 config SENSORS_LIS3_SPI
 	tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
 	depends on !ACPI && SPI_MASTER && INPUT
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d.c linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,9 +31,11 @@
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
+#include <linux/slab.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
+#include <linux/pm_runtime.h>
 #include <asm/atomic.h>
 #include "lis3lv02d.h"
 
@@ -43,6 +45,16 @@
 #define MDPS_POLL_INTERVAL 50
 #define MDPS_POLL_MIN	   0
 #define MDPS_POLL_MAX	   2000
+
+#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */
+
+#define SELFTEST_OK	       0
+#define SELFTEST_FAIL	       -1
+#define SELFTEST_IRQ	       -2
+
+#define IRQ_LINE0	       0
+#define IRQ_LINE1	       1
+
 /*
  * The sensor can also generate interrupts (DRDY) but it's pretty pointless
  * because they are generated even if the data do not change. So it's better
@@ -66,8 +78,10 @@
 #define LIS3_SENSITIVITY_12B		((LIS3_ACCURACY * 1000) / 1024)
 #define LIS3_SENSITIVITY_8B		(18 * LIS3_ACCURACY)
 
-#define LIS3_DEFAULT_FUZZ		3
-#define LIS3_DEFAULT_FLAT		3
+#define LIS3_DEFAULT_FUZZ_12B		3
+#define LIS3_DEFAULT_FLAT_12B		3
+#define LIS3_DEFAULT_FUZZ_8B		1
+#define LIS3_DEFAULT_FLAT_8B		1
 
 struct lis3lv02d lis3_dev = {
 	.misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
@@ -75,6 +89,30 @@
 
 EXPORT_SYMBOL_GPL(lis3_dev);
 
+/* just like param_set_int() but does sanity-check so that it won't point
+ * over the axis array size
+ */
+static int param_set_axis(const char *val, const struct kernel_param *kp)
+{
+	int ret = param_set_int(val, kp);
+	if (!ret) {
+		int val = *(int *)kp->arg;
+		if (val < 0)
+			val = -val;
+		if (!val || val > 3)
+			return -EINVAL;
+	}
+	return ret;
+}
+
+static struct kernel_param_ops param_ops_axis = {
+	.set = param_set_axis,
+	.get = param_get_int,
+};
+
+module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644);
+MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions");
+
 static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg)
 {
 	s8 lo;
@@ -123,9 +161,24 @@
 	int position[3];
 	int i;
 
-	position[0] = lis3->read_data(lis3, OUTX);
-	position[1] = lis3->read_data(lis3, OUTY);
-	position[2] = lis3->read_data(lis3, OUTZ);
+	if (lis3->blkread) {
+		if (lis3_dev.whoami == WAI_12B) {
+			u16 data[3];
+			lis3->blkread(lis3, OUTX_L, 6, (u8 *)data);
+			for (i = 0; i < 3; i++)
+				position[i] = (s16)le16_to_cpu(data[i]);
+		} else {
+			u8 data[5];
+			/* Data: x, dummy, y, dummy, z */
+			lis3->blkread(lis3, OUTX, 5, data);
+			for (i = 0; i < 3; i++)
+				position[i] = (s8)data[i * 2];
+		}
+	} else {
+		position[0] = lis3->read_data(lis3, OUTX);
+		position[1] = lis3->read_data(lis3, OUTY);
+		position[2] = lis3->read_data(lis3, OUTZ);
+	}
 
 	for (i = 0; i < 3; i++)
 		position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY;
@@ -138,6 +191,7 @@
 /* conversion btw sampling rate and the register values */
 static int lis3_12_rates[4] = {40, 160, 640, 2560};
 static int lis3_8_rates[2] = {100, 400};
+static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
 
 /* ODR is Output Data Rate */
 static int lis3lv02d_get_odr(void)
@@ -156,6 +210,9 @@
 	u8 ctrl;
 	int i, len, shift;
 
+	if (!rate)
+		return -EINVAL;
+
 	lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
 	ctrl &= ~lis3_dev.odr_mask;
 	len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */
@@ -172,19 +229,42 @@
 
 static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
 {
-	u8 reg;
+	u8 ctlreg, reg;
 	s16 x, y, z;
 	u8 selftest;
 	int ret;
+	u8 ctrl_reg_data;
+	unsigned char irq_cfg;
 
 	mutex_lock(&lis3->mutex);
-	if (lis3_dev.whoami == WAI_12B)
-		selftest = CTRL1_ST;
-	else
-		selftest = CTRL1_STP;
 
-	lis3->read(lis3, CTRL_REG1, &reg);
-	lis3->write(lis3, CTRL_REG1, (reg | selftest));
+	irq_cfg = lis3->irq_cfg;
+	if (lis3_dev.whoami == WAI_8B) {
+		lis3->data_ready_count[IRQ_LINE0] = 0;
+		lis3->data_ready_count[IRQ_LINE1] = 0;
+
+		/* Change interrupt cfg to data ready for selftest */
+		atomic_inc(&lis3_dev.wake_thread);
+		lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY;
+		lis3->read(lis3, CTRL_REG3, &ctrl_reg_data);
+		lis3->write(lis3, CTRL_REG3, (ctrl_reg_data &
+				~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) |
+				(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
+	}
+
+	if (lis3_dev.whoami == WAI_3DC) {
+		ctlreg = CTRL_REG4;
+		selftest = CTRL4_ST0;
+	} else {
+		ctlreg = CTRL_REG1;
+		if (lis3_dev.whoami == WAI_12B)
+			selftest = CTRL1_ST;
+		else
+			selftest = CTRL1_STP;
+	}
+
+	lis3->read(lis3, ctlreg, &reg);
+	lis3->write(lis3, ctlreg, (reg | selftest));
 	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
 
 	/* Read directly to avoid axis remap */
@@ -193,7 +273,7 @@
 	z = lis3->read_data(lis3, OUTZ);
 
 	/* back to normal settings */
-	lis3->write(lis3, CTRL_REG1, reg);
+	lis3->write(lis3, ctlreg, reg);
 	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
 
 	results[0] = x - lis3->read_data(lis3, OUTX);
@@ -201,13 +281,33 @@
 	results[2] = z - lis3->read_data(lis3, OUTZ);
 
 	ret = 0;
+
+	if (lis3_dev.whoami == WAI_8B) {
+		/* Restore original interrupt configuration */
+		atomic_dec(&lis3_dev.wake_thread);
+		lis3->write(lis3, CTRL_REG3, ctrl_reg_data);
+		lis3->irq_cfg = irq_cfg;
+
+		if ((irq_cfg & LIS3_IRQ1_MASK) &&
+			lis3->data_ready_count[IRQ_LINE0] < 2) {
+			ret = SELFTEST_IRQ;
+			goto fail;
+		}
+
+		if ((irq_cfg & LIS3_IRQ2_MASK) &&
+			lis3->data_ready_count[IRQ_LINE1] < 2) {
+			ret = SELFTEST_IRQ;
+			goto fail;
+		}
+	}
+
 	if (lis3->pdata) {
 		int i;
 		for (i = 0; i < 3; i++) {
 			/* Check against selftest acceptance limits */
 			if ((results[i] < lis3->pdata->st_min_limits[i]) ||
 			    (results[i] > lis3->pdata->st_max_limits[i])) {
-				ret = -EIO;
+				ret = SELFTEST_FAIL;
 				goto fail;
 			}
 		}
@@ -219,10 +319,46 @@
 	return ret;
 }
 
+/*
+ * Order of registers in the list affects to order of the restore process.
+ * Perhaps it is a good idea to set interrupt enable register as a last one
+ * after all other configurations
+ */
+static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1,
+			       FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2,
+			       CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ,
+			       CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW,
+			       CTRL_REG1, CTRL_REG2, CTRL_REG3};
+
+static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H,
+			       FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H,
+			       DD_THSE_L, DD_THSE_H,
+			       CTRL_REG1, CTRL_REG3, CTRL_REG2};
+
+static inline void lis3_context_save(struct lis3lv02d *lis3)
+{
+	int i;
+	for (i = 0; i < lis3->regs_size; i++)
+		lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]);
+	lis3->regs_stored = true;
+}
+
+static inline void lis3_context_restore(struct lis3lv02d *lis3)
+{
+	int i;
+	if (lis3->regs_stored)
+		for (i = 0; i < lis3->regs_size; i++)
+			lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]);
+}
+
 void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 {
+	if (lis3->reg_ctrl)
+		lis3_context_save(lis3);
 	/* disable X,Y,Z axis and power down */
 	lis3->write(lis3, CTRL_REG1, 0x00);
+	if (lis3->reg_ctrl)
+		lis3->reg_ctrl(lis3, LIS3_REG_OFF);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
@@ -232,19 +368,24 @@
 
 	lis3->init(lis3);
 
-	/* LIS3 power on delay is quite long */
-	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
-
 	/*
 	 * Common configuration
 	 * BDU: (12 bits sensors only) LSB and MSB values are not updated until
 	 *      both have been read. So the value read will always be correct.
+	 * Set BOOT bit to refresh factory tuning values.
 	 */
-	if (lis3->whoami ==  WAI_12B) {
-		lis3->read(lis3, CTRL_REG2, &reg);
-		reg |= CTRL2_BDU;
-		lis3->write(lis3, CTRL_REG2, reg);
-	}
+	lis3->read(lis3, CTRL_REG2, &reg);
+	if (lis3->whoami ==  WAI_12B)
+		reg |= CTRL2_BDU | CTRL2_BOOT;
+	else
+		reg |= CTRL2_BOOT_8B;
+	lis3->write(lis3, CTRL_REG2, reg);
+
+	/* LIS3 power on delay is quite long */
+	msleep(lis3->pwron_delay / lis3lv02d_get_odr());
+
+	if (lis3->reg_ctrl)
+		lis3_context_restore(lis3);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
@@ -262,6 +403,27 @@
 	mutex_unlock(&lis3_dev.mutex);
 }
 
+static void lis3lv02d_joystick_open(struct input_polled_dev *pidev)
+{
+	if (lis3_dev.pm_dev)
+		pm_runtime_get_sync(lis3_dev.pm_dev);
+
+	if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev)
+		atomic_set(&lis3_dev.wake_thread, 1);
+	/*
+	 * Update coordinates for the case where poll interval is 0 and
+	 * the chip in running purely under interrupt control
+	 */
+	lis3lv02d_joystick_poll(pidev);
+}
+
+static void lis3lv02d_joystick_close(struct input_polled_dev *pidev)
+{
+	atomic_set(&lis3_dev.wake_thread, 0);
+	if (lis3_dev.pm_dev)
+		pm_runtime_put(lis3_dev.pm_dev);
+}
+
 static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 {
 	if (!test_bit(0, &lis3_dev.misc_opened))
@@ -277,8 +439,7 @@
 	wake_up_interruptible(&lis3_dev.misc_wait);
 	kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN);
 out:
-	if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev &&
-	    lis3_dev.idev->input->users)
+	if (atomic_read(&lis3_dev.wake_thread))
 		return IRQ_WAKE_THREAD;
 	return IRQ_HANDLED;
 }
@@ -309,44 +470,41 @@
 	mutex_unlock(&lis3->mutex);
 }
 
-static void lis302dl_interrupt_handle_ff_wu(struct lis3lv02d *lis3)
+static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index)
 {
-	u8 wu1_src;
-	u8 wu2_src;
-
-	lis3->read(lis3, FF_WU_SRC_1, &wu1_src);
-	lis3->read(lis3, FF_WU_SRC_2, &wu2_src);
-
-	wu1_src = wu1_src & FF_WU_SRC_IA ? wu1_src : 0;
-	wu2_src = wu2_src & FF_WU_SRC_IA ? wu2_src : 0;
+	int dummy;
 
-	/* joystick poll is internally protected by the lis3->mutex. */
-	if (wu1_src || wu2_src)
-		lis3lv02d_joystick_poll(lis3_dev.idev);
+	/* Dummy read to ack interrupt */
+	lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy);
+	lis3->data_ready_count[index]++;
 }
 
 static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data)
 {
-
 	struct lis3lv02d *lis3 = data;
+	u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK;
 
-	if ((lis3->pdata->irq_cfg & LIS3_IRQ1_MASK) == LIS3_IRQ1_CLICK)
+	if (irq_cfg == LIS3_IRQ1_CLICK)
 		lis302dl_interrupt_handle_click(lis3);
+	else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY))
+		lis302dl_data_ready(lis3, IRQ_LINE0);
 	else
-		lis302dl_interrupt_handle_ff_wu(lis3);
+		lis3lv02d_joystick_poll(lis3->idev);
 
 	return IRQ_HANDLED;
 }
 
 static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data)
 {
-
 	struct lis3lv02d *lis3 = data;
+	u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK;
 
-	if ((lis3->pdata->irq_cfg & LIS3_IRQ2_MASK) == LIS3_IRQ2_CLICK)
+	if (irq_cfg == LIS3_IRQ2_CLICK)
 		lis302dl_interrupt_handle_click(lis3);
+	else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY))
+		lis302dl_data_ready(lis3, IRQ_LINE1);
 	else
-		lis302dl_interrupt_handle_ff_wu(lis3);
+		lis3lv02d_joystick_poll(lis3->idev);
 
 	return IRQ_HANDLED;
 }
@@ -356,6 +514,9 @@
 	if (test_and_set_bit(0, &lis3_dev.misc_opened))
 		return -EBUSY; /* already open */
 
+	if (lis3_dev.pm_dev)
+		pm_runtime_get_sync(lis3_dev.pm_dev);
+
 	atomic_set(&lis3_dev.count, 0);
 	return 0;
 }
@@ -364,6 +525,8 @@
 {
 	fasync_helper(-1, file, 0, &lis3_dev.async_queue);
 	clear_bit(0, &lis3_dev.misc_opened); /* release the device */
+	if (lis3_dev.pm_dev)
+		pm_runtime_put(lis3_dev.pm_dev);
 	return 0;
 }
 
@@ -460,6 +623,8 @@
 		return -ENOMEM;
 
 	lis3_dev.idev->poll = lis3lv02d_joystick_poll;
+	lis3_dev.idev->open = lis3lv02d_joystick_open;
+	lis3_dev.idev->close = lis3lv02d_joystick_close;
 	lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
 	lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN;
 	lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX;
@@ -473,8 +638,16 @@
 
 	set_bit(EV_ABS, input_dev->evbit);
 	max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY;
-	fuzz = (LIS3_DEFAULT_FUZZ * lis3_dev.scale) / LIS3_ACCURACY;
-	flat = (LIS3_DEFAULT_FLAT * lis3_dev.scale) / LIS3_ACCURACY;
+	if (lis3_dev.whoami == WAI_12B) {
+		fuzz = LIS3_DEFAULT_FUZZ_12B;
+		flat = LIS3_DEFAULT_FLAT_12B;
+	} else {
+		fuzz = LIS3_DEFAULT_FUZZ_8B;
+		flat = LIS3_DEFAULT_FLAT_8B;
+	}
+	fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY;
+	flat = (flat * lis3_dev.scale) / LIS3_ACCURACY;
+
 	input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat);
 	input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat);
 	input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat);
@@ -512,14 +685,47 @@
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
 
 /* Sysfs stuff */
+static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3)
+{
+	/*
+	 * SYSFS functions are fast visitors so put-call
+	 * immediately after the get-call. However, keep
+	 * chip running for a while and schedule delayed
+	 * suspend. This way periodic sysfs calls doesn't
+	 * suffer from relatively long power up time.
+	 */
+
+	if (lis3->pm_dev) {
+		pm_runtime_get_sync(lis3->pm_dev);
+		pm_runtime_put_noidle(lis3->pm_dev);
+		pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY);
+	}
+}
+
 static ssize_t lis3lv02d_selftest_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	int result;
 	s16 values[3];
 
-	result = lis3lv02d_selftest(&lis3_dev, values);
-	return sprintf(buf, "%s %d %d %d\n", result == 0 ? "OK" : "FAIL",
+	static const char ok[] = "OK";
+	static const char fail[] = "FAIL";
+	static const char irq[] = "FAIL_IRQ";
+	const char *res;
+
+	lis3lv02d_sysfs_poweron(&lis3_dev);
+	switch (lis3lv02d_selftest(&lis3_dev, values)) {
+	case SELFTEST_FAIL:
+		res = fail;
+		break;
+	case SELFTEST_IRQ:
+		res = irq;
+		break;
+	case SELFTEST_OK:
+	default:
+		res = ok;
+		break;
+	}
+	return sprintf(buf, "%s %d %d %d\n", res,
 		values[0], values[1], values[2]);
 }
 
@@ -528,6 +734,7 @@
 {
 	int x, y, z;
 
+	lis3lv02d_sysfs_poweron(&lis3_dev);
 	mutex_lock(&lis3_dev.mutex);
 	lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
 	mutex_unlock(&lis3_dev.mutex);
@@ -537,6 +744,7 @@
 static ssize_t lis3lv02d_rate_show(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
+	lis3lv02d_sysfs_poweron(&lis3_dev);
 	return sprintf(buf, "%d\n", lis3lv02d_get_odr());
 }
 
@@ -549,6 +757,7 @@
 	if (strict_strtoul(buf, 0, &rate))
 		return -EINVAL;
 
+	lis3lv02d_sysfs_poweron(&lis3_dev);
 	if (lis3lv02d_set_odr(rate))
 		return -EINVAL;
 
@@ -585,6 +794,18 @@
 {
 	sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
 	platform_device_unregister(lis3->pdev);
+	if (lis3->pm_dev) {
+		/* Barrier after the sysfs remove */
+		pm_runtime_barrier(lis3->pm_dev);
+
+		/* SYSFS may have left chip running. Turn off if necessary */
+		if (!pm_runtime_suspended(lis3->pm_dev))
+			lis3lv02d_poweroff(&lis3_dev);
+
+		pm_runtime_disable(lis3->pm_dev);
+		pm_runtime_set_suspended(lis3->pm_dev);
+	}
+	kfree(lis3->reg_cache);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
@@ -616,16 +837,16 @@
 	if (p->wakeup_flags) {
 		dev->write(dev, FF_WU_CFG_1, p->wakeup_flags);
 		dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f);
-		/* default to 2.5ms for now */
-		dev->write(dev, FF_WU_DURATION_1, 1);
+		/* pdata value + 1 to keep this backward compatible*/
+		dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1);
 		ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/
 	}
 
 	if (p->wakeup_flags2) {
 		dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2);
 		dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f);
-		/* default to 2.5ms for now */
-		dev->write(dev, FF_WU_DURATION_2, 1);
+		/* pdata value + 1 to keep this backward compatible*/
+		dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1);
 		ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/
 	}
 	/* Configure hipass filters */
@@ -635,8 +856,8 @@
 		err = request_threaded_irq(p->irq2,
 					NULL,
 					lis302dl_interrupt_thread2_8b,
-					IRQF_TRIGGER_RISING |
-					IRQF_ONESHOT,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+					(p->irq_flags2 & IRQF_TRIGGER_MASK),
 					DRIVER_NAME, &lis3_dev);
 		if (err < 0)
 			printk(KERN_ERR DRIVER_NAME
@@ -652,6 +873,7 @@
 {
 	int err;
 	irq_handler_t thread_fn;
+	int irq_flags = 0;
 
 	dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I);
 
@@ -664,6 +886,8 @@
 		dev->odrs = lis3_12_rates;
 		dev->odr_mask = CTRL1_DF0 | CTRL1_DF1;
 		dev->scale = LIS3_SENSITIVITY_12B;
+		dev->regs = lis3_wai12_regs;
+		dev->regs_size = ARRAY_SIZE(lis3_wai12_regs);
 		break;
 	case WAI_8B:
 		printk(KERN_INFO DRIVER_NAME ": 8 bits sensor found\n");
@@ -673,6 +897,17 @@
 		dev->odrs = lis3_8_rates;
 		dev->odr_mask = CTRL1_DR;
 		dev->scale = LIS3_SENSITIVITY_8B;
+		dev->regs = lis3_wai8_regs;
+		dev->regs_size = ARRAY_SIZE(lis3_wai8_regs);
+		break;
+	case WAI_3DC:
+		printk(KERN_INFO DRIVER_NAME ": 8 bits 3DC sensor found\n");
+		dev->read_data = lis3lv02d_read_8;
+		dev->mdps_max_val = 128;
+		dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
+		dev->odrs = lis3_3dc_rates;
+		dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
+		dev->scale = LIS3_SENSITIVITY_8B;
 		break;
 	default:
 		printk(KERN_ERR DRIVER_NAME
@@ -680,11 +915,25 @@
 		return -EINVAL;
 	}
 
+	dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs),
+				     sizeof(lis3_wai12_regs)), GFP_KERNEL);
+
+	if (dev->reg_cache == NULL) {
+		printk(KERN_ERR DRIVER_NAME "out of memory\n");
+		return -ENOMEM;
+	}
+
 	mutex_init(&dev->mutex);
+	atomic_set(&dev->wake_thread, 0);
 
 	lis3lv02d_add_fs(dev);
 	lis3lv02d_poweron(dev);
 
+	if (dev->pm_dev) {
+		pm_runtime_set_active(dev->pm_dev);
+		pm_runtime_enable(dev->pm_dev);
+	}
+
 	if (lis3lv02d_joystick_enable())
 		printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
 
@@ -696,8 +945,14 @@
 		if (dev->whoami == WAI_8B)
 			lis3lv02d_8b_configure(dev, p);
 
+		irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK;
+
+		dev->irq_cfg = p->irq_cfg;
 		if (p->irq_cfg)
 			dev->write(dev, CTRL_REG3, p->irq_cfg);
+
+		if (p->default_rate)
+			lis3lv02d_set_odr(p->default_rate);
 	}
 
 	/* bail if we did not get an IRQ from the bus layer */
@@ -725,7 +980,8 @@
 
 	err = request_threaded_irq(dev->irq, lis302dl_interrupt,
 				thread_fn,
-				IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+				IRQF_TRIGGER_RISING | IRQF_ONESHOT |
+				irq_flags,
 				DRIVER_NAME, &lis3_dev);
 
 	if (err < 0) {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d.h linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d.h
--- linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d.h	2011-01-04 19:50:19.000000000 -0500
@@ -20,6 +20,7 @@
  */
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
+#include <linux/regulator/consumer.h>
 
 /*
  * This driver tries to support the "digital" accelerometer chips from
@@ -45,6 +46,7 @@
 	CTRL_REG1	= 0x20,
 	CTRL_REG2	= 0x21,
 	CTRL_REG3	= 0x22,
+	CTRL_REG4	= 0x23,
 	HP_FILTER_RESET	= 0x23,
 	STATUS_REG	= 0x27,
 	OUTX_L		= 0x28,
@@ -93,6 +95,7 @@
 };
 
 enum lis3_who_am_i {
+	WAI_3DC		= 0x33,	/* 8 bits: LIS3DC, HP3DC */
 	WAI_12B		= 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
 	WAI_8B		= 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
 	WAI_6B		= 0x52, /* 6 bits: LIS331DLF - not supported */
@@ -118,6 +121,13 @@
 	CTRL1_DR	= 0x80,
 };
 
+enum lis3lv02d_ctrl1_3dc {
+	CTRL1_ODR0	= 0x10,
+	CTRL1_ODR1	= 0x20,
+	CTRL1_ODR2	= 0x40,
+	CTRL1_ODR3	= 0x80,
+};
+
 enum lis3lv02d_ctrl2 {
 	CTRL2_DAS	= 0x01,
 	CTRL2_SIM	= 0x02,
@@ -129,9 +139,18 @@
 	CTRL2_FS	= 0x80, /* Full Scale selection */
 };
 
+enum lis3lv02d_ctrl4_3dc {
+	CTRL4_SIM	= 0x01,
+	CTRL4_ST0	= 0x02,
+	CTRL4_ST1	= 0x04,
+	CTRL4_FS0	= 0x10,
+	CTRL4_FS1	= 0x20,
+};
+
 enum lis302d_ctrl2 {
 	HP_FF_WU2	= 0x08,
 	HP_FF_WU1	= 0x04,
+	CTRL2_BOOT_8B   = 0x40,
 };
 
 enum lis3lv02d_ctrl3 {
@@ -206,19 +225,33 @@
 	CLICK_IA	= 0x40,
 };
 
-struct axis_conversion {
-	s8	x;
-	s8	y;
-	s8	z;
+enum lis3lv02d_reg_state {
+	LIS3_REG_OFF	= 0x00,
+	LIS3_REG_ON	= 0x01,
+};
+
+union axis_conversion {
+	struct {
+		int x, y, z;
+	};
+	int as_array[3];
+
 };
 
 struct lis3lv02d {
 	void			*bus_priv; /* used by the bus layer only */
+	struct device		*pm_dev; /* for pm_runtime purposes */
 	int (*init) (struct lis3lv02d *lis3);
 	int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
 	int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
+	int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
+	int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
 
 	int                     *odrs;     /* Supported output data rates */
+	u8			*regs;	   /* Regs to store / restore */
+	int			regs_size;
+	u8                      *reg_cache;
+	bool			regs_stored;
 	u8                      odr_mask;  /* ODR bit mask */
 	u8			whoami;    /* indicates measurement precision */
 	s16 (*read_data) (struct lis3lv02d *lis3, int reg);
@@ -231,14 +264,18 @@
 
 	struct input_polled_dev	*idev;     /* input device */
 	struct platform_device	*pdev;     /* platform device */
+	struct regulator_bulk_data regulators[2];
 	atomic_t		count;     /* interrupt count after last read */
-	struct axis_conversion	ac;        /* hw -> logical axis */
+	union axis_conversion	ac;        /* hw -> logical axis */
 	int			mapped_btns[3];
 
 	u32			irq;       /* IRQ number */
 	struct fasync_struct	*async_queue; /* queue for the misc device */
 	wait_queue_head_t	misc_wait; /* Wait queue for the misc device */
 	unsigned long		misc_opened; /* bit0: whether the device is open */
+	int                     data_ready_count[2];
+	atomic_t		wake_thread;
+	unsigned char           irq_cfg;
 
 	struct lis3lv02d_platform_data *pdata;	/* for passing board config */
 	struct mutex		mutex;     /* Serialize poll and selftest */
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d_i2c.c linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d_i2c.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d_i2c.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d_i2c.c	2011-01-04 19:50:19.000000000 -0500
@@ -29,10 +29,30 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
 #include "lis3lv02d.h"
 
 #define DRV_NAME 	"lis3lv02d_i2c"
 
+static const char reg_vdd[]    = "Vdd";
+static const char reg_vdd_io[] = "Vdd_IO";
+
+static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
+{
+	int ret;
+	if (state == LIS3_REG_OFF) {
+		ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
+					lis3->regulators);
+	} else {
+		ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
+					lis3->regulators);
+		/* Chip needs time to wakeup. Not mentioned in datasheet */
+		usleep_range(10000, 20000);
+	}
+	return ret;
+}
+
 static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
 {
 	struct i2c_client *c = lis3->bus_priv;
@@ -46,24 +66,38 @@
 	return 0;
 }
 
+static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
+				u8 *v)
+{
+	struct i2c_client *c = lis3->bus_priv;
+	reg |= (1 << 7); /* 7th bit enables address auto incrementation */
+	return i2c_smbus_read_i2c_block_data(c, reg, len, v);
+}
+
 static int lis3_i2c_init(struct lis3lv02d *lis3)
 {
 	u8 reg;
 	int ret;
 
+	if (lis3->reg_ctrl)
+		lis3_reg_ctrl(lis3, LIS3_REG_ON);
+
+	lis3->read(lis3, WHO_AM_I, &reg);
+	if (reg != lis3->whoami)
+		printk(KERN_ERR "lis3: power on failure\n");
+
 	/* power up the device */
 	ret = lis3->read(lis3, CTRL_REG1, &reg);
 	if (ret < 0)
 		return ret;
 
-	reg |= CTRL1_PD0;
+	reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
 	return lis3->write(lis3, CTRL_REG1, reg);
 }
 
 /* Default axis mapping but it can be overwritten by platform data */
-static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
-						     LIS3_DEV_Y,
-						     LIS3_DEV_Z };
+static union axis_conversion lis3lv02d_axis_map =
+	{ .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
 
 static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
@@ -72,6 +106,15 @@
 	struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
 
 	if (pdata) {
+		/* Regulator control is optional */
+		if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
+			lis3_dev.reg_ctrl = lis3_reg_ctrl;
+
+		if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
+			(i2c_check_functionality(client->adapter,
+						I2C_FUNC_SMBUS_I2C_BLOCK)))
+			lis3_dev.blkread  = lis3_i2c_blockread;
+
 		if (pdata->axis_x)
 			lis3lv02d_axis_map.x = pdata->axis_x;
 
@@ -88,6 +131,16 @@
 			goto fail;
 	}
 
+	if (lis3_dev.reg_ctrl) {
+		lis3_dev.regulators[0].supply = reg_vdd;
+		lis3_dev.regulators[1].supply = reg_vdd_io;
+		ret = regulator_bulk_get(&client->dev,
+					ARRAY_SIZE(lis3_dev.regulators),
+					lis3_dev.regulators);
+		if (ret < 0)
+			goto fail;
+	}
+
 	lis3_dev.pdata	  = pdata;
 	lis3_dev.bus_priv = client;
 	lis3_dev.init	  = lis3_i2c_init;
@@ -95,10 +148,24 @@
 	lis3_dev.write	  = lis3_i2c_write;
 	lis3_dev.irq	  = client->irq;
 	lis3_dev.ac	  = lis3lv02d_axis_map;
+	lis3_dev.pm_dev	  = &client->dev;
 
 	i2c_set_clientdata(client, &lis3_dev);
+
+	/* Provide power over the init call */
+	if (lis3_dev.reg_ctrl)
+		lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
+
 	ret = lis3lv02d_init_device(&lis3_dev);
+
+	if (lis3_dev.reg_ctrl)
+		lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
+
+	if (ret == 0)
+		return 0;
 fail:
+	if (pdata && pdata->release_resources)
+		pdata->release_resources();
 	return ret;
 }
 
@@ -111,14 +178,18 @@
 		pdata->release_resources();
 
 	lis3lv02d_joystick_disable();
-	lis3lv02d_poweroff(lis3);
+	lis3lv02d_remove_fs(&lis3_dev);
 
-	return lis3lv02d_remove_fs(&lis3_dev);
+	if (lis3_dev.reg_ctrl)
+		regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
+				lis3_dev.regulators);
+	return 0;
 }
 
-#ifdef CONFIG_PM
-static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int lis3lv02d_i2c_suspend(struct device *dev)
 {
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 	struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
 	if (!lis3->pdata || !lis3->pdata->wakeup_flags)
@@ -126,24 +197,43 @@
 	return 0;
 }
 
-static int lis3lv02d_i2c_resume(struct i2c_client *client)
+static int lis3lv02d_i2c_resume(struct device *dev)
 {
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
 	struct lis3lv02d *lis3 = i2c_get_clientdata(client);
 
-	if (!lis3->pdata || !lis3->pdata->wakeup_flags)
+	/*
+	 * pm_runtime documentation says that devices should always
+	 * be powered on at resume. Pm_runtime turns them off after system
+	 * wide resume is complete.
+	 */
+	if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
+		pm_runtime_suspended(dev))
 		lis3lv02d_poweron(lis3);
+
 	return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
-static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
+#ifdef CONFIG_PM_RUNTIME
+static int lis3_i2c_runtime_suspend(struct device *dev)
 {
-	lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+	lis3lv02d_poweroff(lis3);
+	return 0;
 }
-#else
-#define lis3lv02d_i2c_suspend	NULL
-#define lis3lv02d_i2c_resume	NULL
-#define lis3lv02d_i2c_shutdown	NULL
-#endif
+
+static int lis3_i2c_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct lis3lv02d *lis3 = i2c_get_clientdata(client);
+
+	lis3lv02d_poweron(lis3);
+	return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
 
 static const struct i2c_device_id lis3lv02d_id[] = {
 	{"lis3lv02d", 0 },
@@ -152,14 +242,20 @@
 
 MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
 
+static const struct dev_pm_ops lis3_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
+				lis3lv02d_i2c_resume)
+	SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
+			   lis3_i2c_runtime_resume,
+			   NULL)
+};
+
 static struct i2c_driver lis3lv02d_i2c_driver = {
 	.driver	 = {
 		.name   = DRV_NAME,
 		.owner  = THIS_MODULE,
+		.pm     = &lis3_pm_ops,
 	},
-	.suspend = lis3lv02d_i2c_suspend,
-	.shutdown = lis3lv02d_i2c_shutdown,
-	.resume = lis3lv02d_i2c_resume,
 	.probe	= lis3lv02d_i2c_probe,
 	.remove	= __devexit_p(lis3lv02d_i2c_remove),
 	.id_table = lis3lv02d_id,
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d_spi.c linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d_spi.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lis3lv02d_spi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lis3lv02d_spi.c	2011-01-04 19:50:19.000000000 -0500
@@ -50,11 +50,12 @@
 	if (ret < 0)
 		return ret;
 
-	reg |= CTRL1_PD0;
+	reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
 	return lis3->write(lis3, CTRL_REG1, reg);
 }
 
-static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
+static union axis_conversion lis3lv02d_axis_normal =
+	{ .as_array = { 1, 2, 3 } };
 
 static int __devinit lis302dl_spi_probe(struct spi_device *spi)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lm75.c linux-libre-2.6.37-gnu/drivers/hwmon/lm75.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lm75.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lm75.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,22 +1,22 @@
 /*
-    lm75.c - Part of lm_sensors, Linux kernel modules for hardware
-             monitoring
-    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
+ * lm75.c - Part of lm_sensors, Linux kernel modules for hardware
+ *	 monitoring
+ * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -103,7 +103,12 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm75_data *data = i2c_get_clientdata(client);
 	int nr = attr->index;
-	long temp = simple_strtol(buf, NULL, 10);
+	long temp;
+	int error;
+
+	error = strict_strtol(buf, 10, &temp);
+	if (error)
+		return error;
 
 	mutex_lock(&data->update_lock);
 	data->temp[nr] = LM75_TEMP_TO_REG(temp);
@@ -335,9 +340,11 @@
 
 /* register access */
 
-/* All registers are word-sized, except for the configuration register.
-   LM75 uses a high-byte first convention, which is exactly opposite to
-   the SMBus standard. */
+/*
+ * All registers are word-sized, except for the configuration register.
+ * LM75 uses a high-byte first convention, which is exactly opposite to
+ * the SMBus standard.
+ */
 static int lm75_read_value(struct i2c_client *client, u8 reg)
 {
 	int value;
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lm85.c linux-libre-2.6.37-gnu/drivers/hwmon/lm85.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lm85.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lm85.c	2011-01-04 19:50:19.000000000 -0500
@@ -64,9 +64,12 @@
 #define	LM85_REG_VERSTEP		0x3f
 
 #define	ADT7468_REG_CFG5		0x7c
-#define		ADT7468_OFF64		0x01
+#define		ADT7468_OFF64		(1 << 0)
+#define		ADT7468_HFPWM		(1 << 1)
 #define	IS_ADT7468_OFF64(data)		\
 	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_OFF64))
+#define	IS_ADT7468_HFPWM(data)		\
+	((data)->type == adt7468 && !((data)->cfg5 & ADT7468_HFPWM))
 
 /* These are the recognized values for the above regs */
 #define	LM85_COMPANY_NATIONAL		0x01
@@ -567,8 +570,14 @@
 {
 	int nr = to_sensor_dev_attr(attr)->index;
 	struct lm85_data *data = lm85_update_device(dev);
-	return sprintf(buf, "%d\n", FREQ_FROM_REG(data->freq_map,
-						  data->pwm_freq[nr]));
+	int freq;
+
+	if (IS_ADT7468_HFPWM(data))
+		freq = 22500;
+	else
+		freq = FREQ_FROM_REG(data->freq_map, data->pwm_freq[nr]);
+
+	return sprintf(buf, "%d\n", freq);
 }
 
 static ssize_t set_pwm_freq(struct device *dev,
@@ -580,10 +589,22 @@
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
-	data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
-	lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
-		(data->zone[nr].range << 4)
-		| data->pwm_freq[nr]);
+	/* The ADT7468 has a special high-frequency PWM output mode,
+	 * where all PWM outputs are driven by a 22.5 kHz clock.
+	 * This might confuse the user, but there's not much we can do. */
+	if (data->type == adt7468 && val >= 11300) {	/* High freq. mode */
+		data->cfg5 &= ~ADT7468_HFPWM;
+		lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+	} else {					/* Low freq. mode */
+		data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
+		lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
+				 (data->zone[nr].range << 4)
+				 | data->pwm_freq[nr]);
+		if (data->type == adt7468) {
+			data->cfg5 |= ADT7468_HFPWM;
+			lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
+		}
+	}
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1259,6 +1280,7 @@
 	switch (data->type) {
 	case adm1027:
 	case adt7463:
+	case adt7468:
 	case emc6d100:
 	case emc6d102:
 		data->freq_map = adm1027_freq_map;
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lm90.c linux-libre-2.6.37-gnu/drivers/hwmon/lm90.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lm90.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lm90.c	2011-01-04 19:50:19.000000000 -0500
@@ -28,9 +28,11 @@
  * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor
  * chips made by Maxim. These chips are similar to the LM86.
  * Note that there is no easy way to differentiate between the three
- * variants. The extra address and features of the MAX6659 are not
- * supported by this driver. These chips lack the remote temperature
- * offset feature.
+ * variants. We use the device address to detect MAX6659, which will result
+ * in a detection as max6657 if it is on address 0x4c. The extra address
+ * and features of the MAX6659 are only supported if the chip is configured
+ * explicitly as max6659, or if its address is not 0x4c.
+ * These chips lack the remote temperature offset feature.
  *
  * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
  * MAX6692 chips made by Maxim.  These are again similar to the LM86,
@@ -42,6 +44,11 @@
  * chips. The MAX6680 and MAX6681 only differ in the pinout so they can
  * be treated identically.
  *
+ * This driver also supports the MAX6695 and MAX6696, two other sensor
+ * chips made by Maxim. These are also quite similar to other Maxim
+ * chips, but support three temperature sensors instead of two. MAX6695
+ * and MAX6696 only differ in the pinout so they can be treated identically.
+ *
  * This driver also supports the ADT7461 chip from Analog Devices.
  * It's supported in both compatibility and extended mode. It is mostly
  * compatible with LM90 except for a data format difference for the
@@ -81,11 +88,11 @@
  * Addresses to scan
  * Address is fully defined internally and cannot be changed except for
  * MAX6659, MAX6680 and MAX6681.
- * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657
- * and MAX6658 have address 0x4c.
+ * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657,
+ * MAX6658 and W83L771 have address 0x4c.
  * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d.
  * MAX6647 has address 0x4e.
- * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * MAX6659 can have address 0x4c, 0x4d or 0x4e.
  * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
  * 0x4c, 0x4d or 0x4e.
  */
@@ -93,8 +100,8 @@
 static const unsigned short normal_i2c[] = {
 	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
 
-enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646,
-	w83l771 };
+enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
+	max6646, w83l771, max6696 };
 
 /*
  * The LM90 registers
@@ -135,26 +142,30 @@
 #define LM90_REG_R_TCRIT_HYST		0x21
 #define LM90_REG_W_TCRIT_HYST		0x21
 
-/* MAX6646/6647/6649/6657/6658/6659 registers */
+/* MAX6646/6647/6649/6657/6658/6659/6695/6696 registers */
 
 #define MAX6657_REG_R_LOCAL_TEMPL	0x11
+#define MAX6696_REG_R_STATUS2		0x12
+#define MAX6659_REG_R_REMOTE_EMERG	0x16
+#define MAX6659_REG_W_REMOTE_EMERG	0x16
+#define MAX6659_REG_R_LOCAL_EMERG	0x17
+#define MAX6659_REG_W_LOCAL_EMERG	0x17
 
-/*
- * Device flags
- */
-#define LM90_FLAG_ADT7461_EXT		0x01	/* ADT7461 extended mode */
+#define LM90_DEF_CONVRATE_RVAL	6	/* Def conversion rate register value */
+#define LM90_MAX_CONVRATE_MS	16000	/* Maximum conversion rate in ms */
 
 /*
- * Functions declaration
+ * Device flags
  */
-
-static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info);
-static int lm90_probe(struct i2c_client *client,
-		      const struct i2c_device_id *id);
-static void lm90_init_client(struct i2c_client *client);
-static void lm90_alert(struct i2c_client *client, unsigned int flag);
-static int lm90_remove(struct i2c_client *client);
-static struct lm90_data *lm90_update_device(struct device *dev);
+#define LM90_FLAG_ADT7461_EXT	(1 << 0) /* ADT7461 extended mode	*/
+/* Device features */
+#define LM90_HAVE_OFFSET	(1 << 1) /* temperature offset register	*/
+#define LM90_HAVE_LOCAL_EXT	(1 << 2) /* extended local temperature	*/
+#define LM90_HAVE_REM_LIMIT_EXT	(1 << 3) /* extended remote limit	*/
+#define LM90_HAVE_EMERGENCY	(1 << 4) /* 3rd upper (emergency) limit	*/
+#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
+#define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
+#define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
 
 /*
  * Driver data (common to all clients)
@@ -172,25 +183,85 @@
 	{ "max6649", max6646 },
 	{ "max6657", max6657 },
 	{ "max6658", max6657 },
-	{ "max6659", max6657 },
+	{ "max6659", max6659 },
 	{ "max6680", max6680 },
 	{ "max6681", max6680 },
+	{ "max6695", max6696 },
+	{ "max6696", max6696 },
 	{ "w83l771", w83l771 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, lm90_id);
 
-static struct i2c_driver lm90_driver = {
-	.class		= I2C_CLASS_HWMON,
-	.driver = {
-		.name	= "lm90",
+/*
+ * chip type specific parameters
+ */
+struct lm90_params {
+	u32 flags;		/* Capabilities */
+	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
+				/* Upper 8 bits for max6695/96 */
+	u8 max_convrate;	/* Maximum conversion rate register value */
+};
+
+static const struct lm90_params lm90_params[] = {
+	[adm1032] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 10,
+	},
+	[adt7461] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
+		  | LM90_HAVE_BROKEN_ALERT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 10,
+	},
+	[lm86] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[lm90] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[lm99] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7b,
+		.max_convrate = 9,
+	},
+	[max6646] = {
+		.flags = LM90_HAVE_LOCAL_EXT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 6,
+	},
+	[max6657] = {
+		.flags = LM90_HAVE_LOCAL_EXT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+	},
+	[max6659] = {
+		.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
+	},
+	[max6680] = {
+		.flags = LM90_HAVE_OFFSET,
+		.alert_alarms = 0x7c,
+		.max_convrate = 7,
+	},
+	[max6696] = {
+		.flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY
+		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3,
+		.alert_alarms = 0x187c,
+		.max_convrate = 6,
+	},
+	[w83l771] = {
+		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
+		.alert_alarms = 0x7c,
+		.max_convrate = 8,
 	},
-	.probe		= lm90_probe,
-	.remove		= lm90_remove,
-	.alert		= lm90_alert,
-	.id_table	= lm90_id,
-	.detect		= lm90_detect,
-	.address_list	= normal_i2c,
 };
 
 /*
@@ -203,26 +274,268 @@
 	char valid; /* zero until following fields are valid */
 	unsigned long last_updated; /* in jiffies */
 	int kind;
-	int flags;
+	u32 flags;
+
+	int update_interval;	/* in milliseconds */
 
 	u8 config_orig;		/* Original configuration register value */
-	u8 alert_alarms;	/* Which alarm bits trigger ALERT# */
+	u8 convrate_orig;	/* Original conversion rate register value */
+	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
+				/* Upper 8 bits for max6695/96 */
+	u8 max_convrate;	/* Maximum conversion rate */
 
 	/* registers values */
-	s8 temp8[4];	/* 0: local low limit
+	s8 temp8[8];	/* 0: local low limit
 			   1: local high limit
 			   2: local critical limit
-			   3: remote critical limit */
-	s16 temp11[5];	/* 0: remote input
+			   3: remote critical limit
+			   4: local emergency limit (max6659 and max6695/96)
+			   5: remote emergency limit (max6659 and max6695/96)
+			   6: remote 2 critical limit (max6695/96 only)
+			   7: remote 2 emergency limit (max6695/96 only) */
+	s16 temp11[8];	/* 0: remote input
 			   1: remote low limit
 			   2: remote high limit
-			   3: remote offset (except max6646 and max6657)
-			   4: local input */
+			   3: remote offset (except max6646, max6657/58/59,
+					     and max6695/96)
+			   4: local input
+			   5: remote 2 input (max6695/96 only)
+			   6: remote 2 low limit (max6695/96 only)
+			   7: remote 2 high limit (ma6695/96 only) */
 	u8 temp_hyst;
-	u8 alarms; /* bitvector */
+	u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
 };
 
 /*
+ * Support functions
+ */
+
+/*
+ * The ADM1032 supports PEC but not on write byte transactions, so we need
+ * to explicitly ask for a transaction without PEC.
+ */
+static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
+{
+	return i2c_smbus_xfer(client->adapter, client->addr,
+			      client->flags & ~I2C_CLIENT_PEC,
+			      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+
+/*
+ * It is assumed that client->update_lock is held (unless we are in
+ * detection or initialization steps). This matters when PEC is enabled,
+ * because we don't want the address pointer to change between the write
+ * byte and the read byte transactions.
+ */
+static int lm90_read_reg(struct i2c_client *client, u8 reg, u8 *value)
+{
+	int err;
+
+	if (client->flags & I2C_CLIENT_PEC) {
+		err = adm1032_write_byte(client, reg);
+		if (err >= 0)
+			err = i2c_smbus_read_byte(client);
+	} else
+		err = i2c_smbus_read_byte_data(client, reg);
+
+	if (err < 0) {
+		dev_warn(&client->dev, "Register %#02x read failed (%d)\n",
+			 reg, err);
+		return err;
+	}
+	*value = err;
+
+	return 0;
+}
+
+static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
+{
+	int err;
+	u8 oldh, newh, l;
+
+	/*
+	 * There is a trick here. We have to read two registers to have the
+	 * sensor temperature, but we have to beware a conversion could occur
+	 * inbetween the readings. The datasheet says we should either use
+	 * the one-shot conversion register, which we don't want to do
+	 * (disables hardware monitoring) or monitor the busy bit, which is
+	 * impossible (we can't read the values and monitor that bit at the
+	 * exact same time). So the solution used here is to read the high
+	 * byte once, then the low byte, then the high byte again. If the new
+	 * high byte matches the old one, then we have a valid reading. Else
+	 * we have to read the low byte again, and now we believe we have a
+	 * correct reading.
+	 */
+	if ((err = lm90_read_reg(client, regh, &oldh))
+	 || (err = lm90_read_reg(client, regl, &l))
+	 || (err = lm90_read_reg(client, regh, &newh)))
+		return err;
+	if (oldh != newh) {
+		err = lm90_read_reg(client, regl, &l);
+		if (err)
+			return err;
+	}
+	*value = (newh << 8) | l;
+
+	return 0;
+}
+
+/*
+ * client->update_lock must be held when calling this function (unless we are
+ * in detection or initialization steps), and while a remote channel other
+ * than channel 0 is selected. Also, calling code must make sure to re-select
+ * external channel 0 before releasing the lock. This is necessary because
+ * various registers have different meanings as a result of selecting a
+ * non-default remote channel.
+ */
+static inline void lm90_select_remote_channel(struct i2c_client *client,
+					      struct lm90_data *data,
+					      int channel)
+{
+	u8 config;
+
+	if (data->kind == max6696) {
+		lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+		config &= ~0x08;
+		if (channel)
+			config |= 0x08;
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+					  config);
+	}
+}
+
+/*
+ * Set conversion rate.
+ * client->update_lock must be held when calling this function (unless we are
+ * in detection or initialization steps).
+ */
+static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
+			      unsigned int interval)
+{
+	int i;
+	unsigned int update_interval;
+
+	/* Shift calculations to avoid rounding errors */
+	interval <<= 6;
+
+	/* find the nearest update rate */
+	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
+	     i < data->max_convrate; i++, update_interval >>= 1)
+		if (interval >= update_interval * 3 / 4)
+			break;
+
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
+	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
+}
+
+static struct lm90_data *lm90_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm90_data *data = i2c_get_clientdata(client);
+	unsigned long next_update;
+
+	mutex_lock(&data->update_lock);
+
+	next_update = data->last_updated
+	  + msecs_to_jiffies(data->update_interval) + 1;
+	if (time_after(jiffies, next_update) || !data->valid) {
+		u8 h, l;
+		u8 alarms;
+
+		dev_dbg(&client->dev, "Updating lm90 data.\n");
+		lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[0]);
+		lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[1]);
+		lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[2]);
+		lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
+		lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
+
+		if (data->flags & LM90_HAVE_LOCAL_EXT) {
+			lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
+				    MAX6657_REG_R_LOCAL_TEMPL,
+				    &data->temp11[4]);
+		} else {
+			if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
+					  &h) == 0)
+				data->temp11[4] = h << 8;
+		}
+		lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
+			    LM90_REG_R_REMOTE_TEMPL, &data->temp11[0]);
+
+		if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) {
+			data->temp11[1] = h << 8;
+			if ((data->flags & LM90_HAVE_REM_LIMIT_EXT)
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL,
+					  &l) == 0)
+				data->temp11[1] |= l;
+		}
+		if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) {
+			data->temp11[2] = h << 8;
+			if ((data->flags & LM90_HAVE_REM_LIMIT_EXT)
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL,
+					  &l) == 0)
+				data->temp11[2] |= l;
+		}
+
+		if (data->flags & LM90_HAVE_OFFSET) {
+			if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+					  &h) == 0
+			 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+					  &l) == 0)
+				data->temp11[3] = (h << 8) | l;
+		}
+		if (data->flags & LM90_HAVE_EMERGENCY) {
+			lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG,
+				      &data->temp8[4]);
+			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
+				      &data->temp8[5]);
+		}
+		lm90_read_reg(client, LM90_REG_R_STATUS, &alarms);
+		data->alarms = alarms;	/* save as 16 bit value */
+
+		if (data->kind == max6696) {
+			lm90_select_remote_channel(client, data, 1);
+			lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT,
+				      &data->temp8[6]);
+			lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG,
+				      &data->temp8[7]);
+			lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
+				    LM90_REG_R_REMOTE_TEMPL, &data->temp11[5]);
+			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h))
+				data->temp11[6] = h << 8;
+			if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h))
+				data->temp11[7] = h << 8;
+			lm90_select_remote_channel(client, data, 0);
+
+			if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2,
+					   &alarms))
+				data->alarms |= alarms << 8;
+		}
+
+		/* Re-enable ALERT# output if it was originally enabled and
+		 * relevant alarms are all clear */
+		if ((data->config_orig & 0x80) == 0
+		 && (data->alarms & data->alert_alarms) == 0) {
+			u8 config;
+
+			lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
+			if (config & 0x80) {
+				dev_dbg(&client->dev, "Re-enabling ALERT#\n");
+				i2c_smbus_write_byte_data(client,
+							  LM90_REG_W_CONFIG1,
+							  config & ~0x80);
+			}
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/*
  * Conversions
  * For local temperatures and limits, critical limits and the hysteresis
  * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
@@ -377,18 +690,27 @@
 static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
 			 const char *buf, size_t count)
 {
-	static const u8 reg[4] = {
+	static const u8 reg[8] = {
 		LM90_REG_W_LOCAL_LOW,
 		LM90_REG_W_LOCAL_HIGH,
 		LM90_REG_W_LOCAL_CRIT,
 		LM90_REG_W_REMOTE_CRIT,
+		MAX6659_REG_W_LOCAL_EMERG,
+		MAX6659_REG_W_REMOTE_EMERG,
+		LM90_REG_W_REMOTE_CRIT,
+		MAX6659_REG_W_REMOTE_EMERG,
 	};
 
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
-	long val = simple_strtol(buf, NULL, 10);
 	int nr = attr->index;
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
 
 	/* +16 degrees offset for temp2 for the LM99 */
 	if (data->kind == lm99 && attr->index == 3)
@@ -401,7 +723,11 @@
 		data->temp8[nr] = temp_to_u8(val);
 	else
 		data->temp8[nr] = temp_to_s8(val);
+
+	lm90_select_remote_channel(client, data, nr >= 6);
 	i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]);
+	lm90_select_remote_channel(client, data, 0);
+
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -409,7 +735,7 @@
 static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
 			   char *buf)
 {
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 	struct lm90_data *data = lm90_update_device(dev);
 	int temp;
 
@@ -430,46 +756,58 @@
 static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
 			  const char *buf, size_t count)
 {
-	static const u8 reg[6] = {
-		LM90_REG_W_REMOTE_LOWH,
-		LM90_REG_W_REMOTE_LOWL,
-		LM90_REG_W_REMOTE_HIGHH,
-		LM90_REG_W_REMOTE_HIGHL,
-		LM90_REG_W_REMOTE_OFFSH,
-		LM90_REG_W_REMOTE_OFFSL,
+	struct {
+		u8 high;
+		u8 low;
+		int channel;
+	} reg[5] = {
+		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 0 },
+		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 0 },
+		{ LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL, 0 },
+		{ LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, 1 },
+		{ LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, 1 }
 	};
 
-	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
-	long val = simple_strtol(buf, NULL, 10);
-	int nr = attr->index;
+	int nr = attr->nr;
+	int index = attr->index;
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
 
 	/* +16 degrees offset for temp2 for the LM99 */
-	if (data->kind == lm99 && attr->index <= 2)
+	if (data->kind == lm99 && index <= 2)
 		val -= 16000;
 
 	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461)
-		data->temp11[nr] = temp_to_u16_adt7461(data, val);
-	else if (data->kind == max6657 || data->kind == max6680)
-		data->temp11[nr] = temp_to_s8(val) << 8;
+		data->temp11[index] = temp_to_u16_adt7461(data, val);
 	else if (data->kind == max6646)
-		data->temp11[nr] = temp_to_u8(val) << 8;
+		data->temp11[index] = temp_to_u8(val) << 8;
+	else if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+		data->temp11[index] = temp_to_s16(val);
 	else
-		data->temp11[nr] = temp_to_s16(val);
+		data->temp11[index] = temp_to_s8(val) << 8;
+
+	lm90_select_remote_channel(client, data, reg[nr].channel);
+	i2c_smbus_write_byte_data(client, reg[nr].high,
+				  data->temp11[index] >> 8);
+	if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
+		i2c_smbus_write_byte_data(client, reg[nr].low,
+					  data->temp11[index] & 0xff);
+	lm90_select_remote_channel(client, data, 0);
 
-	i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
-				  data->temp11[nr] >> 8);
-	if (data->kind != max6657 && data->kind != max6680
-	    && data->kind != max6646)
-		i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
-					  data->temp11[nr] & 0xff);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t show_temphyst(struct device *dev, struct device_attribute *devattr,
+static ssize_t show_temphyst(struct device *dev,
+			     struct device_attribute *devattr,
 			     char *buf)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -495,9 +833,14 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm90_data *data = i2c_get_clientdata(client);
-	long val = simple_strtol(buf, NULL, 10);
+	long val;
+	int err;
 	int temp;
 
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
+
 	mutex_lock(&data->update_lock);
 	if (data->kind == adt7461)
 		temp = temp_from_u8_adt7461(data, data->temp8[2]);
@@ -530,16 +873,44 @@
 	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
 }
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 4);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
+static ssize_t show_update_interval(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct lm90_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm90_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	int err;
+
+	err = strict_strtoul(buf, 10, &val);
+	if (err)
+		return err;
+
+	mutex_lock(&data->update_lock);
+	lm90_set_convrate(client, data, val);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0);
 static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
 	set_temp8, 0);
-static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 0, 1);
 static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8,
 	set_temp8, 1);
-static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 1, 2);
 static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8,
 	set_temp8, 2);
 static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
@@ -547,8 +918,8 @@
 static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
 	set_temphyst, 2);
 static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
-	set_temp11, 3);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 2, 3);
 
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
@@ -561,6 +932,9 @@
 /* Raw alarm file for compatibility */
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+		   set_update_interval);
+
 static struct attribute *lm90_attributes[] = {
 	&sensor_dev_attr_temp1_input.dev_attr.attr,
 	&sensor_dev_attr_temp2_input.dev_attr.attr,
@@ -581,6 +955,7 @@
 	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 	&dev_attr_alarms.attr,
+	&dev_attr_update_interval.attr,
 	NULL
 };
 
@@ -588,6 +963,86 @@
 	.attrs = lm90_attributes,
 };
 
+/*
+ * Additional attributes for devices with emergency sensors
+ */
+static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, 4);
+static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, 5);
+static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, 5);
+
+static struct attribute *lm90_emergency_attributes[] = {
+	&sensor_dev_attr_temp1_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency_hyst.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_emergency_group = {
+	.attrs = lm90_emergency_attributes,
+};
+
+static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(temp2_emergency_alarm, S_IRUGO, show_alarm, NULL, 13);
+
+static struct attribute *lm90_emergency_alarm_attributes[] = {
+	&sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_emergency_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_emergency_alarm_group = {
+	.attrs = lm90_emergency_alarm_attributes,
+};
+
+/*
+ * Additional attributes for devices with 3 temperature sensors
+ */
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL, 0, 5);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 3, 6);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp11,
+	set_temp11, 4, 7);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, 6);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8,
+	set_temp8, 7);
+static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO, show_temphyst,
+			  NULL, 7);
+
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_emergency_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+static struct attribute *lm90_temp3_attributes[] = {
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency_hyst.dev_attr.attr,
+
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp3_emergency_alarm.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group lm90_temp3_group = {
+	.attrs = lm90_temp3_attributes,
+};
+
 /* pec used for ADM1032 only */
 static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
 			char *buf)
@@ -600,7 +1055,12 @@
 		       const char *buf, size_t count)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	long val = simple_strtol(buf, NULL, 10);
+	long val;
+	int err;
+
+	err = strict_strtol(buf, 10, &val);
+	if (err < 0)
+		return err;
 
 	switch (val) {
 	case 0:
@@ -622,40 +1082,6 @@
  * Real code
  */
 
-/* The ADM1032 supports PEC but not on write byte transactions, so we need
-   to explicitly ask for a transaction without PEC. */
-static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
-{
-	return i2c_smbus_xfer(client->adapter, client->addr,
-			      client->flags & ~I2C_CLIENT_PEC,
-			      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
-}
-
-/* It is assumed that client->update_lock is held (unless we are in
-   detection or initialization steps). This matters when PEC is enabled,
-   because we don't want the address pointer to change between the write
-   byte and the read byte transactions. */
-static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value)
-{
-	int err;
-
- 	if (client->flags & I2C_CLIENT_PEC) {
- 		err = adm1032_write_byte(client, reg);
- 		if (err >= 0)
- 			err = i2c_smbus_read_byte(client);
- 	} else
- 		err = i2c_smbus_read_byte_data(client, reg);
-
-	if (err < 0) {
-		dev_warn(&client->dev, "Register %#02x read failed (%d)\n",
-			 reg, err);
-		return err;
-	}
-	*value = err;
-
-	return 0;
-}
-
 /* Return 0 if detection is successful, -ENODEV otherwise */
 static int lm90_detect(struct i2c_client *new_client,
 		       struct i2c_board_info *info)
@@ -730,6 +1156,23 @@
 		}
 	} else
 	if (man_id == 0x4D) { /* Maxim */
+		int reg_emerg, reg_emerg2, reg_status2;
+
+		/*
+		 * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read
+		 * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG
+		 * exists, both readings will reflect the same value. Otherwise,
+		 * the readings will be different.
+		 */
+		if ((reg_emerg = i2c_smbus_read_byte_data(new_client,
+						MAX6659_REG_R_REMOTE_EMERG)) < 0
+		 || i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID) < 0
+		 || (reg_emerg2 = i2c_smbus_read_byte_data(new_client,
+						MAX6659_REG_R_REMOTE_EMERG)) < 0
+		 || (reg_status2 = i2c_smbus_read_byte_data(new_client,
+						MAX6696_REG_R_STATUS2)) < 0)
+			return -ENODEV;
+
 		/*
 		 * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
 		 * register. Reading from that address will return the last
@@ -737,12 +1180,38 @@
 		 * register. Likewise, the config1 register seems to lack a
 		 * low nibble, so the value will be those of the previous
 		 * read, so in our case those of the man_id register.
+		 * MAX6659 has a third set of upper temperature limit registers.
+		 * Those registers also return values on MAX6657 and MAX6658,
+		 * thus the only way to detect MAX6659 is by its address.
+		 * For this reason it will be mis-detected as MAX6657 if its
+		 * address is 0x4C.
 		 */
 		if (chip_id == man_id
-		 && (address == 0x4C || address == 0x4D)
+		 && (address == 0x4C || address == 0x4D || address == 0x4E)
 		 && (reg_config1 & 0x1F) == (man_id & 0x0F)
 		 && reg_convrate <= 0x09) {
-			name = "max6657";
+			if (address == 0x4C)
+				name = "max6657";
+			else
+				name = "max6659";
+		} else
+		/*
+		 * Even though MAX6695 and MAX6696 do not have a chip ID
+		 * register, reading it returns 0x01. Bit 4 of the config1
+		 * register is unused and should return zero when read. Bit 0 of
+		 * the status2 register is unused and should return zero when
+		 * read.
+		 *
+		 * MAX6695 and MAX6696 have an additional set of temperature
+		 * limit registers. We can detect those chips by checking if
+		 * one of those registers exists.
+		 */
+		if (chip_id == 0x01
+		 && (reg_config1 & 0x10) == 0x00
+		 && (reg_status2 & 0x01) == 0x00
+		 && reg_emerg == reg_emerg2
+		 && reg_convrate <= 0x07) {
+			name = "max6696";
 		} else
 		/*
 		 * The chip_id register of the MAX6680 and MAX6681 holds the
@@ -768,10 +1237,23 @@
 	} else
 	if (address == 0x4C
 	 && man_id == 0x5C) { /* Winbond/Nuvoton */
-		if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
-		 && (reg_config1 & 0x2A) == 0x00
-		 && reg_convrate <= 0x08) {
-			name = "w83l771";
+		int reg_config2;
+
+		reg_config2 = i2c_smbus_read_byte_data(new_client,
+						LM90_REG_R_CONFIG2);
+		if (reg_config2 < 0)
+			return -ENODEV;
+
+		if ((reg_config1 & 0x2A) == 0x00
+		 && (reg_config2 & 0xF8) == 0x00) {
+			if (chip_id == 0x01 /* W83L771W/G */
+			 && reg_convrate <= 0x09) {
+				name = "w83l771";
+			} else
+			if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
+			 && reg_convrate <= 0x08) {
+				name = "w83l771";
+			}
 		}
 	}
 
@@ -787,6 +1269,69 @@
 	return 0;
 }
 
+static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data)
+{
+	if (data->flags & LM90_HAVE_TEMP3)
+		sysfs_remove_group(&client->dev.kobj, &lm90_temp3_group);
+	if (data->flags & LM90_HAVE_EMERGENCY_ALARM)
+		sysfs_remove_group(&client->dev.kobj,
+				   &lm90_emergency_alarm_group);
+	if (data->flags & LM90_HAVE_EMERGENCY)
+		sysfs_remove_group(&client->dev.kobj,
+				   &lm90_emergency_group);
+	if (data->flags & LM90_HAVE_OFFSET)
+		device_remove_file(&client->dev,
+				   &sensor_dev_attr_temp2_offset.dev_attr);
+	device_remove_file(&client->dev, &dev_attr_pec);
+	sysfs_remove_group(&client->dev.kobj, &lm90_group);
+}
+
+static void lm90_init_client(struct i2c_client *client)
+{
+	u8 config, convrate;
+	struct lm90_data *data = i2c_get_clientdata(client);
+
+	if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) {
+		dev_warn(&client->dev, "Failed to read convrate register!\n");
+		convrate = LM90_DEF_CONVRATE_RVAL;
+	}
+	data->convrate_orig = convrate;
+
+	/*
+	 * Start the conversions.
+	 */
+	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
+	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
+		dev_warn(&client->dev, "Initialization failed!\n");
+		return;
+	}
+	data->config_orig = config;
+
+	/* Check Temperature Range Select */
+	if (data->kind == adt7461) {
+		if (config & 0x04)
+			data->flags |= LM90_FLAG_ADT7461_EXT;
+	}
+
+	/*
+	 * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+	 * 0.125 degree resolution) and range (0x08, extend range
+	 * to -64 degree) mode for the remote temperature sensor.
+	 */
+	if (data->kind == max6680)
+		config |= 0x18;
+
+	/*
+	 * Select external channel 0 for max6695/96
+	 */
+	if (data->kind == max6696)
+		config &= ~0x08;
+
+	config &= 0xBF;	/* run */
+	if (config != data->config_orig) /* Only write if changed */
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+}
+
 static int lm90_probe(struct i2c_client *new_client,
 		      const struct i2c_device_id *id)
 {
@@ -811,31 +1356,48 @@
 
 	/* Different devices have different alarm bits triggering the
 	 * ALERT# output */
-	switch (data->kind) {
-	case lm90:
-	case lm99:
-	case lm86:
-		data->alert_alarms = 0x7b;
-		break;
-	default:
-		data->alert_alarms = 0x7c;
-		break;
-	}
+	data->alert_alarms = lm90_params[data->kind].alert_alarms;
+
+	/* Set chip capabilities */
+	data->flags = lm90_params[data->kind].flags;
+
+	/* Set maximum conversion rate */
+	data->max_convrate = lm90_params[data->kind].max_convrate;
 
 	/* Initialize the LM90 chip */
 	lm90_init_client(new_client);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
+	err = sysfs_create_group(&new_client->dev.kobj, &lm90_group);
+	if (err)
 		goto exit_free;
 	if (new_client->flags & I2C_CLIENT_PEC) {
-		if ((err = device_create_file(&new_client->dev,
-					      &dev_attr_pec)))
+		err = device_create_file(&new_client->dev, &dev_attr_pec);
+		if (err)
 			goto exit_remove_files;
 	}
-	if (data->kind != max6657 && data->kind != max6646) {
-		if ((err = device_create_file(&new_client->dev,
-				&sensor_dev_attr_temp2_offset.dev_attr)))
+	if (data->flags & LM90_HAVE_OFFSET) {
+		err = device_create_file(&new_client->dev,
+					&sensor_dev_attr_temp2_offset.dev_attr);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->flags & LM90_HAVE_EMERGENCY) {
+		err = sysfs_create_group(&new_client->dev.kobj,
+					 &lm90_emergency_group);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->flags & LM90_HAVE_EMERGENCY_ALARM) {
+		err = sysfs_create_group(&new_client->dev.kobj,
+					 &lm90_emergency_alarm_group);
+		if (err)
+			goto exit_remove_files;
+	}
+	if (data->flags & LM90_HAVE_TEMP3) {
+		err = sysfs_create_group(&new_client->dev.kobj,
+					 &lm90_temp3_group);
+		if (err)
 			goto exit_remove_files;
 	}
 
@@ -848,62 +1410,23 @@
 	return 0;
 
 exit_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
-	device_remove_file(&new_client->dev, &dev_attr_pec);
+	lm90_remove_files(new_client, data);
 exit_free:
 	kfree(data);
 exit:
 	return err;
 }
 
-static void lm90_init_client(struct i2c_client *client)
-{
-	u8 config;
-	struct lm90_data *data = i2c_get_clientdata(client);
-
-	/*
-	 * Start the conversions.
-	 */
-	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-				  5); /* 2 Hz */
-	if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) {
-		dev_warn(&client->dev, "Initialization failed!\n");
-		return;
-	}
-	data->config_orig = config;
-
-	/* Check Temperature Range Select */
-	if (data->kind == adt7461) {
-		if (config & 0x04)
-			data->flags |= LM90_FLAG_ADT7461_EXT;
-	}
-
-	/*
-	 * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
-	 * 0.125 degree resolution) and range (0x08, extend range
-	 * to -64 degree) mode for the remote temperature sensor.
-	 */
-	if (data->kind == max6680) {
-		config |= 0x18;
-	}
-
-	config &= 0xBF;	/* run */
-	if (config != data->config_orig) /* Only write if changed */
-		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
-}
-
 static int lm90_remove(struct i2c_client *client)
 {
 	struct lm90_data *data = i2c_get_clientdata(client);
 
 	hwmon_device_unregister(data->hwmon_dev);
-	sysfs_remove_group(&client->dev.kobj, &lm90_group);
-	device_remove_file(&client->dev, &dev_attr_pec);
-	if (data->kind != max6657 && data->kind != max6646)
-		device_remove_file(&client->dev,
-				   &sensor_dev_attr_temp2_offset.dev_attr);
+	lm90_remove_files(client, data);
 
 	/* Restore initial configuration */
+	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
+				  data->convrate_orig);
 	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
 				  data->config_orig);
 
@@ -914,10 +1437,14 @@
 static void lm90_alert(struct i2c_client *client, unsigned int flag)
 {
 	struct lm90_data *data = i2c_get_clientdata(client);
-	u8 config, alarms;
+	u8 config, alarms, alarms2 = 0;
 
 	lm90_read_reg(client, LM90_REG_R_STATUS, &alarms);
-	if ((alarms & 0x7f) == 0) {
+
+	if (data->kind == max6696)
+		lm90_read_reg(client, MAX6696_REG_R_STATUS2, &alarms2);
+
+	if ((alarms & 0x7f) == 0 && (alarms2 & 0xfe) == 0) {
 		dev_info(&client->dev, "Everything OK\n");
 	} else {
 		if (alarms & 0x61)
@@ -930,10 +1457,14 @@
 			dev_warn(&client->dev,
 				 "temp%d diode open, please check!\n", 2);
 
+		if (alarms2 & 0x18)
+			dev_warn(&client->dev,
+				 "temp%d out of range, please check!\n", 3);
+
 		/* Disable ALERT# output, because these chips don't implement
 		  SMBus alert correctly; they should only hold the alert line
 		  low briefly. */
-		if ((data->kind == adm1032 || data->kind == adt7461)
+		if ((data->flags & LM90_HAVE_BROKEN_ALERT)
 		 && (alarms & data->alert_alarms)) {
 			dev_dbg(&client->dev, "Disabling ALERT#\n");
 			lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
@@ -943,117 +1474,18 @@
 	}
 }
 
-static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value)
-{
-	int err;
-	u8 oldh, newh, l;
-
-	/*
-	 * There is a trick here. We have to read two registers to have the
-	 * sensor temperature, but we have to beware a conversion could occur
-	 * inbetween the readings. The datasheet says we should either use
-	 * the one-shot conversion register, which we don't want to do
-	 * (disables hardware monitoring) or monitor the busy bit, which is
-	 * impossible (we can't read the values and monitor that bit at the
-	 * exact same time). So the solution used here is to read the high
-	 * byte once, then the low byte, then the high byte again. If the new
-	 * high byte matches the old one, then we have a valid reading. Else
-	 * we have to read the low byte again, and now we believe we have a
-	 * correct reading.
-	 */
-	if ((err = lm90_read_reg(client, regh, &oldh))
-	 || (err = lm90_read_reg(client, regl, &l))
-	 || (err = lm90_read_reg(client, regh, &newh)))
-		return err;
-	if (oldh != newh) {
-		err = lm90_read_reg(client, regl, &l);
-		if (err)
-			return err;
-	}
-	*value = (newh << 8) | l;
-
-	return 0;
-}
-
-static struct lm90_data *lm90_update_device(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	struct lm90_data *data = i2c_get_clientdata(client);
-
-	mutex_lock(&data->update_lock);
-
-	if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10)
-	 || !data->valid) {
-		u8 h, l;
-
-		dev_dbg(&client->dev, "Updating lm90 data.\n");
-		lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[0]);
-		lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[1]);
-		lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[2]);
-		lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]);
-		lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst);
-
-		if (data->kind == max6657 || data->kind == max6646) {
-			lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
-				    MAX6657_REG_R_LOCAL_TEMPL,
-				    &data->temp11[4]);
-		} else {
-			if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP,
-					  &h) == 0)
-				data->temp11[4] = h << 8;
-		}
-		lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
-			    LM90_REG_R_REMOTE_TEMPL, &data->temp11[0]);
-
-		if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) {
-			data->temp11[1] = h << 8;
-			if (data->kind != max6657 && data->kind != max6680
-			 && data->kind != max6646
-			 && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL,
-					  &l) == 0)
-				data->temp11[1] |= l;
-		}
-		if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) {
-			data->temp11[2] = h << 8;
-			if (data->kind != max6657 && data->kind != max6680
-			 && data->kind != max6646
-			 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL,
-					  &l) == 0)
-				data->temp11[2] |= l;
-		}
-
-		if (data->kind != max6657 && data->kind != max6646) {
-			if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
-					  &h) == 0
-			 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
-					  &l) == 0)
-				data->temp11[3] = (h << 8) | l;
-		}
-		lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
-
-		/* Re-enable ALERT# output if it was originally enabled and
-		 * relevant alarms are all clear */
-		if ((data->config_orig & 0x80) == 0
-		 && (data->alarms & data->alert_alarms) == 0) {
-			u8 config;
-
-			lm90_read_reg(client, LM90_REG_R_CONFIG1, &config);
-			if (config & 0x80) {
-				dev_dbg(&client->dev, "Re-enabling ALERT#\n");
-				i2c_smbus_write_byte_data(client,
-							  LM90_REG_W_CONFIG1,
-							  config & ~0x80);
-			}
-		}
-
-		data->last_updated = jiffies;
-		data->valid = 1;
-	}
-
-	mutex_unlock(&data->update_lock);
-
-	return data;
-}
+static struct i2c_driver lm90_driver = {
+	.class		= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "lm90",
+	},
+	.probe		= lm90_probe,
+	.remove		= lm90_remove,
+	.alert		= lm90_alert,
+	.id_table	= lm90_id,
+	.detect		= lm90_detect,
+	.address_list	= normal_i2c,
+};
 
 static int __init sensors_lm90_init(void)
 {
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lm93.c linux-libre-2.6.37-gnu/drivers/hwmon/lm93.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lm93.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lm93.c	2011-01-04 19:50:19.000000000 -0500
@@ -20,7 +20,7 @@
     Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
         Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
 
-    Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+    Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de>
         Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
 
     This program is free software; you can redistribute it and/or modify
@@ -2629,7 +2629,7 @@
 }
 
 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
-		"Hans J. Koch <hjk@linutronix.de");
+		"Hans J. Koch <hjk@hansjkoch.de>");
 MODULE_DESCRIPTION("LM93 driver");
 MODULE_LICENSE("GPL");
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/lm95241.c linux-libre-2.6.37-gnu/drivers/hwmon/lm95241.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/lm95241.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/lm95241.c	2011-01-04 19:50:19.000000000 -0500
@@ -128,9 +128,12 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct lm95241_data *data = i2c_get_clientdata(client);
+	unsigned long val;
 
-	strict_strtol(buf, 10, &data->interval);
-	data->interval = data->interval * HZ / 1000;
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	data->interval = val * HZ / 1000;
 
 	return count;
 }
@@ -188,7 +191,9 @@
 	struct lm95241_data *data = i2c_get_clientdata(client); \
 \
 	long val; \
-	strict_strtol(buf, 10, &val); \
+\
+	if (strict_strtol(buf, 10, &val) < 0) \
+		return -EINVAL; \
 \
 	if ((val == 1) || (val == 2)) { \
 \
@@ -227,7 +232,9 @@
 	struct lm95241_data *data = i2c_get_clientdata(client); \
 \
 	long val; \
-	strict_strtol(buf, 10, &val); \
+\
+	if (strict_strtol(buf, 10, &val) < 0) \
+		return -EINVAL;\
 \
 	mutex_lock(&data->update_lock); \
 \
@@ -256,7 +263,9 @@
 	struct lm95241_data *data = i2c_get_clientdata(client); \
 \
 	long val; \
-	strict_strtol(buf, 10, &val); \
+\
+	if (strict_strtol(buf, 10, &val) < 0) \
+		return -EINVAL; \
 \
 	mutex_lock(&data->update_lock); \
 \
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ltc4215.c linux-libre-2.6.37-gnu/drivers/hwmon/ltc4215.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ltc4215.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ltc4215.c	2011-01-04 19:50:19.000000000 -0500
@@ -205,7 +205,6 @@
 
 /* Power (virtual) */
 LTC4215_POWER(power1_input);
-LTC4215_ALARM(power1_alarm,	(1 << 3),	LTC4215_STATUS);
 
 /* Input Voltage */
 LTC4215_VOLTAGE(in1_input,			LTC4215_ADIN);
@@ -214,6 +213,7 @@
 
 /* Output Voltage */
 LTC4215_VOLTAGE(in2_input,			LTC4215_SOURCE);
+LTC4215_ALARM(in2_min_alarm,	(1 << 3),	LTC4215_STATUS);
 
 /* Finally, construct an array of pointers to members of the above objects,
  * as required for sysfs_create_group()
@@ -223,13 +223,13 @@
 	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
 
 	&sensor_dev_attr_power1_input.dev_attr.attr,
-	&sensor_dev_attr_power1_alarm.dev_attr.attr,
 
 	&sensor_dev_attr_in1_input.dev_attr.attr,
 	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
 	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
 
 	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
 
 	NULL,
 };
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/ltc4261.c linux-libre-2.6.37-gnu/drivers/hwmon/ltc4261.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/ltc4261.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hwmon/ltc4261.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,314 @@
+/*
+ * Driver for Linear Technology LTC4261 I2C Negative Voltage Hot Swap Controller
+ *
+ * Copyright (C) 2010 Ericsson AB.
+ *
+ * Derived from:
+ *
+ *  Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ *  Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * Datasheet: http://cds.linear.com/docs/Datasheet/42612fb.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/* chip registers */
+#define LTC4261_STATUS	0x00	/* readonly */
+#define LTC4261_FAULT	0x01
+#define LTC4261_ALERT	0x02
+#define LTC4261_CONTROL	0x03
+#define LTC4261_SENSE_H	0x04
+#define LTC4261_SENSE_L	0x05
+#define LTC4261_ADIN2_H	0x06
+#define LTC4261_ADIN2_L	0x07
+#define LTC4261_ADIN_H	0x08
+#define LTC4261_ADIN_L	0x09
+
+/*
+ * Fault register bits
+ */
+#define FAULT_OV	(1<<0)
+#define FAULT_UV	(1<<1)
+#define FAULT_OC	(1<<2)
+
+struct ltc4261_data {
+	struct device *hwmon_dev;
+
+	struct mutex update_lock;
+	bool valid;
+	unsigned long last_updated;	/* in jiffies */
+
+	/* Registers */
+	u8 regs[10];
+};
+
+static struct ltc4261_data *ltc4261_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ltc4261_data *data = i2c_get_clientdata(client);
+	struct ltc4261_data *ret = data;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + HZ / 4) || !data->valid) {
+		int i;
+
+		/* Read registers -- 0x00 to 0x09 */
+		for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
+			int val;
+
+			val = i2c_smbus_read_byte_data(client, i);
+			if (unlikely(val < 0)) {
+				dev_dbg(dev,
+					"Failed to read ADC value: error %d\n",
+					val);
+				ret = ERR_PTR(val);
+				goto abort;
+			}
+			data->regs[i] = val;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+abort:
+	mutex_unlock(&data->update_lock);
+	return ret;
+}
+
+/* Return the voltage from the given register in mV or mA */
+static int ltc4261_get_value(struct ltc4261_data *data, u8 reg)
+{
+	u32 val;
+
+	val = (data->regs[reg] << 2) + (data->regs[reg + 1] >> 6);
+
+	switch (reg) {
+	case LTC4261_ADIN_H:
+	case LTC4261_ADIN2_H:
+		/* 2.5mV resolution. Convert to mV. */
+		val = val * 25 / 10;
+		break;
+	case LTC4261_SENSE_H:
+		/*
+		 * 62.5uV resolution. Convert to current as measured with
+		 * an 1 mOhm sense resistor, in mA. If a different sense
+		 * resistor is installed, calculate the actual current by
+		 * dividing the reported current by the sense resistor value
+		 * in mOhm.
+		 */
+		val = val * 625 / 10;
+		break;
+	default:
+		/* If we get here, the developer messed up */
+		WARN_ON_ONCE(1);
+		val = 0;
+		break;
+	}
+
+	return val;
+}
+
+static ssize_t ltc4261_show_value(struct device *dev,
+				  struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ltc4261_data *data = ltc4261_update_device(dev);
+	int value;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	value = ltc4261_get_value(data, attr->index);
+	return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+static ssize_t ltc4261_show_bool(struct device *dev,
+				 struct device_attribute *da, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ltc4261_data *data = ltc4261_update_device(dev);
+	u8 fault;
+
+	if (IS_ERR(data))
+		return PTR_ERR(data);
+
+	fault = data->regs[LTC4261_FAULT] & attr->index;
+	if (fault)		/* Clear reported faults in chip register */
+		i2c_smbus_write_byte_data(client, LTC4261_FAULT, ~fault);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
+}
+
+/*
+ * These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
+	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+	ltc4261_show_value, NULL, ltc4261_cmd_idx)
+
+#define LTC4261_BOOL(name, mask) \
+	static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+	ltc4261_show_bool, NULL, (mask))
+
+/*
+ * Input voltages.
+ */
+LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
+LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
+
+/*
+ * Voltage alarms. The chip has only one set of voltage alarm status bits,
+ * triggered by input voltage alarms. In many designs, those alarms are
+ * associated with the ADIN2 sensor, due to the proximity of the ADIN2 pin
+ * to the OV pin. ADIN2 is, however, not available on all chip variants.
+ * To ensure that the alarm condition is reported to the user, report it
+ * with both voltage sensors.
+ */
+LTC4261_BOOL(in1_min_alarm, FAULT_UV);
+LTC4261_BOOL(in1_max_alarm, FAULT_OV);
+LTC4261_BOOL(in2_min_alarm, FAULT_UV);
+LTC4261_BOOL(in2_max_alarm, FAULT_OV);
+
+/* Currents (via sense resistor) */
+LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
+
+/* Overcurrent alarm */
+LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
+
+static struct attribute *ltc4261_attributes[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_in2_max_alarm.dev_attr.attr,
+
+	&sensor_dev_attr_curr1_input.dev_attr.attr,
+	&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+
+	NULL,
+};
+
+static const struct attribute_group ltc4261_group = {
+	.attrs = ltc4261_attributes,
+};
+
+static int ltc4261_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	struct ltc4261_data *data;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+
+	if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
+		dev_err(&client->dev, "Failed to read status register\n");
+		return -ENODEV;
+	}
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto out_kzalloc;
+	}
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/* Clear faults */
+	i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00);
+
+	/* Register sysfs hooks */
+	ret = sysfs_create_group(&client->dev.kobj, &ltc4261_group);
+	if (ret)
+		goto out_sysfs_create_group;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		ret = PTR_ERR(data->hwmon_dev);
+		goto out_hwmon_device_register;
+	}
+
+	return 0;
+
+out_hwmon_device_register:
+	sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+out_sysfs_create_group:
+	kfree(data);
+out_kzalloc:
+	return ret;
+}
+
+static int ltc4261_remove(struct i2c_client *client)
+{
+	struct ltc4261_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
+
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id ltc4261_id[] = {
+	{"ltc4261", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, ltc4261_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4261_driver = {
+	.driver = {
+		   .name = "ltc4261",
+		   },
+	.probe = ltc4261_probe,
+	.remove = ltc4261_remove,
+	.id_table = ltc4261_id,
+};
+
+static int __init ltc4261_init(void)
+{
+	return i2c_add_driver(&ltc4261_driver);
+}
+
+static void __exit ltc4261_exit(void)
+{
+	i2c_del_driver(&ltc4261_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("LTC4261 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4261_init);
+module_exit(ltc4261_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/Makefile linux-libre-2.6.37-gnu/drivers/hwmon/Makefile
--- linux-libre-2.6.36-gnu/drivers/hwmon/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SENSORS_W83627HF)	+= w83627hf.o
 obj-$(CONFIG_SENSORS_W83792D)	+= w83792d.o
 obj-$(CONFIG_SENSORS_W83793)	+= w83793.o
+obj-$(CONFIG_SENSORS_W83795)	+= w83795.o
 obj-$(CONFIG_SENSORS_W83781D)	+= w83781d.o
 obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
@@ -35,7 +36,6 @@
 obj-$(CONFIG_SENSORS_ADT7470)	+= adt7470.o
 obj-$(CONFIG_SENSORS_ADT7475)	+= adt7475.o
 obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
-obj-$(CONFIG_SENSORS_AMS)	+= ams/
 obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
@@ -51,8 +51,8 @@
 obj-$(CONFIG_SENSORS_G760A)	+= g760a.o
 obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)	+= gl520sm.o
+obj-$(CONFIG_SENSORS_GPIO_FAN)	+= gpio-fan.o
 obj-$(CONFIG_SENSORS_ULTRA45)	+= ultra45_env.o
-obj-$(CONFIG_SENSORS_HDAPS)	+= hdaps.o
 obj-$(CONFIG_SENSORS_I5K_AMB)	+= i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)	+= ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)	+= ibmpex.o
@@ -80,6 +80,7 @@
 obj-$(CONFIG_SENSORS_LM95241)	+= lm95241.o
 obj-$(CONFIG_SENSORS_LTC4215)	+= ltc4215.o
 obj-$(CONFIG_SENSORS_LTC4245)	+= ltc4245.o
+obj-$(CONFIG_SENSORS_LTC4261)	+= ltc4261.o
 obj-$(CONFIG_SENSORS_MAX1111)	+= max1111.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/max6650.c linux-libre-2.6.37-gnu/drivers/hwmon/max6650.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/max6650.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/max6650.c	2011-01-04 19:50:19.000000000 -0500
@@ -2,7 +2,7 @@
  * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
  *             monitoring.
  *
- * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>
  *
  * based on code written by John Morris <john.morris@spirentcom.com>
  * Copyright (c) 2003 Spirent Communications
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/pcf8591.c linux-libre-2.6.37-gnu/drivers/hwmon/pcf8591.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/pcf8591.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/pcf8591.c	2011-01-04 19:50:19.000000000 -0500
@@ -23,10 +23,8 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
-					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+#include <linux/err.h>
+#include <linux/hwmon.h>
 
 /* Insmod parameters */
 
@@ -71,6 +69,7 @@
 #define REG_TO_SIGNED(reg)	(((reg) & 0x80)?((reg) - 256):(reg))
 
 struct pcf8591_data {
+	struct device *hwmon_dev;
 	struct mutex update_lock;
 
 	u8 control;
@@ -167,24 +166,6 @@
  * Real code
  */
 
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int pcf8591_detect(struct i2c_client *client,
-			  struct i2c_board_info *info)
-{
-	struct i2c_adapter *adapter = client->adapter;
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
-				     | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
-		return -ENODEV;
-
-	/* Now, we would do the remaining detection. But the PCF8591 is plainly
-	   impossible to detect! Stupid chip. */
-
-	strlcpy(info->type, "pcf8591", I2C_NAME_SIZE);
-
-	return 0;
-}
-
 static int pcf8591_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
@@ -221,6 +202,12 @@
 			goto exit_sysfs_remove;
 	}
 
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_sysfs_remove;
+	}
+
 	return 0;
 
 exit_sysfs_remove:
@@ -234,6 +221,9 @@
 
 static int pcf8591_remove(struct i2c_client *client)
 {
+	struct pcf8591_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
 	sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
 	kfree(i2c_get_clientdata(client));
@@ -295,10 +285,6 @@
 	.probe		= pcf8591_probe,
 	.remove		= pcf8591_remove,
 	.id_table	= pcf8591_id,
-
-	.class		= I2C_CLASS_HWMON,	/* Nearest choice */
-	.detect		= pcf8591_detect,
-	.address_list	= normal_i2c,
 };
 
 static int __init pcf8591_init(void)
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/pkgtemp.c linux-libre-2.6.37-gnu/drivers/hwmon/pkgtemp.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/pkgtemp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/pkgtemp.c	2011-01-04 19:50:19.000000000 -0500
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -35,6 +34,7 @@
 #include <linux/cpu.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/smp.h>
 
 #define DRVNAME	"pkgtemp"
 
@@ -339,8 +339,7 @@
 	return err;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void pkgtemp_device_remove(unsigned int cpu)
+static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
 {
 	struct pdev_entry *p;
 	unsigned int i;
@@ -387,12 +386,10 @@
 static struct notifier_block pkgtemp_cpu_notifier __refdata = {
 	.notifier_call = pkgtemp_cpu_callback,
 };
-#endif				/* !CONFIG_HOTPLUG_CPU */
 
 static int __init pkgtemp_init(void)
 {
 	int i, err = -ENODEV;
-	struct pdev_entry *p, *n;
 
 	/* quick check if we run Intel */
 	if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
@@ -402,31 +399,23 @@
 	if (err)
 		goto exit;
 
-	for_each_online_cpu(i) {
-		err = pkgtemp_device_add(i);
-		if (err)
-			goto exit_devices_unreg;
-	}
+	for_each_online_cpu(i)
+		pkgtemp_device_add(i);
+
+#ifndef CONFIG_HOTPLUG_CPU
 	if (list_empty(&pdev_list)) {
 		err = -ENODEV;
 		goto exit_driver_unreg;
 	}
+#endif
 
-#ifdef CONFIG_HOTPLUG_CPU
 	register_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
 	return 0;
 
-exit_devices_unreg:
-	mutex_lock(&pdev_list_mutex);
-	list_for_each_entry_safe(p, n, &pdev_list, list) {
-		platform_device_unregister(p->pdev);
-		list_del(&p->list);
-		kfree(p);
-	}
-	mutex_unlock(&pdev_list_mutex);
+#ifndef CONFIG_HOTPLUG_CPU
 exit_driver_unreg:
 	platform_driver_unregister(&pkgtemp_driver);
+#endif
 exit:
 	return err;
 }
@@ -434,9 +423,8 @@
 static void __exit pkgtemp_exit(void)
 {
 	struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
 	unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
-#endif
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
 		platform_device_unregister(p->pdev);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/s3c-hwmon.c linux-libre-2.6.37-gnu/drivers/hwmon/s3c-hwmon.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/s3c-hwmon.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/s3c-hwmon.c	2011-01-04 19:50:19.000000000 -0500
@@ -51,7 +51,7 @@
  * @attr: The holders for the channel attributes.
 */
 struct s3c_hwmon {
-	struct semaphore	lock;
+	struct mutex		lock;
 	struct s3c_adc_client	*client;
 	struct device		*hwmon_dev;
 
@@ -73,14 +73,14 @@
 {
 	int ret;
 
-	ret = down_interruptible(&hwmon->lock);
+	ret = mutex_lock_interruptible(&hwmon->lock);
 	if (ret < 0)
 		return ret;
 
 	dev_dbg(dev, "reading channel %d\n", channel);
 
 	ret = s3c_adc_read(hwmon->client, channel);
-	up(&hwmon->lock);
+	mutex_unlock(&hwmon->lock);
 
 	return ret;
 }
@@ -234,7 +234,6 @@
 	attr->index = channel;
 	attr->dev_attr.attr.name  = attrs->in_name;
 	attr->dev_attr.attr.mode  = S_IRUGO;
-	attr->dev_attr.attr.owner = THIS_MODULE;
 	attr->dev_attr.show = s3c_hwmon_ch_show;
 
 	ret =  device_create_file(dev, &attr->dev_attr);
@@ -252,7 +251,6 @@
 		attr->index = channel;
 		attr->dev_attr.attr.name  = attrs->label_name;
 		attr->dev_attr.attr.mode  = S_IRUGO;
-		attr->dev_attr.attr.owner = THIS_MODULE;
 		attr->dev_attr.show = s3c_hwmon_label_show;
 
 		ret = device_create_file(dev, &attr->dev_attr);
@@ -296,7 +294,7 @@
 
 	platform_set_drvdata(dev, hwmon);
 
-	init_MUTEX(&hwmon->lock);
+	mutex_init(&hwmon->lock);
 
 	/* Register with the core ADC driver. */
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/tmp421.c linux-libre-2.6.37-gnu/drivers/hwmon/tmp421.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/tmp421.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/tmp421.c	2011-01-04 19:50:19.000000000 -0500
@@ -36,8 +36,8 @@
 #include <linux/sysfs.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
-				       I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f,
+					     I2C_CLIENT_END };
 
 enum chips { tmp421, tmp422, tmp423 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/via-cputemp.c linux-libre-2.6.37-gnu/drivers/hwmon/via-cputemp.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/via-cputemp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/via-cputemp.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,10 +22,8 @@
  */
 
 #include <linux/module.h>
-#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
 #include <linux/hwmon.h>
 #include <linux/sysfs.h>
 #include <linux/hwmon-sysfs.h>
@@ -237,8 +235,7 @@
 	return err;
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void via_cputemp_device_remove(unsigned int cpu)
+static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
 {
 	struct pdev_entry *p, *n;
 	mutex_lock(&pdev_list_mutex);
@@ -272,7 +269,6 @@
 static struct notifier_block via_cputemp_cpu_notifier __refdata = {
 	.notifier_call = via_cputemp_cpu_callback,
 };
-#endif				/* !CONFIG_HOTPLUG_CPU */
 
 static int __init via_cputemp_init(void)
 {
@@ -313,9 +309,7 @@
 		goto exit_driver_unreg;
 	}
 
-#ifdef CONFIG_HOTPLUG_CPU
 	register_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
 	return 0;
 
 exit_devices_unreg:
@@ -335,9 +329,8 @@
 static void __exit via_cputemp_exit(void)
 {
 	struct pdev_entry *p, *n;
-#ifdef CONFIG_HOTPLUG_CPU
+
 	unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
-#endif
 	mutex_lock(&pdev_list_mutex);
 	list_for_each_entry_safe(p, n, &pdev_list, list) {
 		platform_device_unregister(p->pdev);
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/w83793.c linux-libre-2.6.37-gnu/drivers/hwmon/w83793.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/w83793.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/hwmon/w83793.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,7 +35,6 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
-#include <linux/smp_lock.h>
 #include <linux/hwmon-vid.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
@@ -52,6 +51,7 @@
 #define WATCHDOG_TIMEOUT 2	/* 2 minute default timeout */
 
 /* Addresses to scan */
+static DEFINE_MUTEX(watchdog_mutex);
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
 						I2C_CLIENT_END };
 
@@ -1333,7 +1333,7 @@
 	int val, ret = 0;
 	struct w83793_data *data = filp->private_data;
 
-	lock_kernel();
+	mutex_lock(&watchdog_mutex);
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 		if (!nowayout)
@@ -1387,7 +1387,7 @@
 	default:
 		ret = -ENOTTY;
 	}
-	unlock_kernel();
+	mutex_unlock(&watchdog_mutex);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/hwmon/w83795.c linux-libre-2.6.37-gnu/drivers/hwmon/w83795.c
--- linux-libre-2.6.36-gnu/drivers/hwmon/w83795.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/hwmon/w83795.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,2262 @@
+/*
+ *  w83795.c - Linux kernel driver for hardware monitoring
+ *  Copyright (C) 2008 Nuvoton Technology Corp.
+ *                Wei Song
+ *  Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation - version 2.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301 USA.
+ *
+ *  Supports following chips:
+ *
+ *  Chip       #vin   #fanin #pwm #temp #dts wchipid  vendid  i2c  ISA
+ *  w83795g     21     14     8     6     8    0x79   0x5ca3  yes   no
+ *  w83795adg   18     14     2     6     8    0x79   0x5ca3  yes   no
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
+};
+
+
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
+
+
+#define W83795_REG_BANKSEL		0x00
+#define W83795_REG_VENDORID		0xfd
+#define W83795_REG_CHIPID		0xfe
+#define W83795_REG_DEVICEID		0xfb
+#define W83795_REG_DEVICEID_A		0xff
+
+#define W83795_REG_I2C_ADDR		0xfc
+#define W83795_REG_CONFIG		0x01
+#define W83795_REG_CONFIG_CONFIG48	0x04
+#define W83795_REG_CONFIG_START	0x01
+
+/* Multi-Function Pin Ctrl Registers */
+#define W83795_REG_VOLT_CTRL1		0x02
+#define W83795_REG_VOLT_CTRL2		0x03
+#define W83795_REG_TEMP_CTRL1		0x04
+#define W83795_REG_TEMP_CTRL2		0x05
+#define W83795_REG_FANIN_CTRL1		0x06
+#define W83795_REG_FANIN_CTRL2		0x07
+#define W83795_REG_VMIGB_CTRL		0x08
+
+#define TEMP_READ			0
+#define TEMP_CRIT			1
+#define TEMP_CRIT_HYST			2
+#define TEMP_WARN			3
+#define TEMP_WARN_HYST			4
+/* only crit and crit_hyst affect real-time alarm status
+ * current crit crit_hyst warn warn_hyst */
+static const u16 W83795_REG_TEMP[][5] = {
+	{0x21, 0x96, 0x97, 0x98, 0x99},	/* TD1/TR1 */
+	{0x22, 0x9a, 0x9b, 0x9c, 0x9d},	/* TD2/TR2 */
+	{0x23, 0x9e, 0x9f, 0xa0, 0xa1},	/* TD3/TR3 */
+	{0x24, 0xa2, 0xa3, 0xa4, 0xa5},	/* TD4/TR4 */
+	{0x1f, 0xa6, 0xa7, 0xa8, 0xa9},	/* TR5 */
+	{0x20, 0xaa, 0xab, 0xac, 0xad},	/* TR6 */
+};
+
+#define IN_READ				0
+#define IN_MAX				1
+#define IN_LOW				2
+static const u16 W83795_REG_IN[][3] = {
+	/* Current, HL, LL */
+	{0x10, 0x70, 0x71},	/* VSEN1 */
+	{0x11, 0x72, 0x73},	/* VSEN2 */
+	{0x12, 0x74, 0x75},	/* VSEN3 */
+	{0x13, 0x76, 0x77},	/* VSEN4 */
+	{0x14, 0x78, 0x79},	/* VSEN5 */
+	{0x15, 0x7a, 0x7b},	/* VSEN6 */
+	{0x16, 0x7c, 0x7d},	/* VSEN7 */
+	{0x17, 0x7e, 0x7f},	/* VSEN8 */
+	{0x18, 0x80, 0x81},	/* VSEN9 */
+	{0x19, 0x82, 0x83},	/* VSEN10 */
+	{0x1A, 0x84, 0x85},	/* VSEN11 */
+	{0x1B, 0x86, 0x87},	/* VTT */
+	{0x1C, 0x88, 0x89},	/* 3VDD */
+	{0x1D, 0x8a, 0x8b},	/* 3VSB */
+	{0x1E, 0x8c, 0x8d},	/* VBAT */
+	{0x1F, 0xa6, 0xa7},	/* VSEN12 */
+	{0x20, 0xaa, 0xab},	/* VSEN13 */
+	{0x21, 0x96, 0x97},	/* VSEN14 */
+	{0x22, 0x9a, 0x9b},	/* VSEN15 */
+	{0x23, 0x9e, 0x9f},	/* VSEN16 */
+	{0x24, 0xa2, 0xa3},	/* VSEN17 */
+};
+#define W83795_REG_VRLSB		0x3C
+
+static const u8 W83795_REG_IN_HL_LSB[] = {
+	0x8e,	/* VSEN1-4 */
+	0x90,	/* VSEN5-8 */
+	0x92,	/* VSEN9-11 */
+	0x94,	/* VTT, 3VDD, 3VSB, 3VBAT */
+	0xa8,	/* VSEN12 */
+	0xac,	/* VSEN13 */
+	0x98,	/* VSEN14 */
+	0x9c,	/* VSEN15 */
+	0xa0,	/* VSEN16 */
+	0xa4,	/* VSEN17 */
+};
+
+#define IN_LSB_REG(index, type) \
+	(((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \
+	: (W83795_REG_IN_HL_LSB[(index)] + 1))
+
+#define IN_LSB_SHIFT			0
+#define IN_LSB_IDX			1
+static const u8 IN_LSB_SHIFT_IDX[][2] = {
+	/* High/Low LSB shift, LSB No. */
+	{0x00, 0x00},	/* VSEN1 */
+	{0x02, 0x00},	/* VSEN2 */
+	{0x04, 0x00},	/* VSEN3 */
+	{0x06, 0x00},	/* VSEN4 */
+	{0x00, 0x01},	/* VSEN5 */
+	{0x02, 0x01},	/* VSEN6 */
+	{0x04, 0x01},	/* VSEN7 */
+	{0x06, 0x01},	/* VSEN8 */
+	{0x00, 0x02},	/* VSEN9 */
+	{0x02, 0x02},	/* VSEN10 */
+	{0x04, 0x02},	/* VSEN11 */
+	{0x00, 0x03},	/* VTT */
+	{0x02, 0x03},	/* 3VDD */
+	{0x04, 0x03},	/* 3VSB	*/
+	{0x06, 0x03},	/* VBAT	*/
+	{0x06, 0x04},	/* VSEN12 */
+	{0x06, 0x05},	/* VSEN13 */
+	{0x06, 0x06},	/* VSEN14 */
+	{0x06, 0x07},	/* VSEN15 */
+	{0x06, 0x08},	/* VSEN16 */
+	{0x06, 0x09},	/* VSEN17 */
+};
+
+
+#define W83795_REG_FAN(index)		(0x2E + (index))
+#define W83795_REG_FAN_MIN_HL(index)	(0xB6 + (index))
+#define W83795_REG_FAN_MIN_LSB(index)	(0xC4 + (index) / 2)
+#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \
+	(((index) & 1) ? 4 : 0)
+
+#define W83795_REG_VID_CTRL		0x6A
+
+#define W83795_REG_ALARM_CTRL		0x40
+#define ALARM_CTRL_RTSACS		(1 << 7)
+#define W83795_REG_ALARM(index)		(0x41 + (index))
+#define W83795_REG_CLR_CHASSIS		0x4D
+#define W83795_REG_BEEP(index)		(0x50 + (index))
+
+#define W83795_REG_OVT_CFG		0x58
+#define OVT_CFG_SEL			(1 << 7)
+
+
+#define W83795_REG_FCMS1		0x201
+#define W83795_REG_FCMS2		0x208
+#define W83795_REG_TFMR(index)		(0x202 + (index))
+#define W83795_REG_FOMC			0x20F
+
+#define W83795_REG_TSS(index)		(0x209 + (index))
+
+#define TSS_MAP_RESERVED		0xff
+static const u8 tss_map[4][6] = {
+	{ 0,  1,  2,  3,  4,  5},
+	{ 6,  7,  8,  9,  0,  1},
+	{10, 11, 12, 13,  2,  3},
+	{ 4,  5,  4,  5, TSS_MAP_RESERVED, TSS_MAP_RESERVED},
+};
+
+#define PWM_OUTPUT			0
+#define PWM_FREQ			1
+#define PWM_START			2
+#define PWM_NONSTOP			3
+#define PWM_STOP_TIME			4
+#define W83795_REG_PWM(index, nr)	(0x210 + (nr) * 8 + (index))
+
+#define W83795_REG_FTSH(index)		(0x240 + (index) * 2)
+#define W83795_REG_FTSL(index)		(0x241 + (index) * 2)
+#define W83795_REG_TFTS			0x250
+
+#define TEMP_PWM_TTTI			0
+#define TEMP_PWM_CTFS			1
+#define TEMP_PWM_HCT			2
+#define TEMP_PWM_HOT			3
+#define W83795_REG_TTTI(index)		(0x260 + (index))
+#define W83795_REG_CTFS(index)		(0x268 + (index))
+#define W83795_REG_HT(index)		(0x270 + (index))
+
+#define SF4_TEMP			0
+#define SF4_PWM				1
+#define W83795_REG_SF4_TEMP(temp_num, index) \
+	(0x280 + 0x10 * (temp_num) + (index))
+#define W83795_REG_SF4_PWM(temp_num, index) \
+	(0x288 + 0x10 * (temp_num) + (index))
+
+#define W83795_REG_DTSC			0x301
+#define W83795_REG_DTSE			0x302
+#define W83795_REG_DTS(index)		(0x26 + (index))
+#define W83795_REG_PECI_TBASE(index)	(0x320 + (index))
+
+#define DTS_CRIT			0
+#define DTS_CRIT_HYST			1
+#define DTS_WARN			2
+#define DTS_WARN_HYST			3
+#define W83795_REG_DTS_EXT(index)	(0xB2 + (index))
+
+#define SETUP_PWM_DEFAULT		0
+#define SETUP_PWM_UPTIME		1
+#define SETUP_PWM_DOWNTIME		2
+#define W83795_REG_SETUP_PWM(index)    (0x20C + (index))
+
+static inline u16 in_from_reg(u8 index, u16 val)
+{
+	/* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */
+	if (index >= 12 && index <= 14)
+		return val * 6;
+	else
+		return val * 2;
+}
+
+static inline u16 in_to_reg(u8 index, u16 val)
+{
+	if (index >= 12 && index <= 14)
+		return val / 6;
+	else
+		return val / 2;
+}
+
+static inline unsigned long fan_from_reg(u16 val)
+{
+	if ((val == 0xfff) || (val == 0))
+		return 0;
+	return 1350000UL / val;
+}
+
+static inline u16 fan_to_reg(long rpm)
+{
+	if (rpm <= 0)
+		return 0x0fff;
+	return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
+}
+
+static inline unsigned long time_from_reg(u8 reg)
+{
+	return reg * 100;
+}
+
+static inline u8 time_to_reg(unsigned long val)
+{
+	return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);
+}
+
+static inline long temp_from_reg(s8 reg)
+{
+	return reg * 1000;
+}
+
+static inline s8 temp_to_reg(long val, s8 min, s8 max)
+{
+	return SENSORS_LIMIT(val / 1000, min, max);
+}
+
+static const u16 pwm_freq_cksel0[16] = {
+	1024, 512, 341, 256, 205, 171, 146, 128,
+	85, 64, 32, 16, 8, 4, 2, 1
+};
+
+static unsigned int pwm_freq_from_reg(u8 reg, u16 clkin)
+{
+	unsigned long base_clock;
+
+	if (reg & 0x80) {
+		base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+		return base_clock / ((reg & 0x7f) + 1);
+	} else
+		return pwm_freq_cksel0[reg & 0x0f];
+}
+
+static u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
+{
+	unsigned long base_clock;
+	u8 reg0, reg1;
+	unsigned long best0, best1;
+
+	/* Best fit for cksel = 0 */
+	for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) {
+		if (val > (pwm_freq_cksel0[reg0] +
+			   pwm_freq_cksel0[reg0 + 1]) / 2)
+			break;
+	}
+	if (val < 375)	/* cksel = 1 can't beat this */
+		return reg0;
+	best0 = pwm_freq_cksel0[reg0];
+
+	/* Best fit for cksel = 1 */
+	base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
+	reg1 = SENSORS_LIMIT(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
+	best1 = base_clock / reg1;
+	reg1 = 0x80 | (reg1 - 1);
+
+	/* Choose the closest one */
+	if (abs(val - best0) > abs(val - best1))
+		return reg1;
+	else
+		return reg0;
+}
+
+enum chip_types {w83795g, w83795adg};
+
+struct w83795_data {
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+	enum chip_types chip_type;
+
+	u8 bank;
+
+	u32 has_in;		/* Enable monitor VIN or not */
+	u8 has_dyn_in;		/* Only in2-0 can have this */
+	u16 in[21][3];		/* Register value, read/high/low */
+	u8 in_lsb[10][3];	/* LSB Register value, high/low */
+	u8 has_gain;		/* has gain: in17-20 * 8 */
+
+	u16 has_fan;		/* Enable fan14-1 or not */
+	u16 fan[14];		/* Register value combine */
+	u16 fan_min[14];	/* Register value combine */
+
+	u8 has_temp;		/* Enable monitor temp6-1 or not */
+	s8 temp[6][5];		/* current, crit, crit_hyst, warn, warn_hyst */
+	u8 temp_read_vrlsb[6];
+	u8 temp_mode;		/* Bit vector, 0 = TR, 1 = TD */
+	u8 temp_src[3];		/* Register value */
+
+	u8 enable_dts;		/* Enable PECI and SB-TSI,
+				 * bit 0: =1 enable, =0 disable,
+				 * bit 1: =1 AMD SB-TSI, =0 Intel PECI */
+	u8 has_dts;		/* Enable monitor DTS temp */
+	s8 dts[8];		/* Register value */
+	u8 dts_read_vrlsb[8];	/* Register value */
+	s8 dts_ext[4];		/* Register value */
+
+	u8 has_pwm;		/* 795g supports 8 pwm, 795adg only supports 2,
+				 * no config register, only affected by chip
+				 * type */
+	u8 pwm[8][5];		/* Register value, output, freq, start,
+				 *  non stop, stop time */
+	u16 clkin;		/* CLKIN frequency in kHz */
+	u8 pwm_fcms[2];		/* Register value */
+	u8 pwm_tfmr[6];		/* Register value */
+	u8 pwm_fomc;		/* Register value */
+
+	u16 target_speed[8];	/* Register value, target speed for speed
+				 * cruise */
+	u8 tol_speed;		/* tolerance of target speed */
+	u8 pwm_temp[6][4];	/* TTTI, CTFS, HCT, HOT */
+	u8 sf4_reg[6][2][7];	/* 6 temp, temp/dcpwm, 7 registers */
+
+	u8 setup_pwm[3];	/* Register value */
+
+	u8 alarms[6];		/* Register value */
+	u8 enable_beep;
+	u8 beeps[6];		/* Register value */
+
+	char valid;
+	char valid_limits;
+	char valid_pwm_config;
+};
+
+/*
+ * Hardware access
+ * We assume that nobdody can change the bank outside the driver.
+ */
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83795_set_bank(struct i2c_client *client, u8 bank)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int err;
+
+	/* If the same bank is already set, nothing to do */
+	if ((data->bank & 0x07) == bank)
+		return 0;
+
+	/* Change to new bank, preserve all other bits */
+	bank |= data->bank & ~0x07;
+	err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to set bank to %d, err %d\n",
+			(int)bank, err);
+		return err;
+	}
+	data->bank = bank;
+
+	return 0;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static u8 w83795_read(struct i2c_client *client, u16 reg)
+{
+	int err;
+
+	err = w83795_set_bank(client, reg >> 8);
+	if (err < 0)
+		return 0x00;	/* Arbitrary */
+
+	err = i2c_smbus_read_byte_data(client, reg & 0xff);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to read from register 0x%03x, err %d\n",
+			(int)reg, err);
+		return 0x00;	/* Arbitrary */
+	}
+	return err;
+}
+
+/* Must be called with data->update_lock held, except during initialization */
+static int w83795_write(struct i2c_client *client, u16 reg, u8 value)
+{
+	int err;
+
+	err = w83795_set_bank(client, reg >> 8);
+	if (err < 0)
+		return err;
+
+	err = i2c_smbus_write_byte_data(client, reg & 0xff, value);
+	if (err < 0)
+		dev_err(&client->dev,
+			"Failed to write to register 0x%03x, err %d\n",
+			(int)reg, err);
+	return err;
+}
+
+static void w83795_update_limits(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int i, limit;
+
+	/* Read the voltage limits */
+	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		data->in[i][IN_MAX] =
+			w83795_read(client, W83795_REG_IN[i][IN_MAX]);
+		data->in[i][IN_LOW] =
+			w83795_read(client, W83795_REG_IN[i][IN_LOW]);
+	}
+	for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) {
+		if ((i == 2 && data->chip_type == w83795adg) ||
+		    (i >= 4 && !(data->has_in & (1 << (i + 11)))))
+			continue;
+		data->in_lsb[i][IN_MAX] =
+			w83795_read(client, IN_LSB_REG(i, IN_MAX));
+		data->in_lsb[i][IN_LOW] =
+			w83795_read(client, IN_LSB_REG(i, IN_LOW));
+	}
+
+	/* Read the fan limits */
+	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+		u8 lsb;
+
+		/* Each register contains LSB for 2 fans, but we want to
+		 * read it only once to save time */
+		if ((i & 1) == 0 && (data->has_fan & (3 << i)))
+			lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
+
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan_min[i] =
+			w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4;
+		data->fan_min[i] |=
+			(lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F;
+	}
+
+	/* Read the temperature limits */
+	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+		for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++)
+			data->temp[i][limit] =
+				w83795_read(client, W83795_REG_TEMP[i][limit]);
+	}
+
+	/* Read the DTS limits */
+	if (data->enable_dts) {
+		for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++)
+			data->dts_ext[limit] =
+				w83795_read(client, W83795_REG_DTS_EXT(limit));
+	}
+
+	/* Read beep settings */
+	if (data->enable_beep) {
+		for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
+			data->beeps[i] =
+				w83795_read(client, W83795_REG_BEEP(i));
+	}
+
+	data->valid_limits = 1;
+}
+
+static struct w83795_data *w83795_update_pwm_config(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	int i, tmp;
+
+	mutex_lock(&data->update_lock);
+
+	if (data->valid_pwm_config)
+		goto END;
+
+	/* Read temperature source selection */
+	for (i = 0; i < ARRAY_SIZE(data->temp_src); i++)
+		data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i));
+
+	/* Read automatic fan speed control settings */
+	data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1);
+	data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2);
+	for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++)
+		data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i));
+	data->pwm_fomc = w83795_read(client, W83795_REG_FOMC);
+	for (i = 0; i < data->has_pwm; i++) {
+		for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++)
+			data->pwm[i][tmp] =
+				w83795_read(client, W83795_REG_PWM(i, tmp));
+	}
+	for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) {
+		data->target_speed[i] =
+			w83795_read(client, W83795_REG_FTSH(i)) << 4;
+		data->target_speed[i] |=
+			w83795_read(client, W83795_REG_FTSL(i)) >> 4;
+	}
+	data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f;
+
+	for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) {
+		data->pwm_temp[i][TEMP_PWM_TTTI] =
+			w83795_read(client, W83795_REG_TTTI(i)) & 0x7f;
+		data->pwm_temp[i][TEMP_PWM_CTFS] =
+			w83795_read(client, W83795_REG_CTFS(i));
+		tmp = w83795_read(client, W83795_REG_HT(i));
+		data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4;
+		data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f;
+	}
+
+	/* Read SmartFanIV trip points */
+	for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) {
+		for (tmp = 0; tmp < 7; tmp++) {
+			data->sf4_reg[i][SF4_TEMP][tmp] =
+				w83795_read(client,
+					    W83795_REG_SF4_TEMP(i, tmp));
+			data->sf4_reg[i][SF4_PWM][tmp] =
+				w83795_read(client, W83795_REG_SF4_PWM(i, tmp));
+		}
+	}
+
+	/* Read setup PWM */
+	for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++)
+		data->setup_pwm[i] =
+			w83795_read(client, W83795_REG_SETUP_PWM(i));
+
+	data->valid_pwm_config = 1;
+
+END:
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+static struct w83795_data *w83795_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	u16 tmp;
+	u8 intrusion;
+	int i;
+
+	mutex_lock(&data->update_lock);
+
+	if (!data->valid_limits)
+		w83795_update_limits(client);
+
+	if (!(time_after(jiffies, data->last_updated + HZ * 2)
+	      || !data->valid))
+		goto END;
+
+	/* Update the voltages value */
+	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2;
+		tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6;
+		data->in[i][IN_READ] = tmp;
+	}
+
+	/* in0-2 can have dynamic limits (W83795G only) */
+	if (data->has_dyn_in) {
+		u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX));
+		u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW));
+
+		for (i = 0; i < 3; i++) {
+			if (!(data->has_dyn_in & (1 << i)))
+				continue;
+			data->in[i][IN_MAX] =
+				w83795_read(client, W83795_REG_IN[i][IN_MAX]);
+			data->in[i][IN_LOW] =
+				w83795_read(client, W83795_REG_IN[i][IN_LOW]);
+			data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03;
+			data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03;
+		}
+	}
+
+	/* Update fan */
+	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
+		data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4;
+	}
+
+	/* Update temperature */
+	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+		data->temp[i][TEMP_READ] =
+			w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]);
+		data->temp_read_vrlsb[i] =
+			w83795_read(client, W83795_REG_VRLSB);
+	}
+
+	/* Update dts temperature */
+	if (data->enable_dts) {
+		for (i = 0; i < ARRAY_SIZE(data->dts); i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			data->dts[i] =
+				w83795_read(client, W83795_REG_DTS(i));
+			data->dts_read_vrlsb[i] =
+				w83795_read(client, W83795_REG_VRLSB);
+		}
+	}
+
+	/* Update pwm output */
+	for (i = 0; i < data->has_pwm; i++) {
+		data->pwm[i][PWM_OUTPUT] =
+		    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
+	}
+
+	/* Update intrusion and alarms
+	 * It is important to read intrusion first, because reading from
+	 * register SMI STS6 clears the interrupt status temporarily. */
+	tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
+	/* Switch to interrupt status for intrusion if needed */
+	if (tmp & ALARM_CTRL_RTSACS)
+		w83795_write(client, W83795_REG_ALARM_CTRL,
+			     tmp & ~ALARM_CTRL_RTSACS);
+	intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6);
+	/* Switch to real-time alarms */
+	w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS);
+	for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
+		data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
+	data->alarms[5] |= intrusion;
+	/* Restore original configuration if needed */
+	if (!(tmp & ALARM_CTRL_RTSACS))
+		w83795_write(client, W83795_REG_ALARM_CTRL,
+			     tmp & ~ALARM_CTRL_RTSACS);
+
+	data->last_updated = jiffies;
+	data->valid = 1;
+
+END:
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/*
+ * Sysfs attributes
+ */
+
+#define ALARM_STATUS      0
+#define BEEP_ENABLE       1
+static ssize_t
+show_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_device(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index >> 3;
+	int bit = sensor_attr->index & 0x07;
+	u8 val;
+
+	if (nr == ALARM_STATUS)
+		val = (data->alarms[index] >> bit) & 1;
+	else		/* BEEP_ENABLE */
+		val = (data->beeps[index] >> bit) & 1;
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index >> 3;
+	int shift = sensor_attr->index & 0x07;
+	u8 beep_bit = 1 << shift;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index));
+	data->beeps[index] &= ~beep_bit;
+	data->beeps[index] |= val << shift;
+	w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* Write 0 to clear chassis alarm */
+static ssize_t
+store_chassis_clear(struct device *dev,
+		    struct device_attribute *attr, const char *buf,
+		    size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0 || val != 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	val = w83795_read(client, W83795_REG_CLR_CHASSIS);
+	val |= 0x80;
+	w83795_write(client, W83795_REG_CLR_CHASSIS, val);
+
+	/* Clear status and force cache refresh */
+	w83795_read(client, W83795_REG_ALARM(5));
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define FAN_INPUT     0
+#define FAN_MIN       1
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	u16 val;
+
+	if (nr == FAN_INPUT)
+		val = data->fan[index] & 0x0fff;
+	else
+		val = data->fan_min[index] & 0x0fff;
+
+	return sprintf(buf, "%lu\n", fan_from_reg(val));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+	val = fan_to_reg(val);
+
+	mutex_lock(&data->update_lock);
+	data->fan_min[index] = val;
+	w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff);
+	val &= 0x0f;
+	if (index & 1) {
+		val <<= 4;
+		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
+		       & 0x0f;
+	} else {
+		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
+		       & 0xf0;
+	}
+	w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data;
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned int val;
+
+	data = nr == PWM_OUTPUT ? w83795_update_device(dev)
+				: w83795_update_pwm_config(dev);
+
+	switch (nr) {
+	case PWM_STOP_TIME:
+		val = time_from_reg(data->pwm[index][nr]);
+		break;
+	case PWM_FREQ:
+		val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin);
+		break;
+	default:
+		val = data->pwm[index][nr];
+		break;
+	}
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case PWM_STOP_TIME:
+		val = time_to_reg(val);
+		break;
+	case PWM_FREQ:
+		val = pwm_freq_to_reg(val, data->clkin);
+		break;
+	default:
+		val = SENSORS_LIMIT(val, 0, 0xff);
+		break;
+	}
+	w83795_write(client, W83795_REG_PWM(index, nr), val);
+	data->pwm[index][nr] = val;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = sensor_attr->index;
+	u8 tmp;
+
+	/* Speed cruise mode */
+	if (data->pwm_fcms[0] & (1 << index)) {
+		tmp = 2;
+		goto out;
+	}
+	/* Thermal cruise or SmartFan IV mode */
+	for (tmp = 0; tmp < 6; tmp++) {
+		if (data->pwm_tfmr[tmp] & (1 << index)) {
+			tmp = 3;
+			goto out;
+		}
+	}
+	/* Manual mode */
+	tmp = 1;
+
+out:
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	unsigned long val;
+	int i;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if (val < 1 || val > 2)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (val) {
+	case 1:
+		/* Clear speed cruise mode bits */
+		data->pwm_fcms[0] &= ~(1 << index);
+		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+		/* Clear thermal cruise mode bits */
+		for (i = 0; i < 6; i++) {
+			data->pwm_tfmr[i] &= ~(1 << index);
+			w83795_write(client, W83795_REG_TFMR(i),
+				data->pwm_tfmr[i]);
+		}
+		break;
+	case 2:
+		data->pwm_fcms[0] |= (1 << index);
+		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
+		break;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = to_sensor_dev_attr_2(attr)->index;
+	unsigned int mode;
+
+	if (data->pwm_fomc & (1 << index))
+		mode = 0;	/* DC */
+	else
+		mode = 1;	/* PWM */
+
+	return sprintf(buf, "%u\n", mode);
+}
+
+/*
+ * Check whether a given temperature source can ever be useful.
+ * Returns the number of selectable temperature channels which are
+ * enabled.
+ */
+static int w83795_tss_useful(const struct w83795_data *data, int tsrc)
+{
+	int useful = 0, i;
+
+	for (i = 0; i < 4; i++) {
+		if (tss_map[i][tsrc] == TSS_MAP_RESERVED)
+			continue;
+		if (tss_map[i][tsrc] < 6)	/* Analog */
+			useful += (data->has_temp >> tss_map[i][tsrc]) & 1;
+		else				/* Digital */
+			useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
+	}
+
+	return useful;
+}
+
+static ssize_t
+show_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	int index = sensor_attr->index;
+	u8 tmp = data->temp_src[index / 2];
+
+	if (index & 1)
+		tmp >>= 4;	/* Pick high nibble */
+	else
+		tmp &= 0x0f;	/* Pick low nibble */
+
+	/* Look-up the actual temperature channel number */
+	if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED)
+		return -EINVAL;		/* Shouldn't happen */
+
+	return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1);
+}
+
+static ssize_t
+store_temp_src(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int tmp;
+	unsigned long channel;
+	u8 val = index / 2;
+
+	if (strict_strtoul(buf, 10, &channel) < 0 ||
+	    channel < 1 || channel > 14)
+		return -EINVAL;
+
+	/* Check if request can be fulfilled */
+	for (tmp = 0; tmp < 4; tmp++) {
+		if (tss_map[tmp][index] == channel - 1)
+			break;
+	}
+	if (tmp == 4)	/* No match */
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (index & 1) {
+		tmp <<= 4;
+		data->temp_src[val] &= 0x0f;
+	} else {
+		data->temp_src[val] &= 0xf0;
+	}
+	data->temp_src[val] |= tmp;
+	w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+#define TEMP_PWM_ENABLE   0
+#define TEMP_PWM_FAN_MAP  1
+static ssize_t
+show_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	u8 tmp = 0xff;
+
+	switch (nr) {
+	case TEMP_PWM_ENABLE:
+		tmp = (data->pwm_fcms[1] >> index) & 1;
+		if (tmp)
+			tmp = 4;
+		else
+			tmp = 3;
+		break;
+	case TEMP_PWM_FAN_MAP:
+		tmp = data->pwm_tfmr[index];
+		break;
+	}
+
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long tmp;
+
+	if (strict_strtoul(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	switch (nr) {
+	case TEMP_PWM_ENABLE:
+		if (tmp != 3 && tmp != 4)
+			return -EINVAL;
+		tmp -= 3;
+		mutex_lock(&data->update_lock);
+		data->pwm_fcms[1] &= ~(1 << index);
+		data->pwm_fcms[1] |= tmp << index;
+		w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]);
+		mutex_unlock(&data->update_lock);
+		break;
+	case TEMP_PWM_FAN_MAP:
+		mutex_lock(&data->update_lock);
+		tmp = SENSORS_LIMIT(tmp, 0, 0xff);
+		w83795_write(client, W83795_REG_TFMR(index), tmp);
+		data->pwm_tfmr[index] = tmp;
+		mutex_unlock(&data->update_lock);
+		break;
+	}
+	return count;
+}
+
+#define FANIN_TARGET   0
+#define FANIN_TOL      1
+static ssize_t
+show_fanin(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	u16 tmp = 0;
+
+	switch (nr) {
+	case FANIN_TARGET:
+		tmp = fan_from_reg(data->target_speed[index]);
+		break;
+	case FANIN_TOL:
+		tmp = data->tol_speed;
+		break;
+	}
+
+	return sprintf(buf, "%u\n", tmp);
+}
+
+static ssize_t
+store_fanin(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case FANIN_TARGET:
+		val = fan_to_reg(SENSORS_LIMIT(val, 0, 0xfff));
+		w83795_write(client, W83795_REG_FTSH(index), val >> 4);
+		w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
+		data->target_speed[index] = val;
+		break;
+	case FANIN_TOL:
+		val = SENSORS_LIMIT(val, 0, 0x3f);
+		w83795_write(client, W83795_REG_TFTS, val);
+		data->tol_speed = val;
+		break;
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static ssize_t
+show_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	long tmp = temp_from_reg(data->pwm_temp[index][nr]);
+
+	return sprintf(buf, "%ld\n", tmp);
+}
+
+static ssize_t
+store_temp_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+	u8 tmp;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+	switch (nr) {
+	case TEMP_PWM_TTTI:
+		val = SENSORS_LIMIT(val, 0, 0x7f);
+		w83795_write(client, W83795_REG_TTTI(index), val);
+		break;
+	case TEMP_PWM_CTFS:
+		val = SENSORS_LIMIT(val, 0, 0x7f);
+		w83795_write(client, W83795_REG_CTFS(index), val);
+		break;
+	case TEMP_PWM_HCT:
+		val = SENSORS_LIMIT(val, 0, 0x0f);
+		tmp = w83795_read(client, W83795_REG_HT(index));
+		tmp &= 0x0f;
+		tmp |= (val << 4) & 0xf0;
+		w83795_write(client, W83795_REG_HT(index), tmp);
+		break;
+	case TEMP_PWM_HOT:
+		val = SENSORS_LIMIT(val, 0, 0x0f);
+		tmp = w83795_read(client, W83795_REG_HT(index));
+		tmp &= 0xf0;
+		tmp |= val & 0x0f;
+		w83795_write(client, W83795_REG_HT(index), tmp);
+		break;
+	}
+	data->pwm_temp[index][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+
+	return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]);
+}
+
+static ssize_t
+store_sf4_pwm(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	w83795_write(client, W83795_REG_SF4_PWM(index, nr), val);
+	data->sf4_reg[index][SF4_PWM][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t
+show_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+
+	return sprintf(buf, "%u\n",
+		(data->sf4_reg[index][SF4_TEMP][nr]) * 1000);
+}
+
+static ssize_t
+store_sf4_temp(struct device *dev, struct device_attribute *attr,
+	  const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val /= 1000;
+
+	mutex_lock(&data->update_lock);
+	w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val);
+	data->sf4_reg[index][SF4_TEMP][nr] = val;
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	long temp = temp_from_reg(data->temp[index][nr]);
+
+	if (nr == TEMP_READ)
+		temp += (data->temp_read_vrlsb[index] >> 6) * 250;
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	long tmp;
+
+	if (strict_strtol(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->temp[index][nr] = temp_to_reg(tmp, -128, 127);
+	w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+static ssize_t
+show_dts_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	int tmp;
+
+	if (data->enable_dts & 2)
+		tmp = 5;
+	else
+		tmp = 6;
+
+	return sprintf(buf, "%d\n", tmp);
+}
+
+static ssize_t
+show_dts(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	long temp = temp_from_reg(data->dts[index]);
+
+	temp += (data->dts_read_vrlsb[index] >> 6) * 250;
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+show_dts_ext(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct w83795_data *data = dev_get_drvdata(dev);
+	long temp = temp_from_reg(data->dts_ext[nr]);
+
+	return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t
+store_dts_ext(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	long tmp;
+
+	if (strict_strtol(buf, 10, &tmp) < 0)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	data->dts_ext[nr] = temp_to_reg(tmp, -128, 127);
+	w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+static ssize_t
+show_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int tmp;
+
+	if (data->temp_mode & (1 << index))
+		tmp = 3;	/* Thermal diode */
+	else
+		tmp = 4;	/* Thermistor */
+
+	return sprintf(buf, "%d\n", tmp);
+}
+
+/* Only for temp1-4 (temp5-6 can only be thermistor) */
+static ssize_t
+store_temp_mode(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int index = sensor_attr->index;
+	int reg_shift;
+	unsigned long val;
+	u8 tmp;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	if ((val != 4) && (val != 3))
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	if (val == 3) {
+		/* Thermal diode */
+		val = 0x01;
+		data->temp_mode |= 1 << index;
+	} else if (val == 4) {
+		/* Thermistor */
+		val = 0x03;
+		data->temp_mode &= ~(1 << index);
+	}
+
+	reg_shift = 2 * index;
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
+	tmp &= ~(0x03 << reg_shift);
+	tmp |= val << reg_shift;
+	w83795_write(client, W83795_REG_TEMP_CTRL2, tmp);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+/* show/store VIN */
+static ssize_t
+show_in(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct w83795_data *data = w83795_update_device(dev);
+	u16 val = data->in[index][nr];
+	u8 lsb_idx;
+
+	switch (nr) {
+	case IN_READ:
+		/* calculate this value again by sensors as sensors3.conf */
+		if ((index >= 17) &&
+		    !((data->has_gain >> (index - 17)) & 1))
+			val *= 8;
+		break;
+	case IN_MAX:
+	case IN_LOW:
+		lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
+		val <<= 2;
+		val |= (data->in_lsb[lsb_idx][nr] >>
+			IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03;
+		if ((index >= 17) &&
+		    !((data->has_gain >> (index - 17)) & 1))
+			val *= 8;
+		break;
+	}
+	val = in_from_reg(index, val);
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_in(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	int index = sensor_attr->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+	u8 tmp;
+	u8 lsb_idx;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+	val = in_to_reg(index, val);
+
+	if ((index >= 17) &&
+	    !((data->has_gain >> (index - 17)) & 1))
+		val /= 8;
+	val = SENSORS_LIMIT(val, 0, 0x3FF);
+	mutex_lock(&data->update_lock);
+
+	lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
+	tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr));
+	tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]);
+	tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT];
+	w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp);
+	data->in_lsb[lsb_idx][nr] = tmp;
+
+	tmp = (val >> 2) & 0xff;
+	w83795_write(client, W83795_REG_IN[index][nr], tmp);
+	data->in[index][nr] = tmp;
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+static ssize_t
+show_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct w83795_data *data = w83795_update_pwm_config(dev);
+	u16 val = data->setup_pwm[nr];
+
+	switch (nr) {
+	case SETUP_PWM_UPTIME:
+	case SETUP_PWM_DOWNTIME:
+		val = time_from_reg(val);
+		break;
+	}
+
+	return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t
+store_sf_setup(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *sensor_attr =
+	    to_sensor_dev_attr_2(attr);
+	int nr = sensor_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83795_data *data = i2c_get_clientdata(client);
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val) < 0)
+		return -EINVAL;
+
+	switch (nr) {
+	case SETUP_PWM_DEFAULT:
+		val = SENSORS_LIMIT(val, 0, 0xff);
+		break;
+	case SETUP_PWM_UPTIME:
+	case SETUP_PWM_DOWNTIME:
+		val = time_to_reg(val);
+		if (val == 0)
+			return -EINVAL;
+		break;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->setup_pwm[nr] = val;
+	w83795_write(client, W83795_REG_SETUP_PWM(nr), val);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+#endif
+
+
+#define NOT_USED			-1
+
+/* Don't change the attribute order, _max, _min and _beep are accessed by index
+ * somewhere else in the code */
+#define SENSOR_ATTR_IN(index) {						\
+	SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,	\
+		IN_READ, index), \
+	SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_MAX, index),				\
+	SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in,	\
+		store_in, IN_LOW, index),				\
+	SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \
+	SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE,		\
+		index + ((index > 14) ? 1 : 0)) }
+
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
+#define SENSOR_ATTR_FAN(index) {					\
+	SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,		\
+		NULL, FAN_INPUT, index - 1), \
+	SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO,		\
+		show_fan, store_fan_min, FAN_MIN, index - 1),	\
+	SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep,	\
+		NULL, ALARM_STATUS, index + 31),			\
+	SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) }
+
+#define SENSOR_ATTR_PWM(index) {					\
+	SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,		\
+		store_pwm, PWM_OUTPUT, index - 1),			\
+	SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_NONSTOP, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,		\
+		show_pwm, store_pwm, PWM_START, index - 1),		\
+	SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,	\
+		show_pwm, store_pwm, PWM_STOP_TIME, index - 1),	 \
+	SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,	\
+		show_pwm, store_pwm, PWM_FREQ, index - 1),	 \
+	SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,		\
+		show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
+	SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,			\
+		show_pwm_mode, NULL, NOT_USED, index - 1),		\
+	SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
+		show_fanin, store_fanin, FANIN_TARGET, index - 1) }
+
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
+#define SENSOR_ATTR_DTS(index) {					\
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,		\
+		show_dts_mode, NULL, NOT_USED, index - 7),	\
+	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts,		\
+		NULL, NOT_USED, index - 7),				\
+	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \
+		store_dts_ext, DTS_CRIT, NOT_USED),			\
+	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
+		show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED),	\
+	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \
+		store_dts_ext, DTS_WARN, NOT_USED),			\
+	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED),	\
+	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
+		show_alarm_beep, NULL, ALARM_STATUS, index + 17),	\
+	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
+
+/* Don't change the attribute order, _beep is accessed by index
+ * somewhere else in the code */
+#define SENSOR_ATTR_TEMP(index) {					\
+	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
+		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp,		\
+		NULL, TEMP_READ, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_CRIT, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_CRIT_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp,	\
+		store_temp, TEMP_WARN, index - 1),			\
+	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp, store_temp, TEMP_WARN_HYST, index - 1),	\
+	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
+		show_alarm_beep, NULL, ALARM_STATUS,			\
+		index + (index > 4 ? 11 : 17)),				\
+	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
+		show_alarm_beep, store_beep, BEEP_ENABLE,		\
+		index + (index > 4 ? 11 : 17)),				\
+	SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm_enable, store_temp_pwm_enable,		\
+		TEMP_PWM_ENABLE, index - 1),				\
+	SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \
+		show_temp_pwm_enable, store_temp_pwm_enable,		\
+		TEMP_PWM_FAN_MAP, index - 1),				\
+	SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO,		\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \
+	SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO,		\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \
+	SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \
+	SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO,	\
+		show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \
+	SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
+		show_sf4_pwm, store_sf4_pwm, 6, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 0, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 1, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 2, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 3, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 4, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 5, index - 1),		\
+	SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
+		show_sf4_temp, store_sf4_temp, 6, index - 1) }
+
+
+static struct sensor_device_attribute_2 w83795_in[][5] = {
+	SENSOR_ATTR_IN(0),
+	SENSOR_ATTR_IN(1),
+	SENSOR_ATTR_IN(2),
+	SENSOR_ATTR_IN(3),
+	SENSOR_ATTR_IN(4),
+	SENSOR_ATTR_IN(5),
+	SENSOR_ATTR_IN(6),
+	SENSOR_ATTR_IN(7),
+	SENSOR_ATTR_IN(8),
+	SENSOR_ATTR_IN(9),
+	SENSOR_ATTR_IN(10),
+	SENSOR_ATTR_IN(11),
+	SENSOR_ATTR_IN(12),
+	SENSOR_ATTR_IN(13),
+	SENSOR_ATTR_IN(14),
+	SENSOR_ATTR_IN(15),
+	SENSOR_ATTR_IN(16),
+	SENSOR_ATTR_IN(17),
+	SENSOR_ATTR_IN(18),
+	SENSOR_ATTR_IN(19),
+	SENSOR_ATTR_IN(20),
+};
+
+static const struct sensor_device_attribute_2 w83795_fan[][4] = {
+	SENSOR_ATTR_FAN(1),
+	SENSOR_ATTR_FAN(2),
+	SENSOR_ATTR_FAN(3),
+	SENSOR_ATTR_FAN(4),
+	SENSOR_ATTR_FAN(5),
+	SENSOR_ATTR_FAN(6),
+	SENSOR_ATTR_FAN(7),
+	SENSOR_ATTR_FAN(8),
+	SENSOR_ATTR_FAN(9),
+	SENSOR_ATTR_FAN(10),
+	SENSOR_ATTR_FAN(11),
+	SENSOR_ATTR_FAN(12),
+	SENSOR_ATTR_FAN(13),
+	SENSOR_ATTR_FAN(14),
+};
+
+static const struct sensor_device_attribute_2 w83795_temp[][28] = {
+	SENSOR_ATTR_TEMP(1),
+	SENSOR_ATTR_TEMP(2),
+	SENSOR_ATTR_TEMP(3),
+	SENSOR_ATTR_TEMP(4),
+	SENSOR_ATTR_TEMP(5),
+	SENSOR_ATTR_TEMP(6),
+};
+
+static const struct sensor_device_attribute_2 w83795_dts[][8] = {
+	SENSOR_ATTR_DTS(7),
+	SENSOR_ATTR_DTS(8),
+	SENSOR_ATTR_DTS(9),
+	SENSOR_ATTR_DTS(10),
+	SENSOR_ATTR_DTS(11),
+	SENSOR_ATTR_DTS(12),
+	SENSOR_ATTR_DTS(13),
+	SENSOR_ATTR_DTS(14),
+};
+
+static const struct sensor_device_attribute_2 w83795_pwm[][8] = {
+	SENSOR_ATTR_PWM(1),
+	SENSOR_ATTR_PWM(2),
+	SENSOR_ATTR_PWM(3),
+	SENSOR_ATTR_PWM(4),
+	SENSOR_ATTR_PWM(5),
+	SENSOR_ATTR_PWM(6),
+	SENSOR_ATTR_PWM(7),
+	SENSOR_ATTR_PWM(8),
+};
+
+static const struct sensor_device_attribute_2 w83795_tss[6] = {
+	SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 0),
+	SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 1),
+	SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 2),
+	SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 3),
+	SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 4),
+	SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO,
+		      show_temp_src, store_temp_src, NOT_USED, 5),
+};
+
+static const struct sensor_device_attribute_2 sda_single_files[] = {
+	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_chassis_clear, ALARM_STATUS, 46),
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+	SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
+		store_fanin, FANIN_TOL, NOT_USED),
+	SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
+	SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
+	SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
+		      store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
+#endif
+};
+
+static const struct sensor_device_attribute_2 sda_beep_files[] = {
+	SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_beep, BEEP_ENABLE, 46),
+	SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
+		      store_beep, BEEP_ENABLE, 47),
+};
+
+/*
+ * Driver interface
+ */
+
+static void w83795_init_client(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	static const u16 clkin[4] = {	/* in kHz */
+		14318, 24000, 33333, 48000
+	};
+	u8 config;
+
+	if (reset)
+		w83795_write(client, W83795_REG_CONFIG, 0x80);
+
+	/* Start monitoring if needed */
+	config = w83795_read(client, W83795_REG_CONFIG);
+	if (!(config & W83795_REG_CONFIG_START)) {
+		dev_info(&client->dev, "Enabling monitoring operations\n");
+		w83795_write(client, W83795_REG_CONFIG,
+			     config | W83795_REG_CONFIG_START);
+	}
+
+	data->clkin = clkin[(config >> 3) & 0x3];
+	dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin);
+}
+
+static int w83795_get_device_id(struct i2c_client *client)
+{
+	int device_id;
+
+	device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
+
+	/* Special case for rev. A chips; can't be checked first because later
+	   revisions emulate this for compatibility */
+	if (device_id < 0 || (device_id & 0xf0) != 0x50) {
+		int alt_id;
+
+		alt_id = i2c_smbus_read_byte_data(client,
+						  W83795_REG_DEVICEID_A);
+		if (alt_id == 0x50)
+			device_id = alt_id;
+	}
+
+	return device_id;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int w83795_detect(struct i2c_client *client,
+			 struct i2c_board_info *info)
+{
+	int bank, vendor_id, device_id, expected, i2c_addr, config;
+	struct i2c_adapter *adapter = client->adapter;
+	unsigned short address = client->addr;
+	const char *chip_name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -ENODEV;
+	bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
+	if (bank < 0 || (bank & 0x7c)) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "bank");
+		return -ENODEV;
+	}
+
+	/* Check Nuvoton vendor ID */
+	vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID);
+	expected = bank & 0x80 ? 0x5c : 0xa3;
+	if (vendor_id != expected) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "vendor id");
+		return -ENODEV;
+	}
+
+	/* Check device ID */
+	device_id = w83795_get_device_id(client) |
+		    (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8);
+	if ((device_id >> 4) != 0x795) {
+		dev_dbg(&adapter->dev,
+			"w83795: Detection failed at addr 0x%02hx, check %s\n",
+			address, "device id\n");
+		return -ENODEV;
+	}
+
+	/* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
+	   should match */
+	if ((bank & 0x07) == 0) {
+		i2c_addr = i2c_smbus_read_byte_data(client,
+						    W83795_REG_I2C_ADDR);
+		if ((i2c_addr & 0x7f) != address) {
+			dev_dbg(&adapter->dev,
+				"w83795: Detection failed at addr 0x%02hx, "
+				"check %s\n", address, "i2c addr");
+			return -ENODEV;
+		}
+	}
+
+	/* Check 795 chip type: 795G or 795ADG
+	   Usually we don't write to chips during detection, but here we don't
+	   quite have the choice; hopefully it's OK, we are about to return
+	   success anyway */
+	if ((bank & 0x07) != 0)
+		i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
+					  bank & ~0x07);
+	config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG);
+	if (config & W83795_REG_CONFIG_CONFIG48)
+		chip_name = "w83795adg";
+	else
+		chip_name = "w83795g";
+
+	strlcpy(info->type, chip_name, I2C_NAME_SIZE);
+	dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name,
+		 'A' + (device_id & 0xf), address);
+
+	return 0;
+}
+
+static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
+			       const struct device_attribute *))
+{
+	struct w83795_data *data = dev_get_drvdata(dev);
+	int err, i, j;
+
+	for (i = 0; i < ARRAY_SIZE(w83795_in); i++) {
+		if (!(data->has_in & (1 << i)))
+			continue;
+		for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) {
+			if (j == 4 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_in[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) {
+		if (!(data->has_fan & (1 << i)))
+			continue;
+		for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) {
+			if (j == 3 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_fan[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
+		j = w83795_tss_useful(data, i);
+		if (!j)
+			continue;
+		err = fn(dev, &w83795_tss[i].dev_attr);
+		if (err)
+			return err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
+		err = fn(dev, &sda_single_files[i].dev_attr);
+		if (err)
+			return err;
+	}
+
+	if (data->enable_beep) {
+		for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
+			err = fn(dev, &sda_beep_files[i].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+	for (i = 0; i < data->has_pwm; i++) {
+		for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
+			err = fn(dev, &w83795_pwm[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+#endif
+
+	for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
+		if (!(data->has_temp & (1 << i)))
+			continue;
+#ifdef CONFIG_SENSORS_W83795_FANCTRL
+		for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) {
+#else
+		for (j = 0; j < 8; j++) {
+#endif
+			if (j == 7 && !data->enable_beep)
+				continue;
+			err = fn(dev, &w83795_temp[i][j].dev_attr);
+			if (err)
+				return err;
+		}
+	}
+
+	if (data->enable_dts) {
+		for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) {
+				if (j == 7 && !data->enable_beep)
+					continue;
+				err = fn(dev, &w83795_dts[i][j].dev_attr);
+				if (err)
+					return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* We need a wrapper that fits in w83795_handle_files */
+static int device_remove_file_wrapper(struct device *dev,
+				      const struct device_attribute *attr)
+{
+	device_remove_file(dev, attr);
+	return 0;
+}
+
+static void w83795_check_dynamic_in_limits(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+	u8 vid_ctl;
+	int i, err_max, err_min;
+
+	vid_ctl = w83795_read(client, W83795_REG_VID_CTRL);
+
+	/* Return immediately if VRM isn't configured */
+	if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07)
+		return;
+
+	data->has_dyn_in = (vid_ctl >> 3) & 0x07;
+	for (i = 0; i < 2; i++) {
+		if (!(data->has_dyn_in & (1 << i)))
+			continue;
+
+		/* Voltage limits in dynamic mode, switch to read-only */
+		err_max = sysfs_chmod_file(&client->dev.kobj,
+					   &w83795_in[i][2].dev_attr.attr,
+					   S_IRUGO);
+		err_min = sysfs_chmod_file(&client->dev.kobj,
+					   &w83795_in[i][3].dev_attr.attr,
+					   S_IRUGO);
+		if (err_max || err_min)
+			dev_warn(&client->dev, "Failed to set in%d limits "
+				 "read-only (%d, %d)\n", i, err_max, err_min);
+		else
+			dev_info(&client->dev, "in%d limits set dynamically "
+				 "from VID\n", i);
+	}
+}
+
+/* Check pins that can be used for either temperature or voltage monitoring */
+static void w83795_apply_temp_config(struct w83795_data *data, u8 config,
+				     int temp_chan, int in_chan)
+{
+	/* config is a 2-bit value */
+	switch (config) {
+	case 0x2: /* Voltage monitoring */
+		data->has_in |= 1 << in_chan;
+		break;
+	case 0x1: /* Thermal diode */
+		if (temp_chan >= 4)
+			break;
+		data->temp_mode |= 1 << temp_chan;
+		/* fall through */
+	case 0x3: /* Thermistor */
+		data->has_temp |= 1 << temp_chan;
+		break;
+	}
+}
+
+static int w83795_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	int i;
+	u8 tmp;
+	struct device *dev = &client->dev;
+	struct w83795_data *data;
+	int err;
+
+	data = kzalloc(sizeof(struct w83795_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(client, data);
+	data->chip_type = id->driver_data;
+	data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
+	mutex_init(&data->update_lock);
+
+	/* Initialize the chip */
+	w83795_init_client(client);
+
+	/* Check which voltages and fans are present */
+	data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1)
+		     | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8);
+	data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1)
+		      | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8);
+
+	/* Check which analog temperatures and extra voltages are present */
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL1);
+	if (tmp & 0x20)
+		data->enable_dts = 1;
+	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16);
+	w83795_apply_temp_config(data, tmp & 0x3, 4, 15);
+	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
+	w83795_apply_temp_config(data, tmp >> 6, 3, 20);
+	w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19);
+	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18);
+	w83795_apply_temp_config(data, tmp & 0x3, 0, 17);
+
+	/* Check DTS enable status */
+	if (data->enable_dts) {
+		if (1 & w83795_read(client, W83795_REG_DTSC))
+			data->enable_dts |= 2;
+		data->has_dts = w83795_read(client, W83795_REG_DTSE);
+	}
+
+	/* Report PECI Tbase values */
+	if (data->enable_dts == 1) {
+		for (i = 0; i < 8; i++) {
+			if (!(data->has_dts & (1 << i)))
+				continue;
+			tmp = w83795_read(client, W83795_REG_PECI_TBASE(i));
+			dev_info(&client->dev,
+				 "PECI agent %d Tbase temperature: %u\n",
+				 i + 1, (unsigned int)tmp & 0x7f);
+		}
+	}
+
+	data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f;
+
+	/* pwm and smart fan */
+	if (data->chip_type == w83795g)
+		data->has_pwm = 8;
+	else
+		data->has_pwm = 2;
+
+	/* Check if BEEP pin is available */
+	if (data->chip_type == w83795g) {
+		/* The W83795G has a dedicated BEEP pin */
+		data->enable_beep = 1;
+	} else {
+		/* The W83795ADG has a shared pin for OVT# and BEEP, so you
+		 * can't have both */
+		tmp = w83795_read(client, W83795_REG_OVT_CFG);
+		if ((tmp & OVT_CFG_SEL) == 0)
+			data->enable_beep = 1;
+	}
+
+	err = w83795_handle_files(dev, device_create_file);
+	if (err)
+		goto exit_remove;
+
+	if (data->chip_type == w83795g)
+		w83795_check_dynamic_in_limits(client);
+
+	data->hwmon_dev = hwmon_device_register(dev);
+	if (IS_ERR(data->hwmon_dev)) {
+		err = PTR_ERR(data->hwmon_dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	w83795_handle_files(dev, device_remove_file_wrapper);
+	kfree(data);
+exit:
+	return err;
+}
+
+static int w83795_remove(struct i2c_client *client)
+{
+	struct w83795_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	w83795_handle_files(&client->dev, device_remove_file_wrapper);
+	kfree(data);
+
+	return 0;
+}
+
+
+static const struct i2c_device_id w83795_id[] = {
+	{ "w83795g", w83795g },
+	{ "w83795adg", w83795adg },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, w83795_id);
+
+static struct i2c_driver w83795_driver = {
+	.driver = {
+		   .name = "w83795",
+	},
+	.probe		= w83795_probe,
+	.remove		= w83795_remove,
+	.id_table	= w83795_id,
+
+	.class		= I2C_CLASS_HWMON,
+	.detect		= w83795_detect,
+	.address_list	= normal_i2c,
+};
+
+static int __init sensors_w83795_init(void)
+{
+	return i2c_add_driver(&w83795_driver);
+}
+
+static void __exit sensors_w83795_exit(void)
+{
+	i2c_del_driver(&w83795_driver);
+}
+
+MODULE_AUTHOR("Wei Song, Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_w83795_init);
+module_exit(sensors_w83795_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/algos/Kconfig linux-libre-2.6.37-gnu/drivers/i2c/algos/Kconfig
--- linux-libre-2.6.36-gnu/drivers/i2c/algos/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/algos/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -3,7 +3,7 @@
 #
 
 menu "I2C Algorithms"
-	depends on !I2C_HELPER_AUTO
+	visible if !I2C_HELPER_AUTO
 
 config I2C_ALGOBIT
 	tristate "I2C bit-banging interfaces"
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/algos/Makefile linux-libre-2.6.37-gnu/drivers/i2c/algos/Makefile
--- linux-libre-2.6.36-gnu/drivers/i2c/algos/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/algos/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -6,6 +6,4 @@
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
 
-ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-amd8111.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-amd8111.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-amd8111.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-amd8111.c	2011-01-04 19:50:19.000000000 -0500
@@ -69,7 +69,7 @@
  * ACPI 2.0 chapter 13 access of registers of the EC
  */
 
-static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
+static int amd_ec_wait_write(struct amd_smbus *smbus)
 {
 	int timeout = 500;
 
@@ -85,7 +85,7 @@
 	return 0;
 }
 
-static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
+static int amd_ec_wait_read(struct amd_smbus *smbus)
 {
 	int timeout = 500;
 
@@ -101,7 +101,7 @@
 	return 0;
 }
 
-static unsigned int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
 		unsigned char *data)
 {
 	int status;
@@ -124,7 +124,7 @@
 	return 0;
 }
 
-static unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
 		unsigned char data)
 {
 	int status;
@@ -196,7 +196,7 @@
 {
 	struct amd_smbus *smbus = adap->algo_data;
 	unsigned char protocol, len, pec, temp[2];
-	int i;
+	int i, status;
 
 	protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
 						  : AMD_SMB_PRTCL_WRITE;
@@ -209,38 +209,62 @@
 			break;
 
 		case I2C_SMBUS_BYTE:
-			if (read_write == I2C_SMBUS_WRITE)
-				amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE) {
+				status = amd_ec_write(smbus, AMD_SMB_CMD,
+						      command);
+				if (status)
+					return status;
+			}
 			protocol |= AMD_SMB_PRTCL_BYTE;
 			break;
 
 		case I2C_SMBUS_BYTE_DATA:
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
-			if (read_write == I2C_SMBUS_WRITE)
-				amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			if (read_write == I2C_SMBUS_WRITE) {
+				status = amd_ec_write(smbus, AMD_SMB_DATA,
+						      data->byte);
+				if (status)
+					return status;
+			}
 			protocol |= AMD_SMB_PRTCL_BYTE_DATA;
 			break;
 
 		case I2C_SMBUS_WORD_DATA:
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
 			if (read_write == I2C_SMBUS_WRITE) {
-				amd_ec_write(smbus, AMD_SMB_DATA,
-					     data->word & 0xff);
-				amd_ec_write(smbus, AMD_SMB_DATA + 1,
-					     data->word >> 8);
+				status = amd_ec_write(smbus, AMD_SMB_DATA,
+						      data->word & 0xff);
+				if (status)
+					return status;
+				status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+						      data->word >> 8);
+				if (status)
+					return status;
 			}
 			protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
 			break;
 
 		case I2C_SMBUS_BLOCK_DATA:
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
 			if (read_write == I2C_SMBUS_WRITE) {
 				len = min_t(u8, data->block[0],
 					    I2C_SMBUS_BLOCK_MAX);
-				amd_ec_write(smbus, AMD_SMB_BCNT, len);
-				for (i = 0; i < len; i++)
-					amd_ec_write(smbus, AMD_SMB_DATA + i,
-						     data->block[i + 1]);
+				status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+				if (status)
+					return status;
+				for (i = 0; i < len; i++) {
+					status =
+					  amd_ec_write(smbus, AMD_SMB_DATA + i,
+						       data->block[i + 1]);
+					if (status)
+						return status;
+				}
 			}
 			protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
 			break;
@@ -248,19 +272,35 @@
 		case I2C_SMBUS_I2C_BLOCK_DATA:
 			len = min_t(u8, data->block[0],
 				    I2C_SMBUS_BLOCK_MAX);
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
-			amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			if (status)
+				return status;
 			if (read_write == I2C_SMBUS_WRITE)
-				for (i = 0; i < len; i++)
-					amd_ec_write(smbus, AMD_SMB_DATA + i,
-						     data->block[i + 1]);
+				for (i = 0; i < len; i++) {
+					status =
+					  amd_ec_write(smbus, AMD_SMB_DATA + i,
+						       data->block[i + 1]);
+					if (status)
+						return status;
+				}
 			protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
 			break;
 
 		case I2C_SMBUS_PROC_CALL:
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
-			amd_ec_write(smbus, AMD_SMB_DATA, data->word & 0xff);
-			amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_DATA,
+					      data->word & 0xff);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+					      data->word >> 8);
+			if (status)
+				return status;
 			protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
 			read_write = I2C_SMBUS_READ;
 			break;
@@ -268,11 +308,18 @@
 		case I2C_SMBUS_BLOCK_PROC_CALL:
 			len = min_t(u8, data->block[0],
 				    I2C_SMBUS_BLOCK_MAX - 1);
-			amd_ec_write(smbus, AMD_SMB_CMD, command);
-			amd_ec_write(smbus, AMD_SMB_BCNT, len);
-			for (i = 0; i < len; i++)
-				amd_ec_write(smbus, AMD_SMB_DATA + i,
-					     data->block[i + 1]);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			if (status)
+				return status;
+			for (i = 0; i < len; i++) {
+				status = amd_ec_write(smbus, AMD_SMB_DATA + i,
+						      data->block[i + 1]);
+				if (status)
+					return status;
+			}
 			protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
 			read_write = I2C_SMBUS_READ;
 			break;
@@ -282,24 +329,29 @@
 			return -EOPNOTSUPP;
 	}
 
-	amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
-	amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+	status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+	if (status)
+		return status;
+	status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+	if (status)
+		return status;
 
-	/* FIXME this discards status from ec_read(); so temp[0] will
-	 * hold stack garbage ... the rest of this routine will act
-	 * nonsensically.  Ignored ec_write() status might explain
-	 * some such failures...
-	 */
-	amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+	status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+	if (status)
+		return status;
 
 	if (~temp[0] & AMD_SMB_STS_DONE) {
 		udelay(500);
-		amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		if (status)
+			return status;
 	}
 
 	if (~temp[0] & AMD_SMB_STS_DONE) {
 		msleep(1);
-		amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		if (status)
+			return status;
 	}
 
 	if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
@@ -311,24 +363,35 @@
 	switch (size) {
 		case I2C_SMBUS_BYTE:
 		case I2C_SMBUS_BYTE_DATA:
-			amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+			status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+			if (status)
+				return status;
 			break;
 
 		case I2C_SMBUS_WORD_DATA:
 		case I2C_SMBUS_PROC_CALL:
-			amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
-			amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+			status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+			if (status)
+				return status;
+			status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+			if (status)
+				return status;
 			data->word = (temp[1] << 8) | temp[0];
 			break;
 
 		case I2C_SMBUS_BLOCK_DATA:
 		case I2C_SMBUS_BLOCK_PROC_CALL:
-			amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+			status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+			if (status)
+				return status;
 			len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
 		case I2C_SMBUS_I2C_BLOCK_DATA:
-			for (i = 0; i < len; i++)
-				amd_ec_read(smbus, AMD_SMB_DATA + i,
-					    data->block + i + 1);
+			for (i = 0; i < len; i++) {
+				status = amd_ec_read(smbus, AMD_SMB_DATA + i,
+						     data->block + i + 1);
+				if (status)
+					return status;
+			}
 			data->block[0] = len;
 			break;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-i801.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-i801.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-i801.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-i801.c	2011-01-04 19:50:19.000000000 -0500
@@ -3,6 +3,8 @@
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
     Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2010         Intel Corporation,
+                               David Woodhouse <dwmw2@infradead.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -38,11 +40,15 @@
   82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
   82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
   82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
-  Tolapai               0x5032     32     hard     yes     yes     yes
+  EP80579 (Tolapai)     0x5032     32     hard     yes     yes     yes
   ICH10                 0x3a30     32     hard     yes     yes     yes
   ICH10                 0x3a60     32     hard     yes     yes     yes
-  3400/5 Series (PCH)   0x3b30     32     hard     yes     yes     yes
+  5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes
   Cougar Point (PCH)    0x1c22     32     hard     yes     yes     yes
+  Patsburg (PCH)        0x1d22     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d70     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
@@ -50,12 +56,11 @@
   Block buffer                     yes
   Block process call transaction   no
   I2C block read transaction       yes  (doesn't use the block buffer)
+  Slave mode                       no
 
   See the file Documentation/i2c/busses/i2c-i801 for details.
 */
 
-/* Note: we assume there can only be one I801, with one SMBus interface */
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -69,16 +74,16 @@
 #include <linux/dmi.h>
 
 /* I801 SMBus address offsets */
-#define SMBHSTSTS	(0 + i801_smba)
-#define SMBHSTCNT	(2 + i801_smba)
-#define SMBHSTCMD	(3 + i801_smba)
-#define SMBHSTADD	(4 + i801_smba)
-#define SMBHSTDAT0	(5 + i801_smba)
-#define SMBHSTDAT1	(6 + i801_smba)
-#define SMBBLKDAT	(7 + i801_smba)
-#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
-#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
-#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
+#define SMBHSTSTS(p)	(0 + (p)->smba)
+#define SMBHSTCNT(p)	(2 + (p)->smba)
+#define SMBHSTCMD(p)	(3 + (p)->smba)
+#define SMBHSTADD(p)	(4 + (p)->smba)
+#define SMBHSTDAT0(p)	(5 + (p)->smba)
+#define SMBHSTDAT1(p)	(6 + (p)->smba)
+#define SMBBLKDAT(p)	(7 + (p)->smba)
+#define SMBPEC(p)	(8 + (p)->smba)		/* ICH3 and later */
+#define SMBAUXSTS(p)	(12 + (p)->smba)	/* ICH4 and later */
+#define SMBAUXCTL(p)	(13 + (p)->smba)	/* ICH4 and later */
 
 /* PCI Address Constants */
 #define SMBBAR		4
@@ -127,16 +132,25 @@
 				 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
 				 SMBHSTSTS_INTR)
 
-static unsigned long i801_smba;
-static unsigned char i801_original_hstcfg;
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0	0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1	0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2	0x1d72
+
+struct i801_priv {
+	struct i2c_adapter adapter;
+	unsigned long smba;
+	unsigned char original_hstcfg;
+	struct pci_dev *pci_dev;
+	unsigned int features;
+};
+
 static struct pci_driver i801_driver;
-static struct pci_dev *I801_dev;
 
 #define FEATURE_SMBUS_PEC	(1 << 0)
 #define FEATURE_BLOCK_BUFFER	(1 << 1)
 #define FEATURE_BLOCK_PROC	(1 << 2)
 #define FEATURE_I2C_BLOCK_READ	(1 << 3)
-static unsigned int i801_features;
 
 static const char *i801_feature_names[] = {
 	"SMBus PEC",
@@ -151,24 +165,24 @@
 
 /* Make sure the SMBus host is ready to start transmitting.
    Return 0 if it is, -EBUSY if it is not. */
-static int i801_check_pre(void)
+static int i801_check_pre(struct i801_priv *priv)
 {
 	int status;
 
-	status = inb_p(SMBHSTSTS);
+	status = inb_p(SMBHSTSTS(priv));
 	if (status & SMBHSTSTS_HOST_BUSY) {
-		dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
+		dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
 		return -EBUSY;
 	}
 
 	status &= STATUS_FLAGS;
 	if (status) {
-		dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
+		dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
 			status);
-		outb_p(status, SMBHSTSTS);
-		status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+		outb_p(status, SMBHSTSTS(priv));
+		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
 		if (status) {
-			dev_err(&I801_dev->dev,
+			dev_err(&priv->pci_dev->dev,
 				"Failed clearing status flags (%02x)\n",
 				status);
 			return -EBUSY;
@@ -179,48 +193,50 @@
 }
 
 /* Convert the status register to an error code, and clear it. */
-static int i801_check_post(int status, int timeout)
+static int i801_check_post(struct i801_priv *priv, int status, int timeout)
 {
 	int result = 0;
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout) {
-		dev_err(&I801_dev->dev, "Transaction timeout\n");
+		dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
 		/* try to stop the current command */
-		dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
-		outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+		outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
+		       SMBHSTCNT(priv));
 		msleep(1);
-		outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
+		outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
+		       SMBHSTCNT(priv));
 
 		/* Check if it worked */
-		status = inb_p(SMBHSTSTS);
+		status = inb_p(SMBHSTSTS(priv));
 		if ((status & SMBHSTSTS_HOST_BUSY) ||
 		    !(status & SMBHSTSTS_FAILED))
-			dev_err(&I801_dev->dev,
+			dev_err(&priv->pci_dev->dev,
 				"Failed terminating the transaction\n");
-		outb_p(STATUS_FLAGS, SMBHSTSTS);
+		outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
 		return -ETIMEDOUT;
 	}
 
 	if (status & SMBHSTSTS_FAILED) {
 		result = -EIO;
-		dev_err(&I801_dev->dev, "Transaction failed\n");
+		dev_err(&priv->pci_dev->dev, "Transaction failed\n");
 	}
 	if (status & SMBHSTSTS_DEV_ERR) {
 		result = -ENXIO;
-		dev_dbg(&I801_dev->dev, "No response\n");
+		dev_dbg(&priv->pci_dev->dev, "No response\n");
 	}
 	if (status & SMBHSTSTS_BUS_ERR) {
 		result = -EAGAIN;
-		dev_dbg(&I801_dev->dev, "Lost arbitration\n");
+		dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
 	}
 
 	if (result) {
 		/* Clear error flags */
-		outb_p(status & STATUS_FLAGS, SMBHSTSTS);
-		status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+		outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
 		if (status) {
-			dev_warn(&I801_dev->dev, "Failed clearing status "
+			dev_warn(&priv->pci_dev->dev, "Failed clearing status "
 				 "flags at end of transaction (%02x)\n",
 				 status);
 		}
@@ -229,86 +245,88 @@
 	return result;
 }
 
-static int i801_transaction(int xact)
+static int i801_transaction(struct i801_priv *priv, int xact)
 {
 	int status;
 	int result;
 	int timeout = 0;
 
-	result = i801_check_pre();
+	result = i801_check_pre(priv);
 	if (result < 0)
 		return result;
 
 	/* the current contents of SMBHSTCNT can be overwritten, since PEC,
 	 * INTREN, SMBSCMD are passed in xact */
-	outb_p(xact | I801_START, SMBHSTCNT);
+	outb_p(xact | I801_START, SMBHSTCNT(priv));
 
 	/* We will always wait for a fraction of a second! */
 	do {
 		msleep(1);
-		status = inb_p(SMBHSTSTS);
+		status = inb_p(SMBHSTSTS(priv));
 	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
 
-	result = i801_check_post(status, timeout > MAX_TIMEOUT);
+	result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
 	if (result < 0)
 		return result;
 
-	outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+	outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
 	return 0;
 }
 
 /* wait for INTR bit as advised by Intel */
-static void i801_wait_hwpec(void)
+static void i801_wait_hwpec(struct i801_priv *priv)
 {
 	int timeout = 0;
 	int status;
 
 	do {
 		msleep(1);
-		status = inb_p(SMBHSTSTS);
+		status = inb_p(SMBHSTSTS(priv));
 	} while ((!(status & SMBHSTSTS_INTR))
 		 && (timeout++ < MAX_TIMEOUT));
 
 	if (timeout > MAX_TIMEOUT)
-		dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+		dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
 
-	outb_p(status, SMBHSTSTS);
+	outb_p(status, SMBHSTSTS(priv));
 }
 
-static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+					   union i2c_smbus_data *data,
 					   char read_write, int hwpec)
 {
 	int i, len;
 	int status;
 
-	inb_p(SMBHSTCNT); /* reset the data buffer index */
+	inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
 
 	/* Use 32-byte buffer to process this transaction */
 	if (read_write == I2C_SMBUS_WRITE) {
 		len = data->block[0];
-		outb_p(len, SMBHSTDAT0);
+		outb_p(len, SMBHSTDAT0(priv));
 		for (i = 0; i < len; i++)
-			outb_p(data->block[i+1], SMBBLKDAT);
+			outb_p(data->block[i+1], SMBBLKDAT(priv));
 	}
 
-	status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
+	status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
 				  I801_PEC_EN * hwpec);
 	if (status)
 		return status;
 
 	if (read_write == I2C_SMBUS_READ) {
-		len = inb_p(SMBHSTDAT0);
+		len = inb_p(SMBHSTDAT0(priv));
 		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
 			return -EPROTO;
 
 		data->block[0] = len;
 		for (i = 0; i < len; i++)
-			data->block[i + 1] = inb_p(SMBBLKDAT);
+			data->block[i + 1] = inb_p(SMBBLKDAT(priv));
 	}
 	return 0;
 }
 
-static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+					       union i2c_smbus_data *data,
 					       char read_write, int command,
 					       int hwpec)
 {
@@ -318,15 +336,15 @@
 	int result;
 	int timeout;
 
-	result = i801_check_pre();
+	result = i801_check_pre(priv);
 	if (result < 0)
 		return result;
 
 	len = data->block[0];
 
 	if (read_write == I2C_SMBUS_WRITE) {
-		outb_p(len, SMBHSTDAT0);
-		outb_p(data->block[1], SMBBLKDAT);
+		outb_p(len, SMBHSTDAT0(priv));
+		outb_p(data->block[1], SMBBLKDAT(priv));
 	}
 
 	for (i = 1; i <= len; i++) {
@@ -342,34 +360,37 @@
 			else
 				smbcmd = I801_BLOCK_DATA;
 		}
-		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
 
 		if (i == 1)
-			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+			outb_p(inb(SMBHSTCNT(priv)) | I801_START,
+			       SMBHSTCNT(priv));
 
 		/* We will always wait for a fraction of a second! */
 		timeout = 0;
 		do {
 			msleep(1);
-			status = inb_p(SMBHSTSTS);
+			status = inb_p(SMBHSTSTS(priv));
 		} while ((!(status & SMBHSTSTS_BYTE_DONE))
 			 && (timeout++ < MAX_TIMEOUT));
 
-		result = i801_check_post(status, timeout > MAX_TIMEOUT);
+		result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);
 		if (result < 0)
 			return result;
 
 		if (i == 1 && read_write == I2C_SMBUS_READ
 		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-			len = inb_p(SMBHSTDAT0);
+			len = inb_p(SMBHSTDAT0(priv));
 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
-				dev_err(&I801_dev->dev,
+				dev_err(&priv->pci_dev->dev,
 					"Illegal SMBus block read size %d\n",
 					len);
 				/* Recover */
-				while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
-					outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
-				outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+				while (inb_p(SMBHSTSTS(priv)) &
+				       SMBHSTSTS_HOST_BUSY)
+					outb_p(SMBHSTSTS_BYTE_DONE,
+					       SMBHSTSTS(priv));
+				outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
 				return -EPROTO;
 			}
 			data->block[0] = len;
@@ -377,27 +398,28 @@
 
 		/* Retrieve/store value in SMBBLKDAT */
 		if (read_write == I2C_SMBUS_READ)
-			data->block[i] = inb_p(SMBBLKDAT);
+			data->block[i] = inb_p(SMBBLKDAT(priv));
 		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
-			outb_p(data->block[i+1], SMBBLKDAT);
+			outb_p(data->block[i+1], SMBBLKDAT(priv));
 
 		/* signals SMBBLKDAT ready */
-		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
+		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
 	}
 
 	return 0;
 }
 
-static int i801_set_block_buffer_mode(void)
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
 {
-	outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
-	if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
+	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+	if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
 		return -EIO;
 	return 0;
 }
 
 /* Block transaction function */
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+static int i801_block_transaction(struct i801_priv *priv,
+				  union i2c_smbus_data *data, char read_write,
 				  int command, int hwpec)
 {
 	int result = 0;
@@ -406,11 +428,11 @@
 	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
 		if (read_write == I2C_SMBUS_WRITE) {
 			/* set I2C_EN bit in configuration register */
-			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
-			pci_write_config_byte(I801_dev, SMBHSTCFG,
+			pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+			pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
 					      hostc | SMBHSTCFG_I2C_EN);
-		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
-			dev_err(&I801_dev->dev,
+		} else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+			dev_err(&priv->pci_dev->dev,
 				"I2C block read is unsupported!\n");
 			return -EOPNOTSUPP;
 		}
@@ -429,22 +451,23 @@
 	/* Experience has shown that the block buffer can only be used for
 	   SMBus (not I2C) block transactions, even though the datasheet
 	   doesn't mention this limitation. */
-	if ((i801_features & FEATURE_BLOCK_BUFFER)
+	if ((priv->features & FEATURE_BLOCK_BUFFER)
 	 && command != I2C_SMBUS_I2C_BLOCK_DATA
-	 && i801_set_block_buffer_mode() == 0)
-		result = i801_block_transaction_by_block(data, read_write,
-							 hwpec);
+	 && i801_set_block_buffer_mode(priv) == 0)
+		result = i801_block_transaction_by_block(priv, data,
+							 read_write, hwpec);
 	else
-		result = i801_block_transaction_byte_by_byte(data, read_write,
+		result = i801_block_transaction_byte_by_byte(priv, data,
+							     read_write,
 							     command, hwpec);
 
 	if (result == 0 && hwpec)
-		i801_wait_hwpec();
+		i801_wait_hwpec(priv);
 
 	if (command == I2C_SMBUS_I2C_BLOCK_DATA
 	 && read_write == I2C_SMBUS_WRITE) {
 		/* restore saved configuration register value */
-		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
+		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
 	}
 	return result;
 }
@@ -457,81 +480,85 @@
 	int hwpec;
 	int block = 0;
 	int ret, xact = 0;
+	struct i801_priv *priv = i2c_get_adapdata(adap);
 
-	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
 
 	switch (size) {
 	case I2C_SMBUS_QUICK:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-		       SMBHSTADD);
+		       SMBHSTADD(priv));
 		xact = I801_QUICK;
 		break;
 	case I2C_SMBUS_BYTE:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-		       SMBHSTADD);
+		       SMBHSTADD(priv));
 		if (read_write == I2C_SMBUS_WRITE)
-			outb_p(command, SMBHSTCMD);
+			outb_p(command, SMBHSTCMD(priv));
 		xact = I801_BYTE;
 		break;
 	case I2C_SMBUS_BYTE_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-		       SMBHSTADD);
-		outb_p(command, SMBHSTCMD);
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
 		if (read_write == I2C_SMBUS_WRITE)
-			outb_p(data->byte, SMBHSTDAT0);
+			outb_p(data->byte, SMBHSTDAT0(priv));
 		xact = I801_BYTE_DATA;
 		break;
 	case I2C_SMBUS_WORD_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-		       SMBHSTADD);
-		outb_p(command, SMBHSTCMD);
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
 		if (read_write == I2C_SMBUS_WRITE) {
-			outb_p(data->word & 0xff, SMBHSTDAT0);
-			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+			outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
 		}
 		xact = I801_WORD_DATA;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
-		       SMBHSTADD);
-		outb_p(command, SMBHSTCMD);
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
 		block = 1;
 		break;
 	case I2C_SMBUS_I2C_BLOCK_DATA:
 		/* NB: page 240 of ICH5 datasheet shows that the R/#W
 		 * bit should be cleared here, even when reading */
-		outb_p((addr & 0x7f) << 1, SMBHSTADD);
+		outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
 		if (read_write == I2C_SMBUS_READ) {
 			/* NB: page 240 of ICH5 datasheet also shows
 			 * that DATA1 is the cmd field when reading */
-			outb_p(command, SMBHSTDAT1);
+			outb_p(command, SMBHSTDAT1(priv));
 		} else
-			outb_p(command, SMBHSTCMD);
+			outb_p(command, SMBHSTCMD(priv));
 		block = 1;
 		break;
 	default:
-		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
+		dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+			size);
 		return -EOPNOTSUPP;
 	}
 
 	if (hwpec)	/* enable/disable hardware PEC */
-		outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+		outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
 	else
-		outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
+		outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+		       SMBAUXCTL(priv));
 
 	if (block)
-		ret = i801_block_transaction(data, read_write, size, hwpec);
+		ret = i801_block_transaction(priv, data, read_write, size,
+					     hwpec);
 	else
-		ret = i801_transaction(xact | ENABLE_INT9);
+		ret = i801_transaction(priv, xact | ENABLE_INT9);
 
 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
 	   time, so we forcibly disable it after every transaction. Turn off
 	   E32B for the same reason. */
 	if (hwpec || block)
-		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
-		       SMBAUXCTL);
+		outb_p(inb_p(SMBAUXCTL(priv)) &
+		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
 	if (block)
 		return ret;
@@ -543,10 +570,11 @@
 	switch (xact & 0x7f) {
 	case I801_BYTE:	/* Result put in SMBHSTDAT0 */
 	case I801_BYTE_DATA:
-		data->byte = inb_p(SMBHSTDAT0);
+		data->byte = inb_p(SMBHSTDAT0(priv));
 		break;
 	case I801_WORD_DATA:
-		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		data->word = inb_p(SMBHSTDAT0(priv)) +
+			     (inb_p(SMBHSTDAT1(priv)) << 8);
 		break;
 	}
 	return 0;
@@ -555,11 +583,13 @@
 
 static u32 i801_func(struct i2c_adapter *adapter)
 {
+	struct i801_priv *priv = i2c_get_adapdata(adapter);
+
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
 	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
 	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
-	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+	       ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+	       ((priv->features & FEATURE_I2C_BLOCK_READ) ?
 		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
 }
 
@@ -568,12 +598,6 @@
 	.functionality	= i801_func,
 };
 
-static struct i2c_adapter i801_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
-	.algo		= &smbus_algorithm,
-};
-
 static const struct pci_device_id i801_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
@@ -587,11 +611,15 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
 	{ 0, }
 };
 
@@ -704,16 +732,25 @@
 {
 	unsigned char temp;
 	int err, i;
+	struct i801_priv *priv;
 
-	I801_dev = dev;
-	i801_features = 0;
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_adapdata(&priv->adapter, priv);
+	priv->adapter.owner = THIS_MODULE;
+	priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	priv->adapter.algo = &smbus_algorithm;
+
+	priv->pci_dev = dev;
 	switch (dev->device) {
 	default:
-		i801_features |= FEATURE_I2C_BLOCK_READ;
+		priv->features |= FEATURE_I2C_BLOCK_READ;
 		/* fall through */
 	case PCI_DEVICE_ID_INTEL_82801DB_3:
-		i801_features |= FEATURE_SMBUS_PEC;
-		i801_features |= FEATURE_BLOCK_BUFFER;
+		priv->features |= FEATURE_SMBUS_PEC;
+		priv->features |= FEATURE_BLOCK_BUFFER;
 		/* fall through */
 	case PCI_DEVICE_ID_INTEL_82801CA_3:
 	case PCI_DEVICE_ID_INTEL_82801BA_2:
@@ -724,11 +761,11 @@
 
 	/* Disable features on user request */
 	for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
-		if (i801_features & disable_features & (1 << i))
+		if (priv->features & disable_features & (1 << i))
 			dev_notice(&dev->dev, "%s disabled by user\n",
 				   i801_feature_names[i]);
 	}
-	i801_features &= ~disable_features;
+	priv->features &= ~disable_features;
 
 	err = pci_enable_device(dev);
 	if (err) {
@@ -738,8 +775,8 @@
 	}
 
 	/* Determine the address of the SMBus area */
-	i801_smba = pci_resource_start(dev, SMBBAR);
-	if (!i801_smba) {
+	priv->smba = pci_resource_start(dev, SMBBAR);
+	if (!priv->smba) {
 		dev_err(&dev->dev, "SMBus base address uninitialized, "
 			"upgrade BIOS\n");
 		err = -ENODEV;
@@ -755,19 +792,19 @@
 	err = pci_request_region(dev, SMBBAR, i801_driver.name);
 	if (err) {
 		dev_err(&dev->dev, "Failed to request SMBus region "
-			"0x%lx-0x%Lx\n", i801_smba,
+			"0x%lx-0x%Lx\n", priv->smba,
 			(unsigned long long)pci_resource_end(dev, SMBBAR));
 		goto exit;
 	}
 
-	pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
-	i801_original_hstcfg = temp;
+	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
+	priv->original_hstcfg = temp;
 	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
 	if (!(temp & SMBHSTCFG_HST_EN)) {
 		dev_info(&dev->dev, "Enabling SMBus device\n");
 		temp |= SMBHSTCFG_HST_EN;
 	}
-	pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
+	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
 
 	if (temp & SMBHSTCFG_SMB_SMI_EN)
 		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
@@ -775,19 +812,19 @@
 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
 	/* Clear special mode bits */
-	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
-		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
-		       SMBAUXCTL);
+	if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+		outb_p(inb_p(SMBAUXCTL(priv)) &
+		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
 
 	/* set up the sysfs linkage to our parent device */
-	i801_adapter.dev.parent = &dev->dev;
+	priv->adapter.dev.parent = &dev->dev;
 
 	/* Retry up to 3 times on lost arbitration */
-	i801_adapter.retries = 3;
+	priv->adapter.retries = 3;
 
-	snprintf(i801_adapter.name, sizeof(i801_adapter.name),
-		"SMBus I801 adapter at %04lx", i801_smba);
-	err = i2c_add_adapter(&i801_adapter);
+	snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+		"SMBus I801 adapter at %04lx", priv->smba);
+	err = i2c_add_adapter(&priv->adapter);
 	if (err) {
 		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
 		goto exit_release;
@@ -801,27 +838,33 @@
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		info.addr = apanel_addr;
 		strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
-		i2c_new_device(&i801_adapter, &info);
+		i2c_new_device(&priv->adapter, &info);
 	}
 #endif
 #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
 	if (dmi_name_in_vendors("FUJITSU"))
-		dmi_walk(dmi_check_onboard_devices, &i801_adapter);
+		dmi_walk(dmi_check_onboard_devices, &priv->adapter);
 #endif
 
+	pci_set_drvdata(dev, priv);
 	return 0;
 
 exit_release:
 	pci_release_region(dev, SMBBAR);
 exit:
+	kfree(priv);
 	return err;
 }
 
 static void __devexit i801_remove(struct pci_dev *dev)
 {
-	i2c_del_adapter(&i801_adapter);
-	pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
+	struct i801_priv *priv = pci_get_drvdata(dev);
+
+	i2c_del_adapter(&priv->adapter);
+	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 	pci_release_region(dev, SMBBAR);
+	pci_set_drvdata(dev, NULL);
+	kfree(priv);
 	/*
 	 * do not call pci_disable_device(dev) since it can cause hard hangs on
 	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
@@ -831,8 +874,10 @@
 #ifdef CONFIG_PM
 static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
 {
+	struct i801_priv *priv = pci_get_drvdata(dev);
+
 	pci_save_state(dev);
-	pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg);
+	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 	pci_set_power_state(dev, pci_choose_state(dev, mesg));
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-ibm_iic.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-ibm_iic.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-ibm_iic.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-ibm_iic.c	2011-01-04 19:50:19.000000000 -0500
@@ -41,7 +41,6 @@
 #include <asm/irq.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/of_platform.h>
 #include <linux/of_i2c.h>
 
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-intel-mid.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-intel-mid.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-intel-mid.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-intel-mid.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,1135 @@
+/*
+ * Support for Moorestown/Medfield I2C chip
+ *
+ * Copyright (c) 2009 Intel Corporation.
+ * Copyright (c) 2009 Synopsys. Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License, version
+ * 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME	"i2c-intel-mid"
+#define VERSION		"Version 0.5ac2"
+#define PLATFORM	"Moorestown/Medfield"
+
+/* Tables use: 0 Moorestown, 1 Medfield */
+#define NUM_PLATFORMS	2
+enum platform_enum {
+	MOORESTOWN = 0,
+	MEDFIELD = 1,
+};
+
+enum mid_i2c_status {
+	STATUS_IDLE = 0,
+	STATUS_READ_START,
+	STATUS_READ_IN_PROGRESS,
+	STATUS_READ_SUCCESS,
+	STATUS_WRITE_START,
+	STATUS_WRITE_SUCCESS,
+	STATUS_XFER_ABORT,
+	STATUS_STANDBY
+};
+
+/**
+ * struct intel_mid_i2c_private	- per device IÂ²C context
+ * @adap: core i2c layer adapter information
+ * @dev: device reference for power management
+ * @base: register base
+ * @speed: speed mode for this port
+ * @complete: completion object for transaction wait
+ * @abort: reason for last abort
+ * @rx_buf: pointer into working receive buffer
+ * @rx_buf_len: receive buffer length
+ * @status: adapter state machine
+ * @msg: the message we are currently processing
+ * @platform: the MID device type we are part of
+ * @lock: transaction serialization
+ *
+ * We allocate one of these per device we discover, it holds the core
+ * i2c layer objects and the data we need to track privately.
+ */
+struct intel_mid_i2c_private {
+	struct i2c_adapter adap;
+	struct device *dev;
+	void __iomem *base;
+	int speed;
+	struct completion complete;
+	int abort;
+	u8 *rx_buf;
+	int rx_buf_len;
+	enum mid_i2c_status status;
+	struct i2c_msg *msg;
+	enum platform_enum platform;
+	struct mutex lock;
+};
+
+#define NUM_SPEEDS		3
+
+#define ACTIVE			0
+#define STANDBY			1
+
+
+/* Control register */
+#define IC_CON			0x00
+#define SLV_DIS			(1 << 6)	/* Disable slave mode */
+#define RESTART			(1 << 5)	/* Send a Restart condition */
+#define	ADDR_10BIT		(1 << 4)	/* 10-bit addressing */
+#define	STANDARD_MODE		(1 << 1)	/* standard mode */
+#define FAST_MODE		(2 << 1)	/* fast mode */
+#define HIGH_MODE		(3 << 1)	/* high speed mode */
+#define	MASTER_EN		(1 << 0)	/* Master mode */
+
+/* Target address register */
+#define IC_TAR			0x04
+#define IC_TAR_10BIT_ADDR	(1 << 12)	/* 10-bit addressing */
+#define IC_TAR_SPECIAL		(1 << 11)	/* Perform special I2C cmd */
+#define IC_TAR_GC_OR_START	(1 << 10)	/* 0: Gerneral Call Address */
+						/* 1: START BYTE */
+/* Slave Address Register */
+#define IC_SAR			0x08		/* Not used in Master mode */
+
+/* High Speed Master Mode Code Address Register */
+#define IC_HS_MADDR		0x0c
+
+/* Rx/Tx Data Buffer and Command Register */
+#define IC_DATA_CMD		0x10
+#define IC_RD			(1 << 8)	/* 1: Read 0: Write */
+
+/* Standard Speed Clock SCL High Count Register */
+#define IC_SS_SCL_HCNT		0x14
+
+/* Standard Speed Clock SCL Low Count Register */
+#define IC_SS_SCL_LCNT		0x18
+
+/* Fast Speed Clock SCL High Count Register */
+#define IC_FS_SCL_HCNT		0x1c
+
+/* Fast Spedd Clock SCL Low Count Register */
+#define IC_FS_SCL_LCNT		0x20
+
+/* High Speed Clock SCL High Count Register */
+#define IC_HS_SCL_HCNT		0x24
+
+/* High Speed Clock SCL Low Count Register */
+#define IC_HS_SCL_LCNT		0x28
+
+/* Interrupt Status Register */
+#define IC_INTR_STAT		0x2c		/* Read only */
+#define R_GEN_CALL		(1 << 11)
+#define R_START_DET		(1 << 10)
+#define R_STOP_DET		(1 << 9)
+#define R_ACTIVITY		(1 << 8)
+#define R_RX_DONE		(1 << 7)
+#define	R_TX_ABRT		(1 << 6)
+#define R_RD_REQ		(1 << 5)
+#define R_TX_EMPTY		(1 << 4)
+#define R_TX_OVER		(1 << 3)
+#define	R_RX_FULL		(1 << 2)
+#define	R_RX_OVER		(1 << 1)
+#define R_RX_UNDER		(1 << 0)
+
+/* Interrupt Mask Register */
+#define IC_INTR_MASK		0x30		/* Read and Write */
+#define M_GEN_CALL		(1 << 11)
+#define M_START_DET		(1 << 10)
+#define M_STOP_DET		(1 << 9)
+#define M_ACTIVITY		(1 << 8)
+#define M_RX_DONE		(1 << 7)
+#define	M_TX_ABRT		(1 << 6)
+#define M_RD_REQ		(1 << 5)
+#define M_TX_EMPTY		(1 << 4)
+#define M_TX_OVER		(1 << 3)
+#define	M_RX_FULL		(1 << 2)
+#define	M_RX_OVER		(1 << 1)
+#define M_RX_UNDER		(1 << 0)
+
+/* Raw Interrupt Status Register */
+#define IC_RAW_INTR_STAT	0x34		/* Read Only */
+#define GEN_CALL		(1 << 11)	/* General call */
+#define START_DET		(1 << 10)	/* (RE)START occured */
+#define STOP_DET		(1 << 9)	/* STOP occured */
+#define ACTIVITY		(1 << 8)	/* Bus busy */
+#define RX_DONE			(1 << 7)	/* Not used in Master mode */
+#define	TX_ABRT			(1 << 6)	/* Transmit Abort */
+#define RD_REQ			(1 << 5)	/* Not used in Master mode */
+#define TX_EMPTY		(1 << 4)	/* TX FIFO <= threshold */
+#define TX_OVER			(1 << 3)	/* TX FIFO overflow */
+#define	RX_FULL			(1 << 2)	/* RX FIFO >= threshold */
+#define	RX_OVER			(1 << 1)	/* RX FIFO overflow */
+#define RX_UNDER		(1 << 0)	/* RX FIFO empty */
+
+/* Receive FIFO Threshold Register */
+#define IC_RX_TL		0x38
+
+/* Transmit FIFO Treshold Register */
+#define IC_TX_TL		0x3c
+
+/* Clear Combined and Individual Interrupt Register */
+#define IC_CLR_INTR		0x40
+#define CLR_INTR		(1 << 0)
+
+/* Clear RX_UNDER Interrupt Register */
+#define IC_CLR_RX_UNDER		0x44
+#define CLR_RX_UNDER		(1 << 0)
+
+/* Clear RX_OVER Interrupt Register */
+#define IC_CLR_RX_OVER		0x48
+#define CLR_RX_OVER		(1 << 0)
+
+/* Clear TX_OVER Interrupt Register */
+#define IC_CLR_TX_OVER		0x4c
+#define CLR_TX_OVER		(1 << 0)
+
+#define IC_CLR_RD_REQ		0x50
+
+/* Clear TX_ABRT Interrupt Register */
+#define IC_CLR_TX_ABRT		0x54
+#define CLR_TX_ABRT		(1 << 0)
+#define IC_CLR_RX_DONE		0x58
+
+/* Clear ACTIVITY Interrupt Register */
+#define IC_CLR_ACTIVITY		0x5c
+#define CLR_ACTIVITY		(1 << 0)
+
+/* Clear STOP_DET Interrupt Register */
+#define IC_CLR_STOP_DET		0x60
+#define CLR_STOP_DET		(1 << 0)
+
+/* Clear START_DET Interrupt Register */
+#define IC_CLR_START_DET	0x64
+#define CLR_START_DET		(1 << 0)
+
+/* Clear GEN_CALL Interrupt Register */
+#define IC_CLR_GEN_CALL		0x68
+#define CLR_GEN_CALL		(1 << 0)
+
+/* Enable Register */
+#define IC_ENABLE		0x6c
+#define ENABLE			(1 << 0)
+
+/* Status Register */
+#define IC_STATUS		0x70		/* Read Only */
+#define STAT_SLV_ACTIVITY	(1 << 6)	/* Slave not in idle */
+#define STAT_MST_ACTIVITY	(1 << 5)	/* Master not in idle */
+#define STAT_RFF		(1 << 4)	/* RX FIFO Full */
+#define STAT_RFNE		(1 << 3)	/* RX FIFO Not Empty */
+#define STAT_TFE		(1 << 2)	/* TX FIFO Empty */
+#define STAT_TFNF		(1 << 1)	/* TX FIFO Not Full */
+#define STAT_ACTIVITY		(1 << 0)	/* Activity Status */
+
+/* Transmit FIFO Level Register */
+#define IC_TXFLR		0x74		/* Read Only */
+#define TXFLR			(1 << 0)	/* TX FIFO level */
+
+/* Receive FIFO Level Register */
+#define IC_RXFLR		0x78		/* Read Only */
+#define RXFLR			(1 << 0)	/* RX FIFO level */
+
+/* Transmit Abort Source Register */
+#define IC_TX_ABRT_SOURCE	0x80
+#define ABRT_SLVRD_INTX		(1 << 15)
+#define ABRT_SLV_ARBLOST	(1 << 14)
+#define ABRT_SLVFLUSH_TXFIFO	(1 << 13)
+#define	ARB_LOST		(1 << 12)
+#define ABRT_MASTER_DIS		(1 << 11)
+#define ABRT_10B_RD_NORSTRT	(1 << 10)
+#define ABRT_SBYTE_NORSTRT	(1 << 9)
+#define ABRT_HS_NORSTRT		(1 << 8)
+#define ABRT_SBYTE_ACKDET	(1 << 7)
+#define ABRT_HS_ACKDET		(1 << 6)
+#define ABRT_GCALL_READ		(1 << 5)
+#define ABRT_GCALL_NOACK	(1 << 4)
+#define ABRT_TXDATA_NOACK	(1 << 3)
+#define ABRT_10ADDR2_NOACK	(1 << 2)
+#define ABRT_10ADDR1_NOACK	(1 << 1)
+#define ABRT_7B_ADDR_NOACK	(1 << 0)
+
+/* Enable Status Register */
+#define IC_ENABLE_STATUS	0x9c
+#define IC_EN			(1 << 0)	/* I2C in an enabled state */
+
+/* Component Parameter Register 1*/
+#define IC_COMP_PARAM_1		0xf4
+#define APB_DATA_WIDTH		(0x3 << 0)
+
+/* added by xiaolin --begin */
+#define SS_MIN_SCL_HIGH         4000
+#define SS_MIN_SCL_LOW          4700
+#define FS_MIN_SCL_HIGH         600
+#define FS_MIN_SCL_LOW          1300
+#define HS_MIN_SCL_HIGH_100PF   60
+#define HS_MIN_SCL_LOW_100PF    120
+
+#define STANDARD		0
+#define FAST			1
+#define HIGH			2
+
+#define NUM_SPEEDS		3
+
+static int speed_mode[6] = {
+	FAST,
+	FAST,
+	FAST,
+	STANDARD,
+	FAST,
+	FAST
+};
+
+static int ctl_num = 6;
+module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
+MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
+
+/**
+ * intel_mid_i2c_disable - Disable I2C controller
+ * @adap: struct pointer to i2c_adapter
+ *
+ * Return Value:
+ * 0		success
+ * -EBUSY	if device is busy
+ * -ETIMEDOUT	if i2c cannot be disabled within the given time
+ *
+ * I2C bus state should be checked prior to disabling the hardware. If bus is
+ * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable
+ * I2C controller.
+ */
+static int intel_mid_i2c_disable(struct i2c_adapter *adap)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int err = 0;
+	int count = 0;
+	int ret1, ret2;
+	static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
+
+	/* Set IC_ENABLE to 0 */
+	writel(0, i2c->base + IC_ENABLE);
+
+	/* Check if device is busy */
+	dev_dbg(&adap->dev, "mrst i2c disable\n");
+	while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
+		|| (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
+		udelay(delay[i2c->speed]);
+		writel(0, i2c->base + IC_ENABLE);
+		dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
+			count, i2c->speed);
+		if (count++ > 10) {
+			err = -ETIMEDOUT;
+			break;
+		}
+	}
+
+	/* Clear all interrupts */
+	readl(i2c->base + IC_CLR_INTR);
+	readl(i2c->base + IC_CLR_STOP_DET);
+	readl(i2c->base + IC_CLR_START_DET);
+	readl(i2c->base + IC_CLR_ACTIVITY);
+	readl(i2c->base + IC_CLR_TX_ABRT);
+	readl(i2c->base + IC_CLR_RX_OVER);
+	readl(i2c->base + IC_CLR_RX_UNDER);
+	readl(i2c->base + IC_CLR_TX_OVER);
+	readl(i2c->base + IC_CLR_RX_DONE);
+	readl(i2c->base + IC_CLR_GEN_CALL);
+
+	/* Disable all interupts */
+	writel(0x0000, i2c->base + IC_INTR_MASK);
+
+	return err;
+}
+
+/**
+ * intel_mid_i2c_hwinit - Initialize the I2C hardware registers
+ * @dev: pci device struct pointer
+ *
+ * This function will be called in intel_mid_i2c_probe() before device
+ * registration.
+ *
+ * Return Values:
+ * 0		success
+ * -EBUSY	i2c cannot be disabled
+ * -ETIMEDOUT	i2c cannot be disabled
+ * -EFAULT	If APB data width is not 32-bit wide
+ *
+ * I2C should be disabled prior to other register operation. If failed, an
+ * errno is returned. Mask and Clear all interrpts, this should be done at
+ * first.  Set common registers which will not be modified during normal
+ * transfers, including: controll register, FIFO threshold and clock freq.
+ * Check APB data width at last.
+ */
+static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c)
+{
+	int err;
+
+	static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+		{ 0x75,  0x15, 0x07 },
+		{ 0x04c,  0x10, 0x06 }
+	};
+	static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+		{ 0x7C,  0x21, 0x0E },
+		{ 0x053, 0x19, 0x0F }
+	};
+
+	/* Disable i2c first */
+	err = intel_mid_i2c_disable(&i2c->adap);
+	if (err)
+		return err;
+
+	/*
+	 * Setup clock frequency and speed mode
+	 * Enable restart condition,
+	 * enable master FSM, disable slave FSM,
+	 * use target address when initiating transfer
+	 */
+
+	writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN,
+		i2c->base + IC_CON);
+	writel(hcnt[i2c->platform][i2c->speed],
+		i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3)));
+	writel(lcnt[i2c->platform][i2c->speed],
+		i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3)));
+
+	/* Set tranmit & receive FIFO threshold to zero */
+	writel(0x0, i2c->base + IC_RX_TL);
+	writel(0x0, i2c->base + IC_TX_TL);
+
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_func - Return the supported three I2C operations.
+ * @adapter: i2c_adapter struct pointer
+ */
+static u32 intel_mid_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+/**
+ * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages
+ * are equal.
+ * @p1: first i2c_msg
+ * @p2: second i2c_msg
+ *
+ * Return Values:
+ * 0	 if addresses are equal
+ * 1	 if not equal
+ *
+ * Within a single transfer, the I2C client may need to send its address more
+ * than once. So a check if the addresses match is needed.
+ */
+static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1,
+				       const struct i2c_msg *p2)
+{
+	if (p1->addr != p2->addr)
+		return 1;
+	if ((p1->flags ^ p2->flags) & I2C_M_TEN)
+		return 1;
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_abort - To handle transfer abortions and print error messages.
+ * @adap: i2c_adapter struct pointer
+ *
+ * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be
+ * distingushed. At present, no circumstances have been found out that
+ * multiple errors would be occured simutaneously, so we simply use the
+ * register value directly.
+ *
+ * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need
+ * a few extra steps)
+ */
+static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
+{
+	/* Read about source register */
+	int abort = i2c->abort;
+	struct i2c_adapter *adap = &i2c->adap;
+
+	/* Single transfer error check:
+	 * According to databook, TX/RX FIFOs would be flushed when
+	 * the abort interrupt occured.
+	 */
+	if (abort & ABRT_MASTER_DIS)
+		dev_err(&adap->dev,
+		"initiate master operation with master mode disabled.\n");
+	if (abort & ABRT_10B_RD_NORSTRT)
+		dev_err(&adap->dev,
+	"RESTART disabled and master sent READ cmd in 10-bit addressing.\n");
+
+	if (abort & ABRT_SBYTE_NORSTRT) {
+		dev_err(&adap->dev,
+		"RESTART disabled and user is trying to send START byte.\n");
+		writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE);
+		writel(RESTART, i2c->base + IC_CON);
+		writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR);
+	}
+
+	if (abort & ABRT_SBYTE_ACKDET)
+		dev_err(&adap->dev,
+			"START byte was not acknowledged.\n");
+	if (abort & ABRT_TXDATA_NOACK)
+		dev_dbg(&adap->dev,
+			"No acknowledgement received from slave.\n");
+	if (abort & ABRT_10ADDR2_NOACK)
+		dev_dbg(&adap->dev,
+	"The 2nd address byte of the 10-bit address was not acknowledged.\n");
+	if (abort & ABRT_10ADDR1_NOACK)
+		dev_dbg(&adap->dev,
+	"The 1st address byte of 10-bit address was not acknowledged.\n");
+	if (abort & ABRT_7B_ADDR_NOACK)
+		dev_dbg(&adap->dev,
+			"I2C slave device not acknowledged.\n");
+
+	/* Clear TX_ABRT bit */
+	readl(i2c->base + IC_CLR_TX_ABRT);
+	i2c->status = STATUS_XFER_ABORT;
+}
+
+/**
+ * xfer_read - Internal function to implement master read transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0		if the read transfer succeeds
+ * -ETIMEDOUT	if cannot read the "raw" interrupt register
+ * -EINVAL	if a transfer abort occurred
+ *
+ * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "read" operation will be performed if an RX_FULL
+ * interrupt occurred.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i = length;
+	int err;
+
+	if (length >= 256) {
+		dev_err(&adap->dev,
+			"I2C FIFO cannot support larger than 256 bytes\n");
+		return -EMSGSIZE;
+	}
+
+	INIT_COMPLETION(i2c->complete);
+
+	readl(i2c->base + IC_CLR_INTR);
+	writel(0x0044, i2c->base + IC_INTR_MASK);
+
+	i2c->status = STATUS_READ_START;
+
+	while (i--)
+		writel(IC_RD, i2c->base + IC_DATA_CMD);
+
+	i2c->status = STATUS_READ_START;
+	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+	if (!err) {
+		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+		intel_mid_i2c_hwinit(i2c);
+		return -ETIMEDOUT;
+	}
+	if (i2c->status == STATUS_READ_SUCCESS)
+		return 0;
+	else
+		return -EIO;
+}
+
+/**
+ * xfer_write - Internal function to implement master write transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0	if the read transfer succeeds
+ * -ETIMEDOUT	if we cannot read the "raw" interrupt register
+ * -EINVAL	if a transfer abort occured
+ *
+ * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "write" operation will be performed when the
+ * RX_FULL interrupt signal occurs.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_write(struct i2c_adapter *adap,
+		      unsigned char *buf, int length)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i, err;
+
+	if (length >= 256) {
+		dev_err(&adap->dev,
+			"I2C FIFO cannot support larger than 256 bytes\n");
+		return -EMSGSIZE;
+	}
+
+	INIT_COMPLETION(i2c->complete);
+
+	readl(i2c->base + IC_CLR_INTR);
+	writel(0x0050, i2c->base + IC_INTR_MASK);
+
+	i2c->status = STATUS_WRITE_START;
+	for (i = 0; i < length; i++)
+		writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
+
+	i2c->status = STATUS_WRITE_START;
+	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+	if (!err) {
+		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+		intel_mid_i2c_hwinit(i2c);
+		return -ETIMEDOUT;
+	} else {
+		if (i2c->status == STATUS_WRITE_SUCCESS)
+			return 0;
+		else
+			return -EIO;
+	}
+}
+
+static int intel_mid_i2c_setup(struct i2c_adapter *adap,  struct i2c_msg *pmsg)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int err;
+	u32 reg;
+	u32 bit_mask;
+	u32 mode;
+
+	/* Disable device first */
+	err = intel_mid_i2c_disable(adap);
+	if (err) {
+		dev_err(&adap->dev,
+			"Cannot disable i2c controller, timeout\n");
+		return err;
+	}
+
+	mode = (1 + i2c->speed) << 1;
+	/* set the speed mode */
+	reg = readl(i2c->base + IC_CON);
+	if ((reg & 0x06) != mode) {
+		dev_dbg(&adap->dev, "set mode %d\n", i2c->speed);
+		writel((reg & ~0x6) | mode, i2c->base + IC_CON);
+	}
+
+	reg = readl(i2c->base + IC_CON);
+	/* use 7-bit addressing */
+	if (pmsg->flags & I2C_M_TEN) {
+		if ((reg & ADDR_10BIT) != ADDR_10BIT) {
+			dev_dbg(&adap->dev, "set i2c 10 bit address mode\n");
+			writel(reg | ADDR_10BIT, i2c->base + IC_CON);
+		}
+	} else {
+		if ((reg & ADDR_10BIT) != 0x0) {
+			dev_dbg(&adap->dev, "set i2c 7 bit address mode\n");
+			writel(reg & ~ADDR_10BIT, i2c->base + IC_CON);
+		}
+	}
+	/* enable restart conditions */
+	reg = readl(i2c->base + IC_CON);
+	if ((reg & RESTART) != RESTART) {
+		dev_dbg(&adap->dev, "enable restart conditions\n");
+		writel(reg | RESTART, i2c->base + IC_CON);
+	}
+
+	/* enable master FSM */
+	reg = readl(i2c->base + IC_CON);
+	dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+	writel(reg | MASTER_EN, i2c->base + IC_CON);
+	if ((reg & SLV_DIS) != SLV_DIS) {
+		dev_dbg(&adap->dev, "enable master FSM\n");
+		writel(reg | SLV_DIS, i2c->base + IC_CON);
+		dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+	}
+
+	/* use target address when initiating transfer */
+	reg = readl(i2c->base + IC_TAR);
+	bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START;
+
+	if ((reg & bit_mask) != 0x0) {
+		dev_dbg(&adap->dev,
+	 "WR: use target address when intiating transfer, i2c_tx_target\n");
+		writel(reg & ~bit_mask, i2c->base + IC_TAR);
+	}
+
+	/* set target address to the I2C slave address */
+	dev_dbg(&adap->dev,
+		"set target address to the I2C slave address, addr is %x\n",
+			pmsg->addr);
+	writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0),
+		i2c->base + IC_TAR);
+
+	/* Enable I2C controller */
+	writel(ENABLE, i2c->base + IC_ENABLE);
+
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_xfer - Main master transfer routine.
+ * @adap: i2c_adapter struct pointer
+ * @pmsg: i2c_msg struct pointer
+ * @num: number of i2c_msg
+ *
+ * Return Values:
+ * +		number of messages transfered
+ * -ETIMEDOUT	If cannot disable I2C controller or read IC_STATUS
+ * -EINVAL	If the address in i2c_msg is invalid
+ *
+ * This function will be registered in i2c-core and exposed to external
+ * I2C clients.
+ * 1. Disable I2C controller
+ * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT
+ * 3. Check if address in i2c_msg is valid
+ * 4. Enable I2C controller
+ * 5. Perform real transfer (call xfer_read or xfer_write)
+ * 6. Wait until the current transfer is finished (check bus state)
+ * 7. Mask and clear all interrupts
+ */
+static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
+			 struct i2c_msg *pmsg,
+			 int num)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i, err = 0;
+
+	/* if number of messages equal 0*/
+	if (num == 0)
+		return 0;
+
+	pm_runtime_get(i2c->dev);
+
+	mutex_lock(&i2c->lock);
+	dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num);
+	dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr);
+
+
+	if (i2c->status != STATUS_IDLE) {
+		dev_err(&adap->dev, "Adapter %d in transfer/standby\n",
+								adap->nr);
+		mutex_unlock(&i2c->lock);
+		pm_runtime_put(i2c->dev);
+		return -1;
+	}
+
+
+	for (i = 1; i < num; i++) {
+		/* Message address equal? */
+		if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) {
+			dev_err(&adap->dev, "Invalid address in msg[%d]\n", i);
+			mutex_unlock(&i2c->lock);
+			pm_runtime_put(i2c->dev);
+			return -EINVAL;
+		}
+	}
+
+	if (intel_mid_i2c_setup(adap, pmsg)) {
+		mutex_unlock(&i2c->lock);
+		pm_runtime_put(i2c->dev);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num; i++) {
+		i2c->msg = pmsg;
+		i2c->status = STATUS_IDLE;
+		/* Read or Write */
+		if (pmsg->flags & I2C_M_RD) {
+			dev_dbg(&adap->dev, "I2C_M_RD\n");
+			err = xfer_read(adap, pmsg->buf, pmsg->len);
+		} else {
+			dev_dbg(&adap->dev, "I2C_M_WR\n");
+			err = xfer_write(adap, pmsg->buf, pmsg->len);
+		}
+		if (err < 0)
+			break;
+		dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i);
+		pmsg++;		/* next message */
+	}
+
+	/* Mask interrupts */
+	writel(0x0000, i2c->base + IC_INTR_MASK);
+	/* Clear all interrupts */
+	readl(i2c->base + IC_CLR_INTR);
+
+	i2c->status = STATUS_IDLE;
+	mutex_unlock(&i2c->lock);
+	pm_runtime_put(i2c->dev);
+
+	return err;
+}
+
+static int intel_mid_i2c_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	int err;
+
+	if (i2c->status != STATUS_IDLE)
+		return -1;
+
+	intel_mid_i2c_disable(adap);
+
+	err = pci_save_state(pdev);
+	if (err) {
+		dev_err(dev, "pci_save_state failed\n");
+		return err;
+	}
+
+	err = pci_set_power_state(pdev, PCI_D3hot);
+	if (err) {
+		dev_err(dev, "pci_set_power_state failed\n");
+		return err;
+	}
+	i2c->status = STATUS_STANDBY;
+
+	return 0;
+}
+
+static int intel_mid_i2c_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+	int err;
+
+	if (i2c->status != STATUS_STANDBY)
+		return 0;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(dev, "pci_enable_device failed\n");
+		return err;
+	}
+
+	i2c->status = STATUS_IDLE;
+
+	intel_mid_i2c_hwinit(i2c);
+	return err;
+}
+
+static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
+{
+	struct i2c_msg *msg = i2c->msg;
+	int rx_num;
+	u32 len;
+	u8 *buf;
+
+	if (!(msg->flags & I2C_M_RD))
+		return;
+
+	if (i2c->status != STATUS_READ_IN_PROGRESS) {
+		len = msg->len;
+		buf = msg->buf;
+	} else {
+		len = i2c->rx_buf_len;
+		buf = i2c->rx_buf;
+	}
+
+	rx_num = readl(i2c->base + IC_RXFLR);
+
+	for (; len > 0 && rx_num > 0; len--, rx_num--)
+		*buf++ = readl(i2c->base + IC_DATA_CMD);
+
+	if (len > 0) {
+		i2c->status = STATUS_READ_IN_PROGRESS;
+		i2c->rx_buf_len = len;
+		i2c->rx_buf = buf;
+	} else
+		i2c->status = STATUS_READ_SUCCESS;
+
+	return;
+}
+
+static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
+{
+	struct intel_mid_i2c_private *i2c = dev;
+	u32 stat = readl(i2c->base + IC_INTR_STAT);
+
+	if (!stat)
+		return IRQ_NONE;
+
+	dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat);
+	stat &= 0x54;
+
+	if (i2c->status != STATUS_WRITE_START &&
+	    i2c->status != STATUS_READ_START &&
+	    i2c->status != STATUS_READ_IN_PROGRESS)
+		goto err;
+
+	if (stat & TX_ABRT)
+		i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE);
+
+	readl(i2c->base + IC_CLR_INTR);
+
+	if (stat & TX_ABRT) {
+		intel_mid_i2c_abort(i2c);
+		goto exit;
+	}
+
+	if (stat & RX_FULL) {
+		i2c_isr_read(i2c);
+		goto exit;
+	}
+
+	if (stat & TX_EMPTY) {
+		if (readl(i2c->base + IC_STATUS) & 0x4)
+			i2c->status = STATUS_WRITE_SUCCESS;
+	}
+
+exit:
+	if (i2c->status == STATUS_READ_SUCCESS ||
+	    i2c->status == STATUS_WRITE_SUCCESS ||
+	    i2c->status == STATUS_XFER_ABORT) {
+		/* Clear all interrupts */
+		readl(i2c->base + IC_CLR_INTR);
+		/* Mask interrupts */
+		writel(0, i2c->base + IC_INTR_MASK);
+		complete(&i2c->complete);
+	}
+err:
+	return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm intel_mid_i2c_algorithm = {
+	.master_xfer	= intel_mid_i2c_xfer,
+	.functionality	= intel_mid_i2c_func,
+};
+
+
+static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
+	.runtime_suspend = intel_mid_i2c_runtime_suspend,
+	.runtime_resume = intel_mid_i2c_runtime_resume,
+};
+
+/**
+ * intel_mid_i2c_probe - I2C controller initialization routine
+ * @dev: pci device
+ * @id: device id
+ *
+ * Return Values:
+ * 0		success
+ * -ENODEV	If cannot allocate pci resource
+ * -ENOMEM	If the register base remapping failed, or
+ *		if kzalloc failed
+ *
+ * Initialization steps:
+ * 1. Request for PCI resource
+ * 2. Remap the start address of PCI resource to register base
+ * 3. Request for device memory region
+ * 4. Fill in the struct members of intel_mid_i2c_private
+ * 5. Call intel_mid_i2c_hwinit() for hardware initialization
+ * 6. Register I2C adapter in i2c-core
+ */
+static int __devinit intel_mid_i2c_probe(struct pci_dev *dev,
+				    const struct pci_device_id *id)
+{
+	struct intel_mid_i2c_private *mrst;
+	unsigned long start, len;
+	int err, busnum;
+	void __iomem *base = NULL;
+
+	dev_dbg(&dev->dev, "Get into probe function for I2C\n");
+	err = pci_enable_device(dev);
+	if (err) {
+		dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n",
+			err);
+		goto exit;
+	}
+
+	/* Determine the address of the I2C area */
+	start = pci_resource_start(dev, 0);
+	len = pci_resource_len(dev, 0);
+	if (!start || len == 0) {
+		dev_err(&dev->dev, "base address not set\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n",
+		PLATFORM, start, len);
+
+	err = pci_request_region(dev, 0, DRIVER_NAME);
+	if (err) {
+		dev_err(&dev->dev, "failed to request I2C region "
+			"0x%lx-0x%lx\n", start,
+			(unsigned long)pci_resource_end(dev, 0));
+		goto exit;
+	}
+
+	base = ioremap_nocache(start, len);
+	if (!base) {
+		dev_err(&dev->dev, "I/O memory remapping failed\n");
+		err = -ENOMEM;
+		goto fail0;
+	}
+
+	/* Allocate the per-device data structure, intel_mid_i2c_private */
+	mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL);
+	if (mrst == NULL) {
+		dev_err(&dev->dev, "can't allocate interface\n");
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	/* Initialize struct members */
+	snprintf(mrst->adap.name, sizeof(mrst->adap.name),
+		"Intel MID I2C at %lx", start);
+	mrst->adap.owner = THIS_MODULE;
+	mrst->adap.algo = &intel_mid_i2c_algorithm;
+	mrst->adap.dev.parent = &dev->dev;
+	mrst->dev = &dev->dev;
+	mrst->base = base;
+	mrst->speed = STANDARD;
+	mrst->abort = 0;
+	mrst->rx_buf_len = 0;
+	mrst->status = STATUS_IDLE;
+
+	pci_set_drvdata(dev, mrst);
+	i2c_set_adapdata(&mrst->adap, mrst);
+
+	mrst->adap.nr = busnum = id->driver_data;
+	if (dev->device <= 0x0804)
+		mrst->platform = MOORESTOWN;
+	else
+		mrst->platform = MEDFIELD;
+
+	dev_dbg(&dev->dev, "I2C%d\n", busnum);
+
+	if (ctl_num > busnum) {
+		if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS)
+			dev_warn(&dev->dev, "invalid speed %d ignored.\n",
+							speed_mode[busnum]);
+		else
+			mrst->speed = speed_mode[busnum];
+	}
+
+	/* Initialize i2c controller */
+	err = intel_mid_i2c_hwinit(mrst);
+	if (err < 0) {
+		dev_err(&dev->dev, "I2C interface initialization failed\n");
+		goto fail2;
+	}
+
+	mutex_init(&mrst->lock);
+	init_completion(&mrst->complete);
+
+	/* Clear all interrupts */
+	readl(mrst->base + IC_CLR_INTR);
+	writel(0x0000, mrst->base + IC_INTR_MASK);
+
+	err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED,
+					mrst->adap.name, mrst);
+	if (err) {
+		dev_err(&dev->dev, "Failed to request IRQ for I2C controller: "
+			"%s", mrst->adap.name);
+		goto fail2;
+	}
+
+	/* Adapter registration */
+	err = i2c_add_numbered_adapter(&mrst->adap);
+	if (err) {
+		dev_err(&dev->dev, "Adapter %s registration failed\n",
+			mrst->adap.name);
+		goto fail3;
+	}
+
+	dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n",
+		(mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield",
+		busnum);
+
+	pm_runtime_enable(&dev->dev);
+	return 0;
+
+fail3:
+	free_irq(dev->irq, mrst);
+fail2:
+	pci_set_drvdata(dev, NULL);
+	kfree(mrst);
+fail1:
+	iounmap(base);
+fail0:
+	pci_release_region(dev, 0);
+exit:
+	return err;
+}
+
+static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
+{
+	struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
+	intel_mid_i2c_disable(&mrst->adap);
+	if (i2c_del_adapter(&mrst->adap))
+		dev_err(&dev->dev, "Failed to delete i2c adapter");
+
+	free_irq(dev->irq, mrst);
+	pci_set_drvdata(dev, NULL);
+	iounmap(mrst->base);
+	kfree(mrst);
+	pci_release_region(dev, 0);
+}
+
+static struct pci_device_id intel_mid_i2c_ids[] = {
+	/* Moorestown */
+	{ PCI_VDEVICE(INTEL, 0x0802), 0 },
+	{ PCI_VDEVICE(INTEL, 0x0803), 1 },
+	{ PCI_VDEVICE(INTEL, 0x0804), 2 },
+	/* Medfield */
+	{ PCI_VDEVICE(INTEL, 0x0817), 3,},
+	{ PCI_VDEVICE(INTEL, 0x0818), 4 },
+	{ PCI_VDEVICE(INTEL, 0x0819), 5 },
+	{ PCI_VDEVICE(INTEL, 0x082C), 0 },
+	{ PCI_VDEVICE(INTEL, 0x082D), 1 },
+	{ PCI_VDEVICE(INTEL, 0x082E), 2 },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids);
+
+static struct pci_driver intel_mid_i2c_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= intel_mid_i2c_ids,
+	.probe		= intel_mid_i2c_probe,
+	.remove		= __devexit_p(intel_mid_i2c_remove),
+};
+
+static int __init intel_mid_i2c_init(void)
+{
+	return pci_register_driver(&intel_mid_i2c_driver);
+}
+
+static void __exit intel_mid_i2c_exit(void)
+{
+	pci_unregister_driver(&intel_mid_i2c_driver);
+}
+
+module_init(intel_mid_i2c_init);
+module_exit(intel_mid_i2c_exit);
+
+MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
+MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-nomadik.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-nomadik.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-nomadik.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-nomadik.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 ST-Ericsson
+ * Copyright (C) 2009 ST-Ericsson SA
  * Copyright (C) 2009 STMicroelectronics
  *
  * I2C master mode controller driver, used in Nomadik 8815
@@ -103,6 +103,9 @@
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD	15
 
+/* per-transfer delay, required for the hardware to stabilize */
+#define I2C_DELAY		150
+
 enum i2c_status {
 	I2C_NOP,
 	I2C_ON_GOING,
@@ -118,7 +121,7 @@
 };
 
 /* controller response timeout in ms */
-#define I2C_TIMEOUT_MS	500
+#define I2C_TIMEOUT_MS	2000
 
 /**
  * struct i2c_nmk_client - client specific data
@@ -250,6 +253,8 @@
 {
 	int stat;
 
+	clk_enable(dev->clk);
+
 	stat = flush_i2c_fifo(dev);
 	if (stat)
 		return stat;
@@ -263,6 +268,9 @@
 
 	dev->cli.operation = I2C_NO_OPERATION;
 
+	clk_disable(dev->clk);
+
+	udelay(I2C_DELAY);
 	return 0;
 }
 
@@ -431,7 +439,6 @@
 		(void) init_hw(dev);
 		status = -ETIMEDOUT;
 	}
-
 	return status;
 }
 
@@ -502,9 +509,9 @@
 
 /**
  * nmk_i2c_xfer() - I2C transfer function used by kernel framework
- * @i2c_adap 	- Adapter pointer to the controller
- * @msgs[] - Pointer to data to be written.
- * @num_msgs - Number of messages to be executed
+ * @i2c_adap: Adapter pointer to the controller
+ * @msgs: Pointer to data to be written.
+ * @num_msgs: Number of messages to be executed
  *
  * This is the function called by the generic kernel i2c_transfer()
  * or i2c_smbus...() API calls. Note that this code is protected by the
@@ -559,6 +566,8 @@
 	if (status)
 		return status;
 
+	clk_enable(dev->clk);
+
 	/* setup the i2c controller */
 	setup_i2c_controller(dev);
 
@@ -591,10 +600,13 @@
 			dev_err(&dev->pdev->dev, "%s\n",
 				cause >= ARRAY_SIZE(abort_causes)
 				? "unknown reason" : abort_causes[cause]);
+			clk_disable(dev->clk);
 			return status;
 		}
-		mdelay(1);
+		udelay(I2C_DELAY);
 	}
+	clk_disable(dev->clk);
+
 	/* return the no. messages processed */
 	if (status)
 		return status;
@@ -605,6 +617,7 @@
 /**
  * disable_interrupts() - disable the interrupts
  * @dev: private data of controller
+ * @irq: interrupt number
  */
 static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
 {
@@ -794,10 +807,7 @@
 
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C
-		| I2C_FUNC_SMBUS_BYTE_DATA
-		| I2C_FUNC_SMBUS_WORD_DATA
-		| I2C_FUNC_SMBUS_I2C_BLOCK;
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
 static const struct i2c_algorithm nmk_i2c_algo = {
@@ -857,8 +867,6 @@
 		goto err_no_clk;
 	}
 
-	clk_enable(dev->clk);
-
 	adap = &dev->adap;
 	adap->dev.parent = &pdev->dev;
 	adap->owner	= THIS_MODULE;
@@ -895,7 +903,6 @@
 	return 0;
 
  err_init_hw:
-	clk_disable(dev->clk);
  err_add_adap:
 	clk_put(dev->clk);
  err_no_clk:
@@ -928,7 +935,6 @@
 	iounmap(dev->virtbase);
 	if (res)
 		release_mem_region(res->start, resource_size(res));
-	clk_disable(dev->clk);
 	clk_put(dev->clk);
 	platform_set_drvdata(pdev, NULL);
 	kfree(dev);
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-nuc900.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-nuc900.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-nuc900.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-nuc900.c	2011-01-04 19:50:19.000000000 -0500
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pasemi.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pasemi.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pasemi.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pasemi.c	2011-01-04 19:50:19.000000000 -0500
@@ -88,7 +88,7 @@
 	reg_write(smbus, REG_SMSTA, status);
 }
 
-static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
 {
 	int timeout = 10;
 	unsigned int status;
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pca-platform.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pca-platform.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pca-platform.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pca-platform.c	2011-01-04 19:50:19.000000000 -0500
@@ -224,7 +224,7 @@
 
 	if (irq) {
 		ret = request_irq(irq, i2c_pca_pf_handler,
-			IRQF_TRIGGER_FALLING, i2c->adap.name, i2c);
+			IRQF_TRIGGER_FALLING, pdev->name, i2c);
 		if (ret)
 			goto e_reqirq;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pxa.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pxa.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-pxa.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-pxa.c	2011-01-04 19:50:19.000000000 -0500
@@ -22,7 +22,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/sched.h>
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-s3c2410.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-s3c2410.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-s3c2410.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-s3c2410.c	2011-01-04 19:50:19.000000000 -0500
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
@@ -555,18 +554,23 @@
 	int retry;
 	int ret;
 
+	clk_enable(i2c->clk);
+
 	for (retry = 0; retry < adap->retries; retry++) {
 
 		ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
 
-		if (ret != -EAGAIN)
+		if (ret != -EAGAIN) {
+			clk_disable(i2c->clk);
 			return ret;
+		}
 
 		dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
 
 		udelay(100);
 	}
 
+	clk_disable(i2c->clk);
 	return -EREMOTEIO;
 }
 
@@ -911,6 +915,7 @@
 	platform_set_drvdata(pdev, i2c);
 
 	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
+	clk_disable(i2c->clk);
 	return 0;
 
  err_cpufreq:
@@ -978,7 +983,9 @@
 	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
 	i2c->suspended = 0;
+	clk_enable(i2c->clk);
 	s3c24xx_i2c_init(i2c);
+	clk_disable(i2c->clk);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-sh7760.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-sh7760.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-sh7760.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-sh7760.c	2011-01-04 19:50:19.000000000 -0500
@@ -101,12 +101,12 @@
 
 static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
 {
-	ctrl_outl(val, (unsigned long)cam->iobase + reg);
+	__raw_writel(val, (unsigned long)cam->iobase + reg);
 }
 
 static inline unsigned long IN32(struct cami2c *cam, int reg)
 {
-	return ctrl_inl((unsigned long)cam->iobase + reg);
+	return __raw_readl((unsigned long)cam->iobase + reg);
 }
 
 static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-sh_mobile.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-sh_mobile.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-sh_mobile.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-sh_mobile.c	2011-01-04 19:50:19.000000000 -0500
@@ -538,15 +538,17 @@
 {
 	struct resource *res;
 	int ret = -ENXIO;
-	int q, m;
-	int k = 0;
-	int n = 0;
+	int n, k = 0;
 
 	while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
 		for (n = res->start; hook && n <= res->end; n++) {
 			if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
-					dev_name(&dev->dev), dev))
+					dev_name(&dev->dev), dev)) {
+				for (n--; n >= res->start; n--)
+					free_irq(n, dev);
+
 				goto rollback;
+			}
 		}
 		k++;
 	}
@@ -554,16 +556,17 @@
 	if (hook)
 		return k > 0 ? 0 : -ENOENT;
 
-	k--;
 	ret = 0;
 
  rollback:
-	for (q = k; k >= 0; k--) {
-		for (m = n; m >= res->start; m--)
-			free_irq(m, dev);
+	k--;
 
-		res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
-		m = res->end;
+	while (k >= 0) {
+		res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+		for (n = res->start; n <= res->end; n++)
+			free_irq(n, dev);
+
+		k--;
 	}
 
 	return ret;
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-viapro.c linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-viapro.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/i2c-viapro.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/i2c-viapro.c	2011-01-04 19:50:19.000000000 -0500
@@ -185,14 +185,8 @@
 	}
 
 	if (temp & 0x04) {
-		int read = inb_p(SMBHSTADD) & 0x01;
 		result = -ENXIO;
-		/* The quick and receive byte commands are used to probe
-		   for chips, so errors are expected, and we don't want
-		   to frighten the user. */
-		if (!((size == VT596_QUICK && !read) ||
-		      (size == VT596_BYTE && read)))
-			dev_err(&vt596_adapter.dev, "Transaction error!\n");
+		dev_dbg(&vt596_adapter.dev, "No response\n");
 	}
 
 	/* Resetting status register */
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/Kconfig linux-libre-2.6.37-gnu/drivers/i2c/busses/Kconfig
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -95,10 +95,11 @@
 	    ESB2
 	    ICH8
 	    ICH9
-	    Tolapai
+	    EP80579 (Tolapai)
 	    ICH10
-	    3400/5 Series (PCH)
+	    5/3400 Series (PCH)
 	    Cougar Point (PCH)
+	    Patsburg (PCH)
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i801.
@@ -396,6 +397,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-imx.
 
+config I2C_INTEL_MID
+	tristate "Intel Moorestown/Medfield Platform I2C controller"
+	depends on PCI
+	help
+	  Say Y here if you have an Intel Moorestown/Medfield platform I2C
+	  controller.
+
+	  This support is also available as a module. If so, the module
+	  will be called i2c-intel-mid.
+
 config I2C_IOP3XX
 	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
 	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/Makefile linux-libre-2.6.37-gnu/drivers/i2c/busses/Makefile
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -38,6 +38,7 @@
 obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
+obj-$(CONFIG_I2C_INTEL_MID)	+= i2c-intel-mid.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
@@ -76,6 +77,4 @@
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
 
-ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/busses/scx200_acb.c linux-libre-2.6.37-gnu/drivers/i2c/busses/scx200_acb.c
--- linux-libre-2.6.36-gnu/drivers/i2c/busses/scx200_acb.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/busses/scx200_acb.c	2011-01-04 19:50:19.000000000 -0500
@@ -560,7 +560,8 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
 	  .driver_data = 1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
-	  .driver_data = 2 }
+	  .driver_data = 2 },
+	{ 0, }
 };
 
 static struct {
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/i2c-core.c linux-libre-2.6.37-gnu/drivers/i2c/i2c-core.c
--- linux-libre-2.6.36-gnu/drivers/i2c/i2c-core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/i2c-core.c	2011-01-04 19:50:19.000000000 -0500
@@ -425,14 +425,14 @@
 /* walk up mux tree */
 static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
 {
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 	int result;
 
 	result = device_for_each_child(&adapter->dev, &addr,
 					__i2c_check_addr_busy);
 
-	if (!result && i2c_parent_is_i2c_adapter(adapter))
-		result = i2c_check_mux_parents(
-				    to_i2c_adapter(adapter->dev.parent), addr);
+	if (!result && parent)
+		result = i2c_check_mux_parents(parent, addr);
 
 	return result;
 }
@@ -453,11 +453,11 @@
 
 static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
 {
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 	int result = 0;
 
-	if (i2c_parent_is_i2c_adapter(adapter))
-		result = i2c_check_mux_parents(
-				    to_i2c_adapter(adapter->dev.parent), addr);
+	if (parent)
+		result = i2c_check_mux_parents(parent, addr);
 
 	if (!result)
 		result = device_for_each_child(&adapter->dev, &addr,
@@ -472,8 +472,10 @@
  */
 void i2c_lock_adapter(struct i2c_adapter *adapter)
 {
-	if (i2c_parent_is_i2c_adapter(adapter))
-		i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent));
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		i2c_lock_adapter(parent);
 	else
 		rt_mutex_lock(&adapter->bus_lock);
 }
@@ -485,8 +487,10 @@
  */
 static int i2c_trylock_adapter(struct i2c_adapter *adapter)
 {
-	if (i2c_parent_is_i2c_adapter(adapter))
-		return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent));
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		return i2c_trylock_adapter(parent);
 	else
 		return rt_mutex_trylock(&adapter->bus_lock);
 }
@@ -497,8 +501,10 @@
  */
 void i2c_unlock_adapter(struct i2c_adapter *adapter)
 {
-	if (i2c_parent_is_i2c_adapter(adapter))
-		i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent));
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		i2c_unlock_adapter(parent);
 	else
 		rt_mutex_unlock(&adapter->bus_lock);
 }
@@ -677,8 +683,6 @@
 	char *blank, end;
 	int res;
 
-	dev_warn(dev, "The new_device interface is still experimental "
-		 "and may change in a near future\n");
 	memset(&info, 0, sizeof(struct i2c_board_info));
 
 	blank = strchr(buf, ' ');
@@ -844,6 +848,18 @@
 		goto out_list;
 	}
 
+	/* Sanity checks */
+	if (unlikely(adap->name[0] == '\0')) {
+		pr_err("i2c-core: Attempt to register an adapter with "
+		       "no name!\n");
+		return -EINVAL;
+	}
+	if (unlikely(!adap->algo)) {
+		pr_err("i2c-core: Attempt to register adapter '%s' with "
+		       "no algo!\n", adap->name);
+		return -EINVAL;
+	}
+
 	rt_mutex_init(&adap->bus_lock);
 	mutex_init(&adap->userspace_clients_lock);
 	INIT_LIST_HEAD(&adap->userspace_clients);
@@ -1504,26 +1520,25 @@
 	if (!driver->detect || !address_list)
 		return 0;
 
+	/* Stop here if the classes do not match */
+	if (!(adapter->class & driver->class))
+		return 0;
+
 	/* Set up a temporary client to help detect callback */
 	temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 	if (!temp_client)
 		return -ENOMEM;
 	temp_client->adapter = adapter;
 
-	/* Stop here if the classes do not match */
-	if (!(adapter->class & driver->class))
-		goto exit_free;
-
 	for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
 		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
 			"addr 0x%02x\n", adap_id, address_list[i]);
 		temp_client->addr = address_list[i];
 		err = i2c_detect_address(temp_client, driver);
-		if (err)
-			goto exit_free;
+		if (unlikely(err))
+			break;
 	}
 
- exit_free:
 	kfree(temp_client);
 	return err;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/i2c-dev.c linux-libre-2.6.37-gnu/drivers/i2c/i2c-dev.c
--- linux-libre-2.6.36-gnu/drivers/i2c/i2c-dev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/i2c-dev.c	2011-01-04 19:50:19.000000000 -0500
@@ -192,13 +192,12 @@
 /* walk up mux tree */
 static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
 {
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 	int result;
 
 	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
-
-	if (!result && i2c_parent_is_i2c_adapter(adapter))
-		result = i2cdev_check_mux_parents(
-				    to_i2c_adapter(adapter->dev.parent), addr);
+	if (!result && parent)
+		result = i2cdev_check_mux_parents(parent, addr);
 
 	return result;
 }
@@ -222,11 +221,11 @@
    driver bound to it, as NOT busy. */
 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
 	int result = 0;
 
-	if (i2c_parent_is_i2c_adapter(adapter))
-		result = i2cdev_check_mux_parents(
-				    to_i2c_adapter(adapter->dev.parent), addr);
+	if (parent)
+		result = i2cdev_check_mux_parents(parent, addr);
 
 	if (!result)
 		result = device_for_each_child(&adapter->dev, &addr,
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/i2c-mux.c linux-libre-2.6.37-gnu/drivers/i2c/i2c-mux.c
--- linux-libre-2.6.36-gnu/drivers/i2c/i2c-mux.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/i2c-mux.c	2011-01-04 19:50:19.000000000 -0500
@@ -120,7 +120,6 @@
 	snprintf(priv->adap.name, sizeof(priv->adap.name),
 		 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
 	priv->adap.owner = THIS_MODULE;
-	priv->adap.id = parent->id;
 	priv->adap.algo = &priv->algo;
 	priv->adap.algo_data = priv;
 	priv->adap.dev.parent = &parent->dev;
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/Makefile linux-libre-2.6.37-gnu/drivers/i2c/Makefile
--- linux-libre-2.6.36-gnu/drivers/i2c/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -9,6 +9,4 @@
 obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
 obj-y				+= algos/ busses/ muxes/
 
-ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/muxes/Kconfig linux-libre-2.6.37-gnu/drivers/i2c/muxes/Kconfig
--- linux-libre-2.6.36-gnu/drivers/i2c/muxes/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/muxes/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -5,6 +5,16 @@
 menu "Multiplexer I2C Chip support"
 	depends on I2C_MUX
 
+config I2C_MUX_PCA9541
+	tristate "NXP PCA9541 I2C Master Selector"
+	depends on EXPERIMENTAL
+	help
+	  If you say yes here you get support for the NXP PCA9541
+	  I2C Master Selector.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pca9541.
+
 config I2C_MUX_PCA954x
 	tristate "Philips PCA954x I2C Mux/switches"
 	depends on EXPERIMENTAL
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/muxes/Makefile linux-libre-2.6.37-gnu/drivers/i2c/muxes/Makefile
--- linux-libre-2.6.36-gnu/drivers/i2c/muxes/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/muxes/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,8 +1,7 @@
 #
 # Makefile for multiplexer I2C chip drivers.
 
+obj-$(CONFIG_I2C_MUX_PCA9541)	+= pca9541.o
 obj-$(CONFIG_I2C_MUX_PCA954x)	+= pca954x.o
 
-ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/muxes/pca9541.c linux-libre-2.6.37-gnu/drivers/i2c/muxes/pca9541.c
--- linux-libre-2.6.36-gnu/drivers/i2c/muxes/pca9541.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-libre-2.6.37-gnu/drivers/i2c/muxes/pca9541.c	2011-01-04 19:50:19.000000000 -0500
@@ -0,0 +1,411 @@
+/*
+ * I2C multiplexer driver for PCA9541 bus master selector
+ *
+ * Copyright (c) 2010 Ericsson AB.
+ *
+ * Author: Guenter Roeck <guenter.roeck@ericsson.com>
+ *
+ * Derived from:
+ *  pca954x.c
+ *
+ *  Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ *  Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+/*
+ * The PCA9541 is a bus master selector. It supports two I2C masters connected
+ * to a single slave bus.
+ *
+ * Before each bus transaction, a master has to acquire bus ownership. After the
+ * transaction is complete, bus ownership has to be released. This fits well
+ * into the I2C multiplexer framework, which provides select and release
+ * functions for this purpose. For this reason, this driver is modeled as
+ * single-channel I2C bus multiplexer.
+ *
+ * This driver assumes that the two bus masters are controlled by two different
+ * hosts. If a single host controls both masters, platform code has to ensure
+ * that only one of the masters is instantiated at any given time.
+ */
+
+#define PCA9541_CONTROL		0x01
+#define PCA9541_ISTAT		0x02
+
+#define PCA9541_CTL_MYBUS	(1 << 0)
+#define PCA9541_CTL_NMYBUS	(1 << 1)
+#define PCA9541_CTL_BUSON	(1 << 2)
+#define PCA9541_CTL_NBUSON	(1 << 3)
+#define PCA9541_CTL_BUSINIT	(1 << 4)
+#define PCA9541_CTL_TESTON	(1 << 6)
+#define PCA9541_CTL_NTESTON	(1 << 7)
+
+#define PCA9541_ISTAT_INTIN	(1 << 0)
+#define PCA9541_ISTAT_BUSINIT	(1 << 1)
+#define PCA9541_ISTAT_BUSOK	(1 << 2)
+#define PCA9541_ISTAT_BUSLOST	(1 << 3)
+#define PCA9541_ISTAT_MYTEST	(1 << 6)
+#define PCA9541_ISTAT_NMYTEST	(1 << 7)
+
+#define BUSON		(PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
+#define MYBUS		(PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
+#define mybus(x)	(!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
+#define busoff(x)	(!((x) & BUSON) || ((x) & BUSON) == BUSON)
+
+/* arbitration timeouts, in jiffies */
+#define ARB_TIMEOUT	(HZ / 8)	/* 125 ms until forcing bus ownership */
+#define ARB2_TIMEOUT	(HZ / 4)	/* 250 ms until acquisition failure */
+
+/* arbitration retry delays, in us */
+#define SELECT_DELAY_SHORT	50
+#define SELECT_DELAY_LONG	1000
+
+struct pca9541 {
+	struct i2c_adapter *mux_adap;
+	unsigned long select_timeout;
+	unsigned long arb_timeout;
+};
+
+static const struct i2c_device_id pca9541_id[] = {
+	{"pca9541", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, pca9541_id);
+
+/*
+ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock the adapter a second time.
+ */
+static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int ret;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg;
+		char buf[2];
+
+		msg.addr = client->addr;
+		msg.flags = 0;
+		msg.len = 2;
+		buf[0] = command;
+		buf[1] = val;
+		msg.buf = buf;
+		ret = adap->algo->master_xfer(adap, &msg, 1);
+	} else {
+		union i2c_smbus_data data;
+
+		data.byte = val;
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_WRITE,
+					     command,
+					     I2C_SMBUS_BYTE_DATA, &data);
+	}
+
+	return ret;
+}
+
+/*
+ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock adapter a second time.
+ */
+static int pca9541_reg_read(struct i2c_client *client, u8 command)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int ret;
+	u8 val;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg[2] = {
+			{
+				.addr = client->addr,
+				.flags = 0,
+				.len = 1,
+				.buf = &command
+			},
+			{
+				.addr = client->addr,
+				.flags = I2C_M_RD,
+				.len = 1,
+				.buf = &val
+			}
+		};
+		ret = adap->algo->master_xfer(adap, msg, 2);
+		if (ret == 2)
+			ret = val;
+		else if (ret >= 0)
+			ret = -EIO;
+	} else {
+		union i2c_smbus_data data;
+
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_READ,
+					     command,
+					     I2C_SMBUS_BYTE_DATA, &data);
+		if (!ret)
+			ret = data.byte;
+	}
+	return ret;
+}
+
+/*
+ * Arbitration management functions
+ */
+
+/* Release bus. Also reset NTESTON and BUSINIT if it was set. */
+static void pca9541_release_bus(struct i2c_client *client)
+{
+	int reg;
+
+	reg = pca9541_reg_read(client, PCA9541_CONTROL);
+	if (reg >= 0 && !busoff(reg) && mybus(reg))
+		pca9541_reg_write(client, PCA9541_CONTROL,
+				  (reg & PCA9541_CTL_NBUSON) >> 1);
+}
+
+/*
+ * Arbitration is defined as a two-step process. A bus master can only activate
+ * the slave bus if it owns it; otherwise it has to request ownership first.
+ * This multi-step process ensures that access contention is resolved
+ * gracefully.
+ *
+ * Bus	Ownership	Other master	Action
+ * state		requested access
+ * ----------------------------------------------------
+ * off	-		yes		wait for arbitration timeout or
+ *					for other master to drop request
+ * off	no		no		take ownership
+ * off	yes		no		turn on bus
+ * on	yes		-		done
+ * on	no		-		wait for arbitration timeout or
+ *					for other master to release bus
+ *
+ * The main contention point occurs if the slave bus is off and both masters
+ * request ownership at the same time. In this case, one master will turn on
+ * the slave bus, believing that it owns it. The other master will request
+ * bus ownership. Result is that the bus is turned on, and master which did
+ * _not_ own the slave bus before ends up owning it.
+ */
+
+/* Control commands per PCA9541 datasheet */
+static const u8 pca9541_control[16] = {
+	4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1
+};
+
+/*
+ * Channel arbitration
+ *
+ * Return values:
+ *  <0: error
+ *  0 : bus not acquired
+ *  1 : bus acquired
+ */
+static int pca9541_arbitrate(struct i2c_client *client)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+	int reg;
+
+	reg = pca9541_reg_read(client, PCA9541_CONTROL);
+	if (reg < 0)
+		return reg;
+
+	if (busoff(reg)) {
+		int istat;
+		/*
+		 * Bus is off. Request ownership or turn it on unless
+		 * other master requested ownership.
+		 */
+		istat = pca9541_reg_read(client, PCA9541_ISTAT);
+		if (!(istat & PCA9541_ISTAT_NMYTEST)
+		    || time_is_before_eq_jiffies(data->arb_timeout)) {
+			/*
+			 * Other master did not request ownership,
+			 * or arbitration timeout expired. Take the bus.
+			 */
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  pca9541_control[reg & 0x0f]
+					  | PCA9541_CTL_NTESTON);
+			data->select_timeout = SELECT_DELAY_SHORT;
+		} else {
+			/*
+			 * Other master requested ownership.
+			 * Set extra long timeout to give it time to acquire it.
+			 */
+			data->select_timeout = SELECT_DELAY_LONG * 2;
+		}
+	} else if (mybus(reg)) {
+		/*
+		 * Bus is on, and we own it. We are done with acquisition.
+		 * Reset NTESTON and BUSINIT, then return success.
+		 */
+		if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT))
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  reg & ~(PCA9541_CTL_NTESTON
+						  | PCA9541_CTL_BUSINIT));
+		return 1;
+	} else {
+		/*
+		 * Other master owns the bus.
+		 * If arbitration timeout has expired, force ownership.
+		 * Otherwise request it.
+		 */
+		data->select_timeout = SELECT_DELAY_LONG;
+		if (time_is_before_eq_jiffies(data->arb_timeout)) {
+			/* Time is up, take the bus and reset it. */
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  pca9541_control[reg & 0x0f]
+					  | PCA9541_CTL_BUSINIT
+					  | PCA9541_CTL_NTESTON);
+		} else {
+			/* Request bus ownership if needed */
+			if (!(reg & PCA9541_CTL_NTESTON))
+				pca9541_reg_write(client,
+						  PCA9541_CONTROL,
+						  reg | PCA9541_CTL_NTESTON);
+		}
+	}
+	return 0;
+}
+
+static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+	int ret;
+	unsigned long timeout = jiffies + ARB2_TIMEOUT;
+		/* give up after this time */
+
+	data->arb_timeout = jiffies + ARB_TIMEOUT;
+		/* force bus ownership after this time */
+
+	do {
+		ret = pca9541_arbitrate(client);
+		if (ret)
+			return ret < 0 ? ret : 0;
+
+		if (data->select_timeout == SELECT_DELAY_SHORT)
+			udelay(data->select_timeout);
+		else
+			msleep(data->select_timeout / 1000);
+	} while (time_is_after_eq_jiffies(timeout));
+
+	return -ETIMEDOUT;
+}
+
+static int pca9541_release_chan(struct i2c_adapter *adap,
+				void *client, u32 chan)
+{
+	pca9541_release_bus(client);
+	return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca9541_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct pca954x_platform_data *pdata = client->dev.platform_data;
+	struct pca9541 *data;
+	int force;
+	int ret = -ENODEV;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto err;
+
+	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/*
+	 * I2C accesses are unprotected here.
+	 * We have to lock the adapter before releasing the bus.
+	 */
+	i2c_lock_adapter(adap);
+	pca9541_release_bus(client);
+	i2c_unlock_adapter(adap);
+
+	/* Create mux adapter */
+
+	force = 0;
+	if (pdata)
+		force = pdata->modes[0].adap_id;
+	data->mux_adap = i2c_add_mux_adapter(adap, client, force, 0,
+					     pca9541_select_chan,
+					     pca9541_release_chan);
+
+	if (data->mux_adap == NULL) {
+		dev_err(&client->dev, "failed to register master selector\n");
+		goto exit_free;
+	}
+
+	dev_info(&client->dev, "registered master selector for I2C %s\n",
+		 client->name);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+err:
+	return ret;
+}
+
+static int pca9541_remove(struct i2c_client *client)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+
+	i2c_del_mux_adapter(data->mux_adap);
+
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_driver pca9541_driver = {
+	.driver = {
+		   .name = "pca9541",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = pca9541_probe,
+	.remove = pca9541_remove,
+	.id_table = pca9541_id,
+};
+
+static int __init pca9541_init(void)
+{
+	return i2c_add_driver(&pca9541_driver);
+}
+
+static void __exit pca9541_exit(void)
+{
+	i2c_del_driver(&pca9541_driver);
+}
+
+module_init(pca9541_init);
+module_exit(pca9541_exit);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
+MODULE_LICENSE("GPL v2");
diff -druN linux-libre-2.6.36-gnu/drivers/i2c/muxes/pca954x.c linux-libre-2.6.37-gnu/drivers/i2c/muxes/pca954x.c
--- linux-libre-2.6.36-gnu/drivers/i2c/muxes/pca954x.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/i2c/muxes/pca954x.c	2011-01-04 19:50:19.000000000 -0500
@@ -181,8 +181,8 @@
 /*
  * I2C init/probing/exit functions
  */
-static int __devinit pca954x_probe(struct i2c_client *client,
-				   const struct i2c_device_id *id)
+static int pca954x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
 	struct pca954x_platform_data *pdata = client->dev.platform_data;
@@ -255,7 +255,7 @@
 	return ret;
 }
 
-static int __devexit pca954x_remove(struct i2c_client *client)
+static int pca954x_remove(struct i2c_client *client)
 {
 	struct pca954x *data = i2c_get_clientdata(client);
 	const struct chip_desc *chip = &chips[data->type];
@@ -279,7 +279,7 @@
 		.owner	= THIS_MODULE,
 	},
 	.probe		= pca954x_probe,
-	.remove		= __devexit_p(pca954x_remove),
+	.remove		= pca954x_remove,
 	.id_table	= pca954x_id,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/ide/hpt366.c linux-libre-2.6.37-gnu/drivers/ide/hpt366.c
--- linux-libre-2.6.36-gnu/drivers/ide/hpt366.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/hpt366.c	2011-01-04 19:50:19.000000000 -0500
@@ -12,7 +12,7 @@
  *
  *
  * HighPoint has its own drivers (open source except for the RAID part)
- * available from http://www.highpoint-tech.com/BIOS%20+%20Driver/.
+ * available from http://www.highpoint-tech.com/USA_new/service_support.htm 
  * This may be useful to anyone wanting to work on this driver, however  do not
  * trust  them too much since the code tends to become less and less meaningful
  * as the time passes... :-/
@@ -838,7 +838,7 @@
 
 static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 {
-	hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x23 : 0x21);
+	hpt3xxn_set_clock(drive->hwif, rq_data_dir(rq) ? 0x21 : 0x23);
 }
 
 /**
@@ -1173,8 +1173,9 @@
 		u16 mcr;
 
 		pci_read_config_word(dev, mcr_addr, &mcr);
-		pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
-		/* now read cable id register */
+		pci_write_config_word(dev, mcr_addr, mcr | 0x8000);
+		/* Debounce, then read cable ID register */
+		udelay(10);
 		pci_read_config_byte(dev, 0x5a, &scr1);
 		pci_write_config_word(dev, mcr_addr, mcr);
 	} else if (chip_type >= HPT370) {
@@ -1185,10 +1186,11 @@
 		u8 scr2 = 0;
 
 		pci_read_config_byte(dev, 0x5b, &scr2);
-		pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
-		/* now read cable id register */
+		pci_write_config_byte(dev, 0x5b, scr2 & ~1);
+		/* Debounce, then read cable ID register */
+		udelay(10);
 		pci_read_config_byte(dev, 0x5a, &scr1);
-		pci_write_config_byte(dev, 0x5b,  scr2);
+		pci_write_config_byte(dev, 0x5b, scr2);
 	} else
 		pci_read_config_byte(dev, 0x5a, &scr1);
 
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ht6560b.c linux-libre-2.6.37-gnu/drivers/ide/ht6560b.c
--- linux-libre-2.6.36-gnu/drivers/ide/ht6560b.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ht6560b.c	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,6 @@
  *  Author:    Mikko Ala-Fossi            <maf@iki.fi>
  *             Jan Evert van Grootheest   <j.e.van.grootheest@caiway.nl>
  *
- *  Try:  http://www.maf.iki.fi/~maf/ht6560b/
  */
 
 #define DRV_NAME	"ht6560b"
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-cd.c linux-libre-2.6.37-gnu/drivers/ide/ide-cd.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-cd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-cd.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,7 +31,6 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
@@ -52,6 +51,7 @@
 
 #include "ide-cd.h"
 
+static DEFINE_MUTEX(ide_cd_mutex);
 static DEFINE_MUTEX(idecd_ref_mutex);
 
 static void ide_cd_release(struct device *);
@@ -1602,7 +1602,7 @@
 	struct cdrom_info *info;
 	int rc = -ENXIO;
 
-	lock_kernel();
+	mutex_lock(&ide_cd_mutex);
 	info = ide_cd_get(bdev->bd_disk);
 	if (!info)
 		goto out;
@@ -1611,7 +1611,7 @@
 	if (rc < 0)
 		ide_cd_put(info);
 out:
-	unlock_kernel();
+	mutex_unlock(&ide_cd_mutex);
 	return rc;
 }
 
@@ -1619,11 +1619,11 @@
 {
 	struct cdrom_info *info = ide_drv_g(disk, cdrom_info);
 
-	lock_kernel();
+	mutex_lock(&ide_cd_mutex);
 	cdrom_release(&info->devinfo, mode);
 
 	ide_cd_put(info);
-	unlock_kernel();
+	mutex_unlock(&ide_cd_mutex);
 
 	return 0;
 }
@@ -1694,9 +1694,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ide_cd_mutex);
 	ret = idecd_locked_ioctl(bdev, mode, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ide_cd_mutex);
 
 	return ret;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-cs.c linux-libre-2.6.37-gnu/drivers/ide/ide-cs.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-cs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-cs.c	2011-01-04 19:50:19.000000000 -0500
@@ -43,7 +43,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
@@ -72,17 +71,6 @@
 
 static void ide_detach(struct pcmcia_device *p_dev);
 
-
-
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int ide_probe(struct pcmcia_device *link)
 {
     ide_info_t *info;
@@ -97,23 +85,12 @@
     info->p_dev = link;
     link->priv = info;
 
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
+	    CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
 
     return ide_config(link);
 } /* ide_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void ide_detach(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
@@ -187,79 +164,31 @@
     return NULL;
 }
 
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-struct pcmcia_config_check {
-	unsigned long ctl_base;
-	int skip_vcc;
-	int is_kme;
-};
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev,
-				   cistpl_cftable_entry_t *cfg,
-				   cistpl_cftable_entry_t *dflt,
-				   unsigned int vcc,
-				   void *priv_data)
+static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
 {
-	struct pcmcia_config_check *stk = priv_data;
+	int *is_kme = priv_data;
 
-	/* Check for matching Vcc, unless we're desperate */
-	if (!stk->skip_vcc) {
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-				return -ENODEV;
-		} else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
-				return -ENODEV;
-		}
+	if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) {
+		pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+		pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 	}
+	pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+	pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
 
-	if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-	else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-		pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-	if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-		cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-		pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-
-		pdev->conf.ConfigIndex = cfg->index;
-		pdev->resource[0]->start = io->win[0].base;
-		if (!(io->flags & CISTPL_IO_16BIT)) {
-			pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-			pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-		}
-		if (io->nwin == 2) {
-			pdev->resource[0]->end = 8;
-			pdev->resource[1]->start = io->win[1].base;
-			pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
-			if (pcmcia_request_io(pdev) != 0)
-				return -ENODEV;
-			stk->ctl_base = pdev->resource[1]->start;
-		} else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-			pdev->resource[0]->end = io->win[0].len;
-			pdev->resource[1]->end = 0;
-			if (pcmcia_request_io(pdev) != 0)
-				return -ENODEV;
-			stk->ctl_base = pdev->resource[0]->start + 0x0e;
-		} else
+	if (pdev->resource[1]->end) {
+		pdev->resource[0]->end = 8;
+		pdev->resource[1]->end = (*is_kme) ? 2 : 1;
+	} else {
+		if (pdev->resource[0]->end < 16)
 			return -ENODEV;
-		/* If we've got this far, we're done */
-		return 0;
 	}
-	return -ENODEV;
+
+	return pcmcia_request_io(pdev);
 }
 
 static int ide_config(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
-    struct pcmcia_config_check *stk = NULL;
     int ret = 0, is_kme = 0;
     unsigned long io_base, ctl_base;
     struct ide_host *host;
@@ -270,23 +199,21 @@
 	      ((link->card_id == PRODID_KME_KXLC005_A) ||
 	       (link->card_id == PRODID_KME_KXLC005_B)));
 
-    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-    if (!stk)
-	    goto err_mem;
-    stk->is_kme = is_kme;
-    stk->skip_vcc = io_base = ctl_base = 0;
-
-    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
-	    stk->skip_vcc = 1;
-	    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
+    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
+	    link->config_flags &= ~CONF_AUTO_CHECK_VCC;
+	    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
 		    goto failed; /* No suitable config found */
     }
     io_base = link->resource[0]->start;
-    ctl_base = stk->ctl_base;
+    if (link->resource[1]->end)
+	    ctl_base = link->resource[1]->start;
+    else
+	    ctl_base = link->resource[0]->start + 0x0e;
 
     if (!link->irq)
 	    goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+
+    ret = pcmcia_enable_device(link);
     if (ret)
 	    goto failed;
 
@@ -311,29 +238,15 @@
     info->host = host;
     dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
 	    'a' + host->ports[0]->index * 2,
-	    link->conf.Vpp / 10, link->conf.Vpp % 10);
+	    link->vpp / 10, link->vpp % 10);
 
-    kfree(stk);
     return 0;
 
-err_mem:
-    printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
-    goto failed;
-
 failed:
-    kfree(stk);
     ide_release(link);
     return -ENODEV;
 } /* ide_config */
 
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void ide_release(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
@@ -359,15 +272,6 @@
 } /* ide_release */
 
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-
-======================================================================*/
-
 static struct pcmcia_device_id ide_ids[] = {
 	PCMCIA_DEVICE_FUNC_ID(4),
 	PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),	/* Corsair */
@@ -440,9 +344,7 @@
 
 static struct pcmcia_driver ide_cs_driver = {
 	.owner		= THIS_MODULE,
-	.drv		= {
-		.name	= "ide-cs",
-	},
+	.name		= "ide-cs",
 	.probe		= ide_probe,
 	.remove		= ide_detach,
 	.id_table       = ide_ids,
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-disk.c linux-libre-2.6.37-gnu/drivers/ide/ide-disk.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-disk.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-disk.c	2011-01-04 19:50:19.000000000 -0500
@@ -435,12 +435,11 @@
 	if (!(rq->cmd_flags & REQ_FLUSH))
 		return BLKPREP_OK;
 
-	cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
+	cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
 
 	/* FIXME: map struct ide_taskfile on rq->cmd[] */
 	BUG_ON(cmd == NULL);
 
-	memset(cmd, 0, sizeof(*cmd));
 	if (ata_id_flush_ext_enabled(drive->id) &&
 	    (drive->capacity64 >= (1UL << 28)))
 		cmd->tf.command = ATA_CMD_FLUSH_EXT;
@@ -516,10 +515,10 @@
 	return ide_no_data_taskfile(drive, &cmd);
 }
 
-static void update_ordered(ide_drive_t *drive)
+static void update_flush(ide_drive_t *drive)
 {
 	u16 *id = drive->id;
-	unsigned ordered = QUEUE_ORDERED_NONE;
+	unsigned flush = 0;
 
 	if (drive->dev_flags & IDE_DFLAG_WCACHE) {
 		unsigned long long capacity;
@@ -543,13 +542,12 @@
 		       drive->name, barrier ? "" : "not ");
 
 		if (barrier) {
-			ordered = QUEUE_ORDERED_DRAIN_FLUSH;
+			flush = REQ_FLUSH;
 			blk_queue_prep_rq(drive->queue, idedisk_prep_fn);
 		}
-	} else
-		ordered = QUEUE_ORDERED_DRAIN;
+	}
 
-	blk_queue_ordered(drive->queue, ordered);
+	blk_queue_flush(drive->queue, flush);
 }
 
 ide_devset_get_flag(wcache, IDE_DFLAG_WCACHE);
@@ -572,7 +570,7 @@
 		}
 	}
 
-	update_ordered(drive);
+	update_flush(drive);
 
 	return err;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-disk_ioctl.c linux-libre-2.6.37-gnu/drivers/ide/ide-disk_ioctl.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-disk_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-disk_ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,11 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
 #include <linux/hdreg.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include "ide-disk.h"
 
+static DEFINE_MUTEX(ide_disk_ioctl_mutex);
 static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
 { HDIO_GET_ADDRESS,	HDIO_SET_ADDRESS,   &ide_devset_address   },
 { HDIO_GET_MULTCOUNT,	HDIO_SET_MULTCOUNT, &ide_devset_multcount },
@@ -19,13 +20,13 @@
 {
 	int err;
 
-	lock_kernel();
+	mutex_lock(&ide_disk_ioctl_mutex);
 	err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);
 	if (err != -EOPNOTSUPP)
 		goto out;
 
 	err = generic_ide_ioctl(drive, bdev, cmd, arg);
 out:
-	unlock_kernel();
+	mutex_unlock(&ide_disk_ioctl_mutex);
 	return err;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-dma.c linux-libre-2.6.37-gnu/drivers/ide/ide-dma.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-dma.c	2011-01-04 19:50:19.000000000 -0500
@@ -449,7 +449,6 @@
 	ide_hwif_t *hwif = drive->hwif;
 	const struct ide_dma_ops *dma_ops = hwif->dma_ops;
 	struct ide_cmd *cmd = &hwif->cmd;
-	struct request *rq;
 	ide_startstop_t ret = ide_stopped;
 
 	/*
@@ -487,14 +486,10 @@
 	ide_dma_off_quietly(drive);
 
 	/*
-	 * un-busy drive etc and make sure request is sane
+	 * make sure request is sane
 	 */
-	rq = hwif->rq;
-	if (rq) {
-		hwif->rq = NULL;
-		rq->errors = 0;
-		ide_requeue_and_plug(drive, rq);
-	}
+	if (hwif->rq)
+		hwif->rq->errors = 0;
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-floppy_ioctl.c linux-libre-2.6.37-gnu/drivers/ide/ide-floppy_ioctl.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-floppy_ioctl.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-floppy_ioctl.c	2011-01-04 19:50:19.000000000 -0500
@@ -5,7 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/ide.h>
 #include <linux/cdrom.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
 
 #include <asm/unaligned.h>
 
@@ -32,6 +32,7 @@
  * On exit we set nformats to the number of records we've actually initialized.
  */
 
+static DEFINE_MUTEX(ide_floppy_ioctl_mutex);
 static int ide_floppy_get_format_capacities(ide_drive_t *drive,
 					    struct ide_atapi_pc *pc,
 					    int __user *arg)
@@ -276,7 +277,7 @@
 	void __user *argp = (void __user *)arg;
 	int err;
 
-	lock_kernel();
+	mutex_lock(&ide_floppy_ioctl_mutex);
 	if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR) {
 		err = ide_floppy_lockdoor(drive, &pc, arg, cmd);
 		goto out;
@@ -298,6 +299,6 @@
 		err = generic_ide_ioctl(drive, bdev, cmd, arg);
 
 out:
-	unlock_kernel();
+	mutex_unlock(&ide_floppy_ioctl_mutex);
 	return err;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-gd.c linux-libre-2.6.37-gnu/drivers/ide/ide-gd.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-gd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-gd.c	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,3 @@
-#include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -23,6 +22,7 @@
 #define IDE_GD_VERSION	"1.18"
 
 /* module parameters */
+static DEFINE_MUTEX(ide_gd_mutex);
 static unsigned long debug_mask;
 module_param(debug_mask, ulong, 0644);
 
@@ -242,9 +242,9 @@
 {
 	int ret;
 
-	lock_kernel();
+	mutex_lock(&ide_gd_mutex);
 	ret = ide_gd_open(bdev, mode);
-	unlock_kernel();
+	mutex_unlock(&ide_gd_mutex);
 
 	return ret;
 }
@@ -257,7 +257,7 @@
 
 	ide_debug_log(IDE_DBG_FUNC, "enter");
 
-	lock_kernel();
+	mutex_lock(&ide_gd_mutex);
 	if (idkp->openers == 1)
 		drive->disk_ops->flush(drive);
 
@@ -269,7 +269,7 @@
 	idkp->openers--;
 
 	ide_disk_put(idkp);
-	unlock_kernel();
+	mutex_unlock(&ide_gd_mutex);
 
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-io.c linux-libre-2.6.37-gnu/drivers/ide/ide-io.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-io.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-io.c	2011-01-04 19:50:19.000000000 -0500
@@ -441,19 +441,6 @@
 	struct request	*rq = NULL;
 	ide_startstop_t	startstop;
 
-	/*
-	 * drive is doing pre-flush, ordered write, post-flush sequence. even
-	 * though that is 3 requests, it must be seen as a single transaction.
-	 * we must not preempt this drive until that is complete
-	 */
-	if (blk_queue_flushing(q))
-		/*
-		 * small race where queue could get replugged during
-		 * the 3-request flush cycle, just yank the plug since
-		 * we want it to finish asap
-		 */
-		blk_remove_plug(q);
-
 	spin_unlock_irq(q->queue_lock);
 
 	/* HLD do_request() callback might sleep, make sure it's okay */
diff -druN linux-libre-2.6.36-gnu/drivers/ide/ide-tape.c linux-libre-2.6.37-gnu/drivers/ide/ide-tape.c
--- linux-libre-2.6.36-gnu/drivers/ide/ide-tape.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ide/ide-tape.c	2011-01-04 19:50:19.000000000 -0500
@@ -32,11 +32,9 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/seq_file.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/ide.h>
-#include <linux/smp_lock.h>
 #include <linux/completion.h>
 #include <linux/bitops.h>
 #include <linux/mutex.h>
@@ -220,6 +218,7 @@
 	char write_prot;
 } idetape_tape_t;
 
+static DEFINE_MUTEX(ide_tape_mutex);
 static DEFINE_MUTEX(idetape_ref_mutex);
 
 static DEFINE_MUTEX(idetape_chrdev_mutex);
@@ -1426,9 +1425,9 @@
 				unsigned int cmd, unsigned long arg)
 {
 	long ret;
-	lock_kernel();
+	mutex_lock(&ide_tape_mutex);
 	ret = do_idetape_chrdev_ioctl(file, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ide_tape_mutex);
 	return ret;
 }
 
@@ -1903,15 +1902,16 @@
 	.unlocked_ioctl	= idetape_chrdev_ioctl,
 	.open		= idetape_chrdev_open,
 	.release	= idetape_chrdev_release,
+	.llseek		= noop_llseek,
 };
 
 static int idetape_open(struct block_device *bdev, fmode_t mode)
 {
 	struct ide_tape_obj *tape;
 
-	lock_kernel();
+	mutex_lock(&ide_tape_mutex);
 	tape = ide_tape_get(bdev->bd_disk, false, 0);
-	unlock_kernel();
+	mutex_unlock(&ide_tape_mutex);
 
 	if (!tape)
 		return -ENXIO;
@@ -1923,9 +1923,9 @@
 {
 	struct ide_tape_obj *tape = ide_drv_g(disk, ide_tape_obj);
 
-	lock_kernel();
+	mutex_lock(&ide_tape_mutex);
 	ide_tape_put(tape);
-	unlock_kernel();
+	mutex_unlock(&ide_tape_mutex);
 
 	return 0;
 }
@@ -1937,11 +1937,11 @@
 	ide_drive_t *drive = tape->drive;
 	int err;
 
-	lock_kernel();
+	mutex_lock(&ide_tape_mutex);
 	err = generic_ide_ioctl(drive, bdev, cmd, arg);
 	if (err == -EINVAL)
 		err = idetape_blkdev_ioctl(drive, cmd, arg);
-	unlock_kernel();
+	mutex_unlock(&ide_tape_mutex);
 
 	return err;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/idle/i7300_idle.c linux-libre-2.6.37-gnu/drivers/idle/i7300_idle.c
--- linux-libre-2.6.36-gnu/drivers/idle/i7300_idle.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/idle/i7300_idle.c	2011-01-04 19:50:19.000000000 -0500
@@ -536,6 +536,7 @@
 static const struct file_operations idle_fops = {
 	.open	= stats_open_generic,
 	.read	= stats_read_ul,
+	.llseek = default_llseek,
 };
 
 struct debugfs_file_info {
diff -druN linux-libre-2.6.36-gnu/drivers/idle/intel_idle.c linux-libre-2.6.37-gnu/drivers/idle/intel_idle.c
--- linux-libre-2.6.36-gnu/drivers/idle/intel_idle.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/idle/intel_idle.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,18 +59,11 @@
 #include <linux/hrtimer.h>	/* ktime_get_real() */
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <asm/mwait.h>
 
 #define INTEL_IDLE_VERSION "0.4"
 #define PREFIX "intel_idle: "
 
-#define MWAIT_SUBSTATE_MASK	(0xf)
-#define MWAIT_CSTATE_MASK	(0xf)
-#define MWAIT_SUBSTATE_SIZE	(4)
-#define MWAIT_MAX_NUM_CSTATES	8
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK	(0x2)
-
 static struct cpuidle_driver intel_idle_driver = {
 	.name = "intel_idle",
 	.owner = THIS_MODULE,
@@ -81,7 +74,7 @@
 static unsigned int mwait_substates;
 
 /* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
-static unsigned int lapic_timer_reliable_states;
+static unsigned int lapic_timer_reliable_states = (1 << 1);	 /* Default to only C1 */
 
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
@@ -101,7 +94,6 @@
 		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 3,
-		.power_usage = 1000,
 		.target_residency = 6,
 		.enter = &intel_idle },
 	{ /* MWAIT C2 */
@@ -110,7 +102,6 @@
 		.driver_data = (void *) 0x10,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 20,
-		.power_usage = 500,
 		.target_residency = 80,
 		.enter = &intel_idle },
 	{ /* MWAIT C3 */
@@ -119,11 +110,46 @@
 		.driver_data = (void *) 0x20,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 200,
-		.power_usage = 350,
 		.target_residency = 800,
 		.enter = &intel_idle },
 };
 
+static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
+	{ /* MWAIT C0 */ },
+	{ /* MWAIT C1 */
+		.name = "SNB-C1",
+		.desc = "MWAIT 0x00",
+		.driver_data = (void *) 0x00,
+		.flags = CPUIDLE_FLAG_TIME_VALID,
+		.exit_latency = 1,
+		.target_residency = 4,
+		.enter = &intel_idle },
+	{ /* MWAIT C2 */
+		.name = "SNB-C3",
+		.desc = "MWAIT 0x10",
+		.driver_data = (void *) 0x10,
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 80,
+		.target_residency = 160,
+		.enter = &intel_idle },
+	{ /* MWAIT C3 */
+		.name = "SNB-C6",
+		.desc = "MWAIT 0x20",
+		.driver_data = (void *) 0x20,
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 104,
+		.target_residency = 208,
+		.enter = &intel_idle },
+	{ /* MWAIT C4 */
+		.name = "SNB-C7",
+		.desc = "MWAIT 0x30",
+		.driver_data = (void *) 0x30,
+		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 109,
+		.target_residency = 300,
+		.enter = &intel_idle },
+};
+
 static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
 	{ /* MWAIT C0 */ },
 	{ /* MWAIT C1 */
@@ -132,7 +158,6 @@
 		.driver_data = (void *) 0x00,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 1,
-		.power_usage = 1000,
 		.target_residency = 4,
 		.enter = &intel_idle },
 	{ /* MWAIT C2 */
@@ -141,7 +166,6 @@
 		.driver_data = (void *) 0x10,
 		.flags = CPUIDLE_FLAG_TIME_VALID,
 		.exit_latency = 20,
-		.power_usage = 500,
 		.target_residency = 80,
 		.enter = &intel_idle },
 	{ /* MWAIT C3 */ },
@@ -151,7 +175,6 @@
 		.driver_data = (void *) 0x30,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 100,
-		.power_usage = 250,
 		.target_residency = 400,
 		.enter = &intel_idle },
 	{ /* MWAIT C5 */ },
@@ -161,7 +184,6 @@
 		.driver_data = (void *) 0x52,
 		.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
 		.exit_latency = 140,
-		.power_usage = 150,
 		.target_residency = 560,
 		.enter = &intel_idle },
 };
@@ -186,13 +208,10 @@
 	local_irq_disable();
 
 	/*
-	 * If the state flag indicates that the TLB will be flushed or if this
-	 * is the deepest c-state supported, do a voluntary leave mm to avoid
-	 * costly and mostly unnecessary wakeups for flushing the user TLB's
-	 * associated with the active mm.
+	 * leave_mm() to avoid costly and often unnecessary wakeups
+	 * for flushing the user TLB's associated with the active mm.
 	 */
-	if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED ||
-	    (&dev->states[dev->state_count - 1] == state))
+	if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
 		leave_mm(cpu);
 
 	if (!(lapic_timer_reliable_states & (1 << (cstate))))
@@ -254,8 +273,6 @@
 
 	pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
 
-	if (boot_cpu_has(X86_FEATURE_ARAT))	/* Always Reliable APIC Timer */
-		lapic_timer_reliable_states = 0xFFFFFFFF;
 
 	if (boot_cpu_data.x86 != 6)	/* family 6 */
 		return -ENODEV;
@@ -267,8 +284,6 @@
 	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
 	case 0x2E:	/* Nehalem-EX Xeon */
 	case 0x2F:	/* Westmere-EX Xeon */
-		lapic_timer_reliable_states = (1 << 1);	 /* C1 */
-
 	case 0x25:	/* Westmere */
 	case 0x2C:	/* Westmere */
 		cpuidle_state_table = nehalem_cstates;
@@ -276,13 +291,13 @@
 
 	case 0x1C:	/* 28 - Atom Processor */
 	case 0x26:	/* 38 - Lincroft Atom Processor */
-		lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
 		cpuidle_state_table = atom_cstates;
 		break;
-#ifdef FUTURE_USE
-	case 0x17:	/* 23 - Core 2 Duo */
-		lapic_timer_reliable_states = (1 << 2) | (1 << 1); /* C2, C1 */
-#endif
+
+	case 0x2A:	/* SNB */
+	case 0x2D:	/* SNB Xeon */
+		cpuidle_state_table = snb_cstates;
+		break;
 
 	default:
 		pr_debug(PREFIX "does not run on family %d model %d\n",
@@ -290,6 +305,9 @@
 		return -ENODEV;
 	}
 
+	if (boot_cpu_has(X86_FEATURE_ARAT))	/* Always Reliable APIC Timer */
+		lapic_timer_reliable_states = 0xFFFFFFFF;
+
 	pr_debug(PREFIX "v" INTEL_IDLE_VERSION
 		" model 0x%X\n", boot_cpu_data.x86_model);
 
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/config_roms.c linux-libre-2.6.37-gnu/drivers/ieee1394/config_roms.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/config_roms.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/config_roms.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,194 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * ConfigROM  entries
- *
- * Copyright (C) 2004 Ben Collins
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/types.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "csr.h"
-#include "config_roms.h"
-
-struct hpsb_config_rom_entry {
-	const char *name;
-
-	/* Base initialization, called at module load */
-	int (*init)(void);
-
-	/* Cleanup called at module exit */
-	void (*cleanup)(void);
-
-	/* The flag added to host->config_roms */
-	unsigned int flag;
-};
-
-/* The default host entry. This must succeed. */
-int hpsb_default_host_entry(struct hpsb_host *host)
-{
-	struct csr1212_keyval *root;
-	struct csr1212_keyval *vend_id = NULL;
-	struct csr1212_keyval *text = NULL;
-	char csr_name[128];
-	int ret;
-
-	sprintf(csr_name, "Linux - %s", host->driver->name);
-	root = host->csr.rom->root_kv;
-
-	vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
-	text = csr1212_new_string_descriptor_leaf(csr_name);
-
-	if (!vend_id || !text) {
-		if (vend_id)
-			csr1212_release_keyval(vend_id);
-		if (text)
-			csr1212_release_keyval(text);
-		csr1212_destroy_csr(host->csr.rom);
-		return -ENOMEM;
-	}
-
-	csr1212_associate_keyval(vend_id, text);
-	csr1212_release_keyval(text);
-	ret = csr1212_attach_keyval_to_directory(root, vend_id);
-	csr1212_release_keyval(vend_id);
-	if (ret != CSR1212_SUCCESS) {
-		csr1212_destroy_csr(host->csr.rom);
-		return -ENOMEM;
-	}
-
-	host->update_config_rom = 1;
-
-	return 0;
-}
-
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-#include "eth1394.h"
-
-static struct csr1212_keyval *ip1394_ud;
-
-static int config_rom_ip1394_init(void)
-{
-	struct csr1212_keyval *spec_id = NULL;
-	struct csr1212_keyval *spec_desc = NULL;
-	struct csr1212_keyval *ver = NULL;
-	struct csr1212_keyval *ver_desc = NULL;
-	int ret = -ENOMEM;
-
-	ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
-
-	spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
-					ETHER1394_GASP_SPECIFIER_ID);
-	spec_desc = csr1212_new_string_descriptor_leaf("IANA");
-	ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
-				    ETHER1394_GASP_VERSION);
-	ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
-
-	if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
-		goto ip1394_fail;
-
-	csr1212_associate_keyval(spec_id, spec_desc);
-	csr1212_associate_keyval(ver, ver_desc);
-	if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
-			== CSR1212_SUCCESS &&
-	    csr1212_attach_keyval_to_directory(ip1394_ud, ver)
-			== CSR1212_SUCCESS)
-		ret = 0;
-
-ip1394_fail:
-	if (ret && ip1394_ud) {
-		csr1212_release_keyval(ip1394_ud);
-		ip1394_ud = NULL;
-	}
-
-	if (spec_id)
-		csr1212_release_keyval(spec_id);
-	if (spec_desc)
-		csr1212_release_keyval(spec_desc);
-	if (ver)
-		csr1212_release_keyval(ver);
-	if (ver_desc)
-		csr1212_release_keyval(ver_desc);
-
-	return ret;
-}
-
-static void config_rom_ip1394_cleanup(void)
-{
-	if (ip1394_ud) {
-		csr1212_release_keyval(ip1394_ud);
-		ip1394_ud = NULL;
-	}
-}
-
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
-{
-	if (!ip1394_ud)
-		return -ENODEV;
-
-	if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
-					       ip1394_ud) != CSR1212_SUCCESS)
-		return -ENOMEM;
-
-	host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
-	host->update_config_rom = 1;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
-
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
-{
-	csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
-	host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
-	host->update_config_rom = 1;
-}
-EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
-
-static struct hpsb_config_rom_entry ip1394_entry = {
-	.name		= "ip1394",
-	.init		= config_rom_ip1394_init,
-	.cleanup	= config_rom_ip1394_cleanup,
-	.flag		= HPSB_CONFIG_ROM_ENTRY_IP1394,
-};
-
-#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
-
-static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-	&ip1394_entry,
-#endif
-};
-
-/* Initialize all config roms */
-int hpsb_init_config_roms(void)
-{
-	int i, error = 0;
-
-	for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
-		if (config_rom_entries[i]->init()) {
-			HPSB_ERR("Failed to initialize config rom entry `%s'",
-				 config_rom_entries[i]->name);
-			error = -1;
-		}
-
-	return error;
-}
-
-/* Cleanup all config roms */
-void hpsb_cleanup_config_roms(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
-		config_rom_entries[i]->cleanup();
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/config_roms.h linux-libre-2.6.37-gnu/drivers/ieee1394/config_roms.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/config_roms.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/config_roms.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_CONFIG_ROMS_H
-#define _IEEE1394_CONFIG_ROMS_H
-
-struct hpsb_host;
-
-int hpsb_default_host_entry(struct hpsb_host *host);
-int hpsb_init_config_roms(void);
-void hpsb_cleanup_config_roms(void);
-
-/* List of flags to check if a host contains a certain extra config rom
- * entry. Available in the host->config_roms member. */
-#define HPSB_CONFIG_ROM_ENTRY_IP1394		0x00000001
-
-#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
-int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
-void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
-#endif
-
-#endif /* _IEEE1394_CONFIG_ROMS_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/csr1212.c linux-libre-2.6.37-gnu/drivers/ieee1394/csr1212.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/csr1212.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/csr1212.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1467 +0,0 @@
-/*
- * csr1212.c -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *    2. Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *    3. The name of the author may not be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* TODO List:
- * - Verify interface consistency: i.e., public functions that take a size
- *   parameter expect size to be in bytes.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/string.h>
-#include <asm/bug.h>
-#include <asm/byteorder.h>
-
-#include "csr1212.h"
-
-
-/* Permitted key type for each key id */
-#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
-#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
-#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
-#define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u8 csr1212_key_id_type_map[0x30] = {
-	__C,			/* used by Apple iSight */
-	__D | __L,		/* Descriptor */
-	__I | __D | __L,	/* Bus_Dependent_Info */
-	__I | __D | __L,	/* Vendor */
-	__I,			/* Hardware_Version */
-	0, 0,			/* Reserved */
-	__D | __L | __I,	/* Module */
-	__I, 0, 0, 0,		/* used by Apple iSight, Reserved */
-	__I,			/* Node_Capabilities */
-	__L,			/* EUI_64 */
-	0, 0, 0,		/* Reserved */
-	__D,			/* Unit */
-	__I,			/* Specifier_ID */
-	__I,			/* Version */
-	__I | __C | __D | __L,	/* Dependent_Info */
-	__L,			/* Unit_Location */
-	0,			/* Reserved */
-	__I,			/* Model */
-	__D,			/* Instance */
-	__L,			/* Keyword */
-	__D,			/* Feature */
-	__L,			/* Extended_ROM */
-	__I,			/* Extended_Key_Specifier_ID */
-	__I,			/* Extended_Key */
-	__I | __C | __D | __L,	/* Extended_Data */
-	__L,			/* Modifiable_Descriptor */
-	__I,			/* Directory_ID */
-	__I,			/* Revision */
-};
-#undef __I
-#undef __C
-#undef __D
-#undef __L
-
-
-#define quads_to_bytes(_q) ((_q) * sizeof(u32))
-#define bytes_to_quads(_b) DIV_ROUND_UP(_b, sizeof(u32))
-
-static void free_keyval(struct csr1212_keyval *kv)
-{
-	if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
-	    (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
-		CSR1212_FREE(kv->value.leaf.data);
-
-	CSR1212_FREE(kv);
-}
-
-static u16 csr1212_crc16(const u32 *buffer, size_t length)
-{
-	int shift;
-	u32 data;
-	u16 sum, crc = 0;
-
-	for (; length; length--) {
-		data = be32_to_cpu(*buffer);
-		buffer++;
-		for (shift = 28; shift >= 0; shift -= 4 ) {
-			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
-			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-		}
-		crc &= 0xffff;
-	}
-
-	return cpu_to_be16(crc);
-}
-
-/* Microsoft computes the CRC with the bytes in reverse order. */
-static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
-{
-	int shift;
-	u32 data;
-	u16 sum, crc = 0;
-
-	for (; length; length--) {
-		data = le32_to_cpu(*buffer);
-		buffer++;
-		for (shift = 28; shift >= 0; shift -= 4 ) {
-			sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
-			crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-		}
-		crc &= 0xffff;
-	}
-
-	return cpu_to_be16(crc);
-}
-
-static struct csr1212_dentry *
-csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
-{
-	struct csr1212_dentry *pos;
-
-	for (pos = dir->value.directory.dentries_head;
-	     pos != NULL; pos = pos->next)
-		if (pos->kv == kv)
-			return pos;
-	return NULL;
-}
-
-static struct csr1212_keyval *
-csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
-{
-	struct csr1212_keyval *kv;
-
-	for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
-		if (kv->offset == offset)
-			return kv;
-	return NULL;
-}
-
-
-/* Creation Routines */
-
-struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
-				       size_t bus_info_size, void *private)
-{
-	struct csr1212_csr *csr;
-
-	csr = CSR1212_MALLOC(sizeof(*csr));
-	if (!csr)
-		return NULL;
-
-	csr->cache_head =
-		csr1212_rom_cache_malloc(CSR1212_CONFIG_ROM_SPACE_OFFSET,
-					 CSR1212_CONFIG_ROM_SPACE_SIZE);
-	if (!csr->cache_head) {
-		CSR1212_FREE(csr);
-		return NULL;
-	}
-
-	/* The keyval key id is not used for the root node, but a valid key id
-	 * that can be used for a directory needs to be passed to
-	 * csr1212_new_directory(). */
-	csr->root_kv = csr1212_new_directory(CSR1212_KV_ID_VENDOR);
-	if (!csr->root_kv) {
-		CSR1212_FREE(csr->cache_head);
-		CSR1212_FREE(csr);
-		return NULL;
-	}
-
-	csr->bus_info_data = csr->cache_head->data;
-	csr->bus_info_len = bus_info_size;
-	csr->crc_len = bus_info_size;
-	csr->ops = ops;
-	csr->private = private;
-	csr->cache_tail = csr->cache_head;
-
-	return csr;
-}
-
-void csr1212_init_local_csr(struct csr1212_csr *csr,
-			    const u32 *bus_info_data, int max_rom)
-{
-	static const int mr_map[] = { 4, 64, 1024, 0 };
-
-	BUG_ON(max_rom & ~0x3);
-	csr->max_rom = mr_map[max_rom];
-	memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
-}
-
-static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
-{
-	struct csr1212_keyval *kv;
-
-	if (key < 0x30 && ((csr1212_key_id_type_map[key] & (1 << type)) == 0))
-		return NULL;
-
-	kv = CSR1212_MALLOC(sizeof(*kv));
-	if (!kv)
-		return NULL;
-
-	atomic_set(&kv->refcnt, 1);
-	kv->key.type = type;
-	kv->key.id = key;
-	kv->associate = NULL;
-	kv->next = NULL;
-	kv->prev = NULL;
-	kv->offset = 0;
-	kv->valid = 0;
-	return kv;
-}
-
-struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
-{
-	struct csr1212_keyval *kv;
-
-	kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
-	if (!kv)
-		return NULL;
-
-	kv->value.immediate = value;
-	kv->valid = 1;
-	return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_leaf(u8 key, const void *data, size_t data_len)
-{
-	struct csr1212_keyval *kv;
-
-	kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
-	if (!kv)
-		return NULL;
-
-	if (data_len > 0) {
-		kv->value.leaf.data = CSR1212_MALLOC(data_len);
-		if (!kv->value.leaf.data) {
-			CSR1212_FREE(kv);
-			return NULL;
-		}
-
-		if (data)
-			memcpy(kv->value.leaf.data, data, data_len);
-	} else {
-		kv->value.leaf.data = NULL;
-	}
-
-	kv->value.leaf.len = bytes_to_quads(data_len);
-	kv->offset = 0;
-	kv->valid = 1;
-
-	return kv;
-}
-
-static struct csr1212_keyval *
-csr1212_new_csr_offset(u8 key, u32 csr_offset)
-{
-	struct csr1212_keyval *kv;
-
-	kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
-	if (!kv)
-		return NULL;
-
-	kv->value.csr_offset = csr_offset;
-
-	kv->offset = 0;
-	kv->valid = 1;
-	return kv;
-}
-
-struct csr1212_keyval *csr1212_new_directory(u8 key)
-{
-	struct csr1212_keyval *kv;
-
-	kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
-	if (!kv)
-		return NULL;
-
-	kv->value.directory.len = 0;
-	kv->offset = 0;
-	kv->value.directory.dentries_head = NULL;
-	kv->value.directory.dentries_tail = NULL;
-	kv->valid = 1;
-	return kv;
-}
-
-void csr1212_associate_keyval(struct csr1212_keyval *kv,
-			      struct csr1212_keyval *associate)
-{
-	BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
-	       (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
-		associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
-		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
-		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
-		associate->key.id < 0x30) ||
-	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
-		associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
-	       (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-		associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
-	       (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
-		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
-	       (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
-		kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
-
-	if (kv->associate)
-		csr1212_release_keyval(kv->associate);
-
-	csr1212_keep_keyval(associate);
-	kv->associate = associate;
-}
-
-static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-						struct csr1212_keyval *kv,
-						bool keep_keyval)
-{
-	struct csr1212_dentry *dentry;
-
-	BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
-
-	dentry = CSR1212_MALLOC(sizeof(*dentry));
-	if (!dentry)
-		return -ENOMEM;
-
-	if (keep_keyval)
-		csr1212_keep_keyval(kv);
-	dentry->kv = kv;
-
-	dentry->next = NULL;
-	dentry->prev = dir->value.directory.dentries_tail;
-
-	if (!dir->value.directory.dentries_head)
-		dir->value.directory.dentries_head = dentry;
-
-	if (dir->value.directory.dentries_tail)
-		dir->value.directory.dentries_tail->next = dentry;
-	dir->value.directory.dentries_tail = dentry;
-
-	return CSR1212_SUCCESS;
-}
-
-int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-				       struct csr1212_keyval *kv)
-{
-	return __csr1212_attach_keyval_to_directory(dir, kv, true);
-}
-
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
-	(&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
-	((kv)->value.leaf.data[0] = \
-	 cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
-		     ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
-	((kv)->value.leaf.data[0] = \
-	 cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
-		      CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
-		     ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
-
-static struct csr1212_keyval *
-csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
-			    const void *data, size_t data_len)
-{
-	struct csr1212_keyval *kv;
-
-	kv = csr1212_new_leaf(CSR1212_KV_ID_DESCRIPTOR, NULL,
-			      data_len + CSR1212_DESCRIPTOR_LEAF_OVERHEAD);
-	if (!kv)
-		return NULL;
-
-	kmemcheck_annotate_variable(kv->value.leaf.data[0]);
-	CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
-	CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
-
-	if (data)
-		memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
-
-	return kv;
-}
-
-/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
-static int csr1212_check_minimal_ascii(const char *s)
-{
-	static const char minimal_ascii_table[] = {
-					/*  1   2   4   8  16  32  64  128 */
-		128,			/* --, --, --, --, --, --, --, 07, */
-		4 + 16 + 32,		/* --, --, 0a, --, 0C, 0D, --, --, */
-		0,			/* --, --, --, --, --, --, --, --, */
-		0,			/* --, --, --, --, --, --, --, --, */
-		255 - 8 - 16,		/* 20, 21, 22, --, --, 25, 26, 27, */
-		255,			/* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
-		255,			/* 30, 31, 32, 33, 34, 35, 36, 37, */
-		255,			/* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
-		255,			/* 40, 41, 42, 43, 44, 45, 46, 47, */
-		255,			/* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
-		255,			/* 50, 51, 52, 53, 54, 55, 56, 57, */
-		1 + 2 + 4 + 128,	/* 58, 59, 5a, --, --, --, --, 5f, */
-		255 - 1,		/* --, 61, 62, 63, 64, 65, 66, 67, */
-		255,			/* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
-		255,			/* 70, 71, 72, 73, 74, 75, 76, 77, */
-		1 + 2 + 4,		/* 78, 79, 7a, --, --, --, --, --, */
-	};
-	int i, j;
-
-	for (; *s; s++) {
-		i = *s >> 3;		/*  i = *s / 8;		*/
-		j = 1 << (*s & 3);	/*  j = 1 << (*s % 8);	*/
-
-		if (i >= ARRAY_SIZE(minimal_ascii_table) ||
-		    !(minimal_ascii_table[i] & j))
-			return -EINVAL;
-	}
-	return 0;
-}
-
-/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
-struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
-{
-	struct csr1212_keyval *kv;
-	u32 *text;
-	size_t str_len, quads;
-
-	if (!s || !*s || csr1212_check_minimal_ascii(s))
-		return NULL;
-
-	str_len = strlen(s);
-	quads = bytes_to_quads(str_len);
-	kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
-				      CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
-	if (!kv)
-		return NULL;
-
-	kv->value.leaf.data[1] = 0;	/* width, character_set, language */
-	text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
-	text[quads - 1] = 0;		/* padding */
-	memcpy(text, s, str_len);
-
-	return kv;
-}
-
-
-/* Destruction Routines */
-
-void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
-					  struct csr1212_keyval *kv)
-{
-	struct csr1212_dentry *dentry;
-
-	if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
-		return;
-
-	dentry = csr1212_find_keyval(dir, kv);
-
-	if (!dentry)
-		return;
-
-	if (dentry->prev)
-		dentry->prev->next = dentry->next;
-	if (dentry->next)
-		dentry->next->prev = dentry->prev;
-	if (dir->value.directory.dentries_head == dentry)
-		dir->value.directory.dentries_head = dentry->next;
-	if (dir->value.directory.dentries_tail == dentry)
-		dir->value.directory.dentries_tail = dentry->prev;
-
-	CSR1212_FREE(dentry);
-
-	csr1212_release_keyval(kv);
-}
-
-/* This function is used to free the memory taken by a keyval.  If the given
- * keyval is a directory type, then any keyvals contained in that directory
- * will be destroyed as well if noone holds a reference on them.  By means of
- * list manipulation, this routine will descend a directory structure in a
- * non-recursive manner. */
-void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
-	struct csr1212_keyval *k, *a;
-	struct csr1212_dentry dentry;
-	struct csr1212_dentry *head, *tail;
-
-	if (!atomic_dec_and_test(&kv->refcnt))
-		return;
-
-	dentry.kv = kv;
-	dentry.next = NULL;
-	dentry.prev = NULL;
-
-	head = &dentry;
-	tail = head;
-
-	while (head) {
-		k = head->kv;
-
-		while (k) {
-			/* must not dec_and_test kv->refcnt again */
-			if (k != kv && !atomic_dec_and_test(&k->refcnt))
-				break;
-
-			a = k->associate;
-
-			if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
-				/* If the current entry is a directory, move all
-				 * the entries to the destruction list. */
-				if (k->value.directory.dentries_head) {
-					tail->next =
-					    k->value.directory.dentries_head;
-					k->value.directory.dentries_head->prev =
-					    tail;
-					tail = k->value.directory.dentries_tail;
-				}
-			}
-			free_keyval(k);
-			k = a;
-		}
-
-		head = head->next;
-		if (head) {
-			if (head->prev && head->prev != &dentry)
-				CSR1212_FREE(head->prev);
-			head->prev = NULL;
-		} else if (tail != &dentry) {
-			CSR1212_FREE(tail);
-		}
-	}
-}
-
-void csr1212_destroy_csr(struct csr1212_csr *csr)
-{
-	struct csr1212_csr_rom_cache *c, *oc;
-	struct csr1212_cache_region *cr, *ocr;
-
-	csr1212_release_keyval(csr->root_kv);
-
-	c = csr->cache_head;
-	while (c) {
-		oc = c;
-		cr = c->filled_head;
-		while (cr) {
-			ocr = cr;
-			cr = cr->next;
-			CSR1212_FREE(ocr);
-		}
-		c = c->next;
-		CSR1212_FREE(oc);
-	}
-
-	CSR1212_FREE(csr);
-}
-
-
-/* CSR Image Creation */
-
-static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
-{
-	struct csr1212_csr_rom_cache *cache;
-	u64 csr_addr;
-
-	BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
-	       !csr->ops->release_addr || csr->max_rom < 1);
-
-	/* ROM size must be a multiple of csr->max_rom */
-	romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
-	csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
-						 csr->private);
-	if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
-		return -ENOMEM;
-
-	if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
-		/* Invalid address returned from allocate_addr_range(). */
-		csr->ops->release_addr(csr_addr, csr->private);
-		return -ENOMEM;
-	}
-
-	cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
-					 romsize);
-	if (!cache) {
-		csr->ops->release_addr(csr_addr, csr->private);
-		return -ENOMEM;
-	}
-
-	cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
-					    CSR1212_KV_ID_EXTENDED_ROM);
-	if (!cache->ext_rom) {
-		csr->ops->release_addr(csr_addr, csr->private);
-		CSR1212_FREE(cache);
-		return -ENOMEM;
-	}
-
-	if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
-	    CSR1212_SUCCESS) {
-		csr1212_release_keyval(cache->ext_rom);
-		csr->ops->release_addr(csr_addr, csr->private);
-		CSR1212_FREE(cache);
-		return -ENOMEM;
-	}
-	cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
-	cache->ext_rom->value.leaf.len = -1;
-	cache->ext_rom->value.leaf.data = cache->data;
-
-	/* Add cache to tail of cache list */
-	cache->prev = csr->cache_tail;
-	csr->cache_tail->next = cache;
-	csr->cache_tail = cache;
-	return CSR1212_SUCCESS;
-}
-
-static void csr1212_remove_cache(struct csr1212_csr *csr,
-				 struct csr1212_csr_rom_cache *cache)
-{
-	if (csr->cache_head == cache)
-		csr->cache_head = cache->next;
-	if (csr->cache_tail == cache)
-		csr->cache_tail = cache->prev;
-
-	if (cache->prev)
-		cache->prev->next = cache->next;
-	if (cache->next)
-		cache->next->prev = cache->prev;
-
-	if (cache->ext_rom) {
-		csr1212_detach_keyval_from_directory(csr->root_kv,
-						     cache->ext_rom);
-		csr1212_release_keyval(cache->ext_rom);
-	}
-
-	CSR1212_FREE(cache);
-}
-
-static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
-					  struct csr1212_keyval **layout_tail)
-{
-	struct csr1212_dentry *dentry;
-	struct csr1212_keyval *dkv;
-	struct csr1212_keyval *last_extkey_spec = NULL;
-	struct csr1212_keyval *last_extkey = NULL;
-	int num_entries = 0;
-
-	for (dentry = dir->value.directory.dentries_head; dentry;
-	     dentry = dentry->next) {
-		for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
-			/* Special Case: Extended Key Specifier_ID */
-			if (dkv->key.id ==
-			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-				if (last_extkey_spec == NULL)
-					last_extkey_spec = dkv;
-				else if (dkv->value.immediate !=
-					 last_extkey_spec->value.immediate)
-					last_extkey_spec = dkv;
-				else
-					continue;
-			/* Special Case: Extended Key */
-			} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-				if (last_extkey == NULL)
-					last_extkey = dkv;
-				else if (dkv->value.immediate !=
-					 last_extkey->value.immediate)
-					last_extkey = dkv;
-				else
-					continue;
-			}
-
-			num_entries += 1;
-
-			switch (dkv->key.type) {
-			default:
-			case CSR1212_KV_TYPE_IMMEDIATE:
-			case CSR1212_KV_TYPE_CSR_OFFSET:
-				break;
-			case CSR1212_KV_TYPE_LEAF:
-			case CSR1212_KV_TYPE_DIRECTORY:
-				/* Remove from list */
-				if (dkv->prev && (dkv->prev->next == dkv))
-					dkv->prev->next = dkv->next;
-				if (dkv->next && (dkv->next->prev == dkv))
-					dkv->next->prev = dkv->prev;
-				//if (dkv == *layout_tail)
-				//	*layout_tail = dkv->prev;
-
-				/* Special case: Extended ROM leafs */
-				if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
-					dkv->value.leaf.len = -1;
-					/* Don't add Extended ROM leafs in the
-					 * layout list, they are handled
-					 * differently. */
-					break;
-				}
-
-				/* Add to tail of list */
-				dkv->next = NULL;
-				dkv->prev = *layout_tail;
-				(*layout_tail)->next = dkv;
-				*layout_tail = dkv;
-				break;
-			}
-		}
-	}
-	return num_entries;
-}
-
-static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
-{
-	struct csr1212_keyval *ltail = kv;
-	size_t agg_size = 0;
-
-	while (kv) {
-		switch (kv->key.type) {
-		case CSR1212_KV_TYPE_LEAF:
-			/* Add 1 quadlet for crc/len field */
-			agg_size += kv->value.leaf.len + 1;
-			break;
-
-		case CSR1212_KV_TYPE_DIRECTORY:
-			kv->value.directory.len =
-				csr1212_generate_layout_subdir(kv, &ltail);
-			/* Add 1 quadlet for crc/len field */
-			agg_size += kv->value.directory.len + 1;
-			break;
-		}
-		kv = kv->next;
-	}
-	return quads_to_bytes(agg_size);
-}
-
-static struct csr1212_keyval *
-csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
-			   struct csr1212_keyval *start_kv, int start_pos)
-{
-	struct csr1212_keyval *kv = start_kv;
-	struct csr1212_keyval *okv = start_kv;
-	int pos = start_pos;
-	int kv_len = 0, okv_len = 0;
-
-	cache->layout_head = kv;
-
-	while (kv && pos < cache->size) {
-		/* Special case: Extended ROM leafs */
-		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-			kv->offset = cache->offset + pos;
-
-		switch (kv->key.type) {
-		case CSR1212_KV_TYPE_LEAF:
-			kv_len = kv->value.leaf.len;
-			break;
-
-		case CSR1212_KV_TYPE_DIRECTORY:
-			kv_len = kv->value.directory.len;
-			break;
-
-		default:
-			/* Should never get here */
-			WARN_ON(1);
-			break;
-		}
-
-		pos += quads_to_bytes(kv_len + 1);
-
-		if (pos <= cache->size) {
-			okv = kv;
-			okv_len = kv_len;
-			kv = kv->next;
-		}
-	}
-
-	cache->layout_tail = okv;
-	cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
-
-	return kv;
-}
-
-#define CSR1212_KV_KEY_SHIFT		24
-#define CSR1212_KV_KEY_TYPE_SHIFT	6
-#define CSR1212_KV_KEY_ID_MASK		0x3f
-#define CSR1212_KV_KEY_TYPE_MASK	0x3	/* after shift */
-
-static void
-csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
-{
-	struct csr1212_dentry *dentry;
-	struct csr1212_keyval *last_extkey_spec = NULL;
-	struct csr1212_keyval *last_extkey = NULL;
-	int index = 0;
-
-	for (dentry = dir->value.directory.dentries_head;
-	     dentry;
-	     dentry = dentry->next) {
-		struct csr1212_keyval *a;
-
-		for (a = dentry->kv; a; a = a->associate) {
-			u32 value = 0;
-
-			/* Special Case: Extended Key Specifier_ID */
-			if (a->key.id ==
-			    CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
-				if (last_extkey_spec == NULL)
-					last_extkey_spec = a;
-				else if (a->value.immediate !=
-					 last_extkey_spec->value.immediate)
-					last_extkey_spec = a;
-				else
-					continue;
-
-			/* Special Case: Extended Key */
-			} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
-				if (last_extkey == NULL)
-					last_extkey = a;
-				else if (a->value.immediate !=
-					 last_extkey->value.immediate)
-					last_extkey = a;
-				else
-					continue;
-			}
-
-			switch (a->key.type) {
-			case CSR1212_KV_TYPE_IMMEDIATE:
-				value = a->value.immediate;
-				break;
-			case CSR1212_KV_TYPE_CSR_OFFSET:
-				value = a->value.csr_offset;
-				break;
-			case CSR1212_KV_TYPE_LEAF:
-				value = a->offset;
-				value -= dir->offset + quads_to_bytes(1+index);
-				value = bytes_to_quads(value);
-				break;
-			case CSR1212_KV_TYPE_DIRECTORY:
-				value = a->offset;
-				value -= dir->offset + quads_to_bytes(1+index);
-				value = bytes_to_quads(value);
-				break;
-			default:
-				/* Should never get here */
-				WARN_ON(1);
-				break;
-			}
-
-			value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
-				 CSR1212_KV_KEY_SHIFT;
-			value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
-				 (CSR1212_KV_KEY_SHIFT +
-				  CSR1212_KV_KEY_TYPE_SHIFT);
-			data_buffer[index] = cpu_to_be32(value);
-			index++;
-		}
-	}
-}
-
-struct csr1212_keyval_img {
-	u16 length;
-	u16 crc;
-
-	/* Must be last */
-	u32 data[0];	/* older gcc can't handle [] which is standard */
-};
-
-static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
-{
-	struct csr1212_keyval *kv, *nkv;
-	struct csr1212_keyval_img *kvi;
-
-	for (kv = cache->layout_head;
-	     kv != cache->layout_tail->next;
-	     kv = nkv) {
-		kvi = (struct csr1212_keyval_img *)(cache->data +
-				bytes_to_quads(kv->offset - cache->offset));
-		switch (kv->key.type) {
-		default:
-		case CSR1212_KV_TYPE_IMMEDIATE:
-		case CSR1212_KV_TYPE_CSR_OFFSET:
-			/* Should never get here */
-			WARN_ON(1);
-			break;
-
-		case CSR1212_KV_TYPE_LEAF:
-			/* Don't copy over Extended ROM areas, they are
-			 * already filled out! */
-			if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-				memcpy(kvi->data, kv->value.leaf.data,
-				       quads_to_bytes(kv->value.leaf.len));
-
-			kvi->length = cpu_to_be16(kv->value.leaf.len);
-			kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
-			break;
-
-		case CSR1212_KV_TYPE_DIRECTORY:
-			csr1212_generate_tree_subdir(kv, kvi->data);
-
-			kvi->length = cpu_to_be16(kv->value.directory.len);
-			kvi->crc = csr1212_crc16(kvi->data,
-						 kv->value.directory.len);
-			break;
-		}
-
-		nkv = kv->next;
-		if (kv->prev)
-			kv->prev->next = NULL;
-		if (kv->next)
-			kv->next->prev = NULL;
-		kv->prev = NULL;
-		kv->next = NULL;
-	}
-}
-
-/* This size is arbitrarily chosen.
- * The struct overhead is subtracted for more economic allocations. */
-#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
-
-int csr1212_generate_csr_image(struct csr1212_csr *csr)
-{
-	struct csr1212_bus_info_block_img *bi;
-	struct csr1212_csr_rom_cache *cache;
-	struct csr1212_keyval *kv;
-	size_t agg_size;
-	int ret;
-	int init_offset;
-
-	BUG_ON(!csr);
-
-	cache = csr->cache_head;
-
-	bi = (struct csr1212_bus_info_block_img*)cache->data;
-
-	bi->length = bytes_to_quads(csr->bus_info_len) - 1;
-	bi->crc_length = bi->length;
-	bi->crc = csr1212_crc16(bi->data, bi->crc_length);
-
-	csr->root_kv->next = NULL;
-	csr->root_kv->prev = NULL;
-
-	agg_size = csr1212_generate_layout_order(csr->root_kv);
-
-	init_offset = csr->bus_info_len;
-
-	for (kv = csr->root_kv, cache = csr->cache_head;
-	     kv;
-	     cache = cache->next) {
-		if (!cache) {
-			/* Estimate approximate number of additional cache
-			 * regions needed (it assumes that the cache holding
-			 * the first 1K Config ROM space always exists). */
-			int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
-						(2 * sizeof(u32))) + 1;
-
-			/* Add additional cache regions, extras will be
-			 * removed later */
-			for (; est_c; est_c--) {
-				ret = csr1212_append_new_cache(csr,
-						CSR1212_EXTENDED_ROM_SIZE);
-				if (ret != CSR1212_SUCCESS)
-					return ret;
-			}
-			/* Need to re-layout for additional cache regions */
-			agg_size = csr1212_generate_layout_order(csr->root_kv);
-			kv = csr->root_kv;
-			cache = csr->cache_head;
-			init_offset = csr->bus_info_len;
-		}
-		kv = csr1212_generate_positions(cache, kv, init_offset);
-		agg_size -= cache->len;
-		init_offset = sizeof(u32);
-	}
-
-	/* Remove unused, excess cache regions */
-	while (cache) {
-		struct csr1212_csr_rom_cache *oc = cache;
-
-		cache = cache->next;
-		csr1212_remove_cache(csr, oc);
-	}
-
-	/* Go through the list backward so that when done, the correct CRC
-	 * will be calculated for the Extended ROM areas. */
-	for (cache = csr->cache_tail; cache; cache = cache->prev) {
-		/* Only Extended ROM caches should have this set. */
-		if (cache->ext_rom) {
-			int leaf_size;
-
-			/* Make sure the Extended ROM leaf is a multiple of
-			 * max_rom in size. */
-			BUG_ON(csr->max_rom < 1);
-			leaf_size = (cache->len + (csr->max_rom - 1)) &
-				~(csr->max_rom - 1);
-
-			/* Zero out the unused ROM region */
-			memset(cache->data + bytes_to_quads(cache->len), 0x00,
-			       leaf_size - cache->len);
-
-			/* Subtract leaf header */
-			leaf_size -= sizeof(u32);
-
-			/* Update the Extended ROM leaf length */
-			cache->ext_rom->value.leaf.len =
-				bytes_to_quads(leaf_size);
-		} else {
-			/* Zero out the unused ROM region */
-			memset(cache->data + bytes_to_quads(cache->len), 0x00,
-			       cache->size - cache->len);
-		}
-
-		/* Copy the data into the cache buffer */
-		csr1212_fill_cache(cache);
-
-		if (cache != csr->cache_head) {
-			/* Set the length and CRC of the extended ROM. */
-			struct csr1212_keyval_img *kvi =
-				(struct csr1212_keyval_img*)cache->data;
-			u16 len = bytes_to_quads(cache->len) - 1;
-
-			kvi->length = cpu_to_be16(len);
-			kvi->crc = csr1212_crc16(kvi->data, len);
-		}
-	}
-
-	return CSR1212_SUCCESS;
-}
-
-int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
-{
-	struct csr1212_csr_rom_cache *cache;
-
-	for (cache = csr->cache_head; cache; cache = cache->next)
-		if (offset >= cache->offset &&
-		    (offset + len) <= (cache->offset + cache->size)) {
-			memcpy(buffer, &cache->data[
-					bytes_to_quads(offset - cache->offset)],
-			       len);
-			return CSR1212_SUCCESS;
-		}
-
-	return -ENOENT;
-}
-
-/*
- * Apparently there are many different wrong implementations of the CRC
- * algorithm.  We don't fail, we just warn... approximately once per GUID.
- */
-static void
-csr1212_check_crc(const u32 *buffer, size_t length, u16 crc, __be32 *guid)
-{
-	static u64 last_bad_eui64;
-	u64 eui64 = ((u64)be32_to_cpu(guid[0]) << 32) | be32_to_cpu(guid[1]);
-
-	if (csr1212_crc16(buffer, length) == crc ||
-	    csr1212_msft_crc16(buffer, length) == crc ||
-	    eui64 == last_bad_eui64)
-		return;
-
-	printk(KERN_DEBUG "ieee1394: config ROM CRC error\n");
-	last_bad_eui64 = eui64;
-}
-
-/* Parse a chunk of data as a Config ROM */
-
-static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
-{
-	struct csr1212_bus_info_block_img *bi;
-	struct csr1212_cache_region *cr;
-	int i;
-	int ret;
-
-	for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
-		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-				&csr->cache_head->data[bytes_to_quads(i)],
-				csr->private);
-		if (ret != CSR1212_SUCCESS)
-			return ret;
-
-		/* check ROM header's info_length */
-		if (i == 0 &&
-		    be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
-		    bytes_to_quads(csr->bus_info_len) - 1)
-			return -EINVAL;
-	}
-
-	bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
-	csr->crc_len = quads_to_bytes(bi->crc_length);
-
-	/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
-	 * is not always the case, so read the rest of the crc area 1 quadlet at
-	 * a time. */
-	for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
-		ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
-				&csr->cache_head->data[bytes_to_quads(i)],
-				csr->private);
-		if (ret != CSR1212_SUCCESS)
-			return ret;
-	}
-
-	csr1212_check_crc(bi->data, bi->crc_length, bi->crc,
-			  &csr->bus_info_data[3]);
-
-	cr = CSR1212_MALLOC(sizeof(*cr));
-	if (!cr)
-		return -ENOMEM;
-
-	cr->next = NULL;
-	cr->prev = NULL;
-	cr->offset_start = 0;
-	cr->offset_end = csr->crc_len + 4;
-
-	csr->cache_head->filled_head = cr;
-	csr->cache_head->filled_tail = cr;
-
-	return CSR1212_SUCCESS;
-}
-
-#define CSR1212_KV_KEY(q)	(be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(q)	(CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(q)	(CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL_MASK	0xffffff
-#define CSR1212_KV_VAL(q)	(be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
-
-static int
-csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
-{
-	int ret = CSR1212_SUCCESS;
-	struct csr1212_keyval *k = NULL;
-	u32 offset;
-	bool keep_keyval = true;
-
-	switch (CSR1212_KV_KEY_TYPE(ki)) {
-	case CSR1212_KV_TYPE_IMMEDIATE:
-		k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
-					  CSR1212_KV_VAL(ki));
-		if (!k) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		/* Don't keep local reference when parsing. */
-		keep_keyval = false;
-		break;
-
-	case CSR1212_KV_TYPE_CSR_OFFSET:
-		k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
-					   CSR1212_KV_VAL(ki));
-		if (!k) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		/* Don't keep local reference when parsing. */
-		keep_keyval = false;
-		break;
-
-	default:
-		/* Compute the offset from 0xffff f000 0000. */
-		offset = quads_to_bytes(CSR1212_KV_VAL(ki)) + kv_pos;
-		if (offset == kv_pos) {
-			/* Uh-oh.  Can't have a relative offset of 0 for Leaves
-			 * or Directories.  The Config ROM image is most likely
-			 * messed up, so we'll just abort here. */
-			ret = -EIO;
-			goto out;
-		}
-
-		k = csr1212_find_keyval_offset(dir, offset);
-
-		if (k)
-			break;		/* Found it. */
-
-		if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
-			k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
-		else
-			k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
-
-		if (!k) {
-			ret = -ENOMEM;
-			goto out;
-		}
-		/* Don't keep local reference when parsing. */
-		keep_keyval = false;
-		/* Contents not read yet so it's not valid. */
-		k->valid = 0;
-		k->offset = offset;
-
-		k->prev = dir;
-		k->next = dir->next;
-		dir->next->prev = k;
-		dir->next = k;
-	}
-	ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
-out:
-	if (ret != CSR1212_SUCCESS && k != NULL)
-		free_keyval(k);
-	return ret;
-}
-
-int csr1212_parse_keyval(struct csr1212_keyval *kv,
-			 struct csr1212_csr_rom_cache *cache)
-{
-	struct csr1212_keyval_img *kvi;
-	int i;
-	int ret = CSR1212_SUCCESS;
-	int kvi_len;
-
-	kvi = (struct csr1212_keyval_img*)
-		&cache->data[bytes_to_quads(kv->offset - cache->offset)];
-	kvi_len = be16_to_cpu(kvi->length);
-
-	/* GUID is wrong in here in case of extended ROM.  We don't care. */
-	csr1212_check_crc(kvi->data, kvi_len, kvi->crc, &cache->data[3]);
-
-	switch (kv->key.type) {
-	case CSR1212_KV_TYPE_DIRECTORY:
-		for (i = 0; i < kvi_len; i++) {
-			u32 ki = kvi->data[i];
-
-			/* Some devices put null entries in their unit
-			 * directories.  If we come across such an entry,
-			 * then skip it. */
-			if (ki == 0x0)
-				continue;
-			ret = csr1212_parse_dir_entry(kv, ki,
-					kv->offset + quads_to_bytes(i + 1));
-		}
-		kv->value.directory.len = kvi_len;
-		break;
-
-	case CSR1212_KV_TYPE_LEAF:
-		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
-			size_t size = quads_to_bytes(kvi_len);
-
-			kv->value.leaf.data = CSR1212_MALLOC(size);
-			if (!kv->value.leaf.data) {
-				ret = -ENOMEM;
-				goto out;
-			}
-
-			kv->value.leaf.len = kvi_len;
-			memcpy(kv->value.leaf.data, kvi->data, size);
-		}
-		break;
-	}
-
-	kv->valid = 1;
-out:
-	return ret;
-}
-
-static int
-csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
-	struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
-	struct csr1212_keyval_img *kvi = NULL;
-	struct csr1212_csr_rom_cache *cache;
-	int cache_index;
-	u64 addr;
-	u32 *cache_ptr;
-	u16 kv_len = 0;
-
-	BUG_ON(!csr || !kv || csr->max_rom < 1);
-
-	/* First find which cache the data should be in (or go in if not read
-	 * yet). */
-	for (cache = csr->cache_head; cache; cache = cache->next)
-		if (kv->offset >= cache->offset &&
-		    kv->offset < (cache->offset + cache->size))
-			break;
-
-	if (!cache) {
-		u32 q, cache_size;
-
-		/* Only create a new cache for Extended ROM leaves. */
-		if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
-			return -EINVAL;
-
-		if (csr->ops->bus_read(csr,
-				       CSR1212_REGISTER_SPACE_BASE + kv->offset,
-				       &q, csr->private))
-			return -EIO;
-
-		kv->value.leaf.len = be32_to_cpu(q) >> 16;
-
-		cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
-			      (csr->max_rom - 1)) & ~(csr->max_rom - 1);
-
-		cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
-		if (!cache)
-			return -ENOMEM;
-
-		kv->value.leaf.data = &cache->data[1];
-		csr->cache_tail->next = cache;
-		cache->prev = csr->cache_tail;
-		cache->next = NULL;
-		csr->cache_tail = cache;
-		cache->filled_head =
-			CSR1212_MALLOC(sizeof(*cache->filled_head));
-		if (!cache->filled_head)
-			return -ENOMEM;
-
-		cache->filled_head->offset_start = 0;
-		cache->filled_head->offset_end = sizeof(u32);
-		cache->filled_tail = cache->filled_head;
-		cache->filled_head->next = NULL;
-		cache->filled_head->prev = NULL;
-		cache->data[0] = q;
-
-		/* Don't read the entire extended ROM now.  Pieces of it will
-		 * be read when entries inside it are read. */
-		return csr1212_parse_keyval(kv, cache);
-	}
-
-	cache_index = kv->offset - cache->offset;
-
-	/* Now seach read portions of the cache to see if it is there. */
-	for (cr = cache->filled_head; cr; cr = cr->next) {
-		if (cache_index < cr->offset_start) {
-			newcr = CSR1212_MALLOC(sizeof(*newcr));
-			if (!newcr)
-				return -ENOMEM;
-
-			newcr->offset_start = cache_index & ~(csr->max_rom - 1);
-			newcr->offset_end = newcr->offset_start;
-			newcr->next = cr;
-			newcr->prev = cr->prev;
-			cr->prev = newcr;
-			cr = newcr;
-			break;
-		} else if ((cache_index >= cr->offset_start) &&
-			   (cache_index < cr->offset_end)) {
-			kvi = (struct csr1212_keyval_img*)
-				(&cache->data[bytes_to_quads(cache_index)]);
-			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
-			break;
-		} else if (cache_index == cr->offset_end) {
-			break;
-		}
-	}
-
-	if (!cr) {
-		cr = cache->filled_tail;
-		newcr = CSR1212_MALLOC(sizeof(*newcr));
-		if (!newcr)
-			return -ENOMEM;
-
-		newcr->offset_start = cache_index & ~(csr->max_rom - 1);
-		newcr->offset_end = newcr->offset_start;
-		newcr->prev = cr;
-		newcr->next = cr->next;
-		cr->next = newcr;
-		cr = newcr;
-		cache->filled_tail = newcr;
-	}
-
-	while(!kvi || cr->offset_end < cache_index + kv_len) {
-		cache_ptr = &cache->data[bytes_to_quads(cr->offset_end &
-							~(csr->max_rom - 1))];
-
-		addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
-			cr->offset_end) & ~(csr->max_rom - 1);
-
-		if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
-			return -EIO;
-
-		cr->offset_end += csr->max_rom - (cr->offset_end &
-						  (csr->max_rom - 1));
-
-		if (!kvi && (cr->offset_end > cache_index)) {
-			kvi = (struct csr1212_keyval_img*)
-				(&cache->data[bytes_to_quads(cache_index)]);
-			kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
-		}
-
-		if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
-			/* The Leaf or Directory claims its length extends
-			 * beyond the ConfigROM image region and thus beyond the
-			 * end of our cache region.  Therefore, we abort now
-			 * rather than seg faulting later. */
-			return -EIO;
-		}
-
-		ncr = cr->next;
-
-		if (ncr && (cr->offset_end >= ncr->offset_start)) {
-			/* consolidate region entries */
-			ncr->offset_start = cr->offset_start;
-
-			if (cr->prev)
-				cr->prev->next = cr->next;
-			ncr->prev = cr->prev;
-			if (cache->filled_head == cr)
-				cache->filled_head = ncr;
-			CSR1212_FREE(cr);
-			cr = ncr;
-		}
-	}
-
-	return csr1212_parse_keyval(kv, cache);
-}
-
-struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
-{
-	if (!kv)
-		return NULL;
-	if (!kv->valid)
-		if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
-			return NULL;
-	return kv;
-}
-
-int csr1212_parse_csr(struct csr1212_csr *csr)
-{
-	struct csr1212_dentry *dentry;
-	int ret;
-
-	BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
-
-	ret = csr1212_parse_bus_info_block(csr);
-	if (ret != CSR1212_SUCCESS)
-		return ret;
-
-	/*
-	 * There has been a buggy firmware with bus_info_block.max_rom > 0
-	 * spotted which actually only supported quadlet read requests to the
-	 * config ROM.  Therefore read everything quadlet by quadlet regardless
-	 * of what the bus info block says.
-	 */
-	csr->max_rom = 4;
-
-	csr->cache_head->layout_head = csr->root_kv;
-	csr->cache_head->layout_tail = csr->root_kv;
-
-	csr->root_kv->offset = (CSR1212_CONFIG_ROM_SPACE_BASE & 0xffff) +
-		csr->bus_info_len;
-
-	csr->root_kv->valid = 0;
-	csr->root_kv->next = csr->root_kv;
-	csr->root_kv->prev = csr->root_kv;
-	ret = csr1212_read_keyval(csr, csr->root_kv);
-	if (ret != CSR1212_SUCCESS)
-		return ret;
-
-	/* Scan through the Root directory finding all extended ROM regions
-	 * and make cache regions for them */
-	for (dentry = csr->root_kv->value.directory.dentries_head;
-	     dentry; dentry = dentry->next) {
-		if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
-			!dentry->kv->valid) {
-			ret = csr1212_read_keyval(csr, dentry->kv);
-			if (ret != CSR1212_SUCCESS)
-				return ret;
-		}
-	}
-
-	return CSR1212_SUCCESS;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/csr1212.h linux-libre-2.6.37-gnu/drivers/ieee1394/csr1212.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/csr1212.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/csr1212.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,383 +0,0 @@
-/*
- * csr1212.h -- IEEE 1212 Control and Status Register support for Linux
- *
- * Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
- *                    Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *    2. Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *    3. The name of the author may not be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __CSR1212_H__
-#define __CSR1212_H__
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <asm/atomic.h>
-
-#define CSR1212_MALLOC(size)	kmalloc((size), GFP_KERNEL)
-#define CSR1212_FREE(ptr)	kfree(ptr)
-
-#define CSR1212_SUCCESS (0)
-
-
-/* CSR 1212 key types */
-#define CSR1212_KV_TYPE_IMMEDIATE		0
-#define CSR1212_KV_TYPE_CSR_OFFSET		1
-#define CSR1212_KV_TYPE_LEAF			2
-#define CSR1212_KV_TYPE_DIRECTORY		3
-
-
-/* CSR 1212 key ids */
-#define CSR1212_KV_ID_DESCRIPTOR		0x01
-#define CSR1212_KV_ID_BUS_DEPENDENT_INFO	0x02
-#define CSR1212_KV_ID_VENDOR			0x03
-#define CSR1212_KV_ID_HARDWARE_VERSION		0x04
-#define CSR1212_KV_ID_MODULE			0x07
-#define CSR1212_KV_ID_NODE_CAPABILITIES		0x0C
-#define CSR1212_KV_ID_EUI_64			0x0D
-#define CSR1212_KV_ID_UNIT			0x11
-#define CSR1212_KV_ID_SPECIFIER_ID		0x12
-#define CSR1212_KV_ID_VERSION			0x13
-#define CSR1212_KV_ID_DEPENDENT_INFO		0x14
-#define CSR1212_KV_ID_UNIT_LOCATION		0x15
-#define CSR1212_KV_ID_MODEL			0x17
-#define CSR1212_KV_ID_INSTANCE			0x18
-#define CSR1212_KV_ID_KEYWORD			0x19
-#define CSR1212_KV_ID_FEATURE			0x1A
-#define CSR1212_KV_ID_EXTENDED_ROM		0x1B
-#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID	0x1C
-#define CSR1212_KV_ID_EXTENDED_KEY		0x1D
-#define CSR1212_KV_ID_EXTENDED_DATA		0x1E
-#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR	0x1F
-#define CSR1212_KV_ID_DIRECTORY_ID		0x20
-#define CSR1212_KV_ID_REVISION			0x21
-
-
-/* IEEE 1212 Address space map */
-#define CSR1212_ALL_SPACE_BASE			(0x000000000000ULL)
-#define CSR1212_ALL_SPACE_SIZE			(1ULL << 48)
-#define CSR1212_ALL_SPACE_END			(CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
-
-#define  CSR1212_MEMORY_SPACE_BASE		(0x000000000000ULL)
-#define  CSR1212_MEMORY_SPACE_SIZE		((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
-#define  CSR1212_MEMORY_SPACE_END		(CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
-
-#define  CSR1212_PRIVATE_SPACE_BASE		(0xffffe0000000ULL)
-#define  CSR1212_PRIVATE_SPACE_SIZE		(256ULL * (1ULL << 20))
-#define  CSR1212_PRIVATE_SPACE_END		(CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
-
-#define  CSR1212_REGISTER_SPACE_BASE		(0xfffff0000000ULL)
-#define  CSR1212_REGISTER_SPACE_SIZE		(256ULL * (1ULL << 20))
-#define  CSR1212_REGISTER_SPACE_END		(CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
-
-#define  CSR1212_CSR_ARCH_REG_SPACE_BASE	(0xfffff0000000ULL)
-#define  CSR1212_CSR_ARCH_REG_SPACE_SIZE	(512)
-#define  CSR1212_CSR_ARCH_REG_SPACE_END		(CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
-#define  CSR1212_CSR_ARCH_REG_SPACE_OFFSET	(CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_BASE	(0xfffff0000200ULL)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE	(512)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_END	(CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
-#define  CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET	(CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_CONFIG_ROM_SPACE_BASE		(0xfffff0000400ULL)
-#define  CSR1212_CONFIG_ROM_SPACE_SIZE		(1024)
-#define  CSR1212_CONFIG_ROM_SPACE_END		(CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
-#define  CSR1212_CONFIG_ROM_SPACE_OFFSET	(CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_UNITS_SPACE_BASE		(0xfffff0000800ULL)
-#define  CSR1212_UNITS_SPACE_SIZE		((256ULL * (1ULL << 20)) - 2048)
-#define  CSR1212_UNITS_SPACE_END		(CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
-#define  CSR1212_UNITS_SPACE_OFFSET		(CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-
-#define  CSR1212_INVALID_ADDR_SPACE		-1
-
-
-/* Config ROM image structures */
-struct csr1212_bus_info_block_img {
-	u8 length;
-	u8 crc_length;
-	u16 crc;
-
-	/* Must be last */
-	u32 data[0];	/* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_leaf {
-	int len;
-	u32 *data;
-};
-
-struct csr1212_dentry {
-	struct csr1212_dentry *next, *prev;
-	struct csr1212_keyval *kv;
-};
-
-struct csr1212_directory {
-	int len;
-	struct csr1212_dentry *dentries_head, *dentries_tail;
-};
-
-struct csr1212_keyval {
-	struct {
-		u8 type;
-		u8 id;
-	} key;
-	union {
-		u32 immediate;
-		u32 csr_offset;
-		struct csr1212_leaf leaf;
-		struct csr1212_directory directory;
-	} value;
-	struct csr1212_keyval *associate;
-	atomic_t refcnt;
-
-	/* used in generating and/or parsing CSR image */
-	struct csr1212_keyval *next, *prev;	/* flat list of CSR elements */
-	u32 offset;	/* position in CSR from 0xffff f000 0000 */
-	u8 valid;	/* flag indicating keyval has valid data*/
-};
-
-
-struct csr1212_cache_region {
-	struct csr1212_cache_region *next, *prev;
-	u32 offset_start;	/* inclusive */
-	u32 offset_end;		/* exclusive */
-};
-
-struct csr1212_csr_rom_cache {
-	struct csr1212_csr_rom_cache *next, *prev;
-	struct csr1212_cache_region *filled_head, *filled_tail;
-	struct csr1212_keyval *layout_head, *layout_tail;
-	size_t size;
-	u32 offset;
-	struct csr1212_keyval *ext_rom;
-	size_t len;
-
-	/* Must be last */
-	u32 data[0];	/* older gcc can't handle [] which is standard */
-};
-
-struct csr1212_csr {
-	size_t bus_info_len;	/* bus info block length in bytes */
-	size_t crc_len;		/* crc length in bytes */
-	__be32 *bus_info_data;	/* bus info data incl bus name and EUI */
-
-	void *private;		/* private, bus specific data */
-	struct csr1212_bus_ops *ops;
-
-	struct csr1212_keyval *root_kv;
-
-	int max_rom;		/* max bytes readable in Config ROM region */
-
-	/* Items below used for image parsing and generation */
-	struct csr1212_csr_rom_cache *cache_head, *cache_tail;
-};
-
-struct csr1212_bus_ops {
-	/* This function is used by csr1212 to read additional information
-	 * from remote nodes when parsing a Config ROM (i.e., read Config ROM
-	 * entries located in the Units Space.  Must return 0 on success
-	 * anything else indicates an error. */
-	int (*bus_read) (struct csr1212_csr *csr, u64 addr,
-			 void *buffer, void *private);
-
-	/* This function is used by csr1212 to allocate a region in units space
-	 * in the event that Config ROM entries don't all fit in the predefined
-	 * 1K region.  The void *private parameter is private member of struct
-	 * csr1212_csr. */
-	u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
-
-	/* This function is used by csr1212 to release a region in units space
-	 * that is no longer needed. */
-	void (*release_addr) (u64 addr, void *private);
-};
-
-
-/* Descriptor Leaf manipulation macros */
-#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
-	(be32_to_cpu((kv)->value.leaf.data[0]) >> \
-	 CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
-#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
-	(be32_to_cpu((kv)->value.leaf.data[0]) & \
-	 CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-
-
-/* Text Descriptor Leaf manipulation macros */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff  /* after shift */
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
-
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
-	(be32_to_cpu((kv)->value.leaf.data[1]) >> \
-	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
-	((be32_to_cpu((kv)->value.leaf.data[1]) >> \
-	  CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
-	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
-	(be32_to_cpu((kv)->value.leaf.data[1]) & \
-	 CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
-	(&((kv)->value.leaf.data[2]))
-
-
-/* The following 2 function are for creating new Configuration ROM trees.  The
- * first function is used for both creating local trees and parsing remote
- * trees.  The second function adds pertinent information to local Configuration
- * ROM trees - namely data for the bus information block. */
-extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
-					      size_t bus_info_size,
-					      void *private);
-extern void csr1212_init_local_csr(struct csr1212_csr *csr,
-				   const u32 *bus_info_data, int max_rom);
-
-
-/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
-extern void csr1212_destroy_csr(struct csr1212_csr *csr);
-
-
-/* The following set of functions are fore creating new keyvals for placement in
- * a Configuration ROM tree.  Code that creates new keyvals with these functions
- * must release those keyvals with csr1212_release_keyval() when they are no
- * longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
-extern struct csr1212_keyval *csr1212_new_directory(u8 key);
-extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-
-
-/* The following function manages association between keyvals.  Typically,
- * Descriptor Leaves and Directories will be associated with another keyval and
- * it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.
- * Take care with subsequent ROM modifications:  There is no function to remove
- * previously specified associations.
- */
-extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
-				     struct csr1212_keyval *associate);
-
-
-/* The following functions manage the association of a keyval and directories.
- * A keyval may be attached to more than one directory. */
-extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
-					      struct csr1212_keyval *kv);
-extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
-						 struct csr1212_keyval *kv);
-
-
-/* Creates a complete Configuration ROM image in the list of caches available
- * via csr->cache_head. */
-extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
-
-
-/* This is a convience function for reading a block of data out of one of the
- * caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
-			u32 len);
-
-
-/* The following functions are in place for parsing Configuration ROM images.
- * csr1212_parse_keyval() is used should there be a need to directly parse a
- * Configuration ROM directly. */
-extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
-				struct csr1212_csr_rom_cache *cache);
-extern int csr1212_parse_csr(struct csr1212_csr *csr);
-
-
-/* This function allocates a new cache which may be used for either parsing or
- * generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *
-csr1212_rom_cache_malloc(u32 offset, size_t size)
-{
-	struct csr1212_csr_rom_cache *cache;
-
-	cache = CSR1212_MALLOC(sizeof(*cache) + size);
-	if (!cache)
-		return NULL;
-
-	cache->next = NULL;
-	cache->prev = NULL;
-	cache->filled_head = NULL;
-	cache->filled_tail = NULL;
-	cache->layout_head = NULL;
-	cache->layout_tail = NULL;
-	cache->offset = offset;
-	cache->size = size;
-	cache->ext_rom = NULL;
-
-	return cache;
-}
-
-
-/* This function ensures that a keyval contains data when referencing a keyval
- * created by parsing a Configuration ROM. */
-extern struct csr1212_keyval *
-csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-
-
-/* This function increments the reference count for a keyval should there be a
- * need for code to retain a keyval that has been parsed. */
-static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
-{
-	atomic_inc(&kv->refcnt);
-	smp_mb__after_atomic_inc();
-}
-
-
-/* This function decrements a keyval's reference count and will destroy the
- * keyval when there are no more users of the keyval.  This should be called by
- * any code that calls csr1212_keep_keyval() or any of the keyval creation
- * routines csr1212_new_*(). */
-extern void csr1212_release_keyval(struct csr1212_keyval *kv);
-
-
-/*
- * This macro allows for looping over the keyval entries in a directory and it
- * ensures that keyvals from remote ConfigROMs are parsed properly.
- *
- * struct csr1212_csr *_csr points to the CSR associated with dir.
- * struct csr1212_keyval *_kv points to the current keyval (loop index).
- * struct csr1212_keyval *_dir points to the directory to be looped.
- * struct csr1212_dentry *_pos is used internally for indexing.
- *
- * kv will be NULL upon exit of the loop.
- */
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos)		\
-	for (csr1212_get_keyval((_csr), (_dir)),			\
-	     _pos = (_dir)->value.directory.dentries_head,		\
-	     _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
-	     (_kv) && (_pos);						\
-	     (_kv->associate == NULL) ?					\
-		     ((_pos = _pos->next), (_kv = (_pos) ?		\
-				csr1212_get_keyval((_csr), _pos->kv) :	\
-				NULL)) :				\
-		     (_kv = csr1212_get_keyval((_csr), _kv->associate)))
-
-#endif /* __CSR1212_H__ */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/csr.c linux-libre-2.6.37-gnu/drivers/ieee1394/csr.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/csr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/csr.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,843 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * CSR implementation, iso/bus manager implementation.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        configuration ROM manipulation
- *
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/param.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "highlevel.h"
-#include "ieee1394_core.h"
-
-/* Module Parameters */
-/* this module parameter can be used to disable mapping of the FCP registers */
-
-static int fcp = 1;
-module_param(fcp, int, 0444);
-MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
-
-static struct csr1212_keyval *node_cap = NULL;
-
-static void add_host(struct hpsb_host *host);
-static void remove_host(struct hpsb_host *host);
-static void host_reset(struct hpsb_host *host);
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-		     u64 addr, size_t length, u16 fl);
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		     u64 addr, size_t length, u16 flags);
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, size_t length, u16 flags);
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
-		       u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-			   u64 addr, size_t length, u16 fl);
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
-static void release_addr_range(u64 addr, void *__host);
-
-static struct hpsb_highlevel csr_highlevel = {
-	.name =		"standard registers",
-	.add_host =	add_host,
-	.remove_host =	remove_host,
-	.host_reset =	host_reset,
-};
-
-static const struct hpsb_address_ops map_ops = {
-	.read = read_maps,
-};
-
-static const struct hpsb_address_ops fcp_ops = {
-	.write = write_fcp,
-};
-
-static const struct hpsb_address_ops reg_ops = {
-	.read = read_regs,
-	.write = write_regs,
-	.lock = lock_regs,
-	.lock64 = lock64_regs,
-};
-
-static const struct hpsb_address_ops config_rom_ops = {
-	.read = read_config_rom,
-};
-
-struct csr1212_bus_ops csr_bus_ops = {
-	.allocate_addr_range =	allocate_addr_range,
-	.release_addr =		release_addr_range,
-};
-
-
-static u16 csr_crc16(unsigned *data, int length)
-{
-        int check=0, i;
-        int shift, sum, next=0;
-
-        for (i = length; i; i--) {
-                for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
-                        next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
-                }
-                check = next & 0xffff;
-                data++;
-        }
-
-        return check;
-}
-
-static void host_reset(struct hpsb_host *host)
-{
-        host->csr.state &= 0x300;
-
-        host->csr.bus_manager_id = 0x3f;
-        host->csr.bandwidth_available = 4915;
-	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
-        host->csr.channels_available_lo = ~0;
-	host->csr.broadcast_channel = 0x80000000 | 31;
-
-	if (host->is_irm) {
-		if (host->driver->hw_csr_reg) {
-			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
-		}
-	}
-
-        host->csr.node_ids = host->node_id << 16;
-
-        if (!host->is_root) {
-                /* clear cmstr bit */
-                host->csr.state &= ~0x100;
-        }
-
-	be32_add_cpu(&host->csr.topology_map[1], 1);
-        host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
-                                                | host->selfid_count);
-        host->csr.topology_map[0] =
-                cpu_to_be32((host->selfid_count + 2) << 16
-                            | csr_crc16(host->csr.topology_map + 1,
-                                        host->selfid_count + 2));
-
-	be32_add_cpu(&host->csr.speed_map[1], 1);
-        host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
-                                             | csr_crc16(host->csr.speed_map+1,
-                                                         0x3f1));
-}
-
-/*
- * HI == seconds (bits 0:2)
- * LO == fractions of a second in units of 125usec (bits 19:31)
- *
- * Convert SPLIT_TIMEOUT to jiffies.
- * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
- */
-static inline void calculate_expire(struct csr_control *csr)
-{
-	unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
-			     (csr->split_timeout_lo >> 19) * 125;
-
-	csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
-	HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
-}
-
-
-static void add_host(struct hpsb_host *host)
-{
-	struct csr1212_keyval *root;
-	quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
-	hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
-				CSR_REGISTER_BASE,
-				CSR_REGISTER_BASE + CSR_CONFIG_ROM);
-	hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
-				CSR_REGISTER_BASE + CSR_CONFIG_ROM,
-				CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-	if (fcp) {
-		hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
-					CSR_REGISTER_BASE + CSR_FCP_COMMAND,
-					CSR_REGISTER_BASE + CSR_FCP_END);
-	}
-	hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
-				CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
-				CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
-	hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
-				CSR_REGISTER_BASE + CSR_SPEED_MAP,
-				CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
-
-        spin_lock_init(&host->csr.lock);
-
-        host->csr.state                 = 0;
-        host->csr.node_ids              = 0;
-        host->csr.split_timeout_hi      = 0;
-        host->csr.split_timeout_lo      = 800 << 19;
-	calculate_expire(&host->csr);
-        host->csr.cycle_time            = 0;
-        host->csr.bus_time              = 0;
-        host->csr.bus_manager_id        = 0x3f;
-        host->csr.bandwidth_available   = 4915;
-	host->csr.channels_available_hi = 0xfffffffe;	/* pre-alloc ch 31 per 1394a-2000 */
-        host->csr.channels_available_lo = ~0;
-	host->csr.broadcast_channel = 0x80000000 | 31;
-
-	if (host->is_irm) {
-		if (host->driver->hw_csr_reg) {
-			host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
-		}
-	}
-
-	if (host->csr.max_rec >= 9)
-		host->csr.max_rom = 2;
-	else if (host->csr.max_rec >= 5)
-		host->csr.max_rom = 1;
-	else
-		host->csr.max_rom = 0;
-
-	host->csr.generation = 2;
-
-	bus_info[1] = IEEE1394_BUSID_MAGIC;
-	bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
-				  (1 << CSR_CMC_SHIFT) |
-				  (1 << CSR_ISC_SHIFT) |
-				  (0 << CSR_BMC_SHIFT) |
-				  (0 << CSR_PMC_SHIFT) |
-				  (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
-				  (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
-				  (host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
-				  (host->csr.generation << CSR_GENERATION_SHIFT) |
-				  host->csr.lnk_spd);
-
-	bus_info[3] = cpu_to_be32(host->csr.guid_hi);
-	bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
-	/* The hardware copy of the bus info block will be set later when a
-	 * bus reset is issued. */
-
-	csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
-
-	root = host->csr.rom->root_kv;
-
-	if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
-		HPSB_ERR("Failed to attach Node Capabilities to root directory");
-	}
-
-	host->update_config_rom = 1;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
-	quadlet_t bus_info[CSR_BUS_INFO_SIZE];
-
-	bus_info[1] = IEEE1394_BUSID_MAGIC;
-	bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
-				  (0 << CSR_CMC_SHIFT) |
-				  (0 << CSR_ISC_SHIFT) |
-				  (0 << CSR_BMC_SHIFT) |
-				  (0 << CSR_PMC_SHIFT) |
-				  (host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
-				  (host->csr.max_rec << CSR_MAX_REC_SHIFT) |
-				  (0 << CSR_MAX_ROM_SHIFT) |
-				  (0 << CSR_GENERATION_SHIFT) |
-				  host->csr.lnk_spd);
-
-	bus_info[3] = cpu_to_be32(host->csr.guid_hi);
-	bus_info[4] = cpu_to_be32(host->csr.guid_lo);
-
-	csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
-
-	csr1212_init_local_csr(host->csr.rom, bus_info, 0);
-	host->update_config_rom = 1;
-}
-
-
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
-	size_t buffersize, unsigned char rom_version)
-{
-	unsigned long flags;
-	int ret;
-
-	HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-	if (rom_version != host->csr.generation)
-                ret = -1;
-	else if (buffersize > host->csr.rom->cache_head->size)
-		ret = -2;
-        else {
-		/* Just overwrite the generated ConfigROM image with new data,
-		 * it can be regenerated later. */
-		memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
-		host->csr.rom->cache_head->len = buffersize;
-
-		if (host->driver->set_hw_config_rom)
-			host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
-		/* Increment the generation number to keep some sort of sync
-		 * with the newer ConfigROM manipulation method. */
-		host->csr.generation++;
-		if (host->csr.generation > 0xf || host->csr.generation < 2)
-			host->csr.generation = 2;
-		ret=0;
-        }
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-        return ret;
-}
-
-
-/* Read topology / speed maps and configuration ROM */
-static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, size_t length, u16 fl)
-{
-	unsigned long flags;
-        int csraddr = addr - CSR_REGISTER_BASE;
-        const char *src;
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-
-	if (csraddr < CSR_SPEED_MAP) {
-                src = ((char *)host->csr.topology_map) + csraddr
-                        - CSR_TOPOLOGY_MAP;
-        } else {
-                src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
-        }
-
-        memcpy(buffer, src, length);
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-        return RCODE_COMPLETE;
-}
-
-
-#define out if (--length == 0) break
-
-static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-        int oldcycle;
-        quadlet_t ret;
-
-        if ((csraddr | length) & 0x3)
-                return RCODE_TYPE_ERROR;
-
-        length /= 4;
-
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-                *(buf++) = cpu_to_be32(host->csr.state);
-                out;
-        case CSR_STATE_SET:
-                *(buf++) = cpu_to_be32(host->csr.state);
-                out;
-        case CSR_NODE_IDS:
-                *(buf++) = cpu_to_be32(host->csr.node_ids);
-                out;
-
-        case CSR_RESET_START:
-                return RCODE_TYPE_ERROR;
-
-                /* address gap - handled by default below */
-
-        case CSR_SPLIT_TIMEOUT_HI:
-                *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
-                out;
-        case CSR_SPLIT_TIMEOUT_LO:
-                *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_CYCLE_TIME:
-                oldcycle = host->csr.cycle_time;
-                host->csr.cycle_time =
-                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
-                if (oldcycle > host->csr.cycle_time) {
-                        /* cycle time wrapped around */
-                        host->csr.bus_time += 1 << 7;
-                }
-                *(buf++) = cpu_to_be32(host->csr.cycle_time);
-                out;
-        case CSR_BUS_TIME:
-                oldcycle = host->csr.cycle_time;
-                host->csr.cycle_time =
-                        host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-
-                if (oldcycle > host->csr.cycle_time) {
-                        /* cycle time wrapped around */
-                        host->csr.bus_time += (1 << 7);
-                }
-                *(buf++) = cpu_to_be32(host->csr.bus_time
-                                       | (host->csr.cycle_time >> 25));
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUS_MANAGER_ID:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 0, 0, 0);
-                else
-                        ret = host->csr.bus_manager_id;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_BANDWIDTH_AVAILABLE:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 1, 0, 0);
-                else
-                        ret = host->csr.bandwidth_available;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_CHANNELS_AVAILABLE_HI:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 2, 0, 0);
-                else
-                        ret = host->csr.channels_available_hi;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-        case CSR_CHANNELS_AVAILABLE_LO:
-                if (host->driver->hw_csr_reg)
-                        ret = host->driver->hw_csr_reg(host, 3, 0, 0);
-                else
-                        ret = host->csr.channels_available_lo;
-
-                *(buf++) = cpu_to_be32(ret);
-                out;
-
-	case CSR_BROADCAST_CHANNEL:
-		*(buf++) = cpu_to_be32(host->csr.broadcast_channel);
-		out;
-
-                /* address gap to end - fall through to default */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-
-        if ((csraddr | length) & 0x3)
-                return RCODE_TYPE_ERROR;
-
-        length /= 4;
-
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-                /* FIXME FIXME FIXME */
-                printk("doh, someone wants to mess with state clear\n");
-                out;
-        case CSR_STATE_SET:
-                printk("doh, someone wants to mess with state set\n");
-                out;
-
-        case CSR_NODE_IDS:
-                host->csr.node_ids &= NODE_MASK << 16;
-                host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
-                host->node_id = host->csr.node_ids >> 16;
-                host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
-                out;
-
-        case CSR_RESET_START:
-                /* FIXME - perform command reset */
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_SPLIT_TIMEOUT_HI:
-                host->csr.split_timeout_hi =
-                        be32_to_cpu(*(data++)) & 0x00000007;
-		calculate_expire(&host->csr);
-                out;
-        case CSR_SPLIT_TIMEOUT_LO:
-                host->csr.split_timeout_lo =
-                        be32_to_cpu(*(data++)) & 0xfff80000;
-		calculate_expire(&host->csr);
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_CYCLE_TIME:
-                /* should only be set by cycle start packet, automatically */
-                host->csr.cycle_time = be32_to_cpu(*data);
-                host->driver->devctl(host, SET_CYCLE_COUNTER,
-                                       be32_to_cpu(*(data++)));
-                out;
-        case CSR_BUS_TIME:
-                host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
-                out;
-
-                /* address gap */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented */
-                return RCODE_ADDRESS_ERROR;
-
-        case CSR_BUS_MANAGER_ID:
-        case CSR_BANDWIDTH_AVAILABLE:
-        case CSR_CHANNELS_AVAILABLE_HI:
-        case CSR_CHANNELS_AVAILABLE_LO:
-                /* these are not writable, only lockable */
-                return RCODE_TYPE_ERROR;
-
-	case CSR_BROADCAST_CHANNEL:
-		/* only the valid bit can be written */
-		host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
-                        | (be32_to_cpu(*data) & 0x40000000);
-		out;
-
-                /* address gap to end - fall through */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-#undef out
-
-
-static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-        unsigned long flags;
-        quadlet_t *regptr = NULL;
-
-        if (csraddr & 0x3)
-		return RCODE_TYPE_ERROR;
-
-        if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
-            || extcode != EXTCODE_COMPARE_SWAP)
-                goto unsupported_lockreq;
-
-        data = be32_to_cpu(data);
-        arg = be32_to_cpu(arg);
-
-	/* Is somebody releasing the broadcast_channel on us? */
-	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
-		/* Note: this is may not be the right way to handle
-		 * the problem, so we should look into the proper way
-		 * eventually. */
-		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
-			  "broadcast channel 31.  Ignoring.",
-			  NODE_BUS_ARGS(host, nodeid));
-
-		data &= ~0x1;	/* keep broadcast channel allocated */
-	}
-
-        if (host->driver->hw_csr_reg) {
-                quadlet_t old;
-
-                old = host->driver->
-                        hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
-                                   data, arg);
-
-                *store = cpu_to_be32(old);
-                return RCODE_COMPLETE;
-        }
-
-        spin_lock_irqsave(&host->csr.lock, flags);
-
-        switch (csraddr) {
-        case CSR_BUS_MANAGER_ID:
-                regptr = &host->csr.bus_manager_id;
-		*store = cpu_to_be32(*regptr);
-		if (*regptr == arg)
-			*regptr = data;
-                break;
-
-        case CSR_BANDWIDTH_AVAILABLE:
-        {
-                quadlet_t bandwidth;
-                quadlet_t old;
-                quadlet_t new;
-
-                regptr = &host->csr.bandwidth_available;
-                old = *regptr;
-
-                /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
-                if (arg > 0x1fff) {
-                        *store = cpu_to_be32(old);	/* change nothing */
-			break;
-                }
-                data &= 0x1fff;
-                if (arg >= data) {
-                        /* allocate bandwidth */
-                        bandwidth = arg - data;
-                        if (old >= bandwidth) {
-                                new = old - bandwidth;
-                                *store = cpu_to_be32(arg);
-                                *regptr = new;
-                        } else {
-                                *store = cpu_to_be32(old);
-                        }
-                } else {
-                        /* deallocate bandwidth */
-                        bandwidth = data - arg;
-                        if (old + bandwidth < 0x2000) {
-                                new = old + bandwidth;
-                                *store = cpu_to_be32(arg);
-                                *regptr = new;
-                        } else {
-                                *store = cpu_to_be32(old);
-                        }
-                }
-                break;
-        }
-
-        case CSR_CHANNELS_AVAILABLE_HI:
-        {
-                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
-                quadlet_t affected_channels = arg ^ data;
-
-                regptr = &host->csr.channels_available_hi;
-
-                if ((arg & affected_channels) == (*regptr & affected_channels)) {
-                        *regptr ^= affected_channels;
-                        *store = cpu_to_be32(arg);
-                } else {
-                        *store = cpu_to_be32(*regptr);
-                }
-
-                break;
-        }
-
-        case CSR_CHANNELS_AVAILABLE_LO:
-        {
-                /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
-                quadlet_t affected_channels = arg ^ data;
-
-                regptr = &host->csr.channels_available_lo;
-
-                if ((arg & affected_channels) == (*regptr & affected_channels)) {
-                        *regptr ^= affected_channels;
-                        *store = cpu_to_be32(arg);
-                } else {
-                        *store = cpu_to_be32(*regptr);
-                }
-                break;
-        }
-        }
-
-        spin_unlock_irqrestore(&host->csr.lock, flags);
-
-        return RCODE_COMPLETE;
-
- unsupported_lockreq:
-        switch (csraddr) {
-        case CSR_STATE_CLEAR:
-        case CSR_STATE_SET:
-        case CSR_RESET_START:
-        case CSR_NODE_IDS:
-        case CSR_SPLIT_TIMEOUT_HI:
-        case CSR_SPLIT_TIMEOUT_LO:
-        case CSR_CYCLE_TIME:
-        case CSR_BUS_TIME:
-	case CSR_BROADCAST_CHANNEL:
-                return RCODE_TYPE_ERROR;
-
-        case CSR_BUSY_TIMEOUT:
-                /* not yet implemented - fall through */
-        default:
-                return RCODE_ADDRESS_ERROR;
-        }
-}
-
-static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
-		       u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
-{
-	int csraddr = addr - CSR_REGISTER_BASE;
-	unsigned long flags;
-
-	data = be64_to_cpu(data);
-	arg = be64_to_cpu(arg);
-
-	if (csraddr & 0x3)
-		return RCODE_TYPE_ERROR;
-
-	if (csraddr != CSR_CHANNELS_AVAILABLE
-	    || extcode != EXTCODE_COMPARE_SWAP)
-		goto unsupported_lock64req;
-
-	/* Is somebody releasing the broadcast_channel on us? */
-	if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
-		/* Note: this is may not be the right way to handle
-		 * the problem, so we should look into the proper way
-                 * eventually. */
-		HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
-			  "broadcast channel 31.  Ignoring.",
-			  NODE_BUS_ARGS(host, nodeid));
-
-		data &= ~0x100000000ULL;	/* keep broadcast channel allocated */
-	}
-
-	if (host->driver->hw_csr_reg) {
-		quadlet_t data_hi, data_lo;
-		quadlet_t arg_hi, arg_lo;
-		quadlet_t old_hi, old_lo;
-
-		data_hi = data >> 32;
-		data_lo = data & 0xFFFFFFFF;
-		arg_hi = arg >> 32;
-		arg_lo = arg & 0xFFFFFFFF;
-
-		old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
-                                                  data_hi, arg_hi);
-
-		old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
-                                                  data_lo, arg_lo);
-
-		*store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
-	} else {
-		octlet_t old;
-		octlet_t affected_channels = arg ^ data;
-
-		spin_lock_irqsave(&host->csr.lock, flags);
-
-		old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
-
-		if ((arg & affected_channels) == (old & affected_channels)) {
-			host->csr.channels_available_hi ^= (affected_channels >> 32);
-			host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
-			*store = cpu_to_be64(arg);
-		} else {
-			*store = cpu_to_be64(old);
-		}
-
-		spin_unlock_irqrestore(&host->csr.lock, flags);
-	}
-
-	/* Is somebody erroneously releasing the broadcast_channel on us? */
-	if (host->csr.channels_available_hi & 0x1)
-		host->csr.channels_available_hi &= ~0x1;
-
-	return RCODE_COMPLETE;
-
- unsupported_lock64req:
-	switch (csraddr) {
-	case CSR_STATE_CLEAR:
-	case CSR_STATE_SET:
-	case CSR_RESET_START:
-	case CSR_NODE_IDS:
-	case CSR_SPLIT_TIMEOUT_HI:
-	case CSR_SPLIT_TIMEOUT_LO:
-	case CSR_CYCLE_TIME:
-	case CSR_BUS_TIME:
-	case CSR_BUS_MANAGER_ID:
-	case CSR_BROADCAST_CHANNEL:
-	case CSR_BUSY_TIMEOUT:
-	case CSR_BANDWIDTH_AVAILABLE:
-		return RCODE_TYPE_ERROR;
-
-	default:
-		return RCODE_ADDRESS_ERROR;
-	}
-}
-
-static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, size_t length, u16 flags)
-{
-        int csraddr = addr - CSR_REGISTER_BASE;
-
-        if (length > 512)
-                return RCODE_TYPE_ERROR;
-
-        switch (csraddr) {
-        case CSR_FCP_COMMAND:
-                highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
-                break;
-        case CSR_FCP_RESPONSE:
-                highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
-                break;
-        default:
-                return RCODE_TYPE_ERROR;
-        }
-
-        return RCODE_COMPLETE;
-}
-
-static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-			   u64 addr, size_t length, u16 fl)
-{
-	u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
-
-	if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
-		return RCODE_COMPLETE;
-	else
-		return RCODE_ADDRESS_ERROR;
-}
-
-static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
-{
- 	struct hpsb_host *host = (struct hpsb_host*)__host;
-
-	return hpsb_allocate_and_register_addrspace(&csr_highlevel,
-						    host,
-						    &config_rom_ops,
-						    size, alignment,
-						    CSR1212_UNITS_SPACE_BASE,
-						    CSR1212_UNITS_SPACE_END);
-}
-
-static void release_addr_range(u64 addr, void *__host)
-{
- 	struct hpsb_host *host = (struct hpsb_host*)__host;
-	hpsb_unregister_addrspace(&csr_highlevel, host, addr);
-}
-
-
-int init_csr(void)
-{
-	node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
-	if (!node_cap) {
-		HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
-		return -ENOMEM;
-	}
-
-	hpsb_register_highlevel(&csr_highlevel);
-
-	return 0;
-}
-
-void cleanup_csr(void)
-{
-	if (node_cap)
-		csr1212_release_keyval(node_cap);
-        hpsb_unregister_highlevel(&csr_highlevel);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/csr.h linux-libre-2.6.37-gnu/drivers/ieee1394/csr.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/csr.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/csr.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,99 +0,0 @@
-#ifndef _IEEE1394_CSR_H
-#define _IEEE1394_CSR_H
-
-#include <linux/spinlock_types.h>
-
-#include "csr1212.h"
-#include "ieee1394_types.h"
-
-#define CSR_REGISTER_BASE		0xfffff0000000ULL
-
-/* register offsets relative to CSR_REGISTER_BASE */
-#define CSR_STATE_CLEAR			0x0
-#define CSR_STATE_SET			0x4
-#define CSR_NODE_IDS			0x8
-#define CSR_RESET_START			0xc
-#define CSR_SPLIT_TIMEOUT_HI		0x18
-#define CSR_SPLIT_TIMEOUT_LO		0x1c
-#define CSR_CYCLE_TIME			0x200
-#define CSR_BUS_TIME			0x204
-#define CSR_BUSY_TIMEOUT		0x210
-#define CSR_BUS_MANAGER_ID		0x21c
-#define CSR_BANDWIDTH_AVAILABLE		0x220
-#define CSR_CHANNELS_AVAILABLE		0x224
-#define CSR_CHANNELS_AVAILABLE_HI	0x224
-#define CSR_CHANNELS_AVAILABLE_LO	0x228
-#define CSR_BROADCAST_CHANNEL		0x234
-#define CSR_CONFIG_ROM			0x400
-#define CSR_CONFIG_ROM_END		0x800
-#define CSR_FCP_COMMAND			0xB00
-#define CSR_FCP_RESPONSE		0xD00
-#define CSR_FCP_END			0xF00
-#define CSR_TOPOLOGY_MAP		0x1000
-#define CSR_TOPOLOGY_MAP_END		0x1400
-#define CSR_SPEED_MAP			0x2000
-#define CSR_SPEED_MAP_END		0x3000
-
-/* IEEE 1394 bus specific Configuration ROM Key IDs */
-#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
-
-/* IEEE 1394 Bus Information Block specifics */
-#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
-
-#define CSR_IRMC_SHIFT			31
-#define CSR_CMC_SHIFT			30
-#define CSR_ISC_SHIFT			29
-#define CSR_BMC_SHIFT			28
-#define CSR_PMC_SHIFT			27
-#define CSR_CYC_CLK_ACC_SHIFT		16
-#define CSR_MAX_REC_SHIFT		12
-#define CSR_MAX_ROM_SHIFT		8
-#define CSR_GENERATION_SHIFT		4
-
-static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
-{
-	csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
-	csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
-}
-
-struct csr_control {
-	spinlock_t lock;
-
-	quadlet_t state;
-	quadlet_t node_ids;
-	quadlet_t split_timeout_hi, split_timeout_lo;
-	unsigned long expire;	/* Calculated from split_timeout */
-	quadlet_t cycle_time;
-	quadlet_t bus_time;
-	quadlet_t bus_manager_id;
-	quadlet_t bandwidth_available;
-	quadlet_t channels_available_hi, channels_available_lo;
-	quadlet_t broadcast_channel;
-
-	/* Bus Info */
-	quadlet_t guid_hi, guid_lo;
-	u8 cyc_clk_acc;
-	u8 max_rec;
-	u8 max_rom;
-	u8 generation;	/* Only use values between 0x2 and 0xf */
-	u8 lnk_spd;
-
-	unsigned long gen_timestamp[16];
-
-	struct csr1212_csr *rom;
-
-	quadlet_t topology_map[256];
-	quadlet_t speed_map[1024];
-};
-
-extern struct csr1212_bus_ops csr_bus_ops;
-
-int init_csr(void);
-void cleanup_csr(void);
-
-/* hpsb_update_config_rom() is deprecated */
-struct hpsb_host;
-int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
-			   size_t size, unsigned char rom_version);
-
-#endif /* _IEEE1394_CSR_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/dma.c linux-libre-2.6.37-gnu/drivers/ieee1394/dma.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/dma.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,289 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/scatterlist.h>
-
-#include "dma.h"
-
-/* dma_prog_region */
-
-void dma_prog_region_init(struct dma_prog_region *prog)
-{
-	prog->kvirt = NULL;
-	prog->dev = NULL;
-	prog->n_pages = 0;
-	prog->bus_addr = 0;
-}
-
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
-			  struct pci_dev *dev)
-{
-	/* round up to page size */
-	n_bytes = PAGE_ALIGN(n_bytes);
-
-	prog->n_pages = n_bytes >> PAGE_SHIFT;
-
-	prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
-	if (!prog->kvirt) {
-		printk(KERN_ERR
-		       "dma_prog_region_alloc: pci_alloc_consistent() failed\n");
-		dma_prog_region_free(prog);
-		return -ENOMEM;
-	}
-
-	prog->dev = dev;
-
-	return 0;
-}
-
-void dma_prog_region_free(struct dma_prog_region *prog)
-{
-	if (prog->kvirt) {
-		pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
-				    prog->kvirt, prog->bus_addr);
-	}
-
-	prog->kvirt = NULL;
-	prog->dev = NULL;
-	prog->n_pages = 0;
-	prog->bus_addr = 0;
-}
-
-/* dma_region */
-
-/**
- * dma_region_init - clear out all fields but do not allocate anything
- */
-void dma_region_init(struct dma_region *dma)
-{
-	dma->kvirt = NULL;
-	dma->dev = NULL;
-	dma->n_pages = 0;
-	dma->n_dma_pages = 0;
-	dma->sglist = NULL;
-}
-
-/**
- * dma_region_alloc - allocate the buffer and map it to the IOMMU
- */
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
-		     struct pci_dev *dev, int direction)
-{
-	unsigned int i;
-
-	/* round up to page size */
-	n_bytes = PAGE_ALIGN(n_bytes);
-
-	dma->n_pages = n_bytes >> PAGE_SHIFT;
-
-	dma->kvirt = vmalloc_32(n_bytes);
-	if (!dma->kvirt) {
-		printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
-		goto err;
-	}
-
-	/* Clear the ram out, no junk to the user */
-	memset(dma->kvirt, 0, n_bytes);
-
-	/* allocate scatter/gather list */
-	dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
-	if (!dma->sglist) {
-		printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
-		goto err;
-	}
-
-	sg_init_table(dma->sglist, dma->n_pages);
-
-	/* fill scatter/gather list with pages */
-	for (i = 0; i < dma->n_pages; i++) {
-		unsigned long va =
-		    (unsigned long)dma->kvirt + (i << PAGE_SHIFT);
-
-		sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
-				PAGE_SIZE, 0);
-	}
-
-	/* map sglist to the IOMMU */
-	dma->n_dma_pages =
-	    pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
-
-	if (dma->n_dma_pages == 0) {
-		printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
-		goto err;
-	}
-
-	dma->dev = dev;
-	dma->direction = direction;
-
-	return 0;
-
-      err:
-	dma_region_free(dma);
-	return -ENOMEM;
-}
-
-/**
- * dma_region_free - unmap and free the buffer
- */
-void dma_region_free(struct dma_region *dma)
-{
-	if (dma->n_dma_pages) {
-		pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
-			     dma->direction);
-		dma->n_dma_pages = 0;
-		dma->dev = NULL;
-	}
-
-	vfree(dma->sglist);
-	dma->sglist = NULL;
-
-	vfree(dma->kvirt);
-	dma->kvirt = NULL;
-	dma->n_pages = 0;
-}
-
-/* find the scatterlist index and remaining offset corresponding to a
-   given offset from the beginning of the buffer */
-static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
-				  unsigned int start, unsigned long *rem)
-{
-	int i;
-	unsigned long off = offset;
-
-	for (i = start; i < dma->n_dma_pages; i++) {
-		if (off < sg_dma_len(&dma->sglist[i])) {
-			*rem = off;
-			break;
-		}
-
-		off -= sg_dma_len(&dma->sglist[i]);
-	}
-
-	BUG_ON(i >= dma->n_dma_pages);
-
-	return i;
-}
-
-/**
- * dma_region_offset_to_bus - get bus address of an offset within a DMA region
- *
- * Returns the DMA bus address of the byte with the given @offset relative to
- * the beginning of the @dma.
- */
-dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
-				    unsigned long offset)
-{
-	unsigned long rem = 0;
-
-	struct scatterlist *sg =
-	    &dma->sglist[dma_region_find(dma, offset, 0, &rem)];
-	return sg_dma_address(sg) + rem;
-}
-
-/**
- * dma_region_sync_for_cpu - sync the CPU's view of the buffer
- */
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
-			     unsigned long len)
-{
-	int first, last;
-	unsigned long rem = 0;
-
-	if (!len)
-		len = 1;
-
-	first = dma_region_find(dma, offset, 0, &rem);
-	last = dma_region_find(dma, rem + len - 1, first, &rem);
-
-	pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
-				dma->direction);
-}
-
-/**
- * dma_region_sync_for_device - sync the IO bus' view of the buffer
- */
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
-				unsigned long len)
-{
-	int first, last;
-	unsigned long rem = 0;
-
-	if (!len)
-		len = 1;
-
-	first = dma_region_find(dma, offset, 0, &rem);
-	last = dma_region_find(dma, rem + len - 1, first, &rem);
-
-	pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
-				   last - first + 1, dma->direction);
-}
-
-#ifdef CONFIG_MMU
-
-static int dma_region_pagefault(struct vm_area_struct *vma,
-				struct vm_fault *vmf)
-{
-	struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
-
-	if (!dma->kvirt)
-		return VM_FAULT_SIGBUS;
-
-	if (vmf->pgoff >= dma->n_pages)
-		return VM_FAULT_SIGBUS;
-
-	vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
-	get_page(vmf->page);
-	return 0;
-}
-
-static const struct vm_operations_struct dma_region_vm_ops = {
-	.fault = dma_region_pagefault,
-};
-
-/**
- * dma_region_mmap - map the buffer into a user space process
- */
-int dma_region_mmap(struct dma_region *dma, struct file *file,
-		    struct vm_area_struct *vma)
-{
-	unsigned long size;
-
-	if (!dma->kvirt)
-		return -EINVAL;
-
-	/* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
-	if (vma->vm_pgoff != 0)
-		return -EINVAL;
-
-	/* check the length */
-	size = vma->vm_end - vma->vm_start;
-	if (size > (dma->n_pages << PAGE_SHIFT))
-		return -EINVAL;
-
-	vma->vm_ops = &dma_region_vm_ops;
-	vma->vm_private_data = dma;
-	vma->vm_file = file;
-	vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
-
-	return 0;
-}
-
-#else				/* CONFIG_MMU */
-
-int dma_region_mmap(struct dma_region *dma, struct file *file,
-		    struct vm_area_struct *vma)
-{
-	return -EINVAL;
-}
-
-#endif				/* CONFIG_MMU */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/dma.h linux-libre-2.6.37-gnu/drivers/ieee1394/dma.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/dma.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/dma.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,89 +0,0 @@
-/*
- * DMA region bookkeeping routines
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_DMA_H
-#define IEEE1394_DMA_H
-
-#include <asm/types.h>
-
-struct file;
-struct pci_dev;
-struct scatterlist;
-struct vm_area_struct;
-
-/**
- * struct dma_prog_region - small contiguous DMA buffer
- * @kvirt:    kernel virtual address
- * @dev:      PCI device
- * @n_pages:  number of kernel pages
- * @bus_addr: base bus address
- *
- * a small, physically contiguous DMA buffer with random-access, synchronous
- * usage characteristics
- */
-struct dma_prog_region {
-	unsigned char *kvirt;
-	struct pci_dev *dev;
-	unsigned int n_pages;
-	dma_addr_t bus_addr;
-};
-
-/* clear out all fields but do not allocate any memory */
-void dma_prog_region_init(struct dma_prog_region *prog);
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
-			  struct pci_dev *dev);
-void dma_prog_region_free(struct dma_prog_region *prog);
-
-static inline dma_addr_t dma_prog_region_offset_to_bus(
-		struct dma_prog_region *prog, unsigned long offset)
-{
-	return prog->bus_addr + offset;
-}
-
-/**
- * struct dma_region - large non-contiguous DMA buffer
- * @virt:        kernel virtual address
- * @dev:         PCI device
- * @n_pages:     number of kernel pages
- * @n_dma_pages: number of IOMMU pages
- * @sglist:      IOMMU mapping
- * @direction:   PCI_DMA_TODEVICE, etc.
- *
- * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
- * usage characteristics
- */
-struct dma_region {
-	unsigned char *kvirt;
-	struct pci_dev *dev;
-	unsigned int n_pages;
-	unsigned int n_dma_pages;
-	struct scatterlist *sglist;
-	int direction;
-};
-
-void dma_region_init(struct dma_region *dma);
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
-		     struct pci_dev *dev, int direction);
-void dma_region_free(struct dma_region *dma);
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
-			     unsigned long len);
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
-				unsigned long len);
-int  dma_region_mmap(struct dma_region *dma, struct file *file,
-		     struct vm_area_struct *vma);
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
-				    unsigned long offset);
-
-/**
- * dma_region_i - macro to index into a DMA region (or dma_prog_region)
- */
-#define dma_region_i(_dma, _type, _index) \
-	( ((_type*) ((_dma)->kvirt)) + (_index) )
-
-#endif /* IEEE1394_DMA_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394.c linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,2584 +0,0 @@
-/*
- * dv1394.c - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *  video1394.c - video driver for OHCI 1394 boards
- *  Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
-  OVERVIEW
-
-  I designed dv1394 as a "pipe" that you can use to shoot DV onto a
-  FireWire bus. In transmission mode, dv1394 does the following:
-
-   1. accepts contiguous frames of DV data from user-space, via write()
-      or mmap() (see dv1394.h for the complete API)
-   2. wraps IEC 61883 packets around the DV data, inserting
-      empty synchronization packets as necessary
-   3. assigns accurate SYT timestamps to the outgoing packets
-   4. shoots them out using the OHCI card's IT DMA engine
-
-   Thanks to Dan Dennedy, we now have a receive mode that does the following:
-
-   1. accepts raw IEC 61883 packets from the OHCI card
-   2. re-assembles the DV data payloads into contiguous frames,
-      discarding empty packets
-   3. sends the DV data to user-space via read() or mmap()
-*/
-
-/*
-  TODO:
-
-  - tunable frame-drop behavior: either loop last frame, or halt transmission
-
-  - use a scatter/gather buffer for DMA programs (f->descriptor_pool)
-    so that we don't rely on allocating 64KB of contiguous kernel memory
-    via pci_alloc_consistent()
-
-  DONE:
-  - during reception, better handling of dropped frames and continuity errors
-  - during reception, prevent DMA from bypassing the irq tasklets
-  - reduce irq rate during reception (1/250 packets).
-  - add many more internal buffers during reception with scatter/gather dma.
-  - add dbc (continuity) checking on receive, increment status.dropped_frames
-    if not continuous.
-  - restart IT DMA after a bus reset
-  - safely obtain and release ISO Tx channels in cooperation with OHCI driver
-  - map received DIF blocks to their proper location in DV frame (ensure
-    recovery if dropped packet)
-  - handle bus resets gracefully (OHCI card seems to take care of this itself(!))
-  - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings
-  - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk
-  - added wmb() and mb() to places where PCI read/write ordering needs to be enforced
-  - set video->id correctly
-  - store video_cards in an array indexed by OHCI card ID, rather than a list
-  - implement DMA context allocation to cooperate with other users of the OHCI
-  - fix all XXX showstoppers
-  - disable IR/IT DMA interrupts on shutdown
-  - flush pci writes to the card by issuing a read
-  - character device dispatching
-  - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
-  - keep all video_cards in a list (for open() via chardev), set file->private_data = video
-  - dv1394_poll should indicate POLLIN when receiving buffers are available
-  - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal
-  - expose xmit and recv as separate devices (not exclusive)
-  - expose NTSC and PAL as separate devices (can be overridden)
-
-*/
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/string.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dv1394.h"
-#include "dv1394-private.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-
-/* DEBUG LEVELS:
-   0 - no debugging messages
-   1 - some debugging messages, but none during DMA frame transmission
-   2 - lots of messages, including during DMA frame transmission
-       (will cause underflows if your machine is too slow!)
-*/
-
-#define DV1394_DEBUG_LEVEL 0
-
-/* for debugging use ONLY: allow more than one open() of the device */
-/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
-
-#if DV1394_DEBUG_LEVEL >= 2
-#define irq_printk( args... ) printk( args )
-#else
-#define irq_printk( args... ) do {} while (0)
-#endif
-
-#if DV1394_DEBUG_LEVEL >= 1
-#define debug_printk( args... ) printk( args)
-#else
-#define debug_printk( args... ) do {} while (0)
-#endif
-
-/* issue a dummy PCI read to force the preceding write
-   to be posted to the PCI bus immediately */
-
-static inline void flush_pci_write(struct ti_ohci *ohci)
-{
-	mb();
-	reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void it_tasklet_func(unsigned long data);
-static void ir_tasklet_func(unsigned long data);
-
-#ifdef CONFIG_COMPAT
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
-			       unsigned long arg);
-#endif
-
-/* GLOBAL DATA */
-
-/* list of all video_cards */
-static LIST_HEAD(dv1394_cards);
-static DEFINE_SPINLOCK(dv1394_cards_lock);
-
-/* translate from a struct file* to the corresponding struct video_card* */
-
-static inline struct video_card* file_to_video_card(struct file *file)
-{
-	return file->private_data;
-}
-
-/*** FRAME METHODS *********************************************************/
-
-static void frame_reset(struct frame *f)
-{
-	f->state = FRAME_CLEAR;
-	f->done = 0;
-	f->n_packets = 0;
-	f->frame_begin_timestamp = NULL;
-	f->assigned_timestamp = 0;
-	f->cip_syt1 = NULL;
-	f->cip_syt2 = NULL;
-	f->mid_frame_timestamp = NULL;
-	f->frame_end_timestamp = NULL;
-	f->frame_end_branch = NULL;
-}
-
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video)
-{
-	struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL);
-	if (!f)
-		return NULL;
-
-	f->video = video;
-	f->frame_num = frame_num;
-
-	f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma);
-	if (!f->header_pool) {
-		printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n");
-		kfree(f);
-		return NULL;
-	}
-
-	debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
-		     (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE);
-
-	f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block);
-	/* make it an even # of pages */
-	f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE);
-
-	f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev,
-						  f->descriptor_pool_size,
-						  &f->descriptor_pool_dma);
-	if (!f->descriptor_pool) {
-		pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
-		kfree(f);
-		return NULL;
-	}
-
-	debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n",
-		     (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size);
-
-	f->data = 0;
-	frame_reset(f);
-
-	return f;
-}
-
-static void frame_delete(struct frame *f)
-{
-	pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma);
-	pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma);
-	kfree(f);
-}
-
-
-
-
-/*
-   frame_prepare() - build the DMA program for transmitting
-
-   Frame_prepare() must be called OUTSIDE the video->spinlock.
-   However, frame_prepare() must still be serialized, so
-   it should be called WITH the video->mtx taken.
- */
-
-static void frame_prepare(struct video_card *video, unsigned int this_frame)
-{
-	struct frame *f = video->frames[this_frame];
-	int last_frame;
-
-	struct DMA_descriptor_block *block;
-	dma_addr_t block_dma;
-	struct CIP_header *cip;
-	dma_addr_t cip_dma;
-
-	unsigned int n_descriptors, full_packets, packets_per_frame, payload_size;
-
-	/* these flags denote packets that need special attention */
-	int empty_packet, first_packet, last_packet, mid_packet;
-
-	__le32 *branch_address, *last_branch_address = NULL;
-	unsigned long data_p;
-	int first_packet_empty = 0;
-	u32 cycleTimer, ct_sec, ct_cyc, ct_off;
-	unsigned long irq_flags;
-
-	irq_printk("frame_prepare( %d ) ---------------------\n", this_frame);
-
-	full_packets = 0;
-
-
-
-	if (video->pal_or_ntsc == DV1394_PAL)
-		packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME;
-	else
-		packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME;
-
-	while ( full_packets < packets_per_frame ) {
-		empty_packet = first_packet = last_packet = mid_packet = 0;
-
-		data_p = f->data + full_packets * 480;
-
-		/************************************************/
-		/* allocate a descriptor block and a CIP header */
-		/************************************************/
-
-		/* note: these should NOT cross a page boundary (DMA restriction) */
-
-		if (f->n_packets >= MAX_PACKETS) {
-			printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n");
-			return;
-		}
-
-		/* the block surely won't cross a page boundary,
-		   since an even number of descriptor_blocks fit on a page */
-		block = &(f->descriptor_pool[f->n_packets]);
-
-		/* DMA address of the block = offset of block relative
-		    to the kernel base address of the descriptor pool
-		    + DMA base address of the descriptor pool */
-		block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-
-		/* the whole CIP pool fits on one page, so no worries about boundaries */
-		if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool)
-		    > PAGE_SIZE) {
-			printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n");
-			return;
-		}
-
-		cip = &(f->header_pool[f->n_packets]);
-
-		/* DMA address of the CIP header = offset of cip
-		   relative to kernel base address of the header pool
-		   + DMA base address of the header pool */
-		cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma;
-
-		/* is this an empty packet? */
-
-		if (video->cip_accum > (video->cip_d - video->cip_n)) {
-			empty_packet = 1;
-			payload_size = 8;
-			video->cip_accum -= (video->cip_d - video->cip_n);
-		} else {
-			payload_size = 488;
-			video->cip_accum += video->cip_n;
-		}
-
-		/* there are three important packets each frame:
-
-		   the first packet in the frame - we ask the card to record the timestamp when
-		                                   this packet is actually sent, so we can monitor
-						   how accurate our timestamps are. Also, the first
-						   packet serves as a semaphore to let us know that
-						   it's OK to free the *previous* frame's DMA buffer
-
-		   the last packet in the frame -  this packet is used to detect buffer underflows.
-		                                   if this is the last ready frame, the last DMA block
-						   will have a branch back to the beginning of the frame
-						   (so that the card will re-send the frame on underflow).
-						   if this branch gets taken, we know that at least one
-						   frame has been dropped. When the next frame is ready,
-						   the branch is pointed to its first packet, and the
-						   semaphore is disabled.
-
-		   a "mid" packet slightly before the end of the frame - this packet should trigger
-		                   an interrupt so we can go and assign a timestamp to the first packet
-				   in the next frame. We don't use the very last packet in the frame
-				   for this purpose, because that would leave very little time to set
-				   the timestamp before DMA starts on the next frame.
-		*/
-
-		if (f->n_packets == 0) {
-			first_packet = 1;
-		} else if ( full_packets == (packets_per_frame-1) ) {
-			last_packet = 1;
-		} else if (f->n_packets == packets_per_frame) {
-			mid_packet = 1;
-		}
-
-
-		/********************/
-		/* setup CIP header */
-		/********************/
-
-		/* the timestamp will be written later from the
-		   mid-frame interrupt handler. For now we just
-		   store the address of the CIP header(s) that
-		   need a timestamp. */
-
-		/* first packet in the frame needs a timestamp */
-		if (first_packet) {
-			f->cip_syt1 = cip;
-			if (empty_packet)
-				first_packet_empty = 1;
-
-		} else if (first_packet_empty && (f->n_packets == 1) ) {
-			/* if the first packet was empty, the second
-			   packet's CIP header also needs a timestamp */
-			f->cip_syt2 = cip;
-		}
-
-		fill_cip_header(cip,
-				/* the node ID number of the OHCI card */
-				reg_read(video->ohci, OHCI1394_NodeID) & 0x3F,
-				video->continuity_counter,
-				video->pal_or_ntsc,
-				0xFFFF /* the timestamp is filled in later */);
-
-		/* advance counter, only for full packets */
-		if ( ! empty_packet )
-			video->continuity_counter++;
-
-		/******************************/
-		/* setup DMA descriptor block */
-		/******************************/
-
-		/* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */
-		fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size);
-
-		if (empty_packet) {
-			/* second descriptor - OUTPUT_LAST for CIP header */
-			fill_output_last( &(block->u.out.u.empty.ol),
-
-					  /* want completion status on all interesting packets */
-					  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-					  /* want interrupts on all interesting packets */
-					  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-					  sizeof(struct CIP_header), /* data size */
-					  cip_dma);
-
-			if (first_packet)
-				f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]);
-			else if (mid_packet)
-				f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]);
-			else if (last_packet) {
-				f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]);
-				f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]);
-			}
-
-			branch_address = &(block->u.out.u.empty.ol.q[2]);
-			n_descriptors = 3;
-			if (first_packet)
-				f->first_n_descriptors = n_descriptors;
-
-		} else { /* full packet */
-
-			/* second descriptor - OUTPUT_MORE for CIP header */
-			fill_output_more( &(block->u.out.u.full.om),
-					  sizeof(struct CIP_header), /* data size */
-					  cip_dma);
-
-
-			/* third (and possibly fourth) descriptor - for DV data */
-			/* the 480-byte payload can cross a page boundary; if so,
-			   we need to split it into two DMA descriptors */
-
-			/* does the 480-byte data payload cross a page boundary? */
-			if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) {
-
-				/* page boundary crossed */
-
-				fill_output_more( &(block->u.out.u.full.u.cross.om),
-						  /* data size - how much of data_p fits on the first page */
-						  PAGE_SIZE - (data_p % PAGE_SIZE),
-
-						  /* DMA address of data_p */
-						  dma_region_offset_to_bus(&video->dv_buf,
-									   data_p - (unsigned long) video->dv_buf.kvirt));
-
-				fill_output_last( &(block->u.out.u.full.u.cross.ol),
-
-						  /* want completion status on all interesting packets */
-						  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-						  /* want interrupt on all interesting packets */
-						  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-						  /* data size - remaining portion of data_p */
-						  480 - (PAGE_SIZE - (data_p % PAGE_SIZE)),
-
-						  /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */
-						  dma_region_offset_to_bus(&video->dv_buf,
-									   data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt));
-
-				if (first_packet)
-					f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-				else if (mid_packet)
-					f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-				else if (last_packet) {
-					f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]);
-					f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]);
-				}
-
-				branch_address = &(block->u.out.u.full.u.cross.ol.q[2]);
-
-				n_descriptors = 5;
-				if (first_packet)
-					f->first_n_descriptors = n_descriptors;
-
-				full_packets++;
-
-			} else {
-				/* fits on one page */
-
-				fill_output_last( &(block->u.out.u.full.u.nocross.ol),
-
-						  /* want completion status on all interesting packets */
-						  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-						  /* want interrupt on all interesting packets */
-						  (first_packet || mid_packet || last_packet) ? 1 : 0,
-
-						  480, /* data size (480 bytes of DV data) */
-
-
-						  /* DMA address of data_p */
-						  dma_region_offset_to_bus(&video->dv_buf,
-									   data_p - (unsigned long) video->dv_buf.kvirt));
-
-				if (first_packet)
-					f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-				else if (mid_packet)
-					f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-				else if (last_packet) {
-					f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]);
-					f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]);
-				}
-
-				branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]);
-
-				n_descriptors = 4;
-				if (first_packet)
-					f->first_n_descriptors = n_descriptors;
-
-				full_packets++;
-			}
-		}
-
-		/* link this descriptor block into the DMA program by filling in
-		   the branch address of the previous block */
-
-		/* note: we are not linked into the active DMA chain yet */
-
-		if (last_branch_address) {
-			*(last_branch_address) = cpu_to_le32(block_dma | n_descriptors);
-		}
-
-		last_branch_address = branch_address;
-
-
-		f->n_packets++;
-
-	}
-
-	/* when we first assemble a new frame, set the final branch
-	   to loop back up to the top */
-	*(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
-	/* make the latest version of this frame visible to the PCI card */
-	dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size);
-
-	/* lock against DMA interrupt */
-	spin_lock_irqsave(&video->spinlock, irq_flags);
-
-	f->state = FRAME_READY;
-
-	video->n_clear_frames--;
-
-	last_frame = video->first_clear_frame - 1;
-	if (last_frame == -1)
-		last_frame = video->n_frames-1;
-
-	video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-
-	irq_printk("   frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n",
-		   this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame);
-
-	irq_printk("   begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n",
-		   (unsigned long) f->frame_begin_timestamp,
-		   (unsigned long) f->mid_frame_timestamp,
-		   (unsigned long) f->frame_end_timestamp,
-		   (unsigned long) f->frame_end_branch);
-
-	if (video->active_frame != -1) {
-
-		/* if DMA is already active, we are almost done */
-		/* just link us onto the active DMA chain */
-		if (video->frames[last_frame]->frame_end_branch) {
-			u32 temp;
-
-			/* point the previous frame's tail to this frame's head */
-			*(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors);
-
-			/* this write MUST precede the next one, or we could silently drop frames */
-			wmb();
-
-			/* disable the want_status semaphore on the last packet */
-			temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2));
-			temp &= 0xF7CFFFFF;
-			*(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp);
-
-			/* flush these writes to memory ASAP */
-			flush_pci_write(video->ohci);
-
-			/* NOTE:
-			   ideally the writes should be "atomic": if
-			   the OHCI card reads the want_status flag in
-			   between them, we'll falsely report a
-			   dropped frame. Hopefully this window is too
-			   small to really matter, and the consequence
-			   is rather harmless. */
-
-
-			irq_printk("     new frame %d linked onto DMA chain\n", this_frame);
-
-		} else {
-			printk(KERN_ERR "dv1394: last frame not ready???\n");
-		}
-
-	} else {
-
-		u32 transmit_sec, transmit_cyc;
-		u32 ts_cyc;
-
-		/* DMA is stopped, so this is the very first frame */
-		video->active_frame = this_frame;
-
-	        /* set CommandPtr to address and size of first descriptor block */
-		reg_write(video->ohci, video->ohci_IsoXmitCommandPtr,
-			  video->frames[video->active_frame]->descriptor_pool_dma |
-			  f->first_n_descriptors);
-
-		/* assign a timestamp based on the current cycle time...
-		   We'll tell the card to begin DMA 100 cycles from now,
-		   and assign a timestamp 103 cycles from now */
-
-		cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer);
-
-		ct_sec = cycleTimer >> 25;
-		ct_cyc = (cycleTimer >> 12) & 0x1FFF;
-		ct_off = cycleTimer & 0xFFF;
-
-		transmit_sec = ct_sec;
-		transmit_cyc = ct_cyc + 100;
-
-		transmit_sec += transmit_cyc/8000;
-		transmit_cyc %= 8000;
-
-		ts_cyc = transmit_cyc + 3;
-		ts_cyc %= 8000;
-
-		f->assigned_timestamp = (ts_cyc&0xF) << 12;
-
-		/* now actually write the timestamp into the appropriate CIP headers */
-		if (f->cip_syt1) {
-			f->cip_syt1->b[6] = f->assigned_timestamp >> 8;
-			f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF;
-		}
-		if (f->cip_syt2) {
-			f->cip_syt2->b[6] = f->assigned_timestamp >> 8;
-			f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF;
-		}
-
-		/* --- start DMA --- */
-
-		/* clear all bits in ContextControl register */
-
-		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF);
-		wmb();
-
-		/* the OHCI card has the ability to start ISO transmission on a
-		   particular cycle (start-on-cycle). This way we can ensure that
-		   the first DV frame will have an accurate timestamp.
-
-		   However, start-on-cycle only appears to work if the OHCI card
-		   is cycle master! Since the consequences of messing up the first
-		   timestamp are minimal*, just disable start-on-cycle for now.
-
-		   * my DV deck drops the first few frames before it "locks in;"
-		     so the first frame having an incorrect timestamp is inconsequential.
-		*/
-
-#if 0
-		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet,
-			  (1 << 31) /* enable start-on-cycle */
-			  | ( (transmit_sec & 0x3) << 29)
-			  | (transmit_cyc << 16));
-		wmb();
-#endif
-
-		video->dma_running = 1;
-
-		/* set the 'run' bit */
-		reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000);
-		flush_pci_write(video->ohci);
-
-		/* --- DMA should be running now --- */
-
-		debug_printk("    Cycle = %4u ContextControl = %08x CmdPtr = %08x\n",
-			     (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF,
-			     reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-			     reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-
-		debug_printk("    DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n",
-			     ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF);
-
-#if DV1394_DEBUG_LEVEL >= 2
-		{
-			/* check if DMA is really running */
-			int i = 0;
-			while (i < 20) {
-				mb();
-				mdelay(1);
-				if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) {
-					printk("DMA ACTIVE after %d msec\n", i);
-					break;
-				}
-				i++;
-			}
-
-			printk("set = %08x, cmdPtr = %08x\n",
-			       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-			       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
-			       );
-
-			if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) &  (1 << 10)) ) {
-				printk("DMA did NOT go active after 20ms, event = %x\n",
-				       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F);
-			} else
-				printk("DMA is RUNNING!\n");
-		}
-#endif
-
-	}
-
-
-	spin_unlock_irqrestore(&video->spinlock, irq_flags);
-}
-
-
-
-/*** RECEIVE FUNCTIONS *****************************************************/
-
-/*
-	frame method put_packet
-
-	map and copy the packet data to its location in the frame
-	based upon DIF section and sequence
-*/
-
-static void inline
-frame_put_packet (struct frame *f, struct packet *p)
-{
-	int section_type = p->data[0] >> 5;           /* section type is in bits 5 - 7 */
-	int dif_sequence = p->data[1] >> 4;           /* dif sequence number is in bits 4 - 7 */
-	int dif_block = p->data[2];
-
-	/* sanity check */
-	if (dif_sequence > 11 || dif_block > 149) return;
-
-	switch (section_type) {
-	case 0:           /* 1 Header block */
-	        memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480);
-	        break;
-
-	case 1:           /* 2 Subcode blocks */
-	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480);
-	        break;
-
-	case 2:           /* 3 VAUX blocks */
-	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480);
-	        break;
-
-	case 3:           /* 9 Audio blocks interleaved with video */
-	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480);
-	        break;
-
-	case 4:           /* 135 Video blocks interleaved with audio */
-	        memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480);
-	        break;
-
-	default:           /* we can not handle any other data */
-	        break;
-	}
-}
-
-
-static void start_dma_receive(struct video_card *video)
-{
-	if (video->first_run == 1) {
-		video->first_run = 0;
-
-		/* start DMA once all of the frames are READY */
-		video->n_clear_frames = 0;
-		video->first_clear_frame = -1;
-		video->current_packet = 0;
-		video->active_frame = 0;
-
-		/* reset iso recv control register */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF);
-		wmb();
-
-		/* clear bufferFill, set isochHeader and speed (0=100) */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000);
-
-		/* match on all tags, listen on channel */
-		reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel);
-
-		/* address and first descriptor block + Z=1 */
-		reg_write(video->ohci, video->ohci_IsoRcvCommandPtr,
-			  video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */
-		wmb();
-
-		video->dma_running = 1;
-
-		/* run */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000);
-		flush_pci_write(video->ohci);
-
-		debug_printk("dv1394: DMA started\n");
-
-#if DV1394_DEBUG_LEVEL >= 2
-		{
-			int i;
-
-			for (i = 0; i < 1000; ++i) {
-				mdelay(1);
-				if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) {
-					printk("DMA ACTIVE after %d msec\n", i);
-					break;
-				}
-			}
-			if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-				printk("DEAD, event = %x\n",
-					   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-			} else
-				printk("RUNNING!\n");
-		}
-#endif
-	} else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) &  (1 << 11) ) {
-		debug_printk("DEAD, event = %x\n",
-			     reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F);
-
-		/* wake */
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-	}
-}
-
-
-/*
-   receive_packets() - build the DMA program for receiving
-*/
-
-static void receive_packets(struct video_card *video)
-{
-	struct DMA_descriptor_block *block = NULL;
-	dma_addr_t block_dma = 0;
-	struct packet *data = NULL;
-	dma_addr_t data_dma = 0;
-	__le32 *last_branch_address = NULL;
-	unsigned long irq_flags;
-	int want_interrupt = 0;
-	struct frame *f = NULL;
-	int i, j;
-
-	spin_lock_irqsave(&video->spinlock, irq_flags);
-
-	for (j = 0; j < video->n_frames; j++) {
-
-		/* connect frames */
-		if (j > 0 && f != NULL && f->frame_end_branch != NULL)
-			*(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */
-
-		f = video->frames[j];
-
-		for (i = 0; i < MAX_PACKETS; i++) {
-			/* locate a descriptor block and packet from the buffer */
-			block = &(f->descriptor_pool[i]);
-			block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-
-			data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i;
-			data_dma = dma_region_offset_to_bus( &video->packet_buf,
-							     ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) );
-
-			/* setup DMA descriptor block */
-			want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1));
-			fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma);
-
-			/* link descriptors */
-			last_branch_address = f->frame_end_branch;
-
-			if (last_branch_address != NULL)
-				*(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */
-
-			f->frame_end_branch = &(block->u.in.il.q[2]);
-		}
-
-	} /* next j */
-
-	spin_unlock_irqrestore(&video->spinlock, irq_flags);
-
-}
-
-
-
-/*** MANAGEMENT FUNCTIONS **************************************************/
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init)
-{
-	unsigned long flags, new_buf_size;
-	int i;
-	u64 chan_mask;
-	int retval = -EINVAL;
-
-	debug_printk("dv1394: initialising %d\n", video->id);
-	if (init->api_version != DV1394_API_VERSION)
-		return -EINVAL;
-
-	/* first sanitize all the parameters */
-	if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) )
-		return -EINVAL;
-
-	if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) )
-		return -EINVAL;
-
-	if ( (init->syt_offset == 0) || (init->syt_offset > 50) )
-		/* default SYT offset is 3 cycles */
-		init->syt_offset = 3;
-
-	if (init->channel > 63)
-		init->channel = 63;
-
-	chan_mask = (u64)1 << init->channel;
-
-	/* calculate what size DMA buffer is needed */
-	if (init->format == DV1394_NTSC)
-		new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames;
-	else
-		new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames;
-
-	/* round up to PAGE_SIZE */
-	if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE);
-
-	/* don't allow the user to allocate the DMA buffer more than once */
-	if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) {
-		printk("dv1394: re-sizing the DMA buffer is not allowed\n");
-		return -EINVAL;
-	}
-
-	/* shutdown the card if it's currently active */
-	/* (the card should not be reset if the parameters are screwy) */
-
-	do_dv1394_shutdown(video, 0);
-
-	/* try to claim the ISO channel */
-	spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-	if (video->ohci->ISO_channel_usage & chan_mask) {
-		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-		retval = -EBUSY;
-		goto err;
-	}
-	video->ohci->ISO_channel_usage |= chan_mask;
-	spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
-	video->channel = init->channel;
-
-	/* initialize misc. fields of video */
-	video->n_frames = init->n_frames;
-	video->pal_or_ntsc = init->format;
-
-	video->cip_accum = 0;
-	video->continuity_counter = 0;
-
-	video->active_frame = -1;
-	video->first_clear_frame = 0;
-	video->n_clear_frames = video->n_frames;
-	video->dropped_frames = 0;
-
-	video->write_off = 0;
-
-	video->first_run = 1;
-	video->current_packet = -1;
-	video->first_frame = 0;
-
-	if (video->pal_or_ntsc == DV1394_NTSC) {
-		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC;
-		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC;
-		video->frame_size = DV1394_NTSC_FRAME_SIZE;
-	} else {
-		video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL;
-		video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL;
-		video->frame_size = DV1394_PAL_FRAME_SIZE;
-	}
-
-	video->syt_offset = init->syt_offset;
-
-	/* find and claim DMA contexts on the OHCI card */
-
-	if (video->ohci_it_ctx == -1) {
-		ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT,
-					  it_tasklet_func, (unsigned long) video);
-
-		if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) {
-			printk(KERN_ERR "dv1394: could not find an available IT DMA context\n");
-			retval = -EBUSY;
-			goto err;
-		}
-
-		video->ohci_it_ctx = video->it_tasklet.context;
-		debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx);
-	}
-
-	if (video->ohci_ir_ctx == -1) {
-		ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE,
-					  ir_tasklet_func, (unsigned long) video);
-
-		if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) {
-			printk(KERN_ERR "dv1394: could not find an available IR DMA context\n");
-			retval = -EBUSY;
-			goto err;
-		}
-		video->ohci_ir_ctx = video->ir_tasklet.context;
-		debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx);
-	}
-
-	/* allocate struct frames */
-	for (i = 0; i < init->n_frames; i++) {
-		video->frames[i] = frame_new(i, video);
-
-		if (!video->frames[i]) {
-			printk(KERN_ERR "dv1394: Cannot allocate frame structs\n");
-			retval = -ENOMEM;
-			goto err;
-		}
-	}
-
-	if (!video->dv_buf.kvirt) {
-		/* allocate the ringbuffer */
-		retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE);
-		if (retval)
-			goto err;
-
-		video->dv_buf_size = new_buf_size;
-
-		debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", 
-			     video->n_frames, video->dv_buf.n_pages,
-			     video->dv_buf.n_dma_pages, video->dv_buf_size);
-	}
-
-	/* set up the frame->data pointers */
-	for (i = 0; i < video->n_frames; i++)
-		video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size;
-
-	if (!video->packet_buf.kvirt) {
-		/* allocate packet buffer */
-		video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS;
-		if (video->packet_buf_size % PAGE_SIZE)
-			video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE);
-
-		retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size,
-					  video->ohci->dev, PCI_DMA_FROMDEVICE);
-		if (retval)
-			goto err;
-
-		debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n",
-				 video->n_frames*MAX_PACKETS, video->packet_buf.n_pages,
-				 video->packet_buf.n_dma_pages, video->packet_buf_size);
-	}
-
-	/* set up register offsets for IT context */
-	/* IT DMA context registers are spaced 16 bytes apart */
-	video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx;
-	video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx;
-	video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx;
-
-	/* enable interrupts for IT context */
-	reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx));
-	debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx);
-
-	/* set up register offsets for IR context */
-	/* IR DMA context registers are spaced 32 bytes apart */
-	video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx;
-	video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx;
-	video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx;
-	video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx;
-
-	/* enable interrupts for IR context */
-	reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) );
-	debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx);
-
-	return 0;
-
-err:
-	do_dv1394_shutdown(video, 1);
-	return retval;
-}
-
-/* if the user doesn't bother to call ioctl(INIT) before starting
-   mmap() or read()/write(), just give him some default values */
-
-static int do_dv1394_init_default(struct video_card *video)
-{
-	struct dv1394_init init;
-
-	init.api_version = DV1394_API_VERSION;
-	init.n_frames = DV1394_MAX_FRAMES / 4;
-	init.channel = video->channel;
-	init.format = video->pal_or_ntsc;
-	init.cip_n = video->cip_n;
-	init.cip_d = video->cip_d;
-	init.syt_offset = video->syt_offset;
-
-	return do_dv1394_init(video, &init);
-}
-
-/* do NOT call from interrupt context */
-static void stop_dma(struct video_card *video)
-{
-	unsigned long flags;
-	int i;
-
-	/* no interrupts */
-	spin_lock_irqsave(&video->spinlock, flags);
-
-	video->dma_running = 0;
-
-	if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) )
-		goto out;
-
-	/* stop DMA if in progress */
-	if ( (video->active_frame != -1) ||
-	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
-	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) &  (1 << 10)) ) {
-
-		/* clear the .run bits */
-		reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
-		reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
-		flush_pci_write(video->ohci);
-
-		video->active_frame = -1;
-		video->first_run = 1;
-
-		/* wait until DMA really stops */
-		i = 0;
-		while (i < 1000) {
-
-			/* wait 0.1 millisecond */
-			udelay(100);
-
-			if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) ||
-			    (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear)  & (1 << 10)) ) {
-				/* still active */
-				debug_printk("dv1394: stop_dma: DMA not stopped yet\n" );
-				mb();
-			} else {
-				debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10);
-				break;
-			}
-
-			i++;
-		}
-
-		if (i == 1000) {
-			printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10);
-		}
-	}
-	else
-		debug_printk("dv1394: stop_dma: already stopped.\n");
-
-out:
-	spin_unlock_irqrestore(&video->spinlock, flags);
-}
-
-
-
-static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf)
-{
-	int i;
-
-	debug_printk("dv1394: shutdown...\n");
-
-	/* stop DMA if in progress */
-	stop_dma(video);
-
-	/* release the DMA contexts */
-	if (video->ohci_it_ctx != -1) {
-		video->ohci_IsoXmitContextControlSet = 0;
-		video->ohci_IsoXmitContextControlClear = 0;
-		video->ohci_IsoXmitCommandPtr = 0;
-
-		/* disable interrupts for IT context */
-		reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx));
-
-		/* remove tasklet */
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet);
-		debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx);
-		video->ohci_it_ctx = -1;
-	}
-
-	if (video->ohci_ir_ctx != -1) {
-		video->ohci_IsoRcvContextControlSet = 0;
-		video->ohci_IsoRcvContextControlClear = 0;
-		video->ohci_IsoRcvCommandPtr = 0;
-		video->ohci_IsoRcvContextMatch = 0;
-
-		/* disable interrupts for IR context */
-		reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx));
-
-		/* remove tasklet */
-		ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet);
-		debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx);
-		video->ohci_ir_ctx = -1;
-	}
-
-	/* release the ISO channel */
-	if (video->channel != -1) {
-		u64 chan_mask;
-		unsigned long flags;
-
-		chan_mask = (u64)1 << video->channel;
-
-		spin_lock_irqsave(&video->ohci->IR_channel_lock, flags);
-		video->ohci->ISO_channel_usage &= ~(chan_mask);
-		spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags);
-
-		video->channel = -1;
-	}
-
-	/* free the frame structs */
-	for (i = 0; i < DV1394_MAX_FRAMES; i++) {
-		if (video->frames[i])
-			frame_delete(video->frames[i]);
-		video->frames[i] = NULL;
-	}
-
-	video->n_frames = 0;
-
-	/* we can't free the DMA buffer unless it is guaranteed that
-	   no more user-space mappings exist */
-
-	if (free_dv_buf) {
-		dma_region_free(&video->dv_buf);
-		video->dv_buf_size = 0;
-	}
-
-	/* free packet buffer */
-	dma_region_free(&video->packet_buf);
-	video->packet_buf_size = 0;
-
-	debug_printk("dv1394: shutdown OK\n");
-}
-
-/*
-       **********************************
-       *** MMAP() THEORY OF OPERATION ***
-       **********************************
-
-        The ringbuffer cannot be re-allocated or freed while
-        a user program maintains a mapping of it. (note that a mapping
-	can persist even after the device fd is closed!)
-
-	So, only let the user process allocate the DMA buffer once.
-	To resize or deallocate it, you must close the device file
-	and open it again.
-
-	Previously Dan M. hacked out a scheme that allowed the DMA
-	buffer to change by forcefully unmapping it from the user's
-	address space. It was prone to error because it's very hard to
-	track all the places the buffer could have been mapped (we
-	would have had to walk the vma list of every process in the
-	system to be sure we found all the mappings!). Instead, we
-	force the user to choose one buffer size and stick with
-	it. This small sacrifice is worth the huge reduction in
-	error-prone code in dv1394.
-*/
-
-static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct video_card *video = file_to_video_card(file);
-	int retval = -EINVAL;
-
-	/*
-	 * We cannot use the blocking variant mutex_lock here because .mmap
-	 * is called with mmap_sem held, while .ioctl, .read, .write acquire
-	 * video->mtx and subsequently call copy_to/from_user which will
-	 * grab mmap_sem in case of a page fault.
-	 */
-	if (!mutex_trylock(&video->mtx))
-		return -EAGAIN;
-
-	if ( ! video_card_initialized(video) ) {
-		retval = do_dv1394_init_default(video);
-		if (retval)
-			goto out;
-	}
-
-	retval = dma_region_mmap(&video->dv_buf, file, vma);
-out:
-	mutex_unlock(&video->mtx);
-	return retval;
-}
-
-/*** DEVICE FILE INTERFACE *************************************************/
-
-/* no need to serialize, multiple threads OK */
-static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct video_card *video = file_to_video_card(file);
-	unsigned int mask = 0;
-	unsigned long flags;
-
-	poll_wait(file, &video->waitq, wait);
-
-	spin_lock_irqsave(&video->spinlock, flags);
-	if ( video->n_frames == 0 ) {
-
-	} else if ( video->active_frame == -1 ) {
-		/* nothing going on */
-		mask |= POLLOUT;
-	} else {
-		/* any clear/ready buffers? */
-		if (video->n_clear_frames >0)
-			mask |= POLLOUT | POLLIN;
-	}
-	spin_unlock_irqrestore(&video->spinlock, flags);
-
-	return mask;
-}
-
-static int dv1394_fasync(int fd, struct file *file, int on)
-{
-	/* I just copied this code verbatim from Alan Cox's mouse driver example
-	   (Documentation/DocBook/) */
-
-	struct video_card *video = file_to_video_card(file);
-
-	return fasync_helper(fd, file, on, &video->fasync);
-}
-
-static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct video_card *video = file_to_video_card(file);
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	size_t cnt;
-	unsigned long flags;
-	int target_frame;
-
-	/* serialize this to prevent multi-threaded mayhem */
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&video->mtx))
-			return -EAGAIN;
-	} else {
-		if (mutex_lock_interruptible(&video->mtx))
-			return -ERESTARTSYS;
-	}
-
-	if ( !video_card_initialized(video) ) {
-		ret = do_dv1394_init_default(video);
-		if (ret) {
-			mutex_unlock(&video->mtx);
-			return ret;
-		}
-	}
-
-	ret = 0;
-	add_wait_queue(&video->waitq, &wait);
-
-	while (count > 0) {
-
-		/* must set TASK_INTERRUPTIBLE *before* checking for free
-		   buffers; otherwise we could miss a wakeup if the interrupt
-		   fires between the check and the schedule() */
-
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		spin_lock_irqsave(&video->spinlock, flags);
-
-		target_frame = video->first_clear_frame;
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
-
-		if (video->frames[target_frame]->state == FRAME_CLEAR) {
-
-			/* how much room is left in the target frame buffer */
-			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
-		} else {
-			/* buffer is already used */
-			cnt = 0;
-		}
-
-		if (cnt > count)
-			cnt = count;
-
-		if (cnt <= 0) {
-			/* no room left, gotta wait */
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-
-			schedule();
-
-			continue; /* start over from 'while(count > 0)...' */
-		}
-
-		if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-
-		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-
-		if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames))
-				frame_prepare(video, target_frame);
-	}
-
-	remove_wait_queue(&video->waitq, &wait);
-	set_current_state(TASK_RUNNING);
-	mutex_unlock(&video->mtx);
-	return ret;
-}
-
-
-static ssize_t dv1394_read(struct file *file,  char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct video_card *video = file_to_video_card(file);
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	size_t cnt;
-	unsigned long flags;
-	int target_frame;
-
-	/* serialize this to prevent multi-threaded mayhem */
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&video->mtx))
-			return -EAGAIN;
-	} else {
-		if (mutex_lock_interruptible(&video->mtx))
-			return -ERESTARTSYS;
-	}
-
-	if ( !video_card_initialized(video) ) {
-		ret = do_dv1394_init_default(video);
-		if (ret) {
-			mutex_unlock(&video->mtx);
-			return ret;
-		}
-		video->continuity_counter = -1;
-
-		receive_packets(video);
-
-		start_dma_receive(video);
-	}
-
-	ret = 0;
-	add_wait_queue(&video->waitq, &wait);
-
-	while (count > 0) {
-
-		/* must set TASK_INTERRUPTIBLE *before* checking for free
-		   buffers; otherwise we could miss a wakeup if the interrupt
-		   fires between the check and the schedule() */
-
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		spin_lock_irqsave(&video->spinlock, flags);
-
-		target_frame = video->first_clear_frame;
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
-
-		if (target_frame >= 0 &&
-			video->n_clear_frames > 0 &&
-			video->frames[target_frame]->state == FRAME_CLEAR) {
-
-			/* how much room is left in the target frame buffer */
-			cnt = video->frame_size - (video->write_off - target_frame * video->frame_size);
-
-		} else {
-			/* buffer is already used */
-			cnt = 0;
-		}
-
-		if (cnt > count)
-			cnt = count;
-
-		if (cnt <= 0) {
-			/* no room left, gotta wait */
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-
-			schedule();
-
-			continue; /* start over from 'while(count > 0)...' */
-		}
-
-		if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) {
-				if (!ret)
-					ret = -EFAULT;
-				break;
-		}
-
-		video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size);
-
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-
-		if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) {
-			spin_lock_irqsave(&video->spinlock, flags);
-			video->n_clear_frames--;
-			video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-			spin_unlock_irqrestore(&video->spinlock, flags);
-		}
-	}
-
-	remove_wait_queue(&video->waitq, &wait);
-	set_current_state(TASK_RUNNING);
-	mutex_unlock(&video->mtx);
-	return ret;
-}
-
-
-/*** DEVICE IOCTL INTERFACE ************************************************/
-
-static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct video_card *video = file_to_video_card(file);
-	unsigned long flags;
-	int ret = -EINVAL;
-	void __user *argp = (void __user *)arg;
-
-	DECLARE_WAITQUEUE(wait, current);
-
-	/* serialize this to prevent multi-threaded mayhem */
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&video->mtx))
-			return -EAGAIN;
-	} else {
-		if (mutex_lock_interruptible(&video->mtx))
-			return -ERESTARTSYS;
-	}
-
-	switch(cmd)
-	{
-	case DV1394_IOC_SUBMIT_FRAMES: {
-		unsigned int n_submit;
-
-		if ( !video_card_initialized(video) ) {
-			ret = do_dv1394_init_default(video);
-			if (ret)
-				goto out;
-		}
-
-		n_submit = (unsigned int) arg;
-
-		if (n_submit > video->n_frames) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		while (n_submit > 0) {
-
-			add_wait_queue(&video->waitq, &wait);
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			spin_lock_irqsave(&video->spinlock, flags);
-
-			/* wait until video->first_clear_frame is really CLEAR */
-			while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) {
-
-				spin_unlock_irqrestore(&video->spinlock, flags);
-
-				if (signal_pending(current)) {
-					remove_wait_queue(&video->waitq, &wait);
-					set_current_state(TASK_RUNNING);
-					ret = -EINTR;
-					goto out;
-				}
-
-				schedule();
-				set_current_state(TASK_INTERRUPTIBLE);
-
-				spin_lock_irqsave(&video->spinlock, flags);
-			}
-			spin_unlock_irqrestore(&video->spinlock, flags);
-
-			remove_wait_queue(&video->waitq, &wait);
-			set_current_state(TASK_RUNNING);
-
-			frame_prepare(video, video->first_clear_frame);
-
-			n_submit--;
-		}
-
-		ret = 0;
-		break;
-	}
-
-	case DV1394_IOC_WAIT_FRAMES: {
-		unsigned int n_wait;
-
-		if ( !video_card_initialized(video) ) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		n_wait = (unsigned int) arg;
-
-		/* since we re-run the last frame on underflow, we will
-		   never actually have n_frames clear frames; at most only
-		   n_frames - 1 */
-
-		if (n_wait > (video->n_frames-1) ) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		add_wait_queue(&video->waitq, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-
-		spin_lock_irqsave(&video->spinlock, flags);
-
-		while (video->n_clear_frames < n_wait) {
-
-			spin_unlock_irqrestore(&video->spinlock, flags);
-
-			if (signal_pending(current)) {
-				remove_wait_queue(&video->waitq, &wait);
-				set_current_state(TASK_RUNNING);
-				ret = -EINTR;
-				goto out;
-			}
-
-			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
-
-			spin_lock_irqsave(&video->spinlock, flags);
-		}
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
-
-		remove_wait_queue(&video->waitq, &wait);
-		set_current_state(TASK_RUNNING);
-		ret = 0;
-		break;
-	}
-
-	case DV1394_IOC_RECEIVE_FRAMES: {
-		unsigned int n_recv;
-
-		if ( !video_card_initialized(video) ) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		n_recv = (unsigned int) arg;
-
-		/* at least one frame must be active */
-		if (n_recv > (video->n_frames-1) ) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		spin_lock_irqsave(&video->spinlock, flags);
-
-		/* release the clear frames */
-		video->n_clear_frames -= n_recv;
-
-		/* advance the clear frame cursor */
-		video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames;
-
-		/* reset dropped_frames */
-		video->dropped_frames = 0;
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
-
-		ret = 0;
-		break;
-	}
-
-	case DV1394_IOC_START_RECEIVE: {
-		if ( !video_card_initialized(video) ) {
-			ret = do_dv1394_init_default(video);
-			if (ret)
-				goto out;
-		}
-
-		video->continuity_counter = -1;
-
-		receive_packets(video);
-
-		start_dma_receive(video);
-
-		ret = 0;
-		break;
-	}
-
-	case DV1394_IOC_INIT: {
-		struct dv1394_init init;
-		if (!argp) {
-			ret = do_dv1394_init_default(video);
-		} else {
-			if (copy_from_user(&init, argp, sizeof(init))) {
-				ret = -EFAULT;
-				goto out;
-			}
-			ret = do_dv1394_init(video, &init);
-		}
-		break;
-	}
-
-	case DV1394_IOC_SHUTDOWN:
-		do_dv1394_shutdown(video, 0);
-		ret = 0;
-		break;
-
-
-        case DV1394_IOC_GET_STATUS: {
-		struct dv1394_status status;
-
-		if ( !video_card_initialized(video) ) {
-			ret = -EINVAL;
-			goto out;
-		}
-
-		status.init.api_version = DV1394_API_VERSION;
-		status.init.channel = video->channel;
-		status.init.n_frames = video->n_frames;
-		status.init.format = video->pal_or_ntsc;
-		status.init.cip_n = video->cip_n;
-		status.init.cip_d = video->cip_d;
-		status.init.syt_offset = video->syt_offset;
-
-		status.first_clear_frame = video->first_clear_frame;
-
-		/* the rest of the fields need to be locked against the interrupt */
-		spin_lock_irqsave(&video->spinlock, flags);
-
-		status.active_frame = video->active_frame;
-		status.n_clear_frames = video->n_clear_frames;
-
-		status.dropped_frames = video->dropped_frames;
-
-		/* reset dropped_frames */
-		video->dropped_frames = 0;
-
-		spin_unlock_irqrestore(&video->spinlock, flags);
-
-		if (copy_to_user(argp, &status, sizeof(status))) {
-			ret = -EFAULT;
-			goto out;
-		}
-
-		ret = 0;
-		break;
-	}
-
-	default:
-		break;
-	}
-
- out:
-	mutex_unlock(&video->mtx);
-	return ret;
-}
-
-/*** DEVICE FILE INTERFACE CONTINUED ***************************************/
-
-static int dv1394_open(struct inode *inode, struct file *file)
-{
-	struct video_card *video = NULL;
-
-	if (file->private_data) {
-		video = file->private_data;
-
-	} else {
-		/* look up the card by ID */
-		unsigned long flags;
-		int idx = ieee1394_file_to_instance(file);
-
-		spin_lock_irqsave(&dv1394_cards_lock, flags);
-		if (!list_empty(&dv1394_cards)) {
-			struct video_card *p;
-			list_for_each_entry(p, &dv1394_cards, list) {
-				if ((p->id) == idx) {
-					video = p;
-					break;
-				}
-			}
-		}
-		spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-		if (!video) {
-			debug_printk("dv1394: OHCI card %d not found", idx);
-			return -ENODEV;
-		}
-
-		file->private_data = (void*) video;
-	}
-
-#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN
-
-	if ( test_and_set_bit(0, &video->open) ) {
-		/* video is already open by someone else */
-		return -EBUSY;
- 	}
-
-#endif
-
-	printk(KERN_INFO "%s: NOTE, the dv1394 interface is unsupported "
-	       "and will not be available in the new firewire driver stack. "
-	       "Try libraw1394 based programs instead.\n", current->comm);
-
-	return nonseekable_open(inode, file);
-}
-
-
-static int dv1394_release(struct inode *inode, struct file *file)
-{
-	struct video_card *video = file_to_video_card(file);
-
-	/* OK to free the DMA buffer, no more mappings can exist */
-	do_dv1394_shutdown(video, 1);
-
-	/* give someone else a turn */
-	clear_bit(0, &video->open);
-
-	return 0;
-}
-
-
-/*** DEVICE DRIVER HANDLERS ************************************************/
-
-static void it_tasklet_func(unsigned long data)
-{
-	int wake = 0;
-	struct video_card *video = (struct video_card*) data;
-
-	spin_lock(&video->spinlock);
-
-	if (!video->dma_running)
-		goto out;
-
-	irq_printk("ContextControl = %08x, CommandPtr = %08x\n",
-	       reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-	       reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)
-	       );
-
-
-	if ( (video->ohci_it_ctx != -1) &&
-	    (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) {
-
-		struct frame *f;
-		unsigned int frame, i;
-
-
-		if (video->active_frame == -1)
-			frame = 0;
-		else
-			frame = video->active_frame;
-
-		/* check all the DMA-able frames */
-		for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) {
-
-			irq_printk("IRQ checking frame %d...", frame);
-			f = video->frames[frame];
-			if (f->state != FRAME_READY) {
-				irq_printk("clear, skipping\n");
-				/* we don't own this frame */
-				continue;
-			}
-
-			irq_printk("DMA\n");
-
-			/* check the frame begin semaphore to see if we can free the previous frame */
-			if ( *(f->frame_begin_timestamp) ) {
-				int prev_frame;
-				struct frame *prev_f;
-
-
-
-				/* don't reset, need this later *(f->frame_begin_timestamp) = 0; */
-				irq_printk("  BEGIN\n");
-
-				prev_frame = frame - 1;
-				if (prev_frame == -1)
-					prev_frame += video->n_frames;
-				prev_f = video->frames[prev_frame];
-
-				/* make sure we can actually garbage collect
-				   this frame */
-				if ( (prev_f->state == FRAME_READY) &&
-				    prev_f->done && (!f->done) )
-				{
-					frame_reset(prev_f);
-					video->n_clear_frames++;
-					wake = 1;
-					video->active_frame = frame;
-
-					irq_printk("  BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame);
-				} else {
-					irq_printk("  BEGIN - can't free yet\n");
-				}
-
-				f->done = 1;
-			}
-
-
-			/* see if we need to set the timestamp for the next frame */
-			if ( *(f->mid_frame_timestamp) ) {
-				struct frame *next_frame;
-				u32 begin_ts, ts_cyc, ts_off;
-
-				*(f->mid_frame_timestamp) = 0;
-
-				begin_ts = le32_to_cpu(*(f->frame_begin_timestamp));
-
-				irq_printk("  MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n",
-					   begin_ts & 0x1FFF, begin_ts & 0xF,
-					   f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF);
-
-				/* prepare next frame and assign timestamp */
-				next_frame = video->frames[ (frame+1) % video->n_frames ];
-
-				if (next_frame->state == FRAME_READY) {
-					irq_printk("  MIDDLE - next frame is ready, good\n");
-				} else {
-					debug_printk("dv1394: Underflow! At least one frame has been dropped.\n");
-					next_frame = f;
-				}
-
-				/* set the timestamp to the timestamp of the last frame sent,
-				   plus the length of the last frame sent, plus the syt latency */
-				ts_cyc = begin_ts & 0xF;
-				/* advance one frame, plus syt latency (typically 2-3) */
-				ts_cyc += f->n_packets + video->syt_offset ;
-
-				ts_off = 0;
-
-				ts_cyc += ts_off/3072;
-				ts_off %= 3072;
-
-				next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off;
-				if (next_frame->cip_syt1) {
-					next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8;
-					next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF;
-				}
-				if (next_frame->cip_syt2) {
-					next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8;
-					next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF;
-				}
-
-			}
-
-			/* see if the frame looped */
-			if ( *(f->frame_end_timestamp) ) {
-
-				*(f->frame_end_timestamp) = 0;
-
-				debug_printk("  END - the frame looped at least once\n");
-
-				video->dropped_frames++;
-			}
-
-		} /* for (each frame) */
-	}
-
-	if (wake) {
-		kill_fasync(&video->fasync, SIGIO, POLL_OUT);
-
-		/* wake readers/writers/ioctl'ers */
-		wake_up_interruptible(&video->waitq);
-	}
-
-out:
-	spin_unlock(&video->spinlock);
-}
-
-static void ir_tasklet_func(unsigned long data)
-{
-	int wake = 0;
-	struct video_card *video = (struct video_card*) data;
-
-	spin_lock(&video->spinlock);
-
-	if (!video->dma_running)
-		goto out;
-
-	if ( (video->ohci_ir_ctx != -1) &&
-	    (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) {
-
-		int sof=0; /* start-of-frame flag */
-		struct frame *f;
-		u16 packet_length;
-		int i, dbc=0;
-		struct DMA_descriptor_block *block = NULL;
-		u16 xferstatus;
-
-		int next_i, prev_i;
-		struct DMA_descriptor_block *next = NULL;
-		dma_addr_t next_dma = 0;
-		struct DMA_descriptor_block *prev = NULL;
-
-		/* loop over all descriptors in all frames */
-		for (i = 0; i < video->n_frames*MAX_PACKETS; i++) {
-			struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet);
-
-			/* make sure we are seeing the latest changes to p */
-			dma_region_sync_for_cpu(&video->packet_buf,
-						(unsigned long) p - (unsigned long) video->packet_buf.kvirt,
-						sizeof(struct packet));
-
-			packet_length = le16_to_cpu(p->data_length);
-
-			/* get the descriptor based on packet_buffer cursor */
-			f = video->frames[video->current_packet / MAX_PACKETS];
-			block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]);
-			xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16;
-			xferstatus &= 0x1F;
-			irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) );
-
-			/* get the current frame */
-			f = video->frames[video->active_frame];
-
-			/* exclude empty packet */
-			if (packet_length > 8 && xferstatus == 0x11) {
-				/* check for start of frame */
-				/* DRD> Changed to check section type ([0]>>5==0)
-				   and dif sequence ([1]>>4==0) */
-				sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0);
-
-				dbc = (int) (p->cip_h1 >> 24);
-				if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) )
-				{
-					printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" );
-					video->dropped_frames += video->n_clear_frames + 1;
-					video->first_frame = 0;
-					video->n_clear_frames = 0;
-					video->first_clear_frame = -1;
-				}
-				video->continuity_counter = dbc;
-
-				if (!video->first_frame) {
-					if (sof) {
-						video->first_frame = 1;
-					}
-
-				} else if (sof) {
-					/* close current frame */
-					frame_reset(f);  /* f->state = STATE_CLEAR */
-					video->n_clear_frames++;
-					if (video->n_clear_frames > video->n_frames) {
-						video->dropped_frames++;
-						printk(KERN_WARNING "dv1394: dropped a frame during reception\n" );
-						video->n_clear_frames = video->n_frames-1;
-						video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames;
-					}
-					if (video->first_clear_frame == -1)
-						video->first_clear_frame = video->active_frame;
-
-					/* get the next frame */
-					video->active_frame = (video->active_frame + 1) % video->n_frames;
-					f = video->frames[video->active_frame];
-					irq_printk("   frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n",
-						   video->active_frame, video->n_clear_frames, video->first_clear_frame);
-				}
-				if (video->first_frame) {
-					if (sof) {
-						/* open next frame */
-						f->state = FRAME_READY;
-					}
-
-					/* copy to buffer */
-					if (f->n_packets > (video->frame_size / 480)) {
-						printk(KERN_ERR "frame buffer overflow during receive\n");
-					}
-
-					frame_put_packet(f, p);
-
-				} /* first_frame */
-			}
-
-			/* stop, end of ready packets */
-			else if (xferstatus == 0) {
-				break;
-			}
-
-			/* reset xferStatus & resCount */
-			block->u.in.il.q[3] = cpu_to_le32(512);
-
-			/* terminate dma chain at this (next) packet */
-			next_i = video->current_packet;
-			f = video->frames[next_i / MAX_PACKETS];
-			next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
-			next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
-			next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
-			next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */
-
-			/* link previous to next */
-			prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
-			f = video->frames[prev_i / MAX_PACKETS];
-			prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
-			if (prev_i % (MAX_PACKETS/2)) {
-				prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */
-			} else {
-				prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
-			}
-			prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
-			wmb();
-
-			/* wake up DMA in case it fell asleep */
-			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-
-			/* advance packet_buffer cursor */
-			video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames);
-
-		} /* for all packets */
-
-		wake = 1; /* why the hell not? */
-
-	} /* receive interrupt */
-
-	if (wake) {
-		kill_fasync(&video->fasync, SIGIO, POLL_IN);
-
-		/* wake readers/writers/ioctl'ers */
-		wake_up_interruptible(&video->waitq);
-	}
-
-out:
-	spin_unlock(&video->spinlock);
-}
-
-static struct cdev dv1394_cdev;
-static const struct file_operations dv1394_fops=
-{
-	.owner =	THIS_MODULE,
-	.poll =		dv1394_poll,
-	.unlocked_ioctl = dv1394_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = dv1394_compat_ioctl,
-#endif
-	.mmap =		dv1394_mmap,
-	.open =		dv1394_open,
-	.write =	dv1394_write,
-	.read =		dv1394_read,
-	.release =	dv1394_release,
-	.fasync =	dv1394_fasync,
-	.llseek =	no_llseek,
-};
-
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id dv1394_id_table[] = {
-	{
-		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-		.specifier_id	= AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
-		.version	= AVC_SW_VERSION_ENTRY & 0xffffff
-	},
-	{ }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver dv1394_driver = {
-	.name = "dv1394",
-};
-
-
-/*** IEEE1394 HPSB CALLBACKS ***********************************************/
-
-static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
-{
-	struct video_card *video;
-	unsigned long flags;
-	int i;
-
-	video = kzalloc(sizeof(*video), GFP_KERNEL);
-	if (!video) {
-		printk(KERN_ERR "dv1394: cannot allocate video_card\n");
-		return -1;
-	}
-
-	video->ohci = ohci;
-	/* lower 2 bits of id indicate which of four "plugs"
-	   per host */
-	video->id = ohci->host->id << 2;
-	if (format == DV1394_NTSC)
-		video->id |= mode;
-	else
-		video->id |= 2 + mode;
-
-	video->ohci_it_ctx = -1;
-	video->ohci_ir_ctx = -1;
-
-	video->ohci_IsoXmitContextControlSet = 0;
-	video->ohci_IsoXmitContextControlClear = 0;
-	video->ohci_IsoXmitCommandPtr = 0;
-
-	video->ohci_IsoRcvContextControlSet = 0;
-	video->ohci_IsoRcvContextControlClear = 0;
-	video->ohci_IsoRcvCommandPtr = 0;
-	video->ohci_IsoRcvContextMatch = 0;
-
-	video->n_frames = 0; /* flag that video is not initialized */
-	video->channel = 63; /* default to broadcast channel */
-	video->active_frame = -1;
-
-	/* initialize the following */
-	video->pal_or_ntsc = format;
-	video->cip_n = 0; /* 0 = use builtin default */
-	video->cip_d = 0;
-	video->syt_offset = 0;
-	video->mode = mode;
-
-	for (i = 0; i < DV1394_MAX_FRAMES; i++)
-		video->frames[i] = NULL;
-
-	dma_region_init(&video->dv_buf);
-	video->dv_buf_size = 0;
-	dma_region_init(&video->packet_buf);
-	video->packet_buf_size = 0;
-
-	clear_bit(0, &video->open);
-	spin_lock_init(&video->spinlock);
-	video->dma_running = 0;
-	mutex_init(&video->mtx);
-	init_waitqueue_head(&video->waitq);
-	video->fasync = NULL;
-
-	spin_lock_irqsave(&dv1394_cards_lock, flags);
-	INIT_LIST_HEAD(&video->list);
-	list_add_tail(&video->list, &dv1394_cards);
-	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-	debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
-	return 0;
-}
-
-static void dv1394_remove_host(struct hpsb_host *host)
-{
-	struct video_card *video, *tmp_video;
-	unsigned long flags;
-	int found_ohci_card = 0;
-
-	do {
-		video = NULL;
-		spin_lock_irqsave(&dv1394_cards_lock, flags);
-		list_for_each_entry(tmp_video, &dv1394_cards, list) {
-			if ((tmp_video->id >> 2) == host->id) {
-				list_del(&tmp_video->list);
-				video = tmp_video;
-				found_ohci_card = 1;
-				break;
-			}
-		}
-		spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-		if (video) {
-			do_dv1394_shutdown(video, 1);
-			kfree(video);
-		}
-	} while (video);
-
-	if (found_ohci_card)
-		device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
-			   IEEE1394_MINOR_BLOCK_DV1394 * 16 + (host->id << 2)));
-}
-
-static void dv1394_add_host(struct hpsb_host *host)
-{
-	struct ti_ohci *ohci;
-	int id = host->id;
-
-	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-		return;
-
-	ohci = (struct ti_ohci *)host->hostdata;
-
-	device_create(hpsb_protocol_class, NULL,
-		      MKDEV(IEEE1394_MAJOR,
-			    IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
-		      NULL, "dv1394-%d", id);
-
-	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
-	dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
-	dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE);
-	dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT);
-}
-
-
-/* Bus reset handler. In the event of a bus reset, we may need to
-   re-start the DMA contexts - otherwise the user program would
-   end up waiting forever.
-*/
-
-static void dv1394_host_reset(struct hpsb_host *host)
-{
-	struct video_card *video = NULL, *tmp_vid;
-	unsigned long flags;
-
-	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-		return;
-
-	/* find the corresponding video_cards */
-	spin_lock_irqsave(&dv1394_cards_lock, flags);
-	list_for_each_entry(tmp_vid, &dv1394_cards, list) {
-		if ((tmp_vid->id >> 2) == host->id) {
-			video = tmp_vid;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
-
-	if (!video)
-		return;
-
-
-	spin_lock_irqsave(&video->spinlock, flags);
-
-	if (!video->dma_running)
-		goto out;
-
-	/* check IT context */
-	if (video->ohci_it_ctx != -1) {
-		u32 ctx;
-
-		ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet);
-
-		/* if (RUN but not ACTIVE) */
-		if ( (ctx & (1<<15)) &&
-		    !(ctx & (1<<10)) ) {
-
-			debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n");
-
-			/* to be safe, assume a frame has been dropped. User-space programs
-			   should handle this condition like an underflow. */
-			video->dropped_frames++;
-
-			/* for some reason you must clear, then re-set the RUN bit to restart DMA */
-
-			/* clear RUN */
-			reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15));
-			flush_pci_write(video->ohci);
-
-			/* set RUN */
-			reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15));
-			flush_pci_write(video->ohci);
-
-			/* set the WAKE bit (just in case; this isn't strictly necessary) */
-			reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12));
-			flush_pci_write(video->ohci);
-
-			irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n",
-				   reg_read(video->ohci, video->ohci_IsoXmitContextControlSet),
-				   reg_read(video->ohci, video->ohci_IsoXmitCommandPtr));
-		}
-	}
-
-	/* check IR context */
-	if (video->ohci_ir_ctx != -1) {
-		u32 ctx;
-
-		ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet);
-
-		/* if (RUN but not ACTIVE) */
-		if ( (ctx & (1<<15)) &&
-		    !(ctx & (1<<10)) ) {
-
-			debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n");
-
-			/* to be safe, assume a frame has been dropped. User-space programs
-			   should handle this condition like an overflow. */
-			video->dropped_frames++;
-
-			/* for some reason you must clear, then re-set the RUN bit to restart DMA */
-			/* XXX this doesn't work for me, I can't get IR DMA to restart :[ */
-
-			/* clear RUN */
-			reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15));
-			flush_pci_write(video->ohci);
-
-			/* set RUN */
-			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15));
-			flush_pci_write(video->ohci);
-
-			/* set the WAKE bit (just in case; this isn't strictly necessary) */
-			reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12));
-			flush_pci_write(video->ohci);
-
-			irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n",
-				   reg_read(video->ohci, video->ohci_IsoRcvContextControlSet),
-				   reg_read(video->ohci, video->ohci_IsoRcvCommandPtr));
-		}
-	}
-
-out:
-	spin_unlock_irqrestore(&video->spinlock, flags);
-
-	/* wake readers/writers/ioctl'ers */
-	wake_up_interruptible(&video->waitq);
-}
-
-static struct hpsb_highlevel dv1394_highlevel = {
-	.name =		"dv1394",
-	.add_host =	dv1394_add_host,
-	.remove_host =	dv1394_remove_host,
-	.host_reset =   dv1394_host_reset,
-};
-
-#ifdef CONFIG_COMPAT
-
-#define DV1394_IOC32_INIT       _IOW('#', 0x06, struct dv1394_init32)
-#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32)
-
-struct dv1394_init32 {
-	u32 api_version;
-	u32 channel;
-	u32 n_frames;
-	u32 format;
-	u32 cip_n;
-	u32 cip_d;
-	u32 syt_offset;
-};
-
-struct dv1394_status32 {
-	struct dv1394_init32 init;
-	s32 active_frame;
-	u32 first_clear_frame;
-	u32 n_clear_frames;
-	u32 dropped_frames;
-};
-
-/* RED-PEN: this should use compat_alloc_userspace instead */
-
-static int handle_dv1394_init(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct dv1394_init32 dv32;
-	struct dv1394_init dv;
-	mm_segment_t old_fs;
-	int ret;
-
-	if (file->f_op->unlocked_ioctl != dv1394_ioctl)
-		return -EFAULT;
-
-	if (copy_from_user(&dv32, (void __user *)arg, sizeof(dv32)))
-		return -EFAULT;
-
-	dv.api_version = dv32.api_version;
-	dv.channel = dv32.channel;
-	dv.n_frames = dv32.n_frames;
-	dv.format = dv32.format;
-	dv.cip_n = (unsigned long)dv32.cip_n;
-	dv.cip_d = (unsigned long)dv32.cip_d;
-	dv.syt_offset = dv32.syt_offset;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = dv1394_ioctl(file, DV1394_IOC_INIT, (unsigned long)&dv);
-	set_fs(old_fs);
-
-	return ret;
-}
-
-static int handle_dv1394_get_status(struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct dv1394_status32 dv32;
-	struct dv1394_status dv;
-	mm_segment_t old_fs;
-	int ret;
-
-	if (file->f_op->unlocked_ioctl != dv1394_ioctl)
-		return -EFAULT;
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = dv1394_ioctl(file, DV1394_IOC_GET_STATUS, (unsigned long)&dv);
-	set_fs(old_fs);
-
-	if (!ret) {
-		dv32.init.api_version = dv.init.api_version;
-		dv32.init.channel = dv.init.channel;
-		dv32.init.n_frames = dv.init.n_frames;
-		dv32.init.format = dv.init.format;
-		dv32.init.cip_n = (u32)dv.init.cip_n;
-		dv32.init.cip_d = (u32)dv.init.cip_d;
-		dv32.init.syt_offset = dv.init.syt_offset;
-		dv32.active_frame = dv.active_frame;
-		dv32.first_clear_frame = dv.first_clear_frame;
-		dv32.n_clear_frames = dv.n_clear_frames;
-		dv32.dropped_frames = dv.dropped_frames;
-
-		if (copy_to_user((struct dv1394_status32 __user *)arg, &dv32, sizeof(dv32)))
-			ret = -EFAULT;
-	}
-
-	return ret;
-}
-
-
-
-static long dv1394_compat_ioctl(struct file *file, unsigned int cmd,
-			       unsigned long arg)
-{
-	switch (cmd) {
-	case DV1394_IOC_SHUTDOWN:
-	case DV1394_IOC_SUBMIT_FRAMES:
-	case DV1394_IOC_WAIT_FRAMES:
-	case DV1394_IOC_RECEIVE_FRAMES:
-	case DV1394_IOC_START_RECEIVE:
-		return dv1394_ioctl(file, cmd, arg);
-
-	case DV1394_IOC32_INIT:
-		return handle_dv1394_init(file, cmd, arg);
-	case DV1394_IOC32_GET_STATUS:
-		return handle_dv1394_get_status(file, cmd, arg);
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
-#endif /* CONFIG_COMPAT */
-
-
-/*** KERNEL MODULE HANDLERS ************************************************/
-
-MODULE_AUTHOR("Dan Maas <dmaas@dcine.com>, Dan Dennedy <dan@dennedy.org>");
-MODULE_DESCRIPTION("driver for DV input/output on OHCI board");
-MODULE_SUPPORTED_DEVICE("dv1394");
-MODULE_LICENSE("GPL");
-
-static void __exit dv1394_exit_module(void)
-{
-	hpsb_unregister_protocol(&dv1394_driver);
-	hpsb_unregister_highlevel(&dv1394_highlevel);
-	cdev_del(&dv1394_cdev);
-}
-
-static int __init dv1394_init_module(void)
-{
-	int ret;
-
-	cdev_init(&dv1394_cdev, &dv1394_fops);
-	dv1394_cdev.owner = THIS_MODULE;
-	ret = cdev_add(&dv1394_cdev, IEEE1394_DV1394_DEV, 16);
-	if (ret) {
-		printk(KERN_ERR "dv1394: unable to register character device\n");
-		return ret;
-	}
-
-	hpsb_register_highlevel(&dv1394_highlevel);
-
-	ret = hpsb_register_protocol(&dv1394_driver);
-	if (ret) {
-		printk(KERN_ERR "dv1394: failed to register protocol\n");
-		hpsb_unregister_highlevel(&dv1394_highlevel);
-		cdev_del(&dv1394_cdev);
-		return ret;
-	}
-
-	return 0;
-}
-
-module_init(dv1394_init_module);
-module_exit(dv1394_exit_module);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,305 +0,0 @@
-/*
- * dv1394.h - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *   video1394.h - driver for OHCI 1394 boards
- *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_H
-#define _DV_1394_H
-
-/* This is the public user-space interface. Try not to break it. */
-
-#define DV1394_API_VERSION 0x20011127
-
-/* ********************
-   **                **
-   **   DV1394 API   **
-   **                **
-   ********************
-
-   There are two methods of operating the DV1394 DV output device.
-
-   1)
-
-   The simplest is an interface based on write(): simply write
-   full DV frames of data to the device, and they will be transmitted
-   as quickly as possible. The FD may be set for non-blocking I/O,
-   in which case you can use select() or poll() to wait for output
-   buffer space.
-
-   To set the DV output parameters (e.g. whether you want NTSC or PAL
-   video), use the DV1394_INIT ioctl, passing in the parameters you
-   want in a struct dv1394_init.
-
-   Example 1:
-         To play a raw .DV file:   cat foo.DV > /dev/dv1394
-	 (cat will use write() internally)
-
-   Example 2:
-           static struct dv1394_init init = {
-	      0x63,        (broadcast channel)
-              4,           (four-frame ringbuffer)
-	      DV1394_NTSC, (send NTSC video)
-	      0, 0         (default empty packet rate)
-           }
-
-	   ioctl(fd, DV1394_INIT, &init);
-
-	   while (1) {
-	          read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
-		  write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
-           }
-
-   2)
-
-   For more control over buffering, and to avoid unnecessary copies
-   of the DV data, you can use the more sophisticated the mmap() interface.
-   First, call the DV1394_INIT ioctl to specify your parameters,
-   including the number of frames in the ringbuffer. Then, calling mmap()
-   on the dv1394 device will give you direct access to the ringbuffer
-   from which the DV card reads your frame data.
-
-   The ringbuffer is simply one large, contiguous region of memory
-   containing two or more frames of packed DV data. Each frame of DV data
-   is 120000 bytes (NTSC) or 144000 bytes (PAL).
-
-   Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
-   ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
-   or select()/poll() to wait until the frames are transmitted. Next, you'll
-   need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
-   frames are clear (ready to be filled with new DV data). Finally, use
-   DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
-
-
-   Example: here is what a four-frame ringbuffer might look like
-            during DV transmission:
-
-
-         frame 0   frame 1   frame 2   frame 3
-
-	*--------------------------------------*
-        | CLEAR   | DV data | DV data | CLEAR  |
-        *--------------------------------------*
-                   <ACTIVE>
-
-	transmission goes in this direction --->>>
-
-
-   The DV hardware is currently transmitting the data in frame 1.
-   Once frame 1 is finished, it will automatically transmit frame 2.
-   (if frame 2 finishes before frame 3 is submitted, the device
-   will continue to transmit frame 2, and will increase the dropped_frames
-   counter each time it repeats the transmission).
-
-
-   If you called DV1394_GET_STATUS at this instant, you would
-   receive the following values:
-
-                  n_frames          = 4
-		  active_frame      = 1
-		  first_clear_frame = 3
-		  n_clear_frames    = 2
-
-   At this point, you should write new DV data into frame 3 and optionally
-   frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
-   it may transmit the new frames.
-
-   ERROR HANDLING
-
-   An error (buffer underflow/overflow or a break in the DV stream due
-   to a 1394 bus reset) can be detected by checking the dropped_frames
-   field of struct dv1394_status (obtained through the
-   DV1394_GET_STATUS ioctl).
-
-   The best way to recover from such an error is to re-initialize
-   dv1394, either by using the DV1394_INIT ioctl call, or closing the
-   file descriptor and opening it again. (note that you must unmap all
-   ringbuffer mappings when closing the file descriptor, or else
-   dv1394 will still be considered 'in use').
-
-   MAIN LOOP
-
-   For maximum efficiency and robustness against bus errors, you are
-   advised to model the main loop of your application after the
-   following pseudo-code example:
-
-   (checks of system call return values omitted for brevity; always
-   check return values in your code!)
-
-   while ( frames left ) {
-
-    struct pollfd *pfd = ...;
-
-    pfd->fd = dv1394_fd;
-    pfd->revents = 0;
-    pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
-
-    (add other sources of I/O here)
-
-    poll(pfd, 1, -1); (or select(); add a timeout if you want)
-
-    if (pfd->revents) {
-         struct dv1394_status status;
-
-         ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
-
-	 if (status.dropped_frames > 0) {
-	      reset_dv1394();
-         } else {
-              for (int i = 0; i < status.n_clear_frames; i++) {
-	          copy_DV_frame();
-              }
-         }
-    }
-   }
-
-   where copy_DV_frame() reads or writes on the dv1394 file descriptor
-   (read/write mode) or copies data to/from the mmap ringbuffer and
-   then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
-   frames are availble (mmap mode).
-
-   reset_dv1394() is called in the event of a buffer
-   underflow/overflow or a halt in the DV stream (e.g. due to a 1394
-   bus reset). To guarantee recovery from the error, this function
-   should close the dv1394 file descriptor (and munmap() all
-   ringbuffer mappings, if you are using them), then re-open the
-   dv1394 device (and re-map the ringbuffer).
-
-*/
-
-
-/* maximum number of frames in the ringbuffer */
-#define DV1394_MAX_FRAMES 32
-
-/* number of *full* isochronous packets per DV frame */
-#define DV1394_NTSC_PACKETS_PER_FRAME 250
-#define DV1394_PAL_PACKETS_PER_FRAME  300
-
-/* size of one frame's worth of DV data, in bytes */
-#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
-#define DV1394_PAL_FRAME_SIZE  (480 * DV1394_PAL_PACKETS_PER_FRAME)
-
-
-/* ioctl() commands */
-#include "ieee1394-ioctl.h"
-
-
-enum pal_or_ntsc {
-	DV1394_NTSC = 0,
-	DV1394_PAL
-};
-
-
-
-
-/* this is the argument to DV1394_INIT */
-struct dv1394_init {
-	/* DV1394_API_VERSION */
-	unsigned int api_version;
-
-	/* isochronous transmission channel to use */
-	unsigned int channel;
-
-	/* number of frames in the ringbuffer. Must be at least 2
-	   and at most DV1394_MAX_FRAMES. */
-	unsigned int n_frames;
-
-	/* send/receive PAL or NTSC video format */
-	enum pal_or_ntsc format;
-
-	/* the following are used only for transmission */
-
-	/* set these to zero unless you want a
-	   non-default empty packet rate (see below) */
-	unsigned long cip_n;
-	unsigned long cip_d;
-
-	/* set this to zero unless you want a
-	   non-default SYT cycle offset (default = 3 cycles) */
-	unsigned int syt_offset;
-};
-
-/* NOTE: you may only allocate the DV frame ringbuffer once each time
-   you open the dv1394 device. DV1394_INIT will fail if you call it a
-   second time with different 'n_frames' or 'format' arguments (which
-   would imply a different size for the ringbuffer). If you need a
-   different buffer size, simply close and re-open the device, then
-   initialize it with your new settings. */
-
-/* Q: What are cip_n and cip_d? */
-
-/*
-  A: DV video streams do not utilize 100% of the potential bandwidth offered
-  by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
-  DV devices must periodically insert empty packets into the 1394 data stream.
-  Typically there is one empty packet per 14-16 data-carrying packets.
-
-  Some DV devices will accept a wide range of empty packet rates, while others
-  require a precise rate. If the dv1394 driver produces empty packets at
-  a rate that your device does not accept, you may see ugly patterns on the
-  DV output, or even no output at all.
-
-  The default empty packet insertion rate seems to work for many people; if
-  your DV output is stable, you can simply ignore this discussion. However,
-  we have exposed the empty packet rate as a parameter to support devices that
-  do not work with the default rate.
-
-  The decision to insert an empty packet is made with a numerator/denominator
-  algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
-  You can alter the empty packet rate by passing non-zero values for cip_n
-  and cip_d to the INIT ioctl.
-
- */
-
-
-
-struct dv1394_status {
-	/* this embedded init struct returns the current dv1394
-	   parameters in use */
-	struct dv1394_init init;
-
-	/* the ringbuffer frame that is currently being
-	   displayed. (-1 if the device is not transmitting anything) */
-	int active_frame;
-
-	/* index of the first buffer (ahead of active_frame) that
-	   is ready to be filled with data */
-	unsigned int first_clear_frame;
-
-	/* how many buffers, including first_clear_buffer, are
-	   ready to be filled with data */
-	unsigned int n_clear_frames;
-
-	/* how many times the DV stream has underflowed, overflowed,
-	   or otherwise encountered an error, since the previous call
-	   to DV1394_GET_STATUS */
-	unsigned int dropped_frames;
-
-	/* N.B. The dropped_frames counter is only a lower bound on the actual
-	   number of dropped frames, with the special case that if dropped_frames
-	   is zero, then it is guaranteed that NO frames have been dropped
-	   since the last call to DV1394_GET_STATUS.
-	*/
-};
-
-
-#endif /* _DV_1394_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394-private.h linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394-private.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/dv1394-private.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/dv1394-private.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,587 +0,0 @@
-/*
- * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
- *   Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
- *     receive by Dan Dennedy <dan@dennedy.org>
- *
- * based on:
- *   video1394.h - driver for OHCI 1394 boards
- *   Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                          Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DV_1394_PRIVATE_H
-#define _DV_1394_PRIVATE_H
-
-#include "ieee1394.h"
-#include "ohci1394.h"
-#include "dma.h"
-
-/* data structures private to the dv1394 driver */
-/* none of this is exposed to user-space */
-
-
-/*
-   the 8-byte CIP (Common Isochronous Packet) header that precedes
-   each packet of DV data.
-
-   See the IEC 61883 standard.
-*/
-
-struct CIP_header { unsigned char b[8]; };
-
-static inline void fill_cip_header(struct CIP_header *cip,
-				   unsigned char source_node_id,
-				   unsigned long counter,
-				   enum pal_or_ntsc format,
-				   unsigned long timestamp)
-{
-	cip->b[0] = source_node_id;
-	cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
-	cip->b[2] = 0x00;
-	cip->b[3] = counter;
-
-	cip->b[4] = 0x80; /* const */
-
-	switch(format) {
-	case DV1394_PAL:
-		cip->b[5] = 0x80;
-		break;
-	case DV1394_NTSC:
-		cip->b[5] = 0x00;
-		break;
-	}
-
-	cip->b[6] = timestamp >> 8;
-	cip->b[7] = timestamp & 0xFF;
-}
-
-
-
-/*
-   DMA commands used to program the OHCI's DMA engine
-
-   See the Texas Instruments OHCI 1394 chipset documentation.
-*/
-
-struct output_more_immediate { __le32 q[8]; };
-struct output_more { __le32 q[4]; };
-struct output_last { __le32 q[4]; };
-struct input_more { __le32 q[4]; };
-struct input_last { __le32 q[4]; };
-
-/* outputs */
-
-static inline void fill_output_more_immediate(struct output_more_immediate *omi,
-					      unsigned char tag,
-					      unsigned char channel,
-					      unsigned char sync_tag,
-					      unsigned int  payload_size)
-{
-	omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
-	omi->q[1] = cpu_to_le32(0);
-	omi->q[2] = cpu_to_le32(0);
-	omi->q[3] = cpu_to_le32(0);
-
-	/* IT packet header */
-	omi->q[4] = cpu_to_le32(  (0x0 << 16)  /* IEEE1394_SPEED_100 */
-				  | (tag << 14)
-				  | (channel << 8)
-				  | (TCODE_ISO_DATA << 4)
-				  | (sync_tag) );
-
-	/* reserved field; mimic behavior of my Sony DSR-40 */
-	omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
-
-	omi->q[6] = cpu_to_le32(0);
-	omi->q[7] = cpu_to_le32(0);
-}
-
-static inline void fill_output_more(struct output_more *om,
-				    unsigned int data_size,
-				    unsigned long data_phys_addr)
-{
-	om->q[0] = cpu_to_le32(data_size);
-	om->q[1] = cpu_to_le32(data_phys_addr);
-	om->q[2] = cpu_to_le32(0);
-	om->q[3] = cpu_to_le32(0);
-}
-
-static inline void fill_output_last(struct output_last *ol,
-				    int want_timestamp,
-				    int want_interrupt,
-				    unsigned int data_size,
-				    unsigned long data_phys_addr)
-{
-	u32 temp = 0;
-	temp |= 1 << 28; /* OUTPUT_LAST */
-
-	if (want_timestamp) /* controller will update timestamp at DMA time */
-		temp |= 1 << 27;
-
-	if (want_interrupt)
-		temp |= 3 << 20;
-
-	temp |= 3 << 18; /* must take branch */
-	temp |= data_size;
-
-	ol->q[0] = cpu_to_le32(temp);
-	ol->q[1] = cpu_to_le32(data_phys_addr);
-	ol->q[2] = cpu_to_le32(0);
-	ol->q[3] = cpu_to_le32(0);
-}
-
-/* inputs */
-
-static inline void fill_input_more(struct input_more *im,
-				   int want_interrupt,
-				   unsigned int data_size,
-				   unsigned long data_phys_addr)
-{
-	u32 temp =  2 << 28; /* INPUT_MORE */
-	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-	if (want_interrupt)
-		temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
-	temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
-	                       /* disable wait on sync field, not used in DV :-( */
-       	temp |= data_size;
-
-	im->q[0] = cpu_to_le32(temp);
-	im->q[1] = cpu_to_le32(data_phys_addr);
-	im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
-	im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
- 
-static inline void fill_input_last(struct input_last *il,
-				    int want_interrupt,
-				    unsigned int data_size,
-				    unsigned long data_phys_addr)
-{
-	u32 temp =  3 << 28; /* INPUT_LAST */
-	temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
-	if (want_interrupt)
-		temp |= 3 << 20; /* enable interrupts */
-	temp |= 0xC << 16; /* enable branch to address */
-	                       /* disable wait on sync field, not used in DV :-( */
-	temp |= data_size;
-
-	il->q[0] = cpu_to_le32(temp);
-	il->q[1] = cpu_to_le32(data_phys_addr);
-	il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
-	il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
-}
-
-
-
-/*
-   A "DMA descriptor block" consists of several contiguous DMA commands.
-   struct DMA_descriptor_block encapsulates all of the commands necessary
-   to send one packet of DV data.
-
-   There are three different types of these blocks:
-
-        1) command to send an empty packet (CIP header only, no DV data):
-
-	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
-	    OUTPUT_LAST           <-- points to the CIP header
-
-	2) command to send a full packet when the DV data payload does NOT
-	   cross a page boundary:
-
-	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
-	    OUTPUT_MORE           <-- points to the CIP header
-	    OUTPUT_LAST           <-- points to entire DV data payload
-
-	3) command to send a full packet when the DV payload DOES cross
-	   a page boundary:
-
-	    OUTPUT_MORE-Immediate <-- contains the iso header in-line
-	    OUTPUT_MORE           <-- points to the CIP header
-	    OUTPUT_MORE           <-- points to first part of DV data payload
-	    OUTPUT_LAST           <-- points to second part of DV data payload
-
-   This struct describes all three block types using unions.
-
-   !!! It is vital that an even number of these descriptor blocks fit on one
-   page of memory, since a block cannot cross a page boundary !!!
-
- */
-
-struct DMA_descriptor_block {
-
-	union {
-		struct {
-			/*  iso header, common to all output block types */
-			struct output_more_immediate omi;
-
-			union {
-				/* empty packet */
-				struct {
-					struct output_last ol;  /* CIP header */
-				} empty;
-
-				/* full packet */
-				struct {
-					struct output_more om;  /* CIP header */
-
-					union {
-				               /* payload does not cross page boundary */
-						struct {
-							struct output_last ol;  /* data payload */
-						} nocross;
-
-				               /* payload crosses page boundary */
-						struct {
-							struct output_more om;  /* data payload */
-							struct output_last ol;  /* data payload */
-						} cross;
-					} u;
-
-				} full;
-			} u;
-		} out;
-
-		struct {
-			struct input_last il;
-		} in;
-
-	} u;
-
-	/* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
-	   by padding out to 128 bytes */
-	u32 __pad__[12];
-};
-
-
-/* struct frame contains all data associated with one frame in the
-   ringbuffer these are allocated when the DMA context is initialized
-   do_dv1394_init().  They are re-used after the card finishes
-   transmitting the frame. */
-
-struct video_card; /* forward declaration */
-
-struct frame {
-
-	/* points to the struct video_card that owns this frame */
-	struct video_card *video;
-
-	/* index of this frame in video_card->frames[] */
-	unsigned int frame_num;
-
-	/* FRAME_CLEAR - DMA program not set up, waiting for data
-	   FRAME_READY - DMA program written, ready to transmit
-
-	   Changes to these should be locked against the interrupt
-	*/
-	enum {
-		FRAME_CLEAR = 0,
-		FRAME_READY
-	} state;
-
-	/* whether this frame has been DMA'ed already; used only from
-	   the IRQ handler to determine whether the frame can be reset */
-	int done;
-
-
-	/* kernel virtual pointer to the start of this frame's data in
-	   the user ringbuffer. Use only for CPU access; to get the DMA
-	   bus address you must go through the video->user_dma mapping */
-	unsigned long data;
-
-	/* Max # of packets per frame */
-#define MAX_PACKETS 500
-
-
-	/* a PAGE_SIZE memory pool for allocating CIP headers
-	   !header_pool must be aligned to PAGE_SIZE! */
-	struct CIP_header *header_pool;
-	dma_addr_t         header_pool_dma;
-
-
-	/* a physically contiguous memory pool for allocating DMA
-	   descriptor blocks; usually around 64KB in size
-	   !descriptor_pool must be aligned to PAGE_SIZE! */
-	struct DMA_descriptor_block *descriptor_pool;
-	dma_addr_t                   descriptor_pool_dma;
-	unsigned long                descriptor_pool_size;
-
-
-	/* # of packets allocated for this frame */
-	unsigned int n_packets;
-
-
-	/* below are several pointers (kernel virtual addresses, not
-	   DMA bus addresses) to parts of the DMA program.  These are
-	   set each time the DMA program is written in
-	   frame_prepare(). They are used later on, e.g. from the
-	   interrupt handler, to check the status of the frame */
-
-	/* points to status/timestamp field of first DMA packet */
-	/* (we'll check it later to monitor timestamp accuracy) */
-	__le32 *frame_begin_timestamp;
-
-	/* the timestamp we assigned to the first packet in the frame */
-	u32 assigned_timestamp;
-
-	/* pointer to the first packet's CIP header (where the timestamp goes) */
-	struct CIP_header *cip_syt1;
-
-	/* pointer to the second packet's CIP header
-	   (only set if the first packet was empty) */
-	struct CIP_header *cip_syt2;
-
-	/* in order to figure out what caused an interrupt,
-	   store pointers to the status fields of the two packets
-	   that can cause interrupts. We'll check these from the
-	   interrupt handler.
-	*/
-	__le32 *mid_frame_timestamp;
-	__le32 *frame_end_timestamp;
-
-	/* branch address field of final packet. This is effectively
-	   the "tail" in the chain of DMA descriptor blocks.
-	   We will fill it with the address of the first DMA descriptor
-	   block in the subsequent frame, once it is ready.
-	*/
-	__le32 *frame_end_branch;
-
-	/* the number of descriptors in the first descriptor block
-	   of the frame. Needed to start DMA */
-	int first_n_descriptors;
-};
-
-
-struct packet {
-	__le16	timestamp;
-	u16	invalid;
-	u16	iso_header;
-	__le16	data_length;
-	u32	cip_h1;
-	u32	cip_h2;
-	unsigned char data[480];
-	unsigned char padding[16]; /* force struct size =512 for page alignment */
-};
-
-
-/* allocate/free a frame */
-static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
-static void frame_delete(struct frame *f);
-
-/* reset f so that it can be used again */
-static void frame_reset(struct frame *f);
-
-/* struct video_card contains all data associated with one instance
-   of the dv1394 driver
-*/
-enum modes {
-	MODE_RECEIVE,
-	MODE_TRANSMIT
-};
-
-struct video_card {
-
-	/* ohci card to which this instance corresponds */
-	struct ti_ohci *ohci;
-
-	/* OHCI card id; the link between the VFS inode and a specific video_card
-	   (essentially the device minor number) */
-	int id;
-
-	/* entry in dv1394_cards */
-	struct list_head list;
-
-	/* OHCI card IT DMA context number, -1 if not in use */
-	int ohci_it_ctx;
-	struct ohci1394_iso_tasklet it_tasklet;
-
-	/* register offsets for current IT DMA context, 0 if not in use */
-	u32 ohci_IsoXmitContextControlSet;
-	u32 ohci_IsoXmitContextControlClear;
-	u32 ohci_IsoXmitCommandPtr;
-
-	/* OHCI card IR DMA context number, -1 if not in use */
-	struct ohci1394_iso_tasklet ir_tasklet;
-	int ohci_ir_ctx;
-
-	/* register offsets for current IR DMA context, 0 if not in use */
-	u32 ohci_IsoRcvContextControlSet;
-	u32 ohci_IsoRcvContextControlClear;
-	u32 ohci_IsoRcvCommandPtr;
-	u32 ohci_IsoRcvContextMatch;
-
-
-	/* CONCURRENCY CONTROL */
-
-	/* there are THREE levels of locking associated with video_card. */
-
-	/*
-	   1) the 'open' flag - this prevents more than one process from
-	   opening the device. (the driver currently assumes only one opener).
-	   This is a regular int, but use test_and_set_bit() (on bit zero) 
-	   for atomicity.
-	 */
-	unsigned long open;
-
-	/*
-	   2) the spinlock - this provides mutual exclusion between the interrupt
-	   handler and process-context operations. Generally you must take the
-	   spinlock under the following conditions:
-	     1) DMA (and hence the interrupt handler) may be running
-	     AND
-	     2) you need to operate on the video_card, especially active_frame
-
-	     It is OK to play with video_card without taking the spinlock if
-	     you are certain that DMA is not running. Even if DMA is running,
-	     it is OK to *read* active_frame with the lock, then drop it
-	     immediately. This is safe because the interrupt handler will never
-	     advance active_frame onto a frame that is not READY (and the spinlock
-	     must be held while marking a frame READY).
-
-	     spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
-	     which can be accessed from both process and interrupt context
-	 */
-	spinlock_t spinlock;
-
-	/* flag to prevent spurious interrupts (which OHCI seems to
-	   generate a lot :) from accessing the struct */
-	int dma_running;
-
-	/*
-	  3) the sleeping mutex 'mtx' - this is used from process context only,
-	  to serialize various operations on the video_card. Even though only one
-	  open() is allowed, we still need to prevent multiple threads of execution
-	  from entering calls like read, write, ioctl, etc.
-
-	  I honestly can't think of a good reason to use dv1394 from several threads
-	  at once, but we need to serialize anyway to prevent oopses =).
-
-	  NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
-	 */
-	struct mutex mtx;
-
-	/* people waiting for buffer space, please form a line here... */
-	wait_queue_head_t waitq;
-
-	/* support asynchronous I/O signals (SIGIO) */
-	struct fasync_struct *fasync;
-
-	/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
-           data, exposed to user-space via mmap() */
-	unsigned long      dv_buf_size;
-	struct dma_region  dv_buf;
-
-	/* next byte in the ringbuffer that a write() call will fill */
-	size_t write_off;
-
-	struct frame *frames[DV1394_MAX_FRAMES];
-
-	/* n_frames also serves as an indicator that this struct video_card is
-	   initialized and ready to run DMA buffers */
-
-	int n_frames;
-
-	/* this is the frame that is currently "owned" by the OHCI DMA controller
-	   (set to -1 iff DMA is not running)
-
-	   ! must lock against the interrupt handler when accessing it !
-
-	   RULES:
-
-	       Only the interrupt handler may change active_frame if DMA
-	          is running; if not, process may change it
-
-	       If the next frame is READY, the interrupt handler will advance
-	       active_frame when the current frame is finished.
-
-	       If the next frame is CLEAR, the interrupt handler will re-transmit
-	       the current frame, and the dropped_frames counter will be  incremented.
-
-	       The interrupt handler will NEVER advance active_frame to a
-	       frame that is not READY.
-	*/
-	int active_frame;
-	int first_run;
-
-	/* the same locking rules apply to these three fields also: */
-
-	/* altered ONLY from process context. Must check first_clear_frame->state;
-	   if it's READY, that means the ringbuffer is full with READY frames;
-	   if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
-	unsigned int first_clear_frame;
-
-	/* altered both by process and interrupt */
-	unsigned int n_clear_frames;
-
-	/* only altered by the interrupt */
-	unsigned int dropped_frames;
-
-
-
-	/* the CIP accumulator and continuity counter are properties
-	   of the DMA stream as a whole (not a single frame), so they
-	   are stored here in the video_card */
-
-	unsigned long cip_accum;
-	unsigned long cip_n, cip_d;
-	unsigned int syt_offset;
-	unsigned int continuity_counter;
-
-	enum pal_or_ntsc pal_or_ntsc;
-
-	/* redundant, but simplifies the code somewhat */
-	unsigned int frame_size; /* in bytes */
-
-	/* the isochronous channel to use, -1 if video card is inactive */
-	int channel;
-
-
-	/* physically contiguous packet ringbuffer for receive */
-	struct dma_region packet_buf;
-	unsigned long  packet_buf_size;
-
-	unsigned int current_packet;
-	int first_frame; 	/* received first start frame marker? */
-	enum modes mode;
-};
-
-/*
-   if the video_card is not initialized, then the ONLY fields that are valid are:
-   ohci
-   open
-   n_frames
-*/
-
-static inline int video_card_initialized(struct video_card *v)
-{
-	return v->n_frames > 0;
-}
-
-static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
-static int do_dv1394_init_default(struct video_card *video);
-static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
-
-
-/* NTSC empty packet rate accurate to within 0.01%,
-   calibrated against a Sony DSR-40 DVCAM deck */
-
-#define CIP_N_NTSC   68000000
-#define CIP_D_NTSC 1068000000
-
-#define CIP_N_PAL  1
-#define CIP_D_PAL 16
-
-#endif /* _DV_1394_PRIVATE_H */
-
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/eth1394.c linux-libre-2.6.37-gnu/drivers/ieee1394/eth1394.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/eth1394.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/eth1394.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1736 +0,0 @@
-/*
- * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
- *               2000 Bonin Franck <boninf@free.fr>
- *               2003 Steve Kinneberg <kinnebergsteve@acmsystems.com>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses.
- *
- * TODO:
- * RFC 2734 related:
- * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
- *
- * Non-RFC 2734 related:
- * - Handle fragmented skb's coming from the networking layer.
- * - Move generic GASP reception to core 1394 code
- * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
- * - Stability improvements
- * - Performance enhancements
- * - Consider garbage collecting old partial datagrams after X amount of time
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-#include <linux/ethtool.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/unaligned.h>
-#include <net/arp.h>
-
-#include "config_roms.h"
-#include "csr1212.h"
-#include "eth1394.h"
-#include "highlevel.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-
-#define ETH1394_PRINT_G(level, fmt, args...) \
-	printk(level "%s: " fmt, driver_name, ## args)
-
-#define ETH1394_PRINT(level, dev_name, fmt, args...) \
-	printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
-
-struct fragment_info {
-	struct list_head list;
-	int offset;
-	int len;
-};
-
-struct partial_datagram {
-	struct list_head list;
-	u16 dgl;
-	u16 dg_size;
-	__be16 ether_type;
-	struct sk_buff *skb;
-	char *pbuf;
-	struct list_head frag_info;
-};
-
-struct pdg_list {
-	struct list_head list;	/* partial datagram list per node	*/
-	unsigned int sz;	/* partial datagram list size per node	*/
-	spinlock_t lock;	/* partial datagram lock		*/
-};
-
-struct eth1394_host_info {
-	struct hpsb_host *host;
-	struct net_device *dev;
-};
-
-struct eth1394_node_ref {
-	struct unit_directory *ud;
-	struct list_head list;
-};
-
-struct eth1394_node_info {
-	u16 maxpayload;		/* max payload			*/
-	u8 sspd;		/* max speed			*/
-	u64 fifo;		/* FIFO address			*/
-	struct pdg_list pdg;	/* partial RX datagram lists	*/
-	int dgl;		/* outgoing datagram label	*/
-};
-
-static const char driver_name[] = "eth1394";
-
-static struct kmem_cache *packet_task_cache;
-
-static struct hpsb_highlevel eth1394_highlevel;
-
-/* Use common.lf to determine header len */
-static const int hdr_type_len[] = {
-	sizeof(struct eth1394_uf_hdr),
-	sizeof(struct eth1394_ff_hdr),
-	sizeof(struct eth1394_sf_hdr),
-	sizeof(struct eth1394_sf_hdr)
-};
-
-static const u16 eth1394_speedto_maxpayload[] = {
-/*     S100, S200, S400, S800, S1600, S3200 */
-	512, 1024, 2048, 4096,  4096,  4096
-};
-
-MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
-MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
-MODULE_LICENSE("GPL");
-
-/*
- * The max_partial_datagrams parameter is the maximum number of fragmented
- * datagrams per node that eth1394 will keep in memory.  Providing an upper
- * bound allows us to limit the amount of memory that partial datagrams
- * consume in the event that some partial datagrams are never completed.
- */
-static int max_partial_datagrams = 25;
-module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_partial_datagrams,
-		 "Maximum number of partially received fragmented datagrams "
-		 "(default = 25).");
-
-
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, const void *daddr,
-			    const void *saddr, unsigned len);
-static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(const struct sk_buff *skb,
-				  unsigned char *haddr);
-static int ether1394_header_cache(const struct neighbour *neigh,
-				  struct hh_cache *hh);
-static void ether1394_header_cache_update(struct hh_cache *hh,
-					  const struct net_device *dev,
-					  const unsigned char *haddr);
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
-				struct net_device *dev);
-static void ether1394_iso(struct hpsb_iso *iso);
-
-static const struct ethtool_ops ethtool_ops;
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
-			   quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host(struct hpsb_host *host);
-static void ether1394_remove_host(struct hpsb_host *host);
-static void ether1394_host_reset(struct hpsb_host *host);
-
-/* Function for incoming 1394 packets */
-static const struct hpsb_address_ops addr_ops = {
-	.write =	ether1394_write,
-};
-
-/* Ieee1394 highlevel driver functions */
-static struct hpsb_highlevel eth1394_highlevel = {
-	.name =		driver_name,
-	.add_host =	ether1394_add_host,
-	.remove_host =	ether1394_remove_host,
-	.host_reset =	ether1394_host_reset,
-};
-
-static int ether1394_recv_init(struct eth1394_priv *priv)
-{
-	unsigned int iso_buf_size;
-
-	/* FIXME: rawiso limits us to PAGE_SIZE */
-	iso_buf_size = min((unsigned int)PAGE_SIZE,
-			   2 * (1U << (priv->host->csr.max_rec + 1)));
-
-	priv->iso = hpsb_iso_recv_init(priv->host,
-				       ETHER1394_GASP_BUFFERS * iso_buf_size,
-				       ETHER1394_GASP_BUFFERS,
-				       priv->broadcast_channel,
-				       HPSB_ISO_DMA_PACKET_PER_BUFFER,
-				       1, ether1394_iso);
-	if (priv->iso == NULL) {
-		ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
-		priv->bc_state = ETHER1394_BC_ERROR;
-		return -EAGAIN;
-	}
-
-	if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
-		priv->bc_state = ETHER1394_BC_STOPPED;
-	else
-		priv->bc_state = ETHER1394_BC_RUNNING;
-	return 0;
-}
-
-/* This is called after an "ifup" */
-static int ether1394_open(struct net_device *dev)
-{
-	struct eth1394_priv *priv = netdev_priv(dev);
-	int ret;
-
-	if (priv->bc_state == ETHER1394_BC_ERROR) {
-		ret = ether1394_recv_init(priv);
-		if (ret)
-			return ret;
-	}
-	netif_start_queue(dev);
-	return 0;
-}
-
-/* This is called after an "ifdown" */
-static int ether1394_stop(struct net_device *dev)
-{
-	/* flush priv->wake */
-	flush_scheduled_work();
-
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/* FIXME: What to do if we timeout? I think a host reset is probably in order,
- * so that's what we do. Should we increment the stat counters too?  */
-static void ether1394_tx_timeout(struct net_device *dev)
-{
-	struct hpsb_host *host =
-			((struct eth1394_priv *)netdev_priv(dev))->host;
-
-	ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
-	ether1394_host_reset(host);
-}
-
-static inline int ether1394_max_mtu(struct hpsb_host* host)
-{
-	return (1 << (host->csr.max_rec + 1))
-			- sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
-}
-
-static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
-{
-	int max_mtu;
-
-	if (new_mtu < 68)
-		return -EINVAL;
-
-	max_mtu = ether1394_max_mtu(
-			((struct eth1394_priv *)netdev_priv(dev))->host);
-	if (new_mtu > max_mtu) {
-		ETH1394_PRINT(KERN_INFO, dev->name,
-			      "Local node constrains MTU to %d\n", max_mtu);
-		return -ERANGE;
-	}
-
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-static void purge_partial_datagram(struct list_head *old)
-{
-	struct partial_datagram *pd;
-	struct list_head *lh, *n;
-	struct fragment_info *fi;
-
-	pd = list_entry(old, struct partial_datagram, list);
-
-	list_for_each_safe(lh, n, &pd->frag_info) {
-		fi = list_entry(lh, struct fragment_info, list);
-		list_del(lh);
-		kfree(fi);
-	}
-	list_del(old);
-	kfree_skb(pd->skb);
-	kfree(pd);
-}
-
-/******************************************
- * 1394 bus activity functions
- ******************************************/
-
-static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl,
-						  struct unit_directory *ud)
-{
-	struct eth1394_node_ref *node;
-
-	list_for_each_entry(node, inl, list)
-		if (node->ud == ud)
-			return node;
-
-	return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl,
-						       u64 guid)
-{
-	struct eth1394_node_ref *node;
-
-	list_for_each_entry(node, inl, list)
-		if (node->ud->ne->guid == guid)
-			return node;
-
-	return NULL;
-}
-
-static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
-							 nodeid_t nodeid)
-{
-	struct eth1394_node_ref *node;
-
-	list_for_each_entry(node, inl, list)
-		if (node->ud->ne->nodeid == nodeid)
-			return node;
-
-	return NULL;
-}
-
-static int eth1394_new_node(struct eth1394_host_info *hi,
-			    struct unit_directory *ud)
-{
-	struct eth1394_priv *priv;
-	struct eth1394_node_ref *new_node;
-	struct eth1394_node_info *node_info;
-
-	new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
-	if (!new_node)
-		return -ENOMEM;
-
-	node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
-	if (!node_info) {
-		kfree(new_node);
-		return -ENOMEM;
-	}
-
-	spin_lock_init(&node_info->pdg.lock);
-	INIT_LIST_HEAD(&node_info->pdg.list);
-	node_info->pdg.sz = 0;
-	node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
-
-	dev_set_drvdata(&ud->device, node_info);
-	new_node->ud = ud;
-
-	priv = netdev_priv(hi->dev);
-	list_add_tail(&new_node->list, &priv->ip_node_list);
-	return 0;
-}
-
-static int eth1394_probe(struct device *dev)
-{
-	struct unit_directory *ud;
-	struct eth1394_host_info *hi;
-
-	ud = container_of(dev, struct unit_directory, device);
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-	if (!hi)
-		return -ENOENT;
-
-	return eth1394_new_node(hi, ud);
-}
-
-static int eth1394_remove(struct device *dev)
-{
-	struct unit_directory *ud;
-	struct eth1394_host_info *hi;
-	struct eth1394_priv *priv;
-	struct eth1394_node_ref *old_node;
-	struct eth1394_node_info *node_info;
-	struct list_head *lh, *n;
-	unsigned long flags;
-
-	ud = container_of(dev, struct unit_directory, device);
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-	if (!hi)
-		return -ENOENT;
-
-	priv = netdev_priv(hi->dev);
-
-	old_node = eth1394_find_node(&priv->ip_node_list, ud);
-	if (!old_node)
-		return 0;
-
-	list_del(&old_node->list);
-	kfree(old_node);
-
-	node_info = dev_get_drvdata(&ud->device);
-
-	spin_lock_irqsave(&node_info->pdg.lock, flags);
-	/* The partial datagram list should be empty, but we'll just
-	 * make sure anyway... */
-	list_for_each_safe(lh, n, &node_info->pdg.list)
-		purge_partial_datagram(lh);
-	spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-
-	kfree(node_info);
-	dev_set_drvdata(&ud->device, NULL);
-	return 0;
-}
-
-static int eth1394_update(struct unit_directory *ud)
-{
-	struct eth1394_host_info *hi;
-	struct eth1394_priv *priv;
-	struct eth1394_node_ref *node;
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
-	if (!hi)
-		return -ENOENT;
-
-	priv = netdev_priv(hi->dev);
-	node = eth1394_find_node(&priv->ip_node_list, ud);
-	if (node)
-		return 0;
-
-	return eth1394_new_node(hi, ud);
-}
-
-static const struct ieee1394_device_id eth1394_id_table[] = {
-	{
-		.match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
-				IEEE1394_MATCH_VERSION),
-		.specifier_id =	ETHER1394_GASP_SPECIFIER_ID,
-		.version = ETHER1394_GASP_VERSION,
-	},
-	{}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
-
-static struct hpsb_protocol_driver eth1394_proto_driver = {
-	.name		= driver_name,
-	.id_table	= eth1394_id_table,
-	.update		= eth1394_update,
-	.driver		= {
-		.probe		= eth1394_probe,
-		.remove		= eth1394_remove,
-	},
-};
-
-static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
-{
-	unsigned long flags;
-	int i;
-	struct eth1394_priv *priv = netdev_priv(dev);
-	struct hpsb_host *host = priv->host;
-	u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
-	int max_speed = IEEE1394_SPEED_MAX;
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	memset(priv->ud_list, 0, sizeof(priv->ud_list));
-	priv->bc_maxpayload = 512;
-
-	/* Determine speed limit */
-	/* FIXME: This is broken for nodes with link speed < PHY speed,
-	 * and it is suboptimal for S200B...S800B hardware.
-	 * The result of nodemgr's speed probe should be used somehow. */
-	for (i = 0; i < host->node_count; i++) {
-		/* take care of S100B...S400B PHY ports */
-		if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
-			max_speed = IEEE1394_SPEED_100;
-			break;
-		}
-		if (max_speed > host->speed[i])
-			max_speed = host->speed[i];
-	}
-	priv->bc_sspd = max_speed;
-
-	if (set_mtu) {
-		/* Use the RFC 2734 default 1500 octets or the maximum payload
-		 * as initial MTU */
-		dev->mtu = min(1500, ether1394_max_mtu(host));
-
-		/* Set our hardware address while we're at it */
-		memcpy(dev->dev_addr, &guid, sizeof(u64));
-		memset(dev->broadcast, 0xff, sizeof(u64));
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static const struct header_ops ether1394_header_ops = {
-	.create		= ether1394_header,
-	.rebuild	= ether1394_rebuild_header,
-	.cache  	= ether1394_header_cache,
-	.cache_update	= ether1394_header_cache_update,
-	.parse		= ether1394_header_parse,
-};
-
-static const struct net_device_ops ether1394_netdev_ops = {
-	.ndo_open	= ether1394_open,
-	.ndo_stop	= ether1394_stop,
-	.ndo_start_xmit	= ether1394_tx,
-	.ndo_tx_timeout	= ether1394_tx_timeout,
-	.ndo_change_mtu	= ether1394_change_mtu,
-};
-
-static void ether1394_init_dev(struct net_device *dev)
-{
-
-	dev->header_ops		= &ether1394_header_ops;
-	dev->netdev_ops		= &ether1394_netdev_ops;
-
-	SET_ETHTOOL_OPS(dev, &ethtool_ops);
-
-	dev->watchdog_timeo	= ETHER1394_TIMEOUT;
-	dev->flags		= IFF_BROADCAST | IFF_MULTICAST;
-	dev->features		= NETIF_F_HIGHDMA;
-	dev->addr_len		= ETH1394_ALEN;
-	dev->hard_header_len 	= ETH1394_HLEN;
-	dev->type		= ARPHRD_IEEE1394;
-
-	/* FIXME: This value was copied from ether_setup(). Is it too much? */
-	dev->tx_queue_len	= 1000;
-}
-
-/*
- * Wake the queue up after commonly encountered transmit failure conditions are
- * hopefully over.  Currently only tlabel exhaustion is accounted for.
- */
-static void ether1394_wake_queue(struct work_struct *work)
-{
-	struct eth1394_priv *priv;
-	struct hpsb_packet *packet;
-
-	priv = container_of(work, struct eth1394_priv, wake);
-	packet = hpsb_alloc_packet(0);
-
-	/* This is really bad, but unjam the queue anyway. */
-	if (!packet)
-		goto out;
-
-	packet->host = priv->host;
-	packet->node_id = priv->wake_node;
-	/*
-	 * A transaction label is all we really want.  If we get one, it almost
-	 * always means we can get a lot more because the ieee1394 core recycled
-	 * a whole batch of tlabels, at last.
-	 */
-	if (hpsb_get_tlabel(packet) == 0)
-		hpsb_free_tlabel(packet);
-
-	hpsb_free_packet(packet);
-out:
-	netif_wake_queue(priv->wake_dev);
-}
-
-/*
- * This function is called every time a card is found. It is generally called
- * when the module is installed. This is where we add all of our ethernet
- * devices. One for each host.
- */
-static void ether1394_add_host(struct hpsb_host *host)
-{
-	struct eth1394_host_info *hi = NULL;
-	struct net_device *dev = NULL;
-	struct eth1394_priv *priv;
-	u64 fifo_addr;
-
-	if (hpsb_config_rom_ip1394_add(host) != 0) {
-		ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
-		return;
-	}
-
-	fifo_addr = hpsb_allocate_and_register_addrspace(
-			&eth1394_highlevel, host, &addr_ops,
-			ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
-			CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
-	if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
-		ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
-		hpsb_config_rom_ip1394_remove(host);
-		return;
-	}
-
-	dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
-	if (dev == NULL) {
-		ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-		goto out;
-	}
-
-	SET_NETDEV_DEV(dev, &host->device);
-
-	priv = netdev_priv(dev);
-	INIT_LIST_HEAD(&priv->ip_node_list);
-	spin_lock_init(&priv->lock);
-	priv->host = host;
-	priv->local_fifo = fifo_addr;
-	INIT_WORK(&priv->wake, ether1394_wake_queue);
-	priv->wake_dev = dev;
-
-	hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
-	if (hi == NULL) {
-		ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-		goto out;
-	}
-
-	ether1394_reset_priv(dev, 1);
-
-	if (register_netdev(dev)) {
-		ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
-		goto out;
-	}
-
-	ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
-		      host->id);
-
-	hi->host = host;
-	hi->dev = dev;
-
-	/* Ignore validity in hopes that it will be set in the future.  It'll
-	 * be checked when the eth device is opened. */
-	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
-
-	ether1394_recv_init(priv);
-	return;
-out:
-	if (dev)
-		free_netdev(dev);
-	if (hi)
-		hpsb_destroy_hostinfo(&eth1394_highlevel, host);
-	hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
-	hpsb_config_rom_ip1394_remove(host);
-}
-
-/* Remove a card from our list */
-static void ether1394_remove_host(struct hpsb_host *host)
-{
-	struct eth1394_host_info *hi;
-	struct eth1394_priv *priv;
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-	if (!hi)
-		return;
-	priv = netdev_priv(hi->dev);
-	hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
-	hpsb_config_rom_ip1394_remove(host);
-	if (priv->iso)
-		hpsb_iso_shutdown(priv->iso);
-	unregister_netdev(hi->dev);
-	free_netdev(hi->dev);
-}
-
-/* A bus reset happened */
-static void ether1394_host_reset(struct hpsb_host *host)
-{
-	struct eth1394_host_info *hi;
-	struct eth1394_priv *priv;
-	struct net_device *dev;
-	struct list_head *lh, *n;
-	struct eth1394_node_ref *node;
-	struct eth1394_node_info *node_info;
-	unsigned long flags;
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-
-	/* This can happen for hosts that we don't use */
-	if (!hi)
-		return;
-
-	dev = hi->dev;
-	priv = netdev_priv(dev);
-
-	/* Reset our private host data, but not our MTU */
-	netif_stop_queue(dev);
-	ether1394_reset_priv(dev, 0);
-
-	list_for_each_entry(node, &priv->ip_node_list, list) {
-		node_info = dev_get_drvdata(&node->ud->device);
-
-		spin_lock_irqsave(&node_info->pdg.lock, flags);
-
-		list_for_each_safe(lh, n, &node_info->pdg.list)
-			purge_partial_datagram(lh);
-
-		INIT_LIST_HEAD(&(node_info->pdg.list));
-		node_info->pdg.sz = 0;
-
-		spin_unlock_irqrestore(&node_info->pdg.lock, flags);
-	}
-
-	netif_wake_queue(dev);
-}
-
-/******************************************
- * HW Header net device functions
- ******************************************/
-/* These functions have been adapted from net/ethernet/eth.c */
-
-/* Create a fake MAC header for an arbitrary protocol layer.
- * saddr=NULL means use device source address
- * daddr=NULL means leave destination address (eg unresolved arp). */
-static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, const void *daddr,
-			    const void *saddr, unsigned len)
-{
-	struct eth1394hdr *eth =
-			(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
-
-	eth->h_proto = htons(type);
-
-	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
-		memset(eth->h_dest, 0, dev->addr_len);
-		return dev->hard_header_len;
-	}
-
-	if (daddr) {
-		memcpy(eth->h_dest, daddr, dev->addr_len);
-		return dev->hard_header_len;
-	}
-
-	return -dev->hard_header_len;
-}
-
-/* Rebuild the faked MAC header. This is called after an ARP
- * (or in future other address resolution) has completed on this
- * sk_buff. We now let ARP fill in the other fields.
- *
- * This routine CANNOT use cached dst->neigh!
- * Really, it is used only when dst->neigh is wrong.
- */
-static int ether1394_rebuild_header(struct sk_buff *skb)
-{
-	struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
-
-	if (eth->h_proto == htons(ETH_P_IP))
-		return arp_find((unsigned char *)&eth->h_dest, skb);
-
-	ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
-		      "unable to resolve type %04x addresses\n",
-		      ntohs(eth->h_proto));
-	return 0;
-}
-
-static int ether1394_header_parse(const struct sk_buff *skb,
-				  unsigned char *haddr)
-{
-	memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
-	return ETH1394_ALEN;
-}
-
-static int ether1394_header_cache(const struct neighbour *neigh,
-				  struct hh_cache *hh)
-{
-	__be16 type = hh->hh_type;
-	struct net_device *dev = neigh->dev;
-	struct eth1394hdr *eth =
-		(struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
-
-	if (type == htons(ETH_P_802_3))
-		return -1;
-
-	eth->h_proto = type;
-	memcpy(eth->h_dest, neigh->ha, dev->addr_len);
-
-	hh->hh_len = ETH1394_HLEN;
-	return 0;
-}
-
-/* Called by Address Resolution module to notify changes in address. */
-static void ether1394_header_cache_update(struct hh_cache *hh,
-					  const struct net_device *dev,
-					  const unsigned char * haddr)
-{
-	memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
-}
-
-/******************************************
- * Datagram reception code
- ******************************************/
-
-/* Copied from net/ethernet/eth.c */
-static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-	struct eth1394hdr *eth;
-	unsigned char *rawp;
-
-	skb_reset_mac_header(skb);
-	skb_pull(skb, ETH1394_HLEN);
-	eth = eth1394_hdr(skb);
-
-	if (*eth->h_dest & 1) {
-		if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
-			skb->pkt_type = PACKET_BROADCAST;
-#if 0
-		else
-			skb->pkt_type = PACKET_MULTICAST;
-#endif
-	} else {
-		if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
-			skb->pkt_type = PACKET_OTHERHOST;
-	}
-
-	if (ntohs(eth->h_proto) >= 1536)
-		return eth->h_proto;
-
-	rawp = skb->data;
-
-	if (*(unsigned short *)rawp == 0xFFFF)
-		return htons(ETH_P_802_3);
-
-	return htons(ETH_P_802_2);
-}
-
-/* Parse an encapsulated IP1394 header into an ethernet frame packet.
- * We also perform ARP translation here, if need be.  */
-static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
-				 nodeid_t srcid, nodeid_t destid,
-				 __be16 ether_type)
-{
-	struct eth1394_priv *priv = netdev_priv(dev);
-	__be64 dest_hw;
-	__be16 ret = 0;
-
-	/* Setup our hw addresses. We use these to build the ethernet header. */
-	if (destid == (LOCAL_BUS | ALL_NODES))
-		dest_hw = ~cpu_to_be64(0);  /* broadcast */
-	else
-		dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
-				      priv->host->csr.guid_lo);
-
-	/* If this is an ARP packet, convert it. First, we want to make
-	 * use of some of the fields, since they tell us a little bit
-	 * about the sending machine.  */
-	if (ether_type == htons(ETH_P_ARP)) {
-		struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-		struct arphdr *arp = (struct arphdr *)skb->data;
-		unsigned char *arp_ptr = (unsigned char *)(arp + 1);
-		u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
-					   ntohl(arp1394->fifo_lo);
-		u8 max_rec = min(priv->host->csr.max_rec,
-				 (u8)(arp1394->max_rec));
-		int sspd = arp1394->sspd;
-		u16 maxpayload;
-		struct eth1394_node_ref *node;
-		struct eth1394_node_info *node_info;
-		__be64 guid;
-
-		/* Sanity check. MacOSX seems to be sending us 131 in this
-		 * field (atleast on my Panther G5). Not sure why. */
-		if (sspd > 5 || sspd < 0)
-			sspd = 0;
-
-		maxpayload = min(eth1394_speedto_maxpayload[sspd],
-				 (u16)(1 << (max_rec + 1)));
-
-		guid = get_unaligned(&arp1394->s_uniq_id);
-		node = eth1394_find_node_guid(&priv->ip_node_list,
-					      be64_to_cpu(guid));
-		if (!node)
-			return cpu_to_be16(0);
-
-		node_info = dev_get_drvdata(&node->ud->device);
-
-		/* Update our speed/payload/fifo_offset table */
-		node_info->maxpayload =	maxpayload;
-		node_info->sspd =	sspd;
-		node_info->fifo =	fifo_addr;
-
-		/* Now that we're done with the 1394 specific stuff, we'll
-		 * need to alter some of the data.  Believe it or not, all
-		 * that needs to be done is sender_IP_address needs to be
-		 * moved, the destination hardware address get stuffed
-		 * in and the hardware address length set to 8.
-		 *
-		 * IMPORTANT: The code below overwrites 1394 specific data
-		 * needed above so keep the munging of the data for the
-		 * higher level IP stack last. */
-
-		arp->ar_hln = 8;
-		arp_ptr += arp->ar_hln;		/* skip over sender unique id */
-		*(u32 *)arp_ptr = arp1394->sip;	/* move sender IP addr */
-		arp_ptr += arp->ar_pln;		/* skip over sender IP addr */
-
-		if (arp->ar_op == htons(ARPOP_REQUEST))
-			memset(arp_ptr, 0, sizeof(u64));
-		else
-			memcpy(arp_ptr, dev->dev_addr, sizeof(u64));
-	}
-
-	/* Now add the ethernet header. */
-	if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
-			    skb->len) >= 0)
-		ret = ether1394_type_trans(skb, dev);
-
-	return ret;
-}
-
-static int fragment_overlap(struct list_head *frag_list, int offset, int len)
-{
-	struct fragment_info *fi;
-	int end = offset + len;
-
-	list_for_each_entry(fi, frag_list, list)
-		if (offset < fi->offset + fi->len && end > fi->offset)
-			return 1;
-
-	return 0;
-}
-
-static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
-{
-	struct partial_datagram *pd;
-
-	list_for_each_entry(pd, pdgl, list)
-		if (pd->dgl == dgl)
-			return &pd->list;
-
-	return NULL;
-}
-
-/* Assumes that new fragment does not overlap any existing fragments */
-static int new_fragment(struct list_head *frag_info, int offset, int len)
-{
-	struct list_head *lh;
-	struct fragment_info *fi, *fi2, *new;
-
-	list_for_each(lh, frag_info) {
-		fi = list_entry(lh, struct fragment_info, list);
-		if (fi->offset + fi->len == offset) {
-			/* The new fragment can be tacked on to the end */
-			fi->len += len;
-			/* Did the new fragment plug a hole? */
-			fi2 = list_entry(lh->next, struct fragment_info, list);
-			if (fi->offset + fi->len == fi2->offset) {
-				/* glue fragments together */
-				fi->len += fi2->len;
-				list_del(lh->next);
-				kfree(fi2);
-			}
-			return 0;
-		} else if (offset + len == fi->offset) {
-			/* The new fragment can be tacked on to the beginning */
-			fi->offset = offset;
-			fi->len += len;
-			/* Did the new fragment plug a hole? */
-			fi2 = list_entry(lh->prev, struct fragment_info, list);
-			if (fi2->offset + fi2->len == fi->offset) {
-				/* glue fragments together */
-				fi2->len += fi->len;
-				list_del(lh);
-				kfree(fi);
-			}
-			return 0;
-		} else if (offset > fi->offset + fi->len) {
-			break;
-		} else if (offset + len < fi->offset) {
-			lh = lh->prev;
-			break;
-		}
-	}
-
-	new = kmalloc(sizeof(*new), GFP_ATOMIC);
-	if (!new)
-		return -ENOMEM;
-
-	new->offset = offset;
-	new->len = len;
-
-	list_add(&new->list, lh);
-	return 0;
-}
-
-static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
-				int dgl, int dg_size, char *frag_buf,
-				int frag_off, int frag_len)
-{
-	struct partial_datagram *new;
-
-	new = kmalloc(sizeof(*new), GFP_ATOMIC);
-	if (!new)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&new->frag_info);
-
-	if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
-		kfree(new);
-		return -ENOMEM;
-	}
-
-	new->dgl = dgl;
-	new->dg_size = dg_size;
-
-	new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
-	if (!new->skb) {
-		struct fragment_info *fi = list_entry(new->frag_info.next,
-						      struct fragment_info,
-						      list);
-		kfree(fi);
-		kfree(new);
-		return -ENOMEM;
-	}
-
-	skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
-	new->pbuf = skb_put(new->skb, dg_size);
-	memcpy(new->pbuf + frag_off, frag_buf, frag_len);
-
-	list_add(&new->list, pdgl);
-	return 0;
-}
-
-static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
-				   char *frag_buf, int frag_off, int frag_len)
-{
-	struct partial_datagram *pd =
-			list_entry(lh, struct partial_datagram, list);
-
-	if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
-		return -ENOMEM;
-
-	memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
-
-	/* Move list entry to beginnig of list so that oldest partial
-	 * datagrams percolate to the end of the list */
-	list_move(lh, pdgl);
-	return 0;
-}
-
-static int is_datagram_complete(struct list_head *lh, int dg_size)
-{
-	struct partial_datagram *pd;
-	struct fragment_info *fi;
-
-	pd = list_entry(lh, struct partial_datagram, list);
-	fi = list_entry(pd->frag_info.next, struct fragment_info, list);
-
-	return (fi->len == dg_size);
-}
-
-/* Packet reception. We convert the IP1394 encapsulation header to an
- * ethernet header, and fill it with some of our other fields. This is
- * an incoming packet from the 1394 bus.  */
-static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
-				  char *buf, int len)
-{
-	struct sk_buff *skb;
-	unsigned long flags;
-	struct eth1394_priv *priv = netdev_priv(dev);
-	union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
-	__be16 ether_type = cpu_to_be16(0);  /* initialized to clear warning */
-	int hdr_len;
-	struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
-	struct eth1394_node_info *node_info;
-
-	if (!ud) {
-		struct eth1394_node_ref *node;
-		node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
-		if (unlikely(!node)) {
-			HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
-				   "lookup failure: " NODE_BUS_FMT,
-				   NODE_BUS_ARGS(priv->host, srcid));
-			dev->stats.rx_dropped++;
-			return -1;
-		}
-		ud = node->ud;
-
-		priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
-	}
-
-	node_info = dev_get_drvdata(&ud->device);
-
-	/* First, did we receive a fragmented or unfragmented datagram? */
-	hdr->words.word1 = ntohs(hdr->words.word1);
-
-	hdr_len = hdr_type_len[hdr->common.lf];
-
-	if (hdr->common.lf == ETH1394_HDR_LF_UF) {
-		/* An unfragmented datagram has been received by the ieee1394
-		 * bus. Build an skbuff around it so we can pass it to the
-		 * high level network layer. */
-
-		skb = dev_alloc_skb(len + dev->hard_header_len + 15);
-		if (unlikely(!skb)) {
-			ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
-			dev->stats.rx_dropped++;
-			return -1;
-		}
-		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
-		memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
-		       len - hdr_len);
-		ether_type = hdr->uf.ether_type;
-	} else {
-		/* A datagram fragment has been received, now the fun begins. */
-
-		struct list_head *pdgl, *lh;
-		struct partial_datagram *pd;
-		int fg_off;
-		int fg_len = len - hdr_len;
-		int dg_size;
-		int dgl;
-		int retval;
-		struct pdg_list *pdg = &(node_info->pdg);
-
-		hdr->words.word3 = ntohs(hdr->words.word3);
-		/* The 4th header word is reserved so no need to do ntohs() */
-
-		if (hdr->common.lf == ETH1394_HDR_LF_FF) {
-			ether_type = hdr->ff.ether_type;
-			dgl = hdr->ff.dgl;
-			dg_size = hdr->ff.dg_size + 1;
-			fg_off = 0;
-		} else {
-			hdr->words.word2 = ntohs(hdr->words.word2);
-			dgl = hdr->sf.dgl;
-			dg_size = hdr->sf.dg_size + 1;
-			fg_off = hdr->sf.fg_off;
-		}
-		spin_lock_irqsave(&pdg->lock, flags);
-
-		pdgl = &(pdg->list);
-		lh = find_partial_datagram(pdgl, dgl);
-
-		if (lh == NULL) {
-			while (pdg->sz >= max_partial_datagrams) {
-				/* remove the oldest */
-				purge_partial_datagram(pdgl->prev);
-				pdg->sz--;
-			}
-
-			retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
-						      buf + hdr_len, fg_off,
-						      fg_len);
-			if (retval < 0) {
-				spin_unlock_irqrestore(&pdg->lock, flags);
-				goto bad_proto;
-			}
-			pdg->sz++;
-			lh = find_partial_datagram(pdgl, dgl);
-		} else {
-			pd = list_entry(lh, struct partial_datagram, list);
-
-			if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
-				/* Overlapping fragments, obliterate old
-				 * datagram and start new one. */
-				purge_partial_datagram(lh);
-				retval = new_partial_datagram(dev, pdgl, dgl,
-							      dg_size,
-							      buf + hdr_len,
-							      fg_off, fg_len);
-				if (retval < 0) {
-					pdg->sz--;
-					spin_unlock_irqrestore(&pdg->lock, flags);
-					goto bad_proto;
-				}
-			} else {
-				retval = update_partial_datagram(pdgl, lh,
-								 buf + hdr_len,
-								 fg_off, fg_len);
-				if (retval < 0) {
-					/* Couldn't save off fragment anyway
-					 * so might as well obliterate the
-					 * datagram now. */
-					purge_partial_datagram(lh);
-					pdg->sz--;
-					spin_unlock_irqrestore(&pdg->lock, flags);
-					goto bad_proto;
-				}
-			} /* fragment overlap */
-		} /* new datagram or add to existing one */
-
-		pd = list_entry(lh, struct partial_datagram, list);
-
-		if (hdr->common.lf == ETH1394_HDR_LF_FF)
-			pd->ether_type = ether_type;
-
-		if (is_datagram_complete(lh, dg_size)) {
-			ether_type = pd->ether_type;
-			pdg->sz--;
-			skb = skb_get(pd->skb);
-			purge_partial_datagram(lh);
-			spin_unlock_irqrestore(&pdg->lock, flags);
-		} else {
-			/* Datagram is not complete, we're done for the
-			 * moment. */
-			spin_unlock_irqrestore(&pdg->lock, flags);
-			return 0;
-		}
-	} /* unframgented datagram or fragmented one */
-
-	/* Write metadata, and then pass to the receive level */
-	skb->dev = dev;
-	skb->ip_summed = CHECKSUM_UNNECESSARY;	/* don't check it */
-
-	/* Parse the encapsulation header. This actually does the job of
-	 * converting to an ethernet frame header, aswell as arp
-	 * conversion if needed. ARP conversion is easier in this
-	 * direction, since we are using ethernet as our backend.  */
-	skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
-					      ether_type);
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	if (!skb->protocol) {
-		dev->stats.rx_errors++;
-		dev->stats.rx_dropped++;
-		dev_kfree_skb_any(skb);
-	} else if (netif_rx(skb) == NET_RX_DROP) {
-		dev->stats.rx_errors++;
-		dev->stats.rx_dropped++;
-	} else {
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += skb->len;
-	}
-
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-bad_proto:
-	if (netif_queue_stopped(dev))
-		netif_wake_queue(dev);
-
-	return 0;
-}
-
-static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
-			   quadlet_t *data, u64 addr, size_t len, u16 flags)
-{
-	struct eth1394_host_info *hi;
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-	if (unlikely(!hi)) {
-		ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
-				host->id);
-		return RCODE_ADDRESS_ERROR;
-	}
-
-	if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
-		return RCODE_ADDRESS_ERROR;
-	else
-		return RCODE_COMPLETE;
-}
-
-static void ether1394_iso(struct hpsb_iso *iso)
-{
-	__be32 *data;
-	char *buf;
-	struct eth1394_host_info *hi;
-	struct net_device *dev;
-	unsigned int len;
-	u32 specifier_id;
-	u16 source_id;
-	int i;
-	int nready;
-
-	hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
-	if (unlikely(!hi)) {
-		ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
-				iso->host->id);
-		return;
-	}
-
-	dev = hi->dev;
-
-	nready = hpsb_iso_n_ready(iso);
-	for (i = 0; i < nready; i++) {
-		struct hpsb_iso_packet_info *info =
-			&iso->infos[(iso->first_packet + i) % iso->buf_packets];
-		data = (__be32 *)(iso->data_buf.kvirt + info->offset);
-
-		/* skip over GASP header */
-		buf = (char *)data + 8;
-		len = info->len - 8;
-
-		specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
-			       (be32_to_cpu(data[1]) & 0xff000000) >> 24;
-		source_id = be32_to_cpu(data[0]) >> 16;
-
-		if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
-		    || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
-			/* This packet is not for us */
-			continue;
-		}
-		ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES,
-				       buf, len);
-	}
-
-	hpsb_iso_recv_release_packets(iso, i);
-
-}
-
-/******************************************
- * Datagram transmission code
- ******************************************/
-
-/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire
- * arphdr) is the same format as the ip1394 header, so they overlap.  The rest
- * needs to be munged a bit.  The remainder of the arphdr is formatted based
- * on hwaddr len and ipaddr len.  We know what they'll be, so it's easy to
- * judge.
- *
- * Now that the EUI is used for the hardware address all we need to do to make
- * this work for 1394 is to insert 2 quadlets that contain max_rec size,
- * speed, and unicast FIFO address information between the sender_unique_id
- * and the IP addresses.
- */
-static void ether1394_arp_to_1394arp(struct sk_buff *skb,
-				     struct net_device *dev)
-{
-	struct eth1394_priv *priv = netdev_priv(dev);
-	struct arphdr *arp = (struct arphdr *)skb->data;
-	unsigned char *arp_ptr = (unsigned char *)(arp + 1);
-	struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
-
-	arp1394->hw_addr_len	= 16;
-	arp1394->sip		= *(u32*)(arp_ptr + ETH1394_ALEN);
-	arp1394->max_rec	= priv->host->csr.max_rec;
-	arp1394->sspd		= priv->host->csr.lnk_spd;
-	arp1394->fifo_hi	= htons(priv->local_fifo >> 32);
-	arp1394->fifo_lo	= htonl(priv->local_fifo & ~0x0);
-}
-
-/* We need to encapsulate the standard header with our own. We use the
- * ethernet header's proto for our own. */
-static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
-					       __be16 proto,
-					       union eth1394_hdr *hdr,
-					       u16 dg_size, u16 dgl)
-{
-	unsigned int adj_max_payload =
-				max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
-
-	/* Does it all fit in one packet? */
-	if (dg_size <= adj_max_payload) {
-		hdr->uf.lf = ETH1394_HDR_LF_UF;
-		hdr->uf.ether_type = proto;
-	} else {
-		hdr->ff.lf = ETH1394_HDR_LF_FF;
-		hdr->ff.ether_type = proto;
-		hdr->ff.dg_size = dg_size - 1;
-		hdr->ff.dgl = dgl;
-		adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
-	}
-	return DIV_ROUND_UP(dg_size, adj_max_payload);
-}
-
-static unsigned int ether1394_encapsulate(struct sk_buff *skb,
-					  unsigned int max_payload,
-					  union eth1394_hdr *hdr)
-{
-	union eth1394_hdr *bufhdr;
-	int ftype = hdr->common.lf;
-	int hdrsz = hdr_type_len[ftype];
-	unsigned int adj_max_payload = max_payload - hdrsz;
-
-	switch (ftype) {
-	case ETH1394_HDR_LF_UF:
-		bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
-		bufhdr->words.word1 = htons(hdr->words.word1);
-		bufhdr->words.word2 = hdr->words.word2;
-		break;
-
-	case ETH1394_HDR_LF_FF:
-		bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
-		bufhdr->words.word1 = htons(hdr->words.word1);
-		bufhdr->words.word2 = hdr->words.word2;
-		bufhdr->words.word3 = htons(hdr->words.word3);
-		bufhdr->words.word4 = 0;
-
-		/* Set frag type here for future interior fragments */
-		hdr->common.lf = ETH1394_HDR_LF_IF;
-		hdr->sf.fg_off = 0;
-		break;
-
-	default:
-		hdr->sf.fg_off += adj_max_payload;
-		bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload);
-		if (max_payload >= skb->len)
-			hdr->common.lf = ETH1394_HDR_LF_LF;
-		bufhdr->words.word1 = htons(hdr->words.word1);
-		bufhdr->words.word2 = htons(hdr->words.word2);
-		bufhdr->words.word3 = htons(hdr->words.word3);
-		bufhdr->words.word4 = 0;
-	}
-	return min(max_payload, skb->len);
-}
-
-static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
-{
-	struct hpsb_packet *p;
-
-	p = hpsb_alloc_packet(0);
-	if (p) {
-		p->host = host;
-		p->generation = get_hpsb_generation(host);
-		p->type = hpsb_async;
-	}
-	return p;
-}
-
-static int ether1394_prep_write_packet(struct hpsb_packet *p,
-				       struct hpsb_host *host, nodeid_t node,
-				       u64 addr, void *data, int tx_len)
-{
-	p->node_id = node;
-
-	if (hpsb_get_tlabel(p))
-		return -EAGAIN;
-
-	p->tcode = TCODE_WRITEB;
-	p->header_size = 16;
-	p->expect_response = 1;
-	p->header[0] =
-		p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
-	p->header[1] = host->node_id << 16 | addr >> 32;
-	p->header[2] = addr & 0xffffffff;
-	p->header[3] = tx_len << 16;
-	p->data_size = (tx_len + 3) & ~3;
-	p->data = data;
-
-	return 0;
-}
-
-static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
-				       struct eth1394_priv *priv,
-				       struct sk_buff *skb, int length)
-{
-	p->header_size = 4;
-	p->tcode = TCODE_STREAM_DATA;
-
-	p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
-		       TCODE_STREAM_DATA << 4;
-	p->data_size = length;
-	p->data = (quadlet_t *)skb->data - 2;
-	p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
-				 ETHER1394_GASP_SPECIFIER_ID_HI);
-	p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
-				 ETHER1394_GASP_VERSION);
-
-	p->speed_code = priv->bc_sspd;
-
-	/* prevent hpsb_send_packet() from overriding our speed code */
-	p->node_id = LOCAL_BUS | ALL_NODES;
-}
-
-static void ether1394_free_packet(struct hpsb_packet *packet)
-{
-	if (packet->tcode != TCODE_STREAM_DATA)
-		hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-}
-
-static void ether1394_complete_cb(void *__ptask);
-
-static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
-{
-	struct eth1394_priv *priv = ptask->priv;
-	struct hpsb_packet *packet = NULL;
-
-	packet = ether1394_alloc_common_packet(priv->host);
-	if (!packet)
-		return -ENOMEM;
-
-	if (ptask->tx_type == ETH1394_GASP) {
-		int length = tx_len + 2 * sizeof(quadlet_t);
-
-		ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
-	} else if (ether1394_prep_write_packet(packet, priv->host,
-					       ptask->dest_node,
-					       ptask->addr, ptask->skb->data,
-					       tx_len)) {
-		hpsb_free_packet(packet);
-		return -EAGAIN;
-	}
-
-	ptask->packet = packet;
-	hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb,
-				      ptask);
-
-	if (hpsb_send_packet(packet) < 0) {
-		ether1394_free_packet(packet);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-/* Task function to be run when a datagram transmission is completed */
-static void ether1394_dg_complete(struct packet_task *ptask, int fail)
-{
-	struct sk_buff *skb = ptask->skb;
-	struct net_device *dev = skb->dev;
-	struct eth1394_priv *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	/* Statistics */
-	spin_lock_irqsave(&priv->lock, flags);
-	if (fail) {
-		dev->stats.tx_dropped++;
-		dev->stats.tx_errors++;
-	} else {
-		dev->stats.tx_bytes += skb->len;
-		dev->stats.tx_packets++;
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	dev_kfree_skb_any(skb);
-	kmem_cache_free(packet_task_cache, ptask);
-}
-
-/* Callback for when a packet has been sent and the status of that packet is
- * known */
-static void ether1394_complete_cb(void *__ptask)
-{
-	struct packet_task *ptask = (struct packet_task *)__ptask;
-	struct hpsb_packet *packet = ptask->packet;
-	int fail = 0;
-
-	if (packet->tcode != TCODE_STREAM_DATA)
-		fail = hpsb_packet_success(packet);
-
-	ether1394_free_packet(packet);
-
-	ptask->outstanding_pkts--;
-	if (ptask->outstanding_pkts > 0 && !fail) {
-		int tx_len, err;
-
-		/* Add the encapsulation header to the fragment */
-		tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
-					       &ptask->hdr);
-		err = ether1394_send_packet(ptask, tx_len);
-		if (err) {
-			if (err == -EAGAIN)
-				ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
-
-			ether1394_dg_complete(ptask, 1);
-		}
-	} else {
-		ether1394_dg_complete(ptask, fail);
-	}
-}
-
-/* Transmit a packet (called by kernel) */
-static netdev_tx_t ether1394_tx(struct sk_buff *skb,
-				struct net_device *dev)
-{
-	struct eth1394hdr hdr_buf;
-	struct eth1394_priv *priv = netdev_priv(dev);
-	__be16 proto;
-	unsigned long flags;
-	nodeid_t dest_node;
-	eth1394_tx_type tx_type;
-	unsigned int tx_len;
-	unsigned int max_payload;
-	u16 dg_size;
-	u16 dgl;
-	struct packet_task *ptask;
-	struct eth1394_node_ref *node;
-	struct eth1394_node_info *node_info = NULL;
-
-	ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
-	if (ptask == NULL)
-		goto fail;
-
-	/* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
-	 * it does not set our validity bit. We need to compensate for
-	 * that somewhere else, but not in eth1394. */
-#if 0
-	if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
-		goto fail;
-#endif
-
-	skb = skb_share_check(skb, GFP_ATOMIC);
-	if (!skb)
-		goto fail;
-
-	/* Get rid of the fake eth1394 header, but first make a copy.
-	 * We might need to rebuild the header on tx failure. */
-	memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
-	skb_pull(skb, ETH1394_HLEN);
-
-	proto = hdr_buf.h_proto;
-	dg_size = skb->len;
-
-	/* Set the transmission type for the packet.  ARP packets and IP
-	 * broadcast packets are sent via GASP. */
-	if (memcmp(hdr_buf.h_dest, dev->broadcast, ETH1394_ALEN) == 0 ||
-	    proto == htons(ETH_P_ARP) ||
-	    (proto == htons(ETH_P_IP) &&
-	     IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
-		tx_type = ETH1394_GASP;
-		dest_node = LOCAL_BUS | ALL_NODES;
-		max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
-		BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-		dgl = priv->bc_dgl;
-		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
-			priv->bc_dgl++;
-	} else {
-		__be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
-
-		node = eth1394_find_node_guid(&priv->ip_node_list,
-					      be64_to_cpu(guid));
-		if (!node)
-			goto fail;
-
-		node_info = dev_get_drvdata(&node->ud->device);
-		if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
-			goto fail;
-
-		dest_node = node->ud->ne->nodeid;
-		max_payload = node_info->maxpayload;
-		BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
-
-		dgl = node_info->dgl;
-		if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
-			node_info->dgl++;
-		tx_type = ETH1394_WRREQ;
-	}
-
-	/* If this is an ARP packet, convert it */
-	if (proto == htons(ETH_P_ARP))
-		ether1394_arp_to_1394arp(skb, dev);
-
-	ptask->hdr.words.word1 = 0;
-	ptask->hdr.words.word2 = 0;
-	ptask->hdr.words.word3 = 0;
-	ptask->hdr.words.word4 = 0;
-	ptask->skb = skb;
-	ptask->priv = priv;
-	ptask->tx_type = tx_type;
-
-	if (tx_type != ETH1394_GASP) {
-		u64 addr;
-
-		spin_lock_irqsave(&priv->lock, flags);
-		addr = node_info->fifo;
-		spin_unlock_irqrestore(&priv->lock, flags);
-
-		ptask->addr = addr;
-		ptask->dest_node = dest_node;
-	}
-
-	ptask->tx_type = tx_type;
-	ptask->max_payload = max_payload;
-	ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
-					proto, &ptask->hdr, dg_size, dgl);
-
-	/* Add the encapsulation header to the fragment */
-	tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
-	dev->trans_start = jiffies;
-	if (ether1394_send_packet(ptask, tx_len)) {
-		if (dest_node == (LOCAL_BUS | ALL_NODES))
-			goto fail;
-
-		/* At this point we want to restore the packet.  When we return
-		 * here with NETDEV_TX_BUSY we will get another entrance in this
-		 * routine with the same skb and we need it to look the same.
-		 * So we pull 4 more bytes, then build the header again. */
-		skb_pull(skb, 4);
-		ether1394_header(skb, dev, ntohs(hdr_buf.h_proto),
-				 hdr_buf.h_dest, NULL, 0);
-
-		/* Most failures of ether1394_send_packet are recoverable. */
-		netif_stop_queue(dev);
-		priv->wake_node = dest_node;
-		schedule_work(&priv->wake);
-		kmem_cache_free(packet_task_cache, ptask);
-		return NETDEV_TX_BUSY;
-	}
-
-	return NETDEV_TX_OK;
-fail:
-	if (ptask)
-		kmem_cache_free(packet_task_cache, ptask);
-
-	if (skb != NULL)
-		dev_kfree_skb(skb);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	dev->stats.tx_dropped++;
-	dev->stats.tx_errors++;
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	return NETDEV_TX_OK;
-}
-
-static void ether1394_get_drvinfo(struct net_device *dev,
-				  struct ethtool_drvinfo *info)
-{
-	strcpy(info->driver, driver_name);
-	strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
-}
-
-static const struct ethtool_ops ethtool_ops = {
-	.get_drvinfo = ether1394_get_drvinfo
-};
-
-static int __init ether1394_init_module(void)
-{
-	int err;
-
-	packet_task_cache = kmem_cache_create("packet_task",
-					      sizeof(struct packet_task),
-					      0, 0, NULL);
-	if (!packet_task_cache)
-		return -ENOMEM;
-
-	hpsb_register_highlevel(&eth1394_highlevel);
-	err = hpsb_register_protocol(&eth1394_proto_driver);
-	if (err) {
-		hpsb_unregister_highlevel(&eth1394_highlevel);
-		kmem_cache_destroy(packet_task_cache);
-	}
-	return err;
-}
-
-static void __exit ether1394_exit_module(void)
-{
-	hpsb_unregister_protocol(&eth1394_proto_driver);
-	hpsb_unregister_highlevel(&eth1394_highlevel);
-	kmem_cache_destroy(packet_task_cache);
-}
-
-module_init(ether1394_init_module);
-module_exit(ether1394_exit_module);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/eth1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/eth1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/eth1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/eth1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,234 +0,0 @@
-/*
- * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
- *
- * Copyright (C) 2000 Bonin Franck <boninf@free.fr>
- *           (C) 2001 Ben Collins <bcollins@debian.org>
- *
- * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __ETH1394_H
-#define __ETH1394_H
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-
-/* Register for incoming packets. This is 4096 bytes, which supports up to
- * S3200 (per Table 16-3 of IEEE 1394b-2002). */
-#define ETHER1394_REGION_ADDR_LEN	4096
-
-/* GASP identifier numbers for IPv4 over IEEE 1394 */
-#define ETHER1394_GASP_SPECIFIER_ID	0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI	((0x00005E >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO	(0x00005E & 0xff)
-#define ETHER1394_GASP_VERSION		1
-
-#define ETHER1394_GASP_OVERHEAD	(2 * sizeof(quadlet_t))	/* for GASP header */
-
-#define ETHER1394_GASP_BUFFERS	16
-
-#define NODE_SET		(ALL_NODES + 1)		/* Node set == 64 */
-
-enum eth1394_bc_states { ETHER1394_BC_ERROR,
-			 ETHER1394_BC_RUNNING,
-			 ETHER1394_BC_STOPPED };
-
-
-/* Private structure for our ethernet driver */
-struct eth1394_priv {
-	struct hpsb_host *host;		/* The card for this dev	 */
-	u16 bc_maxpayload;		/* Max broadcast payload	 */
-	u8 bc_sspd;			/* Max broadcast speed		 */
-	u64 local_fifo;			/* Local FIFO Address		 */
-	spinlock_t lock;		/* Private lock			 */
-	int broadcast_channel;		/* Async stream Broadcast Channel */
-	enum eth1394_bc_states bc_state; /* broadcast channel state	 */
-	struct hpsb_iso *iso;		/* Async stream recv handle	 */
-	int bc_dgl;			/* Outgoing broadcast datagram label */
-	struct list_head ip_node_list;	/* List of IP capable nodes	 */
-	struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
-
-	struct work_struct wake;	/* Wake up after xmit failure	 */
-	struct net_device *wake_dev;	/* Stupid backlink for .wake	 */
-	nodeid_t wake_node;		/* Destination of failed xmit	 */
-};
-
-
-/* Define a fake hardware header format for the networking core.  Note that
- * header size cannot exceed 16 bytes as that is the size of the header cache.
- * Also, we do not need the source address in the header so we omit it and
- * keep the header to under 16 bytes */
-#define ETH1394_ALEN (8)
-#define ETH1394_HLEN (10)
-
-struct eth1394hdr {
-	unsigned char	h_dest[ETH1394_ALEN];	/* destination eth1394 addr	*/
-	__be16		h_proto;		/* packet type ID field	*/
-}  __attribute__((packed));
-
-static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
-{
-	return (struct eth1394hdr *)skb_mac_header(skb);
-}
-
-typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
-
-/* IP1394 headers */
-
-/* Unfragmented */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
-	u16 lf:2;
-	u16 res:14;
-	__be16 ether_type;		/* Ethernet packet type */
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_uf_hdr {
-	u16 res:14;
-	u16 lf:2;
-	__be16 ether_type;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* First fragment */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
-	u16 lf:2;
-	u16 res1:2;
-	u16 dg_size:12;		/* Datagram size */
-	__be16 ether_type;		/* Ethernet packet type */
-	u16 dgl;		/* Datagram label */
-	u16 res2;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_ff_hdr {
-	u16 dg_size:12;
-	u16 res1:2;
-	u16 lf:2;
-	__be16 ether_type;
-	u16 dgl;
-	u16 res2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-/* XXX: Subsequent fragments, including last */
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
-	u16 lf:2;
-	u16 res1:2;
-	u16 dg_size:12;		/* Datagram size */
-	u16 res2:4;
-	u16 fg_off:12;		/* Fragment offset */
-	u16 dgl;		/* Datagram label */
-	u16 res3;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_sf_hdr {
-	u16 dg_size:12;
-	u16 res1:2;
-	u16 lf:2;
-	u16 fg_off:12;
-	u16 res2:4;
-	u16 dgl;
-	u16 res3;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-#if defined __BIG_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
-	u16 lf:2;
-	u16 pad1:14;
-} __attribute__((packed));
-#elif defined __LITTLE_ENDIAN_BITFIELD
-struct eth1394_common_hdr {
-	u16 pad1:14;
-	u16 lf:2;
-} __attribute__((packed));
-#else
-#error Unknown bit field type
-#endif
-
-struct eth1394_hdr_words {
-	u16 word1;
-	u16 word2;
-	u16 word3;
-	u16 word4;
-};
-
-union eth1394_hdr {
-	struct eth1394_common_hdr common;
-	struct eth1394_uf_hdr uf;
-	struct eth1394_ff_hdr ff;
-	struct eth1394_sf_hdr sf;
-	struct eth1394_hdr_words words;
-};
-
-/* End of IP1394 headers */
-
-/* Fragment types */
-#define ETH1394_HDR_LF_UF	0	/* unfragmented		*/
-#define ETH1394_HDR_LF_FF	1	/* first fragment	*/
-#define ETH1394_HDR_LF_LF	2	/* last fragment	*/
-#define ETH1394_HDR_LF_IF	3	/* interior fragment	*/
-
-#define IP1394_HW_ADDR_LEN	16	/* As per RFC		*/
-
-/* Our arp packet (ARPHRD_IEEE1394) */
-struct eth1394_arp {
-	u16 hw_type;		/* 0x0018	*/
-	u16 proto_type;		/* 0x0806	*/
-	u8 hw_addr_len;		/* 16 		*/
-	u8 ip_addr_len;		/* 4		*/
-	u16 opcode;		/* ARP Opcode	*/
-	/* Above is exactly the same format as struct arphdr */
-
-	__be64 s_uniq_id;	/* Sender's 64bit EUI		*/
-	u8 max_rec;		/* Sender's max packet size		*/
-	u8 sspd;		/* Sender's max speed			*/
-	__be16 fifo_hi;		/* hi 16bits of sender's FIFO addr	*/
-	__be32 fifo_lo;		/* lo 32bits of sender's FIFO addr	*/
-	u32 sip;		/* Sender's IP Address			*/
-	u32 tip;		/* IP Address of requested hw addr	*/
-};
-
-/* Network timeout */
-#define ETHER1394_TIMEOUT	100000
-
-/* This is our task struct. It's used for the packet complete callback.  */
-struct packet_task {
-	struct sk_buff *skb;
-	int outstanding_pkts;
-	eth1394_tx_type tx_type;
-	int max_payload;
-	struct hpsb_packet *packet;
-	struct eth1394_priv *priv;
-	union eth1394_hdr hdr;
-	u64 addr;
-	u16 dest_node;
-};
-
-#endif /* __ETH1394_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/highlevel.c linux-libre-2.6.37-gnu/drivers/ieee1394/highlevel.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/highlevel.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/highlevel.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,691 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Christian Toegel <christian.toegel@gmx.at>
- *        unregister address space
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        unregister address space
- *
- */
-
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-
-
-struct hl_host_info {
-	struct list_head list;
-	struct hpsb_host *host;
-	size_t size;
-	unsigned long key;
-	void *data;
-};
-
-
-static LIST_HEAD(hl_drivers);
-static DECLARE_RWSEM(hl_drivers_sem);
-
-static LIST_HEAD(hl_irqs);
-static DEFINE_RWLOCK(hl_irqs_lock);
-
-static DEFINE_RWLOCK(addr_space_lock);
-
-
-static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
-					    struct hpsb_host *host)
-{
-	struct hl_host_info *hi = NULL;
-
-	if (!hl || !host)
-		return NULL;
-
-	read_lock(&hl->host_info_lock);
-	list_for_each_entry(hi, &hl->host_info_list, list) {
-		if (hi->host == host) {
-			read_unlock(&hl->host_info_lock);
-			return hi;
-		}
-	}
-	read_unlock(&hl->host_info_lock);
-	return NULL;
-}
-
-/**
- * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
- *
- * Returns a per @host and @hl driver data structure that was previously stored
- * by hpsb_create_hostinfo.
- */
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
-	struct hl_host_info *hi = hl_get_hostinfo(hl, host);
-
-	return hi ? hi->data : NULL;
-}
-
-/**
- * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
- *
- * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
- * to this @hl driver and @host.  If @data_size is zero, then the return here is
- * only valid for error checking.
- */
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			   size_t data_size)
-{
-	struct hl_host_info *hi;
-	void *data;
-	unsigned long flags;
-
-	hi = hl_get_hostinfo(hl, host);
-	if (hi) {
-		HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
-			 " exists", hl->name);
-		return NULL;
-	}
-
-	hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
-	if (!hi)
-		return NULL;
-
-	if (data_size) {
-		data = hi->data = hi + 1;
-		hi->size = data_size;
-	} else
-		data = hi;
-
-	hi->host = host;
-
-	write_lock_irqsave(&hl->host_info_lock, flags);
-	list_add_tail(&hi->list, &hl->host_info_list);
-	write_unlock_irqrestore(&hl->host_info_lock, flags);
-
-	return data;
-}
-
-/**
- * hpsb_set_hostinfo - set the hostinfo pointer to something useful
- *
- * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
- */
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-		      void *data)
-{
-	struct hl_host_info *hi;
-
-	hi = hl_get_hostinfo(hl, host);
-	if (hi) {
-		if (!hi->size && !hi->data) {
-			hi->data = data;
-			return 0;
-		} else
-			HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
-				 "already has data", hl->name);
-	} else
-		HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
-			 hl->name);
-	return -EINVAL;
-}
-
-/**
- * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
- *
- * Free and remove the hostinfo pointer bound to this @hl driver and @host.
- */
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
-{
-	struct hl_host_info *hi;
-
-	hi = hl_get_hostinfo(hl, host);
-	if (hi) {
-		unsigned long flags;
-		write_lock_irqsave(&hl->host_info_lock, flags);
-		list_del(&hi->list);
-		write_unlock_irqrestore(&hl->host_info_lock, flags);
-		kfree(hi);
-	}
-	return;
-}
-
-/**
- * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
- *
- * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
- * @host.
- */
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			   unsigned long key)
-{
-	struct hl_host_info *hi;
-
-	hi = hl_get_hostinfo(hl, host);
-	if (hi)
-		hi->key = key;
-	return;
-}
-
-/**
- * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
- */
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
-{
-	struct hl_host_info *hi;
-	void *data = NULL;
-
-	if (!hl)
-		return NULL;
-
-	read_lock(&hl->host_info_lock);
-	list_for_each_entry(hi, &hl->host_info_list, list) {
-		if (hi->key == key) {
-			data = hi->data;
-			break;
-		}
-	}
-	read_unlock(&hl->host_info_lock);
-	return data;
-}
-
-static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
-{
-	struct hpsb_highlevel *hl = __data;
-
-	hl->add_host(host);
-
-	if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
-		HPSB_ERR("Failed to generate Configuration ROM image for host "
-			 "%s-%d", hl->name, host->id);
-	return 0;
-}
-
-/**
- * hpsb_register_highlevel - register highlevel driver
- *
- * The name pointer in @hl has to stay valid at all times because the string is
- * not copied.
- */
-void hpsb_register_highlevel(struct hpsb_highlevel *hl)
-{
-	unsigned long flags;
-
-	hpsb_init_highlevel(hl);
-	INIT_LIST_HEAD(&hl->addr_list);
-
-	down_write(&hl_drivers_sem);
-	list_add_tail(&hl->hl_list, &hl_drivers);
-	up_write(&hl_drivers_sem);
-
-	write_lock_irqsave(&hl_irqs_lock, flags);
-	list_add_tail(&hl->irq_list, &hl_irqs);
-	write_unlock_irqrestore(&hl_irqs_lock, flags);
-
-	if (hl->add_host)
-		nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
-	return;
-}
-
-static void __delete_addr(struct hpsb_address_serve *as)
-{
-	list_del(&as->host_list);
-	list_del(&as->hl_list);
-	kfree(as);
-}
-
-static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			      int update_cr)
-{
-	unsigned long flags;
-	struct list_head *lh, *next;
-	struct hpsb_address_serve *as;
-
-	/* First, let the highlevel driver unreg */
-	if (hl->remove_host)
-		hl->remove_host(host);
-
-	/* Remove any addresses that are matched for this highlevel driver
-	 * and this particular host. */
-	write_lock_irqsave(&addr_space_lock, flags);
-	list_for_each_safe (lh, next, &hl->addr_list) {
-		as = list_entry(lh, struct hpsb_address_serve, hl_list);
-		if (as->host == host)
-			__delete_addr(as);
-	}
-	write_unlock_irqrestore(&addr_space_lock, flags);
-
-	/* Now update the config-rom to reflect anything removed by the
-	 * highlevel driver. */
-	if (update_cr && host->update_config_rom &&
-	    hpsb_update_config_rom_image(host) < 0)
-		HPSB_ERR("Failed to generate Configuration ROM image for host "
-			 "%s-%d", hl->name, host->id);
-
-	/* Finally remove all the host info associated between these two. */
-	hpsb_destroy_hostinfo(hl, host);
-}
-
-static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
-{
-	struct hpsb_highlevel *hl = __data;
-
-	__unregister_host(hl, host, 1);
-	return 0;
-}
-
-/**
- * hpsb_unregister_highlevel - unregister highlevel driver
- */
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
-{
-	unsigned long flags;
-
-	write_lock_irqsave(&hl_irqs_lock, flags);
-	list_del(&hl->irq_list);
-	write_unlock_irqrestore(&hl_irqs_lock, flags);
-
-	down_write(&hl_drivers_sem);
-	list_del(&hl->hl_list);
-	up_write(&hl_drivers_sem);
-
-	nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
-}
-
-/**
- * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses.  This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets.  The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation.  Address spaces can be
- * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
-					 struct hpsb_host *host,
-					 const struct hpsb_address_ops *ops,
-					 u64 size, u64 alignment,
-					 u64 start, u64 end)
-{
-	struct hpsb_address_serve *as, *a1, *a2;
-	struct list_head *entry;
-	u64 retval = CSR1212_INVALID_ADDR_SPACE;
-	unsigned long flags;
-	u64 align_mask = ~(alignment - 1);
-
-	if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
-	    (hweight64(alignment) != 1)) {
-		HPSB_ERR("%s called with invalid alignment: 0x%048llx",
-			 __func__, (unsigned long long)alignment);
-		return retval;
-	}
-
-	/* default range,
-	 * avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
-	if (start == CSR1212_INVALID_ADDR_SPACE &&
-	    end   == CSR1212_INVALID_ADDR_SPACE) {
-		start = host->middle_addr_space;
-		end   = CSR1212_ALL_SPACE_END;
-	}
-
-	if (((start|end) & ~align_mask) || (start >= end) ||
-	    (end > CSR1212_ALL_SPACE_END)) {
-		HPSB_ERR("%s called with invalid addresses "
-			 "(start = %012Lx  end = %012Lx)", __func__,
-			 (unsigned long long)start,(unsigned long long)end);
-		return retval;
-	}
-
-	as = kmalloc(sizeof(*as), GFP_KERNEL);
-	if (!as)
-		return retval;
-
-	INIT_LIST_HEAD(&as->host_list);
-	INIT_LIST_HEAD(&as->hl_list);
-	as->op = ops;
-	as->host = host;
-
-	write_lock_irqsave(&addr_space_lock, flags);
-	list_for_each(entry, &host->addr_space) {
-		u64 a1sa, a1ea;
-		u64 a2sa, a2ea;
-
-		a1 = list_entry(entry, struct hpsb_address_serve, host_list);
-		a2 = list_entry(entry->next, struct hpsb_address_serve,
-				host_list);
-
-		a1sa = a1->start & align_mask;
-		a1ea = (a1->end + alignment -1) & align_mask;
-		a2sa = a2->start & align_mask;
-		a2ea = (a2->end + alignment -1) & align_mask;
-
-		if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
-		    (a2sa > start)) {
-			as->start = max(start, a1ea);
-			as->end = as->start + size;
-			list_add(&as->host_list, entry);
-			list_add_tail(&as->hl_list, &hl->addr_list);
-			retval = as->start;
-			break;
-		}
-	}
-	write_unlock_irqrestore(&addr_space_lock, flags);
-
-	if (retval == CSR1212_INVALID_ADDR_SPACE)
-		kfree(as);
-	return retval;
-}
-
-/**
- * hpsb_register_addrspace - register a host address space
- *
- * @start and @end are 48 bit pointers and have to be quadlet aligned.
- * @end points to the first address behind the handled addresses.  This
- * function can be called multiple times for a single hpsb_highlevel @hl to
- * implement sparse register sets.  The requested region must not overlap any
- * previously allocated region, otherwise registering will fail.
- *
- * It returns true for successful allocation.  Address spaces can be
- * unregistered with hpsb_unregister_addrspace.  All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel @hl.
- */
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			    const struct hpsb_address_ops *ops,
-			    u64 start, u64 end)
-{
-	struct hpsb_address_serve *as;
-	struct list_head *lh;
-	int retval = 0;
-	unsigned long flags;
-
-	if (((start|end) & 3) || (start >= end) ||
-	    (end > CSR1212_ALL_SPACE_END)) {
-		HPSB_ERR("%s called with invalid addresses", __func__);
-		return 0;
-	}
-
-	as = kmalloc(sizeof(*as), GFP_KERNEL);
-	if (!as)
-		return 0;
-
-	INIT_LIST_HEAD(&as->host_list);
-	INIT_LIST_HEAD(&as->hl_list);
-	as->op = ops;
-	as->start = start;
-	as->end = end;
-	as->host = host;
-
-	write_lock_irqsave(&addr_space_lock, flags);
-	list_for_each(lh, &host->addr_space) {
-		struct hpsb_address_serve *as_this =
-			list_entry(lh, struct hpsb_address_serve, host_list);
-		struct hpsb_address_serve *as_next =
-			list_entry(lh->next, struct hpsb_address_serve,
-				   host_list);
-
-		if (as_this->end > as->start)
-			break;
-
-		if (as_next->start >= as->end) {
-			list_add(&as->host_list, lh);
-			list_add_tail(&as->hl_list, &hl->addr_list);
-			retval = 1;
-			break;
-		}
-	}
-	write_unlock_irqrestore(&addr_space_lock, flags);
-
-	if (retval == 0)
-		kfree(as);
-	return retval;
-}
-
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			      u64 start)
-{
-	int retval = 0;
-	struct hpsb_address_serve *as;
-	struct list_head *lh, *next;
-	unsigned long flags;
-
-	write_lock_irqsave(&addr_space_lock, flags);
-	list_for_each_safe (lh, next, &hl->addr_list) {
-		as = list_entry(lh, struct hpsb_address_serve, hl_list);
-		if (as->start == start && as->host == host) {
-			__delete_addr(as);
-			retval = 1;
-			break;
-		}
-	}
-	write_unlock_irqrestore(&addr_space_lock, flags);
-	return retval;
-}
-
-static const struct hpsb_address_ops dummy_ops;
-
-/* dummy address spaces as lower and upper bounds of the host's a.s. list */
-static void init_hpsb_highlevel(struct hpsb_host *host)
-{
-	INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
-	INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
-	INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
-	INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
-
-	host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
-
-	host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
-	host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
-
-	list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
-	list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
-}
-
-void highlevel_add_host(struct hpsb_host *host)
-{
-	struct hpsb_highlevel *hl;
-
-	init_hpsb_highlevel(host);
-
-	down_read(&hl_drivers_sem);
-	list_for_each_entry(hl, &hl_drivers, hl_list) {
-		if (hl->add_host)
-			hl->add_host(host);
-	}
-	up_read(&hl_drivers_sem);
-	if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
-		HPSB_ERR("Failed to generate Configuration ROM image for host "
-			 "%s-%d", hl->name, host->id);
-}
-
-void highlevel_remove_host(struct hpsb_host *host)
-{
-	struct hpsb_highlevel *hl;
-
-	down_read(&hl_drivers_sem);
-	list_for_each_entry(hl, &hl_drivers, hl_list)
-		__unregister_host(hl, host, 0);
-	up_read(&hl_drivers_sem);
-}
-
-void highlevel_host_reset(struct hpsb_host *host)
-{
-	unsigned long flags;
-	struct hpsb_highlevel *hl;
-
-	read_lock_irqsave(&hl_irqs_lock, flags);
-	list_for_each_entry(hl, &hl_irqs, irq_list) {
-		if (hl->host_reset)
-			hl->host_reset(host);
-	}
-	read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-			   void *data, size_t length)
-{
-	unsigned long flags;
-	struct hpsb_highlevel *hl;
-	int cts = ((quadlet_t *)data)[0] >> 4;
-
-	read_lock_irqsave(&hl_irqs_lock, flags);
-	list_for_each_entry(hl, &hl_irqs, irq_list) {
-		if (hl->fcp_request)
-			hl->fcp_request(host, nodeid, direction, cts, data,
-					length);
-	}
-	read_unlock_irqrestore(&hl_irqs_lock, flags);
-}
-
-/*
- * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
- *
- * These functions are called to handle transactions. They are called when a
- * packet arrives.  The flags argument contains the second word of the first
- * header quadlet of the incoming packet (containing transaction label, retry
- * code, transaction code and priority).  These functions either return a
- * response code or a negative number.  In the first case a response will be
- * generated.  In the latter case, no response will be sent and the driver which
- * handled the request will send the response itself.
- */
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
-		   unsigned int length, u16 flags)
-{
-	struct hpsb_address_serve *as;
-	unsigned int partlength;
-	int rcode = RCODE_ADDRESS_ERROR;
-
-	read_lock(&addr_space_lock);
-	list_for_each_entry(as, &host->addr_space, host_list) {
-		if (as->start > addr)
-			break;
-
-		if (as->end > addr) {
-			partlength = min(as->end - addr, (u64) length);
-
-			if (as->op->read)
-				rcode = as->op->read(host, nodeid, data,
-						     addr, partlength, flags);
-			else
-				rcode = RCODE_TYPE_ERROR;
-
-			data += partlength;
-			length -= partlength;
-			addr += partlength;
-
-			if ((rcode != RCODE_COMPLETE) || !length)
-				break;
-		}
-	}
-	read_unlock(&addr_space_lock);
-
-	if (length && (rcode == RCODE_COMPLETE))
-		rcode = RCODE_ADDRESS_ERROR;
-	return rcode;
-}
-
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
-		    u64 addr, unsigned int length, u16 flags)
-{
-	struct hpsb_address_serve *as;
-	unsigned int partlength;
-	int rcode = RCODE_ADDRESS_ERROR;
-
-	read_lock(&addr_space_lock);
-	list_for_each_entry(as, &host->addr_space, host_list) {
-		if (as->start > addr)
-			break;
-
-		if (as->end > addr) {
-			partlength = min(as->end - addr, (u64) length);
-
-			if (as->op->write)
-				rcode = as->op->write(host, nodeid, destid,
-						      data, addr, partlength,
-						      flags);
-			else
-				rcode = RCODE_TYPE_ERROR;
-
-			data += partlength;
-			length -= partlength;
-			addr += partlength;
-
-			if ((rcode != RCODE_COMPLETE) || !length)
-				break;
-		}
-	}
-	read_unlock(&addr_space_lock);
-
-	if (length && (rcode == RCODE_COMPLETE))
-		rcode = RCODE_ADDRESS_ERROR;
-	return rcode;
-}
-
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-		   u16 flags)
-{
-	struct hpsb_address_serve *as;
-	int rcode = RCODE_ADDRESS_ERROR;
-
-	read_lock(&addr_space_lock);
-	list_for_each_entry(as, &host->addr_space, host_list) {
-		if (as->start > addr)
-			break;
-
-		if (as->end > addr) {
-			if (as->op->lock)
-				rcode = as->op->lock(host, nodeid, store, addr,
-						     data, arg, ext_tcode,
-						     flags);
-			else
-				rcode = RCODE_TYPE_ERROR;
-			break;
-		}
-	}
-	read_unlock(&addr_space_lock);
-	return rcode;
-}
-
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-		     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-		     u16 flags)
-{
-	struct hpsb_address_serve *as;
-	int rcode = RCODE_ADDRESS_ERROR;
-
-	read_lock(&addr_space_lock);
-
-	list_for_each_entry(as, &host->addr_space, host_list) {
-		if (as->start > addr)
-			break;
-
-		if (as->end > addr) {
-			if (as->op->lock64)
-				rcode = as->op->lock64(host, nodeid, store,
-						       addr, data, arg,
-						       ext_tcode, flags);
-			else
-				rcode = RCODE_TYPE_ERROR;
-			break;
-		}
-	}
-	read_unlock(&addr_space_lock);
-	return rcode;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/highlevel.h linux-libre-2.6.37-gnu/drivers/ieee1394/highlevel.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/highlevel.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/highlevel.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,141 +0,0 @@
-#ifndef IEEE1394_HIGHLEVEL_H
-#define IEEE1394_HIGHLEVEL_H
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-struct module;
-
-#include "ieee1394_types.h"
-
-struct hpsb_host;
-
-/* internal to ieee1394 core */
-struct hpsb_address_serve {
-	struct list_head host_list;	/* per host list */
-	struct list_head hl_list;	/* hpsb_highlevel list */
-	const struct hpsb_address_ops *op;
-	struct hpsb_host *host;
-	u64 start;	/* first address handled, quadlet aligned */
-	u64 end;	/* first address behind, quadlet aligned */
-};
-
-/* Only the following structures are of interest to actual highlevel drivers. */
-
-struct hpsb_highlevel {
-	const char *name;
-
-	/* Any of the following pointers can legally be NULL. */
-
-	/* New host initialized.  Will also be called during
-	 * hpsb_register_highlevel for all hosts already installed. */
-	void (*add_host)(struct hpsb_host *host);
-
-	/* Host about to be removed.  Will also be called during
-	 * hpsb_unregister_highlevel once for each host. */
-	void (*remove_host)(struct hpsb_host *host);
-
-	/* Host experienced bus reset with possible configuration changes.
-	 * Note that this one may occur during interrupt/bottom half handling.
-	 * You can not expect to be able to do stock hpsb_reads. */
-	void (*host_reset)(struct hpsb_host *host);
-
-	/* A write request was received on either the FCP_COMMAND (direction =
-	 * 0) or the FCP_RESPONSE (direction = 1) register.  The cts arg
-	 * contains the cts field (first byte of data). */
-	void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
-			    int cts, u8 *data, size_t length);
-
-	/* These are initialized by the subsystem when the
-	 * hpsb_higlevel is registered. */
-	struct list_head hl_list;
-	struct list_head irq_list;
-	struct list_head addr_list;
-
-	struct list_head host_info_list;
-	rwlock_t host_info_lock;
-};
-
-struct hpsb_address_ops {
-	/*
-	 * Null function pointers will make the respective operation complete
-	 * with RCODE_TYPE_ERROR.  Makes for easy to implement read-only
-	 * registers (just leave everything but read NULL).
-	 *
-	 * All functions shall return appropriate IEEE 1394 rcodes.
-	 */
-
-	/* These functions have to implement block reads for themselves.
-	 *
-	 * These functions either return a response code or a negative number.
-	 * In the first case a response will be generated.  In the latter case,
-	 * no response will be sent and the driver which handled the request
-	 * will send the response itself. */
-	int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-		    u64 addr, size_t length, u16 flags);
-	int (*write)(struct hpsb_host *host, int nodeid, int destid,
-		     quadlet_t *data, u64 addr, size_t length, u16 flags);
-
-	/* Lock transactions: write results of ext_tcode operation into
-	 * *store. */
-	int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-		    u16 flags);
-	int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
-		      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-		      u16 flags);
-};
-
-void highlevel_add_host(struct hpsb_host *host);
-void highlevel_remove_host(struct hpsb_host *host);
-void highlevel_host_reset(struct hpsb_host *host);
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
-		   unsigned int length, u16 flags);
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
-		    u64 addr, unsigned int length, u16 flags);
-int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-		   u16 flags);
-int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-		     u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-		     u16 flags);
-void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-			   void *data, size_t length);
-
-/**
- * hpsb_init_highlevel - initialize a struct hpsb_highlevel
- *
- * This is only necessary if hpsb_get_hostinfo_bykey can be called
- * before hpsb_register_highlevel.
- */
-static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
-{
-	rwlock_init(&hl->host_info_lock);
-	INIT_LIST_HEAD(&hl->host_info_list);
-}
-void hpsb_register_highlevel(struct hpsb_highlevel *hl);
-void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
-
-u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
-					 struct hpsb_host *host,
-					 const struct hpsb_address_ops *ops,
-					 u64 size, u64 alignment,
-					 u64 start, u64 end);
-int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			    const struct hpsb_address_ops *ops,
-			    u64 start, u64 end);
-int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			      u64 start);
-
-void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			   size_t data_size);
-void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
-			   unsigned long key);
-void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
-		      void *data);
-
-#endif /* IEEE1394_HIGHLEVEL_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/hosts.c linux-libre-2.6.37-gnu/drivers/ieee1394/hosts.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/hosts.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/hosts.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,249 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Low level (host adapter) management.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- * Copyright (C) 1999 Emanuel Pirker
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/mutex.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
-#include "csr.h"
-#include "config_roms.h"
-
-
-static void delayed_reset_bus(struct work_struct *work)
-{
-	struct hpsb_host *host =
-		container_of(work, struct hpsb_host, delayed_reset.work);
-	u8 generation = host->csr.generation + 1;
-
-	/* The generation field rolls over to 2 rather than 0 per IEEE
-	 * 1394a-2000. */
-	if (generation > 0xf || generation < 2)
-		generation = 2;
-
-	csr_set_bus_info_generation(host->csr.rom, generation);
-	if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
-		/* CSR image creation failed.
-		 * Reset generation field and do not issue a bus reset. */
-		csr_set_bus_info_generation(host->csr.rom,
-					    host->csr.generation);
-		return;
-	}
-
-	host->csr.generation = generation;
-
-	host->update_config_rom = 0;
-	if (host->driver->set_hw_config_rom)
-		host->driver->set_hw_config_rom(host,
-						host->csr.rom->bus_info_data);
-
-	host->csr.gen_timestamp[host->csr.generation] = jiffies;
-	hpsb_reset_bus(host, SHORT_RESET);
-}
-
-static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
-{
-	return 0;
-}
-
-static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
-{
-	return -1;
-}
-
-static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
-			unsigned long arg)
-{
-	return -1;
-}
-
-static struct hpsb_host_driver dummy_driver = {
-	.transmit_packet = dummy_transmit_packet,
-	.devctl =	   dummy_devctl,
-	.isoctl =	   dummy_isoctl
-};
-
-static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
-{
-	int *hostnum = __data;
-
-	if (host->id == *hostnum)
-		return 1;
-
-	return 0;
-}
-
-static DEFINE_MUTEX(host_num_alloc);
-
-/**
- * hpsb_alloc_host - allocate a new host controller.
- * @drv: the driver that will manage the host controller
- * @extra: number of extra bytes to allocate for the driver
- *
- * Allocate a &hpsb_host and initialize the general subsystem specific
- * fields.  If the driver needs to store per host data, as drivers
- * usually do, the amount of memory required can be specified by the
- * @extra parameter.  Once allocated, the driver should initialize the
- * driver specific parts, enable the controller and make it available
- * to the general subsystem using hpsb_add_host().
- *
- * Return Value: a pointer to the &hpsb_host if successful, %NULL if
- * no memory was available.
- */
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
-				  struct device *dev)
-{
-	struct hpsb_host *h;
-	int i;
-	int hostnum = 0;
-
-	h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
-	if (!h)
-		return NULL;
-
-	h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
-	if (!h->csr.rom)
-		goto fail;
-
-	h->hostdata = h + 1;
-	h->driver = drv;
-
-	INIT_LIST_HEAD(&h->pending_packets);
-	INIT_LIST_HEAD(&h->addr_space);
-
-	for (i = 2; i < 16; i++)
-		h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
-
-	atomic_set(&h->generation, 0);
-
-	INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
-	
-	init_timer(&h->timeout);
-	h->timeout.data = (unsigned long) h;
-	h->timeout.function = abort_timedouts;
-	h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
-
-	h->topology_map = h->csr.topology_map + 3;
-	h->speed_map = (u8 *)(h->csr.speed_map + 2);
-
-	mutex_lock(&host_num_alloc);
-	while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
-		hostnum++;
-	mutex_unlock(&host_num_alloc);
-	h->id = hostnum;
-
-	memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
-	h->device.parent = dev;
-	set_dev_node(&h->device, dev_to_node(dev));
-	dev_set_name(&h->device, "fw-host%d", h->id);
-
-	h->host_dev.parent = &h->device;
-	h->host_dev.class = &hpsb_host_class;
-	dev_set_name(&h->host_dev, "fw-host%d", h->id);
-
-	if (device_register(&h->device))
-		goto fail;
-	if (device_register(&h->host_dev)) {
-		device_unregister(&h->device);
-		goto fail;
-	}
-	get_device(&h->device);
-
-	return h;
-
-fail:
-	kfree(h);
-	return NULL;
-}
-
-int hpsb_add_host(struct hpsb_host *host)
-{
-	if (hpsb_default_host_entry(host))
-		return -ENOMEM;
-
-	highlevel_add_host(host);
-	return 0;
-}
-
-void hpsb_resume_host(struct hpsb_host *host)
-{
-	if (host->driver->set_hw_config_rom)
-		host->driver->set_hw_config_rom(host,
-						host->csr.rom->bus_info_data);
-	host->driver->devctl(host, RESET_BUS, SHORT_RESET);
-}
-
-void hpsb_remove_host(struct hpsb_host *host)
-{
-	host->is_shutdown = 1;
-
-	cancel_delayed_work(&host->delayed_reset);
-	flush_scheduled_work();
-
-	host->driver = &dummy_driver;
-	highlevel_remove_host(host);
-
-	device_unregister(&host->host_dev);
-	device_unregister(&host->device);
-}
-
-/**
- * hpsb_update_config_rom_image - updates configuration ROM image of a host
- *
- * Updates the configuration ROM image of a host.  rom_version must be the
- * current version, otherwise it will fail with return value -1. If this
- * host does not support config-rom-update, it will return -%EINVAL.
- * Return value 0 indicates success.
- */
-int hpsb_update_config_rom_image(struct hpsb_host *host)
-{
-	unsigned long reset_delay;
-	int next_gen = host->csr.generation + 1;
-
-	if (!host->update_config_rom)
-		return -EINVAL;
-
-	if (next_gen > 0xf)
-		next_gen = 2;
-
-	/* Stop the delayed interrupt, we're about to change the config rom and
-	 * it would be a waste to do a bus reset twice. */
-	cancel_delayed_work(&host->delayed_reset);
-
-	/* IEEE 1394a-2000 prohibits using the same generation number
-	 * twice in a 60 second period. */
-	if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
-		/* Wait 60 seconds from the last time this generation number was
-		 * used. */
-		reset_delay =
-			(60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
-	else
-		/* Wait 1 second in case some other code wants to change the
-		 * Config ROM in the near future. */
-		reset_delay = HZ;
-
-	PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
-	schedule_delayed_work(&host->delayed_reset, reset_delay);
-
-	return 0;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/hosts.h linux-libre-2.6.37-gnu/drivers/ieee1394/hosts.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/hosts.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/hosts.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,201 +0,0 @@
-#ifndef _IEEE1394_HOSTS_H
-#define _IEEE1394_HOSTS_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/timer.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-#include <asm/atomic.h>
-
-struct pci_dev;
-struct module;
-
-#include "ieee1394_types.h"
-#include "csr.h"
-#include "highlevel.h"
-
-struct hpsb_packet;
-struct hpsb_iso;
-
-struct hpsb_host {
-	struct list_head host_list;
-
-	void *hostdata;
-
-	atomic_t generation;
-
-	struct list_head pending_packets;
-	struct timer_list timeout;
-	unsigned long timeout_interval;
-
-	int node_count;      /* number of identified nodes on this bus */
-	int selfid_count;    /* total number of SelfIDs received */
-	int nodes_active;    /* number of nodes with active link layer */
-
-	nodeid_t node_id;    /* node ID of this host */
-	nodeid_t irm_id;     /* ID of this bus' isochronous resource manager */
-	nodeid_t busmgr_id;  /* ID of this bus' bus manager */
-
-	/* this nodes state */
-	unsigned in_bus_reset:1;
-	unsigned is_shutdown:1;
-	unsigned resume_packet_sent:1;
-
-	/* this nodes' duties on the bus */
-	unsigned is_root:1;
-	unsigned is_cycmst:1;
-	unsigned is_irm:1;
-	unsigned is_busmgr:1;
-
-	int reset_retries;
-	quadlet_t *topology_map;
-	u8 *speed_map;
-
-	int id;
-	struct hpsb_host_driver *driver;
-	struct pci_dev *pdev;
-	struct device device;
-	struct device host_dev;
-
-	struct delayed_work delayed_reset;
-	unsigned config_roms:31;
-	unsigned update_config_rom:1;
-
-	struct list_head addr_space;
-	u64 low_addr_space;	/* upper bound of physical DMA area */
-	u64 middle_addr_space;	/* upper bound of posted write area */
-
-	u8 speed[ALL_NODES];	/* speed between each node and local node */
-
-	/* per node tlabel allocation */
-	u8 next_tl[ALL_NODES];
-	struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
-
-	struct csr_control csr;
-
-	struct hpsb_address_serve dummy_zero_addr;
-	struct hpsb_address_serve dummy_max_addr;
-};
-
-enum devctl_cmd {
-	/* Host is requested to reset its bus and cancel all outstanding async
-	 * requests.  If arg == 1, it shall also attempt to become root on the
-	 * bus.  Return void. */
-	RESET_BUS,
-
-	/* Arg is void, return value is the hardware cycle counter value. */
-	GET_CYCLE_COUNTER,
-
-	/* Set the hardware cycle counter to the value in arg, return void.
-	 * FIXME - setting is probably not required. */
-	SET_CYCLE_COUNTER,
-
-	/* Configure hardware for new bus ID in arg, return void. */
-	SET_BUS_ID,
-
-	/* If arg true, start sending cycle start packets, stop if arg == 0.
-	 * Return void. */
-	ACT_CYCLE_MASTER,
-
-	/* Cancel all outstanding async requests without resetting the bus.
-	 * Return void. */
-	CANCEL_REQUESTS,
-};
-
-enum isoctl_cmd {
-	/* rawiso API - see iso.h for the meanings of these commands
-	 * (they correspond exactly to the hpsb_iso_* API functions)
-	 * INIT = allocate resources
-	 * START = begin transmission/reception
-	 * STOP = halt transmission/reception
-	 * QUEUE/RELEASE = produce/consume packets
-	 * SHUTDOWN = deallocate resources
-	 */
-
-	XMIT_INIT,
-	XMIT_START,
-	XMIT_STOP,
-	XMIT_QUEUE,
-	XMIT_SHUTDOWN,
-
-	RECV_INIT,
-	RECV_LISTEN_CHANNEL,   /* multi-channel only */
-	RECV_UNLISTEN_CHANNEL, /* multi-channel only */
-	RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
-	RECV_START,
-	RECV_STOP,
-	RECV_RELEASE,
-	RECV_SHUTDOWN,
-	RECV_FLUSH
-};
-
-enum reset_types {
-	/* 166 microsecond reset -- only type of reset available on
-	   non-1394a capable controllers */
-	LONG_RESET,
-
-	/* Short (arbitrated) reset -- only available on 1394a capable
-	   controllers */
-	SHORT_RESET,
-
-	/* Variants that set force_root before issueing the bus reset */
-	LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
-
-	/* Variants that clear force_root before issueing the bus reset */
-	LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
-};
-
-struct hpsb_host_driver {
-	struct module *owner;
-	const char *name;
-
-	/* The hardware driver may optionally support a function that is used
-	 * to set the hardware ConfigROM if the hardware supports handling
-	 * reads to the ConfigROM on its own. */
-	void (*set_hw_config_rom)(struct hpsb_host *host,
-				  __be32 *config_rom);
-
-	/* This function shall implement packet transmission based on
-	 * packet->type.  It shall CRC both parts of the packet (unless
-	 * packet->type == raw) and do byte-swapping as necessary or instruct
-	 * the hardware to do so.  It can return immediately after the packet
-	 * was queued for sending.  After sending, hpsb_sent_packet() has to be
-	 * called.  Return 0 on success, negative errno on failure.
-	 * NOTE: The function must be callable in interrupt context.
-	 */
-	int (*transmit_packet)(struct hpsb_host *host,
-			       struct hpsb_packet *packet);
-
-	/* This function requests miscellanous services from the driver, see
-	 * above for command codes and expected actions.  Return -1 for unknown
-	 * command, though that should never happen.
-	 */
-	int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
-
-	 /* ISO transmission/reception functions. Return 0 on success, -1
-	  * (or -EXXX errno code) on failure. If the low-level driver does not
-	  * support the new ISO API, set isoctl to NULL.
-	  */
-	int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
-		      unsigned long arg);
-
-	/* This function is mainly to redirect local CSR reads/locks to the iso
-	 * management registers (bus manager id, bandwidth available, channels
-	 * available) to the hardware registers in OHCI.  reg is 0,1,2,3 for bus
-	 * mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
-	 * as OHCI uses).  data and compare are the new data and expected data
-	 * respectively, return value is the old value.
-	 */
-	quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
-				 quadlet_t data, quadlet_t compare);
-};
-
-struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
-				  struct device *dev);
-int hpsb_add_host(struct hpsb_host *host);
-void hpsb_resume_host(struct hpsb_host *host);
-void hpsb_remove_host(struct hpsb_host *host);
-int hpsb_update_config_rom_image(struct hpsb_host *host);
-
-#endif /* _IEEE1394_HOSTS_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_core.c linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_core.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_core.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_core.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1380 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Core support: hpsb_packet management, packet handling and forwarding to
- *               highlevel or lowlevel code
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        loopback functionality in hpsb_send_packet
- *        allow highlevel drivers to disable automatic response generation
- *              and to generate responses themselves (deferred)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/bitops.h>
-#include <linux/kdev_t.h>
-#include <linux/freezer.h>
-#include <linux/suspend.h>
-#include <linux/kthread.h>
-#include <linux/preempt.h>
-#include <linux/time.h>
-
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include "ieee1394_types.h"
-#include "ieee1394.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ieee1394_transactions.h"
-#include "csr.h"
-#include "nodemgr.h"
-#include "dma.h"
-#include "iso.h"
-#include "config_roms.h"
-
-/*
- * Disable the nodemgr detection and config rom reading functionality.
- */
-static int disable_nodemgr;
-module_param(disable_nodemgr, int, 0444);
-MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
-
-/* Disable Isochronous Resource Manager functionality */
-int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
-MODULE_PARM_DESC(disable_irm,
-		 "Disable Isochronous Resource Manager functionality.");
-
-/* We are GPL, so treat us special */
-MODULE_LICENSE("GPL");
-
-/* Some globals used */
-const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
-struct class *hpsb_protocol_class;
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
-{
-	int i;
-
-	size /= 4;
-	size = (size > 4 ? 4 : size);
-
-	printk(KERN_DEBUG "ieee1394: %s", text);
-	if (speed > -1 && speed < 6)
-		printk(" at %s", hpsb_speedto_str[speed]);
-	printk(":");
-	for (i = 0; i < size; i++)
-		printk(" %08x", data[i]);
-	printk("\n");
-}
-#else
-#define dump_packet(a,b,c,d) do {} while (0)
-#endif
-
-static void abort_requests(struct hpsb_host *host);
-static void queue_packet_complete(struct hpsb_packet *packet);
-
-
-/**
- * hpsb_set_packet_complete_task - set task that runs when a packet completes
- * @packet: the packet whose completion we want the task added to
- * @routine: function to call
- * @data: data (if any) to pass to the above function
- *
- * Set the task that runs when a packet completes. You cannot call this more
- * than once on a single packet before it is sent.
- *
- * Typically, the complete @routine is responsible to call hpsb_free_packet().
- */
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
-				   void (*routine)(void *), void *data)
-{
-	WARN_ON(packet->complete_routine != NULL);
-	packet->complete_routine = routine;
-	packet->complete_data = data;
-	return;
-}
-
-/**
- * hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated, in bytes
- *
- * This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context.  A header block is always included and
- * initialized with zeros.  Its size is big enough to contain all possible 1394
- * headers.  The data block is only allocated if @data_size is not zero.
- *
- * For packets for which responses will be received the @data_size has to be big
- * enough to contain the response's data block since no further allocation
- * occurs at response matching time.
- *
- * The packet's generation value will be set to the current generation number
- * for ease of use.  Remember to overwrite it with your own recorded generation
- * number if you can not be sure that your code will not race with a bus reset.
- *
- * Return value: A pointer to a &struct hpsb_packet or NULL on allocation
- * failure.
- */
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
-{
-	struct hpsb_packet *packet;
-
-	data_size = ((data_size + 3) & ~3);
-
-	packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
-	if (!packet)
-		return NULL;
-
-	packet->state = hpsb_unused;
-	packet->generation = -1;
-	INIT_LIST_HEAD(&packet->driver_list);
-	INIT_LIST_HEAD(&packet->queue);
-	atomic_set(&packet->refcnt, 1);
-
-	if (data_size) {
-		packet->data = packet->embedded_data;
-		packet->allocated_data_size = data_size;
-	}
-	return packet;
-}
-
-/**
- * hpsb_free_packet - free packet and data associated with it
- * @packet: packet to free (is NULL safe)
- *
- * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
- */
-void hpsb_free_packet(struct hpsb_packet *packet)
-{
-	if (packet && atomic_dec_and_test(&packet->refcnt)) {
-		BUG_ON(!list_empty(&packet->driver_list) ||
-		       !list_empty(&packet->queue));
-		kfree(packet);
-	}
-}
-
-/**
- * hpsb_reset_bus - initiate bus reset on the given host
- * @host: host controller whose bus to reset
- * @type: one of enum reset_types
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_reset_bus(struct hpsb_host *host, int type)
-{
-	if (!host->in_bus_reset) {
-		host->driver->devctl(host, RESET_BUS, type);
-		return 0;
-	} else {
-		return 1;
-	}
-}
-
-/**
- * hpsb_read_cycle_timer - read cycle timer register and system time
- * @host: host whose isochronous cycle timer register is read
- * @cycle_timer: address of bitfield to return the register contents
- * @local_time: address to return the system time
- *
- * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
- * format is also read from non-OHCI controllers. * @local_time contains the
- * system time in microseconds since the Epoch, read at the moment when the
- * cycle timer was read.
- *
- * Return value: 0 for success or error number otherwise.
- */
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
-			  u64 *local_time)
-{
-	int ctr;
-	struct timeval tv;
-	unsigned long flags;
-
-	if (!host || !cycle_timer || !local_time)
-		return -EINVAL;
-
-	preempt_disable();
-	local_irq_save(flags);
-
-	ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
-	if (ctr)
-		do_gettimeofday(&tv);
-
-	local_irq_restore(flags);
-	preempt_enable();
-
-	if (!ctr)
-		return -EIO;
-	*cycle_timer = ctr;
-	*local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
-	return 0;
-}
-
-/**
- * hpsb_bus_reset - notify a bus reset to the core
- *
- * For host driver module usage.  Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Returns 1 if bus reset already in progress, 0 otherwise.
- */
-int hpsb_bus_reset(struct hpsb_host *host)
-{
-	if (host->in_bus_reset) {
-		HPSB_NOTICE("%s called while bus reset already in progress",
-			    __func__);
-		return 1;
-	}
-
-	abort_requests(host);
-	host->in_bus_reset = 1;
-	host->irm_id = -1;
-	host->is_irm = 0;
-	host->busmgr_id = -1;
-	host->is_busmgr = 0;
-	host->is_cycmst = 0;
-	host->node_count = 0;
-	host->selfid_count = 0;
-
-	return 0;
-}
-
-
-/*
- * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in
- * case verification failed.
- */
-static int check_selfids(struct hpsb_host *host)
-{
-	int nodeid = -1;
-	int rest_of_selfids = host->selfid_count;
-	struct selfid *sid = (struct selfid *)host->topology_map;
-	struct ext_selfid *esid;
-	int esid_seq = 23;
-
-	host->nodes_active = 0;
-
-	while (rest_of_selfids--) {
-		if (!sid->extended) {
-			nodeid++;
-			esid_seq = 0;
-
-			if (sid->phy_id != nodeid) {
-				HPSB_INFO("SelfIDs failed monotony check with "
-					  "%d", sid->phy_id);
-				return 0;
-			}
-
-			if (sid->link_active) {
-				host->nodes_active++;
-				if (sid->contender)
-					host->irm_id = LOCAL_BUS | sid->phy_id;
-			}
-		} else {
-			esid = (struct ext_selfid *)sid;
-
-			if ((esid->phy_id != nodeid)
-			    || (esid->seq_nr != esid_seq)) {
-				HPSB_INFO("SelfIDs failed monotony check with "
-					  "%d/%d", esid->phy_id, esid->seq_nr);
-				return 0;
-			}
-			esid_seq++;
-		}
-		sid++;
-	}
-
-	esid = (struct ext_selfid *)(sid - 1);
-	while (esid->extended) {
-		if ((esid->porta == SELFID_PORT_PARENT) ||
-		    (esid->portb == SELFID_PORT_PARENT) ||
-		    (esid->portc == SELFID_PORT_PARENT) ||
-		    (esid->portd == SELFID_PORT_PARENT) ||
-		    (esid->porte == SELFID_PORT_PARENT) ||
-		    (esid->portf == SELFID_PORT_PARENT) ||
-		    (esid->portg == SELFID_PORT_PARENT) ||
-		    (esid->porth == SELFID_PORT_PARENT)) {
-			HPSB_INFO("SelfIDs failed root check on "
-				  "extended SelfID");
-			return 0;
-		}
-		esid--;
-	}
-
-	sid = (struct selfid *)esid;
-	if ((sid->port0 == SELFID_PORT_PARENT) ||
-	    (sid->port1 == SELFID_PORT_PARENT) ||
-	    (sid->port2 == SELFID_PORT_PARENT)) {
-		HPSB_INFO("SelfIDs failed root check");
-		return 0;
-	}
-
-	host->node_count = nodeid + 1;
-	return 1;
-}
-
-static void build_speed_map(struct hpsb_host *host, int nodecount)
-{
-	u8 cldcnt[nodecount];
-	u8 *map = host->speed_map;
-	u8 *speedcap = host->speed;
-	u8 local_link_speed = host->csr.lnk_spd;
-	struct selfid *sid;
-	struct ext_selfid *esid;
-	int i, j, n;
-
-	for (i = 0; i < (nodecount * 64); i += 64) {
-		for (j = 0; j < nodecount; j++) {
-			map[i+j] = IEEE1394_SPEED_MAX;
-		}
-	}
-
-	for (i = 0; i < nodecount; i++) {
-		cldcnt[i] = 0;
-	}
-
-	/* find direct children count and speed */
-	for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
-		     n = nodecount - 1;
-	     (void *)sid >= (void *)host->topology_map; sid--) {
-		if (sid->extended) {
-			esid = (struct ext_selfid *)sid;
-
-			if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;
-                } else {
-			if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;
-			if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;
-
-			speedcap[n] = sid->speed;
-			if (speedcap[n] > local_link_speed)
-				speedcap[n] = local_link_speed;
-			n--;
-		}
-	}
-
-	/* set self mapping */
-	for (i = 0; i < nodecount; i++) {
-		map[64*i + i] = speedcap[i];
-	}
-
-	/* fix up direct children count to total children count;
-	 * also fix up speedcaps for sibling and parent communication */
-	for (i = 1; i < nodecount; i++) {
-		for (j = cldcnt[i], n = i - 1; j > 0; j--) {
-			cldcnt[i] += cldcnt[n];
-			speedcap[n] = min(speedcap[n], speedcap[i]);
-			n -= cldcnt[n] + 1;
-		}
-	}
-
-	for (n = 0; n < nodecount; n++) {
-		for (i = n - cldcnt[n]; i <= n; i++) {
-			for (j = 0; j < (n - cldcnt[n]); j++) {
-				map[j*64 + i] = map[i*64 + j] =
-					min(map[i*64 + j], speedcap[n]);
-			}
-			for (j = n + 1; j < nodecount; j++) {
-				map[j*64 + i] = map[i*64 + j] =
-					min(map[i*64 + j], speedcap[n]);
-			}
-		}
-	}
-
-	/* assume a maximum speed for 1394b PHYs, nodemgr will correct it */
-	if (local_link_speed > SELFID_SPEED_UNKNOWN)
-		for (i = 0; i < nodecount; i++)
-			if (speedcap[i] == SELFID_SPEED_UNKNOWN)
-				speedcap[i] = local_link_speed;
-}
-
-
-/**
- * hpsb_selfid_received - hand over received selfid packet to the core
- *
- * For host driver module usage.  Safe to use in interrupt context.
- *
- * The host driver should have done a successful complement check (second
- * quadlet is complement of first) beforehand.
- */
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
-{
-	if (host->in_bus_reset) {
-		HPSB_VERBOSE("Including SelfID 0x%x", sid);
-		host->topology_map[host->selfid_count++] = sid;
-	} else {
-		HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
-			    sid, NODEID_TO_BUS(host->node_id));
-	}
-}
-
-/**
- * hpsb_selfid_complete - notify completion of SelfID stage to the core
- *
- * For host driver module usage.  Safe to use in interrupt context, although
- * quite complex; so you may want to run it in the bottom rather than top half.
- *
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
-{
-	if (!host->in_bus_reset)
-		HPSB_NOTICE("SelfID completion called outside of bus reset!");
-
-	host->node_id = LOCAL_BUS | phyid;
-	host->is_root = isroot;
-
-	if (!check_selfids(host)) {
-		if (host->reset_retries++ < 20) {
-			/* selfid stage did not complete without error */
-			HPSB_NOTICE("Error in SelfID stage, resetting");
-			host->in_bus_reset = 0;
-			/* this should work from ohci1394 now... */
-			hpsb_reset_bus(host, LONG_RESET);
-			return;
-		} else {
-			HPSB_NOTICE("Stopping out-of-control reset loop");
-			HPSB_NOTICE("Warning - topology map and speed map will not be valid");
-			host->reset_retries = 0;
-		}
-	} else {
-		host->reset_retries = 0;
-		build_speed_map(host, host->node_count);
-	}
-
-	HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
-		     "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
-
-	/* irm_id is kept up to date by check_selfids() */
-	if (host->irm_id == host->node_id) {
-		host->is_irm = 1;
-	} else {
-		host->is_busmgr = 0;
-		host->is_irm = 0;
-	}
-
-	if (isroot) {
-		host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
-		host->is_cycmst = 1;
-	}
-	atomic_inc(&host->generation);
-	host->in_bus_reset = 0;
-	highlevel_host_reset(host);
-}
-
-static DEFINE_SPINLOCK(pending_packets_lock);
-
-/**
- * hpsb_packet_sent - notify core of sending a packet
- *
- * For host driver module usage.  Safe to call from within a transmit packet
- * routine.
- *
- * Notify core of sending a packet.  Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic).
- */
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
-		      int ackcode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pending_packets_lock, flags);
-
-	packet->ack_code = ackcode;
-
-	if (packet->no_waiter || packet->state == hpsb_complete) {
-		/* if packet->no_waiter, must not have a tlabel allocated */
-		spin_unlock_irqrestore(&pending_packets_lock, flags);
-		hpsb_free_packet(packet);
-		return;
-	}
-
-	atomic_dec(&packet->refcnt);	/* drop HC's reference */
-	/* here the packet must be on the host->pending_packets queue */
-
-	if (ackcode != ACK_PENDING || !packet->expect_response) {
-		packet->state = hpsb_complete;
-		list_del_init(&packet->queue);
-		spin_unlock_irqrestore(&pending_packets_lock, flags);
-		queue_packet_complete(packet);
-		return;
-	}
-
-	packet->state = hpsb_pending;
-	packet->sendtime = jiffies;
-
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-	mod_timer(&host->timeout, jiffies + host->timeout_interval);
-}
-
-/**
- * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
- * @host: host that PHY config packet gets sent through
- * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
- * @gapcnt: gap count value to set (-1 = don't set gap count)
- *
- * This function sends a PHY config packet on the bus through the specified
- * host.
- *
- * Return value: 0 for success or negative error number otherwise.
- */
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
-{
-	struct hpsb_packet *packet;
-	quadlet_t d = 0;
-	int retval = 0;
-
-	if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
-	   (rootid == -1 && gapcnt == -1)) {
-		HPSB_DEBUG("Invalid Parameter: rootid = %d   gapcnt = %d",
-			   rootid, gapcnt);
-		return -EINVAL;
-	}
-
-	if (rootid != -1)
-		d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
-	if (gapcnt != -1)
-		d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
-
-	packet = hpsb_make_phypacket(host, d);
-	if (!packet)
-		return -ENOMEM;
-
-	packet->generation = get_hpsb_generation(host);
-	retval = hpsb_send_packet_and_wait(packet);
-	hpsb_free_packet(packet);
-
-	return retval;
-}
-
-/**
- * hpsb_send_packet - transmit a packet on the bus
- * @packet: packet to send
- *
- * The packet is sent through the host specified in the packet->host field.
- * Before sending, the packet's transmit speed is automatically determined
- * using the local speed map when it is an async, non-broadcast packet.
- *
- * Possibilities for failure are that host is either not initialized, in bus
- * reset, the packet's generation number doesn't match the current generation
- * number or the host reports a transmit error.
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet(struct hpsb_packet *packet)
-{
-	struct hpsb_host *host = packet->host;
-
-	if (host->is_shutdown)
-		return -EINVAL;
-	if (host->in_bus_reset ||
-	    (packet->generation != get_hpsb_generation(host)))
-		return -EAGAIN;
-
-	packet->state = hpsb_queued;
-
-	/* This just seems silly to me */
-	WARN_ON(packet->no_waiter && packet->expect_response);
-
-	if (!packet->no_waiter || packet->expect_response) {
-		unsigned long flags;
-
-		atomic_inc(&packet->refcnt);
-		/* Set the initial "sendtime" to 10 seconds from now, to
-		   prevent premature expiry.  If a packet takes more than
-		   10 seconds to hit the wire, we have bigger problems :) */
-		packet->sendtime = jiffies + 10 * HZ;
-		spin_lock_irqsave(&pending_packets_lock, flags);
-		list_add_tail(&packet->queue, &host->pending_packets);
-		spin_unlock_irqrestore(&pending_packets_lock, flags);
-	}
-
-	if (packet->node_id == host->node_id) {
-		/* it is a local request, so handle it locally */
-
-		quadlet_t *data;
-		size_t size = packet->data_size + packet->header_size;
-
-		data = kmalloc(size, GFP_ATOMIC);
-		if (!data) {
-			HPSB_ERR("unable to allocate memory for concatenating header and data");
-			return -ENOMEM;
-		}
-
-		memcpy(data, packet->header, packet->header_size);
-
-		if (packet->data_size)
-			memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
-
-		dump_packet("send packet local", packet->header, packet->header_size, -1);
-
-		hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
-		hpsb_packet_received(host, data, size, 0);
-
-		kfree(data);
-
-		return 0;
-	}
-
-	if (packet->type == hpsb_async &&
-	    NODEID_TO_NODE(packet->node_id) != ALL_NODES)
-		packet->speed_code =
-			host->speed[NODEID_TO_NODE(packet->node_id)];
-
-	dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
-
-	return host->driver->transmit_packet(host, packet);
-}
-
-/* We could just use complete() directly as the packet complete
- * callback, but this is more typesafe, in the sense that we get a
- * compiler error if the prototype for complete() changes. */
-
-static void complete_packet(void *data)
-{
-	complete((struct completion *) data);
-}
-
-/**
- * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
- * @packet: packet to send
- *
- * Return value: 0 on success, negative errno on failure.
- */
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
-{
-	struct completion done;
-	int retval;
-
-	init_completion(&done);
-	hpsb_set_packet_complete_task(packet, complete_packet, &done);
-	retval = hpsb_send_packet(packet);
-	if (retval == 0)
-		wait_for_completion(&done);
-
-	return retval;
-}
-
-static void send_packet_nocare(struct hpsb_packet *packet)
-{
-	if (hpsb_send_packet(packet) < 0) {
-		hpsb_free_packet(packet);
-	}
-}
-
-static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
-				       size_t buffer_size, int tcode)
-{
-	size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
-
-	if (unlikely(ret > buffer_size))
-		ret = buffer_size;
-
-	if (unlikely(ret + header_size != packet_size))
-		HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
-			 packet_size, tcode);
-	return ret;
-}
-
-static void handle_packet_response(struct hpsb_host *host, int tcode,
-				   quadlet_t *data, size_t size)
-{
-	struct hpsb_packet *packet;
-	int tlabel = (data[0] >> 10) & 0x3f;
-	size_t header_size;
-	unsigned long flags;
-
-	spin_lock_irqsave(&pending_packets_lock, flags);
-
-	list_for_each_entry(packet, &host->pending_packets, queue)
-		if (packet->tlabel == tlabel &&
-		    packet->node_id == (data[1] >> 16))
-			goto found;
-
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-	HPSB_DEBUG("unsolicited response packet received - %s",
-		   "no tlabel match");
-	dump_packet("contents", data, 16, -1);
-	return;
-
-found:
-	switch (packet->tcode) {
-	case TCODE_WRITEQ:
-	case TCODE_WRITEB:
-		if (unlikely(tcode != TCODE_WRITE_RESPONSE))
-			break;
-		header_size = 12;
-		size = 0;
-		goto dequeue;
-
-	case TCODE_READQ:
-		if (unlikely(tcode != TCODE_READQ_RESPONSE))
-			break;
-		header_size = 16;
-		size = 0;
-		goto dequeue;
-
-	case TCODE_READB:
-		if (unlikely(tcode != TCODE_READB_RESPONSE))
-			break;
-		header_size = 16;
-		size = packet_size_to_data_size(size, header_size,
-						packet->allocated_data_size,
-						tcode);
-		goto dequeue;
-
-	case TCODE_LOCK_REQUEST:
-		if (unlikely(tcode != TCODE_LOCK_RESPONSE))
-			break;
-		header_size = 16;
-		size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
-						header_size,
-						packet->allocated_data_size,
-						tcode);
-		goto dequeue;
-	}
-
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-	HPSB_DEBUG("unsolicited response packet received - %s",
-		   "tcode mismatch");
-	dump_packet("contents", data, 16, -1);
-	return;
-
-dequeue:
-	list_del_init(&packet->queue);
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-	if (packet->state == hpsb_queued) {
-		packet->sendtime = jiffies;
-		packet->ack_code = ACK_PENDING;
-	}
-	packet->state = hpsb_complete;
-
-	memcpy(packet->header, data, header_size);
-	if (size)
-		memcpy(packet->data, data + 4, size);
-
-	queue_packet_complete(packet);
-}
-
-
-static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
-					       quadlet_t *data, size_t dsize)
-{
-	struct hpsb_packet *p;
-
-	p = hpsb_alloc_packet(dsize);
-	if (unlikely(p == NULL)) {
-		/* FIXME - send data_error response */
-		HPSB_ERR("out of memory, cannot send response packet");
-		return NULL;
-	}
-
-	p->type = hpsb_async;
-	p->state = hpsb_unused;
-	p->host = host;
-	p->node_id = data[1] >> 16;
-	p->tlabel = (data[0] >> 10) & 0x3f;
-	p->no_waiter = 1;
-
-	p->generation = get_hpsb_generation(host);
-
-	if (dsize % 4)
-		p->data[dsize / 4] = 0;
-
-	return p;
-}
-
-#define PREP_ASYNC_HEAD_RCODE(tc) \
-	packet->tcode = tc; \
-	packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
-		| (1 << 8) | (tc << 4); \
-	packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \
-	packet->header[2] = 0
-
-static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
-			      quadlet_t data)
-{
-	PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
-	packet->header[3] = data;
-	packet->header_size = 16;
-	packet->data_size = 0;
-}
-
-static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
-			       int length)
-{
-	if (rcode != RCODE_COMPLETE)
-		length = 0;
-
-	PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);
-	packet->header[3] = length << 16;
-	packet->header_size = 16;
-	packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
-{
-	PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
-	packet->header_size = 12;
-	packet->data_size = 0;
-}
-
-static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
-			  int length)
-{
-	if (rcode != RCODE_COMPLETE)
-		length = 0;
-
-	PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);
-	packet->header[3] = (length << 16) | extcode;
-	packet->header_size = 16;
-	packet->data_size = length;
-}
-
-static void handle_incoming_packet(struct hpsb_host *host, int tcode,
-				   quadlet_t *data, size_t size,
-				   int write_acked)
-{
-	struct hpsb_packet *packet;
-	int length, rcode, extcode;
-	quadlet_t buffer;
-	nodeid_t source = data[1] >> 16;
-	nodeid_t dest = data[0] >> 16;
-	u16 flags = (u16) data[0];
-	u64 addr;
-
-	/* FIXME?
-	 * Out-of-bounds lengths are left for highlevel_read|write to cap. */
-
-	switch (tcode) {
-	case TCODE_WRITEQ:
-		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_write(host, source, dest, data + 3,
-					addr, 4, flags);
-		goto handle_write_request;
-
-	case TCODE_WRITEB:
-		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_write(host, source, dest, data + 4,
-					addr, data[3] >> 16, flags);
-handle_write_request:
-		if (rcode < 0 || write_acked ||
-		    NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
-			return;
-		/* not a broadcast write, reply */
-		packet = create_reply_packet(host, data, 0);
-		if (packet) {
-			fill_async_write_resp(packet, rcode);
-			send_packet_nocare(packet);
-		}
-		return;
-
-	case TCODE_READQ:
-		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
-		if (rcode < 0)
-			return;
-
-		packet = create_reply_packet(host, data, 0);
-		if (packet) {
-			fill_async_readquad_resp(packet, rcode, buffer);
-			send_packet_nocare(packet);
-		}
-		return;
-
-	case TCODE_READB:
-		length = data[3] >> 16;
-		packet = create_reply_packet(host, data, length);
-		if (!packet)
-			return;
-
-		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-		rcode = highlevel_read(host, source, packet->data, addr,
-				       length, flags);
-		if (rcode < 0) {
-			hpsb_free_packet(packet);
-			return;
-		}
-		fill_async_readblock_resp(packet, rcode, length);
-		send_packet_nocare(packet);
-		return;
-
-	case TCODE_LOCK_REQUEST:
-		length = data[3] >> 16;
-		extcode = data[3] & 0xffff;
-		addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-
-		packet = create_reply_packet(host, data, 8);
-		if (!packet)
-			return;
-
-		if (extcode == 0 || extcode >= 7) {
-			/* let switch default handle error */
-			length = 0;
-		}
-
-		switch (length) {
-		case 4:
-			rcode = highlevel_lock(host, source, packet->data, addr,
-					       data[4], 0, extcode, flags);
-			fill_async_lock_resp(packet, rcode, extcode, 4);
-			break;
-		case 8:
-			if (extcode != EXTCODE_FETCH_ADD &&
-			    extcode != EXTCODE_LITTLE_ADD) {
-				rcode = highlevel_lock(host, source,
-						       packet->data, addr,
-						       data[5], data[4],
-						       extcode, flags);
-				fill_async_lock_resp(packet, rcode, extcode, 4);
-			} else {
-				rcode = highlevel_lock64(host, source,
-					     (octlet_t *)packet->data, addr,
-					     *(octlet_t *)(data + 4), 0ULL,
-					     extcode, flags);
-				fill_async_lock_resp(packet, rcode, extcode, 8);
-			}
-			break;
-		case 16:
-			rcode = highlevel_lock64(host, source,
-						 (octlet_t *)packet->data, addr,
-						 *(octlet_t *)(data + 6),
-						 *(octlet_t *)(data + 4),
-						 extcode, flags);
-			fill_async_lock_resp(packet, rcode, extcode, 8);
-			break;
-		default:
-			rcode = RCODE_TYPE_ERROR;
-			fill_async_lock_resp(packet, rcode, extcode, 0);
-		}
-
-		if (rcode < 0)
-			hpsb_free_packet(packet);
-		else
-			send_packet_nocare(packet);
-		return;
-	}
-}
-
-/**
- * hpsb_packet_received - hand over received packet to the core
- *
- * For host driver module usage.
- *
- * The contents of data are expected to be the full packet but with the CRCs
- * left out (data block follows header immediately), with the header (i.e. the
- * first four quadlets) in machine byte order and the data block in big endian.
- * *@data can be safely overwritten after this call.
- *
- * If the packet is a write request, @write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise.  This argument is ignored for any
- * other packet type.
- */
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
-			  int write_acked)
-{
-	int tcode;
-
-	if (unlikely(host->in_bus_reset)) {
-		HPSB_DEBUG("received packet during reset; ignoring");
-		return;
-	}
-
-	dump_packet("received packet", data, size, -1);
-
-	tcode = (data[0] >> 4) & 0xf;
-
-	switch (tcode) {
-	case TCODE_WRITE_RESPONSE:
-	case TCODE_READQ_RESPONSE:
-	case TCODE_READB_RESPONSE:
-	case TCODE_LOCK_RESPONSE:
-		handle_packet_response(host, tcode, data, size);
-		break;
-
-	case TCODE_WRITEQ:
-	case TCODE_WRITEB:
-	case TCODE_READQ:
-	case TCODE_READB:
-	case TCODE_LOCK_REQUEST:
-		handle_incoming_packet(host, tcode, data, size, write_acked);
-		break;
-
-	case TCODE_CYCLE_START:
-		/* simply ignore this packet if it is passed on */
-		break;
-
-	default:
-		HPSB_DEBUG("received packet with bogus transaction code %d",
-			   tcode);
-		break;
-	}
-}
-
-static void abort_requests(struct hpsb_host *host)
-{
-	struct hpsb_packet *packet, *p;
-	struct list_head tmp;
-	unsigned long flags;
-
-	host->driver->devctl(host, CANCEL_REQUESTS, 0);
-
-	INIT_LIST_HEAD(&tmp);
-	spin_lock_irqsave(&pending_packets_lock, flags);
-	list_splice_init(&host->pending_packets, &tmp);
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-	list_for_each_entry_safe(packet, p, &tmp, queue) {
-		list_del_init(&packet->queue);
-		packet->state = hpsb_complete;
-		packet->ack_code = ACKX_ABORTED;
-		queue_packet_complete(packet);
-	}
-}
-
-void abort_timedouts(unsigned long __opaque)
-{
-	struct hpsb_host *host = (struct hpsb_host *)__opaque;
-	struct hpsb_packet *packet, *p;
-	struct list_head tmp;
-	unsigned long flags, expire, j;
-
-	spin_lock_irqsave(&host->csr.lock, flags);
-	expire = host->csr.expire;
-	spin_unlock_irqrestore(&host->csr.lock, flags);
-
-	j = jiffies;
-	INIT_LIST_HEAD(&tmp);
-	spin_lock_irqsave(&pending_packets_lock, flags);
-
-	list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
-		if (time_before(packet->sendtime + expire, j))
-			list_move_tail(&packet->queue, &tmp);
-		else
-			/* Since packets are added to the tail, the oldest
-			 * ones are first, always. When we get to one that
-			 * isn't timed out, the rest aren't either. */
-			break;
-	}
-	if (!list_empty(&host->pending_packets))
-		mod_timer(&host->timeout, j + host->timeout_interval);
-
-	spin_unlock_irqrestore(&pending_packets_lock, flags);
-
-	list_for_each_entry_safe(packet, p, &tmp, queue) {
-		list_del_init(&packet->queue);
-		packet->state = hpsb_complete;
-		packet->ack_code = ACKX_TIMEOUT;
-		queue_packet_complete(packet);
-	}
-}
-
-static struct task_struct *khpsbpkt_thread;
-static LIST_HEAD(hpsbpkt_queue);
-
-static void queue_packet_complete(struct hpsb_packet *packet)
-{
-	unsigned long flags;
-
-	if (packet->no_waiter) {
-		hpsb_free_packet(packet);
-		return;
-	}
-	if (packet->complete_routine != NULL) {
-		spin_lock_irqsave(&pending_packets_lock, flags);
-		list_add_tail(&packet->queue, &hpsbpkt_queue);
-		spin_unlock_irqrestore(&pending_packets_lock, flags);
-		wake_up_process(khpsbpkt_thread);
-	}
-	return;
-}
-
-/*
- * Kernel thread which handles packets that are completed.  This way the
- * packet's "complete" function is asynchronously run in process context.
- * Only packets which have a "complete" function may be sent here.
- */
-static int hpsbpkt_thread(void *__hi)
-{
-	struct hpsb_packet *packet, *p;
-	struct list_head tmp;
-	int may_schedule;
-
-	while (!kthread_should_stop()) {
-
-		INIT_LIST_HEAD(&tmp);
-		spin_lock_irq(&pending_packets_lock);
-		list_splice_init(&hpsbpkt_queue, &tmp);
-		spin_unlock_irq(&pending_packets_lock);
-
-		list_for_each_entry_safe(packet, p, &tmp, queue) {
-			list_del_init(&packet->queue);
-			packet->complete_routine(packet->complete_data);
-		}
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irq(&pending_packets_lock);
-		may_schedule = list_empty(&hpsbpkt_queue);
-		spin_unlock_irq(&pending_packets_lock);
-		if (may_schedule)
-			schedule();
-		__set_current_state(TASK_RUNNING);
-	}
-	return 0;
-}
-
-static int __init ieee1394_init(void)
-{
-	int i, ret;
-
-	/* non-fatal error */
-	if (hpsb_init_config_roms()) {
-		HPSB_ERR("Failed to initialize some config rom entries.\n");
-		HPSB_ERR("Some features may not be available\n");
-	}
-
-	khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
-	if (IS_ERR(khpsbpkt_thread)) {
-		HPSB_ERR("Failed to start hpsbpkt thread!\n");
-		ret = PTR_ERR(khpsbpkt_thread);
-		goto exit_cleanup_config_roms;
-	}
-
-	if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
-		HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
-		ret = -ENODEV;
-		goto exit_release_kernel_thread;
-	}
-
-	ret = bus_register(&ieee1394_bus_type);
-	if (ret < 0) {
-		HPSB_INFO("bus register failed");
-		goto release_chrdev;
-	}
-
-	for (i = 0; fw_bus_attrs[i]; i++) {
-		ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-		if (ret < 0) {
-			while (i >= 0) {
-				bus_remove_file(&ieee1394_bus_type,
-						fw_bus_attrs[i--]);
-			}
-			bus_unregister(&ieee1394_bus_type);
-			goto release_chrdev;
-		}
-	}
-
-	ret = class_register(&hpsb_host_class);
-	if (ret < 0)
-		goto release_all_bus;
-
-	hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
-	if (IS_ERR(hpsb_protocol_class)) {
-		ret = PTR_ERR(hpsb_protocol_class);
-		goto release_class_host;
-	}
-
-	ret = init_csr();
-	if (ret) {
-		HPSB_INFO("init csr failed");
-		ret = -ENOMEM;
-		goto release_class_protocol;
-	}
-
-	if (disable_nodemgr) {
-		HPSB_INFO("nodemgr and IRM functionality disabled");
-		/* We shouldn't contend for IRM with nodemgr disabled, since
-		   nodemgr implements functionality required of ieee1394a-2000
-		   IRMs */
-		hpsb_disable_irm = 1;
-
-		return 0;
-	}
-
-	if (hpsb_disable_irm) {
-		HPSB_INFO("IRM functionality disabled");
-	}
-
-	ret = init_ieee1394_nodemgr();
-	if (ret < 0) {
-		HPSB_INFO("init nodemgr failed");
-		goto cleanup_csr;
-	}
-
-	return 0;
-
-cleanup_csr:
-	cleanup_csr();
-release_class_protocol:
-	class_destroy(hpsb_protocol_class);
-release_class_host:
-	class_unregister(&hpsb_host_class);
-release_all_bus:
-	for (i = 0; fw_bus_attrs[i]; i++)
-		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-	bus_unregister(&ieee1394_bus_type);
-release_chrdev:
-	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-exit_release_kernel_thread:
-	kthread_stop(khpsbpkt_thread);
-exit_cleanup_config_roms:
-	hpsb_cleanup_config_roms();
-	return ret;
-}
-
-static void __exit ieee1394_cleanup(void)
-{
-	int i;
-
-	if (!disable_nodemgr)
-		cleanup_ieee1394_nodemgr();
-
-	cleanup_csr();
-
-	class_destroy(hpsb_protocol_class);
-	class_unregister(&hpsb_host_class);
-	for (i = 0; fw_bus_attrs[i]; i++)
-		bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
-	bus_unregister(&ieee1394_bus_type);
-
-	kthread_stop(khpsbpkt_thread);
-
-	hpsb_cleanup_config_roms();
-
-	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
-}
-
-fs_initcall(ieee1394_init);
-module_exit(ieee1394_cleanup);
-
-/* Exported symbols */
-
-/** hosts.c **/
-EXPORT_SYMBOL(hpsb_alloc_host);
-EXPORT_SYMBOL(hpsb_add_host);
-EXPORT_SYMBOL(hpsb_resume_host);
-EXPORT_SYMBOL(hpsb_remove_host);
-EXPORT_SYMBOL(hpsb_update_config_rom_image);
-
-/** ieee1394_core.c **/
-EXPORT_SYMBOL(hpsb_speedto_str);
-EXPORT_SYMBOL(hpsb_protocol_class);
-EXPORT_SYMBOL(hpsb_set_packet_complete_task);
-EXPORT_SYMBOL(hpsb_alloc_packet);
-EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_reset_bus);
-EXPORT_SYMBOL(hpsb_read_cycle_timer);
-EXPORT_SYMBOL(hpsb_bus_reset);
-EXPORT_SYMBOL(hpsb_selfid_received);
-EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_packet_sent);
-EXPORT_SYMBOL(hpsb_packet_received);
-EXPORT_SYMBOL_GPL(hpsb_disable_irm);
-
-/** ieee1394_transactions.c **/
-EXPORT_SYMBOL(hpsb_get_tlabel);
-EXPORT_SYMBOL(hpsb_free_tlabel);
-EXPORT_SYMBOL(hpsb_make_readpacket);
-EXPORT_SYMBOL(hpsb_make_writepacket);
-EXPORT_SYMBOL(hpsb_make_streampacket);
-EXPORT_SYMBOL(hpsb_make_lockpacket);
-EXPORT_SYMBOL(hpsb_make_lock64packet);
-EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_read);
-EXPORT_SYMBOL(hpsb_write);
-EXPORT_SYMBOL(hpsb_lock);
-EXPORT_SYMBOL(hpsb_packet_success);
-
-/** highlevel.c **/
-EXPORT_SYMBOL(hpsb_register_highlevel);
-EXPORT_SYMBOL(hpsb_unregister_highlevel);
-EXPORT_SYMBOL(hpsb_register_addrspace);
-EXPORT_SYMBOL(hpsb_unregister_addrspace);
-EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_get_hostinfo);
-EXPORT_SYMBOL(hpsb_create_hostinfo);
-EXPORT_SYMBOL(hpsb_destroy_hostinfo);
-EXPORT_SYMBOL(hpsb_set_hostinfo_key);
-EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
-EXPORT_SYMBOL(hpsb_set_hostinfo);
-
-/** nodemgr.c **/
-EXPORT_SYMBOL(hpsb_node_fill_packet);
-EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(__hpsb_register_protocol);
-EXPORT_SYMBOL(hpsb_unregister_protocol);
-
-/** csr.c **/
-EXPORT_SYMBOL(hpsb_update_config_rom);
-
-/** dma.c **/
-EXPORT_SYMBOL(dma_prog_region_init);
-EXPORT_SYMBOL(dma_prog_region_alloc);
-EXPORT_SYMBOL(dma_prog_region_free);
-EXPORT_SYMBOL(dma_region_init);
-EXPORT_SYMBOL(dma_region_alloc);
-EXPORT_SYMBOL(dma_region_free);
-EXPORT_SYMBOL(dma_region_sync_for_cpu);
-EXPORT_SYMBOL(dma_region_sync_for_device);
-EXPORT_SYMBOL(dma_region_mmap);
-EXPORT_SYMBOL(dma_region_offset_to_bus);
-
-/** iso.c **/
-EXPORT_SYMBOL(hpsb_iso_xmit_init);
-EXPORT_SYMBOL(hpsb_iso_recv_init);
-EXPORT_SYMBOL(hpsb_iso_xmit_start);
-EXPORT_SYMBOL(hpsb_iso_recv_start);
-EXPORT_SYMBOL(hpsb_iso_recv_listen_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel);
-EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask);
-EXPORT_SYMBOL(hpsb_iso_stop);
-EXPORT_SYMBOL(hpsb_iso_shutdown);
-EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet);
-EXPORT_SYMBOL(hpsb_iso_xmit_sync);
-EXPORT_SYMBOL(hpsb_iso_recv_release_packets);
-EXPORT_SYMBOL(hpsb_iso_n_ready);
-EXPORT_SYMBOL(hpsb_iso_packet_sent);
-EXPORT_SYMBOL(hpsb_iso_packet_received);
-EXPORT_SYMBOL(hpsb_iso_wake);
-EXPORT_SYMBOL(hpsb_iso_recv_flush);
-
-/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_get_keyval);
-EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_release_keyval);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_core.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_core.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_core.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_core.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,172 +0,0 @@
-#ifndef _IEEE1394_CORE_H
-#define _IEEE1394_CORE_H
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/cdev.h>
-#include <asm/atomic.h>
-
-#include "hosts.h"
-#include "ieee1394_types.h"
-
-struct hpsb_packet {
-	/* This struct is basically read-only for hosts with the exception of
-	 * the data buffer contents and driver_list. */
-
-	/* This can be used for host driver internal linking.
-	 *
-	 * NOTE: This must be left in init state when the driver is done
-	 * with it (e.g. by using list_del_init()), since the core does
-	 * some sanity checks to make sure the packet is not on a
-	 * driver_list when free'ing it. */
-	struct list_head driver_list;
-
-	nodeid_t node_id;
-
-	/* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
-	enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
-
-	/* Okay, this is core internal and a no care for hosts.
-	 * queued   = queued for sending
-	 * pending  = sent, waiting for response
-	 * complete = processing completed, successful or not
-	 */
-	enum {
-		hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
-	} __attribute__((packed)) state;
-
-	/* These are core-internal. */
-	signed char tlabel;
-	signed char ack_code;
-	unsigned char tcode;
-
-	unsigned expect_response:1;
-	unsigned no_waiter:1;
-
-	/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
-	unsigned speed_code:2;
-
-	struct hpsb_host *host;
-	unsigned int generation;
-
-	atomic_t refcnt;
-	struct list_head queue;
-
-	/* Function (and possible data to pass to it) to call when this
-	 * packet is completed.  */
-	void (*complete_routine)(void *);
-	void *complete_data;
-
-	/* Store jiffies for implementing bus timeouts. */
-	unsigned long sendtime;
-
-	/* Core-internal.  */
-	size_t allocated_data_size;	/* as allocated */
-
-	/* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
-	size_t data_size;		/* as filled in */
-	size_t header_size;		/* as filled in, not counting the CRC */
-
-	/* Buffers */
-	quadlet_t *data;		/* can be DMA-mapped */
-	quadlet_t header[5];
-	quadlet_t embedded_data[0];	/* keep as last member */
-};
-
-void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
-				   void (*routine)(void *), void *data);
-static inline struct hpsb_packet *driver_packet(struct list_head *l)
-{
-	return list_entry(l, struct hpsb_packet, driver_list);
-}
-void abort_timedouts(unsigned long __opaque);
-struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
-void hpsb_free_packet(struct hpsb_packet *packet);
-
-/**
- * get_hpsb_generation - generation counter for the complete 1394 subsystem
- *
- * Generation gets incremented on every change in the subsystem (notably on bus
- * resets). Use the functions, not the variable.
- */
-static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
-{
-	return atomic_read(&host->generation);
-}
-
-int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-int hpsb_send_packet(struct hpsb_packet *packet);
-int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-int hpsb_reset_bus(struct hpsb_host *host, int type);
-int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
-			  u64 *local_time);
-
-int hpsb_bus_reset(struct hpsb_host *host);
-void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
-		      int ackcode);
-void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
-			  int write_acked);
-
-/*
- * CHARACTER DEVICE DISPATCHING
- *
- * All ieee1394 character device drivers share the same major number
- * (major 171).  The 256 minor numbers are allocated to the various
- * task-specific interfaces (raw1394, video1394, dv1394, etc) in
- * blocks of 16.
- *
- * The core ieee1394.o module allocates the device number region
- * 171:0-255, the various drivers must then cdev_add() their cdev
- * objects to handle their respective sub-regions.
- *
- * Minor device number block allocations:
- *
- * Block 0  (  0- 15)  raw1394
- * Block 1  ( 16- 31)  video1394
- * Block 2  ( 32- 47)  dv1394
- *
- * Blocks 3-14 free for future allocation
- *
- * Block 15 (240-255)  reserved for drivers under development, etc.
- */
-
-#define IEEE1394_MAJOR			 171
-
-#define IEEE1394_MINOR_BLOCK_RAW1394	   0
-#define IEEE1394_MINOR_BLOCK_VIDEO1394	   1
-#define IEEE1394_MINOR_BLOCK_DV1394	   2
-#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
-
-#define IEEE1394_CORE_DEV	  MKDEV(IEEE1394_MAJOR, 0)
-#define IEEE1394_RAW1394_DEV	  MKDEV(IEEE1394_MAJOR, \
-					IEEE1394_MINOR_BLOCK_RAW1394 * 16)
-#define IEEE1394_VIDEO1394_DEV	  MKDEV(IEEE1394_MAJOR, \
-					IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
-#define IEEE1394_DV1394_DEV	  MKDEV(IEEE1394_MAJOR, \
-					IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
-					IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
-
-/**
- * ieee1394_file_to_instance - get the index within a minor number block
- */
-static inline unsigned char ieee1394_file_to_instance(struct file *file)
-{
-	int idx = cdev_index(file->f_path.dentry->d_inode);
-	if (idx < 0)
-		idx = 0;
-	return idx;
-}
-
-extern int hpsb_disable_irm;
-
-/* Our sysfs bus entry */
-extern struct bus_type ieee1394_bus_type;
-extern struct class hpsb_host_class;
-extern struct class *hpsb_protocol_class;
-
-#endif /* _IEEE1394_CORE_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,220 +0,0 @@
-/*
- * Generic IEEE 1394 definitions
- */
-
-#ifndef _IEEE1394_IEEE1394_H
-#define _IEEE1394_IEEE1394_H
-
-#define TCODE_WRITEQ		0x0
-#define TCODE_WRITEB		0x1
-#define TCODE_WRITE_RESPONSE	0x2
-#define TCODE_READQ		0x4
-#define TCODE_READB		0x5
-#define TCODE_READQ_RESPONSE	0x6
-#define TCODE_READB_RESPONSE	0x7
-#define TCODE_CYCLE_START	0x8
-#define TCODE_LOCK_REQUEST	0x9
-#define TCODE_ISO_DATA		0xa
-#define TCODE_STREAM_DATA	0xa
-#define TCODE_LOCK_RESPONSE	0xb
-
-#define RCODE_COMPLETE		0x0
-#define RCODE_CONFLICT_ERROR	0x4
-#define RCODE_DATA_ERROR	0x5
-#define RCODE_TYPE_ERROR	0x6
-#define RCODE_ADDRESS_ERROR	0x7
-
-#define EXTCODE_MASK_SWAP	0x1
-#define EXTCODE_COMPARE_SWAP	0x2
-#define EXTCODE_FETCH_ADD	0x3
-#define EXTCODE_LITTLE_ADD	0x4
-#define EXTCODE_BOUNDED_ADD	0x5
-#define EXTCODE_WRAP_ADD	0x6
-
-#define ACK_COMPLETE		0x1
-#define ACK_PENDING		0x2
-#define ACK_BUSY_X		0x4
-#define ACK_BUSY_A		0x5
-#define ACK_BUSY_B		0x6
-#define ACK_TARDY		0xb
-#define ACK_CONFLICT_ERROR	0xc
-#define ACK_DATA_ERROR		0xd
-#define ACK_TYPE_ERROR		0xe
-#define ACK_ADDRESS_ERROR	0xf
-
-/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE		(-1)
-#define ACKX_SEND_ERROR		(-2)
-#define ACKX_ABORTED		(-3)
-#define ACKX_TIMEOUT		(-4)
-
-#define IEEE1394_SPEED_100	0x00
-#define IEEE1394_SPEED_200	0x01
-#define IEEE1394_SPEED_400	0x02
-#define IEEE1394_SPEED_800	0x03
-#define IEEE1394_SPEED_1600	0x04
-#define IEEE1394_SPEED_3200	0x05
-#define IEEE1394_SPEED_MAX	IEEE1394_SPEED_3200
-
-/* Maps speed values above to a string representation */
-extern const char *hpsb_speedto_str[];
-
-/* 1394a cable PHY packets */
-#define SELFID_PWRCL_NO_POWER		0x0
-#define SELFID_PWRCL_PROVIDE_15W	0x1
-#define SELFID_PWRCL_PROVIDE_30W	0x2
-#define SELFID_PWRCL_PROVIDE_45W	0x3
-#define SELFID_PWRCL_USE_1W		0x4
-#define SELFID_PWRCL_USE_3W		0x5
-#define SELFID_PWRCL_USE_6W		0x6
-#define SELFID_PWRCL_USE_10W		0x7
-
-#define SELFID_PORT_CHILD		0x3
-#define SELFID_PORT_PARENT		0x2
-#define SELFID_PORT_NCONN		0x1
-#define SELFID_PORT_NONE		0x0
-
-#define SELFID_SPEED_UNKNOWN		0x3	/* 1394b PHY */
-
-#define PHYPACKET_LINKON			0x40000000
-#define PHYPACKET_PHYCONFIG_R			0x00800000
-#define PHYPACKET_PHYCONFIG_T			0x00400000
-#define EXTPHYPACKET_TYPE_PING			0x00000000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE	0x00040000
-#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED	0x00140000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE	0x000C0000
-#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED	0x001C0000
-#define EXTPHYPACKET_TYPE_REMOTECOMMAND		0x00200000
-#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION	0x00280000
-#define EXTPHYPACKET_TYPE_RESUME		0x003C0000
-
-#define EXTPHYPACKET_TYPEMASK			0xC0FC0000
-
-#define PHYPACKET_PORT_SHIFT		24
-#define PHYPACKET_GAPCOUNT_SHIFT	16
-
-/* 1394a PHY register map bitmasks */
-#define PHY_00_PHYSICAL_ID	0xFC
-#define PHY_00_R		0x02 /* Root */
-#define PHY_00_PS		0x01 /* Power Status*/
-#define PHY_01_RHB		0x80 /* Root Hold-Off */
-#define PHY_01_IBR		0x80 /* Initiate Bus Reset */
-#define PHY_01_GAP_COUNT	0x3F
-#define PHY_02_EXTENDED		0xE0 /* 0x7 for 1394a-compliant PHY */
-#define PHY_02_TOTAL_PORTS	0x1F
-#define PHY_03_MAX_SPEED	0xE0
-#define PHY_03_DELAY		0x0F
-#define PHY_04_LCTRL		0x80 /* Link Active Report Control */
-#define PHY_04_CONTENDER	0x40
-#define PHY_04_JITTER		0x38
-#define PHY_04_PWR_CLASS	0x07 /* Power Class */
-#define PHY_05_WATCHDOG		0x80
-#define PHY_05_ISBR		0x40 /* Initiate Short Bus Reset */
-#define PHY_05_LOOP		0x20 /* Loop Detect */
-#define PHY_05_PWR_FAIL		0x10 /* Cable Power Failure Detect */
-#define PHY_05_TIMEOUT		0x08 /* Arbitration State Machine Timeout */
-#define PHY_05_PORT_EVENT	0x04 /* Port Event Detect */
-#define PHY_05_ENAB_ACCEL	0x02 /* Enable Arbitration Acceleration */
-#define PHY_05_ENAB_MULTI	0x01 /* Ena. Multispeed Packet Concatenation */
-
-#include <asm/byteorder.h>
-
-/* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC	cpu_to_be32(0x31333934)
-
-#ifdef __BIG_ENDIAN_BITFIELD
-
-struct selfid {
-	u32 packet_identifier:2; /* always binary 10 */
-	u32 phy_id:6;
-	/* byte */
-	u32 extended:1; /* if true is struct ext_selfid */
-	u32 link_active:1;
-	u32 gap_count:6;
-	/* byte */
-	u32 speed:2;
-	u32 phy_delay:2;
-	u32 contender:1;
-	u32 power_class:3;
-	/* byte */
-	u32 port0:2;
-	u32 port1:2;
-	u32 port2:2;
-	u32 initiated_reset:1;
-	u32 more_packets:1;
-} __attribute__((packed));
-
-struct ext_selfid {
-	u32 packet_identifier:2; /* always binary 10 */
-	u32 phy_id:6;
-	/* byte */
-	u32 extended:1; /* if false is struct selfid */
-	u32 seq_nr:3;
-	u32 reserved:2;
-	u32 porta:2;
-	/* byte */
-	u32 portb:2;
-	u32 portc:2;
-	u32 portd:2;
-	u32 porte:2;
-	/* byte */
-	u32 portf:2;
-	u32 portg:2;
-	u32 porth:2;
-	u32 reserved2:1;
-	u32 more_packets:1;
-} __attribute__((packed));
-
-#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
-
-/*
- * Note: these mean to be bit fields of a big endian SelfID as seen on a little
- * endian machine.  Without swapping.
- */
-
-struct selfid {
-	u32 phy_id:6;
-	u32 packet_identifier:2; /* always binary 10 */
-	/* byte */
-	u32 gap_count:6;
-	u32 link_active:1;
-	u32 extended:1; /* if true is struct ext_selfid */
-	/* byte */
-	u32 power_class:3;
-	u32 contender:1;
-	u32 phy_delay:2;
-	u32 speed:2;
-	/* byte */
-	u32 more_packets:1;
-	u32 initiated_reset:1;
-	u32 port2:2;
-	u32 port1:2;
-	u32 port0:2;
-} __attribute__((packed));
-
-struct ext_selfid {
-	u32 phy_id:6;
-	u32 packet_identifier:2; /* always binary 10 */
-	/* byte */
-	u32 porta:2;
-	u32 reserved:2;
-	u32 seq_nr:3;
-	u32 extended:1; /* if false is struct selfid */
-	/* byte */
-	u32 porte:2;
-	u32 portd:2;
-	u32 portc:2;
-	u32 portb:2;
-	/* byte */
-	u32 more_packets:1;
-	u32 reserved2:1;
-	u32 porth:2;
-	u32 portg:2;
-	u32 portf:2;
-} __attribute__((packed));
-
-#else
-#error What? PDP endian?
-#endif /* __BIG_ENDIAN_BITFIELD */
-
-#endif /* _IEEE1394_IEEE1394_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_hotplug.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_hotplug.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_hotplug.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_hotplug.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,19 +0,0 @@
-#ifndef _IEEE1394_HOTPLUG_H
-#define _IEEE1394_HOTPLUG_H
-
-/* Unit spec id and sw version entry for some protocols */
-#define AVC_UNIT_SPEC_ID_ENTRY		0x0000A02D
-#define AVC_SW_VERSION_ENTRY		0x00010001
-#define CAMERA_UNIT_SPEC_ID_ENTRY	0x0000A02D
-#define CAMERA_SW_VERSION_ENTRY		0x00000100
-
-/* /include/linux/mod_devicetable.h defines:
- *	IEEE1394_MATCH_VENDOR_ID
- *	IEEE1394_MATCH_MODEL_ID
- *	IEEE1394_MATCH_SPECIFIER_ID
- *	IEEE1394_MATCH_VERSION
- *	struct ieee1394_device_id
- */
-#include <linux/mod_devicetable.h>
-
-#endif /* _IEEE1394_HOTPLUG_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394-ioctl.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394-ioctl.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394-ioctl.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394-ioctl.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,106 +0,0 @@
-/*
- * Base file for all ieee1394 ioctl's.
- * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
- */
-
-#ifndef __IEEE1394_IOCTL_H
-#define __IEEE1394_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-/* DV1394 Gets 10 */
-
-/* Get the driver ready to transmit video.  pass a struct dv1394_init* as
- * the parameter (see below), or NULL to get default parameters */
-#define DV1394_IOC_INIT			_IOW('#', 0x06, struct dv1394_init)
-
-/* Stop transmitting video and free the ringbuffer */
-#define DV1394_IOC_SHUTDOWN		_IO ('#', 0x07)
-
-/* Submit N new frames to be transmitted, where the index of the first new
- * frame is first_clear_buffer, and the index of the last new frame is
- * (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_SUBMIT_FRAMES	_IO ('#', 0x08)
-
-/* Block until N buffers are clear (pass N as the parameter) Because we
- * re-transmit the last frame on underrun, there will at most be n_frames
- * - 1 clear frames at any time */
-#define DV1394_IOC_WAIT_FRAMES		_IO ('#', 0x09)
-
-/* Capture new frames that have been received, where the index of the
- * first new frame is first_clear_buffer, and the index of the last new
- * frame is (first_clear_buffer + N) % n_frames */
-#define DV1394_IOC_RECEIVE_FRAMES	_IO ('#', 0x0a)
-
-/* Tell card to start receiving DMA */
-#define DV1394_IOC_START_RECEIVE	_IO ('#', 0x0b)
-
-/* Pass a struct dv1394_status* as the parameter */
-#define DV1394_IOC_GET_STATUS		_IOR('#', 0x0c, struct dv1394_status)
-
-
-/* Video1394 Gets 10 */
-
-#define VIDEO1394_IOC_LISTEN_CHANNEL		\
-	_IOWR('#', 0x10, struct video1394_mmap)
-#define VIDEO1394_IOC_UNLISTEN_CHANNEL		\
-	_IOW ('#', 0x11, int)
-#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER	\
-	_IOW ('#', 0x12, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER	\
-	_IOWR('#', 0x13, struct video1394_wait)
-#define VIDEO1394_IOC_TALK_CHANNEL		\
-	_IOWR('#', 0x14, struct video1394_mmap)
-#define VIDEO1394_IOC_UNTALK_CHANNEL		\
-	_IOW ('#', 0x15, int)
-/*
- * This one is broken: it really wanted
- * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
- * but got just a "size_t"
- */
-#define VIDEO1394_IOC_TALK_QUEUE_BUFFER 	\
-	_IOW ('#', 0x16, size_t)
-#define VIDEO1394_IOC_TALK_WAIT_BUFFER		\
-	_IOW ('#', 0x17, struct video1394_wait)
-#define VIDEO1394_IOC_LISTEN_POLL_BUFFER	\
-	_IOWR('#', 0x18, struct video1394_wait)
-
-
-/* Raw1394's ISO interface */
-#define RAW1394_IOC_ISO_XMIT_INIT		\
-	_IOW ('#', 0x1a, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_INIT		\
-	_IOWR('#', 0x1b, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_RECV_START		\
-	_IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
-#define RAW1394_IOC_ISO_XMIT_START		\
-	_IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
-#define RAW1394_IOC_ISO_XMIT_RECV_STOP		\
-	_IO  ('#', 0x1e)
-#define RAW1394_IOC_ISO_GET_STATUS		\
-	_IOR ('#', 0x1f, struct raw1394_iso_status)
-#define RAW1394_IOC_ISO_SHUTDOWN		\
-	_IO  ('#', 0x20)
-#define RAW1394_IOC_ISO_QUEUE_ACTIVITY		\
-	_IO  ('#', 0x21)
-#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL	\
-	_IOW ('#', 0x22, unsigned char)
-#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL	\
-	_IOW ('#', 0x23, unsigned char)
-#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK	\
-	_IOW ('#', 0x24, __u64)
-#define RAW1394_IOC_ISO_RECV_PACKETS		\
-	_IOW ('#', 0x25, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS	\
-	_IOW ('#', 0x26, unsigned int)
-#define RAW1394_IOC_ISO_XMIT_PACKETS		\
-	_IOW ('#', 0x27, struct raw1394_iso_packets)
-#define RAW1394_IOC_ISO_XMIT_SYNC		\
-	_IO  ('#', 0x28)
-#define RAW1394_IOC_ISO_RECV_FLUSH		\
-	_IO  ('#', 0x29)
-#define RAW1394_IOC_GET_CYCLE_TIMER		\
-	_IOR ('#', 0x30, struct raw1394_cycle_timer)
-
-#endif /* __IEEE1394_IOCTL_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_transactions.c linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_transactions.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_transactions.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_transactions.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,595 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Transaction support.
- *
- * Copyright (C) 1999 Andreas E. Bombe
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitops.h>
-#include <linux/compiler.h>
-#include <linux/hardirq.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/sched.h>  /* because linux/wait.h is broken if CONFIG_SMP=n */
-#include <linux/wait.h>
-
-#include <asm/bug.h>
-#include <asm/errno.h>
-#include <asm/system.h>
-
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-
-#define PREP_ASYNC_HEAD_ADDRESS(tc) \
-        packet->tcode = tc; \
-        packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
-                | (1 << 8) | (tc << 4); \
-        packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
-        packet->header[2] = addr & 0xffffffff
-
-#ifndef HPSB_DEBUG_TLABELS
-static
-#endif
-DEFINE_SPINLOCK(hpsb_tlabel_lock);
-
-static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
-
-static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
-{
-	PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
-	packet->header_size = 12;
-	packet->data_size = 0;
-	packet->expect_response = 1;
-}
-
-static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
-				 int length)
-{
-	PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
-	packet->header[3] = length << 16;
-	packet->header_size = 16;
-	packet->data_size = 0;
-	packet->expect_response = 1;
-}
-
-static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
-				 quadlet_t data)
-{
-	PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
-	packet->header[3] = data;
-	packet->header_size = 16;
-	packet->data_size = 0;
-	packet->expect_response = 1;
-}
-
-static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
-				  int length)
-{
-	PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
-	packet->header[3] = length << 16;
-	packet->header_size = 16;
-	packet->expect_response = 1;
-	packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
-}
-
-static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
-			    int length)
-{
-	PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
-	packet->header[3] = (length << 16) | extcode;
-	packet->header_size = 16;
-	packet->data_size = length;
-	packet->expect_response = 1;
-}
-
-static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
-{
-	packet->header[0] = data;
-	packet->header[1] = ~data;
-	packet->header_size = 8;
-	packet->data_size = 0;
-	packet->expect_response = 0;
-	packet->type = hpsb_raw;	/* No CRC added */
-	packet->speed_code = IEEE1394_SPEED_100;	/* Force speed to be 100Mbps */
-}
-
-static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
-				     int channel, int tag, int sync)
-{
-	packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
-	    | (TCODE_STREAM_DATA << 4) | sync;
-
-	packet->header_size = 4;
-	packet->data_size = length;
-	packet->type = hpsb_async;
-	packet->tcode = TCODE_ISO_DATA;
-}
-
-/* same as hpsb_get_tlabel, except that it returns immediately */
-static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
-{
-	unsigned long flags, *tp;
-	u8 *next;
-	int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
-	/* Broadcast transactions are complete once the request has been sent.
-	 * Use the same transaction label for all broadcast transactions. */
-	if (unlikely(n == ALL_NODES)) {
-		packet->tlabel = 0;
-		return 0;
-	}
-	tp = packet->host->tl_pool[n].map;
-	next = &packet->host->next_tl[n];
-
-	spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-	tlabel = find_next_zero_bit(tp, 64, *next);
-	if (tlabel > 63)
-		tlabel = find_first_zero_bit(tp, 64);
-	if (tlabel > 63) {
-		spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-		return -EAGAIN;
-	}
-	__set_bit(tlabel, tp);
-	*next = (tlabel + 1) & 63;
-	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-	packet->tlabel = tlabel;
-	return 0;
-}
-
-/**
- * hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet whose tlabel and tl_pool we set
- *
- * Every asynchronous transaction on the 1394 bus needs a transaction
- * label to match the response to the request.  This label has to be
- * different from any other transaction label in an outstanding request to
- * the same node to make matching possible without ambiguity.
- *
- * There are 64 different tlabels, so an allocated tlabel has to be freed
- * with hpsb_free_tlabel() after the transaction is complete (unless it's
- * reused again for the same target node).
- *
- * Return value: Zero on success, otherwise non-zero. A non-zero return
- * generally means there are no available tlabels. If this is called out
- * of interrupt or atomic context, then it will sleep until can return a
- * tlabel or a signal is received.
- */
-int hpsb_get_tlabel(struct hpsb_packet *packet)
-{
-	if (irqs_disabled() || in_atomic())
-		return hpsb_get_tlabel_atomic(packet);
-
-	/* NB: The macro wait_event_interruptible() is called with a condition
-	 * argument with side effect.  This is only possible because the side
-	 * effect does not occur until the condition became true, and
-	 * wait_event_interruptible() won't evaluate the condition again after
-	 * that. */
-	return wait_event_interruptible(tlabel_wq,
-					!hpsb_get_tlabel_atomic(packet));
-}
-
-/**
- * hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whose tlabel and tl_pool needs to be cleared
- *
- * Frees the transaction label allocated with hpsb_get_tlabel().  The
- * tlabel has to be freed after the transaction is complete (i.e. response
- * was received for a split transaction or packet was sent for a unified
- * transaction).
- *
- * A tlabel must not be freed twice.
- */
-void hpsb_free_tlabel(struct hpsb_packet *packet)
-{
-	unsigned long flags, *tp;
-	int tlabel, n = NODEID_TO_NODE(packet->node_id);
-
-	if (unlikely(n == ALL_NODES))
-		return;
-	tp = packet->host->tl_pool[n].map;
-	tlabel = packet->tlabel;
-	BUG_ON(tlabel > 63 || tlabel < 0);
-
-	spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-	BUG_ON(!__test_and_clear_bit(tlabel, tp));
-	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-	wake_up_interruptible(&tlabel_wq);
-}
-
-/**
- * hpsb_packet_success - Make sense of the ack and reply codes
- *
- * Make sense of the ack and reply codes and return more convenient error codes:
- * 0 = success.  -%EBUSY = node is busy, try again.  -%EAGAIN = error which can
- * probably resolved by retry.  -%EREMOTEIO = node suffers from an internal
- * error.  -%EACCES = this transaction is not allowed on requested address.
- * -%EINVAL = invalid address at node.
- */
-int hpsb_packet_success(struct hpsb_packet *packet)
-{
-	switch (packet->ack_code) {
-	case ACK_PENDING:
-		switch ((packet->header[1] >> 12) & 0xf) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_CONFLICT_ERROR:
-			return -EAGAIN;
-		case RCODE_DATA_ERROR:
-			return -EREMOTEIO;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-			return -EINVAL;
-		default:
-			HPSB_ERR("received reserved rcode %d from node %d",
-				 (packet->header[1] >> 12) & 0xf,
-				 packet->node_id);
-			return -EAGAIN;
-		}
-
-	case ACK_BUSY_X:
-	case ACK_BUSY_A:
-	case ACK_BUSY_B:
-		return -EBUSY;
-
-	case ACK_TYPE_ERROR:
-		return -EACCES;
-
-	case ACK_COMPLETE:
-		if (packet->tcode == TCODE_WRITEQ
-		    || packet->tcode == TCODE_WRITEB) {
-			return 0;
-		} else {
-			HPSB_ERR("impossible ack_complete from node %d "
-				 "(tcode %d)", packet->node_id, packet->tcode);
-			return -EAGAIN;
-		}
-
-	case ACK_DATA_ERROR:
-		if (packet->tcode == TCODE_WRITEB
-		    || packet->tcode == TCODE_LOCK_REQUEST) {
-			return -EAGAIN;
-		} else {
-			HPSB_ERR("impossible ack_data_error from node %d "
-				 "(tcode %d)", packet->node_id, packet->tcode);
-			return -EAGAIN;
-		}
-
-	case ACK_ADDRESS_ERROR:
-		return -EINVAL;
-
-	case ACK_TARDY:
-	case ACK_CONFLICT_ERROR:
-	case ACKX_NONE:
-	case ACKX_SEND_ERROR:
-	case ACKX_ABORTED:
-	case ACKX_TIMEOUT:
-		/* error while sending */
-		return -EAGAIN;
-
-	default:
-		HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
-			 packet->ack_code, packet->node_id, packet->tcode);
-		return -EAGAIN;
-	}
-}
-
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
-					 u64 addr, size_t length)
-{
-	struct hpsb_packet *packet;
-
-	if (length == 0)
-		return NULL;
-
-	packet = hpsb_alloc_packet(length);
-	if (!packet)
-		return NULL;
-
-	packet->host = host;
-	packet->node_id = node;
-
-	if (hpsb_get_tlabel(packet)) {
-		hpsb_free_packet(packet);
-		return NULL;
-	}
-
-	if (length == 4)
-		fill_async_readquad(packet, addr);
-	else
-		fill_async_readblock(packet, addr, length);
-
-	return packet;
-}
-
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
-					  u64 addr, quadlet_t * buffer,
-					  size_t length)
-{
-	struct hpsb_packet *packet;
-
-	if (length == 0)
-		return NULL;
-
-	packet = hpsb_alloc_packet(length);
-	if (!packet)
-		return NULL;
-
-	if (length % 4) {	/* zero padding bytes */
-		packet->data[length >> 2] = 0;
-	}
-	packet->host = host;
-	packet->node_id = node;
-
-	if (hpsb_get_tlabel(packet)) {
-		hpsb_free_packet(packet);
-		return NULL;
-	}
-
-	if (length == 4) {
-		fill_async_writequad(packet, addr, buffer ? *buffer : 0);
-	} else {
-		fill_async_writeblock(packet, addr, length);
-		if (buffer)
-			memcpy(packet->data, buffer, length);
-	}
-
-	return packet;
-}
-
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
-					   int length, int channel, int tag,
-					   int sync)
-{
-	struct hpsb_packet *packet;
-
-	if (length == 0)
-		return NULL;
-
-	packet = hpsb_alloc_packet(length);
-	if (!packet)
-		return NULL;
-
-	if (length % 4) {	/* zero padding bytes */
-		packet->data[length >> 2] = 0;
-	}
-	packet->host = host;
-
-	/* Because it is too difficult to determine all PHY speeds and link
-	 * speeds here, we use S100... */
-	packet->speed_code = IEEE1394_SPEED_100;
-
-	/* ...and prevent hpsb_send_packet() from overriding it. */
-	packet->node_id = LOCAL_BUS | ALL_NODES;
-
-	if (hpsb_get_tlabel(packet)) {
-		hpsb_free_packet(packet);
-		return NULL;
-	}
-
-	fill_async_stream_packet(packet, length, channel, tag, sync);
-	if (buffer)
-		memcpy(packet->data, buffer, length);
-
-	return packet;
-}
-
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
-					 u64 addr, int extcode,
-					 quadlet_t * data, quadlet_t arg)
-{
-	struct hpsb_packet *p;
-	u32 length;
-
-	p = hpsb_alloc_packet(8);
-	if (!p)
-		return NULL;
-
-	p->host = host;
-	p->node_id = node;
-	if (hpsb_get_tlabel(p)) {
-		hpsb_free_packet(p);
-		return NULL;
-	}
-
-	switch (extcode) {
-	case EXTCODE_FETCH_ADD:
-	case EXTCODE_LITTLE_ADD:
-		length = 4;
-		if (data)
-			p->data[0] = *data;
-		break;
-	default:
-		length = 8;
-		if (data) {
-			p->data[0] = arg;
-			p->data[1] = *data;
-		}
-		break;
-	}
-	fill_async_lock(p, addr, extcode, length);
-
-	return p;
-}
-
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
-					   nodeid_t node, u64 addr, int extcode,
-					   octlet_t * data, octlet_t arg)
-{
-	struct hpsb_packet *p;
-	u32 length;
-
-	p = hpsb_alloc_packet(16);
-	if (!p)
-		return NULL;
-
-	p->host = host;
-	p->node_id = node;
-	if (hpsb_get_tlabel(p)) {
-		hpsb_free_packet(p);
-		return NULL;
-	}
-
-	switch (extcode) {
-	case EXTCODE_FETCH_ADD:
-	case EXTCODE_LITTLE_ADD:
-		length = 8;
-		if (data) {
-			p->data[0] = *data >> 32;
-			p->data[1] = *data & 0xffffffff;
-		}
-		break;
-	default:
-		length = 16;
-		if (data) {
-			p->data[0] = arg >> 32;
-			p->data[1] = arg & 0xffffffff;
-			p->data[2] = *data >> 32;
-			p->data[3] = *data & 0xffffffff;
-		}
-		break;
-	}
-	fill_async_lock(p, addr, extcode, length);
-
-	return p;
-}
-
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
-{
-	struct hpsb_packet *p;
-
-	p = hpsb_alloc_packet(0);
-	if (!p)
-		return NULL;
-
-	p->host = host;
-	fill_phy_packet(p, data);
-
-	return p;
-}
-
-/*
- * FIXME - these functions should probably read from / write to user space to
- * avoid in kernel buffers for user space callers
- */
-
-/**
- * hpsb_read - generic read function
- *
- * Recognizes the local node ID and act accordingly.  Automatically uses a
- * quadlet read request if @length == 4 and and a block read request otherwise.
- * It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	      u64 addr, quadlet_t * buffer, size_t length)
-{
-	struct hpsb_packet *packet;
-	int retval = 0;
-
-	if (length == 0)
-		return -EINVAL;
-
-	packet = hpsb_make_readpacket(host, node, addr, length);
-
-	if (!packet) {
-		return -ENOMEM;
-	}
-
-	packet->generation = generation;
-	retval = hpsb_send_packet_and_wait(packet);
-	if (retval < 0)
-		goto hpsb_read_fail;
-
-	retval = hpsb_packet_success(packet);
-
-	if (retval == 0) {
-		if (length == 4) {
-			*buffer = packet->header[3];
-		} else {
-			memcpy(buffer, packet->data, length);
-		}
-	}
-
-      hpsb_read_fail:
-	hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-
-	return retval;
-}
-
-/**
- * hpsb_write - generic write function
- *
- * Recognizes the local node ID and act accordingly.  Automatically uses a
- * quadlet write request if @length == 4 and and a block write request
- * otherwise.  It does not yet support lengths that are not a multiple of 4.
- *
- * You must explicitly specifiy the @generation for which the node ID is valid,
- * to avoid sending packets to the wrong nodes when we race with a bus reset.
- */
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	       u64 addr, quadlet_t * buffer, size_t length)
-{
-	struct hpsb_packet *packet;
-	int retval;
-
-	if (length == 0)
-		return -EINVAL;
-
-	packet = hpsb_make_writepacket(host, node, addr, buffer, length);
-
-	if (!packet)
-		return -ENOMEM;
-
-	packet->generation = generation;
-	retval = hpsb_send_packet_and_wait(packet);
-	if (retval < 0)
-		goto hpsb_write_fail;
-
-	retval = hpsb_packet_success(packet);
-
-      hpsb_write_fail:
-	hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-
-	return retval;
-}
-
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
-{
-	struct hpsb_packet *packet;
-	int retval = 0;
-
-	packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
-	if (!packet)
-		return -ENOMEM;
-
-	packet->generation = generation;
-	retval = hpsb_send_packet_and_wait(packet);
-	if (retval < 0)
-		goto hpsb_lock_fail;
-
-	retval = hpsb_packet_success(packet);
-
-	if (retval == 0)
-		*data = packet->data[0];
-
-hpsb_lock_fail:
-	hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-
-	return retval;
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_transactions.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_transactions.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_transactions.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_transactions.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,40 +0,0 @@
-#ifndef _IEEE1394_TRANSACTIONS_H
-#define _IEEE1394_TRANSACTIONS_H
-
-#include <linux/types.h>
-
-#include "ieee1394_types.h"
-
-struct hpsb_packet;
-struct hpsb_host;
-
-int hpsb_get_tlabel(struct hpsb_packet *packet);
-void hpsb_free_tlabel(struct hpsb_packet *packet);
-struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
-					 u64 addr, size_t length);
-struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
-					 u64 addr, int extcode, quadlet_t *data,
-					 quadlet_t arg);
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
-					   nodeid_t node, u64 addr, int extcode,
-					   octlet_t *data, octlet_t arg);
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
-struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
-					  nodeid_t node, u64 addr,
-					  quadlet_t *buffer, size_t length);
-struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
-                                           int length, int channel, int tag,
-					   int sync);
-int hpsb_packet_success(struct hpsb_packet *packet);
-int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	      u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	       u64 addr, quadlet_t *buffer, size_t length);
-int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
-	      u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
-
-#ifdef HPSB_DEBUG_TLABELS
-extern spinlock_t hpsb_tlabel_lock;
-#endif
-
-#endif /* _IEEE1394_TRANSACTIONS_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_types.h linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_types.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ieee1394_types.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ieee1394_types.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,69 +0,0 @@
-#ifndef _IEEE1394_TYPES_H
-#define _IEEE1394_TYPES_H
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-typedef u32 quadlet_t;
-typedef u64 octlet_t;
-typedef u16 nodeid_t;
-
-typedef u8  byte_t;
-typedef u64 nodeaddr_t;
-typedef u16 arm_length_t;
-
-#define BUS_MASK  0xffc0
-#define BUS_SHIFT 6
-#define NODE_MASK 0x003f
-#define LOCAL_BUS 0xffc0
-#define ALL_NODES 0x003f
-
-#define NODEID_TO_BUS(nodeid)	((nodeid & BUS_MASK) >> BUS_SHIFT)
-#define NODEID_TO_NODE(nodeid)	(nodeid & NODE_MASK)
-
-/* Can be used to consistently print a node/bus ID. */
-#define NODE_BUS_FMT		"%d-%02d:%04d"
-#define NODE_BUS_ARGS(__host, __nodeid)	\
-	__host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
-
-#define HPSB_PRINT(level, fmt, args...) \
-	printk(level "ieee1394: " fmt "\n" , ## args)
-
-#define HPSB_DEBUG(fmt, args...)	HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_INFO(fmt, args...)		HPSB_PRINT(KERN_INFO, fmt , ## args)
-#define HPSB_NOTICE(fmt, args...)	HPSB_PRINT(KERN_NOTICE, fmt , ## args)
-#define HPSB_WARN(fmt, args...)		HPSB_PRINT(KERN_WARNING, fmt , ## args)
-#define HPSB_ERR(fmt, args...)		HPSB_PRINT(KERN_ERR, fmt , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define HPSB_VERBOSE(fmt, args...)	HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_DEBUG_TLABELS
-#else
-#define HPSB_VERBOSE(fmt, args...)	do {} while (0)
-#endif
-
-#ifdef __BIG_ENDIAN
-
-static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
-{
-	void *tmp = dest;
-	u32 *src = (u32 *)__src;
-
-	count /= 4;
-	while (count--)
-		*dest++ = swab32p(src++);
-	return tmp;
-}
-
-#else
-
-static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
-{
-	return memcpy(dest, src, count);
-}
-
-#endif /* __BIG_ENDIAN */
-
-#endif /* _IEEE1394_TYPES_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/init_ohci1394_dma.c linux-libre-2.6.37-gnu/drivers/ieee1394/init_ohci1394_dma.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/init_ohci1394_dma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/init_ohci1394_dma.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,285 +0,0 @@
-/*
- * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers
- *
- * Copyright (C) 2006-2007      Bernhard Kaindl <bk@suse.de>
- *
- * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c
- * this file has functions to:
- * - scan the PCI very early on boot for all OHCI 1394-compliant controllers
- * - reset and initialize them and make them join the IEEE1394 bus and
- * - enable physical DMA on them to allow remote debugging
- *
- * All code and data is marked as __init and __initdata, respective as
- * during boot, all OHCI1394 controllers may be claimed by the firewire
- * stack and at this point, this code should not touch them anymore.
- *
- * To use physical DMA after the initialization of the firewire stack,
- * be sure that the stack enables it and (re-)attach after the bus reset
- * which may be caused by the firewire stack initialization.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/interrupt.h>	/* for ohci1394.h */
-#include <linux/delay.h>
-#include <linux/pci.h>		/* for PCI defines */
-#include <linux/init_ohci1394_dma.h>
-#include <asm/pci-direct.h>	/* for direct PCI config space access */
-#include <asm/fixmap.h>
-
-#include "ieee1394_types.h"
-#include "ohci1394.h"
-
-int __initdata init_ohci1394_dma_early;
-
-/* Reads a PHY register of an OHCI-1394 controller */
-static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
-	int i;
-	quadlet_t r;
-
-	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
-			break;
-		mdelay(1);
-	}
-	r = reg_read(ohci, OHCI1394_PhyControl);
-
-	return (r & 0x00ff0000) >> 16;
-}
-
-/* Writes to a PHY register of an OHCI-1394 controller */
-static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-	int i;
-
-	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		u32 r = reg_read(ohci, OHCI1394_PhyControl);
-		if (!(r & 0x00004000))
-			break;
-		mdelay(1);
-	}
-}
-
-/* Resets an OHCI-1394 controller (for sane state before initialization) */
-static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
-	int i;
-
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (!(reg_read(ohci, OHCI1394_HCControlSet)
-				   & OHCI1394_HCControl_softReset))
-			break;
-		mdelay(1);
-	}
-}
-
-/* Basic OHCI-1394 register and port inititalization */
-static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
-{
-	quadlet_t bus_options;
-	int num_ports, i;
-
-	/* Put some defaults to these undefined bus options */
-	bus_options = reg_read(ohci, OHCI1394_BusOptions);
-	bus_options |=  0x60000000; /* Enable CMC and ISC */
-	bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
-	bus_options &= ~0x18000000; /* Disable PMC and BMC */
-	reg_write(ohci, OHCI1394_BusOptions, bus_options);
-
-	/* Set the bus number */
-	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
-	/* Enable posted writes */
-	reg_write(ohci, OHCI1394_HCControlSet,
-			OHCI1394_HCControl_postedWriteEnable);
-
-	/* Clear link control register */
-	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-	/* enable phys */
-	reg_write(ohci, OHCI1394_LinkControlSet,
-			OHCI1394_LinkControl_RcvPhyPkt);
-
-	/* Don't accept phy packets into AR request context */
-	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
-
-	/* Clear the Isochonouys interrupt masks */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
-	/* Accept asyncronous transfer requests from all nodes for now */
-	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
-
-	/* Specify asyncronous transfer retries */
-	reg_write(ohci, OHCI1394_ATRetries,
-		  OHCI1394_MAX_AT_REQ_RETRIES |
-		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
-		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
-	/* We don't want hardware swapping */
-	reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
-	/* Enable link */
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
-	/* If anything is connected to a port, make sure it is enabled */
-	num_ports = get_phy_reg(ohci, 2) & 0xf;
-	for (i = 0; i < num_ports; i++) {
-		unsigned int status;
-
-		set_phy_reg(ohci, 7, i);
-		status = get_phy_reg(ohci, 8);
-
-		if (status & 0x20)
-			set_phy_reg(ohci, 8, status & ~1);
-	}
-}
-
-/**
- * init_ohci1394_wait_for_busresets - wait until bus resets are completed
- *
- * OHCI1394 initialization itself and any device going on- or offline
- * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec
- * specifies that physical DMA is disabled on each bus reset and it
- * has to be enabled after each bus reset when needed. We resort
- * to polling here because on early boot, we have no interrupts.
- */
-static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
-{
-	int i, events;
-
-	for (i=0; i < 9; i++) {
-		mdelay(200);
-		events = reg_read(ohci, OHCI1394_IntEventSet);
-		if (events & OHCI1394_busReset)
-			reg_write(ohci, OHCI1394_IntEventClear,
-					OHCI1394_busReset);
-	}
-}
-
-/**
- * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging
- * This enables remote DMA access over IEEE1394 from every host for the low
- * 4GB of address space. DMA accesses above 4GB are not available currently.
- */
-static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
-{
-	reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
-	reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
-	reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
-}
-
-/**
- * init_ohci1394_reset_and_init_dma - init controller and enable DMA
- * This initializes the given controller and enables physical DMA engine in it.
- */
-static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
-{
-	/* Start off with a soft reset, clears everything to a sane state. */
-	init_ohci1394_soft_reset(ohci);
-
-	/* Accessing some registers without LPS enabled may cause lock up */
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
-	/* Disable and clear interrupts */
-	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
-	mdelay(50); /* Wait 50msec to make sure we have full link enabled */
-
-	init_ohci1394_initialize(ohci);
-	/*
-	 * The initialization causes at least one IEEE1394 bus reset. Enabling
-	 * physical DMA only works *after* *all* bus resets have calmed down:
-	 */
-	init_ohci1394_wait_for_busresets(ohci);
-
-	/* We had to wait and do this now if we want to debug early problems */
-	init_ohci1394_enable_physical_dma(ohci);
-}
-
-/**
- * init_ohci1394_controller - Map the registers of the controller and init DMA
- * This maps the registers of the specified controller and initializes it
- */
-static inline void __init init_ohci1394_controller(int num, int slot, int func)
-{
-	unsigned long ohci_base;
-	struct ti_ohci ohci;
-
-	printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
-			 " at %02x:%02x.%x\n", num, slot, func);
-
-	ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2))
-						   & PCI_BASE_ADDRESS_MEM_MASK;
-
-	set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
-
-	ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
-
-	init_ohci1394_reset_and_init_dma(&ohci);
-}
-
-/**
- * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them
- * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them
- */
-void __init init_ohci1394_dma_on_all_controllers(void)
-{
-	int num, slot, func;
-
-	if (!early_pci_allowed())
-		return;
-
-	/* Poor man's PCI discovery, the only thing we can do at early boot */
-	for (num = 0; num < 32; num++) {
-		for (slot = 0; slot < 32; slot++) {
-			for (func = 0; func < 8; func++) {
-				u32 class = read_pci_config(num,slot,func,
-							PCI_CLASS_REVISION);
-				if ((class == 0xffffffff))
-					continue; /* No device at this func */
-
-				if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
-					continue; /* Not an OHCI-1394 device */
-
-				init_ohci1394_controller(num, slot, func);
-				break; /* Assume one controller per device */
-			}
-		}
-	}
-	printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n");
-}
-
-/**
- * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization
- */
-static int __init setup_ohci1394_dma(char *opt)
-{
-	if (!strcmp(opt, "early"))
-		init_ohci1394_dma_early = 1;
-	return 0;
-}
-
-/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */
-early_param("ohci1394_dma", setup_ohci1394_dma);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/iso.c linux-libre-2.6.37-gnu/drivers/ieee1394/iso.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/iso.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/iso.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,568 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include "hosts.h"
-#include "iso.h"
-
-/**
- * hpsb_iso_stop - stop DMA
- */
-void hpsb_iso_stop(struct hpsb_iso *iso)
-{
-	if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
-		return;
-
-	iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
-				  XMIT_STOP : RECV_STOP, 0);
-	iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
-}
-
-/**
- * hpsb_iso_shutdown - deallocate buffer and DMA context
- */
-void hpsb_iso_shutdown(struct hpsb_iso *iso)
-{
-	if (iso->flags & HPSB_ISO_DRIVER_INIT) {
-		hpsb_iso_stop(iso);
-		iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
-					  XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
-		iso->flags &= ~HPSB_ISO_DRIVER_INIT;
-	}
-
-	dma_region_free(&iso->data_buf);
-	kfree(iso);
-}
-
-static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
-					     enum hpsb_iso_type type,
-					     unsigned int data_buf_size,
-					     unsigned int buf_packets,
-					     int channel, int dma_mode,
-					     int irq_interval,
-					     void (*callback) (struct hpsb_iso
-							       *))
-{
-	struct hpsb_iso *iso;
-	int dma_direction;
-
-	/* make sure driver supports the ISO API */
-	if (!host->driver->isoctl) {
-		printk(KERN_INFO
-		       "ieee1394: host driver '%s' does not support the rawiso API\n",
-		       host->driver->name);
-		return NULL;
-	}
-
-	/* sanitize parameters */
-
-	if (buf_packets < 2)
-		buf_packets = 2;
-
-	if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
-	    || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
-		dma_mode = HPSB_ISO_DMA_DEFAULT;
-
-	if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
-		irq_interval = buf_packets / 4;
-	if (irq_interval == 0)	/* really interrupt for each packet */
-		irq_interval = 1;
-
-	if (channel < -1 || channel >= 64)
-		return NULL;
-
-	/* channel = -1 is OK for multi-channel recv but not for xmit */
-	if (type == HPSB_ISO_XMIT && channel < 0)
-		return NULL;
-
-	/* allocate and write the struct hpsb_iso */
-
-	iso =
-	    kmalloc(sizeof(*iso) +
-		    buf_packets * sizeof(struct hpsb_iso_packet_info),
-		    GFP_KERNEL);
-	if (!iso)
-		return NULL;
-
-	iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
-
-	iso->type = type;
-	iso->host = host;
-	iso->hostdata = NULL;
-	iso->callback = callback;
-	init_waitqueue_head(&iso->waitq);
-	iso->channel = channel;
-	iso->irq_interval = irq_interval;
-	iso->dma_mode = dma_mode;
-	dma_region_init(&iso->data_buf);
-	iso->buf_size = PAGE_ALIGN(data_buf_size);
-	iso->buf_packets = buf_packets;
-	iso->pkt_dma = 0;
-	iso->first_packet = 0;
-	spin_lock_init(&iso->lock);
-
-	if (iso->type == HPSB_ISO_XMIT) {
-		iso->n_ready_packets = iso->buf_packets;
-		dma_direction = PCI_DMA_TODEVICE;
-	} else {
-		iso->n_ready_packets = 0;
-		dma_direction = PCI_DMA_FROMDEVICE;
-	}
-
-	atomic_set(&iso->overflows, 0);
-	iso->bytes_discarded = 0;
-	iso->flags = 0;
-	iso->prebuffer = 0;
-
-	/* allocate the packet buffer */
-	if (dma_region_alloc
-	    (&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
-		goto err;
-
-	return iso;
-
-      err:
-	hpsb_iso_shutdown(iso);
-	return NULL;
-}
-
-/**
- * hpsb_iso_n_ready - returns number of packets ready to send or receive
- */
-int hpsb_iso_n_ready(struct hpsb_iso *iso)
-{
-	unsigned long flags;
-	int val;
-
-	spin_lock_irqsave(&iso->lock, flags);
-	val = iso->n_ready_packets;
-	spin_unlock_irqrestore(&iso->lock, flags);
-
-	return val;
-}
-
-/**
- * hpsb_iso_xmit_init - allocate the buffer and DMA context
- */
-struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
-				    unsigned int data_buf_size,
-				    unsigned int buf_packets,
-				    int channel,
-				    int speed,
-				    int irq_interval,
-				    void (*callback) (struct hpsb_iso *))
-{
-	struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
-						    data_buf_size, buf_packets,
-						    channel,
-						    HPSB_ISO_DMA_DEFAULT,
-						    irq_interval, callback);
-	if (!iso)
-		return NULL;
-
-	iso->speed = speed;
-
-	/* tell the driver to start working */
-	if (host->driver->isoctl(iso, XMIT_INIT, 0))
-		goto err;
-
-	iso->flags |= HPSB_ISO_DRIVER_INIT;
-	return iso;
-
-      err:
-	hpsb_iso_shutdown(iso);
-	return NULL;
-}
-
-/**
- * hpsb_iso_recv_init - allocate the buffer and DMA context
- *
- * Note, if channel = -1, multi-channel receive is enabled.
- */
-struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
-				    unsigned int data_buf_size,
-				    unsigned int buf_packets,
-				    int channel,
-				    int dma_mode,
-				    int irq_interval,
-				    void (*callback) (struct hpsb_iso *))
-{
-	struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
-						    data_buf_size, buf_packets,
-						    channel, dma_mode,
-						    irq_interval, callback);
-	if (!iso)
-		return NULL;
-
-	/* tell the driver to start working */
-	if (host->driver->isoctl(iso, RECV_INIT, 0))
-		goto err;
-
-	iso->flags |= HPSB_ISO_DRIVER_INIT;
-	return iso;
-
-      err:
-	hpsb_iso_shutdown(iso);
-	return NULL;
-}
-
-/**
- * hpsb_iso_recv_listen_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
-{
-	if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
-		return -EINVAL;
-	return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_unlisten_channel
- *
- * multi-channel only
- */
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
-{
-	if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
-		return -EINVAL;
-	return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
-}
-
-/**
- * hpsb_iso_recv_set_channel_mask
- *
- * multi-channel only
- */
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
-	if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
-		return -EINVAL;
-	return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
-					 (unsigned long)&mask);
-}
-
-/**
- * hpsb_iso_recv_flush - check for arrival of new packets
- *
- * check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached)
- */
-int hpsb_iso_recv_flush(struct hpsb_iso *iso)
-{
-	if (iso->type != HPSB_ISO_RECV)
-		return -EINVAL;
-	return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
-}
-
-static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
-	int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
-	if (retval)
-		return retval;
-
-	iso->flags |= HPSB_ISO_DRIVER_STARTED;
-	return retval;
-}
-
-/**
- * hpsb_iso_xmit_start - start DMA
- */
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
-{
-	if (iso->type != HPSB_ISO_XMIT)
-		return -1;
-
-	if (iso->flags & HPSB_ISO_DRIVER_STARTED)
-		return 0;
-
-	if (cycle < -1)
-		cycle = -1;
-	else if (cycle >= 8000)
-		cycle %= 8000;
-
-	iso->xmit_cycle = cycle;
-
-	if (prebuffer < 0)
-		prebuffer = iso->buf_packets - 1;
-	else if (prebuffer == 0)
-		prebuffer = 1;
-
-	if (prebuffer >= iso->buf_packets)
-		prebuffer = iso->buf_packets - 1;
-
-	iso->prebuffer = prebuffer;
-
-	/* remember the starting cycle; DMA will commence from xmit_queue_packets()
-	   once enough packets have been buffered */
-	iso->start_cycle = cycle;
-
-	return 0;
-}
-
-/**
- * hpsb_iso_recv_start - start DMA
- */
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
-	int retval = 0;
-	int isoctl_args[3];
-
-	if (iso->type != HPSB_ISO_RECV)
-		return -1;
-
-	if (iso->flags & HPSB_ISO_DRIVER_STARTED)
-		return 0;
-
-	if (cycle < -1)
-		cycle = -1;
-	else if (cycle >= 8000)
-		cycle %= 8000;
-
-	isoctl_args[0] = cycle;
-
-	if (tag_mask < 0)
-		/* match all tags */
-		tag_mask = 0xF;
-	isoctl_args[1] = tag_mask;
-
-	isoctl_args[2] = sync;
-
-	retval =
-	    iso->host->driver->isoctl(iso, RECV_START,
-				      (unsigned long)&isoctl_args[0]);
-	if (retval)
-		return retval;
-
-	iso->flags |= HPSB_ISO_DRIVER_STARTED;
-	return retval;
-}
-
-/* check to make sure the user has not supplied bogus values of offset/len
- * that would cause the kernel to access memory outside the buffer */
-static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
-				     unsigned int offset, unsigned short len,
-				     unsigned int *out_offset,
-				     unsigned short *out_len)
-{
-	if (offset >= iso->buf_size)
-		return -EFAULT;
-
-	/* make sure the packet does not go beyond the end of the buffer */
-	if (offset + len > iso->buf_size)
-		return -EFAULT;
-
-	/* check for wrap-around */
-	if (offset + len < offset)
-		return -EFAULT;
-
-	/* now we can trust 'offset' and 'length' */
-	*out_offset = offset;
-	*out_len = len;
-
-	return 0;
-}
-
-/**
- * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
- *
- * @offset is relative to the beginning of the DMA buffer, where the packet's
- * data payload should already have been placed.
- */
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
-			       u8 tag, u8 sy)
-{
-	struct hpsb_iso_packet_info *info;
-	unsigned long flags;
-	int rv;
-
-	if (iso->type != HPSB_ISO_XMIT)
-		return -EINVAL;
-
-	/* is there space in the buffer? */
-	if (iso->n_ready_packets <= 0) {
-		return -EBUSY;
-	}
-
-	info = &iso->infos[iso->first_packet];
-
-	/* check for bogus offset/length */
-	if (hpsb_iso_check_offset_len
-	    (iso, offset, len, &info->offset, &info->len))
-		return -EFAULT;
-
-	info->tag = tag;
-	info->sy = sy;
-
-	spin_lock_irqsave(&iso->lock, flags);
-
-	rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
-	if (rv)
-		goto out;
-
-	/* increment cursors */
-	iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
-	iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
-	iso->n_ready_packets--;
-
-	if (iso->prebuffer != 0) {
-		iso->prebuffer--;
-		if (iso->prebuffer <= 0) {
-			iso->prebuffer = 0;
-			rv = do_iso_xmit_start(iso, iso->start_cycle);
-		}
-	}
-
-      out:
-	spin_unlock_irqrestore(&iso->lock, flags);
-	return rv;
-}
-
-/**
- * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
- */
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
-{
-	if (iso->type != HPSB_ISO_XMIT)
-		return -EINVAL;
-
-	return wait_event_interruptible(iso->waitq,
-					hpsb_iso_n_ready(iso) ==
-					iso->buf_packets);
-}
-
-/**
- * hpsb_iso_packet_sent
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been transmitted to the bus (interrupt context is
- * OK).  @cycle is the _exact_ cycle the packet was sent on.  @error should be
- * non-zero if some sort of error occurred when sending the packet.
- */
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&iso->lock, flags);
-
-	/* predict the cycle of the next packet to be queued */
-
-	/* jump ahead by the number of packets that are already buffered */
-	cycle += iso->buf_packets - iso->n_ready_packets;
-	cycle %= 8000;
-
-	iso->xmit_cycle = cycle;
-	iso->n_ready_packets++;
-	iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-
-	if (iso->n_ready_packets == iso->buf_packets || error != 0) {
-		/* the buffer has run empty! */
-		atomic_inc(&iso->overflows);
-	}
-
-	spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_packet_received
- *
- * Available to low-level drivers.
- *
- * Call after a packet has been received (interrupt context is OK).
- */
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-			      u16 total_len, u16 cycle, u8 channel, u8 tag,
-			      u8 sy)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&iso->lock, flags);
-
-	if (iso->n_ready_packets == iso->buf_packets) {
-		/* overflow! */
-		atomic_inc(&iso->overflows);
-		/* Record size of this discarded packet */
-		iso->bytes_discarded += total_len;
-	} else {
-		struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
-		info->offset = offset;
-		info->len = len;
-		info->total_len = total_len;
-		info->cycle = cycle;
-		info->channel = channel;
-		info->tag = tag;
-		info->sy = sy;
-
-		iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
-		iso->n_ready_packets++;
-	}
-
-	spin_unlock_irqrestore(&iso->lock, flags);
-}
-
-/**
- * hpsb_iso_recv_release_packets - release packets, reuse buffer
- *
- * @n_packets have been read out of the buffer, re-use the buffer space
- */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
-{
-	unsigned long flags;
-	unsigned int i;
-	int rv = 0;
-
-	if (iso->type != HPSB_ISO_RECV)
-		return -1;
-
-	spin_lock_irqsave(&iso->lock, flags);
-	for (i = 0; i < n_packets; i++) {
-		rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
-					       (unsigned long)&iso->infos[iso->
-									  first_packet]);
-		if (rv)
-			break;
-
-		iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
-		iso->n_ready_packets--;
-
-		/* release memory from packets discarded when queue was full  */
-		if (iso->n_ready_packets == 0) {	/* Release only after all prior packets handled */
-			if (iso->bytes_discarded != 0) {
-				struct hpsb_iso_packet_info inf;
-				inf.total_len = iso->bytes_discarded;
-				iso->host->driver->isoctl(iso, RECV_RELEASE,
-							  (unsigned long)&inf);
-				iso->bytes_discarded = 0;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&iso->lock, flags);
-	return rv;
-}
-
-/**
- * hpsb_iso_wake
- *
- * Available to low-level drivers.
- *
- * Call to wake waiting processes after buffer space has opened up.
- */
-void hpsb_iso_wake(struct hpsb_iso *iso)
-{
-	wake_up_interruptible(&iso->waitq);
-
-	if (iso->callback)
-		iso->callback(iso);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/iso.h linux-libre-2.6.37-gnu/drivers/ieee1394/iso.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/iso.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/iso.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,195 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * kernel ISO transmission/reception
- *
- * Copyright (C) 2002 Maas Digital LLC
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#ifndef IEEE1394_ISO_H
-#define IEEE1394_ISO_H
-
-#include <linux/spinlock_types.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-#include <asm/types.h>
-
-#include "dma.h"
-
-struct hpsb_host;
-
-/* high-level ISO interface */
-
-/*
- * This API sends and receives isochronous packets on a large,
- * virtually-contiguous kernel memory buffer. The buffer may be mapped
- * into a user-space process for zero-copy transmission and reception.
- *
- * There are no explicit boundaries between packets in the buffer. A
- * packet may be transmitted or received at any location. However,
- * low-level drivers may impose certain restrictions on alignment or
- * size of packets. (e.g. in OHCI no packet may cross a page boundary,
- * and packets should be quadlet-aligned)
- */
-
-/* Packet descriptor - the API maintains a ring buffer of these packet
- * descriptors in kernel memory (hpsb_iso.infos[]).  */
-struct hpsb_iso_packet_info {
-	/* offset of data payload relative to the first byte of the buffer */
-	__u32 offset;
-
-	/* length of the data payload, in bytes (not including the isochronous
-	 * header) */
-	__u16 len;
-
-	/* (recv only) the cycle number (mod 8000) on which the packet was
-	 * received */
-	__u16 cycle;
-
-	/* (recv only) channel on which the packet was received */
-	__u8 channel;
-
-	/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
-	__u8 tag;
-	__u8 sy;
-
-	/* length in bytes of the packet including header/trailer.
-	 * MUST be at structure end, since the first part of this structure is
-	 * also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
-	 * copied to userspace and is accessed there through libraw1394. */
-	__u16 total_len;
-};
-
-enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
-
-/* The mode of the dma when receiving iso data. Must be supported by chip */
-enum raw1394_iso_dma_recv_mode {
-	HPSB_ISO_DMA_DEFAULT = -1,
-	HPSB_ISO_DMA_OLD_ABI = 0,
-	HPSB_ISO_DMA_BUFFERFILL = 1,
-	HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
-};
-
-struct hpsb_iso {
-	enum hpsb_iso_type type;
-
-	/* pointer to low-level driver and its private data */
-	struct hpsb_host *host;
-	void *hostdata;
-
-	/* a function to be called (from interrupt context) after
-	 * outgoing packets have been sent, or incoming packets have
-	 * arrived */
-	void (*callback)(struct hpsb_iso*);
-
-	/* wait for buffer space */
-	wait_queue_head_t waitq;
-
-	int speed; /* IEEE1394_SPEED_100, 200, or 400 */
-	int channel; /* -1 if multichannel */
-	int dma_mode; /* dma receive mode */
-
-
-	/* greatest # of packets between interrupts - controls
-	 * the maximum latency of the buffer */
-	int irq_interval;
-
-	/* the buffer for packet data payloads */
-	struct dma_region data_buf;
-
-	/* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
-	unsigned int buf_size;
-
-	/* # of packets in the ringbuffer */
-	unsigned int buf_packets;
-
-	/* protects packet cursors */
-	spinlock_t lock;
-
-	/* the index of the next packet that will be produced
-	   or consumed by the user */
-	int first_packet;
-
-	/* the index of the next packet that will be transmitted
-	   or received by the 1394 hardware */
-	int pkt_dma;
-
-	/* how many packets, starting at first_packet:
-	 * (transmit) are ready to be filled with data
-	 * (receive)  contain received data */
-	int n_ready_packets;
-
-	/* how many times the buffer has overflowed or underflowed */
-	atomic_t overflows;
-	/* how many cycles were skipped for a given context */
-	atomic_t skips;
-
-	/* Current number of bytes lost in discarded packets */
-	int bytes_discarded;
-
-	/* private flags to track initialization progress */
-#define HPSB_ISO_DRIVER_INIT     (1<<0)
-#define HPSB_ISO_DRIVER_STARTED  (1<<1)
-	unsigned int flags;
-
-	/* # of packets left to prebuffer (xmit only) */
-	int prebuffer;
-
-	/* starting cycle for DMA (xmit only) */
-	int start_cycle;
-
-	/* cycle at which next packet will be transmitted,
-	 * -1 if not known */
-	int xmit_cycle;
-
-	/* ringbuffer of packet descriptors in regular kernel memory
-	 * XXX Keep this last, since we use over-allocated memory from
-	 * this entry to fill this field. */
-	struct hpsb_iso_packet_info *infos;
-};
-
-/* functions available to high-level drivers (e.g. raw1394) */
-
-struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
-				    unsigned int data_buf_size,
-				    unsigned int buf_packets,
-				    int channel,
-				    int speed,
-				    int irq_interval,
-				    void (*callback)(struct hpsb_iso*));
-struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
-				    unsigned int data_buf_size,
-				    unsigned int buf_packets,
-				    int channel,
-				    int dma_mode,
-				    int irq_interval,
-				    void (*callback)(struct hpsb_iso*));
-int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
-int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
-			int prebuffer);
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
-			int tag_mask, int sync);
-void hpsb_iso_stop(struct hpsb_iso *iso);
-void hpsb_iso_shutdown(struct hpsb_iso *iso);
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
-			       u8 tag, u8 sy);
-int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
-				  unsigned int n_packets);
-int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-int hpsb_iso_n_ready(struct hpsb_iso *iso);
-
-/* the following are callbacks available to low-level drivers */
-
-void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
-void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
-			      u16 total_len, u16 cycle, u8 channel, u8 tag,
-			      u8 sy);
-void hpsb_iso_wake(struct hpsb_iso *iso);
-
-#endif /* IEEE1394_ISO_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/Kconfig linux-libre-2.6.37-gnu/drivers/ieee1394/Kconfig
--- linux-libre-2.6.36-gnu/drivers/ieee1394/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/Kconfig	1969-12-31 19:00:00.000000000 -0500
@@ -1,182 +0,0 @@
-config IEEE1394
-	tristate "Legacy alternative FireWire driver stack"
-	depends on PCI || BROKEN
-	help
-	  IEEE 1394 describes a high performance serial bus, which is also
-	  known as FireWire(tm) or i.Link(tm) and is used for connecting all
-	  sorts of devices (most notably digital video cameras) to your
-	  computer.
-
-	  If you have FireWire hardware and want to use it, say Y here.  This
-	  is the core support only, you will also need to select a driver for
-	  your IEEE 1394 adapter.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called ieee1394.
-
-	  NOTE:
-	  ieee1394 is superseded by the newer firewire-core driver.  See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_OHCI1394
-	tristate "OHCI-1394 controllers"
-	depends on PCI && IEEE1394
-	help
-	  Enable this driver if you have an IEEE 1394 controller based on the
-	  OHCI-1394 specification. The current driver is only tested with OHCI
-	  chipsets made by Texas Instruments and NEC. Most third-party vendors
-	  use one of these chipsets.  It should work with any OHCI-1394
-	  compliant card, however.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called ohci1394.
-
-	  NOTE:
-	  ohci1394 is superseded by the newer firewire-ohci driver.  See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-	  If you want to install firewire-ohci and ohci1394 together, you
-	  should configure them only as modules and blacklist the driver(s)
-	  which you don't want to have auto-loaded.  Add either
-
-	      blacklist ohci1394
-	      blacklist video1394
-	      blacklist dv1394
-	  or
-	      blacklist firewire-ohci
-
-	  to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
-	  depending on your distribution.
-
-comment "PCILynx controller requires I2C"
-	depends on IEEE1394 && I2C=n
-
-config IEEE1394_PCILYNX
-	tristate "PCILynx controller"
-	depends on PCI && IEEE1394 && I2C
-	select I2C_ALGOBIT
-	help
-	  Say Y here if you have an IEEE-1394 controller with the Texas
-	  Instruments PCILynx chip.  Note: this driver is written for revision
-	  2 of this chip and may not work with revision 0.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called pcilynx.
-
-	  Only some old and now very rare PCI and CardBus cards and
-	  PowerMacs G3 B&W contain the PCILynx controller.  Therefore
-	  almost everybody can say N here.
-
-comment "SBP-2 support (for storage devices) requires SCSI"
-	depends on IEEE1394 && SCSI=n
-
-config IEEE1394_SBP2
-	tristate "Storage devices (SBP-2 protocol)"
-	depends on IEEE1394 && SCSI
-	help
-	  This option enables you to use SBP-2 devices connected to an IEEE
-	  1394 bus.  SBP-2 devices include storage devices like harddisks and
-	  DVD drives, also some other FireWire devices like scanners.
-
-	  You should also enable support for disks, CD-ROMs, etc. in the SCSI
-	  configuration section.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called sbp2.
-
-	  NOTE:
-	  sbp2 is superseded by the newer firewire-sbp2 driver. See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_SBP2_PHYS_DMA
-	bool "Enable replacement for physical DMA in SBP2"
-	depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
-	help
-	  This builds sbp2 for use with non-OHCI host adapters which do not
-	  support physical DMA or for when ohci1394 is run with phys_dma=0.
-	  Physical DMA is data movement without assistance of the drivers'
-	  interrupt handlers.  This option includes the interrupt handlers
-	  that are required in absence of this hardware feature.
-
-	  This option is buggy and currently broken on some architectures.
-	  If unsure, say N.
-
-config IEEE1394_ETH1394_ROM_ENTRY
-	depends on IEEE1394
-	bool
-	default n
-
-config IEEE1394_ETH1394
-	tristate "IP networking over 1394 (experimental)"
-	depends on IEEE1394 && EXPERIMENTAL && INET
-	select IEEE1394_ETH1394_ROM_ENTRY
-	help
-	  This driver implements a functional majority of RFC 2734: IPv4 over
-	  1394.  It will provide IP connectivity with implementations of RFC
-	  2734 found on other operating systems.  It will not communicate with
-	  older versions of this driver found in stock kernels prior to 2.6.3.
-	  This driver is still considered experimental.  It does not yet support
-	  MCAP, therefore multicast support is significantly limited.
-
-	  The module is called eth1394 although it does not emulate Ethernet.
-
-	  NOTE:
-	  eth1394 is superseded by the newer firewire-net driver. See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_RAWIO
-	tristate "raw1394 userspace interface"
-	depends on IEEE1394
-	help
-	  This option adds support for the raw1394 device file which enables
-	  direct communication of user programs with IEEE 1394 devices
-	  (isochronous and asynchronous).  Almost all application programs
-	  which access FireWire require this option.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called raw1394.
-
-	  NOTE:
-	  raw1394 is superseded by the newer firewire-core driver. See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_VIDEO1394
-	tristate "video1394 userspace interface"
-	depends on IEEE1394 && IEEE1394_OHCI1394
-	help
-	  This option adds support for the video1394 device files which enable
-	  isochronous communication of user programs with IEEE 1394 devices,
-	  especially video capture or export.  This interface is used by all
-	  libdc1394 based programs and by several other programs, in addition to
-	  the raw1394 interface.  It is generally not required for DV capture.
-
-	  To compile this driver as a module, say M here: the module will be
-	  called video1394.
-
-	  NOTE:
-	  video1394 is superseded by the newer firewire-core driver. See
-	  http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
-	  further information on how to switch to the new FireWire drivers.
-
-config IEEE1394_DV1394
-	tristate "dv1394 userspace interface (deprecated)"
-	depends on IEEE1394 && IEEE1394_OHCI1394
-	help
-	  The dv1394 driver is unsupported and may be removed from Linux in a
-	  future release.  Its functionality is now provided by either
-	  raw1394 or firewire-core together with libraries such as libiec61883.
-
-config IEEE1394_VERBOSEDEBUG
-	bool "Excessive debugging output"
-	depends on IEEE1394
-	help
-	  If you say Y here, you will get very verbose debugging logs from the
-	  ieee1394 drivers, including sent and received packet headers.  This
-	  will quickly result in large amounts of data sent to the system log.
-
-	  Say Y if you really need the debugging output.  Everyone else says N.
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/Makefile linux-libre-2.6.37-gnu/drivers/ieee1394/Makefile
--- linux-libre-2.6.36-gnu/drivers/ieee1394/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/Makefile	1969-12-31 19:00:00.000000000 -0500
@@ -1,18 +0,0 @@
-#
-# Makefile for the Linux IEEE 1394 implementation
-#
-
-ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
-		 highlevel.o csr.o nodemgr.o dma.o iso.o \
-		 csr1212.o config_roms.o
-
-obj-$(CONFIG_IEEE1394) += ieee1394.o
-obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
-obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
-obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
-obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
-obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
-obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
-obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
-
-obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/nodemgr.c linux-libre-2.6.37-gnu/drivers/ieee1394/nodemgr.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/nodemgr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/nodemgr.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1901 +0,0 @@
-/*
- * Node information (ConfigROM) collection and management.
- *
- * Copyright (C) 2000		Andreas E. Bombe
- *               2001-2003	Ben Collins <bcollins@debian.net>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- */
-
-#include <linux/bitmap.h>
-#include <linux/kernel.h>
-#include <linux/kmemcheck.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
-#include <linux/freezer.h>
-#include <asm/atomic.h>
-
-#include "csr.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "ieee1394_transactions.h"
-#include "nodemgr.h"
-
-static int ignore_drivers;
-module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
-
-struct nodemgr_csr_info {
-	struct hpsb_host *host;
-	nodeid_t nodeid;
-	unsigned int generation;
-
-	kmemcheck_bitfield_begin(flags);
-	unsigned int speed_unverified:1;
-	kmemcheck_bitfield_end(flags);
-};
-
-
-/*
- * Correct the speed map entry.  This is necessary
- *  - for nodes with link speed < phy speed,
- *  - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
- * A possible speed is determined by trial and error, using quadlet reads.
- */
-static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
-			       quadlet_t *buffer)
-{
-	quadlet_t q;
-	u8 i, *speed, old_speed, good_speed;
-	int error;
-
-	speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
-	old_speed = *speed;
-	good_speed = IEEE1394_SPEED_MAX + 1;
-
-	/* Try every speed from S100 to old_speed.
-	 * If we did it the other way around, a too low speed could be caught
-	 * if the retry succeeded for some other reason, e.g. because the link
-	 * just finished its initialization. */
-	for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
-		*speed = i;
-		error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
-				  &q, 4);
-		if (error)
-			break;
-		*buffer = q;
-		good_speed = i;
-	}
-	if (good_speed <= IEEE1394_SPEED_MAX) {
-		HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
-			   NODE_BUS_ARGS(ci->host, ci->nodeid),
-			   hpsb_speedto_str[good_speed]);
-		*speed = good_speed;
-		ci->speed_unverified = 0;
-		return 0;
-	}
-	*speed = old_speed;
-	return error;
-}
-
-static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr,
-			    void *buffer, void *__ci)
-{
-	struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
-	int i, error;
-
-	for (i = 1; ; i++) {
-		error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
-				  buffer, 4);
-		if (!error) {
-			ci->speed_unverified = 0;
-			break;
-		}
-		/* Give up after 3rd failure. */
-		if (i == 3)
-			break;
-
-		/* The ieee1394_core guessed the node's speed capability from
-		 * the self ID.  Check whether a lower speed works. */
-		if (ci->speed_unverified) {
-			error = nodemgr_check_speed(ci, addr, buffer);
-			if (!error)
-				break;
-		}
-		if (msleep_interruptible(334))
-			return -EINTR;
-	}
-	return error;
-}
-
-static struct csr1212_bus_ops nodemgr_csr_ops = {
-	.bus_read =	nodemgr_bus_read,
-};
-
-
-/*
- * Basically what we do here is start off retrieving the bus_info block.
- * From there will fill in some info about the node, verify it is of IEEE
- * 1394 type, and that the crc checks out ok. After that we start off with
- * the root directory, and subdirectories. To do this, we retrieve the
- * quadlet header for a directory, find out the length, and retrieve the
- * complete directory entry (be it a leaf or a directory). We then process
- * it and add the info to our structure for that particular node.
- *
- * We verify CRC's along the way for each directory/block/leaf. The entire
- * node structure is generic, and simply stores the information in a way
- * that's easy to parse by the protocol interface.
- */
-
-/*
- * The nodemgr relies heavily on the Driver Model for device callbacks and
- * driver/device mappings. The old nodemgr used to handle all this itself,
- * but now we are much simpler because of the LDM.
- */
-
-struct host_info {
-	struct hpsb_host *host;
-	struct list_head list;
-	struct task_struct *thread;
-};
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
-
-struct bus_type ieee1394_bus_type = {
-	.name		= "ieee1394",
-	.match		= nodemgr_bus_match,
-};
-
-static void host_cls_release(struct device *dev)
-{
-	put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
-}
-
-struct class hpsb_host_class = {
-	.name		= "ieee1394_host",
-	.dev_release	= host_cls_release,
-};
-
-static void ne_cls_release(struct device *dev)
-{
-	put_device(&container_of((dev), struct node_entry, node_dev)->device);
-}
-
-static struct class nodemgr_ne_class = {
-	.name		= "ieee1394_node",
-	.dev_release	= ne_cls_release,
-};
-
-static void ud_cls_release(struct device *dev)
-{
-	put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
-}
-
-/* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway.
- */
-static struct class nodemgr_ud_class = {
-	.name		= "ieee1394",
-	.dev_release	= ud_cls_release,
-	.dev_uevent	= nodemgr_uevent,
-};
-
-static struct hpsb_highlevel nodemgr_highlevel;
-
-
-static void nodemgr_release_ud(struct device *dev)
-{
-	struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
-	if (ud->vendor_name_kv)
-		csr1212_release_keyval(ud->vendor_name_kv);
-	if (ud->model_name_kv)
-		csr1212_release_keyval(ud->model_name_kv);
-
-	kfree(ud);
-}
-
-static void nodemgr_release_ne(struct device *dev)
-{
-	struct node_entry *ne = container_of(dev, struct node_entry, device);
-
-	if (ne->vendor_name_kv)
-		csr1212_release_keyval(ne->vendor_name_kv);
-
-	kfree(ne);
-}
-
-
-static void nodemgr_release_host(struct device *dev)
-{
-	struct hpsb_host *host = container_of(dev, struct hpsb_host, device);
-
-	csr1212_destroy_csr(host->csr.rom);
-
-	kfree(host);
-}
-
-static int nodemgr_ud_platform_data;
-
-static struct device nodemgr_dev_template_ud = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_ud,
-	.platform_data	= &nodemgr_ud_platform_data,
-};
-
-static struct device nodemgr_dev_template_ne = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_ne,
-};
-
-/* This dummy driver prevents the host devices from being scanned. We have no
- * useful drivers for them yet, and there would be a deadlock possible if the
- * driver core scans the host device while the host's low-level driver (i.e.
- * the host's parent device) is being removed. */
-static struct device_driver nodemgr_mid_layer_driver = {
-	.bus		= &ieee1394_bus_type,
-	.name		= "nodemgr",
-	.owner		= THIS_MODULE,
-};
-
-struct device nodemgr_dev_template_host = {
-	.bus		= &ieee1394_bus_type,
-	.release	= nodemgr_release_host,
-};
-
-
-#define fw_attr(class, class_type, field, type, format_string)		\
-static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\
-{									\
-	class_type *class;						\
-	class = container_of(dev, class_type, device);			\
-	return sprintf(buf, format_string, (type)class->field);		\
-}									\
-static struct device_attribute dev_attr_##class##_##field = {		\
-	.attr = {.name = __stringify(field), .mode = S_IRUGO },		\
-	.show   = fw_show_##class##_##field,				\
-};
-
-#define fw_attr_td(class, class_type, td_kv)				\
-static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\
-{									\
-	int len;							\
-	class_type *class = container_of(dev, class_type, device);	\
-	len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t);	\
-	memcpy(buf,							\
-	       CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv),	\
-	       len);							\
-	while (buf[len - 1] == '\0')					\
-		len--;							\
-	buf[len++] = '\n';						\
-	buf[len] = '\0';						\
-	return len;							\
-}									\
-static struct device_attribute dev_attr_##class##_##td_kv = {		\
-	.attr = {.name = __stringify(td_kv), .mode = S_IRUGO },		\
-	.show   = fw_show_##class##_##td_kv,				\
-};
-
-
-#define fw_drv_attr(field, type, format_string)			\
-static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
-{								\
-	struct hpsb_protocol_driver *driver;			\
-	driver = container_of(drv, struct hpsb_protocol_driver, driver); \
-	return sprintf(buf, format_string, (type)driver->field);\
-}								\
-static struct driver_attribute driver_attr_drv_##field = {	\
-	.attr = {.name = __stringify(field), .mode = S_IRUGO },	\
-	.show   = fw_drv_show_##field,				\
-};
-
-
-static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct node_entry *ne = container_of(dev, struct node_entry, device);
-
-	return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
-		       "LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)\n",
-		       ne->busopt.irmc,
-		       ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-		       ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
-		       ne->busopt.max_rec,
-		       ne->busopt.max_rom,
-		       ne->busopt.cyc_clk_acc);
-}
-static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-
-
-#ifdef HPSB_DEBUG_TLABELS
-static ssize_t fw_show_ne_tlabels_free(struct device *dev,
-				       struct device_attribute *attr, char *buf)
-{
-	struct node_entry *ne = container_of(dev, struct node_entry, device);
-	unsigned long flags;
-	unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
-	int tf;
-
-	spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-	tf = 64 - bitmap_weight(tp, 64);
-	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-	return sprintf(buf, "%d\n", tf);
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-
-
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
-				       struct device_attribute *attr, char *buf)
-{
-	struct node_entry *ne = container_of(dev, struct node_entry, device);
-	unsigned long flags;
-	unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
-	u64 tm;
-
-	spin_lock_irqsave(&hpsb_tlabel_lock, flags);
-#if (BITS_PER_LONG <= 32)
-	tm = ((u64)tp[0] << 32) + tp[1];
-#else
-	tm = tp[0];
-#endif
-	spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-
-	return sprintf(buf, "0x%016llx\n", (unsigned long long)tm);
-}
-static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
-#endif /* HPSB_DEBUG_TLABELS */
-
-
-static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-	struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-	int state = simple_strtoul(buf, NULL, 10);
-
-	if (state == 1) {
-		ud->ignore_driver = 1;
-		device_release_driver(dev);
-	} else if (state == 0)
-		ud->ignore_driver = 0;
-
-	return count;
-}
-static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct unit_directory *ud = container_of(dev, struct unit_directory, device);
-
-	return sprintf(buf, "%d\n", ud->ignore_driver);
-}
-static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver);
-
-
-static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf,
-			     size_t count)
-{
-	int error = 0;
-
-	if (simple_strtoul(buf, NULL, 10) == 1)
-		error = bus_rescan_devices(&ieee1394_bus_type);
-	return error ? error : count;
-}
-static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
-{
-	return sprintf(buf, "You can force a rescan of the bus for "
-			"drivers by writing a 1 to this file\n");
-}
-static BUS_ATTR(rescan, S_IWUSR | S_IRUGO, fw_get_rescan, fw_set_rescan);
-
-
-static ssize_t fw_set_ignore_drivers(struct bus_type *bus, const char *buf, size_t count)
-{
-	int state = simple_strtoul(buf, NULL, 10);
-
-	if (state == 1)
-		ignore_drivers = 1;
-	else if (state == 0)
-		ignore_drivers = 0;
-
-	return count;
-}
-static ssize_t fw_get_ignore_drivers(struct bus_type *bus, char *buf)
-{
-	return sprintf(buf, "%d\n", ignore_drivers);
-}
-static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set_ignore_drivers);
-
-
-struct bus_attribute *const fw_bus_attrs[] = {
-	&bus_attr_rescan,
-	&bus_attr_ignore_drivers,
-	NULL
-};
-
-
-fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
-
-fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
-fw_attr_td(ne, struct node_entry, vendor_name_kv)
-
-fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
-fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ne, struct node_entry, in_limbo, int, "%d\n");
-
-static struct device_attribute *const fw_ne_attrs[] = {
-	&dev_attr_ne_guid,
-	&dev_attr_ne_guid_vendor_id,
-	&dev_attr_ne_capabilities,
-	&dev_attr_ne_vendor_id,
-	&dev_attr_ne_nodeid,
-	&dev_attr_bus_options,
-#ifdef HPSB_DEBUG_TLABELS
-	&dev_attr_tlabels_free,
-	&dev_attr_tlabels_mask,
-#endif
-};
-
-
-
-fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n")
-fw_attr(ud, struct unit_directory, length, int, "%d\n")
-/* These are all dependent on the value being provided */
-fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
-fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
-fw_attr_td(ud, struct unit_directory, vendor_name_kv)
-fw_attr_td(ud, struct unit_directory, model_name_kv)
-
-static struct device_attribute *const fw_ud_attrs[] = {
-	&dev_attr_ud_address,
-	&dev_attr_ud_length,
-	&dev_attr_ignore_driver,
-};
-
-
-fw_attr(host, struct hpsb_host, node_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n")
-fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n")
-fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_root, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_irm, int, "%d\n")
-fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n")
-
-static struct device_attribute *const fw_host_attrs[] = {
-	&dev_attr_host_node_count,
-	&dev_attr_host_selfid_count,
-	&dev_attr_host_nodes_active,
-	&dev_attr_host_in_bus_reset,
-	&dev_attr_host_is_root,
-	&dev_attr_host_is_cycmst,
-	&dev_attr_host_is_irm,
-	&dev_attr_host_is_busmgr,
-};
-
-
-static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
-{
-	struct hpsb_protocol_driver *driver;
-	const struct ieee1394_device_id *id;
-	int length = 0;
-	char *scratch = buf;
-
-	driver = container_of(drv, struct hpsb_protocol_driver, driver);
-	id = driver->id_table;
-	if (!id)
-		return 0;
-
-	for (; id->match_flags != 0; id++) {
-		int need_coma = 0;
-
-		if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
-			length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id);
-			scratch = buf + length;
-			need_coma++;
-		}
-
-		if (id->match_flags & IEEE1394_MATCH_MODEL_ID) {
-			length += sprintf(scratch, "%smodel_id=0x%06x",
-					  need_coma++ ? "," : "",
-					  id->model_id);
-			scratch = buf + length;
-		}
-
-		if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) {
-			length += sprintf(scratch, "%sspecifier_id=0x%06x",
-					  need_coma++ ? "," : "",
-					  id->specifier_id);
-			scratch = buf + length;
-		}
-
-		if (id->match_flags & IEEE1394_MATCH_VERSION) {
-			length += sprintf(scratch, "%sversion=0x%06x",
-					  need_coma++ ? "," : "",
-					  id->version);
-			scratch = buf + length;
-		}
-
-		if (need_coma) {
-			*scratch++ = '\n';
-			length++;
-		}
-	}
-
-	return length;
-}
-static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL);
-
-
-fw_drv_attr(name, const char *, "%s\n")
-
-static struct driver_attribute *const fw_drv_attrs[] = {
-	&driver_attr_drv_name,
-	&driver_attr_device_ids,
-};
-
-
-static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
-{
-	struct device_driver *drv = &driver->driver;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
-		if (driver_create_file(drv, fw_drv_attrs[i]))
-			goto fail;
-	return;
-fail:
-	HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver)
-{
-	struct device_driver *drv = &driver->driver;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
-		driver_remove_file(drv, fw_drv_attrs[i]);
-}
-
-
-static void nodemgr_create_ne_dev_files(struct node_entry *ne)
-{
-	struct device *dev = &ne->device;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
-		if (device_create_file(dev, fw_ne_attrs[i]))
-			goto fail;
-	return;
-fail:
-	HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static void nodemgr_create_host_dev_files(struct hpsb_host *host)
-{
-	struct device *dev = &host->device;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
-		if (device_create_file(dev, fw_host_attrs[i]))
-			goto fail;
-	return;
-fail:
-	HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
-					       nodeid_t nodeid);
-
-static void nodemgr_update_host_dev_links(struct hpsb_host *host)
-{
-	struct device *dev = &host->device;
-	struct node_entry *ne;
-
-	sysfs_remove_link(&dev->kobj, "irm_id");
-	sysfs_remove_link(&dev->kobj, "busmgr_id");
-	sysfs_remove_link(&dev->kobj, "host_id");
-
-	if ((ne = find_entry_by_nodeid(host, host->irm_id)) &&
-	    sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"))
-		goto fail;
-	if ((ne = find_entry_by_nodeid(host, host->busmgr_id)) &&
-	    sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"))
-		goto fail;
-	if ((ne = find_entry_by_nodeid(host, host->node_id)) &&
-	    sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id"))
-		goto fail;
-	return;
-fail:
-	HPSB_ERR("Failed to update sysfs attributes for host %d", host->id);
-}
-
-static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
-{
-	struct device *dev = &ud->device;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
-		if (device_create_file(dev, fw_ud_attrs[i]))
-			goto fail;
-	if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
-		if (device_create_file(dev, &dev_attr_ud_specifier_id))
-			goto fail;
-	if (ud->flags & UNIT_DIRECTORY_VERSION)
-		if (device_create_file(dev, &dev_attr_ud_version))
-			goto fail;
-	if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
-		if (device_create_file(dev, &dev_attr_ud_vendor_id))
-			goto fail;
-		if (ud->vendor_name_kv &&
-		    device_create_file(dev, &dev_attr_ud_vendor_name_kv))
-			goto fail;
-	}
-	if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
-		if (device_create_file(dev, &dev_attr_ud_model_id))
-			goto fail;
-		if (ud->model_name_kv &&
-		    device_create_file(dev, &dev_attr_ud_model_name_kv))
-			goto fail;
-	}
-	return;
-fail:
-	HPSB_ERR("Failed to add sysfs attribute");
-}
-
-
-static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
-{
-	struct hpsb_protocol_driver *driver;
-	struct unit_directory *ud;
-	const struct ieee1394_device_id *id;
-
-	/* We only match unit directories */
-	if (dev->platform_data != &nodemgr_ud_platform_data)
-		return 0;
-
-	ud = container_of(dev, struct unit_directory, device);
-	if (ud->ne->in_limbo || ud->ignore_driver)
-		return 0;
-
-	/* We only match drivers of type hpsb_protocol_driver */
-	if (drv == &nodemgr_mid_layer_driver)
-		return 0;
-
-	driver = container_of(drv, struct hpsb_protocol_driver, driver);
-	id = driver->id_table;
-	if (!id)
-		return 0;
-
-	for (; id->match_flags != 0; id++) {
-		if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
-		    id->vendor_id != ud->vendor_id)
-			continue;
-
-		if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
-		    id->model_id != ud->model_id)
-			continue;
-
-		if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
-		    id->specifier_id != ud->specifier_id)
-			continue;
-
-		if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
-		    id->version != ud->version)
-			continue;
-
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
-
-static int match_ne(struct device *dev, void *data)
-{
-	struct unit_directory *ud;
-	struct node_entry *ne = data;
-
-	ud = container_of(dev, struct unit_directory, unit_dev);
-	return ud->ne == ne;
-}
-
-static void nodemgr_remove_uds(struct node_entry *ne)
-{
-	struct device *dev;
-	struct unit_directory *ud;
-
-	/* Use class_find device to iterate the devices. Since this code
-	 * may be called from other contexts besides the knodemgrds,
-	 * protect it by nodemgr_serialize_remove_uds.
-	 */
-	mutex_lock(&nodemgr_serialize_remove_uds);
-	for (;;) {
-		dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne);
-		if (!dev)
-			break;
-		ud = container_of(dev, struct unit_directory, unit_dev);
-		put_device(dev);
-		device_unregister(&ud->unit_dev);
-		device_unregister(&ud->device);
-	}
-	mutex_unlock(&nodemgr_serialize_remove_uds);
-}
-
-
-static void nodemgr_remove_ne(struct node_entry *ne)
-{
-	struct device *dev;
-
-	dev = get_device(&ne->device);
-	if (!dev)
-		return;
-
-	HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
-	nodemgr_remove_uds(ne);
-
-	device_unregister(&ne->node_dev);
-	device_unregister(dev);
-
-	put_device(dev);
-}
-
-static int remove_host_dev(struct device *dev, void *data)
-{
-	if (dev->bus == &ieee1394_bus_type)
-		nodemgr_remove_ne(container_of(dev, struct node_entry,
-				  device));
-	return 0;
-}
-
-static void nodemgr_remove_host_dev(struct device *dev)
-{
-	device_for_each_child(dev, NULL, remove_host_dev);
-	sysfs_remove_link(&dev->kobj, "irm_id");
-	sysfs_remove_link(&dev->kobj, "busmgr_id");
-	sysfs_remove_link(&dev->kobj, "host_id");
-}
-
-
-static void nodemgr_update_bus_options(struct node_entry *ne)
-{
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	static const u16 mr[] = { 4, 64, 1024, 0};
-#endif
-	quadlet_t busoptions = be32_to_cpu(ne->csr->bus_info_data[2]);
-
-	ne->busopt.irmc		= (busoptions >> 31) & 1;
-	ne->busopt.cmc		= (busoptions >> 30) & 1;
-	ne->busopt.isc		= (busoptions >> 29) & 1;
-	ne->busopt.bmc		= (busoptions >> 28) & 1;
-	ne->busopt.pmc		= (busoptions >> 27) & 1;
-	ne->busopt.cyc_clk_acc	= (busoptions >> 16) & 0xff;
-	ne->busopt.max_rec	= 1 << (((busoptions >> 12) & 0xf) + 1);
-	ne->busopt.max_rom	= (busoptions >> 8) & 0x3;
-	ne->busopt.generation	= (busoptions >> 4) & 0xf;
-	ne->busopt.lnkspd	= busoptions & 0x7;
-
-	HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
-		     "cyc_clk_acc=%d max_rec=%d max_rom=%d gen=%d lspd=%d",
-		     busoptions, ne->busopt.irmc, ne->busopt.cmc,
-		     ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc,
-		     ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
-		     mr[ne->busopt.max_rom],
-		     ne->busopt.generation, ne->busopt.lnkspd);
-}
-
-
-static struct node_entry *nodemgr_create_node(octlet_t guid,
-				struct csr1212_csr *csr, struct hpsb_host *host,
-				nodeid_t nodeid, unsigned int generation)
-{
-	struct node_entry *ne;
-
-	ne = kzalloc(sizeof(*ne), GFP_KERNEL);
-	if (!ne)
-		goto fail_alloc;
-
-	ne->host = host;
-	ne->nodeid = nodeid;
-	ne->generation = generation;
-	ne->needs_probe = true;
-
-	ne->guid = guid;
-	ne->guid_vendor_id = (guid >> 40) & 0xffffff;
-	ne->csr = csr;
-
-	memcpy(&ne->device, &nodemgr_dev_template_ne,
-	       sizeof(ne->device));
-	ne->device.parent = &host->device;
-	dev_set_name(&ne->device, "%016Lx", (unsigned long long)(ne->guid));
-
-	ne->node_dev.parent = &ne->device;
-	ne->node_dev.class = &nodemgr_ne_class;
-	dev_set_name(&ne->node_dev, "%016Lx", (unsigned long long)(ne->guid));
-
-	if (device_register(&ne->device))
-		goto fail_devreg;
-	if (device_register(&ne->node_dev))
-		goto fail_classdevreg;
-	get_device(&ne->device);
-
-	nodemgr_create_ne_dev_files(ne);
-
-	nodemgr_update_bus_options(ne);
-
-	HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-		   (host->node_id == nodeid) ? "Host" : "Node",
-		   NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
-	return ne;
-
-fail_classdevreg:
-	device_unregister(&ne->device);
-fail_devreg:
-	kfree(ne);
-fail_alloc:
-	HPSB_ERR("Failed to create node ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-		 NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid);
-
-	return NULL;
-}
-
-static int match_ne_guid(struct device *dev, void *data)
-{
-	struct node_entry *ne;
-	u64 *guid = data;
-
-	ne = container_of(dev, struct node_entry, node_dev);
-	return ne->guid == *guid;
-}
-
-static struct node_entry *find_entry_by_guid(u64 guid)
-{
-	struct device *dev;
-	struct node_entry *ne;
-
-	dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid);
-	if (!dev)
-		return NULL;
-	ne = container_of(dev, struct node_entry, node_dev);
-	put_device(dev);
-
-	return ne;
-}
-
-struct match_nodeid_parameter {
-	struct hpsb_host *host;
-	nodeid_t nodeid;
-};
-
-static int match_ne_nodeid(struct device *dev, void *data)
-{
-	int found = 0;
-	struct node_entry *ne;
-	struct match_nodeid_parameter *p = data;
-
-	if (!dev)
-		goto ret;
-	ne = container_of(dev, struct node_entry, node_dev);
-	if (ne->host == p->host && ne->nodeid == p->nodeid)
-		found = 1;
-ret:
-	return found;
-}
-
-static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
-					       nodeid_t nodeid)
-{
-	struct device *dev;
-	struct node_entry *ne;
-	struct match_nodeid_parameter p;
-
-	p.host = host;
-	p.nodeid = nodeid;
-
-	dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid);
-	if (!dev)
-		return NULL;
-	ne = container_of(dev, struct node_entry, node_dev);
-	put_device(dev);
-
-	return ne;
-}
-
-
-static void nodemgr_register_device(struct node_entry *ne, 
-	struct unit_directory *ud, struct device *parent)
-{
-	memcpy(&ud->device, &nodemgr_dev_template_ud,
-	       sizeof(ud->device));
-
-	ud->device.parent = parent;
-
-	dev_set_name(&ud->device, "%s-%u", dev_name(&ne->device), ud->id);
-
-	ud->unit_dev.parent = &ud->device;
-	ud->unit_dev.class = &nodemgr_ud_class;
-	dev_set_name(&ud->unit_dev, "%s-%u", dev_name(&ne->device), ud->id);
-
-	if (device_register(&ud->device))
-		goto fail_devreg;
-	if (device_register(&ud->unit_dev))
-		goto fail_classdevreg;
-	get_device(&ud->device);
-
-	nodemgr_create_ud_dev_files(ud);
-
-	return;
-
-fail_classdevreg:
-	device_unregister(&ud->device);
-fail_devreg:
-	HPSB_ERR("Failed to create unit %s", dev_name(&ud->device));
-}	
-
-
-/* This implementation currently only scans the config rom and its
- * immediate unit directories looking for software_id and
- * software_version entries, in order to get driver autoloading working. */
-static struct unit_directory *nodemgr_process_unit_directory
-	(struct node_entry *ne, struct csr1212_keyval *ud_kv,
-	 unsigned int *id, struct unit_directory *parent)
-{
-	struct unit_directory *ud;
-	struct unit_directory *ud_child = NULL;
-	struct csr1212_dentry *dentry;
-	struct csr1212_keyval *kv;
-	u8 last_key_id = 0;
-
-	ud = kzalloc(sizeof(*ud), GFP_KERNEL);
-	if (!ud)
-		goto unit_directory_error;
-
-	ud->ne = ne;
-	ud->ignore_driver = ignore_drivers;
-	ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE;
-	ud->directory_id = ud->address & 0xffffff;
-	ud->ud_kv = ud_kv;
-	ud->id = (*id)++;
-
-	/* inherit vendor_id from root directory if none exists in unit dir */
-	ud->vendor_id = ne->vendor_id;
-
-	csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
-		switch (kv->key.id) {
-		case CSR1212_KV_ID_VENDOR:
-			if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
-				ud->vendor_id = kv->value.immediate;
-				ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
-			}
-			break;
-
-		case CSR1212_KV_ID_MODEL:
-			ud->model_id = kv->value.immediate;
-			ud->flags |= UNIT_DIRECTORY_MODEL_ID;
-			break;
-
-		case CSR1212_KV_ID_SPECIFIER_ID:
-			ud->specifier_id = kv->value.immediate;
-			ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID;
-			break;
-
-		case CSR1212_KV_ID_VERSION:
-			ud->version = kv->value.immediate;
-			ud->flags |= UNIT_DIRECTORY_VERSION;
-			break;
-
-		case CSR1212_KV_ID_DESCRIPTOR:
-			if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
-			    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
-			    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
-			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
-			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
-			    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
-				switch (last_key_id) {
-				case CSR1212_KV_ID_VENDOR:
-					csr1212_keep_keyval(kv);
-					ud->vendor_name_kv = kv;
-					break;
-
-				case CSR1212_KV_ID_MODEL:
-					csr1212_keep_keyval(kv);
-					ud->model_name_kv = kv;
-					break;
-
-				}
-			} /* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
-			break;
-
-		case CSR1212_KV_ID_DEPENDENT_INFO:
-			/* Logical Unit Number */
-			if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
-				if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
-					ud_child = kmemdup(ud, sizeof(*ud_child), GFP_KERNEL);
-					if (!ud_child)
-						goto unit_directory_error;
-					nodemgr_register_device(ne, ud_child, &ne->device);
-					ud_child = NULL;
-					
-					ud->id = (*id)++;
-				}
-				ud->lun = kv->value.immediate;
-				ud->flags |= UNIT_DIRECTORY_HAS_LUN;
-
-			/* Logical Unit Directory */
-			} else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) {
-				/* This should really be done in SBP2 as this is
-				 * doing SBP2 specific parsing.
-				 */
-				
-				/* first register the parent unit */
-				ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY;
-				if (ud->device.bus != &ieee1394_bus_type)
-					nodemgr_register_device(ne, ud, &ne->device);
-				
-				/* process the child unit */
-				ud_child = nodemgr_process_unit_directory(ne, kv, id, ud);
-
-				if (ud_child == NULL)
-					break;
-				
-				/* inherit unspecified values, the driver core picks it up */
-				if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
-				    !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
-				{
-					ud_child->flags |=  UNIT_DIRECTORY_MODEL_ID;
-					ud_child->model_id = ud->model_id;
-				}
-				if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) &&
-				    !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID))
-				{
-					ud_child->flags |=  UNIT_DIRECTORY_SPECIFIER_ID;
-					ud_child->specifier_id = ud->specifier_id;
-				}
-				if ((ud->flags & UNIT_DIRECTORY_VERSION) &&
-				    !(ud_child->flags & UNIT_DIRECTORY_VERSION))
-				{
-					ud_child->flags |=  UNIT_DIRECTORY_VERSION;
-					ud_child->version = ud->version;
-				}
-				
-				/* register the child unit */
-				ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY;
-				nodemgr_register_device(ne, ud_child, &ud->device);
-			}
-
-			break;
-
-		case CSR1212_KV_ID_DIRECTORY_ID:
-			ud->directory_id = kv->value.immediate;
-			break;
-
-		default:
-			break;
-		}
-		last_key_id = kv->key.id;
-	}
-	
-	/* do not process child units here and only if not already registered */
-	if (!parent && ud->device.bus != &ieee1394_bus_type)
-		nodemgr_register_device(ne, ud, &ne->device);
-
-	return ud;
-
-unit_directory_error:
-	kfree(ud);
-	return NULL;
-}
-
-
-static void nodemgr_process_root_directory(struct node_entry *ne)
-{
-	unsigned int ud_id = 0;
-	struct csr1212_dentry *dentry;
-	struct csr1212_keyval *kv, *vendor_name_kv = NULL;
-	u8 last_key_id = 0;
-
-	ne->needs_probe = false;
-
-	csr1212_for_each_dir_entry(ne->csr, kv, ne->csr->root_kv, dentry) {
-		switch (kv->key.id) {
-		case CSR1212_KV_ID_VENDOR:
-			ne->vendor_id = kv->value.immediate;
-			break;
-
-		case CSR1212_KV_ID_NODE_CAPABILITIES:
-			ne->capabilities = kv->value.immediate;
-			break;
-
-		case CSR1212_KV_ID_UNIT:
-			nodemgr_process_unit_directory(ne, kv, &ud_id, NULL);
-			break;
-
-		case CSR1212_KV_ID_DESCRIPTOR:
-			if (last_key_id == CSR1212_KV_ID_VENDOR) {
-				if (kv->key.type == CSR1212_KV_TYPE_LEAF &&
-				    CSR1212_DESCRIPTOR_LEAF_TYPE(kv) == 0 &&
-				    CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) == 0 &&
-				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
-				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
-				    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
-					csr1212_keep_keyval(kv);
-					vendor_name_kv = kv;
-				}
-			}
-			break;
-		}
-		last_key_id = kv->key.id;
-	}
-
-	if (ne->vendor_name_kv) {
-		kv = ne->vendor_name_kv;
-		ne->vendor_name_kv = vendor_name_kv;
-		csr1212_release_keyval(kv);
-	} else if (vendor_name_kv) {
-		ne->vendor_name_kv = vendor_name_kv;
-		if (device_create_file(&ne->device,
-				       &dev_attr_ne_vendor_name_kv) != 0)
-			HPSB_ERR("Failed to add sysfs attribute");
-	}
-}
-
-#ifdef CONFIG_HOTPLUG
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-	struct unit_directory *ud;
-	int retval = 0;
-	/* ieee1394:venNmoNspNverN */
-	char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
-
-	if (!dev)
-		return -ENODEV;
-
-	ud = container_of(dev, struct unit_directory, unit_dev);
-
-	if (ud->ne->in_limbo || ud->ignore_driver)
-		return -ENODEV;
-
-#define PUT_ENVP(fmt,val) 					\
-do {								\
-	retval = add_uevent_var(env, fmt, val);		\
-	if (retval)						\
-		return retval;					\
-} while (0)
-
-	PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
-	PUT_ENVP("MODEL_ID=%06x", ud->model_id);
-	PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
-	PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
-	PUT_ENVP("VERSION=%06x", ud->version);
-	snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
-			ud->vendor_id,
-			ud->model_id,
-			ud->specifier_id,
-			ud->version);
-	PUT_ENVP("MODALIAS=%s", buf);
-
-#undef PUT_ENVP
-
-	return 0;
-}
-
-#else
-
-static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-	return -ENODEV;
-}
-
-#endif /* CONFIG_HOTPLUG */
-
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *drv,
-			     struct module *owner)
-{
-	int error;
-
-	drv->driver.bus = &ieee1394_bus_type;
-	drv->driver.owner = owner;
-	drv->driver.name = drv->name;
-
-	/* This will cause a probe for devices */
-	error = driver_register(&drv->driver);
-	if (!error)
-		nodemgr_create_drv_files(drv);
-	return error;
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
-{
-	nodemgr_remove_drv_files(driver);
-	/* This will subsequently disconnect all devices that our driver
-	 * is attached to. */
-	driver_unregister(&driver->driver);
-}
-
-
-/*
- * This function updates nodes that were present on the bus before the
- * reset and still are after the reset.  The nodeid and the config rom
- * may have changed, and the drivers managing this device must be
- * informed that this device just went through a bus reset, to allow
- * the to take whatever actions required.
- */
-static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
-				nodeid_t nodeid, unsigned int generation)
-{
-	if (ne->nodeid != nodeid) {
-		HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT,
-			   NODE_BUS_ARGS(ne->host, ne->nodeid),
-			   NODE_BUS_ARGS(ne->host, nodeid));
-		ne->nodeid = nodeid;
-	}
-
-	if (ne->busopt.generation != ((be32_to_cpu(csr->bus_info_data[2]) >> 4) & 0xf)) {
-		kfree(ne->csr->private);
-		csr1212_destroy_csr(ne->csr);
-		ne->csr = csr;
-
-		/* If the node's configrom generation has changed, we
-		 * unregister all the unit directories. */
-		nodemgr_remove_uds(ne);
-
-		nodemgr_update_bus_options(ne);
-
-		/* Mark the node as new, so it gets re-probed */
-		ne->needs_probe = true;
-	} else {
-		/* old cache is valid, so update its generation */
-		struct nodemgr_csr_info *ci = ne->csr->private;
-		ci->generation = generation;
-		/* free the partially filled now unneeded new cache */
-		kfree(csr->private);
-		csr1212_destroy_csr(csr);
-	}
-
-	/* Finally, mark the node current */
-	smp_wmb();
-	ne->generation = generation;
-
-	if (ne->in_limbo) {
-		device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
-		ne->in_limbo = false;
-
-		HPSB_DEBUG("Node reactivated: "
-			   "ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-			   NODE_BUS_ARGS(ne->host, ne->nodeid),
-			   (unsigned long long)ne->guid);
-	}
-}
-
-static void nodemgr_node_scan_one(struct hpsb_host *host,
-				  nodeid_t nodeid, int generation)
-{
-	struct node_entry *ne;
-	octlet_t guid;
-	struct csr1212_csr *csr;
-	struct nodemgr_csr_info *ci;
-	u8 *speed;
-
-	ci = kmalloc(sizeof(*ci), GFP_KERNEL);
-	kmemcheck_annotate_bitfield(ci, flags);
-	if (!ci)
-		return;
-
-	ci->host = host;
-	ci->nodeid = nodeid;
-	ci->generation = generation;
-
-	/* Prepare for speed probe which occurs when reading the ROM */
-	speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
-	if (*speed > host->csr.lnk_spd)
-		*speed = host->csr.lnk_spd;
-	ci->speed_unverified = *speed > IEEE1394_SPEED_100;
-
-	/* We need to detect when the ConfigROM's generation has changed,
-	 * so we only update the node's info when it needs to be.  */
-
-	csr = csr1212_create_csr(&nodemgr_csr_ops, 5 * sizeof(quadlet_t), ci);
-	if (!csr || csr1212_parse_csr(csr) != CSR1212_SUCCESS) {
-		HPSB_ERR("Error parsing configrom for node " NODE_BUS_FMT,
-			 NODE_BUS_ARGS(host, nodeid));
-		if (csr)
-			csr1212_destroy_csr(csr);
-		kfree(ci);
-		return;
-	}
-
-	if (csr->bus_info_data[1] != IEEE1394_BUSID_MAGIC) {
-		/* This isn't a 1394 device, but we let it slide. There
-		 * was a report of a device with broken firmware which
-		 * reported '2394' instead of '1394', which is obviously a
-		 * mistake. One would hope that a non-1394 device never
-		 * gets connected to Firewire bus. If someone does, we
-		 * shouldn't be held responsible, so we'll allow it with a
-		 * warning.  */
-		HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]",
-			  NODE_BUS_ARGS(host, nodeid), csr->bus_info_data[1]);
-	}
-
-	guid = ((u64)be32_to_cpu(csr->bus_info_data[3]) << 32) | be32_to_cpu(csr->bus_info_data[4]);
-	ne = find_entry_by_guid(guid);
-
-	if (ne && ne->host != host && ne->in_limbo) {
-		/* Must have moved this device from one host to another */
-		nodemgr_remove_ne(ne);
-		ne = NULL;
-	}
-
-	if (!ne)
-		nodemgr_create_node(guid, csr, host, nodeid, generation);
-	else
-		nodemgr_update_node(ne, csr, nodeid, generation);
-}
-
-
-static void nodemgr_node_scan(struct hpsb_host *host, int generation)
-{
-	int count;
-	struct selfid *sid = (struct selfid *)host->topology_map;
-	nodeid_t nodeid = LOCAL_BUS;
-
-	/* Scan each node on the bus */
-	for (count = host->selfid_count; count; count--, sid++) {
-		if (sid->extended)
-			continue;
-
-		if (!sid->link_active) {
-			nodeid++;
-			continue;
-		}
-		nodemgr_node_scan_one(host, nodeid++, generation);
-	}
-}
-
-static void nodemgr_pause_ne(struct node_entry *ne)
-{
-	HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-		   NODE_BUS_ARGS(ne->host, ne->nodeid),
-		   (unsigned long long)ne->guid);
-
-	ne->in_limbo = true;
-	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
-}
-
-static int update_pdrv(struct device *dev, void *data)
-{
-	struct unit_directory *ud;
-	struct device_driver *drv;
-	struct hpsb_protocol_driver *pdrv;
-	struct node_entry *ne = data;
-	int error;
-
-	ud = container_of(dev, struct unit_directory, unit_dev);
-	if (ud->ne == ne) {
-		drv = get_driver(ud->device.driver);
-		if (drv) {
-			error = 0;
-			pdrv = container_of(drv, struct hpsb_protocol_driver,
-					    driver);
-			if (pdrv->update) {
-				device_lock(&ud->device);
-				error = pdrv->update(ud);
-				device_unlock(&ud->device);
-			}
-			if (error)
-				device_release_driver(&ud->device);
-			put_driver(drv);
-		}
-	}
-
-	return 0;
-}
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
-{
-	class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv);
-}
-
-/* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3.  This
- * seems like an optional service but in the end it is practically mandatory
- * as a consequence of these clauses.
- *
- * Note that we cannot do a broadcast write to all nodes at once because some
- * pre-1394a devices would hang. */
-static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
-{
-	const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL);
-	quadlet_t bc_remote, bc_local;
-	int error;
-
-	if (!ne->host->is_irm || ne->generation != generation ||
-	    ne->nodeid == ne->host->node_id)
-		return;
-
-	bc_local = cpu_to_be32(ne->host->csr.broadcast_channel);
-
-	/* Check if the register is implemented and 1394a compliant. */
-	error = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote,
-			  sizeof(bc_remote));
-	if (!error && bc_remote & cpu_to_be32(0x80000000) &&
-	    bc_remote != bc_local)
-		hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local));
-}
-
-
-static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne,
-			     int generation)
-{
-	struct device *dev;
-
-	if (ne->host != host || ne->in_limbo)
-		return;
-
-	dev = get_device(&ne->device);
-	if (!dev)
-		return;
-
-	nodemgr_irm_write_bc(ne, generation);
-
-	/* If "needs_probe", then this is either a new or changed node we
-	 * rescan totally. If the generation matches for an existing node
-	 * (one that existed prior to the bus reset) we send update calls
-	 * down to the drivers. Otherwise, this is a dead node and we
-	 * suspend it. */
-	if (ne->needs_probe)
-		nodemgr_process_root_directory(ne);
-	else if (ne->generation == generation)
-		nodemgr_update_pdrv(ne);
-	else
-		nodemgr_pause_ne(ne);
-
-	put_device(dev);
-}
-
-struct node_probe_parameter {
-	struct hpsb_host *host;
-	int generation;
-	bool probe_now;
-};
-
-static int node_probe(struct device *dev, void *data)
-{
-	struct node_probe_parameter *p = data;
-	struct node_entry *ne;
-
-	if (p->generation != get_hpsb_generation(p->host))
-		return -EAGAIN;
-
-	ne = container_of(dev, struct node_entry, node_dev);
-	if (ne->needs_probe == p->probe_now)
-		nodemgr_probe_ne(p->host, ne, p->generation);
-	return 0;
-}
-
-static int nodemgr_node_probe(struct hpsb_host *host, int generation)
-{
-	struct node_probe_parameter p;
-
-	p.host = host;
-	p.generation = generation;
-	/*
-	 * Do some processing of the nodes we've probed. This pulls them
-	 * into the sysfs layer if needed, and can result in processing of
-	 * unit-directories, or just updating the node and it's
-	 * unit-directories.
-	 *
-	 * Run updates before probes. Usually, updates are time-critical
-	 * while probes are time-consuming.
-	 *
-	 * Meanwhile, another bus reset may have happened. In this case we
-	 * skip everything here and let the next bus scan handle it.
-	 * Otherwise we may prematurely remove nodes which are still there.
-	 */
-	p.probe_now = false;
-	if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
-		return 0;
-
-	p.probe_now = true;
-	if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0)
-		return 0;
-	/*
-	 * Now let's tell the bus to rescan our devices. This may seem
-	 * like overhead, but the driver-model core will only scan a
-	 * device for a driver when either the device is added, or when a
-	 * new driver is added. A bus reset is a good reason to rescan
-	 * devices that were there before.  For example, an sbp2 device
-	 * may become available for login, if the host that held it was
-	 * just removed.
-	 */
-	if (bus_rescan_devices(&ieee1394_bus_type) != 0)
-		HPSB_DEBUG("bus_rescan_devices had an error");
-
-	return 1;
-}
-
-static int remove_nodes_in_limbo(struct device *dev, void *data)
-{
-	struct node_entry *ne;
-
-	if (dev->bus != &ieee1394_bus_type)
-		return 0;
-
-	ne = container_of(dev, struct node_entry, device);
-	if (ne->in_limbo)
-		nodemgr_remove_ne(ne);
-
-	return 0;
-}
-
-static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host)
-{
-	device_for_each_child(&host->device, NULL, remove_nodes_in_limbo);
-}
-
-static int nodemgr_send_resume_packet(struct hpsb_host *host)
-{
-	struct hpsb_packet *packet;
-	int error = -ENOMEM;
-
-	packet = hpsb_make_phypacket(host,
-			EXTPHYPACKET_TYPE_RESUME |
-			NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT);
-	if (packet) {
-		packet->no_waiter = 1;
-		packet->generation = get_hpsb_generation(host);
-		error = hpsb_send_packet(packet);
-	}
-	if (error)
-		HPSB_WARN("fw-host%d: Failed to broadcast resume packet",
-			  host->id);
-	return error;
-}
-
-/* Perform a few high-level IRM responsibilities. */
-static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
-{
-	quadlet_t bc;
-
-	/* if irm_id == -1 then there is no IRM on this bus */
-	if (!host->is_irm || host->irm_id == (nodeid_t)-1)
-		return 1;
-
-	/* We are a 1394a-2000 compliant IRM. Set the validity bit. */
-	host->csr.broadcast_channel |= 0x40000000;
-
-	/* If there is no bus manager then we should set the root node's
-	 * force_root bit to promote bus stability per the 1394
-	 * spec. (8.4.2.6) */
-	if (host->busmgr_id == 0xffff && host->node_count > 1)
-	{
-		u16 root_node = host->node_count - 1;
-
-		/* get cycle master capability flag from root node */
-		if (host->is_cycmst ||
-		    (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host),
-				(CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)),
-				&bc, sizeof(quadlet_t)) &&
-		     be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT))
-			hpsb_send_phy_config(host, root_node, -1);
-		else {
-			HPSB_DEBUG("The root node is not cycle master capable; "
-				   "selecting a new root node and resetting...");
-
-			if (cycles >= 5) {
-				/* Oh screw it! Just leave the bus as it is */
-				HPSB_DEBUG("Stopping reset loop for IRM sanity");
-				return 1;
-			}
-
-			hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
-			hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
-			return 0;
-		}
-	}
-
-	/* Some devices suspend their ports while being connected to an inactive
-	 * host adapter, i.e. if connected before the low-level driver is
-	 * loaded.  They become visible either when physically unplugged and
-	 * replugged, or when receiving a resume packet.  Send one once. */
-	if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host))
-		host->resume_packet_sent = 1;
-
-	return 1;
-}
-
-/* We need to ensure that if we are not the IRM, that the IRM node is capable of
- * everything we can do, otherwise issue a bus reset and try to become the IRM
- * ourselves. */
-static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles)
-{
-	quadlet_t bc;
-	int status;
-
-	if (hpsb_disable_irm || host->is_irm)
-		return 1;
-
-	status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
-			   get_hpsb_generation(host),
-			   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
-			   &bc, sizeof(quadlet_t));
-
-	if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
-		/* The current irm node does not have a valid BROADCAST_CHANNEL
-		 * register and we do, so reset the bus with force_root set */
-		HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
-
-		if (cycles >= 5) {
-			/* Oh screw it! Just leave the bus as it is */
-			HPSB_DEBUG("Stopping reset loop for IRM sanity");
-			return 1;
-		}
-
-		hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1);
-		hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
-
-		return 0;
-	}
-
-	return 1;
-}
-
-static int nodemgr_host_thread(void *data)
-{
-	struct hpsb_host *host = data;
-	unsigned int g, generation = 0;
-	int i, reset_cycles = 0;
-
-	set_freezable();
-	/* Setup our device-model entries */
-	nodemgr_create_host_dev_files(host);
-
-	for (;;) {
-		/* Sleep until next bus reset */
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (get_hpsb_generation(host) == generation &&
-		    !kthread_should_stop())
-			schedule();
-		__set_current_state(TASK_RUNNING);
-
-		/* Thread may have been woken up to freeze or to exit */
-		if (try_to_freeze())
-			continue;
-		if (kthread_should_stop())
-			goto exit;
-
-		/* Pause for 1/4 second in 1/16 second intervals,
-		 * to make sure things settle down. */
-		g = get_hpsb_generation(host);
-		for (i = 0; i < 4 ; i++) {
-			msleep_interruptible(63);
-			try_to_freeze();
-			if (kthread_should_stop())
-				goto exit;
-
-			/* Now get the generation in which the node ID's we collect
-			 * are valid.  During the bus scan we will use this generation
-			 * for the read transactions, so that if another reset occurs
-			 * during the scan the transactions will fail instead of
-			 * returning bogus data. */
-			generation = get_hpsb_generation(host);
-
-			/* If we get a reset before we are done waiting, then
-			 * start the waiting over again */
-			if (generation != g)
-				g = generation, i = 0;
-		}
-
-		if (!nodemgr_check_irm_capability(host, reset_cycles) ||
-		    !nodemgr_do_irm_duties(host, reset_cycles)) {
-			reset_cycles++;
-			continue;
-		}
-		reset_cycles = 0;
-
-		/* Scan our nodes to get the bus options and create node
-		 * entries. This does not do the sysfs stuff, since that
-		 * would trigger uevents and such, which is a bad idea at
-		 * this point. */
-		nodemgr_node_scan(host, generation);
-
-		/* This actually does the full probe, with sysfs
-		 * registration. */
-		if (!nodemgr_node_probe(host, generation))
-			continue;
-
-		/* Update some of our sysfs symlinks */
-		nodemgr_update_host_dev_links(host);
-
-		/* Sleep 3 seconds */
-		for (i = 3000/200; i; i--) {
-			msleep_interruptible(200);
-			try_to_freeze();
-			if (kthread_should_stop())
-				goto exit;
-
-			if (generation != get_hpsb_generation(host))
-				break;
-		}
-		/* Remove nodes which are gone, unless a bus reset happened */
-		if (!i)
-			nodemgr_remove_nodes_in_limbo(host);
-	}
-exit:
-	HPSB_VERBOSE("NodeMgr: Exiting thread");
-	return 0;
-}
-
-struct per_host_parameter {
-	void *data;
-	int (*cb)(struct hpsb_host *, void *);
-};
-
-static int per_host(struct device *dev, void *data)
-{
-	struct hpsb_host *host;
-	struct per_host_parameter *p = data;
-
-	host = container_of(dev, struct hpsb_host, host_dev);
-	return p->cb(host, p->data);
-}
-
-/**
- * nodemgr_for_each_host - call a function for each IEEE 1394 host
- * @data: an address to supply to the callback
- * @cb: function to call for each host
- *
- * Iterate the hosts, calling a given function with supplied data for each host.
- * If the callback fails on a host, i.e. if it returns a non-zero value, the
- * iteration is stopped.
- *
- * Return value: 0 on success, non-zero on failure (same as returned by last run
- * of the callback).
- */
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
-{
-	struct per_host_parameter p;
-
-	p.cb = cb;
-	p.data = data;
-	return class_for_each_device(&hpsb_host_class, NULL, &p, per_host);
-}
-
-/* The following two convenience functions use a struct node_entry
- * for addressing a node on the bus.  They are intended for use by any
- * process context, not just the nodemgr thread, so we need to be a
- * little careful when reading out the node ID and generation.  The
- * thing that can go wrong is that we get the node ID, then a bus
- * reset occurs, and then we read the generation.  The node ID is
- * possibly invalid, but the generation is current, and we end up
- * sending a packet to a the wrong node.
- *
- * The solution is to make sure we read the generation first, so that
- * if a reset occurs in the process, we end up with a stale generation
- * and the transactions will fail instead of silently using wrong node
- * ID's.
- */
-
-/**
- * hpsb_node_fill_packet - fill some destination information into a packet
- * @ne: destination node
- * @packet: packet to fill in
- *
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the node entry (host, node ID, bus generation number).
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
-{
-	packet->host = ne->host;
-	packet->generation = ne->generation;
-	smp_rmb();
-	packet->node_id = ne->nodeid;
-}
-
-int hpsb_node_write(struct node_entry *ne, u64 addr,
-		    quadlet_t *buffer, size_t length)
-{
-	unsigned int generation = ne->generation;
-
-	smp_rmb();
-	return hpsb_write(ne->host, ne->nodeid, generation,
-			  addr, buffer, length);
-}
-
-static void nodemgr_add_host(struct hpsb_host *host)
-{
-	struct host_info *hi;
-
-	hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
-	if (!hi) {
-		HPSB_ERR("NodeMgr: out of memory in add host");
-		return;
-	}
-	hi->host = host;
-	hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d",
-				 host->id);
-	if (IS_ERR(hi->thread)) {
-		HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
-		hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
-	}
-}
-
-static void nodemgr_host_reset(struct hpsb_host *host)
-{
-	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
-	if (hi) {
-		HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
-		wake_up_process(hi->thread);
-	}
-}
-
-static void nodemgr_remove_host(struct hpsb_host *host)
-{
-	struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
-
-	if (hi) {
-		kthread_stop(hi->thread);
-		nodemgr_remove_host_dev(&host->device);
-	}
-}
-
-static struct hpsb_highlevel nodemgr_highlevel = {
-	.name =		"Node manager",
-	.add_host =	nodemgr_add_host,
-	.host_reset =	nodemgr_host_reset,
-	.remove_host =	nodemgr_remove_host,
-};
-
-int init_ieee1394_nodemgr(void)
-{
-	int error;
-
-	error = class_register(&nodemgr_ne_class);
-	if (error)
-		goto fail_ne;
-	error = class_register(&nodemgr_ud_class);
-	if (error)
-		goto fail_ud;
-	error = driver_register(&nodemgr_mid_layer_driver);
-	if (error)
-		goto fail_ml;
-	/* This driver is not used if nodemgr is off (disable_nodemgr=1). */
-	nodemgr_dev_template_host.driver = &nodemgr_mid_layer_driver;
-
-	hpsb_register_highlevel(&nodemgr_highlevel);
-	return 0;
-
-fail_ml:
-	class_unregister(&nodemgr_ud_class);
-fail_ud:
-	class_unregister(&nodemgr_ne_class);
-fail_ne:
-	return error;
-}
-
-void cleanup_ieee1394_nodemgr(void)
-{
-	hpsb_unregister_highlevel(&nodemgr_highlevel);
-	driver_unregister(&nodemgr_mid_layer_driver);
-	class_unregister(&nodemgr_ud_class);
-	class_unregister(&nodemgr_ne_class);
-}
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/nodemgr.h linux-libre-2.6.37-gnu/drivers/ieee1394/nodemgr.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/nodemgr.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/nodemgr.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2000	Andreas E. Bombe
- *               2001	Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _IEEE1394_NODEMGR_H
-#define _IEEE1394_NODEMGR_H
-
-#include <linux/device.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#include "ieee1394_core.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-
-struct csr1212_csr;
-struct csr1212_keyval;
-struct hpsb_host;
-struct ieee1394_device_id;
-
-/* This is the start of a Node entry structure. It should be a stable API
- * for which to gather info from the Node Manager about devices attached
- * to the bus.  */
-struct bus_options {
-	u8	irmc;		/* Iso Resource Manager Capable */
-	u8	cmc;		/* Cycle Master Capable */
-	u8	isc;		/* Iso Capable */
-	u8	bmc;		/* Bus Master Capable */
-	u8	pmc;		/* Power Manager Capable (PNP spec) */
-	u8	cyc_clk_acc;	/* Cycle clock accuracy */
-	u8	max_rom;	/* Maximum block read supported in the CSR */
-	u8	generation;	/* Incremented when configrom changes */
-	u8	lnkspd;		/* Link speed */
-	u16	max_rec;	/* Maximum packet size node can receive */
-};
-
-#define UNIT_DIRECTORY_VENDOR_ID		0x01
-#define UNIT_DIRECTORY_MODEL_ID			0x02
-#define UNIT_DIRECTORY_SPECIFIER_ID		0x04
-#define UNIT_DIRECTORY_VERSION			0x08
-#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY	0x10
-#define UNIT_DIRECTORY_LUN_DIRECTORY		0x20
-#define UNIT_DIRECTORY_HAS_LUN			0x40
-
-/*
- * A unit directory corresponds to a protocol supported by the
- * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
- * unit directory for each of these protocols.
- */
-struct unit_directory {
-	struct node_entry *ne;	/* The node which this directory belongs to */
-	octlet_t address;	/* Address of the unit directory on the node */
-	u8 flags;		/* Indicates which entries were read */
-
-	quadlet_t vendor_id;
-	struct csr1212_keyval *vendor_name_kv;
-
-	quadlet_t model_id;
-	struct csr1212_keyval *model_name_kv;
-	quadlet_t specifier_id;
-	quadlet_t version;
-	quadlet_t directory_id;
-
-	unsigned int id;
-
-	int ignore_driver;
-
-	int length;		/* Number of quadlets */
-
-	struct device device;
-	struct device unit_dev;
-
-	struct csr1212_keyval *ud_kv;
-	u32 lun;		/* logical unit number immediate value */
-};
-
-struct node_entry {
-	u64 guid;			/* GUID of this node */
-	u32 guid_vendor_id;		/* Top 24bits of guid */
-
-	struct hpsb_host *host;		/* Host this node is attached to */
-	nodeid_t nodeid;		/* NodeID */
-	struct bus_options busopt;	/* Bus Options */
-	bool needs_probe;
-	unsigned int generation;	/* Synced with hpsb generation */
-
-	/* The following is read from the config rom */
-	u32 vendor_id;
-	struct csr1212_keyval *vendor_name_kv;
-
-	u32 capabilities;
-
-	struct device device;
-	struct device node_dev;
-
-	/* Means this node is not attached anymore */
-	bool in_limbo;
-
-	struct csr1212_csr *csr;
-};
-
-struct hpsb_protocol_driver {
-	/* The name of the driver, e.g. SBP2 or IP1394 */
-	const char *name;
-
-	/*
-	 * The device id table describing the protocols and/or devices
-	 * supported by this driver.  This is used by the nodemgr to
-	 * decide if a driver could support a given node, but the
-	 * probe function below can implement further protocol
-	 * dependent or vendor dependent checking.
-	 */
-	const struct ieee1394_device_id *id_table;
-
-	/*
-	 * The update function is called when the node has just
-	 * survived a bus reset, i.e. it is still present on the bus.
-	 * However, it may be necessary to reestablish the connection
-	 * or login into the node again, depending on the protocol. If the
-	 * probe fails (returns non-zero), we unbind the driver from this
-	 * device.
-	 */
-	int (*update)(struct unit_directory *ud);
-
-	/* Our LDM structure */
-	struct device_driver driver;
-};
-
-int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
-static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
-{
-	return __hpsb_register_protocol(driver, THIS_MODULE);
-}
-
-void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
-
-static inline int hpsb_node_entry_valid(struct node_entry *ne)
-{
-	return ne->generation == get_hpsb_generation(ne->host);
-}
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
-int hpsb_node_write(struct node_entry *ne, u64 addr,
-		    quadlet_t *buffer, size_t length);
-static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
-				 quadlet_t *buffer, size_t length)
-{
-	unsigned int g = ne->generation;
-
-	smp_rmb();
-	return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
-}
-static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
-				 quadlet_t *buffer, quadlet_t arg)
-{
-	unsigned int g = ne->generation;
-
-	smp_rmb();
-	return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
-}
-int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
-
-int init_ieee1394_nodemgr(void);
-void cleanup_ieee1394_nodemgr(void);
-
-/* The template for a host device */
-extern struct device nodemgr_dev_template_host;
-
-/* Bus attributes we export */
-extern struct bus_attribute *const fw_bus_attrs[];
-
-#endif /* _IEEE1394_NODEMGR_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ohci1394.c linux-libre-2.6.37-gnu/drivers/ieee1394/ohci1394.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ohci1394.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ohci1394.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,3590 +0,0 @@
-/*
- * ohci1394.c - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Gord Peters <GordPeters@smarttech.com>
- *              2001      Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Things known to be working:
- * . Async Request Transmit
- * . Async Response Receive
- * . Async Request Receive
- * . Async Response Transmit
- * . Iso Receive
- * . DMA mmap for iso receive
- * . Config ROM generation
- *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * . Async Stream Packets Transmit (Receive done via Iso interface)
- *
- * Things not implemented:
- * . DMA error recovery
- *
- * Known bugs:
- * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
- *   added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk
- */
-
-/*
- * Acknowledgments:
- *
- * Adam J Richter <adam@yggdrasil.com>
- *  . Use of pci_class to find device
- *
- * Emilie Chung	<emilie.chung@axis.com>
- *  . Tip on Async Request Filter
- *
- * Pascal Drolet <pascal.drolet@informission.ca>
- *  . Various tips for optimization and functionnalities
- *
- * Robert Ficklin <rficklin@westengineering.com>
- *  . Loop in irq_handler
- *
- * James Goodwin <jamesg@Filanet.com>
- *  . Various tips on initialization, self-id reception, etc.
- *
- * Albrecht Dress <ad@mpifr-bonn.mpg.de>
- *  . Apple PowerBook detection
- *
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- *  . Reset the board properly before leaving + misc cleanups
- *
- * Leon van Stuivenberg <leonvs@iae.nl>
- *  . Bug fixes
- *
- * Ben Collins <bcollins@debian.org>
- *  . Working big-endian support
- *  . Updated to 2.4.x module scheme (PCI aswell)
- *  . Config ROM generation
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *  . Reworked code for initiating bus resets
- *    (long, short, with or without hold-off)
- *
- * Nandu Santhi <contactnandu@users.sourceforge.net>
- *  . Added support for nVidia nForce2 onboard Firewire chipset
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/uaccess.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/irq.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#endif
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "dma.h"
-#include "iso.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "ohci1394.h"
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define OHCI1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef OHCI1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
-
-/* print card specific information */
-#define PRINT(level, fmt, args...) \
-printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
-
-/* Module Parameters */
-static int phys_dma = 1;
-module_param(phys_dma, int, 0444);
-MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1).");
-
-static void dma_trm_tasklet(unsigned long data);
-static void dma_trm_reset(struct dma_trm_ctx *d);
-
-static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
-			     enum context_type type, int ctx, int num_desc,
-			     int buf_size, int split_buf_size, int context_base);
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
-
-static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
-			     enum context_type type, int ctx, int num_desc,
-			     int context_base);
-
-static void ohci1394_pci_remove(struct pci_dev *pdev);
-
-#ifndef __LITTLE_ENDIAN
-static const size_t hdr_sizes[] = {
-	3,	/* TCODE_WRITEQ */
-	4,	/* TCODE_WRITEB */
-	3,	/* TCODE_WRITE_RESPONSE */
-	0,	/* reserved */
-	3,	/* TCODE_READQ */
-	4,	/* TCODE_READB */
-	3,	/* TCODE_READQ_RESPONSE */
-	4,	/* TCODE_READB_RESPONSE */
-	1,	/* TCODE_CYCLE_START */
-	4,	/* TCODE_LOCK_REQUEST */
-	2,	/* TCODE_ISO_DATA */
-	4,	/* TCODE_LOCK_RESPONSE */
-		/* rest is reserved or link-internal */
-};
-
-static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
-{
-	size_t size;
-
-	if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
-		return;
-
-	size = hdr_sizes[tcode];
-	while (size--)
-		data[size] = le32_to_cpu(data[size]);
-}
-#else
-#define header_le32_to_cpu(w,x) do {} while (0)
-#endif /* !LITTLE_ENDIAN */
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr)
-{
-	int i;
-	unsigned long flags;
-	quadlet_t r;
-
-	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
-	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
-			break;
-
-		mdelay(1);
-	}
-
-	r = reg_read(ohci, OHCI1394_PhyControl);
-
-	if (i >= OHCI_LOOP_COUNT)
-		PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",
-		       r, r & 0x80000000, i);
-
-	spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
-	return (r & 0x00ff0000) >> 16;
-}
-
-static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-	int i;
-	unsigned long flags;
-	u32 r = 0;
-
-	spin_lock_irqsave (&ohci->phy_reg_lock, flags);
-
-	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		r = reg_read(ohci, OHCI1394_PhyControl);
-		if (!(r & 0x00004000))
-			break;
-
-		mdelay(1);
-	}
-
-	if (i == OHCI_LOOP_COUNT)
-		PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",
-		       r, r & 0x00004000, i);
-
-	spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
-
-	return;
-}
-
-/* Or's our value into the current value */
-static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
-{
-	u8 old;
-
-	old = get_phy_reg (ohci, addr);
-	old |= data;
-	set_phy_reg (ohci, addr, old);
-
-	return;
-}
-
-static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
-				int phyid, int isroot)
-{
-	quadlet_t *q = ohci->selfid_buf_cpu;
-	quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
-	size_t size;
-	quadlet_t q0, q1;
-
-	/* Check status of self-id reception */
-
-	if (ohci->selfid_swap)
-		q0 = le32_to_cpu(q[0]);
-	else
-		q0 = q[0];
-
-	if ((self_id_count & 0x80000000) ||
-	    ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
-		PRINT(KERN_ERR,
-		      "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
-		      self_id_count, q0, ohci->self_id_errors);
-
-		/* Tip by James Goodwin <jamesg@Filanet.com>:
-		 * We had an error, generate another bus reset in response.  */
-		if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
-			set_phy_reg_mask (ohci, 1, 0x40);
-			ohci->self_id_errors++;
-		} else {
-			PRINT(KERN_ERR,
-			      "Too many errors on SelfID error reception, giving up!");
-		}
-		return;
-	}
-
-	/* SelfID Ok, reset error counter. */
-	ohci->self_id_errors = 0;
-
-	size = ((self_id_count & 0x00001FFC) >> 2) - 1;
-	q++;
-
-	while (size > 0) {
-		if (ohci->selfid_swap) {
-			q0 = le32_to_cpu(q[0]);
-			q1 = le32_to_cpu(q[1]);
-		} else {
-			q0 = q[0];
-			q1 = q[1];
-		}
-
-		if (q0 == ~q1) {
-			DBGMSG ("SelfID packet 0x%x received", q0);
-			hpsb_selfid_received(host, cpu_to_be32(q0));
-			if (((q0 & 0x3f000000) >> 24) == phyid)
-				DBGMSG ("SelfID for this node is 0x%08x", q0);
-		} else {
-			PRINT(KERN_ERR,
-			      "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
-		}
-		q += 2;
-		size -= 2;
-	}
-
-	DBGMSG("SelfID complete");
-
-	return;
-}
-
-static void ohci_soft_reset(struct ti_ohci *ohci) {
-	int i;
-
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
-			break;
-		mdelay(1);
-	}
-	DBGMSG ("Soft reset finished");
-}
-
-
-/* Generate the dma receive prgs and start the context */
-static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
-{
-	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-	int i;
-
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-	for (i=0; i<d->num_desc; i++) {
-		u32 c;
-
-		c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
-		if (generate_irq)
-			c |= DMA_CTL_IRQ;
-
-		d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
-
-		/* End of descriptor list? */
-		if (i + 1 < d->num_desc) {
-			d->prg_cpu[i]->branchAddress =
-				cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
-		} else {
-			d->prg_cpu[i]->branchAddress =
-				cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
-		}
-
-		d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
-		d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
-	}
-
-        d->buf_ind = 0;
-        d->buf_offset = 0;
-
-	if (d->type == DMA_CTX_ISO) {
-		/* Clear contextControl */
-		reg_write(ohci, d->ctrlClear, 0xffffffff);
-
-		/* Set bufferFill, isochHeader, multichannel for IR context */
-		reg_write(ohci, d->ctrlSet, 0xd0000000);
-
-		/* Set the context match register to match on all tags */
-		reg_write(ohci, d->ctxtMatch, 0xf0000000);
-
-		/* Clear the multi channel mask high and low registers */
-		reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
-
-		/* Set up isoRecvIntMask to generate interrupts */
-		reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
-	}
-
-	/* Tell the controller where the first AR program is */
-	reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
-
-	/* Run context */
-	reg_write(ohci, d->ctrlSet, 0x00008000);
-
-	DBGMSG("Receive DMA ctx=%d initialized", d->ctx);
-}
-
-/* Initialize the dma transmit context */
-static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
-{
-	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-
-	/* Stop the context */
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-        d->prg_ind = 0;
-	d->sent_ind = 0;
-	d->free_prgs = d->num_desc;
-        d->branchAddrPtr = NULL;
-	INIT_LIST_HEAD(&d->fifo_list);
-	INIT_LIST_HEAD(&d->pending_list);
-
-	if (d->type == DMA_CTX_ISO) {
-		/* enable interrupts */
-		reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
-	}
-
-	DBGMSG("Transmit DMA ctx=%d initialized", d->ctx);
-}
-
-/* Count the number of available iso contexts */
-static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
-{
-	u32 tmp;
-
-	reg_write(ohci, reg, 0xffffffff);
-	tmp = reg_read(ohci, reg);
-
-	DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
-
-	/* Count the number of contexts */
-	return hweight32(tmp);
-}
-
-/* Global initialization */
-static void ohci_initialize(struct ti_ohci *ohci)
-{
-	quadlet_t buf;
-	int num_ports, i;
-
-	spin_lock_init(&ohci->phy_reg_lock);
-
-	/* Put some defaults to these undefined bus options */
-	buf = reg_read(ohci, OHCI1394_BusOptions);
-	buf |=  0x60000000; /* Enable CMC and ISC */
-	if (hpsb_disable_irm)
-		buf &= ~0x80000000;
-	else
-		buf |=  0x80000000; /* Enable IRMC */
-	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
-	buf &= ~0x18000000; /* Disable PMC and BMC */
-	reg_write(ohci, OHCI1394_BusOptions, buf);
-
-	/* Set the bus number */
-	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
-
-	/* Enable posted writes */
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
-
-	/* Clear link control register */
-	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-	/* Enable cycle timer and cycle master and set the IRM
-	 * contender bit in our self ID packets if appropriate. */
-	reg_write(ohci, OHCI1394_LinkControlSet,
-		  OHCI1394_LinkControl_CycleTimerEnable |
-		  OHCI1394_LinkControl_CycleMaster);
-	i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
-	if (hpsb_disable_irm)
-		i &= ~PHY_04_CONTENDER;
-	else
-		i |= PHY_04_CONTENDER;
-	set_phy_reg(ohci, 4, i);
-
-	/* Set up self-id dma buffer */
-	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
-
-	/* enable self-id */
-	reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
-
-	/* Set the Config ROM mapping register */
-	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
-
-	/* Now get our max packet size */
-	ohci->max_packet_size =
-		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-		
-	/* Clear the interrupt mask */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
-	/* Clear the interrupt mask */
-	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-
-	/* Initialize AR dma */
-	initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
-	initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
-
-	/* Initialize AT dma */
-	initialize_dma_trm_ctx(&ohci->at_req_context);
-	initialize_dma_trm_ctx(&ohci->at_resp_context);
-	
-	/* Accept AR requests from all nodes */
-	reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
-
-	/* Set the address range of the physical response unit.
-	 * Most controllers do not implement it as a writable register though.
-	 * They will keep a hardwired offset of 0x00010000 and show 0x0 as
-	 * register content.
-	 * To actually enable physical responses is the job of our interrupt
-	 * handler which programs the physical request filter. */
-	reg_write(ohci, OHCI1394_PhyUpperBound,
-		  OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED >> 16);
-
-	DBGMSG("physUpperBoundOffset=%08x",
-	       reg_read(ohci, OHCI1394_PhyUpperBound));
-
-	/* Specify AT retries */
-	reg_write(ohci, OHCI1394_ATRetries,
-		  OHCI1394_MAX_AT_REQ_RETRIES |
-		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
-		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
-
-	/* We don't want hardware swapping */
-	reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
-
-	/* Enable interrupts */
-	reg_write(ohci, OHCI1394_IntMaskSet,
-		  OHCI1394_unrecoverableError |
-		  OHCI1394_masterIntEnable |
-		  OHCI1394_busReset |
-		  OHCI1394_selfIDComplete |
-		  OHCI1394_RSPkt |
-		  OHCI1394_RQPkt |
-		  OHCI1394_respTxComplete |
-		  OHCI1394_reqTxComplete |
-		  OHCI1394_isochRx |
-		  OHCI1394_isochTx |
-		  OHCI1394_postedWriteErr |
-		  OHCI1394_cycleTooLong |
-		  OHCI1394_cycleInconsistent);
-
-	/* Enable link */
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
-
-	buf = reg_read(ohci, OHCI1394_Version);
-	PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
-	      "MMIO=[%llx-%llx]  Max Packet=[%d]  IR/IT contexts=[%d/%d]",
-	      ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
-	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
-	      (unsigned long long)pci_resource_start(ohci->dev, 0),
-	      (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
-	      ohci->max_packet_size,
-	      ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
-
-	/* Check all of our ports to make sure that if anything is
-	 * connected, we enable that port. */
-	num_ports = get_phy_reg(ohci, 2) & 0xf;
-	for (i = 0; i < num_ports; i++) {
-		unsigned int status;
-
-		set_phy_reg(ohci, 7, i);
-		status = get_phy_reg(ohci, 8);
-
-		if (status & 0x20)
-			set_phy_reg(ohci, 8, status & ~1);
-	}
-
-        /* Serial EEPROM Sanity check. */
-        if ((ohci->max_packet_size < 512) ||
-	    (ohci->max_packet_size > 4096)) {
-		/* Serial EEPROM contents are suspect, set a sane max packet
-		 * size and print the raw contents for bug reports if verbose
-		 * debug is enabled. */
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-		int i;
-#endif
-
-		PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
-                      "attempting to set max_packet_size to 512 bytes");
-		reg_write(ohci, OHCI1394_BusOptions,
-			  (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
-		ohci->max_packet_size = 512;
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-		PRINT(KERN_DEBUG, "    EEPROM Present: %d",
-		      (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
-		reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
-
-		for (i = 0;
-		     ((i < 1000) &&
-		      (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
-			udelay(10);
-
-		for (i = 0; i < 0x20; i++) {
-			reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
-			PRINT(KERN_DEBUG, "    EEPROM %02x: %02x", i,
-			      (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
-		}
-#endif
-	}
-}
-
-/*
- * Insert a packet in the DMA fifo and generate the DMA prg
- * FIXME: rewrite the program in order to accept packets crossing
- *        page boundaries.
- *        check also that a single dma descriptor doesn't cross a
- *        page boundary.
- */
-static void insert_packet(struct ti_ohci *ohci,
-			  struct dma_trm_ctx *d, struct hpsb_packet *packet)
-{
-	u32 cycleTimer;
-	int idx = d->prg_ind;
-
-	DBGMSG("Inserting packet for node " NODE_BUS_FMT
-	       ", tlabel=%d, tcode=0x%x, speed=%d",
-	       NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
-	       packet->tcode, packet->speed_code);
-
-	d->prg_cpu[idx]->begin.address = 0;
-	d->prg_cpu[idx]->begin.branchAddress = 0;
-
-	if (d->type == DMA_CTX_ASYNC_RESP) {
-		/*
-		 * For response packets, we need to put a timeout value in
-		 * the 16 lower bits of the status... let's try 1 sec timeout
-		 */
-		cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-		d->prg_cpu[idx]->begin.status = cpu_to_le32(
-			(((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
-			((cycleTimer&0x01fff000)>>12));
-
-		DBGMSG("cycleTimer: %08x timeStamp: %08x",
-		       cycleTimer, d->prg_cpu[idx]->begin.status);
-	} else 
-		d->prg_cpu[idx]->begin.status = 0;
-
-        if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
-
-                if (packet->type == hpsb_raw) {
-			d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
-                        d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
-                        d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
-                } else {
-                        d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
-                                (packet->header[0] & 0xFFFF);
-
-			if (packet->tcode == TCODE_ISO_DATA) {
-				/* Sending an async stream packet */
-				d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-			} else {
-				/* Sending a normal async request or response */
-				d->prg_cpu[idx]->data[1] =
-					(packet->header[1] & 0xFFFF) |
-					(packet->header[0] & 0xFFFF0000);
-				d->prg_cpu[idx]->data[2] = packet->header[2];
-				d->prg_cpu[idx]->data[3] = packet->header[3];
-			}
-			header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-                }
-
-                if (packet->data_size) { /* block transmit */
-			if (packet->tcode == TCODE_STREAM_DATA){
-				d->prg_cpu[idx]->begin.control =
-					cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-						    DMA_CTL_IMMEDIATE | 0x8);
-			} else {
-				d->prg_cpu[idx]->begin.control =
-					cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-						    DMA_CTL_IMMEDIATE | 0x10);
-			}
-                        d->prg_cpu[idx]->end.control =
-                                cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-					    DMA_CTL_IRQ |
-					    DMA_CTL_BRANCH |
-					    packet->data_size);
-                        /*
-                         * Check that the packet data buffer
-                         * does not cross a page boundary.
-			 *
-			 * XXX Fix this some day. eth1394 seems to trigger
-			 * it, but ignoring it doesn't seem to cause a
-			 * problem.
-                         */
-#if 0
-                        if (cross_bound((unsigned long)packet->data,
-                                        packet->data_size)>0) {
-                                /* FIXME: do something about it */
-                                PRINT(KERN_ERR,
-                                      "%s: packet data addr: %p size %Zd bytes "
-				      "cross page boundary", __func__,
-                                      packet->data, packet->data_size);
-                        }
-#endif
-                        d->prg_cpu[idx]->end.address = cpu_to_le32(
-                                pci_map_single(ohci->dev, packet->data,
-                                               packet->data_size,
-                                               PCI_DMA_TODEVICE));
-
-                        d->prg_cpu[idx]->end.branchAddress = 0;
-                        d->prg_cpu[idx]->end.status = 0;
-                        if (d->branchAddrPtr)
-                                *(d->branchAddrPtr) =
-					cpu_to_le32(d->prg_bus[idx] | 0x3);
-                        d->branchAddrPtr =
-                                &(d->prg_cpu[idx]->end.branchAddress);
-                } else { /* quadlet transmit */
-                        if (packet->type == hpsb_raw)
-                                d->prg_cpu[idx]->begin.control =
-					cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-						    DMA_CTL_IMMEDIATE |
-						    DMA_CTL_IRQ |
-						    DMA_CTL_BRANCH |
-						    (packet->header_size + 4));
-                        else
-                                d->prg_cpu[idx]->begin.control =
-					cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-						    DMA_CTL_IMMEDIATE |
-						    DMA_CTL_IRQ |
-						    DMA_CTL_BRANCH |
-						    packet->header_size);
-
-                        if (d->branchAddrPtr)
-                                *(d->branchAddrPtr) =
-					cpu_to_le32(d->prg_bus[idx] | 0x2);
-                        d->branchAddrPtr =
-                                &(d->prg_cpu[idx]->begin.branchAddress);
-                }
-
-        } else { /* iso packet */
-                d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
-                        (packet->header[0] & 0xFFFF);
-                d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
-		header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
-
-                d->prg_cpu[idx]->begin.control =
-			cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-				    DMA_CTL_IMMEDIATE | 0x8);
-                d->prg_cpu[idx]->end.control =
-			cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-				    DMA_CTL_UPDATE |
-				    DMA_CTL_IRQ |
-				    DMA_CTL_BRANCH |
-				    packet->data_size);
-                d->prg_cpu[idx]->end.address = cpu_to_le32(
-				pci_map_single(ohci->dev, packet->data,
-				packet->data_size, PCI_DMA_TODEVICE));
-
-                d->prg_cpu[idx]->end.branchAddress = 0;
-                d->prg_cpu[idx]->end.status = 0;
-                DBGMSG("Iso xmit context info: header[%08x %08x]\n"
-                       "                       begin=%08x %08x %08x %08x\n"
-                       "                             %08x %08x %08x %08x\n"
-                       "                       end  =%08x %08x %08x %08x",
-                       d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
-                       d->prg_cpu[idx]->begin.control,
-                       d->prg_cpu[idx]->begin.address,
-                       d->prg_cpu[idx]->begin.branchAddress,
-                       d->prg_cpu[idx]->begin.status,
-                       d->prg_cpu[idx]->data[0],
-                       d->prg_cpu[idx]->data[1],
-                       d->prg_cpu[idx]->data[2],
-                       d->prg_cpu[idx]->data[3],
-                       d->prg_cpu[idx]->end.control,
-                       d->prg_cpu[idx]->end.address,
-                       d->prg_cpu[idx]->end.branchAddress,
-                       d->prg_cpu[idx]->end.status);
-                if (d->branchAddrPtr)
-  		        *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
-                d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
-        }
-	d->free_prgs--;
-
-	/* queue the packet in the appropriate context queue */
-	list_add_tail(&packet->driver_list, &d->fifo_list);
-	d->prg_ind = (d->prg_ind + 1) % d->num_desc;
-}
-
-/*
- * This function fills the FIFO with the (eventual) pending packets
- * and runs or wakes up the DMA prg if necessary.
- *
- * The function MUST be called with the d->lock held.
- */
-static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
-{
-	struct hpsb_packet *packet, *ptmp;
-	int idx = d->prg_ind;
-	int z = 0;
-
-	/* insert the packets into the dma fifo */
-	list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
-		if (!d->free_prgs)
-			break;
-
-		/* For the first packet only */
-		if (!z)
-			z = (packet->data_size) ? 3 : 2;
-
-		/* Insert the packet */
-		list_del_init(&packet->driver_list);
-		insert_packet(ohci, d, packet);
-	}
-
-	/* Nothing must have been done, either no free_prgs or no packets */
-	if (z == 0)
-		return;
-
-	/* Is the context running ? (should be unless it is
-	   the first packet to be sent in this context) */
-	if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
-		u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-
-		DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
-		reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
-
-		/* Check that the node id is valid, and not 63 */
-		if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
-			PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
-		else
-			reg_write(ohci, d->ctrlSet, 0x8000);
-	} else {
-		/* Wake up the dma context if necessary */
-		if (!(reg_read(ohci, d->ctrlSet) & 0x400))
-			DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
-
-		/* do this always, to avoid race condition */
-		reg_write(ohci, d->ctrlSet, 0x1000);
-	}
-
-	return;
-}
-
-/* Transmission of an async or iso packet */
-static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
-	struct ti_ohci *ohci = host->hostdata;
-	struct dma_trm_ctx *d;
-	unsigned long flags;
-
-	if (packet->data_size > ohci->max_packet_size) {
-		PRINT(KERN_ERR,
-		      "Transmit packet size %Zd is too big",
-		      packet->data_size);
-		return -EOVERFLOW;
-	}
-
-	if (packet->type == hpsb_raw)
-		d = &ohci->at_req_context;
-	else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
-		d = &ohci->at_resp_context;
-	else
-		d = &ohci->at_req_context;
-
-	spin_lock_irqsave(&d->lock,flags);
-
-	list_add_tail(&packet->driver_list, &d->pending_list);
-
-	dma_trm_flush(ohci, d);
-
-	spin_unlock_irqrestore(&d->lock,flags);
-
-	return 0;
-}
-
-static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
-	struct ti_ohci *ohci = host->hostdata;
-	int retval = 0, phy_reg;
-
-	switch (cmd) {
-	case RESET_BUS:
-		switch (arg) {
-		case SHORT_RESET:
-			phy_reg = get_phy_reg(ohci, 5);
-			phy_reg |= 0x40;
-			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-			break;
-		case LONG_RESET:
-			phy_reg = get_phy_reg(ohci, 1);
-			phy_reg |= 0x40;
-			set_phy_reg(ohci, 1, phy_reg); /* set IBR */
-			break;
-		case SHORT_RESET_NO_FORCE_ROOT:
-			phy_reg = get_phy_reg(ohci, 1);
-			if (phy_reg & 0x80) {
-				phy_reg &= ~0x80;
-				set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
-			}
-
-			phy_reg = get_phy_reg(ohci, 5);
-			phy_reg |= 0x40;
-			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-			break;
-		case LONG_RESET_NO_FORCE_ROOT:
-			phy_reg = get_phy_reg(ohci, 1);
-			phy_reg &= ~0x80;
-			phy_reg |= 0x40;
-			set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
-			break;
-		case SHORT_RESET_FORCE_ROOT:
-			phy_reg = get_phy_reg(ohci, 1);
-			if (!(phy_reg & 0x80)) {
-				phy_reg |= 0x80;
-				set_phy_reg(ohci, 1, phy_reg); /* set RHB */
-			}
-
-			phy_reg = get_phy_reg(ohci, 5);
-			phy_reg |= 0x40;
-			set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
-			break;
-		case LONG_RESET_FORCE_ROOT:
-			phy_reg = get_phy_reg(ohci, 1);
-			phy_reg |= 0xc0;
-			set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
-			break;
-		default:
-			retval = -1;
-		}
-		break;
-
-	case GET_CYCLE_COUNTER:
-		retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-		break;
-
-	case SET_CYCLE_COUNTER:
-		reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
-		break;
-
-	case SET_BUS_ID:
-		PRINT(KERN_ERR, "devctl command SET_BUS_ID err");
-		break;
-
-	case ACT_CYCLE_MASTER:
-		if (arg) {
-			/* check if we are root and other nodes are present */
-			u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
-			if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
-				/*
-				 * enable cycleTimer, cycleMaster
-				 */
-				DBGMSG("Cycle master enabled");
-				reg_write(ohci, OHCI1394_LinkControlSet,
-					  OHCI1394_LinkControl_CycleTimerEnable |
-					  OHCI1394_LinkControl_CycleMaster);
-			}
-		} else {
-			/* disable cycleTimer, cycleMaster, cycleSource */
-			reg_write(ohci, OHCI1394_LinkControlClear,
-				  OHCI1394_LinkControl_CycleTimerEnable |
-				  OHCI1394_LinkControl_CycleMaster |
-				  OHCI1394_LinkControl_CycleSource);
-		}
-		break;
-
-	case CANCEL_REQUESTS:
-		DBGMSG("Cancel request received");
-		dma_trm_reset(&ohci->at_req_context);
-		dma_trm_reset(&ohci->at_resp_context);
-		break;
-
-	default:
-		PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
-			cmd);
-		break;
-	}
-	return retval;
-}
-
-/***********************************
- * rawiso ISO reception            *
- ***********************************/
-
-/*
-  We use either buffer-fill or packet-per-buffer DMA mode. The DMA
-  buffer is split into "blocks" (regions described by one DMA
-  descriptor). Each block must be one page or less in size, and
-  must not cross a page boundary.
-
-  There is one little wrinkle with buffer-fill mode: a packet that
-  starts in the final block may wrap around into the first block. But
-  the user API expects all packets to be contiguous. Our solution is
-  to keep the very last page of the DMA buffer in reserve - if a
-  packet spans the gap, we copy its tail into this page.
-*/
-
-struct ohci_iso_recv {
-	struct ti_ohci *ohci;
-
-	struct ohci1394_iso_tasklet task;
-	int task_active;
-
-	enum { BUFFER_FILL_MODE = 0,
-	       PACKET_PER_BUFFER_MODE = 1 } dma_mode;
-
-	/* memory and PCI mapping for the DMA descriptors */
-	struct dma_prog_region prog;
-	struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
-
-	/* how many DMA blocks fit in the buffer */
-	unsigned int nblocks;
-
-	/* stride of DMA blocks */
-	unsigned int buf_stride;
-
-	/* number of blocks to batch between interrupts */
-	int block_irq_interval;
-
-	/* block that DMA will finish next */
-	int block_dma;
-
-	/* (buffer-fill only) block that the reader will release next */
-	int block_reader;
-
-	/* (buffer-fill only) bytes of buffer the reader has released,
-	   less than one block */
-	int released_bytes;
-
-	/* (buffer-fill only) buffer offset at which the next packet will appear */
-	int dma_offset;
-
-	/* OHCI DMA context control registers */
-	u32 ContextControlSet;
-	u32 ContextControlClear;
-	u32 CommandPtr;
-	u32 ContextMatch;
-};
-
-static void ohci_iso_recv_task(unsigned long data);
-static void ohci_iso_recv_stop(struct hpsb_iso *iso);
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
-static int  ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
-static void ohci_iso_recv_program(struct hpsb_iso *iso);
-
-static int ohci_iso_recv_init(struct hpsb_iso *iso)
-{
-	struct ti_ohci *ohci = iso->host->hostdata;
-	struct ohci_iso_recv *recv;
-	int ctx;
-	int ret = -ENOMEM;
-
-	recv = kmalloc(sizeof(*recv), GFP_KERNEL);
-	if (!recv)
-		return -ENOMEM;
-
-	iso->hostdata = recv;
-	recv->ohci = ohci;
-	recv->task_active = 0;
-	dma_prog_region_init(&recv->prog);
-	recv->block = NULL;
-
-	/* use buffer-fill mode, unless irq_interval is 1
-	   (note: multichannel requires buffer-fill) */
-
-	if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) ||
-	     iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) {
-		recv->dma_mode = PACKET_PER_BUFFER_MODE;
-	} else {
-		recv->dma_mode = BUFFER_FILL_MODE;
-	}
-
-	/* set nblocks, buf_stride, block_irq_interval */
-
-	if (recv->dma_mode == BUFFER_FILL_MODE) {
-		recv->buf_stride = PAGE_SIZE;
-
-		/* one block per page of data in the DMA buffer, minus the final guard page */
-		recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
-		if (recv->nblocks < 3) {
-			DBGMSG("ohci_iso_recv_init: DMA buffer too small");
-			goto err;
-		}
-
-		/* iso->irq_interval is in packets - translate that to blocks */
-		if (iso->irq_interval == 1)
-			recv->block_irq_interval = 1;
-		else
-			recv->block_irq_interval = iso->irq_interval *
-							((recv->nblocks+1)/iso->buf_packets);
-		if (recv->block_irq_interval*4 > recv->nblocks)
-			recv->block_irq_interval = recv->nblocks/4;
-		if (recv->block_irq_interval < 1)
-			recv->block_irq_interval = 1;
-
-	} else {
-		int max_packet_size;
-
-		recv->nblocks = iso->buf_packets;
-		recv->block_irq_interval = iso->irq_interval;
-		if (recv->block_irq_interval * 4 > iso->buf_packets)
-			recv->block_irq_interval = iso->buf_packets / 4;
-		if (recv->block_irq_interval < 1)
-			recv->block_irq_interval = 1;
-
-		/* choose a buffer stride */
-		/* must be a power of 2, and <= PAGE_SIZE */
-
-		max_packet_size = iso->buf_size / iso->buf_packets;
-
-		for (recv->buf_stride = 8; recv->buf_stride < max_packet_size;
-		    recv->buf_stride *= 2);
-
-		if (recv->buf_stride*iso->buf_packets > iso->buf_size ||
-		   recv->buf_stride > PAGE_SIZE) {
-			/* this shouldn't happen, but anyway... */
-			DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride");
-			goto err;
-		}
-	}
-
-	recv->block_reader = 0;
-	recv->released_bytes = 0;
-	recv->block_dma = 0;
-	recv->dma_offset = 0;
-
-	/* size of DMA program = one descriptor per block */
-	if (dma_prog_region_alloc(&recv->prog,
-				 sizeof(struct dma_cmd) * recv->nblocks,
-				 recv->ohci->dev))
-		goto err;
-
-	recv->block = (struct dma_cmd*) recv->prog.kvirt;
-
-	ohci1394_init_iso_tasklet(&recv->task,
-				  iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
-				                       OHCI_ISO_RECEIVE,
-				  ohci_iso_recv_task, (unsigned long) iso);
-
-	if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
-		ret = -EBUSY;
-		goto err;
-	}
-
-	recv->task_active = 1;
-
-	/* recv context registers are spaced 32 bytes apart */
-	ctx = recv->task.context;
-	recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
-	recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
-	recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
-	recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
-
-	if (iso->channel == -1) {
-		/* clear multi-channel selection mask */
-		reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
-		reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
-	}
-
-	/* write the DMA program */
-	ohci_iso_recv_program(iso);
-
-	DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
-	       " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
-	       recv->dma_mode == BUFFER_FILL_MODE ?
-	       "buffer-fill" : "packet-per-buffer",
-	       iso->buf_size/PAGE_SIZE, iso->buf_size,
-	       recv->nblocks, recv->buf_stride, recv->block_irq_interval);
-
-	return 0;
-
-err:
-	ohci_iso_recv_shutdown(iso);
-	return ret;
-}
-
-static void ohci_iso_recv_stop(struct hpsb_iso *iso)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-
-	/* disable interrupts */
-	reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
-
-	/* halt DMA */
-	ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
-}
-
-static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-
-	if (recv->task_active) {
-		ohci_iso_recv_stop(iso);
-		ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
-		recv->task_active = 0;
-	}
-
-	dma_prog_region_free(&recv->prog);
-	kfree(recv);
-	iso->hostdata = NULL;
-}
-
-/* set up a "gapped" ring buffer DMA program */
-static void ohci_iso_recv_program(struct hpsb_iso *iso)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-	int blk;
-
-	/* address of 'branch' field in previous DMA descriptor */
-	u32 *prev_branch = NULL;
-
-	for (blk = 0; blk < recv->nblocks; blk++) {
-		u32 control;
-
-		/* the DMA descriptor */
-		struct dma_cmd *cmd = &recv->block[blk];
-
-		/* offset of the DMA descriptor relative to the DMA prog buffer */
-		unsigned long prog_offset = blk * sizeof(struct dma_cmd);
-
-		/* offset of this packet's data within the DMA buffer */
-		unsigned long buf_offset = blk * recv->buf_stride;
-
-		if (recv->dma_mode == BUFFER_FILL_MODE) {
-			control = 2 << 28; /* INPUT_MORE */
-		} else {
-			control = 3 << 28; /* INPUT_LAST */
-		}
-
-		control |= 8 << 24; /* s = 1, update xferStatus and resCount */
-
-		/* interrupt on last block, and at intervals */
-		if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
-			control |= 3 << 20; /* want interrupt */
-		}
-
-		control |= 3 << 18; /* enable branch to address */
-		control |= recv->buf_stride;
-
-		cmd->control = cpu_to_le32(control);
-		cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
-		cmd->branchAddress = 0; /* filled in on next loop */
-		cmd->status = cpu_to_le32(recv->buf_stride);
-
-		/* link the previous descriptor to this one */
-		if (prev_branch) {
-			*prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
-		}
-
-		prev_branch = &cmd->branchAddress;
-	}
-
-	/* the final descriptor's branch address and Z should be left at 0 */
-}
-
-/* listen or unlisten to a specific channel (multi-channel mode only) */
-static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-	int reg, i;
-
-	if (channel < 32) {
-		reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
-		i = channel;
-	} else {
-		reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
-		i = channel - 32;
-	}
-
-	reg_write(recv->ohci, reg, (1 << i));
-
-	/* issue a dummy read to force all PCI writes to be posted immediately */
-	mb();
-	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-	int i;
-
-	for (i = 0; i < 64; i++) {
-		if (mask & (1ULL << i)) {
-			if (i < 32)
-				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
-			else
-				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
-		} else {
-			if (i < 32)
-				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
-			else
-				reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
-		}
-	}
-
-	/* issue a dummy read to force all PCI writes to be posted immediately */
-	mb();
-	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-}
-
-static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-	struct ti_ohci *ohci = recv->ohci;
-	u32 command, contextMatch;
-
-	reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
-	wmb();
-
-	/* always keep ISO headers */
-	command = (1 << 30);
-
-	if (recv->dma_mode == BUFFER_FILL_MODE)
-		command |= (1 << 31);
-
-	reg_write(recv->ohci, recv->ContextControlSet, command);
-
-	/* match on specified tags */
-	contextMatch = tag_mask << 28;
-
-	if (iso->channel == -1) {
-		/* enable multichannel reception */
-		reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
-	} else {
-		/* listen on channel */
-		contextMatch |= iso->channel;
-	}
-
-	if (cycle != -1) {
-		u32 seconds;
-
-		/* enable cycleMatch */
-		reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
-
-		/* set starting cycle */
-		cycle &= 0x1FFF;
-
-		/* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
-		   just snarf them from the current time */
-		seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
-		/* advance one second to give some extra time for DMA to start */
-		seconds += 1;
-
-		cycle |= (seconds & 3) << 13;
-
-		contextMatch |= cycle << 12;
-	}
-
-	if (sync != -1) {
-		/* set sync flag on first DMA descriptor */
-		struct dma_cmd *cmd = &recv->block[recv->block_dma];
-		cmd->control |= cpu_to_le32(DMA_CTL_WAIT);
-
-		/* match sync field */
-		contextMatch |= (sync&0xf)<<8;
-	}
-
-	reg_write(recv->ohci, recv->ContextMatch, contextMatch);
-
-	/* address of first descriptor block */
-	command = dma_prog_region_offset_to_bus(&recv->prog,
-						recv->block_dma * sizeof(struct dma_cmd));
-	command |= 1; /* Z=1 */
-
-	reg_write(recv->ohci, recv->CommandPtr, command);
-
-	/* enable interrupts */
-	reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
-
-	wmb();
-
-	/* run */
-	reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
-
-	/* issue a dummy read of the cycle timer register to force
-	   all PCI writes to be posted immediately */
-	mb();
-	reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
-
-	/* check RUN */
-	if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
-		PRINT(KERN_ERR,
-		      "Error starting IR DMA (ContextControl 0x%08x)\n",
-		      reg_read(recv->ohci, recv->ContextControlSet));
-		return -1;
-	}
-
-	return 0;
-}
-
-static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
-{
-	/* re-use the DMA descriptor for the block */
-	/* by linking the previous descriptor to it */
-
-	int next_i = block;
-	int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
-
-	struct dma_cmd *next = &recv->block[next_i];
-	struct dma_cmd *prev = &recv->block[prev_i];
-	
-	/* ignore out-of-range requests */
-	if ((block < 0) || (block > recv->nblocks))
-		return;
-
-	/* 'next' becomes the new end of the DMA chain,
-	   so disable branch and enable interrupt */
-	next->branchAddress = 0;
-	next->control |= cpu_to_le32(3 << 20);
-	next->status = cpu_to_le32(recv->buf_stride);
-
-	/* link prev to next */
-	prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
-									sizeof(struct dma_cmd) * next_i)
-					  | 1); /* Z=1 */
-
-	/* disable interrupt on previous DMA descriptor, except at intervals */
-	if ((prev_i % recv->block_irq_interval) == 0) {
-		prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
-	} else {
-		prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
-	}
-	wmb();
-
-	/* wake up DMA in case it fell asleep */
-	reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
-}
-
-static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
-					     struct hpsb_iso_packet_info *info)
-{
-	/* release the memory where the packet was */
-	recv->released_bytes += info->total_len;
-
-	/* have we released enough memory for one block? */
-	while (recv->released_bytes > recv->buf_stride) {
-		ohci_iso_recv_release_block(recv, recv->block_reader);
-		recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
-		recv->released_bytes -= recv->buf_stride;
-	}
-}
-
-static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
-	struct ohci_iso_recv *recv = iso->hostdata;
-	if (recv->dma_mode == BUFFER_FILL_MODE) {
-		ohci_iso_recv_bufferfill_release(recv, info);
-	} else {
-		ohci_iso_recv_release_block(recv, info - iso->infos);
-	}
-}
-
-/* parse all packets from blocks that have been fully received */
-static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-	int wake = 0;
-	int runaway = 0;
-	struct ti_ohci *ohci = recv->ohci;
-
-	while (1) {
-		/* we expect the next parsable packet to begin at recv->dma_offset */
-		/* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
-
-		unsigned int offset;
-		unsigned short len, cycle, total_len;
-		unsigned char channel, tag, sy;
-
-		unsigned char *p = iso->data_buf.kvirt;
-
-		unsigned int this_block = recv->dma_offset/recv->buf_stride;
-
-		/* don't loop indefinitely */
-		if (runaway++ > 100000) {
-			atomic_inc(&iso->overflows);
-			PRINT(KERN_ERR,
-			      "IR DMA error - Runaway during buffer parsing!\n");
-			break;
-		}
-
-		/* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
-		if (this_block == recv->block_dma)
-			break;
-
-		wake = 1;
-
-		/* parse data length, tag, channel, and sy */
-
-		/* note: we keep our own local copies of 'len' and 'offset'
-		   so the user can't mess with them by poking in the mmap area */
-
-		len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
-
-		if (len > 4096) {
-			PRINT(KERN_ERR,
-			      "IR DMA error - bogus 'len' value %u\n", len);
-		}
-
-		channel = p[recv->dma_offset+1] & 0x3F;
-		tag = p[recv->dma_offset+1] >> 6;
-		sy = p[recv->dma_offset+0] & 0xF;
-
-		/* advance to data payload */
-		recv->dma_offset += 4;
-
-		/* check for wrap-around */
-		if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-			recv->dma_offset -= recv->buf_stride*recv->nblocks;
-		}
-
-		/* dma_offset now points to the first byte of the data payload */
-		offset = recv->dma_offset;
-
-		/* advance to xferStatus/timeStamp */
-		recv->dma_offset += len;
-
-		total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
-		/* payload is padded to 4 bytes */
-		if (len % 4) {
-			recv->dma_offset += 4 - (len%4);
-			total_len += 4 - (len%4);
-		}
-
-		/* check for wrap-around */
-		if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-			/* uh oh, the packet data wraps from the last
-                           to the first DMA block - make the packet
-                           contiguous by copying its "tail" into the
-                           guard page */
-
-			int guard_off = recv->buf_stride*recv->nblocks;
-			int tail_len = len - (guard_off - offset);
-
-			if (tail_len > 0  && tail_len < recv->buf_stride) {
-				memcpy(iso->data_buf.kvirt + guard_off,
-				       iso->data_buf.kvirt,
-				       tail_len);
-			}
-
-			recv->dma_offset -= recv->buf_stride*recv->nblocks;
-		}
-
-		/* parse timestamp */
-		cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
-		cycle &= 0x1FFF;
-
-		/* advance to next packet */
-		recv->dma_offset += 4;
-
-		/* check for wrap-around */
-		if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
-			recv->dma_offset -= recv->buf_stride*recv->nblocks;
-		}
-
-		hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
-	}
-
-	if (wake)
-		hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-	int loop;
-	struct ti_ohci *ohci = recv->ohci;
-
-	/* loop over all blocks */
-	for (loop = 0; loop < recv->nblocks; loop++) {
-
-		/* check block_dma to see if it's done */
-		struct dma_cmd *im = &recv->block[recv->block_dma];
-
-		/* check the DMA descriptor for new writes to xferStatus */
-		u16 xferstatus = le32_to_cpu(im->status) >> 16;
-
-		/* rescount is the number of bytes *remaining to be written* in the block */
-		u16 rescount = le32_to_cpu(im->status) & 0xFFFF;
-
-		unsigned char event = xferstatus & 0x1F;
-
-		if (!event) {
-			/* nothing has happened to this block yet */
-			break;
-		}
-
-		if (event != 0x11) {
-			atomic_inc(&iso->overflows);
-			PRINT(KERN_ERR,
-			      "IR DMA error - OHCI error code 0x%02x\n", event);
-		}
-
-		if (rescount != 0) {
-			/* the card is still writing to this block;
-			   we can't touch it until it's done */
-			break;
-		}
-
-		/* OK, the block is finished... */
-
-		/* sync our view of the block */
-		dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
-
-		/* reset the DMA descriptor */
-		im->status = recv->buf_stride;
-
-		/* advance block_dma */
-		recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
-
-		if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
-			atomic_inc(&iso->overflows);
-			DBGMSG("ISO reception overflow - "
-			       "ran out of DMA blocks");
-		}
-	}
-
-	/* parse any packets that have arrived */
-	ohci_iso_recv_bufferfill_parse(iso, recv);
-}
-
-static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
-{
-	int count;
-	int wake = 0;
-	struct ti_ohci *ohci = recv->ohci;
-
-	/* loop over the entire buffer */
-	for (count = 0; count < recv->nblocks; count++) {
-		u32 packet_len = 0;
-
-		/* pointer to the DMA descriptor */
-		struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
-
-		/* check the DMA descriptor for new writes to xferStatus */
-		u16 xferstatus = le32_to_cpu(il->status) >> 16;
-		u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
-
-		unsigned char event = xferstatus & 0x1F;
-
-		if (!event) {
-			/* this packet hasn't come in yet; we are done for now */
-			goto out;
-		}
-
-		if (event == 0x11) {
-			/* packet received successfully! */
-
-			/* rescount is the number of bytes *remaining* in the packet buffer,
-			   after the packet was written */
-			packet_len = recv->buf_stride - rescount;
-
-		} else if (event == 0x02) {
-			PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n");
-		} else if (event) {
-			PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event);
-		}
-
-		/* sync our view of the buffer */
-		dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
-
-		/* record the per-packet info */
-		{
-			/* iso header is 8 bytes ahead of the data payload */
-			unsigned char *hdr;
-
-			unsigned int offset;
-			unsigned short cycle;
-			unsigned char channel, tag, sy;
-
-			offset = iso->pkt_dma * recv->buf_stride;
-			hdr = iso->data_buf.kvirt + offset;
-
-			/* skip iso header */
-			offset += 8;
-			packet_len -= 8;
-
-			cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
-			channel = hdr[5] & 0x3F;
-			tag = hdr[5] >> 6;
-			sy = hdr[4] & 0xF;
-
-			hpsb_iso_packet_received(iso, offset, packet_len,
-					recv->buf_stride, cycle, channel, tag, sy);
-		}
-
-		/* reset the DMA descriptor */
-		il->status = recv->buf_stride;
-
-		wake = 1;
-		recv->block_dma = iso->pkt_dma;
-	}
-
-out:
-	if (wake)
-		hpsb_iso_wake(iso);
-}
-
-static void ohci_iso_recv_task(unsigned long data)
-{
-	struct hpsb_iso *iso = (struct hpsb_iso*) data;
-	struct ohci_iso_recv *recv = iso->hostdata;
-
-	if (recv->dma_mode == BUFFER_FILL_MODE)
-		ohci_iso_recv_bufferfill_task(iso, recv);
-	else
-		ohci_iso_recv_packetperbuf_task(iso, recv);
-}
-
-/***********************************
- * rawiso ISO transmission         *
- ***********************************/
-
-struct ohci_iso_xmit {
-	struct ti_ohci *ohci;
-	struct dma_prog_region prog;
-	struct ohci1394_iso_tasklet task;
-	int task_active;
-	int last_cycle;
-	atomic_t skips;
-
-	u32 ContextControlSet;
-	u32 ContextControlClear;
-	u32 CommandPtr;
-};
-
-/* transmission DMA program:
-   one OUTPUT_MORE_IMMEDIATE for the IT header
-   one OUTPUT_LAST for the buffer data */
-
-struct iso_xmit_cmd {
-	struct dma_cmd output_more_immediate;
-	u8 iso_hdr[8];
-	u32 unused[2];
-	struct dma_cmd output_last;
-};
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso);
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
-static void ohci_iso_xmit_task(unsigned long data);
-
-static int ohci_iso_xmit_init(struct hpsb_iso *iso)
-{
-	struct ohci_iso_xmit *xmit;
-	unsigned int prog_size;
-	int ctx;
-	int ret = -ENOMEM;
-
-	xmit = kmalloc(sizeof(*xmit), GFP_KERNEL);
-	if (!xmit)
-		return -ENOMEM;
-
-	iso->hostdata = xmit;
-	xmit->ohci = iso->host->hostdata;
-	xmit->task_active = 0;
-	xmit->last_cycle = -1;
-	atomic_set(&iso->skips, 0);
-
-	dma_prog_region_init(&xmit->prog);
-
-	prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
-
-	if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
-		goto err;
-
-	ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
-				  ohci_iso_xmit_task, (unsigned long) iso);
-
-	if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
-		ret = -EBUSY;
-		goto err;
-	}
-
-	xmit->task_active = 1;
-
-	/* xmit context registers are spaced 16 bytes apart */
-	ctx = xmit->task.context;
-	xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
-	xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
-	xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
-
-	return 0;
-
-err:
-	ohci_iso_xmit_shutdown(iso);
-	return ret;
-}
-
-static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
-{
-	struct ohci_iso_xmit *xmit = iso->hostdata;
-	struct ti_ohci *ohci = xmit->ohci;
-
-	/* disable interrupts */
-	reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
-
-	/* halt DMA */
-	if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
-		/* XXX the DMA context will lock up if you try to send too much data! */
-		PRINT(KERN_ERR,
-		      "you probably exceeded the OHCI card's bandwidth limit - "
-		      "reload the module and reduce xmit bandwidth");
-	}
-}
-
-static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
-{
-	struct ohci_iso_xmit *xmit = iso->hostdata;
-
-	if (xmit->task_active) {
-		ohci_iso_xmit_stop(iso);
-		ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
-		xmit->task_active = 0;
-	}
-
-	dma_prog_region_free(&xmit->prog);
-	kfree(xmit);
-	iso->hostdata = NULL;
-}
-
-static void ohci_iso_xmit_task(unsigned long data)
-{
-	struct hpsb_iso *iso = (struct hpsb_iso*) data;
-	struct ohci_iso_xmit *xmit = iso->hostdata;
-	struct ti_ohci *ohci = xmit->ohci;
-	int wake = 0;
-	int count;
-
-	/* check the whole buffer if necessary, starting at pkt_dma */
-	for (count = 0; count < iso->buf_packets; count++) {
-		int cycle;
-
-		/* DMA descriptor */
-		struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
-
-		/* check for new writes to xferStatus */
-		u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
-		u8  event = xferstatus & 0x1F;
-
-		if (!event) {
-			/* packet hasn't been sent yet; we are done for now */
-			break;
-		}
-
-		if (event != 0x11)
-			PRINT(KERN_ERR,
-			      "IT DMA error - OHCI error code 0x%02x\n", event);
-
-		/* at least one packet went out, so wake up the writer */
-		wake = 1;
-
-		/* parse cycle */
-		cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
-
-		if (xmit->last_cycle > -1) {
-			int cycle_diff = cycle - xmit->last_cycle;
-			int skip;
-
-			/* unwrap */
-			if (cycle_diff < 0) {
-				cycle_diff += 8000;
-				if (cycle_diff < 0)
-					PRINT(KERN_ERR, "bogus cycle diff %d\n",
-					      cycle_diff);
-			}
-
-			skip = cycle_diff - 1;
-			if (skip > 0) {
-				DBGMSG("skipped %d cycles without packet loss", skip);
-				atomic_add(skip, &iso->skips);
-			}
-		}
-		xmit->last_cycle = cycle;
-
-		/* tell the subsystem the packet has gone out */
-		hpsb_iso_packet_sent(iso, cycle, event != 0x11);
-
-		/* reset the DMA descriptor for next time */
-		cmd->output_last.status = 0;
-	}
-
-	if (wake)
-		hpsb_iso_wake(iso);
-}
-
-static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
-{
-	struct ohci_iso_xmit *xmit = iso->hostdata;
-	struct ti_ohci *ohci = xmit->ohci;
-
-	int next_i, prev_i;
-	struct iso_xmit_cmd *next, *prev;
-
-	unsigned int offset;
-	unsigned short len;
-	unsigned char tag, sy;
-
-	/* check that the packet doesn't cross a page boundary
-	   (we could allow this if we added OUTPUT_MORE descriptor support) */
-	if (cross_bound(info->offset, info->len)) {
-		PRINT(KERN_ERR,
-		      "rawiso xmit: packet %u crosses a page boundary",
-		      iso->first_packet);
-		return -EINVAL;
-	}
-
-	offset = info->offset;
-	len = info->len;
-	tag = info->tag;
-	sy = info->sy;
-
-	/* sync up the card's view of the buffer */
-	dma_region_sync_for_device(&iso->data_buf, offset, len);
-
-	/* append first_packet to the DMA chain */
-	/* by linking the previous descriptor to it */
-	/* (next will become the new end of the DMA chain) */
-
-	next_i = iso->first_packet;
-	prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
-
-	next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
-	prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
-
-	/* set up the OUTPUT_MORE_IMMEDIATE descriptor */
-	memset(next, 0, sizeof(struct iso_xmit_cmd));
-	next->output_more_immediate.control = cpu_to_le32(0x02000008);
-
-	/* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
-
-	/* tcode = 0xA, and sy */
-	next->iso_hdr[0] = 0xA0 | (sy & 0xF);
-
-	/* tag and channel number */
-	next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
-
-	/* transmission speed */
-	next->iso_hdr[2] = iso->speed & 0x7;
-
-	/* payload size */
-	next->iso_hdr[6] = len & 0xFF;
-	next->iso_hdr[7] = len >> 8;
-
-	/* set up the OUTPUT_LAST */
-	next->output_last.control = cpu_to_le32(1 << 28);
-	next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
-	next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
-	next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
-	next->output_last.control |= cpu_to_le32(len);
-
-	/* payload bus address */
-	next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
-
-	/* leave branchAddress at zero for now */
-
-	/* re-write the previous DMA descriptor to chain to this one */
-
-	/* set prev branch address to point to next (Z=3) */
-	prev->output_last.branchAddress = cpu_to_le32(
-		dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
-
-	/*
-	 * Link the skip address to this descriptor itself. This causes a
-	 * context to skip a cycle whenever lost cycles or FIFO overruns occur,
-	 * without dropping the data at that point the application should then
-	 * decide whether this is an error condition or not. Some protocols
-	 * can deal with this by dropping some rate-matching padding packets.
-	 */
-	next->output_more_immediate.branchAddress =
-			prev->output_last.branchAddress;
-
-	/* disable interrupt, unless required by the IRQ interval */
-	if (prev_i % iso->irq_interval) {
-		prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
-	} else {
-		prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
-	}
-
-	wmb();
-
-	/* wake DMA in case it is sleeping */
-	reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
-
-	/* issue a dummy read of the cycle timer to force all PCI
-	   writes to be posted immediately */
-	mb();
-	reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
-
-	return 0;
-}
-
-static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
-{
-	struct ohci_iso_xmit *xmit = iso->hostdata;
-	struct ti_ohci *ohci = xmit->ohci;
-
-	/* clear out the control register */
-	reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
-	wmb();
-
-	/* address and length of first descriptor block (Z=3) */
-	reg_write(xmit->ohci, xmit->CommandPtr,
-		  dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
-
-	/* cycle match */
-	if (cycle != -1) {
-		u32 start = cycle & 0x1FFF;
-
-		/* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
-		   just snarf them from the current time */
-		u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
-
-		/* advance one second to give some extra time for DMA to start */
-		seconds += 1;
-
-		start |= (seconds & 3) << 13;
-
-		reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
-	}
-
-	/* enable interrupts */
-	reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
-
-	/* run */
-	reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
-	mb();
-
-	/* wait 100 usec to give the card time to go active */
-	udelay(100);
-
-	/* check the RUN bit */
-	if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
-		PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n",
-		      reg_read(xmit->ohci, xmit->ContextControlSet));
-		return -1;
-	}
-
-	return 0;
-}
-
-static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
-{
-
-	switch(cmd) {
-	case XMIT_INIT:
-		return ohci_iso_xmit_init(iso);
-	case XMIT_START:
-		return ohci_iso_xmit_start(iso, arg);
-	case XMIT_STOP:
-		ohci_iso_xmit_stop(iso);
-		return 0;
-	case XMIT_QUEUE:
-		return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
-	case XMIT_SHUTDOWN:
-		ohci_iso_xmit_shutdown(iso);
-		return 0;
-
-	case RECV_INIT:
-		return ohci_iso_recv_init(iso);
-	case RECV_START: {
-		int *args = (int*) arg;
-		return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
-	}
-	case RECV_STOP:
-		ohci_iso_recv_stop(iso);
-		return 0;
-	case RECV_RELEASE:
-		ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
-		return 0;
-	case RECV_FLUSH:
-		ohci_iso_recv_task((unsigned long) iso);
-		return 0;
-	case RECV_SHUTDOWN:
-		ohci_iso_recv_shutdown(iso);
-		return 0;
-	case RECV_LISTEN_CHANNEL:
-		ohci_iso_recv_change_channel(iso, arg, 1);
-		return 0;
-	case RECV_UNLISTEN_CHANNEL:
-		ohci_iso_recv_change_channel(iso, arg, 0);
-		return 0;
-	case RECV_SET_CHANNEL_MASK:
-		ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
-		return 0;
-
-	default:
-		PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
-			cmd);
-		break;
-	}
-	return -EINVAL;
-}
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-static void dma_trm_reset(struct dma_trm_ctx *d)
-{
-	unsigned long flags;
-	LIST_HEAD(packet_list);
-	struct ti_ohci *ohci = d->ohci;
-	struct hpsb_packet *packet, *ptmp;
-
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-	/* Lock the context, reset it and release it. Move the packets
-	 * that were pending in the context to packet_list and free
-	 * them after releasing the lock. */
-
-	spin_lock_irqsave(&d->lock, flags);
-
-	list_splice_init(&d->fifo_list, &packet_list);
-	list_splice_init(&d->pending_list, &packet_list);
-
-	d->branchAddrPtr = NULL;
-	d->sent_ind = d->prg_ind;
-	d->free_prgs = d->num_desc;
-
-	spin_unlock_irqrestore(&d->lock, flags);
-
-	if (list_empty(&packet_list))
-		return;
-
-	PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx);
-
-	/* Now process subsystem callbacks for the packets from this
-	 * context. */
-	list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) {
-		list_del_init(&packet->driver_list);
-		hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED);
-	}
-}
-
-static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
-				       quadlet_t rx_event,
-				       quadlet_t tx_event)
-{
-	struct ohci1394_iso_tasklet *t;
-	unsigned long mask;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-	list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
-		mask = 1 << t->context;
-
-		if (t->type == OHCI_ISO_TRANSMIT) {
-			if (tx_event & mask)
-				tasklet_schedule(&t->tasklet);
-		} else {
-			/* OHCI_ISO_RECEIVE or OHCI_ISO_MULTICHANNEL_RECEIVE */
-			if (rx_event & mask)
-				tasklet_schedule(&t->tasklet);
-		}
-	}
-
-	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
-{
-	quadlet_t event, node_id;
-	struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
-	struct hpsb_host *host = ohci->host;
-	int phyid = -1, isroot = 0;
-	unsigned long flags;
-
-	/* Read and clear the interrupt event register.  Don't clear
-	 * the busReset event, though. This is done when we get the
-	 * selfIDComplete interrupt. */
-	spin_lock_irqsave(&ohci->event_lock, flags);
-	event = reg_read(ohci, OHCI1394_IntEventClear);
-	reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
-	spin_unlock_irqrestore(&ohci->event_lock, flags);
-
-	if (!event)
-		return IRQ_NONE;
-
-	/* If event is ~(u32)0 cardbus card was ejected.  In this case
-	 * we just return, and clean up in the ohci1394_pci_remove
-	 * function. */
-	if (event == ~(u32) 0) {
-		DBGMSG("Device removed.");
-		return IRQ_NONE;
-	}
-
-	DBGMSG("IntEvent: %08x", event);
-
-	if (event & OHCI1394_unrecoverableError) {
-		int ctx;
-		PRINT(KERN_ERR, "Unrecoverable error!");
-
-		if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
-			PRINT(KERN_ERR, "Async Req Tx Context died: "
-				"ctrl[%08x] cmdptr[%08x]",
-				reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
-				reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
-
-		if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
-			PRINT(KERN_ERR, "Async Rsp Tx Context died: "
-				"ctrl[%08x] cmdptr[%08x]",
-				reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
-				reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
-
-		if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
-			PRINT(KERN_ERR, "Async Req Rcv Context died: "
-				"ctrl[%08x] cmdptr[%08x]",
-				reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
-				reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
-
-		if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
-			PRINT(KERN_ERR, "Async Rsp Rcv Context died: "
-				"ctrl[%08x] cmdptr[%08x]",
-				reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
-				reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
-
-		for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
-			if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
-				PRINT(KERN_ERR, "Iso Xmit %d Context died: "
-					"ctrl[%08x] cmdptr[%08x]", ctx,
-					reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
-					reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
-		}
-
-		for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
-			if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
-				PRINT(KERN_ERR, "Iso Recv %d Context died: "
-					"ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
-					reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
-					reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
-					reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
-		}
-
-		event &= ~OHCI1394_unrecoverableError;
-	}
-	if (event & OHCI1394_postedWriteErr) {
-		PRINT(KERN_ERR, "physical posted write error");
-		/* no recovery strategy yet, had to involve protocol drivers */
-		event &= ~OHCI1394_postedWriteErr;
-	}
-	if (event & OHCI1394_cycleTooLong) {
-		if(printk_ratelimit())
-			PRINT(KERN_WARNING, "isochronous cycle too long");
-		else
-			DBGMSG("OHCI1394_cycleTooLong");
-		reg_write(ohci, OHCI1394_LinkControlSet,
-			  OHCI1394_LinkControl_CycleMaster);
-		event &= ~OHCI1394_cycleTooLong;
-	}
-	if (event & OHCI1394_cycleInconsistent) {
-		/* We subscribe to the cycleInconsistent event only to
-		 * clear the corresponding event bit... otherwise,
-		 * isochronous cycleMatch DMA won't work. */
-		DBGMSG("OHCI1394_cycleInconsistent");
-		event &= ~OHCI1394_cycleInconsistent;
-	}
-	if (event & OHCI1394_busReset) {
-		/* The busReset event bit can't be cleared during the
-		 * selfID phase, so we disable busReset interrupts, to
-		 * avoid burying the cpu in interrupt requests. */
-		spin_lock_irqsave(&ohci->event_lock, flags);
-		reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-
-		if (ohci->check_busreset) {
-			int loop_count = 0;
-
-			udelay(10);
-
-			while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-				reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-
-				spin_unlock_irqrestore(&ohci->event_lock, flags);
-				udelay(10);
-				spin_lock_irqsave(&ohci->event_lock, flags);
-
-				/* The loop counter check is to prevent the driver
-				 * from remaining in this state forever. For the
-				 * initial bus reset, the loop continues for ever
-				 * and the system hangs, until some device is plugged-in
-				 * or out manually into a port! The forced reset seems
-				 * to solve this problem. This mainly effects nForce2. */
-				if (loop_count > 10000) {
-					ohci_devctl(host, RESET_BUS, LONG_RESET);
-					DBGMSG("Detected bus-reset loop. Forced a bus reset!");
-					loop_count = 0;
-				}
-
-				loop_count++;
-			}
-		}
-		spin_unlock_irqrestore(&ohci->event_lock, flags);
-		if (!host->in_bus_reset) {
-			DBGMSG("irq_handler: Bus reset requested");
-
-			/* Subsystem call */
-			hpsb_bus_reset(ohci->host);
-		}
-		event &= ~OHCI1394_busReset;
-	}
-	if (event & OHCI1394_reqTxComplete) {
-		struct dma_trm_ctx *d = &ohci->at_req_context;
-		DBGMSG("Got reqTxComplete interrupt "
-		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
-		if (reg_read(ohci, d->ctrlSet) & 0x800)
-			ohci1394_stop_context(ohci, d->ctrlClear,
-					      "reqTxComplete");
-		else
-			dma_trm_tasklet((unsigned long)d);
-			//tasklet_schedule(&d->task);
-		event &= ~OHCI1394_reqTxComplete;
-	}
-	if (event & OHCI1394_respTxComplete) {
-		struct dma_trm_ctx *d = &ohci->at_resp_context;
-		DBGMSG("Got respTxComplete interrupt "
-		       "status=0x%08X", reg_read(ohci, d->ctrlSet));
-		if (reg_read(ohci, d->ctrlSet) & 0x800)
-			ohci1394_stop_context(ohci, d->ctrlClear,
-					      "respTxComplete");
-		else
-			tasklet_schedule(&d->task);
-		event &= ~OHCI1394_respTxComplete;
-	}
-	if (event & OHCI1394_RQPkt) {
-		struct dma_rcv_ctx *d = &ohci->ar_req_context;
-		DBGMSG("Got RQPkt interrupt status=0x%08X",
-		       reg_read(ohci, d->ctrlSet));
-		if (reg_read(ohci, d->ctrlSet) & 0x800)
-			ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
-		else
-			tasklet_schedule(&d->task);
-		event &= ~OHCI1394_RQPkt;
-	}
-	if (event & OHCI1394_RSPkt) {
-		struct dma_rcv_ctx *d = &ohci->ar_resp_context;
-		DBGMSG("Got RSPkt interrupt status=0x%08X",
-		       reg_read(ohci, d->ctrlSet));
-		if (reg_read(ohci, d->ctrlSet) & 0x800)
-			ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
-		else
-			tasklet_schedule(&d->task);
-		event &= ~OHCI1394_RSPkt;
-	}
-	if (event & OHCI1394_isochRx) {
-		quadlet_t rx_event;
-
-		rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
-		reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
-		ohci_schedule_iso_tasklets(ohci, rx_event, 0);
-		event &= ~OHCI1394_isochRx;
-	}
-	if (event & OHCI1394_isochTx) {
-		quadlet_t tx_event;
-
-		tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
-		reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
-		ohci_schedule_iso_tasklets(ohci, 0, tx_event);
-		event &= ~OHCI1394_isochTx;
-	}
-	if (event & OHCI1394_selfIDComplete) {
-		if (host->in_bus_reset) {
-			node_id = reg_read(ohci, OHCI1394_NodeID);
-
-			if (!(node_id & 0x80000000)) {
-				PRINT(KERN_ERR,
-				      "SelfID received, but NodeID invalid "
-				      "(probably new bus reset occurred): %08X",
-				      node_id);
-				goto selfid_not_valid;
-			}
-
-			phyid =  node_id & 0x0000003f;
-			isroot = (node_id & 0x40000000) != 0;
-
-			DBGMSG("SelfID interrupt received "
-			      "(phyid %d, %s)", phyid,
-			      (isroot ? "root" : "not root"));
-
-			handle_selfid(ohci, host, phyid, isroot);
-
-			/* Clear the bus reset event and re-enable the
-			 * busReset interrupt.  */
-			spin_lock_irqsave(&ohci->event_lock, flags);
-			reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
-			reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
-			spin_unlock_irqrestore(&ohci->event_lock, flags);
-
-			/* Turn on phys dma reception.
-			 *
-			 * TODO: Enable some sort of filtering management.
-			 */
-			if (phys_dma) {
-				reg_write(ohci, OHCI1394_PhyReqFilterHiSet,
-					  0xffffffff);
-				reg_write(ohci, OHCI1394_PhyReqFilterLoSet,
-					  0xffffffff);
-			}
-
-			DBGMSG("PhyReqFilter=%08x%08x",
-			       reg_read(ohci, OHCI1394_PhyReqFilterHiSet),
-			       reg_read(ohci, OHCI1394_PhyReqFilterLoSet));
-
-			hpsb_selfid_complete(host, phyid, isroot);
-		} else
-			PRINT(KERN_ERR,
-			      "SelfID received outside of bus reset sequence");
-
-selfid_not_valid:
-		event &= ~OHCI1394_selfIDComplete;
-	}
-
-	/* Make sure we handle everything, just in case we accidentally
-	 * enabled an interrupt that we didn't write a handler for.  */
-	if (event)
-		PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x",
-		      event);
-
-	return IRQ_HANDLED;
-}
-
-/* Put the buffer back into the dma context */
-static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
-{
-	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-	DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
-
-	d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
-	d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
-	idx = (idx + d->num_desc - 1 ) % d->num_desc;
-	d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
-
-	/* To avoid a race, ensure 1394 interface hardware sees the inserted
-	 * context program descriptors before it sees the wakeup bit set. */
-	wmb();
-	
-	/* wake up the dma context if necessary */
-	if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-		PRINT(KERN_INFO,
-		      "Waking dma ctx=%d ... processing is probably too slow",
-		      d->ctx);
-	}
-
-	/* do this always, to avoid race condition */
-	reg_write(ohci, d->ctrlSet, 0x1000);
-}
-
-#define cond_le32_to_cpu(data, noswap) \
-	(noswap ? data : le32_to_cpu(data))
-
-static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
-			    -1, 0, -1, 0, -1, -1, 16, -1};
-
-/*
- * Determine the length of a packet in the buffer
- * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
- */
-static inline int packet_length(struct dma_rcv_ctx *d, int idx,
-				quadlet_t *buf_ptr, int offset,
-				unsigned char tcode, int noswap)
-{
-	int length = -1;
-
-	if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
-		length = TCODE_SIZE[tcode];
-		if (length == 0) {
-			if (offset + 12 >= d->buf_size) {
-				length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
-						[3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
-			} else {
-				length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
-			}
-			length += 20;
-		}
-	} else if (d->type == DMA_CTX_ISO) {
-		/* Assumption: buffer fill mode with header/trailer */
-		length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
-	}
-
-	if (length > 0 && length % 4)
-		length += 4 - (length % 4);
-
-	return length;
-}
-
-/* Tasklet that processes dma receive buffers */
-static void dma_rcv_tasklet (unsigned long data)
-{
-	struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
-	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-	unsigned int split_left, idx, offset, rescount;
-	unsigned char tcode;
-	int length, bytes_left, ack;
-	unsigned long flags;
-	quadlet_t *buf_ptr;
-	char *split_ptr;
-	char msg[256];
-
-	spin_lock_irqsave(&d->lock, flags);
-
-	idx = d->buf_ind;
-	offset = d->buf_offset;
-	buf_ptr = d->buf_cpu[idx] + offset/4;
-
-	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-	bytes_left = d->buf_size - rescount - offset;
-
-	while (bytes_left > 0) {
-		tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
-
-		/* packet_length() will return < 4 for an error */
-		length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
-
-		if (length < 4) { /* something is wrong */
-			sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
-				tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
-				d->ctx, length);
-			ohci1394_stop_context(ohci, d->ctrlClear, msg);
-			spin_unlock_irqrestore(&d->lock, flags);
-			return;
-		}
-
-		/* The first case is where we have a packet that crosses
-		 * over more than one descriptor. The next case is where
-		 * it's all in the first descriptor.  */
-		if ((offset + length) > d->buf_size) {
-			DBGMSG("Split packet rcv'd");
-			if (length > d->split_buf_size) {
-				ohci1394_stop_context(ohci, d->ctrlClear,
-					     "Split packet size exceeded");
-				d->buf_ind = idx;
-				d->buf_offset = offset;
-				spin_unlock_irqrestore(&d->lock, flags);
-				return;
-			}
-
-			if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
-			    == d->buf_size) {
-				/* Other part of packet not written yet.
-				 * this should never happen I think
-				 * anyway we'll get it on the next call.  */
-				PRINT(KERN_INFO,
-				      "Got only half a packet!");
-				d->buf_ind = idx;
-				d->buf_offset = offset;
-				spin_unlock_irqrestore(&d->lock, flags);
-				return;
-			}
-
-			split_left = length;
-			split_ptr = (char *)d->spb;
-			memcpy(split_ptr,buf_ptr,d->buf_size-offset);
-			split_left -= d->buf_size-offset;
-			split_ptr += d->buf_size-offset;
-			insert_dma_buffer(d, idx);
-			idx = (idx+1) % d->num_desc;
-			buf_ptr = d->buf_cpu[idx];
-			offset=0;
-
-			while (split_left >= d->buf_size) {
-				memcpy(split_ptr,buf_ptr,d->buf_size);
-				split_ptr += d->buf_size;
-				split_left -= d->buf_size;
-				insert_dma_buffer(d, idx);
-				idx = (idx+1) % d->num_desc;
-				buf_ptr = d->buf_cpu[idx];
-			}
-
-			if (split_left > 0) {
-				memcpy(split_ptr, buf_ptr, split_left);
-				offset = split_left;
-				buf_ptr += offset/4;
-			}
-		} else {
-			DBGMSG("Single packet rcv'd");
-			memcpy(d->spb, buf_ptr, length);
-			offset += length;
-			buf_ptr += length/4;
-			if (offset==d->buf_size) {
-				insert_dma_buffer(d, idx);
-				idx = (idx+1) % d->num_desc;
-				buf_ptr = d->buf_cpu[idx];
-				offset=0;
-			}
-		}
-
-		/* We get one phy packet to the async descriptor for each
-		 * bus reset. We always ignore it.  */
-		if (tcode != OHCI1394_TCODE_PHY) {
-			if (!ohci->no_swap_incoming)
-				header_le32_to_cpu(d->spb, tcode);
-			DBGMSG("Packet received from node"
-				" %d ack=0x%02X spd=%d tcode=0x%X"
-				" length=%d ctx=%d tlabel=%d",
-				(d->spb[1]>>16)&0x3f,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
-				(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
-				tcode, length, d->ctx,
-				(d->spb[0]>>10)&0x3f);
-
-			ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
-				== 0x11) ? 1 : 0;
-
-			hpsb_packet_received(ohci->host, d->spb,
-					     length-4, ack);
-		}
-#ifdef OHCI1394_DEBUG
-		else
-			PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded",
-			       d->ctx);
-#endif
-
-	       	rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
-
-		bytes_left = d->buf_size - rescount - offset;
-
-	}
-
-	d->buf_ind = idx;
-	d->buf_offset = offset;
-
-	spin_unlock_irqrestore(&d->lock, flags);
-}
-
-/* Bottom half that processes sent packets */
-static void dma_trm_tasklet (unsigned long data)
-{
-	struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
-	struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
-	struct hpsb_packet *packet, *ptmp;
-	unsigned long flags;
-	u32 status, ack;
-        size_t datasize;
-
-	spin_lock_irqsave(&d->lock, flags);
-
-	list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) {
-                datasize = packet->data_size;
-		if (datasize && packet->type != hpsb_raw)
-			status = le32_to_cpu(
-				d->prg_cpu[d->sent_ind]->end.status) >> 16;
-		else
-			status = le32_to_cpu(
-				d->prg_cpu[d->sent_ind]->begin.status) >> 16;
-
-		if (status == 0)
-			/* this packet hasn't been sent yet*/
-			break;
-
-#ifdef OHCI1394_DEBUG
-		if (datasize)
-			if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa)
-				DBGMSG("Stream packet sent to channel %d tcode=0x%X "
-				       "ack=0x%X spd=%d dataLength=%d ctx=%d",
-				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f,
-				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
-				       status&0x1f, (status>>5)&0x3,
-				       le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16,
-				       d->ctx);
-			else
-				DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-				       "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
-				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
-				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
-				       (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
-				       status&0x1f, (status>>5)&0x3,
-				       le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16,
-				       d->ctx);
-		else
-			DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
-			       "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
-                                        >>16)&0x3f,
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
-                                        >>4)&0xf,
-                                (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
-                                        >>10)&0x3f,
-                                status&0x1f, (status>>5)&0x3,
-                                le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
-                                d->ctx);
-#endif
-
-		if (status & 0x10) {
-			ack = status & 0xf;
-		} else {
-			switch (status & 0x1f) {
-			case EVT_NO_STATUS: /* that should never happen */
-			case EVT_RESERVED_A: /* that should never happen */
-			case EVT_LONG_PACKET: /* that should never happen */
-				PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_MISSING_ACK:
-				ack = ACKX_TIMEOUT;
-				break;
-			case EVT_UNDERRUN:
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_OVERRUN: /* that should never happen */
-				PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_DESCRIPTOR_READ:
-			case EVT_DATA_READ:
-			case EVT_DATA_WRITE:
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_BUS_RESET: /* that should never happen */
-				PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_TIMEOUT:
-				ack = ACKX_TIMEOUT;
-				break;
-			case EVT_TCODE_ERR:
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_RESERVED_B: /* that should never happen */
-			case EVT_RESERVED_C: /* that should never happen */
-				PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
-				ack = ACKX_SEND_ERROR;
-				break;
-			case EVT_UNKNOWN:
-			case EVT_FLUSHED:
-				ack = ACKX_SEND_ERROR;
-				break;
-			default:
-				PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
-				ack = ACKX_SEND_ERROR;
-				BUG();
-			}
-		}
-
-		list_del_init(&packet->driver_list);
-		hpsb_packet_sent(ohci->host, packet, ack);
-
-		if (datasize)
-			pci_unmap_single(ohci->dev,
-					 cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
-					 datasize, PCI_DMA_TODEVICE);
-
-		d->sent_ind = (d->sent_ind+1)%d->num_desc;
-		d->free_prgs++;
-	}
-
-	dma_trm_flush(ohci, d);
-
-	spin_unlock_irqrestore(&d->lock, flags);
-}
-
-static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
-{
-	int i;
-	struct ti_ohci *ohci = d->ohci;
-
-	if (ohci == NULL)
-		return;
-
-	DBGMSG("Freeing dma_rcv_ctx %d", d->ctx);
-
-	if (d->buf_cpu) {
-		for (i=0; i<d->num_desc; i++)
-			if (d->buf_cpu[i] && d->buf_bus[i])
-				pci_free_consistent(
-					ohci->dev, d->buf_size,
-					d->buf_cpu[i], d->buf_bus[i]);
-		kfree(d->buf_cpu);
-		kfree(d->buf_bus);
-	}
-	if (d->prg_cpu) {
-		for (i=0; i<d->num_desc; i++)
-			if (d->prg_cpu[i] && d->prg_bus[i])
-				pci_pool_free(d->prg_pool, d->prg_cpu[i],
-					      d->prg_bus[i]);
-		pci_pool_destroy(d->prg_pool);
-		kfree(d->prg_cpu);
-		kfree(d->prg_bus);
-	}
-	kfree(d->spb);
-
-	/* Mark this context as freed. */
-	d->ohci = NULL;
-}
-
-static int
-alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
-		  enum context_type type, int ctx, int num_desc,
-		  int buf_size, int split_buf_size, int context_base)
-{
-	int i, len;
-	static int num_allocs;
-	static char pool_name[20];
-
-	d->ohci = ohci;
-	d->type = type;
-	d->ctx = ctx;
-
-	d->num_desc = num_desc;
-	d->buf_size = buf_size;
-	d->split_buf_size = split_buf_size;
-
-	d->ctrlSet = 0;
-	d->ctrlClear = 0;
-	d->cmdPtr = 0;
-
-	d->buf_cpu = kzalloc(d->num_desc * sizeof(*d->buf_cpu), GFP_ATOMIC);
-	d->buf_bus = kzalloc(d->num_desc * sizeof(*d->buf_bus), GFP_ATOMIC);
-
-	if (d->buf_cpu == NULL || d->buf_bus == NULL) {
-		PRINT(KERN_ERR, "Failed to allocate %s", "DMA buffer");
-		free_dma_rcv_ctx(d);
-		return -ENOMEM;
-	}
-
-	d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_ATOMIC);
-	d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_ATOMIC);
-
-	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-		PRINT(KERN_ERR, "Failed to allocate %s", "DMA prg");
-		free_dma_rcv_ctx(d);
-		return -ENOMEM;
-	}
-
-	d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
-
-	if (d->spb == NULL) {
-		PRINT(KERN_ERR, "Failed to allocate %s", "split buffer");
-		free_dma_rcv_ctx(d);
-		return -ENOMEM;
-	}
-	
-	len = sprintf(pool_name, "ohci1394_rcv_prg");
-	sprintf(pool_name+len, "%d", num_allocs);
-	d->prg_pool = pci_pool_create(pool_name, ohci->dev,
-				sizeof(struct dma_cmd), 4, 0);
-	if(d->prg_pool == NULL)
-	{
-		PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
-		free_dma_rcv_ctx(d);
-		return -ENOMEM;
-	}
-	num_allocs++;
-
-	for (i=0; i<d->num_desc; i++) {
-		d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
-						     d->buf_size,
-						     d->buf_bus+i);
-
-		if (d->buf_cpu[i] != NULL) {
-			memset(d->buf_cpu[i], 0, d->buf_size);
-		} else {
-			PRINT(KERN_ERR,
-			      "Failed to allocate %s", "DMA buffer");
-			free_dma_rcv_ctx(d);
-			return -ENOMEM;
-		}
-
-		d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
-                if (d->prg_cpu[i] != NULL) {
-                        memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
-		} else {
-			PRINT(KERN_ERR,
-			      "Failed to allocate %s", "DMA prg");
-			free_dma_rcv_ctx(d);
-			return -ENOMEM;
-		}
-	}
-
-        spin_lock_init(&d->lock);
-
-	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-
-	tasklet_init(&d->task, dma_rcv_tasklet, (unsigned long) d);
-	return 0;
-}
-
-static void free_dma_trm_ctx(struct dma_trm_ctx *d)
-{
-	int i;
-	struct ti_ohci *ohci = d->ohci;
-
-	if (ohci == NULL)
-		return;
-
-	DBGMSG("Freeing dma_trm_ctx %d", d->ctx);
-
-	if (d->prg_cpu) {
-		for (i=0; i<d->num_desc; i++)
-			if (d->prg_cpu[i] && d->prg_bus[i])
-				pci_pool_free(d->prg_pool, d->prg_cpu[i],
-					      d->prg_bus[i]);
-		pci_pool_destroy(d->prg_pool);
-		kfree(d->prg_cpu);
-		kfree(d->prg_bus);
-	}
-
-	/* Mark this context as freed. */
-	d->ohci = NULL;
-}
-
-static int
-alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
-		  enum context_type type, int ctx, int num_desc,
-		  int context_base)
-{
-	int i, len;
-	static char pool_name[20];
-	static int num_allocs=0;
-
-	d->ohci = ohci;
-	d->type = type;
-	d->ctx = ctx;
-	d->num_desc = num_desc;
-	d->ctrlSet = 0;
-	d->ctrlClear = 0;
-	d->cmdPtr = 0;
-
-	d->prg_cpu = kzalloc(d->num_desc * sizeof(*d->prg_cpu), GFP_KERNEL);
-	d->prg_bus = kzalloc(d->num_desc * sizeof(*d->prg_bus), GFP_KERNEL);
-
-	if (d->prg_cpu == NULL || d->prg_bus == NULL) {
-		PRINT(KERN_ERR, "Failed to allocate %s", "AT DMA prg");
-		free_dma_trm_ctx(d);
-		return -ENOMEM;
-	}
-
-	len = sprintf(pool_name, "ohci1394_trm_prg");
-	sprintf(pool_name+len, "%d", num_allocs);
-	d->prg_pool = pci_pool_create(pool_name, ohci->dev,
-				sizeof(struct at_dma_prg), 4, 0);
-	if (d->prg_pool == NULL) {
-		PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
-		free_dma_trm_ctx(d);
-		return -ENOMEM;
-	}
-	num_allocs++;
-
-	for (i = 0; i < d->num_desc; i++) {
-		d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, GFP_KERNEL, d->prg_bus+i);
-
-                if (d->prg_cpu[i] != NULL) {
-                        memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
-		} else {
-			PRINT(KERN_ERR,
-			      "Failed to allocate %s", "AT DMA prg");
-			free_dma_trm_ctx(d);
-			return -ENOMEM;
-		}
-	}
-
-        spin_lock_init(&d->lock);
-
-	/* initialize tasklet */
-	d->ctrlSet = context_base + OHCI1394_ContextControlSet;
-	d->ctrlClear = context_base + OHCI1394_ContextControlClear;
-	d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
-	tasklet_init(&d->task, dma_trm_tasklet, (unsigned long)d);
-	return 0;
-}
-
-static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom)
-{
-	struct ti_ohci *ohci = host->hostdata;
-
-	reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
-	reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
-
-	memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
-}
-
-
-static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
-                                 quadlet_t data, quadlet_t compare)
-{
-	struct ti_ohci *ohci = host->hostdata;
-	int i;
-
-	reg_write(ohci, OHCI1394_CSRData, data);
-	reg_write(ohci, OHCI1394_CSRCompareData, compare);
-	reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
-
-	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
-			break;
-
-		mdelay(1);
-	}
-
-	return reg_read(ohci, OHCI1394_CSRData);
-}
-
-static struct hpsb_host_driver ohci1394_driver = {
-	.owner =		THIS_MODULE,
-	.name =			OHCI1394_DRIVER_NAME,
-	.set_hw_config_rom =	ohci_set_hw_config_rom,
-	.transmit_packet =	ohci_transmit,
-	.devctl =		ohci_devctl,
-	.isoctl =               ohci_isoctl,
-	.hw_csr_reg =		ohci_hw_csr_reg,
-};
-
-/***********************************
- * PCI Driver Interface functions  *
- ***********************************/
-
-#ifdef CONFIG_PPC_PMAC
-static void ohci1394_pmac_on(struct pci_dev *dev)
-{
-	if (machine_is(powermac)) {
-		struct device_node *ofn = pci_device_to_OF_node(dev);
-
-		if (ofn) {
-			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1);
-			pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1);
-		}
-	}
-}
-
-static void ohci1394_pmac_off(struct pci_dev *dev)
-{
-	if (machine_is(powermac)) {
-		struct device_node *ofn = pci_device_to_OF_node(dev);
-
-		if (ofn) {
-			pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0);
-			pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0);
-		}
-	}
-}
-#else
-#define ohci1394_pmac_on(dev)
-#define ohci1394_pmac_off(dev)
-#endif /* CONFIG_PPC_PMAC */
-
-static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
-					const struct pci_device_id *ent)
-{
-	struct hpsb_host *host;
-	struct ti_ohci *ohci;	/* shortcut to currently handled device */
-	resource_size_t ohci_base;
-	int err = -ENOMEM;
-
-	ohci1394_pmac_on(dev);
-	if (pci_enable_device(dev)) {
-		PRINT_G(KERN_ERR, "Failed to enable OHCI hardware");
-		err = -ENXIO;
-		goto err;
-	}
-        pci_set_master(dev);
-
-	host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev);
-	if (!host) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "host structure");
-		goto err;
-	}
-	ohci = host->hostdata;
-	ohci->dev = dev;
-	ohci->host = host;
-	ohci->init_state = OHCI_INIT_ALLOC_HOST;
-	host->pdev = dev;
-	pci_set_drvdata(dev, ohci);
-
-	/* We don't want hardware swapping */
-	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
-
-	/* Some oddball Apple controllers do not order the selfid
-	 * properly, so we make up for it here.  */
-#ifndef __LITTLE_ENDIAN
-	/* XXX: Need a better way to check this. I'm wondering if we can
-	 * read the values of the OHCI1394_PCI_HCI_Control and the
-	 * noByteSwapData registers to see if they were not cleared to
-	 * zero. Should this work? Obviously it's not defined what these
-	 * registers will read when they aren't supported. Bleh! */
-	if (dev->vendor == PCI_VENDOR_ID_APPLE &&
-	    dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
-		ohci->no_swap_incoming = 1;
-		ohci->selfid_swap = 0;
-	} else
-		ohci->selfid_swap = 1;
-#endif
-
-
-#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
-#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
-#endif
-
-	/* These chipsets require a bit of extra care when checking after
-	 * a busreset.  */
-	if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
-	     dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
-	    (dev->vendor ==  PCI_VENDOR_ID_NVIDIA &&
-	     dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
-		ohci->check_busreset = 1;
-
-	/* We hardwire the MMIO length, since some CardBus adaptors
-	 * fail to report the right length.  Anyway, the ohci spec
-	 * clearly says it's 2kb, so this shouldn't be a problem. */
-	ohci_base = pci_resource_start(dev, 0);
-	if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
-		PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
-		      (unsigned long long)pci_resource_len(dev, 0));
-
-	if (!request_mem_region(ohci_base, OHCI1394_REGISTER_SIZE,
-				OHCI1394_DRIVER_NAME)) {
-		PRINT_G(KERN_ERR, "MMIO resource (0x%llx - 0x%llx) unavailable",
-			(unsigned long long)ohci_base,
-			(unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
-
-	ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
-	if (ohci->registers == NULL) {
-		PRINT_G(KERN_ERR, "Failed to remap registers");
-		err = -ENXIO;
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
-	DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers);
-
-	/* csr_config rom allocation */
-	ohci->csr_config_rom_cpu =
-		pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
-				     &ohci->csr_config_rom_bus);
-	if (ohci->csr_config_rom_cpu == NULL) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "buffer config rom");
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
-
-	/* self-id dma buffer allocation */
-	ohci->selfid_buf_cpu =
-		pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
-                      &ohci->selfid_buf_bus);
-	if (ohci->selfid_buf_cpu == NULL) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "self-ID buffer");
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
-
-	if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
-		PRINT(KERN_INFO, "SelfID buffer %p is not aligned on "
-		      "8Kb boundary... may cause problems on some CXD3222 chip",
-		      ohci->selfid_buf_cpu);
-
-	/* No self-id errors at startup */
-	ohci->self_id_errors = 0;
-
-	ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
-	/* AR DMA request context allocation */
-	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
-			      DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
-			      AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
-			      OHCI1394_AsReqRcvContextBase) < 0) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Req context");
-		goto err;
-	}
-	/* AR DMA response context allocation */
-	if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
-			      DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
-			      AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
-			      OHCI1394_AsRspRcvContextBase) < 0) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "AR Resp context");
-		goto err;
-	}
-	/* AT DMA request context */
-	if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
-			      DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
-			      OHCI1394_AsReqTrContextBase) < 0) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Req context");
-		goto err;
-	}
-	/* AT DMA response context */
-	if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
-			      DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
-			      OHCI1394_AsRspTrContextBase) < 0) {
-		PRINT_G(KERN_ERR, "Failed to allocate %s", "AT Resp context");
-		goto err;
-	}
-	/* Start off with a soft reset, to clear everything to a sane
-	 * state. */
-	ohci_soft_reset(ohci);
-
-	/* Now enable LPS, which we need in order to start accessing
-	 * most of the registers.  In fact, on some cards (ALI M5251),
-	 * accessing registers in the SClk domain without LPS enabled
-	 * will lock up the machine. */
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-
-	/* Disable and clear interrupts */
-	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-
-	/* Flush MMIO writes and wait to make sure we have full link enabled. */
-	reg_read(ohci, OHCI1394_Version);
-	msleep(50);
-
-	/* Determine the number of available IR and IT contexts. */
-	ohci->nb_iso_rcv_ctx =
-		get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
-	ohci->nb_iso_xmit_ctx =
-		get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
-
-	/* Set the usage bits for non-existent contexts so they can't
-	 * be allocated */
-	ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
-	ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
-
-	INIT_LIST_HEAD(&ohci->iso_tasklet_list);
-	spin_lock_init(&ohci->iso_tasklet_list_lock);
-	ohci->ISO_channel_usage = 0;
-        spin_lock_init(&ohci->IR_channel_lock);
-
-	spin_lock_init(&ohci->event_lock);
-
-	/*
-	 * interrupts are disabled, all right, but... due to IRQF_SHARED we
-	 * might get called anyway.  We'll see no event, of course, but
-	 * we need to get to that "no event", so enough should be initialized
-	 * by that point.
-	 */
-	err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
-			  OHCI1394_DRIVER_NAME, ohci);
-	if (err) {
-		PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_HAVE_IRQ;
-	ohci_initialize(ohci);
-
-	/* Set certain csr values */
-	host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
-	host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
-	host->csr.cyc_clk_acc = 100;  /* how do we determine clk accuracy? */
-	host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
-	host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
-
-	if (phys_dma) {
-		host->low_addr_space =
-			(u64) reg_read(ohci, OHCI1394_PhyUpperBound) << 16;
-		if (!host->low_addr_space)
-			host->low_addr_space = OHCI1394_PHYS_UPPER_BOUND_FIXED;
-	}
-	host->middle_addr_space = OHCI1394_MIDDLE_ADDRESS_SPACE;
-
-	/* Tell the highlevel this host is ready */
-	if (hpsb_add_host(host)) {
-		PRINT_G(KERN_ERR, "Failed to register host with highlevel");
-		goto err;
-	}
-	ohci->init_state = OHCI_INIT_DONE;
-
-	return 0;
-err:
-	ohci1394_pci_remove(dev);
-	return err;
-}
-
-static void ohci1394_pci_remove(struct pci_dev *dev)
-{
-	struct ti_ohci *ohci;
-	struct device *device;
-
-	ohci = pci_get_drvdata(dev);
-	if (!ohci)
-		goto out;
-
-	device = get_device(&ohci->host->device);
-
-	switch (ohci->init_state) {
-	case OHCI_INIT_DONE:
-		hpsb_remove_host(ohci->host);
-
-		/* Clear out BUS Options */
-		reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
-		reg_write(ohci, OHCI1394_BusOptions,
-			  (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
-			  0x00ff0000);
-		memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
-
-	case OHCI_INIT_HAVE_IRQ:
-		/* Clear interrupt registers */
-		reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-		reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-
-		/* Disable IRM Contender */
-		set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-
-		/* Clear link control register */
-		reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-
-		/* Let all other nodes know to ignore us */
-		ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
-		/* Soft reset before we start - this disables
-		 * interrupts and clears linkEnable and LPS. */
-		ohci_soft_reset(ohci);
-		free_irq(dev->irq, ohci);
-
-	case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
-		/* The ohci_soft_reset() stops all DMA contexts, so we
-		 * dont need to do this.  */
-		free_dma_rcv_ctx(&ohci->ar_req_context);
-		free_dma_rcv_ctx(&ohci->ar_resp_context);
-		free_dma_trm_ctx(&ohci->at_req_context);
-		free_dma_trm_ctx(&ohci->at_resp_context);
-
-	case OHCI_INIT_HAVE_SELFID_BUFFER:
-		pci_free_consistent(dev, OHCI1394_SI_DMA_BUF_SIZE,
-				    ohci->selfid_buf_cpu,
-				    ohci->selfid_buf_bus);
-
-	case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
-		pci_free_consistent(dev, OHCI_CONFIG_ROM_LEN,
-				    ohci->csr_config_rom_cpu,
-				    ohci->csr_config_rom_bus);
-
-	case OHCI_INIT_HAVE_IOMAPPING:
-		iounmap(ohci->registers);
-
-	case OHCI_INIT_HAVE_MEM_REGION:
-		release_mem_region(pci_resource_start(dev, 0),
-				   OHCI1394_REGISTER_SIZE);
-
-	case OHCI_INIT_ALLOC_HOST:
-		pci_set_drvdata(dev, NULL);
-	}
-
-	if (device)
-		put_device(device);
-out:
-	ohci1394_pmac_off(dev);
-}
-
-#ifdef CONFIG_PM
-static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state)
-{
-	int err;
-	struct ti_ohci *ohci = pci_get_drvdata(dev);
-
-	if (!ohci) {
-		printk(KERN_ERR "%s: tried to suspend nonexisting host\n",
-		       OHCI1394_DRIVER_NAME);
-		return -ENXIO;
-	}
-	DBGMSG("suspend called");
-
-	/* Clear the async DMA contexts and stop using the controller */
-	hpsb_bus_reset(ohci->host);
-
-	/* See ohci1394_pci_remove() for comments on this sequence */
-	reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
-	reg_write(ohci, OHCI1394_BusOptions,
-		  (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
-		  0x00ff0000);
-	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
-	set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
-	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
-	ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-	ohci_soft_reset(ohci);
-
-	free_irq(dev->irq, ohci);
-	err = pci_save_state(dev);
-	if (err) {
-		PRINT(KERN_ERR, "pci_save_state failed with %d", err);
-		return err;
-	}
-	err = pci_set_power_state(dev, pci_choose_state(dev, state));
-	if (err)
-		DBGMSG("pci_set_power_state failed with %d", err);
-	ohci1394_pmac_off(dev);
-
-	return 0;
-}
-
-static int ohci1394_pci_resume(struct pci_dev *dev)
-{
-	int err;
-	struct ti_ohci *ohci = pci_get_drvdata(dev);
-
-	if (!ohci) {
-		printk(KERN_ERR "%s: tried to resume nonexisting host\n",
-		       OHCI1394_DRIVER_NAME);
-		return -ENXIO;
-	}
-	DBGMSG("resume called");
-
-	ohci1394_pmac_on(dev);
-	pci_set_power_state(dev, PCI_D0);
-	pci_restore_state(dev);
-	err = pci_enable_device(dev);
-	if (err) {
-		PRINT(KERN_ERR, "pci_enable_device failed with %d", err);
-		return err;
-	}
-
-	/* See ohci1394_pci_probe() for comments on this sequence */
-	ohci_soft_reset(ohci);
-	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
-	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
-	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
-	reg_read(ohci, OHCI1394_Version);
-	msleep(50);
-
-	err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
-			  OHCI1394_DRIVER_NAME, ohci);
-	if (err) {
-		PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
-		return err;
-	}
-
-	ohci_initialize(ohci);
-
-	hpsb_resume_host(ohci->host);
-	return 0;
-}
-#endif /* CONFIG_PM */
-
-static struct pci_device_id ohci1394_pci_tbl[] = {
-	{
-		.class = 	PCI_CLASS_SERIAL_FIREWIRE_OHCI,
-		.class_mask = 	PCI_ANY_ID,
-		.vendor =	PCI_ANY_ID,
-		.device =	PCI_ANY_ID,
-		.subvendor =	PCI_ANY_ID,
-		.subdevice =	PCI_ANY_ID,
-	},
-	{ 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
-
-static struct pci_driver ohci1394_pci_driver = {
-	.name =		OHCI1394_DRIVER_NAME,
-	.id_table =	ohci1394_pci_tbl,
-	.probe =	ohci1394_pci_probe,
-	.remove =	ohci1394_pci_remove,
-#ifdef CONFIG_PM
-	.resume =	ohci1394_pci_resume,
-	.suspend =	ohci1394_pci_suspend,
-#endif
-};
-
-/***********************************
- * OHCI1394 Video Interface        *
- ***********************************/
-
-/* essentially the only purpose of this code is to allow another
-   module to hook into ohci's interrupt handler */
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
-{
-	int i=0;
-
-	/* stop the channel program if it's still running */
-	reg_write(ohci, reg, 0x8000);
-
-	/* Wait until it effectively stops */
-	while (reg_read(ohci, reg) & 0x400) {
-		i++;
-		if (i>5000) {
-			PRINT(KERN_ERR,
-			      "Runaway loop while stopping context: %s...", msg ? msg : "");
-			return 1;
-		}
-
-		mb();
-		udelay(10);
-	}
-	if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg);
-	return 0;
-}
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
-			       void (*func)(unsigned long), unsigned long data)
-{
-	tasklet_init(&tasklet->tasklet, func, data);
-	tasklet->type = type;
-	/* We init the tasklet->link field, so we can list_del() it
-	 * without worrying whether it was added to the list or not. */
-	INIT_LIST_HEAD(&tasklet->link);
-}
-
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
-				  struct ohci1394_iso_tasklet *tasklet)
-{
-	unsigned long flags, *usage;
-	int n, i, r = -EBUSY;
-
-	if (tasklet->type == OHCI_ISO_TRANSMIT) {
-		n = ohci->nb_iso_xmit_ctx;
-		usage = &ohci->it_ctx_usage;
-	}
-	else {
-		n = ohci->nb_iso_rcv_ctx;
-		usage = &ohci->ir_ctx_usage;
-
-		/* only one receive context can be multichannel (OHCI sec 10.4.1) */
-		if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
-			if (test_and_set_bit(0, &ohci->ir_multichannel_used)) {
-				return r;
-			}
-		}
-	}
-
-	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-	for (i = 0; i < n; i++)
-		if (!test_and_set_bit(i, usage)) {
-			tasklet->context = i;
-			list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
-			r = 0;
-			break;
-		}
-
-	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-
-	return r;
-}
-
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
-				     struct ohci1394_iso_tasklet *tasklet)
-{
-	unsigned long flags;
-
-	tasklet_kill(&tasklet->tasklet);
-
-	spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
-
-	if (tasklet->type == OHCI_ISO_TRANSMIT)
-		clear_bit(tasklet->context, &ohci->it_ctx_usage);
-	else {
-		clear_bit(tasklet->context, &ohci->ir_ctx_usage);
-
-		if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
-			clear_bit(0, &ohci->ir_multichannel_used);
-		}
-	}
-
-	list_del(&tasklet->link);
-
-	spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
-}
-
-EXPORT_SYMBOL(ohci1394_stop_context);
-EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
-EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
-
-/***********************************
- * General module initialization   *
- ***********************************/
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
-MODULE_LICENSE("GPL");
-
-static void __exit ohci1394_cleanup (void)
-{
-	pci_unregister_driver(&ohci1394_pci_driver);
-}
-
-static int __init ohci1394_init(void)
-{
-	return pci_register_driver(&ohci1394_pci_driver);
-}
-
-module_init(ohci1394_init);
-module_exit(ohci1394_cleanup);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/ohci1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/ohci1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/ohci1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/ohci1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,453 +0,0 @@
-/*
- * ohci1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Gord Peters <GordPeters@smarttech.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _OHCI1394_H
-#define _OHCI1394_H
-
-#include "ieee1394_types.h"
-#include <asm/io.h>
-
-#define OHCI1394_DRIVER_NAME      "ohci1394"
-
-#define OHCI1394_MAX_AT_REQ_RETRIES	0xf
-#define OHCI1394_MAX_AT_RESP_RETRIES	0x2
-#define OHCI1394_MAX_PHYS_RESP_RETRIES	0x8
-#define OHCI1394_MAX_SELF_ID_ERRORS	16
-
-#define AR_REQ_NUM_DESC		4		/* number of AR req descriptors */
-#define AR_REQ_BUF_SIZE		PAGE_SIZE	/* size of AR req buffers */
-#define AR_REQ_SPLIT_BUF_SIZE	PAGE_SIZE	/* split packet buffer */
-
-#define AR_RESP_NUM_DESC	4		/* number of AR resp descriptors */
-#define AR_RESP_BUF_SIZE	PAGE_SIZE	/* size of AR resp buffers */
-#define AR_RESP_SPLIT_BUF_SIZE	PAGE_SIZE	/* split packet buffer */
-
-#define IR_NUM_DESC		16		/* number of IR descriptors */
-#define IR_BUF_SIZE		PAGE_SIZE	/* 4096 bytes/buffer */
-#define IR_SPLIT_BUF_SIZE	PAGE_SIZE	/* split packet buffer */
-
-#define IT_NUM_DESC		16	/* number of IT descriptors */
-
-#define AT_REQ_NUM_DESC		32	/* number of AT req descriptors */
-#define AT_RESP_NUM_DESC	32	/* number of AT resp descriptors */
-
-#define OHCI_LOOP_COUNT		100	/* Number of loops for reg read waits */
-
-#define OHCI_CONFIG_ROM_LEN	1024	/* Length of the mapped configrom space */
-
-#define OHCI1394_SI_DMA_BUF_SIZE	8192 /* length of the selfid buffer */
-
-/* PCI configuration space addresses */
-#define OHCI1394_PCI_HCI_Control 0x40
-
-struct dma_cmd {
-        u32 control;
-        u32 address;
-        u32 branchAddress;
-        u32 status;
-};
-
-/*
- * FIXME:
- * It is important that a single at_dma_prg does not cross a page boundary
- * The proper way to do it would be to do the check dynamically as the
- * programs are inserted into the AT fifo.
- */
-struct at_dma_prg {
-	struct dma_cmd begin;
-	quadlet_t data[4];
-	struct dma_cmd end;
-	quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-/* identify whether a DMA context is asynchronous or isochronous */
-enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
-
-/* DMA receive context */
-struct dma_rcv_ctx {
-	struct ti_ohci *ohci;
-	enum context_type type;
-	int ctx;
-	unsigned int num_desc;
-
-	unsigned int buf_size;
-	unsigned int split_buf_size;
-
-	/* dma block descriptors */
-        struct dma_cmd **prg_cpu;
-        dma_addr_t *prg_bus;
-	struct pci_pool *prg_pool;
-
-	/* dma buffers */
-        quadlet_t **buf_cpu;
-        dma_addr_t *buf_bus;
-
-        unsigned int buf_ind;
-        unsigned int buf_offset;
-        quadlet_t *spb;
-        spinlock_t lock;
-        struct tasklet_struct task;
-	int ctrlClear;
-	int ctrlSet;
-	int cmdPtr;
-	int ctxtMatch;
-};
-
-/* DMA transmit context */
-struct dma_trm_ctx {
-	struct ti_ohci *ohci;
-	enum context_type type;
-	int ctx;
-	unsigned int num_desc;
-
-	/* dma block descriptors */
-        struct at_dma_prg **prg_cpu;
-	dma_addr_t *prg_bus;
-	struct pci_pool *prg_pool;
-
-        unsigned int prg_ind;
-        unsigned int sent_ind;
-	int free_prgs;
-        quadlet_t *branchAddrPtr;
-
-	/* list of packets inserted in the AT FIFO */
-	struct list_head fifo_list;
-
-	/* list of pending packets to be inserted in the AT FIFO */
-	struct list_head pending_list;
-
-        spinlock_t lock;
-        struct tasklet_struct task;
-	int ctrlClear;
-	int ctrlSet;
-	int cmdPtr;
-};
-
-struct ohci1394_iso_tasklet {
-	struct tasklet_struct tasklet;
-	struct list_head link;
-	int context;
-	enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
-	       OHCI_ISO_MULTICHANNEL_RECEIVE } type;
-};
-
-struct ti_ohci {
-        struct pci_dev *dev;
-
-	enum {
-		OHCI_INIT_ALLOC_HOST,
-		OHCI_INIT_HAVE_MEM_REGION,
-		OHCI_INIT_HAVE_IOMAPPING,
-		OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
-		OHCI_INIT_HAVE_SELFID_BUFFER,
-		OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
-		OHCI_INIT_HAVE_IRQ,
-		OHCI_INIT_DONE,
-	} init_state;
-
-        /* remapped memory spaces */
-        void __iomem *registers;
-
-	/* dma buffer for self-id packets */
-        quadlet_t *selfid_buf_cpu;
-        dma_addr_t selfid_buf_bus;
-
-	/* buffer for csr config rom */
-        quadlet_t *csr_config_rom_cpu;
-        dma_addr_t csr_config_rom_bus;
-	int csr_config_rom_length;
-
-	unsigned int max_packet_size;
-
-        /* async receive */
-	struct dma_rcv_ctx ar_resp_context;
-	struct dma_rcv_ctx ar_req_context;
-
-	/* async transmit */
-	struct dma_trm_ctx at_resp_context;
-	struct dma_trm_ctx at_req_context;
-
-        /* iso receive */
-	int nb_iso_rcv_ctx;
-	unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
-	unsigned long ir_multichannel_used; /* ditto */
-        spinlock_t IR_channel_lock;
-
-        /* iso transmit */
-	int nb_iso_xmit_ctx;
-	unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
-
-        u64 ISO_channel_usage;
-
-        /* IEEE-1394 part follows */
-        struct hpsb_host *host;
-
-        int phyid, isroot;
-
-        spinlock_t phy_reg_lock;
-	spinlock_t event_lock;
-
-	int self_id_errors;
-
-	/* Tasklets for iso receive and transmit, used by video1394
-	 * and dv1394 */
-	struct list_head iso_tasklet_list;
-	spinlock_t iso_tasklet_list_lock;
-
-	/* Swap the selfid buffer? */
-	unsigned int selfid_swap:1;
-	/* Some Apple chipset seem to swap incoming headers for us */
-	unsigned int no_swap_incoming:1;
-
-	/* Force extra paranoia checking on bus-reset handling */
-	unsigned int check_busreset:1;
-};
-
-static inline int cross_bound(unsigned long addr, unsigned int size)
-{
-	if (size == 0)
-		return 0;
-
-	if (size > PAGE_SIZE)
-		return 1;
-
-	if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
-		return 1;
-
-	return 0;
-}
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
-{
-        writel(data, ohci->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
-{
-        return readl(ohci->registers + offset);
-}
-
-
-/* 2 KiloBytes of register space */
-#define OHCI1394_REGISTER_SIZE                0x800
-
-/* Offsets relative to context bases defined below */
-
-#define OHCI1394_ContextControlSet            0x000
-#define OHCI1394_ContextControlClear          0x004
-#define OHCI1394_ContextCommandPtr            0x00C
-
-/* register map */
-#define OHCI1394_Version                      0x000
-#define OHCI1394_GUID_ROM                     0x004
-#define OHCI1394_ATRetries                    0x008
-#define OHCI1394_CSRData                      0x00C
-#define OHCI1394_CSRCompareData               0x010
-#define OHCI1394_CSRControl                   0x014
-#define OHCI1394_ConfigROMhdr                 0x018
-#define OHCI1394_BusID                        0x01C
-#define OHCI1394_BusOptions                   0x020
-#define OHCI1394_GUIDHi                       0x024
-#define OHCI1394_GUIDLo                       0x028
-#define OHCI1394_ConfigROMmap                 0x034
-#define OHCI1394_PostedWriteAddressLo         0x038
-#define OHCI1394_PostedWriteAddressHi         0x03C
-#define OHCI1394_VendorID                     0x040
-#define OHCI1394_HCControlSet                 0x050
-#define OHCI1394_HCControlClear               0x054
-#define  OHCI1394_HCControl_noByteSwap		0x40000000
-#define  OHCI1394_HCControl_programPhyEnable	0x00800000
-#define  OHCI1394_HCControl_aPhyEnhanceEnable	0x00400000
-#define  OHCI1394_HCControl_LPS			0x00080000
-#define  OHCI1394_HCControl_postedWriteEnable	0x00040000
-#define  OHCI1394_HCControl_linkEnable		0x00020000
-#define  OHCI1394_HCControl_softReset		0x00010000
-#define OHCI1394_SelfIDBuffer                 0x064
-#define OHCI1394_SelfIDCount                  0x068
-#define OHCI1394_IRMultiChanMaskHiSet         0x070
-#define OHCI1394_IRMultiChanMaskHiClear       0x074
-#define OHCI1394_IRMultiChanMaskLoSet         0x078
-#define OHCI1394_IRMultiChanMaskLoClear       0x07C
-#define OHCI1394_IntEventSet                  0x080
-#define OHCI1394_IntEventClear                0x084
-#define OHCI1394_IntMaskSet                   0x088
-#define OHCI1394_IntMaskClear                 0x08C
-#define OHCI1394_IsoXmitIntEventSet           0x090
-#define OHCI1394_IsoXmitIntEventClear         0x094
-#define OHCI1394_IsoXmitIntMaskSet            0x098
-#define OHCI1394_IsoXmitIntMaskClear          0x09C
-#define OHCI1394_IsoRecvIntEventSet           0x0A0
-#define OHCI1394_IsoRecvIntEventClear         0x0A4
-#define OHCI1394_IsoRecvIntMaskSet            0x0A8
-#define OHCI1394_IsoRecvIntMaskClear          0x0AC
-#define OHCI1394_InitialBandwidthAvailable    0x0B0
-#define OHCI1394_InitialChannelsAvailableHi   0x0B4
-#define OHCI1394_InitialChannelsAvailableLo   0x0B8
-#define OHCI1394_FairnessControl              0x0DC
-#define OHCI1394_LinkControlSet               0x0E0
-#define OHCI1394_LinkControlClear             0x0E4
-#define  OHCI1394_LinkControl_RcvSelfID		0x00000200
-#define  OHCI1394_LinkControl_RcvPhyPkt		0x00000400
-#define  OHCI1394_LinkControl_CycleTimerEnable	0x00100000
-#define  OHCI1394_LinkControl_CycleMaster	0x00200000
-#define  OHCI1394_LinkControl_CycleSource	0x00400000
-#define OHCI1394_NodeID                       0x0E8
-#define OHCI1394_PhyControl                   0x0EC
-#define OHCI1394_IsochronousCycleTimer        0x0F0
-#define OHCI1394_AsReqFilterHiSet             0x100
-#define OHCI1394_AsReqFilterHiClear           0x104
-#define OHCI1394_AsReqFilterLoSet             0x108
-#define OHCI1394_AsReqFilterLoClear           0x10C
-#define OHCI1394_PhyReqFilterHiSet            0x110
-#define OHCI1394_PhyReqFilterHiClear          0x114
-#define OHCI1394_PhyReqFilterLoSet            0x118
-#define OHCI1394_PhyReqFilterLoClear          0x11C
-#define OHCI1394_PhyUpperBound                0x120
-
-#define OHCI1394_AsReqTrContextBase           0x180
-#define OHCI1394_AsReqTrContextControlSet     0x180
-#define OHCI1394_AsReqTrContextControlClear   0x184
-#define OHCI1394_AsReqTrCommandPtr            0x18C
-
-#define OHCI1394_AsRspTrContextBase           0x1A0
-#define OHCI1394_AsRspTrContextControlSet     0x1A0
-#define OHCI1394_AsRspTrContextControlClear   0x1A4
-#define OHCI1394_AsRspTrCommandPtr            0x1AC
-
-#define OHCI1394_AsReqRcvContextBase          0x1C0
-#define OHCI1394_AsReqRcvContextControlSet    0x1C0
-#define OHCI1394_AsReqRcvContextControlClear  0x1C4
-#define OHCI1394_AsReqRcvCommandPtr           0x1CC
-
-#define OHCI1394_AsRspRcvContextBase          0x1E0
-#define OHCI1394_AsRspRcvContextControlSet    0x1E0
-#define OHCI1394_AsRspRcvContextControlClear  0x1E4
-#define OHCI1394_AsRspRcvCommandPtr           0x1EC
-
-/* Isochronous transmit registers */
-/* Add (16 * n) for context n */
-#define OHCI1394_IsoXmitContextBase           0x200
-#define OHCI1394_IsoXmitContextControlSet     0x200
-#define OHCI1394_IsoXmitContextControlClear   0x204
-#define OHCI1394_IsoXmitCommandPtr            0x20C
-
-/* Isochronous receive registers */
-/* Add (32 * n) for context n */
-#define OHCI1394_IsoRcvContextBase            0x400
-#define OHCI1394_IsoRcvContextControlSet      0x400
-#define OHCI1394_IsoRcvContextControlClear    0x404
-#define OHCI1394_IsoRcvCommandPtr             0x40C
-#define OHCI1394_IsoRcvContextMatch           0x410
-
-/* Interrupts Mask/Events */
-
-#define OHCI1394_reqTxComplete           0x00000001
-#define OHCI1394_respTxComplete          0x00000002
-#define OHCI1394_ARRQ                    0x00000004
-#define OHCI1394_ARRS                    0x00000008
-#define OHCI1394_RQPkt                   0x00000010
-#define OHCI1394_RSPkt                   0x00000020
-#define OHCI1394_isochTx                 0x00000040
-#define OHCI1394_isochRx                 0x00000080
-#define OHCI1394_postedWriteErr          0x00000100
-#define OHCI1394_lockRespErr             0x00000200
-#define OHCI1394_selfIDComplete          0x00010000
-#define OHCI1394_busReset                0x00020000
-#define OHCI1394_phy                     0x00080000
-#define OHCI1394_cycleSynch              0x00100000
-#define OHCI1394_cycle64Seconds          0x00200000
-#define OHCI1394_cycleLost               0x00400000
-#define OHCI1394_cycleInconsistent       0x00800000
-#define OHCI1394_unrecoverableError      0x01000000
-#define OHCI1394_cycleTooLong            0x02000000
-#define OHCI1394_phyRegRcvd              0x04000000
-#define OHCI1394_masterIntEnable         0x80000000
-
-/* DMA Control flags */
-#define DMA_CTL_OUTPUT_MORE              0x00000000
-#define DMA_CTL_OUTPUT_LAST              0x10000000
-#define DMA_CTL_INPUT_MORE               0x20000000
-#define DMA_CTL_INPUT_LAST               0x30000000
-#define DMA_CTL_UPDATE                   0x08000000
-#define DMA_CTL_IMMEDIATE                0x02000000
-#define DMA_CTL_IRQ                      0x00300000
-#define DMA_CTL_BRANCH                   0x000c0000
-#define DMA_CTL_WAIT                     0x00030000
-
-/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
-#define EVT_NO_STATUS		0x0	/* No event status */
-#define EVT_RESERVED_A		0x1	/* Reserved, not used !!! */
-#define EVT_LONG_PACKET		0x2	/* The revc data was longer than the buf */
-#define EVT_MISSING_ACK		0x3	/* A subaction gap was detected before an ack
-					   arrived, or recv'd ack had a parity error */
-#define EVT_UNDERRUN		0x4	/* Underrun on corresponding FIFO, packet
-					   truncated */
-#define EVT_OVERRUN		0x5	/* A recv FIFO overflowed on reception of ISO
-					   packet */
-#define EVT_DESCRIPTOR_READ	0x6	/* An unrecoverable error occurred while host was
-					   reading a descriptor block */
-#define EVT_DATA_READ		0x7	/* An error occurred while host controller was
-					   attempting to read from host memory in the data
-					   stage of descriptor processing */
-#define EVT_DATA_WRITE		0x8	/* An error occurred while host controller was
-					   attempting to write either during the data stage
-					   of descriptor processing, or when processing a single
-					   16-bit host memory write */
-#define EVT_BUS_RESET		0x9	/* Identifies a PHY packet in the recv buffer as
-					   being a synthesized bus reset packet */
-#define EVT_TIMEOUT		0xa	/* Indicates that the asynchronous transmit response
-					   packet expired and was not transmitted, or that an
-					   IT DMA context experienced a skip processing overflow */
-#define EVT_TCODE_ERR		0xb	/* A bad tCode is associated with this packet.
-					   The packet was flushed */
-#define EVT_RESERVED_B		0xc	/* Reserved, not used !!! */
-#define EVT_RESERVED_C		0xd	/* Reserved, not used !!! */
-#define EVT_UNKNOWN		0xe	/* An error condition has occurred that cannot be
-					   represented by any other event codes defined herein. */
-#define EVT_FLUSHED		0xf	/* Send by the link side of output FIFO when asynchronous
-					   packets are being flushed due to a bus reset. */
-
-#define OHCI1394_TCODE_PHY               0xE
-
-/* Node offset map (phys DMA area, posted write area).
- * The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
- * be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
- * OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
- * constants given by the OHCI spec.
- */
-#define OHCI1394_PHYS_UPPER_BOUND_FIXED		0x000100000000ULL /* 4 GB */
-#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED	0x010000000000ULL /* 1 TB */
-#define OHCI1394_MIDDLE_ADDRESS_SPACE		0xffff00000000ULL
-
-void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
-			       int type,
-			       void (*func)(unsigned long),
-			       unsigned long data);
-int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
-				  struct ohci1394_iso_tasklet *tasklet);
-void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
-				     struct ohci1394_iso_tasklet *tasklet);
-int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
-struct ti_ohci *ohci1394_get_struct(int card_num);
-
-#endif
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/pcilynx.c linux-libre-2.6.37-gnu/drivers/ieee1394/pcilynx.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/pcilynx.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/pcilynx.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1554 +0,0 @@
-/*
- * pcilynx.c - Texas Instruments PCILynx driver
- * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>,
- *                         Stephan Linz <linz@mazet.de>
- *                         Manfred Weihs <weihs@ict.tuwien.ac.at>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        reading bus info block (containing GUID) from serial
- *            eeprom via i2c and storing it in config ROM
- *        Reworked code for initiating bus resets
- *            (long, short, with or without hold-off)
- *        Enhancements in async and iso send code
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/kdev_t.h>
-#include <linux/dma-mapping.h>
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-
-#include "csr1212.h"
-#include "ieee1394.h"
-#include "ieee1394_types.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "pcilynx.h"
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)
-#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)
-#else
-#define PRINT_GD(level, fmt, args...) do {} while (0)
-#define PRINTD(level, card, fmt, args...) do {} while (0)
-#endif
-
-
-/* Module Parameters */
-static int skip_eeprom;
-module_param(skip_eeprom, int, 0444);
-MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
-
-
-static struct hpsb_host_driver lynx_driver;
-static unsigned int card_id;
-
-
-
-/*
- * I2C stuff
- */
-
-/* the i2c stuff was inspired by i2c-philips-par.c */
-
-static void bit_setscl(void *data, int state)
-{
-	if (state) {
-		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;
-	} else {
-		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;
-	}
-	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static void bit_setsda(void *data, int state)
-{
-	if (state) {
-		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;
-	} else {
-		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;
-	}
-	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);
-}
-
-static int bit_getscl(void *data)
-{
-	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;
-}
-
-static int bit_getsda(void *data)
-{
-	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
-}
-
-static struct i2c_algo_bit_data bit_data = {
-	.setsda			= bit_setsda,
-	.setscl			= bit_setscl,
-	.getsda			= bit_getsda,
-	.getscl			= bit_getscl,
-	.udelay			= 5,
-	.timeout		= 100,
-};
-
-
-/*
- * PCL handling functions.
- */
-
-static pcl_t alloc_pcl(struct ti_lynx *lynx)
-{
-        u8 m;
-        int i, j;
-
-        spin_lock(&lynx->lock);
-        /* FIXME - use ffz() to make this readable */
-        for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {
-                m = lynx->pcl_bmap[i];
-                for (j = 0; j < 8; j++) {
-                        if (m & 1<<j) {
-                                continue;
-                        }
-                        m |= 1<<j;
-                        lynx->pcl_bmap[i] = m;
-                        spin_unlock(&lynx->lock);
-                        return 8 * i + j;
-                }
-        }
-        spin_unlock(&lynx->lock);
-
-        return -1;
-}
-
-
-#if 0
-static void free_pcl(struct ti_lynx *lynx, pcl_t pclid)
-{
-        int off, bit;
-
-        off = pclid / 8;
-        bit = pclid % 8;
-
-        if (pclid < 0) {
-                return;
-        }
-
-        spin_lock(&lynx->lock);
-        if (lynx->pcl_bmap[off] & 1<<bit) {
-                lynx->pcl_bmap[off] &= ~(1<<bit);
-        } else {
-                PRINT(KERN_ERR, lynx->id,
-                      "attempted to free unallocated PCL %d", pclid);
-        }
-        spin_unlock(&lynx->lock);
-}
-
-/* functions useful for debugging */
-static void pretty_print_pcl(const struct ti_pcl *pcl)
-{
-        int i;
-
-        printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",
-               pcl->next, pcl->user_data, pcl->pcl_status,
-               pcl->remaining_transfer_count, pcl->next_data_buffer);
-
-        printk("PCL");
-        for (i=0; i<13; i++) {
-                printk(" c%x:%08x d%x:%08x",
-                       i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);
-                if (!(i & 0x3) && (i != 12)) printk("\nPCL");
-        }
-        printk("\n");
-}
-
-static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        struct ti_pcl pcl;
-
-        get_pcl(lynx, pclid, &pcl);
-        pretty_print_pcl(&pcl);
-}
-#endif
-
-
-
-/***********************************
- * IEEE-1394 functionality section *
- ***********************************/
-
-
-static int get_phy_reg(struct ti_lynx *lynx, int addr)
-{
-        int retval;
-        int i = 0;
-
-        unsigned long flags;
-
-        if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id,
-                      "%s: PHY register address %d out of range",
-		      __func__, addr);
-                return -1;
-        }
-
-        spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
-        reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));
-        do {
-                retval = reg_read(lynx, LINK_PHY);
-
-                if (i > 10000) {
-                        PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",
-			      __func__);
-                        retval = -1;
-                        break;
-                }
-                i++;
-        } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));
-
-        reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);
-        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
-        if (retval != -1) {
-                return retval & 0xff;
-        } else {
-                return -1;
-        }
-}
-
-static int set_phy_reg(struct ti_lynx *lynx, int addr, int val)
-{
-        unsigned long flags;
-
-        if (addr > 15) {
-                PRINT(KERN_ERR, lynx->id,
-		      "%s: PHY register address %d out of range", __func__, addr);
-                return -1;
-        }
-
-        if (val > 0xff) {
-                PRINT(KERN_ERR, lynx->id,
-		      "%s: PHY register value %d out of range", __func__, val);
-                return -1;
-        }
-
-        spin_lock_irqsave(&lynx->phy_reg_lock, flags);
-
-        reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)
-                  | LINK_PHY_WDATA(val));
-
-        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);
-
-        return 0;
-}
-
-static int sel_phy_reg_page(struct ti_lynx *lynx, int page)
-{
-        int reg;
-
-        if (page > 7) {
-                PRINT(KERN_ERR, lynx->id,
-		      "%s: PHY page %d out of range", __func__, page);
-                return -1;
-        }
-
-        reg = get_phy_reg(lynx, 7);
-        if (reg != -1) {
-                reg &= 0x1f;
-                reg |= (page << 5);
-                set_phy_reg(lynx, 7, reg);
-                return 0;
-        } else {
-                return -1;
-        }
-}
-
-#if 0 /* not needed at this time */
-static int sel_phy_reg_port(struct ti_lynx *lynx, int port)
-{
-        int reg;
-
-        if (port > 15) {
-                PRINT(KERN_ERR, lynx->id,
-		      "%s: PHY port %d out of range", __func__, port);
-                return -1;
-        }
-
-        reg = get_phy_reg(lynx, 7);
-        if (reg != -1) {
-                reg &= 0xf0;
-                reg |= port;
-                set_phy_reg(lynx, 7, reg);
-                return 0;
-        } else {
-                return -1;
-        }
-}
-#endif
-
-static u32 get_phy_vendorid(struct ti_lynx *lynx)
-{
-        u32 pvid = 0;
-        sel_phy_reg_page(lynx, 1);
-        pvid |= (get_phy_reg(lynx, 10) << 16);
-        pvid |= (get_phy_reg(lynx, 11) << 8);
-        pvid |= get_phy_reg(lynx, 12);
-        PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);
-        return pvid;
-}
-
-static u32 get_phy_productid(struct ti_lynx *lynx)
-{
-        u32 id = 0;
-        sel_phy_reg_page(lynx, 1);
-        id |= (get_phy_reg(lynx, 13) << 16);
-        id |= (get_phy_reg(lynx, 14) << 8);
-        id |= get_phy_reg(lynx, 15);
-        PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);
-        return id;
-}
-
-static quadlet_t generate_own_selfid(struct ti_lynx *lynx,
-                                     struct hpsb_host *host)
-{
-        quadlet_t lsid;
-        char phyreg[7];
-        int i;
-
-        phyreg[0] = lynx->phy_reg0;
-        for (i = 1; i < 7; i++) {
-                phyreg[i] = get_phy_reg(lynx, i);
-        }
-
-        /* FIXME? We assume a TSB21LV03A phy here.  This code doesn't support
-           more than 3 ports on the PHY anyway. */
-
-        lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);
-        lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */
-        lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */
-	if (!hpsb_disable_irm)
-		lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */
-        /* lsid |= 1 << 11; *//* set contender (hack) */
-        lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */
-
-        for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */
-                if (phyreg[3 + i] & 0x4) {
-                        lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)
-                                << (6 - i*2);
-                } else {
-                        lsid |= 1 << (6 - i*2);
-                }
-        }
-
-        cpu_to_be32s(&lsid);
-        PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);
-        return lsid;
-}
-
-static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host)
-{
-        quadlet_t *q = lynx->rcv_page;
-        int phyid, isroot, size;
-        quadlet_t lsid = 0;
-        int i;
-
-        if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return;
-
-        size = lynx->selfid_size;
-        phyid = lynx->phy_reg0;
-
-        i = (size > 16 ? 16 : size) / 4 - 1;
-        while (i >= 0) {
-                cpu_to_be32s(&q[i]);
-                i--;
-        }
-
-        if (!lynx->phyic.reg_1394a) {
-                lsid = generate_own_selfid(lynx, host);
-        }
-
-        isroot = (phyid & 2) != 0;
-        phyid >>= 2;
-        PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",
-              phyid, (isroot ? "root" : "not root"));
-        reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);
-
-        if (!lynx->phyic.reg_1394a && !size) {
-                hpsb_selfid_received(host, lsid);
-        }
-
-        while (size > 0) {
-                struct selfid *sid = (struct selfid *)q;
-
-                if (!lynx->phyic.reg_1394a && !sid->extended
-                    && (sid->phy_id == (phyid + 1))) {
-                        hpsb_selfid_received(host, lsid);
-                }
-
-                if (q[0] == ~q[1]) {
-                        PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd",
-                              q[0]);
-                        hpsb_selfid_received(host, q[0]);
-                } else {
-                        PRINT(KERN_INFO, lynx->id,
-                              "inconsistent selfid 0x%x/0x%x", q[0], q[1]);
-                }
-                q += 2;
-                size -= 8;
-        }
-
-        if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {
-                hpsb_selfid_received(host, lsid);
-        }
-
-        hpsb_selfid_complete(host, phyid, isroot);
-
-        if (host->in_bus_reset) return; /* in bus reset again */
-
-        if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); //FIXME: I do not think, we need this here
-        reg_set_bits(lynx, LINK_CONTROL,
-                     LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN
-                     | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);
-}
-
-
-
-/* This must be called with the respective queue_lock held. */
-static void send_next(struct ti_lynx *lynx, int what)
-{
-        struct ti_pcl pcl;
-        struct lynx_send_data *d;
-        struct hpsb_packet *packet;
-
-#if 0 /* has been removed from ieee1394 core */
-        d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);
-#else
-	d = &lynx->async;
-#endif
-        if (!list_empty(&d->pcl_queue)) {
-                PRINT(KERN_ERR, lynx->id, "trying to queue a new packet in nonempty fifo");
-                BUG();
-        }
-
-        packet = driver_packet(d->queue.next);
-	list_move_tail(&packet->driver_list, &d->pcl_queue);
-
-        d->header_dma = pci_map_single(lynx->dev, packet->header,
-                                       packet->header_size, PCI_DMA_TODEVICE);
-        if (packet->data_size) {
-                d->data_dma = pci_map_single(lynx->dev, packet->data,
-                                             packet->data_size,
-                                             PCI_DMA_TODEVICE);
-        } else {
-                d->data_dma = 0;
-        }
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.pcl_status = 0;
-        pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[0].pointer = d->header_dma;
-        pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;
-        pcl.buffer[1].pointer = d->data_dma;
-
-        switch (packet->type) {
-        case hpsb_async:
-                pcl.buffer[0].control |= PCL_CMD_XMT;
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case hpsb_iso:
-                pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;
-                break;
-#endif
-        case hpsb_raw:
-                pcl.buffer[0].control |= PCL_CMD_UNFXMT;
-                break;
-        }
-
-        put_pcl(lynx, d->pcl, &pcl);
-        run_pcl(lynx, d->pcl_start, d->channel);
-}
-
-
-/* called from subsystem core */
-static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        struct lynx_send_data *d;
-        unsigned long flags;
-
-        if (packet->data_size >= 4096) {
-                PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)",
-                      packet->data_size);
-                return -EOVERFLOW;
-        }
-
-        switch (packet->type) {
-        case hpsb_async:
-        case hpsb_raw:
-                d = &lynx->async;
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case hpsb_iso:
-                d = &lynx->iso_send;
-                break;
-#endif
-        default:
-                PRINT(KERN_ERR, lynx->id, "invalid packet type %d",
-                      packet->type);
-                return -EINVAL;
-        }
-
-        if (packet->tcode == TCODE_WRITEQ
-            || packet->tcode == TCODE_READQ_RESPONSE) {
-                cpu_to_be32s(&packet->header[3]);
-        }
-
-        spin_lock_irqsave(&d->queue_lock, flags);
-
-	list_add_tail(&packet->driver_list, &d->queue);
-	if (list_empty(&d->pcl_queue))
-                send_next(lynx, packet->type);
-
-        spin_unlock_irqrestore(&d->queue_lock, flags);
-
-        return 0;
-}
-
-
-/* called from subsystem core */
-static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
-{
-        struct ti_lynx *lynx = host->hostdata;
-        int retval = 0;
-        struct hpsb_packet *packet;
-	LIST_HEAD(packet_list);
-        unsigned long flags;
-	int phy_reg;
-
-        switch (cmd) {
-        case RESET_BUS:
-                if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) {
-                        retval = 0;
-                        break;
-                }
-
-		switch (arg) {
-		case SHORT_RESET:
-			if (lynx->phyic.reg_1394a) {
-				phy_reg = get_phy_reg(lynx, 5);
-				if (phy_reg == -1) {
-					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-					retval = -1;
-					break;
-				}
-				phy_reg |= 0x40;
-
-				PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset) on request");
-
-				lynx->selfid_size = -1;
-				lynx->phy_reg0 = -1;
-				set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-				break;
-			} else {
-				PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-				/* fall through to long bus reset */
-			}
-		case LONG_RESET:
-			phy_reg = get_phy_reg(lynx, 1);
-			if (phy_reg == -1) {
-				PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-				retval = -1;
-				break;
-			}
-			phy_reg |= 0x40;
-
-			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset) on request");
-
-			lynx->selfid_size = -1;
-			lynx->phy_reg0 = -1;
-			set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
-			break;
-		case SHORT_RESET_NO_FORCE_ROOT:
-			if (lynx->phyic.reg_1394a) {
-				phy_reg = get_phy_reg(lynx, 1);
-				if (phy_reg == -1) {
-					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-					retval = -1;
-					break;
-				}
-				if (phy_reg & 0x80) {
-					phy_reg &= ~0x80;
-					set_phy_reg(lynx, 1, phy_reg); /* clear RHB */
-				}
-
-				phy_reg = get_phy_reg(lynx, 5);
-				if (phy_reg == -1) {
-					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-					retval = -1;
-					break;
-				}
-				phy_reg |= 0x40;
-
-				PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, no force_root) on request");
-
-				lynx->selfid_size = -1;
-				lynx->phy_reg0 = -1;
-				set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-				break;
-			} else {
-				PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-				/* fall through to long bus reset */
-			}
-		case LONG_RESET_NO_FORCE_ROOT:
-			phy_reg = get_phy_reg(lynx, 1);
-			if (phy_reg == -1) {
-				PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-				retval = -1;
-				break;
-			}
-			phy_reg &= ~0x80;
-			phy_reg |= 0x40;
-
-			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, no force_root) on request");
-
-			lynx->selfid_size = -1;
-			lynx->phy_reg0 = -1;
-			set_phy_reg(lynx, 1, phy_reg); /* clear RHB, set IBR */
-			break;
-		case SHORT_RESET_FORCE_ROOT:
-			if (lynx->phyic.reg_1394a) {
-				phy_reg = get_phy_reg(lynx, 1);
-				if (phy_reg == -1) {
-					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-					retval = -1;
-					break;
-				}
-				if (!(phy_reg & 0x80)) {
-					phy_reg |= 0x80;
-					set_phy_reg(lynx, 1, phy_reg); /* set RHB */
-				}
-
-				phy_reg = get_phy_reg(lynx, 5);
-				if (phy_reg == -1) {
-					PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-					retval = -1;
-					break;
-				}
-				phy_reg |= 0x40;
-
-				PRINT(KERN_INFO, lynx->id, "resetting bus (short bus reset, force_root set) on request");
-
-				lynx->selfid_size = -1;
-				lynx->phy_reg0 = -1;
-				set_phy_reg(lynx, 5, phy_reg); /* set ISBR */
-				break;
-			} else {
-				PRINT(KERN_INFO, lynx->id, "cannot do short bus reset, because of old phy");
-				/* fall through to long bus reset */
-			}
-		case LONG_RESET_FORCE_ROOT:
-			phy_reg = get_phy_reg(lynx, 1);
-			if (phy_reg == -1) {
-				PRINT(KERN_ERR, lynx->id, "cannot reset bus, because read phy reg failed");
-				retval = -1;
-				break;
-			}
-			phy_reg |= 0xc0;
-
-			PRINT(KERN_INFO, lynx->id, "resetting bus (long bus reset, force_root set) on request");
-
-			lynx->selfid_size = -1;
-			lynx->phy_reg0 = -1;
-			set_phy_reg(lynx, 1, phy_reg); /* set IBR and RHB */
-			break;
-		default:
-			PRINT(KERN_ERR, lynx->id, "unknown argument for reset_bus command %d", arg);
-			retval = -1;
-		}
-
-                break;
-
-        case GET_CYCLE_COUNTER:
-                retval = reg_read(lynx, CYCLE_TIMER);
-                break;
-
-        case SET_CYCLE_COUNTER:
-                reg_write(lynx, CYCLE_TIMER, arg);
-                break;
-
-        case SET_BUS_ID:
-                reg_write(lynx, LINK_ID,
-                          (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));
-                break;
-
-        case ACT_CYCLE_MASTER:
-                if (arg) {
-                        reg_set_bits(lynx, LINK_CONTROL,
-                                     LINK_CONTROL_CYCMASTER);
-                } else {
-                        reg_clear_bits(lynx, LINK_CONTROL,
-                                       LINK_CONTROL_CYCMASTER);
-                }
-                break;
-
-        case CANCEL_REQUESTS:
-                spin_lock_irqsave(&lynx->async.queue_lock, flags);
-
-                reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);
-		list_splice_init(&lynx->async.queue, &packet_list);
-
-                if (list_empty(&lynx->async.pcl_queue)) {
-                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-                        PRINTD(KERN_DEBUG, lynx->id, "no async packet in PCL to cancel");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-
-                        PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
-
-                        get_pcl(lynx, lynx->async.pcl, &pcl);
-
-                        packet = driver_packet(lynx->async.pcl_queue.next);
-			list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-
-                        spin_unlock_irqrestore(&lynx->async.queue_lock, flags);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
-                                ack = ACKX_ABORTED;
-                        }
-                        hpsb_packet_sent(host, packet, ack);
-                }
-
-		while (!list_empty(&packet_list)) {
-			packet = driver_packet(packet_list.next);
-			list_del_init(&packet->driver_list);
-			hpsb_packet_sent(host, packet, ACKX_ABORTED);
-		}
-
-                break;
-#if 0 /* has been removed from ieee1394 core */
-        case ISO_LISTEN_CHANNEL:
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-                if (lynx->iso_rcv.chan_count++ == 0) {
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                                  DMA_WORD1_CMP_ENABLE_MASTER);
-                }
-
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-                break;
-
-        case ISO_UNLISTEN_CHANNEL:
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-                if (--lynx->iso_rcv.chan_count == 0) {
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                                  0);
-                }
-
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-                break;
-#endif
-        default:
-                PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);
-                retval = -1;
-        }
-
-        return retval;
-}
-
-
-/***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
-
-
-/********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
-
-
-static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
-{
-        struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
-        struct hpsb_host *host = lynx->host;
-        u32 intmask;
-        u32 linkint;
-
-        linkint = reg_read(lynx, LINK_INT_STATUS);
-        intmask = reg_read(lynx, PCI_INT_STATUS);
-
-        if (!(intmask & PCI_INT_INT_PEND))
-		return IRQ_NONE;
-
-        PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,
-               linkint);
-
-        reg_write(lynx, LINK_INT_STATUS, linkint);
-        reg_write(lynx, PCI_INT_STATUS, intmask);
-
-        if (intmask & PCI_INT_1394) {
-                if (linkint & LINK_INT_PHY_TIMEOUT) {
-                        PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
-                }
-                if (linkint & LINK_INT_PHY_BUSRESET) {
-                        PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
-                        lynx->selfid_size = -1;
-                        lynx->phy_reg0 = -1;
-                        if (!host->in_bus_reset)
-                                hpsb_bus_reset(host);
-                }
-                if (linkint & LINK_INT_PHY_REG_RCVD) {
-                        u32 reg;
-
-                        spin_lock(&lynx->phy_reg_lock);
-                        reg = reg_read(lynx, LINK_PHY);
-                        spin_unlock(&lynx->phy_reg_lock);
-
-                        if (!host->in_bus_reset) {
-                                PRINT(KERN_INFO, lynx->id,
-                                      "phy reg received without reset");
-                        } else if (reg & 0xf00) {
-                                PRINT(KERN_INFO, lynx->id,
-                                      "unsolicited phy reg %d received",
-                                      (reg >> 8) & 0xf);
-                        } else {
-                                lynx->phy_reg0 = reg & 0xff;
-                                handle_selfid(lynx, host);
-                        }
-                }
-                if (linkint & LINK_INT_ISO_STUCK) {
-                        PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");
-                }
-                if (linkint & LINK_INT_ASYNC_STUCK) {
-                        PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");
-                }
-                if (linkint & LINK_INT_SENT_REJECT) {
-                        PRINT(KERN_INFO, lynx->id, "sent reject");
-                }
-                if (linkint & LINK_INT_TX_INVALID_TC) {
-                        PRINT(KERN_INFO, lynx->id, "invalid transaction code");
-                }
-                if (linkint & LINK_INT_GRF_OVERFLOW) {
-                        /* flush FIFO if overflow happens during reset */
-                        if (host->in_bus_reset)
-                                reg_write(lynx, FIFO_CONTROL,
-                                          FIFO_CONTROL_GRF_FLUSH);
-                        PRINT(KERN_INFO, lynx->id, "GRF overflow");
-                }
-                if (linkint & LINK_INT_ITF_UNDERFLOW) {
-                        PRINT(KERN_INFO, lynx->id, "ITF underflow");
-                }
-                if (linkint & LINK_INT_ATF_UNDERFLOW) {
-                        PRINT(KERN_INFO, lynx->id, "ATF underflow");
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {
-                PRINTD(KERN_DEBUG, lynx->id, "iso receive");
-
-                spin_lock(&lynx->iso_rcv.lock);
-
-                lynx->iso_rcv.stat[lynx->iso_rcv.next] =
-                        reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));
-
-                lynx->iso_rcv.used++;
-                lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;
-
-                if ((lynx->iso_rcv.next == lynx->iso_rcv.last)
-                    || !lynx->iso_rcv.chan_count) {
-                        PRINTD(KERN_DEBUG, lynx->id, "stopped");
-                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-                }
-
-                run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,
-                            CHANNEL_ISO_RCV);
-
-                spin_unlock(&lynx->iso_rcv.lock);
-
-		tasklet_schedule(&lynx->iso_rcv.tq);
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {
-                PRINTD(KERN_DEBUG, lynx->id, "async sent");
-                spin_lock(&lynx->async.queue_lock);
-
-                if (list_empty(&lynx->async.pcl_queue)) {
-                        spin_unlock(&lynx->async.queue_lock);
-                        PRINT(KERN_WARNING, lynx->id, "async dma halted, but no queued packet (maybe it was cancelled)");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-                        struct hpsb_packet *packet;
-
-                        get_pcl(lynx, lynx->async.pcl, &pcl);
-
-                        packet = driver_packet(lynx->async.pcl_queue.next);
-                        list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->async.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->async.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-
-                        if (!list_empty(&lynx->async.queue)) {
-                                send_next(lynx, hpsb_async);
-                        }
-
-                        spin_unlock(&lynx->async.queue_lock);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "async packet was not completed");
-                                ack = ACKX_SEND_ERROR;
-                        }
-                        hpsb_packet_sent(host, packet, ack);
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {
-                PRINTD(KERN_DEBUG, lynx->id, "iso sent");
-                spin_lock(&lynx->iso_send.queue_lock);
-
-                if (list_empty(&lynx->iso_send.pcl_queue)) {
-                        spin_unlock(&lynx->iso_send.queue_lock);
-                        PRINT(KERN_ERR, lynx->id, "iso send dma halted, but no queued packet");
-                } else {
-                        struct ti_pcl pcl;
-                        u32 ack;
-                        struct hpsb_packet *packet;
-
-                        get_pcl(lynx, lynx->iso_send.pcl, &pcl);
-
-                        packet = driver_packet(lynx->iso_send.pcl_queue.next);
-                        list_del_init(&packet->driver_list);
-
-                        pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,
-                                         packet->header_size, PCI_DMA_TODEVICE);
-                        if (packet->data_size) {
-                                pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,
-                                                 packet->data_size, PCI_DMA_TODEVICE);
-                        }
-#if 0 /* has been removed from ieee1394 core */
-                        if (!list_empty(&lynx->iso_send.queue)) {
-                                send_next(lynx, hpsb_iso);
-                        }
-#endif
-                        spin_unlock(&lynx->iso_send.queue_lock);
-
-                        if (pcl.pcl_status & DMA_CHAN_STAT_PKTCMPL) {
-                                if (pcl.pcl_status & DMA_CHAN_STAT_SPECIALACK) {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);
-                                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);
-                                } else {
-                                        ack = (pcl.pcl_status >> 15) & 0xf;
-                                }
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "iso send packet was not completed");
-                                ack = ACKX_SEND_ERROR;
-                        }
-
-                        hpsb_packet_sent(host, packet, ack); //FIXME: maybe we should just use ACK_COMPLETE and ACKX_SEND_ERROR
-                }
-        }
-
-        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {
-                /* general receive DMA completed */
-                int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV));
-
-                PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",
-                       stat & 0x1fff);
-
-                if (stat & DMA_CHAN_STAT_SELFID) {
-                        lynx->selfid_size = stat & 0x1fff;
-                        handle_selfid(lynx, host);
-                } else {
-                        quadlet_t *q_data = lynx->rcv_page;
-                        if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE
-                            || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {
-                                cpu_to_be32s(q_data + 3);
-                        }
-                        hpsb_packet_received(host, q_data, stat & 0x1fff, 0);
-                }
-
-                run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-        }
-
-	return IRQ_HANDLED;
-}
-
-
-static void iso_rcv_bh(struct ti_lynx *lynx)
-{
-        unsigned int idx;
-        quadlet_t *data;
-        unsigned long flags;
-
-        spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-
-        while (lynx->iso_rcv.used) {
-                idx = lynx->iso_rcv.last;
-                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-
-                data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]
-                        + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;
-
-                if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) {
-                        PRINT(KERN_ERR, lynx->id,
-                              "iso length mismatch 0x%08x/0x%08x", *data,
-                              lynx->iso_rcv.stat[idx]);
-                }
-
-                if (lynx->iso_rcv.stat[idx]
-                    & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {
-                        PRINT(KERN_INFO, lynx->id,
-                              "iso receive error on %d to 0x%p", idx, data);
-                } else {
-                        hpsb_packet_received(lynx->host, data,
-                                             lynx->iso_rcv.stat[idx] & 0x1fff,
-                                             0);
-                }
-
-                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);
-                lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;
-                lynx->iso_rcv.used--;
-        }
-
-        if (lynx->iso_rcv.chan_count) {
-                reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),
-                          DMA_WORD1_CMP_ENABLE_MASTER);
-        }
-        spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);
-}
-
-
-static void remove_card(struct pci_dev *dev)
-{
-        struct ti_lynx *lynx;
-	struct device *lynx_dev;
-        int i;
-
-        lynx = pci_get_drvdata(dev);
-        if (!lynx) return;
-        pci_set_drvdata(dev, NULL);
-
-	lynx_dev = get_device(&lynx->host->device);
-
-        switch (lynx->state) {
-        case is_host:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                hpsb_remove_host(lynx->host);
-        case have_intr:
-                reg_write(lynx, PCI_INT_ENABLE, 0);
-                free_irq(lynx->dev->irq, lynx);
-
-		/* Disable IRM Contender and LCtrl */
-		if (lynx->phyic.reg_1394a)
-			set_phy_reg(lynx, 4, ~0xc0 & get_phy_reg(lynx, 4));
-
-		/* Let all other nodes know to ignore us */
-		lynx_devctl(lynx->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
-
-        case have_iomappings:
-                reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-                /* Fix buggy cards with autoboot pin not tied low: */
-                reg_write(lynx, DMA0_CHAN_CTRL, 0);
-                iounmap(lynx->registers);
-                iounmap(lynx->local_rom);
-                iounmap(lynx->local_ram);
-                iounmap(lynx->aux_port);
-        case have_1394_buffers:
-                for (i = 0; i < ISORCV_PAGES; i++) {
-                        if (lynx->iso_rcv.page[i]) {
-                                pci_free_consistent(lynx->dev, PAGE_SIZE,
-                                                    lynx->iso_rcv.page[i],
-                                                    lynx->iso_rcv.page_dma[i]);
-                        }
-                }
-                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,
-                                    lynx->rcv_page_dma);
-        case have_aux_buf:
-        case have_pcl_mem:
-                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,
-                                    lynx->pcl_mem_dma);
-        case clear:
-                /* do nothing - already freed */
-                ;
-        }
-
-	tasklet_kill(&lynx->iso_rcv.tq);
-
-	if (lynx_dev)
-		put_device(lynx_dev);
-}
-
-
-static int __devinit add_card(struct pci_dev *dev,
-                              const struct pci_device_id *devid_is_unused)
-{
-#define FAIL(fmt, args...) do { \
-        PRINT_G(KERN_ERR, fmt , ## args); \
-        remove_card(dev); \
-        return error; \
-        } while (0)
-
-	char irq_buf[16];
-	struct hpsb_host *host;
-        struct ti_lynx *lynx; /* shortcut to currently handled device */
-        struct ti_pcl pcl;
-        u32 *pcli;
-        int i;
-        int error;
-
-        error = -ENXIO;
-
-        if (pci_set_dma_mask(dev, DMA_BIT_MASK(32)))
-                FAIL("DMA address limits not supported for PCILynx hardware");
-        if (pci_enable_device(dev))
-                FAIL("failed to enable PCILynx hardware");
-        pci_set_master(dev);
-
-        error = -ENOMEM;
-
-	host = hpsb_alloc_host(&lynx_driver, sizeof(struct ti_lynx), &dev->dev);
-        if (!host) FAIL("failed to allocate control structure memory");
-
-        lynx = host->hostdata;
-	lynx->id = card_id++;
-        lynx->dev = dev;
-        lynx->state = clear;
-	lynx->host = host;
-        host->pdev = dev;
-        pci_set_drvdata(dev, lynx);
-
-        spin_lock_init(&lynx->lock);
-        spin_lock_init(&lynx->phy_reg_lock);
-
-        lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE,
-                                             &lynx->pcl_mem_dma);
-
-        if (lynx->pcl_mem != NULL) {
-                lynx->state = have_pcl_mem;
-                PRINT(KERN_INFO, lynx->id,
-                      "allocated PCL memory %d Bytes @ 0x%p", LOCALRAM_SIZE,
-                      lynx->pcl_mem);
-        } else {
-                FAIL("failed to allocate PCL memory area");
-        }
-
-        lynx->rcv_page = pci_alloc_consistent(dev, PAGE_SIZE,
-                                              &lynx->rcv_page_dma);
-        if (lynx->rcv_page == NULL) {
-                FAIL("failed to allocate receive buffer");
-        }
-        lynx->state = have_1394_buffers;
-
-        for (i = 0; i < ISORCV_PAGES; i++) {
-                lynx->iso_rcv.page[i] =
-                        pci_alloc_consistent(dev, PAGE_SIZE,
-                                             &lynx->iso_rcv.page_dma[i]);
-                if (lynx->iso_rcv.page[i] == NULL) {
-                        FAIL("failed to allocate iso receive buffers");
-                }
-        }
-
-        lynx->registers = ioremap_nocache(pci_resource_start(dev,0),
-                                          PCILYNX_MAX_REGISTER);
-        lynx->local_ram = ioremap(pci_resource_start(dev,1), PCILYNX_MAX_MEMORY);
-        lynx->aux_port  = ioremap(pci_resource_start(dev,2), PCILYNX_MAX_MEMORY);
-        lynx->local_rom = ioremap(pci_resource_start(dev,PCI_ROM_RESOURCE),
-                                  PCILYNX_MAX_MEMORY);
-        lynx->state = have_iomappings;
-
-        if (lynx->registers == NULL) {
-                FAIL("failed to remap registers - card not accessible");
-        }
-
-        reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
-        /* Fix buggy cards with autoboot pin not tied low: */
-        reg_write(lynx, DMA0_CHAN_CTRL, 0);
-
-	sprintf (irq_buf, "%d", dev->irq);
-
-        if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED,
-                         PCILYNX_DRIVER_NAME, lynx)) {
-                PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);
-                lynx->state = have_intr;
-        } else {
-                FAIL("failed to allocate shared interrupt %s", irq_buf);
-        }
-
-        /* alloc_pcl return values are not checked, it is expected that the
-         * provided PCL space is sufficient for the initial allocations */
-        lynx->rcv_pcl = alloc_pcl(lynx);
-        lynx->rcv_pcl_start = alloc_pcl(lynx);
-        lynx->async.pcl = alloc_pcl(lynx);
-        lynx->async.pcl_start = alloc_pcl(lynx);
-        lynx->iso_send.pcl = alloc_pcl(lynx);
-        lynx->iso_send.pcl_start = alloc_pcl(lynx);
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                lynx->iso_rcv.pcl[i] = alloc_pcl(lynx);
-        }
-        lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
-
-        /* all allocations successful - simple init stuff follows */
-
-        reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
-
-	tasklet_init(&lynx->iso_rcv.tq, (void (*)(unsigned long))iso_rcv_bh,
-		     (unsigned long)lynx);
-
-        spin_lock_init(&lynx->iso_rcv.lock);
-
-        spin_lock_init(&lynx->async.queue_lock);
-        lynx->async.channel = CHANNEL_ASYNC_SEND;
-        spin_lock_init(&lynx->iso_send.queue_lock);
-        lynx->iso_send.channel = CHANNEL_ISO_SEND;
-
-        PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, "
-              "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom,
-              lynx->local_ram, lynx->aux_port);
-
-        /* now, looking for PHY register set */
-        if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
-                lynx->phyic.reg_1394a = 1;
-                PRINT(KERN_INFO, lynx->id,
-                      "found 1394a conform PHY (using extended register set)");
-                lynx->phyic.vendor = get_phy_vendorid(lynx);
-                lynx->phyic.product = get_phy_productid(lynx);
-        } else {
-                lynx->phyic.reg_1394a = 0;
-                PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
-        }
-
-        lynx->selfid_size = -1;
-        lynx->phy_reg0 = -1;
-
-	INIT_LIST_HEAD(&lynx->async.queue);
-	INIT_LIST_HEAD(&lynx->async.pcl_queue);
-	INIT_LIST_HEAD(&lynx->iso_send.queue);
-	INIT_LIST_HEAD(&lynx->iso_send.pcl_queue);
-
-        pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
-        put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-
-        pcl.buffer[0].control = PCL_CMD_RCV | 16;
-#ifndef __BIG_ENDIAN
-	pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-	pcl.buffer[1].control = PCL_LAST_BUFF | 4080;
-
-        pcl.buffer[0].pointer = lynx->rcv_page_dma;
-        pcl.buffer[1].pointer = lynx->rcv_page_dma + 16;
-        put_pcl(lynx, lynx->rcv_pcl, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->async.pcl);
-        pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl);
-        put_pcl(lynx, lynx->async.pcl_start, &pcl);
-
-        pcl.next = pcl_bus(lynx, lynx->iso_send.pcl);
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        put_pcl(lynx, lynx->iso_send.pcl_start, &pcl);
-
-        pcl.next = PCL_NEXT_INVALID;
-        pcl.async_error_next = PCL_NEXT_INVALID;
-        pcl.buffer[0].control = PCL_CMD_RCV | 4;
-#ifndef __BIG_ENDIAN
-        pcl.buffer[0].control |= PCL_BIGENDIAN;
-#endif
-        pcl.buffer[1].control = PCL_LAST_BUFF | 2044;
-
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                int page = i / ISORCV_PER_PAGE;
-                int sec = i % ISORCV_PER_PAGE;
-
-                pcl.buffer[0].pointer = lynx->iso_rcv.page_dma[page]
-                        + sec * MAX_ISORCV_SIZE;
-                pcl.buffer[1].pointer = pcl.buffer[0].pointer + 4;
-                put_pcl(lynx, lynx->iso_rcv.pcl[i], &pcl);
-        }
-
-        pcli = (u32 *)&pcl;
-        for (i = 0; i < NUM_ISORCV_PCL; i++) {
-                pcli[i] = pcl_bus(lynx, lynx->iso_rcv.pcl[i]);
-        }
-        put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl);
-
-        /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */
-        reg_write(lynx, FIFO_SIZES, 0x003030a0);
-        /* 20 byte threshold before triggering PCI transfer */
-        reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24);
-        /* threshold on both send FIFOs before transmitting:
-           FIFO size - cache line size - 1 */
-        i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff;
-        i = 0x30 - i - 1;
-        reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i);
-
-        reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394);
-
-        reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT
-                  | LINK_INT_PHY_REG_RCVD  | LINK_INT_PHY_BUSRESET
-                  | LINK_INT_ISO_STUCK     | LINK_INT_ASYNC_STUCK
-                  | LINK_INT_SENT_REJECT   | LINK_INT_TX_INVALID_TC
-                  | LINK_INT_GRF_OVERFLOW  | LINK_INT_ITF_UNDERFLOW
-                  | LINK_INT_ATF_UNDERFLOW);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV),
-                  DMA_WORD1_CMP_MATCH_LOCAL_NODE | DMA_WORD1_CMP_MATCH_BROADCAST
-                  | DMA_WORD1_CMP_MATCH_EXACT    | DMA_WORD1_CMP_MATCH_BUS_BCAST
-                  | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER);
-
-        run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);
-
-        reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4);
-        reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ISO_RCV), 0);
-        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);
-
-        run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, 0, CHANNEL_ISO_RCV);
-
-        reg_write(lynx, LINK_CONTROL, LINK_CONTROL_RCV_CMP_VALID
-                  | LINK_CONTROL_TX_ISO_EN   | LINK_CONTROL_RX_ISO_EN
-                  | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN
-                  | LINK_CONTROL_RESET_TX    | LINK_CONTROL_RESET_RX);
-
-	if (!lynx->phyic.reg_1394a) {
-		if (!hpsb_disable_irm) {
-			/* attempt to enable contender bit -FIXME- would this
-			 * work elsewhere? */
-			reg_set_bits(lynx, GPIO_CTRL_A, 0x1);
-			reg_write(lynx, GPIO_DATA_BASE + 0x3c, 0x1);
-		}
-	} else {
-		/* set the contender (if appropriate) and LCtrl bit in the
-		 * extended PHY register set. (Should check that PHY_02_EXTENDED
-		 * is set in register 2?)
-		 */
-		i = get_phy_reg(lynx, 4);
-		i |= PHY_04_LCTRL;
-		if (hpsb_disable_irm)
-			i &= ~PHY_04_CONTENDER;
-		else
-			i |= PHY_04_CONTENDER;
-		if (i != -1) set_phy_reg(lynx, 4, i);
-	}
-	
-        if (!skip_eeprom)
-        {
-        	/* needed for i2c communication with serial eeprom */
-        	struct i2c_adapter *i2c_ad;
-        	struct i2c_algo_bit_data i2c_adapter_data;
-
-        	error = -ENOMEM;
-		i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL);
-        	if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
-
-		strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name));
-                i2c_adapter_data = bit_data;
-                i2c_ad->algo_data = &i2c_adapter_data;
-                i2c_adapter_data.data = lynx;
-		i2c_ad->dev.parent = &dev->dev;
-
-		PRINTD(KERN_DEBUG, lynx->id,"original eeprom control: %d",
-		       reg_read(lynx, SERIAL_EEPROM_CONTROL));
-
-        	/* reset hardware to sane state */
-        	lynx->i2c_driven_state = 0x00000070;
-        	reg_write(lynx, SERIAL_EEPROM_CONTROL, lynx->i2c_driven_state);
-
-        	if (i2c_bit_add_bus(i2c_ad) < 0)
-        	{
-			kfree(i2c_ad);
-			error = -ENXIO;
-			FAIL("unable to register i2c");
-        	}
-        	else
-        	{
-                        /* do i2c stuff */
-                        unsigned char i2c_cmd = 0x10;
-                        struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
-                                                  { 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
-                                                };
-
-			/* we use i2c_transfer because we have no i2c_client
-			   at hand */
-                        if (i2c_transfer(i2c_ad, msg, 2) < 0) {
-                                PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
-                        } else {
-                                PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
-				/* FIXME: probably we should rewrite the max_rec, max_ROM(1394a),
-				 * generation(1394a) and link_spd(1394a) field and recalculate
-				 * the CRC */
-
-                                for (i = 0; i < 5 ; i++)
-                                        PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
-					       i, be32_to_cpu(lynx->bus_info_block[i]));
-
-                                /* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
-				if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
-				    (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC))
-                                {
-                                        PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
-                                } else {
-					kfree(i2c_ad);
-					error = -ENXIO;
-					FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
-                                }
-
-                        }
-
-			i2c_del_adapter(i2c_ad);
-			kfree(i2c_ad);
-                }
-        }
-
-	host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
-	host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
-	host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
-	host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
-	if (!lynx->phyic.reg_1394a)
-		host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
-	else
-		host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
-
-	if (hpsb_add_host(host)) {
-		error = -ENOMEM;
-		FAIL("Failed to register host with highlevel");
-	}
-
-	lynx->state = is_host;
-
-	return 0;
-#undef FAIL
-}
-
-
-static struct pci_device_id pci_table[] = {
-	{
-                .vendor =    PCI_VENDOR_ID_TI,
-                .device =    PCI_DEVICE_ID_TI_PCILYNX,
-                .subvendor = PCI_ANY_ID,
-                .subdevice = PCI_ANY_ID,
-	},
-	{ }			/* Terminating entry */
-};
-
-static struct pci_driver lynx_pci_driver = {
-        .name =     PCILYNX_DRIVER_NAME,
-        .id_table = pci_table,
-        .probe =    add_card,
-        .remove =   remove_card,
-};
-
-static struct hpsb_host_driver lynx_driver = {
-	.owner =	   THIS_MODULE,
-	.name =		   PCILYNX_DRIVER_NAME,
-	.set_hw_config_rom = NULL,
-        .transmit_packet = lynx_transmit,
-        .devctl =          lynx_devctl,
-	.isoctl =          NULL,
-};
-
-MODULE_AUTHOR("Andreas E. Bombe <andreas.bombe@munich.netsurf.de>");
-MODULE_DESCRIPTION("driver for Texas Instruments PCI Lynx IEEE-1394 controller");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("pcilynx");
-MODULE_DEVICE_TABLE(pci, pci_table);
-
-static int __init pcilynx_init(void)
-{
-        int ret;
-
-        ret = pci_register_driver(&lynx_pci_driver);
-        if (ret < 0) {
-                PRINT_G(KERN_ERR, "PCI module init failed");
-                return ret;
-        }
-
-        return 0;
-}
-
-static void __exit pcilynx_cleanup(void)
-{
-        pci_unregister_driver(&lynx_pci_driver);
-}
-
-
-module_init(pcilynx_init);
-module_exit(pcilynx_cleanup);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/pcilynx.h linux-libre-2.6.37-gnu/drivers/ieee1394/pcilynx.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/pcilynx.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/pcilynx.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,468 +0,0 @@
-#ifndef __PCILYNX_H__
-#define __PCILYNX_H__
-
-
-#define PCILYNX_DRIVER_NAME      "pcilynx"
-#define PCILYNX_MAJOR            177
-
-#define PCILYNX_MINOR_AUX_START  0
-#define PCILYNX_MINOR_ROM_START  16
-#define PCILYNX_MINOR_RAM_START  32
-
-#define PCILYNX_MAX_REGISTER     0xfff
-#define PCILYNX_MAX_MEMORY       0xffff
-
-#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
-#define MAX_PCILYNX_CARDS        4
-#define LOCALRAM_SIZE            4096
-
-#define NUM_ISORCV_PCL           4
-#define MAX_ISORCV_SIZE          2048
-#define ISORCV_PER_PAGE          (PAGE_SIZE / MAX_ISORCV_SIZE)
-#define ISORCV_PAGES             (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
-
-#define CHANNEL_LOCALBUS         0
-#define CHANNEL_ASYNC_RCV        1
-#define CHANNEL_ISO_RCV          2
-#define CHANNEL_ASYNC_SEND       3
-#define CHANNEL_ISO_SEND         4
-
-#define PCILYNX_CONFIG_ROM_LENGTH   1024
-
-typedef int pcl_t;
-
-struct ti_lynx {
-        int id; /* sequential card number */
-
-        spinlock_t lock;
-
-        struct pci_dev *dev;
-
-        struct {
-                unsigned reg_1394a:1;
-                u32 vendor;
-                u32 product;
-        } phyic;
-
-        enum { clear, have_intr, have_aux_buf, have_pcl_mem,
-               have_1394_buffers, have_iomappings, is_host } state;
-
-        /* remapped memory spaces */
-        void __iomem *registers;
-        void __iomem *local_rom;
-        void __iomem *local_ram;
-        void __iomem *aux_port;
-	__be32 bus_info_block[5];
-
-        /*
-         * use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
-         * LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
-         * the following is an allocation bitmap
-         */
-        u8 pcl_bmap[LOCALRAM_SIZE / 1024];
-
-	/* point to PCLs memory area if needed */
-	void *pcl_mem;
-        dma_addr_t pcl_mem_dma;
-
-        /* PCLs for local mem / aux transfers */
-        pcl_t dmem_pcl;
-
-        /* IEEE-1394 part follows */
-        struct hpsb_host *host;
-
-        int phyid, isroot;
-        int selfid_size;
-        int phy_reg0;
-
-        spinlock_t phy_reg_lock;
-
-        pcl_t rcv_pcl_start, rcv_pcl;
-        void *rcv_page;
-        dma_addr_t rcv_page_dma;
-        int rcv_active;
-
-        struct lynx_send_data {
-                pcl_t pcl_start, pcl;
-                struct list_head queue;
-                struct list_head pcl_queue; /* this queue contains at most one packet */
-                spinlock_t queue_lock;
-                dma_addr_t header_dma, data_dma;
-                int channel;
-        } async, iso_send;
-
-        struct {
-                pcl_t pcl[NUM_ISORCV_PCL];
-                u32 stat[NUM_ISORCV_PCL];
-                void *page[ISORCV_PAGES];
-                dma_addr_t page_dma[ISORCV_PAGES];
-                pcl_t pcl_start;
-                int chan_count;
-                int next, last, used, running;
-                struct tasklet_struct tq;
-                spinlock_t lock;
-        } iso_rcv;
-
-	u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
-};
-
-/* the per-file data structure for mem space access */
-struct memdata {
-        struct ti_lynx *lynx;
-        int cid;
-        atomic_t aux_intr_last_seen;
-	/* enum values are the same as LBUS_ADDR_SEL_* values below */
-        enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
-};
-
-
-
-/*
- * Register read and write helper functions.
- */
-static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
-{
-        writel(data, lynx->registers + offset);
-}
-
-static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
-{
-        return readl(lynx->registers + offset);
-}
-
-static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
-                                u32 mask)
-{
-        reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
-}
-
-static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
-                                  u32 mask)
-{
-        reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
-}
-
-
-
-/* chip register definitions follow */
-
-#define PCI_LATENCY_CACHELINE             0x0c
-
-#define MISC_CONTROL                      0x40
-#define MISC_CONTROL_SWRESET              (1<<0)
-
-#define SERIAL_EEPROM_CONTROL             0x44
-
-#define PCI_INT_STATUS                    0x48
-#define PCI_INT_ENABLE                    0x4c
-/* status and enable have identical bit numbers */
-#define PCI_INT_INT_PEND                  (1<<31)
-#define PCI_INT_FORCED_INT                (1<<30)
-#define PCI_INT_SLV_ADR_PERR              (1<<28)
-#define PCI_INT_SLV_DAT_PERR              (1<<27)
-#define PCI_INT_MST_DAT_PERR              (1<<26)
-#define PCI_INT_MST_DEV_TIMEOUT           (1<<25)
-#define PCI_INT_INTERNAL_SLV_TIMEOUT      (1<<23)
-#define PCI_INT_AUX_TIMEOUT               (1<<18)
-#define PCI_INT_AUX_INT                   (1<<17)
-#define PCI_INT_1394                      (1<<16)
-#define PCI_INT_DMA4_PCL                  (1<<9)
-#define PCI_INT_DMA4_HLT                  (1<<8)
-#define PCI_INT_DMA3_PCL                  (1<<7)
-#define PCI_INT_DMA3_HLT                  (1<<6)
-#define PCI_INT_DMA2_PCL                  (1<<5)
-#define PCI_INT_DMA2_HLT                  (1<<4)
-#define PCI_INT_DMA1_PCL                  (1<<3)
-#define PCI_INT_DMA1_HLT                  (1<<2)
-#define PCI_INT_DMA0_PCL                  (1<<1)
-#define PCI_INT_DMA0_HLT                  (1<<0)
-/* all DMA interrupts combined: */
-#define PCI_INT_DMA_ALL                   0x3ff
-
-#define PCI_INT_DMA_HLT(chan)             (1 << (chan * 2))
-#define PCI_INT_DMA_PCL(chan)             (1 << (chan * 2 + 1))
-
-#define LBUS_ADDR                         0xb4
-#define LBUS_ADDR_SEL_RAM                 (0x0<<16)
-#define LBUS_ADDR_SEL_ROM                 (0x1<<16)
-#define LBUS_ADDR_SEL_AUX                 (0x2<<16)
-#define LBUS_ADDR_SEL_ZV                  (0x3<<16)
-
-#define GPIO_CTRL_A                       0xb8
-#define GPIO_CTRL_B                       0xbc
-#define GPIO_DATA_BASE                    0xc0
-
-#define DMA_BREG(base, chan)              (base + chan * 0x20)
-#define DMA_SREG(base, chan)              (base + chan * 0x10)
-
-#define DMA0_PREV_PCL                     0x100
-#define DMA1_PREV_PCL                     0x120
-#define DMA2_PREV_PCL                     0x140
-#define DMA3_PREV_PCL                     0x160
-#define DMA4_PREV_PCL                     0x180
-#define DMA_PREV_PCL(chan)                (DMA_BREG(DMA0_PREV_PCL, chan))
-
-#define DMA0_CURRENT_PCL                  0x104
-#define DMA1_CURRENT_PCL                  0x124
-#define DMA2_CURRENT_PCL                  0x144
-#define DMA3_CURRENT_PCL                  0x164
-#define DMA4_CURRENT_PCL                  0x184
-#define DMA_CURRENT_PCL(chan)             (DMA_BREG(DMA0_CURRENT_PCL, chan))
-
-#define DMA0_CHAN_STAT                    0x10c
-#define DMA1_CHAN_STAT                    0x12c
-#define DMA2_CHAN_STAT                    0x14c
-#define DMA3_CHAN_STAT                    0x16c
-#define DMA4_CHAN_STAT                    0x18c
-#define DMA_CHAN_STAT(chan)               (DMA_BREG(DMA0_CHAN_STAT, chan))
-/* CHAN_STATUS registers share bits */
-#define DMA_CHAN_STAT_SELFID              (1<<31)
-#define DMA_CHAN_STAT_ISOPKT              (1<<30)
-#define DMA_CHAN_STAT_PCIERR              (1<<29)
-#define DMA_CHAN_STAT_PKTERR              (1<<28)
-#define DMA_CHAN_STAT_PKTCMPL             (1<<27)
-#define DMA_CHAN_STAT_SPECIALACK          (1<<14)
-
-
-#define DMA0_CHAN_CTRL                    0x110
-#define DMA1_CHAN_CTRL                    0x130
-#define DMA2_CHAN_CTRL                    0x150
-#define DMA3_CHAN_CTRL                    0x170
-#define DMA4_CHAN_CTRL                    0x190
-#define DMA_CHAN_CTRL(chan)               (DMA_BREG(DMA0_CHAN_CTRL, chan))
-/* CHAN_CTRL registers share bits */
-#define DMA_CHAN_CTRL_ENABLE              (1<<31)
-#define DMA_CHAN_CTRL_BUSY                (1<<30)
-#define DMA_CHAN_CTRL_LINK                (1<<29)
-
-#define DMA0_READY                        0x114
-#define DMA1_READY                        0x134
-#define DMA2_READY                        0x154
-#define DMA3_READY                        0x174
-#define DMA4_READY                        0x194
-#define DMA_READY(chan)                   (DMA_BREG(DMA0_READY, chan))
-
-#define DMA_GLOBAL_REGISTER               0x908
-
-#define FIFO_SIZES                        0xa00
-
-#define FIFO_CONTROL                      0xa10
-#define FIFO_CONTROL_GRF_FLUSH            (1<<4)
-#define FIFO_CONTROL_ITF_FLUSH            (1<<3)
-#define FIFO_CONTROL_ATF_FLUSH            (1<<2)
-
-#define FIFO_XMIT_THRESHOLD               0xa14
-
-#define DMA0_WORD0_CMP_VALUE              0xb00
-#define DMA1_WORD0_CMP_VALUE              0xb10
-#define DMA2_WORD0_CMP_VALUE              0xb20
-#define DMA3_WORD0_CMP_VALUE              0xb30
-#define DMA4_WORD0_CMP_VALUE              0xb40
-#define DMA_WORD0_CMP_VALUE(chan)         (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
-
-#define DMA0_WORD0_CMP_ENABLE             0xb04
-#define DMA1_WORD0_CMP_ENABLE             0xb14
-#define DMA2_WORD0_CMP_ENABLE             0xb24
-#define DMA3_WORD0_CMP_ENABLE             0xb34
-#define DMA4_WORD0_CMP_ENABLE             0xb44
-#define DMA_WORD0_CMP_ENABLE(chan)        (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
-
-#define DMA0_WORD1_CMP_VALUE              0xb08
-#define DMA1_WORD1_CMP_VALUE              0xb18
-#define DMA2_WORD1_CMP_VALUE              0xb28
-#define DMA3_WORD1_CMP_VALUE              0xb38
-#define DMA4_WORD1_CMP_VALUE              0xb48
-#define DMA_WORD1_CMP_VALUE(chan)         (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
-
-#define DMA0_WORD1_CMP_ENABLE             0xb0c
-#define DMA1_WORD1_CMP_ENABLE             0xb1c
-#define DMA2_WORD1_CMP_ENABLE             0xb2c
-#define DMA3_WORD1_CMP_ENABLE             0xb3c
-#define DMA4_WORD1_CMP_ENABLE             0xb4c
-#define DMA_WORD1_CMP_ENABLE(chan)        (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
-/* word 1 compare enable flags */
-#define DMA_WORD1_CMP_MATCH_OTHERBUS      (1<<15)
-#define DMA_WORD1_CMP_MATCH_BROADCAST     (1<<14)
-#define DMA_WORD1_CMP_MATCH_BUS_BCAST     (1<<13)
-#define DMA_WORD1_CMP_MATCH_LOCAL_NODE    (1<<12)
-#define DMA_WORD1_CMP_MATCH_EXACT         (1<<11)
-#define DMA_WORD1_CMP_ENABLE_SELF_ID      (1<<10)
-#define DMA_WORD1_CMP_ENABLE_MASTER       (1<<8)
-
-#define LINK_ID                           0xf00
-#define LINK_ID_BUS(id)                   (id<<22)
-#define LINK_ID_NODE(id)                  (id<<16)
-
-#define LINK_CONTROL                      0xf04
-#define LINK_CONTROL_BUSY                 (1<<29)
-#define LINK_CONTROL_TX_ISO_EN            (1<<26)
-#define LINK_CONTROL_RX_ISO_EN            (1<<25)
-#define LINK_CONTROL_TX_ASYNC_EN          (1<<24)
-#define LINK_CONTROL_RX_ASYNC_EN          (1<<23)
-#define LINK_CONTROL_RESET_TX             (1<<21)
-#define LINK_CONTROL_RESET_RX             (1<<20)
-#define LINK_CONTROL_CYCMASTER            (1<<11)
-#define LINK_CONTROL_CYCSOURCE            (1<<10)
-#define LINK_CONTROL_CYCTIMEREN           (1<<9)
-#define LINK_CONTROL_RCV_CMP_VALID        (1<<7)
-#define LINK_CONTROL_SNOOP_ENABLE         (1<<6)
-
-#define CYCLE_TIMER                       0xf08
-
-#define LINK_PHY                          0xf0c
-#define LINK_PHY_READ                     (1<<31)
-#define LINK_PHY_WRITE                    (1<<30)
-#define LINK_PHY_ADDR(addr)               (addr<<24)
-#define LINK_PHY_WDATA(data)              (data<<16)
-#define LINK_PHY_RADDR(addr)              (addr<<8)
-
-
-#define LINK_INT_STATUS                   0xf14
-#define LINK_INT_ENABLE                   0xf18
-/* status and enable have identical bit numbers */
-#define LINK_INT_LINK_INT                 (1<<31)
-#define LINK_INT_PHY_TIMEOUT              (1<<30)
-#define LINK_INT_PHY_REG_RCVD             (1<<29)
-#define LINK_INT_PHY_BUSRESET             (1<<28)
-#define LINK_INT_TX_RDY                   (1<<26)
-#define LINK_INT_RX_DATA_RDY              (1<<25)
-#define LINK_INT_ISO_STUCK                (1<<20)
-#define LINK_INT_ASYNC_STUCK              (1<<19)
-#define LINK_INT_SENT_REJECT              (1<<17)
-#define LINK_INT_HDR_ERR                  (1<<16)
-#define LINK_INT_TX_INVALID_TC            (1<<15)
-#define LINK_INT_CYC_SECOND               (1<<11)
-#define LINK_INT_CYC_START                (1<<10)
-#define LINK_INT_CYC_DONE                 (1<<9)
-#define LINK_INT_CYC_PENDING              (1<<8)
-#define LINK_INT_CYC_LOST                 (1<<7)
-#define LINK_INT_CYC_ARB_FAILED           (1<<6)
-#define LINK_INT_GRF_OVERFLOW             (1<<5)
-#define LINK_INT_ITF_UNDERFLOW            (1<<4)
-#define LINK_INT_ATF_UNDERFLOW            (1<<3)
-#define LINK_INT_ISOARB_FAILED            (1<<0)
-
-/* PHY specifics */
-#define PHY_VENDORID_TI                 0x800028
-#define PHY_PRODUCTID_TSB41LV03         0x000000
-
-
-/* this is the physical layout of a PCL, its size is 128 bytes */
-struct ti_pcl {
-        u32 next;
-        u32 async_error_next;
-        u32 user_data;
-        u32 pcl_status;
-        u32 remaining_transfer_count;
-        u32 next_data_buffer;
-        struct {
-                u32 control;
-                u32 pointer;
-        } buffer[13] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#include <linux/stddef.h>
-#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
-
-
-static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           const struct ti_pcl *pcl)
-{
-        memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
-                    (u32 *)pcl, sizeof(struct ti_pcl));
-}
-
-static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                           struct ti_pcl *pcl)
-{
-        memcpy_le32((u32 *)pcl,
-                    (u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
-                    sizeof(struct ti_pcl));
-}
-
-static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
-{
-        return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
-}
-
-
-#if defined (__BIG_ENDIAN)
-typedef struct ti_pcl pcltmp_t;
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                                      pcltmp_t *tmp)
-{
-        get_pcl(lynx, pclid, tmp);
-        return tmp;
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                              pcltmp_t *tmp)
-{
-        put_pcl(lynx, pclid, tmp);
-}
-
-#else
-typedef int pcltmp_t; /* just a dummy */
-
-static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                                      pcltmp_t *tmp)
-{
-        return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
-}
-
-static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
-                              pcltmp_t *tmp)
-{
-}
-#endif
-
-
-static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
-                               int dmachan)
-{
-        reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
-                  pcl_bus(lynx, pclid) + idx * 4);
-        reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
-                  DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
-}
-
-static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
-{
-        run_sub_pcl(lynx, pclid, 0, dmachan);
-}
-
-#define PCL_NEXT_INVALID (1<<0)
-
-/* transfer commands */
-#define PCL_CMD_RCV            (0x1<<24)
-#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
-#define PCL_CMD_XMT            (0x2<<24)
-#define PCL_CMD_UNFXMT         (0xc<<24)
-#define PCL_CMD_PCI_TO_LBUS    (0x8<<24)
-#define PCL_CMD_LBUS_TO_PCI    (0x9<<24)
-
-/* aux commands */
-#define PCL_CMD_NOP            (0x0<<24)
-#define PCL_CMD_LOAD           (0x3<<24)
-#define PCL_CMD_STOREQ         (0x4<<24)
-#define PCL_CMD_STORED         (0xb<<24)
-#define PCL_CMD_STORE0         (0x5<<24)
-#define PCL_CMD_STORE1         (0x6<<24)
-#define PCL_CMD_COMPARE        (0xe<<24)
-#define PCL_CMD_SWAP_COMPARE   (0xf<<24)
-#define PCL_CMD_ADD            (0xd<<24)
-#define PCL_CMD_BRANCH         (0x7<<24)
-
-/* BRANCH condition codes */
-#define PCL_COND_DMARDY_SET    (0x1<<20)
-#define PCL_COND_DMARDY_CLEAR  (0x2<<20)
-
-#define PCL_GEN_INTR           (1<<19)
-#define PCL_LAST_BUFF          (1<<18)
-#define PCL_LAST_CMD           (PCL_LAST_BUFF)
-#define PCL_WAITSTAT           (1<<17)
-#define PCL_BIGENDIAN          (1<<16)
-#define PCL_ISOMODE            (1<<12)
-
-#endif
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394.c linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,3096 +0,0 @@
-/*
- * IEEE 1394 for Linux
- *
- * Raw interface to the bus
- *
- * Copyright (C) 1999, 2000 Andreas E. Bombe
- *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
- *                     2002 Christian Toegel <christian.toegel@gmx.at>
- *
- * This code is licensed under the GPL.  See the file COPYING in the root
- * directory of the kernel sources for details.
- *
- *
- * Contributions:
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- *        configuration ROM manipulation
- *        address range mapping
- *        adaptation for new (transparent) loopback mechanism
- *        sending of arbitrary async packets
- * Christian Toegel <christian.toegel@gmx.at>
- *        address range mapping
- *        lock64 request
- *        transmit physical packet
- *        busreset notification control (switch on/off)
- *        busreset with selection of type (short/long)
- *        request_reply
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <linux/cdev.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/compat.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "iso.h"
-#include "nodemgr.h"
-#include "raw1394.h"
-#include "raw1394-private.h"
-
-#define int2ptr(x) ((void __user *)(unsigned long)x)
-#define ptr2int(x) ((u64)(unsigned long)(void __user *)x)
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define RAW1394_DEBUG
-#endif
-
-#ifdef RAW1394_DEBUG
-#define DBGMSG(fmt, args...) \
-printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
-#else
-#define DBGMSG(fmt, args...) do {} while (0)
-#endif
-
-static LIST_HEAD(host_info_list);
-static int host_count;
-static DEFINE_SPINLOCK(host_info_lock);
-static atomic_t internal_generation = ATOMIC_INIT(0);
-
-static atomic_t iso_buffer_size;
-static const int iso_buffer_max = 4 * 1024 * 1024;	/* 4 MB */
-
-static struct hpsb_highlevel raw1394_highlevel;
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
-		    u64 addr, size_t length, u16 flags);
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
-		     quadlet_t * data, u64 addr, size_t length, u16 flags);
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-		    u16 flags);
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
-		      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-		      u16 flags);
-static const struct hpsb_address_ops arm_ops = {
-	.read = arm_read,
-	.write = arm_write,
-	.lock = arm_lock,
-	.lock64 = arm_lock64,
-};
-
-static void queue_complete_cb(struct pending_request *req);
-
-static struct pending_request *__alloc_pending_request(gfp_t flags)
-{
-	struct pending_request *req;
-
-	req = kzalloc(sizeof(*req), flags);
-	if (req)
-		INIT_LIST_HEAD(&req->list);
-
-	return req;
-}
-
-static inline struct pending_request *alloc_pending_request(void)
-{
-	return __alloc_pending_request(GFP_KERNEL);
-}
-
-static void free_pending_request(struct pending_request *req)
-{
-	if (req->ibs) {
-		if (atomic_dec_and_test(&req->ibs->refcount)) {
-			atomic_sub(req->ibs->data_size, &iso_buffer_size);
-			kfree(req->ibs);
-		}
-	} else if (req->free_data) {
-		kfree(req->data);
-	}
-	hpsb_free_packet(req->packet);
-	kfree(req);
-}
-
-/* fi->reqlists_lock must be taken */
-static void __queue_complete_req(struct pending_request *req)
-{
-	struct file_info *fi = req->file_info;
-
-	list_move_tail(&req->list, &fi->req_complete);
- 	wake_up(&fi->wait_complete);
-}
-
-static void queue_complete_req(struct pending_request *req)
-{
-	unsigned long flags;
-	struct file_info *fi = req->file_info;
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	__queue_complete_req(req);
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void queue_complete_cb(struct pending_request *req)
-{
-	struct hpsb_packet *packet = req->packet;
-	int rcode = (packet->header[1] >> 12) & 0xf;
-
-	switch (packet->ack_code) {
-	case ACKX_NONE:
-	case ACKX_SEND_ERROR:
-		req->req.error = RAW1394_ERROR_SEND_ERROR;
-		break;
-	case ACKX_ABORTED:
-		req->req.error = RAW1394_ERROR_ABORTED;
-		break;
-	case ACKX_TIMEOUT:
-		req->req.error = RAW1394_ERROR_TIMEOUT;
-		break;
-	default:
-		req->req.error = (packet->ack_code << 16) | rcode;
-		break;
-	}
-
-	if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {
-		req->req.length = 0;
-	}
-
-	if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||
-	    (req->req.type == RAW1394_REQ_ASYNC_WRITE) ||
-	    (req->req.type == RAW1394_REQ_ASYNC_STREAM) ||
-	    (req->req.type == RAW1394_REQ_LOCK) ||
-	    (req->req.type == RAW1394_REQ_LOCK64))
-		hpsb_free_tlabel(packet);
-
-	queue_complete_req(req);
-}
-
-static void add_host(struct hpsb_host *host)
-{
-	struct host_info *hi;
-	unsigned long flags;
-
-	hi = kmalloc(sizeof(*hi), GFP_KERNEL);
-
-	if (hi) {
-		INIT_LIST_HEAD(&hi->list);
-		hi->host = host;
-		INIT_LIST_HEAD(&hi->file_info_list);
-
-		spin_lock_irqsave(&host_info_lock, flags);
-		list_add_tail(&hi->list, &host_info_list);
-		host_count++;
-		spin_unlock_irqrestore(&host_info_lock, flags);
-	}
-
-	atomic_inc(&internal_generation);
-}
-
-static struct host_info *find_host_info(struct hpsb_host *host)
-{
-	struct host_info *hi;
-
-	list_for_each_entry(hi, &host_info_list, list)
-	    if (hi->host == host)
-		return hi;
-
-	return NULL;
-}
-
-static void remove_host(struct hpsb_host *host)
-{
-	struct host_info *hi;
-	unsigned long flags;
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	hi = find_host_info(host);
-
-	if (hi != NULL) {
-		list_del(&hi->list);
-		host_count--;
-		/*
-		   FIXME: address ranges should be removed
-		   and fileinfo states should be initialized
-		   (including setting generation to
-		   internal-generation ...)
-		 */
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-
-	if (hi == NULL) {
-		printk(KERN_ERR "raw1394: attempt to remove unknown host "
-		       "0x%p\n", host);
-		return;
-	}
-
-	kfree(hi);
-
-	atomic_inc(&internal_generation);
-}
-
-static void host_reset(struct hpsb_host *host)
-{
-	unsigned long flags;
-	struct host_info *hi;
-	struct file_info *fi;
-	struct pending_request *req;
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	hi = find_host_info(host);
-
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			if (fi->notification == RAW1394_NOTIFY_ON) {
-				req = __alloc_pending_request(GFP_ATOMIC);
-
-				if (req != NULL) {
-					req->file_info = fi;
-					req->req.type = RAW1394_REQ_BUS_RESET;
-					req->req.generation =
-					    get_hpsb_generation(host);
-					req->req.misc = (host->node_id << 16)
-					    | host->node_count;
-					if (fi->protocol_version > 3) {
-						req->req.misc |=
-						    (NODEID_TO_NODE
-						     (host->irm_id)
-						     << 8);
-					}
-
-					queue_complete_req(req);
-				}
-			}
-		}
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
-			int cts, u8 * data, size_t length)
-{
-	unsigned long flags;
-	struct host_info *hi;
-	struct file_info *fi;
-	struct pending_request *req, *req_next;
-	struct iso_block_store *ibs = NULL;
-	LIST_HEAD(reqs);
-
-	if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {
-		HPSB_INFO("dropped fcp request");
-		return;
-	}
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	hi = find_host_info(host);
-
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			if (!fi->fcp_buffer)
-				continue;
-
-			req = __alloc_pending_request(GFP_ATOMIC);
-			if (!req)
-				break;
-
-			if (!ibs) {
-				ibs = kmalloc(sizeof(*ibs) + length,
-					      GFP_ATOMIC);
-				if (!ibs) {
-					kfree(req);
-					break;
-				}
-
-				atomic_add(length, &iso_buffer_size);
-				atomic_set(&ibs->refcount, 0);
-				ibs->data_size = length;
-				memcpy(ibs->data, data, length);
-			}
-
-			atomic_inc(&ibs->refcount);
-
-			req->file_info = fi;
-			req->ibs = ibs;
-			req->data = ibs->data;
-			req->req.type = RAW1394_REQ_FCP_REQUEST;
-			req->req.generation = get_hpsb_generation(host);
-			req->req.misc = nodeid | (direction << 16);
-			req->req.recvb = ptr2int(fi->fcp_buffer);
-			req->req.length = length;
-
-			list_add_tail(&req->list, &reqs);
-		}
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-
-	list_for_each_entry_safe(req, req_next, &reqs, list)
-	    queue_complete_req(req);
-}
-
-#ifdef CONFIG_COMPAT
-struct compat_raw1394_req {
-	__u32 type;
-	__s32 error;
-	__u32 misc;
-
-	__u32 generation;
-	__u32 length;
-
-	__u64 address;
-
-	__u64 tag;
-
-	__u64 sendb;
-	__u64 recvb;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-static const char __user *raw1394_compat_write(const char __user *buf)
-{
-	struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-	struct raw1394_request __user *r;
-
-	r = compat_alloc_user_space(sizeof(struct raw1394_request));
-
-#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x))
-
-	if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) ||
-	    C(address) ||
-	    C(tag) ||
-	    C(sendb) ||
-	    C(recvb))
-		return (__force const char __user *)ERR_PTR(-EFAULT);
-
-	return (const char __user *)r;
-}
-#undef C
-
-#define P(x) __put_user(r->x, &cr->x)
-
-static int
-raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
-{
-	struct compat_raw1394_req __user *cr = (typeof(cr)) buf;
-
-	if (!access_ok(VERIFY_WRITE, cr, sizeof(struct compat_raw1394_req)) ||
-	    P(type) ||
-	    P(error) ||
-	    P(misc) ||
-	    P(generation) ||
-	    P(length) ||
-	    P(address) ||
-	    P(tag) ||
-	    P(sendb) ||
-	    P(recvb))
-		return -EFAULT;
-
-	return sizeof(struct compat_raw1394_req);
-}
-#undef P
-
-#endif
-
-/* get next completed request  (caller must hold fi->reqlists_lock) */
-static inline struct pending_request *__next_complete_req(struct file_info *fi)
-{
-	struct list_head *lh;
-	struct pending_request *req = NULL;
-
-	if (!list_empty(&fi->req_complete)) {
-		lh = fi->req_complete.next;
-		list_del(lh);
-		req = list_entry(lh, struct pending_request, list);
-	}
-	return req;
-}
-
-/* atomically get next completed request */
-static struct pending_request *next_complete_req(struct file_info *fi)
-{
-	unsigned long flags;
-	struct pending_request *req;
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	req = __next_complete_req(fi);
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-	return req;
-}
-
-static ssize_t raw1394_read(struct file *file, char __user * buffer,
-			    size_t count, loff_t * offset_is_ignored)
-{
-	struct file_info *fi = file->private_data;
-	struct pending_request *req;
-	ssize_t ret;
-
-#ifdef CONFIG_COMPAT
-	if (count == sizeof(struct compat_raw1394_req)) {
-		/* ok */
-	} else
-#endif
-	if (count != sizeof(struct raw1394_request)) {
-		return -EINVAL;
-	}
-
-	if (!access_ok(VERIFY_WRITE, buffer, count)) {
-		return -EFAULT;
-	}
-
-	if (file->f_flags & O_NONBLOCK) {
-		if (!(req = next_complete_req(fi)))
-			return -EAGAIN;
-	} else {
-		/*
-		 * NB: We call the macro wait_event_interruptible() with a
-		 * condition argument with side effect.  This is only possible
-		 * because the side effect does not occur until the condition
-		 * became true, and wait_event_interruptible() won't evaluate
-		 * the condition again after that.
-		 */
-		if (wait_event_interruptible(fi->wait_complete,
-					     (req = next_complete_req(fi))))
-			return -ERESTARTSYS;
-	}
-
-	if (req->req.length) {
-		if (copy_to_user(int2ptr(req->req.recvb), req->data,
-				 req->req.length)) {
-			req->req.error = RAW1394_ERROR_MEMFAULT;
-		}
-	}
-
-#ifdef CONFIG_COMPAT
-	if (count == sizeof(struct compat_raw1394_req) &&
-   	    sizeof(struct compat_raw1394_req) !=
-			sizeof(struct raw1394_request)) {
-		ret = raw1394_compat_read(buffer, &req->req);
-	} else
-#endif
-	{
-		if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
-			ret = -EFAULT;
-			goto out;
-		}
-		ret = (ssize_t) sizeof(struct raw1394_request);
-	}
-      out:
-	free_pending_request(req);
-	return ret;
-}
-
-static int state_opened(struct file_info *fi, struct pending_request *req)
-{
-	if (req->req.type == RAW1394_REQ_INITIALIZE) {
-		switch (req->req.misc) {
-		case RAW1394_KERNELAPI_VERSION:
-		case 3:
-			fi->state = initialized;
-			fi->protocol_version = req->req.misc;
-			req->req.error = RAW1394_ERROR_NONE;
-			req->req.generation = atomic_read(&internal_generation);
-			break;
-
-		default:
-			req->req.error = RAW1394_ERROR_COMPAT;
-			req->req.misc = RAW1394_KERNELAPI_VERSION;
-		}
-	} else {
-		req->req.error = RAW1394_ERROR_STATE_ORDER;
-	}
-
-	req->req.length = 0;
-	queue_complete_req(req);
-	return 0;
-}
-
-static int state_initialized(struct file_info *fi, struct pending_request *req)
-{
-	unsigned long flags;
-	struct host_info *hi;
-	struct raw1394_khost_list *khl;
-
-	if (req->req.generation != atomic_read(&internal_generation)) {
-		req->req.error = RAW1394_ERROR_GENERATION;
-		req->req.generation = atomic_read(&internal_generation);
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	switch (req->req.type) {
-	case RAW1394_REQ_LIST_CARDS:
-		spin_lock_irqsave(&host_info_lock, flags);
-		khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC);
-
-		if (khl) {
-			req->req.misc = host_count;
-			req->data = (quadlet_t *) khl;
-
-			list_for_each_entry(hi, &host_info_list, list) {
-				khl->nodes = hi->host->node_count;
-				strcpy(khl->name, hi->host->driver->name);
-				khl++;
-			}
-		}
-		spin_unlock_irqrestore(&host_info_lock, flags);
-
-		if (khl) {
-			req->req.error = RAW1394_ERROR_NONE;
-			req->req.length = min(req->req.length,
-					      (u32) (sizeof
-						     (struct raw1394_khost_list)
-						     * req->req.misc));
-			req->free_data = 1;
-		} else {
-			return -ENOMEM;
-		}
-		break;
-
-	case RAW1394_REQ_SET_CARD:
-		spin_lock_irqsave(&host_info_lock, flags);
-		if (req->req.misc >= host_count) {
-			req->req.error = RAW1394_ERROR_INVALID_ARG;
-			goto out_set_card;
-		}
-		list_for_each_entry(hi, &host_info_list, list)
-			if (!req->req.misc--)
-				break;
-		get_device(&hi->host->device); /* FIXME handle failure case */
-		list_add_tail(&fi->list, &hi->file_info_list);
-
-		/* prevent unloading of the host's low-level driver */
-		if (!try_module_get(hi->host->driver->owner)) {
-			req->req.error = RAW1394_ERROR_ABORTED;
-			goto out_set_card;
-		}
-		WARN_ON(fi->host);
-		fi->host = hi->host;
-		fi->state = connected;
-
-		req->req.error = RAW1394_ERROR_NONE;
-		req->req.generation = get_hpsb_generation(fi->host);
-		req->req.misc = (fi->host->node_id << 16)
-				| fi->host->node_count;
-		if (fi->protocol_version > 3)
-			req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
-out_set_card:
-		spin_unlock_irqrestore(&host_info_lock, flags);
-
-		req->req.length = 0;
-		break;
-
-	default:
-		req->req.error = RAW1394_ERROR_STATE_ORDER;
-		req->req.length = 0;
-		break;
-	}
-
-	queue_complete_req(req);
-	return 0;
-}
-
-static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
-{
-	if (req->req.misc) {
-		if (fi->fcp_buffer) {
-			req->req.error = RAW1394_ERROR_ALREADY;
-		} else {
-			fi->fcp_buffer = int2ptr(req->req.recvb);
-		}
-	} else {
-		if (!fi->fcp_buffer) {
-			req->req.error = RAW1394_ERROR_ALREADY;
-		} else {
-			fi->fcp_buffer = NULL;
-		}
-	}
-
-	req->req.length = 0;
-	queue_complete_req(req);
-}
-
-static int handle_async_request(struct file_info *fi,
-				struct pending_request *req, int node)
-{
-	unsigned long flags;
-	struct hpsb_packet *packet = NULL;
-	u64 addr = req->req.address & 0xffffffffffffULL;
-
-	switch (req->req.type) {
-	case RAW1394_REQ_ASYNC_READ:
-		DBGMSG("read_request called");
-		packet =
-		    hpsb_make_readpacket(fi->host, node, addr, req->req.length);
-
-		if (!packet)
-			return -ENOMEM;
-
-		if (req->req.length == 4)
-			req->data = &packet->header[3];
-		else
-			req->data = packet->data;
-
-		break;
-
-	case RAW1394_REQ_ASYNC_WRITE:
-		DBGMSG("write_request called");
-
-		packet = hpsb_make_writepacket(fi->host, node, addr, NULL,
-					       req->req.length);
-		if (!packet)
-			return -ENOMEM;
-
-		if (req->req.length == 4) {
-			if (copy_from_user
-			    (&packet->header[3], int2ptr(req->req.sendb),
-			     req->req.length))
-				req->req.error = RAW1394_ERROR_MEMFAULT;
-		} else {
-			if (copy_from_user
-			    (packet->data, int2ptr(req->req.sendb),
-			     req->req.length))
-				req->req.error = RAW1394_ERROR_MEMFAULT;
-		}
-
-		req->req.length = 0;
-		break;
-
-	case RAW1394_REQ_ASYNC_STREAM:
-		DBGMSG("stream_request called");
-
-		packet =
-		    hpsb_make_streampacket(fi->host, NULL, req->req.length,
-					   node & 0x3f /*channel */ ,
-					   (req->req.misc >> 16) & 0x3,
-					   req->req.misc & 0xf);
-		if (!packet)
-			return -ENOMEM;
-
-		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-				   req->req.length))
-			req->req.error = RAW1394_ERROR_MEMFAULT;
-
-		req->req.length = 0;
-		break;
-
-	case RAW1394_REQ_LOCK:
-		DBGMSG("lock_request called");
-		if ((req->req.misc == EXTCODE_FETCH_ADD)
-		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-			if (req->req.length != 4) {
-				req->req.error = RAW1394_ERROR_INVALID_ARG;
-				break;
-			}
-		} else {
-			if (req->req.length != 8) {
-				req->req.error = RAW1394_ERROR_INVALID_ARG;
-				break;
-			}
-		}
-
-		packet = hpsb_make_lockpacket(fi->host, node, addr,
-					      req->req.misc, NULL, 0);
-		if (!packet)
-			return -ENOMEM;
-
-		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-				   req->req.length)) {
-			req->req.error = RAW1394_ERROR_MEMFAULT;
-			break;
-		}
-
-		req->data = packet->data;
-		req->req.length = 4;
-		break;
-
-	case RAW1394_REQ_LOCK64:
-		DBGMSG("lock64_request called");
-		if ((req->req.misc == EXTCODE_FETCH_ADD)
-		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-			if (req->req.length != 8) {
-				req->req.error = RAW1394_ERROR_INVALID_ARG;
-				break;
-			}
-		} else {
-			if (req->req.length != 16) {
-				req->req.error = RAW1394_ERROR_INVALID_ARG;
-				break;
-			}
-		}
-		packet = hpsb_make_lock64packet(fi->host, node, addr,
-						req->req.misc, NULL, 0);
-		if (!packet)
-			return -ENOMEM;
-
-		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
-				   req->req.length)) {
-			req->req.error = RAW1394_ERROR_MEMFAULT;
-			break;
-		}
-
-		req->data = packet->data;
-		req->req.length = 8;
-		break;
-
-	default:
-		req->req.error = RAW1394_ERROR_STATE_ORDER;
-	}
-
-	req->packet = packet;
-
-	if (req->req.error) {
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	hpsb_set_packet_complete_task(packet,
-				      (void (*)(void *))queue_complete_cb, req);
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	list_add_tail(&req->list, &fi->req_pending);
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-	packet->generation = req->req.generation;
-
-	if (hpsb_send_packet(packet) < 0) {
-		req->req.error = RAW1394_ERROR_SEND_ERROR;
-		req->req.length = 0;
-		hpsb_free_tlabel(packet);
-		queue_complete_req(req);
-	}
-	return 0;
-}
-
-static int handle_async_send(struct file_info *fi, struct pending_request *req)
-{
-	unsigned long flags;
-	struct hpsb_packet *packet;
-	int header_length = req->req.misc & 0xffff;
-	int expect_response = req->req.misc >> 16;
-	size_t data_size;
-
-	if (header_length > req->req.length || header_length < 12 ||
-	    header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
-		req->req.error = RAW1394_ERROR_INVALID_ARG;
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	data_size = req->req.length - header_length;
-	packet = hpsb_alloc_packet(data_size);
-	req->packet = packet;
-	if (!packet)
-		return -ENOMEM;
-
-	if (copy_from_user(packet->header, int2ptr(req->req.sendb),
-			   header_length)) {
-		req->req.error = RAW1394_ERROR_MEMFAULT;
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	if (copy_from_user
-	    (packet->data, int2ptr(req->req.sendb) + header_length,
-	     data_size)) {
-		req->req.error = RAW1394_ERROR_MEMFAULT;
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	packet->type = hpsb_async;
-	packet->node_id = packet->header[0] >> 16;
-	packet->tcode = (packet->header[0] >> 4) & 0xf;
-	packet->tlabel = (packet->header[0] >> 10) & 0x3f;
-	packet->host = fi->host;
-	packet->expect_response = expect_response;
-	packet->header_size = header_length;
-	packet->data_size = data_size;
-
-	req->req.length = 0;
-	hpsb_set_packet_complete_task(packet,
-				      (void (*)(void *))queue_complete_cb, req);
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	list_add_tail(&req->list, &fi->req_pending);
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-	/* Update the generation of the packet just before sending. */
-	packet->generation = req->req.generation;
-
-	if (hpsb_send_packet(packet) < 0) {
-		req->req.error = RAW1394_ERROR_SEND_ERROR;
-		queue_complete_req(req);
-	}
-
-	return 0;
-}
-
-static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
-		    u64 addr, size_t length, u16 flags)
-{
-	unsigned long irqflags;
-	struct pending_request *req;
-	struct host_info *hi;
-	struct file_info *fi = NULL;
-	struct list_head *entry;
-	struct arm_addr *arm_addr = NULL;
-	struct arm_request *arm_req = NULL;
-	struct arm_response *arm_resp = NULL;
-	int found = 0, size = 0, rcode = -1;
-	struct arm_request_response *arm_req_resp = NULL;
-
-	DBGMSG("arm_read  called by node: %X "
-	       "addr: %4.4x %8.8x length: %Zu", nodeid,
-	       (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-	       length);
-	spin_lock_irqsave(&host_info_lock, irqflags);
-	hi = find_host_info(host);	/* search address-entry */
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			entry = fi->addr_list.next;
-			while (entry != &(fi->addr_list)) {
-				arm_addr =
-				    list_entry(entry, struct arm_addr,
-					       addr_list);
-				if (((arm_addr->start) <= (addr))
-				    && ((arm_addr->end) >= (addr + length))) {
-					found = 1;
-					break;
-				}
-				entry = entry->next;
-			}
-			if (found) {
-				break;
-			}
-		}
-	}
-	rcode = -1;
-	if (!found) {
-		printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
-		       " -> rcode_address_error\n");
-		spin_unlock_irqrestore(&host_info_lock, irqflags);
-		return (RCODE_ADDRESS_ERROR);
-	} else {
-		DBGMSG("arm_read addr_entry FOUND");
-	}
-	if (arm_addr->rec_length < length) {
-		DBGMSG("arm_read blocklength too big -> rcode_data_error");
-		rcode = RCODE_DATA_ERROR;	/* hardware error, data is unavailable */
-	}
-	if (rcode == -1) {
-		if (arm_addr->access_rights & ARM_READ) {
-			if (!(arm_addr->client_transactions & ARM_READ)) {
-				memcpy(buffer,
-				       (arm_addr->addr_space_buffer) + (addr -
-									(arm_addr->
-									 start)),
-				       length);
-				DBGMSG("arm_read -> (rcode_complete)");
-				rcode = RCODE_COMPLETE;
-			}
-		} else {
-			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-			DBGMSG("arm_read -> rcode_type_error (access denied)");
-		}
-	}
-	if (arm_addr->notification_options & ARM_READ) {
-		DBGMSG("arm_read -> entering notification-section");
-		req = __alloc_pending_request(GFP_ATOMIC);
-		if (!req) {
-			DBGMSG("arm_read -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		if (rcode == RCODE_COMPLETE) {
-			size =
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response) +
-			    length * sizeof(byte_t) +
-			    sizeof(struct arm_request_response);
-		} else {
-			size =
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response) +
-			    sizeof(struct arm_request_response);
-		}
-		req->data = kmalloc(size, GFP_ATOMIC);
-		if (!(req->data)) {
-			free_pending_request(req);
-			DBGMSG("arm_read -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		req->free_data = 1;
-		req->file_info = fi;
-		req->req.type = RAW1394_REQ_ARM;
-		req->req.generation = get_hpsb_generation(host);
-		req->req.misc =
-		    (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
-		req->req.tag = arm_addr->arm_tag;
-		req->req.recvb = arm_addr->recvb;
-		req->req.length = size;
-		arm_req_resp = (struct arm_request_response *)(req->data);
-		arm_req = (struct arm_request *)((byte_t *) (req->data) +
-						 (sizeof
-						  (struct
-						   arm_request_response)));
-		arm_resp =
-		    (struct arm_response *)((byte_t *) (arm_req) +
-					    (sizeof(struct arm_request)));
-		arm_req->buffer = NULL;
-		arm_resp->buffer = NULL;
-		if (rcode == RCODE_COMPLETE) {
-			byte_t *buf =
-			    (byte_t *) arm_resp + sizeof(struct arm_response);
-			memcpy(buf,
-			       (arm_addr->addr_space_buffer) + (addr -
-								(arm_addr->
-								 start)),
-			       length);
-			arm_resp->buffer =
-			    int2ptr((arm_addr->recvb) +
-				    sizeof(struct arm_request_response) +
-				    sizeof(struct arm_request) +
-				    sizeof(struct arm_response));
-		}
-		arm_resp->buffer_length =
-		    (rcode == RCODE_COMPLETE) ? length : 0;
-		arm_resp->response_code = rcode;
-		arm_req->buffer_length = 0;
-		arm_req->generation = req->req.generation;
-		arm_req->extended_transaction_code = 0;
-		arm_req->destination_offset = addr;
-		arm_req->source_nodeid = nodeid;
-		arm_req->destination_nodeid = host->node_id;
-		arm_req->tlabel = (flags >> 10) & 0x3f;
-		arm_req->tcode = (flags >> 4) & 0x0f;
-		arm_req_resp->request = int2ptr((arm_addr->recvb) +
-						sizeof(struct
-						       arm_request_response));
-		arm_req_resp->response =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request));
-		queue_complete_req(req);
-	}
-	spin_unlock_irqrestore(&host_info_lock, irqflags);
-	return (rcode);
-}
-
-static int arm_write(struct hpsb_host *host, int nodeid, int destid,
-		     quadlet_t * data, u64 addr, size_t length, u16 flags)
-{
-	unsigned long irqflags;
-	struct pending_request *req;
-	struct host_info *hi;
-	struct file_info *fi = NULL;
-	struct list_head *entry;
-	struct arm_addr *arm_addr = NULL;
-	struct arm_request *arm_req = NULL;
-	struct arm_response *arm_resp = NULL;
-	int found = 0, size = 0, rcode = -1;
-	struct arm_request_response *arm_req_resp = NULL;
-
-	DBGMSG("arm_write called by node: %X "
-	       "addr: %4.4x %8.8x length: %Zu", nodeid,
-	       (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
-	       length);
-	spin_lock_irqsave(&host_info_lock, irqflags);
-	hi = find_host_info(host);	/* search address-entry */
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			entry = fi->addr_list.next;
-			while (entry != &(fi->addr_list)) {
-				arm_addr =
-				    list_entry(entry, struct arm_addr,
-					       addr_list);
-				if (((arm_addr->start) <= (addr))
-				    && ((arm_addr->end) >= (addr + length))) {
-					found = 1;
-					break;
-				}
-				entry = entry->next;
-			}
-			if (found) {
-				break;
-			}
-		}
-	}
-	rcode = -1;
-	if (!found) {
-		printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
-		       " -> rcode_address_error\n");
-		spin_unlock_irqrestore(&host_info_lock, irqflags);
-		return (RCODE_ADDRESS_ERROR);
-	} else {
-		DBGMSG("arm_write addr_entry FOUND");
-	}
-	if (arm_addr->rec_length < length) {
-		DBGMSG("arm_write blocklength too big -> rcode_data_error");
-		rcode = RCODE_DATA_ERROR;	/* hardware error, data is unavailable */
-	}
-	if (rcode == -1) {
-		if (arm_addr->access_rights & ARM_WRITE) {
-			if (!(arm_addr->client_transactions & ARM_WRITE)) {
-				memcpy((arm_addr->addr_space_buffer) +
-				       (addr - (arm_addr->start)), data,
-				       length);
-				DBGMSG("arm_write -> (rcode_complete)");
-				rcode = RCODE_COMPLETE;
-			}
-		} else {
-			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-			DBGMSG("arm_write -> rcode_type_error (access denied)");
-		}
-	}
-	if (arm_addr->notification_options & ARM_WRITE) {
-		DBGMSG("arm_write -> entering notification-section");
-		req = __alloc_pending_request(GFP_ATOMIC);
-		if (!req) {
-			DBGMSG("arm_write -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request my be retried */
-		}
-		size =
-		    sizeof(struct arm_request) + sizeof(struct arm_response) +
-		    (length) * sizeof(byte_t) +
-		    sizeof(struct arm_request_response);
-		req->data = kmalloc(size, GFP_ATOMIC);
-		if (!(req->data)) {
-			free_pending_request(req);
-			DBGMSG("arm_write -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		req->free_data = 1;
-		req->file_info = fi;
-		req->req.type = RAW1394_REQ_ARM;
-		req->req.generation = get_hpsb_generation(host);
-		req->req.misc =
-		    (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
-		req->req.tag = arm_addr->arm_tag;
-		req->req.recvb = arm_addr->recvb;
-		req->req.length = size;
-		arm_req_resp = (struct arm_request_response *)(req->data);
-		arm_req = (struct arm_request *)((byte_t *) (req->data) +
-						 (sizeof
-						  (struct
-						   arm_request_response)));
-		arm_resp =
-		    (struct arm_response *)((byte_t *) (arm_req) +
-					    (sizeof(struct arm_request)));
-		arm_resp->buffer = NULL;
-		memcpy((byte_t *) arm_resp + sizeof(struct arm_response),
-		       data, length);
-		arm_req->buffer = int2ptr((arm_addr->recvb) +
-					  sizeof(struct arm_request_response) +
-					  sizeof(struct arm_request) +
-					  sizeof(struct arm_response));
-		arm_req->buffer_length = length;
-		arm_req->generation = req->req.generation;
-		arm_req->extended_transaction_code = 0;
-		arm_req->destination_offset = addr;
-		arm_req->source_nodeid = nodeid;
-		arm_req->destination_nodeid = destid;
-		arm_req->tlabel = (flags >> 10) & 0x3f;
-		arm_req->tcode = (flags >> 4) & 0x0f;
-		arm_resp->buffer_length = 0;
-		arm_resp->response_code = rcode;
-		arm_req_resp->request = int2ptr((arm_addr->recvb) +
-						sizeof(struct
-						       arm_request_response));
-		arm_req_resp->response =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request));
-		queue_complete_req(req);
-	}
-	spin_unlock_irqrestore(&host_info_lock, irqflags);
-	return (rcode);
-}
-
-static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
-		    u16 flags)
-{
-	unsigned long irqflags;
-	struct pending_request *req;
-	struct host_info *hi;
-	struct file_info *fi = NULL;
-	struct list_head *entry;
-	struct arm_addr *arm_addr = NULL;
-	struct arm_request *arm_req = NULL;
-	struct arm_response *arm_resp = NULL;
-	int found = 0, size = 0, rcode = -1;
-	quadlet_t old, new;
-	struct arm_request_response *arm_req_resp = NULL;
-
-	if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-	    ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-		DBGMSG("arm_lock  called by node: %X "
-		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X",
-		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
-		       (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
-		       be32_to_cpu(data));
-	} else {
-		DBGMSG("arm_lock  called by node: %X "
-		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X",
-		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
-		       (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF,
-		       be32_to_cpu(data), be32_to_cpu(arg));
-	}
-	spin_lock_irqsave(&host_info_lock, irqflags);
-	hi = find_host_info(host);	/* search address-entry */
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			entry = fi->addr_list.next;
-			while (entry != &(fi->addr_list)) {
-				arm_addr =
-				    list_entry(entry, struct arm_addr,
-					       addr_list);
-				if (((arm_addr->start) <= (addr))
-				    && ((arm_addr->end) >=
-					(addr + sizeof(*store)))) {
-					found = 1;
-					break;
-				}
-				entry = entry->next;
-			}
-			if (found) {
-				break;
-			}
-		}
-	}
-	rcode = -1;
-	if (!found) {
-		printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
-		       " -> rcode_address_error\n");
-		spin_unlock_irqrestore(&host_info_lock, irqflags);
-		return (RCODE_ADDRESS_ERROR);
-	} else {
-		DBGMSG("arm_lock addr_entry FOUND");
-	}
-	if (rcode == -1) {
-		if (arm_addr->access_rights & ARM_LOCK) {
-			if (!(arm_addr->client_transactions & ARM_LOCK)) {
-				memcpy(&old,
-				       (arm_addr->addr_space_buffer) + (addr -
-									(arm_addr->
-									 start)),
-				       sizeof(old));
-				switch (ext_tcode) {
-				case (EXTCODE_MASK_SWAP):
-					new = data | (old & ~arg);
-					break;
-				case (EXTCODE_COMPARE_SWAP):
-					if (old == arg) {
-						new = data;
-					} else {
-						new = old;
-					}
-					break;
-				case (EXTCODE_FETCH_ADD):
-					new =
-					    cpu_to_be32(be32_to_cpu(data) +
-							be32_to_cpu(old));
-					break;
-				case (EXTCODE_LITTLE_ADD):
-					new =
-					    cpu_to_le32(le32_to_cpu(data) +
-							le32_to_cpu(old));
-					break;
-				case (EXTCODE_BOUNDED_ADD):
-					if (old != arg) {
-						new =
-						    cpu_to_be32(be32_to_cpu
-								(data) +
-								be32_to_cpu
-								(old));
-					} else {
-						new = old;
-					}
-					break;
-				case (EXTCODE_WRAP_ADD):
-					if (old != arg) {
-						new =
-						    cpu_to_be32(be32_to_cpu
-								(data) +
-								be32_to_cpu
-								(old));
-					} else {
-						new = data;
-					}
-					break;
-				default:
-					rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-					printk(KERN_ERR
-					       "raw1394: arm_lock FAILED "
-					       "ext_tcode not allowed -> rcode_type_error\n");
-					break;
-				}	/*switch */
-				if (rcode == -1) {
-					DBGMSG("arm_lock -> (rcode_complete)");
-					rcode = RCODE_COMPLETE;
-					memcpy(store, &old, sizeof(*store));
-					memcpy((arm_addr->addr_space_buffer) +
-					       (addr - (arm_addr->start)),
-					       &new, sizeof(*store));
-				}
-			}
-		} else {
-			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-			DBGMSG("arm_lock -> rcode_type_error (access denied)");
-		}
-	}
-	if (arm_addr->notification_options & ARM_LOCK) {
-		byte_t *buf1, *buf2;
-		DBGMSG("arm_lock -> entering notification-section");
-		req = __alloc_pending_request(GFP_ATOMIC);
-		if (!req) {
-			DBGMSG("arm_lock -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);	/* maximum */
-		req->data = kmalloc(size, GFP_ATOMIC);
-		if (!(req->data)) {
-			free_pending_request(req);
-			DBGMSG("arm_lock -> rcode_conflict_error");
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		req->free_data = 1;
-		arm_req_resp = (struct arm_request_response *)(req->data);
-		arm_req = (struct arm_request *)((byte_t *) (req->data) +
-						 (sizeof
-						  (struct
-						   arm_request_response)));
-		arm_resp =
-		    (struct arm_response *)((byte_t *) (arm_req) +
-					    (sizeof(struct arm_request)));
-		buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
-		buf2 = buf1 + 2 * sizeof(*store);
-		if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-		    (ext_tcode == EXTCODE_LITTLE_ADD)) {
-			arm_req->buffer_length = sizeof(*store);
-			memcpy(buf1, &data, sizeof(*store));
-
-		} else {
-			arm_req->buffer_length = 2 * sizeof(*store);
-			memcpy(buf1, &arg, sizeof(*store));
-			memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
-		}
-		if (rcode == RCODE_COMPLETE) {
-			arm_resp->buffer_length = sizeof(*store);
-			memcpy(buf2, &old, sizeof(*store));
-		} else {
-			arm_resp->buffer_length = 0;
-		}
-		req->file_info = fi;
-		req->req.type = RAW1394_REQ_ARM;
-		req->req.generation = get_hpsb_generation(host);
-		req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
-				 (ARM_LOCK & 0xFF));
-		req->req.tag = arm_addr->arm_tag;
-		req->req.recvb = arm_addr->recvb;
-		req->req.length = size;
-		arm_req->generation = req->req.generation;
-		arm_req->extended_transaction_code = ext_tcode;
-		arm_req->destination_offset = addr;
-		arm_req->source_nodeid = nodeid;
-		arm_req->destination_nodeid = host->node_id;
-		arm_req->tlabel = (flags >> 10) & 0x3f;
-		arm_req->tcode = (flags >> 4) & 0x0f;
-		arm_resp->response_code = rcode;
-		arm_req_resp->request = int2ptr((arm_addr->recvb) +
-						sizeof(struct
-						       arm_request_response));
-		arm_req_resp->response =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request));
-		arm_req->buffer =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response));
-		arm_resp->buffer =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response) + 2 * sizeof(*store));
-		queue_complete_req(req);
-	}
-	spin_unlock_irqrestore(&host_info_lock, irqflags);
-	return (rcode);
-}
-
-static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
-		      u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
-		      u16 flags)
-{
-	unsigned long irqflags;
-	struct pending_request *req;
-	struct host_info *hi;
-	struct file_info *fi = NULL;
-	struct list_head *entry;
-	struct arm_addr *arm_addr = NULL;
-	struct arm_request *arm_req = NULL;
-	struct arm_response *arm_resp = NULL;
-	int found = 0, size = 0, rcode = -1;
-	octlet_t old, new;
-	struct arm_request_response *arm_req_resp = NULL;
-
-	if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
-	    ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
-		DBGMSG("arm_lock64 called by node: %X "
-		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
-		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
-		       (u32) (addr & 0xFFFFFFFF),
-		       ext_tcode & 0xFF,
-		       (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-		       (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
-	} else {
-		DBGMSG("arm_lock64 called by node: %X "
-		       "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
-		       "%8.8X %8.8X ",
-		       nodeid, (u16) ((addr >> 32) & 0xFFFF),
-		       (u32) (addr & 0xFFFFFFFF),
-		       ext_tcode & 0xFF,
-		       (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF),
-		       (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
-		       (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF),
-		       (u32) (be64_to_cpu(arg) & 0xFFFFFFFF));
-	}
-	spin_lock_irqsave(&host_info_lock, irqflags);
-	hi = find_host_info(host);	/* search addressentry in file_info's for host */
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			entry = fi->addr_list.next;
-			while (entry != &(fi->addr_list)) {
-				arm_addr =
-				    list_entry(entry, struct arm_addr,
-					       addr_list);
-				if (((arm_addr->start) <= (addr))
-				    && ((arm_addr->end) >=
-					(addr + sizeof(*store)))) {
-					found = 1;
-					break;
-				}
-				entry = entry->next;
-			}
-			if (found) {
-				break;
-			}
-		}
-	}
-	rcode = -1;
-	if (!found) {
-		printk(KERN_ERR
-		       "raw1394: arm_lock64 FAILED addr_entry not found"
-		       " -> rcode_address_error\n");
-		spin_unlock_irqrestore(&host_info_lock, irqflags);
-		return (RCODE_ADDRESS_ERROR);
-	} else {
-		DBGMSG("arm_lock64 addr_entry FOUND");
-	}
-	if (rcode == -1) {
-		if (arm_addr->access_rights & ARM_LOCK) {
-			if (!(arm_addr->client_transactions & ARM_LOCK)) {
-				memcpy(&old,
-				       (arm_addr->addr_space_buffer) + (addr -
-									(arm_addr->
-									 start)),
-				       sizeof(old));
-				switch (ext_tcode) {
-				case (EXTCODE_MASK_SWAP):
-					new = data | (old & ~arg);
-					break;
-				case (EXTCODE_COMPARE_SWAP):
-					if (old == arg) {
-						new = data;
-					} else {
-						new = old;
-					}
-					break;
-				case (EXTCODE_FETCH_ADD):
-					new =
-					    cpu_to_be64(be64_to_cpu(data) +
-							be64_to_cpu(old));
-					break;
-				case (EXTCODE_LITTLE_ADD):
-					new =
-					    cpu_to_le64(le64_to_cpu(data) +
-							le64_to_cpu(old));
-					break;
-				case (EXTCODE_BOUNDED_ADD):
-					if (old != arg) {
-						new =
-						    cpu_to_be64(be64_to_cpu
-								(data) +
-								be64_to_cpu
-								(old));
-					} else {
-						new = old;
-					}
-					break;
-				case (EXTCODE_WRAP_ADD):
-					if (old != arg) {
-						new =
-						    cpu_to_be64(be64_to_cpu
-								(data) +
-								be64_to_cpu
-								(old));
-					} else {
-						new = data;
-					}
-					break;
-				default:
-					printk(KERN_ERR
-					       "raw1394: arm_lock64 FAILED "
-					       "ext_tcode not allowed -> rcode_type_error\n");
-					rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-					break;
-				}	/*switch */
-				if (rcode == -1) {
-					DBGMSG
-					    ("arm_lock64 -> (rcode_complete)");
-					rcode = RCODE_COMPLETE;
-					memcpy(store, &old, sizeof(*store));
-					memcpy((arm_addr->addr_space_buffer) +
-					       (addr - (arm_addr->start)),
-					       &new, sizeof(*store));
-				}
-			}
-		} else {
-			rcode = RCODE_TYPE_ERROR;	/* function not allowed */
-			DBGMSG
-			    ("arm_lock64 -> rcode_type_error (access denied)");
-		}
-	}
-	if (arm_addr->notification_options & ARM_LOCK) {
-		byte_t *buf1, *buf2;
-		DBGMSG("arm_lock64 -> entering notification-section");
-		req = __alloc_pending_request(GFP_ATOMIC);
-		if (!req) {
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			DBGMSG("arm_lock64 -> rcode_conflict_error");
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response);	/* maximum */
-		req->data = kmalloc(size, GFP_ATOMIC);
-		if (!(req->data)) {
-			free_pending_request(req);
-			spin_unlock_irqrestore(&host_info_lock, irqflags);
-			DBGMSG("arm_lock64 -> rcode_conflict_error");
-			return (RCODE_CONFLICT_ERROR);	/* A resource conflict was detected.
-							   The request may be retried */
-		}
-		req->free_data = 1;
-		arm_req_resp = (struct arm_request_response *)(req->data);
-		arm_req = (struct arm_request *)((byte_t *) (req->data) +
-						 (sizeof
-						  (struct
-						   arm_request_response)));
-		arm_resp =
-		    (struct arm_response *)((byte_t *) (arm_req) +
-					    (sizeof(struct arm_request)));
-		buf1 = (byte_t *) arm_resp + sizeof(struct arm_response);
-		buf2 = buf1 + 2 * sizeof(*store);
-		if ((ext_tcode == EXTCODE_FETCH_ADD) ||
-		    (ext_tcode == EXTCODE_LITTLE_ADD)) {
-			arm_req->buffer_length = sizeof(*store);
-			memcpy(buf1, &data, sizeof(*store));
-
-		} else {
-			arm_req->buffer_length = 2 * sizeof(*store);
-			memcpy(buf1, &arg, sizeof(*store));
-			memcpy(buf1 + sizeof(*store), &data, sizeof(*store));
-		}
-		if (rcode == RCODE_COMPLETE) {
-			arm_resp->buffer_length = sizeof(*store);
-			memcpy(buf2, &old, sizeof(*store));
-		} else {
-			arm_resp->buffer_length = 0;
-		}
-		req->file_info = fi;
-		req->req.type = RAW1394_REQ_ARM;
-		req->req.generation = get_hpsb_generation(host);
-		req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) |
-				 (ARM_LOCK & 0xFF));
-		req->req.tag = arm_addr->arm_tag;
-		req->req.recvb = arm_addr->recvb;
-		req->req.length = size;
-		arm_req->generation = req->req.generation;
-		arm_req->extended_transaction_code = ext_tcode;
-		arm_req->destination_offset = addr;
-		arm_req->source_nodeid = nodeid;
-		arm_req->destination_nodeid = host->node_id;
-		arm_req->tlabel = (flags >> 10) & 0x3f;
-		arm_req->tcode = (flags >> 4) & 0x0f;
-		arm_resp->response_code = rcode;
-		arm_req_resp->request = int2ptr((arm_addr->recvb) +
-						sizeof(struct
-						       arm_request_response));
-		arm_req_resp->response =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request));
-		arm_req->buffer =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response));
-		arm_resp->buffer =
-		    int2ptr((arm_addr->recvb) +
-			    sizeof(struct arm_request_response) +
-			    sizeof(struct arm_request) +
-			    sizeof(struct arm_response) + 2 * sizeof(*store));
-		queue_complete_req(req);
-	}
-	spin_unlock_irqrestore(&host_info_lock, irqflags);
-	return (rcode);
-}
-
-static int arm_register(struct file_info *fi, struct pending_request *req)
-{
-	int retval;
-	struct arm_addr *addr;
-	struct host_info *hi;
-	struct file_info *fi_hlp = NULL;
-	struct list_head *entry;
-	struct arm_addr *arm_addr = NULL;
-	int same_host, another_host;
-	unsigned long flags;
-
-	DBGMSG("arm_register called "
-	       "addr(Offset): %8.8x %8.8x length: %u "
-	       "rights: %2.2X notify: %2.2X "
-	       "max_blk_len: %4.4X",
-	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF),
-	       req->req.length, ((req->req.misc >> 8) & 0xFF),
-	       (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF));
-	/* check addressrange */
-	if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) ||
-	    (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) !=
-	     0)) {
-		req->req.length = 0;
-		return (-EINVAL);
-	}
-	/* addr-list-entry for fileinfo */
-	addr = kmalloc(sizeof(*addr), GFP_KERNEL);
-	if (!addr) {
-		req->req.length = 0;
-		return (-ENOMEM);
-	}
-	/* allocation of addr_space_buffer */
-	addr->addr_space_buffer = vmalloc(req->req.length);
-	if (!(addr->addr_space_buffer)) {
-		kfree(addr);
-		req->req.length = 0;
-		return (-ENOMEM);
-	}
-	/* initialization of addr_space_buffer */
-	if ((req->req.sendb) == (unsigned long)NULL) {
-		/* init: set 0 */
-		memset(addr->addr_space_buffer, 0, req->req.length);
-	} else {
-		/* init: user -> kernel */
-		if (copy_from_user
-		    (addr->addr_space_buffer, int2ptr(req->req.sendb),
-		     req->req.length)) {
-			vfree(addr->addr_space_buffer);
-			kfree(addr);
-			return (-EFAULT);
-		}
-	}
-	INIT_LIST_HEAD(&addr->addr_list);
-	addr->arm_tag = req->req.tag;
-	addr->start = req->req.address;
-	addr->end = req->req.address + req->req.length;
-	addr->access_rights = (u8) (req->req.misc & 0x0F);
-	addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
-	addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
-	addr->access_rights |= addr->client_transactions;
-	addr->notification_options |= addr->client_transactions;
-	addr->recvb = req->req.recvb;
-	addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	hi = find_host_info(fi->host);
-	same_host = 0;
-	another_host = 0;
-	/* same host with address-entry containing same addressrange ? */
-	list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-		entry = fi_hlp->addr_list.next;
-		while (entry != &(fi_hlp->addr_list)) {
-			arm_addr =
-			    list_entry(entry, struct arm_addr, addr_list);
-			if ((arm_addr->start == addr->start)
-			    && (arm_addr->end == addr->end)) {
-				DBGMSG("same host ownes same "
-				       "addressrange -> EALREADY");
-				same_host = 1;
-				break;
-			}
-			entry = entry->next;
-		}
-		if (same_host) {
-			break;
-		}
-	}
-	if (same_host) {
-		/* addressrange occupied by same host */
-		spin_unlock_irqrestore(&host_info_lock, flags);
-		vfree(addr->addr_space_buffer);
-		kfree(addr);
-		return (-EALREADY);
-	}
-	/* another host with valid address-entry containing same addressrange */
-	list_for_each_entry(hi, &host_info_list, list) {
-		if (hi->host != fi->host) {
-			list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-				entry = fi_hlp->addr_list.next;
-				while (entry != &(fi_hlp->addr_list)) {
-					arm_addr =
-					    list_entry(entry, struct arm_addr,
-						       addr_list);
-					if ((arm_addr->start == addr->start)
-					    && (arm_addr->end == addr->end)) {
-						DBGMSG
-						    ("another host ownes same "
-						     "addressrange");
-						another_host = 1;
-						break;
-					}
-					entry = entry->next;
-				}
-				if (another_host) {
-					break;
-				}
-			}
-		}
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-
-	if (another_host) {
-		DBGMSG("another hosts entry is valid -> SUCCESS");
-		if (copy_to_user(int2ptr(req->req.recvb),
-				 &addr->start, sizeof(u64))) {
-			printk(KERN_ERR "raw1394: arm_register failed "
-			       " address-range-entry is invalid -> EFAULT !!!\n");
-			vfree(addr->addr_space_buffer);
-			kfree(addr);
-			return (-EFAULT);
-		}
-		free_pending_request(req);	/* immediate success or fail */
-		/* INSERT ENTRY */
-		spin_lock_irqsave(&host_info_lock, flags);
-		list_add_tail(&addr->addr_list, &fi->addr_list);
-		spin_unlock_irqrestore(&host_info_lock, flags);
-		return 0;
-	}
-	retval =
-	    hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops,
-				    req->req.address,
-				    req->req.address + req->req.length);
-	if (retval) {
-		/* INSERT ENTRY */
-		spin_lock_irqsave(&host_info_lock, flags);
-		list_add_tail(&addr->addr_list, &fi->addr_list);
-		spin_unlock_irqrestore(&host_info_lock, flags);
-	} else {
-		DBGMSG("arm_register failed errno: %d \n", retval);
-		vfree(addr->addr_space_buffer);
-		kfree(addr);
-		return (-EALREADY);
-	}
-	free_pending_request(req);	/* immediate success or fail */
-	return 0;
-}
-
-static int arm_unregister(struct file_info *fi, struct pending_request *req)
-{
-	int found = 0;
-	int retval = 0;
-	struct list_head *entry;
-	struct arm_addr *addr = NULL;
-	struct host_info *hi;
-	struct file_info *fi_hlp = NULL;
-	struct arm_addr *arm_addr = NULL;
-	int another_host;
-	unsigned long flags;
-
-	DBGMSG("arm_Unregister called addr(Offset): "
-	       "%8.8x %8.8x",
-	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF));
-	spin_lock_irqsave(&host_info_lock, flags);
-	/* get addr */
-	entry = fi->addr_list.next;
-	while (entry != &(fi->addr_list)) {
-		addr = list_entry(entry, struct arm_addr, addr_list);
-		if (addr->start == req->req.address) {
-			found = 1;
-			break;
-		}
-		entry = entry->next;
-	}
-	if (!found) {
-		DBGMSG("arm_Unregister addr not found");
-		spin_unlock_irqrestore(&host_info_lock, flags);
-		return (-EINVAL);
-	}
-	DBGMSG("arm_Unregister addr found");
-	another_host = 0;
-	/* another host with valid address-entry containing
-	   same addressrange */
-	list_for_each_entry(hi, &host_info_list, list) {
-		if (hi->host != fi->host) {
-			list_for_each_entry(fi_hlp, &hi->file_info_list, list) {
-				entry = fi_hlp->addr_list.next;
-				while (entry != &(fi_hlp->addr_list)) {
-					arm_addr = list_entry(entry,
-							      struct arm_addr,
-							      addr_list);
-					if (arm_addr->start == addr->start) {
-						DBGMSG("another host ownes "
-						       "same addressrange");
-						another_host = 1;
-						break;
-					}
-					entry = entry->next;
-				}
-				if (another_host) {
-					break;
-				}
-			}
-		}
-	}
-	if (another_host) {
-		DBGMSG("delete entry from list -> success");
-		list_del(&addr->addr_list);
-		spin_unlock_irqrestore(&host_info_lock, flags);
-		vfree(addr->addr_space_buffer);
-		kfree(addr);
-		free_pending_request(req);	/* immediate success or fail */
-		return 0;
-	}
-	retval =
-	    hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
-				      addr->start);
-	if (!retval) {
-		printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
-		spin_unlock_irqrestore(&host_info_lock, flags);
-		return (-EINVAL);
-	}
-	DBGMSG("delete entry from list -> success");
-	list_del(&addr->addr_list);
-	spin_unlock_irqrestore(&host_info_lock, flags);
-	vfree(addr->addr_space_buffer);
-	kfree(addr);
-	free_pending_request(req);	/* immediate success or fail */
-	return 0;
-}
-
-/* Copy data from ARM buffer(s) to user buffer. */
-static int arm_get_buf(struct file_info *fi, struct pending_request *req)
-{
-	struct arm_addr *arm_addr = NULL;
-	unsigned long flags;
-	unsigned long offset;
-
-	struct list_head *entry;
-
-	DBGMSG("arm_get_buf "
-	       "addr(Offset): %04X %08X length: %u",
-	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	entry = fi->addr_list.next;
-	while (entry != &(fi->addr_list)) {
-		arm_addr = list_entry(entry, struct arm_addr, addr_list);
-		if ((arm_addr->start <= req->req.address) &&
-		    (arm_addr->end > req->req.address)) {
-			if (req->req.address + req->req.length <= arm_addr->end) {
-				offset = req->req.address - arm_addr->start;
-				spin_unlock_irqrestore(&host_info_lock, flags);
-
-				DBGMSG
-				    ("arm_get_buf copy_to_user( %08X, %p, %u )",
-				     (u32) req->req.recvb,
-				     arm_addr->addr_space_buffer + offset,
-				     (u32) req->req.length);
-				if (copy_to_user
-				    (int2ptr(req->req.recvb),
-				     arm_addr->addr_space_buffer + offset,
-				     req->req.length))
-					return (-EFAULT);
-
-				/* We have to free the request, because we
-				 * queue no response, and therefore nobody
-				 * will free it. */
-				free_pending_request(req);
-				return 0;
-			} else {
-				DBGMSG("arm_get_buf request exceeded mapping");
-				spin_unlock_irqrestore(&host_info_lock, flags);
-				return (-EINVAL);
-			}
-		}
-		entry = entry->next;
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-	return (-EINVAL);
-}
-
-/* Copy data from user buffer to ARM buffer(s). */
-static int arm_set_buf(struct file_info *fi, struct pending_request *req)
-{
-	struct arm_addr *arm_addr = NULL;
-	unsigned long flags;
-	unsigned long offset;
-
-	struct list_head *entry;
-
-	DBGMSG("arm_set_buf "
-	       "addr(Offset): %04X %08X length: %u",
-	       (u32) ((req->req.address >> 32) & 0xFFFF),
-	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	entry = fi->addr_list.next;
-	while (entry != &(fi->addr_list)) {
-		arm_addr = list_entry(entry, struct arm_addr, addr_list);
-		if ((arm_addr->start <= req->req.address) &&
-		    (arm_addr->end > req->req.address)) {
-			if (req->req.address + req->req.length <= arm_addr->end) {
-				offset = req->req.address - arm_addr->start;
-				spin_unlock_irqrestore(&host_info_lock, flags);
-
-				DBGMSG
-				    ("arm_set_buf copy_from_user( %p, %08X, %u )",
-				     arm_addr->addr_space_buffer + offset,
-				     (u32) req->req.sendb,
-				     (u32) req->req.length);
-				if (copy_from_user
-				    (arm_addr->addr_space_buffer + offset,
-				     int2ptr(req->req.sendb),
-				     req->req.length))
-					return (-EFAULT);
-
-				/* We have to free the request, because we
-				 * queue no response, and therefore nobody
-				 * will free it. */
-				free_pending_request(req);
-				return 0;
-			} else {
-				DBGMSG("arm_set_buf request exceeded mapping");
-				spin_unlock_irqrestore(&host_info_lock, flags);
-				return (-EINVAL);
-			}
-		}
-		entry = entry->next;
-	}
-	spin_unlock_irqrestore(&host_info_lock, flags);
-	return (-EINVAL);
-}
-
-static int reset_notification(struct file_info *fi, struct pending_request *req)
-{
-	DBGMSG("reset_notification called - switch %s ",
-	       (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
-	if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
-	    (req->req.misc == RAW1394_NOTIFY_ON)) {
-		fi->notification = (u8) req->req.misc;
-		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
-		return 0;
-	}
-	/* error EINVAL (22) invalid argument */
-	return (-EINVAL);
-}
-
-static int write_phypacket(struct file_info *fi, struct pending_request *req)
-{
-	struct hpsb_packet *packet = NULL;
-	int retval = 0;
-	quadlet_t data;
-	unsigned long flags;
-
-	data = be32_to_cpu((u32) req->req.sendb);
-	DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
-	packet = hpsb_make_phypacket(fi->host, data);
-	if (!packet)
-		return -ENOMEM;
-	req->req.length = 0;
-	req->packet = packet;
-	hpsb_set_packet_complete_task(packet,
-				      (void (*)(void *))queue_complete_cb, req);
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	list_add_tail(&req->list, &fi->req_pending);
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-	packet->generation = req->req.generation;
-	retval = hpsb_send_packet(packet);
-	DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
-	if (retval < 0) {
-		req->req.error = RAW1394_ERROR_SEND_ERROR;
-		req->req.length = 0;
-		queue_complete_req(req);
-	}
-	return 0;
-}
-
-static int get_config_rom(struct file_info *fi, struct pending_request *req)
-{
-	int ret = 0;
-	quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
-	int status;
-
-	if (!data)
-		return -ENOMEM;
-
-	status =
-	    csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
-			 data, req->req.length);
-	if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
-		ret = -EFAULT;
-	if (copy_to_user
-	    (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
-	     sizeof(fi->host->csr.rom->cache_head->len)))
-		ret = -EFAULT;
-	if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
-			 sizeof(fi->host->csr.generation)))
-		ret = -EFAULT;
-	if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
-		ret = -EFAULT;
-	kfree(data);
-	if (ret >= 0) {
-		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
-	}
-	return ret;
-}
-
-static int update_config_rom(struct file_info *fi, struct pending_request *req)
-{
-	int ret = 0;
-	quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-	if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
-		ret = -EFAULT;
-	} else {
-		int status = hpsb_update_config_rom(fi->host,
-						    data, req->req.length,
-						    (unsigned char)req->req.
-						    misc);
-		if (copy_to_user
-		    (int2ptr(req->req.recvb), &status, sizeof(status)))
-			ret = -ENOMEM;
-	}
-	kfree(data);
-	if (ret >= 0) {
-		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
-		fi->cfgrom_upd = 1;
-	}
-	return ret;
-}
-
-static int modify_config_rom(struct file_info *fi, struct pending_request *req)
-{
-	struct csr1212_keyval *kv;
-	struct csr1212_csr_rom_cache *cache;
-	struct csr1212_dentry *dentry;
-	u32 dr;
-	int ret = 0;
-
-	if (req->req.misc == ~0) {
-		if (req->req.length == 0)
-			return -EINVAL;
-
-		/* Find an unused slot */
-		for (dr = 0;
-		     dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
-		     dr++) ;
-
-		if (dr == RAW1394_MAX_USER_CSR_DIRS)
-			return -ENOMEM;
-
-		fi->csr1212_dirs[dr] =
-		    csr1212_new_directory(CSR1212_KV_ID_VENDOR);
-		if (!fi->csr1212_dirs[dr])
-			return -ENOMEM;
-	} else {
-		dr = req->req.misc;
-		if (!fi->csr1212_dirs[dr])
-			return -EINVAL;
-
-		/* Delete old stuff */
-		for (dentry =
-		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
-		     dentry; dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-							     root_kv,
-							     dentry->kv);
-		}
-
-		if (req->req.length == 0) {
-			csr1212_release_keyval(fi->csr1212_dirs[dr]);
-			fi->csr1212_dirs[dr] = NULL;
-
-			hpsb_update_config_rom_image(fi->host);
-			free_pending_request(req);
-			return 0;
-		}
-	}
-
-	cache = csr1212_rom_cache_malloc(0, req->req.length);
-	if (!cache) {
-		csr1212_release_keyval(fi->csr1212_dirs[dr]);
-		fi->csr1212_dirs[dr] = NULL;
-		return -ENOMEM;
-	}
-
-	cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL);
-	if (!cache->filled_head) {
-		csr1212_release_keyval(fi->csr1212_dirs[dr]);
-		fi->csr1212_dirs[dr] = NULL;
-		CSR1212_FREE(cache);
-		return -ENOMEM;
-	}
-	cache->filled_tail = cache->filled_head;
-
-	if (copy_from_user(cache->data, int2ptr(req->req.sendb),
-			   req->req.length)) {
-		csr1212_release_keyval(fi->csr1212_dirs[dr]);
-		fi->csr1212_dirs[dr] = NULL;
-		ret = -EFAULT;
-	} else {
-		cache->len = req->req.length;
-		cache->filled_head->offset_start = 0;
-		cache->filled_head->offset_end = cache->size - 1;
-
-		cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];
-
-		ret = CSR1212_SUCCESS;
-		/* parse all the items */
-		for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
-		     kv = kv->next) {
-			ret = csr1212_parse_keyval(kv, cache);
-		}
-
-		/* attach top level items to the root directory */
-		for (dentry =
-		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
-		     ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
-			ret =
-			    csr1212_attach_keyval_to_directory(fi->host->csr.
-							       rom->root_kv,
-							       dentry->kv);
-		}
-
-		if (ret == CSR1212_SUCCESS) {
-			ret = hpsb_update_config_rom_image(fi->host);
-
-			if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
-						     &dr, sizeof(dr))) {
-				ret = -ENOMEM;
-			}
-		}
-	}
-	kfree(cache->filled_head);
-	CSR1212_FREE(cache);
-
-	if (ret >= 0) {
-		/* we have to free the request, because we queue no response,
-		 * and therefore nobody will free it */
-		free_pending_request(req);
-		return 0;
-	} else {
-		for (dentry =
-		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
-		     dentry; dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-							     root_kv,
-							     dentry->kv);
-		}
-		csr1212_release_keyval(fi->csr1212_dirs[dr]);
-		fi->csr1212_dirs[dr] = NULL;
-		return ret;
-	}
-}
-
-static int state_connected(struct file_info *fi, struct pending_request *req)
-{
-	int node = req->req.address >> 48;
-
-	req->req.error = RAW1394_ERROR_NONE;
-
-	switch (req->req.type) {
-
-	case RAW1394_REQ_ECHO:
-		queue_complete_req(req);
-		return 0;
-
-	case RAW1394_REQ_ARM_REGISTER:
-		return arm_register(fi, req);
-
-	case RAW1394_REQ_ARM_UNREGISTER:
-		return arm_unregister(fi, req);
-
-	case RAW1394_REQ_ARM_SET_BUF:
-		return arm_set_buf(fi, req);
-
-	case RAW1394_REQ_ARM_GET_BUF:
-		return arm_get_buf(fi, req);
-
-	case RAW1394_REQ_RESET_NOTIFY:
-		return reset_notification(fi, req);
-
-	case RAW1394_REQ_ISO_SEND:
-	case RAW1394_REQ_ISO_LISTEN:
-		printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
-		req->req.error = RAW1394_ERROR_COMPAT;
-		req->req.misc = RAW1394_KERNELAPI_VERSION;
-		queue_complete_req(req);
-		return 0;
-
-	case RAW1394_REQ_FCP_LISTEN:
-		handle_fcp_listen(fi, req);
-		return 0;
-
-	case RAW1394_REQ_RESET_BUS:
-		if (req->req.misc == RAW1394_LONG_RESET) {
-			DBGMSG("busreset called (type: LONG)");
-			hpsb_reset_bus(fi->host, LONG_RESET);
-			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
-			return 0;
-		}
-		if (req->req.misc == RAW1394_SHORT_RESET) {
-			DBGMSG("busreset called (type: SHORT)");
-			hpsb_reset_bus(fi->host, SHORT_RESET);
-			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
-			return 0;
-		}
-		/* error EINVAL (22) invalid argument */
-		return (-EINVAL);
-	case RAW1394_REQ_GET_ROM:
-		return get_config_rom(fi, req);
-
-	case RAW1394_REQ_UPDATE_ROM:
-		return update_config_rom(fi, req);
-
-	case RAW1394_REQ_MODIFY_ROM:
-		return modify_config_rom(fi, req);
-	}
-
-	if (req->req.generation != get_hpsb_generation(fi->host)) {
-		req->req.error = RAW1394_ERROR_GENERATION;
-		req->req.generation = get_hpsb_generation(fi->host);
-		req->req.length = 0;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	switch (req->req.type) {
-	case RAW1394_REQ_PHYPACKET:
-		return write_phypacket(fi, req);
-	case RAW1394_REQ_ASYNC_SEND:
-		return handle_async_send(fi, req);
-	}
-
-	if (req->req.length == 0) {
-		req->req.error = RAW1394_ERROR_INVALID_ARG;
-		queue_complete_req(req);
-		return 0;
-	}
-
-	return handle_async_request(fi, req, node);
-}
-
-static ssize_t raw1394_write(struct file *file, const char __user * buffer,
-			     size_t count, loff_t * offset_is_ignored)
-{
-	struct file_info *fi = file->private_data;
-	struct pending_request *req;
-	ssize_t retval = -EBADFD;
-
-#ifdef CONFIG_COMPAT
-	if (count == sizeof(struct compat_raw1394_req) &&
-   	    sizeof(struct compat_raw1394_req) !=
-			sizeof(struct raw1394_request)) {
-		buffer = raw1394_compat_write(buffer);
-		if (IS_ERR((__force void *)buffer))
-			return PTR_ERR((__force void *)buffer);
-	} else
-#endif
-	if (count != sizeof(struct raw1394_request)) {
-		return -EINVAL;
-	}
-
-	req = alloc_pending_request();
-	if (req == NULL) {
-		return -ENOMEM;
-	}
-	req->file_info = fi;
-
-	if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) {
-		free_pending_request(req);
-		return -EFAULT;
-	}
-
-	if (!mutex_trylock(&fi->state_mutex)) {
-		free_pending_request(req);
-		return -EAGAIN;
-	}
-
-	switch (fi->state) {
-	case opened:
-		retval = state_opened(fi, req);
-		break;
-
-	case initialized:
-		retval = state_initialized(fi, req);
-		break;
-
-	case connected:
-		retval = state_connected(fi, req);
-		break;
-	}
-
-	mutex_unlock(&fi->state_mutex);
-
-	if (retval < 0) {
-		free_pending_request(req);
-	} else {
-		BUG_ON(retval);
-		retval = count;
-	}
-
-	return retval;
-}
-
-/* rawiso operations */
-
-/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the
- * completion queue (reqlists_lock must be taken) */
-static inline int __rawiso_event_in_queue(struct file_info *fi)
-{
-	struct pending_request *req;
-
-	list_for_each_entry(req, &fi->req_complete, list)
-	    if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY)
-		return 1;
-
-	return 0;
-}
-
-/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */
-static void queue_rawiso_event(struct file_info *fi)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-
-	/* only one ISO activity event may be in the queue */
-	if (!__rawiso_event_in_queue(fi)) {
-		struct pending_request *req =
-		    __alloc_pending_request(GFP_ATOMIC);
-
-		if (req) {
-			req->file_info = fi;
-			req->req.type = RAW1394_REQ_RAWISO_ACTIVITY;
-			req->req.generation = get_hpsb_generation(fi->host);
-			__queue_complete_req(req);
-		} else {
-			/* on allocation failure, signal an overflow */
-			if (fi->iso_handle) {
-				atomic_inc(&fi->iso_handle->overflows);
-			}
-		}
-	}
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-}
-
-static void rawiso_activity_cb(struct hpsb_iso *iso)
-{
-	unsigned long flags;
-	struct host_info *hi;
-	struct file_info *fi;
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	hi = find_host_info(iso->host);
-
-	if (hi != NULL) {
-		list_for_each_entry(fi, &hi->file_info_list, list) {
-			if (fi->iso_handle == iso)
-				queue_rawiso_event(fi);
-		}
-	}
-
-	spin_unlock_irqrestore(&host_info_lock, flags);
-}
-
-/* helper function - gather all the kernel iso status bits for returning to user-space */
-static void raw1394_iso_fill_status(struct hpsb_iso *iso,
-				    struct raw1394_iso_status *stat)
-{
-	int overflows = atomic_read(&iso->overflows);
-	int skips = atomic_read(&iso->skips);
-
-	stat->config.data_buf_size = iso->buf_size;
-	stat->config.buf_packets = iso->buf_packets;
-	stat->config.channel = iso->channel;
-	stat->config.speed = iso->speed;
-	stat->config.irq_interval = iso->irq_interval;
-	stat->n_packets = hpsb_iso_n_ready(iso);
-	stat->overflows = ((skips & 0xFFFF) << 16) | ((overflows & 0xFFFF));
-	stat->xmit_cycle = iso->xmit_cycle;
-}
-
-static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_iso_status stat;
-
-	if (!fi->host)
-		return -EINVAL;
-
-	if (copy_from_user(&stat, uaddr, sizeof(stat)))
-		return -EFAULT;
-
-	fi->iso_handle = hpsb_iso_xmit_init(fi->host,
-					    stat.config.data_buf_size,
-					    stat.config.buf_packets,
-					    stat.config.channel,
-					    stat.config.speed,
-					    stat.config.irq_interval,
-					    rawiso_activity_cb);
-	if (!fi->iso_handle)
-		return -ENOMEM;
-
-	fi->iso_state = RAW1394_ISO_XMIT;
-
-	raw1394_iso_fill_status(fi->iso_handle, &stat);
-	if (copy_to_user(uaddr, &stat, sizeof(stat)))
-		return -EFAULT;
-
-	/* queue an event to get things started */
-	rawiso_activity_cb(fi->iso_handle);
-
-	return 0;
-}
-
-static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_iso_status stat;
-
-	if (!fi->host)
-		return -EINVAL;
-
-	if (copy_from_user(&stat, uaddr, sizeof(stat)))
-		return -EFAULT;
-
-	fi->iso_handle = hpsb_iso_recv_init(fi->host,
-					    stat.config.data_buf_size,
-					    stat.config.buf_packets,
-					    stat.config.channel,
-					    stat.config.dma_mode,
-					    stat.config.irq_interval,
-					    rawiso_activity_cb);
-	if (!fi->iso_handle)
-		return -ENOMEM;
-
-	fi->iso_state = RAW1394_ISO_RECV;
-
-	raw1394_iso_fill_status(fi->iso_handle, &stat);
-	if (copy_to_user(uaddr, &stat, sizeof(stat)))
-		return -EFAULT;
-	return 0;
-}
-
-static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_iso_status stat;
-	struct hpsb_iso *iso = fi->iso_handle;
-
-	raw1394_iso_fill_status(fi->iso_handle, &stat);
-	if (copy_to_user(uaddr, &stat, sizeof(stat)))
-		return -EFAULT;
-
-	/* reset overflow counter */
-	atomic_set(&iso->overflows, 0);
-	/* reset skip counter */
-	atomic_set(&iso->skips, 0);
-
-	return 0;
-}
-
-/* copy N packet_infos out of the ringbuffer into user-supplied array */
-static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_iso_packets upackets;
-	unsigned int packet = fi->iso_handle->first_packet;
-	int i;
-
-	if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
-		return -EFAULT;
-
-	if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
-		return -EINVAL;
-
-	/* ensure user-supplied buffer is accessible and big enough */
-	if (!access_ok(VERIFY_WRITE, upackets.infos,
-		       upackets.n_packets *
-		       sizeof(struct raw1394_iso_packet_info)))
-		return -EFAULT;
-
-	/* copy the packet_infos out */
-	for (i = 0; i < upackets.n_packets; i++) {
-		if (__copy_to_user(&upackets.infos[i],
-				   &fi->iso_handle->infos[packet],
-				   sizeof(struct raw1394_iso_packet_info)))
-			return -EFAULT;
-
-		packet = (packet + 1) % fi->iso_handle->buf_packets;
-	}
-
-	return 0;
-}
-
-/* copy N packet_infos from user to ringbuffer, and queue them for transmission */
-static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_iso_packets upackets;
-	int i, rv;
-
-	if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
-		return -EFAULT;
-
-	if (upackets.n_packets >= fi->iso_handle->buf_packets)
-		return -EINVAL;
-
-	if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
-		return -EAGAIN;
-
-	/* ensure user-supplied buffer is accessible and big enough */
-	if (!access_ok(VERIFY_READ, upackets.infos,
-		       upackets.n_packets *
-		       sizeof(struct raw1394_iso_packet_info)))
-		return -EFAULT;
-
-	/* copy the infos structs in and queue the packets */
-	for (i = 0; i < upackets.n_packets; i++) {
-		struct raw1394_iso_packet_info info;
-
-		if (__copy_from_user(&info, &upackets.infos[i],
-				     sizeof(struct raw1394_iso_packet_info)))
-			return -EFAULT;
-
-		rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset,
-						info.len, info.tag, info.sy);
-		if (rv)
-			return rv;
-	}
-
-	return 0;
-}
-
-static void raw1394_iso_shutdown(struct file_info *fi)
-{
-	if (fi->iso_handle)
-		hpsb_iso_shutdown(fi->iso_handle);
-
-	fi->iso_handle = NULL;
-	fi->iso_state = RAW1394_ISO_INACTIVE;
-}
-
-static int raw1394_read_cycle_timer(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_cycle_timer ct;
-	int err;
-
-	err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
-	if (!err)
-		if (copy_to_user(uaddr, &ct, sizeof(ct)))
-			err = -EFAULT;
-	return err;
-}
-
-/* mmap the rawiso xmit/recv buffer */
-static int raw1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct file_info *fi = file->private_data;
-	int ret;
-
-	if (!mutex_trylock(&fi->state_mutex))
-		return -EAGAIN;
-
-	if (fi->iso_state == RAW1394_ISO_INACTIVE)
-		ret = -EINVAL;
-	else
-		ret = dma_region_mmap(&fi->iso_handle->data_buf, file, vma);
-
-	mutex_unlock(&fi->state_mutex);
-
-	return ret;
-}
-
-static long raw1394_ioctl_inactive(struct file_info *fi, unsigned int cmd,
-				   void __user *argp)
-{
-	switch (cmd) {
-	case RAW1394_IOC_ISO_XMIT_INIT:
-		return raw1394_iso_xmit_init(fi, argp);
-	case RAW1394_IOC_ISO_RECV_INIT:
-		return raw1394_iso_recv_init(fi, argp);
-	default:
-		return -EINVAL;
-	}
-}
-
-static long raw1394_ioctl_recv(struct file_info *fi, unsigned int cmd,
-			       unsigned long arg)
-{
-	void __user *argp = (void __user *)arg;
-
-	switch (cmd) {
-	case RAW1394_IOC_ISO_RECV_START:{
-			int args[3];
-
-			if (copy_from_user(&args[0], argp, sizeof(args)))
-				return -EFAULT;
-			return hpsb_iso_recv_start(fi->iso_handle,
-						   args[0], args[1], args[2]);
-		}
-	case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-		hpsb_iso_stop(fi->iso_handle);
-		return 0;
-	case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-		return hpsb_iso_recv_listen_channel(fi->iso_handle, arg);
-	case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-		return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg);
-	case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{
-			u64 mask;
-
-			if (copy_from_user(&mask, argp, sizeof(mask)))
-				return -EFAULT;
-			return hpsb_iso_recv_set_channel_mask(fi->iso_handle,
-							      mask);
-		}
-	case RAW1394_IOC_ISO_GET_STATUS:
-		return raw1394_iso_get_status(fi, argp);
-	case RAW1394_IOC_ISO_RECV_PACKETS:
-		return raw1394_iso_recv_packets(fi, argp);
-	case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-		return hpsb_iso_recv_release_packets(fi->iso_handle, arg);
-	case RAW1394_IOC_ISO_RECV_FLUSH:
-		return hpsb_iso_recv_flush(fi->iso_handle);
-	case RAW1394_IOC_ISO_SHUTDOWN:
-		raw1394_iso_shutdown(fi);
-		return 0;
-	case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-		queue_rawiso_event(fi);
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-static long raw1394_ioctl_xmit(struct file_info *fi, unsigned int cmd,
-			       void __user *argp)
-{
-	switch (cmd) {
-	case RAW1394_IOC_ISO_XMIT_START:{
-			int args[2];
-
-			if (copy_from_user(&args[0], argp, sizeof(args)))
-				return -EFAULT;
-			return hpsb_iso_xmit_start(fi->iso_handle,
-						   args[0], args[1]);
-		}
-	case RAW1394_IOC_ISO_XMIT_SYNC:
-		return hpsb_iso_xmit_sync(fi->iso_handle);
-	case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-		hpsb_iso_stop(fi->iso_handle);
-		return 0;
-	case RAW1394_IOC_ISO_GET_STATUS:
-		return raw1394_iso_get_status(fi, argp);
-	case RAW1394_IOC_ISO_XMIT_PACKETS:
-		return raw1394_iso_send_packets(fi, argp);
-	case RAW1394_IOC_ISO_SHUTDOWN:
-		raw1394_iso_shutdown(fi);
-		return 0;
-	case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-		queue_rawiso_event(fi);
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-/* ioctl is only used for rawiso operations */
-static long raw1394_ioctl(struct file *file, unsigned int cmd,
-			  unsigned long arg)
-{
-	struct file_info *fi = file->private_data;
-	void __user *argp = (void __user *)arg;
-	long ret;
-
-	/* state-independent commands */
-	switch(cmd) {
-	case RAW1394_IOC_GET_CYCLE_TIMER:
-		return raw1394_read_cycle_timer(fi, argp);
-	default:
-		break;
-	}
-
-	if (!mutex_trylock(&fi->state_mutex))
-		return -EAGAIN;
-
-	switch (fi->iso_state) {
-	case RAW1394_ISO_INACTIVE:
-		ret = raw1394_ioctl_inactive(fi, cmd, argp);
-		break;
-	case RAW1394_ISO_RECV:
-		ret = raw1394_ioctl_recv(fi, cmd, arg);
-		break;
-	case RAW1394_ISO_XMIT:
-		ret = raw1394_ioctl_xmit(fi, cmd, argp);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-
-	mutex_unlock(&fi->state_mutex);
-
-	return ret;
-}
-
-#ifdef CONFIG_COMPAT
-struct raw1394_iso_packets32 {
-        __u32 n_packets;
-        compat_uptr_t infos;
-} __attribute__((packed));
-
-struct raw1394_cycle_timer32 {
-        __u32 cycle_timer;
-        __u64 local_time;
-}
-#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-__attribute__((packed))
-#endif
-;
-
-#define RAW1394_IOC_ISO_RECV_PACKETS32          \
-        _IOW ('#', 0x25, struct raw1394_iso_packets32)
-#define RAW1394_IOC_ISO_XMIT_PACKETS32          \
-        _IOW ('#', 0x27, struct raw1394_iso_packets32)
-#define RAW1394_IOC_GET_CYCLE_TIMER32           \
-        _IOR ('#', 0x30, struct raw1394_cycle_timer32)
-
-static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
-                                          struct raw1394_iso_packets32 __user *arg)
-{
-	compat_uptr_t infos32;
-	void __user *infos;
-	long err = -EFAULT;
-	struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
-
-	if (!copy_in_user(&dst->n_packets, &arg->n_packets, sizeof arg->n_packets) &&
-	    !copy_from_user(&infos32, &arg->infos, sizeof infos32)) {
-		infos = compat_ptr(infos32);
-		if (!copy_to_user(&dst->infos, &infos, sizeof infos))
-			err = raw1394_ioctl(file, cmd, (unsigned long)dst);
-	}
-	return err;
-}
-
-static long raw1394_read_cycle_timer32(struct file_info *fi, void __user * uaddr)
-{
-	struct raw1394_cycle_timer32 ct;
-	int err;
-
-	err = hpsb_read_cycle_timer(fi->host, &ct.cycle_timer, &ct.local_time);
-	if (!err)
-		if (copy_to_user(uaddr, &ct, sizeof(ct)))
-			err = -EFAULT;
-	return err;
-}
-
-static long raw1394_compat_ioctl(struct file *file,
-				 unsigned int cmd, unsigned long arg)
-{
-	struct file_info *fi = file->private_data;
-	void __user *argp = (void __user *)arg;
-	long err;
-
-	switch (cmd) {
-	/* These requests have same format as long as 'int' has same size. */
-	case RAW1394_IOC_ISO_RECV_INIT:
-	case RAW1394_IOC_ISO_RECV_START:
-	case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL:
-	case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL:
-	case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:
-	case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS:
-	case RAW1394_IOC_ISO_RECV_FLUSH:
-	case RAW1394_IOC_ISO_XMIT_RECV_STOP:
-	case RAW1394_IOC_ISO_XMIT_INIT:
-	case RAW1394_IOC_ISO_XMIT_START:
-	case RAW1394_IOC_ISO_XMIT_SYNC:
-	case RAW1394_IOC_ISO_GET_STATUS:
-	case RAW1394_IOC_ISO_SHUTDOWN:
-	case RAW1394_IOC_ISO_QUEUE_ACTIVITY:
-		err = raw1394_ioctl(file, cmd, arg);
-		break;
-	/* These request have different format. */
-	case RAW1394_IOC_ISO_RECV_PACKETS32:
-		err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_RECV_PACKETS, argp);
-		break;
-	case RAW1394_IOC_ISO_XMIT_PACKETS32:
-		err = raw1394_iso_xmit_recv_packets32(file, RAW1394_IOC_ISO_XMIT_PACKETS, argp);
-		break;
-	case RAW1394_IOC_GET_CYCLE_TIMER32:
-		err = raw1394_read_cycle_timer32(fi, argp);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-
-	return err;
-}
-#endif
-
-static unsigned int raw1394_poll(struct file *file, poll_table * pt)
-{
-	struct file_info *fi = file->private_data;
-	unsigned int mask = POLLOUT | POLLWRNORM;
-	unsigned long flags;
-
-	poll_wait(file, &fi->wait_complete, pt);
-
-	spin_lock_irqsave(&fi->reqlists_lock, flags);
-	if (!list_empty(&fi->req_complete)) {
-		mask |= POLLIN | POLLRDNORM;
-	}
-	spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-	return mask;
-}
-
-static int raw1394_open(struct inode *inode, struct file *file)
-{
-	struct file_info *fi;
-
-	fi = kzalloc(sizeof(*fi), GFP_KERNEL);
-	if (!fi)
-		return -ENOMEM;
-
-	fi->notification = (u8) RAW1394_NOTIFY_ON;	/* busreset notification */
-
-	INIT_LIST_HEAD(&fi->list);
-	mutex_init(&fi->state_mutex);
-	fi->state = opened;
-	INIT_LIST_HEAD(&fi->req_pending);
-	INIT_LIST_HEAD(&fi->req_complete);
-	spin_lock_init(&fi->reqlists_lock);
-	init_waitqueue_head(&fi->wait_complete);
-	INIT_LIST_HEAD(&fi->addr_list);
-
-	file->private_data = fi;
-
-	return nonseekable_open(inode, file);
-}
-
-static int raw1394_release(struct inode *inode, struct file *file)
-{
-	struct file_info *fi = file->private_data;
-	struct list_head *lh;
-	struct pending_request *req;
-	int i, fail;
-	int retval = 0;
-	struct list_head *entry;
-	struct arm_addr *addr = NULL;
-	struct host_info *hi;
-	struct file_info *fi_hlp = NULL;
-	struct arm_addr *arm_addr = NULL;
-	int another_host;
-	int csr_mod = 0;
-	unsigned long flags;
-
-	if (fi->iso_state != RAW1394_ISO_INACTIVE)
-		raw1394_iso_shutdown(fi);
-
-	spin_lock_irqsave(&host_info_lock, flags);
-
-	fail = 0;
-	/* set address-entries invalid */
-
-	while (!list_empty(&fi->addr_list)) {
-		another_host = 0;
-		lh = fi->addr_list.next;
-		addr = list_entry(lh, struct arm_addr, addr_list);
-		/* another host with valid address-entry containing
-		   same addressrange? */
-		list_for_each_entry(hi, &host_info_list, list) {
-			if (hi->host != fi->host) {
-				list_for_each_entry(fi_hlp, &hi->file_info_list,
-						    list) {
-					entry = fi_hlp->addr_list.next;
-					while (entry != &(fi_hlp->addr_list)) {
-						arm_addr = list_entry(entry, struct
-								      arm_addr,
-								      addr_list);
-						if (arm_addr->start ==
-						    addr->start) {
-							DBGMSG
-							    ("raw1394_release: "
-							     "another host ownes "
-							     "same addressrange");
-							another_host = 1;
-							break;
-						}
-						entry = entry->next;
-					}
-					if (another_host) {
-						break;
-					}
-				}
-			}
-		}
-		if (!another_host) {
-			DBGMSG("raw1394_release: call hpsb_arm_unregister");
-			retval =
-			    hpsb_unregister_addrspace(&raw1394_highlevel,
-						      fi->host, addr->start);
-			if (!retval) {
-				++fail;
-				printk(KERN_ERR
-				       "raw1394_release arm_Unregister failed\n");
-			}
-		}
-		DBGMSG("raw1394_release: delete addr_entry from list");
-		list_del(&addr->addr_list);
-		vfree(addr->addr_space_buffer);
-		kfree(addr);
-	}			/* while */
-	spin_unlock_irqrestore(&host_info_lock, flags);
-	if (fail > 0) {
-		printk(KERN_ERR "raw1394: during addr_list-release "
-		       "error(s) occurred \n");
-	}
-
-	for (;;) {
-		/* This locked section guarantees that neither
-		 * complete nor pending requests exist once i!=0 */
-		spin_lock_irqsave(&fi->reqlists_lock, flags);
-		while ((req = __next_complete_req(fi)))
-			free_pending_request(req);
-
-		i = list_empty(&fi->req_pending);
-		spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
-		if (i)
-			break;
-		/*
-		 * Sleep until more requests can be freed.
-		 *
-		 * NB: We call the macro wait_event() with a condition argument
-		 * with side effect.  This is only possible because the side
-		 * effect does not occur until the condition became true, and
-		 * wait_event() won't evaluate the condition again after that.
-		 */
-		wait_event(fi->wait_complete, (req = next_complete_req(fi)));
-		free_pending_request(req);
-	}
-
-	/* Remove any sub-trees left by user space programs */
-	for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) {
-		struct csr1212_dentry *dentry;
-		if (!fi->csr1212_dirs[i])
-			continue;
-		for (dentry =
-		     fi->csr1212_dirs[i]->value.directory.dentries_head; dentry;
-		     dentry = dentry->next) {
-			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
-							     root_kv,
-							     dentry->kv);
-		}
-		csr1212_release_keyval(fi->csr1212_dirs[i]);
-		fi->csr1212_dirs[i] = NULL;
-		csr_mod = 1;
-	}
-
-	if ((csr_mod || fi->cfgrom_upd)
-	    && hpsb_update_config_rom_image(fi->host) < 0)
-		HPSB_ERR
-		    ("Failed to generate Configuration ROM image for host %d",
-		     fi->host->id);
-
-	if (fi->state == connected) {
-		spin_lock_irqsave(&host_info_lock, flags);
-		list_del(&fi->list);
-		spin_unlock_irqrestore(&host_info_lock, flags);
-
-		put_device(&fi->host->device);
-	}
-
-	spin_lock_irqsave(&host_info_lock, flags);
-	if (fi->host)
-		module_put(fi->host->driver->owner);
-	spin_unlock_irqrestore(&host_info_lock, flags);
-
-	kfree(fi);
-
-	return 0;
-}
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id raw1394_id_table[] = {
-	{
-	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-	 .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
-	 .version = AVC_SW_VERSION_ENTRY & 0xffffff},
-	{
-	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-	 .version = CAMERA_SW_VERSION_ENTRY & 0xffffff},
-	{
-	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-	 .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff},
-	{
-	 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-	 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-	 .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff},
-	{}
-};
-
-MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver raw1394_driver = {
-	.name = "raw1394",
-};
-
-/******************************************************************************/
-
-static struct hpsb_highlevel raw1394_highlevel = {
-	.name = RAW1394_DEVICE_NAME,
-	.add_host = add_host,
-	.remove_host = remove_host,
-	.host_reset = host_reset,
-	.fcp_request = fcp_request,
-};
-
-static struct cdev raw1394_cdev;
-static const struct file_operations raw1394_fops = {
-	.owner = THIS_MODULE,
-	.read = raw1394_read,
-	.write = raw1394_write,
-	.mmap = raw1394_mmap,
-	.unlocked_ioctl = raw1394_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = raw1394_compat_ioctl,
-#endif
-	.poll = raw1394_poll,
-	.open = raw1394_open,
-	.release = raw1394_release,
-	.llseek = no_llseek,
-};
-
-static int __init init_raw1394(void)
-{
-	int ret = 0;
-
-	hpsb_register_highlevel(&raw1394_highlevel);
-
-	if (IS_ERR
-	    (device_create(hpsb_protocol_class, NULL,
-			   MKDEV(IEEE1394_MAJOR,
-				 IEEE1394_MINOR_BLOCK_RAW1394 * 16),
-			   NULL, RAW1394_DEVICE_NAME))) {
-		ret = -EFAULT;
-		goto out_unreg;
-	}
-
-	cdev_init(&raw1394_cdev, &raw1394_fops);
-	raw1394_cdev.owner = THIS_MODULE;
-	ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1);
-	if (ret) {
-		HPSB_ERR("raw1394 failed to register minor device block");
-		goto out_dev;
-	}
-
-	HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME);
-
-	ret = hpsb_register_protocol(&raw1394_driver);
-	if (ret) {
-		HPSB_ERR("raw1394: failed to register protocol");
-		cdev_del(&raw1394_cdev);
-		goto out_dev;
-	}
-
-	goto out;
-
-      out_dev:
-	device_destroy(hpsb_protocol_class,
-		       MKDEV(IEEE1394_MAJOR,
-			     IEEE1394_MINOR_BLOCK_RAW1394 * 16));
-      out_unreg:
-	hpsb_unregister_highlevel(&raw1394_highlevel);
-      out:
-	return ret;
-}
-
-static void __exit cleanup_raw1394(void)
-{
-	device_destroy(hpsb_protocol_class,
-		       MKDEV(IEEE1394_MAJOR,
-			     IEEE1394_MINOR_BLOCK_RAW1394 * 16));
-	cdev_del(&raw1394_cdev);
-	hpsb_unregister_highlevel(&raw1394_highlevel);
-	hpsb_unregister_protocol(&raw1394_driver);
-}
-
-module_init(init_raw1394);
-module_exit(cleanup_raw1394);
-MODULE_LICENSE("GPL");
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,191 +0,0 @@
-#ifndef IEEE1394_RAW1394_H
-#define IEEE1394_RAW1394_H
-
-/* header for the raw1394 API that is exported to user-space */
-
-#define RAW1394_KERNELAPI_VERSION 4
-
-/* state: opened */
-#define RAW1394_REQ_INITIALIZE    1
-
-/* state: initialized */
-#define RAW1394_REQ_LIST_CARDS    2
-#define RAW1394_REQ_SET_CARD      3
-
-/* state: connected */
-#define RAW1394_REQ_ASYNC_READ      100
-#define RAW1394_REQ_ASYNC_WRITE     101
-#define RAW1394_REQ_LOCK            102
-#define RAW1394_REQ_LOCK64          103
-#define RAW1394_REQ_ISO_SEND        104 /* removed ABI, now a no-op */
-#define RAW1394_REQ_ASYNC_SEND      105
-#define RAW1394_REQ_ASYNC_STREAM    106
-
-#define RAW1394_REQ_ISO_LISTEN      200 /* removed ABI, now a no-op */
-#define RAW1394_REQ_FCP_LISTEN      201
-#define RAW1394_REQ_RESET_BUS       202
-#define RAW1394_REQ_GET_ROM         203
-#define RAW1394_REQ_UPDATE_ROM      204
-#define RAW1394_REQ_ECHO            205
-#define RAW1394_REQ_MODIFY_ROM      206
-
-#define RAW1394_REQ_ARM_REGISTER    300
-#define RAW1394_REQ_ARM_UNREGISTER  301
-#define RAW1394_REQ_ARM_SET_BUF     302
-#define RAW1394_REQ_ARM_GET_BUF     303
-
-#define RAW1394_REQ_RESET_NOTIFY    400
-
-#define RAW1394_REQ_PHYPACKET       500
-
-/* kernel to user */
-#define RAW1394_REQ_BUS_RESET        10000
-#define RAW1394_REQ_ISO_RECEIVE      10001
-#define RAW1394_REQ_FCP_REQUEST      10002
-#define RAW1394_REQ_ARM              10003
-#define RAW1394_REQ_RAWISO_ACTIVITY  10004
-
-/* error codes */
-#define RAW1394_ERROR_NONE        0
-#define RAW1394_ERROR_COMPAT      (-1001)
-#define RAW1394_ERROR_STATE_ORDER (-1002)
-#define RAW1394_ERROR_GENERATION  (-1003)
-#define RAW1394_ERROR_INVALID_ARG (-1004)
-#define RAW1394_ERROR_MEMFAULT    (-1005)
-#define RAW1394_ERROR_ALREADY     (-1006)
-
-#define RAW1394_ERROR_EXCESSIVE   (-1020)
-#define RAW1394_ERROR_UNTIDY_LEN  (-1021)
-
-#define RAW1394_ERROR_SEND_ERROR  (-1100)
-#define RAW1394_ERROR_ABORTED     (-1101)
-#define RAW1394_ERROR_TIMEOUT     (-1102)
-
-/* arm_codes */
-#define ARM_READ   1
-#define ARM_WRITE  2
-#define ARM_LOCK   4
-
-#define RAW1394_LONG_RESET  0
-#define RAW1394_SHORT_RESET 1
-
-/* busresetnotify ... */
-#define RAW1394_NOTIFY_OFF 0
-#define RAW1394_NOTIFY_ON  1
-
-#include <asm/types.h>
-
-struct raw1394_request {
-        __u32 type;
-        __s32 error;
-        __u32 misc;
-
-        __u32 generation;
-        __u32 length;
-
-        __u64 address;
-
-        __u64 tag;
-
-        __u64 sendb;
-        __u64 recvb;
-};
-
-struct raw1394_khost_list {
-        __u32 nodes;
-        __u8 name[32];
-};
-
-typedef struct arm_request {
-        __u16           destination_nodeid;
-        __u16           source_nodeid;
-        __u64           destination_offset;
-        __u8            tlabel;
-        __u8            tcode;
-        __u8            extended_transaction_code;
-        __u32           generation;
-        __u16           buffer_length;
-        __u8            __user *buffer;
-} *arm_request_t;
-
-typedef struct arm_response {
-        __s32           response_code;
-        __u16           buffer_length;
-        __u8            __user *buffer;
-} *arm_response_t;
-
-typedef struct arm_request_response {
-        struct arm_request  __user *request;
-        struct arm_response __user *response;
-} *arm_request_response_t;
-
-/* rawiso API */
-#include "ieee1394-ioctl.h"
-
-/* per-packet metadata embedded in the ringbuffer */
-/* must be identical to hpsb_iso_packet_info in iso.h! */
-struct raw1394_iso_packet_info {
-	__u32 offset;
-	__u16 len;
-	__u16 cycle;   /* recv only */
-	__u8  channel; /* recv only */
-	__u8  tag;
-	__u8  sy;
-};
-
-/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
-struct raw1394_iso_packets {
-	__u32 n_packets;
-	struct raw1394_iso_packet_info __user *infos;
-};
-
-struct raw1394_iso_config {
-	/* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
-	__u32 data_buf_size;
-
-	/* # of packets to buffer */
-	__u32 buf_packets;
-
-	/* iso channel (set to -1 for multi-channel recv) */
-	__s32 channel;
-
-	/* xmit only - iso transmission speed */
-	__u8 speed;
-
-	/* The mode of the dma when receiving iso data. Must be supported by chip */
-	__u8 dma_mode;
-
-	/* max. latency of buffer, in packets (-1 if you don't care) */
-	__s32 irq_interval;
-};
-
-/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
-struct raw1394_iso_status {
-	/* current settings */
-	struct raw1394_iso_config config;
-
-	/* number of packets waiting to be filled with data (ISO transmission)
-	   or containing data received (ISO reception) */
-	__u32 n_packets;
-
-	/* approximate number of packets dropped due to overflow or
-	   underflow of the packet buffer (a value of zero guarantees
-	   that no packets have been dropped) */
-	__u32 overflows;
-
-	/* cycle number at which next packet will be transmitted;
-	   -1 if not known */
-	__s16 xmit_cycle;
-};
-
-/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
-struct raw1394_cycle_timer {
-	/* contents of Isochronous Cycle Timer register,
-	   as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
-	__u32 cycle_timer;
-
-	/* local time in microseconds since Epoch,
-	   simultaneously read with cycle timer */
-	__u64 local_time;
-};
-#endif /* IEEE1394_RAW1394_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394-private.h linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394-private.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/raw1394-private.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/raw1394-private.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,81 +0,0 @@
-#ifndef IEEE1394_RAW1394_PRIVATE_H
-#define IEEE1394_RAW1394_PRIVATE_H
-
-/* header for definitions that are private to the raw1394 driver
-   and not visible to user-space */
-
-#define RAW1394_DEVICE_MAJOR      171
-#define RAW1394_DEVICE_NAME       "raw1394"
-
-#define RAW1394_MAX_USER_CSR_DIRS	16
-
-struct iso_block_store {
-        atomic_t refcount;
-        size_t data_size;
-        quadlet_t data[0];
-};
-
-enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
-			 RAW1394_ISO_RECV = 1,
-			 RAW1394_ISO_XMIT = 2 };
-
-struct file_info {
-        struct list_head list;
-
-	struct mutex state_mutex;
-        enum { opened, initialized, connected } state;
-        unsigned int protocol_version;
-
-        struct hpsb_host *host;
-
-        struct list_head req_pending;	/* protected by reqlists_lock */
-        struct list_head req_complete;	/* protected by reqlists_lock */
-        spinlock_t reqlists_lock;
-        wait_queue_head_t wait_complete;
-
-        struct list_head addr_list;	/* protected by host_info_lock */
-
-        u8 __user *fcp_buffer;
-
-        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
-
-	/* new rawiso API */
-	enum raw1394_iso_state iso_state;
-	struct hpsb_iso *iso_handle;
-
-	/* User space's CSR1212 dynamic ConfigROM directories */
-	struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
-
-	/* Legacy ConfigROM update flag */
-	u8 cfgrom_upd;
-};
-
-struct arm_addr {
-        struct list_head addr_list; /* file_info list */
-        u64    start, end;
-        u64    arm_tag;
-        u8     access_rights;
-        u8     notification_options;
-        u8     client_transactions;
-        u64    recvb;
-        u16    rec_length;
-        u8     *addr_space_buffer; /* accessed by read/write/lock requests */
-};
-
-struct pending_request {
-        struct list_head list;
-        struct file_info *file_info;
-        struct hpsb_packet *packet;
-        struct iso_block_store *ibs;
-        quadlet_t *data;
-        int free_data;
-        struct raw1394_request req;
-};
-
-struct host_info {
-        struct list_head list;
-        struct hpsb_host *host;
-        struct list_head file_info_list;  /* protected by host_info_lock */
-};
-
-#endif  /* IEEE1394_RAW1394_PRIVATE_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/sbp2.c linux-libre-2.6.37-gnu/drivers/ieee1394/sbp2.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/sbp2.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/sbp2.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,2138 +0,0 @@
-/*
- * sbp2.c - SBP-2 protocol driver for IEEE-1394
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com (JSG)
- *
- * Copyright (C) 2003 Ben Collins <bcollins@debian.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Brief Description:
- *
- * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394
- * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level
- * driver. It also registers as a SCSI lower-level driver in order to accept
- * SCSI commands for transport using SBP-2.
- *
- * You may access any attached SBP-2 (usually storage devices) as regular
- * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc..
- *
- * See http://www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2
- * specification and for where to purchase the official standard.
- *
- * TODO:
- *   - look into possible improvements of the SCSI error handlers
- *   - handle Unit_Characteristics.mgt_ORB_timeout and .ORB_size
- *   - handle Logical_Unit_Number.ordered
- *   - handle src == 1 in status blocks
- *   - reimplement the DMA mapping in absence of physical DMA so that
- *     bus_to_virt is no longer required
- *   - debug the handling of absent physical DMA
- *   - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection
- *     (this is easy but depends on the previous two TODO items)
- *   - make the parameter serialize_io configurable per device
- *   - move all requests to fetch agent registers into non-atomic context,
- *     replace all usages of sbp2util_node_write_no_wait by true transactions
- * Grep for inline FIXME comments below.
- */
-
-#include <linux/blkdev.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/scatterlist.h>
-
-#include <asm/byteorder.h>
-#include <asm/errno.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <asm/types.h>
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-#include <asm/io.h> /* for bus_to_virt */
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-
-#include "csr1212.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_transactions.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "sbp2.h"
-
-/*
- * Module load parameter definitions
- */
-
-/*
- * Change max_speed on module load if you have a bad IEEE-1394
- * controller that has trouble running 2KB packets at 400mb.
- *
- * NOTE: On certain OHCI parts I have seen short packets on async transmit
- * (probably due to PCI latency/throughput issues with the part). You can
- * bump down the speed if you are running into problems.
- */
-static int sbp2_max_speed = IEEE1394_SPEED_MAX;
-module_param_named(max_speed, sbp2_max_speed, int, 0644);
-MODULE_PARM_DESC(max_speed, "Limit data transfer speed (5 <= 3200, "
-		 "4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s)");
-
-/*
- * Set serialize_io to 0 or N to use dynamically appended lists of command ORBs.
- * This is and always has been buggy in multiple subtle ways. See above TODOs.
- */
-static int sbp2_serialize_io = 1;
-module_param_named(serialize_io, sbp2_serialize_io, bool, 0444);
-MODULE_PARM_DESC(serialize_io, "Serialize requests coming from SCSI drivers "
-		 "(default = Y, faster but buggy = N)");
-
-/*
- * Adjust max_sectors if you'd like to influence how many sectors each SCSI
- * command can transfer at most. Please note that some older SBP-2 bridge
- * chips are broken for transfers greater or equal to 128KB, therefore
- * max_sectors used to be a safe 255 sectors for many years. We now have a
- * default of 0 here which means that we let the SCSI stack choose a limit.
- *
- * The SBP2_WORKAROUND_128K_MAX_TRANS flag, if set either in the workarounds
- * module parameter or in the sbp2_workarounds_table[], will override the
- * value of max_sectors. We should use sbp2_workarounds_table[] to cover any
- * bridge chip which becomes known to need the 255 sectors limit.
- */
-static int sbp2_max_sectors;
-module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
-MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
-		 "(default = 0 = use SCSI stack's default)");
-
-/*
- * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
- * do an exclusive login, as it's generally unsafe to have two hosts
- * talking to a single sbp2 device at the same time (filesystem coherency,
- * etc.). If you're running an sbp2 device that supports multiple logins,
- * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, e.g. OpenGFS, Oracle Cluster
- * File System, or Lustre, then set exclusive_login to zero.
- *
- * So far only bridges from Oxford Semiconductor are known to support
- * concurrent logins. Depending on firmware, four or two concurrent logins
- * are possible on OXFW911 and newer Oxsemi bridges.
- */
-static int sbp2_exclusive_login = 1;
-module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
-MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
-		 "(default = Y, use N for concurrent initiators)");
-
-/*
- * If any of the following workarounds is required for your device to work,
- * please submit the kernel messages logged by sbp2 to the linux1394-devel
- * mailing list.
- *
- * - 128kB max transfer
- *   Limit transfer size. Necessary for some old bridges.
- *
- * - 36 byte inquiry
- *   When scsi_mod probes the device, let the inquiry command look like that
- *   from MS Windows.
- *
- * - skip mode page 8
- *   Suppress sending of mode_sense for mode page 8 if the device pretends to
- *   support the SCSI Primary Block commands instead of Reduced Block Commands.
- *
- * - fix capacity
- *   Tell sd_mod to correct the last sector number reported by read_capacity.
- *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
- *   Don't use this with devices which don't have this bug.
- *
- * - delay inquiry
- *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
- *
- * - power condition
- *   Set the power condition field in the START STOP UNIT commands sent by
- *   sd_mod on suspend, resume, and shutdown (if manage_start_stop is on).
- *   Some disks need this to spin down or to resume properly.
- *
- * - override internal blacklist
- *   Instead of adding to the built-in blacklist, use only the workarounds
- *   specified in the module load parameter.
- *   Useful if a blacklist entry interfered with a non-broken device.
- */
-static int sbp2_default_workarounds;
-module_param_named(workarounds, sbp2_default_workarounds, int, 0644);
-MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
-	", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
-	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
-	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
-	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
-	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
-	", set power condition in start stop unit = "
-				  __stringify(SBP2_WORKAROUND_POWER_CONDITION)
-	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
-	", or a combination)");
-
-/*
- * This influences the format of the sysfs attribute
- * /sys/bus/scsi/devices/.../ieee1394_id.
- *
- * The default format is like in older kernels:  %016Lx:%d:%d
- * It contains the target's EUI-64, a number given to the logical unit by
- * the ieee1394 driver's nodemgr (starting at 0), and the LUN.
- *
- * The long format is:  %016Lx:%06x:%04x
- * It contains the target's EUI-64, the unit directory's directory_ID as per
- * IEEE 1212 clause 7.7.19, and the LUN.  This format comes closest to the
- * format of SBP(-3) target port and logical unit identifier as per SAM (SCSI
- * Architecture Model) rev.2 to 4 annex A.  Therefore and because it is
- * independent of the implementation of the ieee1394 nodemgr, the longer format
- * is recommended for future use.
- */
-static int sbp2_long_sysfs_ieee1394_id;
-module_param_named(long_ieee1394_id, sbp2_long_sysfs_ieee1394_id, bool, 0644);
-MODULE_PARM_DESC(long_ieee1394_id, "8+3+2 bytes format of ieee1394_id in sysfs "
-		 "(default = backwards-compatible = N, SAM-conforming = Y)");
-
-
-#define SBP2_INFO(fmt, args...)	HPSB_INFO("sbp2: "fmt, ## args)
-#define SBP2_ERR(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
-
-/*
- * Globals
- */
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32);
-static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *,
-				      void (*)(struct scsi_cmnd *));
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *);
-static int sbp2_start_device(struct sbp2_lu *);
-static void sbp2_remove_device(struct sbp2_lu *);
-static int sbp2_login_device(struct sbp2_lu *);
-static int sbp2_reconnect_device(struct sbp2_lu *);
-static int sbp2_logout_device(struct sbp2_lu *);
-static void sbp2_host_reset(struct hpsb_host *);
-static int sbp2_handle_status_write(struct hpsb_host *, int, int, quadlet_t *,
-				    u64, size_t, u16);
-static int sbp2_agent_reset(struct sbp2_lu *, int);
-static void sbp2_parse_unit_directory(struct sbp2_lu *,
-				      struct unit_directory *);
-static int sbp2_set_busy_timeout(struct sbp2_lu *);
-static int sbp2_max_speed_and_size(struct sbp2_lu *);
-
-
-static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xa, 0xa, 0xa };
-
-static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
-
-static struct hpsb_highlevel sbp2_highlevel = {
-	.name		= SBP2_DEVICE_NAME,
-	.host_reset	= sbp2_host_reset,
-};
-
-static const struct hpsb_address_ops sbp2_ops = {
-	.write		= sbp2_handle_status_write
-};
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *,
-				     u64, size_t, u16);
-static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64,
-				    size_t, u16);
-
-static const struct hpsb_address_ops sbp2_physdma_ops = {
-	.read		= sbp2_handle_physdma_read,
-	.write		= sbp2_handle_physdma_write,
-};
-#endif
-
-
-/*
- * Interface to driver core and IEEE 1394 core
- */
-static const struct ieee1394_device_id sbp2_id_table[] = {
-	{
-	 .match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-	 .specifier_id	= SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
-	 .version	= SBP2_SW_VERSION_ENTRY & 0xffffff},
-	{}
-};
-MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
-
-static int sbp2_probe(struct device *);
-static int sbp2_remove(struct device *);
-static int sbp2_update(struct unit_directory *);
-
-static struct hpsb_protocol_driver sbp2_driver = {
-	.name		= SBP2_DEVICE_NAME,
-	.id_table	= sbp2_id_table,
-	.update		= sbp2_update,
-	.driver		= {
-		.probe		= sbp2_probe,
-		.remove		= sbp2_remove,
-	},
-};
-
-
-/*
- * Interface to SCSI core
- */
-static int sbp2scsi_queuecommand(struct scsi_cmnd *,
-				 void (*)(struct scsi_cmnd *));
-static int sbp2scsi_abort(struct scsi_cmnd *);
-static int sbp2scsi_reset(struct scsi_cmnd *);
-static int sbp2scsi_slave_alloc(struct scsi_device *);
-static int sbp2scsi_slave_configure(struct scsi_device *);
-static void sbp2scsi_slave_destroy(struct scsi_device *);
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *,
-					   struct device_attribute *, char *);
-
-static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
-
-static struct device_attribute *sbp2_sysfs_sdev_attrs[] = {
-	&dev_attr_ieee1394_id,
-	NULL
-};
-
-static struct scsi_host_template sbp2_shost_template = {
-	.module			 = THIS_MODULE,
-	.name			 = "SBP-2 IEEE-1394",
-	.proc_name		 = SBP2_DEVICE_NAME,
-	.queuecommand		 = sbp2scsi_queuecommand,
-	.eh_abort_handler	 = sbp2scsi_abort,
-	.eh_device_reset_handler = sbp2scsi_reset,
-	.slave_alloc		 = sbp2scsi_slave_alloc,
-	.slave_configure	 = sbp2scsi_slave_configure,
-	.slave_destroy		 = sbp2scsi_slave_destroy,
-	.this_id		 = -1,
-	.sg_tablesize		 = SG_ALL,
-	.use_clustering		 = ENABLE_CLUSTERING,
-	.cmd_per_lun		 = SBP2_MAX_CMDS,
-	.can_queue		 = SBP2_MAX_CMDS,
-	.sdev_attrs		 = sbp2_sysfs_sdev_attrs,
-};
-
-#define SBP2_ROM_VALUE_WILDCARD ~0         /* match all */
-#define SBP2_ROM_VALUE_MISSING  0xff000000 /* not present in the unit dir. */
-
-/*
- * List of devices with known bugs.
- *
- * The firmware_revision field, masked with 0xffff00, is the best indicator
- * for the type of bridge chip of a device.  It yields a few false positives
- * but this did not break correctly behaving devices so far.
- */
-static const struct {
-	u32 firmware_revision;
-	u32 model;
-	unsigned workarounds;
-} sbp2_workarounds_table[] = {
-	/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
-		.firmware_revision	= 0x002800,
-		.model			= 0x001010,
-		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
-					  SBP2_WORKAROUND_MODE_SENSE_8 |
-					  SBP2_WORKAROUND_POWER_CONDITION,
-	},
-	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
-		.firmware_revision	= 0x002800,
-		.model			= 0x000000,
-		.workarounds		= SBP2_WORKAROUND_POWER_CONDITION,
-	},
-	/* Initio bridges, actually only needed for some older ones */ {
-		.firmware_revision	= 0x000200,
-		.model			= SBP2_ROM_VALUE_WILDCARD,
-		.workarounds		= SBP2_WORKAROUND_INQUIRY_36,
-	},
-	/* PL-3507 bridge with Prolific firmware */ {
-		.firmware_revision	= 0x012800,
-		.model			= SBP2_ROM_VALUE_WILDCARD,
-		.workarounds		= SBP2_WORKAROUND_POWER_CONDITION,
-	},
-	/* Symbios bridge */ {
-		.firmware_revision	= 0xa0b800,
-		.model			= SBP2_ROM_VALUE_WILDCARD,
-		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,
-	},
-	/* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
-		.firmware_revision	= 0x002600,
-		.model			= SBP2_ROM_VALUE_WILDCARD,
-		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,
-	},
-	/*
-	 * iPod 2nd generation: needs 128k max transfer size workaround
-	 * iPod 3rd generation: needs fix capacity workaround
-	 */
-	{
-		.firmware_revision	= 0x0a2700,
-		.model			= 0x000000,
-		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS |
-					  SBP2_WORKAROUND_FIX_CAPACITY,
-	},
-	/* iPod 4th generation */ {
-		.firmware_revision	= 0x0a2700,
-		.model			= 0x000021,
-		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
-	},
-	/* iPod mini */ {
-		.firmware_revision	= 0x0a2700,
-		.model			= 0x000022,
-		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
-	},
-	/* iPod mini */ {
-		.firmware_revision	= 0x0a2700,
-		.model			= 0x000023,
-		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
-	},
-	/* iPod Photo */ {
-		.firmware_revision	= 0x0a2700,
-		.model			= 0x00007e,
-		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
-	}
-};
-
-/**************************************
- * General utility functions
- **************************************/
-
-#ifndef __BIG_ENDIAN
-/*
- * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
- */
-static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
-{
-	u32 *temp = buffer;
-
-	for (length = (length >> 2); length--; )
-		temp[length] = be32_to_cpu(temp[length]);
-}
-
-/*
- * Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
- */
-static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
-{
-	u32 *temp = buffer;
-
-	for (length = (length >> 2); length--; )
-		temp[length] = cpu_to_be32(temp[length]);
-}
-#else /* BIG_ENDIAN */
-/* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
-#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
-#endif
-
-static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq);
-
-/*
- * Waits for completion of an SBP-2 access request.
- * Returns nonzero if timed out or prematurely interrupted.
- */
-static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout)
-{
-	long leftover;
-
-	leftover = wait_event_interruptible_timeout(
-			sbp2_access_wq, lu->access_complete, timeout);
-	lu->access_complete = 0;
-	return leftover <= 0;
-}
-
-static void sbp2_free_packet(void *packet)
-{
-	hpsb_free_tlabel(packet);
-	hpsb_free_packet(packet);
-}
-
-/*
- * This is much like hpsb_node_write(), except it ignores the response
- * subaction and returns immediately. Can be used from atomic context.
- */
-static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
-				       quadlet_t *buf, size_t len)
-{
-	struct hpsb_packet *packet;
-
-	packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len);
-	if (!packet)
-		return -ENOMEM;
-
-	hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet);
-	hpsb_node_fill_packet(ne, packet);
-	if (hpsb_send_packet(packet) < 0) {
-		sbp2_free_packet(packet);
-		return -EIO;
-	}
-	return 0;
-}
-
-static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset,
-					quadlet_t *data, size_t len)
-{
-	/* There is a small window after a bus reset within which the node
-	 * entry's generation is current but the reconnect wasn't completed. */
-	if (unlikely(atomic_read(&lu->state) == SBP2LU_STATE_IN_RESET))
-		return;
-
-	if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset,
-			    data, len))
-		SBP2_ERR("sbp2util_notify_fetch_agent failed.");
-
-	/* Now accept new SCSI commands, unless a bus reset happended during
-	 * hpsb_node_write. */
-	if (likely(atomic_read(&lu->state) != SBP2LU_STATE_IN_RESET))
-		scsi_unblock_requests(lu->shost);
-}
-
-static void sbp2util_write_orb_pointer(struct work_struct *work)
-{
-	struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-	quadlet_t data[2];
-
-	data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id);
-	data[1] = lu->last_orb_dma;
-	sbp2util_cpu_to_be32_buffer(data, 8);
-	sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);
-}
-
-static void sbp2util_write_doorbell(struct work_struct *work)
-{
-	struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
-
-	sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);
-}
-
-static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
-{
-	struct sbp2_command_info *cmd;
-	struct device *dmadev = lu->hi->host->device.parent;
-	int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
-	for (i = 0; i < orbs; i++) {
-		cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-		if (!cmd)
-			goto failed_alloc;
-
-		cmd->command_orb_dma =
-		    dma_map_single(dmadev, &cmd->command_orb,
-				   sizeof(struct sbp2_command_orb),
-				   DMA_TO_DEVICE);
-		if (dma_mapping_error(dmadev, cmd->command_orb_dma))
-			goto failed_orb;
-
-		cmd->sge_dma =
-		    dma_map_single(dmadev, &cmd->scatter_gather_element,
-				   sizeof(cmd->scatter_gather_element),
-				   DMA_TO_DEVICE);
-		if (dma_mapping_error(dmadev, cmd->sge_dma))
-			goto failed_sge;
-
-		INIT_LIST_HEAD(&cmd->list);
-		list_add_tail(&cmd->list, &lu->cmd_orb_completed);
-	}
-	return 0;
-
-failed_sge:
-	dma_unmap_single(dmadev, cmd->command_orb_dma,
-			 sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-failed_orb:
-	kfree(cmd);
-failed_alloc:
-	return -ENOMEM;
-}
-
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
-					     struct hpsb_host *host)
-{
-	struct list_head *lh, *next;
-	struct sbp2_command_info *cmd;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	if (!list_empty(&lu->cmd_orb_completed))
-		list_for_each_safe(lh, next, &lu->cmd_orb_completed) {
-			cmd = list_entry(lh, struct sbp2_command_info, list);
-			dma_unmap_single(host->device.parent,
-					 cmd->command_orb_dma,
-					 sizeof(struct sbp2_command_orb),
-					 DMA_TO_DEVICE);
-			dma_unmap_single(host->device.parent, cmd->sge_dma,
-					 sizeof(cmd->scatter_gather_element),
-					 DMA_TO_DEVICE);
-			kfree(cmd);
-		}
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-	return;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding command ORB.
- * Only looks at the in-use list.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_orb(
-				struct sbp2_lu *lu, dma_addr_t orb)
-{
-	struct sbp2_command_info *cmd;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	if (!list_empty(&lu->cmd_orb_inuse))
-		list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
-			if (cmd->command_orb_dma == orb) {
-				spin_unlock_irqrestore(
-						&lu->cmd_orb_lock, flags);
-				return cmd;
-			}
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-	return NULL;
-}
-
-/*
- * Finds the sbp2_command for a given outstanding SCpnt.
- * Only looks at the in-use list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
-				struct sbp2_lu *lu, void *SCpnt)
-{
-	struct sbp2_command_info *cmd;
-
-	if (!list_empty(&lu->cmd_orb_inuse))
-		list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
-			if (cmd->Current_SCpnt == SCpnt)
-				return cmd;
-	return NULL;
-}
-
-static struct sbp2_command_info *sbp2util_allocate_command_orb(
-				struct sbp2_lu *lu,
-				struct scsi_cmnd *Current_SCpnt,
-				void (*Current_done)(struct scsi_cmnd *))
-{
-	struct list_head *lh;
-	struct sbp2_command_info *cmd = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	if (!list_empty(&lu->cmd_orb_completed)) {
-		lh = lu->cmd_orb_completed.next;
-		list_del(lh);
-		cmd = list_entry(lh, struct sbp2_command_info, list);
-		cmd->Current_done = Current_done;
-		cmd->Current_SCpnt = Current_SCpnt;
-		list_add_tail(&cmd->list, &lu->cmd_orb_inuse);
-	} else
-		SBP2_ERR("%s: no orbs available", __func__);
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-	return cmd;
-}
-
-/*
- * Unmaps the DMAs of a command and moves the command to the completed ORB list.
- * Must be called with lu->cmd_orb_lock held.
- */
-static void sbp2util_mark_command_completed(struct sbp2_lu *lu,
-					    struct sbp2_command_info *cmd)
-{
-	if (scsi_sg_count(cmd->Current_SCpnt))
-		dma_unmap_sg(lu->ud->ne->host->device.parent,
-			     scsi_sglist(cmd->Current_SCpnt),
-			     scsi_sg_count(cmd->Current_SCpnt),
-			     cmd->Current_SCpnt->sc_data_direction);
-	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
-}
-
-/*
- * Is lu valid? Is the 1394 node still present?
- */
-static inline int sbp2util_node_is_available(struct sbp2_lu *lu)
-{
-	return lu && lu->ne && !lu->ne->in_limbo;
-}
-
-/*********************************************
- * IEEE-1394 core driver stack related section
- *********************************************/
-
-static int sbp2_probe(struct device *dev)
-{
-	struct unit_directory *ud;
-	struct sbp2_lu *lu;
-
-	ud = container_of(dev, struct unit_directory, device);
-
-	/* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
-	 * instead. */
-	if (ud->flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY)
-		return -ENODEV;
-
-	lu = sbp2_alloc_device(ud);
-	if (!lu)
-		return -ENOMEM;
-
-	sbp2_parse_unit_directory(lu, ud);
-	return sbp2_start_device(lu);
-}
-
-static int sbp2_remove(struct device *dev)
-{
-	struct unit_directory *ud;
-	struct sbp2_lu *lu;
-	struct scsi_device *sdev;
-
-	ud = container_of(dev, struct unit_directory, device);
-	lu = dev_get_drvdata(&ud->device);
-	if (!lu)
-		return 0;
-
-	if (lu->shost) {
-		/* Get rid of enqueued commands if there is no chance to
-		 * send them. */
-		if (!sbp2util_node_is_available(lu))
-			sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT);
-		/* scsi_remove_device() may trigger shutdown functions of SCSI
-		 * highlevel drivers which would deadlock if blocked. */
-		atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN);
-		scsi_unblock_requests(lu->shost);
-	}
-	sdev = lu->sdev;
-	if (sdev) {
-		lu->sdev = NULL;
-		scsi_remove_device(sdev);
-	}
-
-	sbp2_logout_device(lu);
-	sbp2_remove_device(lu);
-
-	return 0;
-}
-
-static int sbp2_update(struct unit_directory *ud)
-{
-	struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
-
-	if (sbp2_reconnect_device(lu) != 0) {
-		/*
-		 * Reconnect failed.  If another bus reset happened,
-		 * let nodemgr proceed and call sbp2_update again later
-		 * (or sbp2_remove if this node went away).
-		 */
-		if (!hpsb_node_entry_valid(lu->ne))
-			return 0;
-		/*
-		 * Or the target rejected the reconnect because we weren't
-		 * fast enough.  Try a regular login, but first log out
-		 * just in case of any weirdness.
-		 */
-		sbp2_logout_device(lu);
-
-		if (sbp2_login_device(lu) != 0) {
-			if (!hpsb_node_entry_valid(lu->ne))
-				return 0;
-
-			/* Maybe another initiator won the login. */
-			SBP2_ERR("Failed to reconnect to sbp2 device!");
-			return -EBUSY;
-		}
-	}
-
-	sbp2_set_busy_timeout(lu);
-	sbp2_agent_reset(lu, 1);
-	sbp2_max_speed_and_size(lu);
-
-	/* Complete any pending commands with busy (so they get retried)
-	 * and remove them from our queue. */
-	sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-
-	/* Accept new commands unless there was another bus reset in the
-	 * meantime. */
-	if (hpsb_node_entry_valid(lu->ne)) {
-		atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
-		scsi_unblock_requests(lu->shost);
-	}
-	return 0;
-}
-
-static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
-{
-	struct sbp2_fwhost_info *hi;
-	struct Scsi_Host *shost = NULL;
-	struct sbp2_lu *lu = NULL;
-	unsigned long flags;
-
-	lu = kzalloc(sizeof(*lu), GFP_KERNEL);
-	if (!lu) {
-		SBP2_ERR("failed to create lu");
-		goto failed_alloc;
-	}
-
-	lu->ne = ud->ne;
-	lu->ud = ud;
-	lu->speed_code = IEEE1394_SPEED_100;
-	lu->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
-	lu->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
-	INIT_LIST_HEAD(&lu->cmd_orb_inuse);
-	INIT_LIST_HEAD(&lu->cmd_orb_completed);
-	INIT_LIST_HEAD(&lu->lu_list);
-	spin_lock_init(&lu->cmd_orb_lock);
-	atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
-	INIT_WORK(&lu->protocol_work, NULL);
-
-	dev_set_drvdata(&ud->device, lu);
-
-	hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
-	if (!hi) {
-		hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host,
-					  sizeof(*hi));
-		if (!hi) {
-			SBP2_ERR("failed to allocate hostinfo");
-			goto failed_alloc;
-		}
-		hi->host = ud->ne->host;
-		INIT_LIST_HEAD(&hi->logical_units);
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-		/* Handle data movement if physical dma is not
-		 * enabled or not supported on host controller */
-		if (!hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host,
-					     &sbp2_physdma_ops,
-					     0x0ULL, 0xfffffffcULL)) {
-			SBP2_ERR("failed to register lower 4GB address range");
-			goto failed_alloc;
-		}
-#endif
-	}
-
-	if (dma_get_max_seg_size(hi->host->device.parent) > SBP2_MAX_SEG_SIZE)
-		BUG_ON(dma_set_max_seg_size(hi->host->device.parent,
-					    SBP2_MAX_SEG_SIZE));
-
-	/* Prevent unloading of the 1394 host */
-	if (!try_module_get(hi->host->driver->owner)) {
-		SBP2_ERR("failed to get a reference on 1394 host driver");
-		goto failed_alloc;
-	}
-
-	lu->hi = hi;
-
-	write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-	list_add_tail(&lu->lu_list, &hi->logical_units);
-	write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-	/* Register the status FIFO address range. We could use the same FIFO
-	 * for targets at different nodes. However we need different FIFOs per
-	 * target in order to support multi-unit devices.
-	 * The FIFO is located out of the local host controller's physical range
-	 * but, if possible, within the posted write area. Status writes will
-	 * then be performed as unified transactions. This slightly reduces
-	 * bandwidth usage, and some Prolific based devices seem to require it.
-	 */
-	lu->status_fifo_addr = hpsb_allocate_and_register_addrspace(
-			&sbp2_highlevel, ud->ne->host, &sbp2_ops,
-			sizeof(struct sbp2_status_block), sizeof(quadlet_t),
-			ud->ne->host->low_addr_space, CSR1212_ALL_SPACE_END);
-	if (lu->status_fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
-		SBP2_ERR("failed to allocate status FIFO address range");
-		goto failed_alloc;
-	}
-
-	shost = scsi_host_alloc(&sbp2_shost_template, sizeof(unsigned long));
-	if (!shost) {
-		SBP2_ERR("failed to register scsi host");
-		goto failed_alloc;
-	}
-
-	shost->hostdata[0] = (unsigned long)lu;
-	shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
-
-	if (!scsi_add_host(shost, &ud->device)) {
-		lu->shost = shost;
-		return lu;
-	}
-
-	SBP2_ERR("failed to add scsi host");
-	scsi_host_put(shost);
-
-failed_alloc:
-	sbp2_remove_device(lu);
-	return NULL;
-}
-
-static void sbp2_host_reset(struct hpsb_host *host)
-{
-	struct sbp2_fwhost_info *hi;
-	struct sbp2_lu *lu;
-	unsigned long flags;
-
-	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-	if (!hi)
-		return;
-
-	read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-
-	list_for_each_entry(lu, &hi->logical_units, lu_list)
-		if (atomic_cmpxchg(&lu->state,
-				   SBP2LU_STATE_RUNNING, SBP2LU_STATE_IN_RESET)
-		    == SBP2LU_STATE_RUNNING)
-			scsi_block_requests(lu->shost);
-
-	read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-}
-
-static int sbp2_start_device(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	int error;
-
-	lu->login_response = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_login_response),
-				     &lu->login_response_dma, GFP_KERNEL);
-	if (!lu->login_response)
-		goto alloc_fail;
-
-	lu->query_logins_orb = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_query_logins_orb),
-				     &lu->query_logins_orb_dma, GFP_KERNEL);
-	if (!lu->query_logins_orb)
-		goto alloc_fail;
-
-	lu->query_logins_response = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_query_logins_response),
-				     &lu->query_logins_response_dma, GFP_KERNEL);
-	if (!lu->query_logins_response)
-		goto alloc_fail;
-
-	lu->reconnect_orb = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_reconnect_orb),
-				     &lu->reconnect_orb_dma, GFP_KERNEL);
-	if (!lu->reconnect_orb)
-		goto alloc_fail;
-
-	lu->logout_orb = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_logout_orb),
-				     &lu->logout_orb_dma, GFP_KERNEL);
-	if (!lu->logout_orb)
-		goto alloc_fail;
-
-	lu->login_orb = dma_alloc_coherent(hi->host->device.parent,
-				     sizeof(struct sbp2_login_orb),
-				     &lu->login_orb_dma, GFP_KERNEL);
-	if (!lu->login_orb)
-		goto alloc_fail;
-
-	if (sbp2util_create_command_orb_pool(lu))
-		goto alloc_fail;
-
-	/* Wait a second before trying to log in. Previously logged in
-	 * initiators need a chance to reconnect. */
-	if (msleep_interruptible(1000)) {
-		sbp2_remove_device(lu);
-		return -EINTR;
-	}
-
-	if (sbp2_login_device(lu)) {
-		sbp2_remove_device(lu);
-		return -EBUSY;
-	}
-
-	sbp2_set_busy_timeout(lu);
-	sbp2_agent_reset(lu, 1);
-	sbp2_max_speed_and_size(lu);
-
-	if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
-		ssleep(SBP2_INQUIRY_DELAY);
-
-	error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
-	if (error) {
-		SBP2_ERR("scsi_add_device failed");
-		sbp2_logout_device(lu);
-		sbp2_remove_device(lu);
-		return error;
-	}
-
-	return 0;
-
-alloc_fail:
-	SBP2_ERR("Could not allocate memory for lu");
-	sbp2_remove_device(lu);
-	return -ENOMEM;
-}
-
-static void sbp2_remove_device(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi;
-	unsigned long flags;
-
-	if (!lu)
-		return;
-	hi = lu->hi;
-	if (!hi)
-		goto no_hi;
-
-	if (lu->shost) {
-		scsi_remove_host(lu->shost);
-		scsi_host_put(lu->shost);
-	}
-	flush_scheduled_work();
-	sbp2util_remove_command_orb_pool(lu, hi->host);
-
-	write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-	list_del(&lu->lu_list);
-	write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-	if (lu->login_response)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_login_response),
-				    lu->login_response,
-				    lu->login_response_dma);
-	if (lu->login_orb)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_login_orb),
-				    lu->login_orb,
-				    lu->login_orb_dma);
-	if (lu->reconnect_orb)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_reconnect_orb),
-				    lu->reconnect_orb,
-				    lu->reconnect_orb_dma);
-	if (lu->logout_orb)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_logout_orb),
-				    lu->logout_orb,
-				    lu->logout_orb_dma);
-	if (lu->query_logins_orb)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_query_logins_orb),
-				    lu->query_logins_orb,
-				    lu->query_logins_orb_dma);
-	if (lu->query_logins_response)
-		dma_free_coherent(hi->host->device.parent,
-				    sizeof(struct sbp2_query_logins_response),
-				    lu->query_logins_response,
-				    lu->query_logins_response_dma);
-
-	if (lu->status_fifo_addr != CSR1212_INVALID_ADDR_SPACE)
-		hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
-					  lu->status_fifo_addr);
-
-	dev_set_drvdata(&lu->ud->device, NULL);
-
-	module_put(hi->host->driver->owner);
-no_hi:
-	kfree(lu);
-}
-
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
-/*
- * Deal with write requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid,
-				     int destid, quadlet_t *data, u64 addr,
-				     size_t length, u16 flags)
-{
-	memcpy(bus_to_virt((u32) addr), data, length);
-	return RCODE_COMPLETE;
-}
-
-/*
- * Deal with read requests on adapters which do not support physical DMA or
- * have it switched off.
- */
-static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid,
-				    quadlet_t *data, u64 addr, size_t length,
-				    u16 flags)
-{
-	memcpy(data, bus_to_virt((u32) addr), length);
-	return RCODE_COMPLETE;
-}
-#endif
-
-/**************************************
- * SBP-2 protocol related section
- **************************************/
-
-static int sbp2_query_logins(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	quadlet_t data[2];
-	int max_logins;
-	int active_logins;
-
-	lu->query_logins_orb->reserved1 = 0x0;
-	lu->query_logins_orb->reserved2 = 0x0;
-
-	lu->query_logins_orb->query_response_lo = lu->query_logins_response_dma;
-	lu->query_logins_orb->query_response_hi =
-			ORB_SET_NODE_ID(hi->host->node_id);
-	lu->query_logins_orb->lun_misc =
-			ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
-	lu->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
-	lu->query_logins_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
-	lu->query_logins_orb->reserved_resp_length =
-		ORB_SET_QUERY_LOGINS_RESP_LENGTH(
-			sizeof(struct sbp2_query_logins_response));
-
-	lu->query_logins_orb->status_fifo_hi =
-		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-	lu->query_logins_orb->status_fifo_lo =
-		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-	sbp2util_cpu_to_be32_buffer(lu->query_logins_orb,
-				    sizeof(struct sbp2_query_logins_orb));
-
-	memset(lu->query_logins_response, 0,
-	       sizeof(struct sbp2_query_logins_response));
-
-	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-	data[1] = lu->query_logins_orb_dma;
-	sbp2util_cpu_to_be32_buffer(data, 8);
-
-	hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
-	if (sbp2util_access_timeout(lu, 2*HZ)) {
-		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	if (lu->status_block.ORB_offset_lo != lu->query_logins_orb_dma) {
-		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-		SBP2_INFO("Error querying logins to SBP-2 device - failed");
-		return -EIO;
-	}
-
-	sbp2util_cpu_to_be32_buffer(lu->query_logins_response,
-				    sizeof(struct sbp2_query_logins_response));
-
-	max_logins = RESPONSE_GET_MAX_LOGINS(
-			lu->query_logins_response->length_max_logins);
-	SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
-
-	active_logins = RESPONSE_GET_ACTIVE_LOGINS(
-			lu->query_logins_response->length_max_logins);
-	SBP2_INFO("Number of active logins: %d", active_logins);
-
-	if (active_logins >= max_logins) {
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int sbp2_login_device(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	quadlet_t data[2];
-
-	if (!lu->login_orb)
-		return -EIO;
-
-	if (!sbp2_exclusive_login && sbp2_query_logins(lu)) {
-		SBP2_INFO("Device does not support any more concurrent logins");
-		return -EIO;
-	}
-
-	/* assume no password */
-	lu->login_orb->password_hi = 0;
-	lu->login_orb->password_lo = 0;
-
-	lu->login_orb->login_response_lo = lu->login_response_dma;
-	lu->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
-	lu->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
-
-	/* one second reconnect time */
-	lu->login_orb->lun_misc |= ORB_SET_RECONNECT(0);
-	lu->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);
-	lu->login_orb->lun_misc |= ORB_SET_NOTIFY(1);
-	lu->login_orb->lun_misc |= ORB_SET_LUN(lu->lun);
-
-	lu->login_orb->passwd_resp_lengths =
-		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
-
-	lu->login_orb->status_fifo_hi =
-		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-	lu->login_orb->status_fifo_lo =
-		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-	sbp2util_cpu_to_be32_buffer(lu->login_orb,
-				    sizeof(struct sbp2_login_orb));
-
-	memset(lu->login_response, 0, sizeof(struct sbp2_login_response));
-
-	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-	data[1] = lu->login_orb_dma;
-	sbp2util_cpu_to_be32_buffer(data, 8);
-
-	hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-
-	/* wait up to 20 seconds for login status */
-	if (sbp2util_access_timeout(lu, 20*HZ)) {
-		SBP2_ERR("Error logging into SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	/* make sure that the returned status matches the login ORB */
-	if (lu->status_block.ORB_offset_lo != lu->login_orb_dma) {
-		SBP2_ERR("Error logging into SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-		SBP2_ERR("Error logging into SBP-2 device - failed");
-		return -EIO;
-	}
-
-	sbp2util_cpu_to_be32_buffer(lu->login_response,
-				    sizeof(struct sbp2_login_response));
-	lu->command_block_agent_addr =
-			((u64)lu->login_response->command_block_agent_hi) << 32;
-	lu->command_block_agent_addr |=
-			((u64)lu->login_response->command_block_agent_lo);
-	lu->command_block_agent_addr &= 0x0000ffffffffffffULL;
-
-	SBP2_INFO("Logged into SBP-2 device");
-	return 0;
-}
-
-static int sbp2_logout_device(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	quadlet_t data[2];
-	int error;
-
-	lu->logout_orb->reserved1 = 0x0;
-	lu->logout_orb->reserved2 = 0x0;
-	lu->logout_orb->reserved3 = 0x0;
-	lu->logout_orb->reserved4 = 0x0;
-
-	lu->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
-	lu->logout_orb->login_ID_misc |=
-			ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
-	lu->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
-	lu->logout_orb->reserved5 = 0x0;
-	lu->logout_orb->status_fifo_hi =
-		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-	lu->logout_orb->status_fifo_lo =
-		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-	sbp2util_cpu_to_be32_buffer(lu->logout_orb,
-				    sizeof(struct sbp2_logout_orb));
-
-	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-	data[1] = lu->logout_orb_dma;
-	sbp2util_cpu_to_be32_buffer(data, 8);
-
-	error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-	if (error)
-		return error;
-
-	/* wait up to 1 second for the device to complete logout */
-	if (sbp2util_access_timeout(lu, HZ))
-		return -EIO;
-
-	SBP2_INFO("Logged out of SBP-2 device");
-	return 0;
-}
-
-static int sbp2_reconnect_device(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	quadlet_t data[2];
-	int error;
-
-	lu->reconnect_orb->reserved1 = 0x0;
-	lu->reconnect_orb->reserved2 = 0x0;
-	lu->reconnect_orb->reserved3 = 0x0;
-	lu->reconnect_orb->reserved4 = 0x0;
-
-	lu->reconnect_orb->login_ID_misc =
-			ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
-	lu->reconnect_orb->login_ID_misc |=
-			ORB_SET_LOGIN_ID(lu->login_response->length_login_ID);
-	lu->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
-
-	lu->reconnect_orb->reserved5 = 0x0;
-	lu->reconnect_orb->status_fifo_hi =
-		ORB_SET_STATUS_FIFO_HI(lu->status_fifo_addr, hi->host->node_id);
-	lu->reconnect_orb->status_fifo_lo =
-		ORB_SET_STATUS_FIFO_LO(lu->status_fifo_addr);
-
-	sbp2util_cpu_to_be32_buffer(lu->reconnect_orb,
-				    sizeof(struct sbp2_reconnect_orb));
-
-	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-	data[1] = lu->reconnect_orb_dma;
-	sbp2util_cpu_to_be32_buffer(data, 8);
-
-	error = hpsb_node_write(lu->ne, lu->management_agent_addr, data, 8);
-	if (error)
-		return error;
-
-	/* wait up to 1 second for reconnect status */
-	if (sbp2util_access_timeout(lu, HZ)) {
-		SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	/* make sure that the returned status matches the reconnect ORB */
-	if (lu->status_block.ORB_offset_lo != lu->reconnect_orb_dma) {
-		SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
-		return -EIO;
-	}
-
-	if (STATUS_TEST_RDS(lu->status_block.ORB_offset_hi_misc)) {
-		SBP2_ERR("Error reconnecting to SBP-2 device - failed");
-		return -EIO;
-	}
-
-	SBP2_INFO("Reconnected to SBP-2 device");
-	return 0;
-}
-
-/*
- * Set the target node's Single Phase Retry limit. Affects the target's retry
- * behaviour if our node is too busy to accept requests.
- */
-static int sbp2_set_busy_timeout(struct sbp2_lu *lu)
-{
-	quadlet_t data;
-
-	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);
-	if (hpsb_node_write(lu->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4))
-		SBP2_ERR("%s error", __func__);
-	return 0;
-}
-
-static void sbp2_parse_unit_directory(struct sbp2_lu *lu,
-				      struct unit_directory *ud)
-{
-	struct csr1212_keyval *kv;
-	struct csr1212_dentry *dentry;
-	u64 management_agent_addr;
-	u32 firmware_revision, model;
-	unsigned workarounds;
-	int i;
-
-	management_agent_addr = 0;
-	firmware_revision = SBP2_ROM_VALUE_MISSING;
-	model = ud->flags & UNIT_DIRECTORY_MODEL_ID ?
-				ud->model_id : SBP2_ROM_VALUE_MISSING;
-
-	csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
-		switch (kv->key.id) {
-		case CSR1212_KV_ID_DEPENDENT_INFO:
-			if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET)
-				management_agent_addr =
-				    CSR1212_REGISTER_SPACE_BASE +
-				    (kv->value.csr_offset << 2);
-
-			else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE)
-				lu->lun = ORB_SET_LUN(kv->value.immediate);
-			break;
-
-
-		case SBP2_FIRMWARE_REVISION_KEY:
-			firmware_revision = kv->value.immediate;
-			break;
-
-		default:
-			/* FIXME: Check for SBP2_UNIT_CHARACTERISTICS_KEY
-			 * mgt_ORB_timeout and ORB_size, SBP-2 clause 7.4.8. */
-
-			/* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
-			 * Its "ordered" bit has consequences for command ORB
-			 * list handling. See SBP-2 clauses 4.6, 7.4.11, 10.2 */
-			break;
-		}
-	}
-
-	workarounds = sbp2_default_workarounds;
-
-	if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
-		for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
-			if (sbp2_workarounds_table[i].firmware_revision !=
-			    SBP2_ROM_VALUE_WILDCARD &&
-			    sbp2_workarounds_table[i].firmware_revision !=
-			    (firmware_revision & 0xffff00))
-				continue;
-			if (sbp2_workarounds_table[i].model !=
-			    SBP2_ROM_VALUE_WILDCARD &&
-			    sbp2_workarounds_table[i].model != model)
-				continue;
-			workarounds |= sbp2_workarounds_table[i].workarounds;
-			break;
-		}
-
-	if (workarounds)
-		SBP2_INFO("Workarounds for node " NODE_BUS_FMT ": 0x%x "
-			  "(firmware_revision 0x%06x, vendor_id 0x%06x,"
-			  " model_id 0x%06x)",
-			  NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
-			  workarounds, firmware_revision, ud->vendor_id,
-			  model);
-
-	/* We would need one SCSI host template for each target to adjust
-	 * max_sectors on the fly, therefore warn only. */
-	if (workarounds & SBP2_WORKAROUND_128K_MAX_TRANS &&
-	    (sbp2_max_sectors * 512) > (128 * 1024))
-		SBP2_INFO("Node " NODE_BUS_FMT ": Bridge only supports 128KB "
-			  "max transfer size. WARNING: Current max_sectors "
-			  "setting is larger than 128KB (%d sectors)",
-			  NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid),
-			  sbp2_max_sectors);
-
-	/* If this is a logical unit directory entry, process the parent
-	 * to get the values. */
-	if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
-		struct unit_directory *parent_ud = container_of(
-			ud->device.parent, struct unit_directory, device);
-		sbp2_parse_unit_directory(lu, parent_ud);
-	} else {
-		lu->management_agent_addr = management_agent_addr;
-		lu->workarounds = workarounds;
-		if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
-			lu->lun = ORB_SET_LUN(ud->lun);
-	}
-}
-
-#define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
-
-/*
- * This function is called in order to determine the max speed and packet
- * size we can use in our ORBs. Note, that we (the driver and host) only
- * initiate the transaction. The SBP-2 device actually transfers the data
- * (by reading from the DMA area we tell it). This means that the SBP-2
- * device decides the actual maximum data it can transfer. We just tell it
- * the speed that it needs to use, and the max_rec the host supports, and
- * it takes care of the rest.
- */
-static int sbp2_max_speed_and_size(struct sbp2_lu *lu)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	u8 payload;
-
-	lu->speed_code = hi->host->speed[NODEID_TO_NODE(lu->ne->nodeid)];
-
-	if (lu->speed_code > sbp2_max_speed) {
-		lu->speed_code = sbp2_max_speed;
-		SBP2_INFO("Reducing speed to %s",
-			  hpsb_speedto_str[sbp2_max_speed]);
-	}
-
-	/* Payload size is the lesser of what our speed supports and what
-	 * our host supports.  */
-	payload = min(sbp2_speedto_max_payload[lu->speed_code],
-		      (u8) (hi->host->csr.max_rec - 1));
-
-	/* If physical DMA is off, work around limitation in ohci1394:
-	 * packet size must not exceed PAGE_SIZE */
-	if (lu->ne->host->low_addr_space < (1ULL << 32))
-		while (SBP2_PAYLOAD_TO_BYTES(payload) + 24 > PAGE_SIZE &&
-		       payload)
-			payload--;
-
-	SBP2_INFO("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
-		  NODE_BUS_ARGS(hi->host, lu->ne->nodeid),
-		  hpsb_speedto_str[lu->speed_code],
-		  SBP2_PAYLOAD_TO_BYTES(payload));
-
-	lu->max_payload_size = payload;
-	return 0;
-}
-
-static int sbp2_agent_reset(struct sbp2_lu *lu, int wait)
-{
-	quadlet_t data;
-	u64 addr;
-	int retval;
-	unsigned long flags;
-
-	/* flush lu->protocol_work */
-	if (wait)
-		flush_scheduled_work();
-
-	data = ntohl(SBP2_AGENT_RESET_DATA);
-	addr = lu->command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
-
-	if (wait)
-		retval = hpsb_node_write(lu->ne, addr, &data, 4);
-	else
-		retval = sbp2util_node_write_no_wait(lu->ne, addr, &data, 4);
-
-	if (retval < 0) {
-		SBP2_ERR("hpsb_node_write failed.\n");
-		return -EIO;
-	}
-
-	/* make sure that the ORB_POINTER is written on next command */
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	lu->last_orb = NULL;
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-	return 0;
-}
-
-static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
-				    struct sbp2_fwhost_info *hi,
-				    struct sbp2_command_info *cmd,
-				    unsigned int sg_count,
-				    struct scatterlist *sg,
-				    u32 orb_direction,
-				    enum dma_data_direction dma_dir)
-{
-	struct device *dmadev = hi->host->device.parent;
-	struct sbp2_unrestricted_page_table *pt;
-	int i, n;
-
-	n = dma_map_sg(dmadev, sg, sg_count, dma_dir);
-	if (n == 0)
-		return -ENOMEM;
-
-	orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
-	orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
-	/* special case if only one element (and less than 64KB in size) */
-	if (n == 1) {
-		orb->misc |= ORB_SET_DATA_SIZE(sg_dma_len(sg));
-		orb->data_descriptor_lo = sg_dma_address(sg);
-	} else {
-		pt = &cmd->scatter_gather_element[0];
-
-		dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
-					sizeof(cmd->scatter_gather_element),
-					DMA_TO_DEVICE);
-
-		for_each_sg(sg, sg, n, i) {
-			pt[i].high = cpu_to_be32(sg_dma_len(sg) << 16);
-			pt[i].low = cpu_to_be32(sg_dma_address(sg));
-		}
-
-		orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1) |
-			     ORB_SET_DATA_SIZE(n);
-		orb->data_descriptor_lo = cmd->sge_dma;
-
-		dma_sync_single_for_device(dmadev, cmd->sge_dma,
-					   sizeof(cmd->scatter_gather_element),
-					   DMA_TO_DEVICE);
-	}
-	return 0;
-}
-
-static int sbp2_create_command_orb(struct sbp2_lu *lu,
-				   struct sbp2_command_info *cmd,
-				   struct scsi_cmnd *SCpnt)
-{
-	struct device *dmadev = lu->hi->host->device.parent;
-	struct sbp2_command_orb *orb = &cmd->command_orb;
-	unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
-	enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
-	u32 orb_direction;
-	int ret;
-
-	dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma,
-				sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-	/*
-	 * Set-up our command ORB.
-	 *
-	 * NOTE: We're doing unrestricted page tables (s/g), as this is
-	 * best performance (at least with the devices I have). This means
-	 * that data_size becomes the number of s/g elements, and
-	 * page_size should be zero (for unrestricted).
-	 */
-	orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
-	orb->next_ORB_lo = 0x0;
-	orb->misc = ORB_SET_MAX_PAYLOAD(lu->max_payload_size);
-	orb->misc |= ORB_SET_SPEED(lu->speed_code);
-	orb->misc |= ORB_SET_NOTIFY(1);
-
-	if (dma_dir == DMA_NONE)
-		orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
-	else if (dma_dir == DMA_TO_DEVICE && scsi_request_bufflen)
-		orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
-	else if (dma_dir == DMA_FROM_DEVICE && scsi_request_bufflen)
-		orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
-	else {
-		SBP2_INFO("Falling back to DMA_NONE");
-		orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
-	}
-
-	/* set up our page table stuff */
-	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {
-		orb->data_descriptor_hi = 0x0;
-		orb->data_descriptor_lo = 0x0;
-		orb->misc |= ORB_SET_DIRECTION(1);
-		ret = 0;
-	} else {
-		ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd,
-					       scsi_sg_count(SCpnt),
-					       scsi_sglist(SCpnt),
-					       orb_direction, dma_dir);
-	}
-	sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
-
-	memset(orb->cdb, 0, sizeof(orb->cdb));
-	memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-	dma_sync_single_for_device(dmadev, cmd->command_orb_dma,
-			sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
-	return ret;
-}
-
-static void sbp2_link_orb_command(struct sbp2_lu *lu,
-				  struct sbp2_command_info *cmd)
-{
-	struct sbp2_fwhost_info *hi = lu->hi;
-	struct sbp2_command_orb *last_orb;
-	dma_addr_t last_orb_dma;
-	u64 addr = lu->command_block_agent_addr;
-	quadlet_t data[2];
-	size_t length;
-	unsigned long flags;
-
-	/* check to see if there are any previous orbs to use */
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	last_orb = lu->last_orb;
-	last_orb_dma = lu->last_orb_dma;
-	if (!last_orb) {
-		/*
-		 * last_orb == NULL means: We know that the target's fetch agent
-		 * is not active right now.
-		 */
-		addr += SBP2_ORB_POINTER_OFFSET;
-		data[0] = ORB_SET_NODE_ID(hi->host->node_id);
-		data[1] = cmd->command_orb_dma;
-		sbp2util_cpu_to_be32_buffer(data, 8);
-		length = 8;
-	} else {
-		/*
-		 * last_orb != NULL means: We know that the target's fetch agent
-		 * is (very probably) not dead or in reset state right now.
-		 * We have an ORB already sent that we can append a new one to.
-		 * The target's fetch agent may or may not have read this
-		 * previous ORB yet.
-		 */
-		dma_sync_single_for_cpu(hi->host->device.parent, last_orb_dma,
-					sizeof(struct sbp2_command_orb),
-					DMA_TO_DEVICE);
-		last_orb->next_ORB_lo = cpu_to_be32(cmd->command_orb_dma);
-		wmb();
-		/* Tells hardware that this pointer is valid */
-		last_orb->next_ORB_hi = 0;
-		dma_sync_single_for_device(hi->host->device.parent,
-					   last_orb_dma,
-					   sizeof(struct sbp2_command_orb),
-					   DMA_TO_DEVICE);
-		addr += SBP2_DOORBELL_OFFSET;
-		data[0] = 0;
-		length = 4;
-	}
-	lu->last_orb = &cmd->command_orb;
-	lu->last_orb_dma = cmd->command_orb_dma;
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-	if (sbp2util_node_write_no_wait(lu->ne, addr, data, length)) {
-		/*
-		 * sbp2util_node_write_no_wait failed. We certainly ran out
-		 * of transaction labels, perhaps just because there were no
-		 * context switches which gave khpsbpkt a chance to collect
-		 * free tlabels. Try again in non-atomic context. If necessary,
-		 * the workqueue job will sleep to guaranteedly get a tlabel.
-		 * We do not accept new commands until the job is over.
-		 */
-		scsi_block_requests(lu->shost);
-		PREPARE_WORK(&lu->protocol_work,
-			     last_orb ? sbp2util_write_doorbell:
-					sbp2util_write_orb_pointer);
-		schedule_work(&lu->protocol_work);
-	}
-}
-
-static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
-			     void (*done)(struct scsi_cmnd *))
-{
-	struct sbp2_command_info *cmd;
-
-	cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
-	if (!cmd)
-		return -EIO;
-
-	if (sbp2_create_command_orb(lu, cmd, SCpnt))
-		return -ENOMEM;
-
-	sbp2_link_orb_command(lu, cmd);
-	return 0;
-}
-
-/*
- * Translates SBP-2 status into SCSI sense data for check conditions
- */
-static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
-					      unchar *sense_data)
-{
-	/* OK, it's pretty ugly... ;-) */
-	sense_data[0] = 0x70;
-	sense_data[1] = 0x0;
-	sense_data[2] = sbp2_status[9];
-	sense_data[3] = sbp2_status[12];
-	sense_data[4] = sbp2_status[13];
-	sense_data[5] = sbp2_status[14];
-	sense_data[6] = sbp2_status[15];
-	sense_data[7] = 10;
-	sense_data[8] = sbp2_status[16];
-	sense_data[9] = sbp2_status[17];
-	sense_data[10] = sbp2_status[18];
-	sense_data[11] = sbp2_status[19];
-	sense_data[12] = sbp2_status[10];
-	sense_data[13] = sbp2_status[11];
-	sense_data[14] = sbp2_status[20];
-	sense_data[15] = sbp2_status[21];
-
-	return sbp2_status[8] & 0x3f;
-}
-
-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
-				    int destid, quadlet_t *data, u64 addr,
-				    size_t length, u16 fl)
-{
-	struct sbp2_fwhost_info *hi;
-	struct sbp2_lu *lu = NULL, *lu_tmp;
-	struct scsi_cmnd *SCpnt = NULL;
-	struct sbp2_status_block *sb;
-	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
-	struct sbp2_command_info *cmd;
-	unsigned long flags;
-
-	if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
-		SBP2_ERR("Wrong size of status block");
-		return RCODE_ADDRESS_ERROR;
-	}
-	if (unlikely(!host)) {
-		SBP2_ERR("host is NULL - this is bad!");
-		return RCODE_ADDRESS_ERROR;
-	}
-	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-	if (unlikely(!hi)) {
-		SBP2_ERR("host info is NULL - this is bad!");
-		return RCODE_ADDRESS_ERROR;
-	}
-
-	/* Find the unit which wrote the status. */
-	read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
-	list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
-		if (lu_tmp->ne->nodeid == nodeid &&
-		    lu_tmp->status_fifo_addr == addr) {
-			lu = lu_tmp;
-			break;
-		}
-	}
-	read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
-
-	if (unlikely(!lu)) {
-		SBP2_ERR("lu is NULL - device is gone?");
-		return RCODE_ADDRESS_ERROR;
-	}
-
-	/* Put response into lu status fifo buffer. The first two bytes
-	 * come in big endian bit order. Often the target writes only a
-	 * truncated status block, minimally the first two quadlets. The rest
-	 * is implied to be zeros. */
-	sb = &lu->status_block;
-	memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
-	memcpy(sb, data, length);
-	sbp2util_be32_to_cpu_buffer(sb, 8);
-
-	/* Ignore unsolicited status. Handle command ORB status. */
-	if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
-		cmd = NULL;
-	else
-		cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
-	if (cmd) {
-		/* Grab SCSI command pointers and check status. */
-		/*
-		 * FIXME: If the src field in the status is 1, the ORB DMA must
-		 * not be reused until status for a subsequent ORB is received.
-		 */
-		SCpnt = cmd->Current_SCpnt;
-		spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-		sbp2util_mark_command_completed(lu, cmd);
-		spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-		if (SCpnt) {
-			u32 h = sb->ORB_offset_hi_misc;
-			u32 r = STATUS_GET_RESP(h);
-
-			if (r != RESP_STATUS_REQUEST_COMPLETE) {
-				SBP2_INFO("resp 0x%x, sbp_status 0x%x",
-					  r, STATUS_GET_SBP_STATUS(h));
-				scsi_status =
-					r == RESP_STATUS_TRANSPORT_FAILURE ?
-					SBP2_SCSI_STATUS_BUSY :
-					SBP2_SCSI_STATUS_COMMAND_TERMINATED;
-			}
-
-			if (STATUS_GET_LEN(h) > 1)
-				scsi_status = sbp2_status_to_sense_data(
-					(unchar *)sb, SCpnt->sense_buffer);
-
-			if (STATUS_TEST_DEAD(h))
-                                sbp2_agent_reset(lu, 0);
-		}
-
-		/* Check here to see if there are no commands in-use. If there
-		 * are none, we know that the fetch agent left the active state
-		 * _and_ that we did not reactivate it yet. Therefore clear
-		 * last_orb so that next time we write directly to the
-		 * ORB_POINTER register. That way the fetch agent does not need
-		 * to refetch the next_ORB. */
-		spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-		if (list_empty(&lu->cmd_orb_inuse))
-			lu->last_orb = NULL;
-		spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-	} else {
-		/* It's probably status after a management request. */
-		if ((sb->ORB_offset_lo == lu->reconnect_orb_dma) ||
-		    (sb->ORB_offset_lo == lu->login_orb_dma) ||
-		    (sb->ORB_offset_lo == lu->query_logins_orb_dma) ||
-		    (sb->ORB_offset_lo == lu->logout_orb_dma)) {
-			lu->access_complete = 1;
-			wake_up_interruptible(&sbp2_access_wq);
-		}
-	}
-
-	if (SCpnt)
-		sbp2scsi_complete_command(lu, scsi_status, SCpnt,
-					  cmd->Current_done);
-	return RCODE_COMPLETE;
-}
-
-/**************************************
- * SCSI interface related section
- **************************************/
-
-static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
-				 void (*done)(struct scsi_cmnd *))
-{
-	struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-	struct sbp2_fwhost_info *hi;
-	int result = DID_NO_CONNECT << 16;
-
-	if (unlikely(!sbp2util_node_is_available(lu)))
-		goto done;
-
-	hi = lu->hi;
-
-	if (unlikely(!hi)) {
-		SBP2_ERR("sbp2_fwhost_info is NULL - this is bad!");
-		goto done;
-	}
-
-	/* Multiple units are currently represented to the SCSI core as separate
-	 * targets, not as one target with multiple LUs. Therefore return
-	 * selection time-out to any IO directed at non-zero LUNs. */
-	if (unlikely(SCpnt->device->lun))
-		goto done;
-
-	if (unlikely(!hpsb_node_entry_valid(lu->ne))) {
-		SBP2_ERR("Bus reset in progress - rejecting command");
-		result = DID_BUS_BUSY << 16;
-		goto done;
-	}
-
-	/* Bidirectional commands are not yet implemented,
-	 * and unknown transfer direction not handled. */
-	if (unlikely(SCpnt->sc_data_direction == DMA_BIDIRECTIONAL)) {
-		SBP2_ERR("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
-		result = DID_ERROR << 16;
-		goto done;
-	}
-
-	if (sbp2_send_command(lu, SCpnt, done)) {
-		SBP2_ERR("Error sending SCSI command");
-		sbp2scsi_complete_command(lu,
-					  SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
-					  SCpnt, done);
-	}
-	return 0;
-
-done:
-	SCpnt->result = result;
-	done(SCpnt);
-	return 0;
-}
-
-static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
-{
-	struct list_head *lh;
-	struct sbp2_command_info *cmd;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-	while (!list_empty(&lu->cmd_orb_inuse)) {
-		lh = lu->cmd_orb_inuse.next;
-		cmd = list_entry(lh, struct sbp2_command_info, list);
-		sbp2util_mark_command_completed(lu, cmd);
-		if (cmd->Current_SCpnt) {
-			cmd->Current_SCpnt->result = status << 16;
-			cmd->Current_done(cmd->Current_SCpnt);
-		}
-	}
-	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-	return;
-}
-
-/*
- * Complete a regular SCSI command. Can be called in atomic context.
- */
-static void sbp2scsi_complete_command(struct sbp2_lu *lu, u32 scsi_status,
-				      struct scsi_cmnd *SCpnt,
-				      void (*done)(struct scsi_cmnd *))
-{
-	if (!SCpnt) {
-		SBP2_ERR("SCpnt is NULL");
-		return;
-	}
-
-	switch (scsi_status) {
-	case SBP2_SCSI_STATUS_GOOD:
-		SCpnt->result = DID_OK << 16;
-		break;
-
-	case SBP2_SCSI_STATUS_BUSY:
-		SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
-		SCpnt->result = DID_BUS_BUSY << 16;
-		break;
-
-	case SBP2_SCSI_STATUS_CHECK_CONDITION:
-		SCpnt->result = CHECK_CONDITION << 1 | DID_OK << 16;
-		break;
-
-	case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
-		SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
-		SCpnt->result = DID_NO_CONNECT << 16;
-		scsi_print_command(SCpnt);
-		break;
-
-	case SBP2_SCSI_STATUS_CONDITION_MET:
-	case SBP2_SCSI_STATUS_RESERVATION_CONFLICT:
-	case SBP2_SCSI_STATUS_COMMAND_TERMINATED:
-		SBP2_ERR("Bad SCSI status = %x", scsi_status);
-		SCpnt->result = DID_ERROR << 16;
-		scsi_print_command(SCpnt);
-		break;
-
-	default:
-		SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
-		SCpnt->result = DID_ERROR << 16;
-	}
-
-	/* If a bus reset is in progress and there was an error, complete
-	 * the command as busy so that it will get retried. */
-	if (!hpsb_node_entry_valid(lu->ne)
-	    && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
-		SBP2_ERR("Completing command with busy (bus reset)");
-		SCpnt->result = DID_BUS_BUSY << 16;
-	}
-
-	/* Tell the SCSI stack that we're done with this command. */
-	done(SCpnt);
-}
-
-static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
-{
-	struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
-	if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
-		return -ENODEV;
-
-	lu->sdev = sdev;
-	sdev->allow_restart = 1;
-
-	/* SBP-2 requires quadlet alignment of the data buffers. */
-	blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
-
-	if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
-		sdev->inquiry_len = 36;
-	return 0;
-}
-
-static int sbp2scsi_slave_configure(struct scsi_device *sdev)
-{
-	struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
-
-	sdev->use_10_for_rw = 1;
-
-	if (sbp2_exclusive_login)
-		sdev->manage_start_stop = 1;
-	if (sdev->type == TYPE_ROM)
-		sdev->use_10_for_ms = 1;
-	if (sdev->type == TYPE_DISK &&
-	    lu->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
-		sdev->skip_ms_page_8 = 1;
-	if (lu->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
-		sdev->fix_capacity = 1;
-	if (lu->workarounds & SBP2_WORKAROUND_POWER_CONDITION)
-		sdev->start_stop_pwr_cond = 1;
-	if (lu->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
-		blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
-
-	blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
-	return 0;
-}
-
-static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
-{
-	((struct sbp2_lu *)sdev->host->hostdata[0])->sdev = NULL;
-	return;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- * Usually called when a command has timed-out for some reason.
- */
-static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
-{
-	struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-	struct sbp2_command_info *cmd;
-	unsigned long flags;
-
-	SBP2_INFO("aborting sbp2 command");
-	scsi_print_command(SCpnt);
-
-	if (sbp2util_node_is_available(lu)) {
-		sbp2_agent_reset(lu, 1);
-
-		/* Return a matching command structure to the free pool. */
-		spin_lock_irqsave(&lu->cmd_orb_lock, flags);
-		cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
-		if (cmd) {
-			sbp2util_mark_command_completed(lu, cmd);
-			if (cmd->Current_SCpnt) {
-				cmd->Current_SCpnt->result = DID_ABORT << 16;
-				cmd->Current_done(cmd->Current_SCpnt);
-			}
-		}
-		spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
-
-		sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);
-	}
-
-	return SUCCESS;
-}
-
-/*
- * Called by scsi stack when something has really gone wrong.
- */
-static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
-{
-	struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
-
-	SBP2_INFO("reset requested");
-
-	if (sbp2util_node_is_available(lu)) {
-		SBP2_INFO("generating sbp2 fetch agent reset");
-		sbp2_agent_reset(lu, 1);
-	}
-
-	return SUCCESS;
-}
-
-static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev,
-					   struct device_attribute *attr,
-					   char *buf)
-{
-	struct scsi_device *sdev;
-	struct sbp2_lu *lu;
-
-	if (!(sdev = to_scsi_device(dev)))
-		return 0;
-
-	if (!(lu = (struct sbp2_lu *)sdev->host->hostdata[0]))
-		return 0;
-
-	if (sbp2_long_sysfs_ieee1394_id)
-		return sprintf(buf, "%016Lx:%06x:%04x\n",
-				(unsigned long long)lu->ne->guid,
-				lu->ud->directory_id, ORB_SET_LUN(lu->lun));
-	else
-		return sprintf(buf, "%016Lx:%d:%d\n",
-				(unsigned long long)lu->ne->guid,
-				lu->ud->id, ORB_SET_LUN(lu->lun));
-}
-
-MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
-MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
-MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
-MODULE_LICENSE("GPL");
-
-static int sbp2_module_init(void)
-{
-	int ret;
-
-	if (sbp2_serialize_io) {
-		sbp2_shost_template.can_queue = 1;
-		sbp2_shost_template.cmd_per_lun = 1;
-	}
-
-	sbp2_shost_template.max_sectors = sbp2_max_sectors;
-
-	hpsb_register_highlevel(&sbp2_highlevel);
-	ret = hpsb_register_protocol(&sbp2_driver);
-	if (ret) {
-		SBP2_ERR("Failed to register protocol");
-		hpsb_unregister_highlevel(&sbp2_highlevel);
-		return ret;
-	}
-	return 0;
-}
-
-static void __exit sbp2_module_exit(void)
-{
-	hpsb_unregister_protocol(&sbp2_driver);
-	hpsb_unregister_highlevel(&sbp2_highlevel);
-}
-
-module_init(sbp2_module_init);
-module_exit(sbp2_module_exit);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/sbp2.h linux-libre-2.6.37-gnu/drivers/ieee1394/sbp2.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/sbp2.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/sbp2.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,346 +0,0 @@
-/*
- * sbp2.h - Defines and prototypes for sbp2.c
- *
- * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
- * jamesg@filanet.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef SBP2_H
-#define SBP2_H
-
-#define SBP2_DEVICE_NAME		"sbp2"
-
-/*
- * There is no transport protocol limit to the CDB length,  but we implement
- * a fixed length only.  16 bytes is enough for disks larger than 2 TB.
- */
-#define SBP2_MAX_CDB_SIZE		16
-
-/*
- * SBP-2 specific definitions
- */
-
-#define ORB_DIRECTION_WRITE_TO_MEDIA	0x0
-#define ORB_DIRECTION_READ_FROM_MEDIA	0x1
-#define ORB_DIRECTION_NO_DATA_TRANSFER	0x2
-
-#define ORB_SET_NULL_PTR(v)		(((v) & 0x1) << 31)
-#define ORB_SET_NOTIFY(v)		(((v) & 0x1) << 31)
-#define ORB_SET_RQ_FMT(v)		(((v) & 0x3) << 29)
-#define ORB_SET_NODE_ID(v)		(((v) & 0xffff) << 16)
-#define ORB_SET_STATUS_FIFO_HI(v, id)	((v) >> 32 | ORB_SET_NODE_ID(id))
-#define ORB_SET_STATUS_FIFO_LO(v)	((v) & 0xffffffff)
-#define ORB_SET_DATA_SIZE(v)		((v) & 0xffff)
-#define ORB_SET_PAGE_SIZE(v)		(((v) & 0x7) << 16)
-#define ORB_SET_PAGE_TABLE_PRESENT(v)	(((v) & 0x1) << 19)
-#define ORB_SET_MAX_PAYLOAD(v)		(((v) & 0xf) << 20)
-#define ORB_SET_SPEED(v)		(((v) & 0x7) << 24)
-#define ORB_SET_DIRECTION(v)		(((v) & 0x1) << 27)
-
-struct sbp2_command_orb {
-	u32 next_ORB_hi;
-	u32 next_ORB_lo;
-	u32 data_descriptor_hi;
-	u32 data_descriptor_lo;
-	u32 misc;
-	u8 cdb[SBP2_MAX_CDB_SIZE];
-} __attribute__((packed));
-
-#define SBP2_LOGIN_REQUEST		0x0
-#define SBP2_QUERY_LOGINS_REQUEST	0x1
-#define SBP2_RECONNECT_REQUEST		0x3
-#define SBP2_SET_PASSWORD_REQUEST	0x4
-#define SBP2_LOGOUT_REQUEST		0x7
-#define SBP2_ABORT_TASK_REQUEST		0xb
-#define SBP2_ABORT_TASK_SET		0xc
-#define SBP2_LOGICAL_UNIT_RESET		0xe
-#define SBP2_TARGET_RESET_REQUEST	0xf
-
-#define ORB_SET_LUN(v)			((v) & 0xffff)
-#define ORB_SET_FUNCTION(v)		(((v) & 0xf) << 16)
-#define ORB_SET_RECONNECT(v)		(((v) & 0xf) << 20)
-#define ORB_SET_EXCLUSIVE(v)		((v) ? 1 << 28 : 0)
-#define ORB_SET_LOGIN_RESP_LENGTH(v)	((v) & 0xffff)
-#define ORB_SET_PASSWD_LENGTH(v)	(((v) & 0xffff) << 16)
-
-struct sbp2_login_orb {
-	u32 password_hi;
-	u32 password_lo;
-	u32 login_response_hi;
-	u32 login_response_lo;
-	u32 lun_misc;
-	u32 passwd_resp_lengths;
-	u32 status_fifo_hi;
-	u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_LOGIN_ID(v)	((v) & 0xffff)
-#define RESPONSE_GET_LENGTH(v)		(((v) >> 16) & 0xffff)
-#define RESPONSE_GET_RECONNECT_HOLD(v)	((v) & 0xffff)
-
-struct sbp2_login_response {
-	u32 length_login_ID;
-	u32 command_block_agent_hi;
-	u32 command_block_agent_lo;
-	u32 reconnect_hold;
-} __attribute__((packed));
-
-#define ORB_SET_LOGIN_ID(v)                 ((v) & 0xffff)
-#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
-
-struct sbp2_query_logins_orb {
-	u32 reserved1;
-	u32 reserved2;
-	u32 query_response_hi;
-	u32 query_response_lo;
-	u32 lun_misc;
-	u32 reserved_resp_length;
-	u32 status_fifo_hi;
-	u32 status_fifo_lo;
-} __attribute__((packed));
-
-#define RESPONSE_GET_MAX_LOGINS(v)	((v) & 0xffff)
-#define RESPONSE_GET_ACTIVE_LOGINS(v)	((RESPONSE_GET_LENGTH((v)) - 4) / 12)
-
-struct sbp2_query_logins_response {
-	u32 length_max_logins;
-	u32 misc_IDs;
-	u32 initiator_misc_hi;
-	u32 initiator_misc_lo;
-} __attribute__((packed));
-
-struct sbp2_reconnect_orb {
-	u32 reserved1;
-	u32 reserved2;
-	u32 reserved3;
-	u32 reserved4;
-	u32 login_ID_misc;
-	u32 reserved5;
-	u32 status_fifo_hi;
-	u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_logout_orb {
-	u32 reserved1;
-	u32 reserved2;
-	u32 reserved3;
-	u32 reserved4;
-	u32 login_ID_misc;
-	u32 reserved5;
-	u32 status_fifo_hi;
-	u32 status_fifo_lo;
-} __attribute__((packed));
-
-struct sbp2_unrestricted_page_table {
-	__be32 high;
-	__be32 low;
-};
-
-#define RESP_STATUS_REQUEST_COMPLETE		0x0
-#define RESP_STATUS_TRANSPORT_FAILURE		0x1
-#define RESP_STATUS_ILLEGAL_REQUEST		0x2
-#define RESP_STATUS_VENDOR_DEPENDENT		0x3
-
-#define SBP2_STATUS_NO_ADDITIONAL_INFO		0x0
-#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED	0x1
-#define SBP2_STATUS_SPEED_NOT_SUPPORTED		0x2
-#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED	0x3
-#define SBP2_STATUS_ACCESS_DENIED		0x4
-#define SBP2_STATUS_LU_NOT_SUPPORTED		0x5
-#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL	0x6
-#define SBP2_STATUS_RESOURCES_UNAVAILABLE	0x8
-#define SBP2_STATUS_FUNCTION_REJECTED		0x9
-#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED	0xa
-#define SBP2_STATUS_DUMMY_ORB_COMPLETED		0xb
-#define SBP2_STATUS_REQUEST_ABORTED		0xc
-#define SBP2_STATUS_UNSPECIFIED_ERROR		0xff
-
-#define SFMT_CURRENT_ERROR			0x0
-#define SFMT_DEFERRED_ERROR			0x1
-#define SFMT_VENDOR_DEPENDENT_STATUS		0x3
-
-#define STATUS_GET_SRC(v)			(((v) >> 30) & 0x3)
-#define STATUS_GET_RESP(v)			(((v) >> 28) & 0x3)
-#define STATUS_GET_LEN(v)			(((v) >> 24) & 0x7)
-#define STATUS_GET_SBP_STATUS(v)		(((v) >> 16) & 0xff)
-#define STATUS_GET_ORB_OFFSET_HI(v)		((v) & 0x0000ffff)
-#define STATUS_TEST_DEAD(v)			((v) & 0x08000000)
-/* test 'resp' | 'dead' | 'sbp2_status' */
-#define STATUS_TEST_RDS(v)			((v) & 0x38ff0000)
-
-struct sbp2_status_block {
-	u32 ORB_offset_hi_misc;
-	u32 ORB_offset_lo;
-	u8 command_set_dependent[24];
-} __attribute__((packed));
-
-
-/*
- * SBP2 related configuration ROM definitions
- */
-
-#define SBP2_UNIT_DIRECTORY_OFFSET_KEY		0xd1
-#define SBP2_CSR_OFFSET_KEY			0x54
-#define SBP2_UNIT_SPEC_ID_KEY			0x12
-#define SBP2_UNIT_SW_VERSION_KEY		0x13
-#define SBP2_COMMAND_SET_SPEC_ID_KEY		0x38
-#define SBP2_COMMAND_SET_KEY			0x39
-#define SBP2_UNIT_CHARACTERISTICS_KEY		0x3a
-#define SBP2_DEVICE_TYPE_AND_LUN_KEY		0x14
-#define SBP2_FIRMWARE_REVISION_KEY		0x3c
-
-#define SBP2_AGENT_STATE_OFFSET			0x00ULL
-#define SBP2_AGENT_RESET_OFFSET			0x04ULL
-#define SBP2_ORB_POINTER_OFFSET			0x08ULL
-#define SBP2_DOORBELL_OFFSET			0x10ULL
-#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET	0x14ULL
-#define SBP2_UNSOLICITED_STATUS_VALUE		0xf
-
-#define SBP2_BUSY_TIMEOUT_ADDRESS		0xfffff0000210ULL
-/* biggest possible value for Single Phase Retry count is 0xf */
-#define SBP2_BUSY_TIMEOUT_VALUE			0xf
-
-#define SBP2_AGENT_RESET_DATA			0xf
-
-#define SBP2_UNIT_SPEC_ID_ENTRY			0x0000609e
-#define SBP2_SW_VERSION_ENTRY			0x00010483
-
-/*
- * The default maximum s/g segment size of a FireWire controller is
- * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
- * be quadlet-aligned, we set the length limit to 0xffff & ~3.
- */
-#define SBP2_MAX_SEG_SIZE			0xfffc
-
-/*
- * There is no real limitation of the queue depth (i.e. length of the linked
- * list of command ORBs) at the target. The chosen depth is merely an
- * implementation detail of the sbp2 driver.
- */
-#define SBP2_MAX_CMDS				8
-
-#define SBP2_SCSI_STATUS_GOOD			0x0
-#define SBP2_SCSI_STATUS_CHECK_CONDITION	0x2
-#define SBP2_SCSI_STATUS_CONDITION_MET		0x4
-#define SBP2_SCSI_STATUS_BUSY			0x8
-#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT	0x18
-#define SBP2_SCSI_STATUS_COMMAND_TERMINATED	0x22
-#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT	0xff
-
-
-/*
- * Representations of commands and devices
- */
-
-/* Per SCSI command */
-struct sbp2_command_info {
-	struct list_head list;
-	struct sbp2_command_orb command_orb;
-	dma_addr_t command_orb_dma;
-	struct scsi_cmnd *Current_SCpnt;
-	void (*Current_done)(struct scsi_cmnd *);
-
-	/* Also need s/g structure for each sbp2 command */
-	struct sbp2_unrestricted_page_table
-		scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
-	dma_addr_t sge_dma;
-};
-
-/* Per FireWire host */
-struct sbp2_fwhost_info {
-	struct hpsb_host *host;
-	struct list_head logical_units;
-};
-
-/* Per logical unit */
-struct sbp2_lu {
-	/* Operation request blocks */
-	struct sbp2_command_orb *last_orb;
-	dma_addr_t last_orb_dma;
-	struct sbp2_login_orb *login_orb;
-	dma_addr_t login_orb_dma;
-	struct sbp2_login_response *login_response;
-	dma_addr_t login_response_dma;
-	struct sbp2_query_logins_orb *query_logins_orb;
-	dma_addr_t query_logins_orb_dma;
-	struct sbp2_query_logins_response *query_logins_response;
-	dma_addr_t query_logins_response_dma;
-	struct sbp2_reconnect_orb *reconnect_orb;
-	dma_addr_t reconnect_orb_dma;
-	struct sbp2_logout_orb *logout_orb;
-	dma_addr_t logout_orb_dma;
-	struct sbp2_status_block status_block;
-
-	/* How to talk to the unit */
-	u64 management_agent_addr;
-	u64 command_block_agent_addr;
-	u32 speed_code;
-	u32 max_payload_size;
-	u16 lun;
-
-	/* Address for the unit to write status blocks to */
-	u64 status_fifo_addr;
-
-	/* Waitqueue flag for logins, reconnects, logouts, query logins */
-	unsigned int access_complete:1;
-
-	/* Pool of command ORBs for this logical unit */
-	spinlock_t cmd_orb_lock;
-	struct list_head cmd_orb_inuse;
-	struct list_head cmd_orb_completed;
-
-	/* Backlink to FireWire host; list of units attached to the host */
-	struct sbp2_fwhost_info *hi;
-	struct list_head lu_list;
-
-	/* IEEE 1394 core's device representations */
-	struct node_entry *ne;
-	struct unit_directory *ud;
-
-	/* SCSI core's device representations */
-	struct scsi_device *sdev;
-	struct Scsi_Host *shost;
-
-	/* Device specific workarounds/brokeness */
-	unsigned workarounds;
-
-	/* Connection state */
-	atomic_t state;
-
-	/* For deferred requests to the fetch agent */
-	struct work_struct protocol_work;
-};
-
-/* For use in sbp2_lu.state */
-enum sbp2lu_state_types {
-	SBP2LU_STATE_RUNNING,		/* all normal */
-	SBP2LU_STATE_IN_RESET,		/* between bus reset and reconnect */
-	SBP2LU_STATE_IN_SHUTDOWN	/* when sbp2_remove was called */
-};
-
-/* For use in sbp2_lu.workarounds and in the corresponding
- * module load parameter */
-#define SBP2_WORKAROUND_128K_MAX_TRANS	0x1
-#define SBP2_WORKAROUND_INQUIRY_36	0x2
-#define SBP2_WORKAROUND_MODE_SENSE_8	0x4
-#define SBP2_WORKAROUND_FIX_CAPACITY	0x8
-#define SBP2_WORKAROUND_DELAY_INQUIRY	0x10
-#define SBP2_INQUIRY_DELAY		12
-#define SBP2_WORKAROUND_POWER_CONDITION	0x20
-#define SBP2_WORKAROUND_OVERRIDE	0x100
-
-#endif /* SBP2_H */
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/video1394.c linux-libre-2.6.37-gnu/drivers/ieee1394/video1394.c
--- linux-libre-2.6.36-gnu/drivers/ieee1394/video1394.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/video1394.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,1528 +0,0 @@
-/*
- * video1394.c - video driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * NOTES:
- *
- * ioctl return codes:
- * EFAULT is only for invalid address for the argp
- * EINVAL for out of range values
- * EBUSY when trying to use an already used resource
- * ESRCH when trying to free/stop a not used resource
- * EAGAIN for resource allocation failure that could perhaps succeed later
- * ENOTTY for unsupported ioctl request
- *
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/timex.h>
-#include <linux/mm.h>
-#include <linux/compat.h>
-#include <linux/cdev.h>
-
-#include "dma.h"
-#include "highlevel.h"
-#include "hosts.h"
-#include "ieee1394.h"
-#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
-#include "ieee1394_types.h"
-#include "nodemgr.h"
-#include "ohci1394.h"
-#include "video1394.h"
-
-#define ISO_CHANNELS 64
-
-struct it_dma_prg {
-	struct dma_cmd begin;
-	quadlet_t data[4];
-	struct dma_cmd end;
-	quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
-};
-
-struct dma_iso_ctx {
-	struct ti_ohci *ohci;
-	int type; /* OHCI_ISO_TRANSMIT or OHCI_ISO_RECEIVE */
-	struct ohci1394_iso_tasklet iso_tasklet;
-	int channel;
-	int ctx;
-	int last_buffer;
-	int * next_buffer;  /* For ISO Transmit of video packets
-			       to write the correct SYT field
-			       into the next block */
-	unsigned int num_desc;
-	unsigned int buf_size;
-	unsigned int frame_size;
-	unsigned int packet_size;
-	unsigned int left_size;
-	unsigned int nb_cmd;
-
-	struct dma_region dma;
-
-	struct dma_prog_region *prg_reg;
-
-        struct dma_cmd **ir_prg;
-	struct it_dma_prg **it_prg;
-
-	unsigned int *buffer_status;
-	unsigned int *buffer_prg_assignment;
-        struct timeval *buffer_time; /* time when the buffer was received */
-	unsigned int *last_used_cmd; /* For ISO Transmit with
-					variable sized packets only ! */
-	int ctrlClear;
-	int ctrlSet;
-	int cmdPtr;
-	int ctxMatch;
-	wait_queue_head_t waitq;
-	spinlock_t lock;
-	unsigned int syt_offset;
-	int flags;
-
-	struct list_head link;
-};
-
-
-struct file_ctx {
-	struct ti_ohci *ohci;
-	struct list_head context_list;
-	struct dma_iso_ctx *current_ctx;
-};
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define VIDEO1394_DEBUG
-#endif
-
-#ifdef DBGMSG
-#undef DBGMSG
-#endif
-
-#ifdef VIDEO1394_DEBUG
-#define DBGMSG(card, fmt, args...) \
-printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
-#else
-#define DBGMSG(card, fmt, args...) do {} while (0)
-#endif
-
-/* print general (card independent) information */
-#define PRINT_G(level, fmt, args...) \
-printk(level "video1394: " fmt "\n" , ## args)
-
-/* print card specific information */
-#define PRINT(level, card, fmt, args...) \
-printk(level "video1394_%d: " fmt "\n" , card , ## args)
-
-static void wakeup_dma_ir_ctx(unsigned long l);
-static void wakeup_dma_it_ctx(unsigned long l);
-
-static struct hpsb_highlevel video1394_highlevel;
-
-static int free_dma_iso_ctx(struct dma_iso_ctx *d)
-{
-	int i;
-
-	DBGMSG(d->ohci->host->id, "Freeing dma_iso_ctx %d", d->ctx);
-
-	ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
-	if (d->iso_tasklet.link.next != NULL)
-		ohci1394_unregister_iso_tasklet(d->ohci, &d->iso_tasklet);
-
-	dma_region_free(&d->dma);
-
-	if (d->prg_reg) {
-		for (i = 0; i < d->num_desc; i++)
-			dma_prog_region_free(&d->prg_reg[i]);
-		kfree(d->prg_reg);
-	}
-
-	kfree(d->ir_prg);
-	kfree(d->it_prg);
-	kfree(d->buffer_status);
-	kfree(d->buffer_prg_assignment);
-	kfree(d->buffer_time);
-	kfree(d->last_used_cmd);
-	kfree(d->next_buffer);
-	list_del(&d->link);
-	kfree(d);
-
-	return 0;
-}
-
-static struct dma_iso_ctx *
-alloc_dma_iso_ctx(struct ti_ohci *ohci, int type, int num_desc,
-		  int buf_size, int channel, unsigned int packet_size)
-{
-	struct dma_iso_ctx *d;
-	int i;
-
-	d = kzalloc(sizeof(*d), GFP_KERNEL);
-	if (!d) {
-		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma_iso_ctx");
-		return NULL;
-	}
-
-	d->ohci = ohci;
-	d->type = type;
-	d->channel = channel;
-	d->num_desc = num_desc;
-	d->frame_size = buf_size;
-	d->buf_size = PAGE_ALIGN(buf_size);
-	d->last_buffer = -1;
-	INIT_LIST_HEAD(&d->link);
-	init_waitqueue_head(&d->waitq);
-
-	/* Init the regions for easy cleanup */
-	dma_region_init(&d->dma);
-
-	if (dma_region_alloc(&d->dma, (d->num_desc - 1) * d->buf_size, ohci->dev,
-			     PCI_DMA_BIDIRECTIONAL)) {
-		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma buffer");
-		free_dma_iso_ctx(d);
-		return NULL;
-	}
-
-	if (type == OHCI_ISO_RECEIVE)
-		ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
-					  wakeup_dma_ir_ctx,
-					  (unsigned long) d);
-	else
-		ohci1394_init_iso_tasklet(&d->iso_tasklet, type,
-					  wakeup_dma_it_ctx,
-					  (unsigned long) d);
-
-	if (ohci1394_register_iso_tasklet(ohci, &d->iso_tasklet) < 0) {
-		PRINT(KERN_ERR, ohci->host->id, "no free iso %s contexts",
-		      type == OHCI_ISO_RECEIVE ? "receive" : "transmit");
-		free_dma_iso_ctx(d);
-		return NULL;
-	}
-	d->ctx = d->iso_tasklet.context;
-
-	d->prg_reg = kmalloc(d->num_desc * sizeof(*d->prg_reg), GFP_KERNEL);
-	if (!d->prg_reg) {
-		PRINT(KERN_ERR, ohci->host->id, "Failed to allocate ir prg regs");
-		free_dma_iso_ctx(d);
-		return NULL;
-	}
-	/* Makes for easier cleanup */
-	for (i = 0; i < d->num_desc; i++)
-		dma_prog_region_init(&d->prg_reg[i]);
-
-	if (type == OHCI_ISO_RECEIVE) {
-		d->ctrlSet = OHCI1394_IsoRcvContextControlSet+32*d->ctx;
-		d->ctrlClear = OHCI1394_IsoRcvContextControlClear+32*d->ctx;
-		d->cmdPtr = OHCI1394_IsoRcvCommandPtr+32*d->ctx;
-		d->ctxMatch = OHCI1394_IsoRcvContextMatch+32*d->ctx;
-
-		d->ir_prg = kzalloc(d->num_desc * sizeof(*d->ir_prg),
-				    GFP_KERNEL);
-
-		if (!d->ir_prg) {
-			PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
-			free_dma_iso_ctx(d);
-			return NULL;
-		}
-
-		d->nb_cmd = d->buf_size / PAGE_SIZE + 1;
-		d->left_size = (d->frame_size % PAGE_SIZE) ?
-			d->frame_size % PAGE_SIZE : PAGE_SIZE;
-
-		for (i = 0;i < d->num_desc; i++) {
-			if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
-						  sizeof(struct dma_cmd), ohci->dev)) {
-				PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma ir prg");
-				free_dma_iso_ctx(d);
-				return NULL;
-			}
-			d->ir_prg[i] = (struct dma_cmd *)d->prg_reg[i].kvirt;
-		}
-
-	} else {  /* OHCI_ISO_TRANSMIT */
-		d->ctrlSet = OHCI1394_IsoXmitContextControlSet+16*d->ctx;
-		d->ctrlClear = OHCI1394_IsoXmitContextControlClear+16*d->ctx;
-		d->cmdPtr = OHCI1394_IsoXmitCommandPtr+16*d->ctx;
-
-		d->it_prg = kzalloc(d->num_desc * sizeof(*d->it_prg),
-				    GFP_KERNEL);
-
-		if (!d->it_prg) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Failed to allocate dma it prg");
-			free_dma_iso_ctx(d);
-			return NULL;
-		}
-
-		d->packet_size = packet_size;
-
-		if (PAGE_SIZE % packet_size || packet_size>4096) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Packet size %d (page_size: %ld) "
-			      "not yet supported\n",
-			      packet_size, PAGE_SIZE);
-			free_dma_iso_ctx(d);
-			return NULL;
-		}
-
-		d->nb_cmd = d->frame_size / d->packet_size;
-		if (d->frame_size % d->packet_size) {
-			d->nb_cmd++;
-			d->left_size = d->frame_size % d->packet_size;
-		} else
-			d->left_size = d->packet_size;
-
-		for (i = 0; i < d->num_desc; i++) {
-			if (dma_prog_region_alloc(&d->prg_reg[i], d->nb_cmd *
-						sizeof(struct it_dma_prg), ohci->dev)) {
-				PRINT(KERN_ERR, ohci->host->id, "Failed to allocate dma it prg");
-				free_dma_iso_ctx(d);
-				return NULL;
-			}
-			d->it_prg[i] = (struct it_dma_prg *)d->prg_reg[i].kvirt;
-		}
-	}
-
-	d->buffer_status =
-	    kzalloc(d->num_desc * sizeof(*d->buffer_status), GFP_KERNEL);
-	d->buffer_prg_assignment =
-	    kzalloc(d->num_desc * sizeof(*d->buffer_prg_assignment), GFP_KERNEL);
-	d->buffer_time =
-	    kzalloc(d->num_desc * sizeof(*d->buffer_time), GFP_KERNEL);
-	d->last_used_cmd =
-	    kzalloc(d->num_desc * sizeof(*d->last_used_cmd), GFP_KERNEL);
-	d->next_buffer =
-	    kzalloc(d->num_desc * sizeof(*d->next_buffer), GFP_KERNEL);
-
-	if (!d->buffer_status || !d->buffer_prg_assignment || !d->buffer_time ||
-	    !d->last_used_cmd || !d->next_buffer) {
-		PRINT(KERN_ERR, ohci->host->id,
-		      "Failed to allocate dma_iso_ctx member");
-		free_dma_iso_ctx(d);
-		return NULL;
-	}
-
-        spin_lock_init(&d->lock);
-
-	DBGMSG(ohci->host->id, "Iso %s DMA: %d buffers "
-	      "of size %d allocated for a frame size %d, each with %d prgs",
-	      (type == OHCI_ISO_RECEIVE) ? "receive" : "transmit",
-	      d->num_desc - 1, d->buf_size, d->frame_size, d->nb_cmd);
-
-	return d;
-}
-
-static void reset_ir_status(struct dma_iso_ctx *d, int n)
-{
-	int i;
-	d->ir_prg[n][0].status = cpu_to_le32(4);
-	d->ir_prg[n][1].status = cpu_to_le32(PAGE_SIZE-4);
-	for (i = 2; i < d->nb_cmd - 1; i++)
-		d->ir_prg[n][i].status = cpu_to_le32(PAGE_SIZE);
-	d->ir_prg[n][i].status = cpu_to_le32(d->left_size);
-}
-
-static void reprogram_dma_ir_prg(struct dma_iso_ctx *d, int n, int buffer, int flags)
-{
-	struct dma_cmd *ir_prg = d->ir_prg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
-	int i;
-
-	d->buffer_prg_assignment[n] = buffer;
-
-	ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
-  	                        (unsigned long)d->dma.kvirt));
-	ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-				(buf + 4) - (unsigned long)d->dma.kvirt));
-
-	for (i=2;i<d->nb_cmd-1;i++) {
-		ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-						(buf+(i-1)*PAGE_SIZE) -
-						(unsigned long)d->dma.kvirt));
-	}
-
-	ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-				  DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
-	ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-				  (buf+(i-1)*PAGE_SIZE) - (unsigned long)d->dma.kvirt));
-}
-
-static void initialize_dma_ir_prg(struct dma_iso_ctx *d, int n, int flags)
-{
-	struct dma_cmd *ir_prg = d->ir_prg[n];
-	struct dma_prog_region *ir_reg = &d->prg_reg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt;
-	int i;
-
-	/* the first descriptor will read only 4 bytes */
-	ir_prg[0].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-		DMA_CTL_BRANCH | 4);
-
-	/* set the sync flag */
-	if (flags & VIDEO1394_SYNC_FRAMES)
-		ir_prg[0].control |= cpu_to_le32(DMA_CTL_WAIT);
-
-	ir_prg[0].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, buf -
-				(unsigned long)d->dma.kvirt));
-	ir_prg[0].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-					1 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
-	/* If there is *not* only one DMA page per frame (hence, d->nb_cmd==2) */
-	if (d->nb_cmd > 2) {
-		/* The second descriptor will read PAGE_SIZE-4 bytes */
-		ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-						DMA_CTL_BRANCH | (PAGE_SIZE-4));
-		ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf + 4) -
-						(unsigned long)d->dma.kvirt));
-		ir_prg[1].branchAddress = cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-						      2 * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-
-		for (i = 2; i < d->nb_cmd - 1; i++) {
-			ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-							DMA_CTL_BRANCH | PAGE_SIZE);
-			ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-							(buf+(i-1)*PAGE_SIZE) -
-							(unsigned long)d->dma.kvirt));
-
-			ir_prg[i].branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(ir_reg,
-					    (i + 1) * sizeof(struct dma_cmd)) & 0xfffffff0) | 0x1);
-		}
-
-		/* The last descriptor will generate an interrupt */
-		ir_prg[i].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-						DMA_CTL_IRQ | DMA_CTL_BRANCH | d->left_size);
-		ir_prg[i].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-						(buf+(i-1)*PAGE_SIZE) -
-						(unsigned long)d->dma.kvirt));
-	} else {
-		/* Only one DMA page is used. Read d->left_size immediately and */
-		/* generate an interrupt as this is also the last page. */
-		ir_prg[1].control = cpu_to_le32(DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE |
-						DMA_CTL_IRQ | DMA_CTL_BRANCH | (d->left_size-4));
-		ir_prg[1].address = cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-						(buf + 4) - (unsigned long)d->dma.kvirt));
-	}
-}
-
-static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
-{
-	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
-	int i;
-
-	d->flags = flags;
-
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-	for (i=0;i<d->num_desc;i++) {
-		initialize_dma_ir_prg(d, i, flags);
-		reset_ir_status(d, i);
-	}
-
-	/* reset the ctrl register */
-	reg_write(ohci, d->ctrlClear, 0xf0000000);
-
-	/* Set bufferFill */
-	reg_write(ohci, d->ctrlSet, 0x80000000);
-
-	/* Set isoch header */
-	if (flags & VIDEO1394_INCLUDE_ISO_HEADERS)
-		reg_write(ohci, d->ctrlSet, 0x40000000);
-
-	/* Set the context match register to match on all tags,
-	   sync for sync tag, and listen to d->channel */
-	reg_write(ohci, d->ctxMatch, 0xf0000000|((tag&0xf)<<8)|d->channel);
-
-	/* Set up isoRecvIntMask to generate interrupts */
-	reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1<<d->ctx);
-}
-
-/* find which context is listening to this channel */
-static struct dma_iso_ctx *
-find_ctx(struct list_head *list, int type, int channel)
-{
-	struct dma_iso_ctx *ctx;
-
-	list_for_each_entry(ctx, list, link) {
-		if (ctx->type == type && ctx->channel == channel)
-			return ctx;
-	}
-
-	return NULL;
-}
-
-static void wakeup_dma_ir_ctx(unsigned long l)
-{
-	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
-	int i;
-
-	spin_lock(&d->lock);
-
-	for (i = 0; i < d->num_desc; i++) {
-		if (d->ir_prg[i][d->nb_cmd-1].status & cpu_to_le32(0xFFFF0000)) {
-			reset_ir_status(d, i);
-			d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
-			do_gettimeofday(&d->buffer_time[d->buffer_prg_assignment[i]]);
-			dma_region_sync_for_cpu(&d->dma,
-				d->buffer_prg_assignment[i] * d->buf_size,
-				d->buf_size);
-		}
-	}
-
-	spin_unlock(&d->lock);
-
-	if (waitqueue_active(&d->waitq))
-		wake_up_interruptible(&d->waitq);
-}
-
-static inline void put_timestamp(struct ti_ohci *ohci, struct dma_iso_ctx * d,
-				 int n)
-{
-	unsigned char* buf = d->dma.kvirt + n * d->buf_size;
-	u32 cycleTimer;
-	u32 timeStamp;
-
-	if (n == -1) {
-	  return;
-	}
-
-	cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-
-	timeStamp = ((cycleTimer & 0x0fff) + d->syt_offset); /* 11059 = 450 us */
-	timeStamp = (timeStamp % 3072 + ((timeStamp / 3072) << 12)
-		+ (cycleTimer & 0xf000)) & 0xffff;
-
-	buf[6] = timeStamp >> 8;
-	buf[7] = timeStamp & 0xff;
-
-    /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
-   	    buf += d->packet_size;
-    	buf[6] = timeStamp >> 8;
-	    buf[7] = timeStamp & 0xff;
-	}
-
-    /* do the next buffer frame too in case of irq latency */
-	n = d->next_buffer[n];
-	if (n == -1) {
-	  return;
-	}
-	buf = d->dma.kvirt + n * d->buf_size;
-
-	timeStamp += (d->last_used_cmd[n] << 12) & 0xffff;
-
-	buf[6] = timeStamp >> 8;
-	buf[7] = timeStamp & 0xff;
-
-    /* if first packet is empty packet, then put timestamp into the next full one too */
-    if ( (le32_to_cpu(d->it_prg[n][0].data[1]) >>16) == 0x008) {
-   	    buf += d->packet_size;
-    	buf[6] = timeStamp >> 8;
-	    buf[7] = timeStamp & 0xff;
-	}
-
-#if 0
-	printk("curr: %d, next: %d, cycleTimer: %08x timeStamp: %08x\n",
-	       curr, n, cycleTimer, timeStamp);
-#endif
-}
-
-static void wakeup_dma_it_ctx(unsigned long l)
-{
-	struct dma_iso_ctx *d = (struct dma_iso_ctx *) l;
-	struct ti_ohci *ohci = d->ohci;
-	int i;
-
-	spin_lock(&d->lock);
-
-	for (i = 0; i < d->num_desc; i++) {
-		if (d->it_prg[i][d->last_used_cmd[i]].end.status &
-		    cpu_to_le32(0xFFFF0000)) {
-			int next = d->next_buffer[i];
-			put_timestamp(ohci, d, next);
-			d->it_prg[i][d->last_used_cmd[i]].end.status = 0;
-			d->buffer_status[d->buffer_prg_assignment[i]] = VIDEO1394_BUFFER_READY;
-		}
-	}
-
-	spin_unlock(&d->lock);
-
-	if (waitqueue_active(&d->waitq))
-		wake_up_interruptible(&d->waitq);
-}
-
-static void reprogram_dma_it_prg(struct dma_iso_ctx  *d, int n, int buffer)
-{
-	struct it_dma_prg *it_prg = d->it_prg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt + buffer * d->buf_size;
-	int i;
-
-	d->buffer_prg_assignment[n] = buffer;
-	for (i=0;i<d->nb_cmd;i++) {
-	  it_prg[i].end.address =
-		cpu_to_le32(dma_region_offset_to_bus(&d->dma,
-			(buf+i*d->packet_size) - (unsigned long)d->dma.kvirt));
-	}
-}
-
-static void initialize_dma_it_prg(struct dma_iso_ctx *d, int n, int sync_tag)
-{
-	struct it_dma_prg *it_prg = d->it_prg[n];
-	struct dma_prog_region *it_reg = &d->prg_reg[n];
-	unsigned long buf = (unsigned long)d->dma.kvirt;
-	int i;
-	d->last_used_cmd[n] = d->nb_cmd - 1;
-	for (i=0;i<d->nb_cmd;i++) {
-
-		it_prg[i].begin.control = cpu_to_le32(DMA_CTL_OUTPUT_MORE |
-			DMA_CTL_IMMEDIATE | 8) ;
-		it_prg[i].begin.address = 0;
-
-		it_prg[i].begin.status = 0;
-
-		it_prg[i].data[0] = cpu_to_le32(
-			(IEEE1394_SPEED_100 << 16)
-			| (/* tag */ 1 << 14)
-			| (d->channel << 8)
-			| (TCODE_ISO_DATA << 4));
-		if (i==0) it_prg[i].data[0] |= cpu_to_le32(sync_tag);
-		it_prg[i].data[1] = cpu_to_le32(d->packet_size << 16);
-		it_prg[i].data[2] = 0;
-		it_prg[i].data[3] = 0;
-
-		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST |
-			    	    	     DMA_CTL_BRANCH);
-		it_prg[i].end.address =
-			cpu_to_le32(dma_region_offset_to_bus(&d->dma, (buf+i*d->packet_size) -
-						(unsigned long)d->dma.kvirt));
-
-		if (i<d->nb_cmd-1) {
-			it_prg[i].end.control |= cpu_to_le32(d->packet_size);
-			it_prg[i].begin.branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-			it_prg[i].end.branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-		} else {
-			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
-				DMA_CTL_IRQ | d->left_size);
-			/* the last prg doesn't branch */
-			it_prg[i].begin.branchAddress = 0;
-			it_prg[i].end.branchAddress = 0;
-		}
-		it_prg[i].end.status = 0;
-	}
-}
-
-static void initialize_dma_it_prg_var_packet_queue(
-	struct dma_iso_ctx *d, int n, unsigned int * packet_sizes,
-	struct ti_ohci *ohci)
-{
-	struct it_dma_prg *it_prg = d->it_prg[n];
-	struct dma_prog_region *it_reg = &d->prg_reg[n];
-	int i;
-
-#if 0
-	if (n != -1) {
-		put_timestamp(ohci, d, n);
-	}
-#endif
-	d->last_used_cmd[n] = d->nb_cmd - 1;
-
-	for (i = 0; i < d->nb_cmd; i++) {
-		unsigned int size;
-		if (packet_sizes[i] > d->packet_size) {
-			size = d->packet_size;
-		} else {
-			size = packet_sizes[i];
-		}
-		it_prg[i].data[1] = cpu_to_le32(size << 16);
-		it_prg[i].end.control = cpu_to_le32(DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH);
-
-		if (i < d->nb_cmd-1 && packet_sizes[i+1] != 0) {
-			it_prg[i].end.control |= cpu_to_le32(size);
-			it_prg[i].begin.branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-			it_prg[i].end.branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(it_reg, (i + 1) *
-					sizeof(struct it_dma_prg)) & 0xfffffff0) | 0x3);
-		} else {
-			/* the last prg generates an interrupt */
-			it_prg[i].end.control |= cpu_to_le32(DMA_CTL_UPDATE |
-				DMA_CTL_IRQ | size);
-			/* the last prg doesn't branch */
-			it_prg[i].begin.branchAddress = 0;
-			it_prg[i].end.branchAddress = 0;
-			d->last_used_cmd[n] = i;
-			break;
-		}
-	}
-}
-
-static void initialize_dma_it_ctx(struct dma_iso_ctx *d, int sync_tag,
-				  unsigned int syt_offset, int flags)
-{
-	struct ti_ohci *ohci = (struct ti_ohci *)d->ohci;
-	int i;
-
-	d->flags = flags;
-	d->syt_offset = (syt_offset == 0 ? 11000 : syt_offset);
-
-	ohci1394_stop_context(ohci, d->ctrlClear, NULL);
-
-	for (i=0;i<d->num_desc;i++)
-		initialize_dma_it_prg(d, i, sync_tag);
-
-	/* Set up isoRecvIntMask to generate interrupts */
-	reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1<<d->ctx);
-}
-
-static inline unsigned video1394_buffer_state(struct dma_iso_ctx *d,
-					      unsigned int buffer)
-{
-	unsigned long flags;
-	unsigned int ret;
-	spin_lock_irqsave(&d->lock, flags);
-	ret = d->buffer_status[buffer];
-	spin_unlock_irqrestore(&d->lock, flags);
-	return ret;
-}
-
-static long video1394_ioctl(struct file *file,
-			    unsigned int cmd, unsigned long arg)
-{
-	struct file_ctx *ctx = file->private_data;
-	struct ti_ohci *ohci = ctx->ohci;
-	unsigned long flags;
-	void __user *argp = (void __user *)arg;
-
-	switch(cmd)
-	{
-	case VIDEO1394_IOC_LISTEN_CHANNEL:
-	case VIDEO1394_IOC_TALK_CHANNEL:
-	{
-		struct video1394_mmap v;
-		u64 mask;
-		struct dma_iso_ctx *d;
-		int i;
-
-		if (copy_from_user(&v, argp, sizeof(v)))
-			return -EFAULT;
-
-		/* if channel < 0, find lowest available one */
-		if (v.channel < 0) {
-		    mask = (u64)0x1;
-		    for (i=0; ; i++) {
-			if (i == ISO_CHANNELS) {
-			    PRINT(KERN_ERR, ohci->host->id, 
-				  "No free channel found");
-			    return -EAGAIN;
-			}
-			if (!(ohci->ISO_channel_usage & mask)) {
-			    v.channel = i;
-			    PRINT(KERN_INFO, ohci->host->id, "Found free channel %d", i);
-			    break;
-			}
-			mask = mask << 1;
-		    }
-		} else if (v.channel >= ISO_CHANNELS) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Iso channel %d out of bounds", v.channel);
-			return -EINVAL;
-		} else {
-			mask = (u64)0x1<<v.channel;
-		}
-		DBGMSG(ohci->host->id, "mask: %08X%08X usage: %08X%08X\n",
-			(u32)(mask>>32),(u32)(mask&0xffffffff),
-			(u32)(ohci->ISO_channel_usage>>32),
-			(u32)(ohci->ISO_channel_usage&0xffffffff));
-		if (ohci->ISO_channel_usage & mask) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Channel %d is already taken", v.channel);
-			return -EBUSY;
-		}
-
-		if (v.buf_size == 0 || v.buf_size > VIDEO1394_MAX_SIZE) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Invalid %d length buffer requested",v.buf_size);
-			return -EINVAL;
-		}
-
-		if (v.nb_buffers == 0 || v.nb_buffers > VIDEO1394_MAX_SIZE) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Invalid %d buffers requested",v.nb_buffers);
-			return -EINVAL;
-		}
-
-		if (v.nb_buffers * v.buf_size > VIDEO1394_MAX_SIZE) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "%d buffers of size %d bytes is too big",
-			      v.nb_buffers, v.buf_size);
-			return -EINVAL;
-		}
-
-		if (cmd == VIDEO1394_IOC_LISTEN_CHANNEL) {
-			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_RECEIVE,
-					      v.nb_buffers + 1, v.buf_size,
-					      v.channel, 0);
-
-			if (d == NULL) {
-				PRINT(KERN_ERR, ohci->host->id,
-				      "Couldn't allocate ir context");
-				return -EAGAIN;
-			}
-			initialize_dma_ir_ctx(d, v.sync_tag, v.flags);
-
-			ctx->current_ctx = d;
-
-			v.buf_size = d->buf_size;
-			list_add_tail(&d->link, &ctx->context_list);
-
-			DBGMSG(ohci->host->id,
-			      "iso context %d listen on channel %d",
-			      d->ctx, v.channel);
-		}
-		else {
-			d = alloc_dma_iso_ctx(ohci, OHCI_ISO_TRANSMIT,
-					      v.nb_buffers + 1, v.buf_size,
-					      v.channel, v.packet_size);
-
-			if (d == NULL) {
-				PRINT(KERN_ERR, ohci->host->id,
-				      "Couldn't allocate it context");
-				return -EAGAIN;
-			}
-			initialize_dma_it_ctx(d, v.sync_tag,
-					      v.syt_offset, v.flags);
-
-			ctx->current_ctx = d;
-
-			v.buf_size = d->buf_size;
-
-			list_add_tail(&d->link, &ctx->context_list);
-
-			DBGMSG(ohci->host->id,
-			      "Iso context %d talk on channel %d", d->ctx,
-			      v.channel);
-		}
-
-		if (copy_to_user(argp, &v, sizeof(v))) {
-			/* FIXME : free allocated dma resources */
-			return -EFAULT;
-		}
-		
-		ohci->ISO_channel_usage |= mask;
-
-		return 0;
-	}
-	case VIDEO1394_IOC_UNLISTEN_CHANNEL:
-	case VIDEO1394_IOC_UNTALK_CHANNEL:
-	{
-		int channel;
-		u64 mask;
-		struct dma_iso_ctx *d;
-
-		if (copy_from_user(&channel, argp, sizeof(int)))
-			return -EFAULT;
-
-		if (channel < 0 || channel >= ISO_CHANNELS) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Iso channel %d out of bound", channel);
-			return -EINVAL;
-		}
-		mask = (u64)0x1<<channel;
-		if (!(ohci->ISO_channel_usage & mask)) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Channel %d is not being used", channel);
-			return -ESRCH;
-		}
-
-		/* Mark this channel as unused */
-		ohci->ISO_channel_usage &= ~mask;
-
-		if (cmd == VIDEO1394_IOC_UNLISTEN_CHANNEL)
-			d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, channel);
-		else
-			d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, channel);
-
-		if (d == NULL) return -ESRCH;
-		DBGMSG(ohci->host->id, "Iso context %d "
-		      "stop talking on channel %d", d->ctx, channel);
-		free_dma_iso_ctx(d);
-
-		return 0;
-	}
-	case VIDEO1394_IOC_LISTEN_QUEUE_BUFFER:
-	{
-		struct video1394_wait v;
-		struct dma_iso_ctx *d;
-		int next_prg;
-
-		if (unlikely(copy_from_user(&v, argp, sizeof(v))))
-			return -EFAULT;
-
-		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
-		if (unlikely(d == NULL))
-			return -EFAULT;
-
-		if (unlikely(v.buffer >= d->num_desc - 1)) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d out of range",v.buffer);
-			return -EINVAL;
-		}
-
-		spin_lock_irqsave(&d->lock,flags);
-
-		if (unlikely(d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED)) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d is already used",v.buffer);
-			spin_unlock_irqrestore(&d->lock,flags);
-			return -EBUSY;
-		}
-
-		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
-		next_prg = (d->last_buffer + 1) % d->num_desc;
-		if (d->last_buffer>=0)
-			d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress =
-				cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0)
-					& 0xfffffff0) | 0x1);
-
-		d->last_buffer = next_prg;
-		reprogram_dma_ir_prg(d, d->last_buffer, v.buffer, d->flags);
-
-		d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0;
-
-		spin_unlock_irqrestore(&d->lock,flags);
-
-		if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
-		{
-			DBGMSG(ohci->host->id, "Starting iso DMA ctx=%d",d->ctx);
-
-			/* Tell the controller where the first program is */
-			reg_write(ohci, d->cmdPtr,
-				  dma_prog_region_offset_to_bus(&d->prg_reg[d->last_buffer], 0) | 0x1);
-
-			/* Run IR context */
-			reg_write(ohci, d->ctrlSet, 0x8000);
-		}
-		else {
-			/* Wake up dma context if necessary */
-			if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-				DBGMSG(ohci->host->id,
-				      "Waking up iso dma ctx=%d", d->ctx);
-				reg_write(ohci, d->ctrlSet, 0x1000);
-			}
-		}
-		return 0;
-
-	}
-	case VIDEO1394_IOC_LISTEN_WAIT_BUFFER:
-	case VIDEO1394_IOC_LISTEN_POLL_BUFFER:
-	{
-		struct video1394_wait v;
-		struct dma_iso_ctx *d;
-		int i = 0;
-
-		if (unlikely(copy_from_user(&v, argp, sizeof(v))))
-			return -EFAULT;
-
-		d = find_ctx(&ctx->context_list, OHCI_ISO_RECEIVE, v.channel);
-		if (unlikely(d == NULL))
-			return -EFAULT;
-
-		if (unlikely(v.buffer > d->num_desc - 1)) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d out of range",v.buffer);
-			return -EINVAL;
-		}
-
-		/*
-		 * I change the way it works so that it returns
-		 * the last received frame.
-		 */
-		spin_lock_irqsave(&d->lock, flags);
-		switch(d->buffer_status[v.buffer]) {
-		case VIDEO1394_BUFFER_READY:
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			break;
-		case VIDEO1394_BUFFER_QUEUED:
-			if (cmd == VIDEO1394_IOC_LISTEN_POLL_BUFFER) {
-			    /* for polling, return error code EINTR */
-			    spin_unlock_irqrestore(&d->lock, flags);
-			    return -EINTR;
-			}
-
-			spin_unlock_irqrestore(&d->lock, flags);
-			wait_event_interruptible(d->waitq,
-					video1394_buffer_state(d, v.buffer) ==
-					 VIDEO1394_BUFFER_READY);
-			if (signal_pending(current))
-                                return -EINTR;
-			spin_lock_irqsave(&d->lock, flags);
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			break;
-		default:
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d is not queued",v.buffer);
-			spin_unlock_irqrestore(&d->lock, flags);
-			return -ESRCH;
-		}
-
-		/* set time of buffer */
-		v.filltime = d->buffer_time[v.buffer];
-
-		/*
-		 * Look ahead to see how many more buffers have been received
-		 */
-		i=0;
-		while (d->buffer_status[(v.buffer+1)%(d->num_desc - 1)]==
-		       VIDEO1394_BUFFER_READY) {
-			v.buffer=(v.buffer+1)%(d->num_desc - 1);
-			i++;
-		}
-		spin_unlock_irqrestore(&d->lock, flags);
-
-		v.buffer=i;
-		if (unlikely(copy_to_user(argp, &v, sizeof(v))))
-			return -EFAULT;
-
-		return 0;
-	}
-	case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
-	{
-		struct video1394_wait v;
-		unsigned int *psizes = NULL;
-		struct dma_iso_ctx *d;
-		int next_prg;
-
-		if (copy_from_user(&v, argp, sizeof(v)))
-			return -EFAULT;
-
-		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
-		if (d == NULL) return -EFAULT;
-
-		if (v.buffer >= d->num_desc - 1) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d out of range",v.buffer);
-			return -EINVAL;
-		}
-
-		if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
-			int buf_size = d->nb_cmd * sizeof(*psizes);
-			struct video1394_queue_variable __user *p = argp;
-			unsigned int __user *qv;
-
-			if (get_user(qv, &p->packet_sizes))
-				return -EFAULT;
-
-			psizes = memdup_user(qv, buf_size);
-			if (IS_ERR(psizes))
-				return PTR_ERR(psizes);
-		}
-
-		spin_lock_irqsave(&d->lock,flags);
-
-		/* last_buffer is last_prg */
-		next_prg = (d->last_buffer + 1) % d->num_desc;
-		if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d is already used",v.buffer);
-			spin_unlock_irqrestore(&d->lock,flags);
-			kfree(psizes);
-			return -EBUSY;
-		}
-
-		if (d->flags & VIDEO1394_VARIABLE_PACKET_SIZE) {
-			initialize_dma_it_prg_var_packet_queue(
-				d, next_prg, psizes, ohci);
-		}
-
-		d->buffer_status[v.buffer]=VIDEO1394_BUFFER_QUEUED;
-
-		if (d->last_buffer >= 0) {
-			d->it_prg[d->last_buffer]
-				[ d->last_used_cmd[d->last_buffer] ].end.branchAddress =
-					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
-						0) & 0xfffffff0) | 0x3);
-
-			d->it_prg[d->last_buffer]
-				[ d->last_used_cmd[d->last_buffer] ].begin.branchAddress =
-					cpu_to_le32((dma_prog_region_offset_to_bus(&d->prg_reg[next_prg],
-						0) & 0xfffffff0) | 0x3);
-			d->next_buffer[d->last_buffer] = (v.buffer + 1) % (d->num_desc - 1);
-		}
-		d->last_buffer = next_prg;
-		reprogram_dma_it_prg(d, d->last_buffer, v.buffer);
-		d->next_buffer[d->last_buffer] = -1;
-
-		d->it_prg[d->last_buffer][d->last_used_cmd[d->last_buffer]].end.branchAddress = 0;
-
-		spin_unlock_irqrestore(&d->lock,flags);
-
-		if (!(reg_read(ohci, d->ctrlSet) & 0x8000))
-		{
-			DBGMSG(ohci->host->id, "Starting iso transmit DMA ctx=%d",
-			       d->ctx);
-			put_timestamp(ohci, d, d->last_buffer);
-			dma_region_sync_for_device(&d->dma,
-				v.buffer * d->buf_size, d->buf_size);
-
-			/* Tell the controller where the first program is */
-			reg_write(ohci, d->cmdPtr,
-				dma_prog_region_offset_to_bus(&d->prg_reg[next_prg], 0) | 0x3);
-
-			/* Run IT context */
-			reg_write(ohci, d->ctrlSet, 0x8000);
-		}
-		else {
-			/* Wake up dma context if necessary */
-			if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
-				DBGMSG(ohci->host->id,
-				      "Waking up iso transmit dma ctx=%d",
-				      d->ctx);
-				put_timestamp(ohci, d, d->last_buffer);
-				dma_region_sync_for_device(&d->dma,
-					v.buffer * d->buf_size, d->buf_size);
-
-				reg_write(ohci, d->ctrlSet, 0x1000);
-			}
-		}
-
-		kfree(psizes);
-		return 0;
-
-	}
-	case VIDEO1394_IOC_TALK_WAIT_BUFFER:
-	{
-		struct video1394_wait v;
-		struct dma_iso_ctx *d;
-
-		if (copy_from_user(&v, argp, sizeof(v)))
-			return -EFAULT;
-
-		d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel);
-		if (d == NULL) return -EFAULT;
-
-		if (v.buffer >= d->num_desc - 1) {
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d out of range",v.buffer);
-			return -EINVAL;
-		}
-
-		switch(d->buffer_status[v.buffer]) {
-		case VIDEO1394_BUFFER_READY:
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			return 0;
-		case VIDEO1394_BUFFER_QUEUED:
-			wait_event_interruptible(d->waitq,
-					(d->buffer_status[v.buffer] == VIDEO1394_BUFFER_READY));
-			if (signal_pending(current))
-				return -EINTR;
-			d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE;
-			return 0;
-		default:
-			PRINT(KERN_ERR, ohci->host->id,
-			      "Buffer %d is not queued",v.buffer);
-			return -ESRCH;
-		}
-	}
-	default:
-		return -ENOTTY;
-	}
-}
-
-/*
- *	This maps the vmalloced and reserved buffer to user space.
- *
- *  FIXME:
- *  - PAGE_READONLY should suffice!?
- *  - remap_pfn_range is kind of inefficient for page by page remapping.
- *    But e.g. pte_alloc() does not work in modules ... :-(
- */
-
-static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct file_ctx *ctx = file->private_data;
-
-	if (ctx->current_ctx == NULL) {
-		PRINT(KERN_ERR, ctx->ohci->host->id,
-				"Current iso context not set");
-		return -EINVAL;
-	}
-
-	return dma_region_mmap(&ctx->current_ctx->dma, file, vma);
-}
-
-static unsigned int video1394_poll(struct file *file, poll_table *pt)
-{
-	struct file_ctx *ctx;
-	unsigned int mask = 0;
-	unsigned long flags;
-	struct dma_iso_ctx *d;
-	int i;
-
-	ctx = file->private_data;
-	d = ctx->current_ctx;
-	if (d == NULL) {
-		PRINT(KERN_ERR, ctx->ohci->host->id,
-				"Current iso context not set");
-		return POLLERR;
-	}
-
-	poll_wait(file, &d->waitq, pt);
-
-	spin_lock_irqsave(&d->lock, flags);
-	for (i = 0; i < d->num_desc; i++) {
-		if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
-			mask |= POLLIN | POLLRDNORM;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&d->lock, flags);
-
-	return mask;
-}
-
-static int video1394_open(struct inode *inode, struct file *file)
-{
-	int i = ieee1394_file_to_instance(file);
-	struct ti_ohci *ohci;
-	struct file_ctx *ctx;
-
-	ohci = hpsb_get_hostinfo_bykey(&video1394_highlevel, i);
-        if (ohci == NULL)
-                return -EIO;
-
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)  {
-		PRINT(KERN_ERR, ohci->host->id, "Cannot malloc file_ctx");
-		return -ENOMEM;
-	}
-
-	ctx->ohci = ohci;
-	INIT_LIST_HEAD(&ctx->context_list);
-	ctx->current_ctx = NULL;
-	file->private_data = ctx;
-
-	return nonseekable_open(inode, file);
-}
-
-static int video1394_release(struct inode *inode, struct file *file)
-{
-	struct file_ctx *ctx = file->private_data;
-	struct ti_ohci *ohci = ctx->ohci;
-	struct list_head *lh, *next;
-	u64 mask;
-
-	list_for_each_safe(lh, next, &ctx->context_list) {
-		struct dma_iso_ctx *d;
-		d = list_entry(lh, struct dma_iso_ctx, link);
-		mask = (u64) 1 << d->channel;
-
-		if (!(ohci->ISO_channel_usage & mask))
-			PRINT(KERN_ERR, ohci->host->id, "On release: Channel %d "
-			      "is not being used", d->channel);
-		else
-			ohci->ISO_channel_usage &= ~mask;
-		DBGMSG(ohci->host->id, "On release: Iso %s context "
-		      "%d stop listening on channel %d",
-		      d->type == OHCI_ISO_RECEIVE ? "receive" : "transmit",
-		      d->ctx, d->channel);
-		free_dma_iso_ctx(d);
-	}
-
-	kfree(ctx);
-	file->private_data = NULL;
-
-	return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
-#endif
-
-static struct cdev video1394_cdev;
-static const struct file_operations video1394_fops=
-{
-	.owner =	THIS_MODULE,
-	.unlocked_ioctl = video1394_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = video1394_compat_ioctl,
-#endif
-	.poll =		video1394_poll,
-	.mmap =		video1394_mmap,
-	.open =		video1394_open,
-	.release =	video1394_release,
-	.llseek =	no_llseek,
-};
-
-/*** HOTPLUG STUFF **********************************************************/
-/*
- * Export information about protocols/devices supported by this driver.
- */
-#ifdef MODULE
-static const struct ieee1394_device_id video1394_id_table[] = {
-	{
-		.match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-		.specifier_id	= CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-		.version	= CAMERA_SW_VERSION_ENTRY & 0xffffff
-	},
-        {
-                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-                .version        = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff
-        },
-        {
-                .match_flags    = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
-                .specifier_id   = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
-                .version        = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff
-        },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
-#endif /* MODULE */
-
-static struct hpsb_protocol_driver video1394_driver = {
-	.name = VIDEO1394_DRIVER_NAME,
-};
-
-
-static void video1394_add_host (struct hpsb_host *host)
-{
-	struct ti_ohci *ohci;
-	int minor;
-
-	/* We only work with the OHCI-1394 driver */
-	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
-		return;
-
-	ohci = (struct ti_ohci *)host->hostdata;
-
-	if (!hpsb_create_hostinfo(&video1394_highlevel, host, 0)) {
-		PRINT(KERN_ERR, ohci->host->id, "Cannot allocate hostinfo");
-		return;
-	}
-
-	hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
-	hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->host->id);
-
-	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id;
-	device_create(hpsb_protocol_class, NULL, MKDEV(IEEE1394_MAJOR, minor),
-		      NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
-}
-
-
-static void video1394_remove_host (struct hpsb_host *host)
-{
-	struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
-
-	if (ohci)
-		device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
-			       IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
-	return;
-}
-
-
-static struct hpsb_highlevel video1394_highlevel = {
-	.name =		VIDEO1394_DRIVER_NAME,
-	.add_host =	video1394_add_host,
-	.remove_host =	video1394_remove_host,
-};
-
-MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
-MODULE_DESCRIPTION("driver for digital video on OHCI board");
-MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
-MODULE_LICENSE("GPL");
-
-#ifdef CONFIG_COMPAT
-
-#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER     \
-	_IOW ('#', 0x12, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER      \
-	_IOWR('#', 0x13, struct video1394_wait32)
-#define VIDEO1394_IOC32_TALK_WAIT_BUFFER        \
-	_IOW ('#', 0x17, struct video1394_wait32)
-#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER      \
-	_IOWR('#', 0x18, struct video1394_wait32)
-
-struct video1394_wait32 {
-	u32 channel;
-	u32 buffer;
-	struct compat_timeval filltime;
-};
-
-static int video1394_wr_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        struct video1394_wait32 __user *argp = (void __user *)arg;
-        struct video1394_wait32 wait32;
-        struct video1394_wait wait;
-        mm_segment_t old_fs;
-        int ret;
-
-        if (copy_from_user(&wait32, argp, sizeof(wait32)))
-                return -EFAULT;
-
-        wait.channel = wait32.channel;
-        wait.buffer = wait32.buffer;
-        wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
-        wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
-		ret = video1394_ioctl(file,
-				      VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
-				      (unsigned long) &wait);
-        else
-		ret = video1394_ioctl(file,
-				      VIDEO1394_IOC_LISTEN_POLL_BUFFER,
-				      (unsigned long) &wait);
-        set_fs(old_fs);
-
-        if (!ret) {
-                wait32.channel = wait.channel;
-                wait32.buffer = wait.buffer;
-                wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
-                wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
-
-                if (copy_to_user(argp, &wait32, sizeof(wait32)))
-                        ret = -EFAULT;
-        }
-
-        return ret;
-}
-
-static int video1394_w_wait32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        struct video1394_wait32 wait32;
-        struct video1394_wait wait;
-        mm_segment_t old_fs;
-        int ret;
-
-        if (copy_from_user(&wait32, (void __user *)arg, sizeof(wait32)))
-                return -EFAULT;
-
-        wait.channel = wait32.channel;
-        wait.buffer = wait32.buffer;
-        wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
-        wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
-
-        old_fs = get_fs();
-        set_fs(KERNEL_DS);
-        if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
-		ret = video1394_ioctl(file,
-				      VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
-				      (unsigned long) &wait);
-        else
-		ret = video1394_ioctl(file,
-				      VIDEO1394_IOC_TALK_WAIT_BUFFER,
-				      (unsigned long) &wait);
-        set_fs(old_fs);
-
-        return ret;
-}
-
-static int video1394_queue_buf32(struct file *file, unsigned int cmd, unsigned long arg)
-{
-        return -EFAULT;   /* ??? was there before. */
-
-	return video1394_ioctl(file,
-				VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
-}
-
-static long video1394_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case VIDEO1394_IOC_LISTEN_CHANNEL:
-	case VIDEO1394_IOC_UNLISTEN_CHANNEL:
-	case VIDEO1394_IOC_TALK_CHANNEL:
-	case VIDEO1394_IOC_UNTALK_CHANNEL:
-		return video1394_ioctl(f, cmd, arg);
-
-	case VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER:
-		return video1394_w_wait32(f, cmd, arg);
-	case VIDEO1394_IOC32_LISTEN_WAIT_BUFFER:
-		return video1394_wr_wait32(f, cmd, arg);
-	case VIDEO1394_IOC_TALK_QUEUE_BUFFER:
-		return video1394_queue_buf32(f, cmd, arg);
-	case VIDEO1394_IOC32_TALK_WAIT_BUFFER:
-		return video1394_w_wait32(f, cmd, arg);
-	case VIDEO1394_IOC32_LISTEN_POLL_BUFFER:
-		return video1394_wr_wait32(f, cmd, arg);
-	default:
-		return -ENOIOCTLCMD;
-	}
-}
-
-#endif /* CONFIG_COMPAT */
-
-static void __exit video1394_exit_module (void)
-{
-	hpsb_unregister_protocol(&video1394_driver);
-	hpsb_unregister_highlevel(&video1394_highlevel);
-	cdev_del(&video1394_cdev);
-	PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
-}
-
-static int __init video1394_init_module (void)
-{
-	int ret;
-
-	hpsb_init_highlevel(&video1394_highlevel);
-
-	cdev_init(&video1394_cdev, &video1394_fops);
-	video1394_cdev.owner = THIS_MODULE;
-	ret = cdev_add(&video1394_cdev, IEEE1394_VIDEO1394_DEV, 16);
-	if (ret) {
-		PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
-		return ret;
-        }
-
-	hpsb_register_highlevel(&video1394_highlevel);
-
-	ret = hpsb_register_protocol(&video1394_driver);
-	if (ret) {
-		PRINT_G(KERN_ERR, "video1394: failed to register protocol");
-		hpsb_unregister_highlevel(&video1394_highlevel);
-		cdev_del(&video1394_cdev);
-		return ret;
-	}
-
-	PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
-	return 0;
-}
-
-
-module_init(video1394_init_module);
-module_exit(video1394_exit_module);
diff -druN linux-libre-2.6.36-gnu/drivers/ieee1394/video1394.h linux-libre-2.6.37-gnu/drivers/ieee1394/video1394.h
--- linux-libre-2.6.36-gnu/drivers/ieee1394/video1394.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/ieee1394/video1394.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,67 +0,0 @@
-/*
- * video1394.h - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- *                        Peter Schlaile <udbz@rz.uni-karlsruhe.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _VIDEO_1394_H
-#define _VIDEO_1394_H
-
-#include "ieee1394-ioctl.h"
-
-#define VIDEO1394_DRIVER_NAME "video1394"
-
-#define VIDEO1394_MAX_SIZE 0x4000000
-
-enum {
-	VIDEO1394_BUFFER_FREE = 0,
-	VIDEO1394_BUFFER_QUEUED,
-	VIDEO1394_BUFFER_READY
-};
-
-#define VIDEO1394_SYNC_FRAMES          0x00000001
-#define VIDEO1394_INCLUDE_ISO_HEADERS  0x00000002
-#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
-
-struct video1394_mmap {
-	int channel;			/* -1 to find an open channel in LISTEN/TALK */
-	unsigned int sync_tag;
-	unsigned int nb_buffers;
-	unsigned int buf_size;
-	unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
-				     Maximum packet size */
-	unsigned int fps;
-	unsigned int syt_offset;
-	unsigned int flags;
-};
-
-/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
-struct video1394_queue_variable {
-	unsigned int channel;
-	unsigned int buffer;
-	unsigned int __user * packet_sizes; /* Buffer of size:
-				       buf_size / packet_size  */
-};
-
-struct video1394_wait {
-	unsigned int channel;
-	unsigned int buffer;
-	struct timeval filltime;	/* time of buffer full */
-};
-
-
-#endif
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/agent.c linux-libre-2.6.37-gnu/drivers/infiniband/core/agent.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/agent.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/agent.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,8 +59,8 @@
 	struct ib_agent_port_private *entry;
 
 	list_for_each_entry(entry, &ib_agent_port_list, port_list) {
-		if (entry->agent[0]->device == device &&
-		    entry->agent[0]->port_num == port_num)
+		if (entry->agent[1]->device == device &&
+		    entry->agent[1]->port_num == port_num)
 			return entry;
 	}
 	return NULL;
@@ -155,14 +155,16 @@
 		goto error1;
 	}
 
-	/* Obtain send only MAD agent for SMI QP */
-	port_priv->agent[0] = ib_register_mad_agent(device, port_num,
-						    IB_QPT_SMI, NULL, 0,
-						    &agent_send_handler,
-						    NULL, NULL);
-	if (IS_ERR(port_priv->agent[0])) {
-		ret = PTR_ERR(port_priv->agent[0]);
-		goto error2;
+	if (rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND) {
+		/* Obtain send only MAD agent for SMI QP */
+		port_priv->agent[0] = ib_register_mad_agent(device, port_num,
+							    IB_QPT_SMI, NULL, 0,
+							    &agent_send_handler,
+							    NULL, NULL);
+		if (IS_ERR(port_priv->agent[0])) {
+			ret = PTR_ERR(port_priv->agent[0]);
+			goto error2;
+		}
 	}
 
 	/* Obtain send only MAD agent for GSI QP */
@@ -182,7 +184,8 @@
 	return 0;
 
 error3:
-	ib_unregister_mad_agent(port_priv->agent[0]);
+	if (port_priv->agent[0])
+		ib_unregister_mad_agent(port_priv->agent[0]);
 error2:
 	kfree(port_priv);
 error1:
@@ -205,7 +208,9 @@
 	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
 
 	ib_unregister_mad_agent(port_priv->agent[1]);
-	ib_unregister_mad_agent(port_priv->agent[0]);
+	if (port_priv->agent[0])
+		ib_unregister_mad_agent(port_priv->agent[0]);
+
 	kfree(port_priv);
 	return 0;
 }
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/cma.c linux-libre-2.6.37-gnu/drivers/infiniband/core/cma.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/cma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/cma.c	2011-01-04 19:50:19.000000000 -0500
@@ -59,6 +59,7 @@
 #define CMA_CM_RESPONSE_TIMEOUT 20
 #define CMA_MAX_CM_RETRIES 15
 #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
+#define CMA_IBOE_PACKET_LIFETIME 18
 
 static void cma_add_one(struct ib_device *device);
 static void cma_remove_one(struct ib_device *device);
@@ -157,6 +158,7 @@
 	struct list_head	list;
 	void			*context;
 	struct sockaddr_storage	addr;
+	struct kref		mcref;
 };
 
 struct cma_work {
@@ -173,6 +175,12 @@
 	struct rdma_cm_event	event;
 };
 
+struct iboe_mcast_work {
+	struct work_struct	 work;
+	struct rdma_id_private	*id;
+	struct cma_multicast	*mc;
+};
+
 union cma_ip_addr {
 	struct in6_addr ip6;
 	struct {
@@ -281,6 +289,8 @@
 	atomic_inc(&cma_dev->refcount);
 	id_priv->cma_dev = cma_dev;
 	id_priv->id.device = cma_dev->device;
+	id_priv->id.route.addr.dev_addr.transport =
+		rdma_node_get_transport(cma_dev->device->node_type);
 	list_add_tail(&id_priv->list, &cma_dev->id_list);
 }
 
@@ -290,6 +300,14 @@
 		complete(&cma_dev->comp);
 }
 
+static inline void release_mc(struct kref *kref)
+{
+	struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref);
+
+	kfree(mc->multicast.ib);
+	kfree(mc);
+}
+
 static void cma_detach_from_dev(struct rdma_id_private *id_priv)
 {
 	list_del(&id_priv->list);
@@ -323,22 +341,63 @@
 	return ret;
 }
 
+static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num)
+{
+	int i;
+	int err;
+	struct ib_port_attr props;
+	union ib_gid tmp;
+
+	err = ib_query_port(device, port_num, &props);
+	if (err)
+		return 1;
+
+	for (i = 0; i < props.gid_tbl_len; ++i) {
+		err = ib_query_gid(device, port_num, i, &tmp);
+		if (err)
+			return 1;
+		if (!memcmp(&tmp, gid, sizeof tmp))
+			return 0;
+	}
+
+	return -EAGAIN;
+}
+
 static int cma_acquire_dev(struct rdma_id_private *id_priv)
 {
 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
 	struct cma_device *cma_dev;
-	union ib_gid gid;
+	union ib_gid gid, iboe_gid;
 	int ret = -ENODEV;
+	u8 port;
+	enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
+		IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
 
-	rdma_addr_get_sgid(dev_addr, &gid);
+	iboe_addr_get_sgid(dev_addr, &iboe_gid);
+	memcpy(&gid, dev_addr->src_dev_addr +
+	       rdma_addr_gid_offset(dev_addr), sizeof gid);
 	list_for_each_entry(cma_dev, &dev_list, list) {
-		ret = ib_find_cached_gid(cma_dev->device, &gid,
-					 &id_priv->id.port_num, NULL);
-		if (!ret) {
-			cma_attach_to_dev(id_priv, cma_dev);
-			break;
+		for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
+			if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) {
+				if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB &&
+				    rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET)
+					ret = find_gid_port(cma_dev->device, &iboe_gid, port);
+				else
+					ret = find_gid_port(cma_dev->device, &gid, port);
+
+				if (!ret) {
+					id_priv->id.port_num = port;
+					goto out;
+				} else if (ret == 1)
+					break;
+			}
 		}
 	}
+
+out:
+	if (!ret)
+		cma_attach_to_dev(id_priv, cma_dev);
+
 	return ret;
 }
 
@@ -556,10 +615,16 @@
 {
 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
 	int ret;
+	u16 pkey;
+
+	if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) ==
+	    IB_LINK_LAYER_INFINIBAND)
+		pkey = ib_addr_get_pkey(dev_addr);
+	else
+		pkey = 0xffff;
 
 	ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
-				  ib_addr_get_pkey(dev_addr),
-				  &qp_attr->pkey_index);
+				  pkey, &qp_attr->pkey_index);
 	if (ret)
 		return ret;
 
@@ -737,8 +802,8 @@
 
 static void cma_cancel_route(struct rdma_id_private *id_priv)
 {
-	switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
-	case RDMA_TRANSPORT_IB:
+	switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) {
+	case IB_LINK_LAYER_INFINIBAND:
 		if (id_priv->query)
 			ib_sa_cancel_query(id_priv->query_id, id_priv->query);
 		break;
@@ -816,8 +881,17 @@
 		mc = container_of(id_priv->mc_list.next,
 				  struct cma_multicast, list);
 		list_del(&mc->list);
-		ib_sa_free_multicast(mc->multicast.ib);
-		kfree(mc);
+		switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) {
+		case IB_LINK_LAYER_INFINIBAND:
+			ib_sa_free_multicast(mc->multicast.ib);
+			kfree(mc);
+			break;
+		case IB_LINK_LAYER_ETHERNET:
+			kref_put(&mc->mcref, release_mc);
+			break;
+		default:
+			break;
+		}
 	}
 }
 
@@ -833,7 +907,7 @@
 	mutex_lock(&lock);
 	if (id_priv->cma_dev) {
 		mutex_unlock(&lock);
-		switch (rdma_node_get_transport(id->device->node_type)) {
+		switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
 		case RDMA_TRANSPORT_IB:
 			if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
 				ib_destroy_cm_id(id_priv->cm_id.ib);
@@ -1708,6 +1782,81 @@
 	return 0;
 }
 
+static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
+{
+	struct rdma_route *route = &id_priv->id.route;
+	struct rdma_addr *addr = &route->addr;
+	struct cma_work *work;
+	int ret;
+	struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
+	struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
+	struct net_device *ndev = NULL;
+	u16 vid;
+
+	if (src_addr->sin_family != dst_addr->sin_family)
+		return -EINVAL;
+
+	work = kzalloc(sizeof *work, GFP_KERNEL);
+	if (!work)
+		return -ENOMEM;
+
+	work->id = id_priv;
+	INIT_WORK(&work->work, cma_work_handler);
+
+	route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
+	if (!route->path_rec) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	route->num_paths = 1;
+
+	if (addr->dev_addr.bound_dev_if)
+		ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
+	if (!ndev) {
+		ret = -ENODEV;
+		goto err2;
+	}
+
+	vid = rdma_vlan_dev_vlan_id(ndev);
+
+	iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid);
+	iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid);
+
+	route->path_rec->hop_limit = 1;
+	route->path_rec->reversible = 1;
+	route->path_rec->pkey = cpu_to_be16(0xffff);
+	route->path_rec->mtu_selector = IB_SA_EQ;
+	route->path_rec->sl = id_priv->tos >> 5;
+
+	route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
+	route->path_rec->rate_selector = IB_SA_EQ;
+	route->path_rec->rate = iboe_get_rate(ndev);
+	dev_put(ndev);
+	route->path_rec->packet_life_time_selector = IB_SA_EQ;
+	route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
+	if (!route->path_rec->mtu) {
+		ret = -EINVAL;
+		goto err2;
+	}
+
+	work->old_state = CMA_ROUTE_QUERY;
+	work->new_state = CMA_ROUTE_RESOLVED;
+	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+	work->event.status = 0;
+
+	queue_work(cma_wq, &work->work);
+
+	return 0;
+
+err2:
+	kfree(route->path_rec);
+	route->path_rec = NULL;
+err1:
+	kfree(work);
+	return ret;
+}
+
 int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
 {
 	struct rdma_id_private *id_priv;
@@ -1720,7 +1869,16 @@
 	atomic_inc(&id_priv->refcount);
 	switch (rdma_node_get_transport(id->device->node_type)) {
 	case RDMA_TRANSPORT_IB:
-		ret = cma_resolve_ib_route(id_priv, timeout_ms);
+		switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+		case IB_LINK_LAYER_INFINIBAND:
+			ret = cma_resolve_ib_route(id_priv, timeout_ms);
+			break;
+		case IB_LINK_LAYER_ETHERNET:
+			ret = cma_resolve_iboe_route(id_priv);
+			break;
+		default:
+			ret = -ENOSYS;
+		}
 		break;
 	case RDMA_TRANSPORT_IWARP:
 		ret = cma_resolve_iw_route(id_priv, timeout_ms);
@@ -1773,7 +1931,7 @@
 		goto out;
 
 	id_priv->id.route.addr.dev_addr.dev_type =
-		(rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ?
+		(rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ?
 		ARPHRD_INFINIBAND : ARPHRD_ETHER;
 
 	rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
@@ -2758,6 +2916,102 @@
 	return 0;
 }
 
+static void iboe_mcast_work_handler(struct work_struct *work)
+{
+	struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
+	struct cma_multicast *mc = mw->mc;
+	struct ib_sa_multicast *m = mc->multicast.ib;
+
+	mc->multicast.ib->context = mc;
+	cma_ib_mc_handler(0, m);
+	kref_put(&mc->mcref, release_mc);
+	kfree(mw);
+}
+
+static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+
+	if (cma_any_addr(addr)) {
+		memset(mgid, 0, sizeof *mgid);
+	} else if (addr->sa_family == AF_INET6) {
+		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+	} else {
+		mgid->raw[0] = 0xff;
+		mgid->raw[1] = 0x0e;
+		mgid->raw[2] = 0;
+		mgid->raw[3] = 0;
+		mgid->raw[4] = 0;
+		mgid->raw[5] = 0;
+		mgid->raw[6] = 0;
+		mgid->raw[7] = 0;
+		mgid->raw[8] = 0;
+		mgid->raw[9] = 0;
+		mgid->raw[10] = 0xff;
+		mgid->raw[11] = 0xff;
+		*(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
+	}
+}
+
+static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
+				   struct cma_multicast *mc)
+{
+	struct iboe_mcast_work *work;
+	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
+	int err;
+	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
+	struct net_device *ndev = NULL;
+
+	if (cma_zero_addr((struct sockaddr *)&mc->addr))
+		return -EINVAL;
+
+	work = kzalloc(sizeof *work, GFP_KERNEL);
+	if (!work)
+		return -ENOMEM;
+
+	mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
+	if (!mc->multicast.ib) {
+		err = -ENOMEM;
+		goto out1;
+	}
+
+	cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid);
+
+	mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
+	if (id_priv->id.ps == RDMA_PS_UDP)
+		mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
+
+	if (dev_addr->bound_dev_if)
+		ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+	if (!ndev) {
+		err = -ENODEV;
+		goto out2;
+	}
+	mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
+	mc->multicast.ib->rec.hop_limit = 1;
+	mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
+	dev_put(ndev);
+	if (!mc->multicast.ib->rec.mtu) {
+		err = -EINVAL;
+		goto out2;
+	}
+	iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid);
+	work->id = id_priv;
+	work->mc = mc;
+	INIT_WORK(&work->work, iboe_mcast_work_handler);
+	kref_get(&mc->mcref);
+	queue_work(cma_wq, &work->work);
+
+	return 0;
+
+out2:
+	kfree(mc->multicast.ib);
+out1:
+	kfree(work);
+	return err;
+}
+
 int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
 			void *context)
 {
@@ -2784,7 +3038,17 @@
 
 	switch (rdma_node_get_transport(id->device->node_type)) {
 	case RDMA_TRANSPORT_IB:
-		ret = cma_join_ib_multicast(id_priv, mc);
+		switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+		case IB_LINK_LAYER_INFINIBAND:
+			ret = cma_join_ib_multicast(id_priv, mc);
+			break;
+		case IB_LINK_LAYER_ETHERNET:
+			kref_init(&mc->mcref);
+			ret = cma_iboe_join_multicast(id_priv, mc);
+			break;
+		default:
+			ret = -EINVAL;
+		}
 		break;
 	default:
 		ret = -ENOSYS;
@@ -2817,8 +3081,19 @@
 				ib_detach_mcast(id->qp,
 						&mc->multicast.ib->rec.mgid,
 						mc->multicast.ib->rec.mlid);
-			ib_sa_free_multicast(mc->multicast.ib);
-			kfree(mc);
+			if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) {
+				switch (rdma_port_get_link_layer(id->device, id->port_num)) {
+				case IB_LINK_LAYER_INFINIBAND:
+					ib_sa_free_multicast(mc->multicast.ib);
+					kfree(mc);
+					break;
+				case IB_LINK_LAYER_ETHERNET:
+					kref_put(&mc->mcref, release_mc);
+					break;
+				default:
+					break;
+				}
+			}
 			return;
 		}
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/iwcm.c linux-libre-2.6.37-gnu/drivers/infiniband/core/iwcm.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/iwcm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/iwcm.c	2011-01-04 19:50:19.000000000 -0500
@@ -506,6 +506,8 @@
 	qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
 	if (!qp) {
 		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+		clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+		wake_up_all(&cm_id_priv->connect_wait);
 		return -EINVAL;
 	}
 	cm_id->device->iwcm->add_ref(qp);
@@ -565,6 +567,8 @@
 	qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
 	if (!qp) {
 		spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+		clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+		wake_up_all(&cm_id_priv->connect_wait);
 		return -EINVAL;
 	}
 	cm_id->device->iwcm->add_ref(qp);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/mad.c linux-libre-2.6.37-gnu/drivers/infiniband/core/mad.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/mad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/mad.c	2011-01-04 19:50:19.000000000 -0500
@@ -2598,6 +2598,9 @@
 	struct ib_mad_private *recv;
 	struct ib_mad_list_head *mad_list;
 
+	if (!qp_info->qp)
+		return;
+
 	while (!list_empty(&qp_info->recv_queue.list)) {
 
 		mad_list = list_entry(qp_info->recv_queue.list.next,
@@ -2639,6 +2642,9 @@
 
 	for (i = 0; i < IB_MAD_QPS_CORE; i++) {
 		qp = port_priv->qp_info[i].qp;
+		if (!qp)
+			continue;
+
 		/*
 		 * PKey index for QP1 is irrelevant but
 		 * one is needed for the Reset to Init transition
@@ -2680,6 +2686,9 @@
 	}
 
 	for (i = 0; i < IB_MAD_QPS_CORE; i++) {
+		if (!port_priv->qp_info[i].qp)
+			continue;
+
 		ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL);
 		if (ret) {
 			printk(KERN_ERR PFX "Couldn't post receive WRs\n");
@@ -2758,6 +2767,9 @@
 
 static void destroy_mad_qp(struct ib_mad_qp_info *qp_info)
 {
+	if (!qp_info->qp)
+		return;
+
 	ib_destroy_qp(qp_info->qp);
 	kfree(qp_info->snoop_table);
 }
@@ -2773,6 +2785,7 @@
 	struct ib_mad_port_private *port_priv;
 	unsigned long flags;
 	char name[sizeof "ib_mad123"];
+	int has_smi;
 
 	/* Create new device info */
 	port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
@@ -2788,7 +2801,11 @@
 	init_mad_qp(port_priv, &port_priv->qp_info[0]);
 	init_mad_qp(port_priv, &port_priv->qp_info[1]);
 
-	cq_size = (mad_sendq_size + mad_recvq_size) * 2;
+	cq_size = mad_sendq_size + mad_recvq_size;
+	has_smi = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND;
+	if (has_smi)
+		cq_size *= 2;
+
 	port_priv->cq = ib_create_cq(port_priv->device,
 				     ib_mad_thread_completion_handler,
 				     NULL, port_priv, cq_size, 0);
@@ -2812,9 +2829,11 @@
 		goto error5;
 	}
 
-	ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
-	if (ret)
-		goto error6;
+	if (has_smi) {
+		ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
+		if (ret)
+			goto error6;
+	}
 	ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI);
 	if (ret)
 		goto error7;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/multicast.c linux-libre-2.6.37-gnu/drivers/infiniband/core/multicast.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/multicast.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/multicast.c	2011-01-04 19:50:19.000000000 -0500
@@ -774,6 +774,10 @@
 	int index;
 
 	dev = container_of(handler, struct mcast_device, event_handler);
+	if (rdma_port_get_link_layer(dev->device, event->element.port_num) !=
+	    IB_LINK_LAYER_INFINIBAND)
+		return;
+
 	index = event->element.port_num - dev->start_port;
 
 	switch (event->event) {
@@ -796,6 +800,7 @@
 	struct mcast_device *dev;
 	struct mcast_port *port;
 	int i;
+	int count = 0;
 
 	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
 		return;
@@ -813,6 +818,9 @@
 	}
 
 	for (i = 0; i <= dev->end_port - dev->start_port; i++) {
+		if (rdma_port_get_link_layer(device, dev->start_port + i) !=
+		    IB_LINK_LAYER_INFINIBAND)
+			continue;
 		port = &dev->port[i];
 		port->dev = dev;
 		port->port_num = dev->start_port + i;
@@ -820,6 +828,12 @@
 		port->table = RB_ROOT;
 		init_completion(&port->comp);
 		atomic_set(&port->refcount, 1);
+		++count;
+	}
+
+	if (!count) {
+		kfree(dev);
+		return;
 	}
 
 	dev->device = device;
@@ -843,9 +857,12 @@
 	flush_workqueue(mcast_wq);
 
 	for (i = 0; i <= dev->end_port - dev->start_port; i++) {
-		port = &dev->port[i];
-		deref_port(port);
-		wait_for_completion(&port->comp);
+		if (rdma_port_get_link_layer(device, dev->start_port + i) ==
+		    IB_LINK_LAYER_INFINIBAND) {
+			port = &dev->port[i];
+			deref_port(port);
+			wait_for_completion(&port->comp);
+		}
 	}
 
 	kfree(dev);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/sa_query.c linux-libre-2.6.37-gnu/drivers/infiniband/core/sa_query.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/sa_query.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/sa_query.c	2011-01-04 19:50:19.000000000 -0500
@@ -416,6 +416,9 @@
 		struct ib_sa_port *port =
 			&sa_dev->port[event->element.port_num - sa_dev->start_port];
 
+		if (rdma_port_get_link_layer(handler->device, port->port_num) != IB_LINK_LAYER_INFINIBAND)
+			return;
+
 		spin_lock_irqsave(&port->ah_lock, flags);
 		if (port->sm_ah)
 			kref_put(&port->sm_ah->ref, free_sm_ah);
@@ -493,6 +496,7 @@
 {
 	int ret;
 	u16 gid_index;
+	int force_grh;
 
 	memset(ah_attr, 0, sizeof *ah_attr);
 	ah_attr->dlid = be16_to_cpu(rec->dlid);
@@ -502,7 +506,9 @@
 	ah_attr->port_num = port_num;
 	ah_attr->static_rate = rec->rate;
 
-	if (rec->hop_limit > 1) {
+	force_grh = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_ETHERNET;
+
+	if (rec->hop_limit > 1 || force_grh) {
 		ah_attr->ah_flags = IB_AH_GRH;
 		ah_attr->grh.dgid = rec->dgid;
 
@@ -1007,7 +1013,7 @@
 		e = device->phys_port_cnt;
 	}
 
-	sa_dev = kmalloc(sizeof *sa_dev +
+	sa_dev = kzalloc(sizeof *sa_dev +
 			 (e - s + 1) * sizeof (struct ib_sa_port),
 			 GFP_KERNEL);
 	if (!sa_dev)
@@ -1017,9 +1023,12 @@
 	sa_dev->end_port   = e;
 
 	for (i = 0; i <= e - s; ++i) {
+		spin_lock_init(&sa_dev->port[i].ah_lock);
+		if (rdma_port_get_link_layer(device, i + 1) != IB_LINK_LAYER_INFINIBAND)
+			continue;
+
 		sa_dev->port[i].sm_ah    = NULL;
 		sa_dev->port[i].port_num = i + s;
-		spin_lock_init(&sa_dev->port[i].ah_lock);
 
 		sa_dev->port[i].agent =
 			ib_register_mad_agent(device, i + s, IB_QPT_GSI,
@@ -1045,13 +1054,15 @@
 		goto err;
 
 	for (i = 0; i <= e - s; ++i)
-		update_sm_ah(&sa_dev->port[i].update_task);
+		if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+			update_sm_ah(&sa_dev->port[i].update_task);
 
 	return;
 
 err:
 	while (--i >= 0)
-		ib_unregister_mad_agent(sa_dev->port[i].agent);
+		if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND)
+			ib_unregister_mad_agent(sa_dev->port[i].agent);
 
 	kfree(sa_dev);
 
@@ -1071,9 +1082,12 @@
 	flush_scheduled_work();
 
 	for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) {
-		ib_unregister_mad_agent(sa_dev->port[i].agent);
-		if (sa_dev->port[i].sm_ah)
-			kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+		if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) {
+			ib_unregister_mad_agent(sa_dev->port[i].agent);
+			if (sa_dev->port[i].sm_ah)
+				kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah);
+		}
+
 	}
 
 	kfree(sa_dev);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/sysfs.c linux-libre-2.6.37-gnu/drivers/infiniband/core/sysfs.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/sysfs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/sysfs.c	2011-01-04 19:50:19.000000000 -0500
@@ -222,6 +222,19 @@
 	}
 }
 
+static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused,
+			       char *buf)
+{
+	switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) {
+	case IB_LINK_LAYER_INFINIBAND:
+		return sprintf(buf, "%s\n", "InfiniBand");
+	case IB_LINK_LAYER_ETHERNET:
+		return sprintf(buf, "%s\n", "Ethernet");
+	default:
+		return sprintf(buf, "%s\n", "Unknown");
+	}
+}
+
 static PORT_ATTR_RO(state);
 static PORT_ATTR_RO(lid);
 static PORT_ATTR_RO(lid_mask_count);
@@ -230,6 +243,7 @@
 static PORT_ATTR_RO(cap_mask);
 static PORT_ATTR_RO(rate);
 static PORT_ATTR_RO(phys_state);
+static PORT_ATTR_RO(link_layer);
 
 static struct attribute *port_default_attrs[] = {
 	&port_attr_state.attr,
@@ -240,6 +254,7 @@
 	&port_attr_cap_mask.attr,
 	&port_attr_rate.attr,
 	&port_attr_phys_state.attr,
+	&port_attr_link_layer.attr,
 	NULL
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/ucma.c linux-libre-2.6.37-gnu/drivers/infiniband/core/ucma.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/ucma.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/ucma.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,6 +40,7 @@
 #include <linux/in6.h>
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 
 #include <rdma/rdma_user_cm.h>
 #include <rdma/ib_marshall.h>
@@ -50,8 +51,24 @@
 MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access");
 MODULE_LICENSE("Dual BSD/GPL");
 
-enum {
-	UCMA_MAX_BACKLOG	= 128
+static unsigned int max_backlog = 1024;
+
+static struct ctl_table_header *ucma_ctl_table_hdr;
+static ctl_table ucma_ctl_table[] = {
+	{
+		.procname	= "max_backlog",
+		.data		= &max_backlog,
+		.maxlen		= sizeof max_backlog,
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+	{ }
+};
+
+static struct ctl_path ucma_ctl_path[] = {
+	{ .procname = "net" },
+	{ .procname = "rdma_ucm" },
+	{ }
 };
 
 struct ucma_file {
@@ -583,6 +600,42 @@
 	}
 }
 
+static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp,
+				 struct rdma_route *route)
+{
+	struct rdma_dev_addr *dev_addr;
+	struct net_device *dev;
+	u16 vid = 0;
+
+	resp->num_paths = route->num_paths;
+	switch (route->num_paths) {
+	case 0:
+		dev_addr = &route->addr.dev_addr;
+		dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
+			if (dev) {
+				vid = rdma_vlan_dev_vlan_id(dev);
+				dev_put(dev);
+			}
+
+		iboe_mac_vlan_to_ll((union ib_gid *) &resp->ib_route[0].dgid,
+				    dev_addr->dst_dev_addr, vid);
+		iboe_addr_get_sgid(dev_addr,
+				   (union ib_gid *) &resp->ib_route[0].sgid);
+		resp->ib_route[0].pkey = cpu_to_be16(0xffff);
+		break;
+	case 2:
+		ib_copy_path_rec_to_user(&resp->ib_route[1],
+					 &route->path_rec[1]);
+		/* fall through */
+	case 1:
+		ib_copy_path_rec_to_user(&resp->ib_route[0],
+					 &route->path_rec[0]);
+		break;
+	default:
+		break;
+	}
+}
+
 static ssize_t ucma_query_route(struct ucma_file *file,
 				const char __user *inbuf,
 				int in_len, int out_len)
@@ -617,12 +670,17 @@
 
 	resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid;
 	resp.port_num = ctx->cm_id->port_num;
-	switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) {
-	case RDMA_TRANSPORT_IB:
-		ucma_copy_ib_route(&resp, &ctx->cm_id->route);
-		break;
-	default:
-		break;
+	if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) {
+		switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) {
+		case IB_LINK_LAYER_INFINIBAND:
+			ucma_copy_ib_route(&resp, &ctx->cm_id->route);
+			break;
+		case IB_LINK_LAYER_ETHERNET:
+			ucma_copy_iboe_route(&resp, &ctx->cm_id->route);
+			break;
+		default:
+			break;
+		}
 	}
 
 out:
@@ -686,8 +744,8 @@
 	if (IS_ERR(ctx))
 		return PTR_ERR(ctx);
 
-	ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ?
-		       cmd.backlog : UCMA_MAX_BACKLOG;
+	ctx->backlog = cmd.backlog > 0 && cmd.backlog < max_backlog ?
+		       cmd.backlog : max_backlog;
 	ret = rdma_listen(ctx->cm_id, ctx->backlog);
 	ucma_put_ctx(ctx);
 	return ret;
@@ -1279,16 +1337,26 @@
 	ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version);
 	if (ret) {
 		printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n");
-		goto err;
+		goto err1;
+	}
+
+	ucma_ctl_table_hdr = register_sysctl_paths(ucma_ctl_path, ucma_ctl_table);
+	if (!ucma_ctl_table_hdr) {
+		printk(KERN_ERR "rdma_ucm: couldn't register sysctl paths\n");
+		ret = -ENOMEM;
+		goto err2;
 	}
 	return 0;
-err:
+err2:
+	device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
+err1:
 	misc_deregister(&ucma_misc);
 	return ret;
 }
 
 static void __exit ucma_cleanup(void)
 {
+	unregister_sysctl_table(ucma_ctl_table_hdr);
 	device_remove_file(ucma_misc.this_device, &dev_attr_abi_version);
 	misc_deregister(&ucma_misc);
 	idr_destroy(&ctx_idr);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/ud_header.c linux-libre-2.6.37-gnu/drivers/infiniband/core/ud_header.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/ud_header.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/ud_header.c	2011-01-04 19:50:19.000000000 -0500
@@ -33,6 +33,7 @@
 
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/if_ether.h>
 
 #include <rdma/ib_pack.h>
 
@@ -80,6 +81,40 @@
 	  .size_bits    = 16 }
 };
 
+static const struct ib_field eth_table[]  = {
+	{ STRUCT_FIELD(eth, dmac_h),
+	  .offset_words = 0,
+	  .offset_bits  = 0,
+	  .size_bits    = 32 },
+	{ STRUCT_FIELD(eth, dmac_l),
+	  .offset_words = 1,
+	  .offset_bits  = 0,
+	  .size_bits    = 16 },
+	{ STRUCT_FIELD(eth, smac_h),
+	  .offset_words = 1,
+	  .offset_bits  = 16,
+	  .size_bits    = 16 },
+	{ STRUCT_FIELD(eth, smac_l),
+	  .offset_words = 2,
+	  .offset_bits  = 0,
+	  .size_bits    = 32 },
+	{ STRUCT_FIELD(eth, type),
+	  .offset_words = 3,
+	  .offset_bits  = 0,
+	  .size_bits    = 16 }
+};
+
+static const struct ib_field vlan_table[]  = {
+	{ STRUCT_FIELD(vlan, tag),
+	  .offset_words = 0,
+	  .offset_bits  = 0,
+	  .size_bits    = 16 },
+	{ STRUCT_FIELD(vlan, type),
+	  .offset_words = 0,
+	  .offset_bits  = 16,
+	  .size_bits    = 16 }
+};
+
 static const struct ib_field grh_table[]  = {
 	{ STRUCT_FIELD(grh, ip_version),
 	  .offset_words = 0,
@@ -180,38 +215,43 @@
 /**
  * ib_ud_header_init - Initialize UD header structure
  * @payload_bytes:Length of packet payload
+ * @lrh_present: specify if LRH is present
+ * @eth_present: specify if Eth header is present
+ * @vlan_present: packet is tagged vlan
  * @grh_present:GRH flag (if non-zero, GRH will be included)
- * @immediate_present: specify if immediate data should be used
+ * @immediate_present: specify if immediate data is present
  * @header:Structure to initialize
- *
- * ib_ud_header_init() initializes the lrh.link_version, lrh.link_next_header,
- * lrh.packet_length, grh.ip_version, grh.payload_length,
- * grh.next_header, bth.opcode, bth.pad_count and
- * bth.transport_header_version fields of a &struct ib_ud_header given
- * the payload length and whether a GRH will be included.
  */
 void ib_ud_header_init(int     		    payload_bytes,
+		       int		    lrh_present,
+		       int		    eth_present,
+		       int		    vlan_present,
 		       int    		    grh_present,
 		       int		    immediate_present,
 		       struct ib_ud_header *header)
 {
-	u16 packet_length;
-
 	memset(header, 0, sizeof *header);
 
-	header->lrh.link_version     = 0;
-	header->lrh.link_next_header =
-		grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
-	packet_length		     = (IB_LRH_BYTES     +
-					IB_BTH_BYTES     +
-					IB_DETH_BYTES    +
-					payload_bytes    +
-					4                + /* ICRC     */
-					3) / 4;            /* round up */
+	if (lrh_present) {
+		u16 packet_length;
+
+		header->lrh.link_version     = 0;
+		header->lrh.link_next_header =
+			grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
+		packet_length = (IB_LRH_BYTES	+
+				 IB_BTH_BYTES	+
+				 IB_DETH_BYTES	+
+				 (grh_present ? IB_GRH_BYTES : 0) +
+				 payload_bytes	+
+				 4		+ /* ICRC     */
+				 3) / 4;	  /* round up */
+		header->lrh.packet_length = cpu_to_be16(packet_length);
+	}
+
+	if (vlan_present)
+		header->eth.type = cpu_to_be16(ETH_P_8021Q);
 
-	header->grh_present          = grh_present;
 	if (grh_present) {
-		packet_length		   += IB_GRH_BYTES / 4;
 		header->grh.ip_version      = 6;
 		header->grh.payload_length  =
 			cpu_to_be16((IB_BTH_BYTES     +
@@ -222,15 +262,18 @@
 		header->grh.next_header     = 0x1b;
 	}
 
-	header->lrh.packet_length = cpu_to_be16(packet_length);
-
-	header->immediate_present	     = immediate_present;
 	if (immediate_present)
 		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
 	else
 		header->bth.opcode           = IB_OPCODE_UD_SEND_ONLY;
 	header->bth.pad_count                = (4 - payload_bytes) & 3;
 	header->bth.transport_header_version = 0;
+
+	header->lrh_present = lrh_present;
+	header->eth_present = eth_present;
+	header->vlan_present = vlan_present;
+	header->grh_present = grh_present;
+	header->immediate_present = immediate_present;
 }
 EXPORT_SYMBOL(ib_ud_header_init);
 
@@ -247,10 +290,21 @@
 {
 	int len = 0;
 
-	ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
-		&header->lrh, buf);
-	len += IB_LRH_BYTES;
-
+	if (header->lrh_present) {
+		ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
+			&header->lrh, buf + len);
+		len += IB_LRH_BYTES;
+	}
+	if (header->eth_present) {
+		ib_pack(eth_table, ARRAY_SIZE(eth_table),
+			&header->eth, buf + len);
+		len += IB_ETH_BYTES;
+	}
+	if (header->vlan_present) {
+		ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
+			&header->vlan, buf + len);
+		len += IB_VLAN_BYTES;
+	}
 	if (header->grh_present) {
 		ib_pack(grh_table, ARRAY_SIZE(grh_table),
 			&header->grh, buf + len);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/user_mad.c linux-libre-2.6.37-gnu/drivers/infiniband/core/user_mad.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/user_mad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/user_mad.c	2011-01-04 19:50:19.000000000 -0500
@@ -1022,7 +1022,7 @@
 
 	port->ib_dev   = device;
 	port->port_num = port_num;
-	init_MUTEX(&port->sm_sem);
+	sema_init(&port->sm_sem, 1);
 	mutex_init(&port->file_mutex);
 	INIT_LIST_HEAD(&port->file_list);
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/uverbs_cmd.c linux-libre-2.6.37-gnu/drivers/infiniband/core/uverbs_cmd.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/uverbs_cmd.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/uverbs_cmd.c	2011-01-04 19:50:19.000000000 -0500
@@ -460,6 +460,8 @@
 	resp.active_width    = attr.active_width;
 	resp.active_speed    = attr.active_speed;
 	resp.phys_state      = attr.phys_state;
+	resp.link_layer      = rdma_port_get_link_layer(file->device->ib_dev,
+							cmd.port_num);
 
 	if (copy_to_user((void __user *) (unsigned long) cmd.response,
 			 &resp, sizeof resp))
@@ -891,68 +893,81 @@
 	return ret ? ret : in_len;
 }
 
+static int copy_wc_to_user(void __user *dest, struct ib_wc *wc)
+{
+	struct ib_uverbs_wc tmp;
+
+	tmp.wr_id		= wc->wr_id;
+	tmp.status		= wc->status;
+	tmp.opcode		= wc->opcode;
+	tmp.vendor_err		= wc->vendor_err;
+	tmp.byte_len		= wc->byte_len;
+	tmp.ex.imm_data		= (__u32 __force) wc->ex.imm_data;
+	tmp.qp_num		= wc->qp->qp_num;
+	tmp.src_qp		= wc->src_qp;
+	tmp.wc_flags		= wc->wc_flags;
+	tmp.pkey_index		= wc->pkey_index;
+	tmp.slid		= wc->slid;
+	tmp.sl			= wc->sl;
+	tmp.dlid_path_bits	= wc->dlid_path_bits;
+	tmp.port_num		= wc->port_num;
+	tmp.reserved		= 0;
+
+	if (copy_to_user(dest, &tmp, sizeof tmp))
+		return -EFAULT;
+
+	return 0;
+}
+
 ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
 			  const char __user *buf, int in_len,
 			  int out_len)
 {
 	struct ib_uverbs_poll_cq       cmd;
-	struct ib_uverbs_poll_cq_resp *resp;
+	struct ib_uverbs_poll_cq_resp  resp;
+	u8 __user                     *header_ptr;
+	u8 __user                     *data_ptr;
 	struct ib_cq                  *cq;
-	struct ib_wc                  *wc;
-	int                            ret = 0;
-	int                            i;
-	int                            rsize;
+	struct ib_wc                   wc;
+	int                            ret;
 
 	if (copy_from_user(&cmd, buf, sizeof cmd))
 		return -EFAULT;
 
-	wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL);
-	if (!wc)
-		return -ENOMEM;
-
-	rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc);
-	resp = kmalloc(rsize, GFP_KERNEL);
-	if (!resp) {
-		ret = -ENOMEM;
-		goto out_wc;
-	}
-
 	cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
-	if (!cq) {
-		ret = -EINVAL;
-		goto out;
-	}
+	if (!cq)
+		return -EINVAL;
 
-	resp->count = ib_poll_cq(cq, cmd.ne, wc);
+	/* we copy a struct ib_uverbs_poll_cq_resp to user space */
+	header_ptr = (void __user *)(unsigned long) cmd.response;
+	data_ptr = header_ptr + sizeof resp;
 
-	put_cq_read(cq);
+	memset(&resp, 0, sizeof resp);
+	while (resp.count < cmd.ne) {
+		ret = ib_poll_cq(cq, 1, &wc);
+		if (ret < 0)
+			goto out_put;
+		if (!ret)
+			break;
 
-	for (i = 0; i < resp->count; i++) {
-		resp->wc[i].wr_id 	   = wc[i].wr_id;
-		resp->wc[i].status 	   = wc[i].status;
-		resp->wc[i].opcode 	   = wc[i].opcode;
-		resp->wc[i].vendor_err 	   = wc[i].vendor_err;
-		resp->wc[i].byte_len 	   = wc[i].byte_len;
-		resp->wc[i].ex.imm_data    = (__u32 __force) wc[i].ex.imm_data;
-		resp->wc[i].qp_num 	   = wc[i].qp->qp_num;
-		resp->wc[i].src_qp 	   = wc[i].src_qp;
-		resp->wc[i].wc_flags 	   = wc[i].wc_flags;
-		resp->wc[i].pkey_index 	   = wc[i].pkey_index;
-		resp->wc[i].slid 	   = wc[i].slid;
-		resp->wc[i].sl 		   = wc[i].sl;
-		resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits;
-		resp->wc[i].port_num 	   = wc[i].port_num;
+		ret = copy_wc_to_user(data_ptr, &wc);
+		if (ret)
+			goto out_put;
+
+		data_ptr += sizeof(struct ib_uverbs_wc);
+		++resp.count;
 	}
 
-	if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize))
+	if (copy_to_user(header_ptr, &resp, sizeof resp)) {
 		ret = -EFAULT;
+		goto out_put;
+	}
 
-out:
-	kfree(resp);
+	ret = in_len;
 
-out_wc:
-	kfree(wc);
-	return ret ? ret : in_len;
+out_put:
+	put_cq_read(cq);
+	return ret;
 }
 
 ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/uverbs_marshall.c linux-libre-2.6.37-gnu/drivers/infiniband/core/uverbs_marshall.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/uverbs_marshall.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/uverbs_marshall.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,18 +40,21 @@
 	dst->grh.sgid_index        = src->grh.sgid_index;
 	dst->grh.hop_limit         = src->grh.hop_limit;
 	dst->grh.traffic_class     = src->grh.traffic_class;
+	memset(&dst->grh.reserved, 0, sizeof(dst->grh.reserved));
 	dst->dlid 	    	   = src->dlid;
 	dst->sl   	    	   = src->sl;
 	dst->src_path_bits 	   = src->src_path_bits;
 	dst->static_rate   	   = src->static_rate;
 	dst->is_global             = src->ah_flags & IB_AH_GRH ? 1 : 0;
 	dst->port_num 	    	   = src->port_num;
+	dst->reserved 		   = 0;
 }
 EXPORT_SYMBOL(ib_copy_ah_attr_to_user);
 
 void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst,
 			     struct ib_qp_attr *src)
 {
+	dst->qp_state	        = src->qp_state;
 	dst->cur_qp_state	= src->cur_qp_state;
 	dst->path_mtu		= src->path_mtu;
 	dst->path_mig_state	= src->path_mig_state;
@@ -83,6 +86,7 @@
 	dst->rnr_retry		= src->rnr_retry;
 	dst->alt_port_num	= src->alt_port_num;
 	dst->alt_timeout	= src->alt_timeout;
+	memset(dst->reserved, 0, sizeof(dst->reserved));
 }
 EXPORT_SYMBOL(ib_copy_qp_attr_to_user);
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/core/verbs.c linux-libre-2.6.37-gnu/drivers/infiniband/core/verbs.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/core/verbs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/core/verbs.c	2011-01-04 19:50:19.000000000 -0500
@@ -94,6 +94,22 @@
 }
 EXPORT_SYMBOL(rdma_node_get_transport);
 
+enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num)
+{
+	if (device->get_link_layer)
+		return device->get_link_layer(device, port_num);
+
+	switch (rdma_node_get_transport(device->node_type)) {
+	case RDMA_TRANSPORT_IB:
+		return IB_LINK_LAYER_INFINIBAND;
+	case RDMA_TRANSPORT_IWARP:
+		return IB_LINK_LAYER_ETHERNET;
+	default:
+		return IB_LINK_LAYER_UNSPECIFIED;
+	}
+}
+EXPORT_SYMBOL(rdma_port_get_link_layer);
+
 /* Protection domains */
 
 struct ib_pd *ib_alloc_pd(struct ib_device *device)
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/amso1100/c2_intr.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/amso1100/c2_intr.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/amso1100/c2_intr.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/amso1100/c2_intr.c	2011-01-04 19:50:19.000000000 -0500
@@ -62,8 +62,8 @@
 static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
 {
 	if (c2dev->qptr_array[mq_index] == NULL) {
-		pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
-			mq_index);
+		pr_debug("handle_mq: stray activity for mq_index=%d\n",
+			 mq_index);
 		return;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/amso1100/Kbuild linux-libre-2.6.37-gnu/drivers/infiniband/hw/amso1100/Kbuild
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/amso1100/Kbuild	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/amso1100/Kbuild	2011-01-04 19:50:19.000000000 -0500
@@ -1,6 +1,4 @@
-ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_AMSO1100_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/cxio_hal.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/cxio_hal.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/cxio_hal.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/cxio_hal.c	2011-01-04 19:50:19.000000000 -0500
@@ -160,6 +160,7 @@
 	struct rdma_cq_setup setup;
 	int size = (1UL << (cq->size_log2)) * sizeof(struct t3_cqe);
 
+	size += 1; /* one extra page for storing cq-in-err state */
 	cq->cqid = cxio_hal_get_cqid(rdev_p->rscp);
 	if (!cq->cqid)
 		return -ENOMEM;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/cxio_wr.h linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/cxio_wr.h
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/cxio_wr.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/cxio_wr.h	2011-01-04 19:50:19.000000000 -0500
@@ -728,6 +728,22 @@
 #define CQ_VLD_ENTRY(ptr,size_log2,cqe) (Q_GENBIT(ptr,size_log2) == \
 					 CQE_GENBIT(*cqe))
 
+struct t3_cq_status_page {
+	u32 cq_err;
+};
+
+static inline int cxio_cq_in_error(struct t3_cq *cq)
+{
+	return ((struct t3_cq_status_page *)
+		&cq->queue[1 << cq->size_log2])->cq_err;
+}
+
+static inline void cxio_set_cq_in_error(struct t3_cq *cq)
+{
+	((struct t3_cq_status_page *)
+	 &cq->queue[1 << cq->size_log2])->cq_err = 1;
+}
+
 static inline void cxio_set_wq_in_error(struct t3_wq *wq)
 {
 	wq->queue->wq_in_err.err |= 1;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_cm.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_cm.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_cm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_cm.c	2011-01-04 19:50:19.000000000 -0500
@@ -1093,8 +1093,8 @@
 	PDBG("%s ep %p credits %u\n", __func__, ep, credits);
 
 	if (credits == 0) {
-		PDBG(KERN_ERR "%s 0 credit ack  ep %p state %u\n",
-			__func__, ep, state_read(&ep->com));
+		PDBG("%s 0 credit ack  ep %p state %u\n",
+		     __func__, ep, state_read(&ep->com));
 		return CPL_RET_BUF_DONE;
 	}
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_ev.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_ev.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_ev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_ev.c	2011-01-04 19:50:19.000000000 -0500
@@ -76,6 +76,14 @@
 	atomic_inc(&qhp->refcnt);
 	spin_unlock(&rnicp->lock);
 
+	if (qhp->attr.state == IWCH_QP_STATE_RTS) {
+		attrs.next_state = IWCH_QP_STATE_TERMINATE;
+		iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
+			       &attrs, 1);
+		if (send_term)
+			iwch_post_terminate(qhp, rsp_msg);
+	}
+
 	event.event = ib_event;
 	event.device = chp->ibcq.device;
 	if (ib_event == IB_EVENT_CQ_ERR)
@@ -86,13 +94,7 @@
 	if (qhp->ibqp.event_handler)
 		(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
 
-	if (qhp->attr.state == IWCH_QP_STATE_RTS) {
-		attrs.next_state = IWCH_QP_STATE_TERMINATE;
-		iwch_modify_qp(qhp->rhp, qhp, IWCH_QP_ATTR_NEXT_STATE,
-			       &attrs, 1);
-		if (send_term)
-			iwch_post_terminate(qhp, rsp_msg);
-	}
+	(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
 
 	if (atomic_dec_and_test(&qhp->refcnt))
 		wake_up(&qhp->wait);
@@ -179,7 +181,6 @@
 	case TPT_ERR_BOUND:
 	case TPT_ERR_INVALIDATE_SHARED_MR:
 	case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:
-		(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
 		post_qp_event(rnicp, chp, rsp_msg, IB_EVENT_QP_ACCESS_ERR, 1);
 		break;
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_provider.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_provider.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_provider.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_provider.c	2011-01-04 19:50:19.000000000 -0500
@@ -154,6 +154,8 @@
 	struct iwch_create_cq_resp uresp;
 	struct iwch_create_cq_req ureq;
 	struct iwch_ucontext *ucontext = NULL;
+	static int warned;
+	size_t resplen;
 
 	PDBG("%s ib_dev %p entries %d\n", __func__, ibdev, entries);
 	rhp = to_iwch_dev(ibdev);
@@ -217,15 +219,26 @@
 		uresp.key = ucontext->key;
 		ucontext->key += PAGE_SIZE;
 		spin_unlock(&ucontext->mmap_lock);
-		if (ib_copy_to_udata(udata, &uresp, sizeof (uresp))) {
+		mm->key = uresp.key;
+		mm->addr = virt_to_phys(chp->cq.queue);
+		if (udata->outlen < sizeof uresp) {
+			if (!warned++)
+				printk(KERN_WARNING MOD "Warning - "
+				       "downlevel libcxgb3 (non-fatal).\n");
+			mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
+					     sizeof(struct t3_cqe));
+			resplen = sizeof(struct iwch_create_cq_resp_v0);
+		} else {
+			mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
+					     sizeof(struct t3_cqe));
+			uresp.memsize = mm->len;
+			resplen = sizeof uresp;
+		}
+		if (ib_copy_to_udata(udata, &uresp, resplen)) {
 			kfree(mm);
 			iwch_destroy_cq(&chp->ibcq);
 			return ERR_PTR(-EFAULT);
 		}
-		mm->key = uresp.key;
-		mm->addr = virt_to_phys(chp->cq.queue);
-		mm->len = PAGE_ALIGN((1UL << uresp.size_log2) *
-					     sizeof (struct t3_cqe));
 		insert_mmap(ucontext, mm);
 	}
 	PDBG("created cqid 0x%0x chp %p size 0x%0x, dma_addr 0x%0llx\n",
@@ -1414,6 +1427,7 @@
 	dev->ibdev.post_send = iwch_post_send;
 	dev->ibdev.post_recv = iwch_post_receive;
 	dev->ibdev.get_protocol_stats = iwch_get_mib;
+	dev->ibdev.uverbs_abi_ver = IWCH_UVERBS_ABI_VERSION;
 
 	dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
 	if (!dev->ibdev.iwcm)
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_qp.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_qp.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_qp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_qp.c	2011-01-04 19:50:19.000000000 -0500
@@ -802,14 +802,12 @@
 /*
  * Assumes qhp lock is held.
  */
-static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
+static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,
+				struct iwch_cq *schp, unsigned long *flag)
 {
-	struct iwch_cq *rchp, *schp;
 	int count;
 	int flushed;
 
-	rchp = get_chp(qhp->rhp, qhp->attr.rcq);
-	schp = get_chp(qhp->rhp, qhp->attr.scq);
 
 	PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
 	/* take a ref on the qhp since we must release the lock */
@@ -847,10 +845,23 @@
 
 static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 {
-	if (qhp->ibqp.uobject)
+	struct iwch_cq *rchp, *schp;
+
+	rchp = get_chp(qhp->rhp, qhp->attr.rcq);
+	schp = get_chp(qhp->rhp, qhp->attr.scq);
+
+	if (qhp->ibqp.uobject) {
 		cxio_set_wq_in_error(&qhp->wq);
-	else
-		__flush_qp(qhp, flag);
+		cxio_set_cq_in_error(&rchp->cq);
+		(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+		if (schp != rchp) {
+			cxio_set_cq_in_error(&schp->cq);
+			(*schp->ibcq.comp_handler)(&schp->ibcq,
+						   schp->ibcq.cq_context);
+		}
+		return;
+	}
+	__flush_qp(qhp, rchp, schp, flag);
 }
 
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_user.h linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_user.h
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/iwch_user.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/iwch_user.h	2011-01-04 19:50:19.000000000 -0500
@@ -45,10 +45,18 @@
 	__u64 user_rptr_addr;
 };
 
+struct iwch_create_cq_resp_v0 {
+	__u64 key;
+	__u32 cqid;
+	__u32 size_log2;
+};
+
 struct iwch_create_cq_resp {
 	__u64 key;
 	__u32 cqid;
 	__u32 size_log2;
+	__u32 memsize;
+	__u32 reserved;
 };
 
 struct iwch_create_qp_resp {
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/Kconfig linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/Kconfig
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,7 @@
 	  our website at <http://www.chelsio.com>.
 
 	  For customer support, please visit our customer support page at
-	  <http://www.chelsio.com/support.htm>.
+	  <http://www.chelsio.com/support.html>.
 
 	  Please send feedback to <linux-bugs@chelsio.com>.
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/Makefile linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/Makefile
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb3/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb3/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,10 +1,8 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb3
+ccflags-y := -Idrivers/net/cxgb3
 
 obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
 
 iw_cxgb3-y :=  iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \
 	       iwch_provider.o iwch.o cxio_hal.o cxio_resource.o
 
-ifdef CONFIG_INFINIBAND_CXGB3_DEBUG
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_INFINIBAND_CXGB3_DEBUG) += -DDEBUG
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/cm.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/cm.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/cm.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/cm.c	2011-01-04 19:50:19.000000000 -0500
@@ -117,9 +117,9 @@
 module_param(rcv_win, int, 0644);
 MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256KB)");
 
-static int snd_win = 32 * 1024;
+static int snd_win = 128 * 1024;
 module_param(snd_win, int, 0644);
-MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
+MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=128KB)");
 
 static struct workqueue_struct *workq;
 
@@ -172,7 +172,7 @@
 	error = cxgb4_l2t_send(rdev->lldi.ports[0], skb, l2e);
 	if (error < 0)
 		kfree_skb(skb);
-	return error;
+	return error < 0 ? error : 0;
 }
 
 int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb)
@@ -187,7 +187,7 @@
 	error = cxgb4_ofld_send(rdev->lldi.ports[0], skb);
 	if (error < 0)
 		kfree_skb(skb);
-	return error;
+	return error < 0 ? error : 0;
 }
 
 static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
@@ -219,12 +219,11 @@
 
 static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc)
 {
-	unsigned long flags;
 	enum c4iw_ep_state state;
 
-	spin_lock_irqsave(&epc->lock, flags);
+	mutex_lock(&epc->mutex);
 	state = epc->state;
-	spin_unlock_irqrestore(&epc->lock, flags);
+	mutex_unlock(&epc->mutex);
 	return state;
 }
 
@@ -235,12 +234,10 @@
 
 static void state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state new)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&epc->lock, flags);
+	mutex_lock(&epc->mutex);
 	PDBG("%s - %s -> %s\n", __func__, states[epc->state], states[new]);
 	__state_set(epc, new);
-	spin_unlock_irqrestore(&epc->lock, flags);
+	mutex_unlock(&epc->mutex);
 	return;
 }
 
@@ -251,8 +248,8 @@
 	epc = kzalloc(size, gfp);
 	if (epc) {
 		kref_init(&epc->kref);
-		spin_lock_init(&epc->lock);
-		init_waitqueue_head(&epc->waitq);
+		mutex_init(&epc->mutex);
+		c4iw_init_wr_wait(&epc->wr_wait);
 	}
 	PDBG("%s alloc ep %p\n", __func__, epc);
 	return epc;
@@ -1131,7 +1128,6 @@
 {
 	struct c4iw_ep *ep;
 	struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
-	unsigned long flags;
 	int release = 0;
 	unsigned int tid = GET_TID(rpl);
 	struct tid_info *t = dev->rdev.lldi.tids;
@@ -1139,7 +1135,7 @@
 	ep = lookup_tid(t, tid);
 	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 	BUG_ON(!ep);
-	spin_lock_irqsave(&ep->com.lock, flags);
+	mutex_lock(&ep->com.mutex);
 	switch (ep->com.state) {
 	case ABORTING:
 		__state_set(&ep->com, DEAD);
@@ -1150,7 +1146,7 @@
 		     __func__, ep, ep->com.state);
 		break;
 	}
-	spin_unlock_irqrestore(&ep->com.lock, flags);
+	mutex_unlock(&ep->com.mutex);
 
 	if (release)
 		release_ep_resources(ep);
@@ -1213,9 +1209,9 @@
 	}
 	PDBG("%s ep %p status %d error %d\n", __func__, ep,
 	     rpl->status, status2errno(rpl->status));
-	ep->com.rpl_err = status2errno(rpl->status);
-	ep->com.rpl_done = 1;
-	wake_up(&ep->com.waitq);
+	ep->com.wr_wait.ret = status2errno(rpl->status);
+	ep->com.wr_wait.done = 1;
+	wake_up(&ep->com.wr_wait.wait);
 
 	return 0;
 }
@@ -1249,9 +1245,9 @@
 	struct c4iw_listen_ep *ep = lookup_stid(t, stid);
 
 	PDBG("%s ep %p\n", __func__, ep);
-	ep->com.rpl_err = status2errno(rpl->status);
-	ep->com.rpl_done = 1;
-	wake_up(&ep->com.waitq);
+	ep->com.wr_wait.ret = status2errno(rpl->status);
+	ep->com.wr_wait.done = 1;
+	wake_up(&ep->com.wr_wait.wait);
 	return 0;
 }
 
@@ -1478,7 +1474,6 @@
 	struct cpl_peer_close *hdr = cplhdr(skb);
 	struct c4iw_ep *ep;
 	struct c4iw_qp_attributes attrs;
-	unsigned long flags;
 	int disconnect = 1;
 	int release = 0;
 	int closing = 0;
@@ -1489,7 +1484,7 @@
 	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
 	dst_confirm(ep->dst);
 
-	spin_lock_irqsave(&ep->com.lock, flags);
+	mutex_lock(&ep->com.mutex);
 	switch (ep->com.state) {
 	case MPA_REQ_WAIT:
 		__state_set(&ep->com, CLOSING);
@@ -1507,17 +1502,17 @@
 		 * in rdma connection migration (see c4iw_accept_cr()).
 		 */
 		__state_set(&ep->com, CLOSING);
-		ep->com.rpl_done = 1;
-		ep->com.rpl_err = -ECONNRESET;
+		ep->com.wr_wait.done = 1;
+		ep->com.wr_wait.ret = -ECONNRESET;
 		PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-		wake_up(&ep->com.waitq);
+		wake_up(&ep->com.wr_wait.wait);
 		break;
 	case MPA_REP_SENT:
 		__state_set(&ep->com, CLOSING);
-		ep->com.rpl_done = 1;
-		ep->com.rpl_err = -ECONNRESET;
+		ep->com.wr_wait.done = 1;
+		ep->com.wr_wait.ret = -ECONNRESET;
 		PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-		wake_up(&ep->com.waitq);
+		wake_up(&ep->com.wr_wait.wait);
 		break;
 	case FPDU_MODE:
 		start_ep_timer(ep);
@@ -1550,7 +1545,7 @@
 	default:
 		BUG_ON(1);
 	}
-	spin_unlock_irqrestore(&ep->com.lock, flags);
+	mutex_unlock(&ep->com.mutex);
 	if (closing) {
 		attrs.next_state = C4IW_QP_STATE_CLOSING;
 		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
@@ -1581,7 +1576,6 @@
 	struct c4iw_qp_attributes attrs;
 	int ret;
 	int release = 0;
-	unsigned long flags;
 	struct tid_info *t = dev->rdev.lldi.tids;
 	unsigned int tid = GET_TID(req);
 
@@ -1591,9 +1585,17 @@
 		     ep->hwtid);
 		return 0;
 	}
-	spin_lock_irqsave(&ep->com.lock, flags);
 	PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
 	     ep->com.state);
+
+	/*
+	 * Wake up any threads in rdma_init() or rdma_fini().
+	 */
+	ep->com.wr_wait.done = 1;
+	ep->com.wr_wait.ret = -ECONNRESET;
+	wake_up(&ep->com.wr_wait.wait);
+
+	mutex_lock(&ep->com.mutex);
 	switch (ep->com.state) {
 	case CONNECTING:
 		break;
@@ -1605,23 +1607,8 @@
 		connect_reply_upcall(ep, -ECONNRESET);
 		break;
 	case MPA_REP_SENT:
-		ep->com.rpl_done = 1;
-		ep->com.rpl_err = -ECONNRESET;
-		PDBG("waking up ep %p\n", ep);
-		wake_up(&ep->com.waitq);
 		break;
 	case MPA_REQ_RCVD:
-
-		/*
-		 * We're gonna mark this puppy DEAD, but keep
-		 * the reference on it until the ULP accepts or
-		 * rejects the CR. Also wake up anyone waiting
-		 * in rdma connection migration (see c4iw_accept_cr()).
-		 */
-		ep->com.rpl_done = 1;
-		ep->com.rpl_err = -ECONNRESET;
-		PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
-		wake_up(&ep->com.waitq);
 		break;
 	case MORIBUND:
 	case CLOSING:
@@ -1644,7 +1631,7 @@
 		break;
 	case DEAD:
 		PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
-		spin_unlock_irqrestore(&ep->com.lock, flags);
+		mutex_unlock(&ep->com.mutex);
 		return 0;
 	default:
 		BUG_ON(1);
@@ -1655,7 +1642,7 @@
 		__state_set(&ep->com, DEAD);
 		release = 1;
 	}
-	spin_unlock_irqrestore(&ep->com.lock, flags);
+	mutex_unlock(&ep->com.mutex);
 
 	rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
 	if (!rpl_skb) {
@@ -1681,7 +1668,6 @@
 	struct c4iw_ep *ep;
 	struct c4iw_qp_attributes attrs;
 	struct cpl_close_con_rpl *rpl = cplhdr(skb);
-	unsigned long flags;
 	int release = 0;
 	struct tid_info *t = dev->rdev.lldi.tids;
 	unsigned int tid = GET_TID(rpl);
@@ -1692,7 +1678,7 @@
 	BUG_ON(!ep);
 
 	/* The cm_id may be null if we failed to connect */
-	spin_lock_irqsave(&ep->com.lock, flags);
+	mutex_lock(&ep->com.mutex);
 	switch (ep->com.state) {
 	case CLOSING:
 		__state_set(&ep->com, MORIBUND);
@@ -1717,7 +1703,7 @@
 		BUG_ON(1);
 		break;
 	}
-	spin_unlock_irqrestore(&ep->com.lock, flags);
+	mutex_unlock(&ep->com.mutex);
 	if (release)
 		release_ep_resources(ep);
 	return 0;
@@ -1725,23 +1711,24 @@
 
 static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
 {
-	struct c4iw_ep *ep;
-	struct cpl_rdma_terminate *term = cplhdr(skb);
+	struct cpl_rdma_terminate *rpl = cplhdr(skb);
 	struct tid_info *t = dev->rdev.lldi.tids;
-	unsigned int tid = GET_TID(term);
+	unsigned int tid = GET_TID(rpl);
+	struct c4iw_ep *ep;
+	struct c4iw_qp_attributes attrs;
 
 	ep = lookup_tid(t, tid);
+	BUG_ON(!ep);
 
-	if (state_read(&ep->com) != FPDU_MODE)
-		return 0;
+	if (ep->com.qp) {
+		printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
+		       ep->com.qp->wq.sq.qid);
+		attrs.next_state = C4IW_QP_STATE_TERMINATE;
+		c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+			       C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
+	} else
+		printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
 
-	PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
-	skb_pull(skb, sizeof *term);
-	PDBG("%s saving %d bytes of term msg\n", __func__, skb->len);
-	skb_copy_from_linear_data(skb, ep->com.qp->attr.terminate_buffer,
-				  skb->len);
-	ep->com.qp->attr.terminate_msg_len = skb->len;
-	ep->com.qp->attr.is_terminate_local = 0;
 	return 0;
 }
 
@@ -1762,8 +1749,8 @@
 	ep = lookup_tid(t, tid);
 	PDBG("%s ep %p tid %u credits %u\n", __func__, ep, ep->hwtid, credits);
 	if (credits == 0) {
-		PDBG(KERN_ERR "%s 0 credit ack ep %p tid %u state %u\n",
-			__func__, ep, ep->hwtid, state_read(&ep->com));
+		PDBG("%s 0 credit ack ep %p tid %u state %u\n",
+		     __func__, ep, ep->hwtid, state_read(&ep->com));
 		return 0;
 	}
 
@@ -2042,6 +2029,7 @@
 	}
 
 	state_set(&ep->com, LISTEN);
+	c4iw_init_wr_wait(&ep->com.wr_wait);
 	err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0], ep->stid,
 				  ep->com.local_addr.sin_addr.s_addr,
 				  ep->com.local_addr.sin_port,
@@ -2050,15 +2038,8 @@
 		goto fail3;
 
 	/* wait for pass_open_rpl */
-	wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
-	if (ep->com.rpl_done)
-		err = ep->com.rpl_err;
-	else {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(ep->com.dev->rdev.lldi.pdev));
-		ep->com.dev->rdev.flags = T4_FATAL_ERROR;
-		err = -EIO;
-	}
+	err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+				  __func__);
 	if (!err) {
 		cm_id->provider_data = ep;
 		goto out;
@@ -2082,20 +2063,12 @@
 
 	might_sleep();
 	state_set(&ep->com, DEAD);
-	ep->com.rpl_done = 0;
-	ep->com.rpl_err = 0;
+	c4iw_init_wr_wait(&ep->com.wr_wait);
 	err = listen_stop(ep);
 	if (err)
 		goto done;
-	wait_event_timeout(ep->com.waitq, ep->com.rpl_done, C4IW_WR_TO);
-	if (ep->com.rpl_done)
-		err = ep->com.rpl_err;
-	else {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(ep->com.dev->rdev.lldi.pdev));
-		ep->com.dev->rdev.flags = T4_FATAL_ERROR;
-		err = -EIO;
-	}
+	err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
+				  __func__);
 	cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
 done:
 	cm_id->rem_ref(cm_id);
@@ -2106,12 +2079,11 @@
 int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
 {
 	int ret = 0;
-	unsigned long flags;
 	int close = 0;
 	int fatal = 0;
 	struct c4iw_rdev *rdev;
 
-	spin_lock_irqsave(&ep->com.lock, flags);
+	mutex_lock(&ep->com.mutex);
 
 	PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep,
 	     states[ep->com.state], abrupt);
@@ -2158,7 +2130,7 @@
 		break;
 	}
 
-	spin_unlock_irqrestore(&ep->com.lock, flags);
+	mutex_unlock(&ep->com.mutex);
 	if (close) {
 		if (abrupt)
 			ret = abort_connection(ep, NULL, gfp);
@@ -2172,6 +2144,13 @@
 	return ret;
 }
 
+static int async_event(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+	struct cpl_fw6_msg *rpl = cplhdr(skb);
+	c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+	return 0;
+}
+
 /*
  * These are the real handlers that are called from a
  * work queue.
@@ -2190,7 +2169,8 @@
 	[CPL_ABORT_REQ_RSS] = peer_abort,
 	[CPL_CLOSE_CON_RPL] = close_con_rpl,
 	[CPL_RDMA_TERMINATE] = terminate,
-	[CPL_FW4_ACK] = fw4_ack
+	[CPL_FW4_ACK] = fw4_ack,
+	[CPL_FW6_MSG] = async_event
 };
 
 static void process_timeout(struct c4iw_ep *ep)
@@ -2198,7 +2178,7 @@
 	struct c4iw_qp_attributes attrs;
 	int abort = 1;
 
-	spin_lock_irq(&ep->com.lock);
+	mutex_lock(&ep->com.mutex);
 	PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
 	     ep->com.state);
 	switch (ep->com.state) {
@@ -2225,7 +2205,7 @@
 		WARN_ON(1);
 		abort = 0;
 	}
-	spin_unlock_irq(&ep->com.lock);
+	mutex_unlock(&ep->com.mutex);
 	if (abort)
 		abort_connection(ep, NULL, GFP_KERNEL);
 	c4iw_put_ep(&ep->com);
@@ -2309,6 +2289,7 @@
 		printk(KERN_ERR MOD "Unexpected SET_TCB_RPL status %u "
 		       "for tid %u\n", rpl->status, GET_TID(rpl));
 	}
+	kfree_skb(skb);
 	return 0;
 }
 
@@ -2323,20 +2304,25 @@
 	switch (rpl->type) {
 	case 1:
 		ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
-		wr_waitp = (__force struct c4iw_wr_wait *)rpl->data[1];
+		wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
 		PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
 		if (wr_waitp) {
-			wr_waitp->ret = ret;
+			if (ret)
+				wr_waitp->ret = -ret;
+			else
+				wr_waitp->ret = 0;
 			wr_waitp->done = 1;
 			wake_up(&wr_waitp->wait);
 		}
+		kfree_skb(skb);
 		break;
 	case 2:
-		c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+		sched(dev, skb);
 		break;
 	default:
 		printk(KERN_ERR MOD "%s unexpected fw6 msg type %u\n", __func__,
 		       rpl->type);
+		kfree_skb(skb);
 		break;
 	}
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/cq.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/cq.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/cq.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/cq.c	2011-01-04 19:50:19.000000000 -0500
@@ -55,7 +55,7 @@
 			V_FW_RI_RES_WR_NRES(1) |
 			FW_WR_COMPL(1));
 	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-	res_wr->cookie = (u64)&wr_wait;
+	res_wr->cookie = (unsigned long) &wr_wait;
 	res = res_wr->res;
 	res->u.cq.restype = FW_RI_RES_TYPE_CQ;
 	res->u.cq.op = FW_RI_RES_OP_RESET;
@@ -64,14 +64,7 @@
 	c4iw_init_wr_wait(&wr_wait);
 	ret = c4iw_ofld_send(rdev, skb);
 	if (!ret) {
-		wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-		if (!wr_wait.done) {
-			printk(KERN_ERR MOD "Device %s not responding!\n",
-			       pci_name(rdev->lldi.pdev));
-			rdev->flags = T4_FATAL_ERROR;
-			ret = -EIO;
-		} else
-			ret = wr_wait.ret;
+		ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
 	}
 
 	kfree(cq->sw_queue);
@@ -132,7 +125,7 @@
 			V_FW_RI_RES_WR_NRES(1) |
 			FW_WR_COMPL(1));
 	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-	res_wr->cookie = (u64)&wr_wait;
+	res_wr->cookie = (unsigned long) &wr_wait;
 	res = res_wr->res;
 	res->u.cq.restype = FW_RI_RES_TYPE_CQ;
 	res->u.cq.op = FW_RI_RES_OP_WRITE;
@@ -157,14 +150,7 @@
 	if (ret)
 		goto err4;
 	PDBG("%s wait_event wr_wait %p\n", __func__, &wr_wait);
-	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-	if (!wr_wait.done) {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(rdev->lldi.pdev));
-		rdev->flags = T4_FATAL_ERROR;
-		ret = -EIO;
-	} else
-		ret = wr_wait.ret;
+	ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
 	if (ret)
 		goto err4;
 
@@ -476,6 +462,11 @@
 		goto proc_cqe;
 	}
 
+	if (CQE_OPCODE(hw_cqe) == FW_RI_TERMINATE) {
+		ret = -EAGAIN;
+		goto skip_cqe;
+	}
+
 	/*
 	 * RECV completion.
 	 */
@@ -696,6 +687,7 @@
 		case T4_ERR_MSN_RANGE:
 		case T4_ERR_IRD_OVERFLOW:
 		case T4_ERR_OPCODE:
+		case T4_ERR_INTERNAL_ERR:
 			wc->status = IB_WC_FATAL_ERR;
 			break;
 		case T4_ERR_SWFLUSH:
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/device.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/device.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/device.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/device.c	2011-01-04 19:50:19.000000000 -0500
@@ -49,29 +49,33 @@
 
 static struct dentry *c4iw_debugfs_root;
 
-struct debugfs_qp_data {
+struct c4iw_debugfs_data {
 	struct c4iw_dev *devp;
 	char *buf;
 	int bufsize;
 	int pos;
 };
 
-static int count_qps(int id, void *p, void *data)
+static int count_idrs(int id, void *p, void *data)
 {
-	struct c4iw_qp *qp = p;
 	int *countp = data;
 
-	if (id != qp->wq.sq.qid)
-		return 0;
-
 	*countp = *countp + 1;
 	return 0;
 }
 
-static int dump_qps(int id, void *p, void *data)
+static ssize_t debugfs_read(struct file *file, char __user *buf, size_t count,
+			    loff_t *ppos)
+{
+	struct c4iw_debugfs_data *d = file->private_data;
+
+	return simple_read_from_buffer(buf, count, ppos, d->buf, d->pos);
+}
+
+static int dump_qp(int id, void *p, void *data)
 {
 	struct c4iw_qp *qp = p;
-	struct debugfs_qp_data *qpd = data;
+	struct c4iw_debugfs_data *qpd = data;
 	int space;
 	int cc;
 
@@ -101,7 +105,7 @@
 
 static int qp_release(struct inode *inode, struct file *file)
 {
-	struct debugfs_qp_data *qpd = file->private_data;
+	struct c4iw_debugfs_data *qpd = file->private_data;
 	if (!qpd) {
 		printk(KERN_INFO "%s null qpd?\n", __func__);
 		return 0;
@@ -113,7 +117,7 @@
 
 static int qp_open(struct inode *inode, struct file *file)
 {
-	struct debugfs_qp_data *qpd;
+	struct c4iw_debugfs_data *qpd;
 	int ret = 0;
 	int count = 1;
 
@@ -126,7 +130,7 @@
 	qpd->pos = 0;
 
 	spin_lock_irq(&qpd->devp->lock);
-	idr_for_each(&qpd->devp->qpidr, count_qps, &count);
+	idr_for_each(&qpd->devp->qpidr, count_idrs, &count);
 	spin_unlock_irq(&qpd->devp->lock);
 
 	qpd->bufsize = count * 128;
@@ -137,7 +141,7 @@
 	}
 
 	spin_lock_irq(&qpd->devp->lock);
-	idr_for_each(&qpd->devp->qpidr, dump_qps, qpd);
+	idr_for_each(&qpd->devp->qpidr, dump_qp, qpd);
 	spin_unlock_irq(&qpd->devp->lock);
 
 	qpd->buf[qpd->pos++] = 0;
@@ -149,43 +153,86 @@
 	return ret;
 }
 
-static ssize_t qp_read(struct file *file, char __user *buf, size_t count,
-			loff_t *ppos)
+static const struct file_operations qp_debugfs_fops = {
+	.owner   = THIS_MODULE,
+	.open    = qp_open,
+	.release = qp_release,
+	.read    = debugfs_read,
+	.llseek  = default_llseek,
+};
+
+static int dump_stag(int id, void *p, void *data)
 {
-	struct debugfs_qp_data *qpd = file->private_data;
-	loff_t pos = *ppos;
-	loff_t avail = qpd->pos;
+	struct c4iw_debugfs_data *stagd = data;
+	int space;
+	int cc;
 
-	if (pos < 0)
-		return -EINVAL;
-	if (pos >= avail)
+	space = stagd->bufsize - stagd->pos - 1;
+	if (space == 0)
+		return 1;
+
+	cc = snprintf(stagd->buf + stagd->pos, space, "0x%x\n", id<<8);
+	if (cc < space)
+		stagd->pos += cc;
+	return 0;
+}
+
+static int stag_release(struct inode *inode, struct file *file)
+{
+	struct c4iw_debugfs_data *stagd = file->private_data;
+	if (!stagd) {
+		printk(KERN_INFO "%s null stagd?\n", __func__);
 		return 0;
-	if (count > avail - pos)
-		count = avail - pos;
+	}
+	kfree(stagd->buf);
+	kfree(stagd);
+	return 0;
+}
 
-	while (count) {
-		size_t len = 0;
+static int stag_open(struct inode *inode, struct file *file)
+{
+	struct c4iw_debugfs_data *stagd;
+	int ret = 0;
+	int count = 1;
 
-		len = min((int)count, (int)qpd->pos - (int)pos);
-		if (copy_to_user(buf, qpd->buf + pos, len))
-			return -EFAULT;
-		if (len == 0)
-			return -EINVAL;
+	stagd = kmalloc(sizeof *stagd, GFP_KERNEL);
+	if (!stagd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	stagd->devp = inode->i_private;
+	stagd->pos = 0;
 
-		buf += len;
-		pos += len;
-		count -= len;
+	spin_lock_irq(&stagd->devp->lock);
+	idr_for_each(&stagd->devp->mmidr, count_idrs, &count);
+	spin_unlock_irq(&stagd->devp->lock);
+
+	stagd->bufsize = count * sizeof("0x12345678\n");
+	stagd->buf = kmalloc(stagd->bufsize, GFP_KERNEL);
+	if (!stagd->buf) {
+		ret = -ENOMEM;
+		goto err1;
 	}
-	count = pos - *ppos;
-	*ppos = pos;
-	return count;
+
+	spin_lock_irq(&stagd->devp->lock);
+	idr_for_each(&stagd->devp->mmidr, dump_stag, stagd);
+	spin_unlock_irq(&stagd->devp->lock);
+
+	stagd->buf[stagd->pos++] = 0;
+	file->private_data = stagd;
+	goto out;
+err1:
+	kfree(stagd);
+out:
+	return ret;
 }
 
-static const struct file_operations qp_debugfs_fops = {
+static const struct file_operations stag_debugfs_fops = {
 	.owner   = THIS_MODULE,
-	.open    = qp_open,
-	.release = qp_release,
-	.read    = qp_read,
+	.open    = stag_open,
+	.release = stag_release,
+	.read    = debugfs_read,
+	.llseek  = default_llseek,
 };
 
 static int setup_debugfs(struct c4iw_dev *devp)
@@ -199,6 +246,11 @@
 				 (void *)devp, &qp_debugfs_fops);
 	if (de && de->d_inode)
 		de->d_inode->i_size = 4096;
+
+	de = debugfs_create_file("stags", S_IWUSR, devp->debugfs_root,
+				 (void *)devp, &stag_debugfs_fops);
+	if (de && de->d_inode)
+		de->d_inode->i_size = 4096;
 	return 0;
 }
 
@@ -290,7 +342,14 @@
 		printk(KERN_ERR MOD "error %d initializing rqt pool\n", err);
 		goto err3;
 	}
+	err = c4iw_ocqp_pool_create(rdev);
+	if (err) {
+		printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
+		goto err4;
+	}
 	return 0;
+err4:
+	c4iw_rqtpool_destroy(rdev);
 err3:
 	c4iw_pblpool_destroy(rdev);
 err2:
@@ -317,6 +376,7 @@
 	idr_destroy(&dev->cqidr);
 	idr_destroy(&dev->qpidr);
 	idr_destroy(&dev->mmidr);
+	iounmap(dev->rdev.oc_mw_kva);
 	ib_dealloc_device(&dev->ibdev);
 }
 
@@ -332,6 +392,17 @@
 	}
 	devp->rdev.lldi = *infop;
 
+	devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) +
+		(pci_resource_len(devp->rdev.lldi.pdev, 2) -
+		 roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size));
+	devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
+					       devp->rdev.lldi.vr->ocq.size);
+
+	printk(KERN_INFO MOD "ocq memory: "
+	       "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
+	       devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
+	       devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
+
 	mutex_lock(&dev_mutex);
 
 	ret = c4iw_rdev_open(&devp->rdev);
@@ -383,46 +454,6 @@
 	return dev;
 }
 
-static struct sk_buff *t4_pktgl_to_skb(const struct pkt_gl *gl,
-				       unsigned int skb_len,
-				       unsigned int pull_len)
-{
-	struct sk_buff *skb;
-	struct skb_shared_info *ssi;
-
-	if (gl->tot_len <= 512) {
-		skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
-		if (unlikely(!skb))
-			goto out;
-		__skb_put(skb, gl->tot_len);
-		skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
-	} else {
-		skb = alloc_skb(skb_len, GFP_ATOMIC);
-		if (unlikely(!skb))
-			goto out;
-		__skb_put(skb, pull_len);
-		skb_copy_to_linear_data(skb, gl->va, pull_len);
-
-		ssi = skb_shinfo(skb);
-		ssi->frags[0].page = gl->frags[0].page;
-		ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
-		ssi->frags[0].size = gl->frags[0].size - pull_len;
-		if (gl->nfrags > 1)
-			memcpy(&ssi->frags[1], &gl->frags[1],
-			       (gl->nfrags - 1) * sizeof(skb_frag_t));
-		ssi->nr_frags = gl->nfrags;
-
-		skb->len = gl->tot_len;
-		skb->data_len = skb->len - pull_len;
-		skb->truesize += skb->data_len;
-
-		/* Get a reference for the last page, we don't own it */
-		get_page(gl->frags[gl->nfrags - 1].page);
-	}
-out:
-	return skb;
-}
-
 static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
 			const struct pkt_gl *gl)
 {
@@ -447,7 +478,7 @@
 		c4iw_ev_handler(dev, qid);
 		return 0;
 	} else {
-		skb = t4_pktgl_to_skb(gl, 128, 128);
+		skb = cxgb4_pktgl_to_skb(gl, 128, 128);
 		if (unlikely(!skb))
 			goto nomem;
 	}
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/ev.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/ev.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/ev.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/ev.c	2011-01-04 19:50:19.000000000 -0500
@@ -60,7 +60,7 @@
 	if (qhp->attr.state == C4IW_QP_STATE_RTS) {
 		attrs.next_state = C4IW_QP_STATE_TERMINATE;
 		c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
-			       &attrs, 1);
+			       &attrs, 0);
 	}
 
 	event.event = ib_event;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/iw_cxgb4.h linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/iw_cxgb4.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/iw_cxgb4.h	2011-01-04 19:50:19.000000000 -0500
@@ -46,6 +46,7 @@
 #include <linux/timer.h>
 #include <linux/io.h>
 #include <linux/kfifo.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 
@@ -79,21 +80,6 @@
 	return skb->data;
 }
 
-#define C4IW_WR_TO (10*HZ)
-
-struct c4iw_wr_wait {
-	wait_queue_head_t wait;
-	int done;
-	int ret;
-};
-
-static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
-{
-	wr_waitp->ret = 0;
-	wr_waitp->done = 0;
-	init_waitqueue_head(&wr_waitp->wait);
-}
-
 struct c4iw_resource {
 	struct kfifo tpt_fifo;
 	spinlock_t tpt_fifo_lock;
@@ -127,8 +113,11 @@
 	struct c4iw_dev_ucontext uctx;
 	struct gen_pool *pbl_pool;
 	struct gen_pool *rqt_pool;
+	struct gen_pool *ocqp_pool;
 	u32 flags;
 	struct cxgb4_lld_info lldi;
+	unsigned long oc_mw_pa;
+	void __iomem *oc_mw_kva;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -141,6 +130,44 @@
 	return min((int)T4_MAX_NUM_STAG, (int)(rdev->lldi.vr->stag.size >> 5));
 }
 
+#define C4IW_WR_TO (10*HZ)
+
+struct c4iw_wr_wait {
+	wait_queue_head_t wait;
+	int done;
+	int ret;
+};
+
+static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
+{
+	wr_waitp->ret = 0;
+	wr_waitp->done = 0;
+	init_waitqueue_head(&wr_waitp->wait);
+}
+
+static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
+				 struct c4iw_wr_wait *wr_waitp,
+				 u32 hwtid, u32 qpid,
+				 const char *func)
+{
+	unsigned to = C4IW_WR_TO;
+	do {
+
+		wait_event_timeout(wr_waitp->wait, wr_waitp->done, to);
+		if (!wr_waitp->done) {
+			printk(KERN_ERR MOD "%s - Device %s not responding - "
+			       "tid %u qpid %u\n", func,
+			       pci_name(rdev->lldi.pdev), hwtid, qpid);
+			to = to << 2;
+		}
+	} while (!wr_waitp->done);
+	if (wr_waitp->ret)
+		printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n",
+		       pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
+	return wr_waitp->ret;
+}
+
+
 struct c4iw_dev {
 	struct ib_device ibdev;
 	struct c4iw_rdev rdev;
@@ -327,6 +354,7 @@
 	struct c4iw_qp_attributes attr;
 	struct t4_wq wq;
 	spinlock_t lock;
+	struct mutex mutex;
 	atomic_t refcnt;
 	wait_queue_head_t wait;
 	struct timer_list timer;
@@ -579,12 +607,10 @@
 	struct c4iw_dev *dev;
 	enum c4iw_ep_state state;
 	struct kref kref;
-	spinlock_t lock;
+	struct mutex mutex;
 	struct sockaddr_in local_addr;
 	struct sockaddr_in remote_addr;
-	wait_queue_head_t waitq;
-	int rpl_done;
-	int rpl_err;
+	struct c4iw_wr_wait wr_wait;
 	unsigned long flags;
 };
 
@@ -654,8 +680,10 @@
 int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_pblpool_create(struct c4iw_rdev *rdev);
 int c4iw_rqtpool_create(struct c4iw_rdev *rdev);
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev);
 void c4iw_pblpool_destroy(struct c4iw_rdev *rdev);
 void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev);
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev);
 void c4iw_destroy_resource(struct c4iw_resource *rscp);
 int c4iw_destroy_ctrl_qp(struct c4iw_rdev *rdev);
 int c4iw_register_device(struct c4iw_dev *dev);
@@ -721,6 +749,8 @@
 void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size);
 void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size);
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size);
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size);
 int c4iw_ofld_send(struct c4iw_rdev *rdev, struct sk_buff *skb);
 void c4iw_flush_hw_cq(struct t4_cq *cq);
 void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/Kconfig linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/Kconfig
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -10,7 +10,7 @@
 	  our website at <http://www.chelsio.com>.
 
 	  For customer support, please visit our customer support page at
-	  <http://www.chelsio.com/support.htm>.
+	  <http://www.chelsio.com/support.html>.
 
 	  Please send feedback to <linux-bugs@chelsio.com>.
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/Makefile linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/Makefile
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -Idrivers/net/cxgb4
+ccflags-y := -Idrivers/net/cxgb4
 
 obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/mem.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/mem.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/mem.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/mem.c	2011-01-04 19:50:19.000000000 -0500
@@ -71,7 +71,7 @@
 		if (i == (num_wqe-1)) {
 			req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
 						    FW_WR_COMPL(1));
-			req->wr.wr_lo = (__force __be64)&wr_wait;
+			req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
 		} else
 			req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR));
 		req->wr.wr_mid = cpu_to_be32(
@@ -103,14 +103,7 @@
 		len -= C4IW_MAX_INLINE_SIZE;
 	}
 
-	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-	if (!wr_wait.done) {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(rdev->lldi.pdev));
-		rdev->flags = T4_FATAL_ERROR;
-		ret = -EIO;
-	} else
-		ret = wr_wait.ret;
+	ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
 	return ret;
 }
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/provider.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/provider.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/provider.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/provider.c	2011-01-04 19:50:19.000000000 -0500
@@ -54,9 +54,9 @@
 
 #include "iw_cxgb4.h"
 
-static int fastreg_support;
+static int fastreg_support = 1;
 module_param(fastreg_support, int, 0644);
-MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=0)");
+MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=1)");
 
 static int c4iw_modify_port(struct ib_device *ibdev,
 			    u8 port, int port_modify_mask,
@@ -149,19 +149,28 @@
 	addr = mm->addr;
 	kfree(mm);
 
-	if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
-	    (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
-		       pci_resource_len(rdev->lldi.pdev, 2)))) {
+	if ((addr >= pci_resource_start(rdev->lldi.pdev, 0)) &&
+	    (addr < (pci_resource_start(rdev->lldi.pdev, 0) +
+		    pci_resource_len(rdev->lldi.pdev, 0)))) {
 
 		/*
-		 * Map T4 DB register.
+		 * MA_SYNC register...
 		 */
-		if (vma->vm_flags & VM_READ)
-			return -EPERM;
-
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-		vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
-		vma->vm_flags &= ~VM_MAYREAD;
+		ret = io_remap_pfn_range(vma, vma->vm_start,
+					 addr >> PAGE_SHIFT,
+					 len, vma->vm_page_prot);
+	} else if ((addr >= pci_resource_start(rdev->lldi.pdev, 2)) &&
+		   (addr < (pci_resource_start(rdev->lldi.pdev, 2) +
+		    pci_resource_len(rdev->lldi.pdev, 2)))) {
+
+		/*
+		 * Map user DB or OCQP memory...
+		 */
+		if (addr >= rdev->oc_mw_pa)
+			vma->vm_page_prot = t4_pgprot_wc(vma->vm_page_prot);
+		else
+			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 		ret = io_remap_pfn_range(vma, vma->vm_start,
 					 addr >> PAGE_SHIFT,
 					 len, vma->vm_page_prot);
@@ -382,7 +391,17 @@
 static int c4iw_get_mib(struct ib_device *ibdev,
 			union rdma_protocol_stats *stats)
 {
-	return -ENOSYS;
+	struct tp_tcp_stats v4, v6;
+	struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev);
+
+	cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
+	memset(stats, 0, sizeof *stats);
+	stats->iw.tcpInSegs = v4.tcpInSegs + v6.tcpInSegs;
+	stats->iw.tcpOutSegs = v4.tcpOutSegs + v6.tcpOutSegs;
+	stats->iw.tcpRetransSegs = v4.tcpRetransSegs + v6.tcpRetransSegs;
+	stats->iw.tcpOutRsts = v4.tcpOutRsts + v6.tcpOutSegs;
+
+	return 0;
 }
 
 static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
@@ -472,6 +491,7 @@
 	dev->ibdev.post_send = c4iw_post_send;
 	dev->ibdev.post_recv = c4iw_post_receive;
 	dev->ibdev.get_protocol_stats = c4iw_get_mib;
+	dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
 
 	dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
 	if (!dev->ibdev.iwcm)
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/qp.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/qp.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/qp.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/qp.c	2011-01-04 19:50:19.000000000 -0500
@@ -31,6 +31,63 @@
  */
 #include "iw_cxgb4.h"
 
+static int ocqp_support;
+module_param(ocqp_support, int, 0644);
+MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=0)");
+
+static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
+{
+	unsigned long flag;
+	spin_lock_irqsave(&qhp->lock, flag);
+	qhp->attr.state = state;
+	spin_unlock_irqrestore(&qhp->lock, flag);
+}
+
+static void dealloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+	c4iw_ocqp_pool_free(rdev, sq->dma_addr, sq->memsize);
+}
+
+static void dealloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+	dma_free_coherent(&(rdev->lldi.pdev->dev), sq->memsize, sq->queue,
+			  pci_unmap_addr(sq, mapping));
+}
+
+static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+	if (t4_sq_onchip(sq))
+		dealloc_oc_sq(rdev, sq);
+	else
+		dealloc_host_sq(rdev, sq);
+}
+
+static int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+	if (!ocqp_support || !t4_ocqp_supported())
+		return -ENOSYS;
+	sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
+	if (!sq->dma_addr)
+		return -ENOMEM;
+	sq->phys_addr = rdev->oc_mw_pa + sq->dma_addr -
+			rdev->lldi.vr->ocq.start;
+	sq->queue = (__force union t4_wr *)(rdev->oc_mw_kva + sq->dma_addr -
+					    rdev->lldi.vr->ocq.start);
+	sq->flags |= T4_SQ_ONCHIP;
+	return 0;
+}
+
+static int alloc_host_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
+{
+	sq->queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev), sq->memsize,
+				       &(sq->dma_addr), GFP_KERNEL);
+	if (!sq->queue)
+		return -ENOMEM;
+	sq->phys_addr = virt_to_phys(sq->queue);
+	pci_unmap_addr_set(sq, mapping, sq->dma_addr);
+	return 0;
+}
+
 static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
 		      struct c4iw_dev_ucontext *uctx)
 {
@@ -41,9 +98,7 @@
 	dma_free_coherent(&(rdev->lldi.pdev->dev),
 			  wq->rq.memsize, wq->rq.queue,
 			  dma_unmap_addr(&wq->rq, mapping));
-	dma_free_coherent(&(rdev->lldi.pdev->dev),
-			  wq->sq.memsize, wq->sq.queue,
-			  dma_unmap_addr(&wq->sq, mapping));
+	dealloc_sq(rdev, &wq->sq);
 	c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
 	kfree(wq->rq.sw_rq);
 	kfree(wq->sq.sw_sq);
@@ -93,11 +148,12 @@
 	if (!wq->rq.rqt_hwaddr)
 		goto err4;
 
-	wq->sq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
-					  wq->sq.memsize, &(wq->sq.dma_addr),
-					  GFP_KERNEL);
-	if (!wq->sq.queue)
-		goto err5;
+	if (user) {
+		if (alloc_oc_sq(rdev, &wq->sq) && alloc_host_sq(rdev, &wq->sq))
+			goto err5;
+	} else
+		if (alloc_host_sq(rdev, &wq->sq))
+			goto err5;
 	memset(wq->sq.queue, 0, wq->sq.memsize);
 	dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
 
@@ -144,7 +200,7 @@
 			V_FW_RI_RES_WR_NRES(2) |
 			FW_WR_COMPL(1));
 	res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
-	res_wr->cookie = (u64)&wr_wait;
+	res_wr->cookie = (unsigned long) &wr_wait;
 	res = res_wr->res;
 	res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
 	res->u.sqrq.op = FW_RI_RES_OP_WRITE;
@@ -158,6 +214,7 @@
 		V_FW_RI_RES_WR_HOSTFCMODE(0) |	/* no host cidx updates */
 		V_FW_RI_RES_WR_CPRIO(0) |	/* don't keep in chip cache */
 		V_FW_RI_RES_WR_PCIECHN(0) |	/* set by uP at ri_init time */
+		t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 |
 		V_FW_RI_RES_WR_IQID(scq->cqid));
 	res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
 		V_FW_RI_RES_WR_DCAEN(0) |
@@ -198,14 +255,7 @@
 	ret = c4iw_ofld_send(rdev, skb);
 	if (ret)
 		goto err7;
-	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-	if (!wr_wait.done) {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(rdev->lldi.pdev));
-		rdev->flags = T4_FATAL_ERROR;
-		ret = -EIO;
-	} else
-		ret = wr_wait.ret;
+	ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, wq->sq.qid, __func__);
 	if (ret)
 		goto err7;
 
@@ -219,9 +269,7 @@
 			  wq->rq.memsize, wq->rq.queue,
 			  dma_unmap_addr(&wq->rq, mapping));
 err6:
-	dma_free_coherent(&(rdev->lldi.pdev->dev),
-			  wq->sq.memsize, wq->sq.queue,
-			  dma_unmap_addr(&wq->sq, mapping));
+	dealloc_sq(rdev, &wq->sq);
 err5:
 	c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
 err4:
@@ -263,6 +311,9 @@
 			rem -= len;
 		}
 	}
+	len = roundup(plen + sizeof *immdp, 16) - (plen + sizeof *immdp);
+	if (len)
+		memset(dstp, 0, len);
 	immdp->op = FW_RI_DATA_IMMD;
 	immdp->r1 = 0;
 	immdp->r2 = 0;
@@ -292,6 +343,7 @@
 		if (++flitp == queue_end)
 			flitp = queue_start;
 	}
+	*flitp = (__force __be64)0;
 	isglp->op = FW_RI_DATA_ISGL;
 	isglp->r1 = 0;
 	isglp->nsge = cpu_to_be16(num_sge);
@@ -453,13 +505,15 @@
 	return 0;
 }
 
-static int build_fastreg(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
+static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
+			 struct ib_send_wr *wr, u8 *len16)
 {
 
 	struct fw_ri_immd *imdp;
 	__be64 *p;
 	int i;
 	int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32);
+	int rem;
 
 	if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH)
 		return -EINVAL;
@@ -474,32 +528,28 @@
 	wqe->fr.va_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);
 	wqe->fr.va_lo_fbo = cpu_to_be32(wr->wr.fast_reg.iova_start &
 					0xffffffff);
-	if (pbllen > T4_MAX_FR_IMMD) {
-		struct c4iw_fr_page_list *c4pl =
-				to_c4iw_fr_page_list(wr->wr.fast_reg.page_list);
-		struct fw_ri_dsgl *sglp;
-
-		sglp = (struct fw_ri_dsgl *)(&wqe->fr + 1);
-		sglp->op = FW_RI_DATA_DSGL;
-		sglp->r1 = 0;
-		sglp->nsge = cpu_to_be16(1);
-		sglp->addr0 = cpu_to_be64(c4pl->dma_addr);
-		sglp->len0 = cpu_to_be32(pbllen);
-
-		*len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *sglp, 16);
-	} else {
-		imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
-		imdp->op = FW_RI_DATA_IMMD;
-		imdp->r1 = 0;
-		imdp->r2 = 0;
-		imdp->immdlen = cpu_to_be32(pbllen);
-		p = (__be64 *)(imdp + 1);
-		for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++)
-			*p = cpu_to_be64(
-				(u64)wr->wr.fast_reg.page_list->page_list[i]);
-		*len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen,
-				      16);
+	WARN_ON(pbllen > T4_MAX_FR_IMMD);
+	imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+	imdp->op = FW_RI_DATA_IMMD;
+	imdp->r1 = 0;
+	imdp->r2 = 0;
+	imdp->immdlen = cpu_to_be32(pbllen);
+	p = (__be64 *)(imdp + 1);
+	rem = pbllen;
+	for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) {
+		*p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);
+		rem -= sizeof *p;
+		if (++p == (__be64 *)&sq->queue[sq->size])
+			p = (__be64 *)sq->queue;
 	}
+	BUG_ON(rem < 0);
+	while (rem) {
+		*p = 0;
+		rem -= sizeof *p;
+		if (++p == (__be64 *)&sq->queue[sq->size])
+			p = (__be64 *)sq->queue;
+	}
+	*len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
 	return 0;
 }
 
@@ -587,7 +637,7 @@
 			fw_opcode = FW_RI_RDMA_READ_WR;
 			swsqe->opcode = FW_RI_READ_REQ;
 			if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)
-				fw_flags |= FW_RI_RDMA_READ_INVALIDATE;
+				fw_flags = FW_RI_RDMA_READ_INVALIDATE;
 			else
 				fw_flags = 0;
 			err = build_rdma_read(wqe, wr, &len16);
@@ -600,7 +650,7 @@
 		case IB_WR_FAST_REG_MR:
 			fw_opcode = FW_RI_FR_NSMR_WR;
 			swsqe->opcode = FW_RI_FAST_REGISTER;
-			err = build_fastreg(wqe, wr, &len16);
+			err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16);
 			break;
 		case IB_WR_LOCAL_INV:
 			if (wr->send_flags & IB_SEND_FENCE)
@@ -905,46 +955,38 @@
  * Assumes qhp lock is held.
  */
 static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
-		       struct c4iw_cq *schp, unsigned long *flag)
+		       struct c4iw_cq *schp)
 {
 	int count;
 	int flushed;
+	unsigned long flag;
 
 	PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);
-	/* take a ref on the qhp since we must release the lock */
-	atomic_inc(&qhp->refcnt);
-	spin_unlock_irqrestore(&qhp->lock, *flag);
 
 	/* locking hierarchy: cq lock first, then qp lock. */
-	spin_lock_irqsave(&rchp->lock, *flag);
+	spin_lock_irqsave(&rchp->lock, flag);
 	spin_lock(&qhp->lock);
 	c4iw_flush_hw_cq(&rchp->cq);
 	c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
 	flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
 	spin_unlock(&qhp->lock);
-	spin_unlock_irqrestore(&rchp->lock, *flag);
+	spin_unlock_irqrestore(&rchp->lock, flag);
 	if (flushed)
 		(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
 
 	/* locking hierarchy: cq lock first, then qp lock. */
-	spin_lock_irqsave(&schp->lock, *flag);
+	spin_lock_irqsave(&schp->lock, flag);
 	spin_lock(&qhp->lock);
 	c4iw_flush_hw_cq(&schp->cq);
 	c4iw_count_scqes(&schp->cq, &qhp->wq, &count);
 	flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
 	spin_unlock(&qhp->lock);
-	spin_unlock_irqrestore(&schp->lock, *flag);
+	spin_unlock_irqrestore(&schp->lock, flag);
 	if (flushed)
 		(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
-
-	/* deref */
-	if (atomic_dec_and_test(&qhp->refcnt))
-		wake_up(&qhp->wait);
-
-	spin_lock_irqsave(&qhp->lock, *flag);
 }
 
-static void flush_qp(struct c4iw_qp *qhp, unsigned long *flag)
+static void flush_qp(struct c4iw_qp *qhp)
 {
 	struct c4iw_cq *rchp, *schp;
 
@@ -958,7 +1000,7 @@
 			t4_set_cq_in_error(&schp->cq);
 		return;
 	}
-	__flush_qp(qhp, rchp, schp, flag);
+	__flush_qp(qhp, rchp, schp);
 }
 
 static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
@@ -966,7 +1008,6 @@
 {
 	struct fw_ri_wr *wqe;
 	int ret;
-	struct c4iw_wr_wait wr_wait;
 	struct sk_buff *skb;
 
 	PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -985,28 +1026,16 @@
 	wqe->flowid_len16 = cpu_to_be32(
 		FW_WR_FLOWID(ep->hwtid) |
 		FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
-	wqe->cookie = (u64)&wr_wait;
+	wqe->cookie = (unsigned long) &ep->com.wr_wait;
 
 	wqe->u.fini.type = FW_RI_TYPE_FINI;
-	c4iw_init_wr_wait(&wr_wait);
+	c4iw_init_wr_wait(&ep->com.wr_wait);
 	ret = c4iw_ofld_send(&rhp->rdev, skb);
 	if (ret)
 		goto out;
 
-	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-	if (!wr_wait.done) {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(rhp->rdev.lldi.pdev));
-		rhp->rdev.flags = T4_FATAL_ERROR;
-		ret = -EIO;
-	} else {
-		ret = wr_wait.ret;
-		if (ret)
-			printk(KERN_WARNING MOD
-			       "%s: Abnormal close qpid %d ret %u\n",
-			       pci_name(rhp->rdev.lldi.pdev), qhp->wq.sq.qid,
-			       ret);
-	}
+	ret = c4iw_wait_for_reply(&rhp->rdev, &ep->com.wr_wait, qhp->ep->hwtid,
+			     qhp->wq.sq.qid, __func__);
 out:
 	PDBG("%s ret %d\n", __func__, ret);
 	return ret;
@@ -1040,7 +1069,6 @@
 {
 	struct fw_ri_wr *wqe;
 	int ret;
-	struct c4iw_wr_wait wr_wait;
 	struct sk_buff *skb;
 
 	PDBG("%s qhp %p qid 0x%x tid %u\n", __func__, qhp, qhp->wq.sq.qid,
@@ -1060,7 +1088,7 @@
 		FW_WR_FLOWID(qhp->ep->hwtid) |
 		FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
 
-	wqe->cookie = (u64)&wr_wait;
+	wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
 
 	wqe->u.init.type = FW_RI_TYPE_INIT;
 	wqe->u.init.mpareqbit_p2ptype =
@@ -1097,19 +1125,13 @@
 	if (qhp->attr.mpa_attr.initiator)
 		build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
 
-	c4iw_init_wr_wait(&wr_wait);
+	c4iw_init_wr_wait(&qhp->ep->com.wr_wait);
 	ret = c4iw_ofld_send(&rhp->rdev, skb);
 	if (ret)
 		goto out;
 
-	wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
-	if (!wr_wait.done) {
-		printk(KERN_ERR MOD "Device %s not responding!\n",
-		       pci_name(rhp->rdev.lldi.pdev));
-		rhp->rdev.flags = T4_FATAL_ERROR;
-		ret = -EIO;
-	} else
-		ret = wr_wait.ret;
+	ret = c4iw_wait_for_reply(&rhp->rdev, &qhp->ep->com.wr_wait,
+				  qhp->ep->hwtid, qhp->wq.sq.qid, __func__);
 out:
 	PDBG("%s ret %d\n", __func__, ret);
 	return ret;
@@ -1122,7 +1144,6 @@
 {
 	int ret = 0;
 	struct c4iw_qp_attributes newattr = qhp->attr;
-	unsigned long flag;
 	int disconnect = 0;
 	int terminate = 0;
 	int abort = 0;
@@ -1133,7 +1154,7 @@
 	     qhp, qhp->wq.sq.qid, qhp->wq.rq.qid, qhp->ep, qhp->attr.state,
 	     (mask & C4IW_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);
 
-	spin_lock_irqsave(&qhp->lock, flag);
+	mutex_lock(&qhp->mutex);
 
 	/* Process attr changes if in IDLE */
 	if (mask & C4IW_QP_ATTR_VALID_MODIFY) {
@@ -1184,7 +1205,7 @@
 			qhp->attr.mpa_attr = attrs->mpa_attr;
 			qhp->attr.llp_stream_handle = attrs->llp_stream_handle;
 			qhp->ep = qhp->attr.llp_stream_handle;
-			qhp->attr.state = C4IW_QP_STATE_RTS;
+			set_state(qhp, C4IW_QP_STATE_RTS);
 
 			/*
 			 * Ref the endpoint here and deref when we
@@ -1193,15 +1214,13 @@
 			 * transition.
 			 */
 			c4iw_get_ep(&qhp->ep->com);
-			spin_unlock_irqrestore(&qhp->lock, flag);
 			ret = rdma_init(rhp, qhp);
-			spin_lock_irqsave(&qhp->lock, flag);
 			if (ret)
 				goto err;
 			break;
 		case C4IW_QP_STATE_ERROR:
-			qhp->attr.state = C4IW_QP_STATE_ERROR;
-			flush_qp(qhp, &flag);
+			set_state(qhp, C4IW_QP_STATE_ERROR);
+			flush_qp(qhp);
 			break;
 		default:
 			ret = -EINVAL;
@@ -1212,38 +1231,38 @@
 		switch (attrs->next_state) {
 		case C4IW_QP_STATE_CLOSING:
 			BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);
-			qhp->attr.state = C4IW_QP_STATE_CLOSING;
+			set_state(qhp, C4IW_QP_STATE_CLOSING);
 			ep = qhp->ep;
 			if (!internal) {
 				abort = 0;
 				disconnect = 1;
-				c4iw_get_ep(&ep->com);
+				c4iw_get_ep(&qhp->ep->com);
 			}
-			spin_unlock_irqrestore(&qhp->lock, flag);
 			ret = rdma_fini(rhp, qhp, ep);
-			spin_lock_irqsave(&qhp->lock, flag);
 			if (ret) {
-				c4iw_get_ep(&ep->com);
+				if (internal)
+					c4iw_get_ep(&qhp->ep->com);
 				disconnect = abort = 1;
 				goto err;
 			}
 			break;
 		case C4IW_QP_STATE_TERMINATE:
-			qhp->attr.state = C4IW_QP_STATE_TERMINATE;
+			set_state(qhp, C4IW_QP_STATE_TERMINATE);
 			if (qhp->ibqp.uobject)
 				t4_set_wq_in_error(&qhp->wq);
 			ep = qhp->ep;
-			c4iw_get_ep(&ep->com);
-			terminate = 1;
+			if (!internal)
+				terminate = 1;
 			disconnect = 1;
+			c4iw_get_ep(&qhp->ep->com);
 			break;
 		case C4IW_QP_STATE_ERROR:
-			qhp->attr.state = C4IW_QP_STATE_ERROR;
+			set_state(qhp, C4IW_QP_STATE_ERROR);
 			if (!internal) {
 				abort = 1;
 				disconnect = 1;
 				ep = qhp->ep;
-				c4iw_get_ep(&ep->com);
+				c4iw_get_ep(&qhp->ep->com);
 			}
 			goto err;
 			break;
@@ -1259,8 +1278,8 @@
 		}
 		switch (attrs->next_state) {
 		case C4IW_QP_STATE_IDLE:
-			flush_qp(qhp, &flag);
-			qhp->attr.state = C4IW_QP_STATE_IDLE;
+			flush_qp(qhp);
+			set_state(qhp, C4IW_QP_STATE_IDLE);
 			qhp->attr.llp_stream_handle = NULL;
 			c4iw_put_ep(&qhp->ep->com);
 			qhp->ep = NULL;
@@ -1282,7 +1301,7 @@
 			ret = -EINVAL;
 			goto out;
 		}
-		qhp->attr.state = C4IW_QP_STATE_IDLE;
+		set_state(qhp, C4IW_QP_STATE_IDLE);
 		break;
 	case C4IW_QP_STATE_TERMINATE:
 		if (!internal) {
@@ -1305,15 +1324,16 @@
 
 	/* disassociate the LLP connection */
 	qhp->attr.llp_stream_handle = NULL;
-	ep = qhp->ep;
+	if (!ep)
+		ep = qhp->ep;
 	qhp->ep = NULL;
-	qhp->attr.state = C4IW_QP_STATE_ERROR;
+	set_state(qhp, C4IW_QP_STATE_ERROR);
 	free = 1;
 	wake_up(&qhp->wait);
 	BUG_ON(!ep);
-	flush_qp(qhp, &flag);
+	flush_qp(qhp);
 out:
-	spin_unlock_irqrestore(&qhp->lock, flag);
+	mutex_unlock(&qhp->mutex);
 
 	if (terminate)
 		post_terminate(qhp, NULL, internal ? GFP_ATOMIC : GFP_KERNEL);
@@ -1335,7 +1355,6 @@
 	 */
 	if (free)
 		c4iw_put_ep(&ep->com);
-
 	PDBG("%s exit state %d\n", __func__, qhp->attr.state);
 	return ret;
 }
@@ -1380,7 +1399,7 @@
 	int sqsize, rqsize;
 	struct c4iw_ucontext *ucontext;
 	int ret;
-	struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4;
+	struct c4iw_mm_entry *mm1, *mm2, *mm3, *mm4, *mm5 = NULL;
 
 	PDBG("%s ib_pd %p\n", __func__, pd);
 
@@ -1450,6 +1469,7 @@
 	qhp->attr.max_ord = 1;
 	qhp->attr.max_ird = 1;
 	spin_lock_init(&qhp->lock);
+	mutex_init(&qhp->mutex);
 	init_waitqueue_head(&qhp->wait);
 	atomic_set(&qhp->refcnt, 1);
 
@@ -1478,7 +1498,15 @@
 			ret = -ENOMEM;
 			goto err6;
 		}
-
+		if (t4_sq_onchip(&qhp->wq.sq)) {
+			mm5 = kmalloc(sizeof *mm5, GFP_KERNEL);
+			if (!mm5) {
+				ret = -ENOMEM;
+				goto err7;
+			}
+			uresp.flags = C4IW_QPF_ONCHIP;
+		} else
+			uresp.flags = 0;
 		uresp.qid_mask = rhp->rdev.qpmask;
 		uresp.sqid = qhp->wq.sq.qid;
 		uresp.sq_size = qhp->wq.sq.size;
@@ -1487,6 +1515,10 @@
 		uresp.rq_size = qhp->wq.rq.size;
 		uresp.rq_memsize = qhp->wq.rq.memsize;
 		spin_lock(&ucontext->mmap_lock);
+		if (mm5) {
+			uresp.ma_sync_key = ucontext->key;
+			ucontext->key += PAGE_SIZE;
+		}
 		uresp.sq_key = ucontext->key;
 		ucontext->key += PAGE_SIZE;
 		uresp.rq_key = ucontext->key;
@@ -1498,9 +1530,9 @@
 		spin_unlock(&ucontext->mmap_lock);
 		ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
 		if (ret)
-			goto err7;
+			goto err8;
 		mm1->key = uresp.sq_key;
-		mm1->addr = virt_to_phys(qhp->wq.sq.queue);
+		mm1->addr = qhp->wq.sq.phys_addr;
 		mm1->len = PAGE_ALIGN(qhp->wq.sq.memsize);
 		insert_mmap(ucontext, mm1);
 		mm2->key = uresp.rq_key;
@@ -1515,6 +1547,13 @@
 		mm4->addr = qhp->wq.rq.udb;
 		mm4->len = PAGE_SIZE;
 		insert_mmap(ucontext, mm4);
+		if (mm5) {
+			mm5->key = uresp.ma_sync_key;
+			mm5->addr = (pci_resource_start(rhp->rdev.lldi.pdev, 0)
+				    + A_PCIE_MA_SYNC) & PAGE_MASK;
+			mm5->len = PAGE_SIZE;
+			insert_mmap(ucontext, mm5);
+		}
 	}
 	qhp->ibqp.qp_num = qhp->wq.sq.qid;
 	init_timer(&(qhp->timer));
@@ -1522,6 +1561,8 @@
 	     __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
 	     qhp->wq.sq.qid);
 	return &qhp->ibqp;
+err8:
+	kfree(mm5);
 err7:
 	kfree(mm4);
 err6:
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/resource.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/resource.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/resource.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/resource.c	2011-01-04 19:50:19.000000000 -0500
@@ -311,6 +311,9 @@
 {
 	unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
 	PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+	if (!addr && printk_ratelimit())
+		printk(KERN_WARNING MOD "%s: Out of PBL memory\n",
+		       pci_name(rdev->lldi.pdev));
 	return (u32)addr;
 }
 
@@ -370,6 +373,9 @@
 {
 	unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
 	PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
+	if (!addr && printk_ratelimit())
+		printk(KERN_WARNING MOD "%s: Out of RQT memory\n",
+		       pci_name(rdev->lldi.pdev));
 	return (u32)addr;
 }
 
@@ -416,3 +422,59 @@
 {
 	gen_pool_destroy(rdev->rqt_pool);
 }
+
+/*
+ * On-Chip QP Memory.
+ */
+#define MIN_OCQP_SHIFT 12	/* 4KB == min ocqp size */
+
+u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
+{
+	unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
+	PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
+	return (u32)addr;
+}
+
+void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+{
+	PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
+	gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
+}
+
+int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev)
+{
+	unsigned start, chunk, top;
+
+	rdev->ocqp_pool = gen_pool_create(MIN_OCQP_SHIFT, -1);
+	if (!rdev->ocqp_pool)
+		return -ENOMEM;
+
+	start = rdev->lldi.vr->ocq.start;
+	chunk = rdev->lldi.vr->ocq.size;
+	top = start + chunk;
+
+	while (start < top) {
+		chunk = min(top - start + 1, chunk);
+		if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
+			PDBG("%s failed to add OCQP chunk (%x/%x)\n",
+			     __func__, start, chunk);
+			if (chunk <= 1024 << MIN_OCQP_SHIFT) {
+				printk(KERN_WARNING MOD
+				       "Failed to add all OCQP chunks (%x/%x)\n",
+				       start, top - start);
+				return 0;
+			}
+			chunk >>= 1;
+		} else {
+			PDBG("%s added OCQP chunk (%x/%x)\n",
+			     __func__, start, chunk);
+			start += chunk;
+		}
+	}
+	return 0;
+}
+
+void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev)
+{
+	gen_pool_destroy(rdev->ocqp_pool);
+}
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/t4.h linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/t4.h
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/t4.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/t4.h	2011-01-04 19:50:19.000000000 -0500
@@ -52,6 +52,7 @@
 #define T4_STAG_UNSET 0xffffffff
 #define T4_FW_MAJ 0
 #define T4_EQ_STATUS_ENTRIES (L1_CACHE_BYTES > 64 ? 2 : 1)
+#define A_PCIE_MA_SYNC 0x30b4
 
 struct t4_status_page {
 	__be32 rsvd1;	/* flit 0 - hw owns */
@@ -65,7 +66,7 @@
 
 #define T4_EQ_ENTRY_SIZE 64
 
-#define T4_SQ_NUM_SLOTS 4
+#define T4_SQ_NUM_SLOTS 5
 #define T4_SQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_SQ_NUM_SLOTS)
 #define T4_MAX_SEND_SGE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
 			sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
@@ -78,7 +79,7 @@
 			sizeof(struct fw_ri_rdma_write_wr) - \
 			sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
 #define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
-			sizeof(struct fw_ri_immd)))
+			sizeof(struct fw_ri_immd)) & ~31UL)
 #define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
 
 #define T4_RQ_NUM_SLOTS 2
@@ -266,10 +267,36 @@
 	u16			idx;
 };
 
+static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	return pgprot_writecombine(prot);
+#elif defined(CONFIG_PPC64)
+	return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
+			~(pgprot_t)_PAGE_GUARDED);
+#else
+	return pgprot_noncached(prot);
+#endif
+}
+
+static inline int t4_ocqp_supported(void)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+enum {
+	T4_SQ_ONCHIP = (1<<0),
+};
+
 struct t4_sq {
 	union t4_wr *queue;
 	dma_addr_t dma_addr;
 	DEFINE_DMA_UNMAP_ADDR(mapping);
+	unsigned long phys_addr;
 	struct t4_swsqe *sw_sq;
 	struct t4_swsqe *oldest_read;
 	u64 udb;
@@ -280,6 +307,7 @@
 	u16 cidx;
 	u16 pidx;
 	u16 wq_pidx;
+	u16 flags;
 };
 
 struct t4_swrqe {
@@ -350,6 +378,11 @@
 		wq->rq.cidx = 0;
 }
 
+static inline int t4_sq_onchip(struct t4_sq *sq)
+{
+	return sq->flags & T4_SQ_ONCHIP;
+}
+
 static inline int t4_sq_empty(struct t4_wq *wq)
 {
 	return wq->sq.in_use == 0;
@@ -396,30 +429,27 @@
 
 static inline int t4_wq_in_error(struct t4_wq *wq)
 {
-	return wq->sq.queue[wq->sq.size].status.qp_err;
+	return wq->rq.queue[wq->rq.size].status.qp_err;
 }
 
 static inline void t4_set_wq_in_error(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.qp_err = 1;
 	wq->rq.queue[wq->rq.size].status.qp_err = 1;
 }
 
 static inline void t4_disable_wq_db(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.db_off = 1;
 	wq->rq.queue[wq->rq.size].status.db_off = 1;
 }
 
 static inline void t4_enable_wq_db(struct t4_wq *wq)
 {
-	wq->sq.queue[wq->sq.size].status.db_off = 0;
 	wq->rq.queue[wq->rq.size].status.db_off = 0;
 }
 
 static inline int t4_wq_db_enabled(struct t4_wq *wq)
 {
-	return !wq->sq.queue[wq->sq.size].status.db_off;
+	return !wq->rq.queue[wq->rq.size].status.db_off;
 }
 
 struct t4_cq {
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/user.h linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/user.h
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/cxgb4/user.h	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/cxgb4/user.h	2011-01-04 19:50:19.000000000 -0500
@@ -50,7 +50,13 @@
 	__u32 qid_mask;
 };
 
+
+enum {
+	C4IW_QPF_ONCHIP = (1<<0)
+};
+
 struct c4iw_create_qp_resp {
+	__u64 ma_sync_key;
 	__u64 sq_key;
 	__u64 rq_key;
 	__u64 sq_db_gts_key;
@@ -62,5 +68,6 @@
 	__u32 sq_size;
 	__u32 rq_size;
 	__u32 qid_mask;
+	__u32 flags;
 };
 #endif
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/ehca/ehca_mrmw.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/ehca/ehca_mrmw.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/ehca/ehca_mrmw.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/ehca/ehca_mrmw.c	2011-01-04 19:50:19.000000000 -0500
@@ -171,7 +171,7 @@
 		}
 
 		ret = ehca_reg_maxmr(shca, e_maxmr,
-				     (void *)ehca_map_vaddr((void *)KERNELBASE),
+				     (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)),
 				     mr_access_flags, e_pd,
 				     &e_maxmr->ib.ib_mr.lkey,
 				     &e_maxmr->ib.ib_mr.rkey);
@@ -1636,7 +1636,7 @@
 
 	/* register internal max-MR on HCA */
 	size_maxmr = ehca_mr_len;
-	iova_start = (u64 *)ehca_map_vaddr((void *)KERNELBASE);
+	iova_start = (u64 *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START));
 	ib_pbuf.addr = 0;
 	ib_pbuf.size = size_maxmr;
 	num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
@@ -2209,7 +2209,7 @@
 {
 	/* a MR is treated as max-MR only if it fits following: */
 	if ((size == ehca_mr_len) &&
-	    (iova_start == (void *)ehca_map_vaddr((void *)KERNELBASE))) {
+	    (iova_start == (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)))) {
 		ehca_gen_dbg("this is a max-MR");
 		return 1;
 	} else
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_diag.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_diag.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_diag.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_diag.c	2011-01-04 19:50:19.000000000 -0500
@@ -65,7 +65,8 @@
 	.write = ipath_diag_write,
 	.read = ipath_diag_read,
 	.open = ipath_diag_open,
-	.release = ipath_diag_release
+	.release = ipath_diag_release,
+	.llseek = default_llseek,
 };
 
 static ssize_t ipath_diagpkt_write(struct file *fp,
@@ -75,6 +76,7 @@
 static const struct file_operations diagpkt_file_ops = {
 	.owner = THIS_MODULE,
 	.write = ipath_diagpkt_write,
+	.llseek = noop_llseek,
 };
 
 static atomic_t diagpkt_count = ATOMIC_INIT(0);
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_file_ops.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_file_ops.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_file_ops.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_file_ops.c	2011-01-04 19:50:19.000000000 -0500
@@ -40,7 +40,6 @@
 #include <linux/highmem.h>
 #include <linux/io.h>
 #include <linux/jiffies.h>
-#include <linux/smp_lock.h>
 #include <asm/pgtable.h>
 
 #include "ipath_kernel.h"
@@ -63,7 +62,8 @@
 	.open = ipath_open,
 	.release = ipath_close,
 	.poll = ipath_poll,
-	.mmap = ipath_mmap
+	.mmap = ipath_mmap,
+	.llseek = noop_llseek,
 };
 
 /*
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_fs.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_fs.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/ipath_fs.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/ipath_fs.c	2011-01-04 19:50:19.000000000 -0500
@@ -57,6 +57,7 @@
 		goto bail;
 	}
 
+	inode->i_ino = get_next_ino();
 	inode->i_mode = mode;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	inode->i_private = data;
@@ -103,6 +104,7 @@
 
 static const struct file_operations atomic_stats_ops = {
 	.read = atomic_stats_read,
+	.llseek = default_llseek,
 };
 
 static ssize_t atomic_counters_read(struct file *file, char __user *buf,
@@ -120,6 +122,7 @@
 
 static const struct file_operations atomic_counters_ops = {
 	.read = atomic_counters_read,
+	.llseek = default_llseek,
 };
 
 static ssize_t flash_read(struct file *file, char __user *buf,
@@ -224,6 +227,7 @@
 static const struct file_operations flash_ops = {
 	.read = flash_read,
 	.write = flash_write,
+	.llseek = default_llseek,
 };
 
 static int create_device_files(struct super_block *sb,
@@ -358,13 +362,13 @@
 	return ret;
 }
 
-static int ipathfs_get_sb(struct file_system_type *fs_type, int flags,
-			const char *dev_name, void *data, struct vfsmount *mnt)
+static struct dentry *ipathfs_mount(struct file_system_type *fs_type,
+			int flags, const char *dev_name, void *data)
 {
-	int ret = get_sb_single(fs_type, flags, data,
-				    ipathfs_fill_super, mnt);
-	if (ret >= 0)
-		ipath_super = mnt->mnt_sb;
+	struct dentry *ret;
+	ret = mount_single(fs_type, flags, data, ipathfs_fill_super);
+	if (!IS_ERR(ret))
+		ipath_super = ret->d_sb;
 	return ret;
 }
 
@@ -407,7 +411,7 @@
 static struct file_system_type ipathfs_fs_type = {
 	.owner =	THIS_MODULE,
 	.name =		"ipathfs",
-	.get_sb =	ipathfs_get_sb,
+	.mount =	ipathfs_mount,
 	.kill_sb =	ipathfs_kill_super,
 };
 
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/Makefile linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/Makefile
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/ipath/Makefile	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/ipath/Makefile	2011-01-04 19:50:19.000000000 -0500
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \
+ccflags-y := -DIPATH_IDSTR='"QLogic kernel.org driver"' \
 	-DIPATH_KERN_TYPE=0
 
 obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/ah.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/ah.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/ah.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/ah.c	2011-01-04 19:50:19.000000000 -0500
@@ -30,66 +30,163 @@
  * SOFTWARE.
  */
 
+#include <rdma/ib_addr.h>
+#include <rdma/ib_cache.h>
+
 #include <linux/slab.h>
+#include <linux/inet.h>
+#include <linux/string.h>
 
 #include "mlx4_ib.h"
 
-struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr,
+			u8 *mac, int *is_mcast, u8 port)
 {
-	struct mlx4_dev *dev = to_mdev(pd->device)->dev;
-	struct mlx4_ib_ah *ah;
+	struct in6_addr in6;
 
-	ah = kmalloc(sizeof *ah, GFP_ATOMIC);
-	if (!ah)
-		return ERR_PTR(-ENOMEM);
+	*is_mcast = 0;
 
-	memset(&ah->av, 0, sizeof ah->av);
+	memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6);
+	if (rdma_link_local_addr(&in6))
+		rdma_get_ll_mac(&in6, mac);
+	else if (rdma_is_multicast_addr(&in6)) {
+		rdma_get_mcast_mac(&in6, mac);
+		*is_mcast = 1;
+	} else
+		return -EINVAL;
 
-	ah->av.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
-	ah->av.g_slid  = ah_attr->src_path_bits;
-	ah->av.dlid    = cpu_to_be16(ah_attr->dlid);
-	if (ah_attr->static_rate) {
-		ah->av.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
-		while (ah->av.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
-		       !(1 << ah->av.stat_rate & dev->caps.stat_rate_support))
-			--ah->av.stat_rate;
-	}
-	ah->av.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+	return 0;
+}
+
+static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+				  struct mlx4_ib_ah *ah)
+{
+	struct mlx4_dev *dev = to_mdev(pd->device)->dev;
+
+	ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+	ah->av.ib.g_slid  = ah_attr->src_path_bits;
 	if (ah_attr->ah_flags & IB_AH_GRH) {
-		ah->av.g_slid   |= 0x80;
-		ah->av.gid_index = ah_attr->grh.sgid_index;
-		ah->av.hop_limit = ah_attr->grh.hop_limit;
-		ah->av.sl_tclass_flowlabel |=
+		ah->av.ib.g_slid   |= 0x80;
+		ah->av.ib.gid_index = ah_attr->grh.sgid_index;
+		ah->av.ib.hop_limit = ah_attr->grh.hop_limit;
+		ah->av.ib.sl_tclass_flowlabel |=
 			cpu_to_be32((ah_attr->grh.traffic_class << 20) |
 				    ah_attr->grh.flow_label);
-		memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16);
+		memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16);
 	}
 
+	ah->av.ib.dlid    = cpu_to_be16(ah_attr->dlid);
+	if (ah_attr->static_rate) {
+		ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+		while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+		       !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support))
+			--ah->av.ib.stat_rate;
+	}
+	ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+
 	return &ah->ibah;
 }
 
+static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr,
+				    struct mlx4_ib_ah *ah)
+{
+	struct mlx4_ib_dev *ibdev = to_mdev(pd->device);
+	struct mlx4_dev *dev = ibdev->dev;
+	union ib_gid sgid;
+	u8 mac[6];
+	int err;
+	int is_mcast;
+	u16 vlan_tag;
+
+	err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num);
+	if (err)
+		return ERR_PTR(err);
+
+	memcpy(ah->av.eth.mac, mac, 6);
+	err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid);
+	if (err)
+		return ERR_PTR(err);
+	vlan_tag = rdma_get_vlan_id(&sgid);
+	if (vlan_tag < 0x1000)
+		vlan_tag |= (ah_attr->sl & 7) << 13;
+	ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24));
+	ah->av.eth.gid_index = ah_attr->grh.sgid_index;
+	ah->av.eth.vlan = cpu_to_be16(vlan_tag);
+	if (ah_attr->static_rate) {
+		ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET;
+		while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET &&
+		       !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support))
+			--ah->av.eth.stat_rate;
+	}
+
+	/*
+	 * HW requires multicast LID so we just choose one.
+	 */
+	if (is_mcast)
+		ah->av.ib.dlid = cpu_to_be16(0xc000);
+
+	memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16);
+	ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28);
+
+	return &ah->ibah;
+}
+
+struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+	struct mlx4_ib_ah *ah;
+	struct ib_ah *ret;
+
+	ah = kzalloc(sizeof *ah, GFP_ATOMIC);
+	if (!ah)
+		return ERR_PTR(-ENOMEM);
+
+	if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) {
+		if (!(ah_attr->ah_flags & IB_AH_GRH)) {
+			ret = ERR_PTR(-EINVAL);
+		} else {
+			/*
+			 * TBD: need to handle the case when we get
+			 * called in an atomic context and there we
+			 * might sleep.  We don't expect this
+			 * currently since we're working with link
+			 * local addresses which we can translate
+			 * without going to sleep.
+			 */
+			ret = create_iboe_ah(pd, ah_attr, ah);
+		}
+
+		if (IS_ERR(ret))
+			kfree(ah);
+
+		return ret;
+	} else
+		return create_ib_ah(pd, ah_attr, ah); /* never fails */
+}
+
 int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
 {
 	struct mlx4_ib_ah *ah = to_mah(ibah);
+	enum rdma_link_layer ll;
 
 	memset(ah_attr, 0, sizeof *ah_attr);
-	ah_attr->dlid	       = be16_to_cpu(ah->av.dlid);
-	ah_attr->sl	       = be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 28;
-	ah_attr->port_num      = be32_to_cpu(ah->av.port_pd) >> 24;
-	if (ah->av.stat_rate)
-		ah_attr->static_rate = ah->av.stat_rate - MLX4_STAT_RATE_OFFSET;
-	ah_attr->src_path_bits = ah->av.g_slid & 0x7F;
+	ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28;
+	ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24;
+	ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num);
+	ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0;
+	if (ah->av.ib.stat_rate)
+		ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET;
+	ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F;
 
 	if (mlx4_ib_ah_grh_present(ah)) {
 		ah_attr->ah_flags = IB_AH_GRH;
 
 		ah_attr->grh.traffic_class =
-			be32_to_cpu(ah->av.sl_tclass_flowlabel) >> 20;
+			be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20;
 		ah_attr->grh.flow_label =
-			be32_to_cpu(ah->av.sl_tclass_flowlabel) & 0xfffff;
-		ah_attr->grh.hop_limit  = ah->av.hop_limit;
-		ah_attr->grh.sgid_index = ah->av.gid_index;
-		memcpy(ah_attr->grh.dgid.raw, ah->av.dgid, 16);
+			be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff;
+		ah_attr->grh.hop_limit  = ah->av.ib.hop_limit;
+		ah_attr->grh.sgid_index = ah->av.ib.gid_index;
+		memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16);
 	}
 
 	return 0;
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/Kconfig linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/Kconfig
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/Kconfig	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/Kconfig	2011-01-04 19:50:19.000000000 -0500
@@ -1,5 +1,6 @@
 config MLX4_INFINIBAND
 	tristate "Mellanox ConnectX HCA support"
+	depends on NETDEVICES && NETDEV_10000 && PCI
 	select MLX4_CORE
 	---help---
 	  This driver provides low-level InfiniBand support for
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/mad.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/mad.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/mad.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/mad.c	2011-01-04 19:50:19.000000000 -0500
@@ -311,19 +311,25 @@
 	struct ib_mad_agent *agent;
 	int p, q;
 	int ret;
+	enum rdma_link_layer ll;
 
-	for (p = 0; p < dev->num_ports; ++p)
+	for (p = 0; p < dev->num_ports; ++p) {
+		ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1);
 		for (q = 0; q <= 1; ++q) {
-			agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
-						      q ? IB_QPT_GSI : IB_QPT_SMI,
-						      NULL, 0, send_handler,
-						      NULL, NULL);
-			if (IS_ERR(agent)) {
-				ret = PTR_ERR(agent);
-				goto err;
-			}
-			dev->send_agent[p][q] = agent;
+			if (ll == IB_LINK_LAYER_INFINIBAND) {
+				agent = ib_register_mad_agent(&dev->ib_dev, p + 1,
+							      q ? IB_QPT_GSI : IB_QPT_SMI,
+							      NULL, 0, send_handler,
+							      NULL, NULL);
+				if (IS_ERR(agent)) {
+					ret = PTR_ERR(agent);
+					goto err;
+				}
+				dev->send_agent[p][q] = agent;
+			} else
+				dev->send_agent[p][q] = NULL;
 		}
+	}
 
 	return 0;
 
@@ -344,8 +350,10 @@
 	for (p = 0; p < dev->num_ports; ++p) {
 		for (q = 0; q <= 1; ++q) {
 			agent = dev->send_agent[p][q];
-			dev->send_agent[p][q] = NULL;
-			ib_unregister_mad_agent(agent);
+			if (agent) {
+				dev->send_agent[p][q] = NULL;
+				ib_unregister_mad_agent(agent);
+			}
 		}
 
 		if (dev->sm_ah[p])
diff -druN linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/main.c linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/main.c
--- linux-libre-2.6.36-gnu/drivers/infiniband/hw/mlx4/main.c	2010-10-20 16:30:22.000000000 -0400
+++ linux-libre-2.6.37-gnu/drivers/infiniband/hw/mlx4/main.c	2011-01-04 19:50:19.000000000 -0500
@@ -35,9 +35,14 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
 
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
+#include <rdma/ib_addr.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/cmd.h>
@@ -58,6 +63,15 @@
 	DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
 	DRV_VERSION " (" DRV_RELDATE ")\n";
 
+struct update_gid_work {
+	struct work_struct	work;
+	union ib_gid		gids[128];
+	struct mlx4_ib_dev     *dev;
+	int			port;
+};
+
+static struct workqueue_struct *wq;
+
 static void init_query_mad(struct ib_smp *mad)
 {
 	mad->base_version  = 1;
@@ -66,6 +80,8 @@
 	mad->method	   = IB_MGMT_METHOD_GET;
 }
 
+static union ib_gid zgid;
+
 static int mlx4_ib_query_device(struct ib_device *ibdev,
 				struct ib_device_attr *props)
 {
@@ -135,7 +151,7 @@
 	props->max_srq		   = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs;
 	props->max_srq_wr	   = dev->dev->caps.max_srq_wqes - 1;
 	props->max_srq_sge	   = dev->dev->caps.max_srq_sge;
-	props->max_fast_reg_page_list_len = PAGE_SIZE / sizeof (u64);
+	props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES;
 	props->local_ca_ack_delay  = dev->dev->caps.local_ca_ack_delay;
 	props->atomic_cap	   = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
 		IB_ATOMIC_HCA : IB_ATOMIC_NONE;
@@ -154,28 +170,19 @@
 	return err;
 }
 
-static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
-			      struct ib_port_attr *props)
+static enum rdma_link_layer
+mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num)
 {
-	struct ib_smp *in_mad  = NULL;
-	struct ib_smp *out_mad = NULL;
-	int err = -ENOMEM;
-
-	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
-	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
-	if (!in_mad || !out_mad)
-		goto out;
-
-	memset(props, 0, sizeof *props);
-
-	init_query_mad(in_mad);
-	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
-	in_mad->attr_mod = cpu_to_be32(port);
+	struct mlx4_dev *dev = to_mdev(device)->dev;
 
-	err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
-	if (err)
-		goto out;
+	return dev->caps.port_mask & (1 << (port_num - 1)) ?
+		IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
+}
 
+static int ib_link_query_port(struct ib_device *ibdev, u8 port,
+			      struct ib_port_attr *props,
+			      struct ib_smp *out_mad)
+{
 	props->lid		= be16_to_cpup((__be16 *) (out_mad->data + 16));
 	props->lmc		= out_mad->data[34] & 0x7;
 	props->sm_lid		= be16_to_cpup((__be16 *) (out_mad->data + 18));
@@ -196,6 +203,80 @@
 	props->max_vl_num	= out_mad->data[37] >> 4;
 	props->init_type_reply	= out_mad->data[41] >> 4;
 
+	return 0;
+}
+
+static u8 state_to_phys_state(enum ib_port_state state)
+{
+	return state == IB_PORT_ACTIVE ? 5 : 3;
+}
+
+static int eth_link_query_port(struct ib_device *ibdev, u8 port,
+			       struct ib_port_attr *props,
+			       struct ib_smp *out_mad)
+{
+	struct mlx4_ib_iboe *iboe = &to_mdev(ibdev)->iboe;
+	struct net_device *ndev;
+	enum ib_mtu tmp;
+
+	props->active_width	= IB_WIDTH_1X;
+	props->active_speed	= 4;
+	props->port_cap_flags	= IB_PORT_CM_SUP;
+	props->gid_tbl_len	= to_mdev(ibdev)->dev->caps.gid_table_len[port];
+	props->max_msg_sz	= to_mdev(ibdev)->dev->caps.max_msg_sz;
+	props->pkey_tbl_len	= 1;
+	props->bad_pkey_cntr	= be16_to_cpup((__be16 *) (out_mad->data + 46));
+	props->qkey_viol_cntr	= be16_to_cpup((__be16 *) (out_mad->data + 48));
+	props->max_mtu		= IB_MTU_2048;
+	props->subnet_timeout	= 0;
+	props->max_vl_num	= out_mad->data[37] >> 4;
+	props->init_type_reply	= 0;
+	props->state		= IB_PORT_DOWN;
+	props->phys_state	= state_to_phys_state(props->state);
+	props->active_mtu	= IB_MTU_256;
+	spin_lock(&iboe->lock);
+	ndev = iboe->netdevs[port - 1];
+	if (!ndev)
+		goto out;
+
+	tmp = iboe_get_mtu(ndev->mtu);
+	props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
+
+	props->state		= (netif_running(ndev) && netif_carrier_ok(ndev)) ?
+					IB_PORT_ACTIVE : IB_PORT_DOWN;
+	props->phys_state	= state_to_phys_state(props->state);
+
+out:
+	spin_unlock(&iboe->lock);
+	return 0;
+}
+
+static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
+			      struct ib_port_attr *props)
+{
+	struct ib_smp *in_mad  = NULL;
+	struct ib_smp *out_mad = NULL;
+	int err = -ENOMEM;
+
+	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+	if (!in_mad || !out_mad)
+		goto out;
+
+	memset(props, 0, sizeof *props);
+
+	init_query_mad(in_mad);
+	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+	in_mad->attr_mod = cpu_to_be32(port);
+
+	err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad);
+	if (err)
+		goto out;
+
+	err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ?
+		ib_link_query_port(ibdev, port, props, out_mad) :
+		eth_link_query_port(ibdev, port, props, out_mad);
+
 out:
 	kfree(in_mad);
 	kfree(out_mad);
@@ -203,8 +284,8 @@
 	return err;
 }
 
-static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
-			     union ib_gid *gid)
+static int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+			       union ib_gid *gid)
 {
 	struct ib_smp *in_mad  = NULL;
 	struct ib_smp *out_mad = NULL;
@@ -241,6 +322,25 @@
 	return err;
 }
 
+static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index,
+			  union ib_gid *gid)
+{
+	struct mlx4_ib_dev *dev = to_mdev(ibdev);
+
+	*gid = dev->iboe.gid_table[port - 1][index];
+
+	return 0;
+}
+
+static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index,
+			     union ib_gid *gid)
+{
+	if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+		return __mlx4_ib_query_gid(ibdev, port, index, gid);
+	else
+		return iboe_query_gid(ibdev, port, index, gid);
+}
+
 static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
 			      u16 *pkey)
 {
@@ -272,14 +372,32 @@
 static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
 				 struct ib_device_modify *props)
 {
+	struct mlx4_cmd_mailbox *mailbox;
+
 	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
 		return -EOPNOTSUPP;
 
-	if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
-		spin_lock(&to_mdev(ibdev)->sm_lock);
-		memcpy(ibdev->node_desc, props->node_desc, 64);
-		spin_unlock(&to_mdev(ibdev)->sm_lock);
-	}
+	if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+		return 0;
+
+	spin_lock(&to_mdev(ibdev)->sm_lock);
+	memcpy(ibdev->node_desc, props->node_desc, 64);
+	spin_unlock(&to_mdev(ibdev)->sm_lock);
+
+	/*
+	 * If possible, pass node desc to FW, so it can generate
+	 * a 144 trap.  If cmd fails, just ignore.
+	 */
+	mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev);
+	if (IS_ERR(mailbox))
+		return 0;
+
+	memset(mailbox->buf, 0, 256);
+	memcpy(mailbox->buf, props->node_desc, 64);
+	mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
+		 MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A);
+
+	mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox);
 
 	return 0;
 }
@@ -289,6 +407,7 @@
 {
 	struct mlx4_cmd_mailbox *mailbox;
 	int err;
+	u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
 
 	mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
 	if (IS_ERR(mailbox))
@@ -304,7 +423,7 @@
 		((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
 	}
 
-	err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
+	err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
 		       MLX4_CMD_TIME_CLASS_B);
 
 	mlx4_free_cmd_mailbox(dev->dev, mailbox);
@@ -447,18 +566,132 @@
 	return 0;
 }
 
+static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
+{
+	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+	struct mlx4_ib_gid_entry *ge;
+
+	ge = kzalloc(sizeof *ge, GFP_KERNEL);
+	if (!ge)
+		return -ENOMEM;
+
+	ge->gid = *gid;
+	if (mlx4_ib_add_mc(mdev, mqp, gid)) {
+		ge->port = mqp->port;
+		ge->added = 1;
+	}
+
+	mutex_lock(&mqp->mutex);
+	list_add_tail(&ge->list, &mqp->gid_list);
+	mutex_unlock(&mqp->mutex);
+
+	return 0;
+}
+
+int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
+		   union ib_gid *gid)
+{
+	u8 mac[6];
+	struct net_device *ndev;
+	int ret = 0;
+
+	if (!mqp->port)
+		return 0;
+
+	spin_lock(&mdev->iboe.lock);
+	ndev = mdev->iboe.netdevs[mqp->port - 1];
+	if (ndev)
+		dev_hold(ndev);
+	spin_unlock(&mdev->iboe.lock);
+
+	if (ndev) {
+		rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+		rtnl_lock();
+		dev_mc_add(mdev->iboe.netdevs[mqp->port - 1], mac);
+		ret = 1;
+		rtnl_unlock();
+		dev_put(ndev);
+	}
+
+	return ret;
+}
+
 static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
-	return mlx4_multicast_attach(to_mdev(ibqp->device)->dev,
-				     &to_mqp(ibqp)->mqp, gid->raw,
-				     !!(to_mqp(ibqp)->flags &
-					MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+	int err;
+	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+
+	err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags &
+				    MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK));
+	if (err)
+		return err;
+
+	err = add_gid_entry(ibqp, gid);
+	if (err)
+		goto err_add;
+
+	return 0;
+
+err_add:
+	mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw);
+	return err;
+}
+
+static struct mlx4_ib_gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw)
+{
+	struct mlx4_ib_gid_entry *ge;
+	struct mlx4_ib_gid_entry *tmp;
+	struct mlx4_ib_gid_entry *ret = NULL;
+
+	list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
+		if (!memcmp(raw, ge->gid.raw, 16)) {
+			ret = ge;
+			break;
+		}
+	}
+
+	return ret;
 }
 
 static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 {
-	return mlx4_multicast_detach(to_mdev(ibqp->device)->dev,
-				     &to_mqp(ibqp)->mqp, gid->raw);
+	int err;
+	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
+	u8 mac[6];
+	struct net_device *ndev;
+	struct mlx4_ib_gid_entry *ge;
+
+	err = mlx4_multicast_detach(mdev->dev,
+				    &mqp->mqp, gid->raw);
+	if (err)
+		return err;
+
+	mutex_lock(&mqp->mutex);
+	ge = find_gid_entry(mqp, gid->raw);
+	if (ge) {
+		spin_lock(&mdev->iboe.lock);
+		ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL;
+		if (ndev)
+			dev_hold(ndev);
+		spin_unlock(&mdev->iboe.lock);
+		rdma_get_mcast_mac((struct in6_addr *)gid, mac);
+		if (ndev) {
+			rtnl_lock();
+			dev_mc_del(mdev->iboe.netdevs[ge->port - 1], mac);
+			rtnl_unlock();
+			dev_put(ndev);
+		}
+		list_del(&ge->list);
+		kfree(ge);
+	} else
+		printk(KERN_WARNING "could not find mgid entry\n");
+
+	mutex_unlock(&mqp->mutex);
+
+	return 0;
 }
 
 static int init_node_data(struct mlx4_ib_dev *dev)
@@ -543,15 +776,215 @@
 	&dev_attr_board_id
 };
 
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev)
+{
+	memcpy(eui, dev->dev_addr, 3);
+	memcpy(eui + 5, dev->dev_addr + 3, 3);
+	if (vlan_id < 0x1000) {
+		eui[3] = vlan_id >> 8;
+		eui[4] = vlan_id & 0xff;
+	} else {
+		eui[3] = 0xff;
+		eui[4] = 0xfe;
+	}
+	eui[0] ^= 2;
+}
+
+static void update_gids_task(struct work_struct *work)
+{
+	struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
+	struct mlx4_cmd_mailbox *mailbox;
+	